diff options
Diffstat (limited to 'lib/chibios-contrib/ext/mcux-sdk/devices/LPC54113/drivers/fsl_clock.c')
-rw-r--r-- | lib/chibios-contrib/ext/mcux-sdk/devices/LPC54113/drivers/fsl_clock.c | 1777 |
1 files changed, 1777 insertions, 0 deletions
diff --git a/lib/chibios-contrib/ext/mcux-sdk/devices/LPC54113/drivers/fsl_clock.c b/lib/chibios-contrib/ext/mcux-sdk/devices/LPC54113/drivers/fsl_clock.c new file mode 100644 index 000000000..65b5cd6f1 --- /dev/null +++ b/lib/chibios-contrib/ext/mcux-sdk/devices/LPC54113/drivers/fsl_clock.c | |||
@@ -0,0 +1,1777 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2016, Freescale Semiconductor, Inc. | ||
3 | * Copyright 2016 - 2019 , NXP | ||
4 | * All rights reserved. | ||
5 | * | ||
6 | * | ||
7 | * SPDX-License-Identifier: BSD-3-Clause | ||
8 | */ | ||
9 | |||
10 | #include "fsl_clock.h" | ||
11 | #include "fsl_power.h" | ||
12 | /******************************************************************************* | ||
13 | * Definitions | ||
14 | ******************************************************************************/ | ||
15 | /* Component ID definition, used by tools. */ | ||
16 | #ifndef FSL_COMPONENT_ID | ||
17 | #define FSL_COMPONENT_ID "platform.drivers.clock" | ||
18 | #endif | ||
19 | #define NVALMAX (0x100U) | ||
20 | #define PVALMAX (0x20U) | ||
21 | #define MVALMAX (0x8000U) | ||
22 | |||
23 | #define PLL_MAX_N_DIV 0x100U | ||
24 | |||
25 | #define INDEX_SECTOR_TRIM48 ((uint32_t *)0x01000444U) | ||
26 | #define INDEX_SECTOR_TRIM96 ((uint32_t *)0x01000430U) | ||
27 | /*-------------------------------------------------------------------------- | ||
28 | !!! If required these #defines can be moved to chip library file | ||
29 | ----------------------------------------------------------------------------*/ | ||
30 | |||
31 | #define PLL_SSCG0_MDEC_VAL_P (0U) /* MDEC is in bits 16 downto 0 */ | ||
32 | #define PLL_SSCG0_MDEC_VAL_M (0x1FFFFUL << PLL_SSCG0_MDEC_VAL_P) /* NDEC is in bits 9 downto 0 */ | ||
33 | #define PLL_NDEC_VAL_P (0U) /* NDEC is in bits 9:0 */ | ||
34 | #define PLL_NDEC_VAL_M (0x3FFUL << PLL_NDEC_VAL_P) | ||
35 | #define PLL_PDEC_VAL_P (0U) /* PDEC is in bits 6:0 */ | ||
36 | #define PLL_PDEC_VAL_M (0x7FUL << PLL_PDEC_VAL_P) | ||
37 | |||
38 | #define PLL_MIN_CCO_FREQ_MHZ (75000000U) | ||
39 | #define PLL_MAX_CCO_FREQ_MHZ (150000000U) | ||
40 | #define PLL_LOWER_IN_LIMIT (4000U) /*!< Minimum PLL input rate */ | ||
41 | #define PLL_MIN_IN_SSMODE (2000000U) | ||
42 | #define PLL_MAX_IN_SSMODE (4000000U) | ||
43 | |||
44 | /* Middle of the range values for spread-spectrum */ | ||
45 | #define PLL_SSCG_MF_FREQ_VALUE 4U | ||
46 | #define PLL_SSCG_MC_COMP_VALUE 2U | ||
47 | #define PLL_SSCG_MR_DEPTH_VALUE 4U | ||
48 | #define PLL_SSCG_DITHER_VALUE 0U | ||
49 | |||
50 | /* PLL NDEC reg */ | ||
51 | #define PLL_NDEC_VAL_SET(value) (((unsigned long)(value) << PLL_NDEC_VAL_P) & PLL_NDEC_VAL_M) | ||
52 | /* PLL PDEC reg */ | ||
53 | #define PLL_PDEC_VAL_SET(value) (((unsigned long)(value) << PLL_PDEC_VAL_P) & PLL_PDEC_VAL_M) | ||
54 | /* SSCG control0 */ | ||
55 | #define PLL_SSCG0_MDEC_VAL_SET(value) (((unsigned long)(value) << PLL_SSCG0_MDEC_VAL_P) & PLL_SSCG0_MDEC_VAL_M) | ||
56 | |||
57 | /* SSCG control1 */ | ||
58 | #define PLL_SSCG1_MD_FRACT_P 0U | ||
59 | #define PLL_SSCG1_MD_INT_P 11U | ||
60 | #define PLL_SSCG1_MD_FRACT_M (0x7FFUL << PLL_SSCG1_MD_FRACT_P) | ||
61 | #define PLL_SSCG1_MD_INT_M (0xFFUL << PLL_SSCG1_MD_INT_P) | ||
62 | |||
63 | #define PLL_SSCG1_MD_FRACT_SET(value) (((unsigned long)(value) << PLL_SSCG1_MD_FRACT_P) & PLL_SSCG1_MD_FRACT_M) | ||
64 | #define PLL_SSCG1_MD_INT_SET(value) (((unsigned long)(value) << PLL_SSCG1_MD_INT_P) & PLL_SSCG1_MD_INT_M) | ||
65 | |||
66 | /* Saved value of PLL output rate, computed whenever needed to save run-time | ||
67 | computation on each call to retrive the PLL rate. */ | ||
68 | static uint32_t s_Pll_Freq; | ||
69 | |||
70 | /* I2S mclk. */ | ||
71 | static uint32_t s_I2S_Mclk_Freq = 0U; | ||
72 | |||
73 | /** External clock rate on the CLKIN pin in Hz. If not used, | ||
74 | set this to 0. Otherwise, set it to the exact rate in Hz this pin is | ||
75 | being driven at. */ | ||
76 | static const uint32_t s_Ext_Clk_Freq = 0U; | ||
77 | |||
78 | /******************************************************************************* | ||
79 | * Variables | ||
80 | ******************************************************************************/ | ||
81 | |||
82 | /******************************************************************************* | ||
83 | * Prototypes | ||
84 | ******************************************************************************/ | ||
85 | /* Find encoded NDEC value for raw N value, max N = NVALMAX */ | ||
86 | static uint32_t pllEncodeN(uint32_t N); | ||
87 | /* Find decoded N value for raw NDEC value */ | ||
88 | static uint32_t pllDecodeN(uint32_t NDEC); | ||
89 | /* Find encoded PDEC value for raw P value, max P = PVALMAX */ | ||
90 | static uint32_t pllEncodeP(uint32_t P); | ||
91 | /* Find decoded P value for raw PDEC value */ | ||
92 | static uint32_t pllDecodeP(uint32_t PDEC); | ||
93 | /* Find encoded MDEC value for raw M value, max M = MVALMAX */ | ||
94 | static uint32_t pllEncodeM(uint32_t M); | ||
95 | /* Find decoded M value for raw MDEC value */ | ||
96 | static uint32_t pllDecodeM(uint32_t MDEC); | ||
97 | /* Find SELP, SELI, and SELR values for raw M value, max M = MVALMAX */ | ||
98 | static void pllFindSel(uint32_t M, bool bypassFBDIV2, uint32_t *pSelP, uint32_t *pSelI, uint32_t *pSelR); | ||
99 | /* Get predivider (N) from PLL NDEC setting */ | ||
100 | static uint32_t findPllPreDiv(uint32_t ctrlReg, uint32_t nDecReg); | ||
101 | /* Get postdivider (P) from PLL PDEC setting */ | ||
102 | static uint32_t findPllPostDiv(uint32_t ctrlReg, uint32_t pDecReg); | ||
103 | /* Get multiplier (M) from PLL MDEC and BYPASS_FBDIV2 settings */ | ||
104 | static uint32_t findPllMMult(uint32_t ctrlReg, uint32_t mDecReg); | ||
105 | /* Get the greatest common divisor */ | ||
106 | static uint32_t FindGreatestCommonDivisor(uint32_t m, uint32_t n); | ||
107 | /* Set PLL output based on desired output rate */ | ||
108 | static pll_error_t CLOCK_GetPllConfig( | ||
109 | uint32_t finHz, uint32_t foutHz, pll_setup_t *pSetup, bool useFeedbackDiv2, bool useSS); | ||
110 | /* Update local PLL rate variable */ | ||
111 | static void CLOCK_GetSystemPLLOutFromSetupUpdate(pll_setup_t *pSetup); | ||
112 | |||
113 | static const uint8_t wdtFreqLookup[32] = {0, 8, 12, 15, 18, 20, 24, 26, 28, 30, 32, 34, 36, 38, 40, 41, | ||
114 | 42, 44, 45, 46, 48, 49, 50, 52, 53, 54, 56, 57, 58, 59, 60, 61}; | ||
115 | /******************************************************************************* | ||
116 | * Code | ||
117 | ******************************************************************************/ | ||
118 | |||
119 | /** | ||
120 | * brief Configure the clock selection muxes. | ||
121 | * param connection : Clock to be configured. | ||
122 | * return Nothing | ||
123 | */ | ||
124 | void CLOCK_AttachClk(clock_attach_id_t connection) | ||
125 | { | ||
126 | uint8_t mux; | ||
127 | uint8_t sel; | ||
128 | uint16_t item; | ||
129 | uint32_t tmp32 = (uint32_t)connection; | ||
130 | uint32_t i; | ||
131 | volatile uint32_t *pClkSel; | ||
132 | |||
133 | pClkSel = &(SYSCON->MAINCLKSELA); | ||
134 | |||
135 | if (kNONE_to_NONE != connection) | ||
136 | { | ||
137 | for (i = 0U; i < 2U; i++) | ||
138 | { | ||
139 | if (tmp32 == 0U) | ||
140 | { | ||
141 | break; | ||
142 | } | ||
143 | item = (uint16_t)GET_ID_ITEM(tmp32); | ||
144 | if (item != 0U) | ||
145 | { | ||
146 | mux = GET_ID_ITEM_MUX(item); | ||
147 | sel = GET_ID_ITEM_SEL(item); | ||
148 | if (mux == CM_ASYNCAPB) | ||
149 | { | ||
150 | ASYNC_SYSCON->ASYNCAPBCLKSELA = sel; | ||
151 | } | ||
152 | else | ||
153 | { | ||
154 | ((volatile uint32_t *)pClkSel)[mux] = sel; | ||
155 | } | ||
156 | } | ||
157 | tmp32 = GET_ID_NEXT_ITEM(tmp32); /* pick up next descriptor */ | ||
158 | } | ||
159 | } | ||
160 | } | ||
161 | |||
162 | /* Return the actual clock attach id */ | ||
163 | /** | ||
164 | * brief Get the actual clock attach id. | ||
165 | * This fuction uses the offset in input attach id, then it reads the actual source value in | ||
166 | * the register and combine the offset to obtain an actual attach id. | ||
167 | * param attachId : Clock attach id to get. | ||
168 | * return Clock source value. | ||
169 | */ | ||
170 | clock_attach_id_t CLOCK_GetClockAttachId(clock_attach_id_t attachId) | ||
171 | { | ||
172 | uint8_t mux; | ||
173 | uint8_t actualSel; | ||
174 | uint32_t tmp32 = (uint32_t)attachId; | ||
175 | uint32_t i; | ||
176 | uint32_t actualAttachId = 0U; | ||
177 | uint32_t selector = GET_ID_SELECTOR(tmp32); | ||
178 | volatile uint32_t *pClkSel; | ||
179 | |||
180 | pClkSel = &(SYSCON->MAINCLKSELA); | ||
181 | |||
182 | if (kNONE_to_NONE == attachId) | ||
183 | { | ||
184 | return kNONE_to_NONE; | ||
185 | } | ||
186 | |||
187 | for (i = 0U; i < 2U; i++) | ||
188 | { | ||
189 | mux = GET_ID_ITEM_MUX(tmp32); | ||
190 | if (tmp32 != 0UL) | ||
191 | { | ||
192 | if (mux == CM_ASYNCAPB) | ||
193 | { | ||
194 | actualSel = (uint8_t)(ASYNC_SYSCON->ASYNCAPBCLKSELA); | ||
195 | } | ||
196 | else | ||
197 | { | ||
198 | actualSel = (uint8_t)(((volatile uint32_t *)pClkSel)[mux]); | ||
199 | } | ||
200 | |||
201 | /* Consider the combination of two registers */ | ||
202 | actualAttachId |= CLK_ATTACH_ID(mux, actualSel, i); | ||
203 | } | ||
204 | tmp32 = GET_ID_NEXT_ITEM(tmp32); /*!< pick up next descriptor */ | ||
205 | } | ||
206 | |||
207 | actualAttachId |= selector; | ||
208 | |||
209 | return (clock_attach_id_t)actualAttachId; | ||
210 | } | ||
211 | |||
212 | /** | ||
213 | * brief Setup peripheral clock dividers. | ||
214 | * param div_name : Clock divider name | ||
215 | * param divided_by_value: Value to be divided | ||
216 | * param reset : Whether to reset the divider counter. | ||
217 | * return Nothing | ||
218 | */ | ||
219 | void CLOCK_SetClkDiv(clock_div_name_t div_name, uint32_t divided_by_value, bool reset) | ||
220 | { | ||
221 | volatile uint32_t *pClkDiv; | ||
222 | |||
223 | pClkDiv = &(SYSCON->SYSTICKCLKDIV); | ||
224 | if (reset) | ||
225 | { | ||
226 | ((volatile uint32_t *)pClkDiv)[(uint8_t)div_name] = 1UL << 29U; | ||
227 | } | ||
228 | if (divided_by_value == 0UL) /* halt */ | ||
229 | { | ||
230 | ((volatile uint32_t *)pClkDiv)[(uint8_t)div_name] = 1UL << 30U; | ||
231 | } | ||
232 | else | ||
233 | { | ||
234 | ((volatile uint32_t *)pClkDiv)[(uint8_t)div_name] = (divided_by_value - 1UL); | ||
235 | } | ||
236 | } | ||
237 | |||
238 | /* Set FRO Clocking */ | ||
239 | /** | ||
240 | * brief Initialize the Core clock to given frequency (12, 48 or 96 MHz). | ||
241 | * Turns on FRO and uses default CCO, if freq is 12000000, then high speed output is off, else high speed output is | ||
242 | * enabled. | ||
243 | * param iFreq : Desired frequency (must be one of CLK_FRO_12MHZ or CLK_FRO_48MHZ or CLK_FRO_96MHZ) | ||
244 | * return returns success or fail status. | ||
245 | */ | ||
246 | status_t CLOCK_SetupFROClocking(uint32_t iFreq) | ||
247 | { | ||
248 | uint32_t usb_adj; | ||
249 | if ((iFreq != 12000000U) && (iFreq != 48000000U) && (iFreq != 96000000U)) | ||
250 | { | ||
251 | return kStatus_Fail; | ||
252 | } | ||
253 | /* Power up the FRO and set this as the base clock */ | ||
254 | POWER_DisablePD(kPDRUNCFG_PD_FRO_EN); | ||
255 | /* back up the value of whether USB adj is selected, in which case we will have a value of 1 else 0 */ | ||
256 | usb_adj = ((SYSCON->FROCTRL) & SYSCON_FROCTRL_USBCLKADJ_MASK) >> SYSCON_FROCTRL_USBCLKADJ_SHIFT; | ||
257 | if (iFreq > 12000000U) | ||
258 | { | ||
259 | if (iFreq == 96000000U) | ||
260 | { | ||
261 | SYSCON->FROCTRL = ((SYSCON_FROCTRL_TRIM_MASK | SYSCON_FROCTRL_FREQTRIM_MASK) & *INDEX_SECTOR_TRIM96) | | ||
262 | SYSCON_FROCTRL_SEL(1) | SYSCON_FROCTRL_WRTRIM(1) | SYSCON_FROCTRL_USBCLKADJ(usb_adj) | | ||
263 | SYSCON_FROCTRL_HSPDCLK(1); | ||
264 | } | ||
265 | else | ||
266 | { | ||
267 | SYSCON->FROCTRL = ((SYSCON_FROCTRL_TRIM_MASK | SYSCON_FROCTRL_FREQTRIM_MASK) & *INDEX_SECTOR_TRIM48) | | ||
268 | SYSCON_FROCTRL_SEL(0) | SYSCON_FROCTRL_WRTRIM(1) | SYSCON_FROCTRL_USBCLKADJ(usb_adj) | | ||
269 | SYSCON_FROCTRL_HSPDCLK(1); | ||
270 | } | ||
271 | } | ||
272 | else | ||
273 | { | ||
274 | SYSCON->FROCTRL &= ~SYSCON_FROCTRL_HSPDCLK(1); | ||
275 | } | ||
276 | |||
277 | return kStatus_Success; | ||
278 | } | ||
279 | |||
280 | /*! brief Return Frequency of FRO 12MHz | ||
281 | * return Frequency of FRO 12MHz | ||
282 | */ | ||
283 | uint32_t CLOCK_GetFro12MFreq(void) | ||
284 | { | ||
285 | return ((SYSCON->PDRUNCFG[0] & SYSCON_PDRUNCFG_PDEN_FRO_MASK) != 0UL) ? 0U : 12000000U; | ||
286 | } | ||
287 | |||
288 | /*! brief Return Frequency of External Clock | ||
289 | * return Frequency of External Clock. If no external clock is used returns 0. | ||
290 | */ | ||
291 | uint32_t CLOCK_GetExtClkFreq(void) | ||
292 | { | ||
293 | return (s_Ext_Clk_Freq); | ||
294 | } | ||
295 | /*! brief Return Frequency of Watchdog Oscillator | ||
296 | * return Frequency of Watchdog Oscillator | ||
297 | */ | ||
298 | uint32_t CLOCK_GetWdtOscFreq(void) | ||
299 | { | ||
300 | uint8_t freq_sel, div_sel; | ||
301 | if ((SYSCON->PDRUNCFG[(uint32_t)kPDRUNCFG_PD_WDT_OSC >> 8UL] & (1UL << ((uint32_t)kPDRUNCFG_PD_WDT_OSC & 0xffU))) != | ||
302 | 0UL) | ||
303 | { | ||
304 | return 0UL; | ||
305 | } | ||
306 | else | ||
307 | { | ||
308 | div_sel = (uint8_t)(((SYSCON->WDTOSCCTRL & 0x1fU) + 1UL) << 1U); | ||
309 | freq_sel = | ||
310 | wdtFreqLookup[((SYSCON->WDTOSCCTRL & SYSCON_WDTOSCCTRL_FREQSEL_MASK) >> SYSCON_WDTOSCCTRL_FREQSEL_SHIFT)]; | ||
311 | return ((uint32_t)freq_sel * 50000U) / ((uint32_t)div_sel); | ||
312 | } | ||
313 | } | ||
314 | |||
315 | /* Get HF FRO Clk */ | ||
316 | /*! brief Return Frequency of High-Freq output of FRO | ||
317 | * return Frequency of High-Freq output of FRO | ||
318 | */ | ||
319 | uint32_t CLOCK_GetFroHfFreq(void) | ||
320 | { | ||
321 | if (((SYSCON->PDRUNCFG[0] & SYSCON_PDRUNCFG_PDEN_FRO_MASK) != 0UL) || | ||
322 | ((SYSCON->FROCTRL & SYSCON_FROCTRL_HSPDCLK_MASK) == 0UL)) | ||
323 | { | ||
324 | return 0U; | ||
325 | } | ||
326 | |||
327 | if ((SYSCON->FROCTRL & SYSCON_FROCTRL_SEL_MASK) != 0UL) | ||
328 | { | ||
329 | return 96000000U; | ||
330 | } | ||
331 | else | ||
332 | { | ||
333 | return 48000000U; | ||
334 | } | ||
335 | } | ||
336 | |||
337 | /*! brief Return Frequency of PLL | ||
338 | * return Frequency of PLL | ||
339 | */ | ||
340 | uint32_t CLOCK_GetPllOutFreq(void) | ||
341 | { | ||
342 | return s_Pll_Freq; | ||
343 | } | ||
344 | |||
345 | /*! brief Return Frequency of 32kHz osc | ||
346 | * return Frequency of 32kHz osc | ||
347 | */ | ||
348 | uint32_t CLOCK_GetOsc32KFreq(void) | ||
349 | { | ||
350 | return CLK_RTC_32K_CLK; /* Needs to be corrected to check that RTC Clock is enabled */ | ||
351 | } | ||
352 | /*! brief Return Frequency of Core System | ||
353 | * return Frequency of Core System | ||
354 | */ | ||
355 | uint32_t CLOCK_GetCoreSysClkFreq(void) | ||
356 | { | ||
357 | uint32_t freq = 0U; | ||
358 | |||
359 | switch (SYSCON->MAINCLKSELB) | ||
360 | { | ||
361 | case 0U: | ||
362 | if (SYSCON->MAINCLKSELA == 0U) | ||
363 | { | ||
364 | freq = CLOCK_GetFro12MFreq(); | ||
365 | } | ||
366 | else if (SYSCON->MAINCLKSELA == 1U) | ||
367 | { | ||
368 | freq = CLOCK_GetExtClkFreq(); | ||
369 | } | ||
370 | else if (SYSCON->MAINCLKSELA == 2U) | ||
371 | { | ||
372 | freq = CLOCK_GetWdtOscFreq(); | ||
373 | } | ||
374 | else if (SYSCON->MAINCLKSELA == 3U) | ||
375 | { | ||
376 | freq = CLOCK_GetFroHfFreq(); | ||
377 | } | ||
378 | else | ||
379 | { | ||
380 | /* Add comment to prevent the case of MISRA C-2012 rule 15.7. */ | ||
381 | } | ||
382 | break; | ||
383 | case 2U: | ||
384 | freq = CLOCK_GetPllOutFreq(); | ||
385 | break; | ||
386 | |||
387 | case 3U: | ||
388 | freq = CLOCK_GetOsc32KFreq(); | ||
389 | break; | ||
390 | |||
391 | default: | ||
392 | assert(false); | ||
393 | break; | ||
394 | } | ||
395 | |||
396 | return freq; | ||
397 | } | ||
398 | /*! brief Return Frequency of I2S MCLK Clock | ||
399 | * return Frequency of I2S MCLK Clock | ||
400 | */ | ||
401 | uint32_t CLOCK_GetI2SMClkFreq(void) | ||
402 | { | ||
403 | return s_I2S_Mclk_Freq; | ||
404 | } | ||
405 | |||
406 | /*! brief Return Frequency of Asynchronous APB Clock | ||
407 | * return Frequency of Asynchronous APB Clock Clock | ||
408 | */ | ||
409 | uint32_t CLOCK_GetAsyncApbClkFreq(void) | ||
410 | { | ||
411 | async_clock_src_t clkSrc; | ||
412 | uint32_t clkRate; | ||
413 | |||
414 | clkSrc = CLOCK_GetAsyncApbClkSrc(); | ||
415 | |||
416 | switch (clkSrc) | ||
417 | { | ||
418 | case kCLOCK_AsyncMainClk: | ||
419 | clkRate = CLOCK_GetCoreSysClkFreq(); | ||
420 | break; | ||
421 | case kCLOCK_AsyncFro12Mhz: | ||
422 | clkRate = CLK_FRO_12MHZ; | ||
423 | break; | ||
424 | default: | ||
425 | clkRate = 0U; | ||
426 | break; | ||
427 | } | ||
428 | |||
429 | return clkRate; | ||
430 | } | ||
431 | |||
432 | /* Get FLEXCOMM Clk */ | ||
433 | /*! brief Return Frequency of Flexcomm functional Clock | ||
434 | * return Frequency of Flexcomm functional Clock | ||
435 | */ | ||
436 | uint32_t CLOCK_GetFlexCommClkFreq(uint32_t id) | ||
437 | { | ||
438 | uint32_t freq = 0U; | ||
439 | |||
440 | switch (SYSCON->FXCOMCLKSEL[id]) | ||
441 | { | ||
442 | case 0U: | ||
443 | freq = CLOCK_GetFro12MFreq(); | ||
444 | break; | ||
445 | case 1U: | ||
446 | freq = CLOCK_GetFroHfFreq(); | ||
447 | break; | ||
448 | case 2U: | ||
449 | freq = CLOCK_GetPllOutFreq(); | ||
450 | break; | ||
451 | case 3U: | ||
452 | freq = CLOCK_GetI2SMClkFreq(); | ||
453 | break; | ||
454 | case 4U: | ||
455 | freq = CLOCK_GetFrgClkFreq(); | ||
456 | break; | ||
457 | |||
458 | default: | ||
459 | assert(false); | ||
460 | break; | ||
461 | } | ||
462 | |||
463 | return freq; | ||
464 | } | ||
465 | |||
466 | /* Get ADC Clk */ | ||
467 | /*! brief Return Frequency of Adc Clock | ||
468 | * return Frequency of Adc Clock. | ||
469 | */ | ||
470 | uint32_t CLOCK_GetAdcClkFreq(void) | ||
471 | { | ||
472 | uint32_t freq = 0U; | ||
473 | |||
474 | switch (SYSCON->ADCCLKSEL) | ||
475 | { | ||
476 | case 0U: | ||
477 | freq = CLOCK_GetCoreSysClkFreq(); | ||
478 | break; | ||
479 | case 1U: | ||
480 | freq = CLOCK_GetPllOutFreq(); | ||
481 | break; | ||
482 | case 2U: | ||
483 | freq = CLOCK_GetFroHfFreq(); | ||
484 | break; | ||
485 | case 7U: | ||
486 | freq = 0U; | ||
487 | break; | ||
488 | default: | ||
489 | assert(false); | ||
490 | break; | ||
491 | } | ||
492 | |||
493 | return freq / ((SYSCON->ADCCLKDIV & 0xffU) + 1U); | ||
494 | } | ||
495 | |||
496 | /* Get FRG Clk */ | ||
497 | /*! brief Return Input frequency for the Fractional baud rate generator | ||
498 | * return Input Frequency for FRG | ||
499 | */ | ||
500 | uint32_t CLOCK_GetFRGInputClock(void) | ||
501 | { | ||
502 | uint32_t freq = 0U; | ||
503 | |||
504 | switch (SYSCON->FRGCLKSEL) | ||
505 | { | ||
506 | case 0U: | ||
507 | freq = CLOCK_GetCoreSysClkFreq(); | ||
508 | break; | ||
509 | case 1U: | ||
510 | freq = CLOCK_GetPllOutFreq(); | ||
511 | break; | ||
512 | case 2U: | ||
513 | freq = CLOCK_GetFro12MFreq(); | ||
514 | break; | ||
515 | case 3U: | ||
516 | freq = CLOCK_GetFroHfFreq(); | ||
517 | break; | ||
518 | |||
519 | default: | ||
520 | assert(false); | ||
521 | break; | ||
522 | } | ||
523 | |||
524 | return freq; | ||
525 | } | ||
526 | |||
527 | /* Get DMIC Clk */ | ||
528 | /*! brief Return Input frequency for the DMIC | ||
529 | * return Input Frequency for DMIC | ||
530 | */ | ||
531 | uint32_t CLOCK_GetDmicClkFreq(void) | ||
532 | { | ||
533 | uint32_t freq = 0U; | ||
534 | |||
535 | switch (SYSCON->DMICCLKSEL) | ||
536 | { | ||
537 | case 0U: | ||
538 | freq = CLOCK_GetFro12MFreq(); | ||
539 | break; | ||
540 | case 1U: | ||
541 | freq = CLOCK_GetFroHfFreq(); | ||
542 | break; | ||
543 | case 2U: | ||
544 | freq = CLOCK_GetPllOutFreq(); | ||
545 | break; | ||
546 | case 3U: | ||
547 | freq = CLOCK_GetI2SMClkFreq(); | ||
548 | break; | ||
549 | case 4U: | ||
550 | freq = CLOCK_GetCoreSysClkFreq(); | ||
551 | break; | ||
552 | case 5U: | ||
553 | freq = CLOCK_GetWdtOscFreq(); | ||
554 | break; | ||
555 | default: | ||
556 | assert(false); | ||
557 | break; | ||
558 | } | ||
559 | |||
560 | return freq / ((SYSCON->DMICCLKDIV & 0xffU) + 1U); | ||
561 | } | ||
562 | |||
563 | /*! brief Set output of the Fractional baud rate generator | ||
564 | * param freq : Desired output frequency | ||
565 | * return Error Code 0 - fail 1 - success | ||
566 | */ | ||
567 | uint32_t CLOCK_SetFRGClock(uint32_t freq) | ||
568 | { | ||
569 | uint32_t input = CLOCK_GetFRGInputClock(); | ||
570 | uint32_t mul; | ||
571 | |||
572 | if ((freq > 48000000UL) || (freq > input) || (input / freq >= 2UL)) | ||
573 | { | ||
574 | /* FRG output frequency should be less than equal to 48MHz */ | ||
575 | return 0; | ||
576 | } | ||
577 | else | ||
578 | { | ||
579 | mul = (uint32_t)((((uint64_t)input - freq) * 256UL) / ((uint64_t)freq)); | ||
580 | SYSCON->FRGCTRL = (mul << SYSCON_FRGCTRL_MULT_SHIFT) | SYSCON_FRGCTRL_DIV_MASK; | ||
581 | return 1; | ||
582 | } | ||
583 | } | ||
584 | |||
585 | /* Get FRG Clk */ | ||
586 | /*! brief Return Input frequency for the FRG | ||
587 | * return Input Frequency for FRG | ||
588 | */ | ||
589 | uint32_t CLOCK_GetFrgClkFreq(void) | ||
590 | { | ||
591 | uint32_t freq = 0U; | ||
592 | |||
593 | if ((SYSCON->FRGCTRL & SYSCON_FRGCTRL_DIV_MASK) == SYSCON_FRGCTRL_DIV_MASK) | ||
594 | { | ||
595 | freq = (uint32_t)(((uint64_t)CLOCK_GetFRGInputClock() * (SYSCON_FRGCTRL_DIV_MASK + 1U)) / | ||
596 | ((SYSCON_FRGCTRL_DIV_MASK + 1U) + | ||
597 | ((SYSCON->FRGCTRL & SYSCON_FRGCTRL_MULT_MASK) >> SYSCON_FRGCTRL_MULT_SHIFT))); | ||
598 | } | ||
599 | else | ||
600 | { | ||
601 | freq = 0U; | ||
602 | } | ||
603 | |||
604 | return freq; | ||
605 | } | ||
606 | |||
607 | /*! brief Return Frequency of USB | ||
608 | * return Frequency of USB | ||
609 | */ | ||
610 | uint32_t CLOCK_GetUsbClkFreq(void) | ||
611 | { | ||
612 | uint32_t freq = 0U; | ||
613 | |||
614 | if (SYSCON->USBCLKSEL == 0U) | ||
615 | { | ||
616 | freq = CLOCK_GetFroHfFreq(); | ||
617 | } | ||
618 | else if (SYSCON->USBCLKSEL == 1U) | ||
619 | { | ||
620 | freq = CLOCK_GetPllOutFreq(); | ||
621 | } | ||
622 | else | ||
623 | { | ||
624 | /* Add comment to prevent the case of MISRA C-2012 rule 15.7. */ | ||
625 | } | ||
626 | |||
627 | return freq / ((SYSCON->USBCLKDIV & 0xffU) + 1U); | ||
628 | } | ||
629 | |||
630 | /*! brief Return Frequency of selected clock | ||
631 | * return Frequency of selected clock | ||
632 | */ | ||
633 | uint32_t CLOCK_GetFreq(clock_name_t clockName) | ||
634 | { | ||
635 | uint32_t freq; | ||
636 | switch (clockName) | ||
637 | { | ||
638 | case kCLOCK_CoreSysClk: | ||
639 | freq = CLOCK_GetCoreSysClkFreq(); | ||
640 | break; | ||
641 | case kCLOCK_BusClk: | ||
642 | freq = CLOCK_GetCoreSysClkFreq() / ((SYSCON->AHBCLKDIV & 0xffU) + 1U); | ||
643 | break; | ||
644 | case kCLOCK_FroHf: | ||
645 | freq = CLOCK_GetFroHfFreq(); | ||
646 | break; | ||
647 | case kCLOCK_Fro12M: | ||
648 | freq = CLOCK_GetFro12MFreq(); | ||
649 | break; | ||
650 | case kCLOCK_PllOut: | ||
651 | freq = CLOCK_GetPllOutFreq(); | ||
652 | break; | ||
653 | case kCLOCK_UsbClk: | ||
654 | freq = CLOCK_GetUsbClkFreq(); | ||
655 | break; | ||
656 | case kCLOCK_WdtOsc: | ||
657 | freq = CLOCK_GetWdtOscFreq(); | ||
658 | break; | ||
659 | case kCLOCK_Frg: | ||
660 | freq = CLOCK_GetFrgClkFreq(); | ||
661 | break; | ||
662 | case kCLOCK_AsyncApbClk: | ||
663 | freq = CLOCK_GetAsyncApbClkFreq(); | ||
664 | break; | ||
665 | case kCLOCK_FlexI2S: | ||
666 | freq = CLOCK_GetI2SMClkFreq(); | ||
667 | break; | ||
668 | default: | ||
669 | freq = 0U; | ||
670 | break; | ||
671 | } | ||
672 | |||
673 | return freq; | ||
674 | } | ||
675 | |||
676 | /* Set the FLASH wait states for the passed frequency */ | ||
677 | /** | ||
678 | * brief Set the flash wait states for the input freuqency. | ||
679 | * param iFreq : Input frequency | ||
680 | * return Nothing | ||
681 | */ | ||
682 | void CLOCK_SetFLASHAccessCyclesForFreq(uint32_t iFreq) | ||
683 | { | ||
684 | if (iFreq <= 12000000U) | ||
685 | { | ||
686 | CLOCK_SetFLASHAccessCycles(kCLOCK_Flash1Cycle); | ||
687 | } | ||
688 | else if (iFreq <= 24000000U) | ||
689 | { | ||
690 | CLOCK_SetFLASHAccessCycles(kCLOCK_Flash2Cycle); | ||
691 | } | ||
692 | else if (iFreq <= 48000000U) | ||
693 | { | ||
694 | CLOCK_SetFLASHAccessCycles(kCLOCK_Flash3Cycle); | ||
695 | } | ||
696 | else if (iFreq <= 72000000U) | ||
697 | { | ||
698 | CLOCK_SetFLASHAccessCycles(kCLOCK_Flash4Cycle); | ||
699 | } | ||
700 | else if (iFreq <= 84000000U) | ||
701 | { | ||
702 | CLOCK_SetFLASHAccessCycles(kCLOCK_Flash5Cycle); | ||
703 | } | ||
704 | else if (iFreq <= 100000000U) | ||
705 | { | ||
706 | CLOCK_SetFLASHAccessCycles(kCLOCK_Flash6Cycle); | ||
707 | } | ||
708 | else | ||
709 | { | ||
710 | CLOCK_SetFLASHAccessCycles(kCLOCK_Flash7Cycle); | ||
711 | } | ||
712 | } | ||
713 | |||
714 | /* Find encoded NDEC value for raw N value, max N = NVALMAX */ | ||
715 | static uint32_t pllEncodeN(uint32_t N) | ||
716 | { | ||
717 | uint32_t x, i; | ||
718 | |||
719 | /* Find NDec */ | ||
720 | switch (N) | ||
721 | { | ||
722 | case 0U: | ||
723 | x = 0x3FFU; | ||
724 | break; | ||
725 | |||
726 | case 1U: | ||
727 | x = 0x302U; | ||
728 | break; | ||
729 | |||
730 | case 2U: | ||
731 | x = 0x202U; | ||
732 | break; | ||
733 | |||
734 | default: | ||
735 | x = 0x080U; | ||
736 | for (i = N; i <= NVALMAX; i++) | ||
737 | { | ||
738 | x = (((x ^ (x >> 2U) ^ (x >> 3U) ^ (x >> 4U)) & 1U) << 7U) | ((x >> 1U) & 0x7FU); | ||
739 | } | ||
740 | break; | ||
741 | } | ||
742 | |||
743 | return x & (PLL_NDEC_VAL_M >> PLL_NDEC_VAL_P); | ||
744 | } | ||
745 | |||
746 | /* Find decoded N value for raw NDEC value */ | ||
747 | static uint32_t pllDecodeN(uint32_t NDEC) | ||
748 | { | ||
749 | uint32_t n, x, i; | ||
750 | |||
751 | /* Find NDec */ | ||
752 | switch (NDEC) | ||
753 | { | ||
754 | case 0x3FFU: | ||
755 | n = 0U; | ||
756 | break; | ||
757 | |||
758 | case 0x302U: | ||
759 | n = 1U; | ||
760 | break; | ||
761 | |||
762 | case 0x202U: | ||
763 | n = 2U; | ||
764 | break; | ||
765 | |||
766 | default: | ||
767 | x = 0x080U; | ||
768 | n = 0xFFFFFFFFU; | ||
769 | for (i = NVALMAX; i >= 3U; i--) | ||
770 | { | ||
771 | x = (((x ^ (x >> 2U) ^ (x >> 3U) ^ (x >> 4U)) & 1U) << 7U) | ((x >> 1U) & 0x7FU); | ||
772 | if ((x & (PLL_NDEC_VAL_M >> PLL_NDEC_VAL_P)) == NDEC) | ||
773 | { | ||
774 | /* Decoded value of NDEC */ | ||
775 | n = i; | ||
776 | break; | ||
777 | } | ||
778 | } | ||
779 | break; | ||
780 | } | ||
781 | |||
782 | return n; | ||
783 | } | ||
784 | |||
785 | /* Find encoded PDEC value for raw P value, max P = PVALMAX */ | ||
786 | static uint32_t pllEncodeP(uint32_t P) | ||
787 | { | ||
788 | uint32_t x, i; | ||
789 | |||
790 | /* Find PDec */ | ||
791 | switch (P) | ||
792 | { | ||
793 | case 0U: | ||
794 | x = 0x7FU; | ||
795 | break; | ||
796 | |||
797 | case 1U: | ||
798 | x = 0x62U; | ||
799 | break; | ||
800 | |||
801 | case 2U: | ||
802 | x = 0x42U; | ||
803 | break; | ||
804 | |||
805 | default: | ||
806 | x = 0x10U; | ||
807 | for (i = P; i <= PVALMAX; i++) | ||
808 | { | ||
809 | x = (((x ^ (x >> 2U)) & 1U) << 4U) | ((x >> 1U) & 0xFU); | ||
810 | } | ||
811 | break; | ||
812 | } | ||
813 | |||
814 | return x & (PLL_PDEC_VAL_M >> PLL_PDEC_VAL_P); | ||
815 | } | ||
816 | |||
817 | /* Find decoded P value for raw PDEC value */ | ||
818 | static uint32_t pllDecodeP(uint32_t PDEC) | ||
819 | { | ||
820 | uint32_t p, x, i; | ||
821 | |||
822 | /* Find PDec */ | ||
823 | switch (PDEC) | ||
824 | { | ||
825 | case 0x7FU: | ||
826 | p = 0U; | ||
827 | break; | ||
828 | |||
829 | case 0x62U: | ||
830 | p = 1U; | ||
831 | break; | ||
832 | |||
833 | case 0x42U: | ||
834 | p = 2U; | ||
835 | break; | ||
836 | |||
837 | default: | ||
838 | x = 0x10U; | ||
839 | p = 0xFFFFFFFFU; | ||
840 | for (i = PVALMAX; i >= 3U; i--) | ||
841 | { | ||
842 | x = (((x ^ (x >> 2U)) & 1U) << 4U) | ((x >> 1U) & 0xFU); | ||
843 | if ((x & (PLL_PDEC_VAL_M >> PLL_PDEC_VAL_P)) == PDEC) | ||
844 | { | ||
845 | /* Decoded value of PDEC */ | ||
846 | p = i; | ||
847 | break; | ||
848 | } | ||
849 | } | ||
850 | break; | ||
851 | } | ||
852 | |||
853 | return p; | ||
854 | } | ||
855 | |||
856 | /* Find encoded MDEC value for raw M value, max M = MVALMAX */ | ||
857 | static uint32_t pllEncodeM(uint32_t M) | ||
858 | { | ||
859 | uint32_t i, x; | ||
860 | |||
861 | /* Find MDec */ | ||
862 | switch (M) | ||
863 | { | ||
864 | case 0U: | ||
865 | x = 0x1FFFFU; | ||
866 | break; | ||
867 | |||
868 | case 1U: | ||
869 | x = 0x18003U; | ||
870 | break; | ||
871 | |||
872 | case 2U: | ||
873 | x = 0x10003U; | ||
874 | break; | ||
875 | |||
876 | default: | ||
877 | x = 0x04000U; | ||
878 | for (i = M; i <= MVALMAX; i++) | ||
879 | { | ||
880 | x = (((x ^ (x >> 1U)) & 1U) << 14U) | ((x >> 1U) & 0x3FFFU); | ||
881 | } | ||
882 | break; | ||
883 | } | ||
884 | |||
885 | return x & (PLL_SSCG0_MDEC_VAL_M >> PLL_SSCG0_MDEC_VAL_P); | ||
886 | } | ||
887 | |||
888 | /* Find decoded M value for raw MDEC value */ | ||
889 | static uint32_t pllDecodeM(uint32_t MDEC) | ||
890 | { | ||
891 | uint32_t m, i, x; | ||
892 | |||
893 | /* Find MDec */ | ||
894 | switch (MDEC) | ||
895 | { | ||
896 | case 0x1FFFFU: | ||
897 | m = 0U; | ||
898 | break; | ||
899 | |||
900 | case 0x18003U: | ||
901 | m = 1U; | ||
902 | break; | ||
903 | |||
904 | case 0x10003U: | ||
905 | m = 2U; | ||
906 | break; | ||
907 | |||
908 | default: | ||
909 | x = 0x04000U; | ||
910 | m = 0xFFFFFFFFU; | ||
911 | for (i = MVALMAX; i >= 3U; i--) | ||
912 | { | ||
913 | x = (((x ^ (x >> 1U)) & 1U) << 14U) | ((x >> 1U) & 0x3FFFU); | ||
914 | if ((x & (PLL_SSCG0_MDEC_VAL_M >> PLL_SSCG0_MDEC_VAL_P)) == MDEC) | ||
915 | { | ||
916 | /* Decoded value of MDEC */ | ||
917 | m = i; | ||
918 | break; | ||
919 | } | ||
920 | } | ||
921 | break; | ||
922 | } | ||
923 | |||
924 | return m; | ||
925 | } | ||
926 | |||
927 | /* Find SELP, SELI, and SELR values for raw M value, max M = MVALMAX */ | ||
928 | static void pllFindSel(uint32_t M, bool bypassFBDIV2, uint32_t *pSelP, uint32_t *pSelI, uint32_t *pSelR) | ||
929 | { | ||
930 | /* bandwidth: compute selP from Multiplier */ | ||
931 | if (M < 60U) | ||
932 | { | ||
933 | *pSelP = (M >> 1U) + 1U; | ||
934 | } | ||
935 | else | ||
936 | { | ||
937 | *pSelP = PVALMAX - 1U; | ||
938 | } | ||
939 | |||
940 | /* bandwidth: compute selI from Multiplier */ | ||
941 | if (M > 16384U) | ||
942 | { | ||
943 | *pSelI = 1U; | ||
944 | } | ||
945 | else if (M > 8192U) | ||
946 | { | ||
947 | *pSelI = 2U; | ||
948 | } | ||
949 | else if (M > 2048U) | ||
950 | { | ||
951 | *pSelI = 4U; | ||
952 | } | ||
953 | else if (M >= 501U) | ||
954 | { | ||
955 | *pSelI = 8U; | ||
956 | } | ||
957 | else if (M >= 60U) | ||
958 | { | ||
959 | *pSelI = 4U * (1024U / (M + 9U)); | ||
960 | } | ||
961 | else | ||
962 | { | ||
963 | *pSelI = (M & 0x3CU) + 4U; | ||
964 | } | ||
965 | |||
966 | if (*pSelI > ((0x3FUL << SYSCON_SYSPLLCTRL_SELI_SHIFT) >> SYSCON_SYSPLLCTRL_SELI_SHIFT)) | ||
967 | { | ||
968 | *pSelI = ((0x3FUL << SYSCON_SYSPLLCTRL_SELI_SHIFT) >> SYSCON_SYSPLLCTRL_SELI_SHIFT); | ||
969 | } | ||
970 | |||
971 | *pSelR = 0U; | ||
972 | } | ||
973 | |||
974 | /* Get predivider (N) from PLL NDEC setting */ | ||
975 | static uint32_t findPllPreDiv(uint32_t ctrlReg, uint32_t nDecReg) | ||
976 | { | ||
977 | uint32_t preDiv = 1; | ||
978 | |||
979 | /* Direct input is not used? */ | ||
980 | if ((ctrlReg & (1UL << SYSCON_SYSPLLCTRL_DIRECTI_SHIFT)) == 0U) | ||
981 | { | ||
982 | /* Decode NDEC value to get (N) pre divider */ | ||
983 | preDiv = pllDecodeN(nDecReg & 0x3FFU); | ||
984 | if (preDiv == 0U) | ||
985 | { | ||
986 | preDiv = 1U; | ||
987 | } | ||
988 | } | ||
989 | |||
990 | /* Adjusted by 1, directi is used to bypass */ | ||
991 | return preDiv; | ||
992 | } | ||
993 | |||
994 | /* Get postdivider (P) from PLL PDEC setting */ | ||
995 | static uint32_t findPllPostDiv(uint32_t ctrlReg, uint32_t pDecReg) | ||
996 | { | ||
997 | uint32_t postDiv = 1U; | ||
998 | |||
999 | /* Direct input is not used? */ | ||
1000 | if ((ctrlReg & SYSCON_SYSPLLCTRL_DIRECTO_MASK) == 0U) | ||
1001 | { | ||
1002 | /* Decode PDEC value to get (P) post divider */ | ||
1003 | postDiv = 2U * pllDecodeP(pDecReg & 0x7FU); | ||
1004 | if (postDiv == 0U) | ||
1005 | { | ||
1006 | postDiv = 2U; | ||
1007 | } | ||
1008 | } | ||
1009 | |||
1010 | /* Adjusted by 1, directo is used to bypass */ | ||
1011 | return postDiv; | ||
1012 | } | ||
1013 | |||
1014 | /* Get multiplier (M) from PLL MDEC and BYPASS_FBDIV2 settings */ | ||
1015 | static uint32_t findPllMMult(uint32_t ctrlReg, uint32_t mDecReg) | ||
1016 | { | ||
1017 | uint32_t mMult = 1U; | ||
1018 | |||
1019 | /* Decode MDEC value to get (M) multiplier */ | ||
1020 | mMult = pllDecodeM(mDecReg & 0x1FFFFU); | ||
1021 | |||
1022 | /* Extra multiply by 2 needed? */ | ||
1023 | if ((ctrlReg & (SYSCON_SYSPLLCTRL_BYPASSCCODIV2_MASK)) == 0U) | ||
1024 | { | ||
1025 | mMult = mMult << 1U; | ||
1026 | } | ||
1027 | |||
1028 | if (mMult == 0U) | ||
1029 | { | ||
1030 | mMult = 1U; | ||
1031 | } | ||
1032 | |||
1033 | return mMult; | ||
1034 | } | ||
1035 | |||
1036 | static uint32_t FindGreatestCommonDivisor(uint32_t m, uint32_t n) | ||
1037 | { | ||
1038 | uint32_t tmp; | ||
1039 | |||
1040 | while (n != 0U) | ||
1041 | { | ||
1042 | tmp = n; | ||
1043 | n = m % n; | ||
1044 | m = tmp; | ||
1045 | } | ||
1046 | |||
1047 | return m; | ||
1048 | } | ||
1049 | |||
1050 | /* | ||
1051 | * Set PLL output based on desired output rate. | ||
1052 | * In this function, the it calculates the PLL setting for output frequency from input clock | ||
1053 | * frequency. The calculation would cost a few time. So it is not recommaned to use it frequently. | ||
1054 | * the "pllctrl", "pllndec", "pllpdec", "pllmdec" would updated in this function. | ||
1055 | */ | ||
1056 | static pll_error_t CLOCK_GetPllConfigInternal( | ||
1057 | uint32_t finHz, uint32_t foutHz, pll_setup_t *pSetup, bool useFeedbackDiv2, bool useSS) | ||
1058 | { | ||
1059 | uint32_t nDivOutHz, fccoHz, multFccoDiv; | ||
1060 | uint32_t pllPreDivider, pllMultiplier, pllBypassFBDIV2, pllPostDivider; | ||
1061 | uint32_t pllDirectInput, pllDirectOutput; | ||
1062 | uint32_t pllSelP, pllSelI, pllSelR, bandsel, uplimoff; | ||
1063 | |||
1064 | /* Baseline parameters (no input or output dividers) */ | ||
1065 | pllPreDivider = 1U; /* 1 implies pre-divider will be disabled */ | ||
1066 | pllPostDivider = 0U; /* 0 implies post-divider will be disabled */ | ||
1067 | pllDirectOutput = 1U; | ||
1068 | if (useFeedbackDiv2) | ||
1069 | { | ||
1070 | /* Using feedback divider for M, so disable bypass */ | ||
1071 | pllBypassFBDIV2 = 0U; | ||
1072 | } | ||
1073 | else | ||
1074 | { | ||
1075 | pllBypassFBDIV2 = 1U; | ||
1076 | } | ||
1077 | multFccoDiv = (2U - pllBypassFBDIV2); | ||
1078 | |||
1079 | /* Verify output rate parameter */ | ||
1080 | if (foutHz > PLL_MAX_CCO_FREQ_MHZ) | ||
1081 | { | ||
1082 | /* Maximum PLL output with post divider=1 cannot go above this frequency */ | ||
1083 | return kStatus_PLL_OutputTooHigh; | ||
1084 | } | ||
1085 | if (foutHz < (PLL_MIN_CCO_FREQ_MHZ / (PVALMAX << 1U))) | ||
1086 | { | ||
1087 | /* Minmum PLL output with maximum post divider cannot go below this frequency */ | ||
1088 | return kStatus_PLL_OutputTooLow; | ||
1089 | } | ||
1090 | |||
1091 | /* If using SS mode, input clock needs to be between 2MHz and 4MHz */ | ||
1092 | if (useSS) | ||
1093 | { | ||
1094 | /* Verify input rate parameter */ | ||
1095 | if (finHz < PLL_MIN_IN_SSMODE) | ||
1096 | { | ||
1097 | /* Input clock into the PLL cannot be lower than this */ | ||
1098 | return kStatus_PLL_InputTooLow; | ||
1099 | } | ||
1100 | /* PLL input in SS mode must be under 4MHz */ | ||
1101 | pllPreDivider = finHz / ((PLL_MIN_IN_SSMODE + PLL_MAX_IN_SSMODE) / 2U); | ||
1102 | if (pllPreDivider > NVALMAX) | ||
1103 | { | ||
1104 | return kStatus_PLL_InputTooHigh; | ||
1105 | } | ||
1106 | } | ||
1107 | else | ||
1108 | { | ||
1109 | /* Verify input rate parameter */ | ||
1110 | if (finHz < PLL_LOWER_IN_LIMIT) | ||
1111 | { | ||
1112 | /* Input clock into the PLL cannot be lower than this */ | ||
1113 | return kStatus_PLL_InputTooLow; | ||
1114 | } | ||
1115 | } | ||
1116 | |||
1117 | /* Find the optimal CCO frequency for the output and input that | ||
1118 | will keep it inside the PLL CCO range. This may require | ||
1119 | tweaking the post-divider for the PLL. */ | ||
1120 | fccoHz = foutHz; | ||
1121 | while (fccoHz < PLL_MIN_CCO_FREQ_MHZ) | ||
1122 | { | ||
1123 | /* CCO output is less than minimum CCO range, so the CCO output | ||
1124 | needs to be bumped up and the post-divider is used to bring | ||
1125 | the PLL output back down. */ | ||
1126 | pllPostDivider++; | ||
1127 | if (pllPostDivider > PVALMAX) | ||
1128 | { | ||
1129 | return kStatus_PLL_OutsideIntLimit; | ||
1130 | } | ||
1131 | |||
1132 | /* Target CCO goes up, PLL output goes down */ | ||
1133 | fccoHz = foutHz * (pllPostDivider * 2U); | ||
1134 | pllDirectOutput = 0U; | ||
1135 | } | ||
1136 | |||
1137 | /* Determine if a pre-divider is needed to get the best frequency */ | ||
1138 | if ((finHz > PLL_LOWER_IN_LIMIT) && (fccoHz >= finHz) && (useSS == false)) | ||
1139 | { | ||
1140 | uint32_t a = FindGreatestCommonDivisor(fccoHz, (multFccoDiv * finHz)); | ||
1141 | |||
1142 | if (a > 20000U) | ||
1143 | { | ||
1144 | a = (multFccoDiv * finHz) / a; | ||
1145 | if ((a != 0U) && (a < PLL_MAX_N_DIV)) | ||
1146 | { | ||
1147 | pllPreDivider = a; | ||
1148 | } | ||
1149 | } | ||
1150 | } | ||
1151 | |||
1152 | /* Bypass pre-divider hardware if pre-divider is 1 */ | ||
1153 | if (pllPreDivider > 1U) | ||
1154 | { | ||
1155 | pllDirectInput = 0U; | ||
1156 | } | ||
1157 | else | ||
1158 | { | ||
1159 | pllDirectInput = 1U; | ||
1160 | } | ||
1161 | |||
1162 | /* Determine PLL multipler */ | ||
1163 | nDivOutHz = (finHz / pllPreDivider); | ||
1164 | pllMultiplier = (fccoHz / nDivOutHz) / multFccoDiv; | ||
1165 | |||
1166 | /* Find optimal values for filter */ | ||
1167 | if (useSS == false) | ||
1168 | { | ||
1169 | /* Will bumping up M by 1 get us closer to the desired CCO frequency? */ | ||
1170 | if ((nDivOutHz * ((multFccoDiv * pllMultiplier * 2U) + 1U)) < (fccoHz * 2U)) | ||
1171 | { | ||
1172 | pllMultiplier++; | ||
1173 | } | ||
1174 | |||
1175 | /* Setup filtering */ | ||
1176 | pllFindSel(pllMultiplier, (bool)pllBypassFBDIV2, &pllSelP, &pllSelI, &pllSelR); | ||
1177 | bandsel = 1U; | ||
1178 | uplimoff = 0U; | ||
1179 | |||
1180 | /* Get encoded value for M (mult) and use manual filter, disable SS mode */ | ||
1181 | pSetup->syspllssctrl[0] = | ||
1182 | (PLL_SSCG0_MDEC_VAL_SET(pllEncodeM(pllMultiplier)) | (1UL << SYSCON_SYSPLLSSCTRL0_SEL_EXT_SHIFT)); | ||
1183 | |||
1184 | /* Power down SSC, not used */ | ||
1185 | pSetup->syspllssctrl[1] = (1UL << SYSCON_SYSPLLSSCTRL1_PD_SHIFT); | ||
1186 | } | ||
1187 | else | ||
1188 | { | ||
1189 | uint64_t fc; | ||
1190 | |||
1191 | /* Filtering will be handled by SSC */ | ||
1192 | pllSelR = 0U; | ||
1193 | pllSelI = 0U; | ||
1194 | pllSelP = 0U; | ||
1195 | bandsel = 0U; | ||
1196 | uplimoff = 1U; | ||
1197 | |||
1198 | /* The PLL multiplier will get very close and slightly under the | ||
1199 | desired target frequency. A small fractional component can be | ||
1200 | added to fine tune the frequency upwards to the target. */ | ||
1201 | fc = (((uint64_t)fccoHz % ((uint64_t)multFccoDiv * nDivOutHz)) << 11U) / ((uint64_t)multFccoDiv * nDivOutHz); | ||
1202 | |||
1203 | /* MDEC set by SSC */ | ||
1204 | pSetup->syspllssctrl[0U] = 0U; | ||
1205 | |||
1206 | /* Set multiplier */ | ||
1207 | pSetup->syspllssctrl[1] = PLL_SSCG1_MD_INT_SET(pllMultiplier) | PLL_SSCG1_MD_FRACT_SET((uint32_t)fc); | ||
1208 | } | ||
1209 | |||
1210 | /* Get encoded values for N (prediv) and P (postdiv) */ | ||
1211 | pSetup->syspllndec = PLL_NDEC_VAL_SET(pllEncodeN(pllPreDivider)); | ||
1212 | pSetup->syspllpdec = PLL_PDEC_VAL_SET(pllEncodeP(pllPostDivider)); | ||
1213 | |||
1214 | /* PLL control */ | ||
1215 | pSetup->syspllctrl = (pllSelR << SYSCON_SYSPLLCTRL_SELR_SHIFT) | /* Filter coefficient */ | ||
1216 | (pllSelI << SYSCON_SYSPLLCTRL_SELI_SHIFT) | /* Filter coefficient */ | ||
1217 | (pllSelP << SYSCON_SYSPLLCTRL_SELP_SHIFT) | /* Filter coefficient */ | ||
1218 | (0UL << SYSCON_SYSPLLCTRL_BYPASS_SHIFT) | /* PLL bypass mode disabled */ | ||
1219 | (pllBypassFBDIV2 << SYSCON_SYSPLLCTRL_BYPASSCCODIV2_SHIFT) | /* Extra M / 2 divider? */ | ||
1220 | (uplimoff << SYSCON_SYSPLLCTRL_UPLIMOFF_SHIFT) | /* SS/fractional mode disabled */ | ||
1221 | (bandsel << SYSCON_SYSPLLCTRL_BANDSEL_SHIFT) | /* Manual bandwidth selection enabled */ | ||
1222 | (pllDirectInput << SYSCON_SYSPLLCTRL_DIRECTI_SHIFT) | /* Bypass pre-divider? */ | ||
1223 | (pllDirectOutput << SYSCON_SYSPLLCTRL_DIRECTO_SHIFT); /* Bypass post-divider? */ | ||
1224 | |||
1225 | return kStatus_PLL_Success; | ||
1226 | } | ||
1227 | |||
1228 | #if (defined(CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT) && CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT) | ||
1229 | /* Alloct the static buffer for cache. */ | ||
1230 | static pll_setup_t s_PllSetupCacheStruct[CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT]; | ||
1231 | static uint32_t s_FinHzCache[CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT] = {0}; | ||
1232 | static uint32_t s_FoutHzCache[CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT] = {0}; | ||
1233 | static bool s_UseFeedbackDiv2Cache[CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT] = {false}; | ||
1234 | static bool s_UseSSCache[CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT] = {false}; | ||
1235 | static uint32_t s_PllSetupCacheIdx = 0U; | ||
1236 | #endif /* CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT */ | ||
1237 | |||
1238 | /* | ||
1239 | * Calculate the PLL setting values from input clock freq to output freq. | ||
1240 | */ | ||
1241 | static pll_error_t CLOCK_GetPllConfig( | ||
1242 | uint32_t finHz, uint32_t foutHz, pll_setup_t *pSetup, bool useFeedbackDiv2, bool useSS) | ||
1243 | { | ||
1244 | pll_error_t retErr; | ||
1245 | #if (defined(CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT) && CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT) | ||
1246 | uint32_t i; | ||
1247 | |||
1248 | for (i = 0U; i < CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT; i++) | ||
1249 | { | ||
1250 | if ((finHz == s_FinHzCache[i]) && (foutHz == s_FoutHzCache[i]) && | ||
1251 | (useFeedbackDiv2 == s_UseFeedbackDiv2Cache[i]) && (useSS == s_UseSSCache[i])) | ||
1252 | { | ||
1253 | /* Hit the target in cache buffer. */ | ||
1254 | pSetup->syspllctrl = s_PllSetupCacheStruct[i].syspllctrl; | ||
1255 | pSetup->syspllndec = s_PllSetupCacheStruct[i].syspllndec; | ||
1256 | pSetup->syspllpdec = s_PllSetupCacheStruct[i].syspllpdec; | ||
1257 | pSetup->syspllssctrl[0] = s_PllSetupCacheStruct[i].syspllssctrl[0]; | ||
1258 | pSetup->syspllssctrl[1] = s_PllSetupCacheStruct[i].syspllssctrl[1]; | ||
1259 | retErr = kStatus_PLL_Success; | ||
1260 | break; | ||
1261 | } | ||
1262 | } | ||
1263 | |||
1264 | if (i < CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT) | ||
1265 | { | ||
1266 | return retErr; | ||
1267 | } | ||
1268 | #endif /* CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT */ | ||
1269 | |||
1270 | retErr = CLOCK_GetPllConfigInternal(finHz, foutHz, pSetup, useFeedbackDiv2, useSS); | ||
1271 | |||
1272 | #if (defined(CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT) && CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT) | ||
1273 | /* Cache the most recent calulation result into buffer. */ | ||
1274 | s_FinHzCache[s_PllSetupCacheIdx] = finHz; | ||
1275 | s_FoutHzCache[s_PllSetupCacheIdx] = foutHz; | ||
1276 | s_UseFeedbackDiv2Cache[s_PllSetupCacheIdx] = useFeedbackDiv2; | ||
1277 | s_UseSSCache[s_PllSetupCacheIdx] = useSS; | ||
1278 | |||
1279 | s_PllSetupCacheStruct[s_PllSetupCacheIdx].syspllctrl = pSetup->syspllctrl; | ||
1280 | s_PllSetupCacheStruct[s_PllSetupCacheIdx].syspllndec = pSetup->syspllndec; | ||
1281 | s_PllSetupCacheStruct[s_PllSetupCacheIdx].syspllpdec = pSetup->syspllpdec; | ||
1282 | s_PllSetupCacheStruct[s_PllSetupCacheIdx].syspllssctrl[0] = pSetup->syspllssctrl[0]; | ||
1283 | s_PllSetupCacheStruct[s_PllSetupCacheIdx].syspllssctrl[1] = pSetup->syspllssctrl[1]; | ||
1284 | /* Update the index for next available buffer. */ | ||
1285 | s_PllSetupCacheIdx = (s_PllSetupCacheIdx + 1U) % CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT; | ||
1286 | #endif /* CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT */ | ||
1287 | |||
1288 | return retErr; | ||
1289 | } | ||
1290 | |||
1291 | /* Update local PLL rate variable */ | ||
1292 | static void CLOCK_GetSystemPLLOutFromSetupUpdate(pll_setup_t *pSetup) | ||
1293 | { | ||
1294 | s_Pll_Freq = CLOCK_GetSystemPLLOutFromSetup(pSetup); | ||
1295 | } | ||
1296 | |||
1297 | /* Return System PLL input clock rate */ | ||
1298 | /*! brief Return System PLL input clock rate | ||
1299 | * return System PLL input clock rate | ||
1300 | */ | ||
1301 | uint32_t CLOCK_GetSystemPLLInClockRate(void) | ||
1302 | { | ||
1303 | uint32_t clkRate = 0U; | ||
1304 | |||
1305 | switch ((SYSCON->SYSPLLCLKSEL & SYSCON_SYSPLLCLKSEL_SEL_MASK)) | ||
1306 | { | ||
1307 | case 0x00U: | ||
1308 | clkRate = CLK_FRO_12MHZ; | ||
1309 | break; | ||
1310 | |||
1311 | case 0x01U: | ||
1312 | clkRate = CLOCK_GetExtClkFreq(); | ||
1313 | break; | ||
1314 | |||
1315 | case 0x02U: | ||
1316 | clkRate = CLOCK_GetWdtOscFreq(); | ||
1317 | break; | ||
1318 | |||
1319 | case 0x03U: | ||
1320 | clkRate = CLOCK_GetOsc32KFreq(); | ||
1321 | break; | ||
1322 | |||
1323 | default: | ||
1324 | clkRate = 0U; | ||
1325 | break; | ||
1326 | } | ||
1327 | |||
1328 | return clkRate; | ||
1329 | } | ||
1330 | |||
1331 | /* Return System PLL output clock rate from setup structure */ | ||
1332 | /*! brief Return System PLL output clock rate from setup structure | ||
1333 | * param pSetup : Pointer to a PLL setup structure | ||
1334 | * return System PLL output clock rate calculated from the setup structure | ||
1335 | */ | ||
1336 | uint32_t CLOCK_GetSystemPLLOutFromSetup(pll_setup_t *pSetup) | ||
1337 | { | ||
1338 | uint32_t prediv, postdiv, mMult, inPllRate; | ||
1339 | uint64_t workRate; | ||
1340 | |||
1341 | /* Get the input clock frequency of PLL. */ | ||
1342 | inPllRate = CLOCK_GetSystemPLLInClockRate(); | ||
1343 | |||
1344 | /* | ||
1345 | * If the PLL is bypassed, PLL would not be used and the output of PLL module would just be the input clock. | ||
1346 | */ | ||
1347 | if ((pSetup->syspllctrl & (SYSCON_SYSPLLCTRL_BYPASS_MASK)) == 0U) | ||
1348 | { | ||
1349 | /* PLL is not in bypass mode, get pre-divider, and M divider, post-divider. */ | ||
1350 | /* | ||
1351 | * 1. Pre-divider | ||
1352 | * Pre-divider is only available when the DIRECTI is disabled. | ||
1353 | */ | ||
1354 | if (0U == (pSetup->syspllctrl & SYSCON_SYSPLLCTRL_DIRECTI_MASK)) | ||
1355 | { | ||
1356 | prediv = findPllPreDiv(pSetup->syspllctrl, pSetup->syspllndec); | ||
1357 | } | ||
1358 | else | ||
1359 | { | ||
1360 | prediv = 1U; /* The pre-divider is bypassed. */ | ||
1361 | } | ||
1362 | /* Adjust input clock */ | ||
1363 | inPllRate = inPllRate / prediv; | ||
1364 | |||
1365 | /* | ||
1366 | * 2. M divider | ||
1367 | * If using the SS, use the multiplier. | ||
1368 | */ | ||
1369 | if ((pSetup->syspllssctrl[1] & (SYSCON_SYSPLLSSCTRL1_PD_MASK)) != 0UL) | ||
1370 | { | ||
1371 | /* MDEC used for rate */ | ||
1372 | mMult = findPllMMult(pSetup->syspllctrl, pSetup->syspllssctrl[0]); | ||
1373 | workRate = (uint64_t)inPllRate * (uint64_t)mMult; | ||
1374 | } | ||
1375 | else | ||
1376 | { | ||
1377 | uint64_t fract; | ||
1378 | |||
1379 | /* SS multipler used for rate */ | ||
1380 | mMult = (pSetup->syspllssctrl[1] & PLL_SSCG1_MD_INT_M) >> PLL_SSCG1_MD_INT_P; | ||
1381 | workRate = (uint64_t)inPllRate * (uint64_t)mMult; | ||
1382 | |||
1383 | /* Adjust by fractional */ | ||
1384 | fract = ((uint64_t)(pSetup->syspllssctrl[1]) & PLL_SSCG1_MD_FRACT_M) >> PLL_SSCG1_MD_FRACT_P; | ||
1385 | workRate = workRate + ((inPllRate * fract) / 0x800U); | ||
1386 | } | ||
1387 | |||
1388 | /* | ||
1389 | * 3. Post-divider | ||
1390 | * Post-divider is only available when the DIRECTO is disabled. | ||
1391 | */ | ||
1392 | if (0U == (pSetup->syspllctrl & SYSCON_SYSPLLCTRL_DIRECTO_MASK)) | ||
1393 | { | ||
1394 | postdiv = findPllPostDiv(pSetup->syspllctrl, pSetup->syspllpdec); | ||
1395 | } | ||
1396 | else | ||
1397 | { | ||
1398 | postdiv = 1U; /* The post-divider is bypassed. */ | ||
1399 | } | ||
1400 | workRate = workRate / ((uint64_t)postdiv); | ||
1401 | } | ||
1402 | else | ||
1403 | { | ||
1404 | /* In bypass mode */ | ||
1405 | workRate = (uint64_t)inPllRate; | ||
1406 | } | ||
1407 | |||
1408 | return (uint32_t)workRate; | ||
1409 | } | ||
1410 | |||
1411 | /* Set the current PLL Rate */ | ||
1412 | /*! brief Store the current PLL rate | ||
1413 | * param rate: Current rate of the PLL | ||
1414 | * return Nothing | ||
1415 | **/ | ||
1416 | void CLOCK_SetStoredPLLClockRate(uint32_t rate) | ||
1417 | { | ||
1418 | s_Pll_Freq = rate; | ||
1419 | } | ||
1420 | |||
1421 | /* Return System PLL output clock rate */ | ||
1422 | /*! brief Return System PLL output clock rate | ||
1423 | * param recompute : Forces a PLL rate recomputation if true | ||
1424 | * return System PLL output clock rate | ||
1425 | * note The PLL rate is cached in the driver in a variable as | ||
1426 | * the rate computation function can take some time to perform. It | ||
1427 | * is recommended to use 'false' with the 'recompute' parameter. | ||
1428 | */ | ||
1429 | uint32_t CLOCK_GetSystemPLLOutClockRate(bool recompute) | ||
1430 | { | ||
1431 | pll_setup_t Setup; | ||
1432 | uint32_t rate; | ||
1433 | |||
1434 | if ((recompute) || (s_Pll_Freq == 0U)) | ||
1435 | { | ||
1436 | Setup.syspllctrl = SYSCON->SYSPLLCTRL; | ||
1437 | Setup.syspllndec = SYSCON->SYSPLLNDEC; | ||
1438 | Setup.syspllpdec = SYSCON->SYSPLLPDEC; | ||
1439 | Setup.syspllssctrl[0] = SYSCON->SYSPLLSSCTRL0; | ||
1440 | Setup.syspllssctrl[1] = SYSCON->SYSPLLSSCTRL1; | ||
1441 | |||
1442 | CLOCK_GetSystemPLLOutFromSetupUpdate(&Setup); | ||
1443 | } | ||
1444 | |||
1445 | rate = s_Pll_Freq; | ||
1446 | |||
1447 | return rate; | ||
1448 | } | ||
1449 | |||
1450 | /* Set PLL output based on the passed PLL setup data */ | ||
1451 | /*! brief Set PLL output based on the passed PLL setup data | ||
1452 | * param pControl : Pointer to populated PLL control structure to generate setup with | ||
1453 | * param pSetup : Pointer to PLL setup structure to be filled | ||
1454 | * return PLL_ERROR_SUCCESS on success, or PLL setup error code | ||
1455 | * note Actual frequency for setup may vary from the desired frequency based on the | ||
1456 | * accuracy of input clocks, rounding, non-fractional PLL mode, etc. | ||
1457 | */ | ||
1458 | pll_error_t CLOCK_SetupPLLData(pll_config_t *pControl, pll_setup_t *pSetup) | ||
1459 | { | ||
1460 | uint32_t inRate; | ||
1461 | bool useSS = (bool)((pControl->flags & PLL_CONFIGFLAG_FORCENOFRACT) == 0U); | ||
1462 | bool useFbDiv2; | ||
1463 | |||
1464 | pll_error_t pllError; | ||
1465 | |||
1466 | /* Determine input rate for the PLL */ | ||
1467 | if ((pControl->flags & PLL_CONFIGFLAG_USEINRATE) != 0UL) | ||
1468 | { | ||
1469 | inRate = pControl->inputRate; | ||
1470 | } | ||
1471 | else | ||
1472 | { | ||
1473 | inRate = CLOCK_GetSystemPLLInClockRate(); | ||
1474 | } | ||
1475 | |||
1476 | if ((pSetup->flags & PLL_SETUPFLAG_USEFEEDBACKDIV2) != 0UL) | ||
1477 | { | ||
1478 | useFbDiv2 = true; | ||
1479 | } | ||
1480 | else | ||
1481 | { | ||
1482 | useFbDiv2 = false; | ||
1483 | } | ||
1484 | |||
1485 | /* PLL flag options */ | ||
1486 | pllError = CLOCK_GetPllConfig(inRate, pControl->desiredRate, pSetup, useFbDiv2, useSS); | ||
1487 | if ((useSS) && (pllError == kStatus_PLL_Success)) | ||
1488 | { | ||
1489 | /* If using SS mode, then some tweaks are made to the generated setup */ | ||
1490 | pSetup->syspllssctrl[1] |= (uint32_t)pControl->ss_mf | (uint32_t)pControl->ss_mr | (uint32_t)pControl->ss_mc; | ||
1491 | if (pControl->mfDither) | ||
1492 | { | ||
1493 | pSetup->syspllssctrl[1] |= (1UL << SYSCON_SYSPLLSSCTRL1_DITHER_SHIFT); | ||
1494 | } | ||
1495 | } | ||
1496 | |||
1497 | return pllError; | ||
1498 | } | ||
1499 | |||
1500 | /* Set PLL output from PLL setup structure */ | ||
1501 | /*! brief Set PLL output from PLL setup structure (precise frequency) | ||
1502 | * param pSetup : Pointer to populated PLL setup structure | ||
1503 | * param flagcfg : Flag configuration for PLL config structure | ||
1504 | * return PLL_ERROR_SUCCESS on success, or PLL setup error code | ||
1505 | * note This function will power off the PLL, setup the PLL with the | ||
1506 | * new setup data, and then optionally powerup the PLL, wait for PLL lock, | ||
1507 | * and adjust system voltages to the new PLL rate. The function will not | ||
1508 | * alter any source clocks (ie, main systen clock) that may use the PLL, | ||
1509 | * so these should be setup prior to and after exiting the function. | ||
1510 | */ | ||
1511 | pll_error_t CLOCK_SetupSystemPLLPrec(pll_setup_t *pSetup, uint32_t flagcfg) | ||
1512 | { | ||
1513 | /* Power off PLL during setup changes */ | ||
1514 | POWER_EnablePD(kPDRUNCFG_PD_SYS_PLL0); | ||
1515 | |||
1516 | pSetup->flags = flagcfg; | ||
1517 | |||
1518 | /* Write PLL setup data */ | ||
1519 | SYSCON->SYSPLLCTRL = pSetup->syspllctrl; | ||
1520 | SYSCON->SYSPLLNDEC = pSetup->syspllndec; | ||
1521 | SYSCON->SYSPLLNDEC = pSetup->syspllndec | (1UL << SYSCON_SYSPLLNDEC_NREQ_SHIFT); /* latch */ | ||
1522 | SYSCON->SYSPLLPDEC = pSetup->syspllpdec; | ||
1523 | SYSCON->SYSPLLPDEC = pSetup->syspllpdec | (1UL << SYSCON_SYSPLLPDEC_PREQ_SHIFT); /* latch */ | ||
1524 | SYSCON->SYSPLLSSCTRL0 = pSetup->syspllssctrl[0]; | ||
1525 | SYSCON->SYSPLLSSCTRL0 = pSetup->syspllssctrl[0] | (1UL << SYSCON_SYSPLLSSCTRL0_MREQ_SHIFT); /* latch */ | ||
1526 | SYSCON->SYSPLLSSCTRL1 = pSetup->syspllssctrl[1]; | ||
1527 | SYSCON->SYSPLLSSCTRL1 = pSetup->syspllssctrl[1] | (1UL << SYSCON_SYSPLLSSCTRL1_MDREQ_SHIFT); /* latch */ | ||
1528 | |||
1529 | /* Flags for lock or power on */ | ||
1530 | if ((pSetup->flags & (PLL_SETUPFLAG_POWERUP | PLL_SETUPFLAG_WAITLOCK)) != 0UL) | ||
1531 | { | ||
1532 | /* If turning the PLL back on, perform the following sequence to accelerate PLL lock */ | ||
1533 | uint32_t maxCCO = (1UL << 18U) | 0x5dd2U; /* CCO = 1.6Ghz + MDEC enabled*/ | ||
1534 | uint32_t curSSCTRL = SYSCON->SYSPLLSSCTRL0 & ~(1UL << 17U); | ||
1535 | |||
1536 | /* Initialize and power up PLL */ | ||
1537 | SYSCON->SYSPLLSSCTRL0 = maxCCO; | ||
1538 | POWER_DisablePD(kPDRUNCFG_PD_SYS_PLL0); | ||
1539 | |||
1540 | /* Set mreq to activate */ | ||
1541 | SYSCON->SYSPLLSSCTRL0 = maxCCO | (1UL << 17U); | ||
1542 | |||
1543 | /* Delay for 72 uSec @ 12Mhz */ | ||
1544 | SDK_DelayAtLeastUs(72U, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY); | ||
1545 | |||
1546 | /* clear mreq to prepare for restoring mreq */ | ||
1547 | SYSCON->SYSPLLSSCTRL0 = curSSCTRL; | ||
1548 | |||
1549 | /* set original value back and activate */ | ||
1550 | SYSCON->SYSPLLSSCTRL0 = curSSCTRL | (1UL << 17U); | ||
1551 | |||
1552 | /* Enable peripheral states by setting low */ | ||
1553 | POWER_DisablePD(kPDRUNCFG_PD_SYS_PLL0); | ||
1554 | } | ||
1555 | if ((pSetup->flags & PLL_SETUPFLAG_WAITLOCK) != 0UL) | ||
1556 | { | ||
1557 | while (CLOCK_IsSystemPLLLocked() == false) | ||
1558 | { | ||
1559 | } | ||
1560 | } | ||
1561 | |||
1562 | /* Update current programmed PLL rate var */ | ||
1563 | CLOCK_GetSystemPLLOutFromSetupUpdate(pSetup); | ||
1564 | |||
1565 | /* System voltage adjustment, occurs prior to setting main system clock */ | ||
1566 | if ((pSetup->flags & PLL_SETUPFLAG_ADGVOLT) != 0UL) | ||
1567 | { | ||
1568 | POWER_SetVoltageForFreq(s_Pll_Freq); | ||
1569 | } | ||
1570 | |||
1571 | return kStatus_PLL_Success; | ||
1572 | } | ||
1573 | |||
1574 | /* Setup PLL Frequency from pre-calculated value */ | ||
1575 | /** | ||
1576 | * brief Set PLL output from PLL setup structure (precise frequency) | ||
1577 | * param pSetup : Pointer to populated PLL setup structure | ||
1578 | * return kStatus_PLL_Success on success, or PLL setup error code | ||
1579 | * note This function will power off the PLL, setup the PLL with the | ||
1580 | * new setup data, and then optionally powerup the PLL, wait for PLL lock, | ||
1581 | * and adjust system voltages to the new PLL rate. The function will not | ||
1582 | * alter any source clocks (ie, main systen clock) that may use the PLL, | ||
1583 | * so these should be setup prior to and after exiting the function. | ||
1584 | */ | ||
1585 | pll_error_t CLOCK_SetPLLFreq(const pll_setup_t *pSetup) | ||
1586 | { | ||
1587 | /* Power off PLL during setup changes */ | ||
1588 | POWER_EnablePD(kPDRUNCFG_PD_SYS_PLL0); | ||
1589 | |||
1590 | /* Write PLL setup data */ | ||
1591 | SYSCON->SYSPLLCTRL = pSetup->syspllctrl; | ||
1592 | SYSCON->SYSPLLNDEC = pSetup->syspllndec; | ||
1593 | SYSCON->SYSPLLNDEC = pSetup->syspllndec | (1UL << SYSCON_SYSPLLNDEC_NREQ_SHIFT); /* latch */ | ||
1594 | SYSCON->SYSPLLPDEC = pSetup->syspllpdec; | ||
1595 | SYSCON->SYSPLLPDEC = pSetup->syspllpdec | (1UL << SYSCON_SYSPLLPDEC_PREQ_SHIFT); /* latch */ | ||
1596 | SYSCON->SYSPLLSSCTRL0 = pSetup->syspllssctrl[0]; | ||
1597 | SYSCON->SYSPLLSSCTRL0 = pSetup->syspllssctrl[0] | (1UL << SYSCON_SYSPLLSSCTRL0_MREQ_SHIFT); /* latch */ | ||
1598 | SYSCON->SYSPLLSSCTRL1 = pSetup->syspllssctrl[1]; | ||
1599 | SYSCON->SYSPLLSSCTRL1 = pSetup->syspllssctrl[1] | (1UL << SYSCON_SYSPLLSSCTRL1_MDREQ_SHIFT); /* latch */ | ||
1600 | |||
1601 | /* Flags for lock or power on */ | ||
1602 | if ((pSetup->flags & (PLL_SETUPFLAG_POWERUP | PLL_SETUPFLAG_WAITLOCK)) != 0UL) | ||
1603 | { | ||
1604 | /* If turning the PLL back on, perform the following sequence to accelerate PLL lock */ | ||
1605 | uint32_t maxCCO = (1UL << 18U) | 0x5dd2U; /* CCO = 1.6Ghz + MDEC enabled*/ | ||
1606 | uint32_t curSSCTRL = SYSCON->SYSPLLSSCTRL0 & ~(1UL << 17U); | ||
1607 | |||
1608 | /* Initialize and power up PLL */ | ||
1609 | SYSCON->SYSPLLSSCTRL0 = maxCCO; | ||
1610 | POWER_DisablePD(kPDRUNCFG_PD_SYS_PLL0); | ||
1611 | |||
1612 | /* Set mreq to activate */ | ||
1613 | SYSCON->SYSPLLSSCTRL0 = maxCCO | (1UL << 17U); | ||
1614 | |||
1615 | /* Delay for 72 uSec @ 12Mhz */ | ||
1616 | SDK_DelayAtLeastUs(72U, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY); | ||
1617 | |||
1618 | /* clear mreq to prepare for restoring mreq */ | ||
1619 | SYSCON->SYSPLLSSCTRL0 = curSSCTRL; | ||
1620 | |||
1621 | /* set original value back and activate */ | ||
1622 | SYSCON->SYSPLLSSCTRL0 = curSSCTRL | (1UL << 17U); | ||
1623 | |||
1624 | /* Enable peripheral states by setting low */ | ||
1625 | POWER_DisablePD(kPDRUNCFG_PD_SYS_PLL0); | ||
1626 | } | ||
1627 | if ((pSetup->flags & PLL_SETUPFLAG_WAITLOCK) != 0UL) | ||
1628 | { | ||
1629 | while (CLOCK_IsSystemPLLLocked() == false) | ||
1630 | { | ||
1631 | } | ||
1632 | } | ||
1633 | |||
1634 | /* Update current programmed PLL rate var */ | ||
1635 | s_Pll_Freq = pSetup->pllRate; | ||
1636 | |||
1637 | return kStatus_PLL_Success; | ||
1638 | } | ||
1639 | |||
1640 | /* Set System PLL clock based on the input frequency and multiplier */ | ||
1641 | /*! brief Set PLL output based on the multiplier and input frequency | ||
1642 | * param multiply_by : multiplier | ||
1643 | * param input_freq : Clock input frequency of the PLL | ||
1644 | * return Nothing | ||
1645 | * note Unlike the Chip_Clock_SetupSystemPLLPrec() function, this | ||
1646 | * function does not disable or enable PLL power, wait for PLL lock, | ||
1647 | * or adjust system voltages. These must be done in the application. | ||
1648 | * The function will not alter any source clocks (ie, main systen clock) | ||
1649 | * that may use the PLL, so these should be setup prior to and after | ||
1650 | * exiting the function. | ||
1651 | */ | ||
1652 | void CLOCK_SetupSystemPLLMult(uint32_t multiply_by, uint32_t input_freq) | ||
1653 | { | ||
1654 | uint32_t cco_freq = input_freq * multiply_by; | ||
1655 | uint32_t pdec = 1U; | ||
1656 | uint32_t selr; | ||
1657 | uint32_t seli; | ||
1658 | uint32_t selp; | ||
1659 | uint32_t mdec, ndec; | ||
1660 | |||
1661 | uint32_t directo = SYSCON_SYSPLLCTRL_DIRECTO(1); | ||
1662 | |||
1663 | while (cco_freq < 75000000U) | ||
1664 | { | ||
1665 | multiply_by <<= 1U; /* double value in each iteration */ | ||
1666 | pdec <<= 1U; /* correspondingly double pdec to cancel effect of double msel */ | ||
1667 | cco_freq = input_freq * multiply_by; | ||
1668 | } | ||
1669 | selr = 0U; | ||
1670 | if (multiply_by < 60U) | ||
1671 | { | ||
1672 | seli = (multiply_by & 0x3cU) + 4U; | ||
1673 | selp = (multiply_by >> 1U) + 1U; | ||
1674 | } | ||
1675 | else | ||
1676 | { | ||
1677 | selp = 31U; | ||
1678 | if (multiply_by > 16384U) | ||
1679 | { | ||
1680 | seli = 1U; | ||
1681 | } | ||
1682 | else if (multiply_by > 8192U) | ||
1683 | { | ||
1684 | seli = 2U; | ||
1685 | } | ||
1686 | else if (multiply_by > 2048U) | ||
1687 | { | ||
1688 | seli = 4U; | ||
1689 | } | ||
1690 | else if (multiply_by >= 501U) | ||
1691 | { | ||
1692 | seli = 8U; | ||
1693 | } | ||
1694 | else | ||
1695 | { | ||
1696 | seli = 4U * (1024U / (multiply_by + 9U)); | ||
1697 | } | ||
1698 | } | ||
1699 | |||
1700 | if (pdec > 1U) | ||
1701 | { | ||
1702 | directo = 0U; /* use post divider */ | ||
1703 | pdec = pdec / 2U; /* Account for minus 1 encoding */ | ||
1704 | /* Translate P value */ | ||
1705 | switch (pdec) | ||
1706 | { | ||
1707 | case 1U: | ||
1708 | pdec = 0x62U; /* 1 * 2 */ | ||
1709 | break; | ||
1710 | case 2U: | ||
1711 | pdec = 0x42U; /* 2 * 2 */ | ||
1712 | break; | ||
1713 | case 4U: | ||
1714 | pdec = 0x02U; /* 4 * 2 */ | ||
1715 | break; | ||
1716 | case 8U: | ||
1717 | pdec = 0x0bU; /* 8 * 2 */ | ||
1718 | break; | ||
1719 | case 16U: | ||
1720 | pdec = 0x11U; /* 16 * 2 */ | ||
1721 | break; | ||
1722 | case 32U: | ||
1723 | pdec = 0x08U; /* 32 * 2 */ | ||
1724 | break; | ||
1725 | default: | ||
1726 | pdec = 0x08U; | ||
1727 | break; | ||
1728 | } | ||
1729 | } | ||
1730 | |||
1731 | mdec = PLL_SSCG0_MDEC_VAL_SET(pllEncodeM(multiply_by)); | ||
1732 | ndec = 0x302U; /* pre divide by 1 (hardcoded) */ | ||
1733 | |||
1734 | SYSCON->SYSPLLCTRL = SYSCON_SYSPLLCTRL_BANDSEL(1) | directo | SYSCON_SYSPLLCTRL_BYPASSCCODIV2(1) | | ||
1735 | (selr << SYSCON_SYSPLLCTRL_SELR_SHIFT) | (seli << SYSCON_SYSPLLCTRL_SELI_SHIFT) | | ||
1736 | (selp << SYSCON_SYSPLLCTRL_SELP_SHIFT); | ||
1737 | SYSCON->SYSPLLPDEC = pdec | (1UL << 7U); /* set Pdec value and assert preq */ | ||
1738 | SYSCON->SYSPLLNDEC = ndec | (1UL << 10U); /* set Pdec value and assert preq */ | ||
1739 | SYSCON->SYSPLLSSCTRL0 = | ||
1740 | (1UL << 18U) | (1UL << 17U) | mdec; /* select non sscg MDEC value, assert mreq and select mdec value */ | ||
1741 | } | ||
1742 | bool CLOCK_EnableUsbfs0Clock(clock_usb_src_t src, uint32_t freq) | ||
1743 | { | ||
1744 | bool ret = true; | ||
1745 | |||
1746 | CLOCK_DisableClock(kCLOCK_Usbd0); | ||
1747 | |||
1748 | if (kCLOCK_UsbSrcFro == src) | ||
1749 | { | ||
1750 | switch (freq) | ||
1751 | { | ||
1752 | case 96000000U: | ||
1753 | CLOCK_SetClkDiv(kCLOCK_DivUsbClk, 2, false); /*!< Div by 2 to get 48MHz, no divider reset */ | ||
1754 | break; | ||
1755 | case 48000000U: | ||
1756 | CLOCK_SetClkDiv(kCLOCK_DivUsbClk, 1, false); /*!< Div by 1 to get 48MHz, no divider reset */ | ||
1757 | break; | ||
1758 | default: | ||
1759 | ret = false; | ||
1760 | break; | ||
1761 | } | ||
1762 | /* Turn ON FRO HF and let it adjust TRIM value based on USB SOF */ | ||
1763 | SYSCON->FROCTRL = (SYSCON->FROCTRL & ~((0x01UL << 15U) | (0xFUL << 26U))) | SYSCON_FROCTRL_HSPDCLK_MASK | | ||
1764 | SYSCON_FROCTRL_USBCLKADJ_MASK; | ||
1765 | /* select FRO 96 or 48 MHz */ | ||
1766 | CLOCK_AttachClk(kFRO_HF_to_USB_CLK); | ||
1767 | } | ||
1768 | else | ||
1769 | { | ||
1770 | /*TODO , we only implement FRO as usb clock source*/ | ||
1771 | ret = false; | ||
1772 | } | ||
1773 | |||
1774 | CLOCK_EnableClock(kCLOCK_Usbd0); | ||
1775 | |||
1776 | return ret; | ||
1777 | } | ||