aboutsummaryrefslogtreecommitdiff
path: root/sys/powerpc/mpc85xx/platform_mpc85xx.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/powerpc/mpc85xx/platform_mpc85xx.c')
-rw-r--r--sys/powerpc/mpc85xx/platform_mpc85xx.c256
1 files changed, 162 insertions, 94 deletions
diff --git a/sys/powerpc/mpc85xx/platform_mpc85xx.c b/sys/powerpc/mpc85xx/platform_mpc85xx.c
index aec141202448..00c8a17b4439 100644
--- a/sys/powerpc/mpc85xx/platform_mpc85xx.c
+++ b/sys/powerpc/mpc85xx/platform_mpc85xx.c
@@ -39,7 +39,9 @@ __FBSDID("$FreeBSD$");
#include <machine/bus.h>
#include <machine/cpu.h>
#include <machine/hid.h>
+#include <machine/_inttypes.h>
#include <machine/machdep.h>
+#include <machine/md_var.h>
#include <machine/platform.h>
#include <machine/platformvar.h>
#include <machine/smp.h>
@@ -53,6 +55,7 @@ __FBSDID("$FreeBSD$");
#include <vm/vm.h>
#include <vm/pmap.h>
+#include <vm/vm_extern.h>
#include <powerpc/mpc85xx/mpc85xx.h>
@@ -63,6 +66,15 @@ extern void *ap_pcpu;
extern vm_paddr_t kernload; /* Kernel physical load address */
extern uint8_t __boot_page[]; /* Boot page body */
extern uint32_t bp_kernload;
+
+struct cpu_release {
+ uint32_t entry_h;
+ uint32_t entry_l;
+ uint32_t r3_h;
+ uint32_t r3_l;
+ uint32_t reserved;
+ uint32_t pir;
+};
#endif
extern uint32_t *bootinfo;
@@ -258,16 +270,17 @@ mpc85xx_timebase_freq(platform_t plat, struct cpuref *cpuref)
sizeof(freq)) <= 0)
goto out;
+ if (freq == 0)
+ goto out;
+
/*
* Time Base and Decrementer are updated every 8 CCB bus clocks.
* HID0[SEL_TBCLK] = 0
*/
- if (freq != 0)
-#ifdef QORIQ_DPAA
+ if (mpc85xx_is_qoriq())
ticks = freq / 32;
-#else
+ else
ticks = freq / 8;
-#endif
out:
if (ticks <= 0)
@@ -315,6 +328,51 @@ mpc85xx_smp_get_bsp(platform_t plat, struct cpuref *cpuref)
return (0);
}
+#ifdef SMP
+static int
+mpc85xx_smp_start_cpu_epapr(platform_t plat, struct pcpu *pc)
+{
+ vm_paddr_t rel_pa, bptr;
+ volatile struct cpu_release *rel;
+ vm_offset_t rel_va, rel_page;
+ phandle_t node;
+ int i;
+
+ /* If we're calling this, the node already exists. */
+ node = OF_finddevice("/cpus");
+ for (i = 0, node = OF_child(node); i < pc->pc_cpuid;
+ i++, node = OF_peer(node))
+ ;
+ if (OF_getencprop(node, "cpu-release-addr", (pcell_t *)&rel_pa,
+ sizeof(rel_pa)) == -1) {
+ return (ENOENT);
+ }
+
+ rel_page = kva_alloc(PAGE_SIZE);
+ if (rel_page == 0)
+ return (ENOMEM);
+
+ critical_enter();
+ rel_va = rel_page + (rel_pa & PAGE_MASK);
+ pmap_kenter(rel_page, rel_pa & ~PAGE_MASK);
+ rel = (struct cpu_release *)rel_va;
+ bptr = ((vm_paddr_t)(uintptr_t)__boot_page - KERNBASE) + kernload;
+ cpu_flush_dcache(__DEVOLATILE(struct cpu_release *,rel), sizeof(*rel));
+ rel->pir = pc->pc_cpuid; __asm __volatile("sync");
+ rel->entry_h = (bptr >> 32);
+ rel->entry_l = bptr; __asm __volatile("sync");
+ cpu_flush_dcache(__DEVOLATILE(struct cpu_release *,rel), sizeof(*rel));
+ if (bootverbose)
+ printf("Waking up CPU %d via CPU release page %p\n",
+ pc->pc_cpuid, rel);
+ critical_exit();
+ pmap_kremove(rel_page);
+ kva_free(rel_page, PAGE_SIZE);
+
+ return (0);
+}
+#endif
+
static int
mpc85xx_smp_start_cpu(platform_t plat, struct pcpu *pc)
{
@@ -324,24 +382,39 @@ mpc85xx_smp_start_cpu(platform_t plat, struct pcpu *pc)
int timeout;
uintptr_t brr;
int cpuid;
-
-#ifdef QORIQ_DPAA
+ int epapr_boot = 0;
uint32_t tgt;
- reg = ccsr_read4(OCP85XX_COREDISR);
- cpuid = pc->pc_cpuid;
+ if (mpc85xx_is_qoriq()) {
+ reg = ccsr_read4(OCP85XX_COREDISR);
+ cpuid = pc->pc_cpuid;
- if ((reg & cpuid) != 0) {
- printf("%s: CPU %d is disabled!\n", __func__, pc->pc_cpuid);
- return (-1);
- }
+ if ((reg & (1 << cpuid)) != 0) {
+ printf("%s: CPU %d is disabled!\n", __func__, pc->pc_cpuid);
+ return (-1);
+ }
- brr = OCP85XX_BRR;
-#else /* QORIQ_DPAA */
- brr = OCP85XX_EEBPCR;
- cpuid = pc->pc_cpuid + 24;
-#endif
+ brr = OCP85XX_BRR;
+ } else {
+ brr = OCP85XX_EEBPCR;
+ cpuid = pc->pc_cpuid + 24;
+ }
bp_kernload = kernload;
+ /*
+ * bp_kernload is in the boot page. Sync the cache because ePAPR
+ * booting has the other core(s) already running.
+ */
+ cpu_flush_dcache(&bp_kernload, sizeof(bp_kernload));
+
+ ap_pcpu = pc;
+ __asm __volatile("msync; isync");
+
+ /* First try the ePAPR way. */
+ if (mpc85xx_smp_start_cpu_epapr(plat, pc) == 0) {
+ epapr_boot = 1;
+ goto spin_wait;
+ }
+
reg = ccsr_read4(brr);
if ((reg & (1 << cpuid)) != 0) {
printf("SMP: CPU %d already out of hold-off state!\n",
@@ -349,64 +422,58 @@ mpc85xx_smp_start_cpu(platform_t plat, struct pcpu *pc)
return (ENXIO);
}
- ap_pcpu = pc;
- __asm __volatile("msync; isync");
-
/* Flush caches to have our changes hit DRAM. */
cpu_flush_dcache(__boot_page, 4096);
bptr = ((vm_paddr_t)(uintptr_t)__boot_page - KERNBASE) + kernload;
KASSERT((bptr & 0xfff) == 0,
("%s: boot page is not aligned (%#jx)", __func__, (uintmax_t)bptr));
-#ifdef QORIQ_DPAA
-
- /*
- * Read DDR controller configuration to select proper BPTR target ID.
- *
- * On P5020 bit 29 of DDR1_CS0_CONFIG enables DDR controllers
- * interleaving. If this bit is set, we have to use
- * OCP85XX_TGTIF_RAM_INTL as BPTR target ID. On other QorIQ DPAA SoCs,
- * this bit is reserved and always 0.
- */
-
- reg = ccsr_read4(OCP85XX_DDR1_CS0_CONFIG);
- if (reg & (1 << 29))
- tgt = OCP85XX_TGTIF_RAM_INTL;
- else
- tgt = OCP85XX_TGTIF_RAM1;
-
- /*
- * Set BSTR to the physical address of the boot page
- */
- ccsr_write4(OCP85XX_BSTRH, bptr >> 32);
- ccsr_write4(OCP85XX_BSTRL, bptr);
- ccsr_write4(OCP85XX_BSTAR, OCP85XX_ENA_MASK |
- (tgt << OCP85XX_TRGT_SHIFT) | (ffsl(PAGE_SIZE) - 2));
-
- /* Read back OCP85XX_BSTAR to synchronize write */
- ccsr_read4(OCP85XX_BSTAR);
-
- /*
- * Enable and configure time base on new CPU.
- */
-
- /* Set TB clock source to platform clock / 32 */
- reg = ccsr_read4(CCSR_CTBCKSELR);
- ccsr_write4(CCSR_CTBCKSELR, reg & ~(1 << pc->pc_cpuid));
-
- /* Enable TB */
- reg = ccsr_read4(CCSR_CTBENR);
- ccsr_write4(CCSR_CTBENR, reg | (1 << pc->pc_cpuid));
-#else
-
- /*
- * Set BPTR to the physical address of the boot page
- */
- bptr = (bptr >> 12) | 0x80000000u;
- ccsr_write4(OCP85XX_BPTR, bptr);
- __asm __volatile("isync; msync");
-
-#endif /* QORIQ_DPAA */
+ if (mpc85xx_is_qoriq()) {
+ /*
+ * Read DDR controller configuration to select proper BPTR target ID.
+ *
+ * On P5020 bit 29 of DDR1_CS0_CONFIG enables DDR controllers
+ * interleaving. If this bit is set, we have to use
+ * OCP85XX_TGTIF_RAM_INTL as BPTR target ID. On other QorIQ DPAA SoCs,
+ * this bit is reserved and always 0.
+ */
+
+ reg = ccsr_read4(OCP85XX_DDR1_CS0_CONFIG);
+ if (reg & (1 << 29))
+ tgt = OCP85XX_TGTIF_RAM_INTL;
+ else
+ tgt = OCP85XX_TGTIF_RAM1;
+
+ /*
+ * Set BSTR to the physical address of the boot page
+ */
+ ccsr_write4(OCP85XX_BSTRH, bptr >> 32);
+ ccsr_write4(OCP85XX_BSTRL, bptr);
+ ccsr_write4(OCP85XX_BSTAR, OCP85XX_ENA_MASK |
+ (tgt << OCP85XX_TRGT_SHIFT_QORIQ) | (ffsl(PAGE_SIZE) - 2));
+
+ /* Read back OCP85XX_BSTAR to synchronize write */
+ ccsr_read4(OCP85XX_BSTAR);
+
+ /*
+ * Enable and configure time base on new CPU.
+ */
+
+ /* Set TB clock source to platform clock / 32 */
+ reg = ccsr_read4(CCSR_CTBCKSELR);
+ ccsr_write4(CCSR_CTBCKSELR, reg & ~(1 << pc->pc_cpuid));
+
+ /* Enable TB */
+ reg = ccsr_read4(CCSR_CTBENR);
+ ccsr_write4(CCSR_CTBENR, reg | (1 << pc->pc_cpuid));
+ } else {
+ /*
+ * Set BPTR to the physical address of the boot page
+ */
+ bptr = (bptr >> 12) | 0x80000000u;
+ ccsr_write4(OCP85XX_BPTR, bptr);
+ __asm __volatile("isync; msync");
+ }
/*
* Release AP from hold-off state
@@ -415,6 +482,7 @@ mpc85xx_smp_start_cpu(platform_t plat, struct pcpu *pc)
ccsr_write4(brr, reg | (1 << cpuid));
__asm __volatile("isync; msync");
+spin_wait:
timeout = 500;
while (!pc->pc_awake && timeout--)
DELAY(1000); /* wait 1ms */
@@ -424,15 +492,16 @@ mpc85xx_smp_start_cpu(platform_t plat, struct pcpu *pc)
* address (= 0xfffff000) isn't permanently remapped and thus not
* usable otherwise.
*/
-#ifdef QORIQ_DPAA
- ccsr_write4(OCP85XX_BSTAR, 0);
-#else
- ccsr_write4(OCP85XX_BPTR, 0);
-#endif
- __asm __volatile("isync; msync");
+ if (!epapr_boot) {
+ if (mpc85xx_is_qoriq())
+ ccsr_write4(OCP85XX_BSTAR, 0);
+ else
+ ccsr_write4(OCP85XX_BPTR, 0);
+ __asm __volatile("isync; msync");
+ }
if (!pc->pc_awake)
- printf("SMP: CPU %d didn't wake up.\n", pc->pc_cpuid);
+ panic("SMP: CPU %d didn't wake up.\n", pc->pc_cpuid);
return ((pc->pc_awake) ? 0 : EBUSY);
#else
/* No SMP support */
@@ -469,33 +538,32 @@ mpc85xx_reset(platform_t plat)
static void
mpc85xx_idle(platform_t plat, int cpu)
{
-#ifdef QORIQ_DPAA
uint32_t reg;
- reg = ccsr_read4(OCP85XX_RCPM_CDOZCR);
- ccsr_write4(OCP85XX_RCPM_CDOZCR, reg | (1 << cpu));
- ccsr_read4(OCP85XX_RCPM_CDOZCR);
-#else
- register_t msr;
-
- msr = mfmsr();
- /* Freescale E500 core RM section 6.4.1. */
- __asm __volatile("msync; mtmsr %0; isync" ::
- "r" (msr | PSL_WE));
-#endif
+ if (mpc85xx_is_qoriq()) {
+ reg = ccsr_read4(OCP85XX_RCPM_CDOZCR);
+ ccsr_write4(OCP85XX_RCPM_CDOZCR, reg | (1 << cpu));
+ ccsr_read4(OCP85XX_RCPM_CDOZCR);
+ } else {
+ reg = mfmsr();
+ /* Freescale E500 core RM section 6.4.1. */
+ __asm __volatile("msync; mtmsr %0; isync" ::
+ "r" (reg | PSL_WE));
+ }
}
static int
mpc85xx_idle_wakeup(platform_t plat, int cpu)
{
-#ifdef QORIQ_DPAA
uint32_t reg;
- reg = ccsr_read4(OCP85XX_RCPM_CDOZCR);
- ccsr_write4(OCP85XX_RCPM_CDOZCR, reg & ~(1 << cpu));
- ccsr_read4(OCP85XX_RCPM_CDOZCR);
+ if (mpc85xx_is_qoriq()) {
+ reg = ccsr_read4(OCP85XX_RCPM_CDOZCR);
+ ccsr_write4(OCP85XX_RCPM_CDOZCR, reg & ~(1 << cpu));
+ ccsr_read4(OCP85XX_RCPM_CDOZCR);
+
+ return (1);
+ }
- return (1);
-#endif
return (0);
}