aboutsummaryrefslogtreecommitdiff
path: root/hw/sd
diff options
context:
space:
mode:
authorStefan Hajnoczi <stefanha@redhat.com>2023-09-06 11:14:55 -0400
committerStefan Hajnoczi <stefanha@redhat.com>2023-09-06 11:14:55 -0400
commit912a9efd6bf4d808b238e17d26de2e4bb9bc4743 (patch)
tree9622a651f82f7cfd1664fd0a314fb2ed0d201d4e /hw/sd
parent2d8fbcb1eecd8d39171f457e583428758321d69d (diff)
parentc3287c0f70dae07dd12322c5c8663f7b878826e7 (diff)
Merge tag 'pull-aspeed-20230901' of https://github.com/legoater/qemu into staging
aspeed queue: * Fixes for the Aspeed I2C model * New SDK image for avocado tests * blockdev support for flash device definition * SD refactoring preparing ground for eMMC support # -----BEGIN PGP SIGNATURE----- # # iQIzBAABCAAdFiEEoPZlSPBIlev+awtgUaNDx8/77KEFAmTxsaQACgkQUaNDx8/7 # 7KGXmg//XJNisscl/VWSBaGmH5MbQUAg/QCRalXx1V/lJ8rhE/JqwnWKuoPFd4EN # iDlh3ufpzxPhHFc9boechuM5ytlrJxpLJoCIJ4sw/4qnO3Dy3Q6BCy1t8Ma62D1u # oE7cAMHsriJ1uTJNHUTFo72VapTaH2XwFN9lFDuQW45d+WWAXtVJsqvRgFETNmw6 # YYnTTpH2gLTZZFEgOixhWpGLh4Ibc/l8U1VzL0ctQmC11xng0bqk3PAqU9NGzcM5 # MJmEGAxg43CnFu9NJI1nMqC/coi/8PFtrM7HprSwE3H8Jkwncs4ePVT+kZQC+VNQ # 7EaVkksfEGHlN8XP5+eQDrQ5yT6ve+fbHTLQhwULfeyt0GlQ8h1yewvHCDWo/zw3 # XI1ZyOcNZ2yiaenSUrTPzu0LiqZEJQnzRjPCpgTi1fU08ryEMEaPtr176YDLCguQ # cpRj4QSZHCrGl/Eo9NlkFP/2rQDKTvCcedKPkYLQtsurSiH/36Oj9YvZycNtZ574 # ortKAtru4YV/rglNX4L8JDhdI+nqvy1liifpJsiS/2KBZDpVFaP8PzGIV40HNy3G # 8/LVTnaggZaScF3ftHhkg84uQumELS9l2dhsNCL9HqdlrNXLQrVAIR6iuQlpOKBa # 5S/6h7ZXGOb1qNVQjYp4HCrB7X1KIJYksZ3GdUREf8ot5Ds1FhE= # =ymmX # -----END PGP SIGNATURE----- # gpg: Signature made Fri 01 Sep 2023 05:40:52 EDT # gpg: using RSA key A0F66548F04895EBFE6B0B6051A343C7CFFBECA1 # gpg: Good signature from "Cédric Le Goater <clg@redhat.com>" [unknown] # gpg: aka "Cédric Le Goater <clg@kaod.org>" [unknown] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: A0F6 6548 F048 95EB FE6B 0B60 51A3 43C7 CFFB ECA1 * tag 'pull-aspeed-20230901' of https://github.com/legoater/qemu: (26 commits) hw/sd: Introduce a "sd-card" SPI variant model hw/sd: Add sd_cmd_SET_BLOCK_COUNT() handler hw/sd: Add sd_cmd_SEND_TUNING_BLOCK() handler hw/sd: Add sd_cmd_SEND_RELATIVE_ADDR() handler hw/sd: Add sd_cmd_ALL_SEND_CID() handler hw/sd: Add sd_cmd_SEND_OP_CMD() handler hw/sd: Add sd_cmd_GO_IDLE_STATE() handler hw/sd: Add sd_cmd_unimplemented() handler hw/sd: Add sd_cmd_illegal() handler hw/sd: Introduce sd_cmd_handler type hw/sd: Move proto_name to SDProto structure hw/sd: When card is in wrong state, log which spec version is used hw/sd: When card is in wrong state, log which state it is hw/sd/sdcard: Return ILLEGAL for CMD19/CMD23 prior SD spec v3.01 aspeed: Get the BlockBackend of FMC0 from the flash device m25p80: Introduce an helper to retrieve the BlockBackend of a device aspeed: Create flash devices only when defaults are enabled hw/ssi: Check for duplicate CS indexes aspeed/smc: Wire CS lines at reset hw/ssi: Introduce a ssi_get_cs() helper ... Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Diffstat (limited to 'hw/sd')
-rw-r--r--hw/sd/sd.c348
-rw-r--r--hw/sd/sdmmc-internal.c2
2 files changed, 216 insertions, 134 deletions
diff --git a/hw/sd/sd.c b/hw/sd/sd.c
index 43c374e829..4823befdef 100644
--- a/hw/sd/sd.c
+++ b/hw/sd/sd.c
@@ -87,6 +87,14 @@ enum SDCardStates {
sd_disconnect_state,
};
+typedef sd_rsp_type_t (*sd_cmd_handler)(SDState *sd, SDRequest req);
+
+typedef struct SDProto {
+ const char *name;
+ sd_cmd_handler cmd[SDMMC_CMD_MAX];
+ sd_cmd_handler acmd[SDMMC_CMD_MAX];
+} SDProto;
+
struct SDState {
DeviceState parent_obj;
@@ -107,7 +115,6 @@ struct SDState {
uint8_t spec_version;
BlockBackend *blk;
- bool spi;
/* Runtime changeables */
@@ -137,7 +144,6 @@ struct SDState {
qemu_irq readonly_cb;
qemu_irq inserted_cb;
QEMUTimer *ocr_power_timer;
- const char *proto_name;
bool enable;
uint8_t dat_lines;
bool cmd_line;
@@ -145,6 +151,33 @@ struct SDState {
static void sd_realize(DeviceState *dev, Error **errp);
+static const struct SDProto *sd_proto(SDState *sd)
+{
+ SDCardClass *sc = SD_CARD_GET_CLASS(sd);
+
+ return sc->proto;
+}
+
+static const SDProto sd_proto_spi;
+
+static bool sd_is_spi(SDState *sd)
+{
+ return sd_proto(sd) == &sd_proto_spi;
+}
+
+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",
+ };
+ if (version >= ARRAY_SIZE(sdphy_version)) {
+ return "unsupported version";
+ }
+ return sdphy_version[version];
+}
+
static const char *sd_state_name(enum SDCardStates state)
{
static const char *state_name[] = {
@@ -309,7 +342,7 @@ static void sd_set_ocr(SDState *sd)
/* All voltages OK */
sd->ocr = R_OCR_VDD_VOLTAGE_WIN_HI_MASK;
- if (sd->spi) {
+ if (sd_is_spi(sd)) {
/*
* We don't need to emulate power up sequence in SPI-mode.
* Thus, the card's power up status bit should be set to 1 when reset.
@@ -714,13 +747,12 @@ SDState *sd_init(BlockBackend *blk, bool is_spi)
SDState *sd;
Error *err = NULL;
- obj = object_new(TYPE_SD_CARD);
+ 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;
}
- qdev_prop_set_bit(dev, "spi", is_spi);
/*
* Realizing the device properly would put it into the QOM
@@ -966,6 +998,106 @@ static bool address_in_range(SDState *sd, const char *desc,
return true;
}
+static sd_rsp_type_t sd_invalid_state_for_cmd(SDState *sd, SDRequest req)
+{
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: CMD%i in a wrong state: %s (spec %s)\n",
+ sd_proto(sd)->name, req.cmd, sd_state_name(sd->state),
+ sd_version_str(sd->spec_version));
+
+ return sd_illegal;
+}
+
+static sd_rsp_type_t sd_cmd_illegal(SDState *sd, SDRequest req)
+{
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Unknown CMD%i for spec %s\n",
+ sd_proto(sd)->name, req.cmd,
+ sd_version_str(sd->spec_version));
+
+ return sd_illegal;
+}
+
+/* Commands that are recognised but not yet implemented. */
+static sd_rsp_type_t sd_cmd_unimplemented(SDState *sd, SDRequest req)
+{
+ qemu_log_mask(LOG_UNIMP, "%s: CMD%i not implemented\n",
+ sd_proto(sd)->name, req.cmd);
+
+ return sd_illegal;
+}
+
+static sd_rsp_type_t sd_cmd_GO_IDLE_STATE(SDState *sd, SDRequest req)
+{
+ if (sd->state != sd_inactive_state) {
+ sd->state = sd_idle_state;
+ sd_reset(DEVICE(sd));
+ }
+
+ return sd_is_spi(sd) ? sd_r1 : sd_r0;
+}
+
+static sd_rsp_type_t sd_cmd_SEND_OP_CMD(SDState *sd, SDRequest req)
+{
+ sd->state = sd_transfer_state;
+
+ return sd_r1;
+}
+
+static sd_rsp_type_t sd_cmd_ALL_SEND_CID(SDState *sd, SDRequest req)
+{
+ if (sd->state != sd_ready_state) {
+ return sd_invalid_state_for_cmd(sd, req);
+ }
+
+ sd->state = sd_identification_state;
+
+ return sd_r2_i;
+}
+
+static sd_rsp_type_t sd_cmd_SEND_RELATIVE_ADDR(SDState *sd, SDRequest req)
+{
+ switch (sd->state) {
+ case sd_identification_state:
+ case sd_standby_state:
+ sd->state = sd_standby_state;
+ sd_set_rca(sd);
+ return sd_r6;
+
+ default:
+ return sd_invalid_state_for_cmd(sd, req);
+ }
+}
+
+static sd_rsp_type_t sd_cmd_SEND_TUNING_BLOCK(SDState *sd, SDRequest req)
+{
+ if (sd->spec_version < SD_PHY_SPECv3_01_VERS) {
+ return sd_cmd_illegal(sd, req);
+ }
+
+ if (sd->state != sd_transfer_state) {
+ return sd_invalid_state_for_cmd(sd, req);
+ }
+
+ sd->state = sd_sendingdata_state;
+ sd->data_offset = 0;
+
+ return sd_r1;
+}
+
+static sd_rsp_type_t sd_cmd_SET_BLOCK_COUNT(SDState *sd, SDRequest req)
+{
+ if (sd->spec_version < SD_PHY_SPECv3_01_VERS) {
+ return sd_cmd_illegal(sd, req);
+ }
+
+ if (sd->state != sd_transfer_state) {
+ return sd_invalid_state_for_cmd(sd, req);
+ }
+
+ sd->multi_blk_cnt = req.arg;
+
+ return sd_r1;
+}
+
static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
{
uint32_t rca = 0x0000;
@@ -975,7 +1107,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
* However there is no ACMD55, so we want to trace this particular case.
*/
if (req.cmd != 55 || sd->expecting_acmd) {
- trace_sdcard_normal_command(sd->proto_name,
+ trace_sdcard_normal_command(sd_proto(sd)->name,
sd_cmd_name(req.cmd), req.cmd,
req.arg, sd_state_name(sd->state));
}
@@ -999,58 +1131,13 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
return sd_illegal;
}
+ if (sd_proto(sd)->cmd[req.cmd]) {
+ return sd_proto(sd)->cmd[req.cmd](sd, req);
+ }
+
switch (req.cmd) {
/* Basic commands (Class 0 and Class 1) */
- case 0: /* CMD0: GO_IDLE_STATE */
- switch (sd->state) {
- case sd_inactive_state:
- return sd->spi ? sd_r1 : sd_r0;
-
- default:
- sd->state = sd_idle_state;
- sd_reset(DEVICE(sd));
- return sd->spi ? sd_r1 : sd_r0;
- }
- break;
-
- case 1: /* CMD1: SEND_OP_CMD */
- if (!sd->spi)
- goto bad_cmd;
-
- sd->state = sd_transfer_state;
- return sd_r1;
-
- case 2: /* CMD2: ALL_SEND_CID */
- if (sd->spi)
- goto bad_cmd;
- switch (sd->state) {
- case sd_ready_state:
- sd->state = sd_identification_state;
- return sd_r2_i;
-
- default:
- break;
- }
- break;
-
- case 3: /* CMD3: SEND_RELATIVE_ADDR */
- if (sd->spi)
- goto bad_cmd;
- switch (sd->state) {
- case sd_identification_state:
- case sd_standby_state:
- sd->state = sd_standby_state;
- sd_set_rca(sd);
- return sd_r6;
-
- default:
- break;
- }
- break;
-
case 4: /* CMD4: SEND_DSR */
- if (sd->spi)
- goto bad_cmd;
switch (sd->state) {
case sd_standby_state:
break;
@@ -1060,9 +1147,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
}
break;
- case 5: /* CMD5: reserved for SDIO cards */
- return sd_illegal;
-
case 6: /* CMD6: SWITCH_FUNCTION */
switch (sd->mode) {
case sd_data_transfer_mode:
@@ -1078,8 +1162,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
break;
case 7: /* CMD7: SELECT/DESELECT_CARD */
- if (sd->spi)
- goto bad_cmd;
switch (sd->state) {
case sd_standby_state:
if (sd->rca != rca)
@@ -1126,7 +1208,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
/* No response if not exactly one VHS bit is set. */
if (!(req.arg >> 8) || (req.arg >> (ctz32(req.arg & ~0xff) + 1))) {
- return sd->spi ? sd_r7 : sd_r0;
+ return sd_is_spi(sd) ? sd_r7 : sd_r0;
}
/* Accept. */
@@ -1142,8 +1224,9 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
return sd_r2_s;
case sd_transfer_state:
- if (!sd->spi)
+ if (!sd_is_spi(sd)) {
break;
+ }
sd->state = sd_sendingdata_state;
memcpy(sd->data, sd->csd, 16);
sd->data_start = addr;
@@ -1164,8 +1247,9 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
return sd_r2_i;
case sd_transfer_state:
- if (!sd->spi)
+ if (!sd_is_spi(sd)) {
break;
+ }
sd->state = sd_sendingdata_state;
memcpy(sd->data, sd->cid, 16);
sd->data_start = addr;
@@ -1197,7 +1281,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
case 13: /* CMD13: SEND_STATUS */
switch (sd->mode) {
case sd_data_transfer_mode:
- if (!sd->spi && sd->rca != rca) {
+ if (!sd_is_spi(sd) && sd->rca != rca) {
return sd_r0;
}
@@ -1209,8 +1293,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
break;
case 15: /* CMD15: GO_INACTIVE_STATE */
- if (sd->spi)
- goto bad_cmd;
switch (sd->mode) {
case sd_data_transfer_mode:
if (sd->rca != rca)
@@ -1261,31 +1343,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
}
break;
- case 19: /* CMD19: SEND_TUNING_BLOCK (SD) */
- if (sd->spec_version < SD_PHY_SPECv3_01_VERS) {
- break;
- }
- if (sd->state == sd_transfer_state) {
- sd->state = sd_sendingdata_state;
- sd->data_offset = 0;
- return sd_r1;
- }
- break;
-
- case 23: /* CMD23: SET_BLOCK_COUNT */
- if (sd->spec_version < SD_PHY_SPECv3_01_VERS) {
- break;
- }
- 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 */
case 25: /* CMD25: WRITE_MULTIPLE_BLOCK */
@@ -1317,8 +1374,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
break;
case 26: /* CMD26: PROGRAM_CID */
- if (sd->spi)
- goto bad_cmd;
switch (sd->state) {
case sd_transfer_state:
sd->state = sd_receivingdata_state;
@@ -1468,15 +1523,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
}
break;
- case 52 ... 54:
- /* CMD52, CMD53, CMD54: reserved for SDIO cards
- * (see the SDIO Simplified Specification V2.0)
- * Handle as illegal command but do not complain
- * on stderr, as some OSes may use these in their
- * probing for presence of an SDIO card.
- */
- return sd_illegal;
-
/* Application specific commands (Class 8) */
case 55: /* CMD55: APP_CMD */
switch (sd->state) {
@@ -1492,7 +1538,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
default:
break;
}
- if (!sd->spi) {
+ if (!sd_is_spi(sd)) {
if (sd->rca != rca) {
return sd_r0;
}
@@ -1517,39 +1563,32 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
break;
case 58: /* CMD58: READ_OCR (SPI) */
- if (!sd->spi) {
- goto bad_cmd;
- }
return sd_r3;
case 59: /* CMD59: CRC_ON_OFF (SPI) */
- if (!sd->spi) {
- goto bad_cmd;
- }
return sd_r1;
default:
- bad_cmd:
qemu_log_mask(LOG_GUEST_ERROR, "SD: Unknown CMD%i\n", req.cmd);
return sd_illegal;
}
- qemu_log_mask(LOG_GUEST_ERROR, "SD: CMD%i in a wrong state: %s\n",
- req.cmd, sd_state_name(sd->state));
- return sd_illegal;
+ return sd_invalid_state_for_cmd(sd, req);
}
static sd_rsp_type_t sd_app_command(SDState *sd,
SDRequest req)
{
- trace_sdcard_app_command(sd->proto_name, sd_acmd_name(req.cmd),
+ trace_sdcard_app_command(sd_proto(sd)->name, sd_acmd_name(req.cmd),
req.cmd, req.arg, sd_state_name(sd->state));
sd->card_status |= APP_CMD;
+
+ if (sd_proto(sd)->acmd[req.cmd]) {
+ return sd_proto(sd)->acmd[req.cmd](sd, req);
+ }
+
switch (req.cmd) {
case 6: /* ACMD6: SET_BUS_WIDTH */
- if (sd->spi) {
- goto unimplemented_spi_cmd;
- }
switch (sd->state) {
case sd_transfer_state:
sd->sd_status[0] &= 0x3f;
@@ -1600,11 +1639,6 @@ static sd_rsp_type_t sd_app_command(SDState *sd,
break;
case 41: /* ACMD41: SD_APP_OP_COND */
- if (sd->spi) {
- /* SEND_OP_CMD */
- sd->state = sd_transfer_state;
- return sd_r1;
- }
if (sd->state != sd_idle_state) {
break;
}
@@ -1680,12 +1714,6 @@ static sd_rsp_type_t sd_app_command(SDState *sd,
default:
/* Fall back to standard commands. */
return sd_normal_command(sd, req);
-
- unimplemented_spi_cmd:
- /* Commands that are recognised but not yet implemented in SPI mode. */
- qemu_log_mask(LOG_UNIMP, "SD: CMD%i not implemented in SPI mode\n",
- req.cmd);
- return sd_illegal;
}
qemu_log_mask(LOG_GUEST_ERROR, "SD: ACMD%i in a wrong state\n", req.cmd);
@@ -1836,7 +1864,7 @@ void sd_write_byte(SDState *sd, uint8_t value)
if (sd->card_status & (ADDRESS_ERROR | WP_VIOLATION))
return;
- trace_sdcard_write_data(sd->proto_name,
+ trace_sdcard_write_data(sd_proto(sd)->name,
sd_acmd_name(sd->current_cmd),
sd->current_cmd, value);
switch (sd->current_cmd) {
@@ -1992,7 +2020,7 @@ uint8_t sd_read_byte(SDState *sd)
io_len = (sd->ocr & (1 << 30)) ? 512 : sd->blk_len;
- trace_sdcard_read_data(sd->proto_name,
+ trace_sdcard_read_data(sd_proto(sd)->name,
sd_acmd_name(sd->current_cmd),
sd->current_cmd, io_len);
switch (sd->current_cmd) {
@@ -2111,6 +2139,40 @@ void sd_enable(SDState *sd, bool enable)
sd->enable = enable;
}
+static const SDProto sd_proto_spi = {
+ .name = "SPI",
+ .cmd = {
+ [0] = sd_cmd_GO_IDLE_STATE,
+ [1] = sd_cmd_SEND_OP_CMD,
+ [2 ... 4] = sd_cmd_illegal,
+ [5] = sd_cmd_illegal,
+ [7] = sd_cmd_illegal,
+ [15] = sd_cmd_illegal,
+ [26] = sd_cmd_illegal,
+ [52 ... 54] = sd_cmd_illegal,
+ },
+ .acmd = {
+ [6] = sd_cmd_unimplemented,
+ [41] = sd_cmd_SEND_OP_CMD,
+ },
+};
+
+static const SDProto sd_proto_sd = {
+ .name = "SD",
+ .cmd = {
+ [0] = sd_cmd_GO_IDLE_STATE,
+ [1] = sd_cmd_illegal,
+ [2] = sd_cmd_ALL_SEND_CID,
+ [3] = sd_cmd_SEND_RELATIVE_ADDR,
+ [5] = sd_cmd_illegal,
+ [19] = sd_cmd_SEND_TUNING_BLOCK,
+ [23] = sd_cmd_SET_BLOCK_COUNT,
+ [52 ... 54] = sd_cmd_illegal,
+ [58] = sd_cmd_illegal,
+ [59] = sd_cmd_illegal,
+ },
+};
+
static void sd_instance_init(Object *obj)
{
SDState *sd = SD_CARD(obj);
@@ -2131,8 +2193,6 @@ static void sd_realize(DeviceState *dev, Error **errp)
SDState *sd = SD_CARD(dev);
int ret;
- sd->proto_name = sd->spi ? "SPI" : "SD";
-
switch (sd->spec_version) {
case SD_PHY_SPECv1_10_VERS
... SD_PHY_SPECv3_01_VERS:
@@ -2189,7 +2249,6 @@ static Property sd_properties[] = {
* 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()
};
@@ -2216,6 +2275,7 @@ static void sd_class_init(ObjectClass *klass, void *data)
sc->enable = sd_enable;
sc->get_inserted = sd_get_inserted;
sc->get_readonly = sd_get_readonly;
+ sc->proto = &sd_proto_sd;
}
static const TypeInfo sd_info = {
@@ -2228,9 +2288,31 @@ static const TypeInfo sd_info = {
.instance_finalize = sd_instance_finalize,
};
+/*
+ * 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.
+ */
+static void sd_spi_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SDCardClass *sc = SD_CARD_CLASS(klass);
+
+ dc->desc = "SD SPI";
+ sc->proto = &sd_proto_spi;
+}
+
+static const TypeInfo sd_spi_info = {
+ .name = TYPE_SD_CARD_SPI,
+ .parent = TYPE_SD_CARD,
+ .class_init = sd_spi_class_init,
+};
+
static void sd_register_types(void)
{
type_register_static(&sd_info);
+ type_register_static(&sd_spi_info);
}
type_init(sd_register_types)
diff --git a/hw/sd/sdmmc-internal.c b/hw/sd/sdmmc-internal.c
index 2053def3f1..8648a7808d 100644
--- a/hw/sd/sdmmc-internal.c
+++ b/hw/sd/sdmmc-internal.c
@@ -14,7 +14,7 @@
const char *sd_cmd_name(uint8_t cmd)
{
static const char *cmd_abbrev[SDMMC_CMD_MAX] = {
- [0] = "GO_IDLE_STATE",
+ [0] = "GO_IDLE_STATE", [1] = "SEND_OP_CMD",
[2] = "ALL_SEND_CID", [3] = "SEND_RELATIVE_ADDR",
[4] = "SET_DSR", [5] = "IO_SEND_OP_COND",
[6] = "SWITCH_FUNC", [7] = "SELECT/DESELECT_CARD",