1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2008 Marcel Moolenaar 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/kernel.h> 35 #include <sys/bus.h> 36 #include <sys/pcpu.h> 37 #include <sys/proc.h> 38 #include <sys/sched.h> 39 #include <sys/smp.h> 40 41 #include <machine/bus.h> 42 #include <machine/cpu.h> 43 #include <machine/hid.h> 44 #include <machine/intr_machdep.h> 45 #include <machine/pcb.h> 46 #include <machine/psl.h> 47 #include <machine/smp.h> 48 #include <machine/spr.h> 49 #include <machine/trap.h> 50 51 #include <dev/ofw/openfirm.h> 52 #include <machine/ofw_machdep.h> 53 54 void *ap_pcpu; 55 56 static register_t bsp_state[8] __aligned(8); 57 58 static void cpudep_save_config(void *dummy); 59 SYSINIT(cpu_save_config, SI_SUB_CPU, SI_ORDER_ANY, cpudep_save_config, NULL); 60 61 void 62 cpudep_ap_early_bootstrap(void) 63 { 64 #ifndef __powerpc64__ 65 register_t reg; 66 #endif 67 68 switch (mfpvr() >> 16) { 69 case IBM970: 70 case IBM970FX: 71 case IBM970MP: 72 /* Set HIOR to 0 */ 73 __asm __volatile("mtspr 311,%0" :: "r"(0)); 74 powerpc_sync(); 75 76 /* Restore HID4 and HID5, which are necessary for the MMU */ 77 78 #ifdef __powerpc64__ 79 mtspr(SPR_HID4, bsp_state[2]); powerpc_sync(); isync(); 80 mtspr(SPR_HID5, bsp_state[3]); powerpc_sync(); isync(); 81 #else 82 __asm __volatile("ld %0, 16(%2); sync; isync; \ 83 mtspr %1, %0; sync; isync;" 84 : "=r"(reg) : "K"(SPR_HID4), "b"(bsp_state)); 85 __asm __volatile("ld %0, 24(%2); sync; isync; \ 86 mtspr %1, %0; sync; isync;" 87 : "=r"(reg) : "K"(SPR_HID5), "b"(bsp_state)); 88 #endif 89 powerpc_sync(); 90 break; 91 case IBMPOWER8: 92 case IBMPOWER8E: 93 case IBMPOWER8NVL: 94 case IBMPOWER9: 95 #ifdef __powerpc64__ 96 if (mfmsr() & PSL_HV) { 97 isync(); 98 /* 99 * Direct interrupts to SRR instead of HSRR and 100 * reset LPCR otherwise 101 */ 102 mtspr(SPR_LPID, 0); 103 isync(); 104 105 mtspr(SPR_LPCR, lpcr); 106 isync(); 107 108 /* 109 * Nuke FSCR, to be managed on a per-process basis 110 * later. 111 */ 112 mtspr(SPR_FSCR, 0); 113 } 114 #endif 115 break; 116 } 117 118 __asm __volatile("mtsprg 0, %0" :: "r"(ap_pcpu)); 119 powerpc_sync(); 120 } 121 122 uintptr_t 123 cpudep_ap_bootstrap(void) 124 { 125 register_t msr, sp; 126 127 msr = psl_kernset & ~PSL_EE; 128 mtmsr(msr); 129 130 pcpup->pc_curthread = pcpup->pc_idlethread; 131 #ifdef __powerpc64__ 132 __asm __volatile("mr 13,%0" :: "r"(pcpup->pc_curthread)); 133 #else 134 __asm __volatile("mr 2,%0" :: "r"(pcpup->pc_curthread)); 135 #endif 136 pcpup->pc_curpcb = pcpup->pc_curthread->td_pcb; 137 sp = pcpup->pc_curpcb->pcb_sp; 138 schedinit_ap(); 139 140 return (sp); 141 } 142 143 static register_t 144 mpc74xx_l2_enable(register_t l2cr_config) 145 { 146 register_t ccr, bit; 147 uint16_t vers; 148 149 vers = mfpvr() >> 16; 150 switch (vers) { 151 case MPC7400: 152 case MPC7410: 153 bit = L2CR_L2IP; 154 break; 155 default: 156 bit = L2CR_L2I; 157 break; 158 } 159 160 ccr = mfspr(SPR_L2CR); 161 if (ccr & L2CR_L2E) 162 return (ccr); 163 164 /* Configure L2 cache. */ 165 ccr = l2cr_config & ~L2CR_L2E; 166 mtspr(SPR_L2CR, ccr | L2CR_L2I); 167 do { 168 ccr = mfspr(SPR_L2CR); 169 } while (ccr & bit); 170 powerpc_sync(); 171 mtspr(SPR_L2CR, l2cr_config); 172 powerpc_sync(); 173 174 return (l2cr_config); 175 } 176 177 static register_t 178 mpc745x_l3_enable(register_t l3cr_config) 179 { 180 register_t ccr; 181 182 ccr = mfspr(SPR_L3CR); 183 if (ccr & L3CR_L3E) 184 return (ccr); 185 186 /* Configure L3 cache. */ 187 ccr = l3cr_config & ~(L3CR_L3E | L3CR_L3I | L3CR_L3PE | L3CR_L3CLKEN); 188 mtspr(SPR_L3CR, ccr); 189 ccr |= 0x4000000; /* Magic, but documented. */ 190 mtspr(SPR_L3CR, ccr); 191 ccr |= L3CR_L3CLKEN; 192 mtspr(SPR_L3CR, ccr); 193 mtspr(SPR_L3CR, ccr | L3CR_L3I); 194 while (mfspr(SPR_L3CR) & L3CR_L3I) 195 ; 196 mtspr(SPR_L3CR, ccr & ~L3CR_L3CLKEN); 197 powerpc_sync(); 198 DELAY(100); 199 mtspr(SPR_L3CR, ccr); 200 powerpc_sync(); 201 DELAY(100); 202 ccr |= L3CR_L3E; 203 mtspr(SPR_L3CR, ccr); 204 powerpc_sync(); 205 206 return(ccr); 207 } 208 209 static register_t 210 mpc74xx_l1d_enable(void) 211 { 212 register_t hid; 213 214 hid = mfspr(SPR_HID0); 215 if (hid & HID0_DCE) 216 return (hid); 217 218 /* Enable L1 D-cache */ 219 hid |= HID0_DCE; 220 powerpc_sync(); 221 mtspr(SPR_HID0, hid | HID0_DCFI); 222 powerpc_sync(); 223 224 return (hid); 225 } 226 227 static register_t 228 mpc74xx_l1i_enable(void) 229 { 230 register_t hid; 231 232 hid = mfspr(SPR_HID0); 233 if (hid & HID0_ICE) 234 return (hid); 235 236 /* Enable L1 I-cache */ 237 hid |= HID0_ICE; 238 isync(); 239 mtspr(SPR_HID0, hid | HID0_ICFI); 240 isync(); 241 242 return (hid); 243 } 244 245 static void 246 cpudep_save_config(void *dummy) 247 { 248 uint16_t vers; 249 250 vers = mfpvr() >> 16; 251 252 switch(vers) { 253 case IBM970: 254 case IBM970FX: 255 case IBM970MP: 256 #ifdef __powerpc64__ 257 bsp_state[0] = mfspr(SPR_HID0); 258 bsp_state[1] = mfspr(SPR_HID1); 259 bsp_state[2] = mfspr(SPR_HID4); 260 bsp_state[3] = mfspr(SPR_HID5); 261 #else 262 __asm __volatile ("mfspr %0,%2; mr %1,%0; srdi %0,%0,32" 263 : "=r" (bsp_state[0]),"=r" (bsp_state[1]) : "K" (SPR_HID0)); 264 __asm __volatile ("mfspr %0,%2; mr %1,%0; srdi %0,%0,32" 265 : "=r" (bsp_state[2]),"=r" (bsp_state[3]) : "K" (SPR_HID1)); 266 __asm __volatile ("mfspr %0,%2; mr %1,%0; srdi %0,%0,32" 267 : "=r" (bsp_state[4]),"=r" (bsp_state[5]) : "K" (SPR_HID4)); 268 __asm __volatile ("mfspr %0,%2; mr %1,%0; srdi %0,%0,32" 269 : "=r" (bsp_state[6]),"=r" (bsp_state[7]) : "K" (SPR_HID5)); 270 #endif 271 272 powerpc_sync(); 273 274 break; 275 case IBMCELLBE: 276 #ifdef NOTYET /* Causes problems if in instruction stream on 970 */ 277 if (mfmsr() & PSL_HV) { 278 bsp_state[0] = mfspr(SPR_HID0); 279 bsp_state[1] = mfspr(SPR_HID1); 280 bsp_state[2] = mfspr(SPR_HID4); 281 bsp_state[3] = mfspr(SPR_HID6); 282 283 bsp_state[4] = mfspr(SPR_CELL_TSCR); 284 } 285 #endif 286 287 bsp_state[5] = mfspr(SPR_CELL_TSRL); 288 289 break; 290 case MPC7450: 291 case MPC7455: 292 case MPC7457: 293 /* Only MPC745x CPUs have an L3 cache. */ 294 bsp_state[3] = mfspr(SPR_L3CR); 295 296 /* Fallthrough */ 297 case MPC7400: 298 case MPC7410: 299 case MPC7447A: 300 case MPC7448: 301 bsp_state[2] = mfspr(SPR_L2CR); 302 bsp_state[1] = mfspr(SPR_HID1); 303 bsp_state[0] = mfspr(SPR_HID0); 304 break; 305 } 306 } 307 308 void 309 cpudep_ap_setup() 310 { 311 register_t reg; 312 uint16_t vers; 313 314 vers = mfpvr() >> 16; 315 316 switch(vers) { 317 case IBM970: 318 case IBM970FX: 319 case IBM970MP: 320 /* 321 * The 970 has strange rules about how to update HID registers. 322 * See Table 2-3, 970MP manual 323 * 324 * Note: HID4 and HID5 restored already in 325 * cpudep_ap_early_bootstrap() 326 */ 327 328 __asm __volatile("mtasr %0; sync" :: "r"(0)); 329 #ifdef __powerpc64__ 330 __asm __volatile(" \ 331 sync; isync; \ 332 mtspr %1, %0; \ 333 mfspr %0, %1; mfspr %0, %1; mfspr %0, %1; \ 334 mfspr %0, %1; mfspr %0, %1; mfspr %0, %1; \ 335 sync; isync" 336 :: "r"(bsp_state[0]), "K"(SPR_HID0)); 337 __asm __volatile("sync; isync; \ 338 mtspr %1, %0; mtspr %1, %0; sync; isync" 339 :: "r"(bsp_state[1]), "K"(SPR_HID1)); 340 #else 341 __asm __volatile(" \ 342 ld %0,0(%2); \ 343 sync; isync; \ 344 mtspr %1, %0; \ 345 mfspr %0, %1; mfspr %0, %1; mfspr %0, %1; \ 346 mfspr %0, %1; mfspr %0, %1; mfspr %0, %1; \ 347 sync; isync" 348 : "=r"(reg) : "K"(SPR_HID0), "b"(bsp_state)); 349 __asm __volatile("ld %0, 8(%2); sync; isync; \ 350 mtspr %1, %0; mtspr %1, %0; sync; isync" 351 : "=r"(reg) : "K"(SPR_HID1), "b"(bsp_state)); 352 #endif 353 354 powerpc_sync(); 355 break; 356 case IBMCELLBE: 357 #ifdef NOTYET /* Causes problems if in instruction stream on 970 */ 358 if (mfmsr() & PSL_HV) { 359 mtspr(SPR_HID0, bsp_state[0]); 360 mtspr(SPR_HID1, bsp_state[1]); 361 mtspr(SPR_HID4, bsp_state[2]); 362 mtspr(SPR_HID6, bsp_state[3]); 363 364 mtspr(SPR_CELL_TSCR, bsp_state[4]); 365 } 366 #endif 367 368 mtspr(SPR_CELL_TSRL, bsp_state[5]); 369 370 break; 371 case MPC7400: 372 case MPC7410: 373 case MPC7447A: 374 case MPC7448: 375 case MPC7450: 376 case MPC7455: 377 case MPC7457: 378 /* XXX: Program the CPU ID into PIR */ 379 __asm __volatile("mtspr 1023,%0" :: "r"(PCPU_GET(cpuid))); 380 381 powerpc_sync(); 382 isync(); 383 384 mtspr(SPR_HID0, bsp_state[0]); isync(); 385 mtspr(SPR_HID1, bsp_state[1]); isync(); 386 387 /* Now enable the L3 cache. */ 388 switch (vers) { 389 case MPC7450: 390 case MPC7455: 391 case MPC7457: 392 /* Only MPC745x CPUs have an L3 cache. */ 393 reg = mpc745x_l3_enable(bsp_state[3]); 394 default: 395 break; 396 } 397 398 reg = mpc74xx_l2_enable(bsp_state[2]); 399 reg = mpc74xx_l1d_enable(); 400 reg = mpc74xx_l1i_enable(); 401 402 break; 403 case IBMPOWER7: 404 case IBMPOWER7PLUS: 405 case IBMPOWER8: 406 case IBMPOWER8E: 407 case IBMPOWER8NVL: 408 case IBMPOWER9: 409 #ifdef __powerpc64__ 410 if (mfmsr() & PSL_HV) { 411 mtspr(SPR_LPCR, mfspr(SPR_LPCR) | lpcr | 412 LPCR_PECE_WAKESET); 413 isync(); 414 } 415 #endif 416 break; 417 default: 418 #ifdef __powerpc64__ 419 if (!(mfmsr() & PSL_HV)) /* Rely on HV to have set things up */ 420 break; 421 #endif 422 printf("WARNING: Unknown CPU type. Cache performace may be " 423 "suboptimal.\n"); 424 break; 425 } 426 } 427