diff --git a/components/esp_hw_support/Kconfig b/components/esp_hw_support/Kconfig index 48c66d1137..8561d769b0 100644 --- a/components/esp_hw_support/Kconfig +++ b/components/esp_hw_support/Kconfig @@ -281,6 +281,8 @@ menu "Hardware Settings" endmenu + orsource "./port/$IDF_TARGET/Kconfig.dcdc" + orsource "./port/$IDF_TARGET/Kconfig.ldo" # Invisible bringup bypass options for esp_hw_support component diff --git a/components/esp_hw_support/include/esp_private/esp_pmu.h b/components/esp_hw_support/include/esp_private/esp_pmu.h index 827dce4482..02a2c5762f 100644 --- a/components/esp_hw_support/include/esp_private/esp_pmu.h +++ b/components/esp_hw_support/include/esp_private/esp_pmu.h @@ -277,7 +277,7 @@ void pmu_sleep_shutdown_dcdc(void); * @brief DCDC has taken over power supply, shut down LDO to save power consumption */ void pmu_sleep_shutdown_ldo(void); -#endif +#endif // SOC_DCDC_SUPPORTED /** * @brief Enter deep or light sleep mode @@ -309,9 +309,10 @@ uint32_t pmu_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt, uint32_t lslp /** * @brief Finish sleep process settings and get sleep reject status + * @param dslp True if sleep requests id deep-sleep * @return return sleep reject status */ -bool pmu_sleep_finish(void); +bool pmu_sleep_finish(bool dslp); /** * @brief Initialize PMU related power/clock/digital parameters and functions diff --git a/components/esp_hw_support/lowpower/cpu_retention/port/esp32c5/sleep_cpu.c b/components/esp_hw_support/lowpower/cpu_retention/port/esp32c5/sleep_cpu.c index 2ed461d280..69d2abc5d3 100644 --- a/components/esp_hw_support/lowpower/cpu_retention/port/esp32c5/sleep_cpu.c +++ b/components/esp_hw_support/lowpower/cpu_retention/port/esp32c5/sleep_cpu.c @@ -435,7 +435,7 @@ static IRAM_ATTR esp_err_t do_cpu_retention(sleep_cpu_entry_cb_t goto_sleep, } #endif - return pmu_sleep_finish(); + return pmu_sleep_finish(dslp); } esp_err_t IRAM_ATTR esp_sleep_cpu_retention(uint32_t (*goto_sleep)(uint32_t, uint32_t, uint32_t, bool), diff --git a/components/esp_hw_support/lowpower/cpu_retention/port/esp32c6/sleep_cpu.c b/components/esp_hw_support/lowpower/cpu_retention/port/esp32c6/sleep_cpu.c index 8d0b0a2bc7..66adf7de72 100644 --- a/components/esp_hw_support/lowpower/cpu_retention/port/esp32c6/sleep_cpu.c +++ b/components/esp_hw_support/lowpower/cpu_retention/port/esp32c6/sleep_cpu.c @@ -475,7 +475,7 @@ static IRAM_ATTR esp_err_t do_cpu_retention(sleep_cpu_entry_cb_t goto_sleep, } #endif - return pmu_sleep_finish(); + return pmu_sleep_finish(dslp); } esp_err_t IRAM_ATTR esp_sleep_cpu_retention(uint32_t (*goto_sleep)(uint32_t, uint32_t, uint32_t, bool), diff --git a/components/esp_hw_support/lowpower/cpu_retention/port/esp32h2/sleep_cpu.c b/components/esp_hw_support/lowpower/cpu_retention/port/esp32h2/sleep_cpu.c index c020247710..c4ed689309 100644 --- a/components/esp_hw_support/lowpower/cpu_retention/port/esp32h2/sleep_cpu.c +++ b/components/esp_hw_support/lowpower/cpu_retention/port/esp32h2/sleep_cpu.c @@ -475,7 +475,7 @@ static IRAM_ATTR esp_err_t do_cpu_retention(sleep_cpu_entry_cb_t goto_sleep, } #endif - return pmu_sleep_finish(); + return pmu_sleep_finish(dslp); } esp_err_t IRAM_ATTR esp_sleep_cpu_retention(uint32_t (*goto_sleep)(uint32_t, uint32_t, uint32_t, bool), diff --git a/components/esp_hw_support/lowpower/cpu_retention/port/esp32p4/sleep_cpu.c b/components/esp_hw_support/lowpower/cpu_retention/port/esp32p4/sleep_cpu.c index 740fcc722d..e7756703bc 100644 --- a/components/esp_hw_support/lowpower/cpu_retention/port/esp32p4/sleep_cpu.c +++ b/components/esp_hw_support/lowpower/cpu_retention/port/esp32p4/sleep_cpu.c @@ -429,7 +429,7 @@ static TCM_IRAM_ATTR esp_err_t do_cpu_retention(sleep_cpu_entry_cb_t goto_sleep, } #endif - return pmu_sleep_finish(); + return pmu_sleep_finish(dslp); } esp_err_t TCM_IRAM_ATTR esp_sleep_cpu_retention(uint32_t (*goto_sleep)(uint32_t, uint32_t, uint32_t, bool), diff --git a/components/esp_hw_support/port/esp32c5/pmu_sleep.c b/components/esp_hw_support/port/esp32c5/pmu_sleep.c index 6d8e27faf3..262ce0086e 100644 --- a/components/esp_hw_support/port/esp32c5/pmu_sleep.c +++ b/components/esp_hw_support/port/esp32c5/pmu_sleep.c @@ -274,11 +274,12 @@ uint32_t pmu_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt, uint32_t lslp ; } - return pmu_sleep_finish(); + return pmu_sleep_finish(dslp); } -bool pmu_sleep_finish(void) +bool pmu_sleep_finish(bool dslp) { + (void)dslp; return pmu_ll_hp_is_sleep_reject(PMU_instance()->hal->dev); } diff --git a/components/esp_hw_support/port/esp32c6/pmu_sleep.c b/components/esp_hw_support/port/esp32c6/pmu_sleep.c index 7396e41b8c..b6c11b8632 100644 --- a/components/esp_hw_support/port/esp32c6/pmu_sleep.c +++ b/components/esp_hw_support/port/esp32c6/pmu_sleep.c @@ -341,11 +341,12 @@ uint32_t pmu_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt, uint32_t lslp ; } - return pmu_sleep_finish(); + return pmu_sleep_finish(dslp); } -bool pmu_sleep_finish(void) +bool pmu_sleep_finish(bool dslp) { + (void)dslp; return pmu_ll_hp_is_sleep_reject(PMU_instance()->hal->dev); } diff --git a/components/esp_hw_support/port/esp32h2/pmu_sleep.c b/components/esp_hw_support/port/esp32h2/pmu_sleep.c index a59e81f1ec..ab32613ab5 100644 --- a/components/esp_hw_support/port/esp32h2/pmu_sleep.c +++ b/components/esp_hw_support/port/esp32h2/pmu_sleep.c @@ -258,11 +258,12 @@ uint32_t pmu_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt, uint32_t lslp ; } - return ESP_OK; + return pmu_sleep_finish(dslp); } -bool pmu_sleep_finish(void) +bool pmu_sleep_finish(bool dslp) { + (void)dslp; return pmu_ll_hp_is_sleep_reject(PMU_instance()->hal->dev); } diff --git a/components/esp_hw_support/port/esp32p4/Kconfig.dcdc b/components/esp_hw_support/port/esp32p4/Kconfig.dcdc new file mode 100644 index 0000000000..a4d3ab3d37 --- /dev/null +++ b/components/esp_hw_support/port/esp32p4/Kconfig.dcdc @@ -0,0 +1,30 @@ +menu "DCDC Regulator Configurations" + depends on SOC_GP_LDO_SUPPORTED + + config ESP_SLEEP_KEEP_DCDC_ALWAYS_ON + bool "Keep DC-DC power always on during light-sleep" + default y + help + ESP32P4 will switch the power supply to LDO before sleeping, and switch to DCDC after waking up. + These two processes take a long time and may bring some risks for some short duration + light sleep. (DCDC -> LDO: 2.5ms (max), LDO -> DCDC: 1.2 ms) + Enabling this option will make chip powered by DCDC during light sleep to reduce some power switch + risks, this will also increase the power consumption during the light sleep. + + DO NOT DISABLE UNLESS YOU KNOW WHAT YOU ARE DOING. + + config ESP_SLEEP_DCM_VSET_VAL_IN_SLEEP + int "DCDC voltage parameter during sleep" + default 14 + range 0 31 + depends on ESP_SLEEP_KEEP_DCDC_ALWAYS_ON + help + This value determines the voltage of the DCDC chip during sleep. The same parameter value may + correspond to different voltage values on different models of DCDC chips. Please update this + value according to the model of external DCDC selected in your hardware solution. + + For the DCDC chip model recommended by ESP, the recommended configuration + values are listed below: + + - TI-TLV62569/TLV62569P: 14 +endmenu diff --git a/components/esp_hw_support/port/esp32p4/pmu_init.c b/components/esp_hw_support/port/esp32p4/pmu_init.c index a0d3c53be2..92d67002fd 100644 --- a/components/esp_hw_support/port/esp32p4/pmu_init.c +++ b/components/esp_hw_support/port/esp32p4/pmu_init.c @@ -79,7 +79,6 @@ void pmu_hp_system_init(pmu_context_t *ctx, pmu_hp_mode_t mode, pmu_hp_system_pa pmu_ll_hp_set_bias_xpd (ctx->hal->dev, mode, anlg->bias.xpd_bias); pmu_ll_hp_set_dcm_mode (ctx->hal->dev, mode, anlg->bias.dcm_mode); pmu_ll_hp_set_dcm_vset (ctx->hal->dev, mode, anlg->bias.dcm_vset); - pmu_ll_hp_set_bias_xpd (ctx->hal->dev, mode, anlg->bias.xpd_bias); pmu_ll_hp_set_dbg_atten (ctx->hal->dev, mode, anlg->bias.dbg_atten); pmu_ll_hp_set_current_power_off (ctx->hal->dev, mode, anlg->bias.pd_cur); pmu_ll_hp_set_bias_sleep_enable (ctx->hal->dev, mode, anlg->bias.bias_sleep); diff --git a/components/esp_hw_support/port/esp32p4/pmu_sleep.c b/components/esp_hw_support/port/esp32p4/pmu_sleep.c index 3b0487157c..0b3d5cbaf2 100644 --- a/components/esp_hw_support/port/esp32p4/pmu_sleep.c +++ b/components/esp_hw_support/port/esp32p4/pmu_sleep.c @@ -149,26 +149,35 @@ const pmu_sleep_config_t* pmu_sleep_config_default( iram_pd_flags |= (pd_flags & PMU_SLEEP_PD_MEM_G1) ? BIT(1) : 0; iram_pd_flags |= (pd_flags & PMU_SLEEP_PD_MEM_G2) ? BIT(2) : 0; iram_pd_flags |= (pd_flags & PMU_SLEEP_PD_MEM_G3) ? BIT(3) : 0; - config->power = power_default; - - pmu_sleep_param_config_t param_default = PMU_SLEEP_PARAM_CONFIG_DEFAULT(pd_flags); - config->param = *pmu_sleep_param_config_default(¶m_default, &power_default, pd_flags, adjustment, slowclk_period, fastclk_period); if (dslp) { config->param.lp_sys.analog_wait_target_cycle = rtc_time_us_to_slowclk(PMU_LP_ANALOG_WAIT_TARGET_TIME_DSLP_US, slowclk_period); pmu_sleep_analog_config_t analog_default = PMU_SLEEP_ANALOG_DSLP_CONFIG_DEFAULT(pd_flags); config->analog = analog_default; } else { + // Get light sleep digital_default pmu_sleep_digital_config_t digital_default = PMU_SLEEP_DIGITAL_LSLP_CONFIG_DEFAULT(pd_flags); config->digital = digital_default; + // Get light sleep analog default pmu_sleep_analog_config_t analog_default = PMU_SLEEP_ANALOG_LSLP_CONFIG_DEFAULT(pd_flags); #if CONFIG_SPIRAM analog_default.hp_sys.analog.pd_cur = 1; analog_default.lp_sys[PMU_MODE_LP_SLEEP].analog.pd_cur = 1; #endif + +#if CONFIG_ESP_SLEEP_KEEP_DCDC_ALWAYS_ON + power_default.hp_sys.dig_power.dcdc_switch_pd_en = 0; + analog_default.hp_sys.analog.dcm_vset = CONFIG_ESP_SLEEP_DCM_VSET_VAL_IN_SLEEP; + analog_default.hp_sys.analog.dcm_mode = 1; +#endif config->analog = analog_default; } + + config->power = power_default; + pmu_sleep_param_config_t param_default = PMU_SLEEP_PARAM_CONFIG_DEFAULT(pd_flags); + config->param = *pmu_sleep_param_config_default(¶m_default, &power_default, pd_flags, adjustment, slowclk_period, fastclk_period); + return config; } @@ -194,6 +203,8 @@ static void pmu_sleep_digital_init(pmu_context_t *ctx, const pmu_sleep_digital_c static void pmu_sleep_analog_init(pmu_context_t *ctx, const pmu_sleep_analog_config_t *analog, bool dslp) { assert(ctx->hal); + pmu_ll_hp_set_dcm_mode (ctx->hal->dev, HP(SLEEP), analog->hp_sys.analog.dcm_mode); + pmu_ll_hp_set_dcm_vset (ctx->hal->dev, HP(SLEEP), analog->hp_sys.analog.dcm_vset); pmu_ll_hp_set_current_power_off (ctx->hal->dev, HP(SLEEP), analog->hp_sys.analog.pd_cur); pmu_ll_hp_set_bias_sleep_enable (ctx->hal->dev, HP(SLEEP), analog->hp_sys.analog.bias_sleep); pmu_ll_hp_set_regulator_sleep_memory_xpd (ctx->hal->dev, HP(SLEEP), analog->hp_sys.analog.slp_mem_xpd); @@ -250,10 +261,10 @@ void pmu_sleep_init(const pmu_sleep_config_t *config, bool dslp) } void pmu_sleep_increase_ldo_volt(void) { - REG_SET_FIELD(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_HP_ACTIVE_HP_REGULATOR_DBIAS, 30); - REG_SET_BIT(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_HP_ACTIVE_HP_REGULATOR_XPD); + pmu_ll_hp_set_regulator_dbias(&PMU, PMU_MODE_HP_ACTIVE, 30); + pmu_ll_hp_set_regulator_xpd(&PMU, PMU_MODE_HP_ACTIVE, 1); // Decrease the DCDC voltage to reduce the voltage difference between the DCDC and the LDO to avoid overshooting the DCDC voltage during wake-up. - REG_SET_FIELD(PMU_HP_ACTIVE_BIAS_REG, PMU_HP_ACTIVE_DCM_VSET, 24); + pmu_ll_hp_set_dcm_vset(&PMU, PMU_MODE_HP_ACTIVE, 24); } void pmu_sleep_shutdown_dcdc(void) { @@ -301,19 +312,26 @@ TCM_IRAM_ATTR uint32_t pmu_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt, ; } - return pmu_sleep_finish(); + return pmu_sleep_finish(dslp); } -TCM_IRAM_ATTR bool pmu_sleep_finish(void) +TCM_IRAM_ATTR bool pmu_sleep_finish(bool dslp) { - REG_SET_FIELD(PMU_HP_ACTIVE_BIAS_REG, PMU_HP_ACTIVE_DCM_VSET, 27); - if (pmu_ll_hp_is_sleep_reject(PMU_instance()->hal->dev)) { - // If sleep is rejected, the hardware wake-up process that turns on DCDC - // is skipped, and software is used to enable DCDC here. - pmu_sleep_enable_dcdc(); - esp_rom_delay_us(950); +#if CONFIG_ESP_SLEEP_KEEP_DCDC_ALWAYS_ON + if (!dslp) { + // Keep DCDC always on during light sleep, no need to adjust LDO. + } else +#endif + { + pmu_ll_hp_set_dcm_vset(&PMU, PMU_MODE_HP_ACTIVE, 27); + if (pmu_ll_hp_is_sleep_reject(PMU_instance()->hal->dev)) { + // If sleep is rejected, the hardware wake-up process that turns on DCDC + // is skipped, and software is used to enable DCDC here. + pmu_sleep_enable_dcdc(); + esp_rom_delay_us(950); + } + pmu_sleep_shutdown_ldo(); } - pmu_sleep_shutdown_ldo(); unsigned chip_version = efuse_hal_chip_revision(); if (!ESP_CHIP_REV_ABOVE(chip_version, 1)) { diff --git a/components/esp_hw_support/port/esp32p4/private_include/pmu_param.h b/components/esp_hw_support/port/esp32p4/private_include/pmu_param.h index b1c3aec175..a3c48c0420 100644 --- a/components/esp_hw_support/port/esp32p4/private_include/pmu_param.h +++ b/components/esp_hw_support/port/esp32p4/private_include/pmu_param.h @@ -105,7 +105,7 @@ const pmu_lp_system_analog_param_t* pmu_lp_system_analog_param_default(pmu_lp_mo typedef union { struct { uint32_t reserved0 : 21; - uint32_t dcdc_switch_pd_en: 1; + uint32_t dcdc_switch_pd_en: 1; uint32_t mem_dslp : 1; uint32_t mem_pd_en : 1; uint32_t reserved1 : 6; @@ -153,7 +153,9 @@ typedef union { typedef struct { struct { - uint32_t reserved0 : 25; + uint32_t reserved0 : 18; + uint32_t dcm_vset : 5; + uint32_t dcm_mode : 2; uint32_t xpd_bias : 1; uint32_t dbg_atten : 4; uint32_t pd_cur : 1; diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index d9b77fcafe..6b510d3726 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -905,8 +905,15 @@ static esp_err_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t m #if SOC_PMU_SUPPORTED #if SOC_DCDC_SUPPORTED - s_config.rtc_ticks_at_ldo_prepare = rtc_time_get(); - pmu_sleep_increase_ldo_volt(); +#if CONFIG_ESP_SLEEP_KEEP_DCDC_ALWAYS_ON + if (!deep_sleep) { + // Keep DCDC always on during light sleep, no need to adjust LDO voltage. + } else +#endif + { + s_config.rtc_ticks_at_ldo_prepare = rtc_time_get(); + pmu_sleep_increase_ldo_volt(); + } #endif pmu_sleep_config_t config; @@ -991,11 +998,18 @@ static esp_err_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t m #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); +#if CONFIG_ESP_SLEEP_KEEP_DCDC_ALWAYS_ON + if (!deep_sleep) { + // Keep DCDC always on during light sleep, no need to adjust LDO voltage. + } else +#endif + { + 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(); } - pmu_sleep_shutdown_dcdc(); #endif #if SOC_PMU_SUPPORTED