blob: 52aafcbf99c7f0e42fdc6b54ccbb6197b0c60eea [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
45#ifdef CONFIG_ENV_IS_IN_MMC
46__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
51int mmc_get_env_dev(void)
52{
Peng Fan5de0fc02022-07-26 16:40:48 +080053 int ret;
54 u32 boot;
55 u16 boot_type;
56 u8 boot_instance;
57
Peng Fanc459b582023-04-28 12:08:34 +080058 ret = rom_api_query_boot_infor(QUERY_BT_DEV, &boot);
Peng Fan5de0fc02022-07-26 16:40:48 +080059
60 if (ret != ROM_API_OKAY) {
61 puts("ROMAPI: failure at query_boot_info\n");
62 return CONFIG_SYS_MMC_ENV_DEV;
63 }
64
65 boot_type = boot >> 16;
66 boot_instance = (boot >> 8) & 0xff;
67
68 debug("boot_type %d, instance %d\n", boot_type, boot_instance);
69
70 /* If not boot from sd/mmc, use default value */
71 if (boot_type != BOOT_TYPE_SD && boot_type != BOOT_TYPE_MMC)
72 return env_get_ulong("mmcdev", 10, CONFIG_SYS_MMC_ENV_DEV);
73
74 return board_mmc_get_env_dev(boot_instance);
75}
76#endif
77
Peng Fan0c2f3682023-04-28 12:08:28 +080078/*
79 * SPEED_GRADE[5:4] SPEED_GRADE[3:0] MHz
80 * xx 0000 2300
81 * xx 0001 2200
82 * xx 0010 2100
83 * xx 0011 2000
84 * xx 0100 1900
85 * xx 0101 1800
86 * xx 0110 1700
87 * xx 0111 1600
88 * xx 1000 1500
89 * xx 1001 1400
90 * xx 1010 1300
91 * xx 1011 1200
92 * xx 1100 1100
93 * xx 1101 1000
94 * xx 1110 900
95 * xx 1111 800
96 */
97u32 get_cpu_speed_grade_hz(void)
98{
Peng Fan43126e12024-09-19 12:01:23 +080099 int ret;
100 u32 bank, word, speed, max_speed;
Peng Fan0c2f3682023-04-28 12:08:28 +0800101 u32 val;
102
Peng Fan43126e12024-09-19 12:01:23 +0800103 bank = HW_CFG1 / NUM_WORDS_PER_BANK;
104 word = HW_CFG1 % NUM_WORDS_PER_BANK;
105 ret = fuse_read(bank, word, &val);
106 if (ret)
107 val = 0; /* If read fuse failed, return as blank fuse */
108
Peng Fan0c2f3682023-04-28 12:08:28 +0800109 val = FIELD_GET(SPEED_GRADING_MASK, val) & 0xF;
110
111 speed = MHZ(2300) - val * MHZ(100);
112
113 if (is_imx93())
114 max_speed = MHZ(1700);
115
116 /* In case the fuse of speed grade not programmed */
117 if (speed > max_speed)
118 speed = max_speed;
119
120 return speed;
121}
122
123/*
124 * `00` - Consumer 0C to 95C
125 * `01` - Ext. Consumer -20C to 105C
126 * `10` - Industrial -40C to 105C
127 * `11` - Automotive -40C to 125C
128 */
129u32 get_cpu_temp_grade(int *minc, int *maxc)
130{
Peng Fan43126e12024-09-19 12:01:23 +0800131 int ret;
132 u32 bank, word, val;
133
134 bank = HW_CFG1 / NUM_WORDS_PER_BANK;
135 word = HW_CFG1 % NUM_WORDS_PER_BANK;
136 ret = fuse_read(bank, word, &val);
137 if (ret)
138 val = 0; /* If read fuse failed, return as blank fuse */
Peng Fan0c2f3682023-04-28 12:08:28 +0800139
Peng Fan0c2f3682023-04-28 12:08:28 +0800140 val = FIELD_GET(MARKETING_GRADING_MASK, val);
141
142 if (minc && maxc) {
143 if (val == TEMP_AUTOMOTIVE) {
144 *minc = -40;
145 *maxc = 125;
146 } else if (val == TEMP_INDUSTRIAL) {
147 *minc = -40;
148 *maxc = 105;
149 } else if (val == TEMP_EXTCOMMERCIAL) {
150 if (is_imx93()) {
151 /* imx93 only has extended industrial*/
152 *minc = -40;
153 *maxc = 125;
154 } else {
155 *minc = -20;
156 *maxc = 105;
157 }
158 } else {
159 *minc = 0;
160 *maxc = 95;
161 }
162 }
163 return val;
164}
165
Peng Fand5c31832023-06-15 18:09:05 +0800166static void set_cpu_info(struct ele_get_info_data *info)
Peng Fan3700c472022-07-26 16:40:56 +0800167{
168 gd->arch.soc_rev = info->soc;
169 gd->arch.lifecycle = info->lc;
170 memcpy((void *)&gd->arch.uid, &info->uid, 4 * sizeof(u32));
171}
172
Peng Fanc3db3ad2023-04-28 12:08:32 +0800173static u32 get_cpu_variant_type(u32 type)
174{
Peng Fan43126e12024-09-19 12:01:23 +0800175 u32 bank, word, val, val2;
176 int ret;
177
178 bank = HW_CFG1 / NUM_WORDS_PER_BANK;
179 word = HW_CFG1 % NUM_WORDS_PER_BANK;
180 ret = fuse_read(bank, word, &val);
181 if (ret)
182 val = 0; /* If read fuse failed, return as blank fuse */
183
184 bank = HW_CFG2 / NUM_WORDS_PER_BANK;
185 word = HW_CFG2 % NUM_WORDS_PER_BANK;
186 ret = fuse_read(bank, word, &val2);
187 if (ret)
188 val2 = 0; /* If read fuse failed, return as blank fuse */
189
Peng Fanc3db3ad2023-04-28 12:08:32 +0800190 bool npu_disable = !!(val & BIT(13));
191 bool core1_disable = !!(val & BIT(15));
192 u32 pack_9x9_fused = BIT(4) | BIT(17) | BIT(19) | BIT(24);
193
194 if ((val2 & pack_9x9_fused) == pack_9x9_fused)
195 type = MXC_CPU_IMX9322;
196
197 if (npu_disable && core1_disable)
198 return type + 3;
199 else if (npu_disable)
200 return type + 2;
201 else if (core1_disable)
202 return type + 1;
203
204 return type;
205}
206
Peng Fanbbcd2c42022-07-26 16:40:39 +0800207u32 get_cpu_rev(void)
208{
Peng Fan3700c472022-07-26 16:40:56 +0800209 u32 rev = (gd->arch.soc_rev >> 24) - 0xa0;
210
Peng Fanc3db3ad2023-04-28 12:08:32 +0800211 return (get_cpu_variant_type(MXC_CPU_IMX93) << 12) |
212 (CHIP_REV_1_0 + rev);
Peng Fanbbcd2c42022-07-26 16:40:39 +0800213}
214
Ye Li9e19ff92022-07-26 16:40:47 +0800215#define UNLOCK_WORD 0xD928C520 /* unlock word */
216#define REFRESH_WORD 0xB480A602 /* refresh word */
217
218static void disable_wdog(void __iomem *wdog_base)
219{
220 u32 val_cs = readl(wdog_base + 0x00);
221
222 if (!(val_cs & 0x80))
223 return;
224
225 /* default is 32bits cmd */
226 writel(REFRESH_WORD, (wdog_base + 0x04)); /* Refresh the CNT */
227
228 if (!(val_cs & 0x800)) {
229 writel(UNLOCK_WORD, (wdog_base + 0x04));
230 while (!(readl(wdog_base + 0x00) & 0x800))
231 ;
232 }
233 writel(0x0, (wdog_base + 0x0C)); /* Set WIN to 0 */
234 writel(0x400, (wdog_base + 0x08)); /* Set timeout to default 0x400 */
235 writel(0x2120, (wdog_base + 0x00)); /* Disable it and set update */
236
237 while (!(readl(wdog_base + 0x00) & 0x400))
238 ;
239}
240
241void init_wdog(void)
242{
243 u32 src_val;
244
245 disable_wdog((void __iomem *)WDG3_BASE_ADDR);
246 disable_wdog((void __iomem *)WDG4_BASE_ADDR);
247 disable_wdog((void __iomem *)WDG5_BASE_ADDR);
248
249 src_val = readl(0x54460018); /* reset mask */
250 src_val &= ~0x1c;
251 writel(src_val, 0x54460018);
252}
253
Peng Fanbbcd2c42022-07-26 16:40:39 +0800254static struct mm_region imx93_mem_map[] = {
255 {
256 /* ROM */
257 .virt = 0x0UL,
258 .phys = 0x0UL,
259 .size = 0x100000UL,
260 .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
261 PTE_BLOCK_OUTER_SHARE
262 }, {
Peng Fan313af252022-07-26 16:41:04 +0800263 /* TCM */
264 .virt = 0x201c0000UL,
265 .phys = 0x201c0000UL,
266 .size = 0x80000UL,
267 .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
268 PTE_BLOCK_NON_SHARE |
269 PTE_BLOCK_PXN | PTE_BLOCK_UXN
270 }, {
Peng Fanbbcd2c42022-07-26 16:40:39 +0800271 /* OCRAM */
272 .virt = 0x20480000UL,
273 .phys = 0x20480000UL,
274 .size = 0xA0000UL,
275 .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
276 PTE_BLOCK_OUTER_SHARE
277 }, {
278 /* AIPS */
279 .virt = 0x40000000UL,
280 .phys = 0x40000000UL,
281 .size = 0x40000000UL,
282 .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
283 PTE_BLOCK_NON_SHARE |
284 PTE_BLOCK_PXN | PTE_BLOCK_UXN
285 }, {
286 /* Flexible Serial Peripheral Interface */
287 .virt = 0x28000000UL,
288 .phys = 0x28000000UL,
Ye Li35f15512024-03-28 18:49:18 +0800289 .size = 0x08000000UL,
Peng Fanbbcd2c42022-07-26 16:40:39 +0800290 .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
291 PTE_BLOCK_NON_SHARE |
292 PTE_BLOCK_PXN | PTE_BLOCK_UXN
293 }, {
294 /* DRAM1 */
295 .virt = 0x80000000UL,
296 .phys = 0x80000000UL,
297 .size = PHYS_SDRAM_SIZE,
298 .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
299 PTE_BLOCK_OUTER_SHARE
300 }, {
301 /* empty entrie to split table entry 5 if needed when TEEs are used */
302 0,
303 }, {
304 /* List terminator */
305 0,
306 }
307};
308
309struct mm_region *mem_map = imx93_mem_map;
310
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800311static unsigned int imx9_find_dram_entry_in_mem_map(void)
312{
313 int i;
314
315 for (i = 0; i < ARRAY_SIZE(imx93_mem_map); i++)
316 if (imx93_mem_map[i].phys == CFG_SYS_SDRAM_BASE)
317 return i;
318
319 hang(); /* Entry not found, this must never happen. */
320}
321
322void enable_caches(void)
323{
324 /* If OPTEE runs, remove OPTEE memory from MMU table to avoid speculative prefetch
325 * If OPTEE does not run, still update the MMU table according to dram banks structure
326 * to set correct dram size from board_phys_sdram_size
327 */
328 int i = 0;
329 /*
330 * please make sure that entry initial value matches
331 * imx93_mem_map for DRAM1
332 */
333 int entry = imx9_find_dram_entry_in_mem_map();
334 u64 attrs = imx93_mem_map[entry].attrs;
335
336 while (i < CONFIG_NR_DRAM_BANKS &&
337 entry < ARRAY_SIZE(imx93_mem_map)) {
338 if (gd->bd->bi_dram[i].start == 0)
339 break;
340 imx93_mem_map[entry].phys = gd->bd->bi_dram[i].start;
341 imx93_mem_map[entry].virt = gd->bd->bi_dram[i].start;
342 imx93_mem_map[entry].size = gd->bd->bi_dram[i].size;
343 imx93_mem_map[entry].attrs = attrs;
344 debug("Added memory mapping (%d): %llx %llx\n", entry,
345 imx93_mem_map[entry].phys, imx93_mem_map[entry].size);
346 i++; entry++;
347 }
348
349 icache_enable();
350 dcache_enable();
351}
352
353__weak int board_phys_sdram_size(phys_size_t *size)
354{
Ye Libb1187b2023-04-28 12:08:45 +0800355 phys_size_t start, end;
356 phys_size_t val;
357
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800358 if (!size)
359 return -EINVAL;
360
Ye Libb1187b2023-04-28 12:08:45 +0800361 val = readl(REG_DDR_CS0_BNDS);
362 start = (val >> 16) << 24;
363 end = (val & 0xFFFF);
364 end = end ? end + 1 : 0;
365 end = end << 24;
366 *size = end - start;
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800367
Ye Libb1187b2023-04-28 12:08:45 +0800368 val = readl(REG_DDR_CS1_BNDS);
369 start = (val >> 16) << 24;
370 end = (val & 0xFFFF);
371 end = end ? end + 1 : 0;
372 end = end << 24;
373 *size += end - start;
374
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800375 return 0;
376}
377
Peng Fanbbcd2c42022-07-26 16:40:39 +0800378int dram_init(void)
379{
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800380 phys_size_t sdram_size;
381 int ret;
382
383 ret = board_phys_sdram_size(&sdram_size);
384 if (ret)
385 return ret;
386
387 /* rom_pointer[1] contains the size of TEE occupies */
Elena Popa65c9edb2023-08-08 14:58:26 +0300388 if (!IS_ENABLED(CONFIG_SPL_BUILD) && rom_pointer[1])
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800389 gd->ram_size = sdram_size - rom_pointer[1];
390 else
391 gd->ram_size = sdram_size;
392
393 return 0;
394}
395
396int dram_init_banksize(void)
397{
398 int bank = 0;
399 int ret;
400 phys_size_t sdram_size;
401 phys_size_t sdram_b1_size, sdram_b2_size;
402
403 ret = board_phys_sdram_size(&sdram_size);
404 if (ret)
405 return ret;
406
407 /* Bank 1 can't cross over 4GB space */
408 if (sdram_size > 0x80000000) {
409 sdram_b1_size = 0x80000000;
410 sdram_b2_size = sdram_size - 0x80000000;
411 } else {
412 sdram_b1_size = sdram_size;
413 sdram_b2_size = 0;
414 }
415
416 gd->bd->bi_dram[bank].start = PHYS_SDRAM;
Elena Popa65c9edb2023-08-08 14:58:26 +0300417 if (!IS_ENABLED(CONFIG_SPL_BUILD) && rom_pointer[1]) {
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800418 phys_addr_t optee_start = (phys_addr_t)rom_pointer[0];
419 phys_size_t optee_size = (size_t)rom_pointer[1];
420
421 gd->bd->bi_dram[bank].size = optee_start - gd->bd->bi_dram[bank].start;
422 if ((optee_start + optee_size) < (PHYS_SDRAM + sdram_b1_size)) {
423 if (++bank >= CONFIG_NR_DRAM_BANKS) {
424 puts("CONFIG_NR_DRAM_BANKS is not enough\n");
425 return -1;
426 }
427
428 gd->bd->bi_dram[bank].start = optee_start + optee_size;
429 gd->bd->bi_dram[bank].size = PHYS_SDRAM +
430 sdram_b1_size - gd->bd->bi_dram[bank].start;
431 }
432 } else {
433 gd->bd->bi_dram[bank].size = sdram_b1_size;
434 }
435
436 if (sdram_b2_size) {
437 if (++bank >= CONFIG_NR_DRAM_BANKS) {
438 puts("CONFIG_NR_DRAM_BANKS is not enough for SDRAM_2\n");
439 return -1;
440 }
441 gd->bd->bi_dram[bank].start = 0x100000000UL;
442 gd->bd->bi_dram[bank].size = sdram_b2_size;
443 }
Peng Fanbbcd2c42022-07-26 16:40:39 +0800444
445 return 0;
446}
447
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800448phys_size_t get_effective_memsize(void)
449{
450 int ret;
451 phys_size_t sdram_size;
452 phys_size_t sdram_b1_size;
453
454 ret = board_phys_sdram_size(&sdram_size);
455 if (!ret) {
456 /* Bank 1 can't cross over 4GB space */
457 if (sdram_size > 0x80000000)
458 sdram_b1_size = 0x80000000;
459 else
460 sdram_b1_size = sdram_size;
461
Elena Popa65c9edb2023-08-08 14:58:26 +0300462 if (!IS_ENABLED(CONFIG_SPL_BUILD) && rom_pointer[1]) {
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800463 /* We will relocate u-boot to top of dram1. TEE position has two cases:
464 * 1. At the top of dram1, Then return the size removed optee size.
465 * 2. In the middle of dram1, return the size of dram1.
466 */
467 if ((rom_pointer[0] + rom_pointer[1]) == (PHYS_SDRAM + sdram_b1_size))
468 return ((phys_addr_t)rom_pointer[0] - PHYS_SDRAM);
469 }
470
471 return sdram_b1_size;
472 } else {
473 return PHYS_SDRAM_SIZE;
474 }
475}
476
Peng Fanbbcd2c42022-07-26 16:40:39 +0800477void imx_get_mac_from_fuse(int dev_id, unsigned char *mac)
478{
Ye Li66baefb2023-04-28 12:08:21 +0800479 u32 val[2] = {};
480 int ret;
481
482 if (dev_id == 0) {
483 ret = fuse_read(39, 3, &val[0]);
484 if (ret)
485 goto err;
486
487 ret = fuse_read(39, 4, &val[1]);
488 if (ret)
489 goto err;
490
491 mac[0] = val[1] >> 8;
492 mac[1] = val[1];
493 mac[2] = val[0] >> 24;
494 mac[3] = val[0] >> 16;
495 mac[4] = val[0] >> 8;
496 mac[5] = val[0];
497
498 } else {
499 ret = fuse_read(39, 5, &val[0]);
500 if (ret)
501 goto err;
502
503 ret = fuse_read(39, 4, &val[1]);
504 if (ret)
505 goto err;
506
Ye Liae9b7022024-09-19 12:01:24 +0800507 if (is_imx93() && is_soc_rev(CHIP_REV_1_0)) {
508 mac[0] = val[1] >> 24;
509 mac[1] = val[1] >> 16;
510 mac[2] = val[0] >> 24;
511 mac[3] = val[0] >> 16;
512 mac[4] = val[0] >> 8;
513 mac[5] = val[0];
514 } else {
515 mac[0] = val[0] >> 24;
516 mac[1] = val[0] >> 16;
517 mac[2] = val[0] >> 8;
518 mac[3] = val[0];
519 mac[4] = val[1] >> 24;
520 mac[5] = val[1] >> 16;
521 }
Ye Li66baefb2023-04-28 12:08:21 +0800522 }
523
524 debug("%s: MAC%d: %02x.%02x.%02x.%02x.%02x.%02x\n",
525 __func__, dev_id, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
526 return;
527err:
528 memset(mac, 0, 6);
529 printf("%s: fuse read err: %d\n", __func__, ret);
Peng Fanbbcd2c42022-07-26 16:40:39 +0800530}
531
532int print_cpuinfo(void)
533{
534 u32 cpurev;
535
536 cpurev = get_cpu_rev();
537
538 printf("CPU: i.MX93 rev%d.%d\n", (cpurev & 0x000F0) >> 4, (cpurev & 0x0000F) >> 0);
539
540 return 0;
541}
542
Primoz Fiserebbd4fc2024-01-11 13:56:25 +0100543static int fixup_thermal_trips(void *blob, const char *name)
544{
545 int minc, maxc;
546 int node, trip;
547
548 node = fdt_path_offset(blob, "/thermal-zones");
549 if (node < 0)
550 return node;
551
552 node = fdt_subnode_offset(blob, node, name);
553 if (node < 0)
554 return node;
555
556 node = fdt_subnode_offset(blob, node, "trips");
557 if (node < 0)
558 return node;
559
560 get_cpu_temp_grade(&minc, &maxc);
561
562 fdt_for_each_subnode(trip, blob, node) {
563 const char *type;
564 int temp, ret;
565
566 type = fdt_getprop(blob, trip, "type", NULL);
567 if (!type)
568 continue;
569
570 temp = 0;
571 if (!strcmp(type, "critical"))
Primoz Fiserab813e12024-08-13 14:12:17 +0200572 temp = 1000 * maxc;
Primoz Fiserebbd4fc2024-01-11 13:56:25 +0100573 else if (!strcmp(type, "passive"))
574 temp = 1000 * (maxc - 10);
575 if (temp) {
576 ret = fdt_setprop_u32(blob, trip, "temperature", temp);
577 if (ret)
578 return ret;
579 }
580 }
581
582 return 0;
583}
584
Peng Fan1a17ae82024-09-19 12:01:25 +0800585void build_info(void)
586{
587 u32 fw_version, sha1, res, status;
588 int ret;
589
590 printf("\nBuildInfo:\n");
591
592 ret = ele_get_fw_status(&status, &res);
593 if (ret) {
594 printf(" - ELE firmware status failed %d, 0x%x\n", ret, res);
595 } else if ((status & 0xff) == 1) {
596 ret = ele_get_fw_version(&fw_version, &sha1, &res);
597 if (ret) {
598 printf(" - ELE firmware version failed %d, 0x%x\n", ret, res);
599 } else {
600 printf(" - ELE firmware version %u.%u.%u-%x",
601 (fw_version & (0x00ff0000)) >> 16,
602 (fw_version & (0x0000fff0)) >> 4,
603 (fw_version & (0x0000000f)), sha1);
604 ((fw_version & (0x80000000)) >> 31) == 1 ? puts("-dirty\n") : puts("\n");
605 }
606 } else {
607 printf(" - ELE firmware not included\n");
608 }
609 puts("\n");
610}
611
612int arch_misc_init(void)
613{
614 build_info();
615 return 0;
616}
617
Ye Li7b248152024-09-19 12:01:26 +0800618struct low_drive_freq_entry {
619 const char *node_path;
620 u32 clk;
621 u32 new_rate;
622};
623
624static int low_drive_fdt_fix_clock(void *fdt, int node_off, u32 clk_index, u32 new_rate)
625{
626#define MAX_ASSIGNED_CLKS 8
627 int cnt, j;
628 u32 assignedclks[MAX_ASSIGNED_CLKS]; /* max 8 clocks*/
629
630 cnt = fdtdec_get_int_array_count(fdt, node_off, "assigned-clock-rates",
631 assignedclks, MAX_ASSIGNED_CLKS);
632 if (cnt > 0) {
633 if (cnt <= clk_index)
634 return -ENOENT;
635
636 if (assignedclks[clk_index] <= new_rate)
637 return 0;
638
639 assignedclks[clk_index] = new_rate;
640 for (j = 0; j < cnt; j++)
641 assignedclks[j] = cpu_to_fdt32(assignedclks[j]);
642
643 return fdt_setprop(fdt, node_off, "assigned-clock-rates", &assignedclks,
644 cnt * sizeof(u32));
645 }
646
647 return -ENOENT;
648}
649
650static int low_drive_freq_update(void *blob)
651{
652 int nodeoff, ret;
653 int i;
654
655 /* Update kernel dtb clocks for low drive mode */
656 struct low_drive_freq_entry table[] = {
657 {"/soc@0/bus@42800000/mmc@42850000", 0, 266666667},
658 {"/soc@0/bus@42800000/mmc@42860000", 0, 266666667},
659 {"/soc@0/bus@42800000/mmc@428b0000", 0, 266666667},
660 };
661
662 for (i = 0; i < ARRAY_SIZE(table); i++) {
663 nodeoff = fdt_path_offset(blob, table[i].node_path);
664 if (nodeoff >= 0) {
665 ret = low_drive_fdt_fix_clock(blob, nodeoff, table[i].clk,
666 table[i].new_rate);
667 if (!ret)
668 printf("%s freq updated\n", table[i].node_path);
669 }
670 }
671
672 return 0;
673}
674
675#ifdef CONFIG_OF_BOARD_FIXUP
676#ifndef CONFIG_SPL_BUILD
677int board_fix_fdt(void *fdt)
678{
679 /* Update dtb clocks for low drive mode */
680 if (is_voltage_mode(VOLT_LOW_DRIVE)) {
681 int nodeoff;
682 int i;
683
684 struct low_drive_freq_entry table[] = {
685 {"/soc@0/bus@42800000/mmc@42850000", 0, 266666667},
686 {"/soc@0/bus@42800000/mmc@42860000", 0, 266666667},
687 {"/soc@0/bus@42800000/mmc@428b0000", 0, 266666667},
688 };
689
690 for (i = 0; i < ARRAY_SIZE(table); i++) {
691 nodeoff = fdt_path_offset(fdt, table[i].node_path);
692 if (nodeoff >= 0)
693 low_drive_fdt_fix_clock(fdt, nodeoff, table[i].clk,
694 table[i].new_rate);
695 }
696 }
697
698 return 0;
699}
700#endif
701#endif
702
Peng Fanbbcd2c42022-07-26 16:40:39 +0800703int ft_system_setup(void *blob, struct bd_info *bd)
704{
Primoz Fiserebbd4fc2024-01-11 13:56:25 +0100705 if (fixup_thermal_trips(blob, "cpu-thermal"))
706 printf("Failed to update cpu-thermal trip(s)");
707
Ye Li7b248152024-09-19 12:01:26 +0800708 if (is_voltage_mode(VOLT_LOW_DRIVE))
709 low_drive_freq_update(blob);
710
Peng Fanbbcd2c42022-07-26 16:40:39 +0800711 return 0;
712}
Peng Fan3700c472022-07-26 16:40:56 +0800713
714#if defined(CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG)
715void get_board_serial(struct tag_serialnr *serialnr)
716{
Ye Li8a7f6ef2024-09-19 12:01:22 +0800717 printf("UID: %08x%08x%08x%08x\n", __be32_to_cpu(gd->arch.uid[0]),
718 __be32_to_cpu(gd->arch.uid[1]), __be32_to_cpu(gd->arch.uid[2]),
719 __be32_to_cpu(gd->arch.uid[3]));
Peng Fan3700c472022-07-26 16:40:56 +0800720
Frank Li52b93ea2024-09-19 12:01:21 +0800721 serialnr->low = __be32_to_cpu(gd->arch.uid[1]);
722 serialnr->high = __be32_to_cpu(gd->arch.uid[0]);
Peng Fan3700c472022-07-26 16:40:56 +0800723}
724#endif
Peng Fanbbcd2c42022-07-26 16:40:39 +0800725
Peng Fanb1815c42023-04-28 12:08:27 +0800726static void save_reset_cause(void)
727{
728 struct src_general_regs *src = (struct src_general_regs *)SRC_GLOBAL_RBASE;
729 u32 srsr = readl(&src->srsr);
730
731 /* clear srsr in sec mode */
732 writel(srsr, &src->srsr);
733
734 /* Save value to GPR1 to pass to nonsecure */
735 writel(srsr, &src->gpr[0]);
736}
737
Peng Fanbbcd2c42022-07-26 16:40:39 +0800738int arch_cpu_init(void)
739{
Ye Li9e19ff92022-07-26 16:40:47 +0800740 if (IS_ENABLED(CONFIG_SPL_BUILD)) {
741 /* Disable wdog */
742 init_wdog();
743
Peng Fan28b5cb52022-07-26 16:40:43 +0800744 clock_init();
Ye Li62185922022-07-26 16:40:54 +0800745
746 trdc_early_init();
Peng Fanb1815c42023-04-28 12:08:27 +0800747
748 /* Save SRC SRSR to GPR1 and clear it */
749 save_reset_cause();
Ye Li9e19ff92022-07-26 16:40:47 +0800750 }
Peng Fan28b5cb52022-07-26 16:40:43 +0800751
Peng Fanbbcd2c42022-07-26 16:40:39 +0800752 return 0;
753}
Peng Fan3700c472022-07-26 16:40:56 +0800754
Simon Glassb8357c12023-08-21 21:16:56 -0600755int imx9_probe_mu(void)
Peng Fan3700c472022-07-26 16:40:56 +0800756{
757 struct udevice *devp;
758 int node, ret;
759 u32 res;
Peng Fand5c31832023-06-15 18:09:05 +0800760 struct ele_get_info_data info;
Peng Fan3700c472022-07-26 16:40:56 +0800761
762 node = fdt_node_offset_by_compatible(gd->fdt_blob, -1, "fsl,imx93-mu-s4");
763
764 ret = uclass_get_device_by_of_offset(UCLASS_MISC, node, &devp);
765 if (ret)
766 return ret;
767
768 if (gd->flags & GD_FLG_RELOC)
769 return 0;
770
Peng Fand5c31832023-06-15 18:09:05 +0800771 ret = ele_get_info(&info, &res);
Peng Fan3700c472022-07-26 16:40:56 +0800772 if (ret)
773 return ret;
774
775 set_cpu_info(&info);
776
777 return 0;
778}
Simon Glassb8357c12023-08-21 21:16:56 -0600779EVENT_SPY_SIMPLE(EVT_DM_POST_INIT_F, imx9_probe_mu);
Ye Lif41ffc12024-04-01 09:41:09 +0800780EVENT_SPY_SIMPLE(EVT_DM_POST_INIT_R, imx9_probe_mu);
Jian Liacf41a32022-07-26 16:40:46 +0800781
782int timer_init(void)
783{
784#ifdef CONFIG_SPL_BUILD
785 struct sctr_regs *sctr = (struct sctr_regs *)SYSCNT_CTRL_BASE_ADDR;
786 unsigned long freq = readl(&sctr->cntfid0);
787
788 /* Update with accurate clock frequency */
789 asm volatile("msr cntfrq_el0, %0" : : "r" (freq) : "memory");
790
791 clrsetbits_le32(&sctr->cntcr, SC_CNTCR_FREQ0 | SC_CNTCR_FREQ1,
792 SC_CNTCR_FREQ0 | SC_CNTCR_ENABLE | SC_CNTCR_HDBG);
793#endif
794
795 gd->arch.tbl = 0;
796 gd->arch.tbu = 0;
797
798 return 0;
799}
Peng Fan65563792022-07-26 16:41:02 +0800800
Ye Li8e8687c2022-07-26 16:41:05 +0800801enum env_location env_get_location(enum env_operation op, int prio)
802{
803 enum boot_device dev = get_boot_device();
Ye Li8e8687c2022-07-26 16:41:05 +0800804
805 if (prio)
Oleksandr Suvoroveff7c8d2023-04-11 20:27:41 +0300806 return ENVL_UNKNOWN;
Ye Li8e8687c2022-07-26 16:41:05 +0800807
808 switch (dev) {
Ye Li8e8687c2022-07-26 16:41:05 +0800809 case QSPI_BOOT:
Oleksandr Suvoroveff7c8d2023-04-11 20:27:41 +0300810 if (CONFIG_IS_ENABLED(ENV_IS_IN_SPI_FLASH))
811 return ENVL_SPI_FLASH;
812 return ENVL_NOWHERE;
Ye Li8e8687c2022-07-26 16:41:05 +0800813 case SD1_BOOT:
814 case SD2_BOOT:
815 case SD3_BOOT:
816 case MMC1_BOOT:
817 case MMC2_BOOT:
818 case MMC3_BOOT:
Oleksandr Suvoroveff7c8d2023-04-11 20:27:41 +0300819 if (CONFIG_IS_ENABLED(ENV_IS_IN_MMC))
820 return ENVL_MMC;
821 else if (CONFIG_IS_ENABLED(ENV_IS_IN_EXT4))
822 return ENVL_EXT4;
823 else if (CONFIG_IS_ENABLED(ENV_IS_IN_FAT))
824 return ENVL_FAT;
825 return ENVL_NOWHERE;
Ye Li8e8687c2022-07-26 16:41:05 +0800826 default:
Oleksandr Suvoroveff7c8d2023-04-11 20:27:41 +0300827 return ENVL_NOWHERE;
Ye Li8e8687c2022-07-26 16:41:05 +0800828 }
Ye Li8e8687c2022-07-26 16:41:05 +0800829}
830
Peng Fan65563792022-07-26 16:41:02 +0800831static int mix_power_init(enum mix_power_domain pd)
832{
833 enum src_mix_slice_id mix_id;
834 enum src_mem_slice_id mem_id;
835 struct src_mix_slice_regs *mix_regs;
836 struct src_mem_slice_regs *mem_regs;
837 struct src_general_regs *global_regs;
838 u32 scr, val;
839
840 switch (pd) {
841 case MIX_PD_MEDIAMIX:
842 mix_id = SRC_MIX_MEDIA;
843 mem_id = SRC_MEM_MEDIA;
844 scr = BIT(5);
845
Peng Fand5c31832023-06-15 18:09:05 +0800846 /* Enable ELE handshake */
Peng Fan65563792022-07-26 16:41:02 +0800847 struct blk_ctrl_s_aonmix_regs *s_regs =
848 (struct blk_ctrl_s_aonmix_regs *)BLK_CTRL_S_ANOMIX_BASE_ADDR;
849
850 setbits_le32(&s_regs->lp_handshake[0], BIT(13));
851 break;
852 case MIX_PD_MLMIX:
853 mix_id = SRC_MIX_ML;
854 mem_id = SRC_MEM_ML;
855 scr = BIT(4);
856 break;
857 case MIX_PD_DDRMIX:
858 mix_id = SRC_MIX_DDRMIX;
859 mem_id = SRC_MEM_DDRMIX;
860 scr = BIT(6);
861 break;
862 default:
863 return -EINVAL;
864 }
865
866 mix_regs = (struct src_mix_slice_regs *)(ulong)(SRC_IPS_BASE_ADDR + 0x400 * (mix_id + 1));
867 mem_regs =
868 (struct src_mem_slice_regs *)(ulong)(SRC_IPS_BASE_ADDR + 0x3800 + 0x400 * mem_id);
869 global_regs = (struct src_general_regs *)(ulong)SRC_GLOBAL_RBASE;
870
871 /* Allow NS to set it */
872 setbits_le32(&mix_regs->authen_ctrl, BIT(9));
873
874 clrsetbits_le32(&mix_regs->psw_ack_ctrl[0], BIT(28), BIT(29));
875
876 /* mix reset will be held until boot core write this bit to 1 */
877 setbits_le32(&global_regs->scr, scr);
878
879 /* Enable mem in Low power auto sequence */
880 setbits_le32(&mem_regs->mem_ctrl, BIT(2));
881
882 /* Set the power down state */
883 val = readl(&mix_regs->func_stat);
884 if (val & SRC_MIX_SLICE_FUNC_STAT_PSW_STAT) {
885 /* The mix is default power off, power down it to make PDN_SFT bit
886 * aligned with FUNC STAT
887 */
888 setbits_le32(&mix_regs->slice_sw_ctrl, BIT(31));
889 val = readl(&mix_regs->func_stat);
890
891 /* Since PSW_STAT is 1, can't be used for power off status (SW_CTRL BIT31 set)) */
892 /* Check the MEM STAT change to ensure SSAR is completed */
893 while (!(val & SRC_MIX_SLICE_FUNC_STAT_MEM_STAT))
894 val = readl(&mix_regs->func_stat);
895
896 /* wait few ipg clock cycles to ensure FSM done and power off status is correct */
897 /* About 5 cycles at 24Mhz, 1us is enough */
898 udelay(1);
899 } else {
900 /* The mix is default power on, Do mix power cycle */
901 setbits_le32(&mix_regs->slice_sw_ctrl, BIT(31));
902 val = readl(&mix_regs->func_stat);
903 while (!(val & SRC_MIX_SLICE_FUNC_STAT_PSW_STAT))
904 val = readl(&mix_regs->func_stat);
905 }
906
907 /* power on */
908 clrbits_le32(&mix_regs->slice_sw_ctrl, BIT(31));
909 val = readl(&mix_regs->func_stat);
Peng Fan06e78ff2024-09-19 12:01:19 +0800910 while (val & SRC_MIX_SLICE_FUNC_STAT_SSAR_STAT)
Peng Fan65563792022-07-26 16:41:02 +0800911 val = readl(&mix_regs->func_stat);
912
913 return 0;
914}
915
916void disable_isolation(void)
917{
918 struct src_general_regs *global_regs = (struct src_general_regs *)(ulong)SRC_GLOBAL_RBASE;
919 /* clear isolation for usbphy, dsi, csi*/
920 writel(0x0, &global_regs->sp_iso_ctrl);
921}
922
923void soc_power_init(void)
924{
925 mix_power_init(MIX_PD_MEDIAMIX);
926 mix_power_init(MIX_PD_MLMIX);
927
928 disable_isolation();
929}
Peng Fan6d929962022-07-26 16:41:03 +0800930
Peng Fan313af252022-07-26 16:41:04 +0800931bool m33_is_rom_kicked(void)
Peng Fan6d929962022-07-26 16:41:03 +0800932{
933 struct blk_ctrl_s_aonmix_regs *s_regs =
934 (struct blk_ctrl_s_aonmix_regs *)BLK_CTRL_S_ANOMIX_BASE_ADDR;
935
936 if (!(readl(&s_regs->m33_cfg) & BIT(2)))
937 return true;
938
939 return false;
940}
941
942int m33_prepare(void)
943{
944 struct src_mix_slice_regs *mix_regs =
945 (struct src_mix_slice_regs *)(ulong)(SRC_IPS_BASE_ADDR + 0x400 * (SRC_MIX_CM33 + 1));
946 struct src_general_regs *global_regs =
947 (struct src_general_regs *)(ulong)SRC_GLOBAL_RBASE;
948 struct blk_ctrl_s_aonmix_regs *s_regs =
949 (struct blk_ctrl_s_aonmix_regs *)BLK_CTRL_S_ANOMIX_BASE_ADDR;
Ye Li0667ec92024-09-19 12:01:20 +0800950 u32 val, i;
Peng Fan6d929962022-07-26 16:41:03 +0800951
952 if (m33_is_rom_kicked())
953 return -EPERM;
954
955 /* Release reset of M33 */
956 setbits_le32(&global_regs->scr, BIT(0));
957
958 /* Check the reset released in M33 MIX func stat */
959 val = readl(&mix_regs->func_stat);
960 while (!(val & SRC_MIX_SLICE_FUNC_STAT_RST_STAT))
961 val = readl(&mix_regs->func_stat);
962
Peng Fand5c31832023-06-15 18:09:05 +0800963 /* Release ELE TROUT */
964 ele_release_m33_trout();
Peng Fan6d929962022-07-26 16:41:03 +0800965
966 /* Mask WDOG1 IRQ from A55, we use it for M33 reset */
967 setbits_le32(&s_regs->ca55_irq_mask[1], BIT(6));
968
969 /* Turn on WDOG1 clock */
970 ccm_lpcg_on(CCGR_WDG1, 1);
971
Peng Fand5c31832023-06-15 18:09:05 +0800972 /* Set ELE LP handshake for M33 reset */
Peng Fan6d929962022-07-26 16:41:03 +0800973 setbits_le32(&s_regs->lp_handshake[0], BIT(6));
974
Ye Li0667ec92024-09-19 12:01:20 +0800975 /* OSCCA enabled, reconfigure TRDC for TCM access, otherwise ECC init will raise error */
976 val = readl(BLK_CTRL_NS_ANOMIX_BASE_ADDR + 0x28);
977 if (val & BIT(0)) {
978 trdc_mbc_set_control(0x44270000, 1, 0, 0x6600);
979
980 for (i = 0; i < 32; i++)
981 trdc_mbc_blk_config(0x44270000, 1, 3, 0, i, true, 0);
982
983 for (i = 0; i < 32; i++)
984 trdc_mbc_blk_config(0x44270000, 1, 3, 1, i, true, 0);
985 }
986
Peng Fan6d929962022-07-26 16:41:03 +0800987 /* Clear M33 TCM for ECC */
988 memset((void *)(ulong)0x201e0000, 0, 0x40000);
989
990 return 0;
991}
Peng Fanb1815c42023-04-28 12:08:27 +0800992
993int psci_sysreset_get_status(struct udevice *dev, char *buf, int size)
994{
995 static const char *reset_cause[] = {
996 "POR ",
997 "JTAG ",
998 "IPP USER ",
999 "WDOG1 ",
1000 "WDOG2 ",
1001 "WDOG3 ",
1002 "WDOG4 ",
1003 "WDOG5 ",
1004 "TEMPSENSE ",
1005 "CSU ",
1006 "JTAG_SW ",
1007 "M33_REQ ",
1008 "M33_LOCKUP ",
1009 "UNK ",
1010 "UNK ",
1011 "UNK "
1012 };
1013
1014 struct src_general_regs *src = (struct src_general_regs *)SRC_GLOBAL_RBASE;
1015 u32 srsr;
1016 u32 i;
1017 int res;
1018
1019 srsr = readl(&src->gpr[0]);
1020
1021 for (i = ARRAY_SIZE(reset_cause); i > 0; i--) {
1022 if (srsr & (BIT(i - 1)))
1023 break;
1024 }
1025
1026 res = snprintf(buf, size, "Reset Status: %s\n", i ? reset_cause[i - 1] : "unknown reset");
1027 if (res < 0) {
1028 dev_err(dev, "Could not write reset status message (err = %d)\n", res);
1029 return -EIO;
1030 }
1031
1032 return 0;
1033}
Ye Li7b248152024-09-19 12:01:26 +08001034
1035enum imx9_soc_voltage_mode soc_target_voltage_mode(void)
1036{
1037 u32 speed = get_cpu_speed_grade_hz();
1038 enum imx9_soc_voltage_mode voltage = VOLT_OVER_DRIVE;
1039
1040 if (is_imx93()) {
1041 if (speed == 1700000000)
1042 voltage = VOLT_OVER_DRIVE;
1043 else if (speed == 1400000000)
1044 voltage = VOLT_NOMINAL_DRIVE;
1045 else if (speed == 900000000 || speed == 800000000)
1046 voltage = VOLT_LOW_DRIVE;
1047 else
1048 printf("Unexpected A55 freq %u, default to OD\n", speed);
1049 }
1050
1051 return voltage;
1052}