1 /*
2  * Copyright 2024-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 <fsl_spc.h>
10 #include <soc.h>
11 
12 /* Core clock frequency: 180MHz */
13 #define CLOCK_INIT_CORE_CLOCK               180000000U
14 #define BOARD_BOOTCLOCKFROHF180M_CORE_CLOCK 180000000U
15 /* System clock frequency. */
16 extern uint32_t SystemCoreClock;
17 
board_early_init_hook(void)18 void board_early_init_hook(void)
19 {
20 	uint32_t coreFreq;
21 	spc_active_mode_core_ldo_option_t ldoOption;
22 	spc_sram_voltage_config_t sramOption;
23 
24 	/* Get the CPU Core frequency */
25 	coreFreq = CLOCK_GetCoreSysClkFreq();
26 
27 	/* The flow of increasing voltage and frequency */
28 	if (coreFreq <= BOARD_BOOTCLOCKFROHF180M_CORE_CLOCK) {
29 		/* Set the LDO_CORE VDD regulator level */
30 		ldoOption.CoreLDOVoltage = kSPC_CoreLDO_OverDriveVoltage;
31 		ldoOption.CoreLDODriveStrength = kSPC_CoreLDO_NormalDriveStrength;
32 		(void)SPC_SetActiveModeCoreLDORegulatorConfig(SPC0, &ldoOption);
33 		/* Configure Flash to support different voltage level and frequency */
34 		FMU0->FCTRL =
35 			(FMU0->FCTRL & ~((uint32_t)FMU_FCTRL_RWSC_MASK)) | (FMU_FCTRL_RWSC(0x4U));
36 		/* Specifies the operating voltage for the SRAM's read/write timing margin */
37 		sramOption.operateVoltage = kSPC_sramOperateAt1P2V;
38 		sramOption.requestVoltageUpdate = true;
39 		(void)SPC_SetSRAMOperateVoltage(SPC0, &sramOption);
40 	}
41 
42 	/*!< Set up system dividers */
43 	CLOCK_SetClockDiv(kCLOCK_DivAHBCLK, 1U); /* !< Set SYSCON.AHBCLKDIV divider to value 1 */
44 	CLOCK_SetClockDiv(kCLOCK_DivFRO_HF, 1U); /* !< Set SYSCON.FROHFDIV divider to value 1 */
45 	CLOCK_SetupFROHFClocking(BOARD_BOOTCLOCKFROHF180M_CORE_CLOCK); /*!< Enable FRO HF */
46 	CLOCK_SetupFRO12MClocking();             /*!< Setup FRO12M clock */
47 
48 	CLOCK_AttachClk(kFRO_HF_to_MAIN_CLK); /* !< Switch MAIN_CLK to kFRO_HF */
49 
50 	/* The flow of decreasing voltage and frequency */
51 	if (coreFreq > BOARD_BOOTCLOCKFROHF180M_CORE_CLOCK) {
52 		/* Configure Flash to support different voltage level and frequency */
53 		FMU0->FCTRL =
54 			(FMU0->FCTRL & ~((uint32_t)FMU_FCTRL_RWSC_MASK)) | (FMU_FCTRL_RWSC(0x4U));
55 		/* Specifies the operating voltage for the SRAM's read/write timing margin */
56 		sramOption.operateVoltage = kSPC_sramOperateAt1P2V;
57 		sramOption.requestVoltageUpdate = true;
58 		(void)SPC_SetSRAMOperateVoltage(SPC0, &sramOption);
59 		/* Set the LDO_CORE VDD regulator level */
60 		ldoOption.CoreLDOVoltage = kSPC_CoreLDO_OverDriveVoltage;
61 		ldoOption.CoreLDODriveStrength = kSPC_CoreLDO_NormalDriveStrength;
62 		(void)SPC_SetActiveModeCoreLDORegulatorConfig(SPC0, &ldoOption);
63 	}
64 
65 	/*!< Set up clock selectors - Attach clocks to the peripheries */
66 	CLOCK_AttachClk(kCPU_CLK_to_TRACE); /* !< Switch TRACE to CPU_CLK */
67 
68 	/*!< Set up dividers */
69 	CLOCK_SetClockDiv(kCLOCK_DivFRO_LF, 1U); /* !< Set SYSCON.FROLFDIV divider to value 1 */
70 	CLOCK_SetClockDiv(kCLOCK_DivWWDT0, 1U);  /* !< Set MRCC.WWDT0_CLKDIV divider to value 1 */
71 	CLOCK_SetClockDiv(kCLOCK_DivTRACE, 2U);  /* !< Set MRCC.TRACE_CLKDIV divider to value 2 */
72 
73 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(porta))
74 	RESET_ReleasePeripheralReset(kPORT0_RST_SHIFT_RSTn);
75 	CLOCK_EnableClock(kCLOCK_GatePORT0);
76 #endif
77 
78 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(portb))
79 	RESET_ReleasePeripheralReset(kPORT1_RST_SHIFT_RSTn);
80 	CLOCK_EnableClock(kCLOCK_GatePORT1);
81 #endif
82 
83 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(portc))
84 	RESET_ReleasePeripheralReset(kPORT2_RST_SHIFT_RSTn);
85 	CLOCK_EnableClock(kCLOCK_GatePORT2);
86 #endif
87 
88 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(portd))
89 	RESET_ReleasePeripheralReset(kPORT3_RST_SHIFT_RSTn);
90 	CLOCK_EnableClock(kCLOCK_GatePORT3);
91 #endif
92 
93 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(porte))
94 	RESET_ReleasePeripheralReset(kPORT4_RST_SHIFT_RSTn);
95 	CLOCK_EnableClock(kCLOCK_GatePORT4);
96 #endif
97 
98 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(gpio0))
99 	RESET_ReleasePeripheralReset(kGPIO0_RST_SHIFT_RSTn);
100 	CLOCK_EnableClock(kCLOCK_GateGPIO0);
101 #endif
102 
103 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(gpio1))
104 	RESET_ReleasePeripheralReset(kGPIO1_RST_SHIFT_RSTn);
105 	CLOCK_EnableClock(kCLOCK_GateGPIO1);
106 #endif
107 
108 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(gpio2))
109 	RESET_ReleasePeripheralReset(kGPIO2_RST_SHIFT_RSTn);
110 	CLOCK_EnableClock(kCLOCK_GateGPIO2);
111 #endif
112 
113 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(gpio3))
114 	RESET_ReleasePeripheralReset(kGPIO3_RST_SHIFT_RSTn);
115 	CLOCK_EnableClock(kCLOCK_GateGPIO3);
116 #endif
117 
118 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(gpio4))
119 	RESET_ReleasePeripheralReset(kGPIO4_RST_SHIFT_RSTn);
120 	CLOCK_EnableClock(kCLOCK_GateGPIO4);
121 #endif
122 
123 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpuart0))
124 	CLOCK_SetClockDiv(kCLOCK_DivLPUART0, 1u);
125 	CLOCK_AttachClk(kFRO_LF_DIV_to_LPUART0);
126 	RESET_ReleasePeripheralReset(kLPUART0_RST_SHIFT_RSTn);
127 #endif
128 
129 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpuart1))
130 	CLOCK_SetClockDiv(kCLOCK_DivLPUART1, 1u);
131 	CLOCK_AttachClk(kFRO_LF_DIV_to_LPUART1);
132 	RESET_ReleasePeripheralReset(kLPUART1_RST_SHIFT_RSTn);
133 #endif
134 
135 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpuart2))
136 	CLOCK_SetClockDiv(kCLOCK_DivLPUART2, 1u);
137 	CLOCK_AttachClk(kFRO_LF_DIV_to_LPUART2);
138 	RESET_ReleasePeripheralReset(kLPUART2_RST_SHIFT_RSTn);
139 #endif
140 
141 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpuart3))
142 	CLOCK_SetClockDiv(kCLOCK_DivLPUART3, 1u);
143 	CLOCK_AttachClk(kFRO_LF_DIV_to_LPUART3);
144 	RESET_ReleasePeripheralReset(kLPUART3_RST_SHIFT_RSTn);
145 #endif
146 
147 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpuart4))
148 	CLOCK_SetClockDiv(kCLOCK_DivLPUART4, 1u);
149 	CLOCK_AttachClk(kFRO_LF_DIV_to_LPUART4);
150 	RESET_ReleasePeripheralReset(kLPUART4_RST_SHIFT_RSTn);
151 #endif
152 
153 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(edma0))
154 	RESET_ReleasePeripheralReset(kDMA0_RST_SHIFT_RSTn);
155 #endif
156 
157 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(wwdt0))
158 	CLOCK_SetClockDiv(kCLOCK_DivWWDT0, 1u);
159 #endif
160 
161 
162 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ctimer0))
163 	CLOCK_SetClockDiv(kCLOCK_DivCTIMER0, 1u);
164 	CLOCK_AttachClk(kFRO_LF_DIV_to_CTIMER0);
165 #endif
166 
167 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ctimer1))
168 	CLOCK_SetClockDiv(kCLOCK_DivCTIMER1, 1u);
169 	CLOCK_AttachClk(kFRO_LF_DIV_to_CTIMER1);
170 #endif
171 
172 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ctimer2))
173 	CLOCK_SetClockDiv(kCLOCK_DivCTIMER2, 1u);
174 	CLOCK_AttachClk(kFRO_LF_DIV_to_CTIMER2);
175 #endif
176 
177 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ctimer3))
178 	CLOCK_SetClockDiv(kCLOCK_DivCTIMER3, 1u);
179 	CLOCK_AttachClk(kFRO_LF_DIV_to_CTIMER3);
180 #endif
181 
182 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ctimer4))
183 	CLOCK_SetClockDiv(kCLOCK_DivCTIMER4, 1u);
184 	CLOCK_AttachClk(kFRO_LF_DIV_to_CTIMER4);
185 #endif
186 
187 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(wwdt0))
188 	CLOCK_SetClockDiv(kCLOCK_DivWWDT0, 1u);
189 #endif
190 
191 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpadc0)) || DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpadc1))
192 	CLOCK_SetClockDiv(kCLOCK_DivADC, 1u);
193 	CLOCK_AttachClk(kFRO_LF_DIV_to_ADC);
194 
195 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(i3c0))
196 	CLOCK_SetClockDiv(kCLOCK_DivI3C0_FCLK, 15U);
197 	CLOCK_AttachClk(kFRO_HF_DIV_to_I3C0FCLK);
198 #endif
199 
200 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpadc0))
201 	CLOCK_EnableClock(kCLOCK_GateADC0);
202 #endif
203 
204 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpadc1))
205 	CLOCK_EnableClock(kCLOCK_GateADC1);
206 #endif
207 
208 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpcmp0))
209 	CLOCK_AttachClk(kFRO_LF_DIV_to_CMP0);
210 	CLOCK_SetClockDiv(kCLOCK_DivCMP0_FUNC, 1U);
211 	SPC_EnableActiveModeAnalogModules(SPC0, (kSPC_controlCmp0 | kSPC_controlCmp0Dac));
212 #endif
213 
214 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpcmp1))
215 	CLOCK_AttachClk(kFRO_LF_DIV_to_CMP1);
216 	CLOCK_SetClockDiv(kCLOCK_DivCMP1_FUNC, 1U);
217 	SPC_EnableActiveModeAnalogModules(SPC0, (kSPC_controlCmp1 | kSPC_controlCmp1Dac));
218 #endif
219 
220 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpcmp2))
221 	CLOCK_AttachClk(kFRO_LF_DIV_to_CMP2);
222 	CLOCK_SetClockDiv(kCLOCK_DivCMP2_FUNC, 1U);
223 	SPC_EnableActiveModeAnalogModules(SPC0, (kSPC_controlCmp2 | kSPC_controlCmp2Dac));
224 #endif
225 
226 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpi2c0))
227 	CLOCK_SetClockDiv(kCLOCK_DivLPI2C0, 1u);
228 	CLOCK_AttachClk(kFRO_LF_DIV_to_LPI2C0);
229 #endif
230 
231 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpi2c1))
232 	CLOCK_SetClockDiv(kCLOCK_DivLPI2C1, 1u);
233 	CLOCK_AttachClk(kFRO_LF_DIV_to_LPI2C1);
234 #endif
235 
236 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpi2c2))
237 	CLOCK_SetClockDiv(kCLOCK_DivLPI2C2, 1u);
238 	CLOCK_AttachClk(kFRO_LF_DIV_to_LPI2C2);
239 #endif
240 
241 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpi2c3))
242 	CLOCK_SetClockDiv(kCLOCK_DivLPI2C3, 1u);
243 	CLOCK_AttachClk(kFRO_LF_DIV_to_LPI2C3);
244 #endif
245 
246 #endif
247 
248 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpspi0))
249 	/* Configure input clock to be able to reach the datasheet specified band rate. */
250 	CLOCK_SetClockDiv(kCLOCK_DivLPSPI0, 1u);
251 	CLOCK_AttachClk(kFRO_LF_DIV_to_LPSPI0);
252 #endif
253 
254 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpspi1))
255 	/* Configure input clock to be able to reach the datasheet specified band rate. */
256 	CLOCK_SetClockDiv(kCLOCK_DivLPSPI1, 1u);
257 	CLOCK_AttachClk(kFRO_LF_DIV_to_LPSPI1);
258 #endif
259 
260 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ostimer0))
261 	CLOCK_AttachClk(kCLK_1M_to_OSTIMER);
262 #endif
263 
264 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lptmr0))
265 
266 /*
267  * Clock Select Decides what input source the lptmr will clock from
268  *
269  * 0 <- Reserved
270  * 1 <- 16K FRO
271  * 2 <- Reserved
272  * 3 <- Combination of clocks configured in MRCC_LPTMR0_CLKSEL[MUX] field
273  */
274 #if DT_PROP(DT_NODELABEL(lptmr0), clk_source) == 0x1
275 	CLOCK_SetupFRO16KClocking(kCLKE_16K_SYSTEM | kCLKE_16K_COREMAIN);
276 #elif DT_PROP(DT_NODELABEL(lptmr0), clk_source) == 0x3
277 	CLOCK_AttachClk(kFRO_LF_DIV_to_LPTMR0);
278 	CLOCK_SetClockDiv(kCLOCK_DivLPTMR0, 1u);
279 #endif /* DT_PROP(DT_NODELABEL(lptmr0), clk_source) */
280 
281 #endif
282 
283 	/* Set SystemCoreClock variable. */
284 	SystemCoreClock = CLOCK_INIT_CORE_CLOCK;
285 }
286