xref: /rk3399_rockchip-uboot/arch/powerpc/cpu/mpc85xx/mp.c (revision 9d64c6bb4a0db0f1c74a46f1cabe85d5a7a8a19b)
1a47a12beSStefan Roese /*
2a47a12beSStefan Roese  * Copyright 2008-2010 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>
30a47a12beSStefan Roese #include "mp.h"
31a47a12beSStefan Roese 
32a47a12beSStefan Roese DECLARE_GLOBAL_DATA_PTR;
33a47a12beSStefan Roese 
34a47a12beSStefan Roese u32 get_my_id()
35a47a12beSStefan Roese {
36a47a12beSStefan Roese 	return mfspr(SPRN_PIR);
37a47a12beSStefan Roese }
38a47a12beSStefan Roese 
39*9d64c6bbSAaron Sierra /*
40*9d64c6bbSAaron Sierra  * Determine if U-Boot should keep secondary cores in reset, or let them out
41*9d64c6bbSAaron Sierra  * of reset and hold them in a spinloop
42*9d64c6bbSAaron Sierra  */
43*9d64c6bbSAaron Sierra int hold_cores_in_reset(int verbose)
44*9d64c6bbSAaron Sierra {
45*9d64c6bbSAaron Sierra 	const char *s = getenv("mp_holdoff");
46*9d64c6bbSAaron Sierra 
47*9d64c6bbSAaron Sierra 	/* Default to no, overriden by 'y', 'yes', 'Y', 'Yes', or '1' */
48*9d64c6bbSAaron Sierra 	if (s && (*s == 'y' || *s == 'Y' || *s == '1')) {
49*9d64c6bbSAaron Sierra 		if (verbose) {
50*9d64c6bbSAaron Sierra 			puts("Secondary cores are being held in reset.\n");
51*9d64c6bbSAaron Sierra 			puts("See 'mp_holdoff' environment variable\n");
52*9d64c6bbSAaron Sierra 		}
53*9d64c6bbSAaron Sierra 
54*9d64c6bbSAaron Sierra 		return 1;
55*9d64c6bbSAaron Sierra 	}
56*9d64c6bbSAaron Sierra 
57*9d64c6bbSAaron Sierra 	return 0;
58*9d64c6bbSAaron Sierra }
59*9d64c6bbSAaron Sierra 
60a47a12beSStefan Roese int cpu_reset(int nr)
61a47a12beSStefan Roese {
62680c613aSKim Phillips 	volatile ccsr_pic_t *pic = (void *)(CONFIG_SYS_MPC8xxx_PIC_ADDR);
63a47a12beSStefan Roese 	out_be32(&pic->pir, 1 << nr);
64a47a12beSStefan Roese 	/* the dummy read works around an errata on early 85xx MP PICs */
65a47a12beSStefan Roese 	(void)in_be32(&pic->pir);
66a47a12beSStefan Roese 	out_be32(&pic->pir, 0x0);
67a47a12beSStefan Roese 
68a47a12beSStefan Roese 	return 0;
69a47a12beSStefan Roese }
70a47a12beSStefan Roese 
71a47a12beSStefan Roese int cpu_status(int nr)
72a47a12beSStefan Roese {
73a47a12beSStefan Roese 	u32 *table, id = get_my_id();
74a47a12beSStefan Roese 
75*9d64c6bbSAaron Sierra 	if (hold_cores_in_reset(1))
76*9d64c6bbSAaron Sierra 		return 0;
77*9d64c6bbSAaron Sierra 
78a47a12beSStefan Roese 	if (nr == id) {
79a47a12beSStefan Roese 		table = (u32 *)get_spin_virt_addr();
80a47a12beSStefan Roese 		printf("table base @ 0x%p\n", table);
81a47a12beSStefan Roese 	} else {
82a47a12beSStefan Roese 		table = (u32 *)get_spin_virt_addr() + nr * NUM_BOOT_ENTRY;
83a47a12beSStefan Roese 		printf("Running on cpu %d\n", id);
84a47a12beSStefan Roese 		printf("\n");
85a47a12beSStefan Roese 		printf("table @ 0x%p\n", table);
86a47a12beSStefan Roese 		printf("   addr - 0x%08x\n", table[BOOT_ENTRY_ADDR_LOWER]);
87a47a12beSStefan Roese 		printf("   pir  - 0x%08x\n", table[BOOT_ENTRY_PIR]);
88a47a12beSStefan Roese 		printf("   r3   - 0x%08x\n", table[BOOT_ENTRY_R3_LOWER]);
89a47a12beSStefan Roese 		printf("   r6   - 0x%08x\n", table[BOOT_ENTRY_R6_LOWER]);
90a47a12beSStefan Roese 	}
91a47a12beSStefan Roese 
92a47a12beSStefan Roese 	return 0;
93a47a12beSStefan Roese }
94a47a12beSStefan Roese 
95a47a12beSStefan Roese #ifdef CONFIG_FSL_CORENET
96a47a12beSStefan Roese int cpu_disable(int nr)
97a47a12beSStefan Roese {
98a47a12beSStefan Roese 	volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
99a47a12beSStefan Roese 
100a47a12beSStefan Roese 	setbits_be32(&gur->coredisrl, 1 << nr);
101a47a12beSStefan Roese 
102a47a12beSStefan Roese 	return 0;
103a47a12beSStefan Roese }
1048f3a7fa4SKumar Gala 
1058f3a7fa4SKumar Gala int is_core_disabled(int nr) {
1068f3a7fa4SKumar Gala 	ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
1078f3a7fa4SKumar Gala 	u32 coredisrl = in_be32(&gur->coredisrl);
1088f3a7fa4SKumar Gala 
1098f3a7fa4SKumar Gala 	return (coredisrl & (1 << nr));
1108f3a7fa4SKumar Gala }
111a47a12beSStefan Roese #else
112a47a12beSStefan Roese int cpu_disable(int nr)
113a47a12beSStefan Roese {
114a47a12beSStefan Roese 	volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
115a47a12beSStefan Roese 
116a47a12beSStefan Roese 	switch (nr) {
117a47a12beSStefan Roese 	case 0:
118a47a12beSStefan Roese 		setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_CPU0);
119a47a12beSStefan Roese 		break;
120a47a12beSStefan Roese 	case 1:
121a47a12beSStefan Roese 		setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_CPU1);
122a47a12beSStefan Roese 		break;
123a47a12beSStefan Roese 	default:
124a47a12beSStefan Roese 		printf("Invalid cpu number for disable %d\n", nr);
125a47a12beSStefan Roese 		return 1;
126a47a12beSStefan Roese 	}
127a47a12beSStefan Roese 
128a47a12beSStefan Roese 	return 0;
129a47a12beSStefan Roese }
1308f3a7fa4SKumar Gala 
1318f3a7fa4SKumar Gala int is_core_disabled(int nr) {
1328f3a7fa4SKumar Gala 	ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
1338f3a7fa4SKumar Gala 	u32 devdisr = in_be32(&gur->devdisr);
1348f3a7fa4SKumar Gala 
1358f3a7fa4SKumar Gala 	switch (nr) {
1368f3a7fa4SKumar Gala 	case 0:
1378f3a7fa4SKumar Gala 		return (devdisr & MPC85xx_DEVDISR_CPU0);
1388f3a7fa4SKumar Gala 	case 1:
1398f3a7fa4SKumar Gala 		return (devdisr & MPC85xx_DEVDISR_CPU1);
1408f3a7fa4SKumar Gala 	default:
1418f3a7fa4SKumar Gala 		printf("Invalid cpu number for disable %d\n", nr);
1428f3a7fa4SKumar Gala 	}
1438f3a7fa4SKumar Gala 
1448f3a7fa4SKumar Gala 	return 0;
1458f3a7fa4SKumar Gala }
146a47a12beSStefan Roese #endif
147a47a12beSStefan Roese 
148a47a12beSStefan Roese static u8 boot_entry_map[4] = {
149a47a12beSStefan Roese 	0,
150a47a12beSStefan Roese 	BOOT_ENTRY_PIR,
151a47a12beSStefan Roese 	BOOT_ENTRY_R3_LOWER,
152a47a12beSStefan Roese 	BOOT_ENTRY_R6_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 
160*9d64c6bbSAaron Sierra 	if (hold_cores_in_reset(1))
161*9d64c6bbSAaron Sierra 		return 0;
162*9d64c6bbSAaron 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 
175a47a12beSStefan Roese 	/* handle pir, r3, r6 */
176a47a12beSStefan Roese 	for (i = 1; i < 4; 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 
194a47a12beSStefan Roese u32 determine_mp_bootpg(void)
195a47a12beSStefan Roese {
196a47a12beSStefan Roese 	/* if we have 4G or more of memory, put the boot page at 4Gb-4k */
197a47a12beSStefan Roese 	if ((u64)gd->ram_size > 0xfffff000)
198a47a12beSStefan Roese 		return (0xfffff000);
199a47a12beSStefan Roese 
200a47a12beSStefan Roese 	return (gd->ram_size - 4096);
201a47a12beSStefan Roese }
202a47a12beSStefan Roese 
203a47a12beSStefan Roese ulong get_spin_phys_addr(void)
204a47a12beSStefan Roese {
205a47a12beSStefan Roese 	extern ulong __secondary_start_page;
206a47a12beSStefan Roese 	extern ulong __spin_table;
207a47a12beSStefan Roese 
208a47a12beSStefan Roese 	return (determine_mp_bootpg() +
209a47a12beSStefan Roese 		(ulong)&__spin_table - (ulong)&__secondary_start_page);
210a47a12beSStefan Roese }
211a47a12beSStefan Roese 
212a47a12beSStefan Roese ulong get_spin_virt_addr(void)
213a47a12beSStefan Roese {
214a47a12beSStefan Roese 	extern ulong __secondary_start_page;
215a47a12beSStefan Roese 	extern ulong __spin_table;
216a47a12beSStefan Roese 
217a47a12beSStefan Roese 	return (CONFIG_BPTR_VIRT_ADDR +
218a47a12beSStefan Roese 		(ulong)&__spin_table - (ulong)&__secondary_start_page);
219a47a12beSStefan Roese }
220a47a12beSStefan Roese 
221a47a12beSStefan Roese #ifdef CONFIG_FSL_CORENET
222a47a12beSStefan Roese static void plat_mp_up(unsigned long bootpg)
223a47a12beSStefan Roese {
224a47a12beSStefan Roese 	u32 up, cpu_up_mask, whoami;
225a47a12beSStefan Roese 	u32 *table = (u32 *)get_spin_virt_addr();
226a47a12beSStefan Roese 	volatile ccsr_gur_t *gur;
227a47a12beSStefan Roese 	volatile ccsr_local_t *ccm;
228a47a12beSStefan Roese 	volatile ccsr_rcpm_t *rcpm;
229a47a12beSStefan Roese 	volatile ccsr_pic_t *pic;
230a47a12beSStefan Roese 	int timeout = 10;
231a47a12beSStefan Roese 	u32 nr_cpus;
232a47a12beSStefan Roese 	struct law_entry e;
233a47a12beSStefan Roese 
234a47a12beSStefan Roese 	gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
235a47a12beSStefan Roese 	ccm = (void *)(CONFIG_SYS_FSL_CORENET_CCM_ADDR);
236a47a12beSStefan Roese 	rcpm = (void *)(CONFIG_SYS_FSL_CORENET_RCPM_ADDR);
237680c613aSKim Phillips 	pic = (void *)(CONFIG_SYS_MPC8xxx_PIC_ADDR);
238a47a12beSStefan Roese 
239a47a12beSStefan Roese 	nr_cpus = ((in_be32(&pic->frr) >> 8) & 0xff) + 1;
240a47a12beSStefan Roese 
241a47a12beSStefan Roese 	whoami = in_be32(&pic->whoami);
242a47a12beSStefan Roese 	cpu_up_mask = 1 << whoami;
243a47a12beSStefan Roese 	out_be32(&ccm->bstrl, bootpg);
244a47a12beSStefan Roese 
245a47a12beSStefan Roese 	e = find_law(bootpg);
246a47a12beSStefan Roese 	out_be32(&ccm->bstrar, LAW_EN | e.trgt_id << 20 | LAW_SIZE_4K);
247a47a12beSStefan Roese 
248a47a12beSStefan Roese 	/* readback to sync write */
249a47a12beSStefan Roese 	in_be32(&ccm->bstrar);
250a47a12beSStefan Roese 
251a47a12beSStefan Roese 	/* disable time base at the platform */
252a47a12beSStefan Roese 	out_be32(&rcpm->ctbenrl, cpu_up_mask);
253a47a12beSStefan Roese 
254a47a12beSStefan Roese 	/* release the hounds */
255a47a12beSStefan Roese 	up = ((1 << nr_cpus) - 1);
256a47a12beSStefan Roese 	out_be32(&gur->brrl, up);
257a47a12beSStefan Roese 
258a47a12beSStefan Roese 	/* wait for everyone */
259a47a12beSStefan Roese 	while (timeout) {
260a47a12beSStefan Roese 		int i;
261a47a12beSStefan Roese 		for (i = 0; i < nr_cpus; i++) {
262a47a12beSStefan Roese 			if (table[i * NUM_BOOT_ENTRY + BOOT_ENTRY_ADDR_LOWER])
263a47a12beSStefan Roese 				cpu_up_mask |= (1 << i);
264a47a12beSStefan Roese 		};
265a47a12beSStefan Roese 
266a47a12beSStefan Roese 		if ((cpu_up_mask & up) == up)
267a47a12beSStefan Roese 			break;
268a47a12beSStefan Roese 
269a47a12beSStefan Roese 		udelay(100);
270a47a12beSStefan Roese 		timeout--;
271a47a12beSStefan Roese 	}
272a47a12beSStefan Roese 
273a47a12beSStefan Roese 	if (timeout == 0)
274a47a12beSStefan Roese 		printf("CPU up timeout. CPU up mask is %x should be %x\n",
275a47a12beSStefan Roese 			cpu_up_mask, up);
276a47a12beSStefan Roese 
277a47a12beSStefan Roese 	/* enable time base at the platform */
278a47a12beSStefan Roese 	out_be32(&rcpm->ctbenrl, 0);
279a47a12beSStefan Roese 	mtspr(SPRN_TBWU, 0);
280a47a12beSStefan Roese 	mtspr(SPRN_TBWL, 0);
281a47a12beSStefan Roese 	out_be32(&rcpm->ctbenrl, (1 << nr_cpus) - 1);
282a47a12beSStefan Roese 
283a47a12beSStefan Roese #ifdef CONFIG_MPC8xxx_DISABLE_BPTR
284a47a12beSStefan Roese 	/*
285a47a12beSStefan Roese 	 * Disabling Boot Page Translation allows the memory region 0xfffff000
286a47a12beSStefan Roese 	 * to 0xffffffff to be used normally.  Leaving Boot Page Translation
287a47a12beSStefan Roese 	 * enabled remaps 0xfffff000 to SDRAM which makes that memory region
288a47a12beSStefan Roese 	 * unusable for normal operation but it does allow OSes to easily
289a47a12beSStefan Roese 	 * reset a processor core to put it back into U-Boot's spinloop.
290a47a12beSStefan Roese 	 */
291a47a12beSStefan Roese 	clrbits_be32(&ecm->bptr, 0x80000000);
292a47a12beSStefan Roese #endif
293a47a12beSStefan Roese }
294a47a12beSStefan Roese #else
295a47a12beSStefan Roese static void plat_mp_up(unsigned long bootpg)
296a47a12beSStefan Roese {
297a47a12beSStefan Roese 	u32 up, cpu_up_mask, whoami;
298a47a12beSStefan Roese 	u32 *table = (u32 *)get_spin_virt_addr();
299a47a12beSStefan Roese 	volatile u32 bpcr;
300a47a12beSStefan Roese 	volatile ccsr_local_ecm_t *ecm = (void *)(CONFIG_SYS_MPC85xx_ECM_ADDR);
301a47a12beSStefan Roese 	volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
302680c613aSKim Phillips 	volatile ccsr_pic_t *pic = (void *)(CONFIG_SYS_MPC8xxx_PIC_ADDR);
303a47a12beSStefan Roese 	u32 devdisr;
304a47a12beSStefan Roese 	int timeout = 10;
305a47a12beSStefan Roese 
306a47a12beSStefan Roese 	whoami = in_be32(&pic->whoami);
307a47a12beSStefan Roese 	out_be32(&ecm->bptr, 0x80000000 | (bootpg >> 12));
308a47a12beSStefan Roese 
309a47a12beSStefan Roese 	/* disable time base at the platform */
310a47a12beSStefan Roese 	devdisr = in_be32(&gur->devdisr);
311a47a12beSStefan Roese 	if (whoami)
312a47a12beSStefan Roese 		devdisr |= MPC85xx_DEVDISR_TB0;
313a47a12beSStefan Roese 	else
314a47a12beSStefan Roese 		devdisr |= MPC85xx_DEVDISR_TB1;
315a47a12beSStefan Roese 	out_be32(&gur->devdisr, devdisr);
316a47a12beSStefan Roese 
317a47a12beSStefan Roese 	/* release the hounds */
318a47a12beSStefan Roese 	up = ((1 << cpu_numcores()) - 1);
319a47a12beSStefan Roese 	bpcr = in_be32(&ecm->eebpcr);
320a47a12beSStefan Roese 	bpcr |= (up << 24);
321a47a12beSStefan Roese 	out_be32(&ecm->eebpcr, bpcr);
322a47a12beSStefan Roese 	asm("sync; isync; msync");
323a47a12beSStefan Roese 
324a47a12beSStefan Roese 	cpu_up_mask = 1 << whoami;
325a47a12beSStefan Roese 	/* wait for everyone */
326a47a12beSStefan Roese 	while (timeout) {
327a47a12beSStefan Roese 		int i;
328a47a12beSStefan Roese 		for (i = 0; i < cpu_numcores(); i++) {
329a47a12beSStefan Roese 			if (table[i * NUM_BOOT_ENTRY + BOOT_ENTRY_ADDR_LOWER])
330a47a12beSStefan Roese 				cpu_up_mask |= (1 << i);
331a47a12beSStefan Roese 		};
332a47a12beSStefan Roese 
333a47a12beSStefan Roese 		if ((cpu_up_mask & up) == up)
334a47a12beSStefan Roese 			break;
335a47a12beSStefan Roese 
336a47a12beSStefan Roese 		udelay(100);
337a47a12beSStefan Roese 		timeout--;
338a47a12beSStefan Roese 	}
339a47a12beSStefan Roese 
340a47a12beSStefan Roese 	if (timeout == 0)
341a47a12beSStefan Roese 		printf("CPU up timeout. CPU up mask is %x should be %x\n",
342a47a12beSStefan Roese 			cpu_up_mask, up);
343a47a12beSStefan Roese 
344a47a12beSStefan Roese 	/* enable time base at the platform */
345a47a12beSStefan Roese 	if (whoami)
346a47a12beSStefan Roese 		devdisr |= MPC85xx_DEVDISR_TB1;
347a47a12beSStefan Roese 	else
348a47a12beSStefan Roese 		devdisr |= MPC85xx_DEVDISR_TB0;
349a47a12beSStefan Roese 	out_be32(&gur->devdisr, devdisr);
350a47a12beSStefan Roese 	mtspr(SPRN_TBWU, 0);
351a47a12beSStefan Roese 	mtspr(SPRN_TBWL, 0);
352a47a12beSStefan Roese 
353a47a12beSStefan Roese 	devdisr &= ~(MPC85xx_DEVDISR_TB0 | MPC85xx_DEVDISR_TB1);
354a47a12beSStefan Roese 	out_be32(&gur->devdisr, devdisr);
355a47a12beSStefan Roese 
356a47a12beSStefan Roese #ifdef CONFIG_MPC8xxx_DISABLE_BPTR
357a47a12beSStefan Roese 	/*
358a47a12beSStefan Roese 	 * Disabling Boot Page Translation allows the memory region 0xfffff000
359a47a12beSStefan Roese 	 * to 0xffffffff to be used normally.  Leaving Boot Page Translation
360a47a12beSStefan Roese 	 * enabled remaps 0xfffff000 to SDRAM which makes that memory region
361a47a12beSStefan Roese 	 * unusable for normal operation but it does allow OSes to easily
362a47a12beSStefan Roese 	 * reset a processor core to put it back into U-Boot's spinloop.
363a47a12beSStefan Roese 	 */
364a47a12beSStefan Roese 	clrbits_be32(&ecm->bptr, 0x80000000);
365a47a12beSStefan Roese #endif
366a47a12beSStefan Roese }
367a47a12beSStefan Roese #endif
368a47a12beSStefan Roese 
369a47a12beSStefan Roese void cpu_mp_lmb_reserve(struct lmb *lmb)
370a47a12beSStefan Roese {
371a47a12beSStefan Roese 	u32 bootpg = determine_mp_bootpg();
372a47a12beSStefan Roese 
373a47a12beSStefan Roese 	lmb_reserve(lmb, bootpg, 4096);
374a47a12beSStefan Roese }
375a47a12beSStefan Roese 
376a47a12beSStefan Roese void setup_mp(void)
377a47a12beSStefan Roese {
378a47a12beSStefan Roese 	extern ulong __secondary_start_page;
379a47a12beSStefan Roese 	extern ulong __bootpg_addr;
380a47a12beSStefan Roese 	ulong fixup = (ulong)&__secondary_start_page;
381a47a12beSStefan Roese 	u32 bootpg = determine_mp_bootpg();
382a47a12beSStefan Roese 
383*9d64c6bbSAaron Sierra 	/* Some OSes expect secondary cores to be held in reset */
384*9d64c6bbSAaron Sierra 	if (hold_cores_in_reset(0))
385*9d64c6bbSAaron Sierra 		return;
386*9d64c6bbSAaron Sierra 
387a47a12beSStefan Roese 	/* Store the bootpg's SDRAM address for use by secondary CPU cores */
388a47a12beSStefan Roese 	__bootpg_addr = bootpg;
389a47a12beSStefan Roese 
390a47a12beSStefan Roese 	/* look for the tlb covering the reset page, there better be one */
391a47a12beSStefan Roese 	int i = find_tlb_idx((void *)CONFIG_BPTR_VIRT_ADDR, 1);
392a47a12beSStefan Roese 
393a47a12beSStefan Roese 	/* we found a match */
394a47a12beSStefan Roese 	if (i != -1) {
395a47a12beSStefan Roese 		/* map reset page to bootpg so we can copy code there */
396a47a12beSStefan Roese 		disable_tlb(i);
397a47a12beSStefan Roese 
398a47a12beSStefan Roese 		set_tlb(1, CONFIG_BPTR_VIRT_ADDR, bootpg, /* tlb, epn, rpn */
399a47a12beSStefan Roese 			MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, /* perms, wimge */
400a47a12beSStefan Roese 			0, i, BOOKE_PAGESZ_4K, 1); /* ts, esel, tsize, iprot */
401a47a12beSStefan Roese 
402a47a12beSStefan Roese 		memcpy((void *)CONFIG_BPTR_VIRT_ADDR, (void *)fixup, 4096);
403a47a12beSStefan Roese 
404a47a12beSStefan Roese 		plat_mp_up(bootpg);
405a47a12beSStefan Roese 	} else {
406a47a12beSStefan Roese 		puts("WARNING: No reset page TLB. "
407a47a12beSStefan Roese 			"Skipping secondary core setup\n");
408a47a12beSStefan Roese 	}
409a47a12beSStefan Roese }
410