blob: 21e0e7dd1e8064d2cda222060c8dda1d7fce2e2d [file] [log] [blame]
Peng Fanbbcd2c42022-07-26 16:40:39 +08001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2022 NXP
4 *
5 * Peng Fan <peng.fan@nxp.com>
6 */
7
Tom Rinidec7ea02024-05-20 13:35:03 -06008#include <config.h>
Peng Fanbbcd2c42022-07-26 16:40:39 +08009#include <cpu_func.h>
10#include <init.h>
11#include <log.h>
12#include <asm/arch/imx-regs.h>
13#include <asm/global_data.h>
14#include <asm/io.h>
15#include <asm/arch/clock.h>
Peng Fan6d929962022-07-26 16:41:03 +080016#include <asm/arch/ccm_regs.h>
Peng Fanbbcd2c42022-07-26 16:40:39 +080017#include <asm/arch/sys_proto.h>
Ye Li62185922022-07-26 16:40:54 +080018#include <asm/arch/trdc.h>
Peng Fanbbcd2c42022-07-26 16:40:39 +080019#include <asm/mach-imx/boot_mode.h>
20#include <asm/mach-imx/syscounter.h>
21#include <asm/armv8/mmu.h>
Peng Fanb1815c42023-04-28 12:08:27 +080022#include <dm/device.h>
23#include <dm/device_compat.h>
Peng Fanbbcd2c42022-07-26 16:40:39 +080024#include <dm/uclass.h>
25#include <env.h>
26#include <env_internal.h>
27#include <errno.h>
28#include <fdt_support.h>
Peng Fan0c2f3682023-04-28 12:08:28 +080029#include <imx_thermal.h>
Peng Fanbbcd2c42022-07-26 16:40:39 +080030#include <linux/bitops.h>
Peng Fan0c2f3682023-04-28 12:08:28 +080031#include <linux/bitfield.h>
32#include <linux/delay.h>
33#include <thermal.h>
Peng Fanbbcd2c42022-07-26 16:40:39 +080034#include <asm/setup.h>
35#include <asm/bootm.h>
36#include <asm/arch-imx/cpu.h>
Peng Fand5c31832023-06-15 18:09:05 +080037#include <asm/mach-imx/ele_api.h>
Ye Li66baefb2023-04-28 12:08:21 +080038#include <fuse.h>
Ye Libb1187b2023-04-28 12:08:45 +080039#include <asm/arch/ddr.h>
Peng Fanbbcd2c42022-07-26 16:40:39 +080040
41DECLARE_GLOBAL_DATA_PTR;
42
Peng Fan5de0fc02022-07-26 16:40:48 +080043struct rom_api *g_rom_api = (struct rom_api *)0x1980;
44
Benjamin Szőke4a671072024-11-01 16:26:18 +010045#if CONFIG_IS_ENABLED(ENV_IS_IN_MMC) || CONFIG_IS_ENABLED(ENV_IS_NOWHERE)
Peng Fan5de0fc02022-07-26 16:40:48 +080046__weak int board_mmc_get_env_dev(int devno)
47{
Peng Fan77b36c62023-04-28 12:08:33 +080048 return devno;
49}
Peng Fan5de0fc02022-07-26 16:40:48 +080050
Benjamin Szőke4a671072024-11-01 16:26:18 +010051#ifdef CONFIG_SYS_MMC_ENV_DEV
52#define IMX9_MMC_ENV_DEV CONFIG_SYS_MMC_ENV_DEV
53#else
54#define IMX9_MMC_ENV_DEV 0
55#endif
56
Peng Fan5de0fc02022-07-26 16:40:48 +080057int mmc_get_env_dev(void)
58{
Peng Fan5de0fc02022-07-26 16:40:48 +080059 int ret;
60 u32 boot;
61 u16 boot_type;
62 u8 boot_instance;
63
Peng Fanc459b582023-04-28 12:08:34 +080064 ret = rom_api_query_boot_infor(QUERY_BT_DEV, &boot);
Peng Fan5de0fc02022-07-26 16:40:48 +080065
66 if (ret != ROM_API_OKAY) {
67 puts("ROMAPI: failure at query_boot_info\n");
Benjamin Szőke4a671072024-11-01 16:26:18 +010068 return IMX9_MMC_ENV_DEV;
Peng Fan5de0fc02022-07-26 16:40:48 +080069 }
70
71 boot_type = boot >> 16;
72 boot_instance = (boot >> 8) & 0xff;
73
74 debug("boot_type %d, instance %d\n", boot_type, boot_instance);
75
76 /* If not boot from sd/mmc, use default value */
77 if (boot_type != BOOT_TYPE_SD && boot_type != BOOT_TYPE_MMC)
Benjamin Szőke4a671072024-11-01 16:26:18 +010078 return env_get_ulong("mmcdev", 10, IMX9_MMC_ENV_DEV);
Peng Fan5de0fc02022-07-26 16:40:48 +080079
80 return board_mmc_get_env_dev(boot_instance);
81}
82#endif
83
Peng Fan0c2f3682023-04-28 12:08:28 +080084/*
85 * SPEED_GRADE[5:4] SPEED_GRADE[3:0] MHz
86 * xx 0000 2300
87 * xx 0001 2200
88 * xx 0010 2100
89 * xx 0011 2000
90 * xx 0100 1900
91 * xx 0101 1800
92 * xx 0110 1700
93 * xx 0111 1600
94 * xx 1000 1500
95 * xx 1001 1400
96 * xx 1010 1300
97 * xx 1011 1200
98 * xx 1100 1100
99 * xx 1101 1000
100 * xx 1110 900
101 * xx 1111 800
102 */
103u32 get_cpu_speed_grade_hz(void)
104{
Peng Fan43126e12024-09-19 12:01:23 +0800105 int ret;
106 u32 bank, word, speed, max_speed;
Peng Fan0c2f3682023-04-28 12:08:28 +0800107 u32 val;
108
Peng Fan43126e12024-09-19 12:01:23 +0800109 bank = HW_CFG1 / NUM_WORDS_PER_BANK;
110 word = HW_CFG1 % NUM_WORDS_PER_BANK;
111 ret = fuse_read(bank, word, &val);
112 if (ret)
113 val = 0; /* If read fuse failed, return as blank fuse */
114
Peng Fan0c2f3682023-04-28 12:08:28 +0800115 val = FIELD_GET(SPEED_GRADING_MASK, val) & 0xF;
116
117 speed = MHZ(2300) - val * MHZ(100);
118
119 if (is_imx93())
120 max_speed = MHZ(1700);
121
122 /* In case the fuse of speed grade not programmed */
123 if (speed > max_speed)
124 speed = max_speed;
125
126 return speed;
127}
128
129/*
130 * `00` - Consumer 0C to 95C
131 * `01` - Ext. Consumer -20C to 105C
132 * `10` - Industrial -40C to 105C
133 * `11` - Automotive -40C to 125C
134 */
135u32 get_cpu_temp_grade(int *minc, int *maxc)
136{
Peng Fan43126e12024-09-19 12:01:23 +0800137 int ret;
138 u32 bank, word, val;
139
140 bank = HW_CFG1 / NUM_WORDS_PER_BANK;
141 word = HW_CFG1 % NUM_WORDS_PER_BANK;
142 ret = fuse_read(bank, word, &val);
143 if (ret)
144 val = 0; /* If read fuse failed, return as blank fuse */
Peng Fan0c2f3682023-04-28 12:08:28 +0800145
Peng Fan0c2f3682023-04-28 12:08:28 +0800146 val = FIELD_GET(MARKETING_GRADING_MASK, val);
147
148 if (minc && maxc) {
149 if (val == TEMP_AUTOMOTIVE) {
150 *minc = -40;
151 *maxc = 125;
152 } else if (val == TEMP_INDUSTRIAL) {
153 *minc = -40;
154 *maxc = 105;
155 } else if (val == TEMP_EXTCOMMERCIAL) {
156 if (is_imx93()) {
157 /* imx93 only has extended industrial*/
158 *minc = -40;
159 *maxc = 125;
160 } else {
161 *minc = -20;
162 *maxc = 105;
163 }
164 } else {
165 *minc = 0;
166 *maxc = 95;
167 }
168 }
169 return val;
170}
171
Peng Fand5c31832023-06-15 18:09:05 +0800172static void set_cpu_info(struct ele_get_info_data *info)
Peng Fan3700c472022-07-26 16:40:56 +0800173{
174 gd->arch.soc_rev = info->soc;
175 gd->arch.lifecycle = info->lc;
176 memcpy((void *)&gd->arch.uid, &info->uid, 4 * sizeof(u32));
177}
178
Peng Fanc3db3ad2023-04-28 12:08:32 +0800179static u32 get_cpu_variant_type(u32 type)
180{
Peng Fan43126e12024-09-19 12:01:23 +0800181 u32 bank, word, val, val2;
182 int ret;
183
184 bank = HW_CFG1 / NUM_WORDS_PER_BANK;
185 word = HW_CFG1 % NUM_WORDS_PER_BANK;
186 ret = fuse_read(bank, word, &val);
187 if (ret)
188 val = 0; /* If read fuse failed, return as blank fuse */
189
190 bank = HW_CFG2 / NUM_WORDS_PER_BANK;
191 word = HW_CFG2 % NUM_WORDS_PER_BANK;
192 ret = fuse_read(bank, word, &val2);
193 if (ret)
194 val2 = 0; /* If read fuse failed, return as blank fuse */
195
Peng Fanc3db3ad2023-04-28 12:08:32 +0800196 bool npu_disable = !!(val & BIT(13));
197 bool core1_disable = !!(val & BIT(15));
198 u32 pack_9x9_fused = BIT(4) | BIT(17) | BIT(19) | BIT(24);
199
Ye Li57b2ac42024-09-19 12:01:33 +0800200 /* Low performance 93 part */
201 if (((val >> 6) & 0x3F) == 0xE && npu_disable)
202 return core1_disable ? MXC_CPU_IMX9301 : MXC_CPU_IMX9302;
203
Peng Fanc3db3ad2023-04-28 12:08:32 +0800204 if ((val2 & pack_9x9_fused) == pack_9x9_fused)
205 type = MXC_CPU_IMX9322;
206
207 if (npu_disable && core1_disable)
208 return type + 3;
209 else if (npu_disable)
210 return type + 2;
211 else if (core1_disable)
212 return type + 1;
213
214 return type;
215}
216
Peng Fanbbcd2c42022-07-26 16:40:39 +0800217u32 get_cpu_rev(void)
218{
Peng Fan3700c472022-07-26 16:40:56 +0800219 u32 rev = (gd->arch.soc_rev >> 24) - 0xa0;
220
Peng Fanc3db3ad2023-04-28 12:08:32 +0800221 return (get_cpu_variant_type(MXC_CPU_IMX93) << 12) |
222 (CHIP_REV_1_0 + rev);
Peng Fanbbcd2c42022-07-26 16:40:39 +0800223}
224
Ye Li9e19ff92022-07-26 16:40:47 +0800225#define UNLOCK_WORD 0xD928C520 /* unlock word */
226#define REFRESH_WORD 0xB480A602 /* refresh word */
227
228static void disable_wdog(void __iomem *wdog_base)
229{
230 u32 val_cs = readl(wdog_base + 0x00);
231
232 if (!(val_cs & 0x80))
233 return;
234
235 /* default is 32bits cmd */
236 writel(REFRESH_WORD, (wdog_base + 0x04)); /* Refresh the CNT */
237
238 if (!(val_cs & 0x800)) {
239 writel(UNLOCK_WORD, (wdog_base + 0x04));
240 while (!(readl(wdog_base + 0x00) & 0x800))
241 ;
242 }
243 writel(0x0, (wdog_base + 0x0C)); /* Set WIN to 0 */
244 writel(0x400, (wdog_base + 0x08)); /* Set timeout to default 0x400 */
245 writel(0x2120, (wdog_base + 0x00)); /* Disable it and set update */
246
247 while (!(readl(wdog_base + 0x00) & 0x400))
248 ;
249}
250
251void init_wdog(void)
252{
Ye Li9e19ff92022-07-26 16:40:47 +0800253 disable_wdog((void __iomem *)WDG3_BASE_ADDR);
254 disable_wdog((void __iomem *)WDG4_BASE_ADDR);
255 disable_wdog((void __iomem *)WDG5_BASE_ADDR);
Ye Li9e19ff92022-07-26 16:40:47 +0800256}
257
Peng Fanbbcd2c42022-07-26 16:40:39 +0800258static struct mm_region imx93_mem_map[] = {
259 {
260 /* ROM */
261 .virt = 0x0UL,
262 .phys = 0x0UL,
263 .size = 0x100000UL,
264 .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
265 PTE_BLOCK_OUTER_SHARE
266 }, {
Peng Fan313af252022-07-26 16:41:04 +0800267 /* TCM */
268 .virt = 0x201c0000UL,
269 .phys = 0x201c0000UL,
270 .size = 0x80000UL,
271 .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
272 PTE_BLOCK_NON_SHARE |
273 PTE_BLOCK_PXN | PTE_BLOCK_UXN
274 }, {
Peng Fanbbcd2c42022-07-26 16:40:39 +0800275 /* OCRAM */
276 .virt = 0x20480000UL,
277 .phys = 0x20480000UL,
278 .size = 0xA0000UL,
279 .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
280 PTE_BLOCK_OUTER_SHARE
281 }, {
282 /* AIPS */
283 .virt = 0x40000000UL,
284 .phys = 0x40000000UL,
285 .size = 0x40000000UL,
286 .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
287 PTE_BLOCK_NON_SHARE |
288 PTE_BLOCK_PXN | PTE_BLOCK_UXN
289 }, {
290 /* Flexible Serial Peripheral Interface */
291 .virt = 0x28000000UL,
292 .phys = 0x28000000UL,
Ye Li35f15512024-03-28 18:49:18 +0800293 .size = 0x08000000UL,
Peng Fanbbcd2c42022-07-26 16:40:39 +0800294 .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
295 PTE_BLOCK_NON_SHARE |
296 PTE_BLOCK_PXN | PTE_BLOCK_UXN
297 }, {
298 /* DRAM1 */
299 .virt = 0x80000000UL,
300 .phys = 0x80000000UL,
301 .size = PHYS_SDRAM_SIZE,
302 .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
303 PTE_BLOCK_OUTER_SHARE
304 }, {
305 /* empty entrie to split table entry 5 if needed when TEEs are used */
306 0,
307 }, {
308 /* List terminator */
309 0,
310 }
311};
312
313struct mm_region *mem_map = imx93_mem_map;
314
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800315static unsigned int imx9_find_dram_entry_in_mem_map(void)
316{
317 int i;
318
319 for (i = 0; i < ARRAY_SIZE(imx93_mem_map); i++)
320 if (imx93_mem_map[i].phys == CFG_SYS_SDRAM_BASE)
321 return i;
322
323 hang(); /* Entry not found, this must never happen. */
324}
325
326void enable_caches(void)
327{
328 /* If OPTEE runs, remove OPTEE memory from MMU table to avoid speculative prefetch
329 * If OPTEE does not run, still update the MMU table according to dram banks structure
330 * to set correct dram size from board_phys_sdram_size
331 */
332 int i = 0;
333 /*
334 * please make sure that entry initial value matches
335 * imx93_mem_map for DRAM1
336 */
337 int entry = imx9_find_dram_entry_in_mem_map();
338 u64 attrs = imx93_mem_map[entry].attrs;
339
340 while (i < CONFIG_NR_DRAM_BANKS &&
341 entry < ARRAY_SIZE(imx93_mem_map)) {
342 if (gd->bd->bi_dram[i].start == 0)
343 break;
344 imx93_mem_map[entry].phys = gd->bd->bi_dram[i].start;
345 imx93_mem_map[entry].virt = gd->bd->bi_dram[i].start;
346 imx93_mem_map[entry].size = gd->bd->bi_dram[i].size;
347 imx93_mem_map[entry].attrs = attrs;
348 debug("Added memory mapping (%d): %llx %llx\n", entry,
349 imx93_mem_map[entry].phys, imx93_mem_map[entry].size);
350 i++; entry++;
351 }
352
353 icache_enable();
354 dcache_enable();
355}
356
357__weak int board_phys_sdram_size(phys_size_t *size)
358{
Ye Libb1187b2023-04-28 12:08:45 +0800359 phys_size_t start, end;
360 phys_size_t val;
361
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800362 if (!size)
363 return -EINVAL;
364
Ye Libb1187b2023-04-28 12:08:45 +0800365 val = readl(REG_DDR_CS0_BNDS);
366 start = (val >> 16) << 24;
367 end = (val & 0xFFFF);
368 end = end ? end + 1 : 0;
369 end = end << 24;
370 *size = end - start;
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800371
Ye Libb1187b2023-04-28 12:08:45 +0800372 val = readl(REG_DDR_CS1_BNDS);
373 start = (val >> 16) << 24;
374 end = (val & 0xFFFF);
375 end = end ? end + 1 : 0;
376 end = end << 24;
377 *size += end - start;
378
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800379 return 0;
380}
381
Peng Fanbbcd2c42022-07-26 16:40:39 +0800382int dram_init(void)
383{
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800384 phys_size_t sdram_size;
385 int ret;
386
387 ret = board_phys_sdram_size(&sdram_size);
388 if (ret)
389 return ret;
390
391 /* rom_pointer[1] contains the size of TEE occupies */
Simon Glass85ed77d2024-09-29 19:49:46 -0600392 if (!IS_ENABLED(CONFIG_XPL_BUILD) && rom_pointer[1])
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800393 gd->ram_size = sdram_size - rom_pointer[1];
394 else
395 gd->ram_size = sdram_size;
396
397 return 0;
398}
399
400int dram_init_banksize(void)
401{
402 int bank = 0;
403 int ret;
404 phys_size_t sdram_size;
405 phys_size_t sdram_b1_size, sdram_b2_size;
406
407 ret = board_phys_sdram_size(&sdram_size);
408 if (ret)
409 return ret;
410
411 /* Bank 1 can't cross over 4GB space */
412 if (sdram_size > 0x80000000) {
413 sdram_b1_size = 0x80000000;
414 sdram_b2_size = sdram_size - 0x80000000;
415 } else {
416 sdram_b1_size = sdram_size;
417 sdram_b2_size = 0;
418 }
419
420 gd->bd->bi_dram[bank].start = PHYS_SDRAM;
Simon Glass85ed77d2024-09-29 19:49:46 -0600421 if (!IS_ENABLED(CONFIG_XPL_BUILD) && rom_pointer[1]) {
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800422 phys_addr_t optee_start = (phys_addr_t)rom_pointer[0];
423 phys_size_t optee_size = (size_t)rom_pointer[1];
424
425 gd->bd->bi_dram[bank].size = optee_start - gd->bd->bi_dram[bank].start;
426 if ((optee_start + optee_size) < (PHYS_SDRAM + sdram_b1_size)) {
427 if (++bank >= CONFIG_NR_DRAM_BANKS) {
428 puts("CONFIG_NR_DRAM_BANKS is not enough\n");
429 return -1;
430 }
431
432 gd->bd->bi_dram[bank].start = optee_start + optee_size;
433 gd->bd->bi_dram[bank].size = PHYS_SDRAM +
434 sdram_b1_size - gd->bd->bi_dram[bank].start;
435 }
436 } else {
437 gd->bd->bi_dram[bank].size = sdram_b1_size;
438 }
439
440 if (sdram_b2_size) {
441 if (++bank >= CONFIG_NR_DRAM_BANKS) {
442 puts("CONFIG_NR_DRAM_BANKS is not enough for SDRAM_2\n");
443 return -1;
444 }
445 gd->bd->bi_dram[bank].start = 0x100000000UL;
446 gd->bd->bi_dram[bank].size = sdram_b2_size;
447 }
Peng Fanbbcd2c42022-07-26 16:40:39 +0800448
449 return 0;
450}
451
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800452phys_size_t get_effective_memsize(void)
453{
454 int ret;
455 phys_size_t sdram_size;
456 phys_size_t sdram_b1_size;
457
458 ret = board_phys_sdram_size(&sdram_size);
459 if (!ret) {
460 /* Bank 1 can't cross over 4GB space */
461 if (sdram_size > 0x80000000)
462 sdram_b1_size = 0x80000000;
463 else
464 sdram_b1_size = sdram_size;
465
Simon Glass85ed77d2024-09-29 19:49:46 -0600466 if (!IS_ENABLED(CONFIG_XPL_BUILD) && rom_pointer[1]) {
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800467 /* We will relocate u-boot to top of dram1. TEE position has two cases:
468 * 1. At the top of dram1, Then return the size removed optee size.
469 * 2. In the middle of dram1, return the size of dram1.
470 */
471 if ((rom_pointer[0] + rom_pointer[1]) == (PHYS_SDRAM + sdram_b1_size))
472 return ((phys_addr_t)rom_pointer[0] - PHYS_SDRAM);
473 }
474
475 return sdram_b1_size;
476 } else {
477 return PHYS_SDRAM_SIZE;
478 }
479}
480
Peng Fanbbcd2c42022-07-26 16:40:39 +0800481void imx_get_mac_from_fuse(int dev_id, unsigned char *mac)
482{
Ye Li66baefb2023-04-28 12:08:21 +0800483 u32 val[2] = {};
484 int ret;
485
486 if (dev_id == 0) {
487 ret = fuse_read(39, 3, &val[0]);
488 if (ret)
489 goto err;
490
491 ret = fuse_read(39, 4, &val[1]);
492 if (ret)
493 goto err;
494
495 mac[0] = val[1] >> 8;
496 mac[1] = val[1];
497 mac[2] = val[0] >> 24;
498 mac[3] = val[0] >> 16;
499 mac[4] = val[0] >> 8;
500 mac[5] = val[0];
501
502 } else {
503 ret = fuse_read(39, 5, &val[0]);
504 if (ret)
505 goto err;
506
507 ret = fuse_read(39, 4, &val[1]);
508 if (ret)
509 goto err;
510
Ye Liae9b7022024-09-19 12:01:24 +0800511 if (is_imx93() && is_soc_rev(CHIP_REV_1_0)) {
512 mac[0] = val[1] >> 24;
513 mac[1] = val[1] >> 16;
514 mac[2] = val[0] >> 24;
515 mac[3] = val[0] >> 16;
516 mac[4] = val[0] >> 8;
517 mac[5] = val[0];
518 } else {
519 mac[0] = val[0] >> 24;
520 mac[1] = val[0] >> 16;
521 mac[2] = val[0] >> 8;
522 mac[3] = val[0];
523 mac[4] = val[1] >> 24;
524 mac[5] = val[1] >> 16;
525 }
Ye Li66baefb2023-04-28 12:08:21 +0800526 }
527
528 debug("%s: MAC%d: %02x.%02x.%02x.%02x.%02x.%02x\n",
529 __func__, dev_id, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
530 return;
531err:
532 memset(mac, 0, 6);
533 printf("%s: fuse read err: %d\n", __func__, ret);
Peng Fanbbcd2c42022-07-26 16:40:39 +0800534}
535
536int print_cpuinfo(void)
537{
538 u32 cpurev;
539
540 cpurev = get_cpu_rev();
541
542 printf("CPU: i.MX93 rev%d.%d\n", (cpurev & 0x000F0) >> 4, (cpurev & 0x0000F) >> 0);
543
544 return 0;
545}
546
Peng Fan1a17ae82024-09-19 12:01:25 +0800547void build_info(void)
548{
549 u32 fw_version, sha1, res, status;
550 int ret;
551
552 printf("\nBuildInfo:\n");
553
554 ret = ele_get_fw_status(&status, &res);
555 if (ret) {
556 printf(" - ELE firmware status failed %d, 0x%x\n", ret, res);
557 } else if ((status & 0xff) == 1) {
558 ret = ele_get_fw_version(&fw_version, &sha1, &res);
559 if (ret) {
560 printf(" - ELE firmware version failed %d, 0x%x\n", ret, res);
561 } else {
562 printf(" - ELE firmware version %u.%u.%u-%x",
563 (fw_version & (0x00ff0000)) >> 16,
564 (fw_version & (0x0000fff0)) >> 4,
565 (fw_version & (0x0000000f)), sha1);
566 ((fw_version & (0x80000000)) >> 31) == 1 ? puts("-dirty\n") : puts("\n");
567 }
568 } else {
569 printf(" - ELE firmware not included\n");
570 }
571 puts("\n");
572}
573
574int arch_misc_init(void)
575{
576 build_info();
577 return 0;
578}
579
Ye Li7b248152024-09-19 12:01:26 +0800580struct low_drive_freq_entry {
581 const char *node_path;
582 u32 clk;
583 u32 new_rate;
584};
585
586static int low_drive_fdt_fix_clock(void *fdt, int node_off, u32 clk_index, u32 new_rate)
587{
588#define MAX_ASSIGNED_CLKS 8
589 int cnt, j;
590 u32 assignedclks[MAX_ASSIGNED_CLKS]; /* max 8 clocks*/
591
592 cnt = fdtdec_get_int_array_count(fdt, node_off, "assigned-clock-rates",
593 assignedclks, MAX_ASSIGNED_CLKS);
594 if (cnt > 0) {
595 if (cnt <= clk_index)
596 return -ENOENT;
597
598 if (assignedclks[clk_index] <= new_rate)
599 return 0;
600
601 assignedclks[clk_index] = new_rate;
602 for (j = 0; j < cnt; j++)
603 assignedclks[j] = cpu_to_fdt32(assignedclks[j]);
604
605 return fdt_setprop(fdt, node_off, "assigned-clock-rates", &assignedclks,
606 cnt * sizeof(u32));
607 }
608
609 return -ENOENT;
610}
611
612static int low_drive_freq_update(void *blob)
613{
614 int nodeoff, ret;
615 int i;
616
617 /* Update kernel dtb clocks for low drive mode */
618 struct low_drive_freq_entry table[] = {
619 {"/soc@0/bus@42800000/mmc@42850000", 0, 266666667},
620 {"/soc@0/bus@42800000/mmc@42860000", 0, 266666667},
621 {"/soc@0/bus@42800000/mmc@428b0000", 0, 266666667},
622 };
623
624 for (i = 0; i < ARRAY_SIZE(table); i++) {
625 nodeoff = fdt_path_offset(blob, table[i].node_path);
626 if (nodeoff >= 0) {
627 ret = low_drive_fdt_fix_clock(blob, nodeoff, table[i].clk,
628 table[i].new_rate);
629 if (!ret)
630 printf("%s freq updated\n", table[i].node_path);
631 }
632 }
633
634 return 0;
635}
636
637#ifdef CONFIG_OF_BOARD_FIXUP
Simon Glass85ed77d2024-09-29 19:49:46 -0600638#ifndef CONFIG_XPL_BUILD
Ye Li7b248152024-09-19 12:01:26 +0800639int board_fix_fdt(void *fdt)
640{
641 /* Update dtb clocks for low drive mode */
642 if (is_voltage_mode(VOLT_LOW_DRIVE)) {
643 int nodeoff;
644 int i;
645
646 struct low_drive_freq_entry table[] = {
647 {"/soc@0/bus@42800000/mmc@42850000", 0, 266666667},
648 {"/soc@0/bus@42800000/mmc@42860000", 0, 266666667},
649 {"/soc@0/bus@42800000/mmc@428b0000", 0, 266666667},
650 };
651
652 for (i = 0; i < ARRAY_SIZE(table); i++) {
653 nodeoff = fdt_path_offset(fdt, table[i].node_path);
654 if (nodeoff >= 0)
655 low_drive_fdt_fix_clock(fdt, nodeoff, table[i].clk,
656 table[i].new_rate);
657 }
658 }
659
660 return 0;
661}
662#endif
663#endif
664
Peng Fanbbcd2c42022-07-26 16:40:39 +0800665int ft_system_setup(void *blob, struct bd_info *bd)
666{
Peng Fan904a8862024-09-19 12:01:32 +0800667 static const char * const nodes_path[] = {
668 "/cpus/cpu@0",
669 "/cpus/cpu@100",
670 };
671
Primoz Fiserebbd4fc2024-01-11 13:56:25 +0100672 if (fixup_thermal_trips(blob, "cpu-thermal"))
673 printf("Failed to update cpu-thermal trip(s)");
674
Ye Li57b2ac42024-09-19 12:01:33 +0800675 if (is_imx9351() || is_imx9331() || is_imx9321() || is_imx9311() || is_imx9301())
Peng Fan904a8862024-09-19 12:01:32 +0800676 disable_cpu_nodes(blob, nodes_path, 1, 2);
677
Ye Li7b248152024-09-19 12:01:26 +0800678 if (is_voltage_mode(VOLT_LOW_DRIVE))
679 low_drive_freq_update(blob);
680
Peng Fanbbcd2c42022-07-26 16:40:39 +0800681 return 0;
682}
Peng Fan3700c472022-07-26 16:40:56 +0800683
684#if defined(CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG)
685void get_board_serial(struct tag_serialnr *serialnr)
686{
Ye Li8a7f6ef2024-09-19 12:01:22 +0800687 printf("UID: %08x%08x%08x%08x\n", __be32_to_cpu(gd->arch.uid[0]),
688 __be32_to_cpu(gd->arch.uid[1]), __be32_to_cpu(gd->arch.uid[2]),
689 __be32_to_cpu(gd->arch.uid[3]));
Peng Fan3700c472022-07-26 16:40:56 +0800690
Frank Li52b93ea2024-09-19 12:01:21 +0800691 serialnr->low = __be32_to_cpu(gd->arch.uid[1]);
692 serialnr->high = __be32_to_cpu(gd->arch.uid[0]);
Peng Fan3700c472022-07-26 16:40:56 +0800693}
694#endif
Peng Fanbbcd2c42022-07-26 16:40:39 +0800695
Peng Fanb1815c42023-04-28 12:08:27 +0800696static void save_reset_cause(void)
697{
698 struct src_general_regs *src = (struct src_general_regs *)SRC_GLOBAL_RBASE;
699 u32 srsr = readl(&src->srsr);
700
701 /* clear srsr in sec mode */
702 writel(srsr, &src->srsr);
703
704 /* Save value to GPR1 to pass to nonsecure */
705 writel(srsr, &src->gpr[0]);
706}
707
Peng Fanbbcd2c42022-07-26 16:40:39 +0800708int arch_cpu_init(void)
709{
Simon Glass85ed77d2024-09-29 19:49:46 -0600710 if (IS_ENABLED(CONFIG_XPL_BUILD)) {
Ye Li9e19ff92022-07-26 16:40:47 +0800711 /* Disable wdog */
712 init_wdog();
713
Ye Li66af10a2024-09-19 12:01:27 +0800714 clock_init_early();
Ye Li62185922022-07-26 16:40:54 +0800715
716 trdc_early_init();
Peng Fanb1815c42023-04-28 12:08:27 +0800717
718 /* Save SRC SRSR to GPR1 and clear it */
719 save_reset_cause();
Ye Li9e19ff92022-07-26 16:40:47 +0800720 }
Peng Fan28b5cb52022-07-26 16:40:43 +0800721
Peng Fanbbcd2c42022-07-26 16:40:39 +0800722 return 0;
723}
Peng Fan3700c472022-07-26 16:40:56 +0800724
Simon Glassb8357c12023-08-21 21:16:56 -0600725int imx9_probe_mu(void)
Peng Fan3700c472022-07-26 16:40:56 +0800726{
727 struct udevice *devp;
728 int node, ret;
729 u32 res;
Peng Fand5c31832023-06-15 18:09:05 +0800730 struct ele_get_info_data info;
Peng Fan3700c472022-07-26 16:40:56 +0800731
732 node = fdt_node_offset_by_compatible(gd->fdt_blob, -1, "fsl,imx93-mu-s4");
733
734 ret = uclass_get_device_by_of_offset(UCLASS_MISC, node, &devp);
735 if (ret)
736 return ret;
737
738 if (gd->flags & GD_FLG_RELOC)
739 return 0;
740
Peng Fand5c31832023-06-15 18:09:05 +0800741 ret = ele_get_info(&info, &res);
Peng Fan3700c472022-07-26 16:40:56 +0800742 if (ret)
743 return ret;
744
745 set_cpu_info(&info);
746
747 return 0;
748}
Simon Glassb8357c12023-08-21 21:16:56 -0600749EVENT_SPY_SIMPLE(EVT_DM_POST_INIT_F, imx9_probe_mu);
Ye Lif41ffc12024-04-01 09:41:09 +0800750EVENT_SPY_SIMPLE(EVT_DM_POST_INIT_R, imx9_probe_mu);
Jian Liacf41a32022-07-26 16:40:46 +0800751
752int timer_init(void)
753{
Simon Glass85ed77d2024-09-29 19:49:46 -0600754#ifdef CONFIG_XPL_BUILD
Jian Liacf41a32022-07-26 16:40:46 +0800755 struct sctr_regs *sctr = (struct sctr_regs *)SYSCNT_CTRL_BASE_ADDR;
756 unsigned long freq = readl(&sctr->cntfid0);
757
758 /* Update with accurate clock frequency */
759 asm volatile("msr cntfrq_el0, %0" : : "r" (freq) : "memory");
760
761 clrsetbits_le32(&sctr->cntcr, SC_CNTCR_FREQ0 | SC_CNTCR_FREQ1,
762 SC_CNTCR_FREQ0 | SC_CNTCR_ENABLE | SC_CNTCR_HDBG);
763#endif
764
765 gd->arch.tbl = 0;
766 gd->arch.tbu = 0;
767
768 return 0;
769}
Peng Fan65563792022-07-26 16:41:02 +0800770
Ye Li8e8687c2022-07-26 16:41:05 +0800771enum env_location env_get_location(enum env_operation op, int prio)
772{
773 enum boot_device dev = get_boot_device();
Ye Li8e8687c2022-07-26 16:41:05 +0800774
775 if (prio)
Oleksandr Suvoroveff7c8d2023-04-11 20:27:41 +0300776 return ENVL_UNKNOWN;
Ye Li8e8687c2022-07-26 16:41:05 +0800777
778 switch (dev) {
Ye Li8e8687c2022-07-26 16:41:05 +0800779 case QSPI_BOOT:
Oleksandr Suvoroveff7c8d2023-04-11 20:27:41 +0300780 if (CONFIG_IS_ENABLED(ENV_IS_IN_SPI_FLASH))
781 return ENVL_SPI_FLASH;
782 return ENVL_NOWHERE;
Ye Li8e8687c2022-07-26 16:41:05 +0800783 case SD1_BOOT:
784 case SD2_BOOT:
785 case SD3_BOOT:
786 case MMC1_BOOT:
787 case MMC2_BOOT:
788 case MMC3_BOOT:
Oleksandr Suvoroveff7c8d2023-04-11 20:27:41 +0300789 if (CONFIG_IS_ENABLED(ENV_IS_IN_MMC))
790 return ENVL_MMC;
791 else if (CONFIG_IS_ENABLED(ENV_IS_IN_EXT4))
792 return ENVL_EXT4;
793 else if (CONFIG_IS_ENABLED(ENV_IS_IN_FAT))
794 return ENVL_FAT;
795 return ENVL_NOWHERE;
Ye Li8e8687c2022-07-26 16:41:05 +0800796 default:
Oleksandr Suvoroveff7c8d2023-04-11 20:27:41 +0300797 return ENVL_NOWHERE;
Ye Li8e8687c2022-07-26 16:41:05 +0800798 }
Ye Li8e8687c2022-07-26 16:41:05 +0800799}
800
Peng Fan65563792022-07-26 16:41:02 +0800801static int mix_power_init(enum mix_power_domain pd)
802{
803 enum src_mix_slice_id mix_id;
804 enum src_mem_slice_id mem_id;
805 struct src_mix_slice_regs *mix_regs;
806 struct src_mem_slice_regs *mem_regs;
807 struct src_general_regs *global_regs;
808 u32 scr, val;
809
810 switch (pd) {
811 case MIX_PD_MEDIAMIX:
812 mix_id = SRC_MIX_MEDIA;
813 mem_id = SRC_MEM_MEDIA;
814 scr = BIT(5);
815
Peng Fand5c31832023-06-15 18:09:05 +0800816 /* Enable ELE handshake */
Peng Fan65563792022-07-26 16:41:02 +0800817 struct blk_ctrl_s_aonmix_regs *s_regs =
818 (struct blk_ctrl_s_aonmix_regs *)BLK_CTRL_S_ANOMIX_BASE_ADDR;
819
820 setbits_le32(&s_regs->lp_handshake[0], BIT(13));
821 break;
822 case MIX_PD_MLMIX:
823 mix_id = SRC_MIX_ML;
824 mem_id = SRC_MEM_ML;
825 scr = BIT(4);
826 break;
827 case MIX_PD_DDRMIX:
828 mix_id = SRC_MIX_DDRMIX;
829 mem_id = SRC_MEM_DDRMIX;
830 scr = BIT(6);
831 break;
832 default:
833 return -EINVAL;
834 }
835
836 mix_regs = (struct src_mix_slice_regs *)(ulong)(SRC_IPS_BASE_ADDR + 0x400 * (mix_id + 1));
837 mem_regs =
838 (struct src_mem_slice_regs *)(ulong)(SRC_IPS_BASE_ADDR + 0x3800 + 0x400 * mem_id);
839 global_regs = (struct src_general_regs *)(ulong)SRC_GLOBAL_RBASE;
840
841 /* Allow NS to set it */
842 setbits_le32(&mix_regs->authen_ctrl, BIT(9));
843
844 clrsetbits_le32(&mix_regs->psw_ack_ctrl[0], BIT(28), BIT(29));
845
846 /* mix reset will be held until boot core write this bit to 1 */
847 setbits_le32(&global_regs->scr, scr);
848
849 /* Enable mem in Low power auto sequence */
850 setbits_le32(&mem_regs->mem_ctrl, BIT(2));
851
852 /* Set the power down state */
853 val = readl(&mix_regs->func_stat);
854 if (val & SRC_MIX_SLICE_FUNC_STAT_PSW_STAT) {
855 /* The mix is default power off, power down it to make PDN_SFT bit
856 * aligned with FUNC STAT
857 */
858 setbits_le32(&mix_regs->slice_sw_ctrl, BIT(31));
859 val = readl(&mix_regs->func_stat);
860
861 /* Since PSW_STAT is 1, can't be used for power off status (SW_CTRL BIT31 set)) */
862 /* Check the MEM STAT change to ensure SSAR is completed */
863 while (!(val & SRC_MIX_SLICE_FUNC_STAT_MEM_STAT))
864 val = readl(&mix_regs->func_stat);
865
866 /* wait few ipg clock cycles to ensure FSM done and power off status is correct */
867 /* About 5 cycles at 24Mhz, 1us is enough */
868 udelay(1);
869 } else {
870 /* The mix is default power on, Do mix power cycle */
871 setbits_le32(&mix_regs->slice_sw_ctrl, BIT(31));
872 val = readl(&mix_regs->func_stat);
873 while (!(val & SRC_MIX_SLICE_FUNC_STAT_PSW_STAT))
874 val = readl(&mix_regs->func_stat);
875 }
876
877 /* power on */
878 clrbits_le32(&mix_regs->slice_sw_ctrl, BIT(31));
879 val = readl(&mix_regs->func_stat);
Peng Fan06e78ff2024-09-19 12:01:19 +0800880 while (val & SRC_MIX_SLICE_FUNC_STAT_SSAR_STAT)
Peng Fan65563792022-07-26 16:41:02 +0800881 val = readl(&mix_regs->func_stat);
882
883 return 0;
884}
885
886void disable_isolation(void)
887{
888 struct src_general_regs *global_regs = (struct src_general_regs *)(ulong)SRC_GLOBAL_RBASE;
889 /* clear isolation for usbphy, dsi, csi*/
890 writel(0x0, &global_regs->sp_iso_ctrl);
891}
892
893void soc_power_init(void)
894{
895 mix_power_init(MIX_PD_MEDIAMIX);
896 mix_power_init(MIX_PD_MLMIX);
897
898 disable_isolation();
899}
Peng Fan6d929962022-07-26 16:41:03 +0800900
Peng Fan313af252022-07-26 16:41:04 +0800901bool m33_is_rom_kicked(void)
Peng Fan6d929962022-07-26 16:41:03 +0800902{
903 struct blk_ctrl_s_aonmix_regs *s_regs =
904 (struct blk_ctrl_s_aonmix_regs *)BLK_CTRL_S_ANOMIX_BASE_ADDR;
905
906 if (!(readl(&s_regs->m33_cfg) & BIT(2)))
907 return true;
908
909 return false;
910}
911
912int m33_prepare(void)
913{
914 struct src_mix_slice_regs *mix_regs =
915 (struct src_mix_slice_regs *)(ulong)(SRC_IPS_BASE_ADDR + 0x400 * (SRC_MIX_CM33 + 1));
916 struct src_general_regs *global_regs =
917 (struct src_general_regs *)(ulong)SRC_GLOBAL_RBASE;
918 struct blk_ctrl_s_aonmix_regs *s_regs =
919 (struct blk_ctrl_s_aonmix_regs *)BLK_CTRL_S_ANOMIX_BASE_ADDR;
Ye Li0667ec92024-09-19 12:01:20 +0800920 u32 val, i;
Peng Fan6d929962022-07-26 16:41:03 +0800921
922 if (m33_is_rom_kicked())
923 return -EPERM;
924
925 /* Release reset of M33 */
926 setbits_le32(&global_regs->scr, BIT(0));
927
928 /* Check the reset released in M33 MIX func stat */
929 val = readl(&mix_regs->func_stat);
930 while (!(val & SRC_MIX_SLICE_FUNC_STAT_RST_STAT))
931 val = readl(&mix_regs->func_stat);
932
Peng Fand5c31832023-06-15 18:09:05 +0800933 /* Release ELE TROUT */
934 ele_release_m33_trout();
Peng Fan6d929962022-07-26 16:41:03 +0800935
936 /* Mask WDOG1 IRQ from A55, we use it for M33 reset */
937 setbits_le32(&s_regs->ca55_irq_mask[1], BIT(6));
938
939 /* Turn on WDOG1 clock */
940 ccm_lpcg_on(CCGR_WDG1, 1);
941
Peng Fand5c31832023-06-15 18:09:05 +0800942 /* Set ELE LP handshake for M33 reset */
Peng Fan6d929962022-07-26 16:41:03 +0800943 setbits_le32(&s_regs->lp_handshake[0], BIT(6));
944
Ye Li0667ec92024-09-19 12:01:20 +0800945 /* OSCCA enabled, reconfigure TRDC for TCM access, otherwise ECC init will raise error */
946 val = readl(BLK_CTRL_NS_ANOMIX_BASE_ADDR + 0x28);
947 if (val & BIT(0)) {
948 trdc_mbc_set_control(0x44270000, 1, 0, 0x6600);
949
950 for (i = 0; i < 32; i++)
951 trdc_mbc_blk_config(0x44270000, 1, 3, 0, i, true, 0);
952
953 for (i = 0; i < 32; i++)
954 trdc_mbc_blk_config(0x44270000, 1, 3, 1, i, true, 0);
955 }
956
Peng Fan6d929962022-07-26 16:41:03 +0800957 /* Clear M33 TCM for ECC */
958 memset((void *)(ulong)0x201e0000, 0, 0x40000);
959
960 return 0;
961}
Peng Fanb1815c42023-04-28 12:08:27 +0800962
963int psci_sysreset_get_status(struct udevice *dev, char *buf, int size)
964{
965 static const char *reset_cause[] = {
966 "POR ",
967 "JTAG ",
968 "IPP USER ",
969 "WDOG1 ",
970 "WDOG2 ",
971 "WDOG3 ",
972 "WDOG4 ",
973 "WDOG5 ",
974 "TEMPSENSE ",
975 "CSU ",
976 "JTAG_SW ",
977 "M33_REQ ",
978 "M33_LOCKUP ",
979 "UNK ",
980 "UNK ",
981 "UNK "
982 };
983
984 struct src_general_regs *src = (struct src_general_regs *)SRC_GLOBAL_RBASE;
985 u32 srsr;
986 u32 i;
987 int res;
988
989 srsr = readl(&src->gpr[0]);
990
991 for (i = ARRAY_SIZE(reset_cause); i > 0; i--) {
992 if (srsr & (BIT(i - 1)))
993 break;
994 }
995
996 res = snprintf(buf, size, "Reset Status: %s\n", i ? reset_cause[i - 1] : "unknown reset");
997 if (res < 0) {
998 dev_err(dev, "Could not write reset status message (err = %d)\n", res);
999 return -EIO;
1000 }
1001
1002 return 0;
1003}
Ye Li7b248152024-09-19 12:01:26 +08001004
1005enum imx9_soc_voltage_mode soc_target_voltage_mode(void)
1006{
1007 u32 speed = get_cpu_speed_grade_hz();
1008 enum imx9_soc_voltage_mode voltage = VOLT_OVER_DRIVE;
1009
1010 if (is_imx93()) {
1011 if (speed == 1700000000)
1012 voltage = VOLT_OVER_DRIVE;
1013 else if (speed == 1400000000)
1014 voltage = VOLT_NOMINAL_DRIVE;
1015 else if (speed == 900000000 || speed == 800000000)
1016 voltage = VOLT_LOW_DRIVE;
1017 else
1018 printf("Unexpected A55 freq %u, default to OD\n", speed);
1019 }
1020
1021 return voltage;
1022}