Merge branch 'bugfix/idf-11425' into 'master'

power management module memory (iram or flash) usage optimization

Closes IDF-11425

See merge request espressif/esp-idf!37550
This commit is contained in:
Jiang Jiang Jian
2025-04-19 11:55:45 +08:00
29 changed files with 396 additions and 216 deletions
+12 -1
View File
@@ -70,6 +70,10 @@ menu "Hardware Settings"
# regardless of power management configuration.
config ESP_SLEEP_POWER_DOWN_FLASH
bool "Power down flash in light sleep when there is no SPIRAM or SPIRAM has independent power supply"
# TODO: PM-383
select PM_SLP_IRAM_OPT if (!IDF_TARGET_ESP32H21 && !IDF_TARGET_ESP32H4)
select ESP_PERIPH_CTRL_FUNC_IN_IRAM
select ESP_REGI2C_CTRL_FUNC_IN_IRAM
depends on !SPIRAM || ESP_LDO_RESERVE_PSRAM
depends on !(IDF_TARGET_ESP32P4 && (ESP32P4_REV_MIN_FULL < 100))
default n
@@ -219,12 +223,19 @@ menu "Hardware Settings"
endmenu
menu "Peripheral Control"
config PERIPH_CTRL_FUNC_IN_IRAM
config ESP_PERIPH_CTRL_FUNC_IN_IRAM
bool "Place peripheral control functions into IRAM"
default n
help
Place peripheral control functions (e.g. periph_module_reset) into IRAM,
so that these functions can be IRAM-safe and able to be called in the other IRAM interrupt context.
config ESP_REGI2C_CTRL_FUNC_IN_IRAM
bool "Place regi2c control functions into IRAM"
default y
help
Place analog i2c master control functions (e.g. regi2c_ctrl_read_reg, regi2c_ctrl_write_reg) into IRAM,
so that these functions can be IRAM-safe and able to be called in the other IRAM interrupt context.
endmenu
menu "ETM Configuration"
+7 -1
View File
@@ -26,6 +26,12 @@
#define MHZ (1000000)
#if CONFIG_PM_SLP_IRAM_OPT
# define ESP_CLK_FN_ATTR IRAM_ATTR
#else
# define ESP_CLK_FN_ATTR
#endif
// g_ticks_us defined in ROMs for PRO and APP CPU
extern uint32_t g_ticks_per_us_pro;
@@ -48,7 +54,7 @@ _Static_assert(offsetof(retain_mem_t, checksum) == sizeof(retain_mem_t) - sizeof
#if !NON_OS_BUILD
static __attribute__((section(".rtc_timer_data_in_rtc_mem"))) retain_mem_t s_rtc_timer_retain_mem;
static uint32_t calc_checksum(void)
static ESP_CLK_FN_ATTR uint32_t calc_checksum(void)
{
uint32_t checksum = 0;
uint32_t *data = (uint32_t*) &s_rtc_timer_retain_mem;
+37 -12
View File
@@ -12,36 +12,61 @@ entries:
cpu: esp_cpu_clear_watchpoint (noflash)
cpu: esp_cpu_compare_and_set (noflash)
esp_memory_utils (noflash)
rtc_clk (noflash)
clk_utils (noflash)
if PM_SLP_IRAM_OPT = y:
rtc_clk (noflash)
rtc_time (noflash_text)
if SOC_CONFIGURABLE_VDDSDIO_SUPPORTED = y:
rtc_init:rtc_vddsdio_get_config (noflash)
rtc_init:rtc_vddsdio_set_config (noflash)
if IDF_TARGET_ESP32 = y || IDF_TARGET_ESP32S2 = y || IDF_TARGET_ESP32S3 = y || IDF_TARGET_ESP32C2 = y || IDF_TARGET_ESP32C3 = y:
rtc_sleep (noflash_text)
rtc_time (noflash_text)
rtc_sleep:rtc_sleep_start (noflash)
if PM_SLP_IRAM_OPT = y:
rtc_sleep:rtc_sleep_get_default_config (noflash)
rtc_sleep:rtc_sleep_init (noflash)
rtc_sleep:rtc_sleep_low_init (noflash)
if IDF_TARGET_ESP32 = y || IDF_TARGET_ESP32S2 = y:
rtc_sleep:rtc_sleep_pd (noflash)
if IDF_TARGET_ESP32S3 = y || IDF_TARGET_ESP32C2 = y || IDF_TARGET_ESP32C3 = y:
rtc_sleep:rtc_sleep_pu (noflash)
if SOC_PMU_SUPPORTED = y && SOC_LIGHT_SLEEP_SUPPORTED = y:
pmu_sleep (noflash)
if SPIRAM_FLASH_LOAD_TO_PSRAM = y:
pmu_init (noflash)
pmu_param (noflash)
if SOC_USB_SERIAL_JTAG_SUPPORTED = y:
if SPIRAM_FLASH_LOAD_TO_PSRAM = y:
pmu_init (noflash)
pmu_param (noflash)
elif PM_SLP_IRAM_OPT = y && IDF_TARGET_ESP32P4 != y:
pmu_param:get_act_hp_dbias (noflash)
pmu_param:get_act_lp_dbias (noflash)
if PM_SLP_IRAM_OPT = y && SOC_USB_SERIAL_JTAG_SUPPORTED = y:
sleep_console (noflash)
if SOC_USB_OTG_SUPPORTED && SOC_PM_SUPPORT_CNNT_PD = y:
if PM_SLP_IRAM_OPT = y && SOC_USB_OTG_SUPPORTED && SOC_PM_SUPPORT_CNNT_PD = y:
sleep_usb (noflash)
if IDF_TARGET_ESP32 = y || IDF_TARGET_ESP32S2 = y:
rtc_wdt (noflash_text)
if PERIPH_CTRL_FUNC_IN_IRAM = y:
periph_ctrl: periph_module_reset (noflash)
if PERIPH_CTRL_FUNC_IN_IRAM = y && ESP_WIFI_ENABLED = y:
if ESP_PERIPH_CTRL_FUNC_IN_IRAM = y:
periph_ctrl:periph_module_reset (noflash)
periph_ctrl:periph_rcc_enter (noflash)
periph_ctrl:periph_rcc_exit (noflash)
periph_ctrl:periph_rcc_acquire_enter (noflash)
periph_ctrl:periph_rcc_acquire_exit (noflash)
periph_ctrl:periph_rcc_release_enter (noflash)
periph_ctrl:periph_rcc_release_exit (noflash)
if ESP_PERIPH_CTRL_FUNC_IN_IRAM = y && ESP_WIFI_ENABLED = y:
periph_ctrl: wifi_module_enable (noflash)
periph_ctrl: wifi_module_disable (noflash)
if ESP_REGI2C_CTRL_FUNC_IN_IRAM = y:
regi2c_ctrl:regi2c_ctrl_read_reg (noflash)
regi2c_ctrl:regi2c_ctrl_read_reg_mask (noflash)
regi2c_ctrl:regi2c_ctrl_write_reg (noflash)
regi2c_ctrl:regi2c_ctrl_write_reg_mask (noflash)
regi2c_ctrl:regi2c_enter_critical (noflash)
regi2c_ctrl:regi2c_exit_critical (noflash)
if SOC_SYSTIMER_SUPPORTED = y:
systimer (noflash)
if SOC_ADC_SHARED_POWER = y:
if ADC_ONESHOT_CTRL_FUNC_IN_IRAM = y:
sar_periph_ctrl (noflash)
else:
elif PM_SLP_IRAM_OPT = y:
sar_periph_ctrl: sar_periph_ctrl_power_enable (noflash)
[mapping:soc_pm]
+6 -6
View File
@@ -21,35 +21,35 @@ static portMUX_TYPE periph_spinlock = portMUX_INITIALIZER_UNLOCKED;
static uint8_t ref_counts[PERIPH_MODULE_MAX] = {0};
IRAM_ATTR void periph_rcc_enter(void)
void periph_rcc_enter(void)
{
portENTER_CRITICAL_SAFE(&periph_spinlock);
}
IRAM_ATTR void periph_rcc_exit(void)
void periph_rcc_exit(void)
{
portEXIT_CRITICAL_SAFE(&periph_spinlock);
}
IRAM_ATTR uint8_t periph_rcc_acquire_enter(periph_module_t periph)
uint8_t periph_rcc_acquire_enter(periph_module_t periph)
{
periph_rcc_enter();
return ref_counts[periph];
}
IRAM_ATTR void periph_rcc_acquire_exit(periph_module_t periph, uint8_t ref_count)
void periph_rcc_acquire_exit(periph_module_t periph, uint8_t ref_count)
{
ref_counts[periph] = ++ref_count;
periph_rcc_exit();
}
IRAM_ATTR uint8_t periph_rcc_release_enter(periph_module_t periph)
uint8_t periph_rcc_release_enter(periph_module_t periph)
{
periph_rcc_enter();
return ref_counts[periph] - 1;
}
IRAM_ATTR void periph_rcc_release_exit(periph_module_t periph, uint8_t ref_count)
void periph_rcc_release_exit(periph_module_t periph, uint8_t ref_count)
{
ref_counts[periph] = ref_count;
periph_rcc_exit();
@@ -65,7 +65,7 @@ typedef struct {
* Configure whether certain peripherals are powered down in deep sleep
* @param cfg power down flags as rtc_sleep_pd_config_t structure
*/
static void rtc_sleep_pd(rtc_sleep_pd_config_t cfg)
void rtc_sleep_pd(rtc_sleep_pd_config_t cfg)
{
REG_SET_FIELD(RTC_CNTL_DIG_PWC_REG, RTC_CNTL_LSLP_MEM_FORCE_PU, ~cfg.dig_pd);
REG_SET_FIELD(RTC_CNTL_PWC_REG, RTC_CNTL_SLOWMEM_FORCE_LPU, ~cfg.rtc_pd);
@@ -345,7 +345,7 @@ uint32_t rtc_deep_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt)
return rtc_sleep_finish();
}
static uint32_t rtc_sleep_finish(void)
static IRAM_ATTR uint32_t rtc_sleep_finish(void)
{
/* In deep sleep mode, we never get here */
uint32_t reject = REG_GET_FIELD(RTC_CNTL_INT_RAW_REG, RTC_CNTL_SLP_REJECT_INT_RAW);
@@ -222,7 +222,7 @@ uint32_t rtc_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt, uint32_t lslp
return rtc_sleep_finish(lslp_mem_inf_fpu);
}
static uint32_t rtc_sleep_finish(uint32_t lslp_mem_inf_fpu)
static IRAM_ATTR uint32_t rtc_sleep_finish(uint32_t lslp_mem_inf_fpu)
{
/* In deep sleep mode, we never get here */
uint32_t reject = REG_GET_FIELD(RTC_CNTL_INT_RAW_REG, RTC_CNTL_SLP_REJECT_INT_RAW);
@@ -352,7 +352,7 @@ uint32_t rtc_deep_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt)
return rtc_sleep_finish(0);
}
static uint32_t rtc_sleep_finish(uint32_t lslp_mem_inf_fpu)
static IRAM_ATTR uint32_t rtc_sleep_finish(uint32_t lslp_mem_inf_fpu)
{
/* In deep sleep mode, we never get here */
uint32_t reject = REG_GET_FIELD(RTC_CNTL_INT_RAW_REG, RTC_CNTL_SLP_REJECT_INT_RAW);
@@ -361,7 +361,7 @@ uint32_t rtc_deep_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt)
return rtc_sleep_finish(0);
}
static uint32_t rtc_sleep_finish(uint32_t lslp_mem_inf_fpu)
static IRAM_ATTR uint32_t rtc_sleep_finish(uint32_t lslp_mem_inf_fpu)
{
/* In deep sleep mode, we never get here */
uint32_t reject = REG_GET_FIELD(RTC_CNTL_INT_RAW_REG, RTC_CNTL_SLP_REJECT_INT_RAW);
@@ -284,7 +284,7 @@ __attribute__((weak)) uint32_t rtc_sleep_start(uint32_t wakeup_opt, uint32_t rej
return rtc_sleep_finish(lslp_mem_inf_fpu);
}
static uint32_t rtc_sleep_finish(uint32_t lslp_mem_inf_fpu)
static IRAM_ATTR uint32_t rtc_sleep_finish(uint32_t lslp_mem_inf_fpu)
{
/* In deep sleep mode, we never get here */
uint32_t reject = REG_GET_FIELD(RTC_CNTL_INT_RAW_REG, RTC_CNTL_SLP_REJECT_INT_RAW);
+6 -6
View File
@@ -18,7 +18,7 @@ static portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;
static DRAM_ATTR __attribute__((unused)) const char *TAG = "REGI2C";
uint8_t IRAM_ATTR regi2c_ctrl_read_reg(uint8_t block, uint8_t host_id, uint8_t reg_add)
uint8_t regi2c_ctrl_read_reg(uint8_t block, uint8_t host_id, uint8_t reg_add)
{
REGI2C_CLOCK_ENABLE();
portENTER_CRITICAL_SAFE(&mux);
@@ -28,7 +28,7 @@ uint8_t IRAM_ATTR regi2c_ctrl_read_reg(uint8_t block, uint8_t host_id, uint8_t r
return value;
}
uint8_t IRAM_ATTR regi2c_ctrl_read_reg_mask(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t msb, uint8_t lsb)
uint8_t regi2c_ctrl_read_reg_mask(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t msb, uint8_t lsb)
{
REGI2C_CLOCK_ENABLE();
portENTER_CRITICAL_SAFE(&mux);
@@ -38,7 +38,7 @@ uint8_t IRAM_ATTR regi2c_ctrl_read_reg_mask(uint8_t block, uint8_t host_id, uint
return value;
}
void IRAM_ATTR regi2c_ctrl_write_reg(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t data)
void regi2c_ctrl_write_reg(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t data)
{
REGI2C_CLOCK_ENABLE();
portENTER_CRITICAL_SAFE(&mux);
@@ -47,7 +47,7 @@ void IRAM_ATTR regi2c_ctrl_write_reg(uint8_t block, uint8_t host_id, uint8_t reg
REGI2C_CLOCK_DISABLE();
}
void IRAM_ATTR regi2c_ctrl_write_reg_mask(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t msb, uint8_t lsb, uint8_t data)
void regi2c_ctrl_write_reg_mask(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t msb, uint8_t lsb, uint8_t data)
{
REGI2C_CLOCK_ENABLE();
portENTER_CRITICAL_SAFE(&mux);
@@ -56,12 +56,12 @@ void IRAM_ATTR regi2c_ctrl_write_reg_mask(uint8_t block, uint8_t host_id, uint8_
REGI2C_CLOCK_DISABLE();
}
void IRAM_ATTR regi2c_enter_critical(void)
void regi2c_enter_critical(void)
{
portENTER_CRITICAL_SAFE(&mux);
}
void IRAM_ATTR regi2c_exit_critical(void)
void regi2c_exit_critical(void)
{
portEXIT_CRITICAL_SAFE(&mux);
}
@@ -33,6 +33,12 @@ static const char *TAG_TSENS = "temperature_sensor";
#define TSENS_RCC_ATOMIC()
#endif
#if CONFIG_PM_SLP_IRAM_OPT
# define SAR_PERIPH_CTRL_COMMON_FN_ATTR IRAM_ATTR
#else
# define SAR_PERIPH_CTRL_COMMON_FN_ATTR
#endif
static int s_record_min = INT_NOT_USED;
static int s_record_max = INT_NOT_USED;
static int s_temperature_sensor_power_cnt;
@@ -79,7 +85,7 @@ void temperature_sensor_power_release(void)
portEXIT_CRITICAL(&rtc_spinlock);
}
static int temperature_sensor_get_raw_value(void)
static SAR_PERIPH_CTRL_COMMON_FN_ATTR int temperature_sensor_get_raw_value(void)
{
int raw_value = temperature_sensor_ll_get_raw_value();
return (TEMPERATURE_SENSOR_LL_ADC_FACTOR * raw_value - TEMPERATURE_SENSOR_LL_DAC_FACTOR * temperature_sensor_attributes[s_tsens_idx].offset - TEMPERATURE_SENSOR_LL_OFFSET_FACTOR);
@@ -7,3 +7,5 @@ CONFIG_FOUR_UNIVERSAL_MAC_ADDRESS CONFIG_ESP32_UNIVERSAL_M
CONFIG_ESP_SYSTEM_PD_FLASH CONFIG_ESP_SLEEP_POWER_DOWN_FLASH
CONFIG_ESP_SYSTEM_BROWNOUT_INTR CONFIG_ESP_BROWNOUT_USE_INTR
CONFIG_PERIPH_CTRL_FUNC_IN_IRAM CONFIG_ESP_PERIPH_CTRL_FUNC_IN_IRAM
+18
View File
@@ -14,6 +14,7 @@
#include "esp_log.h"
#include "esp_memory_utils.h"
#include "soc/soc_caps.h"
#include "soc/uart_pins.h"
#include "sdkconfig.h"
@@ -151,6 +152,23 @@ IRAM_ATTR void esp_sleep_isolate_digital_gpio(void)
/* isolate digital IO that is not held(keep the configuration of digital IOs held by users) */
for (gpio_num_t gpio_num = GPIO_NUM_0; gpio_num < GPIO_NUM_MAX; gpio_num++) {
if (GPIO_IS_VALID_DIGITAL_IO_PAD(gpio_num) && !gpio_hal_is_digital_io_hold(&gpio_hal, gpio_num)) {
bool is_mspi_io_pad = false;
esp_mspi_io_t mspi_ios[] = { ESP_MSPI_IO_CS0, ESP_MSPI_IO_CLK, ESP_MSPI_IO_Q, ESP_MSPI_IO_D, ESP_MSPI_IO_HD, ESP_MSPI_IO_WP };
for (int i = 0; i < sizeof(mspi_ios) / sizeof(mspi_ios[0]); i++) {
if (esp_mspi_get_io(mspi_ios[i]) == gpio_num) {
is_mspi_io_pad = true;
break;
}
}
// Ignore MSPI and default Console UART io pads, When the CPU executes
// the following instructions to configure the MSPI IO PAD, access on
// the MSPI signal lines (as CPU instruction execution and MSPI access
// operations are asynchronous) may cause the SoC to hang.
if (is_mspi_io_pad || gpio_num == U0RXD_GPIO_NUM || gpio_num == U0TXD_GPIO_NUM) {
continue;
}
/* disable I/O */
gpio_hal_input_disable(&gpio_hal, gpio_num);
gpio_hal_output_disable(&gpio_hal, gpio_num);
+3 -3
View File
@@ -77,7 +77,7 @@ esp_err_t esp_unregister_mac_bb_pd_callback(mac_bb_power_down_cb_t cb)
return ESP_ERR_INVALID_STATE;
}
void IRAM_ATTR mac_bb_power_down_cb_execute(void)
void mac_bb_power_down_cb_execute(void)
{
for (int i = 0; i < MAC_BB_POWER_DOWN_CB_NO; i++) {
if (s_mac_bb_power_down_cb[i]) {
@@ -118,7 +118,7 @@ esp_err_t esp_unregister_mac_bb_pu_callback(mac_bb_power_up_cb_t cb)
return ESP_ERR_INVALID_STATE;
}
void IRAM_ATTR mac_bb_power_up_cb_execute(void)
void mac_bb_power_up_cb_execute(void)
{
for (int i = 0; i < MAC_BB_POWER_UP_CB_NO; i++) {
if (s_mac_bb_power_up_cb[i]) {
@@ -221,7 +221,7 @@ bool modem_domain_pd_allowed(void)
#endif
}
uint32_t IRAM_ATTR sleep_modem_reject_triggers(void)
uint32_t sleep_modem_reject_triggers(void)
{
uint32_t reject_triggers = 0;
#if SOC_PM_SUPPORT_PMU_MODEM_STATE
+170 -133
View File
@@ -162,6 +162,12 @@
#elif CONFIG_IDF_TARGET_ESP32C2
#define DEFAULT_SLEEP_OUT_OVERHEAD_US (118)
#define DEFAULT_HARDWARE_OUT_OVERHEAD_US (9)
# if !CONFIG_PM_SLP_IRAM_OPT
#undef DEFAULT_SLEEP_OUT_OVERHEAD_US
#define DEFAULT_SLEEP_OUT_OVERHEAD_US (2779)
#undef DEFAULT_HARDWARE_OUT_OVERHEAD_US
#define DEFAULT_HARDWARE_OUT_OVERHEAD_US (157)
# endif
#elif CONFIG_IDF_TARGET_ESP32C6
#define DEFAULT_SLEEP_OUT_OVERHEAD_US (318)
#define DEFAULT_HARDWARE_OUT_OVERHEAD_US (56)
@@ -216,6 +222,12 @@
#define CHECK_SOURCE(source, value, mask) ((s_config.wakeup_triggers & mask) && \
(source == value))
#if CONFIG_PM_SLP_IRAM_OPT
# define SLEEP_FN_ATTR IRAM_ATTR
#else
# define SLEEP_FN_ATTR
#endif
#define MAX_DSLP_HOOKS 3
static esp_deep_sleep_cb_t s_dslp_cb[MAX_DSLP_HOOKS] = {0};
@@ -525,7 +537,7 @@ static uint32_t s_stopped_tgwdt_bmap = 0;
#endif
// Must be called from critical sections.
static void IRAM_ATTR suspend_timers(uint32_t sleep_flags) {
static SLEEP_FN_ATTR void suspend_timers(uint32_t sleep_flags) {
if (!(sleep_flags & RTC_SLEEP_PD_XTAL)) {
#if SOC_SLEEP_TGWDT_STOP_WORKAROUND
/* If timegroup implemented task watchdog or interrupt watchdog is running, we have to stop it. */
@@ -547,7 +559,7 @@ static void IRAM_ATTR suspend_timers(uint32_t sleep_flags) {
}
// Must be called from critical sections.
static void IRAM_ATTR resume_timers(uint32_t sleep_flags) {
static SLEEP_FN_ATTR void resume_timers(uint32_t sleep_flags) {
if (!(sleep_flags & RTC_SLEEP_PD_XTAL)) {
#if SOC_SLEEP_SYSTIMER_STALL_WORKAROUND
for (uint32_t counter_id = 0; counter_id < SOC_SYSTIMER_COUNTER_NUM; ++counter_id) {
@@ -567,7 +579,7 @@ static void IRAM_ATTR resume_timers(uint32_t sleep_flags) {
}
// [refactor-todo] provide target logic for body of uart functions below
static void IRAM_ATTR flush_uarts(void)
static SLEEP_FN_ATTR void flush_uarts(void)
{
for (int i = 0; i < SOC_UART_HP_NUM; ++i) {
if (uart_ll_is_enabled(i)) {
@@ -582,7 +594,7 @@ static uint32_t s_suspended_uarts_bmap = 0;
* Suspend enabled uarts and return suspended uarts bit map.
* Must be called from critical sections.
*/
FORCE_INLINE_ATTR void suspend_uarts(void)
static SLEEP_FN_ATTR void suspend_uarts(void)
{
s_suspended_uarts_bmap = 0;
for (int i = 0; i < SOC_UART_HP_NUM; ++i) {
@@ -603,7 +615,7 @@ FORCE_INLINE_ATTR void suspend_uarts(void)
}
// Must be called from critical sections
FORCE_INLINE_ATTR void resume_uarts(void)
static SLEEP_FN_ATTR void resume_uarts(void)
{
for (int i = 0; i < SOC_UART_HP_NUM; ++i) {
if (s_suspended_uarts_bmap & 0x1) {
@@ -629,7 +641,7 @@ FORCE_INLINE_ATTR void resume_uarts(void)
completion time has exceeded the wakeup time, we should abandon the flush, skip the sleep and
return ESP_ERR_SLEEP_REJECT.
*/
FORCE_INLINE_ATTR bool light_sleep_uart_prepare(uint32_t sleep_flags, int64_t sleep_duration)
static SLEEP_FN_ATTR bool light_sleep_uart_prepare(uint32_t sleep_flags, int64_t sleep_duration)
{
bool should_skip_sleep = false;
#if !SOC_PM_SUPPORT_TOP_PD || !CONFIG_ESP_CONSOLE_UART
@@ -662,7 +674,7 @@ FORCE_INLINE_ATTR bool light_sleep_uart_prepare(uint32_t sleep_flags, int64_t sl
/**
* These save-restore workaround should be moved to lower layer
*/
FORCE_INLINE_ATTR void misc_modules_sleep_prepare(uint32_t sleep_flags, bool deep_sleep)
static SLEEP_FN_ATTR void misc_modules_sleep_prepare(uint32_t sleep_flags, bool deep_sleep)
{
if (deep_sleep){
for (int n = 0; n < MAX_DSLP_HOOKS; n++) {
@@ -716,7 +728,7 @@ FORCE_INLINE_ATTR void misc_modules_sleep_prepare(uint32_t sleep_flags, bool dee
/**
* These save-restore workaround should be moved to lower layer
*/
FORCE_INLINE_ATTR void misc_modules_wake_prepare(uint32_t sleep_flags)
static SLEEP_FN_ATTR void misc_modules_wake_prepare(uint32_t sleep_flags)
{
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
if (sleep_flags & PMU_SLEEP_PD_TOP) {
@@ -760,7 +772,7 @@ FORCE_INLINE_ATTR void misc_modules_wake_prepare(uint32_t sleep_flags)
#endif
}
static IRAM_ATTR void sleep_low_power_clock_calibration(bool is_dslp)
static SLEEP_FN_ATTR void sleep_low_power_clock_calibration(bool is_dslp)
{
// Calibrate rtc slow clock
#ifdef CONFIG_ESP_SYSTEM_RTC_EXT_XTAL
@@ -800,7 +812,133 @@ static IRAM_ATTR void sleep_low_power_clock_calibration(bool is_dslp)
inline static uint32_t call_rtc_sleep_start(uint32_t reject_triggers, uint32_t lslp_mem_inf_fpu, bool dslp);
static esp_err_t IRAM_ATTR esp_sleep_start(uint32_t sleep_flags, uint32_t clk_flags, esp_sleep_mode_t mode, bool allow_sleep_rejection)
#if SOC_PMU_SUPPORTED
static esp_err_t IRAM_ATTR esp_sleep_start_safe(uint32_t sleep_flags, uint32_t reject_triggers, bool deep_sleep, pmu_sleep_config_t *config)
#else
static esp_err_t IRAM_ATTR esp_sleep_start_safe(uint32_t sleep_flags, uint32_t reject_triggers, bool deep_sleep, rtc_sleep_config_t *config)
#endif
{
esp_err_t result = ESP_OK;
#if CONFIG_ESP_SLEEP_DEBUG
if (s_sleep_ctx != NULL) {
s_sleep_ctx->wakeup_triggers = s_config.wakeup_triggers;
}
#endif
if (deep_sleep) {
#if SOC_GPIO_SUPPORT_HOLD_IO_IN_DSLP && !SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP
esp_sleep_isolate_digital_gpio();
#endif
#if ESP_ROM_SUPPORT_DEEP_SLEEP_WAKEUP_STUB && SOC_DEEP_SLEEP_SUPPORTED
#if SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY
esp_set_deep_sleep_wake_stub_default_entry();
#elif !CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP && SOC_RTC_FAST_MEM_SUPPORTED
/* If not possible stack is in RTC FAST memory, use the ROM function to calculate the CRC and save ~140 bytes IRAM */
set_rtc_memory_crc();
#endif // SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY
#endif
#if SOC_DCDC_SUPPORTED
uint64_t ldo_increased_us = rtc_time_slowclk_to_us(rtc_time_get() - s_config.rtc_ticks_at_ldo_prepare, s_config.rtc_clk_cal_period);
if (ldo_increased_us < LDO_POWER_TAKEOVER_PREPARATION_TIME_US) {
esp_rom_delay_us(LDO_POWER_TAKEOVER_PREPARATION_TIME_US - ldo_increased_us);
}
pmu_sleep_shutdown_dcdc();
#endif
// Enter Deep Sleep
#if!ESP_ROM_SUPPORT_DEEP_SLEEP_WAKEUP_STUB || SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY || !CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP
#if SOC_PMU_SUPPORTED
result = call_rtc_sleep_start(reject_triggers, config->power.hp_sys.dig_power.mem_dslp, deep_sleep);
#else
result = call_rtc_sleep_start(reject_triggers, config->lslp_mem_inf_fpu, deep_sleep);
#endif
#else
/* Otherwise, need to call the dedicated soc function for this */
result = rtc_deep_sleep_start(s_config.wakeup_triggers, reject_triggers);
#endif
} else {
suspend_timers(sleep_flags);
/* Cache Suspend 1: will wait cache idle in cache suspend */
suspend_cache();
/* On esp32c6, only the lp_aon pad hold function can only hold the GPIO state in the active mode.
In order to avoid the leakage of the SPI cs pin, hold it here */
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
if(!(sleep_flags & RTC_SLEEP_PD_VDDSDIO) && (sleep_flags & PMU_SLEEP_PD_TOP)) {
#if CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND
/* Cache suspend also means SPI bus IDLE, then we can hold SPI CS pin safely */
#if !CONFIG_IDF_TARGET_ESP32H2 // ESP32H2 TODO IDF-7359
gpio_ll_hold_en(&GPIO, MSPI_IOMUX_PIN_NUM_CS0);
#endif
#endif
#if CONFIG_ESP_SLEEP_PSRAM_LEAKAGE_WORKAROUND && CONFIG_SPIRAM
/* Cache suspend also means SPI bus IDLE, then we can hold SPI CS pin safely */
gpio_ll_hold_en(&GPIO, MSPI_IOMUX_PIN_NUM_CS1);
#endif
}
#endif
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && SOC_PM_MMU_TABLE_RETENTION_WHEN_TOP_PD
if (sleep_flags & PMU_SLEEP_PD_TOP) {
esp_sleep_mmu_retention(true);
}
#endif
#if SOC_DCDC_SUPPORTED && !CONFIG_ESP_SLEEP_KEEP_DCDC_ALWAYS_ON
uint64_t ldo_increased_us = rtc_time_slowclk_to_us(rtc_time_get() - s_config.rtc_ticks_at_ldo_prepare, s_config.rtc_clk_cal_period);
if (ldo_increased_us < LDO_POWER_TAKEOVER_PREPARATION_TIME_US) {
esp_rom_delay_us(LDO_POWER_TAKEOVER_PREPARATION_TIME_US - ldo_increased_us);
}
pmu_sleep_shutdown_dcdc();
#endif
#if SOC_PMU_SUPPORTED
#if SOC_PM_CPU_RETENTION_BY_SW && ESP_SLEEP_POWER_DOWN_CPU
esp_sleep_execute_event_callbacks(SLEEP_EVENT_HW_GOTO_SLEEP, (void *)0);
if (sleep_flags & (PMU_SLEEP_PD_CPU | PMU_SLEEP_PD_TOP)) {
result = esp_sleep_cpu_retention(pmu_sleep_start, s_config.wakeup_triggers, reject_triggers, config->power.hp_sys.dig_power.mem_dslp, deep_sleep);
} else
#endif
{
#if !CONFIG_FREERTOS_UNICORE && ESP_SLEEP_POWER_DOWN_CPU && SOC_PM_CPU_RETENTION_BY_SW
// Skip smp retention if CPU power domain power-down is not allowed
esp_sleep_cpu_skip_retention();
#endif
result = call_rtc_sleep_start(reject_triggers, config->power.hp_sys.dig_power.mem_dslp, deep_sleep);
}
esp_sleep_execute_event_callbacks(SLEEP_EVENT_HW_EXIT_SLEEP, (void *)0);
#else
result = call_rtc_sleep_start(reject_triggers, config->lslp_mem_inf_fpu, deep_sleep);
#endif
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && SOC_PM_MMU_TABLE_RETENTION_WHEN_TOP_PD
if (sleep_flags & PMU_SLEEP_PD_TOP) {
esp_sleep_mmu_retention(false);
}
#endif
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
/* Unhold the SPI CS pin */
if(!(sleep_flags & RTC_SLEEP_PD_VDDSDIO) && (sleep_flags & PMU_SLEEP_PD_TOP)) {
#if CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND
#if !CONFIG_IDF_TARGET_ESP32H2 // ESP32H2 TODO IDF-7359
gpio_ll_hold_dis(&GPIO, MSPI_IOMUX_PIN_NUM_CS0);
#endif
#endif
#if CONFIG_ESP_SLEEP_PSRAM_LEAKAGE_WORKAROUND && CONFIG_SPIRAM
gpio_ll_hold_dis(&GPIO, MSPI_IOMUX_PIN_NUM_CS1);
#endif
}
#endif
/* Cache Resume 1: Resume cache for continue running*/
resume_cache();
resume_timers(sleep_flags);
}
return result;
}
static esp_err_t SLEEP_FN_ATTR esp_sleep_start(uint32_t sleep_flags, uint32_t clk_flags, esp_sleep_mode_t mode, bool allow_sleep_rejection)
{
// Stop UART output so that output is not lost due to APB frequency change.
// For light sleep, suspend UART output — it will resume after wakeup.
@@ -980,123 +1118,7 @@ static esp_err_t IRAM_ATTR esp_sleep_start(uint32_t sleep_flags, uint32_t clk_fl
esp_sleep_cpu_skip_retention();
#endif
} else {
#if CONFIG_ESP_SLEEP_DEBUG
if (s_sleep_ctx != NULL) {
s_sleep_ctx->wakeup_triggers = s_config.wakeup_triggers;
}
#endif
if (deep_sleep) {
#if SOC_GPIO_SUPPORT_HOLD_IO_IN_DSLP && !SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP
esp_sleep_isolate_digital_gpio();
#endif
#if ESP_ROM_SUPPORT_DEEP_SLEEP_WAKEUP_STUB && SOC_DEEP_SLEEP_SUPPORTED
#if SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY
esp_set_deep_sleep_wake_stub_default_entry();
#elif !CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP && SOC_RTC_FAST_MEM_SUPPORTED
/* If not possible stack is in RTC FAST memory, use the ROM function to calculate the CRC and save ~140 bytes IRAM */
set_rtc_memory_crc();
#endif // SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY
#endif
#if SOC_DCDC_SUPPORTED
uint64_t ldo_increased_us = rtc_time_slowclk_to_us(rtc_time_get() - s_config.rtc_ticks_at_ldo_prepare, s_config.rtc_clk_cal_period);
if (ldo_increased_us < LDO_POWER_TAKEOVER_PREPARATION_TIME_US) {
esp_rom_delay_us(LDO_POWER_TAKEOVER_PREPARATION_TIME_US - ldo_increased_us);
}
pmu_sleep_shutdown_dcdc();
#endif
// Enter Deep Sleep
#if!ESP_ROM_SUPPORT_DEEP_SLEEP_WAKEUP_STUB || SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY || !CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP
#if SOC_PMU_SUPPORTED
result = call_rtc_sleep_start(reject_triggers, config.power.hp_sys.dig_power.mem_dslp, deep_sleep);
#else
result = call_rtc_sleep_start(reject_triggers, config.lslp_mem_inf_fpu, deep_sleep);
#endif
#else
/* Otherwise, need to call the dedicated soc function for this */
result = rtc_deep_sleep_start(s_config.wakeup_triggers, reject_triggers);
#endif
} else {
suspend_timers(sleep_flags);
/* Cache Suspend 1: will wait cache idle in cache suspend */
suspend_cache();
/* On esp32c6, only the lp_aon pad hold function can only hold the GPIO state in the active mode.
In order to avoid the leakage of the SPI cs pin, hold it here */
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
if(!(sleep_flags & RTC_SLEEP_PD_VDDSDIO) && (sleep_flags & PMU_SLEEP_PD_TOP)) {
#if CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND
/* Cache suspend also means SPI bus IDLE, then we can hold SPI CS pin safely */
#if !CONFIG_IDF_TARGET_ESP32H2 // ESP32H2 TODO IDF-7359
gpio_ll_hold_en(&GPIO, MSPI_IOMUX_PIN_NUM_CS0);
#endif
#endif
#if CONFIG_ESP_SLEEP_PSRAM_LEAKAGE_WORKAROUND && CONFIG_SPIRAM
/* Cache suspend also means SPI bus IDLE, then we can hold SPI CS pin safely */
gpio_ll_hold_en(&GPIO, MSPI_IOMUX_PIN_NUM_CS1);
#endif
}
#endif
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && SOC_PM_MMU_TABLE_RETENTION_WHEN_TOP_PD
if (sleep_flags & PMU_SLEEP_PD_TOP) {
esp_sleep_mmu_retention(true);
}
#endif
#if SOC_DCDC_SUPPORTED && !CONFIG_ESP_SLEEP_KEEP_DCDC_ALWAYS_ON
uint64_t ldo_increased_us = rtc_time_slowclk_to_us(rtc_time_get() - s_config.rtc_ticks_at_ldo_prepare, s_config.rtc_clk_cal_period);
if (ldo_increased_us < LDO_POWER_TAKEOVER_PREPARATION_TIME_US) {
esp_rom_delay_us(LDO_POWER_TAKEOVER_PREPARATION_TIME_US - ldo_increased_us);
}
pmu_sleep_shutdown_dcdc();
#endif
#if SOC_PMU_SUPPORTED
#if SOC_PM_CPU_RETENTION_BY_SW && ESP_SLEEP_POWER_DOWN_CPU
esp_sleep_execute_event_callbacks(SLEEP_EVENT_HW_GOTO_SLEEP, (void *)0);
if (sleep_flags & (PMU_SLEEP_PD_CPU | PMU_SLEEP_PD_TOP)) {
result = esp_sleep_cpu_retention(pmu_sleep_start, s_config.wakeup_triggers, reject_triggers, config.power.hp_sys.dig_power.mem_dslp, deep_sleep);
} else
#endif
{
#if !CONFIG_FREERTOS_UNICORE && ESP_SLEEP_POWER_DOWN_CPU && SOC_PM_CPU_RETENTION_BY_SW
// Skip smp retention if CPU power domain power-down is not allowed
esp_sleep_cpu_skip_retention();
#endif
result = call_rtc_sleep_start(reject_triggers, config.power.hp_sys.dig_power.mem_dslp, deep_sleep);
}
esp_sleep_execute_event_callbacks(SLEEP_EVENT_HW_EXIT_SLEEP, (void *)0);
#else
result = call_rtc_sleep_start(reject_triggers, config.lslp_mem_inf_fpu, deep_sleep);
#endif
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && SOC_PM_MMU_TABLE_RETENTION_WHEN_TOP_PD
if (sleep_flags & PMU_SLEEP_PD_TOP) {
esp_sleep_mmu_retention(false);
}
#endif
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
/* Unhold the SPI CS pin */
if(!(sleep_flags & RTC_SLEEP_PD_VDDSDIO) && (sleep_flags & PMU_SLEEP_PD_TOP)) {
#if CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND
#if !CONFIG_IDF_TARGET_ESP32H2 // ESP32H2 TODO IDF-7359
gpio_ll_hold_dis(&GPIO, MSPI_IOMUX_PIN_NUM_CS0);
#endif
#endif
#if CONFIG_ESP_SLEEP_PSRAM_LEAKAGE_WORKAROUND && CONFIG_SPIRAM
gpio_ll_hold_dis(&GPIO, MSPI_IOMUX_PIN_NUM_CS1);
#endif
}
#endif
/* Cache Resume 1: Resume cache for continue running*/
resume_cache();
resume_timers(sleep_flags);
}
result = esp_sleep_start_safe(sleep_flags, reject_triggers, deep_sleep, &config);
}
#if CONFIG_ESP_SLEEP_CACHE_SAFE_ASSERTION
if (sleep_flags & RTC_SLEEP_PD_VDDSDIO) {
@@ -1119,6 +1141,21 @@ static esp_err_t IRAM_ATTR esp_sleep_start(uint32_t sleep_flags, uint32_t clk_fl
if (!deep_sleep) {
if (result == ESP_OK) {
#if !CONFIG_PM_SLP_IRAM_OPT && !CONFIG_IDF_TARGET_ESP32
#if CONFIG_SPIRAM
# if CONFIG_IDF_TARGET_ESP32P4
cache_ll_writeback_all(CACHE_LL_LEVEL_ALL, CACHE_TYPE_DATA, CACHE_LL_ID_ALL);
# else
Cache_WriteBack_All();
# endif
#endif
/* When the IRAM optimization for the sleep flow is disabled, all
* cache contents are forcibly invalidated before exiting the sleep
* flow. This ensures that the code execution time of sleep exit
* flow remains consistent, allowing the use of ccount to
* dynamically calculate the sleep adjustment time. */
cache_ll_invalidate_all(CACHE_LL_LEVEL_ALL, CACHE_TYPE_ALL, CACHE_LL_ID_ALL);
#endif
s_config.ccount_ticks_record = esp_cpu_get_cycle_count();
#if SOC_PM_RETENTION_SW_TRIGGER_REGDMA
if (sleep_flags & PMU_SLEEP_PD_TOP) {
@@ -1254,9 +1291,9 @@ esp_err_t IRAM_ATTR esp_deep_sleep_try_to_start(void)
* Placed into IRAM as flash may need some time to be powered on.
*/
static esp_err_t esp_light_sleep_inner(uint32_t sleep_flags, uint32_t clk_flags,
uint32_t flash_enable_time_us) IRAM_ATTR __attribute__((noinline));
uint32_t flash_enable_time_us) __attribute__((noinline));
static esp_err_t esp_light_sleep_inner(uint32_t sleep_flags, uint32_t clk_flags,
static SLEEP_FN_ATTR esp_err_t esp_light_sleep_inner(uint32_t sleep_flags, uint32_t clk_flags,
uint32_t flash_enable_time_us)
{
#if SOC_CONFIGURABLE_VDDSDIO_SUPPORTED
@@ -1687,7 +1724,7 @@ esp_err_t esp_sleep_enable_vad_wakeup(void)
}
#endif
static esp_err_t timer_wakeup_prepare(int64_t sleep_duration)
static SLEEP_FN_ATTR esp_err_t timer_wakeup_prepare(int64_t sleep_duration)
{
if (sleep_duration < 0) {
sleep_duration = 0;
@@ -2325,7 +2362,7 @@ FORCE_INLINE_ATTR bool top_domain_pd_allowed(void) {
}
#endif
static uint32_t get_power_down_flags(void)
static SLEEP_FN_ATTR uint32_t get_power_down_flags(void)
{
// Where needed, convert AUTO options to ON. Later interpret AUTO as OFF.
@@ -2502,7 +2539,7 @@ static uint32_t get_power_down_flags(void)
return pd_flags;
}
static uint32_t get_sleep_flags(uint32_t sleep_flags, bool deepsleep)
static SLEEP_FN_ATTR uint32_t get_sleep_flags(uint32_t sleep_flags, bool deepsleep)
{
// Override user-configured FOSC power modes.
if (s_sleep_sub_mode_ref_cnt[ESP_SLEEP_RTC_USE_RC_FAST_MODE]) {
@@ -2554,7 +2591,7 @@ static uint32_t get_sleep_flags(uint32_t sleep_flags, bool deepsleep)
return sleep_flags;
}
static uint32_t get_sleep_clock_icg_flags(void)
static SLEEP_FN_ATTR uint32_t get_sleep_clock_icg_flags(void)
{
uint32_t clk_flags = 0;