1 /*
2  * SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <stdbool.h>
8 #include <stdint.h>
9 #include <stddef.h>
10 #include <assert.h>
11 #include <stdlib.h>
12 #include "sdkconfig.h"
13 #include "esp32c3/rom/ets_sys.h"
14 #include "esp32c3/rom/rtc.h"
15 #include "esp32c3/rom/gpio.h"
16 #include "soc/rtc.h"
17 #include "soc/rtc_cntl_reg.h"
18 #include "soc/efuse_reg.h"
19 #include "soc/syscon_reg.h"
20 #include "soc/system_reg.h"
21 #include "regi2c_ctrl.h"
22 #include "soc_log.h"
23 #include "rtc_clk_common.h"
24 #include "esp_rom_sys.h"
25 #include "hal/usb_serial_jtag_ll.h"
26 static const char *TAG = "rtc_clk";
27 
28 #define RTC_PLL_FREQ_320M   320
29 #define RTC_PLL_FREQ_480M   480
30 #define DELAY_RTC_CLK_SWITCH 5
31 
32 // Current PLL frequency, in MHZ (320 or 480). Zero if PLL is not enabled.
33 static int s_cur_pll_freq;
34 
35 static void rtc_clk_cpu_freq_to_8m(void);
36 static bool rtc_clk_set_bbpll_always_on(void);
37 
rtc_clk_32k_enable_internal(x32k_config_t cfg)38 void rtc_clk_32k_enable_internal(x32k_config_t cfg)
39 {
40     REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_DAC_XTAL_32K, cfg.dac);
41     REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_DRES_XTAL_32K, cfg.dres);
42     REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_DGM_XTAL_32K, cfg.dgm);
43     REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_DBUF_XTAL_32K, cfg.dbuf);
44     SET_PERI_REG_MASK(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_XPD_XTAL_32K);
45 }
46 
rtc_clk_32k_enable(bool enable)47 void rtc_clk_32k_enable(bool enable)
48 {
49     if (enable) {
50         x32k_config_t cfg = X32K_CONFIG_DEFAULT();
51         rtc_clk_32k_enable_internal(cfg);
52     } else {
53         SET_PERI_REG_MASK(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_XTAL32K_XPD_FORCE);
54         CLEAR_PERI_REG_MASK(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_XPD_XTAL_32K);
55     }
56 }
57 
rtc_clk_32k_enable_external(void)58 void rtc_clk_32k_enable_external(void)
59 {
60     /* TODO ESP32-C3 IDF-2408: external 32k source may need different settings */
61     x32k_config_t cfg = X32K_CONFIG_DEFAULT();
62     rtc_clk_32k_enable_internal(cfg);
63 }
64 
rtc_clk_32k_bootstrap(uint32_t cycle)65 void rtc_clk_32k_bootstrap(uint32_t cycle)
66 {
67     /* No special bootstrapping needed for ESP32-C3, 'cycle' argument is to keep the signature
68      * same as for the ESP32. Just enable the XTAL here.
69      */
70     (void) cycle;
71     rtc_clk_32k_enable(true);
72 }
73 
rtc_clk_32k_enabled(void)74 bool rtc_clk_32k_enabled(void)
75 {
76     uint32_t xtal_conf = READ_PERI_REG(RTC_CNTL_EXT_XTL_CONF_REG);
77     /* If xtal xpd is controlled by software */
78     bool xtal_xpd_sw = (xtal_conf & RTC_CNTL_XTAL32K_XPD_FORCE) >> RTC_CNTL_XTAL32K_XPD_FORCE_S;
79     /* If xtal xpd software control is on */
80     bool xtal_xpd_st = (xtal_conf & RTC_CNTL_XPD_XTAL_32K) >> RTC_CNTL_XPD_XTAL_32K_S;
81     bool disabled = xtal_xpd_sw && !xtal_xpd_st;
82     return !disabled;
83 }
84 
rtc_clk_8m_enable(bool clk_8m_en,bool d256_en)85 void rtc_clk_8m_enable(bool clk_8m_en, bool d256_en)
86 {
87     if (clk_8m_en) {
88         CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M);
89         /* no need to wait once enabled by software */
90         REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT, RTC_CK8M_ENABLE_WAIT_DEFAULT);
91         esp_rom_delay_us(DELAY_8M_ENABLE);
92     } else {
93         SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M);
94         REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT, RTC_CNTL_CK8M_WAIT_DEFAULT);
95     }
96     /* d256 should be independent configured with 8M
97      * Maybe we can split this function into 8m and dmd256
98      */
99     if (d256_en) {
100         CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV);
101     } else {
102         SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV);
103     }
104 }
105 
rtc_clk_8m_enabled(void)106 bool rtc_clk_8m_enabled(void)
107 {
108     return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M) == 0;
109 }
110 
rtc_clk_8md256_enabled(void)111 bool rtc_clk_8md256_enabled(void)
112 {
113     return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV) == 0;
114 }
115 
rtc_clk_slow_freq_set(rtc_slow_freq_t slow_freq)116 void rtc_clk_slow_freq_set(rtc_slow_freq_t slow_freq)
117 {
118     REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL, slow_freq);
119 
120     /* Why we need to connect this clock to digital?
121      * Or maybe this clock should be connected to digital when xtal 32k clock is enabled instead?
122      */
123     REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN,
124                   (slow_freq == RTC_SLOW_FREQ_32K_XTAL) ? 1 : 0);
125 
126     /* The clk_8m_d256 will be closed when rtc_state in SLEEP,
127     so if the slow_clk is 8md256, clk_8m must be force power on
128     */
129     REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_FORCE_PU, (slow_freq == RTC_SLOW_FREQ_8MD256) ? 1 : 0);
130     esp_rom_delay_us(DELAY_SLOW_CLK_SWITCH);
131 }
132 
rtc_clk_slow_freq_get(void)133 rtc_slow_freq_t rtc_clk_slow_freq_get(void)
134 {
135     return REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL);
136 }
137 
rtc_clk_slow_freq_get_hz(void)138 uint32_t rtc_clk_slow_freq_get_hz(void)
139 {
140     switch (rtc_clk_slow_freq_get()) {
141     case RTC_SLOW_FREQ_RTC: return RTC_SLOW_CLK_FREQ_150K;
142     case RTC_SLOW_FREQ_32K_XTAL: return RTC_SLOW_CLK_FREQ_32K;
143     case RTC_SLOW_FREQ_8MD256: return RTC_SLOW_CLK_FREQ_8MD256;
144     }
145     return 0;
146 }
147 
rtc_clk_fast_freq_set(rtc_fast_freq_t fast_freq)148 void rtc_clk_fast_freq_set(rtc_fast_freq_t fast_freq)
149 {
150     REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_FAST_CLK_RTC_SEL, fast_freq);
151     esp_rom_delay_us(DELAY_FAST_CLK_SWITCH);
152 }
153 
rtc_clk_fast_freq_get(void)154 rtc_fast_freq_t rtc_clk_fast_freq_get(void)
155 {
156     return REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_FAST_CLK_RTC_SEL);
157 }
158 
rtc_clk_bbpll_disable(void)159 static void rtc_clk_bbpll_disable(void)
160 {
161     SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BB_I2C_FORCE_PD |
162                       RTC_CNTL_BBPLL_FORCE_PD | RTC_CNTL_BBPLL_I2C_FORCE_PD);
163     s_cur_pll_freq = 0;
164 }
165 
rtc_clk_bbpll_enable(void)166 static void rtc_clk_bbpll_enable(void)
167 {
168     CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BB_I2C_FORCE_PD |
169                         RTC_CNTL_BBPLL_FORCE_PD | RTC_CNTL_BBPLL_I2C_FORCE_PD);
170 }
171 
rtc_clk_bbpll_configure(rtc_xtal_freq_t xtal_freq,int pll_freq)172 void rtc_clk_bbpll_configure(rtc_xtal_freq_t xtal_freq, int pll_freq)
173 {
174     uint8_t div_ref;
175     uint8_t div7_0;
176     uint8_t dr1;
177     uint8_t dr3;
178     uint8_t dchgp;
179     uint8_t dcur;
180     uint8_t dbias;
181 
182     CLEAR_PERI_REG_MASK(I2C_MST_ANA_CONF0_REG, I2C_MST_BBPLL_STOP_FORCE_HIGH);
183     SET_PERI_REG_MASK(I2C_MST_ANA_CONF0_REG, I2C_MST_BBPLL_STOP_FORCE_LOW);
184     if (pll_freq == RTC_PLL_FREQ_480M) {
185         /* Set this register to let the digital part know 480M PLL is used */
186         SET_PERI_REG_MASK(SYSTEM_CPU_PER_CONF_REG, SYSTEM_PLL_FREQ_SEL);
187         /* Configure 480M PLL */
188         switch (xtal_freq) {
189         case RTC_XTAL_FREQ_40M:
190             div_ref = 0;
191             div7_0 = 8;
192             dr1 = 0;
193             dr3 = 0;
194             dchgp = 5;
195             dcur = 3;
196             dbias = 2;
197             break;
198         case RTC_XTAL_FREQ_32M:
199             div_ref = 1;
200             div7_0 = 26;
201             dr1 = 1;
202             dr3 = 1;
203             dchgp = 4;
204             dcur = 0;
205             dbias = 2;
206             break;
207         default:
208             div_ref = 0;
209             div7_0 = 8;
210             dr1 = 0;
211             dr3 = 0;
212             dchgp = 5;
213             dcur = 3;
214             dbias = 2;
215             break;
216         }
217         REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_MODE_HF, 0x6B);
218     } else {
219         /* Clear this register to let the digital part know 320M PLL is used */
220         CLEAR_PERI_REG_MASK(SYSTEM_CPU_PER_CONF_REG, SYSTEM_PLL_FREQ_SEL);
221         /* Configure 320M PLL */
222         switch (xtal_freq) {
223         case RTC_XTAL_FREQ_40M:
224             div_ref = 0;
225             div7_0 = 4;
226             dr1 = 0;
227             dr3 = 0;
228             dchgp = 5;
229             dcur = 3;
230             dbias = 2;
231             break;
232         case RTC_XTAL_FREQ_32M:
233             div_ref = 1;
234             div7_0 = 6;
235             dr1 = 0;
236             dr3 = 0;
237             dchgp = 5;
238             dcur = 3;
239             dbias = 2;
240             break;
241         default:
242             div_ref = 0;
243             div7_0 = 4;
244             dr1 = 0;
245             dr3 = 0;
246             dchgp = 5;
247             dcur = 3;
248             dbias = 2;
249             break;
250         }
251         REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_MODE_HF, 0x69);
252     }
253     uint8_t i2c_bbpll_lref  = (dchgp << I2C_BBPLL_OC_DCHGP_LSB) | (div_ref);
254     uint8_t i2c_bbpll_div_7_0 = div7_0;
255     uint8_t i2c_bbpll_dcur = (2 << I2C_BBPLL_OC_DLREF_SEL_LSB ) | (1 << I2C_BBPLL_OC_DHREF_SEL_LSB) | dcur;
256     REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_REF_DIV, i2c_bbpll_lref);
257     REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_DIV_7_0, i2c_bbpll_div_7_0);
258     REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DR1, dr1);
259     REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DR3, dr3);
260     REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_DCUR, i2c_bbpll_dcur);
261     REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_VCO_DBIAS, dbias);
262     REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DHREF_SEL, 2);
263     REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DLREF_SEL, 1);
264 
265     s_cur_pll_freq = pll_freq;
266 }
267 
268 /**
269  * Switch to one of PLL-based frequencies. Current frequency can be XTAL or PLL.
270  * PLL must already be enabled.
271  * @param cpu_freq new CPU frequency
272  */
rtc_clk_cpu_freq_to_pll_mhz(int cpu_freq_mhz)273 static void rtc_clk_cpu_freq_to_pll_mhz(int cpu_freq_mhz)
274 {
275     int per_conf = DPORT_CPUPERIOD_SEL_80;
276     if (cpu_freq_mhz == 80) {
277         /* nothing to do */
278     } else if (cpu_freq_mhz == 160) {
279         per_conf = DPORT_CPUPERIOD_SEL_160;
280     } else {
281         SOC_LOGE(TAG, "invalid frequency");
282         abort();
283     }
284     REG_SET_FIELD(SYSTEM_CPU_PER_CONF_REG, SYSTEM_CPUPERIOD_SEL, per_conf);
285     REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_PRE_DIV_CNT, 0);
286     REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL, DPORT_SOC_CLK_SEL_PLL);
287     rtc_clk_apb_freq_update(80 * MHZ);
288     ets_update_cpu_frequency(cpu_freq_mhz);
289 }
290 
rtc_clk_cpu_freq_mhz_to_config(uint32_t freq_mhz,rtc_cpu_freq_config_t * out_config)291 bool rtc_clk_cpu_freq_mhz_to_config(uint32_t freq_mhz, rtc_cpu_freq_config_t *out_config)
292 {
293     uint32_t source_freq_mhz;
294     rtc_cpu_freq_src_t source;
295     uint32_t divider;
296     uint32_t real_freq_mhz;
297 
298     uint32_t xtal_freq = (uint32_t) rtc_clk_xtal_freq_get();
299     if (freq_mhz <= xtal_freq) {
300         divider = xtal_freq / freq_mhz;
301         real_freq_mhz = (xtal_freq + divider / 2) / divider; /* round */
302         if (real_freq_mhz != freq_mhz) {
303             // no suitable divider
304             return false;
305         }
306 
307         source_freq_mhz = xtal_freq;
308         source = RTC_CPU_FREQ_SRC_XTAL;
309     } else if (freq_mhz == 80) {
310         real_freq_mhz = freq_mhz;
311         source = RTC_CPU_FREQ_SRC_PLL;
312         source_freq_mhz = RTC_PLL_FREQ_480M;
313         divider = 6;
314     } else if (freq_mhz == 160) {
315         real_freq_mhz = freq_mhz;
316         source = RTC_CPU_FREQ_SRC_PLL;
317         source_freq_mhz = RTC_PLL_FREQ_480M;
318         divider = 3;
319     } else {
320         // unsupported frequency
321         return false;
322     }
323     *out_config = (rtc_cpu_freq_config_t) {
324         .source = source,
325         .div = divider,
326         .source_freq_mhz = source_freq_mhz,
327         .freq_mhz = real_freq_mhz
328     };
329     return true;
330 }
331 
rtc_clk_cpu_freq_set_config(const rtc_cpu_freq_config_t * config)332 void rtc_clk_cpu_freq_set_config(const rtc_cpu_freq_config_t *config)
333 {
334     uint32_t soc_clk_sel = REG_GET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL);
335     if (config->source == RTC_CPU_FREQ_SRC_XTAL) {
336         rtc_clk_cpu_freq_to_xtal(config->freq_mhz, config->div);
337         if ((soc_clk_sel == DPORT_SOC_CLK_SEL_PLL) && !rtc_clk_set_bbpll_always_on()) {
338             // We don't turn off the bbpll if some consumers only depends on bbpll
339             rtc_clk_bbpll_disable();
340         }
341     } else if (config->source == RTC_CPU_FREQ_SRC_PLL) {
342         if (soc_clk_sel != DPORT_SOC_CLK_SEL_PLL) {
343             rtc_clk_bbpll_enable();
344             rtc_clk_bbpll_configure(rtc_clk_xtal_freq_get(), config->source_freq_mhz);
345         }
346         rtc_clk_cpu_freq_to_pll_mhz(config->freq_mhz);
347     } else if (config->source == RTC_CPU_FREQ_SRC_8M) {
348         rtc_clk_cpu_freq_to_8m();
349         if ((soc_clk_sel == DPORT_SOC_CLK_SEL_PLL) && !rtc_clk_set_bbpll_always_on()) {
350             // We don't turn off the bbpll if some consumers only depends on bbpll
351             rtc_clk_bbpll_disable();
352         }
353     }
354 }
355 
rtc_clk_cpu_freq_get_config(rtc_cpu_freq_config_t * out_config)356 void rtc_clk_cpu_freq_get_config(rtc_cpu_freq_config_t *out_config)
357 {
358     rtc_cpu_freq_src_t source = 0;
359     uint32_t source_freq_mhz = 0;
360     uint32_t div = 0;
361     uint32_t freq_mhz = 0;
362     uint32_t soc_clk_sel = REG_GET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL);
363     switch (soc_clk_sel) {
364     case DPORT_SOC_CLK_SEL_XTAL: {
365         source = RTC_CPU_FREQ_SRC_XTAL;
366         div = REG_GET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_PRE_DIV_CNT) + 1;
367         source_freq_mhz = (uint32_t) rtc_clk_xtal_freq_get();
368         freq_mhz = source_freq_mhz / div;
369     }
370     break;
371     case DPORT_SOC_CLK_SEL_PLL: {
372         source = RTC_CPU_FREQ_SRC_PLL;
373         uint32_t cpuperiod_sel = REG_GET_FIELD(SYSTEM_CPU_PER_CONF_REG, SYSTEM_CPUPERIOD_SEL);
374         uint32_t pllfreq_sel = REG_GET_FIELD(SYSTEM_CPU_PER_CONF_REG, SYSTEM_PLL_FREQ_SEL);
375         source_freq_mhz = (pllfreq_sel) ? RTC_PLL_FREQ_480M : RTC_PLL_FREQ_320M;
376         if (cpuperiod_sel == DPORT_CPUPERIOD_SEL_80) {
377             div = (source_freq_mhz == RTC_PLL_FREQ_480M) ? 6 : 4;
378             freq_mhz = 80;
379         } else if (cpuperiod_sel == DPORT_CPUPERIOD_SEL_160) {
380             div = (source_freq_mhz == RTC_PLL_FREQ_480M) ? 3 : 2;
381             div = 3;
382             freq_mhz = 160;
383         } else {
384             SOC_LOGE(TAG, "unsupported frequency configuration");
385             abort();
386         }
387         break;
388     }
389     case DPORT_SOC_CLK_SEL_8M:
390         source = RTC_CPU_FREQ_SRC_8M;
391         source_freq_mhz = 8;
392         div = 1;
393         freq_mhz = source_freq_mhz;
394         break;
395     default:
396         SOC_LOGE(TAG, "unsupported frequency configuration");
397         abort();
398     }
399     *out_config = (rtc_cpu_freq_config_t) {
400         .source = source,
401         .source_freq_mhz = source_freq_mhz,
402         .div = div,
403         .freq_mhz = freq_mhz
404     };
405 }
406 
rtc_clk_cpu_freq_set_config_fast(const rtc_cpu_freq_config_t * config)407 void rtc_clk_cpu_freq_set_config_fast(const rtc_cpu_freq_config_t *config)
408 {
409     if (config->source == RTC_CPU_FREQ_SRC_XTAL) {
410         rtc_clk_cpu_freq_to_xtal(config->freq_mhz, config->div);
411     } else if (config->source == RTC_CPU_FREQ_SRC_PLL &&
412                s_cur_pll_freq == config->source_freq_mhz) {
413         rtc_clk_cpu_freq_to_pll_mhz(config->freq_mhz);
414     } else {
415         /* fallback */
416         rtc_clk_cpu_freq_set_config(config);
417     }
418 }
419 
rtc_clk_cpu_freq_set_xtal(void)420 void rtc_clk_cpu_freq_set_xtal(void)
421 {
422     int freq_mhz = (int) rtc_clk_xtal_freq_get();
423 
424     rtc_clk_cpu_freq_to_xtal(freq_mhz, 1);
425     // We don't turn off the bbpll if some consumers only depends on bbpll
426     if (!rtc_clk_set_bbpll_always_on()) {
427         rtc_clk_bbpll_disable();
428     }
429 }
430 
431 /**
432  * Switch to XTAL frequency. Does not disable the PLL.
433  */
rtc_clk_cpu_freq_to_xtal(int freq,int div)434 void rtc_clk_cpu_freq_to_xtal(int freq, int div)
435 {
436     ets_update_cpu_frequency(freq);
437     /* Set divider from XTAL to APB clock. Need to set divider to 1 (reg. value 0) first. */
438     REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_PRE_DIV_CNT, 0);
439     REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_PRE_DIV_CNT, div - 1);
440     /* no need to adjust the REF_TICK */
441     /* switch clock source */
442     REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL, DPORT_SOC_CLK_SEL_XTAL);
443     rtc_clk_apb_freq_update(freq * MHZ);
444 }
445 
rtc_clk_cpu_freq_to_8m(void)446 static void rtc_clk_cpu_freq_to_8m(void)
447 {
448     ets_update_cpu_frequency(8);
449     REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_PRE_DIV_CNT, 0);
450     REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL, DPORT_SOC_CLK_SEL_8M);
451     rtc_clk_apb_freq_update(RTC_FAST_CLK_FREQ_8M);
452 }
453 
rtc_clk_xtal_freq_get(void)454 rtc_xtal_freq_t rtc_clk_xtal_freq_get(void)
455 {
456     uint32_t xtal_freq_reg = READ_PERI_REG(RTC_XTAL_FREQ_REG);
457     if (!clk_val_is_valid(xtal_freq_reg)) {
458         SOC_LOGW(TAG, "invalid RTC_XTAL_FREQ_REG value: 0x%08x", xtal_freq_reg);
459         return RTC_XTAL_FREQ_40M;
460     }
461     return reg_val_to_clk_val(xtal_freq_reg);
462 }
463 
rtc_clk_xtal_freq_update(rtc_xtal_freq_t xtal_freq)464 void rtc_clk_xtal_freq_update(rtc_xtal_freq_t xtal_freq)
465 {
466     WRITE_PERI_REG(RTC_XTAL_FREQ_REG, clk_val_to_reg_val(xtal_freq));
467 }
468 
rtc_clk_apb_freq_update(uint32_t apb_freq)469 void rtc_clk_apb_freq_update(uint32_t apb_freq)
470 {
471     WRITE_PERI_REG(RTC_APB_FREQ_REG, clk_val_to_reg_val(apb_freq >> 12));
472 }
473 
rtc_clk_apb_freq_get(void)474 uint32_t rtc_clk_apb_freq_get(void)
475 {
476     uint32_t freq_hz = reg_val_to_clk_val(READ_PERI_REG(RTC_APB_FREQ_REG)) << 12;
477     // round to the nearest MHz
478     freq_hz += MHZ / 2;
479     uint32_t remainder = freq_hz % MHZ;
480     return freq_hz - remainder;
481 }
482 
rtc_clk_divider_set(uint32_t div)483 void rtc_clk_divider_set(uint32_t div)
484 {
485     CLEAR_PERI_REG_MASK(RTC_CNTL_SLOW_CLK_CONF_REG, RTC_CNTL_ANA_CLK_DIV_VLD);
486     REG_SET_FIELD(RTC_CNTL_SLOW_CLK_CONF_REG, RTC_CNTL_ANA_CLK_DIV, div);
487     SET_PERI_REG_MASK(RTC_CNTL_SLOW_CLK_CONF_REG, RTC_CNTL_ANA_CLK_DIV_VLD);
488 }
489 
rtc_clk_8m_divider_set(uint32_t div)490 void rtc_clk_8m_divider_set(uint32_t div)
491 {
492     CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL_VLD);
493     REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL, div);
494     SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL_VLD);
495 }
496 
rtc_dig_clk8m_enable(void)497 void rtc_dig_clk8m_enable(void)
498 {
499     SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M);
500     esp_rom_delay_us(DELAY_RTC_CLK_SWITCH);
501 }
502 
rtc_dig_clk8m_disable(void)503 void rtc_dig_clk8m_disable(void)
504 {
505     CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M);
506     esp_rom_delay_us(DELAY_RTC_CLK_SWITCH);
507 }
508 
rtc_clk_set_bbpll_always_on(void)509 static bool rtc_clk_set_bbpll_always_on(void)
510 {
511     /* We just keep the rtc bbpll clock on just under the case that
512     user selects the `RTC_CLOCK_BBPLL_POWER_ON_WITH_USB` as well as
513     the USB_SERIAL_JTAG is connected with PC.
514     */
515     bool is_bbpll_on = false;
516 #if CONFIG_RTC_CLOCK_BBPLL_POWER_ON_WITH_USB
517     if (usb_serial_jtag_ll_txfifo_writable() == 1) {
518         is_bbpll_on = true;
519     }
520 #endif
521     return is_bbpll_on;
522 }
523 
524 /* Name used in libphy.a:phy_chip_v7.o
525  * TODO: update the library to use rtc_clk_xtal_freq_get
526  */
527 rtc_xtal_freq_t rtc_get_xtal(void) __attribute__((alias("rtc_clk_xtal_freq_get")));
528