blob: f06339f13880d116f2ae1578f52050bc22dd479f [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
8#include <common.h>
9#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,
265 .size = 0x30000000UL,
266 .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"))
539 temp = 1000 * (maxc - 5);
540 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);
Jian Liacf41a32022-07-26 16:40:46 +0800625
626int timer_init(void)
627{
628#ifdef CONFIG_SPL_BUILD
629 struct sctr_regs *sctr = (struct sctr_regs *)SYSCNT_CTRL_BASE_ADDR;
630 unsigned long freq = readl(&sctr->cntfid0);
631
632 /* Update with accurate clock frequency */
633 asm volatile("msr cntfrq_el0, %0" : : "r" (freq) : "memory");
634
635 clrsetbits_le32(&sctr->cntcr, SC_CNTCR_FREQ0 | SC_CNTCR_FREQ1,
636 SC_CNTCR_FREQ0 | SC_CNTCR_ENABLE | SC_CNTCR_HDBG);
637#endif
638
639 gd->arch.tbl = 0;
640 gd->arch.tbu = 0;
641
642 return 0;
643}
Peng Fan65563792022-07-26 16:41:02 +0800644
Ye Li8e8687c2022-07-26 16:41:05 +0800645enum env_location env_get_location(enum env_operation op, int prio)
646{
647 enum boot_device dev = get_boot_device();
Ye Li8e8687c2022-07-26 16:41:05 +0800648
649 if (prio)
Oleksandr Suvoroveff7c8d2023-04-11 20:27:41 +0300650 return ENVL_UNKNOWN;
Ye Li8e8687c2022-07-26 16:41:05 +0800651
652 switch (dev) {
Ye Li8e8687c2022-07-26 16:41:05 +0800653 case QSPI_BOOT:
Oleksandr Suvoroveff7c8d2023-04-11 20:27:41 +0300654 if (CONFIG_IS_ENABLED(ENV_IS_IN_SPI_FLASH))
655 return ENVL_SPI_FLASH;
656 return ENVL_NOWHERE;
Ye Li8e8687c2022-07-26 16:41:05 +0800657 case SD1_BOOT:
658 case SD2_BOOT:
659 case SD3_BOOT:
660 case MMC1_BOOT:
661 case MMC2_BOOT:
662 case MMC3_BOOT:
Oleksandr Suvoroveff7c8d2023-04-11 20:27:41 +0300663 if (CONFIG_IS_ENABLED(ENV_IS_IN_MMC))
664 return ENVL_MMC;
665 else if (CONFIG_IS_ENABLED(ENV_IS_IN_EXT4))
666 return ENVL_EXT4;
667 else if (CONFIG_IS_ENABLED(ENV_IS_IN_FAT))
668 return ENVL_FAT;
669 return ENVL_NOWHERE;
Ye Li8e8687c2022-07-26 16:41:05 +0800670 default:
Oleksandr Suvoroveff7c8d2023-04-11 20:27:41 +0300671 return ENVL_NOWHERE;
Ye Li8e8687c2022-07-26 16:41:05 +0800672 }
Ye Li8e8687c2022-07-26 16:41:05 +0800673}
674
Peng Fan65563792022-07-26 16:41:02 +0800675static int mix_power_init(enum mix_power_domain pd)
676{
677 enum src_mix_slice_id mix_id;
678 enum src_mem_slice_id mem_id;
679 struct src_mix_slice_regs *mix_regs;
680 struct src_mem_slice_regs *mem_regs;
681 struct src_general_regs *global_regs;
682 u32 scr, val;
683
684 switch (pd) {
685 case MIX_PD_MEDIAMIX:
686 mix_id = SRC_MIX_MEDIA;
687 mem_id = SRC_MEM_MEDIA;
688 scr = BIT(5);
689
Peng Fand5c31832023-06-15 18:09:05 +0800690 /* Enable ELE handshake */
Peng Fan65563792022-07-26 16:41:02 +0800691 struct blk_ctrl_s_aonmix_regs *s_regs =
692 (struct blk_ctrl_s_aonmix_regs *)BLK_CTRL_S_ANOMIX_BASE_ADDR;
693
694 setbits_le32(&s_regs->lp_handshake[0], BIT(13));
695 break;
696 case MIX_PD_MLMIX:
697 mix_id = SRC_MIX_ML;
698 mem_id = SRC_MEM_ML;
699 scr = BIT(4);
700 break;
701 case MIX_PD_DDRMIX:
702 mix_id = SRC_MIX_DDRMIX;
703 mem_id = SRC_MEM_DDRMIX;
704 scr = BIT(6);
705 break;
706 default:
707 return -EINVAL;
708 }
709
710 mix_regs = (struct src_mix_slice_regs *)(ulong)(SRC_IPS_BASE_ADDR + 0x400 * (mix_id + 1));
711 mem_regs =
712 (struct src_mem_slice_regs *)(ulong)(SRC_IPS_BASE_ADDR + 0x3800 + 0x400 * mem_id);
713 global_regs = (struct src_general_regs *)(ulong)SRC_GLOBAL_RBASE;
714
715 /* Allow NS to set it */
716 setbits_le32(&mix_regs->authen_ctrl, BIT(9));
717
718 clrsetbits_le32(&mix_regs->psw_ack_ctrl[0], BIT(28), BIT(29));
719
720 /* mix reset will be held until boot core write this bit to 1 */
721 setbits_le32(&global_regs->scr, scr);
722
723 /* Enable mem in Low power auto sequence */
724 setbits_le32(&mem_regs->mem_ctrl, BIT(2));
725
726 /* Set the power down state */
727 val = readl(&mix_regs->func_stat);
728 if (val & SRC_MIX_SLICE_FUNC_STAT_PSW_STAT) {
729 /* The mix is default power off, power down it to make PDN_SFT bit
730 * aligned with FUNC STAT
731 */
732 setbits_le32(&mix_regs->slice_sw_ctrl, BIT(31));
733 val = readl(&mix_regs->func_stat);
734
735 /* Since PSW_STAT is 1, can't be used for power off status (SW_CTRL BIT31 set)) */
736 /* Check the MEM STAT change to ensure SSAR is completed */
737 while (!(val & SRC_MIX_SLICE_FUNC_STAT_MEM_STAT))
738 val = readl(&mix_regs->func_stat);
739
740 /* wait few ipg clock cycles to ensure FSM done and power off status is correct */
741 /* About 5 cycles at 24Mhz, 1us is enough */
742 udelay(1);
743 } else {
744 /* The mix is default power on, Do mix power cycle */
745 setbits_le32(&mix_regs->slice_sw_ctrl, BIT(31));
746 val = readl(&mix_regs->func_stat);
747 while (!(val & SRC_MIX_SLICE_FUNC_STAT_PSW_STAT))
748 val = readl(&mix_regs->func_stat);
749 }
750
751 /* power on */
752 clrbits_le32(&mix_regs->slice_sw_ctrl, BIT(31));
753 val = readl(&mix_regs->func_stat);
754 while (val & SRC_MIX_SLICE_FUNC_STAT_ISO_STAT)
755 val = readl(&mix_regs->func_stat);
756
757 return 0;
758}
759
760void disable_isolation(void)
761{
762 struct src_general_regs *global_regs = (struct src_general_regs *)(ulong)SRC_GLOBAL_RBASE;
763 /* clear isolation for usbphy, dsi, csi*/
764 writel(0x0, &global_regs->sp_iso_ctrl);
765}
766
767void soc_power_init(void)
768{
769 mix_power_init(MIX_PD_MEDIAMIX);
770 mix_power_init(MIX_PD_MLMIX);
771
772 disable_isolation();
773}
Peng Fan6d929962022-07-26 16:41:03 +0800774
Peng Fan313af252022-07-26 16:41:04 +0800775bool m33_is_rom_kicked(void)
Peng Fan6d929962022-07-26 16:41:03 +0800776{
777 struct blk_ctrl_s_aonmix_regs *s_regs =
778 (struct blk_ctrl_s_aonmix_regs *)BLK_CTRL_S_ANOMIX_BASE_ADDR;
779
780 if (!(readl(&s_regs->m33_cfg) & BIT(2)))
781 return true;
782
783 return false;
784}
785
786int m33_prepare(void)
787{
788 struct src_mix_slice_regs *mix_regs =
789 (struct src_mix_slice_regs *)(ulong)(SRC_IPS_BASE_ADDR + 0x400 * (SRC_MIX_CM33 + 1));
790 struct src_general_regs *global_regs =
791 (struct src_general_regs *)(ulong)SRC_GLOBAL_RBASE;
792 struct blk_ctrl_s_aonmix_regs *s_regs =
793 (struct blk_ctrl_s_aonmix_regs *)BLK_CTRL_S_ANOMIX_BASE_ADDR;
794 u32 val;
795
796 if (m33_is_rom_kicked())
797 return -EPERM;
798
799 /* Release reset of M33 */
800 setbits_le32(&global_regs->scr, BIT(0));
801
802 /* Check the reset released in M33 MIX func stat */
803 val = readl(&mix_regs->func_stat);
804 while (!(val & SRC_MIX_SLICE_FUNC_STAT_RST_STAT))
805 val = readl(&mix_regs->func_stat);
806
Peng Fand5c31832023-06-15 18:09:05 +0800807 /* Release ELE TROUT */
808 ele_release_m33_trout();
Peng Fan6d929962022-07-26 16:41:03 +0800809
810 /* Mask WDOG1 IRQ from A55, we use it for M33 reset */
811 setbits_le32(&s_regs->ca55_irq_mask[1], BIT(6));
812
813 /* Turn on WDOG1 clock */
814 ccm_lpcg_on(CCGR_WDG1, 1);
815
Peng Fand5c31832023-06-15 18:09:05 +0800816 /* Set ELE LP handshake for M33 reset */
Peng Fan6d929962022-07-26 16:41:03 +0800817 setbits_le32(&s_regs->lp_handshake[0], BIT(6));
818
819 /* Clear M33 TCM for ECC */
820 memset((void *)(ulong)0x201e0000, 0, 0x40000);
821
822 return 0;
823}
Peng Fanb1815c42023-04-28 12:08:27 +0800824
825int psci_sysreset_get_status(struct udevice *dev, char *buf, int size)
826{
827 static const char *reset_cause[] = {
828 "POR ",
829 "JTAG ",
830 "IPP USER ",
831 "WDOG1 ",
832 "WDOG2 ",
833 "WDOG3 ",
834 "WDOG4 ",
835 "WDOG5 ",
836 "TEMPSENSE ",
837 "CSU ",
838 "JTAG_SW ",
839 "M33_REQ ",
840 "M33_LOCKUP ",
841 "UNK ",
842 "UNK ",
843 "UNK "
844 };
845
846 struct src_general_regs *src = (struct src_general_regs *)SRC_GLOBAL_RBASE;
847 u32 srsr;
848 u32 i;
849 int res;
850
851 srsr = readl(&src->gpr[0]);
852
853 for (i = ARRAY_SIZE(reset_cause); i > 0; i--) {
854 if (srsr & (BIT(i - 1)))
855 break;
856 }
857
858 res = snprintf(buf, size, "Reset Status: %s\n", i ? reset_cause[i - 1] : "unknown reset");
859 if (res < 0) {
860 dev_err(dev, "Could not write reset status message (err = %d)\n", res);
861 return -EIO;
862 }
863
864 return 0;
865}