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