Skip to content

Commit 5929eed

Browse files
committed
Merge branch 'feat/support_software_trigger_retention' into 'master'
feat(esp_hw_support): support software trigger regdma retention Closes PM-199 See merge request espressif/esp-idf!32789
2 parents ead16f1 + 56aefbe commit 5929eed

File tree

20 files changed

+249
-115
lines changed

20 files changed

+249
-115
lines changed

components/esp_driver_gptimer/include/esp_private/gptimer.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -42,6 +42,16 @@ esp_err_t gptimer_get_intr_handle(gptimer_handle_t timer, intr_handle_t *ret_int
4242
*/
4343
esp_err_t gptimer_get_pm_lock(gptimer_handle_t timer, esp_pm_lock_handle_t *ret_pm_lock);
4444

45+
/**
46+
* @brief Get the group_id from the timer handle
47+
*
48+
* @param[in] timer Timer handle created by `gptimer_new_timer()`
49+
* @return
50+
* - ESP_OK: Get GPTimer group_id from handler successfully
51+
* - ESP_ERR_INVALID_ARG: Get GPTimer group_id failed because of invalid argument
52+
*/
53+
esp_err_t gptimer_get_group_id(gptimer_handle_t timer, int *group_id);
54+
4555
#ifdef __cplusplus
4656
}
4757
#endif

components/esp_driver_gptimer/src/gptimer_common.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,3 +226,10 @@ esp_err_t gptimer_get_pm_lock(gptimer_handle_t timer, esp_pm_lock_handle_t *ret_
226226
*ret_pm_lock = timer->pm_lock;
227227
return ESP_OK;
228228
}
229+
230+
int gptimer_get_group_id(gptimer_handle_t timer, int *group_id)
231+
{
232+
ESP_RETURN_ON_FALSE(timer && group_id, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
233+
*group_id = timer->group->group_id;
234+
return ESP_OK;
235+
}

components/esp_driver_gptimer/test_apps/gptimer/main/CMakeLists.txt

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
set(srcs "test_app_main.c"
2-
"test_gptimer.c")
2+
"test_gptimer.c"
3+
"test_gptimer_sleep.c")
34

45
if(CONFIG_GPTIMER_ISR_IRAM_SAFE)
56
list(APPEND srcs "test_gptimer_iram.c")
@@ -9,10 +10,6 @@ if(CONFIG_SOC_TIMER_SUPPORT_ETM)
910
list(APPEND srcs "test_gptimer_etm.c")
1011
endif()
1112

12-
if(CONFIG_SOC_LIGHT_SLEEP_SUPPORTED AND CONFIG_PM_ENABLE)
13-
list(APPEND srcs "test_gptimer_sleep.c")
14-
endif()
15-
1613
# In order for the cases defined by `TEST_CASE` to be linked into the final elf,
1714
# the component can be registered as WHOLE_ARCHIVE
1815
idf_component_register(SRCS ${srcs}

components/esp_driver_gptimer/test_apps/gptimer/main/test_gptimer_sleep.c

Lines changed: 70 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,20 @@
1515
#include "esp_private/sleep_cpu.h"
1616
#include "esp_private/esp_sleep_internal.h"
1717
#include "esp_private/esp_pmu.h"
18+
#if !SOC_LIGHT_SLEEP_SUPPORTED
19+
#include "esp_private/gptimer.h"
20+
#include "esp_private/sleep_retention.h"
21+
#include "hal/timer_ll.h"
22+
#include "hal/wdt_hal.h"
23+
#endif
24+
25+
#if CONFIG_GPTIMER_ISR_IRAM_SAFE
26+
#define TEST_ALARM_CALLBACK_ATTR IRAM_ATTR
27+
#else
28+
#define TEST_ALARM_CALLBACK_ATTR
29+
#endif // CONFIG_GPTIMER_ISR_IRAM_SAFE
1830

19-
static bool test_gptimer_alarm_stop_callback(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_data)
31+
static TEST_ALARM_CALLBACK_ATTR bool test_gptimer_alarm_stop_callback(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_data)
2032
{
2133
TaskHandle_t task_handle = (TaskHandle_t)user_data;
2234
BaseType_t high_task_wakeup;
@@ -25,6 +37,62 @@ static bool test_gptimer_alarm_stop_callback(gptimer_handle_t timer, const gptim
2537
return high_task_wakeup == pdTRUE;
2638
}
2739

40+
/**
41+
* @brief This function abstracts the behavior of performing the Backup-Reset-Restore process on the specified
42+
* Timer group and is used as a helper function to test the retention function of the driver.
43+
* If light-sleep feature is supported, this function will enter and exit a real light sleep or PD_TOP
44+
* light sleep. Otherwise, it will trigger retention by software and reset the timer module to simulate
45+
* a light-sleep in/out process to verify the driver's support for GPTimer sleep retention.
46+
*
47+
* @param timer Timer handle to be reset, created by `gptimer_new_timer()`
48+
* @param back_up_before_sleep Whether to back up GPTimer registers before sleep
49+
*/
50+
static void test_gptimer_survival_after_sleep_helper(gptimer_handle_t timer, bool back_up_before_sleep)
51+
{
52+
#if SOC_LIGHT_SLEEP_SUPPORTED
53+
esp_sleep_context_t sleep_ctx;
54+
esp_sleep_set_sleep_context(&sleep_ctx);
55+
printf("go to light sleep for 2 seconds\r\n");
56+
#if ESP_SLEEP_POWER_DOWN_CPU
57+
TEST_ESP_OK(sleep_cpu_configure(true));
58+
#endif
59+
TEST_ESP_OK(esp_sleep_enable_timer_wakeup(2 * 1000 * 1000));
60+
TEST_ESP_OK(esp_light_sleep_start());
61+
62+
printf("Waked up! Let's see if GPTimer driver can still work...\r\n");
63+
#if ESP_SLEEP_POWER_DOWN_CPU
64+
TEST_ESP_OK(sleep_cpu_configure(false));
65+
#endif
66+
67+
printf("check if the sleep happened as expected\r\n");
68+
TEST_ASSERT_EQUAL(0, sleep_ctx.sleep_request_result);
69+
#if SOC_TIMER_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
70+
if (back_up_before_sleep) {
71+
// Verify that when GPTimer retention is configured and sleep is requested,
72+
// the TOP power domain should be allowed to power down.
73+
TEST_ASSERT_EQUAL(PMU_SLEEP_PD_TOP, sleep_ctx.sleep_flags & PMU_SLEEP_PD_TOP);
74+
} else {
75+
// Verify that when GPTimer retention is not configured and sleep is requested, the TOP power
76+
// domain should not be allowed to power down to ensure the peripheral context is not lost.
77+
TEST_ASSERT_EQUAL(0, sleep_ctx.sleep_flags & PMU_SLEEP_PD_TOP);
78+
}
79+
#endif
80+
esp_sleep_set_sleep_context(NULL);
81+
#elif SOC_TIMER_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
82+
if (back_up_before_sleep) {
83+
printf("Back up the timer group context in use and then reset it\r\n");
84+
sleep_retention_do_extra_retention(true);
85+
86+
int group_id;
87+
gptimer_get_group_id(timer, &group_id);
88+
_timer_ll_reset_register(group_id);
89+
90+
printf("Reset done! Let's restore its context and see if its driver can still work...\r\n");
91+
sleep_retention_do_extra_retention(false);
92+
}
93+
#endif
94+
}
95+
2896
/**
2997
* @brief Test the GPTimer driver can still work after light sleep
3098
*
@@ -67,28 +135,7 @@ static void test_gptimer_sleep_retention(bool back_up_before_sleep)
67135
// Note: don't enable the gptimer before going to sleep, ensure no power management lock is acquired by it
68136
TEST_ESP_OK(gptimer_disable(timer));
69137

70-
esp_sleep_context_t sleep_ctx;
71-
esp_sleep_set_sleep_context(&sleep_ctx);
72-
printf("go to light sleep for 2 seconds\r\n");
73-
#if ESP_SLEEP_POWER_DOWN_CPU
74-
TEST_ESP_OK(sleep_cpu_configure(true));
75-
#endif
76-
TEST_ESP_OK(esp_sleep_enable_timer_wakeup(2 * 1000 * 1000));
77-
TEST_ESP_OK(esp_light_sleep_start());
78-
79-
printf("Waked up! Let's see if GPTimer driver can still work...\r\n");
80-
#if ESP_SLEEP_POWER_DOWN_CPU
81-
TEST_ESP_OK(sleep_cpu_configure(false));
82-
#endif
83-
84-
printf("check if the sleep happened as expected\r\n");
85-
TEST_ASSERT_EQUAL(0, sleep_ctx.sleep_request_result);
86-
#if SOC_TIMER_SUPPORT_SLEEP_RETENTION
87-
if (back_up_before_sleep) {
88-
TEST_ASSERT_EQUAL(PMU_SLEEP_PD_TOP, sleep_ctx.sleep_flags & PMU_SLEEP_PD_TOP);
89-
}
90-
#endif
91-
esp_sleep_set_sleep_context(NULL);
138+
test_gptimer_survival_after_sleep_helper(timer, back_up_before_sleep);
92139

93140
uint64_t count_value_after_sleep = 0;
94141
TEST_ESP_OK(gptimer_get_raw_count(timer, &count_value_after_sleep));

components/esp_hw_support/include/esp_private/esp_pau.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -77,6 +77,16 @@ void pau_regdma_trigger_extra_link_backup(void);
7777
*/
7878
void pau_regdma_trigger_extra_link_restore(void);
7979

80+
#if SOC_PAU_IN_TOP_DOMAIN
81+
/**
82+
* @brief Rentention link entry selection, enable or disable the retention
83+
* link entry configuration in always-on domain
84+
*
85+
* @param enable Set true to use always-on domain link configuration instead
86+
*/
87+
void pau_regdma_enable_aon_link_entry(bool enable);
88+
#endif
89+
8090
#ifdef __cplusplus
8191
}
8292
#endif

components/esp_hw_support/include/esp_private/sleep_retention.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,15 +164,13 @@ uint32_t sleep_retention_get_inited_modules(void);
164164
*/
165165
uint32_t sleep_retention_get_created_modules(void);
166166

167-
#if SOC_PM_RETENTION_HAS_CLOCK_BUG
168167
/**
169168
* @brief Software trigger REGDMA to do extra linked list retention
170169
*
171170
* @param backup_or_restore true for backup register context to memory
172171
* or false for restore to register from memory
173172
*/
174173
void sleep_retention_do_extra_retention(bool backup_or_restore);
175-
#endif
176174

177175
#if SOC_PM_RETENTION_SW_TRIGGER_REGDMA
178176
/**

components/esp_hw_support/modem_clock.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ void modem_clock_deselect_lp_clock_source(periph_module_t module)
458458
case PERIPH_BT_MODULE:
459459
modem_clock_hal_deselect_all_ble_rtc_timer_lpclk_source(MODEM_CLOCK_instance()->hal);
460460
modem_clock_hal_enable_ble_rtc_timer_clock(MODEM_CLOCK_instance()->hal, false);
461-
#if SOC_BLE_USE_WIFI_PWR_CLK_WORKAROUND
461+
#if SOC_BLE_USE_WIFI_PWR_CLK_WORKAROUND && SOC_LIGHT_SLEEP_SUPPORTED // TODO: [ESP32C5] IDF-8643
462462
if (efuse_hal_chip_revision() != 0) {
463463
if (last_src == MODEM_CLOCK_LPCLK_SRC_MAIN_XTAL) {
464464
pmu_sleep_enable_hp_sleep_sysclk(false);

components/esp_hw_support/port/pau_regdma.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515
#include "esp_private/esp_pau.h"
1616
#include "esp_private/periph_ctrl.h"
1717

18+
#if SOC_PAU_IN_TOP_DOMAIN
19+
#include "hal/lp_sys_ll.h"
20+
#endif
21+
1822
static __attribute__((unused)) const char *TAG = "pau_regdma";
1923

2024
typedef struct {
@@ -107,3 +111,10 @@ void IRAM_ATTR pau_regdma_trigger_extra_link_restore(void)
107111
pau_hal_start_regdma_extra_link(PAU_instance()->hal, false);
108112
pau_hal_stop_regdma_extra_link(PAU_instance()->hal);
109113
}
114+
115+
#if SOC_PAU_IN_TOP_DOMAIN
116+
void pau_regdma_enable_aon_link_entry(bool enable)
117+
{
118+
lp_sys_ll_set_pau_aon_bypass(enable);
119+
}
120+
#endif

components/esp_hw_support/sleep_retention.c

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@
2121
#include "sdkconfig.h"
2222
#include "esp_pmu.h"
2323

24+
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
25+
#include "hal/cache_ll.h"
26+
#endif
27+
2428
static __attribute__((unused)) const char *TAG = "sleep";
2529

2630
struct sleep_retention_module_object {
@@ -183,9 +187,7 @@ typedef struct {
183187

184188
struct sleep_retention_module_object instance[32];
185189

186-
#if SOC_PM_RETENTION_HAS_CLOCK_BUG
187190
#define EXTRA_LINK_NUM (REGDMA_LINK_ENTRY_NUM - 1)
188-
#endif
189191
} sleep_retention_t;
190192

191193
static DRAM_ATTR __attribute__((unused)) sleep_retention_t s_retention = {
@@ -312,6 +314,7 @@ void sleep_retention_dump_entries(FILE *out)
312314
regdma_link_dump(out, s_retention.lists[s_retention.highpri].entries[entry], entry);
313315
}
314316
}
317+
fflush(out);
315318
_lock_release_recursive(&s_retention.lock);
316319
}
317320

@@ -770,22 +773,28 @@ esp_err_t sleep_retention_module_free(sleep_retention_module_t module)
770773
return err;
771774
}
772775

773-
#if SOC_PM_RETENTION_HAS_CLOCK_BUG
774776
void IRAM_ATTR sleep_retention_do_extra_retention(bool backup_or_restore)
775777
{
776778
if (s_retention.highpri < SLEEP_RETENTION_REGDMA_LINK_HIGHEST_PRIORITY ||
777779
s_retention.highpri > SLEEP_RETENTION_REGDMA_LINK_LOWEST_PRIORITY) {
778780
return;
779781
}
782+
#if SOC_PAU_IN_TOP_DOMAIN
783+
pau_regdma_enable_aon_link_entry(false);
784+
#endif
780785
// Set extra linked list head pointer to hardware
781786
pau_regdma_set_extra_link_addr(s_retention.lists[s_retention.highpri].entries[EXTRA_LINK_NUM]);
787+
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
788+
/* Data of retention link may be temporarily stored in L1 DCache, which is not accessible by
789+
REGDMA, write it back to L2MEM before starting REGDMA. */
790+
cache_ll_writeback_all(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA, CACHE_LL_ID_ALL);
791+
#endif
782792
if (backup_or_restore) {
783793
pau_regdma_trigger_extra_link_backup();
784794
} else {
785795
pau_regdma_trigger_extra_link_restore();
786796
}
787797
}
788-
#endif
789798

790799
#if SOC_PM_RETENTION_SW_TRIGGER_REGDMA
791800
void IRAM_ATTR sleep_retention_do_system_retention(bool backup_or_restore)

components/hal/esp32c5/pau_hal.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,10 @@ void pau_hal_start_regdma_extra_link(pau_hal_context_t *hal, bool backup_or_rest
4040
pau_ll_clear_regdma_backup_done_intr_state(hal->dev);
4141
/* The link 3 of REGDMA is reserved, we use it as an extra linked list to
4242
* provide backup and restore services for BLE, IEEE802.15.4 and possibly
43-
* other modules */
43+
* other modules.
44+
* It is also used as software trigger REGDMA to backup and restore, and is
45+
* used by the UT to test module driver retention function.
46+
*/
4447
pau_ll_select_regdma_entry_link(hal->dev, 3);
4548
pau_ll_set_regdma_entry_link_backup_direction(hal->dev, backup_or_restore);
4649
pau_ll_set_regdma_entry_link_backup_start_enable(hal->dev);

0 commit comments

Comments
 (0)