1 /*
2 * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <stdint.h>
8 #include "esp32c6/rom/ets_sys.h"
9 #include "soc/rtc.h"
10 #include "soc/lp_timer_reg.h"
11 #include "hal/lp_timer_hal.h"
12 #include "hal/clk_tree_ll.h"
13 #include "soc/timer_group_reg.h"
14 #include "esp_rom_sys.h"
15 #include "assert.h"
16 #include "hal/efuse_hal.h"
17 #include "soc/chip_revision.h"
18
19 static const char *TAG = "rtc_time";
20
21 /* Calibration of RTC_SLOW_CLK is performed using a special feature of TIMG0.
22 * This feature counts the number of XTAL clock cycles within a given number of
23 * RTC_SLOW_CLK cycles.
24 *
25 * Slow clock calibration feature has two modes of operation: one-off and cycling.
26 * In cycling mode (which is enabled by default on SoC reset), counting of XTAL
27 * cycles within RTC_SLOW_CLK cycle is done continuously. Cycling mode is enabled
28 * using TIMG_RTC_CALI_START_CYCLING bit. In one-off mode counting is performed
29 * once, and TIMG_RTC_CALI_RDY bit is set when counting is done. One-off mode is
30 * enabled using TIMG_RTC_CALI_START bit.
31 */
32
33 /* On ESP32C6, TIMG_RTC_CALI_CLK_SEL can config to 0, 1, 2, 3
34 * 0 or 3: calibrate RC_SLOW clock
35 * 1: calibrate RC_FAST clock
36 * 2: calibrate 32K clock, which 32k depends on reg_32k_sel: 0: Internal 32 kHz RC oscillator, 1: External 32 kHz XTAL, 2: External 32kHz clock input by lp_pad_gpio0
37 */
38 #define TIMG_RTC_CALI_CLK_SEL_RC_SLOW 0
39 #define TIMG_RTC_CALI_CLK_SEL_RC_FAST 1
40 #define TIMG_RTC_CALI_CLK_SEL_32K 2
41
42 /**
43 * @brief Clock calibration function used by rtc_clk_cal
44 *
45 * Calibration of RTC_SLOW_CLK is performed using a special feature of TIMG0.
46 * This feature counts the number of XTAL clock cycles within a given number of
47 * RTC_SLOW_CLK cycles.
48 *
49 * Slow clock calibration feature has two modes of operation: one-off and cycling.
50 * In cycling mode (which is enabled by default on SoC reset), counting of XTAL
51 * cycles within RTC_SLOW_CLK cycle is done continuously. Cycling mode is enabled
52 * using TIMG_RTC_CALI_START_CYCLING bit. In one-off mode counting is performed
53 * once, and TIMG_RTC_CALI_RDY bit is set when counting is done. One-off mode is
54 * enabled using TIMG_RTC_CALI_START bit.
55 *
56 * @param cal_clk which clock to calibrate
57 * @param slowclk_cycles number of slow clock cycles to count
58 * @return number of XTAL clock cycles within the given number of slow clock cycles
59 */
rtc_clk_cal_internal(rtc_cal_sel_t cal_clk,uint32_t slowclk_cycles)60 static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
61 {
62 assert(slowclk_cycles < TIMG_RTC_CALI_MAX_V);
63
64 uint32_t cali_clk_sel = 0;
65 soc_rtc_slow_clk_src_t slow_clk_src = rtc_clk_slow_src_get();
66 soc_rtc_slow_clk_src_t old_32k_cal_clk_sel = clk_ll_32k_calibration_get_target();
67 if (cal_clk == RTC_CAL_RTC_MUX) {
68 cal_clk = (rtc_cal_sel_t)slow_clk_src;
69 }
70 if (cal_clk == RTC_CAL_RC_FAST) {
71 cali_clk_sel = TIMG_RTC_CALI_CLK_SEL_RC_FAST;
72 } else if (cal_clk == RTC_CAL_RC_SLOW) {
73 cali_clk_sel = TIMG_RTC_CALI_CLK_SEL_RC_SLOW;
74 } else {
75 cali_clk_sel = TIMG_RTC_CALI_CLK_SEL_32K;
76 clk_ll_32k_calibration_set_target((soc_rtc_slow_clk_src_t)cal_clk);
77 }
78
79
80 /* Enable requested clock (150k clock is always on) */
81 // All clocks on/off takes time to be stable, so we shouldn't frequently enable/disable the clock
82 // Only enable if orignally was disabled, and set back to the disable state after calibration is done
83 // If the clock is already on, then do nothing
84 bool dig_32k_xtal_enabled = clk_ll_xtal32k_digi_is_enabled();
85 if (cal_clk == RTC_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
86 clk_ll_xtal32k_digi_enable();
87 }
88
89 bool rc_fast_enabled = clk_ll_rc_fast_is_enabled();
90 bool dig_rc_fast_enabled = clk_ll_rc_fast_digi_is_enabled();
91 if (cal_clk == RTC_CAL_RC_FAST) {
92 if (!rc_fast_enabled) {
93 rtc_clk_8m_enable(true);
94 }
95 if (!dig_rc_fast_enabled) {
96 rtc_dig_clk8m_enable();
97 }
98 }
99
100 bool rc32k_enabled = clk_ll_rc32k_is_enabled();
101 bool dig_rc32k_enabled = clk_ll_rc32k_digi_is_enabled();
102 if (cal_clk == RTC_CAL_RC32K) {
103 if (!rc32k_enabled) {
104 rtc_clk_rc32k_enable(true);
105 }
106 if (!dig_rc32k_enabled) {
107 clk_ll_rc32k_digi_enable();
108 }
109 }
110
111 /* There may be another calibration process already running during we call this function,
112 * so we should wait the last process is done.
113 */
114 if (GET_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START_CYCLING)) {
115 /**
116 * Set a small timeout threshold to accelerate the generation of timeout.
117 * The internal circuit will be reset when the timeout occurs and will not affect the next calibration.
118 */
119 REG_SET_FIELD(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT_THRES, 1);
120 while (!GET_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_RDY)
121 && !GET_PERI_REG_MASK(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT));
122 }
123
124 /* Prepare calibration */
125 REG_SET_FIELD(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_CLK_SEL, cali_clk_sel);
126 CLEAR_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START_CYCLING);
127 REG_SET_FIELD(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_MAX, slowclk_cycles);
128 /* Figure out how long to wait for calibration to finish */
129
130 /* Set timeout reg and expect time delay*/
131 uint32_t expected_freq;
132 if (cali_clk_sel == TIMG_RTC_CALI_CLK_SEL_32K) {
133 REG_SET_FIELD(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT_THRES, RTC_SLOW_CLK_32K_CAL_TIMEOUT_THRES(slowclk_cycles));
134 expected_freq = SOC_CLK_XTAL32K_FREQ_APPROX;
135 } else if (cali_clk_sel == TIMG_RTC_CALI_CLK_SEL_RC_FAST) {
136 REG_SET_FIELD(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT_THRES, RTC_FAST_CLK_20M_CAL_TIMEOUT_THRES(slowclk_cycles));
137 expected_freq = SOC_CLK_RC_FAST_FREQ_APPROX;
138 } else {
139 REG_SET_FIELD(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT_THRES, RTC_SLOW_CLK_150K_CAL_TIMEOUT_THRES(slowclk_cycles));
140 expected_freq = SOC_CLK_RC_SLOW_FREQ_APPROX;
141 }
142 uint32_t us_time_estimate = (uint32_t) (((uint64_t) slowclk_cycles) * MHZ / expected_freq);
143 /* Start calibration */
144 CLEAR_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START);
145 SET_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START);
146
147 /* Wait for calibration to finish up to another us_time_estimate */
148 esp_rom_delay_us(us_time_estimate);
149 uint32_t cal_val;
150 while (true) {
151 if (GET_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_RDY)) {
152 cal_val = REG_GET_FIELD(TIMG_RTCCALICFG1_REG(0), TIMG_RTC_CALI_VALUE);
153
154 /*The Fosc CLK of calibration circuit is divided by 32 for ECO1.
155 So we need to multiply the frequency of the Fosc for ECO1 and above chips by 32 times.
156 And ensure that this modification will not affect ECO0.*/
157 if (ESP_CHIP_REV_ABOVE(efuse_hal_chip_revision(), 1)) {
158 if (cal_clk == RTC_CAL_RC_FAST) {
159 cal_val = cal_val >> 5;
160 }
161 }
162 break;
163 }
164 if (GET_PERI_REG_MASK(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT)) {
165 cal_val = 0;
166 break;
167 }
168 }
169 CLEAR_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START);
170
171 /* if dig_32k_xtal was originally off and enabled due to calibration, then set back to off state */
172 if (cal_clk == RTC_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
173 clk_ll_xtal32k_digi_disable();
174 }
175
176 if (cal_clk == RTC_CAL_RC_FAST) {
177 if (!dig_rc_fast_enabled) {
178 rtc_dig_clk8m_disable();
179 }
180 if (!rc_fast_enabled) {
181 rtc_clk_8m_enable(false);
182 }
183 }
184
185 if (cal_clk == RTC_CAL_RC32K) {
186 if (!dig_rc32k_enabled) {
187 clk_ll_rc32k_digi_disable();
188 }
189 if (!rc32k_enabled) {
190 rtc_clk_rc32k_enable(false);
191 }
192 }
193
194 // Always set back the calibration 32kHz clock selection
195 if (old_32k_cal_clk_sel != SOC_RTC_SLOW_CLK_SRC_INVALID) {
196 clk_ll_32k_calibration_set_target(old_32k_cal_clk_sel);
197 }
198
199 return cal_val;
200 }
201
rtc_clk_cal_32k_valid(rtc_xtal_freq_t xtal_freq,uint32_t slowclk_cycles,uint64_t actual_xtal_cycles)202 static bool rtc_clk_cal_32k_valid(rtc_xtal_freq_t xtal_freq, uint32_t slowclk_cycles, uint64_t actual_xtal_cycles)
203 {
204 uint64_t expected_xtal_cycles = (xtal_freq * 1000000ULL * slowclk_cycles) >> 15; // xtal_freq(hz) * slowclk_cycles / 32768
205 uint64_t delta = expected_xtal_cycles / 2000; // 5/10000 = 0.05% error range
206 return (actual_xtal_cycles >= (expected_xtal_cycles - delta)) && (actual_xtal_cycles <= (expected_xtal_cycles + delta));
207 }
208
rtc_clk_cal(rtc_cal_sel_t cal_clk,uint32_t slowclk_cycles)209 uint32_t rtc_clk_cal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
210 {
211 assert(slowclk_cycles);
212 rtc_xtal_freq_t xtal_freq = rtc_clk_xtal_freq_get();
213
214 /*The Fosc CLK of calibration circuit is divided by 32 for ECO1.
215 So we need to divide the calibrate cycles of the FOSC for ECO1 and above chips by 32 to
216 avoid excessive calibration time.*/
217 if (ESP_CHIP_REV_ABOVE(efuse_hal_chip_revision(), 1)) {
218 if (cal_clk == RTC_CAL_RC_FAST) {
219 slowclk_cycles = slowclk_cycles >> 5;
220 }
221 }
222
223 uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk, slowclk_cycles);
224
225 if (cal_clk == RTC_CAL_32K_XTAL && !rtc_clk_cal_32k_valid(xtal_freq, slowclk_cycles, xtal_cycles)) {
226 return 0;
227 }
228
229 uint64_t divider = ((uint64_t)xtal_freq) * slowclk_cycles;
230 uint64_t period_64 = ((xtal_cycles << RTC_CLK_CAL_FRACT) + divider / 2 - 1) / divider;
231 uint32_t period = (uint32_t)(period_64 & UINT32_MAX);
232 return period;
233 }
234
rtc_time_us_to_slowclk(uint64_t time_in_us,uint32_t period)235 uint64_t rtc_time_us_to_slowclk(uint64_t time_in_us, uint32_t period)
236 {
237 assert(period);
238 /* Overflow will happen in this function if time_in_us >= 2^45, which is about 400 days.
239 * TODO: fix overflow.
240 */
241 return (time_in_us << RTC_CLK_CAL_FRACT) / period;
242 }
243
rtc_time_slowclk_to_us(uint64_t rtc_cycles,uint32_t period)244 uint64_t rtc_time_slowclk_to_us(uint64_t rtc_cycles, uint32_t period)
245 {
246 return (rtc_cycles * period) >> RTC_CLK_CAL_FRACT;
247 }
248
rtc_time_get(void)249 uint64_t rtc_time_get(void)
250 {
251 return lp_timer_hal_get_cycle_count();
252 }
253
rtc_clk_wait_for_slow_cycle(void)254 void rtc_clk_wait_for_slow_cycle(void) //This function may not by useful any more
255 {
256 // TODO: IDF-5781
257 ESP_EARLY_LOGW(TAG, "rtc_clk_wait_for_slow_cycle() has not been implemented yet");
258 }
259
rtc_clk_freq_cal(uint32_t cal_val)260 uint32_t rtc_clk_freq_cal(uint32_t cal_val)
261 {
262 if (cal_val == 0) {
263 return 0; // cal_val will be denominator, return 0 as the symbol of failure.
264 }
265 return 1000000ULL * (1 << RTC_CLK_CAL_FRACT) / cal_val;
266 }
267