1 /*
2  * Copyright 2018 - 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 
308 /*!
309  * brief Gets the PER clock frequency.
310  *
311  * return  The PER clock frequency value in hertz.
312  */
CLOCK_GetPerClkFreq(void)313 uint32_t CLOCK_GetPerClkFreq(void)
314 {
315     uint32_t freq;
316 
317     /* Osc_clk ---> PER Clock*/
318     if ((CCM->CSCMR1 & CCM_CSCMR1_PERCLK_CLK_SEL_MASK) != 0U)
319     {
320         freq = CLOCK_GetOscFreq();
321     }
322     /* Periph_clk ---> AHB Clock ---> IPG Clock ---> PER Clock */
323     else
324     {
325         freq = CLOCK_GetIpgFreq();
326     }
327 
328     freq /= (((CCM->CSCMR1 & CCM_CSCMR1_PERCLK_PODF_MASK) >> CCM_CSCMR1_PERCLK_PODF_SHIFT) + 1U);
329 
330     return freq;
331 }
332 
333 /*!
334  * brief Gets the clock frequency for a specific clock name.
335  *
336  * This function checks the current clock configurations and then calculates
337  * the clock frequency for a specific clock name defined in clock_name_t.
338  *
339  * param clockName Clock names defined in clock_name_t
340  * return Clock frequency value in hertz
341  */
CLOCK_GetFreq(clock_name_t name)342 uint32_t CLOCK_GetFreq(clock_name_t name)
343 {
344     uint32_t freq;
345 
346     switch (name)
347     {
348         case kCLOCK_CpuClk:
349         case kCLOCK_AhbClk:
350             freq = CLOCK_GetAhbFreq();
351             break;
352 
353         case kCLOCK_SemcClk:
354             freq = CLOCK_GetSemcFreq();
355             break;
356 
357         case kCLOCK_IpgClk:
358             freq = CLOCK_GetIpgFreq();
359             break;
360 
361         case kCLOCK_PerClk:
362             freq = CLOCK_GetPerClkFreq();
363             break;
364 
365         case kCLOCK_OscClk:
366             freq = CLOCK_GetOscFreq();
367             break;
368         case kCLOCK_RtcClk:
369             freq = CLOCK_GetRtcFreq();
370             break;
371         case kCLOCK_ArmPllClk:
372             freq = CLOCK_GetPllFreq(kCLOCK_PllArm);
373             break;
374         case kCLOCK_Usb1PllClk:
375             freq = CLOCK_GetPllFreq(kCLOCK_PllUsb1);
376             break;
377         case kCLOCK_Usb1PllPfd0Clk:
378             freq = CLOCK_GetUsb1PfdFreq(kCLOCK_Pfd0);
379             break;
380         case kCLOCK_Usb1PllPfd1Clk:
381             freq = CLOCK_GetUsb1PfdFreq(kCLOCK_Pfd1);
382             break;
383         case kCLOCK_Usb1PllPfd2Clk:
384             freq = CLOCK_GetUsb1PfdFreq(kCLOCK_Pfd2);
385             break;
386         case kCLOCK_Usb1PllPfd3Clk:
387             freq = CLOCK_GetUsb1PfdFreq(kCLOCK_Pfd3);
388             break;
389         case kCLOCK_Usb1SwClk:
390             freq = CLOCK_GetPllUsb1SWFreq();
391             break;
392         case kCLOCK_Usb1Sw120MClk:
393             freq = CLOCK_GetPllUsb1SWFreq() / 4UL;
394             break;
395         case kCLOCK_Usb1Sw60MClk:
396             freq = CLOCK_GetPllUsb1SWFreq() / 8UL;
397             break;
398         case kCLOCK_Usb1Sw80MClk:
399             freq = CLOCK_GetPllUsb1SWFreq() / 6UL;
400             break;
401         case kCLOCK_Usb2PllClk:
402             freq = CLOCK_GetPllFreq(kCLOCK_PllUsb2);
403             break;
404         case kCLOCK_SysPllClk:
405             freq = CLOCK_GetPllFreq(kCLOCK_PllSys);
406             break;
407         case kCLOCK_SysPllPfd0Clk:
408             freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd0);
409             break;
410         case kCLOCK_SysPllPfd1Clk:
411             freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd1);
412             break;
413         case kCLOCK_SysPllPfd2Clk:
414             freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd2);
415             break;
416         case kCLOCK_SysPllPfd3Clk:
417             freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd3);
418             break;
419         case kCLOCK_EnetPll0Clk:
420             freq = CLOCK_GetPllFreq(kCLOCK_PllEnet);
421             break;
422         case kCLOCK_EnetPll1Clk:
423             freq = CLOCK_GetPllFreq(kCLOCK_PllEnet2);
424             break;
425         case kCLOCK_EnetPll2Clk:
426             freq = CLOCK_GetPllFreq(kCLOCK_PllEnet25M);
427             break;
428         case kCLOCK_AudioPllClk:
429             freq = CLOCK_GetPllFreq(kCLOCK_PllAudio);
430             break;
431         case kCLOCK_VideoPllClk:
432             freq = CLOCK_GetPllFreq(kCLOCK_PllVideo);
433             break;
434         default:
435             freq = 0U;
436             break;
437     }
438 
439     return freq;
440 }
441 
442 /*!
443  * brief Gets the frequency of selected clock root.
444  *
445  * param clockRoot The clock root used to get the frequency, please refer to @ref clock_root_t.
446  * return The frequency of selected clock root.
447  */
CLOCK_GetClockRootFreq(clock_root_t clockRoot)448 uint32_t CLOCK_GetClockRootFreq(clock_root_t clockRoot)
449 {
450     static const clock_name_t clockRootSourceArray[][6]  = CLOCK_ROOT_SOUCE;
451     static const clock_mux_t clockRootMuxTupleArray[]    = CLOCK_ROOT_MUX_TUPLE;
452     static const clock_div_t clockRootDivTupleArray[][2] = CLOCK_ROOT_DIV_TUPLE;
453     uint32_t freq                                        = 0UL;
454     clock_mux_t clockRootMuxTuple                        = clockRootMuxTupleArray[(uint8_t)clockRoot];
455     clock_div_t clockRootPreDivTuple                     = clockRootDivTupleArray[(uint8_t)clockRoot][0];
456     clock_div_t clockRootPostDivTuple                    = clockRootDivTupleArray[(uint8_t)clockRoot][1];
457     uint32_t clockRootMuxValue = (CCM_TUPLE_REG(CCM, clockRootMuxTuple) & CCM_TUPLE_MASK(clockRootMuxTuple)) >>
458                                  CCM_TUPLE_SHIFT(clockRootMuxTuple);
459     clock_name_t clockSourceName;
460 
461     clockSourceName = clockRootSourceArray[(uint8_t)clockRoot][clockRootMuxValue];
462 
463     assert(clockSourceName != kCLOCK_NoneName);
464 
465     freq = CLOCK_GetFreq(clockSourceName);
466 
467     if (clockRootPreDivTuple != kCLOCK_NonePreDiv)
468     {
469         freq /= ((CCM_TUPLE_REG(CCM, clockRootPreDivTuple) & CCM_TUPLE_MASK(clockRootPreDivTuple)) >>
470                  CCM_TUPLE_SHIFT(clockRootPreDivTuple)) +
471                 1UL;
472     }
473 
474     freq /= ((CCM_TUPLE_REG(CCM, clockRootPostDivTuple) & CCM_TUPLE_MASK(clockRootPostDivTuple)) >>
475              CCM_TUPLE_SHIFT(clockRootPostDivTuple)) +
476             1UL;
477 
478     return freq;
479 }
480 
481 /*! brief Enable USB HS clock.
482  *
483  * This function only enables the access to USB HS prepheral, upper layer
484  * should first call the ref CLOCK_EnableUsbhs0PhyPllClock to enable the PHY
485  * clock to use USB HS.
486  *
487  * param src  USB HS does not care about the clock source, here must be ref kCLOCK_UsbSrcUnused.
488  * param freq USB HS does not care about the clock source, so this parameter is ignored.
489  * retval true The clock is set successfully.
490  * retval false The clock source is invalid to get proper USB HS clock.
491  */
CLOCK_EnableUsbhs0Clock(clock_usb_src_t src,uint32_t freq)492 bool CLOCK_EnableUsbhs0Clock(clock_usb_src_t src, uint32_t freq)
493 {
494     uint32_t i;
495     CCM->CCGR6 |= CCM_CCGR6_CG0_MASK;
496     USB1->USBCMD |= USBHS_USBCMD_RST_MASK;
497 
498     /* Add a delay between RST and RS so make sure there is a DP pullup sequence*/
499     for (i = 0; i < 400000U; i++)
500     {
501         __ASM("nop");
502     }
503     PMU->REG_3P0 = (PMU->REG_3P0 & (~PMU_REG_3P0_OUTPUT_TRG_MASK)) |
504                    (PMU_REG_3P0_OUTPUT_TRG(0x17) | PMU_REG_3P0_ENABLE_LINREG_MASK);
505     return true;
506 }
507 
508 /*! brief Enable USB HS clock.
509  *
510  * This function only enables the access to USB HS prepheral, upper layer
511  * should first call the ref CLOCK_EnableUsbhs0PhyPllClock to enable the PHY
512  * clock to use USB HS.
513  *
514  * param src  USB HS does not care about the clock source, here must be ref kCLOCK_UsbSrcUnused.
515  * param freq USB HS does not care about the clock source, so this parameter is ignored.
516  * retval true The clock is set successfully.
517  * retval false The clock source is invalid to get proper USB HS clock.
518  */
CLOCK_EnableUsbhs1Clock(clock_usb_src_t src,uint32_t freq)519 bool CLOCK_EnableUsbhs1Clock(clock_usb_src_t src, uint32_t freq)
520 {
521     uint32_t i = 0;
522     CCM->CCGR6 |= CCM_CCGR6_CG0_MASK;
523     USB2->USBCMD |= USBHS_USBCMD_RST_MASK;
524 
525     /* Add a delay between RST and RS so make sure there is a DP pullup sequence*/
526     for (i = 0; i < 400000U; i++)
527     {
528         __ASM("nop");
529     }
530     PMU->REG_3P0 = (PMU->REG_3P0 & (~PMU_REG_3P0_OUTPUT_TRG_MASK)) |
531                    (PMU_REG_3P0_OUTPUT_TRG(0x17) | PMU_REG_3P0_ENABLE_LINREG_MASK);
532     return true;
533 }
534 
535 /*! brief Enable USB HS PHY PLL clock.
536  *
537  * This function enables the internal 480MHz USB PHY PLL clock.
538  *
539  * param src  USB HS PHY PLL clock source.
540  * param freq The frequency specified by src.
541  * retval true The clock is set successfully.
542  * retval false The clock source is invalid to get proper USB HS clock.
543  */
CLOCK_EnableUsbhs0PhyPllClock(clock_usb_phy_src_t src,uint32_t freq)544 bool CLOCK_EnableUsbhs0PhyPllClock(clock_usb_phy_src_t src, uint32_t freq)
545 {
546     static const clock_usb_pll_config_t g_ccmConfigUsbPll = {.loopDivider = 0U};
547     if ((CCM_ANALOG->PLL_USB1 & CCM_ANALOG_PLL_USB1_ENABLE_MASK) != 0U)
548     {
549         CCM_ANALOG->PLL_USB1 |= CCM_ANALOG_PLL_USB1_EN_USB_CLKS_MASK;
550     }
551     else
552     {
553         CLOCK_InitUsb1Pll(&g_ccmConfigUsbPll);
554     }
555     USBPHY1->CTRL &= ~USBPHY_CTRL_SFTRST_MASK; /* release PHY from reset */
556     USBPHY1->CTRL &= ~USBPHY_CTRL_CLKGATE_MASK;
557 
558     USBPHY1->PWD = 0;
559     USBPHY1->CTRL |= USBPHY_CTRL_ENAUTOCLR_PHY_PWD_MASK | USBPHY_CTRL_ENAUTOCLR_CLKGATE_MASK |
560                      USBPHY_CTRL_ENUTMILEVEL2_MASK | USBPHY_CTRL_ENUTMILEVEL3_MASK;
561     return true;
562 }
563 
564 /*! brief Disable USB HS PHY PLL clock.
565  *
566  * This function disables USB HS PHY PLL clock.
567  */
CLOCK_DisableUsbhs0PhyPllClock(void)568 void CLOCK_DisableUsbhs0PhyPllClock(void)
569 {
570     CCM_ANALOG->PLL_USB1 &= ~CCM_ANALOG_PLL_USB1_EN_USB_CLKS_MASK;
571     USBPHY1->CTRL |= USBPHY_CTRL_CLKGATE_MASK; /* Set to 1U to gate clocks */
572 }
573 
574 /*!
575  * brief Initialize the ARM PLL.
576  *
577  * This function initialize the ARM PLL with specific settings
578  *
579  * param config   configuration to set to PLL.
580  */
CLOCK_InitArmPll(const clock_arm_pll_config_t * config)581 void CLOCK_InitArmPll(const clock_arm_pll_config_t *config)
582 {
583     /* Bypass PLL first */
584     CCM_ANALOG->PLL_ARM = (CCM_ANALOG->PLL_ARM & (~CCM_ANALOG_PLL_ARM_BYPASS_CLK_SRC_MASK)) |
585                           CCM_ANALOG_PLL_ARM_BYPASS_MASK | CCM_ANALOG_PLL_ARM_BYPASS_CLK_SRC(config->src);
586 
587     CCM_ANALOG->PLL_ARM =
588         (CCM_ANALOG->PLL_ARM & (~(CCM_ANALOG_PLL_ARM_DIV_SELECT_MASK | CCM_ANALOG_PLL_ARM_POWERDOWN_MASK))) |
589         CCM_ANALOG_PLL_ARM_ENABLE_MASK | CCM_ANALOG_PLL_ARM_DIV_SELECT(config->loopDivider);
590 
591     while ((CCM_ANALOG->PLL_ARM & CCM_ANALOG_PLL_ARM_LOCK_MASK) == 0UL)
592     {
593     }
594 
595     /* Disable Bypass */
596     CCM_ANALOG->PLL_ARM &= ~CCM_ANALOG_PLL_ARM_BYPASS_MASK;
597 }
598 
599 /*!
600  * brief De-initialize the ARM PLL.
601  */
CLOCK_DeinitArmPll(void)602 void CLOCK_DeinitArmPll(void)
603 {
604     CCM_ANALOG->PLL_ARM = CCM_ANALOG_PLL_ARM_POWERDOWN_MASK;
605 }
606 
607 /*!
608  * brief Initialize the System PLL.
609  *
610  * This function initializes the System PLL with specific settings
611  *
612  * param config Configuration to set to PLL.
613  */
CLOCK_InitSysPll(const clock_sys_pll_config_t * config)614 void CLOCK_InitSysPll(const clock_sys_pll_config_t *config)
615 {
616     /* Bypass PLL first */
617     CCM_ANALOG->PLL_SYS = (CCM_ANALOG->PLL_SYS & (~CCM_ANALOG_PLL_SYS_BYPASS_CLK_SRC_MASK)) |
618                           CCM_ANALOG_PLL_SYS_BYPASS_MASK | CCM_ANALOG_PLL_SYS_BYPASS_CLK_SRC(config->src);
619 
620     CCM_ANALOG->PLL_SYS =
621         (CCM_ANALOG->PLL_SYS & (~(CCM_ANALOG_PLL_SYS_DIV_SELECT_MASK | CCM_ANALOG_PLL_SYS_POWERDOWN_MASK))) |
622         CCM_ANALOG_PLL_SYS_ENABLE_MASK | CCM_ANALOG_PLL_SYS_DIV_SELECT(config->loopDivider);
623 
624     /* Initialize the fractional mode */
625     CCM_ANALOG->PLL_SYS_NUM   = CCM_ANALOG_PLL_SYS_NUM_A(config->numerator);
626     CCM_ANALOG->PLL_SYS_DENOM = CCM_ANALOG_PLL_SYS_DENOM_B(config->denominator);
627 
628     /* Initialize the spread spectrum mode */
629     CCM_ANALOG->PLL_SYS_SS = CCM_ANALOG_PLL_SYS_SS_STEP(config->ss_step) |
630                              CCM_ANALOG_PLL_SYS_SS_ENABLE(config->ss_enable) |
631                              CCM_ANALOG_PLL_SYS_SS_STOP(config->ss_stop);
632 
633     while ((CCM_ANALOG->PLL_SYS & CCM_ANALOG_PLL_SYS_LOCK_MASK) == 0UL)
634     {
635     }
636 
637     /* Disable Bypass */
638     CCM_ANALOG->PLL_SYS &= ~CCM_ANALOG_PLL_SYS_BYPASS_MASK;
639 }
640 
641 /*!
642  * brief De-initialize the System PLL.
643  */
CLOCK_DeinitSysPll(void)644 void CLOCK_DeinitSysPll(void)
645 {
646     CCM_ANALOG->PLL_SYS = CCM_ANALOG_PLL_SYS_POWERDOWN_MASK;
647 }
648 
649 /*!
650  * brief Initialize the USB1 PLL.
651  *
652  * This function initializes the USB1 PLL with specific settings
653  *
654  * param config Configuration to set to PLL.
655  */
CLOCK_InitUsb1Pll(const clock_usb_pll_config_t * config)656 void CLOCK_InitUsb1Pll(const clock_usb_pll_config_t *config)
657 {
658     /* Bypass PLL first */
659     CCM_ANALOG->PLL_USB1 = (CCM_ANALOG->PLL_USB1 & (~CCM_ANALOG_PLL_USB1_BYPASS_CLK_SRC_MASK)) |
660                            CCM_ANALOG_PLL_USB1_BYPASS_MASK | CCM_ANALOG_PLL_USB1_BYPASS_CLK_SRC(config->src);
661 
662     CCM_ANALOG->PLL_USB1 = (CCM_ANALOG->PLL_USB1 & (~CCM_ANALOG_PLL_USB1_DIV_SELECT_MASK)) |
663                            CCM_ANALOG_PLL_USB1_ENABLE_MASK | CCM_ANALOG_PLL_USB1_POWER_MASK |
664                            CCM_ANALOG_PLL_USB1_EN_USB_CLKS_MASK | CCM_ANALOG_PLL_USB1_DIV_SELECT(config->loopDivider);
665 
666     while ((CCM_ANALOG->PLL_USB1 & CCM_ANALOG_PLL_USB1_LOCK_MASK) == 0UL)
667     {
668     }
669 
670     /* Disable Bypass */
671     CCM_ANALOG->PLL_USB1 &= ~CCM_ANALOG_PLL_USB1_BYPASS_MASK;
672 }
673 
674 /*!
675  * brief Deinitialize the USB1 PLL.
676  */
CLOCK_DeinitUsb1Pll(void)677 void CLOCK_DeinitUsb1Pll(void)
678 {
679     CCM_ANALOG->PLL_USB1 = 0U;
680 }
681 
682 /*!
683  * brief Initialize the USB2 PLL.
684  *
685  * This function initializes the USB2 PLL with specific settings
686  *
687  * param config Configuration to set to PLL.
688  */
CLOCK_InitUsb2Pll(const clock_usb_pll_config_t * config)689 void CLOCK_InitUsb2Pll(const clock_usb_pll_config_t *config)
690 {
691     /* Bypass PLL first */
692     CCM_ANALOG->PLL_USB2 = (CCM_ANALOG->PLL_USB2 & (~CCM_ANALOG_PLL_USB2_BYPASS_CLK_SRC_MASK)) |
693                            CCM_ANALOG_PLL_USB2_BYPASS_MASK | CCM_ANALOG_PLL_USB2_BYPASS_CLK_SRC(config->src);
694 
695     CCM_ANALOG->PLL_USB2 = (CCM_ANALOG->PLL_USB2 & (~CCM_ANALOG_PLL_USB2_DIV_SELECT_MASK)) |
696                            CCM_ANALOG_PLL_USB2_ENABLE_MASK | CCM_ANALOG_PLL_USB2_POWER_MASK |
697                            CCM_ANALOG_PLL_USB2_EN_USB_CLKS_MASK | CCM_ANALOG_PLL_USB2_DIV_SELECT(config->loopDivider);
698 
699     while ((CCM_ANALOG->PLL_USB2 & CCM_ANALOG_PLL_USB2_LOCK_MASK) == 0UL)
700     {
701     }
702 
703     /* Disable Bypass */
704     CCM_ANALOG->PLL_USB2 &= ~CCM_ANALOG_PLL_USB2_BYPASS_MASK;
705 }
706 
707 /*!
708  * brief Deinitialize the USB2 PLL.
709  */
CLOCK_DeinitUsb2Pll(void)710 void CLOCK_DeinitUsb2Pll(void)
711 {
712     CCM_ANALOG->PLL_USB2 = 0U;
713 }
714 
715 /*!
716  * brief Initializes the Audio PLL.
717  *
718  * This function initializes the Audio PLL with specific settings
719  *
720  * param config Configuration to set to PLL.
721  */
CLOCK_InitAudioPll(const clock_audio_pll_config_t * config)722 void CLOCK_InitAudioPll(const clock_audio_pll_config_t *config)
723 {
724     uint32_t pllAudio;
725     uint32_t misc2 = 0;
726 
727     /* Bypass PLL first */
728     CCM_ANALOG->PLL_AUDIO = (CCM_ANALOG->PLL_AUDIO & (~CCM_ANALOG_PLL_AUDIO_BYPASS_CLK_SRC_MASK)) |
729                             CCM_ANALOG_PLL_AUDIO_BYPASS_MASK | CCM_ANALOG_PLL_AUDIO_BYPASS_CLK_SRC(config->src);
730 
731     CCM_ANALOG->PLL_AUDIO_NUM   = CCM_ANALOG_PLL_AUDIO_NUM_A(config->numerator);
732     CCM_ANALOG->PLL_AUDIO_DENOM = CCM_ANALOG_PLL_AUDIO_DENOM_B(config->denominator);
733 
734     /*
735      * Set post divider:
736      *
737      * ------------------------------------------------------------------------
738      * | config->postDivider | PLL_AUDIO[POST_DIV_SELECT]  | MISC2[AUDIO_DIV] |
739      * ------------------------------------------------------------------------
740      * |         1           |            2                |        0         |
741      * ------------------------------------------------------------------------
742      * |         2           |            1                |        0         |
743      * ------------------------------------------------------------------------
744      * |         4           |            2                |        3         |
745      * ------------------------------------------------------------------------
746      * |         8           |            1                |        3         |
747      * ------------------------------------------------------------------------
748      * |         16          |            0                |        3         |
749      * ------------------------------------------------------------------------
750      */
751     pllAudio =
752         (CCM_ANALOG->PLL_AUDIO & (~(CCM_ANALOG_PLL_AUDIO_DIV_SELECT_MASK | CCM_ANALOG_PLL_AUDIO_POWERDOWN_MASK))) |
753         CCM_ANALOG_PLL_AUDIO_ENABLE_MASK | CCM_ANALOG_PLL_AUDIO_DIV_SELECT(config->loopDivider);
754 
755     switch (config->postDivider)
756     {
757         case 16:
758             pllAudio |= CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(0);
759             misc2 = CCM_ANALOG_MISC2_AUDIO_DIV_MSB_MASK | CCM_ANALOG_MISC2_AUDIO_DIV_LSB_MASK;
760             break;
761 
762         case 8:
763             pllAudio |= CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(1);
764             misc2 = CCM_ANALOG_MISC2_AUDIO_DIV_MSB_MASK | CCM_ANALOG_MISC2_AUDIO_DIV_LSB_MASK;
765             break;
766 
767         case 4:
768             pllAudio |= CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(2);
769             misc2 = CCM_ANALOG_MISC2_AUDIO_DIV_MSB_MASK | CCM_ANALOG_MISC2_AUDIO_DIV_LSB_MASK;
770             break;
771 
772         case 2:
773             pllAudio |= CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(1);
774             break;
775 
776         default:
777             pllAudio |= CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(2);
778             break;
779     }
780 
781     CCM_ANALOG->MISC2 =
782         (CCM_ANALOG->MISC2 & ~(CCM_ANALOG_MISC2_AUDIO_DIV_LSB_MASK | CCM_ANALOG_MISC2_AUDIO_DIV_MSB_MASK)) | misc2;
783 
784     CCM_ANALOG->PLL_AUDIO = pllAudio;
785 
786     while ((CCM_ANALOG->PLL_AUDIO & CCM_ANALOG_PLL_AUDIO_LOCK_MASK) == 0UL)
787     {
788     }
789 
790     /* Disable Bypass */
791     CCM_ANALOG->PLL_AUDIO &= ~CCM_ANALOG_PLL_AUDIO_BYPASS_MASK;
792 }
793 
794 /*!
795  * brief De-initialize the Audio PLL.
796  */
CLOCK_DeinitAudioPll(void)797 void CLOCK_DeinitAudioPll(void)
798 {
799     CCM_ANALOG->PLL_AUDIO = (uint32_t)CCM_ANALOG_PLL_AUDIO_POWERDOWN_MASK;
800 }
801 
802 /*!
803  * brief Initialize the video PLL.
804  *
805  * This function configures the Video PLL with specific settings
806  *
807  * param config   configuration to set to PLL.
808  */
CLOCK_InitVideoPll(const clock_video_pll_config_t * config)809 void CLOCK_InitVideoPll(const clock_video_pll_config_t *config)
810 {
811     uint32_t pllVideo;
812     uint32_t misc2 = 0;
813 
814     /* Bypass PLL first */
815     CCM_ANALOG->PLL_VIDEO = (CCM_ANALOG->PLL_VIDEO & (~CCM_ANALOG_PLL_VIDEO_BYPASS_CLK_SRC_MASK)) |
816                             CCM_ANALOG_PLL_VIDEO_BYPASS_MASK | CCM_ANALOG_PLL_VIDEO_BYPASS_CLK_SRC(config->src);
817 
818     CCM_ANALOG->PLL_VIDEO_NUM   = CCM_ANALOG_PLL_VIDEO_NUM_A(config->numerator);
819     CCM_ANALOG->PLL_VIDEO_DENOM = CCM_ANALOG_PLL_VIDEO_DENOM_B(config->denominator);
820 
821     /*
822      * Set post divider:
823      *
824      * ------------------------------------------------------------------------
825      * | config->postDivider | PLL_VIDEO[POST_DIV_SELECT]  | MISC2[VIDEO_DIV] |
826      * ------------------------------------------------------------------------
827      * |         1           |            2                |        0         |
828      * ------------------------------------------------------------------------
829      * |         2           |            1                |        0         |
830      * ------------------------------------------------------------------------
831      * |         4           |            2                |        3         |
832      * ------------------------------------------------------------------------
833      * |         8           |            1                |        3         |
834      * ------------------------------------------------------------------------
835      * |         16          |            0                |        3         |
836      * ------------------------------------------------------------------------
837      */
838     pllVideo =
839         (CCM_ANALOG->PLL_VIDEO & (~(CCM_ANALOG_PLL_VIDEO_DIV_SELECT_MASK | CCM_ANALOG_PLL_VIDEO_POWERDOWN_MASK))) |
840         CCM_ANALOG_PLL_VIDEO_ENABLE_MASK | CCM_ANALOG_PLL_VIDEO_DIV_SELECT(config->loopDivider);
841 
842     switch (config->postDivider)
843     {
844         case 16:
845             pllVideo |= CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(0);
846             misc2 = CCM_ANALOG_MISC2_VIDEO_DIV(3);
847             break;
848 
849         case 8:
850             pllVideo |= CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(1);
851             misc2 = CCM_ANALOG_MISC2_VIDEO_DIV(3);
852             break;
853 
854         case 4:
855             pllVideo |= CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(2);
856             misc2 = CCM_ANALOG_MISC2_VIDEO_DIV(3);
857             break;
858 
859         case 2:
860             pllVideo |= CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(1);
861             break;
862 
863         default:
864             pllVideo |= CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(2);
865             break;
866     }
867 
868     CCM_ANALOG->MISC2 = (CCM_ANALOG->MISC2 & ~CCM_ANALOG_MISC2_VIDEO_DIV_MASK) | misc2;
869 
870     CCM_ANALOG->PLL_VIDEO = pllVideo;
871 
872     while ((CCM_ANALOG->PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_LOCK_MASK) == 0UL)
873     {
874     }
875 
876     /* Disable Bypass */
877     CCM_ANALOG->PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_BYPASS_MASK;
878 }
879 
880 /*!
881  * brief De-initialize the Video PLL.
882  */
CLOCK_DeinitVideoPll(void)883 void CLOCK_DeinitVideoPll(void)
884 {
885     CCM_ANALOG->PLL_VIDEO = CCM_ANALOG_PLL_VIDEO_POWERDOWN_MASK;
886 }
887 
888 /*!
889  * brief Initialize the ENET PLL.
890  *
891  * This function initializes the ENET PLL with specific settings.
892  *
893  * param config Configuration to set to PLL.
894  */
CLOCK_InitEnetPll(const clock_enet_pll_config_t * config)895 void CLOCK_InitEnetPll(const clock_enet_pll_config_t *config)
896 {
897     uint32_t enet_pll = CCM_ANALOG_PLL_ENET_DIV_SELECT(config->loopDivider) |
898                         CCM_ANALOG_PLL_ENET_ENET2_DIV_SELECT(config->loopDivider1);
899 
900     CCM_ANALOG->PLL_ENET = (CCM_ANALOG->PLL_ENET & (~CCM_ANALOG_PLL_ENET_BYPASS_CLK_SRC_MASK)) |
901                            CCM_ANALOG_PLL_ENET_BYPASS_MASK | CCM_ANALOG_PLL_ENET_BYPASS_CLK_SRC(config->src);
902 
903     if (config->enableClkOutput)
904     {
905         enet_pll |= CCM_ANALOG_PLL_ENET_ENABLE_MASK;
906     }
907 
908     if (config->enableClkOutput1)
909     {
910         enet_pll |= CCM_ANALOG_PLL_ENET_ENET2_REF_EN_MASK;
911     }
912 
913     if (config->enableClkOutput25M)
914     {
915         enet_pll |= CCM_ANALOG_PLL_ENET_ENET_25M_REF_EN_MASK;
916     }
917 
918     CCM_ANALOG->PLL_ENET =
919         (CCM_ANALOG->PLL_ENET & (~(CCM_ANALOG_PLL_ENET_DIV_SELECT_MASK | CCM_ANALOG_PLL_ENET_ENET2_DIV_SELECT_MASK |
920                                    CCM_ANALOG_PLL_ENET_POWERDOWN_MASK))) |
921         enet_pll;
922 
923     /* Wait for stable */
924     while ((CCM_ANALOG->PLL_ENET & CCM_ANALOG_PLL_ENET_LOCK_MASK) == 0UL)
925     {
926     }
927 
928     /* Disable Bypass */
929     CCM_ANALOG->PLL_ENET &= ~CCM_ANALOG_PLL_ENET_BYPASS_MASK;
930 }
931 
932 /*!
933  * brief Deinitialize the ENET PLL.
934  *
935  * This function disables the ENET PLL.
936  */
CLOCK_DeinitEnetPll(void)937 void CLOCK_DeinitEnetPll(void)
938 {
939     CCM_ANALOG->PLL_ENET = CCM_ANALOG_PLL_ENET_POWERDOWN_MASK;
940 }
941 
942 /*!
943  * brief Get current PLL output frequency.
944  *
945  * This function get current output frequency of specific PLL
946  *
947  * param pll   pll name to get frequency.
948  * return The PLL output frequency in hertz.
949  */
CLOCK_GetPllFreq(clock_pll_t pll)950 uint32_t CLOCK_GetPllFreq(clock_pll_t pll)
951 {
952     uint32_t freq;
953     uint32_t divSelect;
954     clock_64b_t freqTmp;
955 
956     static const uint32_t enetRefClkFreq[] = {
957         25000000U,  /* 25M */
958         50000000U,  /* 50M */
959         100000000U, /* 100M */
960         125000000U  /* 125M */
961     };
962 
963     /* check if PLL is enabled */
964     if (!CLOCK_IsPllEnabled(CCM_ANALOG, pll))
965     {
966         return 0U;
967     }
968 
969     /* get pll reference clock */
970     freq = CLOCK_GetPllBypassRefClk(CCM_ANALOG, pll);
971 
972     /* check if pll is bypassed */
973     if (CLOCK_IsPllBypassed(CCM_ANALOG, pll))
974     {
975         return freq;
976     }
977 
978     switch (pll)
979     {
980         case kCLOCK_PllArm:
981             freq = ((freq * ((CCM_ANALOG->PLL_ARM & CCM_ANALOG_PLL_ARM_DIV_SELECT_MASK) >>
982                              CCM_ANALOG_PLL_ARM_DIV_SELECT_SHIFT)) >>
983                     1U);
984             break;
985         case kCLOCK_PllSys:
986             /* PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM). */
987             freqTmp = ((clock_64b_t)freq * ((clock_64b_t)(CCM_ANALOG->PLL_SYS_NUM)));
988             freqTmp /= ((clock_64b_t)(CCM_ANALOG->PLL_SYS_DENOM));
989 
990             if ((CCM_ANALOG->PLL_SYS & CCM_ANALOG_PLL_SYS_DIV_SELECT_MASK) != 0U)
991             {
992                 freq *= 22U;
993             }
994             else
995             {
996                 freq *= 20U;
997             }
998 
999             freq += (uint32_t)freqTmp;
1000             break;
1001 
1002         case kCLOCK_PllUsb1:
1003             freq = (freq * (((CCM_ANALOG->PLL_USB1 & CCM_ANALOG_PLL_USB1_DIV_SELECT_MASK) != 0UL) ? 22U : 20U));
1004             break;
1005 
1006         case kCLOCK_PllAudio:
1007             /* PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM). */
1008             divSelect =
1009                 (CCM_ANALOG->PLL_AUDIO & CCM_ANALOG_PLL_AUDIO_DIV_SELECT_MASK) >> CCM_ANALOG_PLL_AUDIO_DIV_SELECT_SHIFT;
1010 
1011             freqTmp = ((clock_64b_t)freq * ((clock_64b_t)(CCM_ANALOG->PLL_AUDIO_NUM)));
1012             freqTmp /= ((clock_64b_t)(CCM_ANALOG->PLL_AUDIO_DENOM));
1013 
1014             freq = freq * divSelect + (uint32_t)freqTmp;
1015 
1016             /* AUDIO PLL output = PLL output frequency / POSTDIV. */
1017 
1018             /*
1019              * Post divider:
1020              *
1021              * PLL_AUDIO[POST_DIV_SELECT]:
1022              * 0x00: 4
1023              * 0x01: 2
1024              * 0x02: 1
1025              *
1026              * MISC2[AUDO_DIV]:
1027              * 0x00: 1
1028              * 0x01: 2
1029              * 0x02: 1
1030              * 0x03: 4
1031              */
1032             switch (CCM_ANALOG->PLL_AUDIO & CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT_MASK)
1033             {
1034                 case CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(0U):
1035                     freq = freq >> 2U;
1036                     break;
1037 
1038                 case CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(1U):
1039                     freq = freq >> 1U;
1040                     break;
1041 
1042                 case CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(2U):
1043                     freq = freq >> 0U;
1044                     break;
1045 
1046                 default:
1047                     assert(false);
1048                     break;
1049             }
1050 
1051             switch (CCM_ANALOG->MISC2 & (CCM_ANALOG_MISC2_AUDIO_DIV_MSB_MASK | CCM_ANALOG_MISC2_AUDIO_DIV_LSB_MASK))
1052             {
1053                 case CCM_ANALOG_MISC2_AUDIO_DIV_MSB(1) | CCM_ANALOG_MISC2_AUDIO_DIV_LSB(1):
1054                     freq >>= 2U;
1055                     break;
1056 
1057                 case CCM_ANALOG_MISC2_AUDIO_DIV_MSB(0) | CCM_ANALOG_MISC2_AUDIO_DIV_LSB(1):
1058                     freq >>= 1U;
1059                     break;
1060 
1061                 case CCM_ANALOG_MISC2_AUDIO_DIV_MSB(0) | CCM_ANALOG_MISC2_AUDIO_DIV_LSB(0):
1062                 case CCM_ANALOG_MISC2_AUDIO_DIV_MSB(1) | CCM_ANALOG_MISC2_AUDIO_DIV_LSB(0):
1063                     freq >>= 0U;
1064                     break;
1065 
1066                 default:
1067                     assert(false);
1068                     break;
1069             }
1070             break;
1071 
1072         case kCLOCK_PllVideo:
1073             /* PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM). */
1074             divSelect =
1075                 (CCM_ANALOG->PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_DIV_SELECT_MASK) >> CCM_ANALOG_PLL_VIDEO_DIV_SELECT_SHIFT;
1076 
1077             freqTmp = ((clock_64b_t)freq * ((clock_64b_t)(CCM_ANALOG->PLL_VIDEO_NUM)));
1078             freqTmp /= ((clock_64b_t)(CCM_ANALOG->PLL_VIDEO_DENOM));
1079             freq = freq * divSelect + (uint32_t)freqTmp;
1080 
1081             /* VIDEO PLL output = PLL output frequency / POSTDIV. */
1082 
1083             /*
1084              * Post divider:
1085              *
1086              * PLL_VIDEO[POST_DIV_SELECT]:
1087              * 0x00: 4
1088              * 0x01: 2
1089              * 0x02: 1
1090              *
1091              * MISC2[VIDEO_DIV]:
1092              * 0x00: 1
1093              * 0x01: 2
1094              * 0x02: 1
1095              * 0x03: 4
1096              */
1097             switch (CCM_ANALOG->PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT_MASK)
1098             {
1099                 case CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(0U):
1100                     freq = freq >> 2U;
1101                     break;
1102 
1103                 case CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(1U):
1104                     freq = freq >> 1U;
1105                     break;
1106 
1107                 case CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(2U):
1108                     freq = freq >> 0U;
1109                     break;
1110 
1111                 default:
1112                     assert(false);
1113                     break;
1114             }
1115 
1116             switch (CCM_ANALOG->MISC2 & CCM_ANALOG_MISC2_VIDEO_DIV_MASK)
1117             {
1118                 case CCM_ANALOG_MISC2_VIDEO_DIV(3U):
1119                     freq >>= 2U;
1120                     break;
1121 
1122                 case CCM_ANALOG_MISC2_VIDEO_DIV(1U):
1123                     freq >>= 1U;
1124                     break;
1125 
1126                 case CCM_ANALOG_MISC2_VIDEO_DIV(0U):
1127                 case CCM_ANALOG_MISC2_VIDEO_DIV(2U):
1128                     freq >>= 0U;
1129                     break;
1130 
1131                 default:
1132                     assert(false);
1133                     break;
1134             }
1135             break;
1136         case kCLOCK_PllEnet:
1137             divSelect =
1138                 (CCM_ANALOG->PLL_ENET & CCM_ANALOG_PLL_ENET_DIV_SELECT_MASK) >> CCM_ANALOG_PLL_ENET_DIV_SELECT_SHIFT;
1139             freq = enetRefClkFreq[divSelect];
1140             break;
1141 
1142         case kCLOCK_PllEnet2:
1143             divSelect = (CCM_ANALOG->PLL_ENET & CCM_ANALOG_PLL_ENET_ENET2_DIV_SELECT_MASK) >>
1144                         CCM_ANALOG_PLL_ENET_ENET2_DIV_SELECT_SHIFT;
1145             freq = enetRefClkFreq[divSelect];
1146             break;
1147 
1148         case kCLOCK_PllEnet25M:
1149             /* ref_enetpll1 if fixed at 25MHz. */
1150             freq = 25000000UL;
1151             break;
1152 
1153         case kCLOCK_PllUsb2:
1154             freq = (freq * (((CCM_ANALOG->PLL_USB2 & CCM_ANALOG_PLL_USB2_DIV_SELECT_MASK) != 0U) ? 22U : 20U));
1155             break;
1156         default:
1157             freq = 0U;
1158             break;
1159     }
1160 
1161     return freq;
1162 }
1163 
1164 /*!
1165  * brief Initialize the System PLL PFD.
1166  *
1167  * This function initializes the System PLL PFD. During new value setting,
1168  * the clock output is disabled to prevent glitch.
1169  *
1170  * param pfd Which PFD clock to enable.
1171  * param pfdFrac The PFD FRAC value.
1172  * note It is recommended that PFD settings are kept between 12-35.
1173  */
CLOCK_InitSysPfd(clock_pfd_t pfd,uint8_t pfdFrac)1174 void CLOCK_InitSysPfd(clock_pfd_t pfd, uint8_t pfdFrac)
1175 {
1176     uint32_t pfdIndex = (uint32_t)pfd;
1177     uint32_t pfd528;
1178 
1179     pfd528 = CCM_ANALOG->PFD_528 &
1180              ~(((uint32_t)((uint32_t)CCM_ANALOG_PFD_528_PFD0_CLKGATE_MASK | CCM_ANALOG_PFD_528_PFD0_FRAC_MASK)
1181                 << (8UL * pfdIndex)));
1182 
1183     /* Disable the clock output first. */
1184     CCM_ANALOG->PFD_528 = pfd528 | ((uint32_t)CCM_ANALOG_PFD_528_PFD0_CLKGATE_MASK << (8UL * pfdIndex));
1185 
1186     /* Set the new value and enable output. */
1187     CCM_ANALOG->PFD_528 = pfd528 | (CCM_ANALOG_PFD_528_PFD0_FRAC(pfdFrac) << (8UL * pfdIndex));
1188 }
1189 
1190 /*!
1191  * brief De-initialize the System PLL PFD.
1192  *
1193  * This function disables the System PLL PFD.
1194  *
1195  * param pfd Which PFD clock to disable.
1196  */
CLOCK_DeinitSysPfd(clock_pfd_t pfd)1197 void CLOCK_DeinitSysPfd(clock_pfd_t pfd)
1198 {
1199     CCM_ANALOG->PFD_528 |= (uint32_t)CCM_ANALOG_PFD_528_PFD0_CLKGATE_MASK << (8U * (uint8_t)pfd);
1200 }
1201 
1202 /*!
1203  * brief Check if Sys PFD is enabled
1204  *
1205  * param pfd PFD control name
1206  * return PFD bypass status.
1207  *         - true: power on.
1208  *         - false: power off.
1209  */
CLOCK_IsSysPfdEnabled(clock_pfd_t pfd)1210 bool CLOCK_IsSysPfdEnabled(clock_pfd_t pfd)
1211 {
1212     return ((CCM_ANALOG->PFD_528 & (uint32_t)CCM_ANALOG_PFD_528_PFD0_CLKGATE_MASK << (8UL * (uint8_t)pfd)) == 0U);
1213 }
1214 
1215 /*!
1216  * brief Initialize the USB1 PLL PFD.
1217  *
1218  * This function initializes the USB1 PLL PFD. During new value setting,
1219  * the clock output is disabled to prevent glitch.
1220  *
1221  * param pfd Which PFD clock to enable.
1222  * param pfdFrac The PFD FRAC value.
1223  * note It is recommended that PFD settings are kept between 12-35.
1224  */
CLOCK_InitUsb1Pfd(clock_pfd_t pfd,uint8_t pfdFrac)1225 void CLOCK_InitUsb1Pfd(clock_pfd_t pfd, uint8_t pfdFrac)
1226 {
1227     uint32_t pfdIndex = (uint32_t)pfd;
1228     uint32_t pfd480;
1229 
1230     pfd480 = CCM_ANALOG->PFD_480 &
1231              ~(((uint32_t)((uint32_t)CCM_ANALOG_PFD_480_PFD0_CLKGATE_MASK | CCM_ANALOG_PFD_480_PFD0_FRAC_MASK)
1232                 << (8UL * pfdIndex)));
1233 
1234     /* Disable the clock output first. */
1235     CCM_ANALOG->PFD_480 = pfd480 | ((uint32_t)CCM_ANALOG_PFD_480_PFD0_CLKGATE_MASK << (8UL * pfdIndex));
1236 
1237     /* Set the new value and enable output. */
1238     CCM_ANALOG->PFD_480 = pfd480 | (CCM_ANALOG_PFD_480_PFD0_FRAC(pfdFrac) << (8UL * pfdIndex));
1239 }
1240 
1241 /*!
1242  * brief De-initialize the USB1 PLL PFD.
1243  *
1244  * This function disables the USB1 PLL PFD.
1245  *
1246  * param pfd Which PFD clock to disable.
1247  */
CLOCK_DeinitUsb1Pfd(clock_pfd_t pfd)1248 void CLOCK_DeinitUsb1Pfd(clock_pfd_t pfd)
1249 {
1250     CCM_ANALOG->PFD_480 |= (uint32_t)CCM_ANALOG_PFD_480_PFD0_CLKGATE_MASK << (8UL * (uint8_t)pfd);
1251 }
1252 
1253 /*!
1254  * brief Check if Usb1 PFD is enabled
1255  *
1256  * param pfd PFD control name.
1257  * return PFD bypass status.
1258  *         - true: power on.
1259  *         - false: power off.
1260  */
CLOCK_IsUsb1PfdEnabled(clock_pfd_t pfd)1261 bool CLOCK_IsUsb1PfdEnabled(clock_pfd_t pfd)
1262 {
1263     return ((CCM_ANALOG->PFD_480 & (uint32_t)CCM_ANALOG_PFD_480_PFD0_CLKGATE_MASK << (8UL * (uint8_t)pfd)) == 0U);
1264 }
1265 
1266 /*!
1267  * brief Get current System PLL PFD output frequency.
1268  *
1269  * This function get current output frequency of specific System PLL PFD
1270  *
1271  * param pfd   pfd name to get frequency.
1272  * return The PFD output frequency in hertz.
1273  */
CLOCK_GetSysPfdFreq(clock_pfd_t pfd)1274 uint32_t CLOCK_GetSysPfdFreq(clock_pfd_t pfd)
1275 {
1276     uint32_t freq = CLOCK_GetPllFreq(kCLOCK_PllSys);
1277     uint64_t tmp64 = (uint64_t)freq * 18UL;
1278 
1279     switch (pfd)
1280     {
1281         case kCLOCK_Pfd0:
1282             freq = (uint32_t)(tmp64 / (uint64_t)((CCM_ANALOG->PFD_528 & CCM_ANALOG_PFD_528_PFD0_FRAC_MASK) >> CCM_ANALOG_PFD_528_PFD0_FRAC_SHIFT));
1283             break;
1284 
1285         case kCLOCK_Pfd1:
1286             freq = (uint32_t)(tmp64 / (uint64_t)((CCM_ANALOG->PFD_528 & CCM_ANALOG_PFD_528_PFD1_FRAC_MASK) >> CCM_ANALOG_PFD_528_PFD1_FRAC_SHIFT));
1287             break;
1288 
1289         case kCLOCK_Pfd2:
1290             freq = (uint32_t)(tmp64 / (uint64_t)((CCM_ANALOG->PFD_528 & CCM_ANALOG_PFD_528_PFD2_FRAC_MASK) >> CCM_ANALOG_PFD_528_PFD2_FRAC_SHIFT));
1291             break;
1292 
1293         case kCLOCK_Pfd3:
1294             freq = (uint32_t)(tmp64 / (uint64_t)((CCM_ANALOG->PFD_528 & CCM_ANALOG_PFD_528_PFD3_FRAC_MASK) >> CCM_ANALOG_PFD_528_PFD3_FRAC_SHIFT));
1295             break;
1296 
1297         default:
1298             freq = 0U;
1299             break;
1300     }
1301 
1302     return freq;
1303 }
1304 
1305 /*!
1306  * brief Get current USB1 PLL PFD output frequency.
1307  *
1308  * This function get current output frequency of specific USB1 PLL PFD
1309  *
1310  * param pfd   pfd name to get frequency.
1311  * return The PFD output frequency in hertz.
1312  */
CLOCK_GetUsb1PfdFreq(clock_pfd_t pfd)1313 uint32_t CLOCK_GetUsb1PfdFreq(clock_pfd_t pfd)
1314 {
1315     uint32_t freq = CLOCK_GetPllFreq(kCLOCK_PllUsb1);
1316     uint64_t tmp64 = (uint64_t)freq * 18UL;
1317 
1318     switch (pfd)
1319     {
1320         case kCLOCK_Pfd0:
1321             freq = (uint32_t)(tmp64 / (uint64_t)((CCM_ANALOG->PFD_480 & CCM_ANALOG_PFD_480_PFD0_FRAC_MASK) >> CCM_ANALOG_PFD_480_PFD0_FRAC_SHIFT));
1322             break;
1323 
1324         case kCLOCK_Pfd1:
1325             freq = (uint32_t)(tmp64 / (uint64_t)((CCM_ANALOG->PFD_480 & CCM_ANALOG_PFD_480_PFD1_FRAC_MASK) >> CCM_ANALOG_PFD_480_PFD1_FRAC_SHIFT));
1326             break;
1327 
1328         case kCLOCK_Pfd2:
1329             freq = (uint32_t)(tmp64 / (uint64_t)((CCM_ANALOG->PFD_480 & CCM_ANALOG_PFD_480_PFD2_FRAC_MASK) >> CCM_ANALOG_PFD_480_PFD2_FRAC_SHIFT));
1330             break;
1331 
1332         case kCLOCK_Pfd3:
1333             freq = (uint32_t)(tmp64 / (uint64_t)((CCM_ANALOG->PFD_480 & CCM_ANALOG_PFD_480_PFD3_FRAC_MASK) >> CCM_ANALOG_PFD_480_PFD3_FRAC_SHIFT));
1334             break;
1335 
1336         default:
1337             freq = 0U;
1338             break;
1339     }
1340 
1341     return freq;
1342 }
1343 
1344 /*! brief Enable USB HS PHY PLL clock.
1345  *
1346  * This function enables the internal 480MHz USB PHY PLL clock.
1347  *
1348  * param src  USB HS PHY PLL clock source.
1349  * param freq The frequency specified by src.
1350  * retval true The clock is set successfully.
1351  * retval false The clock source is invalid to get proper USB HS clock.
1352  */
CLOCK_EnableUsbhs1PhyPllClock(clock_usb_phy_src_t src,uint32_t freq)1353 bool CLOCK_EnableUsbhs1PhyPllClock(clock_usb_phy_src_t src, uint32_t freq)
1354 {
1355     static const clock_usb_pll_config_t g_ccmConfigUsbPll = {.loopDivider = 0U};
1356     CLOCK_InitUsb2Pll(&g_ccmConfigUsbPll);
1357     USBPHY2->CTRL &= ~USBPHY_CTRL_SFTRST_MASK; /* release PHY from reset */
1358     USBPHY2->CTRL &= ~USBPHY_CTRL_CLKGATE_MASK;
1359 
1360     USBPHY2->PWD = 0;
1361     USBPHY2->CTRL |= USBPHY_CTRL_ENAUTOCLR_PHY_PWD_MASK | USBPHY_CTRL_ENAUTOCLR_CLKGATE_MASK |
1362                      USBPHY_CTRL_ENUTMILEVEL2_MASK | USBPHY_CTRL_ENUTMILEVEL3_MASK;
1363 
1364     return true;
1365 }
1366 
1367 /*! brief Disable USB HS PHY PLL clock.
1368  *
1369  * This function disables USB HS PHY PLL clock.
1370  */
CLOCK_DisableUsbhs1PhyPllClock(void)1371 void CLOCK_DisableUsbhs1PhyPllClock(void)
1372 {
1373     CCM_ANALOG->PLL_USB2 &= ~CCM_ANALOG_PLL_USB2_EN_USB_CLKS_MASK;
1374     USBPHY2->CTRL |= USBPHY_CTRL_CLKGATE_MASK; /* Set to 1U to gate clocks */
1375 }
1376 
1377 /*!
1378  * brief Set the clock source and the divider of the clock output1.
1379  *
1380  * param selection The clock source to be output, please refer to clock_output1_selection_t.
1381  * param divider The divider of the output clock signal, please refer to clock_output_divider_t.
1382  */
CLOCK_SetClockOutput1(clock_output1_selection_t selection,clock_output_divider_t divider)1383 void CLOCK_SetClockOutput1(clock_output1_selection_t selection, clock_output_divider_t divider)
1384 {
1385     uint32_t tmp32;
1386 
1387     tmp32 = CCM->CCOSR;
1388     if (selection == kCLOCK_DisableClockOutput1)
1389     {
1390         tmp32 &= ~CCM_CCOSR_CLKO1_EN_MASK;
1391     }
1392     else
1393     {
1394         tmp32 |= CCM_CCOSR_CLKO1_EN_MASK;
1395         tmp32 &= ~(CCM_CCOSR_CLKO1_SEL_MASK | CCM_CCOSR_CLKO1_DIV_MASK);
1396         tmp32 |= CCM_CCOSR_CLKO1_SEL(selection) | CCM_CCOSR_CLKO1_DIV(divider);
1397     }
1398     CCM->CCOSR = tmp32;
1399 }
1400 
1401 /*!
1402  * brief Set the clock source and the divider of the clock output2.
1403  *
1404  * param selection The clock source to be output, please refer to clock_output2_selection_t.
1405  * param divider The divider of the output clock signal, please refer to clock_output_divider_t.
1406  */
CLOCK_SetClockOutput2(clock_output2_selection_t selection,clock_output_divider_t divider)1407 void CLOCK_SetClockOutput2(clock_output2_selection_t selection, clock_output_divider_t divider)
1408 {
1409     uint32_t tmp32;
1410 
1411     tmp32 = CCM->CCOSR;
1412     if (selection == kCLOCK_DisableClockOutput2)
1413     {
1414         tmp32 &= CCM_CCOSR_CLKO2_EN_MASK;
1415     }
1416     else
1417     {
1418         tmp32 |= CCM_CCOSR_CLKO2_EN_MASK;
1419         tmp32 &= ~(CCM_CCOSR_CLKO2_SEL_MASK | CCM_CCOSR_CLKO2_DIV_MASK);
1420         tmp32 |= CCM_CCOSR_CLKO2_SEL(selection) | CCM_CCOSR_CLKO2_DIV(divider);
1421     }
1422 
1423     CCM->CCOSR = tmp32;
1424 }
1425 
1426 /*!
1427  * brief Get the frequency of clock output1 clock signal.
1428  *
1429  * return The frequency of clock output1 clock signal.
1430  */
CLOCK_GetClockOutCLKO1Freq(void)1431 uint32_t CLOCK_GetClockOutCLKO1Freq(void)
1432 {
1433     uint32_t freq = 0U;
1434     uint32_t tmp32;
1435 
1436     tmp32 = CCM->CCOSR;
1437 
1438     if ((tmp32 & CCM_CCOSR_CLKO1_EN_MASK) != 0UL)
1439     {
1440         switch ((tmp32 & CCM_CCOSR_CLKO1_SEL_MASK) >> CCM_CCOSR_CLKO1_SEL_SHIFT)
1441         {
1442             case (uint32_t)kCLOCK_OutputPllUsb1:
1443                 freq = CLOCK_GetPllFreq(kCLOCK_PllUsb1) / 2U;
1444                 break;
1445             case (uint32_t)kCLOCK_OutputPllSys:
1446                 freq = CLOCK_GetPllFreq(kCLOCK_PllSys) / 2U;
1447                 break;
1448             case (uint32_t)kCLOCK_OutputPllVideo:
1449                 freq = CLOCK_GetPllFreq(kCLOCK_PllVideo) / 2U;
1450                 break;
1451             case (uint32_t)kCLOCK_OutputSemcClk:
1452                 freq = CLOCK_GetSemcFreq();
1453                 break;
1454             case (uint32_t)kCLOCK_OutputLcdifPixClk:
1455                 freq = CLOCK_GetClockRootFreq(kCLOCK_LcdifClkRoot);
1456                 break;
1457             case (uint32_t)kCLOCK_OutputAhbClk:
1458                 freq = CLOCK_GetAhbFreq();
1459                 break;
1460             case (uint32_t)kCLOCK_OutputIpgClk:
1461                 freq = CLOCK_GetIpgFreq();
1462                 break;
1463             case (uint32_t)kCLOCK_OutputPerClk:
1464                 freq = CLOCK_GetPerClkFreq();
1465                 break;
1466             case (uint32_t)kCLOCK_OutputCkilSyncClk:
1467                 freq = CLOCK_GetRtcFreq();
1468                 break;
1469             case (uint32_t)kCLOCK_OutputPll4MainClk:
1470                 freq = CLOCK_GetPllFreq(kCLOCK_PllAudio);
1471                 break;
1472             default:
1473                 /* This branch should never be hit. */
1474                 break;
1475         }
1476 
1477         freq /= (((tmp32 & CCM_CCOSR_CLKO1_DIV_MASK) >> CCM_CCOSR_CLKO1_DIV_SHIFT) + 1U);
1478     }
1479     else
1480     {
1481         freq = 0UL;
1482     }
1483 
1484     return freq;
1485 }
1486 
1487 /*!
1488  * brief Get the frequency of clock output2 clock signal.
1489  *
1490  * return The frequency of clock output2 clock signal.
1491  */
CLOCK_GetClockOutClkO2Freq(void)1492 uint32_t CLOCK_GetClockOutClkO2Freq(void)
1493 {
1494     uint32_t freq = 0U;
1495     uint32_t tmp32;
1496 
1497     tmp32 = CCM->CCOSR;
1498 
1499     if ((tmp32 & CCM_CCOSR_CLKO2_EN_MASK) != 0UL)
1500     {
1501         switch ((tmp32 & CCM_CCOSR_CLKO2_SEL_MASK) >> CCM_CCOSR_CLKO2_SEL_SHIFT)
1502         {
1503             case (uint32_t)kCLOCK_OutputUsdhc1Clk:
1504                 freq = CLOCK_GetClockRootFreq(kCLOCK_Usdhc1ClkRoot);
1505                 break;
1506             case (uint32_t)kCLOCK_OutputLpi2cClk:
1507                 freq = CLOCK_GetClockRootFreq(kCLOCK_Lpi2cClkRoot);
1508                 break;
1509             case (uint32_t)kCLOCK_OutputCsiClk:
1510                 freq = CLOCK_GetClockRootFreq(kCLOCK_CsiClkRoot);
1511                 break;
1512             case (uint32_t)kCLOCK_OutputOscClk:
1513                 freq = CLOCK_GetOscFreq();
1514                 break;
1515             case (uint32_t)kCLOCK_OutputUsdhc2Clk:
1516                 freq = CLOCK_GetClockRootFreq(kCLOCK_Usdhc2ClkRoot);
1517                 break;
1518             case (uint32_t)kCLOCK_OutputSai1Clk:
1519                 freq = CLOCK_GetClockRootFreq(kCLOCK_Sai1ClkRoot);
1520                 break;
1521             case (uint32_t)kCLOCK_OutputSai2Clk:
1522                 freq = CLOCK_GetClockRootFreq(kCLOCK_Sai2ClkRoot);
1523                 break;
1524             case (uint32_t)kCLOCK_OutputSai3Clk:
1525                 freq = CLOCK_GetClockRootFreq(kCLOCK_Sai3ClkRoot);
1526                 break;
1527             case (uint32_t)kCLOCK_OutputCanClk:
1528                 freq = CLOCK_GetClockRootFreq(kCLOCK_CanClkRoot);
1529                 break;
1530             case (uint32_t)kCLOCK_OutputFlexspiClk:
1531                 freq = CLOCK_GetClockRootFreq(kCLOCK_FlexspiClkRoot);
1532                 break;
1533             case (uint32_t)kCLOCK_OutputUartClk:
1534                 freq = CLOCK_GetClockRootFreq(kCLOCK_UartClkRoot);
1535                 break;
1536             case (uint32_t)kCLOCK_OutputSpdif0Clk:
1537                 freq = CLOCK_GetClockRootFreq(kCLOCK_SpdifClkRoot);
1538                 break;
1539             default:
1540                 /* This branch should never be hit. */
1541                 break;
1542         }
1543 
1544         freq /= (((tmp32 & CCM_CCOSR_CLKO2_DIV_MASK) >> CCM_CCOSR_CLKO2_DIV_SHIFT) + 1U);
1545     }
1546     else
1547     {
1548         freq = 0UL;
1549     }
1550 
1551     return freq;
1552 }
1553