1 /*
2 * Copyright 2024 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 #if CONFIG_USB_DC_NXP_EHCI
12 #include "usb_phy.h"
13 #include "usb.h"
14
15 /* USB PHY condfiguration */
16 #define BOARD_USB_PHY_D_CAL 0x04U
17 #define BOARD_USB_PHY_TXCAL45DP 0x07U
18 #define BOARD_USB_PHY_TXCAL45DM 0x07U
19 #endif
20
21 /* Board xtal frequency in Hz */
22 #define BOARD_XTAL0_CLK_HZ 24000000U
23 /* Core clock frequency: 150MHz */
24 #define CLOCK_INIT_CORE_CLOCK 150000000U
25 /* System clock frequency. */
26 extern uint32_t SystemCoreClock;
27
enable_lpcac(void)28 static void enable_lpcac(void)
29 {
30 SYSCON->LPCAC_CTRL |= SYSCON_LPCAC_CTRL_CLR_LPCAC_MASK;
31 SYSCON->LPCAC_CTRL &= ~(SYSCON_LPCAC_CTRL_CLR_LPCAC_MASK |
32 SYSCON_LPCAC_CTRL_DIS_LPCAC_MASK);
33 }
34
35 /* Update Active mode voltage for OverDrive mode. */
power_mode_od(void)36 void power_mode_od(void)
37 {
38 /* Set the DCDC VDD regulator to 1.2 V voltage level */
39 spc_active_mode_dcdc_option_t opt = {
40 .DCDCVoltage = kSPC_DCDC_OverdriveVoltage,
41 .DCDCDriveStrength = kSPC_DCDC_NormalDriveStrength,
42 };
43 SPC_SetActiveModeDCDCRegulatorConfig(SPC0, &opt);
44
45 /* Set the LDO_CORE VDD regulator to 1.2 V voltage level */
46 spc_active_mode_core_ldo_option_t ldo_opt = {
47 .CoreLDOVoltage = kSPC_CoreLDO_OverDriveVoltage,
48 .CoreLDODriveStrength = kSPC_CoreLDO_NormalDriveStrength,
49 };
50 SPC_SetActiveModeCoreLDORegulatorConfig(SPC0, &ldo_opt);
51
52 /* Specifies the 1.2V operating voltage for the SRAM's read/write timing margin */
53 spc_sram_voltage_config_t cfg = {
54 .operateVoltage = kSPC_sramOperateAt1P2V,
55 .requestVoltageUpdate = true,
56 };
57 SPC_SetSRAMOperateVoltage(SPC0, &cfg);
58 }
59
frdm_mcxn236_init(void)60 static int frdm_mcxn236_init(void)
61 {
62 enable_lpcac();
63
64 power_mode_od();
65
66 /* Enable SCG clock */
67 CLOCK_EnableClock(kCLOCK_Scg);
68
69 /* FRO OSC setup - begin, enable the FRO for safety switching */
70
71 /* Switch to FRO 12M first to ensure we can change the clock setting */
72 CLOCK_AttachClk(kFRO12M_to_MAIN_CLK);
73
74 /* Configure Flash wait-states to support 1.2V voltage level and 150000000Hz frequency */
75 FMU0->FCTRL = (FMU0->FCTRL & ~((uint32_t)FMU_FCTRL_RWSC_MASK)) | (FMU_FCTRL_RWSC(0x3U));
76
77 /* Enable FRO HF(48MHz) output */
78 CLOCK_SetupFROHFClocking(48000000U);
79
80 /* Set up PLL0 */
81 const pll_setup_t pll0Setup = {
82 .pllctrl = SCG_APLLCTRL_SOURCE(1U) | SCG_APLLCTRL_SELI(27U) |
83 SCG_APLLCTRL_SELP(13U),
84 .pllndiv = SCG_APLLNDIV_NDIV(8U),
85 .pllpdiv = SCG_APLLPDIV_PDIV(1U),
86 .pllmdiv = SCG_APLLMDIV_MDIV(50U),
87 .pllRate = 150000000U
88 };
89 /* Configure PLL0 to the desired values */
90 CLOCK_SetPLL0Freq(&pll0Setup);
91 /* PLL0 Monitor is disabled */
92 CLOCK_SetPll0MonitorMode(kSCG_Pll0MonitorDisable);
93
94 /* Switch MAIN_CLK to PLL0 */
95 CLOCK_AttachClk(kPLL0_to_MAIN_CLK);
96
97 /* Set AHBCLKDIV divider to value 1 */
98 CLOCK_SetClkDiv(kCLOCK_DivAhbClk, 1U);
99
100 CLOCK_SetupExtClocking(BOARD_XTAL0_CLK_HZ);
101
102 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(flexcan1))
103 /* Set up PLL1 for 80 MHz FlexCAN clock */
104 const pll_setup_t pll1Setup = {
105 .pllctrl = SCG_SPLLCTRL_SOURCE(1U) | SCG_SPLLCTRL_SELI(27U) |
106 SCG_SPLLCTRL_SELP(13U),
107 .pllndiv = SCG_SPLLNDIV_NDIV(3U),
108 .pllpdiv = SCG_SPLLPDIV_PDIV(1U),
109 .pllmdiv = SCG_SPLLMDIV_MDIV(10U),
110 .pllRate = 80000000U
111 };
112
113 /* Configure PLL1 to the desired values */
114 CLOCK_SetPLL1Freq(&pll1Setup);
115 /* PLL1 Monitor is disabled */
116 CLOCK_SetPll1MonitorMode(kSCG_Pll1MonitorDisable);
117 /* Set PLL1 CLK0 divider to value 1 */
118 CLOCK_SetClkDiv(kCLOCK_DivPLL1Clk0, 1U);
119 #endif
120
121 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(flexcomm1))
122 CLOCK_SetClkDiv(kCLOCK_DivFlexcom1Clk, 1u);
123 CLOCK_AttachClk(kFRO12M_to_FLEXCOMM1);
124 #endif
125
126 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(flexcomm2))
127 CLOCK_SetClkDiv(kCLOCK_DivFlexcom2Clk, 1u);
128 CLOCK_AttachClk(kFRO12M_to_FLEXCOMM2);
129 #endif
130
131 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(flexcomm3))
132 CLOCK_SetClkDiv(kCLOCK_DivFlexcom3Clk, 1u);
133 CLOCK_AttachClk(kFRO12M_to_FLEXCOMM3);
134 #endif
135
136 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(flexcomm4))
137 CLOCK_SetClkDiv(kCLOCK_DivFlexcom4Clk, 1u);
138 CLOCK_AttachClk(kFRO12M_to_FLEXCOMM4);
139 #endif
140
141 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(flexcomm5))
142 CLOCK_SetClkDiv(kCLOCK_DivFlexcom5Clk, 1u);
143 CLOCK_AttachClk(kFRO12M_to_FLEXCOMM5);
144 #endif
145
146 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(os_timer))
147 CLOCK_AttachClk(kCLK_1M_to_OSTIMER);
148 #endif
149
150 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(gpio0))
151 CLOCK_EnableClock(kCLOCK_Gpio0);
152 #endif
153
154 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(gpio1))
155 CLOCK_EnableClock(kCLOCK_Gpio1);
156 #endif
157
158 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(gpio2))
159 CLOCK_EnableClock(kCLOCK_Gpio2);
160 #endif
161
162 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(gpio3))
163 CLOCK_EnableClock(kCLOCK_Gpio3);
164 #endif
165
166 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(gpio4))
167 CLOCK_EnableClock(kCLOCK_Gpio4);
168 #endif
169
170 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(gpio5))
171 CLOCK_EnableClock(kCLOCK_Gpio5);
172 #endif
173
174 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(wwdt0))
175 CLOCK_SetClkDiv(kCLOCK_DivWdt0Clk, 1u);
176 #endif
177
178 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ctimer0))
179 CLOCK_SetClkDiv(kCLOCK_DivCtimer0Clk, 1U);
180 CLOCK_AttachClk(kPLL0_to_CTIMER0);
181 #endif
182
183 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ctimer1))
184 CLOCK_SetClkDiv(kCLOCK_DivCtimer1Clk, 1U);
185 CLOCK_AttachClk(kPLL0_to_CTIMER1);
186 #endif
187
188 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ctimer2))
189 CLOCK_SetClkDiv(kCLOCK_DivCtimer2Clk, 1U);
190 CLOCK_AttachClk(kPLL0_to_CTIMER2);
191 #endif
192
193 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ctimer3))
194 CLOCK_SetClkDiv(kCLOCK_DivCtimer3Clk, 1U);
195 CLOCK_AttachClk(kPLL0_to_CTIMER3);
196 #endif
197
198 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ctimer4))
199 CLOCK_SetClkDiv(kCLOCK_DivCtimer4Clk, 1U);
200 CLOCK_AttachClk(kPLL0_to_CTIMER4);
201 #endif
202
203 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(flexcan1))
204 CLOCK_SetClkDiv(kCLOCK_DivFlexcan1Clk, 1U);
205 CLOCK_AttachClk(kPLL1_CLK0_to_FLEXCAN1);
206 #endif
207
208 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(vref))
209 CLOCK_EnableClock(kCLOCK_Vref);
210 SPC_EnableActiveModeAnalogModules(SPC0, kSPC_controlVref);
211 #endif
212
213 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpadc0))
214 CLOCK_SetClkDiv(kCLOCK_DivAdc0Clk, 1U);
215 CLOCK_AttachClk(kFRO_HF_to_ADC0);
216 #endif
217
218 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(usb1)) && CONFIG_USB_DC_NXP_EHCI
219 usb_phy_config_struct_t usbPhyConfig = {
220 BOARD_USB_PHY_D_CAL, BOARD_USB_PHY_TXCAL45DP, BOARD_USB_PHY_TXCAL45DM,
221 };
222
223 SPC0->ACTIVE_VDELAY = 0x0500;
224 /* Change the power DCDC to 1.8v (By default, DCDC is 1.8V), CORELDO to 1.1v (By default,
225 * CORELDO is 1.0V)
226 */
227 SPC0->ACTIVE_CFG &= ~SPC_ACTIVE_CFG_CORELDO_VDD_DS_MASK;
228 SPC0->ACTIVE_CFG |= SPC_ACTIVE_CFG_DCDC_VDD_LVL(0x3) | SPC_ACTIVE_CFG_CORELDO_VDD_LVL(0x3) |
229 SPC_ACTIVE_CFG_SYSLDO_VDD_DS_MASK | SPC_ACTIVE_CFG_DCDC_VDD_DS(0x2u);
230 /* Wait until it is done */
231 while (SPC0->SC & SPC_SC_BUSY_MASK) {
232 };
233 if ((SCG0->LDOCSR & SCG_LDOCSR_LDOEN_MASK) == 0u) {
234 SCG0->TRIM_LOCK = SCG_TRIM_LOCK_TRIM_LOCK_KEY(0x5a5a) |
235 SCG_TRIM_LOCK_TRIM_UNLOCK_MASK;
236 SCG0->LDOCSR |= SCG_LDOCSR_LDOEN_MASK;
237 /* wait LDO ready */
238 while ((SCG0->LDOCSR & SCG_LDOCSR_VOUT_OK_MASK) == 0u) {
239 };
240 }
241 SYSCON->AHBCLKCTRLSET[2] |= SYSCON_AHBCLKCTRL2_USB_HS_MASK |
242 SYSCON_AHBCLKCTRL2_USB_HS_PHY_MASK;
243 SCG0->SOSCCFG &= ~(SCG_SOSCCFG_RANGE_MASK | SCG_SOSCCFG_EREFS_MASK);
244 /* xtal = 20 ~ 30MHz */
245 SCG0->SOSCCFG = BIT(SCG_SOSCCFG_RANGE_SHIFT) | BIT(SCG_SOSCCFG_EREFS_SHIFT);
246 SCG0->SOSCCSR |= SCG_SOSCCSR_SOSCEN_MASK;
247 while (1) {
248 if (SCG0->SOSCCSR & SCG_SOSCCSR_SOSCVLD_MASK) {
249 break;
250 }
251 }
252 SYSCON->CLOCK_CTRL |= SYSCON_CLOCK_CTRL_CLKIN_ENA_MASK |
253 SYSCON_CLOCK_CTRL_CLKIN_ENA_FM_USBH_LPT_MASK;
254 CLOCK_EnableClock(kCLOCK_UsbHs);
255 CLOCK_EnableClock(kCLOCK_UsbHsPhy);
256 CLOCK_EnableUsbhsPhyPllClock(kCLOCK_Usbphy480M, BOARD_XTAL0_CLK_HZ);
257 CLOCK_EnableUsbhsClock();
258 USB_EhciPhyInit(kUSB_ControllerEhci0, BOARD_XTAL0_CLK_HZ, &usbPhyConfig);
259 #endif
260
261 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpcmp0))
262 CLOCK_SetClkDiv(kCLOCK_DivCmp0FClk, 1U);
263 CLOCK_AttachClk(kFRO12M_to_CMP0F);
264 SPC_EnableActiveModeAnalogModules(SPC0, (kSPC_controlCmp0 | kSPC_controlCmp0Dac));
265 #endif
266
267 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(flexio0))
268 CLOCK_SetClkDiv(kCLOCK_DivFlexioClk, 1u);
269 CLOCK_AttachClk(kPLL0_to_FLEXIO);
270 #endif
271
272 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lptmr0))
273
274 /*
275 * Clock Select Decides what input source the lptmr will clock from
276 *
277 * 0 <- 12MHz FRO
278 * 1 <- 16K FRO
279 * 2 <- 32K OSC
280 * 3 <- Output from the OSC_SYS
281 */
282 #if DT_PROP(DT_NODELABEL(lptmr0), clk_source) == 0x0
283 CLOCK_SetupClockCtrl(kCLOCK_FRO12MHZ_ENA);
284 #elif DT_PROP(DT_NODELABEL(lptmr0), clk_source) == 0x1
285 CLOCK_SetupClk16KClocking(kCLOCK_Clk16KToVsys);
286 #elif DT_PROP(DT_NODELABEL(lptmr0), clk_source) == 0x2
287 CLOCK_SetupOsc32KClocking(kCLOCK_Osc32kToVsys);
288 #elif DT_PROP(DT_NODELABEL(lptmr0), clk_source) == 0x3
289 /* Value here should not exceed 25MHZ when using lptmr */
290 CLOCK_SetupExtClocking(MHZ(24));
291 CLOCK_SetupClockCtrl(kCLOCK_CLKIN_ENA_FM_USBH_LPT);
292 #endif /* DT_PROP(DT_NODELABEL(lptmr0), clk_source) */
293
294 #endif /* DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lptmr0)) */
295
296 /* Set SystemCoreClock variable. */
297 SystemCoreClock = CLOCK_INIT_CORE_CLOCK;
298
299 return 0;
300 }
301
302 SYS_INIT(frdm_mcxn236_init, PRE_KERNEL_1, CONFIG_BOARD_INIT_PRIORITY);
303