blob: d47638e8a91a753b7908c0b686d460bc9116962e [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Peng Faneae4de22018-01-10 13:20:37 +08002/*
Gaurav Jain81113a02022-03-24 11:50:27 +05303 * Copyright 2017-2019, 2021 NXP
Peng Faneae4de22018-01-10 13:20:37 +08004 *
5 * Peng Fan <peng.fan@nxp.com>
Peng Faneae4de22018-01-10 13:20:37 +08006 */
7
8#include <common.h>
Simon Glass1d91ba72019-11-14 12:57:37 -07009#include <cpu_func.h>
Simon Glassfc557362022-03-04 08:43:05 -070010#include <event.h>
Simon Glass97589732020-05-10 11:40:02 -060011#include <init.h>
Simon Glass0f2af882020-05-10 11:40:05 -060012#include <log.h>
Peng Faneae4de22018-01-10 13:20:37 +080013#include <asm/arch/imx-regs.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060014#include <asm/global_data.h>
Peng Faneae4de22018-01-10 13:20:37 +080015#include <asm/io.h>
16#include <asm/arch/clock.h>
17#include <asm/arch/sys_proto.h>
18#include <asm/mach-imx/hab.h>
19#include <asm/mach-imx/boot_mode.h>
20#include <asm/mach-imx/syscounter.h>
Peng Fana35215d2020-07-09 13:39:26 +080021#include <asm/ptrace.h>
Peng Faneae4de22018-01-10 13:20:37 +080022#include <asm/armv8/mmu.h>
Peng Fanc98e0322019-08-27 06:25:58 +000023#include <dm/uclass.h>
Gaurav Jain81113a02022-03-24 11:50:27 +053024#include <dm/device.h>
Peng Fana35215d2020-07-09 13:39:26 +080025#include <efi_loader.h>
Ye Li0513f362019-07-15 01:16:46 -070026#include <env.h>
27#include <env_internal.h>
Peng Faneae4de22018-01-10 13:20:37 +080028#include <errno.h>
29#include <fdt_support.h>
30#include <fsl_wdog.h>
31#include <imx_sip.h>
Peng Fan45d843a2020-05-11 15:14:04 +080032#include <linux/arm-smccc.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -060033#include <linux/bitops.h>
Peng Faneae4de22018-01-10 13:20:37 +080034
35DECLARE_GLOBAL_DATA_PTR;
36
Stefano Babicf8b509b2019-09-20 08:47:53 +020037#if defined(CONFIG_IMX_HAB)
Peng Faneae4de22018-01-10 13:20:37 +080038struct imx_sec_config_fuse_t const imx_sec_config_fuse = {
39 .bank = 1,
40 .word = 3,
41};
42#endif
43
44int timer_init(void)
45{
46#ifdef CONFIG_SPL_BUILD
47 struct sctr_regs *sctr = (struct sctr_regs *)SYSCNT_CTRL_BASE_ADDR;
48 unsigned long freq = readl(&sctr->cntfid0);
49
50 /* Update with accurate clock frequency */
51 asm volatile("msr cntfrq_el0, %0" : : "r" (freq) : "memory");
52
53 clrsetbits_le32(&sctr->cntcr, SC_CNTCR_FREQ0 | SC_CNTCR_FREQ1,
54 SC_CNTCR_FREQ0 | SC_CNTCR_ENABLE | SC_CNTCR_HDBG);
55#endif
56
57 gd->arch.tbl = 0;
58 gd->arch.tbu = 0;
59
60 return 0;
61}
62
63void enable_tzc380(void)
64{
65 struct iomuxc_gpr_base_regs *gpr =
66 (struct iomuxc_gpr_base_regs *)IOMUXC_GPR_BASE_ADDR;
67
68 /* Enable TZASC and lock setting */
69 setbits_le32(&gpr->gpr[10], GPR_TZASC_EN);
70 setbits_le32(&gpr->gpr[10], GPR_TZASC_EN_LOCK);
Andrey Zhizhikin7c2d23a2022-01-24 21:48:09 +010071
72 /*
73 * According to TRM, TZASC_ID_SWAP_BYPASS should be set in
74 * order to avoid AXI Bus errors when GPU is in use
75 */
Peng Fanc0e47fc2019-12-27 10:19:42 +080076 if (is_imx8mm() || is_imx8mn() || is_imx8mp())
Andrey Zhizhikin7c2d23a2022-01-24 21:48:09 +010077 setbits_le32(&gpr->gpr[10], GPR_TZASC_ID_SWAP_BYPASS);
78
79 /*
80 * imx8mn and imx8mp implements the lock bit for
81 * TZASC_ID_SWAP_BYPASS, enable it to lock settings
82 */
83 if (is_imx8mn() || is_imx8mp())
84 setbits_le32(&gpr->gpr[10], GPR_TZASC_ID_SWAP_BYPASS_LOCK);
85
Ye Li4c97c462019-08-27 06:25:34 +000086 /*
87 * set Region 0 attribute to allow secure and non-secure
88 * read/write permission. Found some masters like usb dwc3
89 * controllers can't work with secure memory.
90 */
91 writel(0xf0000000, TZASC_BASE_ADDR + 0x108);
Peng Faneae4de22018-01-10 13:20:37 +080092}
93
94void set_wdog_reset(struct wdog_regs *wdog)
95{
96 /*
97 * Output WDOG_B signal to reset external pmic or POR_B decided by
98 * the board design. Without external reset, the peripherals/DDR/
99 * PMIC are not reset, that may cause system working abnormal.
100 * WDZST bit is write-once only bit. Align this bit in kernel,
101 * otherwise kernel code will have no chance to set this bit.
102 */
103 setbits_le16(&wdog->wcr, WDOG_WDT_MASK | WDOG_WDZST_MASK);
104}
105
106static struct mm_region imx8m_mem_map[] = {
107 {
108 /* ROM */
109 .virt = 0x0UL,
110 .phys = 0x0UL,
111 .size = 0x100000UL,
112 .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
113 PTE_BLOCK_OUTER_SHARE
114 }, {
Gary Bisson5c72a452018-11-14 17:55:28 +0100115 /* CAAM */
116 .virt = 0x100000UL,
117 .phys = 0x100000UL,
118 .size = 0x8000UL,
119 .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
120 PTE_BLOCK_NON_SHARE |
121 PTE_BLOCK_PXN | PTE_BLOCK_UXN
122 }, {
Marek Vasutb1738e02021-02-25 21:52:26 +0100123 /* OCRAM_S */
124 .virt = 0x180000UL,
125 .phys = 0x180000UL,
126 .size = 0x8000UL,
127 .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
128 PTE_BLOCK_OUTER_SHARE
129 }, {
Gary Bisson5c72a452018-11-14 17:55:28 +0100130 /* TCM */
131 .virt = 0x7C0000UL,
132 .phys = 0x7C0000UL,
133 .size = 0x80000UL,
134 .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
135 PTE_BLOCK_NON_SHARE |
136 PTE_BLOCK_PXN | PTE_BLOCK_UXN
137 }, {
Peng Faneae4de22018-01-10 13:20:37 +0800138 /* OCRAM */
139 .virt = 0x900000UL,
140 .phys = 0x900000UL,
141 .size = 0x200000UL,
142 .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
143 PTE_BLOCK_OUTER_SHARE
144 }, {
145 /* AIPS */
146 .virt = 0xB00000UL,
147 .phys = 0xB00000UL,
148 .size = 0x3f500000UL,
149 .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
150 PTE_BLOCK_NON_SHARE |
151 PTE_BLOCK_PXN | PTE_BLOCK_UXN
152 }, {
153 /* DRAM1 */
154 .virt = 0x40000000UL,
155 .phys = 0x40000000UL,
Peng Fanb749b5e2019-08-27 06:25:27 +0000156 .size = PHYS_SDRAM_SIZE,
Peng Faneae4de22018-01-10 13:20:37 +0800157 .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
158 PTE_BLOCK_OUTER_SHARE
Peng Fanb749b5e2019-08-27 06:25:27 +0000159#ifdef PHYS_SDRAM_2_SIZE
Peng Faneae4de22018-01-10 13:20:37 +0800160 }, {
161 /* DRAM2 */
162 .virt = 0x100000000UL,
163 .phys = 0x100000000UL,
Peng Fanb749b5e2019-08-27 06:25:27 +0000164 .size = PHYS_SDRAM_2_SIZE,
Peng Faneae4de22018-01-10 13:20:37 +0800165 .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
166 PTE_BLOCK_OUTER_SHARE
Peng Fanb749b5e2019-08-27 06:25:27 +0000167#endif
Peng Faneae4de22018-01-10 13:20:37 +0800168 }, {
Peng Fanfa35c3d2020-07-09 15:26:06 +0800169 /* empty entrie to split table entry 5 if needed when TEEs are used */
170 0,
171 }, {
Peng Faneae4de22018-01-10 13:20:37 +0800172 /* List terminator */
173 0,
174 }
175};
176
177struct mm_region *mem_map = imx8m_mem_map;
178
Marek Vasute48aac02021-02-27 14:59:00 +0100179static unsigned int imx8m_find_dram_entry_in_mem_map(void)
180{
181 int i;
182
183 for (i = 0; i < ARRAY_SIZE(imx8m_mem_map); i++)
184 if (imx8m_mem_map[i].phys == CONFIG_SYS_SDRAM_BASE)
185 return i;
186
187 hang(); /* Entry not found, this must never happen. */
188}
189
Peng Fanb749b5e2019-08-27 06:25:27 +0000190void enable_caches(void)
191{
Peng Fanfa35c3d2020-07-09 15:26:06 +0800192 /* If OPTEE runs, remove OPTEE memory from MMU table to avoid speculative prefetch */
193 if (rom_pointer[1]) {
194 /*
195 * TEE are loaded, So the ddr bank structures
196 * have been modified update mmu table accordingly
197 */
198 int i = 0;
199 /*
200 * please make sure that entry initial value matches
201 * imx8m_mem_map for DRAM1
202 */
Marek Vasute48aac02021-02-27 14:59:00 +0100203 int entry = imx8m_find_dram_entry_in_mem_map();
Peng Fanfa35c3d2020-07-09 15:26:06 +0800204 u64 attrs = imx8m_mem_map[entry].attrs;
205
Marek Vasute48aac02021-02-27 14:59:00 +0100206 while (i < CONFIG_NR_DRAM_BANKS &&
207 entry < ARRAY_SIZE(imx8m_mem_map)) {
Peng Fanfa35c3d2020-07-09 15:26:06 +0800208 if (gd->bd->bi_dram[i].start == 0)
209 break;
210 imx8m_mem_map[entry].phys = gd->bd->bi_dram[i].start;
211 imx8m_mem_map[entry].virt = gd->bd->bi_dram[i].start;
212 imx8m_mem_map[entry].size = gd->bd->bi_dram[i].size;
213 imx8m_mem_map[entry].attrs = attrs;
214 debug("Added memory mapping (%d): %llx %llx\n", entry,
215 imx8m_mem_map[entry].phys, imx8m_mem_map[entry].size);
216 i++; entry++;
217 }
218 }
Peng Fanb749b5e2019-08-27 06:25:27 +0000219
220 icache_enable();
221 dcache_enable();
222}
223
Peng Fanfa35c3d2020-07-09 15:26:06 +0800224__weak int board_phys_sdram_size(phys_size_t *size)
225{
226 if (!size)
227 return -EINVAL;
228
229 *size = PHYS_SDRAM_SIZE;
230 return 0;
231}
232
233int dram_init(void)
234{
Marek Vasute48aac02021-02-27 14:59:00 +0100235 unsigned int entry = imx8m_find_dram_entry_in_mem_map();
Peng Fanfa35c3d2020-07-09 15:26:06 +0800236 phys_size_t sdram_size;
237 int ret;
238
239 ret = board_phys_sdram_size(&sdram_size);
240 if (ret)
241 return ret;
242
243 /* rom_pointer[1] contains the size of TEE occupies */
244 if (rom_pointer[1])
245 gd->ram_size = sdram_size - rom_pointer[1];
246 else
247 gd->ram_size = sdram_size;
248
Tim Harvey32927bc2020-09-25 08:08:35 -0700249 /* also update the SDRAM size in the mem_map used externally */
Marek Vasute48aac02021-02-27 14:59:00 +0100250 imx8m_mem_map[entry].size = sdram_size;
Tim Harvey32927bc2020-09-25 08:08:35 -0700251
Peng Fanfa35c3d2020-07-09 15:26:06 +0800252#ifdef PHYS_SDRAM_2_SIZE
253 gd->ram_size += PHYS_SDRAM_2_SIZE;
254#endif
255
256 return 0;
257}
258
259int dram_init_banksize(void)
260{
261 int bank = 0;
262 int ret;
263 phys_size_t sdram_size;
264
265 ret = board_phys_sdram_size(&sdram_size);
266 if (ret)
267 return ret;
268
269 gd->bd->bi_dram[bank].start = PHYS_SDRAM;
270 if (rom_pointer[1]) {
271 phys_addr_t optee_start = (phys_addr_t)rom_pointer[0];
272 phys_size_t optee_size = (size_t)rom_pointer[1];
273
274 gd->bd->bi_dram[bank].size = optee_start - gd->bd->bi_dram[bank].start;
275 if ((optee_start + optee_size) < (PHYS_SDRAM + sdram_size)) {
276 if (++bank >= CONFIG_NR_DRAM_BANKS) {
277 puts("CONFIG_NR_DRAM_BANKS is not enough\n");
278 return -1;
279 }
280
281 gd->bd->bi_dram[bank].start = optee_start + optee_size;
282 gd->bd->bi_dram[bank].size = PHYS_SDRAM +
283 sdram_size - gd->bd->bi_dram[bank].start;
284 }
285 } else {
286 gd->bd->bi_dram[bank].size = sdram_size;
287 }
288
289#ifdef PHYS_SDRAM_2_SIZE
290 if (++bank >= CONFIG_NR_DRAM_BANKS) {
291 puts("CONFIG_NR_DRAM_BANKS is not enough for SDRAM_2\n");
292 return -1;
293 }
294 gd->bd->bi_dram[bank].start = PHYS_SDRAM_2;
295 gd->bd->bi_dram[bank].size = PHYS_SDRAM_2_SIZE;
296#endif
297
298 return 0;
299}
300
301phys_size_t get_effective_memsize(void)
302{
303 /* return the first bank as effective memory */
304 if (rom_pointer[1])
305 return ((phys_addr_t)rom_pointer[0] - PHYS_SDRAM);
306
307#ifdef PHYS_SDRAM_2_SIZE
308 return gd->ram_size - PHYS_SDRAM_2_SIZE;
309#else
310 return gd->ram_size;
311#endif
312}
313
Frieder Schrempf159879e2021-06-07 14:36:44 +0200314ulong board_get_usable_ram_top(ulong total_size)
315{
Ying-Chun Liu (PaulLiu)ed55caf2021-08-23 10:43:06 +0800316 ulong top_addr = PHYS_SDRAM + gd->ram_size;
317
Frieder Schrempf159879e2021-06-07 14:36:44 +0200318 /*
319 * Some IPs have their accessible address space restricted by
320 * the interconnect. Let's make sure U-Boot only ever uses the
321 * space below the 4G address boundary (which is 3GiB big),
322 * even when the effective available memory is bigger.
323 */
Ying-Chun Liu (PaulLiu)ed55caf2021-08-23 10:43:06 +0800324 if (top_addr > 0x80000000)
325 top_addr = 0x80000000;
326
327 /*
328 * rom_pointer[0] stores the TEE memory start address.
329 * rom_pointer[1] stores the size TEE uses.
330 * We need to reserve the memory region for TEE.
331 */
332 if (rom_pointer[0] && rom_pointer[1] && top_addr > rom_pointer[0])
333 top_addr = rom_pointer[0];
Frieder Schrempf159879e2021-06-07 14:36:44 +0200334
Ying-Chun Liu (PaulLiu)ed55caf2021-08-23 10:43:06 +0800335 return top_addr;
Frieder Schrempf159879e2021-06-07 14:36:44 +0200336}
337
Peng Fan1caffdf2019-08-27 06:25:17 +0000338static u32 get_cpu_variant_type(u32 type)
339{
340 struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR;
341 struct fuse_bank *bank = &ocotp->bank[1];
342 struct fuse_bank1_regs *fuse =
343 (struct fuse_bank1_regs *)bank->fuse_regs;
344
345 u32 value = readl(&fuse->tester4);
346
Peng Fan67815082020-02-05 17:34:54 +0800347 if (type == MXC_CPU_IMX8MQ) {
348 if ((value & 0x3) == 0x2)
349 return MXC_CPU_IMX8MD;
350 else if (value & 0x200000)
351 return MXC_CPU_IMX8MQL;
352
353 } else if (type == MXC_CPU_IMX8MM) {
Peng Fan1caffdf2019-08-27 06:25:17 +0000354 switch (value & 0x3) {
355 case 2:
356 if (value & 0x1c0000)
357 return MXC_CPU_IMX8MMDL;
358 else
359 return MXC_CPU_IMX8MMD;
360 case 3:
361 if (value & 0x1c0000)
362 return MXC_CPU_IMX8MMSL;
363 else
364 return MXC_CPU_IMX8MMS;
365 default:
366 if (value & 0x1c0000)
367 return MXC_CPU_IMX8MML;
368 break;
369 }
Peng Fan1a07d912020-02-05 17:39:27 +0800370 } else if (type == MXC_CPU_IMX8MN) {
371 switch (value & 0x3) {
372 case 2:
Ye Li715180e2021-03-19 15:57:11 +0800373 if (value & 0x1000000) {
374 if (value & 0x10000000) /* MIPI DSI */
375 return MXC_CPU_IMX8MNUD;
376 else
377 return MXC_CPU_IMX8MNDL;
378 } else {
Peng Fan1a07d912020-02-05 17:39:27 +0800379 return MXC_CPU_IMX8MND;
Ye Li715180e2021-03-19 15:57:11 +0800380 }
Peng Fan1a07d912020-02-05 17:39:27 +0800381 case 3:
Ye Li715180e2021-03-19 15:57:11 +0800382 if (value & 0x1000000) {
383 if (value & 0x10000000) /* MIPI DSI */
384 return MXC_CPU_IMX8MNUS;
385 else
386 return MXC_CPU_IMX8MNSL;
387 } else {
Peng Fan1a07d912020-02-05 17:39:27 +0800388 return MXC_CPU_IMX8MNS;
Ye Li715180e2021-03-19 15:57:11 +0800389 }
Peng Fan1a07d912020-02-05 17:39:27 +0800390 default:
Ye Li715180e2021-03-19 15:57:11 +0800391 if (value & 0x1000000) {
392 if (value & 0x10000000) /* MIPI DSI */
393 return MXC_CPU_IMX8MNUQ;
394 else
395 return MXC_CPU_IMX8MNL;
396 }
Peng Fan1a07d912020-02-05 17:39:27 +0800397 break;
398 }
Ye Lid2d754f2020-04-20 20:12:54 -0700399 } else if (type == MXC_CPU_IMX8MP) {
400 u32 value0 = readl(&fuse->tester3);
401 u32 flag = 0;
402
403 if ((value0 & 0xc0000) == 0x80000)
404 return MXC_CPU_IMX8MPD;
405
406 /* vpu disabled */
407 if ((value0 & 0x43000000) == 0x43000000)
408 flag = 1;
409
410 /* npu disabled*/
411 if ((value & 0x8) == 0x8)
Peng Fan0386e7f2022-04-07 15:55:52 +0800412 flag |= BIT(1);
Ye Lid2d754f2020-04-20 20:12:54 -0700413
414 /* isp disabled */
415 if ((value & 0x3) == 0x3)
Peng Fan0386e7f2022-04-07 15:55:52 +0800416 flag |= BIT(2);
417
418 /* gpu disabled */
419 if ((value & 0xc0) == 0xc0)
420 flag |= BIT(3);
421
422 /* lvds disabled */
423 if ((value & 0x180000) == 0x180000)
424 flag |= BIT(4);
425
426 /* mipi dsi disabled */
427 if ((value & 0x60000) == 0x60000)
428 flag |= BIT(5);
Ye Lid2d754f2020-04-20 20:12:54 -0700429
430 switch (flag) {
Peng Fan0386e7f2022-04-07 15:55:52 +0800431 case 0x3f:
432 return MXC_CPU_IMX8MPUL;
Ye Lid2d754f2020-04-20 20:12:54 -0700433 case 7:
434 return MXC_CPU_IMX8MPL;
Ye Lid2d754f2020-04-20 20:12:54 -0700435 case 2:
436 return MXC_CPU_IMX8MP6;
Ye Lid2d754f2020-04-20 20:12:54 -0700437 default:
438 break;
439 }
440
Peng Fan1caffdf2019-08-27 06:25:17 +0000441 }
442
443 return type;
444}
445
Peng Faneae4de22018-01-10 13:20:37 +0800446u32 get_cpu_rev(void)
447{
448 struct anamix_pll *ana_pll = (struct anamix_pll *)ANATOP_BASE_ADDR;
449 u32 reg = readl(&ana_pll->digprog);
450 u32 type = (reg >> 16) & 0xff;
Peng Fan1caffdf2019-08-27 06:25:17 +0000451 u32 major_low = (reg >> 8) & 0xff;
Peng Faneae4de22018-01-10 13:20:37 +0800452 u32 rom_version;
453
454 reg &= 0xff;
455
Peng Fan69cec072019-12-27 10:14:02 +0800456 /* iMX8MP */
457 if (major_low == 0x43) {
Ye Lid2d754f2020-04-20 20:12:54 -0700458 type = get_cpu_variant_type(MXC_CPU_IMX8MP);
Peng Fan69cec072019-12-27 10:14:02 +0800459 } else if (major_low == 0x42) {
460 /* iMX8MN */
Peng Fan1a07d912020-02-05 17:39:27 +0800461 type = get_cpu_variant_type(MXC_CPU_IMX8MN);
Peng Fan5d2f2062019-06-27 17:23:49 +0800462 } else if (major_low == 0x41) {
Peng Fan1caffdf2019-08-27 06:25:17 +0000463 type = get_cpu_variant_type(MXC_CPU_IMX8MM);
464 } else {
465 if (reg == CHIP_REV_1_0) {
466 /*
Peng Fanc23fbdd2019-10-16 10:24:17 +0000467 * For B0 chip, the DIGPROG is not updated,
468 * it is still TO1.0. we have to check ROM
469 * version or OCOTP_READ_FUSE_DATA.
470 * 0xff0055aa is magic number for B1.
Peng Fan1caffdf2019-08-27 06:25:17 +0000471 */
Peng Fanc23fbdd2019-10-16 10:24:17 +0000472 if (readl((void __iomem *)(OCOTP_BASE_ADDR + 0x40)) == 0xff0055aa) {
Ye Lic963ed12021-03-19 15:57:16 +0800473 /*
474 * B2 uses same DIGPROG and OCOTP_READ_FUSE_DATA value with B1,
475 * so have to check ROM to distinguish them
476 */
477 rom_version = readl((void __iomem *)ROM_VERSION_B0);
478 rom_version &= 0xff;
479 if (rom_version == CHIP_REV_2_2)
480 reg = CHIP_REV_2_2;
481 else
482 reg = CHIP_REV_2_1;
Peng Fanc23fbdd2019-10-16 10:24:17 +0000483 } else {
484 rom_version =
485 readl((void __iomem *)ROM_VERSION_A0);
486 if (rom_version != CHIP_REV_1_0) {
487 rom_version = readl((void __iomem *)ROM_VERSION_B0);
Patrick Wildtd4a78b92019-11-19 09:42:06 +0100488 rom_version &= 0xff;
Peng Fanc23fbdd2019-10-16 10:24:17 +0000489 if (rom_version == CHIP_REV_2_0)
490 reg = CHIP_REV_2_0;
491 }
Peng Fan1caffdf2019-08-27 06:25:17 +0000492 }
Peng Faneae4de22018-01-10 13:20:37 +0800493 }
Peng Fan67815082020-02-05 17:34:54 +0800494
495 type = get_cpu_variant_type(type);
Peng Faneae4de22018-01-10 13:20:37 +0800496 }
497
498 return (type << 12) | reg;
499}
500
501static void imx_set_wdog_powerdown(bool enable)
502{
503 struct wdog_regs *wdog1 = (struct wdog_regs *)WDOG1_BASE_ADDR;
504 struct wdog_regs *wdog2 = (struct wdog_regs *)WDOG2_BASE_ADDR;
505 struct wdog_regs *wdog3 = (struct wdog_regs *)WDOG3_BASE_ADDR;
506
507 /* Write to the PDE (Power Down Enable) bit */
508 writew(enable, &wdog1->wmcr);
509 writew(enable, &wdog2->wmcr);
510 writew(enable, &wdog3->wmcr);
511}
512
Simon Glassfc557362022-03-04 08:43:05 -0700513static int imx8m_check_clock(void *ctx, struct event *event)
Peng Fanc98e0322019-08-27 06:25:58 +0000514{
515 struct udevice *dev;
516 int ret;
517
Peng Fan3c073342019-10-16 03:01:51 +0000518 if (CONFIG_IS_ENABLED(CLK)) {
519 ret = uclass_get_device_by_name(UCLASS_CLK,
520 "clock-controller@30380000",
521 &dev);
522 if (ret < 0) {
523 printf("Failed to find clock node. Check device tree\n");
524 return ret;
525 }
Peng Fanc98e0322019-08-27 06:25:58 +0000526 }
527
528 return 0;
529}
Simon Glassfc557362022-03-04 08:43:05 -0700530EVENT_SPY(EVT_DM_POST_INIT, imx8m_check_clock);
Peng Fanc98e0322019-08-27 06:25:58 +0000531
Peng Faneae4de22018-01-10 13:20:37 +0800532int arch_cpu_init(void)
533{
Peng Fanc0b30d72019-04-17 09:41:16 +0000534 struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR;
Peng Faneae4de22018-01-10 13:20:37 +0800535 /*
Peng Fand0ca2892019-08-27 06:25:37 +0000536 * ROM might disable clock for SCTR,
537 * enable the clock before timer_init.
538 */
539 if (IS_ENABLED(CONFIG_SPL_BUILD))
540 clock_enable(CCGR_SCTR, 1);
541 /*
Peng Faneae4de22018-01-10 13:20:37 +0800542 * Init timer at very early state, because sscg pll setting
543 * will use it
544 */
545 timer_init();
546
547 if (IS_ENABLED(CONFIG_SPL_BUILD)) {
548 clock_init();
549 imx_set_wdog_powerdown(false);
Peng Fan9cf2aa32020-07-09 13:52:41 +0800550
551 if (is_imx8md() || is_imx8mmd() || is_imx8mmdl() || is_imx8mms() ||
552 is_imx8mmsl() || is_imx8mnd() || is_imx8mndl() || is_imx8mns() ||
Ye Li715180e2021-03-19 15:57:11 +0800553 is_imx8mnsl() || is_imx8mpd() || is_imx8mnud() || is_imx8mnus()) {
Peng Fan9cf2aa32020-07-09 13:52:41 +0800554 /* Power down cpu core 1, 2 and 3 for iMX8M Dual core or Single core */
555 struct pgc_reg *pgc_core1 = (struct pgc_reg *)(GPC_BASE_ADDR + 0x840);
556 struct pgc_reg *pgc_core2 = (struct pgc_reg *)(GPC_BASE_ADDR + 0x880);
557 struct pgc_reg *pgc_core3 = (struct pgc_reg *)(GPC_BASE_ADDR + 0x8C0);
558 struct gpc_reg *gpc = (struct gpc_reg *)GPC_BASE_ADDR;
559
560 writel(0x1, &pgc_core2->pgcr);
561 writel(0x1, &pgc_core3->pgcr);
Ye Li715180e2021-03-19 15:57:11 +0800562 if (is_imx8mms() || is_imx8mmsl() || is_imx8mns() || is_imx8mnsl() || is_imx8mnus()) {
Peng Fan9cf2aa32020-07-09 13:52:41 +0800563 writel(0x1, &pgc_core1->pgcr);
564 writel(0xE, &gpc->cpu_pgc_dn_trg);
565 } else {
566 writel(0xC, &gpc->cpu_pgc_dn_trg);
567 }
568 }
Peng Faneae4de22018-01-10 13:20:37 +0800569 }
570
Peng Fanc0b30d72019-04-17 09:41:16 +0000571 if (is_imx8mq()) {
572 clock_enable(CCGR_OCOTP, 1);
573 if (readl(&ocotp->ctrl) & 0x200)
574 writel(0x200, &ocotp->ctrl_clr);
575 }
576
Peng Faneae4de22018-01-10 13:20:37 +0800577 return 0;
578}
579
Peng Fanc9823b02019-09-16 03:09:36 +0000580#if defined(CONFIG_IMX8MN) || defined(CONFIG_IMX8MP)
581struct rom_api *g_rom_api = (struct rom_api *)0x980;
582
583enum boot_device get_boot_device(void)
584{
585 volatile gd_t *pgd = gd;
586 int ret;
587 u32 boot;
588 u16 boot_type;
589 u8 boot_instance;
590 enum boot_device boot_dev = SD1_BOOT;
591
592 ret = g_rom_api->query_boot_infor(QUERY_BT_DEV, &boot,
593 ((uintptr_t)&boot) ^ QUERY_BT_DEV);
Marek Behúna8cf1552021-05-20 13:24:10 +0200594 set_gd(pgd);
Peng Fanc9823b02019-09-16 03:09:36 +0000595
596 if (ret != ROM_API_OKAY) {
597 puts("ROMAPI: failure at query_boot_info\n");
598 return -1;
599 }
600
601 boot_type = boot >> 16;
602 boot_instance = (boot >> 8) & 0xff;
603
604 switch (boot_type) {
605 case BT_DEV_TYPE_SD:
606 boot_dev = boot_instance + SD1_BOOT;
607 break;
608 case BT_DEV_TYPE_MMC:
609 boot_dev = boot_instance + MMC1_BOOT;
610 break;
611 case BT_DEV_TYPE_NAND:
612 boot_dev = NAND_BOOT;
613 break;
614 case BT_DEV_TYPE_FLEXSPINOR:
615 boot_dev = QSPI_BOOT;
616 break;
Marek Vasut31b3bc42022-03-25 18:59:28 +0100617 case BT_DEV_TYPE_SPI_NOR:
618 boot_dev = SPI_NOR_BOOT;
619 break;
Peng Fanc9823b02019-09-16 03:09:36 +0000620 case BT_DEV_TYPE_USB:
621 boot_dev = USB_BOOT;
622 break;
623 default:
624 break;
625 }
626
627 return boot_dev;
628}
629#endif
630
Marek Vasut520ded02021-07-03 04:55:33 +0200631#if defined(CONFIG_IMX8M)
632#include <spl.h>
633int spl_mmc_emmc_boot_partition(struct mmc *mmc)
634{
635 u32 *rom_log_addr = (u32 *)0x9e0;
636 u32 *rom_log;
637 u8 event_id;
638 int i, part;
639
640 part = default_spl_mmc_emmc_boot_partition(mmc);
641
642 /* If the ROM event log pointer is not valid. */
643 if (*rom_log_addr < 0x900000 || *rom_log_addr >= 0xb00000 ||
644 *rom_log_addr & 0x3)
645 return part;
646
647 /* Parse the ROM event ID version 2 log */
648 rom_log = (u32 *)(uintptr_t)(*rom_log_addr);
649 for (i = 0; i < 128; i++) {
650 event_id = rom_log[i] >> 24;
651 switch (event_id) {
652 case 0x00: /* End of list */
653 return part;
654 /* Log entries with 1 parameter, skip 1 */
655 case 0x80: /* Start to perform the device initialization */
656 case 0x81: /* The boot device initialization completes */
657 case 0x8f: /* The boot device initialization fails */
658 case 0x90: /* Start to read data from boot device */
659 case 0x91: /* Reading data from boot device completes */
660 case 0x9f: /* Reading data from boot device fails */
661 i += 1;
662 continue;
663 /* Log entries with 2 parameters, skip 2 */
664 case 0xa0: /* Image authentication result */
665 case 0xc0: /* Jump to the boot image soon */
666 i += 2;
667 continue;
668 /* Boot from the secondary boot image */
669 case 0x51:
670 /*
671 * Swap the eMMC boot partitions in case there was a
672 * fallback event (i.e. primary image was corrupted
673 * and that corruption was recognized by the BootROM),
674 * so the SPL loads the rest of the U-Boot from the
675 * correct eMMC boot partition, since the BootROM
676 * leaves the boot partition set to the corrupted one.
677 */
678 if (part == 1)
679 part = 2;
680 else if (part == 2)
681 part = 1;
682 continue;
683 default:
684 continue;
685 }
686 }
687
688 return part;
689}
690#endif
691
Peng Faneae4de22018-01-10 13:20:37 +0800692bool is_usb_boot(void)
693{
694 return get_boot_device() == USB_BOOT;
695}
696
697#ifdef CONFIG_OF_SYSTEM_SETUP
Peng Fan435dc122020-07-09 14:06:49 +0800698bool check_fdt_new_path(void *blob)
699{
700 const char *soc_path = "/soc@0";
701 int nodeoff;
702
703 nodeoff = fdt_path_offset(blob, soc_path);
704 if (nodeoff < 0)
705 return false;
706
707 return true;
708}
709
710static int disable_fdt_nodes(void *blob, const char *const nodes_path[], int size_array)
711{
712 int i = 0;
713 int rc;
714 int nodeoff;
715 const char *status = "disabled";
716
717 for (i = 0; i < size_array; i++) {
718 nodeoff = fdt_path_offset(blob, nodes_path[i]);
719 if (nodeoff < 0)
720 continue; /* Not found, skip it */
721
722 printf("Found %s node\n", nodes_path[i]);
723
724add_status:
725 rc = fdt_setprop(blob, nodeoff, "status", status, strlen(status) + 1);
726 if (rc) {
727 if (rc == -FDT_ERR_NOSPACE) {
728 rc = fdt_increase_size(blob, 512);
729 if (!rc)
730 goto add_status;
731 }
732 printf("Unable to update property %s:%s, err=%s\n",
733 nodes_path[i], "status", fdt_strerror(rc));
734 } else {
735 printf("Modify %s:%s disabled\n",
736 nodes_path[i], "status");
737 }
738 }
739
740 return 0;
741}
742
743#ifdef CONFIG_IMX8MQ
744bool check_dcss_fused(void)
745{
746 struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR;
747 struct fuse_bank *bank = &ocotp->bank[1];
748 struct fuse_bank1_regs *fuse =
749 (struct fuse_bank1_regs *)bank->fuse_regs;
750 u32 value = readl(&fuse->tester4);
751
752 if (value & 0x4000000)
753 return true;
754
755 return false;
756}
757
758static int disable_mipi_dsi_nodes(void *blob)
759{
760 static const char * const nodes_path[] = {
761 "/mipi_dsi@30A00000",
762 "/mipi_dsi_bridge@30A00000",
763 "/dsi_phy@30A00300",
764 "/soc@0/bus@30800000/mipi_dsi@30a00000",
Peng Fan7d4195c2021-03-19 15:57:13 +0800765 "/soc@0/bus@30800000/dphy@30a00300",
766 "/soc@0/bus@30800000/mipi-dsi@30a00000",
Peng Fan435dc122020-07-09 14:06:49 +0800767 };
768
769 return disable_fdt_nodes(blob, nodes_path, ARRAY_SIZE(nodes_path));
770}
771
772static int disable_dcss_nodes(void *blob)
773{
774 static const char * const nodes_path[] = {
775 "/dcss@0x32e00000",
776 "/dcss@32e00000",
777 "/hdmi@32c00000",
778 "/hdmi_cec@32c33800",
779 "/hdmi_drm@32c00000",
780 "/display-subsystem",
781 "/sound-hdmi",
782 "/sound-hdmi-arc",
783 "/soc@0/bus@32c00000/display-controller@32e00000",
784 "/soc@0/bus@32c00000/hdmi@32c00000",
785 };
786
787 return disable_fdt_nodes(blob, nodes_path, ARRAY_SIZE(nodes_path));
788}
789
790static int check_mipi_dsi_nodes(void *blob)
791{
792 static const char * const lcdif_path[] = {
793 "/lcdif@30320000",
Peng Fan7d4195c2021-03-19 15:57:13 +0800794 "/soc@0/bus@30000000/lcdif@30320000",
795 "/soc@0/bus@30000000/lcd-controller@30320000"
Peng Fan435dc122020-07-09 14:06:49 +0800796 };
797 static const char * const mipi_dsi_path[] = {
798 "/mipi_dsi@30A00000",
799 "/soc@0/bus@30800000/mipi_dsi@30a00000"
800 };
801 static const char * const lcdif_ep_path[] = {
802 "/lcdif@30320000/port@0/mipi-dsi-endpoint",
Peng Fan7d4195c2021-03-19 15:57:13 +0800803 "/soc@0/bus@30000000/lcdif@30320000/port@0/endpoint",
804 "/soc@0/bus@30000000/lcd-controller@30320000/port@0/endpoint"
Peng Fan435dc122020-07-09 14:06:49 +0800805 };
806 static const char * const mipi_dsi_ep_path[] = {
807 "/mipi_dsi@30A00000/port@1/endpoint",
Peng Fan7d4195c2021-03-19 15:57:13 +0800808 "/soc@0/bus@30800000/mipi_dsi@30a00000/ports/port@0/endpoint",
809 "/soc@0/bus@30800000/mipi-dsi@30a00000/ports/port@0/endpoint@0"
Peng Fan435dc122020-07-09 14:06:49 +0800810 };
811
812 int lookup_node;
813 int nodeoff;
814 bool new_path = check_fdt_new_path(blob);
815 int i = new_path ? 1 : 0;
816
817 nodeoff = fdt_path_offset(blob, lcdif_path[i]);
818 if (nodeoff < 0 || !fdtdec_get_is_enabled(blob, nodeoff)) {
819 /*
820 * If can't find lcdif node or lcdif node is disabled,
821 * then disable all mipi dsi, since they only can input
822 * from DCSS
823 */
824 return disable_mipi_dsi_nodes(blob);
825 }
826
827 nodeoff = fdt_path_offset(blob, mipi_dsi_path[i]);
828 if (nodeoff < 0 || !fdtdec_get_is_enabled(blob, nodeoff))
829 return 0;
830
831 nodeoff = fdt_path_offset(blob, lcdif_ep_path[i]);
832 if (nodeoff < 0) {
833 /*
834 * If can't find lcdif endpoint, then disable all mipi dsi,
835 * since they only can input from DCSS
836 */
837 return disable_mipi_dsi_nodes(blob);
838 }
839
840 lookup_node = fdtdec_lookup_phandle(blob, nodeoff, "remote-endpoint");
841 nodeoff = fdt_path_offset(blob, mipi_dsi_ep_path[i]);
842
843 if (nodeoff > 0 && nodeoff == lookup_node)
844 return 0;
845
846 return disable_mipi_dsi_nodes(blob);
847}
848#endif
849
850int disable_vpu_nodes(void *blob)
851{
852 static const char * const nodes_path_8mq[] = {
853 "/vpu@38300000",
854 "/soc@0/vpu@38300000"
855 };
856
857 static const char * const nodes_path_8mm[] = {
858 "/vpu_g1@38300000",
859 "/vpu_g2@38310000",
860 "/vpu_h1@38320000"
861 };
862
863 static const char * const nodes_path_8mp[] = {
864 "/vpu_g1@38300000",
865 "/vpu_g2@38310000",
866 "/vpu_vc8000e@38320000"
867 };
868
869 if (is_imx8mq())
870 return disable_fdt_nodes(blob, nodes_path_8mq, ARRAY_SIZE(nodes_path_8mq));
871 else if (is_imx8mm())
872 return disable_fdt_nodes(blob, nodes_path_8mm, ARRAY_SIZE(nodes_path_8mm));
873 else if (is_imx8mp())
874 return disable_fdt_nodes(blob, nodes_path_8mp, ARRAY_SIZE(nodes_path_8mp));
875 else
876 return -EPERM;
877}
878
Ye Liee337ce2021-03-19 15:57:09 +0800879#ifdef CONFIG_IMX8MN_LOW_DRIVE_MODE
880static int low_drive_gpu_freq(void *blob)
881{
882 static const char *nodes_path_8mn[] = {
883 "/gpu@38000000",
884 "/soc@0/gpu@38000000"
885 };
886
887 int nodeoff, cnt, i;
888 u32 assignedclks[7];
889
890 nodeoff = fdt_path_offset(blob, nodes_path_8mn[0]);
891 if (nodeoff < 0)
892 return nodeoff;
893
894 cnt = fdtdec_get_int_array_count(blob, nodeoff, "assigned-clock-rates", assignedclks, 7);
895 if (cnt < 0)
896 return cnt;
897
898 if (cnt != 7)
899 printf("Warning: %s, assigned-clock-rates count %d\n", nodes_path_8mn[0], cnt);
900
901 assignedclks[cnt - 1] = 200000000;
902 assignedclks[cnt - 2] = 200000000;
903
904 for (i = 0; i < cnt; i++) {
905 debug("<%u>, ", assignedclks[i]);
906 assignedclks[i] = cpu_to_fdt32(assignedclks[i]);
907 }
908 debug("\n");
909
910 return fdt_setprop(blob, nodeoff, "assigned-clock-rates", &assignedclks, sizeof(assignedclks));
911}
912#endif
913
Peng Fanf5f9b8e2022-04-07 15:55:53 +0800914static bool check_remote_endpoint(void *blob, const char *ep1, const char *ep2)
915{
916 int lookup_node;
917 int nodeoff;
918
919 nodeoff = fdt_path_offset(blob, ep1);
920 if (nodeoff) {
921 lookup_node = fdtdec_lookup_phandle(blob, nodeoff, "remote-endpoint");
922 nodeoff = fdt_path_offset(blob, ep2);
923
924 if (nodeoff > 0 && nodeoff == lookup_node)
925 return true;
926 }
927
928 return false;
929}
930
931int disable_dsi_lcdif_nodes(void *blob)
932{
933 int ret;
934
935 static const char * const dsi_path_8mp[] = {
936 "/soc@0/bus@32c00000/mipi_dsi@32e60000"
937 };
938
939 static const char * const lcdif_path_8mp[] = {
940 "/soc@0/bus@32c00000/lcd-controller@32e80000"
941 };
942
943 static const char * const lcdif_ep_path_8mp[] = {
944 "/soc@0/bus@32c00000/lcd-controller@32e80000/port@0/endpoint"
945 };
946 static const char * const dsi_ep_path_8mp[] = {
947 "/soc@0/bus@32c00000/mipi_dsi@32e60000/port@0/endpoint"
948 };
949
950 ret = disable_fdt_nodes(blob, dsi_path_8mp, ARRAY_SIZE(dsi_path_8mp));
951 if (ret)
952 return ret;
953
954 if (check_remote_endpoint(blob, dsi_ep_path_8mp[0], lcdif_ep_path_8mp[0])) {
955 /* Disable lcdif node */
956 return disable_fdt_nodes(blob, lcdif_path_8mp, ARRAY_SIZE(lcdif_path_8mp));
957 }
958
959 return 0;
960}
961
962int disable_lvds_lcdif_nodes(void *blob)
963{
964 int ret, i;
965
966 static const char * const ldb_path_8mp[] = {
967 "/soc@0/bus@32c00000/ldb@32ec005c",
968 "/soc@0/bus@32c00000/phy@32ec0128"
969 };
970
971 static const char * const lcdif_path_8mp[] = {
972 "/soc@0/bus@32c00000/lcd-controller@32e90000"
973 };
974
975 static const char * const lcdif_ep_path_8mp[] = {
976 "/soc@0/bus@32c00000/lcd-controller@32e90000/port@0/endpoint@0",
977 "/soc@0/bus@32c00000/lcd-controller@32e90000/port@0/endpoint@1"
978 };
979 static const char * const ldb_ep_path_8mp[] = {
980 "/soc@0/bus@32c00000/ldb@32ec005c/lvds-channel@0/port@0/endpoint",
981 "/soc@0/bus@32c00000/ldb@32ec005c/lvds-channel@1/port@0/endpoint"
982 };
983
984 ret = disable_fdt_nodes(blob, ldb_path_8mp, ARRAY_SIZE(ldb_path_8mp));
985 if (ret)
986 return ret;
987
988 for (i = 0; i < ARRAY_SIZE(ldb_ep_path_8mp); i++) {
989 if (check_remote_endpoint(blob, ldb_ep_path_8mp[i], lcdif_ep_path_8mp[i])) {
990 /* Disable lcdif node */
991 return disable_fdt_nodes(blob, lcdif_path_8mp, ARRAY_SIZE(lcdif_path_8mp));
992 }
993 }
994
995 return 0;
996}
997
Peng Fan435dc122020-07-09 14:06:49 +0800998int disable_gpu_nodes(void *blob)
999{
1000 static const char * const nodes_path_8mn[] = {
Peng Fan7d4195c2021-03-19 15:57:13 +08001001 "/gpu@38000000",
1002 "/soc@/gpu@38000000"
Peng Fan435dc122020-07-09 14:06:49 +08001003 };
1004
Peng Fanf5f9b8e2022-04-07 15:55:53 +08001005 static const char * const nodes_path_8mp[] = {
1006 "/gpu3d@38000000",
1007 "/gpu2d@38008000"
1008 };
1009
1010 if (is_imx8mp())
1011 return disable_fdt_nodes(blob, nodes_path_8mp, ARRAY_SIZE(nodes_path_8mp));
1012 else
1013 return disable_fdt_nodes(blob, nodes_path_8mn, ARRAY_SIZE(nodes_path_8mn));
Peng Fan435dc122020-07-09 14:06:49 +08001014}
1015
1016int disable_npu_nodes(void *blob)
1017{
1018 static const char * const nodes_path_8mp[] = {
1019 "/vipsi@38500000"
1020 };
1021
1022 return disable_fdt_nodes(blob, nodes_path_8mp, ARRAY_SIZE(nodes_path_8mp));
1023}
1024
1025int disable_isp_nodes(void *blob)
1026{
1027 static const char * const nodes_path_8mp[] = {
1028 "/soc@0/bus@32c00000/camera/isp@32e10000",
1029 "/soc@0/bus@32c00000/camera/isp@32e20000"
1030 };
1031
1032 return disable_fdt_nodes(blob, nodes_path_8mp, ARRAY_SIZE(nodes_path_8mp));
1033}
1034
1035int disable_dsp_nodes(void *blob)
1036{
1037 static const char * const nodes_path_8mp[] = {
1038 "/dsp@3b6e8000"
1039 };
1040
1041 return disable_fdt_nodes(blob, nodes_path_8mp, ARRAY_SIZE(nodes_path_8mp));
1042}
1043
Ye Li26517af2021-03-19 15:57:12 +08001044static void disable_thermal_cpu_nodes(void *blob, u32 disabled_cores)
1045{
1046 static const char * const thermal_path[] = {
1047 "/thermal-zones/cpu-thermal/cooling-maps/map0"
1048 };
1049
1050 int nodeoff, cnt, i, ret, j;
1051 u32 cooling_dev[12];
1052
1053 for (i = 0; i < ARRAY_SIZE(thermal_path); i++) {
1054 nodeoff = fdt_path_offset(blob, thermal_path[i]);
1055 if (nodeoff < 0)
1056 continue; /* Not found, skip it */
1057
1058 cnt = fdtdec_get_int_array_count(blob, nodeoff, "cooling-device", cooling_dev, 12);
1059 if (cnt < 0)
1060 continue;
1061
1062 if (cnt != 12)
1063 printf("Warning: %s, cooling-device count %d\n", thermal_path[i], cnt);
1064
1065 for (j = 0; j < cnt; j++)
1066 cooling_dev[j] = cpu_to_fdt32(cooling_dev[j]);
1067
1068 ret = fdt_setprop(blob, nodeoff, "cooling-device", &cooling_dev,
1069 sizeof(u32) * (12 - disabled_cores * 3));
1070 if (ret < 0) {
1071 printf("Warning: %s, cooling-device setprop failed %d\n",
1072 thermal_path[i], ret);
1073 continue;
1074 }
1075
1076 printf("Update node %s, cooling-device prop\n", thermal_path[i]);
1077 }
1078}
1079
1080static void disable_pmu_cpu_nodes(void *blob, u32 disabled_cores)
1081{
1082 static const char * const pmu_path[] = {
1083 "/pmu"
1084 };
1085
1086 int nodeoff, cnt, i, ret, j;
1087 u32 irq_affinity[4];
1088
1089 for (i = 0; i < ARRAY_SIZE(pmu_path); i++) {
1090 nodeoff = fdt_path_offset(blob, pmu_path[i]);
1091 if (nodeoff < 0)
1092 continue; /* Not found, skip it */
1093
1094 cnt = fdtdec_get_int_array_count(blob, nodeoff, "interrupt-affinity",
1095 irq_affinity, 4);
1096 if (cnt < 0)
1097 continue;
1098
1099 if (cnt != 4)
1100 printf("Warning: %s, interrupt-affinity count %d\n", pmu_path[i], cnt);
1101
1102 for (j = 0; j < cnt; j++)
1103 irq_affinity[j] = cpu_to_fdt32(irq_affinity[j]);
1104
1105 ret = fdt_setprop(blob, nodeoff, "interrupt-affinity", &irq_affinity,
1106 sizeof(u32) * (4 - disabled_cores));
1107 if (ret < 0) {
1108 printf("Warning: %s, interrupt-affinity setprop failed %d\n",
1109 pmu_path[i], ret);
1110 continue;
1111 }
1112
1113 printf("Update node %s, interrupt-affinity prop\n", pmu_path[i]);
1114 }
1115}
1116
Peng Fan435dc122020-07-09 14:06:49 +08001117static int disable_cpu_nodes(void *blob, u32 disabled_cores)
1118{
1119 static const char * const nodes_path[] = {
1120 "/cpus/cpu@1",
1121 "/cpus/cpu@2",
1122 "/cpus/cpu@3",
1123 };
1124 u32 i = 0;
1125 int rc;
1126 int nodeoff;
1127
1128 if (disabled_cores > 3)
1129 return -EINVAL;
1130
1131 i = 3 - disabled_cores;
1132
1133 for (; i < 3; i++) {
1134 nodeoff = fdt_path_offset(blob, nodes_path[i]);
1135 if (nodeoff < 0)
1136 continue; /* Not found, skip it */
1137
1138 debug("Found %s node\n", nodes_path[i]);
1139
1140 rc = fdt_del_node(blob, nodeoff);
1141 if (rc < 0) {
1142 printf("Unable to delete node %s, err=%s\n",
1143 nodes_path[i], fdt_strerror(rc));
1144 } else {
1145 printf("Delete node %s\n", nodes_path[i]);
1146 }
1147 }
1148
Ye Li26517af2021-03-19 15:57:12 +08001149 disable_thermal_cpu_nodes(blob, disabled_cores);
1150 disable_pmu_cpu_nodes(blob, disabled_cores);
1151
Peng Fan435dc122020-07-09 14:06:49 +08001152 return 0;
1153}
1154
Peng Fana08bc872022-04-07 15:55:54 +08001155#if defined(CONFIG_IMX8MM)
1156static int cleanup_nodes_for_efi(void *blob)
1157{
1158 static const char * const usbotg_path[] = {
1159 "/soc@0/bus@32c00000/usb@32e40000",
1160 "/soc@0/bus@32c00000/usb@32e50000"
1161 };
1162 int nodeoff, i, rc;
1163
1164 for (i = 0; i < ARRAY_SIZE(usbotg_path); i++) {
1165 nodeoff = fdt_path_offset(blob, usbotg_path[i]);
1166 if (nodeoff < 0)
1167 continue; /* Not found, skip it */
1168 debug("Found %s node\n", usbotg_path[i]);
1169
1170 rc = fdt_delprop(blob, nodeoff, "extcon");
1171 if (rc == -FDT_ERR_NOTFOUND)
1172 continue;
1173 if (rc) {
1174 printf("Unable to update property %s:%s, err=%s\n",
1175 usbotg_path[i], "extcon", fdt_strerror(rc));
1176 return rc;
1177 }
1178
1179 printf("Remove %s:%s\n", usbotg_path[i], "extcon");
1180 }
1181
1182 return 0;
1183}
1184#endif
1185
Masahiro Yamadaf7ed78b2020-06-26 15:13:33 +09001186int ft_system_setup(void *blob, struct bd_info *bd)
Peng Faneae4de22018-01-10 13:20:37 +08001187{
Peng Fan435dc122020-07-09 14:06:49 +08001188#ifdef CONFIG_IMX8MQ
Peng Faneae4de22018-01-10 13:20:37 +08001189 int i = 0;
1190 int rc;
1191 int nodeoff;
1192
Peng Fan435dc122020-07-09 14:06:49 +08001193 if (get_boot_device() == USB_BOOT) {
1194 disable_dcss_nodes(blob);
1195
1196 bool new_path = check_fdt_new_path(blob);
1197 int v = new_path ? 1 : 0;
1198 static const char * const usb_dwc3_path[] = {
1199 "/usb@38100000/dwc3",
1200 "/soc@0/usb@38100000"
1201 };
1202
1203 nodeoff = fdt_path_offset(blob, usb_dwc3_path[v]);
1204 if (nodeoff >= 0) {
1205 const char *speed = "high-speed";
1206
1207 printf("Found %s node\n", usb_dwc3_path[v]);
1208
1209usb_modify_speed:
1210
1211 rc = fdt_setprop(blob, nodeoff, "maximum-speed", speed, strlen(speed) + 1);
1212 if (rc) {
1213 if (rc == -FDT_ERR_NOSPACE) {
1214 rc = fdt_increase_size(blob, 512);
1215 if (!rc)
1216 goto usb_modify_speed;
1217 }
1218 printf("Unable to set property %s:%s, err=%s\n",
1219 usb_dwc3_path[v], "maximum-speed", fdt_strerror(rc));
1220 } else {
1221 printf("Modify %s:%s = %s\n",
1222 usb_dwc3_path[v], "maximum-speed", speed);
1223 }
1224 } else {
1225 printf("Can't found %s node\n", usb_dwc3_path[v]);
1226 }
1227 }
1228
Peng Faneae4de22018-01-10 13:20:37 +08001229 /* Disable the CPU idle for A0 chip since the HW does not support it */
1230 if (is_soc_rev(CHIP_REV_1_0)) {
1231 static const char * const nodes_path[] = {
1232 "/cpus/cpu@0",
1233 "/cpus/cpu@1",
1234 "/cpus/cpu@2",
1235 "/cpus/cpu@3",
1236 };
1237
1238 for (i = 0; i < ARRAY_SIZE(nodes_path); i++) {
1239 nodeoff = fdt_path_offset(blob, nodes_path[i]);
1240 if (nodeoff < 0)
1241 continue; /* Not found, skip it */
1242
Marek Vasute2e7a772020-04-24 21:37:33 +02001243 debug("Found %s node\n", nodes_path[i]);
Peng Faneae4de22018-01-10 13:20:37 +08001244
1245 rc = fdt_delprop(blob, nodeoff, "cpu-idle-states");
Marek Vasute2e7a772020-04-24 21:37:33 +02001246 if (rc == -FDT_ERR_NOTFOUND)
1247 continue;
Peng Faneae4de22018-01-10 13:20:37 +08001248 if (rc) {
1249 printf("Unable to update property %s:%s, err=%s\n",
1250 nodes_path[i], "status", fdt_strerror(rc));
1251 return rc;
1252 }
1253
Marek Vasute2e7a772020-04-24 21:37:33 +02001254 debug("Remove %s:%s\n", nodes_path[i],
Peng Faneae4de22018-01-10 13:20:37 +08001255 "cpu-idle-states");
1256 }
1257 }
1258
Peng Fan435dc122020-07-09 14:06:49 +08001259 if (is_imx8mql()) {
1260 disable_vpu_nodes(blob);
1261 if (check_dcss_fused()) {
1262 printf("DCSS is fused\n");
1263 disable_dcss_nodes(blob);
1264 check_mipi_dsi_nodes(blob);
1265 }
1266 }
1267
1268 if (is_imx8md())
1269 disable_cpu_nodes(blob, 2);
1270
1271#elif defined(CONFIG_IMX8MM)
1272 if (is_imx8mml() || is_imx8mmdl() || is_imx8mmsl())
1273 disable_vpu_nodes(blob);
1274
1275 if (is_imx8mmd() || is_imx8mmdl())
1276 disable_cpu_nodes(blob, 2);
1277 else if (is_imx8mms() || is_imx8mmsl())
1278 disable_cpu_nodes(blob, 3);
1279
Peng Fana08bc872022-04-07 15:55:54 +08001280 cleanup_nodes_for_efi(blob);
1281
Peng Fan435dc122020-07-09 14:06:49 +08001282#elif defined(CONFIG_IMX8MN)
1283 if (is_imx8mnl() || is_imx8mndl() || is_imx8mnsl())
1284 disable_gpu_nodes(blob);
Ye Liee337ce2021-03-19 15:57:09 +08001285#ifdef CONFIG_IMX8MN_LOW_DRIVE_MODE
1286 else {
1287 int ldm_gpu = low_drive_gpu_freq(blob);
1288
1289 if (ldm_gpu < 0)
1290 printf("Update GPU node assigned-clock-rates failed\n");
1291 else
1292 printf("Update GPU node assigned-clock-rates ok\n");
1293 }
1294#endif
Peng Fan435dc122020-07-09 14:06:49 +08001295
Ye Li715180e2021-03-19 15:57:11 +08001296 if (is_imx8mnd() || is_imx8mndl() || is_imx8mnud())
Peng Fan435dc122020-07-09 14:06:49 +08001297 disable_cpu_nodes(blob, 2);
Ye Li715180e2021-03-19 15:57:11 +08001298 else if (is_imx8mns() || is_imx8mnsl() || is_imx8mnus())
Peng Fan435dc122020-07-09 14:06:49 +08001299 disable_cpu_nodes(blob, 3);
1300
1301#elif defined(CONFIG_IMX8MP)
Peng Fanf5f9b8e2022-04-07 15:55:53 +08001302 if (is_imx8mpul()) {
1303 /* Disable GPU */
1304 disable_gpu_nodes(blob);
1305
1306 /* Disable DSI */
1307 disable_dsi_lcdif_nodes(blob);
1308
1309 /* Disable LVDS */
1310 disable_lvds_lcdif_nodes(blob);
1311 }
1312
1313 if (is_imx8mpul() || is_imx8mpl())
Peng Fan435dc122020-07-09 14:06:49 +08001314 disable_vpu_nodes(blob);
1315
Peng Fanf5f9b8e2022-04-07 15:55:53 +08001316 if (is_imx8mpul() || is_imx8mpl() || is_imx8mp6())
Peng Fan435dc122020-07-09 14:06:49 +08001317 disable_npu_nodes(blob);
1318
Peng Fanf5f9b8e2022-04-07 15:55:53 +08001319 if (is_imx8mpul() || is_imx8mpl())
Peng Fan435dc122020-07-09 14:06:49 +08001320 disable_isp_nodes(blob);
1321
Peng Fanf5f9b8e2022-04-07 15:55:53 +08001322 if (is_imx8mpul() || is_imx8mpl() || is_imx8mp6())
Peng Fan435dc122020-07-09 14:06:49 +08001323 disable_dsp_nodes(blob);
1324
1325 if (is_imx8mpd())
1326 disable_cpu_nodes(blob, 2);
1327#endif
1328
Peng Faneae4de22018-01-10 13:20:37 +08001329 return 0;
1330}
1331#endif
1332
Peng Fanf5f9b8e2022-04-07 15:55:53 +08001333#ifdef CONFIG_OF_BOARD_FIXUP
1334#ifndef CONFIG_SPL_BUILD
1335int board_fix_fdt(void *fdt)
1336{
1337 if (is_imx8mpul()) {
1338 int i = 0;
1339 int nodeoff, ret;
1340 const char *status = "disabled";
1341 static const char * const dsi_nodes[] = {
1342 "/soc@0/bus@32c00000/mipi_dsi@32e60000",
1343 "/soc@0/bus@32c00000/lcd-controller@32e80000",
1344 "/dsi-host"
1345 };
1346
1347 for (i = 0; i < ARRAY_SIZE(dsi_nodes); i++) {
1348 nodeoff = fdt_path_offset(fdt, dsi_nodes[i]);
1349 if (nodeoff > 0) {
1350set_status:
1351 ret = fdt_setprop(fdt, nodeoff, "status", status,
1352 strlen(status) + 1);
1353 if (ret == -FDT_ERR_NOSPACE) {
1354 ret = fdt_increase_size(fdt, 512);
1355 if (!ret)
1356 goto set_status;
1357 }
1358 }
1359 }
1360 }
1361
1362 return 0;
1363}
1364#endif
1365#endif
1366
Marek Vasut64dc4de2020-04-29 15:04:21 +02001367#if !CONFIG_IS_ENABLED(SYSRESET)
Harald Seiler6f14d5f2020-12-15 16:47:52 +01001368void reset_cpu(void)
Peng Faneae4de22018-01-10 13:20:37 +08001369{
Claudius Heinee73f3942020-04-29 15:04:23 +02001370 struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR;
Peng Faneae4de22018-01-10 13:20:37 +08001371
Ye Li54a915a2019-12-09 00:47:18 -08001372 /* Clear WDA to trigger WDOG_B immediately */
1373 writew((SET_WCR_WT(1) | WCR_WDT | WCR_WDE | WCR_SRS), &wdog->wcr);
Peng Fan24290d92019-08-27 06:25:41 +00001374
Ye Li54a915a2019-12-09 00:47:18 -08001375 while (1) {
1376 /*
Harald Seilerec0c4472020-04-29 15:04:22 +02001377 * spin for .5 seconds before reset
Ye Li54a915a2019-12-09 00:47:18 -08001378 */
1379 }
Peng Faneae4de22018-01-10 13:20:37 +08001380}
Peng Fan24290d92019-08-27 06:25:41 +00001381#endif
Peng Fan5760d8d2020-04-22 10:51:13 +08001382
1383#if defined(CONFIG_ARCH_MISC_INIT)
1384static void acquire_buildinfo(void)
1385{
1386 u64 atf_commit = 0;
Peng Fan45d843a2020-05-11 15:14:04 +08001387 struct arm_smccc_res res;
Peng Fan5760d8d2020-04-22 10:51:13 +08001388
1389 /* Get ARM Trusted Firmware commit id */
Peng Fan45d843a2020-05-11 15:14:04 +08001390 arm_smccc_smc(IMX_SIP_BUILDINFO, IMX_SIP_BUILDINFO_GET_COMMITHASH,
Fabio Estevam31e410f2020-07-17 16:36:54 -03001391 0, 0, 0, 0, 0, 0, &res);
Peng Fan45d843a2020-05-11 15:14:04 +08001392 atf_commit = res.a0;
Peng Fan5760d8d2020-04-22 10:51:13 +08001393 if (atf_commit == 0xffffffff) {
1394 debug("ATF does not support build info\n");
1395 atf_commit = 0x30; /* Display 0, 0 ascii is 0x30 */
1396 }
1397
1398 printf("\n BuildInfo:\n - ATF %s\n\n", (char *)&atf_commit);
1399}
1400
1401int arch_misc_init(void)
1402{
Gaurav Jain81113a02022-03-24 11:50:27 +05301403 if (IS_ENABLED(CONFIG_FSL_CAAM)) {
1404 struct udevice *dev;
1405 int ret;
1406
1407 ret = uclass_get_device_by_driver(UCLASS_MISC, DM_DRIVER_GET(caam_jr), &dev);
1408 if (ret)
1409 printf("Failed to initialize %s: %d\n", dev->name, ret);
1410 }
Peng Fan5760d8d2020-04-22 10:51:13 +08001411 acquire_buildinfo();
1412
1413 return 0;
1414}
1415#endif
Ye Li325cd012020-05-03 22:19:52 +08001416
1417void imx_tmu_arch_init(void *reg_base)
1418{
Ye Lia00f2f02020-05-03 22:19:53 +08001419 if (is_imx8mm() || is_imx8mn()) {
Ye Li325cd012020-05-03 22:19:52 +08001420 /* Load TCALIV and TASR from fuses */
1421 struct ocotp_regs *ocotp =
1422 (struct ocotp_regs *)OCOTP_BASE_ADDR;
1423 struct fuse_bank *bank = &ocotp->bank[3];
1424 struct fuse_bank3_regs *fuse =
1425 (struct fuse_bank3_regs *)bank->fuse_regs;
1426
1427 u32 tca_rt, tca_hr, tca_en;
1428 u32 buf_vref, buf_slope;
1429
1430 tca_rt = fuse->ana0 & 0xFF;
1431 tca_hr = (fuse->ana0 & 0xFF00) >> 8;
1432 tca_en = (fuse->ana0 & 0x2000000) >> 25;
1433
1434 buf_vref = (fuse->ana0 & 0x1F00000) >> 20;
1435 buf_slope = (fuse->ana0 & 0xF0000) >> 16;
1436
1437 writel(buf_vref | (buf_slope << 16), (ulong)reg_base + 0x28);
1438 writel((tca_en << 31) | (tca_hr << 16) | tca_rt,
1439 (ulong)reg_base + 0x30);
1440 }
Ye Li41a20252020-05-03 22:19:54 +08001441#ifdef CONFIG_IMX8MP
1442 /* Load TCALIV0/1/m40 and TRIM from fuses */
1443 struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR;
1444 struct fuse_bank *bank = &ocotp->bank[38];
1445 struct fuse_bank38_regs *fuse =
1446 (struct fuse_bank38_regs *)bank->fuse_regs;
1447 struct fuse_bank *bank2 = &ocotp->bank[39];
1448 struct fuse_bank39_regs *fuse2 =
1449 (struct fuse_bank39_regs *)bank2->fuse_regs;
1450 u32 buf_vref, buf_slope, bjt_cur, vlsb, bgr;
1451 u32 reg;
1452 u32 tca40[2], tca25[2], tca105[2];
1453
1454 /* For blank sample */
1455 if (!fuse->ana_trim2 && !fuse->ana_trim3 &&
1456 !fuse->ana_trim4 && !fuse2->ana_trim5) {
1457 /* Use a default 25C binary codes */
1458 tca25[0] = 1596;
Ye Lid756ca02020-05-03 22:19:55 +08001459 tca25[1] = 1596;
Ye Li41a20252020-05-03 22:19:54 +08001460 writel(tca25[0], (ulong)reg_base + 0x30);
Ye Lid756ca02020-05-03 22:19:55 +08001461 writel(tca25[1], (ulong)reg_base + 0x34);
Ye Li41a20252020-05-03 22:19:54 +08001462 return;
1463 }
1464
1465 buf_vref = (fuse->ana_trim2 & 0xc0) >> 6;
1466 buf_slope = (fuse->ana_trim2 & 0xF00) >> 8;
1467 bjt_cur = (fuse->ana_trim2 & 0xF000) >> 12;
1468 bgr = (fuse->ana_trim2 & 0xF0000) >> 16;
1469 vlsb = (fuse->ana_trim2 & 0xF00000) >> 20;
1470 writel(buf_vref | (buf_slope << 16), (ulong)reg_base + 0x28);
1471
1472 reg = (bgr << 28) | (bjt_cur << 20) | (vlsb << 12) | (1 << 7);
1473 writel(reg, (ulong)reg_base + 0x3c);
1474
1475 tca40[0] = (fuse->ana_trim3 & 0xFFF0000) >> 16;
1476 tca25[0] = (fuse->ana_trim3 & 0xF0000000) >> 28;
1477 tca25[0] |= ((fuse->ana_trim4 & 0xFF) << 4);
1478 tca105[0] = (fuse->ana_trim4 & 0xFFF00) >> 8;
1479 tca40[1] = (fuse->ana_trim4 & 0xFFF00000) >> 20;
1480 tca25[1] = fuse2->ana_trim5 & 0xFFF;
1481 tca105[1] = (fuse2->ana_trim5 & 0xFFF000) >> 12;
1482
1483 /* use 25c for 1p calibration */
1484 writel(tca25[0] | (tca105[0] << 16), (ulong)reg_base + 0x30);
1485 writel(tca25[1] | (tca105[1] << 16), (ulong)reg_base + 0x34);
1486 writel(tca40[0] | (tca40[1] << 16), (ulong)reg_base + 0x38);
1487#endif
Ye Li325cd012020-05-03 22:19:52 +08001488}
Peng Fana35215d2020-07-09 13:39:26 +08001489
1490#if defined(CONFIG_SPL_BUILD)
1491#if defined(CONFIG_IMX8MQ) || defined(CONFIG_IMX8MM) || defined(CONFIG_IMX8MN)
1492bool serror_need_skip = true;
1493
Sean Anderson2d755492022-03-22 17:17:35 -04001494void do_error(struct pt_regs *pt_regs)
Peng Fana35215d2020-07-09 13:39:26 +08001495{
1496 /*
1497 * If stack is still in ROM reserved OCRAM not switch to SPL,
1498 * it is the ROM SError
1499 */
1500 ulong sp;
1501
1502 asm volatile("mov %0, sp" : "=r"(sp) : );
1503
1504 if (serror_need_skip && sp < 0x910000 && sp >= 0x900000) {
1505 /* Check for ERR050342, imx8mq HDCP enabled parts */
1506 if (is_imx8mq() && !(readl(OCOTP_BASE_ADDR + 0x450) & 0x08000000)) {
1507 serror_need_skip = false;
1508 return; /* Do nothing skip the SError in ROM */
1509 }
1510
1511 /* Check for ERR050350, field return mode for imx8mq, mm and mn */
1512 if (readl(OCOTP_BASE_ADDR + 0x630) & 0x1) {
1513 serror_need_skip = false;
1514 return; /* Do nothing skip the SError in ROM */
1515 }
1516 }
1517
1518 efi_restore_gd();
Sean Anderson2d755492022-03-22 17:17:35 -04001519 printf("\"Error\" handler, esr 0x%08lx\n", pt_regs->esr);
Peng Fana35215d2020-07-09 13:39:26 +08001520 show_regs(pt_regs);
1521 panic("Resetting CPU ...\n");
1522}
1523#endif
1524#endif
Ye Li0513f362019-07-15 01:16:46 -07001525
1526#if defined(CONFIG_IMX8MN) || defined(CONFIG_IMX8MP)
1527enum env_location env_get_location(enum env_operation op, int prio)
1528{
1529 enum boot_device dev = get_boot_device();
Ye Li0513f362019-07-15 01:16:46 -07001530
1531 if (prio)
Ricardo Salveti1daf63f2021-10-20 16:16:26 -03001532 return ENVL_UNKNOWN;
Ye Li0513f362019-07-15 01:16:46 -07001533
1534 switch (dev) {
Ye Li0513f362019-07-15 01:16:46 -07001535 case QSPI_BOOT:
Marek Vasut31b3bc42022-03-25 18:59:28 +01001536 case SPI_NOR_BOOT:
Ricardo Salveti1daf63f2021-10-20 16:16:26 -03001537 if (IS_ENABLED(CONFIG_ENV_IS_IN_SPI_FLASH))
1538 return ENVL_SPI_FLASH;
1539 return ENVL_NOWHERE;
Ye Li0513f362019-07-15 01:16:46 -07001540 case NAND_BOOT:
Ricardo Salveti1daf63f2021-10-20 16:16:26 -03001541 if (IS_ENABLED(CONFIG_ENV_IS_IN_NAND))
1542 return ENVL_NAND;
1543 return ENVL_NOWHERE;
Ye Li0513f362019-07-15 01:16:46 -07001544 case SD1_BOOT:
1545 case SD2_BOOT:
1546 case SD3_BOOT:
1547 case MMC1_BOOT:
1548 case MMC2_BOOT:
1549 case MMC3_BOOT:
Ricardo Salveti1daf63f2021-10-20 16:16:26 -03001550 if (IS_ENABLED(CONFIG_ENV_IS_IN_MMC))
1551 return ENVL_MMC;
1552 else if (IS_ENABLED(CONFIG_ENV_IS_IN_EXT4))
1553 return ENVL_EXT4;
1554 else if (IS_ENABLED(CONFIG_ENV_IS_IN_FAT))
1555 return ENVL_FAT;
1556 return ENVL_NOWHERE;
Ye Li0513f362019-07-15 01:16:46 -07001557 default:
Ricardo Salveti1daf63f2021-10-20 16:16:26 -03001558 return ENVL_NOWHERE;
Ye Li0513f362019-07-15 01:16:46 -07001559 }
Ye Li0513f362019-07-15 01:16:46 -07001560}
1561
Ye Li0513f362019-07-15 01:16:46 -07001562#endif