Merge branch 'fix/fix_esp32p4_retention_cost' into 'master'

fix(esp_hw_support): optimize retention cost and update sleep time compensation

See merge request espressif/esp-idf!37920
This commit is contained in:
Wu Zheng Hui
2025-04-23 13:20:49 +08:00
27 changed files with 212 additions and 61 deletions

View File

@ -193,7 +193,7 @@ esp_err_t IRAM_ATTR periph_rtc_mpll_freq_set(uint32_t expt_freq_hz, uint32_t *re
* But when more than one peripheral refers MPLL, its frequency is not allowed to change once it is set */
if (s_cur_mpll_freq_hz == 0 || s_mpll_ref_cnt < 2) {
uint32_t xtal_freq_mhz = clk_ll_xtal_load_freq_mhz();
rtc_clk_mpll_configure(xtal_freq_mhz, expt_freq_hz / MHZ);
rtc_clk_mpll_configure(xtal_freq_mhz, expt_freq_hz / MHZ, false);
s_cur_mpll_freq_hz = clk_ll_mpll_get_freq_mhz(xtal_freq_mhz) * MHZ;
} else {
ret = ESP_ERR_INVALID_STATE;

View File

@ -161,6 +161,15 @@ void esp_sleep_mmu_retention(bool backup_or_restore);
bool mmu_domain_pd_allowed(void);
#endif
/**
* @brief Notify the sleep process that `sleep_time_overhead_out` needs to be remeasured, which must be called
* in the following scenarios:
* 1. When the CPU frequency changes to below the crystal oscillator frequency.
* 2. When a new callback function is registered in the sleep process.
* 3. Other events occur that affect the execution time of the CPU sleep process.
*/
void esp_sleep_overhead_out_time_refresh(void);
#ifdef __cplusplus
}
#endif

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -70,7 +70,8 @@ extern "C" {
#define regi2c_ctrl_read_reg_mask regi2c_read_reg_mask_raw
#define regi2c_ctrl_write_reg regi2c_write_reg_raw
#define regi2c_ctrl_write_reg_mask regi2c_write_reg_mask_raw
#define REGI2C_ENTER_CRITICAL()
#define REGI2C_EXIT_CRITICAL()
#else
/* Access internal registers, don't use in application */
@ -82,7 +83,8 @@ void regi2c_ctrl_write_reg_mask(uint8_t block, uint8_t host_id, uint8_t reg_add,
/* enter the critical section that protects internal registers. Don't use it in SDK. Use the functions above. */
void regi2c_enter_critical(void);
void regi2c_exit_critical(void);
#define REGI2C_ENTER_CRITICAL() regi2c_enter_critical()
#define REGI2C_EXIT_CRITICAL() regi2c_exit_critical()
#endif // NON_OS_BUILD
/* Convenience macros for the above functions, these use register definitions

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -22,11 +22,24 @@ extern "C" {
* source to XTAL (except for S2).
*
* Currently, this function is only called in `esp_restart_noos` and `esp_restart_noos_dig` to switch the CPU
* clock source back to XTAL (by default) before reset, and in `esp_sleep_start` to switch CPU clock source to XTAL
* before entering sleep for PMU supported chips.
* clock source back to XTAL (by default) before reset.
*/
void rtc_clk_cpu_set_to_default_config(void);
/**
* @brief Switch CPU clock source to XTAL, the PLL has different processing methods for different chips.
* 1. For earlier chips without PMU, there is no PMU module that can turn off the CPU's PLL, so it has to be
* disabled at here to save the power consumption. Though ESP32C3/S3 has USB CDC device, it can not function
* properly during sleep due to the lack of APB clock (before C6, USJ relies on APB clock to work). Therefore,
* we will always disable CPU's PLL (i.e. BBPLL).
* 2. For PMU supported chips, CPU's PLL power can be turned off by PMU, so no need to disable the PLL at here.
* Leaving PLL on at this stage also helps USJ keep connection and retention operation (if they rely on this PLL).
* For ESP32P4, if the APB frequency is configured as the hardware default value (10MHz), this will cause the
* regdma backup/restore to not achieve optimal performance. The MEM/APB frequency divider needs to be configured
* to 40MHz to speed up the retention speed.
*/
void rtc_clk_cpu_freq_set_xtal_for_sleep(void);
/**
* @brief Notify that the BBPLL has a new in-use consumer
*
@ -58,8 +71,9 @@ void rtc_clk_mpll_disable(void);
*
* @param[in] xtal_freq XTAL frequency
* @param[in] mpll_freq MPLL frequency
* @param[in] thread_safe Set true if called from thread safe context, which will save the time of taking spin lock.
*/
void rtc_clk_mpll_configure(uint32_t xtal_freq, uint32_t mpll_freq);
void rtc_clk_mpll_configure(uint32_t xtal_freq, uint32_t mpll_freq, bool thread_safe);
/**
* Get the MPLL frequency

View File

@ -18,9 +18,9 @@ esp_err_t sleep_clock_system_retention_init(void *arg)
const static sleep_retention_entries_config_t pcr_regs_retention[] = {
/* Enable i2c master clock */
[0] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_PCR_LINK(0), LPPERI_CLK_EN_REG, LPPERI_CK_EN_LP_I2CMST, LPPERI_CK_EN_LP_I2CMST_M, 1, 1), .owner = ENTRY(0) },
[0] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_PCR_LINK(0), LPPERI_CLK_EN_REG, LPPERI_CK_EN_LP_I2CMST, LPPERI_CK_EN_LP_I2CMST_M, 1, 0), .owner = ENTRY(0) },
/* Start SYSPLL self-calibration */
[1] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_PCR_LINK(1), HP_SYS_CLKRST_ANA_PLL_CTRL0_REG, 0, HP_SYS_CLKRST_REG_SYS_PLL_CAL_STOP_M, 1, 1), .owner = ENTRY(0) },
[1] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_PCR_LINK(1), HP_SYS_CLKRST_ANA_PLL_CTRL0_REG, 0, HP_SYS_CLKRST_REG_SYS_PLL_CAL_STOP_M, 1, 0), .owner = ENTRY(0) },
/* Wait calibration done */
[2] = { .config = REGDMA_LINK_WAIT_INIT (REGDMA_PCR_LINK(2), HP_SYS_CLKRST_ANA_PLL_CTRL0_REG, HP_SYS_CLKRST_REG_SYS_PLL_CAL_END, HP_SYS_CLKRST_REG_SYS_PLL_CAL_END_M, 1, 0), .owner = ENTRY(0) },
/* Stop SYSPLL self-calibration */

View File

@ -426,6 +426,11 @@ void rtc_clk_cpu_set_to_default_config(void)
rtc_clk_wait_for_slow_cycle();
}
void rtc_clk_cpu_freq_set_xtal_for_sleep(void)
{
rtc_clk_cpu_freq_set_xtal();
}
bool rtc_clk_cpu_freq_mhz_to_config(uint32_t freq_mhz, rtc_cpu_freq_config_t* out_config)
{
uint32_t source_freq_mhz;

View File

@ -296,6 +296,11 @@ void rtc_clk_cpu_set_to_default_config(void)
rtc_clk_cpu_freq_to_xtal(freq_mhz, 1);
}
void rtc_clk_cpu_freq_set_xtal_for_sleep(void)
{
rtc_clk_cpu_freq_set_xtal();
}
/**
* Switch to use XTAL as the CPU clock source.
* Must satisfy: cpu_freq = XTAL_FREQ / div.

View File

@ -325,6 +325,11 @@ void rtc_clk_cpu_set_to_default_config(void)
rtc_clk_cpu_freq_to_xtal(freq_mhz, 1);
}
void rtc_clk_cpu_freq_set_xtal_for_sleep(void)
{
rtc_clk_cpu_freq_set_xtal();
}
/**
* Switch to use XTAL as the CPU clock source.
* Must satisfy: cpu_freq = XTAL_FREQ / div.

View File

@ -386,6 +386,11 @@ void rtc_clk_cpu_set_to_default_config(void)
s_cur_pll_freq = 0; // no disable PLL, but set freq to 0 to trigger a PLL calibration after wake-up from sleep
}
void rtc_clk_cpu_freq_set_xtal_for_sleep(void)
{
rtc_clk_cpu_set_to_default_config();
}
void rtc_clk_cpu_freq_to_pll_and_pll_lock_release(int cpu_freq_mhz)
{
// TODO: IDF-8641 CPU_MAX_FREQ don't know what to do... pll_240 or pll_160...

View File

@ -340,6 +340,11 @@ void rtc_clk_cpu_set_to_default_config(void)
s_cur_pll_freq = 0; // no disable PLL, but set freq to 0 to trigger a PLL calibration after wake-up from sleep
}
void rtc_clk_cpu_freq_set_xtal_for_sleep(void)
{
rtc_clk_cpu_set_to_default_config();
}
void rtc_clk_cpu_freq_to_pll_and_pll_lock_release(int cpu_freq_mhz)
{
rtc_clk_cpu_freq_to_pll_mhz(cpu_freq_mhz);

View File

@ -329,6 +329,11 @@ void rtc_clk_cpu_set_to_default_config(void)
s_cur_pll_freq = 0; // no disable PLL, but set freq to 0 to trigger a PLL calibration after wake-up from sleep
}
void rtc_clk_cpu_freq_set_xtal_for_sleep(void)
{
rtc_clk_cpu_set_to_default_config();
}
void rtc_clk_cpu_freq_to_pll_and_pll_lock_release(int cpu_freq_mhz)
{
rtc_clk_cpu_freq_to_pll_160_mhz(cpu_freq_mhz);

View File

@ -400,6 +400,11 @@ void rtc_clk_cpu_set_to_default_config(void)
s_cur_pll_freq = 0; // no disable PLL, but set freq to 0 to trigger a PLL calibration after wake-up from sleep
}
void rtc_clk_cpu_freq_set_xtal_for_sleep(void)
{
rtc_clk_cpu_set_to_default_config();
}
soc_xtal_freq_t rtc_clk_xtal_freq_get(void)
{
uint32_t xtal_freq_mhz = clk_ll_xtal_load_freq_mhz();

View File

@ -400,6 +400,11 @@ void rtc_clk_cpu_set_to_default_config(void)
s_cur_pll_freq = 0; // no disable PLL, but set freq to 0 to trigger a PLL calibration after wake-up from sleep
}
void rtc_clk_cpu_freq_set_xtal_for_sleep(void)
{
rtc_clk_cpu_set_to_default_config();
}
soc_xtal_freq_t rtc_clk_xtal_freq_get(void)
{
uint32_t xtal_freq_mhz = clk_ll_xtal_load_freq_mhz();

View File

@ -338,6 +338,11 @@ void rtc_clk_cpu_set_to_default_config(void)
rtc_clk_cpu_freq_to_xtal(freq_mhz, 1);
}
void rtc_clk_cpu_freq_set_xtal_for_sleep(void)
{
rtc_clk_cpu_set_to_default_config();
}
void rtc_clk_cpu_freq_to_pll_and_pll_lock_release(int cpu_freq_mhz)
{
rtc_clk_cpu_freq_to_pll_mhz(cpu_freq_mhz);

View File

@ -370,17 +370,17 @@ FORCE_INLINE_ATTR void pmu_sleep_cache_sync_items(uint32_t gid, uint32_t type, u
static TCM_DRAM_ATTR uint32_t s_mpll_freq_mhz_before_sleep = 0;
__attribute__((optimize("-O2")))
TCM_IRAM_ATTR uint32_t pmu_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt, uint32_t lslp_mem_inf_fpu, bool dslp)
{
lp_aon_hal_inform_wakeup_type(dslp);
assert(PMU_instance()->hal);
pmu_ll_hp_set_wakeup_enable(PMU_instance()->hal->dev, wakeup_opt);
pmu_ll_hp_set_reject_enable(PMU_instance()->hal->dev, reject_opt);
pmu_ll_hp_set_wakeup_enable(&PMU, wakeup_opt);
pmu_ll_hp_set_reject_enable(&PMU, reject_opt);
pmu_ll_hp_clear_wakeup_intr_status(PMU_instance()->hal->dev);
pmu_ll_hp_clear_reject_intr_status(PMU_instance()->hal->dev);
pmu_ll_hp_clear_reject_cause(PMU_instance()->hal->dev);
pmu_ll_hp_clear_wakeup_intr_status(&PMU);
pmu_ll_hp_clear_reject_intr_status(&PMU);
pmu_ll_hp_clear_reject_cause(&PMU);
// 1. For the sleep where powered down the TOP domain, the L1 cache data memory will be lost and needs to be written back here.
// 2. For the sleep without power down the TOP domain, regdma retention may still be enabled, and dirty data in the L1 cache needs
@ -421,13 +421,13 @@ TCM_IRAM_ATTR uint32_t pmu_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt,
// The PMU state machine will switch PAD to sleep setting and do IO holding at the same stage.
// IO may be held to an indeterminate state, so the software needs to trigger the PAD to switch
// to the sleep setting before starting the PMU state machine.
pmu_ll_imm_set_pad_slp_sel(PMU_instance()->hal->dev, true);
pmu_ll_imm_set_pad_slp_sel(&PMU, true);
/* Start entry into sleep mode */
pmu_ll_hp_set_sleep_enable(PMU_instance()->hal->dev);
pmu_ll_hp_set_sleep_enable(&PMU);
while (!pmu_ll_hp_is_sleep_wakeup(PMU_instance()->hal->dev) &&
!pmu_ll_hp_is_sleep_reject(PMU_instance()->hal->dev)) {
while (!pmu_ll_hp_is_sleep_wakeup(&PMU) &&
!pmu_ll_hp_is_sleep_reject(&PMU)) {
;
}
@ -451,7 +451,7 @@ TCM_IRAM_ATTR bool pmu_sleep_finish(bool dslp)
{
pmu_ll_hp_set_dcm_vset(&PMU, PMU_MODE_HP_ACTIVE, HP_CALI_ACTIVE_DCM_VSET_DEFAULT);
pmu_sleep_enable_dcdc();
if (pmu_ll_hp_is_sleep_reject(PMU_instance()->hal->dev)) {
if (pmu_ll_hp_is_sleep_reject(&PMU)) {
// If sleep is rejected, the hardware wake-up process that turns on DCDC
// is skipped, and wait DCDC volt rise up by software here.
esp_rom_delay_us(950);
@ -459,14 +459,14 @@ TCM_IRAM_ATTR bool pmu_sleep_finish(bool dslp)
pmu_sleep_shutdown_ldo();
}
pmu_ll_imm_set_pad_slp_sel(PMU_instance()->hal->dev, false);
pmu_ll_imm_set_pad_slp_sel(&PMU, false);
// Wait eFuse memory update done.
while(efuse_ll_get_controller_state() != EFUSE_CONTROLLER_STATE_IDLE);
if (s_mpll_freq_mhz_before_sleep && !dslp) {
rtc_clk_mpll_enable();
rtc_clk_mpll_configure(clk_hal_xtal_get_freq_mhz(), s_mpll_freq_mhz_before_sleep);
rtc_clk_mpll_configure(clk_hal_xtal_get_freq_mhz(), s_mpll_freq_mhz_before_sleep, true);
#if CONFIG_SPIRAM
if (!s_pmu_sleep_regdma_backup_enabled) {
// MSPI2 and MSPI3 share the register for core clock. So we only set MSPI2 here.
@ -484,7 +484,7 @@ TCM_IRAM_ATTR bool pmu_sleep_finish(bool dslp)
REGI2C_WRITE_MASK(I2C_CPLL, I2C_CPLL_OC_DIV_7_0, 6); // lower default cpu_pll freq to 400M
REGI2C_WRITE_MASK(I2C_SYSPLL, I2C_SYSPLL_OC_DIV_7_0, 8); // lower default sys_pll freq to 480M
}
return pmu_ll_hp_is_sleep_reject(PMU_instance()->hal->dev);
return pmu_ll_hp_is_sleep_reject(&PMU);
}
uint32_t pmu_sleep_get_wakup_retention_cost(void)

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -438,6 +438,13 @@ void rtc_clk_cpu_set_to_default_config(void)
int freq_mhz = (int)rtc_clk_xtal_freq_get();
rtc_clk_cpu_freq_to_xtal(freq_mhz, 1, true);
}
void rtc_clk_cpu_freq_set_xtal_for_sleep(void)
{
int freq_mhz = (int)rtc_clk_xtal_freq_get();
rtc_clk_cpu_freq_to_xtal(freq_mhz, 1, false);
s_cur_cpll_freq = 0; // no disable PLL, but set freq to 0 to trigger a PLL calibration after wake-up from sleep
}
@ -585,10 +592,17 @@ TCM_IRAM_ATTR void rtc_clk_mpll_enable(void)
clk_ll_mpll_enable();
}
void rtc_clk_mpll_configure(uint32_t xtal_freq, uint32_t mpll_freq)
void rtc_clk_mpll_configure(uint32_t xtal_freq, uint32_t mpll_freq, bool thread_safe)
{
/* Analog part */
ANALOG_CLOCK_ENABLE();
if (thread_safe) {
_regi2c_ctrl_ll_master_enable_clock(true);
} else {
ANALOG_CLOCK_ENABLE();
#if !BOOTLOADER_BUILD
regi2c_enter_critical();
#endif
}
/* MPLL calibration start */
regi2c_ctrl_ll_mpll_calibration_start();
clk_ll_mpll_set_config(mpll_freq, xtal_freq);
@ -596,8 +610,15 @@ void rtc_clk_mpll_configure(uint32_t xtal_freq, uint32_t mpll_freq)
while(!regi2c_ctrl_ll_mpll_calibration_is_done());
/* MPLL calibration stop */
regi2c_ctrl_ll_mpll_calibration_stop();
ANALOG_CLOCK_DISABLE();
if (thread_safe) {
_regi2c_ctrl_ll_master_enable_clock(false);
} else {
#if !BOOTLOADER_BUILD
regi2c_exit_critical();
#endif
ANALOG_CLOCK_DISABLE();
}
s_cur_mpll_freq = mpll_freq;
}

View File

@ -446,6 +446,11 @@ void rtc_clk_cpu_set_to_default_config(void)
rtc_clk_cpu_freq_to_xtal(CLK_LL_XTAL_FREQ_MHZ, 1);
}
void rtc_clk_cpu_freq_set_xtal_for_sleep(void)
{
rtc_clk_cpu_freq_set_xtal();
}
/**
* Switch to use XTAL as the CPU clock source.
* Must satisfy: cpu_freq = XTAL_FREQ / div.

View File

@ -387,6 +387,11 @@ void rtc_clk_cpu_set_to_default_config(void)
rtc_clk_cpu_freq_to_xtal(freq_mhz, 1);
}
void rtc_clk_cpu_freq_set_xtal_for_sleep(void)
{
rtc_clk_cpu_freq_set_xtal();
}
/**
* Switch to use XTAL as the CPU clock source.
* Must satisfy: cpu_freq = XTAL_FREQ / div.

View File

@ -64,7 +64,7 @@ void esp_sleep_config_gpio_isolate(void)
}
}
#if CONFIG_ESP_SLEEP_MSPI_NEED_ALL_IO_PU
#if CONFIG_ESP_SLEEP_MSPI_NEED_ALL_IO_PU && !SOC_MSPI_HAS_INDEPENT_IOMUX
gpio_sleep_set_pull_mode(esp_mspi_get_io(ESP_MSPI_IO_CLK), GPIO_PULLUP_ONLY);
gpio_sleep_set_pull_mode(esp_mspi_get_io(ESP_MSPI_IO_Q), GPIO_PULLUP_ONLY);
gpio_sleep_set_pull_mode(esp_mspi_get_io(ESP_MSPI_IO_D), GPIO_PULLUP_ONLY);
@ -104,14 +104,14 @@ void esp_sleep_enable_gpio_switch(bool enable)
}
#endif
/* If the PSRAM is disable in ESP32xx chips equipped with PSRAM, there will be a large current leakage. */
#if CONFIG_ESP_SLEEP_PSRAM_LEAKAGE_WORKAROUND && CONFIG_SPIRAM
#if CONFIG_ESP_SLEEP_PSRAM_LEAKAGE_WORKAROUND && CONFIG_SPIRAM & !SOC_MSPI_HAS_INDEPENT_IOMUX
if (gpio_num == esp_mspi_get_io(ESP_MSPI_IO_CS1)) {
gpio_sleep_sel_dis(gpio_num);
continue;
}
#endif // CONFIG_ESP_SLEEP_PSRAM_LEAKAGE_WORKAROUND && CONFIG_SPIRAM
#if CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND
#if CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND & !SOC_MSPI_HAS_INDEPENT_IOMUX
if (gpio_num == esp_mspi_get_io(ESP_MSPI_IO_CS0)) {
gpio_sleep_sel_dis(gpio_num);
continue;

View File

@ -271,6 +271,7 @@ typedef struct {
#if SOC_DCDC_SUPPORTED
uint64_t rtc_ticks_at_ldo_prepare;
#endif
bool overhead_out_need_remeasure;
} sleep_config_t;
@ -302,7 +303,8 @@ static sleep_config_t s_config = {
.lock = portMUX_INITIALIZER_UNLOCKED,
.ccount_ticks_record = 0,
.sleep_time_overhead_out = DEFAULT_SLEEP_OUT_OVERHEAD_US,
.wakeup_triggers = 0
.wakeup_triggers = 0,
.overhead_out_need_remeasure = true
};
/* Internal variable used to track if light sleep wakeup sources are to be
@ -317,6 +319,12 @@ static const char *TAG = "sleep";
static RTC_FAST_ATTR int32_t s_sleep_sub_mode_ref_cnt[ESP_SLEEP_MODE_MAX] = { 0 };
//in this mode, 2uA is saved, but RTC memory can't use at high temperature, and RTCIO can't be used as INPUT.
void esp_sleep_overhead_out_time_refresh(void)
{
portENTER_CRITICAL(&s_config.lock);
s_config.overhead_out_need_remeasure = true;
portEXIT_CRITICAL(&s_config.lock);
}
static uint32_t get_power_down_flags(void);
static uint32_t get_sleep_flags(uint32_t pd_flags, bool deepsleep);
@ -983,16 +991,7 @@ static esp_err_t SLEEP_FN_ATTR esp_sleep_start(uint32_t sleep_flags, uint32_t cl
// Save current frequency and switch to XTAL
rtc_cpu_freq_config_t cpu_freq_config;
rtc_clk_cpu_freq_get_config(&cpu_freq_config);
#if SOC_PMU_SUPPORTED
// For PMU supported chips, CPU's PLL power can be turned off by PMU, so no need to disable the PLL at here.
// Leaving PLL on at this stage also helps USJ keep connection and retention operation (if they rely on this PLL).
rtc_clk_cpu_set_to_default_config();
#else
// For earlier chips, there is no PMU module that can turn off the CPU's PLL, so it has to be disabled at here to save the power consumption.
// Though ESP32C3/S3 has USB CDC device, it can not function properly during sleep due to the lack of APB clock (before C6, USJ relies on APB clock to work).
// Therefore, we will always disable CPU's PLL (i.e. BBPLL).
rtc_clk_cpu_freq_set_xtal();
#endif
rtc_clk_cpu_freq_set_xtal_for_sleep();
#if SOC_PM_SUPPORT_EXT0_WAKEUP
// Configure pins for external wakeup
@ -1446,6 +1445,16 @@ esp_err_t esp_light_sleep_start(void)
// Re-calibrate the RTC clock
sleep_low_power_clock_calibration(false);
if (s_config.overhead_out_need_remeasure) {
uint32_t cur_cpu_freq = esp_clk_cpu_freq() / MHZ;
uint32_t xtal_freq = rtc_clk_xtal_freq_get();
if (cur_cpu_freq < xtal_freq) {
s_config.sleep_time_overhead_out = DEFAULT_SLEEP_OUT_OVERHEAD_US * xtal_freq / cur_cpu_freq;
} else {
s_config.sleep_time_overhead_out = DEFAULT_SLEEP_OUT_OVERHEAD_US;
}
}
/*
* Adjustment time consists of parts below:
* 1. Hardware time waiting for internal 8M oscillate clock and XTAL;
@ -1610,6 +1619,7 @@ esp_err_t esp_light_sleep_start(void)
if (s_light_sleep_wakeup) {
s_config.sleep_time_overhead_out = (esp_cpu_get_cycle_count() - s_config.ccount_ticks_record) / (esp_clk_cpu_freq() / 1000000ULL);
s_config.overhead_out_need_remeasure = false;
}
portEXIT_CRITICAL(&s_config.lock);
@ -1704,8 +1714,10 @@ esp_err_t esp_sleep_enable_timer_wakeup(uint64_t time_in_us)
return ESP_ERR_INVALID_ARG;
}
#endif
portENTER_CRITICAL(&s_config.lock);
s_config.wakeup_triggers |= RTC_TIMER_TRIG_EN;
s_config.sleep_duration = time_in_us;
portEXIT_CRITICAL(&s_config.lock);
return ESP_OK;
}
@ -1747,9 +1759,10 @@ static SLEEP_FN_ATTR esp_err_t timer_wakeup_prepare(int64_t sleep_duration)
#if SOC_LP_TIMER_SUPPORTED
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
int64_t backup_cost_ticks = rtc_time_us_to_slowclk(((pmu_sleep_machine_constant_t *)PMU_instance()->mc)->hp.regdma_a2s_work_time_us, s_config.rtc_clk_cal_period);
// Last timer wake-up validity check
if ((sleep_duration == 0) || \
(target_wakeup_tick < rtc_time_get() + SLEEP_TIMER_ALARM_TO_SLEEP_TICKS)) {
(target_wakeup_tick < rtc_time_get() + SLEEP_TIMER_ALARM_TO_SLEEP_TICKS + backup_cost_ticks)) {
// Treat too short sleep duration setting as timer reject
return ESP_ERR_SLEEP_REJECT;
}

View File

@ -20,6 +20,7 @@
#include "esp_clk_tree.h"
#include "soc/soc_caps.h"
#include "esp_private/esp_sleep_internal.h"
#include "esp_private/crosscore_int.h"
#include "esp_private/periph_ctrl.h"
@ -480,6 +481,7 @@ esp_err_t esp_pm_configure(const void* vconfig)
// Enable the wakeup source here because the `esp_sleep_disable_wakeup_source` in the `else`
// branch must be called if corresponding wakeup source is already enabled.
esp_sleep_enable_timer_wakeup(0);
esp_sleep_overhead_out_time_refresh();
} else if (s_light_sleep_en) {
// Since auto light-sleep will enable the timer wakeup source, to avoid affecting subsequent possible
// deepsleep requests, disable the timer wakeup source here.

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -26,7 +26,7 @@
#include "esp32p4/rom/rtc.h"
#include "hal/misc.h"
#include "hal/efuse_hal.h"
#include "esp_private/regi2c_ctrl.h"
#ifdef __cplusplus
extern "C" {
@ -414,9 +414,12 @@ static inline __attribute__((always_inline)) void clk_ll_cpll_set_config(uint32_
uint8_t i2c_cpll_lref = (oc_enb_fcal << I2C_CPLL_OC_ENB_FCAL_LSB) | (dchgp << I2C_CPLL_OC_DCHGP_LSB) | (div_ref);
uint8_t i2c_cpll_div_7_0 = div7_0;
uint8_t i2c_cpll_dcur = (1 << I2C_CPLL_OC_DLREF_SEL_LSB ) | (3 << I2C_CPLL_OC_DHREF_SEL_LSB) | dcur;
REGI2C_WRITE(I2C_CPLL, I2C_CPLL_OC_REF_DIV, i2c_cpll_lref);
REGI2C_WRITE(I2C_CPLL, I2C_CPLL_OC_DIV_7_0, i2c_cpll_div_7_0);
REGI2C_WRITE(I2C_CPLL, I2C_CPLL_OC_DCUR, i2c_cpll_dcur);
// There are sequential regi2c operations in `clk_ll_cpll_set_config`, use the raw regi2c API with one lock wrapper to save time.
REGI2C_ENTER_CRITICAL();
esp_rom_regi2c_write(I2C_CPLL, I2C_CPLL_HOSTID, I2C_CPLL_OC_REF_DIV, i2c_cpll_lref);
esp_rom_regi2c_write(I2C_CPLL, I2C_CPLL_HOSTID, I2C_CPLL_OC_DIV_7_0, i2c_cpll_div_7_0);
esp_rom_regi2c_write(I2C_CPLL, I2C_CPLL_HOSTID, I2C_CPLL_OC_DCUR, i2c_cpll_dcur);
REGI2C_EXIT_CRITICAL();
}
/**
@ -443,17 +446,17 @@ static inline __attribute__((always_inline)) void clk_ll_mpll_set_config(uint32_
{
HAL_ASSERT(xtal_freq_mhz == SOC_XTAL_FREQ_40M);
uint8_t mpll_dhref_val = REGI2C_READ(I2C_MPLL, I2C_MPLL_DHREF);
REGI2C_WRITE(I2C_MPLL, I2C_MPLL_DHREF, mpll_dhref_val | (3 << I2C_MPLL_DHREF_LSB));
uint8_t mpll_rstb_val = REGI2C_READ(I2C_MPLL, I2C_MPLL_IR_CAL_RSTB);
REGI2C_WRITE(I2C_MPLL, I2C_MPLL_IR_CAL_RSTB, mpll_rstb_val & 0xdf);
REGI2C_WRITE(I2C_MPLL, I2C_MPLL_IR_CAL_RSTB, mpll_rstb_val | (1 << I2C_MPLL_IR_CAL_RSTB_lSB));
uint8_t mpll_dhref_val = esp_rom_regi2c_read(I2C_MPLL, I2C_MPLL_HOSTID, I2C_MPLL_DHREF);
esp_rom_regi2c_write(I2C_MPLL, I2C_MPLL_HOSTID, I2C_MPLL_DHREF, mpll_dhref_val | (3 << I2C_MPLL_DHREF_LSB));
uint8_t mpll_rstb_val = esp_rom_regi2c_read(I2C_MPLL, I2C_MPLL_HOSTID, I2C_MPLL_IR_CAL_RSTB);
esp_rom_regi2c_write(I2C_MPLL, I2C_MPLL_HOSTID, I2C_MPLL_IR_CAL_RSTB, mpll_rstb_val & 0xdf);
esp_rom_regi2c_write(I2C_MPLL, I2C_MPLL_HOSTID, I2C_MPLL_IR_CAL_RSTB, mpll_rstb_val | (1 << I2C_MPLL_IR_CAL_RSTB_lSB));
// MPLL_Freq = XTAL_Freq * (div + 1) / (ref_div + 1)
uint8_t ref_div = 1;
uint8_t div = mpll_freq_mhz / 20 - 1;
uint8_t val = ((div << 3) | ref_div);
REGI2C_WRITE(I2C_MPLL, I2C_MPLL_DIV_REG_ADDR, val);
esp_rom_regi2c_write(I2C_MPLL, I2C_MPLL_HOSTID, I2C_MPLL_DIV_REG_ADDR, val);
}
/**

View File

@ -29,4 +29,7 @@
#define REGI2C_READ(block, reg_add) \
esp_rom_regi2c_read(block, block##_HOSTID, reg_add)
#define REGI2C_ENTER_CRITICAL()
#define REGI2C_EXIT_CRITICAL()
#endif

View File

@ -1551,6 +1551,10 @@ config SOC_SPI_SUPPORT_CLK_SPLL
bool
default y
config SOC_MSPI_HAS_INDEPENT_IOMUX
bool
default y
config SOC_MEMSPI_IS_INDEPENDENT
bool
default y

View File

@ -573,6 +573,7 @@
// host_id = 0 -> SPI0/SPI1, host_id = 1 -> SPI2,
#define SOC_SPI_PERIPH_SUPPORT_MULTILINE_MODE(host_id) ({(void)host_id; 1;})
#define SOC_MSPI_HAS_INDEPENT_IOMUX 1
#define SOC_MEMSPI_IS_INDEPENDENT 1
#define SOC_SPI_MAX_PRE_DIVIDER 16

View File

@ -52,7 +52,7 @@ extern const regdma_entries_config_t hp_system_regs_retention[HP_SYSTEM_RETENTIO
* This is an internal function of the sleep retention driver, and is not
* useful for external use.
*/
#define IOMUX_RETENTION_LINK_LEN 3
#define IOMUX_RETENTION_LINK_LEN 6
extern const regdma_entries_config_t iomux_regs_retention[IOMUX_RETENTION_LINK_LEN];
/**

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -80,13 +80,37 @@ const regdma_entries_config_t hp_system_regs_retention[] = {
_Static_assert(ARRAY_SIZE(hp_system_regs_retention) == HP_SYSTEM_RETENTION_LINK_LEN, "Inconsistent HP_SYSTEM retention link length definitions");
/* IO MUX Registers Context */
#define N_REGS_IOMUX_0() (((IO_MUX_GPIO54_REG - REG_IO_MUX_BASE) / 4) + 1)
#define N_REGS_GPIO_MTX() (((GPIO_ZERO_DET1_FILTER_CNT_REG - DR_REG_GPIO_BASE) / 4) + 1)
#define N_REGS_IOMUX() (((IO_MUX_GPIO54_REG - REG_IO_MUX_BASE) / 4) + 1)
#define N_REGS_MSPI_IOMUX() (((IOMUX_MSPI_PIN_PSRAM_DQS_1_PIN0_REG - IOMUX_MSPI_PIN_CLK_EN0_REG) / 4) + 1)
#define N_REGS_GPIO_PINx() (((GPIO_PIN56_REG - GPIO_PIN0_REG) / 4) + 1)
#define N_REGS_GPIO_FUNCx() (((GPIO_FUNC56_OUT_SEL_CFG_REG - GPIO_FUNC1_IN_SEL_CFG_REG) / 4) + 1)
#define GPIO_RETENTION_REGS_CNT0 6
#define GPIO_RETENTION_REGS_CNT1 9
#define GPIO_RETENTION_REGS_BASE0 (GPIO_OUT_REG)
#define GPIO_RETENTION_REGS_BASE1 (GPIO_CLOCK_GATE_REG)
static const uint32_t gpio_regs_map0[4] = {0x90489, 0x0, 0x0, 0x0};
static const uint32_t gpio_regs_map1[4] = {0x1, 0x6fa000, 0x0, 0x0};
const regdma_entries_config_t iomux_regs_retention[] = {
[0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_IOMUX_LINK(0x00), REG_IO_MUX_BASE, REG_IO_MUX_BASE, N_REGS_IOMUX_0(), 0, 0), .owner = ENTRY(0) }, /* io_mux */
[1] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_IOMUX_LINK(0x01), DR_REG_GPIO_BASE, DR_REG_GPIO_BASE, N_REGS_GPIO_MTX(), 0, 0), .owner = ENTRY(0) },
[2] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_IOMUX_LINK(0x01), IOMUX_MSPI_PIN_CLK_EN0_REG, IOMUX_MSPI_PIN_CLK_EN0_REG, N_REGS_GPIO_MTX(), 0, 0), .owner = ENTRY(0) },
/* IO_MUX */
[0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_IOMUX_LINK(0x00), REG_IO_MUX_BASE, REG_IO_MUX_BASE, N_REGS_IOMUX(), 0, 0), .owner = ENTRY(0) },
/* MSPI IOMUX */
[1] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_IOMUX_LINK(0x01), IOMUX_MSPI_PIN_FLASH_CS_PIN0_REG, IOMUX_MSPI_PIN_FLASH_CS_PIN0_REG, N_REGS_MSPI_IOMUX(), 0, 0), .owner = ENTRY(0) },
/* GPIO_OUT_REG / GPIO_OUT1_REG / GPIO_ENABLE_REG / GPIO_ENABLE1_REG / GPIO_STATUS_REG / GPIO_STATUS1_REG*/
[2] = {
.config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_IOMUX_LINK(0x02), GPIO_RETENTION_REGS_BASE0, GPIO_RETENTION_REGS_BASE0, GPIO_RETENTION_REGS_CNT0, 0, 0, \
gpio_regs_map0[0], gpio_regs_map0[1], gpio_regs_map0[2], gpio_regs_map0[3]), .owner = ENTRY(0)
},
/* GPIO_PIN0_REG ~ GPIO_PIN56_REG*/
[3] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_IOMUX_LINK(0x03), GPIO_PIN0_REG, GPIO_PIN0_REG, N_REGS_GPIO_PINx(), 0, 0), .owner = ENTRY(0) },
/* GPIO_FUNC1_IN_SEL_CFG_REG ~ GPIO_FUNC255_IN_SEL_CFG_REG & GPIO_FUNC0_OUT_SEL_CFG_REG ~ GPIO_FUNC56_OUT_SEL_CFG_REG */
[4] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_IOMUX_LINK(0x04), GPIO_FUNC1_IN_SEL_CFG_REG, GPIO_FUNC1_IN_SEL_CFG_REG, N_REGS_GPIO_FUNCx(), 0, 0), .owner = ENTRY(0) },
[5] = {
.config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_IOMUX_LINK(0x05), GPIO_RETENTION_REGS_BASE1, GPIO_RETENTION_REGS_BASE1, GPIO_RETENTION_REGS_CNT1, 0, 0, \
gpio_regs_map1[0], gpio_regs_map1[1], gpio_regs_map1[2], gpio_regs_map1[3]), .owner = ENTRY(0)
},
};
_Static_assert(ARRAY_SIZE(iomux_regs_retention) == IOMUX_RETENTION_LINK_LEN, "Inconsistent IOMUX retention link length definitions");