1 /*
2  * Copyright (c) 2016, Freescale Semiconductor, Inc.
3  * Copyright 2016-2017 NXP
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include "fsl_common.h"
9 #include "fsl_msmc.h"
10 #include "clock_config.h"
11 
12 /*******************************************************************************
13  * Variables
14  ******************************************************************************/
15 /* System clock frequency. */
16 extern uint32_t SystemCoreClock;
17 
18 /*******************************************************************************
19  ************************ BOARD_InitBootClocks function ************************
20  ******************************************************************************/
BOARD_InitBootClocks(void)21 void BOARD_InitBootClocks(void)
22 {
23     BOARD_BootClockRUN();
24 }
25 /*
26  * SYSOSC clock ROM setting.
27  * SYSOSC clock         : 24MHz
28  * SOSCDIV1_CLK output  : 0MHz (async platform clock)
29  * SOSCDIV2_CLK output  : 0MHz (async bus clock)
30  * SOSCDIV3_CLK output  : 0MHz (async slow clock)
31  */
32 const scg_sosc_config_t g_scgSysOscConfig = {.freq        = BOARD_XTAL0_CLK_HZ,
33                                              .enableMode  = kSCG_SysOscEnable,
34                                              .monitorMode = kSCG_SysOscMonitorDisable,
35                                              .div1        = kSCG_AsyncClkDisable,
36                                              .div2        = kSCG_AsyncClkDisable,
37                                              .div3        = kSCG_AsyncClkDisable,
38                                              .workMode    = kSCG_SysOscModeOscLowPower};
39 
40 /*
41  * SIRC clock ROM setting.
42  * SIRC clock           : 16MHz
43  * SIRCDIV1_CLK output  : 0MHz  (async platform clock)
44  * SIRCDIV2_CLK output  : 0MHz  (async bus clock)
45  * SIRCDIV3_CLK output  : 0MHz  (async slow clock)
46  */
47 const scg_sirc_config_t g_scgSircConfig = {.enableMode = kSCG_SircEnable | kSCG_SircEnableInLowPower,
48                                            .div1       = kSCG_AsyncClkDisable,
49                                            .div2       = kSCG_AsyncClkDisable,
50                                            .div3       = kSCG_AsyncClkDisable,
51                                            .range      = kSCG_SircRangeHigh};
52 
53 /*
54  * FIRC clock ROM setting.
55  * FIRC clock           : 48MHz
56  * FIRCDIV1_CLK output  : 0MHz (async platform clock)
57  * FIRCDIV2_CLK output  : 0MHz (async bus clock)
58  * FIRCDIV3_CLK output  : 0MHz (async slow clock)
59  */
60 const scg_firc_config_t g_scgFircConfig = {.enableMode = kSCG_FircEnable,
61                                            .div1       = kSCG_AsyncClkDisable,
62                                            .div2       = kSCG_AsyncClkDisable,
63                                            .div3       = kSCG_AsyncClkDisable,
64                                            .range      = kSCG_FircRange48M,
65                                            .trimConfig = NULL};
66 
67 /*
68  * SYSPLL clock setting.
69  * SYSPLL clock PFD0      : 480 * 18 / 22 = 392MHz
70  * SYSPLLDIV1_CLK output  : 392MHz (async platform clock)
71  * SYSPLLDIV2_CLK output  : 196MHz (async bus clock)
72  * SYSPLLDIV3_CLK output  : 0MHz   (async slow clock)
73  * PFD0 selected for sync system clock
74  */
75 const scg_spll_config_t g_scgSysPllConfig = {.enableMode    = kSCG_SysPllEnable,
76                                              .div1          = kSCG_AsyncClkDivBy1,
77                                              .div2          = kSCG_AsyncClkDivBy2,
78                                              .div3          = kSCG_AsyncClkDisable,
79                                              .src           = kSCG_SysPllSrcSysOsc,
80                                              .isPfdSelected = true,
81                                              .prediv        = 0U,
82                                              .pfdClkout     = kSCG_SysPllPfd0Clk,
83                                              .mult          = 3U}; /* x20 */
84 
85 /*
86  * AUXPLL clock setting.
87  * AUXPLL clock           : 540.672MHz / 88 = 6.144MHz
88  * AUXPLLDIV1_CLK output  : 6.144MHz (async platform clock)
89  * AUXPLLDIV2_CLK output  : 6.144MHz (async bus clock)
90  * AUXPLLDIV3_CLK output  : 0MHz     (async slow clock)
91  */
92 const scg_apll_config_t g_scgAuxPllConfig = {.enableMode    = kSCG_AuxPllEnable,
93                                              .div1          = kSCG_AsyncClkDivBy1,
94                                              .div2          = kSCG_AsyncClkDivBy1,
95                                              .div3          = kSCG_AsyncClkDisable,
96                                              .src           = kSCG_AuxPllSrcSysOsc,
97                                              .isPfdSelected = false,
98                                              .prediv        = 0U,
99                                              .pfdClkout     = kSCG_AuxPllPfd0Clk,
100                                              .mult          = 22U,
101                                              .pllPostdiv1   = kSCG_SysClkDivBy11,
102                                              .pllPostdiv2   = kSCG_SysClkDivBy8,
103                                              .num           = 528000U,
104                                              .denom         = 1000000U}; /* 24 x 22.528 = 540.672MHz */
105 
106 /*
107  * Select SIRC as system clock source, before configuring other clock sources.
108  * Clock source   : SIRC
109  * Core clock     : 16MHz
110  * Platform clock : 16MHz
111  * Bus clock      : 16MHz
112  * Slow clock     : 8MHz
113  */
114 const scg_sys_clk_config_t g_sysClkConfigSircSource = {
115     .divCore = kSCG_SysClkDivBy1, /* Core clock divider. */
116     .divPlat = kSCG_SysClkDivBy1, /* Platform clock divider. */
117     .divBus  = kSCG_SysClkDivBy1, /* Bus clock divider. */
118     .divSlow = kSCG_SysClkDivBy2, /* Slow clock divider. */
119     .src     = kSCG_SysClkSrcSirc /* System clock source. */
120 };
121 
122 /*
123  * System clock source and divider in Normal RUN mode.
124  * Clock source   : SYSPLL PFD0 392MHz
125  * Core clock     : 98MHz
126  * Platform clock : 98MHz
127  * Bus clock      : 49MHz
128  * Slow clock     : 24.5MHz
129  */
130 const scg_sys_clk_config_t g_sysClkConfigNormalRun = {
131     .divCore = kSCG_SysClkDivBy4,   /* Core clock divider. */
132     .divPlat = kSCG_SysClkDivBy1,   /* Platform clock divider. */
133     .divBus  = kSCG_SysClkDivBy2,   /* Bus clock divider. */
134     .divSlow = kSCG_SysClkDivBy4,   /* Slow clock divider. */
135     .src     = kSCG_SysClkSrcSysPll /* System clock source. */
136 };
137 
138 /*
139  * System clock source and divider in HSRUN mode.
140  * Clock source   : SYSPLL PFD0 392MHz
141  * Core clock     : 196MHz
142  * Platform clock : 196MHz
143  * Bus clock      : 98MHz
144  * Slow clock     : 49MHz
145  */
146 const scg_sys_clk_config_t g_sysClkConfigHsrun = {
147     .divCore = kSCG_SysClkDivBy2,   /* Core clock divider. */
148     .divPlat = kSCG_SysClkDivBy1,   /* Platform clock divider. */
149     .divBus  = kSCG_SysClkDivBy2,   /* Bus clock divider. */
150     .divSlow = kSCG_SysClkDivBy4,   /* Slow clock divider. */
151     .src     = kSCG_SysClkSrcSysPll /* System clock source. */
152 };
153 
154 /*
155  * System clock source and divider in VLPR mode.
156  * Clock source   : SIRC
157  * Core clock     : 16MHz
158  * Platform clock : 16MHz
159  * Bus clock      : 16MHz
160  * Slow clock     : 8MHz
161  */
162 const scg_sys_clk_config_t g_sysClkConfigVlpr = {
163     .divCore = kSCG_SysClkDivBy1, /* Core clock divider. */
164     .divPlat = kSCG_SysClkDivBy1, /* Platform clock divider. */
165     .divBus  = kSCG_SysClkDivBy1, /* Bus clock divider. */
166     .divSlow = kSCG_SysClkDivBy2, /* Slow clock divider. */
167     .src     = kSCG_SysClkSrcSirc /* System clock source. */
168 };
169 
170 /*******************************************************************************
171  * Code
172  ******************************************************************************/
173 typedef void (*BOARD_SetRunModeFunc)(
174     SCG_Type *scg, uint32_t scgRunConfig, QuadSPI_Type *qspi, clock_ip_name_t qspiClock, uint32_t qspiClockConfig);
175 #if 0
176 void BOARD_SetRunMode(SCG_Type *scg, uint32_t scgRunConfig, QuadSPI_Type *qspi,
177                       clock_ip_name_t qspiClock, uint32_t qspiClockConfig)
178 {
179     int32_t i;
180 
181     scg->RCCR = scgRunConfig;
182 
183     /* Wait for clock source switch finished. */
184     while ((scg->CSR & SCG_CSR_SCS_MASK) != (scgRunConfig & SCG_CSR_SCS_MASK))
185     {
186     }
187 
188     if (qspi)
189     {
190         volatile uint32_t *pcc = (volatile uint32_t *)qspiClock;
191 
192         /* Make sure QSPI clock is enabled */
193         *pcc |= PCC1_PCC_QSPI_OTFAD_CGC_MASK;
194         /* Wait until QSPI is not busy */
195         while (qspi->SR & QuadSPI_SR_BUSY_MASK)
196         {
197         }
198         /* Make sure module is enabled when reset */
199         qspi->MCR &= ~QuadSPI_MCR_MDIS_MASK;
200         qspi->MCR |= QuadSPI_MCR_SWRSTHD_MASK | QuadSPI_MCR_SWRSTSD_MASK;
201         /* Wait enough cycles until the ahb domain and serial flash domain are reset */
202         for (i = 0; i < 200; i++)
203         {
204             qspi->SR;
205         }
206         /* Disable module during the reset procedure */
207         qspi->MCR |= QuadSPI_MCR_MDIS_MASK;
208         /* Clear the reset bits. */
209         qspi->MCR &= ~(QuadSPI_MCR_SWRSTHD_MASK | QuadSPI_MCR_SWRSTSD_MASK);
210 
211         *pcc = 0; /* Disable clock before changing clock source */
212         *pcc = qspiClockConfig;
213         /* Re-enable QSPI module */
214         qspi->MCR &= ~QuadSPI_MCR_MDIS_MASK;
215     }
216 }
217 #endif
218 /* The code array is built from above BOARD_SetRunMode() prototype */
219 uint16_t BOARD_SetRunModeCode[] = {
220     0xb430,         /* push    {r4, r5} */
221     0x6141,         /* str     r1, [r0, #20] */
222     0xf001, 0x6570, /* and.w   r5, r1, #251658240    ; 0xf000000 */
223     0x6904,         /* ldr     r4, [r0, #16] */
224     0xf004, 0x6470, /* and.w   r4, r4, #251658240    ; 0xf000000 */
225     0x42ac,         /* cmp     r4, r5 */
226     0xd1fa,         /* bne.n   <BOARD_SetRunMode+0x8> */
227     0xb322,         /* cbz     r2, <BOARD_SetRunMode+0x5e> */
228     0x6818,         /* ldr     r0, [r3, #0] */
229     0xf040, 0x4080, /* orr.w   r0, r0, #1073741824   ; 0x40000000 */
230     0x6018,         /* str     r0, [r3, #0] */
231     0xf8d2, 0x015c, /* ldr.w   r0, [r2, #348]    ; 0x15c */
232     0x07c0,         /* lsls    r0, r0, #31 */
233     0xd4fb,         /* bmi.n   <BOARD_SetRunMode+0x1c> */
234     0x6810,         /* ldr     r0, [r2, #0] */
235     0xf420, 0x4080, /* bic.w   r0, r0, #16384    ; 0x4000 */
236     0x6010,         /* str     r0, [r2, #0] */
237     0x6810,         /* ldr     r0, [r2, #0] */
238     0xf040, 0x0003, /* orr.w   r0, r0, #3 */
239     0x6010,         /* str     r0, [r2, #0] */
240     0x20c8,         /* movs    r0, #200    ; 0xc8 */
241     0xf8d2, 0x115c, /* ldr.w   r1, [r2, #348]    ; 0x15c */
242     0x1e40,         /* subs    r0, r0, #1 */
243     0xd1fb,         /* bne.n   <BOARD_SetRunMode+0x36> */
244     0x6810,         /* ldr     r0, [r2, #0] */
245     0xf440, 0x4080, /* orr.w   r0, r0, #16384    ; 0x4000 */
246     0x6010,         /* str     r0, [r2, #0] */
247     0x6810,         /* ldr     r0, [r2, #0] */
248     0x0880,         /* lsrs    r0, r0, #2 */
249     0x0080,         /* lsls    r0, r0, #2 */
250     0x6010,         /* str     r0, [r2, #0] */
251     0x2000,         /* movs    r0, #0 */
252     0x6018,         /* str     r0, [r3, #0] */
253     0x9802,         /* ldr     r0, [sp, #8] */
254     0x6018,         /* str     r0, [r3, #0] */
255     0x6810,         /* ldr     r0, [r2, #0] */
256     0xf420, 0x4080, /* bic.w   r0, r0, #16384    ; 0x4000 */
257     0x6010,         /* str     r0, [r2, #0] */
258     0xbc30,         /* pop     {r4, r5} */
259     0x4770,         /* bx      lr */
260 };
261 
BOARD_IsRunOnQSPI(void)262 static bool BOARD_IsRunOnQSPI(void)
263 {
264     if (((uint32_t)BOARD_BootClockRUN >= 0x04000000U) && ((uint32_t)BOARD_BootClockRUN < 0x0C000000U))
265     {
266         return true;
267     }
268     return false;
269 }
270 
BOARD_InitClock(void)271 static void BOARD_InitClock(void)
272 {
273     /* First initialize same clock settings as ROM does. It's necessary for debugging
274        in case ROM doesn't initialize well. */
275     if (!CLOCK_IsSircValid())
276     {
277         CLOCK_InitSirc(&g_scgSircConfig);
278     }
279 
280     if (!CLOCK_IsFircValid())
281     {
282         CLOCK_InitFirc(&g_scgFircConfig);
283     }
284 
285     if (!CLOCK_IsSysOscValid())
286     {
287         CLOCK_InitSysOsc(&g_scgSysOscConfig);
288     }
289 
290     CLOCK_SetXtal0Freq(BOARD_XTAL0_CLK_HZ);
291 
292     /* SOSC, FIRC and SIRC needed by Cortex-A core when M4 runs into VLPR or STOP */
293     SCG0->SOSCCSR |= SCG_SOSCCSR_SOSCLPEN_MASK | SCG_SOSCCSR_SOSCSTEN_MASK;
294     SCG0->FIRCCSR |= SCG_FIRCCSR_FIRCSTEN_MASK;
295     SCG0->SIRCCSR |= SCG_SIRCCSR_SIRCSTEN_MASK;
296 
297     /* Then set SOSC, FIRC and SIRC DIV needed by application */
298     CLOCK_SetSysOscAsyncClkDiv(kSCG_AsyncDiv1Clk, kSCG_AsyncClkDivBy1);
299     CLOCK_SetSysOscAsyncClkDiv(kSCG_AsyncDiv2Clk, kSCG_AsyncClkDivBy1);
300 
301     CLOCK_SetFircAsyncClkDiv(kSCG_AsyncDiv1Clk, kSCG_AsyncClkDivBy1);
302     CLOCK_SetFircAsyncClkDiv(kSCG_AsyncDiv2Clk, kSCG_AsyncClkDivBy1);
303 
304     CLOCK_SetSircAsyncClkDiv(kSCG_AsyncDiv1Clk, kSCG_AsyncClkDivBy1);
305     CLOCK_SetSircAsyncClkDiv(kSCG_AsyncDiv2Clk, kSCG_AsyncClkDivBy1);
306 }
307 
308 /*
309  * Clock in VLPR mode:
310  * SYSOSC  : Enable (shared by CA7)
311  * SIRC    : Enable (shared by CA7)
312  * FIRC    : Enable (shared by CA7)
313  * SYSPLL  : Disable
314  * AUXPLL  : Disable
315  */
BOARD_BootClockVLPR(void)316 void BOARD_BootClockVLPR(void)
317 {
318     scg_sys_clk_config_t curConfig;
319     /* BOARD_SetRunMode is running in TCM to avoid clock change issue on QSPI memory */
320     BOARD_SetRunModeFunc BOARD_SetRunMode =
321         (BOARD_SetRunModeFunc)(((uint32_t)BOARD_SetRunModeCode) | 1U); /* Thumb code */
322     QuadSPI_Type *qspi = BOARD_IsRunOnQSPI() ? QuadSPI0 : NULL;
323 
324     BOARD_InitClock();
325 
326     /* Change to use SIRC as RUN system clock source */
327     BOARD_SetRunMode(SCG0, *((uint32_t *)(&g_sysClkConfigVlpr)), qspi, kCLOCK_Qspi,
328                      PCC1_PCC_QSPI_OTFAD_CGC_MASK | PCC1_PCC_QSPI_OTFAD_PCS(2)); /* QSPI source: 16M SIRC Async */
329 
330     /* Change to use SIRC as VLPR system clock source */
331     CLOCK_SetVlprModeSysClkConfig(&g_sysClkConfigVlpr);
332 
333     /* Switch running mode to VLPR */
334     SMC_SetPowerModeProtection(MSMC0, kSMC_AllowPowerModeAll);
335     SMC_SetPowerModeVlpr(MSMC0);
336     while (SMC_GetPowerModeState(MSMC0) != kSMC_PowerStateVlpr)
337     {
338     }
339 
340     /* Wait for clock source switch finished. */
341     do
342     {
343         CLOCK_GetCurSysClkConfig(&curConfig);
344     } while (curConfig.src != g_sysClkConfigVlpr.src);
345 
346     CLOCK_DeinitSysPll();
347     CLOCK_DeinitAuxPll();
348 
349     SystemCoreClockUpdate();
350 }
351 
352 /*
353  * Clock in RUN mode:
354  * SYSOSC  : Enable
355  * SIRC    : Enable
356  * FIRC    : Enable
357  * SYSPLL  : Enable
358  * AUXPLL  : Enable
359  */
BOARD_BootClockRUN(void)360 void BOARD_BootClockRUN(void)
361 {
362     /* BOARD_SetRunMode is running in TCM to avoid clock change issue on QSPI memory */
363     BOARD_SetRunModeFunc BOARD_SetRunMode =
364         (BOARD_SetRunModeFunc)(((uint32_t)BOARD_SetRunModeCode) | 1U); /* Thumb code */
365     QuadSPI_Type *qspi = BOARD_IsRunOnQSPI() ? QuadSPI0 : NULL;
366 
367     BOARD_InitClock();
368 
369     /* Change to use SIRC as system clock source to prepare to initialize other clock sources */
370     BOARD_SetRunMode(SCG0, *((uint32_t *)(&g_sysClkConfigVlpr)), qspi, kCLOCK_Qspi,
371                      PCC1_PCC_QSPI_OTFAD_CGC_MASK | PCC1_PCC_QSPI_OTFAD_PCS(2)); /* QSPI source: 16M SIRC Async */
372 
373     /* Initialize SysPll 480MHz */
374     CLOCK_InitSysPll(&g_scgSysPllConfig);
375 
376     /* Enable SysPll Pfd0 392MHz */
377     CLOCK_EnableSysPllPfdClkout(kSCG_SysPllPfd0Clk, 22U);
378     /* Enable SysPll Pfd3 480MHz (same as SysPll main clock) */
379     CLOCK_EnableSysPllPfdClkout(kSCG_SysPllPfd3Clk, 18U);
380 
381     /* Initialize AuxPll */
382     CLOCK_InitAuxPll(&g_scgAuxPllConfig);
383     /* Enable AuxPll Pfd0 540.672MHz (same as AuxPll before postdiv) */
384     CLOCK_EnableAuxPllPfdClkout(kSCG_AuxPllPfd0Clk, 18U);
385 
386     BOARD_SetRunMode(SCG0, *((uint32_t *)(&g_sysClkConfigNormalRun)), qspi, kCLOCK_Qspi,
387                      PCC1_PCC_QSPI_OTFAD_CGC_MASK | PCC1_PCC_QSPI_OTFAD_PCS(3)); /* QSPI source: 48M FIRC Async */
388 
389     SystemCoreClockUpdate();
390 }
391 
392 /*
393  * Clock in HSRUN mode:
394  * SYSOSC  : Enable
395  * SIRC    : Enable
396  * FIRC    : Enable
397  * SYSPLL  : Enable
398  * AUXPLL  : Enable
399  */
BOARD_BootClockHSRUN(void)400 void BOARD_BootClockHSRUN(void)
401 {
402     scg_sys_clk_config_t curConfig;
403 
404     BOARD_BootClockRUN();
405 
406     /* Change to use SysPll Pfd0 as system clock source */
407     CLOCK_SetHsrunModeSysClkConfig(&g_sysClkConfigHsrun);
408 
409     /* Switch running mode to HSRUN */
410     SMC_SetPowerModeProtection(MSMC0, kSMC_AllowPowerModeAll);
411     SMC_SetPowerModeHsrun(MSMC0);
412     while (SMC_GetPowerModeState(MSMC0) != kSMC_PowerStateHsrun)
413     {
414     }
415 
416     /* Wait for clock source switch finished. */
417     do
418     {
419         CLOCK_GetCurSysClkConfig(&curConfig);
420     } while (curConfig.src != g_sysClkConfigHsrun.src);
421 
422     SystemCoreClockUpdate();
423 }
424