1*8640cc11SPhilippe Mathieu-Daudé /* 2*8640cc11SPhilippe Mathieu-Daudé * QTest testcase for SDHCI controllers 3*8640cc11SPhilippe Mathieu-Daudé * 4*8640cc11SPhilippe Mathieu-Daudé * Written by Philippe Mathieu-Daudé <f4bug@amsat.org> 5*8640cc11SPhilippe Mathieu-Daudé * 6*8640cc11SPhilippe Mathieu-Daudé * This work is licensed under the terms of the GNU GPL, version 2 or later. 7*8640cc11SPhilippe Mathieu-Daudé * See the COPYING file in the top-level directory. 8*8640cc11SPhilippe Mathieu-Daudé * SPDX-License-Identifier: GPL-2.0-or-later 9*8640cc11SPhilippe Mathieu-Daudé */ 10*8640cc11SPhilippe Mathieu-Daudé #include "qemu/osdep.h" 11*8640cc11SPhilippe Mathieu-Daudé #include "hw/registerfields.h" 12*8640cc11SPhilippe Mathieu-Daudé #include "libqtest.h" 13*8640cc11SPhilippe Mathieu-Daudé #include "libqos/pci-pc.h" 14*8640cc11SPhilippe Mathieu-Daudé #include "hw/pci/pci.h" 15*8640cc11SPhilippe Mathieu-Daudé 16*8640cc11SPhilippe Mathieu-Daudé #define SDHC_CAPAB 0x40 17*8640cc11SPhilippe Mathieu-Daudé #define SDHC_HCVER 0xFE 18*8640cc11SPhilippe Mathieu-Daudé 19*8640cc11SPhilippe Mathieu-Daudé static const struct sdhci_t { 20*8640cc11SPhilippe Mathieu-Daudé const char *arch, *machine; 21*8640cc11SPhilippe Mathieu-Daudé struct { 22*8640cc11SPhilippe Mathieu-Daudé uintptr_t addr; 23*8640cc11SPhilippe Mathieu-Daudé uint8_t version; 24*8640cc11SPhilippe Mathieu-Daudé uint8_t baseclock; 25*8640cc11SPhilippe Mathieu-Daudé struct { 26*8640cc11SPhilippe Mathieu-Daudé bool sdma; 27*8640cc11SPhilippe Mathieu-Daudé uint64_t reg; 28*8640cc11SPhilippe Mathieu-Daudé } capab; 29*8640cc11SPhilippe Mathieu-Daudé } sdhci; 30*8640cc11SPhilippe Mathieu-Daudé struct { 31*8640cc11SPhilippe Mathieu-Daudé uint16_t vendor_id, device_id; 32*8640cc11SPhilippe Mathieu-Daudé } pci; 33*8640cc11SPhilippe Mathieu-Daudé } models[] = { 34*8640cc11SPhilippe Mathieu-Daudé /* PC via PCI */ 35*8640cc11SPhilippe Mathieu-Daudé { "x86_64", "pc", 36*8640cc11SPhilippe Mathieu-Daudé {-1, 2, 0, {1, 0x057834b4} }, 37*8640cc11SPhilippe Mathieu-Daudé .pci = { PCI_VENDOR_ID_REDHAT, PCI_DEVICE_ID_REDHAT_SDHCI } }, 38*8640cc11SPhilippe Mathieu-Daudé 39*8640cc11SPhilippe Mathieu-Daudé /* Exynos4210 */ 40*8640cc11SPhilippe Mathieu-Daudé { "arm", "smdkc210", 41*8640cc11SPhilippe Mathieu-Daudé {0x12510000, 2, 0, {1, 0x5e80080} } }, 42*8640cc11SPhilippe Mathieu-Daudé }; 43*8640cc11SPhilippe Mathieu-Daudé 44*8640cc11SPhilippe Mathieu-Daudé typedef struct QSDHCI { 45*8640cc11SPhilippe Mathieu-Daudé struct { 46*8640cc11SPhilippe Mathieu-Daudé QPCIBus *bus; 47*8640cc11SPhilippe Mathieu-Daudé QPCIDevice *dev; 48*8640cc11SPhilippe Mathieu-Daudé } pci; 49*8640cc11SPhilippe Mathieu-Daudé union { 50*8640cc11SPhilippe Mathieu-Daudé QPCIBar mem_bar; 51*8640cc11SPhilippe Mathieu-Daudé uint64_t addr; 52*8640cc11SPhilippe Mathieu-Daudé }; 53*8640cc11SPhilippe Mathieu-Daudé } QSDHCI; 54*8640cc11SPhilippe Mathieu-Daudé 55*8640cc11SPhilippe Mathieu-Daudé static uint64_t sdhci_readq(QSDHCI *s, uint32_t reg) 56*8640cc11SPhilippe Mathieu-Daudé { 57*8640cc11SPhilippe Mathieu-Daudé uint64_t val; 58*8640cc11SPhilippe Mathieu-Daudé 59*8640cc11SPhilippe Mathieu-Daudé if (s->pci.dev) { 60*8640cc11SPhilippe Mathieu-Daudé val = qpci_io_readq(s->pci.dev, s->mem_bar, reg); 61*8640cc11SPhilippe Mathieu-Daudé } else { 62*8640cc11SPhilippe Mathieu-Daudé val = qtest_readq(global_qtest, s->addr + reg); 63*8640cc11SPhilippe Mathieu-Daudé } 64*8640cc11SPhilippe Mathieu-Daudé 65*8640cc11SPhilippe Mathieu-Daudé return val; 66*8640cc11SPhilippe Mathieu-Daudé } 67*8640cc11SPhilippe Mathieu-Daudé 68*8640cc11SPhilippe Mathieu-Daudé static void check_capab_capareg(QSDHCI *s, uint64_t expec_capab) 69*8640cc11SPhilippe Mathieu-Daudé { 70*8640cc11SPhilippe Mathieu-Daudé uint64_t capab; 71*8640cc11SPhilippe Mathieu-Daudé 72*8640cc11SPhilippe Mathieu-Daudé capab = sdhci_readq(s, SDHC_CAPAB); 73*8640cc11SPhilippe Mathieu-Daudé g_assert_cmphex(capab, ==, expec_capab); 74*8640cc11SPhilippe Mathieu-Daudé } 75*8640cc11SPhilippe Mathieu-Daudé 76*8640cc11SPhilippe Mathieu-Daudé static QSDHCI *machine_start(const struct sdhci_t *test) 77*8640cc11SPhilippe Mathieu-Daudé { 78*8640cc11SPhilippe Mathieu-Daudé QSDHCI *s = g_new0(QSDHCI, 1); 79*8640cc11SPhilippe Mathieu-Daudé 80*8640cc11SPhilippe Mathieu-Daudé if (test->pci.vendor_id) { 81*8640cc11SPhilippe Mathieu-Daudé /* PCI */ 82*8640cc11SPhilippe Mathieu-Daudé uint16_t vendor_id, device_id; 83*8640cc11SPhilippe Mathieu-Daudé uint64_t barsize; 84*8640cc11SPhilippe Mathieu-Daudé 85*8640cc11SPhilippe Mathieu-Daudé global_qtest = qtest_startf("-machine %s -device sdhci-pci", 86*8640cc11SPhilippe Mathieu-Daudé test->machine); 87*8640cc11SPhilippe Mathieu-Daudé 88*8640cc11SPhilippe Mathieu-Daudé s->pci.bus = qpci_init_pc(NULL); 89*8640cc11SPhilippe Mathieu-Daudé 90*8640cc11SPhilippe Mathieu-Daudé /* Find PCI device and verify it's the right one */ 91*8640cc11SPhilippe Mathieu-Daudé s->pci.dev = qpci_device_find(s->pci.bus, QPCI_DEVFN(4, 0)); 92*8640cc11SPhilippe Mathieu-Daudé g_assert_nonnull(s->pci.dev); 93*8640cc11SPhilippe Mathieu-Daudé vendor_id = qpci_config_readw(s->pci.dev, PCI_VENDOR_ID); 94*8640cc11SPhilippe Mathieu-Daudé device_id = qpci_config_readw(s->pci.dev, PCI_DEVICE_ID); 95*8640cc11SPhilippe Mathieu-Daudé g_assert(vendor_id == test->pci.vendor_id); 96*8640cc11SPhilippe Mathieu-Daudé g_assert(device_id == test->pci.device_id); 97*8640cc11SPhilippe Mathieu-Daudé s->mem_bar = qpci_iomap(s->pci.dev, 0, &barsize); 98*8640cc11SPhilippe Mathieu-Daudé qpci_device_enable(s->pci.dev); 99*8640cc11SPhilippe Mathieu-Daudé } else { 100*8640cc11SPhilippe Mathieu-Daudé /* SysBus */ 101*8640cc11SPhilippe Mathieu-Daudé global_qtest = qtest_startf("-machine %s", test->machine); 102*8640cc11SPhilippe Mathieu-Daudé s->addr = test->sdhci.addr; 103*8640cc11SPhilippe Mathieu-Daudé } 104*8640cc11SPhilippe Mathieu-Daudé 105*8640cc11SPhilippe Mathieu-Daudé return s; 106*8640cc11SPhilippe Mathieu-Daudé } 107*8640cc11SPhilippe Mathieu-Daudé 108*8640cc11SPhilippe Mathieu-Daudé static void machine_stop(QSDHCI *s) 109*8640cc11SPhilippe Mathieu-Daudé { 110*8640cc11SPhilippe Mathieu-Daudé g_free(s->pci.dev); 111*8640cc11SPhilippe Mathieu-Daudé qtest_quit(global_qtest); 112*8640cc11SPhilippe Mathieu-Daudé } 113*8640cc11SPhilippe Mathieu-Daudé 114*8640cc11SPhilippe Mathieu-Daudé static void test_machine(const void *data) 115*8640cc11SPhilippe Mathieu-Daudé { 116*8640cc11SPhilippe Mathieu-Daudé const struct sdhci_t *test = data; 117*8640cc11SPhilippe Mathieu-Daudé QSDHCI *s; 118*8640cc11SPhilippe Mathieu-Daudé 119*8640cc11SPhilippe Mathieu-Daudé s = machine_start(test); 120*8640cc11SPhilippe Mathieu-Daudé 121*8640cc11SPhilippe Mathieu-Daudé check_capab_capareg(s, test->sdhci.capab.reg); 122*8640cc11SPhilippe Mathieu-Daudé 123*8640cc11SPhilippe Mathieu-Daudé machine_stop(s); 124*8640cc11SPhilippe Mathieu-Daudé } 125*8640cc11SPhilippe Mathieu-Daudé 126*8640cc11SPhilippe Mathieu-Daudé int main(int argc, char *argv[]) 127*8640cc11SPhilippe Mathieu-Daudé { 128*8640cc11SPhilippe Mathieu-Daudé const char *arch = qtest_get_arch(); 129*8640cc11SPhilippe Mathieu-Daudé char *name; 130*8640cc11SPhilippe Mathieu-Daudé int i; 131*8640cc11SPhilippe Mathieu-Daudé 132*8640cc11SPhilippe Mathieu-Daudé g_test_init(&argc, &argv, NULL); 133*8640cc11SPhilippe Mathieu-Daudé for (i = 0; i < ARRAY_SIZE(models); i++) { 134*8640cc11SPhilippe Mathieu-Daudé if (strcmp(arch, models[i].arch)) { 135*8640cc11SPhilippe Mathieu-Daudé continue; 136*8640cc11SPhilippe Mathieu-Daudé } 137*8640cc11SPhilippe Mathieu-Daudé name = g_strdup_printf("sdhci/%s", models[i].machine); 138*8640cc11SPhilippe Mathieu-Daudé qtest_add_data_func(name, &models[i], test_machine); 139*8640cc11SPhilippe Mathieu-Daudé g_free(name); 140*8640cc11SPhilippe Mathieu-Daudé } 141*8640cc11SPhilippe Mathieu-Daudé 142*8640cc11SPhilippe Mathieu-Daudé return g_test_run(); 143*8640cc11SPhilippe Mathieu-Daudé } 144