sdmmc_host: support multiblock transfers

rockbox-gerrit-noreply--- via rockbox-cvs <[email protected]>
Newsgroups gmane.comp.systems.archos.rockbox.cvs
Message-ID <[email protected]>
commit 6da20a18c3dc81d7ca2ae5462d2ed77b4ddd5617
Author: Aidan MacDonald <[email protected]>
Date:   Fri Feb 6 10:22:25 2026 +0000

    sdmmc_host: support multiblock transfers
    
    Change-Id: I6414028bbafd4ea4ef469f9a387f4bd52ec227e5

diff --git a/firmware/drivers/sdmmc_host.c b/firmware/drivers/sdmmc_host.c
index c012731a7e..ad21cfed32 100644
--- a/firmware/drivers/sdmmc_host.c
+++ b/firmware/drivers/sdmmc_host.c
@@ -677,10 +677,12 @@ static int sdmmc_host_transfer(struct sdmmc_host *host,
     if (start + count > host->cardinfo.numblocks)
         goto out;
 
+    int max_nr_blocks = MAX(host->config.max_nr_blocks, 1);
     while (count > 0)
     {
-        /* TODO: multiple block transfers */
-        int xfer_count = 1;
+        int xfer_count = count;
+        if (xfer_count > max_nr_blocks)
+            xfer_count = max_nr_blocks;
 
         /* Set block length for non-HCS cards */
         if (!host->is_hcs_card)
@@ -692,15 +694,25 @@ static int sdmmc_host_transfer(struct sdmmc_host *host,
 
         struct sdmmc_host_command cmd = {
             .buffer = buf,
-            .nr_blocks = 1,
+            .nr_blocks = xfer_count,
             .block_len = SD_BLOCK_SIZE,
             .flags = SDMMC_RESP_SHORT | data_dir,
         };
 
-        if (data_dir == SDMMC_DATA_WRITE)
-            cmd.command = SD_WRITE_BLOCK;
+        if (xfer_count > 1)
+        {
+            if (data_dir == SDMMC_DATA_WRITE)
+                cmd.command = SD_WRITE_MULTIPLE_BLOCK;
+            else
+                cmd.command = SD_READ_MULTIPLE_BLOCK;
+        }
         else
-            cmd.command = SD_READ_SINGLE_BLOCK;
+        {
+            if (data_dir == SDMMC_DATA_WRITE)
+                cmd.command = SD_WRITE_BLOCK;
+            else
+                cmd.command = SD_READ_SINGLE_BLOCK;
+        }
 
         if (host->cardinfo.sd2plus)
             cmd.argument = start;
@@ -711,6 +723,22 @@ static int sdmmc_host_transfer(struct sdmmc_host *host,
         if (rc)
             goto out;
 
+        /*
+         * NOTE: some controllers can send CMD12 automatically after
+         *       the end of a transfer, eg. X1000; it might be worth
+         *       supporting that via a feature flag.
+         */
+        if (xfer_count > 1)
+        {
+            memset(&cmd, 0, sizeof(cmd));
+            cmd.command = SD_STOP_TRANSMISSION;
+            cmd.flags = SDMMC_RESP_SHORT | SDMMC_RESP_BUSY;
+
+            rc = sdmmc_host_submit_cmd(host, &cmd, NULL);
+            if (rc)
+                goto out;
+        }
+
         buf += xfer_count * SD_BLOCK_SIZE;
         start += xfer_count;
         count -= xfer_count;
diff --git a/firmware/export/sdmmc_host.h b/firmware/export/sdmmc_host.h
index 1d00c94a27..3d6c7fbb0f 100644
--- a/firmware/export/sdmmc_host.h
+++ b/firmware/export/sdmmc_host.h
@@ -207,6 +207,9 @@ struct sdmmc_host_config
     uint32_t bus_widths;
     uint32_t bus_clocks;
 
+    /* Max number of blocks in a multiblock transfer */
+    int max_nr_blocks;
+
     /* Set to true if the device is removable at runtime */
     bool is_removable;
 };
-- 
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.