feat(esp_hw_support): add flash deep power down support during sleep

This commit is contained in:
hebinglin
2025-11-28 20:50:41 +08:00
parent e29c2c9a36
commit b5ae961c6c
10 changed files with 77 additions and 19 deletions

View File

@@ -219,6 +219,7 @@ menu "Hardware Settings"
bool "Set SPI flash to deep power-down mode in light sleep"
depends on (!APP_BUILD_TYPE_PURE_RAM_APP && !ESP_SLEEP_POWER_DOWN_FLASH && !SPI_FLASH_ROM_IMPL)
default y if (IDF_TARGET_ESP32H4 || IDF_TARGET_ESP32H21)
default y if (IDF_TARGET_ESP32P4 && ESP32P4_SELECTS_REV_LESS_V3)
default n
help
Deep Power-Down mode is a power mode supported by most SPI Flash, SPI Flash has better power
@@ -236,7 +237,7 @@ menu "Hardware Settings"
config ESP_SLEEP_SPI_FLASH_ENTER_DPD_MODE_DELAY
int "SPI Flash enter deep power-down time delay (in us)"
depends on ESP_SLEEP_SET_FLASH_DPD
default 20
default 25
range 0 100
help
When used to set the SPI Flash to enter the Deep Power-Down mode, the command is issued by driving

View File

@@ -47,6 +47,7 @@ typedef enum {
#define RTC_SLEEP_PD_MODEM PMU_SLEEP_PD_MODEM //!< Power down modem(include wifi, ble and 15.4)
//These flags are not power domains, but will affect some sleep parameters
#define RTC_SLEEP_FLASH_DPD BIT(24)
#define RTC_SLEEP_LP_PERIPH_USE_RC_FAST BIT(25)
#define RTC_SLEEP_POWER_BY_VBAT BIT(26)
#define RTC_SLEEP_DIG_USE_8M BIT(27)

View File

@@ -530,6 +530,7 @@ typedef struct rtc_sleep_config_s {
#define RTC_SLEEP_USE_ADC_TESEN_MONITOR BIT(17)
#define RTC_SLEEP_NO_ULTRA_LOW BIT(18) //!< Avoid using ultra low power in deep sleep, in which RTCIO cannot be used as input, and RTCMEM can't work under high temperature
#define RTC_SLEEP_XTAL_AS_RTC_FAST BIT(19)
#define RTC_SLEEP_FLASH_DPD BIT(20)
/**
* Default initializer for rtc_sleep_config_t
*

View File

@@ -567,6 +567,7 @@ typedef struct {
#define RTC_SLEEP_USE_ADC_TESEN_MONITOR BIT(17)
#define RTC_SLEEP_NO_ULTRA_LOW BIT(18) //!< Avoid using ultra low power in deep sleep, in which RTCIO cannot be used as input, and RTCMEM can't work under high temperature
#define RTC_SLEEP_XTAL_AS_RTC_FAST BIT(19)
#define RTC_SLEEP_FLASH_DPD BIT(20)
/**
* Default initializer for rtc_sleep_config_t

View File

@@ -615,6 +615,7 @@ typedef struct {
#define RTC_SLEEP_USE_ADC_TESEN_MONITOR BIT(17)
#define RTC_SLEEP_NO_ULTRA_LOW BIT(18) //!< Avoid using ultra low power in deep sleep, in which RTCIO cannot be used as input, and RTCMEM can't work under high temperature
#define RTC_SLEEP_XTAL_AS_RTC_FAST BIT(19)
#define RTC_SLEEP_FLASH_DPD BIT(20)
/**
* Default initializer for rtc_sleep_config_t

View File

@@ -91,7 +91,7 @@ void pmu_hp_system_init(pmu_context_t *ctx, pmu_hp_mode_t mode, pmu_hp_system_pa
pmu_ll_hp_set_bias_sleep_enable (ctx->hal->dev, mode, anlg->bias.bias_sleep);
pmu_ll_hp_set_regulator_sleep_memory_xpd (ctx->hal->dev, mode, anlg->regulator0.slp_mem_xpd);
pmu_ll_hp_set_regulator_sleep_logic_xpd (ctx->hal->dev, mode, anlg->regulator0.slp_logic_xpd);
if (ESP_CHIP_REV_ABOVE(efuse_hal_chip_revision(), 100) && (mode == PMU_MODE_HP_SLEEP)) {
if (ESP_CHIP_REV_ABOVE(efuse_hal_chip_revision(), 300) && (mode == PMU_MODE_HP_SLEEP)) {
pmu_ll_hp_enable_sleep_flash_ldo_channel(ctx->hal->dev, anlg->regulator0.xpd_0p1a);
}
pmu_ll_hp_set_regulator_sleep_logic_dbias (ctx->hal->dev, mode, anlg->regulator0.slp_logic_dbias);

View File

@@ -176,7 +176,11 @@ const pmu_sleep_config_t* pmu_sleep_config_default(
config->digital = digital_default;
pmu_sleep_analog_config_t analog_default = PMU_SLEEP_ANALOG_DSLP_CONFIG_DEFAULT(sleep_flags);
analog_default.hp_sys.analog.xpd_0p1a = 0;
if (sleep_flags & PMU_SLEEP_PD_VDDSDIO) {
analog_default.hp_sys.analog.xpd_0p1a = 0;
} else {
analog_default.hp_sys.analog.xpd_0p1a = 1;
}
config->analog = analog_default;
if (sleep_flags & RTC_SLEEP_POWER_BY_VBAT) {
@@ -296,7 +300,7 @@ static void pmu_sleep_analog_init(pmu_context_t *ctx, const pmu_sleep_analog_con
pmu_ll_hp_set_regulator_sleep_memory_xpd (ctx->hal->dev, HP(SLEEP), analog->hp_sys.analog.slp_mem_xpd);
pmu_ll_hp_set_regulator_sleep_logic_xpd (ctx->hal->dev, HP(SLEEP), analog->hp_sys.analog.slp_logic_xpd);
pmu_ll_hp_set_regulator_xpd (ctx->hal->dev, HP(SLEEP), analog->hp_sys.analog.xpd);
if (ESP_CHIP_REV_ABOVE(efuse_hal_chip_revision(), 100)) {
if (ESP_CHIP_REV_ABOVE(efuse_hal_chip_revision(), 300)) {
pmu_ll_hp_enable_sleep_flash_ldo_channel(ctx->hal->dev, analog->hp_sys.analog.xpd_0p1a);
}
pmu_ll_hp_set_regulator_sleep_logic_dbias (ctx->hal->dev, HP(SLEEP), analog->hp_sys.analog.slp_logic_dbias);

View File

@@ -640,6 +640,7 @@ typedef struct {
#define RTC_SLEEP_USE_ADC_TESEN_MONITOR BIT(17)
#define RTC_SLEEP_NO_ULTRA_LOW BIT(18) //!< Avoid using ultra low power in deep sleep, in which RTCIO cannot be used as input, and RTCMEM can't work under high temperature
#define RTC_SLEEP_XTAL_AS_RTC_FAST BIT(19)
#define RTC_SLEEP_FLASH_DPD BIT(20)
/**
* Default initializer for rtc_sleep_config_t

View File

@@ -626,6 +626,7 @@ typedef struct {
#define RTC_SLEEP_USE_ADC_TESEN_MONITOR BIT(17)
#define RTC_SLEEP_NO_ULTRA_LOW BIT(18) //!< Avoid using ultra low power in deep sleep, in which RTCIO cannot be used as input, and RTCMEM can't work under high temperature
#define RTC_SLEEP_XTAL_AS_RTC_FAST BIT(19)
#define RTC_SLEEP_FLASH_DPD BIT(20)
/**
* Default initializer for rtc_sleep_config_t

View File

@@ -26,6 +26,7 @@
#include "esp_private/sleep_retention.h"
#include "esp_private/io_mux.h"
#include "esp_private/critical_section.h"
#include "esp_private/spi_flash_os.h"
#include "esp_log.h"
#include "esp_newlib.h"
#include "esp_timer.h"
@@ -911,6 +912,14 @@ static esp_err_t FORCE_IRAM_ATTR esp_sleep_start_safe(uint32_t sleep_flags, uint
esp_sleep_isolate_digital_gpio();
#endif
#if CONFIG_IDF_TARGET_ESP32P4 && CONFIG_ESP_SLEEP_SET_FLASH_DPD
if ((sleep_flags & RTC_SLEEP_FLASH_DPD) && (!ESP_CHIP_REV_ABOVE(efuse_hal_chip_revision(), 300))) {
/* Switch Flash from standby mode to deep powerdown mode */
/* During bootloader phase following wakeup from deepsleep, flash will exit dpd mode */
spi_flash_enable_deep_power_down_mode(true);
}
#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();
@@ -943,21 +952,28 @@ static esp_err_t FORCE_IRAM_ATTR esp_sleep_start_safe(uint32_t sleep_flags, uint
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 (!(sleep_flags & RTC_SLEEP_PD_VDDSDIO)) {
#if CONFIG_ESP_SLEEP_SET_FLASH_DPD
if (sleep_flags & RTC_SLEEP_FLASH_DPD) {
/* Switch Flash from standby mode to deep powerdown mode */
spi_flash_enable_deep_power_down_mode(true);
}
#endif
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
if(!(sleep_flags & RTC_SLEEP_PD_VDDSDIO) && (sleep_flags & PMU_SLEEP_PD_TOP)) {
/* 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(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 */
gpio_ll_hold_en(&GPIO, MSPI_IOMUX_PIN_NUM_CS0);
/* Cache suspend also means SPI bus IDLE, then we can hold SPI CS pin safely */
gpio_ll_hold_en(&GPIO, MSPI_IOMUX_PIN_NUM_CS0);
#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);
/* 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
}
#endif
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
if (sleep_flags & PMU_SLEEP_PD_TOP) {
@@ -1408,6 +1424,13 @@ static SLEEP_FN_ATTR esp_err_t esp_light_sleep_inner(uint32_t sleep_flags, uint3
#endif
// Wait for the flash chip to start up
esp_rom_delay_us(flash_enable_time_us);
} else {
#if CONFIG_ESP_SLEEP_SET_FLASH_DPD
if (sleep_flags & RTC_SLEEP_FLASH_DPD) {
//Release Flash out from deep powerdown mode
spi_flash_enable_deep_power_down_mode(false);
}
#endif
}
#if CONFIG_ESP_SLEEP_CACHE_SAFE_ASSERTION
@@ -1592,6 +1615,23 @@ esp_err_t esp_light_sleep_start(void)
s_config.sleep_time_adjustment -= flash_enable_time_us;
}
}
} else if (!(sleep_flags & RTC_SLEEP_PD_VDDSDIO)) {
#if CONFIG_ESP_SLEEP_SET_FLASH_DPD
const uint32_t flash_enable_dpd_us = spi_flash_dpd_get_enter_duration() + spi_flash_dpd_get_exit_duration();
if (s_config.sleep_duration > flash_enable_dpd_us) {
if (s_config.sleep_time_overhead_out < flash_enable_dpd_us) {
s_config.sleep_time_adjustment += flash_enable_dpd_us;
}
} else {
/**
* Minimum sleep time is not enough, then reject flash enter deep power-down mode
*/
sleep_flags &= ~RTC_SLEEP_FLASH_DPD;
if (s_config.sleep_time_overhead_out > flash_enable_dpd_us) {
s_config.sleep_time_adjustment -= flash_enable_dpd_us;
}
}
#endif
}
periph_inform_out_light_sleep_overhead(s_config.sleep_time_adjustment - sleep_time_overhead_in);
@@ -2757,11 +2797,6 @@ static SLEEP_FN_ATTR uint32_t get_power_down_flags(void)
if (s_config.domain[ESP_PD_DOMAIN_VDDSDIO].pd_option == ESP_PD_OPTION_AUTO) {
#ifndef CONFIG_ESP_SLEEP_POWER_DOWN_FLASH
s_config.domain[ESP_PD_DOMAIN_VDDSDIO].pd_option = ESP_PD_OPTION_ON;
#endif
#if CONFIG_IDF_TARGET_ESP32P4
if (!ESP_CHIP_REV_ABOVE(efuse_hal_chip_revision(), 100)) {
s_config.domain[ESP_PD_DOMAIN_VDDSDIO].pd_option = ESP_PD_OPTION_ON;
}
#endif
}
#endif
@@ -2850,8 +2885,15 @@ static SLEEP_FN_ATTR uint32_t get_power_down_flags(void)
}
#endif
#if CONFIG_ESP_SLEEP_SET_FLASH_DPD
if (!(pd_flags & RTC_SLEEP_PD_VDDSDIO)) {
// Flash power domain will disable DPD mode.
pd_flags |= RTC_SLEEP_FLASH_DPD;
}
#endif
#if CONFIG_IDF_TARGET_ESP32P4
if (!ESP_CHIP_REV_ABOVE(efuse_hal_chip_revision(), 100)) {
if (!ESP_CHIP_REV_ABOVE(efuse_hal_chip_revision(), 300)) {
if (pd_flags & RTC_SLEEP_PD_VDDSDIO) {
ESP_LOGE(TAG, "ESP32P4 chips lower than v1.0 are not allowed to power down the Flash");
}
@@ -2934,6 +2976,11 @@ static SLEEP_FN_ATTR uint32_t get_sleep_flags(uint32_t sleep_flags, bool deepsle
if (!ESP_CHIP_REV_ABOVE(efuse_hal_chip_revision(), 1)) {
sleep_flags &= ~RTC_SLEEP_PD_RTC_PERIPH;
}
/* The LDO VO1 channel that powers the Flash on esp32p4(<v3) has leakage voltage during deepsleep,
which may cause the Flash to enter an abnormal state, so disable Flash power-down feature on esp32p4(<v3). */
if (!ESP_CHIP_REV_ABOVE(efuse_hal_chip_revision(), 300)) {
sleep_flags &= ~RTC_SLEEP_PD_VDDSDIO;
}
#endif
return sleep_flags;