1 /*
2 * Copyright 2023-2024 NXP
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/arch/cpu.h>
8 #include <zephyr/device.h>
9 #include <zephyr/init.h>
10 #include <zephyr/kernel.h>
11 #include <zephyr/linker/sections.h>
12
13 #include <soc.h>
14
15 #include <fsl_ccm32k.h>
16 #include <fsl_common.h>
17 #include <fsl_clock.h>
18
19 extern uint32_t SystemCoreClock;
20 extern void nxp_nbu_init(void);
21
clock_init(void)22 static ALWAYS_INLINE void clock_init(void)
23 {
24 /* Unlock Reference Clock Status Registers to allow writes */
25 CLOCK_UnlockFircControlStatusReg();
26 CLOCK_UnlockSircControlStatusReg();
27 CLOCK_UnlockRoscControlStatusReg();
28 CLOCK_UnlockSysOscControlStatusReg();
29
30 /*
31 * Configuration for the 32 kHz Oscillator module
32 * Internal capatitor bank is required in order to use the more stable OSC32K source
33 */
34 ccm32k_osc_config_t ccm32k_osc_config = {
35 .coarseAdjustment = kCCM32K_OscCoarseAdjustmentRange0, /* ESR_Range0 */
36 .enableInternalCapBank = true, /* Internal capacitance bank is enabled */
37 .xtalCap = kCCM32K_OscXtal8pFCap, /* 8 pF */
38 .extalCap = kCCM32K_OscExtal8pFCap, /* 8 pF */
39 };
40 /* Enable OSC32K */
41 CCM32K_Set32kOscConfig(CCM32K, kCCM32K_Enable32kHzCrystalOsc, &ccm32k_osc_config);
42 /* Disable ROSC Monitor, because switching the source would generate an expected error */
43 CLOCK_SetRoscMonitorMode(kSCG_RoscMonitorDisable);
44
45 /* Select the Real Time Clock (RTC) source as OSC32K */
46 while ((CCM32K_GetStatusFlag(CCM32K) & CCM32K_STATUS_OSC32K_RDY_MASK) == 0UL) {
47 }
48 CCM32K_SelectClockSource(CCM32K, kCCM32K_ClockSourceSelectOsc32k);
49
50 /* Wait for RTC Oscillator to be Valid */
51 while (!CLOCK_IsRoscValid())
52 ;
53 /* Re-enable monitor */
54 CLOCK_SetRoscMonitorMode(kSCG_RoscMonitorInt);
55 /* Disable the FRO32K to save power */
56 CCM32K_Enable32kFro(CCM32K, false);
57
58 CLOCK_SetXtal32Freq(32768U);
59
60 /* Configuration to set FIRC to maximum frequency */
61 scg_firc_config_t scg_firc_config = {
62 .enableMode = kSCG_FircEnable, /* Fast IRC is enabled */
63 .range = kSCG_FircRange96M, /* 96 Mhz FIRC clock selected */
64 .trimConfig = NULL,
65 };
66
67 scg_sys_clk_config_t sys_clk_safe_config_source = {
68 .divSlow = (uint32_t)kSCG_SysClkDivBy4,
69 .divCore = (uint32_t)kSCG_SysClkDivBy1,
70 .src = (uint32_t)kSCG_SysClkSrcSirc,
71 };
72
73 CLOCK_SetRunModeSysClkConfig(&sys_clk_safe_config_source);
74
75 scg_sys_clk_config_t cur_config;
76
77 do {
78 CLOCK_GetCurSysClkConfig(&cur_config);
79 } while (cur_config.src != sys_clk_safe_config_source.src);
80
81 (void)CLOCK_InitFirc(&scg_firc_config);
82
83 scg_sys_clk_config_t sys_clk_config = {
84 .divSlow = (uint32_t)kSCG_SysClkDivBy4, /* Slow Clock Divider: divided by 4 */
85 .divBus = (uint32_t)kSCG_SysClkDivBy1, /* Bus Clock Divider: divided by 1 */
86 .divCore = (uint32_t)kSCG_SysClkDivBy1, /* Core Clock Divider: divided by 1 */
87 .src = (uint32_t)kSCG_SysClkSrcFirc, /* Select Fast IRC as System Clock */
88 };
89 CLOCK_SetRunModeSysClkConfig(&sys_clk_config);
90
91 /* Wait for clock source switch to finish */
92 do {
93 CLOCK_GetCurSysClkConfig(&cur_config);
94 } while (cur_config.src != sys_clk_config.src);
95
96 SystemCoreClock = 96000000U;
97
98 /* OSC-RF / System Oscillator Configuration */
99 scg_sosc_config_t sosc_config = {
100 .freq = 32000000U,
101 .monitorMode = kSCG_SysOscMonitorDisable,
102 .enableMode = kSCG_SoscEnable,
103 };
104
105 /* Init OSC-RF / SOSC */
106 (void)CLOCK_InitSysOsc(&sosc_config);
107 CLOCK_SetXtal0Freq(sosc_config.freq);
108
109 /* Slow internal reference clock (SIRC) configuration */
110 scg_sirc_config_t sirc_config = {
111 .enableMode = kSCG_SircDisableInSleep,
112 };
113
114 /* Init SIRC */
115 (void)CLOCK_InitSirc(&sirc_config);
116
117 /* Attach Clocks */
118 CLOCK_SetIpSrc(kCLOCK_Lpuart0, kCLOCK_IpSrcFro192M);
119 CLOCK_SetIpSrc(kCLOCK_Lpuart1, kCLOCK_IpSrcFro192M);
120 CLOCK_SetIpSrc(kCLOCK_Lpspi0, kCLOCK_IpSrcFro192M);
121 CLOCK_SetIpSrc(kCLOCK_Lpspi1, kCLOCK_IpSrcFro192M);
122 CLOCK_SetIpSrc(kCLOCK_Can0, kCLOCK_IpSrcFro192M);
123 CLOCK_SetIpSrc(kCLOCK_Tpm0, kCLOCK_IpSrcFro192M);
124 CLOCK_SetIpSrc(kCLOCK_Tpm1, kCLOCK_IpSrcFro192M);
125 CLOCK_SetIpSrc(kCLOCK_Lpi2c0, kCLOCK_IpSrcFro192M);
126 CLOCK_SetIpSrcDiv(kCLOCK_Lpi2c0, kSCG_SysClkDivBy16);
127 CLOCK_SetIpSrc(kCLOCK_Lpi2c1, kCLOCK_IpSrcFro192M);
128 CLOCK_SetIpSrcDiv(kCLOCK_Lpi2c1, kSCG_SysClkDivBy16);
129 CLOCK_SetIpSrc(kCLOCK_Lpspi0, kCLOCK_IpSrcFro192M);
130 CLOCK_SetIpSrc(kCLOCK_Lpspi1, kCLOCK_IpSrcFro192M);
131 CLOCK_SetIpSrc(kCLOCK_Lpadc0, kCLOCK_IpSrcFro192M);
132 CLOCK_SetIpSrcDiv(kCLOCK_Lpadc0, kSCG_SysClkDivBy10);
133
134 /* Ungate clocks if the peripheral is enabled in devicetree */
135 if (DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(gpioa), nxp_kinetis_gpio, okay)) {
136 CLOCK_EnableClock(kCLOCK_PortA);
137 }
138
139 if (DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(gpioc), nxp_kinetis_gpio, okay)) {
140 CLOCK_EnableClock(kCLOCK_PortC);
141 }
142
143 if (DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(lpuart0), nxp_kinetis_lpuart, okay)) {
144 CLOCK_EnableClock(kCLOCK_Lpuart0);
145 }
146
147 if (DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(lpuart1), nxp_kinetis_lpuart, okay)) {
148 CLOCK_EnableClock(kCLOCK_Lpuart1);
149 }
150
151 if (DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(tpm0), nxp_kinetis_tpm, okay)) {
152 CLOCK_EnableClock(kCLOCK_Tpm0);
153 }
154
155 if (DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(tpm1), nxp_kinetis_tpm, okay)) {
156 CLOCK_EnableClock(kCLOCK_Tpm1);
157 }
158
159 if (DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(lpi2c0), nxp_lpi2c, okay)) {
160 CLOCK_EnableClock(kCLOCK_Lpi2c0);
161 }
162
163 if (DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(lpi2c1), nxp_lpi2c, okay)) {
164 CLOCK_EnableClock(kCLOCK_Lpi2c1);
165 }
166
167 if (DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(lpspi0), nxp_lpspi, okay)) {
168 CLOCK_EnableClock(kCLOCK_Lpspi0);
169 }
170
171 if (DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(lpspi1), nxp_lpspi, okay)) {
172 CLOCK_EnableClock(kCLOCK_Lpspi1);
173 }
174
175 if (IS_ENABLED(CONFIG_CAN_MCUX_FLEXCAN)) {
176 CLOCK_EnableClock(kCLOCK_Can0);
177 }
178
179 if (DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(vref), nxp_vref, okay)) {
180 CLOCK_EnableClock(kCLOCK_Vref0);
181 }
182
183 if (DT_NODE_HAS_COMPAT_STATUS(adc0, nxp_lpadc, okay)) {
184 CLOCK_EnableClock(kCLOCK_Lpadc0);
185 }
186 }
187
vbat_init(void)188 static void vbat_init(void)
189 {
190 VBAT_Type *base = (VBAT_Type *)DT_REG_ADDR(DT_NODELABEL(vbat));
191
192 /* Write 1 to Clear POR detect status bit.
193 *
194 * Clearing this bit is acknowledement
195 * that software has recognized a power on reset.
196 *
197 * This avoids also niche issues with NVIC read/write
198 * when searching for available interrupt lines.
199 */
200 base->STATUSA |= VBAT_STATUSA_POR_DET_MASK;
201 };
202
soc_early_init_hook(void)203 void soc_early_init_hook(void)
204 {
205 unsigned int oldLevel; /* old interrupt lock level */
206
207 /* disable interrupts */
208 oldLevel = irq_lock();
209
210 /* Initialize system clock to 96 MHz */
211 clock_init();
212
213 /* Smart power switch initialization */
214 vbat_init();
215
216 /* restore interrupt state */
217 irq_unlock(oldLevel);
218
219 #if defined(CONFIG_BT) || defined(CONFIG_IEEE802154)
220 nxp_nbu_init();
221 #endif
222 }
223