qemu/tests/sdhci-test.c
<<
>>
Prefs
   1/*
   2 * QTest testcase for SDHCI controllers
   3 *
   4 * Written by Philippe Mathieu-Daudé <f4bug@amsat.org>
   5 *
   6 * This work is licensed under the terms of the GNU GPL, version 2 or later.
   7 * See the COPYING file in the top-level directory.
   8 * SPDX-License-Identifier: GPL-2.0-or-later
   9 */
  10#include "qemu/osdep.h"
  11#include "hw/registerfields.h"
  12#include "libqtest.h"
  13#include "libqos/pci-pc.h"
  14#include "hw/pci/pci.h"
  15#include "libqos/qgraph.h"
  16#include "libqos/sdhci.h"
  17
  18#define SDHC_CAPAB                      0x40
  19FIELD(SDHC_CAPAB, BASECLKFREQ,               8, 8); /* since v2 */
  20FIELD(SDHC_CAPAB, SDMA,                     22, 1);
  21FIELD(SDHC_CAPAB, SDR,                      32, 3); /* since v3 */
  22FIELD(SDHC_CAPAB, DRIVER,                   36, 3); /* since v3 */
  23#define SDHC_HCVER                      0xFE
  24
  25static void check_specs_version(QSDHCI *s, uint8_t version)
  26{
  27    uint32_t v;
  28
  29    v = s->readw(s, SDHC_HCVER);
  30    v &= 0xff;
  31    v += 1;
  32    g_assert_cmpuint(v, ==, version);
  33}
  34
  35static void check_capab_capareg(QSDHCI *s, uint64_t expec_capab)
  36{
  37    uint64_t capab;
  38
  39    capab = s->readq(s, SDHC_CAPAB);
  40    g_assert_cmphex(capab, ==, expec_capab);
  41}
  42
  43static void check_capab_readonly(QSDHCI *s)
  44{
  45    const uint64_t vrand = 0x123456789abcdef;
  46    uint64_t capab0, capab1;
  47
  48    capab0 = s->readq(s, SDHC_CAPAB);
  49    g_assert_cmpuint(capab0, !=, vrand);
  50
  51    s->writeq(s, SDHC_CAPAB, vrand);
  52    capab1 = s->readq(s, SDHC_CAPAB);
  53    g_assert_cmpuint(capab1, !=, vrand);
  54    g_assert_cmpuint(capab1, ==, capab0);
  55}
  56
  57static void check_capab_baseclock(QSDHCI *s, uint8_t expec_freq)
  58{
  59    uint64_t capab, capab_freq;
  60
  61    if (!expec_freq) {
  62        return;
  63    }
  64    capab = s->readq(s, SDHC_CAPAB);
  65    capab_freq = FIELD_EX64(capab, SDHC_CAPAB, BASECLKFREQ);
  66    g_assert_cmpuint(capab_freq, ==, expec_freq);
  67}
  68
  69static void check_capab_sdma(QSDHCI *s, bool supported)
  70{
  71    uint64_t capab, capab_sdma;
  72
  73    capab = s->readq(s, SDHC_CAPAB);
  74    capab_sdma = FIELD_EX64(capab, SDHC_CAPAB, SDMA);
  75    g_assert_cmpuint(capab_sdma, ==, supported);
  76}
  77
  78static void check_capab_v3(QSDHCI *s, uint8_t version)
  79{
  80    uint64_t capab, capab_v3;
  81
  82    if (version < 3) {
  83        /* before v3 those fields are RESERVED */
  84        capab = s->readq(s, SDHC_CAPAB);
  85        capab_v3 = FIELD_EX64(capab, SDHC_CAPAB, SDR);
  86        g_assert_cmpuint(capab_v3, ==, 0);
  87        capab_v3 = FIELD_EX64(capab, SDHC_CAPAB, DRIVER);
  88        g_assert_cmpuint(capab_v3, ==, 0);
  89    }
  90}
  91
  92static void test_registers(void *obj, void *data, QGuestAllocator *alloc)
  93{
  94    QSDHCI *s = obj;
  95
  96    check_specs_version(s, s->props.version);
  97    check_capab_capareg(s, s->props.capab.reg);
  98    check_capab_readonly(s);
  99    check_capab_v3(s, s->props.version);
 100    check_capab_sdma(s, s->props.capab.sdma);
 101    check_capab_baseclock(s, s->props.baseclock);
 102}
 103
 104static void register_sdhci_test(void)
 105{
 106    qos_add_test("registers", "sdhci", test_registers, NULL);
 107}
 108
 109libqos_init(register_sdhci_test);
 110