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