1 /*
2  * Copyright 2017 - 2021 , NXP
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include "fsl_clock.h"
9 #include "fsl_power.h"
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 #define NVALMAX (0x100U)
18 #define PVALMAX (0x20U)
19 #define MVALMAX (0x10000U)
20 
21 #define PLL_MAX_N_DIV 0x100U
22 
23 /*--------------------------------------------------------------------------
24 !!! If required these #defines can be moved to chip library file
25 ----------------------------------------------------------------------------*/
26 
27 #define PLL_SSCG1_MDEC_VAL_P (10U) /* MDEC is in bits  25 downto 10 */
28 #define PLL_SSCG1_MDEC_VAL_M (0xFFFFULL << PLL_SSCG1_MDEC_VAL_P)
29 #define PLL_NDEC_VAL_P       (0U) /* NDEC is in bits  9:0 */
30 #define PLL_NDEC_VAL_M       (0xFFUL << PLL_NDEC_VAL_P)
31 #define PLL_PDEC_VAL_P       (0U) /*!<  PDEC is in bits 6:0 */
32 #define PLL_PDEC_VAL_M       (0x1FUL << PLL_PDEC_VAL_P)
33 
34 #define PLL_MIN_CCO_FREQ_MHZ (275000000U)
35 #define PLL_MAX_CCO_FREQ_MHZ (550000000U)
36 #define PLL_LOWER_IN_LIMIT   (2000U)     /*!<  Minimum PLL input rate */
37 #define PLL_HIGHER_IN_LIMIT  (96000000U) /*!<  Maximum PLL input rate */
38 #define PLL_MIN_IN_SSMODE    (3000000U)
39 #define PLL_MAX_IN_SSMODE \
40     (100000000U) /*!<  Not find the value in UM, Just use the maximum frequency which device support */
41 
42 /* PLL NDEC reg */
43 #define PLL_NDEC_VAL_SET(value) (((unsigned long)(value) << PLL_NDEC_VAL_P) & PLL_NDEC_VAL_M)
44 /* PLL PDEC reg */
45 #define PLL_PDEC_VAL_SET(value) (((unsigned long)(value) << PLL_PDEC_VAL_P) & PLL_PDEC_VAL_M)
46 /* SSCG control1 */
47 #define PLL_SSCG1_MDEC_VAL_SET(value) (((uint64_t)(value) << PLL_SSCG1_MDEC_VAL_P) & PLL_SSCG1_MDEC_VAL_M)
48 
49 /* PLL0 SSCG control1 */
50 #define PLL0_SSCG_MD_FRACT_P 0U
51 #define PLL0_SSCG_MD_INT_P   25U
52 #define PLL0_SSCG_MD_FRACT_M (0x1FFFFFFUL << PLL0_SSCG_MD_FRACT_P)
53 #define PLL0_SSCG_MD_INT_M   ((uint64_t)0xFFUL << PLL0_SSCG_MD_INT_P)
54 
55 #define PLL0_SSCG_MD_FRACT_SET(value) (((uint64_t)(value) << PLL0_SSCG_MD_FRACT_P) & PLL0_SSCG_MD_FRACT_M)
56 #define PLL0_SSCG_MD_INT_SET(value)   (((uint64_t)(value) << PLL0_SSCG_MD_INT_P) & PLL0_SSCG_MD_INT_M)
57 
58 /* Saved value of PLL output rate, computed whenever needed to save run-time
59    computation on each call to retrive the PLL rate. */
60 static uint32_t s_Pll0_Freq;
61 static uint32_t s_Pll1_Freq;
62 
63 /** External clock rate on the CLKIN pin in Hz. If not used,
64     set this to 0. Otherwise, set it to the exact rate in Hz this pin is
65     being driven at. */
66 static uint32_t s_Ext_Clk_Freq   = 16000000U;
67 static uint32_t s_I2S_Mclk_Freq  = 0U;
68 static uint32_t s_PLU_ClkIn_Freq = 0U;
69 
70 /*******************************************************************************
71  * Variables
72  ******************************************************************************/
73 
74 /*******************************************************************************
75  * Prototypes
76  ******************************************************************************/
77 /* Find SELP, SELI, and SELR values for raw M value, max M = MVALMAX */
78 static void pllFindSel(uint32_t M, uint32_t *pSelP, uint32_t *pSelI, uint32_t *pSelR);
79 /* Get predivider (N) from PLL0 NDEC setting */
80 static uint32_t findPll0PreDiv(void);
81 /* Get predivider (N) from PLL1 NDEC setting */
82 static uint32_t findPll1PreDiv(void);
83 /* Get postdivider (P) from PLL0 PDEC setting */
84 static uint32_t findPll0PostDiv(void);
85 /* Get postdivider (P) from PLL1 PDEC setting. */
86 static uint32_t findPll1PostDiv(void);
87 /* Get multiplier (M) from PLL0 MDEC and SSCG settings */
88 static float findPll0MMult(void);
89 /* Get multiplier (M) from PLL1 MDEC. */
90 static uint32_t findPll1MMult(void);
91 /* Get the greatest common divisor */
92 static uint32_t FindGreatestCommonDivisor(uint32_t m, uint32_t n);
93 /* Set PLL output based on desired output rate */
94 static pll_error_t CLOCK_GetPll0Config(uint32_t finHz, uint32_t foutHz, pll_setup_t *pSetup, bool useSS);
95 /* Update local PLL rate variable */
96 static void CLOCK_GetPLL0OutFromSetupUpdate(pll_setup_t *pSetup);
97 /* Update local PLL1 rate variable */
98 static void CLOCK_GetPLL1OutFromSetupUpdate(pll_setup_t *pSetup);
99 
100 /*******************************************************************************
101  * Code
102  ******************************************************************************/
103 
104 /* Clock Selection for IP */
105 /**
106  * brief   Configure the clock selection muxes.
107  * param   connection  : Clock to be configured.
108  * return  Nothing
109  */
CLOCK_AttachClk(clock_attach_id_t connection)110 void CLOCK_AttachClk(clock_attach_id_t connection)
111 {
112     uint8_t mux;
113     uint8_t sel;
114     uint16_t item;
115     uint32_t tmp32 = (uint32_t)connection;
116     uint32_t i;
117     volatile uint32_t *pClkSel;
118 
119     pClkSel = &(SYSCON->SYSTICKCLKSELX[0]);
120 
121     if (kNONE_to_NONE != connection)
122     {
123         for (i = 0U; i < 2U; i++)
124         {
125             if (tmp32 == 0U)
126             {
127                 break;
128             }
129             item = (uint16_t)GET_ID_ITEM(tmp32);
130             if (item != 0U)
131             {
132                 mux = (uint8_t)GET_ID_ITEM_MUX(item);
133                 sel = (uint8_t)GET_ID_ITEM_SEL(item);
134                 if (mux == CM_RTCOSC32KCLKSEL)
135                 {
136                     PMC->RTCOSC32K = (PMC->RTCOSC32K & ~PMC_RTCOSC32K_SEL_MASK) | PMC_RTCOSC32K_SEL(sel);
137                 }
138                 else if (mux == CM_OSTIMERCLKSEL)
139                 {
140                     PMC->OSTIMERr = (PMC->OSTIMERr & ~PMC_OSTIMER_OSTIMERCLKSEL_MASK) | PMC_OSTIMER_OSTIMERCLKSEL(sel);
141                 }
142                 else
143                 {
144                     pClkSel[mux] = sel;
145                 }
146             }
147             tmp32 = GET_ID_NEXT_ITEM(tmp32); /* pick up next descriptor */
148         }
149     }
150 }
151 
152 /* Return the actual clock attach id */
153 /**
154  * brief   Get the actual clock attach id.
155  * This fuction uses the offset in input attach id, then it reads the actual source value in
156  * the register and combine the offset to obtain an actual attach id.
157  * param   attachId  : Clock attach id to get.
158  * return  Clock source value.
159  */
CLOCK_GetClockAttachId(clock_attach_id_t attachId)160 clock_attach_id_t CLOCK_GetClockAttachId(clock_attach_id_t attachId)
161 {
162     uint8_t mux;
163     uint32_t actualSel;
164     uint32_t tmp32 = (uint32_t)attachId;
165     uint32_t i;
166     uint32_t actualAttachId = 0U;
167     uint32_t selector       = GET_ID_SELECTOR(tmp32);
168     volatile uint32_t *pClkSel;
169 
170     pClkSel = &(SYSCON->SYSTICKCLKSELX[0]);
171 
172     if (kNONE_to_NONE == attachId)
173     {
174         return kNONE_to_NONE;
175     }
176 
177     for (i = 0U; i < 2U; i++)
178     {
179         mux = (uint8_t)GET_ID_ITEM_MUX(tmp32);
180         if (tmp32 != 0UL)
181         {
182             if (mux == CM_RTCOSC32KCLKSEL)
183             {
184                 actualSel = ((PMC->RTCOSC32K) & PMC_RTCOSC32K_SEL_MASK) >> PMC_RTCOSC32K_SEL_SHIFT;
185             }
186             else if (mux == CM_OSTIMERCLKSEL)
187             {
188                 actualSel = ((PMC->OSTIMERr) & PMC_OSTIMER_OSTIMERCLKSEL_MASK) >> PMC_OSTIMER_OSTIMERCLKSEL_SHIFT;
189             }
190             else
191             {
192                 actualSel = pClkSel[mux];
193             }
194 
195             /* Consider the combination of two registers */
196             actualAttachId |= CLK_ATTACH_ID(mux, actualSel, i);
197         }
198         tmp32 = GET_ID_NEXT_ITEM(tmp32); /*!<  pick up next descriptor */
199     }
200 
201     actualAttachId |= selector;
202 
203     return (clock_attach_id_t)actualAttachId;
204 }
205 
206 /* Set IP Clock Divider */
207 /**
208  * brief   Setup peripheral clock dividers.
209  * param   div_name    : Clock divider name
210  * param divided_by_value: Value to be divided
211  * param reset :  Whether to reset the divider counter.
212  * return  Nothing
213  */
CLOCK_SetClkDiv(clock_div_name_t div_name,uint32_t divided_by_value,bool reset)214 void CLOCK_SetClkDiv(clock_div_name_t div_name, uint32_t divided_by_value, bool reset)
215 {
216     volatile uint32_t *pClkDiv;
217 
218     pClkDiv = &(SYSCON->SYSTICKCLKDIV0);
219 
220     if ((div_name >= kCLOCK_DivFlexFrg0) && (div_name <= kCLOCK_DivFlexFrg7))
221     {
222         /*!<  Flexcomm Interface function clock = (clock selected via FCCLKSEL) / (1+ MULT /DIV), DIV = 0xFF */
223         ((volatile uint32_t *)pClkDiv)[(uint8_t)div_name] =
224             SYSCON_FLEXFRG0CTRL_DIV_MASK | SYSCON_FLEXFRG0CTRL_MULT(divided_by_value);
225     }
226     else
227     {
228         if (reset)
229         {
230             ((volatile uint32_t *)pClkDiv)[(uint8_t)div_name] = 1UL << 29U;
231         }
232         if (divided_by_value == 0U) /*!<  halt */
233         {
234             ((volatile uint32_t *)pClkDiv)[(uint8_t)div_name] = 1UL << 30U;
235         }
236         else
237         {
238             ((volatile uint32_t *)pClkDiv)[(uint8_t)div_name] = (divided_by_value - 1U);
239         }
240     }
241 }
242 
243 /* Set RTC 1KHz Clock Divider */
244 /**
245  * brief   Setup rtc 1khz clock divider.
246  * param divided_by_value: Value to be divided
247  * return  Nothing
248  */
CLOCK_SetRtc1khzClkDiv(uint32_t divided_by_value)249 void CLOCK_SetRtc1khzClkDiv(uint32_t divided_by_value)
250 {
251     PMC->RTCOSC32K =
252         (PMC->RTCOSC32K & ~PMC_RTCOSC32K_CLK1KHZDIV_MASK) | PMC_RTCOSC32K_CLK1KHZDIV(divided_by_value - 28U);
253 }
254 
255 /* Set RTC 1KHz Clock Divider */
256 /**
257  * brief   Setup rtc 1hz clock divider.
258  * param divided_by_value: Value to be divided
259  * return  Nothing
260  */
CLOCK_SetRtc1hzClkDiv(uint32_t divided_by_value)261 void CLOCK_SetRtc1hzClkDiv(uint32_t divided_by_value)
262 {
263     if (divided_by_value == 0U) /*!<  halt */
264     {
265         PMC->RTCOSC32K |= (1UL << PMC_RTCOSC32K_CLK1HZDIVHALT_SHIFT);
266     }
267     else
268     {
269         PMC->RTCOSC32K =
270             (PMC->RTCOSC32K & ~PMC_RTCOSC32K_CLK1HZDIV_MASK) | PMC_RTCOSC32K_CLK1HZDIV(divided_by_value - 31744U);
271     }
272 }
273 
274 /* Set FRO Clocking */
275 /**
276  * brief   Initialize the Core clock to given frequency (12, 48 or 96 MHz).
277  * Turns on FRO and uses default CCO, if freq is 12000000, then high speed output is off, else high speed output is
278  * enabled.
279  * param   iFreq   : Desired frequency (must be one of #CLK_FRO_12MHZ or #CLK_FRO_48MHZ or #CLK_FRO_96MHZ)
280  * return  returns success or fail status.
281  */
CLOCK_SetupFROClocking(uint32_t iFreq)282 status_t CLOCK_SetupFROClocking(uint32_t iFreq)
283 {
284     if ((iFreq != 12000000U) && (iFreq != 96000000U))
285     {
286         return kStatus_Fail;
287     }
288     /* Enable Analog Control module */
289     SYSCON->PRESETCTRLCLR[2] = (1UL << SYSCON_PRESETCTRL2_ANALOG_CTRL_RST_SHIFT);
290     SYSCON->AHBCLKCTRLSET[2] = SYSCON_AHBCLKCTRL2_ANALOG_CTRL_MASK;
291     /* Power up the FRO192M */
292     POWER_DisablePD(kPDRUNCFG_PD_FRO192M);
293 
294     if (iFreq == 96000000U)
295     {
296         ANACTRL->FRO192M_CTRL |= ANACTRL_FRO192M_CTRL_ENA_96MHZCLK(1);
297     }
298     /* always enable
299     else if (iFreq == 48000000U)
300     {
301         ANACTRL->FRO192M_CTRL |= ANACTRL_FRO192M_CTRL_ENA_48MHZCLK(1);
302     }*/
303     else
304     {
305         ANACTRL->FRO192M_CTRL |= ANACTRL_FRO192M_CTRL_ENA_12MHZCLK(1);
306     }
307     return kStatus_Success;
308 }
309 
310 /* Set the FLASH wait states for the passed frequency */
311 /**
312  * brief    Set the flash wait states for the input freuqency.
313  * param    iFreq: Input frequency
314  * return    Nothing
315  */
316 typedef struct
317 {
318     uint32_t waitstate;
319     uint32_t freqMax;
320 } WaitStateInterval_t;
321 
322 /* clang-format off */
323 /* Wait state if frequency is inferior to the one specified */
324 static const WaitStateInterval_t IntervalList[] = {
325     {0, 11000000},
326     {1, 22000000},
327     {2, 33000000},
328     {3, 44000000},
329     {4, 55000000},
330     {5, 66000000},
331     {6, 84000000},
332     {7, 96000000} /* Maximum allowed frequency (96 MHz) */
333 };
334 /* clang-format on */
335 
CLOCK_SetFLASHAccessCyclesForFreq(uint32_t system_freq_hz)336 void CLOCK_SetFLASHAccessCyclesForFreq(uint32_t system_freq_hz)
337 {
338     /* Flash Controller & FMC internal number of Wait States (minus 1) */
339     uint32_t num_wait_states      = 15UL; /* Default to the maximum number of wait states */
340     uint32_t prefetch_enable_mask = SYSCON->FMCCR & SYSCON_FMCCR_PREFEN_MASK;
341 
342     for (size_t cnt = 0; cnt < (sizeof(IntervalList) / sizeof(WaitStateInterval_t)); cnt++)
343     {
344         if (system_freq_hz <= IntervalList[cnt].freqMax)
345         {
346             num_wait_states = IntervalList[cnt].waitstate;
347             break;
348         }
349     }
350 
351     /*The prefetch bit must be disabled before any flash commands*/
352     SYSCON->FMCCR &= ~SYSCON_FMCCR_PREFEN_MASK;
353 
354     FLASH->INT_CLR_STATUS = 0x1F; /* Clear all status flags */
355 
356     FLASH->DATAW[0] = (FLASH->DATAW[0] & 0xFFFFFFF0UL) |
357                       (num_wait_states & (SYSCON_FMCCR_FLASHTIM_MASK >> SYSCON_FMCCR_FLASHTIM_SHIFT));
358 
359     FLASH->CMD = 0x2; /* CMD_SET_READ_MODE */
360 
361     /* Wait until the cmd is completed (without error) */
362     while ((FLASH->INT_STATUS & FLASH_INT_STATUS_DONE_MASK) == 0UL)
363     {
364     }
365 
366     /* Adjust FMC waiting time cycles (num_wait_states) */
367     SYSCON->FMCCR = (SYSCON->FMCCR & ~SYSCON_FMCCR_FLASHTIM_MASK) |
368                     ((num_wait_states << SYSCON_FMCCR_FLASHTIM_SHIFT) & SYSCON_FMCCR_FLASHTIM_MASK);
369 
370     /* restore prefetch enable */
371     SYSCON->FMCCR |= prefetch_enable_mask;
372 }
373 
374 /* Set EXT OSC Clk */
375 /**
376  * brief   Initialize the external osc clock to given frequency.
377  * Crystal oscillator with an operating frequency of 12 MHz to 32 MHz.
378  * Option for external clock input (bypass mode) for clock frequencies of up to 25 MHz.
379  * param   iFreq   : Desired frequency (must be equal to exact rate in Hz)
380  * return  returns success or fail status.
381  */
CLOCK_SetupExtClocking(uint32_t iFreq)382 status_t CLOCK_SetupExtClocking(uint32_t iFreq)
383 {
384     if (iFreq > 32000000U)
385     {
386         return kStatus_Fail;
387     }
388     /* Turn on power for crystal 32 MHz */
389     POWER_DisablePD(kPDRUNCFG_PD_XTAL32M);
390     POWER_DisablePD(kPDRUNCFG_PD_LDOXO32M);
391     /* Enable clock_in clock for clock module. */
392     SYSCON->CLOCK_CTRL |= SYSCON_CLOCK_CTRL_CLKIN_ENA_MASK;
393 
394     s_Ext_Clk_Freq = iFreq;
395     return kStatus_Success;
396 }
397 
398 /* Set I2S MCLK Clk */
399 /**
400  * brief   Initialize the I2S MCLK clock to given frequency.
401  * param   iFreq   : Desired frequency (must be equal to exact rate in Hz)
402  * return  returns success or fail status.
403  */
CLOCK_SetupI2SMClkClocking(uint32_t iFreq)404 status_t CLOCK_SetupI2SMClkClocking(uint32_t iFreq)
405 {
406     s_I2S_Mclk_Freq = iFreq;
407     return kStatus_Success;
408 }
409 
410 /* Set PLU CLKIN Clk */
411 /**
412  * brief   Initialize the PLU CLKIN clock to given frequency.
413  * param   iFreq   : Desired frequency (must be equal to exact rate in Hz)
414  * return  returns success or fail status.
415  */
CLOCK_SetupPLUClkInClocking(uint32_t iFreq)416 status_t CLOCK_SetupPLUClkInClocking(uint32_t iFreq)
417 {
418     s_PLU_ClkIn_Freq = iFreq;
419     return kStatus_Success;
420 }
421 
422 /* Get CLOCK OUT Clk */
423 /*! brief  Return Frequency of ClockOut
424  *  return Frequency of ClockOut
425  */
CLOCK_GetClockOutClkFreq(void)426 uint32_t CLOCK_GetClockOutClkFreq(void)
427 {
428     uint32_t freq = 0U;
429 
430     switch (SYSCON->CLKOUTSEL)
431     {
432         case 0U:
433             freq = CLOCK_GetCoreSysClkFreq();
434             break;
435 
436         case 1U:
437             freq = CLOCK_GetPll0OutFreq();
438             break;
439 
440         case 2U:
441             freq = CLOCK_GetExtClkFreq();
442             break;
443 
444         case 3U:
445             freq = CLOCK_GetFroHfFreq();
446             break;
447 
448         case 4U:
449             freq = CLOCK_GetFro1MFreq();
450             break;
451 
452         case 5U:
453             freq = CLOCK_GetPll1OutFreq();
454             break;
455 
456         case 6U:
457             freq = CLOCK_GetOsc32KFreq();
458             break;
459 
460         case 7U:
461             freq = 0U;
462             break;
463 
464         default:
465             freq = 0U;
466             break;
467     }
468     return freq / ((SYSCON->CLKOUTDIV & 0xffU) + 1U);
469 }
470 
471 /* Get CAN Clk */
472 /*! brief  Return Frequency of Can Clock
473  *  return Frequency of Can.
474  */
CLOCK_GetMCanClkFreq(void)475 uint32_t CLOCK_GetMCanClkFreq(void)
476 {
477     uint32_t freq = 0U;
478 
479     switch (SYSCON->CANCLKSEL)
480     {
481         case 0U:
482             freq = CLOCK_GetCoreSysClkFreq() / ((SYSCON->CANCLKDIV & SYSCON_CANCLKDIV_DIV_MASK) + 1U);
483             break;
484         case 1U:
485             freq = CLOCK_GetFro1MFreq();
486             break;
487         case 2U:
488             freq = CLOCK_GetOsc32KFreq();
489             break;
490         case 7U:
491             freq = 0U;
492             break;
493 
494         default:
495             freq = 0U;
496             break;
497     }
498 
499     return freq;
500 }
501 
502 /* Get ADC Clk */
503 /*! brief  Return Frequency of Adc Clock
504  *  return Frequency of Adc.
505  */
CLOCK_GetAdcClkFreq(void)506 uint32_t CLOCK_GetAdcClkFreq(void)
507 {
508     uint32_t freq = 0U;
509 
510     switch (SYSCON->ADCCLKSEL)
511     {
512         case 0U:
513             freq = CLOCK_GetCoreSysClkFreq();
514             break;
515         case 1U:
516             freq = CLOCK_GetPll0OutFreq();
517             break;
518         case 2U:
519             freq = CLOCK_GetFroHfFreq();
520             break;
521         case 7U:
522             freq = 0U;
523             break;
524 
525         default:
526             freq = 0U;
527             break;
528     }
529 
530     return freq / ((SYSCON->ADCCLKDIV & SYSCON_ADCCLKDIV_DIV_MASK) + 1U);
531 }
532 
533 /* Get MCLK Clk */
534 /*! brief  Return Frequency of MClk Clock
535  *  return Frequency of MClk Clock.
536  */
CLOCK_GetMclkClkFreq(void)537 uint32_t CLOCK_GetMclkClkFreq(void)
538 {
539     uint32_t freq = 0U;
540 
541     switch (SYSCON->MCLKCLKSEL)
542     {
543         case 0U:
544             freq = CLOCK_GetFroHfFreq();
545             break;
546         case 1U:
547             freq = CLOCK_GetPll0OutFreq();
548             break;
549         case 7U:
550             freq = 0U;
551             break;
552 
553         default:
554             freq = 0U;
555             break;
556     }
557 
558     return freq / ((SYSCON->MCLKDIV & 0xffU) + 1U);
559 }
560 
561 /* Get SCTIMER Clk */
562 /*! brief  Return Frequency of SCTimer Clock
563  *  return Frequency of SCTimer Clock.
564  */
CLOCK_GetSctClkFreq(void)565 uint32_t CLOCK_GetSctClkFreq(void)
566 {
567     uint32_t freq = 0U;
568 
569     switch (SYSCON->SCTCLKSEL)
570     {
571         case 0U:
572             freq = CLOCK_GetCoreSysClkFreq();
573             break;
574         case 1U:
575             freq = CLOCK_GetPll0OutFreq();
576             break;
577         case 2U:
578             freq = CLOCK_GetExtClkFreq();
579             break;
580         case 3U:
581             freq = CLOCK_GetFroHfFreq();
582             break;
583         case 5U:
584             freq = CLOCK_GetI2SMClkFreq();
585             break;
586         case 7U:
587             freq = 0U;
588             break;
589 
590         default:
591             freq = 0U;
592             break;
593     }
594 
595     return freq / ((SYSCON->SCTCLKDIV & 0xffU) + 1U);
596 }
597 
598 /* Get FRO 12M Clk */
599 /*! brief  Return Frequency of FRO 12MHz
600  *  return Frequency of FRO 12MHz
601  */
CLOCK_GetFro12MFreq(void)602 uint32_t CLOCK_GetFro12MFreq(void)
603 {
604     return ((ANACTRL->FRO192M_CTRL & ANACTRL_FRO192M_CTRL_ENA_12MHZCLK_MASK) != 0UL) ? 12000000U : 0U;
605 }
606 
607 /* Get FRO 1M Clk */
608 /*! brief  Return Frequency of FRO 1MHz
609  *  return Frequency of FRO 1MHz
610  */
CLOCK_GetFro1MFreq(void)611 uint32_t CLOCK_GetFro1MFreq(void)
612 {
613     return ((SYSCON->CLOCK_CTRL & SYSCON_CLOCK_CTRL_FRO1MHZ_CLK_ENA_MASK) != 0UL) ? 1000000U : 0U;
614 }
615 
616 /* Get EXT OSC Clk */
617 /*! brief  Return Frequency of External Clock
618  *  return Frequency of External Clock. If no external clock is used returns 0.
619  */
CLOCK_GetExtClkFreq(void)620 uint32_t CLOCK_GetExtClkFreq(void)
621 {
622     return ((ANACTRL->XO32M_CTRL & ANACTRL_XO32M_CTRL_ENABLE_SYSTEM_CLK_OUT_MASK) != 0UL) ? s_Ext_Clk_Freq : 0U;
623 }
624 
625 /* Get WATCH DOG Clk */
626 /*! brief  Return Frequency of Watchdog
627  *  return Frequency of Watchdog
628  */
CLOCK_GetWdtClkFreq(void)629 uint32_t CLOCK_GetWdtClkFreq(void)
630 {
631     return CLOCK_GetFro1MFreq() / ((SYSCON->WDTCLKDIV & SYSCON_WDTCLKDIV_DIV_MASK) + 1U);
632 }
633 
634 /* Get HF FRO Clk */
635 /*! brief  Return Frequency of High-Freq output of FRO
636  *  return Frequency of High-Freq output of FRO
637  */
CLOCK_GetFroHfFreq(void)638 uint32_t CLOCK_GetFroHfFreq(void)
639 {
640     return ((ANACTRL->FRO192M_CTRL & ANACTRL_FRO192M_CTRL_ENA_96MHZCLK_MASK) != 0UL) ? 96000000U : 0U;
641 }
642 
643 /* Get SYSTEM PLL Clk */
644 /*! brief  Return Frequency of PLL
645  *  return Frequency of PLL
646  */
CLOCK_GetPll0OutFreq(void)647 uint32_t CLOCK_GetPll0OutFreq(void)
648 {
649     return s_Pll0_Freq;
650 }
651 
652 /* Get USB PLL Clk */
653 /*! brief  Return Frequency of USB PLL
654  *  return Frequency of PLL
655  */
CLOCK_GetPll1OutFreq(void)656 uint32_t CLOCK_GetPll1OutFreq(void)
657 {
658     return s_Pll1_Freq;
659 }
660 
661 /* Get RTC OSC Clk */
662 /*! brief  Return Frequency of 32kHz osc
663  *  return Frequency of 32kHz osc
664  */
CLOCK_GetOsc32KFreq(void)665 uint32_t CLOCK_GetOsc32KFreq(void)
666 {
667     return ((0UL == (PMC->PDRUNCFG0 & PMC_PDRUNCFG0_PDEN_FRO32K_MASK)) &&
668             (0UL == (PMC->RTCOSC32K & PMC_RTCOSC32K_SEL_MASK))) ?
669                CLK_RTC_32K_CLK :
670                ((0UL == (PMC->PDRUNCFG0 & PMC_PDRUNCFG0_PDEN_XTAL32K_MASK)) &&
671                 ((PMC->RTCOSC32K & PMC_RTCOSC32K_SEL_MASK) != 0UL)) ?
672                CLK_RTC_32K_CLK :
673                0UL;
674 }
675 
676 /* Get MAIN Clk */
677 /*! brief  Return Frequency of Core System
678  *  return Frequency of Core System
679  */
CLOCK_GetCoreSysClkFreq(void)680 uint32_t CLOCK_GetCoreSysClkFreq(void)
681 {
682     uint32_t freq = 0U;
683 
684     switch (SYSCON->MAINCLKSELB)
685     {
686         case 0U:
687             if (SYSCON->MAINCLKSELA == 0U)
688             {
689                 freq = CLOCK_GetFro12MFreq();
690             }
691             else if (SYSCON->MAINCLKSELA == 1U)
692             {
693                 freq = CLOCK_GetExtClkFreq();
694             }
695             else if (SYSCON->MAINCLKSELA == 2U)
696             {
697                 freq = CLOCK_GetFro1MFreq();
698             }
699             else if (SYSCON->MAINCLKSELA == 3U)
700             {
701                 freq = CLOCK_GetFroHfFreq();
702             }
703             else
704             {
705                 /* Added comments to avoid the violation of MISRA C-2012 rule 15.7 */
706             }
707             break;
708         case 1U:
709             freq = CLOCK_GetPll0OutFreq();
710             break;
711         case 2U:
712             freq = CLOCK_GetPll1OutFreq();
713             break;
714 
715         case 3U:
716             freq = CLOCK_GetOsc32KFreq();
717             break;
718 
719         default:
720             freq = 0U;
721             break;
722     }
723 
724     return freq;
725 }
726 
727 /* Get I2S MCLK Clk */
728 /*! brief  Return Frequency of I2S MCLK Clock
729  *  return Frequency of I2S MCLK Clock
730  */
CLOCK_GetI2SMClkFreq(void)731 uint32_t CLOCK_GetI2SMClkFreq(void)
732 {
733     return s_I2S_Mclk_Freq;
734 }
735 
736 /* Get PLU CLKIN Clk */
737 /*! brief  Return Frequency of PLU CLKIN Clock
738  *  return Frequency of PLU CLKIN Clock
739  */
CLOCK_GetPLUClkInFreq(void)740 uint32_t CLOCK_GetPLUClkInFreq(void)
741 {
742     return s_PLU_ClkIn_Freq;
743 }
744 
745 /* Get FLEXCOMM input clock */
746 /*! brief  Return Frequency of flexcomm input clock
747  *  param  id     : flexcomm instance id
748  *  return Frequency value
749  */
CLOCK_GetFlexCommInputClock(uint32_t id)750 uint32_t CLOCK_GetFlexCommInputClock(uint32_t id)
751 {
752     uint32_t freq = 0U;
753 
754     switch (SYSCON->FCCLKSELX[id])
755     {
756         case 0U:
757             freq = CLOCK_GetCoreSysClkFreq();
758             break;
759         case 1U:
760             freq = CLOCK_GetPll0OutFreq() / ((SYSCON->PLL0CLKDIV & 0xffU) + 1U);
761             break;
762         case 2U:
763             freq = CLOCK_GetFro12MFreq();
764             break;
765         case 3U:
766             freq = CLOCK_GetFroHfFreq() / ((SYSCON->FROHFDIV & 0xffU) + 1U);
767             break;
768         case 4U:
769             freq = CLOCK_GetFro1MFreq();
770             break;
771         case 5U:
772             freq = CLOCK_GetI2SMClkFreq();
773             break;
774         case 6U:
775             freq = CLOCK_GetOsc32KFreq();
776             break;
777         case 7U:
778             freq = 0U;
779             break;
780 
781         default:
782             freq = 0U;
783             break;
784     }
785 
786     return freq;
787 }
788 
789 /* Get FLEXCOMM Clk */
CLOCK_GetFlexCommClkFreq(uint32_t id)790 uint32_t CLOCK_GetFlexCommClkFreq(uint32_t id)
791 {
792     uint32_t freq   = 0U;
793     uint32_t frgMul = 0U;
794     uint32_t frgDiv = 0U;
795 
796     freq   = CLOCK_GetFlexCommInputClock(id);
797     frgMul = (SYSCON->FLEXFRGXCTRL[id] & SYSCON_FLEXFRG0CTRL_MULT_MASK) >> 8U;
798     frgDiv = SYSCON->FLEXFRGXCTRL[id] & SYSCON_FLEXFRG0CTRL_DIV_MASK;
799     return (uint32_t)(((uint64_t)freq * ((uint64_t)frgDiv + 1ULL)) / (frgMul + frgDiv + 1UL));
800 }
801 
802 /* Get HS_LPSI Clk */
CLOCK_GetHsLspiClkFreq(void)803 uint32_t CLOCK_GetHsLspiClkFreq(void)
804 {
805     uint32_t freq = 0U;
806 
807     switch (SYSCON->HSLSPICLKSEL)
808     {
809         case 0U:
810             freq = CLOCK_GetCoreSysClkFreq();
811             break;
812         case 1U:
813             freq = CLOCK_GetPll0OutFreq() / ((SYSCON->PLL0CLKDIV & 0xffU) + 1U);
814             break;
815         case 2U:
816             freq = CLOCK_GetFro12MFreq();
817             break;
818         case 3U:
819             freq = CLOCK_GetFroHfFreq() / ((SYSCON->FROHFDIV & 0xffU) + 1U);
820             break;
821         case 4U:
822             freq = CLOCK_GetFro1MFreq();
823             break;
824         case 6U:
825             freq = CLOCK_GetOsc32KFreq();
826             break;
827         case 7U:
828             freq = 0U;
829             break;
830 
831         default:
832             freq = 0U;
833             break;
834     }
835 
836     return freq;
837 }
838 
839 /* Get CTimer Clk */
840 /*! brief  Return Frequency of CTimer functional Clock
841  *  return Frequency of CTimer functional Clock
842  */
CLOCK_GetCTimerClkFreq(uint32_t id)843 uint32_t CLOCK_GetCTimerClkFreq(uint32_t id)
844 {
845     uint32_t freq = 0U;
846 
847     switch (SYSCON->CTIMERCLKSELX[id])
848     {
849         case 0U:
850             freq = CLOCK_GetCoreSysClkFreq();
851             break;
852         case 1U:
853             freq = CLOCK_GetPll0OutFreq();
854             break;
855         case 3U:
856             freq = CLOCK_GetFroHfFreq();
857             break;
858         case 4U:
859             freq = CLOCK_GetFro1MFreq();
860             break;
861         case 5U:
862             freq = CLOCK_GetI2SMClkFreq();
863             break;
864         case 6U:
865             freq = CLOCK_GetOsc32KFreq();
866             break;
867         case 7U:
868             freq = 0U;
869             break;
870 
871         default:
872             freq = 0U;
873             break;
874     }
875 
876     return freq;
877 }
878 
879 /* Get Systick Clk */
880 /*! brief  Return Frequency of SystickClock
881  *  return Frequency of Systick Clock
882  */
CLOCK_GetSystickClkFreq(uint32_t id)883 uint32_t CLOCK_GetSystickClkFreq(uint32_t id)
884 {
885     uint32_t freq = 0U;
886 
887     switch (SYSCON->SYSTICKCLKSELX[id])
888     {
889         case 0U:
890             /*Niobe4mini just has one SYSTICKSEL and SYSTICKDIV register, Fix coverity problem in this way temporarily
891              */
892             freq = CLOCK_GetCoreSysClkFreq() / (((SYSCON->SYSTICKCLKDIV0) & 0xffU) + 1U);
893             break;
894         case 1U:
895             freq = CLOCK_GetFro1MFreq();
896             break;
897         case 2U:
898             freq = CLOCK_GetOsc32KFreq();
899             break;
900         case 7U:
901             freq = 0U;
902             break;
903 
904         default:
905             freq = 0U;
906             break;
907     }
908 
909     return freq;
910 }
911 
912 /* Set FlexComm Clock */
913 /**
914  * brief   Set the flexcomm output frequency.
915  * param   id      : flexcomm instance id
916  *          freq    : output frequency
917  * return  0   : the frequency range is out of range.
918  *          1   : switch successfully.
919  */
CLOCK_SetFlexCommClock(uint32_t id,uint32_t freq)920 uint32_t CLOCK_SetFlexCommClock(uint32_t id, uint32_t freq)
921 {
922     uint32_t input = CLOCK_GetFlexCommClkFreq(id);
923     uint32_t mul;
924 
925     if ((freq > 48000000UL) || (freq > input) || (input / freq >= 2UL))
926     {
927         /* FRG output frequency should be less than equal to 48MHz */
928         return 0UL;
929     }
930     else
931     {
932         mul                      = (uint32_t)((((uint64_t)input - freq) * 256ULL) / ((uint64_t)freq));
933         SYSCON->FLEXFRGXCTRL[id] = (mul << 8U) | 0xFFU;
934         return 1UL;
935     }
936 }
937 
938 /* Get IP Clk */
939 /*! brief  Return Frequency of selected clock
940  *  return Frequency of selected clock
941  */
CLOCK_GetFreq(clock_name_t clockName)942 uint32_t CLOCK_GetFreq(clock_name_t clockName)
943 {
944     uint32_t freq;
945     switch (clockName)
946     {
947         case kCLOCK_CoreSysClk:
948             freq = CLOCK_GetCoreSysClkFreq();
949             break;
950         case kCLOCK_BusClk:
951             freq = CLOCK_GetCoreSysClkFreq() / ((SYSCON->AHBCLKDIV & 0xffU) + 1U);
952             break;
953         case kCLOCK_ClockOut:
954             freq = CLOCK_GetClockOutClkFreq();
955             break;
956         case kCLOCK_Pll1Out:
957             freq = CLOCK_GetPll1OutFreq();
958             break;
959         case kCLOCK_Mclk:
960             freq = CLOCK_GetMclkClkFreq();
961             break;
962         case kCLOCK_FroHf:
963             freq = CLOCK_GetFroHfFreq();
964             break;
965         case kCLOCK_Fro12M:
966             freq = CLOCK_GetFro12MFreq();
967             break;
968         case kCLOCK_Fro1M:
969             freq = CLOCK_GetFro1MFreq();
970             break;
971         case kCLOCK_ExtClk:
972             freq = CLOCK_GetExtClkFreq();
973             break;
974         case kCLOCK_Pll0Out:
975             freq = CLOCK_GetPll0OutFreq();
976             break;
977         case kCLOCK_FlexI2S:
978             freq = CLOCK_GetI2SMClkFreq();
979             break;
980         default:
981             freq = 0U;
982             break;
983     }
984     return freq;
985 }
986 
987 /* Find SELP, SELI, and SELR values for raw M value, max M = MVALMAX */
pllFindSel(uint32_t M,uint32_t * pSelP,uint32_t * pSelI,uint32_t * pSelR)988 static void pllFindSel(uint32_t M, uint32_t *pSelP, uint32_t *pSelI, uint32_t *pSelR)
989 {
990     uint32_t seli, selp;
991     /* bandwidth: compute selP from Multiplier */
992     if ((SYSCON->PLL0SSCG1 & SYSCON_PLL0SSCG1_SEL_EXT_MASK) != 0UL) /* normal mode */
993     {
994         selp = (M >> 2U) + 1U;
995         if (selp >= 31U)
996         {
997             selp = 31U;
998         }
999         *pSelP = selp;
1000 
1001         if (M >= 8000UL)
1002         {
1003             seli = 1UL;
1004         }
1005         else if (M >= 122UL)
1006         {
1007             seli = (uint32_t)(8000UL / M); /*floor(8000/M) */
1008         }
1009         else
1010         {
1011             seli = 2UL * ((uint32_t)(M / 4UL)) + 3UL; /* 2*floor(M/4) + 3 */
1012         }
1013 
1014         if (seli >= 63UL)
1015         {
1016             seli = 63UL;
1017         }
1018         *pSelI = seli;
1019 
1020         *pSelR = 0UL;
1021     }
1022     else
1023     {
1024         /* Note: If the spread spectrum mode, choose N to ensure 3 MHz < Fin/N < 5 MHz */
1025         *pSelP = 3U;
1026         *pSelI = 4U;
1027         *pSelR = 4U;
1028     }
1029 }
1030 
1031 /* Get predivider (N) from PLL0 NDEC setting */
findPll0PreDiv(void)1032 static uint32_t findPll0PreDiv(void)
1033 {
1034     uint32_t preDiv = 1UL;
1035 
1036     /* Direct input is not used? */
1037     if ((SYSCON->PLL0CTRL & SYSCON_PLL0CTRL_BYPASSPREDIV_MASK) == 0UL)
1038     {
1039         preDiv = SYSCON->PLL0NDEC & SYSCON_PLL0NDEC_NDIV_MASK;
1040         if (preDiv == 0UL)
1041         {
1042             preDiv = 1UL;
1043         }
1044     }
1045     return preDiv;
1046 }
1047 
1048 /* Get predivider (N) from PLL1 NDEC setting */
findPll1PreDiv(void)1049 static uint32_t findPll1PreDiv(void)
1050 {
1051     uint32_t preDiv = 1UL;
1052 
1053     /* Direct input is not used? */
1054     if ((SYSCON->PLL1CTRL & SYSCON_PLL1CTRL_BYPASSPREDIV_MASK) == 0UL)
1055     {
1056         preDiv = SYSCON->PLL1NDEC & SYSCON_PLL1NDEC_NDIV_MASK;
1057         if (preDiv == 0UL)
1058         {
1059             preDiv = 1UL;
1060         }
1061     }
1062     return preDiv;
1063 }
1064 
1065 /* Get postdivider (P) from PLL0 PDEC setting */
findPll0PostDiv(void)1066 static uint32_t findPll0PostDiv(void)
1067 {
1068     uint32_t postDiv = 1UL;
1069 
1070     if ((SYSCON->PLL0CTRL & SYSCON_PLL0CTRL_BYPASSPOSTDIV_MASK) == 0UL)
1071     {
1072         if ((SYSCON->PLL0CTRL & SYSCON_PLL0CTRL_BYPASSPOSTDIV2_MASK) != 0UL)
1073         {
1074             postDiv = SYSCON->PLL0PDEC & SYSCON_PLL0PDEC_PDIV_MASK;
1075         }
1076         else
1077         {
1078             postDiv = 2UL * (SYSCON->PLL0PDEC & SYSCON_PLL0PDEC_PDIV_MASK);
1079         }
1080         if (postDiv == 0UL)
1081         {
1082             postDiv = 2UL;
1083         }
1084     }
1085     return postDiv;
1086 }
1087 
1088 /* Get postdivider (P) from PLL1 PDEC setting. */
findPll1PostDiv(void)1089 static uint32_t findPll1PostDiv(void)
1090 {
1091     uint32_t postDiv = 1UL;
1092 
1093     if ((SYSCON->PLL1CTRL & SYSCON_PLL1CTRL_BYPASSPOSTDIV_MASK) == 0UL)
1094     {
1095         if ((SYSCON->PLL1CTRL & SYSCON_PLL1CTRL_BYPASSPOSTDIV2_MASK) != 0UL)
1096         {
1097             postDiv = SYSCON->PLL1PDEC & SYSCON_PLL1PDEC_PDIV_MASK;
1098         }
1099         else
1100         {
1101             postDiv = 2UL * (SYSCON->PLL1PDEC & SYSCON_PLL1PDEC_PDIV_MASK);
1102         }
1103         if (postDiv == 0UL)
1104         {
1105             postDiv = 2UL;
1106         }
1107     }
1108 
1109     return postDiv;
1110 }
1111 
1112 /* Get multiplier (M) from PLL0 SSCG and SEL_EXT settings */
findPll0MMult(void)1113 static float findPll0MMult(void)
1114 {
1115     float mMult = 1.0F;
1116     float mMult_fract;
1117     uint32_t mMult_int;
1118 
1119     if ((SYSCON->PLL0SSCG1 & SYSCON_PLL0SSCG1_SEL_EXT_MASK) != 0UL)
1120     {
1121         mMult =
1122             (float)(uint32_t)((SYSCON->PLL0SSCG1 & SYSCON_PLL0SSCG1_MDIV_EXT_MASK) >> SYSCON_PLL0SSCG1_MDIV_EXT_SHIFT);
1123     }
1124     else
1125     {
1126         mMult_int   = ((SYSCON->PLL0SSCG1 & SYSCON_PLL0SSCG1_MD_MBS_MASK) << 7U);
1127         mMult_int   = mMult_int | ((SYSCON->PLL0SSCG0) >> PLL0_SSCG_MD_INT_P);
1128         mMult_fract = ((float)(uint32_t)((SYSCON->PLL0SSCG0) & PLL0_SSCG_MD_FRACT_M) /
1129                        (float)(uint32_t)(1UL << PLL0_SSCG_MD_INT_P));
1130         mMult       = (float)mMult_int + mMult_fract;
1131     }
1132     if (0ULL == ((uint64_t)mMult))
1133     {
1134         mMult = 1.0F;
1135     }
1136     return mMult;
1137 }
1138 
1139 /* Get multiplier (M) from PLL1 MDEC. */
findPll1MMult(void)1140 static uint32_t findPll1MMult(void)
1141 {
1142     uint32_t mMult = 1UL;
1143 
1144     mMult = SYSCON->PLL1MDEC & SYSCON_PLL1MDEC_MDIV_MASK;
1145 
1146     if (mMult == 0UL)
1147     {
1148         mMult = 1UL;
1149     }
1150 
1151     return mMult;
1152 }
1153 
1154 /* Find greatest common divisor between m and n */
FindGreatestCommonDivisor(uint32_t m,uint32_t n)1155 static uint32_t FindGreatestCommonDivisor(uint32_t m, uint32_t n)
1156 {
1157     uint32_t tmp;
1158 
1159     while (n != 0U)
1160     {
1161         tmp = n;
1162         n   = m % n;
1163         m   = tmp;
1164     }
1165 
1166     return m;
1167 }
1168 
1169 /*
1170  * Set PLL0 output based on desired output rate.
1171  * In this function, the it calculates the PLL0 setting for output frequency from input clock
1172  * frequency. The calculation would cost a few time. So it is not recommaned to use it frequently.
1173  * the "pllctrl", "pllndec", "pllpdec", "pllmdec" would updated in this function.
1174  */
CLOCK_GetPll0ConfigInternal(uint32_t finHz,uint32_t foutHz,pll_setup_t * pSetup,bool useSS)1175 static pll_error_t CLOCK_GetPll0ConfigInternal(uint32_t finHz, uint32_t foutHz, pll_setup_t *pSetup, bool useSS)
1176 {
1177     uint32_t nDivOutHz, fccoHz;
1178     uint32_t pllPreDivider, pllMultiplier, pllPostDivider;
1179     uint32_t pllDirectInput, pllDirectOutput;
1180     uint32_t pllSelP, pllSelI, pllSelR, uplimoff;
1181 
1182     /* Baseline parameters (no input or output dividers) */
1183     pllPreDivider   = 1U; /* 1 implies pre-divider will be disabled */
1184     pllPostDivider  = 1U; /* 1 implies post-divider will be disabled */
1185     pllDirectOutput = 1U;
1186 
1187     /* Verify output rate parameter */
1188     if (foutHz > PLL_MAX_CCO_FREQ_MHZ)
1189     {
1190         /* Maximum PLL output with post divider=1 cannot go above this frequency */
1191         return kStatus_PLL_OutputTooHigh;
1192     }
1193     if (foutHz < (PLL_MIN_CCO_FREQ_MHZ / (PVALMAX << 1U)))
1194     {
1195         /* Minmum PLL output with maximum post divider cannot go below this frequency */
1196         return kStatus_PLL_OutputTooLow;
1197     }
1198 
1199     /* If using SS mode, input clock needs to be between 3MHz and 20MHz */
1200     if (useSS)
1201     {
1202         /* Verify input rate parameter */
1203         if (finHz < PLL_MIN_IN_SSMODE)
1204         {
1205             /* Input clock into the PLL cannot be lower than this */
1206             return kStatus_PLL_InputTooLow;
1207         }
1208         /* PLL input in SS mode must be under 20MHz */
1209         if (finHz > (PLL_MAX_IN_SSMODE * NVALMAX))
1210         {
1211             return kStatus_PLL_InputTooHigh;
1212         }
1213     }
1214     else
1215     {
1216         /* Verify input rate parameter */
1217         if (finHz < PLL_LOWER_IN_LIMIT)
1218         {
1219             /* Input clock into the PLL cannot be lower than this */
1220             return kStatus_PLL_InputTooLow;
1221         }
1222         if (finHz > PLL_HIGHER_IN_LIMIT)
1223         {
1224             /* Input clock into the PLL cannot be higher than this */
1225             return kStatus_PLL_InputTooHigh;
1226         }
1227     }
1228 
1229     /* Find the optimal CCO frequency for the output and input that
1230        will keep it inside the PLL CCO range. This may require
1231        tweaking the post-divider for the PLL. */
1232     fccoHz = foutHz;
1233     while (fccoHz < PLL_MIN_CCO_FREQ_MHZ)
1234     {
1235         /* CCO output is less than minimum CCO range, so the CCO output
1236            needs to be bumped up and the post-divider is used to bring
1237            the PLL output back down. */
1238         pllPostDivider++;
1239         if (pllPostDivider > PVALMAX)
1240         {
1241             return kStatus_PLL_OutsideIntLimit;
1242         }
1243 
1244         /* Target CCO goes up, PLL output goes down */
1245         /* divide-by-2 divider in the post-divider is always work*/
1246         fccoHz          = foutHz * (pllPostDivider * 2U);
1247         pllDirectOutput = 0U;
1248     }
1249 
1250     /* Determine if a pre-divider is needed to get the best frequency */
1251     if ((finHz > PLL_LOWER_IN_LIMIT) && (fccoHz >= finHz) && (useSS == false))
1252     {
1253         uint32_t a = FindGreatestCommonDivisor(fccoHz, finHz);
1254 
1255         if (a > PLL_LOWER_IN_LIMIT)
1256         {
1257             a = finHz / a;
1258             if ((a != 0U) && (a < PLL_MAX_N_DIV))
1259             {
1260                 pllPreDivider = a;
1261             }
1262         }
1263     }
1264 
1265     /* Bypass pre-divider hardware if pre-divider is 1 */
1266     if (pllPreDivider > 1U)
1267     {
1268         pllDirectInput = 0U;
1269     }
1270     else
1271     {
1272         pllDirectInput = 1U;
1273     }
1274 
1275     /* Determine PLL multipler */
1276     nDivOutHz     = (finHz / pllPreDivider);
1277     pllMultiplier = (fccoHz / nDivOutHz);
1278 
1279     /* Find optimal values for filter */
1280     if (useSS == false)
1281     {
1282         /* Will bumping up M by 1 get us closer to the desired CCO frequency? */
1283         if ((nDivOutHz * ((pllMultiplier * 2U) + 1U)) < (fccoHz * 2U))
1284         {
1285             pllMultiplier++;
1286         }
1287 
1288         /* Setup filtering */
1289         pllFindSel(pllMultiplier, &pllSelP, &pllSelI, &pllSelR);
1290         uplimoff = 0U;
1291 
1292         /* Get encoded value for M (mult) and use manual filter, disable SS mode */
1293         pSetup->pllsscg[1] =
1294             (uint32_t)((PLL_SSCG1_MDEC_VAL_SET(pllMultiplier)) | (1UL << SYSCON_PLL0SSCG1_SEL_EXT_SHIFT));
1295     }
1296     else
1297     {
1298         uint64_t fc;
1299 
1300         /* Filtering will be handled by SSC */
1301         pllSelR  = 0UL;
1302         pllSelI  = 0UL;
1303         pllSelP  = 0UL;
1304         uplimoff = 1U;
1305 
1306         /* The PLL multiplier will get very close and slightly under the
1307            desired target frequency. A small fractional component can be
1308            added to fine tune the frequency upwards to the target. */
1309         fc = ((uint64_t)(uint32_t)(fccoHz % nDivOutHz) << 25UL) / nDivOutHz;
1310 
1311         /* Set multiplier */
1312         pSetup->pllsscg[0] = (uint32_t)(PLL0_SSCG_MD_INT_SET(pllMultiplier) | PLL0_SSCG_MD_FRACT_SET((uint32_t)fc));
1313         pSetup->pllsscg[1] = (uint32_t)(PLL0_SSCG_MD_INT_SET(pllMultiplier) >> 32U);
1314     }
1315 
1316     /* Get encoded values for N (prediv) and P (postdiv) */
1317     pSetup->pllndec = PLL_NDEC_VAL_SET(pllPreDivider);
1318     pSetup->pllpdec = PLL_PDEC_VAL_SET(pllPostDivider);
1319 
1320     /* PLL control */
1321     pSetup->pllctrl = (pllSelR << SYSCON_PLL0CTRL_SELR_SHIFT) |                  /* Filter coefficient */
1322                       (pllSelI << SYSCON_PLL0CTRL_SELI_SHIFT) |                  /* Filter coefficient */
1323                       (pllSelP << SYSCON_PLL0CTRL_SELP_SHIFT) |                  /* Filter coefficient */
1324                       (0UL << SYSCON_PLL0CTRL_BYPASSPLL_SHIFT) |                 /* PLL bypass mode disabled */
1325                       (uplimoff << SYSCON_PLL0CTRL_LIMUPOFF_SHIFT) |             /* SS/fractional mode disabled */
1326                       (pllDirectInput << SYSCON_PLL0CTRL_BYPASSPREDIV_SHIFT) |   /* Bypass pre-divider? */
1327                       (pllDirectOutput << SYSCON_PLL0CTRL_BYPASSPOSTDIV_SHIFT) | /* Bypass post-divider? */
1328                       (1UL << SYSCON_PLL0CTRL_CLKEN_SHIFT);                      /* Ensure the PLL clock output */
1329 
1330     return kStatus_PLL_Success;
1331 }
1332 
1333 #if (defined(CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT) && CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT)
1334 /* Alloct the static buffer for cache. */
1335 static pll_setup_t s_PllSetupCacheStruct[CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT];
1336 static uint32_t s_FinHzCache[CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT]  = {0};
1337 static uint32_t s_FoutHzCache[CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT] = {0};
1338 static bool s_UseSSCache[CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT]      = {false};
1339 static uint32_t s_PllSetupCacheIdx                                  = 0U;
1340 #endif /* CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT */
1341 
1342 /*
1343  * Calculate the PLL setting values from input clock freq to output freq.
1344  */
CLOCK_GetPll0Config(uint32_t finHz,uint32_t foutHz,pll_setup_t * pSetup,bool useSS)1345 static pll_error_t CLOCK_GetPll0Config(uint32_t finHz, uint32_t foutHz, pll_setup_t *pSetup, bool useSS)
1346 {
1347     pll_error_t retErr;
1348 #if (defined(CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT) && CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT)
1349     uint32_t i;
1350 
1351     for (i = 0U; i < CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT; i++)
1352     {
1353         if ((finHz == s_FinHzCache[i]) && (foutHz == s_FoutHzCache[i]) && (useSS == s_UseSSCache[i]))
1354         {
1355             /* Hit the target in cache buffer. */
1356             pSetup->pllctrl    = s_PllSetupCacheStruct[i].pllctrl;
1357             pSetup->pllndec    = s_PllSetupCacheStruct[i].pllndec;
1358             pSetup->pllpdec    = s_PllSetupCacheStruct[i].pllpdec;
1359             pSetup->pllsscg[0] = s_PllSetupCacheStruct[i].pllsscg[0];
1360             pSetup->pllsscg[1] = s_PllSetupCacheStruct[i].pllsscg[1];
1361             retErr             = kStatus_PLL_Success;
1362             break;
1363         }
1364     }
1365 
1366     if (i < CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT)
1367     {
1368         return retErr;
1369     }
1370 #endif /* CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT */
1371 
1372     retErr = CLOCK_GetPll0ConfigInternal(finHz, foutHz, pSetup, useSS);
1373 
1374 #if (defined(CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT) && CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT)
1375     /* Cache the most recent calulation result into buffer. */
1376     s_FinHzCache[s_PllSetupCacheIdx]  = finHz;
1377     s_FoutHzCache[s_PllSetupCacheIdx] = foutHz;
1378     s_UseSSCache[s_PllSetupCacheIdx]  = useSS;
1379 
1380     s_PllSetupCacheStruct[s_PllSetupCacheIdx].pllctrl    = pSetup->pllctrl;
1381     s_PllSetupCacheStruct[s_PllSetupCacheIdx].pllndec    = pSetup->pllndec;
1382     s_PllSetupCacheStruct[s_PllSetupCacheIdx].pllpdec    = pSetup->pllpdec;
1383     s_PllSetupCacheStruct[s_PllSetupCacheIdx].pllsscg[0] = pSetup->pllsscg[0];
1384     s_PllSetupCacheStruct[s_PllSetupCacheIdx].pllsscg[1] = pSetup->pllsscg[1];
1385     /* Update the index for next available buffer. */
1386     s_PllSetupCacheIdx = (s_PllSetupCacheIdx + 1U) % CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT;
1387 #endif /* CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT */
1388 
1389     return retErr;
1390 }
1391 
1392 /* Update local PLL rate variable */
CLOCK_GetPLL0OutFromSetupUpdate(pll_setup_t * pSetup)1393 static void CLOCK_GetPLL0OutFromSetupUpdate(pll_setup_t *pSetup)
1394 {
1395     s_Pll0_Freq = CLOCK_GetPLL0OutFromSetup(pSetup);
1396 }
1397 
1398 /* Update local PLL1 rate variable */
CLOCK_GetPLL1OutFromSetupUpdate(pll_setup_t * pSetup)1399 static void CLOCK_GetPLL1OutFromSetupUpdate(pll_setup_t *pSetup)
1400 {
1401     s_Pll1_Freq = CLOCK_GetPLL1OutFromSetup(pSetup);
1402 }
1403 
1404 /* Return System PLL input clock rate */
1405 /*! brief    Return  PLL0 input clock rate
1406  *  return    PLL0 input clock rate
1407  */
CLOCK_GetPLL0InClockRate(void)1408 uint32_t CLOCK_GetPLL0InClockRate(void)
1409 {
1410     uint32_t clkRate = 0U;
1411 
1412     switch ((SYSCON->PLL0CLKSEL & SYSCON_PLL0CLKSEL_SEL_MASK))
1413     {
1414         case 0x00U:
1415             clkRate = CLK_FRO_12MHZ;
1416             break;
1417 
1418         case 0x01U:
1419             clkRate = CLOCK_GetExtClkFreq();
1420             break;
1421 
1422         case 0x02U:
1423             clkRate = CLOCK_GetFro1MFreq();
1424             break;
1425 
1426         case 0x03U:
1427             clkRate = CLOCK_GetOsc32KFreq();
1428             break;
1429 
1430         default:
1431             clkRate = 0U;
1432             break;
1433     }
1434 
1435     return clkRate;
1436 }
1437 
1438 /* Return PLL1 input clock rate */
CLOCK_GetPLL1InClockRate(void)1439 uint32_t CLOCK_GetPLL1InClockRate(void)
1440 {
1441     uint32_t clkRate = 0U;
1442 
1443     switch ((SYSCON->PLL1CLKSEL & SYSCON_PLL1CLKSEL_SEL_MASK))
1444     {
1445         case 0x00U:
1446             clkRate = CLK_FRO_12MHZ;
1447             break;
1448 
1449         case 0x01U:
1450             clkRate = CLOCK_GetExtClkFreq();
1451             break;
1452 
1453         case 0x02U:
1454             clkRate = CLOCK_GetFro1MFreq();
1455             break;
1456 
1457         case 0x03U:
1458             clkRate = CLOCK_GetOsc32KFreq();
1459             break;
1460 
1461         default:
1462             clkRate = 0U;
1463             break;
1464     }
1465 
1466     return clkRate;
1467 }
1468 
1469 /* Return PLL0 output clock rate from setup structure */
1470 /*! brief    Return PLL0 output clock rate from setup structure
1471  *  param    pSetup : Pointer to a PLL setup structure
1472  *  return   PLL0 output clock rate the setup structure will generate
1473  */
CLOCK_GetPLL0OutFromSetup(pll_setup_t * pSetup)1474 uint32_t CLOCK_GetPLL0OutFromSetup(pll_setup_t *pSetup)
1475 {
1476     uint32_t clkRate = 0;
1477     uint32_t prediv, postdiv;
1478     float workRate = 0.0F;
1479 
1480     /* Get the input clock frequency of PLL. */
1481     clkRate = CLOCK_GetPLL0InClockRate();
1482 
1483     if (((pSetup->pllctrl & SYSCON_PLL0CTRL_BYPASSPLL_MASK) == 0UL) &&
1484         ((pSetup->pllctrl & SYSCON_PLL0CTRL_CLKEN_MASK) != 0UL) &&
1485         ((PMC->PDRUNCFG0 & PMC_PDRUNCFG0_PDEN_PLL0_MASK) == 0UL) &&
1486         ((PMC->PDRUNCFG0 & PMC_PDRUNCFG0_PDEN_PLL0_SSCG_MASK) == 0UL))
1487     {
1488         prediv  = findPll0PreDiv();
1489         postdiv = findPll0PostDiv();
1490         /* Adjust input clock */
1491         clkRate = clkRate / prediv;
1492         /* MDEC used for rate */
1493         workRate = (float)clkRate * (float)findPll0MMult();
1494         workRate /= (float)postdiv;
1495     }
1496 
1497     return (uint32_t)workRate;
1498 }
1499 
1500 /* Return PLL1 output clock rate from setup structure */
1501 /*! brief    Return PLL1 output clock rate from setup structure
1502  *  param    pSetup : Pointer to a PLL setup structure
1503  *  return   PLL0 output clock rate the setup structure will generate
1504  */
CLOCK_GetPLL1OutFromSetup(pll_setup_t * pSetup)1505 uint32_t CLOCK_GetPLL1OutFromSetup(pll_setup_t *pSetup)
1506 {
1507     uint32_t clkRate = 0;
1508     uint32_t prediv, postdiv;
1509     uint32_t workRate = 0UL;
1510 
1511     /* Get the input clock frequency of PLL. */
1512     clkRate = CLOCK_GetPLL1InClockRate();
1513 
1514     if (((pSetup->pllctrl & SYSCON_PLL1CTRL_BYPASSPLL_MASK) == 0UL) &&
1515         ((pSetup->pllctrl & SYSCON_PLL1CTRL_CLKEN_MASK) != 0UL) &&
1516         ((PMC->PDRUNCFG0 & PMC_PDRUNCFG0_PDEN_PLL1_MASK) == 0UL))
1517     {
1518         prediv  = findPll1PreDiv();
1519         postdiv = findPll1PostDiv();
1520         /* Adjust input clock */
1521         clkRate = clkRate / prediv;
1522         /* MDEC used for rate */
1523         workRate = clkRate * findPll1MMult();
1524         workRate /= postdiv;
1525     }
1526 
1527     return workRate;
1528 }
1529 
1530 /* Set the current PLL0 Rate */
1531 /*! brief Store the current PLL rate
1532  *  param    rate: Current rate of the PLL
1533  *  return   Nothing
1534  **/
CLOCK_SetStoredPLL0ClockRate(uint32_t rate)1535 void CLOCK_SetStoredPLL0ClockRate(uint32_t rate)
1536 {
1537     s_Pll0_Freq = rate;
1538 }
1539 
1540 /* Return PLL0 output clock rate */
1541 /*! brief    Return  PLL0 output clock rate
1542  *  param    recompute   : Forces a PLL rate recomputation if true
1543  *  return    PLL0 output clock rate
1544  *  note The PLL rate is cached in the driver in a variable as
1545  *  the rate computation function can take some time to perform. It
1546  *  is recommended to use 'false' with the 'recompute' parameter.
1547  */
CLOCK_GetPLL0OutClockRate(bool recompute)1548 uint32_t CLOCK_GetPLL0OutClockRate(bool recompute)
1549 {
1550     pll_setup_t Setup;
1551     uint32_t rate;
1552 
1553     if ((recompute) || (s_Pll0_Freq == 0U))
1554     {
1555         Setup.pllctrl    = SYSCON->PLL0CTRL;
1556         Setup.pllndec    = SYSCON->PLL0NDEC;
1557         Setup.pllpdec    = SYSCON->PLL0PDEC;
1558         Setup.pllsscg[0] = SYSCON->PLL0SSCG0;
1559         Setup.pllsscg[1] = SYSCON->PLL0SSCG1;
1560 
1561         CLOCK_GetPLL0OutFromSetupUpdate(&Setup);
1562     }
1563 
1564     rate = s_Pll0_Freq;
1565 
1566     return rate;
1567 }
1568 
1569 /*! brief    Return  PLL1 output clock rate
1570  *  param    recompute   : Forces a PLL rate recomputation if true
1571  *  return    PLL1 output clock rate
1572  *  note The PLL rate is cached in the driver in a variable as
1573  *  the rate computation function can take some time to perform. It
1574  *  is recommended to use 'false' with the 'recompute' parameter.
1575  */
CLOCK_GetPLL1OutClockRate(bool recompute)1576 uint32_t CLOCK_GetPLL1OutClockRate(bool recompute)
1577 {
1578     pll_setup_t Setup;
1579     uint32_t rate;
1580 
1581     if ((recompute) || (s_Pll1_Freq == 0U))
1582     {
1583         Setup.pllctrl = SYSCON->PLL1CTRL;
1584         Setup.pllndec = SYSCON->PLL1NDEC;
1585         Setup.pllpdec = SYSCON->PLL1PDEC;
1586         Setup.pllmdec = SYSCON->PLL1MDEC;
1587         CLOCK_GetPLL1OutFromSetupUpdate(&Setup);
1588     }
1589 
1590     rate = s_Pll1_Freq;
1591 
1592     return rate;
1593 }
1594 
1595 /* Set PLL0 output based on the passed PLL setup data */
1596 /*! brief    Set PLL output based on the passed PLL setup data
1597  *  param    pControl    : Pointer to populated PLL control structure to generate setup with
1598  *  param    pSetup      : Pointer to PLL setup structure to be filled
1599  *  return   PLL_ERROR_SUCCESS on success, or PLL setup error code
1600  *  note Actual frequency for setup may vary from the desired frequency based on the
1601  *  accuracy of input clocks, rounding, non-fractional PLL mode, etc.
1602  */
CLOCK_SetupPLL0Data(pll_config_t * pControl,pll_setup_t * pSetup)1603 pll_error_t CLOCK_SetupPLL0Data(pll_config_t *pControl, pll_setup_t *pSetup)
1604 {
1605     uint32_t inRate;
1606     bool useSS = (bool)((pControl->flags & PLL_CONFIGFLAG_FORCENOFRACT) == 0UL);
1607 
1608     pll_error_t pllError;
1609 
1610     /* Determine input rate for the PLL */
1611     if ((pControl->flags & PLL_CONFIGFLAG_USEINRATE) != 0UL)
1612     {
1613         inRate = pControl->inputRate;
1614     }
1615     else
1616     {
1617         inRate = CLOCK_GetPLL0InClockRate();
1618     }
1619 
1620     /* PLL flag options */
1621     pllError = CLOCK_GetPll0Config(inRate, pControl->desiredRate, pSetup, useSS);
1622     if ((useSS) && (pllError == kStatus_PLL_Success))
1623     {
1624         /* If using SS mode, then some tweaks are made to the generated setup */
1625         pSetup->pllsscg[1] |= (uint32_t)pControl->ss_mf | (uint32_t)pControl->ss_mr | (uint32_t)pControl->ss_mc;
1626         if (pControl->mfDither)
1627         {
1628             pSetup->pllsscg[1] |= (1UL << SYSCON_PLL0SSCG1_DITHER_SHIFT);
1629         }
1630     }
1631 
1632     return pllError;
1633 }
1634 
1635 /* Set PLL0 output from PLL setup structure */
1636 /*! brief    Set PLL output from PLL setup structure (precise frequency)
1637  * param pSetup  : Pointer to populated PLL setup structure
1638  * param flagcfg : Flag configuration for PLL config structure
1639  * return    PLL_ERROR_SUCCESS on success, or PLL setup error code
1640  * note  This function will power off the PLL, setup the PLL with the
1641  * new setup data, and then optionally powerup the PLL, wait for PLL lock,
1642  * and adjust system voltages to the new PLL rate. The function will not
1643  * alter any source clocks (ie, main systen clock) that may use the PLL,
1644  * so these should be setup prior to and after exiting the function.
1645  */
CLOCK_SetupPLL0Prec(pll_setup_t * pSetup,uint32_t flagcfg)1646 pll_error_t CLOCK_SetupPLL0Prec(pll_setup_t *pSetup, uint32_t flagcfg)
1647 {
1648     uint32_t inRate, clkRate, prediv;
1649     uint32_t pll_lock_wait_time     = 0U;
1650     uint32_t max_pll_lock_wait_time = 0U;
1651     /* Power off PLL during setup changes */
1652     POWER_EnablePD(kPDRUNCFG_PD_PLL0);
1653     POWER_EnablePD(kPDRUNCFG_PD_PLL0_SSCG);
1654 
1655     pSetup->flags = flagcfg;
1656 
1657     /* Write PLL setup data */
1658     SYSCON->PLL0CTRL  = pSetup->pllctrl;
1659     SYSCON->PLL0NDEC  = pSetup->pllndec;
1660     SYSCON->PLL0NDEC  = pSetup->pllndec | (1UL << SYSCON_PLL0NDEC_NREQ_SHIFT); /* latch */
1661     SYSCON->PLL0PDEC  = pSetup->pllpdec;
1662     SYSCON->PLL0PDEC  = pSetup->pllpdec | (1UL << SYSCON_PLL0PDEC_PREQ_SHIFT); /* latch */
1663     SYSCON->PLL0SSCG0 = pSetup->pllsscg[0];
1664     SYSCON->PLL0SSCG1 = pSetup->pllsscg[1];
1665     SYSCON->PLL0SSCG1 =
1666         pSetup->pllsscg[1] | (1UL << SYSCON_PLL0SSCG1_MREQ_SHIFT) | (1UL << SYSCON_PLL0SSCG1_MD_REQ_SHIFT); /* latch */
1667 
1668     POWER_DisablePD(kPDRUNCFG_PD_PLL0);
1669     POWER_DisablePD(kPDRUNCFG_PD_PLL0_SSCG);
1670 
1671     if ((pSetup->flags & PLL_SETUPFLAG_WAITLOCK) != 0UL)
1672     {
1673         if ((SYSCON->PLL0SSCG1 & SYSCON_PLL0SSCG1_SEL_EXT_MASK) != 0UL) /* normal mode */
1674         {
1675             inRate = CLOCK_GetPLL0InClockRate();
1676             prediv = findPll0PreDiv();
1677             /* Adjust input clock */
1678             clkRate = inRate / prediv;
1679 
1680             /* Need wait at least (500us + 400/Fref) (Fref in Hz result in s) to ensure the PLL is stable.
1681                The lock bit could be used to shorten the wait time when freq<20MHZ */
1682             max_pll_lock_wait_time = 500U + (400000000U / clkRate);
1683 
1684             if (clkRate < 20000000UL)
1685             {
1686                 pll_lock_wait_time = 0U;
1687                 while ((CLOCK_IsPLL0Locked() == false) && (pll_lock_wait_time < max_pll_lock_wait_time))
1688                 {
1689                     pll_lock_wait_time += 100U;
1690                     SDK_DelayAtLeastUs(100U, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
1691                 }
1692             }
1693             else
1694             {
1695                 SDK_DelayAtLeastUs(max_pll_lock_wait_time, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
1696             }
1697         }
1698         else /* spread spectrum mode */
1699         {
1700             SDK_DelayAtLeastUs(6000U,
1701                                SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY); /* software should use a 6 ms time interval to
1702                                                                            insure the PLL will be stable */
1703         }
1704     }
1705 
1706     /* Update current programmed PLL rate var */
1707     CLOCK_GetPLL0OutFromSetupUpdate(pSetup);
1708 
1709     /* System voltage adjustment, occurs prior to setting main system clock */
1710     if ((pSetup->flags & PLL_SETUPFLAG_ADGVOLT) != 0UL)
1711     {
1712         POWER_SetVoltageForFreq(s_Pll0_Freq);
1713     }
1714 
1715     return kStatus_PLL_Success;
1716 }
1717 
1718 /* Setup PLL Frequency from pre-calculated value */
1719 /**
1720  * brief Set PLL0 output from PLL setup structure (precise frequency)
1721  * param pSetup  : Pointer to populated PLL setup structure
1722  * return    kStatus_PLL_Success on success, or PLL setup error code
1723  * note  This function will power off the PLL, setup the PLL with the
1724  * new setup data, and then optionally powerup the PLL, wait for PLL lock,
1725  * and adjust system voltages to the new PLL rate. The function will not
1726  * alter any source clocks (ie, main systen clock) that may use the PLL,
1727  * so these should be setup prior to and after exiting the function.
1728  */
CLOCK_SetPLL0Freq(const pll_setup_t * pSetup)1729 pll_error_t CLOCK_SetPLL0Freq(const pll_setup_t *pSetup)
1730 {
1731     uint32_t inRate, clkRate, prediv;
1732     uint32_t pll_lock_wait_time     = 0U;
1733     uint32_t max_pll_lock_wait_time = 0U;
1734     /* Power off PLL during setup changes */
1735     POWER_EnablePD(kPDRUNCFG_PD_PLL0);
1736     POWER_EnablePD(kPDRUNCFG_PD_PLL0_SSCG);
1737 
1738     /* Write PLL setup data */
1739     SYSCON->PLL0CTRL  = pSetup->pllctrl;
1740     SYSCON->PLL0NDEC  = pSetup->pllndec;
1741     SYSCON->PLL0NDEC  = pSetup->pllndec | (1UL << SYSCON_PLL0NDEC_NREQ_SHIFT); /* latch */
1742     SYSCON->PLL0PDEC  = pSetup->pllpdec;
1743     SYSCON->PLL0PDEC  = pSetup->pllpdec | (1UL << SYSCON_PLL0PDEC_PREQ_SHIFT); /* latch */
1744     SYSCON->PLL0SSCG0 = pSetup->pllsscg[0];
1745     SYSCON->PLL0SSCG1 = pSetup->pllsscg[1];
1746     SYSCON->PLL0SSCG1 =
1747         pSetup->pllsscg[1] | (1UL << SYSCON_PLL0SSCG1_MD_REQ_SHIFT) | (1UL << SYSCON_PLL0SSCG1_MREQ_SHIFT); /* latch */
1748 
1749     POWER_DisablePD(kPDRUNCFG_PD_PLL0);
1750     POWER_DisablePD(kPDRUNCFG_PD_PLL0_SSCG);
1751 
1752     if ((pSetup->flags & PLL_SETUPFLAG_WAITLOCK) != 0UL)
1753     {
1754         if ((SYSCON->PLL0SSCG1 & SYSCON_PLL0SSCG1_SEL_EXT_MASK) != 0UL) /* normal mode */
1755         {
1756             inRate = CLOCK_GetPLL0InClockRate();
1757             prediv = findPll0PreDiv();
1758             /* Adjust input clock */
1759             clkRate = inRate / prediv;
1760 
1761             /* Need wait at least (500us + 400/Fref) (Fref in Hz result in s) to ensure the PLL is
1762                stable. The lock bit could be used to shorten the wait time when freq<20MHZ */
1763             max_pll_lock_wait_time = 500U + (400000000U / clkRate);
1764 
1765             if (clkRate < 20000000UL)
1766             {
1767                 pll_lock_wait_time = 0U;
1768                 while ((CLOCK_IsPLL0Locked() == false) && (pll_lock_wait_time < max_pll_lock_wait_time))
1769                 {
1770                     pll_lock_wait_time += 100U;
1771                     SDK_DelayAtLeastUs(100U, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
1772                 }
1773             }
1774             else
1775             {
1776                 SDK_DelayAtLeastUs(max_pll_lock_wait_time, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
1777             }
1778         }
1779         else /* spread spectrum mode */
1780         {
1781             SDK_DelayAtLeastUs(6000U,
1782                                SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY); /* software should use a 6 ms time interval
1783                                                                            to insure the PLL will be stable */
1784         }
1785     }
1786 
1787     /* Update current programmed PLL rate var */
1788     s_Pll0_Freq = pSetup->pllRate;
1789 
1790     return kStatus_PLL_Success;
1791 }
1792 
1793 /* Setup PLL1 Frequency from pre-calculated value */
1794 /**
1795  * brief Set PLL1 output from PLL setup structure (precise frequency)
1796  * param pSetup  : Pointer to populated PLL setup structure
1797  * return    kStatus_PLL_Success on success, or PLL setup error code
1798  * note  This function will power off the PLL, setup the PLL with the
1799  * new setup data, and then optionally powerup the PLL, wait for PLL lock,
1800  * and adjust system voltages to the new PLL rate. The function will not
1801  * alter any source clocks (ie, main systen clock) that may use the PLL,
1802  * so these should be setup prior to and after exiting the function.
1803  */
CLOCK_SetPLL1Freq(const pll_setup_t * pSetup)1804 pll_error_t CLOCK_SetPLL1Freq(const pll_setup_t *pSetup)
1805 {
1806     uint32_t inRate, clkRate, prediv;
1807     uint32_t pll_lock_wait_time     = 0U;
1808     uint32_t max_pll_lock_wait_time = 0U;
1809     /* Power off PLL during setup changes */
1810     POWER_EnablePD(kPDRUNCFG_PD_PLL1);
1811 
1812     /* Write PLL setup data */
1813     SYSCON->PLL1CTRL = pSetup->pllctrl;
1814     SYSCON->PLL1NDEC = pSetup->pllndec;
1815     SYSCON->PLL1NDEC = pSetup->pllndec | (1UL << SYSCON_PLL1NDEC_NREQ_SHIFT); /* latch */
1816     SYSCON->PLL1PDEC = pSetup->pllpdec;
1817     SYSCON->PLL1PDEC = pSetup->pllpdec | (1UL << SYSCON_PLL1PDEC_PREQ_SHIFT); /* latch */
1818     SYSCON->PLL1MDEC = pSetup->pllmdec;
1819     SYSCON->PLL1MDEC = pSetup->pllmdec | (1UL << SYSCON_PLL1MDEC_MREQ_SHIFT); /* latch */
1820 
1821     POWER_DisablePD(kPDRUNCFG_PD_PLL1);
1822 
1823     if ((pSetup->flags & PLL_SETUPFLAG_WAITLOCK) != 0UL)
1824     {
1825         inRate = CLOCK_GetPLL1InClockRate();
1826         prediv = findPll1PreDiv();
1827         /* Adjust input clock */
1828         clkRate = inRate / prediv;
1829 
1830         /* Need wait at least (500us + 400/Fref) (Fref in Hz result in s) to ensure the PLL is stable.
1831            The lock bit could be used to shorten the wait time when freq<20MHZ */
1832         max_pll_lock_wait_time = 500U + (400000000U / clkRate);
1833 
1834         if (clkRate < 20000000UL)
1835         {
1836             pll_lock_wait_time = 0U;
1837             while ((CLOCK_IsPLL1Locked() == false) && (pll_lock_wait_time < max_pll_lock_wait_time))
1838             {
1839                 pll_lock_wait_time += 100U;
1840                 SDK_DelayAtLeastUs(100U, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
1841             }
1842         }
1843         else
1844         {
1845             SDK_DelayAtLeastUs(max_pll_lock_wait_time, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
1846         }
1847     }
1848 
1849     /* Update current programmed PLL rate var */
1850     s_Pll1_Freq = pSetup->pllRate;
1851 
1852     return kStatus_PLL_Success;
1853 }
1854 
1855 /* Set PLL0 clock based on the input frequency and multiplier */
1856 /*! brief    Set PLL0 output based on the multiplier and input frequency
1857  * param multiply_by : multiplier
1858  * param input_freq  : Clock input frequency of the PLL
1859  * return    Nothing
1860  * note  Unlike the Chip_Clock_SetupSystemPLLPrec() function, this
1861  * function does not disable or enable PLL power, wait for PLL lock,
1862  * or adjust system voltages. These must be done in the application.
1863  * The function will not alter any source clocks (ie, main systen clock)
1864  * that may use the PLL, so these should be setup prior to and after
1865  * exiting the function.
1866  */
CLOCK_SetupPLL0Mult(uint32_t multiply_by,uint32_t input_freq)1867 void CLOCK_SetupPLL0Mult(uint32_t multiply_by, uint32_t input_freq)
1868 {
1869     uint32_t cco_freq = input_freq * multiply_by;
1870     uint32_t pdec     = 1U;
1871     uint32_t selr;
1872     uint32_t seli;
1873     uint32_t selp;
1874     uint32_t mdec, ndec;
1875 
1876     while (cco_freq < 275000000U)
1877     {
1878         multiply_by <<= 1U; /* double value in each iteration */
1879         pdec <<= 1U;        /* correspondingly double pdec to cancel effect of double msel */
1880         cco_freq = input_freq * multiply_by;
1881     }
1882 
1883     selr = 0U;
1884 
1885     if (multiply_by >= 8000UL)
1886     {
1887         seli = 1UL;
1888     }
1889     else if (multiply_by >= 122UL)
1890     {
1891         seli = (uint32_t)(8000UL / multiply_by); /*floor(8000/M) */
1892     }
1893     else
1894     {
1895         seli = 2UL * ((uint32_t)(multiply_by / 4UL)) + 3UL; /* 2*floor(M/4) + 3 */
1896     }
1897 
1898     if (seli >= 63U)
1899     {
1900         seli = 63U;
1901     }
1902 
1903     {
1904         selp = 31U;
1905     }
1906 
1907     if (pdec > 1U)
1908     {
1909         pdec = pdec / 2U; /* Account for minus 1 encoding */
1910                           /* Translate P value */
1911     }
1912 
1913     mdec = (uint32_t)PLL_SSCG1_MDEC_VAL_SET(multiply_by);
1914     ndec = 0x1U; /* pre divide by 1 (hardcoded) */
1915 
1916     SYSCON->PLL0CTRL = SYSCON_PLL0CTRL_CLKEN_MASK | SYSCON_PLL0CTRL_BYPASSPOSTDIV(0) |
1917                        SYSCON_PLL0CTRL_BYPASSPOSTDIV2(0) | (selr << SYSCON_PLL0CTRL_SELR_SHIFT) |
1918                        (seli << SYSCON_PLL0CTRL_SELI_SHIFT) | (selp << SYSCON_PLL0CTRL_SELP_SHIFT);
1919     SYSCON->PLL0PDEC = pdec | (1UL << SYSCON_PLL0PDEC_PREQ_SHIFT); /* set Pdec value and assert preq */
1920     SYSCON->PLL0NDEC = ndec | (1UL << SYSCON_PLL0NDEC_NREQ_SHIFT); /* set Pdec value and assert preq */
1921     SYSCON->PLL0SSCG1 =
1922         mdec | (1UL << SYSCON_PLL0SSCG1_MREQ_SHIFT); /* select non sscg MDEC value, assert mreq and select mdec value */
1923 }
1924 
1925 /*! @brief Enable the OSTIMER 32k clock.
1926  *  @return  Nothing
1927  */
CLOCK_EnableOstimer32kClock(void)1928 void CLOCK_EnableOstimer32kClock(void)
1929 {
1930     PMC->OSTIMERr |= PMC_OSTIMER_CLOCKENABLE_MASK;
1931 }
1932