1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright 2008-2011 Freescale Semiconductor, Inc.
4  */
5 
6 #include <common.h>
7 #include <cpu_func.h>
8 #include <env.h>
9 #include <log.h>
10 #include <asm/global_data.h>
11 #include <asm/processor.h>
12 #include <env.h>
13 #include <ioports.h>
14 #include <lmb.h>
15 #include <asm/io.h>
16 #include <asm/mmu.h>
17 #include <asm/fsl_law.h>
18 #include <fsl_ddr_sdram.h>
19 #include <linux/delay.h>
20 #include "mp.h"
21 
22 DECLARE_GLOBAL_DATA_PTR;
23 u32 fsl_ddr_get_intl3r(void);
24 
25 extern u32 __spin_table[];
26 
get_my_id()27 u32 get_my_id()
28 {
29 	return mfspr(SPRN_PIR);
30 }
31 
32 /*
33  * Determine if U-Boot should keep secondary cores in reset, or let them out
34  * of reset and hold them in a spinloop
35  */
hold_cores_in_reset(int verbose)36 int hold_cores_in_reset(int verbose)
37 {
38 	/* Default to no, overridden by 'y', 'yes', 'Y', 'Yes', or '1' */
39 	if (env_get_yesno("mp_holdoff") == 1) {
40 		if (verbose) {
41 			puts("Secondary cores are being held in reset.\n");
42 			puts("See 'mp_holdoff' environment variable\n");
43 		}
44 
45 		return 1;
46 	}
47 
48 	return 0;
49 }
50 
cpu_reset(u32 nr)51 int cpu_reset(u32 nr)
52 {
53 	volatile ccsr_pic_t *pic = (void *)(CONFIG_SYS_MPC8xxx_PIC_ADDR);
54 	out_be32(&pic->pir, 1 << nr);
55 	/* the dummy read works around an errata on early 85xx MP PICs */
56 	(void)in_be32(&pic->pir);
57 	out_be32(&pic->pir, 0x0);
58 
59 	return 0;
60 }
61 
cpu_status(u32 nr)62 int cpu_status(u32 nr)
63 {
64 	u32 *table, id = get_my_id();
65 
66 	if (hold_cores_in_reset(1))
67 		return 0;
68 
69 	if (nr == id) {
70 		table = (u32 *)&__spin_table;
71 		printf("table base @ 0x%p\n", table);
72 	} else if (is_core_disabled(nr)) {
73 		puts("Disabled\n");
74 	} else {
75 		table = (u32 *)&__spin_table + nr * NUM_BOOT_ENTRY;
76 		printf("Running on cpu %d\n", id);
77 		printf("\n");
78 		printf("table @ 0x%p\n", table);
79 		printf("   addr - 0x%08x\n", table[BOOT_ENTRY_ADDR_LOWER]);
80 		printf("   r3   - 0x%08x\n", table[BOOT_ENTRY_R3_LOWER]);
81 		printf("   pir  - 0x%08x\n", table[BOOT_ENTRY_PIR]);
82 	}
83 
84 	return 0;
85 }
86 
87 #ifdef CONFIG_FSL_CORENET
cpu_disable(u32 nr)88 int cpu_disable(u32 nr)
89 {
90 	volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
91 
92 	setbits_be32(&gur->coredisrl, 1 << nr);
93 
94 	return 0;
95 }
96 
is_core_disabled(int nr)97 int is_core_disabled(int nr) {
98 	ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
99 	u32 coredisrl = in_be32(&gur->coredisrl);
100 
101 	return (coredisrl & (1 << nr));
102 }
103 #else
cpu_disable(u32 nr)104 int cpu_disable(u32 nr)
105 {
106 	volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
107 
108 	switch (nr) {
109 	case 0:
110 		setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_CPU0);
111 		break;
112 	case 1:
113 		setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_CPU1);
114 		break;
115 	default:
116 		printf("Invalid cpu number for disable %d\n", nr);
117 		return 1;
118 	}
119 
120 	return 0;
121 }
122 
is_core_disabled(int nr)123 int is_core_disabled(int nr) {
124 	ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
125 	u32 devdisr = in_be32(&gur->devdisr);
126 
127 	switch (nr) {
128 	case 0:
129 		return (devdisr & MPC85xx_DEVDISR_CPU0);
130 	case 1:
131 		return (devdisr & MPC85xx_DEVDISR_CPU1);
132 	default:
133 		printf("Invalid cpu number for disable %d\n", nr);
134 	}
135 
136 	return 0;
137 }
138 #endif
139 
140 static u8 boot_entry_map[4] = {
141 	0,
142 	BOOT_ENTRY_PIR,
143 	BOOT_ENTRY_R3_LOWER,
144 };
145 
cpu_release(u32 nr,int argc,char * const argv[])146 int cpu_release(u32 nr, int argc, char *const argv[])
147 {
148 	u32 i, val, *table = (u32 *)&__spin_table + nr * NUM_BOOT_ENTRY;
149 	u64 boot_addr;
150 
151 	if (hold_cores_in_reset(1))
152 		return 0;
153 
154 	if (nr == get_my_id()) {
155 		printf("Invalid to release the boot core.\n\n");
156 		return 1;
157 	}
158 
159 	if (argc != 4) {
160 		printf("Invalid number of arguments to release.\n\n");
161 		return 1;
162 	}
163 
164 	boot_addr = simple_strtoull(argv[0], NULL, 16);
165 
166 	/* handle pir, r3 */
167 	for (i = 1; i < 3; i++) {
168 		if (argv[i][0] != '-') {
169 			u8 entry = boot_entry_map[i];
170 			val = simple_strtoul(argv[i], NULL, 16);
171 			table[entry] = val;
172 		}
173 	}
174 
175 	table[BOOT_ENTRY_ADDR_UPPER] = (u32)(boot_addr >> 32);
176 
177 	/* ensure all table updates complete before final address write */
178 	eieio();
179 
180 	table[BOOT_ENTRY_ADDR_LOWER] = (u32)(boot_addr & 0xffffffff);
181 
182 	return 0;
183 }
184 
determine_mp_bootpg(unsigned int * pagesize)185 u32 determine_mp_bootpg(unsigned int *pagesize)
186 {
187 	u32 bootpg;
188 #ifdef CONFIG_SYS_FSL_ERRATUM_A004468
189 	u32 svr = get_svr();
190 	u32 granule_size, check;
191 	struct law_entry e;
192 #endif
193 
194 
195 	/* use last 4K of mapped memory */
196 	bootpg = ((gd->ram_size > CONFIG_MAX_MEM_MAPPED) ?
197 		CONFIG_MAX_MEM_MAPPED : gd->ram_size) +
198 		CONFIG_SYS_SDRAM_BASE - 4096;
199 	if (pagesize)
200 		*pagesize = 4096;
201 
202 #ifdef CONFIG_SYS_FSL_ERRATUM_A004468
203 /*
204  * Erratum A004468 has two parts. The 3-way interleaving applies to T4240,
205  * to be fixed in rev 2.0. The 2-way interleaving applies to many SoCs. But
206  * the way boot page chosen in u-boot avoids hitting this erratum. So only
207  * thw workaround for 3-way interleaving is needed.
208  *
209  * To make sure boot page translation works with 3-Way DDR interleaving
210  * enforce a check for the following constrains
211  * 8K granule size requires BRSIZE=8K and
212  *    bootpg >> log2(BRSIZE) %3 == 1
213  * 4K and 1K granule size requires BRSIZE=4K and
214  *    bootpg >> log2(BRSIZE) %3 == 0
215  */
216 	if (SVR_SOC_VER(svr) == SVR_T4240 && SVR_MAJ(svr) < 2) {
217 		e = find_law(bootpg);
218 		switch (e.trgt_id) {
219 		case LAW_TRGT_IF_DDR_INTLV_123:
220 			granule_size = fsl_ddr_get_intl3r() & 0x1f;
221 			if (granule_size == FSL_DDR_3WAY_8KB_INTERLEAVING) {
222 				if (pagesize)
223 					*pagesize = 8192;
224 				bootpg &= 0xffffe000;	/* align to 8KB */
225 				check = bootpg >> 13;
226 				while ((check % 3) != 1)
227 					check--;
228 				bootpg = check << 13;
229 				debug("Boot page (8K) at 0x%08x\n", bootpg);
230 				break;
231 			} else {
232 				bootpg &= 0xfffff000;	/* align to 4KB */
233 				check = bootpg >> 12;
234 				while ((check % 3) != 0)
235 					check--;
236 				bootpg = check << 12;
237 				debug("Boot page (4K) at 0x%08x\n", bootpg);
238 			}
239 				break;
240 		default:
241 			break;
242 		}
243 	}
244 #endif /* CONFIG_SYS_FSL_ERRATUM_A004468 */
245 
246 	return bootpg;
247 }
248 
get_spin_phys_addr(void)249 phys_addr_t get_spin_phys_addr(void)
250 {
251 	return virt_to_phys(&__spin_table);
252 }
253 
254 #ifdef CONFIG_FSL_CORENET
plat_mp_up(unsigned long bootpg,unsigned int pagesize)255 static void plat_mp_up(unsigned long bootpg, unsigned int pagesize)
256 {
257 	u32 cpu_up_mask, whoami, brsize = LAW_SIZE_4K;
258 	u32 *table = (u32 *)&__spin_table;
259 	volatile ccsr_gur_t *gur;
260 	volatile ccsr_local_t *ccm;
261 	volatile ccsr_rcpm_t *rcpm;
262 	volatile ccsr_pic_t *pic;
263 	int timeout = 10;
264 	u32 mask = cpu_mask();
265 	struct law_entry e;
266 
267 	gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
268 	ccm = (void *)(CONFIG_SYS_FSL_CORENET_CCM_ADDR);
269 	rcpm = (void *)(CONFIG_SYS_FSL_CORENET_RCPM_ADDR);
270 	pic = (void *)(CONFIG_SYS_MPC8xxx_PIC_ADDR);
271 
272 	whoami = in_be32(&pic->whoami);
273 	cpu_up_mask = 1 << whoami;
274 	out_be32(&ccm->bstrl, bootpg);
275 
276 	e = find_law(bootpg);
277 	/* pagesize is only 4K or 8K */
278 	if (pagesize == 8192)
279 		brsize = LAW_SIZE_8K;
280 	out_be32(&ccm->bstrar, LAW_EN | e.trgt_id << 20 | brsize);
281 	debug("BRSIZE is 0x%x\n", brsize);
282 
283 	/* readback to sync write */
284 	in_be32(&ccm->bstrar);
285 
286 	/* disable time base at the platform */
287 	out_be32(&rcpm->ctbenrl, cpu_up_mask);
288 
289 	out_be32(&gur->brrl, mask);
290 
291 	/* wait for everyone */
292 	while (timeout) {
293 		unsigned int i, cpu, nr_cpus = cpu_numcores();
294 
295 		for_each_cpu(i, cpu, nr_cpus, mask) {
296 			if (table[cpu * NUM_BOOT_ENTRY + BOOT_ENTRY_ADDR_LOWER])
297 				cpu_up_mask |= (1 << cpu);
298 		}
299 
300 		if ((cpu_up_mask & mask) == mask)
301 			break;
302 
303 		udelay(100);
304 		timeout--;
305 	}
306 
307 	if (timeout == 0)
308 		printf("CPU up timeout. CPU up mask is %x should be %x\n",
309 			cpu_up_mask, mask);
310 
311 	/* enable time base at the platform */
312 	out_be32(&rcpm->ctbenrl, 0);
313 
314 	/* readback to sync write */
315 	in_be32(&rcpm->ctbenrl);
316 
317 	mtspr(SPRN_TBWU, 0);
318 	mtspr(SPRN_TBWL, 0);
319 
320 	out_be32(&rcpm->ctbenrl, mask);
321 
322 #ifdef CONFIG_MPC8xxx_DISABLE_BPTR
323 	/*
324 	 * Disabling Boot Page Translation allows the memory region 0xfffff000
325 	 * to 0xffffffff to be used normally.  Leaving Boot Page Translation
326 	 * enabled remaps 0xfffff000 to SDRAM which makes that memory region
327 	 * unusable for normal operation but it does allow OSes to easily
328 	 * reset a processor core to put it back into U-Boot's spinloop.
329 	 */
330 	clrbits_be32(&ccm->bstrar, LAW_EN);
331 #endif
332 }
333 #else
plat_mp_up(unsigned long bootpg,unsigned int pagesize)334 static void plat_mp_up(unsigned long bootpg, unsigned int pagesize)
335 {
336 	u32 up, cpu_up_mask, whoami;
337 	u32 *table = (u32 *)&__spin_table;
338 	volatile u32 bpcr;
339 	volatile ccsr_local_ecm_t *ecm = (void *)(CONFIG_SYS_MPC85xx_ECM_ADDR);
340 	volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
341 	volatile ccsr_pic_t *pic = (void *)(CONFIG_SYS_MPC8xxx_PIC_ADDR);
342 	u32 devdisr;
343 	int timeout = 10;
344 
345 	whoami = in_be32(&pic->whoami);
346 	out_be32(&ecm->bptr, 0x80000000 | (bootpg >> 12));
347 
348 	/* disable time base at the platform */
349 	devdisr = in_be32(&gur->devdisr);
350 	if (whoami)
351 		devdisr |= MPC85xx_DEVDISR_TB0;
352 	else
353 		devdisr |= MPC85xx_DEVDISR_TB1;
354 	out_be32(&gur->devdisr, devdisr);
355 
356 	/* release the hounds */
357 	up = ((1 << cpu_numcores()) - 1);
358 	bpcr = in_be32(&ecm->eebpcr);
359 	bpcr |= (up << 24);
360 	out_be32(&ecm->eebpcr, bpcr);
361 	asm("sync; isync; msync");
362 
363 	cpu_up_mask = 1 << whoami;
364 	/* wait for everyone */
365 	while (timeout) {
366 		int i;
367 		for (i = 0; i < cpu_numcores(); i++) {
368 			if (table[i * NUM_BOOT_ENTRY + BOOT_ENTRY_ADDR_LOWER])
369 				cpu_up_mask |= (1 << i);
370 		};
371 
372 		if ((cpu_up_mask & up) == up)
373 			break;
374 
375 		udelay(100);
376 		timeout--;
377 	}
378 
379 	if (timeout == 0)
380 		printf("CPU up timeout. CPU up mask is %x should be %x\n",
381 			cpu_up_mask, up);
382 
383 	/* enable time base at the platform */
384 	if (whoami)
385 		devdisr |= MPC85xx_DEVDISR_TB1;
386 	else
387 		devdisr |= MPC85xx_DEVDISR_TB0;
388 	out_be32(&gur->devdisr, devdisr);
389 
390 	/* readback to sync write */
391 	in_be32(&gur->devdisr);
392 
393 	mtspr(SPRN_TBWU, 0);
394 	mtspr(SPRN_TBWL, 0);
395 
396 	devdisr &= ~(MPC85xx_DEVDISR_TB0 | MPC85xx_DEVDISR_TB1);
397 	out_be32(&gur->devdisr, devdisr);
398 
399 #ifdef CONFIG_MPC8xxx_DISABLE_BPTR
400 	/*
401 	 * Disabling Boot Page Translation allows the memory region 0xfffff000
402 	 * to 0xffffffff to be used normally.  Leaving Boot Page Translation
403 	 * enabled remaps 0xfffff000 to SDRAM which makes that memory region
404 	 * unusable for normal operation but it does allow OSes to easily
405 	 * reset a processor core to put it back into U-Boot's spinloop.
406 	 */
407 	clrbits_be32(&ecm->bptr, 0x80000000);
408 #endif
409 }
410 #endif
411 
cpu_mp_lmb_reserve(struct lmb * lmb)412 void cpu_mp_lmb_reserve(struct lmb *lmb)
413 {
414 	u32 bootpg = determine_mp_bootpg(NULL);
415 
416 	lmb_reserve(lmb, bootpg, 4096);
417 }
418 
setup_mp(void)419 void setup_mp(void)
420 {
421 	extern u32 __secondary_start_page;
422 	extern u32 __bootpg_addr, __spin_table_addr, __second_half_boot_page;
423 
424 	int i;
425 	ulong fixup = (u32)&__secondary_start_page;
426 	u32 bootpg, bootpg_map, pagesize;
427 
428 	bootpg = determine_mp_bootpg(&pagesize);
429 
430 	/*
431 	 * pagesize is only 4K or 8K
432 	 * we only use the last 4K of boot page
433 	 * bootpg_map saves the address for the boot page
434 	 * 8K is used for the workaround of 3-way DDR interleaving
435 	 */
436 
437 	bootpg_map = bootpg;
438 
439 	if (pagesize == 8192)
440 		bootpg += 4096;	/* use 2nd half */
441 
442 	/* Some OSes expect secondary cores to be held in reset */
443 	if (hold_cores_in_reset(0))
444 		return;
445 
446 	/*
447 	 * Store the bootpg's cache-able half address for use by secondary
448 	 * CPU cores to continue to boot
449 	 */
450 	__bootpg_addr = (u32)virt_to_phys(&__second_half_boot_page);
451 
452 	/* Store spin table's physical address for use by secondary cores */
453 	__spin_table_addr = (u32)get_spin_phys_addr();
454 
455 	/* flush bootpg it before copying invalidate any staled cacheline */
456 	flush_cache(bootpg, 4096);
457 
458 	/* look for the tlb covering the reset page, there better be one */
459 	i = find_tlb_idx((void *)CONFIG_BPTR_VIRT_ADDR, 1);
460 
461 	/* we found a match */
462 	if (i != -1) {
463 		/* map reset page to bootpg so we can copy code there */
464 		disable_tlb(i);
465 
466 		set_tlb(1, CONFIG_BPTR_VIRT_ADDR, bootpg, /* tlb, epn, rpn */
467 			MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, /* perms, wimge */
468 			0, i, BOOKE_PAGESZ_4K, 1); /* ts, esel, tsize, iprot */
469 
470 		memcpy((void *)CONFIG_BPTR_VIRT_ADDR, (void *)fixup, 4096);
471 
472 		plat_mp_up(bootpg_map, pagesize);
473 	} else {
474 		puts("WARNING: No reset page TLB. "
475 			"Skipping secondary core setup\n");
476 	}
477 }
478