diff options
Diffstat (limited to 'hw/sd')
-rw-r--r-- | hw/sd/allwinner-sdhost.c | 22 | ||||
-rw-r--r-- | hw/sd/aspeed_sdhci.c | 10 | ||||
-rw-r--r-- | hw/sd/bcm2835_sdhost.c | 9 | ||||
-rw-r--r-- | hw/sd/cadence_sdhci.c | 2 | ||||
-rw-r--r-- | hw/sd/core.c | 5 | ||||
-rw-r--r-- | hw/sd/npcm7xx_sdhci.c | 2 | ||||
-rw-r--r-- | hw/sd/omap_mmc.c | 7 | ||||
-rw-r--r-- | hw/sd/pl181.c | 10 | ||||
-rw-r--r-- | hw/sd/sd.c | 206 | ||||
-rw-r--r-- | hw/sd/sdhci-pci.c | 6 | ||||
-rw-r--r-- | hw/sd/sdhci.c | 10 | ||||
-rw-r--r-- | hw/sd/ssi-sd.c | 102 | ||||
-rw-r--r-- | hw/sd/trace-events | 4 |
13 files changed, 206 insertions, 189 deletions
diff --git a/hw/sd/allwinner-sdhost.c b/hw/sd/allwinner-sdhost.c index 03980d2..9d61b37 100644 --- a/hw/sd/allwinner-sdhost.c +++ b/hw/sd/allwinner-sdhost.c @@ -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)) { @@ -888,14 +885,15 @@ 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); @@ -905,7 +903,8 @@ static void allwinner_sdhost_class_init(ObjectClass *klass, void *data) 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; @@ -913,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; @@ -922,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; @@ -931,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 12cbbae..fc38ad3 100644 --- a/hw/sd/aspeed_sdhci.c +++ b/hw/sd/aspeed_sdhci.c @@ -208,7 +208,7 @@ static const Property aspeed_sdhci_properties[] = { DEFINE_PROP_UINT8("num-slots", AspeedSDHCIState, num_slots, 0), }; -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); @@ -218,7 +218,7 @@ static void aspeed_sdhci_class_init(ObjectClass *classp, void *data) device_class_set_props(dc, aspeed_sdhci_properties); } -static void aspeed_2400_sdhci_class_init(ObjectClass *klass, void *data) +static void aspeed_2400_sdhci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedSDHCIClass *asc = ASPEED_SDHCI_CLASS(klass); @@ -227,7 +227,7 @@ static void aspeed_2400_sdhci_class_init(ObjectClass *klass, void *data) asc->capareg = 0x0000000001e80080; } -static void aspeed_2500_sdhci_class_init(ObjectClass *klass, void *data) +static void aspeed_2500_sdhci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedSDHCIClass *asc = ASPEED_SDHCI_CLASS(klass); @@ -236,7 +236,7 @@ static void aspeed_2500_sdhci_class_init(ObjectClass *klass, void *data) asc->capareg = 0x0000000001e80080; } -static void aspeed_2600_sdhci_class_init(ObjectClass *klass, void *data) +static void aspeed_2600_sdhci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedSDHCIClass *asc = ASPEED_SDHCI_CLASS(klass); @@ -245,7 +245,7 @@ static void aspeed_2600_sdhci_class_init(ObjectClass *klass, void *data) asc->capareg = 0x0000000701f80080; } -static void aspeed_2700_sdhci_class_init(ObjectClass *klass, void *data) +static void aspeed_2700_sdhci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedSDHCIClass *asc = ASPEED_SDHCI_CLASS(klass); diff --git a/hw/sd/bcm2835_sdhost.c b/hw/sd/bcm2835_sdhost.c index 0724949..f7cef7b 100644 --- a/hw/sd/bcm2835_sdhost.c +++ b/hw/sd/bcm2835_sdhost.c @@ -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,7 +425,7 @@ 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); diff --git a/hw/sd/cadence_sdhci.c b/hw/sd/cadence_sdhci.c index ad9daa2..d576855 100644 --- a/hw/sd/cadence_sdhci.c +++ b/hw/sd/cadence_sdhci.c @@ -165,7 +165,7 @@ 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); 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/npcm7xx_sdhci.c b/hw/sd/npcm7xx_sdhci.c index 99028c1..0233d7b 100644 --- a/hw/sd/npcm7xx_sdhci.c +++ b/hw/sd/npcm7xx_sdhci.c @@ -149,7 +149,7 @@ 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); diff --git a/hw/sd/omap_mmc.c b/hw/sd/omap_mmc.c index bbe7b97..5a1d25d 100644 --- a/hw/sd/omap_mmc.c +++ b/hw/sd/omap_mmc.c @@ -130,7 +130,8 @@ static void omap_mmc_command(OMAPMMCState *host, int cmd, int dir, 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]; @@ -157,7 +158,7 @@ static void omap_mmc_command(OMAPMMCState *host, int cmd, int dir, request.arg = host->arg; request.crc = 0; /* FIXME */ - rsplen = sdbus_do_command(&host->sdbus, &request, response); + rsplen = sdbus_do_command(&host->sdbus, &request, response, sizeof(response)); /* TODO: validate CRCs */ switch (resptype) { @@ -612,7 +613,7 @@ static void omap_mmc_initfn(Object *obj) qbus_init(&s->sdbus, sizeof(s->sdbus), TYPE_SD_BUS, DEVICE(obj), "sd-bus"); } -static void omap_mmc_class_init(ObjectClass *oc, void *data) +static void omap_mmc_class_init(ObjectClass *oc, const void *data) { ResettableClass *rc = RESETTABLE_CLASS(oc); diff --git a/hw/sd/pl181.c b/hw/sd/pl181.c index 03d2ae7..5d56ead 100644 --- a/hw/sd/pl181.c +++ b/hw/sd/pl181.c @@ -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,7 +507,7 @@ 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); @@ -519,7 +517,7 @@ static void pl181_class_init(ObjectClass *klass, void *data) 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); @@ -61,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 */ @@ -146,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; @@ -247,6 +247,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)", @@ -313,27 +314,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(); } } @@ -729,16 +727,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 +820,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); } @@ -952,7 +1021,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), @@ -1252,7 +1321,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; @@ -1305,7 +1374,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; @@ -1341,14 +1410,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) { @@ -1420,11 +1481,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); @@ -1517,14 +1584,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) @@ -1539,11 +1622,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) @@ -1575,7 +1654,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); } @@ -1592,7 +1671,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; @@ -1601,7 +1680,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) { @@ -1906,8 +1985,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 */ @@ -1967,6 +2052,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; } @@ -1998,7 +2086,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 */ @@ -2084,7 +2174,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) { @@ -2139,8 +2231,9 @@ static bool cmd_valid_while_locked(SDState *sd, unsigned cmd) return cmd_class == 0 || cmd_class == 7; } -static 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; @@ -2183,7 +2276,6 @@ static int sd_do_command(SDState *sd, SDRequest *req, } last_state = sd->state; - sd_set_mode(sd); if (sd->expecting_acmd) { sd->expecting_acmd = false; @@ -2203,36 +2295,37 @@ static 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: @@ -2244,7 +2337,6 @@ send_response: sd->data_offset = 0; /* fall-through */ case sd_illegal: - rsplen = 0; break; default: g_assert_not_reached(); @@ -2510,7 +2602,7 @@ 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}, @@ -2546,7 +2638,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}, }, @@ -2751,7 +2843,7 @@ static const Property emmc_properties[] = { DEFINE_PROP_UINT8("boot-config", SDState, boot_config, 0x0), }; -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); @@ -2774,7 +2866,7 @@ static void sdmmc_common_class_init(ObjectClass *klass, void *data) 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); @@ -2793,7 +2885,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); @@ -2802,7 +2894,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-pci.c b/hw/sd/sdhci-pci.c index 5268c0d..c18b91f 100644 --- a/hw/sd/sdhci-pci.c +++ b/hw/sd/sdhci-pci.c @@ -18,6 +18,7 @@ #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" @@ -48,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); @@ -73,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 69baf73..3c897e5 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -337,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; @@ -346,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) { @@ -400,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); } @@ -1620,7 +1620,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); @@ -1633,7 +1633,7 @@ static void sdhci_sysbus_class_init(ObjectClass *klass, void *data) /* --- 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); diff --git a/hw/sd/ssi-sd.c b/hw/sd/ssi-sd.c index c4a58da..594dead 100644 --- a/hw/sd/ssi-sd.c +++ b/hw/sd/ssi-sd.c @@ -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,7 @@ 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]; /* * Special case: allow CMD12 (STOP TRANSMISSION) while reading data. @@ -146,8 +129,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 +154,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 +259,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 +315,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); diff --git a/hw/sd/trace-events b/hw/sd/trace-events index db06442..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) "" |