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