xref: /rk3399_rockchip-uboot/arch/arm/cpu/armv8/fsl-layerscape/mp.c (revision ec7483e34ea932fb68267dc0b1de30be51f271c9)
19f3183d2SMingkai Hu /*
29f3183d2SMingkai Hu  * Copyright 2014-2015 Freescale Semiconductor, Inc.
39f3183d2SMingkai Hu  *
49f3183d2SMingkai Hu  * SPDX-License-Identifier:	GPL-2.0+
59f3183d2SMingkai Hu  */
69f3183d2SMingkai Hu 
79f3183d2SMingkai Hu #include <common.h>
89f3183d2SMingkai Hu #include <asm/io.h>
99f3183d2SMingkai Hu #include <asm/system.h>
109f3183d2SMingkai Hu #include <asm/arch/mp.h>
119f3183d2SMingkai Hu #include <asm/arch/soc.h>
12e87c673cSPriyanka Jain #include "cpu.h"
13e87c673cSPriyanka Jain #include <asm/arch-fsl-layerscape/soc.h>
149f3183d2SMingkai Hu 
159f3183d2SMingkai Hu DECLARE_GLOBAL_DATA_PTR;
169f3183d2SMingkai Hu 
get_spin_tbl_addr(void)179f3183d2SMingkai Hu void *get_spin_tbl_addr(void)
189f3183d2SMingkai Hu {
199f3183d2SMingkai Hu 	return &__spin_table;
209f3183d2SMingkai Hu }
219f3183d2SMingkai Hu 
determine_mp_bootpg(void)229f3183d2SMingkai Hu phys_addr_t determine_mp_bootpg(void)
239f3183d2SMingkai Hu {
249f3183d2SMingkai Hu 	return (phys_addr_t)&secondary_boot_code;
259f3183d2SMingkai Hu }
269f3183d2SMingkai Hu 
update_os_arch_secondary_cores(uint8_t os_arch)27e2c18e40SAlison Wang void update_os_arch_secondary_cores(uint8_t os_arch)
28e2c18e40SAlison Wang {
29e2c18e40SAlison Wang 	u64 *table = get_spin_tbl_addr();
30e2c18e40SAlison Wang 	int i;
31e2c18e40SAlison Wang 
32*020b3ce8SAlison Wang 	for (i = 1; i < CONFIG_MAX_CPUS; i++) {
33*020b3ce8SAlison Wang 		if (os_arch == IH_ARCH_DEFAULT)
34e2c18e40SAlison Wang 			table[i * WORDS_PER_SPIN_TABLE_ENTRY +
35*020b3ce8SAlison Wang 				SPIN_TABLE_ELEM_ARCH_COMP_IDX] = OS_ARCH_SAME;
36*020b3ce8SAlison Wang 		else
37*020b3ce8SAlison Wang 			table[i * WORDS_PER_SPIN_TABLE_ENTRY +
38*020b3ce8SAlison Wang 				SPIN_TABLE_ELEM_ARCH_COMP_IDX] = OS_ARCH_DIFF;
39*020b3ce8SAlison Wang 	}
40e2c18e40SAlison Wang }
41e2c18e40SAlison Wang 
42e87c673cSPriyanka Jain #ifdef CONFIG_FSL_LSCH3
wake_secondary_core_n(int cluster,int core,int cluster_cores)43e87c673cSPriyanka Jain void wake_secondary_core_n(int cluster, int core, int cluster_cores)
44e87c673cSPriyanka Jain {
45e87c673cSPriyanka Jain 	struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
46e87c673cSPriyanka Jain 	struct ccsr_reset __iomem *rst = (void *)(CONFIG_SYS_FSL_RST_ADDR);
47e87c673cSPriyanka Jain 	u32 mpidr = 0;
48e87c673cSPriyanka Jain 
49e87c673cSPriyanka Jain 	mpidr = ((cluster << 8) | core);
50e87c673cSPriyanka Jain 	/*
51e87c673cSPriyanka Jain 	 * mpidr_el1 register value of core which needs to be released
52e87c673cSPriyanka Jain 	 * is written to scratchrw[6] register
53e87c673cSPriyanka Jain 	 */
54e87c673cSPriyanka Jain 	gur_out32(&gur->scratchrw[6], mpidr);
55e87c673cSPriyanka Jain 	asm volatile("dsb st" : : : "memory");
56e87c673cSPriyanka Jain 	rst->brrl |= 1 << ((cluster * cluster_cores) + core);
57e87c673cSPriyanka Jain 	asm volatile("dsb st" : : : "memory");
58e87c673cSPriyanka Jain 	/*
59e87c673cSPriyanka Jain 	 * scratchrw[6] register value is polled
60e87c673cSPriyanka Jain 	 * when the value becomes zero, this means that this core is up
61e87c673cSPriyanka Jain 	 * and running, next core can be released now
62e87c673cSPriyanka Jain 	 */
63e87c673cSPriyanka Jain 	while (gur_in32(&gur->scratchrw[6]) != 0)
64e87c673cSPriyanka Jain 		;
65e87c673cSPriyanka Jain }
66e87c673cSPriyanka Jain #endif
67e87c673cSPriyanka Jain 
fsl_layerscape_wake_seconday_cores(void)689f3183d2SMingkai Hu int fsl_layerscape_wake_seconday_cores(void)
699f3183d2SMingkai Hu {
709f3183d2SMingkai Hu 	struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
71831c068fSHou Zhiqiang #ifdef CONFIG_FSL_LSCH3
729f3183d2SMingkai Hu 	struct ccsr_reset __iomem *rst = (void *)(CONFIG_SYS_FSL_RST_ADDR);
73e87c673cSPriyanka Jain 	u32 svr, ver, cluster, type;
74e87c673cSPriyanka Jain 	int j = 0, cluster_cores = 0;
75831c068fSHou Zhiqiang #elif defined(CONFIG_FSL_LSCH2)
76831c068fSHou Zhiqiang 	struct ccsr_scfg __iomem *scfg = (void *)(CONFIG_SYS_FSL_SCFG_ADDR);
77831c068fSHou Zhiqiang #endif
789f3183d2SMingkai Hu 	u32 cores, cpu_up_mask = 1;
799f3183d2SMingkai Hu 	int i, timeout = 10;
809f3183d2SMingkai Hu 	u64 *table = get_spin_tbl_addr();
819f3183d2SMingkai Hu 
829f3183d2SMingkai Hu #ifdef COUNTER_FREQUENCY_REAL
839f3183d2SMingkai Hu 	/* update for secondary cores */
849f3183d2SMingkai Hu 	__real_cntfrq = COUNTER_FREQUENCY_REAL;
859f3183d2SMingkai Hu 	flush_dcache_range((unsigned long)&__real_cntfrq,
869f3183d2SMingkai Hu 			   (unsigned long)&__real_cntfrq + 8);
879f3183d2SMingkai Hu #endif
889f3183d2SMingkai Hu 
899f3183d2SMingkai Hu 	cores = cpu_mask();
909f3183d2SMingkai Hu 	/* Clear spin table so that secondary processors
919f3183d2SMingkai Hu 	 * observe the correct value after waking up from wfe.
929f3183d2SMingkai Hu 	 */
939f3183d2SMingkai Hu 	memset(table, 0, CONFIG_MAX_CPUS*SPIN_TABLE_ELEM_SIZE);
949f3183d2SMingkai Hu 	flush_dcache_range((unsigned long)table,
959f3183d2SMingkai Hu 			   (unsigned long)table +
969f3183d2SMingkai Hu 			   (CONFIG_MAX_CPUS*SPIN_TABLE_ELEM_SIZE));
979f3183d2SMingkai Hu 
989f3183d2SMingkai Hu 	printf("Waking secondary cores to start from %lx\n", gd->relocaddr);
999f3183d2SMingkai Hu 
100831c068fSHou Zhiqiang #ifdef CONFIG_FSL_LSCH3
1019f3183d2SMingkai Hu 	gur_out32(&gur->bootlocptrh, (u32)(gd->relocaddr >> 32));
1029f3183d2SMingkai Hu 	gur_out32(&gur->bootlocptrl, (u32)gd->relocaddr);
103e87c673cSPriyanka Jain 
104e87c673cSPriyanka Jain 	svr = gur_in32(&gur->svr);
105e87c673cSPriyanka Jain 	ver = SVR_SOC_VER(svr);
106e87c673cSPriyanka Jain 	if (ver == SVR_LS2080A || ver == SVR_LS2085A) {
1079f3183d2SMingkai Hu 		gur_out32(&gur->scratchrw[6], 1);
1089f3183d2SMingkai Hu 		asm volatile("dsb st" : : : "memory");
1099f3183d2SMingkai Hu 		rst->brrl = cores;
1109f3183d2SMingkai Hu 		asm volatile("dsb st" : : : "memory");
111e87c673cSPriyanka Jain 	} else {
112e87c673cSPriyanka Jain 		/*
113e87c673cSPriyanka Jain 		 * Release the cores out of reset one-at-a-time to avoid
114e87c673cSPriyanka Jain 		 * power spikes
115e87c673cSPriyanka Jain 		 */
116e87c673cSPriyanka Jain 		i = 0;
117e87c673cSPriyanka Jain 		cluster = in_le32(&gur->tp_cluster[i].lower);
118e87c673cSPriyanka Jain 		for (j = 0; j < TP_INIT_PER_CLUSTER; j++) {
119e87c673cSPriyanka Jain 			type = initiator_type(cluster, j);
120e87c673cSPriyanka Jain 			if (type &&
121e87c673cSPriyanka Jain 			    TP_ITYP_TYPE(type) == TP_ITYP_TYPE_ARM)
122e87c673cSPriyanka Jain 				cluster_cores++;
123e87c673cSPriyanka Jain 		}
124e87c673cSPriyanka Jain 
125e87c673cSPriyanka Jain 		do {
126e87c673cSPriyanka Jain 			cluster = in_le32(&gur->tp_cluster[i].lower);
127e87c673cSPriyanka Jain 			for (j = 0; j < TP_INIT_PER_CLUSTER; j++) {
128e87c673cSPriyanka Jain 				type = initiator_type(cluster, j);
129e87c673cSPriyanka Jain 				if (type &&
130e87c673cSPriyanka Jain 				    TP_ITYP_TYPE(type) == TP_ITYP_TYPE_ARM)
131e87c673cSPriyanka Jain 					wake_secondary_core_n(i, j,
132e87c673cSPriyanka Jain 							      cluster_cores);
133e87c673cSPriyanka Jain 			}
134e87c673cSPriyanka Jain 		i++;
135e87c673cSPriyanka Jain 		} while ((cluster & TP_CLUSTER_EOC) != TP_CLUSTER_EOC);
136e87c673cSPriyanka Jain 	}
137831c068fSHou Zhiqiang #elif defined(CONFIG_FSL_LSCH2)
138831c068fSHou Zhiqiang 	scfg_out32(&scfg->scratchrw[0], (u32)(gd->relocaddr >> 32));
139831c068fSHou Zhiqiang 	scfg_out32(&scfg->scratchrw[1], (u32)gd->relocaddr);
140831c068fSHou Zhiqiang 	asm volatile("dsb st" : : : "memory");
141831c068fSHou Zhiqiang 	gur_out32(&gur->brrl, cores);
142831c068fSHou Zhiqiang 	asm volatile("dsb st" : : : "memory");
1439f3183d2SMingkai Hu 
144831c068fSHou Zhiqiang 	/* Bootup online cores */
145831c068fSHou Zhiqiang 	scfg_out32(&scfg->corebcr, cores);
146831c068fSHou Zhiqiang #endif
1479f3183d2SMingkai Hu 	/* This is needed as a precautionary measure.
1489f3183d2SMingkai Hu 	 * If some code before this has accidentally  released the secondary
1499f3183d2SMingkai Hu 	 * cores then the pre-bootloader code will trap them in a "wfe" unless
1509f3183d2SMingkai Hu 	 * the scratchrw[6] is set. In this case we need a sev here to get these
1519f3183d2SMingkai Hu 	 * cores moving again.
1529f3183d2SMingkai Hu 	 */
1539f3183d2SMingkai Hu 	asm volatile("sev");
1549f3183d2SMingkai Hu 
1559f3183d2SMingkai Hu 	while (timeout--) {
1569f3183d2SMingkai Hu 		flush_dcache_range((unsigned long)table, (unsigned long)table +
1579f3183d2SMingkai Hu 				   CONFIG_MAX_CPUS * 64);
1589f3183d2SMingkai Hu 		for (i = 1; i < CONFIG_MAX_CPUS; i++) {
1599f3183d2SMingkai Hu 			if (table[i * WORDS_PER_SPIN_TABLE_ENTRY +
1609f3183d2SMingkai Hu 					SPIN_TABLE_ELEM_STATUS_IDX])
1619f3183d2SMingkai Hu 				cpu_up_mask |= 1 << i;
1629f3183d2SMingkai Hu 		}
1639f3183d2SMingkai Hu 		if (hweight32(cpu_up_mask) == hweight32(cores))
1649f3183d2SMingkai Hu 			break;
1659f3183d2SMingkai Hu 		udelay(10);
1669f3183d2SMingkai Hu 	}
1679f3183d2SMingkai Hu 	if (timeout <= 0) {
1689f3183d2SMingkai Hu 		printf("Not all cores (0x%x) are up (0x%x)\n",
1699f3183d2SMingkai Hu 		       cores, cpu_up_mask);
1709f3183d2SMingkai Hu 		return 1;
1719f3183d2SMingkai Hu 	}
1729f3183d2SMingkai Hu 	printf("All (%d) cores are up.\n", hweight32(cores));
1739f3183d2SMingkai Hu 
1749f3183d2SMingkai Hu 	return 0;
1759f3183d2SMingkai Hu }
1769f3183d2SMingkai Hu 
is_core_valid(unsigned int core)1779f3183d2SMingkai Hu int is_core_valid(unsigned int core)
1789f3183d2SMingkai Hu {
1799f3183d2SMingkai Hu 	return !!((1 << core) & cpu_mask());
1809f3183d2SMingkai Hu }
1819f3183d2SMingkai Hu 
is_pos_valid(unsigned int pos)182ef9a5fd8SYork Sun static int is_pos_valid(unsigned int pos)
183ef9a5fd8SYork Sun {
184ef9a5fd8SYork Sun 	return !!((1 << pos) & cpu_pos_mask());
185ef9a5fd8SYork Sun }
186ef9a5fd8SYork Sun 
is_core_online(u64 cpu_id)1879f3183d2SMingkai Hu int is_core_online(u64 cpu_id)
1889f3183d2SMingkai Hu {
1899f3183d2SMingkai Hu 	u64 *table;
1909f3183d2SMingkai Hu 	int pos = id_to_core(cpu_id);
1919f3183d2SMingkai Hu 	table = (u64 *)get_spin_tbl_addr() + pos * WORDS_PER_SPIN_TABLE_ENTRY;
1929f3183d2SMingkai Hu 	return table[SPIN_TABLE_ELEM_STATUS_IDX] == 1;
1939f3183d2SMingkai Hu }
1949f3183d2SMingkai Hu 
cpu_reset(int nr)1959f3183d2SMingkai Hu int cpu_reset(int nr)
1969f3183d2SMingkai Hu {
1979f3183d2SMingkai Hu 	puts("Feature is not implemented.\n");
1989f3183d2SMingkai Hu 
1999f3183d2SMingkai Hu 	return 0;
2009f3183d2SMingkai Hu }
2019f3183d2SMingkai Hu 
cpu_disable(int nr)2029f3183d2SMingkai Hu int cpu_disable(int nr)
2039f3183d2SMingkai Hu {
2049f3183d2SMingkai Hu 	puts("Feature is not implemented.\n");
2059f3183d2SMingkai Hu 
2069f3183d2SMingkai Hu 	return 0;
2079f3183d2SMingkai Hu }
2089f3183d2SMingkai Hu 
core_to_pos(int nr)209ef9a5fd8SYork Sun static int core_to_pos(int nr)
2109f3183d2SMingkai Hu {
211ef9a5fd8SYork Sun 	u32 cores = cpu_pos_mask();
2129f3183d2SMingkai Hu 	int i, count = 0;
2139f3183d2SMingkai Hu 
2149f3183d2SMingkai Hu 	if (nr == 0) {
2159f3183d2SMingkai Hu 		return 0;
2169f3183d2SMingkai Hu 	} else if (nr >= hweight32(cores)) {
2179f3183d2SMingkai Hu 		puts("Not a valid core number.\n");
2189f3183d2SMingkai Hu 		return -1;
2199f3183d2SMingkai Hu 	}
2209f3183d2SMingkai Hu 
2219f3183d2SMingkai Hu 	for (i = 1; i < 32; i++) {
222ef9a5fd8SYork Sun 		if (is_pos_valid(i)) {
2239f3183d2SMingkai Hu 			count++;
2249f3183d2SMingkai Hu 			if (count == nr)
2259f3183d2SMingkai Hu 				break;
2269f3183d2SMingkai Hu 		}
2279f3183d2SMingkai Hu 	}
2289f3183d2SMingkai Hu 
229ef9a5fd8SYork Sun 	if (count != nr)
230ef9a5fd8SYork Sun 		return -1;
231ef9a5fd8SYork Sun 
232ef9a5fd8SYork Sun 	return i;
2339f3183d2SMingkai Hu }
2349f3183d2SMingkai Hu 
cpu_status(int nr)2359f3183d2SMingkai Hu int cpu_status(int nr)
2369f3183d2SMingkai Hu {
2379f3183d2SMingkai Hu 	u64 *table;
2389f3183d2SMingkai Hu 	int pos;
2399f3183d2SMingkai Hu 
2409f3183d2SMingkai Hu 	if (nr == 0) {
2419f3183d2SMingkai Hu 		table = (u64 *)get_spin_tbl_addr();
2429f3183d2SMingkai Hu 		printf("table base @ 0x%p\n", table);
2439f3183d2SMingkai Hu 	} else {
2449f3183d2SMingkai Hu 		pos = core_to_pos(nr);
2459f3183d2SMingkai Hu 		if (pos < 0)
2469f3183d2SMingkai Hu 			return -1;
2479f3183d2SMingkai Hu 		table = (u64 *)get_spin_tbl_addr() + pos *
2489f3183d2SMingkai Hu 			WORDS_PER_SPIN_TABLE_ENTRY;
2499f3183d2SMingkai Hu 		printf("table @ 0x%p\n", table);
2509f3183d2SMingkai Hu 		printf("   addr - 0x%016llx\n",
2519f3183d2SMingkai Hu 		       table[SPIN_TABLE_ELEM_ENTRY_ADDR_IDX]);
2529f3183d2SMingkai Hu 		printf("   status   - 0x%016llx\n",
2539f3183d2SMingkai Hu 		       table[SPIN_TABLE_ELEM_STATUS_IDX]);
2549f3183d2SMingkai Hu 		printf("   lpid  - 0x%016llx\n",
2559f3183d2SMingkai Hu 		       table[SPIN_TABLE_ELEM_LPID_IDX]);
2569f3183d2SMingkai Hu 	}
2579f3183d2SMingkai Hu 
2589f3183d2SMingkai Hu 	return 0;
2599f3183d2SMingkai Hu }
2609f3183d2SMingkai Hu 
cpu_release(int nr,int argc,char * const argv[])2619f3183d2SMingkai Hu int cpu_release(int nr, int argc, char * const argv[])
2629f3183d2SMingkai Hu {
2639f3183d2SMingkai Hu 	u64 boot_addr;
2649f3183d2SMingkai Hu 	u64 *table = (u64 *)get_spin_tbl_addr();
2659f3183d2SMingkai Hu 	int pos;
2669f3183d2SMingkai Hu 
2679f3183d2SMingkai Hu 	pos = core_to_pos(nr);
2689f3183d2SMingkai Hu 	if (pos <= 0)
2699f3183d2SMingkai Hu 		return -1;
2709f3183d2SMingkai Hu 
2719f3183d2SMingkai Hu 	table += pos * WORDS_PER_SPIN_TABLE_ENTRY;
2729f3183d2SMingkai Hu 	boot_addr = simple_strtoull(argv[0], NULL, 16);
2739f3183d2SMingkai Hu 	table[SPIN_TABLE_ELEM_ENTRY_ADDR_IDX] = boot_addr;
2749f3183d2SMingkai Hu 	flush_dcache_range((unsigned long)table,
2759f3183d2SMingkai Hu 			   (unsigned long)table + SPIN_TABLE_ELEM_SIZE);
2769f3183d2SMingkai Hu 	asm volatile("dsb st");
2779f3183d2SMingkai Hu 	smp_kick_all_cpus();	/* only those with entry addr set will run */
2781f6236f0SYork Sun 	/*
2791f6236f0SYork Sun 	 * When the first release command runs, all cores are set to go. Those
2801f6236f0SYork Sun 	 * without a valid entry address will be trapped by "wfe". "sev" kicks
2811f6236f0SYork Sun 	 * them off to check the address again. When set, they continue to run.
2821f6236f0SYork Sun 	 */
2831f6236f0SYork Sun 	asm volatile("sev");
2849f3183d2SMingkai Hu 
2859f3183d2SMingkai Hu 	return 0;
2869f3183d2SMingkai Hu }
287