mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-01 18:50:34 +03:00
feat(mspi): split dma and mspi alignment
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
#include "freertos/semphr.h"
|
||||
#include "esp_private/gdma.h"
|
||||
#include "esp_private/gdma_link.h"
|
||||
#include "esp_private/esp_mspi_align.h"
|
||||
#include "soc/ahb_dma_struct.h"
|
||||
#include "hal/dma_types.h"
|
||||
#include "esp_check.h"
|
||||
@@ -180,8 +181,13 @@ esp_err_t asrc_hw_gdma_create_link_list(uint32_t byte_cnt, asrc_hw_gdma_link_lis
|
||||
ESP_RETURN_ON_FALSE(list_hd, ESP_ERR_INVALID_ARG, TAG, "NULL pointer");
|
||||
ESP_RETURN_ON_FALSE(max_desc_num, ESP_ERR_INVALID_ARG, TAG, "NULL pointer");
|
||||
esp_err_t ret = ESP_OK;
|
||||
int32_t desc_num = byte_cnt / ASRC_HW_GDMA_DESC_BUFFER_MAX_SIZE;
|
||||
if (byte_cnt % ASRC_HW_GDMA_DESC_BUFFER_MAX_SIZE != 0) {
|
||||
size_t mspi_align = esp_mspi_get_alignment(NULL);
|
||||
uint32_t max_desc_size = ASRC_HW_GDMA_DESC_BUFFER_MAX_SIZE;
|
||||
if (mspi_align > 1) {
|
||||
max_desc_size &= ~(mspi_align - 1);
|
||||
}
|
||||
int32_t desc_num = byte_cnt / max_desc_size;
|
||||
if (byte_cnt % max_desc_size != 0) {
|
||||
desc_num++;
|
||||
}
|
||||
gdma_link_list_handle_t list = (gdma_link_list_handle_t)(*list_hd);
|
||||
@@ -208,21 +214,30 @@ esp_err_t asrc_hw_gdma_mount_link_list(asrc_hw_gdma_link_list_handle_t list_hd,
|
||||
ESP_RETURN_ON_FALSE(list_hd, ESP_ERR_INVALID_ARG, TAG, "NULL pointer");
|
||||
esp_err_t ret = ESP_OK;
|
||||
uint32_t remaining_byte_cnt = byte_cnt;
|
||||
size_t mspi_align = esp_mspi_get_alignment(buf);
|
||||
if (mspi_align > 1) {
|
||||
ESP_RETURN_ON_FALSE((((uintptr_t)buf & (mspi_align - 1)) == 0) && ((byte_cnt & (mspi_align - 1)) == 0),
|
||||
ESP_ERR_INVALID_ARG, TAG, "buffer addr or size not aligned to MSPI alignment");
|
||||
}
|
||||
uint32_t max_desc_size = ASRC_HW_GDMA_DESC_BUFFER_MAX_SIZE;
|
||||
if (mspi_align > 1) {
|
||||
max_desc_size &= ~(mspi_align - 1);
|
||||
}
|
||||
gdma_buffer_mount_config_t mount_config[desc_num] = {};
|
||||
for (int i = 0; i < desc_num; i++) {
|
||||
mount_config[i].buffer = buf;
|
||||
mount_config[i].flags.bypass_buffer_align_check = true;
|
||||
mount_config[i].buffer_alignment = mspi_align;
|
||||
if ((i + 1) != desc_num) {
|
||||
mount_config[i].length = ASRC_HW_GDMA_DESC_BUFFER_MAX_SIZE;
|
||||
mount_config[i].length = max_desc_size;
|
||||
mount_config[i].flags.mark_eof = 0;
|
||||
mount_config[i].flags.mark_final = GDMA_FINAL_LINK_TO_DEFAULT;
|
||||
remaining_byte_cnt -= ASRC_HW_GDMA_DESC_BUFFER_MAX_SIZE;
|
||||
remaining_byte_cnt -= max_desc_size;
|
||||
} else {
|
||||
mount_config[i].length = remaining_byte_cnt;
|
||||
mount_config[i].flags.mark_eof = 1;
|
||||
mount_config[i].flags.mark_final = GDMA_FINAL_LINK_TO_NULL;
|
||||
}
|
||||
buf += ASRC_HW_GDMA_DESC_BUFFER_MAX_SIZE;
|
||||
buf += max_desc_size;
|
||||
}
|
||||
ret = gdma_link_mount_buffers((gdma_link_list_handle_t)list_hd, 0, mount_config, desc_num, NULL);
|
||||
if (ret != ESP_OK) {
|
||||
|
||||
@@ -239,6 +239,7 @@ esp_err_t bitscrambler_loopback_run(bitscrambler_handle_t bs, void *buffer_in, s
|
||||
.flags = {
|
||||
.mark_eof = false,
|
||||
.mark_final = GDMA_FINAL_LINK_TO_NULL,
|
||||
.check_size_align = gdma_is_size_alignment_required(bsl->rx_channel),
|
||||
}
|
||||
};
|
||||
gdma_link_mount_buffers(bsl->rx_link_list, 0, &out_buf_mount_config, 1, NULL);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -38,12 +38,12 @@ static const char *TAG = "dvp_gdma";
|
||||
* - ESP_OK on success
|
||||
* - Others if failed
|
||||
*/
|
||||
static void IRAM_ATTR esp_cam_ctlr_dvp_config_dma_desc(esp_cam_ctlr_dvp_dma_desc_t *desc, uint8_t *buffer, uint32_t size)
|
||||
static void IRAM_ATTR esp_cam_ctlr_dvp_config_dma_desc(esp_cam_ctlr_dvp_dma_desc_t *desc, uint8_t *buffer, uint32_t size, uint32_t max_desc_size)
|
||||
{
|
||||
size_t n = 0;
|
||||
|
||||
while (size) {
|
||||
uint32_t node_size = MIN(size, ESP_CAM_CTLR_DVP_DMA_DESC_BUFFER_MAX_SIZE);
|
||||
uint32_t node_size = MIN(size, max_desc_size);
|
||||
|
||||
desc[n].dw0.size = node_size;
|
||||
desc[n].dw0.length = 0;
|
||||
@@ -104,10 +104,15 @@ esp_err_t esp_cam_ctlr_dvp_dma_init(esp_cam_ctlr_dvp_dma_t *dma, uint32_t burst_
|
||||
};
|
||||
ESP_GOTO_ON_ERROR(gdma_config_transfer(dma->dma_chan, &transfer_config), fail1, TAG, "set trans ability failed");
|
||||
|
||||
gdma_get_alignment_constraints(dma->dma_chan, &dma->int_mem_align, &dma->ext_mem_align);
|
||||
gdma_get_channel_alignment_constraints(dma->dma_chan, &dma->int_mem_align, &dma->ext_mem_align, NULL);
|
||||
|
||||
dma->desc_count = size / ESP_CAM_CTLR_DVP_DMA_DESC_BUFFER_MAX_SIZE;
|
||||
if (size % ESP_CAM_CTLR_DVP_DMA_DESC_BUFFER_MAX_SIZE) {
|
||||
size_t buffer_alignment = dma->ext_mem_align;
|
||||
size_t desc_max_size = ESP_CAM_CTLR_DVP_DMA_DESC_BUFFER_MAX_SIZE;
|
||||
if (buffer_alignment > 1) {
|
||||
desc_max_size = ESP_ALIGN_DOWN(desc_max_size, buffer_alignment);
|
||||
}
|
||||
dma->desc_count = size / desc_max_size;
|
||||
if (size % desc_max_size) {
|
||||
dma->desc_count++;
|
||||
}
|
||||
dma->size = size;
|
||||
@@ -163,7 +168,14 @@ esp_err_t IRAM_ATTR esp_cam_ctlr_dvp_dma_start(esp_cam_ctlr_dvp_dma_t *dma, uint
|
||||
ESP_RETURN_ON_FALSE_ISR(dma, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||
ESP_RETURN_ON_FALSE_ISR(dma->size >= size, ESP_ERR_INVALID_ARG, TAG, "input buffer size is out of range");
|
||||
|
||||
esp_cam_ctlr_dvp_config_dma_desc(dma->desc, buffer, size);
|
||||
size_t buffer_alignment = gdma_get_buffer_alignment_constraint(dma->dma_chan, buffer);
|
||||
ESP_RETURN_ON_FALSE_ISR(((uintptr_t)buffer & (buffer_alignment - 1)) == 0 && (size & (buffer_alignment - 1)) == 0,
|
||||
ESP_ERR_INVALID_ARG, TAG, "buffer addr or size not aligned");
|
||||
uint32_t max_desc_size = ESP_CAM_CTLR_DVP_DMA_DESC_BUFFER_MAX_SIZE;
|
||||
if (buffer_alignment > 1) {
|
||||
max_desc_size = ESP_ALIGN_DOWN(max_desc_size, buffer_alignment);
|
||||
}
|
||||
esp_cam_ctlr_dvp_config_dma_desc(dma->desc, buffer, size, max_desc_size);
|
||||
|
||||
if (esp_ptr_external_ram(dma->desc)) {
|
||||
esp_err_t ret = esp_cache_msync(dma->desc, dma->desc_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_INVALIDATE);
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "esp_err.h"
|
||||
#include "hal/dma2d_types.h"
|
||||
|
||||
@@ -269,6 +271,47 @@ typedef struct {
|
||||
*/
|
||||
esp_err_t dma2d_set_transfer_ability(dma2d_channel_handle_t dma2d_chan, const dma2d_transfer_ability_t *ability);
|
||||
|
||||
/**
|
||||
* @brief Get DMA2D buffer alignment constraint for a specific buffer
|
||||
*
|
||||
* @note On invalid arguments, returns an impossible alignment (BIT(31)).
|
||||
*
|
||||
* @param[in] buffer Buffer address
|
||||
* @return Alignment requirement in bytes
|
||||
*/
|
||||
size_t dma2d_get_buffer_alignment_constraint(const void *buffer);
|
||||
|
||||
/**
|
||||
* @brief Get alignment required when allocating a buffer for DMA2D access
|
||||
*
|
||||
* Use this before the buffer exists (e.g. `heap_caps_aligned_calloc`).
|
||||
* Unlike `dma2d_get_buffer_alignment_constraint`, this returns the worst-case
|
||||
* DMA2D/MSPI alignment rather than treating a NULL pointer as invalid.
|
||||
*
|
||||
* @return Alignment requirement in bytes (1 if no strict alignment is needed)
|
||||
*/
|
||||
size_t dma2d_get_alloc_alignment(void);
|
||||
|
||||
/**
|
||||
* @brief Check whether a 2D DMA transaction window satisfies DMA2D/MSPI alignment
|
||||
*
|
||||
* Under Flash Encryption / PSRAM ECC, MSPI requires each AXI access to be aligned in both
|
||||
* address and size. For a 2D transfer that means:
|
||||
* - buffer base address aligned to N bytes
|
||||
* - bytes-per-line (`pic_width * bpp/8`) aligned, so every next line starts on an N-byte boundary
|
||||
* - transfer width (`blk_width * bpp/8`) aligned
|
||||
* - horizontal window offset (`offset_x * bpp/8`) aligned
|
||||
*
|
||||
* @param[in] buf Buffer base address
|
||||
* @param[in] pic_width Picture / stride width in pixels
|
||||
* @param[in] blk_width Transfer block width in pixels
|
||||
* @param[in] offset_x Horizontal offset of the block in pixels
|
||||
* @param[in] bit_depth Bits per pixel
|
||||
* @return true if the transaction satisfies the alignment constraints
|
||||
*/
|
||||
bool dma2d_check_transaction_alignment_constraint(const void *buf, uint32_t pic_width, uint32_t blk_width,
|
||||
uint32_t offset_x, uint32_t bit_depth);
|
||||
|
||||
/**
|
||||
* @brief A collection of color space conversion (CSC) items that each 2D-DMA channel could apply
|
||||
*/
|
||||
|
||||
@@ -219,23 +219,58 @@ typedef struct {
|
||||
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
|
||||
* @brief Get the alignment constraints for a configured GDMA channel
|
||||
*
|
||||
* @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.
|
||||
* adjust the alignment constraints based on GDMA-specific conditions, e.g. burst size.
|
||||
* @note Prefer this when allocating DMA buffers. Once a concrete buffer address is available,
|
||||
* use `gdma_get_buffer_alignment_constraint` for the effective runtime constraint of that region.
|
||||
* @note For allocation from external memory:
|
||||
* - Use `ext_enc_mem_alignment` as the safe default (worst-case MSPI encryption/ECC).
|
||||
* - Use `ext_no_enc_mem_alignment` when intentionally targeting no-encryption external memory (e.g. no-enc PSRAM).
|
||||
* @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_ahb_channel/gdma_new_axi_channel`
|
||||
* @param[out] int_mem_alignment Internal memory alignment
|
||||
* @param[out] ext_mem_alignment External memory alignment
|
||||
* @param[out] ext_enc_mem_alignment External memory alignment including MSPI encryption/ECC constraints
|
||||
* @param[out] ext_no_enc_mem_alignment External memory alignment without MSPI region-specific constraints.
|
||||
* Useful when allocating from no-encryption external memory. Set to NULL if unused.
|
||||
* @return
|
||||
* - 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_get_alignment_constraints(gdma_channel_handle_t dma_chan, size_t *int_mem_alignment, size_t *ext_mem_alignment);
|
||||
esp_err_t gdma_get_channel_alignment_constraints(gdma_channel_handle_t dma_chan, size_t *int_mem_alignment,
|
||||
size_t *ext_enc_mem_alignment, size_t *ext_no_enc_mem_alignment);
|
||||
|
||||
/**
|
||||
* @brief Check whether buffer sizes must meet the configured channel alignment
|
||||
*
|
||||
* @note Call this function after `gdma_config_transfer`.
|
||||
* @note This reports GDMA hardware constraints only. Region-specific MSPI constraints
|
||||
* are enforced independently when buffers are mounted to a GDMA link list.
|
||||
*
|
||||
* @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_ahb_channel/gdma_new_axi_channel`
|
||||
* @return True when buffer sizes must be aligned, otherwise false
|
||||
*/
|
||||
bool gdma_is_size_alignment_required(gdma_channel_handle_t dma_chan);
|
||||
|
||||
/**
|
||||
* @brief Get the effective alignment constraint for a specific DMA buffer
|
||||
*
|
||||
* @note You should call this function after `gdma_config_transfer`.
|
||||
* @note The returned alignment combines GDMA channel constraints with MSPI constraints
|
||||
* of the actual buffer region. This lets external no-encryption PSRAM buffers use
|
||||
* their real runtime constraint instead of a generic worst-case MSPI alignment.
|
||||
* @note The returned alignment doesn't take the cache line size into account.
|
||||
* @note On invalid arguments, returns an impossible alignment (BIT(31)).
|
||||
*
|
||||
* @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_ahb_channel/gdma_new_axi_channel`
|
||||
* @param[in] buffer DMA buffer address
|
||||
* @return Effective buffer alignment in bytes
|
||||
*/
|
||||
size_t gdma_get_buffer_alignment_constraint(gdma_channel_handle_t dma_chan, const void *buffer);
|
||||
|
||||
/**
|
||||
* @brief Apply channel strategy for GDMA channel
|
||||
|
||||
@@ -84,6 +84,10 @@ typedef struct {
|
||||
Note, the final item here does not mean the last item in the link list. It is `start_item_index + num_items - 1` */
|
||||
uint32_t bypass_buffer_align_check: 1; /*!< Whether to bypass the buffer alignment check.
|
||||
Only enable it when you know what you are doing. */
|
||||
uint32_t check_size_align: 1; /*!< Whether to check that `length` is aligned to the alignment.
|
||||
RX callers can query `gdma_is_size_alignment_required` to determine whether
|
||||
the configured channel requires this check. Under MSPI Flash Encryption /
|
||||
PSRAM ECC, length alignment is always enforced regardless of this flag. */
|
||||
} flags; //!< Flags for buffer mount configurations
|
||||
} gdma_buffer_mount_config_t;
|
||||
|
||||
|
||||
@@ -11,6 +11,8 @@ entries:
|
||||
gdma: gdma_stop (noflash)
|
||||
gdma: gdma_append (noflash)
|
||||
gdma: gdma_reset (noflash)
|
||||
gdma: gdma_get_buffer_alignment_constraint (noflash)
|
||||
gdma: gdma_is_size_alignment_required (noflash)
|
||||
|
||||
[mapping:gdma_hal]
|
||||
archive: libesp_hal_dma.a
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <stdatomic.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/param.h>
|
||||
#include <inttypes.h>
|
||||
#include <assert.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
@@ -16,6 +17,7 @@
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_memory_utils.h"
|
||||
#include "esp_async_color_convert_priv.h"
|
||||
#include "esp_private/dma2d.h"
|
||||
#include "soc/dma2d_channel.h"
|
||||
#include "hal/dma2d_types.h"
|
||||
#include "hal/dma2d_ll.h"
|
||||
@@ -207,6 +209,17 @@ static esp_err_t validate_request(const async_color_convert_request_t *request)
|
||||
request->dst_height <= DMA2D_LL_DESC_2D_FIELD_MAX,
|
||||
ESP_ERR_INVALID_ARG, TAG, "dimension exceeds DMA2D descriptor field limit");
|
||||
|
||||
uint32_t src_bit_depth = color_hal_pixel_format_fourcc_get_bit_depth(request->src_color_format);
|
||||
uint32_t dst_bit_depth = color_hal_pixel_format_fourcc_get_bit_depth(request->dst_color_format);
|
||||
ESP_RETURN_ON_FALSE(dma2d_check_transaction_alignment_constraint(request->src_buffer, request->src_stride,
|
||||
request->copy_width, request->src_x,
|
||||
src_bit_depth),
|
||||
ESP_ERR_INVALID_ARG, TAG, "source buffer or window is not aligned to DMA2D alignment");
|
||||
ESP_RETURN_ON_FALSE(dma2d_check_transaction_alignment_constraint(request->dst_buffer, request->dst_stride,
|
||||
request->copy_width, request->dst_x,
|
||||
dst_bit_depth),
|
||||
ESP_ERR_INVALID_ARG, TAG, "destination buffer or window is not aligned to DMA2D alignment");
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <string.h>
|
||||
#include <stdatomic.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/param.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_check.h"
|
||||
@@ -51,8 +52,6 @@ typedef struct {
|
||||
gdma_channel_handle_t rx_channel; // GDMA RX channel handle used to drain M2M data
|
||||
portMUX_TYPE spin_lock; // Spinlock for synchronization
|
||||
_Atomic async_crc_fsm_t fsm; // driver state machine, changing state should be atomic
|
||||
size_t tx_int_mem_alignment; // Required DMA buffer alignment for internal TX memory
|
||||
size_t tx_ext_mem_alignment; // Required DMA buffer alignment for external TX memory
|
||||
uint8_t *rx_sink_buffer; // Sink buffer used to drain the M2M RX path
|
||||
gdma_link_list_handle_t rx_link_list; // Self-loop DMA link list for the RX sink buffer, shared by all crc transactions
|
||||
uint32_t gdma_bus_id; // GDMA bus id (AHB, AXI, etc.)
|
||||
@@ -164,9 +163,8 @@ esp_err_t esp_async_crc_install_gdma_template(const async_crc_config_t *config,
|
||||
ESP_GOTO_ON_ERROR(gdma_config_transfer(crc_gdma->rx_channel, &transfer_cfg), err, TAG, "config RX DMA transfer failed");
|
||||
|
||||
// Get buffer alignment required by GDMA channel
|
||||
gdma_get_alignment_constraints(crc_gdma->tx_channel, &crc_gdma->tx_int_mem_alignment, &crc_gdma->tx_ext_mem_alignment);
|
||||
size_t rx_int_mem_alignment = 0;
|
||||
gdma_get_alignment_constraints(crc_gdma->rx_channel, &rx_int_mem_alignment, NULL);
|
||||
gdma_get_channel_alignment_constraints(crc_gdma->rx_channel, &rx_int_mem_alignment, NULL, NULL);
|
||||
size_t rx_buffer_size = (rx_int_mem_alignment > CRC_DMA_RX_SINK_BUFFER_SIZE) ?
|
||||
rx_int_mem_alignment : CRC_DMA_RX_SINK_BUFFER_SIZE;
|
||||
crc_gdma->rx_sink_buffer = heap_caps_aligned_calloc(rx_int_mem_alignment, 1, rx_buffer_size,
|
||||
@@ -191,6 +189,7 @@ esp_err_t esp_async_crc_install_gdma_template(const async_crc_config_t *config,
|
||||
.length = rx_buffer_size,
|
||||
.flags = {
|
||||
.mark_final = GDMA_FINAL_LINK_TO_HEAD,
|
||||
.check_size_align = gdma_is_size_alignment_required(crc_gdma->rx_channel),
|
||||
},
|
||||
};
|
||||
ESP_GOTO_ON_ERROR(gdma_link_mount_buffers(crc_gdma->rx_link_list, 0, &rx_buf_mount_config, 1, NULL),
|
||||
@@ -324,13 +323,7 @@ static esp_err_t async_crc_prepare_transaction(async_crc_gdma_context_t *crc_gdm
|
||||
uint32_t max_crc_bit_width = (crc_gdma->gdma_bus_id == SOC_GDMA_BUS_AXI) ? GDMA_LL_AXI_MAX_CRC_BIT_WIDTH : GDMA_LL_AHB_MAX_CRC_BIT_WIDTH;
|
||||
ESP_RETURN_ON_FALSE(trans->params.width <= max_crc_bit_width, ESP_ERR_INVALID_ARG, TAG, "invalid crc bit width %"PRIu32, trans->params.width);
|
||||
|
||||
// Get buffer alignment based on memory type
|
||||
size_t buffer_alignment = esp_ptr_internal(trans->data) ? crc_gdma->tx_int_mem_alignment : crc_gdma->tx_ext_mem_alignment;
|
||||
|
||||
// Verify user buffer satisfies DMA alignment requirements
|
||||
ESP_RETURN_ON_FALSE(((uintptr_t)trans->data % buffer_alignment) == 0, ESP_ERR_INVALID_ARG, TAG,
|
||||
"Data buffer not aligned to %zu bytes", buffer_alignment);
|
||||
|
||||
size_t buffer_alignment = gdma_get_buffer_alignment_constraint(crc_gdma->tx_channel, trans->data);
|
||||
// Calculate number of DMA nodes needed
|
||||
size_t tx_num_dma_nodes = esp_dma_calculate_node_count(trans->size, buffer_alignment, CRC_DMA_DESCRIPTOR_BUFFER_MAX_SIZE);
|
||||
|
||||
|
||||
@@ -47,10 +47,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 rx_int_mem_alignment; // Required DMA buffer alignment for internal RX memory
|
||||
size_t rx_ext_mem_alignment; // Required DMA buffer alignment for external RX memory
|
||||
size_t tx_int_mem_alignment; // Required DMA buffer alignment for internal TX memory
|
||||
size_t tx_ext_mem_alignment; // Required DMA buffer alignment for external TX memory
|
||||
int gdma_bus_id; // GDMA bus id (AHB, AXI, etc.)
|
||||
gdma_channel_handle_t tx_channel; // GDMA TX channel handle
|
||||
gdma_channel_handle_t rx_channel; // GDMA RX channel handle
|
||||
@@ -149,10 +145,6 @@ static esp_err_t esp_async_memcpy_install_gdma_template(const async_memcpy_confi
|
||||
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");
|
||||
|
||||
// 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);
|
||||
|
||||
// register rx eof callback
|
||||
gdma_rx_event_callbacks_t cbs = {
|
||||
.on_recv_eof = mcp_gdma_rx_eof_callback,
|
||||
@@ -281,30 +273,6 @@ static async_memcpy_transaction_t *try_pop_trans_from_idle_queue(async_memcpy_gd
|
||||
return trans;
|
||||
}
|
||||
|
||||
/// @brief Check if the address and size can meet the requirement of the DMA engine
|
||||
static bool check_buffer_alignment(async_memcpy_gdma_context_t *mcp_gdma, void *src, void *dst, size_t n)
|
||||
{
|
||||
bool valid = true;
|
||||
|
||||
if (esp_ptr_external_ram(dst)) {
|
||||
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 & (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 & (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 & (mcp_gdma->tx_int_mem_alignment - 1)) == 0);
|
||||
valid = valid && ((n & (mcp_gdma->tx_int_mem_alignment - 1)) == 0);
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
static esp_err_t mcp_gdma_memcpy(async_memcpy_context_t *ctx, void *dst, void *src, size_t n, async_memcpy_isr_cb_t cb_isr, void *cb_args)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
@@ -335,8 +303,6 @@ static esp_err_t mcp_gdma_memcpy(async_memcpy_context_t *ctx, void *dst, void *s
|
||||
dma_link_item_alignment = GDMA_LL_AHB_DESC_ALIGNMENT;
|
||||
}
|
||||
#endif // SOC_HAS(LP_AHB_GDMA)
|
||||
// alignment check
|
||||
ESP_RETURN_ON_FALSE(check_buffer_alignment(mcp_gdma, src, dst, n), ESP_ERR_INVALID_ARG, TAG, "address|size not aligned: %p -> %p, sz=%zu", src, dst, n);
|
||||
|
||||
async_memcpy_transaction_t *trans = NULL;
|
||||
// pick one transaction node from idle queue
|
||||
@@ -368,7 +334,7 @@ static esp_err_t mcp_gdma_memcpy(async_memcpy_context_t *ctx, void *dst, void *s
|
||||
size_t num_dma_nodes = 0;
|
||||
|
||||
// allocate gdma TX link, only the body is handled by the DMA
|
||||
buffer_alignment = esp_ptr_internal(split.body_src) ? mcp_gdma->tx_int_mem_alignment : mcp_gdma->tx_ext_mem_alignment;
|
||||
buffer_alignment = gdma_get_buffer_alignment_constraint(mcp_gdma->tx_channel, split.body_src);
|
||||
num_dma_nodes = esp_dma_calculate_node_count(split.body_len, buffer_alignment, MCP_DMA_DESCRIPTOR_BUFFER_MAX_SIZE);
|
||||
gdma_link_list_config_t tx_link_cfg = {
|
||||
.item_alignment = dma_link_item_alignment,
|
||||
@@ -394,7 +360,7 @@ static esp_err_t mcp_gdma_memcpy(async_memcpy_context_t *ctx, void *dst, void *s
|
||||
gdma_link_mount_buffers(trans->tx_link_list, 0, tx_buf_mount_config, 1, NULL);
|
||||
|
||||
// allocate gdma RX link, only the body is handled by the DMA
|
||||
buffer_alignment = esp_ptr_internal(split.body_dst) ? mcp_gdma->rx_int_mem_alignment : mcp_gdma->rx_ext_mem_alignment;
|
||||
buffer_alignment = gdma_get_buffer_alignment_constraint(mcp_gdma->rx_channel, split.body_dst);
|
||||
num_dma_nodes = esp_dma_calculate_node_count(split.body_len, buffer_alignment, MCP_DMA_DESCRIPTOR_BUFFER_MAX_SIZE);
|
||||
gdma_link_list_config_t rx_link_cfg = {
|
||||
.item_alignment = dma_link_item_alignment,
|
||||
@@ -414,6 +380,7 @@ static esp_err_t mcp_gdma_memcpy(async_memcpy_context_t *ctx, void *dst, void *s
|
||||
.flags = {
|
||||
.mark_eof = true,
|
||||
.mark_final = GDMA_FINAL_LINK_TO_NULL,
|
||||
.check_size_align = gdma_is_size_alignment_required(mcp_gdma->rx_channel),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#include "hal/dma2d_periph.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "esp_bit_defs.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_private/esp_mspi_align.h"
|
||||
#include "esp_private/sleep_retention.h"
|
||||
|
||||
/**
|
||||
@@ -801,8 +801,12 @@ esp_err_t dma2d_set_desc_addr(dma2d_channel_handle_t dma2d_chan, intptr_t desc_b
|
||||
addr_in_spm = esp_ptr_in_spm((void *)desc_base_addr);
|
||||
#endif
|
||||
ESP_GOTO_ON_FALSE_ISR((desc_base_addr & 0x7) == 0 && !addr_in_spm, ESP_ERR_INVALID_ARG, err, TAG, "invalid descriptor base addr");
|
||||
// When flash encryption is enabled, the descriptor must be in internal RAM because descriptor size is not 16-byte aligned, which breaks flash encryption alignment restriction
|
||||
ESP_GOTO_ON_FALSE_ISR(!esp_efuse_is_flash_encryption_enabled() || esp_ptr_internal((void *)desc_base_addr), ESP_ERR_INVALID_ARG, err, TAG, "invalid description base addr");
|
||||
// If descriptors are placed in external memory, their size must meet MSPI alignment constraints;
|
||||
// otherwise, descriptors must be located in internal RAM.
|
||||
size_t mspi_align = esp_mspi_get_alignment((void *)desc_base_addr);
|
||||
bool desc_size_mspi_aligned = (sizeof(dma2d_descriptor_t) & (mspi_align - 1)) == 0;
|
||||
ESP_GOTO_ON_FALSE_ISR(desc_size_mspi_aligned || esp_ptr_internal((void *)desc_base_addr),
|
||||
ESP_ERR_INVALID_ARG, err, TAG, "invalid description base addr");
|
||||
|
||||
dma2d_group_t *group = dma2d_chan->group;
|
||||
int channel_id = dma2d_chan->channel_id;
|
||||
@@ -920,20 +924,19 @@ esp_err_t dma2d_set_transfer_ability(dma2d_channel_handle_t dma2d_chan, const dm
|
||||
ESP_GOTO_ON_FALSE_ISR(dma2d_chan && ability, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
|
||||
ESP_GOTO_ON_FALSE_ISR(ability->data_burst_length && ((ability->data_burst_length & (ability->data_burst_length - 1)) == 0), ESP_ERR_INVALID_ARG, err, TAG, "invalid argument"); // burst size must be power of 2
|
||||
ESP_GOTO_ON_FALSE_ISR(ability->mb_size < DMA2D_MACRO_BLOCK_SIZE_INVALID, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
|
||||
ESP_GOTO_ON_FALSE_ISR(!ability->access_ext_mem || (SOC_PSRAM_DMA_CAPABLE || SOC_DMA_CAN_ACCESS_FLASH), ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
|
||||
|
||||
dma2d_group_t *group = dma2d_chan->group;
|
||||
int channel_id = dma2d_chan->channel_id;
|
||||
|
||||
// When flash encryption is enabled, and the channel is accessing external memory, burst length has to be as least as the encryption alignment restriction size
|
||||
uint32_t data_burst_length = ability->data_burst_length;
|
||||
#if SOC_PSRAM_DMA_CAPABLE || SOC_DMA_CAN_ACCESS_FLASH
|
||||
if (esp_efuse_is_flash_encryption_enabled() && ability->access_ext_mem) {
|
||||
if (data_burst_length < SOC_MEMSPI_ENCRYPTION_ALIGNMENT) {
|
||||
data_burst_length = SOC_MEMSPI_ENCRYPTION_ALIGNMENT;
|
||||
ESP_LOGW(TAG, "channel access encrypted external memory, adjust burst size to %d", SOC_MEMSPI_ENCRYPTION_ALIGNMENT);
|
||||
if (ability->access_ext_mem) {
|
||||
// If channel is accessing external memory, burst length has to be at least the MSPI alignment restriction size
|
||||
size_t mspi_alignment = dma2d_get_alloc_alignment();
|
||||
if (data_burst_length < mspi_alignment) {
|
||||
data_burst_length = mspi_alignment;
|
||||
ESP_LOGW(TAG, "requested burst size does not meet MSPI alignment constraint, adjust to %d", (int)mspi_alignment);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (dma2d_chan->direction == DMA2D_CHANNEL_DIRECTION_TX) {
|
||||
dma2d_ll_tx_enable_descriptor_burst(group->hal.dev, channel_id, ability->desc_burst_en);
|
||||
@@ -949,6 +952,46 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t dma2d_get_buffer_alignment_constraint(const void *buffer)
|
||||
{
|
||||
if (!buffer) {
|
||||
return BIT(31);
|
||||
}
|
||||
|
||||
return esp_mspi_get_alignment(buffer);
|
||||
}
|
||||
|
||||
size_t dma2d_get_alloc_alignment(void)
|
||||
{
|
||||
// Worst-case alignment for buffers that may be accessed by DMA2D (MSPI FE/ECC, etc.)
|
||||
return esp_mspi_get_alignment(NULL);
|
||||
}
|
||||
|
||||
bool dma2d_check_transaction_alignment_constraint(const void *buf, uint32_t pic_width, uint32_t blk_width,
|
||||
uint32_t offset_x, uint32_t bit_depth)
|
||||
{
|
||||
if (!buf || bit_depth == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t alignment = dma2d_get_buffer_alignment_constraint(buf);
|
||||
if (alignment <= 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Under Flash Encryption / PSRAM ECC, MSPI requires each AXI access to be aligned in both address and size.
|
||||
// For 2D DMA that means:
|
||||
// - buffer base address aligned to N bytes
|
||||
// - bytes-per-line (pic_width * bpp/8) aligned, so every next line starts on an N-byte boundary
|
||||
// - transfer width (blk_width * bpp/8) aligned
|
||||
// - horizontal window offset (offset_x * bpp/8) aligned, so the first pixel of the window is aligned
|
||||
uint32_t alignment_bits = alignment * 8;
|
||||
return (((uintptr_t)buf & (alignment - 1)) == 0) &&
|
||||
(((uint64_t)pic_width * bit_depth) % alignment_bits == 0) &&
|
||||
(((uint64_t)blk_width * bit_depth) % alignment_bits == 0) &&
|
||||
(((uint64_t)offset_x * bit_depth) % alignment_bits == 0);
|
||||
}
|
||||
|
||||
esp_err_t dma2d_configure_color_space_conversion(dma2d_channel_handle_t dma2d_chan, const dma2d_csc_config_t *config)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
@@ -43,7 +43,7 @@ esp_err_t esp_dma_split_rx_buffer_to_cache_aligned(void *rx_buffer, size_t buffe
|
||||
split_line_size = int_mem_cache_line_size;
|
||||
}
|
||||
bool align_required = split_line_size > 0;
|
||||
ESP_EARLY_LOGV(TAG, "split_line_size:%zu", split_line_size);
|
||||
ESP_EARLY_LOGV(TAG, "split_line_size:%d", split_line_size);
|
||||
|
||||
if (*ret_stash_buffer == NULL) {
|
||||
// If the stash buffer is not offered by the caller, allocate the stash buffer from internal RAM
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#include "gdma_priv.h"
|
||||
#include "esp_memory_utils.h"
|
||||
#include "esp_private/esp_mspi_align.h"
|
||||
|
||||
#define GDMA_INVALID_PERIPH_TRIG (0x3F)
|
||||
#define SEARCH_REQUEST_RX_CHANNEL (1 << 0)
|
||||
@@ -419,87 +420,101 @@ esp_err_t gdma_config_transfer(gdma_channel_handle_t dma_chan, const gdma_transf
|
||||
if (!dma_chan || !config) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
uint32_t max_data_burst_size = config->max_data_burst_size;
|
||||
size_t int_mem_alignment = 1;
|
||||
size_t ext_enc_mem_alignment = 1;
|
||||
size_t ext_no_enc_mem_alignment = 1;
|
||||
|
||||
if (config->access_ext_mem) {
|
||||
#if (SOC_PSRAM_DMA_CAPABLE || SOC_DMA_CAN_ACCESS_FLASH) && SOC_AHB_GDMA_VERSION != 1
|
||||
// Under Flash Encryption/PSRAM ECC, external DMA must use MSPI-aligned bursts.
|
||||
size_t mspi_alignment = esp_mspi_get_alignment(NULL);
|
||||
if (mspi_alignment > 1) {
|
||||
if (max_data_burst_size < mspi_alignment) {
|
||||
max_data_burst_size = mspi_alignment;
|
||||
ESP_LOGW(TAG, "max_data_burst_size is less than mspi_alignment, adjusted to %d", max_data_burst_size);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if GDMA_LL_GET(AHB_PSRAM_CAPABLE) || GDMA_LL_GET(AXI_PSRAM_CAPABLE) || GDMA_LL_GET(LP_AHB_PSRAM_CAPABLE)
|
||||
ESP_RETURN_ON_FALSE(max_data_burst_size <= GDMA_LL_MAX_BURST_SIZE_PSRAM, ESP_ERR_INVALID_ARG,
|
||||
TAG, "max_data_burst_size must not exceed %d when accessing external memory", GDMA_LL_MAX_BURST_SIZE_PSRAM);
|
||||
#endif
|
||||
}
|
||||
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);
|
||||
#if GDMA_LL_GET(AHB_PSRAM_CAPABLE) || GDMA_LL_GET(AXI_PSRAM_CAPABLE) || GDMA_LL_GET(LP_AHB_PSRAM_CAPABLE)
|
||||
if (config->access_ext_mem) {
|
||||
ESP_RETURN_ON_FALSE(max_data_burst_size <= GDMA_LL_MAX_BURST_SIZE_PSRAM, ESP_ERR_INVALID_ARG,
|
||||
TAG, "max_data_burst_size must not exceed %d when accessing external memory", GDMA_LL_MAX_BURST_SIZE_PSRAM);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
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;
|
||||
|
||||
// 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;
|
||||
|
||||
// There's auto alignment for AHB GDMA version 1, so we don't need to do anything here
|
||||
// While, for AHB GDMA version 2 and AXI GDMA, we need to ensure the alignment by software
|
||||
#if (SOC_PSRAM_DMA_CAPABLE || SOC_DMA_CAN_ACCESS_FLASH) && SOC_AHB_GDMA_VERSION != 1
|
||||
bool ext_mem_needs_mspi_alignment = esp_efuse_is_flash_encryption_enabled();
|
||||
#if CONFIG_SPIRAM_ECC_ENABLE
|
||||
ext_mem_needs_mspi_alignment = true;
|
||||
#endif
|
||||
// When MSPI encryption or PSRAM ECC address conversion is enabled, DMA accesses to
|
||||
// external memory need to follow the MSPI encryption alignment restriction.
|
||||
if (ext_mem_needs_mspi_alignment && config->access_ext_mem) {
|
||||
uint32_t mspi_mem_alignment = SOC_MEMSPI_ENCRYPTION_ALIGNMENT;
|
||||
ext_mem_alignment = MAX(ext_mem_alignment, mspi_mem_alignment);
|
||||
if (max_data_burst_size < mspi_mem_alignment) {
|
||||
ESP_LOGW(TAG, "GDMA channel access encrypted/ECC external memory, adjust burst size to %d", mspi_mem_alignment);
|
||||
en_data_burst = true;
|
||||
max_data_burst_size = mspi_mem_alignment;
|
||||
}
|
||||
}
|
||||
#endif // SOC_PSRAM_DMA_CAPABLE || SOC_DMA_CAN_ACCESS_FLASH
|
||||
|
||||
gdma_hal_enable_burst(hal, pair->pair_id, dma_chan->direction, en_data_burst, en_desc_burst);
|
||||
dma_chan->flags.size_alignment_required = false;
|
||||
if (en_data_burst) {
|
||||
gdma_hal_set_burst_size(hal, pair->pair_id, dma_chan->direction, max_data_burst_size);
|
||||
#if CONFIG_GDMA_ENABLE_WEIGHTED_ARBITRATION
|
||||
// due to hardware limitation, if weighted arbitration is enabled, the data must be aligned to burst size
|
||||
int_mem_alignment = MAX(int_mem_alignment, max_data_burst_size);
|
||||
ext_mem_alignment = MAX(ext_mem_alignment, max_data_burst_size);
|
||||
ext_enc_mem_alignment = MAX(ext_enc_mem_alignment, max_data_burst_size);
|
||||
ext_no_enc_mem_alignment = MAX(ext_no_enc_mem_alignment, max_data_burst_size);
|
||||
#endif
|
||||
}
|
||||
|
||||
#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);
|
||||
ext_enc_mem_alignment = MAX(ext_enc_mem_alignment, max_data_burst_size);
|
||||
ext_no_enc_mem_alignment = MAX(ext_no_enc_mem_alignment, max_data_burst_size);
|
||||
dma_chan->flags.size_alignment_required = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// 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);
|
||||
if (config->access_ext_mem) {
|
||||
// ext_enc includes MSPI encryption/ECC constraints; ext_no_enc keeps DMA-only constraints.
|
||||
size_t mspi_alignment = esp_mspi_get_alignment(NULL);
|
||||
ext_enc_mem_alignment = MAX(ext_enc_mem_alignment, mspi_alignment);
|
||||
} else {
|
||||
// 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
|
||||
ext_enc_mem_alignment = BIT(31);
|
||||
ext_no_enc_mem_alignment = BIT(31);
|
||||
}
|
||||
|
||||
gdma_pair_t *pair = dma_chan->pair;
|
||||
gdma_group_t *group = pair->group;
|
||||
gdma_hal_context_t *hal = &group->hal;
|
||||
|
||||
// always enable descriptor burst as the descriptor is always word aligned and is in the internal SRAM
|
||||
bool en_desc_burst = true;
|
||||
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 CONFIG_IDF_TARGET_ESP32S31 && SOC_HAS(LP_AHB_GDMA)
|
||||
// ESP32-S31 LP AHB GDMA can't burst-access encrypted external memory.
|
||||
// ESP32-S31 LP AHB GDMA can't burst-access external memory (with or without ECC/encryption).
|
||||
// Keep configuration/installation permissive for callers that only intend to
|
||||
// use internal buffers, but poison the external-memory alignment so any
|
||||
// later PSRAM use fails the caller-side validation.
|
||||
if (config->access_ext_mem && group->bus_id == SOC_GDMA_BUS_LP && esp_efuse_is_flash_encryption_enabled()) {
|
||||
ext_mem_alignment = BIT(31);
|
||||
if (config->access_ext_mem && group->bus_id == SOC_GDMA_BUS_LP) {
|
||||
if (esp_efuse_is_flash_encryption_enabled()) {
|
||||
ext_enc_mem_alignment = BIT(31);
|
||||
}
|
||||
#if CONFIG_SPIRAM_ECC_ENABLE
|
||||
// ECC PSRAM is inaccessible to LP AHB regardless of flash encryption state.
|
||||
ext_enc_mem_alignment = BIT(31);
|
||||
ext_no_enc_mem_alignment = BIT(31);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
dma_chan->int_mem_alignment = int_mem_alignment;
|
||||
dma_chan->ext_mem_alignment = ext_mem_alignment;
|
||||
dma_chan->ext_enc_mem_alignment = ext_enc_mem_alignment;
|
||||
dma_chan->ext_no_enc_mem_alignment = ext_no_enc_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_err_t gdma_get_channel_alignment_constraints(gdma_channel_handle_t dma_chan, size_t *int_mem_alignment,
|
||||
size_t *ext_enc_mem_alignment, size_t *ext_no_enc_mem_alignment)
|
||||
{
|
||||
if (!dma_chan) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
@@ -507,12 +522,35 @@ esp_err_t gdma_get_alignment_constraints(gdma_channel_handle_t dma_chan, size_t
|
||||
if (int_mem_alignment) {
|
||||
*int_mem_alignment = dma_chan->int_mem_alignment;
|
||||
}
|
||||
if (ext_mem_alignment) {
|
||||
*ext_mem_alignment = dma_chan->ext_mem_alignment;
|
||||
if (ext_enc_mem_alignment) {
|
||||
*ext_enc_mem_alignment = dma_chan->ext_enc_mem_alignment;
|
||||
}
|
||||
if (ext_no_enc_mem_alignment) {
|
||||
*ext_no_enc_mem_alignment = dma_chan->ext_no_enc_mem_alignment;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
bool gdma_is_size_alignment_required(gdma_channel_handle_t dma_chan)
|
||||
{
|
||||
return dma_chan && dma_chan->flags.size_alignment_required;
|
||||
}
|
||||
|
||||
size_t gdma_get_buffer_alignment_constraint(gdma_channel_handle_t dma_chan, const void *buffer)
|
||||
{
|
||||
if (!dma_chan || !buffer) {
|
||||
return BIT(31);
|
||||
}
|
||||
|
||||
size_t base_alignment = dma_chan->int_mem_alignment;
|
||||
if (esp_ptr_external_ram(buffer) || esp_ptr_in_drom(buffer)) {
|
||||
base_alignment = dma_chan->ext_no_enc_mem_alignment;
|
||||
}
|
||||
|
||||
size_t mspi_alignment = esp_mspi_get_alignment(buffer);
|
||||
return MAX(base_alignment, mspi_alignment);
|
||||
}
|
||||
|
||||
esp_err_t gdma_apply_strategy(gdma_channel_handle_t dma_chan, const gdma_strategy_config_t *config)
|
||||
{
|
||||
if (!dma_chan || !config) {
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/cdefs.h>
|
||||
#include "soc/soc_caps.h"
|
||||
#include "esp_log.h"
|
||||
@@ -15,10 +16,8 @@
|
||||
#include "esp_memory_utils.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_private/gdma_link.h"
|
||||
#include "hal/cache_hal.h"
|
||||
#include "hal/efuse_hal.h"
|
||||
#include "hal/cache_ll.h"
|
||||
#include "esp_cache.h"
|
||||
#include "esp_private/esp_mspi_align.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_macros.h"
|
||||
|
||||
@@ -76,10 +75,10 @@ esp_err_t gdma_new_link_list(const gdma_link_list_config_t *config, gdma_link_li
|
||||
bool items_in_ext_mem = config->flags.items_in_ext_mem;
|
||||
uint32_t list_items_mem_caps = MALLOC_CAP_8BIT | MALLOC_CAP_DMA;
|
||||
if (items_in_ext_mem) {
|
||||
if (esp_efuse_is_flash_encryption_enabled()) {
|
||||
if (esp_mspi_get_alignment(NULL) > 1) {
|
||||
items_in_ext_mem = false;
|
||||
list_items_mem_caps |= MALLOC_CAP_INTERNAL;
|
||||
ESP_LOGW(TAG, "DMA linked list items cannot be placed in PSRAM when external memory encryption is enabled, using internal memory instead");
|
||||
ESP_LOGW(TAG, "DMA linked list items cannot be placed in PSRAM when MSPI strict alignment is required, using internal memory instead");
|
||||
} else {
|
||||
list_items_mem_caps |= MALLOC_CAP_SPIRAM;
|
||||
}
|
||||
@@ -90,12 +89,7 @@ esp_err_t gdma_new_link_list(const gdma_link_list_config_t *config, gdma_link_li
|
||||
ESP_GOTO_ON_FALSE(items, ESP_ERR_NO_MEM, err, TAG, "no mem for link list items");
|
||||
|
||||
// do memory sync if the list items are in the cache
|
||||
uint32_t data_cache_line_size = 0;
|
||||
if (items_in_ext_mem) {
|
||||
data_cache_line_size = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_DATA);
|
||||
} else {
|
||||
data_cache_line_size = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA);
|
||||
}
|
||||
size_t data_cache_line_size = esp_cache_get_line_size_by_addr(items);
|
||||
if (data_cache_line_size) {
|
||||
// write back and then invalidate the cache, because later we will read/write the link list items by non-cached address
|
||||
ESP_GOTO_ON_ERROR(esp_cache_msync(items, ESP_ALIGN_UP(num_items * item_size, data_cache_line_size),
|
||||
@@ -190,12 +184,16 @@ esp_err_t gdma_link_mount_buffers(gdma_link_list_handle_t list, int start_item_i
|
||||
}
|
||||
// alignment must be a power of 2
|
||||
ESP_RETURN_ON_FALSE_ISR((buffer_alignment & (buffer_alignment - 1)) == 0, ESP_ERR_INVALID_ARG, TAG, "align err idx=%"PRIu32" align=%"PRIu32, bi, buffer_alignment);
|
||||
size_t max_buffer_mount_length = ESP_ALIGN_DOWN(GDMA_MAX_BUFFER_SIZE_PER_LINK_ITEM, buffer_alignment);
|
||||
size_t mspi_alignment = esp_mspi_get_alignment(buf);
|
||||
size_t effective_alignment = MAX(buffer_alignment, mspi_alignment);
|
||||
size_t max_buffer_mount_length = ESP_ALIGN_DOWN(GDMA_MAX_BUFFER_SIZE_PER_LINK_ITEM, effective_alignment);
|
||||
if (!config->flags.bypass_buffer_align_check) {
|
||||
ESP_RETURN_ON_FALSE_ISR(((uintptr_t)buf & (buffer_alignment - 1)) == 0, ESP_ERR_INVALID_ARG, TAG, "buf misalign idx=%"PRIu32" align=%"PRIu32, bi, buffer_alignment);
|
||||
if (esp_efuse_is_flash_encryption_enabled()) {
|
||||
// buffer size must be aligned to the encryption alignment which should be provided by the upper buffer_alignment
|
||||
ESP_RETURN_ON_FALSE_ISR((len & (buffer_alignment - 1)) == 0, ESP_ERR_INVALID_ARG, TAG, "buf len misalign idx=%"PRIu32" len=%"PRIu32" align=%"PRIu32"", bi, len, buffer_alignment);
|
||||
ESP_RETURN_ON_FALSE_ISR(((uintptr_t)buf & (effective_alignment - 1)) == 0, ESP_ERR_INVALID_ARG, TAG, "buf misalign idx=%"PRIu32" align=%"PRIu32, bi, effective_alignment);
|
||||
// Length alignment:
|
||||
// - Always required under MSPI strict mode (Flash Encryption / PSRAM ECC): size must align.
|
||||
// - Also when check_size_align is set by a caller whose configured channel requires size alignment.
|
||||
if (mspi_alignment > 1 || config->flags.check_size_align) {
|
||||
ESP_RETURN_ON_FALSE_ISR((len & (effective_alignment - 1)) == 0, ESP_ERR_INVALID_ARG, TAG, "buf len misalign idx=%"PRIu32" len=%"PRIu32" align=%"PRIu32"", bi, len, effective_alignment);
|
||||
}
|
||||
}
|
||||
size_t num_items_need = (len + max_buffer_mount_length - 1) / max_buffer_mount_length;
|
||||
@@ -217,7 +215,6 @@ esp_err_t gdma_link_mount_buffers(gdma_link_list_handle_t list, int start_item_i
|
||||
if (buffer_alignment == 0) {
|
||||
buffer_alignment = 1;
|
||||
}
|
||||
size_t max_buffer_mount_length = ESP_ALIGN_DOWN(GDMA_MAX_BUFFER_SIZE_PER_LINK_ITEM, buffer_alignment);
|
||||
// skip zero-length buffer but scrub any stale descriptor to keep ring clean; no slot consumption
|
||||
if (len == 0 || buf == NULL) {
|
||||
lli_nc = (gdma_link_list_item_t *)(list->items_nc + begin_item_idx % list_item_capacity * item_size);
|
||||
@@ -225,6 +222,9 @@ esp_err_t gdma_link_mount_buffers(gdma_link_list_handle_t list, int start_item_i
|
||||
memset(lli_nc, 0, item_size);
|
||||
continue;
|
||||
}
|
||||
size_t mspi_alignment = esp_mspi_get_alignment(buf);
|
||||
size_t effective_alignment = MAX(buffer_alignment, mspi_alignment);
|
||||
size_t max_buffer_mount_length = ESP_ALIGN_DOWN(GDMA_MAX_BUFFER_SIZE_PER_LINK_ITEM, effective_alignment);
|
||||
size_t num_items_need = (len + max_buffer_mount_length - 1) / max_buffer_mount_length;
|
||||
// mount the buffer to the link list
|
||||
for (size_t i = 0; i < num_items_need; i++) {
|
||||
|
||||
@@ -90,11 +90,13 @@ struct gdma_channel_t {
|
||||
int periph_id; // Peripheral instance ID, indicates which peripheral is connected to this GDMA channel
|
||||
int intr_priority; // interrupt priority, if set to 0, the driver will use the default priority
|
||||
size_t int_mem_alignment; // alignment for memory in internal memory
|
||||
size_t ext_mem_alignment; // alignment for memory in external memory
|
||||
size_t ext_enc_mem_alignment; // alignment for external memory including MSPI encryption/ECC constraints
|
||||
size_t ext_no_enc_mem_alignment; // alignment for external memory without MSPI region-specific constraints
|
||||
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
|
||||
uint32_t isr_cache_safe: 1; // whether the interrupt of this channel need to be cache safe
|
||||
uint32_t size_alignment_required: 1; // whether buffer size must meet the channel alignment
|
||||
} flags;
|
||||
};
|
||||
|
||||
|
||||
@@ -10,16 +10,25 @@
|
||||
#include <stddef.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_private/gdma.h"
|
||||
#include "esp_private/esp_mspi_align.h"
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32S31
|
||||
// ESP32-S31 LP AHB GDMA can't burst-access external PSRAM. Skip the
|
||||
// flash-encrypted PSRAM test paths because encrypted PSRAM requires burst
|
||||
// accesses aligned to the encryption block size.
|
||||
// MSPI-strict PSRAM test paths because Flash Encryption / PSRAM ECC require
|
||||
// burst accesses aligned to the MSPI block size.
|
||||
#define GDMA_TEST_LP_AHB_BURST_PSRAM_SUPPORTED 0
|
||||
#else
|
||||
#define GDMA_TEST_LP_AHB_BURST_PSRAM_SUPPORTED 1
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Whether MSPI strict alignment is required (Flash Encryption and/or PSRAM ECC)
|
||||
*/
|
||||
static inline bool gdma_test_mspi_strict_alignment_required(void)
|
||||
{
|
||||
return esp_mspi_get_alignment(NULL) > 1;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
@@ -15,8 +15,6 @@
|
||||
#include "freertos/semphr.h"
|
||||
#include "ccomp_timer.h"
|
||||
#include "esp_async_memcpy.h"
|
||||
#include "hal/efuse_hal.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "gdma_test_utils.h"
|
||||
|
||||
#if SOC_GDMA_SUPPORTED
|
||||
@@ -168,7 +166,7 @@ static void test_memory_copy_blocking(async_memcpy_handle_t driver)
|
||||
for (int off = 0; off < 4; off++) {
|
||||
test_context.buffer_size = test_buffer_size[i];
|
||||
test_context.seed = i;
|
||||
if (!esp_efuse_is_flash_encryption_enabled()) {
|
||||
if (!gdma_test_mspi_strict_alignment_required()) {
|
||||
test_context.src_offset = off;
|
||||
test_context.dst_offset = off;
|
||||
}
|
||||
@@ -257,8 +255,8 @@ TEST_CASE("memory copy with dest address unaligned", "[async mcp]")
|
||||
};
|
||||
[[maybe_unused]] async_memcpy_handle_t driver = NULL;
|
||||
|
||||
if (esp_efuse_is_flash_encryption_enabled()) {
|
||||
TEST_PASS_MESSAGE("Flash encryption is enabled, skip this test");
|
||||
if (gdma_test_mspi_strict_alignment_required()) {
|
||||
TEST_PASS_MESSAGE("MSPI strict alignment required (Flash Encryption / PSRAM ECC), skip this test");
|
||||
}
|
||||
|
||||
#if SOC_CP_DMA_SUPPORTED
|
||||
@@ -441,8 +439,8 @@ TEST_CASE("memory copy performance 40KB: PSRAM->PSRAM", "[async mcp]")
|
||||
|
||||
#if SOC_HAS(LP_AHB_GDMA)
|
||||
#if GDMA_LL_GET(LP_AHB_PSRAM_CAPABLE)
|
||||
if (esp_efuse_is_flash_encryption_enabled() && !GDMA_TEST_LP_AHB_BURST_PSRAM_SUPPORTED) {
|
||||
TEST_IGNORE_MESSAGE("Skipping LP AHB GDMA PSRAM->PSRAM under flash encryption");
|
||||
if (gdma_test_mspi_strict_alignment_required() && !GDMA_TEST_LP_AHB_BURST_PSRAM_SUPPORTED) {
|
||||
TEST_IGNORE_MESSAGE("Skipping LP AHB GDMA PSRAM->PSRAM under Flash Encryption / PSRAM ECC");
|
||||
} else {
|
||||
printf("Testing memcpy by LP AHB GDMA\r\n");
|
||||
TEST_ESP_OK(esp_async_memcpy_install_gdma_lp_ahb(&driver_config, &driver));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -11,10 +11,9 @@
|
||||
#include "unity.h"
|
||||
#include "esp_private/dw_gdma.h"
|
||||
#include "hal/dw_gdma_ll.h"
|
||||
#include "hal/efuse_hal.h"
|
||||
#include "esp_cache.h"
|
||||
#include "esp_private/esp_cache_private.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_private/esp_mspi_align.h"
|
||||
|
||||
TEST_CASE("DW_GDMA channel allocation", "[DW_GDMA]")
|
||||
{
|
||||
@@ -542,8 +541,8 @@ TEST_CASE("DW_GDMA M2M Test: memory set with fixed address", "[DW_GDMA]")
|
||||
size_t int_mem_alignment = 0;
|
||||
TEST_ESP_OK(esp_cache_get_alignment(MALLOC_CAP_SPIRAM, &ext_mem_alignment));
|
||||
TEST_ESP_OK(esp_cache_get_alignment(0, &int_mem_alignment));
|
||||
if (esp_efuse_is_flash_encryption_enabled()) {
|
||||
TEST_PASS_MESSAGE("Flash encryption is enabled, skip this test");
|
||||
if (esp_mspi_get_alignment(NULL) > 1) {
|
||||
TEST_PASS_MESSAGE("MSPI strict alignment required (Flash Encryption / PSRAM ECC), skip this test");
|
||||
}
|
||||
uint8_t *src_buf = heap_caps_aligned_calloc(ext_mem_alignment, 1, 256, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||
uint8_t *dst_buf = heap_caps_aligned_calloc(int_mem_alignment, 1, 256, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
|
||||
|
||||
@@ -20,11 +20,9 @@
|
||||
#include "hal/gdma_ll.h"
|
||||
#include "hal/cache_ll.h"
|
||||
#include "hal/cache_hal.h"
|
||||
#include "hal/efuse_hal.h"
|
||||
#include "esp_cache.h"
|
||||
#include "esp_memory_utils.h"
|
||||
#include "gdma_test_utils.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_macros.h"
|
||||
|
||||
TEST_CASE("GDMA channel allocation", "[GDMA]")
|
||||
@@ -275,7 +273,7 @@ static void test_gdma_m2m_transaction(gdma_channel_handle_t tx_chan, gdma_channe
|
||||
TEST_ASSERT_NOT_NULL(done_sem);
|
||||
TEST_ESP_OK(gdma_register_rx_event_callbacks(rx_chan, &rx_cbs, done_sem));
|
||||
|
||||
if (esp_efuse_is_flash_encryption_enabled()) {
|
||||
if (gdma_test_mspi_strict_alignment_required()) {
|
||||
dma_link_in_ext_mem = false;
|
||||
}
|
||||
|
||||
@@ -285,7 +283,7 @@ static void test_gdma_m2m_transaction(gdma_channel_handle_t tx_chan, gdma_channe
|
||||
|
||||
size_t int_mem_alignment = 0;
|
||||
size_t ext_mem_alignment = 0;
|
||||
TEST_ESP_OK(gdma_get_alignment_constraints(tx_chan, &int_mem_alignment, &ext_mem_alignment));
|
||||
TEST_ESP_OK(gdma_get_channel_alignment_constraints(tx_chan, &int_mem_alignment, &ext_mem_alignment, NULL));
|
||||
|
||||
// allocate the source buffer from SRAM
|
||||
uint8_t *src_data = heap_caps_aligned_calloc(int_mem_alignment, 1, 128, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
|
||||
@@ -352,6 +350,9 @@ static void test_gdma_m2m_transaction(gdma_channel_handle_t tx_chan, gdma_channe
|
||||
.buffer = dst_data,
|
||||
.buffer_alignment = sram_alignment, // RX buffer should be aligned to the cache line size, because we will do cache invalidate later
|
||||
.length = 256,
|
||||
.flags = {
|
||||
.check_size_align = gdma_is_size_alignment_required(rx_chan),
|
||||
},
|
||||
};
|
||||
TEST_ESP_OK(gdma_link_mount_buffers(rx_link_list, 0, &rx_buf_mount_config, 1, NULL));
|
||||
|
||||
@@ -424,8 +425,8 @@ static void test_gdma_m2m_mode(bool trig_retention_backup)
|
||||
#endif // SOC_HAS(AXI_GDMA)
|
||||
|
||||
#if SOC_HAS(LP_AHB_GDMA)
|
||||
if (esp_efuse_is_flash_encryption_enabled() && !GDMA_TEST_LP_AHB_BURST_PSRAM_SUPPORTED) {
|
||||
TEST_IGNORE_MESSAGE("Skip LP-AHB-GDMA GDMA M2M Mode under flash encryption");
|
||||
if (gdma_test_mspi_strict_alignment_required() && !GDMA_TEST_LP_AHB_BURST_PSRAM_SUPPORTED) {
|
||||
TEST_IGNORE_MESSAGE("Skip LP-AHB-GDMA GDMA M2M Mode under Flash Encryption / PSRAM ECC");
|
||||
} else {
|
||||
printf("Testing GDMA M2M Mode by LP-AHB GDMA%s\n", trig_retention_backup ? " with retention backup" : "");
|
||||
TEST_ESP_OK(gdma_new_lp_ahb_channel(&chan_alloc_config, &tx_chan, &rx_chan));
|
||||
@@ -500,6 +501,7 @@ static void test_gdma_m2m_desc_empty_event(gdma_channel_handle_t tx_chan, gdma_c
|
||||
.length = 64,
|
||||
.flags = {
|
||||
.mark_final = GDMA_FINAL_LINK_TO_NULL,
|
||||
.check_size_align = gdma_is_size_alignment_required(rx_chan),
|
||||
},
|
||||
};
|
||||
TEST_ESP_OK(gdma_link_mount_buffers(rx_link_list, 0, &rx_buf_mount_config, 1, NULL));
|
||||
@@ -569,8 +571,18 @@ static void test_gdma_m2m_unaligned_buffer_test(uint8_t *dst_data, uint8_t *src_
|
||||
gdma_link_list_handle_t rx_link_list = NULL;
|
||||
test_gdma_config_link_list(tx_chan, rx_chan, &tx_link_list, &rx_link_list, 0, false);
|
||||
|
||||
gdma_transfer_config_t transfer_config = {
|
||||
#if GDMA_LL_AHB_RX_BURST_NEEDS_ALIGNMENT || CONFIG_GDMA_ENABLE_WEIGHTED_ARBITRATION
|
||||
.max_data_burst_size = 0,
|
||||
#else
|
||||
.max_data_burst_size = 16,
|
||||
#endif
|
||||
.access_ext_mem = false,
|
||||
};
|
||||
TEST_ESP_OK(gdma_config_transfer(rx_chan, &transfer_config));
|
||||
|
||||
size_t rx_mem_alignment = 0;
|
||||
TEST_ESP_OK(gdma_get_alignment_constraints(rx_chan, &rx_mem_alignment, NULL));
|
||||
TEST_ESP_OK(gdma_get_channel_alignment_constraints(rx_chan, &rx_mem_alignment, NULL, NULL));
|
||||
|
||||
// prepare the source data
|
||||
for (int i = 0; i < data_length; i++) {
|
||||
@@ -602,6 +614,7 @@ static void test_gdma_m2m_unaligned_buffer_test(uint8_t *dst_data, uint8_t *src_
|
||||
rx_aligned_buf_mount_config[i].buffer = align_array.aligned_buffer[i].aligned_buffer;
|
||||
rx_aligned_buf_mount_config[i].buffer_alignment = MAX(sram_alignment, rx_mem_alignment);
|
||||
rx_aligned_buf_mount_config[i].length = align_array.aligned_buffer[i].length;
|
||||
rx_aligned_buf_mount_config[i].flags.check_size_align = gdma_is_size_alignment_required(rx_chan);
|
||||
}
|
||||
TEST_ESP_OK(gdma_link_mount_buffers(rx_link_list, 0, rx_aligned_buf_mount_config, 3, NULL));
|
||||
|
||||
@@ -636,8 +649,8 @@ static void test_gdma_m2m_unaligned_buffer_test(uint8_t *dst_data, uint8_t *src_
|
||||
|
||||
TEST_CASE("GDMA M2M Unaligned RX Buffer Test", "[GDMA][M2M]")
|
||||
{
|
||||
if (esp_efuse_is_flash_encryption_enabled()) {
|
||||
TEST_PASS_MESSAGE("Flash encryption is enabled, skip this test");
|
||||
if (gdma_test_mspi_strict_alignment_required()) {
|
||||
TEST_PASS_MESSAGE("MSPI strict alignment required (Flash Encryption / PSRAM ECC), skip this test");
|
||||
}
|
||||
|
||||
uint8_t *sbuf = heap_caps_aligned_calloc(64, 1, 10240, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
|
||||
@@ -764,6 +777,7 @@ TEST_CASE("GDMA M2M Unaligned RX Buffer Test", "[GDMA][M2M]")
|
||||
.length = COPY_SIZE,
|
||||
.flags = {
|
||||
.mark_final = GDMA_FINAL_LINK_TO_NULL, // using singly list, so terminate the link here
|
||||
.check_size_align = gdma_is_size_alignment_required(rx_chan),
|
||||
}
|
||||
};
|
||||
TEST_ESP_OK(gdma_link_mount_buffers(rx_link_list, 0, &rx_buf_mount_config, 1, NULL));
|
||||
@@ -845,8 +859,8 @@ TEST_CASE("GDMA memory copy SRAM->PSRAM->SRAM", "[GDMA][M2M]")
|
||||
|
||||
#if SOC_HAS(LP_AHB_GDMA)
|
||||
#if GDMA_LL_GET(LP_AHB_PSRAM_CAPABLE)
|
||||
if (esp_efuse_is_flash_encryption_enabled() && !GDMA_TEST_LP_AHB_BURST_PSRAM_SUPPORTED) {
|
||||
TEST_IGNORE_MESSAGE("Skipping LP-AHB-GDMA SRAM->PSRAM->SRAM under flash encryption");
|
||||
if (gdma_test_mspi_strict_alignment_required() && !GDMA_TEST_LP_AHB_BURST_PSRAM_SUPPORTED) {
|
||||
TEST_IGNORE_MESSAGE("Skipping LP-AHB-GDMA SRAM->PSRAM->SRAM under Flash Encryption / PSRAM ECC");
|
||||
} else {
|
||||
printf("Testing LP-AHB-GDMA memory copy SRAM->PSRAM->SRAM\n");
|
||||
TEST_ESP_OK(gdma_new_lp_ahb_channel(&chan_alloc_config, &tx_chan, &rx_chan));
|
||||
|
||||
@@ -370,7 +370,7 @@ static esp_err_t i3c_master_init_dma(i3c_master_bus_t *i3c_master_handle, const
|
||||
|
||||
// create DMA link list
|
||||
size_t int_mem_align = 0;
|
||||
gdma_get_alignment_constraints(i3c_master_handle->dma_tx_chan, &int_mem_align, NULL);
|
||||
gdma_get_channel_alignment_constraints(i3c_master_handle->dma_tx_chan, &int_mem_align, NULL, NULL);
|
||||
i3c_master_handle->dma_buffer_alignment = I3C_ALIGN_UP(int_mem_align, I3C_MASTER_DMA_INTERFACE_ALIGNMENT);
|
||||
size_t num_dma_nodes = esp_dma_calculate_node_count(dma_config->max_transfer_size, i3c_master_handle->dma_buffer_alignment, DMA_DESCRIPTOR_BUFFER_MAX_SIZE);
|
||||
gdma_link_list_config_t dma_link_config = {
|
||||
@@ -581,6 +581,7 @@ static esp_err_t do_dma_transaction_handler(i3c_master_bus_handle_t bus_handle,
|
||||
.flags = {
|
||||
.mark_eof = true,
|
||||
.mark_final = GDMA_FINAL_LINK_TO_NULL,
|
||||
.check_size_align = gdma_is_size_alignment_required(bus_handle->dma_rx_chan),
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#include "jpeg_private.h"
|
||||
#include "hal/jpeg_hal.h"
|
||||
#include "esp_memory_utils.h"
|
||||
#include "driver/jpeg_types.h"
|
||||
#include "sys/lock.h"
|
||||
#include "sys/queue.h"
|
||||
@@ -23,7 +22,6 @@
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
#include "hal/jpeg_periph.h"
|
||||
#include "esp_psram.h"
|
||||
#if JPEG_USE_RETENTION_LINK
|
||||
#include "esp_private/sleep_retention.h"
|
||||
#endif
|
||||
@@ -292,17 +290,3 @@ esp_err_t jpeg_check_intr_priority(jpeg_codec_handle_t jpeg_codec, int intr_prio
|
||||
ESP_RETURN_ON_FALSE(!intr_priority_conflict, ESP_ERR_INVALID_STATE, TAG, "intr_priority conflict, already is %d but attempt to %d", jpeg_codec->intr_priority, intr_priority);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool jpeg_check_dma2d_buffer(const void *buffer)
|
||||
{
|
||||
#if CONFIG_SECURE_FLASH_ENC_ENABLED
|
||||
// jpeg cannot handle encrypted data.
|
||||
if (esp_ptr_external_ram(buffer) && !esp_psram_ptr_is_no_enc(buffer)) {
|
||||
return false;
|
||||
}
|
||||
if (esp_ptr_in_drom(buffer)) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -289,8 +289,10 @@ esp_err_t jpeg_decoder_process(jpeg_decoder_handle_t decoder_engine, const jpeg_
|
||||
"jpeg decode decode_outbuf or out_buffer size is not aligned, please use jpeg_alloc_decoder_mem to malloc your buffer");
|
||||
|
||||
// both the bitstream and output buffer are accessed by the 2D-DMA
|
||||
ESP_RETURN_ON_FALSE(jpeg_check_dma2d_buffer(bit_stream) && jpeg_check_dma2d_buffer(decode_outbuf), ESP_ERR_INVALID_ARG, TAG,
|
||||
"jpeg decode buffer is not 16-byte aligned or not in unencrypted PSRAM, please use jpeg_alloc_decoder_mem to malloc your buffer");
|
||||
size_t bit_stream_alignment = dma2d_get_buffer_alignment_constraint(bit_stream);
|
||||
size_t decode_outbuf_alignment = dma2d_get_buffer_alignment_constraint(decode_outbuf);
|
||||
ESP_RETURN_ON_FALSE(bit_stream_alignment <= 1 && decode_outbuf_alignment <= 1, ESP_ERR_INVALID_ARG, TAG,
|
||||
"jpeg decode buffer doesn't satisfy DMA2D alignment constraints, please use jpeg_alloc_decoder_mem to malloc your buffer");
|
||||
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
|
||||
@@ -177,7 +177,10 @@ esp_err_t jpeg_encoder_process(jpeg_encoder_handle_t encoder_engine, const jpeg_
|
||||
ESP_RETURN_ON_FALSE(out_size, ESP_ERR_INVALID_ARG, TAG, "jpeg encode picture out_size is null");
|
||||
ESP_RETURN_ON_FALSE(((uintptr_t)bit_stream % cache_hal_get_cache_line_size(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_DATA)) == 0, ESP_ERR_INVALID_ARG, TAG, "jpeg encode bit stream is not aligned, please use jpeg_alloc_encoder_mem to malloc your buffer");
|
||||
// both the input picture and output bitstream are accessed by the 2D-DMA
|
||||
ESP_RETURN_ON_FALSE(jpeg_check_dma2d_buffer(encode_inbuf) && jpeg_check_dma2d_buffer(bit_stream), ESP_ERR_INVALID_ARG, TAG, "jpeg encode buffer is not 16-byte aligned or not in unencrypted PSRAM, please use jpeg_alloc_encoder_mem to malloc your buffer");
|
||||
size_t encode_inbuf_alignment = dma2d_get_buffer_alignment_constraint(encode_inbuf);
|
||||
size_t bit_stream_alignment = dma2d_get_buffer_alignment_constraint(bit_stream);
|
||||
ESP_RETURN_ON_FALSE(encode_inbuf_alignment <= 1 && bit_stream_alignment <= 1, ESP_ERR_INVALID_ARG, TAG,
|
||||
"jpeg encode buffer doesn't satisfy DMA2D alignment constraints, please use jpeg_alloc_encoder_mem to malloc your buffer");
|
||||
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
|
||||
@@ -276,18 +276,6 @@ esp_err_t jpeg_isr_deregister(jpeg_codec_handle_t jpeg_codec, jpeg_isr_handler_t
|
||||
*/
|
||||
esp_err_t jpeg_check_intr_priority(jpeg_codec_handle_t jpeg_codec, int intr_priority);
|
||||
|
||||
/**
|
||||
* @brief Validate a user buffer that will be accessed by the 2D-DMA
|
||||
*
|
||||
* The buffer must be 16-byte aligned. When CONFIG_SPIRAM_ENC_EXEMPT is enabled,
|
||||
* a PSRAM buffer must reside in the unencrypted carve-out, since the 2D-DMA
|
||||
* cannot access encrypted PSRAM. Internal RAM buffers are always accepted.
|
||||
*
|
||||
* @param buffer Buffer pointer provided by the user
|
||||
* @return true if the buffer can be used by the 2D-DMA, false otherwise
|
||||
*/
|
||||
bool jpeg_check_dma2d_buffer(const void *buffer);
|
||||
|
||||
/**
|
||||
* @brief Create sleep retention link
|
||||
*
|
||||
|
||||
@@ -145,6 +145,7 @@ size_t parlio_rx_mount_transaction_buffer(parlio_rx_unit_handle_t rx_unit, parli
|
||||
rx_unit->node_num = required_node_num;
|
||||
|
||||
gdma_buffer_mount_config_t mount_config[required_node_num] = {};
|
||||
bool size_alignment_required = gdma_is_size_alignment_required(rx_unit->dma_chan);
|
||||
/* Mount head buffer */
|
||||
if (head_node_num) {
|
||||
mount_config[0].buffer = trans->aligned_payload.buf.head.aligned_buffer;
|
||||
@@ -153,6 +154,7 @@ size_t parlio_rx_mount_transaction_buffer(parlio_rx_unit_handle_t rx_unit, parli
|
||||
mount_config[0].flags.bypass_buffer_align_check = false;
|
||||
mount_config[0].flags.mark_eof = false;
|
||||
mount_config[0].flags.mark_final = GDMA_FINAL_LINK_TO_DEFAULT;
|
||||
mount_config[0].flags.check_size_align = size_alignment_required;
|
||||
}
|
||||
/* Mount body buffer */
|
||||
size_t mount_size = 0;
|
||||
@@ -172,6 +174,7 @@ size_t parlio_rx_mount_transaction_buffer(parlio_rx_unit_handle_t rx_unit, parli
|
||||
mount_config[i].flags.bypass_buffer_align_check = false;
|
||||
mount_config[i].flags.mark_eof = false;
|
||||
mount_config[i].flags.mark_final = GDMA_FINAL_LINK_TO_DEFAULT;
|
||||
mount_config[i].flags.check_size_align = size_alignment_required;
|
||||
offset += mount_size;
|
||||
rest_size -= mount_size;
|
||||
}
|
||||
@@ -181,6 +184,7 @@ size_t parlio_rx_mount_transaction_buffer(parlio_rx_unit_handle_t rx_unit, parli
|
||||
mount_config[required_node_num - 1].buffer_alignment = trans->alignment;
|
||||
mount_config[required_node_num - 1].length = trans->aligned_payload.buf.tail.length;
|
||||
mount_config[required_node_num - 1].flags.bypass_buffer_align_check = false;
|
||||
mount_config[required_node_num - 1].flags.check_size_align = size_alignment_required;
|
||||
}
|
||||
/* For infinite transaction, link the node as a ring */
|
||||
mount_config[required_node_num - 1].flags.mark_final = !trans->flags.infinite ? GDMA_FINAL_LINK_TO_NULL : GDMA_FINAL_LINK_TO_HEAD;
|
||||
@@ -470,7 +474,7 @@ static esp_err_t parlio_rx_unit_init_dma(parlio_rx_unit_handle_t rx_unit, size_t
|
||||
.access_ext_mem = true,
|
||||
};
|
||||
ESP_RETURN_ON_ERROR(gdma_config_transfer(rx_unit->dma_chan, &trans_cfg), TAG, "config DMA transfer failed");
|
||||
ESP_RETURN_ON_ERROR(gdma_get_alignment_constraints(rx_unit->dma_chan, &rx_unit->int_mem_align, &rx_unit->ext_mem_align), TAG, "get alignment constraints failed");
|
||||
ESP_RETURN_ON_ERROR(gdma_get_channel_alignment_constraints(rx_unit->dma_chan, &rx_unit->int_mem_align, &rx_unit->ext_mem_align, NULL), TAG, "get alignment constraints failed");
|
||||
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
|
||||
uint32_t cache_line_size = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA);
|
||||
rx_unit->int_mem_align = rx_unit->int_mem_align > cache_line_size ? rx_unit->int_mem_align : cache_line_size;
|
||||
@@ -982,6 +986,10 @@ esp_err_t parlio_rx_unit_receive(parlio_rx_unit_handle_t rx_unit,
|
||||
ESP_RETURN_ON_FALSE(recv_cfg->delimiter, ESP_ERR_INVALID_ARG, TAG, "no delimiter specified");
|
||||
ESP_RETURN_ON_FALSE(payload_size <= rx_unit->max_recv_size, ESP_ERR_INVALID_ARG, TAG, "trans length too large");
|
||||
size_t alignment = rx_unit->int_mem_align;
|
||||
// partial receive with indirect mount always use internal memory
|
||||
if (!(recv_cfg->flags.partial_rx_en && recv_cfg->flags.indirect_mount)) {
|
||||
alignment = gdma_get_buffer_alignment_constraint(rx_unit->dma_chan, payload);
|
||||
}
|
||||
if (recv_cfg->flags.partial_rx_en) {
|
||||
ESP_RETURN_ON_FALSE(payload_size >= 2 * alignment, ESP_ERR_INVALID_ARG, TAG, "The payload size should greater than %"PRIu32, 2 * alignment);
|
||||
}
|
||||
@@ -1049,6 +1057,10 @@ esp_err_t parlio_rx_unit_receive_from_isr(parlio_rx_unit_handle_t rx_unit,
|
||||
// Can only be called from ISR
|
||||
PARLIO_RX_CHECK_ISR(xPortInIsrContext() == pdTRUE, ESP_ERR_INVALID_STATE);
|
||||
size_t alignment = rx_unit->int_mem_align;
|
||||
// partial receive with indirect mount always use internal memory
|
||||
if (!(recv_cfg->flags.partial_rx_en && recv_cfg->flags.indirect_mount)) {
|
||||
alignment = gdma_get_buffer_alignment_constraint(rx_unit->dma_chan, payload);
|
||||
}
|
||||
if (recv_cfg->flags.partial_rx_en) {
|
||||
PARLIO_RX_CHECK_ISR(payload_size >= 2 * alignment, ESP_ERR_INVALID_ARG);
|
||||
}
|
||||
@@ -1068,6 +1080,7 @@ esp_err_t parlio_rx_unit_receive_from_isr(parlio_rx_unit_handle_t rx_unit,
|
||||
}
|
||||
|
||||
dma_buffer_split_array_t dma_buf_array = {0};
|
||||
/* Create the internal DMA buffer for the infinite transaction if indirect_mount is set */
|
||||
if (recv_cfg->flags.partial_rx_en && recv_cfg->flags.indirect_mount) {
|
||||
/* The internal DMA buffer should be allocated before calling this function */
|
||||
PARLIO_RX_CHECK_ISR(rx_unit->dma_buf, ESP_ERR_INVALID_STATE);
|
||||
@@ -1075,7 +1088,6 @@ esp_err_t parlio_rx_unit_receive_from_isr(parlio_rx_unit_handle_t rx_unit,
|
||||
dma_buf_array.buf.body.recovery_address = rx_unit->dma_buf;
|
||||
dma_buf_array.buf.body.length = payload_size;
|
||||
} else {
|
||||
/* Create the internal DMA buffer for the infinite transaction if indirect_mount is set */
|
||||
esp_err_t esp_ret = esp_dma_split_rx_buffer_to_cache_aligned(payload, payload_size, &dma_buf_array, &rx_unit->stash_buf[rx_unit->stash_buf_idx]);
|
||||
PARLIO_RX_CHECK_ISR(esp_ret == ESP_OK, esp_ret);
|
||||
rx_unit->stash_buf_idx = !rx_unit->stash_buf_idx;
|
||||
|
||||
@@ -163,7 +163,7 @@ static esp_err_t parlio_tx_unit_init_dma(parlio_tx_unit_t *tx_unit, const parlio
|
||||
.access_ext_mem = true, // support transmit PSRAM buffer
|
||||
};
|
||||
ESP_RETURN_ON_ERROR(gdma_config_transfer(tx_unit->dma_chan, &trans_cfg), TAG, "config DMA transfer failed");
|
||||
gdma_get_alignment_constraints(tx_unit->dma_chan, &tx_unit->int_mem_align, &tx_unit->ext_mem_align);
|
||||
gdma_get_channel_alignment_constraints(tx_unit->dma_chan, &tx_unit->int_mem_align, &tx_unit->ext_mem_align, NULL);
|
||||
|
||||
// create DMA link list
|
||||
size_t buffer_alignment = MAX(tx_unit->int_mem_align, tx_unit->ext_mem_align);
|
||||
@@ -463,7 +463,8 @@ esp_err_t parlio_tx_unit_register_event_callbacks(parlio_tx_unit_handle_t tx_uni
|
||||
|
||||
static void parlio_mount_buffer(parlio_tx_unit_t *tx_unit, parlio_tx_trans_desc_t *t)
|
||||
{
|
||||
size_t buffer_alignment = esp_ptr_internal(t->payload) ? tx_unit->int_mem_align : tx_unit->ext_mem_align;
|
||||
size_t buffer_alignment = 0;
|
||||
buffer_alignment = gdma_get_buffer_alignment_constraint(tx_unit->dma_chan, t->payload);
|
||||
// DMA transfer data based on bytes not bits, so convert the bit length to bytes, round up
|
||||
size_t payload_bytes = (t->payload_bits + 7) / 8;
|
||||
gdma_buffer_mount_config_t mount_config = {
|
||||
@@ -701,7 +702,7 @@ esp_err_t parlio_tx_unit_transmit(parlio_tx_unit_handle_t tx_unit, const void *p
|
||||
}
|
||||
#endif // !PARLIO_LL_SUPPORT(TX_EOF_FROM_DMA)
|
||||
|
||||
size_t alignment = esp_ptr_external_ram(payload) ? tx_unit->ext_mem_align : tx_unit->int_mem_align;
|
||||
size_t alignment = gdma_get_buffer_alignment_constraint(tx_unit->dma_chan, payload);
|
||||
// check alignment
|
||||
ESP_RETURN_ON_FALSE(((uint32_t)payload & (alignment - 1)) == 0, ESP_ERR_INVALID_ARG, TAG, "payload address %p not aligned to %d", payload, alignment);
|
||||
ESP_RETURN_ON_FALSE((payload_bits & (alignment - 1)) == 0, ESP_ERR_INVALID_ARG, TAG, "payload size %d not aligned to %d", payload_bits, alignment);
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
#include "hal/color_types.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#include "esp_private/sleep_retention.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
static const char *TAG = "ppa_core";
|
||||
@@ -349,9 +348,6 @@ esp_err_t ppa_register_client(const ppa_client_config_t *config, ppa_client_hand
|
||||
client->oper_type = config->oper_type;
|
||||
client->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
|
||||
client->data_burst_length = config->data_burst_length ? config->data_burst_length : PPA_DATA_BURST_LENGTH_128;
|
||||
if (esp_efuse_is_flash_encryption_enabled() && (client->data_burst_length < SOC_MEMSPI_ENCRYPTION_ALIGNMENT)) {
|
||||
ESP_LOGW(TAG, "flash encryption is enabled, but selected data burst length does not meet encryption alignment restriction if accessing external memory, will be automatically adjusted later on");
|
||||
}
|
||||
|
||||
if (config->oper_type == PPA_OPERATION_SRM) {
|
||||
ppa_engine_config_t engine_config = {
|
||||
@@ -620,28 +616,24 @@ bool ppa_check_buffer_alignment(ppa_client_handle_t ppa_client, const void *pic_
|
||||
}
|
||||
}
|
||||
|
||||
// 2. check with mspi encryption alignment
|
||||
// When flash encryption is enabled, and in/out buffer are in PSRAM (if located in internal RAM, there is no alignment restriction due to encryption):
|
||||
// - The width of the window multiply byte number of one pixel should align to SOC_MEMSPI_ENCRYPTION_ALIGNMENT
|
||||
// - The starting address of every row of the window should align to SOC_MEMSPI_ENCRYPTION_ALIGNMENT
|
||||
// (which also implies the address and size of the in/out buffer will align to SOC_MEMSPI_ENCRYPTION_ALIGNMENT)
|
||||
|
||||
// check pic_width, block_width, block_head
|
||||
// 2. check with DMA2D/MSPI 2D transaction alignment
|
||||
// When MSPI strict alignment is required, and in/out buffer are in PSRAM (if located in internal RAM, there is no alignment restriction):
|
||||
// - The width of the window multiply byte number of one pixel should align to MSPI alignment
|
||||
// - The starting address of every row of the window should align to MSPI alignment
|
||||
// (which also implies the address and size of the in/out buffer will align to MSPI alignment)
|
||||
const void *buffer = (is_input) ? ((ppa_in_pic_blk_config_t *)pic_blk_config)->buffer : ((ppa_out_pic_blk_config_t *)pic_blk_config)->buffer;
|
||||
if (esp_efuse_is_flash_encryption_enabled() && !esp_ptr_internal(buffer)) {
|
||||
size_t dma2d_align = dma2d_get_buffer_alignment_constraint(buffer);
|
||||
if (dma2d_align > 1) {
|
||||
if (ppa_client->engine->type == PPA_ENGINE_TYPE_SRM) {
|
||||
ESP_LOGE(TAG, "SRM processes by macro blocks, where alignment is uncontrollable, makes it unable to work with flash encrypted if buffer is in external memory");
|
||||
ESP_LOGE(TAG, "SRM processes by macro blocks, where alignment is uncontrollable, makes it unable to work with MSPI strict alignment if buffer is in external memory");
|
||||
return false;
|
||||
}
|
||||
uint32_t pic_width = (is_input) ? ((ppa_in_pic_blk_config_t *)pic_blk_config)->pic_w : ((ppa_out_pic_blk_config_t *)pic_blk_config)->pic_w;
|
||||
uint32_t block_offset_x = (is_input) ? ((ppa_in_pic_blk_config_t *)pic_blk_config)->block_offset_x : ((ppa_out_pic_blk_config_t *)pic_blk_config)->block_offset_x;
|
||||
esp_color_fourcc_t color_mode = (is_input) ? ((ppa_in_pic_blk_config_t *)pic_blk_config)->cm : ((ppa_out_pic_blk_config_t *)pic_blk_config)->cm;
|
||||
uint32_t pixel_depth_bytes = color_hal_pixel_format_fourcc_get_bit_depth(color_mode) / 8;
|
||||
|
||||
if (((pic_width * pixel_depth_bytes) & (SOC_MEMSPI_ENCRYPTION_ALIGNMENT - 1)) != 0 ||
|
||||
((block_width * pixel_depth_bytes) & (SOC_MEMSPI_ENCRYPTION_ALIGNMENT - 1)) != 0 ||
|
||||
((block_offset_x * pixel_depth_bytes) & (SOC_MEMSPI_ENCRYPTION_ALIGNMENT - 1)) != 0) {
|
||||
ESP_LOGE(TAG, "(pic_width/block_width/block_offset_x * pixel_depth_bytes) not aligned to SOC_MEMSPI_ENCRYPTION_ALIGNMENT");
|
||||
uint32_t bit_depth = color_hal_pixel_format_fourcc_get_bit_depth(color_mode);
|
||||
if (!dma2d_check_transaction_alignment_constraint(buffer, pic_width, block_width, block_offset_x, bit_depth)) {
|
||||
ESP_LOGE(TAG, "buffer/pic_width/block_width/block_offset_x does not satisfy DMA2D/MSPI alignment (%zu)", dma2d_align);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,8 +230,6 @@ struct rmt_rx_channel_t {
|
||||
void *user_data; // user context
|
||||
rmt_rx_trans_desc_t trans_desc; // transaction description
|
||||
size_t num_dma_nodes; // number of DMA nodes, determined by how big the memory block that user configures
|
||||
size_t dma_int_mem_alignment; // DMA buffer alignment (both in size and address) for internal RX memory
|
||||
size_t dma_ext_mem_alignment; // DMA buffer alignment (both in size and address) for external RX memory
|
||||
gdma_link_list_handle_t dma_link; // DMA link list handle
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -33,6 +33,7 @@ static inline void rmt_rx_mount_dma_buffer(rmt_rx_channel_t *rx_chan, const void
|
||||
.buffer_alignment = mem_alignment,
|
||||
.flags = {
|
||||
.mark_final = GDMA_FINAL_LINK_TO_DEFAULT,
|
||||
.check_size_align = gdma_is_size_alignment_required(rx_chan->base.dma_chan),
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -53,8 +54,6 @@ static esp_err_t rmt_rx_init_dma_link(rmt_rx_channel_t *rx_channel, const rmt_rx
|
||||
.max_data_burst_size = 32,
|
||||
};
|
||||
ESP_RETURN_ON_ERROR(gdma_config_transfer(rx_channel->base.dma_chan, &transfer_cfg), TAG, "config DMA transfer failed");
|
||||
// get the alignment requirement from DMA
|
||||
gdma_get_alignment_constraints(rx_channel->base.dma_chan, &rx_channel->dma_int_mem_alignment, &rx_channel->dma_ext_mem_alignment);
|
||||
|
||||
// register event callbacks
|
||||
gdma_rx_event_callbacks_t cbs = {
|
||||
@@ -63,7 +62,10 @@ static esp_err_t rmt_rx_init_dma_link(rmt_rx_channel_t *rx_channel, const rmt_rx
|
||||
// register the DMA callbacks may fail if the interrupt service can not be installed successfully
|
||||
ESP_RETURN_ON_ERROR(gdma_register_rx_event_callbacks(rx_channel->base.dma_chan, &cbs, rx_channel), TAG, "register DMA callbacks failed");
|
||||
|
||||
size_t buffer_alignment = MAX(rx_channel->dma_int_mem_alignment, rx_channel->dma_ext_mem_alignment);
|
||||
// get the alignment requirement from DMA
|
||||
size_t dma_int_mem_alignment = 0, dma_ext_mem_alignment = 0;
|
||||
gdma_get_channel_alignment_constraints(rx_channel->base.dma_chan, &dma_int_mem_alignment, &dma_ext_mem_alignment, NULL);
|
||||
size_t buffer_alignment = MAX(dma_int_mem_alignment, dma_ext_mem_alignment);
|
||||
rx_channel->num_dma_nodes = esp_dma_calculate_node_count(config->mem_block_symbols * sizeof(rmt_symbol_word_t),
|
||||
buffer_alignment, DMA_DESCRIPTOR_BUFFER_MAX_SIZE);
|
||||
rx_channel->num_dma_nodes = MAX(2, rx_channel->num_dma_nodes); // at least 2 DMA nodes for ping-pong
|
||||
@@ -358,14 +360,10 @@ esp_err_t rmt_receive(rmt_channel_handle_t channel, void *buffer, size_t buffer_
|
||||
size_t mem_alignment = sizeof(rmt_symbol_word_t);
|
||||
|
||||
#if SOC_RMT_SUPPORT_DMA
|
||||
uint32_t int_mem_cache_line_size = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA);
|
||||
uint32_t ext_mem_cache_line_size = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_DATA);
|
||||
if (channel->dma_chan) {
|
||||
if (esp_ptr_external_ram(buffer)) {
|
||||
mem_alignment = MAX(MAX(mem_alignment, rx_chan->dma_ext_mem_alignment), ext_mem_cache_line_size);
|
||||
} else {
|
||||
mem_alignment = MAX(MAX(mem_alignment, rx_chan->dma_int_mem_alignment), int_mem_cache_line_size);
|
||||
}
|
||||
size_t dma_alignment = gdma_get_buffer_alignment_constraint(channel->dma_chan, buffer);
|
||||
size_t cache_line_size = esp_cache_get_line_size_by_addr(buffer);
|
||||
mem_alignment = MAX(MAX(mem_alignment, dma_alignment), cache_line_size);
|
||||
}
|
||||
#endif // SOC_RMT_SUPPORT_DMA
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ static esp_err_t rmt_tx_init_dma_link(rmt_tx_channel_t *tx_channel, const rmt_tx
|
||||
|
||||
size_t int_alignment = 0;
|
||||
// get the alignment requirement from DMA
|
||||
gdma_get_alignment_constraints(tx_channel->base.dma_chan, &int_alignment, NULL);
|
||||
gdma_get_channel_alignment_constraints(tx_channel->base.dma_chan, &int_alignment, NULL, NULL);
|
||||
// apply RMT hardware alignment requirement
|
||||
int_alignment = MAX(int_alignment, sizeof(rmt_symbol_word_t));
|
||||
// the memory returned by `heap_caps_aligned_calloc` also meets the cache alignment requirement (both address and size)
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "esp_cache.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_memory_utils.h"
|
||||
#include "esp_macros.h"
|
||||
#include "driver/spi_master.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_private/gpio.h"
|
||||
@@ -22,6 +23,7 @@
|
||||
#include "esp_private/spi_common_internal.h"
|
||||
#include "esp_private/spi_share_hw_ctrl.h"
|
||||
#include "esp_private/esp_cache_private.h"
|
||||
#include "esp_private/esp_mspi_align.h"
|
||||
#include "esp_private/esp_dma_utils.h"
|
||||
#include "esp_private/gdma_link.h"
|
||||
#include "esp_private/sleep_retention.h"
|
||||
@@ -321,8 +323,8 @@ static esp_err_t alloc_dma_chan(spi_host_device_t host_id, spi_dma_chan_t dma_ch
|
||||
ESP_RETURN_ON_ERROR(gdma_config_transfer(dma_ctx->rx_dma_chan, &trans_cfg), SPI_TAG, "config gdma rx transfer failed");
|
||||
|
||||
// Get DMA alignment constraints
|
||||
gdma_get_alignment_constraints(dma_ctx->tx_dma_chan, &dma_ctx->dma_align_tx_int, &dma_ctx->dma_align_tx_ext);
|
||||
gdma_get_alignment_constraints(dma_ctx->rx_dma_chan, &dma_ctx->dma_align_rx_int, &dma_ctx->dma_align_rx_ext);
|
||||
gdma_get_channel_alignment_constraints(dma_ctx->tx_dma_chan, &dma_ctx->dma_align_tx_int, &dma_ctx->dma_align_tx_ext, NULL);
|
||||
gdma_get_channel_alignment_constraints(dma_ctx->rx_dma_chan, &dma_ctx->dma_align_rx_int, &dma_ctx->dma_align_rx_ext, NULL);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -409,12 +411,23 @@ cleanup:
|
||||
|
||||
void SPI_COMMON_ISR_ATTR spicommon_dma_desc_setup_link(const spi_dma_ctx_t *dma_ctx, int offset, const void *data, int len, bool is_rx)
|
||||
{
|
||||
size_t buffer_alignment;
|
||||
if (esp_ptr_internal(data)) {
|
||||
buffer_alignment = is_rx ? dma_ctx->dma_align_rx_int : dma_ctx->dma_align_tx_int;
|
||||
size_t buffer_alignment = 0;
|
||||
#if SOC_GDMA_SUPPORTED
|
||||
gdma_channel_handle_t dma_chan = is_rx ? dma_ctx->rx_dma_chan : dma_ctx->tx_dma_chan;
|
||||
buffer_alignment = gdma_get_buffer_alignment_constraint(dma_chan, data);
|
||||
#else
|
||||
bool is_ptr_ext = esp_ptr_external_ram(data);
|
||||
if (is_rx) {
|
||||
buffer_alignment = is_ptr_ext ? dma_ctx->dma_align_rx_ext : dma_ctx->dma_align_rx_int;
|
||||
} else {
|
||||
buffer_alignment = is_rx ? dma_ctx->dma_align_rx_ext : dma_ctx->dma_align_tx_ext;
|
||||
buffer_alignment = is_ptr_ext ? dma_ctx->dma_align_tx_ext : dma_ctx->dma_align_tx_int;
|
||||
|
||||
}
|
||||
if (is_ptr_ext || esp_ptr_in_drom(data)) {
|
||||
size_t mspi_alignment = esp_mspi_get_alignment(data);
|
||||
buffer_alignment = MAX(buffer_alignment, mspi_alignment);
|
||||
}
|
||||
#endif
|
||||
|
||||
gdma_buffer_mount_config_t mount_config = {
|
||||
.buffer = (void *)data,
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/param.h>
|
||||
#if CONFIG_UHCI_ENABLE_DEBUG_LOG
|
||||
// The local log level must be defined before including esp_log.h
|
||||
// Set the maximum log level for this source file
|
||||
@@ -13,6 +14,7 @@
|
||||
#endif
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_macros.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_macros.h"
|
||||
@@ -26,13 +28,10 @@
|
||||
#include "hal/uhci_hal.h"
|
||||
#include "hal/uhci_ll.h"
|
||||
#include "hal/dma_types.h"
|
||||
#include "hal/cache_hal.h"
|
||||
#include "hal/cache_ll.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#include "esp_private/gdma.h"
|
||||
#include "esp_private/esp_dma_utils.h"
|
||||
#include "esp_private/gdma_link.h"
|
||||
#include "esp_private/esp_cache_private.h"
|
||||
#include "esp_private/esp_psram_mspi.h"
|
||||
#include "uhci_private.h"
|
||||
#include "esp_memory_utils.h"
|
||||
@@ -213,8 +212,9 @@ static esp_err_t uhci_gdma_initialize(uhci_controller_handle_t uhci_ctrl, const
|
||||
gdma_apply_strategy(uhci_ctrl->tx_dir.dma_chan, &strategy_config);
|
||||
|
||||
// create DMA link list
|
||||
gdma_get_alignment_constraints(uhci_ctrl->tx_dir.dma_chan, &uhci_ctrl->tx_dir.int_mem_align, &uhci_ctrl->tx_dir.ext_mem_align);
|
||||
size_t buffer_alignment = UHCI_MAX(uhci_ctrl->tx_dir.int_mem_align, uhci_ctrl->tx_dir.ext_mem_align);
|
||||
size_t tx_dma_int_mem_alignment = 0, tx_dma_ext_mem_alignment = 0;
|
||||
gdma_get_channel_alignment_constraints(uhci_ctrl->tx_dir.dma_chan, &tx_dma_int_mem_alignment, &tx_dma_ext_mem_alignment, NULL);
|
||||
size_t buffer_alignment = MAX(tx_dma_int_mem_alignment, tx_dma_ext_mem_alignment);
|
||||
// Given that the combined size of all buffers does not exceed `max_transmit_size` and
|
||||
// the number of buffers does not exceed `max_transmit_buffer_count`, a single transfer
|
||||
// requires at most `esp_dma_calculate_node_count(max_transmit_size) + max_transmit_buffer_count - 1` DMA descriptors.
|
||||
@@ -237,8 +237,9 @@ static esp_err_t uhci_gdma_initialize(uhci_controller_handle_t uhci_ctrl, const
|
||||
gdma_connect(uhci_ctrl->rx_dir.dma_chan, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_UHCI, 0));
|
||||
ESP_RETURN_ON_ERROR(gdma_config_transfer(uhci_ctrl->rx_dir.dma_chan, &transfer_cfg), TAG, "Config DMA rx channel transfer failed");
|
||||
|
||||
gdma_get_alignment_constraints(uhci_ctrl->rx_dir.dma_chan, &uhci_ctrl->rx_dir.int_mem_align, &uhci_ctrl->rx_dir.ext_mem_align);
|
||||
buffer_alignment = UHCI_MAX(uhci_ctrl->rx_dir.int_mem_align, uhci_ctrl->rx_dir.ext_mem_align);
|
||||
size_t rx_dma_int_mem_alignment = 0, rx_dma_ext_mem_alignment = 0;
|
||||
gdma_get_channel_alignment_constraints(uhci_ctrl->rx_dir.dma_chan, &rx_dma_int_mem_alignment, &rx_dma_ext_mem_alignment, NULL);
|
||||
buffer_alignment = MAX(rx_dma_int_mem_alignment, rx_dma_ext_mem_alignment);
|
||||
uhci_ctrl->rx_dir.rx_num_dma_nodes = esp_dma_calculate_node_count(config->max_receive_internal_mem, buffer_alignment, DMA_DESCRIPTOR_BUFFER_MAX_SIZE);
|
||||
dma_link_config.num_items = uhci_ctrl->rx_dir.rx_num_dma_nodes;
|
||||
ESP_RETURN_ON_ERROR(gdma_new_link_list(&dma_link_config, &uhci_ctrl->rx_dir.dma_link), TAG, "DMA rx link list alloc failed");
|
||||
@@ -284,10 +285,11 @@ static void uhci_do_transmit(uhci_controller_handle_t uhci_ctrl, uhci_transactio
|
||||
uhci_ctrl->tx_dir.cur_trans = trans;
|
||||
size_t buf_count = trans->buf_info_count;
|
||||
gdma_buffer_mount_config_t *mount_configs = uhci_ctrl->tx_dir.mount_configs;
|
||||
size_t buffer_alignment = 0;
|
||||
|
||||
for (size_t i = 0; i < buf_count; i++) {
|
||||
bool is_last = (i == buf_count - 1);
|
||||
size_t buffer_alignment = esp_ptr_internal(trans->buf_info[i].write_buffer) ? uhci_ctrl->tx_dir.int_mem_align : uhci_ctrl->tx_dir.ext_mem_align;
|
||||
buffer_alignment = gdma_get_buffer_alignment_constraint(uhci_ctrl->tx_dir.dma_chan, trans->buf_info[i].write_buffer);
|
||||
mount_configs[i] = (gdma_buffer_mount_config_t) {
|
||||
.buffer = (void *)trans->buf_info[i].write_buffer,
|
||||
.buffer_alignment = buffer_alignment,
|
||||
@@ -324,9 +326,11 @@ static esp_err_t uhci_receive_internal(uhci_controller_handle_t uhci_ctrl, uint8
|
||||
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
const uint32_t mem_cache_line_size = esp_ptr_external_ram(read_buffer) ? uhci_ctrl->ext_mem_cache_line_size : uhci_ctrl->int_mem_cache_line_size;
|
||||
// Must take cache line into consideration for C2M operation.
|
||||
const uint32_t max_alignment_needed = UHCI_MAX(UHCI_MAX(uhci_ctrl->rx_dir.int_mem_align, uhci_ctrl->rx_dir.ext_mem_align), mem_cache_line_size);
|
||||
const uint32_t mem_cache_line_size = esp_cache_get_line_size_by_addr(read_buffer);
|
||||
|
||||
size_t buffer_alignment = gdma_get_buffer_alignment_constraint(uhci_ctrl->rx_dir.dma_chan, read_buffer);
|
||||
const uint32_t max_alignment_needed = MAX(buffer_alignment, mem_cache_line_size);
|
||||
uhci_ctrl->rx_dir.cache_line = mem_cache_line_size;
|
||||
|
||||
// Align the read_buffer pointer to mem_cache_line_size
|
||||
@@ -364,13 +368,15 @@ static esp_err_t uhci_receive_internal(uhci_controller_handle_t uhci_ctrl, uint8
|
||||
ESP_GOTO_ON_FALSE_ISR(uhci_ctrl->rx_dir.buffer_size_per_desc_node[i] != 0 && uhci_ctrl->rx_dir.buffer_size_per_desc_node[i] <= DMA_DESCRIPTOR_BUFFER_MAX_SIZE,
|
||||
ESP_ERR_INVALID_ARG, err, TAG, "buffer_size is too small or too large");
|
||||
|
||||
size_t buffer_alignment = esp_ptr_internal(read_buffer) ? uhci_ctrl->rx_dir.int_mem_align : uhci_ctrl->rx_dir.ext_mem_align;
|
||||
size_t buffer_alignment = 0;
|
||||
buffer_alignment = gdma_get_buffer_alignment_constraint(uhci_ctrl->rx_dir.dma_chan, read_buffer);
|
||||
mount_configs[i] = (gdma_buffer_mount_config_t) {
|
||||
.buffer = read_buffer,
|
||||
.buffer_alignment = buffer_alignment,
|
||||
.length = uhci_ctrl->rx_dir.buffer_size_per_desc_node[i],
|
||||
.flags = {
|
||||
.mark_final = GDMA_FINAL_LINK_TO_DEFAULT,
|
||||
.check_size_align = gdma_is_size_alignment_required(uhci_ctrl->rx_dir.dma_chan),
|
||||
}
|
||||
};
|
||||
ESP_DRAM_LOGD(TAG, "The DMA node %d has %d byte", i, uhci_ctrl->rx_dir.buffer_size_per_desc_node[i]);
|
||||
@@ -382,8 +388,7 @@ static esp_err_t uhci_receive_internal(uhci_controller_handle_t uhci_ctrl, uint8
|
||||
|
||||
// Invalidate cache before DMA starts to ensure no dirty cache lines.
|
||||
// All DMA nodes (mount_configs) share the same contiguous user buffer, so checking mount_configs[0].buffer is sufficient.
|
||||
bool need_cache_sync = esp_ptr_internal(mount_configs[0].buffer) ? (uhci_ctrl->int_mem_cache_line_size > 0) : (uhci_ctrl->ext_mem_cache_line_size > 0);
|
||||
if (need_cache_sync) {
|
||||
if (esp_cache_get_line_size_by_addr(mount_configs[0].buffer) > 0) {
|
||||
ESP_GOTO_ON_ERROR_ISR(esp_cache_msync(mount_configs[0].buffer, usable_size, ESP_CACHE_MSYNC_FLAG_DIR_M2C), err, TAG, "cache sync failed");
|
||||
}
|
||||
}
|
||||
@@ -465,20 +470,7 @@ esp_err_t uhci_multi_buffer_transmit(uhci_controller_handle_t uhci_ctrl, const u
|
||||
|
||||
total_size += write_size;
|
||||
|
||||
size_t alignment = 0;
|
||||
size_t cache_line_size = 0;
|
||||
if (esp_ptr_external_ram(write_buffer)) {
|
||||
alignment = uhci_ctrl->tx_dir.ext_mem_align;
|
||||
cache_line_size = uhci_ctrl->ext_mem_cache_line_size;
|
||||
} else {
|
||||
alignment = uhci_ctrl->tx_dir.int_mem_align;
|
||||
cache_line_size = uhci_ctrl->int_mem_cache_line_size;
|
||||
}
|
||||
|
||||
ESP_RETURN_ON_FALSE(((((uintptr_t)write_buffer) & (alignment - 1)) == 0) && (((write_size) & (alignment - 1)) == 0), ESP_ERR_INVALID_ARG,
|
||||
TAG, "buffer segment %zu address or size are not %zu bytes aligned", i, alignment);
|
||||
|
||||
if (cache_line_size > 0) {
|
||||
if (esp_cache_get_line_size_by_addr(write_buffer) > 0) {
|
||||
// Write back to cache to synchronize the cache before DMA start
|
||||
ESP_RETURN_ON_ERROR(esp_cache_msync((void *)write_buffer, write_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED), TAG, "cache sync failed");
|
||||
}
|
||||
@@ -669,9 +661,6 @@ esp_err_t uhci_new_controller(const uhci_controller_config_t *config, uhci_contr
|
||||
uhci_ll_rx_set_packet_threshold(uhci_ctrl->hal.dev, config->max_packet_receive);
|
||||
}
|
||||
|
||||
esp_cache_get_alignment(MALLOC_CAP_SPIRAM, &uhci_ctrl->ext_mem_cache_line_size);
|
||||
esp_cache_get_alignment(MALLOC_CAP_INTERNAL, &uhci_ctrl->int_mem_cache_line_size);
|
||||
|
||||
ESP_GOTO_ON_ERROR(uhci_gdma_initialize(uhci_ctrl, config), err, TAG, "uhci gdma initialize failed");
|
||||
|
||||
// rx_num_dma_nodes is only known after uhci_gdma_initialize() queried the DMA alignment, so the
|
||||
|
||||
@@ -22,8 +22,6 @@ extern "C" {
|
||||
|
||||
typedef struct uhci_controller_t uhci_controller_t;
|
||||
|
||||
#define UHCI_MAX(a, b) (((a)>(b))?(a):(b))
|
||||
|
||||
#define UHCI_PM_LOCK_NAME_LEN_MAX 16
|
||||
|
||||
#if CONFIG_UHCI_ISR_HANDLER_IN_IRAM
|
||||
@@ -69,8 +67,6 @@ typedef struct {
|
||||
uhci_transaction_desc_t *cur_trans; // pointer to current transaction
|
||||
QueueHandle_t trans_queues[UHCI_TRANS_QUEUE_MAX]; // transaction queue
|
||||
_Atomic uhci_tx_fsm_t tx_fsm; // channel life cycle specific FSM
|
||||
size_t int_mem_align; // Alignment for internal memory
|
||||
size_t ext_mem_align; // Alignment for external memory
|
||||
atomic_int num_trans_inflight; // Indicates the number of transactions that are undergoing but not recycled to ready_queue
|
||||
size_t max_transmit_size; // per-transaction max total size in bytes, from config->max_transmit_size; the DMA node pool is sized for this
|
||||
size_t max_buf_count; // per-transaction max buffer segment count, from config->max_transmit_buffer_count (at least 1)
|
||||
@@ -86,8 +82,6 @@ typedef struct {
|
||||
uint8_t **buffer_pointers; // Pointer for saving buffer pointer
|
||||
_Atomic uhci_rx_fsm_t rx_fsm; // channel life cycle specific FSM
|
||||
size_t cache_line; // cache line size need to be aligned up.
|
||||
size_t int_mem_align; // Alignment for internal memory
|
||||
size_t ext_mem_align; // Alignment for external memory
|
||||
size_t rx_num_dma_nodes; // rx dma number nodes
|
||||
gdma_buffer_mount_config_t *mount_configs; // scratch array (capacity rx_num_dma_nodes) reused by every receive to mount buffer segments; avoids a VLA in ISR context
|
||||
bool continuous; // continuous mode: keep DMA running across EOFs instead of stopping
|
||||
@@ -99,8 +93,6 @@ struct uhci_controller_t {
|
||||
uhci_tx_dir tx_dir; // tx direction structure
|
||||
uhci_rx_dir rx_dir; // rx direction structure
|
||||
void *user_data; // user data
|
||||
size_t int_mem_cache_line_size; // internal memory cache line size
|
||||
size_t ext_mem_cache_line_size; // external memory cache line size
|
||||
#if CONFIG_PM_ENABLE
|
||||
esp_pm_lock_handle_t pm_lock; // power management lock
|
||||
char pm_lock_name[UHCI_PM_LOCK_NAME_LEN_MAX]; // pm lock name
|
||||
|
||||
@@ -16,6 +16,7 @@ set(public_include_dirs "include" "include/soc"
|
||||
"ldo/include" "debug_probe/include" "etm/include"
|
||||
"mspi/mspi_timing_tuning/include" "mspi/mspi_timing_tuning/tuning_scheme_impl/include"
|
||||
"mspi/mspi_intr/include"
|
||||
"mspi/esp_mspi_align/include"
|
||||
"power_supply/include" "modem/include")
|
||||
|
||||
if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/include/soc/${target}")
|
||||
@@ -52,7 +53,8 @@ set(priv_requires efuse # only esp_hw_support/adc_share_hw_ctrl.
|
||||
esp_hal_ana_conv # sleep process requires backup/restore some ADC, TSENS registers
|
||||
)
|
||||
|
||||
set(srcs "cpu.c" "port/${IDF_TARGET}/esp_cpu_intr.c" "esp_memory_utils.c" "port/${IDF_TARGET}/cpu_region_protect.c")
|
||||
set(srcs "cpu.c" "port/${IDF_TARGET}/esp_cpu_intr.c" "esp_memory_utils.c" "port/${IDF_TARGET}/cpu_region_protect.c"
|
||||
"mspi/esp_mspi_align/esp_mspi_align.c")
|
||||
if(NOT non_os_build)
|
||||
list(APPEND srcs "esp_clk.c"
|
||||
"clk_ctrl_os.c"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2019-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "hal/gdma_ll.h"
|
||||
#include "hal/efuse_hal.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_private/esp_mspi_align.h"
|
||||
#endif
|
||||
|
||||
#if CONFIG_HEAP_PLACE_FUNCTION_INTO_FLASH
|
||||
@@ -83,8 +84,10 @@ HEAP_IRAM_ATTR void esp_heap_adjust_alignment_to_hw(size_t *p_alignment, size_t
|
||||
#endif
|
||||
|
||||
#if SOC_HAS(GDMA) && (SOC_PSRAM_DMA_CAPABLE || SOC_DMA_CAN_ACCESS_FLASH)
|
||||
if ((caps & MALLOC_CAP_DMA) && esp_efuse_is_flash_encryption_enabled()) {
|
||||
alignment = (alignment > SOC_MEMSPI_ENCRYPTION_ALIGNMENT) ? alignment : SOC_MEMSPI_ENCRYPTION_ALIGNMENT;
|
||||
// CPU access to PSRAM always via cache, so alignment to MSPI alignment is needed when DMA is enabled and PSRAM is enabled.
|
||||
if ((caps & MALLOC_CAP_DMA) && (caps & MALLOC_CAP_SPIRAM)) {
|
||||
size_t mspi_align = esp_mspi_get_alignment(NULL);
|
||||
alignment = (alignment > mspi_align) ? alignment : mspi_align;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/param.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_memory_utils.h"
|
||||
#include "esp_private/esp_mspi_align.h"
|
||||
#if CONFIG_SPIRAM
|
||||
#include "esp_psram.h"
|
||||
#endif /* CONFIG_SPIRAM */
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
#define MSPI_FLASH_ENC_ALIGNMENT SOC_MEMSPI_ENCRYPTION_ALIGNMENT
|
||||
#define MSPI_PSRAM_ECC_ALIGNMENT SOC_MEMSPI_ENCRYPTION_ALIGNMENT
|
||||
|
||||
size_t esp_mspi_get_alignment(const void *ptr)
|
||||
{
|
||||
size_t alignment = 1;
|
||||
bool generic_query = ptr == NULL;
|
||||
bool __attribute__((unused)) is_psram = esp_ptr_external_ram(ptr);
|
||||
bool is_drom = esp_ptr_in_drom(ptr);
|
||||
bool is_psram_enc = false;
|
||||
|
||||
#if CONFIG_SPIRAM
|
||||
is_psram_enc = is_psram && !esp_psram_ptr_is_no_enc(ptr);
|
||||
#endif /* CONFIG_SPIRAM */
|
||||
|
||||
if (esp_efuse_is_flash_encryption_enabled() && (generic_query || is_drom || is_psram_enc)) {
|
||||
alignment = MAX(alignment, MSPI_FLASH_ENC_ALIGNMENT);
|
||||
}
|
||||
|
||||
#if CONFIG_SPIRAM_ECC_ENABLE
|
||||
if (generic_query || is_psram) {
|
||||
alignment = MAX(alignment, MSPI_PSRAM_ECC_ALIGNMENT);
|
||||
}
|
||||
#endif
|
||||
|
||||
return alignment;
|
||||
}
|
||||
|
||||
bool esp_mspi_buffer_alignment_satisfied(const void *ptr, size_t size)
|
||||
{
|
||||
// Zero-length is not a valid MSPI transfer, so it never satisfies the check.
|
||||
if (ptr == NULL || size == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t alignment = esp_mspi_get_alignment(ptr);
|
||||
if (alignment <= 1) {
|
||||
return true;
|
||||
}
|
||||
uintptr_t addr = (uintptr_t)ptr;
|
||||
return ((addr & (alignment - 1)) == 0) && ((size & (alignment - 1)) == 0);
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Get MSPI alignment requirement for an address
|
||||
*
|
||||
* The address is used so future targets can apply different alignment rules to
|
||||
* different MSPI-backed regions. Pass NULL when only the generic external-memory
|
||||
* requirement is needed and no concrete address is available yet.
|
||||
*
|
||||
* @param ptr Buffer pointer in the region to be accessed, or NULL for generic query
|
||||
* @return Required alignment in bytes, or 1 when no extra MSPI alignment is needed
|
||||
*/
|
||||
size_t esp_mspi_get_alignment(const void *ptr);
|
||||
|
||||
/**
|
||||
* @brief Check whether a buffer satisfies MSPI strict alignment requirements
|
||||
*
|
||||
* Returns false when @p ptr is NULL or @p size is 0 (not a valid transfer).
|
||||
* When strict alignment is not required, returns true for any non-empty buffer.
|
||||
* When required, both @p ptr and @p size must be aligned to the rule returned by
|
||||
* @ref esp_mspi_get_alignment for that address.
|
||||
*
|
||||
* @param ptr Buffer pointer
|
||||
* @param size Transfer size in bytes
|
||||
* @return true if alignment requirements are satisfied
|
||||
*/
|
||||
bool esp_mspi_buffer_alignment_satisfied(const void *ptr, size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,3 +1,10 @@
|
||||
[mapping:esp_mspi_align]
|
||||
archive: libesp_hw_support.a
|
||||
entries:
|
||||
if APP_BUILD_TYPE_PURE_RAM_APP = n:
|
||||
esp_mspi_align:esp_mspi_get_alignment (noflash)
|
||||
esp_mspi_align:esp_mspi_buffer_alignment_satisfied (noflash)
|
||||
|
||||
[mapping:mspi_timing_tuning_driver]
|
||||
archive: libesp_hw_support.a
|
||||
entries:
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "esp_memory_utils.h"
|
||||
#include "esp_private/async_memcpy_dma2d.h"
|
||||
#include "esp_private/dw_gdma.h"
|
||||
#include "esp_private/dma2d.h"
|
||||
#include "hal/color_hal.h"
|
||||
|
||||
typedef struct esp_lcd_dpi_panel_t esp_lcd_dpi_panel_t;
|
||||
@@ -223,17 +224,23 @@ esp_err_t esp_lcd_new_panel_dpi(esp_lcd_dsi_bus_handle_t bus, const esp_lcd_dpi_
|
||||
dpi_panel->bus = bus;
|
||||
dpi_panel->num_fbs = num_fbs;
|
||||
|
||||
// Although the DW-GDMA can handle unaligned data, frame buffer still may be the dst of DMA2D operation.
|
||||
// Allocate FB with DMA2D alloc alignment so address is usable as a DMA2D destination when enabled later.
|
||||
// Line-size / window misalignment will fail later in async_color_convert's DMA2D transaction check.
|
||||
size_t dma2d_align = dma2d_get_alloc_alignment();
|
||||
|
||||
// allocate frame buffer from PSRAM
|
||||
size_t fb_size = panel_config->video_timing.h_size * panel_config->video_timing.v_size * bits_per_pixel / 8;
|
||||
for (int i = 0; i < num_fbs; i++) {
|
||||
uint8_t *frame_buffer = heap_caps_calloc(1, fb_size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT | MALLOC_CAP_DMA);
|
||||
uint8_t *frame_buffer = heap_caps_aligned_calloc(dma2d_align, 1, fb_size,
|
||||
MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT | MALLOC_CAP_DMA);
|
||||
ESP_GOTO_ON_FALSE(frame_buffer, ESP_ERR_NO_MEM, err, TAG, "no memory for frame buffer");
|
||||
dpi_panel->fbs[i] = frame_buffer;
|
||||
ESP_LOGD(TAG, "fb[%d] @%p", i, frame_buffer);
|
||||
// preset the frame buffer with black color
|
||||
// the frame buffer address alignment is ensured by `heap_caps_calloc`
|
||||
// the frame buffer address alignment is ensured by `heap_caps_aligned_calloc`
|
||||
// while the value of the fb_size may not be aligned to the cache line size
|
||||
// but that's not a problem because the `heap_caps_calloc` internally allocated a buffer whose size is aligned up to the cache line size
|
||||
// but that's not a problem because the `heap_caps_aligned_calloc` internally allocated a buffer whose size is aligned up to the cache line size
|
||||
ESP_GOTO_ON_ERROR(esp_cache_msync(frame_buffer, fb_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED),
|
||||
err, TAG, "cache write back failed");
|
||||
}
|
||||
|
||||
@@ -543,11 +543,12 @@ static esp_err_t panel_io_i80_tx_param(esp_lcd_panel_io_t *io, int lcd_cmd, cons
|
||||
trans_desc->data = (param && param_len) ? bus->format_buffer : NULL;
|
||||
trans_desc->data_length = trans_desc->data ? param_len : 4;
|
||||
trans_desc->trans_done_cb = NULL; // no callback for parameter transaction
|
||||
size_t buffer_alignment = (trans_desc->data == NULL || esp_ptr_internal(trans_desc->data)) ? bus->int_mem_align : bus->ext_mem_align;
|
||||
static uint32_t fake_trigger = 0;
|
||||
void *mount_buffer = trans_desc->data ? (void *)trans_desc->data : &fake_trigger;
|
||||
size_t buffer_alignment = gdma_get_buffer_alignment_constraint(bus->dma_chan, mount_buffer);
|
||||
// mount data to DMA links
|
||||
gdma_buffer_mount_config_t mount_config = {
|
||||
.buffer = trans_desc->data ? (void *)trans_desc->data : (&fake_trigger),
|
||||
.buffer = mount_buffer,
|
||||
.buffer_alignment = buffer_alignment,
|
||||
.length = trans_desc->data_length,
|
||||
.flags = {
|
||||
@@ -581,15 +582,6 @@ static esp_err_t panel_io_i80_tx_color(esp_lcd_panel_io_t *io, int lcd_cmd, cons
|
||||
lcd_i80_trans_descriptor_t *trans_desc = NULL;
|
||||
ESP_RETURN_ON_FALSE(color_size <= bus->max_transfer_bytes, ESP_ERR_INVALID_ARG, TAG,
|
||||
"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");
|
||||
} 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");
|
||||
}
|
||||
if (esp_cache_get_line_size_by_addr(color) > 0) {
|
||||
// flush data from cache to the physical memory
|
||||
esp_cache_msync((void *)color, color_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED);
|
||||
@@ -705,7 +697,7 @@ static esp_err_t lcd_i80_init_dma_link(esp_lcd_i80_bus_handle_t bus, const esp_l
|
||||
.access_ext_mem = true, // the LCD can carry pixel buffer from the external memory
|
||||
};
|
||||
ESP_RETURN_ON_ERROR(gdma_config_transfer(bus->dma_chan, &trans_cfg), TAG, "config DMA transfer failed");
|
||||
gdma_get_alignment_constraints(bus->dma_chan, &bus->int_mem_align, &bus->ext_mem_align);
|
||||
gdma_get_channel_alignment_constraints(bus->dma_chan, &bus->int_mem_align, &bus->ext_mem_align, NULL);
|
||||
|
||||
size_t buffer_alignment = MAX(bus->int_mem_align, bus->ext_mem_align);
|
||||
size_t num_dma_nodes = esp_dma_calculate_node_count(bus->max_transfer_bytes, buffer_alignment, LCD_DMA_DESCRIPTOR_BUFFER_MAX_SIZE);
|
||||
@@ -902,8 +894,10 @@ IRAM_ATTR static void i80_lcd_default_isr_handler(void *args)
|
||||
bus->cur_trans = trans_desc;
|
||||
bus->cur_device = next_device;
|
||||
// mount data to DMA links
|
||||
size_t buffer_alignment = gdma_get_buffer_alignment_constraint(bus->dma_chan, trans_desc->data);
|
||||
gdma_buffer_mount_config_t mount_config = {
|
||||
.buffer = (void *)trans_desc->data,
|
||||
.buffer_alignment = buffer_alignment,
|
||||
.length = trans_desc->data_length,
|
||||
.flags = {
|
||||
.mark_eof = true,
|
||||
|
||||
@@ -186,10 +186,6 @@ static esp_err_t lcd_rgb_panel_alloc_frame_buffers(esp_rgb_panel_t *rgb_panel, c
|
||||
{
|
||||
bool fb_in_psram = rgb_panel->flags.fb_in_psram;
|
||||
|
||||
// read the cache line size of internal and external memory, we use this information to check if the allocated memory is behind the cache
|
||||
uint32_t int_mem_cache_line_size = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA);
|
||||
uint32_t ext_mem_cache_line_size = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_DATA);
|
||||
|
||||
// alloc frame buffer
|
||||
uint8_t user_fb_count = 0;
|
||||
for (int i = 0; i < rgb_panel->num_fbs; i++) {
|
||||
@@ -200,16 +196,6 @@ static esp_err_t lcd_rgb_panel_alloc_frame_buffers(esp_rgb_panel_t *rgb_panel, c
|
||||
if (!esp_ptr_dma_capable(panel_config->user_fbs[i]) && !esp_ptr_dma_ext_capable(panel_config->user_fbs[i])) {
|
||||
ESP_RETURN_ON_FALSE(false, ESP_ERR_INVALID_ARG, TAG, "frame buffer %d is not DMA accessible", i);
|
||||
}
|
||||
// Check if user frame buffer is in PSRAM or internal memory
|
||||
if (esp_ptr_external_ram(panel_config->user_fbs[i])) {
|
||||
ESP_RETURN_ON_FALSE(((uintptr_t)panel_config->user_fbs[i] & (rgb_panel->ext_mem_align - 1)) == 0,
|
||||
ESP_ERR_INVALID_ARG, TAG, "frame buffer %d is not aligned to "PRIu32"", i, rgb_panel->ext_mem_align);
|
||||
rgb_panel->flags.fb_behind_cache = ext_mem_cache_line_size > 0;
|
||||
} else {
|
||||
ESP_RETURN_ON_FALSE(((uintptr_t)panel_config->user_fbs[i] & (rgb_panel->int_mem_align - 1)) == 0,
|
||||
ESP_ERR_INVALID_ARG, TAG, "frame buffer %d is not aligned to "PRIu32"", i, rgb_panel->int_mem_align);
|
||||
rgb_panel->flags.fb_behind_cache = int_mem_cache_line_size > 0;
|
||||
}
|
||||
rgb_panel->fbs[i] = (uint8_t *)panel_config->user_fbs[i];
|
||||
user_fb_count++;
|
||||
} else {
|
||||
@@ -219,15 +205,14 @@ static esp_err_t lcd_rgb_panel_alloc_frame_buffers(esp_rgb_panel_t *rgb_panel, c
|
||||
rgb_panel->fbs[i] = heap_caps_aligned_calloc(rgb_panel->ext_mem_align, 1, rgb_panel->fb_size,
|
||||
MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA | MALLOC_CAP_8BIT);
|
||||
ESP_RETURN_ON_FALSE(rgb_panel->fbs[i], ESP_ERR_NO_MEM, TAG, "no mem for frame buffer");
|
||||
rgb_panel->flags.fb_behind_cache = ext_mem_cache_line_size > 0;
|
||||
} else {
|
||||
rgb_panel->fbs[i] = heap_caps_aligned_calloc(rgb_panel->int_mem_align, 1, rgb_panel->fb_size,
|
||||
MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA | MALLOC_CAP_8BIT);
|
||||
ESP_RETURN_ON_FALSE(rgb_panel->fbs[i], ESP_ERR_NO_MEM, TAG, "no mem for frame buffer");
|
||||
rgb_panel->flags.fb_behind_cache = int_mem_cache_line_size > 0;
|
||||
}
|
||||
}
|
||||
|
||||
rgb_panel->flags.fb_behind_cache = esp_cache_get_line_size_by_addr(rgb_panel->fbs[i]) > 0;
|
||||
// flush data from cache to the physical memory
|
||||
if (rgb_panel->flags.fb_behind_cache) {
|
||||
ESP_LOGD(TAG, "frame buffer %d at %p is behind the cache", i, rgb_panel->fbs[i]);
|
||||
@@ -246,7 +231,7 @@ static esp_err_t lcd_rgb_panel_alloc_frame_buffers(esp_rgb_panel_t *rgb_panel, c
|
||||
rgb_panel->bounce_buffer[i] = heap_caps_aligned_calloc(rgb_panel->int_mem_align, 1, rgb_panel->bb_size,
|
||||
MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA | MALLOC_CAP_8BIT);
|
||||
ESP_RETURN_ON_FALSE(rgb_panel->bounce_buffer[i], ESP_ERR_NO_MEM, TAG, "no mem for bounce buffer");
|
||||
if (int_mem_cache_line_size > 0) {
|
||||
if (esp_cache_get_line_size_by_addr(rgb_panel->bounce_buffer[i]) > 0) {
|
||||
// flush data from cache to the physical memory
|
||||
esp_cache_msync(rgb_panel->bounce_buffer[i], rgb_panel->bb_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED);
|
||||
rgb_panel->flags.bb_behind_cache = true;
|
||||
@@ -1253,7 +1238,7 @@ static esp_err_t lcd_rgb_create_dma_channel(esp_rgb_panel_t *rgb_panel)
|
||||
};
|
||||
ESP_RETURN_ON_ERROR(gdma_config_transfer(rgb_panel->dma_chan, &trans_cfg), TAG, "config DMA transfer failed");
|
||||
// get the memory alignment required by the DMA
|
||||
gdma_get_alignment_constraints(rgb_panel->dma_chan, &rgb_panel->int_mem_align, &rgb_panel->ext_mem_align);
|
||||
gdma_get_channel_alignment_constraints(rgb_panel->dma_chan, &rgb_panel->int_mem_align, &rgb_panel->ext_mem_align, NULL);
|
||||
|
||||
// register DMA event callbacks
|
||||
gdma_tx_event_callbacks_t cbs = {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -47,15 +47,13 @@ size_t esp_psram_get_size(void);
|
||||
*
|
||||
* When @c CONFIG_SPIRAM_ENC_EXEMPT is enabled, esp_psram reserves a region of PSRAM
|
||||
* that is mapped without encryption and exposed through the @c MALLOC_CAP_SPIRAM_NO_ENC
|
||||
* heap capability. This function lets drivers verify whether a buffer returned by the
|
||||
* heap allocator actually lives in that unencrypted region — useful for example after
|
||||
* a @c heap_caps_malloc_prefer() call that may have fallen back to encrypted PSRAM.
|
||||
* heap capability.
|
||||
*
|
||||
* @param[in] p The pointer to check
|
||||
*
|
||||
* @return
|
||||
* - true: the pointer is within the unencrypted PSRAM carve-out
|
||||
* - false: the pointer is not in the carve-out, PSRAM is not initialized,
|
||||
* - true: The pointer is within the unencrypted PSRAM carve-out
|
||||
* - false: The pointer is not in the carve-out, PSRAM is not initialized,
|
||||
* or @c CONFIG_SPIRAM_ENC_EXEMPT is disabled
|
||||
*/
|
||||
bool esp_psram_ptr_is_no_enc(const void *p);
|
||||
|
||||
@@ -370,6 +370,8 @@ if(CONFIG_SOC_SHA_GDMA OR CONFIG_SOC_AES_GDMA)
|
||||
endif()
|
||||
|
||||
if((SHA_PERIPHERAL_TYPE STREQUAL "core" AND CONFIG_SOC_SHA_SUPPORT_DMA) OR AES_PERIPHERAL_TYPE STREQUAL "dma")
|
||||
target_link_libraries(tfpsacrypto PRIVATE idf::esp_hw_support)
|
||||
target_link_libraries(builtin PRIVATE idf::esp_hw_support)
|
||||
target_link_libraries(tfpsacrypto PRIVATE idf::esp_mm)
|
||||
target_link_libraries(builtin PRIVATE idf::esp_mm)
|
||||
if(CONFIG_SOC_SHA_GDMA OR CONFIG_SOC_AES_GDMA)
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_memory_utils.h"
|
||||
#include "esp_private/esp_mspi_align.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "sdkconfig.h"
|
||||
@@ -246,22 +247,33 @@ static int esp_aes_process_dma_ext_ram(esp_aes_context *ctx, const unsigned char
|
||||
size_t input_alignment = 1;
|
||||
size_t output_alignment = 1;
|
||||
|
||||
/* When AES-DMA operations are carried out using external memory with external memory encryption enabled,
|
||||
we need to make sure that the addresses and the sizes of the buffers on which the DMA operates are 16 byte-aligned.
|
||||
This is only applicable for ESP32-P4, as other targets use internal memory for DMA operations. */
|
||||
#ifdef SOC_MEMSPI_ENCRYPTION_ALIGNMENT
|
||||
/* When AES-DMA operations use external memory under MSPI strict alignment (FE or PSRAM ECC),
|
||||
bounce buffers must be aligned to the MSPI requirement. On ESP32-P4, cache-line alignment
|
||||
may also apply because DMA accesses cached external memory directly. */
|
||||
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
|
||||
if (efuse_hal_flash_encryption_enabled()) {
|
||||
if (esp_ptr_external_ram(input) || esp_ptr_external_ram(output) || esp_ptr_in_drom(input) || esp_ptr_in_drom(output)) {
|
||||
if (esp_ptr_external_ram(input) || esp_ptr_external_ram(output) || esp_ptr_in_drom(input) || esp_ptr_in_drom(output)) {
|
||||
size_t input_mspi_align = esp_mspi_get_alignment(input);
|
||||
size_t output_mspi_align = esp_mspi_get_alignment(output);
|
||||
if (input_mspi_align > 1 || output_mspi_align > 1) {
|
||||
size_t input_cache_line_size = get_cache_line_size(input);
|
||||
size_t output_cache_line_size = get_cache_line_size(output);
|
||||
input_alignment = MAX(input_cache_line_size, SOC_GDMA_EXT_MEM_ENC_ALIGNMENT);
|
||||
output_alignment = MAX(output_cache_line_size, SOC_GDMA_EXT_MEM_ENC_ALIGNMENT);
|
||||
input_alignment = MAX(input_cache_line_size, input_mspi_align);
|
||||
output_alignment = MAX(output_cache_line_size, output_mspi_align);
|
||||
|
||||
input_heap_caps = MALLOC_CAP_8BIT | (esp_ptr_external_ram(input) ? MALLOC_CAP_SPIRAM : MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
|
||||
output_heap_caps = MALLOC_CAP_8BIT | (esp_ptr_external_ram(output) ? MALLOC_CAP_SPIRAM : MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
|
||||
}
|
||||
}
|
||||
#endif /* SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE */
|
||||
#else
|
||||
if (realloc_input && (esp_ptr_external_ram(input) || esp_ptr_in_drom(input))) {
|
||||
input_alignment = esp_mspi_get_alignment(input);
|
||||
}
|
||||
if (realloc_output && (esp_ptr_external_ram(output) || esp_ptr_in_drom(output))) {
|
||||
output_alignment = esp_mspi_get_alignment(output);
|
||||
}
|
||||
#endif
|
||||
#endif /* SOC_MEMSPI_ENCRYPTION_ALIGNMENT */
|
||||
|
||||
if (realloc_input) {
|
||||
input_buf = heap_caps_aligned_alloc(input_alignment, chunk_len, input_heap_caps);
|
||||
@@ -277,7 +289,8 @@ static int esp_aes_process_dma_ext_ram(esp_aes_context *ctx, const unsigned char
|
||||
if (output_buf == NULL) {
|
||||
mbedtls_platform_zeroize(output, len);
|
||||
ESP_LOGE(TAG, "Failed to allocate memory");
|
||||
return -1;
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
} else {
|
||||
output_buf = output;
|
||||
@@ -353,9 +366,9 @@ static inline void dma_desc_append(crypto_dma_desc_t **head, crypto_dma_desc_t *
|
||||
|
||||
#define AES_DMA_ALLOC_CAPS (MALLOC_CAP_DMA | MALLOC_CAP_8BIT)
|
||||
|
||||
static inline void *aes_dma_calloc(size_t num, size_t size, uint32_t caps, size_t *actual_size)
|
||||
static inline void *aes_dma_calloc(size_t alignment, size_t num, size_t size, uint32_t caps, size_t *actual_size)
|
||||
{
|
||||
return heap_caps_aligned_calloc(DMA_DESC_MEM_ALIGN_SIZE, num, size, caps);
|
||||
return heap_caps_aligned_calloc(alignment, num, size, caps);
|
||||
}
|
||||
|
||||
static inline esp_err_t dma_desc_link(crypto_dma_desc_t *dmadesc, size_t crypto_dma_desc_num, size_t buffer_cache_line_size)
|
||||
@@ -424,6 +437,14 @@ static esp_err_t generate_descriptor_list(const uint8_t *buffer, const size_t le
|
||||
uint8_t *end_alignment_stream_buffer = NULL;
|
||||
|
||||
crypto_dma_desc_t *dma_descriptors = NULL;
|
||||
size_t buffer_alignment = DMA_DESC_MEM_ALIGN_SIZE;
|
||||
#ifdef SOC_MEMSPI_ENCRYPTION_ALIGNMENT
|
||||
size_t mspi_alignment = esp_mspi_get_alignment(buffer);
|
||||
buffer_alignment = MAX(buffer_alignment, mspi_alignment);
|
||||
#endif
|
||||
buffer_alignment = MAX(buffer_alignment, cache_line_size);
|
||||
uint32_t alignment_buffer_caps = AES_DMA_ALLOC_CAPS |
|
||||
(esp_ptr_external_ram(buffer) ? MALLOC_CAP_SPIRAM : MALLOC_CAP_INTERNAL);
|
||||
|
||||
if (len == 0) {
|
||||
goto ret;
|
||||
@@ -454,7 +475,8 @@ static esp_err_t generate_descriptor_list(const uint8_t *buffer, const size_t le
|
||||
dma_descs_needed = (unaligned_start_bytes ? 1 : 0) + dma_desc_get_required_num(aligned_block_bytes, max_desc_size) + (unaligned_end_bytes ? 1 : 0);
|
||||
|
||||
/* Allocate memory for DMA descriptors of total size aligned up to a multiple of cache line size */
|
||||
dma_descriptors = (crypto_dma_desc_t *) aes_dma_calloc(dma_descs_needed, sizeof(crypto_dma_desc_t), MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL, NULL);
|
||||
dma_descriptors = (crypto_dma_desc_t *) aes_dma_calloc(DMA_DESC_MEM_ALIGN_SIZE, dma_descs_needed,
|
||||
sizeof(crypto_dma_desc_t), MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL, NULL);
|
||||
if (dma_descriptors == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to allocate memory for the array of DMA descriptors");
|
||||
goto err;
|
||||
@@ -463,7 +485,8 @@ static esp_err_t generate_descriptor_list(const uint8_t *buffer, const size_t le
|
||||
size_t populated_dma_descs = 0;
|
||||
|
||||
if (unaligned_start_bytes) {
|
||||
start_alignment_stream_buffer = aes_dma_calloc(alignment_buffer_size, sizeof(uint8_t), AES_DMA_ALLOC_CAPS | (esp_ptr_external_ram(buffer) ? MALLOC_CAP_SPIRAM : MALLOC_CAP_INTERNAL) , NULL);
|
||||
start_alignment_stream_buffer = aes_dma_calloc(buffer_alignment, alignment_buffer_size,
|
||||
sizeof(uint8_t), alignment_buffer_caps, NULL);
|
||||
if (start_alignment_stream_buffer == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to allocate memory for start alignment buffer");
|
||||
goto err;
|
||||
@@ -485,7 +508,8 @@ static esp_err_t generate_descriptor_list(const uint8_t *buffer, const size_t le
|
||||
}
|
||||
|
||||
if (unaligned_end_bytes) {
|
||||
end_alignment_stream_buffer = aes_dma_calloc(alignment_buffer_size, sizeof(uint8_t), AES_DMA_ALLOC_CAPS | (esp_ptr_external_ram(buffer) ? MALLOC_CAP_SPIRAM : MALLOC_CAP_INTERNAL), NULL);
|
||||
end_alignment_stream_buffer = aes_dma_calloc(buffer_alignment, alignment_buffer_size,
|
||||
sizeof(uint8_t), alignment_buffer_caps, NULL);
|
||||
if (end_alignment_stream_buffer == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to allocate memory for end alignment buffer");
|
||||
goto err;
|
||||
@@ -561,19 +585,17 @@ int esp_aes_process_dma(esp_aes_context *ctx, const unsigned char *input, unsign
|
||||
return MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH;
|
||||
}
|
||||
|
||||
#ifdef SOC_GDMA_EXT_MEM_ENC_ALIGNMENT
|
||||
if (efuse_hal_flash_encryption_enabled()) {
|
||||
if (esp_ptr_external_ram(input) || esp_ptr_external_ram(output) || esp_ptr_in_drom(input) || esp_ptr_in_drom(output)) {
|
||||
if (((intptr_t)(input) & (SOC_GDMA_EXT_MEM_ENC_ALIGNMENT - 1)) != 0) {
|
||||
input_needs_realloc = true;
|
||||
}
|
||||
#ifdef SOC_MEMSPI_ENCRYPTION_ALIGNMENT
|
||||
if (esp_ptr_external_ram(input) || esp_ptr_external_ram(output) || esp_ptr_in_drom(input) || esp_ptr_in_drom(output)) {
|
||||
if (!esp_mspi_buffer_alignment_satisfied(input, block_bytes)) {
|
||||
input_needs_realloc = true;
|
||||
}
|
||||
|
||||
if (((intptr_t)(output) & (SOC_GDMA_EXT_MEM_ENC_ALIGNMENT - 1)) != 0) {
|
||||
output_needs_realloc = true;
|
||||
}
|
||||
if (!esp_mspi_buffer_alignment_satisfied(output, block_bytes)) {
|
||||
output_needs_realloc = true;
|
||||
}
|
||||
}
|
||||
#endif /* SOC_GDMA_EXT_MEM_ENC_ALIGNMENT */
|
||||
#endif /* SOC_MEMSPI_ENCRYPTION_ALIGNMENT */
|
||||
|
||||
/* DMA cannot access memory in the iCache range, copy input to internal ram */
|
||||
if (!s_check_dma_capable(input)) {
|
||||
@@ -828,14 +850,14 @@ int esp_aes_process_dma_gcm(esp_aes_context *ctx, const unsigned char *input, un
|
||||
|
||||
out_desc_tail = &output_desc[output_dma_desc_num - 1];
|
||||
|
||||
len_desc = aes_dma_calloc(1, sizeof(crypto_dma_desc_t), AES_DMA_ALLOC_CAPS, NULL);
|
||||
len_desc = aes_dma_calloc(DMA_DESC_MEM_ALIGN_SIZE, 1, sizeof(crypto_dma_desc_t), AES_DMA_ALLOC_CAPS, NULL);
|
||||
if (len_desc == NULL) {
|
||||
mbedtls_platform_zeroize(output, len);
|
||||
ESP_LOGE(TAG, "Failed to allocate memory for len descriptor");
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32_t *len_buf = aes_dma_calloc(4, sizeof(uint32_t), AES_DMA_ALLOC_CAPS, NULL);
|
||||
uint32_t *len_buf = aes_dma_calloc(DMA_DESC_MEM_ALIGN_SIZE, 4, sizeof(uint32_t), AES_DMA_ALLOC_CAPS, NULL);
|
||||
if (len_buf == NULL) {
|
||||
mbedtls_platform_zeroize(output, len);
|
||||
ESP_LOGE(TAG, "Failed to allocate memory for len buffer");
|
||||
@@ -1055,20 +1077,18 @@ int esp_aes_process_dma(esp_aes_context *ctx, const unsigned char *input, unsign
|
||||
if (block_bytes > 0) {
|
||||
/* Flush cache if input in external ram */
|
||||
#if (CONFIG_SPIRAM && SOC_PSRAM_DMA_CAPABLE)
|
||||
#ifdef SOC_GDMA_EXT_MEM_ENC_ALIGNMENT
|
||||
if (efuse_hal_flash_encryption_enabled()) {
|
||||
if (esp_ptr_external_ram(input) || esp_ptr_in_drom(input)) {
|
||||
if (((intptr_t)(input) & (SOC_GDMA_EXT_MEM_ENC_ALIGNMENT - 1)) != 0) {
|
||||
input_needs_realloc = true;
|
||||
}
|
||||
}
|
||||
if (esp_ptr_external_ram(output) || esp_ptr_in_drom(output)) {
|
||||
if (((intptr_t)(output) & (SOC_GDMA_EXT_MEM_ENC_ALIGNMENT - 1)) != 0) {
|
||||
output_needs_realloc = true;
|
||||
}
|
||||
#ifdef SOC_MEMSPI_ENCRYPTION_ALIGNMENT
|
||||
if (esp_ptr_external_ram(input) || esp_ptr_in_drom(input)) {
|
||||
if (!esp_mspi_buffer_alignment_satisfied(input, block_bytes)) {
|
||||
input_needs_realloc = true;
|
||||
}
|
||||
}
|
||||
#endif /* SOC_GDMA_EXT_MEM_ENC_ALIGNMENT */
|
||||
if (esp_ptr_external_ram(output) || esp_ptr_in_drom(output)) {
|
||||
if (!esp_mspi_buffer_alignment_satisfied(output, block_bytes)) {
|
||||
output_needs_realloc = true;
|
||||
}
|
||||
}
|
||||
#endif /* SOC_MEMSPI_ENCRYPTION_ALIGNMENT */
|
||||
|
||||
if (esp_ptr_external_ram(input)) {
|
||||
if (esp_cache_msync((void *)input, len, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED) != ESP_OK) {
|
||||
|
||||
@@ -44,9 +44,9 @@
|
||||
#include "esp_sha_dma_priv.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#ifdef SOC_GDMA_EXT_MEM_ENC_ALIGNMENT
|
||||
#include "hal/efuse_hal.h"
|
||||
#endif /* SOC_GDMA_EXT_MEM_ENC_ALIGNMENT */
|
||||
#ifdef SOC_MEMSPI_ENCRYPTION_ALIGNMENT
|
||||
#include "esp_private/esp_mspi_align.h"
|
||||
#endif /* SOC_MEMSPI_ENCRYPTION_ALIGNMENT */
|
||||
|
||||
#if SOC_SHA_CRYPTO_DMA
|
||||
#include "hal/crypto_dma_ll.h"
|
||||
@@ -155,7 +155,7 @@ static DRAM_ATTR crypto_dma_desc_t s_dma_descr_buf;
|
||||
static esp_err_t esp_sha_dma_process(esp_sha_type sha_type, const void *input, uint32_t ilen,
|
||||
const void *buf, uint32_t buf_len, bool is_first_block);
|
||||
|
||||
#ifdef SOC_GDMA_EXT_MEM_ENC_ALIGNMENT
|
||||
#ifdef SOC_MEMSPI_ENCRYPTION_ALIGNMENT
|
||||
static esp_err_t esp_sha_dma_process_ext(esp_sha_type sha_type, const void *input, uint32_t ilen,
|
||||
const void *buf, uint32_t buf_len, bool is_first_block,
|
||||
bool realloc_input, bool realloc_buf)
|
||||
@@ -171,7 +171,7 @@ static esp_err_t esp_sha_dma_process_ext(esp_sha_type sha_type, const void *inpu
|
||||
|
||||
if (realloc_input) {
|
||||
heap_caps = MALLOC_CAP_8BIT | (esp_ptr_external_ram(input) ? MALLOC_CAP_SPIRAM : MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
|
||||
input_copy = heap_caps_aligned_alloc(SOC_GDMA_EXT_MEM_ENC_ALIGNMENT, ilen, heap_caps);
|
||||
input_copy = heap_caps_aligned_alloc(esp_mspi_get_alignment(input), ilen, heap_caps);
|
||||
if (input_copy == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to allocate aligned SPIRAM memory");
|
||||
return ret;
|
||||
@@ -184,7 +184,7 @@ static esp_err_t esp_sha_dma_process_ext(esp_sha_type sha_type, const void *inpu
|
||||
|
||||
if (realloc_buf) {
|
||||
heap_caps = MALLOC_CAP_8BIT | (esp_ptr_external_ram(buf) ? MALLOC_CAP_SPIRAM : MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
|
||||
buf_copy = heap_caps_aligned_alloc(SOC_GDMA_EXT_MEM_ENC_ALIGNMENT, buf_len, heap_caps);
|
||||
buf_copy = heap_caps_aligned_alloc(esp_mspi_get_alignment(buf), buf_len, heap_caps);
|
||||
if (buf_copy == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to allocate aligned internal memory");
|
||||
if (input_copy) {
|
||||
@@ -213,7 +213,7 @@ static esp_err_t esp_sha_dma_process_ext(esp_sha_type sha_type, const void *inpu
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* SOC_GDMA_EXT_MEM_ENC_ALIGNMENT */
|
||||
#endif /* SOC_MEMSPI_ENCRYPTION_ALIGNMENT */
|
||||
|
||||
/* Performs SHA on multiple blocks at a time */
|
||||
static esp_err_t esp_sha_dma_process(esp_sha_type sha_type, const void *input, uint32_t ilen,
|
||||
@@ -232,28 +232,27 @@ static esp_err_t esp_sha_dma_process(esp_sha_type sha_type, const void *input, u
|
||||
memset(&s_dma_descr_input, 0, sizeof(crypto_dma_desc_t));
|
||||
memset(&s_dma_descr_buf, 0, sizeof(crypto_dma_desc_t));
|
||||
|
||||
/* When SHA-DMA operations are carried out using external memory with external memory encryption enabled,
|
||||
we need to make sure that the addresses and the sizes of the buffers on which the DMA operates are 16 byte-aligned. */
|
||||
#ifdef SOC_GDMA_EXT_MEM_ENC_ALIGNMENT
|
||||
if (efuse_hal_flash_encryption_enabled()) {
|
||||
if (esp_ptr_external_ram(input) || esp_ptr_external_ram(buf) || esp_ptr_in_drom(input) || esp_ptr_in_drom(buf)) {
|
||||
bool input_needs_realloc = false;
|
||||
bool buf_needs_realloc = false;
|
||||
/* When SHA-DMA operations are carried out using external memory with MSPI strict alignment enabled,
|
||||
we need to make sure that the addresses and the sizes of the buffers on which the DMA operates are aligned. */
|
||||
#ifdef SOC_MEMSPI_ENCRYPTION_ALIGNMENT
|
||||
if (esp_ptr_external_ram(input) || esp_ptr_external_ram(buf) || esp_ptr_in_drom(input) || esp_ptr_in_drom(buf)) {
|
||||
bool input_needs_realloc = false;
|
||||
bool buf_needs_realloc = false;
|
||||
|
||||
if (ilen && ((intptr_t)(input) & (SOC_GDMA_EXT_MEM_ENC_ALIGNMENT - 1)) != 0) {
|
||||
input_needs_realloc = true;
|
||||
}
|
||||
/* Skip when length is zero: buffer is unused and ptr may be NULL. */
|
||||
if (ilen && !esp_mspi_buffer_alignment_satisfied(input, ilen)) {
|
||||
input_needs_realloc = true;
|
||||
}
|
||||
|
||||
if (buf_len && ((intptr_t)(buf) & (SOC_GDMA_EXT_MEM_ENC_ALIGNMENT - 1)) != 0) {
|
||||
buf_needs_realloc = true;
|
||||
}
|
||||
if (buf_len && !esp_mspi_buffer_alignment_satisfied(buf, buf_len)) {
|
||||
buf_needs_realloc = true;
|
||||
}
|
||||
|
||||
if (input_needs_realloc || buf_needs_realloc) {
|
||||
return esp_sha_dma_process_ext(sha_type, input, ilen, buf, buf_len, is_first_block, input_needs_realloc, buf_needs_realloc);
|
||||
}
|
||||
if (input_needs_realloc || buf_needs_realloc) {
|
||||
return esp_sha_dma_process_ext(sha_type, input, ilen, buf, buf_len, is_first_block, input_needs_realloc, buf_needs_realloc);
|
||||
}
|
||||
}
|
||||
#endif /* SOC_GDMA_EXT_MEM_ENC_ALIGNMENT */
|
||||
#endif /* SOC_MEMSPI_ENCRYPTION_ALIGNMENT */
|
||||
|
||||
/* DMA descriptor for Memory to DMA-SHA transfer */
|
||||
if (ilen) {
|
||||
|
||||
@@ -527,10 +527,6 @@ config SOC_GDMA_SUPPORT_WEIGHTED_ARBITRATION
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_GDMA_EXT_MEM_ENC_ALIGNMENT
|
||||
int
|
||||
default 16
|
||||
|
||||
config SOC_GPIO_PORT
|
||||
int
|
||||
default 1
|
||||
|
||||
@@ -201,7 +201,6 @@
|
||||
#define SOC_GDMA_SUPPORT_ETM 1
|
||||
#define SOC_GDMA_SUPPORT_SLEEP_RETENTION 1
|
||||
#define SOC_GDMA_SUPPORT_WEIGHTED_ARBITRATION 1
|
||||
#define SOC_GDMA_EXT_MEM_ENC_ALIGNMENT (16)
|
||||
|
||||
/*-------------------------- GPIO CAPS ---------------------------------------*/
|
||||
// ESP32-C5 has 1 GPIO peripheral
|
||||
|
||||
@@ -399,10 +399,6 @@ config SOC_GDMA_SUPPORT_WEIGHTED_ARBITRATION
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_GDMA_EXT_MEM_ENC_ALIGNMENT
|
||||
int
|
||||
default 16
|
||||
|
||||
config SOC_ETM_SUPPORT_SLEEP_RETENTION
|
||||
bool
|
||||
default y
|
||||
|
||||
@@ -153,7 +153,6 @@
|
||||
#define SOC_GDMA_SUPPORT_ETM 1 // Support ETM submodule
|
||||
#define SOC_GDMA_SUPPORT_SLEEP_RETENTION 1
|
||||
#define SOC_GDMA_SUPPORT_WEIGHTED_ARBITRATION 1
|
||||
#define SOC_GDMA_EXT_MEM_ENC_ALIGNMENT (16)
|
||||
|
||||
/*-------------------------- ETM CAPS -----------------------------------*/
|
||||
#define SOC_ETM_SUPPORT_SLEEP_RETENTION 1
|
||||
|
||||
@@ -643,10 +643,6 @@ config SOC_GDMA_SUPPORT_SLEEP_RETENTION
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_GDMA_EXT_MEM_ENC_ALIGNMENT
|
||||
int
|
||||
default 16
|
||||
|
||||
config SOC_GPIO_PORT
|
||||
int
|
||||
default 1
|
||||
|
||||
@@ -231,7 +231,6 @@
|
||||
#define SOC_GDMA_SUPPORT_CRC 1
|
||||
#define SOC_GDMA_SUPPORT_ETM 1
|
||||
#define SOC_GDMA_SUPPORT_SLEEP_RETENTION 1
|
||||
#define SOC_GDMA_EXT_MEM_ENC_ALIGNMENT (16)
|
||||
|
||||
/*-------------------------- GPIO CAPS ---------------------------------------*/
|
||||
// ESP32-P4 has 1 GPIO peripheral
|
||||
|
||||
@@ -595,10 +595,6 @@ config SOC_GDMA_SUPPORT_SLEEP_RETENTION
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_GDMA_EXT_MEM_ENC_ALIGNMENT
|
||||
int
|
||||
default 16
|
||||
|
||||
config SOC_MODEM_SUPPORT_ETM
|
||||
bool
|
||||
default y
|
||||
|
||||
@@ -204,7 +204,6 @@
|
||||
#define SOC_AHB_GDMA_VERSION 2
|
||||
#define SOC_GDMA_SUPPORT_ETM 1
|
||||
#define SOC_GDMA_SUPPORT_SLEEP_RETENTION 1
|
||||
#define SOC_GDMA_EXT_MEM_ENC_ALIGNMENT (16)
|
||||
|
||||
/*-------------------------- MODEM CAPS --------------------------------------*/
|
||||
#define SOC_MODEM_SUPPORT_ETM 1
|
||||
|
||||
@@ -93,9 +93,12 @@ extern void example_lvgl_demo_ui(lv_display_t *disp);
|
||||
#if CONFIG_EXAMPLE_USE_DMA2D_COPY_FRAME
|
||||
void example_rounder_flush_area_cb(lv_event_t * event)
|
||||
{
|
||||
// Under flash encryption, DMA2D access to PSRAM must satisfy MSPI encryption
|
||||
// alignment (typically 16 bytes) for both the buffer address and transfer size.
|
||||
// Round the LVGL invalidate area so the flush region width meets that requirement.
|
||||
lv_area_t * area = lv_event_get_invalidated_area(event);
|
||||
area->x1 = ESP_ALIGN_DOWN(area->x1, 16);
|
||||
area->x2 = ESP_ALIGN_UP(area->x2, 16) - 1;
|
||||
area->x2 = ESP_ALIGN_UP(area->x2 + 1, 16) - 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -106,7 +109,7 @@ static void example_lvgl_flush_cb(lv_display_t *disp, const lv_area_t *area, uin
|
||||
int offsetx2 = area->x2;
|
||||
int offsety1 = area->y1;
|
||||
int offsety2 = area->y2;
|
||||
// pass the draw buffer to the driver
|
||||
// LVGL area coordinates are inclusive; panel draw_bitmap expects [start, end).
|
||||
esp_lcd_panel_draw_bitmap(panel_handle, offsetx1, offsety1, offsetx2 + 1, offsety2 + 1, px_map);
|
||||
}
|
||||
|
||||
@@ -296,23 +299,14 @@ void app_main(void)
|
||||
void *buf2 = NULL;
|
||||
ESP_LOGI(TAG, "Allocate separate LVGL draw buffers");
|
||||
|
||||
size_t alignment = 1;
|
||||
#if CONFIG_EXAMPLE_USE_DMA2D_COPY_FRAME
|
||||
if (esp_efuse_is_flash_encryption_enabled()) {
|
||||
alignment = SOC_GDMA_EXT_MEM_ENC_ALIGNMENT;
|
||||
if (EXAMPLE_MIPI_DSI_LCD_H_RES % alignment != 0) {
|
||||
ESP_LOGW(TAG, "EXAMPLE_MIPI_DSI_LCD_H_RES is not aligned to %d, may cause MSPI error", alignment);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
size_t draw_buffer_sz = EXAMPLE_MIPI_DSI_LCD_H_RES * EXAMPLE_LVGL_DRAW_BUF_LINES * sizeof(lv_color_t);
|
||||
|
||||
// Note:
|
||||
// Keep the display buffer in **internal** RAM can speed up the UI because LVGL uses it a lot and it should have a fast access time
|
||||
// This example allocate the buffer from PSRAM mainly because we want to save the internal RAM
|
||||
buf1 = heap_caps_aligned_calloc(alignment, 1, draw_buffer_sz, MALLOC_CAP_SPIRAM);
|
||||
buf1 = heap_caps_aligned_calloc(16, 1, draw_buffer_sz, MALLOC_CAP_SPIRAM);
|
||||
assert(buf1);
|
||||
buf2 = heap_caps_aligned_calloc(alignment, 1, draw_buffer_sz, MALLOC_CAP_SPIRAM);
|
||||
buf2 = heap_caps_aligned_calloc(16, 1, draw_buffer_sz, MALLOC_CAP_SPIRAM);
|
||||
assert(buf2);
|
||||
// initialize LVGL draw buffers
|
||||
lv_display_set_buffers(display, buf1, buf2, draw_buffer_sz, LV_DISPLAY_RENDER_MODE_PARTIAL);
|
||||
@@ -320,9 +314,13 @@ void app_main(void)
|
||||
lv_display_set_flush_cb(display, example_lvgl_flush_cb);
|
||||
|
||||
#if CONFIG_EXAMPLE_USE_DMA2D_COPY_FRAME
|
||||
// If flash encryption is enabled, DMA2D requires the flush buffer address and size to be aligned to 16 bytes.
|
||||
// We need to round the flush area to the multiple of 16.
|
||||
if (esp_efuse_is_flash_encryption_enabled()) {
|
||||
// If Flash Encryption/ PSRAM ECC is enabled, DMA2D requires the flush buffer address and size to be aligned.
|
||||
// Round the LVGL invalidate area accordingly (this is an LVGL integration hook, not a panel API).
|
||||
bool need_rounder = esp_efuse_is_flash_encryption_enabled();
|
||||
#if CONFIG_SPIRAM_ECC_ENABLE
|
||||
need_rounder = true;
|
||||
#endif
|
||||
if (need_rounder) {
|
||||
ESP_LOGI(TAG, "Register event callback for LVGL flush area rounding");
|
||||
lv_display_add_event_cb(display, example_rounder_flush_area_cb, LV_EVENT_INVALIDATE_AREA, NULL);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user