fix(mpll): fix mpll calibration fail bug

This commit is contained in:
Armando (Dou Yiwen)
2026-08-10 19:33:44 +08:00
committed by Michael.B
parent c6e80a336a
commit 81acd9c18f
7 changed files with 92 additions and 36 deletions

View File

@@ -466,32 +466,6 @@ static inline __attribute__((always_inline)) uint32_t clk_ll_mpll_get_freq_mhz(u
return xtal_freq_mhz * (div + 1) / (ref_div + 1);
}
/**
* @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)
{
HAL_ASSERT(xtal_freq_mhz == SOC_XTAL_FREQ_40M);
// 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 = regi2c_impl_read(I2C_MPLL, I2C_MPLL_HOSTID, I2C_MPLL_DHREF);
regi2c_impl_write(I2C_MPLL, I2C_MPLL_HOSTID, I2C_MPLL_DHREF, mpll_dhref_val | (3 << I2C_MPLL_DHREF_LSB));
uint8_t mpll_rstb_val = regi2c_impl_read(I2C_MPLL, I2C_MPLL_HOSTID, I2C_MPLL_IR_CAL_RSTB);
regi2c_impl_write(I2C_MPLL, I2C_MPLL_HOSTID, I2C_MPLL_IR_CAL_RSTB, mpll_rstb_val & 0xdf);
regi2c_impl_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_impl_write(I2C_MPLL, I2C_MPLL_HOSTID, I2C_MPLL_DIV_REG_ADDR, val);
REGI2C_EXIT_CRITICAL();
}
/**
* @brief Start MPLL self-calibration
*/
@@ -518,6 +492,65 @@ static inline __attribute__((always_inline)) bool clk_ll_mpll_calibration_is_don
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_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 = regi2c_impl_read(I2C_MPLL, I2C_MPLL_HOSTID, I2C_MPLL_DHREF);
regi2c_impl_write(I2C_MPLL, I2C_MPLL_HOSTID, I2C_MPLL_DHREF, mpll_dhref_val | (3 << I2C_MPLL_DHREF_LSB));
uint8_t mpll_rstb_val = regi2c_impl_read(I2C_MPLL, I2C_MPLL_HOSTID, I2C_MPLL_IR_CAL_RSTB);
regi2c_impl_write(I2C_MPLL, I2C_MPLL_HOSTID, I2C_MPLL_IR_CAL_RSTB, mpll_rstb_val & 0xdf);
regi2c_impl_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_impl_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();
}
/**
* @brief Get APLL configuration which can be used to calculate APLL frequency
*

View File

@@ -67,5 +67,5 @@ menu "LDO Regulator Configurations"
config ESP_LDO_VOLTAGE_STABLE_DELAY_US
int
depends on ESP_LDO_RESERVE_PSRAM
default 0
default 200
endmenu

View File

@@ -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"
@@ -221,4 +224,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
}

View File

@@ -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 = { \

View File

@@ -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"
@@ -488,6 +489,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);
@@ -497,7 +505,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) {

View File

@@ -661,13 +661,12 @@ void rtc_clk_mpll_configure(uint32_t xtal_freq, uint32_t mpll_freq, bool thread_
} else {
ANALOG_CLOCK_ENABLE();
}
/* MPLL calibration start */
clk_ll_mpll_calibration_start();
clk_ll_mpll_set_config(mpll_freq, xtal_freq);
/* wait calibration done */
while(!clk_ll_mpll_calibration_is_done());
/* MPLL calibration stop */
clk_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);

View File

@@ -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