1192067Snwhitehorn/*- 2192067Snwhitehorn * Copyright (c) 2008 Marcel Moolenaar 3192067Snwhitehorn * Copyright (c) 2009 Nathan Whitehorn 4192067Snwhitehorn * All rights reserved. 5192067Snwhitehorn * 6192067Snwhitehorn * Redistribution and use in source and binary forms, with or without 7192067Snwhitehorn * modification, are permitted provided that the following conditions 8192067Snwhitehorn * are met: 9192067Snwhitehorn * 10192067Snwhitehorn * 1. Redistributions of source code must retain the above copyright 11192067Snwhitehorn * notice, this list of conditions and the following disclaimer. 12192067Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright 13192067Snwhitehorn * notice, this list of conditions and the following disclaimer in the 14192067Snwhitehorn * documentation and/or other materials provided with the distribution. 15192067Snwhitehorn * 16192067Snwhitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17192067Snwhitehorn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18192067Snwhitehorn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19192067Snwhitehorn * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20192067Snwhitehorn * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21192067Snwhitehorn * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22192067Snwhitehorn * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23192067Snwhitehorn * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24192067Snwhitehorn * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25192067Snwhitehorn * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26192067Snwhitehorn */ 27192067Snwhitehorn 28192067Snwhitehorn#include <sys/cdefs.h> 29192067Snwhitehorn__FBSDID("$FreeBSD$"); 30192067Snwhitehorn 31192067Snwhitehorn#include <sys/param.h> 32192067Snwhitehorn#include <sys/systm.h> 33192067Snwhitehorn#include <sys/kernel.h> 34192067Snwhitehorn#include <sys/bus.h> 35192067Snwhitehorn#include <sys/pcpu.h> 36192067Snwhitehorn#include <sys/proc.h> 37192067Snwhitehorn#include <sys/smp.h> 38198212Snwhitehorn#include <vm/vm.h> 39198212Snwhitehorn#include <vm/pmap.h> 40192067Snwhitehorn 41192067Snwhitehorn#include <machine/bus.h> 42192067Snwhitehorn#include <machine/cpu.h> 43192067Snwhitehorn#include <machine/hid.h> 44192067Snwhitehorn#include <machine/platformvar.h> 45198212Snwhitehorn#include <machine/pmap.h> 46192067Snwhitehorn#include <machine/smp.h> 47192067Snwhitehorn#include <machine/spr.h> 48192067Snwhitehorn 49192067Snwhitehorn#include <dev/ofw/openfirm.h> 50192067Snwhitehorn#include <machine/ofw_machdep.h> 51192067Snwhitehorn 52192067Snwhitehorn#include "platform_if.h" 53192067Snwhitehorn 54192067Snwhitehorn#ifdef SMP 55192067Snwhitehornextern void *ap_pcpu; 56192067Snwhitehorn#endif 57192067Snwhitehorn 58212054Snwhitehornstatic int powermac_probe(platform_t); 59212054Snwhitehornvoid powermac_mem_regions(platform_t, struct mem_region **phys, int *physsz, 60192067Snwhitehorn struct mem_region **avail, int *availsz); 61212054Snwhitehornstatic u_long powermac_timebase_freq(platform_t, struct cpuref *cpuref); 62212054Snwhitehornstatic int powermac_smp_first_cpu(platform_t, struct cpuref *cpuref); 63212054Snwhitehornstatic int powermac_smp_next_cpu(platform_t, struct cpuref *cpuref); 64212054Snwhitehornstatic int powermac_smp_get_bsp(platform_t, struct cpuref *cpuref); 65212054Snwhitehornstatic int powermac_smp_start_cpu(platform_t, struct pcpu *cpu); 66212054Snwhitehornstatic void powermac_reset(platform_t); 67192067Snwhitehorn 68212054Snwhitehornstatic platform_method_t powermac_methods[] = { 69212054Snwhitehorn PLATFORMMETHOD(platform_probe, powermac_probe), 70212054Snwhitehorn PLATFORMMETHOD(platform_mem_regions, powermac_mem_regions), 71212054Snwhitehorn PLATFORMMETHOD(platform_timebase_freq, powermac_timebase_freq), 72192067Snwhitehorn 73212054Snwhitehorn PLATFORMMETHOD(platform_smp_first_cpu, powermac_smp_first_cpu), 74212054Snwhitehorn PLATFORMMETHOD(platform_smp_next_cpu, powermac_smp_next_cpu), 75212054Snwhitehorn PLATFORMMETHOD(platform_smp_get_bsp, powermac_smp_get_bsp), 76212054Snwhitehorn PLATFORMMETHOD(platform_smp_start_cpu, powermac_smp_start_cpu), 77192067Snwhitehorn 78212054Snwhitehorn PLATFORMMETHOD(platform_reset, powermac_reset), 79212054Snwhitehorn 80192067Snwhitehorn { 0, 0 } 81192067Snwhitehorn}; 82192067Snwhitehorn 83212054Snwhitehornstatic platform_def_t powermac_platform = { 84212054Snwhitehorn "powermac", 85212054Snwhitehorn powermac_methods, 86192067Snwhitehorn 0 87192067Snwhitehorn}; 88192067Snwhitehorn 89212054SnwhitehornPLATFORM_DEF(powermac_platform); 90192067Snwhitehorn 91192067Snwhitehornstatic int 92212054Snwhitehornpowermac_probe(platform_t plat) 93192067Snwhitehorn{ 94209851Snwhitehorn if (OF_finddevice("/memory") != -1 || OF_finddevice("/memory@0") != -1) 95192067Snwhitehorn return (BUS_PROBE_GENERIC); 96192067Snwhitehorn 97192067Snwhitehorn return (ENXIO); 98192067Snwhitehorn} 99192067Snwhitehorn 100192067Snwhitehornvoid 101212054Snwhitehornpowermac_mem_regions(platform_t plat, struct mem_region **phys, int *physsz, 102192067Snwhitehorn struct mem_region **avail, int *availsz) 103192067Snwhitehorn{ 104192067Snwhitehorn ofw_mem_regions(phys,physsz,avail,availsz); 105192067Snwhitehorn} 106192067Snwhitehorn 107192067Snwhitehornstatic u_long 108212054Snwhitehornpowermac_timebase_freq(platform_t plat, struct cpuref *cpuref) 109192067Snwhitehorn{ 110192067Snwhitehorn phandle_t phandle; 111209851Snwhitehorn int32_t ticks = -1; 112192067Snwhitehorn 113192067Snwhitehorn phandle = cpuref->cr_hwref; 114192067Snwhitehorn 115192067Snwhitehorn OF_getprop(phandle, "timebase-frequency", &ticks, sizeof(ticks)); 116192067Snwhitehorn 117192067Snwhitehorn if (ticks <= 0) 118192067Snwhitehorn panic("Unable to determine timebase frequency!"); 119192067Snwhitehorn 120192067Snwhitehorn return (ticks); 121192067Snwhitehorn} 122192067Snwhitehorn 123192067Snwhitehorn 124192067Snwhitehornstatic int 125212054Snwhitehornpowermac_smp_fill_cpuref(struct cpuref *cpuref, phandle_t cpu) 126192067Snwhitehorn{ 127209851Snwhitehorn cell_t cpuid, res; 128192067Snwhitehorn 129192067Snwhitehorn cpuref->cr_hwref = cpu; 130192067Snwhitehorn res = OF_getprop(cpu, "reg", &cpuid, sizeof(cpuid)); 131192067Snwhitehorn 132193909Sgrehan /* 133193909Sgrehan * psim doesn't have a reg property, so assume 0 as for the 134193909Sgrehan * uniprocessor case in the CHRP spec. 135193909Sgrehan */ 136193909Sgrehan if (res < 0) { 137193909Sgrehan cpuid = 0; 138193909Sgrehan } 139193909Sgrehan 140192067Snwhitehorn cpuref->cr_cpuid = cpuid & 0xff; 141192067Snwhitehorn return (0); 142192067Snwhitehorn} 143192067Snwhitehorn 144192067Snwhitehornstatic int 145212054Snwhitehornpowermac_smp_first_cpu(platform_t plat, struct cpuref *cpuref) 146192067Snwhitehorn{ 147192067Snwhitehorn char buf[8]; 148192067Snwhitehorn phandle_t cpu, dev, root; 149192067Snwhitehorn int res; 150192067Snwhitehorn 151192067Snwhitehorn root = OF_peer(0); 152192067Snwhitehorn 153192067Snwhitehorn dev = OF_child(root); 154192067Snwhitehorn while (dev != 0) { 155192067Snwhitehorn res = OF_getprop(dev, "name", buf, sizeof(buf)); 156192067Snwhitehorn if (res > 0 && strcmp(buf, "cpus") == 0) 157192067Snwhitehorn break; 158192067Snwhitehorn dev = OF_peer(dev); 159192067Snwhitehorn } 160193909Sgrehan if (dev == 0) { 161193909Sgrehan /* 162193909Sgrehan * psim doesn't have a name property on the /cpus node, 163193909Sgrehan * but it can be found directly 164193909Sgrehan */ 165193909Sgrehan dev = OF_finddevice("/cpus"); 166193909Sgrehan if (dev == 0) 167193909Sgrehan return (ENOENT); 168193909Sgrehan } 169192067Snwhitehorn 170192067Snwhitehorn cpu = OF_child(dev); 171193909Sgrehan 172192067Snwhitehorn while (cpu != 0) { 173192067Snwhitehorn res = OF_getprop(cpu, "device_type", buf, sizeof(buf)); 174192067Snwhitehorn if (res > 0 && strcmp(buf, "cpu") == 0) 175192067Snwhitehorn break; 176192067Snwhitehorn cpu = OF_peer(cpu); 177192067Snwhitehorn } 178192067Snwhitehorn if (cpu == 0) 179192067Snwhitehorn return (ENOENT); 180192067Snwhitehorn 181212054Snwhitehorn return (powermac_smp_fill_cpuref(cpuref, cpu)); 182192067Snwhitehorn} 183192067Snwhitehorn 184192067Snwhitehornstatic int 185212054Snwhitehornpowermac_smp_next_cpu(platform_t plat, struct cpuref *cpuref) 186192067Snwhitehorn{ 187192067Snwhitehorn char buf[8]; 188192067Snwhitehorn phandle_t cpu; 189192067Snwhitehorn int res; 190192067Snwhitehorn 191192067Snwhitehorn cpu = OF_peer(cpuref->cr_hwref); 192192067Snwhitehorn while (cpu != 0) { 193192067Snwhitehorn res = OF_getprop(cpu, "device_type", buf, sizeof(buf)); 194192067Snwhitehorn if (res > 0 && strcmp(buf, "cpu") == 0) 195192067Snwhitehorn break; 196192067Snwhitehorn cpu = OF_peer(cpu); 197192067Snwhitehorn } 198192067Snwhitehorn if (cpu == 0) 199192067Snwhitehorn return (ENOENT); 200192067Snwhitehorn 201212054Snwhitehorn return (powermac_smp_fill_cpuref(cpuref, cpu)); 202192067Snwhitehorn} 203192067Snwhitehorn 204192067Snwhitehornstatic int 205212054Snwhitehornpowermac_smp_get_bsp(platform_t plat, struct cpuref *cpuref) 206192067Snwhitehorn{ 207192067Snwhitehorn ihandle_t inst; 208192067Snwhitehorn phandle_t bsp, chosen; 209192067Snwhitehorn int res; 210192067Snwhitehorn 211192067Snwhitehorn chosen = OF_finddevice("/chosen"); 212192067Snwhitehorn if (chosen == 0) 213192067Snwhitehorn return (ENXIO); 214192067Snwhitehorn 215192067Snwhitehorn res = OF_getprop(chosen, "cpu", &inst, sizeof(inst)); 216192067Snwhitehorn if (res < 0) 217192067Snwhitehorn return (ENXIO); 218192067Snwhitehorn 219192067Snwhitehorn bsp = OF_instance_to_package(inst); 220212054Snwhitehorn return (powermac_smp_fill_cpuref(cpuref, bsp)); 221192067Snwhitehorn} 222192067Snwhitehorn 223192067Snwhitehornstatic int 224212054Snwhitehornpowermac_smp_start_cpu(platform_t plat, struct pcpu *pc) 225192067Snwhitehorn{ 226192067Snwhitehorn#ifdef SMP 227192067Snwhitehorn phandle_t cpu; 228192067Snwhitehorn volatile uint8_t *rstvec; 229198212Snwhitehorn static volatile uint8_t *rstvec_virtbase = NULL; 230192067Snwhitehorn int res, reset, timeout; 231192067Snwhitehorn 232192067Snwhitehorn cpu = pc->pc_hwref; 233192067Snwhitehorn res = OF_getprop(cpu, "soft-reset", &reset, sizeof(reset)); 234209114Snwhitehorn if (res < 0) { 235209114Snwhitehorn reset = 0x58; 236192067Snwhitehorn 237209114Snwhitehorn switch (pc->pc_cpuid) { 238209114Snwhitehorn case 0: 239209114Snwhitehorn reset += 0x03; 240209114Snwhitehorn break; 241209114Snwhitehorn case 1: 242209114Snwhitehorn reset += 0x04; 243209114Snwhitehorn break; 244209114Snwhitehorn case 2: 245209114Snwhitehorn reset += 0x0f; 246209114Snwhitehorn break; 247209853Snwhitehorn case 3: 248209114Snwhitehorn reset += 0x10; 249209114Snwhitehorn break; 250209114Snwhitehorn default: 251209114Snwhitehorn return (ENXIO); 252209114Snwhitehorn } 253209114Snwhitehorn } 254209114Snwhitehorn 255192067Snwhitehorn ap_pcpu = pc; 256192067Snwhitehorn 257198212Snwhitehorn if (rstvec_virtbase == NULL) 258198212Snwhitehorn rstvec_virtbase = pmap_mapdev(0x80000000, PAGE_SIZE); 259192067Snwhitehorn 260198212Snwhitehorn rstvec = rstvec_virtbase + reset; 261198212Snwhitehorn 262192067Snwhitehorn *rstvec = 4; 263209114Snwhitehorn powerpc_sync(); 264198378Snwhitehorn (void)(*rstvec); 265192067Snwhitehorn powerpc_sync(); 266192067Snwhitehorn DELAY(1); 267192067Snwhitehorn *rstvec = 0; 268209114Snwhitehorn powerpc_sync(); 269198378Snwhitehorn (void)(*rstvec); 270192067Snwhitehorn powerpc_sync(); 271192067Snwhitehorn 272198378Snwhitehorn timeout = 10000; 273192067Snwhitehorn while (!pc->pc_awake && timeout--) 274192067Snwhitehorn DELAY(100); 275192067Snwhitehorn 276192067Snwhitehorn return ((pc->pc_awake) ? 0 : EBUSY); 277192067Snwhitehorn#else 278192067Snwhitehorn /* No SMP support */ 279192067Snwhitehorn return (ENXIO); 280192067Snwhitehorn#endif 281192067Snwhitehorn} 282192067Snwhitehorn 283212054Snwhitehornstatic void 284212054Snwhitehornpowermac_reset(platform_t platform) 285212054Snwhitehorn{ 286212054Snwhitehorn OF_reboot(); 287212054Snwhitehorn} 288212054Snwhitehorn 289