change(esp_hw_support): fill H4 M2A clk power tie-high from active clk power

This commit is contained in:
hebinglin
2026-08-27 23:16:03 +08:00
parent c8d733e402
commit 3f9dfb4649
6 changed files with 124 additions and 20 deletions
@@ -94,6 +94,11 @@ FORCE_INLINE_ATTR void pmu_ll_hp_set_clk_power(pmu_dev_t *hw, pmu_hp_mode_t mode
hw->hp_sys[mode].clk_power.val = xpd_flag;
}
FORCE_INLINE_ATTR uint32_t pmu_ll_hp_get_clk_power(pmu_dev_t *hw, pmu_hp_mode_t mode)
{
return hw->hp_sys[mode].clk_power.val;
}
/**
* @brief Set the power and isolation of the analog i2c master shared by all the PLLs
*
@@ -122,6 +127,11 @@ FORCE_INLINE_ATTR void pmu_ll_hp_set_xtalx2_xpd(pmu_dev_t *hw, pmu_hp_mode_t mod
hw->hp_sys[mode].xtal.xpd_xtalx2 = xpd_xtalx2;
}
FORCE_INLINE_ATTR uint32_t pmu_ll_hp_get_xtalx2_xpd(pmu_dev_t *hw, pmu_hp_mode_t mode)
{
return hw->hp_sys[mode].xtal.xpd_xtalx2;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_bias_xpd(pmu_dev_t *hw, pmu_hp_mode_t mode, bool xpd_bias)
{
hw->hp_sys[mode].bias.xpd_bias = xpd_bias;
+1
View File
@@ -52,6 +52,7 @@ entries:
pmu_sleep_clock_icg:pmu_sleep_clock_icg_config (noflash)
if IDF_TARGET_ESP32H4 = y && BT_LE_MODEM_STATE_ENABLED = y:
pmu_sleep_power:pmu_sleep_power_analog_wait_config (noflash)
pmu_sleep_power:pmu_sleep_power_clock_config (noflash)
sleep_mspi (noflash)
if PM_SLP_IRAM_OPT = y && IDF_TARGET_ESP32S31 != y:
pmu_param:get_act_lp_dbias (noflash)
@@ -14,11 +14,9 @@ endif()
if(NOT BOOTLOADER_BUILD)
list(APPEND srcs "sar_periph_ctrl.c")
if(CONFIG_PM_SKIP_MODEM_TO_ACTIVE_ANALOG_WAIT)
list(APPEND srcs "pmu_sleep_power.c")
endif()
if(CONFIG_BT_LE_MODEM_STATE_ENABLED)
list(APPEND srcs "pmu_sleep_power.c")
endif()
endif()
add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" "${srcs}")
@@ -250,7 +250,7 @@ static void pmu_sleep_param_init(pmu_context_t *ctx, const pmu_sleep_param_confi
pmu_ll_set_xtal_stable_wait_cycle(ctx->hal->dev, param->hp_lp.xtal_stable_wait_slow_clk_cycle);
pmu_ll_set_pll_stable_wait_cycle(ctx->hal->dev, param->hp_sys.pll_stable_wait_cycle);
#if CONFIG_PM_SKIP_MODEM_TO_ACTIVE_ANALOG_WAIT
#if CONFIG_BT_LE_MODEM_STATE_ENABLED && CONFIG_PM_SKIP_MODEM_TO_ACTIVE_ANALOG_WAIT
uint16_t ana_wait[ANALOG_WAIT_CTRL_NUM] = {
0x20, // about 1.6us
param->hp_sys.analog_wait_target_cycle,
@@ -258,6 +258,18 @@ static void pmu_sleep_param_init(pmu_context_t *ctx, const pmu_sleep_param_confi
};
pmu_sleep_power_analog_wait_config(ctx->priv, ana_wait);
#endif
#if CONFIG_BT_LE_MODEM_STATE_ENABLED && SOC_PM_MODEM_LOCK_CLK_WORKAROUND
pmu_hp_clk_power_reg_t hp_ck = { .val = pmu_ll_hp_get_clk_power(ctx->hal->dev, HP(ACTIVE)) };
uint32_t xtalx2_xpd = pmu_ll_hp_get_xtalx2_xpd(ctx->hal->dev, HP(ACTIVE));
pmu_imm_hp_clk_power_reg_t imm = {
.tie_high_xpd_bbpll = hp_ck.xpd_bbpll,
.tie_high_xpd_bbpll_i2c = hp_ck.xpd_bbpll_i2c,
.tie_high_global_bbpll_icg = hp_ck.xpd_bbpll || hp_ck.xpd_bbpll_i2c,
.tie_high_xtalx2 = xtalx2_xpd,
.tie_high_global_xtalx2_icg = xtalx2_xpd,
};
pmu_sleep_power_clock_config(ctx->priv, imm.val);
#endif
}
bool pmu_sleep_pll_already_enabled(void)
@@ -20,22 +20,44 @@ ESP_LOG_ATTR_TAG(TAG, "sleep_power");
#if SOC_PM_MODEM_LOCK_CLK_WORKAROUND
#define XTALX2_TIE_HIGH_MASK (PMU_TIE_HIGH_XTALX2_M | PMU_TIE_HIGH_GLOBAL_XTALX2_ICG_M)
#define XTALX2_TIE_HIGH_ON (PMU_TIE_HIGH_XTALX2 | PMU_TIE_HIGH_GLOBAL_XTALX2_ICG)
#define BBPLL_TIE_HIGH_MASK (PMU_TIE_HIGH_XPD_BBPLL_M | PMU_TIE_HIGH_XPD_BBPLL_I2C_M | PMU_TIE_HIGH_GLOBAL_BBPLL_ICG_M)
#define BBPLL_TIE_HIGH_ON (PMU_TIE_HIGH_XPD_BBPLL | PMU_TIE_HIGH_XPD_BBPLL_I2C | PMU_TIE_HIGH_GLOBAL_BBPLL_ICG)
typedef struct {
void *regdma_desc[2];
} pmu_sleep_power_clock_context_t;
static esp_err_t sleep_power_system_retention_init(void *arg)
{
const static sleep_retention_entries_config_t power_regs_retention[] = {
/* During the modem-to-active transition, the MODEM lock keeps the xtalx2, bbpll xpd status unchanged.
* Therefore, if xtalx2, bbpll is disabled in modem state, we need to set xtalx2, bbpll tie-high to enable it in active state. */
[0] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_POWER_LINK(0), PMU_IMM_HP_CK_POWER_REG, PMU_TIE_HIGH_XTALX2 | PMU_TIE_HIGH_GLOBAL_XTALX2_ICG, PMU_TIE_HIGH_XTALX2_M | PMU_TIE_HIGH_GLOBAL_XTALX2_ICG_M, 1, 0), .owner = ENTRY(2) },
[1] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_POWER_LINK(1), PMU_IMM_HP_CK_POWER_REG, PMU_TIE_HIGH_XPD_BBPLL | PMU_TIE_HIGH_XPD_BBPLL_I2C, PMU_TIE_HIGH_XPD_BBPLL_M | PMU_TIE_HIGH_XPD_BBPLL_I2C_M, 1, 0), .owner = ENTRY(2) },
* Therefore, if xtalx2, bbpll is disabled in modem state, we need to set xtalx2, bbpll tie-high to enable it in active state.
*
* XTALX2 and BBPLL write values are back-filled before sleep by pmu_sleep_power_clock_config(). */
[0] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_POWER_LINK(0), PMU_IMM_HP_CK_POWER_REG, XTALX2_TIE_HIGH_ON, XTALX2_TIE_HIGH_MASK, 1, 0), .owner = ENTRY(2) },
[1] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_POWER_LINK(1), PMU_IMM_HP_CK_POWER_REG, BBPLL_TIE_HIGH_ON, BBPLL_TIE_HIGH_MASK, 1, 0), .owner = ENTRY(2) },
};
esp_err_t err = sleep_retention_entries_create(power_regs_retention, ARRAY_SIZE(power_regs_retention), REGDMA_LINK_PRI_POWER, SLEEP_RETENTION_MODULE_POWER);
pmu_sleep_power_clock_context_t *clk = (pmu_sleep_power_clock_context_t *)arg;
int id_array[ARRAY_SIZE(clk->regdma_desc)] = { REGDMA_POWER_LINK(0), REGDMA_POWER_LINK(1) };
for (int i = 0; i < ARRAY_SIZE(id_array); i++) {
void *head = sleep_retention_find_link_by_id(id_array[i]);
if (head) {
clk->regdma_desc[i] = head;
}
}
ESP_RETURN_ON_ERROR(err, TAG, "failed to allocate memory for clock power retention");
ESP_LOGI(TAG, "Clock power sleep retention initialization");
return ESP_OK;
}
#endif
#if CONFIG_PM_SKIP_MODEM_TO_ACTIVE_ANALOG_WAIT
#define SLEEP_POWER_ANA_WAIT_LINK_BASE 10
#define SLEEP_POWER_ANA_WAIT_LINK_ID(_idx) REGDMA_POWER_LINK((SLEEP_POWER_ANA_WAIT_LINK_BASE + (_idx)))
@@ -67,32 +89,53 @@ static esp_err_t sleep_power_analog_wait_ctrl_init(void *arg)
return ESP_OK;
}
#endif
typedef struct {
#if SOC_PM_MODEM_LOCK_CLK_WORKAROUND
pmu_sleep_power_clock_context_t clock;
#endif
#if CONFIG_PM_SKIP_MODEM_TO_ACTIVE_ANALOG_WAIT
pmu_sleep_power_ana_wait_context_t ana_wait;
#endif
} pmu_sleep_power_context_t;
static esp_err_t sleep_power_retention_init(void *arg)
{
pmu_sleep_power_context_t *ctx = (pmu_sleep_power_context_t *)arg;
#if SOC_PM_MODEM_LOCK_CLK_WORKAROUND
ESP_RETURN_ON_ERROR(sleep_power_system_retention_init(arg), TAG, "system retention init failed");
ESP_RETURN_ON_ERROR(sleep_power_system_retention_init(&ctx->clock), TAG, "system retention init failed");
#endif
#if CONFIG_PM_SKIP_MODEM_TO_ACTIVE_ANALOG_WAIT
ESP_RETURN_ON_ERROR(sleep_power_analog_wait_ctrl_init(&ctx->ana_wait), TAG, "analog wait ctrl retention init failed");
#endif
ESP_RETURN_ON_ERROR(sleep_power_analog_wait_ctrl_init(arg), TAG, "analog wait ctrl retention init failed");
return ESP_OK;
}
static esp_err_t sleep_power_retention_deinit(void *arg)
{
pmu_sleep_power_ana_wait_context_t *ana_wait_ctx = (pmu_sleep_power_ana_wait_context_t *)arg;
for (int i = 0; i < ANALOG_WAIT_CTRL_NUM; i++) {
ana_wait_ctx->regdma_desc[i] = NULL;
pmu_sleep_power_context_t *ctx = (pmu_sleep_power_context_t *)arg;
#if SOC_PM_MODEM_LOCK_CLK_WORKAROUND
for (int i = 0; i < ARRAY_SIZE(ctx->clock.regdma_desc); i++) {
ctx->clock.regdma_desc[i] = NULL;
}
#endif
#if CONFIG_PM_SKIP_MODEM_TO_ACTIVE_ANALOG_WAIT
for (int i = 0; i < ANALOG_WAIT_CTRL_NUM; i++) {
ctx->ana_wait.regdma_desc[i] = NULL;
}
#endif
return ESP_OK;
}
ESP_SYSTEM_INIT_FN(sleep_power_startup_init, SECONDARY, BIT(0), 108)
{
static DRAM_ATTR pmu_sleep_power_ana_wait_context_t ana_wait_ctx;
static DRAM_ATTR pmu_sleep_power_context_t power_context = { 0 };
sleep_retention_module_init_param_t init_param = {
.cbs = {
.create = { .handle = sleep_power_retention_init, .arg = &ana_wait_ctx },
.destroy = { .handle = sleep_power_retention_deinit, .arg = &ana_wait_ctx },
.create = { .handle = sleep_power_retention_init, .arg = &power_context },
.destroy = { .handle = sleep_power_retention_deinit, .arg = &power_context },
},
.attribute = SLEEP_RETENTION_MODULE_ATTR_PASSIVE | SLEEP_RETENTION_MODULE_ATTR_ATTACH
};
@@ -101,13 +144,21 @@ ESP_SYSTEM_INIT_FN(sleep_power_startup_init, SECONDARY, BIT(0), 108)
if (err != ESP_OK) {
ESP_LOGW(TAG, "failed to init power retention module, err=%d", err);
} else {
#if PMU_SLEEP_PRIV_ENABLED
pmu_sleep_data_t *data = (pmu_sleep_data_t *)PMU_instance()->priv;
data->func[PMU_SLEEP_PRIV_SKIP_MODEM_TO_ACTIVE_ANALOG_WAIT] = &ana_wait_ctx;
#if CONFIG_PM_SKIP_MODEM_TO_ACTIVE_ANALOG_WAIT
data->func[PMU_SLEEP_PRIV_SKIP_MODEM_TO_ACTIVE_ANALOG_WAIT] = &power_context.ana_wait;
#endif
#if SOC_PM_MODEM_LOCK_CLK_WORKAROUND
data->func[PMU_SLEEP_PRIV_MODEM_LOCK_CLK_POWER] = &power_context.clock;
#endif
#endif
}
return ESP_OK;
}
#if CONFIG_PM_SKIP_MODEM_TO_ACTIVE_ANALOG_WAIT
void pmu_sleep_power_analog_wait_config(void *data, const uint16_t analog_wait[ANALOG_WAIT_CTRL_NUM])
{
pmu_sleep_data_t *data_ctx = (pmu_sleep_data_t *)data;
@@ -123,3 +174,22 @@ void pmu_sleep_power_analog_wait_config(void *data, const uint16_t analog_wait[A
regdma_link_set_write_wait_content(ana_wait_ctx->regdma_desc[i], (uint32_t)analog_wait[i] << PMU_ANA_WAIT_TARGET_S, PMU_ANA_WAIT_TARGET_M);
}
}
#endif
#if SOC_PM_MODEM_LOCK_CLK_WORKAROUND
void pmu_sleep_power_clock_config(void *data, const uint32_t config)
{
pmu_sleep_data_t *datap = (pmu_sleep_data_t *)data;
if (!datap || !datap->func[PMU_SLEEP_PRIV_MODEM_LOCK_CLK_POWER]) {
return;
}
pmu_sleep_power_clock_context_t *clk = (pmu_sleep_power_clock_context_t *)datap->func[PMU_SLEEP_PRIV_MODEM_LOCK_CLK_POWER];
if (clk->regdma_desc[0]) {
regdma_link_set_write_wait_content(clk->regdma_desc[0], config & XTALX2_TIE_HIGH_MASK, XTALX2_TIE_HIGH_MASK);
}
if (clk->regdma_desc[1]) {
regdma_link_set_write_wait_content(clk->regdma_desc[1], config & BBPLL_TIE_HIGH_MASK, BBPLL_TIE_HIGH_MASK);
}
}
#endif
@@ -123,13 +123,26 @@ const pmu_lp_system_analog_param_t* pmu_lp_system_analog_param_default(pmu_lp_mo
void pmu_sleep_power_analog_wait_config(void *data, const uint16_t analog_wait[ANALOG_WAIT_CTRL_NUM]);
#endif
#if SOC_PM_MODEM_LOCK_CLK_WORKAROUND
/**
* @brief Back-fill M2A clk power REGDMA write values before sleep.
*
* @param data PMU sleep data context.
* @param config IMM TIE_HIGH bits to write.
*/
void pmu_sleep_power_clock_config(void *data, const uint32_t config);
#endif
/* Enabled when this chip needs any pmu_sleep_data_t priv slot; conditions differ per chip. */
#define PMU_SLEEP_PRIV_ENABLED (CONFIG_PM_SKIP_MODEM_TO_ACTIVE_ANALOG_WAIT || SOC_PM_SUPPORT_PMU_RETENTION_CLK_ICG)
#define PMU_SLEEP_PRIV_ENABLED (CONFIG_PM_SKIP_MODEM_TO_ACTIVE_ANALOG_WAIT || SOC_PM_SUPPORT_PMU_RETENTION_CLK_ICG || SOC_PM_MODEM_LOCK_CLK_WORKAROUND)
#if PMU_SLEEP_PRIV_ENABLED
enum {
#if CONFIG_PM_SKIP_MODEM_TO_ACTIVE_ANALOG_WAIT
PMU_SLEEP_PRIV_SKIP_MODEM_TO_ACTIVE_ANALOG_WAIT,
#endif
#if SOC_PM_MODEM_LOCK_CLK_WORKAROUND
PMU_SLEEP_PRIV_MODEM_LOCK_CLK_POWER,
#endif
#if SOC_PM_SUPPORT_PMU_RETENTION_CLK_ICG
PMU_SLEEP_PRIV_HW_RETENTION_ICG_CLK,
#endif