blob: 07d1bb20d58087383abdb0f7b6ba0a985624e3bb [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 Fan3700c472022-07-26 16:40:56 +080037#include <asm/mach-imx/s400_api.h>
Ye Li66baefb2023-04-28 12:08:21 +080038#include <fuse.h>
Peng Fanbbcd2c42022-07-26 16:40:39 +080039
40DECLARE_GLOBAL_DATA_PTR;
41
Peng Fan5de0fc02022-07-26 16:40:48 +080042struct rom_api *g_rom_api = (struct rom_api *)0x1980;
43
44#ifdef CONFIG_ENV_IS_IN_MMC
45__weak int board_mmc_get_env_dev(int devno)
46{
Peng Fan77b36c62023-04-28 12:08:33 +080047 return devno;
48}
Peng Fan5de0fc02022-07-26 16:40:48 +080049
50int mmc_get_env_dev(void)
51{
52 volatile gd_t *pgd = gd;
53 int ret;
54 u32 boot;
55 u16 boot_type;
56 u8 boot_instance;
57
58 ret = g_rom_api->query_boot_infor(QUERY_BT_DEV, &boot,
59 ((uintptr_t)&boot) ^ QUERY_BT_DEV);
60 set_gd(pgd);
61
62 if (ret != ROM_API_OKAY) {
63 puts("ROMAPI: failure at query_boot_info\n");
64 return CONFIG_SYS_MMC_ENV_DEV;
65 }
66
67 boot_type = boot >> 16;
68 boot_instance = (boot >> 8) & 0xff;
69
70 debug("boot_type %d, instance %d\n", boot_type, boot_instance);
71
72 /* If not boot from sd/mmc, use default value */
73 if (boot_type != BOOT_TYPE_SD && boot_type != BOOT_TYPE_MMC)
74 return env_get_ulong("mmcdev", 10, CONFIG_SYS_MMC_ENV_DEV);
75
76 return board_mmc_get_env_dev(boot_instance);
77}
78#endif
79
Peng Fan0c2f3682023-04-28 12:08:28 +080080/*
81 * SPEED_GRADE[5:4] SPEED_GRADE[3:0] MHz
82 * xx 0000 2300
83 * xx 0001 2200
84 * xx 0010 2100
85 * xx 0011 2000
86 * xx 0100 1900
87 * xx 0101 1800
88 * xx 0110 1700
89 * xx 0111 1600
90 * xx 1000 1500
91 * xx 1001 1400
92 * xx 1010 1300
93 * xx 1011 1200
94 * xx 1100 1100
95 * xx 1101 1000
96 * xx 1110 900
97 * xx 1111 800
98 */
99u32 get_cpu_speed_grade_hz(void)
100{
101 u32 speed, max_speed;
102 u32 val;
103
104 fuse_read(2, 3, &val);
105 val = FIELD_GET(SPEED_GRADING_MASK, val) & 0xF;
106
107 speed = MHZ(2300) - val * MHZ(100);
108
109 if (is_imx93())
110 max_speed = MHZ(1700);
111
112 /* In case the fuse of speed grade not programmed */
113 if (speed > max_speed)
114 speed = max_speed;
115
116 return speed;
117}
118
119/*
120 * `00` - Consumer 0C to 95C
121 * `01` - Ext. Consumer -20C to 105C
122 * `10` - Industrial -40C to 105C
123 * `11` - Automotive -40C to 125C
124 */
125u32 get_cpu_temp_grade(int *minc, int *maxc)
126{
127 u32 val;
128
129 fuse_read(2, 3, &val);
130 val = FIELD_GET(MARKETING_GRADING_MASK, val);
131
132 if (minc && maxc) {
133 if (val == TEMP_AUTOMOTIVE) {
134 *minc = -40;
135 *maxc = 125;
136 } else if (val == TEMP_INDUSTRIAL) {
137 *minc = -40;
138 *maxc = 105;
139 } else if (val == TEMP_EXTCOMMERCIAL) {
140 if (is_imx93()) {
141 /* imx93 only has extended industrial*/
142 *minc = -40;
143 *maxc = 125;
144 } else {
145 *minc = -20;
146 *maxc = 105;
147 }
148 } else {
149 *minc = 0;
150 *maxc = 95;
151 }
152 }
153 return val;
154}
155
Peng Fan3700c472022-07-26 16:40:56 +0800156static void set_cpu_info(struct sentinel_get_info_data *info)
157{
158 gd->arch.soc_rev = info->soc;
159 gd->arch.lifecycle = info->lc;
160 memcpy((void *)&gd->arch.uid, &info->uid, 4 * sizeof(u32));
161}
162
Peng Fanc3db3ad2023-04-28 12:08:32 +0800163static u32 get_cpu_variant_type(u32 type)
164{
165 /* word 19 */
166 u32 val = readl((ulong)FSB_BASE_ADDR + 0x8000 + (19 << 2));
167 u32 val2 = readl((ulong)FSB_BASE_ADDR + 0x8000 + (20 << 2));
168 bool npu_disable = !!(val & BIT(13));
169 bool core1_disable = !!(val & BIT(15));
170 u32 pack_9x9_fused = BIT(4) | BIT(17) | BIT(19) | BIT(24);
171
172 if ((val2 & pack_9x9_fused) == pack_9x9_fused)
173 type = MXC_CPU_IMX9322;
174
175 if (npu_disable && core1_disable)
176 return type + 3;
177 else if (npu_disable)
178 return type + 2;
179 else if (core1_disable)
180 return type + 1;
181
182 return type;
183}
184
Peng Fanbbcd2c42022-07-26 16:40:39 +0800185u32 get_cpu_rev(void)
186{
Peng Fan3700c472022-07-26 16:40:56 +0800187 u32 rev = (gd->arch.soc_rev >> 24) - 0xa0;
188
Peng Fanc3db3ad2023-04-28 12:08:32 +0800189 return (get_cpu_variant_type(MXC_CPU_IMX93) << 12) |
190 (CHIP_REV_1_0 + rev);
Peng Fanbbcd2c42022-07-26 16:40:39 +0800191}
192
Ye Li9e19ff92022-07-26 16:40:47 +0800193#define UNLOCK_WORD 0xD928C520 /* unlock word */
194#define REFRESH_WORD 0xB480A602 /* refresh word */
195
196static void disable_wdog(void __iomem *wdog_base)
197{
198 u32 val_cs = readl(wdog_base + 0x00);
199
200 if (!(val_cs & 0x80))
201 return;
202
203 /* default is 32bits cmd */
204 writel(REFRESH_WORD, (wdog_base + 0x04)); /* Refresh the CNT */
205
206 if (!(val_cs & 0x800)) {
207 writel(UNLOCK_WORD, (wdog_base + 0x04));
208 while (!(readl(wdog_base + 0x00) & 0x800))
209 ;
210 }
211 writel(0x0, (wdog_base + 0x0C)); /* Set WIN to 0 */
212 writel(0x400, (wdog_base + 0x08)); /* Set timeout to default 0x400 */
213 writel(0x2120, (wdog_base + 0x00)); /* Disable it and set update */
214
215 while (!(readl(wdog_base + 0x00) & 0x400))
216 ;
217}
218
219void init_wdog(void)
220{
221 u32 src_val;
222
223 disable_wdog((void __iomem *)WDG3_BASE_ADDR);
224 disable_wdog((void __iomem *)WDG4_BASE_ADDR);
225 disable_wdog((void __iomem *)WDG5_BASE_ADDR);
226
227 src_val = readl(0x54460018); /* reset mask */
228 src_val &= ~0x1c;
229 writel(src_val, 0x54460018);
230}
231
Peng Fanbbcd2c42022-07-26 16:40:39 +0800232static struct mm_region imx93_mem_map[] = {
233 {
234 /* ROM */
235 .virt = 0x0UL,
236 .phys = 0x0UL,
237 .size = 0x100000UL,
238 .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
239 PTE_BLOCK_OUTER_SHARE
240 }, {
Peng Fan313af252022-07-26 16:41:04 +0800241 /* TCM */
242 .virt = 0x201c0000UL,
243 .phys = 0x201c0000UL,
244 .size = 0x80000UL,
245 .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
246 PTE_BLOCK_NON_SHARE |
247 PTE_BLOCK_PXN | PTE_BLOCK_UXN
248 }, {
Peng Fanbbcd2c42022-07-26 16:40:39 +0800249 /* OCRAM */
250 .virt = 0x20480000UL,
251 .phys = 0x20480000UL,
252 .size = 0xA0000UL,
253 .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
254 PTE_BLOCK_OUTER_SHARE
255 }, {
256 /* AIPS */
257 .virt = 0x40000000UL,
258 .phys = 0x40000000UL,
259 .size = 0x40000000UL,
260 .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
261 PTE_BLOCK_NON_SHARE |
262 PTE_BLOCK_PXN | PTE_BLOCK_UXN
263 }, {
264 /* Flexible Serial Peripheral Interface */
265 .virt = 0x28000000UL,
266 .phys = 0x28000000UL,
267 .size = 0x30000000UL,
268 .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
269 PTE_BLOCK_NON_SHARE |
270 PTE_BLOCK_PXN | PTE_BLOCK_UXN
271 }, {
272 /* DRAM1 */
273 .virt = 0x80000000UL,
274 .phys = 0x80000000UL,
275 .size = PHYS_SDRAM_SIZE,
276 .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
277 PTE_BLOCK_OUTER_SHARE
278 }, {
279 /* empty entrie to split table entry 5 if needed when TEEs are used */
280 0,
281 }, {
282 /* List terminator */
283 0,
284 }
285};
286
287struct mm_region *mem_map = imx93_mem_map;
288
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800289static unsigned int imx9_find_dram_entry_in_mem_map(void)
290{
291 int i;
292
293 for (i = 0; i < ARRAY_SIZE(imx93_mem_map); i++)
294 if (imx93_mem_map[i].phys == CFG_SYS_SDRAM_BASE)
295 return i;
296
297 hang(); /* Entry not found, this must never happen. */
298}
299
300void enable_caches(void)
301{
302 /* If OPTEE runs, remove OPTEE memory from MMU table to avoid speculative prefetch
303 * If OPTEE does not run, still update the MMU table according to dram banks structure
304 * to set correct dram size from board_phys_sdram_size
305 */
306 int i = 0;
307 /*
308 * please make sure that entry initial value matches
309 * imx93_mem_map for DRAM1
310 */
311 int entry = imx9_find_dram_entry_in_mem_map();
312 u64 attrs = imx93_mem_map[entry].attrs;
313
314 while (i < CONFIG_NR_DRAM_BANKS &&
315 entry < ARRAY_SIZE(imx93_mem_map)) {
316 if (gd->bd->bi_dram[i].start == 0)
317 break;
318 imx93_mem_map[entry].phys = gd->bd->bi_dram[i].start;
319 imx93_mem_map[entry].virt = gd->bd->bi_dram[i].start;
320 imx93_mem_map[entry].size = gd->bd->bi_dram[i].size;
321 imx93_mem_map[entry].attrs = attrs;
322 debug("Added memory mapping (%d): %llx %llx\n", entry,
323 imx93_mem_map[entry].phys, imx93_mem_map[entry].size);
324 i++; entry++;
325 }
326
327 icache_enable();
328 dcache_enable();
329}
330
331__weak int board_phys_sdram_size(phys_size_t *size)
332{
333 if (!size)
334 return -EINVAL;
335
336 *size = PHYS_SDRAM_SIZE;
337
338#ifdef PHYS_SDRAM_2_SIZE
339 *size += PHYS_SDRAM_2_SIZE;
340#endif
341 return 0;
342}
343
Peng Fanbbcd2c42022-07-26 16:40:39 +0800344int dram_init(void)
345{
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800346 phys_size_t sdram_size;
347 int ret;
348
349 ret = board_phys_sdram_size(&sdram_size);
350 if (ret)
351 return ret;
352
353 /* rom_pointer[1] contains the size of TEE occupies */
354 if (rom_pointer[1])
355 gd->ram_size = sdram_size - rom_pointer[1];
356 else
357 gd->ram_size = sdram_size;
358
359 return 0;
360}
361
362int dram_init_banksize(void)
363{
364 int bank = 0;
365 int ret;
366 phys_size_t sdram_size;
367 phys_size_t sdram_b1_size, sdram_b2_size;
368
369 ret = board_phys_sdram_size(&sdram_size);
370 if (ret)
371 return ret;
372
373 /* Bank 1 can't cross over 4GB space */
374 if (sdram_size > 0x80000000) {
375 sdram_b1_size = 0x80000000;
376 sdram_b2_size = sdram_size - 0x80000000;
377 } else {
378 sdram_b1_size = sdram_size;
379 sdram_b2_size = 0;
380 }
381
382 gd->bd->bi_dram[bank].start = PHYS_SDRAM;
383 if (rom_pointer[1]) {
384 phys_addr_t optee_start = (phys_addr_t)rom_pointer[0];
385 phys_size_t optee_size = (size_t)rom_pointer[1];
386
387 gd->bd->bi_dram[bank].size = optee_start - gd->bd->bi_dram[bank].start;
388 if ((optee_start + optee_size) < (PHYS_SDRAM + sdram_b1_size)) {
389 if (++bank >= CONFIG_NR_DRAM_BANKS) {
390 puts("CONFIG_NR_DRAM_BANKS is not enough\n");
391 return -1;
392 }
393
394 gd->bd->bi_dram[bank].start = optee_start + optee_size;
395 gd->bd->bi_dram[bank].size = PHYS_SDRAM +
396 sdram_b1_size - gd->bd->bi_dram[bank].start;
397 }
398 } else {
399 gd->bd->bi_dram[bank].size = sdram_b1_size;
400 }
401
402 if (sdram_b2_size) {
403 if (++bank >= CONFIG_NR_DRAM_BANKS) {
404 puts("CONFIG_NR_DRAM_BANKS is not enough for SDRAM_2\n");
405 return -1;
406 }
407 gd->bd->bi_dram[bank].start = 0x100000000UL;
408 gd->bd->bi_dram[bank].size = sdram_b2_size;
409 }
Peng Fanbbcd2c42022-07-26 16:40:39 +0800410
411 return 0;
412}
413
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800414phys_size_t get_effective_memsize(void)
415{
416 int ret;
417 phys_size_t sdram_size;
418 phys_size_t sdram_b1_size;
419
420 ret = board_phys_sdram_size(&sdram_size);
421 if (!ret) {
422 /* Bank 1 can't cross over 4GB space */
423 if (sdram_size > 0x80000000)
424 sdram_b1_size = 0x80000000;
425 else
426 sdram_b1_size = sdram_size;
427
428 if (rom_pointer[1]) {
429 /* We will relocate u-boot to top of dram1. TEE position has two cases:
430 * 1. At the top of dram1, Then return the size removed optee size.
431 * 2. In the middle of dram1, return the size of dram1.
432 */
433 if ((rom_pointer[0] + rom_pointer[1]) == (PHYS_SDRAM + sdram_b1_size))
434 return ((phys_addr_t)rom_pointer[0] - PHYS_SDRAM);
435 }
436
437 return sdram_b1_size;
438 } else {
439 return PHYS_SDRAM_SIZE;
440 }
441}
442
Peng Fanbbcd2c42022-07-26 16:40:39 +0800443void imx_get_mac_from_fuse(int dev_id, unsigned char *mac)
444{
Ye Li66baefb2023-04-28 12:08:21 +0800445 u32 val[2] = {};
446 int ret;
447
448 if (dev_id == 0) {
449 ret = fuse_read(39, 3, &val[0]);
450 if (ret)
451 goto err;
452
453 ret = fuse_read(39, 4, &val[1]);
454 if (ret)
455 goto err;
456
457 mac[0] = val[1] >> 8;
458 mac[1] = val[1];
459 mac[2] = val[0] >> 24;
460 mac[3] = val[0] >> 16;
461 mac[4] = val[0] >> 8;
462 mac[5] = val[0];
463
464 } else {
465 ret = fuse_read(39, 5, &val[0]);
466 if (ret)
467 goto err;
468
469 ret = fuse_read(39, 4, &val[1]);
470 if (ret)
471 goto err;
472
473 mac[0] = val[1] >> 24;
474 mac[1] = val[1] >> 16;
475 mac[2] = val[0] >> 24;
476 mac[3] = val[0] >> 16;
477 mac[4] = val[0] >> 8;
478 mac[5] = val[0];
479 }
480
481 debug("%s: MAC%d: %02x.%02x.%02x.%02x.%02x.%02x\n",
482 __func__, dev_id, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
483 return;
484err:
485 memset(mac, 0, 6);
486 printf("%s: fuse read err: %d\n", __func__, ret);
Peng Fanbbcd2c42022-07-26 16:40:39 +0800487}
488
489int print_cpuinfo(void)
490{
491 u32 cpurev;
492
493 cpurev = get_cpu_rev();
494
495 printf("CPU: i.MX93 rev%d.%d\n", (cpurev & 0x000F0) >> 4, (cpurev & 0x0000F) >> 0);
496
497 return 0;
498}
499
Peng Fanbbcd2c42022-07-26 16:40:39 +0800500int ft_system_setup(void *blob, struct bd_info *bd)
501{
502 return 0;
503}
Peng Fan3700c472022-07-26 16:40:56 +0800504
505#if defined(CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG)
506void get_board_serial(struct tag_serialnr *serialnr)
507{
508 printf("UID: 0x%x 0x%x 0x%x 0x%x\n",
509 gd->arch.uid[0], gd->arch.uid[1], gd->arch.uid[2], gd->arch.uid[3]);
510
511 serialnr->low = gd->arch.uid[0];
512 serialnr->high = gd->arch.uid[3];
513}
514#endif
Peng Fanbbcd2c42022-07-26 16:40:39 +0800515
Peng Fanb1815c42023-04-28 12:08:27 +0800516static void save_reset_cause(void)
517{
518 struct src_general_regs *src = (struct src_general_regs *)SRC_GLOBAL_RBASE;
519 u32 srsr = readl(&src->srsr);
520
521 /* clear srsr in sec mode */
522 writel(srsr, &src->srsr);
523
524 /* Save value to GPR1 to pass to nonsecure */
525 writel(srsr, &src->gpr[0]);
526}
527
Peng Fanbbcd2c42022-07-26 16:40:39 +0800528int arch_cpu_init(void)
529{
Ye Li9e19ff92022-07-26 16:40:47 +0800530 if (IS_ENABLED(CONFIG_SPL_BUILD)) {
531 /* Disable wdog */
532 init_wdog();
533
Peng Fan28b5cb52022-07-26 16:40:43 +0800534 clock_init();
Ye Li62185922022-07-26 16:40:54 +0800535
536 trdc_early_init();
Peng Fanb1815c42023-04-28 12:08:27 +0800537
538 /* Save SRC SRSR to GPR1 and clear it */
539 save_reset_cause();
Ye Li9e19ff92022-07-26 16:40:47 +0800540 }
Peng Fan28b5cb52022-07-26 16:40:43 +0800541
Peng Fanbbcd2c42022-07-26 16:40:39 +0800542 return 0;
543}
Peng Fan3700c472022-07-26 16:40:56 +0800544
545int imx9_probe_mu(void *ctx, struct event *event)
546{
547 struct udevice *devp;
548 int node, ret;
549 u32 res;
550 struct sentinel_get_info_data info;
551
552 node = fdt_node_offset_by_compatible(gd->fdt_blob, -1, "fsl,imx93-mu-s4");
553
554 ret = uclass_get_device_by_of_offset(UCLASS_MISC, node, &devp);
555 if (ret)
556 return ret;
557
558 if (gd->flags & GD_FLG_RELOC)
559 return 0;
560
561 ret = ahab_get_info(&info, &res);
562 if (ret)
563 return ret;
564
565 set_cpu_info(&info);
566
567 return 0;
568}
Simon Glass93074012023-05-04 16:50:45 -0600569EVENT_SPY(EVT_DM_POST_INIT_F, imx9_probe_mu);
Jian Liacf41a32022-07-26 16:40:46 +0800570
571int timer_init(void)
572{
573#ifdef CONFIG_SPL_BUILD
574 struct sctr_regs *sctr = (struct sctr_regs *)SYSCNT_CTRL_BASE_ADDR;
575 unsigned long freq = readl(&sctr->cntfid0);
576
577 /* Update with accurate clock frequency */
578 asm volatile("msr cntfrq_el0, %0" : : "r" (freq) : "memory");
579
580 clrsetbits_le32(&sctr->cntcr, SC_CNTCR_FREQ0 | SC_CNTCR_FREQ1,
581 SC_CNTCR_FREQ0 | SC_CNTCR_ENABLE | SC_CNTCR_HDBG);
582#endif
583
584 gd->arch.tbl = 0;
585 gd->arch.tbu = 0;
586
587 return 0;
588}
Peng Fan65563792022-07-26 16:41:02 +0800589
Ye Li8e8687c2022-07-26 16:41:05 +0800590enum env_location env_get_location(enum env_operation op, int prio)
591{
592 enum boot_device dev = get_boot_device();
593 enum env_location env_loc = ENVL_UNKNOWN;
594
595 if (prio)
596 return env_loc;
597
598 switch (dev) {
599#if defined(CONFIG_ENV_IS_IN_SPI_FLASH)
600 case QSPI_BOOT:
601 env_loc = ENVL_SPI_FLASH;
602 break;
603#endif
604#if defined(CONFIG_ENV_IS_IN_MMC)
605 case SD1_BOOT:
606 case SD2_BOOT:
607 case SD3_BOOT:
608 case MMC1_BOOT:
609 case MMC2_BOOT:
610 case MMC3_BOOT:
611 env_loc = ENVL_MMC;
612 break;
613#endif
614 default:
615#if defined(CONFIG_ENV_IS_NOWHERE)
616 env_loc = ENVL_NOWHERE;
617#endif
618 break;
619 }
620
621 return env_loc;
622}
623
Peng Fan65563792022-07-26 16:41:02 +0800624static int mix_power_init(enum mix_power_domain pd)
625{
626 enum src_mix_slice_id mix_id;
627 enum src_mem_slice_id mem_id;
628 struct src_mix_slice_regs *mix_regs;
629 struct src_mem_slice_regs *mem_regs;
630 struct src_general_regs *global_regs;
631 u32 scr, val;
632
633 switch (pd) {
634 case MIX_PD_MEDIAMIX:
635 mix_id = SRC_MIX_MEDIA;
636 mem_id = SRC_MEM_MEDIA;
637 scr = BIT(5);
638
639 /* Enable S400 handshake */
640 struct blk_ctrl_s_aonmix_regs *s_regs =
641 (struct blk_ctrl_s_aonmix_regs *)BLK_CTRL_S_ANOMIX_BASE_ADDR;
642
643 setbits_le32(&s_regs->lp_handshake[0], BIT(13));
644 break;
645 case MIX_PD_MLMIX:
646 mix_id = SRC_MIX_ML;
647 mem_id = SRC_MEM_ML;
648 scr = BIT(4);
649 break;
650 case MIX_PD_DDRMIX:
651 mix_id = SRC_MIX_DDRMIX;
652 mem_id = SRC_MEM_DDRMIX;
653 scr = BIT(6);
654 break;
655 default:
656 return -EINVAL;
657 }
658
659 mix_regs = (struct src_mix_slice_regs *)(ulong)(SRC_IPS_BASE_ADDR + 0x400 * (mix_id + 1));
660 mem_regs =
661 (struct src_mem_slice_regs *)(ulong)(SRC_IPS_BASE_ADDR + 0x3800 + 0x400 * mem_id);
662 global_regs = (struct src_general_regs *)(ulong)SRC_GLOBAL_RBASE;
663
664 /* Allow NS to set it */
665 setbits_le32(&mix_regs->authen_ctrl, BIT(9));
666
667 clrsetbits_le32(&mix_regs->psw_ack_ctrl[0], BIT(28), BIT(29));
668
669 /* mix reset will be held until boot core write this bit to 1 */
670 setbits_le32(&global_regs->scr, scr);
671
672 /* Enable mem in Low power auto sequence */
673 setbits_le32(&mem_regs->mem_ctrl, BIT(2));
674
675 /* Set the power down state */
676 val = readl(&mix_regs->func_stat);
677 if (val & SRC_MIX_SLICE_FUNC_STAT_PSW_STAT) {
678 /* The mix is default power off, power down it to make PDN_SFT bit
679 * aligned with FUNC STAT
680 */
681 setbits_le32(&mix_regs->slice_sw_ctrl, BIT(31));
682 val = readl(&mix_regs->func_stat);
683
684 /* Since PSW_STAT is 1, can't be used for power off status (SW_CTRL BIT31 set)) */
685 /* Check the MEM STAT change to ensure SSAR is completed */
686 while (!(val & SRC_MIX_SLICE_FUNC_STAT_MEM_STAT))
687 val = readl(&mix_regs->func_stat);
688
689 /* wait few ipg clock cycles to ensure FSM done and power off status is correct */
690 /* About 5 cycles at 24Mhz, 1us is enough */
691 udelay(1);
692 } else {
693 /* The mix is default power on, Do mix power cycle */
694 setbits_le32(&mix_regs->slice_sw_ctrl, BIT(31));
695 val = readl(&mix_regs->func_stat);
696 while (!(val & SRC_MIX_SLICE_FUNC_STAT_PSW_STAT))
697 val = readl(&mix_regs->func_stat);
698 }
699
700 /* power on */
701 clrbits_le32(&mix_regs->slice_sw_ctrl, BIT(31));
702 val = readl(&mix_regs->func_stat);
703 while (val & SRC_MIX_SLICE_FUNC_STAT_ISO_STAT)
704 val = readl(&mix_regs->func_stat);
705
706 return 0;
707}
708
709void disable_isolation(void)
710{
711 struct src_general_regs *global_regs = (struct src_general_regs *)(ulong)SRC_GLOBAL_RBASE;
712 /* clear isolation for usbphy, dsi, csi*/
713 writel(0x0, &global_regs->sp_iso_ctrl);
714}
715
716void soc_power_init(void)
717{
718 mix_power_init(MIX_PD_MEDIAMIX);
719 mix_power_init(MIX_PD_MLMIX);
720
721 disable_isolation();
722}
Peng Fan6d929962022-07-26 16:41:03 +0800723
Peng Fan313af252022-07-26 16:41:04 +0800724bool m33_is_rom_kicked(void)
Peng Fan6d929962022-07-26 16:41:03 +0800725{
726 struct blk_ctrl_s_aonmix_regs *s_regs =
727 (struct blk_ctrl_s_aonmix_regs *)BLK_CTRL_S_ANOMIX_BASE_ADDR;
728
729 if (!(readl(&s_regs->m33_cfg) & BIT(2)))
730 return true;
731
732 return false;
733}
734
735int m33_prepare(void)
736{
737 struct src_mix_slice_regs *mix_regs =
738 (struct src_mix_slice_regs *)(ulong)(SRC_IPS_BASE_ADDR + 0x400 * (SRC_MIX_CM33 + 1));
739 struct src_general_regs *global_regs =
740 (struct src_general_regs *)(ulong)SRC_GLOBAL_RBASE;
741 struct blk_ctrl_s_aonmix_regs *s_regs =
742 (struct blk_ctrl_s_aonmix_regs *)BLK_CTRL_S_ANOMIX_BASE_ADDR;
743 u32 val;
744
745 if (m33_is_rom_kicked())
746 return -EPERM;
747
748 /* Release reset of M33 */
749 setbits_le32(&global_regs->scr, BIT(0));
750
751 /* Check the reset released in M33 MIX func stat */
752 val = readl(&mix_regs->func_stat);
753 while (!(val & SRC_MIX_SLICE_FUNC_STAT_RST_STAT))
754 val = readl(&mix_regs->func_stat);
755
756 /* Release Sentinel TROUT */
757 ahab_release_m33_trout();
758
759 /* Mask WDOG1 IRQ from A55, we use it for M33 reset */
760 setbits_le32(&s_regs->ca55_irq_mask[1], BIT(6));
761
762 /* Turn on WDOG1 clock */
763 ccm_lpcg_on(CCGR_WDG1, 1);
764
765 /* Set sentinel LP handshake for M33 reset */
766 setbits_le32(&s_regs->lp_handshake[0], BIT(6));
767
768 /* Clear M33 TCM for ECC */
769 memset((void *)(ulong)0x201e0000, 0, 0x40000);
770
771 return 0;
772}
Peng Fanb1815c42023-04-28 12:08:27 +0800773
774int psci_sysreset_get_status(struct udevice *dev, char *buf, int size)
775{
776 static const char *reset_cause[] = {
777 "POR ",
778 "JTAG ",
779 "IPP USER ",
780 "WDOG1 ",
781 "WDOG2 ",
782 "WDOG3 ",
783 "WDOG4 ",
784 "WDOG5 ",
785 "TEMPSENSE ",
786 "CSU ",
787 "JTAG_SW ",
788 "M33_REQ ",
789 "M33_LOCKUP ",
790 "UNK ",
791 "UNK ",
792 "UNK "
793 };
794
795 struct src_general_regs *src = (struct src_general_regs *)SRC_GLOBAL_RBASE;
796 u32 srsr;
797 u32 i;
798 int res;
799
800 srsr = readl(&src->gpr[0]);
801
802 for (i = ARRAY_SIZE(reset_cause); i > 0; i--) {
803 if (srsr & (BIT(i - 1)))
804 break;
805 }
806
807 res = snprintf(buf, size, "Reset Status: %s\n", i ? reset_cause[i - 1] : "unknown reset");
808 if (res < 0) {
809 dev_err(dev, "Could not write reset status message (err = %d)\n", res);
810 return -EIO;
811 }
812
813 return 0;
814}