xref: /rk3399_rockchip-uboot/arch/powerpc/cpu/mpc85xx/mp.c (revision 3f0997b3255c1498ac92453aa3a7a1cc95914dfd)
1a47a12beSStefan Roese /*
2e81241afSEd Swarthout  * Copyright 2008-2011 Freescale Semiconductor, Inc.
3a47a12beSStefan Roese  *
4a47a12beSStefan Roese  * See file CREDITS for list of people who contributed to this
5a47a12beSStefan Roese  * project.
6a47a12beSStefan Roese  *
7a47a12beSStefan Roese  * This program is free software; you can redistribute it and/or
8a47a12beSStefan Roese  * modify it under the terms of the GNU General Public License as
9a47a12beSStefan Roese  * published by the Free Software Foundation; either version 2 of
10a47a12beSStefan Roese  * the License, or (at your option) any later version.
11a47a12beSStefan Roese  *
12a47a12beSStefan Roese  * This program is distributed in the hope that it will be useful,
13a47a12beSStefan Roese  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14a47a12beSStefan Roese  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15a47a12beSStefan Roese  * GNU General Public License for more details.
16a47a12beSStefan Roese  *
17a47a12beSStefan Roese  * You should have received a copy of the GNU General Public License
18a47a12beSStefan Roese  * along with this program; if not, write to the Free Software
19a47a12beSStefan Roese  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20a47a12beSStefan Roese  * MA 02111-1307 USA
21a47a12beSStefan Roese  */
22a47a12beSStefan Roese 
23a47a12beSStefan Roese #include <common.h>
24a47a12beSStefan Roese #include <asm/processor.h>
25a47a12beSStefan Roese #include <ioports.h>
26a47a12beSStefan Roese #include <lmb.h>
27a47a12beSStefan Roese #include <asm/io.h>
28a47a12beSStefan Roese #include <asm/mmu.h>
29a47a12beSStefan Roese #include <asm/fsl_law.h>
30eb539412SYork Sun #include <asm/fsl_ddr_sdram.h>
31a47a12beSStefan Roese #include "mp.h"
32a47a12beSStefan Roese 
33a47a12beSStefan Roese DECLARE_GLOBAL_DATA_PTR;
34eb539412SYork Sun u32 fsl_ddr_get_intl3r(void);
35a47a12beSStefan Roese 
36a47a12beSStefan Roese u32 get_my_id()
37a47a12beSStefan Roese {
38a47a12beSStefan Roese 	return mfspr(SPRN_PIR);
39a47a12beSStefan Roese }
40a47a12beSStefan Roese 
419d64c6bbSAaron Sierra /*
429d64c6bbSAaron Sierra  * Determine if U-Boot should keep secondary cores in reset, or let them out
439d64c6bbSAaron Sierra  * of reset and hold them in a spinloop
449d64c6bbSAaron Sierra  */
459d64c6bbSAaron Sierra int hold_cores_in_reset(int verbose)
469d64c6bbSAaron Sierra {
479d64c6bbSAaron Sierra 	const char *s = getenv("mp_holdoff");
489d64c6bbSAaron Sierra 
499d64c6bbSAaron Sierra 	/* Default to no, overriden by 'y', 'yes', 'Y', 'Yes', or '1' */
509d64c6bbSAaron Sierra 	if (s && (*s == 'y' || *s == 'Y' || *s == '1')) {
519d64c6bbSAaron Sierra 		if (verbose) {
529d64c6bbSAaron Sierra 			puts("Secondary cores are being held in reset.\n");
539d64c6bbSAaron Sierra 			puts("See 'mp_holdoff' environment variable\n");
549d64c6bbSAaron Sierra 		}
559d64c6bbSAaron Sierra 
569d64c6bbSAaron Sierra 		return 1;
579d64c6bbSAaron Sierra 	}
589d64c6bbSAaron Sierra 
599d64c6bbSAaron Sierra 	return 0;
609d64c6bbSAaron Sierra }
619d64c6bbSAaron Sierra 
62a47a12beSStefan Roese int cpu_reset(int nr)
63a47a12beSStefan Roese {
64680c613aSKim Phillips 	volatile ccsr_pic_t *pic = (void *)(CONFIG_SYS_MPC8xxx_PIC_ADDR);
65a47a12beSStefan Roese 	out_be32(&pic->pir, 1 << nr);
66a47a12beSStefan Roese 	/* the dummy read works around an errata on early 85xx MP PICs */
67a47a12beSStefan Roese 	(void)in_be32(&pic->pir);
68a47a12beSStefan Roese 	out_be32(&pic->pir, 0x0);
69a47a12beSStefan Roese 
70a47a12beSStefan Roese 	return 0;
71a47a12beSStefan Roese }
72a47a12beSStefan Roese 
73a47a12beSStefan Roese int cpu_status(int nr)
74a47a12beSStefan Roese {
75a47a12beSStefan Roese 	u32 *table, id = get_my_id();
76a47a12beSStefan Roese 
779d64c6bbSAaron Sierra 	if (hold_cores_in_reset(1))
789d64c6bbSAaron Sierra 		return 0;
799d64c6bbSAaron Sierra 
80a47a12beSStefan Roese 	if (nr == id) {
81a47a12beSStefan Roese 		table = (u32 *)get_spin_virt_addr();
82a47a12beSStefan Roese 		printf("table base @ 0x%p\n", table);
83a47a12beSStefan Roese 	} else {
84a47a12beSStefan Roese 		table = (u32 *)get_spin_virt_addr() + nr * NUM_BOOT_ENTRY;
85a47a12beSStefan Roese 		printf("Running on cpu %d\n", id);
86a47a12beSStefan Roese 		printf("\n");
87a47a12beSStefan Roese 		printf("table @ 0x%p\n", table);
88a47a12beSStefan Roese 		printf("   addr - 0x%08x\n", table[BOOT_ENTRY_ADDR_LOWER]);
89a47a12beSStefan Roese 		printf("   r3   - 0x%08x\n", table[BOOT_ENTRY_R3_LOWER]);
90*3f0997b3SYork Sun 		printf("   pir  - 0x%08x\n", table[BOOT_ENTRY_PIR]);
91a47a12beSStefan Roese 	}
92a47a12beSStefan Roese 
93a47a12beSStefan Roese 	return 0;
94a47a12beSStefan Roese }
95a47a12beSStefan Roese 
96a47a12beSStefan Roese #ifdef CONFIG_FSL_CORENET
97a47a12beSStefan Roese int cpu_disable(int nr)
98a47a12beSStefan Roese {
99a47a12beSStefan Roese 	volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
100a47a12beSStefan Roese 
101a47a12beSStefan Roese 	setbits_be32(&gur->coredisrl, 1 << nr);
102a47a12beSStefan Roese 
103a47a12beSStefan Roese 	return 0;
104a47a12beSStefan Roese }
1058f3a7fa4SKumar Gala 
1068f3a7fa4SKumar Gala int is_core_disabled(int nr) {
1078f3a7fa4SKumar Gala 	ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
1088f3a7fa4SKumar Gala 	u32 coredisrl = in_be32(&gur->coredisrl);
1098f3a7fa4SKumar Gala 
1108f3a7fa4SKumar Gala 	return (coredisrl & (1 << nr));
1118f3a7fa4SKumar Gala }
112a47a12beSStefan Roese #else
113a47a12beSStefan Roese int cpu_disable(int nr)
114a47a12beSStefan Roese {
115a47a12beSStefan Roese 	volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
116a47a12beSStefan Roese 
117a47a12beSStefan Roese 	switch (nr) {
118a47a12beSStefan Roese 	case 0:
119a47a12beSStefan Roese 		setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_CPU0);
120a47a12beSStefan Roese 		break;
121a47a12beSStefan Roese 	case 1:
122a47a12beSStefan Roese 		setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_CPU1);
123a47a12beSStefan Roese 		break;
124a47a12beSStefan Roese 	default:
125a47a12beSStefan Roese 		printf("Invalid cpu number for disable %d\n", nr);
126a47a12beSStefan Roese 		return 1;
127a47a12beSStefan Roese 	}
128a47a12beSStefan Roese 
129a47a12beSStefan Roese 	return 0;
130a47a12beSStefan Roese }
1318f3a7fa4SKumar Gala 
1328f3a7fa4SKumar Gala int is_core_disabled(int nr) {
1338f3a7fa4SKumar Gala 	ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
1348f3a7fa4SKumar Gala 	u32 devdisr = in_be32(&gur->devdisr);
1358f3a7fa4SKumar Gala 
1368f3a7fa4SKumar Gala 	switch (nr) {
1378f3a7fa4SKumar Gala 	case 0:
1388f3a7fa4SKumar Gala 		return (devdisr & MPC85xx_DEVDISR_CPU0);
1398f3a7fa4SKumar Gala 	case 1:
1408f3a7fa4SKumar Gala 		return (devdisr & MPC85xx_DEVDISR_CPU1);
1418f3a7fa4SKumar Gala 	default:
1428f3a7fa4SKumar Gala 		printf("Invalid cpu number for disable %d\n", nr);
1438f3a7fa4SKumar Gala 	}
1448f3a7fa4SKumar Gala 
1458f3a7fa4SKumar Gala 	return 0;
1468f3a7fa4SKumar Gala }
147a47a12beSStefan Roese #endif
148a47a12beSStefan Roese 
149a47a12beSStefan Roese static u8 boot_entry_map[4] = {
150a47a12beSStefan Roese 	0,
151a47a12beSStefan Roese 	BOOT_ENTRY_PIR,
152a47a12beSStefan Roese 	BOOT_ENTRY_R3_LOWER,
153a47a12beSStefan Roese };
154a47a12beSStefan Roese 
15554841ab5SWolfgang Denk int cpu_release(int nr, int argc, char * const argv[])
156a47a12beSStefan Roese {
157a47a12beSStefan Roese 	u32 i, val, *table = (u32 *)get_spin_virt_addr() + nr * NUM_BOOT_ENTRY;
158a47a12beSStefan Roese 	u64 boot_addr;
159a47a12beSStefan Roese 
1609d64c6bbSAaron Sierra 	if (hold_cores_in_reset(1))
1619d64c6bbSAaron Sierra 		return 0;
1629d64c6bbSAaron Sierra 
163a47a12beSStefan Roese 	if (nr == get_my_id()) {
164a47a12beSStefan Roese 		printf("Invalid to release the boot core.\n\n");
165a47a12beSStefan Roese 		return 1;
166a47a12beSStefan Roese 	}
167a47a12beSStefan Roese 
168a47a12beSStefan Roese 	if (argc != 4) {
169a47a12beSStefan Roese 		printf("Invalid number of arguments to release.\n\n");
170a47a12beSStefan Roese 		return 1;
171a47a12beSStefan Roese 	}
172a47a12beSStefan Roese 
173a47a12beSStefan Roese 	boot_addr = simple_strtoull(argv[0], NULL, 16);
174a47a12beSStefan Roese 
175*3f0997b3SYork Sun 	/* handle pir, r3 */
176*3f0997b3SYork Sun 	for (i = 1; i < 3; i++) {
177a47a12beSStefan Roese 		if (argv[i][0] != '-') {
178a47a12beSStefan Roese 			u8 entry = boot_entry_map[i];
179a47a12beSStefan Roese 			val = simple_strtoul(argv[i], NULL, 16);
180a47a12beSStefan Roese 			table[entry] = val;
181a47a12beSStefan Roese 		}
182a47a12beSStefan Roese 	}
183a47a12beSStefan Roese 
184a47a12beSStefan Roese 	table[BOOT_ENTRY_ADDR_UPPER] = (u32)(boot_addr >> 32);
185a47a12beSStefan Roese 
186a47a12beSStefan Roese 	/* ensure all table updates complete before final address write */
187a47a12beSStefan Roese 	eieio();
188a47a12beSStefan Roese 
189a47a12beSStefan Roese 	table[BOOT_ENTRY_ADDR_LOWER] = (u32)(boot_addr & 0xffffffff);
190a47a12beSStefan Roese 
191a47a12beSStefan Roese 	return 0;
192a47a12beSStefan Roese }
193a47a12beSStefan Roese 
194eb539412SYork Sun u32 determine_mp_bootpg(unsigned int *pagesize)
195a47a12beSStefan Roese {
196eb539412SYork Sun 	u32 bootpg;
197eb539412SYork Sun #ifdef CONFIG_SYS_FSL_ERRATUM_A004468
198eb539412SYork Sun 	u32 svr = get_svr();
199eb539412SYork Sun 	u32 granule_size, check;
200eb539412SYork Sun 	struct law_entry e;
201eb539412SYork Sun #endif
202eb539412SYork Sun 
203a47a12beSStefan Roese 	/* if we have 4G or more of memory, put the boot page at 4Gb-4k */
204a47a12beSStefan Roese 	if ((u64)gd->ram_size > 0xfffff000)
205eb539412SYork Sun 		bootpg = 0xfffff000;
206eb539412SYork Sun 	else
207eb539412SYork Sun 		bootpg = gd->ram_size - 4096;
208eb539412SYork Sun 	if (pagesize)
209eb539412SYork Sun 		*pagesize = 4096;
210a47a12beSStefan Roese 
211eb539412SYork Sun #ifdef CONFIG_SYS_FSL_ERRATUM_A004468
212eb539412SYork Sun /*
213eb539412SYork Sun  * Erratum A004468 has two parts. The 3-way interleaving applies to T4240,
214eb539412SYork Sun  * to be fixed in rev 2.0. The 2-way interleaving applies to many SoCs. But
215eb539412SYork Sun  * the way boot page chosen in u-boot avoids hitting this erratum. So only
216eb539412SYork Sun  * thw workaround for 3-way interleaving is needed.
217eb539412SYork Sun  *
218eb539412SYork Sun  * To make sure boot page translation works with 3-Way DDR interleaving
219eb539412SYork Sun  * enforce a check for the following constrains
220eb539412SYork Sun  * 8K granule size requires BRSIZE=8K and
221eb539412SYork Sun  *    bootpg >> log2(BRSIZE) %3 == 1
222eb539412SYork Sun  * 4K and 1K granule size requires BRSIZE=4K and
223eb539412SYork Sun  *    bootpg >> log2(BRSIZE) %3 == 0
224eb539412SYork Sun  */
225eb539412SYork Sun 	if (SVR_SOC_VER(svr) == SVR_T4240 && SVR_MAJ(svr) < 2) {
226eb539412SYork Sun 		e = find_law(bootpg);
227eb539412SYork Sun 		switch (e.trgt_id) {
228eb539412SYork Sun 		case LAW_TRGT_IF_DDR_INTLV_123:
229eb539412SYork Sun 			granule_size = fsl_ddr_get_intl3r() & 0x1f;
230eb539412SYork Sun 			if (granule_size == FSL_DDR_3WAY_8KB_INTERLEAVING) {
231eb539412SYork Sun 				if (pagesize)
232eb539412SYork Sun 					*pagesize = 8192;
233eb539412SYork Sun 				bootpg &= 0xffffe000;	/* align to 8KB */
234eb539412SYork Sun 				check = bootpg >> 13;
235eb539412SYork Sun 				while ((check % 3) != 1)
236eb539412SYork Sun 					check--;
237eb539412SYork Sun 				bootpg = check << 13;
238eb539412SYork Sun 				debug("Boot page (8K) at 0x%08x\n", bootpg);
239eb539412SYork Sun 				break;
240eb539412SYork Sun 			} else {
241eb539412SYork Sun 				bootpg &= 0xfffff000;	/* align to 4KB */
242eb539412SYork Sun 				check = bootpg >> 12;
243eb539412SYork Sun 				while ((check % 3) != 0)
244eb539412SYork Sun 					check--;
245eb539412SYork Sun 				bootpg = check << 12;
246eb539412SYork Sun 				debug("Boot page (4K) at 0x%08x\n", bootpg);
247eb539412SYork Sun 			}
248eb539412SYork Sun 				break;
249eb539412SYork Sun 		default:
250eb539412SYork Sun 			break;
251eb539412SYork Sun 		}
252eb539412SYork Sun 	}
253eb539412SYork Sun #endif /* CONFIG_SYS_FSL_ERRATUM_A004468 */
254eb539412SYork Sun 
255eb539412SYork Sun 	return bootpg;
256a47a12beSStefan Roese }
257a47a12beSStefan Roese 
258a47a12beSStefan Roese ulong get_spin_phys_addr(void)
259a47a12beSStefan Roese {
260a47a12beSStefan Roese 	extern ulong __secondary_start_page;
261a47a12beSStefan Roese 	extern ulong __spin_table;
262a47a12beSStefan Roese 
263a47a12beSStefan Roese 	return (determine_mp_bootpg() +
264a47a12beSStefan Roese 		(ulong)&__spin_table - (ulong)&__secondary_start_page);
265a47a12beSStefan Roese }
266a47a12beSStefan Roese 
267a47a12beSStefan Roese ulong get_spin_virt_addr(void)
268a47a12beSStefan Roese {
269a47a12beSStefan Roese 	extern ulong __secondary_start_page;
270a47a12beSStefan Roese 	extern ulong __spin_table;
271a47a12beSStefan Roese 
272a47a12beSStefan Roese 	return (CONFIG_BPTR_VIRT_ADDR +
273a47a12beSStefan Roese 		(ulong)&__spin_table - (ulong)&__secondary_start_page);
274a47a12beSStefan Roese }
275a47a12beSStefan Roese 
276a47a12beSStefan Roese #ifdef CONFIG_FSL_CORENET
277eb539412SYork Sun static void plat_mp_up(unsigned long bootpg, unsigned int pagesize)
278a47a12beSStefan Roese {
279eb539412SYork Sun 	u32 cpu_up_mask, whoami, brsize = LAW_SIZE_4K;
280a47a12beSStefan Roese 	u32 *table = (u32 *)get_spin_virt_addr();
281a47a12beSStefan Roese 	volatile ccsr_gur_t *gur;
282a47a12beSStefan Roese 	volatile ccsr_local_t *ccm;
283a47a12beSStefan Roese 	volatile ccsr_rcpm_t *rcpm;
284a47a12beSStefan Roese 	volatile ccsr_pic_t *pic;
285a47a12beSStefan Roese 	int timeout = 10;
286fbb9ecf7STimur Tabi 	u32 mask = cpu_mask();
287a47a12beSStefan Roese 	struct law_entry e;
288a47a12beSStefan Roese 
289a47a12beSStefan Roese 	gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
290a47a12beSStefan Roese 	ccm = (void *)(CONFIG_SYS_FSL_CORENET_CCM_ADDR);
291a47a12beSStefan Roese 	rcpm = (void *)(CONFIG_SYS_FSL_CORENET_RCPM_ADDR);
292680c613aSKim Phillips 	pic = (void *)(CONFIG_SYS_MPC8xxx_PIC_ADDR);
293a47a12beSStefan Roese 
294a47a12beSStefan Roese 	whoami = in_be32(&pic->whoami);
295a47a12beSStefan Roese 	cpu_up_mask = 1 << whoami;
296a47a12beSStefan Roese 	out_be32(&ccm->bstrl, bootpg);
297a47a12beSStefan Roese 
298a47a12beSStefan Roese 	e = find_law(bootpg);
299eb539412SYork Sun 	/* pagesize is only 4K or 8K */
300eb539412SYork Sun 	if (pagesize == 8192)
301eb539412SYork Sun 		brsize = LAW_SIZE_8K;
302eb539412SYork Sun 	out_be32(&ccm->bstrar, LAW_EN | e.trgt_id << 20 | brsize);
303eb539412SYork Sun 	debug("BRSIZE is 0x%x\n", brsize);
304a47a12beSStefan Roese 
305a47a12beSStefan Roese 	/* readback to sync write */
306a47a12beSStefan Roese 	in_be32(&ccm->bstrar);
307a47a12beSStefan Roese 
308a47a12beSStefan Roese 	/* disable time base at the platform */
309a47a12beSStefan Roese 	out_be32(&rcpm->ctbenrl, cpu_up_mask);
310a47a12beSStefan Roese 
311fbb9ecf7STimur Tabi 	out_be32(&gur->brrl, mask);
312a47a12beSStefan Roese 
313a47a12beSStefan Roese 	/* wait for everyone */
314a47a12beSStefan Roese 	while (timeout) {
315fbb9ecf7STimur Tabi 		unsigned int i, cpu, nr_cpus = cpu_numcores();
316a47a12beSStefan Roese 
317fbb9ecf7STimur Tabi 		for_each_cpu(i, cpu, nr_cpus, mask) {
318fbb9ecf7STimur Tabi 			if (table[cpu * NUM_BOOT_ENTRY + BOOT_ENTRY_ADDR_LOWER])
319fbb9ecf7STimur Tabi 				cpu_up_mask |= (1 << cpu);
320fbb9ecf7STimur Tabi 		}
321fbb9ecf7STimur Tabi 
322fbb9ecf7STimur Tabi 		if ((cpu_up_mask & mask) == mask)
323a47a12beSStefan Roese 			break;
324a47a12beSStefan Roese 
325a47a12beSStefan Roese 		udelay(100);
326a47a12beSStefan Roese 		timeout--;
327a47a12beSStefan Roese 	}
328a47a12beSStefan Roese 
329a47a12beSStefan Roese 	if (timeout == 0)
330a47a12beSStefan Roese 		printf("CPU up timeout. CPU up mask is %x should be %x\n",
331fbb9ecf7STimur Tabi 			cpu_up_mask, mask);
332a47a12beSStefan Roese 
333a47a12beSStefan Roese 	/* enable time base at the platform */
334a47a12beSStefan Roese 	out_be32(&rcpm->ctbenrl, 0);
3357afc45adSKumar Gala 
3367afc45adSKumar Gala 	/* readback to sync write */
3377afc45adSKumar Gala 	in_be32(&rcpm->ctbenrl);
3387afc45adSKumar Gala 
339a47a12beSStefan Roese 	mtspr(SPRN_TBWU, 0);
340a47a12beSStefan Roese 	mtspr(SPRN_TBWL, 0);
3417afc45adSKumar Gala 
342fbb9ecf7STimur Tabi 	out_be32(&rcpm->ctbenrl, mask);
343a47a12beSStefan Roese 
344a47a12beSStefan Roese #ifdef CONFIG_MPC8xxx_DISABLE_BPTR
345a47a12beSStefan Roese 	/*
346a47a12beSStefan Roese 	 * Disabling Boot Page Translation allows the memory region 0xfffff000
347a47a12beSStefan Roese 	 * to 0xffffffff to be used normally.  Leaving Boot Page Translation
348a47a12beSStefan Roese 	 * enabled remaps 0xfffff000 to SDRAM which makes that memory region
349a47a12beSStefan Roese 	 * unusable for normal operation but it does allow OSes to easily
350a47a12beSStefan Roese 	 * reset a processor core to put it back into U-Boot's spinloop.
351a47a12beSStefan Roese 	 */
352e81241afSEd Swarthout 	clrbits_be32(&ccm->bstrar, LAW_EN);
353a47a12beSStefan Roese #endif
354a47a12beSStefan Roese }
355a47a12beSStefan Roese #else
356eb539412SYork Sun static void plat_mp_up(unsigned long bootpg, unsigned int pagesize)
357a47a12beSStefan Roese {
358a47a12beSStefan Roese 	u32 up, cpu_up_mask, whoami;
359a47a12beSStefan Roese 	u32 *table = (u32 *)get_spin_virt_addr();
360a47a12beSStefan Roese 	volatile u32 bpcr;
361a47a12beSStefan Roese 	volatile ccsr_local_ecm_t *ecm = (void *)(CONFIG_SYS_MPC85xx_ECM_ADDR);
362a47a12beSStefan Roese 	volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
363680c613aSKim Phillips 	volatile ccsr_pic_t *pic = (void *)(CONFIG_SYS_MPC8xxx_PIC_ADDR);
364a47a12beSStefan Roese 	u32 devdisr;
365a47a12beSStefan Roese 	int timeout = 10;
366a47a12beSStefan Roese 
367a47a12beSStefan Roese 	whoami = in_be32(&pic->whoami);
368a47a12beSStefan Roese 	out_be32(&ecm->bptr, 0x80000000 | (bootpg >> 12));
369a47a12beSStefan Roese 
370a47a12beSStefan Roese 	/* disable time base at the platform */
371a47a12beSStefan Roese 	devdisr = in_be32(&gur->devdisr);
372a47a12beSStefan Roese 	if (whoami)
373a47a12beSStefan Roese 		devdisr |= MPC85xx_DEVDISR_TB0;
374a47a12beSStefan Roese 	else
375a47a12beSStefan Roese 		devdisr |= MPC85xx_DEVDISR_TB1;
376a47a12beSStefan Roese 	out_be32(&gur->devdisr, devdisr);
377a47a12beSStefan Roese 
378a47a12beSStefan Roese 	/* release the hounds */
379a47a12beSStefan Roese 	up = ((1 << cpu_numcores()) - 1);
380a47a12beSStefan Roese 	bpcr = in_be32(&ecm->eebpcr);
381a47a12beSStefan Roese 	bpcr |= (up << 24);
382a47a12beSStefan Roese 	out_be32(&ecm->eebpcr, bpcr);
383a47a12beSStefan Roese 	asm("sync; isync; msync");
384a47a12beSStefan Roese 
385a47a12beSStefan Roese 	cpu_up_mask = 1 << whoami;
386a47a12beSStefan Roese 	/* wait for everyone */
387a47a12beSStefan Roese 	while (timeout) {
388a47a12beSStefan Roese 		int i;
389a47a12beSStefan Roese 		for (i = 0; i < cpu_numcores(); i++) {
390a47a12beSStefan Roese 			if (table[i * NUM_BOOT_ENTRY + BOOT_ENTRY_ADDR_LOWER])
391a47a12beSStefan Roese 				cpu_up_mask |= (1 << i);
392a47a12beSStefan Roese 		};
393a47a12beSStefan Roese 
394a47a12beSStefan Roese 		if ((cpu_up_mask & up) == up)
395a47a12beSStefan Roese 			break;
396a47a12beSStefan Roese 
397a47a12beSStefan Roese 		udelay(100);
398a47a12beSStefan Roese 		timeout--;
399a47a12beSStefan Roese 	}
400a47a12beSStefan Roese 
401a47a12beSStefan Roese 	if (timeout == 0)
402a47a12beSStefan Roese 		printf("CPU up timeout. CPU up mask is %x should be %x\n",
403a47a12beSStefan Roese 			cpu_up_mask, up);
404a47a12beSStefan Roese 
405a47a12beSStefan Roese 	/* enable time base at the platform */
406a47a12beSStefan Roese 	if (whoami)
407a47a12beSStefan Roese 		devdisr |= MPC85xx_DEVDISR_TB1;
408a47a12beSStefan Roese 	else
409a47a12beSStefan Roese 		devdisr |= MPC85xx_DEVDISR_TB0;
410a47a12beSStefan Roese 	out_be32(&gur->devdisr, devdisr);
4117afc45adSKumar Gala 
4127afc45adSKumar Gala 	/* readback to sync write */
4137afc45adSKumar Gala 	in_be32(&gur->devdisr);
4147afc45adSKumar Gala 
415a47a12beSStefan Roese 	mtspr(SPRN_TBWU, 0);
416a47a12beSStefan Roese 	mtspr(SPRN_TBWL, 0);
417a47a12beSStefan Roese 
418a47a12beSStefan Roese 	devdisr &= ~(MPC85xx_DEVDISR_TB0 | MPC85xx_DEVDISR_TB1);
419a47a12beSStefan Roese 	out_be32(&gur->devdisr, devdisr);
420a47a12beSStefan Roese 
421a47a12beSStefan Roese #ifdef CONFIG_MPC8xxx_DISABLE_BPTR
422a47a12beSStefan Roese 	/*
423a47a12beSStefan Roese 	 * Disabling Boot Page Translation allows the memory region 0xfffff000
424a47a12beSStefan Roese 	 * to 0xffffffff to be used normally.  Leaving Boot Page Translation
425a47a12beSStefan Roese 	 * enabled remaps 0xfffff000 to SDRAM which makes that memory region
426a47a12beSStefan Roese 	 * unusable for normal operation but it does allow OSes to easily
427a47a12beSStefan Roese 	 * reset a processor core to put it back into U-Boot's spinloop.
428a47a12beSStefan Roese 	 */
429a47a12beSStefan Roese 	clrbits_be32(&ecm->bptr, 0x80000000);
430a47a12beSStefan Roese #endif
431a47a12beSStefan Roese }
432a47a12beSStefan Roese #endif
433a47a12beSStefan Roese 
434a47a12beSStefan Roese void cpu_mp_lmb_reserve(struct lmb *lmb)
435a47a12beSStefan Roese {
436eb539412SYork Sun 	u32 bootpg = determine_mp_bootpg(NULL);
437a47a12beSStefan Roese 
438a47a12beSStefan Roese 	lmb_reserve(lmb, bootpg, 4096);
439a47a12beSStefan Roese }
440a47a12beSStefan Roese 
441a47a12beSStefan Roese void setup_mp(void)
442a47a12beSStefan Roese {
443a47a12beSStefan Roese 	extern ulong __secondary_start_page;
444a47a12beSStefan Roese 	extern ulong __bootpg_addr;
445eb539412SYork Sun 
446a47a12beSStefan Roese 	ulong fixup = (ulong)&__secondary_start_page;
447eb539412SYork Sun 	u32 bootpg, bootpg_map, pagesize;
448eb539412SYork Sun 
449eb539412SYork Sun 	bootpg = determine_mp_bootpg(&pagesize);
450eb539412SYork Sun 
451eb539412SYork Sun 	/*
452eb539412SYork Sun 	 * pagesize is only 4K or 8K
453eb539412SYork Sun 	 * we only use the last 4K of boot page
454eb539412SYork Sun 	 * bootpg_map saves the address for the boot page
455eb539412SYork Sun 	 * 8K is used for the workaround of 3-way DDR interleaving
456eb539412SYork Sun 	 */
457eb539412SYork Sun 
458eb539412SYork Sun 	bootpg_map = bootpg;
459eb539412SYork Sun 
460eb539412SYork Sun 	if (pagesize == 8192)
461eb539412SYork Sun 		bootpg += 4096;	/* use 2nd half */
462a47a12beSStefan Roese 
4639d64c6bbSAaron Sierra 	/* Some OSes expect secondary cores to be held in reset */
4649d64c6bbSAaron Sierra 	if (hold_cores_in_reset(0))
4659d64c6bbSAaron Sierra 		return;
4669d64c6bbSAaron Sierra 
467a47a12beSStefan Roese 	/* Store the bootpg's SDRAM address for use by secondary CPU cores */
468a47a12beSStefan Roese 	__bootpg_addr = bootpg;
469a47a12beSStefan Roese 
470a47a12beSStefan Roese 	/* look for the tlb covering the reset page, there better be one */
471a47a12beSStefan Roese 	int i = find_tlb_idx((void *)CONFIG_BPTR_VIRT_ADDR, 1);
472a47a12beSStefan Roese 
473a47a12beSStefan Roese 	/* we found a match */
474a47a12beSStefan Roese 	if (i != -1) {
475a47a12beSStefan Roese 		/* map reset page to bootpg so we can copy code there */
476a47a12beSStefan Roese 		disable_tlb(i);
477a47a12beSStefan Roese 
478a47a12beSStefan Roese 		set_tlb(1, CONFIG_BPTR_VIRT_ADDR, bootpg, /* tlb, epn, rpn */
479a47a12beSStefan Roese 			MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, /* perms, wimge */
480a47a12beSStefan Roese 			0, i, BOOKE_PAGESZ_4K, 1); /* ts, esel, tsize, iprot */
481a47a12beSStefan Roese 
482a47a12beSStefan Roese 		memcpy((void *)CONFIG_BPTR_VIRT_ADDR, (void *)fixup, 4096);
483a47a12beSStefan Roese 
484eb539412SYork Sun 		plat_mp_up(bootpg_map, pagesize);
485a47a12beSStefan Roese 	} else {
486a47a12beSStefan Roese 		puts("WARNING: No reset page TLB. "
487a47a12beSStefan Roese 			"Skipping secondary core setup\n");
488a47a12beSStefan Roese 	}
489a47a12beSStefan Roese }
490