aboutsummaryrefslogtreecommitdiff
path: root/hw/sd
diff options
context:
space:
mode:
Diffstat (limited to 'hw/sd')
-rw-r--r--hw/sd/allwinner-sdhost.c33
-rw-r--r--hw/sd/aspeed_sdhci.c110
-rw-r--r--hw/sd/bcm2835_sdhost.c13
-rw-r--r--hw/sd/cadence_sdhci.c4
-rw-r--r--hw/sd/core.c5
-rw-r--r--hw/sd/meson.build1
-rw-r--r--hw/sd/npcm7xx_sdhci.c4
-rw-r--r--hw/sd/omap_mmc.c312
-rw-r--r--hw/sd/pl181.c14
-rw-r--r--hw/sd/pxa2xx_mmci.c594
-rw-r--r--hw/sd/sd.c365
-rw-r--r--hw/sd/sdhci-internal.h2
-rw-r--r--hw/sd/sdhci-pci.c9
-rw-r--r--hw/sd/sdhci.c208
-rw-r--r--hw/sd/sdmmc-internal.h3
-rw-r--r--hw/sd/ssi-sd.c110
-rw-r--r--hw/sd/trace-events8
17 files changed, 609 insertions, 1186 deletions
diff --git a/hw/sd/allwinner-sdhost.c b/hw/sd/allwinner-sdhost.c
index a1b7230..9d61b37 100644
--- a/hw/sd/allwinner-sdhost.c
+++ b/hw/sd/allwinner-sdhost.c
@@ -22,8 +22,8 @@
#include "qemu/module.h"
#include "qemu/units.h"
#include "qapi/error.h"
-#include "sysemu/blockdev.h"
-#include "sysemu/dma.h"
+#include "system/blockdev.h"
+#include "system/dma.h"
#include "hw/qdev-properties.h"
#include "hw/irq.h"
#include "hw/sd/allwinner-sdhost.h"
@@ -233,7 +233,7 @@ static void allwinner_sdhost_send_command(AwSdHostState *s)
{
SDRequest request;
uint8_t resp[16];
- int rlen;
+ size_t rlen;
/* Auto clear load flag */
s->command &= ~SD_CMDR_LOAD;
@@ -246,10 +246,7 @@ static void allwinner_sdhost_send_command(AwSdHostState *s)
request.arg = s->command_arg;
/* Send request to SD bus */
- rlen = sdbus_do_command(&s->sdbus, &request, resp);
- if (rlen < 0) {
- goto error;
- }
+ rlen = sdbus_do_command(&s->sdbus, &request, resp, sizeof(resp));
/* If the command has a response, store it in the response registers */
if ((s->command & SD_CMDR_RESPONSE)) {
@@ -761,7 +758,7 @@ static void allwinner_sdhost_write(void *opaque, hwaddr offset,
static const MemoryRegionOps allwinner_sdhost_ops = {
.read = allwinner_sdhost_read,
.write = allwinner_sdhost_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 4,
.max_access_size = 4,
@@ -808,10 +805,9 @@ static const VMStateDescription vmstate_allwinner_sdhost = {
}
};
-static Property allwinner_sdhost_properties[] = {
+static const Property allwinner_sdhost_properties[] = {
DEFINE_PROP_LINK("dma-memory", AwSdHostState, dma_mr,
TYPE_MEMORY_REGION, MemoryRegion *),
- DEFINE_PROP_END_OF_LIST(),
};
static void allwinner_sdhost_init(Object *obj)
@@ -889,24 +885,26 @@ static void allwinner_sdhost_reset(DeviceState *dev)
}
}
-static void allwinner_sdhost_bus_class_init(ObjectClass *klass, void *data)
+static void allwinner_sdhost_bus_class_init(ObjectClass *klass,
+ const void *data)
{
SDBusClass *sbc = SD_BUS_CLASS(klass);
sbc->set_inserted = allwinner_sdhost_set_inserted;
}
-static void allwinner_sdhost_class_init(ObjectClass *klass, void *data)
+static void allwinner_sdhost_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = allwinner_sdhost_reset;
+ device_class_set_legacy_reset(dc, allwinner_sdhost_reset);
dc->vmsd = &vmstate_allwinner_sdhost;
dc->realize = allwinner_sdhost_realize;
device_class_set_props(dc, allwinner_sdhost_properties);
}
-static void allwinner_sdhost_sun4i_class_init(ObjectClass *klass, void *data)
+static void allwinner_sdhost_sun4i_class_init(ObjectClass *klass,
+ const void *data)
{
AwSdHostClass *sc = AW_SDHOST_CLASS(klass);
sc->max_desc_size = 8 * KiB;
@@ -914,7 +912,8 @@ static void allwinner_sdhost_sun4i_class_init(ObjectClass *klass, void *data)
sc->can_calibrate = false;
}
-static void allwinner_sdhost_sun5i_class_init(ObjectClass *klass, void *data)
+static void allwinner_sdhost_sun5i_class_init(ObjectClass *klass,
+ const void *data)
{
AwSdHostClass *sc = AW_SDHOST_CLASS(klass);
sc->max_desc_size = 64 * KiB;
@@ -923,7 +922,7 @@ static void allwinner_sdhost_sun5i_class_init(ObjectClass *klass, void *data)
}
static void allwinner_sdhost_sun50i_a64_class_init(ObjectClass *klass,
- void *data)
+ const void *data)
{
AwSdHostClass *sc = AW_SDHOST_CLASS(klass);
sc->max_desc_size = 64 * KiB;
@@ -932,7 +931,7 @@ static void allwinner_sdhost_sun50i_a64_class_init(ObjectClass *klass,
}
static void allwinner_sdhost_sun50i_a64_emmc_class_init(ObjectClass *klass,
- void *data)
+ const void *data)
{
AwSdHostClass *sc = AW_SDHOST_CLASS(klass);
sc->max_desc_size = 8 * KiB;
diff --git a/hw/sd/aspeed_sdhci.c b/hw/sd/aspeed_sdhci.c
index 3b63926..fc38ad3 100644
--- a/hw/sd/aspeed_sdhci.c
+++ b/hw/sd/aspeed_sdhci.c
@@ -24,8 +24,10 @@
#define ASPEED_SDHCI_DEBOUNCE_RESET 0x00000005
#define ASPEED_SDHCI_BUS 0x08
#define ASPEED_SDHCI_SDIO_140 0x10
+#define ASPEED_SDHCI_SDIO_144 0x14
#define ASPEED_SDHCI_SDIO_148 0x18
#define ASPEED_SDHCI_SDIO_240 0x20
+#define ASPEED_SDHCI_SDIO_244 0x24
#define ASPEED_SDHCI_SDIO_248 0x28
#define ASPEED_SDHCI_WP_POL 0xec
#define ASPEED_SDHCI_CARD_DET 0xf0
@@ -35,21 +37,27 @@
static uint64_t aspeed_sdhci_read(void *opaque, hwaddr addr, unsigned int size)
{
- uint32_t val = 0;
+ uint64_t val = 0;
AspeedSDHCIState *sdhci = opaque;
switch (addr) {
case ASPEED_SDHCI_SDIO_140:
- val = (uint32_t)sdhci->slots[0].capareg;
+ val = extract64(sdhci->slots[0].capareg, 0, 32);
+ break;
+ case ASPEED_SDHCI_SDIO_144:
+ val = extract64(sdhci->slots[0].capareg, 32, 32);
break;
case ASPEED_SDHCI_SDIO_148:
- val = (uint32_t)sdhci->slots[0].maxcurr;
+ val = extract64(sdhci->slots[0].maxcurr, 0, 32);
break;
case ASPEED_SDHCI_SDIO_240:
- val = (uint32_t)sdhci->slots[1].capareg;
+ val = extract64(sdhci->slots[1].capareg, 0, 32);
+ break;
+ case ASPEED_SDHCI_SDIO_244:
+ val = extract64(sdhci->slots[1].capareg, 32, 32);
break;
case ASPEED_SDHCI_SDIO_248:
- val = (uint32_t)sdhci->slots[1].maxcurr;
+ val = extract64(sdhci->slots[1].maxcurr, 0, 32);
break;
default:
if (addr < ASPEED_SDHCI_REG_SIZE) {
@@ -61,9 +69,9 @@ static uint64_t aspeed_sdhci_read(void *opaque, hwaddr addr, unsigned int size)
}
}
- trace_aspeed_sdhci_read(addr, size, (uint64_t) val);
+ trace_aspeed_sdhci_read(addr, size, val);
- return (uint64_t)val;
+ return val;
}
static void aspeed_sdhci_write(void *opaque, hwaddr addr, uint64_t val,
@@ -79,16 +87,28 @@ static void aspeed_sdhci_write(void *opaque, hwaddr addr, uint64_t val,
sdhci->regs[TO_REG(addr)] = (uint32_t)val & ~ASPEED_SDHCI_INFO_RESET;
break;
case ASPEED_SDHCI_SDIO_140:
- sdhci->slots[0].capareg = (uint64_t)(uint32_t)val;
+ sdhci->slots[0].capareg = deposit64(sdhci->slots[0].capareg,
+ 0, 32, val);
+ break;
+ case ASPEED_SDHCI_SDIO_144:
+ sdhci->slots[0].capareg = deposit64(sdhci->slots[0].capareg,
+ 32, 32, val);
break;
case ASPEED_SDHCI_SDIO_148:
- sdhci->slots[0].maxcurr = (uint64_t)(uint32_t)val;
+ sdhci->slots[0].maxcurr = deposit64(sdhci->slots[0].maxcurr,
+ 0, 32, val);
break;
case ASPEED_SDHCI_SDIO_240:
- sdhci->slots[1].capareg = (uint64_t)(uint32_t)val;
+ sdhci->slots[1].capareg = deposit64(sdhci->slots[1].capareg,
+ 0, 32, val);
+ break;
+ case ASPEED_SDHCI_SDIO_244:
+ sdhci->slots[1].capareg = deposit64(sdhci->slots[1].capareg,
+ 32, 32, val);
break;
case ASPEED_SDHCI_SDIO_248:
- sdhci->slots[1].maxcurr = (uint64_t)(uint32_t)val;
+ sdhci->slots[1].maxcurr = deposit64(sdhci->slots[0].maxcurr,
+ 0, 32, val);
break;
default:
if (addr < ASPEED_SDHCI_REG_SIZE) {
@@ -128,6 +148,7 @@ static void aspeed_sdhci_realize(DeviceState *dev, Error **errp)
{
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
AspeedSDHCIState *sdhci = ASPEED_SDHCI(dev);
+ AspeedSDHCIClass *asc = ASPEED_SDHCI_GET_CLASS(sdhci);
/* Create input irqs for the slots */
qdev_init_gpio_in_named_with_opaque(DEVICE(sbd), aspeed_sdhci_set_irq,
@@ -147,7 +168,7 @@ static void aspeed_sdhci_realize(DeviceState *dev, Error **errp)
}
if (!object_property_set_uint(sdhci_slot, "capareg",
- ASPEED_SDHCI_CAPABILITIES, errp)) {
+ asc->capareg, errp)) {
return;
}
@@ -183,27 +204,84 @@ static const VMStateDescription vmstate_aspeed_sdhci = {
},
};
-static Property aspeed_sdhci_properties[] = {
+static const Property aspeed_sdhci_properties[] = {
DEFINE_PROP_UINT8("num-slots", AspeedSDHCIState, num_slots, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void aspeed_sdhci_class_init(ObjectClass *classp, void *data)
+static void aspeed_sdhci_class_init(ObjectClass *classp, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(classp);
dc->realize = aspeed_sdhci_realize;
- dc->reset = aspeed_sdhci_reset;
+ device_class_set_legacy_reset(dc, aspeed_sdhci_reset);
dc->vmsd = &vmstate_aspeed_sdhci;
device_class_set_props(dc, aspeed_sdhci_properties);
}
+static void aspeed_2400_sdhci_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedSDHCIClass *asc = ASPEED_SDHCI_CLASS(klass);
+
+ dc->desc = "ASPEED 2400 SDHCI Controller";
+ asc->capareg = 0x0000000001e80080;
+}
+
+static void aspeed_2500_sdhci_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedSDHCIClass *asc = ASPEED_SDHCI_CLASS(klass);
+
+ dc->desc = "ASPEED 2500 SDHCI Controller";
+ asc->capareg = 0x0000000001e80080;
+}
+
+static void aspeed_2600_sdhci_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedSDHCIClass *asc = ASPEED_SDHCI_CLASS(klass);
+
+ dc->desc = "ASPEED 2600 SDHCI Controller";
+ asc->capareg = 0x0000000701f80080;
+}
+
+static void aspeed_2700_sdhci_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedSDHCIClass *asc = ASPEED_SDHCI_CLASS(klass);
+
+ dc->desc = "ASPEED 2700 SDHCI Controller";
+ asc->capareg = 0x0000000719f80080;
+}
+
static const TypeInfo aspeed_sdhci_types[] = {
{
.name = TYPE_ASPEED_SDHCI,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(AspeedSDHCIState),
.class_init = aspeed_sdhci_class_init,
+ .class_size = sizeof(AspeedSDHCIClass),
+ .abstract = true,
+ },
+ {
+ .name = TYPE_ASPEED_2400_SDHCI,
+ .parent = TYPE_ASPEED_SDHCI,
+ .class_init = aspeed_2400_sdhci_class_init,
+ },
+ {
+ .name = TYPE_ASPEED_2500_SDHCI,
+ .parent = TYPE_ASPEED_SDHCI,
+ .class_init = aspeed_2500_sdhci_class_init,
+ },
+ {
+ .name = TYPE_ASPEED_2600_SDHCI,
+ .parent = TYPE_ASPEED_SDHCI,
+ .class_init = aspeed_2600_sdhci_class_init,
+ },
+ {
+ .name = TYPE_ASPEED_2700_SDHCI,
+ .parent = TYPE_ASPEED_SDHCI,
+ .class_init = aspeed_2700_sdhci_class_init,
},
};
diff --git a/hw/sd/bcm2835_sdhost.c b/hw/sd/bcm2835_sdhost.c
index 11c54dd..f7cef7b 100644
--- a/hw/sd/bcm2835_sdhost.c
+++ b/hw/sd/bcm2835_sdhost.c
@@ -14,7 +14,7 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "qemu/module.h"
-#include "sysemu/blockdev.h"
+#include "system/blockdev.h"
#include "hw/irq.h"
#include "hw/sd/bcm2835_sdhost.h"
#include "migration/vmstate.h"
@@ -113,15 +113,12 @@ static void bcm2835_sdhost_send_command(BCM2835SDHostState *s)
{
SDRequest request;
uint8_t rsp[16];
- int rlen;
+ size_t rlen;
request.cmd = s->cmd & SDCMD_CMD_MASK;
request.arg = s->cmdarg;
- rlen = sdbus_do_command(&s->sdbus, &request, rsp);
- if (rlen < 0) {
- goto error;
- }
+ rlen = sdbus_do_command(&s->sdbus, &request, rsp, sizeof(rsp));
if (!(s->cmd & SDCMD_NO_RESPONSE)) {
if (rlen == 0 || (rlen == 4 && (s->cmd & SDCMD_LONG_RESPONSE))) {
goto error;
@@ -428,11 +425,11 @@ static void bcm2835_sdhost_reset(DeviceState *dev)
s->fifo_len = 0;
}
-static void bcm2835_sdhost_class_init(ObjectClass *klass, void *data)
+static void bcm2835_sdhost_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = bcm2835_sdhost_reset;
+ device_class_set_legacy_reset(dc, bcm2835_sdhost_reset);
dc->vmsd = &vmstate_bcm2835_sdhost;
}
diff --git a/hw/sd/cadence_sdhci.c b/hw/sd/cadence_sdhci.c
index 7c8bc54..d576855 100644
--- a/hw/sd/cadence_sdhci.c
+++ b/hw/sd/cadence_sdhci.c
@@ -165,13 +165,13 @@ static const VMStateDescription vmstate_cadence_sdhci = {
},
};
-static void cadence_sdhci_class_init(ObjectClass *classp, void *data)
+static void cadence_sdhci_class_init(ObjectClass *classp, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(classp);
dc->desc = "Cadence SD/SDIO/eMMC Host Controller (SD4HC)";
dc->realize = cadence_sdhci_realize;
- dc->reset = cadence_sdhci_reset;
+ device_class_set_legacy_reset(dc, cadence_sdhci_reset);
dc->vmsd = &vmstate_cadence_sdhci;
}
diff --git a/hw/sd/core.c b/hw/sd/core.c
index 4b30218..d3c9017 100644
--- a/hw/sd/core.c
+++ b/hw/sd/core.c
@@ -90,7 +90,8 @@ void sdbus_set_voltage(SDBus *sdbus, uint16_t millivolts)
}
}
-int sdbus_do_command(SDBus *sdbus, SDRequest *req, uint8_t *response)
+size_t sdbus_do_command(SDBus *sdbus, SDRequest *req,
+ uint8_t *resp, size_t respsz)
{
SDState *card = get_card(sdbus);
@@ -98,7 +99,7 @@ int sdbus_do_command(SDBus *sdbus, SDRequest *req, uint8_t *response)
if (card) {
SDCardClass *sc = SDMMC_COMMON_GET_CLASS(card);
- return sc->do_command(card, req, response);
+ return sc->do_command(card, req, resp, respsz);
}
return 0;
diff --git a/hw/sd/meson.build b/hw/sd/meson.build
index bbb75af..b43d45b 100644
--- a/hw/sd/meson.build
+++ b/hw/sd/meson.build
@@ -5,7 +5,6 @@ system_ss.add(when: 'CONFIG_SDHCI_PCI', if_true: files('sdhci-pci.c'))
system_ss.add(when: 'CONFIG_SSI_SD', if_true: files('ssi-sd.c'))
system_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_mmc.c'))
-system_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx_mmci.c'))
system_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_sdhost.c'))
system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_sdhci.c'))
system_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-sdhost.c'))
diff --git a/hw/sd/npcm7xx_sdhci.c b/hw/sd/npcm7xx_sdhci.c
index fb51821..0233d7b 100644
--- a/hw/sd/npcm7xx_sdhci.c
+++ b/hw/sd/npcm7xx_sdhci.c
@@ -149,13 +149,13 @@ static const VMStateDescription vmstate_npcm7xx_sdhci = {
},
};
-static void npcm7xx_sdhci_class_init(ObjectClass *classp, void *data)
+static void npcm7xx_sdhci_class_init(ObjectClass *classp, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(classp);
dc->desc = "NPCM7xx SD/eMMC Host Controller";
dc->realize = npcm7xx_sdhci_realize;
- dc->reset = npcm7xx_sdhci_reset;
+ device_class_set_legacy_reset(dc, npcm7xx_sdhci_reset);
dc->vmsd = &vmstate_npcm7xx_sdhci;
}
diff --git a/hw/sd/omap_mmc.c b/hw/sd/omap_mmc.c
index edd3cf2..5a1d25d 100644
--- a/hw/sd/omap_mmc.c
+++ b/hw/sd/omap_mmc.c
@@ -21,17 +21,22 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
+#include "qapi/error.h"
#include "hw/irq.h"
+#include "hw/sysbus.h"
#include "hw/arm/omap.h"
-#include "hw/sd/sdcard_legacy.h"
+#include "hw/sd/sd.h"
+
+typedef struct OMAPMMCState {
+ SysBusDevice parent_obj;
+
+ SDBus sdbus;
-struct omap_mmc_s {
qemu_irq irq;
- qemu_irq *dma;
- qemu_irq coverswitch;
+ qemu_irq dma_tx_gpio;
+ qemu_irq dma_rx_gpio;
MemoryRegion iomem;
omap_clk clk;
- SDState *card;
uint16_t last_cmd;
uint16_t sdio;
uint16_t rsp[8];
@@ -64,16 +69,15 @@ struct omap_mmc_s {
int cdet_wakeup;
int cdet_enable;
- int cdet_state;
qemu_irq cdet;
-};
+} OMAPMMCState;
-static void omap_mmc_interrupts_update(struct omap_mmc_s *s)
+static void omap_mmc_interrupts_update(OMAPMMCState *s)
{
qemu_set_irq(s->irq, !!(s->status & s->mask));
}
-static void omap_mmc_fifolevel_update(struct omap_mmc_s *host)
+static void omap_mmc_fifolevel_update(OMAPMMCState *host)
{
if (!host->transfer && !host->fifo_len) {
host->status &= 0xf3ff;
@@ -83,40 +87,51 @@ static void omap_mmc_fifolevel_update(struct omap_mmc_s *host)
if (host->fifo_len > host->af_level && host->ddir) {
if (host->rx_dma) {
host->status &= 0xfbff;
- qemu_irq_raise(host->dma[1]);
+ qemu_irq_raise(host->dma_rx_gpio);
} else
host->status |= 0x0400;
} else {
host->status &= 0xfbff;
- qemu_irq_lower(host->dma[1]);
+ qemu_irq_lower(host->dma_rx_gpio);
}
if (host->fifo_len < host->ae_level && !host->ddir) {
if (host->tx_dma) {
host->status &= 0xf7ff;
- qemu_irq_raise(host->dma[0]);
+ qemu_irq_raise(host->dma_tx_gpio);
} else
host->status |= 0x0800;
} else {
- qemu_irq_lower(host->dma[0]);
+ qemu_irq_lower(host->dma_tx_gpio);
host->status &= 0xf7ff;
}
}
+/* These must match the encoding of the MMC_CMD Response field */
typedef enum {
- sd_nore = 0, /* no response */
- sd_r1, /* normal response command */
- sd_r2, /* CID, CSD registers */
- sd_r3, /* OCR register */
- sd_r6 = 6, /* Published RCA response */
+ sd_nore = 0, /* no response */
+ sd_r1, /* normal response command */
+ sd_r2, /* CID, CSD registers */
+ sd_r3, /* OCR register */
+ sd_r6 = 6, /* Published RCA response */
sd_r1b = -1,
} sd_rsp_type_t;
-static void omap_mmc_command(struct omap_mmc_s *host, int cmd, int dir,
- sd_cmd_type_t type, int busy, sd_rsp_type_t resptype, int init)
+/* These must match the encoding of the MMC_CMD Type field */
+typedef enum {
+ SD_TYPE_BC = 0, /* broadcast -- no response */
+ SD_TYPE_BCR = 1, /* broadcast with response */
+ SD_TYPE_AC = 2, /* addressed -- no data transfer */
+ SD_TYPE_ADTC = 3, /* addressed with data transfer */
+} MMCCmdType;
+
+static void omap_mmc_command(OMAPMMCState *host, int cmd, int dir,
+ MMCCmdType type, int busy,
+ sd_rsp_type_t resptype, int init)
{
uint32_t rspstatus, mask;
- int rsplen, timeout;
+ size_t rsplen;
+ int timeout;
SDRequest request;
uint8_t response[16];
@@ -128,7 +143,7 @@ static void omap_mmc_command(struct omap_mmc_s *host, int cmd, int dir,
if (resptype == sd_r1 && busy)
resptype = sd_r1b;
- if (type == sd_adtc) {
+ if (type == SD_TYPE_ADTC) {
host->fifo_start = 0;
host->fifo_len = 0;
host->transfer = 1;
@@ -143,7 +158,7 @@ static void omap_mmc_command(struct omap_mmc_s *host, int cmd, int dir,
request.arg = host->arg;
request.crc = 0; /* FIXME */
- rsplen = sd_do_command(host->card, &request, response);
+ rsplen = sdbus_do_command(&host->sdbus, &request, response, sizeof(response));
/* TODO: validate CRCs */
switch (resptype) {
@@ -215,12 +230,12 @@ static void omap_mmc_command(struct omap_mmc_s *host, int cmd, int dir,
if (timeout)
host->status |= 0x0080;
else if (cmd == 12)
- host->status |= 0x0005; /* Makes it more real */
+ host->status |= 0x0005; /* Makes it more real */
else
host->status |= 0x0001;
}
-static void omap_mmc_transfer(struct omap_mmc_s *host)
+static void omap_mmc_transfer(OMAPMMCState *host)
{
uint8_t value;
@@ -232,10 +247,10 @@ static void omap_mmc_transfer(struct omap_mmc_s *host)
if (host->fifo_len > host->af_level)
break;
- value = sd_read_byte(host->card);
+ value = sdbus_read_byte(&host->sdbus);
host->fifo[(host->fifo_start + host->fifo_len) & 31] = value;
if (-- host->blen_counter) {
- value = sd_read_byte(host->card);
+ value = sdbus_read_byte(&host->sdbus);
host->fifo[(host->fifo_start + host->fifo_len) & 31] |=
value << 8;
host->blen_counter --;
@@ -247,10 +262,10 @@ static void omap_mmc_transfer(struct omap_mmc_s *host)
break;
value = host->fifo[host->fifo_start] & 0xff;
- sd_write_byte(host->card, value);
+ sdbus_write_byte(&host->sdbus, value);
if (-- host->blen_counter) {
value = host->fifo[host->fifo_start] >> 8;
- sd_write_byte(host->card, value);
+ sdbus_write_byte(&host->sdbus, value);
host->blen_counter --;
}
@@ -275,19 +290,19 @@ static void omap_mmc_transfer(struct omap_mmc_s *host)
static void omap_mmc_update(void *opaque)
{
- struct omap_mmc_s *s = opaque;
+ OMAPMMCState *s = opaque;
omap_mmc_transfer(s);
omap_mmc_fifolevel_update(s);
omap_mmc_interrupts_update(s);
}
-static void omap_mmc_pseudo_reset(struct omap_mmc_s *host)
+static void omap_mmc_pseudo_reset(OMAPMMCState *host)
{
host->status = 0;
host->fifo_len = 0;
}
-void omap_mmc_reset(struct omap_mmc_s *host)
+static void omap_mmc_reset(OMAPMMCState *host)
{
host->last_cmd = 0;
memset(host->rsp, 0, sizeof(host->rsp));
@@ -309,54 +324,47 @@ void omap_mmc_reset(struct omap_mmc_s *host)
host->transfer = 0;
host->cdet_wakeup = 0;
host->cdet_enable = 0;
- qemu_set_irq(host->coverswitch, host->cdet_state);
host->clkdiv = 0;
omap_mmc_pseudo_reset(host);
-
- /* Since we're still using the legacy SD API the card is not plugged
- * into any bus, and we must reset it manually. When omap_mmc is
- * QOMified this must move into the QOM reset function.
- */
- device_cold_reset(DEVICE(host->card));
}
static uint64_t omap_mmc_read(void *opaque, hwaddr offset, unsigned size)
{
uint16_t i;
- struct omap_mmc_s *s = opaque;
+ OMAPMMCState *s = opaque;
if (size != 2) {
return omap_badwidth_read16(opaque, offset);
}
switch (offset) {
- case 0x00: /* MMC_CMD */
+ case 0x00: /* MMC_CMD */
return s->last_cmd;
- case 0x04: /* MMC_ARGL */
+ case 0x04: /* MMC_ARGL */
return s->arg & 0x0000ffff;
- case 0x08: /* MMC_ARGH */
+ case 0x08: /* MMC_ARGH */
return s->arg >> 16;
- case 0x0c: /* MMC_CON */
+ case 0x0c: /* MMC_CON */
return (s->dw << 15) | (s->mode << 12) | (s->enable << 11) |
(s->be << 10) | s->clkdiv;
- case 0x10: /* MMC_STAT */
+ case 0x10: /* MMC_STAT */
return s->status;
- case 0x14: /* MMC_IE */
+ case 0x14: /* MMC_IE */
return s->mask;
- case 0x18: /* MMC_CTO */
+ case 0x18: /* MMC_CTO */
return s->cto;
- case 0x1c: /* MMC_DTO */
+ case 0x1c: /* MMC_DTO */
return s->dto;
- case 0x20: /* MMC_DATA */
+ case 0x20: /* MMC_DATA */
/* TODO: support 8-bit access */
i = s->fifo[s->fifo_start];
if (s->fifo_len == 0) {
@@ -371,42 +379,42 @@ static uint64_t omap_mmc_read(void *opaque, hwaddr offset, unsigned size)
omap_mmc_interrupts_update(s);
return i;
- case 0x24: /* MMC_BLEN */
+ case 0x24: /* MMC_BLEN */
return s->blen_counter;
- case 0x28: /* MMC_NBLK */
+ case 0x28: /* MMC_NBLK */
return s->nblk_counter;
- case 0x2c: /* MMC_BUF */
+ case 0x2c: /* MMC_BUF */
return (s->rx_dma << 15) | (s->af_level << 8) |
(s->tx_dma << 7) | s->ae_level;
- case 0x30: /* MMC_SPI */
+ case 0x30: /* MMC_SPI */
return 0x0000;
- case 0x34: /* MMC_SDIO */
+ case 0x34: /* MMC_SDIO */
return (s->cdet_wakeup << 2) | (s->cdet_enable) | s->sdio;
- case 0x38: /* MMC_SYST */
+ case 0x38: /* MMC_SYST */
return 0x0000;
- case 0x3c: /* MMC_REV */
+ case 0x3c: /* MMC_REV */
return s->rev;
- case 0x40: /* MMC_RSP0 */
- case 0x44: /* MMC_RSP1 */
- case 0x48: /* MMC_RSP2 */
- case 0x4c: /* MMC_RSP3 */
- case 0x50: /* MMC_RSP4 */
- case 0x54: /* MMC_RSP5 */
- case 0x58: /* MMC_RSP6 */
- case 0x5c: /* MMC_RSP7 */
+ case 0x40: /* MMC_RSP0 */
+ case 0x44: /* MMC_RSP1 */
+ case 0x48: /* MMC_RSP2 */
+ case 0x4c: /* MMC_RSP3 */
+ case 0x50: /* MMC_RSP4 */
+ case 0x54: /* MMC_RSP5 */
+ case 0x58: /* MMC_RSP6 */
+ case 0x5c: /* MMC_RSP7 */
return s->rsp[(offset - 0x40) >> 2];
/* OMAP2-specific */
- case 0x60: /* MMC_IOSR */
- case 0x64: /* MMC_SYSC */
+ case 0x60: /* MMC_IOSR */
+ case 0x64: /* MMC_SYSC */
return 0;
- case 0x68: /* MMC_SYSS */
- return 1; /* RSTD */
+ case 0x68: /* MMC_SYSS */
+ return 1; /* RSTD */
}
OMAP_BAD_REG(offset);
@@ -417,7 +425,7 @@ static void omap_mmc_write(void *opaque, hwaddr offset,
uint64_t value, unsigned size)
{
int i;
- struct omap_mmc_s *s = opaque;
+ OMAPMMCState *s = opaque;
if (size != 2) {
omap_badwidth_write16(opaque, offset, value);
@@ -425,7 +433,7 @@ static void omap_mmc_write(void *opaque, hwaddr offset,
}
switch (offset) {
- case 0x00: /* MMC_CMD */
+ case 0x00: /* MMC_CMD */
if (!s->enable)
break;
@@ -433,24 +441,24 @@ static void omap_mmc_write(void *opaque, hwaddr offset,
for (i = 0; i < 8; i ++)
s->rsp[i] = 0x0000;
omap_mmc_command(s, value & 63, (value >> 15) & 1,
- (sd_cmd_type_t) ((value >> 12) & 3),
- (value >> 11) & 1,
- (sd_rsp_type_t) ((value >> 8) & 7),
- (value >> 7) & 1);
+ (MMCCmdType)((value >> 12) & 3),
+ (value >> 11) & 1,
+ (sd_rsp_type_t) ((value >> 8) & 7),
+ (value >> 7) & 1);
omap_mmc_update(s);
break;
- case 0x04: /* MMC_ARGL */
+ case 0x04: /* MMC_ARGL */
s->arg &= 0xffff0000;
s->arg |= 0x0000ffff & value;
break;
- case 0x08: /* MMC_ARGH */
+ case 0x08: /* MMC_ARGH */
s->arg &= 0x0000ffff;
s->arg |= value << 16;
break;
- case 0x0c: /* MMC_CON */
+ case 0x0c: /* MMC_CON */
s->dw = (value >> 15) & 1;
s->mode = (value >> 12) & 3;
s->enable = (value >> 11) & 1;
@@ -470,27 +478,27 @@ static void omap_mmc_write(void *opaque, hwaddr offset,
omap_mmc_pseudo_reset(s);
break;
- case 0x10: /* MMC_STAT */
+ case 0x10: /* MMC_STAT */
s->status &= ~value;
omap_mmc_interrupts_update(s);
break;
- case 0x14: /* MMC_IE */
+ case 0x14: /* MMC_IE */
s->mask = value & 0x7fff;
omap_mmc_interrupts_update(s);
break;
- case 0x18: /* MMC_CTO */
+ case 0x18: /* MMC_CTO */
s->cto = value & 0xff;
if (s->cto > 0xfd && s->rev <= 1)
printf("MMC: CTO of 0xff and 0xfe cannot be used!\n");
break;
- case 0x1c: /* MMC_DTO */
+ case 0x1c: /* MMC_DTO */
s->dto = value & 0xffff;
break;
- case 0x20: /* MMC_DATA */
+ case 0x20: /* MMC_DATA */
/* TODO: support 8-bit access */
if (s->fifo_len == 32)
break;
@@ -501,18 +509,18 @@ static void omap_mmc_write(void *opaque, hwaddr offset,
omap_mmc_interrupts_update(s);
break;
- case 0x24: /* MMC_BLEN */
+ case 0x24: /* MMC_BLEN */
s->blen = (value & 0x07ff) + 1;
s->blen_counter = s->blen;
break;
- case 0x28: /* MMC_NBLK */
+ case 0x28: /* MMC_NBLK */
s->nblk = (value & 0x07ff) + 1;
s->nblk_counter = s->nblk;
s->blen_counter = s->blen;
break;
- case 0x2c: /* MMC_BUF */
+ case 0x2c: /* MMC_BUF */
s->rx_dma = (value >> 15) & 1;
s->af_level = (value >> 8) & 0x1f;
s->tx_dma = (value >> 7) & 1;
@@ -527,38 +535,38 @@ static void omap_mmc_write(void *opaque, hwaddr offset,
break;
/* SPI, SDIO and TEST modes unimplemented */
- case 0x30: /* MMC_SPI (OMAP1 only) */
+ case 0x30: /* MMC_SPI (OMAP1 only) */
break;
- case 0x34: /* MMC_SDIO */
+ case 0x34: /* MMC_SDIO */
s->sdio = value & (s->rev >= 2 ? 0xfbf3 : 0x2020);
s->cdet_wakeup = (value >> 9) & 1;
s->cdet_enable = (value >> 2) & 1;
break;
- case 0x38: /* MMC_SYST */
+ case 0x38: /* MMC_SYST */
break;
- case 0x3c: /* MMC_REV */
- case 0x40: /* MMC_RSP0 */
- case 0x44: /* MMC_RSP1 */
- case 0x48: /* MMC_RSP2 */
- case 0x4c: /* MMC_RSP3 */
- case 0x50: /* MMC_RSP4 */
- case 0x54: /* MMC_RSP5 */
- case 0x58: /* MMC_RSP6 */
- case 0x5c: /* MMC_RSP7 */
+ case 0x3c: /* MMC_REV */
+ case 0x40: /* MMC_RSP0 */
+ case 0x44: /* MMC_RSP1 */
+ case 0x48: /* MMC_RSP2 */
+ case 0x4c: /* MMC_RSP3 */
+ case 0x50: /* MMC_RSP4 */
+ case 0x54: /* MMC_RSP5 */
+ case 0x58: /* MMC_RSP6 */
+ case 0x5c: /* MMC_RSP7 */
OMAP_RO_REG(offset);
break;
/* OMAP2-specific */
- case 0x60: /* MMC_IOSR */
+ case 0x60: /* MMC_IOSR */
if (value & 0xf)
printf("MMC: SDIO bits used!\n");
break;
- case 0x64: /* MMC_SYSC */
- if (value & (1 << 2)) /* SRTS */
+ case 0x64: /* MMC_SYSC */
+ if (value & (1 << 2)) /* SRTS */
omap_mmc_reset(s);
break;
- case 0x68: /* MMC_SYSS */
+ case 0x68: /* MMC_SYSS */
OMAP_RO_REG(offset);
break;
@@ -573,92 +581,56 @@ static const MemoryRegionOps omap_mmc_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
-static void omap_mmc_cover_cb(void *opaque, int line, int level)
+void omap_mmc_set_clk(DeviceState *dev, omap_clk clk)
{
- struct omap_mmc_s *host = opaque;
+ OMAPMMCState *s = OMAP_MMC(dev);
- if (!host->cdet_state && level) {
- host->status |= 0x0002;
- omap_mmc_interrupts_update(host);
- if (host->cdet_wakeup) {
- /* TODO: Assert wake-up */
- }
- }
-
- if (host->cdet_state != level) {
- qemu_set_irq(host->coverswitch, level);
- host->cdet_state = level;
- }
+ s->clk = clk;
}
-struct omap_mmc_s *omap_mmc_init(hwaddr base,
- MemoryRegion *sysmem,
- BlockBackend *blk,
- qemu_irq irq, qemu_irq dma[], omap_clk clk)
+static void omap_mmc_reset_hold(Object *obj, ResetType type)
{
- struct omap_mmc_s *s = g_new0(struct omap_mmc_s, 1);
-
- s->irq = irq;
- s->dma = dma;
- s->clk = clk;
- s->lines = 1; /* TODO: needs to be settable per-board */
- s->rev = 1;
-
- memory_region_init_io(&s->iomem, NULL, &omap_mmc_ops, s, "omap.mmc", 0x800);
- memory_region_add_subregion(sysmem, base, &s->iomem);
-
- /* Instantiate the storage */
- s->card = sd_init(blk, false);
- if (s->card == NULL) {
- exit(1);
- }
+ OMAPMMCState *s = OMAP_MMC(obj);
omap_mmc_reset(s);
-
- return s;
}
-struct omap_mmc_s *omap2_mmc_init(struct omap_target_agent_s *ta,
- BlockBackend *blk, qemu_irq irq, qemu_irq dma[],
- omap_clk fclk, omap_clk iclk)
+static void omap_mmc_initfn(Object *obj)
{
- struct omap_mmc_s *s = g_new0(struct omap_mmc_s, 1);
-
- s->irq = irq;
- s->dma = dma;
- s->clk = fclk;
- s->lines = 4;
- s->rev = 2;
-
- memory_region_init_io(&s->iomem, NULL, &omap_mmc_ops, s, "omap.mmc",
- omap_l4_region_size(ta, 0));
- omap_l4_attach(ta, 0, &s->iomem);
-
- /* Instantiate the storage */
- s->card = sd_init(blk, false);
- if (s->card == NULL) {
- exit(1);
- }
+ OMAPMMCState *s = OMAP_MMC(obj);
- s->cdet = qemu_allocate_irq(omap_mmc_cover_cb, s, 0);
- sd_set_cb(s->card, NULL, s->cdet);
+ /* In theory these could be settable per-board */
+ s->lines = 1;
+ s->rev = 1;
- omap_mmc_reset(s);
+ memory_region_init_io(&s->iomem, obj, &omap_mmc_ops, s, "omap.mmc", 0x800);
+ sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
- return s;
+ sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
+ qdev_init_gpio_out_named(DEVICE(obj), &s->dma_tx_gpio, "dma-tx", 1);
+ qdev_init_gpio_out_named(DEVICE(obj), &s->dma_rx_gpio, "dma-rx", 1);
+
+ qbus_init(&s->sdbus, sizeof(s->sdbus), TYPE_SD_BUS, DEVICE(obj), "sd-bus");
}
-void omap_mmc_handlers(struct omap_mmc_s *s, qemu_irq ro, qemu_irq cover)
+static void omap_mmc_class_init(ObjectClass *oc, const void *data)
{
- if (s->cdet) {
- sd_set_cb(s->card, ro, s->cdet);
- s->coverswitch = cover;
- qemu_set_irq(cover, s->cdet_state);
- } else
- sd_set_cb(s->card, ro, cover);
+ ResettableClass *rc = RESETTABLE_CLASS(oc);
+
+ rc->phases.hold = omap_mmc_reset_hold;
}
-void omap_mmc_enable(struct omap_mmc_s *s, int enable)
+static const TypeInfo omap_mmc_info = {
+ .name = TYPE_OMAP_MMC,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(OMAPMMCState),
+ .instance_init = omap_mmc_initfn,
+ .class_init = omap_mmc_class_init,
+};
+
+static void omap_mmc_register_types(void)
{
- sd_enable(s->card, enable);
+ type_register_static(&omap_mmc_info);
}
+
+type_init(omap_mmc_register_types)
diff --git a/hw/sd/pl181.c b/hw/sd/pl181.c
index e3633c2..5d56ead 100644
--- a/hw/sd/pl181.c
+++ b/hw/sd/pl181.c
@@ -8,7 +8,7 @@
*/
#include "qemu/osdep.h"
-#include "sysemu/blockdev.h"
+#include "system/blockdev.h"
#include "hw/sysbus.h"
#include "migration/vmstate.h"
#include "hw/irq.h"
@@ -173,14 +173,12 @@ static void pl181_do_command(PL181State *s)
{
SDRequest request;
uint8_t response[16];
- int rlen;
+ size_t rlen;
request.cmd = s->cmd & PL181_CMD_INDEX;
request.arg = s->cmdarg;
trace_pl181_command_send(request.cmd, request.arg);
- rlen = sdbus_do_command(&s->sdbus, &request, response);
- if (rlen < 0)
- goto error;
+ rlen = sdbus_do_command(&s->sdbus, &request, response, sizeof(response));
if (s->cmd & PL181_CMD_RESPONSE) {
if (rlen == 0 || (rlen == 4 && (s->cmd & PL181_CMD_LONGRESP)))
goto error;
@@ -509,17 +507,17 @@ static void pl181_init(Object *obj)
qbus_init(&s->sdbus, sizeof(s->sdbus), TYPE_PL181_BUS, dev, "sd-bus");
}
-static void pl181_class_init(ObjectClass *klass, void *data)
+static void pl181_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *k = DEVICE_CLASS(klass);
k->vmsd = &vmstate_pl181;
- k->reset = pl181_reset;
+ device_class_set_legacy_reset(k, pl181_reset);
/* Reason: output IRQs should be wired up */
k->user_creatable = false;
}
-static void pl181_bus_class_init(ObjectClass *klass, void *data)
+static void pl181_bus_class_init(ObjectClass *klass, const void *data)
{
SDBusClass *sbc = SD_BUS_CLASS(klass);
diff --git a/hw/sd/pxa2xx_mmci.c b/hw/sd/pxa2xx_mmci.c
deleted file mode 100644
index 8252970..0000000
--- a/hw/sd/pxa2xx_mmci.c
+++ /dev/null
@@ -1,594 +0,0 @@
-/*
- * Intel XScale PXA255/270 MultiMediaCard/SD/SDIO Controller emulation.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GPLv2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/irq.h"
-#include "hw/sysbus.h"
-#include "migration/vmstate.h"
-#include "hw/arm/pxa.h"
-#include "hw/sd/sd.h"
-#include "hw/qdev-properties.h"
-#include "qemu/log.h"
-#include "qemu/module.h"
-#include "trace.h"
-#include "qom/object.h"
-
-#define TYPE_PXA2XX_MMCI_BUS "pxa2xx-mmci-bus"
-/* This is reusing the SDBus typedef from SD_BUS */
-DECLARE_INSTANCE_CHECKER(SDBus, PXA2XX_MMCI_BUS,
- 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;
-
- BlockBackend *blk;
- SDBus sdbus;
-
- uint32_t status;
- uint32_t clkrt;
- uint32_t spi;
- uint32_t cmdat;
- uint32_t resp_tout;
- uint32_t read_tout;
- int32_t blklen;
- int32_t numblk;
- uint32_t intmask;
- uint32_t intreq;
- int32_t cmd;
- uint32_t arg;
-
- int32_t active;
- int32_t bytesleft;
- uint8_t tx_fifo[64];
- uint32_t tx_start;
- uint32_t tx_len;
- uint8_t rx_fifo[32];
- uint32_t rx_start;
- uint32_t rx_len;
- uint16_t resp_fifo[9];
- uint32_t resp_len;
-
- 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 = (const 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 */
-#define MMC_STAT 0x04 /* MMC Status register */
-#define MMC_CLKRT 0x08 /* MMC Clock Rate register */
-#define MMC_SPI 0x0c /* MMC SPI Mode register */
-#define MMC_CMDAT 0x10 /* MMC Command/Data register */
-#define MMC_RESTO 0x14 /* MMC Response Time-Out register */
-#define MMC_RDTO 0x18 /* MMC Read Time-Out register */
-#define MMC_BLKLEN 0x1c /* MMC Block Length register */
-#define MMC_NUMBLK 0x20 /* MMC Number of Blocks register */
-#define MMC_PRTBUF 0x24 /* MMC Buffer Partly Full register */
-#define MMC_I_MASK 0x28 /* MMC Interrupt Mask register */
-#define MMC_I_REG 0x2c /* MMC Interrupt Request register */
-#define MMC_CMD 0x30 /* MMC Command register */
-#define MMC_ARGH 0x34 /* MMC Argument High register */
-#define MMC_ARGL 0x38 /* MMC Argument Low register */
-#define MMC_RES 0x3c /* MMC Response FIFO */
-#define MMC_RXFIFO 0x40 /* MMC Receive FIFO */
-#define MMC_TXFIFO 0x44 /* MMC Transmit FIFO */
-#define MMC_RDWAIT 0x48 /* MMC RD_WAIT register */
-#define MMC_BLKS_REM 0x4c /* MMC Blocks Remaining register */
-
-/* Bitfield masks */
-#define STRPCL_STOP_CLK (1 << 0)
-#define STRPCL_STRT_CLK (1 << 1)
-#define STAT_TOUT_RES (1 << 1)
-#define STAT_CLK_EN (1 << 8)
-#define STAT_DATA_DONE (1 << 11)
-#define STAT_PRG_DONE (1 << 12)
-#define STAT_END_CMDRES (1 << 13)
-#define SPI_SPI_MODE (1 << 0)
-#define CMDAT_RES_TYPE (3 << 0)
-#define CMDAT_DATA_EN (1 << 2)
-#define CMDAT_WR_RD (1 << 3)
-#define CMDAT_DMA_EN (1 << 7)
-#define CMDAT_STOP_TRAN (1 << 10)
-#define INT_DATA_DONE (1 << 0)
-#define INT_PRG_DONE (1 << 1)
-#define INT_END_CMD (1 << 2)
-#define INT_STOP_CMD (1 << 3)
-#define INT_CLK_OFF (1 << 4)
-#define INT_RXFIFO_REQ (1 << 5)
-#define INT_TXFIFO_REQ (1 << 6)
-#define INT_TINT (1 << 7)
-#define INT_DAT_ERR (1 << 8)
-#define INT_RES_ERR (1 << 9)
-#define INT_RD_STALLED (1 << 10)
-#define INT_SDIO_INT (1 << 11)
-#define INT_SDIO_SACK (1 << 12)
-#define PRTBUF_PRT_BUF (1 << 0)
-
-/* Route internal interrupt lines to the global IC and DMA */
-static void pxa2xx_mmci_int_update(PXA2xxMMCIState *s)
-{
- uint32_t mask = s->intmask;
- if (s->cmdat & CMDAT_DMA_EN) {
- mask |= INT_RXFIFO_REQ | INT_TXFIFO_REQ;
-
- qemu_set_irq(s->rx_dma, !!(s->intreq & INT_RXFIFO_REQ));
- qemu_set_irq(s->tx_dma, !!(s->intreq & INT_TXFIFO_REQ));
- }
-
- qemu_set_irq(s->irq, !!(s->intreq & ~mask));
-}
-
-static void pxa2xx_mmci_fifo_update(PXA2xxMMCIState *s)
-{
- if (!s->active)
- return;
-
- if (s->cmdat & CMDAT_WR_RD) {
- while (s->bytesleft && s->tx_len) {
- sdbus_write_byte(&s->sdbus, s->tx_fifo[s->tx_start++]);
- s->tx_start &= 0x1f;
- s->tx_len --;
- s->bytesleft --;
- }
- if (s->bytesleft)
- s->intreq |= INT_TXFIFO_REQ;
- } else
- while (s->bytesleft && s->rx_len < 32) {
- s->rx_fifo[(s->rx_start + (s->rx_len ++)) & 0x1f] =
- sdbus_read_byte(&s->sdbus);
- s->bytesleft --;
- s->intreq |= INT_RXFIFO_REQ;
- }
-
- if (!s->bytesleft) {
- s->active = 0;
- s->intreq |= INT_DATA_DONE;
- s->status |= STAT_DATA_DONE;
-
- if (s->cmdat & CMDAT_WR_RD) {
- s->intreq |= INT_PRG_DONE;
- s->status |= STAT_PRG_DONE;
- }
- }
-
- pxa2xx_mmci_int_update(s);
-}
-
-static void pxa2xx_mmci_wakequeues(PXA2xxMMCIState *s)
-{
- int rsplen, i;
- SDRequest request;
- uint8_t response[16];
-
- s->active = 1;
- s->rx_len = 0;
- s->tx_len = 0;
- s->cmdreq = 0;
-
- request.cmd = s->cmd;
- request.arg = s->arg;
- request.crc = 0; /* FIXME */
-
- rsplen = sdbus_do_command(&s->sdbus, &request, response);
- s->intreq |= INT_END_CMD;
-
- memset(s->resp_fifo, 0, sizeof(s->resp_fifo));
- switch (s->cmdat & CMDAT_RES_TYPE) {
-#define PXAMMCI_RESP(wd, value0, value1) \
- s->resp_fifo[(wd) + 0] |= (value0); \
- s->resp_fifo[(wd) + 1] |= (value1) << 8;
- case 0: /* No response */
- goto complete;
-
- case 1: /* R1, R4, R5 or R6 */
- if (rsplen < 4)
- goto timeout;
- goto complete;
-
- case 2: /* R2 */
- if (rsplen < 16)
- goto timeout;
- goto complete;
-
- case 3: /* R3 */
- if (rsplen < 4)
- goto timeout;
- goto complete;
-
- complete:
- for (i = 0; rsplen > 0; i ++, rsplen -= 2) {
- PXAMMCI_RESP(i, response[i * 2], response[i * 2 + 1]);
- }
- s->status |= STAT_END_CMDRES;
-
- if (!(s->cmdat & CMDAT_DATA_EN))
- s->active = 0;
- else
- s->bytesleft = s->numblk * s->blklen;
-
- s->resp_len = 0;
- break;
-
- timeout:
- s->active = 0;
- s->status |= STAT_TOUT_RES;
- break;
- }
-
- pxa2xx_mmci_fifo_update(s);
-}
-
-static uint64_t pxa2xx_mmci_read(void *opaque, hwaddr offset, unsigned size)
-{
- PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
- uint32_t ret = 0;
-
- switch (offset) {
- case MMC_STRPCL:
- break;
- case MMC_STAT:
- ret = s->status;
- break;
- case MMC_CLKRT:
- ret = s->clkrt;
- break;
- case MMC_SPI:
- ret = s->spi;
- break;
- case MMC_CMDAT:
- ret = s->cmdat;
- break;
- case MMC_RESTO:
- ret = s->resp_tout;
- break;
- case MMC_RDTO:
- ret = s->read_tout;
- break;
- case MMC_BLKLEN:
- ret = s->blklen;
- break;
- case MMC_NUMBLK:
- ret = s->numblk;
- break;
- case MMC_PRTBUF:
- break;
- case MMC_I_MASK:
- ret = s->intmask;
- break;
- case MMC_I_REG:
- ret = s->intreq;
- break;
- case MMC_CMD:
- ret = s->cmd | 0x40;
- break;
- case MMC_ARGH:
- ret = s->arg >> 16;
- break;
- case MMC_ARGL:
- ret = s->arg & 0xffff;
- break;
- case MMC_RES:
- ret = (s->resp_len < 9) ? s->resp_fifo[s->resp_len++] : 0;
- break;
- case MMC_RXFIFO:
- while (size-- && s->rx_len) {
- ret |= s->rx_fifo[s->rx_start++] << (size << 3);
- s->rx_start &= 0x1f;
- s->rx_len --;
- }
- s->intreq &= ~INT_RXFIFO_REQ;
- pxa2xx_mmci_fifo_update(s);
- break;
- case MMC_RDWAIT:
- break;
- case MMC_BLKS_REM:
- ret = s->numblk;
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: incorrect register 0x%02" HWADDR_PRIx "\n",
- __func__, offset);
- }
- trace_pxa2xx_mmci_read(size, offset, ret);
-
- return ret;
-}
-
-static void pxa2xx_mmci_write(void *opaque,
- hwaddr offset, uint64_t value, unsigned size)
-{
- PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
-
- trace_pxa2xx_mmci_write(size, offset, value);
- switch (offset) {
- case MMC_STRPCL:
- if (value & STRPCL_STRT_CLK) {
- s->status |= STAT_CLK_EN;
- s->intreq &= ~INT_CLK_OFF;
-
- if (s->cmdreq && !(s->cmdat & CMDAT_STOP_TRAN)) {
- s->status &= STAT_CLK_EN;
- pxa2xx_mmci_wakequeues(s);
- }
- }
-
- if (value & STRPCL_STOP_CLK) {
- s->status &= ~STAT_CLK_EN;
- s->intreq |= INT_CLK_OFF;
- s->active = 0;
- }
-
- pxa2xx_mmci_int_update(s);
- break;
-
- case MMC_CLKRT:
- s->clkrt = value & 7;
- break;
-
- case MMC_SPI:
- s->spi = value & 0xf;
- if (value & SPI_SPI_MODE) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: attempted to use card in SPI mode\n", __func__);
- }
- break;
-
- case MMC_CMDAT:
- s->cmdat = value & 0x3dff;
- s->active = 0;
- s->cmdreq = 1;
- if (!(value & CMDAT_STOP_TRAN)) {
- s->status &= STAT_CLK_EN;
-
- if (s->status & STAT_CLK_EN)
- pxa2xx_mmci_wakequeues(s);
- }
-
- pxa2xx_mmci_int_update(s);
- break;
-
- case MMC_RESTO:
- s->resp_tout = value & 0x7f;
- break;
-
- case MMC_RDTO:
- s->read_tout = value & 0xffff;
- break;
-
- case MMC_BLKLEN:
- s->blklen = value & 0xfff;
- break;
-
- case MMC_NUMBLK:
- s->numblk = value & 0xffff;
- break;
-
- case MMC_PRTBUF:
- if (value & PRTBUF_PRT_BUF) {
- s->tx_start ^= 32;
- s->tx_len = 0;
- }
- pxa2xx_mmci_fifo_update(s);
- break;
-
- case MMC_I_MASK:
- s->intmask = value & 0x1fff;
- pxa2xx_mmci_int_update(s);
- break;
-
- case MMC_CMD:
- s->cmd = value & 0x3f;
- break;
-
- case MMC_ARGH:
- s->arg &= 0x0000ffff;
- s->arg |= value << 16;
- break;
-
- case MMC_ARGL:
- s->arg &= 0xffff0000;
- s->arg |= value & 0x0000ffff;
- break;
-
- case MMC_TXFIFO:
- while (size-- && s->tx_len < 0x20)
- s->tx_fifo[(s->tx_start + (s->tx_len ++)) & 0x1f] =
- (value >> (size << 3)) & 0xff;
- s->intreq &= ~INT_TXFIFO_REQ;
- pxa2xx_mmci_fifo_update(s);
- break;
-
- case MMC_RDWAIT:
- case MMC_BLKS_REM:
- break;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: incorrect reg 0x%02" HWADDR_PRIx " "
- "(value 0x%08" PRIx64 ")\n", __func__, offset, value);
- }
-}
-
-static const MemoryRegionOps pxa2xx_mmci_ops = {
- .read = pxa2xx_mmci_read,
- .write = pxa2xx_mmci_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-PXA2xxMMCIState *pxa2xx_mmci_init(MemoryRegion *sysmem,
- hwaddr base,
- qemu_irq irq, qemu_irq rx_dma, qemu_irq tx_dma)
-{
- DeviceState *dev;
-
- dev = sysbus_create_simple(TYPE_PXA2XX_MMCI, base, irq);
- qdev_connect_gpio_out_named(dev, "rx-dma", 0, rx_dma);
- qdev_connect_gpio_out_named(dev, "tx-dma", 0, tx_dma);
-
- return PXA2XX_MMCI(dev);
-}
-
-static void pxa2xx_mmci_set_inserted(DeviceState *dev, bool inserted)
-{
- PXA2xxMMCIState *s = PXA2XX_MMCI(dev);
-
- qemu_set_irq(s->inserted, inserted);
-}
-
-static void pxa2xx_mmci_set_readonly(DeviceState *dev, bool readonly)
-{
- PXA2xxMMCIState *s = PXA2XX_MMCI(dev);
-
- qemu_set_irq(s->readonly, readonly);
-}
-
-void pxa2xx_mmci_handlers(PXA2xxMMCIState *s, qemu_irq readonly,
- qemu_irq coverswitch)
-{
- 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));
-}
-
-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, obj, &pxa2xx_mmci_ops, s,
- "pxa2xx-mmci", 0x00100000);
- 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);
-
- qbus_init(&s->sdbus, sizeof(s->sdbus),
- TYPE_PXA2XX_MMCI_BUS, DEVICE(obj), "sd-bus");
-}
-
-static void pxa2xx_mmci_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->vmsd = &vmstate_pxa2xx_mmci;
- dc->reset = pxa2xx_mmci_reset;
-}
-
-static void pxa2xx_mmci_bus_class_init(ObjectClass *klass, void *data)
-{
- 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_types[] = {
- {
- .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,
- },
- {
- .name = TYPE_PXA2XX_MMCI_BUS,
- .parent = TYPE_SD_BUS,
- .instance_size = sizeof(SDBus),
- .class_init = pxa2xx_mmci_bus_class_init,
- },
-};
-
-DEFINE_TYPES(pxa2xx_mmci_types)
diff --git a/hw/sd/sd.c b/hw/sd/sd.c
index a140a32..d7a496d 100644
--- a/hw/sd/sd.c
+++ b/hw/sd/sd.c
@@ -37,9 +37,8 @@
#include "qemu/cutils.h"
#include "hw/irq.h"
#include "hw/registerfields.h"
-#include "sysemu/block-backend.h"
+#include "system/block-backend.h"
#include "hw/sd/sd.h"
-#include "hw/sd/sdcard_legacy.h"
#include "migration/vmstate.h"
#include "qapi/error.h"
#include "qemu/bitmap.h"
@@ -62,6 +61,7 @@
typedef enum {
sd_r0 = 0, /* no response */
sd_r1, /* normal response command */
+ spi_r2, /* STATUS */
sd_r2_i, /* CID register */
sd_r2_s, /* CSD register */
sd_r3, /* OCR register */
@@ -71,6 +71,14 @@ typedef enum {
sd_illegal = -2,
} sd_rsp_type_t;
+typedef enum {
+ sd_spi,
+ sd_bc, /* broadcast -- no response */
+ sd_bcr, /* broadcast with response */
+ sd_ac, /* addressed -- no data transfer */
+ sd_adtc, /* addressed with data transfer */
+} sd_cmd_type_t;
+
enum SDCardModes {
sd_inactive,
sd_card_identification_mode,
@@ -112,10 +120,6 @@ typedef struct SDProto {
struct SDState {
DeviceState parent_obj;
- /* If true, created by sd_init() for a non-qdevified caller */
- /* TODO purge them with fire */
- bool me_no_qdev_me_kill_mammoth_with_rocks;
-
/* SD Memory Card Registers */
uint32_t ocr;
uint8_t scr[8];
@@ -143,7 +147,6 @@ struct SDState {
/* Runtime changeables */
- uint32_t mode; /* current card mode, one of SDCardModes */
int32_t state; /* current card state, one of SDCardStates */
uint32_t vhs;
bool wp_switch;
@@ -169,10 +172,7 @@ struct SDState {
uint32_t data_offset;
size_t data_size;
uint8_t data[512];
- qemu_irq readonly_cb;
- qemu_irq inserted_cb;
QEMUTimer *ocr_power_timer;
- bool enable;
uint8_t dat_lines;
bool cmd_line;
};
@@ -195,7 +195,6 @@ static bool sd_is_emmc(SDState *sd)
static const char *sd_version_str(enum SDPhySpecificationVersion version)
{
static const char *sdphy_version[] = {
- [SD_PHY_SPECv1_10_VERS] = "v1.10",
[SD_PHY_SPECv2_00_VERS] = "v2.00",
[SD_PHY_SPECv3_01_VERS] = "v3.01",
};
@@ -247,6 +246,7 @@ static const char *sd_response_name(sd_rsp_type_t rsp)
static const char *response_name[] = {
[sd_r0] = "RESP#0 (no response)",
[sd_r1] = "RESP#1 (normal cmd)",
+ [spi_r2] = "RESP#2 (STATUS reg)",
[sd_r2_i] = "RESP#2 (CID reg)",
[sd_r2_s] = "RESP#2 (CSD reg)",
[sd_r3] = "RESP#3 (OCR reg)",
@@ -291,12 +291,12 @@ static const char *sd_acmd_name(SDState *sd, uint8_t cmd)
static uint8_t sd_get_dat_lines(SDState *sd)
{
- return sd->enable ? sd->dat_lines : 0;
+ return sd->dat_lines;
}
static bool sd_get_cmd_line(SDState *sd)
{
- return sd->enable ? sd->cmd_line : false;
+ return sd->cmd_line;
}
static void sd_set_voltage(SDState *sd, uint16_t millivolts)
@@ -313,27 +313,24 @@ static void sd_set_voltage(SDState *sd, uint16_t millivolts)
}
}
-static void sd_set_mode(SDState *sd)
+static enum SDCardModes sd_mode(SDState *sd)
{
switch (sd->state) {
case sd_inactive_state:
- sd->mode = sd_inactive;
- break;
-
+ return sd_inactive;
case sd_idle_state:
case sd_ready_state:
case sd_identification_state:
- sd->mode = sd_card_identification_mode;
- break;
-
+ return sd_card_identification_mode;
case sd_standby_state:
case sd_transfer_state:
case sd_sendingdata_state:
case sd_receivingdata_state:
case sd_programming_state:
case sd_disconnect_state:
- sd->mode = sd_data_transfer_mode;
- break;
+ return sd_data_transfer_mode;
+ default:
+ g_assert_not_reached();
}
}
@@ -409,11 +406,7 @@ static void sd_set_ocr(SDState *sd)
static void sd_set_scr(SDState *sd)
{
sd->scr[0] = 0 << 4; /* SCR structure version 1.0 */
- if (sd->spec_version == SD_PHY_SPECv1_10_VERS) {
- sd->scr[0] |= 1; /* Spec Version 1.10 */
- } else {
- sd->scr[0] |= 2; /* Spec Version 2.00 or Version 3.0X */
- }
+ sd->scr[0] |= 2; /* Spec Version 2.00 or Version 3.0X */
sd->scr[1] = (2 << 4) /* SDSC Card (Security Version 1.01) */
| 0b0101; /* 1-bit or 4-bit width bus modes */
sd->scr[2] = 0x00; /* Extended Security is not supported. */
@@ -729,16 +722,82 @@ static int sd_req_crc_validate(SDRequest *req)
return sd_crc7(buffer, 5) != req->crc; /* TODO */
}
+static size_t sd_response_size(SDState *sd, sd_rsp_type_t rtype)
+{
+ switch (rtype) {
+ case sd_r1:
+ case sd_r1b:
+ return sd_is_spi(sd) ? 1 : 4;
+
+ case spi_r2:
+ assert(sd_is_spi(sd));
+ return 2;
+
+ case sd_r2_i:
+ case sd_r2_s:
+ assert(!sd_is_spi(sd));
+ return 16;
+
+ case sd_r3:
+ case sd_r7:
+ return sd_is_spi(sd) ? 5 : 4;
+
+ case sd_r6:
+ assert(!sd_is_spi(sd));
+ return 4;
+
+ case sd_r0:
+ case sd_illegal:
+ return sd_is_spi(sd) ? 1 : 0;
+
+ default:
+ g_assert_not_reached();
+ }
+}
+
static void sd_response_r1_make(SDState *sd, uint8_t *response)
{
- stl_be_p(response, sd->card_status);
+ if (sd_is_spi(sd)) {
+ response[0] = sd->state == sd_idle_state
+ && !FIELD_EX32(sd->ocr, OCR, CARD_POWER_UP);
+ response[0] |= FIELD_EX32(sd->card_status, CSR, ERASE_RESET) << 1;
+ response[0] |= FIELD_EX32(sd->card_status, CSR, ILLEGAL_COMMAND) << 2;
+ response[0] |= FIELD_EX32(sd->card_status, CSR, COM_CRC_ERROR) << 3;
+ response[0] |= FIELD_EX32(sd->card_status, CSR, ERASE_SEQ_ERROR) << 4;
+ response[0] |= FIELD_EX32(sd->card_status, CSR, ADDRESS_ERROR) << 5;
+ response[0] |= FIELD_EX32(sd->card_status, CSR, BLOCK_LEN_ERROR) << 6;
+ response[0] |= 0 << 7;
+ } else {
+ stl_be_p(response, sd->card_status);
+ }
/* Clear the "clear on read" status bits */
sd->card_status &= ~CARD_STATUS_C;
}
+static void spi_response_r2_make(SDState *sd, uint8_t *resp)
+{
+ /* Prepend R1 */
+ sd_response_r1_make(sd, resp);
+
+ resp[1] = FIELD_EX32(sd->card_status, CSR, CARD_IS_LOCKED) << 0;
+ resp[1] |= (FIELD_EX32(sd->card_status, CSR, LOCK_UNLOCK_FAILED)
+ || FIELD_EX32(sd->card_status, CSR, WP_ERASE_SKIP)) << 1;
+ resp[1] |= FIELD_EX32(sd->card_status, CSR, ERROR) << 2;
+ resp[1] |= FIELD_EX32(sd->card_status, CSR, CC_ERROR) << 3;
+ resp[1] |= FIELD_EX32(sd->card_status, CSR, CARD_ECC_FAILED) << 4;
+ resp[1] |= FIELD_EX32(sd->card_status, CSR, WP_VIOLATION) << 5;
+ resp[1] |= FIELD_EX32(sd->card_status, CSR, ERASE_PARAM) << 6;
+ resp[1] |= FIELD_EX32(sd->card_status, CSR, OUT_OF_RANGE) << 7;
+}
+
static void sd_response_r3_make(SDState *sd, uint8_t *response)
{
+ if (sd_is_spi(sd)) {
+ /* Prepend R1 */
+ sd_response_r1_make(sd, response);
+ response++;
+ }
stl_be_p(response, sd->ocr & ACMD41_R3_MASK);
}
@@ -756,6 +815,11 @@ static void sd_response_r6_make(SDState *sd, uint8_t *response)
static void sd_response_r7_make(SDState *sd, uint8_t *response)
{
+ if (sd_is_spi(sd)) {
+ /* Prepend R1 */
+ sd_response_r1_make(sd, response);
+ response++;
+ }
stl_be_p(response, sd->vhs);
}
@@ -769,21 +833,14 @@ static uint32_t sd_blk_len(SDState *sd)
/*
* This requires a disk image that has two boot partitions inserted at the
- * beginning of it. The size of the boot partitions is the "boot-size"
- * property.
+ * beginning of it, followed by an RPMB partition. The size of the boot
+ * partitions is the "boot-partition-size" property.
*/
-static uint32_t sd_bootpart_offset(SDState *sd)
+static uint32_t sd_part_offset(SDState *sd)
{
- bool partitions_enabled;
unsigned partition_access;
- if (!sd->boot_part_size || !sd_is_emmc(sd)) {
- return 0;
- }
-
- partitions_enabled = sd->ext_csd[EXT_CSD_PART_CONFIG]
- & EXT_CSD_PART_CONFIG_EN_MASK;
- if (!partitions_enabled) {
+ if (!sd_is_emmc(sd)) {
return 0;
}
@@ -792,9 +849,9 @@ static uint32_t sd_bootpart_offset(SDState *sd)
switch (partition_access) {
case EXT_CSD_PART_CONFIG_ACC_DEFAULT:
return sd->boot_part_size * 2;
- case EXT_CSD_PART_CONFIG_ACC_BOOT0:
+ case EXT_CSD_PART_CONFIG_ACC_BOOT1:
return 0;
- case EXT_CSD_PART_CONFIG_ACC_BOOT0 + 1:
+ case EXT_CSD_PART_CONFIG_ACC_BOOT2:
return sd->boot_part_size * 1;
default:
g_assert_not_reached();
@@ -833,7 +890,9 @@ static void sd_reset(DeviceState *dev)
sect = 0;
}
size = sect << HWBLOCK_SHIFT;
- size -= sd_bootpart_offset(sd);
+ if (sd_is_emmc(sd)) {
+ size -= sd->boot_part_size * 2;
+ }
sect = sd_addr_to_wpnum(size) + 1;
@@ -889,17 +948,10 @@ static void sd_cardchange(void *opaque, bool load, Error **errp)
trace_sdcard_ejected();
}
- if (sd->me_no_qdev_me_kill_mammoth_with_rocks) {
- qemu_set_irq(sd->inserted_cb, inserted);
- if (inserted) {
- qemu_set_irq(sd->readonly_cb, readonly);
- }
- } else {
- sdbus = SD_BUS(qdev_get_parent_bus(dev));
- sdbus_set_inserted(sdbus, inserted);
- if (inserted) {
- sdbus_set_readonly(sdbus, readonly);
- }
+ sdbus = SD_BUS(qdev_get_parent_bus(dev));
+ sdbus_set_inserted(sdbus, inserted);
+ if (inserted) {
+ sdbus_set_readonly(sdbus, readonly);
}
}
@@ -964,7 +1016,7 @@ static const VMStateDescription sd_vmstate = {
.minimum_version_id = 2,
.pre_load = sd_vmstate_pre_load,
.fields = (const VMStateField[]) {
- VMSTATE_UINT32(mode, SDState),
+ VMSTATE_UNUSED(4),
VMSTATE_INT32(state, SDState),
VMSTATE_UINT8_ARRAY(cid, SDState, 16),
VMSTATE_UINT8_ARRAY(csd, SDState, 16),
@@ -987,7 +1039,7 @@ static const VMStateDescription sd_vmstate = {
VMSTATE_UINT32(data_offset, SDState),
VMSTATE_UINT8_ARRAY(data, SDState, 512),
VMSTATE_UNUSED_V(1, 512),
- VMSTATE_BOOL(enable, SDState),
+ VMSTATE_UNUSED(1),
VMSTATE_END_OF_LIST()
},
.subsections = (const VMStateDescription * const []) {
@@ -997,52 +1049,10 @@ static const VMStateDescription sd_vmstate = {
},
};
-/* Legacy initialization function for use by non-qdevified callers */
-SDState *sd_init(BlockBackend *blk, bool is_spi)
-{
- Object *obj;
- DeviceState *dev;
- SDState *sd;
- Error *err = NULL;
-
- obj = object_new(is_spi ? TYPE_SD_CARD_SPI : TYPE_SD_CARD);
- dev = DEVICE(obj);
- if (!qdev_prop_set_drive_err(dev, "drive", blk, &err)) {
- error_reportf_err(err, "sd_init failed: ");
- return NULL;
- }
-
- /*
- * Realizing the device properly would put it into the QOM
- * composition tree even though it is not plugged into an
- * appropriate bus. That's a no-no. Hide the device from
- * QOM/qdev, and call its qdev realize callback directly.
- */
- object_ref(obj);
- object_unparent(obj);
- sd_realize(dev, &err);
- if (err) {
- error_reportf_err(err, "sd_init failed: ");
- return NULL;
- }
-
- sd = SD_CARD(dev);
- sd->me_no_qdev_me_kill_mammoth_with_rocks = true;
- return sd;
-}
-
-void sd_set_cb(SDState *sd, qemu_irq readonly, qemu_irq insert)
-{
- sd->readonly_cb = readonly;
- sd->inserted_cb = insert;
- qemu_set_irq(readonly, sd->blk ? !blk_is_writable(sd->blk) : 0);
- qemu_set_irq(insert, sd->blk ? blk_is_inserted(sd->blk) : 0);
-}
-
static void sd_blk_read(SDState *sd, uint64_t addr, uint32_t len)
{
trace_sdcard_read_block(addr, len);
- addr += sd_bootpart_offset(sd);
+ addr += sd_part_offset(sd);
if (!sd->blk || blk_pread(sd->blk, addr, len, sd->data, 0) < 0) {
fprintf(stderr, "sd_blk_read: read error on host side\n");
}
@@ -1051,7 +1061,7 @@ static void sd_blk_read(SDState *sd, uint64_t addr, uint32_t len)
static void sd_blk_write(SDState *sd, uint64_t addr, uint32_t len)
{
trace_sdcard_write_block(addr, len);
- addr += sd_bootpart_offset(sd);
+ addr += sd_part_offset(sd);
if (!sd->blk || blk_pwrite(sd->blk, addr, len, sd->data, 0) < 0) {
fprintf(stderr, "sd_blk_write: write error on host side\n");
}
@@ -1306,7 +1316,7 @@ static sd_rsp_type_t sd_invalid_state_for_cmd(SDState *sd, SDRequest req)
static sd_rsp_type_t sd_invalid_mode_for_cmd(SDState *sd, SDRequest req)
{
qemu_log_mask(LOG_GUEST_ERROR, "%s: CMD%i in a wrong mode: %s (spec %s)\n",
- sd->proto->name, req.cmd, sd_mode_name(sd->mode),
+ sd->proto->name, req.cmd, sd_mode_name(sd_mode(sd)),
sd_version_str(sd->spec_version));
return sd_illegal;
@@ -1359,7 +1369,7 @@ static sd_rsp_type_t sd_cmd_to_sendingdata(SDState *sd, SDRequest req,
const void *data, size_t size)
{
if (sd->state != sd_transfer_state) {
- sd_invalid_state_for_cmd(sd, req);
+ return sd_invalid_state_for_cmd(sd, req);
}
sd->state = sd_sendingdata_state;
@@ -1395,14 +1405,6 @@ static sd_rsp_type_t sd_cmd_GO_IDLE_STATE(SDState *sd, SDRequest req)
return sd_is_spi(sd) ? sd_r1 : sd_r0;
}
-/* CMD1 */
-static sd_rsp_type_t spi_cmd_SEND_OP_COND(SDState *sd, SDRequest req)
-{
- sd->state = sd_transfer_state;
-
- return sd_r1;
-}
-
/* CMD2 */
static sd_rsp_type_t sd_cmd_ALL_SEND_CID(SDState *sd, SDRequest req)
{
@@ -1474,11 +1476,17 @@ static sd_rsp_type_t emmc_cmd_sleep_awake(SDState *sd, SDRequest req)
/* CMD6 */
static sd_rsp_type_t sd_cmd_SWITCH_FUNCTION(SDState *sd, SDRequest req)
{
- if (sd->mode != sd_data_transfer_mode) {
+ if (sd_mode(sd) != sd_data_transfer_mode) {
return sd_invalid_mode_for_cmd(sd, req);
}
- if (sd->state != sd_transfer_state) {
- return sd_invalid_state_for_cmd(sd, req);
+ if (sd_is_spi(sd)) {
+ if (sd->state == sd_idle_state) {
+ return sd_invalid_state_for_cmd(sd, req);
+ }
+ } else {
+ if (sd->state != sd_transfer_state) {
+ return sd_invalid_state_for_cmd(sd, req);
+ }
}
sd_function_switch(sd, req.arg);
@@ -1542,9 +1550,6 @@ static sd_rsp_type_t sd_cmd_DE_SELECT_CARD(SDState *sd, SDRequest req)
/* CMD8 */
static sd_rsp_type_t sd_cmd_SEND_IF_COND(SDState *sd, SDRequest req)
{
- if (sd->spec_version < SD_PHY_SPECv2_00_VERS) {
- return sd_cmd_illegal(sd, req);
- }
if (sd->state != sd_idle_state) {
return sd_invalid_state_for_cmd(sd, req);
}
@@ -1571,14 +1576,30 @@ static sd_rsp_type_t emmc_cmd_SEND_EXT_CSD(SDState *sd, SDRequest req)
sd->ext_csd, sizeof(sd->ext_csd));
}
-/* CMD9 */
-static sd_rsp_type_t spi_cmd_SEND_CSD(SDState *sd, SDRequest req)
+static sd_rsp_type_t spi_cmd_SEND_CxD(SDState *sd, SDRequest req,
+ const void *data, size_t size)
{
+ /*
+ * XXX as of v10.1.0-rc1 command is reached in sd_idle_state,
+ * so disable this check.
if (sd->state != sd_standby_state) {
return sd_invalid_state_for_cmd(sd, req);
}
- return sd_cmd_to_sendingdata(sd, req, sd_req_get_address(sd, req),
- sd->csd, 16);
+ */
+
+ /*
+ * Since SPI returns CSD and CID on the DAT lines,
+ * switch to sd_transfer_state.
+ */
+ sd->state = sd_transfer_state;
+
+ return sd_cmd_to_sendingdata(sd, req, 0, data, size);
+}
+
+/* CMD9 */
+static sd_rsp_type_t spi_cmd_SEND_CSD(SDState *sd, SDRequest req)
+{
+ return spi_cmd_SEND_CxD(sd, req, sd->csd, sizeof(sd->csd));
}
static sd_rsp_type_t sd_cmd_SEND_CSD(SDState *sd, SDRequest req)
@@ -1593,11 +1614,7 @@ static sd_rsp_type_t sd_cmd_SEND_CSD(SDState *sd, SDRequest req)
/* CMD10 */
static sd_rsp_type_t spi_cmd_SEND_CID(SDState *sd, SDRequest req)
{
- if (sd->state != sd_standby_state) {
- return sd_invalid_state_for_cmd(sd, req);
- }
- return sd_cmd_to_sendingdata(sd, req, sd_req_get_address(sd, req),
- sd->cid, 16);
+ return spi_cmd_SEND_CxD(sd, req, sd->cid, sizeof(sd->cid));
}
static sd_rsp_type_t sd_cmd_SEND_CID(SDState *sd, SDRequest req)
@@ -1629,7 +1646,7 @@ static sd_rsp_type_t sd_cmd_STOP_TRANSMISSION(SDState *sd, SDRequest req)
/* CMD13 */
static sd_rsp_type_t sd_cmd_SEND_STATUS(SDState *sd, SDRequest req)
{
- if (sd->mode != sd_data_transfer_mode) {
+ if (sd_mode(sd) != sd_data_transfer_mode) {
return sd_invalid_mode_for_cmd(sd, req);
}
@@ -1646,7 +1663,7 @@ static sd_rsp_type_t sd_cmd_SEND_STATUS(SDState *sd, SDRequest req)
}
if (sd_is_spi(sd)) {
- return sd_r2_s;
+ return spi_r2;
}
return sd_req_rca_same(sd, req) ? sd_r1 : sd_r0;
@@ -1655,7 +1672,7 @@ static sd_rsp_type_t sd_cmd_SEND_STATUS(SDState *sd, SDRequest req)
/* CMD15 */
static sd_rsp_type_t sd_cmd_GO_INACTIVE_STATE(SDState *sd, SDRequest req)
{
- if (sd->mode != sd_data_transfer_mode) {
+ if (sd_mode(sd) != sd_data_transfer_mode) {
return sd_invalid_mode_for_cmd(sd, req);
}
switch (sd->state) {
@@ -1960,8 +1977,14 @@ static sd_rsp_type_t sd_acmd_SET_BUS_WIDTH(SDState *sd, SDRequest req)
/* ACMD13 */
static sd_rsp_type_t sd_acmd_SD_STATUS(SDState *sd, SDRequest req)
{
- return sd_cmd_to_sendingdata(sd, req, 0,
- sd->sd_status, sizeof(sd->sd_status));
+ sd_rsp_type_t rsp;
+
+ rsp = sd_cmd_to_sendingdata(sd, req, 0,
+ sd->sd_status, sizeof(sd->sd_status));
+ if (sd_is_spi(sd) && rsp != sd_illegal) {
+ return spi_r2;
+ }
+ return rsp;
}
/* ACMD22 */
@@ -2021,6 +2044,9 @@ static sd_rsp_type_t sd_cmd_SEND_OP_COND(SDState *sd, SDRequest req)
sd->state = sd_ready_state;
}
+ if (sd_is_spi(sd)) {
+ return sd_r1;
+ }
return sd_r3;
}
@@ -2052,7 +2078,9 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
if (req.cmd != 55 || sd->expecting_acmd) {
trace_sdcard_normal_command(sd->proto->name,
sd->last_cmd_name, req.cmd,
- req.arg, sd_state_name(sd->state));
+ req.arg,
+ sd_mode_name(sd_mode(sd)),
+ sd_state_name(sd->state));
}
/* Not interpreting this as an app command */
@@ -2138,7 +2166,9 @@ static sd_rsp_type_t sd_app_command(SDState *sd,
{
sd->last_cmd_name = sd_acmd_name(sd, req.cmd);
trace_sdcard_app_command(sd->proto->name, sd->last_cmd_name,
- req.cmd, req.arg, sd_state_name(sd->state));
+ req.cmd, req.arg,
+ sd_mode_name(sd_mode(sd)),
+ sd_state_name(sd->state));
sd->card_status |= APP_CMD;
if (sd->proto->acmd[req.cmd].handler) {
@@ -2193,13 +2223,14 @@ static bool cmd_valid_while_locked(SDState *sd, unsigned cmd)
return cmd_class == 0 || cmd_class == 7;
}
-int sd_do_command(SDState *sd, SDRequest *req,
- uint8_t *response) {
+static size_t sd_do_command(SDState *sd, SDRequest *req,
+ uint8_t *response, size_t respsz)
+{
int last_state;
sd_rsp_type_t rtype;
int rsplen;
- if (!sd->blk || !blk_is_inserted(sd->blk) || !sd->enable) {
+ if (!sd->blk || !blk_is_inserted(sd->blk)) {
return 0;
}
@@ -2237,7 +2268,6 @@ int sd_do_command(SDState *sd, SDRequest *req,
}
last_state = sd->state;
- sd_set_mode(sd);
if (sd->expecting_acmd) {
sd->expecting_acmd = false;
@@ -2257,36 +2287,37 @@ int sd_do_command(SDState *sd, SDRequest *req,
}
send_response:
+ rsplen = sd_response_size(sd, rtype);
+ assert(rsplen <= respsz);
+
switch (rtype) {
case sd_r1:
case sd_r1b:
sd_response_r1_make(sd, response);
- rsplen = 4;
+ break;
+
+ case spi_r2:
+ spi_response_r2_make(sd, response);
break;
case sd_r2_i:
memcpy(response, sd->cid, sizeof(sd->cid));
- rsplen = 16;
break;
case sd_r2_s:
memcpy(response, sd->csd, sizeof(sd->csd));
- rsplen = 16;
break;
case sd_r3:
sd_response_r3_make(sd, response);
- rsplen = 4;
break;
case sd_r6:
sd_response_r6_make(sd, response);
- rsplen = 4;
break;
case sd_r7:
sd_response_r7_make(sd, response);
- rsplen = 4;
break;
case sd_r0:
@@ -2298,7 +2329,6 @@ send_response:
sd->data_offset = 0;
/* fall-through */
case sd_illegal:
- rsplen = 0;
break;
default:
g_assert_not_reached();
@@ -2346,12 +2376,13 @@ static bool sd_generic_read_byte(SDState *sd, uint8_t *value)
return false;
}
-void sd_write_byte(SDState *sd, uint8_t value)
+static void sd_write_byte(SDState *sd, uint8_t value)
{
int i;
- if (!sd->blk || !blk_is_inserted(sd->blk) || !sd->enable)
+ if (!sd->blk || !blk_is_inserted(sd->blk)) {
return;
+ }
if (sd->state != sd_receivingdata_state) {
qemu_log_mask(LOG_GUEST_ERROR,
@@ -2475,15 +2506,16 @@ void sd_write_byte(SDState *sd, uint8_t value)
}
}
-uint8_t sd_read_byte(SDState *sd)
+static uint8_t sd_read_byte(SDState *sd)
{
/* TODO: Append CRCs */
const uint8_t dummy_byte = 0x00;
uint8_t ret;
uint32_t io_len;
- if (!sd->blk || !blk_is_inserted(sd->blk) || !sd->enable)
+ if (!sd->blk || !blk_is_inserted(sd->blk)) {
return dummy_byte;
+ }
if (sd->state != sd_sendingdata_state) {
qemu_log_mask(LOG_GUEST_ERROR,
@@ -2558,16 +2590,11 @@ static bool sd_data_ready(SDState *sd)
return sd->state == sd_sendingdata_state;
}
-void sd_enable(SDState *sd, bool enable)
-{
- sd->enable = enable;
-}
-
static const SDProto sd_proto_spi = {
.name = "SPI",
.cmd = {
[0] = {0, sd_spi, "GO_IDLE_STATE", sd_cmd_GO_IDLE_STATE},
- [1] = {0, sd_spi, "SEND_OP_COND", spi_cmd_SEND_OP_COND},
+ [1] = {0, sd_spi, "SEND_OP_COND", sd_cmd_SEND_OP_COND},
[5] = {9, sd_spi, "IO_SEND_OP_COND", sd_cmd_optional},
[6] = {10, sd_spi, "SWITCH_FUNCTION", sd_cmd_SWITCH_FUNCTION},
[8] = {0, sd_spi, "SEND_IF_COND", sd_cmd_SEND_IF_COND},
@@ -2603,7 +2630,7 @@ static const SDProto sd_proto_spi = {
[13] = {8, sd_spi, "SD_STATUS", sd_acmd_SD_STATUS},
[22] = {8, sd_spi, "SEND_NUM_WR_BLOCKS", sd_acmd_SEND_NUM_WR_BLOCKS},
[23] = {8, sd_spi, "SET_WR_BLK_ERASE_COUNT", sd_acmd_SET_WR_BLK_ERASE_COUNT},
- [41] = {8, sd_spi, "SEND_OP_COND", spi_cmd_SEND_OP_COND},
+ [41] = {8, sd_spi, "SEND_OP_COND", sd_cmd_SEND_OP_COND},
[42] = {8, sd_spi, "SET_CLR_CARD_DETECT", sd_acmd_SET_CLR_CARD_DETECT},
[51] = {8, sd_spi, "SEND_SCR", sd_acmd_SEND_SCR},
},
@@ -2722,7 +2749,6 @@ static void sd_instance_init(Object *obj)
sd->proto = sc->proto;
sd->last_cmd_name = "UNSET";
- sd->enable = true;
sd->ocr_power_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sd_ocr_powerup, sd);
}
@@ -2739,7 +2765,7 @@ static void sd_realize(DeviceState *dev, Error **errp)
int ret;
switch (sd->spec_version) {
- case SD_PHY_SPECv1_10_VERS
+ case SD_PHY_SPECv2_00_VERS
... SD_PHY_SPECv3_01_VERS:
break;
default:
@@ -2784,6 +2810,15 @@ static void sd_realize(DeviceState *dev, Error **errp)
}
blk_set_dev_ops(sd->blk, &sd_block_ops, sd);
}
+ if (sd->boot_part_size % (128 * KiB) ||
+ sd->boot_part_size > 255 * 128 * KiB) {
+ g_autofree char *size_str = size_to_str(sd->boot_part_size);
+
+ error_setg(errp, "Invalid boot partition size: %s", size_str);
+ error_append_hint(errp,
+ "The boot partition size must be multiples of 128K"
+ "and not larger than 32640K.\n");
+ }
}
static void emmc_realize(DeviceState *dev, Error **errp)
@@ -2795,31 +2830,28 @@ static void emmc_realize(DeviceState *dev, Error **errp)
sd_realize(dev, errp);
}
-static Property sdmmc_common_properties[] = {
+static const Property sdmmc_common_properties[] = {
DEFINE_PROP_DRIVE("drive", SDState, blk),
- DEFINE_PROP_END_OF_LIST()
};
-static Property sd_properties[] = {
+static const Property sd_properties[] = {
DEFINE_PROP_UINT8("spec_version", SDState,
spec_version, SD_PHY_SPECv3_01_VERS),
- DEFINE_PROP_END_OF_LIST()
};
-static Property emmc_properties[] = {
+static const Property emmc_properties[] = {
DEFINE_PROP_UINT64("boot-partition-size", SDState, boot_part_size, 0),
DEFINE_PROP_UINT8("boot-config", SDState, boot_config, 0x0),
- DEFINE_PROP_END_OF_LIST()
};
-static void sdmmc_common_class_init(ObjectClass *klass, void *data)
+static void sdmmc_common_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SDCardClass *sc = SDMMC_COMMON_CLASS(klass);
device_class_set_props(dc, sdmmc_common_properties);
dc->vmsd = &sd_vmstate;
- dc->reset = sd_reset;
+ device_class_set_legacy_reset(dc, sd_reset);
dc->bus_type = TYPE_SD_BUS;
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
@@ -2831,12 +2863,11 @@ static void sdmmc_common_class_init(ObjectClass *klass, void *data)
sc->read_byte = sd_read_byte;
sc->receive_ready = sd_receive_ready;
sc->data_ready = sd_data_ready;
- sc->enable = sd_enable;
sc->get_inserted = sd_get_inserted;
sc->get_readonly = sd_get_readonly;
}
-static void sd_class_init(ObjectClass *klass, void *data)
+static void sd_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SDCardClass *sc = SDMMC_COMMON_CLASS(klass);
@@ -2855,7 +2886,7 @@ static void sd_class_init(ObjectClass *klass, void *data)
* board to ensure that ssi transfers only occur when the chip select
* is asserted.
*/
-static void sd_spi_class_init(ObjectClass *klass, void *data)
+static void sd_spi_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SDCardClass *sc = SDMMC_COMMON_CLASS(klass);
@@ -2864,7 +2895,7 @@ static void sd_spi_class_init(ObjectClass *klass, void *data)
sc->proto = &sd_proto_spi;
}
-static void emmc_class_init(ObjectClass *klass, void *data)
+static void emmc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SDCardClass *sc = SDMMC_COMMON_CLASS(klass);
diff --git a/hw/sd/sdhci-internal.h b/hw/sd/sdhci-internal.h
index 5f3765f..9f768c4 100644
--- a/hw/sd/sdhci-internal.h
+++ b/hw/sd/sdhci-internal.h
@@ -322,6 +322,6 @@ void sdhci_initfn(SDHCIState *s);
void sdhci_uninitfn(SDHCIState *s);
void sdhci_common_realize(SDHCIState *s, Error **errp);
void sdhci_common_unrealize(SDHCIState *s);
-void sdhci_common_class_init(ObjectClass *klass, void *data);
+void sdhci_common_class_init(ObjectClass *klass, const void *data);
#endif
diff --git a/hw/sd/sdhci-pci.c b/hw/sd/sdhci-pci.c
index 9b7bee8..c18b91f 100644
--- a/hw/sd/sdhci-pci.c
+++ b/hw/sd/sdhci-pci.c
@@ -18,13 +18,13 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qemu/module.h"
+#include "hw/irq.h"
#include "hw/qdev-properties.h"
#include "hw/sd/sdhci.h"
#include "sdhci-internal.h"
-static Property sdhci_pci_properties[] = {
+static const Property sdhci_pci_properties[] = {
DEFINE_SDHCI_COMMON_PROPERTIES(SDHCIState),
- DEFINE_PROP_END_OF_LIST(),
};
static void sdhci_pci_realize(PCIDevice *dev, Error **errp)
@@ -49,11 +49,12 @@ static void sdhci_pci_exit(PCIDevice *dev)
{
SDHCIState *s = PCI_SDHCI(dev);
+ qemu_free_irq(s->irq);
sdhci_common_unrealize(s);
sdhci_uninitfn(s);
}
-static void sdhci_pci_class_init(ObjectClass *klass, void *data)
+static void sdhci_pci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -74,7 +75,7 @@ static const TypeInfo sdhci_pci_types[] = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(SDHCIState),
.class_init = sdhci_pci_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c
index 8293d83..89b595c 100644
--- a/hw/sd/sdhci.c
+++ b/hw/sd/sdhci.c
@@ -30,14 +30,13 @@
#include "qapi/error.h"
#include "hw/irq.h"
#include "hw/qdev-properties.h"
-#include "sysemu/dma.h"
+#include "system/dma.h"
#include "qemu/timer.h"
#include "qemu/bitops.h"
#include "hw/sd/sdhci.h"
#include "migration/vmstate.h"
#include "sdhci-internal.h"
#include "qemu/log.h"
-#include "qemu/module.h"
#include "trace.h"
#include "qom/object.h"
@@ -234,7 +233,7 @@ static void sdhci_raise_insertion_irq(void *opaque)
if (s->norintsts & SDHC_NIS_REMOVE) {
timer_mod(s->insert_timer,
- qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + SDHC_INSERTION_DELAY);
+ qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + SDHC_INSERTION_DELAY);
} else {
s->prnsts = 0x1ff0000;
if (s->norintstsen & SDHC_NISEN_INSERT) {
@@ -252,7 +251,7 @@ static void sdhci_set_inserted(DeviceState *dev, bool level)
if ((s->norintsts & SDHC_NIS_REMOVE) && level) {
/* Give target some time to notice card ejection */
timer_mod(s->insert_timer,
- qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + SDHC_INSERTION_DELAY);
+ qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + SDHC_INSERTION_DELAY);
} else {
if (level) {
s->prnsts = 0x1ff0000;
@@ -275,6 +274,10 @@ static void sdhci_set_readonly(DeviceState *dev, bool level)
{
SDHCIState *s = (SDHCIState *)dev;
+ if (s->wp_inverted) {
+ level = !level;
+ }
+
if (level) {
s->prnsts &= ~SDHC_WRITE_PROTECT;
} else {
@@ -290,9 +293,11 @@ static void sdhci_reset(SDHCIState *s)
timer_del(s->insert_timer);
timer_del(s->transfer_timer);
- /* Set all registers to 0. Capabilities/Version registers are not cleared
+ /*
+ * Set all registers to 0. Capabilities/Version registers are not cleared
* and assumed to always preserve their value, given to them during
- * initialization */
+ * initialization
+ */
memset(&s->sdmasysad, 0, (uintptr_t)&s->capareg - (uintptr_t)&s->sdmasysad);
/* Reset other state based on current card insertion/readonly status */
@@ -302,11 +307,16 @@ static void sdhci_reset(SDHCIState *s)
s->data_count = 0;
s->stopped_state = sdhc_not_stopped;
s->pending_insert_state = false;
+ if (s->vendor == SDHCI_VENDOR_FSL) {
+ s->norintstsen = 0x013f;
+ s->errintstsen = 0x117f;
+ }
}
static void sdhci_poweron_reset(DeviceState *dev)
{
- /* QOM (ie power-on) reset. This is identical to reset
+ /*
+ * QOM (ie power-on) reset. This is identical to reset
* commanded via device register apart from handling of the
* 'pending insert on powerup' quirk.
*/
@@ -327,7 +337,7 @@ static void sdhci_send_command(SDHCIState *s)
{
SDRequest request;
uint8_t response[16];
- int rlen;
+ size_t rlen;
bool timeout = false;
s->errintsts = 0;
@@ -336,7 +346,7 @@ static void sdhci_send_command(SDHCIState *s)
request.arg = s->argument;
trace_sdhci_send_command(request.cmd, request.arg);
- rlen = sdbus_do_command(&s->sdbus, &request, response);
+ rlen = sdbus_do_command(&s->sdbus, &request, response, sizeof(response));
if (s->cmdreg & SDHC_CMD_RESPONSE) {
if (rlen == 4) {
@@ -390,7 +400,7 @@ static void sdhci_end_transfer(SDHCIState *s)
request.cmd = 0x0C;
request.arg = 0;
trace_sdhci_end_transfer(request.cmd, request.arg);
- sdbus_do_command(&s->sdbus, &request, response);
+ sdbus_do_command(&s->sdbus, &request, response, sizeof(response));
/* Auto CMD12 response goes to the upper Response register */
s->rspreg[3] = ldl_be_p(response);
}
@@ -446,8 +456,10 @@ static void sdhci_read_block_from_card(SDHCIState *s)
s->prnsts &= ~SDHC_DAT_LINE_ACTIVE;
}
- /* If stop at block gap request was set and it's not the last block of
- * data - generate Block Event interrupt */
+ /*
+ * If stop at block gap request was set and it's not the last block of
+ * data - generate Block Event interrupt
+ */
if (s->stopped_state == sdhc_gap_read && (s->trnmod & SDHC_TRNS_MULTI) &&
s->blkcnt != 1) {
s->prnsts &= ~SDHC_DAT_LINE_ACTIVE;
@@ -549,8 +561,10 @@ static void sdhci_write_block_to_card(SDHCIState *s)
sdhci_update_irq(s);
}
-/* Write @size bytes of @value data to host controller @s Buffer Data Port
- * register */
+/*
+ * Write @size bytes of @value data to host controller @s Buffer Data Port
+ * register
+ */
static void sdhci_write_dataport(SDHCIState *s, uint32_t value, unsigned size)
{
unsigned i;
@@ -595,9 +609,11 @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s)
return;
}
- /* XXX: Some sd/mmc drivers (for example, u-boot-slp) do not account for
+ /*
+ * XXX: Some sd/mmc drivers (for example, u-boot-slp) do not account for
* possible stop at page boundary if initial address is not page aligned,
- * allow them to work properly */
+ * allow them to work properly
+ */
if ((s->sdmasysad % boundary_chk) == 0) {
page_aligned = true;
}
@@ -657,12 +673,13 @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s)
}
}
+ if (s->norintstsen & SDHC_NISEN_DMA) {
+ s->norintsts |= SDHC_NIS_DMA;
+ }
+
if (s->blkcnt == 0) {
sdhci_end_transfer(s);
} else {
- if (s->norintstsen & SDHC_NISEN_DMA) {
- s->norintsts |= SDHC_NIS_DMA;
- }
sdhci_update_irq(s);
}
}
@@ -683,9 +700,22 @@ static void sdhci_sdma_transfer_single_block(SDHCIState *s)
}
s->blkcnt--;
+ if (s->norintstsen & SDHC_NISEN_DMA) {
+ s->norintsts |= SDHC_NIS_DMA;
+ }
+
sdhci_end_transfer(s);
}
+static void sdhci_sdma_transfer(SDHCIState *s)
+{
+ if ((s->blkcnt == 1) || !(s->trnmod & SDHC_TRNS_MULTI)) {
+ sdhci_sdma_transfer_single_block(s);
+ } else {
+ sdhci_sdma_transfer_multi_blocks(s);
+ }
+}
+
typedef struct ADMADescr {
hwaddr addr;
uint16_t length;
@@ -703,7 +733,8 @@ static void get_adma_description(SDHCIState *s, ADMADescr *dscr)
dma_memory_read(s->dma_as, entry_addr, &adma2, sizeof(adma2),
MEMTXATTRS_UNSPECIFIED);
adma2 = le64_to_cpu(adma2);
- /* The spec does not specify endianness of descriptor table.
+ /*
+ * The spec does not specify endianness of descriptor table.
* We currently assume that it is LE.
*/
dscr->addr = (hwaddr)extract64(adma2, 32, 32) & ~0x3ull;
@@ -747,7 +778,7 @@ static void sdhci_do_adma(SDHCIState *s)
const uint16_t block_size = s->blksize & BLOCK_SIZE_MASK;
const MemTxAttrs attrs = { .memory = true };
ADMADescr dscr = {};
- MemTxResult res;
+ MemTxResult res = MEMTX_ERROR;
int i;
if (s->trnmod & SDHC_TRNS_BLK_CNT_EN && !s->blkcnt) {
@@ -916,12 +947,7 @@ static void sdhci_data_transfer(void *opaque)
if (s->trnmod & SDHC_TRNS_DMA) {
switch (SDHC_DMA_TYPE(s->hostctl1)) {
case SDHC_CTRL_SDMA:
- if ((s->blkcnt == 1) || !(s->trnmod & SDHC_TRNS_MULTI)) {
- sdhci_sdma_transfer_single_block(s);
- } else {
- sdhci_sdma_transfer_multi_blocks(s);
- }
-
+ sdhci_sdma_transfer(s);
break;
case SDHC_CTRL_ADMA1_32:
if (!(s->capareg & R_SDHC_CAPAB_ADMA1_MASK)) {
@@ -978,8 +1004,10 @@ static bool sdhci_can_issue_command(SDHCIState *s)
return true;
}
-/* The Buffer Data Port register must be accessed in sequential and
- * continuous manner */
+/*
+ * The Buffer Data Port register must be accessed in sequential and
+ * continuous manner
+ */
static inline bool
sdhci_buff_access_is_sequential(SDHCIState *s, unsigned byte_num)
{
@@ -1163,11 +1191,7 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
if (!(mask & 0xFF000000) && s->blkcnt &&
(s->blksize & BLOCK_SIZE_MASK) &&
SDHC_DMA_TYPE(s->hostctl1) == SDHC_CTRL_SDMA) {
- if (s->trnmod & SDHC_TRNS_MULTI) {
- sdhci_sdma_transfer_multi_blocks(s);
- } else {
- sdhci_sdma_transfer_single_block(s);
- }
+ sdhci_sdma_transfer(s);
}
}
break;
@@ -1207,8 +1231,10 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
MASKED_WRITE(s->argument, mask, value);
break;
case SDHC_TRNMOD:
- /* DMA can be enabled only if it is supported as indicated by
- * capabilities register */
+ /*
+ * DMA can be enabled only if it is supported as indicated by
+ * capabilities register
+ */
if (!(s->capareg & R_SDHC_CAPAB_SDMA_MASK)) {
value &= ~SDHC_TRNS_DMA;
}
@@ -1280,8 +1306,10 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
} else {
s->norintsts &= ~SDHC_NIS_ERR;
}
- /* Quirk for Raspberry Pi: pending card insert interrupt
- * appears when first enabled after power on */
+ /*
+ * Quirk for Raspberry Pi: pending card insert interrupt
+ * appears when first enabled after power on
+ */
if ((s->norintstsen & SDHC_NISEN_INSERT) && s->pending_insert_state) {
assert(s->pending_insert_quirk);
s->norintsts |= SDHC_NIS_INSERT;
@@ -1397,8 +1425,10 @@ void sdhci_initfn(SDHCIState *s)
{
qbus_init(&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);
+ 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);
s->io_ops = &sdhci_mmio_le_ops;
}
@@ -1446,11 +1476,13 @@ void sdhci_common_realize(SDHCIState *s, Error **errp)
void sdhci_common_unrealize(SDHCIState *s)
{
- /* This function is expected to be called only once for each class:
+ /*
+ * This function is expected to be called only once for each class:
* - SysBus: via DeviceClass->unrealize(),
* - PCI: via PCIDeviceClass->exit().
* However to avoid double-free and/or use-after-free we still nullify
- * this variable (better safe than sorry!). */
+ * this variable (better safe than sorry!).
+ */
g_free(s->fifo_buffer);
s->fifo_buffer = NULL;
}
@@ -1514,24 +1546,25 @@ const VMStateDescription sdhci_vmstate = {
},
};
-void sdhci_common_class_init(ObjectClass *klass, void *data)
+void sdhci_common_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
dc->vmsd = &sdhci_vmstate;
- dc->reset = sdhci_poweron_reset;
+ device_class_set_legacy_reset(dc, sdhci_poweron_reset);
}
/* --- qdev SysBus --- */
-static Property sdhci_sysbus_properties[] = {
+static const Property sdhci_sysbus_properties[] = {
DEFINE_SDHCI_COMMON_PROPERTIES(SDHCIState),
DEFINE_PROP_BOOL("pending-insert-quirk", SDHCIState, pending_insert_quirk,
false),
DEFINE_PROP_LINK("dma", SDHCIState,
dma_mr, TYPE_MEMORY_REGION, MemoryRegion *),
- DEFINE_PROP_END_OF_LIST(),
+ DEFINE_PROP_BOOL("wp-inverted", SDHCIState,
+ wp_inverted, false),
};
static void sdhci_sysbus_init(Object *obj)
@@ -1545,10 +1578,6 @@ static void sdhci_sysbus_finalize(Object *obj)
{
SDHCIState *s = SYSBUS_SDHCI(obj);
- if (s->dma_mr) {
- object_unparent(OBJECT(s->dma_mr));
- }
-
sdhci_uninitfn(s);
}
@@ -1587,7 +1616,7 @@ static void sdhci_sysbus_unrealize(DeviceState *dev)
}
}
-static void sdhci_sysbus_class_init(ObjectClass *klass, void *data)
+static void sdhci_sysbus_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -1598,18 +1627,9 @@ static void sdhci_sysbus_class_init(ObjectClass *klass, void *data)
sdhci_common_class_init(klass, data);
}
-static const TypeInfo sdhci_sysbus_info = {
- .name = TYPE_SYSBUS_SDHCI,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(SDHCIState),
- .instance_init = sdhci_sysbus_init,
- .instance_finalize = sdhci_sysbus_finalize,
- .class_init = sdhci_sysbus_class_init,
-};
-
/* --- qdev bus master --- */
-static void sdhci_bus_class_init(ObjectClass *klass, void *data)
+static void sdhci_bus_class_init(ObjectClass *klass, const void *data)
{
SDBusClass *sbc = SD_BUS_CLASS(klass);
@@ -1617,13 +1637,6 @@ static void sdhci_bus_class_init(ObjectClass *klass, void *data)
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,
-};
-
/* --- qdev i.MX eSDHC --- */
#define USDHC_MIX_CTRL 0x48
@@ -1718,16 +1731,10 @@ usdhc_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
case USDHC_VENDOR_SPEC:
s->vendor_spec = value;
- switch (s->vendor) {
- case SDHCI_VENDOR_IMX:
- if (value & USDHC_IMX_FRC_SDCLK_ON) {
- s->prnsts &= ~SDHC_IMX_CLOCK_GATE_OFF;
- } else {
- s->prnsts |= SDHC_IMX_CLOCK_GATE_OFF;
- }
- break;
- default:
- break;
+ if (value & USDHC_IMX_FRC_SDCLK_ON) {
+ s->prnsts &= ~SDHC_IMX_CLOCK_GATE_OFF;
+ } else {
+ s->prnsts |= SDHC_IMX_CLOCK_GATE_OFF;
}
break;
@@ -1882,12 +1889,6 @@ static void imx_usdhc_init(Object *obj)
s->quirks = SDHCI_QUIRK_NO_BUSY_IRQ;
}
-static const TypeInfo imx_usdhc_info = {
- .name = TYPE_IMX_USDHC,
- .parent = TYPE_SYSBUS_SDHCI,
- .instance_init = imx_usdhc_init,
-};
-
/* --- qdev Samsung s3c --- */
#define S3C_SDHCI_CONTROL2 0x80
@@ -1946,18 +1947,31 @@ static void sdhci_s3c_init(Object *obj)
s->io_ops = &sdhci_s3c_mmio_ops;
}
-static const TypeInfo sdhci_s3c_info = {
- .name = TYPE_S3C_SDHCI ,
- .parent = TYPE_SYSBUS_SDHCI,
- .instance_init = sdhci_s3c_init,
+static const TypeInfo sdhci_types[] = {
+ {
+ .name = TYPE_SDHCI_BUS,
+ .parent = TYPE_SD_BUS,
+ .instance_size = sizeof(SDBus),
+ .class_init = sdhci_bus_class_init,
+ },
+ {
+ .name = TYPE_SYSBUS_SDHCI,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SDHCIState),
+ .instance_init = sdhci_sysbus_init,
+ .instance_finalize = sdhci_sysbus_finalize,
+ .class_init = sdhci_sysbus_class_init,
+ },
+ {
+ .name = TYPE_IMX_USDHC,
+ .parent = TYPE_SYSBUS_SDHCI,
+ .instance_init = imx_usdhc_init,
+ },
+ {
+ .name = TYPE_S3C_SDHCI,
+ .parent = TYPE_SYSBUS_SDHCI,
+ .instance_init = sdhci_s3c_init,
+ },
};
-static void sdhci_register_types(void)
-{
- type_register_static(&sdhci_sysbus_info);
- type_register_static(&sdhci_bus_info);
- type_register_static(&imx_usdhc_info);
- type_register_static(&sdhci_s3c_info);
-}
-
-type_init(sdhci_register_types)
+DEFINE_TYPES(sdhci_types)
diff --git a/hw/sd/sdmmc-internal.h b/hw/sd/sdmmc-internal.h
index 91eb5b6..ce6bc4e 100644
--- a/hw/sd/sdmmc-internal.h
+++ b/hw/sd/sdmmc-internal.h
@@ -116,7 +116,8 @@ DECLARE_OBJ_CHECKERS(SDState, SDCardClass, SDMMC_COMMON, TYPE_SDMMC_COMMON)
#define EXT_CSD_PART_CONFIG_ACC_MASK (0x7)
#define EXT_CSD_PART_CONFIG_ACC_DEFAULT (0x0)
-#define EXT_CSD_PART_CONFIG_ACC_BOOT0 (0x1)
+#define EXT_CSD_PART_CONFIG_ACC_BOOT1 (0x1)
+#define EXT_CSD_PART_CONFIG_ACC_BOOT2 (0x2)
#define EXT_CSD_PART_CONFIG_EN_MASK (0x7 << 3)
#define EXT_CSD_PART_CONFIG_EN_BOOT0 (0x1 << 3)
diff --git a/hw/sd/ssi-sd.c b/hw/sd/ssi-sd.c
index 2dd070f..3aacbd0 100644
--- a/hw/sd/ssi-sd.c
+++ b/hw/sd/ssi-sd.c
@@ -16,7 +16,7 @@
*/
#include "qemu/osdep.h"
-#include "sysemu/blockdev.h"
+#include "system/blockdev.h"
#include "hw/ssi/ssi.h"
#include "migration/vmstate.h"
#include "hw/qdev-properties.h"
@@ -70,23 +70,6 @@ struct ssi_sd_state {
#define TYPE_SSI_SD "ssi-sd"
OBJECT_DECLARE_SIMPLE_TYPE(ssi_sd_state, SSI_SD)
-/* State word bits. */
-#define SSI_SDR_LOCKED 0x0001
-#define SSI_SDR_WP_ERASE 0x0002
-#define SSI_SDR_ERROR 0x0004
-#define SSI_SDR_CC_ERROR 0x0008
-#define SSI_SDR_ECC_FAILED 0x0010
-#define SSI_SDR_WP_VIOLATION 0x0020
-#define SSI_SDR_ERASE_PARAM 0x0040
-#define SSI_SDR_OUT_OF_RANGE 0x0080
-#define SSI_SDR_IDLE 0x0100
-#define SSI_SDR_ERASE_RESET 0x0200
-#define SSI_SDR_ILLEGAL_COMMAND 0x0400
-#define SSI_SDR_COM_CRC_ERROR 0x0800
-#define SSI_SDR_ERASE_SEQ_ERROR 0x1000
-#define SSI_SDR_ADDRESS_ERROR 0x2000
-#define SSI_SDR_PARAMETER_ERROR 0x4000
-
/* multiple block write */
#define SSI_TOKEN_MULTI_WRITE 0xfc
/* terminate multiple block write */
@@ -104,7 +87,11 @@ static uint32_t ssi_sd_transfer(SSIPeripheral *dev, uint32_t val)
{
ssi_sd_state *s = SSI_SD(dev);
SDRequest request;
- uint8_t longresp[16];
+ uint8_t longresp[5];
+
+ if (!sdbus_get_inserted(&s->sdbus)) {
+ return SSI_DUMMY;
+ }
/*
* Special case: allow CMD12 (STOP TRANSMISSION) while reading data.
@@ -146,8 +133,9 @@ static uint32_t ssi_sd_transfer(SSIPeripheral *dev, uint32_t val)
/* manually issue cmd12 to stop the transfer */
request.cmd = 12;
request.arg = 0;
- s->arglen = sdbus_do_command(&s->sdbus, &request, longresp);
- if (s->arglen <= 0) {
+ s->arglen = sdbus_do_command(&s->sdbus, &request,
+ longresp, sizeof(longresp));
+ if (s->arglen == 0) {
s->arglen = 1;
/* a zero value indicates the card is busy */
s->response[0] = 0;
@@ -170,73 +158,15 @@ static uint32_t ssi_sd_transfer(SSIPeripheral *dev, uint32_t val)
/* FIXME: Check CRC. */
request.cmd = s->cmd;
request.arg = ldl_be_p(s->cmdarg);
- DPRINTF("CMD%d arg 0x%08x\n", s->cmd, request.arg);
- s->arglen = sdbus_do_command(&s->sdbus, &request, longresp);
- if (s->arglen <= 0) {
- s->arglen = 1;
- s->response[0] = 4;
- DPRINTF("SD command failed\n");
- } else if (s->cmd == 8 || s->cmd == 58) {
- /* CMD8/CMD58 returns R3/R7 response */
- DPRINTF("Returned R3/R7\n");
- s->arglen = 5;
- s->response[0] = 1;
- memcpy(&s->response[1], longresp, 4);
- } else if (s->arglen != 4) {
- BADF("Unexpected response to cmd %d\n", s->cmd);
- /* Illegal command is about as near as we can get. */
- s->arglen = 1;
- s->response[0] = 4;
- } else {
- /* All other commands return status. */
- uint32_t cardstatus;
- uint16_t status;
- /* CMD13 returns a 2-byte statuse work. Other commands
- only return the first byte. */
- s->arglen = (s->cmd == 13) ? 2 : 1;
-
- /* handle R1b */
- if (s->cmd == 28 || s->cmd == 29 || s->cmd == 38) {
- s->stopping = 1;
- }
+ s->arglen = sdbus_do_command(&s->sdbus, &request,
+ longresp, sizeof(longresp));
+ DPRINTF("CMD%d arg 0x%08x = %d\n", s->cmd, request.arg, s->arglen);
+ assert(s->arglen > 0);
+ memcpy(s->response, longresp, s->arglen);
- cardstatus = ldl_be_p(longresp);
- status = 0;
- if (((cardstatus >> 9) & 0xf) < 4)
- status |= SSI_SDR_IDLE;
- if (cardstatus & ERASE_RESET)
- status |= SSI_SDR_ERASE_RESET;
- if (cardstatus & ILLEGAL_COMMAND)
- status |= SSI_SDR_ILLEGAL_COMMAND;
- if (cardstatus & COM_CRC_ERROR)
- status |= SSI_SDR_COM_CRC_ERROR;
- if (cardstatus & ERASE_SEQ_ERROR)
- status |= SSI_SDR_ERASE_SEQ_ERROR;
- if (cardstatus & ADDRESS_ERROR)
- status |= SSI_SDR_ADDRESS_ERROR;
- if (cardstatus & CARD_IS_LOCKED)
- status |= SSI_SDR_LOCKED;
- if (cardstatus & (LOCK_UNLOCK_FAILED | WP_ERASE_SKIP))
- status |= SSI_SDR_WP_ERASE;
- if (cardstatus & SD_ERROR)
- status |= SSI_SDR_ERROR;
- if (cardstatus & CC_ERROR)
- status |= SSI_SDR_CC_ERROR;
- if (cardstatus & CARD_ECC_FAILED)
- status |= SSI_SDR_ECC_FAILED;
- if (cardstatus & WP_VIOLATION)
- status |= SSI_SDR_WP_VIOLATION;
- if (cardstatus & ERASE_PARAM)
- status |= SSI_SDR_ERASE_PARAM;
- if (cardstatus & (OUT_OF_RANGE | CID_CSD_OVERWRITE))
- status |= SSI_SDR_OUT_OF_RANGE;
- /* ??? Don't know what Parameter Error really means, so
- assume it's set if the second byte is nonzero. */
- if (status & 0xff)
- status |= SSI_SDR_PARAMETER_ERROR;
- s->response[0] = status >> 8;
- s->response[1] = status;
- DPRINTF("Card status 0x%02x\n", status);
+ /* handle R1b (busy signal) */
+ if (s->cmd == 28 || s->cmd == 29 || s->cmd == 38) {
+ s->stopping = 1;
}
s->mode = SSI_SD_PREP_RESP;
s->response_pos = 0;
@@ -333,7 +263,7 @@ static int ssi_sd_post_load(void *opaque, int version_id)
return -EINVAL;
}
if (s->mode == SSI_SD_CMDARG &&
- (s->arglen < 0 || s->arglen >= ARRAY_SIZE(s->cmdarg))) {
+ (s->arglen >= ARRAY_SIZE(s->cmdarg))) {
return -EINVAL;
}
if (s->mode == SSI_SD_RESPONSE &&
@@ -389,7 +319,7 @@ static void ssi_sd_reset(DeviceState *dev)
s->stopping = 0;
}
-static void ssi_sd_class_init(ObjectClass *klass, void *data)
+static void ssi_sd_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass);
@@ -398,7 +328,7 @@ static void ssi_sd_class_init(ObjectClass *klass, void *data)
k->transfer = ssi_sd_transfer;
k->cs_polarity = SSI_CS_LOW;
dc->vmsd = &vmstate_ssi_sd;
- dc->reset = ssi_sd_reset;
+ device_class_set_legacy_reset(dc, ssi_sd_reset);
/* Reason: GPIO chip-select line should be wired up */
dc->user_creatable = false;
}
diff --git a/hw/sd/trace-events b/hw/sd/trace-events
index 43671dc..8d49840 100644
--- a/hw/sd/trace-events
+++ b/hw/sd/trace-events
@@ -37,8 +37,8 @@ sdhci_write_dataport(uint16_t data_count) "write buffer filled with %u bytes of
sdhci_capareg(const char *desc, uint16_t val) "%s: %u"
# sd.c
-sdcard_normal_command(const char *proto, const char *cmd_desc, uint8_t cmd, uint32_t arg, const char *state) "%s %20s/ CMD%02d arg 0x%08x (state %s)"
-sdcard_app_command(const char *proto, const char *acmd_desc, uint8_t acmd, uint32_t arg, const char *state) "%s %23s/ACMD%02d arg 0x%08x (state %s)"
+sdcard_normal_command(const char *proto, const char *cmd_desc, uint8_t cmd, uint32_t arg, const char *mode, const char *state) "%s %20s/ CMD%02d arg 0x%08x (mode %s, state %s)"
+sdcard_app_command(const char *proto, const char *acmd_desc, uint8_t acmd, uint32_t arg, const char *mode, const char *state) "%s %23s/ACMD%02d arg 0x%08x (mode %s, state %s)"
sdcard_response(const char *rspdesc, int rsplen) "%s (sz:%d)"
sdcard_powerup(void) ""
sdcard_inquiry_cmd41(void) ""
@@ -60,10 +60,6 @@ sdcard_set_voltage(uint16_t millivolts) "%u mV"
sdcard_ext_csd_update(unsigned index, uint8_t oval, uint8_t nval) "index %u: 0x%02x -> 0x%02x"
sdcard_switch(unsigned access, unsigned index, unsigned value, unsigned set) "SWITCH acc:%u idx:%u val:%u set:%u"
-# pxa2xx_mmci.c
-pxa2xx_mmci_read(uint8_t size, uint32_t addr, uint32_t value) "size %d addr 0x%02x value 0x%08x"
-pxa2xx_mmci_write(uint8_t size, uint32_t addr, uint32_t value) "size %d addr 0x%02x value 0x%08x"
-
# pl181.c
pl181_command_send(uint8_t cmd, uint32_t arg) "sending CMD%02d arg 0x%08" PRIx32
pl181_command_sent(void) "command sent"