]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
c5752f73 AA |
2 | /* |
3 | * Copyright (C) 2015 Freescale Semiconductor, Inc. | |
c5752f73 AA |
4 | */ |
5 | ||
6 | #include <common.h> | |
691d719d | 7 | #include <init.h> |
c5752f73 AA |
8 | #include <asm/io.h> |
9 | #include <asm/arch/imx-regs.h> | |
10 | #include <asm/arch/clock.h> | |
11 | #include <asm/arch/sys_proto.h> | |
552a848e SB |
12 | #include <asm/mach-imx/dma.h> |
13 | #include <asm/mach-imx/hab.h> | |
14 | #include <asm/mach-imx/rdc-sema.h> | |
35c4ce5e | 15 | #include <asm/arch/imx-rdc.h> |
c5752f73 AA |
16 | #include <asm/arch/crm_regs.h> |
17 | #include <dm.h> | |
9fb625ce | 18 | #include <env.h> |
c5752f73 | 19 | #include <imx_thermal.h> |
d1ceb0c4 | 20 | #include <fsl_sec.h> |
ca831822 | 21 | #include <asm/setup.h> |
c05ed00a | 22 | #include <linux/delay.h> |
c5752f73 | 23 | |
b0598378 AH |
24 | #define IOMUXC_GPR1 0x4 |
25 | #define BM_IOMUXC_GPR1_IRQ 0x1000 | |
26 | ||
27 | #define GPC_LPCR_A7_BSC 0x0 | |
28 | #define GPC_LPCR_M4 0x8 | |
29 | #define GPC_SLPCR 0x14 | |
30 | #define GPC_PGC_ACK_SEL_A7 0x24 | |
31 | #define GPC_IMR1_CORE0 0x30 | |
32 | #define GPC_IMR1_CORE1 0x40 | |
33 | #define GPC_IMR1_M4 0x50 | |
34 | #define GPC_PGC_CPU_MAPPING 0xec | |
35 | #define GPC_PGC_C0_PUPSCR 0x804 | |
36 | #define GPC_PGC_SCU_TIMING 0x890 | |
37 | #define GPC_PGC_C1_PUPSCR 0x844 | |
38 | ||
39 | #define BM_LPCR_A7_BSC_IRQ_SRC_A7_WAKEUP 0x70000000 | |
40 | #define BM_LPCR_A7_BSC_CPU_CLK_ON_LPM 0x4000 | |
41 | #define BM_LPCR_M4_MASK_DSM_TRIGGER 0x80000000 | |
42 | #define BM_SLPCR_EN_DSM 0x80000000 | |
43 | #define BM_SLPCR_RBC_EN 0x40000000 | |
44 | #define BM_SLPCR_REG_BYPASS_COUNT 0x3f000000 | |
45 | #define BM_SLPCR_VSTBY 0x4 | |
46 | #define BM_SLPCR_SBYOS 0x2 | |
47 | #define BM_SLPCR_BYPASS_PMIC_READY 0x1 | |
48 | #define BM_SLPCR_EN_A7_FASTWUP_WAIT_MODE 0x10000 | |
49 | ||
50 | #define BM_GPC_PGC_ACK_SEL_A7_DUMMY_PUP_ACK 0x80000000 | |
51 | #define BM_GPC_PGC_ACK_SEL_A7_DUMMY_PDN_ACK 0x8000 | |
52 | ||
53 | #define BM_GPC_PGC_CORE_PUPSCR 0x7fff80 | |
54 | ||
c5752f73 AA |
55 | #if defined(CONFIG_IMX_THERMAL) |
56 | static const struct imx_thermal_plat imx7_thermal_plat = { | |
57 | .regs = (void *)ANATOP_BASE_ADDR, | |
58 | .fuse_bank = 3, | |
59 | .fuse_word = 3, | |
60 | }; | |
61 | ||
62 | U_BOOT_DEVICE(imx7_thermal) = { | |
63 | .name = "imx_thermal", | |
64 | .platdata = &imx7_thermal_plat, | |
65 | }; | |
66 | #endif | |
67 | ||
e872f27a | 68 | #if CONFIG_IS_ENABLED(IMX_RDC) |
35c4ce5e PF |
69 | /* |
70 | * In current design, if any peripheral was assigned to both A7 and M4, | |
71 | * it will receive ipg_stop or ipg_wait when any of the 2 platforms enter | |
72 | * low power mode. So M4 sleep will cause some peripherals fail to work | |
73 | * at A7 core side. At default, all resources are in domain 0 - 3. | |
74 | * | |
75 | * There are 26 peripherals impacted by this IC issue: | |
76 | * SIM2(sim2/emvsim2) | |
77 | * SIM1(sim1/emvsim1) | |
78 | * UART1/UART2/UART3/UART4/UART5/UART6/UART7 | |
79 | * SAI1/SAI2/SAI3 | |
80 | * WDOG1/WDOG2/WDOG3/WDOG4 | |
81 | * GPT1/GPT2/GPT3/GPT4 | |
82 | * PWM1/PWM2/PWM3/PWM4 | |
83 | * ENET1/ENET2 | |
84 | * Software Workaround: | |
85 | * Here we setup some resources to domain 0 where M4 codes will move | |
86 | * the M4 out of this domain. Then M4 is not able to access them any longer. | |
87 | * This is a workaround for ic issue. So the peripherals are not shared | |
88 | * by them. This way requires the uboot implemented the RDC driver and | |
89 | * set the 26 IPs above to domain 0 only. M4 code will assign resource | |
90 | * to its own domain, if it want to use the resource. | |
91 | */ | |
92 | static rdc_peri_cfg_t const resources[] = { | |
93 | (RDC_PER_SIM1 | RDC_DOMAIN(0)), | |
94 | (RDC_PER_SIM2 | RDC_DOMAIN(0)), | |
95 | (RDC_PER_UART1 | RDC_DOMAIN(0)), | |
96 | (RDC_PER_UART2 | RDC_DOMAIN(0)), | |
97 | (RDC_PER_UART3 | RDC_DOMAIN(0)), | |
98 | (RDC_PER_UART4 | RDC_DOMAIN(0)), | |
99 | (RDC_PER_UART5 | RDC_DOMAIN(0)), | |
100 | (RDC_PER_UART6 | RDC_DOMAIN(0)), | |
101 | (RDC_PER_UART7 | RDC_DOMAIN(0)), | |
102 | (RDC_PER_SAI1 | RDC_DOMAIN(0)), | |
103 | (RDC_PER_SAI2 | RDC_DOMAIN(0)), | |
104 | (RDC_PER_SAI3 | RDC_DOMAIN(0)), | |
105 | (RDC_PER_WDOG1 | RDC_DOMAIN(0)), | |
106 | (RDC_PER_WDOG2 | RDC_DOMAIN(0)), | |
107 | (RDC_PER_WDOG3 | RDC_DOMAIN(0)), | |
108 | (RDC_PER_WDOG4 | RDC_DOMAIN(0)), | |
109 | (RDC_PER_GPT1 | RDC_DOMAIN(0)), | |
110 | (RDC_PER_GPT2 | RDC_DOMAIN(0)), | |
111 | (RDC_PER_GPT3 | RDC_DOMAIN(0)), | |
112 | (RDC_PER_GPT4 | RDC_DOMAIN(0)), | |
113 | (RDC_PER_PWM1 | RDC_DOMAIN(0)), | |
114 | (RDC_PER_PWM2 | RDC_DOMAIN(0)), | |
115 | (RDC_PER_PWM3 | RDC_DOMAIN(0)), | |
116 | (RDC_PER_PWM4 | RDC_DOMAIN(0)), | |
117 | (RDC_PER_ENET1 | RDC_DOMAIN(0)), | |
118 | (RDC_PER_ENET2 | RDC_DOMAIN(0)), | |
119 | }; | |
120 | ||
121 | static void isolate_resource(void) | |
122 | { | |
123 | imx_rdc_setup_peripherals(resources, ARRAY_SIZE(resources)); | |
124 | } | |
125 | #endif | |
126 | ||
d714a75f | 127 | #if defined(CONFIG_IMX_HAB) |
bb955146 AA |
128 | struct imx_sec_config_fuse_t const imx_sec_config_fuse = { |
129 | .bank = 1, | |
130 | .word = 3, | |
131 | }; | |
132 | #endif | |
133 | ||
e25a0656 FE |
134 | static bool is_mx7d(void) |
135 | { | |
136 | struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR; | |
137 | struct fuse_bank *bank = &ocotp->bank[1]; | |
138 | struct fuse_bank1_regs *fuse = | |
139 | (struct fuse_bank1_regs *)bank->fuse_regs; | |
140 | int val; | |
141 | ||
142 | val = readl(&fuse->tester4); | |
143 | if (val & 1) | |
144 | return false; | |
145 | else | |
146 | return true; | |
147 | } | |
148 | ||
c5752f73 AA |
149 | u32 get_cpu_rev(void) |
150 | { | |
151 | struct mxc_ccm_anatop_reg *ccm_anatop = (struct mxc_ccm_anatop_reg *) | |
152 | ANATOP_BASE_ADDR; | |
153 | u32 reg = readl(&ccm_anatop->digprog); | |
154 | u32 type = (reg >> 16) & 0xff; | |
155 | ||
e25a0656 FE |
156 | if (!is_mx7d()) |
157 | type = MXC_CPU_MX7S; | |
158 | ||
c5752f73 AA |
159 | reg &= 0xff; |
160 | return (type << 12) | reg; | |
161 | } | |
162 | ||
163 | #ifdef CONFIG_REVISION_TAG | |
164 | u32 __weak get_board_rev(void) | |
165 | { | |
166 | return get_cpu_rev(); | |
167 | } | |
168 | #endif | |
169 | ||
d9699de8 PF |
170 | static void imx_enet_mdio_fixup(void) |
171 | { | |
172 | struct iomuxc_gpr_base_regs *gpr_regs = | |
173 | (struct iomuxc_gpr_base_regs *)IOMUXC_GPR_BASE_ADDR; | |
174 | ||
175 | /* | |
176 | * The management data input/output (MDIO) requires open-drain, | |
177 | * i.MX7D TO1.0 ENET MDIO pin has no open drain, but TO1.1 supports | |
178 | * this feature. So to TO1.1, need to enable open drain by setting | |
179 | * bits GPR0[8:7]. | |
180 | */ | |
181 | ||
182 | if (soc_rev() >= CHIP_REV_1_1) { | |
183 | setbits_le32(&gpr_regs->gpr[0], | |
184 | IOMUXC_GPR_GPR0_ENET_MDIO_OPEN_DRAIN_MASK); | |
185 | } | |
186 | } | |
187 | ||
bc7c9ed3 JN |
188 | static void init_cpu_basic(void) |
189 | { | |
190 | imx_enet_mdio_fixup(); | |
191 | ||
192 | #ifdef CONFIG_APBH_DMA | |
193 | /* Start APBH DMA */ | |
194 | mxs_dma_init(); | |
195 | #endif | |
196 | } | |
197 | ||
c0f037f6 IO |
198 | #ifdef CONFIG_IMX_BOOTAUX |
199 | /* | |
200 | * Table of mappings of physical mem regions in both | |
201 | * Cortex-A7 and Cortex-M4 address spaces. | |
202 | * | |
203 | * For additional details check sections 2.1.2 and 2.1.3 in | |
204 | * i.MX7Dual Applications Processor Reference Manual | |
205 | * | |
206 | */ | |
207 | const struct rproc_att hostmap[] = { | |
208 | /* aux core , host core, size */ | |
209 | { 0x00000000, 0x00180000, 0x8000 }, /* OCRAM_S */ | |
210 | { 0x00180000, 0x00180000, 0x8000 }, /* OCRAM_S */ | |
211 | { 0x20180000, 0x00180000, 0x8000 }, /* OCRAM_S */ | |
212 | { 0x1fff8000, 0x007f8000, 0x8000 }, /* TCML */ | |
213 | { 0x20000000, 0x00800000, 0x8000 }, /* TCMU */ | |
214 | { 0x00900000, 0x00900000, 0x20000 }, /* OCRAM_128KB */ | |
215 | { 0x20200000, 0x00900000, 0x20000 }, /* OCRAM_128KB */ | |
216 | { 0x00920000, 0x00920000, 0x20000 }, /* OCRAM_EPDC */ | |
217 | { 0x20220000, 0x00920000, 0x20000 }, /* OCRAM_EPDC */ | |
218 | { 0x00940000, 0x00940000, 0x20000 }, /* OCRAM_PXP */ | |
219 | { 0x20240000, 0x00940000, 0x20000 }, /* OCRAM_PXP */ | |
220 | { 0x10000000, 0x80000000, 0x0fff0000 }, /* DDR Code alias */ | |
221 | { 0x80000000, 0x80000000, 0xe0000000 }, /* DDRC */ | |
222 | { /* sentinel */ } | |
223 | }; | |
224 | #endif | |
225 | ||
bc7c9ed3 JN |
226 | #ifndef CONFIG_SKIP_LOWLEVEL_INIT |
227 | /* enable all periherial can be accessed in nosec mode */ | |
228 | static void init_csu(void) | |
229 | { | |
230 | int i = 0; | |
231 | ||
232 | for (i = 0; i < CSU_NUM_REGS; i++) | |
233 | writel(CSU_INIT_SEC_LEVEL0, CSU_IPS_BASE_ADDR + i * 4); | |
234 | } | |
235 | ||
b0598378 AH |
236 | static void imx_gpcv2_init(void) |
237 | { | |
238 | u32 val, i; | |
239 | ||
240 | /* | |
241 | * Force IOMUXC irq pending, so that the interrupt to GPC can be | |
242 | * used to deassert dsm_request signal when the signal gets | |
243 | * asserted unexpectedly. | |
244 | */ | |
245 | val = readl(IOMUXC_GPR_BASE_ADDR + IOMUXC_GPR1); | |
246 | val |= BM_IOMUXC_GPR1_IRQ; | |
247 | writel(val, IOMUXC_GPR_BASE_ADDR + IOMUXC_GPR1); | |
248 | ||
249 | /* Initially mask all interrupts */ | |
250 | for (i = 0; i < 4; i++) { | |
251 | writel(~0, GPC_IPS_BASE_ADDR + GPC_IMR1_CORE0 + i * 4); | |
252 | writel(~0, GPC_IPS_BASE_ADDR + GPC_IMR1_CORE1 + i * 4); | |
253 | writel(~0, GPC_IPS_BASE_ADDR + GPC_IMR1_M4 + i * 4); | |
254 | } | |
255 | ||
256 | /* set SCU timing */ | |
257 | writel((0x59 << 10) | 0x5B | (0x2 << 20), | |
258 | GPC_IPS_BASE_ADDR + GPC_PGC_SCU_TIMING); | |
259 | ||
260 | /* only external IRQs to wake up LPM and core 0/1 */ | |
261 | val = readl(GPC_IPS_BASE_ADDR + GPC_LPCR_A7_BSC); | |
262 | val |= BM_LPCR_A7_BSC_IRQ_SRC_A7_WAKEUP; | |
263 | writel(val, GPC_IPS_BASE_ADDR + GPC_LPCR_A7_BSC); | |
264 | ||
265 | /* set C0 power up timming per design requirement */ | |
266 | val = readl(GPC_IPS_BASE_ADDR + GPC_PGC_C0_PUPSCR); | |
267 | val &= ~BM_GPC_PGC_CORE_PUPSCR; | |
268 | val |= (0x1A << 7); | |
269 | writel(val, GPC_IPS_BASE_ADDR + GPC_PGC_C0_PUPSCR); | |
270 | ||
271 | /* set C1 power up timming per design requirement */ | |
272 | val = readl(GPC_IPS_BASE_ADDR + GPC_PGC_C1_PUPSCR); | |
273 | val &= ~BM_GPC_PGC_CORE_PUPSCR; | |
274 | val |= (0x1A << 7); | |
275 | writel(val, GPC_IPS_BASE_ADDR + GPC_PGC_C1_PUPSCR); | |
276 | ||
277 | /* dummy ack for time slot by default */ | |
278 | writel(BM_GPC_PGC_ACK_SEL_A7_DUMMY_PUP_ACK | | |
279 | BM_GPC_PGC_ACK_SEL_A7_DUMMY_PDN_ACK, | |
280 | GPC_IPS_BASE_ADDR + GPC_PGC_ACK_SEL_A7); | |
281 | ||
282 | /* mask M4 DSM trigger */ | |
283 | writel(readl(GPC_IPS_BASE_ADDR + GPC_LPCR_M4) | | |
284 | BM_LPCR_M4_MASK_DSM_TRIGGER, | |
285 | GPC_IPS_BASE_ADDR + GPC_LPCR_M4); | |
286 | ||
287 | /* set mega/fast mix in A7 domain */ | |
288 | writel(0x1, GPC_IPS_BASE_ADDR + GPC_PGC_CPU_MAPPING); | |
289 | ||
290 | /* DSM related settings */ | |
291 | val = readl(GPC_IPS_BASE_ADDR + GPC_SLPCR); | |
292 | val &= ~(BM_SLPCR_EN_DSM | BM_SLPCR_VSTBY | BM_SLPCR_RBC_EN | | |
293 | BM_SLPCR_SBYOS | BM_SLPCR_BYPASS_PMIC_READY | | |
294 | BM_SLPCR_REG_BYPASS_COUNT); | |
295 | val |= BM_SLPCR_EN_A7_FASTWUP_WAIT_MODE; | |
296 | writel(val, GPC_IPS_BASE_ADDR + GPC_SLPCR); | |
297 | ||
298 | /* | |
299 | * disabling RBC need to delay at least 2 cycles of CKIL(32K) | |
300 | * due to hardware design requirement, which is | |
301 | * ~61us, here we use 65us for safe | |
302 | */ | |
303 | udelay(65); | |
304 | } | |
305 | ||
c5752f73 AA |
306 | int arch_cpu_init(void) |
307 | { | |
308 | init_aips(); | |
309 | ||
7de47036 | 310 | init_csu(); |
c5752f73 | 311 | /* Disable PDE bit of WMCR register */ |
e2162d70 | 312 | imx_wdog_disable_powerdown(); |
c5752f73 | 313 | |
bc7c9ed3 | 314 | init_cpu_basic(); |
c5752f73 | 315 | |
e872f27a PF |
316 | #if CONFIG_IS_ENABLED(IMX_RDC) |
317 | isolate_resource(); | |
318 | #endif | |
35c4ce5e | 319 | |
723f8359 BD |
320 | init_snvs(); |
321 | ||
b0598378 AH |
322 | imx_gpcv2_init(); |
323 | ||
c5752f73 AA |
324 | return 0; |
325 | } | |
bc7c9ed3 JN |
326 | #else |
327 | int arch_cpu_init(void) | |
328 | { | |
329 | init_cpu_basic(); | |
330 | ||
c5752f73 AA |
331 | return 0; |
332 | } | |
be277c3a | 333 | #endif |
c5752f73 | 334 | |
ec7fde3e SA |
335 | #ifdef CONFIG_ARCH_MISC_INIT |
336 | int arch_misc_init(void) | |
337 | { | |
338 | #ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG | |
339 | if (is_mx7d()) | |
382bee57 | 340 | env_set("soc", "imx7d"); |
ec7fde3e | 341 | else |
382bee57 | 342 | env_set("soc", "imx7s"); |
ec7fde3e SA |
343 | #endif |
344 | ||
d1ceb0c4 BD |
345 | #ifdef CONFIG_FSL_CAAM |
346 | sec_init(); | |
347 | #endif | |
348 | ||
ec7fde3e SA |
349 | return 0; |
350 | } | |
351 | #endif | |
352 | ||
c5752f73 | 353 | #ifdef CONFIG_SERIAL_TAG |
1ab1ffde BD |
354 | /* |
355 | * OCOTP_TESTER | |
356 | * i.MX 7Solo Applications Processor Reference Manual, Rev. 0.1, 08/2016 | |
357 | * OCOTP_TESTER describes a unique ID based on silicon wafer | |
358 | * and die X/Y position | |
359 | * | |
360 | * OCOTOP_TESTER offset 0x410 | |
361 | * 31:0 fuse 0 | |
362 | * FSL-wide unique, encoded LOT ID STD II/SJC CHALLENGE/ Unique ID | |
363 | * | |
364 | * OCOTP_TESTER1 offset 0x420 | |
365 | * 31:24 fuse 1 | |
366 | * The X-coordinate of the die location on the wafer/SJC CHALLENGE/ Unique ID | |
367 | * 23:16 fuse 1 | |
368 | * The Y-coordinate of the die location on the wafer/SJC CHALLENGE/ Unique ID | |
369 | * 15:11 fuse 1 | |
370 | * The wafer number of the wafer on which the device was fabricated/SJC | |
371 | * CHALLENGE/ Unique ID | |
372 | * 10:0 fuse 1 | |
373 | * FSL-wide unique, encoded LOT ID STD II/SJC CHALLENGE/ Unique ID | |
374 | */ | |
c5752f73 AA |
375 | void get_board_serial(struct tag_serialnr *serialnr) |
376 | { | |
377 | struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR; | |
378 | struct fuse_bank *bank = &ocotp->bank[0]; | |
379 | struct fuse_bank0_regs *fuse = | |
380 | (struct fuse_bank0_regs *)bank->fuse_regs; | |
381 | ||
382 | serialnr->low = fuse->tester0; | |
383 | serialnr->high = fuse->tester1; | |
384 | } | |
385 | #endif | |
386 | ||
c5752f73 AA |
387 | void set_wdog_reset(struct wdog_regs *wdog) |
388 | { | |
389 | u32 reg = readw(&wdog->wcr); | |
390 | /* | |
391 | * Output WDOG_B signal to reset external pmic or POR_B decided by | |
392 | * the board desgin. Without external reset, the peripherals/DDR/ | |
393 | * PMIC are not reset, that may cause system working abnormal. | |
394 | */ | |
395 | reg = readw(&wdog->wcr); | |
396 | reg |= 1 << 3; | |
397 | /* | |
398 | * WDZST bit is write-once only bit. Align this bit in kernel, | |
399 | * otherwise kernel code will have no chance to set this bit. | |
400 | */ | |
401 | reg |= 1 << 0; | |
402 | writew(reg, &wdog->wcr); | |
403 | } | |
404 | ||
c5752f73 AA |
405 | void s_init(void) |
406 | { | |
c5752f73 AA |
407 | /* clock configuration. */ |
408 | clock_init(); | |
409 | ||
410 | return; | |
411 | } | |
9f8fa184 PF |
412 | |
413 | void reset_misc(void) | |
414 | { | |
bab289cb | 415 | #ifndef CONFIG_SPL_BUILD |
8c1df09f | 416 | #if defined(CONFIG_VIDEO_MXS) && !defined(CONFIG_DM_VIDEO) |
9f8fa184 PF |
417 | lcdif_power_down(); |
418 | #endif | |
bab289cb | 419 | #endif |
9f8fa184 PF |
420 | } |
421 |