1 /*
2 * Copyright 2019 NXP
3 * All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7 #include "fsl_common.h"
8 #include "fsl_clock.h"
9
10 /*******************************************************************************
11 * Definitions
12 ******************************************************************************/
13 /* Component ID definition, used by tools. */
14 #ifndef FSL_COMPONENT_ID
15 #define FSL_COMPONENT_ID "platform.drivers.clock"
16 #endif
17
18 #define FracPLL_GNRL_CTL_Offset (0U)
19 #define FracPLL_FDIV_CTL0_Offset (4U)
20 #define FracPLL_FDIV_CTL1_Offset (8U)
21
22 #define IntegerPLL_GNRL_CTL_Offset (0U)
23 #define IntegerPLL_DIV_CTL_Offset (4U)
24 /*******************************************************************************
25 * Prototypes
26 ******************************************************************************/
27
28 /*******************************************************************************
29 * Variables
30 ******************************************************************************/
31
32 /*******************************************************************************
33 * Code
34 ******************************************************************************/
35 /*!
36 * brief Gets the clock frequency for a specific clock name.
37 *
38 * This function checks the current clock configurations and then calculates
39 * the clock frequency for a specific clock name defined in clock_name_t.
40 *
41 * param clockName Clock names defined in clock_name_t
42 * return Clock frequency value in hertz
43 */
CLOCK_GetFreq(clock_name_t clockName)44 uint32_t CLOCK_GetFreq(clock_name_t clockName)
45 {
46 uint32_t freq;
47 uint32_t temp;
48
49 switch (clockName)
50 {
51 case kCLOCK_CoreM7Clk:
52 freq = CLOCK_GetCoreM7Freq();
53 break;
54 case kCLOCK_AxiClk:
55 freq = CLOCK_GetAxiFreq();
56 break;
57 case kCLOCK_AhbClk:
58 freq = CLOCK_GetAhbFreq();
59 break;
60 case kCLOCK_IpgClk:
61 {
62 temp = CLOCK_GetAhbFreq();
63 freq = temp / CLOCK_GetRootPostDivider(kCLOCK_RootIpg);
64 break;
65 }
66 case kCLOCK_EnetIpgClk:
67 freq = CLOCK_GetEnetAxiFreq();
68 break;
69 case kCLOCK_Osc24MClk:
70 freq = OSC24M_CLK_FREQ;
71 break;
72 case kCLOCK_ArmPllClk:
73 freq = CLOCK_GetPllFreq(kCLOCK_ArmPllCtrl);
74 break;
75 case kCLOCK_DramPllClk:
76 freq = CLOCK_GetPllFreq(kCLOCK_DramPllCtrl);
77 break;
78 case kCLOCK_VpuPllClk:
79 freq = CLOCK_GetPllFreq(kCLOCK_VpuPllCtrl);
80 break;
81 case kCLOCK_SysPll1Clk:
82 freq = CLOCK_GetPllFreq(kCLOCK_SystemPll1Ctrl);
83 break;
84 case kCLOCK_SysPll1Div2Clk:
85 freq = CLOCK_GetPllFreq(kCLOCK_SystemPll1Ctrl) / 2U;
86 break;
87 case kCLOCK_SysPll1Div3Clk:
88 freq = CLOCK_GetPllFreq(kCLOCK_SystemPll1Ctrl) / 3U;
89 break;
90 case kCLOCK_SysPll1Div4Clk:
91 freq = CLOCK_GetPllFreq(kCLOCK_SystemPll1Ctrl) / 4U;
92 break;
93 case kCLOCK_SysPll1Div5Clk:
94 freq = CLOCK_GetPllFreq(kCLOCK_SystemPll1Ctrl) / 5U;
95 break;
96 case kCLOCK_SysPll1Div6Clk:
97 freq = CLOCK_GetPllFreq(kCLOCK_SystemPll1Ctrl) / 6U;
98 break;
99 case kCLOCK_SysPll1Div8Clk:
100 freq = CLOCK_GetPllFreq(kCLOCK_SystemPll1Ctrl) / 8U;
101 break;
102 case kCLOCK_SysPll1Div10Clk:
103 freq = CLOCK_GetPllFreq(kCLOCK_SystemPll1Ctrl) / 10U;
104 break;
105 case kCLOCK_SysPll1Div20Clk:
106 freq = CLOCK_GetPllFreq(kCLOCK_SystemPll1Ctrl) / 20U;
107 break;
108 case kCLOCK_SysPll2Clk:
109 freq = CLOCK_GetPllFreq(kCLOCK_SystemPll2Ctrl);
110 break;
111 case kCLOCK_SysPll2Div2Clk:
112 freq = CLOCK_GetPllFreq(kCLOCK_SystemPll2Ctrl) / 2U;
113 break;
114 case kCLOCK_SysPll2Div3Clk:
115 freq = CLOCK_GetPllFreq(kCLOCK_SystemPll2Ctrl) / 3U;
116 break;
117 case kCLOCK_SysPll2Div4Clk:
118 freq = CLOCK_GetPllFreq(kCLOCK_SystemPll2Ctrl) / 4U;
119 break;
120 case kCLOCK_SysPll2Div5Clk:
121 freq = CLOCK_GetPllFreq(kCLOCK_SystemPll2Ctrl) / 5U;
122 break;
123 case kCLOCK_SysPll2Div6Clk:
124 freq = CLOCK_GetPllFreq(kCLOCK_SystemPll2Ctrl) / 6U;
125 break;
126 case kCLOCK_SysPll2Div8Clk:
127 freq = CLOCK_GetPllFreq(kCLOCK_SystemPll2Ctrl) / 8U;
128 break;
129 case kCLOCK_SysPll2Div10Clk:
130 freq = CLOCK_GetPllFreq(kCLOCK_SystemPll2Ctrl) / 10U;
131 break;
132 case kCLOCK_SysPll2Div20Clk:
133 freq = CLOCK_GetPllFreq(kCLOCK_SystemPll2Ctrl) / 20U;
134 break;
135 case kCLOCK_SysPll3Clk:
136 freq = CLOCK_GetPllFreq(kCLOCK_SystemPll3Ctrl);
137 break;
138 case kCLOCK_AudioPll1Clk:
139 freq = CLOCK_GetPllFreq(kCLOCK_AudioPll1Ctrl);
140 break;
141 case kCLOCK_AudioPll2Clk:
142 freq = CLOCK_GetPllFreq(kCLOCK_AudioPll2Ctrl);
143 break;
144 case kCLOCK_VideoPll1Clk:
145 freq = CLOCK_GetPllFreq(kCLOCK_VideoPll1Ctrl);
146 break;
147 case kCLOCK_ExtClk1:
148 case kCLOCK_ExtClk2:
149 case kCLOCK_ExtClk3:
150 case kCLOCK_ExtClk4:
151 freq = CLKPAD_FREQ;
152 break;
153 default:
154 freq = 0U;
155 break;
156 }
157 return freq;
158 }
159
160 /*!
161 * brief Gets the frequency of selected clock root.
162 *
163 * param clockRoot The clock root used to get the frequency, please refer to @ref clock_root_t.
164 * return The frequency of selected clock root.
165 */
CLOCK_GetClockRootFreq(clock_root_t clockRoot)166 uint32_t CLOCK_GetClockRootFreq(clock_root_t clockRoot)
167 {
168 static const clock_name_t clockRootSourceArray[][8] = CLOCK_ROOT_SOURCE;
169 static const clock_root_control_t clockRootControlArray[] = CLOCK_ROOT_CONTROL_TUPLE;
170
171 clock_root_control_t clockRootControl = clockRootControlArray[(uint8_t)clockRoot];
172
173 uint32_t freq = 0U;
174 uint32_t pre = CLOCK_GetRootPreDivider(clockRootControl);
175 uint32_t post = CLOCK_GetRootPostDivider(clockRootControl);
176 uint32_t mux = CLOCK_GetRootMux(clockRootControl);
177
178 clock_name_t clockSourceName;
179
180 clockSourceName = clockRootSourceArray[(uint8_t)clockRoot][mux];
181
182 assert(clockSourceName != kCLOCK_NoneName);
183
184 freq = CLOCK_GetFreq(clockSourceName);
185
186 if (clockRoot == kCLOCK_IpgClkRoot)
187 {
188 freq /= CLOCK_GetRootPostDivider(kCLOCK_RootIpg);
189 }
190 if (clockRoot == kCLOCK_AudioIpgClkRoot)
191 {
192 freq /= CLOCK_GetRootPostDivider(kCLOCK_RootAudioIpg);
193 }
194
195 return freq / pre / post;
196 }
197
198 /*!
199 * brief Get the CCM Cortex M7 core frequency.
200 *
201 * return Clock frequency; If the clock is invalid, returns 0.
202 */
CLOCK_GetCoreM7Freq(void)203 uint32_t CLOCK_GetCoreM7Freq(void)
204 {
205 uint32_t freq;
206 uint32_t pre = CLOCK_GetRootPreDivider(kCLOCK_RootM7);
207 uint32_t post = CLOCK_GetRootPostDivider(kCLOCK_RootM7);
208
209 switch (CLOCK_GetRootMux(kCLOCK_RootM7))
210 {
211 case (uint32_t)kCLOCK_M7RootmuxOsc24M:
212 freq = OSC24M_CLK_FREQ;
213 break;
214 case (uint32_t)kCLOCK_M7RootmuxSysPll2Div5:
215 freq = CLOCK_GetPllFreq(kCLOCK_SystemPll2Ctrl) / 5U;
216 break;
217 case (uint32_t)kCLOCK_M7RootmuxSysPll2Div4:
218 freq = CLOCK_GetPllFreq(kCLOCK_SystemPll2Ctrl) / 4U;
219 break;
220 case (uint32_t)kCLOCK_M7RootmuxSysVpuPll:
221 freq = CLOCK_GetPllFreq(kCLOCK_VpuPllCtrl);
222 break;
223 case (uint32_t)kCLOCK_M7RootmuxSysPll1:
224 freq = CLOCK_GetPllFreq(kCLOCK_SystemPll1Ctrl);
225 break;
226 case (uint32_t)kCLOCK_M7RootmuxAudioPll1:
227 freq = CLOCK_GetPllFreq(kCLOCK_AudioPll1Ctrl);
228 break;
229 case (uint32_t)kCLOCK_M7RootmuxVideoPll1:
230 freq = CLOCK_GetPllFreq(kCLOCK_VideoPll1Ctrl);
231 break;
232 case (uint32_t)kCLOCK_M7RootmuxSysPll3:
233 freq = CLOCK_GetPllFreq(kCLOCK_SystemPll3Ctrl);
234 break;
235 default:
236 freq = 0U;
237 break;
238 }
239
240 return freq / pre / post;
241 }
242
243 /*!
244 * brief Get the CCM Axi bus frequency.
245 *
246 * return Clock frequency; If the clock is invalid, returns 0.
247 */
CLOCK_GetAxiFreq(void)248 uint32_t CLOCK_GetAxiFreq(void)
249 {
250 uint32_t freq;
251 uint32_t pre = CLOCK_GetRootPreDivider(kCLOCK_RootMainAxi);
252 uint32_t post = CLOCK_GetRootPostDivider(kCLOCK_RootMainAxi);
253
254 switch (CLOCK_GetRootMux(kCLOCK_RootMainAxi))
255 {
256 case (uint32_t)kCLOCK_AxiRootmuxOsc24M:
257 freq = OSC24M_CLK_FREQ;
258 break;
259 case (uint32_t)kCLOCK_AxiRootmuxSysPll2Div3:
260 freq = CLOCK_GetPllFreq(kCLOCK_SystemPll2Ctrl) / 3U;
261 break;
262 case (uint32_t)kCLOCK_AxiRootmuxSysPll2Div4:
263 freq = CLOCK_GetPllFreq(kCLOCK_SystemPll2Ctrl) / 4U;
264 break;
265 case (uint32_t)kCLOCK_AxiRootmuxSysPll2:
266 freq = CLOCK_GetPllFreq(kCLOCK_SystemPll2Ctrl);
267 break;
268 case (uint32_t)kCLOCK_AxiRootmuxAudioPll1:
269 freq = CLOCK_GetPllFreq(kCLOCK_AudioPll1Ctrl);
270 break;
271 case (uint32_t)kCLOCK_AxiRootmuxVideoPll1:
272 freq = CLOCK_GetPllFreq(kCLOCK_VideoPll1Ctrl);
273 break;
274 case (uint32_t)kCLOCK_AxiRootmuxSysPll1Div8:
275 freq = CLOCK_GetPllFreq(kCLOCK_SystemPll1Ctrl) / 8UL;
276 break;
277 case (uint32_t)kCLOCK_AxiRootmuxSysPll1:
278 freq = CLOCK_GetPllFreq(kCLOCK_SystemPll1Ctrl);
279 break;
280 default:
281 freq = 0U;
282 break;
283 }
284
285 return freq / pre / post;
286 }
287
288 /*!
289 * brief Get the CCM Ahb bus frequency.
290 *
291 * return Clock frequency; If the clock is invalid, returns 0.
292 */
CLOCK_GetAhbFreq(void)293 uint32_t CLOCK_GetAhbFreq(void)
294 {
295 uint32_t freq;
296 uint32_t pre = CLOCK_GetRootPreDivider(kCLOCK_RootAhb);
297 uint32_t post = CLOCK_GetRootPostDivider(kCLOCK_RootAhb);
298
299 switch (CLOCK_GetRootMux(kCLOCK_RootAhb))
300 {
301 case (uint32_t)kCLOCK_AhbRootmuxOsc24M:
302 freq = OSC24M_CLK_FREQ;
303 break;
304 case (uint32_t)kCLOCK_AhbRootmuxSysPll1Div6:
305 freq = CLOCK_GetPllFreq(kCLOCK_SystemPll1Ctrl) / 6U;
306 break;
307 case (uint32_t)kCLOCK_AhbRootmuxSysPll1Div2:
308 freq = CLOCK_GetPllFreq(kCLOCK_SystemPll1Ctrl) / 2U;
309 break;
310 case (uint32_t)kCLOCK_AhbRootmuxSysPll1:
311 freq = CLOCK_GetPllFreq(kCLOCK_SystemPll1Ctrl);
312 break;
313 case (uint32_t)kCLOCK_AhbRootmuxSysPll2Div8:
314 freq = CLOCK_GetPllFreq(kCLOCK_SystemPll2Ctrl) / 8U;
315 break;
316 case (uint32_t)kCLOCK_AhbRootmuxSysPll3:
317 freq = CLOCK_GetPllFreq(kCLOCK_SystemPll3Ctrl);
318 break;
319 case (uint32_t)kCLOCK_AhbRootmuxAudioPll1:
320 freq = CLOCK_GetPllFreq(kCLOCK_AudioPll1Ctrl);
321 break;
322 case (uint32_t)kCLOCK_AhbRootmuxVideoPll1:
323 freq = CLOCK_GetPllFreq(kCLOCK_VideoPll1Ctrl);
324 break;
325 default:
326 freq = 0U;
327 break;
328 }
329
330 return freq / pre / post;
331 }
332
333 /*!
334 * brief Get the CCM Enet AXI bus frequency.
335 *
336 * return Clock frequency; If the clock is invalid, returns 0.
337 */
CLOCK_GetEnetAxiFreq(void)338 uint32_t CLOCK_GetEnetAxiFreq(void)
339 {
340 uint32_t freq;
341 uint32_t pre = CLOCK_GetRootPreDivider(kCLOCK_RootEnetAxi);
342 uint32_t post = CLOCK_GetRootPostDivider(kCLOCK_RootEnetAxi);
343
344 switch (CLOCK_GetRootMux(kCLOCK_RootEnetAxi))
345 {
346 case (uint32_t)kCLOCK_EnetAxiRootmuxOsc24M:
347 freq = OSC24M_CLK_FREQ;
348 break;
349 case (uint32_t)kCLOCK_EnetAxiRootmuxSysPll1Div3:
350 freq = CLOCK_GetPllFreq(kCLOCK_SystemPll1Ctrl) / 3U;
351 break;
352 case (uint32_t)kCLOCK_EnetAxiRootmuxSysPll1:
353 freq = CLOCK_GetPllFreq(kCLOCK_SystemPll1Ctrl);
354 break;
355 case (uint32_t)kCLOCK_EnetAxiRootmuxSysPll2Div4:
356 freq = CLOCK_GetPllFreq(kCLOCK_SystemPll2Ctrl) / 4U;
357 break;
358 case (uint32_t)kCLOCK_EnetAxiRootmuxSysPll2Div5:
359 freq = CLOCK_GetPllFreq(kCLOCK_SystemPll2Ctrl) / 5U;
360 break;
361 case (uint32_t)kCLOCK_EnetAxiRootmuxAudioPll1:
362 freq = CLOCK_GetPllFreq(kCLOCK_AudioPll1Ctrl);
363 break;
364 case (uint32_t)kCLOCK_EnetAxiRootmuxVideoPll1:
365 freq = CLOCK_GetPllFreq(kCLOCK_VideoPll1Ctrl);
366 break;
367 case (uint32_t)kCLOCK_EnetAxiRootmuxSysPll3:
368 freq = CLOCK_GetPllFreq(kCLOCK_SystemPll3Ctrl);
369 break;
370 default:
371 freq = 0U;
372 break;
373 }
374
375 return freq / pre / post;
376 }
377
378 /*!
379 * brief Gets PLL reference clock frequency.
380 *
381 * param type fractional pll type.
382
383 * return Clock frequency
384 */
CLOCK_GetPllRefClkFreq(clock_pll_ctrl_t ctrl)385 uint32_t CLOCK_GetPllRefClkFreq(clock_pll_ctrl_t ctrl)
386 {
387 uint32_t refClkFreq = 0U;
388 uint8_t clkSel = 0U;
389
390 if (ctrl < kCLOCK_ArmPllCtrl)
391 {
392 clkSel =
393 (uint8_t)((CCM_ANALOG_TUPLE_REG(CCM_ANALOG, ctrl) & CCM_ANALOG_AUDIO_PLL1_GEN_CTRL_PLL_REF_CLK_SEL_MASK));
394 }
395 else
396 {
397 clkSel = (uint8_t)(CCM_ANALOG_TUPLE_REG(CCM_ANALOG, ctrl) & CCM_ANALOG_SYS_PLL1_GEN_CTRL_PLL_REF_CLK_SEL_MASK);
398 }
399
400 switch (clkSel)
401 {
402 case kANALOG_PllRefOsc24M:
403 refClkFreq = OSC24M_CLK_FREQ;
404 break;
405
406 case kANALOG_PllPadClk:
407 /* The value of PAD CLK need user to define according to the actual condition. */
408 refClkFreq = CLKPAD_FREQ;
409 break;
410
411 default:
412 refClkFreq = 0U;
413 break;
414 }
415
416 return refClkFreq;
417 }
418
419 /*!
420 * brief Gets PLL clock frequency.
421 *
422 * param type fractional pll type.
423
424 * return Clock frequency
425 */
CLOCK_GetPllFreq(clock_pll_ctrl_t pll)426 uint32_t CLOCK_GetPllFreq(clock_pll_ctrl_t pll)
427 {
428 uint32_t pllFreq = 0U;
429 uint32_t pllRefFreq = 0U;
430 bool intergerPllBypass = false;
431 bool fracPllBypass = false;
432
433 pllRefFreq = CLOCK_GetPllRefClkFreq(pll);
434
435 switch (pll)
436 {
437 /* Integer PLL frequency */
438 case kCLOCK_ArmPllCtrl:
439 intergerPllBypass = CLOCK_IsPllBypassed(CCM_ANALOG, kCLOCK_ArmPllPwrBypassCtrl);
440 break;
441 case kCLOCK_SystemPll1Ctrl:
442 intergerPllBypass = CLOCK_IsPllBypassed(CCM_ANALOG, kCLOCK_SysPll1InternalPll1BypassCtrl);
443 break;
444 case kCLOCK_SystemPll2Ctrl:
445 intergerPllBypass = CLOCK_IsPllBypassed(CCM_ANALOG, kCLOCK_SysPll2InternalPll1BypassCtrl);
446 break;
447 case kCLOCK_SystemPll3Ctrl:
448 intergerPllBypass = CLOCK_IsPllBypassed(CCM_ANALOG, kCLOCK_SysPll3InternalPll1BypassCtrl);
449 break;
450 /* Fractional PLL frequency */
451 case kCLOCK_AudioPll1Ctrl:
452 fracPllBypass = CLOCK_IsPllBypassed(CCM_ANALOG, kCLOCK_AudioPll1BypassCtrl);
453 break;
454 case kCLOCK_AudioPll2Ctrl:
455 fracPllBypass = CLOCK_IsPllBypassed(CCM_ANALOG, kCLOCK_AudioPll2BypassCtrl);
456 break;
457 case kCLOCK_VideoPll1Ctrl:
458 fracPllBypass = CLOCK_IsPllBypassed(CCM_ANALOG, kCLOCK_VideoPll1BypassCtrl);
459 break;
460 case kCLOCK_DramPllCtrl:
461 fracPllBypass = CLOCK_IsPllBypassed(CCM_ANALOG, kCLOCK_DramPllInternalPll1BypassCtrl);
462 break;
463 default:
464 fracPllBypass = false;
465 break;
466 }
467 if (pll < kCLOCK_ArmPllCtrl)
468 {
469 if (fracPllBypass)
470 {
471 pllFreq = pllRefFreq;
472 }
473 else
474 {
475 pllFreq = CLOCK_GetFracPllFreq(CCM_ANALOG, pll, pllRefFreq);
476 }
477 }
478 else
479 {
480 if (intergerPllBypass)
481 {
482 /* if PLL is bypass, return reference clock directly */
483 pllFreq = pllRefFreq;
484 }
485 else
486 {
487 pllFreq = CLOCK_GetIntegerPllFreq(CCM_ANALOG, pll, pllRefFreq, false);
488 }
489 }
490
491 return (uint32_t)pllFreq;
492 }
493
494 /*!
495 * brief Initializes the ANALOG ARM PLL.
496 *
497 * param config Pointer to the configuration structure(see ref ccm_analog_integer_pll_config_t enumeration).
498 *
499 * note This function can't detect whether the Arm PLL has been enabled and
500 * used by some IPs.
501 */
CLOCK_InitArmPll(const ccm_analog_integer_pll_config_t * config)502 void CLOCK_InitArmPll(const ccm_analog_integer_pll_config_t *config)
503 {
504 assert(config != NULL);
505
506 /* Integer PLL configuration */
507 CLOCK_InitIntegerPll(CCM_ANALOG, config, kCLOCK_ArmPllCtrl);
508 /* Disable PLL bypass */
509 CLOCK_SetPllBypass(CCM_ANALOG, kCLOCK_ArmPllPwrBypassCtrl, false);
510 /* Enable and power up PLL clock. */
511 CLOCK_EnableAnalogClock(CCM_ANALOG, kCLOCK_ArmPllClke);
512
513 /* Wait for PLL to be locked. */
514 while (!CLOCK_IsPllLocked(CCM_ANALOG, kCLOCK_ArmPllCtrl))
515 {
516 }
517 }
518
519 /*!
520 * brief De-initialize the ARM PLL.
521 */
CLOCK_DeinitArmPll(void)522 void CLOCK_DeinitArmPll(void)
523 {
524 CLOCK_PowerDownPll(CCM_ANALOG, kCLOCK_ArmPllCtrl);
525 }
526
527 /*!
528 * brief Initializes the ANALOG AUDIO PLL1.
529 *
530 * param config Pointer to the configuration structure(see ref ccm_analog_frac_pll_config_t enumeration).
531 *
532 * note This function can't detect whether the AUDIO PLL has been enabled and
533 * used by some IPs.
534 */
CLOCK_InitAudioPll1(const ccm_analog_frac_pll_config_t * config)535 void CLOCK_InitAudioPll1(const ccm_analog_frac_pll_config_t *config)
536 {
537 assert(config != NULL);
538
539 /* Disable PLL bypass */
540 CLOCK_SetPllBypass(CCM_ANALOG, kCLOCK_AudioPll1BypassCtrl, false);
541 /* Fractional pll configuration */
542 CLOCK_InitFracPll(CCM_ANALOG, config, kCLOCK_AudioPll1Ctrl);
543 /* Enable and power up PLL clock. */
544 CLOCK_EnableAnalogClock(CCM_ANALOG, kCLOCK_AudioPll1Clke);
545
546 /* Wait for PLL to be locked. */
547 while (!CLOCK_IsPllLocked(CCM_ANALOG, kCLOCK_AudioPll1Ctrl))
548 {
549 }
550 }
551
552 /*!
553 * brief De-initialize the Audio PLL1.
554 */
CLOCK_DeinitAudioPll1(void)555 void CLOCK_DeinitAudioPll1(void)
556 {
557 CLOCK_PowerDownPll(CCM_ANALOG, kCLOCK_AudioPll1Ctrl);
558 }
559
560 /*!
561 * brief Initializes the ANALOG AUDIO PLL2.
562 *
563 * param config Pointer to the configuration structure(see ref ccm_analog_frac_pll_config_t enumeration).
564 *
565 * note This function can't detect whether the AUDIO PLL has been enabled and
566 * used by some IPs.
567 */
CLOCK_InitAudioPll2(const ccm_analog_frac_pll_config_t * config)568 void CLOCK_InitAudioPll2(const ccm_analog_frac_pll_config_t *config)
569 {
570 assert(config != NULL);
571
572 /* Disable PLL bypass */
573 CLOCK_SetPllBypass(CCM_ANALOG, kCLOCK_AudioPll2BypassCtrl, false);
574 /* Fractional pll configuration */
575 CLOCK_InitFracPll(CCM_ANALOG, config, kCLOCK_AudioPll2Ctrl);
576 /* Enable and power up PLL clock. */
577 CLOCK_EnableAnalogClock(CCM_ANALOG, kCLOCK_AudioPll2Clke);
578
579 /* Wait for PLL to be locked. */
580 while (!CLOCK_IsPllLocked(CCM_ANALOG, kCLOCK_AudioPll2Ctrl))
581 {
582 }
583 }
584
585 /*!
586 * brief De-initialize the Audio PLL2.
587 */
CLOCK_DeinitAudioPll2(void)588 void CLOCK_DeinitAudioPll2(void)
589 {
590 CLOCK_PowerDownPll(CCM_ANALOG, kCLOCK_AudioPll2Ctrl);
591 }
592
593 /*!
594 * brief Initializes the ANALOG VIDEO PLL1.
595 *
596 * param config Pointer to the configuration structure(see ref ccm_analog_frac_pll_config_t enumeration).
597 *
598 */
CLOCK_InitVideoPll1(const ccm_analog_frac_pll_config_t * config)599 void CLOCK_InitVideoPll1(const ccm_analog_frac_pll_config_t *config)
600 {
601 assert(config != NULL);
602
603 /* Disable PLL bypass */
604 CLOCK_SetPllBypass(CCM_ANALOG, kCLOCK_VideoPll1BypassCtrl, false);
605 /* Fractional pll configuration */
606 CLOCK_InitFracPll(CCM_ANALOG, config, kCLOCK_VideoPll1Ctrl);
607 /* Enable and power up PLL clock. */
608 CLOCK_EnableAnalogClock(CCM_ANALOG, kCLOCK_VideoPll1Clke);
609
610 /* Wait for PLL to be locked. */
611 while (!CLOCK_IsPllLocked(CCM_ANALOG, kCLOCK_VideoPll1Ctrl))
612 {
613 }
614 }
615
616 /*!
617 * brief De-initialize the Video PLL1.
618 */
CLOCK_DeinitVideoPll1(void)619 void CLOCK_DeinitVideoPll1(void)
620 {
621 CLOCK_PowerDownPll(CCM_ANALOG, kCLOCK_VideoPll1Ctrl);
622 }
623
624 /*!
625 * brief Initializes the ANALOG SYS PLL1.
626 *
627 * param config Pointer to the configuration structure(see ref ccm_analog_integer_pll_config_t enumeration).
628 *
629 * note This function can't detect whether the SYS PLL has been enabled and
630 * used by some IPs.
631 */
CLOCK_InitSysPll1(const ccm_analog_integer_pll_config_t * config)632 void CLOCK_InitSysPll1(const ccm_analog_integer_pll_config_t *config)
633 {
634 assert(config != NULL);
635
636 /* Integer PLL configuration */
637 CLOCK_InitIntegerPll(CCM_ANALOG, config, kCLOCK_SystemPll1Ctrl);
638 /* Disable PLL bypass */
639 CLOCK_SetPllBypass(CCM_ANALOG, kCLOCK_SysPll1InternalPll1BypassCtrl, false);
640 /* Enable and power up PLL clock. */
641 CLOCK_EnableAnalogClock(CCM_ANALOG, kCLOCK_SystemPll1Clke);
642
643 /* Wait for PLL to be locked. */
644 while (!CLOCK_IsPllLocked(CCM_ANALOG, kCLOCK_SystemPll1Ctrl))
645 {
646 }
647 }
648
649 /*!
650 * brief De-initialize the System PLL1.
651 */
CLOCK_DeinitSysPll1(void)652 void CLOCK_DeinitSysPll1(void)
653 {
654 CLOCK_PowerDownPll(CCM_ANALOG, kCLOCK_SystemPll1Ctrl);
655 }
656
657 /*!
658 * brief Initializes the ANALOG SYS PLL2.
659 *
660 * param config Pointer to the configuration structure(see ref ccm_analog_integer_pll_config_t enumeration).
661 *
662 * note This function can't detect whether the SYS PLL has been enabled and
663 * used by some IPs.
664 */
CLOCK_InitSysPll2(const ccm_analog_integer_pll_config_t * config)665 void CLOCK_InitSysPll2(const ccm_analog_integer_pll_config_t *config)
666 {
667 assert(config != NULL);
668
669 /* Integer PLL configuration */
670 CLOCK_InitIntegerPll(CCM_ANALOG, config, kCLOCK_SystemPll2Ctrl);
671 /* Disable PLL bypass */
672 CLOCK_SetPllBypass(CCM_ANALOG, kCLOCK_SysPll2InternalPll1BypassCtrl, false);
673 /* Enable and power up PLL clock. */
674 CLOCK_EnableAnalogClock(CCM_ANALOG, kCLOCK_SystemPll2Clke);
675
676 /* Wait for PLL to be locked. */
677 while (!CLOCK_IsPllLocked(CCM_ANALOG, kCLOCK_SystemPll2Ctrl))
678 {
679 }
680 }
681
682 /*!
683 * brief De-initialize the System PLL2.
684 */
CLOCK_DeinitSysPll2(void)685 void CLOCK_DeinitSysPll2(void)
686 {
687 CLOCK_PowerDownPll(CCM_ANALOG, kCLOCK_SystemPll2Ctrl);
688 }
689
690 /*!
691 * brief Initializes the ANALOG SYS PLL3.
692 *
693 * param config Pointer to the configuration structure(see ref ccm_analog_integer_pll_config_t enumeration).
694 *
695 * note This function can't detect whether the SYS PLL has been enabled and
696 * used by some IPs.
697 */
CLOCK_InitSysPll3(const ccm_analog_integer_pll_config_t * config)698 void CLOCK_InitSysPll3(const ccm_analog_integer_pll_config_t *config)
699 {
700 assert(config != NULL);
701
702 /* Integer PLL configuration */
703 CLOCK_InitIntegerPll(CCM_ANALOG, config, kCLOCK_SystemPll3Ctrl);
704 /* Disable PLL bypass */
705 CLOCK_SetPllBypass(CCM_ANALOG, kCLOCK_SysPll3InternalPll1BypassCtrl, false);
706 /* Enable and power up PLL clock. */
707 CLOCK_EnableAnalogClock(CCM_ANALOG, kCLOCK_SystemPll3Clke);
708
709 /* Wait for PLL to be locked. */
710 while (!CLOCK_IsPllLocked(CCM_ANALOG, kCLOCK_SystemPll3Ctrl))
711 {
712 }
713 }
714
715 /*!
716 * brief De-initialize the System PLL3.
717 */
CLOCK_DeinitSysPll3(void)718 void CLOCK_DeinitSysPll3(void)
719 {
720 CLOCK_PowerDownPll(CCM_ANALOG, kCLOCK_SystemPll3Ctrl);
721 }
722
723 /*!
724 * brief Initializes the ANALOG Fractional PLL.
725 *
726 * param base CCM ANALOG base address.
727 * param config Pointer to the configuration structure(see ref ccm_analog_frac_pll_config_t enumeration).
728 * param type fractional pll type.
729 *
730 */
CLOCK_InitFracPll(CCM_ANALOG_Type * base,const ccm_analog_frac_pll_config_t * config,clock_pll_ctrl_t type)731 void CLOCK_InitFracPll(CCM_ANALOG_Type *base, const ccm_analog_frac_pll_config_t *config, clock_pll_ctrl_t type)
732 {
733 assert(config != NULL);
734 assert((config->mainDiv >= 64U) && (config->mainDiv <= 1023U));
735 assert((config->preDiv >= 1U) && (config->preDiv <= 63U));
736 assert(config->postDiv <= 6U);
737
738 assert(type < kCLOCK_ArmPllCtrl);
739
740 uint32_t fracCfg0 = CCM_ANALOG_TUPLE_REG_OFF(base, type, FracPLL_GNRL_CTL_Offset) &
741 ~((uint32_t)1 << CCM_ANALOG_AUDIO_PLL1_GEN_CTRL_PLL_RST_SHIFT);
742 uint32_t fracCfg1 = CCM_ANALOG_TUPLE_REG_OFF(base, type, FracPLL_FDIV_CTL0_Offset);
743 uint32_t fracCfg2 = CCM_ANALOG_TUPLE_REG_OFF(base, type, FracPLL_FDIV_CTL1_Offset);
744
745 /* power down the fractional PLL first */
746 CCM_ANALOG_TUPLE_REG_OFF(base, type, FracPLL_GNRL_CTL_Offset) = fracCfg0;
747
748 CCM_ANALOG_TUPLE_REG_OFF(base, type, FracPLL_FDIV_CTL0_Offset) =
749 (fracCfg1 &
750 (~(CCM_ANALOG_AUDIO_PLL1_FDIV_CTL0_PLL_MAIN_DIV_MASK | CCM_ANALOG_AUDIO_PLL1_FDIV_CTL0_PLL_PRE_DIV_MASK |
751 CCM_ANALOG_AUDIO_PLL1_FDIV_CTL0_PLL_POST_DIV_MASK))) |
752 CCM_ANALOG_AUDIO_PLL1_FDIV_CTL0_PLL_MAIN_DIV(config->mainDiv) |
753 CCM_ANALOG_AUDIO_PLL1_FDIV_CTL0_PLL_PRE_DIV(config->preDiv) |
754 CCM_ANALOG_AUDIO_PLL1_FDIV_CTL0_PLL_POST_DIV(config->postDiv);
755
756 CCM_ANALOG_TUPLE_REG_OFF(base, type, FracPLL_FDIV_CTL1_Offset) =
757 (fracCfg2 & (~(CCM_ANALOG_AUDIO_PLL1_FDIV_CTL1_PLL_DSM_MASK))) |
758 CCM_ANALOG_AUDIO_PLL1_FDIV_CTL1_PLL_DSM(config->dsm);
759
760 /* power up the fractional pll */
761 CCM_ANALOG_TUPLE_REG_OFF(base, type, FracPLL_GNRL_CTL_Offset) |= CCM_ANALOG_AUDIO_PLL1_GEN_CTRL_PLL_RST_MASK;
762 }
763
764 /*!
765 * brief Gets the ANALOG Fractional PLL clock frequency.
766 *
767 * param base CCM_ANALOG base pointer.
768 * param type fractional pll type.
769 * param fractional pll reference clock frequency
770 *
771 * return Clock frequency
772 */
CLOCK_GetFracPllFreq(CCM_ANALOG_Type * base,clock_pll_ctrl_t type,uint32_t refClkFreq)773 uint32_t CLOCK_GetFracPllFreq(CCM_ANALOG_Type *base, clock_pll_ctrl_t type, uint32_t refClkFreq)
774 {
775 assert(type < kCLOCK_ArmPllCtrl);
776
777 uint32_t fracCfg1 = CCM_ANALOG_TUPLE_REG_OFF(base, type, FracPLL_FDIV_CTL0_Offset);
778 uint32_t fracCfg2 = CCM_ANALOG_TUPLE_REG_OFF(base, type, FracPLL_FDIV_CTL1_Offset);
779 uint64_t fracClk = 0U;
780
781 uint32_t mainDiv = CCM_BIT_FIELD_EXTRACTION(fracCfg1, CCM_ANALOG_AUDIO_PLL1_FDIV_CTL0_PLL_MAIN_DIV_MASK,
782 CCM_ANALOG_AUDIO_PLL1_FDIV_CTL0_PLL_MAIN_DIV_SHIFT);
783 uint8_t preDiv = (uint8_t)CCM_BIT_FIELD_EXTRACTION(fracCfg1, CCM_ANALOG_AUDIO_PLL1_FDIV_CTL0_PLL_PRE_DIV_MASK,
784 CCM_ANALOG_AUDIO_PLL1_FDIV_CTL0_PLL_PRE_DIV_SHIFT);
785 uint8_t postDiv = (uint8_t)CCM_BIT_FIELD_EXTRACTION(fracCfg1, CCM_ANALOG_AUDIO_PLL1_FDIV_CTL0_PLL_POST_DIV_MASK,
786 CCM_ANALOG_AUDIO_PLL1_FDIV_CTL0_PLL_POST_DIV_SHIFT);
787 uint32_t dsm = CCM_BIT_FIELD_EXTRACTION(fracCfg2, CCM_ANALOG_AUDIO_PLL1_FDIV_CTL1_PLL_DSM_MASK,
788 CCM_ANALOG_AUDIO_PLL1_FDIV_CTL1_PLL_DSM_SHIFT);
789
790 fracClk = (uint64_t)((uint64_t)refClkFreq * ((uint64_t)mainDiv * 65536ULL + dsm) /
791 (65536ULL * (uint32_t)preDiv * (1ULL << postDiv)));
792
793 return (uint32_t)fracClk;
794 }
795
796 /*!
797 * brief Initializes the ANALOG Integer PLL.
798 *
799 * param base CCM ANALOG base address
800 * param config Pointer to the configuration structure(see ref ccm_analog_integer_pll_config_t enumeration).
801 * param type integer pll type
802 *
803 */
CLOCK_InitIntegerPll(CCM_ANALOG_Type * base,const ccm_analog_integer_pll_config_t * config,clock_pll_ctrl_t type)804 void CLOCK_InitIntegerPll(CCM_ANALOG_Type *base, const ccm_analog_integer_pll_config_t *config, clock_pll_ctrl_t type)
805 {
806 assert(config != NULL);
807 assert((config->mainDiv >= 64U) && (config->mainDiv <= 1023U));
808 assert((config->preDiv >= 1U) && (config->preDiv <= 63U));
809 assert(config->postDiv <= 6U);
810
811 assert(type >= kCLOCK_SystemPll1Ctrl);
812
813 uint32_t integerCfg0 = CCM_ANALOG_TUPLE_REG_OFF(base, type, IntegerPLL_GNRL_CTL_Offset) &
814 ~((uint32_t)1 << CCM_ANALOG_SYS_PLL1_GEN_CTRL_PLL_RST_SHIFT);
815 uint32_t integerCfg1 = CCM_ANALOG_TUPLE_REG_OFF(base, type, IntegerPLL_DIV_CTL_Offset);
816
817 /* power down the Integer PLL first */
818 CCM_ANALOG_TUPLE_REG_OFF(base, type, IntegerPLL_GNRL_CTL_Offset) = integerCfg0;
819
820 /* pll mux configuration */
821 CCM_ANALOG_TUPLE_REG_OFF(base, type, IntegerPLL_GNRL_CTL_Offset) =
822 (integerCfg0 & (~CCM_ANALOG_SYS_PLL1_GEN_CTRL_PLL_REF_CLK_SEL_MASK)) | config->refSel;
823
824 /* divider configuration */
825 CCM_ANALOG_TUPLE_REG_OFF(base, type, IntegerPLL_DIV_CTL_Offset) =
826 (integerCfg1 &
827 (~(CCM_ANALOG_SYS_PLL1_FDIV_CTL0_PLL_MAIN_DIV_MASK | CCM_ANALOG_SYS_PLL1_FDIV_CTL0_PLL_PRE_DIV_MASK |
828 CCM_ANALOG_SYS_PLL1_FDIV_CTL0_PLL_POST_DIV_MASK))) |
829 CCM_ANALOG_SYS_PLL1_FDIV_CTL0_PLL_MAIN_DIV(config->mainDiv) |
830 CCM_ANALOG_SYS_PLL1_FDIV_CTL0_PLL_PRE_DIV(config->preDiv) |
831 CCM_ANALOG_SYS_PLL1_FDIV_CTL0_PLL_POST_DIV(config->postDiv);
832
833 /* power up the Integer PLL */
834 CCM_ANALOG_TUPLE_REG_OFF(base, type, IntegerPLL_GNRL_CTL_Offset) |= CCM_ANALOG_SYS_PLL1_GEN_CTRL_PLL_RST_MASK;
835 }
836
837 /*!
838 * brief Get the ANALOG Integer PLL clock frequency.
839 *
840 * param base CCM ANALOG base address.
841 * param type integer pll type
842 * param pll1Bypass pll1 bypass flag
843 *
844 * return Clock frequency
845 */
CLOCK_GetIntegerPllFreq(CCM_ANALOG_Type * base,clock_pll_ctrl_t type,uint32_t refClkFreq,bool pll1Bypass)846 uint32_t CLOCK_GetIntegerPllFreq(CCM_ANALOG_Type *base, clock_pll_ctrl_t type, uint32_t refClkFreq, bool pll1Bypass)
847 {
848 assert(type >= kCLOCK_SystemPll1Ctrl);
849
850 uint32_t integerCfg1 = CCM_ANALOG_TUPLE_REG_OFF(base, type, IntegerPLL_DIV_CTL_Offset);
851 uint64_t pllOutClock = 0U;
852
853 uint32_t mainDiv = CCM_BIT_FIELD_EXTRACTION(integerCfg1, CCM_ANALOG_SYS_PLL1_FDIV_CTL0_PLL_MAIN_DIV_MASK,
854 CCM_ANALOG_SYS_PLL1_FDIV_CTL0_PLL_MAIN_DIV_SHIFT);
855 uint8_t preDiv = (uint8_t)CCM_BIT_FIELD_EXTRACTION(integerCfg1, CCM_ANALOG_SYS_PLL1_FDIV_CTL0_PLL_PRE_DIV_MASK,
856 CCM_ANALOG_SYS_PLL1_FDIV_CTL0_PLL_PRE_DIV_SHIFT);
857 uint8_t postDiv = (uint8_t)CCM_BIT_FIELD_EXTRACTION(integerCfg1, CCM_ANALOG_SYS_PLL1_FDIV_CTL0_PLL_POST_DIV_MASK,
858 CCM_ANALOG_SYS_PLL1_FDIV_CTL0_PLL_POST_DIV_SHIFT);
859
860 if (pll1Bypass)
861 {
862 pllOutClock = refClkFreq;
863 }
864
865 else
866 {
867 pllOutClock = (uint64_t)refClkFreq * mainDiv / (((uint64_t)(1U) << postDiv) * preDiv);
868 }
869
870 return (uint32_t)pllOutClock;
871 }
872
873 /*!
874 * brief Set root clock divider
875 * Note: The PRE and POST dividers in this function are the actually divider, software will map it to register value
876 *
877 * param ccmRootClk Root control (see ref clock_root_control_t enumeration)
878 * param pre Pre divider value (1-8)
879 * param post Post divider value (1-64)
880 */
CLOCK_SetRootDivider(clock_root_control_t ccmRootClk,uint32_t pre,uint32_t post)881 void CLOCK_SetRootDivider(clock_root_control_t ccmRootClk, uint32_t pre, uint32_t post)
882 {
883 assert((pre <= 8U) && (pre != 0U));
884 assert((post <= 64U) && (post != 0U));
885
886 CCM_REG(ccmRootClk) = (CCM_REG(ccmRootClk) & (~(CCM_TARGET_ROOT_PRE_PODF_MASK | CCM_TARGET_ROOT_POST_PODF_MASK))) |
887 CCM_TARGET_ROOT_PRE_PODF(pre - 1U) | CCM_TARGET_ROOT_POST_PODF(post - 1U);
888 }
889
890 /*!
891 * brief Update clock root in one step, for dynamical clock switching
892 * Note: The PRE and POST dividers in this function are the actually divider, software will map it to register value
893 *
894 * param ccmRootClk Root control (see ref clock_root_control_t enumeration)
895 * param root mux value (see ref _ccm_rootmux_xxx enumeration)
896 * param pre Pre divider value (0-7, divider=n+1)
897 * param post Post divider value (0-63, divider=n+1)
898 */
CLOCK_UpdateRoot(clock_root_control_t ccmRootClk,uint32_t mux,uint32_t pre,uint32_t post)899 void CLOCK_UpdateRoot(clock_root_control_t ccmRootClk, uint32_t mux, uint32_t pre, uint32_t post)
900 {
901 assert((pre <= 8U) && (pre != 0U));
902 assert((post <= 64U) && (post != 0U));
903
904 CCM_REG(ccmRootClk) =
905 (CCM_REG(ccmRootClk) &
906 (~(CCM_TARGET_ROOT_MUX_MASK | CCM_TARGET_ROOT_PRE_PODF_MASK | CCM_TARGET_ROOT_POST_PODF_MASK))) |
907 CCM_TARGET_ROOT_MUX(mux) | CCM_TARGET_ROOT_PRE_PODF(pre - 1U) | CCM_TARGET_ROOT_POST_PODF(post - 1U);
908 }
909
910 /*!
911 * brief Enable CCGR clock gate and root clock gate for each module
912 * User should set specific gate for each module according to the description
913 * of the table of system clocks, gating and override in CCM chapter of
914 * reference manual. Take care of that one module may need to set more than
915 * one clock gate.
916 *
917 * param ccmGate Gate control for each module (see ref clock_ip_name_t enumeration).
918 */
CLOCK_EnableClock(clock_ip_name_t ccmGate)919 void CLOCK_EnableClock(clock_ip_name_t ccmGate)
920 {
921 uint32_t clockType = CLOCK_GATE_TYPE(ccmGate);
922 uint32_t ccgr = CCM_TUPLE_CCGR(ccmGate);
923 uint32_t rootClk = 0U;
924
925 if (CLOCK_GATE_IN_AUDIOMIX == clockType)
926 {
927 uint32_t offset = AUDIOMIX_TUPLE_OFFSET(ccmGate);
928 uint32_t gate = AUDIOMIX_TUPLE_GATE(ccmGate);
929 rootClk = AUDIOMIX_TUPLE_ROOT(ccmGate);
930
931 *(volatile uint32_t *)((uintptr_t)AUDIOMIX + offset) |= (uint32_t)1U << gate;
932 }
933 else
934 {
935 CCM_REG_SET(ccgr) = (uint32_t)kCLOCK_ClockNeededAll;
936 rootClk = CCM_TUPLE_ROOT(ccmGate);
937 }
938
939 /* if root clock is 0xFFFFU, then skip enable root clock */
940 if (rootClk != 0xFFFFU)
941 {
942 CCM_REG_SET(rootClk) = CCM_TARGET_ROOT_SET_ENABLE_MASK;
943 }
944 }
945
946 /*!
947 * brief Disable CCGR clock gate for the each module
948 * User should set specific gate for each module according to the description
949 * of the table of system clocks, gating and override in CCM chapter of
950 * reference manual. Take care of that one module may need to set more than
951 * one clock gate.
952 *
953 * param ccmGate Gate control for each module (see ref clock_ip_name_t enumeration).
954 */
CLOCK_DisableClock(clock_ip_name_t ccmGate)955 void CLOCK_DisableClock(clock_ip_name_t ccmGate)
956 {
957 uint32_t ccgr = CCM_TUPLE_CCGR(ccmGate);
958 uint32_t clockType = CLOCK_GATE_TYPE(ccmGate);
959 uint32_t rootClk = 0U;
960
961 if (CLOCK_GATE_IN_AUDIOMIX == clockType)
962 {
963 uint32_t offset = AUDIOMIX_TUPLE_OFFSET(ccmGate);
964 uint32_t gate = AUDIOMIX_TUPLE_GATE(ccmGate);
965 rootClk = AUDIOMIX_TUPLE_ROOT(ccmGate);
966
967 *(volatile uint32_t *)((uintptr_t)AUDIOMIX + offset) &= ~((uint32_t)1U << gate);
968 }
969 else
970 {
971 CCM_REG(ccgr) = (uint32_t)kCLOCK_ClockNotNeeded;
972 rootClk = CCM_TUPLE_ROOT(ccmGate);
973 }
974
975 /* if root clock is 0xFFFFU, then skip disable root clock */
976 if (rootClk != 0xFFFFU)
977 {
978 CCM_REG_CLR(rootClk) = CCM_TARGET_ROOT_CLR_ENABLE_MASK;
979 }
980 }
981