diff options
Diffstat (limited to 'sys/powerpc/mpc85xx/platform_mpc85xx.c')
-rw-r--r-- | sys/powerpc/mpc85xx/platform_mpc85xx.c | 256 |
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); } |