11e8a1faeSThomas Huth /* 21e8a1faeSThomas Huth * QTest testcase for SDHCI controllers 31e8a1faeSThomas Huth * 41e8a1faeSThomas Huth * Written by Philippe Mathieu-Daudé <f4bug@amsat.org> 51e8a1faeSThomas Huth * 61e8a1faeSThomas Huth * This work is licensed under the terms of the GNU GPL, version 2 or later. 71e8a1faeSThomas Huth * See the COPYING file in the top-level directory. 81e8a1faeSThomas Huth * SPDX-License-Identifier: GPL-2.0-or-later 91e8a1faeSThomas Huth */ 101e8a1faeSThomas Huth 111e8a1faeSThomas Huth #include "qemu/osdep.h" 121e8a1faeSThomas Huth #include "hw/registerfields.h" 13*907b5105SMarc-André Lureau #include "libqtest.h" 141e8a1faeSThomas Huth #include "qemu/module.h" 151e8a1faeSThomas Huth #include "libqos/pci-pc.h" 161e8a1faeSThomas Huth #include "hw/pci/pci.h" 171e8a1faeSThomas Huth #include "libqos/qgraph.h" 181e8a1faeSThomas Huth #include "libqos/sdhci.h" 191e8a1faeSThomas Huth 201e8a1faeSThomas Huth #define SDHC_CAPAB 0x40 211e8a1faeSThomas Huth FIELD(SDHC_CAPAB, BASECLKFREQ, 8, 8); /* since v2 */ 221e8a1faeSThomas Huth FIELD(SDHC_CAPAB, SDMA, 22, 1); 231e8a1faeSThomas Huth FIELD(SDHC_CAPAB, SDR, 32, 3); /* since v3 */ 241e8a1faeSThomas Huth FIELD(SDHC_CAPAB, DRIVER, 36, 3); /* since v3 */ 251e8a1faeSThomas Huth #define SDHC_HCVER 0xFE 261e8a1faeSThomas Huth 271e8a1faeSThomas Huth static void check_specs_version(QSDHCI *s, uint8_t version) 281e8a1faeSThomas Huth { 291e8a1faeSThomas Huth uint32_t v; 301e8a1faeSThomas Huth 311e8a1faeSThomas Huth v = s->readw(s, SDHC_HCVER); 321e8a1faeSThomas Huth v &= 0xff; 331e8a1faeSThomas Huth v += 1; 341e8a1faeSThomas Huth g_assert_cmpuint(v, ==, version); 351e8a1faeSThomas Huth } 361e8a1faeSThomas Huth 371e8a1faeSThomas Huth static void check_capab_capareg(QSDHCI *s, uint64_t expec_capab) 381e8a1faeSThomas Huth { 391e8a1faeSThomas Huth uint64_t capab; 401e8a1faeSThomas Huth 411e8a1faeSThomas Huth capab = s->readq(s, SDHC_CAPAB); 421e8a1faeSThomas Huth g_assert_cmphex(capab, ==, expec_capab); 431e8a1faeSThomas Huth } 441e8a1faeSThomas Huth 451e8a1faeSThomas Huth static void check_capab_readonly(QSDHCI *s) 461e8a1faeSThomas Huth { 471e8a1faeSThomas Huth const uint64_t vrand = 0x123456789abcdef; 481e8a1faeSThomas Huth uint64_t capab0, capab1; 491e8a1faeSThomas Huth 501e8a1faeSThomas Huth capab0 = s->readq(s, SDHC_CAPAB); 511e8a1faeSThomas Huth g_assert_cmpuint(capab0, !=, vrand); 521e8a1faeSThomas Huth 531e8a1faeSThomas Huth s->writeq(s, SDHC_CAPAB, vrand); 541e8a1faeSThomas Huth capab1 = s->readq(s, SDHC_CAPAB); 551e8a1faeSThomas Huth g_assert_cmpuint(capab1, !=, vrand); 561e8a1faeSThomas Huth g_assert_cmpuint(capab1, ==, capab0); 571e8a1faeSThomas Huth } 581e8a1faeSThomas Huth 591e8a1faeSThomas Huth static void check_capab_baseclock(QSDHCI *s, uint8_t expec_freq) 601e8a1faeSThomas Huth { 611e8a1faeSThomas Huth uint64_t capab, capab_freq; 621e8a1faeSThomas Huth 631e8a1faeSThomas Huth if (!expec_freq) { 641e8a1faeSThomas Huth return; 651e8a1faeSThomas Huth } 661e8a1faeSThomas Huth capab = s->readq(s, SDHC_CAPAB); 671e8a1faeSThomas Huth capab_freq = FIELD_EX64(capab, SDHC_CAPAB, BASECLKFREQ); 681e8a1faeSThomas Huth g_assert_cmpuint(capab_freq, ==, expec_freq); 691e8a1faeSThomas Huth } 701e8a1faeSThomas Huth 711e8a1faeSThomas Huth static void check_capab_sdma(QSDHCI *s, bool supported) 721e8a1faeSThomas Huth { 731e8a1faeSThomas Huth uint64_t capab, capab_sdma; 741e8a1faeSThomas Huth 751e8a1faeSThomas Huth capab = s->readq(s, SDHC_CAPAB); 761e8a1faeSThomas Huth capab_sdma = FIELD_EX64(capab, SDHC_CAPAB, SDMA); 771e8a1faeSThomas Huth g_assert_cmpuint(capab_sdma, ==, supported); 781e8a1faeSThomas Huth } 791e8a1faeSThomas Huth 801e8a1faeSThomas Huth static void check_capab_v3(QSDHCI *s, uint8_t version) 811e8a1faeSThomas Huth { 821e8a1faeSThomas Huth uint64_t capab, capab_v3; 831e8a1faeSThomas Huth 841e8a1faeSThomas Huth if (version < 3) { 851e8a1faeSThomas Huth /* before v3 those fields are RESERVED */ 861e8a1faeSThomas Huth capab = s->readq(s, SDHC_CAPAB); 871e8a1faeSThomas Huth capab_v3 = FIELD_EX64(capab, SDHC_CAPAB, SDR); 881e8a1faeSThomas Huth g_assert_cmpuint(capab_v3, ==, 0); 891e8a1faeSThomas Huth capab_v3 = FIELD_EX64(capab, SDHC_CAPAB, DRIVER); 901e8a1faeSThomas Huth g_assert_cmpuint(capab_v3, ==, 0); 911e8a1faeSThomas Huth } 921e8a1faeSThomas Huth } 931e8a1faeSThomas Huth 941e8a1faeSThomas Huth static void test_registers(void *obj, void *data, QGuestAllocator *alloc) 951e8a1faeSThomas Huth { 961e8a1faeSThomas Huth QSDHCI *s = obj; 971e8a1faeSThomas Huth 981e8a1faeSThomas Huth check_specs_version(s, s->props.version); 991e8a1faeSThomas Huth check_capab_capareg(s, s->props.capab.reg); 1001e8a1faeSThomas Huth check_capab_readonly(s); 1011e8a1faeSThomas Huth check_capab_v3(s, s->props.version); 1021e8a1faeSThomas Huth check_capab_sdma(s, s->props.capab.sdma); 1031e8a1faeSThomas Huth check_capab_baseclock(s, s->props.baseclock); 1041e8a1faeSThomas Huth } 1051e8a1faeSThomas Huth 1061e8a1faeSThomas Huth static void register_sdhci_test(void) 1071e8a1faeSThomas Huth { 1081e8a1faeSThomas Huth qos_add_test("registers", "sdhci", test_registers, NULL); 1091e8a1faeSThomas Huth } 1101e8a1faeSThomas Huth 1111e8a1faeSThomas Huth libqos_init(register_sdhci_test); 112