1 /*
2 * Copyright (c) 2018, NXP
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/init.h>
8 #include <zephyr/irq.h>
9 #include <zephyr/sys/barrier.h>
10 #include <soc.h>
11 #include <zephyr/dt-bindings/rdc/imx_rdc.h>
12 #include <zephyr/arch/arm/aarch32/cortex_m/cmsis.h>
13 #include <zephyr/arch/arm/aarch32/nmi.h>
14 #include "wdog_imx.h"
15
16 /* Initialize Resource Domain Controller. */
SOC_RdcInit(void)17 static void SOC_RdcInit(void)
18 {
19 /* Move M4 core to the configured RDC domain */
20 RDC_SetDomainID(RDC, rdcMdaM4, M4_DOMAIN_ID, false);
21
22 /* Set access to WDOG3 for M4 core */
23 RDC_SetPdapAccess(RDC, rdcPdapWdog3,
24 RDC_DOMAIN_PERM(M4_DOMAIN_ID, RDC_DOMAIN_PERM_RW),
25 false, false);
26
27 #if DT_NODE_HAS_STATUS(DT_NODELABEL(uart1), okay)
28 /* Set access to UART_1 for M4 core */
29 RDC_SetPdapAccess(RDC, rdcPdapUart1, RDC_DT_VAL(uart1), false, false);
30 #endif
31 #if DT_NODE_HAS_STATUS(DT_NODELABEL(uart2), okay)
32 /* Set access to UART_2 for M4 core */
33 RDC_SetPdapAccess(RDC, rdcPdapUart2, RDC_DT_VAL(uart2), false, false);
34 #endif
35 #if DT_NODE_HAS_STATUS(DT_NODELABEL(uart3), okay)
36 /* Set access to UART_3 for M4 core */
37 RDC_SetPdapAccess(RDC, rdcPdapUart3, RDC_DT_VAL(uart3), false, false);
38 #endif
39 #if DT_NODE_HAS_STATUS(DT_NODELABEL(uart4), okay)
40 /* Set access to UART_4 for M4 core */
41 RDC_SetPdapAccess(RDC, rdcPdapUart4, RDC_DT_VAL(uart4), false, false);
42 #endif
43 #if DT_NODE_HAS_STATUS(DT_NODELABEL(uart5), okay)
44 /* Set access to UART_5 for M4 core */
45 RDC_SetPdapAccess(RDC, rdcPdapUart5, RDC_DT_VAL(uart5), false, false);
46 #endif
47 #if DT_NODE_HAS_STATUS(DT_NODELABEL(uart6), okay)
48 /* Set access to UART_6 for M4 core */
49 RDC_SetPdapAccess(RDC, rdcPdapUart6, RDC_DT_VAL(uart6), false, false);
50 #endif
51 #if DT_NODE_HAS_STATUS(DT_NODELABEL(gpio1), okay)
52 /* Set access to GPIO_1 for M4 core */
53 RDC_SetPdapAccess(RDC, rdcPdapGpio1, RDC_DT_VAL(gpio1), false, false);
54 #endif
55 #if DT_NODE_HAS_STATUS(DT_NODELABEL(gpio2), okay)
56 /* Set access to GPIO_2 for M4 core */
57 RDC_SetPdapAccess(RDC, rdcPdapGpio2, RDC_DT_VAL(gpio2), false, false);
58 #endif
59 #if DT_NODE_HAS_STATUS(DT_NODELABEL(gpio3), okay)
60 /* Set access to GPIO_3 for M4 core */
61 RDC_SetPdapAccess(RDC, rdcPdapGpio3, RDC_DT_VAL(gpio3), false, false);
62 #endif
63 #if DT_NODE_HAS_STATUS(DT_NODELABEL(gpio4), okay)
64 /* Set access to GPIO_4 for M4 core */
65 RDC_SetPdapAccess(RDC, rdcPdapGpio4, RDC_DT_VAL(gpio4), false, false);
66 #endif
67 #if DT_NODE_HAS_STATUS(DT_NODELABEL(gpio5), okay)
68 /* Set access to GPIO_5 for M4 core */
69 RDC_SetPdapAccess(RDC, rdcPdapGpio5, RDC_DT_VAL(gpio5), false, false);
70 #endif
71 #if DT_NODE_HAS_STATUS(DT_NODELABEL(gpio6), okay)
72 /* Set access to GPIO_6 for M4 core */
73 RDC_SetPdapAccess(RDC, rdcPdapGpio6, RDC_DT_VAL(gpio6), false, false);
74 #endif
75 #if DT_NODE_HAS_STATUS(DT_NODELABEL(gpio7), okay)
76 /* Set access to GPIO_7 for M4 core */
77 RDC_SetPdapAccess(RDC, rdcPdapGpio7, RDC_DT_VAL(gpio7), false, false);
78 #endif
79
80 #ifdef CONFIG_IPM_IMX
81 /* Set access to MU B for M4 core */
82 RDC_SetPdapAccess(RDC, rdcPdapMuB, RDC_DT_VAL(mub), false, false);
83 #endif /* CONFIG_IPM_IMX */
84
85 #if DT_NODE_HAS_STATUS(DT_NODELABEL(epit1), okay)
86 /* Set access to EPIT_1 for M4 core */
87 RDC_SetPdapAccess(RDC, rdcPdapEpit1, RDC_DT_VAL(epit1), false, false);
88 #endif
89 #if DT_NODE_HAS_STATUS(DT_NODELABEL(epit2), okay)
90 /* Set access to EPIT_2 for M4 core */
91 RDC_SetPdapAccess(RDC, rdcPdapEpit2, RDC_DT_VAL(epit2), false, false);
92 #endif
93
94 #if DT_NODE_HAS_STATUS(DT_NODELABEL(i2c1), okay)
95 /* Set access to I2C-1 for M4 core */
96 RDC_SetPdapAccess(RDC, rdcPdapI2c1, RDC_DT_VAL(i2c1), false, false);
97 #endif
98 #if DT_NODE_HAS_STATUS(DT_NODELABEL(i2c2), okay)
99 /* Set access to I2C-2 for M4 core */
100 RDC_SetPdapAccess(RDC, rdcPdapI2c2, RDC_DT_VAL(i2c2), false, false);
101 #endif
102 #if DT_NODE_HAS_STATUS(DT_NODELABEL(i2c3), okay)
103 /* Set access to I2C-3 for M4 core */
104 RDC_SetPdapAccess(RDC, rdcPdapI2c3, RDC_DT_VAL(i2c3), false, false);
105 #endif
106 #if DT_NODE_HAS_STATUS(DT_NODELABEL(i2c4), okay)
107 /* Set access to I2C-4 for M4 core */
108 RDC_SetPdapAccess(RDC, rdcPdapI2c4, RDC_DT_VAL(i2c4), false, false);
109 #endif
110
111 #if DT_NODE_HAS_STATUS(DT_NODELABEL(pwm1), okay)
112 /* Set access to PWM-1 for M4 core */
113 RDC_SetPdapAccess(RDC, rdcPdapPwm1, RDC_DT_VAL(pwm1), false, false);
114 #endif
115 #if DT_NODE_HAS_STATUS(DT_NODELABEL(pwm2), okay)
116 /* Set access to PWM-2 for M4 core */
117 RDC_SetPdapAccess(RDC, rdcPdapPwm2, RDC_DT_VAL(pwm2), false, false);
118 #endif
119 #if DT_NODE_HAS_STATUS(DT_NODELABEL(pwm3), okay)
120 /* Set access to PWM-3 for M4 core */
121 RDC_SetPdapAccess(RDC, rdcPdapPwm3, RDC_DT_VAL(pwm3), false, false);
122 #endif
123 #if DT_NODE_HAS_STATUS(DT_NODELABEL(pwm4), okay)
124 /* Set access to PWM-4 for M4 core */
125 RDC_SetPdapAccess(RDC, rdcPdapPwm4, RDC_DT_VAL(pwm4), false, false);
126 #endif
127 #if DT_NODE_HAS_STATUS(DT_NODELABEL(pwm5), okay)
128 /* Set access to PWM-5 for M4 core */
129 RDC_SetPdapAccess(RDC, rdcPdapPwm5, RDC_DT_VAL(pwm5), false, false);
130 #endif
131 #if DT_NODE_HAS_STATUS(DT_NODELABEL(pwm6), okay)
132 /* Set access to PWM-6 for M4 core */
133 RDC_SetPdapAccess(RDC, rdcPdapPwm6, RDC_DT_VAL(pwm6), false, false);
134 #endif
135 #if DT_NODE_HAS_STATUS(DT_NODELABEL(pwm7), okay)
136 /* Set access to PWM-7 for M4 core */
137 RDC_SetPdapAccess(RDC, rdcPdapPwm7, RDC_DT_VAL(pwm7), false, false);
138 #endif
139 #if DT_NODE_HAS_STATUS(DT_NODELABEL(pwm8), okay)
140 /* Set access to PWM-8 for M4 core */
141 RDC_SetPdapAccess(RDC, rdcPdapPwm8, RDC_DT_VAL(pwm8), false, false);
142 #endif
143 #if DT_NODE_HAS_STATUS(DT_NODELABEL(adc1), okay)
144 /* Set access to ADC-1 for M4 core */
145 RDC_SetPdapAccess(RDC, rdcPdapAdc1, RDC_DT_VAL(adc1), false, false);
146 #endif
147 #if DT_NODE_HAS_STATUS(DT_NODELABEL(adc2), okay)
148 /* Set access to ADC-2 for M4 core */
149 RDC_SetPdapAccess(RDC, rdcPdapAdc2, RDC_DT_VAL(adc2), false, false);
150 #endif
151 }
152
153 /* Initialize cache. */
SOC_CacheInit(void)154 static void SOC_CacheInit(void)
155 {
156 /* Enable System Bus Cache */
157 /* set command to invalidate all ways and write GO bit
158 * to initiate command
159 */
160 LMEM_PSCCR = LMEM_PSCCR_INVW1_MASK | LMEM_PSCCR_INVW0_MASK;
161 LMEM_PSCCR |= LMEM_PSCCR_GO_MASK;
162 /* Wait until the command completes */
163 while (LMEM_PSCCR & LMEM_PSCCR_GO_MASK)
164 ;
165 /* Enable system bus cache, enable write buffer */
166 LMEM_PSCCR = (LMEM_PSCCR_ENWRBUF_MASK | LMEM_PSCCR_ENCACHE_MASK);
167 barrier_isync_fence_full();
168
169 /* Enable Code Bus Cache */
170 /* set command to invalidate all ways and write GO bit
171 * to initiate command
172 */
173 LMEM_PCCCR = LMEM_PCCCR_INVW1_MASK | LMEM_PCCCR_INVW0_MASK;
174 LMEM_PCCCR |= LMEM_PCCCR_GO_MASK;
175 /* Wait until the command completes */
176 while (LMEM_PCCCR & LMEM_PCCCR_GO_MASK)
177 ;
178 /* Enable code bus cache, enable write buffer */
179 LMEM_PCCCR = (LMEM_PCCCR_ENWRBUF_MASK | LMEM_PCCCR_ENCACHE_MASK);
180 barrier_isync_fence_full();
181 barrier_dsync_fence_full();
182 }
183
184 /* Initialize clock. */
SOC_ClockInit(void)185 static void SOC_ClockInit(void)
186 {
187 /* OSC/PLL is already initialized by Cortex-A9 core */
188
189 /* Enable IP bridge and IO mux clock */
190 CCM_ControlGate(CCM, ccmCcgrGateIomuxIptClkIo, ccmClockNeededAll);
191 CCM_ControlGate(CCM, ccmCcgrGateIpmux1Clk, ccmClockNeededAll);
192 CCM_ControlGate(CCM, ccmCcgrGateIpmux2Clk, ccmClockNeededAll);
193 CCM_ControlGate(CCM, ccmCcgrGateIpmux3Clk, ccmClockNeededAll);
194
195 #ifdef CONFIG_UART_IMX
196 /* Set UART clock is derived from OSC clock (24M) */
197 CCM_SetRootMux(CCM, ccmRootUartClkSel, ccmRootmuxUartClkOsc24m);
198
199 /* Configure UART divider */
200 CCM_SetRootDivider(CCM, ccmRootUartClkPodf, 0);
201
202 /* Enable UART clock */
203 CCM_ControlGate(CCM, ccmCcgrGateUartClk, ccmClockNeededAll);
204 CCM_ControlGate(CCM, ccmCcgrGateUartSerialClk, ccmClockNeededAll);
205 #endif /* CONFIG_UART_IMX */
206
207 #ifdef CONFIG_COUNTER_IMX_EPIT
208 /* Select EPIT clock is derived from OSC (24M) */
209 CCM_SetRootMux(CCM, ccmRootPerclkClkSel, ccmRootmuxPerclkClkOsc24m);
210
211 /* Configure EPIT divider */
212 CCM_SetRootDivider(CCM, ccmRootPerclkPodf, 0);
213
214 /* Enable EPIT clocks */
215 #if DT_NODE_HAS_STATUS(DT_NODELABEL(epit1), okay)
216 CCM_ControlGate(CCM, ccmCcgrGateEpit1Clk, ccmClockNeededAll);
217 #endif
218 #if DT_NODE_HAS_STATUS(DT_NODELABEL(epit2), okay)
219 CCM_ControlGate(CCM, ccmCcgrGateEpit2Clk, ccmClockNeededAll);
220 #endif
221 #endif /* CONFIG_COUNTER_IMX_EPIT */
222
223 #ifdef CONFIG_I2C_IMX
224 /* Select I2C clock is derived from OSC (24M) */
225 CCM_SetRootMux(CCM, ccmRootPerclkClkSel, ccmRootmuxPerclkClkOsc24m);
226
227 /* Set relevant divider = 1. */
228 CCM_SetRootDivider(CCM, ccmRootPerclkPodf, 0);
229
230 /* Enable I2C clock */
231 #if DT_NODE_HAS_STATUS(DT_NODELABEL(i2c1), okay)
232 CCM_ControlGate(CCM, ccmCcgrGateI2c1Serialclk, ccmClockNeededAll);
233 #endif
234 #if DT_NODE_HAS_STATUS(DT_NODELABEL(i2c2), okay)
235 CCM_ControlGate(CCM, ccmCcgrGateI2c2Serialclk, ccmClockNeededAll);
236 #endif
237 #if DT_NODE_HAS_STATUS(DT_NODELABEL(i2c3), okay)
238 CCM_ControlGate(CCM, ccmCcgrGateI2c3Serialclk, ccmClockNeededAll);
239 #endif
240 #if DT_NODE_HAS_STATUS(DT_NODELABEL(i2c4), okay)
241 CCM_ControlGate(CCM, ccmCcgrGateI2c4Serialclk, ccmClockNeededAll);
242 #endif
243 #endif /* CONFIG_I2C_IMX */
244
245 #ifdef CONFIG_PWM_IMX
246 /* Select PWM clock is derived from OSC (24M) */
247 CCM_SetRootMux(CCM, ccmRootPerclkClkSel, ccmRootmuxPerclkClkOsc24m);
248
249 /* Set relevant divider = 1. */
250 CCM_SetRootDivider(CCM, ccmRootPerclkPodf, 0);
251
252 /* Enable PWM clock */
253 #if DT_NODE_HAS_STATUS(DT_NODELABEL(pwm1), okay)
254 CCM_ControlGate(CCM, ccmCcgrGatePwm1Clk, ccmClockNeededAll);
255 #endif
256 #if DT_NODE_HAS_STATUS(DT_NODELABEL(pwm2), okay)
257 CCM_ControlGate(CCM, ccmCcgrGatePwm2Clk, ccmClockNeededAll);
258 #endif
259 #if DT_NODE_HAS_STATUS(DT_NODELABEL(pwm3), okay)
260 CCM_ControlGate(CCM, ccmCcgrGatePwm3Clk, ccmClockNeededAll);
261 #endif
262 #if DT_NODE_HAS_STATUS(DT_NODELABEL(pwm4), okay)
263 CCM_ControlGate(CCM, ccmCcgrGatePwm4Clk, ccmClockNeededAll);
264 #endif
265 #if DT_NODE_HAS_STATUS(DT_NODELABEL(pwm5), okay)
266 CCM_ControlGate(CCM, ccmCcgrGatePwm5Clk, ccmClockNeededAll);
267 #endif
268 #if DT_NODE_HAS_STATUS(DT_NODELABEL(pwm6), okay)
269 CCM_ControlGate(CCM, ccmCcgrGatePwm6Clk, ccmClockNeededAll);
270 #endif
271 #if DT_NODE_HAS_STATUS(DT_NODELABEL(pwm7), okay)
272 CCM_ControlGate(CCM, ccmCcgrGatePwm7Clk, ccmClockNeededAll);
273 #endif
274 #if DT_NODE_HAS_STATUS(DT_NODELABEL(pwm8), okay)
275 CCM_ControlGate(CCM, ccmCcgrGatePwm8Clk, ccmClockNeededAll);
276 #endif
277 #endif /* CONFIG_PWM_IMX */
278 }
279
280 /**
281 *
282 * @brief Perform basic hardware initialization
283 *
284 * Initialize the interrupt controller device drivers.
285 * Also initialize the counter device driver, if required.
286 *
287 * @return 0
288 */
mcimx6x_m4_init(void)289 static int mcimx6x_m4_init(void)
290 {
291
292 unsigned int oldLevel; /* Old interrupt lock level */
293
294 /* Disable interrupts */
295 oldLevel = irq_lock();
296
297 /* Configure RDC */
298 SOC_RdcInit();
299
300 /* Disable WDOG3 powerdown */
301 WDOG_DisablePowerdown(WDOG3);
302
303 /* Initialize Cache */
304 SOC_CacheInit();
305
306 /* Initialize clock */
307 SOC_ClockInit();
308
309 /*
310 * Install default handler that simply resets the CPU
311 * if configured in the kernel, NOP otherwise
312 */
313 NMI_INIT();
314
315 /* Restore interrupt state */
316 irq_unlock(oldLevel);
317
318 return 0;
319 }
320
321 SYS_INIT(mcimx6x_m4_init, PRE_KERNEL_1, 0);
322