feat(dma): refactor dma calloc function

This commit is contained in:
gaoxu 2024-03-29 11:36:27 +08:00 committed by Gao Xu
parent 78f96c4466
commit 40f38bea6f
30 changed files with 204 additions and 363 deletions

View File

@ -1,4 +1,4 @@
[codespell] [codespell]
skip = build,*.yuv,components/fatfs/src/*,alice.txt,*.rgb skip = build,*.yuv,components/fatfs/src/*,alice.txt,*.rgb
ignore-words-list = ser,dout,rsource,fram,inout ignore-words-list = ser,dout,rsource,fram,inout,shs
write-changes = true write-changes = true

View File

@ -576,9 +576,10 @@ static esp_err_t i2s_alloc_dma_buffer(i2s_port_t i2s_num, i2s_dma_t *dma_obj)
for (int cnt = 0; cnt < buf_cnt; cnt++) { for (int cnt = 0; cnt < buf_cnt; cnt++) {
/* Allocate DMA buffer */ /* Allocate DMA buffer */
esp_dma_mem_info_t dma_mem_info = { esp_dma_mem_info_t dma_mem_info = {
.heap_caps = MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA, .extra_heap_caps = MALLOC_CAP_INTERNAL,
.dma_alignment = 4, .dma_alignment_bytes = 4,
}; };
//TODO: IDF-9636
esp_dma_capable_calloc(1, sizeof(char) * dma_obj->buf_size, &dma_mem_info, (void **)&dma_obj->buf[cnt], NULL); esp_dma_capable_calloc(1, sizeof(char) * dma_obj->buf_size, &dma_mem_info, (void **)&dma_obj->buf[cnt], NULL);
ESP_GOTO_ON_FALSE(dma_obj->buf[cnt], ESP_ERR_NO_MEM, err, TAG, "Error malloc dma buffer"); ESP_GOTO_ON_FALSE(dma_obj->buf[cnt], ESP_ERR_NO_MEM, err, TAG, "Error malloc dma buffer");
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE #if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
@ -587,7 +588,6 @@ static esp_err_t i2s_alloc_dma_buffer(i2s_port_t i2s_num, i2s_dma_t *dma_obj)
/* Allocate DMA descriptor */ /* Allocate DMA descriptor */
esp_dma_capable_calloc(1, sizeof(lldesc_t), &dma_mem_info, (void **)&dma_obj->desc[cnt], &desc_size); esp_dma_capable_calloc(1, sizeof(lldesc_t), &dma_mem_info, (void **)&dma_obj->desc[cnt], &desc_size);
// esp_dma_calloc(1, sizeof(lldesc_t), MALLOC_CAP_DEFAULT, (void **)&dma_obj->desc[cnt], &desc_size);
ESP_GOTO_ON_FALSE(dma_obj->desc[cnt], ESP_ERR_NO_MEM, err, TAG, "Error malloc dma description entry"); ESP_GOTO_ON_FALSE(dma_obj->desc[cnt], ESP_ERR_NO_MEM, err, TAG, "Error malloc dma description entry");
} }
/* DMA descriptor must be initialize after all descriptor has been created, otherwise they can't be linked together as a chain */ /* DMA descriptor must be initialize after all descriptor has been created, otherwise they can't be linked together as a chain */

View File

@ -69,32 +69,15 @@
static const char *TAG = "i2s_common"; static const char *TAG = "i2s_common";
__attribute__((always_inline)) __attribute__((always_inline))
inline void *i2s_dma_calloc(i2s_chan_handle_t handle, size_t num, size_t size, bool is_desc, size_t *actual_size) inline void *i2s_dma_calloc(i2s_chan_handle_t handle, size_t num, size_t size, size_t *actual_size)
{ {
esp_err_t ret = ESP_FAIL;
void *ptr = NULL; void *ptr = NULL;
size_t dma_alignment = 0;
void *gdma_chan_handle = NULL;
#if SOC_GDMA_SUPPORTED
gdma_chan_handle = handle->dma.dma_chan;
#endif
dma_alignment_info_t info = {
.is_desc = is_desc,
};
ret = esp_dma_get_alignment(gdma_chan_handle, &info, &dma_alignment);
assert(ret == ESP_OK);
esp_dma_mem_info_t dma_mem_info = { esp_dma_mem_info_t dma_mem_info = {
.heap_caps = MALLOC_CAP_DMA, .extra_heap_caps = I2S_DMA_ALLOC_CAPS,
.dma_alignment = 4, .dma_alignment_bytes = 4,
}; };
//TODO: IDF-9636
esp_dma_capable_calloc(num, size, &dma_mem_info, &ptr, actual_size); esp_dma_capable_calloc(num, size, &dma_mem_info, &ptr, actual_size);
#if CONFIG_IDF_TARGET_ESP32P4
assert((int)ptr % 64 == 0);
#else
assert((int)ptr % 4 == 0);
#endif
return ptr; return ptr;
} }
@ -444,7 +427,7 @@ esp_err_t i2s_alloc_dma_desc(i2s_chan_handle_t handle, uint32_t num, uint32_t bu
size_t desc_size = 0; size_t desc_size = 0;
for (int i = 0; i < num; i++) { for (int i = 0; i < num; i++) {
/* Allocate DMA descriptor */ /* Allocate DMA descriptor */
handle->dma.desc[i] = (lldesc_t *) i2s_dma_calloc(handle, 1, sizeof(lldesc_t), true, &desc_size); handle->dma.desc[i] = (lldesc_t *) i2s_dma_calloc(handle, 1, sizeof(lldesc_t), &desc_size);
ESP_GOTO_ON_FALSE(handle->dma.desc[i], ESP_ERR_NO_MEM, err, TAG, "allocate DMA description failed"); ESP_GOTO_ON_FALSE(handle->dma.desc[i], ESP_ERR_NO_MEM, err, TAG, "allocate DMA description failed");
handle->dma.desc[i]->owner = 1; handle->dma.desc[i]->owner = 1;
handle->dma.desc[i]->eof = 1; handle->dma.desc[i]->eof = 1;
@ -452,7 +435,7 @@ esp_err_t i2s_alloc_dma_desc(i2s_chan_handle_t handle, uint32_t num, uint32_t bu
handle->dma.desc[i]->length = bufsize; handle->dma.desc[i]->length = bufsize;
handle->dma.desc[i]->size = bufsize; handle->dma.desc[i]->size = bufsize;
handle->dma.desc[i]->offset = 0; handle->dma.desc[i]->offset = 0;
handle->dma.bufs[i] = (uint8_t *) i2s_dma_calloc(handle, 1, bufsize * sizeof(uint8_t), false, NULL); handle->dma.bufs[i] = (uint8_t *) i2s_dma_calloc(handle, 1, bufsize * sizeof(uint8_t), NULL);
ESP_GOTO_ON_FALSE(handle->dma.bufs[i], ESP_ERR_NO_MEM, err, TAG, "allocate DMA buffer failed"); ESP_GOTO_ON_FALSE(handle->dma.bufs[i], ESP_ERR_NO_MEM, err, TAG, "allocate DMA buffer failed");
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE #if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
esp_cache_msync(handle->dma.bufs[i], bufsize * sizeof(uint8_t), ESP_CACHE_MSYNC_FLAG_DIR_C2M); esp_cache_msync(handle->dma.bufs[i], bufsize * sizeof(uint8_t), ESP_CACHE_MSYNC_FLAG_DIR_C2M);

View File

@ -176,7 +176,11 @@ esp_err_t jpeg_decoder_process(jpeg_decoder_handle_t decoder_engine, const jpeg_
ESP_RETURN_ON_FALSE(decoder_engine, ESP_ERR_INVALID_ARG, TAG, "jpeg decode handle is null"); ESP_RETURN_ON_FALSE(decoder_engine, ESP_ERR_INVALID_ARG, TAG, "jpeg decode handle is null");
ESP_RETURN_ON_FALSE(decode_cfg, ESP_ERR_INVALID_ARG, TAG, "jpeg decode config is null"); ESP_RETURN_ON_FALSE(decode_cfg, ESP_ERR_INVALID_ARG, TAG, "jpeg decode config is null");
ESP_RETURN_ON_FALSE(decode_outbuf, ESP_ERR_INVALID_ARG, TAG, "jpeg decode picture buffer is null"); ESP_RETURN_ON_FALSE(decode_outbuf, ESP_ERR_INVALID_ARG, TAG, "jpeg decode picture buffer is null");
ESP_RETURN_ON_FALSE(esp_dma_is_buffer_aligned(decode_outbuf, outbuf_size, ESP_DMA_BUF_LOCATION_PSRAM), ESP_ERR_INVALID_ARG, TAG, "jpeg decode decode_outbuf or out_buffer size is not aligned, please use jpeg_alloc_decoder_mem to malloc your buffer"); esp_dma_mem_info_t dma_mem_info = {
.dma_alignment_bytes = 4,
};
//TODO: IDF-9637
ESP_RETURN_ON_FALSE(esp_dma_is_buffer_alignment_satisfied(decode_outbuf, outbuf_size, dma_mem_info), ESP_ERR_INVALID_ARG, TAG, "jpeg decode decode_outbuf or out_buffer size is not aligned, please use jpeg_alloc_decoder_mem to malloc your buffer");
esp_err_t ret = ESP_OK; esp_err_t ret = ESP_OK;

View File

@ -46,6 +46,7 @@ extern "C" {
.set_input_delay = &sdmmc_host_set_input_delay, \ .set_input_delay = &sdmmc_host_set_input_delay, \
.dma_aligned_buffer = NULL, \ .dma_aligned_buffer = NULL, \
.pwr_ctrl_handle = NULL, \ .pwr_ctrl_handle = NULL, \
.get_dma_info = &sdmmc_host_get_dma_info, \
} }
#define SDMMC_SLOT_NO_CD GPIO_NUM_NC ///< indicates that card detect line is not used #define SDMMC_SLOT_NO_CD GPIO_NUM_NC ///< indicates that card detect line is not used

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -247,6 +247,17 @@ esp_err_t sdmmc_host_get_real_freq(int slot, int* real_freq_khz);
*/ */
esp_err_t sdmmc_host_set_input_delay(int slot, sdmmc_delay_phase_t delay_phase); esp_err_t sdmmc_host_set_input_delay(int slot, sdmmc_delay_phase_t delay_phase);
/**
* @brief Get the DMA memory information for the host driver
*
* @param[in] slot slot number (SDMMC_HOST_SLOT_0 or SDMMC_HOST_SLOT_1)
* @param[out] dma_mem_info DMA memory information structure
* @return
* - ESP_OK: ON success.
* - ESP_ERR_INVALID_ARG: Invalid argument.
*/
esp_err_t sdmmc_host_get_dma_info(int slot, esp_dma_mem_info_t *dma_mem_info);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -921,3 +921,13 @@ static esp_err_t sdmmc_host_pullup_en_internal(int slot, int width)
} }
return ESP_OK; return ESP_OK;
} }
esp_err_t sdmmc_host_get_dma_info(int slot, esp_dma_mem_info_t *dma_mem_info)
{
if (!(slot == 0 || slot == 1)) {
return ESP_ERR_INVALID_ARG;
}
dma_mem_info->extra_heap_caps = MALLOC_CAP_DMA;
dma_mem_info->dma_alignment_bytes = 4;
return ESP_OK;
}

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -53,7 +53,8 @@ typedef int sdspi_dev_handle_t;
.command_timeout_ms = 0, \ .command_timeout_ms = 0, \
.get_real_freq = &sdspi_host_get_real_freq, \ .get_real_freq = &sdspi_host_get_real_freq, \
.input_delay_phase = SDMMC_DELAY_PHASE_0, \ .input_delay_phase = SDMMC_DELAY_PHASE_0, \
.set_input_delay = NULL \ .set_input_delay = NULL, \
.get_dma_info = &sdspi_host_get_dma_info, \
} }
/** /**
@ -209,6 +210,17 @@ esp_err_t sdspi_host_io_int_enable(sdspi_dev_handle_t handle);
*/ */
esp_err_t sdspi_host_io_int_wait(sdspi_dev_handle_t handle, TickType_t timeout_ticks); esp_err_t sdspi_host_io_int_wait(sdspi_dev_handle_t handle, TickType_t timeout_ticks);
/**
* @brief Get the DMA memory information for the host driver
*
* @param[in] slot Not used
* @param[out] dma_mem_info DMA memory information structure
* @return
* - ESP_OK: ON success.
* - ESP_ERR_INVALID_ARG: Invalid argument.
*/
esp_err_t sdspi_host_get_dma_info(int slot, esp_dma_mem_info_t *dma_mem_info);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -998,3 +998,11 @@ esp_err_t sdspi_host_io_int_wait(sdspi_dev_handle_t handle, TickType_t timeout_t
} }
return ESP_OK; return ESP_OK;
} }
esp_err_t sdspi_host_get_dma_info(int slot, esp_dma_mem_info_t *dma_mem_info)
{
(void)slot;
dma_mem_info->extra_heap_caps = MALLOC_CAP_DMA;
dma_mem_info->dma_alignment_bytes = 4;
return ESP_OK;
}

View File

@ -385,7 +385,7 @@ uint8_t *emac_esp_dma_alloc_recv_buf(emac_esp_dma_handle_t emac_esp_dma, uint32_
buf = malloc(copy_len); buf = malloc(copy_len);
if (buf != NULL) { if (buf != NULL) {
emac_esp_dma_auto_buf_info_t *buff_info = (emac_esp_dma_auto_buf_info_t *)buf; emac_esp_dma_auto_buf_info_t *buff_info = (emac_esp_dma_auto_buf_info_t *)buf;
/* no need to check allocated buffer min lenght prior writing since we know that EMAC DMA is configured to /* no need to check allocated buffer min length prior writing since we know that EMAC DMA is configured to
not forward erroneous or undersized frames (less than 64B) on ESP32, see emac_hal_init_dma_default */ not forward erroneous or undersized frames (less than 64B) on ESP32, see emac_hal_init_dma_default */
#ifndef NDEBUG #ifndef NDEBUG
buff_info->magic_id = EMAC_HAL_BUF_MAGIC_ID; buff_info->magic_id = EMAC_HAL_BUF_MAGIC_ID;
@ -532,8 +532,8 @@ esp_err_t emac_esp_new_dma(const emac_esp_dma_config_t* config, emac_esp_dma_han
uint32_t desc_size = CONFIG_ETH_DMA_RX_BUFFER_NUM * sizeof(eth_dma_rx_descriptor_t) + uint32_t desc_size = CONFIG_ETH_DMA_RX_BUFFER_NUM * sizeof(eth_dma_rx_descriptor_t) +
CONFIG_ETH_DMA_TX_BUFFER_NUM * sizeof(eth_dma_tx_descriptor_t); CONFIG_ETH_DMA_TX_BUFFER_NUM * sizeof(eth_dma_tx_descriptor_t);
esp_dma_mem_info_t dma_mem_info = { esp_dma_mem_info_t dma_mem_info = {
.heap_caps = MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA, .extra_heap_caps = MALLOC_CAP_INTERNAL,
.dma_alignment = 4, .dma_alignment_bytes = 4,
}; };
esp_dma_capable_calloc(1, desc_size, &dma_mem_info, (void*)&emac_esp_dma->descriptors, NULL); esp_dma_capable_calloc(1, desc_size, &dma_mem_info, (void*)&emac_esp_dma->descriptors, NULL);

View File

@ -14,7 +14,6 @@
#include "esp_memory_utils.h" #include "esp_memory_utils.h"
#include "esp_dma_utils.h" #include "esp_dma_utils.h"
#include "esp_private/esp_cache_private.h" #include "esp_private/esp_cache_private.h"
#include "esp_private/gdma.h"
#include "soc/soc_caps.h" #include "soc/soc_caps.h"
#include "hal/hal_utils.h" #include "hal/hal_utils.h"
@ -28,33 +27,31 @@ esp_err_t esp_dma_capable_malloc(size_t size, const esp_dma_mem_info_t *dma_mem_
{ {
ESP_RETURN_ON_FALSE_ISR(dma_mem_info && out_ptr, ESP_ERR_INVALID_ARG, TAG, "null pointer"); ESP_RETURN_ON_FALSE_ISR(dma_mem_info && out_ptr, ESP_ERR_INVALID_ARG, TAG, "null pointer");
size_t alignment = 1; size_t alignment_bytes = 0;
//dma align //dma align
size_t dma_alignment = dma_mem_info->dma_alignment; size_t dma_alignment_bytes = dma_mem_info->dma_alignment_bytes;
//custom align
size_t custom_alignment = dma_mem_info->custom_alignment;
//cache align //cache align
int cache_flags = 0; int cache_flags = 0;
size_t cache_alignment = 1; size_t cache_alignment_bytes = 0;
if (dma_mem_info->heap_caps & MALLOC_CAP_SPIRAM) {
int heap_caps = dma_mem_info->extra_heap_caps | MALLOC_CAP_DMA;
if (dma_mem_info->extra_heap_caps & MALLOC_CAP_SPIRAM) {
cache_flags |= ESP_DMA_MALLOC_FLAG_PSRAM; cache_flags |= ESP_DMA_MALLOC_FLAG_PSRAM;
heap_caps = dma_mem_info->extra_heap_caps | MALLOC_CAP_SPIRAM;
} }
esp_err_t ret = esp_cache_get_alignment(cache_flags, &cache_alignment);
esp_err_t ret = esp_cache_get_alignment(cache_flags, &cache_alignment_bytes);
assert(ret == ESP_OK); assert(ret == ESP_OK);
//lcm3 //Get the least common multiple of two alignment
alignment = _lcm_3(dma_alignment, cache_alignment, custom_alignment); alignment_bytes = hal_utils_calc_lcm(dma_alignment_bytes, cache_alignment_bytes);
ESP_LOGD(TAG, "alignment: 0x%x", alignment);
//malloc //malloc
size = ALIGN_UP_BY(size, alignment); size = ALIGN_UP_BY(size, alignment_bytes);
int heap_caps = dma_mem_info->heap_caps; void *ptr = heap_caps_aligned_alloc(alignment_bytes, size, heap_caps);
ESP_RETURN_ON_FALSE_ISR(ptr, ESP_ERR_NO_MEM, TAG, "Not enough heap memory");
void *ptr = heap_caps_aligned_alloc(alignment, size, heap_caps);
ESP_RETURN_ON_FALSE_ISR(ptr, ESP_ERR_NO_MEM, TAG, "no enough heap memory");
*out_ptr = ptr; *out_ptr = ptr;
if (actual_size) { if (actual_size) {
@ -64,13 +61,13 @@ esp_err_t esp_dma_capable_malloc(size_t size, const esp_dma_mem_info_t *dma_mem_
return ESP_OK; return ESP_OK;
} }
esp_err_t esp_dma_capable_calloc(size_t n, size_t size, const esp_dma_mem_info_t *dma_mem_info, void **out_ptr, size_t *actual_size) esp_err_t esp_dma_capable_calloc(size_t calloc_num, size_t size, const esp_dma_mem_info_t *dma_mem_info, void **out_ptr, size_t *actual_size)
{ {
esp_err_t ret = ESP_FAIL; esp_err_t ret = ESP_FAIL;
size_t size_bytes = 0; size_t size_bytes = 0;
bool ovf = false; bool ovf = false;
ovf = __builtin_mul_overflow(n, size, &size_bytes); ovf = __builtin_mul_overflow(calloc_num, size, &size_bytes);
ESP_RETURN_ON_FALSE_ISR(!ovf, ESP_ERR_INVALID_ARG, TAG, "wrong size, total size overflow"); ESP_RETURN_ON_FALSE_ISR(!ovf, ESP_ERR_INVALID_ARG, TAG, "wrong size, total size overflow");
void *ptr = NULL; void *ptr = NULL;
@ -105,7 +102,7 @@ static inline bool s_is_buf_aligned(intptr_t ptr, size_t alignment)
return (ptr % alignment == 0); return (ptr % alignment == 0);
} }
bool esp_dma_is_buffer_alignment_satisfied(const void *ptr, size_t size, esp_dma_mem_info_t *dma_mem_info) bool esp_dma_is_buffer_alignment_satisfied(const void *ptr, size_t size, esp_dma_mem_info_t dma_mem_info)
{ {
assert(ptr); assert(ptr);
@ -120,27 +117,24 @@ bool esp_dma_is_buffer_alignment_satisfied(const void *ptr, size_t size, esp_dma
return false; return false;
} }
size_t alignment = 1; size_t alignment_bytes = 0;
//dma align //dma align
size_t dma_alignment = dma_mem_info->dma_alignment; size_t dma_alignment_bytes = dma_mem_info.dma_alignment_bytes;
//custom align
size_t custom_alignment = dma_mem_info->custom_alignment;
//cache align //cache align
int cache_flags = 0; int cache_flags = 0;
size_t cache_alignment = 1; size_t cache_alignment_bytes = 0;
if (dma_mem_info->heap_caps & MALLOC_CAP_SPIRAM) { if (esp_ptr_external_ram(ptr)) {
cache_flags |= ESP_DMA_MALLOC_FLAG_PSRAM; cache_flags |= ESP_DMA_MALLOC_FLAG_PSRAM;
} }
esp_err_t ret = esp_cache_get_alignment(cache_flags, &cache_alignment); esp_err_t ret = esp_cache_get_alignment(cache_flags, &cache_alignment_bytes);
assert(ret == ESP_OK); assert(ret == ESP_OK);
//lcm3 //Get the least common multiple of two alignment
alignment = _lcm_3(dma_alignment, cache_alignment, custom_alignment); alignment_bytes = hal_utils_calc_lcm(dma_alignment_bytes, cache_alignment_bytes);
bool is_aligned = s_is_buf_aligned((intptr_t)ptr, alignment) && s_is_buf_aligned((intptr_t)size, alignment); bool is_aligned = s_is_buf_aligned((intptr_t)ptr, alignment_bytes) && s_is_buf_aligned((intptr_t)size, alignment_bytes);
return is_aligned; return is_aligned;
} }
@ -158,8 +152,8 @@ esp_err_t s_legacy_malloc(size_t size, uint32_t flags, void **out_ptr, size_t *a
} }
esp_dma_mem_info_t dma_mem_info = { esp_dma_mem_info_t dma_mem_info = {
.heap_caps = heap_caps, .extra_heap_caps = heap_caps,
.dma_alignment = 4, //legacy API behaviour is only check max dma buffer alignment .dma_alignment_bytes = 4, //legacy API behaviour is only check max dma buffer alignment
}; };
ESP_RETURN_ON_ERROR_ISR(esp_dma_capable_malloc(size, &dma_mem_info, out_ptr, actual_size), TAG, "failed to do malloc"); ESP_RETURN_ON_ERROR_ISR(esp_dma_capable_malloc(size, &dma_mem_info, out_ptr, actual_size), TAG, "failed to do malloc");
@ -235,28 +229,8 @@ bool esp_dma_is_buffer_aligned(const void *ptr, size_t size, esp_dma_buf_locatio
} }
esp_dma_mem_info_t dma_mem_info = { esp_dma_mem_info_t dma_mem_info = {
.heap_caps = heap_caps, .extra_heap_caps = heap_caps,
.dma_alignment = 4, //legacy API behaviour is only check max dma buffer alignment .dma_alignment_bytes = 4, //legacy API behaviour is only check max dma buffer alignment
}; };
return esp_dma_is_buffer_alignment_satisfied(ptr, size, &dma_mem_info); return esp_dma_is_buffer_alignment_satisfied(ptr, size, dma_mem_info);
}
esp_err_t esp_dma_get_alignment(void *gdma_chan_handle, const dma_alignment_info_t *info, size_t *alignment)
{
ESP_RETURN_ON_FALSE(info && alignment, ESP_ERR_INVALID_ARG, TAG, "null pointer");
#if SOC_GDMA_SUPPORTED
if (gdma_chan_handle) {
gdma_channel_handle_t dma_chan = (gdma_channel_handle_t)gdma_chan_handle;
gdma_alignment_info_t gdma_info = {};
memcpy(&gdma_info, info, sizeof(gdma_alignment_info_t));
ESP_RETURN_ON_ERROR(gdma_get_alignment(dma_chan, &gdma_info, alignment), TAG, "failed to get gdma alignment");
} else
#endif
{
//for esp32 and esp32s2
*alignment = 4;
}
return ESP_OK;
} }

View File

@ -944,34 +944,3 @@ static esp_err_t gdma_install_tx_interrupt(gdma_tx_channel_t *tx_chan)
err: err:
return ret; return ret;
} }
esp_err_t gdma_get_alignment(gdma_channel_handle_t dma_chan, const gdma_alignment_info_t *info, size_t *alignment)
{
ESP_RETURN_ON_FALSE(dma_chan && info && alignment, ESP_ERR_INVALID_ARG, TAG, "null pointer");
bool desc_on_psram = info->is_desc && info->on_psram;
ESP_RETURN_ON_FALSE(!desc_on_psram, ESP_ERR_INVALID_ARG, TAG, "should not place descriptor on psram");
if (info->is_desc) {
if (dma_chan->pair->group->bus_id == SOC_GDMA_BUS_AHB) {
*alignment = GDMA_LL_AHB_DESC_ALIGNMENT;
}
#if SOC_AXI_GDMA_SUPPORTED
else if (dma_chan->pair->group->bus_id == SOC_GDMA_BUS_AXI) {
*alignment = GDMA_LL_AXI_DESC_ALIGNMENT;
}
#endif
} else {
if (dma_chan->psram_alignment == 0 && dma_chan->sram_alignment == 0) {
ESP_LOGI(TAG, "gdma_set_transfer_ability isn't called before, use fallback alignment");
*alignment = 4;
} else {
if (info->on_psram) {
*alignment = dma_chan->psram_alignment;
} else {
*alignment = dma_chan->sram_alignment;
}
}
}
return ESP_OK;
}

View File

@ -16,17 +16,20 @@ extern "C" {
#endif #endif
/** /**
* @breif DMA Mem info * @brief DMA Mem info
*/ */
typedef struct { typedef struct {
int heap_caps; ///< See heap caps int extra_heap_caps; ///< extra heap caps based on MALLOC_CAP_DMA
size_t dma_alignment; ///< DMA alignment size_t dma_alignment_bytes; ///< DMA alignment
size_t custom_alignment; ///< Set this if you have custom alignment. E.g. if `psram_trans_align` is set when using GDMA driver, or you're using IP self DMA (e.g. SDMMC)
} esp_dma_mem_info_t; } esp_dma_mem_info_t;
/** /**
* @brief Helper function for malloc a DMA capable memory buffer * @brief Helper function for malloc a DMA capable memory buffer
* *
* @note This API will take care of the cache alignment internally,
* you will need to set `esp_dma_mem_info_t: dma_alignment_bytes`
* with either the custom alignment or DMA alignment of used peripheral driver.
*
* @param[in] size Size in bytes, the amount of memory to allocate * @param[in] size Size in bytes, the amount of memory to allocate
* @param[in] dma_mem_info DMA and memory info, see `esp_dma_mem_info_t` * @param[in] dma_mem_info DMA and memory info, see `esp_dma_mem_info_t`
* @param[out] out_ptr A pointer to the memory allocated successfully * @param[out] out_ptr A pointer to the memory allocated successfully
@ -42,6 +45,7 @@ esp_err_t esp_dma_capable_malloc(size_t size, const esp_dma_mem_info_t *dma_mem_
/** /**
* @brief Helper function for calloc a DMA capable memory buffer * @brief Helper function for calloc a DMA capable memory buffer
* *
* @param[in] calloc_num Number of elements to allocate
* @param[in] size Size in bytes, the amount of memory to allocate * @param[in] size Size in bytes, the amount of memory to allocate
* @param[in] dma_mem_info DMA and memory info, see `esp_dma_mem_info_t` * @param[in] dma_mem_info DMA and memory info, see `esp_dma_mem_info_t`
* @param[out] out_ptr A pointer to the memory allocated successfully * @param[out] out_ptr A pointer to the memory allocated successfully
@ -52,10 +56,10 @@ esp_err_t esp_dma_capable_malloc(size_t size, const esp_dma_mem_info_t *dma_mem_
* - ESP_ERR_INVALID_ARG: Invalid argument * - ESP_ERR_INVALID_ARG: Invalid argument
* - ESP_ERR_NO_MEM: No enough memory for allocation * - ESP_ERR_NO_MEM: No enough memory for allocation
*/ */
esp_err_t esp_dma_capable_calloc(size_t n, size_t size, const esp_dma_mem_info_t *dma_mem_info, void **out_ptr, size_t *actual_size); esp_err_t esp_dma_capable_calloc(size_t calloc_num, size_t size, const esp_dma_mem_info_t *dma_mem_info, void **out_ptr, size_t *actual_size);
/** /**
* @brief Helper function to check if a DMA buffer meets alignment requirements * @brief Helper function to check if a DMA buffer pointer and size meet both hardware alignment requirements and custom alignment requirements
* *
* @param[in] ptr Pointer to the buffer * @param[in] ptr Pointer to the buffer
* @param[in] size Size of the buffer * @param[in] size Size of the buffer
@ -65,29 +69,16 @@ esp_err_t esp_dma_capable_calloc(size_t n, size_t size, const esp_dma_mem_info_t
* - True: Buffer is aligned * - True: Buffer is aligned
* - False: Buffer is not aligned, or buffer is not DMA capable * - False: Buffer is not aligned, or buffer is not DMA capable
*/ */
bool esp_dma_is_buffer_alignment_satisfied(const void *ptr, size_t size, esp_dma_mem_info_t *dma_mem_info); bool esp_dma_is_buffer_alignment_satisfied(const void *ptr, size_t size, esp_dma_mem_info_t dma_mem_info);
/** /**
* @brief Needed info to get GDMA alignment * @brief Needed info to get GDMA alignment
*/ */
typedef struct { typedef struct {
bool is_desc; bool is_desc; ///< allocate DMA descriptor
bool on_psram; bool on_psram; ///< allocate DMA from the PSRAM
} dma_alignment_info_t; } dma_alignment_info_t;
/**
* @brief Helper to get DMA alignment
*
* @param[in] gdma_chan_handle GDMA channel handle, if no GDMA supported, set it to NULL
* @param[in] info DMA alignment info
* @param[out] alignment Alignment
*
* @return
* - ESP_OK
* - ESP_ERR_INVALID_ARG Invalid argument
*/
esp_err_t esp_dma_get_alignment(void *gdma_chan_handle, const dma_alignment_info_t *info, size_t *alignment);
//-----------------------Deprecated APIs-----------------------// //-----------------------Deprecated APIs-----------------------//
/** /**
* DMA malloc flags * DMA malloc flags

View File

@ -457,26 +457,6 @@ esp_err_t gdma_config_crc_calculator(gdma_channel_handle_t dma_chan, const gdma_
esp_err_t gdma_crc_get_result(gdma_channel_handle_t dma_chan, uint32_t *result); esp_err_t gdma_crc_get_result(gdma_channel_handle_t dma_chan, uint32_t *result);
#endif // SOC_GDMA_SUPPORT_CRC #endif // SOC_GDMA_SUPPORT_CRC
/**
* @brief Needed info to get GDMA alignment
*/
typedef struct {
bool is_desc;
bool on_psram;
} gdma_alignment_info_t;
/**
* @brief Get GDMA alignment from the channel handle
*
* @param[in] dma_chan GDMA channel handle
* @param[in] info GDMA alignment info
* @param[out] alignment Alignment
*
* @return
* - ESP_OK
* - ESP_ERR_INVALID_ARG Invalid argument
*/
esp_err_t gdma_get_alignment(gdma_channel_handle_t dma_chan, const gdma_alignment_info_t *info, size_t *alignment);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -39,9 +39,8 @@ TEST_CASE("test esp_dma_capable_malloc for PSRAM", "[dma_utils]")
size_t actual_size = 0; size_t actual_size = 0;
esp_dma_mem_info_t dma_mem_info = { esp_dma_mem_info_t dma_mem_info = {
.heap_caps = MALLOC_CAP_SPIRAM, .extra_heap_caps = MALLOC_CAP_SPIRAM,
.dma_alignment = 4, .dma_alignment_bytes = 4,
.custom_alignment = 4,
}; };
//------ psram ------// //------ psram ------//
@ -65,91 +64,18 @@ TEST_CASE("test esp_dma_capable_malloc for PSRAM", "[dma_utils]")
} }
#endif #endif
TEST_CASE("test custom alignment", "[dma_utils]")
{
size_t test_size = 0;
void *test_ptr = NULL;
size_t actual_size = 0;
size_t custom_alignment = 512;
esp_dma_mem_info_t dma_mem_info = {
.heap_caps = MALLOC_CAP_SPIRAM,
.dma_alignment = 4,
.custom_alignment = custom_alignment,
};
test_size = custom_alignment + 3;
ESP_LOGI(TAG, "to alloc 0x%zx", test_size);
TEST_ESP_OK(esp_dma_capable_malloc(test_size, &dma_mem_info, &test_ptr, &actual_size));
ESP_LOGI(TAG, "get test_ptr: %p, actual_size: 0x%zx", test_ptr, actual_size);
TEST_ASSERT((uint32_t)test_ptr % custom_alignment == 0);
TEST_ASSERT(ALIGN_UP_BY(test_size, custom_alignment) == actual_size);
free(test_ptr);
}
TEST_CASE("test esp_dma_is_buffer_alignment_satisfied", "[dma_utils]") TEST_CASE("test esp_dma_is_buffer_alignment_satisfied", "[dma_utils]")
{ {
size_t test_size = 64; size_t test_size = 64;
void *test_ptr = NULL; void *test_ptr = NULL;
esp_dma_mem_info_t dma_mem_info = { esp_dma_mem_info_t dma_mem_info = {
.heap_caps = MALLOC_CAP_DMA, .dma_alignment_bytes = 4,
.dma_alignment = 4,
}; };
TEST_ESP_OK(esp_dma_capable_malloc(test_size, &dma_mem_info, &test_ptr, NULL)); TEST_ESP_OK(esp_dma_capable_malloc(test_size, &dma_mem_info, &test_ptr, NULL));
ESP_LOGI(TAG, "test_ptr %p", test_ptr); ESP_LOGI(TAG, "test_ptr %p", test_ptr);
bool is_aligned = esp_dma_is_buffer_alignment_satisfied(test_ptr, test_size, &dma_mem_info); bool is_aligned = esp_dma_is_buffer_alignment_satisfied(test_ptr, test_size, dma_mem_info);
TEST_ASSERT(is_aligned); TEST_ASSERT(is_aligned);
is_aligned = esp_dma_is_buffer_alignment_satisfied(test_ptr + 3, test_size, &dma_mem_info); is_aligned = esp_dma_is_buffer_alignment_satisfied(test_ptr + 3, test_size, dma_mem_info);
TEST_ASSERT(!is_aligned); TEST_ASSERT(!is_aligned);
} }
#if CONFIG_IDF_TARGET_ESP32P4
#define TEST_DMA_ALIGNMENT_INT 8
#else
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
#define TEST_DMA_ALIGNMENT_INT 4
#else
#define TEST_DMA_ALIGNMENT_INT 8
#endif
#endif
TEST_CASE("test esp_dma_get_alignment", "[dma_utils]")
{
size_t dma_alignment = 0;
gdma_channel_handle_t tx_channel = NULL;
#if SOC_GDMA_SUPPORTED
gdma_channel_alloc_config_t channel_config = {};
channel_config.direction = GDMA_CHANNEL_DIRECTION_TX;
TEST_ESP_OK(gdma_new_ahb_channel(&channel_config, &tx_channel));
gdma_transfer_ability_t ability = {
.psram_trans_align = 0,
.sram_trans_align = 8,
};
TEST_ESP_OK(gdma_set_transfer_ability(tx_channel, &ability));
#endif
dma_alignment_info_t internal_info = {};
TEST_ESP_OK(esp_dma_get_alignment(tx_channel, &internal_info, &dma_alignment));
ESP_LOGI(TAG, "dma_alignment: 0x%x", dma_alignment);
TEST_ASSERT(dma_alignment == TEST_DMA_ALIGNMENT_INT);
}
#if SOC_GDMA_SUPPORTED
TEST_CASE("test esp_dma_get_alignment with no transfer ability set", "[dma_utils]")
{
size_t dma_alignment = 0;
gdma_channel_handle_t tx_channel = NULL;
gdma_channel_alloc_config_t channel_config = {};
channel_config.direction = GDMA_CHANNEL_DIRECTION_TX;
TEST_ESP_OK(gdma_new_ahb_channel(&channel_config, &tx_channel));
dma_alignment_info_t internal_info = {};
TEST_ESP_OK(esp_dma_get_alignment(tx_channel, &internal_info, &dma_alignment));
ESP_LOGI(TAG, "dma_alignment: 0x%x", dma_alignment);
TEST_ASSERT(dma_alignment == 4);
}
#endif

View File

@ -99,6 +99,8 @@ extern "C" {
// TODO: Workaround for C5-beta3 only. C5-mp can still vectorized channels into an array in gdma_struct.h // TODO: Workaround for C5-beta3 only. C5-mp can still vectorized channels into an array in gdma_struct.h
#define GDMA_LL_CHANNEL_GET_REG_ADDR(dev, ch) ((volatile gdma_chn_reg_t*[]){&dev->channel0, &dev->channel1, &dev->channel2}[(ch)]) #define GDMA_LL_CHANNEL_GET_REG_ADDR(dev, ch) ((volatile gdma_chn_reg_t*[]){&dev->channel0, &dev->channel1, &dev->channel2}[(ch)])
#define GDMA_LL_AHB_DESC_ALIGNMENT 4
///////////////////////////////////// Common ///////////////////////////////////////// ///////////////////////////////////// Common /////////////////////////////////////////
/** /**

View File

@ -26,7 +26,7 @@ uint32_t hal_utils_calc_clk_div_frac_fast(const hal_utils_clk_info_t *clk_info,
// Carry bit if the decimal is greater than 1.0 - 1.0 / ((max_fract - 1) * 2) // Carry bit if the decimal is greater than 1.0 - 1.0 / ((max_fract - 1) * 2)
if (freq_error < clk_info->exp_freq_hz - clk_info->exp_freq_hz / (clk_info->max_fract - 1) * 2) { if (freq_error < clk_info->exp_freq_hz - clk_info->exp_freq_hz / (clk_info->max_fract - 1) * 2) {
// Calculate the Greatest Common Divisor, time complexity O(log n) // Calculate the Greatest Common Divisor, time complexity O(log n)
uint32_t gcd = _gcd(clk_info->exp_freq_hz, freq_error); uint32_t gcd = hal_utils_gcd(clk_info->exp_freq_hz, freq_error);
// divide by the Greatest Common Divisor to get the accurate fraction before normalization // divide by the Greatest Common Divisor to get the accurate fraction before normalization
div_denom = clk_info->exp_freq_hz / gcd; div_denom = clk_info->exp_freq_hz / gcd;
div_numer = freq_error / gcd; div_numer = freq_error / gcd;

View File

@ -23,7 +23,7 @@ typedef enum {
} hal_utils_div_round_opt_t; } hal_utils_div_round_opt_t;
/** /**
* @brief Clock infomation * @brief Clock information
* *
*/ */
typedef struct { typedef struct {
@ -53,7 +53,7 @@ typedef struct {
* @note Speed first algorithm, Time complexity O(log n). * @note Speed first algorithm, Time complexity O(log n).
* About 8~10 times faster than the accurate algorithm * About 8~10 times faster than the accurate algorithm
* *
* @param[in] clk_info The clock infomation * @param[in] clk_info The clock information
* @param[out] clk_div The clock division with integral and fractal part * @param[out] clk_div The clock division with integral and fractal part
* @return * @return
* - 0: Failed to get the result because the division is out of range * - 0: Failed to get the result because the division is out of range
@ -66,7 +66,7 @@ uint32_t hal_utils_calc_clk_div_frac_fast(const hal_utils_clk_info_t *clk_info,
* @note Accuracy first algorithm, Time complexity O(n). * @note Accuracy first algorithm, Time complexity O(n).
* About 1~hundreds times more accurate than the fast algorithm * About 1~hundreds times more accurate than the fast algorithm
* *
* @param[in] clk_info The clock infomation * @param[in] clk_info The clock information
* @param[out] clk_div The clock division with integral and fractal part * @param[out] clk_div The clock division with integral and fractal part
* @return * @return
* - 0: Failed to get the result because the division is out of range * - 0: Failed to get the result because the division is out of range
@ -77,12 +77,12 @@ uint32_t hal_utils_calc_clk_div_frac_accurate(const hal_utils_clk_info_t *clk_in
/** /**
* @brief Calculate the clock division without fractal part * @brief Calculate the clock division without fractal part
* *
* @param[in] clk_info The clock infomation * @param[in] clk_info The clock information
* @param[out] int_div The clock integral division * @param[out] int_div The clock integral division
* @return * @return
* - 0: Failed to get the result because the division is out of range, * - 0: Failed to get the result because the division is out of range,
* but parameter `int_div` will still be assigned to min/max division that given in `clk_info`, * but parameter `int_div` will still be assigned to min/max division that given in `clk_info`,
* incase the caller still want to use the min/max division in this case. * in case the caller still want to use the min/max division in this case.
* - others: The real output clock frequency * - others: The real output clock frequency
*/ */
uint32_t hal_utils_calc_clk_div_integer(const hal_utils_clk_info_t *clk_info, uint32_t *int_div); uint32_t hal_utils_calc_clk_div_integer(const hal_utils_clk_info_t *clk_info, uint32_t *int_div);
@ -103,20 +103,31 @@ static inline uint8_t hal_utils_bitwise_reverse8(uint8_t n)
} }
/** /**
* @brief helper function, calculate the Greatest Common Divisor * @brief Helper function to calculate the GCD between two numbers using the Euclidean algorithm.
* @note gcd(a, b) = gcd(b, a % b) * Calculate the Greatest Common Divisor (GDC) of two unsigned numbers
* @param a bigger value *
* @param b smaller value * @param num_1 First number
* @return result of gcd(a, b) * @param num_2 Second number
* @return GCD of 'a' and 'b'
*/ */
__attribute__((always_inline)) __attribute__((always_inline))
static inline uint32_t _gcd(uint32_t a, uint32_t b) static inline uint32_t hal_utils_gcd(uint32_t num_1, uint32_t num_2)
{ {
uint32_t c = a % b; uint32_t a, b, rem;
while (c != 0) { // Always mod larger number by smaller number
if (num_1 > num_2) {
a = num_1;
b = num_2;
} else {
b = num_2;
a = num_1;
}
rem = a % b;
while (rem != 0) {
a = b; a = b;
b = c; b = rem;
c = a % b; rem = a % b;
} }
return b; return b;
} }
@ -130,29 +141,11 @@ static inline uint32_t _gcd(uint32_t a, uint32_t b)
* @return LCM of A and B * @return LCM of A and B
*/ */
__attribute__((always_inline)) __attribute__((always_inline))
static inline uint32_t _lcm(uint32_t a, uint32_t b) static inline uint32_t hal_utils_calc_lcm(uint32_t a, uint32_t b)
{ {
a = a == 0 ? 1 : a; a = a == 0 ? 1 : a;
b = b == 0 ? 1 : b; b = b == 0 ? 1 : b;
return (a * b / _gcd(a, b)); return (a * b / hal_utils_gcd(a, b));
}
/**
* @brief Get the least common multiple of three integer
*
* @param[in] Integer A
* @param[in] Integer B
* @param[in] Integer C
*
* @return LCM of A, B and C
*/
__attribute__((always_inline))
static inline uint32_t _lcm_3(uint32_t a, uint32_t b, uint32_t c)
{
a = a == 0 ? 1 : a;
b = b == 0 ? 1 : b;
c = c == 0 ? 1 : c;
return _lcm(a, _lcm(b, c));
} }
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -46,7 +46,7 @@
#define AES_DMA_INTR_TRIG_LEN 2000 #define AES_DMA_INTR_TRIG_LEN 2000
/* With buffers in PSRAM (worst condition) we still achieve a speed of 4 MB/s /* With buffers in PSRAM (worst condition) we still achieve a speed of 4 MB/s
thus a 2 second timeout value should be suffient for even very large buffers. thus a 2 second timeout value should be sufficient for even very large buffers.
*/ */
#define AES_WAIT_INTR_TIMEOUT_MS 2000 #define AES_WAIT_INTR_TIMEOUT_MS 2000
@ -98,7 +98,7 @@ void esp_aes_intr_alloc(void)
static StaticSemaphore_t op_sem_buf; static StaticSemaphore_t op_sem_buf;
op_complete_sem = xSemaphoreCreateBinaryStatic(&op_sem_buf); op_complete_sem = xSemaphoreCreateBinaryStatic(&op_sem_buf);
// Static semaphore creation is unlikley to fail but still basic sanity // Static semaphore creation is unlikely to fail but still basic sanity
assert(op_complete_sem != NULL); assert(op_complete_sem != NULL);
} }
} }
@ -164,7 +164,7 @@ static int esp_aes_dma_wait_complete(bool use_intr, crypto_dma_desc_t *output_de
} }
/* Output buffers in external ram needs to be 16-byte aligned and DMA cant access input in the iCache mem range, /* Output buffers in external ram needs to be 16-byte aligned and DMA can't access input in the iCache mem range,
reallocate them into internal memory and encrypt in chunks to avoid reallocate them into internal memory and encrypt in chunks to avoid
having to malloc too big of a buffer having to malloc too big of a buffer
@ -276,7 +276,12 @@ static inline void dma_desc_append(crypto_dma_desc_t **head, crypto_dma_desc_t *
static inline void *aes_dma_calloc(size_t num, size_t size, uint32_t caps, size_t *actual_size) static inline void *aes_dma_calloc(size_t num, size_t size, uint32_t caps, size_t *actual_size)
{ {
void *ptr = NULL; void *ptr = NULL;
esp_dma_calloc(num, size, caps, &ptr, actual_size); esp_dma_mem_info_t dma_mem_info = {
.extra_heap_caps = caps,
.dma_alignment_bytes = 4,
};
//TODO: IDF-9638
esp_dma_capable_calloc(num, size, &dma_mem_info, &ptr, actual_size);
return ptr; return ptr;
} }

View File

@ -28,6 +28,7 @@
#include "esp_err.h" #include "esp_err.h"
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "sd_pwr_ctrl.h" #include "sd_pwr_ctrl.h"
#include "esp_dma_utils.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -79,7 +80,7 @@ typedef struct {
uint32_t erase_size_au: 16; /*!< Erase size for the purpose of timeout calculation, in multiples of allocation unit */ uint32_t erase_size_au: 16; /*!< Erase size for the purpose of timeout calculation, in multiples of allocation unit */
uint32_t cur_bus_width: 2; /*!< SD current bus width */ uint32_t cur_bus_width: 2; /*!< SD current bus width */
uint32_t discard_support: 1; /*!< SD discard feature support */ uint32_t discard_support: 1; /*!< SD discard feature support */
uint32_t fule_support: 1; /*!< SD FULE (Full User Area Logical Erase) feature support */ uint32_t fule_support: 1; /*!< SD FILE (Full User Area Logical Erase) feature support */
uint32_t erase_timeout: 6; /*!< Timeout (in seconds) for erase of a single allocation unit */ uint32_t erase_timeout: 6; /*!< Timeout (in seconds) for erase of a single allocation unit */
uint32_t erase_offset: 2; /*!< Constant timeout offset (in seconds) for any erase operation */ uint32_t erase_offset: 2; /*!< Constant timeout offset (in seconds) for any erase operation */
uint32_t reserved: 20; /*!< reserved for future expansion */ uint32_t reserved: 20; /*!< reserved for future expansion */
@ -209,6 +210,7 @@ typedef struct {
esp_err_t (*set_input_delay)(int slot, sdmmc_delay_phase_t delay_phase); /*!< set input delay phase */ esp_err_t (*set_input_delay)(int slot, sdmmc_delay_phase_t delay_phase); /*!< set input delay phase */
void* dma_aligned_buffer; /*!< Leave it NULL. Reserved for cache aligned buffers for SDIO mode */ 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 */ 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*/
} sdmmc_host_t; } sdmmc_host_t;
/** /**

View File

@ -326,13 +326,11 @@ esp_err_t sdmmc_send_cmd_send_scr(sdmmc_card_t* card, sdmmc_scr_t *out_scr)
{ {
size_t datalen = 8; size_t datalen = 8;
esp_err_t err = ESP_FAIL; esp_err_t err = ESP_FAIL;
uint32_t *buf = NULL; void *buf = NULL;
size_t actual_size = 0; size_t actual_size = 0;
esp_dma_mem_info_t dma_mem_info = { esp_dma_mem_info_t dma_mem_info;
.heap_caps = MALLOC_CAP_DMA, card->host.get_dma_info(card->host.slot, &dma_mem_info);
.custom_alignment = 4, err = esp_dma_capable_malloc(datalen, &dma_mem_info, &buf, &actual_size);
};
err = esp_dma_capable_malloc(datalen, &dma_mem_info, (void *)&buf, &actual_size);
if (err != ESP_OK) { if (err != ESP_OK) {
return err; return err;
} }
@ -405,11 +403,9 @@ esp_err_t sdmmc_write_sectors(sdmmc_card_t* card, const void* src,
esp_err_t err = ESP_OK; esp_err_t err = ESP_OK;
size_t block_size = card->csd.sector_size; size_t block_size = card->csd.sector_size;
esp_dma_mem_info_t dma_mem_info = { esp_dma_mem_info_t dma_mem_info;
.heap_caps = MALLOC_CAP_DMA, card->host.get_dma_info(card->host.slot, &dma_mem_info);
.custom_alignment = 4, if (esp_dma_is_buffer_alignment_satisfied(src, block_size * block_count, dma_mem_info)) {
};
if (esp_dma_is_buffer_alignment_satisfied(src, block_size * block_count, &dma_mem_info)) {
err = sdmmc_write_sectors_dma(card, src, start_block, block_count, block_size * block_count); err = sdmmc_write_sectors_dma(card, src, start_block, block_count, block_size * block_count);
} else { } else {
// SDMMC peripheral needs DMA-capable buffers. Split the write into // SDMMC peripheral needs DMA-capable buffers. Split the write into
@ -527,11 +523,9 @@ esp_err_t sdmmc_read_sectors(sdmmc_card_t* card, void* dst,
esp_err_t err = ESP_OK; esp_err_t err = ESP_OK;
size_t block_size = card->csd.sector_size; size_t block_size = card->csd.sector_size;
esp_dma_mem_info_t dma_mem_info = { esp_dma_mem_info_t dma_mem_info;
.heap_caps = MALLOC_CAP_DMA, card->host.get_dma_info(card->host.slot, &dma_mem_info);
.custom_alignment = 4, if (esp_dma_is_buffer_alignment_satisfied(dst, block_size * block_count, dma_mem_info)) {
};
if (esp_dma_is_buffer_alignment_satisfied(dst, block_size * block_count, &dma_mem_info)) {
err = sdmmc_read_sectors_dma(card, dst, start_block, block_count, block_size * block_count); err = sdmmc_read_sectors_dma(card, dst, start_block, block_count, block_size * block_count);
} else { } else {
// SDMMC peripheral needs DMA-capable buffers. Split the read into // SDMMC peripheral needs DMA-capable buffers. Split the read into

View File

@ -340,11 +340,8 @@ esp_err_t sdmmc_allocate_aligned_buf(sdmmc_card_t* card)
if (card->host.flags & SDMMC_HOST_FLAG_ALLOC_ALIGNED_BUF) { if (card->host.flags & SDMMC_HOST_FLAG_ALLOC_ALIGNED_BUF) {
void* buf = NULL; void* buf = NULL;
size_t actual_size = 0; size_t actual_size = 0;
// esp_err_t ret = esp_dma_malloc(SDMMC_IO_BLOCK_SIZE, 0, &buf, &actual_size); esp_dma_mem_info_t dma_mem_info;
esp_dma_mem_info_t dma_mem_info = { card->host.get_dma_info(card->host.slot, &dma_mem_info);
.heap_caps = MALLOC_CAP_DMA,
.custom_alignment = 4,
};
esp_err_t ret = esp_dma_capable_malloc(SDMMC_IO_BLOCK_SIZE, &dma_mem_info, &buf, &actual_size); esp_err_t ret = esp_dma_capable_malloc(SDMMC_IO_BLOCK_SIZE, &dma_mem_info, &buf, &actual_size);
if (ret != ESP_OK) { if (ret != ESP_OK) {

View File

@ -277,11 +277,9 @@ 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 */ .blklen = SDMMC_IO_BLOCK_SIZE /* TODO: read max block size from CIS */
}; };
esp_dma_mem_info_t dma_mem_info = { esp_dma_mem_info_t dma_mem_info;
.heap_caps = MALLOC_CAP_DMA, card->host.get_dma_info(card->host.slot, &dma_mem_info);
.custom_alignment = 4, if (unlikely(datalen > 0 && !esp_dma_is_buffer_alignment_satisfied(datap, buflen, dma_mem_info))) {
};
if (unlikely(datalen > 0 && !esp_dma_is_buffer_alignment_satisfied(datap, buflen, &dma_mem_info))) {
if (datalen > SDMMC_IO_BLOCK_SIZE || card->host.dma_aligned_buffer == NULL) { 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. // User gives unaligned buffer while `SDMMC_HOST_FLAG_ALLOC_ALIGNED_BUF` not set.
return ESP_ERR_INVALID_ARG; return ESP_ERR_INVALID_ARG;
@ -304,7 +302,7 @@ esp_err_t sdmmc_io_rw_extended(sdmmc_card_t* card, int func,
return ESP_ERR_INVALID_SIZE; return ESP_ERR_INVALID_SIZE;
} }
if (datalen == SDMMC_IO_BLOCK_SIZE) { if (datalen == SDMMC_IO_BLOCK_SIZE) {
count = 0; // See 5.3.1 SDIO simplifed spec count = 0; // See 5.3.1 SDIO simplified spec
} else { } else {
count = datalen; count = datalen;
} }
@ -390,11 +388,9 @@ esp_err_t sdmmc_io_write_bytes(sdmmc_card_t* card, uint32_t function,
esp_err_t sdmmc_io_read_blocks(sdmmc_card_t* card, uint32_t function, esp_err_t sdmmc_io_read_blocks(sdmmc_card_t* card, uint32_t function,
uint32_t addr, void* dst, size_t size) uint32_t addr, void* dst, size_t size)
{ {
esp_dma_mem_info_t dma_mem_info = { esp_dma_mem_info_t dma_mem_info;
.heap_caps = MALLOC_CAP_DMA, card->host.get_dma_info(card->host.slot, &dma_mem_info);
.custom_alignment = 4, if (unlikely(!esp_dma_is_buffer_alignment_satisfied(dst, size, dma_mem_info))) {
};
if (unlikely(!esp_dma_is_buffer_alignment_satisfied(dst, size, &dma_mem_info))) {
return ESP_ERR_INVALID_ARG; return ESP_ERR_INVALID_ARG;
} }
return sdmmc_io_rw_extended(card, function, addr, return sdmmc_io_rw_extended(card, function, addr,
@ -405,11 +401,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, esp_err_t sdmmc_io_write_blocks(sdmmc_card_t* card, uint32_t function,
uint32_t addr, const void* src, size_t size) uint32_t addr, const void* src, size_t size)
{ {
esp_dma_mem_info_t dma_mem_info = { esp_dma_mem_info_t dma_mem_info;
.heap_caps = MALLOC_CAP_DMA, card->host.get_dma_info(card->host.slot, &dma_mem_info);
.custom_alignment = 4, if (unlikely(!esp_dma_is_buffer_alignment_satisfied(src, size, dma_mem_info))) {
};
if (unlikely(!esp_dma_is_buffer_alignment_satisfied(src, size, &dma_mem_info))) {
return ESP_ERR_INVALID_ARG; return ESP_ERR_INVALID_ARG;
} }
return sdmmc_io_rw_extended(card, function, addr, return sdmmc_io_rw_extended(card, function, addr,

View File

@ -28,10 +28,8 @@ esp_err_t sdmmc_init_mmc_read_ext_csd(sdmmc_card_t* card)
esp_err_t err = ESP_OK; esp_err_t err = ESP_OK;
uint8_t* ext_csd = NULL; uint8_t* ext_csd = NULL;
size_t actual_size = 0; size_t actual_size = 0;
esp_dma_mem_info_t dma_mem_info = { esp_dma_mem_info_t dma_mem_info;
.heap_caps = MALLOC_CAP_DMA, card->host.get_dma_info(card->host.slot, &dma_mem_info);
.custom_alignment = 4,
};
err = esp_dma_capable_malloc(EXT_CSD_MMC_SIZE, &dma_mem_info, (void *)&ext_csd, &actual_size); err = esp_dma_capable_malloc(EXT_CSD_MMC_SIZE, &dma_mem_info, (void *)&ext_csd, &actual_size);
if (err != ESP_OK) { if (err != ESP_OK) {
ESP_LOGE(TAG, "%s: could not allocate ext_csd", __func__); ESP_LOGE(TAG, "%s: could not allocate ext_csd", __func__);
@ -259,10 +257,8 @@ 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 */ /* ensure EXT_CSD buffer is available before starting any SD-card operation */
uint8_t* ext_csd = NULL; uint8_t* ext_csd = NULL;
size_t actual_size = 0; size_t actual_size = 0;
esp_dma_mem_info_t dma_mem_info = { esp_dma_mem_info_t dma_mem_info;
.heap_caps = MALLOC_CAP_DMA, card->host.get_dma_info(card->host.slot, &dma_mem_info);
.custom_alignment = 4,
};
esp_err_t err = esp_dma_capable_malloc(EXT_CSD_MMC_SIZE, &dma_mem_info, (void *)&ext_csd, &actual_size); esp_err_t err = esp_dma_capable_malloc(EXT_CSD_MMC_SIZE, &dma_mem_info, (void *)&ext_csd, &actual_size);
if (err != ESP_OK) { if (err != ESP_OK) {
ESP_LOGE(TAG, "%s: could not allocate ext_csd", __func__); ESP_LOGE(TAG, "%s: could not allocate ext_csd", __func__);

View File

@ -91,10 +91,8 @@ esp_err_t sdmmc_init_sd_ssr(sdmmc_card_t* card)
*/ */
uint32_t* sd_ssr = NULL; uint32_t* sd_ssr = NULL;
size_t actual_size = 0; size_t actual_size = 0;
esp_dma_mem_info_t dma_mem_info = { esp_dma_mem_info_t dma_mem_info;
.heap_caps = MALLOC_CAP_DMA, card->host.get_dma_info(card->host.slot, &dma_mem_info);
.custom_alignment = 4,
};
err = esp_dma_capable_calloc(1, SD_SSR_SIZE, &dma_mem_info, (void *)&sd_ssr, &actual_size); err = esp_dma_capable_calloc(1, SD_SSR_SIZE, &dma_mem_info, (void *)&sd_ssr, &actual_size);
if (err != ESP_OK) { if (err != ESP_OK) {
ESP_LOGE(TAG, "%s: could not allocate sd_ssr", __func__); ESP_LOGE(TAG, "%s: could not allocate sd_ssr", __func__);
@ -243,10 +241,8 @@ esp_err_t sdmmc_enable_hs_mode(sdmmc_card_t* card)
size_t actual_size = 0; size_t actual_size = 0;
sdmmc_switch_func_rsp_t *response = NULL; sdmmc_switch_func_rsp_t *response = NULL;
esp_dma_mem_info_t dma_mem_info = { esp_dma_mem_info_t dma_mem_info;
.heap_caps = MALLOC_CAP_DMA, card->host.get_dma_info(card->host.slot, &dma_mem_info);
.custom_alignment = 4,
};
esp_err_t err = esp_dma_capable_malloc(sizeof(*response), &dma_mem_info, (void *)&response, &actual_size); esp_err_t err = esp_dma_capable_malloc(sizeof(*response), &dma_mem_info, (void *)&response, &actual_size);
assert(actual_size == sizeof(*response)); assert(actual_size == sizeof(*response));
if (err != ESP_OK) { if (err != ESP_OK) {

View File

@ -1040,18 +1040,18 @@ static void port_obj_free(port_t *port)
void *frame_list_alloc(size_t frame_list_len) void *frame_list_alloc(size_t frame_list_len)
{ {
esp_err_t ret = ESP_FAIL; esp_err_t ret;
void *frame_list = NULL; void *frame_list = NULL;
size_t actual_size = 0;
esp_dma_mem_info_t dma_mem_info = { esp_dma_mem_info_t dma_mem_info = {
.heap_caps = MALLOC_CAP_DMA, .dma_alignment_bytes = USB_DWC_FRAME_LIST_MEM_ALIGN,
.custom_alignment = USB_DWC_FRAME_LIST_MEM_ALIGN,
}; };
ret = esp_dma_capable_calloc(frame_list_len, sizeof(uint32_t), &dma_mem_info, &frame_list, NULL); ret = esp_dma_capable_calloc(frame_list_len, sizeof(uint32_t), &dma_mem_info, &frame_list, &actual_size);
assert(ret != ESP_ERR_INVALID_ARG); assert(ret == ESP_OK);
// Both Frame List start address and size should be already cache aligned so this is only a sanity check // Both Frame List start address and size should be already cache aligned so this is only a sanity check
if (frame_list) { if (frame_list) {
if (!esp_dma_is_buffer_alignment_satisfied(frame_list, frame_list_len * sizeof(uint32_t), &dma_mem_info)) { if (!esp_dma_is_buffer_alignment_satisfied(frame_list, actual_size, dma_mem_info)) {
// This should never happen // This should never happen
heap_caps_free(frame_list); heap_caps_free(frame_list);
frame_list = NULL; frame_list = NULL;
@ -1072,17 +1072,17 @@ void *transfer_descriptor_list_alloc(size_t list_len, size_t *list_len_bytes_out
*list_len_bytes_out = list_len * sizeof(usb_dwc_ll_dma_qtd_t); *list_len_bytes_out = list_len * sizeof(usb_dwc_ll_dma_qtd_t);
#endif // SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE #endif // SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
esp_err_t ret = ESP_FAIL; esp_err_t ret;
void *qtd_list = NULL; void *qtd_list = NULL;
size_t actual_size = 0;
esp_dma_mem_info_t dma_mem_info = { esp_dma_mem_info_t dma_mem_info = {
.heap_caps = MALLOC_CAP_DMA, .dma_alignment_bytes = USB_DWC_QTD_LIST_MEM_ALIGN,
.custom_alignment = USB_DWC_QTD_LIST_MEM_ALIGN,
}; };
ret = esp_dma_capable_calloc(*list_len_bytes_out, 1, &dma_mem_info, &qtd_list, NULL); ret = esp_dma_capable_calloc(*list_len_bytes_out, 1, &dma_mem_info, &qtd_list, &actual_size);
assert(ret != ESP_ERR_INVALID_ARG); assert(ret == ESP_OK);
if (qtd_list) { if (qtd_list) {
if (!esp_dma_is_buffer_alignment_satisfied(qtd_list, *list_len_bytes_out * sizeof(usb_dwc_ll_dma_qtd_t), &dma_mem_info)) { if (!esp_dma_is_buffer_alignment_satisfied(qtd_list, actual_size, dma_mem_info)) {
// This should never happen // This should never happen
heap_caps_free(qtd_list); heap_caps_free(qtd_list);
qtd_list = NULL; qtd_list = NULL;

View File

@ -267,11 +267,7 @@ urb_t *test_hcd_alloc_urb(int num_isoc_packets, size_t data_buffer_size)
void *data_buffer; void *data_buffer;
size_t real_size; size_t real_size;
esp_dma_mem_info_t dma_mem_info = { esp_dma_mem_info_t dma_mem_info = {
.dma_type = ESP_DMA_OTHERS, .dma_alignment_bytes = 4,
.mem_flags = {
.dir = ESP_DMA_MEM_DIR_DONT_CARE,
},
.custom_alignment = 4,
}; };
esp_dma_capable_malloc(data_buffer_size, &dma_mem_info, &data_buffer, &real_size); esp_dma_capable_malloc(data_buffer_size, &dma_mem_info, &data_buffer, &real_size);
TEST_ASSERT_NOT_NULL_MESSAGE(urb, "Failed to allocate URB"); TEST_ASSERT_NOT_NULL_MESSAGE(urb, "Failed to allocate URB");

View File

@ -15,12 +15,9 @@ urb_t *urb_alloc(size_t data_buffer_size, int num_isoc_packets)
void *data_buffer; void *data_buffer;
size_t real_size; size_t real_size;
esp_dma_mem_info_t dma_mem_info = { esp_dma_mem_info_t dma_mem_info = {
.dma_type = ESP_DMA_OTHERS, .dma_alignment_bytes = 4,
.mem_flags = {
.dir = ESP_DMA_MEM_DIR_DONT_CARE,
},
.custom_alignment = 4,
}; };
//TODO: IDF-9639
esp_dma_capable_malloc(data_buffer_size, &dma_mem_info, &data_buffer, &real_size); esp_dma_capable_malloc(data_buffer_size, &dma_mem_info, &data_buffer, &real_size);
if (urb == NULL || data_buffer == NULL) { if (urb == NULL || data_buffer == NULL) {
goto err; goto err;

View File

@ -109,7 +109,7 @@ cache memory synchronization is usually considered when DMA is involved. ESP-IDF
- :cpp:func:`esp_dma_capable_malloc`, this API allocates a chunk of memory that meets the alignment requirement from both the cache and the DMA. - :cpp:func:`esp_dma_capable_malloc`, this API allocates a chunk of memory that meets the alignment requirement from both the cache and the DMA.
- :cpp:func:`esp_dma_capable_calloc`, this API allocates a chunk of memory that meets the alignment requirement from both the cache and the DMA. The initialized value in the memory is set to zero. - :cpp:func:`esp_dma_capable_calloc`, this API allocates a chunk of memory that meets the alignment requirement from both the cache and the DMA. The initialized value in the memory is set to zero.
You can also use :cpp:member:`esp_dma_mem_info_t::on_psram` to allocate from the PSRAM. You can also use :c:macro:`ESP_DMA_MALLOC_FLAG_PSRAM` to allocate from the PSRAM.
Warning for Address Alignment Requirement Warning for Address Alignment Requirement

View File

@ -448,11 +448,11 @@ void app_main(void)
lv_color_t *buf1 = NULL; lv_color_t *buf1 = NULL;
lv_color_t *buf2 = NULL; lv_color_t *buf2 = NULL;
esp_dma_mem_info_t dma_mem_info = { esp_dma_mem_info_t dma_mem_info = {
.dma_alignment = 4, .dma_alignment_bytes = 4,
#if CONFIG_EXAMPLE_LCD_I80_COLOR_IN_PSRAM #if CONFIG_EXAMPLE_LCD_I80_COLOR_IN_PSRAM
.heap_caps = MALLOC_CAP_SPIRAM, .extra_heap_caps = MALLOC_CAP_SPIRAM,
#else #else
.heap_caps = MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL, .extra_heap_caps = MALLOC_CAP_INTERNAL,
#endif // CONFIG_EXAMPLE_LCD_I80_COLOR_IN_PSRAM #endif // CONFIG_EXAMPLE_LCD_I80_COLOR_IN_PSRAM
}; };
ESP_ERROR_CHECK(esp_dma_capable_malloc(EXAMPLE_LCD_H_RES * 100 * sizeof(lv_color_t), &dma_mem_info, (void *)&buf1, NULL)); ESP_ERROR_CHECK(esp_dma_capable_malloc(EXAMPLE_LCD_H_RES * 100 * sizeof(lv_color_t), &dma_mem_info, (void *)&buf1, NULL));