1 /*
2 * Copyright 2024 NXP
3 * Copyright (c) 2019-2021 Vestas Wind Systems A/S
4 *
5 * Based on NXP k6x soc.c, which is:
6 * Copyright (c) 2014-2015 Wind River Systems, Inc.
7 * Copyright (c) 2016, Freescale Semiconductor, Inc.
8 *
9 * SPDX-License-Identifier: Apache-2.0
10 */
11
12 #include <zephyr/kernel.h>
13 #include <zephyr/device.h>
14 #include <zephyr/init.h>
15 #include <fsl_clock.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
33 /* System Clock configuration */
34 ASSERT_WITHIN_RANGE(SCG_CLOCK_DIV(bus_clk), 2, 8,
35 "Invalid SCG bus clock divider value");
36 ASSERT_WITHIN_RANGE(SCG_CLOCK_DIV(core_clk), 1, 16,
37 "Invalid SCG core clock divider value");
38
39 static const scg_sys_clk_config_t scg_sys_clk_config = {
40 .divSlow = TO_SYS_CLK_DIV(SCG_CLOCK_DIV(bus_clk)),
41 .divCore = TO_SYS_CLK_DIV(SCG_CLOCK_DIV(core_clk)),
42 #if DT_SAME_NODE(DT_CLOCKS_CTLR(SCG_CLOCK_NODE(core_clk)), SCG_CLOCK_NODE(sirc_clk))
43 .src = kSCG_SysClkSrcSirc,
44 #elif DT_SAME_NODE(DT_CLOCKS_CTLR(SCG_CLOCK_NODE(core_clk)), SCG_CLOCK_NODE(firc_clk))
45 .src = kSCG_SysClkSrcFirc,
46 #endif
47 };
48
49 /* Slow Internal Reference Clock (SIRC) configuration */
50 ASSERT_ASYNC_CLK_DIV_VALID(SCG_CLOCK_DIV(sircdiv2_clk),
51 "Invalid SCG SIRC divider 2 value");
52 static const scg_sirc_config_t scg_sirc_config = {
53 .enableMode = kSCG_SircEnable,
54 .div2 = TO_ASYNC_CLK_DIV(SCG_CLOCK_DIV(sircdiv2_clk)),
55 #if MHZ(2) == DT_PROP(SCG_CLOCK_NODE(sirc_clk), clock_frequency)
56 .range = kSCG_SircRangeLow
57 #elif MHZ(8) == DT_PROP(SCG_CLOCK_NODE(sirc_clk), clock_frequency)
58 .range = kSCG_SircRangeHigh
59 #else
60 #error Invalid SCG SIRC clock frequency
61 #endif
62 };
63
64 /* Fast Internal Reference Clock (FIRC) configuration */
65 ASSERT_ASYNC_CLK_DIV_VALID(SCG_CLOCK_DIV(fircdiv2_clk),
66 "Invalid SCG FIRC divider 2 value");
67 static const scg_firc_config_t scg_firc_config = {
68 .enableMode = kSCG_FircEnable,
69 .div2 = TO_ASYNC_CLK_DIV(SCG_CLOCK_DIV(fircdiv2_clk)), /* b20253 */
70 #if MHZ(48) == DT_PROP(SCG_CLOCK_NODE(firc_clk), clock_frequency)
71 .range = kSCG_FircRange48M,
72 #elif MHZ(52) == DT_PROP(SCG_CLOCK_NODE(firc_clk), clock_frequency)
73 .range = kSCG_FircRange52M,
74 #elif MHZ(56) == DT_PROP(SCG_CLOCK_NODE(firc_clk), clock_frequency)
75 .range = kSCG_FircRange56M,
76 #elif MHZ(60) == DT_PROP(SCG_CLOCK_NODE(firc_clk), clock_frequency)
77 .range = kSCG_FircRange60M,
78 #else
79 #error Invalid SCG FIRC clock frequency
80 #endif
81 .trimConfig = NULL
82 };
83
clk_init(void)84 static ALWAYS_INLINE void clk_init(void)
85 {
86 const scg_sys_clk_config_t scg_sys_clk_config_safe = {
87 .divSlow = kSCG_SysClkDivBy4,
88 .divCore = kSCG_SysClkDivBy1,
89 .src = kSCG_SysClkSrcSirc
90 };
91 scg_sys_clk_config_t current;
92
93 /* Configure SIRC */
94 CLOCK_InitSirc(&scg_sirc_config);
95
96 /* Temporary switch to safe SIRC in order to configure FIRC */
97 CLOCK_SetRunModeSysClkConfig(&scg_sys_clk_config_safe);
98 do {
99 CLOCK_GetCurSysClkConfig(¤t);
100 } while (current.src != scg_sys_clk_config_safe.src);
101 CLOCK_InitFirc(&scg_firc_config);
102
103 /* Only RUN mode supported for now */
104 CLOCK_SetRunModeSysClkConfig(&scg_sys_clk_config);
105 do {
106 CLOCK_GetCurSysClkConfig(¤t);
107 } while (current.src != scg_sys_clk_config.src);
108
109 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpuart0))
110 CLOCK_SetIpSrc(kCLOCK_Lpuart0,
111 DT_CLOCKS_CELL(DT_NODELABEL(lpuart0), ip_source));
112 #endif
113 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpuart1))
114 CLOCK_SetIpSrc(kCLOCK_Lpuart1,
115 DT_CLOCKS_CELL(DT_NODELABEL(lpuart1), ip_source));
116 #endif
117 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpuart2))
118 CLOCK_SetIpSrc(kCLOCK_Lpuart2,
119 DT_CLOCKS_CELL(DT_NODELABEL(lpuart2), ip_source));
120 #endif
121 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpi2c0))
122 CLOCK_SetIpSrc(kCLOCK_Lpi2c0,
123 DT_CLOCKS_CELL(DT_NODELABEL(lpi2c0), ip_source));
124 #endif
125 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpi2c1))
126 CLOCK_SetIpSrc(kCLOCK_Lpi2c1,
127 DT_CLOCKS_CELL(DT_NODELABEL(lpi2c1), ip_source));
128 #endif
129 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(flexio))
130 CLOCK_SetIpSrc(kCLOCK_Flexio0,
131 DT_CLOCKS_CELL(DT_NODELABEL(flexio), ip_source));
132 #endif
133 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpspi0))
134 CLOCK_SetIpSrc(kCLOCK_Lpspi0,
135 DT_CLOCKS_CELL(DT_NODELABEL(lpspi0), ip_source));
136 #endif
137 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpspi1))
138 CLOCK_SetIpSrc(kCLOCK_Lpspi1,
139 DT_CLOCKS_CELL(DT_NODELABEL(lpspi1), ip_source));
140 #endif
141 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(adc0))
142 CLOCK_SetIpSrc(kCLOCK_Adc0,
143 DT_CLOCKS_CELL(DT_NODELABEL(adc0), ip_source));
144 #endif
145 }
146
soc_early_init_hook(void)147 void soc_early_init_hook(void)
148
149 {
150 /* Initialize system clocks and PLL */
151 clk_init();
152 }
153
154 #ifdef CONFIG_SOC_RESET_HOOK
155
soc_reset_hook(void)156 void soc_reset_hook(void)
157 {
158 /* SystemInit is provided by the NXP SDK */
159 SystemInit();
160 }
161
162 #endif /* CONFIG_SOC_RESET_HOOK */
163