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 condfiguration */
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) || defined(CONFIG_ETH_MCUX)
70 #if DT_NODE_HAS_STATUS(DT_NODELABEL(enet), okay)
71 .enableClkOutput = true,
72 #endif
73 #if DT_NODE_HAS_STATUS(DT_NODELABEL(enet2), okay)
74 .enableClkOutput1 = true,
75 #endif
76 #endif
77 #if defined(CONFIG_PTP_CLOCK_MCUX) || defined(CONFIG_PTP_CLOCK_NXP_ENET)
78 .enableClkOutput25M = true,
79 #else
80 .enableClkOutput25M = false,
81 #endif
82 #if DT_NODE_HAS_STATUS(DT_NODELABEL(enet), okay)
83 .loopDivider = 1,
84 #endif
85 #if DT_NODE_HAS_STATUS(DT_NODELABEL(enet2), okay)
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 static ALWAYS_INLINE 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 /* Setting the VDD_SOC value.
155 */
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
163 #ifdef CONFIG_INIT_ARM_PLL
164 CLOCK_InitArmPll(&armPllConfig); /* Configure ARM PLL to 1200M */
165 #endif
166 #ifdef CONFIG_INIT_ENET_PLL
167 CLOCK_InitEnetPll(ðPllConfig);
168 #endif
169 #ifdef CONFIG_INIT_VIDEO_PLL
170 CLOCK_InitVideoPll(&videoPllConfig);
171 #endif
172
173 #if CONFIG_INIT_SYS_PLL
174 CLOCK_InitSysPll(&sysPllConfig);
175 #endif
176
177 #if DT_NODE_EXISTS(DT_CHILD(CCM_NODE, arm_podf))
178 /* Set ARM PODF */
179 BUILD_ASSERT_PODF_IN_RANGE(arm_podf, 1, 8);
180 CLOCK_SetDiv(kCLOCK_ArmDiv, DT_PROP(DT_CHILD(CCM_NODE, arm_podf), clock_div) - 1);
181 #endif
182 /* Set AHB PODF */
183 BUILD_ASSERT_PODF_IN_RANGE(ahb_podf, 1, 8);
184 CLOCK_SetDiv(kCLOCK_AhbDiv, DT_PROP(DT_CHILD(CCM_NODE, ahb_podf), clock_div) - 1);
185 /* Set IPG PODF */
186 BUILD_ASSERT_PODF_IN_RANGE(ipg_podf, 1, 4);
187 CLOCK_SetDiv(kCLOCK_IpgDiv, DT_PROP(DT_CHILD(CCM_NODE, ipg_podf), clock_div) - 1);
188
189 #ifdef CONFIG_SOC_MIMXRT1042
190 /* Set PRE_PERIPH_CLK to SYS_PLL */
191 CLOCK_SetMux(kCLOCK_PrePeriphMux, 0x0);
192 #else
193 /* Set PRE_PERIPH_CLK to PLL1, 1200M */
194 CLOCK_SetMux(kCLOCK_PrePeriphMux, 0x3);
195 #endif
196
197 /* Set PERIPH_CLK MUX to PRE_PERIPH_CLK */
198 CLOCK_SetMux(kCLOCK_PeriphMux, 0x0);
199
200 #ifdef CONFIG_UART_MCUX_LPUART
201 /* Configure UART divider to default */
202 CLOCK_SetMux(kCLOCK_UartMux, 0); /* Set UART source to PLL3 80M */
203 CLOCK_SetDiv(kCLOCK_UartDiv, 0); /* Set UART divider to 1 */
204 #endif
205
206 #ifdef CONFIG_I2C_MCUX_LPI2C
207 CLOCK_SetMux(kCLOCK_Lpi2cMux, 0); /* Set I2C source as USB1 PLL 480M */
208 CLOCK_SetDiv(kCLOCK_Lpi2cDiv, 5); /* Set I2C divider to 6 */
209 #endif
210
211 #ifdef CONFIG_SPI_MCUX_LPSPI
212 CLOCK_SetMux(kCLOCK_LpspiMux, 1); /* Set SPI source to USB1 PFD0 720M */
213 CLOCK_SetDiv(kCLOCK_LpspiDiv, 7); /* Set SPI divider to 8 */
214 #endif
215
216 #ifdef CONFIG_DISPLAY_MCUX_ELCDIF
217 /* MUX selects video PLL, which is initialized to 93MHz */
218 CLOCK_SetMux(kCLOCK_LcdifPreMux, 2);
219 /* Divide output by 2 */
220 CLOCK_SetDiv(kCLOCK_LcdifDiv, 1);
221 /* Set final div based on LCDIF clock-frequency */
222 CLOCK_SetDiv(kCLOCK_LcdifPreDiv,
223 ((CLOCK_GetPllFreq(kCLOCK_PllVideo) / 2) /
224 DT_PROP(DT_CHILD(DT_NODELABEL(lcdif), display_timings),
225 clock_frequency)) - 1);
226 #endif
227
228
229 #if DT_NODE_HAS_STATUS(DT_NODELABEL(enet), okay) && CONFIG_NET_L2_ETHERNET
230 #if CONFIG_ETH_MCUX_RMII_EXT_CLK
231 /* Enable clock input for ENET1 */
232 IOMUXC_EnableMode(IOMUXC_GPR, kIOMUXC_GPR_ENET1TxClkOutputDir, false);
233 #else
234 /* Enable clock output for ENET1 */
235 IOMUXC_EnableMode(IOMUXC_GPR, kIOMUXC_GPR_ENET1TxClkOutputDir, true);
236 #endif
237 #endif
238
239 #if DT_NODE_HAS_STATUS(DT_NODELABEL(enet2), okay) && CONFIG_NET_L2_ETHERNET
240 /* Set ENET2 ref clock to be generated by External OSC,*/
241 /* direction as output and frequency to 50MHz */
242 IOMUXC_EnableMode(IOMUXC_GPR, kIOMUXC_GPR_ENET2TxClkOutputDir |
243 kIOMUXC_GPR_ENET2RefClkMode, true);
244 #endif
245
246 #if DT_NODE_HAS_STATUS(DT_NODELABEL(usb1), okay) && \
247 (CONFIG_USB_DC_NXP_EHCI || CONFIG_UDC_NXP_EHCI)
248 CLOCK_EnableUsbhs0PhyPllClock(kCLOCK_Usb480M,
249 DT_PROP_BY_PHANDLE(DT_NODELABEL(usb1), clocks, clock_frequency));
250 CLOCK_EnableUsbhs0Clock(kCLOCK_Usb480M,
251 DT_PROP_BY_PHANDLE(DT_NODELABEL(usb1), clocks, clock_frequency));
252 #if DT_NODE_HAS_STATUS(DT_NODELABEL(usb1), okay) && CONFIG_USB_DC_NXP_EHCI
253 USB_EhciPhyInit(kUSB_ControllerEhci0, CPU_XTAL_CLK_HZ, &usbPhyConfig);
254 #endif
255 #endif
256
257 #if DT_NODE_HAS_STATUS(DT_NODELABEL(usb2), okay) && \
258 (CONFIG_USB_DC_NXP_EHCI || CONFIG_UDC_NXP_EHCI)
259 CLOCK_EnableUsbhs1PhyPllClock(kCLOCK_Usb480M,
260 DT_PROP_BY_PHANDLE(DT_NODELABEL(usb2), clocks, clock_frequency));
261 CLOCK_EnableUsbhs1Clock(kCLOCK_Usb480M,
262 DT_PROP_BY_PHANDLE(DT_NODELABEL(usb2), clocks, clock_frequency));
263 #if DT_NODE_HAS_STATUS(DT_NODELABEL(usb1), okay) && CONFIG_USB_DC_NXP_EHCI
264 USB_EhciPhyInit(kUSB_ControllerEhci1, CPU_XTAL_CLK_HZ, &usbPhyConfig);
265 #endif
266 #endif
267
268 #if DT_NODE_HAS_STATUS(DT_NODELABEL(usdhc1), okay) && CONFIG_IMX_USDHC
269 /* Configure USDHC clock source and divider */
270 CLOCK_InitSysPfd(kCLOCK_Pfd0, 24U);
271 CLOCK_SetDiv(kCLOCK_Usdhc1Div, 1U);
272 CLOCK_SetMux(kCLOCK_Usdhc1Mux, 1U);
273 CLOCK_EnableClock(kCLOCK_Usdhc1);
274 #endif
275 #if DT_NODE_HAS_STATUS(DT_NODELABEL(usdhc2), okay) && CONFIG_IMX_USDHC
276 /* Configure USDHC clock source and divider */
277 CLOCK_InitSysPfd(kCLOCK_Pfd0, 24U);
278 CLOCK_SetDiv(kCLOCK_Usdhc2Div, 1U);
279 CLOCK_SetMux(kCLOCK_Usdhc2Mux, 1U);
280 CLOCK_EnableClock(kCLOCK_Usdhc2);
281 #endif
282
283 #ifdef CONFIG_VIDEO_MCUX_CSI
284 CLOCK_EnableClock(kCLOCK_Csi); /* Disable CSI clock gate */
285 CLOCK_SetDiv(kCLOCK_CsiDiv, 0); /* Set CSI divider to 1 */
286 CLOCK_SetMux(kCLOCK_CsiMux, 0); /* Set CSI source to OSC 24M */
287 #endif
288 #ifdef CONFIG_CAN_MCUX_FLEXCAN
289 CLOCK_SetDiv(kCLOCK_CanDiv, 1); /* Set CAN_CLK_PODF. */
290 CLOCK_SetMux(kCLOCK_CanMux, 2); /* Set Can clock source. */
291 #endif
292
293 #ifdef CONFIG_LOG_BACKEND_SWO
294 /* Enable ARM trace clock to enable SWO output */
295 CLOCK_EnableClock(kCLOCK_Trace);
296 /* Divide root clock output by 3 */
297 CLOCK_SetDiv(kCLOCK_TraceDiv, 3);
298 /* Source clock from 528MHz system PLL */
299 CLOCK_SetMux(kCLOCK_TraceMux, 0);
300 #endif
301
302 /* Keep the system clock running so SYSTICK can wake up the system from
303 * wfi.
304 */
305 CLOCK_SetMode(kCLOCK_ModeRun);
306
307 }
308
309 #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)310 void imxrt_audio_codec_pll_init(uint32_t clock_name, uint32_t clk_src,
311 uint32_t clk_pre_div, uint32_t clk_src_div)
312 {
313 switch (clock_name) {
314 case IMX_CCM_SAI1_CLK:
315 CLOCK_SetMux(kCLOCK_Sai1Mux, clk_src);
316 CLOCK_SetDiv(kCLOCK_Sai1PreDiv, clk_pre_div);
317 CLOCK_SetDiv(kCLOCK_Sai1Div, clk_src_div);
318 break;
319 case IMX_CCM_SAI2_CLK:
320 CLOCK_SetMux(kCLOCK_Sai2Mux, clk_src);
321 CLOCK_SetDiv(kCLOCK_Sai2PreDiv, clk_pre_div);
322 CLOCK_SetDiv(kCLOCK_Sai2Div, clk_src_div);
323 break;
324 case IMX_CCM_SAI3_CLK:
325 CLOCK_SetMux(kCLOCK_Sai2Mux, clk_src);
326 CLOCK_SetDiv(kCLOCK_Sai2PreDiv, clk_pre_div);
327 CLOCK_SetDiv(kCLOCK_Sai2Div, clk_src_div);
328 break;
329 default:
330 return;
331 }
332 }
333 #endif
334
335 /**
336 *
337 * @brief Perform basic hardware initialization
338 *
339 * Initialize the interrupt controller device drivers.
340 * Also initialize the timer device driver, if required.
341 *
342 * @return 0
343 */
344
imxrt_init(void)345 static int imxrt_init(void)
346 {
347 sys_cache_instr_enable();
348 sys_cache_data_enable();
349
350 /* Initialize system clock */
351 clock_init();
352
353 return 0;
354 }
355
356 #ifdef CONFIG_PLATFORM_SPECIFIC_INIT
z_arm_platform_init(void)357 void z_arm_platform_init(void)
358 {
359 /* Call CMSIS SystemInit */
360 SystemInit();
361
362 #if defined(FLEXRAM_RUNTIME_BANKS_USED)
363 /* Configure flexram if not running from RAM */
364 memc_flexram_dt_partition();
365 #endif
366 }
367 #endif
368
369 SYS_INIT(imxrt_init, PRE_KERNEL_1, 0);
370