1 /*
2  * Copyright 2017-2019 NXP
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include "fsl_clock.h"
9 #include "rom_api.h"
10 /*******************************************************************************
11  * Definitions
12  ******************************************************************************/
13 /* Component ID definition, used by tools. */
14 #ifndef FSL_COMPONENT_ID
15 #define FSL_COMPONENT_ID "platform.drivers.clock"
16 #endif
17 #define SYSPLL_MIN_INPUT_FREQ_HZ (10000000U)   /*!<  Minimum PLL input rate */
18 #define SYSPLL_MAX_INPUT_FREQ_HZ (25000000U)   /*!<  Maximum PLL input rate */
19 #define SYSPLL_MAX_OUTPUT_FREQ_HZ (100000000U) /*!< Maximum PLL output rate */
20 #define SYSOSC_BOUNDARY_FREQ_HZ (15000000U)    /*!< boundary frequency value */
21 
22 /* External clock rate.
23  * Either external clk in rate or system oscillator frequency.
24  */
25 volatile uint32_t g_Ext_Clk_Freq = 0U;
26 /** watch dog oscillator rate in Hz.*/
27 volatile uint32_t g_Wdt_Osc_Freq = 0U;
28 /** For oscillator rate in Hz */
29 volatile uint32_t g_Fro_Osc_Freq = 0U;
30 
31 /*******************************************************************************
32  * Variables
33  ******************************************************************************/
34 
35 /*******************************************************************************
36  * Prototypes
37  ******************************************************************************/
38 
39 /*
40  * @brief   Get
41  input clock frequency.
42  * @param fractional clock register base address.
43  * @return  input clock frequency.
44  */
45 static uint32_t CLOCK_GetFRGInputClkFreq(uint32_t *base);
46 
47 /*
48  * @brief Update clock source.
49  * @param base clock register base address.
50  * @param mask clock source update enable bit mask value.
51  */
52 static void CLOCK_UpdateClkSrc(volatile uint32_t *base, uint32_t mask);
53 
54 /*******************************************************************************
55  * Code
56  ******************************************************************************/
CLOCK_GetFRGInputClkFreq(uint32_t * base)57 static uint32_t CLOCK_GetFRGInputClkFreq(uint32_t *base)
58 {
59     uint32_t sel = CLK_FRG_SEL_REG_MAP(base) & SYSCON_FRG_FRGCLKSEL_SEL_MASK;
60     uint32_t freq;
61 
62     if (sel == 0U)
63     {
64         freq = CLOCK_GetFroFreq();
65     }
66     else
67     {
68         freq = CLOCK_GetMainClkFreq();
69     }
70     return freq;
71 }
72 
73 /*! brief Set FRG0 output frequency.
74  * param freq, target output frequency,freq < input and (input / freq) < 2 should be satisfy.
75  * retval true - successfully, false - input argument is invalid.
76  *
77  */
CLOCK_SetFRGClkFreq(uint32_t freq)78 bool CLOCK_SetFRGClkFreq(uint32_t freq)
79 {
80     assert(freq);
81 
82     uint32_t *base = (uint32_t *)(&SYSCON->FRG);
83     uint32_t input = CLOCK_GetFRGInputClkFreq(base);
84     uint32_t mul;
85 
86     if ((freq > input) || (input / freq >= 2U))
87     {
88         return false;
89     }
90 
91     mul = (uint32_t)(((uint64_t)((uint64_t)input - freq) << 8U) / ((uint64_t)freq));
92 
93     CLK_FRG_DIV_REG_MAP(base) = SYSCON_FRG_FRGDIV_DIV_MASK;
94     CLK_FRG_MUL_REG_MAP(base) = SYSCON_FRG_FRGMULT_MULT(mul);
95 
96     return true;
97 }
98 
CLOCK_UpdateClkSrc(volatile uint32_t * base,uint32_t mask)99 static void CLOCK_UpdateClkSrc(volatile uint32_t *base, uint32_t mask)
100 {
101     assert(base);
102 
103     *base &= ~mask;
104     *base |= mask;
105     while ((*base & mask) == 0U)
106     {
107     }
108 }
109 
110 /*! brief  Return Frequency of FRG0 Clock.
111  *  return Frequency of FRG0 Clock.
112  */
CLOCK_GetFRGClkFreq(void)113 uint32_t CLOCK_GetFRGClkFreq(void)
114 {
115     uint32_t temp;
116 
117     temp = CLOCK_GetFRGInputClkFreq((uint32_t *)(&SYSCON->FRG)) << 8U;
118     return (uint32_t)(((uint64_t)(temp)) / (((uint64_t)SYSCON->FRG->FRGMULT & SYSCON_FRG_FRGMULT_MULT_MASK) + 256ULL));
119 }
120 
121 /*! brief  Return Frequency of Main Clock.
122  *  return Frequency of Main Clock.
123  */
CLOCK_GetMainClkFreq(void)124 uint32_t CLOCK_GetMainClkFreq(void)
125 {
126     uint32_t freq = 0U;
127 
128     switch (SYSCON->MAINCLKSEL)
129     {
130         case 0U:
131             freq = CLOCK_GetFroFreq();
132             break;
133 
134         case 1U:
135             freq = CLOCK_GetExtClkFreq();
136             break;
137 
138         case 2U:
139             freq = CLOCK_GetLPOscFreq();
140             break;
141 
142         case 3U:
143             freq = CLOCK_GetFroFreq() >> 1U;
144             break;
145         default:
146             assert(false);
147             break;
148     }
149 
150     return freq;
151 }
152 
153 /*! brief  Return Frequency of FRO.
154  *  return Frequency of FRO.
155  */
CLOCK_GetFroFreq(void)156 uint32_t CLOCK_GetFroFreq(void)
157 {
158     return g_Fro_Osc_Freq / 2U;
159 }
160 
161 /*! brief  Return Frequency of ClockOut
162  *  return Frequency of ClockOut
163  */
CLOCK_GetClockOutClkFreq(void)164 uint32_t CLOCK_GetClockOutClkFreq(void)
165 {
166     uint32_t div = SYSCON->CLKOUTDIV & 0xffU, freq = 0U;
167 
168     switch (SYSCON->CLKOUTSEL)
169     {
170         case 0U:
171             freq = CLOCK_GetFroFreq();
172             break;
173 
174         case 1U:
175             freq = CLOCK_GetMainClkFreq();
176             break;
177 
178         case 3U:
179             freq = CLOCK_GetExtClkFreq();
180             break;
181 
182         case 4U:
183             freq = CLOCK_GetLPOscFreq();
184             break;
185 
186         default:
187             assert(false);
188             break;
189     }
190 
191     return div == 0U ? 0U : (freq / div);
192 }
193 
194 /*! brief  Return Frequency of UART0
195  *  return Frequency of UART0
196  */
CLOCK_GetUart0ClkFreq(void)197 uint32_t CLOCK_GetUart0ClkFreq(void)
198 {
199     uint32_t freq = 0U;
200 
201     switch (SYSCON->UART0CLKSEL)
202     {
203         case 0U:
204             freq = CLOCK_GetFroFreq();
205             break;
206         case 1U:
207             freq = CLOCK_GetMainClkFreq();
208             break;
209         case 2U:
210             freq = CLOCK_GetFRGClkFreq();
211             break;
212         case 4U:
213             freq = CLOCK_GetFroFreq() >> 1U;
214             break;
215 
216         default:
217             assert(false);
218             break;
219     }
220 
221     return freq;
222 }
223 
224 /*! brief  Return Frequency of UART1
225  *  return Frequency of UART1
226  */
CLOCK_GetUart1ClkFreq(void)227 uint32_t CLOCK_GetUart1ClkFreq(void)
228 {
229     uint32_t freq = 0U;
230 
231     switch (SYSCON->UART1CLKSEL)
232     {
233         case 0U:
234             freq = CLOCK_GetFroFreq();
235             break;
236         case 1U:
237             freq = CLOCK_GetMainClkFreq();
238             break;
239         case 2U:
240             freq = CLOCK_GetFRGClkFreq();
241             break;
242         case 4U:
243             freq = CLOCK_GetFroFreq() >> 1U;
244             break;
245 
246         default:
247             assert(false);
248             break;
249     }
250 
251     return freq;
252 }
253 
254 /*! brief	Return Frequency of selected clock
255  *  return	Frequency of selected clock
256  */
CLOCK_GetFreq(clock_name_t clockName)257 uint32_t CLOCK_GetFreq(clock_name_t clockName)
258 {
259     uint32_t freq;
260 
261     switch (clockName)
262     {
263         case kCLOCK_CoreSysClk:
264             freq = CLOCK_GetCoreSysClkFreq();
265             break;
266         case kCLOCK_MainClk:
267             freq = CLOCK_GetMainClkFreq();
268             break;
269         case kCLOCK_Fro:
270             freq = CLOCK_GetFroFreq();
271             break;
272         case kCLOCK_FroDiv:
273             freq = CLOCK_GetFroFreq() >> 1U;
274             break;
275         case kCLOCK_ExtClk:
276             freq = CLOCK_GetExtClkFreq();
277             break;
278         case kCLOCK_LPOsc:
279             freq = CLOCK_GetLPOscFreq();
280             break;
281         case kCLOCK_Frg:
282             freq = CLOCK_GetFRGClkFreq();
283             break;
284 
285         default:
286             freq = 0U;
287             break;
288     }
289 
290     return freq;
291 }
292 
293 /*! brief  Init external CLK IN, select the CLKIN as the external clock source.
294  * param clkInFreq external clock in frequency.
295  */
CLOCK_InitExtClkin(uint32_t clkInFreq)296 void CLOCK_InitExtClkin(uint32_t clkInFreq)
297 {
298     /* remove the pull up and pull down resistors in the IOCON */
299     IOCON->PIO[IOCON_INDEX_PIO0_1] &= ~IOCON_PIO_MODE_MASK;
300     /* enable the 1 bit functions for CLKIN */
301     SWM0->PINENABLE0 &= ~SWM_PINENABLE0_CLKIN_MASK;
302     /* record the external clock rate */
303     g_Ext_Clk_Freq = clkInFreq;
304 }
305 
306 /*! brief  Set main clock reference source.
307  * param src, reference clock_main_clk_src_t to set the main clock source.
308  */
CLOCK_SetMainClkSrc(clock_main_clk_src_t src)309 void CLOCK_SetMainClkSrc(clock_main_clk_src_t src)
310 {
311     uint32_t mainMux = CLK_MAIN_CLK_MUX_GET_MUX(src), mainPreMux = CLK_MAIN_CLK_MUX_GET_PRE_MUX(src);
312 
313     if (((SYSCON->MAINCLKSEL & SYSCON_MAINCLKSEL_SEL_MASK) != mainPreMux) && (mainMux == 0U))
314     {
315         SYSCON->MAINCLKSEL = (SYSCON->MAINCLKSEL & (~SYSCON_MAINCLKSEL_SEL_MASK)) | SYSCON_MAINCLKSEL_SEL(mainPreMux);
316         CLOCK_UpdateClkSrc((volatile uint32_t *)(&(SYSCON->MAINCLKUEN)), SYSCON_MAINCLKUEN_ENA_MASK);
317     }
318 }
319 
320 /*! brief Set FRO oscillator output frequency.
321  *  Initialize the FRO clock to given frequency (18, 24 or 30 MHz).
322  * param freq, please reference clock_fro_osc_freq_t definition, frequency must be one of 18000, 24000 or 30000 KHz.
323  *
324  */
CLOCK_SetFroOscFreq(clock_fro_osc_freq_t freq)325 void CLOCK_SetFroOscFreq(clock_fro_osc_freq_t freq)
326 {
327     g_Fro_Osc_Freq = ((uint32_t)freq) * 1000U;
328     LPC_PWRD_API->set_fro_frequency((uint32_t)freq);
329 }
330