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