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