From 81860c55d60735930afc0c1b00c0c0552595fc7c Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Fri, 21 Mar 2025 20:46:08 +0800 Subject: [PATCH] feat(esp_hw_support): use non-lock regi2c fast-up cpll/mpll enable process after sleep wakeup --- components/esp_hw_support/clk_ctrl_os.c | 2 +- .../include/esp_private/regi2c_ctrl.h | 8 +++--- .../include/esp_private/rtc_clk.h | 3 ++- .../esp_hw_support/port/esp32p4/pmu_sleep.c | 2 +- .../esp_hw_support/port/esp32p4/rtc_clk.c | 11 ++++++-- .../hal/esp32p4/include/hal/clk_tree_ll.h | 25 +++++++++++-------- .../platform_port/include/hal/regi2c_ctrl.h | 3 +++ 7 files changed, 35 insertions(+), 19 deletions(-) diff --git a/components/esp_hw_support/clk_ctrl_os.c b/components/esp_hw_support/clk_ctrl_os.c index add12e4bb2..76b683e300 100644 --- a/components/esp_hw_support/clk_ctrl_os.c +++ b/components/esp_hw_support/clk_ctrl_os.c @@ -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; diff --git a/components/esp_hw_support/include/esp_private/regi2c_ctrl.h b/components/esp_hw_support/include/esp_private/regi2c_ctrl.h index e77322677f..68b0b8b68d 100644 --- a/components/esp_hw_support/include/esp_private/regi2c_ctrl.h +++ b/components/esp_hw_support/include/esp_private/regi2c_ctrl.h @@ -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 diff --git a/components/esp_hw_support/include/esp_private/rtc_clk.h b/components/esp_hw_support/include/esp_private/rtc_clk.h index 4480780217..3a592a4780 100644 --- a/components/esp_hw_support/include/esp_private/rtc_clk.h +++ b/components/esp_hw_support/include/esp_private/rtc_clk.h @@ -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 diff --git a/components/esp_hw_support/port/esp32p4/pmu_sleep.c b/components/esp_hw_support/port/esp32p4/pmu_sleep.c index aff24145cc..7e931d6a2a 100644 --- a/components/esp_hw_support/port/esp32p4/pmu_sleep.c +++ b/components/esp_hw_support/port/esp32p4/pmu_sleep.c @@ -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. diff --git a/components/esp_hw_support/port/esp32p4/rtc_clk.c b/components/esp_hw_support/port/esp32p4/rtc_clk.c index f9e19ce08c..c727f7bd4b 100644 --- a/components/esp_hw_support/port/esp32p4/rtc_clk.c +++ b/components/esp_hw_support/port/esp32p4/rtc_clk.c @@ -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; } diff --git a/components/hal/esp32p4/include/hal/clk_tree_ll.h b/components/hal/esp32p4/include/hal/clk_tree_ll.h index 786444cadc..7579effd45 100644 --- a/components/hal/esp32p4/include/hal/clk_tree_ll.h +++ b/components/hal/esp32p4/include/hal/clk_tree_ll.h @@ -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); } /** diff --git a/components/hal/platform_port/include/hal/regi2c_ctrl.h b/components/hal/platform_port/include/hal/regi2c_ctrl.h index b87fdb3108..dea715874d 100644 --- a/components/hal/platform_port/include/hal/regi2c_ctrl.h +++ b/components/hal/platform_port/include/hal/regi2c_ctrl.h @@ -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