xref: /openbmc/qemu/tests/qtest/libqos/sdhci.c (revision 2e3408b3cc7de4e87a9adafc8c19bfce3abec947)
11cf4323eSThomas Huth /*
21cf4323eSThomas Huth  * libqos driver framework
31cf4323eSThomas Huth  *
41cf4323eSThomas Huth  * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
51cf4323eSThomas Huth  *
61cf4323eSThomas Huth  * This library is free software; you can redistribute it and/or
71cf4323eSThomas Huth  * modify it under the terms of the GNU Lesser General Public
8dc0ad02dSThomas Huth  * License version 2.1 as published by the Free Software Foundation.
91cf4323eSThomas Huth  *
101cf4323eSThomas Huth  * This library is distributed in the hope that it will be useful,
111cf4323eSThomas Huth  * but WITHOUT ANY WARRANTY; without even the implied warranty of
121cf4323eSThomas Huth  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
131cf4323eSThomas Huth  * Lesser General Public License for more details.
141cf4323eSThomas Huth  *
151cf4323eSThomas Huth  * You should have received a copy of the GNU Lesser General Public
161cf4323eSThomas Huth  * License along with this library; if not, see <http://www.gnu.org/licenses/>
171cf4323eSThomas Huth  */
181cf4323eSThomas Huth 
191cf4323eSThomas Huth #include "qemu/osdep.h"
20*907b5105SMarc-André Lureau #include "../libqtest.h"
21a2ce7dbdSPaolo Bonzini #include "qgraph.h"
221cf4323eSThomas Huth #include "pci.h"
231cf4323eSThomas Huth #include "qemu/module.h"
241cf4323eSThomas Huth #include "sdhci.h"
251cf4323eSThomas Huth #include "hw/pci/pci.h"
261cf4323eSThomas Huth 
set_qsdhci_fields(QSDHCI * s,uint8_t version,uint8_t baseclock,bool sdma,uint64_t reg)271cf4323eSThomas Huth static void set_qsdhci_fields(QSDHCI *s, uint8_t version, uint8_t baseclock,
281cf4323eSThomas Huth                               bool sdma, uint64_t reg)
291cf4323eSThomas Huth {
301cf4323eSThomas Huth     s->props.version = version;
311cf4323eSThomas Huth     s->props.baseclock = baseclock;
321cf4323eSThomas Huth     s->props.capab.sdma = sdma;
331cf4323eSThomas Huth     s->props.capab.reg = reg;
341cf4323eSThomas Huth }
351cf4323eSThomas Huth 
361cf4323eSThomas Huth /* Memory mapped implementation of QSDHCI */
371cf4323eSThomas Huth 
sdhci_mm_readw(QSDHCI * s,uint32_t reg)381cf4323eSThomas Huth static uint16_t sdhci_mm_readw(QSDHCI *s, uint32_t reg)
391cf4323eSThomas Huth {
401cf4323eSThomas Huth     QSDHCI_MemoryMapped *smm = container_of(s, QSDHCI_MemoryMapped, sdhci);
411cf4323eSThomas Huth     return qtest_readw(smm->qts, smm->addr + reg);
421cf4323eSThomas Huth }
431cf4323eSThomas Huth 
sdhci_mm_readq(QSDHCI * s,uint32_t reg)441cf4323eSThomas Huth static uint64_t sdhci_mm_readq(QSDHCI *s, uint32_t reg)
451cf4323eSThomas Huth {
461cf4323eSThomas Huth     QSDHCI_MemoryMapped *smm = container_of(s, QSDHCI_MemoryMapped, sdhci);
471cf4323eSThomas Huth     return qtest_readq(smm->qts, smm->addr + reg);
481cf4323eSThomas Huth }
491cf4323eSThomas Huth 
sdhci_mm_writeq(QSDHCI * s,uint32_t reg,uint64_t val)501cf4323eSThomas Huth static void sdhci_mm_writeq(QSDHCI *s, uint32_t reg, uint64_t val)
511cf4323eSThomas Huth {
521cf4323eSThomas Huth     QSDHCI_MemoryMapped *smm = container_of(s, QSDHCI_MemoryMapped, sdhci);
531cf4323eSThomas Huth     qtest_writeq(smm->qts, smm->addr + reg, val);
541cf4323eSThomas Huth }
551cf4323eSThomas Huth 
sdhci_mm_get_driver(void * obj,const char * interface)561cf4323eSThomas Huth static void *sdhci_mm_get_driver(void *obj, const char *interface)
571cf4323eSThomas Huth {
581cf4323eSThomas Huth     QSDHCI_MemoryMapped *smm = obj;
591cf4323eSThomas Huth     if (!g_strcmp0(interface, "sdhci")) {
601cf4323eSThomas Huth         return &smm->sdhci;
611cf4323eSThomas Huth     }
621cf4323eSThomas Huth     fprintf(stderr, "%s not present in generic-sdhci\n", interface);
631cf4323eSThomas Huth     g_assert_not_reached();
641cf4323eSThomas Huth }
651cf4323eSThomas Huth 
qos_init_sdhci_mm(QSDHCI_MemoryMapped * sdhci,QTestState * qts,uint32_t addr,QSDHCIProperties * common)661cf4323eSThomas Huth void qos_init_sdhci_mm(QSDHCI_MemoryMapped *sdhci, QTestState *qts,
671cf4323eSThomas Huth                        uint32_t addr, QSDHCIProperties *common)
681cf4323eSThomas Huth {
691cf4323eSThomas Huth     sdhci->obj.get_driver = sdhci_mm_get_driver;
701cf4323eSThomas Huth     sdhci->sdhci.readw = sdhci_mm_readw;
711cf4323eSThomas Huth     sdhci->sdhci.readq = sdhci_mm_readq;
721cf4323eSThomas Huth     sdhci->sdhci.writeq = sdhci_mm_writeq;
731cf4323eSThomas Huth     memcpy(&sdhci->sdhci.props, common, sizeof(QSDHCIProperties));
741cf4323eSThomas Huth     sdhci->addr = addr;
751cf4323eSThomas Huth     sdhci->qts = qts;
761cf4323eSThomas Huth }
771cf4323eSThomas Huth 
781cf4323eSThomas Huth /* PCI implementation of QSDHCI */
791cf4323eSThomas Huth 
sdhci_pci_readw(QSDHCI * s,uint32_t reg)801cf4323eSThomas Huth static uint16_t sdhci_pci_readw(QSDHCI *s, uint32_t reg)
811cf4323eSThomas Huth {
821cf4323eSThomas Huth     QSDHCI_PCI *spci = container_of(s, QSDHCI_PCI, sdhci);
831cf4323eSThomas Huth     return qpci_io_readw(&spci->dev, spci->mem_bar, reg);
841cf4323eSThomas Huth }
851cf4323eSThomas Huth 
sdhci_pci_readq(QSDHCI * s,uint32_t reg)861cf4323eSThomas Huth static uint64_t sdhci_pci_readq(QSDHCI *s, uint32_t reg)
871cf4323eSThomas Huth {
881cf4323eSThomas Huth     QSDHCI_PCI *spci = container_of(s, QSDHCI_PCI, sdhci);
891cf4323eSThomas Huth     return qpci_io_readq(&spci->dev, spci->mem_bar, reg);
901cf4323eSThomas Huth }
911cf4323eSThomas Huth 
sdhci_pci_writeq(QSDHCI * s,uint32_t reg,uint64_t val)921cf4323eSThomas Huth static void sdhci_pci_writeq(QSDHCI *s, uint32_t reg, uint64_t val)
931cf4323eSThomas Huth {
941cf4323eSThomas Huth     QSDHCI_PCI *spci = container_of(s, QSDHCI_PCI, sdhci);
951cf4323eSThomas Huth     return qpci_io_writeq(&spci->dev, spci->mem_bar, reg, val);
961cf4323eSThomas Huth }
971cf4323eSThomas Huth 
sdhci_pci_get_driver(void * object,const char * interface)981cf4323eSThomas Huth static void *sdhci_pci_get_driver(void *object, const char *interface)
991cf4323eSThomas Huth {
1001cf4323eSThomas Huth     QSDHCI_PCI *spci = object;
1011cf4323eSThomas Huth     if (!g_strcmp0(interface, "sdhci")) {
1021cf4323eSThomas Huth         return &spci->sdhci;
1031cf4323eSThomas Huth     }
1041cf4323eSThomas Huth 
1051cf4323eSThomas Huth     fprintf(stderr, "%s not present in sdhci-pci\n", interface);
1061cf4323eSThomas Huth     g_assert_not_reached();
1071cf4323eSThomas Huth }
1081cf4323eSThomas Huth 
sdhci_pci_start_hw(QOSGraphObject * obj)1091cf4323eSThomas Huth static void sdhci_pci_start_hw(QOSGraphObject *obj)
1101cf4323eSThomas Huth {
1111cf4323eSThomas Huth     QSDHCI_PCI *spci = (QSDHCI_PCI *)obj;
1121cf4323eSThomas Huth     qpci_device_enable(&spci->dev);
1131cf4323eSThomas Huth }
1141cf4323eSThomas Huth 
sdhci_destructor(QOSGraphObject * obj)1151cf4323eSThomas Huth static void sdhci_destructor(QOSGraphObject *obj)
1161cf4323eSThomas Huth {
1171cf4323eSThomas Huth     QSDHCI_PCI *spci = (QSDHCI_PCI *)obj;
1181cf4323eSThomas Huth     qpci_iounmap(&spci->dev, spci->mem_bar);
1191cf4323eSThomas Huth }
1201cf4323eSThomas Huth 
sdhci_pci_create(void * pci_bus,QGuestAllocator * alloc,void * addr)1211cf4323eSThomas Huth static void *sdhci_pci_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
1221cf4323eSThomas Huth {
1231cf4323eSThomas Huth     QSDHCI_PCI *spci = g_new0(QSDHCI_PCI, 1);
1241cf4323eSThomas Huth     QPCIBus *bus = pci_bus;
1251cf4323eSThomas Huth     uint64_t barsize;
1261cf4323eSThomas Huth 
1271cf4323eSThomas Huth     qpci_device_init(&spci->dev, bus, addr);
1281cf4323eSThomas Huth     spci->mem_bar = qpci_iomap(&spci->dev, 0, &barsize);
1291cf4323eSThomas Huth     spci->sdhci.readw = sdhci_pci_readw;
1301cf4323eSThomas Huth     spci->sdhci.readq = sdhci_pci_readq;
1311cf4323eSThomas Huth     spci->sdhci.writeq = sdhci_pci_writeq;
1321cf4323eSThomas Huth     set_qsdhci_fields(&spci->sdhci, 2, 0, 1, 0x057834b4);
1331cf4323eSThomas Huth 
1341cf4323eSThomas Huth     spci->obj.get_driver = sdhci_pci_get_driver;
1351cf4323eSThomas Huth     spci->obj.start_hw = sdhci_pci_start_hw;
1361cf4323eSThomas Huth     spci->obj.destructor = sdhci_destructor;
1371cf4323eSThomas Huth     return &spci->obj;
1381cf4323eSThomas Huth }
1391cf4323eSThomas Huth 
qsdhci_register_nodes(void)1401cf4323eSThomas Huth static void qsdhci_register_nodes(void)
1411cf4323eSThomas Huth {
1421cf4323eSThomas Huth     QPCIAddress addr = {
1431cf4323eSThomas Huth         .devfn = QPCI_DEVFN(4, 0),
1441cf4323eSThomas Huth         .vendor_id = PCI_VENDOR_ID_REDHAT,
1451cf4323eSThomas Huth         .device_id = PCI_DEVICE_ID_REDHAT_SDHCI,
1461cf4323eSThomas Huth     };
1471cf4323eSThomas Huth 
1481cf4323eSThomas Huth     QOSGraphEdgeOptions opts = {
1491cf4323eSThomas Huth         .extra_device_opts = "addr=04.0",
1501cf4323eSThomas Huth     };
1511cf4323eSThomas Huth 
1521cf4323eSThomas Huth     /* generic-sdhci */
1531cf4323eSThomas Huth     qos_node_create_driver("generic-sdhci", NULL);
1541cf4323eSThomas Huth     qos_node_produces("generic-sdhci", "sdhci");
1551cf4323eSThomas Huth 
1561cf4323eSThomas Huth     /* sdhci-pci */
1571cf4323eSThomas Huth     add_qpci_address(&opts, &addr);
1581cf4323eSThomas Huth     qos_node_create_driver("sdhci-pci", sdhci_pci_create);
1591cf4323eSThomas Huth     qos_node_produces("sdhci-pci", "sdhci");
1601cf4323eSThomas Huth     qos_node_consumes("sdhci-pci", "pci-bus", &opts);
1611cf4323eSThomas Huth 
1621cf4323eSThomas Huth }
1631cf4323eSThomas Huth 
1641cf4323eSThomas Huth libqos_init(qsdhci_register_nodes);
165