sdmmc_host: add support for SET_BLOCK_COUNT (CMD23)
rockbox-gerrit-noreply--- via rockbox-cvs <[email protected]>
| Newsgroups | gmane.comp.systems.archos.rockbox.cvs |
|---|---|
| Message-ID | <[email protected]> |
commit cdad8cde6475bdef7103a3a36240e011ff5b8060 Author: Aidan MacDonald <[email protected]> Date: Mon Aug 17 11:51:01 2026 +0100 sdmmc_host: add support for SET_BLOCK_COUNT (CMD23) According to commit 7327d9fb6c ("Implement set block count (CMD23) for x1000 target") some cards may experience data corruption with certain controllers when CMD12 is used to terminate multiblock writes. Using set block count (CMD23) is reported to fix this issue. Following the approach in that patch, use the SCR register to probe support for CMD23, but disable use at runtime if CMD23 generates an illegal command error. Change-Id: I3ee1e48939b79b848fbda12c6737f2f974f47fa0 diff --git a/firmware/drivers/sdmmc_host.c b/firmware/drivers/sdmmc_host.c index 1cec921d80..8db8fcfc92 100644 --- a/firmware/drivers/sdmmc_host.c +++ b/firmware/drivers/sdmmc_host.c @@ -196,6 +196,7 @@ static void sdmmc_host_bus_reset(struct sdmmc_host *host) host->need_reset = false; host->initialized = false; host->is_hcs_card = false; + host->use_cmd23 = false; memset(&host->cardinfo, 0, sizeof(host->cardinfo)); } @@ -487,6 +488,10 @@ static int sdmmc_host_cmd_send_scr(struct sdmmc_host *host) host->cardinfo.scr[0] = load_be32_aligned(cmd.buffer + 4); host->cardinfo.scr[1] = load_be32_aligned(cmd.buffer + 0); + /* Use CMD23 (SET_BLOCK_COUNT) if card reports support */ + if (host->cardinfo.scr[1] & 0x2) + host->use_cmd23 = true; + return rc; } @@ -562,6 +567,28 @@ static int sdmmc_host_cmd_set_block_len(struct sdmmc_host *host, int len) return sdmmc_host_submit_cmd(host, &cmd, NULL); } +static int sdmmc_host_cmd_set_block_count(struct sdmmc_host *host, int count) +{ + struct sdmmc_host_response resp; + struct sdmmc_host_command cmd = { + .command = SD_SET_BLOCK_COUNT, + .argument = count, + .flags = SDMMC_RESP_SHORT, + }; + + int rc = sdmmc_host_submit_cmd(host, &cmd, &resp); + if (rc) + return rc; + + if (resp.data[0] & SD_R1_ILLEGAL_COMMAND) + { + logf("sdmmc: card claimed support for CMD23 but rejected it"); + host->use_cmd23 = false; + } + + return rc; +} + static void sdmmc_host_set_controller_bus_width(struct sdmmc_host *host, uint32_t width) { if (host->ops->set_bus_width) @@ -764,6 +791,18 @@ static int sdmmc_host_transfer(struct sdmmc_host *host, cmd.command = SD_WRITE_MULTIPLE_BLOCK; else cmd.command = SD_READ_MULTIPLE_BLOCK; + + /* + * Note: if the card rejects the command the return code + * will be successful, but use_cmd23 is set to false, and + * CMD12 will be used to terminate the read/write instead. + */ + if (host->use_cmd23) + { + rc = sdmmc_host_cmd_set_block_count(host, xfer_count); + if (rc) + goto out; + } } else { @@ -787,7 +826,7 @@ static int sdmmc_host_transfer(struct sdmmc_host *host, * the end of a transfer, eg. X1000; it might be worth * supporting that via a feature flag. */ - if (xfer_count > 1) + if (xfer_count > 1 && !host->use_cmd23) { memset(&cmd, 0, sizeof(cmd)); cmd.command = SD_STOP_TRANSMISSION; diff --git a/firmware/export/sdmmc_host.h b/firmware/export/sdmmc_host.h index 1953b4d1c8..5258460196 100644 --- a/firmware/export/sdmmc_host.h +++ b/firmware/export/sdmmc_host.h @@ -241,6 +241,7 @@ struct sdmmc_host bool powered : 1; bool initialized : 1; bool is_hcs_card : 1; + bool use_cmd23 : 1; /* Controller implemented by the target */ const struct sdmmc_controller_ops *ops; -- rockbox-cvs mailing list [email protected] https://lists.haxx.se/mailman/listinfo/rockbox-cvs