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