|
| 1 | +/* |
| 2 | + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD |
| 3 | + * |
| 4 | + * SPDX-License-Identifier: Apache-2.0 |
| 5 | + */ |
| 6 | + |
| 7 | +#include <stdint.h> |
| 8 | +#include <stdlib.h> |
| 9 | +#include <esp_types.h> |
| 10 | +#include "sdkconfig.h" |
| 11 | +#include "esp_attr.h" |
| 12 | +#include "soc/soc.h" |
| 13 | +#include "soc/pmu_struct.h" |
| 14 | +#include "hal/pmu_hal.h" |
| 15 | +#include "pmu_param.h" |
| 16 | +#include "esp_private/esp_pmu.h" |
| 17 | + |
| 18 | +static __attribute__((unused)) const char *TAG = "pmu_init"; |
| 19 | + |
| 20 | +typedef struct { |
| 21 | + const pmu_hp_system_power_param_t *power; |
| 22 | + const pmu_hp_system_clock_param_t *clock; |
| 23 | + const pmu_hp_system_digital_param_t *digital; |
| 24 | + pmu_hp_system_analog_param_t *analog; //param determined at runtime |
| 25 | + const pmu_hp_system_retention_param_t *retent; |
| 26 | +} pmu_hp_system_param_t; |
| 27 | + |
| 28 | +typedef struct { |
| 29 | + const pmu_lp_system_power_param_t *power; |
| 30 | + pmu_lp_system_analog_param_t *analog; //param determined at runtime |
| 31 | +} pmu_lp_system_param_t; |
| 32 | + |
| 33 | +pmu_context_t * __attribute__((weak)) IRAM_ATTR PMU_instance(void) |
| 34 | +{ |
| 35 | + /* It should be explicitly defined in the internal RAM, because this |
| 36 | + * instance will be used in pmu_sleep.c */ |
| 37 | + static DRAM_ATTR pmu_hal_context_t pmu_hal = { .dev = &PMU }; |
| 38 | + static DRAM_ATTR pmu_sleep_machine_constant_t pmu_mc = PMU_SLEEP_MC_DEFAULT(); |
| 39 | + static DRAM_ATTR pmu_context_t pmu_context = { .hal = &pmu_hal, .mc = (void *)&pmu_mc }; |
| 40 | + return &pmu_context; |
| 41 | +} |
| 42 | + |
| 43 | +void pmu_hp_system_init(pmu_context_t *ctx, pmu_hp_mode_t mode, const pmu_hp_system_param_t *param) |
| 44 | +{ |
| 45 | + const pmu_hp_system_power_param_t *power = param->power; |
| 46 | + const pmu_hp_system_clock_param_t *clock = param->clock; |
| 47 | + const pmu_hp_system_digital_param_t *dig = param->digital; |
| 48 | + const pmu_hp_system_analog_param_t *anlg = param->analog; |
| 49 | + const pmu_hp_system_retention_param_t *ret = param->retent; |
| 50 | + |
| 51 | + assert(ctx->hal); |
| 52 | + /* Default configuration of hp-system power in active, modem and sleep modes */ |
| 53 | + pmu_ll_hp_set_dig_power(ctx->hal->dev, mode, power->dig_power.val); |
| 54 | + pmu_ll_hp_set_clk_power(ctx->hal->dev, mode, power->clk_power.val); |
| 55 | + pmu_ll_hp_set_xtal_xpd (ctx->hal->dev, mode, power->xtal.xpd_xtal); |
| 56 | + |
| 57 | + /* Default configuration of hp-system clock in active, modem and sleep modes */ |
| 58 | + pmu_ll_hp_set_icg_func (ctx->hal->dev, mode, clock->icg_func); |
| 59 | + pmu_ll_hp_set_icg_apb (ctx->hal->dev, mode, clock->icg_apb); |
| 60 | + pmu_ll_hp_set_icg_modem (ctx->hal->dev, mode, clock->icg_modem.code); |
| 61 | + pmu_ll_hp_set_sysclk_nodiv (ctx->hal->dev, mode, clock->sysclk.dig_sysclk_nodiv); |
| 62 | + pmu_ll_hp_set_icg_sysclk_enable (ctx->hal->dev, mode, clock->sysclk.icg_sysclk_en); |
| 63 | + pmu_ll_hp_set_sysclk_slp_sel (ctx->hal->dev, mode, clock->sysclk.sysclk_slp_sel); |
| 64 | + pmu_ll_hp_set_icg_sysclk_slp_sel(ctx->hal->dev, mode, clock->sysclk.icg_slp_sel); |
| 65 | + pmu_ll_hp_set_dig_sysclk (ctx->hal->dev, mode, clock->sysclk.dig_sysclk_sel); |
| 66 | + |
| 67 | + /* Default configuration of hp-system digital sub-system in active, modem |
| 68 | + * and sleep modes */ |
| 69 | + pmu_ll_hp_set_uart_wakeup_enable(ctx->hal->dev, mode, dig->syscntl.uart_wakeup_en); |
| 70 | + pmu_ll_hp_set_hold_all_lp_pad (ctx->hal->dev, mode, dig->syscntl.lp_pad_hold_all); |
| 71 | + pmu_ll_hp_set_hold_all_hp_pad (ctx->hal->dev, mode, dig->syscntl.hp_pad_hold_all); |
| 72 | + pmu_ll_hp_set_dig_pad_slp_sel (ctx->hal->dev, mode, dig->syscntl.dig_pad_slp_sel); |
| 73 | + pmu_ll_hp_set_pause_watchdog (ctx->hal->dev, mode, dig->syscntl.dig_pause_wdt); |
| 74 | + pmu_ll_hp_set_cpu_stall (ctx->hal->dev, mode, dig->syscntl.dig_cpu_stall); |
| 75 | + |
| 76 | + /* Default configuration of hp-system analog sub-system in active, modem and |
| 77 | + * sleep modes */ |
| 78 | + pmu_ll_hp_set_dcdc_ccm_enable (ctx->hal->dev, mode, anlg->bias.dcdc_ccm_enb); |
| 79 | + pmu_ll_hp_set_dcdc_clear_ready (ctx->hal->dev, mode, anlg->bias.dcdc_clear_rdy); |
| 80 | + pmu_ll_hp_set_dig_reg_dpcur_bias (ctx->hal->dev, mode, anlg->bias.dig_reg_dpcur_bias); |
| 81 | + pmu_ll_hp_set_dig_reg_dsfmos (ctx->hal->dev, mode, anlg->bias.dig_reg_dsfmos); |
| 82 | + pmu_ll_hp_set_dcm_vset (ctx->hal->dev, mode, anlg->bias.dcm_vset); |
| 83 | + pmu_ll_hp_set_dcm_mode (ctx->hal->dev, mode, anlg->bias.dcm_mode); |
| 84 | + pmu_ll_hp_set_bias_xpd (ctx->hal->dev, mode, anlg->bias.xpd_bias); |
| 85 | + pmu_ll_hp_set_trx_xpd (ctx->hal->dev, mode, anlg->bias.xpd_trx); |
| 86 | + pmu_ll_hp_set_discnnt_dig_rtc (ctx->hal->dev, mode, anlg->bias.discnnt_dig_rtc); |
| 87 | + pmu_ll_hp_set_current_power_off (ctx->hal->dev, mode, anlg->bias.pd_cur); |
| 88 | + pmu_ll_hp_set_bias_sleep_enable (ctx->hal->dev, mode, anlg->bias.bias_sleep); |
| 89 | + if (mode == PMU_MODE_HP_ACTIVE) { |
| 90 | + pmu_ll_hp_set_regulator_lp_dbias_voltage(ctx->hal->dev, mode, anlg->regulator0.lp_dbias_vol); |
| 91 | + pmu_ll_hp_set_regulator_hp_dbias_voltage(ctx->hal->dev, mode, anlg->regulator0.hp_dbias_vol); |
| 92 | + pmu_ll_hp_set_regulator_dbias_sel (ctx->hal->dev, mode, anlg->regulator0.dbias_sel); |
| 93 | + pmu_ll_hp_set_regulator_dbias_init (ctx->hal->dev, mode, anlg->regulator0.dbias_init); |
| 94 | + } |
| 95 | + pmu_ll_hp_set_regulator_power_detect_bypass(ctx->hal->dev, mode, anlg->regulator0.power_det_bypass); |
| 96 | + pmu_ll_hp_set_regulator_sleep_memory_xpd (ctx->hal->dev, mode, anlg->regulator0.slp_mem_xpd); |
| 97 | + pmu_ll_hp_set_regulator_sleep_logic_xpd (ctx->hal->dev, mode, anlg->regulator0.slp_logic_xpd); |
| 98 | + pmu_ll_hp_set_regulator_xpd (ctx->hal->dev, mode, anlg->regulator0.xpd); |
| 99 | + pmu_ll_hp_set_regulator_sleep_memory_dbias (ctx->hal->dev, mode, anlg->regulator0.slp_mem_dbias); |
| 100 | + pmu_ll_hp_set_regulator_sleep_logic_dbias (ctx->hal->dev, mode, anlg->regulator0.slp_logic_dbias); |
| 101 | + pmu_ll_hp_set_regulator_dbias (ctx->hal->dev, mode, anlg->regulator0.dbias); |
| 102 | + pmu_ll_hp_set_regulator_driver_bar (ctx->hal->dev, mode, anlg->regulator1.drv_b); |
| 103 | + |
| 104 | + /* Default configuration of hp-system retention sub-system in active, modem |
| 105 | + * and sleep modes */ |
| 106 | + pmu_ll_hp_set_retention_param(ctx->hal->dev, mode, ret->retention.val); |
| 107 | + pmu_ll_hp_set_backup_icg_func(ctx->hal->dev, mode, ret->backup_clk); |
| 108 | + |
| 109 | + /* Some PMU initial parameter configuration */ |
| 110 | + pmu_ll_imm_update_dig_icg_modem_code(ctx->hal->dev, true); |
| 111 | + pmu_ll_imm_update_dig_icg_switch(ctx->hal->dev, true); |
| 112 | + |
| 113 | + pmu_ll_hp_set_sleep_protect_mode(ctx->hal->dev, PMU_SLEEP_PROTECT_HP_LP_SLEEP); |
| 114 | +} |
| 115 | + |
| 116 | +void pmu_lp_system_init(pmu_context_t *ctx, pmu_lp_mode_t mode, const pmu_lp_system_param_t *param) |
| 117 | +{ |
| 118 | + const pmu_lp_system_power_param_t *power = param->power; |
| 119 | + const pmu_lp_system_analog_param_t *anlg = param->analog; |
| 120 | + |
| 121 | + assert(ctx->hal); |
| 122 | + /* Default configuration of lp-system power in active and sleep modes */ |
| 123 | + pmu_ll_lp_set_dig_power(ctx->hal->dev, mode, power->dig_power.val); |
| 124 | + pmu_ll_lp_set_clk_power(ctx->hal->dev, mode, power->clk_power.val); |
| 125 | + pmu_ll_lp_set_xtal_xpd (ctx->hal->dev, PMU_MODE_LP_SLEEP, power->xtal.xpd_xtal); |
| 126 | + |
| 127 | + /* Default configuration of lp-system analog sub-system in active and |
| 128 | + * sleep modes */ |
| 129 | + if (mode == PMU_MODE_LP_SLEEP) { |
| 130 | + pmu_ll_lp_set_dcdc_ccm_enable (ctx->hal->dev, mode, anlg->bias.dcdc_ccm_enb); |
| 131 | + pmu_ll_lp_set_dcdc_clear_ready (ctx->hal->dev, mode, anlg->bias.dcdc_clear_rdy); |
| 132 | + pmu_ll_lp_set_dig_reg_dpcur_bias (ctx->hal->dev, mode, anlg->bias.dig_reg_dpcur_bias); |
| 133 | + pmu_ll_lp_set_dig_reg_dsfmos (ctx->hal->dev, mode, anlg->bias.dig_reg_dsfmos); |
| 134 | + pmu_ll_lp_set_dcm_vset (ctx->hal->dev, mode, anlg->bias.dcm_vset); |
| 135 | + pmu_ll_lp_set_dcm_mode (ctx->hal->dev, mode, anlg->bias.dcm_mode); |
| 136 | + pmu_ll_lp_set_bias_xpd (ctx->hal->dev, mode, anlg->bias.xpd_bias); |
| 137 | + pmu_ll_lp_set_discnnt_dig_rtc (ctx->hal->dev, mode, anlg->bias.discnnt_dig_rtc); |
| 138 | + pmu_ll_lp_set_current_power_off (ctx->hal->dev, mode, anlg->bias.pd_cur); |
| 139 | + pmu_ll_lp_set_bias_sleep_enable (ctx->hal->dev, mode, anlg->bias.bias_sleep); |
| 140 | + } |
| 141 | + pmu_ll_lp_set_regulator_slp_xpd (ctx->hal->dev, mode, anlg->regulator0.slp_xpd); |
| 142 | + pmu_ll_lp_set_regulator_xpd (ctx->hal->dev, mode, anlg->regulator0.xpd); |
| 143 | + pmu_ll_lp_set_regulator_sleep_dbias(ctx->hal->dev, mode, anlg->regulator0.slp_dbias); |
| 144 | + pmu_ll_lp_set_regulator_dbias (ctx->hal->dev, mode, anlg->regulator0.dbias); |
| 145 | + pmu_ll_lp_set_regulator_driver_bar (ctx->hal->dev, mode, anlg->regulator1.drv_b); |
| 146 | +} |
| 147 | + |
| 148 | +static inline void pmu_power_domain_force_default(pmu_context_t *ctx) |
| 149 | +{ |
| 150 | + assert(ctx); |
| 151 | + // for bypass reserved power domain |
| 152 | + const pmu_hp_power_domain_t pmu_hp_domains[] = { |
| 153 | + PMU_HP_PD_TOP, |
| 154 | + PMU_HP_PD_HP_AON, |
| 155 | + PMU_HP_PD_CPU, |
| 156 | + PMU_HP_PD_WIFI |
| 157 | + }; |
| 158 | + |
| 159 | + for (uint8_t idx = 0; idx < (sizeof(pmu_hp_domains) / sizeof(pmu_hp_power_domain_t)); idx++) { |
| 160 | + pmu_ll_hp_set_power_force_power_up (ctx->hal->dev, pmu_hp_domains[idx], false); |
| 161 | + pmu_ll_hp_set_power_force_reset (ctx->hal->dev, pmu_hp_domains[idx], false); |
| 162 | + pmu_ll_hp_set_power_force_isolate (ctx->hal->dev, pmu_hp_domains[idx], false); |
| 163 | + pmu_ll_hp_set_power_force_power_down(ctx->hal->dev, pmu_hp_domains[idx], false); |
| 164 | + pmu_ll_hp_set_power_force_no_isolate(ctx->hal->dev, pmu_hp_domains[idx], false); |
| 165 | + pmu_ll_hp_set_power_force_no_reset (ctx->hal->dev, pmu_hp_domains[idx], false); |
| 166 | + } |
| 167 | + /* Isolate all memory banks while sleeping, avoid memory leakage current */ |
| 168 | + pmu_ll_hp_set_memory_no_isolate (ctx->hal->dev, 0); |
| 169 | + |
| 170 | + pmu_ll_lp_set_power_force_power_up (ctx->hal->dev, false); |
| 171 | + pmu_ll_lp_set_power_force_no_reset (ctx->hal->dev, false); |
| 172 | + pmu_ll_lp_set_power_force_no_isolate(ctx->hal->dev, false); |
| 173 | + pmu_ll_lp_set_power_force_power_down(ctx->hal->dev, false); |
| 174 | + pmu_ll_lp_set_power_force_isolate (ctx->hal->dev, false); |
| 175 | + pmu_ll_lp_set_power_force_reset (ctx->hal->dev, false); |
| 176 | +} |
| 177 | + |
| 178 | +static inline void pmu_hp_system_param_default(pmu_hp_mode_t mode, pmu_hp_system_param_t *param) |
| 179 | +{ |
| 180 | + assert (param->analog); |
| 181 | + param->power = pmu_hp_system_power_param_default(mode); |
| 182 | + param->clock = pmu_hp_system_clock_param_default(mode); |
| 183 | + param->digital = pmu_hp_system_digital_param_default(mode); |
| 184 | + *param->analog = *pmu_hp_system_analog_param_default(mode); //copy default value |
| 185 | + param->retent = pmu_hp_system_retention_param_default(mode); |
| 186 | + |
| 187 | + if (mode == PMU_MODE_HP_ACTIVE || mode == PMU_MODE_HP_MODEM) { |
| 188 | + param->analog->regulator0.dbias = get_act_hp_dbias(); |
| 189 | + } |
| 190 | +} |
| 191 | + |
| 192 | +static void pmu_hp_system_init_default(pmu_context_t *ctx) |
| 193 | +{ |
| 194 | + assert(ctx); |
| 195 | + for (pmu_hp_mode_t mode = PMU_MODE_HP_ACTIVE; mode < PMU_MODE_HP_MAX; mode++) { |
| 196 | + pmu_hp_system_analog_param_t analog = {}; |
| 197 | + pmu_hp_system_param_t param = {.analog = &analog}; |
| 198 | + |
| 199 | + pmu_hp_system_param_default(mode, ¶m); |
| 200 | + pmu_hp_system_init(ctx, mode, ¶m); |
| 201 | + } |
| 202 | +} |
| 203 | + |
| 204 | +static inline void pmu_lp_system_param_default(pmu_lp_mode_t mode, pmu_lp_system_param_t *param) |
| 205 | +{ |
| 206 | + assert (param->analog); |
| 207 | + |
| 208 | + param->power = pmu_lp_system_power_param_default(mode); |
| 209 | + *param->analog = *pmu_lp_system_analog_param_default(mode); //copy default value |
| 210 | + |
| 211 | + if (mode == PMU_MODE_LP_ACTIVE) { |
| 212 | + param->analog->regulator0.dbias = get_act_lp_dbias(); |
| 213 | + } |
| 214 | +} |
| 215 | + |
| 216 | +static void pmu_lp_system_init_default(pmu_context_t *ctx) |
| 217 | +{ |
| 218 | + assert(ctx); |
| 219 | + for (pmu_lp_mode_t mode = PMU_MODE_LP_ACTIVE; mode < PMU_MODE_LP_MAX; mode++) { |
| 220 | + pmu_lp_system_analog_param_t analog = {}; |
| 221 | + pmu_lp_system_param_t param = {.analog = &analog}; |
| 222 | + |
| 223 | + pmu_lp_system_param_default(mode, ¶m); |
| 224 | + pmu_lp_system_init(ctx, mode, ¶m); |
| 225 | + } |
| 226 | +} |
| 227 | + |
| 228 | +void pmu_init(void) |
| 229 | +{ |
| 230 | +#if 0 // TODO: IDF-12313 |
| 231 | + /* Peripheral reg i2c power up */ |
| 232 | + SET_PERI_REG_MASK(PMU_RF_PWC_REG, PMU_XPD_PERIF_I2C); |
| 233 | + SET_PERI_REG_MASK(PMU_RF_PWC_REG, PMU_XPD_RFTX_I2C); |
| 234 | + SET_PERI_REG_MASK(PMU_RF_PWC_REG, PMU_XPD_RFRX_I2C); |
| 235 | + SET_PERI_REG_MASK(PMU_RF_PWC_REG, PMU_XPD_RFPLL); |
| 236 | + |
| 237 | + REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_ENIF_RTC_DREG, 1); |
| 238 | + REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_ENIF_DIG_DREG, 1); |
| 239 | + REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_XPD_RTC_REG, 0); |
| 240 | + REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_XPD_DIG_REG, 0); |
| 241 | +#endif |
| 242 | + |
| 243 | + pmu_hp_system_init_default(PMU_instance()); |
| 244 | + pmu_lp_system_init_default(PMU_instance()); |
| 245 | + |
| 246 | + pmu_power_domain_force_default(PMU_instance()); |
| 247 | +} |
0 commit comments