Merge branch 'feat/support_lp_dma_on_s31' into 'master'

feat(gdma): support lp ahb dma on esp32s31

Closes IDF-14761

See merge request espressif/esp-idf!45229
This commit is contained in:
morris
2026-01-29 11:43:46 +08:00
18 changed files with 400 additions and 54 deletions

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2020-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -97,6 +97,21 @@ esp_err_t esp_async_memcpy_install_gdma_ahb(const async_memcpy_config_t *config,
esp_err_t esp_async_memcpy_install_gdma_axi(const async_memcpy_config_t *config, async_memcpy_handle_t *mcp);
#endif // SOC_HAS(AXI_GDMA)
#if SOC_HAS(LP_AHB_GDMA)
/**
* @brief Install async memcpy driver, with LP AHB-GDMA as the backend
*
* @param[in] config Configuration of async memcpy
* @param[out] mcp Returned driver handle
* @return
* - ESP_OK: Install async memcpy driver successfully
* - ESP_ERR_INVALID_ARG: Install async memcpy driver failed because of invalid argument
* - ESP_ERR_NO_MEM: Install async memcpy driver failed because out of memory
* - ESP_FAIL: Install async memcpy driver failed because of other error
*/
esp_err_t esp_async_memcpy_install_gdma_lp_ahb(const async_memcpy_config_t *config, async_memcpy_handle_t *mcp);
#endif // SOC_HAS(LP_AHB_GDMA)
#if SOC_CP_DMA_SUPPORTED
/**
* @brief Install async memcpy driver, with CPDMA as the backend

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2020-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -143,6 +143,26 @@ esp_err_t gdma_new_ahb_channel(const gdma_channel_alloc_config_t *config, gdma_c
*/
esp_err_t gdma_new_axi_channel(const gdma_channel_alloc_config_t *config, gdma_channel_handle_t *ret_tx_chan, gdma_channel_handle_t *ret_rx_chan);
/**
* @brief Create LP-AHB-GDMA channel(s)
* @note This API won't install interrupt service for the allocated channel.
* If interrupt service is needed, user has to register GDMA event callback by `gdma_register_tx_event_callbacks` or `gdma_register_rx_event_callbacks`.
* @note To allocate both TX and RX channels in a pair, pass non-NULL pointers for both ret_tx_chan and ret_rx_chan.
* To allocate only one direction, pass NULL for the unwanted direction.
* @note Allocation is atomic: if any channel fails to allocate, all partially allocated resources are cleaned up automatically.
* Either all requested channels are successfully allocated, or the function fails with no channels allocated.
*
* @param[in] config Pointer to a collection of configurations for allocating GDMA channel
* @param[out] ret_tx_chan Returned TX channel handle. Pass NULL if TX channel is not needed. Must not be NULL if ret_rx_chan is also NULL.
* @param[out] ret_rx_chan Returned RX channel handle. Pass NULL if RX channel is not needed. Must not be NULL if ret_tx_chan is also NULL.
* @return
* - ESP_OK: Create DMA channel(s) successfully
* - ESP_ERR_INVALID_ARG: Create DMA channel failed because both ret_tx_chan and ret_rx_chan are NULL
* - ESP_ERR_NO_MEM: Create DMA channel failed because out of memory
* - ESP_FAIL: Create DMA channel failed because of other error
*/
esp_err_t gdma_new_lp_ahb_channel(const gdma_channel_alloc_config_t *config, gdma_channel_handle_t *ret_tx_chan, gdma_channel_handle_t *ret_rx_chan);
/**
* @brief Connect GDMA channel to trigger peripheral
*

View File

@@ -207,6 +207,13 @@ esp_err_t esp_async_memcpy_install_gdma_axi(const async_memcpy_config_t *config,
}
#endif // SOC_HAS(AXI_GDMA)
#if SOC_HAS(LP_AHB_GDMA)
esp_err_t esp_async_memcpy_install_gdma_lp_ahb(const async_memcpy_config_t *config, async_memcpy_handle_t *mcp)
{
return esp_async_memcpy_install_gdma_template(config, mcp, gdma_new_lp_ahb_channel, SOC_GDMA_BUS_LP);
}
#endif // SOC_HAS(LP_AHB_GDMA)
#if SOC_HAS(AHB_GDMA)
/// default installation falls back to use the AHB GDMA
esp_err_t esp_async_memcpy_install(const async_memcpy_config_t *config, async_memcpy_handle_t *asmcp)
@@ -320,6 +327,14 @@ static esp_err_t mcp_gdma_memcpy(async_memcpy_context_t *ctx, void *dst, void *s
dma_link_item_alignment = GDMA_LL_AXI_DESC_ALIGNMENT;
}
#endif // SOC_HAS(AXI_GDMA)
#if SOC_HAS(LP_AHB_GDMA)
if (mcp_gdma->gdma_bus_id == SOC_GDMA_BUS_LP) {
#if !GDMA_LL_GET(LP_AHB_PSRAM_CAPABLE)
ESP_RETURN_ON_FALSE(esp_ptr_internal(src) && esp_ptr_internal(dst), ESP_ERR_INVALID_ARG, TAG, "LP AHB GDMA can only access SRAM");
#endif // !GDMA_LL_GET(LP_AHB_PSRAM_CAPABLE)
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);

View File

@@ -264,6 +264,21 @@ esp_err_t gdma_new_axi_channel(const gdma_channel_alloc_config_t *config, gdma_c
}
#endif // SOC_HAS(AXI_GDMA)
#if SOC_HAS(LP_AHB_GDMA)
esp_err_t gdma_new_lp_ahb_channel(const gdma_channel_alloc_config_t *config, gdma_channel_handle_t *ret_tx_chan, gdma_channel_handle_t *ret_rx_chan)
{
gdma_channel_search_info_t search_info = {
.bus_id = SOC_GDMA_BUS_LP,
.start_group_id = GDMA_LL_LP_AHB_GROUP_START_ID,
.end_group_id = GDMA_LL_LP_AHB_GROUP_START_ID + GDMA_LL_LP_AHB_NUM_GROUPS,
.pairs_per_group = GDMA_LL_LP_AHB_PAIRS_PER_GROUP,
.m2m_capable_mask = GDMA_LL_LP_AHB_M2M_CAPABLE_PAIR_MASK,
.hal_init = gdma_lp_ahb_hal_init,
};
return do_allocate_gdma_channel(&search_info, config, ret_tx_chan, ret_rx_chan);
}
#endif // SOC_HAS(LP_AHB_GDMA)
esp_err_t gdma_del_channel(gdma_channel_handle_t dma_chan)
{
if (!dma_chan) {
@@ -400,7 +415,7 @@ esp_err_t gdma_config_transfer(gdma_channel_handle_t dma_chan, const gdma_transf
// 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)
#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);

View File

@@ -141,6 +141,13 @@ TEST_CASE("memory copy the same buffer with different content", "[async mcp]")
test_memory_copy_with_same_buffer(driver, &config);
TEST_ESP_OK(esp_async_memcpy_uninstall(driver));
#endif // SOC_CP_DMA_SUPPORTED
#if SOC_HAS(LP_AHB_GDMA)
printf("Testing memcpy by LP AHB GDMA\r\n");
TEST_ESP_OK(esp_async_memcpy_install_gdma_lp_ahb(&config, &driver));
test_memory_copy_with_same_buffer(driver, &config);
TEST_ESP_OK(esp_async_memcpy_uninstall(driver));
#endif // SOC_HAS(LP_AHB_GDMA)
}
static bool test_async_memcpy_cb_v1(async_memcpy_handle_t mcp_hdl, async_memcpy_event_t *event, void *cb_args)
@@ -206,6 +213,13 @@ TEST_CASE("memory copy by DMA (blocking)", "[async mcp]")
test_memory_copy_blocking(driver);
TEST_ESP_OK(esp_async_memcpy_uninstall(driver));
#endif // SOC_CP_DMA_SUPPORTED
#if SOC_HAS(LP_AHB_GDMA)
printf("Testing memcpy by LP AHB GDMA\r\n");
TEST_ESP_OK(esp_async_memcpy_install_gdma_lp_ahb(&config, &driver));
test_memory_copy_blocking(driver);
TEST_ESP_OK(esp_async_memcpy_uninstall(driver));
#endif // SOC_HAS(LP_AHB_GDMA)
}
[[maybe_unused]] static void test_memcpy_with_dest_addr_unaligned(async_memcpy_handle_t driver, bool src_in_psram, bool dst_in_psram)
@@ -273,6 +287,16 @@ TEST_CASE("memory copy with dest address unaligned", "[async mcp]")
#endif // GDMA_LL_GET(AXI_PSRAM_CAPABLE) && SOC_HAS(SPIRAM)
TEST_ESP_OK(esp_async_memcpy_uninstall(driver));
#endif // SOC_HAS(AXI_GDMA)
#if SOC_HAS(LP_AHB_GDMA) && !CONFIG_GDMA_ENABLE_WEIGHTED_ARBITRATION
printf("Testing memcpy by LP AHB GDMA\r\n");
TEST_ESP_OK(esp_async_memcpy_install_gdma_lp_ahb(&driver_config, &driver));
test_memcpy_with_dest_addr_unaligned(driver, false, false);
#if GDMA_LL_GET(LP_AHB_PSRAM_CAPABLE) && SOC_HAS(SPIRAM)
test_memcpy_with_dest_addr_unaligned(driver, true, true);
#endif // GDMA_LL_GET(LP_AHB_PSRAM_CAPABLE) && SOC_HAS(SPIRAM)
TEST_ESP_OK(esp_async_memcpy_uninstall(driver));
#endif // SOC_HAS(LP_AHB_GDMA)
}
#define TEST_ASYNC_MEMCPY_BENCH_COUNTS 16
@@ -362,6 +386,13 @@ TEST_CASE("memory copy performance 40KB: SRAM->SRAM", "[async mcp]")
test_memcpy_performance(driver, 40 * 1024, false, false);
TEST_ESP_OK(esp_async_memcpy_uninstall(driver));
#endif // SOC_CP_DMA_SUPPORTED
#if SOC_HAS(LP_AHB_GDMA)
printf("Testing memcpy by LP AHB GDMA\r\n");
TEST_ESP_OK(esp_async_memcpy_install_gdma_lp_ahb(&driver_config, &driver));
test_memcpy_performance(driver, 40 * 1024, false, false);
TEST_ESP_OK(esp_async_memcpy_uninstall(driver));
#endif // SOC_HAS(LP_AHB_GDMA)
}
#if SOC_SPIRAM_SUPPORTED
@@ -390,6 +421,15 @@ TEST_CASE("memory copy performance 40KB: PSRAM->PSRAM", "[async mcp]")
TEST_ESP_OK(esp_async_memcpy_uninstall(driver));
#endif
#endif // SOC_HAS(AXI_GDMA)
#if SOC_HAS(LP_AHB_GDMA)
#if GDMA_LL_GET(LP_AHB_PSRAM_CAPABLE)
printf("Testing memcpy by LP AHB GDMA\r\n");
TEST_ESP_OK(esp_async_memcpy_install_gdma_lp_ahb(&driver_config, &driver));
test_memcpy_performance(driver, 40 * 1024, true, true);
TEST_ESP_OK(esp_async_memcpy_uninstall(driver));
#endif // GDMA_LL_GET(LP_AHB_PSRAM_CAPABLE)
#endif // SOC_HAS(LP_AHB_GDMA)
}
#endif

View File

@@ -147,6 +147,64 @@ TEST_CASE("GDMA channel allocation", "[GDMA]")
TEST_ESP_OK(gdma_del_channel(rx_channels[i]));
}
#endif // GDMA_LL_AXI_PAIRS_PER_GROUP >= 2
#if SOC_HAS(LP_AHB_GDMA)
// install TX channels
for (int i = 0; i < GDMA_LL_LP_AHB_PAIRS_PER_GROUP; i++) {
TEST_ESP_OK(gdma_new_lp_ahb_channel(&channel_config, &tx_channels[i], NULL));
};
TEST_ASSERT_EQUAL(ESP_ERR_NOT_FOUND, gdma_new_lp_ahb_channel(&channel_config, &tx_channels[0], NULL));
// Free interrupts before installing RX interrupts to ensure enough free interrupts
for (int i = 0; i < GDMA_LL_LP_AHB_PAIRS_PER_GROUP; i++) {
TEST_ESP_OK(gdma_del_channel(tx_channels[i]));
}
// install RX channels
for (int i = 0; i < GDMA_LL_LP_AHB_PAIRS_PER_GROUP; i++) {
TEST_ESP_OK(gdma_new_lp_ahb_channel(&channel_config, NULL, &rx_channels[i]));
}
TEST_ASSERT_EQUAL(ESP_ERR_NOT_FOUND, gdma_new_lp_ahb_channel(&channel_config, NULL, &rx_channels[0]));
for (int i = 0; i < GDMA_LL_LP_AHB_PAIRS_PER_GROUP; i++) {
TEST_ESP_OK(gdma_del_channel(rx_channels[i]));
}
#endif // SOC_HAS(LP_AHB_GDMA)
// install single and paired TX/RX channels
#if GDMA_LL_LP_AHB_PAIRS_PER_GROUP >= 2
// single tx channel
TEST_ESP_OK(gdma_new_lp_ahb_channel(&channel_config, &tx_channels[0], NULL));
// create tx and rx channel pair
TEST_ESP_OK(gdma_new_lp_ahb_channel(&channel_config, &tx_channels[1], &rx_channels[1]));
// create single rx channel
TEST_ESP_OK(gdma_new_lp_ahb_channel(&channel_config, NULL, &rx_channels[0]));
gdma_trigger_t fake_lp_ahb_trigger1 = {
.bus_id = SOC_GDMA_BUS_LP,
.instance_id = 0,
};
gdma_trigger_t fake_lp_ahb_trigger2 = {
.bus_id = SOC_GDMA_BUS_LP,
.instance_id = 1,
};
TEST_ESP_OK(gdma_connect(tx_channels[0], fake_lp_ahb_trigger1));
// can't connect multiple channels to the same peripheral
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, gdma_connect(tx_channels[1], fake_lp_ahb_trigger1));
TEST_ESP_OK(gdma_connect(tx_channels[1], fake_lp_ahb_trigger2));
// but rx and tx can connect to the same peripheral
TEST_ESP_OK(gdma_connect(rx_channels[0], fake_lp_ahb_trigger1));
TEST_ESP_OK(gdma_connect(rx_channels[1], fake_lp_ahb_trigger2));
for (int i = 0; i < 2; i++) {
TEST_ESP_OK(gdma_disconnect(tx_channels[i]));
TEST_ESP_OK(gdma_disconnect(rx_channels[i]));
TEST_ESP_OK(gdma_del_channel(tx_channels[i]));
TEST_ESP_OK(gdma_del_channel(rx_channels[i]));
}
#endif // GDMA_LL_LP_AHB_PAIRS_PER_GROUP >= 2
}
static void test_gdma_config_link_list(gdma_channel_handle_t tx_chan, gdma_channel_handle_t rx_chan,
@@ -363,6 +421,15 @@ static void test_gdma_m2m_mode(bool trig_retention_backup)
TEST_ESP_OK(gdma_del_channel(tx_chan));
TEST_ESP_OK(gdma_del_channel(rx_chan));
#endif // SOC_HAS(AXI_GDMA)
#if SOC_HAS(LP_AHB_GDMA)
TEST_ESP_OK(gdma_new_lp_ahb_channel(&chan_alloc_config, &tx_chan, &rx_chan));
test_gdma_m2m_transaction(tx_chan, rx_chan, false, trig_retention_backup);
TEST_ESP_OK(gdma_del_channel(tx_chan));
TEST_ESP_OK(gdma_del_channel(rx_chan));
#endif // SOC_HAS(LP_AHB_GDMA)
}
TEST_CASE("GDMA M2M Mode", "[GDMA][M2M]")
@@ -677,5 +744,15 @@ TEST_CASE("GDMA memory copy SRAM->PSRAM->SRAM", "[GDMA][M2M]")
TEST_ESP_OK(gdma_del_channel(rx_chan));
#endif
#endif // SOC_HAS(AXI_GDMA)
#if SOC_HAS(LP_AHB_GDMA)
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));
test_gdma_memcpy_from_to_psram(tx_chan, rx_chan);
TEST_ESP_OK(gdma_del_channel(tx_chan));
TEST_ESP_OK(gdma_del_channel(rx_chan));
#endif // SOC_HAS(LP_AHB_GDMA)
}
#endif // SOC_SPIRAM_SUPPORTED

View File

@@ -47,6 +47,18 @@ const gdma_signal_conn_t gdma_periph_signals = {
.tx_irq_id = ETS_AXI_PDMA_OUT_CH2_INTR_SOURCE,
}
}
},
[2] = {
.pairs = {
[0] = {
.rx_irq_id = ETS_LP_AHB_PDMA_IN_CH0_INTR_SOURCE,
.tx_irq_id = ETS_LP_AHB_PDMA_OUT_CH0_INTR_SOURCE,
},
[1] = {
.rx_irq_id = ETS_LP_AHB_PDMA_IN_CH1_INTR_SOURCE,
.tx_irq_id = ETS_LP_AHB_PDMA_OUT_CH1_INTR_SOURCE,
}
}
}
}
};

View File

@@ -18,10 +18,11 @@
extern "C" {
#endif
#define AHB_DMA_LL_GET_HW(id) (((id) == 0) ? (&AHB_DMA) : NULL)
#define AHB_DMA_LL_GET_HW(id) (((id) == 0) ? (&AHB_DMA) : (((id) == 2) ? ((ahb_dma_dev_t *)&LP_AHB_DMA) : NULL))
// any "dummy" peripheral ID can be used for M2M mode
#define AHB_DMA_LL_M2M_FREE_PERIPH_ID_MASK (0x8200)
#define LP_AHB_DMA_LL_M2M_FREE_PERIPH_ID_MASK (0xFFFC)
///////////////////////////////////// Common /////////////////////////////////////////
@@ -67,6 +68,17 @@ static inline void ahb_dma_ll_set_default_memory_range(ahb_dma_dev_t *dev)
dev->intr_mem_end_addr.val = 0x53FFFFFF;
}
/**
* @brief Preset valid memory range for LP_AHB-DMA
* @param dev DMA register base address
*/
static inline void lp_ahb_dma_ll_set_default_memory_range(ahb_dma_dev_t *dev)
{
// LP_AHB-DMA can access LPMEM, SRAM, ROM, MSPI Flash, MSPI PSRAM
dev->intr_mem_start_addr.val = 0x2E000000;
dev->intr_mem_end_addr.val = 0x53FFFFFF;
}
///////////////////////////////////// RX /////////////////////////////////////////
/**
* @brief Get DMA RX channel interrupt status word

View File

@@ -9,20 +9,21 @@
#include <stdbool.h>
#include <sys/param.h>
#include "soc/hp_sys_clkrst_struct.h"
#include "soc/lp_peri_clkrst_struct.h"
#include "soc/soc_etm_source.h"
#define GDMA_LL_GET(_attr) GDMA_LL_ ## _attr
#define GDMA_LL_INST_NUM 2
#define GDMA_LL_INST_NUM 3
#define GDMA_LL_PAIRS_PER_INST MAX(GDMA_LL_AHB_PAIRS_PER_GROUP, GDMA_LL_AXI_PAIRS_PER_GROUP)
#define GDMA_LL_PAIRS_PER_INST MAX(MAX(GDMA_LL_AHB_PAIRS_PER_GROUP, GDMA_LL_AXI_PAIRS_PER_GROUP), GDMA_LL_LP_AHB_PAIRS_PER_GROUP)
#define GDMA_LL_CHANNEL_MAX_PRIORITY 5 // supported priority levels: [0,5]
#define GDMA_LL_RX_EVENT_MASK (0x7F)
#define GDMA_LL_TX_EVENT_MASK (0x3F)
// the following event bits are identical for ahb-dma and axi-dma
// the following event bits are identical for ahb-dma, axi-dma and lp-ahb-dma
#define GDMA_LL_EVENT_TX_FIFO_UDF (1<<5)
#define GDMA_LL_EVENT_TX_FIFO_OVF (1<<4)
#define GDMA_LL_EVENT_TX_TOTAL_EOF (1<<3)
@@ -45,8 +46,13 @@
#define GDMA_LL_AXI_NUM_GROUPS 1 // Number of AXI GDMA groups
#define GDMA_LL_AXI_PAIRS_PER_GROUP 3 // Number of GDMA pairs in each AXI group
#define GDMA_LL_LP_AHB_GROUP_START_ID 2 // LP AHB GDMA group ID starts from 2
#define GDMA_LL_LP_AHB_NUM_GROUPS 1 // Number of LP AHB GDMA groups
#define GDMA_LL_LP_AHB_PAIRS_PER_GROUP 2 // Number of GDMA pairs in each LP AHB group
#define GDMA_LL_AHB_PSRAM_CAPABLE 1
#define GDMA_LL_AXI_PSRAM_CAPABLE 1
#define GDMA_LL_LP_AHB_PSRAM_CAPABLE 1
#define GDMA_LL_AHB_BURST_SIZE_ADJUSTABLE 1 // AHB GDMA supports adjustable burst size
#define GDMA_LL_AHB_DESC_ALIGNMENT 4
@@ -56,45 +62,58 @@
#define GDMA_LL_AHB_M2M_CAPABLE_PAIR_MASK 0x1F // pair 0,1,2,3,4 are M2M capable
#define GDMA_LL_AXI_M2M_CAPABLE_PAIR_MASK 0x07 // pair 0,1,2 are M2M capable
#define GDMA_LL_LP_AHB_M2M_CAPABLE_PAIR_MASK 0x03 // pair 0,1 are M2M capable
#define GDMA_LL_TX_ETM_EVENT_TABLE(group, chan, event) \
(uint32_t[2][GDMA_ETM_EVENT_MAX]){ \
{ \
[GDMA_ETM_EVENT_EOF] = PDMA_AHB_EVT_OUT_EOF_CH0 + (chan), \
}, \
{ \
[GDMA_ETM_EVENT_EOF] = PDMA_AXI_EVT_OUT_EOF_CH0 + (chan), \
}, \
}[group][event]
#define GDMA_LL_RX_ETM_EVENT_TABLE(group, chan, event) \
(uint32_t[2][GDMA_ETM_EVENT_MAX]){ \
#define GDMA_LL_TX_ETM_EVENT_TABLE(group, chan, event) \
(uint32_t[GDMA_LL_INST_NUM][GDMA_ETM_EVENT_MAX]){ \
{ \
[GDMA_ETM_EVENT_EOF] = PDMA_AHB_EVT_IN_SUC_EOF_CH0 + (chan), \
[GDMA_ETM_EVENT_EOF] = PDMA_AHB_EVT_OUT_EOF_CH0 + (chan), \
}, \
{ \
[GDMA_ETM_EVENT_EOF] = PDMA_AXI_EVT_IN_SUC_EOF_CH0 + (chan), \
[GDMA_ETM_EVENT_EOF] = PDMA_AXI_EVT_OUT_EOF_CH0 + (chan), \
}, \
{ \
[GDMA_ETM_EVENT_EOF] = LP_PDMA_AHB_EVT_OUT_EOF_CH0 + (chan), \
}, \
}[group][event]
#define GDMA_LL_TX_ETM_TASK_TABLE(group, chan, task) \
(uint32_t[2][GDMA_ETM_TASK_MAX]){ \
{ \
[GDMA_ETM_TASK_START] = PDMA_AHB_TASK_OUT_START_CH0 + (chan), \
}, \
{ \
[GDMA_ETM_TASK_START] = PDMA_AXI_TASK_OUT_START_CH0 + (chan), \
}, \
#define GDMA_LL_RX_ETM_EVENT_TABLE(group, chan, event) \
(uint32_t[GDMA_LL_INST_NUM][GDMA_ETM_EVENT_MAX]){ \
{ \
[GDMA_ETM_EVENT_EOF] = PDMA_AHB_EVT_IN_SUC_EOF_CH0 + (chan), \
}, \
{ \
[GDMA_ETM_EVENT_EOF] = PDMA_AXI_EVT_IN_SUC_EOF_CH0 + (chan), \
}, \
{ \
[GDMA_ETM_EVENT_EOF] = LP_PDMA_AHB_EVT_IN_SUC_EOF_CH0 + (chan), \
}, \
}[group][event]
#define GDMA_LL_TX_ETM_TASK_TABLE(group, chan, task) \
(uint32_t[GDMA_LL_INST_NUM][GDMA_ETM_TASK_MAX]){ \
{ \
[GDMA_ETM_TASK_START] = PDMA_AHB_TASK_OUT_START_CH0 + (chan), \
}, \
{ \
[GDMA_ETM_TASK_START] = PDMA_AXI_TASK_OUT_START_CH0 + (chan), \
}, \
{ \
[GDMA_ETM_TASK_START] = LP_PDMA_AHB_TASK_OUT_START_CH0 + (chan), \
}, \
}[group][task]
#define GDMA_LL_RX_ETM_TASK_TABLE(group, chan, task) \
(uint32_t[2][GDMA_ETM_TASK_MAX]){ \
{ \
[GDMA_ETM_TASK_START] = PDMA_AHB_TASK_IN_START_CH0 + (chan), \
}, \
{ \
[GDMA_ETM_TASK_START] = PDMA_AXI_TASK_IN_START_CH0 + (chan), \
}, \
#define GDMA_LL_RX_ETM_TASK_TABLE(group, chan, task) \
(uint32_t[GDMA_LL_INST_NUM][GDMA_ETM_TASK_MAX]){ \
{ \
[GDMA_ETM_TASK_START] = PDMA_AHB_TASK_IN_START_CH0 + (chan), \
}, \
{ \
[GDMA_ETM_TASK_START] = PDMA_AXI_TASK_IN_START_CH0 + (chan), \
}, \
{ \
[GDMA_ETM_TASK_START] = LP_PDMA_AHB_TASK_IN_START_CH0 + (chan), \
}, \
}[group][task]
#ifdef __cplusplus
@@ -108,8 +127,10 @@ static inline void gdma_ll_enable_bus_clock(int group_id, bool enable)
{
if (group_id == 0) {
HP_SYS_CLKRST.ahb_pdma_ctrl0.reg_ahb_pdma_sys_clk_en = enable;
} else {
} else if (group_id == 1) {
HP_SYS_CLKRST.axi_pdma_ctrl0.reg_axi_pdma_sys_clk_en = enable;
} else { // group_id == 2, LP AHB GDMA
LP_PERI_CLKRST.ahb_dma_ctrl.lp_ahb_dma_clk_en = enable;
}
}
@@ -121,9 +142,12 @@ static inline void _gdma_ll_reset_register(int group_id)
if (group_id == 0) {
HP_SYS_CLKRST.ahb_pdma_ctrl0.reg_ahb_pdma_rst_en = 1;
HP_SYS_CLKRST.ahb_pdma_ctrl0.reg_ahb_pdma_rst_en = 0;
} else {
} else if (group_id == 1) {
HP_SYS_CLKRST.axi_pdma_ctrl0.reg_axi_pdma_rst_en = 1;
HP_SYS_CLKRST.axi_pdma_ctrl0.reg_axi_pdma_rst_en = 0;
} else {
LP_PERI_CLKRST.ahb_dma_ctrl.lp_ahb_dma_rst_en = 1;
LP_PERI_CLKRST.ahb_dma_ctrl.lp_ahb_dma_rst_en = 0;
}
}

View File

@@ -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
*/
@@ -297,3 +297,43 @@ void gdma_ahb_hal_init(gdma_hal_context_t *hal, const gdma_hal_config_t *config)
#endif // SOC_GDMA_SUPPORT_WEIGHTED_ARBITRATION
ahb_dma_ll_set_default_memory_range(hal->ahb_dma_dev);
}
#if SOC_LP_AHB_GDMA_SUPPORTED
/**
* @brief Private data for LP AHB GDMA HAL
*/
static gdma_hal_priv_data_t gdma_lp_ahb_hal_priv_data = {
.m2m_free_periph_mask = LP_AHB_DMA_LL_M2M_FREE_PERIPH_ID_MASK,
};
void gdma_lp_ahb_hal_init(gdma_hal_context_t *hal, const gdma_hal_config_t *config)
{
// LP AHB DMA uses group_id 2, we pass this directly to the LL layer
hal->ahb_dma_dev = AHB_DMA_LL_GET_HW(config->group_id);
hal->priv_data = &gdma_lp_ahb_hal_priv_data;
// LP AHB GDMA reuses the same HAL functions as HP AHB GDMA
hal->start_with_desc = gdma_ahb_hal_start_with_desc;
hal->stop = gdma_ahb_hal_stop;
hal->append = gdma_ahb_hal_append;
hal->reset = gdma_ahb_hal_reset;
hal->set_priority = gdma_ahb_hal_set_priority;
hal->connect_peri = gdma_ahb_hal_connect_peri;
hal->connect_mem = gdma_ahb_hal_connect_mem;
hal->disconnect_all = gdma_ahb_hal_disconnect_all;
hal->enable_burst = gdma_ahb_hal_enable_burst;
hal->set_strategy = gdma_ahb_hal_set_strategy;
hal->enable_intr = gdma_ahb_hal_enable_intr;
hal->clear_intr = gdma_ahb_hal_clear_intr;
hal->read_intr_status = gdma_ahb_hal_read_intr_status;
hal->get_intr_status_reg = gdma_ahb_hal_get_intr_status_reg;
hal->get_eof_desc_addr = gdma_ahb_hal_get_eof_desc_addr;
#if SOC_GDMA_SUPPORT_ETM
hal->enable_etm_task = gdma_ahb_hal_enable_etm_task;
#endif // SOC_GDMA_SUPPORT_ETM
#if GDMA_LL_GET(AHB_BURST_SIZE_ADJUSTABLE)
hal->set_burst_size = gdma_ahb_hal_set_burst_size;
#endif // GDMA_LL_GET(AHB_BURST_SIZE_ADJUSTABLE)
// LP AHB GDMA has a different memory range
lp_ahb_dma_ll_set_default_memory_range(hal->ahb_dma_dev);
}
#endif // SOC_LP_AHB_GDMA_SUPPORTED

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2020-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -46,6 +46,8 @@ uint32_t gdma_ahb_hal_get_eof_desc_addr(gdma_hal_context_t *hal, int chan_id, gd
void gdma_ahb_hal_init(gdma_hal_context_t *hal, const gdma_hal_config_t *config);
void gdma_lp_ahb_hal_init(gdma_hal_context_t *hal, const gdma_hal_config_t *config);
#ifdef __cplusplus
}
#endif

View File

@@ -23,6 +23,10 @@ config SOC_AXI_GDMA_SUPPORTED
bool
default y
config SOC_LP_AHB_GDMA_SUPPORTED
bool
default y
config SOC_GPTIMER_SUPPORTED
bool
default y

View File

@@ -31,6 +31,7 @@
// #define SOC_UHCI_SUPPORTED 1 // TODO: [ESP32S31] IDF-14791
#define SOC_AHB_GDMA_SUPPORTED 1
#define SOC_AXI_GDMA_SUPPORTED 1
#define SOC_LP_AHB_GDMA_SUPPORTED 1
// #define SOC_DMA2D_SUPPORTED 1 // TODO: [ESP32S31] IDF-14762
#define SOC_GPTIMER_SUPPORTED 1
// #define SOC_PCNT_SUPPORTED 1 // TODO: [ESP32S31] IDF-14699

View File

@@ -88,7 +88,7 @@ PROVIDE ( TOUCH_AON = 0x20705000 );
PROVIDE ( LP_PERI_PMS = 0x20706000 );
PROVIDE ( LP_TEE = 0x20706800 );
PROVIDE ( LP_APM = 0x20706C00 );
PROVIDE ( LP_PERICLKRST = 0x20710000 );
PROVIDE ( LP_PERI_CLKRST = 0x20710000 );
PROVIDE ( LP_IO_MUX = 0x20712000 );
PROVIDE ( LP_GPIO = 0x20713000 );
PROVIDE ( LP_INTR = 0x20714000 );
@@ -108,7 +108,7 @@ PROVIDE ( ADC = 0x20815000 );
PROVIDE ( TOUCH_SENS = 0x20816000 );
PROVIDE ( LP_MAILBOX = 0x20817000 );
PROVIDE ( TSENS = 0x20818000 );
PROVIDE ( LP_AHB_PDMA = 0x20819000 );
PROVIDE ( LP_AHB_DMA = 0x20819000 );
PROVIDE ( LP_DAC = 0x2081A000 );
PROVIDE ( CACHE = 0x2C000000 );
PROVIDE ( TRACE0 = 0x2D000000 );

View File

@@ -835,31 +835,31 @@ typedef union {
*/
typedef union {
struct {
/** ahb_apb_sync_clk_en : R/W; bitpos: [4:0]; default: 31;
/** HP-AHB-DMA layout: ahb_apb_sync_clk_en : R/W; bitpos: [4:0]; default: 31;
* Configures whether to force on ahb_apb_sync 4~0 module clock. For bit n:
* 0 : Not force on ahb_apb_sync n clock
* 1 : Force on ahb_apb_sync n clock
*/
uint32_t ahb_apb_sync_clk_en:5;
/** out_dscr_clk_en : R/W; bitpos: [9:5]; default: 31;
/** HP-AHB-DMA layout: out_dscr_clk_en : R/W; bitpos: [9:5]; default: 31;
* Configures whether to force on out_dscr 4~0 module clock. For bit n:
* 0 : Not force on out_dscr n clock
* 1 : Force on out_dscr n clock
*/
uint32_t out_dscr_clk_en:5;
/** out_ctrl_clk_en : R/W; bitpos: [14:10]; default: 31;
/** HP-AHB-DMA layout: out_ctrl_clk_en : R/W; bitpos: [14:10]; default: 31;
* Configures whether to force on out_ctrl 4~0 module clock. For bit n:
* 0 : Not force on out_ctrl n clock
* 1 : Force on out_ctrl n clock
*/
uint32_t out_ctrl_clk_en:5;
/** in_dscr_clk_en : R/W; bitpos: [19:15]; default: 31;
/** HP-AHB-DMA layout: in_dscr_clk_en : R/W; bitpos: [19:15]; default: 31;
* Configures whether to force on in_dscr 4~0 module clock. For bit n:
* 0 : Not force on in_dscr n clock
* 1 : Force on in_dscr n clock
*/
uint32_t in_dscr_clk_en:5;
/** in_ctrl_clk_en : R/W; bitpos: [24:20]; default: 31;
/** HP-AHB-DMA layout: in_ctrl_clk_en : R/W; bitpos: [24:20]; default: 31;
* Configures whether to force on in_ctrl 4~0 module clock. For bit n:
* 0 : Not force on in_ctrl n clock
* 1 : Force on in_ctrl n clock
@@ -879,7 +879,57 @@ typedef union {
*/
uint32_t ahbinf_clk_en:1;
uint32_t reserved_29:3;
};
} hp;
struct {
/** LP-AHB-DMA layout: ahb_apb_sync_clk_en : R/W; bitpos: [1:0]; default: 3;
* Configures whether to force on ahb_apb_sync 1~0 module clock. For bit n:
* 0 : Not force on ahb_apb_sync n clock
* 1 : Force on ahb_apb_sync n clock
*/
uint32_t ahb_apb_sync_clk_en:2;
uint32_t reserved_2:3;
/** LP-AHB-DMA layout: out_dscr_clk_en : R/W; bitpos: [6:5]; default: 3;
* Configures whether to force on out_dscr 1~0 module clock. For bit n:
* 0 : Not force on out_dscr n clock
* 1 : Force on out_dscr n clock
*/
uint32_t out_dscr_clk_en:2;
uint32_t reserved_7:3;
/** LP-AHB-DMA layout: out_ctrl_clk_en : R/W; bitpos: [11:10]; default: 3;
* Configures whether to force on out_ctrl 1~0 module clock. For bit n:
* 0 : Not force on out_ctrl n clock
* 1 : Force on out_ctrl n clock
*/
uint32_t out_ctrl_clk_en:2;
uint32_t reserved_12:3;
/** LP-AHB-DMA layout: in_dscr_clk_en : R/W; bitpos: [16:15]; default: 3;
* Configures whether to force on in_dscr 1~0 module clock. For bit n:
* 0 : Not force on in_dscr n clock
* 1 : Force on in_dscr n clock
*/
uint32_t in_dscr_clk_en:2;
uint32_t reserved_17:3;
/** LP-AHB-DMA layout: in_ctrl_clk_en : R/W; bitpos: [21:20]; default: 3;
* Configures whether to force on in_ctrl 1~0 module clock. For bit n:
* 0 : Not force on in_ctrl n clock
* 1 : Force on in_ctrl n clock
*/
uint32_t in_ctrl_clk_en:2;
uint32_t reserved_22:5;
/** cmd_arb_clk_en : R/W; bitpos: [27]; default: 1;
* Configures whether to force on cmd_arb module clock.
* 0 : Not force on cmd_arb clock
* 1 : Force on cmd_arb clock
*/
uint32_t cmd_arb_clk_en:1;
/** ahbinf_clk_en : R/W; bitpos: [28]; default: 1;
* Configures whether to force on ahbinf module clock.
* 0 : Not force on ahbinf clock
* 1 : Force on ahbinf clock
*/
uint32_t ahbinf_clk_en:1;
uint32_t reserved_29:3;
} lp;
uint32_t val;
} ahb_dma_module_clk_en_reg_t;
@@ -1226,17 +1276,33 @@ typedef union {
* Represents the AHB response error is write request.
*/
uint32_t ahbinf_resp_err_wr:1;
/** ahbinf_resp_err_id : RO; bitpos: [5:1]; default: 31;
/** HP-AHB-DMA layout: ahbinf_resp_err_id : RO; bitpos: [5:1]; default: 31;
* Represents the AHB response error request id.
*/
uint32_t ahbinf_resp_err_id:5;
/** ahbinf_resp_err_ch_id : RO; bitpos: [9:6]; default: 0;
/** HP-AHB-DMA layout: ahbinf_resp_err_ch_id : RO; bitpos: [9:6]; default: 0;
* Represents the AHB response error request channel id.bit[3]=1:TX channel.
* bit[3]=0:RX channel.
*/
uint32_t ahbinf_resp_err_ch_id:4;
uint32_t reserved_10:22;
};
} hp;
struct {
/** ahbinf_resp_err_wr : RO; bitpos: [0]; default: 0;
* Represents the AHB response error is write request.
*/
uint32_t ahbinf_resp_err_wr:1;
/** LP-AHB-DMA layout: ahbinf_resp_err_id : RO; bitpos: [5:1]; default: 31;
* Represents the AHB response error request id.
*/
uint32_t ahbinf_resp_err_id:5;
/** LP-AHB-DMA layout: ahbinf_resp_err_ch_id : RO; bitpos: [7:6]; default: 0;
* Represents the AHB response error request channel id.bit[1]=1:TX channel.
* bit[1]=0:RX channel.
*/
uint32_t ahbinf_resp_err_ch_id:2;
uint32_t reserved_8:24;
} lp;
uint32_t val;
} ahb_dma_ahbinf_resp_err_status1_reg_t;
@@ -1416,6 +1482,7 @@ typedef struct {
} ahb_dma_dev_t;
extern ahb_dma_dev_t AHB_DMA;
extern ahb_dma_dev_t LP_AHB_DMA;
#ifndef __cplusplus
_Static_assert(sizeof(ahb_dma_dev_t) == 0x628, "Invalid size of ahb_dma_dev_t structure");

View File

@@ -1420,6 +1420,7 @@ typedef struct {
volatile ahb_dma_ahbinf_resp_err_status1_reg_t ahbinf_resp_err_status1;
} ahb_dma_dev_t;
// We map the LP_AHB_DMA instance to the ahb_dma_dev_t struct for convenience of using the same HAL/LL. See soc/ahb_dma_struct.h
#ifndef __cplusplus
_Static_assert(sizeof(ahb_dma_dev_t) == 0x628, "Invalid size of ahb_dma_dev_t structure");

View File

@@ -451,11 +451,12 @@ typedef struct {
volatile lp_periclkrst_dm_ctrl_reg_t dm_ctrl;
uint32_t reserved_054[234];
volatile lp_periclkrst_date_reg_t date;
} lp_periclkrst_dev_t;
} lp_peri_clkrst_dev_t;
extern lp_peri_clkrst_dev_t LP_PERI_CLKRST;
#ifndef __cplusplus
_Static_assert(sizeof(lp_periclkrst_dev_t) == 0x400, "Invalid size of lp_periclkrst_dev_t structure");
_Static_assert(sizeof(lp_peri_clkrst_dev_t) == 0x400, "Invalid size of lp_peri_clkrst_dev_t structure");
#endif
#ifdef __cplusplus