2 * Copyright (c) 2016, Freescale Semiconductor, Inc.
\r
3 * Copyright 2016 - 2019 , NXP
\r
4 * All rights reserved.
\r
7 * SPDX-License-Identifier: BSD-3-Clause
\r
10 #include "fsl_clock.h"
\r
11 #include "fsl_power.h"
\r
12 /*******************************************************************************
\r
14 ******************************************************************************/
\r
15 /* Component ID definition, used by tools. */
\r
16 #ifndef FSL_COMPONENT_ID
\r
17 #define FSL_COMPONENT_ID "platform.drivers.clock"
\r
19 #define NVALMAX (0x100U)
\r
20 #define PVALMAX (0x20U)
\r
21 #define MVALMAX (0x8000U)
\r
23 #define PLL_MAX_N_DIV 0x100U
\r
25 #define INDEX_SECTOR_TRIM48 ((uint32_t *)0x01000444U)
\r
26 #define INDEX_SECTOR_TRIM96 ((uint32_t *)0x01000430U)
\r
27 /*--------------------------------------------------------------------------
\r
28 !!! If required these #defines can be moved to chip library file
\r
29 ----------------------------------------------------------------------------*/
\r
31 #define PLL_SSCG0_MDEC_VAL_P (0U) /* MDEC is in bits 16 downto 0 */
\r
32 #define PLL_SSCG0_MDEC_VAL_M (0x1FFFFUL << PLL_SSCG0_MDEC_VAL_P) /* NDEC is in bits 9 downto 0 */
\r
33 #define PLL_NDEC_VAL_P (0U) /* NDEC is in bits 9:0 */
\r
34 #define PLL_NDEC_VAL_M (0x3FFUL << PLL_NDEC_VAL_P)
\r
35 #define PLL_PDEC_VAL_P (0U) /* PDEC is in bits 6:0 */
\r
36 #define PLL_PDEC_VAL_M (0x7FUL << PLL_PDEC_VAL_P)
\r
38 #define PLL_MIN_CCO_FREQ_MHZ (75000000U)
\r
39 #define PLL_MAX_CCO_FREQ_MHZ (150000000U)
\r
40 #define PLL_LOWER_IN_LIMIT (4000U) /*!< Minimum PLL input rate */
\r
41 #define PLL_MIN_IN_SSMODE (2000000U)
\r
42 #define PLL_MAX_IN_SSMODE (4000000U)
\r
44 /* Middle of the range values for spread-spectrum */
\r
45 #define PLL_SSCG_MF_FREQ_VALUE 4U
\r
46 #define PLL_SSCG_MC_COMP_VALUE 2U
\r
47 #define PLL_SSCG_MR_DEPTH_VALUE 4U
\r
48 #define PLL_SSCG_DITHER_VALUE 0U
\r
51 #define PLL_NDEC_VAL_SET(value) (((unsigned long)(value) << PLL_NDEC_VAL_P) & PLL_NDEC_VAL_M)
\r
53 #define PLL_PDEC_VAL_SET(value) (((unsigned long)(value) << PLL_PDEC_VAL_P) & PLL_PDEC_VAL_M)
\r
55 #define PLL_SSCG0_MDEC_VAL_SET(value) (((unsigned long)(value) << PLL_SSCG0_MDEC_VAL_P) & PLL_SSCG0_MDEC_VAL_M)
\r
58 #define PLL_SSCG1_MD_FRACT_P 0U
\r
59 #define PLL_SSCG1_MD_INT_P 11U
\r
60 #define PLL_SSCG1_MD_FRACT_M (0x7FFUL << PLL_SSCG1_MD_FRACT_P)
\r
61 #define PLL_SSCG1_MD_INT_M (0xFFUL << PLL_SSCG1_MD_INT_P)
\r
63 #define PLL_SSCG1_MD_FRACT_SET(value) (((unsigned long)(value) << PLL_SSCG1_MD_FRACT_P) & PLL_SSCG1_MD_FRACT_M)
\r
64 #define PLL_SSCG1_MD_INT_SET(value) (((unsigned long)(value) << PLL_SSCG1_MD_INT_P) & PLL_SSCG1_MD_INT_M)
\r
66 /* Saved value of PLL output rate, computed whenever needed to save run-time
\r
67 computation on each call to retrive the PLL rate. */
\r
68 static uint32_t s_Pll_Freq;
\r
70 uint32_t g_I2S_Mclk_Freq = 0U;
\r
72 /** External clock rate on the CLKIN pin in Hz. If not used,
\r
73 set this to 0. Otherwise, set it to the exact rate in Hz this pin is
\r
75 const uint32_t g_Ext_Clk_Freq = 0U;
\r
77 /*******************************************************************************
\r
79 ******************************************************************************/
\r
81 /*******************************************************************************
\r
83 ******************************************************************************/
\r
84 /* Find encoded NDEC value for raw N value, max N = NVALMAX */
\r
85 static uint32_t pllEncodeN(uint32_t N);
\r
86 /* Find decoded N value for raw NDEC value */
\r
87 static uint32_t pllDecodeN(uint32_t NDEC);
\r
88 /* Find encoded PDEC value for raw P value, max P = PVALMAX */
\r
89 static uint32_t pllEncodeP(uint32_t P);
\r
90 /* Find decoded P value for raw PDEC value */
\r
91 static uint32_t pllDecodeP(uint32_t PDEC);
\r
92 /* Find encoded MDEC value for raw M value, max M = MVALMAX */
\r
93 static uint32_t pllEncodeM(uint32_t M);
\r
94 /* Find decoded M value for raw MDEC value */
\r
95 static uint32_t pllDecodeM(uint32_t MDEC);
\r
96 /* Find SELP, SELI, and SELR values for raw M value, max M = MVALMAX */
\r
97 static void pllFindSel(uint32_t M, bool bypassFBDIV2, uint32_t *pSelP, uint32_t *pSelI, uint32_t *pSelR);
\r
98 /* Get predivider (N) from PLL NDEC setting */
\r
99 static uint32_t findPllPreDiv(uint32_t ctrlReg, uint32_t nDecReg);
\r
100 /* Get postdivider (P) from PLL PDEC setting */
\r
101 static uint32_t findPllPostDiv(uint32_t ctrlReg, uint32_t pDecReg);
\r
102 /* Get multiplier (M) from PLL MDEC and BYPASS_FBDIV2 settings */
\r
103 static uint32_t findPllMMult(uint32_t ctrlReg, uint32_t mDecReg);
\r
104 /* Get the greatest common divisor */
\r
105 static uint32_t FindGreatestCommonDivisor(uint32_t m, uint32_t n);
\r
106 /* Set PLL output based on desired output rate */
\r
107 static pll_error_t CLOCK_GetPllConfig(
\r
108 uint32_t finHz, uint32_t foutHz, pll_setup_t *pSetup, bool useFeedbackDiv2, bool useSS);
\r
109 /* Update local PLL rate variable */
\r
110 static void CLOCK_GetSystemPLLOutFromSetupUpdate(pll_setup_t *pSetup);
\r
112 static const uint8_t wdtFreqLookup[32] = {0, 8, 12, 15, 18, 20, 24, 26, 28, 30, 32, 34, 36, 38, 40, 41,
\r
113 42, 44, 45, 46, 48, 49, 50, 52, 53, 54, 56, 57, 58, 59, 60, 61};
\r
114 /*******************************************************************************
\r
116 ******************************************************************************/
\r
119 * brief Configure the clock selection muxes.
\r
120 * param connection : Clock to be configured.
\r
123 void CLOCK_AttachClk(clock_attach_id_t connection)
\r
128 uint32_t tmp32 = (uint32_t)connection;
\r
130 volatile uint32_t *pClkSel;
\r
132 pClkSel = &(SYSCON->MAINCLKSELA);
\r
134 if (kNONE_to_NONE != connection)
\r
136 for (i = 0U; i < 2U; i++)
\r
142 item = (uint16_t)GET_ID_ITEM(tmp32);
\r
145 mux = GET_ID_ITEM_MUX(item);
\r
146 sel = GET_ID_ITEM_SEL(item);
\r
147 if (mux == CM_ASYNCAPB)
\r
149 ASYNC_SYSCON->ASYNCAPBCLKSELA = sel;
\r
153 pClkSel[mux] = sel;
\r
156 tmp32 = GET_ID_NEXT_ITEM(tmp32); /* pick up next descriptor */
\r
161 /* Return the actual clock attach id */
\r
163 * brief Get the actual clock attach id.
\r
164 * This fuction uses the offset in input attach id, then it reads the actual source value in
\r
165 * the register and combine the offset to obtain an actual attach id.
\r
166 * param attachId : Clock attach id to get.
\r
167 * return Clock source value.
\r
169 clock_attach_id_t CLOCK_GetClockAttachId(clock_attach_id_t attachId)
\r
173 uint32_t tmp32 = (uint32_t)attachId;
\r
175 uint32_t actualAttachId = 0U;
\r
176 uint32_t selector = GET_ID_SELECTOR(tmp32);
\r
177 volatile uint32_t *pClkSel;
\r
179 pClkSel = &(SYSCON->MAINCLKSELA);
\r
181 if (kNONE_to_NONE == attachId)
\r
183 return kNONE_to_NONE;
\r
186 for (i = 0U; i < 2U; i++)
\r
188 mux = GET_ID_ITEM_MUX(tmp32);
\r
191 if (mux == CM_ASYNCAPB)
\r
193 actualSel = ASYNC_SYSCON->ASYNCAPBCLKSELA;
\r
197 actualSel = pClkSel[mux];
\r
200 /* Consider the combination of two registers */
\r
201 actualAttachId |= CLK_ATTACH_ID(mux, actualSel, i);
\r
203 tmp32 = GET_ID_NEXT_ITEM(tmp32); /*!< pick up next descriptor */
\r
206 actualAttachId |= selector;
\r
208 return (clock_attach_id_t)actualAttachId;
\r
212 * brief Setup peripheral clock dividers.
\r
213 * param div_name : Clock divider name
\r
214 * param divided_by_value: Value to be divided
\r
215 * param reset : Whether to reset the divider counter.
\r
218 void CLOCK_SetClkDiv(clock_div_name_t div_name, uint32_t divided_by_value, bool reset)
\r
220 volatile uint32_t *pClkDiv;
\r
222 pClkDiv = &(SYSCON->SYSTICKCLKDIV);
\r
225 pClkDiv[div_name] = 1U << 29U;
\r
227 if (divided_by_value == 0U) /* halt */
\r
229 pClkDiv[div_name] = 1U << 30U;
\r
233 pClkDiv[div_name] = (divided_by_value - 1U);
\r
237 /* Set FRO Clocking */
\r
239 * brief Initialize the Core clock to given frequency (12, 48 or 96 MHz).
\r
240 * Turns on FRO and uses default CCO, if freq is 12000000, then high speed output is off, else high speed output is
\r
242 * param iFreq : Desired frequency (must be one of CLK_FRO_12MHZ or CLK_FRO_48MHZ or CLK_FRO_96MHZ)
\r
243 * return returns success or fail status.
\r
245 status_t CLOCK_SetupFROClocking(uint32_t iFreq)
\r
248 if ((iFreq != 12000000U) && (iFreq != 48000000U) && (iFreq != 96000000U))
\r
250 return kStatus_Fail;
\r
252 /* Power up the FRO and set this as the base clock */
\r
253 POWER_DisablePD(kPDRUNCFG_PD_FRO_EN);
\r
254 /* back up the value of whether USB adj is selected, in which case we will have a value of 1 else 0 */
\r
255 usb_adj = ((SYSCON->FROCTRL) & SYSCON_FROCTRL_USBCLKADJ_MASK) >> SYSCON_FROCTRL_USBCLKADJ_SHIFT;
\r
256 if (iFreq > 12000000U)
\r
258 if (iFreq == 96000000U)
\r
260 SYSCON->FROCTRL = ((SYSCON_FROCTRL_TRIM_MASK | SYSCON_FROCTRL_FREQTRIM_MASK) & *INDEX_SECTOR_TRIM96) |
\r
261 SYSCON_FROCTRL_SEL(1) | SYSCON_FROCTRL_WRTRIM(1) | SYSCON_FROCTRL_USBCLKADJ(usb_adj) |
\r
262 SYSCON_FROCTRL_HSPDCLK(1);
\r
266 SYSCON->FROCTRL = ((SYSCON_FROCTRL_TRIM_MASK | SYSCON_FROCTRL_FREQTRIM_MASK) & *INDEX_SECTOR_TRIM48) |
\r
267 SYSCON_FROCTRL_SEL(0) | SYSCON_FROCTRL_WRTRIM(1) | SYSCON_FROCTRL_USBCLKADJ(usb_adj) |
\r
268 SYSCON_FROCTRL_HSPDCLK(1);
\r
273 SYSCON->FROCTRL &= ~SYSCON_FROCTRL_HSPDCLK(1);
\r
279 /*! brief Return Frequency of FRO 12MHz
\r
280 * return Frequency of FRO 12MHz
\r
282 uint32_t CLOCK_GetFro12MFreq(void)
\r
284 return (SYSCON->PDRUNCFG[0] & SYSCON_PDRUNCFG_PDEN_FRO_MASK) ? 0U : 12000000U;
\r
287 /*! brief Return Frequency of External Clock
\r
288 * return Frequency of External Clock. If no external clock is used returns 0.
\r
290 uint32_t CLOCK_GetExtClkFreq(void)
\r
292 return (g_Ext_Clk_Freq);
\r
294 /*! brief Return Frequency of Watchdog Oscillator
\r
295 * return Frequency of Watchdog Oscillator
\r
297 uint32_t CLOCK_GetWdtOscFreq(void)
\r
299 uint8_t freq_sel, div_sel;
\r
300 if (SYSCON->PDRUNCFG[0] & (1UL << (kPDRUNCFG_PD_WDT_OSC & 0xffU)))
\r
306 div_sel = ((SYSCON->WDTOSCCTRL & 0x1f) + 1) << 1;
\r
308 wdtFreqLookup[((SYSCON->WDTOSCCTRL & SYSCON_WDTOSCCTRL_FREQSEL_MASK) >> SYSCON_WDTOSCCTRL_FREQSEL_SHIFT)];
\r
309 return ((uint32_t)freq_sel * 50000U) / ((uint32_t)div_sel);
\r
313 /*! brief Return Frequency of High-Freq output of FRO
\r
314 * return Frequency of High-Freq output of FRO
\r
316 uint32_t CLOCK_GetFroHfFreq(void)
\r
318 return (SYSCON->PDRUNCFG[0] & SYSCON_PDRUNCFG_PDEN_FRO_MASK) ?
\r
320 !(SYSCON->FROCTRL & SYSCON_FROCTRL_HSPDCLK_MASK) ?
\r
322 (SYSCON->FROCTRL & SYSCON_FROCTRL_SEL_MASK) ? 96000000U : 48000000U;
\r
325 /*! brief Return Frequency of PLL
\r
326 * return Frequency of PLL
\r
328 uint32_t CLOCK_GetPllOutFreq(void)
\r
333 /*! brief Return Frequency of 32kHz osc
\r
334 * return Frequency of 32kHz osc
\r
336 uint32_t CLOCK_GetOsc32KFreq(void)
\r
338 return CLK_RTC_32K_CLK; /* Needs to be corrected to check that RTC Clock is enabled */
\r
340 /*! brief Return Frequency of Core System
\r
341 * return Frequency of Core System
\r
343 uint32_t CLOCK_GetCoreSysClkFreq(void)
\r
345 return ((SYSCON->MAINCLKSELB == 0U) && (SYSCON->MAINCLKSELA == 0U)) ?
\r
346 CLOCK_GetFro12MFreq() :
\r
347 ((SYSCON->MAINCLKSELB == 0U) && (SYSCON->MAINCLKSELA == 1U)) ?
\r
348 CLOCK_GetExtClkFreq() :
\r
349 ((SYSCON->MAINCLKSELB == 0U) && (SYSCON->MAINCLKSELA == 2U)) ?
\r
350 CLOCK_GetWdtOscFreq() :
\r
351 ((SYSCON->MAINCLKSELB == 0U) && (SYSCON->MAINCLKSELA == 3U)) ?
\r
352 CLOCK_GetFroHfFreq() :
\r
353 (SYSCON->MAINCLKSELB == 2U) ? CLOCK_GetPllOutFreq() :
\r
354 (SYSCON->MAINCLKSELB == 3U) ? CLOCK_GetOsc32KFreq() : 0U;
\r
356 /*! brief Return Frequency of I2S MCLK Clock
\r
357 * return Frequency of I2S MCLK Clock
\r
359 uint32_t CLOCK_GetI2SMClkFreq(void)
\r
361 return g_I2S_Mclk_Freq;
\r
364 /*! brief Return Frequency of Asynchronous APB Clock
\r
365 * return Frequency of Asynchronous APB Clock Clock
\r
367 uint32_t CLOCK_GetAsyncApbClkFreq(void)
\r
369 async_clock_src_t clkSrc;
\r
372 clkSrc = CLOCK_GetAsyncApbClkSrc();
\r
376 case kCLOCK_AsyncMainClk:
\r
377 clkRate = CLOCK_GetCoreSysClkFreq();
\r
379 case kCLOCK_AsyncFro12Mhz:
\r
380 clkRate = CLK_FRO_12MHZ;
\r
390 /*! brief Return Frequency of Flexcomm functional Clock
\r
391 * return Frequency of Flexcomm functional Clock
\r
393 uint32_t CLOCK_GetFlexCommClkFreq(uint32_t id)
\r
395 return (SYSCON->FXCOMCLKSEL[id] == 0U) ?
\r
396 CLOCK_GetFro12MFreq() :
\r
397 (SYSCON->FXCOMCLKSEL[id] == 1U) ?
\r
398 CLOCK_GetFroHfFreq() :
\r
399 (SYSCON->FXCOMCLKSEL[id] == 2U) ?
\r
400 CLOCK_GetPllOutFreq() :
\r
401 (SYSCON->FXCOMCLKSEL[id] == 3U) ? CLOCK_GetI2SMClkFreq() :
\r
402 (SYSCON->FXCOMCLKSEL[id] == 4U) ? CLOCK_GetFreq(kCLOCK_Frg) : 0U;
\r
406 /*! brief Return Frequency of Adc Clock
\r
407 * return Frequency of Adc Clock.
\r
409 uint32_t CLOCK_GetAdcClkFreq(void)
\r
411 uint32_t freq = 0U;
\r
413 switch (SYSCON->ADCCLKSEL)
\r
416 freq = CLOCK_GetCoreSysClkFreq();
\r
419 freq = CLOCK_GetPllOutFreq();
\r
422 freq = CLOCK_GetFroHfFreq();
\r
431 return freq / ((SYSCON->ADCCLKDIV & 0xffU) + 1U);
\r
434 /*! brief Return Input frequency for the Fractional baud rate generator
\r
435 * return Input Frequency for FRG
\r
437 uint32_t CLOCK_GetFRGInputClock(void)
\r
439 return (SYSCON->FRGCLKSEL == 0U) ?
\r
440 CLOCK_GetCoreSysClkFreq() :
\r
441 (SYSCON->FRGCLKSEL == 1U) ?
\r
442 CLOCK_GetPllOutFreq() :
\r
443 (SYSCON->FRGCLKSEL == 2U) ? CLOCK_GetFro12MFreq() :
\r
444 (SYSCON->FRGCLKSEL == 3U) ? CLOCK_GetFroHfFreq() : 0U;
\r
447 /*! brief Set output of the Fractional baud rate generator
\r
448 * param freq : Desired output frequency
\r
449 * return Error Code 0 - fail 1 - success
\r
451 uint32_t CLOCK_SetFRGClock(uint32_t freq)
\r
453 uint32_t input = CLOCK_GetFRGInputClock();
\r
456 if ((freq > 48000000) || (freq > input) || (input / freq >= 2))
\r
458 /* FRG output frequency should be less than equal to 48MHz */
\r
463 mul = ((uint64_t)(input - freq) * 256) / ((uint64_t)freq);
\r
464 SYSCON->FRGCTRL = (mul << SYSCON_FRGCTRL_MULT_SHIFT) | SYSCON_FRGCTRL_DIV_MASK;
\r
469 /*! brief Return Frequency of selected clock
\r
470 * return Frequency of selected clock
\r
472 uint32_t CLOCK_GetFreq(clock_name_t clockName)
\r
477 case kCLOCK_CoreSysClk:
\r
478 freq = CLOCK_GetCoreSysClkFreq();
\r
480 case kCLOCK_BusClk:
\r
481 freq = CLOCK_GetCoreSysClkFreq() / ((SYSCON->AHBCLKDIV & 0xffU) + 1U);
\r
484 freq = CLOCK_GetFroHfFreq();
\r
486 case kCLOCK_Fro12M:
\r
487 freq = CLOCK_GetFro12MFreq();
\r
489 case kCLOCK_PllOut:
\r
490 freq = CLOCK_GetPllOutFreq();
\r
492 case kCLOCK_UsbClk:
\r
493 freq = (SYSCON->USBCLKSEL == 0U) ? CLOCK_GetFroHfFreq() :
\r
494 (SYSCON->USBCLKSEL == 1) ? CLOCK_GetPllOutFreq() : 0U;
\r
495 freq = freq / ((SYSCON->USBCLKDIV & 0xffU) + 1U);
\r
497 case kCLOCK_WdtOsc:
\r
498 freq = CLOCK_GetWdtOscFreq();
\r
501 freq = ((SYSCON->FRGCTRL & SYSCON_FRGCTRL_DIV_MASK) == SYSCON_FRGCTRL_DIV_MASK) ?
\r
502 ((uint64_t)CLOCK_GetFRGInputClock() * (SYSCON_FRGCTRL_DIV_MASK + 1)) /
\r
503 ((SYSCON_FRGCTRL_DIV_MASK + 1) +
\r
504 ((SYSCON->FRGCTRL & SYSCON_FRGCTRL_MULT_MASK) >> SYSCON_FRGCTRL_MULT_SHIFT)) :
\r
508 case kCLOCK_AsyncApbClk:
\r
509 freq = CLOCK_GetAsyncApbClkFreq();
\r
512 case kCLOCK_FlexI2S:
\r
513 freq = CLOCK_GetI2SMClkFreq();
\r
516 case kCLOCK_Flexcomm0:
\r
517 freq = CLOCK_GetFlexCommClkFreq(0U);
\r
519 case kCLOCK_Flexcomm1:
\r
520 freq = CLOCK_GetFlexCommClkFreq(1U);
\r
522 case kCLOCK_Flexcomm2:
\r
523 freq = CLOCK_GetFlexCommClkFreq(2U);
\r
525 case kCLOCK_Flexcomm3:
\r
526 freq = CLOCK_GetFlexCommClkFreq(3U);
\r
528 case kCLOCK_Flexcomm4:
\r
529 freq = CLOCK_GetFlexCommClkFreq(4U);
\r
531 case kCLOCK_Flexcomm5:
\r
532 freq = CLOCK_GetFlexCommClkFreq(5U);
\r
534 case kCLOCK_Flexcomm6:
\r
535 freq = CLOCK_GetFlexCommClkFreq(6U);
\r
537 case kCLOCK_Flexcomm7:
\r
538 freq = CLOCK_GetFlexCommClkFreq(7U);
\r
548 /* Set the FLASH wait states for the passed frequency */
\r
550 * brief Set the flash wait states for the input freuqency.
\r
551 * param iFreq : Input frequency
\r
554 void CLOCK_SetFLASHAccessCyclesForFreq(uint32_t iFreq)
\r
556 if (iFreq <= 12000000U)
\r
558 CLOCK_SetFLASHAccessCycles(kCLOCK_Flash1Cycle);
\r
560 else if (iFreq <= 24000000U)
\r
562 CLOCK_SetFLASHAccessCycles(kCLOCK_Flash2Cycle);
\r
564 else if (iFreq <= 48000000U)
\r
566 CLOCK_SetFLASHAccessCycles(kCLOCK_Flash3Cycle);
\r
568 else if (iFreq <= 72000000U)
\r
570 CLOCK_SetFLASHAccessCycles(kCLOCK_Flash4Cycle);
\r
572 else if (iFreq <= 84000000U)
\r
574 CLOCK_SetFLASHAccessCycles(kCLOCK_Flash5Cycle);
\r
578 CLOCK_SetFLASHAccessCycles(kCLOCK_Flash6Cycle);
\r
582 /* Find encoded NDEC value for raw N value, max N = NVALMAX */
\r
583 static uint32_t pllEncodeN(uint32_t N)
\r
604 for (i = N; i <= NVALMAX; i++)
\r
606 x = (((x ^ (x >> 2U) ^ (x >> 3U) ^ (x >> 4U)) & 1U) << 7U) | ((x >> 1U) & 0x7FU);
\r
611 return x & (PLL_NDEC_VAL_M >> PLL_NDEC_VAL_P);
\r
614 /* Find decoded N value for raw NDEC value */
\r
615 static uint32_t pllDecodeN(uint32_t NDEC)
\r
637 for (i = NVALMAX; ((i >= 3U) && (n == 0xFFFFFFFFU)); i--)
\r
639 x = (((x ^ (x >> 2U) ^ (x >> 3U) ^ (x >> 4U)) & 1U) << 7U) | ((x >> 1U) & 0x7FU);
\r
640 if ((x & (PLL_NDEC_VAL_M >> PLL_NDEC_VAL_P)) == NDEC)
\r
642 /* Decoded value of NDEC */
\r
652 /* Find encoded PDEC value for raw P value, max P = PVALMAX */
\r
653 static uint32_t pllEncodeP(uint32_t P)
\r
674 for (i = P; i <= PVALMAX; i++)
\r
676 x = (((x ^ (x >> 2U)) & 1U) << 4U) | ((x >> 1U) & 0xFU);
\r
681 return x & (PLL_PDEC_VAL_M >> PLL_PDEC_VAL_P);
\r
684 /* Find decoded P value for raw PDEC value */
\r
685 static uint32_t pllDecodeP(uint32_t PDEC)
\r
707 for (i = PVALMAX; ((i >= 3U) && (p == 0xFFFFFFFFU)); i--)
\r
709 x = (((x ^ (x >> 2U)) & 1U) << 4U) | ((x >> 1U) & 0xFU);
\r
710 if ((x & (PLL_PDEC_VAL_M >> PLL_PDEC_VAL_P)) == PDEC)
\r
712 /* Decoded value of PDEC */
\r
722 /* Find encoded MDEC value for raw M value, max M = MVALMAX */
\r
723 static uint32_t pllEncodeM(uint32_t M)
\r
744 for (i = M; i <= MVALMAX; i++)
\r
746 x = (((x ^ (x >> 1U)) & 1U) << 14U) | ((x >> 1U) & 0x3FFFU);
\r
751 return x & (PLL_SSCG0_MDEC_VAL_M >> PLL_SSCG0_MDEC_VAL_P);
\r
754 /* Find decoded M value for raw MDEC value */
\r
755 static uint32_t pllDecodeM(uint32_t MDEC)
\r
777 for (i = MVALMAX; ((i >= 3U) && (m == 0xFFFFFFFFU)); i--)
\r
779 x = (((x ^ (x >> 1U)) & 1) << 14U) | ((x >> 1U) & 0x3FFFU);
\r
780 if ((x & (PLL_SSCG0_MDEC_VAL_M >> PLL_SSCG0_MDEC_VAL_P)) == MDEC)
\r
782 /* Decoded value of MDEC */
\r
792 /* Find SELP, SELI, and SELR values for raw M value, max M = MVALMAX */
\r
793 static void pllFindSel(uint32_t M, bool bypassFBDIV2, uint32_t *pSelP, uint32_t *pSelI, uint32_t *pSelR)
\r
795 /* bandwidth: compute selP from Multiplier */
\r
798 *pSelP = (M >> 1U) + 1U;
\r
802 *pSelP = PVALMAX - 1U;
\r
805 /* bandwidth: compute selI from Multiplier */
\r
810 else if (M > 8192U)
\r
814 else if (M > 2048U)
\r
818 else if (M >= 501U)
\r
824 *pSelI = 4U * (1024U / (M + 9U));
\r
828 *pSelI = (M & 0x3CU) + 4U;
\r
831 if (*pSelI > ((0x3FUL << SYSCON_SYSPLLCTRL_SELI_SHIFT) >> SYSCON_SYSPLLCTRL_SELI_SHIFT))
\r
833 *pSelI = ((0x3FUL << SYSCON_SYSPLLCTRL_SELI_SHIFT) >> SYSCON_SYSPLLCTRL_SELI_SHIFT);
\r
839 /* Get predivider (N) from PLL NDEC setting */
\r
840 static uint32_t findPllPreDiv(uint32_t ctrlReg, uint32_t nDecReg)
\r
842 uint32_t preDiv = 1;
\r
844 /* Direct input is not used? */
\r
845 if ((ctrlReg & (1UL << SYSCON_SYSPLLCTRL_DIRECTI_SHIFT)) == 0U)
\r
847 /* Decode NDEC value to get (N) pre divider */
\r
848 preDiv = pllDecodeN(nDecReg & 0x3FFU);
\r
855 /* Adjusted by 1, directi is used to bypass */
\r
859 /* Get postdivider (P) from PLL PDEC setting */
\r
860 static uint32_t findPllPostDiv(uint32_t ctrlReg, uint32_t pDecReg)
\r
862 uint32_t postDiv = 1U;
\r
864 /* Direct input is not used? */
\r
865 if ((ctrlReg & SYSCON_SYSPLLCTRL_DIRECTO_MASK) == 0U)
\r
867 /* Decode PDEC value to get (P) post divider */
\r
868 postDiv = 2U * pllDecodeP(pDecReg & 0x7FU);
\r
875 /* Adjusted by 1, directo is used to bypass */
\r
879 /* Get multiplier (M) from PLL MDEC and BYPASS_FBDIV2 settings */
\r
880 static uint32_t findPllMMult(uint32_t ctrlReg, uint32_t mDecReg)
\r
882 uint32_t mMult = 1U;
\r
884 /* Decode MDEC value to get (M) multiplier */
\r
885 mMult = pllDecodeM(mDecReg & 0x1FFFFU);
\r
887 /* Extra multiply by 2 needed? */
\r
888 if ((ctrlReg & (SYSCON_SYSPLLCTRL_BYPASSCCODIV2_MASK)) == 0U)
\r
890 mMult = mMult << 1U;
\r
901 static uint32_t FindGreatestCommonDivisor(uint32_t m, uint32_t n)
\r
916 * Set PLL output based on desired output rate.
\r
917 * In this function, the it calculates the PLL setting for output frequency from input clock
\r
918 * frequency. The calculation would cost a few time. So it is not recommaned to use it frequently.
\r
919 * the "pllctrl", "pllndec", "pllpdec", "pllmdec" would updated in this function.
\r
921 static pll_error_t CLOCK_GetPllConfigInternal(
\r
922 uint32_t finHz, uint32_t foutHz, pll_setup_t *pSetup, bool useFeedbackDiv2, bool useSS)
\r
924 uint32_t nDivOutHz, fccoHz, multFccoDiv;
\r
925 uint32_t pllPreDivider, pllMultiplier, pllBypassFBDIV2, pllPostDivider;
\r
926 uint32_t pllDirectInput, pllDirectOutput;
\r
927 uint32_t pllSelP, pllSelI, pllSelR, bandsel, uplimoff;
\r
929 /* Baseline parameters (no input or output dividers) */
\r
930 pllPreDivider = 1U; /* 1 implies pre-divider will be disabled */
\r
931 pllPostDivider = 0U; /* 0 implies post-divider will be disabled */
\r
932 pllDirectOutput = 1U;
\r
933 if (useFeedbackDiv2)
\r
935 /* Using feedback divider for M, so disable bypass */
\r
936 pllBypassFBDIV2 = 0U;
\r
940 pllBypassFBDIV2 = 1U;
\r
942 multFccoDiv = (2U - pllBypassFBDIV2);
\r
944 /* Verify output rate parameter */
\r
945 if (foutHz > PLL_MAX_CCO_FREQ_MHZ)
\r
947 /* Maximum PLL output with post divider=1 cannot go above this frequency */
\r
948 return kStatus_PLL_OutputTooHigh;
\r
950 if (foutHz < (PLL_MIN_CCO_FREQ_MHZ / (PVALMAX << 1U)))
\r
952 /* Minmum PLL output with maximum post divider cannot go below this frequency */
\r
953 return kStatus_PLL_OutputTooLow;
\r
956 /* If using SS mode, input clock needs to be between 2MHz and 4MHz */
\r
959 /* Verify input rate parameter */
\r
960 if (finHz < PLL_MIN_IN_SSMODE)
\r
962 /* Input clock into the PLL cannot be lower than this */
\r
963 return kStatus_PLL_InputTooLow;
\r
965 /* PLL input in SS mode must be under 4MHz */
\r
966 pllPreDivider = finHz / ((PLL_MIN_IN_SSMODE + PLL_MAX_IN_SSMODE) / 2);
\r
967 if (pllPreDivider > NVALMAX)
\r
969 return kStatus_PLL_InputTooHigh;
\r
974 /* Verify input rate parameter */
\r
975 if (finHz < PLL_LOWER_IN_LIMIT)
\r
977 /* Input clock into the PLL cannot be lower than this */
\r
978 return kStatus_PLL_InputTooLow;
\r
982 /* Find the optimal CCO frequency for the output and input that
\r
983 will keep it inside the PLL CCO range. This may require
\r
984 tweaking the post-divider for the PLL. */
\r
986 while (fccoHz < PLL_MIN_CCO_FREQ_MHZ)
\r
988 /* CCO output is less than minimum CCO range, so the CCO output
\r
989 needs to be bumped up and the post-divider is used to bring
\r
990 the PLL output back down. */
\r
992 if (pllPostDivider > PVALMAX)
\r
994 return kStatus_PLL_OutsideIntLimit;
\r
997 /* Target CCO goes up, PLL output goes down */
\r
998 fccoHz = foutHz * (pllPostDivider * 2U);
\r
999 pllDirectOutput = 0U;
\r
1002 /* Determine if a pre-divider is needed to get the best frequency */
\r
1003 if ((finHz > PLL_LOWER_IN_LIMIT) && (fccoHz >= finHz) && (useSS == false))
\r
1005 uint32_t a = FindGreatestCommonDivisor(fccoHz, (multFccoDiv * finHz));
\r
1009 a = (multFccoDiv * finHz) / a;
\r
1010 if ((a != 0U) && (a < PLL_MAX_N_DIV))
\r
1012 pllPreDivider = a;
\r
1017 /* Bypass pre-divider hardware if pre-divider is 1 */
\r
1018 if (pllPreDivider > 1U)
\r
1020 pllDirectInput = 0U;
\r
1024 pllDirectInput = 1U;
\r
1027 /* Determine PLL multipler */
\r
1028 nDivOutHz = (finHz / pllPreDivider);
\r
1029 pllMultiplier = (fccoHz / nDivOutHz) / multFccoDiv;
\r
1031 /* Find optimal values for filter */
\r
1032 if (useSS == false)
\r
1034 /* Will bumping up M by 1 get us closer to the desired CCO frequency? */
\r
1035 if ((nDivOutHz * ((multFccoDiv * pllMultiplier * 2U) + 1U)) < (fccoHz * 2U))
\r
1040 /* Setup filtering */
\r
1041 pllFindSel(pllMultiplier, pllBypassFBDIV2, &pllSelP, &pllSelI, &pllSelR);
\r
1045 /* Get encoded value for M (mult) and use manual filter, disable SS mode */
\r
1046 pSetup->syspllssctrl[0] =
\r
1047 (PLL_SSCG0_MDEC_VAL_SET(pllEncodeM(pllMultiplier)) | (1U << SYSCON_SYSPLLSSCTRL0_SEL_EXT_SHIFT));
\r
1049 /* Power down SSC, not used */
\r
1050 pSetup->syspllssctrl[1] = (1U << SYSCON_SYSPLLSSCTRL1_PD_SHIFT);
\r
1056 /* Filtering will be handled by SSC */
\r
1057 pllSelR = pllSelI = pllSelP = 0U;
\r
1061 /* The PLL multiplier will get very close and slightly under the
\r
1062 desired target frequency. A small fractional component can be
\r
1063 added to fine tune the frequency upwards to the target. */
\r
1064 fc = ((uint64_t)(fccoHz % (multFccoDiv * nDivOutHz)) << 11U) / (multFccoDiv * nDivOutHz);
\r
1066 /* MDEC set by SSC */
\r
1067 pSetup->syspllssctrl[0U] = 0U;
\r
1069 /* Set multiplier */
\r
1070 pSetup->syspllssctrl[1] = PLL_SSCG1_MD_INT_SET(pllMultiplier) | PLL_SSCG1_MD_FRACT_SET((uint32_t)fc);
\r
1073 /* Get encoded values for N (prediv) and P (postdiv) */
\r
1074 pSetup->syspllndec = PLL_NDEC_VAL_SET(pllEncodeN(pllPreDivider));
\r
1075 pSetup->syspllpdec = PLL_PDEC_VAL_SET(pllEncodeP(pllPostDivider));
\r
1078 pSetup->syspllctrl = (pllSelR << SYSCON_SYSPLLCTRL_SELR_SHIFT) | /* Filter coefficient */
\r
1079 (pllSelI << SYSCON_SYSPLLCTRL_SELI_SHIFT) | /* Filter coefficient */
\r
1080 (pllSelP << SYSCON_SYSPLLCTRL_SELP_SHIFT) | /* Filter coefficient */
\r
1081 (0 << SYSCON_SYSPLLCTRL_BYPASS_SHIFT) | /* PLL bypass mode disabled */
\r
1082 (pllBypassFBDIV2 << SYSCON_SYSPLLCTRL_BYPASSCCODIV2_SHIFT) | /* Extra M / 2 divider? */
\r
1083 (uplimoff << SYSCON_SYSPLLCTRL_UPLIMOFF_SHIFT) | /* SS/fractional mode disabled */
\r
1084 (bandsel << SYSCON_SYSPLLCTRL_BANDSEL_SHIFT) | /* Manual bandwidth selection enabled */
\r
1085 (pllDirectInput << SYSCON_SYSPLLCTRL_DIRECTI_SHIFT) | /* Bypass pre-divider? */
\r
1086 (pllDirectOutput << SYSCON_SYSPLLCTRL_DIRECTO_SHIFT); /* Bypass post-divider? */
\r
1088 return kStatus_PLL_Success;
\r
1091 #if (defined(CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT) && CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT)
\r
1092 /* Alloct the static buffer for cache. */
\r
1093 pll_setup_t gPllSetupCacheStruct[CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT];
\r
1094 uint32_t gFinHzCache[CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT] = {0};
\r
1095 uint32_t gFoutHzCache[CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT] = {0};
\r
1096 bool gUseFeedbackDiv2Cache[CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT] = {false};
\r
1097 bool gUseSSCache[CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT] = {false};
\r
1098 uint32_t gPllSetupCacheIdx = 0U;
\r
1099 #endif /* CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT */
\r
1102 * Calculate the PLL setting values from input clock freq to output freq.
\r
1104 static pll_error_t CLOCK_GetPllConfig(
\r
1105 uint32_t finHz, uint32_t foutHz, pll_setup_t *pSetup, bool useFeedbackDiv2, bool useSS)
\r
1107 pll_error_t retErr;
\r
1108 #if (defined(CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT) && CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT)
\r
1111 for (i = 0U; i < CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT; i++)
\r
1113 if ((finHz == gFinHzCache[i]) && (foutHz == gFoutHzCache[i]) && (useFeedbackDiv2 == gUseFeedbackDiv2Cache[i]) &&
\r
1114 (useSS == gUseSSCache[i]))
\r
1116 /* Hit the target in cache buffer. */
\r
1117 pSetup->syspllctrl = gPllSetupCacheStruct[i].syspllctrl;
\r
1118 pSetup->syspllndec = gPllSetupCacheStruct[i].syspllndec;
\r
1119 pSetup->syspllpdec = gPllSetupCacheStruct[i].syspllpdec;
\r
1120 pSetup->syspllssctrl[0] = gPllSetupCacheStruct[i].syspllssctrl[0];
\r
1121 pSetup->syspllssctrl[1] = gPllSetupCacheStruct[i].syspllssctrl[1];
\r
1122 retErr = kStatus_PLL_Success;
\r
1127 if (i < CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT)
\r
1131 #endif /* CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT */
\r
1133 retErr = CLOCK_GetPllConfigInternal(finHz, foutHz, pSetup, useFeedbackDiv2, useSS);
\r
1135 #if (defined(CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT) && CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT)
\r
1136 /* Cache the most recent calulation result into buffer. */
\r
1137 gFinHzCache[gPllSetupCacheIdx] = finHz;
\r
1138 gFoutHzCache[gPllSetupCacheIdx] = foutHz;
\r
1139 gUseFeedbackDiv2Cache[gPllSetupCacheIdx] = useFeedbackDiv2;
\r
1140 gUseSSCache[gPllSetupCacheIdx] = useSS;
\r
1142 gPllSetupCacheStruct[gPllSetupCacheIdx].syspllctrl = pSetup->syspllctrl;
\r
1143 gPllSetupCacheStruct[gPllSetupCacheIdx].syspllndec = pSetup->syspllndec;
\r
1144 gPllSetupCacheStruct[gPllSetupCacheIdx].syspllpdec = pSetup->syspllpdec;
\r
1145 gPllSetupCacheStruct[gPllSetupCacheIdx].syspllssctrl[0] = pSetup->syspllssctrl[0];
\r
1146 gPllSetupCacheStruct[gPllSetupCacheIdx].syspllssctrl[1] = pSetup->syspllssctrl[1];
\r
1147 /* Update the index for next available buffer. */
\r
1148 gPllSetupCacheIdx = (gPllSetupCacheIdx + 1U) % CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT;
\r
1149 #endif /* CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT */
\r
1154 /* Update local PLL rate variable */
\r
1155 static void CLOCK_GetSystemPLLOutFromSetupUpdate(pll_setup_t *pSetup)
\r
1157 s_Pll_Freq = CLOCK_GetSystemPLLOutFromSetup(pSetup);
\r
1160 /* Return System PLL input clock rate */
\r
1161 /*! brief Return System PLL input clock rate
\r
1162 * return System PLL input clock rate
\r
1164 uint32_t CLOCK_GetSystemPLLInClockRate(void)
\r
1166 uint32_t clkRate = 0U;
\r
1168 switch ((SYSCON->SYSPLLCLKSEL & SYSCON_SYSPLLCLKSEL_SEL_MASK))
\r
1171 clkRate = CLK_FRO_12MHZ;
\r
1175 clkRate = CLOCK_GetExtClkFreq();
\r
1179 clkRate = CLOCK_GetWdtOscFreq();
\r
1183 clkRate = CLOCK_GetOsc32KFreq();
\r
1194 /* Return System PLL output clock rate from setup structure */
\r
1195 /*! brief Return System PLL output clock rate from setup structure
\r
1196 * param pSetup : Pointer to a PLL setup structure
\r
1197 * return System PLL output clock rate calculated from the setup structure
\r
1199 uint32_t CLOCK_GetSystemPLLOutFromSetup(pll_setup_t *pSetup)
\r
1201 uint32_t prediv, postdiv, mMult, inPllRate;
\r
1202 uint64_t workRate;
\r
1204 /* Get the input clock frequency of PLL. */
\r
1205 inPllRate = CLOCK_GetSystemPLLInClockRate();
\r
1208 * If the PLL is bypassed, PLL would not be used and the output of PLL module would just be the input clock.
\r
1210 if ((pSetup->syspllctrl & (SYSCON_SYSPLLCTRL_BYPASS_MASK)) == 0U)
\r
1212 /* PLL is not in bypass mode, get pre-divider, and M divider, post-divider. */
\r
1215 * Pre-divider is only available when the DIRECTI is disabled.
\r
1217 if (0U == (pSetup->syspllctrl & SYSCON_SYSPLLCTRL_DIRECTI_MASK))
\r
1219 prediv = findPllPreDiv(pSetup->syspllctrl, pSetup->syspllndec);
\r
1223 prediv = 1U; /* The pre-divider is bypassed. */
\r
1225 /* Adjust input clock */
\r
1226 inPllRate = inPllRate / prediv;
\r
1230 * If using the SS, use the multiplier.
\r
1232 if (pSetup->syspllssctrl[1] & (SYSCON_SYSPLLSSCTRL1_PD_MASK))
\r
1234 /* MDEC used for rate */
\r
1235 mMult = findPllMMult(pSetup->syspllctrl, pSetup->syspllssctrl[0]);
\r
1236 workRate = (uint64_t)inPllRate * (uint64_t)mMult;
\r
1242 /* SS multipler used for rate */
\r
1243 mMult = (pSetup->syspllssctrl[1] & PLL_SSCG1_MD_INT_M) >> PLL_SSCG1_MD_INT_P;
\r
1244 workRate = (uint64_t)inPllRate * (uint64_t)mMult;
\r
1246 /* Adjust by fractional */
\r
1247 fract = (uint64_t)(pSetup->syspllssctrl[1] & PLL_SSCG1_MD_FRACT_M) >> PLL_SSCG1_MD_FRACT_P;
\r
1248 workRate = workRate + ((inPllRate * fract) / 0x800U);
\r
1253 * Post-divider is only available when the DIRECTO is disabled.
\r
1255 if (0U == (pSetup->syspllctrl & SYSCON_SYSPLLCTRL_DIRECTO_MASK))
\r
1257 postdiv = findPllPostDiv(pSetup->syspllctrl, pSetup->syspllpdec);
\r
1261 postdiv = 1U; /* The post-divider is bypassed. */
\r
1263 workRate = workRate / ((uint64_t)postdiv);
\r
1267 /* In bypass mode */
\r
1268 workRate = (uint64_t)inPllRate;
\r
1271 return (uint32_t)workRate;
\r
1274 /* Set the current PLL Rate */
\r
1275 /*! brief Store the current PLL rate
\r
1276 * param rate: Current rate of the PLL
\r
1279 void CLOCK_SetStoredPLLClockRate(uint32_t rate)
\r
1281 s_Pll_Freq = rate;
\r
1284 /* Return System PLL output clock rate */
\r
1285 /*! brief Return System PLL output clock rate
\r
1286 * param recompute : Forces a PLL rate recomputation if true
\r
1287 * return System PLL output clock rate
\r
1288 * note The PLL rate is cached in the driver in a variable as
\r
1289 * the rate computation function can take some time to perform. It
\r
1290 * is recommended to use 'false' with the 'recompute' parameter.
\r
1292 uint32_t CLOCK_GetSystemPLLOutClockRate(bool recompute)
\r
1294 pll_setup_t Setup;
\r
1297 if ((recompute) || (s_Pll_Freq == 0U))
\r
1299 Setup.syspllctrl = SYSCON->SYSPLLCTRL;
\r
1300 Setup.syspllndec = SYSCON->SYSPLLNDEC;
\r
1301 Setup.syspllpdec = SYSCON->SYSPLLPDEC;
\r
1302 Setup.syspllssctrl[0] = SYSCON->SYSPLLSSCTRL0;
\r
1303 Setup.syspllssctrl[1] = SYSCON->SYSPLLSSCTRL1;
\r
1305 CLOCK_GetSystemPLLOutFromSetupUpdate(&Setup);
\r
1308 rate = s_Pll_Freq;
\r
1313 /* Set PLL output based on the passed PLL setup data */
\r
1314 /*! brief Set PLL output based on the passed PLL setup data
\r
1315 * param pControl : Pointer to populated PLL control structure to generate setup with
\r
1316 * param pSetup : Pointer to PLL setup structure to be filled
\r
1317 * return PLL_ERROR_SUCCESS on success, or PLL setup error code
\r
1318 * note Actual frequency for setup may vary from the desired frequency based on the
\r
1319 * accuracy of input clocks, rounding, non-fractional PLL mode, etc.
\r
1321 pll_error_t CLOCK_SetupPLLData(pll_config_t *pControl, pll_setup_t *pSetup)
\r
1324 bool useSS = (bool)((pControl->flags & PLL_CONFIGFLAG_FORCENOFRACT) == 0U);
\r
1327 pll_error_t pllError;
\r
1329 /* Determine input rate for the PLL */
\r
1330 if ((pControl->flags & PLL_CONFIGFLAG_USEINRATE) != 0U)
\r
1332 inRate = pControl->inputRate;
\r
1336 inRate = CLOCK_GetSystemPLLInClockRate();
\r
1339 if ((pSetup->flags & PLL_SETUPFLAG_USEFEEDBACKDIV2) != 0U)
\r
1345 useFbDiv2 = false;
\r
1348 /* PLL flag options */
\r
1349 pllError = CLOCK_GetPllConfig(inRate, pControl->desiredRate, pSetup, useFbDiv2, useSS);
\r
1350 if ((useSS) && (pllError == kStatus_PLL_Success))
\r
1352 /* If using SS mode, then some tweaks are made to the generated setup */
\r
1353 pSetup->syspllssctrl[1] |= (uint32_t)pControl->ss_mf | (uint32_t)pControl->ss_mr | (uint32_t)pControl->ss_mc;
\r
1354 if (pControl->mfDither)
\r
1356 pSetup->syspllssctrl[1] |= (1U << SYSCON_SYSPLLSSCTRL1_DITHER_SHIFT);
\r
1363 /* Set PLL output from PLL setup structure */
\r
1364 /*! brief Set PLL output from PLL setup structure (precise frequency)
\r
1365 * param pSetup : Pointer to populated PLL setup structure
\r
1366 * param flagcfg : Flag configuration for PLL config structure
\r
1367 * return PLL_ERROR_SUCCESS on success, or PLL setup error code
\r
1368 * note This function will power off the PLL, setup the PLL with the
\r
1369 * new setup data, and then optionally powerup the PLL, wait for PLL lock,
\r
1370 * and adjust system voltages to the new PLL rate. The function will not
\r
1371 * alter any source clocks (ie, main systen clock) that may use the PLL,
\r
1372 * so these should be setup prior to and after exiting the function.
\r
1374 pll_error_t CLOCK_SetupSystemPLLPrec(pll_setup_t *pSetup, uint32_t flagcfg)
\r
1376 /* Power off PLL during setup changes */
\r
1377 POWER_EnablePD(kPDRUNCFG_PD_SYS_PLL0);
\r
1379 pSetup->flags = flagcfg;
\r
1381 /* Write PLL setup data */
\r
1382 SYSCON->SYSPLLCTRL = pSetup->syspllctrl;
\r
1383 SYSCON->SYSPLLNDEC = pSetup->syspllndec;
\r
1384 SYSCON->SYSPLLNDEC = pSetup->syspllndec | (1U << SYSCON_SYSPLLNDEC_NREQ_SHIFT); /* latch */
\r
1385 SYSCON->SYSPLLPDEC = pSetup->syspllpdec;
\r
1386 SYSCON->SYSPLLPDEC = pSetup->syspllpdec | (1U << SYSCON_SYSPLLPDEC_PREQ_SHIFT); /* latch */
\r
1387 SYSCON->SYSPLLSSCTRL0 = pSetup->syspllssctrl[0];
\r
1388 SYSCON->SYSPLLSSCTRL0 = pSetup->syspllssctrl[0] | (1U << SYSCON_SYSPLLSSCTRL0_MREQ_SHIFT); /* latch */
\r
1389 SYSCON->SYSPLLSSCTRL1 = pSetup->syspllssctrl[1];
\r
1390 SYSCON->SYSPLLSSCTRL1 = pSetup->syspllssctrl[1] | (1U << SYSCON_SYSPLLSSCTRL1_MDREQ_SHIFT); /* latch */
\r
1392 /* Flags for lock or power on */
\r
1393 if ((pSetup->flags & (PLL_SETUPFLAG_POWERUP | PLL_SETUPFLAG_WAITLOCK)) != 0U)
\r
1395 /* If turning the PLL back on, perform the following sequence to accelerate PLL lock */
\r
1396 volatile uint32_t delayX;
\r
1397 uint32_t maxCCO = (1U << 18U) | 0x5dd2U; /* CCO = 1.6Ghz + MDEC enabled*/
\r
1398 uint32_t curSSCTRL = SYSCON->SYSPLLSSCTRL0 & ~(1U << 17U);
\r
1400 /* Initialize and power up PLL */
\r
1401 SYSCON->SYSPLLSSCTRL0 = maxCCO;
\r
1402 POWER_DisablePD(kPDRUNCFG_PD_SYS_PLL0);
\r
1404 /* Set mreq to activate */
\r
1405 SYSCON->SYSPLLSSCTRL0 = maxCCO | (1U << 17U);
\r
1407 /* Delay for 72 uSec @ 12Mhz */
\r
1408 for (delayX = 0U; delayX < 172U; ++delayX)
\r
1412 /* clear mreq to prepare for restoring mreq */
\r
1413 SYSCON->SYSPLLSSCTRL0 = curSSCTRL;
\r
1415 /* set original value back and activate */
\r
1416 SYSCON->SYSPLLSSCTRL0 = curSSCTRL | (1U << 17U);
\r
1418 /* Enable peripheral states by setting low */
\r
1419 POWER_DisablePD(kPDRUNCFG_PD_SYS_PLL0);
\r
1421 if ((pSetup->flags & PLL_SETUPFLAG_WAITLOCK) != 0U)
\r
1423 while (CLOCK_IsSystemPLLLocked() == false)
\r
1428 /* Update current programmed PLL rate var */
\r
1429 CLOCK_GetSystemPLLOutFromSetupUpdate(pSetup);
\r
1431 /* System voltage adjustment, occurs prior to setting main system clock */
\r
1432 if ((pSetup->flags & PLL_SETUPFLAG_ADGVOLT) != 0U)
\r
1434 POWER_SetVoltageForFreq(s_Pll_Freq);
\r
1437 return kStatus_PLL_Success;
\r
1440 /* Setup PLL Frequency from pre-calculated value */
\r
1442 * brief Set PLL output from PLL setup structure (precise frequency)
\r
1443 * param pSetup : Pointer to populated PLL setup structure
\r
1444 * return kStatus_PLL_Success on success, or PLL setup error code
\r
1445 * note This function will power off the PLL, setup the PLL with the
\r
1446 * new setup data, and then optionally powerup the PLL, wait for PLL lock,
\r
1447 * and adjust system voltages to the new PLL rate. The function will not
\r
1448 * alter any source clocks (ie, main systen clock) that may use the PLL,
\r
1449 * so these should be setup prior to and after exiting the function.
\r
1451 pll_error_t CLOCK_SetPLLFreq(const pll_setup_t *pSetup)
\r
1453 /* Power off PLL during setup changes */
\r
1454 POWER_EnablePD(kPDRUNCFG_PD_SYS_PLL0);
\r
1456 /* Write PLL setup data */
\r
1457 SYSCON->SYSPLLCTRL = pSetup->syspllctrl;
\r
1458 SYSCON->SYSPLLNDEC = pSetup->syspllndec;
\r
1459 SYSCON->SYSPLLNDEC = pSetup->syspllndec | (1U << SYSCON_SYSPLLNDEC_NREQ_SHIFT); /* latch */
\r
1460 SYSCON->SYSPLLPDEC = pSetup->syspllpdec;
\r
1461 SYSCON->SYSPLLPDEC = pSetup->syspllpdec | (1U << SYSCON_SYSPLLPDEC_PREQ_SHIFT); /* latch */
\r
1462 SYSCON->SYSPLLSSCTRL0 = pSetup->syspllssctrl[0];
\r
1463 SYSCON->SYSPLLSSCTRL0 = pSetup->syspllssctrl[0] | (1U << SYSCON_SYSPLLSSCTRL0_MREQ_SHIFT); /* latch */
\r
1464 SYSCON->SYSPLLSSCTRL1 = pSetup->syspllssctrl[1];
\r
1465 SYSCON->SYSPLLSSCTRL1 = pSetup->syspllssctrl[1] | (1U << SYSCON_SYSPLLSSCTRL1_MDREQ_SHIFT); /* latch */
\r
1467 /* Flags for lock or power on */
\r
1468 if ((pSetup->flags & (PLL_SETUPFLAG_POWERUP | PLL_SETUPFLAG_WAITLOCK)) != 0)
\r
1470 /* If turning the PLL back on, perform the following sequence to accelerate PLL lock */
\r
1471 volatile uint32_t delayX;
\r
1472 uint32_t maxCCO = (1U << 18U) | 0x5dd2U; /* CCO = 1.6Ghz + MDEC enabled*/
\r
1473 uint32_t curSSCTRL = SYSCON->SYSPLLSSCTRL0 & ~(1U << 17U);
\r
1475 /* Initialize and power up PLL */
\r
1476 SYSCON->SYSPLLSSCTRL0 = maxCCO;
\r
1477 POWER_DisablePD(kPDRUNCFG_PD_SYS_PLL0);
\r
1479 /* Set mreq to activate */
\r
1480 SYSCON->SYSPLLSSCTRL0 = maxCCO | (1U << 17U);
\r
1482 /* Delay for 72 uSec @ 12Mhz */
\r
1483 for (delayX = 0U; delayX < 172U; ++delayX)
\r
1487 /* clear mreq to prepare for restoring mreq */
\r
1488 SYSCON->SYSPLLSSCTRL0 = curSSCTRL;
\r
1490 /* set original value back and activate */
\r
1491 SYSCON->SYSPLLSSCTRL0 = curSSCTRL | (1U << 17U);
\r
1493 /* Enable peripheral states by setting low */
\r
1494 POWER_DisablePD(kPDRUNCFG_PD_SYS_PLL0);
\r
1496 if ((pSetup->flags & PLL_SETUPFLAG_WAITLOCK) != 0U)
\r
1498 while (CLOCK_IsSystemPLLLocked() == false)
\r
1503 /* Update current programmed PLL rate var */
\r
1504 s_Pll_Freq = pSetup->pllRate;
\r
1506 return kStatus_PLL_Success;
\r
1509 /* Set System PLL clock based on the input frequency and multiplier */
\r
1510 /*! brief Set PLL output based on the multiplier and input frequency
\r
1511 * param multiply_by : multiplier
\r
1512 * param input_freq : Clock input frequency of the PLL
\r
1514 * note Unlike the Chip_Clock_SetupSystemPLLPrec() function, this
\r
1515 * function does not disable or enable PLL power, wait for PLL lock,
\r
1516 * or adjust system voltages. These must be done in the application.
\r
1517 * The function will not alter any source clocks (ie, main systen clock)
\r
1518 * that may use the PLL, so these should be setup prior to and after
\r
1519 * exiting the function.
\r
1521 void CLOCK_SetupSystemPLLMult(uint32_t multiply_by, uint32_t input_freq)
\r
1523 uint32_t cco_freq = input_freq * multiply_by;
\r
1524 uint32_t pdec = 1U;
\r
1528 uint32_t mdec, ndec;
\r
1530 uint32_t directo = SYSCON_SYSPLLCTRL_DIRECTO(1);
\r
1532 while (cco_freq < 75000000U)
\r
1534 multiply_by <<= 1U; /* double value in each iteration */
\r
1535 pdec <<= 1U; /* correspondingly double pdec to cancel effect of double msel */
\r
1536 cco_freq = input_freq * multiply_by;
\r
1539 if (multiply_by < 60U)
\r
1541 seli = (multiply_by & 0x3cU) + 4U;
\r
1542 selp = (multiply_by >> 1U) + 1U;
\r
1547 if (multiply_by > 16384U)
\r
1551 else if (multiply_by > 8192U)
\r
1555 else if (multiply_by > 2048U)
\r
1559 else if (multiply_by >= 501U)
\r
1565 seli = 4U * (1024U / (multiply_by + 9U));
\r
1571 directo = 0U; /* use post divider */
\r
1572 pdec = pdec / 2U; /* Account for minus 1 encoding */
\r
1573 /* Translate P value */
\r
1577 pdec = 0x62U; /* 1 * 2 */
\r
1580 pdec = 0x42U; /* 2 * 2 */
\r
1583 pdec = 0x02U; /* 4 * 2 */
\r
1586 pdec = 0x0bU; /* 8 * 2 */
\r
1589 pdec = 0x11U; /* 16 * 2 */
\r
1592 pdec = 0x08U; /* 32 * 2 */
\r
1600 mdec = PLL_SSCG0_MDEC_VAL_SET(pllEncodeM(multiply_by));
\r
1601 ndec = 0x302U; /* pre divide by 1 (hardcoded) */
\r
1603 SYSCON->SYSPLLCTRL = SYSCON_SYSPLLCTRL_BANDSEL(1) | directo | SYSCON_SYSPLLCTRL_BYPASSCCODIV2(1) |
\r
1604 (selr << SYSCON_SYSPLLCTRL_SELR_SHIFT) | (seli << SYSCON_SYSPLLCTRL_SELI_SHIFT) |
\r
1605 (selp << SYSCON_SYSPLLCTRL_SELP_SHIFT);
\r
1606 SYSCON->SYSPLLPDEC = pdec | (1U << 7U); /* set Pdec value and assert preq */
\r
1607 SYSCON->SYSPLLNDEC = ndec | (1U << 10U); /* set Pdec value and assert preq */
\r
1608 SYSCON->SYSPLLSSCTRL0 =
\r
1609 (1U << 18U) | (1U << 17U) | mdec; /* select non sscg MDEC value, assert mreq and select mdec value */
\r
1611 bool CLOCK_EnableUsbfs0Clock(clock_usb_src_t src, uint32_t freq)
\r
1615 CLOCK_DisableClock(kCLOCK_Usbd0);
\r
1617 if (kCLOCK_UsbSrcFro == src)
\r
1622 CLOCK_SetClkDiv(kCLOCK_DivUsbClk, 2, false); /*!< Div by 2 to get 48MHz, no divider reset */
\r
1625 CLOCK_SetClkDiv(kCLOCK_DivUsbClk, 1, false); /*!< Div by 1 to get 48MHz, no divider reset */
\r
1631 /* Turn ON FRO HF and let it adjust TRIM value based on USB SOF */
\r
1632 SYSCON->FROCTRL = (SYSCON->FROCTRL & ~((0x01U << 15U) | (0xFU << 26U))) | SYSCON_FROCTRL_HSPDCLK_MASK |
\r
1633 SYSCON_FROCTRL_USBCLKADJ_MASK;
\r
1634 /* select FRO 96 or 48 MHz */
\r
1635 CLOCK_AttachClk(kFRO_HF_to_USB_CLK);
\r
1639 /*TODO , we only implement FRO as usb clock source*/
\r
1643 CLOCK_EnableClock(kCLOCK_Usbd0);
\r
1649 * brief Delay at least for several microseconds.
\r
1650 * Please note that, this API will calculate the microsecond period with the maximum devices
\r
1651 * supported CPU frequency, so this API will only delay for at least the given microseconds, if precise
\r
1652 * delay count was needed, please implement a new timer count to achieve this function.
\r
1654 * param delay_us Delay time in unit of microsecond.
\r
1656 __attribute__((weak)) void SDK_DelayAtLeastUs(uint32_t delay_us)
\r
1658 assert(0U != delay_us);
\r
1660 uint32_t count = (uint32_t)USEC_TO_COUNT(delay_us, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
\r
1663 * Calculate the real delay count depend on the excute instructions cycles,
\r
1664 * users can change the divider value to adapt to the real IDE optimise level.
\r
1666 count = (count / 4U);
\r
1668 for (; count > 0UL; count--)
\r