qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

hw/sd/aspeed_sdhci: New device

The Aspeed SOCs have two SD/MMC controllers. Add a device that
encapsulates both of these controllers and models the Aspeed-specific
registers and behavior.

Tested by reading from mmcblk0 in Linux:
qemu-system-arm -machine romulus-bmc -nographic \
-drive file=flash-romulus,format=raw,if=mtd \
-device sd-card,drive=sd0 -drive file=_tmp/kernel,format=raw,if=sd,id=sd0

Signed-off-by: Eddie James <eajames@linux.ibm.com>
Reviewed-by: Cédric Le Goater <clg@kaod.org>
Reviewed-by: Joel Stanley <joel@jms.id.au>
Signed-off-by: Cédric Le Goater <clg@kaod.org>
Message-id: 20190925143248.10000-3-clg@kaod.org
[clg: - changed the controller MMIO window size to 0x1000
- moved the MMIO mapping of the SDHCI slots at the SoC level
- merged code to add SD drives on the SD buses at the machine level ]
Signed-off-by: Cédric Le Goater <clg@kaod.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

authored by

Eddie James and committed by
Peter Maydell
2bea128c 1ff68783

+273 -1
+14 -1
hw/arm/aspeed.c
··· 170 170 AspeedSoCClass *sc; 171 171 DriveInfo *drive0 = drive_get(IF_MTD, 0, 0); 172 172 ram_addr_t max_ram_size; 173 + int i; 173 174 174 175 bmc = g_new0(AspeedBoardState, 1); 175 176 ··· 250 251 251 252 if (cfg->i2c_init) { 252 253 cfg->i2c_init(bmc); 254 + } 255 + 256 + for (i = 0; i < ARRAY_SIZE(bmc->soc.sdhci.slots); i++) { 257 + SDHCIState *sdhci = &bmc->soc.sdhci.slots[i]; 258 + DriveInfo *dinfo = drive_get_next(IF_SD); 259 + BlockBackend *blk; 260 + DeviceState *card; 261 + 262 + blk = dinfo ? blk_by_legacy_dinfo(dinfo) : NULL; 263 + card = qdev_create(qdev_get_child_bus(DEVICE(sdhci), "sd-bus"), 264 + TYPE_SD_CARD); 265 + qdev_prop_set_drive(card, "drive", blk, &error_fatal); 266 + object_property_set_bool(OBJECT(card), true, "realized", &error_fatal); 253 267 } 254 268 255 269 arm_load_kernel(ARM_CPU(first_cpu), machine, &aspeed_board_binfo); ··· 373 387 mc->desc = board->desc; 374 388 mc->init = aspeed_machine_init; 375 389 mc->max_cpus = ASPEED_CPUS_NUM; 376 - mc->no_sdcard = 1; 377 390 mc->no_floppy = 1; 378 391 mc->no_cdrom = 1; 379 392 mc->no_parallel = 1;
+23
hw/arm/aspeed_soc.c
··· 36 36 [ASPEED_XDMA] = 0x1E6E7000, 37 37 [ASPEED_ADC] = 0x1E6E9000, 38 38 [ASPEED_SRAM] = 0x1E720000, 39 + [ASPEED_SDHCI] = 0x1E740000, 39 40 [ASPEED_GPIO] = 0x1E780000, 40 41 [ASPEED_RTC] = 0x1E781000, 41 42 [ASPEED_TIMER1] = 0x1E782000, ··· 63 64 [ASPEED_XDMA] = 0x1E6E7000, 64 65 [ASPEED_ADC] = 0x1E6E9000, 65 66 [ASPEED_SRAM] = 0x1E720000, 67 + [ASPEED_SDHCI] = 0x1E740000, 66 68 [ASPEED_GPIO] = 0x1E780000, 67 69 [ASPEED_RTC] = 0x1E781000, 68 70 [ASPEED_TIMER1] = 0x1E782000, ··· 108 110 [ASPEED_ETH1] = 2, 109 111 [ASPEED_ETH2] = 3, 110 112 [ASPEED_XDMA] = 6, 113 + [ASPEED_SDHCI] = 26, 111 114 }; 112 115 113 116 #define aspeed_soc_ast2500_irqmap aspeed_soc_ast2400_irqmap ··· 230 233 snprintf(typename, sizeof(typename), "aspeed.gpio-%s", socname); 231 234 sysbus_init_child_obj(obj, "gpio", OBJECT(&s->gpio), sizeof(s->gpio), 232 235 typename); 236 + 237 + sysbus_init_child_obj(obj, "sdc", OBJECT(&s->sdhci), sizeof(s->sdhci), 238 + TYPE_ASPEED_SDHCI); 239 + 240 + /* Init sd card slot class here so that they're under the correct parent */ 241 + for (i = 0; i < ASPEED_SDHCI_NUM_SLOTS; ++i) { 242 + sysbus_init_child_obj(obj, "sdhci[*]", OBJECT(&s->sdhci.slots[i]), 243 + sizeof(s->sdhci.slots[i]), TYPE_SYSBUS_SDHCI); 244 + } 233 245 } 234 246 235 247 static void aspeed_soc_realize(DeviceState *dev, Error **errp) ··· 419 431 sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio), 0, sc->info->memmap[ASPEED_GPIO]); 420 432 sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio), 0, 421 433 aspeed_soc_get_irq(s, ASPEED_GPIO)); 434 + 435 + /* SDHCI */ 436 + object_property_set_bool(OBJECT(&s->sdhci), true, "realized", &err); 437 + if (err) { 438 + error_propagate(errp, err); 439 + return; 440 + } 441 + sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdhci), 0, 442 + sc->info->memmap[ASPEED_SDHCI]); 443 + sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdhci), 0, 444 + aspeed_soc_get_irq(s, ASPEED_SDHCI)); 422 445 } 423 446 static Property aspeed_soc_properties[] = { 424 447 DEFINE_PROP_UINT32("num-cpus", AspeedSoCState, num_cpus, 0),
+1
hw/sd/Makefile.objs
··· 8 8 obj-$(CONFIG_OMAP) += omap_mmc.o 9 9 obj-$(CONFIG_PXA2XX) += pxa2xx_mmci.o 10 10 obj-$(CONFIG_RASPI) += bcm2835_sdhost.o 11 + obj-$(CONFIG_ASPEED_SOC) += aspeed_sdhci.o
+198
hw/sd/aspeed_sdhci.c
··· 1 + /* 2 + * Aspeed SD Host Controller 3 + * Eddie James <eajames@linux.ibm.com> 4 + * 5 + * Copyright (C) 2019 IBM Corp 6 + * SPDX-License-Identifer: GPL-2.0-or-later 7 + */ 8 + 9 + #include "qemu/osdep.h" 10 + #include "qemu/log.h" 11 + #include "qemu/error-report.h" 12 + #include "hw/sd/aspeed_sdhci.h" 13 + #include "qapi/error.h" 14 + #include "hw/irq.h" 15 + #include "migration/vmstate.h" 16 + 17 + #define ASPEED_SDHCI_INFO 0x00 18 + #define ASPEED_SDHCI_INFO_RESET 0x00030000 19 + #define ASPEED_SDHCI_DEBOUNCE 0x04 20 + #define ASPEED_SDHCI_DEBOUNCE_RESET 0x00000005 21 + #define ASPEED_SDHCI_BUS 0x08 22 + #define ASPEED_SDHCI_SDIO_140 0x10 23 + #define ASPEED_SDHCI_SDIO_148 0x18 24 + #define ASPEED_SDHCI_SDIO_240 0x20 25 + #define ASPEED_SDHCI_SDIO_248 0x28 26 + #define ASPEED_SDHCI_WP_POL 0xec 27 + #define ASPEED_SDHCI_CARD_DET 0xf0 28 + #define ASPEED_SDHCI_IRQ_STAT 0xfc 29 + 30 + #define TO_REG(addr) ((addr) / sizeof(uint32_t)) 31 + 32 + static uint64_t aspeed_sdhci_read(void *opaque, hwaddr addr, unsigned int size) 33 + { 34 + uint32_t val = 0; 35 + AspeedSDHCIState *sdhci = opaque; 36 + 37 + switch (addr) { 38 + case ASPEED_SDHCI_SDIO_140: 39 + val = (uint32_t)sdhci->slots[0].capareg; 40 + break; 41 + case ASPEED_SDHCI_SDIO_148: 42 + val = (uint32_t)sdhci->slots[0].maxcurr; 43 + break; 44 + case ASPEED_SDHCI_SDIO_240: 45 + val = (uint32_t)sdhci->slots[1].capareg; 46 + break; 47 + case ASPEED_SDHCI_SDIO_248: 48 + val = (uint32_t)sdhci->slots[1].maxcurr; 49 + break; 50 + default: 51 + if (addr < ASPEED_SDHCI_REG_SIZE) { 52 + val = sdhci->regs[TO_REG(addr)]; 53 + } else { 54 + qemu_log_mask(LOG_GUEST_ERROR, 55 + "%s: Out-of-bounds read at 0x%" HWADDR_PRIx "\n", 56 + __func__, addr); 57 + } 58 + } 59 + 60 + return (uint64_t)val; 61 + } 62 + 63 + static void aspeed_sdhci_write(void *opaque, hwaddr addr, uint64_t val, 64 + unsigned int size) 65 + { 66 + AspeedSDHCIState *sdhci = opaque; 67 + 68 + switch (addr) { 69 + case ASPEED_SDHCI_SDIO_140: 70 + sdhci->slots[0].capareg = (uint64_t)(uint32_t)val; 71 + break; 72 + case ASPEED_SDHCI_SDIO_148: 73 + sdhci->slots[0].maxcurr = (uint64_t)(uint32_t)val; 74 + break; 75 + case ASPEED_SDHCI_SDIO_240: 76 + sdhci->slots[1].capareg = (uint64_t)(uint32_t)val; 77 + break; 78 + case ASPEED_SDHCI_SDIO_248: 79 + sdhci->slots[1].maxcurr = (uint64_t)(uint32_t)val; 80 + break; 81 + default: 82 + if (addr < ASPEED_SDHCI_REG_SIZE) { 83 + sdhci->regs[TO_REG(addr)] = (uint32_t)val; 84 + } else { 85 + qemu_log_mask(LOG_GUEST_ERROR, 86 + "%s: Out-of-bounds write at 0x%" HWADDR_PRIx "\n", 87 + __func__, addr); 88 + } 89 + } 90 + } 91 + 92 + static const MemoryRegionOps aspeed_sdhci_ops = { 93 + .read = aspeed_sdhci_read, 94 + .write = aspeed_sdhci_write, 95 + .endianness = DEVICE_NATIVE_ENDIAN, 96 + .valid.min_access_size = 4, 97 + .valid.max_access_size = 4, 98 + }; 99 + 100 + static void aspeed_sdhci_set_irq(void *opaque, int n, int level) 101 + { 102 + AspeedSDHCIState *sdhci = opaque; 103 + 104 + if (level) { 105 + sdhci->regs[TO_REG(ASPEED_SDHCI_IRQ_STAT)] |= BIT(n); 106 + 107 + qemu_irq_raise(sdhci->irq); 108 + } else { 109 + sdhci->regs[TO_REG(ASPEED_SDHCI_IRQ_STAT)] &= ~BIT(n); 110 + 111 + qemu_irq_lower(sdhci->irq); 112 + } 113 + } 114 + 115 + static void aspeed_sdhci_realize(DeviceState *dev, Error **errp) 116 + { 117 + Error *err = NULL; 118 + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 119 + AspeedSDHCIState *sdhci = ASPEED_SDHCI(dev); 120 + 121 + /* Create input irqs for the slots */ 122 + qdev_init_gpio_in_named_with_opaque(DEVICE(sbd), aspeed_sdhci_set_irq, 123 + sdhci, NULL, ASPEED_SDHCI_NUM_SLOTS); 124 + 125 + sysbus_init_irq(sbd, &sdhci->irq); 126 + memory_region_init_io(&sdhci->iomem, OBJECT(sdhci), &aspeed_sdhci_ops, 127 + sdhci, TYPE_ASPEED_SDHCI, 0x1000); 128 + sysbus_init_mmio(sbd, &sdhci->iomem); 129 + 130 + for (int i = 0; i < ASPEED_SDHCI_NUM_SLOTS; ++i) { 131 + Object *sdhci_slot = OBJECT(&sdhci->slots[i]); 132 + SysBusDevice *sbd_slot = SYS_BUS_DEVICE(&sdhci->slots[i]); 133 + 134 + object_property_set_int(sdhci_slot, 2, "sd-spec-version", &err); 135 + if (err) { 136 + error_propagate(errp, err); 137 + return; 138 + } 139 + 140 + object_property_set_uint(sdhci_slot, ASPEED_SDHCI_CAPABILITIES, 141 + "capareg", &err); 142 + if (err) { 143 + error_propagate(errp, err); 144 + return; 145 + } 146 + 147 + object_property_set_bool(sdhci_slot, true, "realized", &err); 148 + if (err) { 149 + error_propagate(errp, err); 150 + return; 151 + } 152 + 153 + sysbus_connect_irq(sbd_slot, 0, qdev_get_gpio_in(DEVICE(sbd), i)); 154 + memory_region_add_subregion(&sdhci->iomem, (i + 1) * 0x100, 155 + &sdhci->slots[i].iomem); 156 + } 157 + } 158 + 159 + static void aspeed_sdhci_reset(DeviceState *dev) 160 + { 161 + AspeedSDHCIState *sdhci = ASPEED_SDHCI(dev); 162 + 163 + memset(sdhci->regs, 0, ASPEED_SDHCI_REG_SIZE); 164 + sdhci->regs[TO_REG(ASPEED_SDHCI_INFO)] = ASPEED_SDHCI_INFO_RESET; 165 + sdhci->regs[TO_REG(ASPEED_SDHCI_DEBOUNCE)] = ASPEED_SDHCI_DEBOUNCE_RESET; 166 + } 167 + 168 + static const VMStateDescription vmstate_aspeed_sdhci = { 169 + .name = TYPE_ASPEED_SDHCI, 170 + .version_id = 1, 171 + .fields = (VMStateField[]) { 172 + VMSTATE_UINT32_ARRAY(regs, AspeedSDHCIState, ASPEED_SDHCI_NUM_REGS), 173 + VMSTATE_END_OF_LIST(), 174 + }, 175 + }; 176 + 177 + static void aspeed_sdhci_class_init(ObjectClass *classp, void *data) 178 + { 179 + DeviceClass *dc = DEVICE_CLASS(classp); 180 + 181 + dc->realize = aspeed_sdhci_realize; 182 + dc->reset = aspeed_sdhci_reset; 183 + dc->vmsd = &vmstate_aspeed_sdhci; 184 + } 185 + 186 + static TypeInfo aspeed_sdhci_info = { 187 + .name = TYPE_ASPEED_SDHCI, 188 + .parent = TYPE_SYS_BUS_DEVICE, 189 + .instance_size = sizeof(AspeedSDHCIState), 190 + .class_init = aspeed_sdhci_class_init, 191 + }; 192 + 193 + static void aspeed_sdhci_register_types(void) 194 + { 195 + type_register_static(&aspeed_sdhci_info); 196 + } 197 + 198 + type_init(aspeed_sdhci_register_types)
+3
include/hw/arm/aspeed_soc.h
··· 24 24 #include "hw/net/ftgmac100.h" 25 25 #include "target/arm/cpu.h" 26 26 #include "hw/gpio/aspeed_gpio.h" 27 + #include "hw/sd/aspeed_sdhci.h" 27 28 28 29 #define ASPEED_SPIS_NUM 2 29 30 #define ASPEED_WDTS_NUM 3 ··· 50 51 AspeedWDTState wdt[ASPEED_WDTS_NUM]; 51 52 FTGMAC100State ftgmac100[ASPEED_MACS_NUM]; 52 53 AspeedGPIOState gpio; 54 + AspeedSDHCIState sdhci; 53 55 } AspeedSoCState; 54 56 55 57 #define TYPE_ASPEED_SOC "aspeed-soc" ··· 93 95 ASPEED_SCU, 94 96 ASPEED_ADC, 95 97 ASPEED_SRAM, 98 + ASPEED_SDHCI, 96 99 ASPEED_GPIO, 97 100 ASPEED_RTC, 98 101 ASPEED_TIMER1,
+34
include/hw/sd/aspeed_sdhci.h
··· 1 + /* 2 + * Aspeed SD Host Controller 3 + * Eddie James <eajames@linux.ibm.com> 4 + * 5 + * Copyright (C) 2019 IBM Corp 6 + * SPDX-License-Identifer: GPL-2.0-or-later 7 + */ 8 + 9 + #ifndef ASPEED_SDHCI_H 10 + #define ASPEED_SDHCI_H 11 + 12 + #include "hw/sd/sdhci.h" 13 + 14 + #define TYPE_ASPEED_SDHCI "aspeed.sdhci" 15 + #define ASPEED_SDHCI(obj) OBJECT_CHECK(AspeedSDHCIState, (obj), \ 16 + TYPE_ASPEED_SDHCI) 17 + 18 + #define ASPEED_SDHCI_CAPABILITIES 0x01E80080 19 + #define ASPEED_SDHCI_NUM_SLOTS 2 20 + #define ASPEED_SDHCI_NUM_REGS (ASPEED_SDHCI_REG_SIZE / sizeof(uint32_t)) 21 + #define ASPEED_SDHCI_REG_SIZE 0x100 22 + 23 + typedef struct AspeedSDHCIState { 24 + SysBusDevice parent; 25 + 26 + SDHCIState slots[ASPEED_SDHCI_NUM_SLOTS]; 27 + 28 + MemoryRegion iomem; 29 + qemu_irq irq; 30 + 31 + uint32_t regs[ASPEED_SDHCI_NUM_REGS]; 32 + } AspeedSDHCIState; 33 + 34 + #endif /* ASPEED_SDHCI_H */