qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

sdhci.c (4910B)


      1 /*
      2  * libqos driver framework
      3  *
      4  * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
      5  *
      6  * This library is free software; you can redistribute it and/or
      7  * modify it under the terms of the GNU Lesser General Public
      8  * License version 2.1 as published by the Free Software Foundation.
      9  *
     10  * This library is distributed in the hope that it will be useful,
     11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13  * Lesser General Public License for more details.
     14  *
     15  * You should have received a copy of the GNU Lesser General Public
     16  * License along with this library; if not, see <http://www.gnu.org/licenses/>
     17  */
     18 
     19 #include "qemu/osdep.h"
     20 #include "../libqtest.h"
     21 #include "qgraph.h"
     22 #include "pci.h"
     23 #include "qemu/module.h"
     24 #include "sdhci.h"
     25 #include "hw/pci/pci.h"
     26 
     27 static void set_qsdhci_fields(QSDHCI *s, uint8_t version, uint8_t baseclock,
     28                               bool sdma, uint64_t reg)
     29 {
     30     s->props.version = version;
     31     s->props.baseclock = baseclock;
     32     s->props.capab.sdma = sdma;
     33     s->props.capab.reg = reg;
     34 }
     35 
     36 /* Memory mapped implementation of QSDHCI */
     37 
     38 static uint16_t sdhci_mm_readw(QSDHCI *s, uint32_t reg)
     39 {
     40     QSDHCI_MemoryMapped *smm = container_of(s, QSDHCI_MemoryMapped, sdhci);
     41     return qtest_readw(smm->qts, smm->addr + reg);
     42 }
     43 
     44 static uint64_t sdhci_mm_readq(QSDHCI *s, uint32_t reg)
     45 {
     46     QSDHCI_MemoryMapped *smm = container_of(s, QSDHCI_MemoryMapped, sdhci);
     47     return qtest_readq(smm->qts, smm->addr + reg);
     48 }
     49 
     50 static void sdhci_mm_writeq(QSDHCI *s, uint32_t reg, uint64_t val)
     51 {
     52     QSDHCI_MemoryMapped *smm = container_of(s, QSDHCI_MemoryMapped, sdhci);
     53     qtest_writeq(smm->qts, smm->addr + reg, val);
     54 }
     55 
     56 static void *sdhci_mm_get_driver(void *obj, const char *interface)
     57 {
     58     QSDHCI_MemoryMapped *smm = obj;
     59     if (!g_strcmp0(interface, "sdhci")) {
     60         return &smm->sdhci;
     61     }
     62     fprintf(stderr, "%s not present in generic-sdhci\n", interface);
     63     g_assert_not_reached();
     64 }
     65 
     66 void qos_init_sdhci_mm(QSDHCI_MemoryMapped *sdhci, QTestState *qts,
     67                        uint32_t addr, QSDHCIProperties *common)
     68 {
     69     sdhci->obj.get_driver = sdhci_mm_get_driver;
     70     sdhci->sdhci.readw = sdhci_mm_readw;
     71     sdhci->sdhci.readq = sdhci_mm_readq;
     72     sdhci->sdhci.writeq = sdhci_mm_writeq;
     73     memcpy(&sdhci->sdhci.props, common, sizeof(QSDHCIProperties));
     74     sdhci->addr = addr;
     75     sdhci->qts = qts;
     76 }
     77 
     78 /* PCI implementation of QSDHCI */
     79 
     80 static uint16_t sdhci_pci_readw(QSDHCI *s, uint32_t reg)
     81 {
     82     QSDHCI_PCI *spci = container_of(s, QSDHCI_PCI, sdhci);
     83     return qpci_io_readw(&spci->dev, spci->mem_bar, reg);
     84 }
     85 
     86 static uint64_t sdhci_pci_readq(QSDHCI *s, uint32_t reg)
     87 {
     88     QSDHCI_PCI *spci = container_of(s, QSDHCI_PCI, sdhci);
     89     return qpci_io_readq(&spci->dev, spci->mem_bar, reg);
     90 }
     91 
     92 static void sdhci_pci_writeq(QSDHCI *s, uint32_t reg, uint64_t val)
     93 {
     94     QSDHCI_PCI *spci = container_of(s, QSDHCI_PCI, sdhci);
     95     return qpci_io_writeq(&spci->dev, spci->mem_bar, reg, val);
     96 }
     97 
     98 static void *sdhci_pci_get_driver(void *object, const char *interface)
     99 {
    100     QSDHCI_PCI *spci = object;
    101     if (!g_strcmp0(interface, "sdhci")) {
    102         return &spci->sdhci;
    103     }
    104 
    105     fprintf(stderr, "%s not present in sdhci-pci\n", interface);
    106     g_assert_not_reached();
    107 }
    108 
    109 static void sdhci_pci_start_hw(QOSGraphObject *obj)
    110 {
    111     QSDHCI_PCI *spci = (QSDHCI_PCI *)obj;
    112     qpci_device_enable(&spci->dev);
    113 }
    114 
    115 static void sdhci_destructor(QOSGraphObject *obj)
    116 {
    117     QSDHCI_PCI *spci = (QSDHCI_PCI *)obj;
    118     qpci_iounmap(&spci->dev, spci->mem_bar);
    119 }
    120 
    121 static void *sdhci_pci_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
    122 {
    123     QSDHCI_PCI *spci = g_new0(QSDHCI_PCI, 1);
    124     QPCIBus *bus = pci_bus;
    125     uint64_t barsize;
    126 
    127     qpci_device_init(&spci->dev, bus, addr);
    128     spci->mem_bar = qpci_iomap(&spci->dev, 0, &barsize);
    129     spci->sdhci.readw = sdhci_pci_readw;
    130     spci->sdhci.readq = sdhci_pci_readq;
    131     spci->sdhci.writeq = sdhci_pci_writeq;
    132     set_qsdhci_fields(&spci->sdhci, 2, 0, 1, 0x057834b4);
    133 
    134     spci->obj.get_driver = sdhci_pci_get_driver;
    135     spci->obj.start_hw = sdhci_pci_start_hw;
    136     spci->obj.destructor = sdhci_destructor;
    137     return &spci->obj;
    138 }
    139 
    140 static void qsdhci_register_nodes(void)
    141 {
    142     QPCIAddress addr = {
    143         .devfn = QPCI_DEVFN(4, 0),
    144         .vendor_id = PCI_VENDOR_ID_REDHAT,
    145         .device_id = PCI_DEVICE_ID_REDHAT_SDHCI,
    146     };
    147 
    148     QOSGraphEdgeOptions opts = {
    149         .extra_device_opts = "addr=04.0",
    150     };
    151 
    152     /* generic-sdhci */
    153     qos_node_create_driver("generic-sdhci", NULL);
    154     qos_node_produces("generic-sdhci", "sdhci");
    155 
    156     /* sdhci-pci */
    157     add_qpci_address(&opts, &addr);
    158     qos_node_create_driver("sdhci-pci", sdhci_pci_create);
    159     qos_node_produces("sdhci-pci", "sdhci");
    160     qos_node_consumes("sdhci-pci", "pci-bus", &opts);
    161 
    162 }
    163 
    164 libqos_init(qsdhci_register_nodes);