1 /*
2 * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #pragma once
8
9 #include <stdint.h>
10 #include "soc/soc.h"
11 #include "soc/clk_tree_defs.h"
12 #include "soc/rtc.h"
13 #include "soc/rtc_cntl_reg.h"
14 #include "soc/rtc_io_reg.h"
15 #include "soc/dport_reg.h"
16 #include "soc/syscon_reg.h"
17 #include "hal/regi2c_ctrl.h"
18 #include "soc/regi2c_bbpll.h"
19 #include "soc/regi2c_apll.h"
20 #include "hal/assert.h"
21 #include "esp32/rom/rtc.h"
22
23 #ifdef __cplusplus
24 extern "C" {
25 #endif
26
27 #undef MHZ
28 #define MHZ (1000000)
29
30 #define CLK_LL_PLL_80M_FREQ_MHZ (80)
31 #define CLK_LL_PLL_160M_FREQ_MHZ (160)
32 #define CLK_LL_PLL_240M_FREQ_MHZ (240)
33
34 #define CLK_LL_PLL_320M_FREQ_MHZ (320)
35 #define CLK_LL_PLL_480M_FREQ_MHZ (480)
36
37 #define CLK_LL_AHB_MAX_FREQ_MHZ CLK_LL_PLL_80M_FREQ_MHZ
38
39 /* BBPLL configuration parameters at reset */
40 #define CLK_LL_BBPLL_IR_CAL_DELAY_VAL 0x18
41 #define CLK_LL_BBPLL_IR_CAL_EXT_CAP_VAL 0x20
42 #define CLK_LL_BBPLL_OC_ENB_FCAL_VAL 0x9a
43 #define CLK_LL_BBPLL_OC_ENB_VCON_VAL 0x00
44 #define CLK_LL_BBPLL_BBADC_CAL_7_0_VAL 0x00
45
46 /* BBPLL configuration parameters */
47 #define CLK_LL_BBPLL_ENDIV5_VAL_320M 0x43
48 #define CLK_LL_BBPLL_BBADC_DSMP_VAL_320M 0x84
49 #define CLK_LL_BBPLL_ENDIV5_VAL_480M 0xc3
50 #define CLK_LL_BBPLL_BBADC_DSMP_VAL_480M 0x74
51
52 /* APLL configuration parameters */
53 #define CLK_LL_APLL_SDM_STOP_VAL_1 0x09
54 #define CLK_LL_APLL_SDM_STOP_VAL_2_REV0 0x69
55 #define CLK_LL_APLL_SDM_STOP_VAL_2_REV1 0x49
56
57 /* APLL calibration parameters */
58 #define CLK_LL_APLL_CAL_DELAY_1 0x0f
59 #define CLK_LL_APLL_CAL_DELAY_2 0x3f
60 #define CLK_LL_APLL_CAL_DELAY_3 0x1f
61
62 /* XTAL32K configuration parameters for 32kHz crystal */
63 #define CLK_LL_XTAL_32K_DAC_VAL 1
64 #define CLK_LL_XTAL_32K_DRES_VAL 3
65 #define CLK_LL_XTAL_32K_DBIAS_VAL 0
66
67 /* XTAL32K configuration parameters for external oscillator clock */
68 #define CLK_LL_XTAL_32K_EXT_DAC_VAL 2
69 #define CLK_LL_XTAL_32K_EXT_DRES_VAL 3
70 #define CLK_LL_XTAL_32K_EXT_DBIAS_VAL 1
71
72 /* XTAL32K configuration parameters for fast startup with bootstrap */
73 #define CLK_LL_XTAL_32K_BOOTSTRAP_DAC_VAL 3
74 #define CLK_LL_XTAL_32K_BOOTSTRAP_DRES_VAL 3
75 #define CLK_LL_XTAL_32K_BOOTSTRAP_DBIAS_VAL 0
76
77 /**
78 * @brief XTAL32K_CLK enable modes
79 */
80 typedef enum {
81 CLK_LL_XTAL32K_ENABLE_MODE_CRYSTAL, //!< Enable the external 32kHz crystal for XTAL32K_CLK
82 CLK_LL_XTAL32K_ENABLE_MODE_EXTERNAL, //!< Enable the external clock signal for XTAL32K_CLK
83 CLK_LL_XTAL32K_ENABLE_MODE_BOOTSTRAP, //!< Bootstrap the crystal oscillator for faster XTAL32K_CLK start up */
84 } clk_ll_xtal32k_enable_mode_t;
85
86 /**
87 * @brief Power up internal I2C bus
88 */
clk_ll_i2c_pu(void)89 static inline __attribute__((always_inline)) void clk_ll_i2c_pu(void)
90 {
91 CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BIAS_I2C_FORCE_PD);
92 }
93
94 /**
95 * @brief Power down internal I2C bus
96 */
clk_ll_i2c_pd(void)97 static inline __attribute__((always_inline)) void clk_ll_i2c_pd(void)
98 {
99 SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BIAS_I2C_FORCE_PD);
100 }
101
102 /**
103 * @brief Power up BBPLL circuit
104 */
clk_ll_bbpll_enable(void)105 static inline __attribute__((always_inline)) void clk_ll_bbpll_enable(void)
106 {
107 CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG,
108 RTC_CNTL_BB_I2C_FORCE_PD | RTC_CNTL_BBPLL_FORCE_PD |
109 RTC_CNTL_BBPLL_I2C_FORCE_PD);
110 // Reset BBPLL configuration
111 REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_IR_CAL_DELAY, CLK_LL_BBPLL_IR_CAL_DELAY_VAL);
112 REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_IR_CAL_EXT_CAP, CLK_LL_BBPLL_IR_CAL_EXT_CAP_VAL);
113 REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_ENB_FCAL, CLK_LL_BBPLL_OC_ENB_FCAL_VAL);
114 REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_ENB_VCON, CLK_LL_BBPLL_OC_ENB_VCON_VAL);
115 REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_BBADC_CAL_7_0, CLK_LL_BBPLL_BBADC_CAL_7_0_VAL);
116 }
117
118 /**
119 * @brief Power down BBPLL circuit
120 */
clk_ll_bbpll_disable(void)121 static inline __attribute__((always_inline)) void clk_ll_bbpll_disable(void)
122 {
123 SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG,
124 RTC_CNTL_BB_I2C_FORCE_PD | RTC_CNTL_BBPLL_FORCE_PD |
125 RTC_CNTL_BBPLL_I2C_FORCE_PD);
126 }
127
128 /**
129 * @brief Power up APLL circuit
130 */
clk_ll_apll_enable(void)131 static inline __attribute__((always_inline)) void clk_ll_apll_enable(void)
132 {
133 CLEAR_PERI_REG_MASK(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_PLLA_FORCE_PD);
134 SET_PERI_REG_MASK(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_PLLA_FORCE_PU);
135 }
136
137 /**
138 * @brief Power down APLL circuit
139 */
clk_ll_apll_disable(void)140 static inline __attribute__((always_inline)) void clk_ll_apll_disable(void)
141 {
142 SET_PERI_REG_MASK(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_PLLA_FORCE_PD);
143 CLEAR_PERI_REG_MASK(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_PLLA_FORCE_PU);
144 }
145
146 /**
147 * @brief Check whether APLL is under force power down state
148 *
149 * @return True if APLL is under force power down; otherwise false
150 */
clk_ll_apll_is_fpd(void)151 static inline __attribute__((always_inline)) bool clk_ll_apll_is_fpd(void)
152 {
153 return REG_GET_FIELD(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_PLLA_FORCE_PD);
154 }
155
156 /**
157 * @brief Get APLL configuration which can be used to calculate APLL frequency
158 *
159 * @param[out] o_div Frequency divider, 0..31
160 * @param[out] sdm0 Frequency adjustment parameter, 0..255
161 * @param[out] sdm1 Frequency adjustment parameter, 0..255
162 * @param[out] sdm2 Frequency adjustment parameter, 0..63
163 */
clk_ll_apll_get_config(uint32_t * o_div,uint32_t * sdm0,uint32_t * sdm1,uint32_t * sdm2)164 static inline __attribute__((always_inline)) void clk_ll_apll_get_config(uint32_t *o_div, uint32_t *sdm0, uint32_t *sdm1, uint32_t *sdm2)
165 {
166 *o_div = REGI2C_READ_MASK(I2C_APLL, I2C_APLL_OR_OUTPUT_DIV);
167 *sdm0 = REGI2C_READ_MASK(I2C_APLL, I2C_APLL_DSDM0);
168 *sdm1 = REGI2C_READ_MASK(I2C_APLL, I2C_APLL_DSDM1);
169 *sdm2 = REGI2C_READ_MASK(I2C_APLL, I2C_APLL_DSDM2);
170 }
171
172 /**
173 * @brief Set APLL configuration
174 *
175 * @param is_rev0 True if chip version is rev0
176 * @param o_div Frequency divider, 0..31
177 * @param sdm0 Frequency adjustment parameter, 0..255
178 * @param sdm1 Frequency adjustment parameter, 0..255
179 * @param sdm2 Frequency adjustment parameter, 0..63
180 */
clk_ll_apll_set_config(bool is_rev0,uint32_t o_div,uint32_t sdm0,uint32_t sdm1,uint32_t sdm2)181 static inline __attribute__((always_inline)) void clk_ll_apll_set_config(bool is_rev0, uint32_t o_div, uint32_t sdm0, uint32_t sdm1, uint32_t sdm2)
182 {
183 uint8_t sdm_stop_val_2 = CLK_LL_APLL_SDM_STOP_VAL_2_REV1;
184 if (is_rev0) {
185 sdm0 = 0;
186 sdm1 = 0;
187 sdm_stop_val_2 = CLK_LL_APLL_SDM_STOP_VAL_2_REV0;
188 }
189 REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_DSDM2, sdm2);
190 REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_DSDM0, sdm0);
191 REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_DSDM1, sdm1);
192 REGI2C_WRITE(I2C_APLL, I2C_APLL_SDM_STOP, CLK_LL_APLL_SDM_STOP_VAL_1);
193 REGI2C_WRITE(I2C_APLL, I2C_APLL_SDM_STOP, sdm_stop_val_2);
194 REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_OR_OUTPUT_DIV, o_div);
195 }
196
197 /**
198 * @brief Set APLL calibration parameters
199 */
clk_ll_apll_set_calibration(void)200 static inline __attribute__((always_inline)) void clk_ll_apll_set_calibration(void)
201 {
202 REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, CLK_LL_APLL_CAL_DELAY_1);
203 REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, CLK_LL_APLL_CAL_DELAY_2);
204 REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, CLK_LL_APLL_CAL_DELAY_3);
205 }
206
207 /**
208 * @brief Check whether APLL calibration is done
209 *
210 * @return True if calibration is done; otherwise false
211 */
clk_ll_apll_calibration_is_done(void)212 static inline __attribute__((always_inline)) bool clk_ll_apll_calibration_is_done(void)
213 {
214 return REGI2C_READ_MASK(I2C_APLL, I2C_APLL_OR_CAL_END);
215 }
216
217 /**
218 * @brief Enable the 32kHz crystal oscillator
219 *
220 * @param mode Used to determine the xtal32k configuration parameters
221 */
clk_ll_xtal32k_enable(clk_ll_xtal32k_enable_mode_t mode)222 static inline __attribute__((always_inline)) void clk_ll_xtal32k_enable(clk_ll_xtal32k_enable_mode_t mode)
223 {
224 // Configure xtal32k
225 // Default mode as CLK_LL_XTAL32K_ENABLE_MODE_CRYSTAL
226 uint32_t dac = CLK_LL_XTAL_32K_DAC_VAL; // current
227 uint32_t dres = CLK_LL_XTAL_32K_DRES_VAL; // resistance
228 uint32_t dbias = CLK_LL_XTAL_32K_DBIAS_VAL; // dbias voltage
229 if (mode == CLK_LL_XTAL32K_ENABLE_MODE_EXTERNAL) {
230 dac = CLK_LL_XTAL_32K_EXT_DAC_VAL;
231 dres = CLK_LL_XTAL_32K_EXT_DRES_VAL;
232 dbias = CLK_LL_XTAL_32K_EXT_DBIAS_VAL;
233 } else if (mode == CLK_LL_XTAL32K_ENABLE_MODE_BOOTSTRAP) {
234 dac = CLK_LL_XTAL_32K_BOOTSTRAP_DAC_VAL;
235 dres = CLK_LL_XTAL_32K_BOOTSTRAP_DRES_VAL;
236 dbias = CLK_LL_XTAL_32K_BOOTSTRAP_DBIAS_VAL;
237 }
238 REG_SET_FIELD(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_DAC_XTAL_32K, dac);
239 REG_SET_FIELD(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_DRES_XTAL_32K, dres);
240 REG_SET_FIELD(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_DBIAS_XTAL_32K, dbias);
241 // Enable xtal32k xpd status
242 SET_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_XPD_XTAL_32K_M);
243 }
244
245 /**
246 * @brief Disable the 32kHz crystal oscillator
247 */
clk_ll_xtal32k_disable(void)248 static inline __attribute__((always_inline)) void clk_ll_xtal32k_disable(void)
249 {
250 // Disable xtal32k xpd status
251 CLEAR_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_XPD_XTAL_32K_M);
252 }
253
254 /**
255 * @brief Get the state of the 32kHz crystal clock
256 *
257 * @return True if the 32kHz XTAL is enabled
258 */
clk_ll_xtal32k_is_enabled(void)259 static inline __attribute__((always_inline)) bool clk_ll_xtal32k_is_enabled(void)
260 {
261 return GET_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_XPD_XTAL_32K);
262 }
263
264 /**
265 * @brief Enable the internal oscillator output for RC_FAST_CLK
266 */
clk_ll_rc_fast_enable(void)267 static inline __attribute__((always_inline)) void clk_ll_rc_fast_enable(void)
268 {
269 CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M);
270 REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT, RTC_CK8M_ENABLE_WAIT_DEFAULT);
271 }
272
273 /**
274 * @brief Disable the internal oscillator output for RC_FAST_CLK
275 */
clk_ll_rc_fast_disable(void)276 static inline __attribute__((always_inline)) void clk_ll_rc_fast_disable(void)
277 {
278 SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M);
279 REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT, RTC_CNTL_CK8M_WAIT_DEFAULT);
280 }
281
282 /**
283 * @brief Get the state of the internal oscillator for RC_FAST_CLK
284 *
285 * @return True if the oscillator is enabled
286 */
clk_ll_rc_fast_is_enabled(void)287 static inline __attribute__((always_inline)) bool clk_ll_rc_fast_is_enabled(void)
288 {
289 return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M) == 0;
290 }
291
292 /**
293 * @brief Enable the output from the internal oscillator to be passed into a configurable divider,
294 * which by default divides the input clock frequency by 256. i.e. RC_FAST_D256_CLK = RC_FAST_CLK / 256
295 *
296 * Divider values other than 256 may be configured, but this facility is not currently needed,
297 * so is not exposed in the code.
298 * The output of the divider, RC_FAST_D256_CLK, is referred as 8md256 or simply d256 in reg. descriptions.
299 */
clk_ll_rc_fast_d256_enable(void)300 static inline __attribute__((always_inline)) void clk_ll_rc_fast_d256_enable(void)
301 {
302 CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV);
303 }
304
305 /**
306 * @brief Disable the output from the internal oscillator to be passed into a configurable divider.
307 * i.e. RC_FAST_D256_CLK = RC_FAST_CLK / 256
308 *
309 * Disabling this divider could reduce power consumption.
310 */
clk_ll_rc_fast_d256_disable(void)311 static inline __attribute__((always_inline)) void clk_ll_rc_fast_d256_disable(void)
312 {
313 SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV);
314 }
315
316 /**
317 * @brief Get the state of the divider which is applied to the output from the internal oscillator (RC_FAST_CLK)
318 *
319 * @return True if the divided output is enabled
320 */
clk_ll_rc_fast_d256_is_enabled(void)321 static inline __attribute__((always_inline)) bool clk_ll_rc_fast_d256_is_enabled(void)
322 {
323 return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV) == 0;
324 }
325
326 /**
327 * @brief Enable the digital RC_FAST_CLK, which is used to support peripherals.
328 */
clk_ll_rc_fast_digi_enable(void)329 static inline __attribute__((always_inline)) void clk_ll_rc_fast_digi_enable(void)
330 {
331 SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M);
332 }
333
334 /**
335 * @brief Disable the digital RC_FAST_CLK, which is used to support peripherals.
336 */
clk_ll_rc_fast_digi_disable(void)337 static inline __attribute__((always_inline)) void clk_ll_rc_fast_digi_disable(void)
338 {
339 CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M);
340 }
341
342 /**
343 * @brief Get the state of the digital RC_FAST_CLK
344 *
345 * @return True if the digital RC_FAST_CLK is enabled
346 */
clk_ll_rc_fast_digi_is_enabled(void)347 static inline __attribute__((always_inline)) bool clk_ll_rc_fast_digi_is_enabled(void)
348 {
349 return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M);
350 }
351
352 /**
353 * @brief Enable the digital RC_FAST_D256_CLK, which is used to support peripherals.
354 */
clk_ll_rc_fast_d256_digi_enable(void)355 static inline __attribute__((always_inline)) void clk_ll_rc_fast_d256_digi_enable(void)
356 {
357 SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_D256_EN_M);
358 }
359
360 /**
361 * @brief Disable the digital RC_FAST_D256_CLK, which is used to support peripherals.
362 */
clk_ll_rc_fast_d256_digi_disable(void)363 static inline __attribute__((always_inline)) void clk_ll_rc_fast_d256_digi_disable(void)
364 {
365 CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_D256_EN_M);
366 }
367
368 /**
369 * @brief Enable the digital XTAL32K_CLK, which is used to support peripherals.
370 */
clk_ll_xtal32k_digi_enable(void)371 static inline __attribute__((always_inline)) void clk_ll_xtal32k_digi_enable(void)
372 {
373 SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN_M);
374 }
375
376 /**
377 * @brief Disable the digital XTAL32K_CLK, which is used to support peripherals.
378 */
clk_ll_xtal32k_digi_disable(void)379 static inline __attribute__((always_inline)) void clk_ll_xtal32k_digi_disable(void)
380 {
381 CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN_M);
382 }
383
384 /**
385 * @brief Get the state of the digital XTAL32K_CLK
386 *
387 * @return True if the digital XTAL32K_CLK is enabled
388 */
clk_ll_xtal32k_digi_is_enabled(void)389 static inline __attribute__((always_inline)) bool clk_ll_xtal32k_digi_is_enabled(void)
390 {
391 return REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN);
392 }
393
394 /**
395 * @brief Get PLL_CLK frequency
396 *
397 * @return PLL clock frequency, in MHz. Returns 0 if register field value is invalid.
398 */
clk_ll_bbpll_get_freq_mhz(void)399 static inline __attribute__((always_inline)) uint32_t clk_ll_bbpll_get_freq_mhz(void)
400 {
401 // ESP32 BBPLL frequency is determined by the cpu freq sel
402 uint32_t cpu_freq_sel = DPORT_REG_GET_FIELD(DPORT_CPU_PER_CONF_REG, DPORT_CPUPERIOD_SEL);
403 switch (cpu_freq_sel) {
404 case 0:
405 case 1:
406 return CLK_LL_PLL_320M_FREQ_MHZ;
407 case 2:
408 return CLK_LL_PLL_480M_FREQ_MHZ;
409 default:
410 // Invalid CPUPERIOD_SEL value
411 return 0;
412 }
413 }
414
415 /**
416 * @brief Set BBPLL frequency from XTAL source (digital part)
417 *
418 * @param pll_freq_mhz PLL frequency, in MHz
419 */
clk_ll_bbpll_set_freq_mhz(uint32_t pll_freq_mhz)420 static inline __attribute__((always_inline)) void clk_ll_bbpll_set_freq_mhz(uint32_t pll_freq_mhz)
421 {
422 (void)pll_freq_mhz;
423 // No such operation on ESP32
424 }
425
426 /**
427 * @brief Set BBPLL frequency from XTAL source (Analog part)
428 *
429 * @param pll_freq_mhz PLL frequency, in MHz
430 * @param xtal_freq_mhz XTAL frequency, in MHz
431 */
clk_ll_bbpll_set_config(uint32_t pll_freq_mhz,uint32_t xtal_freq_mhz)432 static inline __attribute__((always_inline)) void clk_ll_bbpll_set_config(uint32_t pll_freq_mhz, uint32_t xtal_freq_mhz)
433 {
434 uint8_t div_ref;
435 uint8_t div7_0;
436 uint8_t div10_8;
437 uint8_t lref;
438 uint8_t dcur;
439 uint8_t bw;
440
441 if (pll_freq_mhz == CLK_LL_PLL_320M_FREQ_MHZ) {
442 /* Configure 320M PLL */
443 switch (xtal_freq_mhz) {
444 case RTC_XTAL_FREQ_40M:
445 div_ref = 0;
446 div7_0 = 32;
447 div10_8 = 0;
448 lref = 0;
449 dcur = 6;
450 bw = 3;
451 break;
452 case RTC_XTAL_FREQ_26M:
453 div_ref = 12;
454 div7_0 = 224;
455 div10_8 = 4;
456 lref = 1;
457 dcur = 0;
458 bw = 1;
459 break;
460 case RTC_XTAL_FREQ_24M:
461 div_ref = 11;
462 div7_0 = 224;
463 div10_8 = 4;
464 lref = 1;
465 dcur = 0;
466 bw = 1;
467 break;
468 default:
469 div_ref = 12;
470 div7_0 = 224;
471 div10_8 = 4;
472 lref = 0;
473 dcur = 0;
474 bw = 0;
475 break;
476 }
477 REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_ENDIV5, CLK_LL_BBPLL_ENDIV5_VAL_320M);
478 REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_BBADC_DSMP, CLK_LL_BBPLL_BBADC_DSMP_VAL_320M);
479 } else {
480 /* Configure 480M PLL */
481 switch (xtal_freq_mhz) {
482 case RTC_XTAL_FREQ_40M:
483 div_ref = 0;
484 div7_0 = 28;
485 div10_8 = 0;
486 lref = 0;
487 dcur = 6;
488 bw = 3;
489 break;
490 case RTC_XTAL_FREQ_26M:
491 div_ref = 12;
492 div7_0 = 144;
493 div10_8 = 4;
494 lref = 1;
495 dcur = 0;
496 bw = 1;
497 break;
498 case RTC_XTAL_FREQ_24M:
499 div_ref = 11;
500 div7_0 = 144;
501 div10_8 = 4;
502 lref = 1;
503 dcur = 0;
504 bw = 1;
505 break;
506 default:
507 div_ref = 12;
508 div7_0 = 224;
509 div10_8 = 4;
510 lref = 0;
511 dcur = 0;
512 bw = 0;
513 break;
514 }
515 REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_ENDIV5, CLK_LL_BBPLL_ENDIV5_VAL_480M);
516 REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_BBADC_DSMP, CLK_LL_BBPLL_BBADC_DSMP_VAL_480M);
517 }
518
519 uint8_t i2c_bbpll_lref = (lref << 7) | (div10_8 << 4) | (div_ref);
520 uint8_t i2c_bbpll_div_7_0 = div7_0;
521 uint8_t i2c_bbpll_dcur = (bw << 6) | dcur;
522 REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_LREF, i2c_bbpll_lref);
523 REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_DIV_7_0, i2c_bbpll_div_7_0);
524 REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_DCUR, i2c_bbpll_dcur);
525 }
526
527 /**
528 * @brief Select the clock source for CPU_CLK
529 *
530 * @param in_sel One of the clock sources in soc_cpu_clk_src_t
531 */
clk_ll_cpu_set_src(soc_cpu_clk_src_t in_sel)532 static inline __attribute__((always_inline)) void clk_ll_cpu_set_src(soc_cpu_clk_src_t in_sel)
533 {
534 switch (in_sel) {
535 case SOC_CPU_CLK_SRC_XTAL:
536 REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_SOC_CLK_SEL, 0);
537 break;
538 case SOC_CPU_CLK_SRC_PLL:
539 REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_SOC_CLK_SEL, 1);
540 break;
541 case SOC_CPU_CLK_SRC_RC_FAST:
542 REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_SOC_CLK_SEL, 2);
543 break;
544 case SOC_CPU_CLK_SRC_APLL:
545 REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_SOC_CLK_SEL, 3);
546 break;
547 default:
548 // Unsupported CPU_CLK mux input sel
549 abort();
550 }
551 }
552
553 /**
554 * @brief Get the clock source for CPU_CLK
555 *
556 * @return Currently selected clock source (one of soc_cpu_clk_src_t values)
557 */
clk_ll_cpu_get_src(void)558 static inline __attribute__((always_inline)) soc_cpu_clk_src_t clk_ll_cpu_get_src(void)
559 {
560 uint32_t clk_sel = REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_SOC_CLK_SEL);
561 switch (clk_sel) {
562 case 0:
563 return SOC_CPU_CLK_SRC_XTAL;
564 case 1:
565 return SOC_CPU_CLK_SRC_PLL;
566 case 2:
567 return SOC_CPU_CLK_SRC_RC_FAST;
568 case 3:
569 return SOC_CPU_CLK_SRC_APLL;
570 default:
571 return SOC_CPU_CLK_SRC_INVALID;
572 }
573 }
574
575 /**
576 * @brief Set CPU frequency from PLL clock
577 *
578 * @param cpu_mhz CPU frequency value, in MHz
579 */
clk_ll_cpu_set_freq_mhz_from_pll(uint32_t cpu_mhz)580 static inline __attribute__((always_inline)) void clk_ll_cpu_set_freq_mhz_from_pll(uint32_t cpu_mhz)
581 {
582 switch (cpu_mhz) {
583 case CLK_LL_PLL_80M_FREQ_MHZ:
584 DPORT_REG_WRITE(DPORT_CPU_PER_CONF_REG, 0);
585 break;
586 case CLK_LL_PLL_160M_FREQ_MHZ:
587 DPORT_REG_WRITE(DPORT_CPU_PER_CONF_REG, 1);
588 break;
589 case CLK_LL_PLL_240M_FREQ_MHZ:
590 DPORT_REG_WRITE(DPORT_CPU_PER_CONF_REG, 2);
591 break;
592 default:
593 // Unsupported CPU_CLK freq from PLL
594 abort();
595 }
596 }
597
598 /**
599 * @brief Get CPU_CLK frequency from PLL_CLK source
600 *
601 * @return CPU clock frequency, in MHz. Returns 0 if register field value is invalid.
602 */
clk_ll_cpu_get_freq_mhz_from_pll(void)603 static inline __attribute__((always_inline)) uint32_t clk_ll_cpu_get_freq_mhz_from_pll(void)
604 {
605 uint32_t cpu_freq_sel = DPORT_REG_GET_FIELD(DPORT_CPU_PER_CONF_REG, DPORT_CPUPERIOD_SEL);
606 switch (cpu_freq_sel) {
607 case 0:
608 return CLK_LL_PLL_80M_FREQ_MHZ;
609 case 1:
610 return CLK_LL_PLL_160M_FREQ_MHZ;
611 case 2:
612 return CLK_LL_PLL_240M_FREQ_MHZ;
613 default:
614 // Invalid CPUPERIOD_SEL value
615 return 0;
616 }
617 }
618
619 /**
620 * @brief Set CPU_CLK's XTAL/FAST_RC clock source path divider
621 *
622 * @param divider Divider. Usually this divider is set to 1 in bootloader stage. PRE_DIV_CNT = divider - 1.
623 */
clk_ll_cpu_set_divider(uint32_t divider)624 static inline __attribute__((always_inline)) void clk_ll_cpu_set_divider(uint32_t divider)
625 {
626 HAL_ASSERT(divider > 0);
627 REG_SET_FIELD(SYSCON_SYSCLK_CONF_REG, SYSCON_PRE_DIV_CNT, divider - 1);
628 }
629
630 /**
631 * @brief Get CPU_CLK's XTAL/FAST_RC clock source path divider
632 *
633 * @return Divider. Divider = (PRE_DIV_CNT + 1).
634 */
clk_ll_cpu_get_divider(void)635 static inline __attribute__((always_inline)) uint32_t clk_ll_cpu_get_divider(void)
636 {
637 return REG_GET_FIELD(SYSCON_SYSCLK_CONF_REG, SYSCON_PRE_DIV_CNT) + 1;
638 }
639
640 /**
641 * @brief Get CPU_CLK's APLL clock source path divider
642 *
643 * @return Divider. Returns 0 means invalid.
644 */
clk_ll_cpu_get_divider_from_apll(void)645 static inline __attribute__((always_inline)) uint32_t clk_ll_cpu_get_divider_from_apll(void)
646 {
647 // APLL path divider choice shares the same register with CPUPERIOD_SEL
648 uint32_t cpu_freq_sel = DPORT_REG_GET_FIELD(DPORT_CPU_PER_CONF_REG, DPORT_CPUPERIOD_SEL);
649 switch (cpu_freq_sel) {
650 case 0:
651 return 4;
652 case 1:
653 return 2;
654 default:
655 // Invalid CPUPERIOD_SEL value if APLL is the clock source
656 return 0;
657 }
658 }
659
660 /**
661 * @brief Set REF_TICK divider to make REF_TICK frequency at 1MHz
662 *
663 * @param cpu_clk_src Selected CPU clock source (one of soc_cpu_clk_src_t values)
664 * @param cpu_freq_mhz CPU frequency value, in MHz
665 *
666 * Divider = APB_CLK freq in Hz / 1MHz. Value in register = divider - 1.
667 */
clk_ll_ref_tick_set_divider(soc_cpu_clk_src_t cpu_clk_src,uint32_t cpu_freq_mhz)668 static inline __attribute__((always_inline)) void clk_ll_ref_tick_set_divider(soc_cpu_clk_src_t cpu_clk_src, uint32_t cpu_freq_mhz)
669 {
670 uint32_t apb_freq_mhz;
671 switch (cpu_clk_src) {
672 case SOC_CPU_CLK_SRC_XTAL:
673 apb_freq_mhz = cpu_freq_mhz;
674 REG_WRITE(SYSCON_XTAL_TICK_CONF_REG, apb_freq_mhz - 1);
675 break;
676 case SOC_CPU_CLK_SRC_PLL:
677 apb_freq_mhz = 80;
678 REG_WRITE(SYSCON_PLL_TICK_CONF_REG, apb_freq_mhz - 1);
679 break;
680 case SOC_CPU_CLK_SRC_RC_FAST:
681 apb_freq_mhz = cpu_freq_mhz;
682 REG_WRITE(SYSCON_CK8M_TICK_CONF_REG, apb_freq_mhz - 1);
683 break;
684 case SOC_CPU_CLK_SRC_APLL:
685 apb_freq_mhz = cpu_freq_mhz >> 1;
686 REG_WRITE(SYSCON_APLL_TICK_CONF_REG, apb_freq_mhz - 1);
687 break;
688 default:
689 // Unsupported CPU_CLK mux input sel
690 abort();
691 }
692 }
693
694 /**
695 * @brief Select the clock source for RTC_SLOW_CLK
696 *
697 * @param in_sel One of the clock sources in soc_rtc_slow_clk_src_t
698 */
clk_ll_rtc_slow_set_src(soc_rtc_slow_clk_src_t in_sel)699 static inline __attribute__((always_inline)) void clk_ll_rtc_slow_set_src(soc_rtc_slow_clk_src_t in_sel)
700 {
701 switch (in_sel) {
702 case SOC_RTC_SLOW_CLK_SRC_RC_SLOW:
703 REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL, 0);
704 break;
705 case SOC_RTC_SLOW_CLK_SRC_XTAL32K:
706 REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL, 1);
707 break;
708 case SOC_RTC_SLOW_CLK_SRC_RC_FAST_D256:
709 REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL, 2);
710 break;
711 default:
712 // Unsupported RTC_SLOW_CLK mux input sel
713 abort();
714 }
715 }
716
717 /**
718 * @brief Get the clock source for RTC_SLOW_CLK
719 *
720 * @return Currently selected clock source (one of soc_rtc_slow_clk_src_t values)
721 */
clk_ll_rtc_slow_get_src(void)722 static inline __attribute__((always_inline)) soc_rtc_slow_clk_src_t clk_ll_rtc_slow_get_src(void)
723 {
724 uint32_t clk_sel = REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL);
725 switch (clk_sel) {
726 case 0:
727 return SOC_RTC_SLOW_CLK_SRC_RC_SLOW;
728 case 1:
729 return SOC_RTC_SLOW_CLK_SRC_XTAL32K;
730 case 2:
731 return SOC_RTC_SLOW_CLK_SRC_RC_FAST_D256;
732 default:
733 // Invalid ANA_CLK_RTC_SEL value
734 return SOC_RTC_SLOW_CLK_SRC_INVALID;
735 }
736 }
737
738 /**
739 * @brief Select the clock source for RTC_FAST_CLK
740 *
741 * @param in_sel One of the clock sources in soc_rtc_fast_clk_src_t
742 */
clk_ll_rtc_fast_set_src(soc_rtc_fast_clk_src_t in_sel)743 static inline __attribute__((always_inline)) void clk_ll_rtc_fast_set_src(soc_rtc_fast_clk_src_t in_sel)
744 {
745 switch (in_sel) {
746 case SOC_RTC_FAST_CLK_SRC_XTAL_D4:
747 REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_FAST_CLK_RTC_SEL, 0);
748 break;
749 case SOC_RTC_FAST_CLK_SRC_RC_FAST:
750 REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_FAST_CLK_RTC_SEL, 1);
751 break;
752 default:
753 // Unsupported RTC_FAST_CLK mux input sel
754 abort();
755 }
756 }
757
758 /**
759 * @brief Get the clock source for RTC_FAST_CLK
760 *
761 * @return Currently selected clock source (one of soc_rtc_fast_clk_src_t values)
762 */
clk_ll_rtc_fast_get_src(void)763 static inline __attribute__((always_inline)) soc_rtc_fast_clk_src_t clk_ll_rtc_fast_get_src(void)
764 {
765 uint32_t clk_sel = REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_FAST_CLK_RTC_SEL);
766 switch (clk_sel) {
767 case 0:
768 return SOC_RTC_FAST_CLK_SRC_XTAL_D4;
769 case 1:
770 return SOC_RTC_FAST_CLK_SRC_RC_FAST;
771 default:
772 return SOC_RTC_FAST_CLK_SRC_INVALID;
773 }
774 }
775
776 /**
777 * @brief Set RC_FAST_CLK divider. The output from the divider is passed into rtc_fast_clk MUX.
778 *
779 * @param divider Divider of RC_FAST_CLK. Usually this divider is set to 1 (reg. value is 0) in bootloader stage.
780 */
clk_ll_rc_fast_set_divider(uint32_t divider)781 static inline void clk_ll_rc_fast_set_divider(uint32_t divider)
782 {
783 HAL_ASSERT(divider > 0);
784 REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL, divider - 1);
785 }
786
787 /**
788 * @brief Get RC_FAST_CLK divider
789 *
790 * @return Divider. Divider = (CK8M_DIV_SEL + 1).
791 */
clk_ll_rc_fast_get_divider(void)792 static inline __attribute__((always_inline)) uint32_t clk_ll_rc_fast_get_divider(void)
793 {
794 return REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL) + 1;
795 }
796
797 /************************* RTC STORAGE REGISTER STORE/LOAD **************************/
798 /**
799 * @brief Store XTAL_CLK frequency in RTC storage register
800 *
801 * Value of RTC_XTAL_FREQ_REG is stored as two copies in lower and upper 16-bit
802 * halves. These are the routines to work with that representation.
803 *
804 * @param xtal_freq_mhz XTAL frequency, in MHz. The frequency must necessarily be even,
805 * otherwise there will be a conflict with the low bit, which is used to disable logs
806 * in the ROM code.
807 */
clk_ll_xtal_store_freq_mhz(uint32_t xtal_freq_mhz)808 static inline __attribute__((always_inline)) void clk_ll_xtal_store_freq_mhz(uint32_t xtal_freq_mhz)
809 {
810 // Read the status of whether disabling logging from ROM code
811 uint32_t reg = READ_PERI_REG(RTC_XTAL_FREQ_REG) & RTC_DISABLE_ROM_LOG;
812 // If so, need to write back this setting
813 if (reg == RTC_DISABLE_ROM_LOG) {
814 xtal_freq_mhz |= 1;
815 }
816 WRITE_PERI_REG(RTC_XTAL_FREQ_REG, (xtal_freq_mhz & UINT16_MAX) | ((xtal_freq_mhz & UINT16_MAX) << 16));
817 }
818
819 /**
820 * @brief Load XTAL_CLK frequency from RTC storage register
821 *
822 * Value of RTC_XTAL_FREQ_REG is stored as two copies in lower and upper 16-bit
823 * halves. These are the routines to work with that representation.
824 *
825 * @return XTAL frequency, in MHz. Returns 0 if format in reg is invalid.
826 */
clk_ll_xtal_load_freq_mhz(void)827 static inline __attribute__((always_inline)) uint32_t clk_ll_xtal_load_freq_mhz(void)
828 {
829 // Read from RTC storage register
830 uint32_t xtal_freq_reg = READ_PERI_REG(RTC_XTAL_FREQ_REG);
831 if ((xtal_freq_reg & 0xFFFF) == ((xtal_freq_reg >> 16) & 0xFFFF) &&
832 xtal_freq_reg != 0 && xtal_freq_reg != UINT32_MAX) {
833 return xtal_freq_reg & ~RTC_DISABLE_ROM_LOG & UINT16_MAX;
834 }
835 // If the format in reg is invalid or haven't written XTAL value into RTC_XTAL_FREQ_REG
836 return 0;
837 }
838
839 /**
840 * @brief Store APB_CLK frequency in RTC storage register
841 *
842 * Value of RTC_APB_FREQ_REG is stored as two copies in lower and upper 16-bit
843 * halves. These are the routines to work with that representation.
844 *
845 * @param apb_freq_hz APB frequency, in Hz
846 */
clk_ll_apb_store_freq_hz(uint32_t apb_freq_hz)847 static inline __attribute__((always_inline)) void clk_ll_apb_store_freq_hz(uint32_t apb_freq_hz)
848 {
849 uint32_t val = apb_freq_hz >> 12;
850 WRITE_PERI_REG(RTC_APB_FREQ_REG, (val & UINT16_MAX) | ((val & UINT16_MAX) << 16));
851 }
852
853 /**
854 * @brief Load APB_CLK frequency from RTC storage register
855 *
856 * Value of RTC_APB_FREQ_REG is stored as two copies in lower and upper 16-bit
857 * halves. These are the routines to work with that representation.
858 *
859 * @return The stored APB frequency, in Hz
860 */
clk_ll_apb_load_freq_hz(void)861 static inline __attribute__((always_inline)) uint32_t clk_ll_apb_load_freq_hz(void)
862 {
863 // Read from RTC storage register
864 uint32_t apb_freq_hz = (READ_PERI_REG(RTC_APB_FREQ_REG) & UINT16_MAX) << 12;
865 // Round to the nearest MHz
866 apb_freq_hz += MHZ / 2;
867 uint32_t remainder = apb_freq_hz % MHZ;
868 return apb_freq_hz - remainder;
869 }
870
871 /**
872 * @brief Store RTC_SLOW_CLK calibration value in RTC storage register
873 *
874 * Value of RTC_SLOW_CLK_CAL_REG has to be in the same format as returned by rtc_clk_cal (microseconds,
875 * in Q13.19 fixed-point format).
876 *
877 * @param cal_value The calibration value of slow clock period in microseconds, in Q13.19 fixed point format
878 */
clk_ll_rtc_slow_store_cal(uint32_t cal_value)879 static inline __attribute__((always_inline)) void clk_ll_rtc_slow_store_cal(uint32_t cal_value)
880 {
881 REG_WRITE(RTC_SLOW_CLK_CAL_REG, cal_value);
882 }
883
884 /**
885 * @brief Load the calibration value of RTC_SLOW_CLK frequency from RTC storage register
886 *
887 * This value gets updated (i.e. rtc slow clock gets calibrated) every time RTC_SLOW_CLK source switches
888 *
889 * @return The calibration value of slow clock period in microseconds, in Q13.19 fixed point format
890 */
clk_ll_rtc_slow_load_cal(void)891 static inline __attribute__((always_inline)) uint32_t clk_ll_rtc_slow_load_cal(void)
892 {
893 return REG_READ(RTC_SLOW_CLK_CAL_REG);
894 }
895
896 #ifdef __cplusplus
897 }
898 #endif
899