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