feat(esp_hw_support): use non-lock regi2c fast-up cpll/mpll enable process after sleep wakeup

This commit is contained in:
wuzhenghui
2025-03-21 20:46:08 +08:00
parent 41dd6ef81a
commit 81860c55d6
7 changed files with 35 additions and 19 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

@ -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
*/
@ -31,7 +31,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 */
@ -43,7 +44,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 // BOOTLOADER_BUILD
/* Convenience macros for the above functions, these use register definitions

View File

@ -58,8 +58,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

@ -463,7 +463,7 @@ TCM_IRAM_ATTR bool pmu_sleep_finish(bool dslp)
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.

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
*/
@ -587,9 +587,12 @@ 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 */
if (!thread_safe) {
REGI2C_ENTER_CRITICAL();
}
/* MPLL calibration start */
regi2c_ctrl_ll_mpll_calibration_start();
clk_ll_mpll_set_config(mpll_freq, xtal_freq);
@ -597,6 +600,10 @@ 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();
if (!thread_safe) {
REGI2C_EXIT_CRITICAL();
}
s_cur_mpll_freq = mpll_freq;
}

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