1 /*
2  * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <stdint.h>
8 #include "soc/soc.h"
9 #include "soc/rtc.h"
10 #include "soc/regi2c_dig_reg.h"
11 #include "soc/regi2c_lp_bias.h"
12 #include "hal/efuse_hal.h"
13 #include "hal/efuse_ll.h"
14 #include "regi2c_ctrl.h"
15 #include "esp_hw_log.h"
16 
17 
18 static const char *TAG = "ocode_init";
19 
set_ocode_by_efuse(int ocode_scheme_ver)20 static void set_ocode_by_efuse(int ocode_scheme_ver)
21 {
22     assert(ocode_scheme_ver == 1);
23     unsigned int ocode = efuse_ll_get_ocode();
24 
25     //set ext_ocode
26     REGI2C_WRITE_MASK(I2C_ULP, I2C_ULP_EXT_CODE, ocode);
27     REGI2C_WRITE_MASK(I2C_ULP, I2C_ULP_IR_FORCE_CODE, 1);
28 }
29 
calibrate_ocode(void)30 static void calibrate_ocode(void)
31 {
32     /*
33     Bandgap output voltage is not precise when calibrate o-code by hardware sometimes, so need software o-code calibration (must turn off PLL).
34     Method:
35     1. read current cpu config, save in old_config;
36     2. switch cpu to xtal because PLL will be closed when o-code calibration;
37     3. begin o-code calibration;
38     4. wait o-code calibration done flag(odone_flag & bg_odone_flag) or timeout;
39     5. set cpu to old-config.
40     */
41     soc_rtc_slow_clk_src_t slow_clk_src = rtc_clk_slow_src_get();
42     rtc_cal_sel_t cal_clk = RTC_CAL_RTC_MUX;
43     if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_OSC_SLOW) {
44         cal_clk = RTC_CAL_32K_OSC_SLOW;
45     } else if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_XTAL32K) {
46         cal_clk  = RTC_CAL_32K_XTAL;
47     }
48 
49     uint64_t max_delay_time_us = 10000;
50     uint32_t slow_clk_period = rtc_clk_cal(cal_clk, 100);
51     uint64_t max_delay_cycle = rtc_time_us_to_slowclk(max_delay_time_us, slow_clk_period);
52     uint64_t cycle0 = rtc_time_get();
53     uint64_t timeout_cycle = cycle0 + max_delay_cycle;
54     uint64_t cycle1 = 0;
55 
56     rtc_cpu_freq_config_t old_config;
57     rtc_clk_cpu_freq_get_config(&old_config);
58     rtc_clk_cpu_freq_set_xtal();
59 
60     REGI2C_WRITE_MASK(I2C_ULP, I2C_ULP_IR_RESETB, 0);
61     REGI2C_WRITE_MASK(I2C_ULP, I2C_ULP_IR_RESETB, 1);
62     bool odone_flag = 0;
63     bool bg_odone_flag = 0;
64     while (1) {
65         odone_flag = REGI2C_READ_MASK(I2C_ULP, I2C_ULP_O_DONE_FLAG);
66         bg_odone_flag = REGI2C_READ_MASK(I2C_ULP, I2C_ULP_BG_O_DONE_FLAG);
67         cycle1 = rtc_time_get();
68         if (odone_flag && bg_odone_flag) {
69             break;
70         }
71         if (cycle1 >= timeout_cycle) {
72             ESP_HW_LOGW(TAG, "o_code calibration fail\n");
73             break;
74         }
75     }
76     rtc_clk_cpu_freq_set_config(&old_config);
77 }
78 
esp_ocode_calib_init(void)79 void esp_ocode_calib_init(void)
80 {
81     if (efuse_hal_blk_version() >= 1) {
82         set_ocode_by_efuse(1);
83     } else {
84         calibrate_ocode();
85     }
86 }
87