From 2e02ed84845dac862877196cd1bc2602ce99bf53 Mon Sep 17 00:00:00 2001 From: Yogesh Mantri Date: Thu, 17 Sep 2026 15:50:08 +0800 Subject: [PATCH] feat(sdmmc): add dma_burst_size config, fix DMA to PSRAM on esp32p4 FIFOTH.dma_multiple_transaction_size was never programmed and kept its reset value of 0, which selects 1-byte DMA bursts. On esp32p4 with flash encryption enabled those bursts do not reach PSRAM. Add sdmmc_ll_set_dma_burst_size() and a dma_burst_size field in sd_host_sdmmc_cfg_t, 0 selecting the per-target default. esp32p4 defaults to 16 bytes; esp32 and esp32s3 keep their current 1 byte. --- .../include/driver/sd_host_sdmmc.h | 1 + components/esp_driver_sdmmc/src/sd_host_sdmmc.c | 6 ++++++ .../esp_hal_sd/esp32/include/hal/sdmmc_ll.h | 15 +++++++++++++++ .../esp_hal_sd/esp32p4/include/hal/sdmmc_ll.h | 15 +++++++++++++++ .../esp_hal_sd/esp32s3/include/hal/sdmmc_ll.h | 15 +++++++++++++++ .../esp_hal_sd/esp32s31/include/hal/sdmmc_ll.h | 15 +++++++++++++++ 6 files changed, 67 insertions(+) diff --git a/components/esp_driver_sdmmc/include/driver/sd_host_sdmmc.h b/components/esp_driver_sdmmc/include/driver/sd_host_sdmmc.h index 6f1d9a09b45..0cfb82d63b4 100644 --- a/components/esp_driver_sdmmc/include/driver/sd_host_sdmmc.h +++ b/components/esp_driver_sdmmc/include/driver/sd_host_sdmmc.h @@ -22,6 +22,7 @@ extern "C" { typedef struct { uint32_t event_queue_items; ///< Event queue items. If 0, fallback to default queue item number (4) uint32_t dma_desc_num; ///< Number of DMA descriptor, fallback to default dma descriptor number (4) + size_t dma_burst_size; ///< DMA burst size in bytes, a power of two in 4..256. 0 for the default, 1 to disable the burst } sd_host_sdmmc_cfg_t; /** diff --git a/components/esp_driver_sdmmc/src/sd_host_sdmmc.c b/components/esp_driver_sdmmc/src/sd_host_sdmmc.c index 8429f300be9..e24d822d69e 100644 --- a/components/esp_driver_sdmmc/src/sd_host_sdmmc.c +++ b/components/esp_driver_sdmmc/src/sd_host_sdmmc.c @@ -76,6 +76,11 @@ esp_err_t sd_host_create_sdmmc_controller(const sd_host_sdmmc_cfg_t *config, sd_ esp_err_t ret = ESP_FAIL; ESP_RETURN_ON_FALSE(config && ret_handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + size_t burst_size = config->dma_burst_size ? config->dma_burst_size : SDMMC_LL_DMA_BURST_SIZE_DEFAULT; + ESP_RETURN_ON_FALSE(burst_size == 1 || + (burst_size >= 4 && burst_size <= 256 && (burst_size & (burst_size - 1)) == 0), + ESP_ERR_INVALID_ARG, TAG, "invalid dma_burst_size"); + sd_host_sdmmc_ctlr_t *ctlr = heap_caps_calloc(1, sizeof(sd_host_sdmmc_ctlr_t), SD_HOST_SDMMC_MEM_ALLOC_CAPS); ESP_RETURN_ON_FALSE(ctlr, ESP_ERR_NO_MEM, TAG, "no mem for sd host controller context"); @@ -130,6 +135,7 @@ esp_err_t sd_host_create_sdmmc_controller(const sd_host_sdmmc_cfg_t *config, sd_ sdmmc_ll_enable_interrupt(ctlr->hal.dev, 0xffffffff, false); sdmmc_ll_enable_global_interrupt(ctlr->hal.dev, false); sdmmc_ll_init_dma(ctlr->hal.dev); + sdmmc_ll_set_dma_burst_size(ctlr->hal.dev, burst_size); ctlr->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED; ctlr->drv.del_ctlr = sd_host_del_sdmmc_controller; diff --git a/components/esp_hal_sd/esp32/include/hal/sdmmc_ll.h b/components/esp_hal_sd/esp32/include/hal/sdmmc_ll.h index 495fc65c8e1..3a1df93f8aa 100644 --- a/components/esp_hal_sd/esp32/include/hal/sdmmc_ll.h +++ b/components/esp_hal_sd/esp32/include/hal/sdmmc_ll.h @@ -88,6 +88,7 @@ extern "C" { #define SDMMC_LL_HOST_CTLR_NUMS 1U #define SDMMC_LL_DEFAULT_DIV 2 +#define SDMMC_LL_DMA_BURST_SIZE_DEFAULT 1 typedef enum { SDMMC_LL_DELAY_PHASE_0, @@ -687,6 +688,20 @@ static inline void sdmmc_ll_init_dma(sdmmc_dev_t *hw) hw->idinten.ti = 1; } +/** + * @brief Set the burst size of the internal DMA + * + * @param hw hardware instance address + * @param burst_size burst size in bytes, 1 to disable the data burst, + * otherwise a power of two between 4 and 256 + */ +static inline void sdmmc_ll_set_dma_burst_size(sdmmc_dev_t *hw, size_t burst_size) +{ + HAL_ASSERT(burst_size == 1 || + (burst_size >= 4 && burst_size <= 256 && (burst_size & (burst_size - 1)) == 0)); + hw->fifoth.dw_dma_mts = (burst_size == 1) ? 0 : (__builtin_ctz(burst_size) - 1); +} + /** * @brief Enable DMA * diff --git a/components/esp_hal_sd/esp32p4/include/hal/sdmmc_ll.h b/components/esp_hal_sd/esp32p4/include/hal/sdmmc_ll.h index 5f59858923c..6235304c0fa 100644 --- a/components/esp_hal_sd/esp32p4/include/hal/sdmmc_ll.h +++ b/components/esp_hal_sd/esp32p4/include/hal/sdmmc_ll.h @@ -96,6 +96,7 @@ extern "C" { #define SDMMC_LL_SDR50_SUPPORTED 1 #define SDMMC_LL_DEFAULT_DIV 2 +#define SDMMC_LL_DMA_BURST_SIZE_DEFAULT 16 /** * SDMMC delay phase @@ -876,6 +877,20 @@ static inline void sdmmc_ll_init_dma(sdmmc_dev_t *hw) hw->idinten.ti = 1; } +/** + * @brief Set the burst size of the internal DMA + * + * @param hw hardware instance address + * @param burst_size burst size in bytes, 1 to disable the data burst, + * otherwise a power of two between 4 and 256 + */ +static inline void sdmmc_ll_set_dma_burst_size(sdmmc_dev_t *hw, size_t burst_size) +{ + HAL_ASSERT(burst_size == 1 || + (burst_size >= 4 && burst_size <= 256 && (burst_size & (burst_size - 1)) == 0)); + hw->fifoth.dma_multiple_transaction_size = (burst_size == 1) ? 0 : (__builtin_ctz(burst_size) - 1); +} + /** * @brief Enable DMA * diff --git a/components/esp_hal_sd/esp32s3/include/hal/sdmmc_ll.h b/components/esp_hal_sd/esp32s3/include/hal/sdmmc_ll.h index 87e63af3aa7..054cdc06109 100644 --- a/components/esp_hal_sd/esp32s3/include/hal/sdmmc_ll.h +++ b/components/esp_hal_sd/esp32s3/include/hal/sdmmc_ll.h @@ -90,6 +90,7 @@ extern "C" { #define SDMMC_LL_DELAY_PHASE_SUPPORTED 1 #define SDMMC_LL_DEFAULT_DIV 2 +#define SDMMC_LL_DMA_BURST_SIZE_DEFAULT 1 /** * SDMMC delay phase @@ -751,6 +752,20 @@ static inline void sdmmc_ll_init_dma(sdmmc_dev_t *hw) hw->idinten.ti = 1; } +/** + * @brief Set the burst size of the internal DMA + * + * @param hw hardware instance address + * @param burst_size burst size in bytes, 1 to disable the data burst, + * otherwise a power of two between 4 and 256 + */ +static inline void sdmmc_ll_set_dma_burst_size(sdmmc_dev_t *hw, size_t burst_size) +{ + HAL_ASSERT(burst_size == 1 || + (burst_size >= 4 && burst_size <= 256 && (burst_size & (burst_size - 1)) == 0)); + hw->fifoth.dw_dma_mts = (burst_size == 1) ? 0 : (__builtin_ctz(burst_size) - 1); +} + /** * @brief Enable DMA * diff --git a/components/esp_hal_sd/esp32s31/include/hal/sdmmc_ll.h b/components/esp_hal_sd/esp32s31/include/hal/sdmmc_ll.h index 0f7d38a1957..2ece0cfdb9c 100644 --- a/components/esp_hal_sd/esp32s31/include/hal/sdmmc_ll.h +++ b/components/esp_hal_sd/esp32s31/include/hal/sdmmc_ll.h @@ -97,6 +97,7 @@ extern "C" { #define SDMMC_LL_SDR50_SUPPORTED 1 #define SDMMC_LL_DEFAULT_DIV 8 +#define SDMMC_LL_DMA_BURST_SIZE_DEFAULT 64 /** * SDMMC delay phase @@ -820,6 +821,20 @@ static inline void sdmmc_ll_init_dma(sdmmc_dev_t *hw) hw->bmod.bmod_pbl = 0x7; } +/** + * @brief Set the burst size of the internal DMA + * + * @param hw hardware instance address + * @param burst_size burst size in bytes, 1 to disable the data burst, + * otherwise a power of two between 4 and 256 + */ +static inline void sdmmc_ll_set_dma_burst_size(sdmmc_dev_t *hw, size_t burst_size) +{ + HAL_ASSERT(burst_size == 1 || + (burst_size >= 4 && burst_size <= 256 && (burst_size & (burst_size - 1)) == 0)); + hw->fifoth.dma_multiple_transaction_size = (burst_size == 1) ? 0 : (__builtin_ctz(burst_size) - 1); +} + /** * @brief Enable DMA *