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 41262675Sjhibbits#include <machine/altivec.h> /* For save_vec() */ 42192067Snwhitehorn#include <machine/bus.h> 43192067Snwhitehorn#include <machine/cpu.h> 44262675Sjhibbits#include <machine/fpu.h> /* For save_fpu() */ 45192067Snwhitehorn#include <machine/hid.h> 46192067Snwhitehorn#include <machine/platformvar.h> 47198212Snwhitehorn#include <machine/pmap.h> 48262675Sjhibbits#include <machine/setjmp.h> 49192067Snwhitehorn#include <machine/smp.h> 50192067Snwhitehorn#include <machine/spr.h> 51192067Snwhitehorn 52192067Snwhitehorn#include <dev/ofw/openfirm.h> 53192067Snwhitehorn#include <machine/ofw_machdep.h> 54192067Snwhitehorn 55192067Snwhitehorn#include "platform_if.h" 56192067Snwhitehorn 57192067Snwhitehornextern void *ap_pcpu; 58192067Snwhitehorn 59212054Snwhitehornstatic int powermac_probe(platform_t); 60255910Snwhitehornstatic int powermac_attach(platform_t); 61266020Sianvoid powermac_mem_regions(platform_t, struct mem_region *phys, int *physsz, 62266020Sian struct mem_region *avail, int *availsz); 63212054Snwhitehornstatic u_long powermac_timebase_freq(platform_t, struct cpuref *cpuref); 64212054Snwhitehornstatic int powermac_smp_first_cpu(platform_t, struct cpuref *cpuref); 65212054Snwhitehornstatic int powermac_smp_next_cpu(platform_t, struct cpuref *cpuref); 66212054Snwhitehornstatic int powermac_smp_get_bsp(platform_t, struct cpuref *cpuref); 67212054Snwhitehornstatic int powermac_smp_start_cpu(platform_t, struct pcpu *cpu); 68212054Snwhitehornstatic void powermac_reset(platform_t); 69262675Sjhibbitsstatic void powermac_sleep(platform_t); 70192067Snwhitehorn 71212054Snwhitehornstatic platform_method_t powermac_methods[] = { 72212054Snwhitehorn PLATFORMMETHOD(platform_probe, powermac_probe), 73255910Snwhitehorn PLATFORMMETHOD(platform_attach, powermac_attach), 74212054Snwhitehorn PLATFORMMETHOD(platform_mem_regions, powermac_mem_regions), 75212054Snwhitehorn PLATFORMMETHOD(platform_timebase_freq, powermac_timebase_freq), 76192067Snwhitehorn 77212054Snwhitehorn PLATFORMMETHOD(platform_smp_first_cpu, powermac_smp_first_cpu), 78212054Snwhitehorn PLATFORMMETHOD(platform_smp_next_cpu, powermac_smp_next_cpu), 79212054Snwhitehorn PLATFORMMETHOD(platform_smp_get_bsp, powermac_smp_get_bsp), 80212054Snwhitehorn PLATFORMMETHOD(platform_smp_start_cpu, powermac_smp_start_cpu), 81192067Snwhitehorn 82212054Snwhitehorn PLATFORMMETHOD(platform_reset, powermac_reset), 83262675Sjhibbits PLATFORMMETHOD(platform_sleep, powermac_sleep), 84212054Snwhitehorn 85246732Srpaulo PLATFORMMETHOD_END 86192067Snwhitehorn}; 87192067Snwhitehorn 88212054Snwhitehornstatic platform_def_t powermac_platform = { 89212054Snwhitehorn "powermac", 90212054Snwhitehorn powermac_methods, 91192067Snwhitehorn 0 92192067Snwhitehorn}; 93192067Snwhitehorn 94212054SnwhitehornPLATFORM_DEF(powermac_platform); 95192067Snwhitehorn 96192067Snwhitehornstatic int 97212054Snwhitehornpowermac_probe(platform_t plat) 98192067Snwhitehorn{ 99255420Snwhitehorn char compat[255]; 100255420Snwhitehorn ssize_t compatlen; 101255420Snwhitehorn char *curstr; 102255420Snwhitehorn phandle_t root; 103192067Snwhitehorn 104255420Snwhitehorn root = OF_peer(0); 105255420Snwhitehorn if (root == 0) 106255420Snwhitehorn return (ENXIO); 107255420Snwhitehorn 108255420Snwhitehorn compatlen = OF_getprop(root, "compatible", compat, sizeof(compat)); 109255420Snwhitehorn 110255420Snwhitehorn for (curstr = compat; curstr < compat + compatlen; 111255420Snwhitehorn curstr += strlen(curstr) + 1) { 112255420Snwhitehorn if (strncmp(curstr, "MacRISC", 7) == 0) 113255420Snwhitehorn return (BUS_PROBE_SPECIFIC); 114255420Snwhitehorn } 115255420Snwhitehorn 116192067Snwhitehorn return (ENXIO); 117192067Snwhitehorn} 118192067Snwhitehorn 119192067Snwhitehornvoid 120266020Sianpowermac_mem_regions(platform_t plat, struct mem_region *phys, int *physsz, 121266020Sian struct mem_region *avail, int *availsz) 122192067Snwhitehorn{ 123266020Sian phandle_t memory; 124266020Sian cell_t memoryprop[PHYS_AVAIL_SZ * 2]; 125266020Sian ssize_t propsize, i, j; 126266020Sian int physacells = 1; 127266020Sian 128266020Sian memory = OF_finddevice("/memory"); 129266020Sian 130266020Sian /* "reg" has variable #address-cells, but #size-cells is always 1 */ 131266020Sian OF_getprop(OF_parent(memory), "#address-cells", &physacells, 132266020Sian sizeof(physacells)); 133266020Sian 134266020Sian propsize = OF_getprop(memory, "reg", memoryprop, sizeof(memoryprop)); 135266020Sian propsize /= sizeof(cell_t); 136266020Sian for (i = 0, j = 0; i < propsize; i += physacells+1, j++) { 137266020Sian phys[j].mr_start = memoryprop[i]; 138266020Sian if (physacells == 2) { 139266020Sian#ifndef __powerpc64__ 140266020Sian /* On 32-bit PPC, ignore regions starting above 4 GB */ 141266020Sian if (memoryprop[i] != 0) { 142266020Sian j--; 143266020Sian continue; 144266020Sian } 145266020Sian#else 146266020Sian phys[j].mr_start <<= 32; 147266020Sian#endif 148266020Sian phys[j].mr_start |= memoryprop[i+1]; 149266020Sian } 150266020Sian phys[j].mr_size = memoryprop[i + physacells]; 151266020Sian } 152266020Sian *physsz = j; 153266020Sian 154266020Sian /* "available" always has #address-cells = 1 */ 155266020Sian propsize = OF_getprop(memory, "available", memoryprop, 156266020Sian sizeof(memoryprop)); 157266020Sian propsize /= sizeof(cell_t); 158266020Sian for (i = 0, j = 0; i < propsize; i += 2, j++) { 159266020Sian avail[j].mr_start = memoryprop[i]; 160266020Sian avail[j].mr_size = memoryprop[i + 1]; 161266020Sian } 162266020Sian 163266020Sian#ifdef __powerpc64__ 164266020Sian /* Add in regions above 4 GB to the available list */ 165266020Sian for (i = 0; i < *physsz; i++) { 166266020Sian if (phys[i].mr_start > BUS_SPACE_MAXADDR_32BIT) { 167266020Sian avail[j].mr_start = phys[i].mr_start; 168266020Sian avail[j].mr_size = phys[i].mr_size; 169266020Sian j++; 170266020Sian } 171266020Sian } 172266020Sian#endif 173266020Sian *availsz = j; 174192067Snwhitehorn} 175192067Snwhitehorn 176255910Snwhitehornstatic int 177255910Snwhitehornpowermac_attach(platform_t plat) 178255910Snwhitehorn{ 179255910Snwhitehorn phandle_t rootnode; 180255910Snwhitehorn char model[32]; 181255910Snwhitehorn 182255910Snwhitehorn 183255910Snwhitehorn /* 184255910Snwhitehorn * Quiesce Open Firmware on PowerMac11,2 and 12,1. It is 185255910Snwhitehorn * necessary there to shut down a background thread doing fan 186255910Snwhitehorn * management, and is harmful on other machines (it will make OF 187255910Snwhitehorn * shut off power to various system components it had turned on). 188255910Snwhitehorn * 189255910Snwhitehorn * Note: we don't need to worry about which OF module we are 190255910Snwhitehorn * using since this is called only from very early boot, within 191255910Snwhitehorn * OF's boot context. 192255910Snwhitehorn */ 193255910Snwhitehorn 194255910Snwhitehorn rootnode = OF_finddevice("/"); 195255910Snwhitehorn if (OF_getprop(rootnode, "model", model, sizeof(model)) > 0) { 196255910Snwhitehorn if (strcmp(model, "PowerMac11,2") == 0 || 197255910Snwhitehorn strcmp(model, "PowerMac12,1") == 0) { 198255910Snwhitehorn ofw_quiesce(); 199255910Snwhitehorn } 200255910Snwhitehorn } 201255910Snwhitehorn 202255910Snwhitehorn return (0); 203255910Snwhitehorn} 204255910Snwhitehorn 205192067Snwhitehornstatic u_long 206212054Snwhitehornpowermac_timebase_freq(platform_t plat, struct cpuref *cpuref) 207192067Snwhitehorn{ 208192067Snwhitehorn phandle_t phandle; 209209851Snwhitehorn int32_t ticks = -1; 210192067Snwhitehorn 211192067Snwhitehorn phandle = cpuref->cr_hwref; 212192067Snwhitehorn 213192067Snwhitehorn OF_getprop(phandle, "timebase-frequency", &ticks, sizeof(ticks)); 214192067Snwhitehorn 215192067Snwhitehorn if (ticks <= 0) 216192067Snwhitehorn panic("Unable to determine timebase frequency!"); 217192067Snwhitehorn 218192067Snwhitehorn return (ticks); 219192067Snwhitehorn} 220192067Snwhitehorn 221192067Snwhitehorn 222192067Snwhitehornstatic int 223212054Snwhitehornpowermac_smp_fill_cpuref(struct cpuref *cpuref, phandle_t cpu) 224192067Snwhitehorn{ 225260673Sjhibbits cell_t cpuid; 226260673Sjhibbits int res; 227192067Snwhitehorn 228192067Snwhitehorn cpuref->cr_hwref = cpu; 229192067Snwhitehorn res = OF_getprop(cpu, "reg", &cpuid, sizeof(cpuid)); 230192067Snwhitehorn 231193909Sgrehan /* 232193909Sgrehan * psim doesn't have a reg property, so assume 0 as for the 233193909Sgrehan * uniprocessor case in the CHRP spec. 234193909Sgrehan */ 235193909Sgrehan if (res < 0) { 236193909Sgrehan cpuid = 0; 237193909Sgrehan } 238193909Sgrehan 239192067Snwhitehorn cpuref->cr_cpuid = cpuid & 0xff; 240192067Snwhitehorn return (0); 241192067Snwhitehorn} 242192067Snwhitehorn 243192067Snwhitehornstatic int 244212054Snwhitehornpowermac_smp_first_cpu(platform_t plat, struct cpuref *cpuref) 245192067Snwhitehorn{ 246192067Snwhitehorn char buf[8]; 247192067Snwhitehorn phandle_t cpu, dev, root; 248192067Snwhitehorn int res; 249192067Snwhitehorn 250192067Snwhitehorn root = OF_peer(0); 251192067Snwhitehorn 252192067Snwhitehorn dev = OF_child(root); 253192067Snwhitehorn while (dev != 0) { 254192067Snwhitehorn res = OF_getprop(dev, "name", buf, sizeof(buf)); 255192067Snwhitehorn if (res > 0 && strcmp(buf, "cpus") == 0) 256192067Snwhitehorn break; 257192067Snwhitehorn dev = OF_peer(dev); 258192067Snwhitehorn } 259193909Sgrehan if (dev == 0) { 260193909Sgrehan /* 261193909Sgrehan * psim doesn't have a name property on the /cpus node, 262193909Sgrehan * but it can be found directly 263193909Sgrehan */ 264193909Sgrehan dev = OF_finddevice("/cpus"); 265228201Sjchandra if (dev == -1) 266193909Sgrehan return (ENOENT); 267193909Sgrehan } 268192067Snwhitehorn 269192067Snwhitehorn cpu = OF_child(dev); 270193909Sgrehan 271192067Snwhitehorn while (cpu != 0) { 272192067Snwhitehorn res = OF_getprop(cpu, "device_type", buf, sizeof(buf)); 273192067Snwhitehorn if (res > 0 && strcmp(buf, "cpu") == 0) 274192067Snwhitehorn break; 275192067Snwhitehorn cpu = OF_peer(cpu); 276192067Snwhitehorn } 277192067Snwhitehorn if (cpu == 0) 278192067Snwhitehorn return (ENOENT); 279192067Snwhitehorn 280212054Snwhitehorn return (powermac_smp_fill_cpuref(cpuref, cpu)); 281192067Snwhitehorn} 282192067Snwhitehorn 283192067Snwhitehornstatic int 284212054Snwhitehornpowermac_smp_next_cpu(platform_t plat, struct cpuref *cpuref) 285192067Snwhitehorn{ 286192067Snwhitehorn char buf[8]; 287192067Snwhitehorn phandle_t cpu; 288192067Snwhitehorn int res; 289192067Snwhitehorn 290192067Snwhitehorn cpu = OF_peer(cpuref->cr_hwref); 291192067Snwhitehorn while (cpu != 0) { 292192067Snwhitehorn res = OF_getprop(cpu, "device_type", buf, sizeof(buf)); 293192067Snwhitehorn if (res > 0 && strcmp(buf, "cpu") == 0) 294192067Snwhitehorn break; 295192067Snwhitehorn cpu = OF_peer(cpu); 296192067Snwhitehorn } 297192067Snwhitehorn if (cpu == 0) 298192067Snwhitehorn return (ENOENT); 299192067Snwhitehorn 300212054Snwhitehorn return (powermac_smp_fill_cpuref(cpuref, cpu)); 301192067Snwhitehorn} 302192067Snwhitehorn 303192067Snwhitehornstatic int 304212054Snwhitehornpowermac_smp_get_bsp(platform_t plat, struct cpuref *cpuref) 305192067Snwhitehorn{ 306192067Snwhitehorn ihandle_t inst; 307192067Snwhitehorn phandle_t bsp, chosen; 308192067Snwhitehorn int res; 309192067Snwhitehorn 310192067Snwhitehorn chosen = OF_finddevice("/chosen"); 311228201Sjchandra if (chosen == -1) 312192067Snwhitehorn return (ENXIO); 313192067Snwhitehorn 314192067Snwhitehorn res = OF_getprop(chosen, "cpu", &inst, sizeof(inst)); 315192067Snwhitehorn if (res < 0) 316192067Snwhitehorn return (ENXIO); 317192067Snwhitehorn 318192067Snwhitehorn bsp = OF_instance_to_package(inst); 319212054Snwhitehorn return (powermac_smp_fill_cpuref(cpuref, bsp)); 320192067Snwhitehorn} 321192067Snwhitehorn 322192067Snwhitehornstatic int 323212054Snwhitehornpowermac_smp_start_cpu(platform_t plat, struct pcpu *pc) 324192067Snwhitehorn{ 325192067Snwhitehorn#ifdef SMP 326192067Snwhitehorn phandle_t cpu; 327192067Snwhitehorn volatile uint8_t *rstvec; 328198212Snwhitehorn static volatile uint8_t *rstvec_virtbase = NULL; 329192067Snwhitehorn int res, reset, timeout; 330192067Snwhitehorn 331192067Snwhitehorn cpu = pc->pc_hwref; 332192067Snwhitehorn res = OF_getprop(cpu, "soft-reset", &reset, sizeof(reset)); 333209114Snwhitehorn if (res < 0) { 334209114Snwhitehorn reset = 0x58; 335192067Snwhitehorn 336209114Snwhitehorn switch (pc->pc_cpuid) { 337209114Snwhitehorn case 0: 338209114Snwhitehorn reset += 0x03; 339209114Snwhitehorn break; 340209114Snwhitehorn case 1: 341209114Snwhitehorn reset += 0x04; 342209114Snwhitehorn break; 343209114Snwhitehorn case 2: 344209114Snwhitehorn reset += 0x0f; 345209114Snwhitehorn break; 346209853Snwhitehorn case 3: 347209114Snwhitehorn reset += 0x10; 348209114Snwhitehorn break; 349209114Snwhitehorn default: 350209114Snwhitehorn return (ENXIO); 351209114Snwhitehorn } 352209114Snwhitehorn } 353209114Snwhitehorn 354192067Snwhitehorn ap_pcpu = pc; 355192067Snwhitehorn 356198212Snwhitehorn if (rstvec_virtbase == NULL) 357198212Snwhitehorn rstvec_virtbase = pmap_mapdev(0x80000000, PAGE_SIZE); 358192067Snwhitehorn 359198212Snwhitehorn rstvec = rstvec_virtbase + reset; 360198212Snwhitehorn 361192067Snwhitehorn *rstvec = 4; 362209114Snwhitehorn powerpc_sync(); 363198378Snwhitehorn (void)(*rstvec); 364192067Snwhitehorn powerpc_sync(); 365192067Snwhitehorn DELAY(1); 366192067Snwhitehorn *rstvec = 0; 367209114Snwhitehorn powerpc_sync(); 368198378Snwhitehorn (void)(*rstvec); 369192067Snwhitehorn powerpc_sync(); 370192067Snwhitehorn 371198378Snwhitehorn timeout = 10000; 372192067Snwhitehorn while (!pc->pc_awake && timeout--) 373192067Snwhitehorn DELAY(100); 374192067Snwhitehorn 375192067Snwhitehorn return ((pc->pc_awake) ? 0 : EBUSY); 376192067Snwhitehorn#else 377192067Snwhitehorn /* No SMP support */ 378192067Snwhitehorn return (ENXIO); 379192067Snwhitehorn#endif 380192067Snwhitehorn} 381192067Snwhitehorn 382212054Snwhitehornstatic void 383212054Snwhitehornpowermac_reset(platform_t platform) 384212054Snwhitehorn{ 385212054Snwhitehorn OF_reboot(); 386212054Snwhitehorn} 387212054Snwhitehorn 388262675Sjhibbitsvoid 389262675Sjhibbitspowermac_sleep(platform_t platform) 390262675Sjhibbits{ 391262675Sjhibbits 392262675Sjhibbits *(unsigned long *)0x80 = 0x100; 393262675Sjhibbits cpu_sleep(); 394262675Sjhibbits} 395262675Sjhibbits 396