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