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