[PATCH v42 06/98] hw/sd/sdcard: Do not store vendor data on block drive (CMD56)
"General command" (GEN_CMD, CMD56) is described as: GEN_CMD is the same as the single block read or write commands (CMD24 or CMD17). The difference is that [...] the data block is not a memory payload data but has a vendor specific format and meaning. Thus this block must not be stored overwriting data block on underlying storage drive. Keep it in a dedicated 'vendor_data[]' array. Signed-off-by: Philippe Mathieu-Daudé Tested-by: Cédric Le Goater --- RFC: Is it safe to reuse VMSTATE_UNUSED_V() (which happens to be the same size)? Cc: Peter Xu Cc: Fabiano Rosas --- hw/sd/sd.c | 17 + 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 464576751a..1f3eea6e84 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -142,6 +142,8 @@ struct SDState { uint64_t data_start; uint32_t data_offset; uint8_t data[512]; +uint8_t vendor_data[512]; + qemu_irq readonly_cb; qemu_irq inserted_cb; QEMUTimer *ocr_power_timer; @@ -656,6 +658,7 @@ static void sd_reset(DeviceState *dev) sd->wp_switch = sd->blk ? !blk_is_writable(sd->blk) : false; sd->wp_group_bits = sect; sd->wp_group_bmap = bitmap_new(sd->wp_group_bits); +memset(sd->vendor_data, 0xec, sizeof(sd->vendor_data)); memset(sd->function_group, 0, sizeof(sd->function_group)); sd->erase_start = INVALID_ADDRESS; sd->erase_end = INVALID_ADDRESS; @@ -771,7 +774,7 @@ static const VMStateDescription sd_vmstate = { VMSTATE_UINT64(data_start, SDState), VMSTATE_UINT32(data_offset, SDState), VMSTATE_UINT8_ARRAY(data, SDState, 512), -VMSTATE_UNUSED_V(1, 512), +VMSTATE_UINT8_ARRAY(vendor_data, SDState, 512), VMSTATE_BOOL(enable, SDState), VMSTATE_END_OF_LIST() }, @@ -2029,9 +2032,8 @@ void sd_write_byte(SDState *sd, uint8_t value) break; case 56: /* CMD56: GEN_CMD */ -sd->data[sd->data_offset ++] = value; -if (sd->data_offset >= sd->blk_len) { -APP_WRITE_BLOCK(sd->data_start, sd->data_offset); +sd->vendor_data[sd->data_offset ++] = value; +if (sd->data_offset >= sizeof(sd->vendor_data)) { sd->state = sd_transfer_state; } break; @@ -2165,12 +2167,11 @@ uint8_t sd_read_byte(SDState *sd) break; case 56: /* CMD56: GEN_CMD */ -if (sd->data_offset == 0) -APP_READ_BLOCK(sd->data_start, sd->blk_len); -ret = sd->data[sd->data_offset ++]; +ret = sd->vendor_data[sd->data_offset ++]; -if (sd->data_offset >= sd->blk_len) +if (sd->data_offset >= sizeof(sd->vendor_data)) { sd->state = sd_transfer_state; +} break; default: -- 2.41.0
[PATCH v42 03/98] hw/sd/sdcard: Track last command used to help logging
The command is selected on the I/O lines, and further processing might be done on the DAT lines via the sd_read_byte() and sd_write_byte() handlers. Since these methods can't distinct between normal and APP commands, keep the name of the current command in the SDState and use it in the DAT handlers. This fixes a bug that all normal commands were displayed as APP commands. Fixes: 2ed61fb57b ("sdcard: Display command name when tracing CMD/ACMD") Signed-off-by: Philippe Mathieu-Daudé Tested-by: Cédric Le Goater --- hw/sd/sd.c | 12 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index d0a1d5db18..bc87807793 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -133,6 +133,7 @@ struct SDState { uint32_t pwd_len; uint8_t function_group[6]; uint8_t current_cmd; +const char *last_cmd_name; /* True if we will handle the next command as an ACMD. Note that this does * *not* track the APP_CMD status bit! */ @@ -1154,12 +1155,13 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) uint16_t rca; uint64_t addr; +sd->last_cmd_name = sd_cmd_name(req.cmd); /* CMD55 precedes an ACMD, so we are not interested in tracing it. * 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(sd)->name, -sd_cmd_name(req.cmd), req.cmd, +sd->last_cmd_name, req.cmd, req.arg, sd_state_name(sd->state)); } @@ -1620,7 +1622,8 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) static sd_rsp_type_t sd_app_command(SDState *sd, SDRequest req) { -trace_sdcard_app_command(sd_proto(sd)->name, sd_acmd_name(req.cmd), +sd->last_cmd_name = sd_acmd_name(req.cmd); +trace_sdcard_app_command(sd_proto(sd)->name, sd->last_cmd_name, req.cmd, req.arg, sd_state_name(sd->state)); sd->card_status |= APP_CMD; @@ -1913,7 +1916,7 @@ void sd_write_byte(SDState *sd, uint8_t value) return; trace_sdcard_write_data(sd_proto(sd)->name, -sd_acmd_name(sd->current_cmd), +sd->last_cmd_name, sd->current_cmd, value); switch (sd->current_cmd) { case 24: /* CMD24: WRITE_SINGLE_BLOCK */ @@ -2069,7 +2072,7 @@ uint8_t sd_read_byte(SDState *sd) io_len = (sd->ocr & (1 << 30)) ? 512 : sd->blk_len; trace_sdcard_read_data(sd_proto(sd)->name, - sd_acmd_name(sd->current_cmd), + sd->last_cmd_name, sd->current_cmd, io_len); switch (sd->current_cmd) { case 6: /* CMD6: SWITCH_FUNCTION */ @@ -2214,6 +2217,7 @@ static void sd_instance_init(Object *obj) { SDState *sd = SD_CARD(obj); +sd->last_cmd_name = "UNSET"; sd->enable = true; sd->ocr_power_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sd_ocr_powerup, sd); } -- 2.41.0
[PATCH v42 07/98] hw/sd/sdcard: Send WRITE_PROT bits MSB first (CMD30)
Per sections 3.6.1 (SD Bus Protocol) and 7.3.2 (Responses): In the CMD line the Most Significant Bit is transmitted first. Use the stl_be_p() helper to store the value in big-endian. Signed-off-by: Philippe Mathieu-Daudé Tested-by: Cédric Le Goater --- RFC because I'm surprised this has been unnoticed for 17 years (commit a1bb27b1e9 "initial SD card emulation", April 2007). Cc: Peter Maydell --- hw/sd/sd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 1f3eea6e84..4e09640852 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1507,7 +1507,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) } sd->state = sd_sendingdata_state; -*(uint32_t *) sd->data = sd_wpbits(sd, req.arg); +stl_be_p(sd->data, sd_wpbits(sd, req.arg)); sd->data_start = addr; sd->data_offset = 0; return sd_r1; -- 2.41.0
[PATCH v42 02/98] hw/sd/sdcard: Use spec v3.01 by default
Recent SDHCI expect cards to support the v3.01 spec to negociate lower I/O voltage. Select it by default. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Cédric Le Goater --- hw/sd/sd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index a48010cfc1..d0a1d5db18 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -2280,7 +2280,7 @@ static void sd_realize(DeviceState *dev, Error **errp) static Property sd_properties[] = { DEFINE_PROP_UINT8("spec_version", SDState, - spec_version, SD_PHY_SPECv2_00_VERS), + spec_version, SD_PHY_SPECv3_01_VERS), DEFINE_PROP_DRIVE("drive", SDState, blk), /* We do not model the chip select pin, so allow the board to select * whether card should be in SSI or MMC/SD mode. It is also up to the -- 2.41.0
[PATCH v42 10/98] hw/sd/sdcard: Assign SDCardStates enum values
SDCardStates enum values are specified, so assign them correspondingly. It will be useful later when we add states from later specs, which might not be continuous. See CURRENT_STATE bits in section 4.10.1 "Card Status". Signed-off-by: Philippe Mathieu-Daudé Tested-by: Cédric Le Goater --- hw/sd/sd.c | 20 ++-- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 135b7d2e23..fbdfafa3a6 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -75,16 +75,16 @@ enum SDCardModes { }; enum SDCardStates { -sd_inactive_state = -1, -sd_idle_state = 0, -sd_ready_state, -sd_identification_state, -sd_standby_state, -sd_transfer_state, -sd_sendingdata_state, -sd_receivingdata_state, -sd_programming_state, -sd_disconnect_state, +sd_inactive_state = -1, +sd_idle_state = 0, +sd_ready_state = 1, +sd_identification_state = 2, +sd_standby_state= 3, +sd_transfer_state = 4, +sd_sendingdata_state= 5, +sd_receivingdata_state = 6, +sd_programming_state= 7, +sd_disconnect_state = 8, }; typedef sd_rsp_type_t (*sd_cmd_handler)(SDState *sd, SDRequest req); -- 2.41.0
[PATCH v42 11/98] hw/sd/sdcard: Simplify sd_inactive_state handling
Card entering sd_inactive_state powers off, and won't respond anymore. Handle that once when entering sd_do_command(). Remove condition always true in sd_cmd_GO_IDLE_STATE(). Signed-off-by: Philippe Mathieu-Daudé Tested-by: Cédric Le Goater --- hw/sd/sd.c | 12 +++- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index fbdfafa3a6..7533a78cf6 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1081,10 +1081,8 @@ static sd_rsp_type_t sd_cmd_unimplemented(SDState *sd, SDRequest req) /* CMD0 */ 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)); -} +sd->state = sd_idle_state; +sd_reset(DEVICE(sd)); return sd_is_spi(sd) ? sd_r1 : sd_r0; } @@ -1579,7 +1577,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) switch (sd->state) { case sd_ready_state: case sd_identification_state: -case sd_inactive_state: return sd_illegal; case sd_idle_state: if (rca) { @@ -1800,6 +1797,11 @@ int sd_do_command(SDState *sd, SDRequest *req, return 0; } +if (sd->state == sd_inactive_state) { +rtype = sd_illegal; +goto send_response; +} + if (sd_req_crc_validate(req)) { sd->card_status |= COM_CRC_ERROR; rtype = sd_illegal; -- 2.41.0
[NOTFORMERGE PATCH v42 15/98] tests/qtest: Disable npcm7xx_sdhci tests using hardcoded RCA
Disable tests using 0x4567 hardcoded RCA otherwise when using random RCA we get: ERROR:../../tests/qtest/npcm7xx_sdhci-test.c:69:write_sdread: assertion failed: (ret == len) not ok /arm/npcm7xx_sdhci/read_sd - ERROR:../../tests/qtest/npcm7xx_sdhci-test.c:69:write_sdread: assertion failed: (ret == len) Bail out! See https://lore.kernel.org/qemu-devel/37f83be9-deb5-42a1-b704-14984351d...@linaro.org/ Signed-off-by: Philippe Mathieu-Daudé --- Cc: Hao Wu Cc: Shengtan Mao Cc: Tyrone Ting See also discussion with Thomas: https://lore.kernel.org/qemu-devel/484dce48-286a-4a2b-9040-98c45bcfb...@linaro.org/ --- tests/qtest/npcm7xx_sdhci-test.c | 7 +++ 1 file changed, 7 insertions(+) diff --git a/tests/qtest/npcm7xx_sdhci-test.c b/tests/qtest/npcm7xx_sdhci-test.c index 5d68540e52..6a42b142ad 100644 --- a/tests/qtest/npcm7xx_sdhci-test.c +++ b/tests/qtest/npcm7xx_sdhci-test.c @@ -44,6 +44,7 @@ static QTestState *setup_sd_card(void) sdhci_cmd_regs(qts, NPCM7XX_MMC_BA, 0, 0, 0x4120, 0, (41 << 8)); sdhci_cmd_regs(qts, NPCM7XX_MMC_BA, 0, 0, 0, 0, SDHC_ALL_SEND_CID); sdhci_cmd_regs(qts, NPCM7XX_MMC_BA, 0, 0, 0, 0, SDHC_SEND_RELATIVE_ADDR); +g_test_skip("hardcoded 0x4567 card address"); sdhci_cmd_regs(qts, NPCM7XX_MMC_BA, 0, 0, 0x4567, 0, SDHC_SELECT_DESELECT_CARD); @@ -76,6 +77,9 @@ static void test_read_sd(void) { QTestState *qts = setup_sd_card(); +g_test_skip("hardcoded 0x4567 card address used in setup_sd_card()"); +return; + write_sdread(qts, "hello world"); write_sdread(qts, "goodbye"); @@ -108,6 +112,9 @@ static void test_write_sd(void) { QTestState *qts = setup_sd_card(); +g_test_skip("hardcoded 0x4567 card address used in setup_sd_card()"); +return; + sdwrite_read(qts, "hello world"); sdwrite_read(qts, "goodbye"); -- 2.41.0
[PATCH v42 14/98] hw/sd/sdcard: Extract sd_blk_len() helper
From: Philippe Mathieu-Daudé Extract sd_blk_len() helper, use definitions instead of magic values. Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 10 +- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index aaa50ab2c5..5997e13107 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -603,6 +603,14 @@ static void sd_response_r7_make(SDState *sd, uint8_t *response) stl_be_p(response, sd->vhs); } +static uint32_t sd_blk_len(SDState *sd) +{ +if (FIELD_EX32(sd->ocr, OCR, CARD_CAPACITY)) { +return 1 << HWBLOCK_SHIFT; +} +return sd->blk_len; +} + static uint64_t sd_req_get_address(SDState *sd, SDRequest req) { uint64_t addr; @@ -2076,7 +2084,7 @@ uint8_t sd_read_byte(SDState *sd) if (sd->card_status & (ADDRESS_ERROR | WP_VIOLATION)) return 0x00; -io_len = (sd->ocr & (1 << 30)) ? 512 : sd->blk_len; +io_len = sd_blk_len(sd); trace_sdcard_read_data(sd->proto->name, sd->last_cmd_name, -- 2.41.0
[PATCH v42 05/98] hw/sd/sdcard: Trace requested address computed by sd_req_get_address()
Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 9 +++-- hw/sd/trace-events | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 090a6fdcdb..464576751a 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -608,10 +608,15 @@ static void sd_response_r7_make(SDState *sd, uint8_t *response) static uint64_t sd_req_get_address(SDState *sd, SDRequest req) { +uint64_t addr; + if (FIELD_EX32(sd->ocr, OCR, CARD_CAPACITY)) { -return (uint64_t) req.arg << HWBLOCK_SHIFT; +addr = (uint64_t) req.arg << HWBLOCK_SHIFT; +} else { +addr = req.arg; } -return req.arg; +trace_sdcard_req_addr(req.arg, addr); +return addr; } static inline uint64_t sd_addr_to_wpnum(uint64_t addr) diff --git a/hw/sd/trace-events b/hw/sd/trace-events index 0eee98a646..43eaeba149 100644 --- a/hw/sd/trace-events +++ b/hw/sd/trace-events @@ -50,6 +50,7 @@ sdcard_ejected(void) "" sdcard_erase(uint32_t first, uint32_t last) "addr first 0x%" PRIx32" last 0x%" PRIx32 sdcard_lock(void) "" sdcard_unlock(void) "" +sdcard_req_addr(uint32_t req_arg, uint64_t addr) "req 0x%" PRIx32 " addr 0x%" PRIx64 sdcard_read_block(uint64_t addr, uint32_t len) "addr 0x%" PRIx64 " size 0x%x" sdcard_write_block(uint64_t addr, uint32_t len) "addr 0x%" PRIx64 " size 0x%x" sdcard_write_data(const char *proto, const char *cmd_desc, uint8_t cmd, uint32_t offset, uint8_t value) "%s %20s/ CMD%02d ofs %"PRIu32" value 0x%02x" -- 2.41.0
[PATCH v42 09/98] hw/sd/sdcard: Use READY_FOR_DATA definition instead of magic value
Signed-off-by: Philippe Mathieu-Daudé Tested-by: Cédric Le Goater --- hw/sd/sd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 1f37d9c93a..135b7d2e23 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -561,7 +561,7 @@ FIELD(CSR, OUT_OF_RANGE, 31, 1) static void sd_set_cardstatus(SDState *sd) { -sd->card_status = 0x0100; +sd->card_status = READY_FOR_DATA; } static void sd_set_sdstatus(SDState *sd) -- 2.41.0
[PATCH v42 08/98] hw/sd/sdcard: Send NUM_WR_BLOCKS bits MSB first (ACMD22)
Per sections 3.6.1 (SD Bus Protocol), 4.3.4 "Data Write" and 7.3.2 (Responses): In the CMD line the Most Significant Bit is transmitted first. Use the stl_be_p() helper to store the value in big-endian. Signed-off-by: Philippe Mathieu-Daudé Tested-by: Cédric Le Goater --- RFC because I'm surprised this has been unnoticed for 17 years (commit a1bb27b1e9 "initial SD card emulation", April 2007). Cc: Peter Maydell --- hw/sd/sd.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 4e09640852..1f37d9c93a 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1668,8 +1668,7 @@ static sd_rsp_type_t sd_app_command(SDState *sd, case 22: /* ACMD22: SEND_NUM_WR_BLOCKS */ switch (sd->state) { case sd_transfer_state: -*(uint32_t *) sd->data = sd->blk_written; - +stl_be_p(sd->data, sd->blk_written); sd->state = sd_sendingdata_state; sd->data_start = 0; sd->data_offset = 0; -- 2.41.0
[PATCH v42 17/98] hw/sd/sdcard: Introduce definitions for EXT_CSD register
From: Cédric Le Goater Signed-off-by: Cédric Le Goater Signed-off-by: Cédric Le Goater Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sdmmc-internal.h | 97 ++ 1 file changed, 97 insertions(+) diff --git a/hw/sd/sdmmc-internal.h b/hw/sd/sdmmc-internal.h index d8bf17d204..306ffa7f53 100644 --- a/hw/sd/sdmmc-internal.h +++ b/hw/sd/sdmmc-internal.h @@ -11,6 +11,103 @@ #ifndef SDMMC_INTERNAL_H #define SDMMC_INTERNAL_H +/* + * EXT_CSD fields + */ + +#define EXT_CSD_CMDQ_MODE_EN15 /* R/W */ +#define EXT_CSD_FLUSH_CACHE 32 /* W */ +#define EXT_CSD_CACHE_CTRL 33 /* R/W */ +#define EXT_CSD_POWER_OFF_NOTIFICATION 34 /* R/W */ +#define EXT_CSD_PACKED_FAILURE_INDEX35 /* RO */ +#define EXT_CSD_PACKED_CMD_STATUS 36 /* RO */ +#define EXT_CSD_EXP_EVENTS_STATUS 54 /* RO, 2 bytes */ +#define EXT_CSD_EXP_EVENTS_CTRL 56 /* R/W, 2 bytes */ +#define EXT_CSD_DATA_SECTOR_SIZE61 /* R */ +#define EXT_CSD_GP_SIZE_MULT143 /* R/W */ +#define EXT_CSD_PARTITION_SETTING_COMPLETED 155 /* R/W */ +#define EXT_CSD_PARTITION_ATTRIBUTE 156 /* R/W */ +#define EXT_CSD_PARTITION_SUPPORT 160 /* RO */ +#define EXT_CSD_HPI_MGMT161 /* R/W */ +#define EXT_CSD_RST_N_FUNCTION 162 /* R/W */ +#define EXT_CSD_BKOPS_EN163 /* R/W */ +#define EXT_CSD_BKOPS_START 164 /* W */ +#define EXT_CSD_SANITIZE_START 165 /* W */ +#define EXT_CSD_WR_REL_PARAM166 /* RO */ +#define EXT_CSD_RPMB_MULT 168 /* RO */ +#define EXT_CSD_FW_CONFIG 169 /* R/W */ +#define EXT_CSD_BOOT_WP 173 /* R/W */ +#define EXT_CSD_ERASE_GROUP_DEF 175 /* R/W */ +#define EXT_CSD_PART_CONFIG 179 /* R/W */ +#define EXT_CSD_ERASED_MEM_CONT 181 /* RO */ +#define EXT_CSD_BUS_WIDTH 183 /* R/W */ +#define EXT_CSD_STROBE_SUPPORT 184 /* RO */ +#define EXT_CSD_HS_TIMING 185 /* R/W */ +#define EXT_CSD_POWER_CLASS 187 /* R/W */ +#define EXT_CSD_REV 192 /* RO */ +#define EXT_CSD_STRUCTURE 194 /* RO */ +#define EXT_CSD_CARD_TYPE 196 /* RO */ +#define EXT_CSD_DRIVER_STRENGTH 197 /* RO */ +#define EXT_CSD_OUT_OF_INTERRUPT_TIME 198 /* RO */ +#define EXT_CSD_PART_SWITCH_TIME199 /* RO */ +#define EXT_CSD_PWR_CL_52_195 200 /* RO */ +#define EXT_CSD_PWR_CL_26_195 201 /* RO */ +#define EXT_CSD_PWR_CL_52_360 202 /* RO */ +#define EXT_CSD_PWR_CL_26_360 203 /* RO */ +#define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */ +#define EXT_CSD_S_A_TIMEOUT 217 /* RO */ +#define EXT_CSD_S_C_VCCQ219 /* RO */ +#define EXT_CSD_S_C_VCC 220 /* RO */ +#define EXT_CSD_REL_WR_SEC_C222 /* RO */ +#define EXT_CSD_HC_WP_GRP_SIZE 221 /* RO */ +#define EXT_CSD_ERASE_TIMEOUT_MULT 223 /* RO */ +#define EXT_CSD_HC_ERASE_GRP_SIZE 224 /* RO */ +#define EXT_CSD_ACC_SIZE225 /* RO */ +#define EXT_CSD_BOOT_MULT 226 /* RO */ +#define EXT_CSD_BOOT_INFO 228 /* RO */ +#define EXT_CSD_SEC_TRIM_MULT 229 /* RO */ +#define EXT_CSD_SEC_ERASE_MULT 230 /* RO */ +#define EXT_CSD_SEC_FEATURE_SUPPORT 231 /* RO */ +#define EXT_CSD_TRIM_MULT 232 /* RO */ +#define EXT_CSD_PWR_CL_200_195 236 /* RO */ +#define EXT_CSD_PWR_CL_200_360 237 /* RO */ +#define EXT_CSD_PWR_CL_DDR_52_195 238 /* RO */ +#define EXT_CSD_PWR_CL_DDR_52_360 239 /* RO */ +#define EXT_CSD_BKOPS_STATUS246 /* RO */ +#define EXT_CSD_POWER_OFF_LONG_TIME 247 /* RO */ +#define EXT_CSD_GENERIC_CMD6_TIME 248 /* RO */ +#define EXT_CSD_CACHE_SIZE 249 /* RO, 4 bytes */ +#define EXT_CSD_PWR_CL_DDR_200_360 253 /* RO */ +#define EXT_CSD_FIRMWARE_VERSION254 /* RO, 8 bytes */ +#define EXT_CSD_PRE_EOL_INFO267 /* RO */ +#define EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_A 268 /* RO */ +#define EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_B 269 /* RO */ +#define EXT_CSD_CMDQ_DEPTH 307 /* RO */ +#define EXT_CSD_CMDQ_SUPPORT308 /* RO */ +#define EXT_CSD_SUPPORTED_MODE 493 /* RO */ +#define EXT_CSD_TAG_UNIT_SIZE 498 /* RO */ +#define EXT_CSD_DATA_TAG_SUPPORT499 /* RO */ +#define EXT_CSD_MAX_PACKED_WRITES 500 /* RO */ +#define EXT_CSD_MAX_PACKED_READS501 /* RO */ +#define EXT_CSD_BKOPS_SUPPORT 502 /* RO */ +#define EXT_CSD_HPI_FEATURES503 /* RO */ +#define EXT_CSD_
[PATCH v42 16/98] hw/sd/sdcard: Generate random RCA value
Rather than using the obscure 0x4567 magic value, use a real random one. Signed-off-by: Philippe Mathieu-Daudé Tested-by: Cédric Le Goater --- hw/sd/sd.c | 11 --- hw/sd/trace-events | 1 + 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 5997e13107..d85b2906f4 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -46,6 +46,7 @@ #include "qemu/error-report.h" #include "qemu/timer.h" #include "qemu/log.h" +#include "qemu/guest-random.h" #include "qemu/module.h" #include "sdmmc-internal.h" #include "trace.h" @@ -488,9 +489,10 @@ static void sd_set_csd(SDState *sd, uint64_t size) /* Relative Card Address register */ -static void sd_set_rca(SDState *sd) +static void sd_set_rca(SDState *sd, uint16_t value) { -sd->rca += 0x4567; +trace_sdcard_set_rca(value); +sd->rca = value; } static uint16_t sd_req_get_rca(SDState *s, SDRequest req) @@ -1113,11 +1115,14 @@ static sd_rsp_type_t sd_cmd_ALL_SEND_CID(SDState *sd, SDRequest req) /* CMD3 */ static sd_rsp_type_t sd_cmd_SEND_RELATIVE_ADDR(SDState *sd, SDRequest req) { +uint16_t random_rca; + switch (sd->state) { case sd_identification_state: case sd_standby_state: sd->state = sd_standby_state; -sd_set_rca(sd); +qemu_guest_getrandom_nofail(&random_rca, sizeof(random_rca)); +sd_set_rca(sd, random_rca); return sd_r6; default: diff --git a/hw/sd/trace-events b/hw/sd/trace-events index 43eaeba149..6a51b0e906 100644 --- a/hw/sd/trace-events +++ b/hw/sd/trace-events @@ -43,6 +43,7 @@ sdcard_response(const char *rspdesc, int rsplen) "%s (sz:%d)" sdcard_powerup(void) "" sdcard_inquiry_cmd41(void) "" sdcard_reset(void) "" +sdcard_set_rca(uint16_t value) "new RCA: 0x%04x" sdcard_set_blocklen(uint16_t length) "block len 0x%03x" sdcard_set_block_count(uint32_t cnt) "block cnt 0x%"PRIx32 sdcard_inserted(bool readonly) "read_only: %u" -- 2.41.0
[PATCH v42 18/98] hw/sd/sdcard: Introduce sd_cmd_to_sendingdata and sd_generic_read_byte
All commands switching from TRANSFER state to (sending)DATA do the same: send stream of data on the DAT lines. Instead of duplicating the same code many times, introduce 2 helpers: - sd_cmd_to_sendingdata() on the I/O line setup the data to be transferred, - sd_generic_read_byte() on the DAT lines to fetch the data. Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 39 +++ 1 file changed, 39 insertions(+) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index d85b2906f4..1a8d06804d 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -142,8 +142,10 @@ struct SDState { */ bool expecting_acmd; uint32_t blk_written; + uint64_t data_start; uint32_t data_offset; +size_t data_size; uint8_t data[512]; uint8_t vendor_data[512]; @@ -1083,6 +1085,29 @@ static sd_rsp_type_t sd_cmd_unimplemented(SDState *sd, SDRequest req) return sd_illegal; } +/* Configure fields for following sd_generic_read_byte() calls */ +__attribute__((unused)) +static sd_rsp_type_t sd_cmd_to_sendingdata(SDState *sd, SDRequest req, + uint64_t start, + const void *data, size_t size) +{ +if (sd->state != sd_transfer_state) { +sd_invalid_state_for_cmd(sd, req); +} + +sd->state = sd_sendingdata_state; +sd->data_start = start; +sd->data_offset = 0; +if (data) { +assert(size); +memcpy(sd->data, data, size); +} +if (size) { +sd->data_size = size; +} +return sd_r1; +} + /* CMD0 */ static sd_rsp_type_t sd_cmd_GO_IDLE_STATE(SDState *sd, SDRequest req) { @@ -1920,6 +1945,20 @@ send_response: return rsplen; } +/* Return true when buffer is consumed. Configured by sd_cmd_to_sendingdata() */ +__attribute__((unused)) +static bool sd_generic_read_byte(SDState *sd, uint8_t *value) +{ +*value = sd->data[sd->data_offset]; + +if (++sd->data_offset >= sd->data_size) { +sd->state = sd_transfer_state; +return true; +} + +return false; +} + void sd_write_byte(SDState *sd, uint8_t value) { int i; -- 2.41.0
[PATCH v42 34/98] hw/sd/sdcard: Convert LOCK_UNLOCK to generic_write_byte (CMD42)
Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 15 ++- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index bdd5f3486a..0cb528b0b2 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1628,17 +1628,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) /* Lock card commands (Class 7) */ case 42: /* CMD42: LOCK_UNLOCK */ -switch (sd->state) { -case sd_transfer_state: -sd->state = sd_receivingdata_state; -sd->data_start = 0; -sd->data_offset = 0; -return sd_r1; - -default: -break; -} -break; +return sd_cmd_to_receivingdata(sd, req, 0, 0); /* Application specific commands (Class 8) */ case 55: /* CMD55: APP_CMD */ @@ -2109,8 +2099,7 @@ void sd_write_byte(SDState *sd, uint8_t value) break; case 42: /* CMD42: LOCK_UNLOCK */ -sd->data[sd->data_offset ++] = value; -if (sd->data_offset >= sd->blk_len) { +if (sd_generic_write_byte(sd, value)) { /* TODO: Check CRC before committing */ sd->state = sd_programming_state; sd_lock_command(sd); -- 2.41.0
[PATCH v42 23/98] hw/sd/sdcard: Convert SEND_TUNING_BLOCK to generic_read_byte (CMD19)
From: Philippe Mathieu-Daudé Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 48 +++- 1 file changed, 19 insertions(+), 29 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 605269163d..eece33194a 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -568,6 +568,21 @@ static void sd_set_sdstatus(SDState *sd) memset(sd->sd_status, 0, 64); } +static const uint8_t sd_tuning_block_pattern4[64] = { +/* + * See: Physical Layer Simplified Specification Version 3.01, + * Table 4-2. + */ +0xff, 0x0f, 0xff, 0x00, 0x0f, 0xfc, 0xc3, 0xcc, +0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef, +0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb, +0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef, +0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c, +0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee, +0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff, +0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde +}; + static int sd_req_crc_validate(SDRequest *req) { uint8_t buffer[5]; @@ -1161,14 +1176,9 @@ static sd_rsp_type_t sd_cmd_SEND_TUNING_BLOCK(SDState *sd, SDRequest req) 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; +return sd_cmd_to_sendingdata(sd, req, 0, + sd_tuning_block_pattern4, + sizeof(sd_tuning_block_pattern4)); } /* CMD23 */ @@ -2100,20 +2110,6 @@ void sd_write_byte(SDState *sd, uint8_t value) } } -#define SD_TUNING_BLOCK_SIZE64 - -static const uint8_t sd_tuning_block_pattern[SD_TUNING_BLOCK_SIZE] = { -/* See: Physical Layer Simplified Specification Version 3.01, Table 4-2 */ -0xff, 0x0f, 0xff, 0x00, 0x0f, 0xfc, 0xc3, 0xcc, -0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef, -0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb, -0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef, -0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c, -0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee, -0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff, -0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde, -}; - uint8_t sd_read_byte(SDState *sd) { /* TODO: Append CRCs */ @@ -2142,6 +2138,7 @@ uint8_t sd_read_byte(SDState *sd) case 9: /* CMD9: SEND_CSD */ case 10: /* CMD10: SEND_CID */ case 17: /* CMD17: READ_SINGLE_BLOCK */ +case 19: /* CMD19: SEND_TUNING_BLOCK (SD) */ sd_generic_read_byte(sd, &ret); break; @@ -2176,13 +2173,6 @@ uint8_t sd_read_byte(SDState *sd) } break; -case 19:/* CMD19: SEND_TUNING_BLOCK (SD) */ -if (sd->data_offset >= SD_TUNING_BLOCK_SIZE - 1) { -sd->state = sd_transfer_state; -} -ret = sd_tuning_block_pattern[sd->data_offset++]; -break; - case 22: /* ACMD22: SEND_NUM_WR_BLOCKS */ ret = sd->data[sd->data_offset ++]; -- 2.41.0
[PATCH v42 21/98] hw/sd/sdcard: Duplicate READ_SINGLE_BLOCK / READ_MULTIPLE_BLOCK cases
In order to modify the READ_SINGLE_BLOCK case in the next commit, duplicate it first. Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 18 ++ 1 file changed, 18 insertions(+) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 8201f3245c..dfcb213aa9 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1398,6 +1398,24 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) break; case 17: /* CMD17: READ_SINGLE_BLOCK */ +addr = sd_req_get_address(sd, req); +switch (sd->state) { +case sd_transfer_state: + +if (!address_in_range(sd, "READ_SINGLE_BLOCK", addr, sd->blk_len)) { +return sd_r1; +} + +sd->state = sd_sendingdata_state; +sd->data_start = addr; +sd->data_offset = 0; +return sd_r1; + +default: +break; +} +break; + case 18: /* CMD18: READ_MULTIPLE_BLOCK */ addr = sd_req_get_address(sd, req); switch (sd->state) { -- 2.41.0
[PATCH v42 13/98] hw/sd/sdcard: Add direct reference to SDProto in SDState
Keep direct reference to SDProto in SDState, remove then unnecessary sd_proto(). Signed-off-by: Philippe Mathieu-Daudé Tested-by: Cédric Le Goater --- hw/sd/sd.c | 37 + 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 8f441e418c..aaa50ab2c5 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -116,6 +116,8 @@ struct SDState { uint8_t spec_version; BlockBackend *blk; +const SDProto *proto; + /* Runtime changeables */ uint32_t mode;/* current card mode, one of SDCardModes */ @@ -154,18 +156,11 @@ 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; +return sd->proto == &sd_proto_spi; } static const char *sd_version_str(enum SDPhySpecificationVersion version) @@ -1044,7 +1039,7 @@ static bool address_in_range(SDState *sd, const char *desc, 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->proto->name, req.cmd, sd_state_name(sd->state), sd_version_str(sd->spec_version)); return sd_illegal; @@ -1053,7 +1048,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(sd)->name, req.cmd, sd_mode_name(sd->mode), + sd->proto->name, req.cmd, sd_mode_name(sd->mode), sd_version_str(sd->spec_version)); return sd_illegal; @@ -1062,7 +1057,7 @@ static sd_rsp_type_t sd_invalid_mode_for_cmd(SDState *sd, SDRequest req) 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->proto->name, req.cmd, sd_version_str(sd->spec_version)); return sd_illegal; @@ -1073,7 +1068,7 @@ __attribute__((unused)) 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); + sd->proto->name, req.cmd); return sd_illegal; } @@ -1166,7 +1161,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(sd)->name, +trace_sdcard_normal_command(sd->proto->name, sd->last_cmd_name, req.cmd, req.arg, sd_state_name(sd->state)); } @@ -1185,8 +1180,8 @@ 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); +if (sd->proto->cmd[req.cmd]) { +return sd->proto->cmd[req.cmd](sd, req); } switch (req.cmd) { @@ -1632,12 +1627,12 @@ static sd_rsp_type_t sd_app_command(SDState *sd, SDRequest req) { sd->last_cmd_name = sd_acmd_name(req.cmd); -trace_sdcard_app_command(sd_proto(sd)->name, sd->last_cmd_name, +trace_sdcard_app_command(sd->proto->name, sd->last_cmd_name, 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); +if (sd->proto->acmd[req.cmd]) { +return sd->proto->acmd[req.cmd](sd, req); } switch (req.cmd) { @@ -1928,7 +1923,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(sd)->name, +trace_sdcard_write_data(sd->proto->name, sd->last_cmd_name, sd->current_cmd, sd->data_offset, value); switch (sd->current_cmd) { @@ -2083,7 +2078,7 @@ uint8_t sd_read_byte(SDState *sd) io_len = (sd->ocr & (1 << 30)) ? 512 : sd->blk_len; -trace_sdcard_read_data(sd_proto(sd)->name, +trace_sdcard_read_data(sd->proto->name, sd->last_cmd_name, sd->current_cmd, sd->data_offset, io_len); switch (sd->current_cmd) { @@ -2227,7 +,9 @@ static const SDProto sd_proto_sd = { static void sd_
[PATCH v42 27/98] hw/sd/sdcard: Convert SEND_NUM_WR_BLOCKS to generic_read_byte (ACMD22)
Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 16 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 1c4811f410..8d02cd9a26 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1715,11 +1715,9 @@ static sd_rsp_type_t sd_app_command(SDState *sd, case 22: /* ACMD22: SEND_NUM_WR_BLOCKS */ switch (sd->state) { case sd_transfer_state: -stl_be_p(sd->data, sd->blk_written); -sd->state = sd_sendingdata_state; -sd->data_start = 0; -sd->data_offset = 0; -return sd_r1; +return sd_cmd_to_sendingdata(sd, req, 0, + &sd->blk_written, + sizeof(sd->blk_written)); default: break; @@ -2138,6 +2136,7 @@ uint8_t sd_read_byte(SDState *sd) case 13: /* ACMD13: SD_STATUS */ case 17: /* CMD17: READ_SINGLE_BLOCK */ case 19: /* CMD19: SEND_TUNING_BLOCK (SD) */ +case 22: /* ACMD22: SEND_NUM_WR_BLOCKS */ case 30: /* CMD30: SEND_WRITE_PROT */ case 56: /* CMD56: GEN_CMD */ sd_generic_read_byte(sd, &ret); @@ -2167,13 +2166,6 @@ uint8_t sd_read_byte(SDState *sd) } break; -case 22: /* ACMD22: SEND_NUM_WR_BLOCKS */ -ret = sd->data[sd->data_offset ++]; - -if (sd->data_offset >= 4) -sd->state = sd_transfer_state; -break; - case 51: /* ACMD51: SEND_SCR */ ret = sd->scr[sd->data_offset ++]; -- 2.41.0
[PATCH v42 29/98] hw/sd/sdcard: Introduce sd_cmd_to_receivingdata / sd_generic_write_byte
All commands switching from TRANSFER state to (receiving)DATA do the same: receive stream of data from the DAT lines. Instead of duplicating the same code many times, introduce 2 helpers: - sd_cmd_to_receivingdata() on the I/O line setup the data to be received on the data[] buffer, - sd_generic_write_byte() on the DAT lines to push the data. Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 29 + 1 file changed, 29 insertions(+) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index cd308e9a89..690a3f275e 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1100,6 +1100,22 @@ static sd_rsp_type_t sd_cmd_unimplemented(SDState *sd, SDRequest req) return sd_illegal; } +/* Configure fields for following sd_generic_write_byte() calls */ +__attribute__((unused)) +static sd_rsp_type_t sd_cmd_to_receivingdata(SDState *sd, SDRequest req, + uint64_t start, size_t size) +{ +if (sd->state != sd_transfer_state) { +return sd_invalid_state_for_cmd(sd, req); +} +sd->state = sd_receivingdata_state; +sd->data_start = start; +sd->data_offset = 0; +/* sd->data[] used as receive buffer */ +sd->data_size = size ?: sizeof(sd->data); +return sd_r1; +} + /* Configure fields for following sd_generic_read_byte() calls */ static sd_rsp_type_t sd_cmd_to_sendingdata(SDState *sd, SDRequest req, uint64_t start, @@ -1953,6 +1969,19 @@ send_response: return rsplen; } +/* Return true if buffer is consumed. Configured by sd_cmd_to_receivingdata() */ +__attribute__((unused)) +static bool sd_generic_write_byte(SDState *sd, uint8_t value) +{ +sd->data[sd->data_offset] = value; + +if (++sd->data_offset >= sd->data_size) { +sd->state = sd_transfer_state; +return true; +} +return false; +} + /* Return true when buffer is consumed. Configured by sd_cmd_to_sendingdata() */ static bool sd_generic_read_byte(SDState *sd, uint8_t *value) { -- 2.41.0
[PATCH v42 36/98] hw/sd/sdcard: Move sd_[a]cmd_name() methods to sd.c
Merge sdmmc-internal.c into sd.c by moving sd_cmd_name() and sd_acmd_name() and updating meson.build. Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sdmmc-internal.h | 26 --- hw/sd/sd.c | 62 hw/sd/sdmmc-internal.c | 72 -- hw/sd/meson.build | 2 +- 4 files changed, 63 insertions(+), 99 deletions(-) delete mode 100644 hw/sd/sdmmc-internal.c diff --git a/hw/sd/sdmmc-internal.h b/hw/sd/sdmmc-internal.h index 306ffa7f53..20d85aea6d 100644 --- a/hw/sd/sdmmc-internal.h +++ b/hw/sd/sdmmc-internal.h @@ -108,30 +108,4 @@ #define EXT_CSD_PART_CONFIG_EN_BOOT0(0x1 << 3) #define EXT_CSD_PART_CONFIG_EN_USER (0x7 << 3) -#define SDMMC_CMD_MAX 64 - -/** - * sd_cmd_name: - * @cmd: A SD "normal" command, up to SDMMC_CMD_MAX. - * - * Returns a human-readable name describing the command. - * The return value is always a static string which does not need - * to be freed after use. - * - * Returns: The command name of @cmd or "UNKNOWN_CMD". - */ -const char *sd_cmd_name(uint8_t cmd); - -/** - * sd_acmd_name: - * @cmd: A SD "Application-Specific" command, up to SDMMC_CMD_MAX. - * - * Returns a human-readable name describing the application command. - * The return value is always a static string which does not need - * to be freed after use. - * - * Returns: The application command name of @cmd or "UNKNOWN_ACMD". - */ -const char *sd_acmd_name(uint8_t cmd); - #endif diff --git a/hw/sd/sd.c b/hw/sd/sd.c index f9708064d0..93a4a4e1b4 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -88,6 +88,8 @@ enum SDCardStates { sd_disconnect_state = 8, }; +#define SDMMC_CMD_MAX 64 + typedef sd_rsp_type_t (*sd_cmd_handler)(SDState *sd, SDRequest req); typedef struct SDProto { @@ -231,6 +233,66 @@ static const char *sd_response_name(sd_rsp_type_t rsp) return response_name[rsp]; } +static const char *sd_cmd_name(uint8_t cmd) +{ +static const char *cmd_abbrev[SDMMC_CMD_MAX] = { + [0]= "GO_IDLE_STATE", [1]= "SEND_OP_COND", + [2]= "ALL_SEND_CID",[3]= "SEND_RELATIVE_ADDR", + [4]= "SET_DSR", [5]= "IO_SEND_OP_COND", + [6]= "SWITCH_FUNC", [7]= "SELECT/DESELECT_CARD", + [8]= "SEND_IF_COND",[9]= "SEND_CSD", +[10]= "SEND_CID", [11]= "VOLTAGE_SWITCH", +[12]= "STOP_TRANSMISSION", [13]= "SEND_STATUS", +[15]= "GO_INACTIVE_STATE", +[16]= "SET_BLOCKLEN", [17]= "READ_SINGLE_BLOCK", +[18]= "READ_MULTIPLE_BLOCK",[19]= "SEND_TUNING_BLOCK", +[20]= "SPEED_CLASS_CONTROL",[21]= "DPS_spec", +[23]= "SET_BLOCK_COUNT", +[24]= "WRITE_BLOCK",[25]= "WRITE_MULTIPLE_BLOCK", +[26]= "MANUF_RSVD", [27]= "PROGRAM_CSD", +[28]= "SET_WRITE_PROT", [29]= "CLR_WRITE_PROT", +[30]= "SEND_WRITE_PROT", +[32]= "ERASE_WR_BLK_START", [33]= "ERASE_WR_BLK_END", +[34]= "SW_FUNC_RSVD", [35]= "SW_FUNC_RSVD", +[36]= "SW_FUNC_RSVD", [37]= "SW_FUNC_RSVD", +[38]= "ERASE", +[40]= "DPS_spec", +[42]= "LOCK_UNLOCK",[43]= "Q_MANAGEMENT", +[44]= "Q_TASK_INFO_A", [45]= "Q_TASK_INFO_B", +[46]= "Q_RD_TASK", [47]= "Q_WR_TASK", +[48]= "READ_EXTR_SINGLE", [49]= "WRITE_EXTR_SINGLE", +[50]= "SW_FUNC_RSVD", +[52]= "IO_RW_DIRECT", [53]= "IO_RW_EXTENDED", +[54]= "SDIO_RSVD", [55]= "APP_CMD", +[56]= "GEN_CMD",[57]= "SW_FUNC_RSVD", +[58]= "READ_EXTR_MULTI",[59]= "WRITE_EXTR_MULTI", +[60]= "MANUF_RSVD", [61]= "MANUF_RSVD", +[62]= "MANUF_RSVD", [63]= "MANUF_RSVD", +}; +return cmd_abbrev[cmd] ? cmd_abbrev[cmd] : "UNKNOWN_CMD"; +} + +static const char *sd_acmd_name(uint8_t cmd) +{ +static const char *acmd_abbrev[SDMMC_CMD_MAX] = { + [6] = "SET_BUS_WIDTH", +[13] = "SD_STATUS", +[14] = "DPS_spec", [15] = "DPS_spec", +[16] = "DPS_spec", +[18] = "SECU_spec", +[22] = "SEND_NUM_WR_BLOCKS",[23] = "SET_WR_BLK_ERASE_COUNT", +[41] = "SD_SEND_OP_COND", +[42] = "SET_CLR_CARD_DETECT", +[51] = "SEND_SCR", +[52] = "SECU_spec", [53] = "SECU_spec", +[54] = "SECU_spec", +[56] = "SECU_spec", [57] = "SECU_spec", +[58] = "SECU_spec", [59] = "SECU_spec", +}; + +return acmd_abbrev[cmd] ? acmd_abbrev[
[PATCH v42 12/98] hw/sd/sdcard: Restrict SWITCH_FUNCTION to sd_transfer_state (CMD6)
SWITCH_FUNCTION is only allowed in TRANSFER state (See 4.8 "Card State Transition Table). Signed-off-by: Philippe Mathieu-Daudé Tested-by: Cédric Le Goater --- hw/sd/sd.c | 4 1 file changed, 4 insertions(+) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 7533a78cf6..8f441e418c 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1205,6 +1205,10 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) if (sd->mode != 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); +} + sd_function_switch(sd, req.arg); sd->state = sd_sendingdata_state; sd->data_start = 0; -- 2.41.0
[PATCH v42 32/98] hw/sd/sdcard: Convert PROGRAM_CID to generic_write_byte (CMD26)
From: Philippe Mathieu-Daudé Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 15 ++- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 4a03f41086..b9c72a0128 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1515,17 +1515,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) break; case 26: /* CMD26: PROGRAM_CID */ -switch (sd->state) { -case sd_transfer_state: -sd->state = sd_receivingdata_state; -sd->data_start = 0; -sd->data_offset = 0; -return sd_r1; - -default: -break; -} -break; +return sd_cmd_to_receivingdata(sd, req, 0, sizeof(sd->cid)); case 27: /* CMD27: PROGRAM_CSD */ switch (sd->state) { @@ -2088,8 +2078,7 @@ void sd_write_byte(SDState *sd, uint8_t value) break; case 26: /* CMD26: PROGRAM_CID */ -sd->data[sd->data_offset ++] = value; -if (sd->data_offset >= sizeof(sd->cid)) { +if (sd_generic_write_byte(sd, value)) { /* TODO: Check CRC before committing */ sd->state = sd_programming_state; for (i = 0; i < sizeof(sd->cid); i ++) -- 2.41.0
[PATCH v42 42/98] hw/sd/sdcard: Remove SEND_DSR dead case (CMD4)
The CSD::CSR_IMP bit defines whether the Driver Stage Register (DSR) is implemented or not. We do not set this bit in CSD: static void sd_set_csd(SDState *sd, uint64_t size) { ... if (size <= SDSC_MAX_CAPACITY) { /* Standard Capacity SD */ ... sd->csd[6] = 0xe0 | /* Partial block for read allowed */ ((csize >> 10) & 0x03); ... } else {/* SDHC */ ... sd->csd[6] = 0x00; ... } ... } The sd_normal_command() switch case for the SEND_DSR command do nothing and fallback to "illegal command". Since the command is mandatory (although the register isn't...) call the sd_cmd_unimplemented() handler. Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 14 ++ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index a816493d37..097cb0f2e2 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -240,7 +240,7 @@ static const char *sd_response_name(sd_rsp_type_t rsp) static const char *sd_cmd_name(SDState *sd, uint8_t cmd) { static const char *cmd_abbrev[SDMMC_CMD_MAX] = { - [4]= "SET_DSR", [5]= "IO_SEND_OP_COND", + [5]= "IO_SEND_OP_COND", [6]= "SWITCH_FUNC", [7]= "SELECT/DESELECT_CARD", [8]= "SEND_IF_COND",[9]= "SEND_CSD", [10]= "SEND_CID", [11]= "VOLTAGE_SWITCH", @@ -1153,7 +1153,6 @@ static sd_rsp_type_t sd_cmd_illegal(SDState *sd, SDRequest req) } /* Commands that are recognised but not yet implemented. */ -__attribute__((unused)) static sd_rsp_type_t sd_cmd_unimplemented(SDState *sd, SDRequest req) { qemu_log_mask(LOG_UNIMP, "%s: CMD%i not implemented\n", @@ -1312,16 +1311,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) switch (req.cmd) { /* Basic commands (Class 0 and Class 1) */ -case 4: /* CMD4: SEND_DSR */ -switch (sd->state) { -case sd_standby_state: -break; - -default: -break; -} -break; - case 6: /* CMD6: SWITCH_FUNCTION */ if (sd->mode != sd_data_transfer_mode) { return sd_invalid_mode_for_cmd(sd, req); @@ -2289,6 +2278,7 @@ static const SDProto sd_proto_sd = { [0] = {0, sd_bc, "GO_IDLE_STATE", sd_cmd_GO_IDLE_STATE}, [2] = {0, sd_bcr, "ALL_SEND_CID", sd_cmd_ALL_SEND_CID}, [3] = {0, sd_bcr, "SEND_RELATIVE_ADDR", sd_cmd_SEND_RELATIVE_ADDR}, +[4] = {0, sd_bc, "SEND_DSR", sd_cmd_unimplemented}, [19] = {2, sd_adtc, "SEND_TUNING_BLOCK", sd_cmd_SEND_TUNING_BLOCK}, [23] = {2, sd_ac, "SET_BLOCK_COUNT", sd_cmd_SET_BLOCK_COUNT}, }, -- 2.41.0
[PATCH v42 25/98] hw/sd/sdcard: Convert GEN_CMD to generic_read_byte (CMD56)
From: Philippe Mathieu-Daudé Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 19 +++ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index bf922da2cc..ccf81b9e59 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1648,10 +1648,12 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) switch (sd->state) { case sd_transfer_state: sd->data_offset = 0; -if (req.arg & 1) -sd->state = sd_sendingdata_state; -else -sd->state = sd_receivingdata_state; +if (req.arg & 1) { +return sd_cmd_to_sendingdata(sd, req, 0, + sd->vendor_data, + sizeof(sd->vendor_data)); +} +sd->state = sd_receivingdata_state; return sd_r1; default: @@ -2137,6 +2139,7 @@ uint8_t sd_read_byte(SDState *sd) case 17: /* CMD17: READ_SINGLE_BLOCK */ case 19: /* CMD19: SEND_TUNING_BLOCK (SD) */ case 30: /* CMD30: SEND_WRITE_PROT */ +case 56: /* CMD56: GEN_CMD */ sd_generic_read_byte(sd, &ret); break; @@ -2185,14 +2188,6 @@ uint8_t sd_read_byte(SDState *sd) sd->state = sd_transfer_state; break; -case 56: /* CMD56: GEN_CMD */ -ret = sd->vendor_data[sd->data_offset ++]; - -if (sd->data_offset >= sizeof(sd->vendor_data)) { -sd->state = sd_transfer_state; -} -break; - default: qemu_log_mask(LOG_GUEST_ERROR, "%s: unknown command\n", __func__); return 0x00; -- 2.41.0
[PATCH v42 35/98] hw/sd/sdcard: Convert GEN_CMD to generic_write_byte (CMD56)
Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 9 +++-- 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 0cb528b0b2..f9708064d0 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1657,14 +1657,12 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) case 56: /* CMD56: GEN_CMD */ switch (sd->state) { case sd_transfer_state: -sd->data_offset = 0; if (req.arg & 1) { return sd_cmd_to_sendingdata(sd, req, 0, sd->vendor_data, sizeof(sd->vendor_data)); } -sd->state = sd_receivingdata_state; -return sd_r1; +return sd_cmd_to_receivingdata(sd, req, 0, sizeof(sd->vendor_data)); default: break; @@ -2109,9 +2107,8 @@ void sd_write_byte(SDState *sd, uint8_t value) break; case 56: /* CMD56: GEN_CMD */ -sd->vendor_data[sd->data_offset ++] = value; -if (sd->data_offset >= sizeof(sd->vendor_data)) { -sd->state = sd_transfer_state; +if (sd_generic_write_byte(sd, value)) { +memcpy(sd->vendor_data, sd->data, sizeof(sd->vendor_data)); } break; -- 2.41.0
[PATCH v42 20/98] hw/sd/sdcard: Convert SEND_CSD/SEND_CID to generic_read_byte (CMD9 & 10)
From: Philippe Mathieu-Daudé Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 24 ++-- 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index f7735c39a8..8201f3245c 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1312,11 +1312,8 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) if (!sd_is_spi(sd)) { break; } -sd->state = sd_sendingdata_state; -memcpy(sd->data, sd->csd, 16); -sd->data_start = sd_req_get_address(sd, req); -sd->data_offset = 0; -return sd_r1; +return sd_cmd_to_sendingdata(sd, req, sd_req_get_address(sd, req), + sd->csd, 16); default: break; @@ -1336,11 +1333,8 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) if (!sd_is_spi(sd)) { break; } -sd->state = sd_sendingdata_state; -memcpy(sd->data, sd->cid, 16); -sd->data_start = sd_req_get_address(sd, req); -sd->data_offset = 0; -return sd_r1; +return sd_cmd_to_sendingdata(sd, req, sd_req_get_address(sd, req), + sd->cid, 16); default: break; @@ -2130,15 +2124,9 @@ uint8_t sd_read_byte(SDState *sd) sd->current_cmd, sd->data_offset, io_len); switch (sd->current_cmd) { case 6: /* CMD6: SWITCH_FUNCTION */ -sd_generic_read_byte(sd, &ret); -break; - case 9: /* CMD9: SEND_CSD */ -case 10: /* CMD10: SEND_CID */ -ret = sd->data[sd->data_offset ++]; - -if (sd->data_offset >= 16) -sd->state = sd_transfer_state; +case 10: /* CMD10: SEND_CID */ +sd_generic_read_byte(sd, &ret); break; case 13: /* ACMD13: SD_STATUS */ -- 2.41.0
[PATCH v42 40/98] hw/sd/sdcard: Store command type in SDProto
Store the command type altogether with the command handler and name. Signed-off-by: Philippe Mathieu-Daudé --- include/hw/sd/sd.h | 5 +++-- hw/sd/sd.c | 44 2 files changed, 23 insertions(+), 26 deletions(-) diff --git a/include/hw/sd/sd.h b/include/hw/sd/sd.h index 2c8748fb9b..29c76935a0 100644 --- a/include/hw/sd/sd.h +++ b/include/hw/sd/sd.h @@ -76,8 +76,9 @@ typedef enum { } sd_uhs_mode_t; typedef enum { -sd_none = -1, -sd_bc = 0, /* broadcast -- no response */ +sd_none = 0, +sd_spi, +sd_bc, /* broadcast -- no response */ sd_bcr,/* broadcast with response */ sd_ac, /* addressed -- no data transfer */ sd_adtc, /* addressed with data transfer */ diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 97fb3785ee..c4cc48926d 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -95,6 +95,7 @@ typedef sd_rsp_type_t (*sd_cmd_handler)(SDState *sd, SDRequest req); typedef struct SDProto { const char *name; struct { +const sd_cmd_type_t type; const char *name; sd_cmd_handler handler; } cmd[SDMMC_CMD_MAX], acmd[SDMMC_CMD_MAX]; @@ -351,20 +352,6 @@ static void sd_set_mode(SDState *sd) } } -static const sd_cmd_type_t sd_cmd_type[SDMMC_CMD_MAX] = { -sd_bc, sd_none, sd_bcr, sd_bcr, sd_none, sd_none, sd_none, sd_ac, -sd_bcr, sd_ac, sd_ac, sd_adtc, sd_ac, sd_ac, sd_none, sd_ac, -/* 16 */ -sd_ac, sd_adtc, sd_adtc, sd_none, sd_none, sd_none, sd_none, sd_none, -sd_adtc, sd_adtc, sd_adtc, sd_adtc, sd_ac, sd_ac, sd_adtc, sd_none, -/* 32 */ -sd_ac, sd_ac, sd_none, sd_none, sd_none, sd_none, sd_ac, sd_none, -sd_none, sd_none, sd_bc, sd_none, sd_none, sd_none, sd_none, sd_none, -/* 48 */ -sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_ac, -sd_adtc, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, -}; - static const int sd_cmd_class[SDMMC_CMD_MAX] = { 0, 0, 0, 0, 0, 9, 10, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 6, 6, 6, 6, @@ -571,10 +558,19 @@ static void sd_set_rca(SDState *sd, uint16_t value) static uint16_t sd_req_get_rca(SDState *s, SDRequest req) { -if (sd_cmd_type[req.cmd] == sd_ac || sd_cmd_type[req.cmd] == sd_adtc) { +switch (s->proto->cmd[req.cmd].type) { +case sd_none: +/* Called from legacy code not ported to SDProto array */ +assert(!s->proto->cmd[req.cmd].handler); +/* fall-through */ +case sd_ac: +case sd_adtc: return req.arg >> 16; +case sd_spi: +g_assert_not_reached(); +default: +return 0; } -return 0; } /* Card Status register */ @@ -2277,22 +2273,22 @@ void sd_enable(SDState *sd, bool enable) static const SDProto sd_proto_spi = { .name = "SPI", .cmd = { -[0] = {"GO_IDLE_STATE", sd_cmd_GO_IDLE_STATE}, -[1] = {"SEND_OP_COND", spi_cmd_SEND_OP_COND}, +[0] = {sd_spi, "GO_IDLE_STATE", sd_cmd_GO_IDLE_STATE}, +[1] = {sd_spi, "SEND_OP_COND", spi_cmd_SEND_OP_COND}, }, .acmd = { -[41] = {"SEND_OP_COND", spi_cmd_SEND_OP_COND}, +[41] = {sd_spi, "SEND_OP_COND", spi_cmd_SEND_OP_COND}, }, }; static const SDProto sd_proto_sd = { .name = "SD", .cmd = { -[0] = { "GO_IDLE_STATE", sd_cmd_GO_IDLE_STATE}, -[2] = { "ALL_SEND_CID", sd_cmd_ALL_SEND_CID}, -[3] = { "SEND_RELATIVE_ADDR", sd_cmd_SEND_RELATIVE_ADDR}, -[19] = { "SEND_TUNING_BLOCK", sd_cmd_SEND_TUNING_BLOCK}, -[23] = { "SET_BLOCK_COUNT", sd_cmd_SET_BLOCK_COUNT}, +[0] = {sd_bc, "GO_IDLE_STATE", sd_cmd_GO_IDLE_STATE}, +[2] = {sd_bcr, "ALL_SEND_CID", sd_cmd_ALL_SEND_CID}, +[3] = {sd_bcr, "SEND_RELATIVE_ADDR", sd_cmd_SEND_RELATIVE_ADDR}, +[19] = {sd_adtc, "SEND_TUNING_BLOCK", sd_cmd_SEND_TUNING_BLOCK}, +[23] = {sd_ac, "SET_BLOCK_COUNT", sd_cmd_SET_BLOCK_COUNT}, }, }; -- 2.41.0
[PATCH v42 01/98] hw/sd/sdcard: Deprecate support for spec v1.10
We use the v2.00 spec by default since commit 2f0939c234 ("sdcard: Add a 'spec_version' property, default to Spec v2.00"). Time to deprecate the v1.10 which doesn't bring much, and is not tested. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Cédric Le Goater --- docs/about/deprecated.rst | 6 ++ 1 file changed, 6 insertions(+) diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index ff3da68208..02cdef14aa 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -362,6 +362,12 @@ recommending to switch to their stable counterparts: - "Zve64f" should be replaced with "zve64f" - "Zve64d" should be replaced with "zve64d" +``-device sd-card,spec_version=1`` (since 9.1) +^^ + +SD physical layer specification v2.00 supersedes the v1.10 one. +v2.00 is the default since QEMU 3.0.0. + Block device options -- 2.41.0
[PATCH v42 19/98] hw/sd/sdcard: Convert SWITCH_FUNCTION to generic_read_byte (CMD6)
Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 12 ++-- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 1a8d06804d..f7735c39a8 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1086,7 +1086,6 @@ static sd_rsp_type_t sd_cmd_unimplemented(SDState *sd, SDRequest req) } /* Configure fields for following sd_generic_read_byte() calls */ -__attribute__((unused)) static sd_rsp_type_t sd_cmd_to_sendingdata(SDState *sd, SDRequest req, uint64_t start, const void *data, size_t size) @@ -1243,10 +1242,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) } sd_function_switch(sd, req.arg); -sd->state = sd_sendingdata_state; -sd->data_start = 0; -sd->data_offset = 0; -return sd_r1; +return sd_cmd_to_sendingdata(sd, req, 0, NULL, 64); case 7: /* CMD7: SELECT/DESELECT_CARD */ rca = sd_req_get_rca(sd, req); @@ -1946,7 +1942,6 @@ send_response: } /* Return true when buffer is consumed. Configured by sd_cmd_to_sendingdata() */ -__attribute__((unused)) static bool sd_generic_read_byte(SDState *sd, uint8_t *value) { *value = sd->data[sd->data_offset]; @@ -2135,10 +2130,7 @@ uint8_t sd_read_byte(SDState *sd) sd->current_cmd, sd->data_offset, io_len); switch (sd->current_cmd) { case 6: /* CMD6: SWITCH_FUNCTION */ -ret = sd->data[sd->data_offset ++]; - -if (sd->data_offset >= 64) -sd->state = sd_transfer_state; +sd_generic_read_byte(sd, &ret); break; case 9: /* CMD9: SEND_CSD */ -- 2.41.0
[PATCH v42 04/98] hw/sd/sdcard: Trace block offset in READ/WRITE data accesses
Useful to detect out of bound accesses. Signed-off-by: Philippe Mathieu-Daudé Tested-by: Cédric Le Goater --- hw/sd/sd.c | 4 ++-- hw/sd/trace-events | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index bc87807793..090a6fdcdb 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1917,7 +1917,7 @@ void sd_write_byte(SDState *sd, uint8_t value) trace_sdcard_write_data(sd_proto(sd)->name, sd->last_cmd_name, -sd->current_cmd, value); +sd->current_cmd, sd->data_offset, value); switch (sd->current_cmd) { case 24: /* CMD24: WRITE_SINGLE_BLOCK */ sd->data[sd->data_offset ++] = value; @@ -2073,7 +2073,7 @@ uint8_t sd_read_byte(SDState *sd) trace_sdcard_read_data(sd_proto(sd)->name, sd->last_cmd_name, - sd->current_cmd, io_len); + sd->current_cmd, sd->data_offset, io_len); switch (sd->current_cmd) { case 6: /* CMD6: SWITCH_FUNCTION */ ret = sd->data[sd->data_offset ++]; diff --git a/hw/sd/trace-events b/hw/sd/trace-events index 724365efc3..0eee98a646 100644 --- a/hw/sd/trace-events +++ b/hw/sd/trace-events @@ -52,8 +52,8 @@ sdcard_lock(void) "" sdcard_unlock(void) "" sdcard_read_block(uint64_t addr, uint32_t len) "addr 0x%" PRIx64 " size 0x%x" sdcard_write_block(uint64_t addr, uint32_t len) "addr 0x%" PRIx64 " size 0x%x" -sdcard_write_data(const char *proto, const char *cmd_desc, uint8_t cmd, uint8_t value) "%s %20s/ CMD%02d value 0x%02x" -sdcard_read_data(const char *proto, const char *cmd_desc, uint8_t cmd, uint32_t length) "%s %20s/ CMD%02d len %" PRIu32 +sdcard_write_data(const char *proto, const char *cmd_desc, uint8_t cmd, uint32_t offset, uint8_t value) "%s %20s/ CMD%02d ofs %"PRIu32" value 0x%02x" +sdcard_read_data(const char *proto, const char *cmd_desc, uint8_t cmd, uint32_t offset, uint32_t length) "%s %20s/ CMD%02d ofs %"PRIu32" len %" PRIu32 sdcard_set_voltage(uint16_t millivolts) "%u mV" # pxa2xx_mmci.c -- 2.41.0
[PATCH v42 28/98] hw/sd/sdcard: Convert SEND_SCR to generic_read_byte (ACMD51)
From: Philippe Mathieu-Daudé Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 13 ++--- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 8d02cd9a26..cd308e9a89 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1785,10 +1785,7 @@ static sd_rsp_type_t sd_app_command(SDState *sd, case 51: /* ACMD51: SEND_SCR */ switch (sd->state) { case sd_transfer_state: -sd->state = sd_sendingdata_state; -sd->data_start = 0; -sd->data_offset = 0; -return sd_r1; +return sd_cmd_to_sendingdata(sd, req, 0, sd->scr, sizeof(sd->scr)); default: break; @@ -2138,6 +2135,7 @@ uint8_t sd_read_byte(SDState *sd) case 19: /* CMD19: SEND_TUNING_BLOCK (SD) */ case 22: /* ACMD22: SEND_NUM_WR_BLOCKS */ case 30: /* CMD30: SEND_WRITE_PROT */ +case 51: /* ACMD51: SEND_SCR */ case 56: /* CMD56: GEN_CMD */ sd_generic_read_byte(sd, &ret); break; @@ -2166,13 +2164,6 @@ uint8_t sd_read_byte(SDState *sd) } break; -case 51: /* ACMD51: SEND_SCR */ -ret = sd->scr[sd->data_offset ++]; - -if (sd->data_offset >= sizeof(sd->scr)) -sd->state = sd_transfer_state; -break; - default: qemu_log_mask(LOG_GUEST_ERROR, "%s: unknown command\n", __func__); return 0x00; -- 2.41.0
[PATCH v42 44/98] hw/sd/sdcard: Register optional handlers from spec v6.00
Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 15 ++- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 74aa38a442..406fadb3b4 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -258,15 +258,11 @@ static const char *sd_cmd_name(SDState *sd, uint8_t cmd) [36]= "SW_FUNC_RSVD", [37]= "SW_FUNC_RSVD", [38]= "ERASE", [40]= "DPS_spec", -[42]= "LOCK_UNLOCK",[43]= "Q_MANAGEMENT", -[44]= "Q_TASK_INFO_A", [45]= "Q_TASK_INFO_B", -[46]= "Q_RD_TASK", [47]= "Q_WR_TASK", -[48]= "READ_EXTR_SINGLE", [49]= "WRITE_EXTR_SINGLE", +[42]= "LOCK_UNLOCK", [50]= "SW_FUNC_RSVD", [52]= "IO_RW_DIRECT", [53]= "IO_RW_EXTENDED", [54]= "SDIO_RSVD", [55]= "APP_CMD", [56]= "GEN_CMD",[57]= "SW_FUNC_RSVD", -[58]= "READ_EXTR_MULTI",[59]= "WRITE_EXTR_MULTI", [60]= "MANUF_RSVD", [61]= "MANUF_RSVD", [62]= "MANUF_RSVD", [63]= "MANUF_RSVD", }; @@ -2291,6 +2287,15 @@ static const SDProto sd_proto_sd = { [19] = {2, sd_adtc, "SEND_TUNING_BLOCK", sd_cmd_SEND_TUNING_BLOCK}, [20] = {2, sd_ac, "SPEED_CLASS_CONTROL", sd_cmd_optional}, [23] = {2, sd_ac, "SET_BLOCK_COUNT", sd_cmd_SET_BLOCK_COUNT}, +[43] = {1, sd_ac, "Q_MANAGEMENT", sd_cmd_optional}, +[44] = {1, sd_ac, "Q_TASK_INFO_A", sd_cmd_optional}, +[45] = {1, sd_ac, "Q_TASK_INFO_B", sd_cmd_optional}, +[46] = {1, sd_adtc, "Q_RD_TASK", sd_cmd_optional}, +[47] = {1, sd_adtc, "Q_WR_TASK", sd_cmd_optional}, +[48] = {1, sd_adtc, "READ_EXTR_SINGLE", sd_cmd_optional}, +[49] = {1, sd_adtc, "WRITE_EXTR_SINGLE", sd_cmd_optional}, +[58] = {11, sd_adtc, "READ_EXTR_MULTI", sd_cmd_optional}, +[59] = {11, sd_adtc, "WRITE_EXTR_MULTI", sd_cmd_optional}, }, }; -- 2.41.0
[PATCH v42 22/98] hw/sd/sdcard: Convert READ_SINGLE_BLOCK to generic_read_byte (CMD17)
From: Philippe Mathieu-Daudé Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 18 +++--- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index dfcb213aa9..605269163d 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1405,11 +1405,8 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) if (!address_in_range(sd, "READ_SINGLE_BLOCK", addr, sd->blk_len)) { return sd_r1; } - -sd->state = sd_sendingdata_state; -sd->data_start = addr; -sd->data_offset = 0; -return sd_r1; +sd_blk_read(sd, addr, sd->blk_len); +return sd_cmd_to_sendingdata(sd, req, addr, NULL, sd->blk_len); default: break; @@ -2144,6 +2141,7 @@ uint8_t sd_read_byte(SDState *sd) case 6: /* CMD6: SWITCH_FUNCTION */ case 9: /* CMD9: SEND_CSD */ case 10: /* CMD10: SEND_CID */ +case 17: /* CMD17: READ_SINGLE_BLOCK */ sd_generic_read_byte(sd, &ret); break; @@ -2154,16 +2152,6 @@ uint8_t sd_read_byte(SDState *sd) sd->state = sd_transfer_state; break; -case 17: /* CMD17: READ_SINGLE_BLOCK */ -if (sd->data_offset == 0) { -sd_blk_read(sd, sd->data_start, io_len); -} -ret = sd->data[sd->data_offset ++]; - -if (sd->data_offset >= io_len) -sd->state = sd_transfer_state; -break; - case 18: /* CMD18: READ_MULTIPLE_BLOCK */ if (sd->data_offset == 0) { if (!address_in_range(sd, "READ_MULTIPLE_BLOCK", -- 2.41.0
[PATCH v42 00/98] hw/sd/sdcard: Add eMMC support
Cédric asked for one big series to review instead of various tiny ones... I plan to send a pull request before v9.1 soft freeze with at least patches 1-81 (prerequisistes before the "Basis for eMMC support" patch) except qtest patch #15. Also available as: https://gitlab.com/philmd/qemu/-/commits/emmc-testing/ Cédric Le Goater (5): hw/sd/sdcard: Introduce definitions for EXT_CSD register hw/sd/sdcard: Add emmc_cmd_SET_RELATIVE_ADDR() handler hw/sd/sdcard: Fix SET_BLOCK_COUNT command argument on eMMC (CMD23) hw/sd/sdcard: Adapt sd_cmd_ALL_SEND_CID handler for eMMC (CMD2) hw/sd/sdcard: Adapt sd_cmd_APP_CMD handler for eMMC (CMD55) Joel Stanley (3): hw/sd/sdcard: Support boot area in emmc image hw/sd/sdcard: Subtract bootarea size from blk hw/sd/sdcard: Add boot config support Luc Michel (1): hw/sd/sdcard: Implement eMMC sleep state (CMD5) Philippe Mathieu-Daudé (85): hw/sd/sdcard: Deprecate support for spec v1.10 hw/sd/sdcard: Use spec v3.01 by default hw/sd/sdcard: Track last command used to help logging hw/sd/sdcard: Trace block offset in READ/WRITE data accesses hw/sd/sdcard: Trace requested address computed by sd_req_get_address() hw/sd/sdcard: Do not store vendor data on block drive (CMD56) hw/sd/sdcard: Send WRITE_PROT bits MSB first (CMD30) hw/sd/sdcard: Send NUM_WR_BLOCKS bits MSB first (ACMD22) hw/sd/sdcard: Use READY_FOR_DATA definition instead of magic value hw/sd/sdcard: Assign SDCardStates enum values hw/sd/sdcard: Simplify sd_inactive_state handling hw/sd/sdcard: Restrict SWITCH_FUNCTION to sd_transfer_state (CMD6) hw/sd/sdcard: Add direct reference to SDProto in SDState hw/sd/sdcard: Extract sd_blk_len() helper tests/qtest: Disable npcm7xx_sdhci tests using hardcoded RCA hw/sd/sdcard: Generate random RCA value hw/sd/sdcard: Introduce sd_cmd_to_sendingdata and sd_generic_read_byte hw/sd/sdcard: Convert SWITCH_FUNCTION to generic_read_byte (CMD6) hw/sd/sdcard: Convert SEND_CSD/SEND_CID to generic_read_byte (CMD9 & 10) hw/sd/sdcard: Duplicate READ_SINGLE_BLOCK / READ_MULTIPLE_BLOCK cases hw/sd/sdcard: Convert READ_SINGLE_BLOCK to generic_read_byte (CMD17) hw/sd/sdcard: Convert SEND_TUNING_BLOCK to generic_read_byte (CMD19) hw/sd/sdcard: Convert SEND_WRITE_PROT to generic_read_byte (CMD30) hw/sd/sdcard: Convert GEN_CMD to generic_read_byte (CMD56) hw/sd/sdcard: Convert SD_STATUS to generic_read_byte (ACMD13) hw/sd/sdcard: Convert SEND_NUM_WR_BLOCKS to generic_read_byte (ACMD22) hw/sd/sdcard: Convert SEND_SCR to generic_read_byte (ACMD51) hw/sd/sdcard: Introduce sd_cmd_to_receivingdata / sd_generic_write_byte hw/sd/sdcard: Duplicate WRITE_SINGLE_BLOCK / WRITE_MULTIPLE_BLOCK cases hw/sd/sdcard: Convert WRITE_SINGLE_BLOCK to generic_write_byte (CMD24) hw/sd/sdcard: Convert PROGRAM_CID to generic_write_byte (CMD26) hw/sd/sdcard: Convert PROGRAM_CSD to generic_write_byte (CMD27) hw/sd/sdcard: Convert LOCK_UNLOCK to generic_write_byte (CMD42) hw/sd/sdcard: Convert GEN_CMD to generic_write_byte (CMD56) hw/sd/sdcard: Move sd_[a]cmd_name() methods to sd.c hw/sd/sdcard: Pass SDState as argument to sd_[a]cmd_name() hw/sd/sdcard: Prepare SDProto to contain more fields hw/sd/sdcard: Store command name in SDProto hw/sd/sdcard: Store command type in SDProto hw/sd/sdcard: Store command class in SDProto hw/sd/sdcard: Remove SEND_DSR dead case (CMD4) hw/sd/sdcard: Register generic optional handlers (CMD11 and CMD20) hw/sd/sdcard: Register optional handlers from spec v6.00 hw/sd/sdcard: Register SDIO optional handlers hw/sd/sdcard: Register Security Extension optional handlers hw/sd/sdcard: Add sd_cmd_SWITCH_FUNCTION handler (CMD6) hw/sd/sdcard: Add sd_cmd_DE/SELECT_CARD handler (CMD7) hw/sd/sdcard: Add sd_cmd_SEND_IF_COND handler (CMD8) hw/sd/sdcard: Add sd_cmd_SEND_CSD/CID handlers (CMD9 & CMD10) hw/sd/sdcard: Add spi_cmd_SEND_CSD/CID handlers (CMD9 & CMD10) hw/sd/sdcard: Add sd_cmd_STOP_TRANSMISSION handler (CMD12) hw/sd/sdcard: Add sd_cmd_SEND_STATUS handler (CMD13) hw/sd/sdcard: Add sd_cmd_GO_INACTIVE_STATE handler (CMD15) hw/sd/sdcard: Add sd_cmd_SET_BLOCKLEN handler (CMD16) hw/sd/sdcard: Add sd_cmd_READ_SINGLE_BLOCK handler (CMD17) hw/sd/sdcard: Add sd_cmd_WRITE_SINGLE_BLOCK handler (CMD24) hw/sd/sdcard: Add sd_cmd_PROGRAM_CSD handler (CMD27) hw/sd/sdcard: Add sd_cmd_SET/CLR_WRITE_PROT handler (CMD28 & CMD29) hw/sd/sdcard: Add sd_cmd_SEND_WRITE_PROT handler (CMD30) hw/sd/sdcard: Add sd_cmd_ERASE_WR_BLK_START/END handlers (CMD32 & CMD33) hw/sd/sdcard: Add sd_cmd_ERASE handler (CMD38) hw/sd/sdcard: Add sd_cmd_LOCK_UNLOCK handler (CMD42) hw/sd/sdcard: Add sd_cmd_APP_CMD handler (CMD55) hw/sd/sdcard: Add sd_cmd_GEN_CMD handler (CMD56) hw/sd/sdcard: Add spi_cmd_READ_OCR handler (CMD58) hw/sd/sdcard: Add spi_cmd_CRC_ON_OFF handler (CMD59) hw/sd/sdcard: Add sd_acmd_SET_BUS_WIDTH handler (ACMD6) hw/sd/sdcard: Add sd_acmd_SD_STATUS handler (ACMD
[PATCH v42 30/98] hw/sd/sdcard: Duplicate WRITE_SINGLE_BLOCK / WRITE_MULTIPLE_BLOCK cases
In order to modify the WRITE_SINGLE_BLOCK case in the next commit, duplicate it first. Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 29 + 1 file changed, 29 insertions(+) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 690a3f275e..5dbfc8000b 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1461,6 +1461,35 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) /* Block write commands (Class 4) */ case 24: /* CMD24: WRITE_SINGLE_BLOCK */ +addr = sd_req_get_address(sd, req); +switch (sd->state) { +case sd_transfer_state: + +if (!address_in_range(sd, "WRITE_SINGLE_BLOCK", addr, + sd->blk_len)) { +return sd_r1; +} + +sd->state = sd_receivingdata_state; +sd->data_start = addr; +sd->data_offset = 0; + +if (sd->size <= SDSC_MAX_CAPACITY) { +if (sd_wp_addr(sd, sd->data_start)) { +sd->card_status |= WP_VIOLATION; +} +} +if (sd->csd[14] & 0x30) { +sd->card_status |= WP_VIOLATION; +} +sd->blk_written = 0; +return sd_r1; + +default: +break; +} +break; + case 25: /* CMD25: WRITE_MULTIPLE_BLOCK */ addr = sd_req_get_address(sd, req); switch (sd->state) { -- 2.41.0
[PATCH v42 26/98] hw/sd/sdcard: Convert SD_STATUS to generic_read_byte (ACMD13)
From: Philippe Mathieu-Daudé Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 15 --- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index ccf81b9e59..1c4811f410 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1703,10 +1703,9 @@ static sd_rsp_type_t sd_app_command(SDState *sd, case 13: /* ACMD13: SD_STATUS */ switch (sd->state) { case sd_transfer_state: -sd->state = sd_sendingdata_state; -sd->data_start = 0; -sd->data_offset = 0; -return sd_r1; +return sd_cmd_to_sendingdata(sd, req, 0, + sd->sd_status, + sizeof(sd->sd_status)); default: break; @@ -2136,6 +2135,7 @@ uint8_t sd_read_byte(SDState *sd) case 6: /* CMD6: SWITCH_FUNCTION */ case 9: /* CMD9: SEND_CSD */ case 10: /* CMD10: SEND_CID */ +case 13: /* ACMD13: SD_STATUS */ case 17: /* CMD17: READ_SINGLE_BLOCK */ case 19: /* CMD19: SEND_TUNING_BLOCK (SD) */ case 30: /* CMD30: SEND_WRITE_PROT */ @@ -2143,13 +2143,6 @@ uint8_t sd_read_byte(SDState *sd) sd_generic_read_byte(sd, &ret); break; -case 13: /* ACMD13: SD_STATUS */ -ret = sd->sd_status[sd->data_offset ++]; - -if (sd->data_offset >= sizeof(sd->sd_status)) -sd->state = sd_transfer_state; -break; - case 18: /* CMD18: READ_MULTIPLE_BLOCK */ if (sd->data_offset == 0) { if (!address_in_range(sd, "READ_MULTIPLE_BLOCK", -- 2.41.0
[PATCH v42 47/98] hw/sd/sdcard: Add sd_cmd_SWITCH_FUNCTION handler (CMD6)
From: Philippe Mathieu-Daudé Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 29 + 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index e4941cfdab..61c9aff2fb 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -240,7 +240,7 @@ static const char *sd_response_name(sd_rsp_type_t rsp) static const char *sd_cmd_name(SDState *sd, uint8_t cmd) { static const char *cmd_abbrev[SDMMC_CMD_MAX] = { - [6]= "SWITCH_FUNC", [7]= "SELECT/DESELECT_CARD", + [7]= "SELECT/DESELECT_CARD", [8]= "SEND_IF_COND",[9]= "SEND_CSD", [10]= "SEND_CID", [12]= "STOP_TRANSMISSION", [13]= "SEND_STATUS", @@ -1244,6 +1244,20 @@ static sd_rsp_type_t sd_cmd_SEND_RELATIVE_ADDR(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) { +return sd_invalid_mode_for_cmd(sd, req); +} +if (sd->state != sd_transfer_state) { +return sd_invalid_state_for_cmd(sd, req); +} + +sd_function_switch(sd, req.arg); +return sd_cmd_to_sendingdata(sd, req, 0, NULL, 64); +} + /* CMD19 */ static sd_rsp_type_t sd_cmd_SEND_TUNING_BLOCK(SDState *sd, SDRequest req) { @@ -1310,17 +1324,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) switch (req.cmd) { /* Basic commands (Class 0 and Class 1) */ -case 6: /* CMD6: SWITCH_FUNCTION */ -if (sd->mode != 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); -} - -sd_function_switch(sd, req.arg); -return sd_cmd_to_sendingdata(sd, req, 0, NULL, 64); - case 7: /* CMD7: SELECT/DESELECT_CARD */ rca = sd_req_get_rca(sd, req); switch (sd->state) { @@ -2266,6 +2269,7 @@ static const SDProto sd_proto_spi = { [0] = {0, sd_spi, "GO_IDLE_STATE", sd_cmd_GO_IDLE_STATE}, [1] = {0, sd_spi, "SEND_OP_COND", spi_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}, [34] = {10, sd_spi, "READ_SEC_CMD", sd_cmd_optional}, [35] = {10, sd_spi, "WRITE_SEC_CMD", sd_cmd_optional}, [36] = {10, sd_spi, "SEND_PSI", sd_cmd_optional}, @@ -2288,6 +2292,7 @@ static const SDProto sd_proto_sd = { [3] = {0, sd_bcr, "SEND_RELATIVE_ADDR", sd_cmd_SEND_RELATIVE_ADDR}, [4] = {0, sd_bc, "SEND_DSR", sd_cmd_unimplemented}, [5] = {9, sd_bc, "IO_SEND_OP_COND", sd_cmd_optional}, +[6] = {10, sd_adtc, "SWITCH_FUNCTION", sd_cmd_SWITCH_FUNCTION}, [11] = {0, sd_ac, "VOLTAGE_SWITCH", sd_cmd_optional}, [19] = {2, sd_adtc, "SEND_TUNING_BLOCK", sd_cmd_SEND_TUNING_BLOCK}, [20] = {2, sd_ac, "SPEED_CLASS_CONTROL", sd_cmd_optional}, -- 2.41.0
[PATCH v42 54/98] hw/sd/sdcard: Add sd_cmd_GO_INACTIVE_STATE handler (CMD15)
Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 37 + 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index bb80d11f87..d7ed8aee73 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -240,7 +240,6 @@ static const char *sd_response_name(sd_rsp_type_t rsp) static const char *sd_cmd_name(SDState *sd, uint8_t cmd) { static const char *cmd_abbrev[SDMMC_CMD_MAX] = { -[15]= "GO_INACTIVE_STATE", [16]= "SET_BLOCKLEN", [17]= "READ_SINGLE_BLOCK", [18]= "READ_MULTIPLE_BLOCK", [21]= "DPS_spec", @@ -1402,6 +1401,30 @@ static sd_rsp_type_t sd_cmd_SEND_STATUS(SDState *sd, SDRequest req) return sd_req_rca_same(sd, req) ? sd_r1 : sd_r0; } +/* CMD15 */ +static sd_rsp_type_t sd_cmd_GO_INACTIVE_STATE(SDState *sd, SDRequest req) +{ +if (sd->mode != sd_data_transfer_mode) { +return sd_invalid_mode_for_cmd(sd, req); +} +switch (sd->state) { +case sd_standby_state: +case sd_transfer_state: +case sd_sendingdata_state: +case sd_receivingdata_state: +case sd_programming_state: +case sd_disconnect_state: +break; +default: +return sd_invalid_state_for_cmd(sd, req); +} +if (sd_req_rca_same(sd, req)) { +sd->state = sd_inactive_state; +} + +return sd_r0; +} + /* CMD19 */ static sd_rsp_type_t sd_cmd_SEND_TUNING_BLOCK(SDState *sd, SDRequest req) { @@ -1467,17 +1490,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) } switch (req.cmd) { -/* Basic commands (Class 0 and Class 1) */ -case 15: /* CMD15: GO_INACTIVE_STATE */ -if (sd->mode != sd_data_transfer_mode) { -return sd_invalid_mode_for_cmd(sd, req); -} -rca = sd_req_get_rca(sd, req); -if (sd->rca == rca) { -sd->state = sd_inactive_state; -} -return sd_r0; - /* Block read commands (Class 2) */ case 16: /* CMD16: SET_BLOCKLEN */ switch (sd->state) { @@ -2324,6 +2336,7 @@ static const SDProto sd_proto_sd = { [11] = {0, sd_ac, "VOLTAGE_SWITCH", sd_cmd_optional}, [12] = {0, sd_ac, "STOP_TRANSMISSION", sd_cmd_STOP_TRANSMISSION}, [13] = {0, sd_ac, "SEND_STATUS", sd_cmd_SEND_STATUS}, +[15] = {0, sd_ac, "GO_INACTIVE_STATE", sd_cmd_GO_INACTIVE_STATE}, [19] = {2, sd_adtc, "SEND_TUNING_BLOCK", sd_cmd_SEND_TUNING_BLOCK}, [20] = {2, sd_ac, "SPEED_CLASS_CONTROL", sd_cmd_optional}, [23] = {2, sd_ac, "SET_BLOCK_COUNT", sd_cmd_SET_BLOCK_COUNT}, -- 2.41.0
[PATCH v42 52/98] hw/sd/sdcard: Add sd_cmd_STOP_TRANSMISSION handler (CMD12)
Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 38 -- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 564e08709b..1c092ab43c 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -240,7 +240,7 @@ static const char *sd_response_name(sd_rsp_type_t rsp) static const char *sd_cmd_name(SDState *sd, uint8_t cmd) { static const char *cmd_abbrev[SDMMC_CMD_MAX] = { -[12]= "STOP_TRANSMISSION", [13]= "SEND_STATUS", +[13]= "SEND_STATUS", [15]= "GO_INACTIVE_STATE", [16]= "SET_BLOCKLEN", [17]= "READ_SINGLE_BLOCK", [18]= "READ_MULTIPLE_BLOCK", @@ -1360,6 +1360,23 @@ static sd_rsp_type_t sd_cmd_SEND_CID(SDState *sd, SDRequest req) return sd_req_rca_same(sd, req) ? sd_r2_i : sd_r0; } +/* CMD12 */ +static sd_rsp_type_t sd_cmd_STOP_TRANSMISSION(SDState *sd, SDRequest req) +{ +switch (sd->state) { +case sd_sendingdata_state: +sd->state = sd_transfer_state; +return sd_r1b; +case sd_receivingdata_state: +sd->state = sd_programming_state; +/* Bzzztt Operation complete. */ +sd->state = sd_transfer_state; +return sd_r1; +default: +return sd_invalid_state_for_cmd(sd, req); +} +} + /* CMD19 */ static sd_rsp_type_t sd_cmd_SEND_TUNING_BLOCK(SDState *sd, SDRequest req) { @@ -1426,23 +1443,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) switch (req.cmd) { /* Basic commands (Class 0 and Class 1) */ -case 12: /* CMD12: STOP_TRANSMISSION */ -switch (sd->state) { -case sd_sendingdata_state: -sd->state = sd_transfer_state; -return sd_r1b; - -case sd_receivingdata_state: -sd->state = sd_programming_state; -/* Bzzztt Operation complete. */ -sd->state = sd_transfer_state; -return sd_r1b; - -default: -break; -} -break; - case 13: /* CMD13: SEND_STATUS */ rca = sd_req_get_rca(sd, req); if (sd->mode != sd_data_transfer_mode) { @@ -2278,6 +2278,7 @@ static const SDProto sd_proto_spi = { [8] = {0, sd_spi, "SEND_IF_COND", sd_cmd_SEND_IF_COND}, [9] = {0, sd_spi, "SEND_CSD", spi_cmd_SEND_CSD}, [10] = {0, sd_spi, "SEND_CID", spi_cmd_SEND_CID}, +[12] = {0, sd_spi, "STOP_TRANSMISSION", sd_cmd_STOP_TRANSMISSION}, [34] = {10, sd_spi, "READ_SEC_CMD", sd_cmd_optional}, [35] = {10, sd_spi, "WRITE_SEC_CMD", sd_cmd_optional}, [36] = {10, sd_spi, "SEND_PSI", sd_cmd_optional}, @@ -2306,6 +2307,7 @@ static const SDProto sd_proto_sd = { [9] = {0, sd_ac, "SEND_CSD", sd_cmd_SEND_CSD}, [10] = {0, sd_ac, "SEND_CID", sd_cmd_SEND_CID}, [11] = {0, sd_ac, "VOLTAGE_SWITCH", sd_cmd_optional}, +[12] = {0, sd_ac, "STOP_TRANSMISSION", sd_cmd_STOP_TRANSMISSION}, [19] = {2, sd_adtc, "SEND_TUNING_BLOCK", sd_cmd_SEND_TUNING_BLOCK}, [20] = {2, sd_ac, "SPEED_CLASS_CONTROL", sd_cmd_optional}, [23] = {2, sd_ac, "SET_BLOCK_COUNT", sd_cmd_SET_BLOCK_COUNT}, -- 2.41.0
[PATCH v42 31/98] hw/sd/sdcard: Convert WRITE_SINGLE_BLOCK to generic_write_byte (CMD24)
From: Philippe Mathieu-Daudé Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 11 ++- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 5dbfc8000b..4a03f41086 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1101,7 +1101,6 @@ static sd_rsp_type_t sd_cmd_unimplemented(SDState *sd, SDRequest req) } /* Configure fields for following sd_generic_write_byte() calls */ -__attribute__((unused)) static sd_rsp_type_t sd_cmd_to_receivingdata(SDState *sd, SDRequest req, uint64_t start, size_t size) { @@ -1470,10 +1469,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) return sd_r1; } -sd->state = sd_receivingdata_state; -sd->data_start = addr; -sd->data_offset = 0; - if (sd->size <= SDSC_MAX_CAPACITY) { if (sd_wp_addr(sd, sd->data_start)) { sd->card_status |= WP_VIOLATION; @@ -1483,7 +1478,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) sd->card_status |= WP_VIOLATION; } sd->blk_written = 0; -return sd_r1; +return sd_cmd_to_receivingdata(sd, req, addr, sd->blk_len); default: break; @@ -1999,7 +1994,6 @@ send_response: } /* Return true if buffer is consumed. Configured by sd_cmd_to_receivingdata() */ -__attribute__((unused)) static bool sd_generic_write_byte(SDState *sd, uint8_t value) { sd->data[sd->data_offset] = value; @@ -2045,8 +2039,7 @@ void sd_write_byte(SDState *sd, uint8_t value) sd->current_cmd, sd->data_offset, value); switch (sd->current_cmd) { case 24: /* CMD24: WRITE_SINGLE_BLOCK */ -sd->data[sd->data_offset ++] = value; -if (sd->data_offset >= sd->blk_len) { +if (sd_generic_write_byte(sd, value)) { /* TODO: Check CRC before committing */ sd->state = sd_programming_state; sd_blk_write(sd, sd->data_start, sd->data_offset); -- 2.41.0
[PATCH v42 46/98] hw/sd/sdcard: Register Security Extension optional handlers
See "Advanced Security SD Extension Specification" v2.00. Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 17 + 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 87bfd0fd56..e4941cfdab 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -253,14 +253,11 @@ static const char *sd_cmd_name(SDState *sd, uint8_t cmd) [28]= "SET_WRITE_PROT", [29]= "CLR_WRITE_PROT", [30]= "SEND_WRITE_PROT", [32]= "ERASE_WR_BLK_START", [33]= "ERASE_WR_BLK_END", -[34]= "SW_FUNC_RSVD", [35]= "SW_FUNC_RSVD", -[36]= "SW_FUNC_RSVD", [37]= "SW_FUNC_RSVD", [38]= "ERASE", [40]= "DPS_spec", [42]= "LOCK_UNLOCK", -[50]= "SW_FUNC_RSVD", [54]= "SDIO_RSVD", [55]= "APP_CMD", -[56]= "GEN_CMD",[57]= "SW_FUNC_RSVD", +[56]= "GEN_CMD", [60]= "MANUF_RSVD", [61]= "MANUF_RSVD", [62]= "MANUF_RSVD", [63]= "MANUF_RSVD", }; @@ -2269,8 +2266,14 @@ static const SDProto sd_proto_spi = { [0] = {0, sd_spi, "GO_IDLE_STATE", sd_cmd_GO_IDLE_STATE}, [1] = {0, sd_spi, "SEND_OP_COND", spi_cmd_SEND_OP_COND}, [5] = {9, sd_spi, "IO_SEND_OP_COND", sd_cmd_optional}, +[34] = {10, sd_spi, "READ_SEC_CMD", sd_cmd_optional}, +[35] = {10, sd_spi, "WRITE_SEC_CMD", sd_cmd_optional}, +[36] = {10, sd_spi, "SEND_PSI", sd_cmd_optional}, +[37] = {10, sd_spi, "CONTROL_ASSD_SYSTEM", sd_cmd_optional}, +[50] = {10, sd_spi, "DIRECT_SECURE_READ", sd_cmd_optional}, [52] = {9, sd_spi, "IO_RW_DIRECT", sd_cmd_optional}, [53] = {9, sd_spi, "IO_RW_EXTENDED", sd_cmd_optional}, +[57] = {10, sd_spi, "DIRECT_SECURE_WRITE", sd_cmd_optional}, }, .acmd = { [41] = {8, sd_spi, "SEND_OP_COND", spi_cmd_SEND_OP_COND}, @@ -2289,6 +2292,10 @@ static const SDProto sd_proto_sd = { [19] = {2, sd_adtc, "SEND_TUNING_BLOCK", sd_cmd_SEND_TUNING_BLOCK}, [20] = {2, sd_ac, "SPEED_CLASS_CONTROL", sd_cmd_optional}, [23] = {2, sd_ac, "SET_BLOCK_COUNT", sd_cmd_SET_BLOCK_COUNT}, +[34] = {10, sd_adtc, "READ_SEC_CMD", sd_cmd_optional}, +[35] = {10, sd_adtc, "WRITE_SEC_CMD", sd_cmd_optional}, +[36] = {10, sd_adtc, "SEND_PSI", sd_cmd_optional}, +[37] = {10, sd_ac, "CONTROL_ASSD_SYSTEM", sd_cmd_optional}, [43] = {1, sd_ac, "Q_MANAGEMENT", sd_cmd_optional}, [44] = {1, sd_ac, "Q_TASK_INFO_A", sd_cmd_optional}, [45] = {1, sd_ac, "Q_TASK_INFO_B", sd_cmd_optional}, @@ -2296,8 +2303,10 @@ static const SDProto sd_proto_sd = { [47] = {1, sd_adtc, "Q_WR_TASK", sd_cmd_optional}, [48] = {1, sd_adtc, "READ_EXTR_SINGLE", sd_cmd_optional}, [49] = {1, sd_adtc, "WRITE_EXTR_SINGLE", sd_cmd_optional}, +[50] = {10, sd_adtc, "DIRECT_SECURE_READ", sd_cmd_optional}, [52] = {9, sd_bc, "IO_RW_DIRECT", sd_cmd_optional}, [53] = {9, sd_bc, "IO_RW_EXTENDED", sd_cmd_optional}, +[57] = {10, sd_adtc, "DIRECT_SECURE_WRITE", sd_cmd_optional}, [58] = {11, sd_adtc, "READ_EXTR_MULTI", sd_cmd_optional}, [59] = {11, sd_adtc, "WRITE_EXTR_MULTI", sd_cmd_optional}, }, -- 2.41.0
[PATCH v42 41/98] hw/sd/sdcard: Store command class in SDProto
Store the command class altogether with the other command fields (handler, name and type). Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 36 +++- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index c4cc48926d..a816493d37 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -95,6 +95,7 @@ typedef sd_rsp_type_t (*sd_cmd_handler)(SDState *sd, SDRequest req); typedef struct SDProto { const char *name; struct { +const unsigned class; const sd_cmd_type_t type; const char *name; sd_cmd_handler handler; @@ -352,13 +353,6 @@ static void sd_set_mode(SDState *sd) } } -static const int sd_cmd_class[SDMMC_CMD_MAX] = { -0, 0, 0, 0, 0, 9, 10, 0, 0, 0, 0, 1, 0, 0, 0, 0, -2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 6, 6, 6, 6, -5, 5, 10, 10, 10, 10, 5, 9, 9, 9, 7, 7, 7, 7, 7, 7, -7, 7, 10, 7, 9, 9, 9, 8, 8, 10, 8, 8, 8, 8, 8, 8, -}; - static uint8_t sd_crc7(const void *message, size_t width) { int i, bit; @@ -1306,7 +1300,8 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) sd->multi_blk_cnt = 0; } -if (sd_cmd_class[req.cmd] == 6 && FIELD_EX32(sd->ocr, OCR, CARD_CAPACITY)) { +if (sd->proto->cmd[req.cmd].class == 6 && FIELD_EX32(sd->ocr, OCR, + CARD_CAPACITY)) { /* Only Standard Capacity cards support class 6 commands */ return sd_illegal; } @@ -1891,6 +1886,8 @@ static sd_rsp_type_t sd_app_command(SDState *sd, static bool cmd_valid_while_locked(SDState *sd, unsigned cmd) { +unsigned cmd_class; + /* Valid commands in locked state: * basic class (0) * lock card class (7) @@ -1905,7 +1902,12 @@ static bool cmd_valid_while_locked(SDState *sd, unsigned cmd) if (cmd == 16 || cmd == 55) { return true; } -return sd_cmd_class[cmd] == 0 || sd_cmd_class[cmd] == 7; +if (!sd->proto->cmd[cmd].handler) { +return false; +} +cmd_class = sd->proto->cmd[cmd].class; + +return cmd_class == 0 || cmd_class == 7; } int sd_do_command(SDState *sd, SDRequest *req, @@ -2273,22 +2275,22 @@ void sd_enable(SDState *sd, bool enable) static const SDProto sd_proto_spi = { .name = "SPI", .cmd = { -[0] = {sd_spi, "GO_IDLE_STATE", sd_cmd_GO_IDLE_STATE}, -[1] = {sd_spi, "SEND_OP_COND", spi_cmd_SEND_OP_COND}, +[0] = {0, sd_spi, "GO_IDLE_STATE", sd_cmd_GO_IDLE_STATE}, +[1] = {0, sd_spi, "SEND_OP_COND", spi_cmd_SEND_OP_COND}, }, .acmd = { -[41] = {sd_spi, "SEND_OP_COND", spi_cmd_SEND_OP_COND}, +[41] = {8, sd_spi, "SEND_OP_COND", spi_cmd_SEND_OP_COND}, }, }; static const SDProto sd_proto_sd = { .name = "SD", .cmd = { -[0] = {sd_bc, "GO_IDLE_STATE", sd_cmd_GO_IDLE_STATE}, -[2] = {sd_bcr, "ALL_SEND_CID", sd_cmd_ALL_SEND_CID}, -[3] = {sd_bcr, "SEND_RELATIVE_ADDR", sd_cmd_SEND_RELATIVE_ADDR}, -[19] = {sd_adtc, "SEND_TUNING_BLOCK", sd_cmd_SEND_TUNING_BLOCK}, -[23] = {sd_ac, "SET_BLOCK_COUNT", sd_cmd_SET_BLOCK_COUNT}, +[0] = {0, sd_bc, "GO_IDLE_STATE", sd_cmd_GO_IDLE_STATE}, +[2] = {0, sd_bcr, "ALL_SEND_CID", sd_cmd_ALL_SEND_CID}, +[3] = {0, sd_bcr, "SEND_RELATIVE_ADDR", sd_cmd_SEND_RELATIVE_ADDR}, +[19] = {2, sd_adtc, "SEND_TUNING_BLOCK", sd_cmd_SEND_TUNING_BLOCK}, +[23] = {2, sd_ac, "SET_BLOCK_COUNT", sd_cmd_SET_BLOCK_COUNT}, }, }; -- 2.41.0
[PATCH v42 51/98] hw/sd/sdcard: Add spi_cmd_SEND_CSD/CID handlers (CMD9 & CMD10)
Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 50 -- 1 file changed, 20 insertions(+), 30 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index bd7c7cf518..564e08709b 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1323,6 +1323,15 @@ static sd_rsp_type_t sd_cmd_SEND_IF_COND(SDState *sd, SDRequest req) } /* CMD9 */ +static sd_rsp_type_t spi_cmd_SEND_CSD(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->csd, 16); +} + static sd_rsp_type_t sd_cmd_SEND_CSD(SDState *sd, SDRequest req) { if (sd->state != sd_standby_state) { @@ -1333,6 +1342,15 @@ 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); +} + static sd_rsp_type_t sd_cmd_SEND_CID(SDState *sd, SDRequest req) { if (sd->state != sd_standby_state) { @@ -1408,36 +1426,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) switch (req.cmd) { /* Basic commands (Class 0 and Class 1) */ -case 9: /* CMD9: SEND_CSD */ -rca = sd_req_get_rca(sd, req); -switch (sd->state) { -case sd_transfer_state: -if (!sd_is_spi(sd)) { -break; -} -return sd_cmd_to_sendingdata(sd, req, sd_req_get_address(sd, req), - sd->csd, 16); - -default: -break; -} -break; - -case 10: /* CMD10: SEND_CID */ -rca = sd_req_get_rca(sd, req); -switch (sd->state) { -case sd_transfer_state: -if (!sd_is_spi(sd)) { -break; -} -return sd_cmd_to_sendingdata(sd, req, sd_req_get_address(sd, req), - sd->cid, 16); - -default: -break; -} -break; - case 12: /* CMD12: STOP_TRANSMISSION */ switch (sd->state) { case sd_sendingdata_state: @@ -2288,6 +2276,8 @@ static const SDProto sd_proto_spi = { [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}, +[9] = {0, sd_spi, "SEND_CSD", spi_cmd_SEND_CSD}, +[10] = {0, sd_spi, "SEND_CID", spi_cmd_SEND_CID}, [34] = {10, sd_spi, "READ_SEC_CMD", sd_cmd_optional}, [35] = {10, sd_spi, "WRITE_SEC_CMD", sd_cmd_optional}, [36] = {10, sd_spi, "SEND_PSI", sd_cmd_optional}, -- 2.41.0
[PATCH v42 43/98] hw/sd/sdcard: Register generic optional handlers (CMD11 and CMD20)
Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 14 -- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 097cb0f2e2..74aa38a442 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -243,12 +243,12 @@ static const char *sd_cmd_name(SDState *sd, uint8_t cmd) [5]= "IO_SEND_OP_COND", [6]= "SWITCH_FUNC", [7]= "SELECT/DESELECT_CARD", [8]= "SEND_IF_COND",[9]= "SEND_CSD", -[10]= "SEND_CID", [11]= "VOLTAGE_SWITCH", +[10]= "SEND_CID", [12]= "STOP_TRANSMISSION", [13]= "SEND_STATUS", [15]= "GO_INACTIVE_STATE", [16]= "SET_BLOCKLEN", [17]= "READ_SINGLE_BLOCK", [18]= "READ_MULTIPLE_BLOCK", -[20]= "SPEED_CLASS_CONTROL",[21]= "DPS_spec", +[21]= "DPS_spec", [24]= "WRITE_BLOCK",[25]= "WRITE_MULTIPLE_BLOCK", [26]= "MANUF_RSVD", [27]= "PROGRAM_CSD", [28]= "SET_WRITE_PROT", [29]= "CLR_WRITE_PROT", @@ -1161,6 +1161,14 @@ static sd_rsp_type_t sd_cmd_unimplemented(SDState *sd, SDRequest req) return sd_illegal; } +static sd_rsp_type_t sd_cmd_optional(SDState *sd, SDRequest req) +{ +qemu_log_mask(LOG_UNIMP, "%s: Optional CMD%i not implemented\n", + sd->proto->name, req.cmd); + +return sd_illegal; +} + /* Configure fields for following sd_generic_write_byte() calls */ static sd_rsp_type_t sd_cmd_to_receivingdata(SDState *sd, SDRequest req, uint64_t start, size_t size) @@ -2279,7 +2287,9 @@ static const SDProto sd_proto_sd = { [2] = {0, sd_bcr, "ALL_SEND_CID", sd_cmd_ALL_SEND_CID}, [3] = {0, sd_bcr, "SEND_RELATIVE_ADDR", sd_cmd_SEND_RELATIVE_ADDR}, [4] = {0, sd_bc, "SEND_DSR", sd_cmd_unimplemented}, +[11] = {0, sd_ac, "VOLTAGE_SWITCH", sd_cmd_optional}, [19] = {2, sd_adtc, "SEND_TUNING_BLOCK", sd_cmd_SEND_TUNING_BLOCK}, +[20] = {2, sd_ac, "SPEED_CLASS_CONTROL", sd_cmd_optional}, [23] = {2, sd_ac, "SET_BLOCK_COUNT", sd_cmd_SET_BLOCK_COUNT}, }, }; -- 2.41.0
[PATCH v42 33/98] hw/sd/sdcard: Convert PROGRAM_CSD to generic_write_byte (CMD27)
Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 15 ++- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index b9c72a0128..bdd5f3486a 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1518,17 +1518,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) return sd_cmd_to_receivingdata(sd, req, 0, sizeof(sd->cid)); case 27: /* CMD27: PROGRAM_CSD */ -switch (sd->state) { -case sd_transfer_state: -sd->state = sd_receivingdata_state; -sd->data_start = 0; -sd->data_offset = 0; -return sd_r1; - -default: -break; -} -break; +return sd_cmd_to_receivingdata(sd, req, 0, sizeof(sd->csd)); /* Write protection (Class 6) */ case 28: /* CMD28: SET_WRITE_PROT */ @@ -2096,8 +2086,7 @@ void sd_write_byte(SDState *sd, uint8_t value) break; case 27: /* CMD27: PROGRAM_CSD */ -sd->data[sd->data_offset ++] = value; -if (sd->data_offset >= sizeof(sd->csd)) { +if (sd_generic_write_byte(sd, value)) { /* TODO: Check CRC before committing */ sd->state = sd_programming_state; for (i = 0; i < sizeof(sd->csd); i ++) -- 2.41.0
[PATCH v42 55/98] hw/sd/sdcard: Add sd_cmd_SET_BLOCKLEN handler (CMD16)
Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 37 +++-- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index d7ed8aee73..d731c3df58 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -240,7 +240,7 @@ static const char *sd_response_name(sd_rsp_type_t rsp) static const char *sd_cmd_name(SDState *sd, uint8_t cmd) { static const char *cmd_abbrev[SDMMC_CMD_MAX] = { -[16]= "SET_BLOCKLEN", [17]= "READ_SINGLE_BLOCK", +[17]= "READ_SINGLE_BLOCK", [18]= "READ_MULTIPLE_BLOCK", [21]= "DPS_spec", [24]= "WRITE_BLOCK",[25]= "WRITE_MULTIPLE_BLOCK", @@ -1425,6 +1425,22 @@ static sd_rsp_type_t sd_cmd_GO_INACTIVE_STATE(SDState *sd, SDRequest req) return sd_r0; } +/* CMD16 */ +static sd_rsp_type_t sd_cmd_SET_BLOCKLEN(SDState *sd, SDRequest req) +{ +if (sd->state != sd_transfer_state) { +return sd_invalid_state_for_cmd(sd, req); +} +if (req.arg > (1 << HWBLOCK_SHIFT)) { +sd->card_status |= BLOCK_LEN_ERROR; +} else { +trace_sdcard_set_blocklen(req.arg); +sd->blk_len = req.arg; +} + +return sd_r1; +} + /* CMD19 */ static sd_rsp_type_t sd_cmd_SEND_TUNING_BLOCK(SDState *sd, SDRequest req) { @@ -1491,23 +1507,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) switch (req.cmd) { /* Block read commands (Class 2) */ -case 16: /* CMD16: SET_BLOCKLEN */ -switch (sd->state) { -case sd_transfer_state: -if (req.arg > (1 << HWBLOCK_SHIFT)) { -sd->card_status |= BLOCK_LEN_ERROR; -} else { -trace_sdcard_set_blocklen(req.arg); -sd->blk_len = req.arg; -} - -return sd_r1; - -default: -break; -} -break; - case 17: /* CMD17: READ_SINGLE_BLOCK */ addr = sd_req_get_address(sd, req); switch (sd->state) { @@ -2306,6 +2305,7 @@ static const SDProto sd_proto_spi = { [10] = {0, sd_spi, "SEND_CID", spi_cmd_SEND_CID}, [12] = {0, sd_spi, "STOP_TRANSMISSION", sd_cmd_STOP_TRANSMISSION}, [13] = {0, sd_spi, "SEND_STATUS", sd_cmd_SEND_STATUS}, +[16] = {2, sd_spi, "SET_BLOCKLEN", sd_cmd_SET_BLOCKLEN}, [34] = {10, sd_spi, "READ_SEC_CMD", sd_cmd_optional}, [35] = {10, sd_spi, "WRITE_SEC_CMD", sd_cmd_optional}, [36] = {10, sd_spi, "SEND_PSI", sd_cmd_optional}, @@ -2337,6 +2337,7 @@ static const SDProto sd_proto_sd = { [12] = {0, sd_ac, "STOP_TRANSMISSION", sd_cmd_STOP_TRANSMISSION}, [13] = {0, sd_ac, "SEND_STATUS", sd_cmd_SEND_STATUS}, [15] = {0, sd_ac, "GO_INACTIVE_STATE", sd_cmd_GO_INACTIVE_STATE}, +[16] = {2, sd_ac, "SET_BLOCKLEN", sd_cmd_SET_BLOCKLEN}, [19] = {2, sd_adtc, "SEND_TUNING_BLOCK", sd_cmd_SEND_TUNING_BLOCK}, [20] = {2, sd_ac, "SPEED_CLASS_CONTROL", sd_cmd_optional}, [23] = {2, sd_ac, "SET_BLOCK_COUNT", sd_cmd_SET_BLOCK_COUNT}, -- 2.41.0
[PATCH v42 63/98] hw/sd/sdcard: Add sd_cmd_LOCK_UNLOCK handler (CMD42)
Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 13 - 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 17fec612eb..4d78ac5b59 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -245,7 +245,6 @@ static const char *sd_cmd_name(SDState *sd, uint8_t cmd) [25]= "WRITE_MULTIPLE_BLOCK", [26]= "MANUF_RSVD", [40]= "DPS_spec", -[42]= "LOCK_UNLOCK", [54]= "SDIO_RSVD", [55]= "APP_CMD", [56]= "GEN_CMD", [60]= "MANUF_RSVD", [61]= "MANUF_RSVD", @@ -1619,6 +1618,12 @@ static sd_rsp_type_t sd_cmd_ERASE(SDState *sd, SDRequest req) return sd_r1b; } +/* CMD42 */ +static sd_rsp_type_t sd_cmd_LOCK_UNLOCK(SDState *sd, SDRequest req) +{ +return sd_cmd_to_receivingdata(sd, req, 0, 0); +} + static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) { uint16_t rca; @@ -1707,10 +1712,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) case 26: /* CMD26: PROGRAM_CID */ return sd_cmd_to_receivingdata(sd, req, 0, sizeof(sd->cid)); -/* Lock card commands (Class 7) */ -case 42: /* CMD42: LOCK_UNLOCK */ -return sd_cmd_to_receivingdata(sd, req, 0, 0); - /* Application specific commands (Class 8) */ case 55: /* CMD55: APP_CMD */ rca = sd_req_get_rca(sd, req); @@ -2316,6 +2317,7 @@ static const SDProto sd_proto_spi = { [36] = {10, sd_spi, "SEND_PSI", sd_cmd_optional}, [37] = {10, sd_spi, "CONTROL_ASSD_SYSTEM", sd_cmd_optional}, [38] = {5, sd_spi, "ERASE", sd_cmd_ERASE}, +[42] = {7, sd_spi, "LOCK_UNLOCK", sd_cmd_LOCK_UNLOCK}, [50] = {10, sd_spi, "DIRECT_SECURE_READ", sd_cmd_optional}, [52] = {9, sd_spi, "IO_RW_DIRECT", sd_cmd_optional}, [53] = {9, sd_spi, "IO_RW_EXTENDED", sd_cmd_optional}, @@ -2360,6 +2362,7 @@ static const SDProto sd_proto_sd = { [36] = {10, sd_adtc, "SEND_PSI", sd_cmd_optional}, [37] = {10, sd_ac, "CONTROL_ASSD_SYSTEM", sd_cmd_optional}, [38] = {5, sd_ac, "ERASE", sd_cmd_ERASE}, +[42] = {7, sd_adtc, "LOCK_UNLOCK", sd_cmd_LOCK_UNLOCK}, [43] = {1, sd_ac, "Q_MANAGEMENT", sd_cmd_optional}, [44] = {1, sd_ac, "Q_TASK_INFO_A", sd_cmd_optional}, [45] = {1, sd_ac, "Q_TASK_INFO_B", sd_cmd_optional}, -- 2.41.0
[PATCH v42 64/98] hw/sd/sdcard: Add sd_cmd_APP_CMD handler (CMD55)
Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 53 - 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 4d78ac5b59..5461e56e17 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -245,7 +245,6 @@ static const char *sd_cmd_name(SDState *sd, uint8_t cmd) [25]= "WRITE_MULTIPLE_BLOCK", [26]= "MANUF_RSVD", [40]= "DPS_spec", -[54]= "SDIO_RSVD", [55]= "APP_CMD", [56]= "GEN_CMD", [60]= "MANUF_RSVD", [61]= "MANUF_RSVD", [62]= "MANUF_RSVD", [63]= "MANUF_RSVD", @@ -1624,9 +1623,34 @@ static sd_rsp_type_t sd_cmd_LOCK_UNLOCK(SDState *sd, SDRequest req) return sd_cmd_to_receivingdata(sd, req, 0, 0); } +/* CMD55 */ +static sd_rsp_type_t sd_cmd_APP_CMD(SDState *sd, SDRequest req) +{ +switch (sd->state) { +case sd_ready_state: +case sd_identification_state: +case sd_inactive_state: +return sd_invalid_state_for_cmd(sd, req); +case sd_idle_state: +if (!sd_is_spi(sd) && sd_req_get_rca(sd, req) != 0x) { +qemu_log_mask(LOG_GUEST_ERROR, + "SD: illegal RCA 0x%04x for APP_CMD\n", req.cmd); +} +/* fall-through */ +default: +break; +} +if (!sd_is_spi(sd) && !sd_req_rca_same(sd, req)) { +return sd_r0; +} +sd->expecting_acmd = true; +sd->card_status |= APP_CMD; + +return sd_r1; +} + static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) { -uint16_t rca; uint64_t addr; sd->last_cmd_name = sd_cmd_name(sd, req.cmd); @@ -1713,29 +1737,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) return sd_cmd_to_receivingdata(sd, req, 0, sizeof(sd->cid)); /* Application specific commands (Class 8) */ -case 55: /* CMD55: APP_CMD */ -rca = sd_req_get_rca(sd, req); -switch (sd->state) { -case sd_ready_state: -case sd_identification_state: -return sd_illegal; -case sd_idle_state: -if (rca) { -qemu_log_mask(LOG_GUEST_ERROR, - "SD: illegal RCA 0x%04x for APP_CMD\n", req.cmd); -} -default: -break; -} -if (!sd_is_spi(sd)) { -if (sd->rca != rca) { -return sd_r0; -} -} -sd->expecting_acmd = true; -sd->card_status |= APP_CMD; -return sd_r1; - case 56: /* CMD56: GEN_CMD */ switch (sd->state) { case sd_transfer_state: @@ -2321,6 +2322,7 @@ static const SDProto sd_proto_spi = { [50] = {10, sd_spi, "DIRECT_SECURE_READ", sd_cmd_optional}, [52] = {9, sd_spi, "IO_RW_DIRECT", sd_cmd_optional}, [53] = {9, sd_spi, "IO_RW_EXTENDED", sd_cmd_optional}, +[55] = {8, sd_spi, "APP_CMD", sd_cmd_APP_CMD}, [57] = {10, sd_spi, "DIRECT_SECURE_WRITE", sd_cmd_optional}, }, .acmd = { @@ -2373,6 +2375,7 @@ static const SDProto sd_proto_sd = { [50] = {10, sd_adtc, "DIRECT_SECURE_READ", sd_cmd_optional}, [52] = {9, sd_bc, "IO_RW_DIRECT", sd_cmd_optional}, [53] = {9, sd_bc, "IO_RW_EXTENDED", sd_cmd_optional}, +[55] = {8, sd_ac, "APP_CMD", sd_cmd_APP_CMD}, [57] = {10, sd_adtc, "DIRECT_SECURE_WRITE", sd_cmd_optional}, [58] = {11, sd_adtc, "READ_EXTR_MULTI", sd_cmd_optional}, [59] = {11, sd_adtc, "WRITE_EXTR_MULTI", sd_cmd_optional}, -- 2.41.0
[PATCH v42 24/98] hw/sd/sdcard: Convert SEND_WRITE_PROT to generic_read_byte (CMD30)
Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 17 - 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index eece33194a..bf922da2cc 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1202,6 +1202,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) { uint16_t rca; uint64_t addr; +uint32_t data; sd->last_cmd_name = sd_cmd_name(req.cmd); /* CMD55 precedes an ACMD, so we are not interested in tracing it. @@ -1555,12 +1556,8 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) req.arg, sd->blk_len)) { return sd_r1; } - -sd->state = sd_sendingdata_state; -stl_be_p(sd->data, sd_wpbits(sd, req.arg)); -sd->data_start = addr; -sd->data_offset = 0; -return sd_r1; +data = sd_wpbits(sd, req.arg); +return sd_cmd_to_sendingdata(sd, req, addr, &data, sizeof(data)); default: break; @@ -2139,6 +2136,7 @@ uint8_t sd_read_byte(SDState *sd) case 10: /* CMD10: SEND_CID */ case 17: /* CMD17: READ_SINGLE_BLOCK */ case 19: /* CMD19: SEND_TUNING_BLOCK (SD) */ +case 30: /* CMD30: SEND_WRITE_PROT */ sd_generic_read_byte(sd, &ret); break; @@ -2180,13 +2178,6 @@ uint8_t sd_read_byte(SDState *sd) sd->state = sd_transfer_state; break; -case 30: /* CMD30: SEND_WRITE_PROT */ -ret = sd->data[sd->data_offset ++]; - -if (sd->data_offset >= 4) -sd->state = sd_transfer_state; -break; - case 51: /* ACMD51: SEND_SCR */ ret = sd->scr[sd->data_offset ++]; -- 2.41.0
[PATCH v42 50/98] hw/sd/sdcard: Add sd_cmd_SEND_CSD/CID handlers (CMD9 & CMD10)
Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 36 ++-- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index e2f7e99ea2..bd7c7cf518 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -240,8 +240,6 @@ static const char *sd_response_name(sd_rsp_type_t rsp) static const char *sd_cmd_name(SDState *sd, uint8_t cmd) { static const char *cmd_abbrev[SDMMC_CMD_MAX] = { - [9]= "SEND_CSD", -[10]= "SEND_CID", [12]= "STOP_TRANSMISSION", [13]= "SEND_STATUS", [15]= "GO_INACTIVE_STATE", [16]= "SET_BLOCKLEN", [17]= "READ_SINGLE_BLOCK", @@ -1324,6 +1322,26 @@ static sd_rsp_type_t sd_cmd_SEND_IF_COND(SDState *sd, SDRequest req) return sd_r7; } +/* CMD9 */ +static sd_rsp_type_t sd_cmd_SEND_CSD(SDState *sd, SDRequest req) +{ +if (sd->state != sd_standby_state) { +return sd_invalid_state_for_cmd(sd, req); +} + +return sd_req_rca_same(sd, req) ? sd_r2_s : sd_r0; +} + +/* CMD10 */ +static sd_rsp_type_t sd_cmd_SEND_CID(SDState *sd, SDRequest req) +{ +if (sd->state != sd_standby_state) { +return sd_invalid_state_for_cmd(sd, req); +} + +return sd_req_rca_same(sd, req) ? sd_r2_i : sd_r0; +} + /* CMD19 */ static sd_rsp_type_t sd_cmd_SEND_TUNING_BLOCK(SDState *sd, SDRequest req) { @@ -1393,12 +1411,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) case 9: /* CMD9: SEND_CSD */ rca = sd_req_get_rca(sd, req); switch (sd->state) { -case sd_standby_state: -if (sd->rca != rca) -return sd_r0; - -return sd_r2_s; - case sd_transfer_state: if (!sd_is_spi(sd)) { break; @@ -1414,12 +1426,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) case 10: /* CMD10: SEND_CID */ rca = sd_req_get_rca(sd, req); switch (sd->state) { -case sd_standby_state: -if (sd->rca != rca) -return sd_r0; - -return sd_r2_i; - case sd_transfer_state: if (!sd_is_spi(sd)) { break; @@ -2307,6 +2313,8 @@ static const SDProto sd_proto_sd = { [6] = {10, sd_adtc, "SWITCH_FUNCTION", sd_cmd_SWITCH_FUNCTION}, [7] = {0, sd_ac, "(DE)SELECT_CARD", sd_cmd_DE_SELECT_CARD}, [8] = {0, sd_bcr, "SEND_IF_COND", sd_cmd_SEND_IF_COND}, +[9] = {0, sd_ac, "SEND_CSD", sd_cmd_SEND_CSD}, +[10] = {0, sd_ac, "SEND_CID", sd_cmd_SEND_CID}, [11] = {0, sd_ac, "VOLTAGE_SWITCH", sd_cmd_optional}, [19] = {2, sd_adtc, "SEND_TUNING_BLOCK", sd_cmd_SEND_TUNING_BLOCK}, [20] = {2, sd_ac, "SPEED_CLASS_CONTROL", sd_cmd_optional}, -- 2.41.0
[PATCH v42 83/98] hw/sd/sdcard: Register generic command handlers
Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 22 ++ 1 file changed, 22 insertions(+) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 249fad0468..ebcd8c1e43 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -2383,6 +2383,28 @@ static const SDProto sd_proto_emmc = { /* Only v4.5 is supported */ .name = "eMMC", .cmd = { +[0] = {0, sd_bc, "GO_IDLE_STATE", sd_cmd_GO_IDLE_STATE}, +[2] = {0, sd_bcr, "ALL_SEND_CID", sd_cmd_ALL_SEND_CID}, +[7] = {0, sd_ac, "(DE)SELECT_CARD", sd_cmd_DE_SELECT_CARD}, +[9] = {0, sd_ac, "SEND_CSD", sd_cmd_SEND_CSD}, +[10] = {0, sd_ac, "SEND_CID", sd_cmd_SEND_CID}, +[12] = {0, sd_ac, "STOP_TRANSMISSION", sd_cmd_STOP_TRANSMISSION}, +[13] = {0, sd_ac, "SEND_STATUS", sd_cmd_SEND_STATUS}, +[15] = {0, sd_ac, "GO_INACTIVE_STATE", sd_cmd_GO_INACTIVE_STATE}, +[16] = {2, sd_ac, "SET_BLOCKLEN", sd_cmd_SET_BLOCKLEN}, +[17] = {2, sd_adtc, "READ_SINGLE_BLOCK", sd_cmd_READ_SINGLE_BLOCK}, +[23] = {2, sd_ac, "SET_BLOCK_COUNT", sd_cmd_SET_BLOCK_COUNT}, +[24] = {4, sd_adtc, "WRITE_SINGLE_BLOCK", sd_cmd_WRITE_SINGLE_BLOCK}, +[27] = {4, sd_adtc, "PROGRAM_CSD", sd_cmd_PROGRAM_CSD}, +[28] = {6, sd_ac, "SET_WRITE_PROT", sd_cmd_SET_WRITE_PROT}, +[29] = {6, sd_ac, "CLR_WRITE_PROT", sd_cmd_CLR_WRITE_PROT}, +[30] = {6, sd_adtc, "SEND_WRITE_PROT", sd_cmd_SEND_WRITE_PROT}, +[35] = {5, sd_ac, "ERASE_WR_BLK_START", sd_cmd_ERASE_WR_BLK_START}, +[36] = {5, sd_ac, "ERASE_WR_BLK_END", sd_cmd_ERASE_WR_BLK_END}, +[38] = {5, sd_ac, "ERASE", sd_cmd_ERASE}, +[42] = {7, sd_adtc, "LOCK_UNLOCK", sd_cmd_LOCK_UNLOCK}, +[55] = {8, sd_ac, "APP_CMD", sd_cmd_APP_CMD}, +[56] = {8, sd_adtc, "GEN_CMD", sd_cmd_GEN_CMD}, }, }; -- 2.41.0
[RFC PATCH v42 90/98] hw/sd/sdcard: Add experimental 'x-aspeed-emmc-kludge' property
When booting U-boot/Linux on Aspeed boards via eMMC, some commands don't behave as expected from the spec. Add the 'x-aspeed-emmc-kludge' property to allow non standard uses until we figure out the reasons. Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index bd77853419..dc692fe1fa 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -127,6 +127,7 @@ struct SDState { uint8_t spec_version; BlockBackend *blk; +bool aspeed_emmc_kludge; const SDProto *proto; @@ -2567,6 +2568,8 @@ static Property sd_properties[] = { DEFINE_PROP_UINT8("spec_version", SDState, spec_version, SD_PHY_SPECv3_01_VERS), DEFINE_PROP_DRIVE("drive", SDState, blk), +DEFINE_PROP_BOOL("x-aspeed-emmc-kludge", SDState, + aspeed_emmc_kludge, false), /* 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 -- 2.41.0
[PATCH v42 39/98] hw/sd/sdcard: Store command name in SDProto
We already have a const array where command handlers are listed. Store the command name there too. Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 35 ++- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 558c39419d..97fb3785ee 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -95,6 +95,7 @@ typedef sd_rsp_type_t (*sd_cmd_handler)(SDState *sd, SDRequest req); typedef struct SDProto { const char *name; struct { +const char *name; sd_cmd_handler handler; } cmd[SDMMC_CMD_MAX], acmd[SDMMC_CMD_MAX]; } SDProto; @@ -237,8 +238,6 @@ static const char *sd_response_name(sd_rsp_type_t rsp) static const char *sd_cmd_name(SDState *sd, uint8_t cmd) { static const char *cmd_abbrev[SDMMC_CMD_MAX] = { - [0]= "GO_IDLE_STATE", [1]= "SEND_OP_COND", - [2]= "ALL_SEND_CID",[3]= "SEND_RELATIVE_ADDR", [4]= "SET_DSR", [5]= "IO_SEND_OP_COND", [6]= "SWITCH_FUNC", [7]= "SELECT/DESELECT_CARD", [8]= "SEND_IF_COND",[9]= "SEND_CSD", @@ -246,9 +245,8 @@ static const char *sd_cmd_name(SDState *sd, uint8_t cmd) [12]= "STOP_TRANSMISSION", [13]= "SEND_STATUS", [15]= "GO_INACTIVE_STATE", [16]= "SET_BLOCKLEN", [17]= "READ_SINGLE_BLOCK", -[18]= "READ_MULTIPLE_BLOCK",[19]= "SEND_TUNING_BLOCK", +[18]= "READ_MULTIPLE_BLOCK", [20]= "SPEED_CLASS_CONTROL",[21]= "DPS_spec", -[23]= "SET_BLOCK_COUNT", [24]= "WRITE_BLOCK",[25]= "WRITE_MULTIPLE_BLOCK", [26]= "MANUF_RSVD", [27]= "PROGRAM_CSD", [28]= "SET_WRITE_PROT", [29]= "CLR_WRITE_PROT", @@ -270,6 +268,12 @@ static const char *sd_cmd_name(SDState *sd, uint8_t cmd) [60]= "MANUF_RSVD", [61]= "MANUF_RSVD", [62]= "MANUF_RSVD", [63]= "MANUF_RSVD", }; +const SDProto *sdp = sd->proto; + +if (sdp->cmd[cmd].handler) { +assert(!cmd_abbrev[cmd]); +return sdp->cmd[cmd].name; +} return cmd_abbrev[cmd] ? cmd_abbrev[cmd] : "UNKNOWN_CMD"; } @@ -282,7 +286,6 @@ static const char *sd_acmd_name(SDState *sd, uint8_t cmd) [16] = "DPS_spec", [18] = "SECU_spec", [22] = "SEND_NUM_WR_BLOCKS",[23] = "SET_WR_BLK_ERASE_COUNT", -[41] = "SD_SEND_OP_COND", [42] = "SET_CLR_CARD_DETECT", [51] = "SEND_SCR", [52] = "SECU_spec", [53] = "SECU_spec", @@ -290,6 +293,12 @@ static const char *sd_acmd_name(SDState *sd, uint8_t cmd) [56] = "SECU_spec", [57] = "SECU_spec", [58] = "SECU_spec", [59] = "SECU_spec", }; +const SDProto *sdp = sd->proto; + +if (sdp->acmd[cmd].handler) { +assert(!acmd_abbrev[cmd]); +return sdp->acmd[cmd].name; +} return acmd_abbrev[cmd] ? acmd_abbrev[cmd] : "UNKNOWN_ACMD"; } @@ -2268,22 +2277,22 @@ void sd_enable(SDState *sd, bool enable) static const SDProto sd_proto_spi = { .name = "SPI", .cmd = { -[0] = {sd_cmd_GO_IDLE_STATE}, -[1] = {spi_cmd_SEND_OP_COND}, +[0] = {"GO_IDLE_STATE", sd_cmd_GO_IDLE_STATE}, +[1] = {"SEND_OP_COND", spi_cmd_SEND_OP_COND}, }, .acmd = { -[41] = {spi_cmd_SEND_OP_COND}, +[41] = {"SEND_OP_COND", spi_cmd_SEND_OP_COND}, }, }; static const SDProto sd_proto_sd = { .name = "SD", .cmd = { -[0] = {sd_cmd_GO_IDLE_STATE}, -[2] = {sd_cmd_ALL_SEND_CID}, -[3] = {sd_cmd_SEND_RELATIVE_ADDR}, -[19] = {sd_cmd_SEND_TUNING_BLOCK}, -[23] = {sd_cmd_SET_BLOCK_COUNT}, +[0] = { "GO_IDLE_STATE", sd_cmd_GO_IDLE_STATE}, +[2] = { "ALL_SEND_CID", sd_cmd_ALL_SEND_CID}, +[3] = { "SEND_RELATIVE_ADDR", sd_cmd_SEND_RELATIVE_ADDR}, +[19] = { "SEND_TUNING_BLOCK", sd_cmd_SEND_TUNING_BLOCK}, +[23] = { "SET_BLOCK_COUNT", sd_cmd_SET_BLOCK_COUNT}, }, }; -- 2.41.0
[PATCH v42 58/98] hw/sd/sdcard: Add sd_cmd_PROGRAM_CSD handler (CMD27)
Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 13 + 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 4650d20ee7..9d33113f11 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -243,7 +243,7 @@ static const char *sd_cmd_name(SDState *sd, uint8_t cmd) [18]= "READ_MULTIPLE_BLOCK", [21]= "DPS_spec", [25]= "WRITE_MULTIPLE_BLOCK", -[26]= "MANUF_RSVD", [27]= "PROGRAM_CSD", +[26]= "MANUF_RSVD", [28]= "SET_WRITE_PROT", [29]= "CLR_WRITE_PROT", [30]= "SEND_WRITE_PROT", [32]= "ERASE_WR_BLK_START", [33]= "ERASE_WR_BLK_END", @@ -1514,6 +1514,12 @@ static sd_rsp_type_t sd_cmd_WRITE_SINGLE_BLOCK(SDState *sd, SDRequest req) return sd_cmd_to_receivingdata(sd, req, addr, sd->blk_len); } +/* CMD27 */ +static sd_rsp_type_t sd_cmd_PROGRAM_CSD(SDState *sd, SDRequest req) +{ +return sd_cmd_to_receivingdata(sd, req, 0, sizeof(sd->csd)); +} + static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) { uint16_t rca; @@ -1603,9 +1609,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) case 26: /* CMD26: PROGRAM_CID */ return sd_cmd_to_receivingdata(sd, req, 0, sizeof(sd->cid)); -case 27: /* CMD27: PROGRAM_CSD */ -return sd_cmd_to_receivingdata(sd, req, 0, sizeof(sd->csd)); - /* Write protection (Class 6) */ case 28: /* CMD28: SET_WRITE_PROT */ if (sd->size > SDSC_MAX_CAPACITY) { @@ -2310,6 +2313,7 @@ static const SDProto sd_proto_spi = { [16] = {2, sd_spi, "SET_BLOCKLEN", sd_cmd_SET_BLOCKLEN}, [17] = {2, sd_spi, "READ_SINGLE_BLOCK", sd_cmd_READ_SINGLE_BLOCK}, [24] = {4, sd_spi, "WRITE_SINGLE_BLOCK", sd_cmd_WRITE_SINGLE_BLOCK}, +[27] = {4, sd_spi, "PROGRAM_CSD", sd_cmd_PROGRAM_CSD}, [34] = {10, sd_spi, "READ_SEC_CMD", sd_cmd_optional}, [35] = {10, sd_spi, "WRITE_SEC_CMD", sd_cmd_optional}, [36] = {10, sd_spi, "SEND_PSI", sd_cmd_optional}, @@ -2347,6 +2351,7 @@ static const SDProto sd_proto_sd = { [20] = {2, sd_ac, "SPEED_CLASS_CONTROL", sd_cmd_optional}, [23] = {2, sd_ac, "SET_BLOCK_COUNT", sd_cmd_SET_BLOCK_COUNT}, [24] = {4, sd_adtc, "WRITE_SINGLE_BLOCK", sd_cmd_WRITE_SINGLE_BLOCK}, +[27] = {4, sd_adtc, "PROGRAM_CSD", sd_cmd_PROGRAM_CSD}, [34] = {10, sd_adtc, "READ_SEC_CMD", sd_cmd_optional}, [35] = {10, sd_adtc, "WRITE_SEC_CMD", sd_cmd_optional}, [36] = {10, sd_adtc, "SEND_PSI", sd_cmd_optional}, -- 2.41.0
[PATCH v42 60/98] hw/sd/sdcard: Add sd_cmd_SEND_WRITE_PROT handler (CMD30)
Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 47 +-- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index a63213613b..bf9975e9b1 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -244,7 +244,6 @@ static const char *sd_cmd_name(SDState *sd, uint8_t cmd) [21]= "DPS_spec", [25]= "WRITE_MULTIPLE_BLOCK", [26]= "MANUF_RSVD", -[30]= "SEND_WRITE_PROT", [32]= "ERASE_WR_BLK_START", [33]= "ERASE_WR_BLK_END", [38]= "ERASE", [40]= "DPS_spec", @@ -1561,11 +1560,33 @@ static sd_rsp_type_t sd_cmd_CLR_WRITE_PROT(SDState *sd, SDRequest req) return sd_cmd_SET_CLR_WRITE_PROT(sd, req, false); } +/* CMD30 */ +static sd_rsp_type_t sd_cmd_SEND_WRITE_PROT(SDState *sd, SDRequest req) +{ +uint64_t addr; +uint32_t data; + +if (sd->size > SDSC_MAX_CAPACITY) { +return sd_illegal; +} + +if (sd->state != sd_transfer_state) { +return sd_invalid_state_for_cmd(sd, req); +} + +addr = sd_req_get_address(sd, req); +if (!address_in_range(sd, "SEND_WRITE_PROT", addr, sd->blk_len)) { +return sd_r1; +} + +data = sd_wpbits(sd, req.arg); +return sd_cmd_to_sendingdata(sd, req, addr, &data, sizeof(data)); +} + static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) { uint16_t rca; uint64_t addr; -uint32_t data; sd->last_cmd_name = sd_cmd_name(sd, req.cmd); /* CMD55 precedes an ACMD, so we are not interested in tracing it. @@ -1650,26 +1671,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) case 26: /* CMD26: PROGRAM_CID */ return sd_cmd_to_receivingdata(sd, req, 0, sizeof(sd->cid)); -/* Write protection (Class 6) */ -case 30: /* CMD30: SEND_WRITE_PROT */ -if (sd->size > SDSC_MAX_CAPACITY) { -return sd_illegal; -} -addr = sd_req_get_address(sd, req); -switch (sd->state) { -case sd_transfer_state: -if (!address_in_range(sd, "SEND_WRITE_PROT", - req.arg, sd->blk_len)) { -return sd_r1; -} -data = sd_wpbits(sd, req.arg); -return sd_cmd_to_sendingdata(sd, req, addr, &data, sizeof(data)); - -default: -break; -} -break; - /* Erase commands (Class 5) */ case 32: /* CMD32: ERASE_WR_BLK_START */ switch (sd->state) { @@ -2313,6 +2314,7 @@ static const SDProto sd_proto_spi = { [27] = {4, sd_spi, "PROGRAM_CSD", sd_cmd_PROGRAM_CSD}, [28] = {6, sd_spi, "SET_WRITE_PROT", sd_cmd_SET_WRITE_PROT}, [29] = {6, sd_spi, "CLR_WRITE_PROT", sd_cmd_CLR_WRITE_PROT}, +[30] = {6, sd_spi, "SEND_WRITE_PROT", sd_cmd_SEND_WRITE_PROT}, [34] = {10, sd_spi, "READ_SEC_CMD", sd_cmd_optional}, [35] = {10, sd_spi, "WRITE_SEC_CMD", sd_cmd_optional}, [36] = {10, sd_spi, "SEND_PSI", sd_cmd_optional}, @@ -2353,6 +2355,7 @@ static const SDProto sd_proto_sd = { [27] = {4, sd_adtc, "PROGRAM_CSD", sd_cmd_PROGRAM_CSD}, [28] = {6, sd_ac, "SET_WRITE_PROT", sd_cmd_SET_WRITE_PROT}, [29] = {6, sd_ac, "CLR_WRITE_PROT", sd_cmd_CLR_WRITE_PROT}, +[30] = {6, sd_adtc, "SEND_WRITE_PROT", sd_cmd_SEND_WRITE_PROT}, [34] = {10, sd_adtc, "READ_SEC_CMD", sd_cmd_optional}, [35] = {10, sd_adtc, "WRITE_SEC_CMD", sd_cmd_optional}, [36] = {10, sd_adtc, "SEND_PSI", sd_cmd_optional}, -- 2.41.0
[PATCH v42 89/98] hw/sd/sdcard: Implement eMMC sleep state (CMD5)
From: Luc Michel The JEDEC standards specifies a sleep state where the eMMC won't answer any command appart from RESET and WAKEUP and go to low power state. Implement this state and the corresponding command number 5. Signed-off-by: Luc Michel Signed-off-by: Francisco Iglesias Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 47 +-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 0f9bab105e..bd77853419 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1182,8 +1182,19 @@ static sd_rsp_type_t sd_cmd_to_sendingdata(SDState *sd, SDRequest req, /* CMD0 */ static sd_rsp_type_t sd_cmd_GO_IDLE_STATE(SDState *sd, SDRequest req) { -sd->state = sd_idle_state; -sd_reset(DEVICE(sd)); +if (sd->state == sd_sleep_state) { +switch (req.arg) { +case 0x: +case 0xf0f0f0f0: +break; +default: +return sd_r0; +} +} +if (sd->state != sd_inactive_state) { +sd->state = sd_idle_state; +sd_reset(DEVICE(sd)); +} return sd_is_spi(sd) ? sd_r1 : sd_r0; } @@ -1246,6 +1257,30 @@ static sd_rsp_type_t emmc_cmd_SET_RELATIVE_ADDR(SDState *sd, SDRequest req) } } +/* CMD5 */ +static sd_rsp_type_t emmc_cmd_sleep_awake(SDState *sd, SDRequest req) +{ +bool do_sleep = extract32(req.arg, 15, 1); + +switch (sd->state) { +case sd_sleep_state: +if (!do_sleep) { +/* Awake */ +sd->state = sd_standby_state; +} +return sd_r1b; + +case sd_standby_state: +if (do_sleep) { +sd->state = sd_sleep_state; +} +return sd_r1b; + +default: +return sd_invalid_state_for_cmd(sd, req); +} +} + /* CMD6 */ static sd_rsp_type_t sd_cmd_SWITCH_FUNCTION(SDState *sd, SDRequest req) { @@ -1648,6 +1683,7 @@ static sd_rsp_type_t sd_cmd_APP_CMD(SDState *sd, SDRequest req) case sd_ready_state: case sd_identification_state: case sd_inactive_state: +case sd_sleep_state: return sd_invalid_state_for_cmd(sd, req); case sd_idle_state: if (!sd_is_spi(sd) && sd_req_get_rca(sd, req) != 0x) { @@ -1969,6 +2005,12 @@ int sd_do_command(SDState *sd, SDRequest *req, req->cmd &= 0x3f; } +if (sd->state == sd_sleep_state && req->cmd) { +qemu_log_mask(LOG_GUEST_ERROR, "SD: Card is sleeping\n"); +rtype = sd_r0; +goto send_response; +} + if (sd->card_status & CARD_IS_LOCKED) { if (!cmd_valid_while_locked(sd, req->cmd)) { sd->card_status |= ILLEGAL_COMMAND; @@ -2420,6 +2462,7 @@ static const SDProto sd_proto_emmc = { [2] = {0, sd_bcr, "ALL_SEND_CID", sd_cmd_ALL_SEND_CID}, [3] = {0, sd_ac, "SET_RELATIVE_ADDR", emmc_cmd_SET_RELATIVE_ADDR}, [4] = {0, sd_bc, "SEND_DSR", sd_cmd_unimplemented}, +[5] = {0, sd_ac, "SLEEP/AWAKE", emmc_cmd_sleep_awake}, [7] = {0, sd_ac, "(DE)SELECT_CARD", sd_cmd_DE_SELECT_CARD}, [9] = {0, sd_ac, "SEND_CSD", sd_cmd_SEND_CSD}, [10] = {0, sd_ac, "SEND_CID", sd_cmd_SEND_CID}, -- 2.41.0
[PATCH v42 61/98] hw/sd/sdcard: Add sd_cmd_ERASE_WR_BLK_START/END handlers (CMD32 & CMD33)
Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 47 --- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index bf9975e9b1..4e31dfe18f 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -244,7 +244,6 @@ static const char *sd_cmd_name(SDState *sd, uint8_t cmd) [21]= "DPS_spec", [25]= "WRITE_MULTIPLE_BLOCK", [26]= "MANUF_RSVD", -[32]= "ERASE_WR_BLK_START", [33]= "ERASE_WR_BLK_END", [38]= "ERASE", [40]= "DPS_spec", [42]= "LOCK_UNLOCK", @@ -1583,6 +1582,26 @@ static sd_rsp_type_t sd_cmd_SEND_WRITE_PROT(SDState *sd, SDRequest req) return sd_cmd_to_sendingdata(sd, req, addr, &data, sizeof(data)); } +/* CMD32 */ +static sd_rsp_type_t sd_cmd_ERASE_WR_BLK_START(SDState *sd, SDRequest req) +{ +if (sd->state != sd_transfer_state) { +return sd_invalid_state_for_cmd(sd, req); +} +sd->erase_start = req.arg; +return sd_r1; +} + +/* CMD33 */ +static sd_rsp_type_t sd_cmd_ERASE_WR_BLK_END(SDState *sd, SDRequest req) +{ +if (sd->state != sd_transfer_state) { +return sd_invalid_state_for_cmd(sd, req); +} +sd->erase_end = req.arg; +return sd_r1; +} + static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) { uint16_t rca; @@ -1672,28 +1691,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) return sd_cmd_to_receivingdata(sd, req, 0, sizeof(sd->cid)); /* Erase commands (Class 5) */ -case 32: /* CMD32: ERASE_WR_BLK_START */ -switch (sd->state) { -case sd_transfer_state: -sd->erase_start = req.arg; -return sd_r1; - -default: -break; -} -break; - -case 33: /* CMD33: ERASE_WR_BLK_END */ -switch (sd->state) { -case sd_transfer_state: -sd->erase_end = req.arg; -return sd_r1; - -default: -break; -} -break; - case 38: /* CMD38: ERASE */ switch (sd->state) { case sd_transfer_state: @@ -2315,6 +2312,8 @@ static const SDProto sd_proto_spi = { [28] = {6, sd_spi, "SET_WRITE_PROT", sd_cmd_SET_WRITE_PROT}, [29] = {6, sd_spi, "CLR_WRITE_PROT", sd_cmd_CLR_WRITE_PROT}, [30] = {6, sd_spi, "SEND_WRITE_PROT", sd_cmd_SEND_WRITE_PROT}, +[32] = {5, sd_spi, "ERASE_WR_BLK_START", sd_cmd_ERASE_WR_BLK_START}, +[33] = {5, sd_spi, "ERASE_WR_BLK_END", sd_cmd_ERASE_WR_BLK_END}, [34] = {10, sd_spi, "READ_SEC_CMD", sd_cmd_optional}, [35] = {10, sd_spi, "WRITE_SEC_CMD", sd_cmd_optional}, [36] = {10, sd_spi, "SEND_PSI", sd_cmd_optional}, @@ -2356,6 +2355,8 @@ static const SDProto sd_proto_sd = { [28] = {6, sd_ac, "SET_WRITE_PROT", sd_cmd_SET_WRITE_PROT}, [29] = {6, sd_ac, "CLR_WRITE_PROT", sd_cmd_CLR_WRITE_PROT}, [30] = {6, sd_adtc, "SEND_WRITE_PROT", sd_cmd_SEND_WRITE_PROT}, +[32] = {5, sd_ac, "ERASE_WR_BLK_START", sd_cmd_ERASE_WR_BLK_START}, +[33] = {5, sd_ac, "ERASE_WR_BLK_END", sd_cmd_ERASE_WR_BLK_END}, [34] = {10, sd_adtc, "READ_SEC_CMD", sd_cmd_optional}, [35] = {10, sd_adtc, "WRITE_SEC_CMD", sd_cmd_optional}, [36] = {10, sd_adtc, "SEND_PSI", sd_cmd_optional}, -- 2.41.0
[PATCH v42 62/98] hw/sd/sdcard: Add sd_cmd_ERASE handler (CMD38)
Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 41 - 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 4e31dfe18f..17fec612eb 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -244,7 +244,6 @@ static const char *sd_cmd_name(SDState *sd, uint8_t cmd) [21]= "DPS_spec", [25]= "WRITE_MULTIPLE_BLOCK", [26]= "MANUF_RSVD", -[38]= "ERASE", [40]= "DPS_spec", [42]= "LOCK_UNLOCK", [54]= "SDIO_RSVD", [55]= "APP_CMD", @@ -1602,6 +1601,24 @@ static sd_rsp_type_t sd_cmd_ERASE_WR_BLK_END(SDState *sd, SDRequest req) return sd_r1; } +/* CMD38 */ +static sd_rsp_type_t sd_cmd_ERASE(SDState *sd, SDRequest req) +{ +if (sd->state != sd_transfer_state) { +return sd_invalid_state_for_cmd(sd, req); +} +if (sd->csd[14] & 0x30) { +sd->card_status |= WP_VIOLATION; +return sd_r1b; +} + +sd->state = sd_programming_state; +sd_erase(sd); +/* Bzzztt Operation complete. */ +sd->state = sd_transfer_state; +return sd_r1b; +} + static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) { uint16_t rca; @@ -1690,26 +1707,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) case 26: /* CMD26: PROGRAM_CID */ return sd_cmd_to_receivingdata(sd, req, 0, sizeof(sd->cid)); -/* Erase commands (Class 5) */ -case 38: /* CMD38: ERASE */ -switch (sd->state) { -case sd_transfer_state: -if (sd->csd[14] & 0x30) { -sd->card_status |= WP_VIOLATION; -return sd_r1b; -} - -sd->state = sd_programming_state; -sd_erase(sd); -/* Bzzztt Operation complete. */ -sd->state = sd_transfer_state; -return sd_r1b; - -default: -break; -} -break; - /* Lock card commands (Class 7) */ case 42: /* CMD42: LOCK_UNLOCK */ return sd_cmd_to_receivingdata(sd, req, 0, 0); @@ -2318,6 +2315,7 @@ static const SDProto sd_proto_spi = { [35] = {10, sd_spi, "WRITE_SEC_CMD", sd_cmd_optional}, [36] = {10, sd_spi, "SEND_PSI", sd_cmd_optional}, [37] = {10, sd_spi, "CONTROL_ASSD_SYSTEM", sd_cmd_optional}, +[38] = {5, sd_spi, "ERASE", sd_cmd_ERASE}, [50] = {10, sd_spi, "DIRECT_SECURE_READ", sd_cmd_optional}, [52] = {9, sd_spi, "IO_RW_DIRECT", sd_cmd_optional}, [53] = {9, sd_spi, "IO_RW_EXTENDED", sd_cmd_optional}, @@ -2361,6 +2359,7 @@ static const SDProto sd_proto_sd = { [35] = {10, sd_adtc, "WRITE_SEC_CMD", sd_cmd_optional}, [36] = {10, sd_adtc, "SEND_PSI", sd_cmd_optional}, [37] = {10, sd_ac, "CONTROL_ASSD_SYSTEM", sd_cmd_optional}, +[38] = {5, sd_ac, "ERASE", sd_cmd_ERASE}, [43] = {1, sd_ac, "Q_MANAGEMENT", sd_cmd_optional}, [44] = {1, sd_ac, "Q_TASK_INFO_A", sd_cmd_optional}, [45] = {1, sd_ac, "Q_TASK_INFO_B", sd_cmd_optional}, -- 2.41.0
[PATCH v42 38/98] hw/sd/sdcard: Prepare SDProto to contain more fields
Convert array of command handlers to array of structures. The structure contains the command handler. No logical change intended. Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 29 +++-- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index f4bdd12b26..558c39419d 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -94,8 +94,9 @@ 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]; +struct { +sd_cmd_handler handler; +} cmd[SDMMC_CMD_MAX], acmd[SDMMC_CMD_MAX]; } SDProto; struct SDState { @@ -1305,8 +1306,8 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) return sd_illegal; } -if (sd->proto->cmd[req.cmd]) { -return sd->proto->cmd[req.cmd](sd, req); +if (sd->proto->cmd[req.cmd].handler) { +return sd->proto->cmd[req.cmd].handler(sd, req); } switch (req.cmd) { @@ -1753,8 +1754,8 @@ static sd_rsp_type_t sd_app_command(SDState *sd, req.cmd, req.arg, sd_state_name(sd->state)); sd->card_status |= APP_CMD; -if (sd->proto->acmd[req.cmd]) { -return sd->proto->acmd[req.cmd](sd, req); +if (sd->proto->acmd[req.cmd].handler) { +return sd->proto->acmd[req.cmd].handler(sd, req); } switch (req.cmd) { @@ -2267,22 +2268,22 @@ void sd_enable(SDState *sd, bool enable) static const SDProto sd_proto_spi = { .name = "SPI", .cmd = { -[0] = sd_cmd_GO_IDLE_STATE, -[1] = spi_cmd_SEND_OP_COND, +[0] = {sd_cmd_GO_IDLE_STATE}, +[1] = {spi_cmd_SEND_OP_COND}, }, .acmd = { -[41]= spi_cmd_SEND_OP_COND, +[41] = {spi_cmd_SEND_OP_COND}, }, }; static const SDProto sd_proto_sd = { .name = "SD", .cmd = { -[0] = sd_cmd_GO_IDLE_STATE, -[2] = sd_cmd_ALL_SEND_CID, -[3] = sd_cmd_SEND_RELATIVE_ADDR, -[19]= sd_cmd_SEND_TUNING_BLOCK, -[23]= sd_cmd_SET_BLOCK_COUNT, +[0] = {sd_cmd_GO_IDLE_STATE}, +[2] = {sd_cmd_ALL_SEND_CID}, +[3] = {sd_cmd_SEND_RELATIVE_ADDR}, +[19] = {sd_cmd_SEND_TUNING_BLOCK}, +[23] = {sd_cmd_SET_BLOCK_COUNT}, }, }; -- 2.41.0
[PATCH v42 73/98] hw/sd/sdcard: Add sd_acmd_SET_CLR_CARD_DETECT handler (ACMD42)
Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 25 + 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 167e1c517a..a27a7e0f24 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -263,7 +263,6 @@ static const char *sd_acmd_name(SDState *sd, uint8_t cmd) [14] = "DPS_spec", [15] = "DPS_spec", [16] = "DPS_spec", [18] = "SECU_spec", -[42] = "SET_CLR_CARD_DETECT", [51] = "SEND_SCR", [52] = "SECU_spec", [53] = "SECU_spec", [54] = "SECU_spec", @@ -1748,6 +1747,17 @@ static sd_rsp_type_t sd_acmd_SD_APP_OP_COND(SDState *sd, SDRequest req) return sd_r3; } +/* ACMD42 */ +static sd_rsp_type_t sd_acmd_SET_CLR_CARD_DETECT(SDState *sd, SDRequest req) +{ +if (sd->state != sd_transfer_state) { +return sd_invalid_state_for_cmd(sd, req); +} + +/* Bringing in the 50KOhm pull-up resistor... Done. */ +return sd_r1; +} + static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) { uint64_t addr; @@ -1856,17 +1866,6 @@ static sd_rsp_type_t sd_app_command(SDState *sd, } switch (req.cmd) { -case 42: /* ACMD42: SET_CLR_CARD_DETECT */ -switch (sd->state) { -case sd_transfer_state: -/* Bringing in the 50KOhm pull-up resistor... Done. */ -return sd_r1; - -default: -break; -} -break; - case 51: /* ACMD51: SEND_SCR */ switch (sd->state) { case sd_transfer_state: @@ -2327,6 +2326,7 @@ static const SDProto sd_proto_spi = { [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}, +[42] = {8, sd_spi, "SET_CLR_CARD_DETECT", sd_acmd_SET_CLR_CARD_DETECT}, }, }; @@ -2387,6 +2387,7 @@ static const SDProto sd_proto_sd = { [22] = {8, sd_adtc, "SEND_NUM_WR_BLOCKS", sd_acmd_SEND_NUM_WR_BLOCKS}, [23] = {8, sd_ac, "SET_WR_BLK_ERASE_COUNT", sd_acmd_SET_WR_BLK_ERASE_COUNT}, [41] = {8, sd_bcr, "SD_APP_OP_COND", sd_acmd_SD_APP_OP_COND}, +[42] = {8, sd_ac, "SET_CLR_CARD_DETECT", sd_acmd_SET_CLR_CARD_DETECT}, }, }; -- 2.41.0
Re: [PATCH v6 01/11] gdbstub: Clean up process_string_cmd
On 28/6/24 07:08, Gustavo Romero wrote: Change 'process_string_cmd' to return true on success and false on failure, instead of 0 and -1. Signed-off-by: Gustavo Romero Reviewed-by: Alex Bennée Reviewed-by: Richard Henderson --- gdbstub/gdbstub.c | 40 1 file changed, 20 insertions(+), 20 deletions(-) Reviewed-by: Philippe Mathieu-Daudé
[PATCH v42 56/98] hw/sd/sdcard: Add sd_cmd_READ_SINGLE_BLOCK handler (CMD17)
Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 37 - 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index d731c3df58..e2a7ed8b45 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -240,7 +240,6 @@ static const char *sd_response_name(sd_rsp_type_t rsp) static const char *sd_cmd_name(SDState *sd, uint8_t cmd) { static const char *cmd_abbrev[SDMMC_CMD_MAX] = { -[17]= "READ_SINGLE_BLOCK", [18]= "READ_MULTIPLE_BLOCK", [21]= "DPS_spec", [24]= "WRITE_BLOCK",[25]= "WRITE_MULTIPLE_BLOCK", @@ -1441,6 +1440,24 @@ static sd_rsp_type_t sd_cmd_SET_BLOCKLEN(SDState *sd, SDRequest req) return sd_r1; } +/* CMD17 */ +static sd_rsp_type_t sd_cmd_READ_SINGLE_BLOCK(SDState *sd, SDRequest req) +{ +uint64_t addr; + +if (sd->state != sd_transfer_state) { +return sd_invalid_state_for_cmd(sd, req); +} + +addr = sd_req_get_address(sd, req); +if (!address_in_range(sd, "READ_SINGLE_BLOCK", addr, sd->blk_len)) { +return sd_r1; +} + +sd_blk_read(sd, addr, sd->blk_len); +return sd_cmd_to_sendingdata(sd, req, addr, NULL, sd->blk_len); +} + /* CMD19 */ static sd_rsp_type_t sd_cmd_SEND_TUNING_BLOCK(SDState *sd, SDRequest req) { @@ -1507,22 +1524,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) switch (req.cmd) { /* Block read commands (Class 2) */ -case 17: /* CMD17: READ_SINGLE_BLOCK */ -addr = sd_req_get_address(sd, req); -switch (sd->state) { -case sd_transfer_state: - -if (!address_in_range(sd, "READ_SINGLE_BLOCK", addr, sd->blk_len)) { -return sd_r1; -} -sd_blk_read(sd, addr, sd->blk_len); -return sd_cmd_to_sendingdata(sd, req, addr, NULL, sd->blk_len); - -default: -break; -} -break; - case 18: /* CMD18: READ_MULTIPLE_BLOCK */ addr = sd_req_get_address(sd, req); switch (sd->state) { @@ -2306,6 +2307,7 @@ static const SDProto sd_proto_spi = { [12] = {0, sd_spi, "STOP_TRANSMISSION", sd_cmd_STOP_TRANSMISSION}, [13] = {0, sd_spi, "SEND_STATUS", sd_cmd_SEND_STATUS}, [16] = {2, sd_spi, "SET_BLOCKLEN", sd_cmd_SET_BLOCKLEN}, +[17] = {2, sd_spi, "READ_SINGLE_BLOCK", sd_cmd_READ_SINGLE_BLOCK}, [34] = {10, sd_spi, "READ_SEC_CMD", sd_cmd_optional}, [35] = {10, sd_spi, "WRITE_SEC_CMD", sd_cmd_optional}, [36] = {10, sd_spi, "SEND_PSI", sd_cmd_optional}, @@ -2338,6 +2340,7 @@ static const SDProto sd_proto_sd = { [13] = {0, sd_ac, "SEND_STATUS", sd_cmd_SEND_STATUS}, [15] = {0, sd_ac, "GO_INACTIVE_STATE", sd_cmd_GO_INACTIVE_STATE}, [16] = {2, sd_ac, "SET_BLOCKLEN", sd_cmd_SET_BLOCKLEN}, +[17] = {2, sd_adtc, "READ_SINGLE_BLOCK", sd_cmd_READ_SINGLE_BLOCK}, [19] = {2, sd_adtc, "SEND_TUNING_BLOCK", sd_cmd_SEND_TUNING_BLOCK}, [20] = {2, sd_ac, "SPEED_CLASS_CONTROL", sd_cmd_optional}, [23] = {2, sd_ac, "SET_BLOCK_COUNT", sd_cmd_SET_BLOCK_COUNT}, -- 2.41.0
[PATCH v42 37/98] hw/sd/sdcard: Pass SDState as argument to sd_[a]cmd_name()
In order to access SDState::SDProto from sd_[a]cmd_name(), pass SDState as argument. Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 8 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 93a4a4e1b4..f4bdd12b26 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -233,7 +233,7 @@ static const char *sd_response_name(sd_rsp_type_t rsp) return response_name[rsp]; } -static const char *sd_cmd_name(uint8_t cmd) +static const char *sd_cmd_name(SDState *sd, uint8_t cmd) { static const char *cmd_abbrev[SDMMC_CMD_MAX] = { [0]= "GO_IDLE_STATE", [1]= "SEND_OP_COND", @@ -272,7 +272,7 @@ static const char *sd_cmd_name(uint8_t cmd) return cmd_abbrev[cmd] ? cmd_abbrev[cmd] : "UNKNOWN_CMD"; } -static const char *sd_acmd_name(uint8_t cmd) +static const char *sd_acmd_name(SDState *sd, uint8_t cmd) { static const char *acmd_abbrev[SDMMC_CMD_MAX] = { [6] = "SET_BUS_WIDTH", @@ -1281,7 +1281,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) uint64_t addr; uint32_t data; -sd->last_cmd_name = sd_cmd_name(req.cmd); +sd->last_cmd_name = sd_cmd_name(sd, req.cmd); /* CMD55 precedes an ACMD, so we are not interested in tracing it. * However there is no ACMD55, so we want to trace this particular case. */ @@ -1748,7 +1748,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) static sd_rsp_type_t sd_app_command(SDState *sd, SDRequest req) { -sd->last_cmd_name = sd_acmd_name(req.cmd); +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)); sd->card_status |= APP_CMD; -- 2.41.0
[PATCH v42 66/98] hw/sd/sdcard: Add spi_cmd_READ_OCR handler (CMD58)
Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 10 +++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 50cee5ac40..b3b4cd5a3a 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1660,6 +1660,12 @@ static sd_rsp_type_t sd_cmd_GEN_CMD(SDState *sd, SDRequest req) } } +/* CMD58 */ +static sd_rsp_type_t spi_cmd_READ_OCR(SDState *sd, SDRequest req) +{ +return sd_r3; +} + static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) { uint64_t addr; @@ -1748,9 +1754,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) return sd_cmd_to_receivingdata(sd, req, 0, sizeof(sd->cid)); /* Application specific commands (Class 8) */ -case 58:/* CMD58: READ_OCR (SPI) */ -return sd_r3; - case 59:/* CMD59: CRC_ON_OFF (SPI) */ return sd_r1; @@ -2321,6 +2324,7 @@ static const SDProto sd_proto_spi = { [55] = {8, sd_spi, "APP_CMD", sd_cmd_APP_CMD}, [56] = {8, sd_spi, "GEN_CMD", sd_cmd_GEN_CMD}, [57] = {10, sd_spi, "DIRECT_SECURE_WRITE", sd_cmd_optional}, +[58] = {0, sd_spi, "READ_OCR", spi_cmd_READ_OCR}, }, .acmd = { [41] = {8, sd_spi, "SEND_OP_COND", spi_cmd_SEND_OP_COND}, -- 2.41.0
[PATCH v42 77/98] hw/sd/sdcard: Remove noise from sd_cmd_name()
These CMD names weren't really useful, "UNKNOWN_CMD" is simpler. Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 5 - 1 file changed, 5 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 19322c558f..0a7b422b2c 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -241,12 +241,7 @@ static const char *sd_cmd_name(SDState *sd, uint8_t cmd) { static const char *cmd_abbrev[SDMMC_CMD_MAX] = { [18]= "READ_MULTIPLE_BLOCK", -[21]= "DPS_spec", [25]= "WRITE_MULTIPLE_BLOCK", -[26]= "MANUF_RSVD", -[40]= "DPS_spec", -[60]= "MANUF_RSVD", [61]= "MANUF_RSVD", -[62]= "MANUF_RSVD", [63]= "MANUF_RSVD", }; const SDProto *sdp = sd->proto; -- 2.41.0
[RFC PATCH v42 92/98] hw/sd/sdcard: Adapt sd_cmd_APP_CMD handler for eMMC (CMD55)
From: Cédric Le Goater Signed-off-by: Cédric Le Goater [PMD: Use aspeed_emmc_kludge] Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 5 - 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index f875fcd741..82e0b5838f 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1693,6 +1693,9 @@ static sd_rsp_type_t sd_cmd_APP_CMD(SDState *sd, SDRequest req) case sd_sleep_state: return sd_invalid_state_for_cmd(sd, req); case sd_idle_state: +if (sd_is_emmc(sd)) { +return sd_invalid_state_for_cmd(sd, req); +} if (!sd_is_spi(sd) && sd_req_get_rca(sd, req) != 0x) { qemu_log_mask(LOG_GUEST_ERROR, "SD: illegal RCA 0x%04x for APP_CMD\n", req.cmd); @@ -1707,7 +1710,7 @@ static sd_rsp_type_t sd_cmd_APP_CMD(SDState *sd, SDRequest req) sd->expecting_acmd = true; sd->card_status |= APP_CMD; -return sd_r1; +return sd->aspeed_emmc_kludge ? sd_r0 : sd_r1; } /* CMD56 */ -- 2.41.0
[PATCH v42 74/98] hw/sd/sdcard: Add sd_acmd_SEND_SCR handler (ACMD51)
Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 19 --- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index a27a7e0f24..6a9d611429 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -263,7 +263,6 @@ static const char *sd_acmd_name(SDState *sd, uint8_t cmd) [14] = "DPS_spec", [15] = "DPS_spec", [16] = "DPS_spec", [18] = "SECU_spec", -[51] = "SEND_SCR", [52] = "SECU_spec", [53] = "SECU_spec", [54] = "SECU_spec", [56] = "SECU_spec", [57] = "SECU_spec", @@ -1758,6 +1757,12 @@ static sd_rsp_type_t sd_acmd_SET_CLR_CARD_DETECT(SDState *sd, SDRequest req) return sd_r1; } +/* ACMD51 */ +static sd_rsp_type_t sd_acmd_SEND_SCR(SDState *sd, SDRequest req) +{ +return sd_cmd_to_sendingdata(sd, req, 0, sd->scr, sizeof(sd->scr)); +} + static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) { uint64_t addr; @@ -1866,16 +1871,6 @@ static sd_rsp_type_t sd_app_command(SDState *sd, } switch (req.cmd) { -case 51: /* ACMD51: SEND_SCR */ -switch (sd->state) { -case sd_transfer_state: -return sd_cmd_to_sendingdata(sd, req, 0, sd->scr, sizeof(sd->scr)); - -default: -break; -} -break; - case 18:/* Reserved for SD security applications */ case 25: case 26: @@ -2327,6 +2322,7 @@ static const SDProto sd_proto_spi = { [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}, [42] = {8, sd_spi, "SET_CLR_CARD_DETECT", sd_acmd_SET_CLR_CARD_DETECT}, +[51] = {8, sd_spi, "SEND_SCR", sd_acmd_SEND_SCR}, }, }; @@ -2388,6 +2384,7 @@ static const SDProto sd_proto_sd = { [23] = {8, sd_ac, "SET_WR_BLK_ERASE_COUNT", sd_acmd_SET_WR_BLK_ERASE_COUNT}, [41] = {8, sd_bcr, "SD_APP_OP_COND", sd_acmd_SD_APP_OP_COND}, [42] = {8, sd_ac, "SET_CLR_CARD_DETECT", sd_acmd_SET_CLR_CARD_DETECT}, +[51] = {8, sd_adtc, "SEND_SCR", sd_acmd_SEND_SCR}, }, }; -- 2.41.0
[PATCH v42 65/98] hw/sd/sdcard: Add sd_cmd_GEN_CMD handler (CMD56)
Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 36 +--- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 5461e56e17..50cee5ac40 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -245,7 +245,6 @@ static const char *sd_cmd_name(SDState *sd, uint8_t cmd) [25]= "WRITE_MULTIPLE_BLOCK", [26]= "MANUF_RSVD", [40]= "DPS_spec", -[56]= "GEN_CMD", [60]= "MANUF_RSVD", [61]= "MANUF_RSVD", [62]= "MANUF_RSVD", [63]= "MANUF_RSVD", }; @@ -910,9 +909,6 @@ static void sd_blk_write(SDState *sd, uint64_t addr, uint32_t len) } } -#define APP_READ_BLOCK(a, len) memset(sd->data, 0xec, len) -#define APP_WRITE_BLOCK(a, len) - static void sd_erase(SDState *sd) { uint64_t erase_start = sd->erase_start; @@ -1649,6 +1645,21 @@ static sd_rsp_type_t sd_cmd_APP_CMD(SDState *sd, SDRequest req) return sd_r1; } +/* CMD56 */ +static sd_rsp_type_t sd_cmd_GEN_CMD(SDState *sd, SDRequest req) +{ +if (sd->state != sd_transfer_state) { +return sd_invalid_state_for_cmd(sd, req); +} + +if (req.arg & 1) { +return sd_cmd_to_sendingdata(sd, req, 0, + sd->vendor_data, sizeof(sd->vendor_data)); +} else { +return sd_cmd_to_receivingdata(sd, req, 0, sizeof(sd->vendor_data)); +} +} + static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) { uint64_t addr; @@ -1737,21 +1748,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) return sd_cmd_to_receivingdata(sd, req, 0, sizeof(sd->cid)); /* Application specific commands (Class 8) */ -case 56: /* CMD56: GEN_CMD */ -switch (sd->state) { -case sd_transfer_state: -if (req.arg & 1) { -return sd_cmd_to_sendingdata(sd, req, 0, - sd->vendor_data, - sizeof(sd->vendor_data)); -} -return sd_cmd_to_receivingdata(sd, req, 0, sizeof(sd->vendor_data)); - -default: -break; -} -break; - case 58:/* CMD58: READ_OCR (SPI) */ return sd_r3; @@ -2323,6 +2319,7 @@ static const SDProto sd_proto_spi = { [52] = {9, sd_spi, "IO_RW_DIRECT", sd_cmd_optional}, [53] = {9, sd_spi, "IO_RW_EXTENDED", sd_cmd_optional}, [55] = {8, sd_spi, "APP_CMD", sd_cmd_APP_CMD}, +[56] = {8, sd_spi, "GEN_CMD", sd_cmd_GEN_CMD}, [57] = {10, sd_spi, "DIRECT_SECURE_WRITE", sd_cmd_optional}, }, .acmd = { @@ -2376,6 +2373,7 @@ static const SDProto sd_proto_sd = { [52] = {9, sd_bc, "IO_RW_DIRECT", sd_cmd_optional}, [53] = {9, sd_bc, "IO_RW_EXTENDED", sd_cmd_optional}, [55] = {8, sd_ac, "APP_CMD", sd_cmd_APP_CMD}, +[56] = {8, sd_adtc, "GEN_CMD", sd_cmd_GEN_CMD}, [57] = {10, sd_adtc, "DIRECT_SECURE_WRITE", sd_cmd_optional}, [58] = {11, sd_adtc, "READ_EXTR_MULTI", sd_cmd_optional}, [59] = {11, sd_adtc, "WRITE_EXTR_MULTI", sd_cmd_optional}, -- 2.41.0
Re: [PATCH v6 06/11] target/arm: Factor out code for setting MTE TCF0 field
On 28/6/24 07:08, Gustavo Romero wrote: Factor out the code used for setting the MTE TCF0 field from the prctl code into a convenient function. Other subsystems, like gdbstub, need to set this field as well, so keep it as a separate function to avoid duplication and ensure consistency in how this field is set across the board. Signed-off-by: Gustavo Romero --- linux-user/aarch64/meson.build | 2 ++ linux-user/aarch64/mte_user_helper.c | 34 linux-user/aarch64/mte_user_helper.h | 25 linux-user/aarch64/target_prctl.h| 22 ++ 4 files changed, 63 insertions(+), 20 deletions(-) create mode 100644 linux-user/aarch64/mte_user_helper.c create mode 100644 linux-user/aarch64/mte_user_helper.h diff --git a/linux-user/aarch64/meson.build b/linux-user/aarch64/meson.build index 248c578d15..f75bb3cd75 100644 --- a/linux-user/aarch64/meson.build +++ b/linux-user/aarch64/meson.build @@ -9,3 +9,5 @@ vdso_le_inc = gen_vdso.process('vdso-le.so', extra_args: ['-r', '__kernel_rt_sigreturn']) linux_user_ss.add(when: 'TARGET_AARCH64', if_true: [vdso_be_inc, vdso_le_inc]) + +linux_user_ss.add(when: 'TARGET_AARCH64', if_true: [files('mte_user_helper.c')]) diff --git a/linux-user/aarch64/mte_user_helper.c b/linux-user/aarch64/mte_user_helper.c new file mode 100644 index 00..8be6deaf03 --- /dev/null +++ b/linux-user/aarch64/mte_user_helper.c @@ -0,0 +1,34 @@ +/* + * ARM MemTag convenience functions. + * + * This code is licensed under the GNU GPL v2 or later. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + #include "qemu/osdep.h" #include "qemu.h" +#include +#include "mte_user_helper.h" + +void arm_set_mte_tcf0(CPUArchState *env, abi_long value) +{ +/* + * Write PR_MTE_TCF to SCTLR_EL1[TCF0]. + * + * The kernel has a per-cpu configuration for the sysadmin, + * /sys/devices/system/cpu/cpu/mte_tcf_preferred, + * which qemu does not implement. + * + * Because there is no performance difference between the modes, and + * because SYNC is most useful for debugging MTE errors, choose SYNC + * as the preferred mode. With this preference, and the way the API + * uses only two bits, there is no way for the program to select + * ASYMM mode. + */ +unsigned tcf = 0; +if (value & PR_MTE_TCF_SYNC) { +tcf = 1; +} else if (value & PR_MTE_TCF_ASYNC) { +tcf = 2; +} +env->cp15.sctlr_el[1] = deposit64(env->cp15.sctlr_el[1], 38, 2, tcf); +} diff --git a/linux-user/aarch64/mte_user_helper.h b/linux-user/aarch64/mte_user_helper.h new file mode 100644 index 00..ee3f6b190a --- /dev/null +++ b/linux-user/aarch64/mte_user_helper.h @@ -0,0 +1,25 @@ +/* + * ARM MemTag convenience functions. + * + * This code is licensed under the GNU GPL v2 or later. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifndef AARCH64_MTE_USER_HELPER_H +#define AARCH64_MTE USER_HELPER_H + +#include "qemu/osdep.h" +#include "qemu.h" NACK. See my comment on v5.
[RFC PATCH v42 96/98] hw/sd/sdcard: Support boot area in emmc image
From: Joel Stanley This assumes a specially constructed image: dd if=/dev/zero of=mmc-bootarea.img count=2 bs=1M dd if=u-boot-spl.bin of=mmc-bootarea.img conv=notrunc dd if=u-boot.bin of=mmc-bootarea.img conv=notrunc count=64 bs=1K cat mmc-bootarea.img obmc-phosphor-image.wic > mmc.img truncate --size 16GB mmc.img truncate --size 128MB mmc-bootarea.img For now this still requires a mtd image to load the SPL: qemu-system-arm -M tacoma-bmc -nographic \ -global driver=sd-card,property=emmc,value=true \ -drive file=mmc.img,if=sd,index=2 \ -drive file=mmc-bootarea.img,if=mtd,format=raw Signed-off-by: Joel Stanley Signed-off-by: Cédric Le Goater Signed-off-by: Philippe Mathieu-Daudé --- include/hw/sd/sd.h | 1 + hw/sd/sd.c | 39 +++ 2 files changed, 40 insertions(+) diff --git a/include/hw/sd/sd.h b/include/hw/sd/sd.h index d35a839f5e..07435d2e17 100644 --- a/include/hw/sd/sd.h +++ b/include/hw/sd/sd.h @@ -132,6 +132,7 @@ struct SDCardClass { bool (*get_readonly)(SDState *sd); void (*set_cid)(SDState *sd); void (*set_csd)(SDState *sd, uint64_t size); +uint32_t (*bootpart_offset)(SDState *sd); const struct SDProto *proto; }; diff --git a/hw/sd/sd.c b/hw/sd/sd.c index e7d8b9c0fb..2d49be61f6 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -783,6 +783,12 @@ static inline uint64_t sd_addr_to_wpnum(uint64_t addr) return addr >> (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT); } + +static unsigned sd_boot_capacity_bytes(SDState *sd) +{ +return sd->ext_csd[EXT_CSD_BOOT_MULT] << 17; +} + static void sd_reset(DeviceState *dev) { SDState *sd = SD_CARD(dev); @@ -984,9 +990,40 @@ void sd_set_cb(SDState *sd, qemu_irq readonly, qemu_irq insert) qemu_set_irq(insert, sd->blk ? blk_is_inserted(sd->blk) : 0); } +/* + * This requires a disk image that has two boot partitions inserted at the + * beginning of it. The size of the boot partitions are configured in the + * ext_csd structure, which is hardcoded in qemu. They are currently set to + * 1MB each. + */ +static uint32_t sd_emmc_bootpart_offset(SDState *sd) +{ +unsigned int access = sd->ext_csd[EXT_CSD_PART_CONFIG] & +EXT_CSD_PART_CONFIG_ACC_MASK; +unsigned int boot_capacity = sd_boot_capacity_bytes(sd); + +switch (access) { +case EXT_CSD_PART_CONFIG_ACC_DEFAULT: +return boot_capacity * 2; +case EXT_CSD_PART_CONFIG_ACC_BOOT0: +return 0; +case EXT_CSD_PART_CONFIG_ACC_BOOT0 + 1: +return boot_capacity * 1; +default: + g_assert_not_reached(); +} +} + +static uint32_t sd_bootpart_offset(SDState *sd) +{ +SDCardClass *sc = SD_CARD_GET_CLASS(sd); +return sc->bootpart_offset ? sc->bootpart_offset(sd) : 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); if (!sd->blk || blk_pread(sd->blk, addr, len, sd->data, 0) < 0) { fprintf(stderr, "sd_blk_read: read error on host side\n"); } @@ -995,6 +1032,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); if (!sd->blk || blk_pwrite(sd->blk, addr, len, sd->data, 0) < 0) { fprintf(stderr, "sd_blk_write: write error on host side\n"); } @@ -2833,6 +2871,7 @@ static void emmc_class_init(ObjectClass *klass, void *data) dc->realize = emmc_realize; sc->proto = &sd_proto_emmc; sc->set_csd = sd_emmc_set_csd; +sc->bootpart_offset = sd_emmc_bootpart_offset; } static const TypeInfo sd_types[] = { -- 2.41.0
[PATCH v42 85/98] hw/sd/sdcard: Add emmc_cmd_SET_RELATIVE_ADDR() handler
From: Cédric Le Goater Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Cédric Le Goater Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 15 +++ 1 file changed, 15 insertions(+) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 9a2bfeaab6..c6e5c93acb 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1220,6 +1220,20 @@ static sd_rsp_type_t sd_cmd_SEND_RELATIVE_ADDR(SDState *sd, SDRequest req) } } +static sd_rsp_type_t emmc_cmd_SET_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, req.arg >> 16); +return sd_r1; + +default: +return sd_invalid_state_for_cmd(sd, req); +} +} + /* CMD6 */ static sd_rsp_type_t sd_cmd_SWITCH_FUNCTION(SDState *sd, SDRequest req) { @@ -2385,6 +2399,7 @@ static const SDProto sd_proto_emmc = { .cmd = { [0] = {0, sd_bc, "GO_IDLE_STATE", sd_cmd_GO_IDLE_STATE}, [2] = {0, sd_bcr, "ALL_SEND_CID", sd_cmd_ALL_SEND_CID}, +[3] = {0, sd_ac, "SET_RELATIVE_ADDR", emmc_cmd_SET_RELATIVE_ADDR}, [4] = {0, sd_bc, "SEND_DSR", sd_cmd_unimplemented}, [7] = {0, sd_ac, "(DE)SELECT_CARD", sd_cmd_DE_SELECT_CARD}, [9] = {0, sd_ac, "SEND_CSD", sd_cmd_SEND_CSD}, -- 2.41.0
[RFC PATCH v42 97/98] hw/sd/sdcard: Subtract bootarea size from blk
From: Joel Stanley The userdata size is derived from the file the user passes on the command line, but we must take into account the boot areas. Signed-off-by: Joel Stanley Signed-off-by: Cédric Le Goater Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 4 1 file changed, 4 insertions(+) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 2d49be61f6..bbf054ea1e 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -804,6 +804,10 @@ static void sd_reset(DeviceState *dev) } size = sect << HWBLOCK_SHIFT; +if (sc->bootpart_offset) { +size -= sd_boot_capacity_bytes(sd) * 2; +} + sect = sd_addr_to_wpnum(size) + 1; sd->state = sd_idle_state; -- 2.41.0
[PATCH v42 87/98] hw/sd/sdcard: Fix SET_BLOCK_COUNT command argument on eMMC (CMD23)
From: Cédric Le Goater The number of blocks is defined in the lower bits [15:0]. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Cédric Le Goater Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 9 + 1 file changed, 9 insertions(+) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 2dc0209482..7c6f5ccc72 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -171,12 +171,18 @@ struct SDState { static void sd_realize(DeviceState *dev, Error **errp); static const SDProto sd_proto_spi; +static const SDProto sd_proto_emmc; static bool sd_is_spi(SDState *sd) { return sd->proto == &sd_proto_spi; } +static bool sd_is_emmc(SDState *sd) +{ +return sd->proto == &sd_proto_emmc; +} + static const char *sd_version_str(enum SDPhySpecificationVersion version) { static const char *sdphy_version[] = { @@ -1479,6 +1485,9 @@ static sd_rsp_type_t sd_cmd_SET_BLOCK_COUNT(SDState *sd, SDRequest req) } sd->multi_blk_cnt = req.arg; +if (sd_is_emmc(sd)) { +sd->multi_blk_cnt &= 0x; +} trace_sdcard_set_block_count(sd->multi_blk_cnt); return sd_r1; -- 2.41.0
[PATCH v42 68/98] hw/sd/sdcard: Add sd_acmd_SET_BUS_WIDTH handler (ACMD6)
Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 28 +++- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 2f853a89d1..0310a5a3a1 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -260,7 +260,6 @@ static const char *sd_cmd_name(SDState *sd, uint8_t cmd) static const char *sd_acmd_name(SDState *sd, uint8_t cmd) { static const char *acmd_abbrev[SDMMC_CMD_MAX] = { - [6] = "SET_BUS_WIDTH", [13] = "SD_STATUS", [14] = "DPS_spec", [15] = "DPS_spec", [16] = "DPS_spec", @@ -1672,6 +1671,18 @@ static sd_rsp_type_t spi_cmd_CRC_ON_OFF(SDState *sd, SDRequest req) return sd_r1; } +/* ACMD6 */ +static sd_rsp_type_t sd_acmd_SET_BUS_WIDTH(SDState *sd, SDRequest req) +{ +if (sd->state != sd_transfer_state) { +return sd_invalid_state_for_cmd(sd, req); +} + +sd->sd_status[0] &= 0x3f; +sd->sd_status[0] |= (req.arg & 0x03) << 6; +return sd_r1; +} + static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) { uint64_t addr; @@ -1780,18 +1791,6 @@ static sd_rsp_type_t sd_app_command(SDState *sd, } switch (req.cmd) { -case 6: /* ACMD6: SET_BUS_WIDTH */ -switch (sd->state) { -case sd_transfer_state: -sd->sd_status[0] &= 0x3f; -sd->sd_status[0] |= (req.arg & 0x03) << 6; -return sd_r1; - -default: -break; -} -break; - case 13: /* ACMD13: SD_STATUS */ switch (sd->state) { case sd_transfer_state: @@ -2385,6 +2384,9 @@ static const SDProto sd_proto_sd = { [58] = {11, sd_adtc, "READ_EXTR_MULTI", sd_cmd_optional}, [59] = {11, sd_adtc, "WRITE_EXTR_MULTI", sd_cmd_optional}, }, +.acmd = { +[6] = {8, sd_ac, "SET_BUS_WIDTH", sd_acmd_SET_BUS_WIDTH}, +}, }; static void sd_instance_init(Object *obj) -- 2.41.0
[PATCH v42 84/98] hw/sd/sdcard: Register unimplemented command handlers
Per the spec v4.5 these commands are mandatory, but we don't implement them. Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 6 ++ 1 file changed, 6 insertions(+) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index ebcd8c1e43..9a2bfeaab6 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -2385,24 +2385,30 @@ static const SDProto sd_proto_emmc = { .cmd = { [0] = {0, sd_bc, "GO_IDLE_STATE", sd_cmd_GO_IDLE_STATE}, [2] = {0, sd_bcr, "ALL_SEND_CID", sd_cmd_ALL_SEND_CID}, +[4] = {0, sd_bc, "SEND_DSR", sd_cmd_unimplemented}, [7] = {0, sd_ac, "(DE)SELECT_CARD", sd_cmd_DE_SELECT_CARD}, [9] = {0, sd_ac, "SEND_CSD", sd_cmd_SEND_CSD}, [10] = {0, sd_ac, "SEND_CID", sd_cmd_SEND_CID}, [12] = {0, sd_ac, "STOP_TRANSMISSION", sd_cmd_STOP_TRANSMISSION}, [13] = {0, sd_ac, "SEND_STATUS", sd_cmd_SEND_STATUS}, +[14] = {0, sd_adtc, "BUSTEST_R", sd_cmd_unimplemented}, [15] = {0, sd_ac, "GO_INACTIVE_STATE", sd_cmd_GO_INACTIVE_STATE}, [16] = {2, sd_ac, "SET_BLOCKLEN", sd_cmd_SET_BLOCKLEN}, [17] = {2, sd_adtc, "READ_SINGLE_BLOCK", sd_cmd_READ_SINGLE_BLOCK}, +[19] = {0, sd_adtc, "BUSTEST_W", sd_cmd_unimplemented}, [23] = {2, sd_ac, "SET_BLOCK_COUNT", sd_cmd_SET_BLOCK_COUNT}, [24] = {4, sd_adtc, "WRITE_SINGLE_BLOCK", sd_cmd_WRITE_SINGLE_BLOCK}, [27] = {4, sd_adtc, "PROGRAM_CSD", sd_cmd_PROGRAM_CSD}, [28] = {6, sd_ac, "SET_WRITE_PROT", sd_cmd_SET_WRITE_PROT}, [29] = {6, sd_ac, "CLR_WRITE_PROT", sd_cmd_CLR_WRITE_PROT}, [30] = {6, sd_adtc, "SEND_WRITE_PROT", sd_cmd_SEND_WRITE_PROT}, +[31] = {6, sd_adtc, "SEND_WRITE_PROT_TYPE", sd_cmd_unimplemented}, [35] = {5, sd_ac, "ERASE_WR_BLK_START", sd_cmd_ERASE_WR_BLK_START}, [36] = {5, sd_ac, "ERASE_WR_BLK_END", sd_cmd_ERASE_WR_BLK_END}, [38] = {5, sd_ac, "ERASE", sd_cmd_ERASE}, +[39] = {9, sd_ac, "FAST_IO", sd_cmd_unimplemented}, [42] = {7, sd_adtc, "LOCK_UNLOCK", sd_cmd_LOCK_UNLOCK}, +[49] = {0, sd_adtc, "SET_TIME", sd_cmd_unimplemented}, [55] = {8, sd_ac, "APP_CMD", sd_cmd_APP_CMD}, [56] = {8, sd_adtc, "GEN_CMD", sd_cmd_GEN_CMD}, }, -- 2.41.0
[RFC PATCH v42 98/98] hw/sd/sdcard: Add boot config support
From: Joel Stanley Introduced "boot-config" property to set CSD 179, the boot config register. With this correctly set we can use the enable bit to detect if partition support is enabled. Signed-off-by: Joel Stanley Signed-off-by: Cédric Le Goater Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 10 ++ 1 file changed, 10 insertions(+) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index bbf054ea1e..b598974bbf 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -129,6 +129,7 @@ struct SDState { uint8_t spec_version; BlockBackend *blk; bool aspeed_emmc_kludge; +uint8_t boot_config; const SDProto *proto; @@ -505,6 +506,8 @@ static void mmc_set_ext_csd(SDState *sd, uint64_t size) sd->ext_csd[159] = 0x00; /* Max enhanced area size */ sd->ext_csd[158] = 0x00; /* ... */ sd->ext_csd[157] = 0xEC; /* ... */ + +sd->ext_csd[EXT_CSD_PART_CONFIG] = sd->boot_config; } static void sd_emmc_set_csd(SDState *sd, uint64_t size) @@ -1004,8 +1007,14 @@ static uint32_t sd_emmc_bootpart_offset(SDState *sd) { unsigned int access = sd->ext_csd[EXT_CSD_PART_CONFIG] & EXT_CSD_PART_CONFIG_ACC_MASK; +unsigned int enable = sd->ext_csd[EXT_CSD_PART_CONFIG] & + EXT_CSD_PART_CONFIG_EN_MASK; unsigned int boot_capacity = sd_boot_capacity_bytes(sd); +if (!enable) { +return 0; +} + switch (access) { case EXT_CSD_PART_CONFIG_ACC_DEFAULT: return boot_capacity * 2; @@ -2808,6 +2817,7 @@ 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_UINT8("boot-config", SDState, boot_config, 0x0), DEFINE_PROP_END_OF_LIST() }; -- 2.41.0
[PATCH v42 78/98] hw/sd/sdcard: Remove default case in read/write on DAT lines
All read/write on DAT lines are explicitly handled. Reaching this point would be a programming error: replace by an assertion. Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 9 - 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 0a7b422b2c..64621d4340 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1951,7 +1951,6 @@ int sd_do_command(SDState *sd, SDRequest *req, /* Valid command, we can update the 'state before command' bits. * (Do this now so they appear in r1 responses.) */ -sd->current_cmd = req->cmd; sd->card_status = FIELD_DP32(sd->card_status, CSR, CURRENT_STATE, last_state); } @@ -2016,6 +2015,8 @@ send_response: qemu_hexdump(stderr, "Response", response, rsplen); #endif +sd->current_cmd = rtype == sd_illegal ? 0 : req->cmd; + return rsplen; } @@ -2171,8 +2172,7 @@ void sd_write_byte(SDState *sd, uint8_t value) break; default: -qemu_log_mask(LOG_GUEST_ERROR, "%s: unknown command\n", __func__); -break; +g_assert_not_reached(); } } @@ -2238,8 +2238,7 @@ uint8_t sd_read_byte(SDState *sd) break; default: -qemu_log_mask(LOG_GUEST_ERROR, "%s: unknown command\n", __func__); -return 0x00; +g_assert_not_reached(); } return ret; -- 2.41.0
[PATCH v42 76/98] hw/sd/sdcard: Remove noise from sd_acmd_name()
These ACMD names weren't really useful, "UNKNOWN_ACMD" is simpler. Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 12 +--- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 7f93d363c7..19322c558f 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -259,23 +259,13 @@ static const char *sd_cmd_name(SDState *sd, uint8_t cmd) static const char *sd_acmd_name(SDState *sd, uint8_t cmd) { -static const char *acmd_abbrev[SDMMC_CMD_MAX] = { -[14] = "DPS_spec", [15] = "DPS_spec", -[16] = "DPS_spec", -[18] = "SECU_spec", -[52] = "SECU_spec", [53] = "SECU_spec", -[54] = "SECU_spec", -[56] = "SECU_spec", [57] = "SECU_spec", -[58] = "SECU_spec", [59] = "SECU_spec", -}; const SDProto *sdp = sd->proto; if (sdp->acmd[cmd].handler) { -assert(!acmd_abbrev[cmd]); return sdp->acmd[cmd].name; } -return acmd_abbrev[cmd] ? acmd_abbrev[cmd] : "UNKNOWN_ACMD"; +return "UNKNOWN_ACMD"; } static uint8_t sd_get_dat_lines(SDState *sd) -- 2.41.0
[PATCH v42 72/98] hw/sd/sdcard: Add sd_acmd_SD_APP_OP_COND handler (ACMD41)
Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 82 ++ 1 file changed, 45 insertions(+), 37 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index cd207a3090..167e1c517a 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1704,6 +1704,50 @@ static sd_rsp_type_t sd_acmd_SET_WR_BLK_ERASE_COUNT(SDState *sd, SDRequest req) return sd_r1; } +/* ACMD41 */ +static sd_rsp_type_t sd_acmd_SD_APP_OP_COND(SDState *sd, SDRequest req) +{ +if (sd->state != sd_idle_state) { +return sd_invalid_state_for_cmd(sd, req); +} + +/* + * If it's the first ACMD41 since reset, we need to decide + * whether to power up. If this is not an enquiry ACMD41, + * we immediately report power on and proceed below to the + * ready state, but if it is, we set a timer to model a + * delay for power up. This works around a bug in EDK2 + * UEFI, which sends an initial enquiry ACMD41, but + * assumes that the card is in ready state as soon as it + * sees the power up bit set. + */ +if (!FIELD_EX32(sd->ocr, OCR, CARD_POWER_UP)) { +if ((req.arg & ACMD41_ENQUIRY_MASK) != 0) { +timer_del(sd->ocr_power_timer); +sd_ocr_powerup(sd); +} else { +trace_sdcard_inquiry_cmd41(); +if (!timer_pending(sd->ocr_power_timer)) { +timer_mod_ns(sd->ocr_power_timer, + (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + + OCR_POWER_DELAY_NS)); +} +} +} + +if (FIELD_EX32(sd->ocr & req.arg, OCR, VDD_VOLTAGE_WINDOW)) { +/* + * We accept any voltage. 1 V is nothing. + * + * Once we're powered up, we advance straight to ready state + * unless it's an enquiry ACMD41 (bits 23:0 == 0). + */ +sd->state = sd_ready_state; +} + +return sd_r3; +} + static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) { uint64_t addr; @@ -1812,43 +1856,6 @@ static sd_rsp_type_t sd_app_command(SDState *sd, } switch (req.cmd) { -case 41: /* ACMD41: SD_APP_OP_COND */ -if (sd->state != sd_idle_state) { -break; -} -/* If it's the first ACMD41 since reset, we need to decide - * whether to power up. If this is not an enquiry ACMD41, - * we immediately report power on and proceed below to the - * ready state, but if it is, we set a timer to model a - * delay for power up. This works around a bug in EDK2 - * UEFI, which sends an initial enquiry ACMD41, but - * assumes that the card is in ready state as soon as it - * sees the power up bit set. */ -if (!FIELD_EX32(sd->ocr, OCR, CARD_POWER_UP)) { -if ((req.arg & ACMD41_ENQUIRY_MASK) != 0) { -timer_del(sd->ocr_power_timer); -sd_ocr_powerup(sd); -} else { -trace_sdcard_inquiry_cmd41(); -if (!timer_pending(sd->ocr_power_timer)) { -timer_mod_ns(sd->ocr_power_timer, - (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - + OCR_POWER_DELAY_NS)); -} -} -} - -if (FIELD_EX32(sd->ocr & req.arg, OCR, VDD_VOLTAGE_WINDOW)) { -/* We accept any voltage. 1 V is nothing. - * - * Once we're powered up, we advance straight to ready state - * unless it's an enquiry ACMD41 (bits 23:0 == 0). - */ -sd->state = sd_ready_state; -} - -return sd_r3; - case 42: /* ACMD42: SET_CLR_CARD_DETECT */ switch (sd->state) { case sd_transfer_state: @@ -2379,6 +2386,7 @@ static const SDProto sd_proto_sd = { [13] = {8, sd_adtc, "SD_STATUS", sd_acmd_SD_STATUS}, [22] = {8, sd_adtc, "SEND_NUM_WR_BLOCKS", sd_acmd_SEND_NUM_WR_BLOCKS}, [23] = {8, sd_ac, "SET_WR_BLK_ERASE_COUNT", sd_acmd_SET_WR_BLK_ERASE_COUNT}, +[41] = {8, sd_bcr, "SD_APP_OP_COND", sd_acmd_SD_APP_OP_COND}, }, }; -- 2.41.0
Re: [PATCH 02/14] hw/ide: Free macio-ide IRQs
On 26/06/2024 13:59, Peter Maydell wrote: On Wed, 26 Jun 2024 at 12:09, Akihiko Odaki wrote: This suppresses LeakSanitizer warnings. Signed-off-by: Akihiko Odaki --- hw/ide/macio.c | 9 + 1 file changed, 9 insertions(+) diff --git a/hw/ide/macio.c b/hw/ide/macio.c index aca90d04f0e8..d8fbc1a17ba6 100644 --- a/hw/ide/macio.c +++ b/hw/ide/macio.c @@ -464,6 +464,14 @@ static void macio_ide_initfn(Object *obj) qdev_prop_allow_set_link_before_realize, 0); } +static void macio_ide_finalize(Object *obj) +{ +MACIOIDEState *s = MACIO_IDE(obj); + +qemu_free_irq(s->dma_irq); +qemu_free_irq(s->ide_irq); +} + static Property macio_ide_properties[] = { DEFINE_PROP_UINT32("channel", MACIOIDEState, channel, 0), DEFINE_PROP_UINT32("addr", MACIOIDEState, addr, -1), @@ -486,6 +494,7 @@ static const TypeInfo macio_ide_type_info = { .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MACIOIDEState), .instance_init = macio_ide_initfn, +.instance_finalize = macio_ide_finalize, .class_init = macio_ide_class_init, }; Rather than this, I suspect macio_ide_initfn() should not be using qemu_allocate_irq() in the first place. Looks like maybe a QOM conversion that left a loose end un-tidied-up. This is definitely old code: there used to be problems interfacing the IDE code with qdev due to the hard-coded bus IRQs but I think this may is now possible with the advent of ide_bus_init_output_irq(). I'll have a quick look and see what has changed in this area. ATB, Mark.
[PATCH v42 82/98] hw/sd/sdcard: Basis for eMMC support
From: Philippe Mathieu-Daudé Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Cédric Le Goater Signed-off-by: Philippe Mathieu-Daudé --- include/hw/sd/sd.h | 3 +++ hw/sd/sd.c | 34 ++ 2 files changed, 37 insertions(+) diff --git a/include/hw/sd/sd.h b/include/hw/sd/sd.h index 0d6d9e452b..d35a839f5e 100644 --- a/include/hw/sd/sd.h +++ b/include/hw/sd/sd.h @@ -96,6 +96,9 @@ OBJECT_DECLARE_TYPE(SDState, SDCardClass, SD_CARD) #define TYPE_SD_CARD_SPI "sd-card-spi" DECLARE_INSTANCE_CHECKER(SDState, SD_CARD_SPI, TYPE_SD_CARD_SPI) +#define TYPE_EMMC "emmc" +DECLARE_INSTANCE_CHECKER(SDState, EMMC, TYPE_EMMC) + struct SDCardClass { /*< private >*/ DeviceClass parent_class; diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 92ac57a648..249fad0468 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -2379,6 +2379,13 @@ static const SDProto sd_proto_sd = { }, }; +static const SDProto sd_proto_emmc = { +/* Only v4.5 is supported */ +.name = "eMMC", +.cmd = { +}, +}; + static void sd_instance_init(Object *obj) { SDState *sd = SD_CARD(obj); @@ -2504,6 +2511,28 @@ static void sd_spi_class_init(ObjectClass *klass, void *data) sc->proto = &sd_proto_spi; } +static void emmc_realize(DeviceState *dev, Error **errp) +{ +SDState *sd = SD_CARD(dev); + +if (sd->spec_version == SD_PHY_SPECv2_00_VERS) { +error_setg(errp, "eMMC can not use spec v2.00"); +return; +} + +sd_realize(dev, errp); +} + +static void emmc_class_init(ObjectClass *klass, void *data) +{ +DeviceClass *dc = DEVICE_CLASS(klass); +SDCardClass *sc = SD_CARD_CLASS(klass); + +dc->desc = "eMMC"; +dc->realize = emmc_realize; +sc->proto = &sd_proto_emmc; +} + static const TypeInfo sd_types[] = { { .name = TYPE_SD_CARD, @@ -2519,6 +2548,11 @@ static const TypeInfo sd_types[] = { .parent = TYPE_SD_CARD, .class_init = sd_spi_class_init, }, +{ +.name = TYPE_EMMC, +.parent = TYPE_SD_CARD, +.class_init = emmc_class_init, +}, }; DEFINE_TYPES(sd_types) -- 2.41.0
[RFC PATCH v42 86/98] hw/sd/sdcard: Add emmc_cmd_SEND_OP_COND handler (CMD1)
From: Sai Pavan Boddu Add support to Power up the card and send response r3 in case of MMC. Signed-off-by: Sai Pavan Boddu Signed-off-by: Edgar E. Iglesias Signed-off-by: Cédric Le Goater Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 7 +++ 1 file changed, 7 insertions(+) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index c6e5c93acb..2dc0209482 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1190,6 +1190,12 @@ static sd_rsp_type_t spi_cmd_SEND_OP_COND(SDState *sd, SDRequest req) return sd_r1; } +static sd_rsp_type_t emmc_cmd_SEND_OP_COND(SDState *sd, SDRequest req) +{ +sd_ocr_powerup(sd); +return sd->state == sd_idle_state ? sd_r3 : sd_r0; +} + /* CMD2 */ static sd_rsp_type_t sd_cmd_ALL_SEND_CID(SDState *sd, SDRequest req) { @@ -2398,6 +2404,7 @@ static const SDProto sd_proto_emmc = { .name = "eMMC", .cmd = { [0] = {0, sd_bc, "GO_IDLE_STATE", sd_cmd_GO_IDLE_STATE}, +[1] = {0, sd_bcr, "SEND_OP_COND", emmc_cmd_SEND_OP_COND}, [2] = {0, sd_bcr, "ALL_SEND_CID", sd_cmd_ALL_SEND_CID}, [3] = {0, sd_ac, "SET_RELATIVE_ADDR", emmc_cmd_SET_RELATIVE_ADDR}, [4] = {0, sd_bc, "SEND_DSR", sd_cmd_unimplemented}, -- 2.41.0
[PATCH v42 67/98] hw/sd/sdcard: Add spi_cmd_CRC_ON_OFF handler (CMD59)
Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 11 +++ 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index b3b4cd5a3a..2f853a89d1 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1666,6 +1666,12 @@ static sd_rsp_type_t spi_cmd_READ_OCR(SDState *sd, SDRequest req) return sd_r3; } +/* CMD59 */ +static sd_rsp_type_t spi_cmd_CRC_ON_OFF(SDState *sd, SDRequest req) +{ +return sd_r1; +} + static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) { uint64_t addr; @@ -1753,10 +1759,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) case 26: /* CMD26: PROGRAM_CID */ return sd_cmd_to_receivingdata(sd, req, 0, sizeof(sd->cid)); -/* Application specific commands (Class 8) */ -case 59:/* CMD59: CRC_ON_OFF (SPI) */ -return sd_r1; - default: qemu_log_mask(LOG_GUEST_ERROR, "SD: Unknown CMD%i\n", req.cmd); return sd_illegal; @@ -2325,6 +2327,7 @@ static const SDProto sd_proto_spi = { [56] = {8, sd_spi, "GEN_CMD", sd_cmd_GEN_CMD}, [57] = {10, sd_spi, "DIRECT_SECURE_WRITE", sd_cmd_optional}, [58] = {0, sd_spi, "READ_OCR", spi_cmd_READ_OCR}, +[59] = {0, sd_spi, "CRC_ON_OFF", spi_cmd_CRC_ON_OFF}, }, .acmd = { [41] = {8, sd_spi, "SEND_OP_COND", spi_cmd_SEND_OP_COND}, -- 2.41.0
[PATCH v42 59/98] hw/sd/sdcard: Add sd_cmd_SET/CLR_WRITE_PROT handler (CMD28 & CMD29)
Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 91 +++--- 1 file changed, 46 insertions(+), 45 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 9d33113f11..a63213613b 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -244,7 +244,6 @@ static const char *sd_cmd_name(SDState *sd, uint8_t cmd) [21]= "DPS_spec", [25]= "WRITE_MULTIPLE_BLOCK", [26]= "MANUF_RSVD", -[28]= "SET_WRITE_PROT", [29]= "CLR_WRITE_PROT", [30]= "SEND_WRITE_PROT", [32]= "ERASE_WR_BLK_START", [33]= "ERASE_WR_BLK_END", [38]= "ERASE", @@ -1520,6 +1519,48 @@ static sd_rsp_type_t sd_cmd_PROGRAM_CSD(SDState *sd, SDRequest req) return sd_cmd_to_receivingdata(sd, req, 0, sizeof(sd->csd)); } +static sd_rsp_type_t sd_cmd_SET_CLR_WRITE_PROT(SDState *sd, SDRequest req, + bool is_write) +{ +uint64_t addr; + +if (sd->size > SDSC_MAX_CAPACITY) { +return sd_illegal; +} + +if (sd->state != sd_transfer_state) { +return sd_invalid_state_for_cmd(sd, req); +} + +addr = sd_req_get_address(sd, req); +if (!address_in_range(sd, is_write ? "SET_WRITE_PROT" : "CLR_WRITE_PROT", + addr, 1)) { +return sd_r1b; +} + +sd->state = sd_programming_state; +if (is_write) { +set_bit(sd_addr_to_wpnum(addr), sd->wp_group_bmap); +} else { +clear_bit(sd_addr_to_wpnum(addr), sd->wp_group_bmap); +} +/* Bzzztt Operation complete. */ +sd->state = sd_transfer_state; +return sd_r1; +} + +/* CMD28 */ +static sd_rsp_type_t sd_cmd_SET_WRITE_PROT(SDState *sd, SDRequest req) +{ +return sd_cmd_SET_CLR_WRITE_PROT(sd, req, true); +} + +/* CMD29 */ +static sd_rsp_type_t sd_cmd_CLR_WRITE_PROT(SDState *sd, SDRequest req) +{ +return sd_cmd_SET_CLR_WRITE_PROT(sd, req, false); +} + static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) { uint16_t rca; @@ -1610,50 +1651,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) return sd_cmd_to_receivingdata(sd, req, 0, sizeof(sd->cid)); /* Write protection (Class 6) */ -case 28: /* CMD28: SET_WRITE_PROT */ -if (sd->size > SDSC_MAX_CAPACITY) { -return sd_illegal; -} -addr = sd_req_get_address(sd, req); -switch (sd->state) { -case sd_transfer_state: -if (!address_in_range(sd, "SET_WRITE_PROT", addr, 1)) { -return sd_r1b; -} - -sd->state = sd_programming_state; -set_bit(sd_addr_to_wpnum(addr), sd->wp_group_bmap); -/* Bzzztt Operation complete. */ -sd->state = sd_transfer_state; -return sd_r1b; - -default: -break; -} -break; - -case 29: /* CMD29: CLR_WRITE_PROT */ -if (sd->size > SDSC_MAX_CAPACITY) { -return sd_illegal; -} -addr = sd_req_get_address(sd, req); -switch (sd->state) { -case sd_transfer_state: -if (!address_in_range(sd, "CLR_WRITE_PROT", addr, 1)) { -return sd_r1b; -} - -sd->state = sd_programming_state; -clear_bit(sd_addr_to_wpnum(addr), sd->wp_group_bmap); -/* Bzzztt Operation complete. */ -sd->state = sd_transfer_state; -return sd_r1b; - -default: -break; -} -break; - case 30: /* CMD30: SEND_WRITE_PROT */ if (sd->size > SDSC_MAX_CAPACITY) { return sd_illegal; @@ -2314,6 +2311,8 @@ static const SDProto sd_proto_spi = { [17] = {2, sd_spi, "READ_SINGLE_BLOCK", sd_cmd_READ_SINGLE_BLOCK}, [24] = {4, sd_spi, "WRITE_SINGLE_BLOCK", sd_cmd_WRITE_SINGLE_BLOCK}, [27] = {4, sd_spi, "PROGRAM_CSD", sd_cmd_PROGRAM_CSD}, +[28] = {6, sd_spi, "SET_WRITE_PROT", sd_cmd_SET_WRITE_PROT}, +[29] = {6, sd_spi, "CLR_WRITE_PROT", sd_cmd_CLR_WRITE_PROT}, [34] = {10, sd_spi, "READ_SEC_CMD", sd_cmd_optional}, [35] = {10, sd_spi, "WRITE_SEC_CMD", sd_cmd_optional}, [36] = {10, sd_spi, "SEND_PSI", sd_cmd_optional}, @@ -2352,6 +2351,8 @@ static const SDProto sd_proto_sd = { [23] = {2, sd_ac, "SET_BLOCK_COUNT", sd_cmd_SET_BLOCK_COUNT}, [24] = {4, sd_adtc, "WRITE_SINGLE_BLOCK", sd_cmd_WRITE_SINGLE_BLOCK}, [27] = {4, sd_adtc, "PROGRAM_CSD", sd_cmd_PROGRAM_CSD}, +[28] = {6, sd_ac, "SET_WRITE_PROT", sd_cmd_SET_WRITE_PROT}, +[29] = {6, sd_ac, "CLR_WRITE_PROT", sd_cmd_CLR_WRITE_PROT}, [34] = {10, sd_adtc, "READ_SEC_CMD", sd_cmd_optional}, [35] = {10, sd_adtc, "WRITE_SEC_CMD", sd_cmd_optional}, [36] = {10, sd_adtc, "SEND_P
[PATCH v42 80/98] hw/sd/sdcard: Introduce set_csd/set_cid handlers
In preparation of introducing eMMC support which have different CSD/CID structures, introduce a pair of handlers in SDCardClass. Signed-off-by: Philippe Mathieu-Daudé --- include/hw/sd/sd.h | 2 ++ hw/sd/sd.c | 7 +-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/include/hw/sd/sd.h b/include/hw/sd/sd.h index c1a35ab420..0d6d9e452b 100644 --- a/include/hw/sd/sd.h +++ b/include/hw/sd/sd.h @@ -127,6 +127,8 @@ struct SDCardClass { void (*enable)(SDState *sd, bool enable); bool (*get_inserted)(SDState *sd); bool (*get_readonly)(SDState *sd); +void (*set_cid)(SDState *sd); +void (*set_csd)(SDState *sd, uint64_t size); const struct SDProto *proto; }; diff --git a/hw/sd/sd.c b/hw/sd/sd.c index a0da06e017..b0ef252001 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -671,6 +671,7 @@ static inline uint64_t sd_addr_to_wpnum(uint64_t addr) static void sd_reset(DeviceState *dev) { SDState *sd = SD_CARD(dev); +SDCardClass *sc = SD_CARD_GET_CLASS(sd); uint64_t size; uint64_t sect; @@ -691,8 +692,8 @@ static void sd_reset(DeviceState *dev) sd->size = size; sd_set_ocr(sd); sd_set_scr(sd); -sd_set_cid(sd); -sd_set_csd(sd, size); +sc->set_cid(sd); +sc->set_csd(sd, size); sd_set_cardstatus(sd); sd_set_sdstatus(sd); @@ -2472,6 +2473,8 @@ 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->set_cid = sd_set_cid; +sc->set_csd = sd_set_csd; sc->proto = &sd_proto_sd; } -- 2.41.0
[PATCH v42 70/98] hw/sd/sdcard: Add sd_acmd_SEND_NUM_WR_BLOCKS handler (ACMD22)
Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 23 ++- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 5323a42df2..9d66c3715a 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -263,7 +263,7 @@ static const char *sd_acmd_name(SDState *sd, uint8_t cmd) [14] = "DPS_spec", [15] = "DPS_spec", [16] = "DPS_spec", [18] = "SECU_spec", -[22] = "SEND_NUM_WR_BLOCKS",[23] = "SET_WR_BLK_ERASE_COUNT", +[23] = "SET_WR_BLK_ERASE_COUNT", [42] = "SET_CLR_CARD_DETECT", [51] = "SEND_SCR", [52] = "SECU_spec", [53] = "SECU_spec", @@ -1689,6 +1689,13 @@ static sd_rsp_type_t sd_acmd_SD_STATUS(SDState *sd, SDRequest req) sd->sd_status, sizeof(sd->sd_status)); } +/* ACMD22 */ +static sd_rsp_type_t sd_acmd_SEND_NUM_WR_BLOCKS(SDState *sd, SDRequest req) +{ +return sd_cmd_to_sendingdata(sd, req, 0, + &sd->blk_written, sizeof(sd->blk_written)); +} + static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) { uint64_t addr; @@ -1797,18 +1804,6 @@ static sd_rsp_type_t sd_app_command(SDState *sd, } switch (req.cmd) { -case 22: /* ACMD22: SEND_NUM_WR_BLOCKS */ -switch (sd->state) { -case sd_transfer_state: -return sd_cmd_to_sendingdata(sd, req, 0, - &sd->blk_written, - sizeof(sd->blk_written)); - -default: -break; -} -break; - case 23: /* ACMD23: SET_WR_BLK_ERASE_COUNT */ switch (sd->state) { case sd_transfer_state: @@ -2324,6 +2319,7 @@ static const SDProto sd_proto_spi = { }, .acmd = { [13] = {8, sd_spi, "SD_STATUS", sd_acmd_SD_STATUS}, +[22] = {8, sd_spi, "SEND_NUM_WR_BLOCKS", sd_acmd_SEND_NUM_WR_BLOCKS}, [41] = {8, sd_spi, "SEND_OP_COND", spi_cmd_SEND_OP_COND}, }, }; @@ -2382,6 +2378,7 @@ static const SDProto sd_proto_sd = { .acmd = { [6] = {8, sd_ac, "SET_BUS_WIDTH", sd_acmd_SET_BUS_WIDTH}, [13] = {8, sd_adtc, "SD_STATUS", sd_acmd_SD_STATUS}, +[22] = {8, sd_adtc, "SEND_NUM_WR_BLOCKS", sd_acmd_SEND_NUM_WR_BLOCKS}, }, }; -- 2.41.0
[PATCH v42 49/98] hw/sd/sdcard: Add sd_cmd_SEND_IF_COND handler (CMD8)
Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 43 --- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 6ad98db981..e2f7e99ea2 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -240,7 +240,7 @@ static const char *sd_response_name(sd_rsp_type_t rsp) static const char *sd_cmd_name(SDState *sd, uint8_t cmd) { static const char *cmd_abbrev[SDMMC_CMD_MAX] = { - [8]= "SEND_IF_COND",[9]= "SEND_CSD", + [9]= "SEND_CSD", [10]= "SEND_CID", [12]= "STOP_TRANSMISSION", [13]= "SEND_STATUS", [15]= "GO_INACTIVE_STATE", @@ -1303,6 +1303,27 @@ static sd_rsp_type_t sd_cmd_DE_SELECT_CARD(SDState *sd, SDRequest req) return sd_invalid_state_for_cmd(sd, 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); +} +sd->vhs = 0; + +/* No response if not exactly one VHS bit is set. */ +if (!(req.arg >> 8) || (req.arg >> (ctz32(req.arg & ~0xff) + 1))) { +return sd_is_spi(sd) ? sd_r7 : sd_r0; +} + +/* Accept. */ +sd->vhs = req.arg; +return sd_r7; +} + /* CMD19 */ static sd_rsp_type_t sd_cmd_SEND_TUNING_BLOCK(SDState *sd, SDRequest req) { @@ -1369,24 +1390,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) switch (req.cmd) { /* Basic commands (Class 0 and Class 1) */ -case 8: /* CMD8: SEND_IF_COND */ -if (sd->spec_version < SD_PHY_SPECv2_00_VERS) { -break; -} -if (sd->state != sd_idle_state) { -break; -} -sd->vhs = 0; - -/* No response if not exactly one VHS bit is set. */ -if (!(req.arg >> 8) || (req.arg >> (ctz32(req.arg & ~0xff) + 1))) { -return sd_is_spi(sd) ? sd_r7 : sd_r0; -} - -/* Accept. */ -sd->vhs = req.arg; -return sd_r7; - case 9: /* CMD9: SEND_CSD */ rca = sd_req_get_rca(sd, req); switch (sd->state) { @@ -2278,6 +2281,7 @@ static const SDProto sd_proto_spi = { [1] = {0, sd_spi, "SEND_OP_COND", spi_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}, [34] = {10, sd_spi, "READ_SEC_CMD", sd_cmd_optional}, [35] = {10, sd_spi, "WRITE_SEC_CMD", sd_cmd_optional}, [36] = {10, sd_spi, "SEND_PSI", sd_cmd_optional}, @@ -2302,6 +2306,7 @@ static const SDProto sd_proto_sd = { [5] = {9, sd_bc, "IO_SEND_OP_COND", sd_cmd_optional}, [6] = {10, sd_adtc, "SWITCH_FUNCTION", sd_cmd_SWITCH_FUNCTION}, [7] = {0, sd_ac, "(DE)SELECT_CARD", sd_cmd_DE_SELECT_CARD}, +[8] = {0, sd_bcr, "SEND_IF_COND", sd_cmd_SEND_IF_COND}, [11] = {0, sd_ac, "VOLTAGE_SWITCH", sd_cmd_optional}, [19] = {2, sd_adtc, "SEND_TUNING_BLOCK", sd_cmd_SEND_TUNING_BLOCK}, [20] = {2, sd_ac, "SPEED_CLASS_CONTROL", sd_cmd_optional}, -- 2.41.0
[PATCH v42 95/98] hw/sd/sdcard: Add mmc SWITCH function support (CMD6)
From: Sai Pavan Boddu switch operation in mmc cards, updated the ext_csd register to request changes in card operations. Here we implement similar sequence but requests are mostly dummy and make no change. Implement SWITCH_ERROR if the write operation offset goes beyond length of ext_csd. Signed-off-by: Sai Pavan Boddu Signed-off-by: Edgar E. Iglesias Signed-off-by: Cédric Le Goater Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 52 1 file changed, 52 insertions(+) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index ae5e73175e..e7d8b9c0fb 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -625,6 +625,7 @@ static bool sd_req_rca_same(SDState *s, SDRequest req) FIELD(CSR, AKE_SEQ_ERROR, 3, 1) FIELD(CSR, APP_CMD, 5, 1) FIELD(CSR, FX_EVENT,6, 1) +FIELD(CSR, SWITCH_ERROR,7, 1) FIELD(CSR, READY_FOR_DATA, 8, 1) FIELD(CSR, CURRENT_STATE, 9, 4) FIELD(CSR, ERASE_RESET,13, 1) @@ -1075,6 +1076,43 @@ static uint32_t sd_wpbits(SDState *sd, uint64_t addr) return ret; } +enum { +MMC_CMD6_ACCESS_COMMAND_SET = 0, +MMC_CMD6_ACCESS_SET_BITS, +MMC_CMD6_ACCESS_CLEAR_BITS, +MMC_CMD6_ACCESS_WRITE_BYTE, +}; + +static void mmc_function_switch(SDState *sd, uint32_t arg) +{ +uint32_t access = extract32(arg, 24, 2); +uint32_t index = extract32(arg, 16, 8); +uint32_t value = extract32(arg, 8, 8); +uint8_t b = sd->ext_csd[index]; + +switch (access) { +case MMC_CMD6_ACCESS_COMMAND_SET: +qemu_log_mask(LOG_UNIMP, "MMC Command set switching not supported\n"); +return; +case MMC_CMD6_ACCESS_SET_BITS: +b |= value; +break; +case MMC_CMD6_ACCESS_CLEAR_BITS: +b &= ~value; +break; +case MMC_CMD6_ACCESS_WRITE_BYTE: +b = value; +break; +} + +if (index >= 192) { +sd->card_status |= R_CSR_SWITCH_ERROR_MASK; +return; +} + +sd->ext_csd[index] = b; +} + static void sd_function_switch(SDState *sd, uint32_t arg) { int i, mode, new_func; @@ -1398,6 +1436,19 @@ static sd_rsp_type_t sd_cmd_SWITCH_FUNCTION(SDState *sd, SDRequest req) return sd_cmd_to_sendingdata(sd, req, 0, NULL, 64); } +static sd_rsp_type_t emmc_cmd_SWITCH(SDState *sd, SDRequest req) +{ +switch (sd->state) { +case sd_transfer_state: +sd->state = sd_programming_state; +mmc_function_switch(sd, req.arg); +sd->state = sd_transfer_state; +return sd_r1b; +default: +return sd_invalid_state_for_cmd(sd, req); +} +} + /* CMD7 */ static sd_rsp_type_t sd_cmd_DE_SELECT_CARD(SDState *sd, SDRequest req) { @@ -2602,6 +2653,7 @@ static const SDProto sd_proto_emmc = { [3] = {0, sd_ac, "SET_RELATIVE_ADDR", emmc_cmd_SET_RELATIVE_ADDR}, [4] = {0, sd_bc, "SEND_DSR", sd_cmd_unimplemented}, [5] = {0, sd_ac, "SLEEP/AWAKE", emmc_cmd_sleep_awake}, +[6] = {10, sd_adtc, "SWITCH", emmc_cmd_SWITCH}, [7] = {0, sd_ac, "(DE)SELECT_CARD", sd_cmd_DE_SELECT_CARD}, [8] = {0, sd_adtc, "SEND_EXT_CSD", emmc_cmd_SEND_EXT_CSD}, [9] = {0, sd_ac, "SEND_CSD", sd_cmd_SEND_CSD}, -- 2.41.0
[PATCH v42 45/98] hw/sd/sdcard: Register SDIO optional handlers
See "SD Input/Output Card Specification" v1.00. Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 8 ++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 406fadb3b4..87bfd0fd56 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -240,7 +240,6 @@ static const char *sd_response_name(sd_rsp_type_t rsp) static const char *sd_cmd_name(SDState *sd, uint8_t cmd) { static const char *cmd_abbrev[SDMMC_CMD_MAX] = { - [5]= "IO_SEND_OP_COND", [6]= "SWITCH_FUNC", [7]= "SELECT/DESELECT_CARD", [8]= "SEND_IF_COND",[9]= "SEND_CSD", [10]= "SEND_CID", @@ -260,7 +259,6 @@ static const char *sd_cmd_name(SDState *sd, uint8_t cmd) [40]= "DPS_spec", [42]= "LOCK_UNLOCK", [50]= "SW_FUNC_RSVD", -[52]= "IO_RW_DIRECT", [53]= "IO_RW_EXTENDED", [54]= "SDIO_RSVD", [55]= "APP_CMD", [56]= "GEN_CMD",[57]= "SW_FUNC_RSVD", [60]= "MANUF_RSVD", [61]= "MANUF_RSVD", @@ -2270,6 +2268,9 @@ static const SDProto sd_proto_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}, +[5] = {9, sd_spi, "IO_SEND_OP_COND", sd_cmd_optional}, +[52] = {9, sd_spi, "IO_RW_DIRECT", sd_cmd_optional}, +[53] = {9, sd_spi, "IO_RW_EXTENDED", sd_cmd_optional}, }, .acmd = { [41] = {8, sd_spi, "SEND_OP_COND", spi_cmd_SEND_OP_COND}, @@ -2283,6 +2284,7 @@ static const SDProto sd_proto_sd = { [2] = {0, sd_bcr, "ALL_SEND_CID", sd_cmd_ALL_SEND_CID}, [3] = {0, sd_bcr, "SEND_RELATIVE_ADDR", sd_cmd_SEND_RELATIVE_ADDR}, [4] = {0, sd_bc, "SEND_DSR", sd_cmd_unimplemented}, +[5] = {9, sd_bc, "IO_SEND_OP_COND", sd_cmd_optional}, [11] = {0, sd_ac, "VOLTAGE_SWITCH", sd_cmd_optional}, [19] = {2, sd_adtc, "SEND_TUNING_BLOCK", sd_cmd_SEND_TUNING_BLOCK}, [20] = {2, sd_ac, "SPEED_CLASS_CONTROL", sd_cmd_optional}, @@ -2294,6 +2296,8 @@ static const SDProto sd_proto_sd = { [47] = {1, sd_adtc, "Q_WR_TASK", sd_cmd_optional}, [48] = {1, sd_adtc, "READ_EXTR_SINGLE", sd_cmd_optional}, [49] = {1, sd_adtc, "WRITE_EXTR_SINGLE", sd_cmd_optional}, +[52] = {9, sd_bc, "IO_RW_DIRECT", sd_cmd_optional}, +[53] = {9, sd_bc, "IO_RW_EXTENDED", sd_cmd_optional}, [58] = {11, sd_adtc, "READ_EXTR_MULTI", sd_cmd_optional}, [59] = {11, sd_adtc, "WRITE_EXTR_MULTI", sd_cmd_optional}, }, -- 2.41.0
[PATCH v42 57/98] hw/sd/sdcard: Add sd_cmd_WRITE_SINGLE_BLOCK handler (CMD24)
Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 57 -- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index e2a7ed8b45..4650d20ee7 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -242,7 +242,7 @@ static const char *sd_cmd_name(SDState *sd, uint8_t cmd) static const char *cmd_abbrev[SDMMC_CMD_MAX] = { [18]= "READ_MULTIPLE_BLOCK", [21]= "DPS_spec", -[24]= "WRITE_BLOCK",[25]= "WRITE_MULTIPLE_BLOCK", +[25]= "WRITE_MULTIPLE_BLOCK", [26]= "MANUF_RSVD", [27]= "PROGRAM_CSD", [28]= "SET_WRITE_PROT", [29]= "CLR_WRITE_PROT", [30]= "SEND_WRITE_PROT", @@ -1487,6 +1487,33 @@ static sd_rsp_type_t sd_cmd_SET_BLOCK_COUNT(SDState *sd, SDRequest req) return sd_r1; } +/* CMD24 */ +static sd_rsp_type_t sd_cmd_WRITE_SINGLE_BLOCK(SDState *sd, SDRequest req) +{ +uint64_t addr; + +if (sd->state != sd_transfer_state) { +return sd_invalid_state_for_cmd(sd, req); +} + +addr = sd_req_get_address(sd, req); +if (!address_in_range(sd, "WRITE_SINGLE_BLOCK", addr, sd->blk_len)) { +return sd_r1; +} + +if (sd->size <= SDSC_MAX_CAPACITY) { +if (sd_wp_addr(sd, addr)) { +sd->card_status |= WP_VIOLATION; +} +} +if (sd->csd[14] & 0x30) { +sd->card_status |= WP_VIOLATION; +} + +sd->blk_written = 0; +return sd_cmd_to_receivingdata(sd, req, addr, sd->blk_len); +} + static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) { uint16_t rca; @@ -1544,32 +1571,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) break; /* Block write commands (Class 4) */ -case 24: /* CMD24: WRITE_SINGLE_BLOCK */ -addr = sd_req_get_address(sd, req); -switch (sd->state) { -case sd_transfer_state: - -if (!address_in_range(sd, "WRITE_SINGLE_BLOCK", addr, - sd->blk_len)) { -return sd_r1; -} - -if (sd->size <= SDSC_MAX_CAPACITY) { -if (sd_wp_addr(sd, sd->data_start)) { -sd->card_status |= WP_VIOLATION; -} -} -if (sd->csd[14] & 0x30) { -sd->card_status |= WP_VIOLATION; -} -sd->blk_written = 0; -return sd_cmd_to_receivingdata(sd, req, addr, sd->blk_len); - -default: -break; -} -break; - case 25: /* CMD25: WRITE_MULTIPLE_BLOCK */ addr = sd_req_get_address(sd, req); switch (sd->state) { @@ -2308,6 +2309,7 @@ static const SDProto sd_proto_spi = { [13] = {0, sd_spi, "SEND_STATUS", sd_cmd_SEND_STATUS}, [16] = {2, sd_spi, "SET_BLOCKLEN", sd_cmd_SET_BLOCKLEN}, [17] = {2, sd_spi, "READ_SINGLE_BLOCK", sd_cmd_READ_SINGLE_BLOCK}, +[24] = {4, sd_spi, "WRITE_SINGLE_BLOCK", sd_cmd_WRITE_SINGLE_BLOCK}, [34] = {10, sd_spi, "READ_SEC_CMD", sd_cmd_optional}, [35] = {10, sd_spi, "WRITE_SEC_CMD", sd_cmd_optional}, [36] = {10, sd_spi, "SEND_PSI", sd_cmd_optional}, @@ -2344,6 +2346,7 @@ static const SDProto sd_proto_sd = { [19] = {2, sd_adtc, "SEND_TUNING_BLOCK", sd_cmd_SEND_TUNING_BLOCK}, [20] = {2, sd_ac, "SPEED_CLASS_CONTROL", sd_cmd_optional}, [23] = {2, sd_ac, "SET_BLOCK_COUNT", sd_cmd_SET_BLOCK_COUNT}, +[24] = {4, sd_adtc, "WRITE_SINGLE_BLOCK", sd_cmd_WRITE_SINGLE_BLOCK}, [34] = {10, sd_adtc, "READ_SEC_CMD", sd_cmd_optional}, [35] = {10, sd_adtc, "WRITE_SEC_CMD", sd_cmd_optional}, [36] = {10, sd_adtc, "SEND_PSI", sd_cmd_optional}, -- 2.41.0
[PATCH v42 75/98] hw/sd/sdcard: Remove sd_none enum from sd_cmd_type_t
All handlers using the 'sd_none' enum got converted, remove it. Signed-off-by: Philippe Mathieu-Daudé --- include/hw/sd/sd.h | 1 - hw/sd/sd.c | 7 +-- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/include/hw/sd/sd.h b/include/hw/sd/sd.h index 29c76935a0..c1a35ab420 100644 --- a/include/hw/sd/sd.h +++ b/include/hw/sd/sd.h @@ -76,7 +76,6 @@ typedef enum { } sd_uhs_mode_t; typedef enum { -sd_none = 0, sd_spi, sd_bc, /* broadcast -- no response */ sd_bcr,/* broadcast with response */ diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 6a9d611429..7f93d363c7 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -526,17 +526,12 @@ static void sd_set_rca(SDState *sd, uint16_t value) static uint16_t sd_req_get_rca(SDState *s, SDRequest req) { switch (s->proto->cmd[req.cmd].type) { -case sd_none: -/* Called from legacy code not ported to SDProto array */ -assert(!s->proto->cmd[req.cmd].handler); -/* fall-through */ case sd_ac: case sd_adtc: return req.arg >> 16; case sd_spi: -g_assert_not_reached(); default: -return 0; +g_assert_not_reached(); } } -- 2.41.0
[PATCH v42 88/98] hw/sd/sdcard: Add mmc_cmd_PROGRAM_CID handler (CMD26)
Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 10 +++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 7c6f5ccc72..0f9bab105e 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1520,6 +1520,12 @@ static sd_rsp_type_t sd_cmd_WRITE_SINGLE_BLOCK(SDState *sd, SDRequest req) return sd_cmd_to_receivingdata(sd, req, addr, sd->blk_len); } +/* CMD26 */ +static sd_rsp_type_t mmc_cmd_PROGRAM_CID(SDState *sd, SDRequest req) +{ +return sd_cmd_to_receivingdata(sd, req, 0, sizeof(sd->cid)); +} + /* CMD27 */ static sd_rsp_type_t sd_cmd_PROGRAM_CSD(SDState *sd, SDRequest req) { @@ -1868,9 +1874,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) } break; -case 26: /* CMD26: PROGRAM_CID */ -return sd_cmd_to_receivingdata(sd, req, 0, sizeof(sd->cid)); - default: qemu_log_mask(LOG_GUEST_ERROR, "SD: Unknown CMD%i\n", req.cmd); return sd_illegal; @@ -2429,6 +2432,7 @@ static const SDProto sd_proto_emmc = { [19] = {0, sd_adtc, "BUSTEST_W", sd_cmd_unimplemented}, [23] = {2, sd_ac, "SET_BLOCK_COUNT", sd_cmd_SET_BLOCK_COUNT}, [24] = {4, sd_adtc, "WRITE_SINGLE_BLOCK", sd_cmd_WRITE_SINGLE_BLOCK}, +[26] = {4, sd_adtc, "PROGRAM_CID", mmc_cmd_PROGRAM_CID}, [27] = {4, sd_adtc, "PROGRAM_CSD", sd_cmd_PROGRAM_CSD}, [28] = {6, sd_ac, "SET_WRITE_PROT", sd_cmd_SET_WRITE_PROT}, [29] = {6, sd_ac, "CLR_WRITE_PROT", sd_cmd_CLR_WRITE_PROT}, -- 2.41.0
[PATCH v42 94/98] hw/sd/sdcard: add emmc_cmd_SEND_TUNING_BLOCK handler (CMD21)
From: Sai Pavan Boddu MMC cards support different tuning sequence for entering HS200 mode. Signed-off-by: Sai Pavan Boddu Signed-off-by: Edgar E. Iglesias Signed-off-by: Cédric Le Goater Signed-off-by: Cédric Le Goater Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sdmmc-internal.h | 3 +++ hw/sd/sd.c | 41 + 2 files changed, 44 insertions(+) diff --git a/hw/sd/sdmmc-internal.h b/hw/sd/sdmmc-internal.h index 20d85aea6d..a2769a80aa 100644 --- a/hw/sd/sdmmc-internal.h +++ b/hw/sd/sdmmc-internal.h @@ -108,4 +108,7 @@ #define EXT_CSD_PART_CONFIG_EN_BOOT0(0x1 << 3) #define EXT_CSD_PART_CONFIG_EN_USER (0x7 << 3) +#define EXT_CSD_BUS_WIDTH_8_MASK0x4 +#define EXT_CSD_BUS_WIDTH_4_MASK0x2 + #endif diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 0561079eff..ae5e73175e 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -698,6 +698,25 @@ static const uint8_t sd_tuning_block_pattern4[64] = { 0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde }; +static const uint8_t mmc_tuning_block_pattern8[128] = { +0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, +0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc, +0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff, +0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff, +0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd, +0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb, +0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff, +0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff, +0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, +0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, +0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, +0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, +0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, +0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, +0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, +0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee +}; + static int sd_req_crc_validate(SDRequest *req) { uint8_t buffer[5]; @@ -1603,6 +1622,26 @@ static sd_rsp_type_t sd_cmd_SEND_TUNING_BLOCK(SDState *sd, SDRequest req) sizeof(sd_tuning_block_pattern4)); } +/* CMD21 */ +static sd_rsp_type_t emmc_cmd_SEND_TUNING_BLOCK(SDState *sd, SDRequest req) +{ +const uint8_t *buf; +size_t size; + +if (sd->state != sd_transfer_state) { +sd_invalid_state_for_cmd(sd, req); +} + +if (sd->ext_csd[EXT_CSD_BUS_WIDTH] & EXT_CSD_BUS_WIDTH_8_MASK) { +buf = mmc_tuning_block_pattern8; +size = sizeof(mmc_tuning_block_pattern8); +} else { +buf = sd_tuning_block_pattern4; +size = sizeof(sd_tuning_block_pattern4); +} +return sd_cmd_to_sendingdata(sd, req, 0, buf, size); +} + /* CMD23 */ static sd_rsp_type_t sd_cmd_SET_BLOCK_COUNT(SDState *sd, SDRequest req) { @@ -2391,6 +2430,7 @@ uint8_t sd_read_byte(SDState *sd) case 13: /* ACMD13: SD_STATUS */ case 17: /* CMD17: READ_SINGLE_BLOCK */ case 19: /* CMD19: SEND_TUNING_BLOCK (SD) */ +case 21: /* CMD21: SEND_TUNING_BLOCK (MMC) */ case 22: /* ACMD22: SEND_NUM_WR_BLOCKS */ case 30: /* CMD30: SEND_WRITE_PROT */ case 51: /* ACMD51: SEND_SCR */ @@ -2573,6 +2613,7 @@ static const SDProto sd_proto_emmc = { [16] = {2, sd_ac, "SET_BLOCKLEN", sd_cmd_SET_BLOCKLEN}, [17] = {2, sd_adtc, "READ_SINGLE_BLOCK", sd_cmd_READ_SINGLE_BLOCK}, [19] = {0, sd_adtc, "BUSTEST_W", sd_cmd_unimplemented}, +[21] = {2, sd_adtc, "SEND_TUNING_BLOCK", emmc_cmd_SEND_TUNING_BLOCK}, [23] = {2, sd_ac, "SET_BLOCK_COUNT", sd_cmd_SET_BLOCK_COUNT}, [24] = {4, sd_adtc, "WRITE_SINGLE_BLOCK", sd_cmd_WRITE_SINGLE_BLOCK}, [26] = {4, sd_adtc, "PROGRAM_CID", mmc_cmd_PROGRAM_CID}, -- 2.41.0
[PATCH v42 71/98] hw/sd/sdcard: Add sd_acmd_SET_WR_BLK_ERASE_COUNT handler (ACMD23)
Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 22 +++--- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 9d66c3715a..cd207a3090 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -263,7 +263,6 @@ static const char *sd_acmd_name(SDState *sd, uint8_t cmd) [14] = "DPS_spec", [15] = "DPS_spec", [16] = "DPS_spec", [18] = "SECU_spec", -[23] = "SET_WR_BLK_ERASE_COUNT", [42] = "SET_CLR_CARD_DETECT", [51] = "SEND_SCR", [52] = "SECU_spec", [53] = "SECU_spec", @@ -1696,6 +1695,15 @@ static sd_rsp_type_t sd_acmd_SEND_NUM_WR_BLOCKS(SDState *sd, SDRequest req) &sd->blk_written, sizeof(sd->blk_written)); } +/* ACMD23 */ +static sd_rsp_type_t sd_acmd_SET_WR_BLK_ERASE_COUNT(SDState *sd, SDRequest req) +{ +if (sd->state != sd_transfer_state) { +return sd_invalid_state_for_cmd(sd, req); +} +return sd_r1; +} + static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) { uint64_t addr; @@ -1804,16 +1812,6 @@ static sd_rsp_type_t sd_app_command(SDState *sd, } switch (req.cmd) { -case 23: /* ACMD23: SET_WR_BLK_ERASE_COUNT */ -switch (sd->state) { -case sd_transfer_state: -return sd_r1; - -default: -break; -} -break; - case 41: /* ACMD41: SD_APP_OP_COND */ if (sd->state != sd_idle_state) { break; @@ -2320,6 +2318,7 @@ static const SDProto sd_proto_spi = { .acmd = { [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}, }, }; @@ -2379,6 +2378,7 @@ static const SDProto sd_proto_sd = { [6] = {8, sd_ac, "SET_BUS_WIDTH", sd_acmd_SET_BUS_WIDTH}, [13] = {8, sd_adtc, "SD_STATUS", sd_acmd_SD_STATUS}, [22] = {8, sd_adtc, "SEND_NUM_WR_BLOCKS", sd_acmd_SEND_NUM_WR_BLOCKS}, +[23] = {8, sd_ac, "SET_WR_BLK_ERASE_COUNT", sd_acmd_SET_WR_BLK_ERASE_COUNT}, }, }; -- 2.41.0
[PATCH v42 53/98] hw/sd/sdcard: Add sd_cmd_SEND_STATUS handler (CMD13)
Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 40 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 1c092ab43c..bb80d11f87 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -240,7 +240,6 @@ static const char *sd_response_name(sd_rsp_type_t rsp) static const char *sd_cmd_name(SDState *sd, uint8_t cmd) { static const char *cmd_abbrev[SDMMC_CMD_MAX] = { -[13]= "SEND_STATUS", [15]= "GO_INACTIVE_STATE", [16]= "SET_BLOCKLEN", [17]= "READ_SINGLE_BLOCK", [18]= "READ_MULTIPLE_BLOCK", @@ -1377,6 +1376,32 @@ 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) { +return sd_invalid_mode_for_cmd(sd, req); +} + +switch (sd->state) { +case sd_standby_state: +case sd_transfer_state: +case sd_sendingdata_state: +case sd_receivingdata_state: +case sd_programming_state: +case sd_disconnect_state: +break; +default: +return sd_invalid_state_for_cmd(sd, req); +} + +if (sd_is_spi(sd)) { +return sd_r2_s; +} + +return sd_req_rca_same(sd, req) ? sd_r1 : sd_r0; +} + /* CMD19 */ static sd_rsp_type_t sd_cmd_SEND_TUNING_BLOCK(SDState *sd, SDRequest req) { @@ -1443,17 +1468,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) switch (req.cmd) { /* Basic commands (Class 0 and Class 1) */ -case 13: /* CMD13: SEND_STATUS */ -rca = sd_req_get_rca(sd, req); -if (sd->mode != sd_data_transfer_mode) { -return sd_invalid_mode_for_cmd(sd, req); -} -if (!sd_is_spi(sd) && sd->rca != rca) { -return sd_r0; -} - -return sd_r1; - case 15: /* CMD15: GO_INACTIVE_STATE */ if (sd->mode != sd_data_transfer_mode) { return sd_invalid_mode_for_cmd(sd, req); @@ -2279,6 +2293,7 @@ static const SDProto sd_proto_spi = { [9] = {0, sd_spi, "SEND_CSD", spi_cmd_SEND_CSD}, [10] = {0, sd_spi, "SEND_CID", spi_cmd_SEND_CID}, [12] = {0, sd_spi, "STOP_TRANSMISSION", sd_cmd_STOP_TRANSMISSION}, +[13] = {0, sd_spi, "SEND_STATUS", sd_cmd_SEND_STATUS}, [34] = {10, sd_spi, "READ_SEC_CMD", sd_cmd_optional}, [35] = {10, sd_spi, "WRITE_SEC_CMD", sd_cmd_optional}, [36] = {10, sd_spi, "SEND_PSI", sd_cmd_optional}, @@ -2308,6 +2323,7 @@ static const SDProto sd_proto_sd = { [10] = {0, sd_ac, "SEND_CID", sd_cmd_SEND_CID}, [11] = {0, sd_ac, "VOLTAGE_SWITCH", sd_cmd_optional}, [12] = {0, sd_ac, "STOP_TRANSMISSION", sd_cmd_STOP_TRANSMISSION}, +[13] = {0, sd_ac, "SEND_STATUS", sd_cmd_SEND_STATUS}, [19] = {2, sd_adtc, "SEND_TUNING_BLOCK", sd_cmd_SEND_TUNING_BLOCK}, [20] = {2, sd_ac, "SPEED_CLASS_CONTROL", sd_cmd_optional}, [23] = {2, sd_ac, "SET_BLOCK_COUNT", sd_cmd_SET_BLOCK_COUNT}, -- 2.41.0
[PATCH v42 69/98] hw/sd/sdcard: Add sd_acmd_SD_STATUS handler (ACMD13)
Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 22 +- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 0310a5a3a1..5323a42df2 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -260,7 +260,6 @@ static const char *sd_cmd_name(SDState *sd, uint8_t cmd) static const char *sd_acmd_name(SDState *sd, uint8_t cmd) { static const char *acmd_abbrev[SDMMC_CMD_MAX] = { -[13] = "SD_STATUS", [14] = "DPS_spec", [15] = "DPS_spec", [16] = "DPS_spec", [18] = "SECU_spec", @@ -1683,6 +1682,13 @@ static sd_rsp_type_t sd_acmd_SET_BUS_WIDTH(SDState *sd, SDRequest req) return sd_r1; } +/* 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)); +} + static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) { uint64_t addr; @@ -1791,18 +1797,6 @@ static sd_rsp_type_t sd_app_command(SDState *sd, } switch (req.cmd) { -case 13: /* ACMD13: SD_STATUS */ -switch (sd->state) { -case sd_transfer_state: -return sd_cmd_to_sendingdata(sd, req, 0, - sd->sd_status, - sizeof(sd->sd_status)); - -default: -break; -} -break; - case 22: /* ACMD22: SEND_NUM_WR_BLOCKS */ switch (sd->state) { case sd_transfer_state: @@ -2329,6 +2323,7 @@ static const SDProto sd_proto_spi = { [59] = {0, sd_spi, "CRC_ON_OFF", spi_cmd_CRC_ON_OFF}, }, .acmd = { +[13] = {8, sd_spi, "SD_STATUS", sd_acmd_SD_STATUS}, [41] = {8, sd_spi, "SEND_OP_COND", spi_cmd_SEND_OP_COND}, }, }; @@ -2386,6 +2381,7 @@ static const SDProto sd_proto_sd = { }, .acmd = { [6] = {8, sd_ac, "SET_BUS_WIDTH", sd_acmd_SET_BUS_WIDTH}, +[13] = {8, sd_adtc, "SD_STATUS", sd_acmd_SD_STATUS}, }, }; -- 2.41.0
[RFC PATCH v42 91/98] hw/sd/sdcard: Adapt sd_cmd_ALL_SEND_CID handler for eMMC (CMD2)
From: Cédric Le Goater Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Cédric Le Goater [PMD: Use aspeed_emmc_kludge] Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 6 ++ 1 file changed, 6 insertions(+) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index dc692fe1fa..f875fcd741 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1218,7 +1218,13 @@ static sd_rsp_type_t emmc_cmd_SEND_OP_COND(SDState *sd, SDRequest req) static sd_rsp_type_t sd_cmd_ALL_SEND_CID(SDState *sd, SDRequest req) { switch (sd->state) { +case sd_idle_state: +if (!sd->aspeed_emmc_kludge) { +return sd_invalid_state_for_cmd(sd, req); +} +/* fall-through */ case sd_ready_state: +/* Bus always won */ sd->state = sd_identification_state; return sd_r2_i; default: -- 2.41.0
[RFC PATCH v42 93/98] hw/sd/sdcard: Add emmc_cmd_SEND_EXT_CSD handler (CMD8)
From: Vincent Palatin The parameters mimick a real 4GB eMMC, but it can be set to various sizes. Initially from Vincent Palatin eMMC CSD is similar to SD with an option to refer EXT_CSD for larger devices. Signed-off-by: Vincent Palatin Signed-off-by: Cédric Le Goater Signed-off-by: Sai Pavan Boddu Signed-off-by: Edgar E. Iglesias Signed-off-by: Cédric Le Goater Signed-off-by: Philippe Mathieu-Daudé --- TODO simplify params, see: https://lore.kernel.org/qemu-devel/54bc25fd-acea-44a3-b696-c261e7e97...@kaod.org/ --- hw/sd/sd.c | 91 ++ 1 file changed, 91 insertions(+) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 82e0b5838f..0561079eff 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -122,6 +122,7 @@ struct SDState { uint16_t rca; uint32_t card_status; uint8_t sd_status[64]; +uint8_t ext_csd[512]; /* Static properties */ @@ -460,6 +461,82 @@ static const uint8_t sd_csd_rw_mask[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xfe, }; +static void mmc_set_ext_csd(SDState *sd, uint64_t size) +{ +uint32_t sectcount = size >> HWBLOCK_SHIFT; + +memset(sd->ext_csd, 0, sizeof(sd->ext_csd)); + +sd->ext_csd[EXT_CSD_S_CMD_SET] = 0x1; /* supported command sets */ +sd->ext_csd[EXT_CSD_HPI_FEATURES] = 0x3; /* HPI features */ +sd->ext_csd[EXT_CSD_BKOPS_SUPPORT] = 0x1; /* Background operations */ +sd->ext_csd[241] = 0xA; /* 1st initialization time after partitioning */ +sd->ext_csd[EXT_CSD_TRIM_MULT] = 0x1; /* Trim multiplier */ +sd->ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT] = 0x15; /* Secure feature */ +sd->ext_csd[EXT_CSD_SEC_ERASE_MULT] = 0x96; /* Secure erase support */ +sd->ext_csd[EXT_CSD_SEC_TRIM_MULT] = 0x96; /* Secure TRIM multiplier */ +sd->ext_csd[EXT_CSD_BOOT_INFO] = 0x7; /* Boot information */ +sd->ext_csd[EXT_CSD_BOOT_MULT] = 0x8; /* Boot partition size. 128KB unit */ +sd->ext_csd[EXT_CSD_ACC_SIZE] = 0x6; /* Access size */ +sd->ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] = 0x4; /* HC Erase unit size */ +sd->ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT] = 0x1; /* HC erase timeout */ +sd->ext_csd[EXT_CSD_REL_WR_SEC_C] = 0x1; /* Reliable write sector count */ +sd->ext_csd[EXT_CSD_HC_WP_GRP_SIZE] = 0x4; /* HC write protect group size */ +sd->ext_csd[EXT_CSD_S_C_VCC] = 0x8; /* Sleep current VCC */ +sd->ext_csd[EXT_CSD_S_C_VCCQ] = 0x7; /* Sleep current VCCQ */ +sd->ext_csd[EXT_CSD_S_A_TIMEOUT] = 0x11; /* Sleep/Awake timeout */ +sd->ext_csd[215] = (sectcount >> 24) & 0xff; /* Sector count */ +sd->ext_csd[214] = (sectcount >> 16) & 0xff; /* ... */ +sd->ext_csd[213] = (sectcount >> 8) & 0xff; /* ... */ +sd->ext_csd[EXT_CSD_SEC_CNT] = (sectcount & 0xff); /* ... */ +sd->ext_csd[210] = 0xa; /* Min write perf for 8bit@52Mhz */ +sd->ext_csd[209] = 0xa; /* Min read perf for 8bit@52Mhz */ +sd->ext_csd[208] = 0xa; /* Min write perf for 4bit@52Mhz */ +sd->ext_csd[207] = 0xa; /* Min read perf for 4bit@52Mhz */ +sd->ext_csd[206] = 0xa; /* Min write perf for 4bit@26Mhz */ +sd->ext_csd[205] = 0xa; /* Min read perf for 4bit@26Mhz */ +sd->ext_csd[EXT_CSD_PART_SWITCH_TIME] = 0x1; +sd->ext_csd[EXT_CSD_OUT_OF_INTERRUPT_TIME] = 0x1; +sd->ext_csd[EXT_CSD_CARD_TYPE] = 0x7; +sd->ext_csd[EXT_CSD_STRUCTURE] = 0x2; +sd->ext_csd[EXT_CSD_REV] = 0x5; +sd->ext_csd[EXT_CSD_RPMB_MULT] = 0x1; /* RPMB size */ +sd->ext_csd[EXT_CSD_PARTITION_SUPPORT] = 0x3; +sd->ext_csd[159] = 0x00; /* Max enhanced area size */ +sd->ext_csd[158] = 0x00; /* ... */ +sd->ext_csd[157] = 0xEC; /* ... */ +} + +static void sd_emmc_set_csd(SDState *sd, uint64_t size) +{ +sd->csd[0] = 0xd0; +sd->csd[1] = 0x0f; +sd->csd[2] = 0x00; +sd->csd[3] = 0x32; +sd->csd[4] = 0x0f; +if (size <= 2 * GiB) { +/* use 1k blocks */ +uint32_t csize1k = (size >> (CMULT_SHIFT + 10)) - 1; +sd->csd[5] = 0x5a; +sd->csd[6] = 0x80 | ((csize1k >> 10) & 0xf); +sd->csd[7] = (csize1k >> 2) & 0xff; +} else { /* >= 2GB : size stored in ext CSD, block addressing */ +sd->csd[5] = 0x59; +sd->csd[6] = 0x8f; +sd->csd[7] = 0xff; +sd->ocr = FIELD_DP32(sd->ocr, OCR, CARD_CAPACITY, 1); +} +sd->csd[8] = 0xff; +sd->csd[9] = 0xff; +sd->csd[10] = 0xf7; +sd->csd[11] = 0xfe; +sd->csd[12] = 0x49; +sd->csd[13] = 0x10; +sd->csd[14] = 0x00; +sd->csd[15] = (sd_crc7(sd->csd, 15) << 1) | 1; +mmc_set_ext_csd(sd, size); +} + static void sd_set_csd(SDState *sd, uint64_t size) { int hwblock_shift = HWBLOCK_SHIFT; @@ -1364,6 +1441,17 @@ static sd_rsp_type_t sd_cmd_SEND_IF_COND(SDState *sd, SDRequest req) return sd_r7; } +/* CMD8 */ +static sd_rsp_type_t emmc_cmd_SEND_EXT_CSD(SDState *sd, SDRequest req) +{ +if (sd->state != sd_transfer_state) { +return sd_invalid_state_for_cmd(sd, req); +} + +return sd_cmd_to_sendingdata(sd, req
[PATCH v42 79/98] hw/sd/sdcard: Trace length of data read on DAT lines
Some commands expect less than BLOCK_LENGTH. Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 4 ++-- hw/sd/trace-events | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 64621d4340..a0da06e017 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -2197,8 +2197,8 @@ uint8_t sd_read_byte(SDState *sd) io_len = sd_blk_len(sd); trace_sdcard_read_data(sd->proto->name, - sd->last_cmd_name, - sd->current_cmd, sd->data_offset, io_len); + sd->last_cmd_name, sd->current_cmd, + sd->data_offset, sd->data_size, io_len); switch (sd->current_cmd) { case 6: /* CMD6: SWITCH_FUNCTION */ case 9: /* CMD9: SEND_CSD */ diff --git a/hw/sd/trace-events b/hw/sd/trace-events index 6a51b0e906..5dfe6be7b7 100644 --- a/hw/sd/trace-events +++ b/hw/sd/trace-events @@ -55,7 +55,7 @@ sdcard_req_addr(uint32_t req_arg, uint64_t addr) "req 0x%" PRIx32 " addr 0x%" PR sdcard_read_block(uint64_t addr, uint32_t len) "addr 0x%" PRIx64 " size 0x%x" sdcard_write_block(uint64_t addr, uint32_t len) "addr 0x%" PRIx64 " size 0x%x" sdcard_write_data(const char *proto, const char *cmd_desc, uint8_t cmd, uint32_t offset, uint8_t value) "%s %20s/ CMD%02d ofs %"PRIu32" value 0x%02x" -sdcard_read_data(const char *proto, const char *cmd_desc, uint8_t cmd, uint32_t offset, uint32_t length) "%s %20s/ CMD%02d ofs %"PRIu32" len %" PRIu32 +sdcard_read_data(const char *proto, const char *cmd_desc, uint8_t cmd, uint32_t offset, uint64_t size, uint32_t blklen) "%s %20s/ CMD%02d ofs %"PRIu32" size %"PRIu64" blklen %" PRIu32 sdcard_set_voltage(uint16_t millivolts) "%u mV" # pxa2xx_mmci.c -- 2.41.0