diff --git a/components/esp_hw_support/CMakeLists.txt b/components/esp_hw_support/CMakeLists.txt index 077e6f6191..2846fab097 100644 --- a/components/esp_hw_support/CMakeLists.txt +++ b/components/esp_hw_support/CMakeLists.txt @@ -18,6 +18,9 @@ if(NOT BOOTLOADER_BUILD) "sleep_gpio.c" "sleep_mac_bb.c" "regi2c_ctrl.c") + if(NOT CONFIG_IDF_TARGET_ESP32 AND NOT CONFIG_IDF_TARGET_ESP32S2) + list(APPEND srcs "sleep_retention.c") + endif() list(APPEND requires esp_ipc) else() # Requires "_esp_error_check_failed()" function diff --git a/components/esp_hw_support/component.mk b/components/esp_hw_support/component.mk index 5e75d5e0e3..f0f472034f 100644 --- a/components/esp_hw_support/component.mk +++ b/components/esp_hw_support/component.mk @@ -6,6 +6,9 @@ ifdef IS_BOOTLOADER_BUILD COMPONENT_OBJEXCLUDE += clk_ctrl_os.o \ intr_alloc.o \ sleep_modes.o \ + sleep_gpio.o \ + sleep_mac_bb.o \ + sleep_retention.o \ esp_async_memcpy.o \ mac_addr.o \ regi2c_ctrl.o \ @@ -16,4 +19,11 @@ COMPONENT_OBJEXCLUDE += clk_ctrl_os.o \ port/$(IDF_TARGET)/spiram_psram.o endif +ifdef CONFIG_IDF_TARGET_ESP32 +COMPONENT_OBJEXCLUDE += sleep_retention.o +endif +ifdef CONFIG_IDF_TARGET_ESP32S2 +COMPONENT_OBJEXCLUDE += sleep_retention.o +endif + COMPONENT_OBJEXCLUDE += esp_async_memcpy.o diff --git a/components/esp_hw_support/include/esp_private/sleep_retention.h b/components/esp_hw_support/include/esp_private/sleep_retention.h new file mode 100644 index 0000000000..001e559c0c --- /dev/null +++ b/components/esp_hw_support/include/esp_private/sleep_retention.h @@ -0,0 +1,55 @@ +/* + * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once +#include +#include "sdkconfig.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file sleep_retention.h + * + * This file contains declarations of memory retention related functions in light sleeo mode. + */ + +#if SOC_PM_SUPPORT_CPU_PD + +/** + * @brief Whether to allow the cpu power domain to be powered off. + * + * In light sleep mode, only when the system can provide enough memory + * for cpu retention, the cpu power domain can be powered off. + */ +bool cpu_domain_pd_allowed(void); + +#endif + +#if SOC_PM_SUPPORT_CPU_PD || SOC_PM_SUPPORT_TAGMEM_PD + +/** + * @brief Enable memory retention of some modules. + * + * In light sleep mode, before the system goes to sleep, enable the memory + * retention of modules such as CPU and I/D-cache tag memory. + */ +void sleep_enable_memory_retention(void); + +/** + * @brief Disable memory retention of some modules. + * + * In light sleep mode, after the system exits sleep, disable the memory + * retention of moudles such as CPU and I/D-cache tag memory. + */ +void sleep_disable_memory_retention(void); + +#endif // SOC_PM_SUPPORT_CPU_PD || SOC_PM_SUPPORT_TAGMEM_PD + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_hw_support/include/esp_sleep.h b/components/esp_hw_support/include/esp_sleep.h index 6a0b9d7d21..0ae44b3071 100644 --- a/components/esp_hw_support/include/esp_sleep.h +++ b/components/esp_hw_support/include/esp_sleep.h @@ -41,7 +41,9 @@ typedef enum { ESP_PD_DOMAIN_RTC_SLOW_MEM, //!< RTC slow memory ESP_PD_DOMAIN_RTC_FAST_MEM, //!< RTC fast memory ESP_PD_DOMAIN_XTAL, //!< XTAL oscillator +#if SOC_PM_SUPPORT_CPU_PD ESP_PD_DOMAIN_CPU, //!< CPU core +#endif ESP_PD_DOMAIN_VDDSDIO, //!< VDD_SDIO ESP_PD_DOMAIN_MAX //!< Number of domains } esp_sleep_pd_domain_t; diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index be331d05e1..d7f6d86a01 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -43,6 +43,7 @@ #include "esp_rom_uart.h" #include "esp_rom_sys.h" #include "brownout.h" +#include "esp_private/sleep_retention.h" #ifdef CONFIG_IDF_TARGET_ESP32 #include "esp32/rom/cache.h" @@ -67,14 +68,12 @@ #include "esp32c3/rom/cache.h" #include "esp32c3/rom/rtc.h" #include "soc/extmem_reg.h" -#include "esp_heap_caps.h" #include "esp_private/sleep_mac_bb.h" #elif CONFIG_IDF_TARGET_ESP32H2 #include "esp32h2/clk.h" #include "esp32h2/rom/cache.h" #include "esp32h2/rom/rtc.h" #include "soc/extmem_reg.h" -#include "esp_heap_caps.h" #endif // If light sleep time is less than that, don't power down flash @@ -151,13 +150,16 @@ typedef struct { uint32_t sleep_time_overhead_out; uint32_t rtc_clk_cal_period; uint64_t rtc_ticks_at_sleep_start; -#if SOC_PM_SUPPORT_CPU_PD - void *cpu_pd_mem; -#endif } sleep_config_t; static sleep_config_t s_config = { - .pd_options = { ESP_PD_OPTION_AUTO, ESP_PD_OPTION_AUTO, ESP_PD_OPTION_AUTO, ESP_PD_OPTION_AUTO, ESP_PD_OPTION_AUTO, ESP_PD_OPTION_AUTO }, + .pd_options = { + ESP_PD_OPTION_AUTO, ESP_PD_OPTION_AUTO, ESP_PD_OPTION_AUTO, ESP_PD_OPTION_AUTO, +#if SOC_PM_SUPPORT_CPU_PD + ESP_PD_OPTION_AUTO, +#endif + ESP_PD_OPTION_AUTO + }, .ccount_ticks_record = 0, .sleep_time_overhead_out = DEFAULT_SLEEP_OUT_OVERHEAD_US, .wakeup_triggers = 0 @@ -278,33 +280,33 @@ static void IRAM_ATTR resume_uarts(void) } } -inline static uint32_t IRAM_ATTR call_rtc_sleep_start(uint32_t reject_triggers, uint32_t lslp_mem_inf_fpu); - -#if SOC_PM_SUPPORT_CPU_PD -esp_err_t esp_sleep_cpu_pd_low_init(bool enable) +inline static void IRAM_ATTR misc_modules_sleep_prepare(void) { - if (enable) { - if (s_config.cpu_pd_mem == NULL) { - void *buf = heap_caps_aligned_alloc(SOC_RTC_CNTL_CPU_PD_DMA_ADDR_ALIGN, - SOC_RTC_CNTL_CPU_PD_RETENTION_MEM_SIZE + RTC_HAL_DMA_LINK_NODE_SIZE, - MALLOC_CAP_RETENTION | MALLOC_CAP_DEFAULT); - if (buf) { - memset(buf, 0, SOC_RTC_CNTL_CPU_PD_RETENTION_MEM_SIZE + RTC_HAL_DMA_LINK_NODE_SIZE); - s_config.cpu_pd_mem = rtc_cntl_hal_dma_link_init(buf, - buf + RTC_HAL_DMA_LINK_NODE_SIZE, SOC_RTC_CNTL_CPU_PD_RETENTION_MEM_SIZE, NULL); - } else { - return ESP_ERR_NO_MEM; - } - } - } else { - if (s_config.cpu_pd_mem) { - heap_caps_free(s_config.cpu_pd_mem); - s_config.cpu_pd_mem = NULL; - } - } - return ESP_OK; +#if CONFIG_MAC_BB_PD + mac_bb_power_down_cb_execute(); +#endif +#if CONFIG_GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL + gpio_sleep_mode_config_apply(); +#endif +#if SOC_PM_SUPPORT_CPU_PD || SOC_PM_SUPPORT_TAGMEM_PD + sleep_enable_memory_retention(); +#endif } -#endif // SOC_PM_SUPPORT_CPU_PD + +inline static void IRAM_ATTR misc_modules_wake_prepare(void) +{ +#if SOC_PM_SUPPORT_CPU_PD || SOC_PM_SUPPORT_TAGMEM_PD + sleep_disable_memory_retention(); +#endif +#if CONFIG_GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL + gpio_sleep_mode_config_unapply(); +#endif +#if CONFIG_MAC_BB_PD + mac_bb_power_up_cb_execute(); +#endif +} + +inline static uint32_t IRAM_ATTR call_rtc_sleep_start(uint32_t reject_triggers, uint32_t lslp_mem_inf_fpu); static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags) { @@ -333,10 +335,6 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags) rtc_clk_cpu_freq_get_config(&cpu_freq_config); rtc_clk_cpu_freq_set_xtal(); -#if CONFIG_MAC_BB_PD - mac_bb_power_down_cb_execute(); -#endif - #if SOC_PM_SUPPORT_EXT_WAKEUP // Configure pins for external wakeup if (s_config.wakeup_triggers & RTC_EXT0_TRIG_EN) { @@ -358,11 +356,10 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags) if (s_config.wakeup_triggers & RTC_ULP_TRIG_EN) { rtc_hal_ulp_wakeup_enable(); } -#if CONFIG_GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL - gpio_sleep_mode_config_apply(); -#endif #endif + misc_modules_sleep_prepare(); + #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 if (deep_sleep) { if (s_config.wakeup_triggers & RTC_TOUCH_TRIG_EN) { @@ -443,17 +440,8 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags) s_config.ccount_ticks_record = cpu_ll_get_cycle_count(); } -#if SOC_PM_SUPPORT_CPU_PD - rtc_cntl_hal_disable_cpu_retention(); -#endif + misc_modules_wake_prepare(); -#if CONFIG_GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL - gpio_sleep_mode_config_unapply(); -#endif - -#if CONFIG_MAC_BB_PD - mac_bb_power_up_cb_execute(); -#endif // re-enable UART output resume_uarts(); @@ -637,10 +625,6 @@ esp_err_t esp_light_sleep_start(void) periph_inform_out_light_sleep_overhead(s_config.sleep_time_adjustment - sleep_time_overhead_in); -#if SOC_PM_SUPPORT_CPU_PD - rtc_cntl_hal_enable_cpu_retention(s_config.cpu_pd_mem); -#endif - rtc_vddsdio_config_t vddsdio_config = rtc_vddsdio_get_config(); // Safety net: enable WDT in case exit from light sleep fails @@ -1176,11 +1160,7 @@ static uint32_t get_power_down_flags(void) } #if SOC_PM_SUPPORT_CPU_PD - if (s_config.cpu_pd_mem == NULL) { - s_config.pd_options[ESP_PD_DOMAIN_CPU] = ESP_PD_OPTION_ON; - } -#else - if (s_config.pd_options[ESP_PD_DOMAIN_CPU] != ESP_PD_OPTION_ON) { + if (!cpu_domain_pd_allowed()) { s_config.pd_options[ESP_PD_DOMAIN_CPU] = ESP_PD_OPTION_ON; } #endif diff --git a/components/esp_hw_support/sleep_retention.c b/components/esp_hw_support/sleep_retention.c new file mode 100644 index 0000000000..f915f3f107 --- /dev/null +++ b/components/esp_hw_support/sleep_retention.c @@ -0,0 +1,81 @@ +/* + * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include "esp_attr.h" +#include "esp_sleep.h" +#include "esp_log.h" +#include "esp_heap_caps.h" +#include "soc/soc_caps.h" +#include "hal/rtc_hal.h" +#include "esp_private/sleep_retention.h" +#include "sdkconfig.h" + +/** + * Internal structure which holds all requested light sleep memory retention parameters + */ +typedef struct { + rtc_cntl_sleep_retent_t retent; +} sleep_retention_t; + +static DRAM_ATTR sleep_retention_t s_retention; + +#if SOC_PM_SUPPORT_CPU_PD + +#define CPU_PD_MEM_TYPE_CAPS (MALLOC_CAP_RETENTION | MALLOC_CAP_DEFAULT) + +esp_err_t esp_sleep_cpu_pd_low_init(bool enable) +{ + if (enable) { + if (s_retention.retent.cpu_pd_mem == NULL) { + void *buf = heap_caps_aligned_alloc(SOC_RTC_CNTL_CPU_PD_DMA_ADDR_ALIGN, + SOC_RTC_CNTL_CPU_PD_RETENTION_MEM_SIZE + RTC_HAL_DMA_LINK_NODE_SIZE, + CPU_PD_MEM_TYPE_CAPS); + if (buf) { + memset(buf, 0, SOC_RTC_CNTL_CPU_PD_RETENTION_MEM_SIZE + RTC_HAL_DMA_LINK_NODE_SIZE); + s_retention.retent.cpu_pd_mem = rtc_cntl_hal_dma_link_init(buf, + buf + RTC_HAL_DMA_LINK_NODE_SIZE, SOC_RTC_CNTL_CPU_PD_RETENTION_MEM_SIZE, NULL); + } else { + return ESP_ERR_NO_MEM; + } + } + } else { + if (s_retention.retent.cpu_pd_mem) { + heap_caps_free(s_retention.retent.cpu_pd_mem); + s_retention.retent.cpu_pd_mem = NULL; + } + } + return ESP_OK; +} + +bool cpu_domain_pd_allowed(void) +{ + return (s_retention.retent.cpu_pd_mem != NULL); +} + +#endif // SOC_PM_SUPPORT_CPU_PD + +#if SOC_PM_SUPPORT_CPU_PD || SOC_PM_SUPPORT_TAGMEM_PD + +void sleep_enable_memory_retention(void) +{ +#if SOC_PM_SUPPORT_CPU_PD + rtc_cntl_hal_enable_cpu_retention(&s_retention.retent); +#endif +} + +void IRAM_ATTR sleep_disable_memory_retention(void) +{ +#if SOC_PM_SUPPORT_CPU_PD + rtc_cntl_hal_disable_cpu_retention(&s_retention.retent); +#endif +} + +#endif // SOC_PM_SUPPORT_CPU_PD || SOC_PM_SUPPORT_TAGMEM_PD diff --git a/components/esp_pm/linker.lf b/components/esp_pm/linker.lf index 3f4426b229..a8f3a9e6ab 100644 --- a/components/esp_pm/linker.lf +++ b/components/esp_pm/linker.lf @@ -21,6 +21,9 @@ entries: esp_clk:esp_rtc_get_time_us (noflash) if GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL = y: sleep_gpio:gpio_sleep_mode_config_apply (noflash) + if IDF_TARGET_ESP32 = n && IDF_TARGET_ESP32S2 = n: + sleep_retention:sleep_enable_memory_retention (noflash) + sleep_retention:cpu_domain_pd_allowed (noflash) [mapping:esp_system_pm] archive: libesp_system.a