1302acc2eSNathan Whitehorn /*- 2302acc2eSNathan Whitehorn * Copyright (c) 2008-2012 Semihalf. 3302acc2eSNathan Whitehorn * All rights reserved. 4302acc2eSNathan Whitehorn * 5302acc2eSNathan Whitehorn * Redistribution and use in source and binary forms, with or without 6302acc2eSNathan Whitehorn * modification, are permitted provided that the following conditions 7302acc2eSNathan Whitehorn * are met: 8302acc2eSNathan Whitehorn * 9302acc2eSNathan Whitehorn * 1. Redistributions of source code must retain the above copyright 10302acc2eSNathan Whitehorn * notice, this list of conditions and the following disclaimer. 11302acc2eSNathan Whitehorn * 2. Redistributions in binary form must reproduce the above copyright 12302acc2eSNathan Whitehorn * notice, this list of conditions and the following disclaimer in the 13302acc2eSNathan Whitehorn * documentation and/or other materials provided with the distribution. 14302acc2eSNathan Whitehorn * 15302acc2eSNathan Whitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16302acc2eSNathan Whitehorn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17302acc2eSNathan Whitehorn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18302acc2eSNathan Whitehorn * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19302acc2eSNathan Whitehorn * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20302acc2eSNathan Whitehorn * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21302acc2eSNathan Whitehorn * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22302acc2eSNathan Whitehorn * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23302acc2eSNathan Whitehorn * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24302acc2eSNathan Whitehorn * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25302acc2eSNathan Whitehorn */ 26302acc2eSNathan Whitehorn 273f068cbfSJustin Hibbits #include "opt_platform.h" 28302acc2eSNathan Whitehorn #include <sys/cdefs.h> 29302acc2eSNathan Whitehorn __FBSDID("$FreeBSD$"); 30302acc2eSNathan Whitehorn 31302acc2eSNathan Whitehorn #include <sys/param.h> 32302acc2eSNathan Whitehorn #include <sys/systm.h> 33302acc2eSNathan Whitehorn #include <sys/kernel.h> 34302acc2eSNathan Whitehorn #include <sys/bus.h> 35302acc2eSNathan Whitehorn #include <sys/pcpu.h> 36302acc2eSNathan Whitehorn #include <sys/proc.h> 37302acc2eSNathan Whitehorn #include <sys/smp.h> 38302acc2eSNathan Whitehorn 39302acc2eSNathan Whitehorn #include <machine/bus.h> 40302acc2eSNathan Whitehorn #include <machine/cpu.h> 41302acc2eSNathan Whitehorn #include <machine/hid.h> 42253902b4SJustin Hibbits #include <machine/_inttypes.h> 433f068cbfSJustin Hibbits #include <machine/machdep.h> 44253902b4SJustin Hibbits #include <machine/md_var.h> 45302acc2eSNathan Whitehorn #include <machine/platform.h> 46302acc2eSNathan Whitehorn #include <machine/platformvar.h> 47302acc2eSNathan Whitehorn #include <machine/smp.h> 48302acc2eSNathan Whitehorn #include <machine/spr.h> 49302acc2eSNathan Whitehorn #include <machine/vmparam.h> 50302acc2eSNathan Whitehorn 51302acc2eSNathan Whitehorn #include <dev/fdt/fdt_common.h> 52302acc2eSNathan Whitehorn #include <dev/ofw/ofw_bus.h> 53302acc2eSNathan Whitehorn #include <dev/ofw/ofw_bus_subr.h> 54302acc2eSNathan Whitehorn #include <dev/ofw/openfirm.h> 55302acc2eSNathan Whitehorn 5652cfe485SNathan Whitehorn #include <vm/vm.h> 5752cfe485SNathan Whitehorn #include <vm/pmap.h> 58253902b4SJustin Hibbits #include <vm/vm_extern.h> 5952cfe485SNathan Whitehorn 60302acc2eSNathan Whitehorn #include <powerpc/mpc85xx/mpc85xx.h> 61302acc2eSNathan Whitehorn 62302acc2eSNathan Whitehorn #include "platform_if.h" 63302acc2eSNathan Whitehorn 64302acc2eSNathan Whitehorn #ifdef SMP 65302acc2eSNathan Whitehorn extern void *ap_pcpu; 66302acc2eSNathan Whitehorn extern vm_paddr_t kernload; /* Kernel physical load address */ 67302acc2eSNathan Whitehorn extern uint8_t __boot_page[]; /* Boot page body */ 68f60708c9SJustin Hibbits extern uint32_t bp_kernload; 69253902b4SJustin Hibbits 70253902b4SJustin Hibbits struct cpu_release { 71253902b4SJustin Hibbits uint32_t entry_h; 72253902b4SJustin Hibbits uint32_t entry_l; 73253902b4SJustin Hibbits uint32_t r3_h; 74253902b4SJustin Hibbits uint32_t r3_l; 75253902b4SJustin Hibbits uint32_t reserved; 76253902b4SJustin Hibbits uint32_t pir; 77253902b4SJustin Hibbits }; 78302acc2eSNathan Whitehorn #endif 79302acc2eSNathan Whitehorn 80302acc2eSNathan Whitehorn extern uint32_t *bootinfo; 81b2f831c0SJustin Hibbits vm_paddr_t ccsrbar_pa; 8252cfe485SNathan Whitehorn vm_offset_t ccsrbar_va; 83b2f831c0SJustin Hibbits vm_size_t ccsrbar_size; 84302acc2eSNathan Whitehorn 85302acc2eSNathan Whitehorn static int cpu, maxcpu; 86302acc2eSNathan Whitehorn 87302acc2eSNathan Whitehorn static int mpc85xx_probe(platform_t); 88c1cb22d7SNathan Whitehorn static void mpc85xx_mem_regions(platform_t, struct mem_region *phys, 89c1cb22d7SNathan Whitehorn int *physsz, struct mem_region *avail, int *availsz); 90302acc2eSNathan Whitehorn static u_long mpc85xx_timebase_freq(platform_t, struct cpuref *cpuref); 91302acc2eSNathan Whitehorn static int mpc85xx_smp_first_cpu(platform_t, struct cpuref *cpuref); 92302acc2eSNathan Whitehorn static int mpc85xx_smp_next_cpu(platform_t, struct cpuref *cpuref); 93302acc2eSNathan Whitehorn static int mpc85xx_smp_get_bsp(platform_t, struct cpuref *cpuref); 94302acc2eSNathan Whitehorn static int mpc85xx_smp_start_cpu(platform_t, struct pcpu *cpu); 95*de2dd83fSNathan Whitehorn static void mpc85xx_smp_timebase_sync(platform_t, u_long tb, int ap); 96637f34cbSJustin Hibbits static void mpc85xx_idle(platform_t, int cpu); 97637f34cbSJustin Hibbits static int mpc85xx_idle_wakeup(platform_t plat, int cpu); 98302acc2eSNathan Whitehorn 99302acc2eSNathan Whitehorn static void mpc85xx_reset(platform_t); 100302acc2eSNathan Whitehorn 101302acc2eSNathan Whitehorn static platform_method_t mpc85xx_methods[] = { 102302acc2eSNathan Whitehorn PLATFORMMETHOD(platform_probe, mpc85xx_probe), 103302acc2eSNathan Whitehorn PLATFORMMETHOD(platform_attach, mpc85xx_attach), 104302acc2eSNathan Whitehorn PLATFORMMETHOD(platform_mem_regions, mpc85xx_mem_regions), 105302acc2eSNathan Whitehorn PLATFORMMETHOD(platform_timebase_freq, mpc85xx_timebase_freq), 106302acc2eSNathan Whitehorn 107302acc2eSNathan Whitehorn PLATFORMMETHOD(platform_smp_first_cpu, mpc85xx_smp_first_cpu), 108302acc2eSNathan Whitehorn PLATFORMMETHOD(platform_smp_next_cpu, mpc85xx_smp_next_cpu), 109302acc2eSNathan Whitehorn PLATFORMMETHOD(platform_smp_get_bsp, mpc85xx_smp_get_bsp), 110302acc2eSNathan Whitehorn PLATFORMMETHOD(platform_smp_start_cpu, mpc85xx_smp_start_cpu), 111*de2dd83fSNathan Whitehorn PLATFORMMETHOD(platform_smp_timebase_sync, mpc85xx_smp_timebase_sync), 112302acc2eSNathan Whitehorn 113302acc2eSNathan Whitehorn PLATFORMMETHOD(platform_reset, mpc85xx_reset), 114637f34cbSJustin Hibbits PLATFORMMETHOD(platform_idle, mpc85xx_idle), 115637f34cbSJustin Hibbits PLATFORMMETHOD(platform_idle_wakeup, mpc85xx_idle_wakeup), 116302acc2eSNathan Whitehorn 117302acc2eSNathan Whitehorn PLATFORMMETHOD_END 118302acc2eSNathan Whitehorn }; 119302acc2eSNathan Whitehorn 120fa7a1ca7SJustin Hibbits DEFINE_CLASS_0(mpc85xx, mpc85xx_platform, mpc85xx_methods, 0); 121302acc2eSNathan Whitehorn 122302acc2eSNathan Whitehorn PLATFORM_DEF(mpc85xx_platform); 123302acc2eSNathan Whitehorn 124302acc2eSNathan Whitehorn static int 125302acc2eSNathan Whitehorn mpc85xx_probe(platform_t plat) 126302acc2eSNathan Whitehorn { 127adbe2685SJustin Hibbits u_int pvr = (mfpvr() >> 16) & 0xFFFF; 128302acc2eSNathan Whitehorn 129adbe2685SJustin Hibbits switch (pvr) { 130adbe2685SJustin Hibbits case FSL_E500v1: 131adbe2685SJustin Hibbits case FSL_E500v2: 132adbe2685SJustin Hibbits case FSL_E500mc: 133adbe2685SJustin Hibbits case FSL_E5500: 134adbe2685SJustin Hibbits case FSL_E6500: 135302acc2eSNathan Whitehorn return (BUS_PROBE_DEFAULT); 136adbe2685SJustin Hibbits } 137302acc2eSNathan Whitehorn return (ENXIO); 138302acc2eSNathan Whitehorn } 139302acc2eSNathan Whitehorn 140fa7a1ca7SJustin Hibbits int 141302acc2eSNathan Whitehorn mpc85xx_attach(platform_t plat) 142302acc2eSNathan Whitehorn { 14352cfe485SNathan Whitehorn phandle_t cpus, child, ccsr; 14452cfe485SNathan Whitehorn const char *soc_name_guesses[] = {"/soc", "soc", NULL}; 14552cfe485SNathan Whitehorn const char **name; 14652cfe485SNathan Whitehorn pcell_t ranges[6], acells, pacells, scells; 14752cfe485SNathan Whitehorn uint64_t ccsrbar, ccsrsize; 148adbe2685SJustin Hibbits int i; 149302acc2eSNathan Whitehorn 150302acc2eSNathan Whitehorn if ((cpus = OF_finddevice("/cpus")) != -1) { 151302acc2eSNathan Whitehorn for (maxcpu = 0, child = OF_child(cpus); child != 0; 152302acc2eSNathan Whitehorn child = OF_peer(child), maxcpu++) 153302acc2eSNathan Whitehorn ; 154302acc2eSNathan Whitehorn } else 155302acc2eSNathan Whitehorn maxcpu = 1; 156302acc2eSNathan Whitehorn 157302acc2eSNathan Whitehorn /* 15852cfe485SNathan Whitehorn * Locate CCSR region. Irritatingly, there is no way to find it 15952cfe485SNathan Whitehorn * unless you already know where it is. Try to infer its location 16052cfe485SNathan Whitehorn * from the device tree. 16152cfe485SNathan Whitehorn */ 16252cfe485SNathan Whitehorn 16352cfe485SNathan Whitehorn ccsr = -1; 16452cfe485SNathan Whitehorn for (name = soc_name_guesses; *name != NULL && ccsr == -1; name++) 16552cfe485SNathan Whitehorn ccsr = OF_finddevice(*name); 16652cfe485SNathan Whitehorn if (ccsr == -1) { 16752cfe485SNathan Whitehorn char type[64]; 16852cfe485SNathan Whitehorn 16952cfe485SNathan Whitehorn /* That didn't work. Search for devices of type "soc" */ 17052cfe485SNathan Whitehorn child = OF_child(OF_peer(0)); 17152cfe485SNathan Whitehorn for (OF_child(child); child != 0; child = OF_peer(child)) { 17252cfe485SNathan Whitehorn if (OF_getprop(child, "device_type", type, sizeof(type)) 17352cfe485SNathan Whitehorn <= 0) 17452cfe485SNathan Whitehorn continue; 17552cfe485SNathan Whitehorn 17652cfe485SNathan Whitehorn if (strcmp(type, "soc") == 0) { 17752cfe485SNathan Whitehorn ccsr = child; 17852cfe485SNathan Whitehorn break; 17952cfe485SNathan Whitehorn } 18052cfe485SNathan Whitehorn } 18152cfe485SNathan Whitehorn } 18252cfe485SNathan Whitehorn 18352cfe485SNathan Whitehorn if (ccsr == -1) 18452cfe485SNathan Whitehorn panic("Could not locate CCSR window!"); 18552cfe485SNathan Whitehorn 18652cfe485SNathan Whitehorn OF_getprop(ccsr, "#size-cells", &scells, sizeof(scells)); 18752cfe485SNathan Whitehorn OF_getprop(ccsr, "#address-cells", &acells, sizeof(acells)); 18852cfe485SNathan Whitehorn OF_searchprop(OF_parent(ccsr), "#address-cells", &pacells, 18952cfe485SNathan Whitehorn sizeof(pacells)); 19052cfe485SNathan Whitehorn OF_getprop(ccsr, "ranges", ranges, sizeof(ranges)); 19152cfe485SNathan Whitehorn ccsrbar = ccsrsize = 0; 19252cfe485SNathan Whitehorn for (i = acells; i < acells + pacells; i++) { 19352cfe485SNathan Whitehorn ccsrbar <<= 32; 19452cfe485SNathan Whitehorn ccsrbar |= ranges[i]; 19552cfe485SNathan Whitehorn } 19652cfe485SNathan Whitehorn for (i = acells + pacells; i < acells + pacells + scells; i++) { 19752cfe485SNathan Whitehorn ccsrsize <<= 32; 19852cfe485SNathan Whitehorn ccsrsize |= ranges[i]; 19952cfe485SNathan Whitehorn } 20052cfe485SNathan Whitehorn ccsrbar_va = pmap_early_io_map(ccsrbar, ccsrsize); 201b2f831c0SJustin Hibbits ccsrbar_pa = ccsrbar; 202b2f831c0SJustin Hibbits ccsrbar_size = ccsrsize; 20352cfe485SNathan Whitehorn 204a2fe9079SJustin Hibbits #if 0 2053f068cbfSJustin Hibbits mpc85xx_fix_errata(ccsrbar_va); 206a2fe9079SJustin Hibbits #endif 2073f068cbfSJustin Hibbits mpc85xx_enable_l3_cache(); 2083f068cbfSJustin Hibbits 209302acc2eSNathan Whitehorn return (0); 210302acc2eSNathan Whitehorn } 211302acc2eSNathan Whitehorn 212302acc2eSNathan Whitehorn void 213c1cb22d7SNathan Whitehorn mpc85xx_mem_regions(platform_t plat, struct mem_region *phys, int *physsz, 214c1cb22d7SNathan Whitehorn struct mem_region *avail, int *availsz) 215302acc2eSNathan Whitehorn { 216302acc2eSNathan Whitehorn 217302acc2eSNathan Whitehorn ofw_mem_regions(phys, physsz, avail, availsz); 218302acc2eSNathan Whitehorn } 219302acc2eSNathan Whitehorn 220302acc2eSNathan Whitehorn static u_long 221302acc2eSNathan Whitehorn mpc85xx_timebase_freq(platform_t plat, struct cpuref *cpuref) 222302acc2eSNathan Whitehorn { 223302acc2eSNathan Whitehorn u_long ticks; 224302acc2eSNathan Whitehorn phandle_t cpus, child; 225302acc2eSNathan Whitehorn pcell_t freq; 226302acc2eSNathan Whitehorn 227302acc2eSNathan Whitehorn if (bootinfo != NULL) { 228302acc2eSNathan Whitehorn if (bootinfo[0] == 1) { 229302acc2eSNathan Whitehorn /* Backward compatibility. See 8-STABLE. */ 230302acc2eSNathan Whitehorn ticks = bootinfo[3] >> 3; 231302acc2eSNathan Whitehorn } else { 232302acc2eSNathan Whitehorn /* Compatibility with Juniper's loader. */ 233302acc2eSNathan Whitehorn ticks = bootinfo[5] >> 3; 234302acc2eSNathan Whitehorn } 235302acc2eSNathan Whitehorn } else 236302acc2eSNathan Whitehorn ticks = 0; 237302acc2eSNathan Whitehorn 238302acc2eSNathan Whitehorn if ((cpus = OF_finddevice("/cpus")) == -1) 239302acc2eSNathan Whitehorn goto out; 240302acc2eSNathan Whitehorn 241302acc2eSNathan Whitehorn if ((child = OF_child(cpus)) == 0) 242302acc2eSNathan Whitehorn goto out; 243302acc2eSNathan Whitehorn 244302acc2eSNathan Whitehorn switch (OF_getproplen(child, "timebase-frequency")) { 245302acc2eSNathan Whitehorn case 4: 246302acc2eSNathan Whitehorn { 247302acc2eSNathan Whitehorn uint32_t tbase; 248302acc2eSNathan Whitehorn OF_getprop(child, "timebase-frequency", &tbase, sizeof(tbase)); 249302acc2eSNathan Whitehorn ticks = tbase; 250302acc2eSNathan Whitehorn return (ticks); 251302acc2eSNathan Whitehorn } 252302acc2eSNathan Whitehorn case 8: 253302acc2eSNathan Whitehorn { 254302acc2eSNathan Whitehorn uint64_t tbase; 255302acc2eSNathan Whitehorn OF_getprop(child, "timebase-frequency", &tbase, sizeof(tbase)); 256302acc2eSNathan Whitehorn ticks = tbase; 257302acc2eSNathan Whitehorn return (ticks); 258302acc2eSNathan Whitehorn } 259302acc2eSNathan Whitehorn default: 260302acc2eSNathan Whitehorn break; 261302acc2eSNathan Whitehorn } 262302acc2eSNathan Whitehorn 263302acc2eSNathan Whitehorn freq = 0; 264302acc2eSNathan Whitehorn if (OF_getprop(child, "bus-frequency", (void *)&freq, 265302acc2eSNathan Whitehorn sizeof(freq)) <= 0) 266302acc2eSNathan Whitehorn goto out; 267302acc2eSNathan Whitehorn 2686cedae09SJustin Hibbits if (freq == 0) 2696cedae09SJustin Hibbits goto out; 2706cedae09SJustin Hibbits 271302acc2eSNathan Whitehorn /* 272302acc2eSNathan Whitehorn * Time Base and Decrementer are updated every 8 CCB bus clocks. 273302acc2eSNathan Whitehorn * HID0[SEL_TBCLK] = 0 274302acc2eSNathan Whitehorn */ 2756cedae09SJustin Hibbits if (mpc85xx_is_qoriq()) 2763f068cbfSJustin Hibbits ticks = freq / 32; 2776cedae09SJustin Hibbits else 278302acc2eSNathan Whitehorn ticks = freq / 8; 279302acc2eSNathan Whitehorn 280302acc2eSNathan Whitehorn out: 281302acc2eSNathan Whitehorn if (ticks <= 0) 282302acc2eSNathan Whitehorn panic("Unable to determine timebase frequency!"); 283302acc2eSNathan Whitehorn 284302acc2eSNathan Whitehorn return (ticks); 285302acc2eSNathan Whitehorn } 286302acc2eSNathan Whitehorn 287302acc2eSNathan Whitehorn static int 288302acc2eSNathan Whitehorn mpc85xx_smp_first_cpu(platform_t plat, struct cpuref *cpuref) 289302acc2eSNathan Whitehorn { 290302acc2eSNathan Whitehorn 291302acc2eSNathan Whitehorn cpu = 0; 292302acc2eSNathan Whitehorn cpuref->cr_cpuid = cpu; 293302acc2eSNathan Whitehorn cpuref->cr_hwref = cpuref->cr_cpuid; 294302acc2eSNathan Whitehorn if (bootverbose) 295302acc2eSNathan Whitehorn printf("powerpc_smp_first_cpu: cpuid %d\n", cpuref->cr_cpuid); 296302acc2eSNathan Whitehorn cpu++; 297302acc2eSNathan Whitehorn 298302acc2eSNathan Whitehorn return (0); 299302acc2eSNathan Whitehorn } 300302acc2eSNathan Whitehorn 301302acc2eSNathan Whitehorn static int 302302acc2eSNathan Whitehorn mpc85xx_smp_next_cpu(platform_t plat, struct cpuref *cpuref) 303302acc2eSNathan Whitehorn { 304302acc2eSNathan Whitehorn 305302acc2eSNathan Whitehorn if (cpu >= maxcpu) 306302acc2eSNathan Whitehorn return (ENOENT); 307302acc2eSNathan Whitehorn 308302acc2eSNathan Whitehorn cpuref->cr_cpuid = cpu++; 309302acc2eSNathan Whitehorn cpuref->cr_hwref = cpuref->cr_cpuid; 310302acc2eSNathan Whitehorn if (bootverbose) 311302acc2eSNathan Whitehorn printf("powerpc_smp_next_cpu: cpuid %d\n", cpuref->cr_cpuid); 312302acc2eSNathan Whitehorn 313302acc2eSNathan Whitehorn return (0); 314302acc2eSNathan Whitehorn } 315302acc2eSNathan Whitehorn 316302acc2eSNathan Whitehorn static int 317302acc2eSNathan Whitehorn mpc85xx_smp_get_bsp(platform_t plat, struct cpuref *cpuref) 318302acc2eSNathan Whitehorn { 319302acc2eSNathan Whitehorn 320302acc2eSNathan Whitehorn cpuref->cr_cpuid = mfspr(SPR_PIR); 321302acc2eSNathan Whitehorn cpuref->cr_hwref = cpuref->cr_cpuid; 322302acc2eSNathan Whitehorn 323302acc2eSNathan Whitehorn return (0); 324302acc2eSNathan Whitehorn } 325302acc2eSNathan Whitehorn 326253902b4SJustin Hibbits #ifdef SMP 327253902b4SJustin Hibbits static int 328253902b4SJustin Hibbits mpc85xx_smp_start_cpu_epapr(platform_t plat, struct pcpu *pc) 329253902b4SJustin Hibbits { 330253902b4SJustin Hibbits vm_paddr_t rel_pa, bptr; 331253902b4SJustin Hibbits volatile struct cpu_release *rel; 332253902b4SJustin Hibbits vm_offset_t rel_va, rel_page; 333253902b4SJustin Hibbits phandle_t node; 334253902b4SJustin Hibbits int i; 335253902b4SJustin Hibbits 336253902b4SJustin Hibbits /* If we're calling this, the node already exists. */ 337253902b4SJustin Hibbits node = OF_finddevice("/cpus"); 338253902b4SJustin Hibbits for (i = 0, node = OF_child(node); i < pc->pc_cpuid; 339253902b4SJustin Hibbits i++, node = OF_peer(node)) 340253902b4SJustin Hibbits ; 341253902b4SJustin Hibbits if (OF_getencprop(node, "cpu-release-addr", (pcell_t *)&rel_pa, 342253902b4SJustin Hibbits sizeof(rel_pa)) == -1) { 343253902b4SJustin Hibbits return (ENOENT); 344253902b4SJustin Hibbits } 345253902b4SJustin Hibbits 346253902b4SJustin Hibbits rel_page = kva_alloc(PAGE_SIZE); 347253902b4SJustin Hibbits if (rel_page == 0) 348253902b4SJustin Hibbits return (ENOMEM); 349253902b4SJustin Hibbits 350253902b4SJustin Hibbits critical_enter(); 351253902b4SJustin Hibbits rel_va = rel_page + (rel_pa & PAGE_MASK); 352253902b4SJustin Hibbits pmap_kenter(rel_page, rel_pa & ~PAGE_MASK); 353253902b4SJustin Hibbits rel = (struct cpu_release *)rel_va; 354253902b4SJustin Hibbits bptr = ((vm_paddr_t)(uintptr_t)__boot_page - KERNBASE) + kernload; 355253902b4SJustin Hibbits cpu_flush_dcache(__DEVOLATILE(struct cpu_release *,rel), sizeof(*rel)); 356253902b4SJustin Hibbits rel->pir = pc->pc_cpuid; __asm __volatile("sync"); 357253902b4SJustin Hibbits rel->entry_h = (bptr >> 32); 358253902b4SJustin Hibbits rel->entry_l = bptr; __asm __volatile("sync"); 359253902b4SJustin Hibbits cpu_flush_dcache(__DEVOLATILE(struct cpu_release *,rel), sizeof(*rel)); 360253902b4SJustin Hibbits if (bootverbose) 361253902b4SJustin Hibbits printf("Waking up CPU %d via CPU release page %p\n", 362253902b4SJustin Hibbits pc->pc_cpuid, rel); 363253902b4SJustin Hibbits critical_exit(); 364253902b4SJustin Hibbits pmap_kremove(rel_page); 365253902b4SJustin Hibbits kva_free(rel_page, PAGE_SIZE); 366253902b4SJustin Hibbits 367253902b4SJustin Hibbits return (0); 368253902b4SJustin Hibbits } 369253902b4SJustin Hibbits #endif 370253902b4SJustin Hibbits 371302acc2eSNathan Whitehorn static int 372302acc2eSNathan Whitehorn mpc85xx_smp_start_cpu(platform_t plat, struct pcpu *pc) 373302acc2eSNathan Whitehorn { 374302acc2eSNathan Whitehorn #ifdef SMP 3753f068cbfSJustin Hibbits vm_paddr_t bptr; 3763f068cbfSJustin Hibbits uint32_t reg; 377f60708c9SJustin Hibbits int timeout; 3783f068cbfSJustin Hibbits uintptr_t brr; 3793f068cbfSJustin Hibbits int cpuid; 380253902b4SJustin Hibbits int epapr_boot = 0; 3813f068cbfSJustin Hibbits uint32_t tgt; 3823f068cbfSJustin Hibbits 3836cedae09SJustin Hibbits if (mpc85xx_is_qoriq()) { 3843f068cbfSJustin Hibbits reg = ccsr_read4(OCP85XX_COREDISR); 3853f068cbfSJustin Hibbits cpuid = pc->pc_cpuid; 3863f068cbfSJustin Hibbits 3876cedae09SJustin Hibbits if ((reg & (1 << cpuid)) != 0) { 3883f068cbfSJustin Hibbits printf("%s: CPU %d is disabled!\n", __func__, pc->pc_cpuid); 3893f068cbfSJustin Hibbits return (-1); 3903f068cbfSJustin Hibbits } 3913f068cbfSJustin Hibbits 3923f068cbfSJustin Hibbits brr = OCP85XX_BRR; 3936cedae09SJustin Hibbits } else { 3943f068cbfSJustin Hibbits brr = OCP85XX_EEBPCR; 3953f068cbfSJustin Hibbits cpuid = pc->pc_cpuid + 24; 3966cedae09SJustin Hibbits } 397f60708c9SJustin Hibbits bp_kernload = kernload; 398253902b4SJustin Hibbits /* 399253902b4SJustin Hibbits * bp_kernload is in the boot page. Sync the cache because ePAPR 400253902b4SJustin Hibbits * booting has the other core(s) already running. 401253902b4SJustin Hibbits */ 4027599d2ddSJustin Hibbits cpu_flush_dcache(&bp_kernload, sizeof(bp_kernload)); 403253902b4SJustin Hibbits 404253902b4SJustin Hibbits ap_pcpu = pc; 405253902b4SJustin Hibbits __asm __volatile("msync; isync"); 406253902b4SJustin Hibbits 407253902b4SJustin Hibbits /* First try the ePAPR way. */ 408253902b4SJustin Hibbits if (mpc85xx_smp_start_cpu_epapr(plat, pc) == 0) { 409253902b4SJustin Hibbits epapr_boot = 1; 410253902b4SJustin Hibbits goto spin_wait; 411253902b4SJustin Hibbits } 4126cedae09SJustin Hibbits 4133f068cbfSJustin Hibbits reg = ccsr_read4(brr); 4143f068cbfSJustin Hibbits if ((reg & (1 << cpuid)) != 0) { 415302acc2eSNathan Whitehorn printf("SMP: CPU %d already out of hold-off state!\n", 416302acc2eSNathan Whitehorn pc->pc_cpuid); 417302acc2eSNathan Whitehorn return (ENXIO); 418302acc2eSNathan Whitehorn } 419302acc2eSNathan Whitehorn 4203f068cbfSJustin Hibbits /* Flush caches to have our changes hit DRAM. */ 4213f068cbfSJustin Hibbits cpu_flush_dcache(__boot_page, 4096); 4223f068cbfSJustin Hibbits 4233f068cbfSJustin Hibbits bptr = ((vm_paddr_t)(uintptr_t)__boot_page - KERNBASE) + kernload; 4243f068cbfSJustin Hibbits KASSERT((bptr & 0xfff) == 0, 4253f068cbfSJustin Hibbits ("%s: boot page is not aligned (%#jx)", __func__, (uintmax_t)bptr)); 4266cedae09SJustin Hibbits if (mpc85xx_is_qoriq()) { 4273f068cbfSJustin Hibbits /* 4283f068cbfSJustin Hibbits * Read DDR controller configuration to select proper BPTR target ID. 4293f068cbfSJustin Hibbits * 4303f068cbfSJustin Hibbits * On P5020 bit 29 of DDR1_CS0_CONFIG enables DDR controllers 4313f068cbfSJustin Hibbits * interleaving. If this bit is set, we have to use 4323f068cbfSJustin Hibbits * OCP85XX_TGTIF_RAM_INTL as BPTR target ID. On other QorIQ DPAA SoCs, 4333f068cbfSJustin Hibbits * this bit is reserved and always 0. 4343f068cbfSJustin Hibbits */ 4353f068cbfSJustin Hibbits 4363f068cbfSJustin Hibbits reg = ccsr_read4(OCP85XX_DDR1_CS0_CONFIG); 4373f068cbfSJustin Hibbits if (reg & (1 << 29)) 4383f068cbfSJustin Hibbits tgt = OCP85XX_TGTIF_RAM_INTL; 4393f068cbfSJustin Hibbits else 4403f068cbfSJustin Hibbits tgt = OCP85XX_TGTIF_RAM1; 4413f068cbfSJustin Hibbits 4423f068cbfSJustin Hibbits /* 4433f068cbfSJustin Hibbits * Set BSTR to the physical address of the boot page 4443f068cbfSJustin Hibbits */ 4453f068cbfSJustin Hibbits ccsr_write4(OCP85XX_BSTRH, bptr >> 32); 4463f068cbfSJustin Hibbits ccsr_write4(OCP85XX_BSTRL, bptr); 4473f068cbfSJustin Hibbits ccsr_write4(OCP85XX_BSTAR, OCP85XX_ENA_MASK | 4486cedae09SJustin Hibbits (tgt << OCP85XX_TRGT_SHIFT_QORIQ) | (ffsl(PAGE_SIZE) - 2)); 4493f068cbfSJustin Hibbits 4503f068cbfSJustin Hibbits /* Read back OCP85XX_BSTAR to synchronize write */ 4513f068cbfSJustin Hibbits ccsr_read4(OCP85XX_BSTAR); 4523f068cbfSJustin Hibbits 4533f068cbfSJustin Hibbits /* 4543f068cbfSJustin Hibbits * Enable and configure time base on new CPU. 4553f068cbfSJustin Hibbits */ 4563f068cbfSJustin Hibbits 4573f068cbfSJustin Hibbits /* Set TB clock source to platform clock / 32 */ 4583f068cbfSJustin Hibbits reg = ccsr_read4(CCSR_CTBCKSELR); 4593f068cbfSJustin Hibbits ccsr_write4(CCSR_CTBCKSELR, reg & ~(1 << pc->pc_cpuid)); 4603f068cbfSJustin Hibbits 4613f068cbfSJustin Hibbits /* Enable TB */ 4623f068cbfSJustin Hibbits reg = ccsr_read4(CCSR_CTBENR); 4633f068cbfSJustin Hibbits ccsr_write4(CCSR_CTBENR, reg | (1 << pc->pc_cpuid)); 4646cedae09SJustin Hibbits } else { 465302acc2eSNathan Whitehorn /* 466302acc2eSNathan Whitehorn * Set BPTR to the physical address of the boot page 467302acc2eSNathan Whitehorn */ 468302acc2eSNathan Whitehorn bptr = (bptr >> 12) | 0x80000000u; 469302acc2eSNathan Whitehorn ccsr_write4(OCP85XX_BPTR, bptr); 470302acc2eSNathan Whitehorn __asm __volatile("isync; msync"); 4716cedae09SJustin Hibbits } 472302acc2eSNathan Whitehorn 473302acc2eSNathan Whitehorn /* 474302acc2eSNathan Whitehorn * Release AP from hold-off state 475302acc2eSNathan Whitehorn */ 4763f068cbfSJustin Hibbits reg = ccsr_read4(brr); 4773f068cbfSJustin Hibbits ccsr_write4(brr, reg | (1 << cpuid)); 478302acc2eSNathan Whitehorn __asm __volatile("isync; msync"); 479302acc2eSNathan Whitehorn 480253902b4SJustin Hibbits spin_wait: 481302acc2eSNathan Whitehorn timeout = 500; 482302acc2eSNathan Whitehorn while (!pc->pc_awake && timeout--) 483302acc2eSNathan Whitehorn DELAY(1000); /* wait 1ms */ 484302acc2eSNathan Whitehorn 485302acc2eSNathan Whitehorn /* 486302acc2eSNathan Whitehorn * Disable boot page translation so that the 4K page at the default 487302acc2eSNathan Whitehorn * address (= 0xfffff000) isn't permanently remapped and thus not 488302acc2eSNathan Whitehorn * usable otherwise. 489302acc2eSNathan Whitehorn */ 490253902b4SJustin Hibbits if (!epapr_boot) { 4916cedae09SJustin Hibbits if (mpc85xx_is_qoriq()) 4923f068cbfSJustin Hibbits ccsr_write4(OCP85XX_BSTAR, 0); 4936cedae09SJustin Hibbits else 494302acc2eSNathan Whitehorn ccsr_write4(OCP85XX_BPTR, 0); 495302acc2eSNathan Whitehorn __asm __volatile("isync; msync"); 496253902b4SJustin Hibbits } 497302acc2eSNathan Whitehorn 498302acc2eSNathan Whitehorn if (!pc->pc_awake) 4996cedae09SJustin Hibbits panic("SMP: CPU %d didn't wake up.\n", pc->pc_cpuid); 500302acc2eSNathan Whitehorn return ((pc->pc_awake) ? 0 : EBUSY); 501302acc2eSNathan Whitehorn #else 502302acc2eSNathan Whitehorn /* No SMP support */ 503302acc2eSNathan Whitehorn return (ENXIO); 504302acc2eSNathan Whitehorn #endif 505302acc2eSNathan Whitehorn } 506302acc2eSNathan Whitehorn 507302acc2eSNathan Whitehorn static void 508302acc2eSNathan Whitehorn mpc85xx_reset(platform_t plat) 509302acc2eSNathan Whitehorn { 510302acc2eSNathan Whitehorn 511302acc2eSNathan Whitehorn /* 512302acc2eSNathan Whitehorn * Try the dedicated reset register first. 513302acc2eSNathan Whitehorn * If the SoC doesn't have one, we'll fall 514302acc2eSNathan Whitehorn * back to using the debug control register. 515302acc2eSNathan Whitehorn */ 516302acc2eSNathan Whitehorn ccsr_write4(OCP85XX_RSTCR, 2); 517302acc2eSNathan Whitehorn 518302acc2eSNathan Whitehorn /* Clear DBCR0, disables debug interrupts and events. */ 519302acc2eSNathan Whitehorn mtspr(SPR_DBCR0, 0); 520302acc2eSNathan Whitehorn __asm __volatile("isync"); 521302acc2eSNathan Whitehorn 522302acc2eSNathan Whitehorn /* Enable Debug Interrupts in MSR. */ 523302acc2eSNathan Whitehorn mtmsr(mfmsr() | PSL_DE); 524302acc2eSNathan Whitehorn 525302acc2eSNathan Whitehorn /* Enable debug interrupts and issue reset. */ 526302acc2eSNathan Whitehorn mtspr(SPR_DBCR0, mfspr(SPR_DBCR0) | DBCR0_IDM | DBCR0_RST_SYSTEM); 527302acc2eSNathan Whitehorn 528302acc2eSNathan Whitehorn printf("Reset failed...\n"); 529302acc2eSNathan Whitehorn while (1) 530302acc2eSNathan Whitehorn ; 531302acc2eSNathan Whitehorn } 532302acc2eSNathan Whitehorn 533637f34cbSJustin Hibbits static void 534*de2dd83fSNathan Whitehorn mpc85xx_smp_timebase_sync(platform_t plat, u_long tb, int ap) 535*de2dd83fSNathan Whitehorn { 536*de2dd83fSNathan Whitehorn 537*de2dd83fSNathan Whitehorn mttb(tb); 538*de2dd83fSNathan Whitehorn } 539*de2dd83fSNathan Whitehorn 540*de2dd83fSNathan Whitehorn static void 541637f34cbSJustin Hibbits mpc85xx_idle(platform_t plat, int cpu) 542637f34cbSJustin Hibbits { 543637f34cbSJustin Hibbits uint32_t reg; 544637f34cbSJustin Hibbits 5456cedae09SJustin Hibbits if (mpc85xx_is_qoriq()) { 546e5a8e245SJustin Hibbits /* 547e5a8e245SJustin Hibbits * Base binutils doesn't know what the 'wait' instruction is, so 548e5a8e245SJustin Hibbits * use the opcode encoding here. 549e5a8e245SJustin Hibbits */ 550e5a8e245SJustin Hibbits __asm __volatile("wrteei 1; .long 0x7c00007c"); 5516cedae09SJustin Hibbits } else { 5526cedae09SJustin Hibbits reg = mfmsr(); 553637f34cbSJustin Hibbits /* Freescale E500 core RM section 6.4.1. */ 554637f34cbSJustin Hibbits __asm __volatile("msync; mtmsr %0; isync" :: 5556cedae09SJustin Hibbits "r" (reg | PSL_WE)); 5566cedae09SJustin Hibbits } 557637f34cbSJustin Hibbits } 558637f34cbSJustin Hibbits 559637f34cbSJustin Hibbits static int 560637f34cbSJustin Hibbits mpc85xx_idle_wakeup(platform_t plat, int cpu) 561637f34cbSJustin Hibbits { 5626cedae09SJustin Hibbits 563637f34cbSJustin Hibbits return (0); 564637f34cbSJustin Hibbits } 565