diff --git a/components/esp_hal_clock/esp32p4/include/hal/clk_tree_ll.h b/components/esp_hal_clock/esp32p4/include/hal/clk_tree_ll.h index 958cbbaaf06..eb76c2bbd3e 100644 --- a/components/esp_hal_clock/esp32p4/include/hal/clk_tree_ll.h +++ b/components/esp_hal_clock/esp32p4/include/hal/clk_tree_ll.h @@ -440,16 +440,45 @@ static inline __attribute__((always_inline)) uint32_t clk_ll_mpll_get_freq_mhz(u return xtal_freq_mhz * (div + 1) / (ref_div + 1); } +/** + * @brief Start MPLL self-calibration + */ +static inline __attribute__((always_inline)) void clk_ll_mpll_calibration_start(void) +{ + HP_SYS_CLKRST.ana_pll_ctrl0.reg_mspi_cal_stop = 0; +} + +/** + * @brief Stop MPLL self-calibration + */ +static inline __attribute__((always_inline)) void clk_ll_mpll_calibration_stop(void) +{ + HP_SYS_CLKRST.ana_pll_ctrl0.reg_mspi_cal_stop = 1; +} + +/** + * @brief Check whether MPLL calibration is done + * + * @return True if calibration is done; otherwise false + */ +static inline __attribute__((always_inline)) bool clk_ll_mpll_calibration_is_done(void) +{ + return HP_SYS_CLKRST.ana_pll_ctrl0.reg_mspi_cal_end; +} + /** * @brief Set MPLL frequency from XTAL source (Analog part - through regi2c) * * @param mpll_freq_mhz MPLL frequency, in MHz * @param xtal_freq_mhz XTAL frequency, in MHz */ -static inline __attribute__((always_inline)) void clk_ll_mpll_set_config(uint32_t mpll_freq_mhz, uint32_t xtal_freq_mhz) +static inline __attribute__((always_inline)) void clk_ll_mpll_set_config_v1(uint32_t mpll_freq_mhz, uint32_t xtal_freq_mhz) { HAL_ASSERT(xtal_freq_mhz == SOC_XTAL_FREQ_40M); + /* MPLL calibration start */ + clk_ll_mpll_calibration_start(); + // There are sequential regi2c operations in `clk_ll_mpll_set_config`, use the raw regi2c API with one lock wrapper to save time. REGI2C_ENTER_CRITICAL(); uint8_t mpll_dhref_val = esp_rom_regi2c_read(I2C_MPLL, I2C_MPLL_HOSTID, I2C_MPLL_DHREF); @@ -464,6 +493,36 @@ static inline __attribute__((always_inline)) void clk_ll_mpll_set_config(uint32_ uint8_t val = ((div << 3) | ref_div); esp_rom_regi2c_write(I2C_MPLL, I2C_MPLL_HOSTID, I2C_MPLL_DIV_REG_ADDR, val); REGI2C_EXIT_CRITICAL(); + /* wait calibration done */ + while (!clk_ll_mpll_calibration_is_done()); + /* MPLL calibration stop */ + clk_ll_mpll_calibration_stop(); +} + +/** + * @brief MPLL hardware self-calibration (debug flow) + * + * Power up MPLL, configure IR cal / div / dhref, run HW calibration and wait until done. + * Caller must enable the regi2c master clock before calling this function. + */ +static inline __attribute__((always_inline)) void clk_ll_mpll_set_config_v3(uint32_t mpll_freq_mhz, uint32_t xtal_freq_mhz) +{ + HAL_ASSERT(xtal_freq_mhz == SOC_XTAL_FREQ_40M); + + REGI2C_WRITE_MASK(I2C_MPLL, I2C_MPLL_IR_CAL_EXT_CAP, 3); + REGI2C_WRITE_MASK(I2C_MPLL, I2C_MPLL_IR_CAL_ENX_CAP, 1); + REGI2C_WRITE_MASK(I2C_MPLL, I2C_MPLL_DIV_ADDR, 9); + REGI2C_WRITE_MASK(I2C_MPLL, I2C_MPLL_DHREF, 3); + + REGI2C_WRITE_MASK(I2C_MPLL, I2C_MPLL_IR_CAL_ENX_CAP, 0); + clk_ll_mpll_calibration_start(); + + uint8_t div = mpll_freq_mhz / 20 - 1; + REGI2C_WRITE_MASK(I2C_MPLL, I2C_MPLL_DIV_ADDR, div); + + while (!clk_ll_mpll_calibration_is_done()) { + } + clk_ll_mpll_calibration_stop(); } /** diff --git a/components/esp_hw_support/port/esp32p4/pmu_init.c b/components/esp_hw_support/port/esp32p4/pmu_init.c index ad4dedd21db..36fe663f9a1 100644 --- a/components/esp_hw_support/port/esp32p4/pmu_init.c +++ b/components/esp_hw_support/port/esp32p4/pmu_init.c @@ -18,6 +18,9 @@ #include "pmu_param.h" #include "esp_private/esp_pmu.h" #include "soc/regi2c_dig_reg.h" +#include "soc/regi2c_mpll.h" +#include "soc/regi2c_bias.h" +#include "hal/regi2c_ctrl_ll.h" #include "soc/lp_system_reg.h" #include "regi2c_ctrl.h" #include "esp_rom_sys.h" @@ -212,4 +215,10 @@ void pmu_init(void) // For PVT func taking effect, need delay. esp_rom_delay_us(1000); #endif +#if !CONFIG_ESP32P4_SELECTS_REV_LESS_V3 + REG_SET_BIT(PMU_RF_PWC_REG, PMU_MSPI_PHY_XPD); + REGI2C_WRITE_MASK(I2C_BIAS, I2C_BIAS_DREG_1P1, 12); + REGI2C_WRITE_MASK(I2C_BIAS, I2C_BIAS_DREG_1P1_PVT, 12); + REGI2C_WRITE_MASK(I2C_MPLL, I2C_MPLL_IR_CAL_EXT_CAP, 3); +#endif } diff --git a/components/esp_hw_support/port/esp32p4/pmu_param.c b/components/esp_hw_support/port/esp32p4/pmu_param.c index 66620cf82e1..386f01024f2 100644 --- a/components/esp_hw_support/port/esp32p4/pmu_param.c +++ b/components/esp_hw_support/port/esp32p4/pmu_param.c @@ -53,7 +53,7 @@ ESP_HW_LOG_ATTR_TAG(TAG, "pmu_param"); .clk_power = { \ .i2c_iso_en = 1, \ .i2c_retention = 1, \ - .xpd_pll_i2c = 1, \ + .xpd_pll_i2c = 0xf, \ .xpd_pll = 0 \ }, \ .xtal = { \ diff --git a/components/esp_hw_support/port/esp32p4/pmu_sleep.c b/components/esp_hw_support/port/esp32p4/pmu_sleep.c index 1dbd9f8a016..e81d52a186c 100644 --- a/components/esp_hw_support/port/esp32p4/pmu_sleep.c +++ b/components/esp_hw_support/port/esp32p4/pmu_sleep.c @@ -18,6 +18,7 @@ #include "soc/soc.h" #include "soc/regi2c_syspll.h" #include "soc/regi2c_cpll.h" +#include "soc/regi2c_mpll.h" #include "soc/rtc.h" #include "soc/cache_reg.h" #include "soc/pau_reg.h" @@ -486,6 +487,13 @@ SPM_IRAM_ATTR bool pmu_sleep_finish(bool dslp) esp_rom_delay_us(DCDC_STARTUP_TIME_US); } pmu_sleep_shutdown_ldo(); + } else if (s_mpll_freq_mhz_before_sleep) { + rtc_clk_mpll_enable(); +#if !CONFIG_ESP32P4_SELECTS_REV_LESS_V3 + _regi2c_ctrl_ll_master_enable_clock(true); + REGI2C_WRITE_MASK(I2C_MPLL, I2C_MPLL_IR_CAL_EXT_CAP, 3); + esp_rom_delay_us(10); +#endif } pmu_ll_imm_set_pad_slp_sel(&PMU, false); @@ -495,7 +503,6 @@ SPM_IRAM_ATTR bool pmu_sleep_finish(bool dslp) if (!dslp) { if (s_mpll_freq_mhz_before_sleep) { - rtc_clk_mpll_enable(); 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) { diff --git a/components/esp_hw_support/port/esp32p4/rtc_clk.c b/components/esp_hw_support/port/esp32p4/rtc_clk.c index 1373bbdcec2..e089b85589b 100644 --- a/components/esp_hw_support/port/esp32p4/rtc_clk.c +++ b/components/esp_hw_support/port/esp32p4/rtc_clk.c @@ -662,13 +662,12 @@ void rtc_clk_mpll_configure(uint32_t xtal_freq, uint32_t mpll_freq, bool thread_ } else { ANALOG_CLOCK_ENABLE(); } - /* MPLL calibration start */ - regi2c_ctrl_ll_mpll_calibration_start(); - clk_ll_mpll_set_config(mpll_freq, xtal_freq); - /* wait calibration done */ - while(!regi2c_ctrl_ll_mpll_calibration_is_done()); - /* MPLL calibration stop */ - regi2c_ctrl_ll_mpll_calibration_stop(); + +#if CONFIG_ESP32P4_SELECTS_REV_LESS_V3 + clk_ll_mpll_set_config_v1(mpll_freq, xtal_freq); +#else + clk_ll_mpll_set_config_v3(mpll_freq, xtal_freq); +#endif if (thread_safe) { _regi2c_ctrl_ll_master_enable_clock(false); diff --git a/components/soc/esp32p4/include/soc/regi2c_mpll.h b/components/soc/esp32p4/include/soc/regi2c_mpll.h index d3e3b19b616..39983ac83fd 100644 --- a/components/soc/esp32p4/include/soc/regi2c_mpll.h +++ b/components/soc/esp32p4/include/soc/regi2c_mpll.h @@ -17,6 +17,14 @@ #define I2C_MPLL 0x63 #define I2C_MPLL_HOSTID 0 +#define I2C_MPLL_IR_CAL_EXT_CAP 1 +#define I2C_MPLL_IR_CAL_EXT_CAP_MSB 1 +#define I2C_MPLL_IR_CAL_EXT_CAP_LSB 0 + +#define I2C_MPLL_IR_CAL_ENX_CAP 1 +#define I2C_MPLL_IR_CAL_ENX_CAP_MSB 2 +#define I2C_MPLL_IR_CAL_ENX_CAP_LSB 2 + #define I2C_MPLL_IR_CAL_RSTB 1 #define I2C_MPLL_IR_CAL_RSTB_MSB 5 #define I2C_MPLL_IR_CAL_RSTB_lSB 5