sdio: allow reads/writes with lengths not divisible by 4

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.
This commit is contained in:
Ivan Grokhotkov 2018-04-20 17:42:13 +08:00 committed by Angus Gratton
parent 97a228e6ab
commit cf81db40a2
3 changed files with 70 additions and 25 deletions

View 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;

View 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);

View 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);