aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/arm/xilinx_zynq.c17
-rw-r--r--hw/arm/xlnx-ep108.c21
-rw-r--r--hw/arm/xlnx-zynqmp.c8
-rw-r--r--hw/gpio/pl061.c37
-rw-r--r--hw/sd/Makefile.objs2
-rw-r--r--hw/sd/core.c146
-rw-r--r--hw/sd/pxa2xx_mmci.c304
-rw-r--r--hw/sd/sd.c289
-rw-r--r--hw/sd/sdhci.c82
-rw-r--r--hw/timer/arm_timer.c42
-rw-r--r--hw/timer/exynos4210_mct.c12
-rw-r--r--hw/timer/exynos4210_pwm.c12
-rw-r--r--hw/timer/exynos4210_rtc.c12
-rw-r--r--hw/timer/pl031.c11
-rw-r--r--hw/timer/pxa2xx_timer.c36
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,
};