blob: ca312ff455ab6df0e99a23395ba4b638e182c645 [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 Fanbbcd2c42022-07-26 16:40:39 +0800162u32 get_cpu_rev(void)
163{
Peng Fan3700c472022-07-26 16:40:56 +0800164 u32 rev = (gd->arch.soc_rev >> 24) - 0xa0;
165
166 return (MXC_CPU_IMX93 << 12) | (CHIP_REV_1_0 + rev);
Peng Fanbbcd2c42022-07-26 16:40:39 +0800167}
168
Ye Li9e19ff92022-07-26 16:40:47 +0800169#define UNLOCK_WORD 0xD928C520 /* unlock word */
170#define REFRESH_WORD 0xB480A602 /* refresh word */
171
172static void disable_wdog(void __iomem *wdog_base)
173{
174 u32 val_cs = readl(wdog_base + 0x00);
175
176 if (!(val_cs & 0x80))
177 return;
178
179 /* default is 32bits cmd */
180 writel(REFRESH_WORD, (wdog_base + 0x04)); /* Refresh the CNT */
181
182 if (!(val_cs & 0x800)) {
183 writel(UNLOCK_WORD, (wdog_base + 0x04));
184 while (!(readl(wdog_base + 0x00) & 0x800))
185 ;
186 }
187 writel(0x0, (wdog_base + 0x0C)); /* Set WIN to 0 */
188 writel(0x400, (wdog_base + 0x08)); /* Set timeout to default 0x400 */
189 writel(0x2120, (wdog_base + 0x00)); /* Disable it and set update */
190
191 while (!(readl(wdog_base + 0x00) & 0x400))
192 ;
193}
194
195void init_wdog(void)
196{
197 u32 src_val;
198
199 disable_wdog((void __iomem *)WDG3_BASE_ADDR);
200 disable_wdog((void __iomem *)WDG4_BASE_ADDR);
201 disable_wdog((void __iomem *)WDG5_BASE_ADDR);
202
203 src_val = readl(0x54460018); /* reset mask */
204 src_val &= ~0x1c;
205 writel(src_val, 0x54460018);
206}
207
Peng Fanbbcd2c42022-07-26 16:40:39 +0800208static struct mm_region imx93_mem_map[] = {
209 {
210 /* ROM */
211 .virt = 0x0UL,
212 .phys = 0x0UL,
213 .size = 0x100000UL,
214 .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
215 PTE_BLOCK_OUTER_SHARE
216 }, {
Peng Fan313af252022-07-26 16:41:04 +0800217 /* TCM */
218 .virt = 0x201c0000UL,
219 .phys = 0x201c0000UL,
220 .size = 0x80000UL,
221 .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
222 PTE_BLOCK_NON_SHARE |
223 PTE_BLOCK_PXN | PTE_BLOCK_UXN
224 }, {
Peng Fanbbcd2c42022-07-26 16:40:39 +0800225 /* OCRAM */
226 .virt = 0x20480000UL,
227 .phys = 0x20480000UL,
228 .size = 0xA0000UL,
229 .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
230 PTE_BLOCK_OUTER_SHARE
231 }, {
232 /* AIPS */
233 .virt = 0x40000000UL,
234 .phys = 0x40000000UL,
235 .size = 0x40000000UL,
236 .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
237 PTE_BLOCK_NON_SHARE |
238 PTE_BLOCK_PXN | PTE_BLOCK_UXN
239 }, {
240 /* Flexible Serial Peripheral Interface */
241 .virt = 0x28000000UL,
242 .phys = 0x28000000UL,
243 .size = 0x30000000UL,
244 .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
245 PTE_BLOCK_NON_SHARE |
246 PTE_BLOCK_PXN | PTE_BLOCK_UXN
247 }, {
248 /* DRAM1 */
249 .virt = 0x80000000UL,
250 .phys = 0x80000000UL,
251 .size = PHYS_SDRAM_SIZE,
252 .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
253 PTE_BLOCK_OUTER_SHARE
254 }, {
255 /* empty entrie to split table entry 5 if needed when TEEs are used */
256 0,
257 }, {
258 /* List terminator */
259 0,
260 }
261};
262
263struct mm_region *mem_map = imx93_mem_map;
264
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800265static unsigned int imx9_find_dram_entry_in_mem_map(void)
266{
267 int i;
268
269 for (i = 0; i < ARRAY_SIZE(imx93_mem_map); i++)
270 if (imx93_mem_map[i].phys == CFG_SYS_SDRAM_BASE)
271 return i;
272
273 hang(); /* Entry not found, this must never happen. */
274}
275
276void enable_caches(void)
277{
278 /* If OPTEE runs, remove OPTEE memory from MMU table to avoid speculative prefetch
279 * If OPTEE does not run, still update the MMU table according to dram banks structure
280 * to set correct dram size from board_phys_sdram_size
281 */
282 int i = 0;
283 /*
284 * please make sure that entry initial value matches
285 * imx93_mem_map for DRAM1
286 */
287 int entry = imx9_find_dram_entry_in_mem_map();
288 u64 attrs = imx93_mem_map[entry].attrs;
289
290 while (i < CONFIG_NR_DRAM_BANKS &&
291 entry < ARRAY_SIZE(imx93_mem_map)) {
292 if (gd->bd->bi_dram[i].start == 0)
293 break;
294 imx93_mem_map[entry].phys = gd->bd->bi_dram[i].start;
295 imx93_mem_map[entry].virt = gd->bd->bi_dram[i].start;
296 imx93_mem_map[entry].size = gd->bd->bi_dram[i].size;
297 imx93_mem_map[entry].attrs = attrs;
298 debug("Added memory mapping (%d): %llx %llx\n", entry,
299 imx93_mem_map[entry].phys, imx93_mem_map[entry].size);
300 i++; entry++;
301 }
302
303 icache_enable();
304 dcache_enable();
305}
306
307__weak int board_phys_sdram_size(phys_size_t *size)
308{
309 if (!size)
310 return -EINVAL;
311
312 *size = PHYS_SDRAM_SIZE;
313
314#ifdef PHYS_SDRAM_2_SIZE
315 *size += PHYS_SDRAM_2_SIZE;
316#endif
317 return 0;
318}
319
Peng Fanbbcd2c42022-07-26 16:40:39 +0800320int dram_init(void)
321{
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800322 phys_size_t sdram_size;
323 int ret;
324
325 ret = board_phys_sdram_size(&sdram_size);
326 if (ret)
327 return ret;
328
329 /* rom_pointer[1] contains the size of TEE occupies */
330 if (rom_pointer[1])
331 gd->ram_size = sdram_size - rom_pointer[1];
332 else
333 gd->ram_size = sdram_size;
334
335 return 0;
336}
337
338int dram_init_banksize(void)
339{
340 int bank = 0;
341 int ret;
342 phys_size_t sdram_size;
343 phys_size_t sdram_b1_size, sdram_b2_size;
344
345 ret = board_phys_sdram_size(&sdram_size);
346 if (ret)
347 return ret;
348
349 /* Bank 1 can't cross over 4GB space */
350 if (sdram_size > 0x80000000) {
351 sdram_b1_size = 0x80000000;
352 sdram_b2_size = sdram_size - 0x80000000;
353 } else {
354 sdram_b1_size = sdram_size;
355 sdram_b2_size = 0;
356 }
357
358 gd->bd->bi_dram[bank].start = PHYS_SDRAM;
359 if (rom_pointer[1]) {
360 phys_addr_t optee_start = (phys_addr_t)rom_pointer[0];
361 phys_size_t optee_size = (size_t)rom_pointer[1];
362
363 gd->bd->bi_dram[bank].size = optee_start - gd->bd->bi_dram[bank].start;
364 if ((optee_start + optee_size) < (PHYS_SDRAM + sdram_b1_size)) {
365 if (++bank >= CONFIG_NR_DRAM_BANKS) {
366 puts("CONFIG_NR_DRAM_BANKS is not enough\n");
367 return -1;
368 }
369
370 gd->bd->bi_dram[bank].start = optee_start + optee_size;
371 gd->bd->bi_dram[bank].size = PHYS_SDRAM +
372 sdram_b1_size - gd->bd->bi_dram[bank].start;
373 }
374 } else {
375 gd->bd->bi_dram[bank].size = sdram_b1_size;
376 }
377
378 if (sdram_b2_size) {
379 if (++bank >= CONFIG_NR_DRAM_BANKS) {
380 puts("CONFIG_NR_DRAM_BANKS is not enough for SDRAM_2\n");
381 return -1;
382 }
383 gd->bd->bi_dram[bank].start = 0x100000000UL;
384 gd->bd->bi_dram[bank].size = sdram_b2_size;
385 }
Peng Fanbbcd2c42022-07-26 16:40:39 +0800386
387 return 0;
388}
389
Peng Fan1ed3c0a2023-04-28 12:08:20 +0800390phys_size_t get_effective_memsize(void)
391{
392 int ret;
393 phys_size_t sdram_size;
394 phys_size_t sdram_b1_size;
395
396 ret = board_phys_sdram_size(&sdram_size);
397 if (!ret) {
398 /* Bank 1 can't cross over 4GB space */
399 if (sdram_size > 0x80000000)
400 sdram_b1_size = 0x80000000;
401 else
402 sdram_b1_size = sdram_size;
403
404 if (rom_pointer[1]) {
405 /* We will relocate u-boot to top of dram1. TEE position has two cases:
406 * 1. At the top of dram1, Then return the size removed optee size.
407 * 2. In the middle of dram1, return the size of dram1.
408 */
409 if ((rom_pointer[0] + rom_pointer[1]) == (PHYS_SDRAM + sdram_b1_size))
410 return ((phys_addr_t)rom_pointer[0] - PHYS_SDRAM);
411 }
412
413 return sdram_b1_size;
414 } else {
415 return PHYS_SDRAM_SIZE;
416 }
417}
418
Peng Fanbbcd2c42022-07-26 16:40:39 +0800419void imx_get_mac_from_fuse(int dev_id, unsigned char *mac)
420{
Ye Li66baefb2023-04-28 12:08:21 +0800421 u32 val[2] = {};
422 int ret;
423
424 if (dev_id == 0) {
425 ret = fuse_read(39, 3, &val[0]);
426 if (ret)
427 goto err;
428
429 ret = fuse_read(39, 4, &val[1]);
430 if (ret)
431 goto err;
432
433 mac[0] = val[1] >> 8;
434 mac[1] = val[1];
435 mac[2] = val[0] >> 24;
436 mac[3] = val[0] >> 16;
437 mac[4] = val[0] >> 8;
438 mac[5] = val[0];
439
440 } else {
441 ret = fuse_read(39, 5, &val[0]);
442 if (ret)
443 goto err;
444
445 ret = fuse_read(39, 4, &val[1]);
446 if (ret)
447 goto err;
448
449 mac[0] = val[1] >> 24;
450 mac[1] = val[1] >> 16;
451 mac[2] = val[0] >> 24;
452 mac[3] = val[0] >> 16;
453 mac[4] = val[0] >> 8;
454 mac[5] = val[0];
455 }
456
457 debug("%s: MAC%d: %02x.%02x.%02x.%02x.%02x.%02x\n",
458 __func__, dev_id, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
459 return;
460err:
461 memset(mac, 0, 6);
462 printf("%s: fuse read err: %d\n", __func__, ret);
Peng Fanbbcd2c42022-07-26 16:40:39 +0800463}
464
465int print_cpuinfo(void)
466{
467 u32 cpurev;
468
469 cpurev = get_cpu_rev();
470
471 printf("CPU: i.MX93 rev%d.%d\n", (cpurev & 0x000F0) >> 4, (cpurev & 0x0000F) >> 0);
472
473 return 0;
474}
475
Peng Fanbbcd2c42022-07-26 16:40:39 +0800476int ft_system_setup(void *blob, struct bd_info *bd)
477{
478 return 0;
479}
Peng Fan3700c472022-07-26 16:40:56 +0800480
481#if defined(CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG)
482void get_board_serial(struct tag_serialnr *serialnr)
483{
484 printf("UID: 0x%x 0x%x 0x%x 0x%x\n",
485 gd->arch.uid[0], gd->arch.uid[1], gd->arch.uid[2], gd->arch.uid[3]);
486
487 serialnr->low = gd->arch.uid[0];
488 serialnr->high = gd->arch.uid[3];
489}
490#endif
Peng Fanbbcd2c42022-07-26 16:40:39 +0800491
Peng Fanb1815c42023-04-28 12:08:27 +0800492static void save_reset_cause(void)
493{
494 struct src_general_regs *src = (struct src_general_regs *)SRC_GLOBAL_RBASE;
495 u32 srsr = readl(&src->srsr);
496
497 /* clear srsr in sec mode */
498 writel(srsr, &src->srsr);
499
500 /* Save value to GPR1 to pass to nonsecure */
501 writel(srsr, &src->gpr[0]);
502}
503
Peng Fanbbcd2c42022-07-26 16:40:39 +0800504int arch_cpu_init(void)
505{
Ye Li9e19ff92022-07-26 16:40:47 +0800506 if (IS_ENABLED(CONFIG_SPL_BUILD)) {
507 /* Disable wdog */
508 init_wdog();
509
Peng Fan28b5cb52022-07-26 16:40:43 +0800510 clock_init();
Ye Li62185922022-07-26 16:40:54 +0800511
512 trdc_early_init();
Peng Fanb1815c42023-04-28 12:08:27 +0800513
514 /* Save SRC SRSR to GPR1 and clear it */
515 save_reset_cause();
Ye Li9e19ff92022-07-26 16:40:47 +0800516 }
Peng Fan28b5cb52022-07-26 16:40:43 +0800517
Peng Fanbbcd2c42022-07-26 16:40:39 +0800518 return 0;
519}
Peng Fan3700c472022-07-26 16:40:56 +0800520
521int imx9_probe_mu(void *ctx, struct event *event)
522{
523 struct udevice *devp;
524 int node, ret;
525 u32 res;
526 struct sentinel_get_info_data info;
527
528 node = fdt_node_offset_by_compatible(gd->fdt_blob, -1, "fsl,imx93-mu-s4");
529
530 ret = uclass_get_device_by_of_offset(UCLASS_MISC, node, &devp);
531 if (ret)
532 return ret;
533
534 if (gd->flags & GD_FLG_RELOC)
535 return 0;
536
537 ret = ahab_get_info(&info, &res);
538 if (ret)
539 return ret;
540
541 set_cpu_info(&info);
542
543 return 0;
544}
Simon Glass93074012023-05-04 16:50:45 -0600545EVENT_SPY(EVT_DM_POST_INIT_F, imx9_probe_mu);
Jian Liacf41a32022-07-26 16:40:46 +0800546
547int timer_init(void)
548{
549#ifdef CONFIG_SPL_BUILD
550 struct sctr_regs *sctr = (struct sctr_regs *)SYSCNT_CTRL_BASE_ADDR;
551 unsigned long freq = readl(&sctr->cntfid0);
552
553 /* Update with accurate clock frequency */
554 asm volatile("msr cntfrq_el0, %0" : : "r" (freq) : "memory");
555
556 clrsetbits_le32(&sctr->cntcr, SC_CNTCR_FREQ0 | SC_CNTCR_FREQ1,
557 SC_CNTCR_FREQ0 | SC_CNTCR_ENABLE | SC_CNTCR_HDBG);
558#endif
559
560 gd->arch.tbl = 0;
561 gd->arch.tbu = 0;
562
563 return 0;
564}
Peng Fan65563792022-07-26 16:41:02 +0800565
Ye Li8e8687c2022-07-26 16:41:05 +0800566enum env_location env_get_location(enum env_operation op, int prio)
567{
568 enum boot_device dev = get_boot_device();
569 enum env_location env_loc = ENVL_UNKNOWN;
570
571 if (prio)
572 return env_loc;
573
574 switch (dev) {
575#if defined(CONFIG_ENV_IS_IN_SPI_FLASH)
576 case QSPI_BOOT:
577 env_loc = ENVL_SPI_FLASH;
578 break;
579#endif
580#if defined(CONFIG_ENV_IS_IN_MMC)
581 case SD1_BOOT:
582 case SD2_BOOT:
583 case SD3_BOOT:
584 case MMC1_BOOT:
585 case MMC2_BOOT:
586 case MMC3_BOOT:
587 env_loc = ENVL_MMC;
588 break;
589#endif
590 default:
591#if defined(CONFIG_ENV_IS_NOWHERE)
592 env_loc = ENVL_NOWHERE;
593#endif
594 break;
595 }
596
597 return env_loc;
598}
599
Peng Fan65563792022-07-26 16:41:02 +0800600static int mix_power_init(enum mix_power_domain pd)
601{
602 enum src_mix_slice_id mix_id;
603 enum src_mem_slice_id mem_id;
604 struct src_mix_slice_regs *mix_regs;
605 struct src_mem_slice_regs *mem_regs;
606 struct src_general_regs *global_regs;
607 u32 scr, val;
608
609 switch (pd) {
610 case MIX_PD_MEDIAMIX:
611 mix_id = SRC_MIX_MEDIA;
612 mem_id = SRC_MEM_MEDIA;
613 scr = BIT(5);
614
615 /* Enable S400 handshake */
616 struct blk_ctrl_s_aonmix_regs *s_regs =
617 (struct blk_ctrl_s_aonmix_regs *)BLK_CTRL_S_ANOMIX_BASE_ADDR;
618
619 setbits_le32(&s_regs->lp_handshake[0], BIT(13));
620 break;
621 case MIX_PD_MLMIX:
622 mix_id = SRC_MIX_ML;
623 mem_id = SRC_MEM_ML;
624 scr = BIT(4);
625 break;
626 case MIX_PD_DDRMIX:
627 mix_id = SRC_MIX_DDRMIX;
628 mem_id = SRC_MEM_DDRMIX;
629 scr = BIT(6);
630 break;
631 default:
632 return -EINVAL;
633 }
634
635 mix_regs = (struct src_mix_slice_regs *)(ulong)(SRC_IPS_BASE_ADDR + 0x400 * (mix_id + 1));
636 mem_regs =
637 (struct src_mem_slice_regs *)(ulong)(SRC_IPS_BASE_ADDR + 0x3800 + 0x400 * mem_id);
638 global_regs = (struct src_general_regs *)(ulong)SRC_GLOBAL_RBASE;
639
640 /* Allow NS to set it */
641 setbits_le32(&mix_regs->authen_ctrl, BIT(9));
642
643 clrsetbits_le32(&mix_regs->psw_ack_ctrl[0], BIT(28), BIT(29));
644
645 /* mix reset will be held until boot core write this bit to 1 */
646 setbits_le32(&global_regs->scr, scr);
647
648 /* Enable mem in Low power auto sequence */
649 setbits_le32(&mem_regs->mem_ctrl, BIT(2));
650
651 /* Set the power down state */
652 val = readl(&mix_regs->func_stat);
653 if (val & SRC_MIX_SLICE_FUNC_STAT_PSW_STAT) {
654 /* The mix is default power off, power down it to make PDN_SFT bit
655 * aligned with FUNC STAT
656 */
657 setbits_le32(&mix_regs->slice_sw_ctrl, BIT(31));
658 val = readl(&mix_regs->func_stat);
659
660 /* Since PSW_STAT is 1, can't be used for power off status (SW_CTRL BIT31 set)) */
661 /* Check the MEM STAT change to ensure SSAR is completed */
662 while (!(val & SRC_MIX_SLICE_FUNC_STAT_MEM_STAT))
663 val = readl(&mix_regs->func_stat);
664
665 /* wait few ipg clock cycles to ensure FSM done and power off status is correct */
666 /* About 5 cycles at 24Mhz, 1us is enough */
667 udelay(1);
668 } else {
669 /* The mix is default power on, Do mix power cycle */
670 setbits_le32(&mix_regs->slice_sw_ctrl, BIT(31));
671 val = readl(&mix_regs->func_stat);
672 while (!(val & SRC_MIX_SLICE_FUNC_STAT_PSW_STAT))
673 val = readl(&mix_regs->func_stat);
674 }
675
676 /* power on */
677 clrbits_le32(&mix_regs->slice_sw_ctrl, BIT(31));
678 val = readl(&mix_regs->func_stat);
679 while (val & SRC_MIX_SLICE_FUNC_STAT_ISO_STAT)
680 val = readl(&mix_regs->func_stat);
681
682 return 0;
683}
684
685void disable_isolation(void)
686{
687 struct src_general_regs *global_regs = (struct src_general_regs *)(ulong)SRC_GLOBAL_RBASE;
688 /* clear isolation for usbphy, dsi, csi*/
689 writel(0x0, &global_regs->sp_iso_ctrl);
690}
691
692void soc_power_init(void)
693{
694 mix_power_init(MIX_PD_MEDIAMIX);
695 mix_power_init(MIX_PD_MLMIX);
696
697 disable_isolation();
698}
Peng Fan6d929962022-07-26 16:41:03 +0800699
Peng Fan313af252022-07-26 16:41:04 +0800700bool m33_is_rom_kicked(void)
Peng Fan6d929962022-07-26 16:41:03 +0800701{
702 struct blk_ctrl_s_aonmix_regs *s_regs =
703 (struct blk_ctrl_s_aonmix_regs *)BLK_CTRL_S_ANOMIX_BASE_ADDR;
704
705 if (!(readl(&s_regs->m33_cfg) & BIT(2)))
706 return true;
707
708 return false;
709}
710
711int m33_prepare(void)
712{
713 struct src_mix_slice_regs *mix_regs =
714 (struct src_mix_slice_regs *)(ulong)(SRC_IPS_BASE_ADDR + 0x400 * (SRC_MIX_CM33 + 1));
715 struct src_general_regs *global_regs =
716 (struct src_general_regs *)(ulong)SRC_GLOBAL_RBASE;
717 struct blk_ctrl_s_aonmix_regs *s_regs =
718 (struct blk_ctrl_s_aonmix_regs *)BLK_CTRL_S_ANOMIX_BASE_ADDR;
719 u32 val;
720
721 if (m33_is_rom_kicked())
722 return -EPERM;
723
724 /* Release reset of M33 */
725 setbits_le32(&global_regs->scr, BIT(0));
726
727 /* Check the reset released in M33 MIX func stat */
728 val = readl(&mix_regs->func_stat);
729 while (!(val & SRC_MIX_SLICE_FUNC_STAT_RST_STAT))
730 val = readl(&mix_regs->func_stat);
731
732 /* Release Sentinel TROUT */
733 ahab_release_m33_trout();
734
735 /* Mask WDOG1 IRQ from A55, we use it for M33 reset */
736 setbits_le32(&s_regs->ca55_irq_mask[1], BIT(6));
737
738 /* Turn on WDOG1 clock */
739 ccm_lpcg_on(CCGR_WDG1, 1);
740
741 /* Set sentinel LP handshake for M33 reset */
742 setbits_le32(&s_regs->lp_handshake[0], BIT(6));
743
744 /* Clear M33 TCM for ECC */
745 memset((void *)(ulong)0x201e0000, 0, 0x40000);
746
747 return 0;
748}
Peng Fanb1815c42023-04-28 12:08:27 +0800749
750int psci_sysreset_get_status(struct udevice *dev, char *buf, int size)
751{
752 static const char *reset_cause[] = {
753 "POR ",
754 "JTAG ",
755 "IPP USER ",
756 "WDOG1 ",
757 "WDOG2 ",
758 "WDOG3 ",
759 "WDOG4 ",
760 "WDOG5 ",
761 "TEMPSENSE ",
762 "CSU ",
763 "JTAG_SW ",
764 "M33_REQ ",
765 "M33_LOCKUP ",
766 "UNK ",
767 "UNK ",
768 "UNK "
769 };
770
771 struct src_general_regs *src = (struct src_general_regs *)SRC_GLOBAL_RBASE;
772 u32 srsr;
773 u32 i;
774 int res;
775
776 srsr = readl(&src->gpr[0]);
777
778 for (i = ARRAY_SIZE(reset_cause); i > 0; i--) {
779 if (srsr & (BIT(i - 1)))
780 break;
781 }
782
783 res = snprintf(buf, size, "Reset Status: %s\n", i ? reset_cause[i - 1] : "unknown reset");
784 if (res < 0) {
785 dev_err(dev, "Could not write reset status message (err = %d)\n", res);
786 return -EIO;
787 }
788
789 return 0;
790}