1 /*
2  * Copyright 2017 - 2021, 2024 NXP
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include "fsl_clock.h"
9 /* Component ID definition, used by tools. */
10 #ifndef FSL_COMPONENT_ID
11 #define FSL_COMPONENT_ID "platform.drivers.clock"
12 #endif
13 /*******************************************************************************
14  * Definitions
15  ******************************************************************************/
16 /* To make full use of CM7 hardware FPU, use double instead of uint64_t in clock driver to
17 achieve better performance, it is depend on the IDE Floating point settings, if double precision is selected
18 in IDE, clock_64b_t will switch to double type automatically. only support IAR and MDK here */
19 #if __FPU_USED
20 
21 #if (defined(__ICCARM__))
22 
23 #if (__ARMVFP__ >= __ARMFPV5__) && \
24     (__ARM_FP == 0xE) /*0xe implies support for half, single and double precision operations*/
25 typedef double clock_64b_t;
26 #else
27 typedef uint64_t clock_64b_t;
28 #endif
29 
30 #elif (defined(__GNUC__))
31 
32 #if (__ARM_FP == 0xE) /*0xe implies support for half, single and double precision operations*/
33 typedef double clock_64b_t;
34 #else
35 typedef uint64_t clock_64b_t;
36 #endif
37 
38 #elif defined(__CC_ARM) || defined(__ARMCC_VERSION)
39 
40 #if defined __TARGET_FPU_FPV5_D16
41 typedef double clock_64b_t;
42 #else
43 typedef uint64_t clock_64b_t;
44 #endif
45 
46 #else
47 typedef uint64_t clock_64b_t;
48 #endif
49 
50 #else
51 typedef uint64_t clock_64b_t;
52 #endif
53 
54 /*******************************************************************************
55  * Variables
56  ******************************************************************************/
57 
58 /* External XTAL (OSC) clock frequency. */
59 volatile uint32_t g_xtalFreq;
60 /* External RTC XTAL clock frequency. */
61 volatile uint32_t g_rtcXtalFreq;
62 
63 /*******************************************************************************
64  * Prototypes
65  ******************************************************************************/
66 
67 /*!
68  * @brief Get the periph clock frequency.
69  *
70  * @return Periph clock frequency in Hz.
71  */
72 static uint32_t CLOCK_GetPeriphClkFreq(void);
73 
74 /*!
75  * @brief Get the frequency of PLL USB1 software clock.
76  *
77  * @return The frequency of PLL USB1 software clock.
78  */
79 static uint32_t CLOCK_GetPllUsb1SWFreq(void);
80 
81 /*******************************************************************************
82  * Code
83  ******************************************************************************/
84 
CLOCK_GetPeriphClkFreq(void)85 static uint32_t CLOCK_GetPeriphClkFreq(void)
86 {
87     uint32_t freq;
88 
89     /* Periph_clk2_clk ---> Periph_clk */
90     if ((CCM->CBCDR & CCM_CBCDR_PERIPH_CLK_SEL_MASK) != 0U)
91     {
92         switch (CCM->CBCMR & CCM_CBCMR_PERIPH_CLK2_SEL_MASK)
93         {
94             /* Pll3_sw_clk ---> Periph_clk2_clk ---> Periph_clk */
95             case CCM_CBCMR_PERIPH_CLK2_SEL(0U):
96                 freq = CLOCK_GetPllFreq(kCLOCK_PllUsb1);
97                 break;
98 
99             /* Osc_clk ---> Periph_clk2_clk ---> Periph_clk */
100             case CCM_CBCMR_PERIPH_CLK2_SEL(1U):
101                 freq = CLOCK_GetOscFreq();
102                 break;
103 
104             case CCM_CBCMR_PERIPH_CLK2_SEL(2U):
105                 freq = CLOCK_GetPllFreq(kCLOCK_PllSys);
106                 break;
107 
108             case CCM_CBCMR_PERIPH_CLK2_SEL(3U):
109             default:
110                 freq = 0U;
111                 break;
112         }
113 
114         freq /= (((CCM->CBCDR & CCM_CBCDR_PERIPH_CLK2_PODF_MASK) >> CCM_CBCDR_PERIPH_CLK2_PODF_SHIFT) + 1U);
115     }
116     /* Pre_Periph_clk ---> Periph_clk */
117     else
118     {
119         switch (CCM->CBCMR & CCM_CBCMR_PRE_PERIPH_CLK_SEL_MASK)
120         {
121             /* PLL2 ---> Pre_Periph_clk ---> Periph_clk */
122             case CCM_CBCMR_PRE_PERIPH_CLK_SEL(0U):
123                 freq = CLOCK_GetPllFreq(kCLOCK_PllSys);
124                 break;
125 
126             /* PLL2 PFD2 ---> Pre_Periph_clk ---> Periph_clk */
127             case CCM_CBCMR_PRE_PERIPH_CLK_SEL(1U):
128                 freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd2);
129                 break;
130 
131             /* PLL2 PFD0 ---> Pre_Periph_clk ---> Periph_clk */
132             case CCM_CBCMR_PRE_PERIPH_CLK_SEL(2U):
133                 freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd0);
134                 break;
135 
136             /* PLL1 divided(/2) ---> Pre_Periph_clk ---> Periph_clk */
137             case CCM_CBCMR_PRE_PERIPH_CLK_SEL(3U):
138                 freq = CLOCK_GetPllFreq(kCLOCK_PllArm) /
139                        (((CCM->CACRR & CCM_CACRR_ARM_PODF_MASK) >> CCM_CACRR_ARM_PODF_SHIFT) + 1U);
140                 break;
141 
142             default:
143                 freq = 0U;
144                 break;
145         }
146     }
147 
148     return freq;
149 }
150 
CLOCK_GetPllUsb1SWFreq(void)151 static uint32_t CLOCK_GetPllUsb1SWFreq(void)
152 {
153     uint32_t freq;
154 
155     switch ((CCM->CCSR & CCM_CCSR_PLL3_SW_CLK_SEL_MASK) >> CCM_CCSR_PLL3_SW_CLK_SEL_SHIFT)
156     {
157         case 0:
158         {
159             freq = CLOCK_GetPllFreq(kCLOCK_PllUsb1);
160             break;
161         }
162         case 1:
163         {
164             freq = 24000000UL;
165             break;
166         }
167         default:
168             freq = 0UL;
169             break;
170     }
171 
172     return freq;
173 }
174 
175 /*!
176  * brief Initialize the external 24MHz clock.
177  *
178  * This function supports two modes:
179  * 1. Use external crystal oscillator.
180  * 2. Bypass the external crystal oscillator, using input source clock directly.
181  *
182  * After this function, please call ref CLOCK_SetXtal0Freq to inform clock driver
183  * the external clock frequency.
184  *
185  * param bypassXtalOsc Pass in true to bypass the external crystal oscillator.
186  * note This device does not support bypass external crystal oscillator, so
187  * the input parameter should always be false.
188  */
CLOCK_InitExternalClk(bool bypassXtalOsc)189 void CLOCK_InitExternalClk(bool bypassXtalOsc)
190 {
191     /* This device does not support bypass XTAL OSC. */
192     assert(!bypassXtalOsc);
193 
194     CCM_ANALOG->MISC0_CLR = CCM_ANALOG_MISC0_XTAL_24M_PWD_MASK; /* Power up */
195     while ((XTALOSC24M->LOWPWR_CTRL & XTALOSC24M_LOWPWR_CTRL_XTALOSC_PWRUP_STAT_MASK) == 0U)
196     {
197     }
198     CCM_ANALOG->MISC0_SET = CCM_ANALOG_MISC0_OSC_XTALOK_EN_MASK; /* detect freq */
199     while ((CCM_ANALOG->MISC0 & CCM_ANALOG_MISC0_OSC_XTALOK_MASK) == 0UL)
200     {
201     }
202     CCM_ANALOG->MISC0_CLR = CCM_ANALOG_MISC0_OSC_XTALOK_EN_MASK;
203 }
204 
205 /*!
206  * brief Deinitialize the external 24MHz clock.
207  *
208  * This function disables the external 24MHz clock.
209  *
210  * After this function, please call ref CLOCK_SetXtal0Freq to set external clock
211  * frequency to 0.
212  */
CLOCK_DeinitExternalClk(void)213 void CLOCK_DeinitExternalClk(void)
214 {
215     CCM_ANALOG->MISC0_SET = CCM_ANALOG_MISC0_XTAL_24M_PWD_MASK; /* Power down */
216 }
217 
218 /*!
219  * brief Switch the OSC.
220  *
221  * This function switches the OSC source for SoC.
222  *
223  * param osc   OSC source to switch to.
224  */
CLOCK_SwitchOsc(clock_osc_t osc)225 void CLOCK_SwitchOsc(clock_osc_t osc)
226 {
227     if (osc == kCLOCK_RcOsc)
228     {
229         XTALOSC24M->LOWPWR_CTRL_SET = XTALOSC24M_LOWPWR_CTRL_SET_OSC_SEL_MASK;
230     }
231     else
232     {
233         XTALOSC24M->LOWPWR_CTRL_CLR = XTALOSC24M_LOWPWR_CTRL_CLR_OSC_SEL_MASK;
234     }
235 }
236 
237 /*!
238  * brief Initialize the RC oscillator 24MHz clock.
239  */
CLOCK_InitRcOsc24M(void)240 void CLOCK_InitRcOsc24M(void)
241 {
242     XTALOSC24M->LOWPWR_CTRL |= XTALOSC24M_LOWPWR_CTRL_RC_OSC_EN_MASK;
243 }
244 
245 /*!
246  * brief Power down the RCOSC 24M clock.
247  */
CLOCK_DeinitRcOsc24M(void)248 void CLOCK_DeinitRcOsc24M(void)
249 {
250     XTALOSC24M->LOWPWR_CTRL &= ~XTALOSC24M_LOWPWR_CTRL_RC_OSC_EN_MASK;
251 }
252 
253 /*!
254  * brief Gets the AHB clock frequency.
255  *
256  * return  The AHB clock frequency value in hertz.
257  */
CLOCK_GetAhbFreq(void)258 uint32_t CLOCK_GetAhbFreq(void)
259 {
260     return CLOCK_GetPeriphClkFreq() / (((CCM->CBCDR & CCM_CBCDR_AHB_PODF_MASK) >> CCM_CBCDR_AHB_PODF_SHIFT) + 1U);
261 }
262 
263 /*!
264  * brief Gets the SEMC clock frequency.
265  *
266  * return  The SEMC clock frequency value in hertz.
267  */
CLOCK_GetSemcFreq(void)268 uint32_t CLOCK_GetSemcFreq(void)
269 {
270     uint32_t freq;
271 
272     /* SEMC alternative clock ---> SEMC Clock */
273     if ((CCM->CBCDR & CCM_CBCDR_SEMC_CLK_SEL_MASK) != 0U)
274     {
275         /* PLL3 PFD1 ---> SEMC alternative clock ---> SEMC Clock */
276         if ((CCM->CBCDR & CCM_CBCDR_SEMC_ALT_CLK_SEL_MASK) != 0U)
277         {
278             freq = CLOCK_GetUsb1PfdFreq(kCLOCK_Pfd1);
279         }
280         /* PLL2 PFD2 ---> SEMC alternative clock ---> SEMC Clock */
281         else
282         {
283             freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd2);
284         }
285     }
286     /* Periph_clk ---> SEMC Clock */
287     else
288     {
289         freq = CLOCK_GetPeriphClkFreq();
290     }
291 
292     freq /= (((CCM->CBCDR & CCM_CBCDR_SEMC_PODF_MASK) >> CCM_CBCDR_SEMC_PODF_SHIFT) + 1U);
293 
294     return freq;
295 }
296 
297 /*!
298  * brief Gets the IPG clock frequency.
299  *
300  * return  The IPG clock frequency value in hertz.
301  */
CLOCK_GetIpgFreq(void)302 uint32_t CLOCK_GetIpgFreq(void)
303 {
304     return CLOCK_GetAhbFreq() / (((CCM->CBCDR & CCM_CBCDR_IPG_PODF_MASK) >> CCM_CBCDR_IPG_PODF_SHIFT) + 1U);
305 }
306 
307 /*!
308  * brief Gets the PER clock frequency.
309  *
310  * return  The PER clock frequency value in hertz.
311  */
CLOCK_GetPerClkFreq(void)312 uint32_t CLOCK_GetPerClkFreq(void)
313 {
314     uint32_t freq;
315 
316     /* Osc_clk ---> PER Clock*/
317     if ((CCM->CSCMR1 & CCM_CSCMR1_PERCLK_CLK_SEL_MASK) != 0U)
318     {
319         freq = CLOCK_GetOscFreq();
320     }
321     /* Periph_clk ---> AHB Clock ---> IPG Clock ---> PER Clock */
322     else
323     {
324         freq = CLOCK_GetIpgFreq();
325     }
326 
327     freq /= (((CCM->CSCMR1 & CCM_CSCMR1_PERCLK_PODF_MASK) >> CCM_CSCMR1_PERCLK_PODF_SHIFT) + 1U);
328 
329     return freq;
330 }
331 
332 /*!
333  * brief Gets the clock frequency for a specific clock name.
334  *
335  * This function checks the current clock configurations and then calculates
336  * the clock frequency for a specific clock name defined in clock_name_t.
337  *
338  * param clockName Clock names defined in clock_name_t
339  * return Clock frequency value in hertz
340  */
CLOCK_GetFreq(clock_name_t name)341 uint32_t CLOCK_GetFreq(clock_name_t name)
342 {
343     uint32_t freq;
344 
345     switch (name)
346     {
347         case kCLOCK_CpuClk:
348         case kCLOCK_AhbClk:
349             freq = CLOCK_GetAhbFreq();
350             break;
351 
352         case kCLOCK_SemcClk:
353             freq = CLOCK_GetSemcFreq();
354             break;
355 
356         case kCLOCK_IpgClk:
357             freq = CLOCK_GetIpgFreq();
358             break;
359 
360         case kCLOCK_PerClk:
361             freq = CLOCK_GetPerClkFreq();
362             break;
363 
364         case kCLOCK_OscClk:
365             freq = CLOCK_GetOscFreq();
366             break;
367         case kCLOCK_RtcClk:
368             freq = CLOCK_GetRtcFreq();
369             break;
370         case kCLOCK_ArmPllClk:
371             freq = CLOCK_GetPllFreq(kCLOCK_PllArm);
372             break;
373         case kCLOCK_Usb1PllClk:
374             freq = CLOCK_GetPllFreq(kCLOCK_PllUsb1);
375             break;
376         case kCLOCK_Usb1PllPfd0Clk:
377             freq = CLOCK_GetUsb1PfdFreq(kCLOCK_Pfd0);
378             break;
379         case kCLOCK_Usb1PllPfd1Clk:
380             freq = CLOCK_GetUsb1PfdFreq(kCLOCK_Pfd1);
381             break;
382         case kCLOCK_Usb1PllPfd2Clk:
383             freq = CLOCK_GetUsb1PfdFreq(kCLOCK_Pfd2);
384             break;
385         case kCLOCK_Usb1PllPfd3Clk:
386             freq = CLOCK_GetUsb1PfdFreq(kCLOCK_Pfd3);
387             break;
388         case kCLOCK_Usb1SwClk:
389             freq = CLOCK_GetPllUsb1SWFreq();
390             break;
391         case kCLOCK_Usb1Sw120MClk:
392             freq = CLOCK_GetPllUsb1SWFreq() / 4UL;
393             break;
394         case kCLOCK_Usb1Sw60MClk:
395             freq = CLOCK_GetPllUsb1SWFreq() / 8UL;
396             break;
397         case kCLOCK_Usb1Sw80MClk:
398             freq = CLOCK_GetPllUsb1SWFreq() / 6UL;
399             break;
400         case kCLOCK_Usb2PllClk:
401             freq = CLOCK_GetPllFreq(kCLOCK_PllUsb2);
402             break;
403         case kCLOCK_SysPllClk:
404             freq = CLOCK_GetPllFreq(kCLOCK_PllSys);
405             break;
406         case kCLOCK_SysPllPfd0Clk:
407             freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd0);
408             break;
409         case kCLOCK_SysPllPfd1Clk:
410             freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd1);
411             break;
412         case kCLOCK_SysPllPfd2Clk:
413             freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd2);
414             break;
415         case kCLOCK_SysPllPfd3Clk:
416             freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd3);
417             break;
418         case kCLOCK_EnetPll0Clk:
419             freq = CLOCK_GetPllFreq(kCLOCK_PllEnet);
420             break;
421         case kCLOCK_EnetPll1Clk:
422             freq = CLOCK_GetPllFreq(kCLOCK_PllEnet25M);
423             break;
424         case kCLOCK_AudioPllClk:
425             freq = CLOCK_GetPllFreq(kCLOCK_PllAudio);
426             break;
427         case kCLOCK_VideoPllClk:
428             freq = CLOCK_GetPllFreq(kCLOCK_PllVideo);
429             break;
430         default:
431             freq = 0U;
432             break;
433     }
434 
435     return freq;
436 }
437 
438 /*!
439  * brief Gets the frequency of selected clock root.
440  *
441  * param clockRoot The clock root used to get the frequency, please refer to @ref clock_root_t.
442  * return The frequency of selected clock root.
443  */
CLOCK_GetClockRootFreq(clock_root_t clockRoot)444 uint32_t CLOCK_GetClockRootFreq(clock_root_t clockRoot)
445 {
446     static const clock_name_t clockRootSourceArray[][6]  = CLOCK_ROOT_SOUCE;
447     static const clock_mux_t clockRootMuxTupleArray[]    = CLOCK_ROOT_MUX_TUPLE;
448     static const clock_div_t clockRootDivTupleArray[][2] = CLOCK_ROOT_DIV_TUPLE;
449     uint32_t freq                                        = 0UL;
450     clock_mux_t clockRootMuxTuple                        = clockRootMuxTupleArray[(uint8_t)clockRoot];
451     clock_div_t clockRootPreDivTuple                     = clockRootDivTupleArray[(uint8_t)clockRoot][0];
452     clock_div_t clockRootPostDivTuple                    = clockRootDivTupleArray[(uint8_t)clockRoot][1];
453     uint32_t clockRootMuxValue = (CCM_TUPLE_REG(CCM, clockRootMuxTuple) & CCM_TUPLE_MASK(clockRootMuxTuple)) >>
454                                  CCM_TUPLE_SHIFT(clockRootMuxTuple);
455     clock_name_t clockSourceName;
456 
457     clockSourceName = clockRootSourceArray[(uint8_t)clockRoot][clockRootMuxValue];
458 
459     assert(clockSourceName != kCLOCK_NoneName);
460 
461     freq = CLOCK_GetFreq(clockSourceName);
462 
463     if (clockRootPreDivTuple != kCLOCK_NonePreDiv)
464     {
465         freq /= ((CCM_TUPLE_REG(CCM, clockRootPreDivTuple) & CCM_TUPLE_MASK(clockRootPreDivTuple)) >>
466                  CCM_TUPLE_SHIFT(clockRootPreDivTuple)) +
467                 1UL;
468     }
469 
470     freq /= ((CCM_TUPLE_REG(CCM, clockRootPostDivTuple) & CCM_TUPLE_MASK(clockRootPostDivTuple)) >>
471              CCM_TUPLE_SHIFT(clockRootPostDivTuple)) +
472             1UL;
473 
474     return freq;
475 }
476 
477 /*! brief Enable USB HS clock.
478  *
479  * This function only enables the access to USB HS prepheral, upper layer
480  * should first call the ref CLOCK_EnableUsbhs0PhyPllClock to enable the PHY
481  * clock to use USB HS.
482  *
483  * param src  USB HS does not care about the clock source, here must be ref kCLOCK_UsbSrcUnused.
484  * param freq USB HS does not care about the clock source, so this parameter is ignored.
485  * retval true The clock is set successfully.
486  * retval false The clock source is invalid to get proper USB HS clock.
487  */
CLOCK_EnableUsbhs0Clock(clock_usb_src_t src,uint32_t freq)488 bool CLOCK_EnableUsbhs0Clock(clock_usb_src_t src, uint32_t freq)
489 {
490     uint32_t i;
491     CCM->CCGR6 |= CCM_CCGR6_CG0_MASK;
492     USB1->USBCMD |= USBHS_USBCMD_RST_MASK;
493 
494     /* Add a delay between RST and RS so make sure there is a DP pullup sequence*/
495     for (i = 0; i < 400000U; i++)
496     {
497         __ASM("nop");
498     }
499     PMU->REG_3P0 = (PMU->REG_3P0 & (~PMU_REG_3P0_OUTPUT_TRG_MASK)) |
500                    (PMU_REG_3P0_OUTPUT_TRG(0x17) | PMU_REG_3P0_ENABLE_LINREG_MASK);
501     return true;
502 }
503 
504 /*! brief Enable USB HS clock.
505  *
506  * This function only enables the access to USB HS prepheral, upper layer
507  * should first call the ref CLOCK_EnableUsbhs0PhyPllClock to enable the PHY
508  * clock to use USB HS.
509  *
510  * param src  USB HS does not care about the clock source, here must be ref kCLOCK_UsbSrcUnused.
511  * param freq USB HS does not care about the clock source, so this parameter is ignored.
512  * retval true The clock is set successfully.
513  * retval false The clock source is invalid to get proper USB HS clock.
514  */
CLOCK_EnableUsbhs1Clock(clock_usb_src_t src,uint32_t freq)515 bool CLOCK_EnableUsbhs1Clock(clock_usb_src_t src, uint32_t freq)
516 {
517     uint32_t i = 0;
518     CCM->CCGR6 |= CCM_CCGR6_CG0_MASK;
519     USB2->USBCMD |= USBHS_USBCMD_RST_MASK;
520 
521     /* Add a delay between RST and RS so make sure there is a DP pullup sequence*/
522     for (i = 0; i < 400000U; i++)
523     {
524         __ASM("nop");
525     }
526     PMU->REG_3P0 = (PMU->REG_3P0 & (~PMU_REG_3P0_OUTPUT_TRG_MASK)) |
527                    (PMU_REG_3P0_OUTPUT_TRG(0x17) | PMU_REG_3P0_ENABLE_LINREG_MASK);
528     return true;
529 }
530 
531 /*! brief Enable USB HS PHY PLL clock.
532  *
533  * This function enables the internal 480MHz USB PHY PLL clock.
534  *
535  * param src  USB HS PHY PLL clock source.
536  * param freq The frequency specified by src.
537  * retval true The clock is set successfully.
538  * retval false The clock source is invalid to get proper USB HS clock.
539  */
CLOCK_EnableUsbhs0PhyPllClock(clock_usb_phy_src_t src,uint32_t freq)540 bool CLOCK_EnableUsbhs0PhyPllClock(clock_usb_phy_src_t src, uint32_t freq)
541 {
542     static const clock_usb_pll_config_t g_ccmConfigUsbPll = {.loopDivider = 0U};
543     if ((CCM_ANALOG->PLL_USB1 & CCM_ANALOG_PLL_USB1_ENABLE_MASK) != 0U)
544     {
545         CCM_ANALOG->PLL_USB1 |= CCM_ANALOG_PLL_USB1_EN_USB_CLKS_MASK;
546     }
547     else
548     {
549         CLOCK_InitUsb1Pll(&g_ccmConfigUsbPll);
550     }
551     USBPHY1->CTRL &= ~USBPHY_CTRL_SFTRST_MASK; /* release PHY from reset */
552     USBPHY1->CTRL &= ~USBPHY_CTRL_CLKGATE_MASK;
553 
554     USBPHY1->PWD = 0;
555     USBPHY1->CTRL |= USBPHY_CTRL_ENAUTOCLR_PHY_PWD_MASK | USBPHY_CTRL_ENAUTOCLR_CLKGATE_MASK |
556                      USBPHY_CTRL_ENUTMILEVEL2_MASK | USBPHY_CTRL_ENUTMILEVEL3_MASK;
557     return true;
558 }
559 
560 /*! brief Disable USB HS PHY PLL clock.
561  *
562  * This function disables USB HS PHY PLL clock.
563  */
CLOCK_DisableUsbhs0PhyPllClock(void)564 void CLOCK_DisableUsbhs0PhyPllClock(void)
565 {
566     CCM_ANALOG->PLL_USB1 &= ~CCM_ANALOG_PLL_USB1_EN_USB_CLKS_MASK;
567     USBPHY1->CTRL |= USBPHY_CTRL_CLKGATE_MASK; /* Set to 1U to gate clocks */
568 }
569 
570 /*!
571  * brief Initialize the ARM PLL.
572  *
573  * This function initialize the ARM PLL with specific settings
574  *
575  * param config   configuration to set to PLL.
576  */
CLOCK_InitArmPll(const clock_arm_pll_config_t * config)577 void CLOCK_InitArmPll(const clock_arm_pll_config_t *config)
578 {
579     /* Bypass PLL first */
580     CCM_ANALOG->PLL_ARM = (CCM_ANALOG->PLL_ARM & (~CCM_ANALOG_PLL_ARM_BYPASS_CLK_SRC_MASK)) |
581                           CCM_ANALOG_PLL_ARM_BYPASS_MASK | CCM_ANALOG_PLL_ARM_BYPASS_CLK_SRC(config->src);
582 
583     CCM_ANALOG->PLL_ARM =
584         (CCM_ANALOG->PLL_ARM & (~(CCM_ANALOG_PLL_ARM_DIV_SELECT_MASK | CCM_ANALOG_PLL_ARM_POWERDOWN_MASK))) |
585         CCM_ANALOG_PLL_ARM_ENABLE_MASK | CCM_ANALOG_PLL_ARM_DIV_SELECT(config->loopDivider);
586 
587     while ((CCM_ANALOG->PLL_ARM & CCM_ANALOG_PLL_ARM_LOCK_MASK) == 0UL)
588     {
589     }
590 
591     /* Disable Bypass */
592     CCM_ANALOG->PLL_ARM &= ~CCM_ANALOG_PLL_ARM_BYPASS_MASK;
593 }
594 
595 /*!
596  * brief De-initialize the ARM PLL.
597  */
CLOCK_DeinitArmPll(void)598 void CLOCK_DeinitArmPll(void)
599 {
600     CCM_ANALOG->PLL_ARM = CCM_ANALOG_PLL_ARM_POWERDOWN_MASK;
601 }
602 
603 /*!
604  * brief Initialize the System PLL.
605  *
606  * This function initializes the System PLL with specific settings
607  *
608  * param config Configuration to set to PLL.
609  */
CLOCK_InitSysPll(const clock_sys_pll_config_t * config)610 void CLOCK_InitSysPll(const clock_sys_pll_config_t *config)
611 {
612     /* Bypass PLL first */
613     CCM_ANALOG->PLL_SYS = (CCM_ANALOG->PLL_SYS & (~CCM_ANALOG_PLL_SYS_BYPASS_CLK_SRC_MASK)) |
614                           CCM_ANALOG_PLL_SYS_BYPASS_MASK | CCM_ANALOG_PLL_SYS_BYPASS_CLK_SRC(config->src);
615 
616     CCM_ANALOG->PLL_SYS =
617         (CCM_ANALOG->PLL_SYS & (~(CCM_ANALOG_PLL_SYS_DIV_SELECT_MASK | CCM_ANALOG_PLL_SYS_POWERDOWN_MASK))) |
618         CCM_ANALOG_PLL_SYS_ENABLE_MASK | CCM_ANALOG_PLL_SYS_DIV_SELECT(config->loopDivider);
619 
620     /* Initialize the fractional mode */
621     CCM_ANALOG->PLL_SYS_NUM   = CCM_ANALOG_PLL_SYS_NUM_A(config->numerator);
622     CCM_ANALOG->PLL_SYS_DENOM = CCM_ANALOG_PLL_SYS_DENOM_B(config->denominator);
623 
624     /* Initialize the spread spectrum mode */
625     CCM_ANALOG->PLL_SYS_SS = CCM_ANALOG_PLL_SYS_SS_STEP(config->ss_step) |
626                              CCM_ANALOG_PLL_SYS_SS_ENABLE(config->ss_enable) |
627                              CCM_ANALOG_PLL_SYS_SS_STOP(config->ss_stop);
628 
629     while ((CCM_ANALOG->PLL_SYS & CCM_ANALOG_PLL_SYS_LOCK_MASK) == 0UL)
630     {
631     }
632 
633     /* Disable Bypass */
634     CCM_ANALOG->PLL_SYS &= ~CCM_ANALOG_PLL_SYS_BYPASS_MASK;
635 }
636 
637 /*!
638  * brief De-initialize the System PLL.
639  */
CLOCK_DeinitSysPll(void)640 void CLOCK_DeinitSysPll(void)
641 {
642     CCM_ANALOG->PLL_SYS = CCM_ANALOG_PLL_SYS_POWERDOWN_MASK;
643 }
644 
645 /*!
646  * brief Initialize the USB1 PLL.
647  *
648  * This function initializes the USB1 PLL with specific settings
649  *
650  * param config Configuration to set to PLL.
651  */
CLOCK_InitUsb1Pll(const clock_usb_pll_config_t * config)652 void CLOCK_InitUsb1Pll(const clock_usb_pll_config_t *config)
653 {
654     /* Bypass PLL first */
655     CCM_ANALOG->PLL_USB1 = (CCM_ANALOG->PLL_USB1 & (~CCM_ANALOG_PLL_USB1_BYPASS_CLK_SRC_MASK)) |
656                            CCM_ANALOG_PLL_USB1_BYPASS_MASK | CCM_ANALOG_PLL_USB1_BYPASS_CLK_SRC(config->src);
657 
658     CCM_ANALOG->PLL_USB1 = (CCM_ANALOG->PLL_USB1 & (~CCM_ANALOG_PLL_USB1_DIV_SELECT_MASK)) |
659                            CCM_ANALOG_PLL_USB1_ENABLE_MASK | CCM_ANALOG_PLL_USB1_POWER_MASK |
660                            CCM_ANALOG_PLL_USB1_EN_USB_CLKS_MASK | CCM_ANALOG_PLL_USB1_DIV_SELECT(config->loopDivider);
661 
662     while ((CCM_ANALOG->PLL_USB1 & CCM_ANALOG_PLL_USB1_LOCK_MASK) == 0UL)
663     {
664     }
665 
666     /* Disable Bypass */
667     CCM_ANALOG->PLL_USB1 &= ~CCM_ANALOG_PLL_USB1_BYPASS_MASK;
668 }
669 
670 /*!
671  * brief Deinitialize the USB1 PLL.
672  */
CLOCK_DeinitUsb1Pll(void)673 void CLOCK_DeinitUsb1Pll(void)
674 {
675     CCM_ANALOG->PLL_USB1 = 0U;
676 }
677 
678 /*!
679  * brief Initialize the USB2 PLL.
680  *
681  * This function initializes the USB2 PLL with specific settings
682  *
683  * param config Configuration to set to PLL.
684  */
CLOCK_InitUsb2Pll(const clock_usb_pll_config_t * config)685 void CLOCK_InitUsb2Pll(const clock_usb_pll_config_t *config)
686 {
687     /* Bypass PLL first */
688     CCM_ANALOG->PLL_USB2 = (CCM_ANALOG->PLL_USB2 & (~CCM_ANALOG_PLL_USB2_BYPASS_CLK_SRC_MASK)) |
689                            CCM_ANALOG_PLL_USB2_BYPASS_MASK | CCM_ANALOG_PLL_USB2_BYPASS_CLK_SRC(config->src);
690 
691     CCM_ANALOG->PLL_USB2 = (CCM_ANALOG->PLL_USB2 & (~CCM_ANALOG_PLL_USB2_DIV_SELECT_MASK)) |
692                            CCM_ANALOG_PLL_USB2_ENABLE_MASK | CCM_ANALOG_PLL_USB2_POWER_MASK |
693                            CCM_ANALOG_PLL_USB2_EN_USB_CLKS_MASK | CCM_ANALOG_PLL_USB2_DIV_SELECT(config->loopDivider);
694 
695     while ((CCM_ANALOG->PLL_USB2 & CCM_ANALOG_PLL_USB2_LOCK_MASK) == 0UL)
696     {
697     }
698 
699     /* Disable Bypass */
700     CCM_ANALOG->PLL_USB2 &= ~CCM_ANALOG_PLL_USB2_BYPASS_MASK;
701 }
702 
703 /*!
704  * brief Deinitialize the USB2 PLL.
705  */
CLOCK_DeinitUsb2Pll(void)706 void CLOCK_DeinitUsb2Pll(void)
707 {
708     CCM_ANALOG->PLL_USB2 = 0U;
709 }
710 
711 /*!
712  * brief Initializes the Audio PLL.
713  *
714  * This function initializes the Audio PLL with specific settings
715  *
716  * param config Configuration to set to PLL.
717  */
CLOCK_InitAudioPll(const clock_audio_pll_config_t * config)718 void CLOCK_InitAudioPll(const clock_audio_pll_config_t *config)
719 {
720     uint32_t pllAudio;
721     uint32_t misc2 = 0;
722 
723     /* Bypass PLL first */
724     CCM_ANALOG->PLL_AUDIO = (CCM_ANALOG->PLL_AUDIO & (~CCM_ANALOG_PLL_AUDIO_BYPASS_CLK_SRC_MASK)) |
725                             CCM_ANALOG_PLL_AUDIO_BYPASS_MASK | CCM_ANALOG_PLL_AUDIO_BYPASS_CLK_SRC(config->src);
726 
727     CCM_ANALOG->PLL_AUDIO_NUM   = CCM_ANALOG_PLL_AUDIO_NUM_A(config->numerator);
728     CCM_ANALOG->PLL_AUDIO_DENOM = CCM_ANALOG_PLL_AUDIO_DENOM_B(config->denominator);
729 
730     /*
731      * Set post divider:
732      *
733      * ------------------------------------------------------------------------
734      * | config->postDivider | PLL_AUDIO[POST_DIV_SELECT]  | MISC2[AUDIO_DIV] |
735      * ------------------------------------------------------------------------
736      * |         1           |            2                |        0         |
737      * ------------------------------------------------------------------------
738      * |         2           |            1                |        0         |
739      * ------------------------------------------------------------------------
740      * |         4           |            2                |        3         |
741      * ------------------------------------------------------------------------
742      * |         8           |            1                |        3         |
743      * ------------------------------------------------------------------------
744      * |         16          |            0                |        3         |
745      * ------------------------------------------------------------------------
746      */
747     pllAudio =
748         (CCM_ANALOG->PLL_AUDIO & (~(CCM_ANALOG_PLL_AUDIO_DIV_SELECT_MASK | CCM_ANALOG_PLL_AUDIO_POWERDOWN_MASK))) |
749         CCM_ANALOG_PLL_AUDIO_ENABLE_MASK | CCM_ANALOG_PLL_AUDIO_DIV_SELECT(config->loopDivider);
750 
751     switch (config->postDivider)
752     {
753         case 16:
754             pllAudio |= CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(0);
755             misc2 = CCM_ANALOG_MISC2_AUDIO_DIV_MSB_MASK | CCM_ANALOG_MISC2_AUDIO_DIV_LSB_MASK;
756             break;
757 
758         case 8:
759             pllAudio |= CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(1);
760             misc2 = CCM_ANALOG_MISC2_AUDIO_DIV_MSB_MASK | CCM_ANALOG_MISC2_AUDIO_DIV_LSB_MASK;
761             break;
762 
763         case 4:
764             pllAudio |= CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(2);
765             misc2 = CCM_ANALOG_MISC2_AUDIO_DIV_MSB_MASK | CCM_ANALOG_MISC2_AUDIO_DIV_LSB_MASK;
766             break;
767 
768         case 2:
769             pllAudio |= CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(1);
770             break;
771 
772         default:
773             pllAudio |= CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(2);
774             break;
775     }
776 
777     CCM_ANALOG->MISC2 =
778         (CCM_ANALOG->MISC2 & ~(CCM_ANALOG_MISC2_AUDIO_DIV_LSB_MASK | CCM_ANALOG_MISC2_AUDIO_DIV_MSB_MASK)) | misc2;
779 
780     CCM_ANALOG->PLL_AUDIO = pllAudio;
781 
782     while ((CCM_ANALOG->PLL_AUDIO & CCM_ANALOG_PLL_AUDIO_LOCK_MASK) == 0UL)
783     {
784     }
785 
786     /* Disable Bypass */
787     CCM_ANALOG->PLL_AUDIO &= ~CCM_ANALOG_PLL_AUDIO_BYPASS_MASK;
788 }
789 
790 /*!
791  * brief De-initialize the Audio PLL.
792  */
CLOCK_DeinitAudioPll(void)793 void CLOCK_DeinitAudioPll(void)
794 {
795     CCM_ANALOG->PLL_AUDIO = (uint32_t)CCM_ANALOG_PLL_AUDIO_POWERDOWN_MASK;
796 }
797 
798 /*!
799  * brief Initialize the video PLL.
800  *
801  * This function configures the Video PLL with specific settings
802  *
803  * param config   configuration to set to PLL.
804  */
CLOCK_InitVideoPll(const clock_video_pll_config_t * config)805 void CLOCK_InitVideoPll(const clock_video_pll_config_t *config)
806 {
807     uint32_t pllVideo;
808     uint32_t misc2 = 0;
809 
810     /* Bypass PLL first */
811     CCM_ANALOG->PLL_VIDEO = (CCM_ANALOG->PLL_VIDEO & (~CCM_ANALOG_PLL_VIDEO_BYPASS_CLK_SRC_MASK)) |
812                             CCM_ANALOG_PLL_VIDEO_BYPASS_MASK | CCM_ANALOG_PLL_VIDEO_BYPASS_CLK_SRC(config->src);
813 
814     CCM_ANALOG->PLL_VIDEO_NUM   = CCM_ANALOG_PLL_VIDEO_NUM_A(config->numerator);
815     CCM_ANALOG->PLL_VIDEO_DENOM = CCM_ANALOG_PLL_VIDEO_DENOM_B(config->denominator);
816 
817     /*
818      * Set post divider:
819      *
820      * ------------------------------------------------------------------------
821      * | config->postDivider | PLL_VIDEO[POST_DIV_SELECT]  | MISC2[VIDEO_DIV] |
822      * ------------------------------------------------------------------------
823      * |         1           |            2                |        0         |
824      * ------------------------------------------------------------------------
825      * |         2           |            1                |        0         |
826      * ------------------------------------------------------------------------
827      * |         4           |            2                |        3         |
828      * ------------------------------------------------------------------------
829      * |         8           |            1                |        3         |
830      * ------------------------------------------------------------------------
831      * |         16          |            0                |        3         |
832      * ------------------------------------------------------------------------
833      */
834     pllVideo =
835         (CCM_ANALOG->PLL_VIDEO & (~(CCM_ANALOG_PLL_VIDEO_DIV_SELECT_MASK | CCM_ANALOG_PLL_VIDEO_POWERDOWN_MASK))) |
836         CCM_ANALOG_PLL_VIDEO_ENABLE_MASK | CCM_ANALOG_PLL_VIDEO_DIV_SELECT(config->loopDivider);
837 
838     switch (config->postDivider)
839     {
840         case 16:
841             pllVideo |= CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(0);
842             misc2 = CCM_ANALOG_MISC2_VIDEO_DIV(3);
843             break;
844 
845         case 8:
846             pllVideo |= CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(1);
847             misc2 = CCM_ANALOG_MISC2_VIDEO_DIV(3);
848             break;
849 
850         case 4:
851             pllVideo |= CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(2);
852             misc2 = CCM_ANALOG_MISC2_VIDEO_DIV(3);
853             break;
854 
855         case 2:
856             pllVideo |= CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(1);
857             break;
858 
859         default:
860             pllVideo |= CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(2);
861             break;
862     }
863 
864     CCM_ANALOG->MISC2 = (CCM_ANALOG->MISC2 & ~CCM_ANALOG_MISC2_VIDEO_DIV_MASK) | misc2;
865 
866     CCM_ANALOG->PLL_VIDEO = pllVideo;
867 
868     while ((CCM_ANALOG->PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_LOCK_MASK) == 0UL)
869     {
870     }
871 
872     /* Disable Bypass */
873     CCM_ANALOG->PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_BYPASS_MASK;
874 }
875 
876 /*!
877  * brief De-initialize the Video PLL.
878  */
CLOCK_DeinitVideoPll(void)879 void CLOCK_DeinitVideoPll(void)
880 {
881     CCM_ANALOG->PLL_VIDEO = CCM_ANALOG_PLL_VIDEO_POWERDOWN_MASK;
882 }
883 
884 /*!
885  * brief Initialize the ENET PLL.
886  *
887  * This function initializes the ENET PLL with specific settings.
888  *
889  * param config Configuration to set to PLL.
890  */
CLOCK_InitEnetPll(const clock_enet_pll_config_t * config)891 void CLOCK_InitEnetPll(const clock_enet_pll_config_t *config)
892 {
893     uint32_t enet_pll = CCM_ANALOG_PLL_ENET_DIV_SELECT(config->loopDivider);
894 
895     CCM_ANALOG->PLL_ENET = (CCM_ANALOG->PLL_ENET & (~CCM_ANALOG_PLL_ENET_BYPASS_CLK_SRC_MASK)) |
896                            CCM_ANALOG_PLL_ENET_BYPASS_MASK | CCM_ANALOG_PLL_ENET_BYPASS_CLK_SRC(config->src);
897 
898     if (config->enableClkOutput)
899     {
900         enet_pll |= CCM_ANALOG_PLL_ENET_ENABLE_MASK;
901     }
902 
903     if (config->enableClkOutput25M)
904     {
905         enet_pll |= CCM_ANALOG_PLL_ENET_ENET_25M_REF_EN_MASK;
906     }
907 
908     CCM_ANALOG->PLL_ENET =
909         (CCM_ANALOG->PLL_ENET & (~(CCM_ANALOG_PLL_ENET_DIV_SELECT_MASK | CCM_ANALOG_PLL_ENET_POWERDOWN_MASK))) |
910         enet_pll;
911 
912     /* Wait for stable */
913     while ((CCM_ANALOG->PLL_ENET & CCM_ANALOG_PLL_ENET_LOCK_MASK) == 0UL)
914     {
915     }
916 
917     /* Disable Bypass */
918     CCM_ANALOG->PLL_ENET &= ~CCM_ANALOG_PLL_ENET_BYPASS_MASK;
919 }
920 
921 /*!
922  * brief Deinitialize the ENET PLL.
923  *
924  * This function disables the ENET PLL.
925  */
CLOCK_DeinitEnetPll(void)926 void CLOCK_DeinitEnetPll(void)
927 {
928     CCM_ANALOG->PLL_ENET = CCM_ANALOG_PLL_ENET_POWERDOWN_MASK;
929 }
930 
931 /*!
932  * brief Get current PLL output frequency.
933  *
934  * This function get current output frequency of specific PLL
935  *
936  * param pll   pll name to get frequency.
937  * return The PLL output frequency in hertz.
938  */
CLOCK_GetPllFreq(clock_pll_t pll)939 uint32_t CLOCK_GetPllFreq(clock_pll_t pll)
940 {
941     uint32_t freq;
942     uint32_t divSelect;
943     clock_64b_t freqTmp;
944 
945     static const uint32_t enetRefClkFreq[] = {
946         25000000U,  /* 25M */
947         50000000U,  /* 50M */
948         100000000U, /* 100M */
949         125000000U  /* 125M */
950     };
951 
952     /* check if PLL is enabled */
953     if (!CLOCK_IsPllEnabled(CCM_ANALOG, pll))
954     {
955         return 0U;
956     }
957 
958     /* get pll reference clock */
959     freq = CLOCK_GetPllBypassRefClk(CCM_ANALOG, pll);
960 
961     /* check if pll is bypassed */
962     if (CLOCK_IsPllBypassed(CCM_ANALOG, pll))
963     {
964         return freq;
965     }
966 
967     switch (pll)
968     {
969         case kCLOCK_PllArm:
970             freq = ((freq * ((CCM_ANALOG->PLL_ARM & CCM_ANALOG_PLL_ARM_DIV_SELECT_MASK) >>
971                              CCM_ANALOG_PLL_ARM_DIV_SELECT_SHIFT)) >>
972                     1U);
973             break;
974         case kCLOCK_PllSys:
975             /* PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM). */
976             freqTmp = ((clock_64b_t)freq * ((clock_64b_t)(CCM_ANALOG->PLL_SYS_NUM)));
977             freqTmp /= ((clock_64b_t)(CCM_ANALOG->PLL_SYS_DENOM));
978 
979             if ((CCM_ANALOG->PLL_SYS & CCM_ANALOG_PLL_SYS_DIV_SELECT_MASK) != 0U)
980             {
981                 freq *= 22U;
982             }
983             else
984             {
985                 freq *= 20U;
986             }
987 
988             freq += (uint32_t)freqTmp;
989             break;
990 
991         case kCLOCK_PllUsb1:
992             freq = (freq * (((CCM_ANALOG->PLL_USB1 & CCM_ANALOG_PLL_USB1_DIV_SELECT_MASK) != 0UL) ? 22U : 20U));
993             break;
994 
995         case kCLOCK_PllAudio:
996             /* PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM). */
997             divSelect =
998                 (CCM_ANALOG->PLL_AUDIO & CCM_ANALOG_PLL_AUDIO_DIV_SELECT_MASK) >> CCM_ANALOG_PLL_AUDIO_DIV_SELECT_SHIFT;
999 
1000             freqTmp = ((clock_64b_t)freq * ((clock_64b_t)(CCM_ANALOG->PLL_AUDIO_NUM)));
1001             freqTmp /= ((clock_64b_t)(CCM_ANALOG->PLL_AUDIO_DENOM));
1002 
1003             freq = freq * divSelect + (uint32_t)freqTmp;
1004 
1005             /* AUDIO PLL output = PLL output frequency / POSTDIV. */
1006 
1007             /*
1008              * Post divider:
1009              *
1010              * PLL_AUDIO[POST_DIV_SELECT]:
1011              * 0x00: 4
1012              * 0x01: 2
1013              * 0x02: 1
1014              *
1015              * MISC2[AUDO_DIV]:
1016              * 0x00: 1
1017              * 0x01: 2
1018              * 0x02: 1
1019              * 0x03: 4
1020              */
1021             switch (CCM_ANALOG->PLL_AUDIO & CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT_MASK)
1022             {
1023                 case CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(0U):
1024                     freq = freq >> 2U;
1025                     break;
1026 
1027                 case CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(1U):
1028                     freq = freq >> 1U;
1029                     break;
1030 
1031                 case CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(2U):
1032                     freq = freq >> 0U;
1033                     break;
1034 
1035                 default:
1036                     assert(false);
1037                     break;
1038             }
1039 
1040             switch (CCM_ANALOG->MISC2 & (CCM_ANALOG_MISC2_AUDIO_DIV_MSB_MASK | CCM_ANALOG_MISC2_AUDIO_DIV_LSB_MASK))
1041             {
1042                 case CCM_ANALOG_MISC2_AUDIO_DIV_MSB(1) | CCM_ANALOG_MISC2_AUDIO_DIV_LSB(1):
1043                     freq >>= 2U;
1044                     break;
1045 
1046                 case CCM_ANALOG_MISC2_AUDIO_DIV_MSB(0) | CCM_ANALOG_MISC2_AUDIO_DIV_LSB(1):
1047                     freq >>= 1U;
1048                     break;
1049 
1050                 case CCM_ANALOG_MISC2_AUDIO_DIV_MSB(0) | CCM_ANALOG_MISC2_AUDIO_DIV_LSB(0):
1051                 case CCM_ANALOG_MISC2_AUDIO_DIV_MSB(1) | CCM_ANALOG_MISC2_AUDIO_DIV_LSB(0):
1052                     freq >>= 0U;
1053                     break;
1054 
1055                 default:
1056                     assert(false);
1057                     break;
1058             }
1059             break;
1060 
1061         case kCLOCK_PllVideo:
1062             /* PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM). */
1063             divSelect =
1064                 (CCM_ANALOG->PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_DIV_SELECT_MASK) >> CCM_ANALOG_PLL_VIDEO_DIV_SELECT_SHIFT;
1065 
1066             freqTmp = ((clock_64b_t)freq * ((clock_64b_t)(CCM_ANALOG->PLL_VIDEO_NUM)));
1067             freqTmp /= ((clock_64b_t)(CCM_ANALOG->PLL_VIDEO_DENOM));
1068             freq = freq * divSelect + (uint32_t)freqTmp;
1069 
1070             /* VIDEO PLL output = PLL output frequency / POSTDIV. */
1071 
1072             /*
1073              * Post divider:
1074              *
1075              * PLL_VIDEO[POST_DIV_SELECT]:
1076              * 0x00: 4
1077              * 0x01: 2
1078              * 0x02: 1
1079              *
1080              * MISC2[VIDEO_DIV]:
1081              * 0x00: 1
1082              * 0x01: 2
1083              * 0x02: 1
1084              * 0x03: 4
1085              */
1086             switch (CCM_ANALOG->PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT_MASK)
1087             {
1088                 case CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(0U):
1089                     freq = freq >> 2U;
1090                     break;
1091 
1092                 case CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(1U):
1093                     freq = freq >> 1U;
1094                     break;
1095 
1096                 case CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(2U):
1097                     freq = freq >> 0U;
1098                     break;
1099 
1100                 default:
1101                     assert(false);
1102                     break;
1103             }
1104 
1105             switch (CCM_ANALOG->MISC2 & CCM_ANALOG_MISC2_VIDEO_DIV_MASK)
1106             {
1107                 case CCM_ANALOG_MISC2_VIDEO_DIV(3U):
1108                     freq >>= 2U;
1109                     break;
1110 
1111                 case CCM_ANALOG_MISC2_VIDEO_DIV(1U):
1112                     freq >>= 1U;
1113                     break;
1114 
1115                 case CCM_ANALOG_MISC2_VIDEO_DIV(0U):
1116                 case CCM_ANALOG_MISC2_VIDEO_DIV(2U):
1117                     freq >>= 0U;
1118                     break;
1119 
1120                 default:
1121                     assert(false);
1122                     break;
1123             }
1124             break;
1125         case kCLOCK_PllEnet:
1126             divSelect =
1127                 (CCM_ANALOG->PLL_ENET & CCM_ANALOG_PLL_ENET_DIV_SELECT_MASK) >> CCM_ANALOG_PLL_ENET_DIV_SELECT_SHIFT;
1128             freq = enetRefClkFreq[divSelect];
1129             break;
1130 
1131         case kCLOCK_PllEnet25M:
1132             /* ref_enetpll1 if fixed at 25MHz. */
1133             freq = 25000000UL;
1134             break;
1135 
1136         case kCLOCK_PllUsb2:
1137             freq = (freq * (((CCM_ANALOG->PLL_USB2 & CCM_ANALOG_PLL_USB2_DIV_SELECT_MASK) != 0U) ? 22U : 20U));
1138             break;
1139         default:
1140             freq = 0U;
1141             break;
1142     }
1143 
1144     return freq;
1145 }
1146 
1147 /*!
1148  * brief Initialize the System PLL PFD.
1149  *
1150  * This function initializes the System PLL PFD. During new value setting,
1151  * the clock output is disabled to prevent glitch.
1152  *
1153  * param pfd Which PFD clock to enable.
1154  * param pfdFrac The PFD FRAC value.
1155  * note It is recommended that PFD settings are kept between 12-35.
1156  */
CLOCK_InitSysPfd(clock_pfd_t pfd,uint8_t pfdFrac)1157 void CLOCK_InitSysPfd(clock_pfd_t pfd, uint8_t pfdFrac)
1158 {
1159     uint32_t pfdIndex = (uint32_t)pfd;
1160     uint32_t pfd528;
1161 
1162     pfd528 = CCM_ANALOG->PFD_528 &
1163              ~(((uint32_t)((uint32_t)CCM_ANALOG_PFD_528_PFD0_CLKGATE_MASK | CCM_ANALOG_PFD_528_PFD0_FRAC_MASK)
1164                 << (8UL * pfdIndex)));
1165 
1166     /* Disable the clock output first. */
1167     CCM_ANALOG->PFD_528 = pfd528 | ((uint32_t)CCM_ANALOG_PFD_528_PFD0_CLKGATE_MASK << (8UL * pfdIndex));
1168 
1169     /* Set the new value and enable output. */
1170     CCM_ANALOG->PFD_528 = pfd528 | (CCM_ANALOG_PFD_528_PFD0_FRAC(pfdFrac) << (8UL * pfdIndex));
1171 }
1172 
1173 /*!
1174  * brief De-initialize the System PLL PFD.
1175  *
1176  * This function disables the System PLL PFD.
1177  *
1178  * param pfd Which PFD clock to disable.
1179  */
CLOCK_DeinitSysPfd(clock_pfd_t pfd)1180 void CLOCK_DeinitSysPfd(clock_pfd_t pfd)
1181 {
1182     CCM_ANALOG->PFD_528 |= (uint32_t)CCM_ANALOG_PFD_528_PFD0_CLKGATE_MASK << (8U * (uint8_t)pfd);
1183 }
1184 
1185 /*!
1186  * brief Check if Sys PFD is enabled
1187  *
1188  * param pfd PFD control name
1189  * return PFD bypass status.
1190  *         - true: power on.
1191  *         - false: power off.
1192  */
CLOCK_IsSysPfdEnabled(clock_pfd_t pfd)1193 bool CLOCK_IsSysPfdEnabled(clock_pfd_t pfd)
1194 {
1195     return ((CCM_ANALOG->PFD_528 & (uint32_t)CCM_ANALOG_PFD_528_PFD0_CLKGATE_MASK << (8UL * (uint8_t)pfd)) == 0U);
1196 }
1197 
1198 /*!
1199  * brief Initialize the USB1 PLL PFD.
1200  *
1201  * This function initializes the USB1 PLL PFD. During new value setting,
1202  * the clock output is disabled to prevent glitch.
1203  *
1204  * param pfd Which PFD clock to enable.
1205  * param pfdFrac The PFD FRAC value.
1206  * note It is recommended that PFD settings are kept between 12-35.
1207  */
CLOCK_InitUsb1Pfd(clock_pfd_t pfd,uint8_t pfdFrac)1208 void CLOCK_InitUsb1Pfd(clock_pfd_t pfd, uint8_t pfdFrac)
1209 {
1210     uint32_t pfdIndex = (uint32_t)pfd;
1211     uint32_t pfd480;
1212 
1213     pfd480 = CCM_ANALOG->PFD_480 &
1214              ~(((uint32_t)((uint32_t)CCM_ANALOG_PFD_480_PFD0_CLKGATE_MASK | CCM_ANALOG_PFD_480_PFD0_FRAC_MASK)
1215                 << (8UL * pfdIndex)));
1216 
1217     /* Disable the clock output first. */
1218     CCM_ANALOG->PFD_480 = pfd480 | ((uint32_t)CCM_ANALOG_PFD_480_PFD0_CLKGATE_MASK << (8UL * pfdIndex));
1219 
1220     /* Set the new value and enable output. */
1221     CCM_ANALOG->PFD_480 = pfd480 | (CCM_ANALOG_PFD_480_PFD0_FRAC(pfdFrac) << (8UL * pfdIndex));
1222 }
1223 
1224 /*!
1225  * brief De-initialize the USB1 PLL PFD.
1226  *
1227  * This function disables the USB1 PLL PFD.
1228  *
1229  * param pfd Which PFD clock to disable.
1230  */
CLOCK_DeinitUsb1Pfd(clock_pfd_t pfd)1231 void CLOCK_DeinitUsb1Pfd(clock_pfd_t pfd)
1232 {
1233     CCM_ANALOG->PFD_480 |= (uint32_t)CCM_ANALOG_PFD_480_PFD0_CLKGATE_MASK << (8UL * (uint8_t)pfd);
1234 }
1235 
1236 /*!
1237  * brief Check if Usb1 PFD is enabled
1238  *
1239  * param pfd PFD control name.
1240  * return PFD bypass status.
1241  *         - true: power on.
1242  *         - false: power off.
1243  */
CLOCK_IsUsb1PfdEnabled(clock_pfd_t pfd)1244 bool CLOCK_IsUsb1PfdEnabled(clock_pfd_t pfd)
1245 {
1246     return ((CCM_ANALOG->PFD_480 & (uint32_t)CCM_ANALOG_PFD_480_PFD0_CLKGATE_MASK << (8UL * (uint8_t)pfd)) == 0U);
1247 }
1248 
1249 /*!
1250  * brief Get current System PLL PFD output frequency.
1251  *
1252  * This function get current output frequency of specific System PLL PFD
1253  *
1254  * param pfd   pfd name to get frequency.
1255  * return The PFD output frequency in hertz.
1256  */
CLOCK_GetSysPfdFreq(clock_pfd_t pfd)1257 uint32_t CLOCK_GetSysPfdFreq(clock_pfd_t pfd)
1258 {
1259     uint32_t freq = CLOCK_GetPllFreq(kCLOCK_PllSys);
1260     uint64_t tmp64 = (uint64_t)freq * 18UL;
1261 
1262     switch (pfd)
1263     {
1264         case kCLOCK_Pfd0:
1265             freq = (uint32_t)(tmp64 / (uint64_t)((CCM_ANALOG->PFD_528 & CCM_ANALOG_PFD_528_PFD0_FRAC_MASK) >> CCM_ANALOG_PFD_528_PFD0_FRAC_SHIFT));
1266             break;
1267 
1268         case kCLOCK_Pfd1:
1269             freq = (uint32_t)(tmp64 / (uint64_t)((CCM_ANALOG->PFD_528 & CCM_ANALOG_PFD_528_PFD1_FRAC_MASK) >> CCM_ANALOG_PFD_528_PFD1_FRAC_SHIFT));
1270             break;
1271 
1272         case kCLOCK_Pfd2:
1273             freq = (uint32_t)(tmp64 / (uint64_t)((CCM_ANALOG->PFD_528 & CCM_ANALOG_PFD_528_PFD2_FRAC_MASK) >> CCM_ANALOG_PFD_528_PFD2_FRAC_SHIFT));
1274             break;
1275 
1276         case kCLOCK_Pfd3:
1277             freq = (uint32_t)(tmp64 / (uint64_t)((CCM_ANALOG->PFD_528 & CCM_ANALOG_PFD_528_PFD3_FRAC_MASK) >> CCM_ANALOG_PFD_528_PFD3_FRAC_SHIFT));
1278             break;
1279 
1280         default:
1281             freq = 0U;
1282             break;
1283     }
1284 
1285     return freq;
1286 }
1287 
1288 /*!
1289  * brief Get current USB1 PLL PFD output frequency.
1290  *
1291  * This function get current output frequency of specific USB1 PLL PFD
1292  *
1293  * param pfd   pfd name to get frequency.
1294  * return The PFD output frequency in hertz.
1295  */
CLOCK_GetUsb1PfdFreq(clock_pfd_t pfd)1296 uint32_t CLOCK_GetUsb1PfdFreq(clock_pfd_t pfd)
1297 {
1298     uint32_t freq = CLOCK_GetPllFreq(kCLOCK_PllUsb1);
1299     uint64_t tmp64 = (uint64_t)freq * 18UL;
1300 
1301     switch (pfd)
1302     {
1303         case kCLOCK_Pfd0:
1304             freq = (uint32_t)(tmp64 / (uint64_t)((CCM_ANALOG->PFD_480 & CCM_ANALOG_PFD_480_PFD0_FRAC_MASK) >> CCM_ANALOG_PFD_480_PFD0_FRAC_SHIFT));
1305             break;
1306 
1307         case kCLOCK_Pfd1:
1308             freq = (uint32_t)(tmp64 / (uint64_t)((CCM_ANALOG->PFD_480 & CCM_ANALOG_PFD_480_PFD1_FRAC_MASK) >> CCM_ANALOG_PFD_480_PFD1_FRAC_SHIFT));
1309             break;
1310 
1311         case kCLOCK_Pfd2:
1312             freq = (uint32_t)(tmp64 / (uint64_t)((CCM_ANALOG->PFD_480 & CCM_ANALOG_PFD_480_PFD2_FRAC_MASK) >> CCM_ANALOG_PFD_480_PFD2_FRAC_SHIFT));
1313             break;
1314 
1315         case kCLOCK_Pfd3:
1316             freq = (uint32_t)(tmp64 / (uint64_t)((CCM_ANALOG->PFD_480 & CCM_ANALOG_PFD_480_PFD3_FRAC_MASK) >> CCM_ANALOG_PFD_480_PFD3_FRAC_SHIFT));
1317             break;
1318 
1319         default:
1320             freq = 0U;
1321             break;
1322     }
1323 
1324     return freq;
1325 }
1326 
1327 /*! brief Enable USB HS PHY PLL clock.
1328  *
1329  * This function enables the internal 480MHz USB PHY PLL clock.
1330  *
1331  * param src  USB HS PHY PLL clock source.
1332  * param freq The frequency specified by src.
1333  * retval true The clock is set successfully.
1334  * retval false The clock source is invalid to get proper USB HS clock.
1335  */
CLOCK_EnableUsbhs1PhyPllClock(clock_usb_phy_src_t src,uint32_t freq)1336 bool CLOCK_EnableUsbhs1PhyPllClock(clock_usb_phy_src_t src, uint32_t freq)
1337 {
1338     static const clock_usb_pll_config_t g_ccmConfigUsbPll = {.loopDivider = 0U};
1339     CLOCK_InitUsb2Pll(&g_ccmConfigUsbPll);
1340     USBPHY2->CTRL &= ~USBPHY_CTRL_SFTRST_MASK; /* release PHY from reset */
1341     USBPHY2->CTRL &= ~USBPHY_CTRL_CLKGATE_MASK;
1342 
1343     USBPHY2->PWD = 0;
1344     USBPHY2->CTRL |= USBPHY_CTRL_ENAUTOCLR_PHY_PWD_MASK | USBPHY_CTRL_ENAUTOCLR_CLKGATE_MASK |
1345                      USBPHY_CTRL_ENUTMILEVEL2_MASK | USBPHY_CTRL_ENUTMILEVEL3_MASK;
1346 
1347     return true;
1348 }
1349 
1350 /*! brief Disable USB HS PHY PLL clock.
1351  *
1352  * This function disables USB HS PHY PLL clock.
1353  */
CLOCK_DisableUsbhs1PhyPllClock(void)1354 void CLOCK_DisableUsbhs1PhyPllClock(void)
1355 {
1356     CCM_ANALOG->PLL_USB2 &= ~CCM_ANALOG_PLL_USB2_EN_USB_CLKS_MASK;
1357     USBPHY2->CTRL |= USBPHY_CTRL_CLKGATE_MASK; /* Set to 1U to gate clocks */
1358 }
1359 
1360 /*!
1361  * brief Set the clock source and the divider of the clock output1.
1362  *
1363  * param selection The clock source to be output, please refer to clock_output1_selection_t.
1364  * param divider The divider of the output clock signal, please refer to clock_output_divider_t.
1365  */
CLOCK_SetClockOutput1(clock_output1_selection_t selection,clock_output_divider_t divider)1366 void CLOCK_SetClockOutput1(clock_output1_selection_t selection, clock_output_divider_t divider)
1367 {
1368     uint32_t tmp32;
1369 
1370     tmp32 = CCM->CCOSR;
1371     if (selection == kCLOCK_DisableClockOutput1)
1372     {
1373         tmp32 &= ~CCM_CCOSR_CLKO1_EN_MASK;
1374     }
1375     else
1376     {
1377         tmp32 |= CCM_CCOSR_CLKO1_EN_MASK;
1378         tmp32 &= ~(CCM_CCOSR_CLKO1_SEL_MASK | CCM_CCOSR_CLKO1_DIV_MASK);
1379         tmp32 |= CCM_CCOSR_CLKO1_SEL(selection) | CCM_CCOSR_CLKO1_DIV(divider);
1380     }
1381     CCM->CCOSR = tmp32;
1382 }
1383 
1384 /*!
1385  * brief Set the clock source and the divider of the clock output2.
1386  *
1387  * param selection The clock source to be output, please refer to clock_output2_selection_t.
1388  * param divider The divider of the output clock signal, please refer to clock_output_divider_t.
1389  */
CLOCK_SetClockOutput2(clock_output2_selection_t selection,clock_output_divider_t divider)1390 void CLOCK_SetClockOutput2(clock_output2_selection_t selection, clock_output_divider_t divider)
1391 {
1392     uint32_t tmp32;
1393 
1394     tmp32 = CCM->CCOSR;
1395     if (selection == kCLOCK_DisableClockOutput2)
1396     {
1397         tmp32 &= CCM_CCOSR_CLKO2_EN_MASK;
1398     }
1399     else
1400     {
1401         tmp32 |= CCM_CCOSR_CLKO2_EN_MASK;
1402         tmp32 &= ~(CCM_CCOSR_CLKO2_SEL_MASK | CCM_CCOSR_CLKO2_DIV_MASK);
1403         tmp32 |= CCM_CCOSR_CLKO2_SEL(selection) | CCM_CCOSR_CLKO2_DIV(divider);
1404     }
1405 
1406     CCM->CCOSR = tmp32;
1407 }
1408 
1409 /*!
1410  * brief Get the frequency of clock output1 clock signal.
1411  *
1412  * return The frequency of clock output1 clock signal.
1413  */
CLOCK_GetClockOutCLKO1Freq(void)1414 uint32_t CLOCK_GetClockOutCLKO1Freq(void)
1415 {
1416     uint32_t freq = 0U;
1417     uint32_t tmp32;
1418 
1419     tmp32 = CCM->CCOSR;
1420 
1421     if ((tmp32 & CCM_CCOSR_CLKO1_EN_MASK) != 0UL)
1422     {
1423         switch ((tmp32 & CCM_CCOSR_CLKO1_SEL_MASK) >> CCM_CCOSR_CLKO1_SEL_SHIFT)
1424         {
1425             case (uint32_t)kCLOCK_OutputPllUsb1:
1426                 freq = CLOCK_GetPllFreq(kCLOCK_PllUsb1) / 2U;
1427                 break;
1428             case (uint32_t)kCLOCK_OutputPllSys:
1429                 freq = CLOCK_GetPllFreq(kCLOCK_PllSys) / 2U;
1430                 break;
1431             case (uint32_t)kCLOCK_OutputPllVideo:
1432                 freq = CLOCK_GetPllFreq(kCLOCK_PllVideo) / 2U;
1433                 break;
1434             case (uint32_t)kCLOCK_OutputSemcClk:
1435                 freq = CLOCK_GetSemcFreq();
1436                 break;
1437             case (uint32_t)kCLOCK_OutputLcdifPixClk:
1438                 freq = CLOCK_GetClockRootFreq(kCLOCK_LcdifClkRoot);
1439                 break;
1440             case (uint32_t)kCLOCK_OutputAhbClk:
1441                 freq = CLOCK_GetAhbFreq();
1442                 break;
1443             case (uint32_t)kCLOCK_OutputIpgClk:
1444                 freq = CLOCK_GetIpgFreq();
1445                 break;
1446             case (uint32_t)kCLOCK_OutputPerClk:
1447                 freq = CLOCK_GetPerClkFreq();
1448                 break;
1449             case (uint32_t)kCLOCK_OutputCkilSyncClk:
1450                 freq = CLOCK_GetRtcFreq();
1451                 break;
1452             case (uint32_t)kCLOCK_OutputPll4MainClk:
1453                 freq = CLOCK_GetPllFreq(kCLOCK_PllAudio);
1454                 break;
1455             default:
1456                 /* This branch should never be hit. */
1457                 break;
1458         }
1459 
1460         freq /= (((tmp32 & CCM_CCOSR_CLKO1_DIV_MASK) >> CCM_CCOSR_CLKO1_DIV_SHIFT) + 1U);
1461     }
1462     else
1463     {
1464         freq = 0UL;
1465     }
1466 
1467     return freq;
1468 }
1469 
1470 /*!
1471  * brief Get the frequency of clock output2 clock signal.
1472  *
1473  * return The frequency of clock output2 clock signal.
1474  */
CLOCK_GetClockOutClkO2Freq(void)1475 uint32_t CLOCK_GetClockOutClkO2Freq(void)
1476 {
1477     uint32_t freq = 0U;
1478     uint32_t tmp32;
1479 
1480     tmp32 = CCM->CCOSR;
1481 
1482     if ((tmp32 & CCM_CCOSR_CLKO2_EN_MASK) != 0UL)
1483     {
1484         switch ((tmp32 & CCM_CCOSR_CLKO2_SEL_MASK) >> CCM_CCOSR_CLKO2_SEL_SHIFT)
1485         {
1486             case (uint32_t)kCLOCK_OutputUsdhc1Clk:
1487                 freq = CLOCK_GetClockRootFreq(kCLOCK_Usdhc1ClkRoot);
1488                 break;
1489             case (uint32_t)kCLOCK_OutputLpi2cClk:
1490                 freq = CLOCK_GetClockRootFreq(kCLOCK_Lpi2cClkRoot);
1491                 break;
1492             case (uint32_t)kCLOCK_OutputCsiClk:
1493                 freq = CLOCK_GetClockRootFreq(kCLOCK_CsiClkRoot);
1494                 break;
1495             case (uint32_t)kCLOCK_OutputOscClk:
1496                 freq = CLOCK_GetOscFreq();
1497                 break;
1498             case (uint32_t)kCLOCK_OutputUsdhc2Clk:
1499                 freq = CLOCK_GetClockRootFreq(kCLOCK_Usdhc2ClkRoot);
1500                 break;
1501             case (uint32_t)kCLOCK_OutputSai1Clk:
1502                 freq = CLOCK_GetClockRootFreq(kCLOCK_Sai1ClkRoot);
1503                 break;
1504             case (uint32_t)kCLOCK_OutputSai2Clk:
1505                 freq = CLOCK_GetClockRootFreq(kCLOCK_Sai2ClkRoot);
1506                 break;
1507             case (uint32_t)kCLOCK_OutputSai3Clk:
1508                 freq = CLOCK_GetClockRootFreq(kCLOCK_Sai3ClkRoot);
1509                 break;
1510             case (uint32_t)kCLOCK_OutputCanClk:
1511                 freq = CLOCK_GetClockRootFreq(kCLOCK_CanClkRoot);
1512                 break;
1513             case (uint32_t)kCLOCK_OutputFlexspiClk:
1514                 freq = CLOCK_GetClockRootFreq(kCLOCK_FlexspiClkRoot);
1515                 break;
1516             case (uint32_t)kCLOCK_OutputUartClk:
1517                 freq = CLOCK_GetClockRootFreq(kCLOCK_UartClkRoot);
1518                 break;
1519             case (uint32_t)kCLOCK_OutputSpdif0Clk:
1520                 freq = CLOCK_GetClockRootFreq(kCLOCK_SpdifClkRoot);
1521                 break;
1522             default:
1523                 /* This branch should never be hit. */
1524                 break;
1525         }
1526 
1527         freq /= (((tmp32 & CCM_CCOSR_CLKO2_DIV_MASK) >> CCM_CCOSR_CLKO2_DIV_SHIFT) + 1U);
1528     }
1529     else
1530     {
1531         freq = 0UL;
1532     }
1533 
1534     return freq;
1535 }
1536