]> granicus.if.org Git - esp-idf/commitdiff
sdio: allow reads/writes with lengths not divisible by 4
authorIvan Grokhotkov <ivan@espressif.com>
Fri, 20 Apr 2018 09:42:13 +0000 (17:42 +0800)
committerAngus Gratton <gus@projectgus.com>
Tue, 15 May 2018 01:59:20 +0000 (09:59 +0800)
CMD53 in byte mode supports transfers of any number of bytes between 1
and 512. This change removes limitation that the number of bytes must
be divisible by 4. Host quirk, that such transfers must be split into
two commands (one for the aligned part and the other one for
unaligned) is taken into account.

components/driver/sdmmc_transaction.c
components/sdmmc/sdmmc_cmd.c
components/sdmmc/test/test_sdio.c

index 52dec2991ce3faa5864c6a8f759e167f2eb84ca1..c53b4b11c49f0eabeaae55280c9c46dfb5a3c472 100644 (file)
@@ -122,9 +122,10 @@ esp_err_t sdmmc_host_do_transaction(int slot, sdmmc_command_t* cmdinfo)
     // convert cmdinfo to hardware register value
     sdmmc_hw_cmd_t hw_cmd = make_hw_cmd(cmdinfo);
     if (cmdinfo->data) {
-        if (cmdinfo->datalen < 4 || cmdinfo->blklen % 4 != 0) {
-            ESP_LOGD(TAG, "%s: invalid size: total=%d block=%d",
-                    __func__, cmdinfo->datalen, cmdinfo->blklen);
+        // Length should be either <4 or >=4 and =0 (mod 4).
+        if (cmdinfo->datalen >= 4 && cmdinfo->datalen % 4 != 0) {
+            ESP_LOGD(TAG, "%s: invalid size: total=%d",
+                    __func__, cmdinfo->datalen);
             ret = ESP_ERR_INVALID_SIZE;
             goto out;
         }
@@ -212,7 +213,8 @@ static void fill_dma_descriptors(size_t num_desc)
         desc->owned_by_idmac = 1;
         desc->buffer1_ptr = s_cur_transfer.ptr;
         desc->next_desc_ptr = (last) ? NULL : &s_dma_desc[(next + 1) % SDMMC_DMA_DESC_CNT];
-        desc->buffer1_size = size_to_fill;
+        assert(size_to_fill < 4 || size_to_fill % 4 == 0);
+        desc->buffer1_size = (size_to_fill + 3) & (~3);
 
         s_cur_transfer.size_remaining -= size_to_fill;
         s_cur_transfer.ptr += size_to_fill;
index 7279dec44c184f517b355e5c26d2d797438153c3..ab88b7780fc704ed3ff0a14f90ed3fbc0cf4727a 100644 (file)
@@ -1269,22 +1269,57 @@ static esp_err_t sdmmc_io_rw_extended(sdmmc_card_t* card, int func,
 esp_err_t sdmmc_io_read_bytes(sdmmc_card_t* card, uint32_t function,
         uint32_t addr, void* dst, size_t size)
 {
-    return sdmmc_io_rw_extended(card, function, addr,
-            SD_ARG_CMD53_READ | SD_ARG_CMD53_INCREMENT,
-            dst, size);
+    /* host quirk: SDIO transfer with length not divisible by 4 bytes
+     * has to be split into two transfers: one with aligned length,
+     * the other one for the remaining 1-3 bytes.
+     */
+    uint8_t *pc_dst = dst;
+    while (size > 0) {
+        size_t size_aligned = size & (~3);
+        size_t will_transfer = size_aligned > 0 ? size_aligned : size;
+
+        esp_err_t err = sdmmc_io_rw_extended(card, function, addr,
+                SD_ARG_CMD53_READ | SD_ARG_CMD53_INCREMENT,
+                pc_dst, will_transfer);
+        if (err != ESP_OK) {
+            return err;
+        }
+        pc_dst += will_transfer;
+        size -= will_transfer;
+        addr += will_transfer;
+    }
+    return ESP_OK;
 }
 
 esp_err_t sdmmc_io_write_bytes(sdmmc_card_t* card, uint32_t function,
         uint32_t addr, const void* src, size_t size)
 {
-    return sdmmc_io_rw_extended(card, function, addr,
-            SD_ARG_CMD53_WRITE | SD_ARG_CMD53_INCREMENT,
-            (void*) src, size);
+    /* same host quirk as in sdmmc_io_read_bytes */
+    const uint8_t *pc_src = (const uint8_t*) src;
+
+    while (size > 0) {
+        size_t size_aligned = size & (~3);
+        size_t will_transfer = size_aligned > 0 ? size_aligned : size;
+
+        esp_err_t err = sdmmc_io_rw_extended(card, function, addr,
+                SD_ARG_CMD53_WRITE | SD_ARG_CMD53_INCREMENT,
+                (void*) pc_src, will_transfer);
+        if (err != ESP_OK) {
+            return err;
+        }
+        pc_src += will_transfer;
+        size -= will_transfer;
+        addr += will_transfer;
+    }
+    return ESP_OK;
 }
 
 esp_err_t sdmmc_io_read_blocks(sdmmc_card_t* card, uint32_t function,
         uint32_t addr, void* dst, size_t size)
 {
+    if (size % 4 != 0) {
+        return ESP_ERR_INVALID_SIZE;
+    }
     return sdmmc_io_rw_extended(card, function, addr,
             SD_ARG_CMD53_READ | SD_ARG_CMD53_INCREMENT | SD_ARG_CMD53_BLOCK_MODE,
             dst, size);
@@ -1293,6 +1328,9 @@ esp_err_t sdmmc_io_read_blocks(sdmmc_card_t* card, uint32_t function,
 esp_err_t sdmmc_io_write_blocks(sdmmc_card_t* card, uint32_t function,
         uint32_t addr, const void* src, size_t size)
 {
+    if (size % 4 != 0) {
+        return ESP_ERR_INVALID_SIZE;
+    }
     return sdmmc_io_rw_extended(card, function, addr,
             SD_ARG_CMD53_WRITE | SD_ARG_CMD53_INCREMENT | SD_ARG_CMD53_BLOCK_MODE,
             (void*) src, size);
index 8b885baf55bb1208358f2ac8e97e350b7ba873e6..f4eae0598019656106cb9767b2aed7d110cbb54b 100644 (file)
@@ -309,35 +309,33 @@ static void test_cmd52_read_write_single_byte(sdmmc_card_t* card)
     TEST_ASSERT_EQUAL_UINT8(test_byte_2, val);
 }
 
-static void test_cmd53_read_write_multiple_bytes(sdmmc_card_t* card)
+static void test_cmd53_read_write_multiple_bytes(sdmmc_card_t* card, size_t n_bytes)
 {
     printf("Write multiple bytes using CMD53\n");
     const size_t scratch_area_reg = SLCHOST_CONF_W0 - DR_REG_SLCHOST_BASE;
 
     uint8_t* src = heap_caps_malloc(512, MALLOC_CAP_DMA);
     uint32_t* src_32 = (uint32_t*) src;
-    const size_t n_words = 6;
-    srand(0);
-    for (size_t i = 0; i < n_words; ++i) {
+
+    for (size_t i = 0; i < (n_bytes + 3) / 4; ++i) {
         src_32[i] = rand();
     }
-    size_t len = n_words * sizeof(uint32_t);
 
-    TEST_ESP_OK(sdmmc_io_write_bytes(card, 1, scratch_area_reg, src, len));
-    ESP_LOG_BUFFER_HEX(TAG, src, len);
+    TEST_ESP_OK(sdmmc_io_write_bytes(card, 1, scratch_area_reg, src, n_bytes));
+    ESP_LOG_BUFFER_HEX(TAG, src, n_bytes);
 
     printf("Read back using CMD52\n");
     uint8_t* dst = heap_caps_malloc(512, MALLOC_CAP_DMA);
-    for (size_t i = 0; i < len; ++i) {
+    for (size_t i = 0; i < n_bytes; ++i) {
         TEST_ESP_OK(sdmmc_io_read_byte(card, 1, scratch_area_reg + i, &dst[i]));
     }
-    ESP_LOG_BUFFER_HEX(TAG, dst, len);
-    TEST_ASSERT_EQUAL_UINT8_ARRAY(src, dst, len);
+    ESP_LOG_BUFFER_HEX(TAG, dst, n_bytes);
+    TEST_ASSERT_EQUAL_UINT8_ARRAY(src, dst, n_bytes);
 
     printf("Read back using CMD53\n");
-    TEST_ESP_OK(sdmmc_io_read_bytes(card, 1, scratch_area_reg, dst, len));
-    ESP_LOG_BUFFER_HEX(TAG, dst, len);
-    TEST_ASSERT_EQUAL_UINT8_ARRAY(src, dst, len);
+    TEST_ESP_OK(sdmmc_io_read_bytes(card, 1, scratch_area_reg, dst, n_bytes));
+    ESP_LOG_BUFFER_HEX(TAG, dst, n_bytes);
+    TEST_ASSERT_EQUAL_UINT8_ARRAY(src, dst, n_bytes);
 
     free(src);
     free(dst);
@@ -364,9 +362,16 @@ TEST_CASE("can probe and talk to ESP32 SDIO slave", "[sdio][ignore]")
     /* Set up standard SDIO registers */
     sdio_slave_common_init(card);
 
-    for (int repeat = 0; repeat < 10; ++repeat) {
+    srand(0);
+    for (int repeat = 0; repeat < 4; ++repeat) {
         test_cmd52_read_write_single_byte(card);
-        test_cmd53_read_write_multiple_bytes(card);
+        test_cmd53_read_write_multiple_bytes(card, 1);
+        test_cmd53_read_write_multiple_bytes(card, 2);
+        test_cmd53_read_write_multiple_bytes(card, 3);
+        test_cmd53_read_write_multiple_bytes(card, 4);
+        test_cmd53_read_write_multiple_bytes(card, 5);
+        test_cmd53_read_write_multiple_bytes(card, 23);
+        test_cmd53_read_write_multiple_bytes(card, 24);
     }
 
     sdio_slave_set_blocksize(card, 0, 512);