1 /*
2  * Copyright (c) 2019-2021 Vestas Wind Systems A/S
3  *
4  * Based on NXP k6x soc.c, which is:
5  * Copyright (c) 2014-2015 Wind River Systems, Inc.
6  * Copyright (c) 2016, Freescale Semiconductor, Inc.
7  *
8  * SPDX-License-Identifier: Apache-2.0
9  */
10 
11 #include <zephyr/kernel.h>
12 #include <zephyr/device.h>
13 #include <zephyr/init.h>
14 #include <fsl_clock.h>
15 #include <fsl_cache.h>
16 #include <cmsis_core.h>
17 
18 #define ASSERT_WITHIN_RANGE(val, min, max, str) \
19 	BUILD_ASSERT(val >= min && val <= max, str)
20 
21 #define ASSERT_ASYNC_CLK_DIV_VALID(val, str) \
22 	BUILD_ASSERT(val == 0 || val == 1 || val == 2 || val == 4 ||	\
23 		     val == 8 || val == 16 || val == 2 || val == 64, str)
24 
25 #define TO_SYS_CLK_DIV(val) _DO_CONCAT(kSCG_SysClkDivBy, val)
26 
27 #define kSCG_AsyncClkDivBy0 kSCG_AsyncClkDisable
28 #define TO_ASYNC_CLK_DIV(val) _DO_CONCAT(kSCG_AsyncClkDivBy, val)
29 
30 #define SCG_CLOCK_NODE(name) DT_CHILD(DT_INST(0, nxp_kinetis_scg), name)
31 #define SCG_CLOCK_DIV(name) DT_PROP(SCG_CLOCK_NODE(name), clock_div)
32 #define SCG_CLOCK_MULT(name) DT_PROP(SCG_CLOCK_NODE(name), clock_mult)
33 
34 /* System Clock configuration */
35 ASSERT_WITHIN_RANGE(SCG_CLOCK_DIV(slow_clk), 2, 8,
36 		    "Invalid SCG slow clock divider value");
37 ASSERT_WITHIN_RANGE(SCG_CLOCK_DIV(bus_clk), 1, 16,
38 		    "Invalid SCG bus clock divider value");
39 #if DT_SAME_NODE(DT_CLOCKS_CTLR(SCG_CLOCK_NODE(core_clk)), SCG_CLOCK_NODE(spll_clk))
40 /* Core divider range is 1 to 4 with SPLL as clock source */
41 ASSERT_WITHIN_RANGE(SCG_CLOCK_DIV(core_clk), 1, 4,
42 		    "Invalid SCG core clock divider value");
43 #else
44 ASSERT_WITHIN_RANGE(SCG_CLOCK_DIV(core_clk), 1, 16,
45 		    "Invalid SCG core clock divider value");
46 #endif
47 static const scg_sys_clk_config_t scg_sys_clk_config = {
48 	.divSlow = TO_SYS_CLK_DIV(SCG_CLOCK_DIV(slow_clk)),
49 	.divBus  = TO_SYS_CLK_DIV(SCG_CLOCK_DIV(bus_clk)),
50 	.divCore = TO_SYS_CLK_DIV(SCG_CLOCK_DIV(core_clk)),
51 #if DT_SAME_NODE(DT_CLOCKS_CTLR(SCG_CLOCK_NODE(core_clk)), SCG_CLOCK_NODE(sosc_clk))
52 	.src     = kSCG_SysClkSrcSysOsc,
53 #elif DT_SAME_NODE(DT_CLOCKS_CTLR(SCG_CLOCK_NODE(core_clk)), SCG_CLOCK_NODE(sirc_clk))
54 	.src     = kSCG_SysClkSrcSirc,
55 #elif DT_SAME_NODE(DT_CLOCKS_CTLR(SCG_CLOCK_NODE(core_clk)), SCG_CLOCK_NODE(firc_clk))
56 	.src     = kSCG_SysClkSrcFirc,
57 #elif DT_SAME_NODE(DT_CLOCKS_CTLR(SCG_CLOCK_NODE(core_clk)), SCG_CLOCK_NODE(spll_clk))
58 	.src     = kSCG_SysClkSrcSysPll,
59 #else
60 #error Invalid SCG core clock source
61 #endif
62 };
63 
64 #if DT_NODE_HAS_STATUS(SCG_CLOCK_NODE(sosc_clk), okay)
65 /* System Oscillator (SOSC) configuration */
66 ASSERT_ASYNC_CLK_DIV_VALID(SCG_CLOCK_DIV(soscdiv1_clk),
67 		       "Invalid SCG SOSC divider 1 value");
68 ASSERT_ASYNC_CLK_DIV_VALID(SCG_CLOCK_DIV(soscdiv2_clk),
69 		       "Invalid SCG SOSC divider 2 value");
70 static const scg_sosc_config_t scg_sosc_config = {
71 	.freq        = DT_PROP(SCG_CLOCK_NODE(sosc_clk), clock_frequency),
72 	.monitorMode = kSCG_SysOscMonitorDisable,
73 	.enableMode  = kSCG_SysOscEnable | kSCG_SysOscEnableInLowPower,
74 	.div1        = TO_ASYNC_CLK_DIV(SCG_CLOCK_DIV(soscdiv1_clk)),
75 	.div2        = TO_ASYNC_CLK_DIV(SCG_CLOCK_DIV(soscdiv2_clk)),
76 	.workMode    = DT_PROP(DT_INST(0, nxp_kinetis_scg), sosc_mode)
77 };
78 #endif /* DT_NODE_HAS_PROP(DT_INST(0, nxp_kinetis_scg), sosc_freq) */
79 
80 /* Slow Internal Reference Clock (SIRC) configuration */
81 ASSERT_ASYNC_CLK_DIV_VALID(SCG_CLOCK_DIV(sircdiv1_clk),
82 		       "Invalid SCG SIRC divider 1 value");
83 ASSERT_ASYNC_CLK_DIV_VALID(SCG_CLOCK_DIV(sircdiv2_clk),
84 		       "Invalid SCG SIRC divider 2 value");
85 static const scg_sirc_config_t scg_sirc_config = {
86 	.enableMode = kSCG_SircEnable | kSCG_SircEnableInLowPower,
87 	.div1       = TO_ASYNC_CLK_DIV(SCG_CLOCK_DIV(sircdiv1_clk)),
88 	.div2       = TO_ASYNC_CLK_DIV(SCG_CLOCK_DIV(sircdiv2_clk)),
89 #if MHZ(2) == DT_PROP(SCG_CLOCK_NODE(sirc_clk), clock_frequency)
90 	.range      = kSCG_SircRangeLow
91 #elif MHZ(8) == DT_PROP(SCG_CLOCK_NODE(sirc_clk), clock_frequency)
92 	.range      = kSCG_SircRangeHigh
93 #else
94 #error Invalid SCG SIRC clock frequency
95 #endif
96 };
97 
98 /* Fast Internal Reference Clock (FIRC) configuration */
99 ASSERT_ASYNC_CLK_DIV_VALID(SCG_CLOCK_DIV(fircdiv1_clk),
100 		       "Invalid SCG FIRC divider 1 value");
101 ASSERT_ASYNC_CLK_DIV_VALID(SCG_CLOCK_DIV(fircdiv2_clk),
102 		       "Invalid SCG FIRC divider 2 value");
103 static const scg_firc_config_t scg_firc_config = {
104 	.enableMode = kSCG_FircEnable,
105 	.div1       = TO_ASYNC_CLK_DIV(SCG_CLOCK_DIV(fircdiv1_clk)),
106 	.div2       = TO_ASYNC_CLK_DIV(SCG_CLOCK_DIV(fircdiv2_clk)),
107 #if MHZ(48) == DT_PROP(SCG_CLOCK_NODE(firc_clk), clock_frequency)
108 	.range      = kSCG_FircRange48M,
109 #elif MHZ(52) == DT_PROP(SCG_CLOCK_NODE(firc_clk), clock_frequency)
110 	.range      = kSCG_FircRange52M,
111 #elif MHZ(56) == DT_PROP(SCG_CLOCK_NODE(firc_clk), clock_frequency)
112 	.range      = kSCG_FircRange56M,
113 #elif MHZ(60) == DT_PROP(SCG_CLOCK_NODE(firc_clk), clock_frequency)
114 	.range      = kSCG_FircRange60M,
115 #else
116 #error Invalid SCG FIRC clock frequency
117 #endif
118 	.trimConfig = NULL
119 };
120 
121 /* System Phase-Locked Loop (SPLL) configuration */
122 ASSERT_WITHIN_RANGE(SCG_CLOCK_DIV(spll_clk), 2, 2,
123 		    "Invalid SCG SPLL fixed divider value");
124 ASSERT_ASYNC_CLK_DIV_VALID(SCG_CLOCK_DIV(splldiv1_clk),
125 		       "Invalid SCG SPLL divider 1 value");
126 ASSERT_ASYNC_CLK_DIV_VALID(SCG_CLOCK_DIV(splldiv2_clk),
127 		       "Invalid SCG SPLL divider 2 value");
128 ASSERT_WITHIN_RANGE(SCG_CLOCK_DIV(pll), 1, 8,
129 		    "Invalid SCG PLL pre divider value");
130 ASSERT_WITHIN_RANGE(SCG_CLOCK_MULT(pll), 16, 47,
131 		    "Invalid SCG PLL multiplier value");
132 static const scg_spll_config_t scg_spll_config = {
133 	.enableMode  = kSCG_SysPllEnable,
134 	.monitorMode = kSCG_SysPllMonitorDisable,
135 	.div1        = TO_ASYNC_CLK_DIV(SCG_CLOCK_DIV(splldiv1_clk)),
136 	.div2        = TO_ASYNC_CLK_DIV(SCG_CLOCK_DIV(splldiv2_clk)),
137 #if DT_SAME_NODE(DT_CLOCKS_CTLR(SCG_CLOCK_NODE(pll)), SCG_CLOCK_NODE(sosc_clk))
138 	.src         = kSCG_SysPllSrcSysOsc,
139 #elif DT_SAME_NODE(DT_CLOCKS_CTLR(SCG_CLOCK_NODE(pll)), SCG_CLOCK_NODE(firc_clk))
140 	.src         = kSCG_SysPllSrcFirc,
141 #else
142 #error Invalid SCG PLL clock source
143 #endif
144 	.prediv      = (SCG_CLOCK_DIV(pll) - 1U),
145 	.mult        = (SCG_CLOCK_MULT(pll) - 16U)
146 };
147 
clk_init(void)148 static ALWAYS_INLINE void clk_init(void)
149 {
150 	const scg_sys_clk_config_t scg_sys_clk_config_safe = {
151 		.divSlow = kSCG_SysClkDivBy4,
152 		.divBus  = kSCG_SysClkDivBy1,
153 		.divCore = kSCG_SysClkDivBy1,
154 		.src     = kSCG_SysClkSrcSirc
155 	};
156 	scg_sys_clk_config_t current;
157 
158 #if DT_NODE_HAS_STATUS(SCG_CLOCK_NODE(sosc_clk), okay)
159 	/* Optionally initialize system oscillator */
160 	CLOCK_InitSysOsc(&scg_sosc_config);
161 	CLOCK_SetXtal0Freq(scg_sosc_config.freq);
162 #endif
163 	/* Configure SIRC */
164 	CLOCK_InitSirc(&scg_sirc_config);
165 
166 	/* Temporary switch to safe SIRC in order to configure FIRC */
167 	CLOCK_SetRunModeSysClkConfig(&scg_sys_clk_config_safe);
168 	do {
169 		CLOCK_GetCurSysClkConfig(&current);
170 	} while (current.src != scg_sys_clk_config_safe.src);
171 	CLOCK_InitFirc(&scg_firc_config);
172 
173 	/* Configure System PLL */
174 	CLOCK_InitSysPll(&scg_spll_config);
175 
176 	/* Only RUN mode supported for now */
177 	CLOCK_SetRunModeSysClkConfig(&scg_sys_clk_config);
178 	do {
179 		CLOCK_GetCurSysClkConfig(&current);
180 	} while (current.src != scg_sys_clk_config.src);
181 
182 #if DT_NODE_HAS_STATUS(DT_NODELABEL(lpuart0), okay)
183 	CLOCK_SetIpSrc(kCLOCK_Lpuart0,
184 		       DT_CLOCKS_CELL(DT_NODELABEL(lpuart0), ip_source));
185 #endif
186 #if DT_NODE_HAS_STATUS(DT_NODELABEL(lpuart1), okay)
187 	CLOCK_SetIpSrc(kCLOCK_Lpuart1,
188 		       DT_CLOCKS_CELL(DT_NODELABEL(lpuart1), ip_source));
189 #endif
190 #if DT_NODE_HAS_STATUS(DT_NODELABEL(lpuart2), okay)
191 	CLOCK_SetIpSrc(kCLOCK_Lpuart2,
192 		       DT_CLOCKS_CELL(DT_NODELABEL(lpuart2), ip_source));
193 #endif
194 #if DT_NODE_HAS_STATUS(DT_NODELABEL(lpi2c0), okay)
195 	CLOCK_SetIpSrc(kCLOCK_Lpi2c0,
196 		       DT_CLOCKS_CELL(DT_NODELABEL(lpi2c0), ip_source));
197 #endif
198 #if DT_NODE_HAS_STATUS(DT_NODELABEL(lpi2c1), okay)
199 	CLOCK_SetIpSrc(kCLOCK_Lpi2c1,
200 		       DT_CLOCKS_CELL(DT_NODELABEL(lpi2c1), ip_source));
201 #endif
202 #if DT_NODE_HAS_STATUS(DT_NODELABEL(lpspi0), okay)
203 	CLOCK_SetIpSrc(kCLOCK_Lpspi0,
204 		       DT_CLOCKS_CELL(DT_NODELABEL(lpspi0), ip_source));
205 #endif
206 #if DT_NODE_HAS_STATUS(DT_NODELABEL(lpspi1), okay)
207 	CLOCK_SetIpSrc(kCLOCK_Lpspi1,
208 		       DT_CLOCKS_CELL(DT_NODELABEL(lpspi1), ip_source));
209 #endif
210 #if DT_NODE_HAS_STATUS(DT_NODELABEL(adc0), okay)
211 	CLOCK_SetIpSrc(kCLOCK_Adc0,
212 		       DT_CLOCKS_CELL(DT_NODELABEL(adc0), ip_source));
213 #endif
214 #if DT_NODE_HAS_STATUS(DT_NODELABEL(adc1), okay)
215 	CLOCK_SetIpSrc(kCLOCK_Adc1,
216 		       DT_CLOCKS_CELL(DT_NODELABEL(adc1), ip_source));
217 #endif
218 #if DT_NODE_HAS_STATUS(DT_NODELABEL(adc2), okay)
219 	CLOCK_SetIpSrc(kCLOCK_Adc2,
220 		       DT_CLOCKS_CELL(DT_NODELABEL(adc2), ip_source));
221 #endif
222 #if DT_NODE_HAS_STATUS(DT_NODELABEL(ftm0), okay)
223 	CLOCK_SetIpSrc(kCLOCK_Ftm0,
224 		       DT_CLOCKS_CELL(DT_NODELABEL(ftm0), ip_source));
225 #endif
226 #if DT_NODE_HAS_STATUS(DT_NODELABEL(ftm1), okay)
227 	CLOCK_SetIpSrc(kCLOCK_Ftm1,
228 		       DT_CLOCKS_CELL(DT_NODELABEL(ftm1), ip_source));
229 #endif
230 #if DT_NODE_HAS_STATUS(DT_NODELABEL(ftm2), okay)
231 	CLOCK_SetIpSrc(kCLOCK_Ftm2,
232 		       DT_CLOCKS_CELL(DT_NODELABEL(ftm2), ip_source));
233 #endif
234 #if DT_NODE_HAS_STATUS(DT_NODELABEL(ftm3), okay)
235 	CLOCK_SetIpSrc(kCLOCK_Ftm3,
236 		       DT_CLOCKS_CELL(DT_NODELABEL(ftm3), ip_source));
237 #endif
238 }
239 
ke1xf_init(void)240 static int ke1xf_init(void)
241 
242 {
243 #if !defined(CONFIG_ARM_MPU)
244 	uint32_t temp_reg;
245 #endif /* !CONFIG_ARM_MPU */
246 
247 #if !defined(CONFIG_ARM_MPU)
248 	/*
249 	 * Disable memory protection and clear slave port errors.
250 	 * Note that the KE1xF does not implement the optional ARMv7-M memory
251 	 * protection unit (MPU), specified by the architecture (PMSAv7), in the
252 	 * Cortex-M4 core.  Instead, the processor includes its own MPU module.
253 	 */
254 	temp_reg = SYSMPU->CESR;
255 	temp_reg &= ~SYSMPU_CESR_VLD_MASK;
256 	temp_reg |= SYSMPU_CESR_SPERR_MASK;
257 	SYSMPU->CESR = temp_reg;
258 #endif /* !CONFIG_ARM_MPU */
259 
260 	/* Initialize system clocks and PLL */
261 	clk_init();
262 
263 #ifndef CONFIG_KINETIS_KE1XF_ENABLE_CODE_CACHE
264 	/* SystemInit will have enabled the code cache. Disable it here */
265 	L1CACHE_DisableCodeCache();
266 #endif
267 
268 	return 0;
269 }
270 
271 #ifdef CONFIG_PLATFORM_SPECIFIC_INIT
272 
273 #ifdef CONFIG_WDOG_INIT
274 
z_arm_watchdog_init(void)275 void z_arm_watchdog_init(void)
276 {
277 	/*
278 	 * NOTE: DO NOT SINGLE STEP THROUGH THIS SECTION!!! Watchdog
279 	 * reconfiguration must take place within 128 bus clocks from
280 	 * unlocking. Single stepping through the code will cause the
281 	 * watchdog to close the unlock window again.
282 	 */
283 
284 	/*
285 	 * Unlocking watchdog to enable reconfiguration after bootloader
286 	 * watchdog reconfiguration is only required if the watchdog
287 	 * is to be enabled, since SystemInit will disable
288 	 * it at boot unless CONFIG_WDOG_ENABLE_AT_BOOT is set
289 	 */
290 	WDOG->CNT = WDOG_UPDATE_KEY;
291 	while (!(WDOG->CS & WDOG_CS_ULK_MASK)) {
292 		;
293 	}
294 
295 	/*
296 	 * Watchdog reconfiguration only takes effect after writing to
297 	 * both TOVAL and CS registers.
298 	 */
299 	WDOG->TOVAL = CONFIG_WDOG_INITIAL_TIMEOUT >> 1;
300 	WDOG->CS = WDOG_CS_PRES(1) | WDOG_CS_CLK(1) | WDOG_CS_WAIT(1) |
301 		   WDOG_CS_EN(1) | WDOG_CS_UPDATE(1);
302 
303 	while (!(WDOG->CS & WDOG_CS_RCS_MASK)) {
304 		;
305 	}
306 }
307 
308 #endif /* CONFIG_WDOG_INIT */
309 
z_arm_platform_init(void)310 void z_arm_platform_init(void)
311 {
312 	/* SystemInit is provided by the NXP SDK */
313 	SystemInit();
314 }
315 
316 #endif /* CONFIG_PLATFORM_SPECIFIC_INIT */
317 
318 SYS_INIT(ke1xf_init, PRE_KERNEL_1, 0);
319