|
| 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 "soc/pvt_reg.h" |
| 15 | +#include "soc/pmu_reg.h" |
| 16 | +#include "hal/pmu_hal.h" |
| 17 | +#include "pmu_param.h" |
| 18 | +#include "esp_rom_sys.h" |
| 19 | +#include "esp_private/esp_pmu.h" |
| 20 | +#include "soc/regi2c_dig_reg.h" |
| 21 | +#include "regi2c_ctrl.h" |
| 22 | +#include "soc/rtc.h" |
| 23 | +#include "hal/efuse_ll.h" |
| 24 | +#include "hal/efuse_hal.h" |
| 25 | +#include "esp_hw_log.h" |
| 26 | + |
| 27 | +static __attribute__((unused)) const char *TAG = "pmu_pvt"; |
| 28 | + |
| 29 | +#if CONFIG_ESP_ENABLE_PVT |
| 30 | + |
| 31 | +static uint8_t get_lp_hp_gap(void) |
| 32 | +{ |
| 33 | + int8_t lp_hp_gap = 0; |
| 34 | + uint32_t blk_version = efuse_hal_blk_version(); |
| 35 | + uint8_t lp_hp_gap_efuse = 0; |
| 36 | + if (blk_version >= 2) { |
| 37 | + lp_hp_gap_efuse = efuse_ll_get_dbias_vol_gap(); |
| 38 | + bool gap_flag = lp_hp_gap_efuse >> 4; |
| 39 | + uint8_t gap_abs_value = lp_hp_gap_efuse & 0xf; |
| 40 | + if (gap_flag) { |
| 41 | + lp_hp_gap = -1 * gap_abs_value; |
| 42 | + } else { |
| 43 | + lp_hp_gap = gap_abs_value; |
| 44 | + } |
| 45 | + lp_hp_gap = lp_hp_gap - 8; |
| 46 | + assert((lp_hp_gap >= -15) && (lp_hp_gap <= 7)); |
| 47 | + if (lp_hp_gap < 0 ) { |
| 48 | + lp_hp_gap = 16 - lp_hp_gap; |
| 49 | + } |
| 50 | + } |
| 51 | + return lp_hp_gap; |
| 52 | +} |
| 53 | + |
| 54 | +static void set_pvt_hp_lp_gap(uint8_t value) |
| 55 | +{ |
| 56 | + bool flag = value >> 4; |
| 57 | + uint8_t abs_value = value & 0xf; |
| 58 | + |
| 59 | + SET_PERI_REG_BITS(PVT_DBIAS_CMD0_REG, PVT_DBIAS_CMD0_OFFSET_FLAG, flag, PVT_DBIAS_CMD0_OFFSET_FLAG_S); |
| 60 | + SET_PERI_REG_BITS(PVT_DBIAS_CMD0_REG, PVT_DBIAS_CMD0_OFFSET_VALUE, abs_value, PVT_DBIAS_CMD0_OFFSET_VALUE_S); |
| 61 | + SET_PERI_REG_BITS(PVT_DBIAS_CMD1_REG, PVT_DBIAS_CMD1_OFFSET_FLAG, flag, PVT_DBIAS_CMD1_OFFSET_FLAG_S); |
| 62 | + SET_PERI_REG_BITS(PVT_DBIAS_CMD1_REG, PVT_DBIAS_CMD1_OFFSET_VALUE, abs_value, PVT_DBIAS_CMD1_OFFSET_VALUE_S); |
| 63 | + SET_PERI_REG_BITS(PVT_DBIAS_CMD2_REG, PVT_DBIAS_CMD2_OFFSET_FLAG, flag, PVT_DBIAS_CMD2_OFFSET_FLAG_S); |
| 64 | + SET_PERI_REG_BITS(PVT_DBIAS_CMD2_REG, PVT_DBIAS_CMD2_OFFSET_VALUE, abs_value, PVT_DBIAS_CMD2_OFFSET_VALUE_S); |
| 65 | +} |
| 66 | + |
| 67 | +static uint32_t pvt_get_dcmvset(void) |
| 68 | +{ |
| 69 | + return GET_PERI_REG_BITS2(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_HP_DBIAS_VOL_V, PMU_HP_DBIAS_VOL_S); |
| 70 | +} |
| 71 | + |
| 72 | +static uint32_t pvt_get_lp_dbias(void) |
| 73 | +{ |
| 74 | + return GET_PERI_REG_BITS2(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_LP_DBIAS_VOL_V, PMU_LP_DBIAS_VOL_S); |
| 75 | +} |
| 76 | + |
| 77 | +void pvt_auto_dbias_init(void) |
| 78 | +{ |
| 79 | + uint32_t blk_version = efuse_hal_blk_version(); |
| 80 | + if (blk_version >= 2) { |
| 81 | + SET_PERI_REG_MASK(HP_SYS_CLKRST_REF_CLK_CTRL2_REG, HP_SYS_CLKRST_REG_REF_160M_CLK_EN); |
| 82 | + SET_PERI_REG_MASK(HP_SYS_CLKRST_SOC_CLK_CTRL1_REG, HP_SYS_CLKRST_REG_PVT_SYS_CLK_EN); |
| 83 | + /*config for dbias func*/ |
| 84 | + CLEAR_PERI_REG_MASK(PVT_DBIAS_TIMER_REG, PVT_TIMER_EN); |
| 85 | + esp_rom_delay_us(100); |
| 86 | + SET_PERI_REG_BITS(PVT_DBIAS_CHANNEL_SEL0_REG, PVT_DBIAS_CHANNEL0_SEL, PVT_CHANNEL0_SEL, PVT_DBIAS_CHANNEL0_SEL_S); |
| 87 | + SET_PERI_REG_BITS(PVT_DBIAS_CHANNEL_SEL0_REG, PVT_DBIAS_CHANNEL1_SEL, PVT_CHANNEL1_SEL, PVT_DBIAS_CHANNEL1_SEL_S); // Select monitor cell, which used to monitor PVT situation |
| 88 | + SET_PERI_REG_BITS(PVT_DBIAS_CHANNEL0_SEL_REG, PVT_DBIAS_CHANNEL0_CFG, PVT_CHANNEL0_CFG, PVT_DBIAS_CHANNEL0_CFG_S); |
| 89 | + SET_PERI_REG_BITS(PVT_DBIAS_CHANNEL1_SEL_REG, PVT_DBIAS_CHANNEL1_CFG, PVT_CHANNEL1_CFG, PVT_DBIAS_CHANNEL1_CFG_S); |
| 90 | + SET_PERI_REG_BITS(PVT_DBIAS_CHANNEL2_SEL_REG, PVT_DBIAS_CHANNEL2_CFG, PVT_CHANNEL2_CFG, PVT_DBIAS_CHANNEL2_CFG_S); // Configure filter threshold for avoiding auto-dbias overly sensitive regulation |
| 91 | + SET_PERI_REG_BITS(PVT_DBIAS_CMD0_REG, PVT_DBIAS_CMD0_PVT, PVT_CMD0, PVT_DBIAS_CMD0_PVT_S); |
| 92 | + SET_PERI_REG_BITS(PVT_DBIAS_CMD1_REG, PVT_DBIAS_CMD1_PVT, PVT_CMD1, PVT_DBIAS_CMD1_PVT_S); |
| 93 | + SET_PERI_REG_BITS(PVT_DBIAS_CMD2_REG, PVT_DBIAS_CMD2_PVT, PVT_CMD2, PVT_DBIAS_CMD2_PVT_S); // Configure auto-dbias adjust property, such as adjusting step |
| 94 | + SET_PERI_REG_MASK(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_DIG_DBIAS_INIT); // Start calibration @HP_CALI_DBIAS_DEFAULT |
| 95 | + SET_PERI_REG_BITS(PVT_DBIAS_TIMER_REG, PVT_TIMER_TARGET, PVT_TARGET, PVT_TIMER_TARGET_S); // Configure auto-dbias voltage regulation cycle |
| 96 | + |
| 97 | + SET_PERI_REG_BITS(HP_SYS_CLKRST_PERI_CLK_CTRL24_REG, HP_SYS_CLKRST_REG_PVT_CLK_DIV_NUM, PVT_CLK_DIV, HP_SYS_CLKRST_REG_PVT_CLK_DIV_NUM_S); // PVT function clock divider number |
| 98 | + SET_PERI_REG_BITS(HP_SYS_CLKRST_PERI_CLK_CTRL25_REG, HP_SYS_CLKRST_REG_PVT_PERI_GROUP_CLK_DIV_NUM, PVT_CLK_DIV, HP_SYS_CLKRST_REG_PVT_PERI_GROUP_CLK_DIV_NUM_S); // PVT function clock divider number |
| 99 | + SET_PERI_REG_MASK(HP_SYS_CLKRST_PERI_CLK_CTRL24_REG, HP_SYS_CLKRST_REG_PVT_CLK_EN); |
| 100 | + SET_PERI_REG_MASK(HP_SYS_CLKRST_PERI_CLK_CTRL25_REG, HP_SYS_CLKRST_REG_PVT_PERI_GROUP1_CLK_EN); |
| 101 | + SET_PERI_REG_MASK(HP_SYS_CLKRST_PERI_CLK_CTRL25_REG, HP_SYS_CLKRST_REG_PVT_PERI_GROUP2_CLK_EN); |
| 102 | + SET_PERI_REG_MASK(HP_SYS_CLKRST_PERI_CLK_CTRL25_REG, HP_SYS_CLKRST_REG_PVT_PERI_GROUP3_CLK_EN); |
| 103 | + SET_PERI_REG_MASK(HP_SYS_CLKRST_PERI_CLK_CTRL25_REG, HP_SYS_CLKRST_REG_PVT_PERI_GROUP4_CLK_EN); |
| 104 | + |
| 105 | + /*config for pvt cell: unit0; site3; vt1*/ |
| 106 | + SET_PERI_REG_MASK(PVT_CLK_CFG_REG, PVT_MONITOR_CLK_PVT_EN); // Once enable cannot be closed |
| 107 | + esp_rom_delay_us(100); |
| 108 | + SET_PERI_REG_BITS(PVT_COMB_PD_SITE3_UNIT0_VT1_CONF2_REG, PVT_MONITOR_EDG_MOD_VT1_PD_SITE3_UNIT0, PVT_EDG_MODE, PVT_MONITOR_EDG_MOD_VT1_PD_SITE3_UNIT0_S); // Select edge_mode |
| 109 | + SET_PERI_REG_BITS(PVT_COMB_PD_SITE3_UNIT0_VT1_CONF1_REG, PVT_DELAY_LIMIT_VT1_PD_SITE3_UNIT0, PVT_DELAY_NUM_HIGH, PVT_DELAY_LIMIT_VT1_PD_SITE3_UNIT0_S); // The threshold for determining whether the voltage is too high |
| 110 | + SET_PERI_REG_BITS(PVT_COMB_PD_SITE3_UNIT1_VT1_CONF1_REG, PVT_DELAY_LIMIT_VT1_PD_SITE3_UNIT1, PVT_DELAY_NUM_LOW, PVT_DELAY_LIMIT_VT1_PD_SITE3_UNIT1_S); // The threshold for determining whether the voltage is too low |
| 111 | + |
| 112 | + /*config lp offset for pvt func*/ |
| 113 | + uint8_t lp_hp_gap = get_lp_hp_gap(); |
| 114 | + set_pvt_hp_lp_gap(lp_hp_gap); |
| 115 | + } else { |
| 116 | + ESP_HW_LOGW(TAG, "blk_version is less than 2, pvt auto dbias init not supported in efuse."); |
| 117 | + } |
| 118 | +} |
| 119 | + |
| 120 | +void pvt_func_enable(bool enable) |
| 121 | +{ |
| 122 | + uint32_t blk_version = efuse_hal_blk_version(); |
| 123 | + if (blk_version >= 2){ |
| 124 | + |
| 125 | + if (enable) { |
| 126 | + SET_PERI_REG_MASK(HP_SYS_CLKRST_REF_CLK_CTRL2_REG, HP_SYS_CLKRST_REG_REF_160M_CLK_EN); |
| 127 | + SET_PERI_REG_MASK(HP_SYS_CLKRST_SOC_CLK_CTRL1_REG, HP_SYS_CLKRST_REG_PVT_SYS_CLK_EN); |
| 128 | + SET_PERI_REG_MASK(HP_SYS_CLKRST_PERI_CLK_CTRL24_REG, HP_SYS_CLKRST_REG_PVT_CLK_EN); |
| 129 | + SET_PERI_REG_MASK(HP_SYS_CLKRST_PERI_CLK_CTRL25_REG, HP_SYS_CLKRST_REG_PVT_PERI_GROUP1_CLK_EN); |
| 130 | + SET_PERI_REG_MASK(HP_SYS_CLKRST_PERI_CLK_CTRL25_REG, HP_SYS_CLKRST_REG_PVT_PERI_GROUP2_CLK_EN); |
| 131 | + SET_PERI_REG_MASK(HP_SYS_CLKRST_PERI_CLK_CTRL25_REG, HP_SYS_CLKRST_REG_PVT_PERI_GROUP3_CLK_EN); |
| 132 | + SET_PERI_REG_MASK(HP_SYS_CLKRST_PERI_CLK_CTRL25_REG, HP_SYS_CLKRST_REG_PVT_PERI_GROUP4_CLK_EN); |
| 133 | + SET_PERI_REG_MASK(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_DIG_DBIAS_INIT); // Start calibration @HP_CALI_DBIAS_DEFAULT |
| 134 | + SET_PERI_REG_MASK(PVT_CLK_CFG_REG, PVT_MONITOR_CLK_PVT_EN); // Once enable cannot be closed |
| 135 | + SET_PERI_REG_MASK(PVT_COMB_PD_SITE3_UNIT0_VT1_CONF1_REG, PVT_MONITOR_EN_VT1_PD_SITE3_UNIT0); // Enable pvt clk |
| 136 | + esp_rom_delay_us(1000); |
| 137 | + CLEAR_PERI_REG_MASK(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_DIG_REGULATOR0_DBIAS_SEL); // Hand over control of dbias to pvt |
| 138 | + CLEAR_PERI_REG_MASK(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_DIG_DBIAS_INIT); // Must clear @HP_CALI_DBIAS_DEFAULT |
| 139 | + SET_PERI_REG_MASK(PVT_DBIAS_TIMER_REG, PVT_TIMER_EN); // Enable auto dbias |
| 140 | + } else { |
| 141 | + uint32_t pvt_dcmvset = pvt_get_dcmvset(); |
| 142 | + uint32_t pvt_lpdbias = pvt_get_lp_dbias(); // Update pvt_cali_dbias |
| 143 | + SET_PERI_REG_BITS(PMU_HP_ACTIVE_BIAS_REG, PMU_HP_ACTIVE_DCM_VSET, pvt_dcmvset, PMU_HP_ACTIVE_DCM_VSET_S); |
| 144 | + SET_PERI_REG_BITS(PMU_HP_SLEEP_LP_REGULATOR0_REG, PMU_HP_SLEEP_LP_REGULATOR_DBIAS, pvt_lpdbias, PMU_HP_SLEEP_LP_REGULATOR_DBIAS_S); |
| 145 | + SET_PERI_REG_MASK(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_DIG_REGULATOR0_DBIAS_SEL); // Hand over control of dbias to pmu |
| 146 | + CLEAR_PERI_REG_MASK(HP_SYS_CLKRST_PERI_CLK_CTRL24_REG, HP_SYS_CLKRST_REG_PVT_CLK_EN); |
| 147 | + } |
| 148 | + } else { |
| 149 | + ESP_HW_LOGD(TAG, "blk_version is less than 2, pvt function not supported in efuse."); |
| 150 | + } |
| 151 | +} |
| 152 | + |
| 153 | +#endif |
0 commit comments