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: releng/10.2/sys/powerpc/mpc85xx/platform_mpc85xx.c 266020 2014-05-14 14:17:51Z ian $"); 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 52266003Sian#include <vm/vm.h> 53266003Sian#include <vm/pmap.h> 54266003Sian 55192067Snwhitehorn#include <powerpc/mpc85xx/mpc85xx.h> 56192067Snwhitehorn 57192067Snwhitehorn#include "platform_if.h" 58192067Snwhitehorn 59192532Sraj#ifdef SMP 60192532Srajextern void *ap_pcpu; 61242526Smarcelextern vm_paddr_t kernload; /* Kernel physical load address */ 62192532Srajextern uint8_t __boot_page[]; /* Boot page body */ 63242526Smarcelextern uint32_t bp_ntlb1s; 64242526Smarcelextern uint32_t bp_tlb1[]; 65242526Smarcelextern uint32_t bp_tlb1_end[]; 66192532Sraj#endif 67192532Sraj 68217523Smarcelextern uint32_t *bootinfo; 69266003Sianvm_offset_t ccsrbar_va; 70217523Smarcel 71193492Srajstatic int cpu, maxcpu; 72192067Snwhitehorn 73257995Snwhitehornstatic int mpc85xx_probe(platform_t); 74257995Snwhitehornstatic int mpc85xx_attach(platform_t); 75266020Sianstatic void mpc85xx_mem_regions(platform_t, struct mem_region *phys, 76266020Sian int *physsz, struct mem_region *avail, int *availsz); 77257995Snwhitehornstatic u_long mpc85xx_timebase_freq(platform_t, struct cpuref *cpuref); 78257995Snwhitehornstatic int mpc85xx_smp_first_cpu(platform_t, struct cpuref *cpuref); 79257995Snwhitehornstatic int mpc85xx_smp_next_cpu(platform_t, struct cpuref *cpuref); 80257995Snwhitehornstatic int mpc85xx_smp_get_bsp(platform_t, struct cpuref *cpuref); 81257995Snwhitehornstatic int mpc85xx_smp_start_cpu(platform_t, struct pcpu *cpu); 82192067Snwhitehorn 83257995Snwhitehornstatic void mpc85xx_reset(platform_t); 84212054Snwhitehorn 85257995Snwhitehornstatic platform_method_t mpc85xx_methods[] = { 86257995Snwhitehorn PLATFORMMETHOD(platform_probe, mpc85xx_probe), 87257995Snwhitehorn PLATFORMMETHOD(platform_attach, mpc85xx_attach), 88257995Snwhitehorn PLATFORMMETHOD(platform_mem_regions, mpc85xx_mem_regions), 89257995Snwhitehorn PLATFORMMETHOD(platform_timebase_freq, mpc85xx_timebase_freq), 90192067Snwhitehorn 91257995Snwhitehorn PLATFORMMETHOD(platform_smp_first_cpu, mpc85xx_smp_first_cpu), 92257995Snwhitehorn PLATFORMMETHOD(platform_smp_next_cpu, mpc85xx_smp_next_cpu), 93257995Snwhitehorn PLATFORMMETHOD(platform_smp_get_bsp, mpc85xx_smp_get_bsp), 94257995Snwhitehorn PLATFORMMETHOD(platform_smp_start_cpu, mpc85xx_smp_start_cpu), 95192067Snwhitehorn 96257995Snwhitehorn PLATFORMMETHOD(platform_reset, mpc85xx_reset), 97212054Snwhitehorn 98246732Srpaulo PLATFORMMETHOD_END 99192067Snwhitehorn}; 100192067Snwhitehorn 101257995Snwhitehornstatic platform_def_t mpc85xx_platform = { 102257995Snwhitehorn "mpc85xx", 103257995Snwhitehorn mpc85xx_methods, 104192067Snwhitehorn 0 105192067Snwhitehorn}; 106192067Snwhitehorn 107257995SnwhitehornPLATFORM_DEF(mpc85xx_platform); 108192067Snwhitehorn 109192067Snwhitehornstatic int 110257995Snwhitehornmpc85xx_probe(platform_t plat) 111192067Snwhitehorn{ 112257995Snwhitehorn u_int pvr = mfpvr() >> 16; 113257995Snwhitehorn 114257995Snwhitehorn if ((pvr & 0xfff0) == FSL_E500v1) 115257995Snwhitehorn return (BUS_PROBE_DEFAULT); 116257995Snwhitehorn 117257995Snwhitehorn return (ENXIO); 118257995Snwhitehorn} 119257995Snwhitehorn 120257995Snwhitehornstatic int 121257995Snwhitehornmpc85xx_attach(platform_t plat) 122257995Snwhitehorn{ 123266003Sian phandle_t cpus, child, ccsr; 124266003Sian const char *soc_name_guesses[] = {"/soc", "soc", NULL}; 125266003Sian const char **name; 126266003Sian pcell_t ranges[6], acells, pacells, scells; 127236098Sraj uint32_t sr; 128266003Sian uint64_t ccsrbar, ccsrsize; 129209908Sraj int i, law_max, tgt; 130192067Snwhitehorn 131257995Snwhitehorn if ((cpus = OF_finddevice("/cpus")) != -1) { 132236098Sraj for (maxcpu = 0, child = OF_child(cpus); child != 0; 133236098Sraj child = OF_peer(child), maxcpu++) 134236098Sraj ; 135236098Sraj } else 136193492Sraj maxcpu = 1; 137193492Sraj 138209908Sraj /* 139266003Sian * Locate CCSR region. Irritatingly, there is no way to find it 140266003Sian * unless you already know where it is. Try to infer its location 141266003Sian * from the device tree. 142266003Sian */ 143266003Sian 144266003Sian ccsr = -1; 145266003Sian for (name = soc_name_guesses; *name != NULL && ccsr == -1; name++) 146266003Sian ccsr = OF_finddevice(*name); 147266003Sian if (ccsr == -1) { 148266003Sian char type[64]; 149266003Sian 150266003Sian /* That didn't work. Search for devices of type "soc" */ 151266003Sian child = OF_child(OF_peer(0)); 152266003Sian for (OF_child(child); child != 0; child = OF_peer(child)) { 153266003Sian if (OF_getprop(child, "device_type", type, sizeof(type)) 154266003Sian <= 0) 155266003Sian continue; 156266003Sian 157266003Sian if (strcmp(type, "soc") == 0) { 158266003Sian ccsr = child; 159266003Sian break; 160266003Sian } 161266003Sian } 162266003Sian } 163266003Sian 164266003Sian if (ccsr == -1) 165266003Sian panic("Could not locate CCSR window!"); 166266003Sian 167266003Sian OF_getprop(ccsr, "#size-cells", &scells, sizeof(scells)); 168266003Sian OF_getprop(ccsr, "#address-cells", &acells, sizeof(acells)); 169266003Sian OF_searchprop(OF_parent(ccsr), "#address-cells", &pacells, 170266003Sian sizeof(pacells)); 171266003Sian OF_getprop(ccsr, "ranges", ranges, sizeof(ranges)); 172266003Sian ccsrbar = ccsrsize = 0; 173266003Sian for (i = acells; i < acells + pacells; i++) { 174266003Sian ccsrbar <<= 32; 175266003Sian ccsrbar |= ranges[i]; 176266003Sian } 177266003Sian for (i = acells + pacells; i < acells + pacells + scells; i++) { 178266003Sian ccsrsize <<= 32; 179266003Sian ccsrsize |= ranges[i]; 180266003Sian } 181266003Sian ccsrbar_va = pmap_early_io_map(ccsrbar, ccsrsize); 182266003Sian 183266003Sian /* 184209908Sraj * Clear local access windows. Skip DRAM entries, so we don't shoot 185209908Sraj * ourselves in the foot. 186209908Sraj */ 187209908Sraj law_max = law_getmax(); 188209908Sraj for (i = 0; i < law_max; i++) { 189209908Sraj sr = ccsr_read4(OCP85XX_LAWSR(i)); 190209908Sraj if ((sr & 0x80000000) == 0) 191209908Sraj continue; 192209908Sraj tgt = (sr & 0x01f00000) >> 20; 193209908Sraj if (tgt == OCP85XX_TGTIF_RAM1 || tgt == OCP85XX_TGTIF_RAM2 || 194209908Sraj tgt == OCP85XX_TGTIF_RAM_INTL) 195209908Sraj continue; 196209908Sraj 197209908Sraj ccsr_write4(OCP85XX_LAWSR(i), sr & 0x7fffffff); 198209908Sraj } 199209908Sraj 200257995Snwhitehorn return (0); 201192067Snwhitehorn} 202192067Snwhitehorn 203192067Snwhitehornvoid 204266020Sianmpc85xx_mem_regions(platform_t plat, struct mem_region *phys, int *physsz, 205266020Sian struct mem_region *avail, int *availsz) 206192067Snwhitehorn{ 207192067Snwhitehorn 208257995Snwhitehorn ofw_mem_regions(phys, physsz, avail, availsz); 209192067Snwhitehorn} 210192067Snwhitehorn 211192067Snwhitehornstatic u_long 212257995Snwhitehornmpc85xx_timebase_freq(platform_t plat, struct cpuref *cpuref) 213192067Snwhitehorn{ 214217523Smarcel u_long ticks; 215209908Sraj phandle_t cpus, child; 216209908Sraj pcell_t freq; 217192067Snwhitehorn 218224618Smarcel if (bootinfo != NULL) { 219224611Smarcel if (bootinfo[0] == 1) { 220224611Smarcel /* Backward compatibility. See 8-STABLE. */ 221224611Smarcel ticks = bootinfo[3] >> 3; 222224611Smarcel } else { 223224618Smarcel /* Compatibility with Juniper's loader. */ 224224611Smarcel ticks = bootinfo[5] >> 3; 225224618Smarcel } 226222327Smarcel } else 227222327Smarcel ticks = 0; 228217523Smarcel 229228201Sjchandra if ((cpus = OF_finddevice("/cpus")) == -1) 230209908Sraj goto out; 231209908Sraj 232209908Sraj if ((child = OF_child(cpus)) == 0) 233209908Sraj goto out; 234209908Sraj 235256974Snwhitehorn switch (OF_getproplen(child, "timebase-frequency")) { 236256974Snwhitehorn case 4: 237256974Snwhitehorn { 238256974Snwhitehorn uint32_t tbase; 239256974Snwhitehorn OF_getprop(child, "timebase-frequency", &tbase, sizeof(tbase)); 240256974Snwhitehorn ticks = tbase; 241256974Snwhitehorn return (ticks); 242256974Snwhitehorn } 243256974Snwhitehorn case 8: 244256974Snwhitehorn { 245256974Snwhitehorn uint64_t tbase; 246256974Snwhitehorn OF_getprop(child, "timebase-frequency", &tbase, sizeof(tbase)); 247256974Snwhitehorn ticks = tbase; 248256974Snwhitehorn return (ticks); 249256974Snwhitehorn } 250256974Snwhitehorn default: 251256974Snwhitehorn break; 252256974Snwhitehorn } 253256973Snwhitehorn 254217523Smarcel freq = 0; 255209908Sraj if (OF_getprop(child, "bus-frequency", (void *)&freq, 256209908Sraj sizeof(freq)) <= 0) 257209908Sraj goto out; 258217523Smarcel 259192067Snwhitehorn /* 260192067Snwhitehorn * Time Base and Decrementer are updated every 8 CCB bus clocks. 261192067Snwhitehorn * HID0[SEL_TBCLK] = 0 262192067Snwhitehorn */ 263217523Smarcel if (freq != 0) 264217523Smarcel ticks = freq / 8; 265217523Smarcel 266209908Srajout: 267192067Snwhitehorn if (ticks <= 0) 268192067Snwhitehorn panic("Unable to determine timebase frequency!"); 269192067Snwhitehorn 270192067Snwhitehorn return (ticks); 271192067Snwhitehorn} 272192067Snwhitehorn 273192067Snwhitehornstatic int 274257995Snwhitehornmpc85xx_smp_first_cpu(platform_t plat, struct cpuref *cpuref) 275192067Snwhitehorn{ 276192067Snwhitehorn 277192067Snwhitehorn cpu = 0; 278192067Snwhitehorn cpuref->cr_cpuid = cpu; 279192067Snwhitehorn cpuref->cr_hwref = cpuref->cr_cpuid; 280192067Snwhitehorn if (bootverbose) 281192067Snwhitehorn printf("powerpc_smp_first_cpu: cpuid %d\n", cpuref->cr_cpuid); 282192067Snwhitehorn cpu++; 283192067Snwhitehorn 284192067Snwhitehorn return (0); 285192067Snwhitehorn} 286192067Snwhitehorn 287192067Snwhitehornstatic int 288257995Snwhitehornmpc85xx_smp_next_cpu(platform_t plat, struct cpuref *cpuref) 289192067Snwhitehorn{ 290192067Snwhitehorn 291193492Sraj if (cpu >= maxcpu) 292192067Snwhitehorn return (ENOENT); 293192067Snwhitehorn 294192067Snwhitehorn cpuref->cr_cpuid = cpu++; 295192067Snwhitehorn cpuref->cr_hwref = cpuref->cr_cpuid; 296192067Snwhitehorn if (bootverbose) 297192067Snwhitehorn printf("powerpc_smp_next_cpu: cpuid %d\n", cpuref->cr_cpuid); 298192067Snwhitehorn 299192067Snwhitehorn return (0); 300192067Snwhitehorn} 301192067Snwhitehorn 302192067Snwhitehornstatic int 303257995Snwhitehornmpc85xx_smp_get_bsp(platform_t plat, struct cpuref *cpuref) 304192067Snwhitehorn{ 305192067Snwhitehorn 306192067Snwhitehorn cpuref->cr_cpuid = mfspr(SPR_PIR); 307192067Snwhitehorn cpuref->cr_hwref = cpuref->cr_cpuid; 308192067Snwhitehorn 309192067Snwhitehorn return (0); 310192067Snwhitehorn} 311192067Snwhitehorn 312192067Snwhitehornstatic int 313257995Snwhitehornmpc85xx_smp_start_cpu(platform_t plat, struct pcpu *pc) 314192067Snwhitehorn{ 315192532Sraj#ifdef SMP 316242526Smarcel uint32_t *tlb1; 317192532Sraj uint32_t bptr, eebpcr; 318242526Smarcel int i, timeout; 319192067Snwhitehorn 320192532Sraj eebpcr = ccsr_read4(OCP85XX_EEBPCR); 321222813Sattilio if ((eebpcr & (1 << (pc->pc_cpuid + 24))) != 0) { 322235932Smarcel printf("SMP: CPU %d already out of hold-off state!\n", 323235932Smarcel pc->pc_cpuid); 324192532Sraj return (ENXIO); 325192532Sraj } 326192532Sraj 327192532Sraj ap_pcpu = pc; 328192532Sraj 329242526Smarcel i = 0; 330242526Smarcel tlb1 = bp_tlb1; 331242526Smarcel while (i < bp_ntlb1s && tlb1 < bp_tlb1_end) { 332242526Smarcel mtspr(SPR_MAS0, MAS0_TLBSEL(1) | MAS0_ESEL(i)); 333242526Smarcel __asm __volatile("isync; tlbre"); 334242526Smarcel tlb1[0] = mfspr(SPR_MAS1); 335242526Smarcel tlb1[1] = mfspr(SPR_MAS2); 336242526Smarcel tlb1[2] = mfspr(SPR_MAS3); 337242526Smarcel i++; 338242526Smarcel tlb1 += 3; 339242526Smarcel } 340242526Smarcel if (i < bp_ntlb1s) 341242526Smarcel bp_ntlb1s = i; 342242526Smarcel 343192532Sraj /* 344192532Sraj * Set BPTR to the physical address of the boot page 345192532Sraj */ 346242526Smarcel bptr = ((uint32_t)__boot_page - KERNBASE) + kernload; 347242526Smarcel KASSERT((bptr & 0xfff) == 0, 348242526Smarcel ("%s: boot page is not aligned (%#x)", __func__, bptr)); 349242526Smarcel bptr = (bptr >> 12) | 0x80000000u; 350242526Smarcel ccsr_write4(OCP85XX_BPTR, bptr); 351242526Smarcel __asm __volatile("isync; msync"); 352192532Sraj 353242526Smarcel /* Flush caches to have our changes hit DRAM. */ 354242526Smarcel cpu_flush_dcache(__boot_page, 4096); 355242526Smarcel 356192532Sraj /* 357192532Sraj * Release AP from hold-off state 358192532Sraj */ 359222813Sattilio eebpcr |= (1 << (pc->pc_cpuid + 24)); 360192532Sraj ccsr_write4(OCP85XX_EEBPCR, eebpcr); 361192532Sraj __asm __volatile("isync; msync"); 362192532Sraj 363192532Sraj timeout = 500; 364192532Sraj while (!pc->pc_awake && timeout--) 365192532Sraj DELAY(1000); /* wait 1ms */ 366192532Sraj 367235932Smarcel /* 368235932Smarcel * Disable boot page translation so that the 4K page at the default 369235932Smarcel * address (= 0xfffff000) isn't permanently remapped and thus not 370235932Smarcel * usable otherwise. 371235932Smarcel */ 372235932Smarcel ccsr_write4(OCP85XX_BPTR, 0); 373242526Smarcel __asm __volatile("isync; msync"); 374235932Smarcel 375235932Smarcel if (!pc->pc_awake) 376242526Smarcel printf("SMP: CPU %d didn't wake up.\n", pc->pc_cpuid); 377192532Sraj return ((pc->pc_awake) ? 0 : EBUSY); 378192532Sraj#else 379192067Snwhitehorn /* No SMP support */ 380192067Snwhitehorn return (ENXIO); 381192532Sraj#endif 382192067Snwhitehorn} 383212054Snwhitehorn 384212054Snwhitehornstatic void 385257995Snwhitehornmpc85xx_reset(platform_t plat) 386212054Snwhitehorn{ 387212054Snwhitehorn 388222392Smarcel /* 389222392Smarcel * Try the dedicated reset register first. 390222392Smarcel * If the SoC doesn't have one, we'll fall 391222392Smarcel * back to using the debug control register. 392222392Smarcel */ 393222392Smarcel ccsr_write4(OCP85XX_RSTCR, 2); 394212054Snwhitehorn 395222392Smarcel /* Clear DBCR0, disables debug interrupts and events. */ 396222392Smarcel mtspr(SPR_DBCR0, 0); 397222392Smarcel __asm __volatile("isync"); 398212054Snwhitehorn 399222392Smarcel /* Enable Debug Interrupts in MSR. */ 400222392Smarcel mtmsr(mfmsr() | PSL_DE); 401212054Snwhitehorn 402222392Smarcel /* Enable debug interrupts and issue reset. */ 403222392Smarcel mtspr(SPR_DBCR0, mfspr(SPR_DBCR0) | DBCR0_IDM | DBCR0_RST_SYSTEM); 404222392Smarcel 405212054Snwhitehorn printf("Reset failed...\n"); 406236097Sraj while (1) 407236097Sraj ; 408212054Snwhitehorn} 409212054Snwhitehorn 410