refactor(sd): replace esp_dma_ with heap_caps_

This commit is contained in:
Armando
2025-01-15 16:16:10 +08:00
parent d8166220fd
commit e8ad9b05aa
16 changed files with 186 additions and 103 deletions

View File

@@ -28,7 +28,6 @@
#include "sys/param.h"
#include "soc/soc_memory_layout.h"
#include "soc/soc_caps.h"
#include "esp_dma_utils.h"
#ifdef __cplusplus
extern "C" {
@@ -187,6 +186,12 @@ esp_err_t sdmmc_wait_for_idle(sdmmc_card_t* card, uint32_t status);
#define SDMMC_IO_BLOCK_SIZE 512
esp_err_t sdmmc_allocate_aligned_buf(sdmmc_card_t* card);
/**
* For newly added host driver function pointers,
* use this function to check if they are correctly initialised.
*/
esp_err_t sdmmc_check_host_function_ptr_integrity(sdmmc_card_t *card);
#ifdef __cplusplus
}
#endif

View File

@@ -242,6 +242,7 @@ typedef struct {
void* dma_aligned_buffer; /*!< Leave it NULL. Reserved for cache aligned buffers for SDIO mode */
sd_pwr_ctrl_handle_t pwr_ctrl_handle; /*!< Power control handle */
esp_err_t (*get_dma_info)(int slot, esp_dma_mem_info_t *dma_mem_info); /*!< host function to dma memory information*/
bool (*check_buffer_alignment)(int slot, const void *buf, size_t size); /*!< Check if buffer meets alignment requirements */
esp_err_t (*is_slot_set_to_uhs1)(int slot, bool *is_uhs1); /*!< host slot is set to uhs1 or not*/
} sdmmc_host_t;

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -340,14 +340,13 @@ esp_err_t sdmmc_send_cmd_send_scr(sdmmc_card_t* card, sdmmc_scr_t *out_scr)
{
size_t datalen = 8;
esp_err_t err = ESP_FAIL;
void *buf = NULL;
size_t actual_size = 0;
esp_dma_mem_info_t dma_mem_info;
card->host.get_dma_info(card->host.slot, &dma_mem_info);
err = esp_dma_capable_malloc(datalen, &dma_mem_info, &buf, &actual_size);
if (err != ESP_OK) {
return err;
void *buf = heap_caps_malloc(datalen, MALLOC_CAP_DMA);
if (!buf) {
ESP_LOGE(TAG, "%s: not enough mem, err=0x%x", __func__, ESP_ERR_NO_MEM);
return ESP_ERR_NO_MEM;
}
size_t actual_size = heap_caps_get_allocated_size(buf);
sdmmc_command_t cmd = {
.data = buf,
@@ -412,14 +411,13 @@ esp_err_t sdmmc_send_cmd_num_of_written_blocks(sdmmc_card_t* card, size_t* out_n
{
size_t datalen = sizeof(uint32_t);
esp_err_t err = ESP_OK;
void* buf = NULL;
esp_dma_mem_info_t dma_mem_info;
card->host.get_dma_info(card->host.slot, &dma_mem_info);
size_t actual_size = 0;
err = esp_dma_capable_malloc(datalen, &dma_mem_info, &buf, &actual_size);
if (err != ESP_OK) {
return err;
void *buf = heap_caps_malloc(datalen, MALLOC_CAP_DMA);
if (!buf) {
ESP_LOGE(TAG, "%s: not enough mem, err=0x%x", __func__, ESP_ERR_NO_MEM);
return ESP_ERR_NO_MEM;
}
size_t actual_size = heap_caps_get_allocated_size(buf);
sdmmc_command_t cmd = {
.data = buf,
@@ -454,12 +452,9 @@ esp_err_t sdmmc_write_sectors(sdmmc_card_t* card, const void* src,
esp_err_t err = ESP_OK;
size_t block_size = card->csd.sector_size;
esp_dma_mem_info_t dma_mem_info;
card->host.get_dma_info(card->host.slot, &dma_mem_info);
#ifdef SOC_SDMMC_PSRAM_DMA_CAPABLE
dma_mem_info.extra_heap_caps |= MALLOC_CAP_SPIRAM;
#endif
if (esp_dma_is_buffer_alignment_satisfied(src, block_size * block_count, dma_mem_info)
bool is_aligned = card->host.check_buffer_alignment(card->host.slot, src, block_size * block_count);
if (is_aligned
#if !SOC_SDMMC_PSRAM_DMA_CAPABLE
&& !esp_ptr_external_ram(src)
#endif
@@ -471,13 +466,14 @@ esp_err_t sdmmc_write_sectors(sdmmc_card_t* card, const void* src,
// DMA-capable buffer.
void *tmp_buf = NULL;
size_t actual_size = 0;
// Clear the SPIRAM flag. We don't want to force the allocation into SPIRAM, the allocator
// We don't want to force the allocation into SPIRAM, the allocator
// will decide based on the buffer size and memory availability.
dma_mem_info.extra_heap_caps &= ~MALLOC_CAP_SPIRAM;
err = esp_dma_capable_malloc(block_size, &dma_mem_info, &tmp_buf, &actual_size);
if (err != ESP_OK) {
return err;
tmp_buf = heap_caps_malloc(block_size, MALLOC_CAP_DMA);
if (!tmp_buf) {
ESP_LOGE(TAG, "%s: not enough mem, err=0x%x", __func__, ESP_ERR_NO_MEM);
return ESP_ERR_NO_MEM;
}
actual_size = heap_caps_get_allocated_size(tmp_buf);
const uint8_t* cur_src = (const uint8_t*) src;
for (size_t i = 0; i < block_count; ++i) {
@@ -594,9 +590,9 @@ esp_err_t sdmmc_read_sectors(sdmmc_card_t* card, void* dst,
esp_err_t err = ESP_OK;
size_t block_size = card->csd.sector_size;
esp_dma_mem_info_t dma_mem_info;
card->host.get_dma_info(card->host.slot, &dma_mem_info);
if (esp_dma_is_buffer_alignment_satisfied(dst, block_size * block_count, dma_mem_info)
bool is_aligned = card->host.check_buffer_alignment(card->host.slot, dst, block_size * block_count);
if (is_aligned
#if !SOC_SDMMC_PSRAM_DMA_CAPABLE
&& !esp_ptr_external_ram(dst)
#endif
@@ -608,10 +604,13 @@ esp_err_t sdmmc_read_sectors(sdmmc_card_t* card, void* dst,
// DMA-capable buffer.
void *tmp_buf = NULL;
size_t actual_size = 0;
err = esp_dma_capable_malloc(block_size, &dma_mem_info, &tmp_buf, &actual_size);
if (err != ESP_OK) {
return err;
tmp_buf = heap_caps_malloc(block_size, MALLOC_CAP_DMA);
if (!tmp_buf) {
ESP_LOGE(TAG, "%s: not enough mem, err=0x%x", __func__, ESP_ERR_NO_MEM);
return ESP_ERR_NO_MEM;
}
actual_size = heap_caps_get_allocated_size(tmp_buf);
uint8_t* cur_dst = (uint8_t*) dst;
for (size_t i = 0; i < block_count; ++i) {
err = sdmmc_read_sectors_dma(card, tmp_buf, start_block + i, 1, actual_size);

View File

@@ -395,20 +395,30 @@ esp_err_t sdmmc_allocate_aligned_buf(sdmmc_card_t* card)
{
if (card->host.flags & SDMMC_HOST_FLAG_ALLOC_ALIGNED_BUF) {
void* buf = NULL;
size_t actual_size = 0;
esp_dma_mem_info_t dma_mem_info;
card->host.get_dma_info(card->host.slot, &dma_mem_info);
esp_err_t ret = esp_dma_capable_malloc(SDMMC_IO_BLOCK_SIZE, &dma_mem_info, &buf, &actual_size);
if (ret != ESP_OK) {
return ret;
size_t actual_size = 0;
buf = heap_caps_malloc(SDMMC_IO_BLOCK_SIZE, MALLOC_CAP_DMA);
if (!buf) {
ESP_LOGE(TAG, "%s: not enough mem, err=0x%x", __func__, ESP_ERR_NO_MEM);
return ESP_ERR_NO_MEM;
}
actual_size = heap_caps_get_allocated_size(buf);
assert(actual_size == SDMMC_IO_BLOCK_SIZE);
card->host.dma_aligned_buffer = buf;
}
return ESP_OK;
}
esp_err_t sdmmc_check_host_function_ptr_integrity(sdmmc_card_t *card)
{
if (!card->host.check_buffer_alignment) {
ESP_LOGE(TAG, "%s: host drv check_buffer_alignment not initialised, err=0x%x", __func__, ESP_ERR_INVALID_ARG);
return ESP_ERR_INVALID_ARG;
}
return ESP_OK;
}
uint32_t sdmmc_get_erase_timeout_ms(const sdmmc_card_t* card, int arg, size_t erase_size_kb)
{
if (card->is_mmc) {

View File

@@ -68,6 +68,9 @@ esp_err_t sdmmc_card_init(const sdmmc_host_t* config, sdmmc_card_t* card)
/* Check if host flags are compatible with slot configuration. */
SDMMC_INIT_STEP(!is_spi, sdmmc_fix_host_flags);
/* Check if host function pointers are correctly initialised */
SDMMC_INIT_STEP(always, sdmmc_check_host_function_ptr_integrity);
/* Reset SDIO (CMD52, RES) before re-initializing IO (CMD5). */
SDMMC_INIT_STEP(io_supported, sdmmc_io_reset);

View File

@@ -319,9 +319,8 @@ esp_err_t sdmmc_io_rw_extended(sdmmc_card_t* card, int func,
.blklen = SDMMC_IO_BLOCK_SIZE /* TODO: read max block size from CIS */
};
esp_dma_mem_info_t dma_mem_info;
card->host.get_dma_info(card->host.slot, &dma_mem_info);
if (unlikely(datalen > 0 && !esp_dma_is_buffer_alignment_satisfied(datap, buflen, dma_mem_info))) {
bool is_aligned = card->host.check_buffer_alignment(card->host.slot, datap, buflen);
if (unlikely(datalen > 0 && !is_aligned)) {
if (datalen > SDMMC_IO_BLOCK_SIZE || card->host.dma_aligned_buffer == NULL) {
// User gives unaligned buffer while `SDMMC_HOST_FLAG_ALLOC_ALIGNED_BUF` not set.
return ESP_ERR_INVALID_ARG;
@@ -463,9 +462,8 @@ esp_err_t sdmmc_io_read_blocks(sdmmc_card_t* card, uint32_t function,
addr &= ~SDMMC_IO_FIXED_ADDR;
}
esp_dma_mem_info_t dma_mem_info;
card->host.get_dma_info(card->host.slot, &dma_mem_info);
if (unlikely(!esp_dma_is_buffer_alignment_satisfied(dst, size, dma_mem_info))) {
bool is_aligned = card->host.check_buffer_alignment(card->host.slot, dst, size);
if (unlikely(!is_aligned)) {
return ESP_ERR_INVALID_ARG;
}
return sdmmc_io_rw_extended(card, function, addr, arg, dst, size);
@@ -481,9 +479,8 @@ esp_err_t sdmmc_io_write_blocks(sdmmc_card_t* card, uint32_t function,
addr &= ~SDMMC_IO_FIXED_ADDR;
}
esp_dma_mem_info_t dma_mem_info;
card->host.get_dma_info(card->host.slot, &dma_mem_info);
if (unlikely(!esp_dma_is_buffer_alignment_satisfied(src, size, dma_mem_info))) {
bool is_aligned = card->host.check_buffer_alignment(card->host.slot, src, size);
if (unlikely(!is_aligned)) {
return ESP_ERR_INVALID_ARG;
}
return sdmmc_io_rw_extended(card, function, addr, arg, (void*) src, size);

View File

@@ -28,14 +28,12 @@ esp_err_t sdmmc_init_mmc_read_ext_csd(sdmmc_card_t* card)
esp_err_t err = ESP_OK;
uint8_t* ext_csd = NULL;
size_t actual_size = 0;
esp_dma_mem_info_t dma_mem_info;
card->host.get_dma_info(card->host.slot, &dma_mem_info);
err = esp_dma_capable_malloc(EXT_CSD_MMC_SIZE, &dma_mem_info, (void *)&ext_csd, &actual_size);
if (err != ESP_OK) {
ESP_LOGE(TAG, "%s: could not allocate ext_csd", __func__);
return err;
ext_csd = heap_caps_malloc(EXT_CSD_MMC_SIZE, MALLOC_CAP_DMA);
if (!ext_csd) {
ESP_LOGE(TAG, "%s: not enough mem, err=0x%x", __func__, ESP_ERR_NO_MEM);
return ESP_ERR_NO_MEM;
}
actual_size = heap_caps_get_allocated_size(ext_csd);
uint32_t sectors = 0;
ESP_LOGD(TAG, "MMC version: %d", card->csd.mmc_ver);
@@ -257,13 +255,13 @@ esp_err_t sdmmc_init_mmc_check_ext_csd(sdmmc_card_t* card)
/* ensure EXT_CSD buffer is available before starting any SD-card operation */
uint8_t* ext_csd = NULL;
size_t actual_size = 0;
esp_dma_mem_info_t dma_mem_info;
card->host.get_dma_info(card->host.slot, &dma_mem_info);
esp_err_t err = esp_dma_capable_malloc(EXT_CSD_MMC_SIZE, &dma_mem_info, (void *)&ext_csd, &actual_size);
if (err != ESP_OK) {
ESP_LOGE(TAG, "%s: could not allocate ext_csd", __func__);
return err;
esp_err_t err = ESP_FAIL;
ext_csd = heap_caps_malloc(EXT_CSD_MMC_SIZE, MALLOC_CAP_DMA);
if (!ext_csd) {
ESP_LOGE(TAG, "%s: not enough mem, err=0x%x", __func__, ESP_ERR_NO_MEM);
return ESP_ERR_NO_MEM;
}
actual_size = heap_caps_get_allocated_size(ext_csd);
/* ensure card is in transfer state before read ext_csd */
uint32_t status;

View File

@@ -92,13 +92,13 @@ esp_err_t sdmmc_init_sd_ssr(sdmmc_card_t* card)
*/
uint32_t* sd_ssr = NULL;
size_t actual_size = 0;
esp_dma_mem_info_t dma_mem_info;
card->host.get_dma_info(card->host.slot, &dma_mem_info);
err = esp_dma_capable_calloc(1, SD_SSR_SIZE, &dma_mem_info, (void *)&sd_ssr, &actual_size);
if (err != ESP_OK) {
ESP_LOGE(TAG, "%s: could not allocate sd_ssr", __func__);
return err;
sd_ssr = heap_caps_calloc(1, SD_SSR_SIZE, MALLOC_CAP_DMA);
if (!sd_ssr) {
ESP_LOGE(TAG, "%s: not enough mem, err=0x%x", __func__, ESP_ERR_NO_MEM);
return ESP_ERR_NO_MEM;
}
actual_size = heap_caps_get_allocated_size(sd_ssr);
sdmmc_command_t cmd = {
.data = sd_ssr,
@@ -240,14 +240,12 @@ esp_err_t sdmmc_enter_higher_speed_mode(sdmmc_card_t* card)
return ESP_ERR_NOT_SUPPORTED;
}
size_t actual_size = 0;
sdmmc_switch_func_rsp_t *response = NULL;
esp_dma_mem_info_t dma_mem_info;
card->host.get_dma_info(card->host.slot, &dma_mem_info);
esp_err_t err = esp_dma_capable_malloc(sizeof(*response), &dma_mem_info, (void *)&response, &actual_size);
assert(actual_size == sizeof(*response));
if (err != ESP_OK) {
return err;
esp_err_t err = ESP_FAIL;
response = heap_caps_malloc(sizeof(*response), MALLOC_CAP_DMA);
if (!response) {
ESP_LOGE(TAG, "%s: not enough mem, err=0x%x", __func__, ESP_ERR_NO_MEM);
return ESP_ERR_NO_MEM;
}
err = sdmmc_send_cmd_switch_func(card, 0, SD_ACCESS_MODE, 0, response);