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:
morris 2024-06-11 11:59:03 +08:00
commit dafc3b3cd5
43 changed files with 575 additions and 444 deletions

View File

@ -243,12 +243,13 @@ static esp_err_t alloc_dma_chan(spi_host_device_t host_id, spi_dma_chan_t dma_ch
gdma_connect(dma_ctx->rx_dma_chan, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_SPI, 3));
}
#endif
gdma_transfer_ability_t ability = {
.psram_trans_align = 0, // fall back to use the same size of the psram data cache line size
.sram_trans_align = 4,
// TODO: add support to allow SPI transfer PSRAM buffer
gdma_transfer_config_t trans_cfg = {
.max_data_burst_size = 16,
.access_ext_mem = false,
};
ESP_RETURN_ON_ERROR(gdma_set_transfer_ability(dma_ctx->tx_dma_chan, &ability), SPI_TAG, "set gdma tx transfer ability failed");
ESP_RETURN_ON_ERROR(gdma_set_transfer_ability(dma_ctx->rx_dma_chan, &ability), SPI_TAG, "set gdma rx transfer ability failed");
ESP_RETURN_ON_ERROR(gdma_config_transfer(dma_ctx->tx_dma_chan, &trans_cfg), SPI_TAG, "config gdma tx transfer failed");
ESP_RETURN_ON_ERROR(gdma_config_transfer(dma_ctx->rx_dma_chan, &trans_cfg), SPI_TAG, "config gdma rx transfer failed");
}
return ret;
}

View File

@ -68,13 +68,16 @@ if(NOT BOOTLOADER_BUILD)
endif()
if(CONFIG_SOC_GDMA_SUPPORTED)
list(APPEND srcs "dma/gdma.c")
list(APPEND srcs "dma/gdma.c" "deprecated/gdma_legacy.c")
if(CONFIG_SOC_GDMA_SUPPORT_SLEEP_RETENTION)
list(APPEND srcs "dma/gdma_sleep_retention.c")
endif()
if(CONFIG_SOC_GDMA_SUPPORT_ETM)
list(APPEND srcs "dma/gdma_etm.c")
endif()
if(CONFIG_SOC_GDMA_SUPPORT_CRC)
list(APPEND srcs "dma/gdma_crc.c")
endif()
endif()
if(CONFIG_SOC_GP_LDO_SUPPORTED)

View File

@ -0,0 +1,62 @@
/*
* SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdlib.h>
#include <string.h>
#include <sys/param.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "esp_check.h"
#include "../dma/gdma_priv.h"
#include "hal/cache_hal.h"
#include "hal/cache_ll.h"
static const char *TAG = "gdma";
esp_err_t gdma_set_transfer_ability(gdma_channel_handle_t dma_chan, const gdma_transfer_ability_t *ability)
{
ESP_RETURN_ON_FALSE(dma_chan && ability, 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;
size_t int_mem_alignment = ability->sram_trans_align;
size_t ext_mem_alignment = ability->psram_trans_align;
// alignment should be 2^n
ESP_RETURN_ON_FALSE((int_mem_alignment & (int_mem_alignment - 1)) == 0, ESP_ERR_INVALID_ARG,
TAG, "invalid sram alignment: %zu", int_mem_alignment);
uint32_t ext_mem_cache_line_size = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_DATA);
if (ext_mem_alignment == 0) {
// fall back to use the same size of the psram data cache line size
ext_mem_alignment = ext_mem_cache_line_size;
}
if ((ext_mem_cache_line_size > 0) && (ext_mem_alignment > ext_mem_cache_line_size)) {
ESP_RETURN_ON_FALSE(((ext_mem_alignment % ext_mem_cache_line_size) == 0), ESP_ERR_INVALID_ARG,
TAG, "ext_mem_alignment(%d) should be multiple of the ext_mem_cache_line_size(%"PRIu32")",
ext_mem_alignment, ext_mem_cache_line_size);
}
// if the DMA can't access the PSRAM, this HAL function is no-op
gdma_hal_set_burst_size(hal, pair->pair_id, dma_chan->direction, ext_mem_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 = int_mem_alignment >= 4;
}
gdma_hal_enable_burst(hal, pair->pair_id, dma_chan->direction, en_burst, en_burst);
dma_chan->int_mem_alignment = int_mem_alignment;
dma_chan->ext_mem_alignment = ext_mem_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, int_mem_alignment, ext_mem_alignment, en_burst ? "enabled" : "disabled");
return ESP_OK;
}

View File

@ -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

View File

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

View File

@ -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");

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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
*/
@ -51,8 +51,11 @@ typedef bool (*async_memcpy_isr_cb_t)(async_memcpy_handle_t mcp_hdl, async_memcp
*/
typedef struct {
uint32_t backlog; /*!< Maximum number of transactions that can be prepared in the background */
size_t sram_trans_align; /*!< DMA transfer alignment (both in size and address) for SRAM memory */
size_t psram_trans_align; /*!< DMA transfer alignment (both in size and address) for PSRAM memory */
size_t sram_trans_align __attribute__((deprecated)); /*!< DMA transfer alignment (both in size and address) for SRAM memory */
union {
size_t psram_trans_align; /*!< DMA transfer alignment (both in size and address) for PSRAM memory */
size_t dma_burst_size; /*!< DMA transfer burst size, in bytes */
};
uint32_t flags; /*!< Extra flags to control async memcpy feature */
} async_memcpy_config_t;
@ -62,8 +65,7 @@ typedef struct {
#define ASYNC_MEMCPY_DEFAULT_CONFIG() \
{ \
.backlog = 8, \
.sram_trans_align = 0, \
.psram_trans_align = 0, \
.dma_burst_size = 16, \
.flags = 0, \
}

View File

@ -302,8 +302,7 @@ static void memcpy_performance_test(uint32_t buffer_size)
async_memcpy_config_t config = ASYNC_MEMCPY_DEFAULT_CONFIG();
config.backlog = (buffer_size / DMA_DESCRIPTOR_BUFFER_MAX_SIZE + 1) * TEST_ASYNC_MEMCPY_BENCH_COUNTS;
config.sram_trans_align = 4; // at least 4 bytes aligned for SRAM transfer
config.psram_trans_align = 64; // at least 64 bytes aligned for PSRAM transfer
config.dma_burst_size = 64; // set a big burst size for performance
async_memcpy_handle_t driver = NULL;
int64_t elapse_us = 0;
float throughput = 0.0;
@ -311,7 +310,7 @@ static void memcpy_performance_test(uint32_t buffer_size)
// 1. SRAM->SRAM
memcpy_testbench_context_t test_context = {
.align = config.psram_trans_align,
.align = config.dma_burst_size,
.buffer_size = buffer_size,
.src_in_psram = false,
.dst_in_psram = false,

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -27,10 +27,9 @@
#include "soc/soc_caps.h"
#include "esp_clk_tree.h"
#include "esp_memory_utils.h"
#include "esp_cache.h"
#include "hal/dma_types.h"
#include "hal/gpio_hal.h"
#include "hal/cache_hal.h"
#include "hal/cache_ll.h"
#include "esp_private/gdma.h"
#include "driver/gpio.h"
#include "esp_private/periph_ctrl.h"
@ -38,7 +37,6 @@
#include "soc/lcd_periph.h"
#include "hal/lcd_ll.h"
#include "hal/lcd_hal.h"
#include "esp_cache.h"
#define ALIGN_UP(size, align) (((size) + (align) - 1) & ~((align) - 1))
#define ALIGN_DOWN(size, align) ((size) & ~((align) - 1))
@ -52,7 +50,7 @@ typedef struct lcd_i80_trans_descriptor_t lcd_i80_trans_descriptor_t;
static esp_err_t panel_io_i80_tx_param(esp_lcd_panel_io_t *io, int lcd_cmd, const void *param, size_t param_size);
static esp_err_t panel_io_i80_tx_color(esp_lcd_panel_io_t *io, int lcd_cmd, const void *color, size_t color_size);
static esp_err_t panel_io_i80_del(esp_lcd_panel_io_t *io);
static esp_err_t lcd_i80_init_dma_link(esp_lcd_i80_bus_handle_t bus);
static esp_err_t lcd_i80_init_dma_link(esp_lcd_i80_bus_handle_t bus, const esp_lcd_i80_bus_config_t *bus_config);
static void lcd_periph_trigger_quick_trans_done_event(esp_lcd_i80_bus_handle_t bus);
static esp_err_t lcd_i80_select_periph_clock(esp_lcd_i80_bus_handle_t bus, lcd_clock_source_t clk_src);
static esp_err_t lcd_i80_bus_configure_gpio(esp_lcd_i80_bus_handle_t bus, const esp_lcd_i80_bus_config_t *bus_config);
@ -72,8 +70,8 @@ struct esp_lcd_i80_bus_t {
uint8_t *format_buffer; // The driver allocates an internal buffer for DMA to do data format transformer
size_t resolution_hz; // LCD_CLK resolution, determined by selected clock source
gdma_channel_handle_t dma_chan; // DMA channel handle
size_t psram_trans_align; // DMA transfer alignment for data allocated from PSRAM
size_t sram_trans_align; // DMA transfer alignment for data allocated from SRAM
size_t int_mem_align; // Alignment for internal memory
size_t ext_mem_align; // Alignment for external memory
lcd_i80_trans_descriptor_t *cur_trans; // Current transaction
lcd_panel_io_i80_t *cur_device; // Current working device
LIST_HEAD(i80_device_list, lcd_panel_io_i80_t) device_list; // Head of i80 device list
@ -175,10 +173,8 @@ esp_err_t esp_lcd_new_i80_bus(const esp_lcd_i80_bus_config_t *bus_config, esp_lc
lcd_ll_enable_interrupt(bus->hal.dev, LCD_LL_EVENT_TRANS_DONE, false); // disable all interrupts
lcd_ll_clear_interrupt_status(bus->hal.dev, UINT32_MAX); // clear pending interrupt
// install DMA service
bus->psram_trans_align = bus_config->psram_trans_align;
bus->sram_trans_align = bus_config->sram_trans_align;
bus->bus_width = bus_config->bus_width;
ret = lcd_i80_init_dma_link(bus);
ret = lcd_i80_init_dma_link(bus, bus_config);
ESP_GOTO_ON_ERROR(ret, err, TAG, "install DMA failed");
// disable RGB-LCD mode
lcd_ll_enable_rgb_mode(bus->hal.dev, false);
@ -481,6 +477,18 @@ static esp_err_t panel_io_i80_tx_color(esp_lcd_panel_io_t *io, int lcd_cmd, cons
esp_lcd_i80_bus_t *bus = i80_device->bus;
lcd_i80_trans_descriptor_t *trans_desc = NULL;
assert(color_size <= (bus->num_dma_nodes * DMA_DESCRIPTOR_BUFFER_MAX_SIZE) && "color bytes too long, enlarge max_transfer_bytes");
if (esp_ptr_external_ram(color)) {
// check alignment
ESP_RETURN_ON_FALSE(((uint32_t)color & (bus->ext_mem_align - 1)) == 0, ESP_ERR_INVALID_ARG, TAG, "color address not aligned");
ESP_RETURN_ON_FALSE((color_size & (bus->ext_mem_align - 1)) == 0, ESP_ERR_INVALID_ARG, TAG, "color size not aligned");
// flush frame buffer from cache to the physical PSRAM
esp_cache_msync((void *)color, color_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED);
} else {
// check alignment
ESP_RETURN_ON_FALSE(((uint32_t)color & (bus->int_mem_align - 1)) == 0, ESP_ERR_INVALID_ARG, TAG, "color address not aligned");
ESP_RETURN_ON_FALSE((color_size & (bus->int_mem_align - 1)) == 0, ESP_ERR_INVALID_ARG, TAG, "color size not aligned");
}
// in case bus_width=16 and cmd_bits=8, we still need 1 cmd_cycle
uint32_t cmd_cycles = i80_device->lcd_cmd_bits / bus->bus_width;
if (cmd_cycles * bus->bus_width < i80_device->lcd_cmd_bits) {
@ -503,13 +511,6 @@ static esp_err_t panel_io_i80_tx_color(esp_lcd_panel_io_t *io, int lcd_cmd, cons
trans_desc->trans_done_cb = i80_device->on_color_trans_done;
trans_desc->user_ctx = i80_device->user_ctx;
if (esp_ptr_external_ram(color)) {
uint32_t dcache_line_size = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_DATA);
// flush frame buffer from cache to the physical PSRAM
// note the esp_cache_msync function will check the alignment of the address and size, make sure they're aligned to current cache line size
esp_cache_msync((void *)ALIGN_DOWN((intptr_t)color, dcache_line_size), ALIGN_UP(color_size, dcache_line_size), 0);
}
// send transaction to trans_queue
xQueueSend(i80_device->trans_queue, &trans_desc, portMAX_DELAY);
i80_device->num_trans_inflight++;
@ -542,7 +543,7 @@ static esp_err_t lcd_i80_select_periph_clock(esp_lcd_i80_bus_handle_t bus, lcd_c
return ESP_OK;
}
static esp_err_t lcd_i80_init_dma_link(esp_lcd_i80_bus_handle_t bus)
static esp_err_t lcd_i80_init_dma_link(esp_lcd_i80_bus_handle_t bus, const esp_lcd_i80_bus_config_t *bus_config)
{
esp_err_t ret = ESP_OK;
// chain DMA descriptors
@ -567,12 +568,13 @@ static esp_err_t lcd_i80_init_dma_link(esp_lcd_i80_bus_handle_t bus)
.owner_check = true
};
gdma_apply_strategy(bus->dma_chan, &strategy_config);
// set DMA transfer ability
gdma_transfer_ability_t ability = {
.psram_trans_align = bus->psram_trans_align,
.sram_trans_align = bus->sram_trans_align,
// config DMA transfer parameters
gdma_transfer_config_t trans_cfg = {
.max_data_burst_size = bus_config->dma_burst_size ? bus_config->dma_burst_size : 16, // Enable DMA burst transfer for better performance
.access_ext_mem = true, // the LCD can carry pixel buffer from the external memory
};
gdma_set_transfer_ability(bus->dma_chan, &ability);
ESP_GOTO_ON_ERROR(gdma_config_transfer(bus->dma_chan, &trans_cfg), err, TAG, "config DMA transfer failed");
gdma_get_alignment_constraints(bus->dma_chan, &bus->int_mem_align, &bus->ext_mem_align);
return ESP_OK;
err:
if (bus->dma_chan) {

View File

@ -238,8 +238,11 @@ typedef struct {
int data_gpio_nums[ESP_LCD_I80_BUS_WIDTH_MAX]; /*!< GPIOs used for data lines */
size_t bus_width; /*!< Number of data lines, 8 or 16 */
size_t max_transfer_bytes; /*!< Maximum transfer size, this determines the length of internal DMA link */
size_t psram_trans_align; /*!< DMA transfer alignment for data allocated from PSRAM */
size_t sram_trans_align; /*!< DMA transfer alignment for data allocated from SRAM */
union {
size_t psram_trans_align; /*!< DMA transfer alignment for data allocated from PSRAM */
size_t dma_burst_size; /*!< DMA burst size, in bytes */
};
size_t sram_trans_align __attribute__((deprecated)); /*!< DMA transfer alignment for data allocated from SRAM */
} esp_lcd_i80_bus_config_t;
/**

View File

@ -39,7 +39,8 @@
#include "soc/lcd_periph.h"
#include "hal/lcd_hal.h"
#include "hal/lcd_ll.h"
#include "hal/gdma_ll.h"
#include "hal/cache_hal.h"
#include "hal/cache_ll.h"
#include "rom/cache.h"
#include "esp_cache.h"
@ -77,7 +78,8 @@ static esp_err_t rgb_panel_swap_xy(esp_lcd_panel_t *panel, bool swap_axes);
static esp_err_t rgb_panel_set_gap(esp_lcd_panel_t *panel, int x_gap, int y_gap);
static esp_err_t rgb_panel_disp_on_off(esp_lcd_panel_t *panel, bool off);
static esp_err_t lcd_rgb_panel_select_clock_src(esp_rgb_panel_t *panel, lcd_clock_source_t clk_src);
static esp_err_t lcd_rgb_panel_create_trans_link(esp_rgb_panel_t *panel);
static esp_err_t lcd_rgb_create_dma_channel(esp_rgb_panel_t *panel);
static void lcd_rgb_panel_init_trans_link(esp_rgb_panel_t *panel);
static esp_err_t lcd_rgb_panel_configure_gpio(esp_rgb_panel_t *panel, const esp_lcd_rgb_panel_config_t *panel_config);
static void lcd_rgb_panel_start_transmission(esp_rgb_panel_t *rgb_panel);
static void lcd_default_isr_handler(void *args);
@ -90,8 +92,7 @@ struct esp_rgb_panel_t {
size_t fb_bits_per_pixel; // Frame buffer color depth, in bpp
size_t num_fbs; // Number of frame buffers
size_t output_bits_per_pixel; // Color depth seen from the output data line. Default to fb_bits_per_pixel, but can be changed by YUV-RGB conversion
size_t sram_trans_align; // Alignment for framebuffer that allocated in SRAM
size_t psram_trans_align; // Alignment for framebuffer that allocated in PSRAM
size_t dma_burst_size; // DMA transfer burst size
int disp_gpio_num; // Display control GPIO, which is used to perform action like "disp_off"
intr_handle_t intr; // LCD peripheral interrupt handle
esp_pm_lock_handle_t pm_lock; // Power management lock
@ -134,10 +135,20 @@ struct esp_rgb_panel_t {
static esp_err_t lcd_rgb_panel_alloc_frame_buffers(const esp_lcd_rgb_panel_config_t *rgb_panel_config, esp_rgb_panel_t *rgb_panel)
{
bool fb_in_psram = false;
size_t psram_trans_align = rgb_panel_config->psram_trans_align ? rgb_panel_config->psram_trans_align : 64;
size_t sram_trans_align = rgb_panel_config->sram_trans_align ? rgb_panel_config->sram_trans_align : 4;
rgb_panel->psram_trans_align = psram_trans_align;
rgb_panel->sram_trans_align = sram_trans_align;
size_t ext_mem_align = 0;
size_t int_mem_align = 0;
gdma_get_alignment_constraints(rgb_panel->dma_chan, &int_mem_align, &ext_mem_align);
// also take the cache line size into account when allocating the frame buffer
uint32_t ext_mem_cache_line_size = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_DATA);
uint32_t int_mem_cache_line_size = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA);
// The buffer must be aligned to the cache line size
if (ext_mem_cache_line_size) {
ext_mem_align = MAX(ext_mem_align, ext_mem_cache_line_size);
}
if (int_mem_cache_line_size) {
int_mem_align = MAX(int_mem_align, int_mem_cache_line_size);
}
// alloc frame buffer
if (rgb_panel->num_fbs > 0) {
@ -152,13 +163,13 @@ static esp_err_t lcd_rgb_panel_alloc_frame_buffers(const esp_lcd_rgb_panel_confi
for (int i = 0; i < rgb_panel->num_fbs; i++) {
if (fb_in_psram) {
// the low level malloc function will help check the validation of alignment
rgb_panel->fbs[i] = heap_caps_aligned_calloc(psram_trans_align, 1, rgb_panel->fb_size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
rgb_panel->fbs[i] = heap_caps_aligned_calloc(ext_mem_align, 1, rgb_panel->fb_size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
ESP_RETURN_ON_FALSE(rgb_panel->fbs[i], ESP_ERR_NO_MEM, TAG, "no mem for frame buffer");
// calloc not only allocates but also zero's the buffer. We have to make sure this is
// properly committed to the PSRAM, otherwise all sorts of visual corruption will happen.
ESP_RETURN_ON_ERROR(esp_cache_msync(rgb_panel->fbs[i], rgb_panel->fb_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M), TAG, "cache write back failed");
} else {
rgb_panel->fbs[i] = heap_caps_aligned_calloc(sram_trans_align, 1, rgb_panel->fb_size, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA);
rgb_panel->fbs[i] = heap_caps_aligned_calloc(int_mem_align, 1, rgb_panel->fb_size, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA);
ESP_RETURN_ON_FALSE(rgb_panel->fbs[i], ESP_ERR_NO_MEM, TAG, "no mem for frame buffer");
}
}
@ -168,7 +179,7 @@ static esp_err_t lcd_rgb_panel_alloc_frame_buffers(const esp_lcd_rgb_panel_confi
if (rgb_panel->bb_size) {
for (int i = 0; i < RGB_LCD_PANEL_BOUNCE_BUF_NUM; i++) {
// bounce buffer must come from SRAM
rgb_panel->bounce_buffer[i] = heap_caps_aligned_calloc(sram_trans_align, 1, rgb_panel->bb_size, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA);
rgb_panel->bounce_buffer[i] = heap_caps_aligned_calloc(int_mem_align, 1, rgb_panel->bb_size, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA);
ESP_RETURN_ON_FALSE(rgb_panel->bounce_buffer[i], ESP_ERR_NO_MEM, TAG, "no mem for bounce buffer");
}
}
@ -302,9 +313,6 @@ esp_err_t esp_lcd_new_rgb_panel(const esp_lcd_rgb_panel_config_t *rgb_panel_conf
}
}
// allocate frame buffers + bounce buffers
ESP_GOTO_ON_ERROR(lcd_rgb_panel_alloc_frame_buffers(rgb_panel_config, rgb_panel), err, TAG, "alloc frame buffers failed");
// initialize HAL layer, so we can call LL APIs later
lcd_hal_init(&rgb_panel->hal, panel_id);
// enable clock
@ -334,8 +342,13 @@ esp_err_t esp_lcd_new_rgb_panel(const esp_lcd_rgb_panel_config_t *rgb_panel_conf
// install DMA service
rgb_panel->flags.stream_mode = !rgb_panel_config->flags.refresh_on_demand;
rgb_panel->fb_bits_per_pixel = fb_bits_per_pixel;
ret = lcd_rgb_panel_create_trans_link(rgb_panel);
ESP_GOTO_ON_ERROR(ret, err, TAG, "install DMA failed");
rgb_panel->dma_burst_size = rgb_panel_config->dma_burst_size ? rgb_panel_config->dma_burst_size : 64;
ESP_GOTO_ON_ERROR(lcd_rgb_create_dma_channel(rgb_panel), err, TAG, "install DMA failed");
// allocate frame buffers + bounce buffers
ESP_GOTO_ON_ERROR(lcd_rgb_panel_alloc_frame_buffers(rgb_panel_config, rgb_panel), err, TAG, "alloc frame buffers failed");
// initialize DMA descriptor link
lcd_rgb_panel_init_trans_link(rgb_panel);
// configure GPIO
ret = lcd_rgb_panel_configure_gpio(rgb_panel, rgb_panel_config);
ESP_GOTO_ON_ERROR(ret, err, TAG, "configure GPIO failed");
@ -959,11 +972,42 @@ static IRAM_ATTR bool lcd_rgb_panel_eof_handler(gdma_channel_handle_t dma_chan,
return lcd_rgb_panel_fill_bounce_buffer(panel, panel->bounce_buffer[bb]);
}
static esp_err_t lcd_rgb_create_dma_channel(esp_rgb_panel_t *panel)
{
// alloc DMA channel and connect to LCD peripheral
gdma_channel_alloc_config_t dma_chan_config = {
.direction = GDMA_CHANNEL_DIRECTION_TX,
};
#if SOC_GDMA_TRIG_PERIPH_LCD0_BUS == SOC_GDMA_BUS_AHB
ESP_RETURN_ON_ERROR(gdma_new_ahb_channel(&dma_chan_config, &panel->dma_chan), TAG, "alloc DMA channel failed");
#elif SOC_GDMA_TRIG_PERIPH_LCD0_BUS == SOC_GDMA_BUS_AXI
ESP_RETURN_ON_ERROR(gdma_new_axi_channel(&dma_chan_config, &panel->dma_chan), TAG, "alloc DMA channel failed");
#endif
gdma_connect(panel->dma_chan, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_LCD, 0));
// configure DMA transfer parameters
gdma_transfer_config_t trans_cfg = {
.max_data_burst_size = panel->dma_burst_size,
.access_ext_mem = true, // frame buffer was allocated from external memory
};
ESP_RETURN_ON_ERROR(gdma_config_transfer(panel->dma_chan, &trans_cfg), TAG, "config DMA transfer failed");
// we need to refill the bounce buffer in the DMA EOF interrupt, so only register the callback for bounce buffer mode
if (panel->bb_size) {
gdma_tx_event_callbacks_t cbs = {
.on_trans_eof = lcd_rgb_panel_eof_handler,
};
gdma_register_tx_event_callbacks(panel->dma_chan, &cbs, panel);
}
return ESP_OK;
}
// If we restart GDMA, many pixels already have been transferred to the LCD peripheral.
// Looks like that has 16 pixels of FIFO plus one holding register.
#define LCD_FIFO_PRESERVE_SIZE_PX (LCD_LL_FIFO_DEPTH + 1)
static esp_err_t lcd_rgb_panel_create_trans_link(esp_rgb_panel_t *panel)
static void lcd_rgb_panel_init_trans_link(esp_rgb_panel_t *panel)
{
for (int i = 0; i < RGB_LCD_PANEL_DMA_LINKS_REPLICA; i++) {
panel->dma_links[i] = &panel->dma_nodes[panel->num_dma_nodes * i];
@ -1007,32 +1051,6 @@ static esp_err_t lcd_rgb_panel_create_trans_link(esp_rgb_panel_t *panel)
panel->dma_restart_node.buffer = &p[restart_skip_bytes];
panel->dma_restart_node.dw0.length -= restart_skip_bytes;
panel->dma_restart_node.dw0.size -= restart_skip_bytes;
// alloc DMA channel and connect to LCD peripheral
gdma_channel_alloc_config_t dma_chan_config = {
.direction = GDMA_CHANNEL_DIRECTION_TX,
};
#if SOC_GDMA_TRIG_PERIPH_LCD0_BUS == SOC_GDMA_BUS_AHB
ESP_RETURN_ON_ERROR(gdma_new_ahb_channel(&dma_chan_config, &panel->dma_chan), TAG, "alloc DMA channel failed");
#elif SOC_GDMA_TRIG_PERIPH_LCD0_BUS == SOC_GDMA_BUS_AXI
ESP_RETURN_ON_ERROR(gdma_new_axi_channel(&dma_chan_config, &panel->dma_chan), TAG, "alloc DMA channel failed");
#endif
gdma_connect(panel->dma_chan, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_LCD, 0));
gdma_transfer_ability_t ability = {
.psram_trans_align = panel->psram_trans_align,
.sram_trans_align = panel->sram_trans_align,
};
gdma_set_transfer_ability(panel->dma_chan, &ability);
// we need to refill the bounce buffer in the DMA EOF interrupt, so only register the callback for bounce buffer mode
if (panel->bb_size) {
gdma_tx_event_callbacks_t cbs = {
.on_trans_eof = lcd_rgb_panel_eof_handler,
};
gdma_register_tx_event_callbacks(panel->dma_chan, &cbs, panel);
}
return ESP_OK;
}
// reset the GDMA channel every VBlank to stop permanent desyncs from happening.

View File

@ -132,8 +132,11 @@ typedef struct {
size_t num_fbs; /*!< Number of screen-sized frame buffers that allocated by the driver. By default (set to either 0 or 1) only one frame buffer will be used. Maximum number of buffers are 3 */
size_t bounce_buffer_size_px; /*!< If it's non-zero, the driver allocates two DRAM bounce buffers for DMA use.
DMA fetching from DRAM bounce buffer is much faster than PSRAM frame buffer. */
size_t sram_trans_align; /*!< Alignment of buffers (frame buffer or bounce buffer) that allocated in SRAM */
size_t psram_trans_align; /*!< Alignment of buffers (frame buffer) that allocated in PSRAM */
size_t sram_trans_align __attribute__((deprecated)); /*!< Alignment of buffers (frame buffer or bounce buffer) that allocated in SRAM */
union {
size_t psram_trans_align; /*!< Alignment of buffers (frame buffer) that allocated in PSRAM */
size_t dma_burst_size; /*!< DMA burst size, in bytes */
};
int hsync_gpio_num; /*!< GPIO used for HSYNC signal */
int vsync_gpio_num; /*!< GPIO used for VSYNC signal */
int de_gpio_num; /*!< GPIO used for DE signal, set to -1 if it's not used */

View File

@ -31,7 +31,7 @@ static esp_lcd_panel_handle_t test_rgb_panel_initialization(size_t data_width, s
esp_lcd_panel_handle_t panel_handle = NULL;
esp_lcd_rgb_panel_config_t panel_config = {
.data_width = data_width,
.psram_trans_align = 64,
.dma_burst_size = 64,
.bounce_buffer_size_px = bb_pixels,
.bits_per_pixel = bpp,
.clk_src = LCD_CLK_SRC_DEFAULT,

View File

@ -27,7 +27,7 @@ TEST_CASE("lcd_rgb_panel_yuv422_conversion", "[lcd]")
esp_lcd_panel_handle_t panel_handle = NULL;
esp_lcd_rgb_panel_config_t panel_config = {
.data_width = 16,
.psram_trans_align = 64,
.dma_burst_size = 64,
.bits_per_pixel = 16, // YUV422: 16bits per pixel
.clk_src = LCD_CLK_SRC_DEFAULT,
.disp_gpio_num = TEST_LCD_DISP_EN_GPIO,

View File

@ -48,6 +48,7 @@ extern "C" {
#define GDMA_LL_AHB_TX_RX_SHARE_INTERRUPT 1 // TX and RX channel in the same pair will share the same interrupt source number
#define GDMA_LL_AHB_DESC_ALIGNMENT 4
#define GDMA_LL_AHB_RX_BURST_NEEDS_ALIGNMENT 1
///////////////////////////////////// Common /////////////////////////////////////////

View File

@ -48,6 +48,7 @@ extern "C" {
#define GDMA_LL_AHB_TX_RX_SHARE_INTERRUPT 1 // TX and RX channel in the same pair will share the same interrupt source number
#define GDMA_LL_AHB_DESC_ALIGNMENT 4
#define GDMA_LL_AHB_RX_BURST_NEEDS_ALIGNMENT 1
///////////////////////////////////// Common /////////////////////////////////////////

View File

@ -51,6 +51,7 @@ extern "C" {
#define GDMA_LL_AHB_PAIRS_PER_GROUP 3 // Number of GDMA pairs in each AHB group
#define GDMA_LL_AHB_DESC_ALIGNMENT 4
#define GDMA_LL_AHB_RX_BURST_NEEDS_ALIGNMENT 1
#define GDMA_LL_TX_ETM_EVENT_TABLE(group, chan, event) \
(uint32_t[1][3][GDMA_ETM_EVENT_MAX]){{{ \

View File

@ -51,6 +51,7 @@ extern "C" {
#define GDMA_LL_AHB_PAIRS_PER_GROUP 3 // Number of GDMA pairs in each AHB group
#define GDMA_LL_AHB_DESC_ALIGNMENT 4
#define GDMA_LL_AHB_RX_BURST_NEEDS_ALIGNMENT 1
#define GDMA_LL_TX_ETM_EVENT_TABLE(group, chan, event) \
(uint32_t[1][3][GDMA_ETM_EVENT_MAX]){{{ \

View File

@ -125,7 +125,7 @@ static inline void axi_dma_ll_rx_enable_owner_check(axi_dma_dev_t *dev, uint32_t
}
/**
* @brief Enable DMA RX channel burst reading data, disabled by default
* @brief Enable DMA RX channel burst reading data, always enabled
*/
static inline void axi_dma_ll_rx_enable_data_burst(axi_dma_dev_t *dev, uint32_t channel, bool enable)
{
@ -139,6 +139,16 @@ static inline void axi_dma_ll_rx_enable_descriptor_burst(axi_dma_dev_t *dev, uin
dev->in[channel].conf.in_conf0.indscr_burst_en_chn = enable;
}
/**
* @brief Set the RX channel burst size
*/
static inline void axi_dma_ll_rx_set_burst_size(axi_dma_dev_t *dev, uint32_t channel, uint32_t sz)
{
HAL_ASSERT(sz >= 8 && sz <= 128);
int ctz = __builtin_ctz(sz);
dev->in[channel].conf.in_conf0.in_burst_size_sel_chn = ctz - 3;
}
/**
* @brief Reset DMA RX channel FSM and FIFO pointer
*/
@ -274,11 +284,11 @@ static inline void axi_dma_ll_rx_enable_etm_task(axi_dma_dev_t *dev, uint32_t ch
}
/**
* @brief Whether to enable the mean access ecc or aes domain
* @brief Whether to enable access to ecc or aes memory
*/
static inline void axi_dma_ll_rx_enable_ext_mem_ecc_aes_access(axi_dma_dev_t *dev, uint32_t channel, bool enable)
{
dev->in[channel].conf.in_conf0.in_ecc_aec_en_chn = enable;
dev->in[channel].conf.in_conf0.in_ecc_aes_en_chn = enable;
}
///////////////////////////////////// TX /////////////////////////////////////////
@ -333,7 +343,7 @@ static inline void axi_dma_ll_tx_enable_owner_check(axi_dma_dev_t *dev, uint32_t
}
/**
* @brief Enable DMA TX channel burst sending data, disabled by default
* @brief Enable DMA TX channel burst sending data, always enabled
*/
static inline void axi_dma_ll_tx_enable_data_burst(axi_dma_dev_t *dev, uint32_t channel, bool enable)
{
@ -347,6 +357,16 @@ static inline void axi_dma_ll_tx_enable_descriptor_burst(axi_dma_dev_t *dev, uin
dev->out[channel].conf.out_conf0.outdscr_burst_en_chn = enable;
}
/**
* @brief Set the TX channel burst size
*/
static inline void axi_dma_ll_tx_set_burst_size(axi_dma_dev_t *dev, uint32_t channel, uint32_t sz)
{
HAL_ASSERT(sz >= 8 && sz <= 128);
int ctz = __builtin_ctz(sz);
dev->out[channel].conf.out_conf0.out_burst_size_sel_chn = ctz - 3;
}
/**
* @brief Set TX channel EOF mode
*/
@ -480,11 +500,11 @@ static inline void axi_dma_ll_tx_enable_etm_task(axi_dma_dev_t *dev, uint32_t ch
}
/**
* @brief Whether to enable the mean access ecc or aes domain
* @brief Whether to enable access to ecc or aes memory
*/
static inline void axi_dma_ll_tx_enable_ext_mem_ecc_aes_access(axi_dma_dev_t *dev, uint32_t channel, bool enable)
{
dev->out[channel].conf.out_conf0.out_ecc_aec_en_chn = enable;
dev->out[channel].conf.out_conf0.out_ecc_aes_en_chn = enable;
}
///////////////////////////////////// CRC-TX /////////////////////////////////////////

View File

@ -62,6 +62,9 @@ extern "C" {
#define GDMA_LL_AHB_DESC_ALIGNMENT 4
#define GDMA_LL_AHB_BURST_SIZE_ADJUSTABLE 1 // AHB GDMA supports adjustable burst size
#define GDMA_LL_AHB_RX_BURST_NEEDS_ALIGNMENT 1
///////////////////////////////////// Common /////////////////////////////////////////
/**
@ -177,20 +180,20 @@ static inline void gdma_ll_rx_reset_channel(gdma_dev_t *dev, uint32_t channel)
}
/**
* @brief Set DMA RX channel memory block size based on the alignment requirement
* @param align Supported value: 16/32/64
* @brief Set DMA RX channel memory block size based on the burst requirement
* @param burst_sz Supported value: 16/32/64
*/
static inline void gdma_ll_rx_set_ext_mem_block_size(gdma_dev_t *dev, uint32_t channel, uint8_t align)
static inline void gdma_ll_rx_set_burst_size(gdma_dev_t *dev, uint32_t channel, uint32_t burst_sz)
{
uint32_t block_size = 0;
switch (align) {
case 64: // 64 Bytes alignment
switch (burst_sz) {
case 64:
block_size = GDMA_LL_EXT_MEM_BK_SIZE_64B;
break;
case 32: // 32 Bytes alignment
case 32:
block_size = GDMA_LL_EXT_MEM_BK_SIZE_32B;
break;
case 16: // 16 Bytes alignment
case 16:
block_size = GDMA_LL_EXT_MEM_BK_SIZE_16B;
break;
default:
@ -461,20 +464,20 @@ static inline void gdma_ll_tx_reset_channel(gdma_dev_t *dev, uint32_t channel)
}
/**
* @brief Set DMA TX channel memory block size based on the alignment requirement
* @param align Supported value: 16/32/64
* @brief Set DMA TX channel memory block size based on the burst requirement
* @param burst_sz Supported value: 16/32/64
*/
static inline void gdma_ll_tx_set_ext_mem_block_size(gdma_dev_t *dev, uint32_t channel, uint8_t align)
static inline void gdma_ll_tx_set_burst_size(gdma_dev_t *dev, uint32_t channel, uint32_t burst_sz)
{
uint32_t block_size = 0;
switch (align) {
case 64: // 64 Bytes alignment
switch (burst_sz) {
case 64:
block_size = GDMA_LL_EXT_MEM_BK_SIZE_64B;
break;
case 32: // 32 Bytes alignment
case 32:
block_size = GDMA_LL_EXT_MEM_BK_SIZE_32B;
break;
case 16: // 16 Bytes alignment
case 16:
block_size = GDMA_LL_EXT_MEM_BK_SIZE_16B;
break;
default:

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -91,16 +91,16 @@ void gdma_ahb_hal_enable_burst(gdma_hal_context_t *hal, int chan_id, gdma_channe
}
}
#if SOC_AHB_GDMA_SUPPORT_PSRAM
void gdma_ahb_hal_set_ext_mem_align(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint8_t align)
#if GDMA_LL_AHB_BURST_SIZE_ADJUSTABLE
void gdma_ahb_hal_set_burst_size(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint32_t burst_sz)
{
if (dir == GDMA_CHANNEL_DIRECTION_RX) {
gdma_ll_rx_set_ext_mem_block_size(hal->dev, chan_id, align);
gdma_ll_rx_set_burst_size(hal->dev, chan_id, burst_sz);
} else {
gdma_ll_tx_set_ext_mem_block_size(hal->dev, chan_id, align);
gdma_ll_tx_set_burst_size(hal->dev, chan_id, burst_sz);
}
}
#endif
#endif // GDMA_LL_AHB_BURST_SIZE_ADJUSTABLE
void gdma_ahb_hal_set_strategy(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool en_owner_check, bool en_desc_write_back)
{
@ -193,8 +193,8 @@ void gdma_ahb_hal_init(gdma_hal_context_t *hal, const gdma_hal_config_t *config)
#if SOC_GDMA_SUPPORT_ETM
hal->enable_etm_task = gdma_ahb_hal_enable_etm_task;
#endif
#if SOC_AHB_GDMA_SUPPORT_PSRAM
hal->set_ext_mem_align = gdma_ahb_hal_set_ext_mem_align;
#endif // SOC_AHB_GDMA_SUPPORT_PSRAM
#if GDMA_LL_AHB_BURST_SIZE_ADJUSTABLE
hal->set_burst_size = gdma_ahb_hal_set_burst_size;
#endif // GDMA_LL_AHB_BURST_SIZE_ADJUSTABLE
hal->priv_data = &gdma_ahb_hal_priv_data;
}

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -102,6 +102,17 @@ void gdma_ahb_hal_set_strategy(gdma_hal_context_t *hal, int chan_id, gdma_channe
}
}
#if GDMA_LL_AHB_BURST_SIZE_ADJUSTABLE
void gdma_ahb_hal_set_burst_size(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint32_t burst_sz)
{
if (dir == GDMA_CHANNEL_DIRECTION_RX) {
ahb_dma_ll_rx_set_burst_size(hal->ahb_dma_dev, chan_id, burst_sz);
} else {
ahb_dma_ll_tx_set_burst_size(hal->ahb_dma_dev, chan_id, burst_sz);
}
}
#endif // GDMA_LL_AHB_BURST_SIZE_ADJUSTABLE
void gdma_ahb_hal_enable_intr(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint32_t intr_event_mask, bool en_or_dis)
{
if (dir == GDMA_CHANNEL_DIRECTION_RX) {
@ -244,5 +255,8 @@ void gdma_ahb_hal_init(gdma_hal_context_t *hal, const gdma_hal_config_t *config)
#if SOC_GDMA_SUPPORT_ETM
hal->enable_etm_task = gdma_ahb_hal_enable_etm_task;
#endif // SOC_GDMA_SUPPORT_ETM
#if GDMA_LL_AHB_BURST_SIZE_ADJUSTABLE
hal->set_burst_size = gdma_ahb_hal_set_burst_size;
#endif // GDMA_LL_AHB_BURST_SIZE_ADJUSTABLE
ahb_dma_ll_set_default_memory_range(hal->ahb_dma_dev);
}

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -102,6 +102,15 @@ void gdma_axi_hal_set_strategy(gdma_hal_context_t *hal, int chan_id, gdma_channe
}
}
void gdma_axi_hal_set_burst_size(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint32_t burst_sz)
{
if (dir == GDMA_CHANNEL_DIRECTION_RX) {
axi_dma_ll_rx_set_burst_size(hal->axi_dma_dev, chan_id, burst_sz);
} else {
axi_dma_ll_tx_set_burst_size(hal->axi_dma_dev, chan_id, burst_sz);
}
}
void gdma_axi_hal_enable_intr(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint32_t intr_event_mask, bool en_or_dis)
{
if (dir == GDMA_CHANNEL_DIRECTION_RX) {
@ -151,6 +160,15 @@ uint32_t gdma_axi_hal_get_eof_desc_addr(gdma_hal_context_t *hal, int chan_id, gd
}
}
void gdma_axi_hal_enable_access_encrypt_mem(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool en_or_dis)
{
if (dir == GDMA_CHANNEL_DIRECTION_RX) {
axi_dma_ll_rx_enable_ext_mem_ecc_aes_access(hal->axi_dma_dev, chan_id, en_or_dis);
} else {
axi_dma_ll_tx_enable_ext_mem_ecc_aes_access(hal->axi_dma_dev, chan_id, en_or_dis);
}
}
#if SOC_GDMA_SUPPORT_CRC
void gdma_axi_hal_clear_crc(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir)
{
@ -236,6 +254,8 @@ void gdma_axi_hal_init(gdma_hal_context_t *hal, const gdma_hal_config_t *config)
hal->read_intr_status = gdma_axi_hal_read_intr_status;
hal->get_intr_status_reg = gdma_axi_hal_get_intr_status_reg;
hal->get_eof_desc_addr = gdma_axi_hal_get_eof_desc_addr;
hal->set_burst_size = gdma_axi_hal_set_burst_size;
hal->enable_access_encrypt_mem = gdma_axi_hal_enable_access_encrypt_mem;
#if SOC_GDMA_SUPPORT_CRC
hal->clear_crc = gdma_axi_hal_clear_crc;
hal->set_crc_poly = gdma_axi_hal_set_crc_poly;

View File

@ -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
*/
@ -53,10 +53,10 @@ void gdma_hal_enable_burst(gdma_hal_context_t *hal, int chan_id, gdma_channel_di
hal->enable_burst(hal, chan_id, dir, en_data_burst, en_desc_burst);
}
void gdma_hal_set_ext_mem_align(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint8_t align)
void gdma_hal_set_burst_size(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint32_t burst_sz)
{
if (hal->set_ext_mem_align) {
hal->set_ext_mem_align(hal, chan_id, dir, align);
if (hal->set_burst_size) {
hal->set_burst_size(hal, chan_id, dir, burst_sz);
}
}
@ -90,6 +90,13 @@ uint32_t gdma_hal_get_eof_desc_addr(gdma_hal_context_t *hal, int chan_id, gdma_c
return hal->get_eof_desc_addr(hal, chan_id, dir, is_success);
}
void gdma_hal_enable_access_encrypt_mem(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool en_or_dis)
{
if (hal->enable_access_encrypt_mem) {
hal->enable_access_encrypt_mem(hal, chan_id, dir, en_or_dis);
}
}
#if SOC_GDMA_SUPPORT_CRC
void gdma_hal_clear_crc(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir)
{

View File

@ -80,13 +80,14 @@ struct gdma_hal_context_t {
void (*connect_peri)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, gdma_trigger_peripheral_t periph, int periph_sub_id); /// Connect the channel to a peripheral
void (*disconnect_peri)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir); /// Disconnect the channel from a peripheral
void (*enable_burst)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool en_data_burst, bool en_desc_burst); /// Enable burst mode
void (*set_ext_mem_align)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint8_t align); /// Set the alignment of the external memory
void (*set_strategy)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool en_owner_check, bool en_desc_write_back); /// Set some misc strategy of the channel behaviour
void (*set_burst_size)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint32_t burst_sz); /// Set burst transfer size
uint32_t (*get_intr_status_reg)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir); // Get the interrupt status register address
void (*enable_intr)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint32_t intr_event_mask, bool en_or_dis); /// Enable the channel interrupt
void (*clear_intr)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint32_t intr_event_mask); /// Clear the channel interrupt
uint32_t (*read_intr_status)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool raw); /// Read the channel interrupt status
uint32_t (*get_eof_desc_addr)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool is_success); /// Get the address of the descriptor with success/error EOF flag set
void (*enable_access_encrypt_mem)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool en_or_dis); /// Enable the access to the encrypted memory
#if SOC_GDMA_SUPPORT_CRC
void (*clear_crc)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir); /// Clear the CRC interim results
void (*set_crc_poly)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, const gdma_hal_crc_config_t *config); /// Set the CRC polynomial
@ -115,7 +116,7 @@ void gdma_hal_disconnect_peri(gdma_hal_context_t *hal, int chan_id, gdma_channel
void gdma_hal_enable_burst(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool en_data_burst, bool en_desc_burst);
void gdma_hal_set_ext_mem_align(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint8_t align);
void gdma_hal_set_burst_size(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint32_t burst_sz);
void gdma_hal_set_strategy(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool en_owner_check, bool en_desc_write_back);
@ -129,6 +130,8 @@ uint32_t gdma_hal_read_intr_status(gdma_hal_context_t *hal, int chan_id, gdma_ch
uint32_t gdma_hal_get_eof_desc_addr(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool is_success);
void gdma_hal_enable_access_encrypt_mem(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool en_or_dis);
#if SOC_GDMA_SUPPORT_CRC
void gdma_hal_build_parallel_crc_matrix(int crc_width, uint32_t crc_poly_hex, int data_width,
uint32_t *lfsr_transform_matrix, uint32_t *data_transform_matrix);

View File

@ -28,7 +28,7 @@ void gdma_ahb_hal_disconnect_peri(gdma_hal_context_t *hal, int chan_id, gdma_cha
void gdma_ahb_hal_enable_burst(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool en_data_burst, bool en_desc_burst);
void gdma_ahb_hal_set_ext_mem_align(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint8_t align);
void gdma_ahb_hal_set_burst_size(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint32_t burst_sz);
void gdma_ahb_hal_set_strategy(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool en_owner_check, bool en_desc_write_back);

View File

@ -28,6 +28,8 @@ void gdma_axi_hal_disconnect_peri(gdma_hal_context_t *hal, int chan_id, gdma_cha
void gdma_axi_hal_enable_burst(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool en_data_burst, bool en_desc_burst);
void gdma_axi_hal_set_burst_size(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint32_t burst_sz);
void gdma_axi_hal_set_ext_mem_align(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint8_t align);
void gdma_axi_hal_set_strategy(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool en_owner_check, bool en_desc_write_back);

View File

@ -73,12 +73,6 @@ static esp_err_t crypto_shared_gdma_init(void)
.direction = GDMA_CHANNEL_DIRECTION_RX,
};
gdma_transfer_ability_t transfer_ability = {
.sram_trans_align = 1,
.psram_trans_align = 16,
};
ret = crypto_shared_gdma_new_channel(&channel_config_tx, &tx_channel);
if (ret != ESP_OK) {
goto err;
@ -90,9 +84,13 @@ static esp_err_t crypto_shared_gdma_init(void)
goto err;
}
gdma_set_transfer_ability(tx_channel, &transfer_ability);
gdma_set_transfer_ability(rx_channel, &transfer_ability);
gdma_transfer_config_t transfer_cfg = {
.max_data_burst_size = 16,
.access_ext_mem = true, // crypto peripheral may want to access PSRAM
};
gdma_config_transfer(tx_channel, &transfer_cfg);
transfer_cfg.max_data_burst_size = 0;
gdma_config_transfer(rx_channel, &transfer_cfg);
gdma_connect(rx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_AES, 0));
gdma_connect(tx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_AES, 0));
@ -223,7 +221,7 @@ bool esp_crypto_shared_gdma_done(void)
{
int rx_ch_id = 0;
gdma_get_channel_id(rx_channel, &rx_ch_id);
while(1) {
while (1) {
if ((axi_dma_ll_rx_get_interrupt_status(&AXI_DMA, rx_ch_id, true) & 1)) {
break;
}

View File

@ -471,7 +471,7 @@ config SOC_DS_KEY_CHECK_MAX_WAIT_US
int
default 1100
config SOC_DMA_CAN_ACCESS_MSPI_MEM
config SOC_DMA_CAN_ACCESS_FLASH
bool
default y

View File

@ -1,5 +1,5 @@
/**
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -273,10 +273,10 @@ typedef union {
* 1:mean disable cmd of this ch0
*/
uint32_t in_cmd_disable_chn: 1;
/** in_ecc_aec_en_chn : R/W; bitpos: [8]; default: 0;
/** in_ecc_aes_en_chn : R/W; bitpos: [8]; default: 0;
* 1: mean access ecc or aes domain,0: mean not
*/
uint32_t in_ecc_aec_en_chn: 1;
uint32_t in_ecc_aes_en_chn: 1;
/** indscr_burst_en_chn : R/W; bitpos: [9]; default: 0;
* Set this bit to 1 to enable INCR burst transfer for Rx channel 0 reading link
* descriptor when accessing internal SRAM.
@ -567,7 +567,7 @@ typedef union {
*/
uint32_t rx_ch_arb_weigh_chn: 4;
/** rx_arb_weigh_opt_dir_chn : R/W; bitpos: [8]; default: 0;
* 0: mean not optimazation weight function ,1: mean optimazation
* 0: mean not optimization weight function ,1: mean optimization
*/
uint32_t rx_arb_weigh_opt_dir_chn: 1;
uint32_t reserved_9: 23;
@ -952,10 +952,10 @@ typedef union {
* 1:mean disable cmd of this chn
*/
uint32_t out_cmd_disable_chn: 1;
/** out_ecc_aec_en_chn : R/W; bitpos: [9]; default: 0;
/** out_ecc_aes_en_chn : R/W; bitpos: [9]; default: 0;
* 1: mean access ecc or aes domain,0: mean not
*/
uint32_t out_ecc_aec_en_chn: 1;
uint32_t out_ecc_aes_en_chn: 1;
/** outdscr_burst_en_chn : R/W; bitpos: [10]; default: 0;
* Set this bit to 1 to enable INCR burst transfer for Tx channel0 reading link
* descriptor when accessing internal SRAM.
@ -1238,7 +1238,7 @@ typedef union {
*/
uint32_t tx_ch_arb_weigh_chn: 4;
/** tx_arb_weigh_opt_dir_chn : R/W; bitpos: [8]; default: 0;
* 0: mean not optimazation weight function ,1: mean optimazation
* 0: mean not optimization weight function ,1: mean optimization
*/
uint32_t tx_arb_weigh_opt_dir_chn: 1;
uint32_t reserved_9: 23;
@ -1374,106 +1374,6 @@ typedef union {
uint32_t val;
} axi_dma_tx_crc_data_en_addr_chn_reg_t;
/** Type of out_conf0_ch1 register
* Configure 0 register of Tx channel1
*/
typedef union {
struct {
/** out_rst_ch1 : R/W; bitpos: [0]; default: 0;
* This bit is used to reset AXI_DMA channel1 Tx FSM and Tx FIFO pointer.
*/
uint32_t out_rst_ch1: 1;
/** out_loop_test_ch1 : R/W; bitpos: [1]; default: 0;
* reserved
*/
uint32_t out_loop_test_ch1: 1;
/** out_auto_wrback_ch1 : R/W; bitpos: [2]; default: 0;
* Set this bit to enable automatic outlink-writeback when all the data in tx buffer
* has been transmitted.
*/
uint32_t out_auto_wrback_ch1: 1;
/** out_eof_mode_ch1 : R/W; bitpos: [3]; default: 1;
* EOF flag generation mode when transmitting data. 1: EOF flag for Tx channel1 is
* generated when data need to transmit has been popped from FIFO in AXI_DMA
*/
uint32_t out_eof_mode_ch1: 1;
/** out_etm_en_ch1 : R/W; bitpos: [4]; default: 0;
* Set this bit to 1 to enable etm control mode, dma Tx channel1 is triggered by etm
* task.
*/
uint32_t out_etm_en_ch1: 1;
/** out_burst_size_sel_ch1 : R/W; bitpos: [7:5]; default: 0;
* 3'b000-3'b100:burst length 8byte~128byte
*/
uint32_t out_burst_size_sel_ch1: 3;
/** out_cmd_disable_ch1 : R/W; bitpos: [8]; default: 0;
* 1:mean disable cmd of this ch1
*/
uint32_t out_cmd_disable_ch1: 1;
/** out_ecc_aec_en_ch1 : R/W; bitpos: [9]; default: 0;
* 1: mean access ecc or aes domain,0: mean not
*/
uint32_t out_ecc_aec_en_ch1: 1;
/** outdscr_burst_en_ch1 : R/W; bitpos: [10]; default: 0;
* Set this bit to 1 to enable INCR burst transfer for Tx channel1 reading link
* descriptor when accessing internal SRAM.
*/
uint32_t outdscr_burst_en_ch1: 1;
uint32_t reserved_11: 21;
};
uint32_t val;
} axi_dma_out_conf0_ch1_reg_t;
/** Type of out_conf0_ch2 register
* Configure 0 register of Tx channel2
*/
typedef union {
struct {
/** out_rst_ch2 : R/W; bitpos: [0]; default: 0;
* This bit is used to reset AXI_DMA channel2 Tx FSM and Tx FIFO pointer.
*/
uint32_t out_rst_ch2: 1;
/** out_loop_test_ch2 : R/W; bitpos: [1]; default: 0;
* reserved
*/
uint32_t out_loop_test_ch2: 1;
/** out_auto_wrback_ch2 : R/W; bitpos: [2]; default: 0;
* Set this bit to enable automatic outlink-writeback when all the data in tx buffer
* has been transmitted.
*/
uint32_t out_auto_wrback_ch2: 1;
/** out_eof_mode_ch2 : R/W; bitpos: [3]; default: 1;
* EOF flag generation mode when transmitting data. 1: EOF flag for Tx channel2 is
* generated when data need to transmit has been popped from FIFO in AXI_DMA
*/
uint32_t out_eof_mode_ch2: 1;
/** out_etm_en_ch2 : R/W; bitpos: [4]; default: 0;
* Set this bit to 1 to enable etm control mode, dma Tx channel2 is triggered by etm
* task.
*/
uint32_t out_etm_en_ch2: 1;
/** out_burst_size_sel_ch2 : R/W; bitpos: [7:5]; default: 0;
* 3'b000-3'b100:burst length 8byte~128byte
*/
uint32_t out_burst_size_sel_ch2: 3;
/** out_cmd_disable_ch2 : R/W; bitpos: [8]; default: 0;
* 1:mean disable cmd of this ch2
*/
uint32_t out_cmd_disable_ch2: 1;
/** out_ecc_aec_en_ch2 : R/W; bitpos: [9]; default: 0;
* 1: mean access ecc or aes domain,0: mean not
*/
uint32_t out_ecc_aec_en_ch2: 1;
/** outdscr_burst_en_ch2 : R/W; bitpos: [10]; default: 0;
* Set this bit to 1 to enable INCR burst transfer for Tx channel2 reading link
* descriptor when accessing internal SRAM.
*/
uint32_t outdscr_burst_en_ch2: 1;
uint32_t reserved_11: 21;
};
uint32_t val;
} axi_dma_out_conf0_ch2_reg_t;
/** Group: Configuration Registers */
/** Type of arb_timeout register
* This retister is used to config arbiter time slice
@ -1705,12 +1605,12 @@ typedef union {
/** Group: Status Registers */
/** Type of wresp_cnt register
* AXI wr responce cnt register.
* AXI wr response cnt register.
*/
typedef union {
struct {
/** wresp_cnt : RO; bitpos: [3:0]; default: 0;
* axi wr responce cnt reg.
* axi wr response cnt reg.
*/
uint32_t wresp_cnt: 4;
uint32_t reserved_4: 28;
@ -1719,12 +1619,12 @@ typedef union {
} axi_dma_wresp_cnt_reg_t;
/** Type of rresp_cnt register
* AXI wr responce cnt register.
* AXI wr response cnt register.
*/
typedef union {
struct {
/** rresp_cnt : RO; bitpos: [3:0]; default: 0;
* axi rd responce cnt reg.
* axi rd response cnt reg.
*/
uint32_t rresp_cnt: 4;
uint32_t reserved_4: 28;

View File

@ -188,7 +188,7 @@
#define SOC_DS_KEY_CHECK_MAX_WAIT_US (1100)
/*-------------------------- DMA Common CAPS ----------------------------------------*/
#define SOC_DMA_CAN_ACCESS_MSPI_MEM 1 /*!< DMA can access MSPI memory (e.g. Flash, PSRAM) */
#define SOC_DMA_CAN_ACCESS_FLASH 1 /*!< DMA can access Flash memory */
/*-------------------------- GDMA CAPS -------------------------------------*/
#define SOC_AHB_GDMA_VERSION 2

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
*/
@ -37,7 +37,6 @@ TEST_CASE("Test crypto lib bignum apis", "[wpa_crypto]")
bn = crypto_bignum_init_set(buf, 32);
TEST_ASSERT_NOT_NULL(bn);
TEST_ASSERT(crypto_bignum_to_bin(bn, buf2, 32, 0) == 32);
TEST_ASSERT(!memcmp(buf, buf2, 32));
@ -245,7 +244,6 @@ TEST_CASE("Test crypto lib bignum apis", "[wpa_crypto]")
uint8_t buf1[32], buf2[32];
crypto_bignum *bn1, *bn2;
buf1[0] = 0xf;
buf2[0] = 0x11;
@ -277,7 +275,6 @@ TEST_CASE("Test crypto lib bignum apis", "[wpa_crypto]")
}
}
/*
* Conversion macros for embedded constants:
* build lists of mbedtls_mpi_uint's from lists of unsigned char's grouped by 8, 4 or 2
@ -322,30 +319,29 @@ TEST_CASE("Test crypto lib bignum apis", "[wpa_crypto]")
* (assumes len is an exact multiple of sizeof mbedtls_mpi_uint)
* Allocate a new memory as well so that it can be freed.
*/
static inline void ecp_mpi_load( mbedtls_mpi *X, const mbedtls_mpi_uint *p, size_t len )
static inline void ecp_mpi_load(mbedtls_mpi *X, const mbedtls_mpi_uint *p, size_t len)
{
X->MBEDTLS_PRIVATE(s) = 1;
X->MBEDTLS_PRIVATE(n) = len / sizeof( mbedtls_mpi_uint );
X->MBEDTLS_PRIVATE(n) = len / sizeof(mbedtls_mpi_uint);
X->MBEDTLS_PRIVATE(p) = os_zalloc(len);
memcpy(X->MBEDTLS_PRIVATE(p), (void *)p, len);
}
TEST_CASE("Test crypto lib ECC apis", "[wpa_crypto]")
{
set_leak_threshold(600);
set_leak_threshold(620);
static const mbedtls_mpi_uint secp256r1_gx[] = {
BYTES_TO_T_UINT_8( 0x96, 0xC2, 0x98, 0xD8, 0x45, 0x39, 0xA1, 0xF4 ),
BYTES_TO_T_UINT_8( 0xA0, 0x33, 0xEB, 0x2D, 0x81, 0x7D, 0x03, 0x77 ),
BYTES_TO_T_UINT_8( 0xF2, 0x40, 0xA4, 0x63, 0xE5, 0xE6, 0xBC, 0xF8 ),
BYTES_TO_T_UINT_8( 0x47, 0x42, 0x2C, 0xE1, 0xF2, 0xD1, 0x17, 0x6B ),
BYTES_TO_T_UINT_8(0x96, 0xC2, 0x98, 0xD8, 0x45, 0x39, 0xA1, 0xF4),
BYTES_TO_T_UINT_8(0xA0, 0x33, 0xEB, 0x2D, 0x81, 0x7D, 0x03, 0x77),
BYTES_TO_T_UINT_8(0xF2, 0x40, 0xA4, 0x63, 0xE5, 0xE6, 0xBC, 0xF8),
BYTES_TO_T_UINT_8(0x47, 0x42, 0x2C, 0xE1, 0xF2, 0xD1, 0x17, 0x6B),
};
static const mbedtls_mpi_uint secp256r1_gy[] = {
BYTES_TO_T_UINT_8( 0xF5, 0x51, 0xBF, 0x37, 0x68, 0x40, 0xB6, 0xCB ),
BYTES_TO_T_UINT_8( 0xCE, 0x5E, 0x31, 0x6B, 0x57, 0x33, 0xCE, 0x2B ),
BYTES_TO_T_UINT_8( 0x16, 0x9E, 0x0F, 0x7C, 0x4A, 0xEB, 0xE7, 0x8E ),
BYTES_TO_T_UINT_8( 0x9B, 0x7F, 0x1A, 0xFE, 0xE2, 0x42, 0xE3, 0x4F ),
BYTES_TO_T_UINT_8(0xF5, 0x51, 0xBF, 0x37, 0x68, 0x40, 0xB6, 0xCB),
BYTES_TO_T_UINT_8(0xCE, 0x5E, 0x31, 0x6B, 0x57, 0x33, 0xCE, 0x2B),
BYTES_TO_T_UINT_8(0x16, 0x9E, 0x0F, 0x7C, 0x4A, 0xEB, 0xE7, 0x8E),
BYTES_TO_T_UINT_8(0x9B, 0x7F, 0x1A, 0xFE, 0xE2, 0x42, 0xE3, 0x4F),
};
{
@ -393,8 +389,8 @@ TEST_CASE("Test crypto lib ECC apis", "[wpa_crypto]")
TEST_ASSERT_NOT_NULL(q);
TEST_ASSERT_NOT_NULL(r);
mbedtls_mpi_init( &num );
mbedtls_mpi_lset( &num, 3 );
mbedtls_mpi_init(&num);
mbedtls_mpi_lset(&num, 3);
ecp_mpi_load(& ((mbedtls_ecp_point *)p)->MBEDTLS_PRIVATE(X), secp256r1_gx, sizeof(secp256r1_gx));
ecp_mpi_load(& ((mbedtls_ecp_point *)p)->MBEDTLS_PRIVATE(Y), secp256r1_gy, sizeof(secp256r1_gy));
@ -408,7 +404,7 @@ TEST_CASE("Test crypto lib ECC apis", "[wpa_crypto]")
TEST_ASSERT(crypto_ec_point_cmp(e, q, r) == 0);
mbedtls_mpi_free( &num );
mbedtls_mpi_free(&num);
crypto_ec_point_deinit(p, 1);
crypto_ec_point_deinit(q, 1);
crypto_ec_point_deinit(r, 1);
@ -432,8 +428,8 @@ TEST_CASE("Test crypto lib ECC apis", "[wpa_crypto]")
TEST_ASSERT_NOT_NULL(q);
TEST_ASSERT_NOT_NULL(r);
mbedtls_mpi_init( &num );
mbedtls_mpi_lset( &num, 100 );
mbedtls_mpi_init(&num);
mbedtls_mpi_lset(&num, 100);
ecp_mpi_load(& ((mbedtls_ecp_point *)p)->MBEDTLS_PRIVATE(X), secp256r1_gx, sizeof(secp256r1_gx));
ecp_mpi_load(& ((mbedtls_ecp_point *)p)->MBEDTLS_PRIVATE(Y), secp256r1_gy, sizeof(secp256r1_gy));
@ -448,7 +444,7 @@ TEST_CASE("Test crypto lib ECC apis", "[wpa_crypto]")
TEST_ASSERT(crypto_ec_point_is_at_infinity(e, r));
mbedtls_mpi_free( &num );
mbedtls_mpi_free(&num);
crypto_ec_point_deinit(p, 1);
crypto_ec_point_deinit(q, 1);
crypto_ec_point_deinit(r, 1);
@ -468,8 +464,8 @@ TEST_CASE("Test crypto lib ECC apis", "[wpa_crypto]")
TEST_ASSERT_NOT_NULL(p);
TEST_ASSERT_NOT_NULL(q);
mbedtls_mpi_init( &num );
mbedtls_mpi_lset( &num, 50 );
mbedtls_mpi_init(&num);
mbedtls_mpi_lset(&num, 50);
ecp_mpi_load(& ((mbedtls_ecp_point *)p)->MBEDTLS_PRIVATE(X), secp256r1_gx, sizeof(secp256r1_gx));
ecp_mpi_load(& ((mbedtls_ecp_point *)p)->MBEDTLS_PRIVATE(Y), secp256r1_gy, sizeof(secp256r1_gy));
@ -483,8 +479,7 @@ TEST_CASE("Test crypto lib ECC apis", "[wpa_crypto]")
TEST_ASSERT(crypto_ec_point_mul(e, p, (crypto_bignum *) &num, q) == 0);
TEST_ASSERT(crypto_ec_point_is_on_curve(e, q));
mbedtls_mpi_free( &num );
mbedtls_mpi_free(&num);
crypto_ec_point_deinit(p, 1);
crypto_ec_point_deinit(q, 1);
crypto_ec_deinit(e);
@ -506,8 +501,8 @@ TEST_CASE("Test crypto lib ECC apis", "[wpa_crypto]")
TEST_ASSERT_NOT_NULL(q);
TEST_ASSERT_NOT_NULL(r);
mbedtls_mpi_init( &num );
mbedtls_mpi_lset( &num, 50 );
mbedtls_mpi_init(&num);
mbedtls_mpi_lset(&num, 50);
ecp_mpi_load(& ((mbedtls_ecp_point *)p)->MBEDTLS_PRIVATE(X), secp256r1_gx, sizeof(secp256r1_gx));
ecp_mpi_load(& ((mbedtls_ecp_point *)p)->MBEDTLS_PRIVATE(Y), secp256r1_gy, sizeof(secp256r1_gy));
@ -532,7 +527,7 @@ TEST_CASE("Test crypto lib ECC apis", "[wpa_crypto]")
TEST_ASSERT(crypto_ec_point_add(e, q, r, r) == 0);
TEST_ASSERT(crypto_ec_point_is_at_infinity(e, r));
mbedtls_mpi_free( &num );
mbedtls_mpi_free(&num);
crypto_ec_point_deinit(p, 1);
crypto_ec_point_deinit(q, 1);
crypto_ec_point_deinit(r, 1);

View File

@ -29,8 +29,7 @@ I80 Interfaced LCD
},
.bus_width = 8,
.max_transfer_bytes = EXAMPLE_LCD_H_RES * 100 * sizeof(uint16_t), // transfer 100 lines of pixels (assume pixel is RGB565) at most in one transaction
.psram_trans_align = EXAMPLE_PSRAM_DATA_ALIGNMENT,
.sram_trans_align = 4,
.dma_burst_size = EXAMPLE_DMA_BURST_SIZE,
};
ESP_ERROR_CHECK(esp_lcd_new_i80_bus(&bus_config, &i80_bus));

View File

@ -7,7 +7,7 @@ RGB LCD panel is allocated in one step: :cpp:func:`esp_lcd_new_rgb_panel`, with
- :cpp:member:`esp_lcd_rgb_panel_config_t::data_width` set number of data lines used by the RGB interface. Currently, the supported value can be 8 or 16.
- :cpp:member:`esp_lcd_rgb_panel_config_t::bits_per_pixel` set the number of bits per pixel. This is different from :cpp:member:`esp_lcd_rgb_panel_config_t::data_width`. By default, if you set this field to 0, the driver will automatically adjust the bpp to the :cpp:member:`esp_lcd_rgb_panel_config_t::data_width`. But in some cases, these two value must be different. For example, a Serial RGB interface LCD only needs ``8`` data lines, but the color width can reach to ``RGB888``, i.e., the :cpp:member:`esp_lcd_rgb_panel_config_t::bits_per_pixel` should be set to ``24``.
- :cpp:member:`esp_lcd_rgb_panel_config_t::hsync_gpio_num`, :cpp:member:`esp_lcd_rgb_panel_config_t::vsync_gpio_num`, :cpp:member:`esp_lcd_rgb_panel_config_t::de_gpio_num`, :cpp:member:`esp_lcd_rgb_panel_config_t::pclk_gpio_num`, :cpp:member:`esp_lcd_rgb_panel_config_t::disp_gpio_num` and :cpp:member:`esp_lcd_rgb_panel_config_t::data_gpio_nums` are the GPIO pins used by the RGB LCD controller. If some of them are not used, please set it to `-1`.
- :cpp:member:`esp_lcd_rgb_panel_config_t::sram_trans_align` and :cpp:member:`esp_lcd_rgb_panel_config_t::psram_trans_align` set the alignment of the allocated frame buffer. Internally, the DMA transfer ability will adjust against these alignment values. A higher alignment value can lead to a bigger DMA burst size. Please note, the alignment value must be a power of 2.
- :cpp:member:`esp_lcd_rgb_panel_config_t::dma_burst_size` set the DMA transfer burst size, the value must be a power of 2.
- :cpp:member:`esp_lcd_rgb_panel_config_t::bounce_buffer_size_px` set the size of bounce buffer. This is only necessary for a so-called "bounce buffer" mode. Please refer to :ref:`bounce_buffer_with_single_psram_frame_buffer` for more information.
- :cpp:member:`esp_lcd_rgb_panel_config_t::timings` sets the LCD panel specific timing parameters. All required parameters are listed in the :cpp:type:`esp_lcd_rgb_timing_t`, including the LCD resolution and blanking porches. Please fill them according to the datasheet of your LCD.
- :cpp:member:`esp_lcd_rgb_panel_config_t::fb_in_psram` sets whether to allocate the frame buffer from PSRAM or not. Please refer to :ref:`single_frame_buffer_in_psram` for more information.

View File

@ -77,12 +77,12 @@ Non-IRAM-Safe Interrupt Handlers
If the ``ESP_INTR_FLAG_IRAM`` flag is not set when registering, the interrupt handler will not get executed when the caches are disabled. Once the caches are restored, the non-IRAM-safe interrupts will be re-enabled. After this moment, the interrupt handler will run normally again. This means that as long as caches are disabled, users will not see the corresponding hardware event happening.
.. only:: SOC_DMA_CAN_ACCESS_MSPI_MEM
.. only:: SOC_DMA_CAN_ACCESS_FLASH
When DMA Read Data from Flash
-----------------------------
When DMA is reading data from Flash, erase/write operations from SPI1 take higher priority in hardware, resulting in unpredictable data read by DMA. It is recommended to stop DMA access to Flash before erasing or writing to it. If DMA cannot be stopped (for example, the LCD needs to continuously refresh image data stored in Flash), it is advisable to copy such data to PSRAM or internal SRAM.
When DMA is reading data from Flash, erase/write operations from SPI1 take higher priority in hardware, resulting in unpredictable data read by DMA if auto-suspend is not enabled. It is recommended to stop DMA access to Flash before erasing or writing to it. If DMA cannot be stopped (for example, the LCD needs to continuously refresh image data stored in Flash), it is advisable to copy such data to PSRAM or internal SRAM.
.. only:: SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND

View File

@ -36,8 +36,7 @@ There are several ways to install the async memcpy driver, depending on the unde
Driver configuration is described in :cpp:type:`async_memcpy_config_t`:
* :cpp:member:`backlog`: This is used to configure the maximum number of memory copy transactions that can be queued up before the first one is completed. If this field is set to zero, then the default value 4 will be applied.
* :cpp:member:`sram_trans_align`: Declare SRAM alignment for both data address and copy size, set to zero if the data has no restriction in alignment. If set to a quadruple value (i.e., 4X), the driver will enable the burst mode internally, which is helpful for some performance related application.
* :cpp:member:`psram_trans_align`: Declare PSRAM alignment for both data address and copy size. User has to give it a valid value (only 16, 32, 64 are supported) if the destination of memcpy is located in PSRAM. The default alignment (i.e., 16) will be applied if it is set to zero. Internally, the driver configures the size of block used by DMA to access PSRAM, according to the alignment.
* :cpp:member:`dma_burst_size`: Set the burst size in a DMA burst transfer.
* :cpp:member:`flags`: This is used to enable some special driver features.
.. code-block:: c

View File

@ -77,12 +77,12 @@ IRAM 安全中断处理程序
如果在注册时没有设置 ``ESP_INTR_FLAG_IRAM`` 标志,当禁用 cache 时,将不会执行中断处理程序。一旦 cache 恢复,非 IRAM 安全的中断将重新启用,中断处理程序随即再次正常运行。这意味着,只要禁用了 cache就不会发生相应的硬件事件。
.. only:: SOC_DMA_CAN_ACCESS_MSPI_MEM
.. only:: SOC_DMA_CAN_ACCESS_FLASH
当 DMA 也可以访问 Flash 中的数据时
----------------------------------
当 DMA 正在从 Flash 中读取数据时,来自 SPI1 的擦/写操作优先级会更高,导致 DMA 读到错误的数据。建议在擦写 Flash 之前先停止 DMA 对 Flash 的访问。如果 DMA 不可以停止,比如 LCD 需要持续刷新保存在 Flash 中的图像数据,建议将此类数据拷贝到 PSRAM 或者内部的 SRAM 中。
当 DMA 正在从 Flash 中读取数据时,来自 SPI1 的擦/写操作优先级会更高,如果 Flash 的 auto-suspend 功能没有开启,将会导致 DMA 读到错误的数据。建议在擦写 Flash 之前先停止 DMA 对 Flash 的访问。如果 DMA 不可以停止,比如 LCD 需要持续刷新保存在 Flash 中的图像数据,建议将此类数据拷贝到 PSRAM 或者内部的 SRAM 中。
.. only:: SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND

View File

@ -36,8 +36,7 @@ DMA 允许多个内存复制请求在首个请求完成之前排队,即允许
:cpp:type:`async_memcpy_config_t` 中设置驱动配置:
* :cpp:member:`backlog`:此项用于配置首个请求完成前可以排队的最大内存复制事务数量。如果将此字段设置为零,会应用默认值 4。
* :cpp:member:`sram_trans_align`:声明 SRAM 中数据地址和复制大小的对齐方式,如果数据没有对齐限制,则设置为零。如果设置为四的倍数值(即 4X驱动程序将内部启用突发模式这有利于某些和性能相关的应用程序。
* :cpp:member:`psram_trans_align`:声明 PSRAM 中数据地址和复制大小的对齐方式。如果 memcpy 的目标地址位于 PSRAM 中,用户必须给出一个有效值(只支持 16、32、64。如果设置为零会默认采用 16 位对齐。在内部,驱动程序会根据对齐方式来配置 DMA 访问 PSRAM 时所用的块大小。
* :cpp:member:`dma_burst_size`:设置单次 DMA 传输中突发数据量的大小。
* :cpp:member:`flags`:此项可以启用一些特殊的驱动功能。
.. code-block:: c

View File

@ -93,8 +93,7 @@ static const char *TAG = "example";
#define EXAMPLE_LVGL_TASK_STACK_SIZE (4 * 1024)
#define EXAMPLE_LVGL_TASK_PRIORITY 2
// Supported alignment: 16, 32, 64. A higher alignment can enables higher burst transfer size, thus a higher i80 bus throughput.
#define EXAMPLE_PSRAM_DATA_ALIGNMENT 64
#define EXAMPLE_DMA_BURST_SIZE 64 // 16, 32, 64. Higher burst size can improve the performance when the DMA buffer comes from PSRAM
static SemaphoreHandle_t lvgl_mux = NULL;
@ -248,8 +247,7 @@ void example_init_i80_bus(esp_lcd_panel_io_handle_t *io_handle, void *user_ctx)
},
.bus_width = CONFIG_EXAMPLE_LCD_I80_BUS_WIDTH,
.max_transfer_bytes = EXAMPLE_LCD_H_RES * 100 * sizeof(uint16_t),
.psram_trans_align = EXAMPLE_PSRAM_DATA_ALIGNMENT,
.sram_trans_align = 4,
.dma_burst_size = EXAMPLE_DMA_BURST_SIZE,
};
ESP_ERROR_CHECK(esp_lcd_new_i80_bus(&bus_config, &i80_bus));

View File

@ -166,7 +166,7 @@ void app_main(void)
esp_lcd_panel_handle_t panel_handle = NULL;
esp_lcd_rgb_panel_config_t panel_config = {
.data_width = 16, // RGB565 in parallel mode, thus 16bit in width
.psram_trans_align = 64,
.dma_burst_size = 64,
.num_fbs = EXAMPLE_LCD_NUM_FB,
#if CONFIG_EXAMPLE_USE_BOUNCE_BUFFER
.bounce_buffer_size_px = 10 * EXAMPLE_LCD_H_RES,