1 /*
2  * Copyright  2017-2023 NXP
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <zephyr/device.h>
9 #include <zephyr/init.h>
10 #include <soc.h>
11 #include <zephyr/linker/sections.h>
12 #include <zephyr/linker/linker-defs.h>
13 #include <zephyr/cache.h>
14 #include <fsl_clock.h>
15 #ifdef CONFIG_NXP_IMXRT_BOOT_HEADER
16 #include <fsl_flexspi_nor_boot.h>
17 #endif
18 #include <zephyr/dt-bindings/clock/imx_ccm.h>
19 #include <fsl_iomuxc.h>
20 #if CONFIG_USB_DC_NXP_EHCI
21 #include "usb_phy.h"
22 #include "usb.h"
23 #endif
24 
25 #include "memc_nxp_flexram.h"
26 
27 #include <cmsis_core.h>
28 
29 #define CCM_NODE	DT_INST(0, nxp_imx_ccm)
30 
31 #define BUILD_ASSERT_PODF_IN_RANGE(podf, a, b)				\
32 	BUILD_ASSERT(DT_PROP(DT_CHILD(CCM_NODE, podf), clock_div) >= (a) && \
33 		     DT_PROP(DT_CHILD(CCM_NODE, podf), clock_div) <= (b), \
34 		     #podf " is out of supported range (" #a ", " #b ")")
35 
36 #ifdef CONFIG_INIT_ARM_PLL
37 /* ARM PLL configuration for RUN mode */
38 const clock_arm_pll_config_t armPllConfig = {
39 	.loopDivider = 100U
40 };
41 #endif
42 
43 #if CONFIG_INIT_SYS_PLL
44 /* Configure System PLL */
45 const clock_sys_pll_config_t sysPllConfig = {
46 	.loopDivider = (DT_PROP(DT_CHILD(CCM_NODE, sys_pll), loop_div) - 20) / 2,
47 	.numerator = DT_PROP(DT_CHILD(CCM_NODE, sys_pll), numerator),
48 	.denominator = DT_PROP(DT_CHILD(CCM_NODE, sys_pll), denominator),
49 	.src = DT_PROP(DT_CHILD(CCM_NODE, sys_pll), src),
50 };
51 #endif
52 
53 #if CONFIG_USB_DC_NXP_EHCI
54 /* USB PHY configuration */
55 #define BOARD_USB_PHY_D_CAL (0x0CU)
56 #define BOARD_USB_PHY_TXCAL45DP (0x06U)
57 #define BOARD_USB_PHY_TXCAL45DM (0x06U)
58 #endif
59 
60 #ifdef CONFIG_INIT_ENET_PLL
61 /* ENET PLL configuration for RUN mode */
62 const clock_enet_pll_config_t ethPllConfig = {
63 #if defined(CONFIG_SOC_MIMXRT1011) || \
64 	defined(CONFIG_SOC_MIMXRT1015) || \
65 	defined(CONFIG_SOC_MIMXRT1021) || \
66 	defined(CONFIG_SOC_MIMXRT1024)
67 	.enableClkOutput500M = true,
68 #endif
69 #if defined(CONFIG_ETH_NXP_ENET)
70 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(enet))
71 	.enableClkOutput = true,
72 #endif
73 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(enet2))
74 	.enableClkOutput1 = true,
75 #endif
76 #endif
77 #if defined(CONFIG_PTP_CLOCK_NXP_ENET)
78 	.enableClkOutput25M = true,
79 #else
80 	.enableClkOutput25M = false,
81 #endif
82 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(enet))
83 	.loopDivider = 1,
84 #endif
85 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(enet2))
86 	.loopDivider1 = 1,
87 #endif
88 };
89 #endif
90 
91 #if CONFIG_USB_DC_NXP_EHCI
92 	usb_phy_config_struct_t usbPhyConfig = {
93 		BOARD_USB_PHY_D_CAL, BOARD_USB_PHY_TXCAL45DP, BOARD_USB_PHY_TXCAL45DM,
94 	};
95 #endif
96 
97 #ifdef CONFIG_INIT_VIDEO_PLL
98 const clock_video_pll_config_t videoPllConfig = {
99 	.loopDivider = 31,
100 	.postDivider = 8,
101 	.numerator = 0,
102 	.denominator = 0,
103 };
104 #endif
105 
106 #ifdef CONFIG_NXP_IMXRT_BOOT_HEADER
107 const __imx_boot_data_section BOOT_DATA_T boot_data = {
108 #ifdef CONFIG_XIP
109 	.start = CONFIG_FLASH_BASE_ADDRESS,
110 	.size = (uint32_t)&_flash_used,
111 #else
112 	.start = CONFIG_SRAM_BASE_ADDRESS,
113 	.size = (uint32_t)&_image_ram_size,
114 #endif
115 	.plugin = PLUGIN_FLAG,
116 	.placeholder = 0xFFFFFFFF,
117 };
118 
119 const __imx_boot_ivt_section ivt image_vector_table = {
120 	.hdr = IVT_HEADER,
121 	.entry = (uint32_t) _vector_start,
122 	.reserved1 = IVT_RSVD,
123 #ifdef CONFIG_DEVICE_CONFIGURATION_DATA
124 	.dcd = (uint32_t) dcd_data,
125 #else
126 	.dcd = (uint32_t) NULL,
127 #endif
128 	.boot_data = (uint32_t) &boot_data,
129 	.self = (uint32_t) &image_vector_table,
130 	.csf = (uint32_t)CSF_ADDRESS,
131 	.reserved2 = IVT_RSVD,
132 };
133 #endif
134 
135 /**
136  * @brief Initialize the system clock
137  */
clock_init(void)138 __weak void clock_init(void)
139 {
140 	/* Boot ROM did initialize the XTAL, here we only sets external XTAL
141 	 * OSC freq
142 	 */
143 	CLOCK_SetXtalFreq(DT_PROP(DT_CLOCKS_CTLR_BY_NAME(CCM_NODE, xtal),
144 				  clock_frequency));
145 	CLOCK_SetRtcXtalFreq(DT_PROP(DT_CLOCKS_CTLR_BY_NAME(CCM_NODE, rtc_xtal),
146 				     clock_frequency));
147 
148 	/* Set PERIPH_CLK2 MUX to OSC */
149 	CLOCK_SetMux(kCLOCK_PeriphClk2Mux, 0x1);
150 
151 	/* Set PERIPH_CLK MUX to PERIPH_CLK2 */
152 	CLOCK_SetMux(kCLOCK_PeriphMux, 0x1);
153 
154 #if CONFIG_ADJUST_DCDC
155 	/* Setting the VDD_SOC value */
156 	DCDC->REG3 = (DCDC->REG3 & (~DCDC_REG3_TRG_MASK)) | DCDC_REG3_TRG(CONFIG_DCDC_VALUE);
157 	/* Waiting for DCDC_STS_DC_OK bit is asserted */
158 	while (DCDC_REG0_STS_DC_OK_MASK !=
159 			(DCDC_REG0_STS_DC_OK_MASK & DCDC->REG0)) {
160 		;
161 	}
162 #endif
163 
164 #ifdef CONFIG_INIT_ARM_PLL
165 	CLOCK_InitArmPll(&armPllConfig); /* Configure ARM PLL to 1200M */
166 #endif
167 #ifdef CONFIG_INIT_ENET_PLL
168 	CLOCK_InitEnetPll(ðPllConfig);
169 #endif
170 #ifdef CONFIG_INIT_VIDEO_PLL
171 	CLOCK_InitVideoPll(&videoPllConfig);
172 #endif
173 
174 #if CONFIG_INIT_SYS_PLL
175 	CLOCK_InitSysPll(&sysPllConfig);
176 #endif
177 
178 #if DT_NODE_EXISTS(DT_CHILD(CCM_NODE, arm_podf))
179 	/* Set ARM PODF */
180 	BUILD_ASSERT_PODF_IN_RANGE(arm_podf, 1, 8);
181 	CLOCK_SetDiv(kCLOCK_ArmDiv, DT_PROP(DT_CHILD(CCM_NODE, arm_podf), clock_div) - 1);
182 #endif
183 	/* Set AHB PODF */
184 	BUILD_ASSERT_PODF_IN_RANGE(ahb_podf, 1, 8);
185 	CLOCK_SetDiv(kCLOCK_AhbDiv, DT_PROP(DT_CHILD(CCM_NODE, ahb_podf), clock_div) - 1);
186 	/* Set IPG PODF */
187 	BUILD_ASSERT_PODF_IN_RANGE(ipg_podf, 1, 4);
188 	CLOCK_SetDiv(kCLOCK_IpgDiv, DT_PROP(DT_CHILD(CCM_NODE, ipg_podf), clock_div) - 1);
189 
190 #ifdef CONFIG_SOC_MIMXRT1042
191 	/* Set PRE_PERIPH_CLK to SYS_PLL */
192 	CLOCK_SetMux(kCLOCK_PrePeriphMux, 0x0);
193 #else
194 	/* Set PRE_PERIPH_CLK to PLL1, 1200M */
195 	CLOCK_SetMux(kCLOCK_PrePeriphMux, 0x3);
196 #endif
197 
198 	/* Set PERIPH_CLK MUX to PRE_PERIPH_CLK */
199 	CLOCK_SetMux(kCLOCK_PeriphMux, 0x0);
200 
201 #ifdef CONFIG_UART_MCUX_LPUART
202 	/* Configure UART divider to default */
203 	CLOCK_SetMux(kCLOCK_UartMux, 0); /* Set UART source to PLL3 80M */
204 	CLOCK_SetDiv(kCLOCK_UartDiv, 0); /* Set UART divider to 1 */
205 #endif
206 
207 #ifdef CONFIG_I2C_MCUX_LPI2C
208 	CLOCK_SetMux(kCLOCK_Lpi2cMux, 0); /* Set I2C source as USB1 PLL 480M */
209 	CLOCK_SetDiv(kCLOCK_Lpi2cDiv, 5); /* Set I2C divider to 6 */
210 #endif
211 
212 #ifdef CONFIG_SPI_MCUX_LPSPI
213 	/* Configure input clock to be able to reach the datasheet specified band rate. */
214 	CLOCK_SetMux(kCLOCK_LpspiMux, 1); /* Set SPI source to USB1 PFD0 */
215 	CLOCK_SetDiv(kCLOCK_LpspiDiv, 0); /* Set SPI divider to 1 */
216 #endif
217 
218 #ifdef CONFIG_DISPLAY_MCUX_ELCDIF
219 	/* MUX selects video PLL, which is initialized to 93MHz */
220 	CLOCK_SetMux(kCLOCK_LcdifPreMux, 2);
221 	/* Divide output by 2 */
222 	CLOCK_SetDiv(kCLOCK_LcdifDiv, 1);
223 	/* Set final div based on LCDIF clock-frequency */
224 	CLOCK_SetDiv(kCLOCK_LcdifPreDiv,
225 		((CLOCK_GetPllFreq(kCLOCK_PllVideo) / 2) /
226 		DT_PROP(DT_CHILD(DT_NODELABEL(lcdif), display_timings),
227 			clock_frequency)) - 1);
228 #endif
229 
230 
231 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(enet)) && CONFIG_NET_L2_ETHERNET
232 #if CONFIG_ETH_NXP_ENET_RMII_EXT_CLK
233 	/* Enable clock input for ENET1 */
234 	IOMUXC_EnableMode(IOMUXC_GPR, kIOMUXC_GPR_ENET1TxClkOutputDir, false);
235 #else
236 	/* Enable clock output for ENET1 */
237 	IOMUXC_EnableMode(IOMUXC_GPR, kIOMUXC_GPR_ENET1TxClkOutputDir, true);
238 #endif
239 #endif
240 
241 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(enet2)) && CONFIG_NET_L2_ETHERNET
242 	/* Set ENET2 ref clock to be generated by External OSC,*/
243 	/* direction as output and frequency to 50MHz */
244 	IOMUXC_EnableMode(IOMUXC_GPR, kIOMUXC_GPR_ENET2TxClkOutputDir |
245 				kIOMUXC_GPR_ENET2RefClkMode, true);
246 #endif
247 
248 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(usb1)) && \
249 	(CONFIG_USB_DC_NXP_EHCI || CONFIG_UDC_NXP_EHCI)
250 	CLOCK_EnableUsbhs0PhyPllClock(kCLOCK_Usb480M,
251 		DT_PROP_BY_PHANDLE(DT_NODELABEL(usb1), clocks, clock_frequency));
252 	CLOCK_EnableUsbhs0Clock(kCLOCK_Usb480M,
253 		DT_PROP_BY_PHANDLE(DT_NODELABEL(usb1), clocks, clock_frequency));
254 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(usb1)) && CONFIG_USB_DC_NXP_EHCI
255 	USB_EhciPhyInit(kUSB_ControllerEhci0, CPU_XTAL_CLK_HZ, &usbPhyConfig);
256 #endif
257 #endif
258 
259 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(usb2)) && \
260 	(CONFIG_USB_DC_NXP_EHCI || CONFIG_UDC_NXP_EHCI)
261 	CLOCK_EnableUsbhs1PhyPllClock(kCLOCK_Usb480M,
262 		DT_PROP_BY_PHANDLE(DT_NODELABEL(usb2), clocks, clock_frequency));
263 	CLOCK_EnableUsbhs1Clock(kCLOCK_Usb480M,
264 		DT_PROP_BY_PHANDLE(DT_NODELABEL(usb2), clocks, clock_frequency));
265 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(usb1)) && CONFIG_USB_DC_NXP_EHCI
266 	USB_EhciPhyInit(kUSB_ControllerEhci1, CPU_XTAL_CLK_HZ, &usbPhyConfig);
267 #endif
268 #endif
269 
270 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(usdhc1)) && CONFIG_IMX_USDHC
271 	/* Configure USDHC clock source and divider */
272 	CLOCK_InitSysPfd(kCLOCK_Pfd0, 24U);
273 	CLOCK_SetDiv(kCLOCK_Usdhc1Div, 1U);
274 	CLOCK_SetMux(kCLOCK_Usdhc1Mux, 1U);
275 	CLOCK_EnableClock(kCLOCK_Usdhc1);
276 #endif
277 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(usdhc2)) && CONFIG_IMX_USDHC
278 	/* Configure USDHC clock source and divider */
279 	CLOCK_InitSysPfd(kCLOCK_Pfd0, 24U);
280 	CLOCK_SetDiv(kCLOCK_Usdhc2Div, 1U);
281 	CLOCK_SetMux(kCLOCK_Usdhc2Mux, 1U);
282 	CLOCK_EnableClock(kCLOCK_Usdhc2);
283 #endif
284 
285 #ifdef CONFIG_VIDEO_MCUX_CSI
286 	CLOCK_EnableClock(kCLOCK_Csi); /* Disable CSI clock gate */
287 	CLOCK_SetDiv(kCLOCK_CsiDiv, 0); /* Set CSI divider to 1 */
288 	CLOCK_SetMux(kCLOCK_CsiMux, 0); /* Set CSI source to OSC 24M */
289 #endif
290 #ifdef CONFIG_CAN_MCUX_FLEXCAN
291 	CLOCK_SetDiv(kCLOCK_CanDiv, 1); /* Set CAN_CLK_PODF. */
292 	CLOCK_SetMux(kCLOCK_CanMux, 2); /* Set Can clock source. */
293 #endif
294 
295 #ifdef CONFIG_LOG_BACKEND_SWO
296 	/* Enable ARM trace clock to enable SWO output */
297 	CLOCK_EnableClock(kCLOCK_Trace);
298 	/* Divide root clock output by 3 */
299 	CLOCK_SetDiv(kCLOCK_TraceDiv, 3);
300 	/* Source clock from 528MHz system PLL */
301 	CLOCK_SetMux(kCLOCK_TraceMux, 0);
302 #endif
303 
304 	/* Keep the system clock running so SYSTICK can wake up the system from
305 	 * wfi.
306 	 */
307 	CLOCK_SetMode(kCLOCK_ModeRun);
308 
309 }
310 
311 #if CONFIG_I2S_MCUX_SAI
imxrt_audio_codec_pll_init(uint32_t clock_name,uint32_t clk_src,uint32_t clk_pre_div,uint32_t clk_src_div)312 void imxrt_audio_codec_pll_init(uint32_t clock_name, uint32_t clk_src,
313 					uint32_t clk_pre_div, uint32_t clk_src_div)
314 {
315 	switch (clock_name) {
316 	case IMX_CCM_SAI1_CLK:
317 		CLOCK_SetMux(kCLOCK_Sai1Mux, clk_src);
318 		CLOCK_SetDiv(kCLOCK_Sai1PreDiv, clk_pre_div);
319 		CLOCK_SetDiv(kCLOCK_Sai1Div, clk_src_div);
320 		break;
321 	case IMX_CCM_SAI2_CLK:
322 		CLOCK_SetMux(kCLOCK_Sai2Mux, clk_src);
323 		CLOCK_SetDiv(kCLOCK_Sai2PreDiv, clk_pre_div);
324 		CLOCK_SetDiv(kCLOCK_Sai2Div, clk_src_div);
325 		break;
326 	case IMX_CCM_SAI3_CLK:
327 		CLOCK_SetMux(kCLOCK_Sai2Mux, clk_src);
328 		CLOCK_SetDiv(kCLOCK_Sai2PreDiv, clk_pre_div);
329 		CLOCK_SetDiv(kCLOCK_Sai2Div, clk_src_div);
330 		break;
331 	default:
332 		return;
333 	}
334 }
335 #endif
336 
337 extern void rt10xx_power_init(void);
338 extern void imxrt_lpm_init(void);
339 
340 /**
341  *
342  * @brief Perform basic hardware initialization
343  *
344  * Initialize the interrupt controller device drivers.
345  * Also initialize the timer device driver, if required.
346  */
soc_early_init_hook(void)347 void soc_early_init_hook(void)
348 {
349 	sys_cache_instr_enable();
350 	sys_cache_data_enable();
351 
352 	/* Initialize system clock */
353 	clock_init();
354 #ifdef CONFIG_PM
355 #ifdef CONFIG_SOC_MIMXRT1064
356 	imxrt_lpm_init();
357 #endif
358 	rt10xx_power_init();
359 #endif
360 }
361 
362 #ifdef CONFIG_SOC_RESET_HOOK
soc_reset_hook(void)363 void soc_reset_hook(void)
364 {
365 	/* Call CMSIS SystemInit */
366 	SystemInit();
367 
368 #if defined(FLEXRAM_RUNTIME_BANKS_USED)
369 	/* Configure flexram if not running from RAM */
370 	memc_flexram_dt_partition();
371 #endif
372 }
373 #endif
374