1 /*
2  * SPDX-FileCopyrightText: 2022-2023 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/pcr_struct.h"
14 #include "soc/lp_clkrst_struct.h"
15 #include "soc/pmu_reg.h"
16 #include "hal/regi2c_ctrl.h"
17 #include "soc/regi2c_bbpll.h"
18 #include "soc/regi2c_pmu.h"
19 #include "hal/assert.h"
20 #include "hal/log.h"
21 #include "esp32h2/rom/rtc.h"
22 #include "hal/misc.h"
23 
24 #ifdef __cplusplus
25 extern "C" {
26 #endif
27 
28 #define MHZ                 (1000000)
29 
30 #define CLK_LL_PLL_8M_FREQ_MHZ    (8)
31 #define CLK_LL_PLL_48M_FREQ_MHZ   (48)
32 #define CLK_LL_PLL_64M_FREQ_MHZ   (64)
33 #define CLK_LL_PLL_96M_FREQ_MHZ   (96)
34 
35 #define CLK_LL_XTAL32K_CONFIG_DEFAULT() { \
36     .dac = 3, \
37     .dres = 3, \
38     .dgm = 3, \
39     .dbuf = 1, \
40 }
41 
42 /*
43 Set the frequency division factor of ref_tick
44 The FOSC of rtc calibration uses the 32 frequency division clock for ECO2,
45 So the frequency division factor of ref_tick must be greater than or equal to 32
46 */
47 #define REG_FOSC_TICK_NUM  255
48 
49 /**
50  * @brief XTAL32K_CLK enable modes
51  */
52 typedef enum {
53     CLK_LL_XTAL32K_ENABLE_MODE_CRYSTAL,       //!< Enable the external 32kHz crystal for XTAL32K_CLK
54     CLK_LL_XTAL32K_ENABLE_MODE_EXTERNAL,      //!< Enable the external clock signal for XTAL32K_CLK
55     CLK_LL_XTAL32K_ENABLE_MODE_BOOTSTRAP,     //!< Bootstrap the crystal oscillator for faster XTAL32K_CLK start up */
56 } clk_ll_xtal32k_enable_mode_t;
57 
58 /**
59  * @brief XTAL32K_CLK configuration structure
60  */
61 typedef struct {
62     uint32_t dac : 6;
63     uint32_t dres : 3;
64     uint32_t dgm : 3;
65     uint32_t dbuf: 1;
66 } clk_ll_xtal32k_config_t;
67 
68 /**
69  * @brief Power up BBPLL circuit
70  */
clk_ll_bbpll_enable(void)71 static inline __attribute__((always_inline)) void clk_ll_bbpll_enable(void)
72 {
73     SET_PERI_REG_MASK(PMU_IMM_HP_CK_POWER_REG, PMU_TIE_HIGH_XPD_BB_I2C |
74                       PMU_TIE_HIGH_XPD_BBPLL | PMU_TIE_HIGH_XPD_BBPLL_I2C);
75     SET_PERI_REG_MASK(PMU_IMM_HP_CK_POWER_REG, PMU_TIE_HIGH_GLOBAL_BBPLL_ICG);
76 }
77 
78 /**
79  * @brief Power down BBPLL circuit
80  */
clk_ll_bbpll_disable(void)81 static inline __attribute__((always_inline)) void clk_ll_bbpll_disable(void)
82 {
83     SET_PERI_REG_MASK(PMU_IMM_HP_CK_POWER_REG, PMU_TIE_LOW_GLOBAL_BBPLL_ICG) ;
84     SET_PERI_REG_MASK(PMU_IMM_HP_CK_POWER_REG, PMU_TIE_LOW_XPD_BBPLL | PMU_TIE_LOW_XPD_BBPLL_I2C);
85 }
86 
87 /**
88  * @brief Enable the internal oscillator output for LP_PLL_CLK
89  */
clk_ll_lp_pll_enable(void)90 static inline __attribute__((always_inline)) void clk_ll_lp_pll_enable(void)
91 {
92     // Enable lp_pll xpd status
93     SET_PERI_REG_MASK(PMU_HP_SLEEP_LP_CK_POWER_REG, PMU_HP_SLEEP_XPD_LPPLL);
94 }
95 
96 /**
97  * @brief Disable the internal oscillator output for LP_PLL_CLK
98  */
clk_ll_lp_pll_disable(void)99 static inline __attribute__((always_inline)) void clk_ll_lp_pll_disable(void)
100 {
101     // Disable lp_pll xpd status
102     CLEAR_PERI_REG_MASK(PMU_HP_SLEEP_LP_CK_POWER_REG, PMU_HP_SLEEP_XPD_LPPLL);
103 }
104 
105 /**
106  * @brief Enable the 32kHz crystal oscillator
107  *
108  * @param mode Used to determine the xtal32k configuration parameters
109  */
clk_ll_xtal32k_enable(clk_ll_xtal32k_enable_mode_t mode)110 static inline __attribute__((always_inline)) void clk_ll_xtal32k_enable(clk_ll_xtal32k_enable_mode_t mode)
111 {
112     if (mode == CLK_LL_XTAL32K_ENABLE_MODE_EXTERNAL) {
113         // No need to configure anything for OSC_SLOW_CLK
114         return;
115     }
116     // Configure xtal32k
117     clk_ll_xtal32k_config_t cfg = CLK_LL_XTAL32K_CONFIG_DEFAULT();
118     LP_CLKRST.xtal32k.dac_xtal32k = cfg.dac;
119     LP_CLKRST.xtal32k.dres_xtal32k = cfg.dres;
120     LP_CLKRST.xtal32k.dgm_xtal32k = cfg.dgm;
121     LP_CLKRST.xtal32k.dbuf_xtal32k = cfg.dbuf;
122     // Enable xtal32k xpd
123     SET_PERI_REG_MASK(PMU_HP_SLEEP_LP_CK_POWER_REG, PMU_HP_SLEEP_XPD_XTAL32K);
124 }
125 
126 /**
127  * @brief Disable the 32kHz crystal oscillator
128  */
clk_ll_xtal32k_disable(void)129 static inline __attribute__((always_inline)) void clk_ll_xtal32k_disable(void)
130 {
131     // Disable xtal32k xpd
132     CLEAR_PERI_REG_MASK(PMU_HP_SLEEP_LP_CK_POWER_REG, PMU_HP_SLEEP_XPD_XTAL32K);
133 }
134 
135 /**
136  * @brief Get the state of the 32kHz crystal clock
137  *
138  * @return True if the 32kHz XTAL is enabled
139  */
clk_ll_xtal32k_is_enabled(void)140 static inline __attribute__((always_inline)) bool clk_ll_xtal32k_is_enabled(void)
141 {
142     return REG_GET_FIELD(PMU_HP_SLEEP_LP_CK_POWER_REG, PMU_HP_SLEEP_XPD_XTAL32K) == 1;
143 }
144 
145 /**
146  * @brief Enable the internal oscillator output for RC32K_CLK
147  */
clk_ll_rc32k_enable(void)148 static inline __attribute__((always_inline)) void clk_ll_rc32k_enable(void)
149 {
150     // Enable rc32k xpd status
151     SET_PERI_REG_MASK(PMU_HP_SLEEP_LP_CK_POWER_REG, PMU_HP_SLEEP_XPD_RC32K);
152 }
153 
154 /**
155  * @brief Disable the internal oscillator output for RC32K_CLK
156  */
clk_ll_rc32k_disable(void)157 static inline __attribute__((always_inline)) void clk_ll_rc32k_disable(void)
158 {
159     // Disable rc32k xpd status
160     CLEAR_PERI_REG_MASK(PMU_HP_SLEEP_LP_CK_POWER_REG, PMU_HP_SLEEP_XPD_RC32K);
161 }
162 
163 /**
164  * @brief Get the state of the internal oscillator for RC32K_CLK
165  *
166  * @return True if the oscillator is enabled
167  */
clk_ll_rc32k_is_enabled(void)168 static inline __attribute__((always_inline)) bool clk_ll_rc32k_is_enabled(void)
169 {
170     return REG_GET_FIELD(PMU_HP_SLEEP_LP_CK_POWER_REG, PMU_HP_SLEEP_XPD_RC32K) == 1;
171 }
172 
173 /**
174  * @brief Enable the internal oscillator output for RC_FAST_CLK
175  */
clk_ll_rc_fast_enable(void)176 static inline __attribute__((always_inline)) void clk_ll_rc_fast_enable(void)
177 {
178     SET_PERI_REG_MASK(PMU_HP_SLEEP_LP_CK_POWER_REG, PMU_HP_SLEEP_XPD_FOSC_CLK);
179 }
180 
181 /**
182  * @brief Disable the internal oscillator output for RC_FAST_CLK
183  */
clk_ll_rc_fast_disable(void)184 static inline __attribute__((always_inline)) void clk_ll_rc_fast_disable(void)
185 {
186     CLEAR_PERI_REG_MASK(PMU_HP_SLEEP_LP_CK_POWER_REG, PMU_HP_SLEEP_XPD_FOSC_CLK);
187 }
188 
189 /**
190  * @brief Get the state of the internal oscillator for RC_FAST_CLK
191  *
192  * @return True if the oscillator is enabled
193  */
clk_ll_rc_fast_is_enabled(void)194 static inline __attribute__((always_inline)) bool clk_ll_rc_fast_is_enabled(void)
195 {
196     return REG_GET_FIELD(PMU_HP_SLEEP_LP_CK_POWER_REG, PMU_HP_SLEEP_XPD_FOSC_CLK) == 1;
197 }
198 
199 /**
200  * @brief Enable the digital RC_FAST_CLK, which is used to support peripherals.
201  */
clk_ll_rc_fast_digi_enable(void)202 static inline __attribute__((always_inline)) void clk_ll_rc_fast_digi_enable(void)
203 {
204     LP_CLKRST.clk_to_hp.icg_hp_fosc = 1;
205 }
206 
207 /**
208  * @brief Disable the digital RC_FAST_CLK, which is used to support peripherals.
209  */
clk_ll_rc_fast_digi_disable(void)210 static inline __attribute__((always_inline)) void clk_ll_rc_fast_digi_disable(void)
211 {
212     LP_CLKRST.clk_to_hp.icg_hp_fosc = 0;
213 }
214 
215 /**
216  * @brief Get the state of the digital RC_FAST_CLK
217  *
218  * @return True if the digital RC_FAST_CLK is enabled
219  */
clk_ll_rc_fast_digi_is_enabled(void)220 static inline __attribute__((always_inline)) bool clk_ll_rc_fast_digi_is_enabled(void)
221 {
222     return LP_CLKRST.clk_to_hp.icg_hp_fosc;
223 }
224 
225 /**
226  * @brief Enable the digital XTAL32K_CLK, which is used to support peripherals.
227  */
clk_ll_xtal32k_digi_enable(void)228 static inline __attribute__((always_inline)) void clk_ll_xtal32k_digi_enable(void)
229 {
230     LP_CLKRST.clk_to_hp.icg_hp_xtal32k = 1;
231 }
232 
233 /**
234  * @brief Disable the digital XTAL32K_CLK, which is used to support peripherals.
235  */
clk_ll_xtal32k_digi_disable(void)236 static inline __attribute__((always_inline)) void clk_ll_xtal32k_digi_disable(void)
237 {
238     LP_CLKRST.clk_to_hp.icg_hp_xtal32k = 0;
239 }
240 
241 /**
242  * @brief Get the state of the digital XTAL32K_CLK
243  *
244  * @return True if the digital XTAL32K_CLK is enabled
245  */
clk_ll_xtal32k_digi_is_enabled(void)246 static inline __attribute__((always_inline)) bool clk_ll_xtal32k_digi_is_enabled(void)
247 {
248     return LP_CLKRST.clk_to_hp.icg_hp_xtal32k;
249 }
250 
251 /**
252  * @brief Enable the digital RC32K_CLK, which is used to support peripherals.
253  */
clk_ll_rc32k_digi_enable(void)254 static inline __attribute__((always_inline)) void clk_ll_rc32k_digi_enable(void)
255 {
256     LP_CLKRST.clk_to_hp.icg_hp_osc32k = 1;
257 }
258 
259 /**
260  * @brief Disable the digital RC32K_CLK, which is used to support peripherals.
261  */
clk_ll_rc32k_digi_disable(void)262 static inline __attribute__((always_inline)) void clk_ll_rc32k_digi_disable(void)
263 {
264     LP_CLKRST.clk_to_hp.icg_hp_osc32k = 0;
265 }
266 
267 /**
268  * @brief Get the state of the digital RC32K_CLK
269  *
270  * @return True if the digital RC32K_CLK is enabled
271  */
clk_ll_rc32k_digi_is_enabled(void)272 static inline __attribute__((always_inline)) bool clk_ll_rc32k_digi_is_enabled(void)
273 {
274     return LP_CLKRST.clk_to_hp.icg_hp_osc32k;
275 }
276 
277 /**
278  * @brief Get PLL_CLK frequency
279  *
280  * @return PLL clock frequency, in MHz. Returns 0 if register field value is invalid.
281  */
clk_ll_bbpll_get_freq_mhz(void)282 static inline __attribute__((always_inline)) uint32_t clk_ll_bbpll_get_freq_mhz(void)
283 {
284     // The target has a fixed 96MHz SPLL
285     return CLK_LL_PLL_96M_FREQ_MHZ;
286 }
287 
288 /**
289  * @brief Set BBPLL frequency from XTAL source (Digital part)
290  *
291  * @param pll_freq_mhz PLL frequency, in MHz
292  */
clk_ll_bbpll_set_freq_mhz(uint32_t pll_freq_mhz)293 static inline __attribute__((always_inline)) void clk_ll_bbpll_set_freq_mhz(uint32_t pll_freq_mhz)
294 {
295     // The target SPLL is fixed to 96MHz
296     // Do nothing
297     HAL_ASSERT(pll_freq_mhz == CLK_LL_PLL_96M_FREQ_MHZ);
298 }
299 
300 /**
301  * @brief Set BBPLL frequency from XTAL source (Analog part)
302  *
303  * @param pll_freq_mhz PLL frequency, in MHz
304  * @param xtal_freq_mhz XTAL frequency, in MHz
305  */
clk_ll_bbpll_set_config(uint32_t pll_freq_mhz,uint32_t xtal_freq_mhz)306 static inline __attribute__((always_inline)) void clk_ll_bbpll_set_config(uint32_t pll_freq_mhz, uint32_t xtal_freq_mhz)
307 {
308     HAL_ASSERT(xtal_freq_mhz == RTC_XTAL_FREQ_32M);
309     HAL_ASSERT(pll_freq_mhz == CLK_LL_PLL_96M_FREQ_MHZ);
310     uint8_t oc_ref_div;
311     uint8_t oc_div;
312     uint8_t oc_dhref_sel;
313     uint8_t oc_dlref_sel;
314 
315     oc_ref_div = 0;
316     oc_div = 1;
317     oc_dhref_sel = 3;
318     oc_dlref_sel = 1;
319 
320     REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_REF_DIV, oc_ref_div);
321     REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DIV, oc_div);
322     REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DHREF_SEL, oc_dhref_sel);
323     REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DLREF_SEL, oc_dlref_sel);
324 }
325 
326 /**
327  * @brief Get FLASH_PLL_CLK frequency
328  *
329  * @return FLASH_PLL clock frequency, in MHz
330  */
clk_ll_flash_pll_get_freq_mhz(void)331 static inline __attribute__((always_inline)) uint32_t clk_ll_flash_pll_get_freq_mhz(void)
332 {
333     // The target has a fixed 64MHz flash PLL, which is directly derived from BBPLL
334     return CLK_LL_PLL_64M_FREQ_MHZ;
335 }
336 
337 /**
338  * @brief To enable the change of soc_clk_sel, cpu_div_num, and ahb_div_num
339  */
clk_ll_bus_update(void)340 static inline __attribute__((always_inline)) void clk_ll_bus_update(void)
341 {
342     PCR.bus_clk_update.bus_clock_update = 1;
343     while (PCR.bus_clk_update.bus_clock_update);
344 }
345 
346 /**
347  * @brief Select the clock source for CPU_CLK (SOC Clock Root)
348  *
349  * @param in_sel One of the clock sources in soc_cpu_clk_src_t
350  */
clk_ll_cpu_set_src(soc_cpu_clk_src_t in_sel)351 static inline __attribute__((always_inline)) void clk_ll_cpu_set_src(soc_cpu_clk_src_t in_sel)
352 {
353     switch (in_sel) {
354     case SOC_CPU_CLK_SRC_XTAL:
355         PCR.sysclk_conf.soc_clk_sel = 0;
356         break;
357     case SOC_CPU_CLK_SRC_PLL:
358         PCR.sysclk_conf.soc_clk_sel = 1;
359         break;
360     case SOC_CPU_CLK_SRC_RC_FAST:
361         PCR.sysclk_conf.soc_clk_sel = 2;
362         break;
363     case SOC_CPU_CLK_SRC_FLASH_PLL:
364         PCR.sysclk_conf.soc_clk_sel = 3;
365         break;
366     default:
367         // Unsupported CPU_CLK mux input sel
368         abort();
369     }
370 }
371 
372 /**
373  * @brief Get the clock source for CPU_CLK (SOC Clock Root)
374  *
375  * @return Currently selected clock source (one of soc_cpu_clk_src_t values)
376  */
clk_ll_cpu_get_src(void)377 static inline __attribute__((always_inline)) soc_cpu_clk_src_t clk_ll_cpu_get_src(void)
378 {
379     uint32_t clk_sel = PCR.sysclk_conf.soc_clk_sel;
380     switch (clk_sel) {
381     case 0:
382         return SOC_CPU_CLK_SRC_XTAL;
383     case 1:
384         return SOC_CPU_CLK_SRC_PLL;
385     case 2:
386         return SOC_CPU_CLK_SRC_RC_FAST;
387     case 3:
388         return SOC_CPU_CLK_SRC_FLASH_PLL;
389     default:
390         // Invalid SOC_CLK_SEL value
391         return SOC_CPU_CLK_SRC_INVALID;
392     }
393 }
394 
395 /**
396  * @brief Set CPU_CLK divider
397  *
398  * @param divider Divider. PRE_DIV_CNT = divider - 1.
399  */
clk_ll_cpu_set_divider(uint32_t divider)400 static inline __attribute__((always_inline)) void clk_ll_cpu_set_divider(uint32_t divider)
401 {
402     HAL_ASSERT(divider >= 1);
403     HAL_FORCE_MODIFY_U32_REG_FIELD(PCR.cpu_freq_conf, cpu_div_num, divider - 1);
404 }
405 
406 /**
407  * @brief Get CPU_CLK divider
408  *
409  * @return Divider. Divider = (PRE_DIV_CNT + 1).
410  */
clk_ll_cpu_get_divider(void)411 static inline __attribute__((always_inline)) uint32_t clk_ll_cpu_get_divider(void)
412 {
413     return HAL_FORCE_READ_U32_REG_FIELD(PCR.cpu_freq_conf, cpu_div_num) + 1;
414 }
415 
416 /**
417  * @brief Set AHB_CLK divider
418  *
419  * @param divider Divider. PRE_DIV_CNT = divider - 1.
420  */
clk_ll_ahb_set_divider(uint32_t divider)421 static inline __attribute__((always_inline)) void clk_ll_ahb_set_divider(uint32_t divider)
422 {
423     HAL_ASSERT(divider >= 1);
424     HAL_FORCE_MODIFY_U32_REG_FIELD(PCR.ahb_freq_conf, ahb_div_num, divider - 1);
425 }
426 
427 /**
428  * @brief Get AHB_CLK divider
429  *
430  * @return Divider. Divider = (PRE_DIV_CNT + 1).
431  */
clk_ll_ahb_get_divider(void)432 static inline __attribute__((always_inline)) uint32_t clk_ll_ahb_get_divider(void)
433 {
434     return HAL_FORCE_READ_U32_REG_FIELD(PCR.ahb_freq_conf, ahb_div_num) + 1;
435 }
436 
437 /**
438  * @brief Set APB_CLK divider. freq of APB_CLK = freq of AHB_CLK / divider
439  *
440  * @param divider Divider. PCR_APB_DIV_NUM = divider - 1.
441  */
clk_ll_apb_set_divider(uint32_t divider)442 static inline __attribute__((always_inline)) void clk_ll_apb_set_divider(uint32_t divider)
443 {
444     // AHB ------> APB
445     // Divider option: 1, 2, 4 (PCR_APB_DIV_NUM=0, 1, 3)
446     HAL_ASSERT(divider == 1 || divider == 2 || divider == 4);
447     HAL_FORCE_MODIFY_U32_REG_FIELD(PCR.apb_freq_conf, apb_div_num, divider - 1);
448 }
449 
450 /**
451  * @brief Get APB_CLK divider
452  *
453  * @return Divider. Divider = (PCR_APB_DIV_NUM + 1).
454  */
clk_ll_apb_get_divider(void)455 static inline __attribute__((always_inline)) uint32_t clk_ll_apb_get_divider(void)
456 {
457     return HAL_FORCE_READ_U32_REG_FIELD(PCR.apb_freq_conf, apb_div_num) + 1;
458 }
459 
460 /**
461  * @brief Select the calibration 32kHz clock source for timergroup0
462  *
463  * @param in_sel One of the 32kHz clock sources (RC32K_CLK, XTAL32K_CLK, OSC_SLOW_CLK)
464  */
clk_ll_32k_calibration_set_target(soc_rtc_slow_clk_src_t in_sel)465 static inline __attribute__((always_inline)) void clk_ll_32k_calibration_set_target(soc_rtc_slow_clk_src_t in_sel)
466 {
467     switch (in_sel) {
468     case SOC_RTC_SLOW_CLK_SRC_RC32K:
469         PCR.ctrl_32k_conf.clk_32k_sel = 0;
470         break;
471     case SOC_RTC_SLOW_CLK_SRC_XTAL32K:
472         PCR.ctrl_32k_conf.clk_32k_sel = 1;
473         break;
474     case SOC_RTC_SLOW_CLK_SRC_OSC_SLOW:
475         PCR.ctrl_32k_conf.clk_32k_sel = 2;
476         break;
477     default:
478         // Unsupported 32K_SEL mux input
479         abort();
480     }
481 }
482 
483 /**
484  * @brief Get the calibration 32kHz clock source for timergroup0
485  *
486  * @return soc_rtc_slow_clk_src_t Currently selected calibration 32kHz clock (one of the 32kHz clocks)
487  */
clk_ll_32k_calibration_get_target(void)488 static inline __attribute__((always_inline)) soc_rtc_slow_clk_src_t clk_ll_32k_calibration_get_target(void)
489 {
490     uint32_t clk_sel = PCR.ctrl_32k_conf.clk_32k_sel;
491     switch (clk_sel) {
492     case 0:
493         return SOC_RTC_SLOW_CLK_SRC_RC32K;
494     case 1:
495         return SOC_RTC_SLOW_CLK_SRC_XTAL32K;
496     case 2:
497         return SOC_RTC_SLOW_CLK_SRC_OSC_SLOW;
498     default:
499         return SOC_RTC_SLOW_CLK_SRC_INVALID;
500     }
501 }
502 
503 /**
504  * @brief Select the clock source for RTC_SLOW_CLK
505  *
506  * @param in_sel One of the clock sources in soc_rtc_slow_clk_src_t
507  */
clk_ll_rtc_slow_set_src(soc_rtc_slow_clk_src_t in_sel)508 static inline __attribute__((always_inline)) void clk_ll_rtc_slow_set_src(soc_rtc_slow_clk_src_t in_sel)
509 {
510     switch (in_sel) {
511     case SOC_RTC_SLOW_CLK_SRC_RC_SLOW:
512         LP_CLKRST.lp_clk_conf.slow_clk_sel = 0;
513         break;
514     case SOC_RTC_SLOW_CLK_SRC_XTAL32K:
515         LP_CLKRST.lp_clk_conf.slow_clk_sel = 1;
516         break;
517     case SOC_RTC_SLOW_CLK_SRC_RC32K:
518         LP_CLKRST.lp_clk_conf.slow_clk_sel = 2;
519         break;
520     case SOC_RTC_SLOW_CLK_SRC_OSC_SLOW:
521         LP_CLKRST.lp_clk_conf.slow_clk_sel = 3;
522         break;
523     default:
524         // Unsupported RTC_SLOW_CLK mux input sel
525         abort();
526     }
527 }
528 
529 /**
530  * @brief Get the clock source for RTC_SLOW_CLK
531  *
532  * @return Currently selected clock source (one of soc_rtc_slow_clk_src_t values)
533  */
clk_ll_rtc_slow_get_src(void)534 static inline __attribute__((always_inline)) soc_rtc_slow_clk_src_t clk_ll_rtc_slow_get_src(void)
535 {
536     uint32_t clk_sel = LP_CLKRST.lp_clk_conf.slow_clk_sel;
537     switch (clk_sel) {
538     case 0:
539         return SOC_RTC_SLOW_CLK_SRC_RC_SLOW;
540     case 1:
541         return SOC_RTC_SLOW_CLK_SRC_XTAL32K;
542     case 2:
543         return SOC_RTC_SLOW_CLK_SRC_RC32K;
544     case 3:
545         return SOC_RTC_SLOW_CLK_SRC_OSC_SLOW;
546     default:
547         return SOC_RTC_SLOW_CLK_SRC_INVALID;
548     }
549 }
550 
551 /**
552  * @brief Select the clock source for LP_PLL_CLK
553  *
554  * @param in_sel One of the clock sources in soc_lp_pll_clk_src_t
555  */
clk_ll_lp_pll_set_src(soc_lp_pll_clk_src_t in_sel)556 static inline __attribute__((always_inline)) void clk_ll_lp_pll_set_src(soc_lp_pll_clk_src_t in_sel)
557 {
558     uint32_t field_value;
559     switch (in_sel) {
560     case SOC_LP_PLL_CLK_SRC_RC32K:
561         field_value = 0;
562         break;
563     case SOC_LP_PLL_CLK_SRC_XTAL32K:
564         field_value = 1;
565         break;
566     default:
567         // Unsupported LP_PLL_CLK mux input sel
568         abort();
569     }
570     REGI2C_WRITE_MASK(I2C_PMU, I2C_PMU_SEL_PLL8M_REF, field_value);
571 }
572 
573 /**
574  * @brief Get the clock source for LP_PLL_CLK
575  *
576  * @return Currently selected clock source (one of soc_lp_pll_clk_src_t values)
577  */
clk_ll_lp_pll_get_src(void)578 static inline __attribute__((always_inline)) soc_lp_pll_clk_src_t clk_ll_lp_pll_get_src(void)
579 {
580     uint32_t clk_sel = REGI2C_READ_MASK(I2C_PMU, I2C_PMU_SEL_PLL8M_REF);
581     switch (clk_sel) {
582     case 0:
583         return SOC_LP_PLL_CLK_SRC_RC32K;
584     case 1:
585         return SOC_LP_PLL_CLK_SRC_XTAL32K;
586     default:
587         return SOC_LP_PLL_CLK_SRC_INVALID;
588     }
589 }
590 
591 /**
592  * @brief Get LP_PLL_CLK frequency
593  *
594  * @return LP_PLL clock frequency, in MHz
595  */
clk_ll_lp_pll_get_freq_mhz(void)596 static inline __attribute__((always_inline)) uint32_t clk_ll_lp_pll_get_freq_mhz(void)
597 {
598     // The target has a fixed 8MHz LP_PLL
599     return CLK_LL_PLL_8M_FREQ_MHZ;
600 }
601 
602 /**
603  * @brief Select the clock source for RTC_FAST_CLK
604  *
605  * @param in_sel One of the clock sources in soc_rtc_fast_clk_src_t
606  */
clk_ll_rtc_fast_set_src(soc_rtc_fast_clk_src_t in_sel)607 static inline __attribute__((always_inline)) void clk_ll_rtc_fast_set_src(soc_rtc_fast_clk_src_t in_sel)
608 {
609     switch (in_sel) {
610     case SOC_RTC_FAST_CLK_SRC_RC_FAST:
611         LP_CLKRST.lp_clk_conf.fast_clk_sel = 0;
612         break;
613     case SOC_RTC_FAST_CLK_SRC_XTAL_D2:
614         LP_CLKRST.lp_clk_conf.fast_clk_sel = 1;
615         break;
616     case SOC_RTC_FAST_CLK_SRC_LP_PLL:
617         LP_CLKRST.lp_clk_conf.fast_clk_sel = 2;
618         break;
619     default:
620         // Unsupported RTC_FAST_CLK mux input sel
621         abort();
622     }
623 }
624 
625 /**
626  * @brief Get the clock source for RTC_FAST_CLK
627  *
628  * @return Currently selected clock source (one of soc_rtc_fast_clk_src_t values)
629  */
clk_ll_rtc_fast_get_src(void)630 static inline __attribute__((always_inline)) soc_rtc_fast_clk_src_t clk_ll_rtc_fast_get_src(void)
631 {
632     uint32_t clk_sel = LP_CLKRST.lp_clk_conf.fast_clk_sel;
633     switch (clk_sel) {
634     case 0:
635         return SOC_RTC_FAST_CLK_SRC_RC_FAST;
636     case 1:
637         return SOC_RTC_FAST_CLK_SRC_XTAL_D2;
638     case 2:
639         return SOC_RTC_FAST_CLK_SRC_LP_PLL;
640     default:
641         return SOC_RTC_FAST_CLK_SRC_INVALID;
642     }
643 }
644 
645 /**
646  * @brief Set RC_FAST_CLK divider. The output from the divider is passed into rtc_fast_clk MUX.
647  *
648  * @param divider Divider of RC_FAST_CLK. Usually this divider is set to 1 (reg. value is 0) in bootloader stage.
649  */
clk_ll_rc_fast_set_divider(uint32_t divider)650 static inline __attribute__((always_inline)) void clk_ll_rc_fast_set_divider(uint32_t divider)
651 {
652     // No divider on the target
653     HAL_ASSERT(divider == 1);
654 }
655 
656 /**
657  * @brief Get RC_FAST_CLK divider
658  *
659  * @return Divider. Divider = (CK8M_DIV_SEL + 1).
660  */
clk_ll_rc_fast_get_divider(void)661 static inline __attribute__((always_inline)) uint32_t clk_ll_rc_fast_get_divider(void)
662 {
663     // No divider on the target, always return divider = 1
664     return 1;
665 }
666 
667 /**
668  * @brief Set RC_SLOW_CLK divider
669  *
670  * @param divider Divider of RC_SLOW_CLK. Usually this divider is set to 1 (reg. value is 0) in bootloader stage.
671  */
clk_ll_rc_slow_set_divider(uint32_t divider)672 static inline __attribute__((always_inline)) void clk_ll_rc_slow_set_divider(uint32_t divider)
673 {
674     // No divider on the target
675     HAL_ASSERT(divider == 1);
676 }
677 
678 /************************** LP STORAGE REGISTER STORE/LOAD **************************/
679 /**
680  * @brief Store XTAL_CLK frequency in RTC storage register
681  *
682  * Value of RTC_XTAL_FREQ_REG is stored as two copies in lower and upper 16-bit
683  * halves. These are the routines to work with that representation.
684  *
685  * @param xtal_freq_mhz XTAL frequency, in MHz. The frequency must necessarily be even,
686  * otherwise there will be a conflict with the low bit, which is used to disable logs
687  * in the ROM code.
688  */
clk_ll_xtal_store_freq_mhz(uint32_t xtal_freq_mhz)689 static inline __attribute__((always_inline)) void clk_ll_xtal_store_freq_mhz(uint32_t xtal_freq_mhz)
690 {
691     // Read the status of whether disabling logging from ROM code
692     uint32_t reg = READ_PERI_REG(RTC_XTAL_FREQ_REG) & RTC_DISABLE_ROM_LOG;
693     // If so, need to write back this setting
694     if (reg == RTC_DISABLE_ROM_LOG) {
695         xtal_freq_mhz |= 1;
696     }
697     WRITE_PERI_REG(RTC_XTAL_FREQ_REG, (xtal_freq_mhz & UINT16_MAX) | ((xtal_freq_mhz & UINT16_MAX) << 16));
698 }
699 
700 /**
701  * @brief Load XTAL_CLK frequency from RTC storage register
702  *
703  * Value of RTC_XTAL_FREQ_REG is stored as two copies in lower and upper 16-bit
704  * halves. These are the routines to work with that representation.
705  *
706  * @return XTAL frequency, in MHz. Returns 0 if value in reg is invalid.
707  */
clk_ll_xtal_load_freq_mhz(void)708 static inline __attribute__((always_inline)) uint32_t clk_ll_xtal_load_freq_mhz(void)
709 {
710     // Read from RTC storage register
711     uint32_t xtal_freq_reg = READ_PERI_REG(RTC_XTAL_FREQ_REG);
712     if ((xtal_freq_reg & 0xFFFF) == ((xtal_freq_reg >> 16) & 0xFFFF) &&
713         xtal_freq_reg != 0 && xtal_freq_reg != UINT32_MAX) {
714         return xtal_freq_reg & ~RTC_DISABLE_ROM_LOG & UINT16_MAX;
715     }
716     // If the format in reg is invalid
717     return 0;
718 }
719 
720 /**
721  * @brief Store RTC_SLOW_CLK calibration value in RTC storage register
722  *
723  * Value of RTC_SLOW_CLK_CAL_REG has to be in the same format as returned by rtc_clk_cal (microseconds,
724  * in Q13.19 fixed-point format).
725  *
726  * @param cal_value The calibration value of slow clock period in microseconds, in Q13.19 fixed point format
727  */
clk_ll_rtc_slow_store_cal(uint32_t cal_value)728 static inline __attribute__((always_inline)) void clk_ll_rtc_slow_store_cal(uint32_t cal_value)
729 {
730     REG_WRITE(RTC_SLOW_CLK_CAL_REG, cal_value);
731 }
732 
733 /**
734  * @brief Load the calibration value of RTC_SLOW_CLK frequency from RTC storage register
735  *
736  * This value gets updated (i.e. rtc slow clock gets calibrated) every time RTC_SLOW_CLK source switches
737  *
738  * @return The calibration value of slow clock period in microseconds, in Q13.19 fixed point format
739  */
clk_ll_rtc_slow_load_cal(void)740 static inline __attribute__((always_inline)) uint32_t clk_ll_rtc_slow_load_cal(void)
741 {
742     return REG_READ(RTC_SLOW_CLK_CAL_REG);
743 }
744 
745 /*
746 Set the frequency division factor of ref_tick
747 */
clk_ll_rc_fast_tick_conf(void)748 static inline void clk_ll_rc_fast_tick_conf(void)
749 {
750     PCR.ctrl_tick_conf.fosc_tick_num = REG_FOSC_TICK_NUM;
751 }
752 
753 #ifdef __cplusplus
754 }
755 #endif
756