blob: 06032f2ff59f23decf51efb77ace02939739c83f [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{
99 u32 speed, max_speed;
100 u32 val;
101
102 fuse_read(2, 3, &val);
103 val = FIELD_GET(SPEED_GRADING_MASK, val) & 0xF;
104
105 speed = MHZ(2300) - val * MHZ(100);
106
107 if (is_imx93())
108 max_speed = MHZ(1700);
109
110 /* In case the fuse of speed grade not programmed */
111 if (speed > max_speed)
112 speed = max_speed;
113
114 return speed;
115}
116
117/*
118 * `00` - Consumer 0C to 95C
119 * `01` - Ext. Consumer -20C to 105C
120 * `10` - Industrial -40C to 105C
121 * `11` - Automotive -40C to 125C
122 */
123u32 get_cpu_temp_grade(int *minc, int *maxc)
124{
125 u32 val;
126
127 fuse_read(2, 3, &val);
128 val = FIELD_GET(MARKETING_GRADING_MASK, val);
129
130 if (minc && maxc) {
131 if (val == TEMP_AUTOMOTIVE) {
132 *minc = -40;
133 *maxc = 125;
134 } else if (val == TEMP_INDUSTRIAL) {
135 *minc = -40;
136 *maxc = 105;
137 } else if (val == TEMP_EXTCOMMERCIAL) {
138 if (is_imx93()) {
139 /* imx93 only has extended industrial*/
140 *minc = -40;
141 *maxc = 125;
142 } else {
143 *minc = -20;
144 *maxc = 105;
145 }
146 } else {
147 *minc = 0;
148 *maxc = 95;
149 }
150 }
151 return val;
152}
153
Peng Fand5c31832023-06-15 18:09:05 +0800154static void set_cpu_info(struct ele_get_info_data *info)
Peng Fan3700c472022-07-26 16:40:56 +0800155{
156 gd->arch.soc_rev = info->soc;
157 gd->arch.lifecycle = info->lc;
158 memcpy((void *)&gd->arch.uid, &info->uid, 4 * sizeof(u32));
159}
160
Peng Fanc3db3ad2023-04-28 12:08:32 +0800161static u32 get_cpu_variant_type(u32 type)
162{
163 /* word 19 */
164 u32 val = readl((ulong)FSB_BASE_ADDR + 0x8000 + (19 << 2));
165 u32 val2 = readl((ulong)FSB_BASE_ADDR + 0x8000 + (20 << 2));
166 bool npu_disable = !!(val & BIT(13));
167 bool core1_disable = !!(val & BIT(15));
168 u32 pack_9x9_fused = BIT(4) | BIT(17) | BIT(19) | BIT(24);
169
170 if ((val2 & pack_9x9_fused) == pack_9x9_fused)
171 type = MXC_CPU_IMX9322;
172
173 if (npu_disable && core1_disable)
174 return type + 3;
175 else if (npu_disable)
176 return type + 2;
177 else if (core1_disable)
178 return type + 1;
179
180 return type;
181}
182
Peng Fanbbcd2c42022-07-26 16:40:39 +0800183u32 get_cpu_rev(void)
184{
Peng Fan3700c472022-07-26 16:40:56 +0800185 u32 rev = (gd->arch.soc_rev >> 24) - 0xa0;
186
Peng Fanc3db3ad2023-04-28 12:08:32 +0800187 return (get_cpu_variant_type(MXC_CPU_IMX93) << 12) |
188 (CHIP_REV_1_0 + rev);
Peng Fanbbcd2c42022-07-26 16:40:39 +0800189}
190
Ye Li9e19ff92022-07-26 16:40:47 +0800191#define UNLOCK_WORD 0xD928C520 /* unlock word */
192#define REFRESH_WORD 0xB480A602 /* refresh word */
193
194static void disable_wdog(void __iomem *wdog_base)
195{
196 u32 val_cs = readl(wdog_base + 0x00);
197
198 if (!(val_cs & 0x80))
199 return;
200
201 /* default is 32bits cmd */
202 writel(REFRESH_WORD, (wdog_base + 0x04)); /* Refresh the CNT */
203
204 if (!(val_cs & 0x800)) {
205 writel(UNLOCK_WORD, (wdog_base + 0x04));
206 while (!(readl(wdog_base + 0x00) & 0x800))
207 ;
208 }
209 writel(0x0, (wdog_base + 0x0C)); /* Set WIN to 0 */
210 writel(0x400, (wdog_base + 0x08)); /* Set timeout to default 0x400 */
211 writel(0x2120, (wdog_base + 0x00)); /* Disable it and set update */
212
213 while (!(readl(wdog_base + 0x00) & 0x400))
214 ;
215}
216
217void init_wdog(void)
218{
219 u32 src_val;
220
221 disable_wdog((void __iomem *)WDG3_BASE_ADDR);
222 disable_wdog((void __iomem *)WDG4_BASE_ADDR);
223 disable_wdog((void __iomem *)WDG5_BASE_ADDR);
224
225 src_val = readl(0x54460018); /* reset mask */
226 src_val &= ~0x1c;
227 writel(src_val, 0x54460018);
228}
229
Peng Fanbbcd2c42022-07-26 16:40:39 +0800230static struct mm_region imx93_mem_map[] = {
231 {
232 /* ROM */
233 .virt = 0x0UL,
234 .phys = 0x0UL,
235 .size = 0x100000UL,
236 .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
237 PTE_BLOCK_OUTER_SHARE
238 }, {
Peng Fan313af252022-07-26 16:41:04 +0800239 /* TCM */
240 .virt = 0x201c0000UL,
241 .phys = 0x201c0000UL,
242 .size = 0x80000UL,
243 .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
244 PTE_BLOCK_NON_SHARE |
245 PTE_BLOCK_PXN | PTE_BLOCK_UXN
246 }, {
Peng Fanbbcd2c42022-07-26 16:40:39 +0800247 /* OCRAM */
248 .virt = 0x20480000UL,
249 .phys = 0x20480000UL,
250 .size = 0xA0000UL,
251 .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
252 PTE_BLOCK_OUTER_SHARE
253 }, {
254 /* AIPS */
255 .virt = 0x40000000UL,
256 .phys = 0x40000000UL,
257 .size = 0x40000000UL,
258 .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
259 PTE_BLOCK_NON_SHARE |
260 PTE_BLOCK_PXN | PTE_BLOCK_UXN
261 }, {
262 /* Flexible Serial Peripheral Interface */
263 .virt = 0x28000000UL,
264 .phys = 0x28000000UL,
Ye Li35f15512024-03-28 18:49:18 +0800265 .size = 0x08000000UL,
Peng Fanbbcd2c42022-07-26 16:40:39 +0800266 .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
267 PTE_BLOCK_NON_SHARE |
268 PTE_BLOCK_PXN | PTE_BLOCK_UXN
269 }, {
270 /* DRAM1 */
271 .virt = 0x80000000UL,
272 .phys = 0x80000000UL,
273 .size = PHYS_SDRAM_SIZE,
274 .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
275 PTE_BLOCK_OUTER_SHARE
276 }, {
277 /* empty entrie to split table entry 5 if needed when TEEs are used */
278 0,
279 }, {
280 /* List terminator */
281 0,
282 }
283};
284
285struct mm_region *mem_map = imx93_mem_map;
286
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800287static unsigned int imx9_find_dram_entry_in_mem_map(void)
288{
289 int i;
290
291 for (i = 0; i < ARRAY_SIZE(imx93_mem_map); i++)
292 if (imx93_mem_map[i].phys == CFG_SYS_SDRAM_BASE)
293 return i;
294
295 hang(); /* Entry not found, this must never happen. */
296}
297
298void enable_caches(void)
299{
300 /* If OPTEE runs, remove OPTEE memory from MMU table to avoid speculative prefetch
301 * If OPTEE does not run, still update the MMU table according to dram banks structure
302 * to set correct dram size from board_phys_sdram_size
303 */
304 int i = 0;
305 /*
306 * please make sure that entry initial value matches
307 * imx93_mem_map for DRAM1
308 */
309 int entry = imx9_find_dram_entry_in_mem_map();
310 u64 attrs = imx93_mem_map[entry].attrs;
311
312 while (i < CONFIG_NR_DRAM_BANKS &&
313 entry < ARRAY_SIZE(imx93_mem_map)) {
314 if (gd->bd->bi_dram[i].start == 0)
315 break;
316 imx93_mem_map[entry].phys = gd->bd->bi_dram[i].start;
317 imx93_mem_map[entry].virt = gd->bd->bi_dram[i].start;
318 imx93_mem_map[entry].size = gd->bd->bi_dram[i].size;
319 imx93_mem_map[entry].attrs = attrs;
320 debug("Added memory mapping (%d): %llx %llx\n", entry,
321 imx93_mem_map[entry].phys, imx93_mem_map[entry].size);
322 i++; entry++;
323 }
324
325 icache_enable();
326 dcache_enable();
327}
328
329__weak int board_phys_sdram_size(phys_size_t *size)
330{
Ye Libb1187b2023-04-28 12:08:45 +0800331 phys_size_t start, end;
332 phys_size_t val;
333
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800334 if (!size)
335 return -EINVAL;
336
Ye Libb1187b2023-04-28 12:08:45 +0800337 val = readl(REG_DDR_CS0_BNDS);
338 start = (val >> 16) << 24;
339 end = (val & 0xFFFF);
340 end = end ? end + 1 : 0;
341 end = end << 24;
342 *size = end - start;
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800343
Ye Libb1187b2023-04-28 12:08:45 +0800344 val = readl(REG_DDR_CS1_BNDS);
345 start = (val >> 16) << 24;
346 end = (val & 0xFFFF);
347 end = end ? end + 1 : 0;
348 end = end << 24;
349 *size += end - start;
350
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800351 return 0;
352}
353
Peng Fanbbcd2c42022-07-26 16:40:39 +0800354int dram_init(void)
355{
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800356 phys_size_t sdram_size;
357 int ret;
358
359 ret = board_phys_sdram_size(&sdram_size);
360 if (ret)
361 return ret;
362
363 /* rom_pointer[1] contains the size of TEE occupies */
Elena Popa65c9edb2023-08-08 14:58:26 +0300364 if (!IS_ENABLED(CONFIG_SPL_BUILD) && rom_pointer[1])
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800365 gd->ram_size = sdram_size - rom_pointer[1];
366 else
367 gd->ram_size = sdram_size;
368
369 return 0;
370}
371
372int dram_init_banksize(void)
373{
374 int bank = 0;
375 int ret;
376 phys_size_t sdram_size;
377 phys_size_t sdram_b1_size, sdram_b2_size;
378
379 ret = board_phys_sdram_size(&sdram_size);
380 if (ret)
381 return ret;
382
383 /* Bank 1 can't cross over 4GB space */
384 if (sdram_size > 0x80000000) {
385 sdram_b1_size = 0x80000000;
386 sdram_b2_size = sdram_size - 0x80000000;
387 } else {
388 sdram_b1_size = sdram_size;
389 sdram_b2_size = 0;
390 }
391
392 gd->bd->bi_dram[bank].start = PHYS_SDRAM;
Elena Popa65c9edb2023-08-08 14:58:26 +0300393 if (!IS_ENABLED(CONFIG_SPL_BUILD) && rom_pointer[1]) {
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800394 phys_addr_t optee_start = (phys_addr_t)rom_pointer[0];
395 phys_size_t optee_size = (size_t)rom_pointer[1];
396
397 gd->bd->bi_dram[bank].size = optee_start - gd->bd->bi_dram[bank].start;
398 if ((optee_start + optee_size) < (PHYS_SDRAM + sdram_b1_size)) {
399 if (++bank >= CONFIG_NR_DRAM_BANKS) {
400 puts("CONFIG_NR_DRAM_BANKS is not enough\n");
401 return -1;
402 }
403
404 gd->bd->bi_dram[bank].start = optee_start + optee_size;
405 gd->bd->bi_dram[bank].size = PHYS_SDRAM +
406 sdram_b1_size - gd->bd->bi_dram[bank].start;
407 }
408 } else {
409 gd->bd->bi_dram[bank].size = sdram_b1_size;
410 }
411
412 if (sdram_b2_size) {
413 if (++bank >= CONFIG_NR_DRAM_BANKS) {
414 puts("CONFIG_NR_DRAM_BANKS is not enough for SDRAM_2\n");
415 return -1;
416 }
417 gd->bd->bi_dram[bank].start = 0x100000000UL;
418 gd->bd->bi_dram[bank].size = sdram_b2_size;
419 }
Peng Fanbbcd2c42022-07-26 16:40:39 +0800420
421 return 0;
422}
423
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800424phys_size_t get_effective_memsize(void)
425{
426 int ret;
427 phys_size_t sdram_size;
428 phys_size_t sdram_b1_size;
429
430 ret = board_phys_sdram_size(&sdram_size);
431 if (!ret) {
432 /* Bank 1 can't cross over 4GB space */
433 if (sdram_size > 0x80000000)
434 sdram_b1_size = 0x80000000;
435 else
436 sdram_b1_size = sdram_size;
437
Elena Popa65c9edb2023-08-08 14:58:26 +0300438 if (!IS_ENABLED(CONFIG_SPL_BUILD) && rom_pointer[1]) {
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800439 /* We will relocate u-boot to top of dram1. TEE position has two cases:
440 * 1. At the top of dram1, Then return the size removed optee size.
441 * 2. In the middle of dram1, return the size of dram1.
442 */
443 if ((rom_pointer[0] + rom_pointer[1]) == (PHYS_SDRAM + sdram_b1_size))
444 return ((phys_addr_t)rom_pointer[0] - PHYS_SDRAM);
445 }
446
447 return sdram_b1_size;
448 } else {
449 return PHYS_SDRAM_SIZE;
450 }
451}
452
Peng Fanbbcd2c42022-07-26 16:40:39 +0800453void imx_get_mac_from_fuse(int dev_id, unsigned char *mac)
454{
Ye Li66baefb2023-04-28 12:08:21 +0800455 u32 val[2] = {};
456 int ret;
457
458 if (dev_id == 0) {
459 ret = fuse_read(39, 3, &val[0]);
460 if (ret)
461 goto err;
462
463 ret = fuse_read(39, 4, &val[1]);
464 if (ret)
465 goto err;
466
467 mac[0] = val[1] >> 8;
468 mac[1] = val[1];
469 mac[2] = val[0] >> 24;
470 mac[3] = val[0] >> 16;
471 mac[4] = val[0] >> 8;
472 mac[5] = val[0];
473
474 } else {
475 ret = fuse_read(39, 5, &val[0]);
476 if (ret)
477 goto err;
478
479 ret = fuse_read(39, 4, &val[1]);
480 if (ret)
481 goto err;
482
483 mac[0] = val[1] >> 24;
484 mac[1] = val[1] >> 16;
485 mac[2] = val[0] >> 24;
486 mac[3] = val[0] >> 16;
487 mac[4] = val[0] >> 8;
488 mac[5] = val[0];
489 }
490
491 debug("%s: MAC%d: %02x.%02x.%02x.%02x.%02x.%02x\n",
492 __func__, dev_id, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
493 return;
494err:
495 memset(mac, 0, 6);
496 printf("%s: fuse read err: %d\n", __func__, ret);
Peng Fanbbcd2c42022-07-26 16:40:39 +0800497}
498
499int print_cpuinfo(void)
500{
501 u32 cpurev;
502
503 cpurev = get_cpu_rev();
504
505 printf("CPU: i.MX93 rev%d.%d\n", (cpurev & 0x000F0) >> 4, (cpurev & 0x0000F) >> 0);
506
507 return 0;
508}
509
Primoz Fiserebbd4fc2024-01-11 13:56:25 +0100510static int fixup_thermal_trips(void *blob, const char *name)
511{
512 int minc, maxc;
513 int node, trip;
514
515 node = fdt_path_offset(blob, "/thermal-zones");
516 if (node < 0)
517 return node;
518
519 node = fdt_subnode_offset(blob, node, name);
520 if (node < 0)
521 return node;
522
523 node = fdt_subnode_offset(blob, node, "trips");
524 if (node < 0)
525 return node;
526
527 get_cpu_temp_grade(&minc, &maxc);
528
529 fdt_for_each_subnode(trip, blob, node) {
530 const char *type;
531 int temp, ret;
532
533 type = fdt_getprop(blob, trip, "type", NULL);
534 if (!type)
535 continue;
536
537 temp = 0;
538 if (!strcmp(type, "critical"))
Primoz Fiserab813e12024-08-13 14:12:17 +0200539 temp = 1000 * maxc;
Primoz Fiserebbd4fc2024-01-11 13:56:25 +0100540 else if (!strcmp(type, "passive"))
541 temp = 1000 * (maxc - 10);
542 if (temp) {
543 ret = fdt_setprop_u32(blob, trip, "temperature", temp);
544 if (ret)
545 return ret;
546 }
547 }
548
549 return 0;
550}
551
Peng Fanbbcd2c42022-07-26 16:40:39 +0800552int ft_system_setup(void *blob, struct bd_info *bd)
553{
Primoz Fiserebbd4fc2024-01-11 13:56:25 +0100554 if (fixup_thermal_trips(blob, "cpu-thermal"))
555 printf("Failed to update cpu-thermal trip(s)");
556
Peng Fanbbcd2c42022-07-26 16:40:39 +0800557 return 0;
558}
Peng Fan3700c472022-07-26 16:40:56 +0800559
560#if defined(CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG)
561void get_board_serial(struct tag_serialnr *serialnr)
562{
563 printf("UID: 0x%x 0x%x 0x%x 0x%x\n",
564 gd->arch.uid[0], gd->arch.uid[1], gd->arch.uid[2], gd->arch.uid[3]);
565
566 serialnr->low = gd->arch.uid[0];
567 serialnr->high = gd->arch.uid[3];
568}
569#endif
Peng Fanbbcd2c42022-07-26 16:40:39 +0800570
Peng Fanb1815c42023-04-28 12:08:27 +0800571static void save_reset_cause(void)
572{
573 struct src_general_regs *src = (struct src_general_regs *)SRC_GLOBAL_RBASE;
574 u32 srsr = readl(&src->srsr);
575
576 /* clear srsr in sec mode */
577 writel(srsr, &src->srsr);
578
579 /* Save value to GPR1 to pass to nonsecure */
580 writel(srsr, &src->gpr[0]);
581}
582
Peng Fanbbcd2c42022-07-26 16:40:39 +0800583int arch_cpu_init(void)
584{
Ye Li9e19ff92022-07-26 16:40:47 +0800585 if (IS_ENABLED(CONFIG_SPL_BUILD)) {
586 /* Disable wdog */
587 init_wdog();
588
Peng Fan28b5cb52022-07-26 16:40:43 +0800589 clock_init();
Ye Li62185922022-07-26 16:40:54 +0800590
591 trdc_early_init();
Peng Fanb1815c42023-04-28 12:08:27 +0800592
593 /* Save SRC SRSR to GPR1 and clear it */
594 save_reset_cause();
Ye Li9e19ff92022-07-26 16:40:47 +0800595 }
Peng Fan28b5cb52022-07-26 16:40:43 +0800596
Peng Fanbbcd2c42022-07-26 16:40:39 +0800597 return 0;
598}
Peng Fan3700c472022-07-26 16:40:56 +0800599
Simon Glassb8357c12023-08-21 21:16:56 -0600600int imx9_probe_mu(void)
Peng Fan3700c472022-07-26 16:40:56 +0800601{
602 struct udevice *devp;
603 int node, ret;
604 u32 res;
Peng Fand5c31832023-06-15 18:09:05 +0800605 struct ele_get_info_data info;
Peng Fan3700c472022-07-26 16:40:56 +0800606
607 node = fdt_node_offset_by_compatible(gd->fdt_blob, -1, "fsl,imx93-mu-s4");
608
609 ret = uclass_get_device_by_of_offset(UCLASS_MISC, node, &devp);
610 if (ret)
611 return ret;
612
613 if (gd->flags & GD_FLG_RELOC)
614 return 0;
615
Peng Fand5c31832023-06-15 18:09:05 +0800616 ret = ele_get_info(&info, &res);
Peng Fan3700c472022-07-26 16:40:56 +0800617 if (ret)
618 return ret;
619
620 set_cpu_info(&info);
621
622 return 0;
623}
Simon Glassb8357c12023-08-21 21:16:56 -0600624EVENT_SPY_SIMPLE(EVT_DM_POST_INIT_F, imx9_probe_mu);
Ye Lif41ffc12024-04-01 09:41:09 +0800625EVENT_SPY_SIMPLE(EVT_DM_POST_INIT_R, imx9_probe_mu);
Jian Liacf41a32022-07-26 16:40:46 +0800626
627int timer_init(void)
628{
629#ifdef CONFIG_SPL_BUILD
630 struct sctr_regs *sctr = (struct sctr_regs *)SYSCNT_CTRL_BASE_ADDR;
631 unsigned long freq = readl(&sctr->cntfid0);
632
633 /* Update with accurate clock frequency */
634 asm volatile("msr cntfrq_el0, %0" : : "r" (freq) : "memory");
635
636 clrsetbits_le32(&sctr->cntcr, SC_CNTCR_FREQ0 | SC_CNTCR_FREQ1,
637 SC_CNTCR_FREQ0 | SC_CNTCR_ENABLE | SC_CNTCR_HDBG);
638#endif
639
640 gd->arch.tbl = 0;
641 gd->arch.tbu = 0;
642
643 return 0;
644}
Peng Fan65563792022-07-26 16:41:02 +0800645
Ye Li8e8687c2022-07-26 16:41:05 +0800646enum env_location env_get_location(enum env_operation op, int prio)
647{
648 enum boot_device dev = get_boot_device();
Ye Li8e8687c2022-07-26 16:41:05 +0800649
650 if (prio)
Oleksandr Suvoroveff7c8d2023-04-11 20:27:41 +0300651 return ENVL_UNKNOWN;
Ye Li8e8687c2022-07-26 16:41:05 +0800652
653 switch (dev) {
Ye Li8e8687c2022-07-26 16:41:05 +0800654 case QSPI_BOOT:
Oleksandr Suvoroveff7c8d2023-04-11 20:27:41 +0300655 if (CONFIG_IS_ENABLED(ENV_IS_IN_SPI_FLASH))
656 return ENVL_SPI_FLASH;
657 return ENVL_NOWHERE;
Ye Li8e8687c2022-07-26 16:41:05 +0800658 case SD1_BOOT:
659 case SD2_BOOT:
660 case SD3_BOOT:
661 case MMC1_BOOT:
662 case MMC2_BOOT:
663 case MMC3_BOOT:
Oleksandr Suvoroveff7c8d2023-04-11 20:27:41 +0300664 if (CONFIG_IS_ENABLED(ENV_IS_IN_MMC))
665 return ENVL_MMC;
666 else if (CONFIG_IS_ENABLED(ENV_IS_IN_EXT4))
667 return ENVL_EXT4;
668 else if (CONFIG_IS_ENABLED(ENV_IS_IN_FAT))
669 return ENVL_FAT;
670 return ENVL_NOWHERE;
Ye Li8e8687c2022-07-26 16:41:05 +0800671 default:
Oleksandr Suvoroveff7c8d2023-04-11 20:27:41 +0300672 return ENVL_NOWHERE;
Ye Li8e8687c2022-07-26 16:41:05 +0800673 }
Ye Li8e8687c2022-07-26 16:41:05 +0800674}
675
Peng Fan65563792022-07-26 16:41:02 +0800676static int mix_power_init(enum mix_power_domain pd)
677{
678 enum src_mix_slice_id mix_id;
679 enum src_mem_slice_id mem_id;
680 struct src_mix_slice_regs *mix_regs;
681 struct src_mem_slice_regs *mem_regs;
682 struct src_general_regs *global_regs;
683 u32 scr, val;
684
685 switch (pd) {
686 case MIX_PD_MEDIAMIX:
687 mix_id = SRC_MIX_MEDIA;
688 mem_id = SRC_MEM_MEDIA;
689 scr = BIT(5);
690
Peng Fand5c31832023-06-15 18:09:05 +0800691 /* Enable ELE handshake */
Peng Fan65563792022-07-26 16:41:02 +0800692 struct blk_ctrl_s_aonmix_regs *s_regs =
693 (struct blk_ctrl_s_aonmix_regs *)BLK_CTRL_S_ANOMIX_BASE_ADDR;
694
695 setbits_le32(&s_regs->lp_handshake[0], BIT(13));
696 break;
697 case MIX_PD_MLMIX:
698 mix_id = SRC_MIX_ML;
699 mem_id = SRC_MEM_ML;
700 scr = BIT(4);
701 break;
702 case MIX_PD_DDRMIX:
703 mix_id = SRC_MIX_DDRMIX;
704 mem_id = SRC_MEM_DDRMIX;
705 scr = BIT(6);
706 break;
707 default:
708 return -EINVAL;
709 }
710
711 mix_regs = (struct src_mix_slice_regs *)(ulong)(SRC_IPS_BASE_ADDR + 0x400 * (mix_id + 1));
712 mem_regs =
713 (struct src_mem_slice_regs *)(ulong)(SRC_IPS_BASE_ADDR + 0x3800 + 0x400 * mem_id);
714 global_regs = (struct src_general_regs *)(ulong)SRC_GLOBAL_RBASE;
715
716 /* Allow NS to set it */
717 setbits_le32(&mix_regs->authen_ctrl, BIT(9));
718
719 clrsetbits_le32(&mix_regs->psw_ack_ctrl[0], BIT(28), BIT(29));
720
721 /* mix reset will be held until boot core write this bit to 1 */
722 setbits_le32(&global_regs->scr, scr);
723
724 /* Enable mem in Low power auto sequence */
725 setbits_le32(&mem_regs->mem_ctrl, BIT(2));
726
727 /* Set the power down state */
728 val = readl(&mix_regs->func_stat);
729 if (val & SRC_MIX_SLICE_FUNC_STAT_PSW_STAT) {
730 /* The mix is default power off, power down it to make PDN_SFT bit
731 * aligned with FUNC STAT
732 */
733 setbits_le32(&mix_regs->slice_sw_ctrl, BIT(31));
734 val = readl(&mix_regs->func_stat);
735
736 /* Since PSW_STAT is 1, can't be used for power off status (SW_CTRL BIT31 set)) */
737 /* Check the MEM STAT change to ensure SSAR is completed */
738 while (!(val & SRC_MIX_SLICE_FUNC_STAT_MEM_STAT))
739 val = readl(&mix_regs->func_stat);
740
741 /* wait few ipg clock cycles to ensure FSM done and power off status is correct */
742 /* About 5 cycles at 24Mhz, 1us is enough */
743 udelay(1);
744 } else {
745 /* The mix is default power on, Do mix power cycle */
746 setbits_le32(&mix_regs->slice_sw_ctrl, BIT(31));
747 val = readl(&mix_regs->func_stat);
748 while (!(val & SRC_MIX_SLICE_FUNC_STAT_PSW_STAT))
749 val = readl(&mix_regs->func_stat);
750 }
751
752 /* power on */
753 clrbits_le32(&mix_regs->slice_sw_ctrl, BIT(31));
754 val = readl(&mix_regs->func_stat);
Peng Fan06e78ff2024-09-19 12:01:19 +0800755 while (val & SRC_MIX_SLICE_FUNC_STAT_SSAR_STAT)
Peng Fan65563792022-07-26 16:41:02 +0800756 val = readl(&mix_regs->func_stat);
757
758 return 0;
759}
760
761void disable_isolation(void)
762{
763 struct src_general_regs *global_regs = (struct src_general_regs *)(ulong)SRC_GLOBAL_RBASE;
764 /* clear isolation for usbphy, dsi, csi*/
765 writel(0x0, &global_regs->sp_iso_ctrl);
766}
767
768void soc_power_init(void)
769{
770 mix_power_init(MIX_PD_MEDIAMIX);
771 mix_power_init(MIX_PD_MLMIX);
772
773 disable_isolation();
774}
Peng Fan6d929962022-07-26 16:41:03 +0800775
Peng Fan313af252022-07-26 16:41:04 +0800776bool m33_is_rom_kicked(void)
Peng Fan6d929962022-07-26 16:41:03 +0800777{
778 struct blk_ctrl_s_aonmix_regs *s_regs =
779 (struct blk_ctrl_s_aonmix_regs *)BLK_CTRL_S_ANOMIX_BASE_ADDR;
780
781 if (!(readl(&s_regs->m33_cfg) & BIT(2)))
782 return true;
783
784 return false;
785}
786
787int m33_prepare(void)
788{
789 struct src_mix_slice_regs *mix_regs =
790 (struct src_mix_slice_regs *)(ulong)(SRC_IPS_BASE_ADDR + 0x400 * (SRC_MIX_CM33 + 1));
791 struct src_general_regs *global_regs =
792 (struct src_general_regs *)(ulong)SRC_GLOBAL_RBASE;
793 struct blk_ctrl_s_aonmix_regs *s_regs =
794 (struct blk_ctrl_s_aonmix_regs *)BLK_CTRL_S_ANOMIX_BASE_ADDR;
Ye Li0667ec92024-09-19 12:01:20 +0800795 u32 val, i;
Peng Fan6d929962022-07-26 16:41:03 +0800796
797 if (m33_is_rom_kicked())
798 return -EPERM;
799
800 /* Release reset of M33 */
801 setbits_le32(&global_regs->scr, BIT(0));
802
803 /* Check the reset released in M33 MIX func stat */
804 val = readl(&mix_regs->func_stat);
805 while (!(val & SRC_MIX_SLICE_FUNC_STAT_RST_STAT))
806 val = readl(&mix_regs->func_stat);
807
Peng Fand5c31832023-06-15 18:09:05 +0800808 /* Release ELE TROUT */
809 ele_release_m33_trout();
Peng Fan6d929962022-07-26 16:41:03 +0800810
811 /* Mask WDOG1 IRQ from A55, we use it for M33 reset */
812 setbits_le32(&s_regs->ca55_irq_mask[1], BIT(6));
813
814 /* Turn on WDOG1 clock */
815 ccm_lpcg_on(CCGR_WDG1, 1);
816
Peng Fand5c31832023-06-15 18:09:05 +0800817 /* Set ELE LP handshake for M33 reset */
Peng Fan6d929962022-07-26 16:41:03 +0800818 setbits_le32(&s_regs->lp_handshake[0], BIT(6));
819
Ye Li0667ec92024-09-19 12:01:20 +0800820 /* OSCCA enabled, reconfigure TRDC for TCM access, otherwise ECC init will raise error */
821 val = readl(BLK_CTRL_NS_ANOMIX_BASE_ADDR + 0x28);
822 if (val & BIT(0)) {
823 trdc_mbc_set_control(0x44270000, 1, 0, 0x6600);
824
825 for (i = 0; i < 32; i++)
826 trdc_mbc_blk_config(0x44270000, 1, 3, 0, i, true, 0);
827
828 for (i = 0; i < 32; i++)
829 trdc_mbc_blk_config(0x44270000, 1, 3, 1, i, true, 0);
830 }
831
Peng Fan6d929962022-07-26 16:41:03 +0800832 /* Clear M33 TCM for ECC */
833 memset((void *)(ulong)0x201e0000, 0, 0x40000);
834
835 return 0;
836}
Peng Fanb1815c42023-04-28 12:08:27 +0800837
838int psci_sysreset_get_status(struct udevice *dev, char *buf, int size)
839{
840 static const char *reset_cause[] = {
841 "POR ",
842 "JTAG ",
843 "IPP USER ",
844 "WDOG1 ",
845 "WDOG2 ",
846 "WDOG3 ",
847 "WDOG4 ",
848 "WDOG5 ",
849 "TEMPSENSE ",
850 "CSU ",
851 "JTAG_SW ",
852 "M33_REQ ",
853 "M33_LOCKUP ",
854 "UNK ",
855 "UNK ",
856 "UNK "
857 };
858
859 struct src_general_regs *src = (struct src_general_regs *)SRC_GLOBAL_RBASE;
860 u32 srsr;
861 u32 i;
862 int res;
863
864 srsr = readl(&src->gpr[0]);
865
866 for (i = ARRAY_SIZE(reset_cause); i > 0; i--) {
867 if (srsr & (BIT(i - 1)))
868 break;
869 }
870
871 res = snprintf(buf, size, "Reset Status: %s\n", i ? reset_cause[i - 1] : "unknown reset");
872 if (res < 0) {
873 dev_err(dev, "Could not write reset status message (err = %d)\n", res);
874 return -EIO;
875 }
876
877 return 0;
878}