1192067Snwhitehorn/*- 2236098Sraj * Copyright (c) 2008-2012 Semihalf. 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; 58242526Smarcelextern vm_paddr_t kernload; /* Kernel physical load address */ 59192532Srajextern uint8_t __boot_page[]; /* Boot page body */ 60242526Smarcelextern uint32_t bp_ntlb1s; 61242526Smarcelextern uint32_t bp_tlb1[]; 62242526Smarcelextern uint32_t bp_tlb1_end[]; 63192532Sraj#endif 64192532Sraj 65217523Smarcelextern uint32_t *bootinfo; 66217523Smarcel 67193492Srajstatic int cpu, maxcpu; 68192067Snwhitehorn 69192067Snwhitehornstatic int bare_probe(platform_t); 70192067Snwhitehornstatic void bare_mem_regions(platform_t, struct mem_region **phys, int *physsz, 71192067Snwhitehorn struct mem_region **avail, int *availsz); 72192067Snwhitehornstatic u_long bare_timebase_freq(platform_t, struct cpuref *cpuref); 73192067Snwhitehornstatic int bare_smp_first_cpu(platform_t, struct cpuref *cpuref); 74192067Snwhitehornstatic int bare_smp_next_cpu(platform_t, struct cpuref *cpuref); 75192067Snwhitehornstatic int bare_smp_get_bsp(platform_t, struct cpuref *cpuref); 76192067Snwhitehornstatic int bare_smp_start_cpu(platform_t, struct pcpu *cpu); 77192067Snwhitehorn 78236097Srajstatic void booke_reset(platform_t); 79212054Snwhitehorn 80192067Snwhitehornstatic platform_method_t bare_methods[] = { 81236325Sraj PLATFORMMETHOD(platform_probe, bare_probe), 82192067Snwhitehorn PLATFORMMETHOD(platform_mem_regions, bare_mem_regions), 83192067Snwhitehorn PLATFORMMETHOD(platform_timebase_freq, bare_timebase_freq), 84192067Snwhitehorn 85192067Snwhitehorn PLATFORMMETHOD(platform_smp_first_cpu, bare_smp_first_cpu), 86192067Snwhitehorn PLATFORMMETHOD(platform_smp_next_cpu, bare_smp_next_cpu), 87192067Snwhitehorn PLATFORMMETHOD(platform_smp_get_bsp, bare_smp_get_bsp), 88192067Snwhitehorn PLATFORMMETHOD(platform_smp_start_cpu, bare_smp_start_cpu), 89192067Snwhitehorn 90236097Sraj PLATFORMMETHOD(platform_reset, booke_reset), 91212054Snwhitehorn 92246732Srpaulo PLATFORMMETHOD_END 93192067Snwhitehorn}; 94192067Snwhitehorn 95192067Snwhitehornstatic platform_def_t bare_platform = { 96192067Snwhitehorn "bare metal", 97192067Snwhitehorn bare_methods, 98192067Snwhitehorn 0 99192067Snwhitehorn}; 100192067Snwhitehorn 101192067SnwhitehornPLATFORM_DEF(bare_platform); 102192067Snwhitehorn 103192067Snwhitehornstatic int 104192067Snwhitehornbare_probe(platform_t plat) 105192067Snwhitehorn{ 106236098Sraj phandle_t cpus, child; 107236098Sraj uint32_t sr; 108209908Sraj int i, law_max, tgt; 109192067Snwhitehorn 110236098Sraj if ((cpus = OF_finddevice("/cpus")) != 0) { 111236098Sraj for (maxcpu = 0, child = OF_child(cpus); child != 0; 112236098Sraj child = OF_peer(child), maxcpu++) 113236098Sraj ; 114236098Sraj } else 115193492Sraj maxcpu = 1; 116193492Sraj 117209908Sraj /* 118209908Sraj * Clear local access windows. Skip DRAM entries, so we don't shoot 119209908Sraj * ourselves in the foot. 120209908Sraj */ 121209908Sraj law_max = law_getmax(); 122209908Sraj for (i = 0; i < law_max; i++) { 123209908Sraj sr = ccsr_read4(OCP85XX_LAWSR(i)); 124209908Sraj if ((sr & 0x80000000) == 0) 125209908Sraj continue; 126209908Sraj tgt = (sr & 0x01f00000) >> 20; 127209908Sraj if (tgt == OCP85XX_TGTIF_RAM1 || tgt == OCP85XX_TGTIF_RAM2 || 128209908Sraj tgt == OCP85XX_TGTIF_RAM_INTL) 129209908Sraj continue; 130209908Sraj 131209908Sraj ccsr_write4(OCP85XX_LAWSR(i), sr & 0x7fffffff); 132209908Sraj } 133209908Sraj 134192067Snwhitehorn return (BUS_PROBE_GENERIC); 135192067Snwhitehorn} 136192067Snwhitehorn 137192067Snwhitehorn#define MEM_REGIONS 8 138192067Snwhitehornstatic struct mem_region avail_regions[MEM_REGIONS]; 139192067Snwhitehorn 140192067Snwhitehornvoid 141192067Snwhitehornbare_mem_regions(platform_t plat, struct mem_region **phys, int *physsz, 142192067Snwhitehorn struct mem_region **avail, int *availsz) 143192067Snwhitehorn{ 144209908Sraj uint32_t memsize; 145209908Sraj int i, rv; 146192067Snwhitehorn 147209908Sraj rv = fdt_get_mem_regions(avail_regions, availsz, &memsize); 148209908Sraj if (rv != 0) 149236325Sraj panic("%s: could not retrieve mem regions from the 'memory' " 150236325Sraj "node, error: %d", __func__, rv); 151209908Sraj 152209908Sraj for (i = 0; i < *availsz; i++) { 153209908Sraj if (avail_regions[i].mr_start < 1048576) { 154209908Sraj avail_regions[i].mr_size = 155209908Sraj avail_regions[i].mr_size - 156209908Sraj (1048576 - avail_regions[i].mr_start); 157192067Snwhitehorn avail_regions[i].mr_start = 1048576; 158192067Snwhitehorn } 159192067Snwhitehorn } 160192067Snwhitehorn *avail = avail_regions; 161192067Snwhitehorn 162192067Snwhitehorn /* On the bare metal platform phys == avail memory */ 163192067Snwhitehorn *physsz = *availsz; 164192067Snwhitehorn *phys = *avail; 165192067Snwhitehorn} 166192067Snwhitehorn 167192067Snwhitehornstatic u_long 168192067Snwhitehornbare_timebase_freq(platform_t plat, struct cpuref *cpuref) 169192067Snwhitehorn{ 170217523Smarcel u_long ticks; 171209908Sraj phandle_t cpus, child; 172209908Sraj pcell_t freq; 173192067Snwhitehorn 174224618Smarcel if (bootinfo != NULL) { 175224611Smarcel if (bootinfo[0] == 1) { 176224611Smarcel /* Backward compatibility. See 8-STABLE. */ 177224611Smarcel ticks = bootinfo[3] >> 3; 178224611Smarcel } else { 179224618Smarcel /* Compatibility with Juniper's loader. */ 180224611Smarcel ticks = bootinfo[5] >> 3; 181224618Smarcel } 182222327Smarcel } else 183222327Smarcel ticks = 0; 184217523Smarcel 185228201Sjchandra if ((cpus = OF_finddevice("/cpus")) == -1) 186209908Sraj goto out; 187209908Sraj 188209908Sraj if ((child = OF_child(cpus)) == 0) 189209908Sraj goto out; 190209908Sraj 191217523Smarcel freq = 0; 192209908Sraj if (OF_getprop(child, "bus-frequency", (void *)&freq, 193209908Sraj sizeof(freq)) <= 0) 194209908Sraj goto out; 195217523Smarcel 196192067Snwhitehorn /* 197192067Snwhitehorn * Time Base and Decrementer are updated every 8 CCB bus clocks. 198192067Snwhitehorn * HID0[SEL_TBCLK] = 0 199192067Snwhitehorn */ 200217523Smarcel if (freq != 0) 201217523Smarcel ticks = freq / 8; 202217523Smarcel 203209908Srajout: 204192067Snwhitehorn if (ticks <= 0) 205192067Snwhitehorn panic("Unable to determine timebase frequency!"); 206192067Snwhitehorn 207192067Snwhitehorn return (ticks); 208192067Snwhitehorn} 209192067Snwhitehorn 210192067Snwhitehornstatic int 211192067Snwhitehornbare_smp_first_cpu(platform_t plat, struct cpuref *cpuref) 212192067Snwhitehorn{ 213192067Snwhitehorn 214192067Snwhitehorn cpu = 0; 215192067Snwhitehorn cpuref->cr_cpuid = cpu; 216192067Snwhitehorn cpuref->cr_hwref = cpuref->cr_cpuid; 217192067Snwhitehorn if (bootverbose) 218192067Snwhitehorn printf("powerpc_smp_first_cpu: cpuid %d\n", cpuref->cr_cpuid); 219192067Snwhitehorn cpu++; 220192067Snwhitehorn 221192067Snwhitehorn return (0); 222192067Snwhitehorn} 223192067Snwhitehorn 224192067Snwhitehornstatic int 225192067Snwhitehornbare_smp_next_cpu(platform_t plat, struct cpuref *cpuref) 226192067Snwhitehorn{ 227192067Snwhitehorn 228193492Sraj if (cpu >= maxcpu) 229192067Snwhitehorn return (ENOENT); 230192067Snwhitehorn 231192067Snwhitehorn cpuref->cr_cpuid = cpu++; 232192067Snwhitehorn cpuref->cr_hwref = cpuref->cr_cpuid; 233192067Snwhitehorn if (bootverbose) 234192067Snwhitehorn printf("powerpc_smp_next_cpu: cpuid %d\n", cpuref->cr_cpuid); 235192067Snwhitehorn 236192067Snwhitehorn return (0); 237192067Snwhitehorn} 238192067Snwhitehorn 239192067Snwhitehornstatic int 240192067Snwhitehornbare_smp_get_bsp(platform_t plat, struct cpuref *cpuref) 241192067Snwhitehorn{ 242192067Snwhitehorn 243192067Snwhitehorn cpuref->cr_cpuid = mfspr(SPR_PIR); 244192067Snwhitehorn cpuref->cr_hwref = cpuref->cr_cpuid; 245192067Snwhitehorn 246192067Snwhitehorn return (0); 247192067Snwhitehorn} 248192067Snwhitehorn 249192067Snwhitehornstatic int 250192067Snwhitehornbare_smp_start_cpu(platform_t plat, struct pcpu *pc) 251192067Snwhitehorn{ 252192532Sraj#ifdef SMP 253242526Smarcel uint32_t *tlb1; 254192532Sraj uint32_t bptr, eebpcr; 255242526Smarcel int i, timeout; 256192067Snwhitehorn 257192532Sraj eebpcr = ccsr_read4(OCP85XX_EEBPCR); 258222813Sattilio if ((eebpcr & (1 << (pc->pc_cpuid + 24))) != 0) { 259235932Smarcel printf("SMP: CPU %d already out of hold-off state!\n", 260235932Smarcel pc->pc_cpuid); 261192532Sraj return (ENXIO); 262192532Sraj } 263192532Sraj 264192532Sraj ap_pcpu = pc; 265192532Sraj 266242526Smarcel i = 0; 267242526Smarcel tlb1 = bp_tlb1; 268242526Smarcel while (i < bp_ntlb1s && tlb1 < bp_tlb1_end) { 269242526Smarcel mtspr(SPR_MAS0, MAS0_TLBSEL(1) | MAS0_ESEL(i)); 270242526Smarcel __asm __volatile("isync; tlbre"); 271242526Smarcel tlb1[0] = mfspr(SPR_MAS1); 272242526Smarcel tlb1[1] = mfspr(SPR_MAS2); 273242526Smarcel tlb1[2] = mfspr(SPR_MAS3); 274242526Smarcel i++; 275242526Smarcel tlb1 += 3; 276242526Smarcel } 277242526Smarcel if (i < bp_ntlb1s) 278242526Smarcel bp_ntlb1s = i; 279242526Smarcel 280192532Sraj /* 281192532Sraj * Set BPTR to the physical address of the boot page 282192532Sraj */ 283242526Smarcel bptr = ((uint32_t)__boot_page - KERNBASE) + kernload; 284242526Smarcel KASSERT((bptr & 0xfff) == 0, 285242526Smarcel ("%s: boot page is not aligned (%#x)", __func__, bptr)); 286242526Smarcel bptr = (bptr >> 12) | 0x80000000u; 287242526Smarcel ccsr_write4(OCP85XX_BPTR, bptr); 288242526Smarcel __asm __volatile("isync; msync"); 289192532Sraj 290242526Smarcel /* Flush caches to have our changes hit DRAM. */ 291242526Smarcel cpu_flush_dcache(__boot_page, 4096); 292242526Smarcel 293192532Sraj /* 294192532Sraj * Release AP from hold-off state 295192532Sraj */ 296222813Sattilio eebpcr |= (1 << (pc->pc_cpuid + 24)); 297192532Sraj ccsr_write4(OCP85XX_EEBPCR, eebpcr); 298192532Sraj __asm __volatile("isync; msync"); 299192532Sraj 300192532Sraj timeout = 500; 301192532Sraj while (!pc->pc_awake && timeout--) 302192532Sraj DELAY(1000); /* wait 1ms */ 303192532Sraj 304235932Smarcel /* 305235932Smarcel * Disable boot page translation so that the 4K page at the default 306235932Smarcel * address (= 0xfffff000) isn't permanently remapped and thus not 307235932Smarcel * usable otherwise. 308235932Smarcel */ 309235932Smarcel ccsr_write4(OCP85XX_BPTR, 0); 310242526Smarcel __asm __volatile("isync; msync"); 311235932Smarcel 312235932Smarcel if (!pc->pc_awake) 313242526Smarcel printf("SMP: CPU %d didn't wake up.\n", pc->pc_cpuid); 314192532Sraj return ((pc->pc_awake) ? 0 : EBUSY); 315192532Sraj#else 316192067Snwhitehorn /* No SMP support */ 317192067Snwhitehorn return (ENXIO); 318192532Sraj#endif 319192067Snwhitehorn} 320212054Snwhitehorn 321212054Snwhitehornstatic void 322236097Srajbooke_reset(platform_t plat) 323212054Snwhitehorn{ 324212054Snwhitehorn 325222392Smarcel /* 326222392Smarcel * Try the dedicated reset register first. 327222392Smarcel * If the SoC doesn't have one, we'll fall 328222392Smarcel * back to using the debug control register. 329222392Smarcel */ 330222392Smarcel ccsr_write4(OCP85XX_RSTCR, 2); 331212054Snwhitehorn 332222392Smarcel /* Clear DBCR0, disables debug interrupts and events. */ 333222392Smarcel mtspr(SPR_DBCR0, 0); 334222392Smarcel __asm __volatile("isync"); 335212054Snwhitehorn 336222392Smarcel /* Enable Debug Interrupts in MSR. */ 337222392Smarcel mtmsr(mfmsr() | PSL_DE); 338212054Snwhitehorn 339222392Smarcel /* Enable debug interrupts and issue reset. */ 340222392Smarcel mtspr(SPR_DBCR0, mfspr(SPR_DBCR0) | DBCR0_IDM | DBCR0_RST_SYSTEM); 341222392Smarcel 342212054Snwhitehorn printf("Reset failed...\n"); 343236097Sraj while (1) 344236097Sraj ; 345212054Snwhitehorn} 346212054Snwhitehorn 347