[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