diff --git a/components/esp_hw_support/port/esp32c6/private_include/ocode_init.h b/components/esp_hw_support/include/esp_private/ocode_init.h similarity index 100% rename from components/esp_hw_support/port/esp32c6/private_include/ocode_init.h rename to components/esp_hw_support/include/esp_private/ocode_init.h diff --git a/components/esp_hw_support/port/esp32c5/CMakeLists.txt b/components/esp_hw_support/port/esp32c5/CMakeLists.txt index b6f2939450..3d96ad1e1c 100644 --- a/components/esp_hw_support/port/esp32c5/CMakeLists.txt +++ b/components/esp_hw_support/port/esp32c5/CMakeLists.txt @@ -5,6 +5,7 @@ set(srcs "rtc_clk_init.c" "pmu_init.c" "pmu_sleep.c" "chip_info.c" + "ocode_init.c" ) if(NOT BOOTLOADER_BUILD) diff --git a/components/esp_hw_support/port/esp32c5/ocode_init.c b/components/esp_hw_support/port/esp32c5/ocode_init.c new file mode 100644 index 0000000000..e17a972bbb --- /dev/null +++ b/components/esp_hw_support/port/esp32c5/ocode_init.c @@ -0,0 +1,92 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "soc/rtc.h" +#include "esp_attr.h" +#include "soc/regi2c_dig_reg.h" +#include "soc/regi2c_lp_bias.h" +#include "hal/efuse_hal.h" +#include "hal/efuse_ll.h" +#include "hal/clk_tree_ll.h" +#include "esp_private/regi2c_ctrl.h" +#include "esp_hw_log.h" + +static const char *TAG = "ocode_init"; + +static void set_ocode_by_efuse(int ocode_scheme_ver) +{ + assert(ocode_scheme_ver == 1); + unsigned int ocode = efuse_ll_get_ocode(); + + //set ext_ocode + REGI2C_WRITE_MASK(I2C_ULP, I2C_ULP_EXT_CODE, ocode); + REGI2C_WRITE_MASK(I2C_ULP, I2C_ULP_IR_FORCE_CODE, 1); +} + +static void IRAM_ATTR calibrate_ocode(void) +{ + /* + Bandgap output voltage is not precise when calibrate o-code by hardware sometimes, so need software o-code calibration (must turn off PLL). + Method: + 1. read current cpu config, save in old_config; + 2. switch cpu to xtal because PLL will be closed when o-code calibration; + 3. begin o-code calibration; + 4. wait o-code calibration done flag(odone_flag & bg_odone_flag) or timeout; + 5. set cpu to old-config. + */ + soc_rtc_slow_clk_src_t slow_clk_src = rtc_clk_slow_src_get(); + rtc_cal_sel_t cal_clk = RTC_CAL_RTC_MUX; + if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_OSC_SLOW) { + cal_clk = RTC_CAL_32K_OSC_SLOW; + } else if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_XTAL32K) { + cal_clk = RTC_CAL_32K_XTAL; + } + + uint64_t max_delay_time_us = 10000; + uint32_t slow_clk_period = rtc_clk_cal(cal_clk, 100); + uint64_t max_delay_cycle = rtc_time_us_to_slowclk(max_delay_time_us, slow_clk_period); + uint64_t cycle0 = rtc_time_get(); + uint64_t timeout_cycle = cycle0 + max_delay_cycle; + uint64_t cycle1 = 0; + + rtc_cpu_freq_config_t old_config; + rtc_clk_cpu_freq_get_config(&old_config); + rtc_clk_cpu_freq_set_xtal(); + + ANALOG_CLOCK_ENABLE(); + REGI2C_WRITE_MASK(I2C_ULP, I2C_ULP_IR_RESETB, 0); + REGI2C_WRITE_MASK(I2C_ULP, I2C_ULP_IR_RESETB, 1); + bool odone_flag = 0; + bool bg_odone_flag = 0; + while (1) { + odone_flag = REGI2C_READ_MASK(I2C_ULP, I2C_ULP_O_DONE_FLAG); + bg_odone_flag = REGI2C_READ_MASK(I2C_ULP, I2C_ULP_BG_O_DONE_FLAG); + cycle1 = rtc_time_get(); + if (odone_flag && bg_odone_flag) { + break; + } + if (cycle1 >= timeout_cycle) { + ESP_HW_LOGW(TAG, "o_code calibration fail\n"); + break; + } + } + ANALOG_CLOCK_DISABLE(); + + rtc_clk_cpu_freq_set_config(&old_config); +} + +void esp_ocode_calib_init(void) +{ + uint32_t blk_ver = efuse_hal_blk_version(); + if ((blk_ver >= 1) && (blk_ver < 100)) { + set_ocode_by_efuse(1); + ESP_HW_LOGD(TAG, "efuse ocode"); + } else { + calibrate_ocode(); + ESP_HW_LOGD(TAG, "calib ocode"); + } +} diff --git a/components/esp_system/port/soc/esp32c5/clk.c b/components/esp_system/port/soc/esp32c5/clk.c index 16cbb648e2..a617a63e54 100644 --- a/components/esp_system/port/soc/esp32c5/clk.c +++ b/components/esp_system/port/soc/esp32c5/clk.c @@ -31,6 +31,7 @@ #include "esp_private/periph_ctrl.h" #include "esp_private/esp_clk.h" #include "esp_private/esp_pmu.h" +#include "esp_private/ocode_init.h" #include "esp_rom_uart.h" #include "esp_rom_sys.h" @@ -50,6 +51,9 @@ void esp_rtc_init(void) { #if !CONFIG_IDF_ENV_FPGA pmu_init(); + if (esp_rom_get_reset_reason(0) == RESET_REASON_CHIP_POWER_ON) { + esp_ocode_calib_init(); + } #endif } diff --git a/components/esp_system/port/soc/esp32c6/clk.c b/components/esp_system/port/soc/esp32c6/clk.c index ca2b940060..15c8dfd70b 100644 --- a/components/esp_system/port/soc/esp32c6/clk.c +++ b/components/esp_system/port/soc/esp32c6/clk.c @@ -45,9 +45,9 @@ #include "esp_private/periph_ctrl.h" #include "esp_private/esp_clk.h" #include "esp_private/esp_pmu.h" +#include "esp_private/ocode_init.h" #include "esp_rom_uart.h" #include "esp_rom_sys.h" -#include "ocode_init.h" /* Number of cycles to wait from the 32k XTAL oscillator to consider it running. * Larger values increase startup delay. Smaller values may cause false positive diff --git a/components/hal/esp32c5/include/hal/efuse_ll.h b/components/hal/esp32c5/include/hal/efuse_ll.h index 00bb7f61ca..00d5dce614 100644 --- a/components/hal/esp32c5/include/hal/efuse_ll.h +++ b/components/hal/esp32c5/include/hal/efuse_ll.h @@ -98,6 +98,11 @@ __attribute__((always_inline)) static inline void efuse_ll_set_ecdsa_key_blk(int EFUSE.conf.cfg_ecdsa_blk = efuse_blk; } +__attribute__((always_inline)) static inline uint32_t efuse_ll_get_ocode(void) +{ + return EFUSE.rd_sys_part1_data4.ocode; +} + /******************* eFuse control functions *************************/ __attribute__((always_inline)) static inline bool efuse_ll_get_read_cmd(void) diff --git a/components/soc/esp32c5/include/soc/regi2c_lp_bias.h b/components/soc/esp32c5/include/soc/regi2c_lp_bias.h new file mode 100644 index 0000000000..4c69ac7d26 --- /dev/null +++ b/components/soc/esp32c5/include/soc/regi2c_lp_bias.h @@ -0,0 +1,55 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +/** + * @file regi2c_lp_bias.h + * @brief Register definitions for analog to calibrate o_code for getting a more precise voltage. + * + * This file lists register fields of low power dbais, located on an internal configuration + * bus. These definitions are used via macros defined in regi2c_ctrl.h, by + * rtc_init function in rtc_init.c. + */ + +#define I2C_ULP 0x61 +#define I2C_ULP_HOSTID 0 + +#define I2C_ULP_IR_RESETB 0 +#define I2C_ULP_IR_RESETB_MSB 0 +#define I2C_ULP_IR_RESETB_LSB 0 + +#define I2C_ULP_IR_FORCE_XPD_CK 0 +#define I2C_ULP_IR_FORCE_XPD_CK_MSB 2 +#define I2C_ULP_IR_FORCE_XPD_CK_LSB 2 + +#define I2C_ULP_IR_FORCE_XPD_IPH 0 +#define I2C_ULP_IR_FORCE_XPD_IPH_MSB 4 +#define I2C_ULP_IR_FORCE_XPD_IPH_LSB 4 + +#define I2C_ULP_IR_DISABLE_WATCHDOG_CK 0 +#define I2C_ULP_IR_DISABLE_WATCHDOG_CK_MSB 6 +#define I2C_ULP_IR_DISABLE_WATCHDOG_CK_LSB 6 + +#define I2C_ULP_O_DONE_FLAG 3 +#define I2C_ULP_O_DONE_FLAG_MSB 0 +#define I2C_ULP_O_DONE_FLAG_LSB 0 + +#define I2C_ULP_BG_O_DONE_FLAG 3 +#define I2C_ULP_BG_O_DONE_FLAG_MSB 3 +#define I2C_ULP_BG_O_DONE_FLAG_LSB 3 + +#define I2C_ULP_OCODE 4 +#define I2C_ULP_OCODE_MSB 7 +#define I2C_ULP_OCODE_LSB 0 + +#define I2C_ULP_IR_FORCE_CODE 5 +#define I2C_ULP_IR_FORCE_CODE_MSB 6 +#define I2C_ULP_IR_FORCE_CODE_LSB 6 + +#define I2C_ULP_EXT_CODE 6 +#define I2C_ULP_EXT_CODE_MSB 7 +#define I2C_ULP_EXT_CODE_LSB 0