platform_bare.c revision 222327
11556Srgrimes/*- 21556Srgrimes * Copyright (c) 2008-2009 Semihalf, Rafal Jaworowski 31556Srgrimes * All rights reserved. 41556Srgrimes * 51556Srgrimes * Redistribution and use in source and binary forms, with or without 61556Srgrimes * modification, are permitted provided that the following conditions 71556Srgrimes * are met: 81556Srgrimes * 91556Srgrimes * 1. Redistributions of source code must retain the above copyright 101556Srgrimes * notice, this list of conditions and the following disclaimer. 111556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 121556Srgrimes * notice, this list of conditions and the following disclaimer in the 131556Srgrimes * documentation and/or other materials provided with the distribution. 141556Srgrimes * 151556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 161556Srgrimes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 171556Srgrimes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 181556Srgrimes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 191556Srgrimes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 201556Srgrimes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 211556Srgrimes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 221556Srgrimes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 231556Srgrimes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 241556Srgrimes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 251556Srgrimes */ 261556Srgrimes 271556Srgrimes#include <sys/cdefs.h> 281556Srgrimes__FBSDID("$FreeBSD: head/sys/powerpc/booke/platform_bare.c 222327 2011-05-26 20:47:05Z marcel $"); 291556Srgrimes 30114433Sobrien#include <sys/param.h> 311556Srgrimes#include <sys/systm.h> 3227959Ssteve#include <sys/kernel.h> 331556Srgrimes#include <sys/bus.h> 341556Srgrimes#include <sys/pcpu.h> 3527964Ssteve#include <sys/proc.h> 3627964Ssteve#include <sys/smp.h> 3727964Ssteve 3827964Ssteve#include <machine/bus.h> 39114433Sobrien#include <machine/cpu.h> 4027964Ssteve#include <machine/hid.h> 4199110Sobrien#include <machine/platform.h> 4299110Sobrien#include <machine/platformvar.h> 431556Srgrimes#include <machine/smp.h> 441556Srgrimes#include <machine/spr.h> 4547584Skris#include <machine/vmparam.h> 4647584Skris 471556Srgrimes#include <dev/fdt/fdt_common.h> 481556Srgrimes#include <dev/ofw/ofw_bus.h> 491556Srgrimes#include <dev/ofw/ofw_bus_subr.h> 501556Srgrimes#include <dev/ofw/openfirm.h> 511556Srgrimes 5290644Simp#include <powerpc/mpc85xx/mpc85xx.h> 5390644Simp 54241014Smdf#include "platform_if.h" 551556Srgrimes 561556Srgrimes#ifdef SMP 571556Srgrimesextern void *ap_pcpu; 5850539Smharoextern uint8_t __boot_page[]; /* Boot page body */ 591556Srgrimesextern uint32_t kernload; /* Kernel physical load address */ 601556Srgrimes#endif 61226961Sed 62249948Seadlerextern uint32_t *bootinfo; 63226961Sed 64226961Sedstatic int cpu, maxcpu; 651556Srgrimes 66249949Seadlerstatic int bare_probe(platform_t); 67249949Seadlerstatic void bare_mem_regions(platform_t, struct mem_region **phys, int *physsz, 68249949Seadler struct mem_region **avail, int *availsz); 69249949Seadlerstatic u_long bare_timebase_freq(platform_t, struct cpuref *cpuref); 70249949Seadlerstatic int bare_smp_first_cpu(platform_t, struct cpuref *cpuref); 71249949Seadlerstatic int bare_smp_next_cpu(platform_t, struct cpuref *cpuref); 72249949Seadlerstatic int bare_smp_get_bsp(platform_t, struct cpuref *cpuref); 73191670Simpstatic int bare_smp_start_cpu(platform_t, struct pcpu *cpu); 74249949Seadler 751556Srgrimesstatic void e500_reset(platform_t); 761556Srgrimes 771556Srgrimesstatic platform_method_t bare_methods[] = { 781556Srgrimes PLATFORMMETHOD(platform_probe, bare_probe), 79136112Sdes PLATFORMMETHOD(platform_mem_regions, bare_mem_regions), 801556Srgrimes PLATFORMMETHOD(platform_timebase_freq, bare_timebase_freq), 81136112Sdes 821556Srgrimes PLATFORMMETHOD(platform_smp_first_cpu, bare_smp_first_cpu), 831556Srgrimes PLATFORMMETHOD(platform_smp_next_cpu, bare_smp_next_cpu), 8490110Simp PLATFORMMETHOD(platform_smp_get_bsp, bare_smp_get_bsp), 851556Srgrimes PLATFORMMETHOD(platform_smp_start_cpu, bare_smp_start_cpu), 86137009Sdelphij 8754895Ssheldonh PLATFORMMETHOD(platform_reset, e500_reset), 881556Srgrimes 8954895Ssheldonh { 0, 0 } 9054895Ssheldonh}; 9154895Ssheldonh 9254895Ssheldonhstatic platform_def_t bare_platform = { 9354895Ssheldonh "bare metal", 94219680Sjilles bare_methods, 9554895Ssheldonh 0 9654895Ssheldonh}; 9754895Ssheldonh 9854895SsheldonhPLATFORM_DEF(bare_platform); 9997533Stjr 10054895Ssheldonhstatic int 10197533Stjrbare_probe(platform_t plat) 10297533Stjr{ 10399858Stjr uint32_t ver, sr; 10497533Stjr int i, law_max, tgt; 10597533Stjr 10697533Stjr ver = SVR_VER(mfspr(SPR_SVR)); 10754895Ssheldonh if (ver == SVR_MPC8572E || ver == SVR_MPC8572) 10854895Ssheldonh maxcpu = 2; 109249948Seadler else 110249948Seadler maxcpu = 1; 1111556Srgrimes 1121556Srgrimes /* 1131556Srgrimes * Clear local access windows. Skip DRAM entries, so we don't shoot 1141556Srgrimes * ourselves in the foot. 1151556Srgrimes */ 1161556Srgrimes law_max = law_getmax(); 1171556Srgrimes for (i = 0; i < law_max; i++) { 1181556Srgrimes sr = ccsr_read4(OCP85XX_LAWSR(i)); 1191556Srgrimes if ((sr & 0x80000000) == 0) 1201556Srgrimes continue; 1211556Srgrimes tgt = (sr & 0x01f00000) >> 20; 1221556Srgrimes if (tgt == OCP85XX_TGTIF_RAM1 || tgt == OCP85XX_TGTIF_RAM2 || 123137009Sdelphij tgt == OCP85XX_TGTIF_RAM_INTL) 124137009Sdelphij continue; 125137009Sdelphij 1261556Srgrimes ccsr_write4(OCP85XX_LAWSR(i), sr & 0x7fffffff); 1271556Srgrimes } 1281556Srgrimes 1291556Srgrimes return (BUS_PROBE_GENERIC); 1301556Srgrimes} 1311556Srgrimes 1321556Srgrimes#define MEM_REGIONS 8 13350872Smharostatic struct mem_region avail_regions[MEM_REGIONS]; 13450872Smharo 13550872Smharovoid 13620421Sstevebare_mem_regions(platform_t plat, struct mem_region **phys, int *physsz, 13720421Ssteve struct mem_region **avail, int *availsz) 13820421Ssteve{ 139249948Seadler uint32_t memsize; 140249948Seadler int i, rv; 141249948Seadler 1421556Srgrimes rv = fdt_get_mem_regions(avail_regions, availsz, &memsize); 1431556Srgrimes 1441556Srgrimes if (rv != 0) 1451556Srgrimes return; 1461556Srgrimes 1471556Srgrimes for (i = 0; i < *availsz; i++) { 14844282Sjkh if (avail_regions[i].mr_start < 1048576) { 14944282Sjkh avail_regions[i].mr_size = 150122409Sguido avail_regions[i].mr_size - 1511556Srgrimes (1048576 - avail_regions[i].mr_start); 15244282Sjkh avail_regions[i].mr_start = 1048576; 1531556Srgrimes } 1541556Srgrimes } 155136124Sdes *avail = avail_regions; 156136124Sdes 1577798Sache /* On the bare metal platform phys == avail memory */ 1581556Srgrimes *physsz = *availsz; 159191670Simp *phys = *avail; 16020421Ssteve} 16120421Ssteve 16220421Sstevestatic u_long 163137009Sdelphijbare_timebase_freq(platform_t plat, struct cpuref *cpuref) 164137009Sdelphij{ 165137009Sdelphij u_long ticks; 166137009Sdelphij phandle_t cpus, child; 16720421Ssteve pcell_t freq; 16820421Ssteve 16920421Ssteve if (bootinfo != NULL) { 17020421Ssteve /* Backward compatibility. See 8-STABLE. */ 17120421Ssteve ticks = bootinfo[3] >> 3; 17220421Ssteve } else 1731556Srgrimes ticks = 0; 1741556Srgrimes 1751556Srgrimes if ((cpus = OF_finddevice("/cpus")) == 0) 176249949Seadler goto out; 17790110Simp 1781556Srgrimes if ((child = OF_child(cpus)) == 0) 1791556Srgrimes goto out; 1801556Srgrimes 1811556Srgrimes freq = 0; 18220421Ssteve if (OF_getprop(child, "bus-frequency", (void *)&freq, 1837798Sache sizeof(freq)) <= 0) 1841556Srgrimes goto out; 1851556Srgrimes 1861556Srgrimes /* 1871556Srgrimes * Time Base and Decrementer are updated every 8 CCB bus clocks. 1881556Srgrimes * HID0[SEL_TBCLK] = 0 18920421Ssteve */ 1901556Srgrimes if (freq != 0) 1911556Srgrimes ticks = freq / 8; 1921556Srgrimes 1931556Srgrimesout: 1941556Srgrimes if (ticks <= 0) 1951556Srgrimes panic("Unable to determine timebase frequency!"); 1961556Srgrimes 19751230Sbde return (ticks); 19820421Ssteve} 19920421Ssteve 20020421Sstevestatic int 20120421Sstevebare_smp_first_cpu(platform_t plat, struct cpuref *cpuref) 202249948Seadler{ 203249948Seadler 204137639Sjkh cpu = 0; 205137639Sjkh cpuref->cr_cpuid = cpu; 206137639Sjkh cpuref->cr_hwref = cpuref->cr_cpuid; 20799744Sdillon if (bootverbose) 208137639Sjkh printf("powerpc_smp_first_cpu: cpuid %d\n", cpuref->cr_cpuid); 2091556Srgrimes cpu++; 2101556Srgrimes 2111556Srgrimes return (0); 2121556Srgrimes} 2131556Srgrimes 2141556Srgrimesstatic int 2151556Srgrimesbare_smp_next_cpu(platform_t plat, struct cpuref *cpuref) 2161556Srgrimes{ 2171556Srgrimes 2181556Srgrimes if (cpu >= maxcpu) 2191556Srgrimes return (ENOENT); 2201556Srgrimes 2211556Srgrimes cpuref->cr_cpuid = cpu++; 222124041Skuriyama cpuref->cr_hwref = cpuref->cr_cpuid; 223124041Skuriyama if (bootverbose) 2241556Srgrimes printf("powerpc_smp_next_cpu: cpuid %d\n", cpuref->cr_cpuid); 2251556Srgrimes 2261556Srgrimes return (0); 2271556Srgrimes} 2281556Srgrimes 2291556Srgrimesstatic int 2301556Srgrimesbare_smp_get_bsp(platform_t plat, struct cpuref *cpuref) 2311556Srgrimes{ 2321556Srgrimes 2331556Srgrimes cpuref->cr_cpuid = mfspr(SPR_PIR); 2341556Srgrimes cpuref->cr_hwref = cpuref->cr_cpuid; 23520421Ssteve 2361556Srgrimes return (0); 2371556Srgrimes} 2381556Srgrimes 2391556Srgrimesstatic int 2407798Sachebare_smp_start_cpu(platform_t plat, struct pcpu *pc) 2417798Sache{ 2427798Sache#ifdef SMP 243193087Sjilles uint32_t bptr, eebpcr; 2447798Sache int timeout; 2457798Sache 2461556Srgrimes eebpcr = ccsr_read4(OCP85XX_EEBPCR); 2471556Srgrimes if ((eebpcr & (pc->pc_cpumask << 24)) != 0) { 2481556Srgrimes printf("%s: CPU=%d already out of hold-off state!\n", 2491556Srgrimes __func__, pc->pc_cpuid); 2501556Srgrimes return (ENXIO); 2511556Srgrimes } 25220421Ssteve 25320421Ssteve ap_pcpu = pc; 25420421Ssteve __asm __volatile("msync; isync"); 25520421Ssteve 2561556Srgrimes /* 2571556Srgrimes * Set BPTR to the physical address of the boot page 2587798Sache */ 2597798Sache bptr = ((uint32_t)__boot_page - KERNBASE) + kernload; 2607798Sache ccsr_write4(OCP85XX_BPTR, (bptr >> 12) | 0x80000000); 2617798Sache 262193087Sjilles /* 2637798Sache * Release AP from hold-off state 26453819Smharo */ 2657798Sache eebpcr |= (pc->pc_cpumask << 24); 2667798Sache ccsr_write4(OCP85XX_EEBPCR, eebpcr); 2677798Sache __asm __volatile("isync; msync"); 2687798Sache 2697798Sache timeout = 500; 27020421Ssteve while (!pc->pc_awake && timeout--) 27120421Ssteve DELAY(1000); /* wait 1ms */ 27220421Ssteve 27353819Smharo return ((pc->pc_awake) ? 0 : EBUSY); 27453819Smharo#else 27553819Smharo /* No SMP support */ 27650872Smharo return (ENXIO); 27770219Sobrien#endif 278191670Simp} 279191670Simp 280191670Simpstatic void 281191670Simpe500_reset(platform_t plat) 282191670Simp{ 2831556Srgrimes uint32_t ver = SVR_VER(mfspr(SPR_SVR)); 28450539Smharo 28520421Ssteve if (ver == SVR_MPC8572E || ver == SVR_MPC8572 || 28620421Ssteve ver == SVR_MPC8548E || ver == SVR_MPC8548) 28720421Ssteve /* Systems with dedicated reset register */ 28853819Smharo ccsr_write4(OCP85XX_RSTCR, 2); 28953819Smharo else { 29053819Smharo /* Clear DBCR0, disables debug interrupts and events. */ 29150872Smharo mtspr(SPR_DBCR0, 0); 29270219Sobrien __asm __volatile("isync"); 293191670Simp 294191670Simp /* Enable Debug Interrupts in MSR. */ 295191670Simp mtmsr(mfmsr() | PSL_DE); 296191670Simp 297191670Simp /* Enable debug interrupts and issue reset. */ 29820421Ssteve mtspr(SPR_DBCR0, mfspr(SPR_DBCR0) | DBCR0_IDM | 29950539Smharo DBCR0_RST_SYSTEM); 30020421Ssteve } 30120421Ssteve 302124041Skuriyama printf("Reset failed...\n"); 303124041Skuriyama while (1); 304124041Skuriyama} 305124041Skuriyama 306124041Skuriyama