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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.