From 881e1b0fd559b516fb71f158946a9ef4bb0efcd6 Mon Sep 17 00:00:00 2001 From: Li Shuai Date: Wed, 11 Aug 2021 22:06:47 +0800 Subject: [PATCH] deep sleep: add deep sleep support for esp32s3 --- components/esp_hw_support/sleep_modes.c | 50 +++++++++++++++++-- components/esp_rom/include/esp32s3/rom/rtc.h | 46 ++++++++--------- .../esp_system/ld/esp32s3/sections.ld.in | 2 + components/soc/esp32s3/include/soc/soc_caps.h | 3 ++ 4 files changed, 72 insertions(+), 29 deletions(-) diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index c9278b91ec..8d00a84677 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -188,12 +188,41 @@ static void touch_wakeup_prepare(void); static void esp_deep_sleep_wakeup_prepare(void); #endif +#if SOC_PM_SUPPORT_DEEPSLEEP_VERIFY_STUB_ONLY +static RTC_FAST_ATTR esp_deep_sleep_wake_stub_fn_t wake_stub_fn_handler = NULL; + +static void RTC_IRAM_ATTR __attribute__((used, noinline)) esp_wake_stub_start(void) +{ + if (wake_stub_fn_handler) { + (*wake_stub_fn_handler)(); + } +} + +/* We must have a default deep sleep wake stub entry function, which must be + * located at the start address of the RTC fast memory, and its implementation + * must be simple enough to ensure that there is no litteral data before the + * wake stub entry, otherwise, the litteral data before the wake stub entry + * will not be CRC checked. */ +static void __attribute__((section(".rtc.entry.text"))) esp_wake_stub_entry(void) +{ +#define _SYM2STR(s) # s +#define SYM2STR(s) _SYM2STR(s) + // call4 has a larger effective addressing range (-524284 to 524288 bytes), + // which is sufficient for instruction addressing in RTC fast memory. + __asm__ __volatile__ ("call4 " SYM2STR(esp_wake_stub_start) "\n"); +} +#endif // SOC_PM_SUPPORT_DEEPSLEEP_VERIFY_STUB_ONLY + /* Wake from deep sleep stub See esp_deepsleep.h esp_wake_deep_sleep() comments for details. */ esp_deep_sleep_wake_stub_fn_t esp_get_deep_sleep_wake_stub(void) { +#if SOC_PM_SUPPORT_DEEPSLEEP_VERIFY_STUB_ONLY + esp_deep_sleep_wake_stub_fn_t stub_ptr = wake_stub_fn_handler; +#else esp_deep_sleep_wake_stub_fn_t stub_ptr = (esp_deep_sleep_wake_stub_fn_t) REG_READ(RTC_ENTRY_ADDR_REG); +#endif if (!esp_ptr_executable(stub_ptr)) { return NULL; } @@ -202,7 +231,11 @@ esp_deep_sleep_wake_stub_fn_t esp_get_deep_sleep_wake_stub(void) void esp_set_deep_sleep_wake_stub(esp_deep_sleep_wake_stub_fn_t new_stub) { +#if SOC_PM_SUPPORT_DEEPSLEEP_VERIFY_STUB_ONLY + wake_stub_fn_handler = new_stub; +#else REG_WRITE(RTC_ENTRY_ADDR_REG, (uint32_t)new_stub); +#endif } void RTC_IRAM_ATTR esp_default_wake_deep_sleep(void) @@ -416,18 +449,27 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags) */ portENTER_CRITICAL(&spinlock_rtc_deep_sleep); +#if SOC_PM_SUPPORT_DEEPSLEEP_VERIFY_STUB_ONLY + extern char _rtc_text_start[]; +#if CONFIG_ESP32S3_RTCDATA_IN_FAST_MEM + extern char _rtc_noinit_end[]; + size_t rtc_fast_length = (size_t)_rtc_noinit_end - (size_t)_rtc_text_start; +#else + extern char _rtc_force_fast_end[]; + size_t rtc_fast_length = (size_t)_rtc_force_fast_end - (size_t)_rtc_text_start; +#endif + esp_rom_set_rtc_wake_addr((esp_rom_wake_func_t)esp_wake_stub_entry, rtc_fast_length); + result = call_rtc_sleep_start(reject_triggers, config.lslp_mem_inf_fpu); +#else #if !CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP /* If not possible stack is in RTC FAST memory, use the ROM function to calculate the CRC and save ~140 bytes IRAM */ -#if CONFIG_IDF_TARGET_ESP32S3//TODO: WIFI-3542 - result = 0; -#else set_rtc_memory_crc(); result = call_rtc_sleep_start(reject_triggers, config.lslp_mem_inf_fpu); -#endif #else /* Otherwise, need to call the dedicated soc function for this */ result = rtc_deep_sleep_start(s_config.wakeup_triggers, reject_triggers); #endif +#endif // SOC_PM_SUPPORT_DEEPSLEEP_VERIFY_STUB_ONLY portEXIT_CRITICAL(&spinlock_rtc_deep_sleep); } else { diff --git a/components/esp_rom/include/esp32s3/rom/rtc.h b/components/esp_rom/include/esp32s3/rom/rtc.h index d928c4dee4..88d2f76795 100644 --- a/components/esp_rom/include/esp32s3/rom/rtc.h +++ b/components/esp_rom/include/esp32s3/rom/rtc.h @@ -62,6 +62,7 @@ extern "C" { #define RTC_BOOT_TIME_LOW_REG RTC_CNTL_STORE2_REG #define RTC_BOOT_TIME_HIGH_REG RTC_CNTL_STORE3_REG #define RTC_XTAL_FREQ_REG RTC_CNTL_STORE4_REG +#define RTC_ENTRY_LENGTH_REG RTC_CNTL_STORE5_REG #define RTC_ENTRY_ADDR_REG RTC_CNTL_STORE6_REG #define RTC_RESET_CAUSE_REG RTC_CNTL_STORE6_REG #define RTC_MEMORY_CRC_REG RTC_CNTL_STORE7_REG @@ -173,16 +174,31 @@ RESET_REASON rtc_get_reset_reason(int cpu_no); */ WAKEUP_REASON rtc_get_wakeup_cause(void); +typedef void (* esp_rom_wake_func_t)(void); + /** - * @brief Get CRC for Fast RTC Memory. + * @brief Read stored RTC wake function address * - * @param uint32_t start_addr : 0 - 0x7ff for Fast RTC Memory. + * Returns pointer to wake address if a value is set in RTC registers, and stored length & CRC all valid. * - * @param uint32_t crc_len : 0 - 0x7ff, 0 for 4 byte, 0x7ff for 0x2000 byte. + * @param None * - * @return uint32_t : CRC32 result + * @return esp_rom_wake_func_t : Returns pointer to wake address if a value is set in RTC registers */ -uint32_t calc_rtc_memory_crc(uint32_t start_addr, uint32_t crc_len); +esp_rom_wake_func_t esp_rom_get_rtc_wake_addr(void); + +/** + * @brief Store new RTC wake function address + * + * Set a new RTC wake address function. If a non-NULL function pointer is set then the function + * memory is calculated and stored also. + * + * @param entry_addr Address of function. If NULL, length is ignored and all registers are cleared to 0. + * @param length of function in RTC fast memory. cannot be larger than RTC Fast memory size. + * + * @return None + */ +void esp_rom_set_rtc_wake_addr(esp_rom_wake_func_t entry_addr, size_t length); /** * @brief Suppress ROM log by setting specific RTC control register. @@ -202,26 +218,6 @@ static inline void rtc_suppress_rom_log(void) REG_SET_BIT(RTC_CNTL_STORE4_REG, RTC_DISABLE_ROM_LOG); } -/** - * @brief Set CRC of Fast RTC memory 0-0x7ff into RTC STORE7. - * - * @param None - * - * @return None - */ -void set_rtc_memory_crc(void); - -/** - * @brief Fetch entry from RTC memory and RTC STORE reg - * - * @param uint32_t * entry_addr : the address to save entry - * - * @param RESET_REASON reset_reason : reset reason this time - * - * @return None - */ -void rtc_boot_control(uint32_t *entry_addr, RESET_REASON reset_reason); - /** * @brief Software Reset digital core. * diff --git a/components/esp_system/ld/esp32s3/sections.ld.in b/components/esp_system/ld/esp32s3/sections.ld.in index 7ef4075a31..aff65b0f29 100644 --- a/components/esp_system/ld/esp32s3/sections.ld.in +++ b/components/esp_system/ld/esp32s3/sections.ld.in @@ -18,6 +18,8 @@ SECTIONS .rtc.text : { . = ALIGN(4); + _rtc_text_start = ABSOLUTE(.); + *(.rtc.entry.text) mapping[rtc_text] diff --git a/components/soc/esp32s3/include/soc/soc_caps.h b/components/soc/esp32s3/include/soc/soc_caps.h index ee95e0dc67..587a0491bd 100644 --- a/components/soc/esp32s3/include/soc/soc_caps.h +++ b/components/soc/esp32s3/include/soc/soc_caps.h @@ -287,6 +287,9 @@ #define SOC_PM_SUPPORT_TOUCH_SENSOR_WAKEUP (1) /*!