platform_bare.c revision 235932
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: head/sys/powerpc/booke/platform_bare.c 235932 2012-05-24 20:58:40Z marcel $"); 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 */ 59235932Smarcelextern uint32_t bp_kernload; /* Kernel physical load address */ 60235932Smarcelextern uint32_t bp_trace; /* AP boot trace field */ 61192532Sraj#endif 62192532Sraj 63217523Smarcelextern uint32_t *bootinfo; 64217523Smarcel 65193492Srajstatic int cpu, maxcpu; 66192067Snwhitehorn 67192067Snwhitehornstatic int bare_probe(platform_t); 68192067Snwhitehornstatic void bare_mem_regions(platform_t, struct mem_region **phys, int *physsz, 69192067Snwhitehorn struct mem_region **avail, int *availsz); 70192067Snwhitehornstatic u_long bare_timebase_freq(platform_t, struct cpuref *cpuref); 71192067Snwhitehornstatic int bare_smp_first_cpu(platform_t, struct cpuref *cpuref); 72192067Snwhitehornstatic int bare_smp_next_cpu(platform_t, struct cpuref *cpuref); 73192067Snwhitehornstatic int bare_smp_get_bsp(platform_t, struct cpuref *cpuref); 74192067Snwhitehornstatic int bare_smp_start_cpu(platform_t, struct pcpu *cpu); 75192067Snwhitehorn 76212054Snwhitehornstatic void e500_reset(platform_t); 77212054Snwhitehorn 78192067Snwhitehornstatic platform_method_t bare_methods[] = { 79192067Snwhitehorn PLATFORMMETHOD(platform_probe, bare_probe), 80192067Snwhitehorn PLATFORMMETHOD(platform_mem_regions, bare_mem_regions), 81192067Snwhitehorn PLATFORMMETHOD(platform_timebase_freq, bare_timebase_freq), 82192067Snwhitehorn 83192067Snwhitehorn PLATFORMMETHOD(platform_smp_first_cpu, bare_smp_first_cpu), 84192067Snwhitehorn PLATFORMMETHOD(platform_smp_next_cpu, bare_smp_next_cpu), 85192067Snwhitehorn PLATFORMMETHOD(platform_smp_get_bsp, bare_smp_get_bsp), 86192067Snwhitehorn PLATFORMMETHOD(platform_smp_start_cpu, bare_smp_start_cpu), 87192067Snwhitehorn 88212453Smav PLATFORMMETHOD(platform_reset, e500_reset), 89212054Snwhitehorn 90192067Snwhitehorn { 0, 0 } 91192067Snwhitehorn}; 92192067Snwhitehorn 93192067Snwhitehornstatic platform_def_t bare_platform = { 94192067Snwhitehorn "bare metal", 95192067Snwhitehorn bare_methods, 96192067Snwhitehorn 0 97192067Snwhitehorn}; 98192067Snwhitehorn 99192067SnwhitehornPLATFORM_DEF(bare_platform); 100192067Snwhitehorn 101192067Snwhitehornstatic int 102192067Snwhitehornbare_probe(platform_t plat) 103192067Snwhitehorn{ 104209908Sraj uint32_t ver, sr; 105209908Sraj int i, law_max, tgt; 106192067Snwhitehorn 107193492Sraj ver = SVR_VER(mfspr(SPR_SVR)); 108222433Smarcel switch (ver & ~0x0008) { /* Mask Security Enabled bit */ 109222433Smarcel case SVR_P4080: 110222433Smarcel maxcpu = 8; 111222433Smarcel break; 112222433Smarcel case SVR_P4040: 113222433Smarcel maxcpu = 4; 114222433Smarcel break; 115222433Smarcel case SVR_MPC8572: 116222433Smarcel case SVR_P1020: 117222433Smarcel case SVR_P2020: 118193492Sraj maxcpu = 2; 119222433Smarcel break; 120222433Smarcel default: 121193492Sraj maxcpu = 1; 122222433Smarcel break; 123222433Smarcel } 124193492Sraj 125209908Sraj /* 126209908Sraj * Clear local access windows. Skip DRAM entries, so we don't shoot 127209908Sraj * ourselves in the foot. 128209908Sraj */ 129209908Sraj law_max = law_getmax(); 130209908Sraj for (i = 0; i < law_max; i++) { 131209908Sraj sr = ccsr_read4(OCP85XX_LAWSR(i)); 132209908Sraj if ((sr & 0x80000000) == 0) 133209908Sraj continue; 134209908Sraj tgt = (sr & 0x01f00000) >> 20; 135209908Sraj if (tgt == OCP85XX_TGTIF_RAM1 || tgt == OCP85XX_TGTIF_RAM2 || 136209908Sraj tgt == OCP85XX_TGTIF_RAM_INTL) 137209908Sraj continue; 138209908Sraj 139209908Sraj ccsr_write4(OCP85XX_LAWSR(i), sr & 0x7fffffff); 140209908Sraj } 141209908Sraj 142192067Snwhitehorn return (BUS_PROBE_GENERIC); 143192067Snwhitehorn} 144192067Snwhitehorn 145192067Snwhitehorn#define MEM_REGIONS 8 146192067Snwhitehornstatic struct mem_region avail_regions[MEM_REGIONS]; 147192067Snwhitehorn 148192067Snwhitehornvoid 149192067Snwhitehornbare_mem_regions(platform_t plat, struct mem_region **phys, int *physsz, 150192067Snwhitehorn struct mem_region **avail, int *availsz) 151192067Snwhitehorn{ 152209908Sraj uint32_t memsize; 153209908Sraj int i, rv; 154192067Snwhitehorn 155209908Sraj rv = fdt_get_mem_regions(avail_regions, availsz, &memsize); 156209908Sraj 157209908Sraj if (rv != 0) 158209908Sraj return; 159209908Sraj 160209908Sraj for (i = 0; i < *availsz; i++) { 161209908Sraj if (avail_regions[i].mr_start < 1048576) { 162209908Sraj avail_regions[i].mr_size = 163209908Sraj avail_regions[i].mr_size - 164209908Sraj (1048576 - avail_regions[i].mr_start); 165192067Snwhitehorn avail_regions[i].mr_start = 1048576; 166192067Snwhitehorn } 167192067Snwhitehorn } 168192067Snwhitehorn *avail = avail_regions; 169192067Snwhitehorn 170192067Snwhitehorn /* On the bare metal platform phys == avail memory */ 171192067Snwhitehorn *physsz = *availsz; 172192067Snwhitehorn *phys = *avail; 173192067Snwhitehorn} 174192067Snwhitehorn 175192067Snwhitehornstatic u_long 176192067Snwhitehornbare_timebase_freq(platform_t plat, struct cpuref *cpuref) 177192067Snwhitehorn{ 178217523Smarcel u_long ticks; 179209908Sraj phandle_t cpus, child; 180209908Sraj pcell_t freq; 181192067Snwhitehorn 182224618Smarcel if (bootinfo != NULL) { 183224611Smarcel if (bootinfo[0] == 1) { 184224611Smarcel /* Backward compatibility. See 8-STABLE. */ 185224611Smarcel ticks = bootinfo[3] >> 3; 186224611Smarcel } else { 187224618Smarcel /* Compatibility with Juniper's loader. */ 188224611Smarcel ticks = bootinfo[5] >> 3; 189224618Smarcel } 190222327Smarcel } else 191222327Smarcel ticks = 0; 192217523Smarcel 193228201Sjchandra if ((cpus = OF_finddevice("/cpus")) == -1) 194209908Sraj goto out; 195209908Sraj 196209908Sraj if ((child = OF_child(cpus)) == 0) 197209908Sraj goto out; 198209908Sraj 199217523Smarcel freq = 0; 200209908Sraj if (OF_getprop(child, "bus-frequency", (void *)&freq, 201209908Sraj sizeof(freq)) <= 0) 202209908Sraj goto out; 203217523Smarcel 204192067Snwhitehorn /* 205192067Snwhitehorn * Time Base and Decrementer are updated every 8 CCB bus clocks. 206192067Snwhitehorn * HID0[SEL_TBCLK] = 0 207192067Snwhitehorn */ 208217523Smarcel if (freq != 0) 209217523Smarcel ticks = freq / 8; 210217523Smarcel 211209908Srajout: 212192067Snwhitehorn if (ticks <= 0) 213192067Snwhitehorn panic("Unable to determine timebase frequency!"); 214192067Snwhitehorn 215192067Snwhitehorn return (ticks); 216192067Snwhitehorn} 217192067Snwhitehorn 218192067Snwhitehornstatic int 219192067Snwhitehornbare_smp_first_cpu(platform_t plat, struct cpuref *cpuref) 220192067Snwhitehorn{ 221192067Snwhitehorn 222192067Snwhitehorn cpu = 0; 223192067Snwhitehorn cpuref->cr_cpuid = cpu; 224192067Snwhitehorn cpuref->cr_hwref = cpuref->cr_cpuid; 225192067Snwhitehorn if (bootverbose) 226192067Snwhitehorn printf("powerpc_smp_first_cpu: cpuid %d\n", cpuref->cr_cpuid); 227192067Snwhitehorn cpu++; 228192067Snwhitehorn 229192067Snwhitehorn return (0); 230192067Snwhitehorn} 231192067Snwhitehorn 232192067Snwhitehornstatic int 233192067Snwhitehornbare_smp_next_cpu(platform_t plat, struct cpuref *cpuref) 234192067Snwhitehorn{ 235192067Snwhitehorn 236193492Sraj if (cpu >= maxcpu) 237192067Snwhitehorn return (ENOENT); 238192067Snwhitehorn 239192067Snwhitehorn cpuref->cr_cpuid = cpu++; 240192067Snwhitehorn cpuref->cr_hwref = cpuref->cr_cpuid; 241192067Snwhitehorn if (bootverbose) 242192067Snwhitehorn printf("powerpc_smp_next_cpu: cpuid %d\n", cpuref->cr_cpuid); 243192067Snwhitehorn 244192067Snwhitehorn return (0); 245192067Snwhitehorn} 246192067Snwhitehorn 247192067Snwhitehornstatic int 248192067Snwhitehornbare_smp_get_bsp(platform_t plat, struct cpuref *cpuref) 249192067Snwhitehorn{ 250192067Snwhitehorn 251192067Snwhitehorn cpuref->cr_cpuid = mfspr(SPR_PIR); 252192067Snwhitehorn cpuref->cr_hwref = cpuref->cr_cpuid; 253192067Snwhitehorn 254192067Snwhitehorn return (0); 255192067Snwhitehorn} 256192067Snwhitehorn 257192067Snwhitehornstatic int 258192067Snwhitehornbare_smp_start_cpu(platform_t plat, struct pcpu *pc) 259192067Snwhitehorn{ 260192532Sraj#ifdef SMP 261192532Sraj uint32_t bptr, eebpcr; 262192532Sraj int timeout; 263192067Snwhitehorn 264192532Sraj eebpcr = ccsr_read4(OCP85XX_EEBPCR); 265222813Sattilio if ((eebpcr & (1 << (pc->pc_cpuid + 24))) != 0) { 266235932Smarcel printf("SMP: CPU %d already out of hold-off state!\n", 267235932Smarcel pc->pc_cpuid); 268192532Sraj return (ENXIO); 269192532Sraj } 270192532Sraj 271192532Sraj ap_pcpu = pc; 272192532Sraj __asm __volatile("msync; isync"); 273192532Sraj 274192532Sraj /* 275192532Sraj * Set BPTR to the physical address of the boot page 276192532Sraj */ 277235932Smarcel bptr = ((uint32_t)__boot_page - KERNBASE) + bp_kernload; 278192532Sraj ccsr_write4(OCP85XX_BPTR, (bptr >> 12) | 0x80000000); 279192532Sraj 280192532Sraj /* 281192532Sraj * Release AP from hold-off state 282192532Sraj */ 283235932Smarcel bp_trace = 0; 284222813Sattilio eebpcr |= (1 << (pc->pc_cpuid + 24)); 285192532Sraj ccsr_write4(OCP85XX_EEBPCR, eebpcr); 286192532Sraj __asm __volatile("isync; msync"); 287192532Sraj 288192532Sraj timeout = 500; 289192532Sraj while (!pc->pc_awake && timeout--) 290192532Sraj DELAY(1000); /* wait 1ms */ 291192532Sraj 292235932Smarcel /* 293235932Smarcel * Disable boot page translation so that the 4K page at the default 294235932Smarcel * address (= 0xfffff000) isn't permanently remapped and thus not 295235932Smarcel * usable otherwise. 296235932Smarcel */ 297235932Smarcel ccsr_write4(OCP85XX_BPTR, 0); 298235932Smarcel 299235932Smarcel if (!pc->pc_awake) 300235932Smarcel printf("SMP: CPU %d didn't wake up (trace code %#x).\n", 301235932Smarcel pc->pc_awake, bp_trace); 302192532Sraj return ((pc->pc_awake) ? 0 : EBUSY); 303192532Sraj#else 304192067Snwhitehorn /* No SMP support */ 305192067Snwhitehorn return (ENXIO); 306192532Sraj#endif 307192067Snwhitehorn} 308212054Snwhitehorn 309212054Snwhitehornstatic void 310212054Snwhitehorne500_reset(platform_t plat) 311212054Snwhitehorn{ 312212054Snwhitehorn 313222392Smarcel /* 314222392Smarcel * Try the dedicated reset register first. 315222392Smarcel * If the SoC doesn't have one, we'll fall 316222392Smarcel * back to using the debug control register. 317222392Smarcel */ 318222392Smarcel ccsr_write4(OCP85XX_RSTCR, 2); 319212054Snwhitehorn 320222392Smarcel /* Clear DBCR0, disables debug interrupts and events. */ 321222392Smarcel mtspr(SPR_DBCR0, 0); 322222392Smarcel __asm __volatile("isync"); 323212054Snwhitehorn 324222392Smarcel /* Enable Debug Interrupts in MSR. */ 325222392Smarcel mtmsr(mfmsr() | PSL_DE); 326212054Snwhitehorn 327222392Smarcel /* Enable debug interrupts and issue reset. */ 328222392Smarcel mtspr(SPR_DBCR0, mfspr(SPR_DBCR0) | DBCR0_IDM | DBCR0_RST_SYSTEM); 329222392Smarcel 330212054Snwhitehorn printf("Reset failed...\n"); 331212054Snwhitehorn while (1); 332212054Snwhitehorn} 333212054Snwhitehorn 334