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