blob: 560bfb22a0d81dd37e4af539443133c1f4044c53 [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 Fan435dc122020-07-09 14:06:49 +0800914int disable_gpu_nodes(void *blob)
915{
916 static const char * const nodes_path_8mn[] = {
Peng Fan7d4195c2021-03-19 15:57:13 +0800917 "/gpu@38000000",
918 "/soc@/gpu@38000000"
Peng Fan435dc122020-07-09 14:06:49 +0800919 };
920
921 return disable_fdt_nodes(blob, nodes_path_8mn, ARRAY_SIZE(nodes_path_8mn));
922}
923
924int disable_npu_nodes(void *blob)
925{
926 static const char * const nodes_path_8mp[] = {
927 "/vipsi@38500000"
928 };
929
930 return disable_fdt_nodes(blob, nodes_path_8mp, ARRAY_SIZE(nodes_path_8mp));
931}
932
933int disable_isp_nodes(void *blob)
934{
935 static const char * const nodes_path_8mp[] = {
936 "/soc@0/bus@32c00000/camera/isp@32e10000",
937 "/soc@0/bus@32c00000/camera/isp@32e20000"
938 };
939
940 return disable_fdt_nodes(blob, nodes_path_8mp, ARRAY_SIZE(nodes_path_8mp));
941}
942
943int disable_dsp_nodes(void *blob)
944{
945 static const char * const nodes_path_8mp[] = {
946 "/dsp@3b6e8000"
947 };
948
949 return disable_fdt_nodes(blob, nodes_path_8mp, ARRAY_SIZE(nodes_path_8mp));
950}
951
Ye Li26517af2021-03-19 15:57:12 +0800952static void disable_thermal_cpu_nodes(void *blob, u32 disabled_cores)
953{
954 static const char * const thermal_path[] = {
955 "/thermal-zones/cpu-thermal/cooling-maps/map0"
956 };
957
958 int nodeoff, cnt, i, ret, j;
959 u32 cooling_dev[12];
960
961 for (i = 0; i < ARRAY_SIZE(thermal_path); i++) {
962 nodeoff = fdt_path_offset(blob, thermal_path[i]);
963 if (nodeoff < 0)
964 continue; /* Not found, skip it */
965
966 cnt = fdtdec_get_int_array_count(blob, nodeoff, "cooling-device", cooling_dev, 12);
967 if (cnt < 0)
968 continue;
969
970 if (cnt != 12)
971 printf("Warning: %s, cooling-device count %d\n", thermal_path[i], cnt);
972
973 for (j = 0; j < cnt; j++)
974 cooling_dev[j] = cpu_to_fdt32(cooling_dev[j]);
975
976 ret = fdt_setprop(blob, nodeoff, "cooling-device", &cooling_dev,
977 sizeof(u32) * (12 - disabled_cores * 3));
978 if (ret < 0) {
979 printf("Warning: %s, cooling-device setprop failed %d\n",
980 thermal_path[i], ret);
981 continue;
982 }
983
984 printf("Update node %s, cooling-device prop\n", thermal_path[i]);
985 }
986}
987
988static void disable_pmu_cpu_nodes(void *blob, u32 disabled_cores)
989{
990 static const char * const pmu_path[] = {
991 "/pmu"
992 };
993
994 int nodeoff, cnt, i, ret, j;
995 u32 irq_affinity[4];
996
997 for (i = 0; i < ARRAY_SIZE(pmu_path); i++) {
998 nodeoff = fdt_path_offset(blob, pmu_path[i]);
999 if (nodeoff < 0)
1000 continue; /* Not found, skip it */
1001
1002 cnt = fdtdec_get_int_array_count(blob, nodeoff, "interrupt-affinity",
1003 irq_affinity, 4);
1004 if (cnt < 0)
1005 continue;
1006
1007 if (cnt != 4)
1008 printf("Warning: %s, interrupt-affinity count %d\n", pmu_path[i], cnt);
1009
1010 for (j = 0; j < cnt; j++)
1011 irq_affinity[j] = cpu_to_fdt32(irq_affinity[j]);
1012
1013 ret = fdt_setprop(blob, nodeoff, "interrupt-affinity", &irq_affinity,
1014 sizeof(u32) * (4 - disabled_cores));
1015 if (ret < 0) {
1016 printf("Warning: %s, interrupt-affinity setprop failed %d\n",
1017 pmu_path[i], ret);
1018 continue;
1019 }
1020
1021 printf("Update node %s, interrupt-affinity prop\n", pmu_path[i]);
1022 }
1023}
1024
Peng Fan435dc122020-07-09 14:06:49 +08001025static int disable_cpu_nodes(void *blob, u32 disabled_cores)
1026{
1027 static const char * const nodes_path[] = {
1028 "/cpus/cpu@1",
1029 "/cpus/cpu@2",
1030 "/cpus/cpu@3",
1031 };
1032 u32 i = 0;
1033 int rc;
1034 int nodeoff;
1035
1036 if (disabled_cores > 3)
1037 return -EINVAL;
1038
1039 i = 3 - disabled_cores;
1040
1041 for (; i < 3; i++) {
1042 nodeoff = fdt_path_offset(blob, nodes_path[i]);
1043 if (nodeoff < 0)
1044 continue; /* Not found, skip it */
1045
1046 debug("Found %s node\n", nodes_path[i]);
1047
1048 rc = fdt_del_node(blob, nodeoff);
1049 if (rc < 0) {
1050 printf("Unable to delete node %s, err=%s\n",
1051 nodes_path[i], fdt_strerror(rc));
1052 } else {
1053 printf("Delete node %s\n", nodes_path[i]);
1054 }
1055 }
1056
Ye Li26517af2021-03-19 15:57:12 +08001057 disable_thermal_cpu_nodes(blob, disabled_cores);
1058 disable_pmu_cpu_nodes(blob, disabled_cores);
1059
Peng Fan435dc122020-07-09 14:06:49 +08001060 return 0;
1061}
1062
Masahiro Yamadaf7ed78b2020-06-26 15:13:33 +09001063int ft_system_setup(void *blob, struct bd_info *bd)
Peng Faneae4de22018-01-10 13:20:37 +08001064{
Peng Fan435dc122020-07-09 14:06:49 +08001065#ifdef CONFIG_IMX8MQ
Peng Faneae4de22018-01-10 13:20:37 +08001066 int i = 0;
1067 int rc;
1068 int nodeoff;
1069
Peng Fan435dc122020-07-09 14:06:49 +08001070 if (get_boot_device() == USB_BOOT) {
1071 disable_dcss_nodes(blob);
1072
1073 bool new_path = check_fdt_new_path(blob);
1074 int v = new_path ? 1 : 0;
1075 static const char * const usb_dwc3_path[] = {
1076 "/usb@38100000/dwc3",
1077 "/soc@0/usb@38100000"
1078 };
1079
1080 nodeoff = fdt_path_offset(blob, usb_dwc3_path[v]);
1081 if (nodeoff >= 0) {
1082 const char *speed = "high-speed";
1083
1084 printf("Found %s node\n", usb_dwc3_path[v]);
1085
1086usb_modify_speed:
1087
1088 rc = fdt_setprop(blob, nodeoff, "maximum-speed", speed, strlen(speed) + 1);
1089 if (rc) {
1090 if (rc == -FDT_ERR_NOSPACE) {
1091 rc = fdt_increase_size(blob, 512);
1092 if (!rc)
1093 goto usb_modify_speed;
1094 }
1095 printf("Unable to set property %s:%s, err=%s\n",
1096 usb_dwc3_path[v], "maximum-speed", fdt_strerror(rc));
1097 } else {
1098 printf("Modify %s:%s = %s\n",
1099 usb_dwc3_path[v], "maximum-speed", speed);
1100 }
1101 } else {
1102 printf("Can't found %s node\n", usb_dwc3_path[v]);
1103 }
1104 }
1105
Peng Faneae4de22018-01-10 13:20:37 +08001106 /* Disable the CPU idle for A0 chip since the HW does not support it */
1107 if (is_soc_rev(CHIP_REV_1_0)) {
1108 static const char * const nodes_path[] = {
1109 "/cpus/cpu@0",
1110 "/cpus/cpu@1",
1111 "/cpus/cpu@2",
1112 "/cpus/cpu@3",
1113 };
1114
1115 for (i = 0; i < ARRAY_SIZE(nodes_path); i++) {
1116 nodeoff = fdt_path_offset(blob, nodes_path[i]);
1117 if (nodeoff < 0)
1118 continue; /* Not found, skip it */
1119
Marek Vasute2e7a772020-04-24 21:37:33 +02001120 debug("Found %s node\n", nodes_path[i]);
Peng Faneae4de22018-01-10 13:20:37 +08001121
1122 rc = fdt_delprop(blob, nodeoff, "cpu-idle-states");
Marek Vasute2e7a772020-04-24 21:37:33 +02001123 if (rc == -FDT_ERR_NOTFOUND)
1124 continue;
Peng Faneae4de22018-01-10 13:20:37 +08001125 if (rc) {
1126 printf("Unable to update property %s:%s, err=%s\n",
1127 nodes_path[i], "status", fdt_strerror(rc));
1128 return rc;
1129 }
1130
Marek Vasute2e7a772020-04-24 21:37:33 +02001131 debug("Remove %s:%s\n", nodes_path[i],
Peng Faneae4de22018-01-10 13:20:37 +08001132 "cpu-idle-states");
1133 }
1134 }
1135
Peng Fan435dc122020-07-09 14:06:49 +08001136 if (is_imx8mql()) {
1137 disable_vpu_nodes(blob);
1138 if (check_dcss_fused()) {
1139 printf("DCSS is fused\n");
1140 disable_dcss_nodes(blob);
1141 check_mipi_dsi_nodes(blob);
1142 }
1143 }
1144
1145 if (is_imx8md())
1146 disable_cpu_nodes(blob, 2);
1147
1148#elif defined(CONFIG_IMX8MM)
1149 if (is_imx8mml() || is_imx8mmdl() || is_imx8mmsl())
1150 disable_vpu_nodes(blob);
1151
1152 if (is_imx8mmd() || is_imx8mmdl())
1153 disable_cpu_nodes(blob, 2);
1154 else if (is_imx8mms() || is_imx8mmsl())
1155 disable_cpu_nodes(blob, 3);
1156
1157#elif defined(CONFIG_IMX8MN)
1158 if (is_imx8mnl() || is_imx8mndl() || is_imx8mnsl())
1159 disable_gpu_nodes(blob);
Ye Liee337ce2021-03-19 15:57:09 +08001160#ifdef CONFIG_IMX8MN_LOW_DRIVE_MODE
1161 else {
1162 int ldm_gpu = low_drive_gpu_freq(blob);
1163
1164 if (ldm_gpu < 0)
1165 printf("Update GPU node assigned-clock-rates failed\n");
1166 else
1167 printf("Update GPU node assigned-clock-rates ok\n");
1168 }
1169#endif
Peng Fan435dc122020-07-09 14:06:49 +08001170
Ye Li715180e2021-03-19 15:57:11 +08001171 if (is_imx8mnd() || is_imx8mndl() || is_imx8mnud())
Peng Fan435dc122020-07-09 14:06:49 +08001172 disable_cpu_nodes(blob, 2);
Ye Li715180e2021-03-19 15:57:11 +08001173 else if (is_imx8mns() || is_imx8mnsl() || is_imx8mnus())
Peng Fan435dc122020-07-09 14:06:49 +08001174 disable_cpu_nodes(blob, 3);
1175
1176#elif defined(CONFIG_IMX8MP)
Peng Fan8a472a22020-09-16 15:17:22 +08001177 if (is_imx8mpl())
Peng Fan435dc122020-07-09 14:06:49 +08001178 disable_vpu_nodes(blob);
1179
Peng Fan8a472a22020-09-16 15:17:22 +08001180 if (is_imx8mpl() || is_imx8mp6())
Peng Fan435dc122020-07-09 14:06:49 +08001181 disable_npu_nodes(blob);
1182
Peng Fan8a472a22020-09-16 15:17:22 +08001183 if (is_imx8mpl())
Peng Fan435dc122020-07-09 14:06:49 +08001184 disable_isp_nodes(blob);
1185
Peng Fan8a472a22020-09-16 15:17:22 +08001186 if (is_imx8mpl() || is_imx8mp6())
Peng Fan435dc122020-07-09 14:06:49 +08001187 disable_dsp_nodes(blob);
1188
1189 if (is_imx8mpd())
1190 disable_cpu_nodes(blob, 2);
1191#endif
1192
Peng Faneae4de22018-01-10 13:20:37 +08001193 return 0;
1194}
1195#endif
1196
Marek Vasut64dc4de2020-04-29 15:04:21 +02001197#if !CONFIG_IS_ENABLED(SYSRESET)
Harald Seiler6f14d5f2020-12-15 16:47:52 +01001198void reset_cpu(void)
Peng Faneae4de22018-01-10 13:20:37 +08001199{
Claudius Heinee73f3942020-04-29 15:04:23 +02001200 struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR;
Peng Faneae4de22018-01-10 13:20:37 +08001201
Ye Li54a915a2019-12-09 00:47:18 -08001202 /* Clear WDA to trigger WDOG_B immediately */
1203 writew((SET_WCR_WT(1) | WCR_WDT | WCR_WDE | WCR_SRS), &wdog->wcr);
Peng Fan24290d92019-08-27 06:25:41 +00001204
Ye Li54a915a2019-12-09 00:47:18 -08001205 while (1) {
1206 /*
Harald Seilerec0c4472020-04-29 15:04:22 +02001207 * spin for .5 seconds before reset
Ye Li54a915a2019-12-09 00:47:18 -08001208 */
1209 }
Peng Faneae4de22018-01-10 13:20:37 +08001210}
Peng Fan24290d92019-08-27 06:25:41 +00001211#endif
Peng Fan5760d8d2020-04-22 10:51:13 +08001212
1213#if defined(CONFIG_ARCH_MISC_INIT)
1214static void acquire_buildinfo(void)
1215{
1216 u64 atf_commit = 0;
Peng Fan45d843a2020-05-11 15:14:04 +08001217 struct arm_smccc_res res;
Peng Fan5760d8d2020-04-22 10:51:13 +08001218
1219 /* Get ARM Trusted Firmware commit id */
Peng Fan45d843a2020-05-11 15:14:04 +08001220 arm_smccc_smc(IMX_SIP_BUILDINFO, IMX_SIP_BUILDINFO_GET_COMMITHASH,
Fabio Estevam31e410f2020-07-17 16:36:54 -03001221 0, 0, 0, 0, 0, 0, &res);
Peng Fan45d843a2020-05-11 15:14:04 +08001222 atf_commit = res.a0;
Peng Fan5760d8d2020-04-22 10:51:13 +08001223 if (atf_commit == 0xffffffff) {
1224 debug("ATF does not support build info\n");
1225 atf_commit = 0x30; /* Display 0, 0 ascii is 0x30 */
1226 }
1227
1228 printf("\n BuildInfo:\n - ATF %s\n\n", (char *)&atf_commit);
1229}
1230
1231int arch_misc_init(void)
1232{
Gaurav Jain81113a02022-03-24 11:50:27 +05301233 if (IS_ENABLED(CONFIG_FSL_CAAM)) {
1234 struct udevice *dev;
1235 int ret;
1236
1237 ret = uclass_get_device_by_driver(UCLASS_MISC, DM_DRIVER_GET(caam_jr), &dev);
1238 if (ret)
1239 printf("Failed to initialize %s: %d\n", dev->name, ret);
1240 }
Peng Fan5760d8d2020-04-22 10:51:13 +08001241 acquire_buildinfo();
1242
1243 return 0;
1244}
1245#endif
Ye Li325cd012020-05-03 22:19:52 +08001246
1247void imx_tmu_arch_init(void *reg_base)
1248{
Ye Lia00f2f02020-05-03 22:19:53 +08001249 if (is_imx8mm() || is_imx8mn()) {
Ye Li325cd012020-05-03 22:19:52 +08001250 /* Load TCALIV and TASR from fuses */
1251 struct ocotp_regs *ocotp =
1252 (struct ocotp_regs *)OCOTP_BASE_ADDR;
1253 struct fuse_bank *bank = &ocotp->bank[3];
1254 struct fuse_bank3_regs *fuse =
1255 (struct fuse_bank3_regs *)bank->fuse_regs;
1256
1257 u32 tca_rt, tca_hr, tca_en;
1258 u32 buf_vref, buf_slope;
1259
1260 tca_rt = fuse->ana0 & 0xFF;
1261 tca_hr = (fuse->ana0 & 0xFF00) >> 8;
1262 tca_en = (fuse->ana0 & 0x2000000) >> 25;
1263
1264 buf_vref = (fuse->ana0 & 0x1F00000) >> 20;
1265 buf_slope = (fuse->ana0 & 0xF0000) >> 16;
1266
1267 writel(buf_vref | (buf_slope << 16), (ulong)reg_base + 0x28);
1268 writel((tca_en << 31) | (tca_hr << 16) | tca_rt,
1269 (ulong)reg_base + 0x30);
1270 }
Ye Li41a20252020-05-03 22:19:54 +08001271#ifdef CONFIG_IMX8MP
1272 /* Load TCALIV0/1/m40 and TRIM from fuses */
1273 struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR;
1274 struct fuse_bank *bank = &ocotp->bank[38];
1275 struct fuse_bank38_regs *fuse =
1276 (struct fuse_bank38_regs *)bank->fuse_regs;
1277 struct fuse_bank *bank2 = &ocotp->bank[39];
1278 struct fuse_bank39_regs *fuse2 =
1279 (struct fuse_bank39_regs *)bank2->fuse_regs;
1280 u32 buf_vref, buf_slope, bjt_cur, vlsb, bgr;
1281 u32 reg;
1282 u32 tca40[2], tca25[2], tca105[2];
1283
1284 /* For blank sample */
1285 if (!fuse->ana_trim2 && !fuse->ana_trim3 &&
1286 !fuse->ana_trim4 && !fuse2->ana_trim5) {
1287 /* Use a default 25C binary codes */
1288 tca25[0] = 1596;
Ye Lid756ca02020-05-03 22:19:55 +08001289 tca25[1] = 1596;
Ye Li41a20252020-05-03 22:19:54 +08001290 writel(tca25[0], (ulong)reg_base + 0x30);
Ye Lid756ca02020-05-03 22:19:55 +08001291 writel(tca25[1], (ulong)reg_base + 0x34);
Ye Li41a20252020-05-03 22:19:54 +08001292 return;
1293 }
1294
1295 buf_vref = (fuse->ana_trim2 & 0xc0) >> 6;
1296 buf_slope = (fuse->ana_trim2 & 0xF00) >> 8;
1297 bjt_cur = (fuse->ana_trim2 & 0xF000) >> 12;
1298 bgr = (fuse->ana_trim2 & 0xF0000) >> 16;
1299 vlsb = (fuse->ana_trim2 & 0xF00000) >> 20;
1300 writel(buf_vref | (buf_slope << 16), (ulong)reg_base + 0x28);
1301
1302 reg = (bgr << 28) | (bjt_cur << 20) | (vlsb << 12) | (1 << 7);
1303 writel(reg, (ulong)reg_base + 0x3c);
1304
1305 tca40[0] = (fuse->ana_trim3 & 0xFFF0000) >> 16;
1306 tca25[0] = (fuse->ana_trim3 & 0xF0000000) >> 28;
1307 tca25[0] |= ((fuse->ana_trim4 & 0xFF) << 4);
1308 tca105[0] = (fuse->ana_trim4 & 0xFFF00) >> 8;
1309 tca40[1] = (fuse->ana_trim4 & 0xFFF00000) >> 20;
1310 tca25[1] = fuse2->ana_trim5 & 0xFFF;
1311 tca105[1] = (fuse2->ana_trim5 & 0xFFF000) >> 12;
1312
1313 /* use 25c for 1p calibration */
1314 writel(tca25[0] | (tca105[0] << 16), (ulong)reg_base + 0x30);
1315 writel(tca25[1] | (tca105[1] << 16), (ulong)reg_base + 0x34);
1316 writel(tca40[0] | (tca40[1] << 16), (ulong)reg_base + 0x38);
1317#endif
Ye Li325cd012020-05-03 22:19:52 +08001318}
Peng Fana35215d2020-07-09 13:39:26 +08001319
1320#if defined(CONFIG_SPL_BUILD)
1321#if defined(CONFIG_IMX8MQ) || defined(CONFIG_IMX8MM) || defined(CONFIG_IMX8MN)
1322bool serror_need_skip = true;
1323
Sean Anderson2d755492022-03-22 17:17:35 -04001324void do_error(struct pt_regs *pt_regs)
Peng Fana35215d2020-07-09 13:39:26 +08001325{
1326 /*
1327 * If stack is still in ROM reserved OCRAM not switch to SPL,
1328 * it is the ROM SError
1329 */
1330 ulong sp;
1331
1332 asm volatile("mov %0, sp" : "=r"(sp) : );
1333
1334 if (serror_need_skip && sp < 0x910000 && sp >= 0x900000) {
1335 /* Check for ERR050342, imx8mq HDCP enabled parts */
1336 if (is_imx8mq() && !(readl(OCOTP_BASE_ADDR + 0x450) & 0x08000000)) {
1337 serror_need_skip = false;
1338 return; /* Do nothing skip the SError in ROM */
1339 }
1340
1341 /* Check for ERR050350, field return mode for imx8mq, mm and mn */
1342 if (readl(OCOTP_BASE_ADDR + 0x630) & 0x1) {
1343 serror_need_skip = false;
1344 return; /* Do nothing skip the SError in ROM */
1345 }
1346 }
1347
1348 efi_restore_gd();
Sean Anderson2d755492022-03-22 17:17:35 -04001349 printf("\"Error\" handler, esr 0x%08lx\n", pt_regs->esr);
Peng Fana35215d2020-07-09 13:39:26 +08001350 show_regs(pt_regs);
1351 panic("Resetting CPU ...\n");
1352}
1353#endif
1354#endif
Ye Li0513f362019-07-15 01:16:46 -07001355
1356#if defined(CONFIG_IMX8MN) || defined(CONFIG_IMX8MP)
1357enum env_location env_get_location(enum env_operation op, int prio)
1358{
1359 enum boot_device dev = get_boot_device();
Ye Li0513f362019-07-15 01:16:46 -07001360
1361 if (prio)
Ricardo Salveti1daf63f2021-10-20 16:16:26 -03001362 return ENVL_UNKNOWN;
Ye Li0513f362019-07-15 01:16:46 -07001363
1364 switch (dev) {
Ye Li0513f362019-07-15 01:16:46 -07001365 case QSPI_BOOT:
Marek Vasut31b3bc42022-03-25 18:59:28 +01001366 case SPI_NOR_BOOT:
Ricardo Salveti1daf63f2021-10-20 16:16:26 -03001367 if (IS_ENABLED(CONFIG_ENV_IS_IN_SPI_FLASH))
1368 return ENVL_SPI_FLASH;
1369 return ENVL_NOWHERE;
Ye Li0513f362019-07-15 01:16:46 -07001370 case NAND_BOOT:
Ricardo Salveti1daf63f2021-10-20 16:16:26 -03001371 if (IS_ENABLED(CONFIG_ENV_IS_IN_NAND))
1372 return ENVL_NAND;
1373 return ENVL_NOWHERE;
Ye Li0513f362019-07-15 01:16:46 -07001374 case SD1_BOOT:
1375 case SD2_BOOT:
1376 case SD3_BOOT:
1377 case MMC1_BOOT:
1378 case MMC2_BOOT:
1379 case MMC3_BOOT:
Ricardo Salveti1daf63f2021-10-20 16:16:26 -03001380 if (IS_ENABLED(CONFIG_ENV_IS_IN_MMC))
1381 return ENVL_MMC;
1382 else if (IS_ENABLED(CONFIG_ENV_IS_IN_EXT4))
1383 return ENVL_EXT4;
1384 else if (IS_ENABLED(CONFIG_ENV_IS_IN_FAT))
1385 return ENVL_FAT;
1386 return ENVL_NOWHERE;
Ye Li0513f362019-07-15 01:16:46 -07001387 default:
Ricardo Salveti1daf63f2021-10-20 16:16:26 -03001388 return ENVL_NOWHERE;
Ye Li0513f362019-07-15 01:16:46 -07001389 }
Ye Li0513f362019-07-15 01:16:46 -07001390}
1391
Ye Li0513f362019-07-15 01:16:46 -07001392#endif