identcpu.c revision 266341
1/* $NetBSD: cpu.c,v 1.55 2004/02/13 11:36:10 wiz Exp $ */ 2 3/*- 4 * Copyright (c) 1995 Mark Brinicombe. 5 * Copyright (c) 1995 Brini. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 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 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by Brini. 19 * 4. The name of the company nor the name of the author may be used to 20 * endorse or promote products derived from this software without specific 21 * prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED 24 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 27 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 29 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * RiscBSD kernel project 36 * 37 * cpu.c 38 * 39 * Probing and configuration for the master CPU 40 * 41 * Created : 10/10/95 42 */ 43 44#include <sys/cdefs.h> 45__FBSDID("$FreeBSD: stable/10/sys/arm/arm/identcpu.c 266341 2014-05-17 19:37:04Z ian $"); 46#include <sys/systm.h> 47#include <sys/param.h> 48#include <sys/malloc.h> 49#include <sys/time.h> 50#include <sys/proc.h> 51#include <sys/conf.h> 52#include <sys/kernel.h> 53#include <sys/sysctl.h> 54#include <machine/cpu.h> 55#include <machine/endian.h> 56 57#include <machine/cpuconf.h> 58#include <machine/md_var.h> 59 60char machine[] = "arm"; 61 62SYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD, 63 machine, 0, "Machine class"); 64 65static const char * const generic_steppings[16] = { 66 "rev 0", "rev 1", "rev 2", "rev 3", 67 "rev 4", "rev 5", "rev 6", "rev 7", 68 "rev 8", "rev 9", "rev 10", "rev 11", 69 "rev 12", "rev 13", "rev 14", "rev 15", 70}; 71 72static const char * const xscale_steppings[16] = { 73 "step A-0", "step A-1", "step B-0", "step C-0", 74 "step D-0", "rev 5", "rev 6", "rev 7", 75 "rev 8", "rev 9", "rev 10", "rev 11", 76 "rev 12", "rev 13", "rev 14", "rev 15", 77}; 78 79static const char * const i80219_steppings[16] = { 80 "step A-0", "rev 1", "rev 2", "rev 3", 81 "rev 4", "rev 5", "rev 6", "rev 7", 82 "rev 8", "rev 9", "rev 10", "rev 11", 83 "rev 12", "rev 13", "rev 14", "rev 15", 84}; 85 86static const char * const i80321_steppings[16] = { 87 "step A-0", "step B-0", "rev 2", "rev 3", 88 "rev 4", "rev 5", "rev 6", "rev 7", 89 "rev 8", "rev 9", "rev 10", "rev 11", 90 "rev 12", "rev 13", "rev 14", "rev 15", 91}; 92 93static const char * const i81342_steppings[16] = { 94 "step A-0", "rev 1", "rev 2", "rev 3", 95 "rev 4", "rev 5", "rev 6", "rev 7", 96 "rev 8", "rev 9", "rev 10", "rev 11", 97 "rev 12", "rev 13", "rev 14", "rev 15", 98}; 99 100/* Steppings for PXA2[15]0 */ 101static const char * const pxa2x0_steppings[16] = { 102 "step A-0", "step A-1", "step B-0", "step B-1", 103 "step B-2", "step C-0", "rev 6", "rev 7", 104 "rev 8", "rev 9", "rev 10", "rev 11", 105 "rev 12", "rev 13", "rev 14", "rev 15", 106}; 107 108/* Steppings for PXA255/26x. 109 * rev 5: PXA26x B0, rev 6: PXA255 A0 110 */ 111static const char * const pxa255_steppings[16] = { 112 "rev 0", "rev 1", "rev 2", "step A-0", 113 "rev 4", "step B-0", "step A-0", "rev 7", 114 "rev 8", "rev 9", "rev 10", "rev 11", 115 "rev 12", "rev 13", "rev 14", "rev 15", 116}; 117 118/* Stepping for PXA27x */ 119static const char * const pxa27x_steppings[16] = { 120 "step A-0", "step A-1", "step B-0", "step B-1", 121 "step C-0", "rev 5", "rev 6", "rev 7", 122 "rev 8", "rev 9", "rev 10", "rev 11", 123 "rev 12", "rev 13", "rev 14", "rev 15", 124}; 125 126static const char * const ixp425_steppings[16] = { 127 "step 0 (A0)", "rev 1 (ARMv5TE)", "rev 2", "rev 3", 128 "rev 4", "rev 5", "rev 6", "rev 7", 129 "rev 8", "rev 9", "rev 10", "rev 11", 130 "rev 12", "rev 13", "rev 14", "rev 15", 131}; 132 133struct cpuidtab { 134 u_int32_t cpuid; 135 enum cpu_class cpu_class; 136 const char *cpu_name; 137 const char * const *cpu_steppings; 138}; 139 140const struct cpuidtab cpuids[] = { 141 { CPU_ID_ARM920T, CPU_CLASS_ARM9TDMI, "ARM920T", 142 generic_steppings }, 143 { CPU_ID_ARM920T_ALT, CPU_CLASS_ARM9TDMI, "ARM920T", 144 generic_steppings }, 145 { CPU_ID_ARM922T, CPU_CLASS_ARM9TDMI, "ARM922T", 146 generic_steppings }, 147 { CPU_ID_ARM926EJS, CPU_CLASS_ARM9EJS, "ARM926EJ-S", 148 generic_steppings }, 149 { CPU_ID_ARM940T, CPU_CLASS_ARM9TDMI, "ARM940T", 150 generic_steppings }, 151 { CPU_ID_ARM946ES, CPU_CLASS_ARM9ES, "ARM946E-S", 152 generic_steppings }, 153 { CPU_ID_ARM966ES, CPU_CLASS_ARM9ES, "ARM966E-S", 154 generic_steppings }, 155 { CPU_ID_ARM966ESR1, CPU_CLASS_ARM9ES, "ARM966E-S", 156 generic_steppings }, 157 { CPU_ID_FA526, CPU_CLASS_ARM9TDMI, "FA526", 158 generic_steppings }, 159 { CPU_ID_FA626TE, CPU_CLASS_ARM9ES, "FA626TE", 160 generic_steppings }, 161 162 { CPU_ID_TI925T, CPU_CLASS_ARM9TDMI, "TI ARM925T", 163 generic_steppings }, 164 165 { CPU_ID_ARM1020E, CPU_CLASS_ARM10E, "ARM1020E", 166 generic_steppings }, 167 { CPU_ID_ARM1022ES, CPU_CLASS_ARM10E, "ARM1022E-S", 168 generic_steppings }, 169 { CPU_ID_ARM1026EJS, CPU_CLASS_ARM10EJ, "ARM1026EJ-S", 170 generic_steppings }, 171 172 { CPU_ID_CORTEXA7, CPU_CLASS_CORTEXA, "Cortex A7", 173 generic_steppings }, 174 { CPU_ID_CORTEXA8R1, CPU_CLASS_CORTEXA, "Cortex A8-r1", 175 generic_steppings }, 176 { CPU_ID_CORTEXA8R2, CPU_CLASS_CORTEXA, "Cortex A8-r2", 177 generic_steppings }, 178 { CPU_ID_CORTEXA8R3, CPU_CLASS_CORTEXA, "Cortex A8-r3", 179 generic_steppings }, 180 { CPU_ID_CORTEXA9R1, CPU_CLASS_CORTEXA, "Cortex A9-r1", 181 generic_steppings }, 182 { CPU_ID_CORTEXA9R2, CPU_CLASS_CORTEXA, "Cortex A9-r2", 183 generic_steppings }, 184 { CPU_ID_CORTEXA9R3, CPU_CLASS_CORTEXA, "Cortex A9-r3", 185 generic_steppings }, 186 { CPU_ID_CORTEXA15R0, CPU_CLASS_CORTEXA, "Cortex A15-r0", 187 generic_steppings }, 188 { CPU_ID_CORTEXA15R1, CPU_CLASS_CORTEXA, "Cortex A15-r1", 189 generic_steppings }, 190 { CPU_ID_CORTEXA15R2, CPU_CLASS_CORTEXA, "Cortex A15-r2", 191 generic_steppings }, 192 { CPU_ID_CORTEXA15R3, CPU_CLASS_CORTEXA, "Cortex A15-r3", 193 generic_steppings }, 194 { CPU_ID_KRAIT, CPU_CLASS_KRAIT, "Krait", 195 generic_steppings }, 196 197 { CPU_ID_80200, CPU_CLASS_XSCALE, "i80200", 198 xscale_steppings }, 199 200 { CPU_ID_80321_400, CPU_CLASS_XSCALE, "i80321 400MHz", 201 i80321_steppings }, 202 { CPU_ID_80321_600, CPU_CLASS_XSCALE, "i80321 600MHz", 203 i80321_steppings }, 204 { CPU_ID_80321_400_B0, CPU_CLASS_XSCALE, "i80321 400MHz", 205 i80321_steppings }, 206 { CPU_ID_80321_600_B0, CPU_CLASS_XSCALE, "i80321 600MHz", 207 i80321_steppings }, 208 209 { CPU_ID_81342, CPU_CLASS_XSCALE, "i81342", 210 i81342_steppings }, 211 212 { CPU_ID_80219_400, CPU_CLASS_XSCALE, "i80219 400MHz", 213 i80219_steppings }, 214 { CPU_ID_80219_600, CPU_CLASS_XSCALE, "i80219 600MHz", 215 i80219_steppings }, 216 217 { CPU_ID_PXA27X, CPU_CLASS_XSCALE, "PXA27x", 218 pxa27x_steppings }, 219 { CPU_ID_PXA250A, CPU_CLASS_XSCALE, "PXA250", 220 pxa2x0_steppings }, 221 { CPU_ID_PXA210A, CPU_CLASS_XSCALE, "PXA210", 222 pxa2x0_steppings }, 223 { CPU_ID_PXA250B, CPU_CLASS_XSCALE, "PXA250", 224 pxa2x0_steppings }, 225 { CPU_ID_PXA210B, CPU_CLASS_XSCALE, "PXA210", 226 pxa2x0_steppings }, 227 { CPU_ID_PXA250C, CPU_CLASS_XSCALE, "PXA255", 228 pxa255_steppings }, 229 { CPU_ID_PXA210C, CPU_CLASS_XSCALE, "PXA210", 230 pxa2x0_steppings }, 231 232 { CPU_ID_IXP425_533, CPU_CLASS_XSCALE, "IXP425 533MHz", 233 ixp425_steppings }, 234 { CPU_ID_IXP425_400, CPU_CLASS_XSCALE, "IXP425 400MHz", 235 ixp425_steppings }, 236 { CPU_ID_IXP425_266, CPU_CLASS_XSCALE, "IXP425 266MHz", 237 ixp425_steppings }, 238 239 /* XXX ixp435 steppings? */ 240 { CPU_ID_IXP435, CPU_CLASS_XSCALE, "IXP435", 241 ixp425_steppings }, 242 243 { CPU_ID_ARM1136JS, CPU_CLASS_ARM11J, "ARM1136J-S", 244 generic_steppings }, 245 { CPU_ID_ARM1136JSR1, CPU_CLASS_ARM11J, "ARM1136J-S R1", 246 generic_steppings }, 247 { CPU_ID_ARM1176JZS, CPU_CLASS_ARM11J, "ARM1176JZ-S", 248 generic_steppings }, 249 250 { CPU_ID_MV88FR131, CPU_CLASS_MARVELL, "Feroceon 88FR131", 251 generic_steppings }, 252 253 { CPU_ID_MV88FR571_VD, CPU_CLASS_MARVELL, "Feroceon 88FR571-VD", 254 generic_steppings }, 255 { CPU_ID_MV88SV581X_V7, CPU_CLASS_MARVELL, "Sheeva 88SV581x", 256 generic_steppings }, 257 { CPU_ID_ARM_88SV581X_V7, CPU_CLASS_MARVELL, "Sheeva 88SV581x", 258 generic_steppings }, 259 { CPU_ID_MV88SV584X_V7, CPU_CLASS_MARVELL, "Sheeva 88SV584x", 260 generic_steppings }, 261 262 { 0, CPU_CLASS_NONE, NULL, NULL } 263}; 264 265struct cpu_classtab { 266 const char *class_name; 267 const char *class_option; 268}; 269 270const struct cpu_classtab cpu_classes[] = { 271 { "unknown", NULL }, /* CPU_CLASS_NONE */ 272 { "ARM9TDMI", "CPU_ARM9TDMI" }, /* CPU_CLASS_ARM9TDMI */ 273 { "ARM9E-S", "CPU_ARM9E" }, /* CPU_CLASS_ARM9ES */ 274 { "ARM9EJ-S", "CPU_ARM9E" }, /* CPU_CLASS_ARM9EJS */ 275 { "ARM10E", "CPU_ARM10" }, /* CPU_CLASS_ARM10E */ 276 { "ARM10EJ", "CPU_ARM10" }, /* CPU_CLASS_ARM10EJ */ 277 { "Cortex-A", "CPU_CORTEXA" }, /* CPU_CLASS_CORTEXA */ 278 { "Krait", "CPU_KRAIT" }, /* CPU_CLASS_KRAIT */ 279 { "XScale", "CPU_XSCALE_..." }, /* CPU_CLASS_XSCALE */ 280 { "ARM11J", "CPU_ARM11" }, /* CPU_CLASS_ARM11J */ 281 { "Marvell", "CPU_MARVELL" }, /* CPU_CLASS_MARVELL */ 282}; 283 284/* 285 * Report the type of the specified arm processor. This uses the generic and 286 * arm specific information in the cpu structure to identify the processor. 287 * The remaining fields in the cpu structure are filled in appropriately. 288 */ 289 290static const char * const wtnames[] = { 291 "write-through", 292 "write-back", 293 "write-back", 294 "**unknown 3**", 295 "**unknown 4**", 296 "write-back-locking", /* XXX XScale-specific? */ 297 "write-back-locking-A", 298 "write-back-locking-B", 299 "**unknown 8**", 300 "**unknown 9**", 301 "**unknown 10**", 302 "**unknown 11**", 303 "**unknown 12**", 304 "**unknown 13**", 305 "write-back-locking-C", 306 "**unknown 15**", 307}; 308 309static void 310print_enadis(int enadis, char *s) 311{ 312 313 printf(" %s %sabled", s, (enadis == 0) ? "dis" : "en"); 314} 315 316extern int ctrl; 317enum cpu_class cpu_class = CPU_CLASS_NONE; 318 319u_int cpu_pfr(int num) 320{ 321 u_int feat; 322 323 switch (num) { 324 case 0: 325 __asm __volatile("mrc p15, 0, %0, c0, c1, 0" 326 : "=r" (feat)); 327 break; 328 case 1: 329 __asm __volatile("mrc p15, 0, %0, c0, c1, 1" 330 : "=r" (feat)); 331 break; 332 default: 333 panic("Processor Feature Register %d not implemented", num); 334 break; 335 } 336 337 return (feat); 338} 339 340static 341void identify_armv7(void) 342{ 343 u_int feature; 344 345 printf("Supported features:"); 346 /* Get Processor Feature Register 0 */ 347 feature = cpu_pfr(0); 348 349 if (feature & ARM_PFR0_ARM_ISA_MASK) 350 printf(" ARM_ISA"); 351 352 if (feature & ARM_PFR0_THUMB2) 353 printf(" THUMB2"); 354 else if (feature & ARM_PFR0_THUMB) 355 printf(" THUMB"); 356 357 if (feature & ARM_PFR0_JAZELLE_MASK) 358 printf(" JAZELLE"); 359 360 if (feature & ARM_PFR0_THUMBEE_MASK) 361 printf(" THUMBEE"); 362 363 364 /* Get Processor Feature Register 1 */ 365 feature = cpu_pfr(1); 366 367 if (feature & ARM_PFR1_ARMV4_MASK) 368 printf(" ARMv4"); 369 370 if (feature & ARM_PFR1_SEC_EXT_MASK) 371 printf(" Security_Ext"); 372 373 if (feature & ARM_PFR1_MICROCTRL_MASK) 374 printf(" M_profile"); 375 376 printf("\n"); 377} 378 379void 380identify_arm_cpu(void) 381{ 382 u_int cpuid, reg, size, sets, ways; 383 u_int8_t type, linesize; 384 int i; 385 386 cpuid = cpu_id(); 387 388 if (cpuid == 0) { 389 printf("Processor failed probe - no CPU ID\n"); 390 return; 391 } 392 393 for (i = 0; cpuids[i].cpuid != 0; i++) 394 if (cpuids[i].cpuid == (cpuid & CPU_ID_CPU_MASK)) { 395 cpu_class = cpuids[i].cpu_class; 396 printf("CPU: %s %s (%s core)\n", 397 cpuids[i].cpu_name, 398 cpuids[i].cpu_steppings[cpuid & 399 CPU_ID_REVISION_MASK], 400 cpu_classes[cpu_class].class_name); 401 break; 402 } 403 if (cpuids[i].cpuid == 0) 404 printf("unknown CPU (ID = 0x%x)\n", cpuid); 405 406 printf(" "); 407 408 if ((cpuid & CPU_ID_ARCH_MASK) == CPU_ID_CPUID_SCHEME) { 409 identify_armv7(); 410 } else { 411 if (ctrl & CPU_CONTROL_BEND_ENABLE) 412 printf(" Big-endian"); 413 else 414 printf(" Little-endian"); 415 416 switch (cpu_class) { 417 case CPU_CLASS_ARM9TDMI: 418 case CPU_CLASS_ARM9ES: 419 case CPU_CLASS_ARM9EJS: 420 case CPU_CLASS_ARM10E: 421 case CPU_CLASS_ARM10EJ: 422 case CPU_CLASS_XSCALE: 423 case CPU_CLASS_ARM11J: 424 case CPU_CLASS_MARVELL: 425 print_enadis(ctrl & CPU_CONTROL_DC_ENABLE, "DC"); 426 print_enadis(ctrl & CPU_CONTROL_IC_ENABLE, "IC"); 427#ifdef CPU_XSCALE_81342 428 print_enadis(ctrl & CPU_CONTROL_L2_ENABLE, "L2"); 429#endif 430#if defined(SOC_MV_KIRKWOOD) || defined(SOC_MV_DISCOVERY) 431 i = sheeva_control_ext(0, 0); 432 print_enadis(i & MV_WA_ENABLE, "WA"); 433 print_enadis(i & MV_DC_STREAM_ENABLE, "DC streaming"); 434 printf("\n "); 435 print_enadis((i & MV_BTB_DISABLE) == 0, "BTB"); 436 print_enadis(i & MV_L2_ENABLE, "L2"); 437 print_enadis((i & MV_L2_PREFETCH_DISABLE) == 0, 438 "L2 prefetch"); 439 printf("\n "); 440#endif 441 break; 442 default: 443 break; 444 } 445 } 446 447 print_enadis(ctrl & CPU_CONTROL_WBUF_ENABLE, "WB"); 448 if (ctrl & CPU_CONTROL_LABT_ENABLE) 449 printf(" LABT"); 450 else 451 printf(" EABT"); 452 453 print_enadis(ctrl & CPU_CONTROL_BPRD_ENABLE, "branch prediction"); 454 printf("\n"); 455 456 if (arm_cache_level) { 457 printf("LoUU:%d LoC:%d LoUIS:%d \n", CPU_CLIDR_LOUU(arm_cache_level) + 1, 458 arm_cache_loc, CPU_CLIDR_LOUIS(arm_cache_level) + 1); 459 i = 0; 460 while (((type = CPU_CLIDR_CTYPE(arm_cache_level, i)) != 0) && i < 7) { 461 printf("Cache level %d: \n", i + 1); 462 if (type == CACHE_DCACHE || type == CACHE_UNI_CACHE || 463 type == CACHE_SEP_CACHE) { 464 reg = arm_cache_type[2 * i]; 465 ways = CPUV7_CT_xSIZE_ASSOC(reg) + 1; 466 sets = CPUV7_CT_xSIZE_SET(reg) + 1; 467 linesize = 1 << (CPUV7_CT_xSIZE_LEN(reg) + 4); 468 size = (ways * sets * linesize) / 1024; 469 470 if (type == CACHE_UNI_CACHE) 471 printf(" %dKB/%dB %d-way unified cache", size, linesize,ways); 472 else 473 printf(" %dKB/%dB %d-way data cache", size, linesize, ways); 474 if (reg & CPUV7_CT_CTYPE_WT) 475 printf(" WT"); 476 if (reg & CPUV7_CT_CTYPE_WB) 477 printf(" WB"); 478 if (reg & CPUV7_CT_CTYPE_RA) 479 printf(" Read-Alloc"); 480 if (reg & CPUV7_CT_CTYPE_WA) 481 printf(" Write-Alloc"); 482 printf("\n"); 483 } 484 485 if (type == CACHE_ICACHE || type == CACHE_SEP_CACHE) { 486 reg = arm_cache_type[(2 * i) + 1]; 487 488 ways = CPUV7_CT_xSIZE_ASSOC(reg) + 1; 489 sets = CPUV7_CT_xSIZE_SET(reg) + 1; 490 linesize = 1 << (CPUV7_CT_xSIZE_LEN(reg) + 4); 491 size = (ways * sets * linesize) / 1024; 492 493 printf(" %dKB/%dB %d-way instruction cache", size, linesize, ways); 494 if (reg & CPUV7_CT_CTYPE_WT) 495 printf(" WT"); 496 if (reg & CPUV7_CT_CTYPE_WB) 497 printf(" WB"); 498 if (reg & CPUV7_CT_CTYPE_RA) 499 printf(" Read-Alloc"); 500 if (reg & CPUV7_CT_CTYPE_WA) 501 printf(" Write-Alloc"); 502 printf("\n"); 503 } 504 i++; 505 } 506 } else { 507 /* Print cache info. */ 508 if (arm_picache_line_size == 0 && arm_pdcache_line_size == 0) 509 return; 510 511 if (arm_pcache_unified) { 512 printf(" %dKB/%dB %d-way %s unified cache\n", 513 arm_pdcache_size / 1024, 514 arm_pdcache_line_size, arm_pdcache_ways, 515 wtnames[arm_pcache_type]); 516 } else { 517 printf(" %dKB/%dB %d-way instruction cache\n", 518 arm_picache_size / 1024, 519 arm_picache_line_size, arm_picache_ways); 520 printf(" %dKB/%dB %d-way %s data cache\n", 521 arm_pdcache_size / 1024, 522 arm_pdcache_line_size, arm_pdcache_ways, 523 wtnames[arm_pcache_type]); 524 } 525 } 526} 527