blob: bb13ca742e3a245e0ca63b8fb8c69068d5339d7a [file] [log] [blame]
Peng Fanbbcd2c42022-07-26 16:40:39 +08001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2022 NXP
4 *
5 * Peng Fan <peng.fan@nxp.com>
6 */
7
Tom Rinidec7ea02024-05-20 13:35:03 -06008#include <config.h>
Peng Fanbbcd2c42022-07-26 16:40:39 +08009#include <cpu_func.h>
10#include <init.h>
11#include <log.h>
12#include <asm/arch/imx-regs.h>
13#include <asm/global_data.h>
14#include <asm/io.h>
15#include <asm/arch/clock.h>
Peng Fan6d929962022-07-26 16:41:03 +080016#include <asm/arch/ccm_regs.h>
Peng Fanbbcd2c42022-07-26 16:40:39 +080017#include <asm/arch/sys_proto.h>
Ye Li62185922022-07-26 16:40:54 +080018#include <asm/arch/trdc.h>
Peng Fanbbcd2c42022-07-26 16:40:39 +080019#include <asm/mach-imx/boot_mode.h>
20#include <asm/mach-imx/syscounter.h>
21#include <asm/armv8/mmu.h>
Peng Fanb1815c42023-04-28 12:08:27 +080022#include <dm/device.h>
23#include <dm/device_compat.h>
Peng Fanbbcd2c42022-07-26 16:40:39 +080024#include <dm/uclass.h>
25#include <env.h>
26#include <env_internal.h>
27#include <errno.h>
28#include <fdt_support.h>
Peng Fan0c2f3682023-04-28 12:08:28 +080029#include <imx_thermal.h>
Peng Fanbbcd2c42022-07-26 16:40:39 +080030#include <linux/bitops.h>
Peng Fan0c2f3682023-04-28 12:08:28 +080031#include <linux/bitfield.h>
32#include <linux/delay.h>
33#include <thermal.h>
Peng Fanbbcd2c42022-07-26 16:40:39 +080034#include <asm/setup.h>
35#include <asm/bootm.h>
36#include <asm/arch-imx/cpu.h>
Peng Fand5c31832023-06-15 18:09:05 +080037#include <asm/mach-imx/ele_api.h>
Ye Li66baefb2023-04-28 12:08:21 +080038#include <fuse.h>
Ye Libb1187b2023-04-28 12:08:45 +080039#include <asm/arch/ddr.h>
Peng Fanbbcd2c42022-07-26 16:40:39 +080040
41DECLARE_GLOBAL_DATA_PTR;
42
Peng Fan5de0fc02022-07-26 16:40:48 +080043struct rom_api *g_rom_api = (struct rom_api *)0x1980;
44
Benjamin Szőke4a671072024-11-01 16:26:18 +010045#if CONFIG_IS_ENABLED(ENV_IS_IN_MMC) || CONFIG_IS_ENABLED(ENV_IS_NOWHERE)
Peng Fan5de0fc02022-07-26 16:40:48 +080046__weak int board_mmc_get_env_dev(int devno)
47{
Peng Fan77b36c62023-04-28 12:08:33 +080048 return devno;
49}
Peng Fan5de0fc02022-07-26 16:40:48 +080050
Benjamin Szőke4a671072024-11-01 16:26:18 +010051#ifdef CONFIG_SYS_MMC_ENV_DEV
52#define IMX9_MMC_ENV_DEV CONFIG_SYS_MMC_ENV_DEV
53#else
54#define IMX9_MMC_ENV_DEV 0
55#endif
56
Peng Fan5de0fc02022-07-26 16:40:48 +080057int mmc_get_env_dev(void)
58{
Peng Fan5de0fc02022-07-26 16:40:48 +080059 int ret;
60 u32 boot;
61 u16 boot_type;
62 u8 boot_instance;
63
Peng Fanc459b582023-04-28 12:08:34 +080064 ret = rom_api_query_boot_infor(QUERY_BT_DEV, &boot);
Peng Fan5de0fc02022-07-26 16:40:48 +080065
66 if (ret != ROM_API_OKAY) {
67 puts("ROMAPI: failure at query_boot_info\n");
Benjamin Szőke4a671072024-11-01 16:26:18 +010068 return IMX9_MMC_ENV_DEV;
Peng Fan5de0fc02022-07-26 16:40:48 +080069 }
70
71 boot_type = boot >> 16;
72 boot_instance = (boot >> 8) & 0xff;
73
74 debug("boot_type %d, instance %d\n", boot_type, boot_instance);
75
76 /* If not boot from sd/mmc, use default value */
77 if (boot_type != BOOT_TYPE_SD && boot_type != BOOT_TYPE_MMC)
Benjamin Szőke4a671072024-11-01 16:26:18 +010078 return env_get_ulong("mmcdev", 10, IMX9_MMC_ENV_DEV);
Peng Fan5de0fc02022-07-26 16:40:48 +080079
80 return board_mmc_get_env_dev(boot_instance);
81}
82#endif
83
Peng Fan0c2f3682023-04-28 12:08:28 +080084/*
85 * SPEED_GRADE[5:4] SPEED_GRADE[3:0] MHz
86 * xx 0000 2300
87 * xx 0001 2200
88 * xx 0010 2100
89 * xx 0011 2000
90 * xx 0100 1900
91 * xx 0101 1800
92 * xx 0110 1700
93 * xx 0111 1600
94 * xx 1000 1500
95 * xx 1001 1400
96 * xx 1010 1300
97 * xx 1011 1200
98 * xx 1100 1100
99 * xx 1101 1000
100 * xx 1110 900
101 * xx 1111 800
102 */
103u32 get_cpu_speed_grade_hz(void)
104{
Peng Fan43126e12024-09-19 12:01:23 +0800105 int ret;
106 u32 bank, word, speed, max_speed;
Peng Fan0c2f3682023-04-28 12:08:28 +0800107 u32 val;
108
Peng Fan43126e12024-09-19 12:01:23 +0800109 bank = HW_CFG1 / NUM_WORDS_PER_BANK;
110 word = HW_CFG1 % NUM_WORDS_PER_BANK;
111 ret = fuse_read(bank, word, &val);
112 if (ret)
113 val = 0; /* If read fuse failed, return as blank fuse */
114
Peng Fan0c2f3682023-04-28 12:08:28 +0800115 val = FIELD_GET(SPEED_GRADING_MASK, val) & 0xF;
116
117 speed = MHZ(2300) - val * MHZ(100);
118
119 if (is_imx93())
120 max_speed = MHZ(1700);
Peng Fan0ce300f2024-12-03 23:42:48 +0800121 else if (is_imx91())
122 max_speed = MHZ(1400);
Peng Fan0c2f3682023-04-28 12:08:28 +0800123
124 /* In case the fuse of speed grade not programmed */
125 if (speed > max_speed)
126 speed = max_speed;
127
128 return speed;
129}
130
131/*
132 * `00` - Consumer 0C to 95C
133 * `01` - Ext. Consumer -20C to 105C
134 * `10` - Industrial -40C to 105C
135 * `11` - Automotive -40C to 125C
136 */
137u32 get_cpu_temp_grade(int *minc, int *maxc)
138{
Peng Fan43126e12024-09-19 12:01:23 +0800139 int ret;
140 u32 bank, word, val;
141
142 bank = HW_CFG1 / NUM_WORDS_PER_BANK;
143 word = HW_CFG1 % NUM_WORDS_PER_BANK;
144 ret = fuse_read(bank, word, &val);
145 if (ret)
146 val = 0; /* If read fuse failed, return as blank fuse */
Peng Fan0c2f3682023-04-28 12:08:28 +0800147
Peng Fan0c2f3682023-04-28 12:08:28 +0800148 val = FIELD_GET(MARKETING_GRADING_MASK, val);
149
150 if (minc && maxc) {
151 if (val == TEMP_AUTOMOTIVE) {
152 *minc = -40;
153 *maxc = 125;
154 } else if (val == TEMP_INDUSTRIAL) {
155 *minc = -40;
156 *maxc = 105;
157 } else if (val == TEMP_EXTCOMMERCIAL) {
158 if (is_imx93()) {
159 /* imx93 only has extended industrial*/
160 *minc = -40;
161 *maxc = 125;
162 } else {
163 *minc = -20;
164 *maxc = 105;
165 }
166 } else {
167 *minc = 0;
168 *maxc = 95;
169 }
170 }
171 return val;
172}
173
Peng Fand5c31832023-06-15 18:09:05 +0800174static void set_cpu_info(struct ele_get_info_data *info)
Peng Fan3700c472022-07-26 16:40:56 +0800175{
176 gd->arch.soc_rev = info->soc;
177 gd->arch.lifecycle = info->lc;
178 memcpy((void *)&gd->arch.uid, &info->uid, 4 * sizeof(u32));
179}
180
Peng Fanc3db3ad2023-04-28 12:08:32 +0800181static u32 get_cpu_variant_type(u32 type)
182{
Peng Fan43126e12024-09-19 12:01:23 +0800183 u32 bank, word, val, val2;
184 int ret;
185
186 bank = HW_CFG1 / NUM_WORDS_PER_BANK;
187 word = HW_CFG1 % NUM_WORDS_PER_BANK;
188 ret = fuse_read(bank, word, &val);
189 if (ret)
190 val = 0; /* If read fuse failed, return as blank fuse */
191
192 bank = HW_CFG2 / NUM_WORDS_PER_BANK;
193 word = HW_CFG2 % NUM_WORDS_PER_BANK;
194 ret = fuse_read(bank, word, &val2);
195 if (ret)
196 val2 = 0; /* If read fuse failed, return as blank fuse */
197
Peng Fanc3db3ad2023-04-28 12:08:32 +0800198 bool npu_disable = !!(val & BIT(13));
199 bool core1_disable = !!(val & BIT(15));
Ye Lif7c9bac2024-12-03 23:42:47 +0800200 u32 pack_9x9_fused = BIT(4) | BIT(5) | BIT(17) | BIT(19) | BIT(24);
Peng Fan0ce300f2024-12-03 23:42:48 +0800201 u32 nxp_recog = (val & GENMASK(23, 16)) >> 16;
202
203 /* For iMX91 */
204 if (type == MXC_CPU_IMX91) {
205 switch (nxp_recog) {
206 case 0x9:
207 case 0xA:
208 type = MXC_CPU_IMX9111;
209 break;
210 case 0xD:
211 case 0xE:
212 type = MXC_CPU_IMX9121;
213 break;
214 case 0xF:
215 case 0x10:
216 type = MXC_CPU_IMX9101;
217 break;
218 default:
219 break; /* 9131 as default */
220 }
221
222 return type;
223 }
Peng Fanc3db3ad2023-04-28 12:08:32 +0800224
Ye Li57b2ac42024-09-19 12:01:33 +0800225 /* Low performance 93 part */
226 if (((val >> 6) & 0x3F) == 0xE && npu_disable)
227 return core1_disable ? MXC_CPU_IMX9301 : MXC_CPU_IMX9302;
228
Peng Fanc3db3ad2023-04-28 12:08:32 +0800229 if ((val2 & pack_9x9_fused) == pack_9x9_fused)
230 type = MXC_CPU_IMX9322;
231
232 if (npu_disable && core1_disable)
233 return type + 3;
234 else if (npu_disable)
235 return type + 2;
236 else if (core1_disable)
237 return type + 1;
238
239 return type;
240}
241
Peng Fanbbcd2c42022-07-26 16:40:39 +0800242u32 get_cpu_rev(void)
243{
Peng Fan3700c472022-07-26 16:40:56 +0800244 u32 rev = (gd->arch.soc_rev >> 24) - 0xa0;
Peng Fan0ce300f2024-12-03 23:42:48 +0800245 u32 type;
246
247 if ((gd->arch.soc_rev & 0xFFFF) == 0x9300)
248 type = MXC_CPU_IMX93;
249 else
250 type = MXC_CPU_IMX91;
Peng Fan3700c472022-07-26 16:40:56 +0800251
Peng Fan0ce300f2024-12-03 23:42:48 +0800252 return (get_cpu_variant_type(type) << 12) |
Peng Fanc3db3ad2023-04-28 12:08:32 +0800253 (CHIP_REV_1_0 + rev);
Peng Fanbbcd2c42022-07-26 16:40:39 +0800254}
255
Ye Li9e19ff92022-07-26 16:40:47 +0800256#define UNLOCK_WORD 0xD928C520 /* unlock word */
257#define REFRESH_WORD 0xB480A602 /* refresh word */
258
259static void disable_wdog(void __iomem *wdog_base)
260{
261 u32 val_cs = readl(wdog_base + 0x00);
262
263 if (!(val_cs & 0x80))
264 return;
265
266 /* default is 32bits cmd */
267 writel(REFRESH_WORD, (wdog_base + 0x04)); /* Refresh the CNT */
268
269 if (!(val_cs & 0x800)) {
270 writel(UNLOCK_WORD, (wdog_base + 0x04));
271 while (!(readl(wdog_base + 0x00) & 0x800))
272 ;
273 }
274 writel(0x0, (wdog_base + 0x0C)); /* Set WIN to 0 */
275 writel(0x400, (wdog_base + 0x08)); /* Set timeout to default 0x400 */
276 writel(0x2120, (wdog_base + 0x00)); /* Disable it and set update */
277
278 while (!(readl(wdog_base + 0x00) & 0x400))
279 ;
280}
281
282void init_wdog(void)
283{
Ye Li9e19ff92022-07-26 16:40:47 +0800284 disable_wdog((void __iomem *)WDG3_BASE_ADDR);
285 disable_wdog((void __iomem *)WDG4_BASE_ADDR);
286 disable_wdog((void __iomem *)WDG5_BASE_ADDR);
Ye Li9e19ff92022-07-26 16:40:47 +0800287}
288
Peng Fanbbcd2c42022-07-26 16:40:39 +0800289static struct mm_region imx93_mem_map[] = {
290 {
291 /* ROM */
292 .virt = 0x0UL,
293 .phys = 0x0UL,
294 .size = 0x100000UL,
295 .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
296 PTE_BLOCK_OUTER_SHARE
297 }, {
Peng Fan313af252022-07-26 16:41:04 +0800298 /* TCM */
299 .virt = 0x201c0000UL,
300 .phys = 0x201c0000UL,
301 .size = 0x80000UL,
302 .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
303 PTE_BLOCK_NON_SHARE |
304 PTE_BLOCK_PXN | PTE_BLOCK_UXN
305 }, {
Peng Fanbbcd2c42022-07-26 16:40:39 +0800306 /* OCRAM */
307 .virt = 0x20480000UL,
308 .phys = 0x20480000UL,
309 .size = 0xA0000UL,
310 .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
311 PTE_BLOCK_OUTER_SHARE
312 }, {
313 /* AIPS */
314 .virt = 0x40000000UL,
315 .phys = 0x40000000UL,
316 .size = 0x40000000UL,
317 .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
318 PTE_BLOCK_NON_SHARE |
319 PTE_BLOCK_PXN | PTE_BLOCK_UXN
320 }, {
321 /* Flexible Serial Peripheral Interface */
322 .virt = 0x28000000UL,
323 .phys = 0x28000000UL,
Ye Li35f15512024-03-28 18:49:18 +0800324 .size = 0x08000000UL,
Peng Fanbbcd2c42022-07-26 16:40:39 +0800325 .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
326 PTE_BLOCK_NON_SHARE |
327 PTE_BLOCK_PXN | PTE_BLOCK_UXN
328 }, {
329 /* DRAM1 */
330 .virt = 0x80000000UL,
331 .phys = 0x80000000UL,
332 .size = PHYS_SDRAM_SIZE,
333 .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
334 PTE_BLOCK_OUTER_SHARE
335 }, {
336 /* empty entrie to split table entry 5 if needed when TEEs are used */
337 0,
338 }, {
339 /* List terminator */
340 0,
341 }
342};
343
344struct mm_region *mem_map = imx93_mem_map;
345
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800346static unsigned int imx9_find_dram_entry_in_mem_map(void)
347{
348 int i;
349
350 for (i = 0; i < ARRAY_SIZE(imx93_mem_map); i++)
351 if (imx93_mem_map[i].phys == CFG_SYS_SDRAM_BASE)
352 return i;
353
354 hang(); /* Entry not found, this must never happen. */
355}
356
357void enable_caches(void)
358{
359 /* If OPTEE runs, remove OPTEE memory from MMU table to avoid speculative prefetch
360 * If OPTEE does not run, still update the MMU table according to dram banks structure
361 * to set correct dram size from board_phys_sdram_size
362 */
363 int i = 0;
364 /*
365 * please make sure that entry initial value matches
366 * imx93_mem_map for DRAM1
367 */
368 int entry = imx9_find_dram_entry_in_mem_map();
369 u64 attrs = imx93_mem_map[entry].attrs;
370
371 while (i < CONFIG_NR_DRAM_BANKS &&
372 entry < ARRAY_SIZE(imx93_mem_map)) {
373 if (gd->bd->bi_dram[i].start == 0)
374 break;
375 imx93_mem_map[entry].phys = gd->bd->bi_dram[i].start;
376 imx93_mem_map[entry].virt = gd->bd->bi_dram[i].start;
377 imx93_mem_map[entry].size = gd->bd->bi_dram[i].size;
378 imx93_mem_map[entry].attrs = attrs;
379 debug("Added memory mapping (%d): %llx %llx\n", entry,
380 imx93_mem_map[entry].phys, imx93_mem_map[entry].size);
381 i++; entry++;
382 }
383
384 icache_enable();
385 dcache_enable();
386}
387
388__weak int board_phys_sdram_size(phys_size_t *size)
389{
Ye Libb1187b2023-04-28 12:08:45 +0800390 phys_size_t start, end;
391 phys_size_t val;
392
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800393 if (!size)
394 return -EINVAL;
395
Ye Libb1187b2023-04-28 12:08:45 +0800396 val = readl(REG_DDR_CS0_BNDS);
397 start = (val >> 16) << 24;
398 end = (val & 0xFFFF);
399 end = end ? end + 1 : 0;
400 end = end << 24;
401 *size = end - start;
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800402
Ye Libb1187b2023-04-28 12:08:45 +0800403 val = readl(REG_DDR_CS1_BNDS);
404 start = (val >> 16) << 24;
405 end = (val & 0xFFFF);
406 end = end ? end + 1 : 0;
407 end = end << 24;
408 *size += end - start;
409
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800410 return 0;
411}
412
Peng Fanbbcd2c42022-07-26 16:40:39 +0800413int dram_init(void)
414{
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800415 phys_size_t sdram_size;
416 int ret;
417
418 ret = board_phys_sdram_size(&sdram_size);
419 if (ret)
420 return ret;
421
422 /* rom_pointer[1] contains the size of TEE occupies */
Simon Glass85ed77d2024-09-29 19:49:46 -0600423 if (!IS_ENABLED(CONFIG_XPL_BUILD) && rom_pointer[1])
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800424 gd->ram_size = sdram_size - rom_pointer[1];
425 else
426 gd->ram_size = sdram_size;
427
428 return 0;
429}
430
431int dram_init_banksize(void)
432{
433 int bank = 0;
434 int ret;
435 phys_size_t sdram_size;
436 phys_size_t sdram_b1_size, sdram_b2_size;
437
438 ret = board_phys_sdram_size(&sdram_size);
439 if (ret)
440 return ret;
441
442 /* Bank 1 can't cross over 4GB space */
443 if (sdram_size > 0x80000000) {
444 sdram_b1_size = 0x80000000;
445 sdram_b2_size = sdram_size - 0x80000000;
446 } else {
447 sdram_b1_size = sdram_size;
448 sdram_b2_size = 0;
449 }
450
451 gd->bd->bi_dram[bank].start = PHYS_SDRAM;
Simon Glass85ed77d2024-09-29 19:49:46 -0600452 if (!IS_ENABLED(CONFIG_XPL_BUILD) && rom_pointer[1]) {
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800453 phys_addr_t optee_start = (phys_addr_t)rom_pointer[0];
454 phys_size_t optee_size = (size_t)rom_pointer[1];
455
456 gd->bd->bi_dram[bank].size = optee_start - gd->bd->bi_dram[bank].start;
457 if ((optee_start + optee_size) < (PHYS_SDRAM + sdram_b1_size)) {
458 if (++bank >= CONFIG_NR_DRAM_BANKS) {
459 puts("CONFIG_NR_DRAM_BANKS is not enough\n");
460 return -1;
461 }
462
463 gd->bd->bi_dram[bank].start = optee_start + optee_size;
464 gd->bd->bi_dram[bank].size = PHYS_SDRAM +
465 sdram_b1_size - gd->bd->bi_dram[bank].start;
466 }
467 } else {
468 gd->bd->bi_dram[bank].size = sdram_b1_size;
469 }
470
471 if (sdram_b2_size) {
472 if (++bank >= CONFIG_NR_DRAM_BANKS) {
473 puts("CONFIG_NR_DRAM_BANKS is not enough for SDRAM_2\n");
474 return -1;
475 }
476 gd->bd->bi_dram[bank].start = 0x100000000UL;
477 gd->bd->bi_dram[bank].size = sdram_b2_size;
478 }
Peng Fanbbcd2c42022-07-26 16:40:39 +0800479
480 return 0;
481}
482
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800483phys_size_t get_effective_memsize(void)
484{
485 int ret;
486 phys_size_t sdram_size;
487 phys_size_t sdram_b1_size;
488
489 ret = board_phys_sdram_size(&sdram_size);
490 if (!ret) {
491 /* Bank 1 can't cross over 4GB space */
492 if (sdram_size > 0x80000000)
493 sdram_b1_size = 0x80000000;
494 else
495 sdram_b1_size = sdram_size;
496
Simon Glass85ed77d2024-09-29 19:49:46 -0600497 if (!IS_ENABLED(CONFIG_XPL_BUILD) && rom_pointer[1]) {
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800498 /* We will relocate u-boot to top of dram1. TEE position has two cases:
499 * 1. At the top of dram1, Then return the size removed optee size.
500 * 2. In the middle of dram1, return the size of dram1.
501 */
502 if ((rom_pointer[0] + rom_pointer[1]) == (PHYS_SDRAM + sdram_b1_size))
503 return ((phys_addr_t)rom_pointer[0] - PHYS_SDRAM);
504 }
505
506 return sdram_b1_size;
507 } else {
508 return PHYS_SDRAM_SIZE;
509 }
510}
511
Peng Fanbbcd2c42022-07-26 16:40:39 +0800512void imx_get_mac_from_fuse(int dev_id, unsigned char *mac)
513{
Ye Li66baefb2023-04-28 12:08:21 +0800514 u32 val[2] = {};
515 int ret;
516
517 if (dev_id == 0) {
518 ret = fuse_read(39, 3, &val[0]);
519 if (ret)
520 goto err;
521
522 ret = fuse_read(39, 4, &val[1]);
523 if (ret)
524 goto err;
525
526 mac[0] = val[1] >> 8;
527 mac[1] = val[1];
528 mac[2] = val[0] >> 24;
529 mac[3] = val[0] >> 16;
530 mac[4] = val[0] >> 8;
531 mac[5] = val[0];
532
533 } else {
534 ret = fuse_read(39, 5, &val[0]);
535 if (ret)
536 goto err;
537
538 ret = fuse_read(39, 4, &val[1]);
539 if (ret)
540 goto err;
541
Ye Liae9b7022024-09-19 12:01:24 +0800542 if (is_imx93() && is_soc_rev(CHIP_REV_1_0)) {
543 mac[0] = val[1] >> 24;
544 mac[1] = val[1] >> 16;
545 mac[2] = val[0] >> 24;
546 mac[3] = val[0] >> 16;
547 mac[4] = val[0] >> 8;
548 mac[5] = val[0];
549 } else {
550 mac[0] = val[0] >> 24;
551 mac[1] = val[0] >> 16;
552 mac[2] = val[0] >> 8;
553 mac[3] = val[0];
554 mac[4] = val[1] >> 24;
555 mac[5] = val[1] >> 16;
556 }
Ye Li66baefb2023-04-28 12:08:21 +0800557 }
558
559 debug("%s: MAC%d: %02x.%02x.%02x.%02x.%02x.%02x\n",
560 __func__, dev_id, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
561 return;
562err:
563 memset(mac, 0, 6);
564 printf("%s: fuse read err: %d\n", __func__, ret);
Peng Fanbbcd2c42022-07-26 16:40:39 +0800565}
566
567int print_cpuinfo(void)
568{
569 u32 cpurev;
570
571 cpurev = get_cpu_rev();
572
Peng Fan0ce300f2024-12-03 23:42:48 +0800573 printf("CPU: i.MX%s rev%d.%d\n", is_imx93() ? "93" : "91",
574 (cpurev & 0x000F0) >> 4, (cpurev & 0x0000F) >> 0);
Peng Fanbbcd2c42022-07-26 16:40:39 +0800575
576 return 0;
577}
578
Peng Fan1a17ae82024-09-19 12:01:25 +0800579void build_info(void)
580{
581 u32 fw_version, sha1, res, status;
582 int ret;
583
584 printf("\nBuildInfo:\n");
585
586 ret = ele_get_fw_status(&status, &res);
587 if (ret) {
588 printf(" - ELE firmware status failed %d, 0x%x\n", ret, res);
589 } else if ((status & 0xff) == 1) {
590 ret = ele_get_fw_version(&fw_version, &sha1, &res);
591 if (ret) {
592 printf(" - ELE firmware version failed %d, 0x%x\n", ret, res);
593 } else {
594 printf(" - ELE firmware version %u.%u.%u-%x",
595 (fw_version & (0x00ff0000)) >> 16,
596 (fw_version & (0x0000fff0)) >> 4,
597 (fw_version & (0x0000000f)), sha1);
598 ((fw_version & (0x80000000)) >> 31) == 1 ? puts("-dirty\n") : puts("\n");
599 }
600 } else {
601 printf(" - ELE firmware not included\n");
602 }
603 puts("\n");
604}
605
606int arch_misc_init(void)
607{
608 build_info();
609 return 0;
610}
611
Ye Li7b248152024-09-19 12:01:26 +0800612struct low_drive_freq_entry {
613 const char *node_path;
614 u32 clk;
615 u32 new_rate;
616};
617
618static int low_drive_fdt_fix_clock(void *fdt, int node_off, u32 clk_index, u32 new_rate)
619{
620#define MAX_ASSIGNED_CLKS 8
621 int cnt, j;
622 u32 assignedclks[MAX_ASSIGNED_CLKS]; /* max 8 clocks*/
623
624 cnt = fdtdec_get_int_array_count(fdt, node_off, "assigned-clock-rates",
625 assignedclks, MAX_ASSIGNED_CLKS);
626 if (cnt > 0) {
627 if (cnt <= clk_index)
628 return -ENOENT;
629
630 if (assignedclks[clk_index] <= new_rate)
631 return 0;
632
633 assignedclks[clk_index] = new_rate;
634 for (j = 0; j < cnt; j++)
635 assignedclks[j] = cpu_to_fdt32(assignedclks[j]);
636
637 return fdt_setprop(fdt, node_off, "assigned-clock-rates", &assignedclks,
638 cnt * sizeof(u32));
639 }
640
641 return -ENOENT;
642}
643
644static int low_drive_freq_update(void *blob)
645{
646 int nodeoff, ret;
647 int i;
648
649 /* Update kernel dtb clocks for low drive mode */
650 struct low_drive_freq_entry table[] = {
651 {"/soc@0/bus@42800000/mmc@42850000", 0, 266666667},
652 {"/soc@0/bus@42800000/mmc@42860000", 0, 266666667},
653 {"/soc@0/bus@42800000/mmc@428b0000", 0, 266666667},
654 };
655
656 for (i = 0; i < ARRAY_SIZE(table); i++) {
657 nodeoff = fdt_path_offset(blob, table[i].node_path);
658 if (nodeoff >= 0) {
659 ret = low_drive_fdt_fix_clock(blob, nodeoff, table[i].clk,
660 table[i].new_rate);
661 if (!ret)
662 printf("%s freq updated\n", table[i].node_path);
663 }
664 }
665
666 return 0;
667}
668
Christoph Stoidner5b7d7012024-11-20 17:31:42 +0100669#if defined(CONFIG_OF_BOARD_FIXUP) && !defined(CONFIG_TARGET_PHYCORE_IMX93)
Simon Glass85ed77d2024-09-29 19:49:46 -0600670#ifndef CONFIG_XPL_BUILD
Ye Li7b248152024-09-19 12:01:26 +0800671int board_fix_fdt(void *fdt)
672{
673 /* Update dtb clocks for low drive mode */
674 if (is_voltage_mode(VOLT_LOW_DRIVE)) {
675 int nodeoff;
676 int i;
677
678 struct low_drive_freq_entry table[] = {
679 {"/soc@0/bus@42800000/mmc@42850000", 0, 266666667},
680 {"/soc@0/bus@42800000/mmc@42860000", 0, 266666667},
681 {"/soc@0/bus@42800000/mmc@428b0000", 0, 266666667},
682 };
683
684 for (i = 0; i < ARRAY_SIZE(table); i++) {
685 nodeoff = fdt_path_offset(fdt, table[i].node_path);
686 if (nodeoff >= 0)
687 low_drive_fdt_fix_clock(fdt, nodeoff, table[i].clk,
688 table[i].new_rate);
689 }
690 }
691
692 return 0;
693}
694#endif
695#endif
696
Peng Fanbbcd2c42022-07-26 16:40:39 +0800697int ft_system_setup(void *blob, struct bd_info *bd)
698{
Peng Fan904a8862024-09-19 12:01:32 +0800699 static const char * const nodes_path[] = {
700 "/cpus/cpu@0",
701 "/cpus/cpu@100",
702 };
703
Primoz Fiserebbd4fc2024-01-11 13:56:25 +0100704 if (fixup_thermal_trips(blob, "cpu-thermal"))
705 printf("Failed to update cpu-thermal trip(s)");
706
Ye Li57b2ac42024-09-19 12:01:33 +0800707 if (is_imx9351() || is_imx9331() || is_imx9321() || is_imx9311() || is_imx9301())
Peng Fan904a8862024-09-19 12:01:32 +0800708 disable_cpu_nodes(blob, nodes_path, 1, 2);
709
Ye Li7b248152024-09-19 12:01:26 +0800710 if (is_voltage_mode(VOLT_LOW_DRIVE))
711 low_drive_freq_update(blob);
712
Peng Fanbbcd2c42022-07-26 16:40:39 +0800713 return 0;
714}
Peng Fan3700c472022-07-26 16:40:56 +0800715
716#if defined(CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG)
717void get_board_serial(struct tag_serialnr *serialnr)
718{
Ye Li8a7f6ef2024-09-19 12:01:22 +0800719 printf("UID: %08x%08x%08x%08x\n", __be32_to_cpu(gd->arch.uid[0]),
720 __be32_to_cpu(gd->arch.uid[1]), __be32_to_cpu(gd->arch.uid[2]),
721 __be32_to_cpu(gd->arch.uid[3]));
Peng Fan3700c472022-07-26 16:40:56 +0800722
Frank Li52b93ea2024-09-19 12:01:21 +0800723 serialnr->low = __be32_to_cpu(gd->arch.uid[1]);
724 serialnr->high = __be32_to_cpu(gd->arch.uid[0]);
Peng Fan3700c472022-07-26 16:40:56 +0800725}
726#endif
Peng Fanbbcd2c42022-07-26 16:40:39 +0800727
Peng Fanb1815c42023-04-28 12:08:27 +0800728static void save_reset_cause(void)
729{
730 struct src_general_regs *src = (struct src_general_regs *)SRC_GLOBAL_RBASE;
731 u32 srsr = readl(&src->srsr);
732
733 /* clear srsr in sec mode */
734 writel(srsr, &src->srsr);
735
736 /* Save value to GPR1 to pass to nonsecure */
737 writel(srsr, &src->gpr[0]);
738}
739
Peng Fanbbcd2c42022-07-26 16:40:39 +0800740int arch_cpu_init(void)
741{
Simon Glass85ed77d2024-09-29 19:49:46 -0600742 if (IS_ENABLED(CONFIG_XPL_BUILD)) {
Ye Li9e19ff92022-07-26 16:40:47 +0800743 /* Disable wdog */
744 init_wdog();
745
Ye Li66af10a2024-09-19 12:01:27 +0800746 clock_init_early();
Ye Li62185922022-07-26 16:40:54 +0800747
748 trdc_early_init();
Peng Fanb1815c42023-04-28 12:08:27 +0800749
750 /* Save SRC SRSR to GPR1 and clear it */
751 save_reset_cause();
Ye Li9e19ff92022-07-26 16:40:47 +0800752 }
Peng Fan28b5cb52022-07-26 16:40:43 +0800753
Peng Fanbbcd2c42022-07-26 16:40:39 +0800754 return 0;
755}
Peng Fan3700c472022-07-26 16:40:56 +0800756
Simon Glassb8357c12023-08-21 21:16:56 -0600757int imx9_probe_mu(void)
Peng Fan3700c472022-07-26 16:40:56 +0800758{
759 struct udevice *devp;
760 int node, ret;
761 u32 res;
Peng Fand5c31832023-06-15 18:09:05 +0800762 struct ele_get_info_data info;
Peng Fan3700c472022-07-26 16:40:56 +0800763
764 node = fdt_node_offset_by_compatible(gd->fdt_blob, -1, "fsl,imx93-mu-s4");
765
766 ret = uclass_get_device_by_of_offset(UCLASS_MISC, node, &devp);
767 if (ret)
768 return ret;
769
770 if (gd->flags & GD_FLG_RELOC)
771 return 0;
772
Peng Fand5c31832023-06-15 18:09:05 +0800773 ret = ele_get_info(&info, &res);
Peng Fan3700c472022-07-26 16:40:56 +0800774 if (ret)
775 return ret;
776
777 set_cpu_info(&info);
778
779 return 0;
780}
Simon Glassb8357c12023-08-21 21:16:56 -0600781EVENT_SPY_SIMPLE(EVT_DM_POST_INIT_F, imx9_probe_mu);
Ye Lif41ffc12024-04-01 09:41:09 +0800782EVENT_SPY_SIMPLE(EVT_DM_POST_INIT_R, imx9_probe_mu);
Jian Liacf41a32022-07-26 16:40:46 +0800783
784int timer_init(void)
785{
Simon Glass85ed77d2024-09-29 19:49:46 -0600786#ifdef CONFIG_XPL_BUILD
Jian Liacf41a32022-07-26 16:40:46 +0800787 struct sctr_regs *sctr = (struct sctr_regs *)SYSCNT_CTRL_BASE_ADDR;
788 unsigned long freq = readl(&sctr->cntfid0);
789
790 /* Update with accurate clock frequency */
791 asm volatile("msr cntfrq_el0, %0" : : "r" (freq) : "memory");
792
793 clrsetbits_le32(&sctr->cntcr, SC_CNTCR_FREQ0 | SC_CNTCR_FREQ1,
794 SC_CNTCR_FREQ0 | SC_CNTCR_ENABLE | SC_CNTCR_HDBG);
795#endif
796
797 gd->arch.tbl = 0;
798 gd->arch.tbu = 0;
799
800 return 0;
801}
Peng Fan65563792022-07-26 16:41:02 +0800802
Ye Li8e8687c2022-07-26 16:41:05 +0800803enum env_location env_get_location(enum env_operation op, int prio)
804{
805 enum boot_device dev = get_boot_device();
Ye Li8e8687c2022-07-26 16:41:05 +0800806
807 if (prio)
Oleksandr Suvoroveff7c8d2023-04-11 20:27:41 +0300808 return ENVL_UNKNOWN;
Ye Li8e8687c2022-07-26 16:41:05 +0800809
810 switch (dev) {
Ye Li8e8687c2022-07-26 16:41:05 +0800811 case QSPI_BOOT:
Oleksandr Suvoroveff7c8d2023-04-11 20:27:41 +0300812 if (CONFIG_IS_ENABLED(ENV_IS_IN_SPI_FLASH))
813 return ENVL_SPI_FLASH;
814 return ENVL_NOWHERE;
Ye Li8e8687c2022-07-26 16:41:05 +0800815 case SD1_BOOT:
816 case SD2_BOOT:
817 case SD3_BOOT:
818 case MMC1_BOOT:
819 case MMC2_BOOT:
820 case MMC3_BOOT:
Oleksandr Suvoroveff7c8d2023-04-11 20:27:41 +0300821 if (CONFIG_IS_ENABLED(ENV_IS_IN_MMC))
822 return ENVL_MMC;
823 else if (CONFIG_IS_ENABLED(ENV_IS_IN_EXT4))
824 return ENVL_EXT4;
825 else if (CONFIG_IS_ENABLED(ENV_IS_IN_FAT))
826 return ENVL_FAT;
827 return ENVL_NOWHERE;
Ye Li8e8687c2022-07-26 16:41:05 +0800828 default:
Oleksandr Suvoroveff7c8d2023-04-11 20:27:41 +0300829 return ENVL_NOWHERE;
Ye Li8e8687c2022-07-26 16:41:05 +0800830 }
Ye Li8e8687c2022-07-26 16:41:05 +0800831}
832
Peng Fan65563792022-07-26 16:41:02 +0800833static int mix_power_init(enum mix_power_domain pd)
834{
835 enum src_mix_slice_id mix_id;
836 enum src_mem_slice_id mem_id;
837 struct src_mix_slice_regs *mix_regs;
838 struct src_mem_slice_regs *mem_regs;
839 struct src_general_regs *global_regs;
840 u32 scr, val;
841
842 switch (pd) {
843 case MIX_PD_MEDIAMIX:
844 mix_id = SRC_MIX_MEDIA;
845 mem_id = SRC_MEM_MEDIA;
846 scr = BIT(5);
847
Peng Fand5c31832023-06-15 18:09:05 +0800848 /* Enable ELE handshake */
Peng Fan65563792022-07-26 16:41:02 +0800849 struct blk_ctrl_s_aonmix_regs *s_regs =
850 (struct blk_ctrl_s_aonmix_regs *)BLK_CTRL_S_ANOMIX_BASE_ADDR;
851
852 setbits_le32(&s_regs->lp_handshake[0], BIT(13));
853 break;
854 case MIX_PD_MLMIX:
855 mix_id = SRC_MIX_ML;
856 mem_id = SRC_MEM_ML;
857 scr = BIT(4);
858 break;
859 case MIX_PD_DDRMIX:
860 mix_id = SRC_MIX_DDRMIX;
861 mem_id = SRC_MEM_DDRMIX;
862 scr = BIT(6);
863 break;
864 default:
865 return -EINVAL;
866 }
867
868 mix_regs = (struct src_mix_slice_regs *)(ulong)(SRC_IPS_BASE_ADDR + 0x400 * (mix_id + 1));
869 mem_regs =
870 (struct src_mem_slice_regs *)(ulong)(SRC_IPS_BASE_ADDR + 0x3800 + 0x400 * mem_id);
871 global_regs = (struct src_general_regs *)(ulong)SRC_GLOBAL_RBASE;
872
873 /* Allow NS to set it */
874 setbits_le32(&mix_regs->authen_ctrl, BIT(9));
875
876 clrsetbits_le32(&mix_regs->psw_ack_ctrl[0], BIT(28), BIT(29));
877
878 /* mix reset will be held until boot core write this bit to 1 */
879 setbits_le32(&global_regs->scr, scr);
880
881 /* Enable mem in Low power auto sequence */
882 setbits_le32(&mem_regs->mem_ctrl, BIT(2));
883
884 /* Set the power down state */
885 val = readl(&mix_regs->func_stat);
886 if (val & SRC_MIX_SLICE_FUNC_STAT_PSW_STAT) {
887 /* The mix is default power off, power down it to make PDN_SFT bit
888 * aligned with FUNC STAT
889 */
890 setbits_le32(&mix_regs->slice_sw_ctrl, BIT(31));
891 val = readl(&mix_regs->func_stat);
892
893 /* Since PSW_STAT is 1, can't be used for power off status (SW_CTRL BIT31 set)) */
894 /* Check the MEM STAT change to ensure SSAR is completed */
895 while (!(val & SRC_MIX_SLICE_FUNC_STAT_MEM_STAT))
896 val = readl(&mix_regs->func_stat);
897
898 /* wait few ipg clock cycles to ensure FSM done and power off status is correct */
899 /* About 5 cycles at 24Mhz, 1us is enough */
900 udelay(1);
901 } else {
902 /* The mix is default power on, Do mix power cycle */
903 setbits_le32(&mix_regs->slice_sw_ctrl, BIT(31));
904 val = readl(&mix_regs->func_stat);
905 while (!(val & SRC_MIX_SLICE_FUNC_STAT_PSW_STAT))
906 val = readl(&mix_regs->func_stat);
907 }
908
909 /* power on */
910 clrbits_le32(&mix_regs->slice_sw_ctrl, BIT(31));
911 val = readl(&mix_regs->func_stat);
Peng Fan06e78ff2024-09-19 12:01:19 +0800912 while (val & SRC_MIX_SLICE_FUNC_STAT_SSAR_STAT)
Peng Fan65563792022-07-26 16:41:02 +0800913 val = readl(&mix_regs->func_stat);
914
915 return 0;
916}
917
918void disable_isolation(void)
919{
920 struct src_general_regs *global_regs = (struct src_general_regs *)(ulong)SRC_GLOBAL_RBASE;
921 /* clear isolation for usbphy, dsi, csi*/
922 writel(0x0, &global_regs->sp_iso_ctrl);
923}
924
925void soc_power_init(void)
926{
927 mix_power_init(MIX_PD_MEDIAMIX);
Peng Fan0ce300f2024-12-03 23:42:48 +0800928
929 if (is_imx93())
930 mix_power_init(MIX_PD_MLMIX);
Peng Fan65563792022-07-26 16:41:02 +0800931
932 disable_isolation();
933}
Peng Fan6d929962022-07-26 16:41:03 +0800934
Peng Fan313af252022-07-26 16:41:04 +0800935bool m33_is_rom_kicked(void)
Peng Fan6d929962022-07-26 16:41:03 +0800936{
937 struct blk_ctrl_s_aonmix_regs *s_regs =
938 (struct blk_ctrl_s_aonmix_regs *)BLK_CTRL_S_ANOMIX_BASE_ADDR;
939
940 if (!(readl(&s_regs->m33_cfg) & BIT(2)))
941 return true;
942
943 return false;
944}
945
946int m33_prepare(void)
947{
948 struct src_mix_slice_regs *mix_regs =
949 (struct src_mix_slice_regs *)(ulong)(SRC_IPS_BASE_ADDR + 0x400 * (SRC_MIX_CM33 + 1));
950 struct src_general_regs *global_regs =
951 (struct src_general_regs *)(ulong)SRC_GLOBAL_RBASE;
952 struct blk_ctrl_s_aonmix_regs *s_regs =
953 (struct blk_ctrl_s_aonmix_regs *)BLK_CTRL_S_ANOMIX_BASE_ADDR;
Ye Li0667ec92024-09-19 12:01:20 +0800954 u32 val, i;
Peng Fan6d929962022-07-26 16:41:03 +0800955
Peng Fan0ce300f2024-12-03 23:42:48 +0800956 if (is_imx91())
957 return -ENODEV;
958
Peng Fan6d929962022-07-26 16:41:03 +0800959 if (m33_is_rom_kicked())
960 return -EPERM;
961
962 /* Release reset of M33 */
963 setbits_le32(&global_regs->scr, BIT(0));
964
965 /* Check the reset released in M33 MIX func stat */
966 val = readl(&mix_regs->func_stat);
967 while (!(val & SRC_MIX_SLICE_FUNC_STAT_RST_STAT))
968 val = readl(&mix_regs->func_stat);
969
Peng Fand5c31832023-06-15 18:09:05 +0800970 /* Release ELE TROUT */
971 ele_release_m33_trout();
Peng Fan6d929962022-07-26 16:41:03 +0800972
973 /* Mask WDOG1 IRQ from A55, we use it for M33 reset */
974 setbits_le32(&s_regs->ca55_irq_mask[1], BIT(6));
975
976 /* Turn on WDOG1 clock */
977 ccm_lpcg_on(CCGR_WDG1, 1);
978
Peng Fand5c31832023-06-15 18:09:05 +0800979 /* Set ELE LP handshake for M33 reset */
Peng Fan6d929962022-07-26 16:41:03 +0800980 setbits_le32(&s_regs->lp_handshake[0], BIT(6));
981
Ye Li0667ec92024-09-19 12:01:20 +0800982 /* OSCCA enabled, reconfigure TRDC for TCM access, otherwise ECC init will raise error */
983 val = readl(BLK_CTRL_NS_ANOMIX_BASE_ADDR + 0x28);
984 if (val & BIT(0)) {
985 trdc_mbc_set_control(0x44270000, 1, 0, 0x6600);
986
987 for (i = 0; i < 32; i++)
988 trdc_mbc_blk_config(0x44270000, 1, 3, 0, i, true, 0);
989
990 for (i = 0; i < 32; i++)
991 trdc_mbc_blk_config(0x44270000, 1, 3, 1, i, true, 0);
992 }
993
Peng Fan6d929962022-07-26 16:41:03 +0800994 /* Clear M33 TCM for ECC */
995 memset((void *)(ulong)0x201e0000, 0, 0x40000);
996
997 return 0;
998}
Peng Fanb1815c42023-04-28 12:08:27 +0800999
1000int psci_sysreset_get_status(struct udevice *dev, char *buf, int size)
1001{
1002 static const char *reset_cause[] = {
1003 "POR ",
1004 "JTAG ",
1005 "IPP USER ",
1006 "WDOG1 ",
1007 "WDOG2 ",
1008 "WDOG3 ",
1009 "WDOG4 ",
1010 "WDOG5 ",
1011 "TEMPSENSE ",
1012 "CSU ",
1013 "JTAG_SW ",
1014 "M33_REQ ",
1015 "M33_LOCKUP ",
1016 "UNK ",
1017 "UNK ",
1018 "UNK "
1019 };
1020
1021 struct src_general_regs *src = (struct src_general_regs *)SRC_GLOBAL_RBASE;
1022 u32 srsr;
1023 u32 i;
1024 int res;
1025
1026 srsr = readl(&src->gpr[0]);
1027
1028 for (i = ARRAY_SIZE(reset_cause); i > 0; i--) {
1029 if (srsr & (BIT(i - 1)))
1030 break;
1031 }
1032
1033 res = snprintf(buf, size, "Reset Status: %s\n", i ? reset_cause[i - 1] : "unknown reset");
1034 if (res < 0) {
1035 dev_err(dev, "Could not write reset status message (err = %d)\n", res);
1036 return -EIO;
1037 }
1038
1039 return 0;
1040}
Ye Li7b248152024-09-19 12:01:26 +08001041
1042enum imx9_soc_voltage_mode soc_target_voltage_mode(void)
1043{
1044 u32 speed = get_cpu_speed_grade_hz();
1045 enum imx9_soc_voltage_mode voltage = VOLT_OVER_DRIVE;
1046
Peng Fan0ce300f2024-12-03 23:42:48 +08001047 if (is_imx93() || is_imx91()) {
Ye Li7b248152024-09-19 12:01:26 +08001048 if (speed == 1700000000)
1049 voltage = VOLT_OVER_DRIVE;
1050 else if (speed == 1400000000)
1051 voltage = VOLT_NOMINAL_DRIVE;
1052 else if (speed == 900000000 || speed == 800000000)
1053 voltage = VOLT_LOW_DRIVE;
1054 else
1055 printf("Unexpected A55 freq %u, default to OD\n", speed);
1056 }
1057
1058 return voltage;
1059}