[U-Boot-Users] [RFC/PATCH] 85xx: Initial multicore boot support

Kumar Gala galak at kernel.crashing.org
Tue Jan 22 09:22:18 CET 2008


I was hoping to get some feed back on this patch that will add support for
booting the multiprocessor 85xx chips.  The boot mechanism is based on the
forth coming ePAPR spec (based on how device tree, linux
booting-without-of spec).

The biggest feedback I'm hoping for is related to the command set and its
name:

"cpu     - CPU boot table manipulation and release\n",
    "<num> reset          - Reset cpu <num>\n"
"cpu <num> status         - Status of cpu <num>\n"
"cpu <num> release <addr> - Release cpu <num> and start at <addr>\n"
"cpu <num> pir <val>      - Set cpu <num> PIR\n"
"cpu <num> r3 <val>       - Set cpu <num> r3\n"
"cpu <num> r4 <val>       - Set cpu <num> r4\n"
"cpu <num> r7 <val>       - Set cpu <num> r7\n"

- k

---
 cpu/mpc85xx/Makefile         |    3 +
 cpu/mpc85xx/cpu_init.c       |    4 +
 cpu/mpc85xx/fdt.c            |   43 +++++++++
 cpu/mpc85xx/mp.c             |  211 ++++++++++++++++++++++++++++++++++++++++++
 cpu/mpc85xx/mp.h             |    7 ++
 cpu/mpc85xx/release.S        |  142 ++++++++++++++++++++++++++++
 include/asm-ppc/immap_85xx.h |    4 +
 include/configs/MPC8572DS.h  |    2 +
 8 files changed, 416 insertions(+), 0 deletions(-)
 create mode 100644 cpu/mpc85xx/mp.c
 create mode 100644 cpu/mpc85xx/mp.h
 create mode 100644 cpu/mpc85xx/release.S

diff --git a/cpu/mpc85xx/Makefile b/cpu/mpc85xx/Makefile
index 2205dca..adbc585 100644
--- a/cpu/mpc85xx/Makefile
+++ b/cpu/mpc85xx/Makefile
@@ -29,6 +29,9 @@ include $(TOPDIR)/config.mk
 LIB	= $(obj)lib$(CPU).a

 START	= start.o resetvec.o
+SOBJS-$(CONFIG_MP) += release.o
+SOBJS	= $(SOBJS-y)
+COBJS-$(CONFIG_MP) += mp.o
 COBJS-$(CONFIG_OF_LIBFDT) += fdt.o
 COBJS	= traps.o cpu.o cpu_init.o speed.o interrupts.o tlb.o \
 	  pci.o serial_scc.o commproc.o ether_fcc.o spd_sdram.o qe_io.o \
diff --git a/cpu/mpc85xx/cpu_init.c b/cpu/mpc85xx/cpu_init.c
index ffb7132..700ce8e 100644
--- a/cpu/mpc85xx/cpu_init.c
+++ b/cpu/mpc85xx/cpu_init.c
@@ -33,6 +33,7 @@
 #include <asm/io.h>
 #include <asm/mmu.h>
 #include <asm/fsl_law.h>
+#include "mp.h"

 DECLARE_GLOBAL_DATA_PTR;

@@ -332,5 +333,8 @@ int cpu_init_r(void)
 	qe_reset();
 #endif

+#if defined(CONFIG_MP)
+	setup_mp();
+#endif
 	return 0;
 }
diff --git a/cpu/mpc85xx/fdt.c b/cpu/mpc85xx/fdt.c
index 0ce17e7..860c7a0 100644
--- a/cpu/mpc85xx/fdt.c
+++ b/cpu/mpc85xx/fdt.c
@@ -27,6 +27,45 @@
 #include <libfdt.h>
 #include <fdt_support.h>

+#ifdef CONFIG_MP
+#include "mp.h"
+DECLARE_GLOBAL_DATA_PTR;
+
+void ft_fixup_cpu(void *blob, u64 memory_limit)
+{
+	int off;
+	ulong spin_tbl_addr = get_spin_addr();
+	u32 bootpg;
+
+	/* if we have 4G or more of memory, put the boot page at 4Gb-4k */
+	if ((u64)gd->ram_size > 0xfffff000)
+		bootpg = 0xfffff000;
+	else
+		bootpg = gd->ram_size - 4096;
+
+	off = fdt_node_offset_by_prop_value(blob, -1, "device_type", "cpu", 4);
+	while (off != -FDT_ERR_NOTFOUND) {
+		u32 *reg = (u32 *)fdt_getprop(blob, off, "reg", 0);
+
+		if (reg) {
+			u32 val = *reg * 20 + spin_tbl_addr;
+			val = cpu_to_fdt32(val);
+			fdt_setprop(blob, off, "cpu-release-addr", &val, sizeof(val));
+		} else {
+			printf ("cpu NULL\n");
+		}
+		off = fdt_node_offset_by_prop_value(blob, off, "device_type", "cpu", 4);
+	}
+
+	/* Reserve the boot page so OSes dont use it */
+	if ((u64)bootpg < memory_limit) {
+		off = fdt_add_mem_rsv(blob, bootpg, (u64)4096);
+		if (off < 0)
+			printf("%s: %s\n", __FUNCTION__, fdt_strerror(off));
+	}
+}
+#endif
+
 void ft_cpu_setup(void *blob, bd_t *bd)
 {
 #if defined(CONFIG_HAS_ETH0) || defined(CONFIG_HAS_ETH1) ||\
@@ -64,4 +103,8 @@ void ft_cpu_setup(void *blob, bd_t *bd)
 #endif

 	fdt_fixup_memory(blob, (u64)bd->bi_memstart, (u64)bd->bi_memsize);
+
+#ifdef CONFIG_MP
+	ft_fixup_cpu(blob, (u64)bd->bi_memstart + (u64)bd->bi_memsize);
+#endif
 }
diff --git a/cpu/mpc85xx/mp.c b/cpu/mpc85xx/mp.c
new file mode 100644
index 0000000..b00d852
--- /dev/null
+++ b/cpu/mpc85xx/mp.c
@@ -0,0 +1,211 @@
+/*
+ * Copyright 2007 Freescale Semiconductor.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/processor.h>
+#include <ioports.h>
+#include <asm/io.h>
+#include "mp.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define BOOT_ENTRY_ADDR	0
+#define BOOT_ENTRY_PIR	1
+#define BOOT_ENTRY_R3	2
+#define BOOT_ENTRY_R4	3
+#define BOOT_ENTRY_R7	4
+#define NUM_BOOT_ENTRY	5
+
+ulong get_spin_addr(void)
+{
+	extern ulong __secondary_start_page;
+	extern ulong __spin_table;
+
+	ulong addr =
+		(ulong)&__spin_table - (ulong)&__secondary_start_page;
+	addr += 0xfffff000;
+
+	return addr;
+}
+
+static void pq3_mp_up(unsigned long bootpg)
+{
+	u32 up, cpu_up_mask, whoami;
+	u32 *table = (u32 *)get_spin_addr();
+	volatile u32 bpcr;
+	volatile ccsr_local_ecm_t *ecm = (void *)(CFG_MPC85xx_ECM_ADDR);
+	volatile ccsr_gur_t *gur = (void *)(CFG_MPC85xx_GUTS_ADDR);
+	volatile ccsr_pic_t *pic = (void *)(CFG_MPC85xx_PIC_ADDR);
+	u32 devdisr;
+	int timeout = 10;
+
+	whoami = in_be32(&pic->whoami);
+	out_be32(&ecm->bptr, 0x80000000 | (bootpg >> 12));
+
+	/* disable time base at the platform */
+	devdisr = in_be32(&gur->devdisr);
+	if (whoami)
+		devdisr |= MPC85xx_DEVDISR_TB0;
+	else
+		devdisr |= MPC85xx_DEVDISR_TB1;
+	out_be32(&gur->devdisr, devdisr);
+
+	/* release the hounds */
+	up = ((1 << CONFIG_NR_CPUS) - 1);
+	bpcr = in_be32(&ecm->eebpcr);
+	bpcr |= (up << 24);
+	out_be32(&ecm->eebpcr, bpcr);
+	asm("sync; isync; msync");
+
+	cpu_up_mask = 1 << whoami;
+	/* wait for everyone */
+	while (timeout) {
+		int i;
+		for (i = 1; i < CONFIG_NR_CPUS; i++) {
+			if (table[i * NUM_BOOT_ENTRY])
+				cpu_up_mask |= (1 << i);
+		};
+
+		if ((cpu_up_mask & up) == up)
+			break;
+
+		udelay(100);
+		timeout--;
+	}
+
+	/* enable time base at the platform */
+	if (whoami)
+		devdisr |= MPC85xx_DEVDISR_TB1;
+	else
+		devdisr |= MPC85xx_DEVDISR_TB0;
+	out_be32(&gur->devdisr, devdisr);
+	mtspr(SPRN_TBWU, 0);
+	mtspr(SPRN_TBWL, 0);
+
+	devdisr &= ~(MPC85xx_DEVDISR_TB0 | MPC85xx_DEVDISR_TB1);
+	out_be32(&gur->devdisr, devdisr);
+}
+
+void setup_mp(void)
+{
+	extern ulong __secondary_start_page;
+	ulong fixup = (ulong)&__secondary_start_page;
+	u32 bootpg;
+
+	/* if we have 4G or more of memory, put the boot page at 4Gb-4k */
+	if ((u64)gd->ram_size > 0xfffff000)
+		bootpg = 0xfffff000;
+	else
+		bootpg = gd->ram_size - 4096;
+
+	memcpy((void *)bootpg, (void *)fixup, 4096);
+	flush_cache(bootpg, 4096);
+
+	pq3_mp_up(bootpg);
+}
+
+int
+cpu_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	unsigned long cpuid, val = 0, idx = 0;
+	u32 *table = NULL;
+
+	switch (argc) {
+	case 0:
+	case 1:
+	case 2:
+		printf ("Usage:\n%s\n", cmdtp->usage);
+		return 1;
+	case 3:
+		cpuid = simple_strtoul(argv[1], NULL, 10);
+		if (cpuid >= CONFIG_NR_CPUS) {
+			printf ("Core num: %d is out of range[0..%d]\n",
+				 cpuid, CONFIG_NR_CPUS - 1);
+			return 1;
+		}
+
+		if (strncmp(argv[2], "res", 3) == 0) {
+			volatile ccsr_pic_t *pic = (void *)(CFG_MPC85xx_PIC_ADDR);
+			out_be32(&pic->pir, 1 << cpuid);
+			(void)in_be32(&pic->pir);
+			out_be32(&pic->pir, 0x0);
+		} else if (strncmp(argv[2], "sta", 3) == 0) {
+			table = (u32 *)get_spin_addr()
+				 + cpuid * NUM_BOOT_ENTRY;
+			printf("table @ 0x%08x:\n", table);
+			printf("   addr - 0x%08x\n", table[BOOT_ENTRY_ADDR]);
+			printf("   pir  - 0x%08x\n", table[BOOT_ENTRY_PIR]);
+			printf("   r3   - 0x%08x\n", table[BOOT_ENTRY_R3]);
+			printf("   r4   - 0x%08x\n", table[BOOT_ENTRY_R4]);
+			printf("   r7   - 0x%08x\n", table[BOOT_ENTRY_R7]);
+		} else {
+			printf ("Usage:\n%s\n", cmdtp->usage);
+			return 1;
+		}
+		break;
+
+	default:
+		cpuid = simple_strtoul(argv[1], NULL, 10);
+		if (cpuid >= CONFIG_NR_CPUS) {
+			printf ("Core num: %d is out of range[0..%d]\n",
+				 cpuid, CONFIG_NR_CPUS - 1);
+			return 1;
+		}
+		val = simple_strtoul(argv[3], NULL, 16);
+
+		table = (u32 *)get_spin_addr() + cpuid * NUM_BOOT_ENTRY;
+
+		if (strncmp(argv[2], "rel", 3) == 0) {
+			idx = BOOT_ENTRY_ADDR;
+		} else if (strncmp(argv[2], "pir", 3) == 0) {
+			idx = BOOT_ENTRY_PIR;
+		} else if (strncmp(argv[2], "r3", 2) == 0) {
+			idx = BOOT_ENTRY_R3;
+		} else if (strncmp(argv[2], "r4", 2) == 0) {
+			idx = BOOT_ENTRY_R4;
+		} else if (strncmp(argv[2], "r7", 2) == 0) {
+			idx = BOOT_ENTRY_R7;
+		} else {
+			printf ("Usage:\n%s\n", cmdtp->usage);
+			return 1;
+		}
+
+		table[idx] = val;
+
+		break;
+	}
+
+	return 0;
+}
+
+U_BOOT_CMD(
+	cpu, 4, 1, cpu_cmd,
+	"cpu     - CPU boot table manipulation and release\n",
+	    "<num> reset          - Reset cpu <num>\n"
+	"cpu <num> status         - Status of cpu <num>\n"
+	"cpu <num> release <addr> - Release cpu <num> and start at <addr>\n"
+	"cpu <num> pir <val>      - Set cpu <num> PIR\n"
+	"cpu <num> r3 <val>       - Set cpu <num> r3\n"
+	"cpu <num> r4 <val>       - Set cpu <num> r4\n"
+	"cpu <num> r7 <val>       - Set cpu <num> r7\n"
+	);
diff --git a/cpu/mpc85xx/mp.h b/cpu/mpc85xx/mp.h
new file mode 100644
index 0000000..e10af94
--- /dev/null
+++ b/cpu/mpc85xx/mp.h
@@ -0,0 +1,7 @@
+#ifndef __MPC85XX_MP_H_
+#define __MPC85XX_MP_H_
+
+ulong get_spin_addr(void);
+void setup_mp(void);
+
+#endif
diff --git a/cpu/mpc85xx/release.S b/cpu/mpc85xx/release.S
new file mode 100644
index 0000000..1e851a3
--- /dev/null
+++ b/cpu/mpc85xx/release.S
@@ -0,0 +1,142 @@
+#include <config.h>
+#include <mpc85xx.h>
+#include <version.h>
+
+#define _LINUX_CONFIG_H 1	/* avoid reading Linux autoconf.h file	*/
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+#include <asm/cache.h>
+#include <asm/mmu.h>
+
+/* To boot secondary cpus, we need a place for them to start up.
+ * Normally, they start at 0xfffffffc, but that's usually the
+ * firmware, and we don't want to have to run the firmware again.
+ * Instead, the primary cpu will set the BPTR to point here to
+ * this page.  We then set up the core, and head to
+ * start_secondary.  Note that this means that the code below
+ * must never exceed 1023 instructions (the branch at the end
+ * would then be the 1024th).
+ */
+	.globl	__secondary_start_page
+	.align	12
+__secondary_start_page:
+/* First do some preliminary setup */
+	lis	r3, HID0_EMCP at h		/* enable machine check */
+	ori	r3,r3,HID0_TBEN at l	/* enable Timebase */
+#ifdef CONFIG_PHYS_64BIT
+	ori	r3,r3,HID0_ENMAS7 at l	/* enable MAS7 updates */
+#endif
+	mtspr	SPRN_HID0,r3
+
+	li	r3,(HID1_ASTME|HID1_ABE)@l	/* Addr streaming & broadcast */
+	mtspr	SPRN_HID1,r3
+
+	/* Enable branch prediction */
+	li	r3,0x201
+	mtspr	SPRN_BUCSR,r3
+
+	/* Enable/invalidate the I-Cache */
+	mfspr	r0,SPRN_L1CSR1
+	ori	r0,r0,(L1CSR1_ICFI|L1CSR1_ICE)
+	mtspr	SPRN_L1CSR1,r0
+	isync
+
+	/* Enable/invalidate the D-Cache */
+	mfspr	r0,SPRN_L1CSR0
+	ori	r0,r0,(L1CSR0_DCFI|L1CSR0_DCE)
+	msync
+	isync
+	mtspr	SPRN_L1CSR0,r0
+	isync
+
+#define toreset(x) (x - __secondary_start_page + 0xfffff000)
+
+	/* get our PIR to figure out our table entry */
+	lis	r3,toreset(__spin_table)@h
+	ori	r3,r3,toreset(__spin_table)@l
+
+	/* r9 has the base address for the entry */
+	mfspr	r0,SPRN_PIR
+	slwi	r8,r0,4
+	slwi	r9,r0,2
+	add	r8,r8,r9
+	add	r9,r3,r8
+
+#define EPAPR_MAGIC	(0x65504150)
+#define ENTRY_ADDR	0
+#define ENTRY_PIR	4
+#define ENTRY_R3	8
+#define ENTRY_R4	12
+#define ENTRY_R7	16
+
+	/* setup the entry */
+	li	r4,0
+	li	r8,1
+	stw	r0,ENTRY_PIR(r9)
+	stw	r8,ENTRY_ADDR(r9)
+	stw	r4,ENTRY_R3(r9)
+	stw	r4,ENTRY_R4(r9)
+	stw	r4,ENTRY_R7(r9)
+
+	/* spin waiting for addr */
+1:	lwz	r4,ENTRY_ADDR(r9)
+	andi.	r11,r4,1
+	bne	1b
+
+	/* setup branch addr */
+	mtctr	r4
+
+	/* mark the entry as released */
+	li	r8,3
+	stw	r8,ENTRY_ADDR(r9)
+
+	/* mask by ~64M to setup our tlb we will jump to */
+	rlwinm	r8,r4,0,0,5
+
+	/* setup r3, r5, r6, r7 */
+	lwz	r3,ENTRY_R3(r9)
+	lwz	r4,ENTRY_R4(r9)
+	li	r5,0
+	lis	r6,EPAPR_MAGIC at h
+	ori	r6,r6,EPAPR_MAGIC at l
+	lwz	r7,ENTRY_R7(r9)
+
+	/* load up the pir */
+	lwz	r0,ENTRY_PIR(r9)
+	mtspr	SPRN_PIR,r0
+
+/*
+ * Coming here, we know the cpu has one TLB mapping in TLB1[0]
+ * which maps 0xfffff000-0xffffffff one-to-one.  We set up a
+ * second mapping that maps addr 1:1 for 64M, and then we jump to
+ * addr
+ */
+	lis	r9,(MAS0_TLBSEL(1)|MAS0_ESEL(1))@h
+	mtspr	SPRN_MAS0,r9
+	lis	r9,(MAS1_VALID|MAS1_IPROT)@h
+	ori	r9,r9,(MAS1_TSIZE(BOOKE_PAGESZ_64M))@l
+	mtspr	SPRN_MAS1,r9
+	/* WIMGE = 0b00000 for now */
+	mtspr	SPRN_MAS2,r8
+	ori	r8,r8,(MAS3_SX|MAS3_SW|MAS3_SR)
+	mtspr	SPRN_MAS3,r8
+	tlbwe
+
+/* Now we have another mapping for this page, so we jump to that
+ * mapping
+ */
+	bctr
+
+	.align 3
+	.globl __spin_table
+__spin_table:
+	.space CONFIG_NR_CPUS*20
+
+	/* Fill in the empty space.  The actual reset vector is
+	 * the last word of the page */
+__secondary_start_code_end:
+	.space 4092 - (__secondary_start_code_end - __secondary_start_page)
+__secondary_reset_vector:
+	b	__secondary_start_page
diff --git a/include/asm-ppc/immap_85xx.h b/include/asm-ppc/immap_85xx.h
index a0e26cc..4c04e0a 100644
--- a/include/asm-ppc/immap_85xx.h
+++ b/include/asm-ppc/immap_85xx.h
@@ -1578,7 +1578,11 @@ typedef struct ccsr_gur {
 #define MPC85xx_DEVDISR_RMSG		0x00040000
 #define MPC85xx_DEVDISR_DDR 		0x00010000
 #define MPC85xx_DEVDISR_CPU 		0x00008000
+#define MPC85xx_DEVDISR_CPU0 		MPC85xx_DEVDISR_CPU
 #define MPC85xx_DEVDISR_TB 		0x00004000
+#define MPC85xx_DEVDISR_TB0 		MPC85xx_DEVDISR_TB
+#define MPC85xx_DEVDISR_CPU1 		0x00002000
+#define MPC85xx_DEVDISR_TB1 		0x00001000
 #define MPC85xx_DEVDISR_DMA		0x00000400
 #define MPC85xx_DEVDISR_TSEC1		0x00000080
 #define MPC85xx_DEVDISR_TSEC2		0x00000040
diff --git a/include/configs/MPC8572DS.h b/include/configs/MPC8572DS.h
index 40041a0..25563b0 100644
--- a/include/configs/MPC8572DS.h
+++ b/include/configs/MPC8572DS.h
@@ -33,6 +33,8 @@
 #define CONFIG_MPC85xx		1	/* MPC8540/60/55/41/48 */
 #define CONFIG_MPC8572		1
 #define CONFIG_MPC8572DS	1
+#define CONFIG_MP		1	/* support multiple processors */
+#define CONFIG_NR_CPUS		2	/* Number of CPUs in the system */

 #define CONFIG_PCI		1	/* Enable PCI/PCIE */
 #define CONFIG_PCIE1		1	/* PCIE controler 1 (slot 1) */
-- 
1.5.3.7





More information about the U-Boot mailing list