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/smp.h> 39 40 #include <machine/bus.h> 41 #include <machine/cpu.h> 42 #include <machine/hid.h> 43 #include <machine/intr_machdep.h> 44 #include <machine/pcb.h> 45 #include <machine/psl.h> 46 #include <machine/smp.h> 47 #include <machine/spr.h> 48 #include <machine/trap.h> 49 50 #include <dev/ofw/openfirm.h> 51 #include <machine/ofw_machdep.h> 52 53 void *ap_pcpu; 54 55 static register_t bsp_state[8] __aligned(8); 56 57 static void cpudep_save_config(void *dummy); 58 SYSINIT(cpu_save_config, SI_SUB_CPU, SI_ORDER_ANY, cpudep_save_config, NULL); 59 60 void 61 cpudep_ap_early_bootstrap(void) 62 { 63 #ifndef __powerpc64__ 64 register_t reg; 65 #endif 66 67 switch (mfpvr() >> 16) { 68 case IBM970: 69 case IBM970FX: 70 case IBM970MP: 71 /* Restore HID4 and HID5, which are necessary for the MMU */ 72 73 #ifdef __powerpc64__ 74 mtspr(SPR_HID4, bsp_state[2]); powerpc_sync(); isync(); 75 mtspr(SPR_HID5, bsp_state[3]); powerpc_sync(); isync(); 76 #else 77 __asm __volatile("ld %0, 16(%2); sync; isync; \ 78 mtspr %1, %0; sync; isync;" 79 : "=r"(reg) : "K"(SPR_HID4), "b"(bsp_state)); 80 __asm __volatile("ld %0, 24(%2); sync; isync; \ 81 mtspr %1, %0; sync; isync;" 82 : "=r"(reg) : "K"(SPR_HID5), "b"(bsp_state)); 83 #endif 84 powerpc_sync(); 85 break; 86 case IBMPOWER8: 87 case IBMPOWER8E: 88 case IBMPOWER9: 89 #ifdef __powerpc64__ 90 if (mfmsr() & PSL_HV) { 91 isync(); 92 /* 93 * Direct interrupts to SRR instead of HSRR and 94 * reset LPCR otherwise 95 */ 96 mtspr(SPR_LPID, 0); 97 isync(); 98 99 mtspr(SPR_LPCR, lpcr); 100 isync(); 101 } 102 #endif 103 break; 104 } 105 106 __asm __volatile("mtsprg 0, %0" :: "r"(ap_pcpu)); 107 powerpc_sync(); 108 } 109 110 uintptr_t 111 cpudep_ap_bootstrap(void) 112 { 113 register_t msr, sp; 114 115 msr = psl_kernset & ~PSL_EE; 116 mtmsr(msr); 117 118 pcpup->pc_curthread = pcpup->pc_idlethread; 119 #ifdef __powerpc64__ 120 __asm __volatile("mr 13,%0" :: "r"(pcpup->pc_curthread)); 121 #else 122 __asm __volatile("mr 2,%0" :: "r"(pcpup->pc_curthread)); 123 #endif 124 pcpup->pc_curpcb = pcpup->pc_curthread->td_pcb; 125 sp = pcpup->pc_curpcb->pcb_sp; 126 127 return (sp); 128 } 129 130 static register_t 131 mpc74xx_l2_enable(register_t l2cr_config) 132 { 133 register_t ccr, bit; 134 uint16_t vers; 135 136 vers = mfpvr() >> 16; 137 switch (vers) { 138 case MPC7400: 139 case MPC7410: 140 bit = L2CR_L2IP; 141 break; 142 default: 143 bit = L2CR_L2I; 144 break; 145 } 146 147 ccr = mfspr(SPR_L2CR); 148 if (ccr & L2CR_L2E) 149 return (ccr); 150 151 /* Configure L2 cache. */ 152 ccr = l2cr_config & ~L2CR_L2E; 153 mtspr(SPR_L2CR, ccr | L2CR_L2I); 154 do { 155 ccr = mfspr(SPR_L2CR); 156 } while (ccr & bit); 157 powerpc_sync(); 158 mtspr(SPR_L2CR, l2cr_config); 159 powerpc_sync(); 160 161 return (l2cr_config); 162 } 163 164 static register_t 165 mpc745x_l3_enable(register_t l3cr_config) 166 { 167 register_t ccr; 168 169 ccr = mfspr(SPR_L3CR); 170 if (ccr & L3CR_L3E) 171 return (ccr); 172 173 /* Configure L3 cache. */ 174 ccr = l3cr_config & ~(L3CR_L3E | L3CR_L3I | L3CR_L3PE | L3CR_L3CLKEN); 175 mtspr(SPR_L3CR, ccr); 176 ccr |= 0x4000000; /* Magic, but documented. */ 177 mtspr(SPR_L3CR, ccr); 178 ccr |= L3CR_L3CLKEN; 179 mtspr(SPR_L3CR, ccr); 180 mtspr(SPR_L3CR, ccr | L3CR_L3I); 181 while (mfspr(SPR_L3CR) & L3CR_L3I) 182 ; 183 mtspr(SPR_L3CR, ccr & ~L3CR_L3CLKEN); 184 powerpc_sync(); 185 DELAY(100); 186 mtspr(SPR_L3CR, ccr); 187 powerpc_sync(); 188 DELAY(100); 189 ccr |= L3CR_L3E; 190 mtspr(SPR_L3CR, ccr); 191 powerpc_sync(); 192 193 return(ccr); 194 } 195 196 static register_t 197 mpc74xx_l1d_enable(void) 198 { 199 register_t hid; 200 201 hid = mfspr(SPR_HID0); 202 if (hid & HID0_DCE) 203 return (hid); 204 205 /* Enable L1 D-cache */ 206 hid |= HID0_DCE; 207 powerpc_sync(); 208 mtspr(SPR_HID0, hid | HID0_DCFI); 209 powerpc_sync(); 210 211 return (hid); 212 } 213 214 static register_t 215 mpc74xx_l1i_enable(void) 216 { 217 register_t hid; 218 219 hid = mfspr(SPR_HID0); 220 if (hid & HID0_ICE) 221 return (hid); 222 223 /* Enable L1 I-cache */ 224 hid |= HID0_ICE; 225 isync(); 226 mtspr(SPR_HID0, hid | HID0_ICFI); 227 isync(); 228 229 return (hid); 230 } 231 232 static void 233 cpudep_save_config(void *dummy) 234 { 235 uint16_t vers; 236 237 vers = mfpvr() >> 16; 238 239 switch(vers) { 240 case IBM970: 241 case IBM970FX: 242 case IBM970MP: 243 #ifdef __powerpc64__ 244 bsp_state[0] = mfspr(SPR_HID0); 245 bsp_state[1] = mfspr(SPR_HID1); 246 bsp_state[2] = mfspr(SPR_HID4); 247 bsp_state[3] = mfspr(SPR_HID5); 248 #else 249 __asm __volatile ("mfspr %0,%2; mr %1,%0; srdi %0,%0,32" 250 : "=r" (bsp_state[0]),"=r" (bsp_state[1]) : "K" (SPR_HID0)); 251 __asm __volatile ("mfspr %0,%2; mr %1,%0; srdi %0,%0,32" 252 : "=r" (bsp_state[2]),"=r" (bsp_state[3]) : "K" (SPR_HID1)); 253 __asm __volatile ("mfspr %0,%2; mr %1,%0; srdi %0,%0,32" 254 : "=r" (bsp_state[4]),"=r" (bsp_state[5]) : "K" (SPR_HID4)); 255 __asm __volatile ("mfspr %0,%2; mr %1,%0; srdi %0,%0,32" 256 : "=r" (bsp_state[6]),"=r" (bsp_state[7]) : "K" (SPR_HID5)); 257 #endif 258 259 powerpc_sync(); 260 261 break; 262 case IBMCELLBE: 263 #ifdef NOTYET /* Causes problems if in instruction stream on 970 */ 264 if (mfmsr() & PSL_HV) { 265 bsp_state[0] = mfspr(SPR_HID0); 266 bsp_state[1] = mfspr(SPR_HID1); 267 bsp_state[2] = mfspr(SPR_HID4); 268 bsp_state[3] = mfspr(SPR_HID6); 269 270 bsp_state[4] = mfspr(SPR_CELL_TSCR); 271 } 272 #endif 273 274 bsp_state[5] = mfspr(SPR_CELL_TSRL); 275 276 break; 277 case MPC7450: 278 case MPC7455: 279 case MPC7457: 280 /* Only MPC745x CPUs have an L3 cache. */ 281 bsp_state[3] = mfspr(SPR_L3CR); 282 283 /* Fallthrough */ 284 case MPC7400: 285 case MPC7410: 286 case MPC7447A: 287 case MPC7448: 288 bsp_state[2] = mfspr(SPR_L2CR); 289 bsp_state[1] = mfspr(SPR_HID1); 290 bsp_state[0] = mfspr(SPR_HID0); 291 break; 292 } 293 } 294 295 void 296 cpudep_ap_setup() 297 { 298 register_t reg; 299 uint16_t vers; 300 301 vers = mfpvr() >> 16; 302 303 /* The following is needed for restoring from sleep. */ 304 platform_smp_timebase_sync(0, 1); 305 306 switch(vers) { 307 case IBM970: 308 case IBM970FX: 309 case IBM970MP: 310 /* Set HIOR to 0 */ 311 __asm __volatile("mtspr 311,%0" :: "r"(0)); 312 powerpc_sync(); 313 314 /* 315 * The 970 has strange rules about how to update HID registers. 316 * See Table 2-3, 970MP manual 317 * 318 * Note: HID4 and HID5 restored already in 319 * cpudep_ap_early_bootstrap() 320 */ 321 322 __asm __volatile("mtasr %0; sync" :: "r"(0)); 323 #ifdef __powerpc64__ 324 __asm __volatile(" \ 325 sync; isync; \ 326 mtspr %1, %0; \ 327 mfspr %0, %1; mfspr %0, %1; mfspr %0, %1; \ 328 mfspr %0, %1; mfspr %0, %1; mfspr %0, %1; \ 329 sync; isync" 330 :: "r"(bsp_state[0]), "K"(SPR_HID0)); 331 __asm __volatile("sync; isync; \ 332 mtspr %1, %0; mtspr %1, %0; sync; isync" 333 :: "r"(bsp_state[1]), "K"(SPR_HID1)); 334 #else 335 __asm __volatile(" \ 336 ld %0,0(%2); \ 337 sync; isync; \ 338 mtspr %1, %0; \ 339 mfspr %0, %1; mfspr %0, %1; mfspr %0, %1; \ 340 mfspr %0, %1; mfspr %0, %1; mfspr %0, %1; \ 341 sync; isync" 342 : "=r"(reg) : "K"(SPR_HID0), "b"(bsp_state)); 343 __asm __volatile("ld %0, 8(%2); sync; isync; \ 344 mtspr %1, %0; mtspr %1, %0; sync; isync" 345 : "=r"(reg) : "K"(SPR_HID1), "b"(bsp_state)); 346 #endif 347 348 powerpc_sync(); 349 break; 350 case IBMCELLBE: 351 #ifdef NOTYET /* Causes problems if in instruction stream on 970 */ 352 if (mfmsr() & PSL_HV) { 353 mtspr(SPR_HID0, bsp_state[0]); 354 mtspr(SPR_HID1, bsp_state[1]); 355 mtspr(SPR_HID4, bsp_state[2]); 356 mtspr(SPR_HID6, bsp_state[3]); 357 358 mtspr(SPR_CELL_TSCR, bsp_state[4]); 359 } 360 #endif 361 362 mtspr(SPR_CELL_TSRL, bsp_state[5]); 363 364 break; 365 case MPC7400: 366 case MPC7410: 367 case MPC7447A: 368 case MPC7448: 369 case MPC7450: 370 case MPC7455: 371 case MPC7457: 372 /* XXX: Program the CPU ID into PIR */ 373 __asm __volatile("mtspr 1023,%0" :: "r"(PCPU_GET(cpuid))); 374 375 powerpc_sync(); 376 isync(); 377 378 mtspr(SPR_HID0, bsp_state[0]); isync(); 379 mtspr(SPR_HID1, bsp_state[1]); isync(); 380 381 /* Now enable the L3 cache. */ 382 switch (vers) { 383 case MPC7450: 384 case MPC7455: 385 case MPC7457: 386 /* Only MPC745x CPUs have an L3 cache. */ 387 reg = mpc745x_l3_enable(bsp_state[3]); 388 default: 389 break; 390 } 391 392 reg = mpc74xx_l2_enable(bsp_state[2]); 393 reg = mpc74xx_l1d_enable(); 394 reg = mpc74xx_l1i_enable(); 395 396 break; 397 case IBMPOWER7: 398 case IBMPOWER7PLUS: 399 case IBMPOWER8: 400 case IBMPOWER8E: 401 case IBMPOWER9: 402 #ifdef __powerpc64__ 403 if (mfmsr() & PSL_HV) { 404 mtspr(SPR_LPCR, mfspr(SPR_LPCR) | lpcr | 405 LPCR_PECE_WAKESET); 406 isync(); 407 } 408 #endif 409 break; 410 default: 411 #ifdef __powerpc64__ 412 if (!(mfmsr() & PSL_HV)) /* Rely on HV to have set things up */ 413 break; 414 #endif 415 printf("WARNING: Unknown CPU type. Cache performace may be " 416 "suboptimal.\n"); 417 break; 418 } 419 } 420 421