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