1 /*- 2 * Copyright (c) 2008 Marcel Moolenaar 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/bat.h> 39 #include <machine/bus.h> 40 #include <machine/cpu.h> 41 #include <machine/hid.h> 42 #include <machine/intr_machdep.h> 43 #include <machine/pcb.h> 44 #include <machine/psl.h> 45 #include <machine/smp.h> 46 #include <machine/spr.h> 47 #include <machine/trap_aim.h> 48 49 #include <dev/ofw/openfirm.h> 50 #include <machine/ofw_machdep.h> 51 52 extern void *rstcode; 53 extern register_t l2cr_config; 54 extern register_t l3cr_config; 55 56 void *ap_pcpu; 57 58 static int 59 powerpc_smp_fill_cpuref(struct cpuref *cpuref, phandle_t cpu) 60 { 61 int cpuid, res; 62 63 cpuref->cr_hwref = cpu; 64 res = OF_getprop(cpu, "reg", &cpuid, sizeof(cpuid)); 65 if (res < 0) 66 return (ENOENT); 67 68 cpuref->cr_cpuid = cpuid & 0xff; 69 return (0); 70 } 71 72 int 73 powerpc_smp_first_cpu(struct cpuref *cpuref) 74 { 75 char buf[8]; 76 phandle_t cpu, dev, root; 77 int res; 78 79 root = OF_peer(0); 80 81 dev = OF_child(root); 82 while (dev != 0) { 83 res = OF_getprop(dev, "name", buf, sizeof(buf)); 84 if (res > 0 && strcmp(buf, "cpus") == 0) 85 break; 86 dev = OF_peer(dev); 87 } 88 if (dev == 0) 89 return (ENOENT); 90 91 cpu = OF_child(dev); 92 while (cpu != 0) { 93 res = OF_getprop(cpu, "device_type", buf, sizeof(buf)); 94 if (res > 0 && strcmp(buf, "cpu") == 0) 95 break; 96 cpu = OF_peer(cpu); 97 } 98 if (cpu == 0) 99 return (ENOENT); 100 101 return (powerpc_smp_fill_cpuref(cpuref, cpu)); 102 } 103 104 int 105 powerpc_smp_next_cpu(struct cpuref *cpuref) 106 { 107 char buf[8]; 108 phandle_t cpu; 109 int res; 110 111 cpu = OF_peer(cpuref->cr_hwref); 112 while (cpu != 0) { 113 res = OF_getprop(cpu, "device_type", buf, sizeof(buf)); 114 if (res > 0 && strcmp(buf, "cpu") == 0) 115 break; 116 cpu = OF_peer(cpu); 117 } 118 if (cpu == 0) 119 return (ENOENT); 120 121 return (powerpc_smp_fill_cpuref(cpuref, cpu)); 122 } 123 124 int 125 powerpc_smp_get_bsp(struct cpuref *cpuref) 126 { 127 ihandle_t inst; 128 phandle_t bsp, chosen; 129 int res; 130 131 chosen = OF_finddevice("/chosen"); 132 if (chosen == 0) 133 return (ENXIO); 134 135 res = OF_getprop(chosen, "cpu", &inst, sizeof(inst)); 136 if (res < 0) 137 return (ENXIO); 138 139 bsp = OF_instance_to_package(inst); 140 return (powerpc_smp_fill_cpuref(cpuref, bsp)); 141 } 142 143 static register_t 144 l2_enable(void) 145 { 146 register_t ccr; 147 148 ccr = mfspr(SPR_L2CR); 149 if (ccr & L2CR_L2E) 150 return (ccr); 151 152 /* Configure L2 cache. */ 153 ccr = l2cr_config & ~L2CR_L2E; 154 mtspr(SPR_L2CR, ccr | L2CR_L2I); 155 do { 156 ccr = mfspr(SPR_L2CR); 157 } while (ccr & L2CR_L2I); 158 powerpc_sync(); 159 mtspr(SPR_L2CR, l2cr_config); 160 powerpc_sync(); 161 162 return (l2cr_config); 163 } 164 165 static register_t 166 l3_enable(void) 167 { 168 register_t ccr; 169 170 ccr = mfspr(SPR_L3CR); 171 if (ccr & L3CR_L3E) 172 return (ccr); 173 174 /* Configure L3 cache. */ 175 ccr = l3cr_config & ~(L3CR_L3E | L3CR_L3I | L3CR_L3PE | L3CR_L3CLKEN); 176 mtspr(SPR_L3CR, ccr); 177 ccr |= 0x4000000; /* Magic, but documented. */ 178 mtspr(SPR_L3CR, ccr); 179 ccr |= L3CR_L3CLKEN; 180 mtspr(SPR_L3CR, ccr); 181 mtspr(SPR_L3CR, ccr | L3CR_L3I); 182 while (mfspr(SPR_L3CR) & L3CR_L3I) 183 ; 184 mtspr(SPR_L3CR, ccr & ~L3CR_L3CLKEN); 185 powerpc_sync(); 186 DELAY(100); 187 mtspr(SPR_L3CR, ccr); 188 powerpc_sync(); 189 DELAY(100); 190 ccr |= L3CR_L3E; 191 mtspr(SPR_L3CR, ccr); 192 powerpc_sync(); 193 194 return(ccr); 195 } 196 197 static register_t 198 l1d_enable(void) 199 { 200 register_t hid; 201 202 hid = mfspr(SPR_HID0); 203 if (hid & HID0_DCE) 204 return (hid); 205 206 /* Enable L1 D-cache */ 207 hid |= HID0_DCE; 208 powerpc_sync(); 209 mtspr(SPR_HID0, hid | HID0_DCFI); 210 powerpc_sync(); 211 212 return (hid); 213 } 214 215 static register_t 216 l1i_enable(void) 217 { 218 register_t hid; 219 220 hid = mfspr(SPR_HID0); 221 if (hid & HID0_ICE) 222 return (hid); 223 224 /* Enable L1 I-cache */ 225 hid |= HID0_ICE; 226 isync(); 227 mtspr(SPR_HID0, hid | HID0_ICFI); 228 isync(); 229 230 return (hid); 231 } 232 233 uint32_t 234 cpudep_ap_bootstrap(void) 235 { 236 uint32_t hid, msr, reg, sp; 237 238 // reg = mfspr(SPR_MSSCR0); 239 // mtspr(SPR_MSSCR0, reg | 0x3); 240 241 __asm __volatile("mtsprg 0, %0" :: "r"(ap_pcpu)); 242 powerpc_sync(); 243 244 __asm __volatile("mtspr 1023,%0" :: "r"(PCPU_GET(cpuid))); 245 __asm __volatile("mfspr %0,1023" : "=r"(pcpup->pc_pir)); 246 247 msr = PSL_FP | PSL_IR | PSL_DR | PSL_ME | PSL_RI; 248 powerpc_sync(); 249 isync(); 250 mtmsr(msr); 251 isync(); 252 253 reg = l3_enable(); 254 reg = l2_enable(); 255 reg = l1d_enable(); 256 reg = l1i_enable(); 257 258 hid = mfspr(SPR_HID0); 259 hid &= ~(HID0_DOZE | HID0_SLEEP); 260 hid |= HID0_NAP | HID0_DPM; 261 mtspr(SPR_HID0, hid); 262 isync(); 263 264 pcpup->pc_curthread = pcpup->pc_idlethread; 265 pcpup->pc_curpcb = pcpup->pc_curthread->td_pcb; 266 sp = pcpup->pc_curpcb->pcb_sp; 267 268 return (sp); 269 } 270 271 int 272 powerpc_smp_start_cpu(struct pcpu *pc) 273 { 274 phandle_t cpu; 275 volatile uint8_t *rstvec; 276 int res, reset, timeout; 277 278 cpu = pc->pc_hwref; 279 res = OF_getprop(cpu, "soft-reset", &reset, sizeof(reset)); 280 if (res < 0) 281 return (ENXIO); 282 283 ap_pcpu = pc; 284 285 rstvec = (uint8_t *)(0x80000000 + reset); 286 287 *rstvec = 4; 288 powerpc_sync(); 289 DELAY(1); 290 *rstvec = 0; 291 powerpc_sync(); 292 293 timeout = 1000; 294 while (!pc->pc_awake && timeout--) 295 DELAY(100); 296 297 return ((pc->pc_awake) ? 0 : EBUSY); 298 } 299