|
| 1 | +/* |
| 2 | + * Copyright 2025 NXP |
| 3 | + * SPDX-License-Identifier: Apache-2.0 |
| 4 | + */ |
| 5 | +#include <zephyr/init.h> |
| 6 | +#include <zephyr/device.h> |
| 7 | +#include <zephyr/dt-bindings/clock/mcux_lpc_syscon_clock.h> |
| 8 | +#include <fsl_clock.h> |
| 9 | +#include <soc.h> |
| 10 | + |
| 11 | +/******************************************************************************* |
| 12 | + * Definitions |
| 13 | + ******************************************************************************/ |
| 14 | +#define ASSERT_WITHIN_RANGE(val, min, max, str) \ |
| 15 | + BUILD_ASSERT(val >= min && val <= max, str) |
| 16 | + |
| 17 | +#define ASSERT_ASYNC_CLK_DIV_VALID(val, str) \ |
| 18 | + BUILD_ASSERT(val == 0 || val == 1 || val == 2 || val == 4 || \ |
| 19 | + val == 8 || val == 16 || val == 2 || val == 64, str) |
| 20 | + |
| 21 | +#define kSCG_AsyncClkDivBy0 kSCG_AsyncClkDisable |
| 22 | + |
| 23 | +#define TO_SYS_CLK_DIV(val) _DO_CONCAT(kSCG_SysClkDivBy, val) |
| 24 | +#define TO_ASYNC_CLK_DIV(val) _DO_CONCAT(kSCG_AsyncClkDivBy, val) |
| 25 | + |
| 26 | +#define SCG_CLOCK_NODE(name) DT_CHILD(DT_INST(0, nxp_kinetis_scg), name) |
| 27 | +#define SCG_CLOCK_DIV(name) DT_PROP(SCG_CLOCK_NODE(name), clock_div) |
| 28 | +#define SCG_CLOCK_MULT(name) DT_PROP(SCG_CLOCK_NODE(name), clock_mult) |
| 29 | + |
| 30 | +/* System Clock configuration */ |
| 31 | +ASSERT_WITHIN_RANGE(SCG_CLOCK_DIV(slow_clk), 2, 8, |
| 32 | + "Invalid SCG slow clock divider value"); |
| 33 | +ASSERT_WITHIN_RANGE(SCG_CLOCK_DIV(bus_clk), 1, 16, |
| 34 | + "Invalid SCG bus clock divider value"); |
| 35 | +ASSERT_WITHIN_RANGE(SCG_CLOCK_DIV(core_clk), 1, 16, |
| 36 | + "Invalid SCG core clock divider value"); |
| 37 | + |
| 38 | +/******************************************************************************* |
| 39 | + * Variables |
| 40 | + ******************************************************************************/ |
| 41 | + |
| 42 | +static const scg_sys_clk_config_t scg_sys_clk_config = { |
| 43 | + .divSlow = TO_SYS_CLK_DIV(SCG_CLOCK_DIV(slow_clk)), |
| 44 | + .divBus = TO_SYS_CLK_DIV(SCG_CLOCK_DIV(bus_clk)), |
| 45 | + .divCore = TO_SYS_CLK_DIV(SCG_CLOCK_DIV(core_clk)), |
| 46 | +#if DT_SAME_NODE(DT_CLOCKS_CTLR(SCG_CLOCK_NODE(core_clk)), SCG_CLOCK_NODE(sosc_clk)) |
| 47 | + .src = kSCG_SysClkSrcSysOsc, |
| 48 | +#elif DT_SAME_NODE(DT_CLOCKS_CTLR(SCG_CLOCK_NODE(core_clk)), SCG_CLOCK_NODE(sirc_clk)) |
| 49 | + .src = kSCG_SysClkSrcSirc, |
| 50 | +#elif DT_SAME_NODE(DT_CLOCKS_CTLR(SCG_CLOCK_NODE(core_clk)), SCG_CLOCK_NODE(firc_clk)) |
| 51 | + .src = kSCG_SysClkSrcFirc, |
| 52 | +#elif DT_SAME_NODE(DT_CLOCKS_CTLR(SCG_CLOCK_NODE(core_clk)), SCG_CLOCK_NODE(spll_clk)) |
| 53 | + .src = kSCG_SysClkSrcSysPll, |
| 54 | +#else |
| 55 | +#error Invalid SCG core clock source |
| 56 | +#endif |
| 57 | +}; |
| 58 | + |
| 59 | +#if DT_NODE_HAS_STATUS_OKAY(SCG_CLOCK_NODE(sosc_clk)) |
| 60 | +/* System Oscillator (SOSC) configuration */ |
| 61 | +ASSERT_ASYNC_CLK_DIV_VALID(SCG_CLOCK_DIV(soscdiv1_clk), |
| 62 | + "Invalid SCG SOSC divider 1 value"); |
| 63 | +ASSERT_ASYNC_CLK_DIV_VALID(SCG_CLOCK_DIV(soscdiv2_clk), |
| 64 | + "Invalid SCG SOSC divider 2 value"); |
| 65 | +static const scg_sosc_config_t scg_sosc_config = { |
| 66 | + .freq = DT_PROP(SCG_CLOCK_NODE(sosc_clk), clock_frequency), |
| 67 | + .monitorMode = kSCG_SysOscMonitorDisable, |
| 68 | + .enableMode = kSCG_SysOscEnable, |
| 69 | + .div1 = TO_ASYNC_CLK_DIV(SCG_CLOCK_DIV(soscdiv1_clk)), |
| 70 | + .div2 = TO_ASYNC_CLK_DIV(SCG_CLOCK_DIV(soscdiv2_clk)), |
| 71 | + .workMode = DT_PROP(DT_INST(0, nxp_kinetis_scg), sosc_mode) |
| 72 | +}; |
| 73 | +#endif /* DT_NODE_HAS_STATUS_OKAY(SCG_CLOCK_NODE(sosc_clk)) */ |
| 74 | + |
| 75 | +/* Slow Internal Reference Clock (SIRC) configuration */ |
| 76 | +ASSERT_ASYNC_CLK_DIV_VALID(SCG_CLOCK_DIV(sircdiv1_clk), |
| 77 | + "Invalid SCG SIRC divider 1 value"); |
| 78 | +ASSERT_ASYNC_CLK_DIV_VALID(SCG_CLOCK_DIV(sircdiv2_clk), |
| 79 | + "Invalid SCG SIRC divider 2 value"); |
| 80 | +static const scg_sirc_config_t scg_sirc_config = { |
| 81 | + .enableMode = kSCG_SircEnable | kSCG_SircEnableInLowPower, |
| 82 | + .div1 = TO_ASYNC_CLK_DIV(SCG_CLOCK_DIV(sircdiv1_clk)), |
| 83 | + .div2 = TO_ASYNC_CLK_DIV(SCG_CLOCK_DIV(sircdiv2_clk)), |
| 84 | +#if MHZ(8) == DT_PROP(SCG_CLOCK_NODE(sirc_clk), clock_frequency) |
| 85 | + .range = kSCG_SircRangeHigh |
| 86 | +#else |
| 87 | +#error Invalid SCG SIRC clock frequency |
| 88 | +#endif |
| 89 | +}; |
| 90 | + |
| 91 | +/* Fast Internal Reference Clock (FIRC) configuration */ |
| 92 | +ASSERT_ASYNC_CLK_DIV_VALID(SCG_CLOCK_DIV(fircdiv1_clk), |
| 93 | + "Invalid SCG FIRC divider 1 value"); |
| 94 | +ASSERT_ASYNC_CLK_DIV_VALID(SCG_CLOCK_DIV(fircdiv2_clk), |
| 95 | + "Invalid SCG FIRC divider 2 value"); |
| 96 | +static const scg_firc_config_t scg_firc_config = { |
| 97 | + .enableMode = kSCG_FircEnable, |
| 98 | + .div1 = TO_ASYNC_CLK_DIV(SCG_CLOCK_DIV(fircdiv1_clk)), |
| 99 | + .div2 = TO_ASYNC_CLK_DIV(SCG_CLOCK_DIV(fircdiv2_clk)), |
| 100 | +#if MHZ(48) == DT_PROP(SCG_CLOCK_NODE(firc_clk), clock_frequency) |
| 101 | + .range = kSCG_FircRange48M, |
| 102 | +#else |
| 103 | +#error Invalid SCG FIRC clock frequency |
| 104 | +#endif |
| 105 | + .trimConfig = NULL |
| 106 | +}; |
| 107 | + |
| 108 | +/* System Phase-Locked Loop (SPLL) configuration */ |
| 109 | +ASSERT_WITHIN_RANGE(SCG_CLOCK_DIV(spll_clk), 2, 2, |
| 110 | + "Invalid SCG SPLL fixed divider value"); |
| 111 | +ASSERT_ASYNC_CLK_DIV_VALID(SCG_CLOCK_DIV(splldiv1_clk), |
| 112 | + "Invalid SCG SPLL divider 1 value"); |
| 113 | +ASSERT_ASYNC_CLK_DIV_VALID(SCG_CLOCK_DIV(splldiv2_clk), |
| 114 | + "Invalid SCG SPLL divider 2 value"); |
| 115 | +ASSERT_WITHIN_RANGE(SCG_CLOCK_DIV(pll), 1, 8, |
| 116 | + "Invalid SCG PLL pre divider value"); |
| 117 | +ASSERT_WITHIN_RANGE(SCG_CLOCK_MULT(pll), 16, 47, |
| 118 | + "Invalid SCG PLL multiplier value"); |
| 119 | +#if (DT_NODE_HAS_STATUS_OKAY(SCG_CLOCK_NODE(sosc_clk)) && \ |
| 120 | + DT_NODE_HAS_STATUS_OKAY(SCG_CLOCK_NODE(spll_clk))) |
| 121 | +static const scg_spll_config_t scg_spll_config = { |
| 122 | + .enableMode = kSCG_SysPllEnable, |
| 123 | + .monitorMode = kSCG_SysPllMonitorDisable, |
| 124 | + .div1 = TO_ASYNC_CLK_DIV(SCG_CLOCK_DIV(splldiv1_clk)), |
| 125 | + .div2 = TO_ASYNC_CLK_DIV(SCG_CLOCK_DIV(splldiv2_clk)), |
| 126 | +#if !DT_SAME_NODE(DT_CLOCKS_CTLR(SCG_CLOCK_NODE(pll)), SCG_CLOCK_NODE(sosc_clk)) |
| 127 | +#error Invalid SCG PLL clock source |
| 128 | +#endif |
| 129 | + .prediv = (SCG_CLOCK_DIV(pll) - 1U), |
| 130 | + .mult = (SCG_CLOCK_MULT(pll) - 16U) |
| 131 | +}; |
| 132 | +#endif |
| 133 | + |
| 134 | +__weak void clock_init(void) |
| 135 | +{ |
| 136 | + scg_sys_clk_config_t current; |
| 137 | + |
| 138 | + const scg_sys_clk_config_t scg_sys_clk_config_safe = { |
| 139 | + .divSlow = kSCG_SysClkDivBy4, |
| 140 | + .divBus = kSCG_SysClkDivBy1, |
| 141 | + .divCore = kSCG_SysClkDivBy1, |
| 142 | + .src = kSCG_SysClkSrcSirc |
| 143 | + }; |
| 144 | + |
| 145 | +#if DT_NODE_HAS_STATUS_OKAY(SCG_CLOCK_NODE(sosc_clk)) |
| 146 | + /* Optionally initialize system oscillator */ |
| 147 | + CLOCK_InitSysOsc(&scg_sosc_config); |
| 148 | + CLOCK_SetXtal0Freq(scg_sosc_config.freq); |
| 149 | +#endif |
| 150 | + |
| 151 | + /* Configure SIRC */ |
| 152 | + CLOCK_InitSirc(&scg_sirc_config); |
| 153 | + |
| 154 | + /* Temporary switch to safe SIRC in order to configure FIRC */ |
| 155 | + CLOCK_SetRunModeSysClkConfig(&scg_sys_clk_config_safe); |
| 156 | + do { |
| 157 | + CLOCK_GetCurSysClkConfig(¤t); |
| 158 | + } while (current.src != scg_sys_clk_config_safe.src); |
| 159 | + CLOCK_InitFirc(&scg_firc_config); |
| 160 | + |
| 161 | + #if (DT_NODE_HAS_STATUS_OKAY(SCG_CLOCK_NODE(sosc_clk)) && \ |
| 162 | + DT_NODE_HAS_STATUS_OKAY(SCG_CLOCK_NODE(spll_clk))) |
| 163 | + /* Configure System PLL only if system oscilator is initialized */ |
| 164 | + /* as the oscillator is the only SPLL clock source.*/ |
| 165 | + CLOCK_InitSysPll(&scg_spll_config); |
| 166 | + #endif |
| 167 | + |
| 168 | + /* Only RUN mode supported for now */ |
| 169 | + CLOCK_SetRunModeSysClkConfig(&scg_sys_clk_config); |
| 170 | + do { |
| 171 | + CLOCK_GetCurSysClkConfig(¤t); |
| 172 | + } while (current.src != scg_sys_clk_config.src); |
| 173 | + |
| 174 | +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpuart0)) |
| 175 | + CLOCK_SetIpSrc(kCLOCK_Lpuart0, |
| 176 | + DT_CLOCKS_CELL(DT_NODELABEL(lpuart0), ip_source)); |
| 177 | +#endif |
| 178 | +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpuart1)) |
| 179 | + CLOCK_SetIpSrc(kCLOCK_Lpuart1, |
| 180 | + DT_CLOCKS_CELL(DT_NODELABEL(lpuart1), ip_source)); |
| 181 | +#endif |
| 182 | +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpuart2)) |
| 183 | + CLOCK_SetIpSrc(kCLOCK_Lpuart2, |
| 184 | + DT_CLOCKS_CELL(DT_NODELABEL(lpuart2), ip_source)); |
| 185 | +#endif |
| 186 | +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpi2c0)) |
| 187 | + CLOCK_SetIpSrc(kCLOCK_Lpi2c0, |
| 188 | + DT_CLOCKS_CELL(DT_NODELABEL(lpi2c0), ip_source)); |
| 189 | +#endif |
| 190 | +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpi2c1)) |
| 191 | + CLOCK_SetIpSrc(kCLOCK_Lpi2c1, |
| 192 | + DT_CLOCKS_CELL(DT_NODELABEL(lpi2c1), ip_source)); |
| 193 | +#endif |
| 194 | +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpspi0)) |
| 195 | + CLOCK_SetIpSrc(kCLOCK_Lpspi0, |
| 196 | + DT_CLOCKS_CELL(DT_NODELABEL(lpspi0), ip_source)); |
| 197 | +#endif |
| 198 | +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpspi1)) |
| 199 | + CLOCK_SetIpSrc(kCLOCK_Lpspi1, |
| 200 | + DT_CLOCKS_CELL(DT_NODELABEL(lpspi1), ip_source)); |
| 201 | +#endif |
| 202 | +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpspi2)) |
| 203 | + CLOCK_SetIpSrc(kCLOCK_Lpspi2, |
| 204 | + DT_CLOCKS_CELL(DT_NODELABEL(lpspi2), ip_source)); |
| 205 | +#endif |
| 206 | +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(adc0)) |
| 207 | + CLOCK_SetIpSrc(kCLOCK_Adc0 |
| 208 | + DT_CLOCKS_CELL(DT_NODELABEL(adc0), ip_source)); |
| 209 | +#endif |
| 210 | +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(adc1)) |
| 211 | + CLOCK_SetIpSrc(kCLOCK_Adc1, |
| 212 | + DT_CLOCKS_CELL(DT_NODELABEL(adc1), ip_source)); |
| 213 | +#endif |
| 214 | +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ftm0)) |
| 215 | + CLOCK_SetIpSrc(kCLOCK_Ftm0, |
| 216 | + DT_CLOCKS_CELL(DT_NODELABEL(ftm0), ip_source)); |
| 217 | +#endif |
| 218 | +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ftm1)) |
| 219 | + CLOCK_SetIpSrc(kCLOCK_Ftm1, |
| 220 | + DT_CLOCKS_CELL(DT_NODELABEL(ftm1), ip_source)); |
| 221 | +#endif |
| 222 | +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ftm2)) |
| 223 | + CLOCK_SetIpSrc(kCLOCK_Ftm2, |
| 224 | + DT_CLOCKS_CELL(DT_NODELABEL(ftm2), ip_source)); |
| 225 | +#endif |
| 226 | +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ftm3)) |
| 227 | + CLOCK_SetIpSrc(kCLOCK_Ftm3, |
| 228 | + DT_CLOCKS_CELL(DT_NODELABEL(ftm3), ip_source)); |
| 229 | +#endif |
| 230 | +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ftm4)) |
| 231 | + CLOCK_SetIpSrc(kCLOCK_Ftm4, |
| 232 | + DT_CLOCKS_CELL(DT_NODELABEL(ftm4), ip_source)); |
| 233 | +#endif |
| 234 | +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ftm5)) |
| 235 | + CLOCK_SetIpSrc(kCLOCK_Ftm5, |
| 236 | + DT_CLOCKS_CELL(DT_NODELABEL(ftm5), ip_source)); |
| 237 | +#endif |
| 238 | +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ftm6)) |
| 239 | + CLOCK_SetIpSrc(kCLOCK_Ftm6, |
| 240 | + DT_CLOCKS_CELL(DT_NODELABEL(ftm6), ip_source)); |
| 241 | +#endif |
| 242 | +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ftm7)) |
| 243 | + CLOCK_SetIpSrc(kCLOCK_Ftm7, |
| 244 | + DT_CLOCKS_CELL(DT_NODELABEL(ftm7), ip_source)); |
| 245 | +#endif |
| 246 | +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ewm0)) |
| 247 | + CLOCK_SetIpSrc(kCLOCK_Ewm0, |
| 248 | + DT_CLOCKS_CELL(DT_NODELABEL(ewm0), ip_source)); |
| 249 | +#endif |
| 250 | +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(flexio0)) |
| 251 | + CLOCK_SetIpSrc(kCLOCK_Flexio0, |
| 252 | + DT_CLOCKS_CELL(DT_NODELABEL(flexio0), ip_source)); |
| 253 | +#endif |
| 254 | +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(enet_ptp_clock)) |
| 255 | + CLOCK_SetIpSrc(kCLOCK_Enet, |
| 256 | + DT_CLOCKS_CELL(DT_NODELABEL(enet_ptp_clock), ip_source)); |
| 257 | +#endif |
| 258 | +} |
| 259 | + |
| 260 | +void board_early_init_hook(void) |
| 261 | +{ |
| 262 | +#if !defined(CONFIG_ARM_MPU) |
| 263 | + uint32_t temp_reg; |
| 264 | +#endif /* !CONFIG_ARM_MPU */ |
| 265 | + |
| 266 | +#if !defined(CONFIG_ARM_MPU) |
| 267 | + /* |
| 268 | + * Disable memory protection and clear slave port errors. |
| 269 | + * MCXE24x does not implement the optional ARMv7-M memory |
| 270 | + * protection unit (MPU), specified by the architecture (PMSAv7), in the |
| 271 | + * Cortex-M4 core. Instead, the processor includes its own MPU module. |
| 272 | + */ |
| 273 | + temp_reg = SYSMPU->CESR; |
| 274 | + temp_reg &= ~SYSMPU_CESR_VLD_MASK; |
| 275 | + temp_reg |= SYSMPU_CESR_SPERR_MASK; |
| 276 | + SYSMPU->CESR = temp_reg; |
| 277 | +#endif /* !CONFIG_ARM_MPU */ |
| 278 | + |
| 279 | + clock_init(); |
| 280 | +} |
0 commit comments