blob: 6364709278234cb8446bc068247188bbbc81164d [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
Ye Li57b2ac42024-09-19 12:01:33 +0800194 /* Low performance 93 part */
195 if (((val >> 6) & 0x3F) == 0xE && npu_disable)
196 return core1_disable ? MXC_CPU_IMX9301 : MXC_CPU_IMX9302;
197
Peng Fanc3db3ad2023-04-28 12:08:32 +0800198 if ((val2 & pack_9x9_fused) == pack_9x9_fused)
199 type = MXC_CPU_IMX9322;
200
201 if (npu_disable && core1_disable)
202 return type + 3;
203 else if (npu_disable)
204 return type + 2;
205 else if (core1_disable)
206 return type + 1;
207
208 return type;
209}
210
Peng Fanbbcd2c42022-07-26 16:40:39 +0800211u32 get_cpu_rev(void)
212{
Peng Fan3700c472022-07-26 16:40:56 +0800213 u32 rev = (gd->arch.soc_rev >> 24) - 0xa0;
214
Peng Fanc3db3ad2023-04-28 12:08:32 +0800215 return (get_cpu_variant_type(MXC_CPU_IMX93) << 12) |
216 (CHIP_REV_1_0 + rev);
Peng Fanbbcd2c42022-07-26 16:40:39 +0800217}
218
Ye Li9e19ff92022-07-26 16:40:47 +0800219#define UNLOCK_WORD 0xD928C520 /* unlock word */
220#define REFRESH_WORD 0xB480A602 /* refresh word */
221
222static void disable_wdog(void __iomem *wdog_base)
223{
224 u32 val_cs = readl(wdog_base + 0x00);
225
226 if (!(val_cs & 0x80))
227 return;
228
229 /* default is 32bits cmd */
230 writel(REFRESH_WORD, (wdog_base + 0x04)); /* Refresh the CNT */
231
232 if (!(val_cs & 0x800)) {
233 writel(UNLOCK_WORD, (wdog_base + 0x04));
234 while (!(readl(wdog_base + 0x00) & 0x800))
235 ;
236 }
237 writel(0x0, (wdog_base + 0x0C)); /* Set WIN to 0 */
238 writel(0x400, (wdog_base + 0x08)); /* Set timeout to default 0x400 */
239 writel(0x2120, (wdog_base + 0x00)); /* Disable it and set update */
240
241 while (!(readl(wdog_base + 0x00) & 0x400))
242 ;
243}
244
245void init_wdog(void)
246{
Ye Li9e19ff92022-07-26 16:40:47 +0800247 disable_wdog((void __iomem *)WDG3_BASE_ADDR);
248 disable_wdog((void __iomem *)WDG4_BASE_ADDR);
249 disable_wdog((void __iomem *)WDG5_BASE_ADDR);
Ye Li9e19ff92022-07-26 16:40:47 +0800250}
251
Peng Fanbbcd2c42022-07-26 16:40:39 +0800252static struct mm_region imx93_mem_map[] = {
253 {
254 /* ROM */
255 .virt = 0x0UL,
256 .phys = 0x0UL,
257 .size = 0x100000UL,
258 .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
259 PTE_BLOCK_OUTER_SHARE
260 }, {
Peng Fan313af252022-07-26 16:41:04 +0800261 /* TCM */
262 .virt = 0x201c0000UL,
263 .phys = 0x201c0000UL,
264 .size = 0x80000UL,
265 .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
266 PTE_BLOCK_NON_SHARE |
267 PTE_BLOCK_PXN | PTE_BLOCK_UXN
268 }, {
Peng Fanbbcd2c42022-07-26 16:40:39 +0800269 /* OCRAM */
270 .virt = 0x20480000UL,
271 .phys = 0x20480000UL,
272 .size = 0xA0000UL,
273 .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
274 PTE_BLOCK_OUTER_SHARE
275 }, {
276 /* AIPS */
277 .virt = 0x40000000UL,
278 .phys = 0x40000000UL,
279 .size = 0x40000000UL,
280 .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
281 PTE_BLOCK_NON_SHARE |
282 PTE_BLOCK_PXN | PTE_BLOCK_UXN
283 }, {
284 /* Flexible Serial Peripheral Interface */
285 .virt = 0x28000000UL,
286 .phys = 0x28000000UL,
Ye Li35f15512024-03-28 18:49:18 +0800287 .size = 0x08000000UL,
Peng Fanbbcd2c42022-07-26 16:40:39 +0800288 .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
289 PTE_BLOCK_NON_SHARE |
290 PTE_BLOCK_PXN | PTE_BLOCK_UXN
291 }, {
292 /* DRAM1 */
293 .virt = 0x80000000UL,
294 .phys = 0x80000000UL,
295 .size = PHYS_SDRAM_SIZE,
296 .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
297 PTE_BLOCK_OUTER_SHARE
298 }, {
299 /* empty entrie to split table entry 5 if needed when TEEs are used */
300 0,
301 }, {
302 /* List terminator */
303 0,
304 }
305};
306
307struct mm_region *mem_map = imx93_mem_map;
308
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800309static unsigned int imx9_find_dram_entry_in_mem_map(void)
310{
311 int i;
312
313 for (i = 0; i < ARRAY_SIZE(imx93_mem_map); i++)
314 if (imx93_mem_map[i].phys == CFG_SYS_SDRAM_BASE)
315 return i;
316
317 hang(); /* Entry not found, this must never happen. */
318}
319
320void enable_caches(void)
321{
322 /* If OPTEE runs, remove OPTEE memory from MMU table to avoid speculative prefetch
323 * If OPTEE does not run, still update the MMU table according to dram banks structure
324 * to set correct dram size from board_phys_sdram_size
325 */
326 int i = 0;
327 /*
328 * please make sure that entry initial value matches
329 * imx93_mem_map for DRAM1
330 */
331 int entry = imx9_find_dram_entry_in_mem_map();
332 u64 attrs = imx93_mem_map[entry].attrs;
333
334 while (i < CONFIG_NR_DRAM_BANKS &&
335 entry < ARRAY_SIZE(imx93_mem_map)) {
336 if (gd->bd->bi_dram[i].start == 0)
337 break;
338 imx93_mem_map[entry].phys = gd->bd->bi_dram[i].start;
339 imx93_mem_map[entry].virt = gd->bd->bi_dram[i].start;
340 imx93_mem_map[entry].size = gd->bd->bi_dram[i].size;
341 imx93_mem_map[entry].attrs = attrs;
342 debug("Added memory mapping (%d): %llx %llx\n", entry,
343 imx93_mem_map[entry].phys, imx93_mem_map[entry].size);
344 i++; entry++;
345 }
346
347 icache_enable();
348 dcache_enable();
349}
350
351__weak int board_phys_sdram_size(phys_size_t *size)
352{
Ye Libb1187b2023-04-28 12:08:45 +0800353 phys_size_t start, end;
354 phys_size_t val;
355
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800356 if (!size)
357 return -EINVAL;
358
Ye Libb1187b2023-04-28 12:08:45 +0800359 val = readl(REG_DDR_CS0_BNDS);
360 start = (val >> 16) << 24;
361 end = (val & 0xFFFF);
362 end = end ? end + 1 : 0;
363 end = end << 24;
364 *size = end - start;
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800365
Ye Libb1187b2023-04-28 12:08:45 +0800366 val = readl(REG_DDR_CS1_BNDS);
367 start = (val >> 16) << 24;
368 end = (val & 0xFFFF);
369 end = end ? end + 1 : 0;
370 end = end << 24;
371 *size += end - start;
372
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800373 return 0;
374}
375
Peng Fanbbcd2c42022-07-26 16:40:39 +0800376int dram_init(void)
377{
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800378 phys_size_t sdram_size;
379 int ret;
380
381 ret = board_phys_sdram_size(&sdram_size);
382 if (ret)
383 return ret;
384
385 /* rom_pointer[1] contains the size of TEE occupies */
Elena Popa65c9edb2023-08-08 14:58:26 +0300386 if (!IS_ENABLED(CONFIG_SPL_BUILD) && rom_pointer[1])
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800387 gd->ram_size = sdram_size - rom_pointer[1];
388 else
389 gd->ram_size = sdram_size;
390
391 return 0;
392}
393
394int dram_init_banksize(void)
395{
396 int bank = 0;
397 int ret;
398 phys_size_t sdram_size;
399 phys_size_t sdram_b1_size, sdram_b2_size;
400
401 ret = board_phys_sdram_size(&sdram_size);
402 if (ret)
403 return ret;
404
405 /* Bank 1 can't cross over 4GB space */
406 if (sdram_size > 0x80000000) {
407 sdram_b1_size = 0x80000000;
408 sdram_b2_size = sdram_size - 0x80000000;
409 } else {
410 sdram_b1_size = sdram_size;
411 sdram_b2_size = 0;
412 }
413
414 gd->bd->bi_dram[bank].start = PHYS_SDRAM;
Elena Popa65c9edb2023-08-08 14:58:26 +0300415 if (!IS_ENABLED(CONFIG_SPL_BUILD) && rom_pointer[1]) {
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800416 phys_addr_t optee_start = (phys_addr_t)rom_pointer[0];
417 phys_size_t optee_size = (size_t)rom_pointer[1];
418
419 gd->bd->bi_dram[bank].size = optee_start - gd->bd->bi_dram[bank].start;
420 if ((optee_start + optee_size) < (PHYS_SDRAM + sdram_b1_size)) {
421 if (++bank >= CONFIG_NR_DRAM_BANKS) {
422 puts("CONFIG_NR_DRAM_BANKS is not enough\n");
423 return -1;
424 }
425
426 gd->bd->bi_dram[bank].start = optee_start + optee_size;
427 gd->bd->bi_dram[bank].size = PHYS_SDRAM +
428 sdram_b1_size - gd->bd->bi_dram[bank].start;
429 }
430 } else {
431 gd->bd->bi_dram[bank].size = sdram_b1_size;
432 }
433
434 if (sdram_b2_size) {
435 if (++bank >= CONFIG_NR_DRAM_BANKS) {
436 puts("CONFIG_NR_DRAM_BANKS is not enough for SDRAM_2\n");
437 return -1;
438 }
439 gd->bd->bi_dram[bank].start = 0x100000000UL;
440 gd->bd->bi_dram[bank].size = sdram_b2_size;
441 }
Peng Fanbbcd2c42022-07-26 16:40:39 +0800442
443 return 0;
444}
445
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800446phys_size_t get_effective_memsize(void)
447{
448 int ret;
449 phys_size_t sdram_size;
450 phys_size_t sdram_b1_size;
451
452 ret = board_phys_sdram_size(&sdram_size);
453 if (!ret) {
454 /* Bank 1 can't cross over 4GB space */
455 if (sdram_size > 0x80000000)
456 sdram_b1_size = 0x80000000;
457 else
458 sdram_b1_size = sdram_size;
459
Elena Popa65c9edb2023-08-08 14:58:26 +0300460 if (!IS_ENABLED(CONFIG_SPL_BUILD) && rom_pointer[1]) {
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800461 /* We will relocate u-boot to top of dram1. TEE position has two cases:
462 * 1. At the top of dram1, Then return the size removed optee size.
463 * 2. In the middle of dram1, return the size of dram1.
464 */
465 if ((rom_pointer[0] + rom_pointer[1]) == (PHYS_SDRAM + sdram_b1_size))
466 return ((phys_addr_t)rom_pointer[0] - PHYS_SDRAM);
467 }
468
469 return sdram_b1_size;
470 } else {
471 return PHYS_SDRAM_SIZE;
472 }
473}
474
Peng Fanbbcd2c42022-07-26 16:40:39 +0800475void imx_get_mac_from_fuse(int dev_id, unsigned char *mac)
476{
Ye Li66baefb2023-04-28 12:08:21 +0800477 u32 val[2] = {};
478 int ret;
479
480 if (dev_id == 0) {
481 ret = fuse_read(39, 3, &val[0]);
482 if (ret)
483 goto err;
484
485 ret = fuse_read(39, 4, &val[1]);
486 if (ret)
487 goto err;
488
489 mac[0] = val[1] >> 8;
490 mac[1] = val[1];
491 mac[2] = val[0] >> 24;
492 mac[3] = val[0] >> 16;
493 mac[4] = val[0] >> 8;
494 mac[5] = val[0];
495
496 } else {
497 ret = fuse_read(39, 5, &val[0]);
498 if (ret)
499 goto err;
500
501 ret = fuse_read(39, 4, &val[1]);
502 if (ret)
503 goto err;
504
Ye Liae9b7022024-09-19 12:01:24 +0800505 if (is_imx93() && is_soc_rev(CHIP_REV_1_0)) {
506 mac[0] = val[1] >> 24;
507 mac[1] = val[1] >> 16;
508 mac[2] = val[0] >> 24;
509 mac[3] = val[0] >> 16;
510 mac[4] = val[0] >> 8;
511 mac[5] = val[0];
512 } else {
513 mac[0] = val[0] >> 24;
514 mac[1] = val[0] >> 16;
515 mac[2] = val[0] >> 8;
516 mac[3] = val[0];
517 mac[4] = val[1] >> 24;
518 mac[5] = val[1] >> 16;
519 }
Ye Li66baefb2023-04-28 12:08:21 +0800520 }
521
522 debug("%s: MAC%d: %02x.%02x.%02x.%02x.%02x.%02x\n",
523 __func__, dev_id, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
524 return;
525err:
526 memset(mac, 0, 6);
527 printf("%s: fuse read err: %d\n", __func__, ret);
Peng Fanbbcd2c42022-07-26 16:40:39 +0800528}
529
530int print_cpuinfo(void)
531{
532 u32 cpurev;
533
534 cpurev = get_cpu_rev();
535
536 printf("CPU: i.MX93 rev%d.%d\n", (cpurev & 0x000F0) >> 4, (cpurev & 0x0000F) >> 0);
537
538 return 0;
539}
540
Primoz Fiserebbd4fc2024-01-11 13:56:25 +0100541static int fixup_thermal_trips(void *blob, const char *name)
542{
543 int minc, maxc;
544 int node, trip;
545
546 node = fdt_path_offset(blob, "/thermal-zones");
547 if (node < 0)
548 return node;
549
550 node = fdt_subnode_offset(blob, node, name);
551 if (node < 0)
552 return node;
553
554 node = fdt_subnode_offset(blob, node, "trips");
555 if (node < 0)
556 return node;
557
558 get_cpu_temp_grade(&minc, &maxc);
559
560 fdt_for_each_subnode(trip, blob, node) {
561 const char *type;
562 int temp, ret;
563
564 type = fdt_getprop(blob, trip, "type", NULL);
565 if (!type)
566 continue;
567
568 temp = 0;
569 if (!strcmp(type, "critical"))
Primoz Fiserab813e12024-08-13 14:12:17 +0200570 temp = 1000 * maxc;
Primoz Fiserebbd4fc2024-01-11 13:56:25 +0100571 else if (!strcmp(type, "passive"))
572 temp = 1000 * (maxc - 10);
573 if (temp) {
574 ret = fdt_setprop_u32(blob, trip, "temperature", temp);
575 if (ret)
576 return ret;
577 }
578 }
579
580 return 0;
581}
582
Peng Fan1a17ae82024-09-19 12:01:25 +0800583void build_info(void)
584{
585 u32 fw_version, sha1, res, status;
586 int ret;
587
588 printf("\nBuildInfo:\n");
589
590 ret = ele_get_fw_status(&status, &res);
591 if (ret) {
592 printf(" - ELE firmware status failed %d, 0x%x\n", ret, res);
593 } else if ((status & 0xff) == 1) {
594 ret = ele_get_fw_version(&fw_version, &sha1, &res);
595 if (ret) {
596 printf(" - ELE firmware version failed %d, 0x%x\n", ret, res);
597 } else {
598 printf(" - ELE firmware version %u.%u.%u-%x",
599 (fw_version & (0x00ff0000)) >> 16,
600 (fw_version & (0x0000fff0)) >> 4,
601 (fw_version & (0x0000000f)), sha1);
602 ((fw_version & (0x80000000)) >> 31) == 1 ? puts("-dirty\n") : puts("\n");
603 }
604 } else {
605 printf(" - ELE firmware not included\n");
606 }
607 puts("\n");
608}
609
610int arch_misc_init(void)
611{
612 build_info();
613 return 0;
614}
615
Ye Li7b248152024-09-19 12:01:26 +0800616struct low_drive_freq_entry {
617 const char *node_path;
618 u32 clk;
619 u32 new_rate;
620};
621
622static int low_drive_fdt_fix_clock(void *fdt, int node_off, u32 clk_index, u32 new_rate)
623{
624#define MAX_ASSIGNED_CLKS 8
625 int cnt, j;
626 u32 assignedclks[MAX_ASSIGNED_CLKS]; /* max 8 clocks*/
627
628 cnt = fdtdec_get_int_array_count(fdt, node_off, "assigned-clock-rates",
629 assignedclks, MAX_ASSIGNED_CLKS);
630 if (cnt > 0) {
631 if (cnt <= clk_index)
632 return -ENOENT;
633
634 if (assignedclks[clk_index] <= new_rate)
635 return 0;
636
637 assignedclks[clk_index] = new_rate;
638 for (j = 0; j < cnt; j++)
639 assignedclks[j] = cpu_to_fdt32(assignedclks[j]);
640
641 return fdt_setprop(fdt, node_off, "assigned-clock-rates", &assignedclks,
642 cnt * sizeof(u32));
643 }
644
645 return -ENOENT;
646}
647
648static int low_drive_freq_update(void *blob)
649{
650 int nodeoff, ret;
651 int i;
652
653 /* Update kernel dtb clocks for low drive mode */
654 struct low_drive_freq_entry table[] = {
655 {"/soc@0/bus@42800000/mmc@42850000", 0, 266666667},
656 {"/soc@0/bus@42800000/mmc@42860000", 0, 266666667},
657 {"/soc@0/bus@42800000/mmc@428b0000", 0, 266666667},
658 };
659
660 for (i = 0; i < ARRAY_SIZE(table); i++) {
661 nodeoff = fdt_path_offset(blob, table[i].node_path);
662 if (nodeoff >= 0) {
663 ret = low_drive_fdt_fix_clock(blob, nodeoff, table[i].clk,
664 table[i].new_rate);
665 if (!ret)
666 printf("%s freq updated\n", table[i].node_path);
667 }
668 }
669
670 return 0;
671}
672
673#ifdef CONFIG_OF_BOARD_FIXUP
674#ifndef CONFIG_SPL_BUILD
675int board_fix_fdt(void *fdt)
676{
677 /* Update dtb clocks for low drive mode */
678 if (is_voltage_mode(VOLT_LOW_DRIVE)) {
679 int nodeoff;
680 int i;
681
682 struct low_drive_freq_entry table[] = {
683 {"/soc@0/bus@42800000/mmc@42850000", 0, 266666667},
684 {"/soc@0/bus@42800000/mmc@42860000", 0, 266666667},
685 {"/soc@0/bus@42800000/mmc@428b0000", 0, 266666667},
686 };
687
688 for (i = 0; i < ARRAY_SIZE(table); i++) {
689 nodeoff = fdt_path_offset(fdt, table[i].node_path);
690 if (nodeoff >= 0)
691 low_drive_fdt_fix_clock(fdt, nodeoff, table[i].clk,
692 table[i].new_rate);
693 }
694 }
695
696 return 0;
697}
698#endif
699#endif
700
Peng Fanbbcd2c42022-07-26 16:40:39 +0800701int ft_system_setup(void *blob, struct bd_info *bd)
702{
Peng Fan904a8862024-09-19 12:01:32 +0800703 static const char * const nodes_path[] = {
704 "/cpus/cpu@0",
705 "/cpus/cpu@100",
706 };
707
Primoz Fiserebbd4fc2024-01-11 13:56:25 +0100708 if (fixup_thermal_trips(blob, "cpu-thermal"))
709 printf("Failed to update cpu-thermal trip(s)");
710
Ye Li57b2ac42024-09-19 12:01:33 +0800711 if (is_imx9351() || is_imx9331() || is_imx9321() || is_imx9311() || is_imx9301())
Peng Fan904a8862024-09-19 12:01:32 +0800712 disable_cpu_nodes(blob, nodes_path, 1, 2);
713
Ye Li7b248152024-09-19 12:01:26 +0800714 if (is_voltage_mode(VOLT_LOW_DRIVE))
715 low_drive_freq_update(blob);
716
Peng Fanbbcd2c42022-07-26 16:40:39 +0800717 return 0;
718}
Peng Fan3700c472022-07-26 16:40:56 +0800719
720#if defined(CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG)
721void get_board_serial(struct tag_serialnr *serialnr)
722{
Ye Li8a7f6ef2024-09-19 12:01:22 +0800723 printf("UID: %08x%08x%08x%08x\n", __be32_to_cpu(gd->arch.uid[0]),
724 __be32_to_cpu(gd->arch.uid[1]), __be32_to_cpu(gd->arch.uid[2]),
725 __be32_to_cpu(gd->arch.uid[3]));
Peng Fan3700c472022-07-26 16:40:56 +0800726
Frank Li52b93ea2024-09-19 12:01:21 +0800727 serialnr->low = __be32_to_cpu(gd->arch.uid[1]);
728 serialnr->high = __be32_to_cpu(gd->arch.uid[0]);
Peng Fan3700c472022-07-26 16:40:56 +0800729}
730#endif
Peng Fanbbcd2c42022-07-26 16:40:39 +0800731
Peng Fanb1815c42023-04-28 12:08:27 +0800732static void save_reset_cause(void)
733{
734 struct src_general_regs *src = (struct src_general_regs *)SRC_GLOBAL_RBASE;
735 u32 srsr = readl(&src->srsr);
736
737 /* clear srsr in sec mode */
738 writel(srsr, &src->srsr);
739
740 /* Save value to GPR1 to pass to nonsecure */
741 writel(srsr, &src->gpr[0]);
742}
743
Peng Fanbbcd2c42022-07-26 16:40:39 +0800744int arch_cpu_init(void)
745{
Ye Li9e19ff92022-07-26 16:40:47 +0800746 if (IS_ENABLED(CONFIG_SPL_BUILD)) {
747 /* Disable wdog */
748 init_wdog();
749
Ye Li66af10a2024-09-19 12:01:27 +0800750 clock_init_early();
Ye Li62185922022-07-26 16:40:54 +0800751
752 trdc_early_init();
Peng Fanb1815c42023-04-28 12:08:27 +0800753
754 /* Save SRC SRSR to GPR1 and clear it */
755 save_reset_cause();
Ye Li9e19ff92022-07-26 16:40:47 +0800756 }
Peng Fan28b5cb52022-07-26 16:40:43 +0800757
Peng Fanbbcd2c42022-07-26 16:40:39 +0800758 return 0;
759}
Peng Fan3700c472022-07-26 16:40:56 +0800760
Simon Glassb8357c12023-08-21 21:16:56 -0600761int imx9_probe_mu(void)
Peng Fan3700c472022-07-26 16:40:56 +0800762{
763 struct udevice *devp;
764 int node, ret;
765 u32 res;
Peng Fand5c31832023-06-15 18:09:05 +0800766 struct ele_get_info_data info;
Peng Fan3700c472022-07-26 16:40:56 +0800767
768 node = fdt_node_offset_by_compatible(gd->fdt_blob, -1, "fsl,imx93-mu-s4");
769
770 ret = uclass_get_device_by_of_offset(UCLASS_MISC, node, &devp);
771 if (ret)
772 return ret;
773
774 if (gd->flags & GD_FLG_RELOC)
775 return 0;
776
Peng Fand5c31832023-06-15 18:09:05 +0800777 ret = ele_get_info(&info, &res);
Peng Fan3700c472022-07-26 16:40:56 +0800778 if (ret)
779 return ret;
780
781 set_cpu_info(&info);
782
783 return 0;
784}
Simon Glassb8357c12023-08-21 21:16:56 -0600785EVENT_SPY_SIMPLE(EVT_DM_POST_INIT_F, imx9_probe_mu);
Ye Lif41ffc12024-04-01 09:41:09 +0800786EVENT_SPY_SIMPLE(EVT_DM_POST_INIT_R, imx9_probe_mu);
Jian Liacf41a32022-07-26 16:40:46 +0800787
788int timer_init(void)
789{
790#ifdef CONFIG_SPL_BUILD
791 struct sctr_regs *sctr = (struct sctr_regs *)SYSCNT_CTRL_BASE_ADDR;
792 unsigned long freq = readl(&sctr->cntfid0);
793
794 /* Update with accurate clock frequency */
795 asm volatile("msr cntfrq_el0, %0" : : "r" (freq) : "memory");
796
797 clrsetbits_le32(&sctr->cntcr, SC_CNTCR_FREQ0 | SC_CNTCR_FREQ1,
798 SC_CNTCR_FREQ0 | SC_CNTCR_ENABLE | SC_CNTCR_HDBG);
799#endif
800
801 gd->arch.tbl = 0;
802 gd->arch.tbu = 0;
803
804 return 0;
805}
Peng Fan65563792022-07-26 16:41:02 +0800806
Ye Li8e8687c2022-07-26 16:41:05 +0800807enum env_location env_get_location(enum env_operation op, int prio)
808{
809 enum boot_device dev = get_boot_device();
Ye Li8e8687c2022-07-26 16:41:05 +0800810
811 if (prio)
Oleksandr Suvoroveff7c8d2023-04-11 20:27:41 +0300812 return ENVL_UNKNOWN;
Ye Li8e8687c2022-07-26 16:41:05 +0800813
814 switch (dev) {
Ye Li8e8687c2022-07-26 16:41:05 +0800815 case QSPI_BOOT:
Oleksandr Suvoroveff7c8d2023-04-11 20:27:41 +0300816 if (CONFIG_IS_ENABLED(ENV_IS_IN_SPI_FLASH))
817 return ENVL_SPI_FLASH;
818 return ENVL_NOWHERE;
Ye Li8e8687c2022-07-26 16:41:05 +0800819 case SD1_BOOT:
820 case SD2_BOOT:
821 case SD3_BOOT:
822 case MMC1_BOOT:
823 case MMC2_BOOT:
824 case MMC3_BOOT:
Oleksandr Suvoroveff7c8d2023-04-11 20:27:41 +0300825 if (CONFIG_IS_ENABLED(ENV_IS_IN_MMC))
826 return ENVL_MMC;
827 else if (CONFIG_IS_ENABLED(ENV_IS_IN_EXT4))
828 return ENVL_EXT4;
829 else if (CONFIG_IS_ENABLED(ENV_IS_IN_FAT))
830 return ENVL_FAT;
831 return ENVL_NOWHERE;
Ye Li8e8687c2022-07-26 16:41:05 +0800832 default:
Oleksandr Suvoroveff7c8d2023-04-11 20:27:41 +0300833 return ENVL_NOWHERE;
Ye Li8e8687c2022-07-26 16:41:05 +0800834 }
Ye Li8e8687c2022-07-26 16:41:05 +0800835}
836
Peng Fan65563792022-07-26 16:41:02 +0800837static int mix_power_init(enum mix_power_domain pd)
838{
839 enum src_mix_slice_id mix_id;
840 enum src_mem_slice_id mem_id;
841 struct src_mix_slice_regs *mix_regs;
842 struct src_mem_slice_regs *mem_regs;
843 struct src_general_regs *global_regs;
844 u32 scr, val;
845
846 switch (pd) {
847 case MIX_PD_MEDIAMIX:
848 mix_id = SRC_MIX_MEDIA;
849 mem_id = SRC_MEM_MEDIA;
850 scr = BIT(5);
851
Peng Fand5c31832023-06-15 18:09:05 +0800852 /* Enable ELE handshake */
Peng Fan65563792022-07-26 16:41:02 +0800853 struct blk_ctrl_s_aonmix_regs *s_regs =
854 (struct blk_ctrl_s_aonmix_regs *)BLK_CTRL_S_ANOMIX_BASE_ADDR;
855
856 setbits_le32(&s_regs->lp_handshake[0], BIT(13));
857 break;
858 case MIX_PD_MLMIX:
859 mix_id = SRC_MIX_ML;
860 mem_id = SRC_MEM_ML;
861 scr = BIT(4);
862 break;
863 case MIX_PD_DDRMIX:
864 mix_id = SRC_MIX_DDRMIX;
865 mem_id = SRC_MEM_DDRMIX;
866 scr = BIT(6);
867 break;
868 default:
869 return -EINVAL;
870 }
871
872 mix_regs = (struct src_mix_slice_regs *)(ulong)(SRC_IPS_BASE_ADDR + 0x400 * (mix_id + 1));
873 mem_regs =
874 (struct src_mem_slice_regs *)(ulong)(SRC_IPS_BASE_ADDR + 0x3800 + 0x400 * mem_id);
875 global_regs = (struct src_general_regs *)(ulong)SRC_GLOBAL_RBASE;
876
877 /* Allow NS to set it */
878 setbits_le32(&mix_regs->authen_ctrl, BIT(9));
879
880 clrsetbits_le32(&mix_regs->psw_ack_ctrl[0], BIT(28), BIT(29));
881
882 /* mix reset will be held until boot core write this bit to 1 */
883 setbits_le32(&global_regs->scr, scr);
884
885 /* Enable mem in Low power auto sequence */
886 setbits_le32(&mem_regs->mem_ctrl, BIT(2));
887
888 /* Set the power down state */
889 val = readl(&mix_regs->func_stat);
890 if (val & SRC_MIX_SLICE_FUNC_STAT_PSW_STAT) {
891 /* The mix is default power off, power down it to make PDN_SFT bit
892 * aligned with FUNC STAT
893 */
894 setbits_le32(&mix_regs->slice_sw_ctrl, BIT(31));
895 val = readl(&mix_regs->func_stat);
896
897 /* Since PSW_STAT is 1, can't be used for power off status (SW_CTRL BIT31 set)) */
898 /* Check the MEM STAT change to ensure SSAR is completed */
899 while (!(val & SRC_MIX_SLICE_FUNC_STAT_MEM_STAT))
900 val = readl(&mix_regs->func_stat);
901
902 /* wait few ipg clock cycles to ensure FSM done and power off status is correct */
903 /* About 5 cycles at 24Mhz, 1us is enough */
904 udelay(1);
905 } else {
906 /* The mix is default power on, Do mix power cycle */
907 setbits_le32(&mix_regs->slice_sw_ctrl, BIT(31));
908 val = readl(&mix_regs->func_stat);
909 while (!(val & SRC_MIX_SLICE_FUNC_STAT_PSW_STAT))
910 val = readl(&mix_regs->func_stat);
911 }
912
913 /* power on */
914 clrbits_le32(&mix_regs->slice_sw_ctrl, BIT(31));
915 val = readl(&mix_regs->func_stat);
Peng Fan06e78ff2024-09-19 12:01:19 +0800916 while (val & SRC_MIX_SLICE_FUNC_STAT_SSAR_STAT)
Peng Fan65563792022-07-26 16:41:02 +0800917 val = readl(&mix_regs->func_stat);
918
919 return 0;
920}
921
922void disable_isolation(void)
923{
924 struct src_general_regs *global_regs = (struct src_general_regs *)(ulong)SRC_GLOBAL_RBASE;
925 /* clear isolation for usbphy, dsi, csi*/
926 writel(0x0, &global_regs->sp_iso_ctrl);
927}
928
929void soc_power_init(void)
930{
931 mix_power_init(MIX_PD_MEDIAMIX);
932 mix_power_init(MIX_PD_MLMIX);
933
934 disable_isolation();
935}
Peng Fan6d929962022-07-26 16:41:03 +0800936
Peng Fan313af252022-07-26 16:41:04 +0800937bool m33_is_rom_kicked(void)
Peng Fan6d929962022-07-26 16:41:03 +0800938{
939 struct blk_ctrl_s_aonmix_regs *s_regs =
940 (struct blk_ctrl_s_aonmix_regs *)BLK_CTRL_S_ANOMIX_BASE_ADDR;
941
942 if (!(readl(&s_regs->m33_cfg) & BIT(2)))
943 return true;
944
945 return false;
946}
947
948int m33_prepare(void)
949{
950 struct src_mix_slice_regs *mix_regs =
951 (struct src_mix_slice_regs *)(ulong)(SRC_IPS_BASE_ADDR + 0x400 * (SRC_MIX_CM33 + 1));
952 struct src_general_regs *global_regs =
953 (struct src_general_regs *)(ulong)SRC_GLOBAL_RBASE;
954 struct blk_ctrl_s_aonmix_regs *s_regs =
955 (struct blk_ctrl_s_aonmix_regs *)BLK_CTRL_S_ANOMIX_BASE_ADDR;
Ye Li0667ec92024-09-19 12:01:20 +0800956 u32 val, i;
Peng Fan6d929962022-07-26 16:41:03 +0800957
958 if (m33_is_rom_kicked())
959 return -EPERM;
960
961 /* Release reset of M33 */
962 setbits_le32(&global_regs->scr, BIT(0));
963
964 /* Check the reset released in M33 MIX func stat */
965 val = readl(&mix_regs->func_stat);
966 while (!(val & SRC_MIX_SLICE_FUNC_STAT_RST_STAT))
967 val = readl(&mix_regs->func_stat);
968
Peng Fand5c31832023-06-15 18:09:05 +0800969 /* Release ELE TROUT */
970 ele_release_m33_trout();
Peng Fan6d929962022-07-26 16:41:03 +0800971
972 /* Mask WDOG1 IRQ from A55, we use it for M33 reset */
973 setbits_le32(&s_regs->ca55_irq_mask[1], BIT(6));
974
975 /* Turn on WDOG1 clock */
976 ccm_lpcg_on(CCGR_WDG1, 1);
977
Peng Fand5c31832023-06-15 18:09:05 +0800978 /* Set ELE LP handshake for M33 reset */
Peng Fan6d929962022-07-26 16:41:03 +0800979 setbits_le32(&s_regs->lp_handshake[0], BIT(6));
980
Ye Li0667ec92024-09-19 12:01:20 +0800981 /* OSCCA enabled, reconfigure TRDC for TCM access, otherwise ECC init will raise error */
982 val = readl(BLK_CTRL_NS_ANOMIX_BASE_ADDR + 0x28);
983 if (val & BIT(0)) {
984 trdc_mbc_set_control(0x44270000, 1, 0, 0x6600);
985
986 for (i = 0; i < 32; i++)
987 trdc_mbc_blk_config(0x44270000, 1, 3, 0, i, true, 0);
988
989 for (i = 0; i < 32; i++)
990 trdc_mbc_blk_config(0x44270000, 1, 3, 1, i, true, 0);
991 }
992
Peng Fan6d929962022-07-26 16:41:03 +0800993 /* Clear M33 TCM for ECC */
994 memset((void *)(ulong)0x201e0000, 0, 0x40000);
995
996 return 0;
997}
Peng Fanb1815c42023-04-28 12:08:27 +0800998
999int psci_sysreset_get_status(struct udevice *dev, char *buf, int size)
1000{
1001 static const char *reset_cause[] = {
1002 "POR ",
1003 "JTAG ",
1004 "IPP USER ",
1005 "WDOG1 ",
1006 "WDOG2 ",
1007 "WDOG3 ",
1008 "WDOG4 ",
1009 "WDOG5 ",
1010 "TEMPSENSE ",
1011 "CSU ",
1012 "JTAG_SW ",
1013 "M33_REQ ",
1014 "M33_LOCKUP ",
1015 "UNK ",
1016 "UNK ",
1017 "UNK "
1018 };
1019
1020 struct src_general_regs *src = (struct src_general_regs *)SRC_GLOBAL_RBASE;
1021 u32 srsr;
1022 u32 i;
1023 int res;
1024
1025 srsr = readl(&src->gpr[0]);
1026
1027 for (i = ARRAY_SIZE(reset_cause); i > 0; i--) {
1028 if (srsr & (BIT(i - 1)))
1029 break;
1030 }
1031
1032 res = snprintf(buf, size, "Reset Status: %s\n", i ? reset_cause[i - 1] : "unknown reset");
1033 if (res < 0) {
1034 dev_err(dev, "Could not write reset status message (err = %d)\n", res);
1035 return -EIO;
1036 }
1037
1038 return 0;
1039}
Ye Li7b248152024-09-19 12:01:26 +08001040
1041enum imx9_soc_voltage_mode soc_target_voltage_mode(void)
1042{
1043 u32 speed = get_cpu_speed_grade_hz();
1044 enum imx9_soc_voltage_mode voltage = VOLT_OVER_DRIVE;
1045
1046 if (is_imx93()) {
1047 if (speed == 1700000000)
1048 voltage = VOLT_OVER_DRIVE;
1049 else if (speed == 1400000000)
1050 voltage = VOLT_NOMINAL_DRIVE;
1051 else if (speed == 900000000 || speed == 800000000)
1052 voltage = VOLT_LOW_DRIVE;
1053 else
1054 printf("Unexpected A55 freq %u, default to OD\n", speed);
1055 }
1056
1057 return voltage;
1058}