Skip to content

Commit

Permalink
Merge branch 'feature/gdma_retention_support_p4_c5_c61' into 'master'
Browse files Browse the repository at this point in the history
feat(gdma): add retention support for esp32p4, esp32c5, esp32c61

Closes IDF-9225, IDF-9929, and IDF-10380

See merge request espressif/esp-idf!33733
  • Loading branch information
songruo committed Sep 24, 2024
2 parents 0a60517 + 6afbc06 commit ec50cb1
Show file tree
Hide file tree
Showing 36 changed files with 624 additions and 128 deletions.
2 changes: 1 addition & 1 deletion components/esp_hw_support/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ if(NOT BOOTLOADER_BUILD)

if(CONFIG_SOC_GDMA_SUPPORTED)
list(APPEND srcs "dma/gdma.c" "deprecated/gdma_legacy.c")
if(CONFIG_SOC_GDMA_SUPPORT_SLEEP_RETENTION)
if(CONFIG_SOC_GDMA_SUPPORT_SLEEP_RETENTION AND CONFIG_SOC_PAU_SUPPORTED)
list(APPEND srcs "dma/gdma_sleep_retention.c")
endif()
if(CONFIG_SOC_GDMA_SUPPORT_ETM)
Expand Down
9 changes: 7 additions & 2 deletions components/esp_hw_support/dma/gdma.c
Original file line number Diff line number Diff line change
Expand Up @@ -255,13 +255,18 @@ esp_err_t gdma_del_channel(gdma_channel_handle_t dma_chan)
return dma_chan->del(dma_chan);
}

esp_err_t gdma_get_channel_id(gdma_channel_handle_t dma_chan, int *channel_id)
esp_err_t gdma_get_group_channel_id(gdma_channel_handle_t dma_chan, int *group_id, int *channel_id)
{
esp_err_t ret = ESP_OK;
gdma_pair_t *pair = NULL;
ESP_GOTO_ON_FALSE(dma_chan, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
pair = dma_chan->pair;
*channel_id = pair->pair_id;
if (group_id != NULL) {
*group_id = pair->group->group_id;
}
if (channel_id != NULL) {
*channel_id = pair->pair_id;
}
err:
return ret;
}
Expand Down
11 changes: 5 additions & 6 deletions components/esp_hw_support/dma/gdma_sleep_retention.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@
#include "esp_private/sleep_retention.h"
#include "esp_private/esp_regdma.h"

#include "hal/gdma_ll.h"

static const char *TAG = "gdma";

typedef struct {
Expand All @@ -36,7 +34,7 @@ static esp_err_t sleep_gdma_channel_retention_init(void *arg)
int group_id = parg->group_id;
int pair_id = parg->pair_id;

sleep_retention_module_bitmap_t module = GDMA_CH_RETENTION_GET_MODULE_ID(group_id, pair_id);
sleep_retention_module_t module = gdma_chx_regs_retention[group_id][pair_id].module_id;
esp_err_t err = sleep_retention_entries_create(gdma_chx_regs_retention[group_id][pair_id].link_list, gdma_chx_regs_retention[group_id][pair_id].link_num, REGDMA_LINK_PRI_GDMA, module);
if (err == ESP_OK) {
ESP_LOGD(TAG, "GDMA pair (%d, %d) retention initialization", group_id, pair_id);
Expand All @@ -53,7 +51,7 @@ esp_err_t gdma_sleep_retention_init(int group_id, int pair_id)
.cbs = { .create = { .handle = sleep_gdma_channel_retention_init, .arg = &arg } },
.depends = BIT(SLEEP_RETENTION_MODULE_CLOCK_SYSTEM)
};
sleep_retention_module_bitmap_t module = GDMA_CH_RETENTION_GET_MODULE_ID(group_id, pair_id);
sleep_retention_module_t module = gdma_chx_regs_retention[group_id][pair_id].module_id;
esp_err_t err = sleep_retention_module_init(module, &init_param);
if (err == ESP_OK) {
err = sleep_retention_module_allocate(module);
Expand All @@ -66,11 +64,12 @@ esp_err_t gdma_sleep_retention_init(int group_id, int pair_id)

esp_err_t gdma_sleep_retention_deinit(int group_id, int pair_id)
{
esp_err_t err = sleep_retention_module_free(GDMA_CH_RETENTION_GET_MODULE_ID(group_id, pair_id));
sleep_retention_module_t module = gdma_chx_regs_retention[group_id][pair_id].module_id;
esp_err_t err = sleep_retention_module_free(module);
if (err != ESP_OK) {
ESP_LOGW(TAG, "GDMA pair (%d, %d) retention destroy failed", group_id, pair_id);
}
err = sleep_retention_module_deinit(GDMA_CH_RETENTION_GET_MODULE_ID(group_id, pair_id));
err = sleep_retention_module_deinit(module);
if (err != ESP_OK) {
ESP_LOGW(TAG, "GDMA pair (%d, %d) retention deinit failed", group_id, pair_id);
}
Expand Down
13 changes: 8 additions & 5 deletions components/esp_hw_support/dma/include/esp_private/gdma.h
Original file line number Diff line number Diff line change
Expand Up @@ -249,19 +249,22 @@ esp_err_t gdma_set_priority(gdma_channel_handle_t dma_chan, uint32_t priority);
esp_err_t gdma_del_channel(gdma_channel_handle_t dma_chan);

/**
* @brief Get the channel ID
* @brief Get the group ID and the channel ID
*
* @note This API breaks the encapsulation of GDMA Channel Object.
* With the returned channel ID, you can even bypass all other GDMA driver API and access Low Level API directly.
* With the returned group/channel ID, you can even bypass all other GDMA driver API and access Low Level API directly.
*
* @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel`
* @param[out] group_id Returned group ID
* @param[out] channel_id Returned channel ID
* @return
* - ESP_OK: Get GDMA channel ID successfully
* - ESP_ERR_INVALID_ARG: Get GDMA channel ID failed because of invalid argument
* - ESP_OK: Get GDMA channel/group ID successfully
* - ESP_ERR_INVALID_ARG: Get GDMA channel/group ID failed because of invalid argument
* - ESP_FAIL: Get GDMA channel ID failed because of other error
*/
esp_err_t gdma_get_channel_id(gdma_channel_handle_t dma_chan, int *channel_id);
esp_err_t gdma_get_group_channel_id(gdma_channel_handle_t dma_chan, int *group_id, int *channel_id);

#define gdma_get_channel_id(dma_chan, channel_id) gdma_get_group_channel_id(dma_chan, NULL, channel_id)

/**
* @brief Set GDMA event callbacks for TX channel
Expand Down
20 changes: 12 additions & 8 deletions components/esp_hw_support/test_apps/dma/main/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,27 @@ if(CONFIG_SOC_ASYNC_MEMCPY_SUPPORTED)
endif()

if(CONFIG_SOC_GDMA_SUPPORTED)
list(APPEND srcs "test_gdma.c")
endif()
list(APPEND srcs "test_gdma.c" "gdma_test_utils.c")

if(CONFIG_SOC_ETM_SUPPORTED AND CONFIG_SOC_GDMA_SUPPORT_ETM)
list(APPEND srcs "test_gdma_etm.c")
endif()

if(CONFIG_SOC_ETM_SUPPORTED AND CONFIG_SOC_GDMA_SUPPORT_ETM)
list(APPEND srcs "test_gdma_etm.c")
if(CONFIG_SOC_GDMA_SUPPORT_CRC)
list(APPEND srcs "test_gdma_crc.c")
endif()
endif()

if(CONFIG_SOC_DW_GDMA_SUPPORTED)
list(APPEND srcs "test_dw_gdma.c")
endif()

if(CONFIG_SOC_GDMA_SUPPORT_CRC)
list(APPEND srcs "test_gdma_crc.c")
endif()

# In order for the cases defined by `TEST_CASE` to be linked into the final elf,
# the component can be registered as WHOLE_ARCHIVE
idf_component_register(SRCS ${srcs}
PRIV_REQUIRES unity esp_mm esp_driver_gpio
WHOLE_ARCHIVE)

idf_component_get_property(lib_name soc COMPONENT_LIB)
# Test GDMA retention correctness with software retention feature
target_compile_definitions(${lib_name} PRIVATE "CI_TEST_SW_RETENTION=1")
36 changes: 36 additions & 0 deletions components/esp_hw_support/test_apps/dma/main/gdma_test_utils.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "soc/soc_caps.h"
#include "gdma_test_utils.h"
#include "esp_private/sleep_retention.h"
#include "hal/gdma_ll.h"

void test_gdma_trigger_retention_backup(gdma_channel_handle_t chan, ...)
{
#if SOC_PAU_SUPPORTED && SOC_GDMA_SUPPORT_SLEEP_RETENTION
// trigger a software retention to test GDMA retention correctnesss
// 1. backup gdma register context
sleep_retention_do_extra_retention(true);

// 2. reset gdma registers to default value
gdma_channel_handle_t chan_itor = chan;
va_list args;
int group_id = -1;
va_start(args, chan);
while (chan_itor) {
gdma_get_group_channel_id(chan_itor, &group_id, NULL);
_gdma_ll_reset_register(group_id);
chan_itor = va_arg(args, gdma_channel_handle_t);
}
va_end(args);

// 3. restore gdma register context
sleep_retention_do_extra_retention(false);
#endif
vTaskDelay(pdMS_TO_TICKS(10));
}
28 changes: 28 additions & 0 deletions components/esp_hw_support/test_apps/dma/main/gdma_test_utils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/

#pragma once

#include <stdbool.h>
#include "esp_private/gdma.h"

#ifdef __cplusplus
extern "C" {
#endif

/**
* @brief Trigger a "fake" sleep retention process.
*
* @note Call this help function after the gdma set up is completed. Then check the gdma functionality is still working.
*
* @param chan GDMA channel handle to be reset
* @param ... Other GDMA channel handle if any
*/
void test_gdma_trigger_retention_backup(gdma_channel_handle_t chan, ...);

#ifdef __cplusplus
}
#endif
22 changes: 18 additions & 4 deletions components/esp_hw_support/test_apps/dma/main/test_gdma.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "hal/cache_hal.h"
#include "esp_cache.h"
#include "esp_memory_utils.h"
#include "gdma_test_utils.h"

#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
#define ALIGN_DOWN(num, align) ((num) & ~((align) - 1))
Expand Down Expand Up @@ -202,7 +203,7 @@ static bool test_gdma_m2m_rx_eof_callback(gdma_channel_handle_t dma_chan, gdma_e
return task_woken == pdTRUE;
}

static void test_gdma_m2m_mode(gdma_channel_handle_t tx_chan, gdma_channel_handle_t rx_chan, bool dma_link_in_ext_mem)
static void test_gdma_m2m_transaction(gdma_channel_handle_t tx_chan, gdma_channel_handle_t rx_chan, bool dma_link_in_ext_mem, bool trig_retention_backup)
{
size_t sram_alignment = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA);
gdma_rx_event_callbacks_t rx_cbs = {
Expand Down Expand Up @@ -280,6 +281,10 @@ static void test_gdma_m2m_mode(gdma_channel_handle_t tx_chan, gdma_channel_handl
};
TEST_ESP_OK(gdma_link_mount_buffers(rx_link_list, 0, &rx_buf_mount_config, 1, NULL));

if (trig_retention_backup) {
test_gdma_trigger_retention_backup(tx_chan, rx_chan);
}

TEST_ESP_OK(gdma_start(rx_chan, gdma_link_get_head_addr(rx_link_list)));
TEST_ESP_OK(gdma_start(tx_chan, gdma_link_get_head_addr(tx_link_list)));

Expand Down Expand Up @@ -313,7 +318,7 @@ static void test_gdma_m2m_mode(gdma_channel_handle_t tx_chan, gdma_channel_handl
vSemaphoreDelete(done_sem);
}

TEST_CASE("GDMA M2M Mode", "[GDMA][M2M]")
static void test_gdma_m2m_mode(bool trig_retention_backup)
{
gdma_channel_handle_t tx_chan = NULL;
gdma_channel_handle_t rx_chan = NULL;
Expand All @@ -332,7 +337,7 @@ TEST_CASE("GDMA M2M Mode", "[GDMA][M2M]")
};
TEST_ESP_OK(gdma_new_ahb_channel(&rx_chan_alloc_config, &rx_chan));

test_gdma_m2m_mode(tx_chan, rx_chan, false);
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));
Expand All @@ -351,13 +356,22 @@ TEST_CASE("GDMA M2M Mode", "[GDMA][M2M]")
TEST_ESP_OK(gdma_new_axi_channel(&rx_chan_alloc_config, &rx_chan));

// the AXI GDMA allows to put the DMA link list in the external memory
test_gdma_m2m_mode(tx_chan, rx_chan, true);
test_gdma_m2m_transaction(tx_chan, rx_chan, true, trig_retention_backup);

TEST_ESP_OK(gdma_del_channel(tx_chan));
TEST_ESP_OK(gdma_del_channel(rx_chan));
#endif // SOC_AXI_GDMA_SUPPORTED
}

TEST_CASE("GDMA M2M Mode", "[GDMA][M2M]")
{
test_gdma_m2m_mode(false);
#if SOC_GDMA_SUPPORT_SLEEP_RETENTION
// test again with retention
test_gdma_m2m_mode(true);
#endif
}

typedef struct {
SemaphoreHandle_t done_sem;
dma_buffer_split_array_t *align_array;
Expand Down
3 changes: 3 additions & 0 deletions components/esp_hw_support/test_apps/dma/sdkconfig.ci.release
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@ CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y

# we can silent the assertion to save the binary footprint
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y

# enable the option to test retention correctness
CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP=y
2 changes: 1 addition & 1 deletion components/esp_system/port/soc/esp32c6/clk.c
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ __attribute__((weak)) void esp_perip_clk_init(void)
parlio_ll_tx_enable_clock(&PARL_IO, false);
parlio_ll_enable_bus_clock(0, false);
gdma_ll_force_enable_reg_clock(&GDMA, false);
gdma_ll_enable_bus_clock(0, false);
_gdma_ll_enable_bus_clock(0, false);
#if CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
spi_ll_enable_bus_clock(SPI1_HOST, false);
#endif
Expand Down
2 changes: 1 addition & 1 deletion components/esp_system/port/soc/esp32h2/clk.c
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ __attribute__((weak)) void esp_perip_clk_init(void)
parlio_ll_tx_enable_clock(&PARL_IO, false);
parlio_ll_enable_bus_clock(0, false);
gdma_ll_force_enable_reg_clock(&GDMA, false);
gdma_ll_enable_bus_clock(0, false);
_gdma_ll_enable_bus_clock(0, false);
#if CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
spi_ll_enable_bus_clock(SPI1_HOST, false);
#endif
Expand Down
8 changes: 4 additions & 4 deletions components/hal/esp32c2/include/hal/gdma_ll.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,20 +55,20 @@ extern "C" {
/**
* @brief Enable the bus clock for the DMA module
*/
static inline void gdma_ll_enable_bus_clock(int group_id, bool enable)
static inline void _gdma_ll_enable_bus_clock(int group_id, bool enable)
{
(void)group_id;
SYSTEM.perip_clk_en1.dma_clk_en = enable;
}

/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define gdma_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; gdma_ll_enable_bus_clock(__VA_ARGS__)
#define gdma_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; _gdma_ll_enable_bus_clock(__VA_ARGS__)

/**
* @brief Reset the DMA module
*/
static inline void gdma_ll_reset_register(int group_id)
static inline void _gdma_ll_reset_register(int group_id)
{
(void)group_id;
SYSTEM.perip_rst_en1.dma_rst = 1;
Expand All @@ -77,7 +77,7 @@ static inline void gdma_ll_reset_register(int group_id)

/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define gdma_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; gdma_ll_reset_register(__VA_ARGS__)
#define gdma_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; _gdma_ll_reset_register(__VA_ARGS__)

/**
* @brief Force enable register clock
Expand Down
8 changes: 4 additions & 4 deletions components/hal/esp32c3/include/hal/gdma_ll.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,20 +55,20 @@ extern "C" {
/**
* @brief Enable the bus clock for the DMA module
*/
static inline void gdma_ll_enable_bus_clock(int group_id, bool enable)
static inline void _gdma_ll_enable_bus_clock(int group_id, bool enable)
{
(void)group_id;
SYSTEM.perip_clk_en1.reg_dma_clk_en = enable;
}

/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define gdma_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; gdma_ll_enable_bus_clock(__VA_ARGS__)
#define gdma_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; _gdma_ll_enable_bus_clock(__VA_ARGS__)

/**
* @brief Reset the DMA module
*/
static inline void gdma_ll_reset_register(int group_id)
static inline void _gdma_ll_reset_register(int group_id)
{
(void)group_id;
SYSTEM.perip_rst_en1.reg_dma_rst = 1;
Expand All @@ -77,7 +77,7 @@ static inline void gdma_ll_reset_register(int group_id)

/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define gdma_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; gdma_ll_reset_register(__VA_ARGS__)
#define gdma_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; _gdma_ll_reset_register(__VA_ARGS__)

/**
* @brief Force enable register clock
Expand Down
3 changes: 0 additions & 3 deletions components/hal/esp32c5/include/hal/ahb_dma_ll.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,11 @@
#include "soc/ahb_dma_struct.h"
#include "soc/ahb_dma_reg.h"
#include "soc/soc_etm_source.h"
#include "soc/retention_periph_defs.h"

#ifdef __cplusplus
extern "C" {
#endif

#define GDMA_CH_RETENTION_GET_MODULE_ID(group_id, pair_id) (SLEEP_RETENTION_MODULE_GDMA_CH0 << (SOC_GDMA_PAIRS_PER_GROUP_MAX * group_id) << pair_id)

#define AHB_DMA_LL_GET_HW(id) (((id) == 0) ? (&AHB_DMA) : NULL)

#define GDMA_LL_CHANNEL_MAX_PRIORITY 5 // supported priority levels: [0,5]
Expand Down
Loading

0 comments on commit ec50cb1

Please sign in to comment.