1 /*- 2 * SPDX-License-Identifier: BSD-4-Clause AND BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2001 Matt Thomas. 5 * Copyright (c) 2001 Tsubai Masanari. 6 * Copyright (c) 1998, 1999, 2001 Internet Research Institute, Inc. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by 20 * Internet Research Institute, Inc. 21 * 4. The name of the author may not be used to endorse or promote products 22 * derived from this software without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 27 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 29 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 30 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 33 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 */ 35 /*- 36 * Copyright (C) 2003 Benno Rice. 37 * All rights reserved. 38 * 39 * Redistribution and use in source and binary forms, with or without 40 * modification, are permitted provided that the following conditions 41 * are met: 42 * 1. Redistributions of source code must retain the above copyright 43 * notice, this list of conditions and the following disclaimer. 44 * 2. Redistributions in binary form must reproduce the above copyright 45 * notice, this list of conditions and the following disclaimer in the 46 * documentation and/or other materials provided with the distribution. 47 * 48 * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR 49 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 50 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 51 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 52 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 53 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 54 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 55 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 56 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 57 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 58 * 59 * from $NetBSD: cpu_subr.c,v 1.1 2003/02/03 17:10:09 matt Exp $ 60 * $FreeBSD$ 61 */ 62 63 #include <sys/param.h> 64 #include <sys/systm.h> 65 #include <sys/bus.h> 66 #include <sys/conf.h> 67 #include <sys/cpu.h> 68 #include <sys/kernel.h> 69 #include <sys/ktr.h> 70 #include <sys/lock.h> 71 #include <sys/proc.h> 72 #include <sys/sysctl.h> 73 #include <sys/sched.h> 74 #include <sys/smp.h> 75 #include <sys/endian.h> 76 77 #include <machine/bus.h> 78 #include <machine/cpu.h> 79 #include <machine/hid.h> 80 #include <machine/md_var.h> 81 #include <machine/smp.h> 82 #include <machine/spr.h> 83 84 #include <dev/ofw/openfirm.h> 85 86 static void cpu_6xx_setup(int cpuid, uint16_t vers); 87 static void cpu_970_setup(int cpuid, uint16_t vers); 88 static void cpu_booke_setup(int cpuid, uint16_t vers); 89 static void cpu_powerx_setup(int cpuid, uint16_t vers); 90 91 int powerpc_pow_enabled; 92 void (*cpu_idle_hook)(sbintime_t) = NULL; 93 static void cpu_idle_60x(sbintime_t); 94 static void cpu_idle_booke(sbintime_t); 95 #ifdef BOOKE_E500 96 static void cpu_idle_e500mc(sbintime_t sbt); 97 #endif 98 #if defined(__powerpc64__) && defined(AIM) 99 static void cpu_idle_powerx(sbintime_t); 100 static void cpu_idle_power9(sbintime_t); 101 #endif 102 103 struct cputab { 104 const char *name; 105 uint16_t version; 106 uint16_t revfmt; 107 int features; /* Do not include PPC_FEATURE_32 or 108 * PPC_FEATURE_HAS_MMU */ 109 int features2; 110 void (*cpu_setup)(int cpuid, uint16_t vers); 111 }; 112 #define REVFMT_MAJMIN 1 /* %u.%u */ 113 #define REVFMT_HEX 2 /* 0x%04x */ 114 #define REVFMT_DEC 3 /* %u */ 115 static const struct cputab models[] = { 116 { "Motorola PowerPC 601", MPC601, REVFMT_DEC, 117 PPC_FEATURE_HAS_FPU | PPC_FEATURE_UNIFIED_CACHE, 0, cpu_6xx_setup }, 118 { "Motorola PowerPC 602", MPC602, REVFMT_DEC, 119 PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup }, 120 { "Motorola PowerPC 603", MPC603, REVFMT_MAJMIN, 121 PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup }, 122 { "Motorola PowerPC 603e", MPC603e, REVFMT_MAJMIN, 123 PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup }, 124 { "Motorola PowerPC 603ev", MPC603ev, REVFMT_MAJMIN, 125 PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup }, 126 { "Motorola PowerPC 604", MPC604, REVFMT_MAJMIN, 127 PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup }, 128 { "Motorola PowerPC 604ev", MPC604ev, REVFMT_MAJMIN, 129 PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup }, 130 { "Motorola PowerPC 620", MPC620, REVFMT_HEX, 131 PPC_FEATURE_64 | PPC_FEATURE_HAS_FPU, 0, NULL }, 132 { "Motorola PowerPC 750", MPC750, REVFMT_MAJMIN, 133 PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup }, 134 { "IBM PowerPC 750FX", IBM750FX, REVFMT_MAJMIN, 135 PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup }, 136 { "IBM PowerPC 970", IBM970, REVFMT_MAJMIN, 137 PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, 138 0, cpu_970_setup }, 139 { "IBM PowerPC 970FX", IBM970FX, REVFMT_MAJMIN, 140 PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, 141 0, cpu_970_setup }, 142 { "IBM PowerPC 970GX", IBM970GX, REVFMT_MAJMIN, 143 PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, 144 0, cpu_970_setup }, 145 { "IBM PowerPC 970MP", IBM970MP, REVFMT_MAJMIN, 146 PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, 147 0, cpu_970_setup }, 148 { "IBM POWER4", IBMPOWER4, REVFMT_MAJMIN, 149 PPC_FEATURE_64 | PPC_FEATURE_HAS_FPU | PPC_FEATURE_POWER4, 0, NULL }, 150 { "IBM POWER4+", IBMPOWER4PLUS, REVFMT_MAJMIN, 151 PPC_FEATURE_64 | PPC_FEATURE_HAS_FPU | PPC_FEATURE_POWER4, 0, NULL }, 152 { "IBM POWER5", IBMPOWER5, REVFMT_MAJMIN, 153 PPC_FEATURE_64 | PPC_FEATURE_HAS_FPU | PPC_FEATURE_POWER4 | 154 PPC_FEATURE_SMT | PPC_FEATURE_ICACHE_SNOOP, 0, NULL }, 155 { "IBM POWER5+", IBMPOWER5PLUS, REVFMT_MAJMIN, 156 PPC_FEATURE_64 | PPC_FEATURE_HAS_FPU | PPC_FEATURE_POWER5_PLUS | 157 PPC_FEATURE_SMT | PPC_FEATURE_ICACHE_SNOOP, 0, NULL }, 158 { "IBM POWER6", IBMPOWER6, REVFMT_MAJMIN, 159 PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU | 160 PPC_FEATURE_SMT | PPC_FEATURE_ICACHE_SNOOP | PPC_FEATURE_ARCH_2_05 | 161 PPC_FEATURE_TRUE_LE, 0, NULL }, 162 { "IBM POWER7", IBMPOWER7, REVFMT_MAJMIN, 163 PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU | 164 PPC_FEATURE_SMT | PPC_FEATURE_ARCH_2_05 | PPC_FEATURE_ARCH_2_06 | 165 PPC_FEATURE_HAS_VSX | PPC_FEATURE_TRUE_LE, PPC_FEATURE2_DSCR, NULL }, 166 { "IBM POWER7+", IBMPOWER7PLUS, REVFMT_MAJMIN, 167 PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU | 168 PPC_FEATURE_SMT | PPC_FEATURE_ARCH_2_05 | PPC_FEATURE_ARCH_2_06 | 169 PPC_FEATURE_HAS_VSX, PPC_FEATURE2_DSCR, NULL }, 170 { "IBM POWER8E", IBMPOWER8E, REVFMT_MAJMIN, 171 PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU | 172 PPC_FEATURE_SMT | PPC_FEATURE_ICACHE_SNOOP | PPC_FEATURE_ARCH_2_05 | 173 PPC_FEATURE_ARCH_2_06 | PPC_FEATURE_HAS_VSX | PPC_FEATURE_TRUE_LE, 174 PPC_FEATURE2_ARCH_2_07 | PPC_FEATURE2_DSCR | PPC_FEATURE2_ISEL | 175 PPC_FEATURE2_TAR | PPC_FEATURE2_HAS_VEC_CRYPTO, cpu_powerx_setup }, 176 { "IBM POWER8NVL", IBMPOWER8NVL, REVFMT_MAJMIN, 177 PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU | 178 PPC_FEATURE_SMT | PPC_FEATURE_ICACHE_SNOOP | PPC_FEATURE_ARCH_2_05 | 179 PPC_FEATURE_ARCH_2_06 | PPC_FEATURE_HAS_VSX | PPC_FEATURE_TRUE_LE, 180 PPC_FEATURE2_ARCH_2_07 | PPC_FEATURE2_DSCR | PPC_FEATURE2_ISEL | 181 PPC_FEATURE2_TAR | PPC_FEATURE2_HAS_VEC_CRYPTO, cpu_powerx_setup }, 182 { "IBM POWER8", IBMPOWER8, REVFMT_MAJMIN, 183 PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU | 184 PPC_FEATURE_SMT | PPC_FEATURE_ICACHE_SNOOP | PPC_FEATURE_ARCH_2_05 | 185 PPC_FEATURE_ARCH_2_06 | PPC_FEATURE_HAS_VSX | PPC_FEATURE_TRUE_LE, 186 PPC_FEATURE2_ARCH_2_07 | PPC_FEATURE2_DSCR | PPC_FEATURE2_ISEL | 187 PPC_FEATURE2_TAR | PPC_FEATURE2_HAS_VEC_CRYPTO, cpu_powerx_setup }, 188 { "IBM POWER9", IBMPOWER9, REVFMT_MAJMIN, 189 PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU | 190 PPC_FEATURE_SMT | PPC_FEATURE_ICACHE_SNOOP | PPC_FEATURE_ARCH_2_05 | 191 PPC_FEATURE_ARCH_2_06 | PPC_FEATURE_HAS_VSX | PPC_FEATURE_TRUE_LE, 192 PPC_FEATURE2_ARCH_2_07 | PPC_FEATURE2_DSCR | PPC_FEATURE2_EBB | 193 PPC_FEATURE2_ISEL | PPC_FEATURE2_TAR | PPC_FEATURE2_HAS_VEC_CRYPTO | 194 PPC_FEATURE2_ARCH_3_00 | PPC_FEATURE2_HAS_IEEE128 | 195 PPC_FEATURE2_DARN, cpu_powerx_setup }, 196 { "Motorola PowerPC 7400", MPC7400, REVFMT_MAJMIN, 197 PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup }, 198 { "Motorola PowerPC 7410", MPC7410, REVFMT_MAJMIN, 199 PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup }, 200 { "Motorola PowerPC 7450", MPC7450, REVFMT_MAJMIN, 201 PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup }, 202 { "Motorola PowerPC 7455", MPC7455, REVFMT_MAJMIN, 203 PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup }, 204 { "Motorola PowerPC 7457", MPC7457, REVFMT_MAJMIN, 205 PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup }, 206 { "Motorola PowerPC 7447A", MPC7447A, REVFMT_MAJMIN, 207 PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup }, 208 { "Motorola PowerPC 7448", MPC7448, REVFMT_MAJMIN, 209 PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup }, 210 { "Motorola PowerPC 8240", MPC8240, REVFMT_MAJMIN, 211 PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup }, 212 { "Motorola PowerPC 8245", MPC8245, REVFMT_MAJMIN, 213 PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup }, 214 { "Freescale e500v1 core", FSL_E500v1, REVFMT_MAJMIN, 215 PPC_FEATURE_HAS_SPE | PPC_FEATURE_HAS_EFP_SINGLE | PPC_FEATURE_BOOKE, 216 PPC_FEATURE2_ISEL, cpu_booke_setup }, 217 { "Freescale e500v2 core", FSL_E500v2, REVFMT_MAJMIN, 218 PPC_FEATURE_HAS_SPE | PPC_FEATURE_BOOKE | 219 PPC_FEATURE_HAS_EFP_SINGLE | PPC_FEATURE_HAS_EFP_DOUBLE, 220 PPC_FEATURE2_ISEL, cpu_booke_setup }, 221 { "Freescale e500mc core", FSL_E500mc, REVFMT_MAJMIN, 222 PPC_FEATURE_HAS_FPU | PPC_FEATURE_BOOKE | PPC_FEATURE_ARCH_2_05 | 223 PPC_FEATURE_ARCH_2_06, PPC_FEATURE2_ISEL, 224 cpu_booke_setup }, 225 { "Freescale e5500 core", FSL_E5500, REVFMT_MAJMIN, 226 PPC_FEATURE_64 | PPC_FEATURE_HAS_FPU | PPC_FEATURE_BOOKE | 227 PPC_FEATURE_ARCH_2_05 | PPC_FEATURE_ARCH_2_06, 228 PPC_FEATURE2_ISEL, cpu_booke_setup }, 229 { "Freescale e6500 core", FSL_E6500, REVFMT_MAJMIN, 230 PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU | 231 PPC_FEATURE_BOOKE | PPC_FEATURE_ARCH_2_05 | PPC_FEATURE_ARCH_2_06, 232 PPC_FEATURE2_ISEL, cpu_booke_setup }, 233 { "IBM Cell Broadband Engine", IBMCELLBE, REVFMT_MAJMIN, 234 PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU | 235 PPC_FEATURE_CELL | PPC_FEATURE_SMT, 0, NULL}, 236 { "Unknown PowerPC CPU", 0, REVFMT_HEX, 0, 0, NULL }, 237 }; 238 239 static void cpu_6xx_print_cacheinfo(u_int, uint16_t); 240 static int cpu_feature_bit(SYSCTL_HANDLER_ARGS); 241 242 static char model[64]; 243 SYSCTL_STRING(_hw, HW_MODEL, model, CTLFLAG_RD, model, 0, ""); 244 245 static const struct cputab *cput; 246 247 u_long cpu_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU; 248 u_long cpu_features2 = 0; 249 SYSCTL_OPAQUE(_hw, OID_AUTO, cpu_features, CTLFLAG_RD, 250 &cpu_features, sizeof(cpu_features), "LX", "PowerPC CPU features"); 251 SYSCTL_OPAQUE(_hw, OID_AUTO, cpu_features2, CTLFLAG_RD, 252 &cpu_features2, sizeof(cpu_features2), "LX", "PowerPC CPU features 2"); 253 254 #ifdef __powerpc64__ 255 register_t lpcr = LPCR_LPES; 256 #endif 257 258 /* Provide some user-friendly aliases for bits in cpu_features */ 259 SYSCTL_PROC(_hw, OID_AUTO, floatingpoint, 260 CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, 0, PPC_FEATURE_HAS_FPU, 261 cpu_feature_bit, "I", "Floating point instructions executed in hardware"); 262 SYSCTL_PROC(_hw, OID_AUTO, altivec, CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, 263 0, PPC_FEATURE_HAS_ALTIVEC, cpu_feature_bit, "I", "CPU supports Altivec"); 264 265 /* 266 * Phase 1 (early) CPU setup. Setup the cpu_features/cpu_features2 variables, 267 * so they can be used during platform and MMU bringup. 268 */ 269 void 270 cpu_feature_setup(void) 271 { 272 u_int pvr; 273 uint16_t vers; 274 const struct cputab *cp; 275 276 pvr = mfpvr(); 277 vers = pvr >> 16; 278 for (cp = models; cp->version != 0; cp++) { 279 if (cp->version == vers) 280 break; 281 } 282 283 cput = cp; 284 cpu_features |= cp->features; 285 cpu_features2 |= cp->features2; 286 } 287 288 void 289 cpu_setup(u_int cpuid) 290 { 291 uint64_t cps; 292 const char *name; 293 u_int maj, min, pvr; 294 uint16_t rev, revfmt, vers; 295 296 pvr = mfpvr(); 297 vers = pvr >> 16; 298 rev = pvr; 299 switch (vers) { 300 case MPC7410: 301 min = (pvr >> 0) & 0xff; 302 maj = min <= 4 ? 1 : 2; 303 break; 304 case FSL_E500v1: 305 case FSL_E500v2: 306 case FSL_E500mc: 307 case FSL_E5500: 308 maj = (pvr >> 4) & 0xf; 309 min = (pvr >> 0) & 0xf; 310 break; 311 default: 312 maj = (pvr >> 8) & 0xf; 313 min = (pvr >> 0) & 0xf; 314 } 315 316 revfmt = cput->revfmt; 317 name = cput->name; 318 if (rev == MPC750 && pvr == 15) { 319 name = "Motorola MPC755"; 320 revfmt = REVFMT_HEX; 321 } 322 strncpy(model, name, sizeof(model) - 1); 323 324 printf("cpu%d: %s revision ", cpuid, name); 325 326 switch (revfmt) { 327 case REVFMT_MAJMIN: 328 printf("%u.%u", maj, min); 329 break; 330 case REVFMT_HEX: 331 printf("0x%04x", rev); 332 break; 333 case REVFMT_DEC: 334 printf("%u", rev); 335 break; 336 } 337 338 if (cpu_est_clockrate(0, &cps) == 0) 339 printf(", %jd.%02jd MHz", cps / 1000000, (cps / 10000) % 100); 340 printf("\n"); 341 342 printf("cpu%d: Features %b\n", cpuid, (int)cpu_features, 343 PPC_FEATURE_BITMASK); 344 if (cpu_features2 != 0) 345 printf("cpu%d: Features2 %b\n", cpuid, (int)cpu_features2, 346 PPC_FEATURE2_BITMASK); 347 348 /* 349 * Configure CPU 350 */ 351 if (cput->cpu_setup != NULL) 352 cput->cpu_setup(cpuid, vers); 353 } 354 355 /* Get current clock frequency for the given cpu id. */ 356 int 357 cpu_est_clockrate(int cpu_id, uint64_t *cps) 358 { 359 uint16_t vers; 360 register_t msr; 361 phandle_t cpu, dev, root; 362 uint32_t freq32; 363 int res = 0; 364 char buf[8]; 365 366 vers = mfpvr() >> 16; 367 msr = mfmsr(); 368 mtmsr(msr & ~PSL_EE); 369 370 switch (vers) { 371 case MPC7450: 372 case MPC7455: 373 case MPC7457: 374 case MPC750: 375 case IBM750FX: 376 case MPC7400: 377 case MPC7410: 378 case MPC7447A: 379 case MPC7448: 380 mtspr(SPR_MMCR0_74XX, SPR_MMCR0_FC); 381 mtspr(SPR_PMC1_74XX, 0); 382 mtspr(SPR_MMCR0_74XX, 383 SPR_MMCR0_74XX_PMC1SEL(PMCN_CYCLES)); 384 DELAY(1000); 385 *cps = (mfspr(SPR_PMC1_74XX) * 1000) + 4999; 386 mtspr(SPR_MMCR0_74XX, SPR_MMCR0_FC); 387 388 mtmsr(msr); 389 return (0); 390 case IBM970: 391 case IBM970FX: 392 case IBM970MP: 393 isync(); 394 mtspr(SPR_MMCR0, SPR_MMCR0_FC); 395 isync(); 396 mtspr(SPR_MMCR1, 0); 397 mtspr(SPR_MMCRA, 0); 398 mtspr(SPR_PMC1, 0); 399 mtspr(SPR_MMCR0, SPR_MMCR0_PMC1SEL(PMC970N_CYCLES)); 400 isync(); 401 DELAY(1000); 402 powerpc_sync(); 403 mtspr(SPR_MMCR0, SPR_MMCR0_FC); 404 *cps = (mfspr(SPR_PMC1) * 1000) + 4999; 405 406 mtmsr(msr); 407 return (0); 408 409 default: 410 root = OF_peer(0); 411 if (root == 0) 412 return (ENXIO); 413 414 dev = OF_child(root); 415 while (dev != 0) { 416 res = OF_getprop(dev, "name", buf, sizeof(buf)); 417 if (res > 0 && strcmp(buf, "cpus") == 0) 418 break; 419 dev = OF_peer(dev); 420 } 421 cpu = OF_child(dev); 422 while (cpu != 0) { 423 res = OF_getprop(cpu, "device_type", buf, 424 sizeof(buf)); 425 if (res > 0 && strcmp(buf, "cpu") == 0) 426 break; 427 cpu = OF_peer(cpu); 428 } 429 if (cpu == 0) 430 return (ENOENT); 431 if (OF_getprop(cpu, "ibm,extended-clock-frequency", 432 cps, sizeof(*cps)) >= 0) { 433 *cps = be64toh(*cps); 434 return (0); 435 } else if (OF_getencprop(cpu, "clock-frequency", 436 &freq32, sizeof(freq32)) >= 0) { 437 *cps = freq32; 438 return (0); 439 } else { 440 return (ENOENT); 441 } 442 } 443 } 444 445 void 446 cpu_6xx_setup(int cpuid, uint16_t vers) 447 { 448 register_t hid0, pvr; 449 const char *bitmask; 450 451 hid0 = mfspr(SPR_HID0); 452 pvr = mfpvr(); 453 454 /* 455 * Configure power-saving mode. 456 */ 457 switch (vers) { 458 case MPC603: 459 case MPC603e: 460 case MPC603ev: 461 case MPC604ev: 462 case MPC750: 463 case IBM750FX: 464 case MPC7400: 465 case MPC7410: 466 case MPC8240: 467 case MPC8245: 468 /* Select DOZE mode. */ 469 hid0 &= ~(HID0_DOZE | HID0_NAP | HID0_SLEEP); 470 hid0 |= HID0_DOZE | HID0_DPM; 471 powerpc_pow_enabled = 1; 472 break; 473 474 case MPC7448: 475 case MPC7447A: 476 case MPC7457: 477 case MPC7455: 478 case MPC7450: 479 /* Enable the 7450 branch caches */ 480 hid0 |= HID0_SGE | HID0_BTIC; 481 hid0 |= HID0_LRSTK | HID0_FOLD | HID0_BHT; 482 /* Disable BTIC on 7450 Rev 2.0 or earlier and on 7457 */ 483 if (((pvr >> 16) == MPC7450 && (pvr & 0xFFFF) <= 0x0200) 484 || (pvr >> 16) == MPC7457) 485 hid0 &= ~HID0_BTIC; 486 /* Select NAP mode. */ 487 hid0 &= ~(HID0_DOZE | HID0_NAP | HID0_SLEEP); 488 hid0 |= HID0_NAP | HID0_DPM; 489 powerpc_pow_enabled = 1; 490 break; 491 492 default: 493 /* No power-saving mode is available. */ ; 494 } 495 496 switch (vers) { 497 case IBM750FX: 498 case MPC750: 499 hid0 &= ~HID0_DBP; /* XXX correct? */ 500 hid0 |= HID0_EMCP | HID0_BTIC | HID0_SGE | HID0_BHT; 501 break; 502 503 case MPC7400: 504 case MPC7410: 505 hid0 &= ~HID0_SPD; 506 hid0 |= HID0_EMCP | HID0_BTIC | HID0_SGE | HID0_BHT; 507 hid0 |= HID0_EIEC; 508 break; 509 } 510 511 mtspr(SPR_HID0, hid0); 512 513 if (bootverbose) 514 cpu_6xx_print_cacheinfo(cpuid, vers); 515 516 switch (vers) { 517 case MPC7447A: 518 case MPC7448: 519 case MPC7450: 520 case MPC7455: 521 case MPC7457: 522 bitmask = HID0_7450_BITMASK; 523 break; 524 default: 525 bitmask = HID0_BITMASK; 526 break; 527 } 528 529 printf("cpu%d: HID0 %b\n", cpuid, (int)hid0, bitmask); 530 531 if (cpu_idle_hook == NULL) 532 cpu_idle_hook = cpu_idle_60x; 533 } 534 535 static void 536 cpu_6xx_print_cacheinfo(u_int cpuid, uint16_t vers) 537 { 538 register_t hid; 539 540 hid = mfspr(SPR_HID0); 541 printf("cpu%u: ", cpuid); 542 printf("L1 I-cache %sabled, ", (hid & HID0_ICE) ? "en" : "dis"); 543 printf("L1 D-cache %sabled\n", (hid & HID0_DCE) ? "en" : "dis"); 544 545 printf("cpu%u: ", cpuid); 546 if (mfspr(SPR_L2CR) & L2CR_L2E) { 547 switch (vers) { 548 case MPC7450: 549 case MPC7455: 550 case MPC7457: 551 printf("256KB L2 cache, "); 552 if (mfspr(SPR_L3CR) & L3CR_L3E) 553 printf("%cMB L3 backside cache", 554 mfspr(SPR_L3CR) & L3CR_L3SIZ ? '2' : '1'); 555 else 556 printf("L3 cache disabled"); 557 printf("\n"); 558 break; 559 case IBM750FX: 560 printf("512KB L2 cache\n"); 561 break; 562 default: 563 switch (mfspr(SPR_L2CR) & L2CR_L2SIZ) { 564 case L2SIZ_256K: 565 printf("256KB "); 566 break; 567 case L2SIZ_512K: 568 printf("512KB "); 569 break; 570 case L2SIZ_1M: 571 printf("1MB "); 572 break; 573 } 574 printf("write-%s", (mfspr(SPR_L2CR) & L2CR_L2WT) 575 ? "through" : "back"); 576 if (mfspr(SPR_L2CR) & L2CR_L2PE) 577 printf(", with parity"); 578 printf(" backside cache\n"); 579 break; 580 } 581 } else 582 printf("L2 cache disabled\n"); 583 } 584 585 static void 586 cpu_booke_setup(int cpuid, uint16_t vers) 587 { 588 #ifdef BOOKE_E500 589 register_t hid0; 590 const char *bitmask; 591 592 hid0 = mfspr(SPR_HID0); 593 594 switch (vers) { 595 case FSL_E500mc: 596 bitmask = HID0_E500MC_BITMASK; 597 cpu_idle_hook = cpu_idle_e500mc; 598 break; 599 case FSL_E5500: 600 case FSL_E6500: 601 bitmask = HID0_E5500_BITMASK; 602 cpu_idle_hook = cpu_idle_e500mc; 603 break; 604 case FSL_E500v1: 605 case FSL_E500v2: 606 /* Only e500v1/v2 support HID0 power management setup. */ 607 608 /* Program power-management mode. */ 609 hid0 &= ~(HID0_DOZE | HID0_NAP | HID0_SLEEP); 610 hid0 |= HID0_DOZE; 611 612 mtspr(SPR_HID0, hid0); 613 default: 614 bitmask = HID0_E500_BITMASK; 615 break; 616 } 617 printf("cpu%d: HID0 %b\n", cpuid, (int)hid0, bitmask); 618 #endif 619 620 if (cpu_idle_hook == NULL) 621 cpu_idle_hook = cpu_idle_booke; 622 } 623 624 static void 625 cpu_970_setup(int cpuid, uint16_t vers) 626 { 627 #ifdef AIM 628 uint32_t hid0_hi, hid0_lo; 629 630 __asm __volatile ("mfspr %0,%2; clrldi %1,%0,32; srdi %0,%0,32;" 631 : "=r" (hid0_hi), "=r" (hid0_lo) : "K" (SPR_HID0)); 632 633 /* Configure power-saving mode */ 634 switch (vers) { 635 case IBM970MP: 636 hid0_hi |= (HID0_DEEPNAP | HID0_NAP | HID0_DPM); 637 hid0_hi &= ~HID0_DOZE; 638 break; 639 default: 640 hid0_hi |= (HID0_NAP | HID0_DPM); 641 hid0_hi &= ~(HID0_DOZE | HID0_DEEPNAP); 642 break; 643 } 644 powerpc_pow_enabled = 1; 645 646 __asm __volatile (" \ 647 sync; isync; \ 648 sldi %0,%0,32; or %0,%0,%1; \ 649 mtspr %2, %0; \ 650 mfspr %0, %2; mfspr %0, %2; mfspr %0, %2; \ 651 mfspr %0, %2; mfspr %0, %2; mfspr %0, %2; \ 652 sync; isync" 653 :: "r" (hid0_hi), "r"(hid0_lo), "K" (SPR_HID0)); 654 655 __asm __volatile ("mfspr %0,%1; srdi %0,%0,32;" 656 : "=r" (hid0_hi) : "K" (SPR_HID0)); 657 printf("cpu%d: HID0 %b\n", cpuid, (int)(hid0_hi), HID0_970_BITMASK); 658 #endif 659 660 cpu_idle_hook = cpu_idle_60x; 661 } 662 663 static void 664 cpu_powerx_setup(int cpuid, uint16_t vers) 665 { 666 667 #if defined(__powerpc64__) && defined(AIM) 668 if ((mfmsr() & PSL_HV) == 0) 669 return; 670 671 /* Nuke the FSCR, to disable all facilities. */ 672 mtspr(SPR_FSCR, 0); 673 674 /* Configure power-saving */ 675 switch (vers) { 676 case IBMPOWER8: 677 case IBMPOWER8E: 678 case IBMPOWER8NVL: 679 cpu_idle_hook = cpu_idle_powerx; 680 mtspr(SPR_LPCR, mfspr(SPR_LPCR) | LPCR_PECE_WAKESET); 681 isync(); 682 break; 683 case IBMPOWER9: 684 cpu_idle_hook = cpu_idle_power9; 685 mtspr(SPR_LPCR, mfspr(SPR_LPCR) | LPCR_PECE_WAKESET); 686 isync(); 687 break; 688 default: 689 return; 690 } 691 692 #endif 693 } 694 695 static int 696 cpu_feature_bit(SYSCTL_HANDLER_ARGS) 697 { 698 int result; 699 700 result = (cpu_features & arg2) ? 1 : 0; 701 702 return (sysctl_handle_int(oidp, &result, 0, req)); 703 } 704 705 void 706 cpu_idle(int busy) 707 { 708 sbintime_t sbt = -1; 709 710 #ifdef INVARIANTS 711 if ((mfmsr() & PSL_EE) != PSL_EE) { 712 struct thread *td = curthread; 713 printf("td msr %#lx\n", (u_long)td->td_md.md_saved_msr); 714 panic("ints disabled in idleproc!"); 715 } 716 #endif 717 718 CTR1(KTR_SPARE2, "cpu_idle(%d)", busy); 719 720 if (cpu_idle_hook != NULL) { 721 if (!busy) { 722 critical_enter(); 723 sbt = cpu_idleclock(); 724 } 725 cpu_idle_hook(sbt); 726 if (!busy) { 727 cpu_activeclock(); 728 critical_exit(); 729 } 730 } 731 732 CTR1(KTR_SPARE2, "cpu_idle(%d) done", busy); 733 } 734 735 static void 736 cpu_idle_60x(sbintime_t sbt) 737 { 738 #ifdef AIM 739 register_t msr; 740 uint16_t vers; 741 #endif 742 743 if (!powerpc_pow_enabled) 744 return; 745 746 #ifdef AIM 747 msr = mfmsr(); 748 vers = mfpvr() >> 16; 749 750 switch (vers) { 751 case IBM970: 752 case IBM970FX: 753 case IBM970MP: 754 case MPC7447A: 755 case MPC7448: 756 case MPC7450: 757 case MPC7455: 758 case MPC7457: 759 /* 0x7e00066c: dssall */ 760 __asm __volatile("\ 761 .long 0x7e00066c; sync; mtmsr %0; isync" 762 :: "r"(msr | PSL_POW)); 763 break; 764 default: 765 powerpc_sync(); 766 mtmsr(msr | PSL_POW); 767 break; 768 } 769 #endif 770 } 771 772 #ifdef BOOKE_E500 773 static void 774 cpu_idle_e500mc(sbintime_t sbt) 775 { 776 /* 777 * Base binutils doesn't know what the 'wait' instruction is, so 778 * use the opcode encoding here. 779 */ 780 __asm __volatile(".long 0x7c00007c"); 781 } 782 #endif 783 784 static void 785 cpu_idle_booke(sbintime_t sbt) 786 { 787 #ifdef BOOKE_E500 788 register_t msr; 789 790 msr = mfmsr(); 791 792 powerpc_sync(); 793 mtmsr(msr | PSL_WE); 794 #endif 795 } 796 797 #if defined(__powerpc64__) && defined(AIM) 798 static void 799 cpu_idle_powerx(sbintime_t sbt) 800 { 801 /* Sleeping when running on one cpu gives no advantages - avoid it */ 802 if (smp_started == 0) 803 return; 804 805 spinlock_enter(); 806 if (sched_runnable()) { 807 spinlock_exit(); 808 return; 809 } 810 811 if (can_wakeup == 0) 812 can_wakeup = 1; 813 mb(); 814 815 enter_idle_powerx(); 816 spinlock_exit(); 817 } 818 819 static void 820 cpu_idle_power9(sbintime_t sbt) 821 { 822 register_t msr; 823 824 msr = mfmsr(); 825 826 /* Suspend external interrupts until stop instruction completes. */ 827 mtmsr(msr & ~PSL_EE); 828 /* Set the stop state to lowest latency, wake up to next instruction */ 829 /* Set maximum transition level to 2, for deepest lossless sleep. */ 830 mtspr(SPR_PSSCR, (2 << PSSCR_MTL_S) | (0 << PSSCR_RL_S)); 831 /* "stop" instruction (PowerISA 3.0) */ 832 __asm __volatile (".long 0x4c0002e4"); 833 /* 834 * Re-enable external interrupts to capture the interrupt that caused 835 * the wake up. 836 */ 837 mtmsr(msr); 838 839 } 840 #endif 841 842 int 843 cpu_idle_wakeup(int cpu) 844 { 845 846 return (0); 847 } 848