diff options
author | Stefan Hajnoczi <stefanha@redhat.com> | 2023-09-06 11:14:55 -0400 |
---|---|---|
committer | Stefan Hajnoczi <stefanha@redhat.com> | 2023-09-06 11:14:55 -0400 |
commit | 912a9efd6bf4d808b238e17d26de2e4bb9bc4743 (patch) | |
tree | 9622a651f82f7cfd1664fd0a314fb2ed0d201d4e /hw/sd/sd.c | |
parent | 2d8fbcb1eecd8d39171f457e583428758321d69d (diff) | |
parent | c3287c0f70dae07dd12322c5c8663f7b878826e7 (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/sd.c')
-rw-r--r-- | hw/sd/sd.c | 348 |
1 files changed, 215 insertions, 133 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) |