diff options
Diffstat (limited to 'hw')
-rw-r--r-- | hw/arm/xilinx_zynq.c | 17 | ||||
-rw-r--r-- | hw/arm/xlnx-ep108.c | 21 | ||||
-rw-r--r-- | hw/arm/xlnx-zynqmp.c | 8 | ||||
-rw-r--r-- | hw/gpio/pl061.c | 37 | ||||
-rw-r--r-- | hw/sd/Makefile.objs | 2 | ||||
-rw-r--r-- | hw/sd/core.c | 146 | ||||
-rw-r--r-- | hw/sd/pxa2xx_mmci.c | 304 | ||||
-rw-r--r-- | hw/sd/sd.c | 289 | ||||
-rw-r--r-- | hw/sd/sdhci.c | 82 | ||||
-rw-r--r-- | hw/timer/arm_timer.c | 42 | ||||
-rw-r--r-- | hw/timer/exynos4210_mct.c | 12 | ||||
-rw-r--r-- | hw/timer/exynos4210_pwm.c | 12 | ||||
-rw-r--r-- | hw/timer/exynos4210_rtc.c | 12 | ||||
-rw-r--r-- | hw/timer/pl031.c | 11 | ||||
-rw-r--r-- | hw/timer/pxa2xx_timer.c | 36 |
15 files changed, 772 insertions, 259 deletions
diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c index 66e7f27ace..a35983a9ec 100644 --- a/hw/arm/xilinx_zynq.c +++ b/hw/arm/xilinx_zynq.c @@ -28,6 +28,7 @@ #include "hw/misc/zynq-xadc.h" #include "hw/ssi/ssi.h" #include "qemu/error-report.h" +#include "hw/sd/sd.h" #define NUM_SPI_FLASHES 4 #define NUM_QSPI_FLASHES 2 @@ -154,8 +155,10 @@ static void zynq_init(MachineState *machine) MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *ext_ram = g_new(MemoryRegion, 1); MemoryRegion *ocm_ram = g_new(MemoryRegion, 1); - DeviceState *dev; + DeviceState *dev, *carddev; SysBusDevice *busdev; + DriveInfo *di; + BlockBackend *blk; qemu_irq pic[64]; int n; @@ -245,11 +248,23 @@ static void zynq_init(MachineState *machine) sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xE0100000); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[56-IRQ_OFFSET]); + di = drive_get_next(IF_SD); + blk = di ? blk_by_legacy_dinfo(di) : NULL; + carddev = qdev_create(qdev_get_child_bus(dev, "sd-bus"), TYPE_SD_CARD); + qdev_prop_set_drive(carddev, "drive", blk, &error_fatal); + object_property_set_bool(OBJECT(carddev), true, "realized", &error_fatal); + dev = qdev_create(NULL, "generic-sdhci"); qdev_init_nofail(dev); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xE0101000); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[79-IRQ_OFFSET]); + di = drive_get_next(IF_SD); + blk = di ? blk_by_legacy_dinfo(di) : NULL; + carddev = qdev_create(qdev_get_child_bus(dev, "sd-bus"), TYPE_SD_CARD); + qdev_prop_set_drive(carddev, "drive", blk, &error_fatal); + object_property_set_bool(OBJECT(carddev), true, "realized", &error_fatal); + dev = qdev_create(NULL, TYPE_ZYNQ_XADC); qdev_init_nofail(dev); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xF8007100); diff --git a/hw/arm/xlnx-ep108.c b/hw/arm/xlnx-ep108.c index 0de132abd2..a1bd283a52 100644 --- a/hw/arm/xlnx-ep108.c +++ b/hw/arm/xlnx-ep108.c @@ -59,6 +59,27 @@ static void xlnx_ep108_init(MachineState *machine) object_property_set_bool(OBJECT(&s->soc), true, "realized", &error_fatal); + /* Create and plug in the SD cards */ + for (i = 0; i < XLNX_ZYNQMP_NUM_SDHCI; i++) { + BusState *bus; + DriveInfo *di = drive_get_next(IF_SD); + BlockBackend *blk = di ? blk_by_legacy_dinfo(di) : NULL; + DeviceState *carddev; + char *bus_name; + + bus_name = g_strdup_printf("sd-bus%d", i); + bus = qdev_get_child_bus(DEVICE(&s->soc), bus_name); + g_free(bus_name); + if (!bus) { + error_report("No SD bus found for SD card %d", i); + exit(1); + } + carddev = qdev_create(bus, TYPE_SD_CARD); + qdev_prop_set_drive(carddev, "drive", blk, &error_fatal); + object_property_set_bool(OBJECT(carddev), true, "realized", + &error_fatal); + } + for (i = 0; i < XLNX_ZYNQMP_NUM_SPIS; i++) { SSIBus *spi_bus; DeviceState *flash_dev; diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c index 1508d0867d..4fbb63550b 100644 --- a/hw/arm/xlnx-zynqmp.c +++ b/hw/arm/xlnx-zynqmp.c @@ -327,6 +327,8 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) sysbus_connect_irq(SYS_BUS_DEVICE(&s->sata), 0, gic_spi[SATA_INTR]); for (i = 0; i < XLNX_ZYNQMP_NUM_SDHCI; i++) { + char *bus_name; + object_property_set_bool(OBJECT(&s->sdhci[i]), true, "realized", &err); if (err) { @@ -337,6 +339,12 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) sdhci_addr[i]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdhci[i]), 0, gic_spi[sdhci_intr[i]]); + /* Alias controller SD bus to the SoC itself */ + bus_name = g_strdup_printf("sd-bus%d", i); + object_property_add_alias(OBJECT(s), bus_name, + OBJECT(&s->sdhci[i]), "sd-bus", + &error_abort); + g_free(bus_name); } for (i = 0; i < XLNX_ZYNQMP_NUM_SPIS; i++) { diff --git a/hw/gpio/pl061.c b/hw/gpio/pl061.c index e5a696ef43..5ece8b068e 100644 --- a/hw/gpio/pl061.c +++ b/hw/gpio/pl061.c @@ -56,7 +56,6 @@ typedef struct PL061State { uint32_t slr; uint32_t den; uint32_t cr; - uint32_t float_high; uint32_t amsel; qemu_irq irq; qemu_irq out[8]; @@ -65,8 +64,8 @@ typedef struct PL061State { static const VMStateDescription vmstate_pl061 = { .name = "pl061", - .version_id = 3, - .minimum_version_id = 3, + .version_id = 4, + .minimum_version_id = 4, .fields = (VMStateField[]) { VMSTATE_UINT32(locked, PL061State), VMSTATE_UINT32(data, PL061State), @@ -88,7 +87,6 @@ static const VMStateDescription vmstate_pl061 = { VMSTATE_UINT32(slr, PL061State), VMSTATE_UINT32(den, PL061State), VMSTATE_UINT32(cr, PL061State), - VMSTATE_UINT32(float_high, PL061State), VMSTATE_UINT32_V(amsel, PL061State, 2), VMSTATE_END_OF_LIST() } @@ -282,10 +280,32 @@ static void pl061_write(void *opaque, hwaddr offset, pl061_update(s); } -static void pl061_reset(PL061State *s) +static void pl061_reset(DeviceState *dev) { - s->locked = 1; - s->cr = 0xff; + PL061State *s = PL061(dev); + + /* reset values from PL061 TRM, Stellaris LM3S5P31 & LM3S8962 Data Sheet */ + s->data = 0; + s->old_out_data = 0; + s->old_in_data = 0; + s->dir = 0; + s->isense = 0; + s->ibe = 0; + s->iev = 0; + s->im = 0; + s->istate = 0; + s->afsel = 0; + s->dr2r = 0xff; + s->dr4r = 0; + s->dr8r = 0; + s->odr = 0; + s->pur = 0; + s->pdr = 0; + s->slr = 0; + s->den = 0; + s->locked = 1; + s->cr = 0xff; + s->amsel = 0; } static void pl061_set_irq(void * opaque, int irq, int level) @@ -318,7 +338,7 @@ static int pl061_initfn(SysBusDevice *sbd) sysbus_init_irq(sbd, &s->irq); qdev_init_gpio_in(dev, pl061_set_irq, 8); qdev_init_gpio_out(dev, s->out, 8); - pl061_reset(s); + return 0; } @@ -343,6 +363,7 @@ static void pl061_class_init(ObjectClass *klass, void *data) k->init = pl061_initfn; dc->vmsd = &vmstate_pl061; + dc->reset = &pl061_reset; } static const TypeInfo pl061_info = { diff --git a/hw/sd/Makefile.objs b/hw/sd/Makefile.objs index f1aed83d9d..31c83308f2 100644 --- a/hw/sd/Makefile.objs +++ b/hw/sd/Makefile.objs @@ -1,6 +1,6 @@ common-obj-$(CONFIG_PL181) += pl181.o common-obj-$(CONFIG_SSI_SD) += ssi-sd.o -common-obj-$(CONFIG_SD) += sd.o +common-obj-$(CONFIG_SD) += sd.o core.o common-obj-$(CONFIG_SDHCI) += sdhci.o obj-$(CONFIG_MILKYMIST) += milkymist-memcard.o diff --git a/hw/sd/core.c b/hw/sd/core.c new file mode 100644 index 0000000000..14c2bdf27b --- /dev/null +++ b/hw/sd/core.c @@ -0,0 +1,146 @@ +/* + * SD card bus interface code. + * + * Copyright (c) 2015 Linaro Limited + * + * Author: + * Peter Maydell <peter.maydell@linaro.org> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "qemu/osdep.h" +#include "hw/qdev-core.h" +#include "sysemu/block-backend.h" +#include "hw/sd/sd.h" + +static SDState *get_card(SDBus *sdbus) +{ + /* We only ever have one child on the bus so just return it */ + BusChild *kid = QTAILQ_FIRST(&sdbus->qbus.children); + + if (!kid) { + return NULL; + } + return SD_CARD(kid->child); +} + +int sdbus_do_command(SDBus *sdbus, SDRequest *req, uint8_t *response) +{ + SDState *card = get_card(sdbus); + + if (card) { + SDCardClass *sc = SD_CARD_GET_CLASS(card); + + return sc->do_command(card, req, response); + } + + return 0; +} + +void sdbus_write_data(SDBus *sdbus, uint8_t value) +{ + SDState *card = get_card(sdbus); + + if (card) { + SDCardClass *sc = SD_CARD_GET_CLASS(card); + + sc->write_data(card, value); + } +} + +uint8_t sdbus_read_data(SDBus *sdbus) +{ + SDState *card = get_card(sdbus); + + if (card) { + SDCardClass *sc = SD_CARD_GET_CLASS(card); + + return sc->read_data(card); + } + + return 0; +} + +bool sdbus_data_ready(SDBus *sdbus) +{ + SDState *card = get_card(sdbus); + + if (card) { + SDCardClass *sc = SD_CARD_GET_CLASS(card); + + return sc->data_ready(card); + } + + return false; +} + +bool sdbus_get_inserted(SDBus *sdbus) +{ + SDState *card = get_card(sdbus); + + if (card) { + SDCardClass *sc = SD_CARD_GET_CLASS(card); + + return sc->get_inserted(card); + } + + return false; +} + +bool sdbus_get_readonly(SDBus *sdbus) +{ + SDState *card = get_card(sdbus); + + if (card) { + SDCardClass *sc = SD_CARD_GET_CLASS(card); + + return sc->get_readonly(card); + } + + return false; +} + +void sdbus_set_inserted(SDBus *sdbus, bool inserted) +{ + SDBusClass *sbc = SD_BUS_GET_CLASS(sdbus); + BusState *qbus = BUS(sdbus); + + if (sbc->set_inserted) { + sbc->set_inserted(qbus->parent, inserted); + } +} + +void sdbus_set_readonly(SDBus *sdbus, bool readonly) +{ + SDBusClass *sbc = SD_BUS_GET_CLASS(sdbus); + BusState *qbus = BUS(sdbus); + + if (sbc->set_readonly) { + sbc->set_readonly(qbus->parent, readonly); + } +} + +static const TypeInfo sd_bus_info = { + .name = TYPE_SD_BUS, + .parent = TYPE_BUS, + .instance_size = sizeof(SDBus), + .class_size = sizeof(SDBusClass), +}; + +static void sd_bus_register_types(void) +{ + type_register_static(&sd_bus_info); +} + +type_init(sd_bus_register_types) diff --git a/hw/sd/pxa2xx_mmci.c b/hw/sd/pxa2xx_mmci.c index 81da7b7bbd..9c3679b5db 100644 --- a/hw/sd/pxa2xx_mmci.c +++ b/hw/sd/pxa2xx_mmci.c @@ -12,17 +12,31 @@ #include "qemu/osdep.h" #include "hw/hw.h" +#include "hw/sysbus.h" #include "hw/arm/pxa.h" #include "hw/sd/sd.h" #include "hw/qdev.h" +#include "hw/qdev-properties.h" +#include "qemu/error-report.h" + +#define TYPE_PXA2XX_MMCI "pxa2xx-mmci" +#define PXA2XX_MMCI(obj) OBJECT_CHECK(PXA2xxMMCIState, (obj), TYPE_PXA2XX_MMCI) + +#define TYPE_PXA2XX_MMCI_BUS "pxa2xx-mmci-bus" +#define PXA2XX_MMCI_BUS(obj) OBJECT_CHECK(SDBus, (obj), TYPE_PXA2XX_MMCI_BUS) struct PXA2xxMMCIState { + SysBusDevice parent_obj; + MemoryRegion iomem; qemu_irq irq; qemu_irq rx_dma; qemu_irq tx_dma; + qemu_irq inserted; + qemu_irq readonly; - SDState *card; + BlockBackend *blk; + SDBus sdbus; uint32_t status; uint32_t clkrt; @@ -30,25 +44,70 @@ struct PXA2xxMMCIState { uint32_t cmdat; uint32_t resp_tout; uint32_t read_tout; - int blklen; - int numblk; + int32_t blklen; + int32_t numblk; uint32_t intmask; uint32_t intreq; - int cmd; + int32_t cmd; uint32_t arg; - int active; - int bytesleft; + int32_t active; + int32_t bytesleft; uint8_t tx_fifo[64]; - int tx_start; - int tx_len; + uint32_t tx_start; + uint32_t tx_len; uint8_t rx_fifo[32]; - int rx_start; - int rx_len; + uint32_t rx_start; + uint32_t rx_len; uint16_t resp_fifo[9]; - int resp_len; + uint32_t resp_len; - int cmdreq; + int32_t cmdreq; +}; + +static bool pxa2xx_mmci_vmstate_validate(void *opaque, int version_id) +{ + PXA2xxMMCIState *s = opaque; + + return s->tx_start < ARRAY_SIZE(s->tx_fifo) + && s->rx_start < ARRAY_SIZE(s->rx_fifo) + && s->tx_len <= ARRAY_SIZE(s->tx_fifo) + && s->rx_len <= ARRAY_SIZE(s->rx_fifo) + && s->resp_len <= ARRAY_SIZE(s->resp_fifo); +} + + +static const VMStateDescription vmstate_pxa2xx_mmci = { + .name = "pxa2xx-mmci", + .version_id = 2, + .minimum_version_id = 2, + .fields = (VMStateField[]) { + VMSTATE_UINT32(status, PXA2xxMMCIState), + VMSTATE_UINT32(clkrt, PXA2xxMMCIState), + VMSTATE_UINT32(spi, PXA2xxMMCIState), + VMSTATE_UINT32(cmdat, PXA2xxMMCIState), + VMSTATE_UINT32(resp_tout, PXA2xxMMCIState), + VMSTATE_UINT32(read_tout, PXA2xxMMCIState), + VMSTATE_INT32(blklen, PXA2xxMMCIState), + VMSTATE_INT32(numblk, PXA2xxMMCIState), + VMSTATE_UINT32(intmask, PXA2xxMMCIState), + VMSTATE_UINT32(intreq, PXA2xxMMCIState), + VMSTATE_INT32(cmd, PXA2xxMMCIState), + VMSTATE_UINT32(arg, PXA2xxMMCIState), + VMSTATE_INT32(cmdreq, PXA2xxMMCIState), + VMSTATE_INT32(active, PXA2xxMMCIState), + VMSTATE_INT32(bytesleft, PXA2xxMMCIState), + VMSTATE_UINT32(tx_start, PXA2xxMMCIState), + VMSTATE_UINT32(tx_len, PXA2xxMMCIState), + VMSTATE_UINT32(rx_start, PXA2xxMMCIState), + VMSTATE_UINT32(rx_len, PXA2xxMMCIState), + VMSTATE_UINT32(resp_len, PXA2xxMMCIState), + VMSTATE_VALIDATE("fifo size incorrect", pxa2xx_mmci_vmstate_validate), + VMSTATE_UINT8_ARRAY(tx_fifo, PXA2xxMMCIState, 64), + VMSTATE_UINT8_ARRAY(rx_fifo, PXA2xxMMCIState, 32), + VMSTATE_UINT16_ARRAY(resp_fifo, PXA2xxMMCIState, 9), + VMSTATE_END_OF_LIST() + } }; #define MMC_STRPCL 0x00 /* MMC Clock Start/Stop register */ @@ -122,7 +181,7 @@ static void pxa2xx_mmci_fifo_update(PXA2xxMMCIState *s) if (s->cmdat & CMDAT_WR_RD) { while (s->bytesleft && s->tx_len) { - sd_write_data(s->card, s->tx_fifo[s->tx_start ++]); + sdbus_write_data(&s->sdbus, s->tx_fifo[s->tx_start++]); s->tx_start &= 0x1f; s->tx_len --; s->bytesleft --; @@ -132,7 +191,7 @@ static void pxa2xx_mmci_fifo_update(PXA2xxMMCIState *s) } else while (s->bytesleft && s->rx_len < 32) { s->rx_fifo[(s->rx_start + (s->rx_len ++)) & 0x1f] = - sd_read_data(s->card); + sdbus_read_data(&s->sdbus); s->bytesleft --; s->intreq |= INT_RXFIFO_REQ; } @@ -166,7 +225,7 @@ static void pxa2xx_mmci_wakequeues(PXA2xxMMCIState *s) request.arg = s->arg; request.crc = 0; /* FIXME */ - rsplen = sd_do_command(s->card, &request, response); + rsplen = sdbus_do_command(&s->sdbus, &request, response); s->intreq |= INT_END_CMD; memset(s->resp_fifo, 0, sizeof(s->resp_fifo)); @@ -392,114 +451,147 @@ static const MemoryRegionOps pxa2xx_mmci_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static void pxa2xx_mmci_save(QEMUFile *f, void *opaque) +PXA2xxMMCIState *pxa2xx_mmci_init(MemoryRegion *sysmem, + hwaddr base, + BlockBackend *blk, qemu_irq irq, + qemu_irq rx_dma, qemu_irq tx_dma) { - PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque; - int i; - - qemu_put_be32s(f, &s->status); - qemu_put_be32s(f, &s->clkrt); - qemu_put_be32s(f, &s->spi); - qemu_put_be32s(f, &s->cmdat); - qemu_put_be32s(f, &s->resp_tout); - qemu_put_be32s(f, &s->read_tout); - qemu_put_be32(f, s->blklen); - qemu_put_be32(f, s->numblk); - qemu_put_be32s(f, &s->intmask); - qemu_put_be32s(f, &s->intreq); - qemu_put_be32(f, s->cmd); - qemu_put_be32s(f, &s->arg); - qemu_put_be32(f, s->cmdreq); - qemu_put_be32(f, s->active); - qemu_put_be32(f, s->bytesleft); - - qemu_put_byte(f, s->tx_len); - for (i = 0; i < s->tx_len; i ++) - qemu_put_byte(f, s->tx_fifo[(s->tx_start + i) & 63]); - - qemu_put_byte(f, s->rx_len); - for (i = 0; i < s->rx_len; i ++) - qemu_put_byte(f, s->rx_fifo[(s->rx_start + i) & 31]); - - qemu_put_byte(f, s->resp_len); - for (i = s->resp_len; i < 9; i ++) - qemu_put_be16s(f, &s->resp_fifo[i]); + DeviceState *dev, *carddev; + SysBusDevice *sbd; + PXA2xxMMCIState *s; + Error *err = NULL; + + dev = qdev_create(NULL, TYPE_PXA2XX_MMCI); + s = PXA2XX_MMCI(dev); + sbd = SYS_BUS_DEVICE(dev); + sysbus_mmio_map(sbd, 0, base); + sysbus_connect_irq(sbd, 0, irq); + qdev_connect_gpio_out_named(dev, "rx-dma", 0, rx_dma); + qdev_connect_gpio_out_named(dev, "tx-dma", 0, tx_dma); + + /* Create and plug in the sd card */ + carddev = qdev_create(qdev_get_child_bus(dev, "sd-bus"), TYPE_SD_CARD); + qdev_prop_set_drive(carddev, "drive", blk, &err); + if (err) { + error_report("failed to init SD card: %s", error_get_pretty(err)); + return NULL; + } + object_property_set_bool(OBJECT(carddev), true, "realized", &err); + if (err) { + error_report("failed to init SD card: %s", error_get_pretty(err)); + return NULL; + } + + return s; } -static int pxa2xx_mmci_load(QEMUFile *f, void *opaque, int version_id) +static void pxa2xx_mmci_set_inserted(DeviceState *dev, bool inserted) { - PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque; - int i; - - qemu_get_be32s(f, &s->status); - qemu_get_be32s(f, &s->clkrt); - qemu_get_be32s(f, &s->spi); - qemu_get_be32s(f, &s->cmdat); - qemu_get_be32s(f, &s->resp_tout); - qemu_get_be32s(f, &s->read_tout); - s->blklen = qemu_get_be32(f); - s->numblk = qemu_get_be32(f); - qemu_get_be32s(f, &s->intmask); - qemu_get_be32s(f, &s->intreq); - s->cmd = qemu_get_be32(f); - qemu_get_be32s(f, &s->arg); - s->cmdreq = qemu_get_be32(f); - s->active = qemu_get_be32(f); - s->bytesleft = qemu_get_be32(f); - - s->tx_len = qemu_get_byte(f); - s->tx_start = 0; - if (s->tx_len >= sizeof(s->tx_fifo) || s->tx_len < 0) - return -EINVAL; - for (i = 0; i < s->tx_len; i ++) - s->tx_fifo[i] = qemu_get_byte(f); + PXA2xxMMCIState *s = PXA2XX_MMCI(dev); - s->rx_len = qemu_get_byte(f); - s->rx_start = 0; - if (s->rx_len >= sizeof(s->rx_fifo) || s->rx_len < 0) - return -EINVAL; - for (i = 0; i < s->rx_len; i ++) - s->rx_fifo[i] = qemu_get_byte(f); + qemu_set_irq(s->inserted, inserted); +} - s->resp_len = qemu_get_byte(f); - if (s->resp_len > 9 || s->resp_len < 0) - return -EINVAL; - for (i = s->resp_len; i < 9; i ++) - qemu_get_be16s(f, &s->resp_fifo[i]); +static void pxa2xx_mmci_set_readonly(DeviceState *dev, bool readonly) +{ + PXA2xxMMCIState *s = PXA2XX_MMCI(dev); - return 0; + qemu_set_irq(s->readonly, readonly); } -PXA2xxMMCIState *pxa2xx_mmci_init(MemoryRegion *sysmem, - hwaddr base, - BlockBackend *blk, qemu_irq irq, - qemu_irq rx_dma, qemu_irq tx_dma) +void pxa2xx_mmci_handlers(PXA2xxMMCIState *s, qemu_irq readonly, + qemu_irq coverswitch) { - PXA2xxMMCIState *s; + DeviceState *dev = DEVICE(s); + + s->readonly = readonly; + s->inserted = coverswitch; + + pxa2xx_mmci_set_inserted(dev, sdbus_get_inserted(&s->sdbus)); + pxa2xx_mmci_set_readonly(dev, sdbus_get_readonly(&s->sdbus)); +} + +static void pxa2xx_mmci_reset(DeviceState *d) +{ + PXA2xxMMCIState *s = PXA2XX_MMCI(d); + + s->status = 0; + s->clkrt = 0; + s->spi = 0; + s->cmdat = 0; + s->resp_tout = 0; + s->read_tout = 0; + s->blklen = 0; + s->numblk = 0; + s->intmask = 0; + s->intreq = 0; + s->cmd = 0; + s->arg = 0; + s->active = 0; + s->bytesleft = 0; + s->tx_start = 0; + s->tx_len = 0; + s->rx_start = 0; + s->rx_len = 0; + s->resp_len = 0; + s->cmdreq = 0; + memset(s->tx_fifo, 0, sizeof(s->tx_fifo)); + memset(s->rx_fifo, 0, sizeof(s->rx_fifo)); + memset(s->resp_fifo, 0, sizeof(s->resp_fifo)); +} - s = (PXA2xxMMCIState *) g_malloc0(sizeof(PXA2xxMMCIState)); - s->irq = irq; - s->rx_dma = rx_dma; - s->tx_dma = tx_dma; +static void pxa2xx_mmci_instance_init(Object *obj) +{ + PXA2xxMMCIState *s = PXA2XX_MMCI(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + DeviceState *dev = DEVICE(obj); - memory_region_init_io(&s->iomem, NULL, &pxa2xx_mmci_ops, s, + memory_region_init_io(&s->iomem, obj, &pxa2xx_mmci_ops, s, "pxa2xx-mmci", 0x00100000); - memory_region_add_subregion(sysmem, base, &s->iomem); + sysbus_init_mmio(sbd, &s->iomem); + sysbus_init_irq(sbd, &s->irq); + qdev_init_gpio_out_named(dev, &s->rx_dma, "rx-dma", 1); + qdev_init_gpio_out_named(dev, &s->tx_dma, "tx-dma", 1); - /* Instantiate the actual storage */ - s->card = sd_init(blk, false); - if (s->card == NULL) { - exit(1); - } + qbus_create_inplace(&s->sdbus, sizeof(s->sdbus), + TYPE_PXA2XX_MMCI_BUS, DEVICE(obj), "sd-bus"); +} - register_savevm(NULL, "pxa2xx_mmci", 0, 0, - pxa2xx_mmci_save, pxa2xx_mmci_load, s); +static void pxa2xx_mmci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); - return s; + dc->vmsd = &vmstate_pxa2xx_mmci; + dc->reset = pxa2xx_mmci_reset; } -void pxa2xx_mmci_handlers(PXA2xxMMCIState *s, qemu_irq readonly, - qemu_irq coverswitch) +static void pxa2xx_mmci_bus_class_init(ObjectClass *klass, void *data) { - sd_set_cb(s->card, readonly, coverswitch); + SDBusClass *sbc = SD_BUS_CLASS(klass); + + sbc->set_inserted = pxa2xx_mmci_set_inserted; + sbc->set_readonly = pxa2xx_mmci_set_readonly; } + +static const TypeInfo pxa2xx_mmci_info = { + .name = TYPE_PXA2XX_MMCI, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(PXA2xxMMCIState), + .instance_init = pxa2xx_mmci_instance_init, + .class_init = pxa2xx_mmci_class_init, +}; + +static const TypeInfo pxa2xx_mmci_bus_info = { + .name = TYPE_PXA2XX_MMCI_BUS, + .parent = TYPE_SD_BUS, + .instance_size = sizeof(SDBus), + .class_init = pxa2xx_mmci_bus_class_init, +}; + +static void pxa2xx_mmci_register_types(void) +{ + type_register_static(&pxa2xx_mmci_info); + type_register_static(&pxa2xx_mmci_bus_info); +} + +type_init(pxa2xx_mmci_register_types) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index dd614b0890..edb6b32690 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -30,10 +30,14 @@ */ #include "qemu/osdep.h" +#include "hw/qdev.h" #include "hw/hw.h" #include "sysemu/block-backend.h" #include "hw/sd/sd.h" #include "qemu/bitmap.h" +#include "hw/qdev-properties.h" +#include "qemu/error-report.h" +#include "qemu/timer.h" //#define DEBUG_SD 1 @@ -44,7 +48,9 @@ do { fprintf(stderr, "SD: " fmt , ## __VA_ARGS__); } while (0) #define DPRINTF(fmt, ...) do {} while(0) #endif -#define ACMD41_ENQUIRY_MASK 0x00ffffff +#define ACMD41_ENQUIRY_MASK 0x00ffffff +#define OCR_POWER_UP 0x80000000 +#define OCR_POWER_DELAY_NS 500000 /* 0.5ms */ typedef enum { sd_r0 = 0, /* no response */ @@ -78,9 +84,12 @@ enum SDCardStates { }; struct SDState { + DeviceState parent_obj; + uint32_t mode; /* current card mode, one of SDCardModes */ int32_t state; /* current card state, one of SDCardStates */ uint32_t ocr; + QEMUTimer *ocr_power_timer; uint8_t scr[8]; uint8_t cid[16]; uint8_t csd[16]; @@ -93,6 +102,7 @@ struct SDState { int32_t wpgrps_size; uint64_t size; uint32_t blk_len; + uint32_t multi_blk_cnt; uint32_t erase_start; uint32_t erase_end; uint8_t pwd[16]; @@ -194,8 +204,17 @@ static uint16_t sd_crc16(void *message, size_t width) static void sd_set_ocr(SDState *sd) { - /* All voltages OK, card power-up OK, Standard Capacity SD Memory Card */ - sd->ocr = 0x80ffff00; + /* All voltages OK, Standard Capacity SD Memory Card, not yet powered up */ + sd->ocr = 0x00ffff00; +} + +static void sd_ocr_powerup(void *opaque) +{ + SDState *sd = opaque; + + /* Set powered up bit in OCR */ + assert(!(sd->ocr & OCR_POWER_UP)); + sd->ocr |= OCR_POWER_UP; } static void sd_set_scr(SDState *sd) @@ -390,8 +409,9 @@ static inline uint64_t sd_addr_to_wpnum(uint64_t addr) return addr >> (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT); } -static void sd_reset(SDState *sd) +static void sd_reset(DeviceState *dev) { + SDState *sd = SD_CARD(dev); uint64_t size; uint64_t sect; @@ -424,16 +444,44 @@ static void sd_reset(SDState *sd) sd->blk_len = 0x200; sd->pwd_len = 0; sd->expecting_acmd = false; + sd->multi_blk_cnt = 0; +} + +static bool sd_get_inserted(SDState *sd) +{ + return blk_is_inserted(sd->blk); +} + +static bool sd_get_readonly(SDState *sd) +{ + return sd->wp_switch; } static void sd_cardchange(void *opaque, bool load) { SDState *sd = opaque; + DeviceState *dev = DEVICE(sd); + SDBus *sdbus = SD_BUS(qdev_get_parent_bus(dev)); + bool inserted = sd_get_inserted(sd); + bool readonly = sd_get_readonly(sd); - qemu_set_irq(sd->inserted_cb, blk_is_inserted(sd->blk)); - if (blk_is_inserted(sd->blk)) { - sd_reset(sd); - qemu_set_irq(sd->readonly_cb, sd->wp_switch); + if (inserted) { + sd_reset(dev); + } + + /* The IRQ notification is for legacy non-QOM SD controller devices; + * QOMified controllers use the SDBus APIs. + */ + if (sdbus) { + sdbus_set_inserted(sdbus, inserted); + if (inserted) { + sdbus_set_readonly(sdbus, readonly); + } + } else { + qemu_set_irq(sd->inserted_cb, inserted); + if (inserted) { + qemu_set_irq(sd->readonly_cb, readonly); + } } } @@ -441,10 +489,44 @@ static const BlockDevOps sd_block_ops = { .change_media_cb = sd_cardchange, }; +static bool sd_ocr_vmstate_needed(void *opaque) +{ + SDState *sd = opaque; + + /* Include the OCR state (and timer) if it is not yet powered up */ + return !(sd->ocr & OCR_POWER_UP); +} + +static const VMStateDescription sd_ocr_vmstate = { + .name = "sd-card/ocr-state", + .version_id = 1, + .minimum_version_id = 1, + .needed = sd_ocr_vmstate_needed, + .fields = (VMStateField[]) { + VMSTATE_UINT32(ocr, SDState), + VMSTATE_TIMER_PTR(ocr_power_timer, SDState), + VMSTATE_END_OF_LIST() + }, +}; + +static int sd_vmstate_pre_load(void *opaque) +{ + SDState *sd = opaque; + + /* If the OCR state is not included (prior versions, or not + * needed), then the OCR must be set as powered up. If the OCR state + * is included, this will be replaced by the state restore. + */ + sd_ocr_powerup(sd); + + return 0; +} + static const VMStateDescription sd_vmstate = { .name = "sd-card", .version_id = 1, .minimum_version_id = 1, + .pre_load = sd_vmstate_pre_load, .fields = (VMStateField[]) { VMSTATE_UINT32(mode, SDState), VMSTATE_INT32(state, SDState), @@ -456,6 +538,7 @@ static const VMStateDescription sd_vmstate = { VMSTATE_UINT32(vhs, SDState), VMSTATE_BITMAP(wp_groups, SDState, 0, wpgrps_size), VMSTATE_UINT32(blk_len, SDState), + VMSTATE_UINT32(multi_blk_cnt, SDState), VMSTATE_UINT32(erase_start, SDState), VMSTATE_UINT32(erase_end, SDState), VMSTATE_UINT8_ARRAY(pwd, SDState, 16), @@ -470,37 +553,33 @@ static const VMStateDescription sd_vmstate = { VMSTATE_BUFFER_POINTER_UNSAFE(buf, SDState, 1, 512), VMSTATE_BOOL(enable, SDState), VMSTATE_END_OF_LIST() - } + }, + .subsections = (const VMStateDescription*[]) { + &sd_ocr_vmstate, + NULL + }, }; -/* We do not model the chip select pin, so allow the board to select - whether card should be in SSI or MMC/SD mode. It is also up to the - board to ensure that ssi transfers only occur when the chip select - is asserted. */ +/* Legacy initialization function for use by non-qdevified callers */ SDState *sd_init(BlockBackend *blk, bool is_spi) { - SDState *sd; + DeviceState *dev; + Error *err = NULL; - if (blk && blk_is_read_only(blk)) { - fprintf(stderr, "sd_init: Cannot use read-only drive\n"); + dev = qdev_create(NULL, TYPE_SD_CARD); + qdev_prop_set_drive(dev, "drive", blk, &err); + if (err) { + error_report("sd_init failed: %s", error_get_pretty(err)); return NULL; } - - sd = (SDState *) g_malloc0(sizeof(SDState)); - sd->buf = blk_blockalign(blk, 512); - sd->spi = is_spi; - sd->enable = true; - sd->blk = blk; - sd_reset(sd); - if (sd->blk) { - /* Attach dev if not already attached. (This call ignores an - * error return code if sd->blk is already attached.) */ - /* FIXME ignoring blk_attach_dev() failure is dangerously brittle */ - blk_attach_dev(sd->blk, sd); - blk_set_dev_ops(sd->blk, &sd_block_ops, sd); + qdev_prop_set_bit(dev, "spi", is_spi); + object_property_set_bool(OBJECT(dev), true, "realized", &err); + if (err) { + error_report("sd_init failed: %s", error_get_pretty(err)); + return NULL; } - vmstate_register(NULL, -1, &sd_vmstate, sd); - return sd; + + return SD_CARD(dev); } void sd_set_cb(SDState *sd, qemu_irq readonly, qemu_irq insert) @@ -674,6 +753,12 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, rca = req.arg >> 16; } + /* CMD23 (set block count) must be immediately followed by CMD18 or CMD25 + * if not, its effects are cancelled */ + if (sd->multi_blk_cnt != 0 && !(req.cmd == 18 || req.cmd == 25)) { + sd->multi_blk_cnt = 0; + } + DPRINTF("CMD%d 0x%08x state %d\n", req.cmd, req.arg, sd->state); switch (req.cmd) { /* Basic commands (Class 0 and Class 1) */ @@ -684,7 +769,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, default: sd->state = sd_idle_state; - sd_reset(sd); + sd_reset(DEVICE(sd)); return sd->spi ? sd_r1 : sd_r0; } break; @@ -969,6 +1054,17 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, } break; + case 23: /* CMD23: SET_BLOCK_COUNT */ + switch (sd->state) { + case sd_transfer_state: + sd->multi_blk_cnt = req.arg; + return sd_r1; + + default: + break; + } + break; + /* Block write commands (Class 4) */ case 24: /* CMD24: WRITE_SINGLE_BLOCK */ if (sd->spi) @@ -1201,16 +1297,17 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, default: bad_cmd: - fprintf(stderr, "SD: Unknown CMD%i\n", req.cmd); + qemu_log_mask(LOG_GUEST_ERROR, "SD: Unknown CMD%i\n", req.cmd); return sd_illegal; unimplemented_cmd: /* Commands that are recognised but not yet implemented in SPI mode. */ - fprintf(stderr, "SD: CMD%i not implemented in SPI mode\n", req.cmd); + qemu_log_mask(LOG_UNIMP, "SD: CMD%i not implemented in SPI mode\n", + req.cmd); return sd_illegal; } - fprintf(stderr, "SD: CMD%i in a wrong state\n", req.cmd); + qemu_log_mask(LOG_GUEST_ERROR, "SD: CMD%i in a wrong state\n", req.cmd); return sd_illegal; } @@ -1278,9 +1375,28 @@ static sd_rsp_type_t sd_app_command(SDState *sd, } switch (sd->state) { case sd_idle_state: + /* If it's the first ACMD41 since reset, we need to decide + * whether to power up. If this is not an enquiry ACMD41, + * we immediately report power on and proceed below to the + * ready state, but if it is, we set a timer to model a + * delay for power up. This works around a bug in EDK2 + * UEFI, which sends an initial enquiry ACMD41, but + * assumes that the card is in ready state as soon as it + * sees the power up bit set. */ + if (!(sd->ocr & OCR_POWER_UP)) { + if ((req.arg & ACMD41_ENQUIRY_MASK) != 0) { + timer_del(sd->ocr_power_timer); + sd_ocr_powerup(sd); + } else if (!timer_pending(sd->ocr_power_timer)) { + timer_mod_ns(sd->ocr_power_timer, + (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + + OCR_POWER_DELAY_NS)); + } + } + /* We accept any voltage. 10000 V is nothing. * - * We don't model init delay so just advance straight to ready state + * Once we're powered up, we advance straight to ready state * unless it's an enquiry ACMD41 (bits 23:0 == 0). */ if (req.arg & ACMD41_ENQUIRY_MASK) { @@ -1323,7 +1439,7 @@ static sd_rsp_type_t sd_app_command(SDState *sd, return sd_normal_command(sd, req); } - fprintf(stderr, "SD: ACMD%i in a wrong state\n", req.cmd); + qemu_log_mask(LOG_GUEST_ERROR, "SD: ACMD%i in a wrong state\n", req.cmd); return sd_illegal; } @@ -1367,7 +1483,7 @@ int sd_do_command(SDState *sd, SDRequest *req, if (!cmd_valid_while_locked(sd, req)) { sd->card_status |= ILLEGAL_COMMAND; sd->expecting_acmd = false; - fprintf(stderr, "SD: Card is locked\n"); + qemu_log_mask(LOG_GUEST_ERROR, "SD: Card is locked\n"); rtype = sd_illegal; goto send_response; } @@ -1525,7 +1641,8 @@ void sd_write_data(SDState *sd, uint8_t value) return; if (sd->state != sd_receivingdata_state) { - fprintf(stderr, "sd_write_data: not in Receiving-Data state\n"); + qemu_log_mask(LOG_GUEST_ERROR, + "sd_write_data: not in Receiving-Data state\n"); return; } @@ -1569,6 +1686,14 @@ void sd_write_data(SDState *sd, uint8_t value) sd->csd[14] |= 0x40; /* Bzzzzzzztt .... Operation complete. */ + if (sd->multi_blk_cnt != 0) { + if (--sd->multi_blk_cnt == 0) { + /* Stop! */ + sd->state = sd_transfer_state; + break; + } + } + sd->state = sd_receivingdata_state; } break; @@ -1636,7 +1761,7 @@ void sd_write_data(SDState *sd, uint8_t value) break; default: - fprintf(stderr, "sd_write_data: unknown command\n"); + qemu_log_mask(LOG_GUEST_ERROR, "sd_write_data: unknown command\n"); break; } } @@ -1651,7 +1776,8 @@ uint8_t sd_read_data(SDState *sd) return 0x00; if (sd->state != sd_sendingdata_state) { - fprintf(stderr, "sd_read_data: not in Sending-Data state\n"); + qemu_log_mask(LOG_GUEST_ERROR, + "sd_read_data: not in Sending-Data state\n"); return 0x00; } @@ -1715,6 +1841,15 @@ uint8_t sd_read_data(SDState *sd) if (sd->data_offset >= io_len) { sd->data_start += io_len; sd->data_offset = 0; + + if (sd->multi_blk_cnt != 0) { + if (--sd->multi_blk_cnt == 0) { + /* Stop! */ + sd->state = sd_transfer_state; + break; + } + } + if (sd->data_start + io_len > sd->size) { sd->card_status |= ADDRESS_ERROR; break; @@ -1753,7 +1888,7 @@ uint8_t sd_read_data(SDState *sd) break; default: - fprintf(stderr, "sd_read_data: unknown command\n"); + qemu_log_mask(LOG_GUEST_ERROR, "sd_read_data: unknown command\n"); return 0x00; } @@ -1769,3 +1904,73 @@ void sd_enable(SDState *sd, bool enable) { sd->enable = enable; } + +static void sd_instance_init(Object *obj) +{ + SDState *sd = SD_CARD(obj); + + sd->enable = true; + sd->ocr_power_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sd_ocr_powerup, sd); +} + +static void sd_realize(DeviceState *dev, Error **errp) +{ + SDState *sd = SD_CARD(dev); + + if (sd->blk && blk_is_read_only(sd->blk)) { + error_setg(errp, "Cannot use read-only drive as SD card"); + return; + } + + sd->buf = blk_blockalign(sd->blk, 512); + + if (sd->blk) { + blk_set_dev_ops(sd->blk, &sd_block_ops, sd); + } +} + +static Property sd_properties[] = { + DEFINE_PROP_DRIVE("drive", SDState, blk), + /* We do not model the chip select pin, so allow the board to select + * whether card should be in SSI or MMC/SD mode. It is also up to the + * board to ensure that ssi transfers only occur when the chip select + * is asserted. */ + DEFINE_PROP_BOOL("spi", SDState, spi, false), + DEFINE_PROP_END_OF_LIST() +}; + +static void sd_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SDCardClass *sc = SD_CARD_CLASS(klass); + + dc->realize = sd_realize; + dc->props = sd_properties; + dc->vmsd = &sd_vmstate; + dc->reset = sd_reset; + dc->bus_type = TYPE_SD_BUS; + + sc->do_command = sd_do_command; + sc->write_data = sd_write_data; + sc->read_data = sd_read_data; + sc->data_ready = sd_data_ready; + sc->enable = sd_enable; + sc->get_inserted = sd_get_inserted; + sc->get_readonly = sd_get_readonly; +} + +static const TypeInfo sd_info = { + .name = TYPE_SD_CARD, + .parent = TYPE_DEVICE, + .instance_size = sizeof(SDState), + .class_size = sizeof(SDCardClass), + .class_init = sd_class_init, + .instance_init = sd_instance_init, +}; + +static void sd_register_types(void) +{ + type_register_static(&sd_info); +} + +type_init(sd_register_types) diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index 30e3bf4f3c..73e7c87fbf 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -55,6 +55,9 @@ } \ } while (0) +#define TYPE_SDHCI_BUS "sdhci-bus" +#define SDHCI_BUS(obj) OBJECT_CHECK(SDBus, (obj), TYPE_SDHCI_BUS) + /* Default SD/MMC host controller features information, which will be * presented in CAPABILITIES register of generic SD host controller at reset. * If not stated otherwise: @@ -145,9 +148,9 @@ static void sdhci_raise_insertion_irq(void *opaque) } } -static void sdhci_insert_eject_cb(void *opaque, int irq, int level) +static void sdhci_set_inserted(DeviceState *dev, bool level) { - SDHCIState *s = (SDHCIState *)opaque; + SDHCIState *s = (SDHCIState *)dev; DPRINT_L1("Card state changed: %s!\n", level ? "insert" : "eject"); if ((s->norintsts & SDHC_NIS_REMOVE) && level) { @@ -172,9 +175,9 @@ static void sdhci_insert_eject_cb(void *opaque, int irq, int level) } } -static void sdhci_card_readonly_cb(void *opaque, int irq, int level) +static void sdhci_set_readonly(DeviceState *dev, bool level) { - SDHCIState *s = (SDHCIState *)opaque; + SDHCIState *s = (SDHCIState *)dev; if (level) { s->prnsts &= ~SDHC_WRITE_PROTECT; @@ -186,6 +189,8 @@ static void sdhci_card_readonly_cb(void *opaque, int irq, int level) static void sdhci_reset(SDHCIState *s) { + DeviceState *dev = DEVICE(s); + timer_del(s->insert_timer); timer_del(s->transfer_timer); /* Set all registers to 0. Capabilities registers are not cleared @@ -194,8 +199,11 @@ static void sdhci_reset(SDHCIState *s) memset(&s->sdmasysad, 0, (uintptr_t)&s->capareg - (uintptr_t)&s->sdmasysad); if (!s->noeject_quirk) { - sd_set_cb(s->card, s->ro_cb, s->eject_cb); + /* Reset other state based on current card insertion/readonly status */ + sdhci_set_inserted(dev, sdbus_get_inserted(&s->sdbus)); + sdhci_set_readonly(dev, sdbus_get_readonly(&s->sdbus)); } + s->data_count = 0; s->stopped_state = sdhc_not_stopped; } @@ -213,7 +221,7 @@ static void sdhci_send_command(SDHCIState *s) request.cmd = s->cmdreg >> 8; request.arg = s->argument; DPRINT_L1("sending CMD%u ARG[0x%08x]\n", request.cmd, request.arg); - rlen = sd_do_command(s->card, &request, response); + rlen = sdbus_do_command(&s->sdbus, &request, response); if (s->cmdreg & SDHC_CMD_RESPONSE) { if (rlen == 4) { @@ -269,7 +277,7 @@ static void sdhci_end_transfer(SDHCIState *s) request.cmd = 0x0C; request.arg = 0; DPRINT_L1("Automatically issue CMD%d %08x\n", request.cmd, request.arg); - sd_do_command(s->card, &request, response); + sdbus_do_command(&s->sdbus, &request, response); /* Auto CMD12 response goes to the upper Response register */ s->rspreg[3] = (response[0] << 24) | (response[1] << 16) | (response[2] << 8) | response[3]; @@ -301,7 +309,7 @@ static void sdhci_read_block_from_card(SDHCIState *s) } for (index = 0; index < (s->blksize & 0x0fff); index++) { - s->fifo_buffer[index] = sd_read_data(s->card); + s->fifo_buffer[index] = sdbus_read_data(&s->sdbus); } /* New data now available for READ through Buffer Port Register */ @@ -394,7 +402,7 @@ static void sdhci_write_block_to_card(SDHCIState *s) } for (index = 0; index < (s->blksize & 0x0fff); index++) { - sd_write_data(s->card, s->fifo_buffer[index]); + sdbus_write_data(&s->sdbus, s->fifo_buffer[index]); } /* Next data can be written through BUFFER DATORT register */ @@ -476,7 +484,7 @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s) while (s->blkcnt) { if (s->data_count == 0) { for (n = 0; n < block_size; n++) { - s->fifo_buffer[n] = sd_read_data(s->card); + s->fifo_buffer[n] = sdbus_read_data(&s->sdbus); } } begin = s->data_count; @@ -517,7 +525,7 @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s) s->sdmasysad += s->data_count - begin; if (s->data_count == block_size) { for (n = 0; n < block_size; n++) { - sd_write_data(s->card, s->fifo_buffer[n]); + sdbus_write_data(&s->sdbus, s->fifo_buffer[n]); } s->data_count = 0; if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) { @@ -549,7 +557,7 @@ static void sdhci_sdma_transfer_single_block(SDHCIState *s) if (s->trnmod & SDHC_TRNS_READ) { for (n = 0; n < datacnt; n++) { - s->fifo_buffer[n] = sd_read_data(s->card); + s->fifo_buffer[n] = sdbus_read_data(&s->sdbus); } dma_memory_write(&address_space_memory, s->sdmasysad, s->fifo_buffer, datacnt); @@ -557,7 +565,7 @@ static void sdhci_sdma_transfer_single_block(SDHCIState *s) dma_memory_read(&address_space_memory, s->sdmasysad, s->fifo_buffer, datacnt); for (n = 0; n < datacnt; n++) { - sd_write_data(s->card, s->fifo_buffer[n]); + sdbus_write_data(&s->sdbus, s->fifo_buffer[n]); } } @@ -661,7 +669,7 @@ static void sdhci_do_adma(SDHCIState *s) while (length) { if (s->data_count == 0) { for (n = 0; n < block_size; n++) { - s->fifo_buffer[n] = sd_read_data(s->card); + s->fifo_buffer[n] = sdbus_read_data(&s->sdbus); } } begin = s->data_count; @@ -702,7 +710,7 @@ static void sdhci_do_adma(SDHCIState *s) dscr.addr += s->data_count - begin; if (s->data_count == block_size) { for (n = 0; n < block_size; n++) { - sd_write_data(s->card, s->fifo_buffer[n]); + sdbus_write_data(&s->sdbus, s->fifo_buffer[n]); } s->data_count = 0; if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) { @@ -816,7 +824,7 @@ static void sdhci_data_transfer(void *opaque) break; } } else { - if ((s->trnmod & SDHC_TRNS_READ) && sd_data_ready(s->card)) { + if ((s->trnmod & SDHC_TRNS_READ) && sdbus_data_ready(&s->sdbus)) { s->prnsts |= SDHC_DOING_READ | SDHC_DATA_INHIBIT | SDHC_DAT_LINE_ACTIVE; sdhci_read_block_from_card(s); @@ -1153,15 +1161,10 @@ static inline unsigned int sdhci_get_fifolen(SDHCIState *s) } } -static void sdhci_initfn(SDHCIState *s, BlockBackend *blk) +static void sdhci_initfn(SDHCIState *s) { - s->card = sd_init(blk, false); - if (s->card == NULL) { - exit(1); - } - s->eject_cb = qemu_allocate_irq(sdhci_insert_eject_cb, s, 0); - s->ro_cb = qemu_allocate_irq(sdhci_card_readonly_cb, s, 0); - sd_set_cb(s->card, s->ro_cb, s->eject_cb); + qbus_create_inplace(&s->sdbus, sizeof(s->sdbus), + TYPE_SDHCI_BUS, DEVICE(s), "sd-bus"); s->insert_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sdhci_raise_insertion_irq, s); s->transfer_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sdhci_data_transfer, s); @@ -1220,12 +1223,6 @@ const VMStateDescription sdhci_vmstate = { /* Capabilities registers provide information on supported features of this * specific host controller implementation */ static Property sdhci_pci_properties[] = { - /* - * We currently fuse controller and card into a single device - * model, but we intend to separate them. For that purpose, the - * properties that belong to the card are marked as experimental. - */ - DEFINE_PROP_DRIVE("x-drive", SDHCIState, blk), DEFINE_PROP_UINT32("capareg", SDHCIState, capareg, SDHC_CAPAB_REG_DEFAULT), DEFINE_PROP_UINT32("maxcurr", SDHCIState, maxcurr, 0), @@ -1237,7 +1234,7 @@ static void sdhci_pci_realize(PCIDevice *dev, Error **errp) SDHCIState *s = PCI_SDHCI(dev); dev->config[PCI_CLASS_PROG] = 0x01; /* Standard Host supported DMA */ dev->config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */ - sdhci_initfn(s, s->blk); + sdhci_initfn(s); s->buf_maxsz = sdhci_get_fifolen(s); s->fifo_buffer = g_malloc0(s->buf_maxsz); s->irq = pci_allocate_irq(dev); @@ -1285,11 +1282,8 @@ static Property sdhci_sysbus_properties[] = { static void sdhci_sysbus_init(Object *obj) { SDHCIState *s = SYSBUS_SDHCI(obj); - DriveInfo *di; - /* FIXME use a qdev drive property instead of drive_get_next() */ - di = drive_get_next(IF_SD); - sdhci_initfn(s, di ? blk_by_legacy_dinfo(di) : NULL); + sdhci_initfn(s); } static void sdhci_sysbus_finalize(Object *obj) @@ -1318,8 +1312,6 @@ static void sdhci_sysbus_class_init(ObjectClass *klass, void *data) dc->vmsd = &sdhci_vmstate; dc->props = sdhci_sysbus_properties; dc->realize = sdhci_sysbus_realize; - /* Reason: instance_init() method uses drive_get_next() */ - dc->cannot_instantiate_with_device_add_yet = true; } static const TypeInfo sdhci_sysbus_info = { @@ -1331,10 +1323,26 @@ static const TypeInfo sdhci_sysbus_info = { .class_init = sdhci_sysbus_class_init, }; +static void sdhci_bus_class_init(ObjectClass *klass, void *data) +{ + SDBusClass *sbc = SD_BUS_CLASS(klass); + + sbc->set_inserted = sdhci_set_inserted; + sbc->set_readonly = sdhci_set_readonly; +} + +static const TypeInfo sdhci_bus_info = { + .name = TYPE_SDHCI_BUS, + .parent = TYPE_SD_BUS, + .instance_size = sizeof(SDBus), + .class_init = sdhci_bus_class_init, +}; + static void sdhci_register_types(void) { type_register_static(&sdhci_pci_info); type_register_static(&sdhci_sysbus_info); + type_register_static(&sdhci_bus_info); } type_init(sdhci_register_types) diff --git a/hw/timer/arm_timer.c b/hw/timer/arm_timer.c index ba390ad50b..f1ede5f53b 100644 --- a/hw/timer/arm_timer.c +++ b/hw/timer/arm_timer.c @@ -277,21 +277,25 @@ static const VMStateDescription vmstate_sp804 = { } }; -static int sp804_init(SysBusDevice *sbd) +static void sp804_init(Object *obj) { - DeviceState *dev = DEVICE(sbd); - SP804State *s = SP804(dev); + SP804State *s = SP804(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); sysbus_init_irq(sbd, &s->irq); + memory_region_init_io(&s->iomem, obj, &sp804_ops, s, + "sp804", 0x1000); + sysbus_init_mmio(sbd, &s->iomem); +} + +static void sp804_realize(DeviceState *dev, Error **errp) +{ + SP804State *s = SP804(dev); + s->timer[0] = arm_timer_init(s->freq0); s->timer[1] = arm_timer_init(s->freq1); s->timer[0]->irq = qemu_allocate_irq(sp804_set_irq, s, 0); s->timer[1]->irq = qemu_allocate_irq(sp804_set_irq, s, 1); - memory_region_init_io(&s->iomem, OBJECT(s), &sp804_ops, s, - "sp804", 0x1000); - sysbus_init_mmio(sbd, &s->iomem); - vmstate_register(dev, -1, &vmstate_sp804, s); - return 0; } /* Integrator/CP timer module. */ @@ -344,9 +348,10 @@ static const MemoryRegionOps icp_pit_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static int icp_pit_init(SysBusDevice *dev) +static void icp_pit_init(Object *obj) { - icp_pit_state *s = INTEGRATOR_PIT(dev); + icp_pit_state *s = INTEGRATOR_PIT(obj); + SysBusDevice *dev = SYS_BUS_DEVICE(obj); /* Timer 0 runs at the system clock speed (40MHz). */ s->timer[0] = arm_timer_init(40000000); @@ -358,26 +363,18 @@ static int icp_pit_init(SysBusDevice *dev) sysbus_init_irq(dev, &s->timer[1]->irq); sysbus_init_irq(dev, &s->timer[2]->irq); - memory_region_init_io(&s->iomem, OBJECT(s), &icp_pit_ops, s, + memory_region_init_io(&s->iomem, obj, &icp_pit_ops, s, "icp_pit", 0x1000); sysbus_init_mmio(dev, &s->iomem); /* This device has no state to save/restore. The component timers will save themselves. */ - return 0; -} - -static void icp_pit_class_init(ObjectClass *klass, void *data) -{ - SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); - - sdc->init = icp_pit_init; } static const TypeInfo icp_pit_info = { .name = TYPE_INTEGRATOR_PIT, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(icp_pit_state), - .class_init = icp_pit_class_init, + .instance_init = icp_pit_init, }; static Property sp804_properties[] = { @@ -388,17 +385,18 @@ static Property sp804_properties[] = { static void sp804_class_init(ObjectClass *klass, void *data) { - SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); DeviceClass *k = DEVICE_CLASS(klass); - sdc->init = sp804_init; + k->realize = sp804_realize; k->props = sp804_properties; + k->vmsd = &vmstate_sp804; } static const TypeInfo sp804_info = { .name = TYPE_SP804, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(SP804State), + .instance_init = sp804_init, .class_init = sp804_class_init, }; diff --git a/hw/timer/exynos4210_mct.c b/hw/timer/exynos4210_mct.c index 73e547c91f..ae69345f0d 100644 --- a/hw/timer/exynos4210_mct.c +++ b/hw/timer/exynos4210_mct.c @@ -1422,10 +1422,11 @@ static const MemoryRegionOps exynos4210_mct_ops = { }; /* MCT init */ -static int exynos4210_mct_init(SysBusDevice *dev) +static void exynos4210_mct_init(Object *obj) { int i; - Exynos4210MCTState *s = EXYNOS4210_MCT(dev); + Exynos4210MCTState *s = EXYNOS4210_MCT(obj); + SysBusDevice *dev = SYS_BUS_DEVICE(obj); QEMUBH *bh[2]; /* Global timer */ @@ -1450,19 +1451,15 @@ static int exynos4210_mct_init(SysBusDevice *dev) sysbus_init_irq(dev, &s->l_timer[i].irq); } - memory_region_init_io(&s->iomem, OBJECT(s), &exynos4210_mct_ops, s, + memory_region_init_io(&s->iomem, obj, &exynos4210_mct_ops, s, "exynos4210-mct", MCT_SFR_SIZE); sysbus_init_mmio(dev, &s->iomem); - - return 0; } static void exynos4210_mct_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - k->init = exynos4210_mct_init; dc->reset = exynos4210_mct_reset; dc->vmsd = &vmstate_exynos4210_mct_state; } @@ -1471,6 +1468,7 @@ static const TypeInfo exynos4210_mct_info = { .name = TYPE_EXYNOS4210_MCT, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(Exynos4210MCTState), + .instance_init = exynos4210_mct_init, .class_init = exynos4210_mct_class_init, }; diff --git a/hw/timer/exynos4210_pwm.c b/hw/timer/exynos4210_pwm.c index 38f941f441..0e9e2e9bf5 100644 --- a/hw/timer/exynos4210_pwm.c +++ b/hw/timer/exynos4210_pwm.c @@ -380,9 +380,10 @@ static const MemoryRegionOps exynos4210_pwm_ops = { /* * PWM timer initialization */ -static int exynos4210_pwm_init(SysBusDevice *dev) +static void exynos4210_pwm_init(Object *obj) { - Exynos4210PWMState *s = EXYNOS4210_PWM(dev); + Exynos4210PWMState *s = EXYNOS4210_PWM(obj); + SysBusDevice *dev = SYS_BUS_DEVICE(obj); int i; QEMUBH *bh; @@ -394,19 +395,15 @@ static int exynos4210_pwm_init(SysBusDevice *dev) s->timer[i].parent = s; } - memory_region_init_io(&s->iomem, OBJECT(s), &exynos4210_pwm_ops, s, + memory_region_init_io(&s->iomem, obj, &exynos4210_pwm_ops, s, "exynos4210-pwm", EXYNOS4210_PWM_REG_MEM_SIZE); sysbus_init_mmio(dev, &s->iomem); - - return 0; } static void exynos4210_pwm_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - k->init = exynos4210_pwm_init; dc->reset = exynos4210_pwm_reset; dc->vmsd = &vmstate_exynos4210_pwm_state; } @@ -415,6 +412,7 @@ static const TypeInfo exynos4210_pwm_info = { .name = TYPE_EXYNOS4210_PWM, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(Exynos4210PWMState), + .instance_init = exynos4210_pwm_init, .class_init = exynos4210_pwm_class_init, }; diff --git a/hw/timer/exynos4210_rtc.c b/hw/timer/exynos4210_rtc.c index 33413039aa..f21fb54f5c 100644 --- a/hw/timer/exynos4210_rtc.c +++ b/hw/timer/exynos4210_rtc.c @@ -547,9 +547,10 @@ static const MemoryRegionOps exynos4210_rtc_ops = { /* * RTC timer initialization */ -static int exynos4210_rtc_init(SysBusDevice *dev) +static void exynos4210_rtc_init(Object *obj) { - Exynos4210RTCState *s = EXYNOS4210_RTC(dev); + Exynos4210RTCState *s = EXYNOS4210_RTC(obj); + SysBusDevice *dev = SYS_BUS_DEVICE(obj); QEMUBH *bh; bh = qemu_bh_new(exynos4210_rtc_tick, s); @@ -564,19 +565,15 @@ static int exynos4210_rtc_init(SysBusDevice *dev) sysbus_init_irq(dev, &s->alm_irq); sysbus_init_irq(dev, &s->tick_irq); - memory_region_init_io(&s->iomem, OBJECT(s), &exynos4210_rtc_ops, s, + memory_region_init_io(&s->iomem, obj, &exynos4210_rtc_ops, s, "exynos4210-rtc", EXYNOS4210_RTC_REG_MEM_SIZE); sysbus_init_mmio(dev, &s->iomem); - - return 0; } static void exynos4210_rtc_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - k->init = exynos4210_rtc_init; dc->reset = exynos4210_rtc_reset; dc->vmsd = &vmstate_exynos4210_rtc_state; } @@ -585,6 +582,7 @@ static const TypeInfo exynos4210_rtc_info = { .name = TYPE_EXYNOS4210_RTC, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(Exynos4210RTCState), + .instance_init = exynos4210_rtc_init, .class_init = exynos4210_rtc_class_init, }; diff --git a/hw/timer/pl031.c b/hw/timer/pl031.c index d99d18ce51..3ccb2cb460 100644 --- a/hw/timer/pl031.c +++ b/hw/timer/pl031.c @@ -192,12 +192,13 @@ static const MemoryRegionOps pl031_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static int pl031_init(SysBusDevice *dev) +static void pl031_init(Object *obj) { - PL031State *s = PL031(dev); + PL031State *s = PL031(obj); + SysBusDevice *dev = SYS_BUS_DEVICE(obj); struct tm tm; - memory_region_init_io(&s->iomem, OBJECT(s), &pl031_ops, s, "pl031", 0x1000); + memory_region_init_io(&s->iomem, obj, &pl031_ops, s, "pl031", 0x1000); sysbus_init_mmio(dev, &s->iomem); sysbus_init_irq(dev, &s->irq); @@ -206,7 +207,6 @@ static int pl031_init(SysBusDevice *dev) qemu_clock_get_ns(rtc_clock) / get_ticks_per_sec(); s->timer = timer_new_ns(rtc_clock, pl031_interrupt, s); - return 0; } static void pl031_pre_save(void *opaque) @@ -249,9 +249,7 @@ static const VMStateDescription vmstate_pl031 = { static void pl031_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - k->init = pl031_init; dc->vmsd = &vmstate_pl031; } @@ -259,6 +257,7 @@ static const TypeInfo pl031_info = { .name = TYPE_PL031, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(PL031State), + .instance_init = pl031_init, .class_init = pl031_class_init, }; diff --git a/hw/timer/pxa2xx_timer.c b/hw/timer/pxa2xx_timer.c index 0daa69c6b9..33449e66b5 100644 --- a/hw/timer/pxa2xx_timer.c +++ b/hw/timer/pxa2xx_timer.c @@ -433,10 +433,10 @@ static int pxa25x_timer_post_load(void *opaque, int version_id) return 0; } -static int pxa2xx_timer_init(SysBusDevice *dev) +static void pxa2xx_timer_init(Object *obj) { - PXA2xxTimerInfo *s = PXA2XX_TIMER(dev); - int i; + PXA2xxTimerInfo *s = PXA2XX_TIMER(obj); + SysBusDevice *dev = SYS_BUS_DEVICE(obj); s->irq_enabled = 0; s->oldclock = 0; @@ -444,16 +444,28 @@ static int pxa2xx_timer_init(SysBusDevice *dev) s->lastload = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); s->reset3 = 0; + memory_region_init_io(&s->iomem, obj, &pxa2xx_timer_ops, s, + "pxa2xx-timer", 0x00001000); + sysbus_init_mmio(dev, &s->iomem); +} + +static void pxa2xx_timer_realize(DeviceState *dev, Error **errp) +{ + PXA2xxTimerInfo *s = PXA2XX_TIMER(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + int i; + for (i = 0; i < 4; i ++) { s->timer[i].value = 0; - sysbus_init_irq(dev, &s->timer[i].irq); + sysbus_init_irq(sbd, &s->timer[i].irq); s->timer[i].info = s; s->timer[i].num = i; s->timer[i].qtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, - pxa2xx_timer_tick, &s->timer[i]); + pxa2xx_timer_tick, &s->timer[i]); } + if (s->flags & (1 << PXA2XX_TIMER_HAVE_TM4)) { - sysbus_init_irq(dev, &s->irq4); + sysbus_init_irq(sbd, &s->irq4); for (i = 0; i < 8; i ++) { s->tm4[i].tm.value = 0; @@ -462,15 +474,9 @@ static int pxa2xx_timer_init(SysBusDevice *dev) s->tm4[i].freq = 0; s->tm4[i].control = 0x0; s->tm4[i].tm.qtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, - pxa2xx_timer_tick4, &s->tm4[i]); + pxa2xx_timer_tick4, &s->tm4[i]); } } - - memory_region_init_io(&s->iomem, OBJECT(s), &pxa2xx_timer_ops, s, - "pxa2xx-timer", 0x00001000); - sysbus_init_mmio(dev, &s->iomem); - - return 0; } static const VMStateDescription vmstate_pxa2xx_timer0_regs = { @@ -573,9 +579,8 @@ static const TypeInfo pxa27x_timer_dev_info = { static void pxa2xx_timer_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); - SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(oc); - sdc->init = pxa2xx_timer_init; + dc->realize = pxa2xx_timer_realize; dc->vmsd = &vmstate_pxa2xx_timer_regs; } @@ -583,6 +588,7 @@ static const TypeInfo pxa2xx_timer_type_info = { .name = TYPE_PXA2XX_TIMER, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(PXA2xxTimerInfo), + .instance_init = pxa2xx_timer_init, .abstract = true, .class_init = pxa2xx_timer_class_init, }; |