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; 8152cfe485SNathan Whitehorn vm_offset_t ccsrbar_va; 82302acc2eSNathan Whitehorn 83302acc2eSNathan Whitehorn static int cpu, maxcpu; 84302acc2eSNathan Whitehorn 85302acc2eSNathan Whitehorn static int mpc85xx_probe(platform_t); 86c1cb22d7SNathan Whitehorn static void mpc85xx_mem_regions(platform_t, struct mem_region *phys, 87c1cb22d7SNathan Whitehorn int *physsz, struct mem_region *avail, int *availsz); 88302acc2eSNathan Whitehorn static u_long mpc85xx_timebase_freq(platform_t, struct cpuref *cpuref); 89302acc2eSNathan Whitehorn static int mpc85xx_smp_first_cpu(platform_t, struct cpuref *cpuref); 90302acc2eSNathan Whitehorn static int mpc85xx_smp_next_cpu(platform_t, struct cpuref *cpuref); 91302acc2eSNathan Whitehorn static int mpc85xx_smp_get_bsp(platform_t, struct cpuref *cpuref); 92302acc2eSNathan Whitehorn static int mpc85xx_smp_start_cpu(platform_t, struct pcpu *cpu); 93637f34cbSJustin Hibbits static void mpc85xx_idle(platform_t, int cpu); 94637f34cbSJustin Hibbits static int mpc85xx_idle_wakeup(platform_t plat, int cpu); 95302acc2eSNathan Whitehorn 96302acc2eSNathan Whitehorn static void mpc85xx_reset(platform_t); 97302acc2eSNathan Whitehorn 98302acc2eSNathan Whitehorn static platform_method_t mpc85xx_methods[] = { 99302acc2eSNathan Whitehorn PLATFORMMETHOD(platform_probe, mpc85xx_probe), 100302acc2eSNathan Whitehorn PLATFORMMETHOD(platform_attach, mpc85xx_attach), 101302acc2eSNathan Whitehorn PLATFORMMETHOD(platform_mem_regions, mpc85xx_mem_regions), 102302acc2eSNathan Whitehorn PLATFORMMETHOD(platform_timebase_freq, mpc85xx_timebase_freq), 103302acc2eSNathan Whitehorn 104302acc2eSNathan Whitehorn PLATFORMMETHOD(platform_smp_first_cpu, mpc85xx_smp_first_cpu), 105302acc2eSNathan Whitehorn PLATFORMMETHOD(platform_smp_next_cpu, mpc85xx_smp_next_cpu), 106302acc2eSNathan Whitehorn PLATFORMMETHOD(platform_smp_get_bsp, mpc85xx_smp_get_bsp), 107302acc2eSNathan Whitehorn PLATFORMMETHOD(platform_smp_start_cpu, mpc85xx_smp_start_cpu), 108302acc2eSNathan Whitehorn 109302acc2eSNathan Whitehorn PLATFORMMETHOD(platform_reset, mpc85xx_reset), 110637f34cbSJustin Hibbits PLATFORMMETHOD(platform_idle, mpc85xx_idle), 111637f34cbSJustin Hibbits PLATFORMMETHOD(platform_idle_wakeup, mpc85xx_idle_wakeup), 112302acc2eSNathan Whitehorn 113302acc2eSNathan Whitehorn PLATFORMMETHOD_END 114302acc2eSNathan Whitehorn }; 115302acc2eSNathan Whitehorn 116fa7a1ca7SJustin Hibbits DEFINE_CLASS_0(mpc85xx, mpc85xx_platform, mpc85xx_methods, 0); 117302acc2eSNathan Whitehorn 118302acc2eSNathan Whitehorn PLATFORM_DEF(mpc85xx_platform); 119302acc2eSNathan Whitehorn 120302acc2eSNathan Whitehorn static int 121302acc2eSNathan Whitehorn mpc85xx_probe(platform_t plat) 122302acc2eSNathan Whitehorn { 123302acc2eSNathan Whitehorn u_int pvr = mfpvr() >> 16; 124302acc2eSNathan Whitehorn 125302acc2eSNathan Whitehorn if ((pvr & 0xfff0) == FSL_E500v1) 126302acc2eSNathan Whitehorn return (BUS_PROBE_DEFAULT); 127302acc2eSNathan Whitehorn 128302acc2eSNathan Whitehorn return (ENXIO); 129302acc2eSNathan Whitehorn } 130302acc2eSNathan Whitehorn 131fa7a1ca7SJustin Hibbits int 132302acc2eSNathan Whitehorn mpc85xx_attach(platform_t plat) 133302acc2eSNathan Whitehorn { 13452cfe485SNathan Whitehorn phandle_t cpus, child, ccsr; 13552cfe485SNathan Whitehorn const char *soc_name_guesses[] = {"/soc", "soc", NULL}; 13652cfe485SNathan Whitehorn const char **name; 13752cfe485SNathan Whitehorn pcell_t ranges[6], acells, pacells, scells; 138302acc2eSNathan Whitehorn uint32_t sr; 13952cfe485SNathan Whitehorn uint64_t ccsrbar, ccsrsize; 140302acc2eSNathan Whitehorn int i, law_max, tgt; 141302acc2eSNathan Whitehorn 142302acc2eSNathan Whitehorn if ((cpus = OF_finddevice("/cpus")) != -1) { 143302acc2eSNathan Whitehorn for (maxcpu = 0, child = OF_child(cpus); child != 0; 144302acc2eSNathan Whitehorn child = OF_peer(child), maxcpu++) 145302acc2eSNathan Whitehorn ; 146302acc2eSNathan Whitehorn } else 147302acc2eSNathan Whitehorn maxcpu = 1; 148302acc2eSNathan Whitehorn 149302acc2eSNathan Whitehorn /* 15052cfe485SNathan Whitehorn * Locate CCSR region. Irritatingly, there is no way to find it 15152cfe485SNathan Whitehorn * unless you already know where it is. Try to infer its location 15252cfe485SNathan Whitehorn * from the device tree. 15352cfe485SNathan Whitehorn */ 15452cfe485SNathan Whitehorn 15552cfe485SNathan Whitehorn ccsr = -1; 15652cfe485SNathan Whitehorn for (name = soc_name_guesses; *name != NULL && ccsr == -1; name++) 15752cfe485SNathan Whitehorn ccsr = OF_finddevice(*name); 15852cfe485SNathan Whitehorn if (ccsr == -1) { 15952cfe485SNathan Whitehorn char type[64]; 16052cfe485SNathan Whitehorn 16152cfe485SNathan Whitehorn /* That didn't work. Search for devices of type "soc" */ 16252cfe485SNathan Whitehorn child = OF_child(OF_peer(0)); 16352cfe485SNathan Whitehorn for (OF_child(child); child != 0; child = OF_peer(child)) { 16452cfe485SNathan Whitehorn if (OF_getprop(child, "device_type", type, sizeof(type)) 16552cfe485SNathan Whitehorn <= 0) 16652cfe485SNathan Whitehorn continue; 16752cfe485SNathan Whitehorn 16852cfe485SNathan Whitehorn if (strcmp(type, "soc") == 0) { 16952cfe485SNathan Whitehorn ccsr = child; 17052cfe485SNathan Whitehorn break; 17152cfe485SNathan Whitehorn } 17252cfe485SNathan Whitehorn } 17352cfe485SNathan Whitehorn } 17452cfe485SNathan Whitehorn 17552cfe485SNathan Whitehorn if (ccsr == -1) 17652cfe485SNathan Whitehorn panic("Could not locate CCSR window!"); 17752cfe485SNathan Whitehorn 17852cfe485SNathan Whitehorn OF_getprop(ccsr, "#size-cells", &scells, sizeof(scells)); 17952cfe485SNathan Whitehorn OF_getprop(ccsr, "#address-cells", &acells, sizeof(acells)); 18052cfe485SNathan Whitehorn OF_searchprop(OF_parent(ccsr), "#address-cells", &pacells, 18152cfe485SNathan Whitehorn sizeof(pacells)); 18252cfe485SNathan Whitehorn OF_getprop(ccsr, "ranges", ranges, sizeof(ranges)); 18352cfe485SNathan Whitehorn ccsrbar = ccsrsize = 0; 18452cfe485SNathan Whitehorn for (i = acells; i < acells + pacells; i++) { 18552cfe485SNathan Whitehorn ccsrbar <<= 32; 18652cfe485SNathan Whitehorn ccsrbar |= ranges[i]; 18752cfe485SNathan Whitehorn } 18852cfe485SNathan Whitehorn for (i = acells + pacells; i < acells + pacells + scells; i++) { 18952cfe485SNathan Whitehorn ccsrsize <<= 32; 19052cfe485SNathan Whitehorn ccsrsize |= ranges[i]; 19152cfe485SNathan Whitehorn } 19252cfe485SNathan Whitehorn ccsrbar_va = pmap_early_io_map(ccsrbar, ccsrsize); 19352cfe485SNathan Whitehorn 1943f068cbfSJustin Hibbits mpc85xx_fix_errata(ccsrbar_va); 1953f068cbfSJustin Hibbits mpc85xx_enable_l3_cache(); 1963f068cbfSJustin Hibbits 19752cfe485SNathan Whitehorn /* 198302acc2eSNathan Whitehorn * Clear local access windows. Skip DRAM entries, so we don't shoot 199302acc2eSNathan Whitehorn * ourselves in the foot. 200302acc2eSNathan Whitehorn */ 201302acc2eSNathan Whitehorn law_max = law_getmax(); 202302acc2eSNathan Whitehorn for (i = 0; i < law_max; i++) { 203302acc2eSNathan Whitehorn sr = ccsr_read4(OCP85XX_LAWSR(i)); 2043f068cbfSJustin Hibbits if ((sr & OCP85XX_ENA_MASK) == 0) 205302acc2eSNathan Whitehorn continue; 206302acc2eSNathan Whitehorn tgt = (sr & 0x01f00000) >> 20; 207302acc2eSNathan Whitehorn if (tgt == OCP85XX_TGTIF_RAM1 || tgt == OCP85XX_TGTIF_RAM2 || 208302acc2eSNathan Whitehorn tgt == OCP85XX_TGTIF_RAM_INTL) 209302acc2eSNathan Whitehorn continue; 210302acc2eSNathan Whitehorn 2113f068cbfSJustin Hibbits ccsr_write4(OCP85XX_LAWSR(i), sr & OCP85XX_DIS_MASK); 212302acc2eSNathan Whitehorn } 213302acc2eSNathan Whitehorn 214302acc2eSNathan Whitehorn return (0); 215302acc2eSNathan Whitehorn } 216302acc2eSNathan Whitehorn 217302acc2eSNathan Whitehorn void 218c1cb22d7SNathan Whitehorn mpc85xx_mem_regions(platform_t plat, struct mem_region *phys, int *physsz, 219c1cb22d7SNathan Whitehorn struct mem_region *avail, int *availsz) 220302acc2eSNathan Whitehorn { 221302acc2eSNathan Whitehorn 222302acc2eSNathan Whitehorn ofw_mem_regions(phys, physsz, avail, availsz); 223302acc2eSNathan Whitehorn } 224302acc2eSNathan Whitehorn 225302acc2eSNathan Whitehorn static u_long 226302acc2eSNathan Whitehorn mpc85xx_timebase_freq(platform_t plat, struct cpuref *cpuref) 227302acc2eSNathan Whitehorn { 228302acc2eSNathan Whitehorn u_long ticks; 229302acc2eSNathan Whitehorn phandle_t cpus, child; 230302acc2eSNathan Whitehorn pcell_t freq; 231302acc2eSNathan Whitehorn 232302acc2eSNathan Whitehorn if (bootinfo != NULL) { 233302acc2eSNathan Whitehorn if (bootinfo[0] == 1) { 234302acc2eSNathan Whitehorn /* Backward compatibility. See 8-STABLE. */ 235302acc2eSNathan Whitehorn ticks = bootinfo[3] >> 3; 236302acc2eSNathan Whitehorn } else { 237302acc2eSNathan Whitehorn /* Compatibility with Juniper's loader. */ 238302acc2eSNathan Whitehorn ticks = bootinfo[5] >> 3; 239302acc2eSNathan Whitehorn } 240302acc2eSNathan Whitehorn } else 241302acc2eSNathan Whitehorn ticks = 0; 242302acc2eSNathan Whitehorn 243302acc2eSNathan Whitehorn if ((cpus = OF_finddevice("/cpus")) == -1) 244302acc2eSNathan Whitehorn goto out; 245302acc2eSNathan Whitehorn 246302acc2eSNathan Whitehorn if ((child = OF_child(cpus)) == 0) 247302acc2eSNathan Whitehorn goto out; 248302acc2eSNathan Whitehorn 249302acc2eSNathan Whitehorn switch (OF_getproplen(child, "timebase-frequency")) { 250302acc2eSNathan Whitehorn case 4: 251302acc2eSNathan Whitehorn { 252302acc2eSNathan Whitehorn uint32_t tbase; 253302acc2eSNathan Whitehorn OF_getprop(child, "timebase-frequency", &tbase, sizeof(tbase)); 254302acc2eSNathan Whitehorn ticks = tbase; 255302acc2eSNathan Whitehorn return (ticks); 256302acc2eSNathan Whitehorn } 257302acc2eSNathan Whitehorn case 8: 258302acc2eSNathan Whitehorn { 259302acc2eSNathan Whitehorn uint64_t tbase; 260302acc2eSNathan Whitehorn OF_getprop(child, "timebase-frequency", &tbase, sizeof(tbase)); 261302acc2eSNathan Whitehorn ticks = tbase; 262302acc2eSNathan Whitehorn return (ticks); 263302acc2eSNathan Whitehorn } 264302acc2eSNathan Whitehorn default: 265302acc2eSNathan Whitehorn break; 266302acc2eSNathan Whitehorn } 267302acc2eSNathan Whitehorn 268302acc2eSNathan Whitehorn freq = 0; 269302acc2eSNathan Whitehorn if (OF_getprop(child, "bus-frequency", (void *)&freq, 270302acc2eSNathan Whitehorn sizeof(freq)) <= 0) 271302acc2eSNathan Whitehorn goto out; 272302acc2eSNathan Whitehorn 2736cedae09SJustin Hibbits if (freq == 0) 2746cedae09SJustin Hibbits goto out; 2756cedae09SJustin Hibbits 276302acc2eSNathan Whitehorn /* 277302acc2eSNathan Whitehorn * Time Base and Decrementer are updated every 8 CCB bus clocks. 278302acc2eSNathan Whitehorn * HID0[SEL_TBCLK] = 0 279302acc2eSNathan Whitehorn */ 2806cedae09SJustin Hibbits if (mpc85xx_is_qoriq()) 2813f068cbfSJustin Hibbits ticks = freq / 32; 2826cedae09SJustin Hibbits else 283302acc2eSNathan Whitehorn ticks = freq / 8; 284302acc2eSNathan Whitehorn 285302acc2eSNathan Whitehorn out: 286302acc2eSNathan Whitehorn if (ticks <= 0) 287302acc2eSNathan Whitehorn panic("Unable to determine timebase frequency!"); 288302acc2eSNathan Whitehorn 289302acc2eSNathan Whitehorn return (ticks); 290302acc2eSNathan Whitehorn } 291302acc2eSNathan Whitehorn 292302acc2eSNathan Whitehorn static int 293302acc2eSNathan Whitehorn mpc85xx_smp_first_cpu(platform_t plat, struct cpuref *cpuref) 294302acc2eSNathan Whitehorn { 295302acc2eSNathan Whitehorn 296302acc2eSNathan Whitehorn cpu = 0; 297302acc2eSNathan Whitehorn cpuref->cr_cpuid = cpu; 298302acc2eSNathan Whitehorn cpuref->cr_hwref = cpuref->cr_cpuid; 299302acc2eSNathan Whitehorn if (bootverbose) 300302acc2eSNathan Whitehorn printf("powerpc_smp_first_cpu: cpuid %d\n", cpuref->cr_cpuid); 301302acc2eSNathan Whitehorn cpu++; 302302acc2eSNathan Whitehorn 303302acc2eSNathan Whitehorn return (0); 304302acc2eSNathan Whitehorn } 305302acc2eSNathan Whitehorn 306302acc2eSNathan Whitehorn static int 307302acc2eSNathan Whitehorn mpc85xx_smp_next_cpu(platform_t plat, struct cpuref *cpuref) 308302acc2eSNathan Whitehorn { 309302acc2eSNathan Whitehorn 310302acc2eSNathan Whitehorn if (cpu >= maxcpu) 311302acc2eSNathan Whitehorn return (ENOENT); 312302acc2eSNathan Whitehorn 313302acc2eSNathan Whitehorn cpuref->cr_cpuid = cpu++; 314302acc2eSNathan Whitehorn cpuref->cr_hwref = cpuref->cr_cpuid; 315302acc2eSNathan Whitehorn if (bootverbose) 316302acc2eSNathan Whitehorn printf("powerpc_smp_next_cpu: cpuid %d\n", cpuref->cr_cpuid); 317302acc2eSNathan Whitehorn 318302acc2eSNathan Whitehorn return (0); 319302acc2eSNathan Whitehorn } 320302acc2eSNathan Whitehorn 321302acc2eSNathan Whitehorn static int 322302acc2eSNathan Whitehorn mpc85xx_smp_get_bsp(platform_t plat, struct cpuref *cpuref) 323302acc2eSNathan Whitehorn { 324302acc2eSNathan Whitehorn 325302acc2eSNathan Whitehorn cpuref->cr_cpuid = mfspr(SPR_PIR); 326302acc2eSNathan Whitehorn cpuref->cr_hwref = cpuref->cr_cpuid; 327302acc2eSNathan Whitehorn 328302acc2eSNathan Whitehorn return (0); 329302acc2eSNathan Whitehorn } 330302acc2eSNathan Whitehorn 331253902b4SJustin Hibbits #ifdef SMP 332253902b4SJustin Hibbits static int 333253902b4SJustin Hibbits mpc85xx_smp_start_cpu_epapr(platform_t plat, struct pcpu *pc) 334253902b4SJustin Hibbits { 335253902b4SJustin Hibbits vm_paddr_t rel_pa, bptr; 336253902b4SJustin Hibbits volatile struct cpu_release *rel; 337253902b4SJustin Hibbits vm_offset_t rel_va, rel_page; 338253902b4SJustin Hibbits phandle_t node; 339253902b4SJustin Hibbits int i; 340253902b4SJustin Hibbits 341253902b4SJustin Hibbits /* If we're calling this, the node already exists. */ 342253902b4SJustin Hibbits node = OF_finddevice("/cpus"); 343253902b4SJustin Hibbits for (i = 0, node = OF_child(node); i < pc->pc_cpuid; 344253902b4SJustin Hibbits i++, node = OF_peer(node)) 345253902b4SJustin Hibbits ; 346253902b4SJustin Hibbits if (OF_getencprop(node, "cpu-release-addr", (pcell_t *)&rel_pa, 347253902b4SJustin Hibbits sizeof(rel_pa)) == -1) { 348253902b4SJustin Hibbits return (ENOENT); 349253902b4SJustin Hibbits } 350253902b4SJustin Hibbits 351253902b4SJustin Hibbits rel_page = kva_alloc(PAGE_SIZE); 352253902b4SJustin Hibbits if (rel_page == 0) 353253902b4SJustin Hibbits return (ENOMEM); 354253902b4SJustin Hibbits 355253902b4SJustin Hibbits critical_enter(); 356253902b4SJustin Hibbits rel_va = rel_page + (rel_pa & PAGE_MASK); 357253902b4SJustin Hibbits pmap_kenter(rel_page, rel_pa & ~PAGE_MASK); 358253902b4SJustin Hibbits rel = (struct cpu_release *)rel_va; 359253902b4SJustin Hibbits bptr = ((vm_paddr_t)(uintptr_t)__boot_page - KERNBASE) + kernload; 360253902b4SJustin Hibbits cpu_flush_dcache(__DEVOLATILE(struct cpu_release *,rel), sizeof(*rel)); 361253902b4SJustin Hibbits rel->pir = pc->pc_cpuid; __asm __volatile("sync"); 362253902b4SJustin Hibbits rel->entry_h = (bptr >> 32); 363253902b4SJustin Hibbits rel->entry_l = bptr; __asm __volatile("sync"); 364253902b4SJustin Hibbits cpu_flush_dcache(__DEVOLATILE(struct cpu_release *,rel), sizeof(*rel)); 365253902b4SJustin Hibbits if (bootverbose) 366253902b4SJustin Hibbits printf("Waking up CPU %d via CPU release page %p\n", 367253902b4SJustin Hibbits pc->pc_cpuid, rel); 368253902b4SJustin Hibbits critical_exit(); 369253902b4SJustin Hibbits pmap_kremove(rel_page); 370253902b4SJustin Hibbits kva_free(rel_page, PAGE_SIZE); 371253902b4SJustin Hibbits 372253902b4SJustin Hibbits return (0); 373253902b4SJustin Hibbits } 374253902b4SJustin Hibbits #endif 375253902b4SJustin Hibbits 376302acc2eSNathan Whitehorn static int 377302acc2eSNathan Whitehorn mpc85xx_smp_start_cpu(platform_t plat, struct pcpu *pc) 378302acc2eSNathan Whitehorn { 379302acc2eSNathan Whitehorn #ifdef SMP 3803f068cbfSJustin Hibbits vm_paddr_t bptr; 3813f068cbfSJustin Hibbits uint32_t reg; 382f60708c9SJustin Hibbits int timeout; 3833f068cbfSJustin Hibbits uintptr_t brr; 3843f068cbfSJustin Hibbits int cpuid; 385253902b4SJustin Hibbits int epapr_boot = 0; 3863f068cbfSJustin Hibbits uint32_t tgt; 3873f068cbfSJustin Hibbits 3886cedae09SJustin Hibbits if (mpc85xx_is_qoriq()) { 3893f068cbfSJustin Hibbits reg = ccsr_read4(OCP85XX_COREDISR); 3903f068cbfSJustin Hibbits cpuid = pc->pc_cpuid; 3913f068cbfSJustin Hibbits 3926cedae09SJustin Hibbits if ((reg & (1 << cpuid)) != 0) { 3933f068cbfSJustin Hibbits printf("%s: CPU %d is disabled!\n", __func__, pc->pc_cpuid); 3943f068cbfSJustin Hibbits return (-1); 3953f068cbfSJustin Hibbits } 3963f068cbfSJustin Hibbits 3973f068cbfSJustin Hibbits brr = OCP85XX_BRR; 3986cedae09SJustin Hibbits } else { 3993f068cbfSJustin Hibbits brr = OCP85XX_EEBPCR; 4003f068cbfSJustin Hibbits cpuid = pc->pc_cpuid + 24; 4016cedae09SJustin Hibbits } 402f60708c9SJustin Hibbits bp_kernload = kernload; 403253902b4SJustin Hibbits /* 404253902b4SJustin Hibbits * bp_kernload is in the boot page. Sync the cache because ePAPR 405253902b4SJustin Hibbits * booting has the other core(s) already running. 406253902b4SJustin Hibbits */ 407*7599d2ddSJustin Hibbits cpu_flush_dcache(&bp_kernload, sizeof(bp_kernload)); 408253902b4SJustin Hibbits 409253902b4SJustin Hibbits ap_pcpu = pc; 410253902b4SJustin Hibbits __asm __volatile("msync; isync"); 411253902b4SJustin Hibbits 412253902b4SJustin Hibbits /* First try the ePAPR way. */ 413253902b4SJustin Hibbits if (mpc85xx_smp_start_cpu_epapr(plat, pc) == 0) { 414253902b4SJustin Hibbits epapr_boot = 1; 415253902b4SJustin Hibbits goto spin_wait; 416253902b4SJustin Hibbits } 4176cedae09SJustin Hibbits 4183f068cbfSJustin Hibbits reg = ccsr_read4(brr); 4193f068cbfSJustin Hibbits if ((reg & (1 << cpuid)) != 0) { 420302acc2eSNathan Whitehorn printf("SMP: CPU %d already out of hold-off state!\n", 421302acc2eSNathan Whitehorn pc->pc_cpuid); 422302acc2eSNathan Whitehorn return (ENXIO); 423302acc2eSNathan Whitehorn } 424302acc2eSNathan Whitehorn 4253f068cbfSJustin Hibbits /* Flush caches to have our changes hit DRAM. */ 4263f068cbfSJustin Hibbits cpu_flush_dcache(__boot_page, 4096); 4273f068cbfSJustin Hibbits 4283f068cbfSJustin Hibbits bptr = ((vm_paddr_t)(uintptr_t)__boot_page - KERNBASE) + kernload; 4293f068cbfSJustin Hibbits KASSERT((bptr & 0xfff) == 0, 4303f068cbfSJustin Hibbits ("%s: boot page is not aligned (%#jx)", __func__, (uintmax_t)bptr)); 4316cedae09SJustin Hibbits if (mpc85xx_is_qoriq()) { 4323f068cbfSJustin Hibbits /* 4333f068cbfSJustin Hibbits * Read DDR controller configuration to select proper BPTR target ID. 4343f068cbfSJustin Hibbits * 4353f068cbfSJustin Hibbits * On P5020 bit 29 of DDR1_CS0_CONFIG enables DDR controllers 4363f068cbfSJustin Hibbits * interleaving. If this bit is set, we have to use 4373f068cbfSJustin Hibbits * OCP85XX_TGTIF_RAM_INTL as BPTR target ID. On other QorIQ DPAA SoCs, 4383f068cbfSJustin Hibbits * this bit is reserved and always 0. 4393f068cbfSJustin Hibbits */ 4403f068cbfSJustin Hibbits 4413f068cbfSJustin Hibbits reg = ccsr_read4(OCP85XX_DDR1_CS0_CONFIG); 4423f068cbfSJustin Hibbits if (reg & (1 << 29)) 4433f068cbfSJustin Hibbits tgt = OCP85XX_TGTIF_RAM_INTL; 4443f068cbfSJustin Hibbits else 4453f068cbfSJustin Hibbits tgt = OCP85XX_TGTIF_RAM1; 4463f068cbfSJustin Hibbits 4473f068cbfSJustin Hibbits /* 4483f068cbfSJustin Hibbits * Set BSTR to the physical address of the boot page 4493f068cbfSJustin Hibbits */ 4503f068cbfSJustin Hibbits ccsr_write4(OCP85XX_BSTRH, bptr >> 32); 4513f068cbfSJustin Hibbits ccsr_write4(OCP85XX_BSTRL, bptr); 4523f068cbfSJustin Hibbits ccsr_write4(OCP85XX_BSTAR, OCP85XX_ENA_MASK | 4536cedae09SJustin Hibbits (tgt << OCP85XX_TRGT_SHIFT_QORIQ) | (ffsl(PAGE_SIZE) - 2)); 4543f068cbfSJustin Hibbits 4553f068cbfSJustin Hibbits /* Read back OCP85XX_BSTAR to synchronize write */ 4563f068cbfSJustin Hibbits ccsr_read4(OCP85XX_BSTAR); 4573f068cbfSJustin Hibbits 4583f068cbfSJustin Hibbits /* 4593f068cbfSJustin Hibbits * Enable and configure time base on new CPU. 4603f068cbfSJustin Hibbits */ 4613f068cbfSJustin Hibbits 4623f068cbfSJustin Hibbits /* Set TB clock source to platform clock / 32 */ 4633f068cbfSJustin Hibbits reg = ccsr_read4(CCSR_CTBCKSELR); 4643f068cbfSJustin Hibbits ccsr_write4(CCSR_CTBCKSELR, reg & ~(1 << pc->pc_cpuid)); 4653f068cbfSJustin Hibbits 4663f068cbfSJustin Hibbits /* Enable TB */ 4673f068cbfSJustin Hibbits reg = ccsr_read4(CCSR_CTBENR); 4683f068cbfSJustin Hibbits ccsr_write4(CCSR_CTBENR, reg | (1 << pc->pc_cpuid)); 4696cedae09SJustin Hibbits } else { 470302acc2eSNathan Whitehorn /* 471302acc2eSNathan Whitehorn * Set BPTR to the physical address of the boot page 472302acc2eSNathan Whitehorn */ 473302acc2eSNathan Whitehorn bptr = (bptr >> 12) | 0x80000000u; 474302acc2eSNathan Whitehorn ccsr_write4(OCP85XX_BPTR, bptr); 475302acc2eSNathan Whitehorn __asm __volatile("isync; msync"); 4766cedae09SJustin Hibbits } 477302acc2eSNathan Whitehorn 478302acc2eSNathan Whitehorn /* 479302acc2eSNathan Whitehorn * Release AP from hold-off state 480302acc2eSNathan Whitehorn */ 4813f068cbfSJustin Hibbits reg = ccsr_read4(brr); 4823f068cbfSJustin Hibbits ccsr_write4(brr, reg | (1 << cpuid)); 483302acc2eSNathan Whitehorn __asm __volatile("isync; msync"); 484302acc2eSNathan Whitehorn 485253902b4SJustin Hibbits spin_wait: 486302acc2eSNathan Whitehorn timeout = 500; 487302acc2eSNathan Whitehorn while (!pc->pc_awake && timeout--) 488302acc2eSNathan Whitehorn DELAY(1000); /* wait 1ms */ 489302acc2eSNathan Whitehorn 490302acc2eSNathan Whitehorn /* 491302acc2eSNathan Whitehorn * Disable boot page translation so that the 4K page at the default 492302acc2eSNathan Whitehorn * address (= 0xfffff000) isn't permanently remapped and thus not 493302acc2eSNathan Whitehorn * usable otherwise. 494302acc2eSNathan Whitehorn */ 495253902b4SJustin Hibbits if (!epapr_boot) { 4966cedae09SJustin Hibbits if (mpc85xx_is_qoriq()) 4973f068cbfSJustin Hibbits ccsr_write4(OCP85XX_BSTAR, 0); 4986cedae09SJustin Hibbits else 499302acc2eSNathan Whitehorn ccsr_write4(OCP85XX_BPTR, 0); 500302acc2eSNathan Whitehorn __asm __volatile("isync; msync"); 501253902b4SJustin Hibbits } 502302acc2eSNathan Whitehorn 503302acc2eSNathan Whitehorn if (!pc->pc_awake) 5046cedae09SJustin Hibbits panic("SMP: CPU %d didn't wake up.\n", pc->pc_cpuid); 505302acc2eSNathan Whitehorn return ((pc->pc_awake) ? 0 : EBUSY); 506302acc2eSNathan Whitehorn #else 507302acc2eSNathan Whitehorn /* No SMP support */ 508302acc2eSNathan Whitehorn return (ENXIO); 509302acc2eSNathan Whitehorn #endif 510302acc2eSNathan Whitehorn } 511302acc2eSNathan Whitehorn 512302acc2eSNathan Whitehorn static void 513302acc2eSNathan Whitehorn mpc85xx_reset(platform_t plat) 514302acc2eSNathan Whitehorn { 515302acc2eSNathan Whitehorn 516302acc2eSNathan Whitehorn /* 517302acc2eSNathan Whitehorn * Try the dedicated reset register first. 518302acc2eSNathan Whitehorn * If the SoC doesn't have one, we'll fall 519302acc2eSNathan Whitehorn * back to using the debug control register. 520302acc2eSNathan Whitehorn */ 521302acc2eSNathan Whitehorn ccsr_write4(OCP85XX_RSTCR, 2); 522302acc2eSNathan Whitehorn 523302acc2eSNathan Whitehorn /* Clear DBCR0, disables debug interrupts and events. */ 524302acc2eSNathan Whitehorn mtspr(SPR_DBCR0, 0); 525302acc2eSNathan Whitehorn __asm __volatile("isync"); 526302acc2eSNathan Whitehorn 527302acc2eSNathan Whitehorn /* Enable Debug Interrupts in MSR. */ 528302acc2eSNathan Whitehorn mtmsr(mfmsr() | PSL_DE); 529302acc2eSNathan Whitehorn 530302acc2eSNathan Whitehorn /* Enable debug interrupts and issue reset. */ 531302acc2eSNathan Whitehorn mtspr(SPR_DBCR0, mfspr(SPR_DBCR0) | DBCR0_IDM | DBCR0_RST_SYSTEM); 532302acc2eSNathan Whitehorn 533302acc2eSNathan Whitehorn printf("Reset failed...\n"); 534302acc2eSNathan Whitehorn while (1) 535302acc2eSNathan Whitehorn ; 536302acc2eSNathan Whitehorn } 537302acc2eSNathan Whitehorn 538637f34cbSJustin Hibbits static void 539637f34cbSJustin Hibbits mpc85xx_idle(platform_t plat, int cpu) 540637f34cbSJustin Hibbits { 541637f34cbSJustin Hibbits uint32_t reg; 542637f34cbSJustin Hibbits 5436cedae09SJustin Hibbits if (mpc85xx_is_qoriq()) { 544637f34cbSJustin Hibbits reg = ccsr_read4(OCP85XX_RCPM_CDOZCR); 545637f34cbSJustin Hibbits ccsr_write4(OCP85XX_RCPM_CDOZCR, reg | (1 << cpu)); 546637f34cbSJustin Hibbits ccsr_read4(OCP85XX_RCPM_CDOZCR); 5476cedae09SJustin Hibbits } else { 5486cedae09SJustin Hibbits reg = mfmsr(); 549637f34cbSJustin Hibbits /* Freescale E500 core RM section 6.4.1. */ 550637f34cbSJustin Hibbits __asm __volatile("msync; mtmsr %0; isync" :: 5516cedae09SJustin Hibbits "r" (reg | PSL_WE)); 5526cedae09SJustin Hibbits } 553637f34cbSJustin Hibbits } 554637f34cbSJustin Hibbits 555637f34cbSJustin Hibbits static int 556637f34cbSJustin Hibbits mpc85xx_idle_wakeup(platform_t plat, int cpu) 557637f34cbSJustin Hibbits { 558637f34cbSJustin Hibbits uint32_t reg; 559637f34cbSJustin Hibbits 5606cedae09SJustin Hibbits if (mpc85xx_is_qoriq()) { 561637f34cbSJustin Hibbits reg = ccsr_read4(OCP85XX_RCPM_CDOZCR); 562637f34cbSJustin Hibbits ccsr_write4(OCP85XX_RCPM_CDOZCR, reg & ~(1 << cpu)); 563637f34cbSJustin Hibbits ccsr_read4(OCP85XX_RCPM_CDOZCR); 564637f34cbSJustin Hibbits 565637f34cbSJustin Hibbits return (1); 5666cedae09SJustin Hibbits } 5676cedae09SJustin Hibbits 568637f34cbSJustin Hibbits return (0); 569637f34cbSJustin Hibbits } 570