1192067Snwhitehorn/*- 2192067Snwhitehorn * Copyright (c) 2008-2009 Semihalf, Rafal Jaworowski 3192067Snwhitehorn * All rights reserved. 4192067Snwhitehorn * 5192067Snwhitehorn * Redistribution and use in source and binary forms, with or without 6192067Snwhitehorn * modification, are permitted provided that the following conditions 7192067Snwhitehorn * are met: 8192067Snwhitehorn * 9192067Snwhitehorn * 1. Redistributions of source code must retain the above copyright 10192067Snwhitehorn * notice, this list of conditions and the following disclaimer. 11192067Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright 12192067Snwhitehorn * notice, this list of conditions and the following disclaimer in the 13192067Snwhitehorn * documentation and/or other materials provided with the distribution. 14192067Snwhitehorn * 15192067Snwhitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16192067Snwhitehorn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17192067Snwhitehorn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18192067Snwhitehorn * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19192067Snwhitehorn * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20192067Snwhitehorn * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21192067Snwhitehorn * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22192067Snwhitehorn * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23192067Snwhitehorn * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24192067Snwhitehorn * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25192067Snwhitehorn */ 26192067Snwhitehorn 27192067Snwhitehorn#include <sys/cdefs.h> 28192067Snwhitehorn__FBSDID("$FreeBSD$"); 29192067Snwhitehorn 30192067Snwhitehorn#include <sys/param.h> 31192067Snwhitehorn#include <sys/systm.h> 32192067Snwhitehorn#include <sys/kernel.h> 33192067Snwhitehorn#include <sys/bus.h> 34192067Snwhitehorn#include <sys/pcpu.h> 35192067Snwhitehorn#include <sys/proc.h> 36192067Snwhitehorn#include <sys/smp.h> 37192067Snwhitehorn 38192067Snwhitehorn#include <machine/bus.h> 39192067Snwhitehorn#include <machine/cpu.h> 40192067Snwhitehorn#include <machine/hid.h> 41192067Snwhitehorn#include <machine/platform.h> 42192067Snwhitehorn#include <machine/platformvar.h> 43192067Snwhitehorn#include <machine/smp.h> 44192067Snwhitehorn#include <machine/spr.h> 45192067Snwhitehorn#include <machine/vmparam.h> 46192067Snwhitehorn 47209908Sraj#include <dev/fdt/fdt_common.h> 48209908Sraj#include <dev/ofw/ofw_bus.h> 49209908Sraj#include <dev/ofw/ofw_bus_subr.h> 50209908Sraj#include <dev/ofw/openfirm.h> 51209908Sraj 52192067Snwhitehorn#include <powerpc/mpc85xx/mpc85xx.h> 53192067Snwhitehorn 54192067Snwhitehorn#include "platform_if.h" 55192067Snwhitehorn 56192532Sraj#ifdef SMP 57192532Srajextern void *ap_pcpu; 58192532Srajextern uint8_t __boot_page[]; /* Boot page body */ 59224611Smarcelextern uint32_t kernload_ap; /* Kernel physical load address */ 60192532Sraj#endif 61192532Sraj 62217523Smarcelextern uint32_t *bootinfo; 63217523Smarcel 64193492Srajstatic int cpu, maxcpu; 65192067Snwhitehorn 66192067Snwhitehornstatic int bare_probe(platform_t); 67192067Snwhitehornstatic void bare_mem_regions(platform_t, struct mem_region **phys, int *physsz, 68192067Snwhitehorn struct mem_region **avail, int *availsz); 69192067Snwhitehornstatic u_long bare_timebase_freq(platform_t, struct cpuref *cpuref); 70192067Snwhitehornstatic int bare_smp_first_cpu(platform_t, struct cpuref *cpuref); 71192067Snwhitehornstatic int bare_smp_next_cpu(platform_t, struct cpuref *cpuref); 72192067Snwhitehornstatic int bare_smp_get_bsp(platform_t, struct cpuref *cpuref); 73192067Snwhitehornstatic int bare_smp_start_cpu(platform_t, struct pcpu *cpu); 74192067Snwhitehorn 75212054Snwhitehornstatic void e500_reset(platform_t); 76212054Snwhitehorn 77192067Snwhitehornstatic platform_method_t bare_methods[] = { 78192067Snwhitehorn PLATFORMMETHOD(platform_probe, bare_probe), 79192067Snwhitehorn PLATFORMMETHOD(platform_mem_regions, bare_mem_regions), 80192067Snwhitehorn PLATFORMMETHOD(platform_timebase_freq, bare_timebase_freq), 81192067Snwhitehorn 82192067Snwhitehorn PLATFORMMETHOD(platform_smp_first_cpu, bare_smp_first_cpu), 83192067Snwhitehorn PLATFORMMETHOD(platform_smp_next_cpu, bare_smp_next_cpu), 84192067Snwhitehorn PLATFORMMETHOD(platform_smp_get_bsp, bare_smp_get_bsp), 85192067Snwhitehorn PLATFORMMETHOD(platform_smp_start_cpu, bare_smp_start_cpu), 86192067Snwhitehorn 87212453Smav PLATFORMMETHOD(platform_reset, e500_reset), 88212054Snwhitehorn 89192067Snwhitehorn { 0, 0 } 90192067Snwhitehorn}; 91192067Snwhitehorn 92192067Snwhitehornstatic platform_def_t bare_platform = { 93192067Snwhitehorn "bare metal", 94192067Snwhitehorn bare_methods, 95192067Snwhitehorn 0 96192067Snwhitehorn}; 97192067Snwhitehorn 98192067SnwhitehornPLATFORM_DEF(bare_platform); 99192067Snwhitehorn 100192067Snwhitehornstatic int 101192067Snwhitehornbare_probe(platform_t plat) 102192067Snwhitehorn{ 103209908Sraj uint32_t ver, sr; 104209908Sraj int i, law_max, tgt; 105192067Snwhitehorn 106193492Sraj ver = SVR_VER(mfspr(SPR_SVR)); 107222433Smarcel switch (ver & ~0x0008) { /* Mask Security Enabled bit */ 108222433Smarcel case SVR_P4080: 109222433Smarcel maxcpu = 8; 110222433Smarcel break; 111222433Smarcel case SVR_P4040: 112222433Smarcel maxcpu = 4; 113222433Smarcel break; 114222433Smarcel case SVR_MPC8572: 115222433Smarcel case SVR_P1020: 116222433Smarcel case SVR_P2020: 117193492Sraj maxcpu = 2; 118222433Smarcel break; 119222433Smarcel default: 120193492Sraj maxcpu = 1; 121222433Smarcel break; 122222433Smarcel } 123193492Sraj 124209908Sraj /* 125209908Sraj * Clear local access windows. Skip DRAM entries, so we don't shoot 126209908Sraj * ourselves in the foot. 127209908Sraj */ 128209908Sraj law_max = law_getmax(); 129209908Sraj for (i = 0; i < law_max; i++) { 130209908Sraj sr = ccsr_read4(OCP85XX_LAWSR(i)); 131209908Sraj if ((sr & 0x80000000) == 0) 132209908Sraj continue; 133209908Sraj tgt = (sr & 0x01f00000) >> 20; 134209908Sraj if (tgt == OCP85XX_TGTIF_RAM1 || tgt == OCP85XX_TGTIF_RAM2 || 135209908Sraj tgt == OCP85XX_TGTIF_RAM_INTL) 136209908Sraj continue; 137209908Sraj 138209908Sraj ccsr_write4(OCP85XX_LAWSR(i), sr & 0x7fffffff); 139209908Sraj } 140209908Sraj 141192067Snwhitehorn return (BUS_PROBE_GENERIC); 142192067Snwhitehorn} 143192067Snwhitehorn 144192067Snwhitehorn#define MEM_REGIONS 8 145192067Snwhitehornstatic struct mem_region avail_regions[MEM_REGIONS]; 146192067Snwhitehorn 147192067Snwhitehornvoid 148192067Snwhitehornbare_mem_regions(platform_t plat, struct mem_region **phys, int *physsz, 149192067Snwhitehorn struct mem_region **avail, int *availsz) 150192067Snwhitehorn{ 151209908Sraj uint32_t memsize; 152209908Sraj int i, rv; 153192067Snwhitehorn 154209908Sraj rv = fdt_get_mem_regions(avail_regions, availsz, &memsize); 155209908Sraj 156209908Sraj if (rv != 0) 157209908Sraj return; 158209908Sraj 159209908Sraj for (i = 0; i < *availsz; i++) { 160209908Sraj if (avail_regions[i].mr_start < 1048576) { 161209908Sraj avail_regions[i].mr_size = 162209908Sraj avail_regions[i].mr_size - 163209908Sraj (1048576 - avail_regions[i].mr_start); 164192067Snwhitehorn avail_regions[i].mr_start = 1048576; 165192067Snwhitehorn } 166192067Snwhitehorn } 167192067Snwhitehorn *avail = avail_regions; 168192067Snwhitehorn 169192067Snwhitehorn /* On the bare metal platform phys == avail memory */ 170192067Snwhitehorn *physsz = *availsz; 171192067Snwhitehorn *phys = *avail; 172192067Snwhitehorn} 173192067Snwhitehorn 174192067Snwhitehornstatic u_long 175192067Snwhitehornbare_timebase_freq(platform_t plat, struct cpuref *cpuref) 176192067Snwhitehorn{ 177217523Smarcel u_long ticks; 178209908Sraj phandle_t cpus, child; 179209908Sraj pcell_t freq; 180192067Snwhitehorn 181224618Smarcel if (bootinfo != NULL) { 182224611Smarcel if (bootinfo[0] == 1) { 183224611Smarcel /* Backward compatibility. See 8-STABLE. */ 184224611Smarcel ticks = bootinfo[3] >> 3; 185224611Smarcel } else { 186224618Smarcel /* Compatibility with Juniper's loader. */ 187224611Smarcel ticks = bootinfo[5] >> 3; 188224618Smarcel } 189222327Smarcel } else 190222327Smarcel ticks = 0; 191217523Smarcel 192209908Sraj if ((cpus = OF_finddevice("/cpus")) == 0) 193209908Sraj goto out; 194209908Sraj 195209908Sraj if ((child = OF_child(cpus)) == 0) 196209908Sraj goto out; 197209908Sraj 198217523Smarcel freq = 0; 199209908Sraj if (OF_getprop(child, "bus-frequency", (void *)&freq, 200209908Sraj sizeof(freq)) <= 0) 201209908Sraj goto out; 202217523Smarcel 203192067Snwhitehorn /* 204192067Snwhitehorn * Time Base and Decrementer are updated every 8 CCB bus clocks. 205192067Snwhitehorn * HID0[SEL_TBCLK] = 0 206192067Snwhitehorn */ 207217523Smarcel if (freq != 0) 208217523Smarcel ticks = freq / 8; 209217523Smarcel 210209908Srajout: 211192067Snwhitehorn if (ticks <= 0) 212192067Snwhitehorn panic("Unable to determine timebase frequency!"); 213192067Snwhitehorn 214192067Snwhitehorn return (ticks); 215192067Snwhitehorn} 216192067Snwhitehorn 217192067Snwhitehornstatic int 218192067Snwhitehornbare_smp_first_cpu(platform_t plat, struct cpuref *cpuref) 219192067Snwhitehorn{ 220192067Snwhitehorn 221192067Snwhitehorn cpu = 0; 222192067Snwhitehorn cpuref->cr_cpuid = cpu; 223192067Snwhitehorn cpuref->cr_hwref = cpuref->cr_cpuid; 224192067Snwhitehorn if (bootverbose) 225192067Snwhitehorn printf("powerpc_smp_first_cpu: cpuid %d\n", cpuref->cr_cpuid); 226192067Snwhitehorn cpu++; 227192067Snwhitehorn 228192067Snwhitehorn return (0); 229192067Snwhitehorn} 230192067Snwhitehorn 231192067Snwhitehornstatic int 232192067Snwhitehornbare_smp_next_cpu(platform_t plat, struct cpuref *cpuref) 233192067Snwhitehorn{ 234192067Snwhitehorn 235193492Sraj if (cpu >= maxcpu) 236192067Snwhitehorn return (ENOENT); 237192067Snwhitehorn 238192067Snwhitehorn cpuref->cr_cpuid = cpu++; 239192067Snwhitehorn cpuref->cr_hwref = cpuref->cr_cpuid; 240192067Snwhitehorn if (bootverbose) 241192067Snwhitehorn printf("powerpc_smp_next_cpu: cpuid %d\n", cpuref->cr_cpuid); 242192067Snwhitehorn 243192067Snwhitehorn return (0); 244192067Snwhitehorn} 245192067Snwhitehorn 246192067Snwhitehornstatic int 247192067Snwhitehornbare_smp_get_bsp(platform_t plat, struct cpuref *cpuref) 248192067Snwhitehorn{ 249192067Snwhitehorn 250192067Snwhitehorn cpuref->cr_cpuid = mfspr(SPR_PIR); 251192067Snwhitehorn cpuref->cr_hwref = cpuref->cr_cpuid; 252192067Snwhitehorn 253192067Snwhitehorn return (0); 254192067Snwhitehorn} 255192067Snwhitehorn 256192067Snwhitehornstatic int 257192067Snwhitehornbare_smp_start_cpu(platform_t plat, struct pcpu *pc) 258192067Snwhitehorn{ 259192532Sraj#ifdef SMP 260192532Sraj uint32_t bptr, eebpcr; 261192532Sraj int timeout; 262192067Snwhitehorn 263192532Sraj eebpcr = ccsr_read4(OCP85XX_EEBPCR); 264222813Sattilio if ((eebpcr & (1 << (pc->pc_cpuid + 24))) != 0) { 265192532Sraj printf("%s: CPU=%d already out of hold-off state!\n", 266192532Sraj __func__, pc->pc_cpuid); 267192532Sraj return (ENXIO); 268192532Sraj } 269192532Sraj 270192532Sraj ap_pcpu = pc; 271192532Sraj __asm __volatile("msync; isync"); 272192532Sraj 273192532Sraj /* 274192532Sraj * Set BPTR to the physical address of the boot page 275192532Sraj */ 276224611Smarcel bptr = ((uint32_t)__boot_page - KERNBASE) + kernload_ap; 277192532Sraj ccsr_write4(OCP85XX_BPTR, (bptr >> 12) | 0x80000000); 278192532Sraj 279192532Sraj /* 280192532Sraj * Release AP from hold-off state 281192532Sraj */ 282222813Sattilio eebpcr |= (1 << (pc->pc_cpuid + 24)); 283192532Sraj ccsr_write4(OCP85XX_EEBPCR, eebpcr); 284192532Sraj __asm __volatile("isync; msync"); 285192532Sraj 286192532Sraj timeout = 500; 287192532Sraj while (!pc->pc_awake && timeout--) 288192532Sraj DELAY(1000); /* wait 1ms */ 289192532Sraj 290192532Sraj return ((pc->pc_awake) ? 0 : EBUSY); 291192532Sraj#else 292192067Snwhitehorn /* No SMP support */ 293192067Snwhitehorn return (ENXIO); 294192532Sraj#endif 295192067Snwhitehorn} 296212054Snwhitehorn 297212054Snwhitehornstatic void 298212054Snwhitehorne500_reset(platform_t plat) 299212054Snwhitehorn{ 300212054Snwhitehorn 301222392Smarcel /* 302222392Smarcel * Try the dedicated reset register first. 303222392Smarcel * If the SoC doesn't have one, we'll fall 304222392Smarcel * back to using the debug control register. 305222392Smarcel */ 306222392Smarcel ccsr_write4(OCP85XX_RSTCR, 2); 307212054Snwhitehorn 308222392Smarcel /* Clear DBCR0, disables debug interrupts and events. */ 309222392Smarcel mtspr(SPR_DBCR0, 0); 310222392Smarcel __asm __volatile("isync"); 311212054Snwhitehorn 312222392Smarcel /* Enable Debug Interrupts in MSR. */ 313222392Smarcel mtmsr(mfmsr() | PSL_DE); 314212054Snwhitehorn 315222392Smarcel /* Enable debug interrupts and issue reset. */ 316222392Smarcel mtspr(SPR_DBCR0, mfspr(SPR_DBCR0) | DBCR0_IDM | DBCR0_RST_SYSTEM); 317222392Smarcel 318212054Snwhitehorn printf("Reset failed...\n"); 319212054Snwhitehorn while (1); 320212054Snwhitehorn} 321212054Snwhitehorn 322