forked from espressif/esp-idf
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:
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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...
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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];
|
||||
|
||||
/**
|
||||
|
@ -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");
|
||||
|
||||
|
Reference in New Issue
Block a user