xref: /rk3399_rockchip-uboot/arch/arm/cpu/armv8/fsl-layerscape/mp.c (revision 8281c58fd46d095e28e60b2fb0ce84b4444896f8)
1 /*
2  * Copyright 2014-2015 Freescale Semiconductor, Inc.
3  *
4  * SPDX-License-Identifier:	GPL-2.0+
5  */
6 
7 #include <common.h>
8 #include <asm/io.h>
9 #include <asm/system.h>
10 #include <asm/arch/mp.h>
11 #include <asm/arch/soc.h>
12 
13 DECLARE_GLOBAL_DATA_PTR;
14 
15 void *get_spin_tbl_addr(void)
16 {
17 	return &__spin_table;
18 }
19 
20 phys_addr_t determine_mp_bootpg(void)
21 {
22 	return (phys_addr_t)&secondary_boot_code;
23 }
24 
25 int fsl_layerscape_wake_seconday_cores(void)
26 {
27 	struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
28 	struct ccsr_reset __iomem *rst = (void *)(CONFIG_SYS_FSL_RST_ADDR);
29 	u32 cores, cpu_up_mask = 1;
30 	int i, timeout = 10;
31 	u64 *table = get_spin_tbl_addr();
32 
33 #ifdef COUNTER_FREQUENCY_REAL
34 	/* update for secondary cores */
35 	__real_cntfrq = COUNTER_FREQUENCY_REAL;
36 	flush_dcache_range((unsigned long)&__real_cntfrq,
37 			   (unsigned long)&__real_cntfrq + 8);
38 #endif
39 
40 	cores = cpu_mask();
41 	/* Clear spin table so that secondary processors
42 	 * observe the correct value after waking up from wfe.
43 	 */
44 	memset(table, 0, CONFIG_MAX_CPUS*SPIN_TABLE_ELEM_SIZE);
45 	flush_dcache_range((unsigned long)table,
46 			   (unsigned long)table +
47 			   (CONFIG_MAX_CPUS*SPIN_TABLE_ELEM_SIZE));
48 
49 	printf("Waking secondary cores to start from %lx\n", gd->relocaddr);
50 
51 	gur_out32(&gur->bootlocptrh, (u32)(gd->relocaddr >> 32));
52 	gur_out32(&gur->bootlocptrl, (u32)gd->relocaddr);
53 	gur_out32(&gur->scratchrw[6], 1);
54 	asm volatile("dsb st" : : : "memory");
55 	rst->brrl = cores;
56 	asm volatile("dsb st" : : : "memory");
57 
58 	/* This is needed as a precautionary measure.
59 	 * If some code before this has accidentally  released the secondary
60 	 * cores then the pre-bootloader code will trap them in a "wfe" unless
61 	 * the scratchrw[6] is set. In this case we need a sev here to get these
62 	 * cores moving again.
63 	 */
64 	asm volatile("sev");
65 
66 	while (timeout--) {
67 		flush_dcache_range((unsigned long)table, (unsigned long)table +
68 				   CONFIG_MAX_CPUS * 64);
69 		for (i = 1; i < CONFIG_MAX_CPUS; i++) {
70 			if (table[i * WORDS_PER_SPIN_TABLE_ENTRY +
71 					SPIN_TABLE_ELEM_STATUS_IDX])
72 				cpu_up_mask |= 1 << i;
73 		}
74 		if (hweight32(cpu_up_mask) == hweight32(cores))
75 			break;
76 		udelay(10);
77 	}
78 	if (timeout <= 0) {
79 		printf("Not all cores (0x%x) are up (0x%x)\n",
80 		       cores, cpu_up_mask);
81 		return 1;
82 	}
83 	printf("All (%d) cores are up.\n", hweight32(cores));
84 
85 	return 0;
86 }
87 
88 int is_core_valid(unsigned int core)
89 {
90 	return !!((1 << core) & cpu_mask());
91 }
92 
93 int is_core_online(u64 cpu_id)
94 {
95 	u64 *table;
96 	int pos = id_to_core(cpu_id);
97 	table = (u64 *)get_spin_tbl_addr() + pos * WORDS_PER_SPIN_TABLE_ENTRY;
98 	return table[SPIN_TABLE_ELEM_STATUS_IDX] == 1;
99 }
100 
101 int cpu_reset(int nr)
102 {
103 	puts("Feature is not implemented.\n");
104 
105 	return 0;
106 }
107 
108 int cpu_disable(int nr)
109 {
110 	puts("Feature is not implemented.\n");
111 
112 	return 0;
113 }
114 
115 int core_to_pos(int nr)
116 {
117 	u32 cores = cpu_mask();
118 	int i, count = 0;
119 
120 	if (nr == 0) {
121 		return 0;
122 	} else if (nr >= hweight32(cores)) {
123 		puts("Not a valid core number.\n");
124 		return -1;
125 	}
126 
127 	for (i = 1; i < 32; i++) {
128 		if (is_core_valid(i)) {
129 			count++;
130 			if (count == nr)
131 				break;
132 		}
133 	}
134 
135 	return count;
136 }
137 
138 int cpu_status(int nr)
139 {
140 	u64 *table;
141 	int pos;
142 
143 	if (nr == 0) {
144 		table = (u64 *)get_spin_tbl_addr();
145 		printf("table base @ 0x%p\n", table);
146 	} else {
147 		pos = core_to_pos(nr);
148 		if (pos < 0)
149 			return -1;
150 		table = (u64 *)get_spin_tbl_addr() + pos *
151 			WORDS_PER_SPIN_TABLE_ENTRY;
152 		printf("table @ 0x%p\n", table);
153 		printf("   addr - 0x%016llx\n",
154 		       table[SPIN_TABLE_ELEM_ENTRY_ADDR_IDX]);
155 		printf("   status   - 0x%016llx\n",
156 		       table[SPIN_TABLE_ELEM_STATUS_IDX]);
157 		printf("   lpid  - 0x%016llx\n",
158 		       table[SPIN_TABLE_ELEM_LPID_IDX]);
159 	}
160 
161 	return 0;
162 }
163 
164 int cpu_release(int nr, int argc, char * const argv[])
165 {
166 	u64 boot_addr;
167 	u64 *table = (u64 *)get_spin_tbl_addr();
168 	int pos;
169 
170 	pos = core_to_pos(nr);
171 	if (pos <= 0)
172 		return -1;
173 
174 	table += pos * WORDS_PER_SPIN_TABLE_ENTRY;
175 	boot_addr = simple_strtoull(argv[0], NULL, 16);
176 	table[SPIN_TABLE_ELEM_ENTRY_ADDR_IDX] = boot_addr;
177 	flush_dcache_range((unsigned long)table,
178 			   (unsigned long)table + SPIN_TABLE_ELEM_SIZE);
179 	asm volatile("dsb st");
180 	smp_kick_all_cpus();	/* only those with entry addr set will run */
181 
182 	return 0;
183 }
184