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