1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2022 MediaTek Inc. All rights reserved.
4  *
5  * Author: Weijie Gao <weijie.gao@mediatek.com>
6  */
7 
8 #include <asm/io.h>
9 #include <asm/cm.h>
10 #include <asm/sections.h>
11 #include <asm/addrspace.h>
12 #include <asm/mipsmtregs.h>
13 #include <linux/sizes.h>
14 #include <time.h>
15 #include <cpu_func.h>
16 #include "launch.h"
17 #include "../mt7621.h"
18 
19 /* Cluster Power Controller (CPC) offsets */
20 #define CPC_CL_OTHER			0x2010
21 #define CPC_CO_CMD			0x4000
22 
23 /* CPC_CL_OTHER fields */
24 #define CPC_CL_OTHER_CORENUM_SHIFT	16
25 #define CPC_CL_OTHER_CORENUM		GENMASK(23, 16)
26 
27 /* CPC_CO_CMD */
28 #define PWR_UP				3
29 
30 #define NUM_CORES			2
31 #define NUM_CPUS			4
32 #define WAIT_CPUS_TIMEOUT		4000
33 
copy_launch_wait_code(void)34 static void copy_launch_wait_code(void)
35 {
36 	memset((void *)KSEG1, 0, SZ_4K);
37 
38 	memcpy((void *)KSEG1ADDR(LAUNCH_WAITCODE),
39 	       &launch_wait_code_start,
40 	       &launch_wait_code_end - &launch_wait_code_start);
41 
42 	invalidate_dcache_range(KSEG0, SZ_4K);
43 }
44 
bootup_secondary_core(void)45 static void bootup_secondary_core(void)
46 {
47 	void __iomem *cpcbase = (void __iomem *)KSEG1ADDR(MIPS_CPC_BASE);
48 	int i;
49 
50 	for (i = 1; i < NUM_CORES; i++) {
51 		writel(i << CPC_CL_OTHER_CORENUM_SHIFT, cpcbase + CPC_CL_OTHER);
52 		writel(PWR_UP, cpcbase + CPC_CO_CMD);
53 	}
54 }
55 
secondary_cpu_init(void)56 void secondary_cpu_init(void)
57 {
58 	void __iomem *sysc = (void __iomem *)KSEG1ADDR(SYSCTL_BASE);
59 	u32 i, dual_core = 0, cpuready = 1, cpumask = 0x03;
60 	ulong wait_tick;
61 	struct cpulaunch_t *c;
62 
63 	/* Copy LAUNCH wait code used by other VPEs */
64 	copy_launch_wait_code();
65 
66 	dual_core = readl(sysc + SYSCTL_CHIP_REV_ID_REG) & CPU_ID;
67 
68 	if (dual_core) {
69 		/* Bootup secondary core for MT7621A */
70 		cpumask = 0x0f;
71 
72 		/* Make BootROM/TPL redirect Core1's bootup flow to our entry point */
73 		writel((uintptr_t)&_start, sysc + BOOT_SRAM_BASE_REG);
74 
75 		bootup_secondary_core();
76 	}
77 
78 	/* Join the coherent domain */
79 	join_coherent_domain(dual_core ? 2 : 1);
80 
81 	/* Bootup Core0/VPE1 */
82 	boot_vpe1();
83 
84 	/* Wait for all CPU ready */
85 	wait_tick = get_timer(0) + WAIT_CPUS_TIMEOUT;
86 
87 	while (time_before(get_timer(0), wait_tick)) {
88 		/* CPU0 is obviously ready */
89 		for (i = 1; i < NUM_CPUS; i++) {
90 			c = (struct cpulaunch_t *)(KSEG0ADDR(CPULAUNCH) +
91 						   (i << LOG2CPULAUNCH));
92 
93 			if (c->flags & LAUNCH_FREADY)
94 				cpuready |= BIT(i);
95 		}
96 
97 		if ((cpuready & cpumask) == cpumask)
98 			break;
99 	}
100 }
101