1 /*- 2 * Copyright (c) 2008-2009 Semihalf, Rafal Jaworowski 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <sys/param.h> 31 #include <sys/systm.h> 32 #include <sys/kernel.h> 33 #include <sys/bus.h> 34 #include <sys/pcpu.h> 35 #include <sys/proc.h> 36 #include <sys/smp.h> 37 38 #include <machine/bootinfo.h> 39 #include <machine/bus.h> 40 #include <machine/cpu.h> 41 #include <machine/hid.h> 42 #include <machine/platform.h> 43 #include <machine/platformvar.h> 44 #include <machine/smp.h> 45 #include <machine/spr.h> 46 #include <machine/vmparam.h> 47 48 #include <powerpc/mpc85xx/mpc85xx.h> 49 #include <powerpc/mpc85xx/ocpbus.h> 50 51 #include "platform_if.h" 52 53 #ifdef SMP 54 extern void *ap_pcpu; 55 extern uint8_t __boot_page[]; /* Boot page body */ 56 extern uint32_t kernload; /* Kernel physical load address */ 57 #endif 58 59 static int cpu, maxcpu; 60 61 static int bare_probe(platform_t); 62 static void bare_mem_regions(platform_t, struct mem_region **phys, int *physsz, 63 struct mem_region **avail, int *availsz); 64 static u_long bare_timebase_freq(platform_t, struct cpuref *cpuref); 65 static int bare_smp_first_cpu(platform_t, struct cpuref *cpuref); 66 static int bare_smp_next_cpu(platform_t, struct cpuref *cpuref); 67 static int bare_smp_get_bsp(platform_t, struct cpuref *cpuref); 68 static int bare_smp_start_cpu(platform_t, struct pcpu *cpu); 69 70 static platform_method_t bare_methods[] = { 71 PLATFORMMETHOD(platform_probe, bare_probe), 72 PLATFORMMETHOD(platform_mem_regions, bare_mem_regions), 73 PLATFORMMETHOD(platform_timebase_freq, bare_timebase_freq), 74 75 PLATFORMMETHOD(platform_smp_first_cpu, bare_smp_first_cpu), 76 PLATFORMMETHOD(platform_smp_next_cpu, bare_smp_next_cpu), 77 PLATFORMMETHOD(platform_smp_get_bsp, bare_smp_get_bsp), 78 PLATFORMMETHOD(platform_smp_start_cpu, bare_smp_start_cpu), 79 80 { 0, 0 } 81 }; 82 83 static platform_def_t bare_platform = { 84 "bare metal", 85 bare_methods, 86 0 87 }; 88 89 PLATFORM_DEF(bare_platform); 90 91 static int 92 bare_probe(platform_t plat) 93 { 94 uint32_t ver; 95 96 ver = SVR_VER(mfspr(SPR_SVR)); 97 if (ver == SVR_MPC8572E || ver == SVR_MPC8572) 98 maxcpu = 2; 99 else 100 maxcpu = 1; 101 102 return (BUS_PROBE_GENERIC); 103 } 104 105 #define MEM_REGIONS 8 106 static struct mem_region avail_regions[MEM_REGIONS]; 107 108 void 109 bare_mem_regions(platform_t plat, struct mem_region **phys, int *physsz, 110 struct mem_region **avail, int *availsz) 111 { 112 struct bi_mem_region *mr; 113 int i; 114 115 /* Initialize memory regions table */ 116 mr = bootinfo_mr(); 117 for (i = 0; i < bootinfo->bi_mem_reg_no; i++, mr++) { 118 if (i == MEM_REGIONS) 119 break; 120 if (mr->mem_base < 1048576) { 121 avail_regions[i].mr_start = 1048576; 122 avail_regions[i].mr_size = mr->mem_size - 123 (1048576 - mr->mem_base); 124 } else { 125 avail_regions[i].mr_start = mr->mem_base; 126 avail_regions[i].mr_size = mr->mem_size; 127 } 128 } 129 *availsz = i; 130 *avail = avail_regions; 131 132 /* On the bare metal platform phys == avail memory */ 133 *physsz = *availsz; 134 *phys = *avail; 135 } 136 137 static u_long 138 bare_timebase_freq(platform_t plat, struct cpuref *cpuref) 139 { 140 u_long ticks = -1; 141 142 /* 143 * Time Base and Decrementer are updated every 8 CCB bus clocks. 144 * HID0[SEL_TBCLK] = 0 145 */ 146 ticks = bootinfo->bi_bus_clk / 8; 147 if (ticks <= 0) 148 panic("Unable to determine timebase frequency!"); 149 150 return (ticks); 151 } 152 153 static int 154 bare_smp_first_cpu(platform_t plat, struct cpuref *cpuref) 155 { 156 157 cpu = 0; 158 cpuref->cr_cpuid = cpu; 159 cpuref->cr_hwref = cpuref->cr_cpuid; 160 if (bootverbose) 161 printf("powerpc_smp_first_cpu: cpuid %d\n", cpuref->cr_cpuid); 162 cpu++; 163 164 return (0); 165 } 166 167 static int 168 bare_smp_next_cpu(platform_t plat, struct cpuref *cpuref) 169 { 170 171 if (cpu >= maxcpu) 172 return (ENOENT); 173 174 cpuref->cr_cpuid = cpu++; 175 cpuref->cr_hwref = cpuref->cr_cpuid; 176 if (bootverbose) 177 printf("powerpc_smp_next_cpu: cpuid %d\n", cpuref->cr_cpuid); 178 179 return (0); 180 } 181 182 static int 183 bare_smp_get_bsp(platform_t plat, struct cpuref *cpuref) 184 { 185 186 cpuref->cr_cpuid = mfspr(SPR_PIR); 187 cpuref->cr_hwref = cpuref->cr_cpuid; 188 189 return (0); 190 } 191 192 static int 193 bare_smp_start_cpu(platform_t plat, struct pcpu *pc) 194 { 195 #ifdef SMP 196 uint32_t bptr, eebpcr; 197 int timeout; 198 199 eebpcr = ccsr_read4(OCP85XX_EEBPCR); 200 if ((eebpcr & (pc->pc_cpumask << 24)) != 0) { 201 printf("%s: CPU=%d already out of hold-off state!\n", 202 __func__, pc->pc_cpuid); 203 return (ENXIO); 204 } 205 206 ap_pcpu = pc; 207 __asm __volatile("msync; isync"); 208 209 /* 210 * Set BPTR to the physical address of the boot page 211 */ 212 bptr = ((uint32_t)__boot_page - KERNBASE) + kernload; 213 ccsr_write4(OCP85XX_BPTR, (bptr >> 12) | 0x80000000); 214 215 /* 216 * Release AP from hold-off state 217 */ 218 eebpcr |= (pc->pc_cpumask << 24); 219 ccsr_write4(OCP85XX_EEBPCR, eebpcr); 220 __asm __volatile("isync; msync"); 221 222 timeout = 500; 223 while (!pc->pc_awake && timeout--) 224 DELAY(1000); /* wait 1ms */ 225 226 return ((pc->pc_awake) ? 0 : EBUSY); 227 #else 228 /* No SMP support */ 229 return (ENXIO); 230 #endif 231 } 232