mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-02 03:00:34 +03:00
Merge branch 'feat/gdma_set_burst_size_v5.3' into 'release/v5.3'
feat(gdma): return alignment constraints required by the GDMA channel (v5.3) See merge request espressif/esp-idf!31113
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -48,7 +48,6 @@ typedef struct async_memcpy_transaction_t {
|
||||
/// @note - Number of transaction objects are determined by the backlog parameter
|
||||
typedef struct {
|
||||
async_memcpy_context_t parent; // Parent IO interface
|
||||
size_t sram_trans_align; // DMA transfer alignment (both in size and address) for SRAM memory
|
||||
size_t max_single_dma_buffer; // max DMA buffer size by a single descriptor
|
||||
cp_dma_hal_context_t hal; // CPDMA hal
|
||||
intr_handle_t intr; // CPDMA interrupt handle
|
||||
@@ -90,7 +89,7 @@ esp_err_t esp_async_memcpy_install_cpdma(const async_memcpy_config_t *config, as
|
||||
uint32_t trans_queue_len = config->backlog ? config->backlog : DEFAULT_TRANSACTION_QUEUE_LENGTH;
|
||||
// allocate memory for transaction pool, aligned to 4 because the trans->eof_node requires that alignment
|
||||
mcp_dma->transaction_pool = heap_caps_aligned_calloc(4, trans_queue_len, sizeof(async_memcpy_transaction_t),
|
||||
MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT | MALLOC_CAP_DMA);
|
||||
MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT | MALLOC_CAP_DMA);
|
||||
ESP_GOTO_ON_FALSE(mcp_dma->transaction_pool, ESP_ERR_NO_MEM, err, TAG, "no mem for transaction pool");
|
||||
|
||||
// Init hal context
|
||||
@@ -111,8 +110,7 @@ esp_err_t esp_async_memcpy_install_cpdma(const async_memcpy_config_t *config, as
|
||||
// initialize other members
|
||||
portMUX_INITIALIZE(&mcp_dma->spin_lock);
|
||||
atomic_init(&mcp_dma->fsm, MCP_FSM_IDLE);
|
||||
mcp_dma->sram_trans_align = config->sram_trans_align;
|
||||
size_t trans_align = config->sram_trans_align;
|
||||
size_t trans_align = config->dma_burst_size;
|
||||
mcp_dma->max_single_dma_buffer = trans_align ? ALIGN_DOWN(DMA_DESCRIPTOR_BUFFER_MAX_SIZE, trans_align) : DMA_DESCRIPTOR_BUFFER_MAX_SIZE;
|
||||
mcp_dma->parent.del = mcp_cpdma_del;
|
||||
mcp_dma->parent.memcpy = mcp_cpdma_memcpy;
|
||||
@@ -240,12 +238,6 @@ static esp_err_t mcp_cpdma_memcpy(async_memcpy_context_t *ctx, void *dst, void *
|
||||
esp_err_t ret = ESP_OK;
|
||||
async_memcpy_cpdma_context_t *mcp_dma = __containerof(ctx, async_memcpy_cpdma_context_t, parent);
|
||||
ESP_RETURN_ON_FALSE(esp_ptr_internal(src) && esp_ptr_internal(dst), ESP_ERR_INVALID_ARG, TAG, "CP_DMA can only access SRAM");
|
||||
// alignment check
|
||||
if (mcp_dma->sram_trans_align) {
|
||||
ESP_RETURN_ON_FALSE((((intptr_t)dst & (mcp_dma->sram_trans_align - 1)) == 0), ESP_ERR_INVALID_ARG, TAG, "buffer address not aligned: %p -> %p", src, dst);
|
||||
ESP_RETURN_ON_FALSE(((n & (mcp_dma->sram_trans_align - 1)) == 0), ESP_ERR_INVALID_ARG, TAG,
|
||||
"copy size should align to %d bytes", mcp_dma->sram_trans_align);
|
||||
}
|
||||
async_memcpy_transaction_t *trans = NULL;
|
||||
// pick one transaction node from idle queue
|
||||
trans = try_pop_trans_from_idle_queue(mcp_dma);
|
||||
@@ -257,12 +249,12 @@ static esp_err_t mcp_cpdma_memcpy(async_memcpy_context_t *ctx, void *dst, void *
|
||||
uint32_t num_desc_per_path = (n + max_single_dma_buffer - 1) / max_single_dma_buffer;
|
||||
// allocate DMA descriptors, descriptors need a strict alignment
|
||||
trans->tx_desc_link = heap_caps_aligned_calloc(4, num_desc_per_path, sizeof(dma_descriptor_align4_t),
|
||||
MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT | MALLOC_CAP_DMA);
|
||||
MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT | MALLOC_CAP_DMA);
|
||||
ESP_GOTO_ON_FALSE(trans->tx_desc_link, ESP_ERR_NO_MEM, err, TAG, "no mem for DMA descriptors");
|
||||
// don't have to allocate the EOF descriptor, we will use trans->eof_node as the RX EOF descriptor
|
||||
if (num_desc_per_path > 1) {
|
||||
trans->rx_desc_link = heap_caps_aligned_calloc(4, num_desc_per_path - 1, sizeof(dma_descriptor_align4_t),
|
||||
MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT | MALLOC_CAP_DMA);
|
||||
MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT | MALLOC_CAP_DMA);
|
||||
ESP_GOTO_ON_FALSE(trans->rx_desc_link, ESP_ERR_NO_MEM, err, TAG, "no mem for DMA descriptors");
|
||||
} else {
|
||||
// small copy buffer, use the trans->eof_node is sufficient
|
||||
|
||||
@@ -69,8 +69,10 @@ typedef struct async_memcpy_transaction_t {
|
||||
typedef struct {
|
||||
async_memcpy_context_t parent; // Parent IO interface
|
||||
size_t descriptor_align; // DMA descriptor alignment
|
||||
size_t sram_trans_align; // DMA buffer alignment (both in size and address) for SRAM memory
|
||||
size_t psram_trans_align; // DMA buffer alignment (both in size and address) for PSRAM memory
|
||||
size_t rx_int_mem_alignment; // DMA buffer alignment (both in size and address) for internal RX memory
|
||||
size_t rx_ext_mem_alignment; // DMA buffer alignment (both in size and address) for external RX memory
|
||||
size_t tx_int_mem_alignment; // DMA buffer alignment (both in size and address) for internal TX memory
|
||||
size_t tx_ext_mem_alignment; // DMA buffer alignment (both in size and address) for external TX memory
|
||||
size_t max_single_dma_buffer; // max DMA buffer size by a single descriptor
|
||||
int gdma_bus_id; // GDMA bus id (AHB, AXI, etc.)
|
||||
gdma_channel_handle_t tx_channel; // GDMA TX channel handle
|
||||
@@ -146,12 +148,12 @@ static esp_err_t esp_async_memcpy_install_gdma_template(const async_memcpy_confi
|
||||
ESP_GOTO_ON_ERROR(gdma_connect(mcp_gdma->rx_channel, m2m_trigger), err, TAG, "GDMA rx connect failed");
|
||||
ESP_GOTO_ON_ERROR(gdma_connect(mcp_gdma->tx_channel, m2m_trigger), err, TAG, "GDMA tx connect failed");
|
||||
|
||||
gdma_transfer_ability_t transfer_ability = {
|
||||
.sram_trans_align = config->sram_trans_align,
|
||||
.psram_trans_align = config->psram_trans_align,
|
||||
gdma_transfer_config_t transfer_cfg = {
|
||||
.max_data_burst_size = config->dma_burst_size ? config->dma_burst_size : 16,
|
||||
.access_ext_mem = true, // allow to do memory copy from/to external memory
|
||||
};
|
||||
ESP_GOTO_ON_ERROR(gdma_set_transfer_ability(mcp_gdma->tx_channel, &transfer_ability), err, TAG, "set tx trans ability failed");
|
||||
ESP_GOTO_ON_ERROR(gdma_set_transfer_ability(mcp_gdma->rx_channel, &transfer_ability), err, TAG, "set rx trans ability failed");
|
||||
ESP_GOTO_ON_ERROR(gdma_config_transfer(mcp_gdma->tx_channel, &transfer_cfg), err, TAG, "config transfer for tx channel failed");
|
||||
ESP_GOTO_ON_ERROR(gdma_config_transfer(mcp_gdma->rx_channel, &transfer_cfg), err, TAG, "config transfer for rx channel failed");
|
||||
|
||||
// register rx eof callback
|
||||
gdma_rx_event_callbacks_t cbs = {
|
||||
@@ -172,15 +174,13 @@ static esp_err_t esp_async_memcpy_install_gdma_template(const async_memcpy_confi
|
||||
atomic_init(&mcp_gdma->fsm, MCP_FSM_IDLE);
|
||||
mcp_gdma->gdma_bus_id = gdma_bus_id;
|
||||
|
||||
uint32_t psram_cache_line_size = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_DATA);
|
||||
uint32_t sram_cache_line_size = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA);
|
||||
// if the psram_trans_align is configured to zero, we should fall back to use the data cache line size
|
||||
size_t psram_trans_align = MAX(psram_cache_line_size, config->psram_trans_align);
|
||||
size_t sram_trans_align = MAX(sram_cache_line_size, config->sram_trans_align);
|
||||
size_t trans_align = MAX(sram_trans_align, psram_trans_align);
|
||||
mcp_gdma->max_single_dma_buffer = ALIGN_DOWN(DMA_DESCRIPTOR_BUFFER_MAX_SIZE, trans_align);
|
||||
mcp_gdma->psram_trans_align = psram_trans_align;
|
||||
mcp_gdma->sram_trans_align = sram_trans_align;
|
||||
// get the buffer alignment required by the GDMA channel
|
||||
gdma_get_alignment_constraints(mcp_gdma->rx_channel, &mcp_gdma->rx_int_mem_alignment, &mcp_gdma->rx_ext_mem_alignment);
|
||||
gdma_get_alignment_constraints(mcp_gdma->tx_channel, &mcp_gdma->tx_int_mem_alignment, &mcp_gdma->tx_ext_mem_alignment);
|
||||
|
||||
size_t buf_align = MAX(MAX(mcp_gdma->rx_int_mem_alignment, mcp_gdma->rx_ext_mem_alignment),
|
||||
MAX(mcp_gdma->tx_int_mem_alignment, mcp_gdma->tx_ext_mem_alignment));
|
||||
mcp_gdma->max_single_dma_buffer = ALIGN_DOWN(DMA_DESCRIPTOR_BUFFER_MAX_SIZE, buf_align);
|
||||
mcp_gdma->parent.del = mcp_gdma_del;
|
||||
mcp_gdma->parent.memcpy = mcp_gdma_memcpy;
|
||||
#if SOC_GDMA_SUPPORT_ETM
|
||||
@@ -335,29 +335,21 @@ static async_memcpy_transaction_t *try_pop_trans_from_idle_queue(async_memcpy_gd
|
||||
static bool check_buffer_alignment(async_memcpy_gdma_context_t *mcp_gdma, void *src, void *dst, size_t n)
|
||||
{
|
||||
bool valid = true;
|
||||
uint32_t psram_align_mask = 0;
|
||||
uint32_t sram_align_mask = 0;
|
||||
if (mcp_gdma->psram_trans_align) {
|
||||
psram_align_mask = mcp_gdma->psram_trans_align - 1;
|
||||
}
|
||||
if (mcp_gdma->sram_trans_align) {
|
||||
sram_align_mask = mcp_gdma->sram_trans_align - 1;
|
||||
}
|
||||
|
||||
if (esp_ptr_external_ram(dst)) {
|
||||
valid = valid && (((uint32_t)dst & psram_align_mask) == 0);
|
||||
valid = valid && ((n & psram_align_mask) == 0);
|
||||
valid = valid && (((uint32_t)dst & (mcp_gdma->rx_ext_mem_alignment - 1)) == 0);
|
||||
valid = valid && ((n & (mcp_gdma->rx_ext_mem_alignment - 1)) == 0);
|
||||
} else {
|
||||
valid = valid && (((uint32_t)dst & sram_align_mask) == 0);
|
||||
valid = valid && ((n & sram_align_mask) == 0);
|
||||
valid = valid && (((uint32_t)dst & (mcp_gdma->rx_int_mem_alignment - 1)) == 0);
|
||||
valid = valid && ((n & (mcp_gdma->rx_int_mem_alignment - 1)) == 0);
|
||||
}
|
||||
|
||||
if (esp_ptr_external_ram(src)) {
|
||||
valid = valid && (((uint32_t)src & psram_align_mask) == 0);
|
||||
valid = valid && ((n & psram_align_mask) == 0);
|
||||
valid = valid && (((uint32_t)src & (mcp_gdma->tx_ext_mem_alignment - 1)) == 0);
|
||||
valid = valid && ((n & (mcp_gdma->tx_ext_mem_alignment - 1)) == 0);
|
||||
} else {
|
||||
valid = valid && (((uint32_t)src & sram_align_mask) == 0);
|
||||
valid = valid && ((n & sram_align_mask) == 0);
|
||||
valid = valid && (((uint32_t)src & (mcp_gdma->tx_int_mem_alignment - 1)) == 0);
|
||||
valid = valid && ((n & (mcp_gdma->tx_int_mem_alignment - 1)) == 0);
|
||||
}
|
||||
|
||||
return valid;
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/param.h>
|
||||
#include "sdkconfig.h"
|
||||
#if CONFIG_GDMA_ENABLE_DEBUG_LOG
|
||||
// The local log level must be defined before including esp_log.h
|
||||
@@ -42,10 +43,9 @@
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_memory_utils.h"
|
||||
#include "esp_flash_encrypt.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#include "gdma_priv.h"
|
||||
#include "hal/cache_hal.h"
|
||||
#include "hal/cache_ll.h"
|
||||
|
||||
#if CONFIG_PM_ENABLE && SOC_PM_SUPPORT_TOP_PD
|
||||
#include "esp_private/gdma_sleep_retention.h"
|
||||
@@ -354,46 +354,68 @@ esp_err_t gdma_get_free_m2m_trig_id_mask(gdma_channel_handle_t dma_chan, uint32_
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t gdma_set_transfer_ability(gdma_channel_handle_t dma_chan, const gdma_transfer_ability_t *ability)
|
||||
esp_err_t gdma_config_transfer(gdma_channel_handle_t dma_chan, const gdma_transfer_config_t *config)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(dma_chan && ability, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
ESP_RETURN_ON_FALSE(dma_chan && config, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
uint32_t max_data_burst_size = config->max_data_burst_size;
|
||||
if (max_data_burst_size) {
|
||||
// burst size must be power of 2
|
||||
ESP_RETURN_ON_FALSE((max_data_burst_size & (max_data_burst_size - 1)) == 0, ESP_ERR_INVALID_ARG,
|
||||
TAG, "invalid max_data_burst_size: %"PRIu32, max_data_burst_size);
|
||||
}
|
||||
gdma_pair_t *pair = dma_chan->pair;
|
||||
gdma_group_t *group = pair->group;
|
||||
gdma_hal_context_t *hal = &group->hal;
|
||||
size_t int_mem_alignment = 1;
|
||||
size_t ext_mem_alignment = 1;
|
||||
|
||||
size_t sram_alignment = ability->sram_trans_align;
|
||||
size_t psram_alignment = ability->psram_trans_align;
|
||||
// alignment should be 2^n
|
||||
ESP_RETURN_ON_FALSE((sram_alignment & (sram_alignment - 1)) == 0, ESP_ERR_INVALID_ARG,
|
||||
TAG, "invalid sram alignment: %zu", sram_alignment);
|
||||
|
||||
uint32_t ext_mem_cache_line_size = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_DATA);
|
||||
if (psram_alignment == 0) {
|
||||
// fall back to use the same size of the psram data cache line size
|
||||
psram_alignment = ext_mem_cache_line_size;
|
||||
}
|
||||
if (psram_alignment > ext_mem_cache_line_size) {
|
||||
ESP_RETURN_ON_FALSE(((psram_alignment % ext_mem_cache_line_size) == 0), ESP_ERR_INVALID_ARG,
|
||||
TAG, "psram_alignment(%d) should be multiple of the ext_mem_cache_line_size(%"PRIu32")",
|
||||
psram_alignment, ext_mem_cache_line_size);
|
||||
// always enable descriptor burst as the descriptor is always word aligned and is in the internal SRAM
|
||||
bool en_desc_burst = true;
|
||||
bool en_data_burst = max_data_burst_size > 0;
|
||||
gdma_hal_enable_burst(hal, pair->pair_id, dma_chan->direction, en_data_burst, en_desc_burst);
|
||||
if (en_data_burst) {
|
||||
gdma_hal_set_burst_size(hal, pair->pair_id, dma_chan->direction, max_data_burst_size);
|
||||
}
|
||||
|
||||
// if the DMA can't access the PSRAM, this HAL function is no-op
|
||||
gdma_hal_set_ext_mem_align(hal, pair->pair_id, dma_chan->direction, psram_alignment);
|
||||
|
||||
// TX channel can always enable burst mode, no matter data alignment
|
||||
bool en_burst = true;
|
||||
if (dma_chan->direction == GDMA_CHANNEL_DIRECTION_RX) {
|
||||
// RX channel burst mode depends on specific data alignment
|
||||
en_burst = sram_alignment >= 4;
|
||||
#if GDMA_LL_AHB_RX_BURST_NEEDS_ALIGNMENT
|
||||
if (en_data_burst && dma_chan->direction == GDMA_CHANNEL_DIRECTION_RX) {
|
||||
int_mem_alignment = MAX(int_mem_alignment, 4);
|
||||
ext_mem_alignment = MAX(ext_mem_alignment, max_data_burst_size);
|
||||
}
|
||||
gdma_hal_enable_burst(hal, pair->pair_id, dma_chan->direction, en_burst, en_burst);
|
||||
#endif
|
||||
|
||||
dma_chan->sram_alignment = sram_alignment;
|
||||
dma_chan->psram_alignment = psram_alignment;
|
||||
ESP_LOGD(TAG, "%s channel (%d,%d), (%u:%u) bytes aligned, burst %s", dma_chan->direction == GDMA_CHANNEL_DIRECTION_TX ? "tx" : "rx",
|
||||
group->group_id, pair->pair_id, sram_alignment, psram_alignment, en_burst ? "enabled" : "disabled");
|
||||
// if MSPI encryption is enabled, and DMA wants to read/write external memory
|
||||
if (esp_flash_encryption_enabled()) {
|
||||
gdma_hal_enable_access_encrypt_mem(hal, pair->pair_id, dma_chan->direction, config->access_ext_mem);
|
||||
// when DMA access the encrypted memory, extra alignment is needed, for both internal and external memory
|
||||
if (config->access_ext_mem) {
|
||||
ext_mem_alignment = MAX(ext_mem_alignment, GDMA_ACCESS_ENCRYPTION_MEM_ALIGNMENT);
|
||||
int_mem_alignment = MAX(int_mem_alignment, GDMA_ACCESS_ENCRYPTION_MEM_ALIGNMENT);
|
||||
}
|
||||
} else {
|
||||
gdma_hal_enable_access_encrypt_mem(hal, pair->pair_id, dma_chan->direction, false);
|
||||
}
|
||||
|
||||
// if the channel is not allowed to access external memory, set a super big (meaningless) alignment value
|
||||
// so when the upper layer checks the alignment with an external buffer, the check should fail
|
||||
if (!config->access_ext_mem) {
|
||||
ext_mem_alignment = BIT(31);
|
||||
}
|
||||
|
||||
dma_chan->int_mem_alignment = int_mem_alignment;
|
||||
dma_chan->ext_mem_alignment = ext_mem_alignment;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t gdma_get_alignment_constraints(gdma_channel_handle_t dma_chan, size_t *int_mem_alignment, size_t *ext_mem_alignment)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(dma_chan, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
if (int_mem_alignment) {
|
||||
*int_mem_alignment = dma_chan->int_mem_alignment;
|
||||
}
|
||||
if (ext_mem_alignment) {
|
||||
*ext_mem_alignment = dma_chan->ext_mem_alignment;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@@ -421,57 +443,6 @@ esp_err_t gdma_set_priority(gdma_channel_handle_t dma_chan, uint32_t priority)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#if SOC_GDMA_SUPPORT_CRC
|
||||
esp_err_t gdma_config_crc_calculator(gdma_channel_handle_t dma_chan, const gdma_crc_calculator_config_t *config)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(dma_chan && config, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
gdma_pair_t *pair = dma_chan->pair;
|
||||
gdma_group_t *group = pair->group;
|
||||
gdma_hal_context_t *hal = &group->hal;
|
||||
switch (group->bus_id) {
|
||||
#if SOC_AHB_GDMA_SUPPORTED
|
||||
case SOC_GDMA_BUS_AHB:
|
||||
ESP_RETURN_ON_FALSE(config->crc_bit_width <= GDMA_LL_AHB_MAX_CRC_BIT_WIDTH, ESP_ERR_INVALID_ARG, TAG, "invalid crc bit width");
|
||||
break;
|
||||
#endif // SOC_AHB_GDMA_SUPPORTED
|
||||
#if SOC_AXI_GDMA_SUPPORTED
|
||||
case SOC_GDMA_BUS_AXI:
|
||||
ESP_RETURN_ON_FALSE(config->crc_bit_width <= GDMA_LL_AXI_MAX_CRC_BIT_WIDTH, ESP_ERR_INVALID_ARG, TAG, "invalid crc bit width");
|
||||
break;
|
||||
#endif // SOC_AXI_GDMA_SUPPORTED
|
||||
default:
|
||||
ESP_LOGE(TAG, "invalid bus id: %d", group->bus_id);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
// clear the previous CRC result
|
||||
gdma_hal_clear_crc(hal, pair->pair_id, dma_chan->direction);
|
||||
|
||||
// set polynomial and initial value
|
||||
gdma_hal_crc_config_t hal_config = {
|
||||
.crc_bit_width = config->crc_bit_width,
|
||||
.poly_hex = config->poly_hex,
|
||||
.init_value = config->init_value,
|
||||
.reverse_data_mask = config->reverse_data_mask,
|
||||
};
|
||||
gdma_hal_set_crc_poly(hal, pair->pair_id, dma_chan->direction, &hal_config);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t gdma_crc_get_result(gdma_channel_handle_t dma_chan, uint32_t *result)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(dma_chan && result, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
gdma_pair_t *pair = dma_chan->pair;
|
||||
gdma_group_t *group = pair->group;
|
||||
gdma_hal_context_t *hal = &group->hal;
|
||||
|
||||
*result = gdma_hal_get_crc_result(hal, pair->pair_id, dma_chan->direction);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif // SOC_GDMA_SUPPORT_CRC
|
||||
|
||||
esp_err_t gdma_register_tx_event_callbacks(gdma_channel_handle_t dma_chan, gdma_tx_event_callbacks_t *cbs, void *user_data)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(dma_chan && cbs && dma_chan->direction == GDMA_CHANNEL_DIRECTION_TX, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/param.h>
|
||||
#include "sdkconfig.h"
|
||||
#if CONFIG_GDMA_ENABLE_DEBUG_LOG
|
||||
// The local log level must be defined before including esp_log.h
|
||||
// Set the maximum log level for this source file
|
||||
#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
|
||||
#endif
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "soc/periph_defs.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
#include "gdma_priv.h"
|
||||
|
||||
static const char *TAG = "gdma";
|
||||
|
||||
esp_err_t gdma_config_crc_calculator(gdma_channel_handle_t dma_chan, const gdma_crc_calculator_config_t *config)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(dma_chan && config, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
gdma_pair_t *pair = dma_chan->pair;
|
||||
gdma_group_t *group = pair->group;
|
||||
gdma_hal_context_t *hal = &group->hal;
|
||||
switch (group->bus_id) {
|
||||
#if SOC_AHB_GDMA_SUPPORTED
|
||||
case SOC_GDMA_BUS_AHB:
|
||||
ESP_RETURN_ON_FALSE(config->crc_bit_width <= GDMA_LL_AHB_MAX_CRC_BIT_WIDTH, ESP_ERR_INVALID_ARG, TAG, "invalid crc bit width");
|
||||
break;
|
||||
#endif // SOC_AHB_GDMA_SUPPORTED
|
||||
#if SOC_AXI_GDMA_SUPPORTED
|
||||
case SOC_GDMA_BUS_AXI:
|
||||
ESP_RETURN_ON_FALSE(config->crc_bit_width <= GDMA_LL_AXI_MAX_CRC_BIT_WIDTH, ESP_ERR_INVALID_ARG, TAG, "invalid crc bit width");
|
||||
break;
|
||||
#endif // SOC_AXI_GDMA_SUPPORTED
|
||||
default:
|
||||
ESP_LOGE(TAG, "invalid bus id: %d", group->bus_id);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
// clear the previous CRC result
|
||||
gdma_hal_clear_crc(hal, pair->pair_id, dma_chan->direction);
|
||||
|
||||
// set polynomial and initial value
|
||||
gdma_hal_crc_config_t hal_config = {
|
||||
.crc_bit_width = config->crc_bit_width,
|
||||
.poly_hex = config->poly_hex,
|
||||
.init_value = config->init_value,
|
||||
.reverse_data_mask = config->reverse_data_mask,
|
||||
};
|
||||
gdma_hal_set_crc_poly(hal, pair->pair_id, dma_chan->direction, &hal_config);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t gdma_crc_get_result(gdma_channel_handle_t dma_chan, uint32_t *result)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(dma_chan && result, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
gdma_pair_t *pair = dma_chan->pair;
|
||||
gdma_group_t *group = pair->group;
|
||||
gdma_hal_context_t *hal = &group->hal;
|
||||
|
||||
*result = gdma_hal_get_crc_result(hal, pair->pair_id, dma_chan->direction);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -32,6 +32,8 @@
|
||||
#define GDMA_INTR_ALLOC_FLAGS ESP_INTR_FLAG_INTRDISABLED
|
||||
#endif
|
||||
|
||||
#define GDMA_ACCESS_ENCRYPTION_MEM_ALIGNMENT 16 /*!< The alignment of the memory and size when DMA accesses the encryption memory */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@@ -67,8 +69,8 @@ struct gdma_channel_t {
|
||||
portMUX_TYPE spinlock; // channel level spinlock
|
||||
gdma_channel_direction_t direction; // channel direction
|
||||
int periph_id; // Peripheral instance ID, indicates which peripheral is connected to this GDMA channel
|
||||
size_t sram_alignment; // alignment for memory in SRAM
|
||||
size_t psram_alignment; // alignment for memory in PSRAM
|
||||
size_t int_mem_alignment; // alignment for memory in internal memory
|
||||
size_t ext_mem_alignment; // alignment for memory in external memory
|
||||
esp_err_t (*del)(gdma_channel_t *channel); // channel deletion function, it's polymorphic, see `gdma_del_tx_channel` or `gdma_del_rx_channel`
|
||||
struct {
|
||||
uint32_t start_stop_by_etm: 1; // whether the channel is started/stopped by ETM
|
||||
|
||||
@@ -4,9 +4,6 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
// DO NOT USE THESE APIS IN ANY APPLICATIONS
|
||||
// GDMA driver is not public for end users, but for ESP-IDF developers.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
@@ -37,19 +34,6 @@ typedef struct {
|
||||
} flags;
|
||||
} gdma_channel_alloc_config_t;
|
||||
|
||||
/**
|
||||
* @brief GDMA transfer ability
|
||||
*
|
||||
* @note The alignment set in this structure is **not** a guarantee that gdma driver will take care of the nonalignment cases.
|
||||
* Actually the GDMA driver has no knowledge about the DMA buffer (address and size) used by upper layer.
|
||||
* So it's the responsibility of the **upper layer** to take care of the buffer address and size.
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
size_t sram_trans_align; /*!< DMA transfer alignment for memory in SRAM, in bytes. The driver enables/disables burst mode based on this value. 0 means no alignment is required */
|
||||
size_t psram_trans_align; /*!< DMA transfer alignment for memory in PSRAM, in bytes. The driver sets proper burst block size based on the alignment value. 0 means no alignment is required */
|
||||
} gdma_transfer_ability_t;
|
||||
|
||||
/**
|
||||
* @brief Type of GDMA event data
|
||||
*/
|
||||
@@ -199,16 +183,48 @@ esp_err_t gdma_connect(gdma_channel_handle_t dma_chan, gdma_trigger_t trig_perip
|
||||
esp_err_t gdma_disconnect(gdma_channel_handle_t dma_chan);
|
||||
|
||||
/**
|
||||
* @brief Set DMA channel transfer ability
|
||||
* @brief Channel transfer configurations
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t max_data_burst_size; /*!< Set the max burst size when DMA read/write the data buffer.
|
||||
Set to 0 means to disable the data burst.
|
||||
Other value must be power of 2, e.g., 4/8/16/32/64 */
|
||||
bool access_ext_mem; /*!< Set this if the DMA transfer will access external memory */
|
||||
} gdma_transfer_config_t;
|
||||
|
||||
/**
|
||||
* @brief Configure transfer parameters for a DMA channel
|
||||
*
|
||||
* @note It's highly recommended to enable the burst mode and set proper burst size for the DMA channel,
|
||||
* which can improve the performance in accessing external memory by a lot.
|
||||
*
|
||||
* @param[in] chan DMA channel handle, allocated by `gdma_new_channel`
|
||||
* @param[in] config Transfer configurations
|
||||
* @return
|
||||
* - ESP_OK: Configure DMA transfer parameters successfully
|
||||
* - ESP_ERR_INVALID_ARG: Configure DMA transfer parameters failed because of invalid argument
|
||||
* - ESP_FAIL: Configure DMA transfer parameters failed because of other error
|
||||
*/
|
||||
esp_err_t gdma_config_transfer(gdma_channel_handle_t dma_chan, const gdma_transfer_config_t *config);
|
||||
|
||||
/**
|
||||
* @brief Get the alignment constraints for internal and external memory
|
||||
*
|
||||
* @note You should call this function after `gdma_config_transfer`, the later one can
|
||||
* adjust the alignment constraints based on various conditions, e.g. burst size, memory encryption, etc.
|
||||
* @note You can use returned alignment value to validate if a DMA buffer provided by the upper layer meets the constraints.
|
||||
* @note The returned alignment doesn't take the cache line size into account, if you want to do aligned memory allocation,
|
||||
* you should align the buffer size to the cache line size by yourself if the DMA buffer is behind a cache.
|
||||
*
|
||||
* @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel`
|
||||
* @param[in] ability Transfer ability, e.g. alignment
|
||||
* @param[out] int_mem_alignment Internal memory alignment
|
||||
* @param[out] ext_mem_alignment External memory alignment
|
||||
* @return
|
||||
* - ESP_OK: Set DMA channel transfer ability successfully
|
||||
* - ESP_ERR_INVALID_ARG: Set DMA channel transfer ability failed because of invalid argument
|
||||
* - ESP_FAIL: Set DMA channel transfer ability failed because of other error
|
||||
* - ESP_OK: Get alignment constraints successfully
|
||||
* - ESP_ERR_INVALID_ARG: Get alignment constraints failed because of invalid argument
|
||||
* - ESP_FAIL: Get alignment constraints failed because of other error
|
||||
*/
|
||||
esp_err_t gdma_set_transfer_ability(gdma_channel_handle_t dma_chan, const gdma_transfer_ability_t *ability);
|
||||
esp_err_t gdma_get_alignment_constraints(gdma_channel_handle_t dma_chan, size_t *int_mem_alignment, size_t *ext_mem_alignment);
|
||||
|
||||
/**
|
||||
* @brief Apply channel strategy for GDMA channel
|
||||
@@ -457,6 +473,36 @@ 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);
|
||||
#endif // SOC_GDMA_SUPPORT_CRC
|
||||
|
||||
/****************************************************************************************
|
||||
* Deprecated APIs
|
||||
****************************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief GDMA transfer ability
|
||||
*
|
||||
* @note The alignment set in this structure is **not** a guarantee that gdma driver will take care of the nonalignment cases.
|
||||
* Actually the GDMA driver has no knowledge about the DMA buffer (address and size) used by upper layer.
|
||||
* So it's the responsibility of the **upper layer** to take care of the buffer address and size.
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
size_t sram_trans_align; /*!< DMA transfer alignment for memory in SRAM, in bytes. The driver enables/disables burst mode based on this value. 0 means no alignment is required */
|
||||
size_t psram_trans_align; /*!< DMA transfer alignment for memory in PSRAM, in bytes. The driver sets proper burst block size based on the alignment value. 0 means no alignment is required */
|
||||
} gdma_transfer_ability_t;
|
||||
|
||||
/**
|
||||
* @brief Set DMA channel transfer ability
|
||||
*
|
||||
* @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel`
|
||||
* @param[in] ability Transfer ability, e.g. alignment
|
||||
* @return
|
||||
* - ESP_OK: Set DMA channel transfer ability successfully
|
||||
* - ESP_ERR_INVALID_ARG: Set DMA channel transfer ability failed because of invalid argument
|
||||
* - ESP_FAIL: Set DMA channel transfer ability failed because of other error
|
||||
*/
|
||||
esp_err_t gdma_set_transfer_ability(gdma_channel_handle_t dma_chan, const gdma_transfer_ability_t *ability)
|
||||
__attribute__((deprecated("please use gdma_config_transfer instead")));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user