diff --git a/components/esp_driver_gptimer/src/gptimer_common.c b/components/esp_driver_gptimer/src/gptimer_common.c index 928ce3c84ad2..8338ebb2f491 100644 --- a/components/esp_driver_gptimer/src/gptimer_common.c +++ b/components/esp_driver_gptimer/src/gptimer_common.c @@ -27,24 +27,21 @@ static esp_err_t gptimer_create_sleep_retention_link_cb(void *arg) { gptimer_group_t *group = (gptimer_group_t *)arg; int group_id = group->group_id; - sleep_retention_module_t module = group->sleep_retention_module; esp_err_t err = sleep_retention_entries_create(tg_timer_reg_retention_info[group_id].regdma_entry_array, tg_timer_reg_retention_info[group_id].array_size, - REGDMA_LINK_PRI_GPTIMER, module); - ESP_RETURN_ON_ERROR(err, TAG, "create retention link failed"); - return ESP_OK; + REGDMA_LINK_PRI_GPTIMER, tg_timer_reg_retention_info[group_id].module); + return err; } void gptimer_create_retention_module(gptimer_group_t *group) { - sleep_retention_module_t module = group->sleep_retention_module; + int group_id = group->group_id; + sleep_retention_module_t module = tg_timer_reg_retention_info[group_id].module; _lock_acquire(&s_platform.mutex); - if (group->retention_link_created == false) { + if ((sleep_retention_get_inited_modules() & BIT(module)) && !(sleep_retention_get_created_modules() & BIT(module))) { if (sleep_retention_module_allocate(module) != ESP_OK) { // even though the sleep retention module create failed, GPTimer driver should still work, so just warning here - ESP_LOGW(TAG, "create retention module for group %d retention, power domain can't turn off", group->group_id); - } else { - group->retention_link_created = true; + ESP_LOGW(TAG, "create retention link failed %d, power domain won't be turned off during sleep", group_id); } } _lock_release(&s_platform.mutex); @@ -97,9 +94,7 @@ gptimer_group_t *gptimer_acquire_group_handle(int group_id) }, .depends = BIT(SLEEP_RETENTION_MODULE_CLOCK_SYSTEM) }; - if (sleep_retention_module_init(module, &init_param) == ESP_OK) { - group->sleep_retention_module = module; - } else { + if (sleep_retention_module_init(module, &init_param) != ESP_OK) { // even though the sleep retention module init failed, RMT driver should still work, so just warning here ESP_LOGW(TAG, "init sleep retention failed %d, power domain may be turned off during sleep", group_id); } @@ -132,11 +127,12 @@ void gptimer_release_group_handle(gptimer_group_t *group) } } #if GPTIMER_USE_RETENTION_LINK - if (group->sleep_retention_module) { - if (group->retention_link_created) { - sleep_retention_module_free(group->sleep_retention_module); - } - sleep_retention_module_deinit(group->sleep_retention_module); + sleep_retention_module_t module = tg_timer_reg_retention_info[group_id].module; + if (sleep_retention_get_created_modules() & BIT(module)) { + sleep_retention_module_free(module); + } + if (sleep_retention_get_inited_modules() & BIT(module)) { + sleep_retention_module_deinit(module); } #endif free(group); diff --git a/components/esp_driver_gptimer/src/gptimer_priv.h b/components/esp_driver_gptimer/src/gptimer_priv.h index 3c117af44f9d..b5d4d1c0e662 100644 --- a/components/esp_driver_gptimer/src/gptimer_priv.h +++ b/components/esp_driver_gptimer/src/gptimer_priv.h @@ -59,10 +59,6 @@ typedef struct gptimer_group_t { int group_id; portMUX_TYPE spinlock; // to protect per-group register level concurrent access gptimer_t *timers[SOC_TIMER_GROUP_TIMERS_PER_GROUP]; -#if GPTIMER_USE_RETENTION_LINK - sleep_retention_module_t sleep_retention_module; // sleep retention module - bool retention_link_created; // mark if the retention link is created -#endif } gptimer_group_t; typedef enum { diff --git a/components/esp_driver_gptimer/test_apps/gptimer/main/test_gptimer_sleep.c b/components/esp_driver_gptimer/test_apps/gptimer/main/test_gptimer_sleep.c index 34a437159898..5b7e5879d57a 100644 --- a/components/esp_driver_gptimer/test_apps/gptimer/main/test_gptimer_sleep.c +++ b/components/esp_driver_gptimer/test_apps/gptimer/main/test_gptimer_sleep.c @@ -10,6 +10,8 @@ #include "freertos/task.h" #include "unity.h" #include "driver/gptimer.h" +#include "driver/gpio_etm.h" +#include "driver/gpio.h" #include "soc/soc_caps.h" #include "esp_sleep.h" #include "esp_private/sleep_cpu.h" @@ -117,3 +119,135 @@ TEST_CASE("gptimer can work after light sleep", "[gptimer]") test_gptimer_sleep_retention(true); #endif } + +#if SOC_TIMER_SUPPORT_ETM +/** + * @brief Test the GPTimer and ETM subsystem can still work after light sleep + * + * @param back_up_before_sleep Whether to back up GPTimer registers before sleep + */ +static void test_gptimer_etm_sleep_retention(bool back_up_before_sleep) +{ + const uint32_t output_gpio = 1; + // GPTimer alarm ---> ETM channel A ---> GPTimer alarm re-enable + // GPTimer alarm ---> ETM channel B ---> GPIO toggle + printf("allocate etm channel\r\n"); + esp_etm_channel_config_t etm_config = { + .flags.allow_pd = back_up_before_sleep, + }; + esp_etm_channel_handle_t etm_channel_a, etm_channel_b; + TEST_ESP_OK(esp_etm_new_channel(&etm_config, &etm_channel_a)); + TEST_ESP_OK(esp_etm_new_channel(&etm_config, &etm_channel_b)); + + printf("initialize gpio\r\n"); + gpio_config_t task_gpio_config = { + .intr_type = GPIO_INTR_DISABLE, + .mode = GPIO_MODE_OUTPUT, + .pin_bit_mask = 1ULL << output_gpio, + }; + TEST_ESP_OK(gpio_config(&task_gpio_config)); + + printf("create a gptimer\r\n"); + gptimer_handle_t gptimer = NULL; + gptimer_config_t timer_config = { + .clk_src = GPTIMER_CLK_SRC_DEFAULT, + .direction = GPTIMER_COUNT_UP, + .resolution_hz = 1 * 1000 * 1000, // 1MHz, 1 tick = 1us + .flags.backup_before_sleep = back_up_before_sleep, + }; + TEST_ESP_OK(gptimer_new_timer(&timer_config, &gptimer)); + + printf("get gptimer etm event and task handle\r\n"); + esp_etm_event_handle_t gptimer_event = NULL; + gptimer_etm_event_config_t gptimer_etm_event_conf = { + .event_type = GPTIMER_ETM_EVENT_ALARM_MATCH, + }; + TEST_ESP_OK(gptimer_new_etm_event(gptimer, &gptimer_etm_event_conf, &gptimer_event)); + esp_etm_task_handle_t gptimer_task = NULL; + gptimer_etm_task_config_t gptimer_etm_task_conf = { + .task_type = GPTIMER_ETM_TASK_EN_ALARM, + }; + TEST_ESP_OK(gptimer_new_etm_task(gptimer, &gptimer_etm_task_conf, & gptimer_task)); + + printf("connect event and task to the channel a\r\n"); + TEST_ESP_OK(esp_etm_channel_connect(etm_channel_a, gptimer_event, gptimer_task)); + + printf("enable etm channels\r\n"); + TEST_ESP_OK(esp_etm_channel_enable(etm_channel_a)); + TEST_ESP_OK(esp_etm_channel_enable(etm_channel_b)); + + printf("set timer alarm action\r\n"); + gptimer_alarm_config_t alarm_config = { + .reload_count = 0, + .alarm_count = 100, // 100us per alarm event + .flags.auto_reload_on_alarm = true, + }; + TEST_ESP_OK(gptimer_set_alarm_action(gptimer, &alarm_config)); + + // before going to sleep, ensure the gptimer is not enabled yet, otherwise it will acquire power management lock + + esp_sleep_context_t sleep_ctx; + esp_sleep_set_sleep_context(&sleep_ctx); + printf("go to light sleep for 2 seconds\r\n"); +#if ESP_SLEEP_POWER_DOWN_CPU + TEST_ESP_OK(sleep_cpu_configure(true)); +#endif + TEST_ESP_OK(esp_sleep_enable_timer_wakeup(2 * 1000 * 1000)); + TEST_ESP_OK(esp_light_sleep_start()); + + printf("Waked up! Let's see if GPTimer and ETM can still work...\r\n"); +#if ESP_SLEEP_POWER_DOWN_CPU + TEST_ESP_OK(sleep_cpu_configure(false)); +#endif + + printf("check if the sleep happened as expected\r\n"); + TEST_ASSERT_EQUAL(0, sleep_ctx.sleep_request_result); +#if SOC_RMT_SUPPORT_SLEEP_RETENTION + // check if the power domain also is powered down + TEST_ASSERT_EQUAL(back_up_before_sleep ? PMU_SLEEP_PD_TOP : 0, (sleep_ctx.sleep_flags) & PMU_SLEEP_PD_TOP); +#endif + esp_sleep_set_sleep_context(NULL); + + printf("enable and start timer\r\n"); + TEST_ESP_OK(gptimer_enable(gptimer)); + TEST_ESP_OK(gptimer_start(gptimer)); + + printf("allocate GPIO etm task\r\n"); + esp_etm_task_handle_t gpio_task = NULL; + gpio_etm_task_config_t gpio_task_config = { + .action = GPIO_ETM_TASK_ACTION_TOG, + }; + TEST_ESP_OK(gpio_new_etm_task(&gpio_task_config, &gpio_task)); + // set gpio number for the gpio etm primitives + TEST_ESP_OK(gpio_etm_task_add_gpio(gpio_task, output_gpio)); + printf("connect event and task to the channel b\r\n"); + TEST_ESP_OK(esp_etm_channel_connect(etm_channel_b, gptimer_event, gpio_task)); + + // delay sometime for us to view the waveform, should see a 5KHz square waveform + vTaskDelay(pdMS_TO_TICKS(1000)); + + // delete gptimer + TEST_ESP_OK(gptimer_stop(gptimer)); + TEST_ESP_OK(gptimer_disable(gptimer)); + TEST_ESP_OK(gptimer_del_timer(gptimer)); + + // delete etm primitives + TEST_ESP_OK(gpio_etm_task_rm_gpio(gpio_task, output_gpio)); + TEST_ESP_OK(esp_etm_del_task(gpio_task)); + TEST_ESP_OK(esp_etm_del_task(gptimer_task)); + TEST_ESP_OK(esp_etm_del_event(gptimer_event)); + TEST_ESP_OK(esp_etm_channel_disable(etm_channel_a)); + TEST_ESP_OK(esp_etm_channel_disable(etm_channel_b)); + TEST_ESP_OK(esp_etm_del_channel(etm_channel_a)); + TEST_ESP_OK(esp_etm_del_channel(etm_channel_b)); +} + +TEST_CASE("gptimer and ETM can work after light sleep", "[gptimer]") +{ + test_gptimer_etm_sleep_retention(false); +#if SOC_TIMER_SUPPORT_SLEEP_RETENTION && SOC_ETM_SUPPORT_SLEEP_RETENTION + test_gptimer_etm_sleep_retention(true); +#endif +} + +#endif // SOC_TIMER_SUPPORT_ETM diff --git a/components/esp_driver_rmt/src/rmt_common.c b/components/esp_driver_rmt/src/rmt_common.c index d2b6f856f6ff..7a3cf11ca3d9 100644 --- a/components/esp_driver_rmt/src/rmt_common.c +++ b/components/esp_driver_rmt/src/rmt_common.c @@ -75,7 +75,7 @@ rmt_group_t *rmt_acquire_group_handle(int group_id) rmt_ll_reset_register(group_id); } #if RMT_USE_RETENTION_LINK - sleep_retention_module_t module = RMT_LL_SLEEP_RETENTION_MODULE_ID(group_id); + sleep_retention_module_t module = rmt_reg_retention_info[group_id].module; sleep_retention_module_init_param_t init_param = { .cbs = { .create = { @@ -85,9 +85,7 @@ rmt_group_t *rmt_acquire_group_handle(int group_id) }, .depends = BIT(SLEEP_RETENTION_MODULE_CLOCK_SYSTEM) }; - if (sleep_retention_module_init(module, &init_param) == ESP_OK) { - group->sleep_retention_module = module; - } else { + if (sleep_retention_module_init(module, &init_param) != ESP_OK) { // even though the sleep retention module init failed, RMT driver should still work, so just warning here ESP_LOGW(TAG, "init sleep retention failed %d, power domain may be turned off during sleep", group_id); } @@ -147,11 +145,12 @@ void rmt_release_group_handle(rmt_group_t *group) if (do_deinitialize) { #if RMT_USE_RETENTION_LINK - if (group->sleep_retention_module) { - if (group->retention_link_created) { - sleep_retention_module_free(group->sleep_retention_module); - } - sleep_retention_module_deinit(group->sleep_retention_module); + sleep_retention_module_t module = rmt_reg_retention_info[group_id].module; + if (sleep_retention_get_created_modules() & BIT(module)) { + sleep_retention_module_free(module); + } + if (sleep_retention_get_inited_modules() & BIT(module)) { + sleep_retention_module_deinit(module); } #endif free(group); @@ -303,24 +302,21 @@ static esp_err_t rmt_create_sleep_retention_link_cb(void *arg) { rmt_group_t *group = (rmt_group_t *)arg; int group_id = group->group_id; - sleep_retention_module_t module = group->sleep_retention_module; esp_err_t err = sleep_retention_entries_create(rmt_reg_retention_info[group_id].regdma_entry_array, rmt_reg_retention_info[group_id].array_size, - REGDMA_LINK_PRI_RMT, module); + REGDMA_LINK_PRI_RMT, rmt_reg_retention_info[group_id].module); return err; } void rmt_create_retention_module(rmt_group_t *group) { - sleep_retention_module_t module = group->sleep_retention_module; - + int group_id = group->group_id; + sleep_retention_module_t module = rmt_reg_retention_info[group_id].module; _lock_acquire(&s_platform.mutex); - if (group->retention_link_created == false) { + if ((sleep_retention_get_inited_modules() & BIT(module)) && !(sleep_retention_get_created_modules() & BIT(module))) { if (sleep_retention_module_allocate(module) != ESP_OK) { // even though the sleep retention module create failed, RMT driver should still work, so just warning here - ESP_LOGW(TAG, "create retention link failed, power domain can't be turned off"); - } else { - group->retention_link_created = true; + ESP_LOGW(TAG, "create retention link failed, power domain won't be turned off during sleep"); } } _lock_release(&s_platform.mutex); diff --git a/components/esp_driver_rmt/src/rmt_private.h b/components/esp_driver_rmt/src/rmt_private.h index 017ed9d9ab6d..16efc8ca9eba 100644 --- a/components/esp_driver_rmt/src/rmt_private.h +++ b/components/esp_driver_rmt/src/rmt_private.h @@ -119,10 +119,6 @@ struct rmt_group_t { rmt_rx_channel_t *rx_channels[SOC_RMT_RX_CANDIDATES_PER_GROUP]; // array of RMT RX channels rmt_sync_manager_t *sync_manager; // sync manager, this can be extended into an array if there're more sync controllers in one RMT group int intr_priority; // RMT interrupt priority -#if RMT_USE_RETENTION_LINK - sleep_retention_module_t sleep_retention_module; // sleep retention module - bool retention_link_created; // mark if the retention link is created -#endif }; struct rmt_channel_t { diff --git a/components/esp_hw_support/esp_etm.c b/components/esp_hw_support/esp_etm.c index 9dfbfc6cb40e..b8ae6349b7c1 100644 --- a/components/esp_hw_support/esp_etm.c +++ b/components/esp_hw_support/esp_etm.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -16,7 +16,7 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "soc/soc_caps.h" -#include "soc/periph_defs.h" +#include "soc/etm_periph.h" #include "esp_log.h" #include "esp_check.h" #include "esp_heap_caps.h" @@ -25,10 +25,13 @@ #include "hal/etm_ll.h" #include "esp_private/periph_ctrl.h" #include "esp_private/etm_interface.h" +#include "esp_private/sleep_retention.h" #define ETM_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT -#if CONFIG_IDF_TARGET_ESP32P4 +#define ETM_USE_RETENTION_LINK (SOC_ETM_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP) + +#if !SOC_RCC_IS_INDEPENDENT // Reset and Clock Control registers are mixing with other peripherals, so we need to use a critical section #define ETM_RCC_ATOMIC() PERIPH_RCC_ATOMIC() #else @@ -70,6 +73,32 @@ struct esp_etm_channel_t { // ETM driver platform, it's always a singleton static etm_platform_t s_platform; +#if ETM_USE_RETENTION_LINK +static esp_err_t etm_create_sleep_retention_link_cb(void *arg) +{ + etm_group_t *group = (etm_group_t *)arg; + int group_id = group->group_id; + esp_err_t err = sleep_retention_entries_create(etm_reg_retention_info[group_id].regdma_entry_array, + etm_reg_retention_info[group_id].array_size, + REGDMA_LINK_PRI_ETM, etm_reg_retention_info[group_id].module); + return err; +} + +static void etm_create_retention_module(etm_group_t *group) +{ + int group_id = group->group_id; + sleep_retention_module_t module = etm_reg_retention_info[group_id].module; + _lock_acquire(&s_platform.mutex); + if ((sleep_retention_get_inited_modules() & BIT(module)) && !(sleep_retention_get_created_modules() & BIT(module))) { + if (sleep_retention_module_allocate(module) != ESP_OK) { + // even though the sleep retention module create failed, ETM driver should still work, so just warning here + ESP_LOGW(TAG, "create retention link failed %d, power domain won't be turned off during sleep", group_id); + } + } + _lock_release(&s_platform.mutex); +} +#endif // ETM_USE_RETENTION_LINK + static etm_group_t *etm_acquire_group_handle(int group_id) { bool new_group = false; @@ -90,7 +119,22 @@ static etm_group_t *etm_acquire_group_handle(int group_id) etm_ll_enable_bus_clock(group_id, true); etm_ll_reset_register(group_id); } - +#if ETM_USE_RETENTION_LINK + sleep_retention_module_t module = etm_reg_retention_info[group_id].module; + sleep_retention_module_init_param_t init_param = { + .cbs = { + .create = { + .handle = etm_create_sleep_retention_link_cb, + .arg = group, + }, + }, + .depends = BIT(SLEEP_RETENTION_MODULE_CLOCK_SYSTEM) + }; + if (sleep_retention_module_init(module, &init_param) != ESP_OK) { + // even though the sleep retention module init failed, ETM driver may still work, so just warning here + ESP_LOGW(TAG, "init sleep retention failed %d, power domain may be turned off during sleep", group_id); + } +#endif // ETM_USE_RETENTION_LINK // initialize HAL context etm_hal_init(&group->hal); } @@ -129,6 +173,15 @@ static void etm_release_group_handle(etm_group_t *group) _lock_release(&s_platform.mutex); if (do_deinitialize) { +#if ETM_USE_RETENTION_LINK + sleep_retention_module_t module = etm_reg_retention_info[group_id].module; + if (sleep_retention_get_created_modules() & BIT(module)) { + sleep_retention_module_free(module); + } + if (sleep_retention_get_inited_modules() & BIT(module)) { + sleep_retention_module_deinit(module); + } +#endif free(group); ESP_LOGD(TAG, "del group (%d)", group_id); } @@ -192,6 +245,9 @@ esp_err_t esp_etm_new_channel(const esp_etm_channel_config_t *config, esp_etm_ch esp_err_t ret = ESP_OK; esp_etm_channel_t *chan = NULL; ESP_GOTO_ON_FALSE(config && ret_chan, ESP_ERR_INVALID_ARG, err, TAG, "invalid args"); +#if !SOC_ETM_SUPPORT_SLEEP_RETENTION + ESP_RETURN_ON_FALSE(config->flags.allow_pd == 0, ESP_ERR_NOT_SUPPORTED, TAG, "not able to power down in light sleep"); +#endif // SOC_ETM_SUPPORT_SLEEP_RETENTION chan = heap_caps_calloc(1, sizeof(esp_etm_channel_t), ETM_MEM_ALLOC_CAPS); ESP_GOTO_ON_FALSE(chan, ESP_ERR_NO_MEM, err, TAG, "no mem for channel"); @@ -201,6 +257,12 @@ esp_err_t esp_etm_new_channel(const esp_etm_channel_config_t *config, esp_etm_ch int group_id = group->group_id; int chan_id = chan->chan_id; +#if ETM_USE_RETENTION_LINK + if (config->flags.allow_pd != 0) { + etm_create_retention_module(group); + } +#endif // ETM_USE_RETENTION_LINK + chan->fsm = ETM_CHAN_FSM_INIT; ESP_LOGD(TAG, "new etm channel (%d,%d) at %p", group_id, chan_id, chan); *ret_chan = chan; diff --git a/components/esp_hw_support/include/esp_etm.h b/components/esp_hw_support/include/esp_etm.h index c0757abf8aba..daa97d76c32c 100644 --- a/components/esp_hw_support/include/esp_etm.h +++ b/components/esp_hw_support/include/esp_etm.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -32,7 +32,11 @@ typedef struct esp_etm_task_t *esp_etm_task_handle_t; * @brief ETM channel configuration */ typedef struct { - + /// Extra configuration flags for ETM channel + struct etm_chan_flags { + uint32_t allow_pd : 1; /*!< If set, driver allows the power domain to be powered off when system enters sleep mode. + This can save power, but at the expense of more RAM being consumed to save register context. */ + } flags; /*!< ETM channel flags */ } esp_etm_channel_config_t; /** diff --git a/components/hal/esp32c5/include/hal/rmt_ll.h b/components/hal/esp32c5/include/hal/rmt_ll.h index 053e27d0e9b4..0e54a0b37867 100644 --- a/components/hal/esp32c5/include/hal/rmt_ll.h +++ b/components/hal/esp32c5/include/hal/rmt_ll.h @@ -38,8 +38,6 @@ extern "C" { #define RMT_LL_MAX_FILTER_VALUE 255 #define RMT_LL_MAX_IDLE_VALUE 32767 -#define RMT_LL_SLEEP_RETENTION_MODULE_ID(group_id) (SLEEP_RETENTION_MODULE_RMT0) - typedef enum { RMT_LL_MEM_OWNER_SW = 0, RMT_LL_MEM_OWNER_HW = 1, diff --git a/components/hal/esp32c6/include/hal/rmt_ll.h b/components/hal/esp32c6/include/hal/rmt_ll.h index 247d63e5fe80..9fdc75764e0b 100644 --- a/components/hal/esp32c6/include/hal/rmt_ll.h +++ b/components/hal/esp32c6/include/hal/rmt_ll.h @@ -38,8 +38,6 @@ extern "C" { #define RMT_LL_MAX_FILTER_VALUE 255 #define RMT_LL_MAX_IDLE_VALUE 32767 -#define RMT_LL_SLEEP_RETENTION_MODULE_ID(group_id) (SLEEP_RETENTION_MODULE_RMT0) - typedef enum { RMT_LL_MEM_OWNER_SW = 0, RMT_LL_MEM_OWNER_HW = 1, diff --git a/components/hal/esp32h2/include/hal/rmt_ll.h b/components/hal/esp32h2/include/hal/rmt_ll.h index a3179addba59..4ebb3a1e0628 100644 --- a/components/hal/esp32h2/include/hal/rmt_ll.h +++ b/components/hal/esp32h2/include/hal/rmt_ll.h @@ -38,8 +38,6 @@ extern "C" { #define RMT_LL_MAX_FILTER_VALUE 255 #define RMT_LL_MAX_IDLE_VALUE 32767 -#define RMT_LL_SLEEP_RETENTION_MODULE_ID(group_id) (SLEEP_RETENTION_MODULE_RMT0) - typedef enum { RMT_LL_MEM_OWNER_SW = 0, RMT_LL_MEM_OWNER_HW = 1, diff --git a/components/hal/esp32p4/include/hal/rmt_ll.h b/components/hal/esp32p4/include/hal/rmt_ll.h index affcc3eeacd9..105aa426925e 100644 --- a/components/hal/esp32p4/include/hal/rmt_ll.h +++ b/components/hal/esp32p4/include/hal/rmt_ll.h @@ -33,8 +33,6 @@ extern "C" { #define RMT_LL_EVENT_TX_MASK(channel) (RMT_LL_EVENT_TX_DONE(channel) | RMT_LL_EVENT_TX_THRES(channel) | RMT_LL_EVENT_TX_LOOP_END(channel)) #define RMT_LL_EVENT_RX_MASK(channel) (RMT_LL_EVENT_RX_DONE(channel) | RMT_LL_EVENT_RX_THRES(channel)) -#define RMT_LL_SLEEP_RETENTION_MODULE_ID(group_id) (SLEEP_RETENTION_MODULE_RMT0) - #define RMT_LL_MAX_LOOP_COUNT_PER_BATCH 1023 #define RMT_LL_MAX_FILTER_VALUE 255 #define RMT_LL_MAX_IDLE_VALUE 32767 diff --git a/components/soc/CMakeLists.txt b/components/soc/CMakeLists.txt index 765cde298b77..59822b467f31 100644 --- a/components/soc/CMakeLists.txt +++ b/components/soc/CMakeLists.txt @@ -47,6 +47,10 @@ if(CONFIG_SOC_EMAC_SUPPORTED) list(APPEND srcs "${target_folder}/emac_periph.c") endif() +if(CONFIG_SOC_ETM_SUPPORTED) + list(APPEND srcs "${target_folder}/etm_periph.c") +endif() + if(CONFIG_SOC_GDMA_SUPPORTED) list(APPEND srcs "${target_folder}/gdma_periph.c") endif() diff --git a/components/soc/esp32c5/etm_periph.c b/components/soc/esp32c5/etm_periph.c new file mode 100644 index 000000000000..7b268c443a55 --- /dev/null +++ b/components/soc/esp32c5/etm_periph.c @@ -0,0 +1,44 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "soc/etm_periph.h" +#include "soc/soc_etm_reg.h" + +/** + * ETM Registers to be saved during sleep retention + * - Channel configuration registers, e.g.: SOC_ETM_CH0_EVT_ID_REG, SOC_ETM_CH0_TASK_ID_REG +*/ +#define ETM_RETENTION_REGS_CNT ((SOC_ETM_CH49_TASK_ID_REG - SOC_ETM_CH0_EVT_ID_REG) / 4 + 1) + +static const regdma_entries_config_t etm_regdma_entries[] = { + // backup stage: save the status of enabled channels + // restore stage: store the enabled channels + [0] = { + .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_ETM_LINK(0x00), + SOC_ETM_CH_ENA_AD0_REG, SOC_ETM_CH_ENA_AD0_SET_REG, 1, 0, 0), + .owner = ENTRY(0) | ENTRY(2), + }, + [1] = { + .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_ETM_LINK(0x01), + SOC_ETM_CH_ENA_AD1_REG, SOC_ETM_CH_ENA_AD1_SET_REG, 1, 0, 0), + .owner = ENTRY(0) | ENTRY(2), + }, + // backup stage: save configuration registers + // restore stage: restore the configuration registers + [2] = { + .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_ETM_LINK(0x02), + SOC_ETM_CH0_EVT_ID_REG, SOC_ETM_CH0_EVT_ID_REG, ETM_RETENTION_REGS_CNT, 0, 0), + .owner = ENTRY(0) | ENTRY(2), + }, +}; + +const etm_reg_retention_info_t etm_reg_retention_info[SOC_ETM_GROUPS] = { + [0] = { + .module = SLEEP_RETENTION_MODULE_ETM0, + .regdma_entry_array = etm_regdma_entries, + .array_size = ARRAY_SIZE(etm_regdma_entries) + }, +}; diff --git a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in index 23a96312324b..3ca17508c5da 100644 --- a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in @@ -463,6 +463,10 @@ config SOC_ETM_CHANNELS_PER_GROUP int default 50 +config SOC_ETM_SUPPORT_SLEEP_RETENTION + bool + default y + config SOC_GPIO_PORT int default 1 diff --git a/components/soc/esp32c5/include/soc/retention_periph_defs.h b/components/soc/esp32c5/include/soc/retention_periph_defs.h index 02002a7d0fe5..b21f1d3edeae 100644 --- a/components/soc/esp32c5/include/soc/retention_periph_defs.h +++ b/components/soc/esp32c5/include/soc/retention_periph_defs.h @@ -37,6 +37,7 @@ typedef enum periph_retention_module { SLEEP_RETENTION_MODULE_UART0 = 14, SLEEP_RETENTION_MODULE_UART1 = 15, SLEEP_RETENTION_MODULE_I2S0 = 16, + SLEEP_RETENTION_MODULE_ETM0 = 17, /* modem module, which includes WiFi, BLE and 802.15.4 */ SLEEP_RETENTION_MODULE_WIFI_MAC = 26, @@ -76,6 +77,7 @@ typedef enum periph_retention_module_bitmap { SLEEP_RETENTION_MODULE_BM_UART0 = BIT(SLEEP_RETENTION_MODULE_UART0), SLEEP_RETENTION_MODULE_BM_UART1 = BIT(SLEEP_RETENTION_MODULE_UART1), SLEEP_RETENTION_MODULE_BM_I2S0 = BIT(SLEEP_RETENTION_MODULE_I2S0), + SLEEP_RETENTION_MODULE_BM_ETM0 = BIT(SLEEP_RETENTION_MODULE_ETM0), SLEEP_RETENTION_MODULE_BM_GDMA_CH0 = BIT(SLEEP_RETENTION_MODULE_GDMA_CH0), SLEEP_RETENTION_MODULE_BM_GDMA_CH1 = BIT(SLEEP_RETENTION_MODULE_GDMA_CH1), @@ -97,6 +99,7 @@ typedef enum periph_retention_module_bitmap { | SLEEP_RETENTION_MODULE_BM_UART0 \ | SLEEP_RETENTION_MODULE_BM_UART1 \ | SLEEP_RETENTION_MODULE_BM_I2S0 \ + | SLEEP_RETENTION_MODULE_BM_ETM0 \ ) #ifdef __cplusplus } diff --git a/components/soc/esp32c5/include/soc/soc_caps.h b/components/soc/esp32c5/include/soc/soc_caps.h index c8f1619ce982..b98bce60b930 100644 --- a/components/soc/esp32c5/include/soc/soc_caps.h +++ b/components/soc/esp32c5/include/soc/soc_caps.h @@ -191,6 +191,7 @@ /*-------------------------- ETM CAPS --------------------------------------*/ #define SOC_ETM_GROUPS 1U // Number of ETM groups #define SOC_ETM_CHANNELS_PER_GROUP 50 // Number of ETM channels in the group +#define SOC_ETM_SUPPORT_SLEEP_RETENTION 1 // Support sleep retention /*-------------------------- GPIO CAPS ---------------------------------------*/ // ESP32-C5 has 1 GPIO peripheral diff --git a/components/soc/esp32c5/rmt_periph.c b/components/soc/esp32c5/rmt_periph.c index 87c00ebd260c..aa92c87aea32 100644 --- a/components/soc/esp32c5/rmt_periph.c +++ b/components/soc/esp32c5/rmt_periph.c @@ -60,6 +60,7 @@ static const regdma_entries_config_t rmt_regdma_entries[] = { const rmt_reg_retention_info_t rmt_reg_retention_info[SOC_RMT_GROUPS] = { [0] = { + .module = SLEEP_RETENTION_MODULE_RMT0, .regdma_entry_array = rmt_regdma_entries, .array_size = ARRAY_SIZE(rmt_regdma_entries) }, diff --git a/components/soc/esp32c6/etm_periph.c b/components/soc/esp32c6/etm_periph.c new file mode 100644 index 000000000000..7b268c443a55 --- /dev/null +++ b/components/soc/esp32c6/etm_periph.c @@ -0,0 +1,44 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "soc/etm_periph.h" +#include "soc/soc_etm_reg.h" + +/** + * ETM Registers to be saved during sleep retention + * - Channel configuration registers, e.g.: SOC_ETM_CH0_EVT_ID_REG, SOC_ETM_CH0_TASK_ID_REG +*/ +#define ETM_RETENTION_REGS_CNT ((SOC_ETM_CH49_TASK_ID_REG - SOC_ETM_CH0_EVT_ID_REG) / 4 + 1) + +static const regdma_entries_config_t etm_regdma_entries[] = { + // backup stage: save the status of enabled channels + // restore stage: store the enabled channels + [0] = { + .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_ETM_LINK(0x00), + SOC_ETM_CH_ENA_AD0_REG, SOC_ETM_CH_ENA_AD0_SET_REG, 1, 0, 0), + .owner = ENTRY(0) | ENTRY(2), + }, + [1] = { + .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_ETM_LINK(0x01), + SOC_ETM_CH_ENA_AD1_REG, SOC_ETM_CH_ENA_AD1_SET_REG, 1, 0, 0), + .owner = ENTRY(0) | ENTRY(2), + }, + // backup stage: save configuration registers + // restore stage: restore the configuration registers + [2] = { + .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_ETM_LINK(0x02), + SOC_ETM_CH0_EVT_ID_REG, SOC_ETM_CH0_EVT_ID_REG, ETM_RETENTION_REGS_CNT, 0, 0), + .owner = ENTRY(0) | ENTRY(2), + }, +}; + +const etm_reg_retention_info_t etm_reg_retention_info[SOC_ETM_GROUPS] = { + [0] = { + .module = SLEEP_RETENTION_MODULE_ETM0, + .regdma_entry_array = etm_regdma_entries, + .array_size = ARRAY_SIZE(etm_regdma_entries) + }, +}; diff --git a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in index b07201194296..396d8ff0e079 100644 --- a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in @@ -459,6 +459,10 @@ config SOC_ETM_CHANNELS_PER_GROUP int default 50 +config SOC_ETM_SUPPORT_SLEEP_RETENTION + bool + default y + config SOC_GPIO_PORT int default 1 diff --git a/components/soc/esp32c6/include/soc/retention_periph_defs.h b/components/soc/esp32c6/include/soc/retention_periph_defs.h index 5cdbc108e812..5bba74ce3531 100644 --- a/components/soc/esp32c6/include/soc/retention_periph_defs.h +++ b/components/soc/esp32c6/include/soc/retention_periph_defs.h @@ -37,6 +37,7 @@ typedef enum periph_retention_module { SLEEP_RETENTION_MODULE_UART0 = 14, SLEEP_RETENTION_MODULE_UART1 = 15, SLEEP_RETENTION_MODULE_I2S0 = 16, + SLEEP_RETENTION_MODULE_ETM0 = 17, /* Modem module, which includes WiFi, BLE and 802.15.4 */ SLEEP_RETENTION_MODULE_WIFI_MAC = 26, @@ -70,6 +71,7 @@ typedef enum periph_retention_module_bitmap { SLEEP_RETENTION_MODULE_BM_UART0 = BIT(SLEEP_RETENTION_MODULE_UART0), SLEEP_RETENTION_MODULE_BM_UART1 = BIT(SLEEP_RETENTION_MODULE_UART1), SLEEP_RETENTION_MODULE_BM_I2S0 = BIT(SLEEP_RETENTION_MODULE_I2S0), + SLEEP_RETENTION_MODULE_BM_ETM0 = BIT(SLEEP_RETENTION_MODULE_ETM0), /* modem module, which includes WiFi, BLE and 802.15.4 */ SLEEP_RETENTION_MODULE_BM_WIFI_MAC = BIT(SLEEP_RETENTION_MODULE_WIFI_MAC), SLEEP_RETENTION_MODULE_BM_WIFI_BB = BIT(SLEEP_RETENTION_MODULE_WIFI_BB), @@ -93,6 +95,7 @@ typedef enum periph_retention_module_bitmap { | SLEEP_RETENTION_MODULE_BM_UART0 \ | SLEEP_RETENTION_MODULE_BM_UART1 \ | SLEEP_RETENTION_MODULE_BM_I2S0 \ + | SLEEP_RETENTION_MODULE_BM_ETM0 \ ) #ifdef __cplusplus diff --git a/components/soc/esp32c6/include/soc/soc_caps.h b/components/soc/esp32c6/include/soc/soc_caps.h index e887e6856144..70835692ee81 100644 --- a/components/soc/esp32c6/include/soc/soc_caps.h +++ b/components/soc/esp32c6/include/soc/soc_caps.h @@ -178,6 +178,7 @@ /*-------------------------- ETM CAPS --------------------------------------*/ #define SOC_ETM_GROUPS 1U // Number of ETM groups #define SOC_ETM_CHANNELS_PER_GROUP 50 // Number of ETM channels in the group +#define SOC_ETM_SUPPORT_SLEEP_RETENTION 1 // Support sleep retention /*-------------------------- GPIO CAPS ---------------------------------------*/ // ESP32-C6 has 1 GPIO peripheral diff --git a/components/soc/esp32c6/rmt_periph.c b/components/soc/esp32c6/rmt_periph.c index 7ca8a5ddcbd6..c08da463f299 100644 --- a/components/soc/esp32c6/rmt_periph.c +++ b/components/soc/esp32c6/rmt_periph.c @@ -60,6 +60,7 @@ static const regdma_entries_config_t rmt_regdma_entries[] = { const rmt_reg_retention_info_t rmt_reg_retention_info[SOC_RMT_GROUPS] = { [0] = { + .module = SLEEP_RETENTION_MODULE_RMT0, .regdma_entry_array = rmt_regdma_entries, .array_size = ARRAY_SIZE(rmt_regdma_entries) }, diff --git a/components/soc/esp32c61/etm_periph.c b/components/soc/esp32c61/etm_periph.c new file mode 100644 index 000000000000..7b268c443a55 --- /dev/null +++ b/components/soc/esp32c61/etm_periph.c @@ -0,0 +1,44 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "soc/etm_periph.h" +#include "soc/soc_etm_reg.h" + +/** + * ETM Registers to be saved during sleep retention + * - Channel configuration registers, e.g.: SOC_ETM_CH0_EVT_ID_REG, SOC_ETM_CH0_TASK_ID_REG +*/ +#define ETM_RETENTION_REGS_CNT ((SOC_ETM_CH49_TASK_ID_REG - SOC_ETM_CH0_EVT_ID_REG) / 4 + 1) + +static const regdma_entries_config_t etm_regdma_entries[] = { + // backup stage: save the status of enabled channels + // restore stage: store the enabled channels + [0] = { + .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_ETM_LINK(0x00), + SOC_ETM_CH_ENA_AD0_REG, SOC_ETM_CH_ENA_AD0_SET_REG, 1, 0, 0), + .owner = ENTRY(0) | ENTRY(2), + }, + [1] = { + .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_ETM_LINK(0x01), + SOC_ETM_CH_ENA_AD1_REG, SOC_ETM_CH_ENA_AD1_SET_REG, 1, 0, 0), + .owner = ENTRY(0) | ENTRY(2), + }, + // backup stage: save configuration registers + // restore stage: restore the configuration registers + [2] = { + .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_ETM_LINK(0x02), + SOC_ETM_CH0_EVT_ID_REG, SOC_ETM_CH0_EVT_ID_REG, ETM_RETENTION_REGS_CNT, 0, 0), + .owner = ENTRY(0) | ENTRY(2), + }, +}; + +const etm_reg_retention_info_t etm_reg_retention_info[SOC_ETM_GROUPS] = { + [0] = { + .module = SLEEP_RETENTION_MODULE_ETM0, + .regdma_entry_array = etm_regdma_entries, + .array_size = ARRAY_SIZE(etm_regdma_entries) + }, +}; diff --git a/components/soc/esp32c61/include/soc/retention_periph_defs.h b/components/soc/esp32c61/include/soc/retention_periph_defs.h index 5bc404860b7a..6883ac14522d 100644 --- a/components/soc/esp32c61/include/soc/retention_periph_defs.h +++ b/components/soc/esp32c61/include/soc/retention_periph_defs.h @@ -33,6 +33,7 @@ typedef enum periph_retention_module { SLEEP_RETENTION_MODULE_I2C0 = 12, SLEEP_RETENTION_MODULE_UART0 = 14, SLEEP_RETENTION_MODULE_UART1 = 15, + SLEEP_RETENTION_MODULE_ETM0 = 16, /* Modem module, which includes WiFi, BLE and 802.15.4 */ SLEEP_RETENTION_MODULE_WIFI_MAC = 26, @@ -62,6 +63,7 @@ typedef enum periph_retention_module_bitmap { SLEEP_RETENTION_MODULE_BM_I2C0 = BIT(SLEEP_RETENTION_MODULE_I2C0), SLEEP_RETENTION_MODULE_BM_UART0 = BIT(SLEEP_RETENTION_MODULE_UART0), SLEEP_RETENTION_MODULE_BM_UART1 = BIT(SLEEP_RETENTION_MODULE_UART1), + SLEEP_RETENTION_MODULE_BM_ETM0 = BIT(SLEEP_RETENTION_MODULE_ETM0), /* modem module, which includes WiFi, BLE and 802.15.4 */ SLEEP_RETENTION_MODULE_BM_WIFI_MAC = BIT(SLEEP_RETENTION_MODULE_WIFI_MAC), SLEEP_RETENTION_MODULE_BM_WIFI_BB = BIT(SLEEP_RETENTION_MODULE_WIFI_BB), @@ -81,6 +83,7 @@ typedef enum periph_retention_module_bitmap { | SLEEP_RETENTION_MODULE_BM_I2C0 \ | SLEEP_RETENTION_MODULE_BM_UART0 \ | SLEEP_RETENTION_MODULE_BM_UART1 \ + | SLEEP_RETENTION_MODULE_BM_ETM0 \ ) #ifdef __cplusplus diff --git a/components/soc/esp32c61/include/soc/soc_caps.h b/components/soc/esp32c61/include/soc/soc_caps.h index 34a34bdb91dd..5e70aafba195 100644 --- a/components/soc/esp32c61/include/soc/soc_caps.h +++ b/components/soc/esp32c61/include/soc/soc_caps.h @@ -154,6 +154,7 @@ /*-------------------------- ETM CAPS --------------------------------------*/ #define SOC_ETM_GROUPS 1U // Number of ETM groups #define SOC_ETM_CHANNELS_PER_GROUP 50 // Number of ETM channels in the group +// #define SOC_ETM_SUPPORT_SLEEP_RETENTION 1 // Support sleep retention /*-------------------------- GPIO CAPS ---------------------------------------*/ // ESP32-C61 has 1 GPIO peripheral diff --git a/components/soc/esp32h2/etm_periph.c b/components/soc/esp32h2/etm_periph.c new file mode 100644 index 000000000000..7b268c443a55 --- /dev/null +++ b/components/soc/esp32h2/etm_periph.c @@ -0,0 +1,44 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "soc/etm_periph.h" +#include "soc/soc_etm_reg.h" + +/** + * ETM Registers to be saved during sleep retention + * - Channel configuration registers, e.g.: SOC_ETM_CH0_EVT_ID_REG, SOC_ETM_CH0_TASK_ID_REG +*/ +#define ETM_RETENTION_REGS_CNT ((SOC_ETM_CH49_TASK_ID_REG - SOC_ETM_CH0_EVT_ID_REG) / 4 + 1) + +static const regdma_entries_config_t etm_regdma_entries[] = { + // backup stage: save the status of enabled channels + // restore stage: store the enabled channels + [0] = { + .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_ETM_LINK(0x00), + SOC_ETM_CH_ENA_AD0_REG, SOC_ETM_CH_ENA_AD0_SET_REG, 1, 0, 0), + .owner = ENTRY(0) | ENTRY(2), + }, + [1] = { + .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_ETM_LINK(0x01), + SOC_ETM_CH_ENA_AD1_REG, SOC_ETM_CH_ENA_AD1_SET_REG, 1, 0, 0), + .owner = ENTRY(0) | ENTRY(2), + }, + // backup stage: save configuration registers + // restore stage: restore the configuration registers + [2] = { + .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_ETM_LINK(0x02), + SOC_ETM_CH0_EVT_ID_REG, SOC_ETM_CH0_EVT_ID_REG, ETM_RETENTION_REGS_CNT, 0, 0), + .owner = ENTRY(0) | ENTRY(2), + }, +}; + +const etm_reg_retention_info_t etm_reg_retention_info[SOC_ETM_GROUPS] = { + [0] = { + .module = SLEEP_RETENTION_MODULE_ETM0, + .regdma_entry_array = etm_regdma_entries, + .array_size = ARRAY_SIZE(etm_regdma_entries) + }, +}; diff --git a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in index 0a59f3a8d664..1330fbf23324 100644 --- a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in @@ -467,6 +467,10 @@ config SOC_ETM_CHANNELS_PER_GROUP int default 50 +config SOC_ETM_SUPPORT_SLEEP_RETENTION + bool + default y + config SOC_GPIO_PORT int default 1 diff --git a/components/soc/esp32h2/include/soc/retention_periph_defs.h b/components/soc/esp32h2/include/soc/retention_periph_defs.h index 819af3a2b354..372e43e981c9 100644 --- a/components/soc/esp32h2/include/soc/retention_periph_defs.h +++ b/components/soc/esp32h2/include/soc/retention_periph_defs.h @@ -38,6 +38,7 @@ typedef enum periph_retention_module { SLEEP_RETENTION_MODULE_UART0 = 15, SLEEP_RETENTION_MODULE_UART1 = 16, SLEEP_RETENTION_MODULE_I2S0 = 17, + SLEEP_RETENTION_MODULE_ETM0 = 18, /* Modem module, which includes BLE and 802.15.4 */ SLEEP_RETENTION_MODULE_BLE_MAC = 28, @@ -70,6 +71,7 @@ typedef enum periph_retention_module_bitmap { SLEEP_RETENTION_MODULE_BM_UART0 = BIT(SLEEP_RETENTION_MODULE_UART0), SLEEP_RETENTION_MODULE_BM_UART1 = BIT(SLEEP_RETENTION_MODULE_UART1), SLEEP_RETENTION_MODULE_BM_I2S0 = BIT(SLEEP_RETENTION_MODULE_I2S0), + SLEEP_RETENTION_MODULE_BM_ETM0 = BIT(SLEEP_RETENTION_MODULE_ETM0), /* modem module, which includes BLE and 802.15.4 */ SLEEP_RETENTION_MODULE_BM_BLE_MAC = BIT(SLEEP_RETENTION_MODULE_BLE_MAC), SLEEP_RETENTION_MODULE_BM_BT_BB = BIT(SLEEP_RETENTION_MODULE_BT_BB), @@ -92,6 +94,7 @@ typedef enum periph_retention_module_bitmap { | SLEEP_RETENTION_MODULE_BM_UART0 \ | SLEEP_RETENTION_MODULE_BM_UART1 \ | SLEEP_RETENTION_MODULE_BM_I2S0 \ + | SLEEP_RETENTION_MODULE_BM_ETM0 \ ) #ifdef __cplusplus diff --git a/components/soc/esp32h2/include/soc/soc_caps.h b/components/soc/esp32h2/include/soc/soc_caps.h index 2f28d6c6a62e..26110b48eba6 100644 --- a/components/soc/esp32h2/include/soc/soc_caps.h +++ b/components/soc/esp32h2/include/soc/soc_caps.h @@ -181,6 +181,7 @@ /*-------------------------- ETM CAPS --------------------------------------*/ #define SOC_ETM_GROUPS 1U // Number of ETM groups #define SOC_ETM_CHANNELS_PER_GROUP 50 // Number of ETM channels in the group +#define SOC_ETM_SUPPORT_SLEEP_RETENTION 1 // Support sleep retention /*-------------------------- GPIO CAPS ---------------------------------------*/ // ESP32-H2 has 1 GPIO peripheral diff --git a/components/soc/esp32h2/rmt_periph.c b/components/soc/esp32h2/rmt_periph.c index 7ca8a5ddcbd6..c08da463f299 100644 --- a/components/soc/esp32h2/rmt_periph.c +++ b/components/soc/esp32h2/rmt_periph.c @@ -60,6 +60,7 @@ static const regdma_entries_config_t rmt_regdma_entries[] = { const rmt_reg_retention_info_t rmt_reg_retention_info[SOC_RMT_GROUPS] = { [0] = { + .module = SLEEP_RETENTION_MODULE_RMT0, .regdma_entry_array = rmt_regdma_entries, .array_size = ARRAY_SIZE(rmt_regdma_entries) }, diff --git a/components/soc/esp32p4/etm_periph.c b/components/soc/esp32p4/etm_periph.c new file mode 100644 index 000000000000..f7b28b02bf7d --- /dev/null +++ b/components/soc/esp32p4/etm_periph.c @@ -0,0 +1,44 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "soc/etm_periph.h" +#include "soc/soc_etm_reg.h" + +/** + * ETM Registers to be saved during sleep retention + * - Channel configuration registers, e.g.: SOC_ETM_CH0_EVT_ID_REG, SOC_ETM_CH0_TASK_ID_REG +*/ +#define ETM_RETENTION_REGS_CNT ((SOC_ETM_CH49_TASK_ID_REG - SOC_ETM_CH0_EVT_ID_REG) / 4 + 1) + +static const regdma_entries_config_t etm_regdma_entries[] = { + // backup stage: save the status of enabled channels + // restore stage: store the enabled channels + [0] = { + .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_ETM_LINK(0x00), + SOC_ETM_CH_ENA_AD0_REG, SOC_ETM_CH_ENA_AD0_SET_REG, 1, 0, 0), + .owner = ENTRY(0), + }, + [1] = { + .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_ETM_LINK(0x01), + SOC_ETM_CH_ENA_AD1_REG, SOC_ETM_CH_ENA_AD1_SET_REG, 1, 0, 0), + .owner = ENTRY(0), + }, + // backup stage: save configuration registers + // restore stage: restore the configuration registers + [2] = { + .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_ETM_LINK(0x02), + SOC_ETM_CH0_EVT_ID_REG, SOC_ETM_CH0_EVT_ID_REG, ETM_RETENTION_REGS_CNT, 0, 0), + .owner = ENTRY(0), + }, +}; + +const etm_reg_retention_info_t etm_reg_retention_info[SOC_ETM_GROUPS] = { + [0] = { + .module = SLEEP_RETENTION_MODULE_ETM0, + .regdma_entry_array = etm_regdma_entries, + .array_size = ARRAY_SIZE(etm_regdma_entries) + }, +}; diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index cefa4d0350fd..f8319e722ee2 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -595,6 +595,10 @@ config SOC_ETM_CHANNELS_PER_GROUP int default 50 +config SOC_ETM_SUPPORT_SLEEP_RETENTION + bool + default y + config SOC_GPIO_PORT int default 1 diff --git a/components/soc/esp32p4/include/soc/retention_periph_defs.h b/components/soc/esp32p4/include/soc/retention_periph_defs.h index 48cf71404c6e..ab603ed24a85 100644 --- a/components/soc/esp32p4/include/soc/retention_periph_defs.h +++ b/components/soc/esp32p4/include/soc/retention_periph_defs.h @@ -46,6 +46,7 @@ typedef enum periph_retention_module { SLEEP_RETENTION_MODULE_I2S2 = 21, SLEEP_RETENTION_MODULE_I2C0 = 22, SLEEP_RETENTION_MODULE_I2C1 = 23, + SLEEP_RETENTION_MODULE_ETM0 = 24, SLEEP_RETENTION_MODULE_MAX = 31 } periph_retention_module_t; @@ -79,6 +80,7 @@ typedef enum periph_retention_module_bitmap { SLEEP_RETENTION_MODULE_BM_I2S0 = BIT(SLEEP_RETENTION_MODULE_I2S0), SLEEP_RETENTION_MODULE_BM_I2S1 = BIT(SLEEP_RETENTION_MODULE_I2S1), SLEEP_RETENTION_MODULE_BM_I2S2 = BIT(SLEEP_RETENTION_MODULE_I2S2), + SLEEP_RETENTION_MODULE_BM_ETM0 = BIT(SLEEP_RETENTION_MODULE_ETM0), SLEEP_RETENTION_MODULE_BM_ALL = (uint32_t)-1 } periph_retention_module_bitmap_t; @@ -100,9 +102,10 @@ typedef enum periph_retention_module_bitmap { | SLEEP_RETENTION_MODULE_BM_UART3 \ | SLEEP_RETENTION_MODULE_BM_UART4 \ | SLEEP_RETENTION_MODULE_BM_RMT0 \ - | SLEEP_RETENTION_MODULE_BM_I2S0 \ - | SLEEP_RETENTION_MODULE_BM_I2S1 \ - | SLEEP_RETENTION_MODULE_BM_I2S2 \ + | SLEEP_RETENTION_MODULE_BM_I2S0 \ + | SLEEP_RETENTION_MODULE_BM_I2S1 \ + | SLEEP_RETENTION_MODULE_BM_I2S2 \ + | SLEEP_RETENTION_MODULE_BM_ETM0 \ ) #ifdef __cplusplus diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index ba380964b4fd..a8a90bda8676 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -221,6 +221,7 @@ /*-------------------------- ETM CAPS --------------------------------------*/ #define SOC_ETM_GROUPS 1U // Number of ETM groups #define SOC_ETM_CHANNELS_PER_GROUP 50 // Number of ETM channels in the group +#define SOC_ETM_SUPPORT_SLEEP_RETENTION 1 // Support sleep retention /*-------------------------- GPIO CAPS ---------------------------------------*/ // ESP32-P4 has 1 GPIO peripheral diff --git a/components/soc/esp32p4/rmt_periph.c b/components/soc/esp32p4/rmt_periph.c index ec8625bc9450..e838ccb182a1 100644 --- a/components/soc/esp32p4/rmt_periph.c +++ b/components/soc/esp32p4/rmt_periph.c @@ -76,6 +76,7 @@ static const regdma_entries_config_t rmt_regdma_entries[] = { const rmt_reg_retention_info_t rmt_reg_retention_info[SOC_RMT_GROUPS] = { [0] = { + .module = SLEEP_RETENTION_MODULE_RMT0, .regdma_entry_array = rmt_regdma_entries, .array_size = ARRAY_SIZE(rmt_regdma_entries) }, diff --git a/components/soc/include/soc/etm_periph.h b/components/soc/include/soc/etm_periph.h new file mode 100644 index 000000000000..f7168ff71731 --- /dev/null +++ b/components/soc/include/soc/etm_periph.h @@ -0,0 +1,32 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "soc/soc_caps.h" +#include "soc/regdma.h" + +#if SOC_ETM_SUPPORT_SLEEP_RETENTION +#include "soc/retention_periph_defs.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if SOC_ETM_SUPPORT_SLEEP_RETENTION +typedef struct { + periph_retention_module_t module; + const regdma_entries_config_t *regdma_entry_array; + uint32_t array_size; +} etm_reg_retention_info_t; + +extern const etm_reg_retention_info_t etm_reg_retention_info[SOC_ETM_GROUPS]; +#endif // SOC_ETM_SUPPORT_SLEEP_RETENTION + +#ifdef __cplusplus +} +#endif diff --git a/components/soc/include/soc/regdma.h b/components/soc/include/soc/regdma.h index c3c62081f002..15186cbb95a8 100644 --- a/components/soc/include/soc/regdma.h +++ b/components/soc/include/soc/regdma.h @@ -54,6 +54,7 @@ extern "C" { #define REGDMA_TG0_TIMER_LINK(_pri) ((0x1C << 8) | _pri) #define REGDMA_TG1_TIMER_LINK(_pri) ((0x1D << 8) | _pri) #define REGDMA_I2S_LINK(_pri) ((0x1E << 8) | _pri) +#define REGDMA_ETM_LINK(_pri) ((0x1F << 8) | _pri) #define REGDMA_MODEM_FE_LINK(_pri) ((0xFF << 8) | _pri) #define REGDMA_LINK_PRI_SYS_CLK REGDMA_LINK_PRI_0 @@ -68,6 +69,7 @@ extern "C" { #define REGDMA_LINK_PRI_IEEE802154 REGDMA_LINK_PRI_GENERAL_PERIPH #define REGDMA_LINK_PRI_GDMA REGDMA_LINK_PRI_GENERAL_PERIPH #define REGDMA_LINK_PRI_RMT REGDMA_LINK_PRI_GENERAL_PERIPH +#define REGDMA_LINK_PRI_ETM REGDMA_LINK_PRI_GENERAL_PERIPH #define REGDMA_LINK_PRI_GPTIMER REGDMA_LINK_PRI_GENERAL_PERIPH #define REGDMA_LINK_PRI_I2C REGDMA_LINK_PRI_GENERAL_PERIPH #define REGDMA_LINK_PRI_I2S REGDMA_LINK_PRI_GENERAL_PERIPH diff --git a/components/soc/include/soc/rmt_periph.h b/components/soc/include/soc/rmt_periph.h index a85b5930a220..bb35a67b8635 100644 --- a/components/soc/include/soc/rmt_periph.h +++ b/components/soc/include/soc/rmt_periph.h @@ -10,6 +10,10 @@ #include "soc/periph_defs.h" #include "soc/regdma.h" +#if SOC_RMT_SUPPORT_SLEEP_RETENTION +#include "soc/retention_periph_defs.h" +#endif + #ifdef __cplusplus extern "C" { #endif @@ -32,6 +36,7 @@ extern const rmt_signal_conn_t rmt_periph_signals; #if SOC_RMT_SUPPORT_SLEEP_RETENTION typedef struct { + periph_retention_module_t module; const regdma_entries_config_t *regdma_entry_array; uint32_t array_size; } rmt_reg_retention_info_t; diff --git a/docs/en/api-reference/peripherals/etm.rst b/docs/en/api-reference/peripherals/etm.rst index b5a6a963dddd..a462082e83c7 100644 --- a/docs/en/api-reference/peripherals/etm.rst +++ b/docs/en/api-reference/peripherals/etm.rst @@ -32,6 +32,7 @@ The following sections of this document cover the typical steps to configure and - :ref:`etm-event` - describes how to allocate a new ETM event handle or fetch an existing handle from various peripherals. - :ref:`etm-task` - describes how to allocate a new ETM task handle or fetch an existing handle from various peripherals. - :ref:`etm-channel-control` - describes common ETM channel control functions. +- :ref:`etm-power-management` - describes the options and strategies provided by the driver in order to save power. - :ref:`etm-thread-safety` - lists which APIs are guaranteed to be thread-safe by the driver. - :ref:`etm-kconfig-options` - lists the supported Kconfig options that can be used to make a different effect on driver behavior. @@ -131,6 +132,17 @@ To check if the ETM channels are set with proper events and tasks, you can call The digital ID printed in the dump information is defined in the ``soc/soc_etm_source.h`` file. +.. _etm-power-management: + +Power Management +^^^^^^^^^^^^^^^^ + +When power management is enabled, i.e., :ref:`CONFIG_PM_ENABLE` is on, the system may adjust or disable the clock source, and power off the ETM peripheral before going to sleep. As a result, the existing connection between events and tasks will be lost, and the ETM channels can't work correctly after wake up. So by default, the driver will acquire a power management lock internally to forbid the system from powering off the ETM peripheral. + +.. only:: SOC_ETM_SUPPORT_SLEEP_RETENTION + + If you want to save more power, you can set :cpp:member:`esp_etm_channel_config_t::etm_chan_flags::allow_pd` to ``true``. Then ETM registers will be backed up before sleep and restored after wake up. Please note, enabling this option will increase the memory consumption for saving the register context. + .. _etm-thread-safety: Thread Safety diff --git a/docs/en/api-reference/system/power_management.rst b/docs/en/api-reference/system/power_management.rst index 8a7b9c37ba80..f583b86718c8 100644 --- a/docs/en/api-reference/system/power_management.rst +++ b/docs/en/api-reference/system/power_management.rst @@ -148,10 +148,11 @@ The following peripheral drivers are not aware of DFS yet. Applications need to - INT_MTX - TEE/APM - IO_MUX / GPIO - - Timer Group 0 & Timer Group 1 - SPI0/1 - SYSTIMER + :SOC_TIMER_SUPPORT_SLEEP_RETENTION: - GPTimer :SOC_RMT_SUPPORT_SLEEP_RETENTION: - RMT + :SOC_ETM_SUPPORT_SLEEP_RETENTION: - ETM :SOC_I2C_SUPPORT_SLEEP_RETENTION: - I2C :SOC_I2S_SUPPORT_SLEEP_RETENTION: - I2S :SOC_UART_SUPPORT_SLEEP_RETENTION: - All UARTs @@ -160,7 +161,6 @@ The following peripheral drivers are not aware of DFS yet. Applications need to .. list:: - - ETM - ASSIST_DEBUG - Trace - Crypto: AES/ECC/HMAC/RSA/SHA/DS/XTA_AES/ECDSA diff --git a/docs/zh_CN/api-reference/peripherals/etm.rst b/docs/zh_CN/api-reference/peripherals/etm.rst index 9c1967dcadd3..448b1be6c69a 100644 --- a/docs/zh_CN/api-reference/peripherals/etm.rst +++ b/docs/zh_CN/api-reference/peripherals/etm.rst @@ -32,6 +32,7 @@ ETM 模块具有多个通道,这些通道支持用户根据需要进行配置 - :ref:`etm-event` - 介绍如何分配新的 ETM 事件句柄,以及如何从不同外设获取现有句柄。 - :ref:`etm-task` - 介绍如何分配新的 ETM 任务句柄,以及如何从不同外设获取现有句柄。 - :ref:`etm-channel-control` - 介绍常见的 ETM 通道控制函数。 +- :ref:`etm-power-management` - 介绍了驱动针对功耗管理提供的选项和策略。 - :ref:`etm-thread-safety` - 列出了驱动程序中始终线程安全的 API。 - :ref:`etm-kconfig-options` - 列出了 ETM 支持的 Kconfig 选项,这些选项对驱动程序的行为会产生不同影响。 @@ -131,6 +132,17 @@ ETM 通道分析 以上输出信息打印的数字 ID 在 ``soc/soc_etm_source.h`` 文件中定义。 +.. _etm-power-management: + +电源管理 +^^^^^^^^ + +当启用电源管理时,即 :ref:`CONFIG_PM_ENABLE` 打开的时候,系统可能会调整或禁用时钟源,并在进入睡眠前关闭 ETM 外设依赖的电源。这会导致事件和任务之间的连接信息被丢失,ETM 通道在唤醒后无法正常工作。因此,默认情况下,驱动程序会获取电源管理锁,以禁止系统关闭 ETM 外设。 + +.. only:: SOC_ETM_SUPPORT_SLEEP_RETENTION + + 如果你想节省更多电量,可以将 :cpp:member:`esp_etm_channel_config_t::etm_chan_flags::allow_pd` 设置为 ``true``。ETM 寄存器将在睡眠前备份,并在唤醒后恢复。请注意,启用此选项会增加内存消耗,用于保存寄存器上下文。 + .. _etm-thread-safety: 线程安全 diff --git a/docs/zh_CN/api-reference/system/power_management.rst b/docs/zh_CN/api-reference/system/power_management.rst index 6d1e464abc05..3ea51dc30bb6 100644 --- a/docs/zh_CN/api-reference/system/power_management.rst +++ b/docs/zh_CN/api-reference/system/power_management.rst @@ -148,19 +148,19 @@ ESP-IDF 中集成的电源管理算法可以根据应用程序组件的需求, - INT_MTX - TEE/APM - IO_MUX / GPIO - - Timer Group 0 & Timer Group 1 - SPI0/1 - SYSTIMER + :SOC_TIMER_SUPPORT_SLEEP_RETENTION: - GPTimer :SOC_RMT_SUPPORT_SLEEP_RETENTION: - RMT :SOC_I2C_SUPPORT_SLEEP_RETENTION: - I2C :SOC_I2S_SUPPORT_SLEEP_RETENTION: - I2S + :SOC_ETM_SUPPORT_SLEEP_RETENTION: - ETM :SOC_UART_SUPPORT_SLEEP_RETENTION: - All UARTs 以下外设尚未支持: .. list:: - - ETM - ASSIST_DEBUG - Trace - Crypto: AES/ECC/HMAC/RSA/SHA/DS/XTA_AES/ECDSA