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(¤t);
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(¤t);
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