1 /* $NetBSD: cpu.c,v 1.55 2004/02/13 11:36:10 wiz Exp $ */
4 * Copyright (c) 1995 Mark Brinicombe.
5 * Copyright (c) 1995 Brini.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
35 * RiscBSD kernel project
39 * Probing and configuration for the master CPU
44 #include <sys/cdefs.h>
45 __FBSDID("$FreeBSD$");
46 #include <sys/systm.h>
47 #include <sys/param.h>
48 #include <sys/malloc.h>
52 #include <sys/kernel.h>
53 #include <sys/sysctl.h>
54 #include <machine/cpu.h>
55 #include <machine/endian.h>
57 #include <machine/cpuconf.h>
58 #include <machine/md_var.h>
60 char machine[] = "arm";
62 SYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD,
63 machine, 0, "Machine class");
65 static 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",
72 static const char * const sa110_steppings[16] = {
73 "rev 0", "step J", "step K", "step S",
74 "step T", "rev 5", "rev 6", "rev 7",
75 "rev 8", "rev 9", "rev 10", "rev 11",
76 "rev 12", "rev 13", "rev 14", "rev 15",
79 static const char * const sa1100_steppings[16] = {
80 "rev 0", "step B", "step C", "rev 3",
81 "rev 4", "rev 5", "rev 6", "rev 7",
82 "step D", "step E", "rev 10" "step G",
83 "rev 12", "rev 13", "rev 14", "rev 15",
86 static const char * const sa1110_steppings[16] = {
87 "step A-0", "rev 1", "rev 2", "rev 3",
88 "step B-0", "step B-1", "step B-2", "step B-3",
89 "step B-4", "step B-5", "rev 10", "rev 11",
90 "rev 12", "rev 13", "rev 14", "rev 15",
93 static const char * const ixp12x0_steppings[16] = {
94 "(IXP1200 step A)", "(IXP1200 step B)",
95 "rev 2", "(IXP1200 step C)",
96 "(IXP1200 step D)", "(IXP1240/1250 step A)",
97 "(IXP1240 step B)", "(IXP1250 step B)",
98 "rev 8", "rev 9", "rev 10", "rev 11",
99 "rev 12", "rev 13", "rev 14", "rev 15",
102 static const char * const xscale_steppings[16] = {
103 "step A-0", "step A-1", "step B-0", "step C-0",
104 "step D-0", "rev 5", "rev 6", "rev 7",
105 "rev 8", "rev 9", "rev 10", "rev 11",
106 "rev 12", "rev 13", "rev 14", "rev 15",
109 static const char * const i80219_steppings[16] = {
110 "step A-0", "rev 1", "rev 2", "rev 3",
111 "rev 4", "rev 5", "rev 6", "rev 7",
112 "rev 8", "rev 9", "rev 10", "rev 11",
113 "rev 12", "rev 13", "rev 14", "rev 15",
116 static const char * const i80321_steppings[16] = {
117 "step A-0", "step B-0", "rev 2", "rev 3",
118 "rev 4", "rev 5", "rev 6", "rev 7",
119 "rev 8", "rev 9", "rev 10", "rev 11",
120 "rev 12", "rev 13", "rev 14", "rev 15",
123 static const char * const i81342_steppings[16] = {
124 "step A-0", "rev 1", "rev 2", "rev 3",
125 "rev 4", "rev 5", "rev 6", "rev 7",
126 "rev 8", "rev 9", "rev 10", "rev 11",
127 "rev 12", "rev 13", "rev 14", "rev 15",
130 /* Steppings for PXA2[15]0 */
131 static const char * const pxa2x0_steppings[16] = {
132 "step A-0", "step A-1", "step B-0", "step B-1",
133 "step B-2", "step C-0", "rev 6", "rev 7",
134 "rev 8", "rev 9", "rev 10", "rev 11",
135 "rev 12", "rev 13", "rev 14", "rev 15",
138 /* Steppings for PXA255/26x.
139 * rev 5: PXA26x B0, rev 6: PXA255 A0
141 static const char * const pxa255_steppings[16] = {
142 "rev 0", "rev 1", "rev 2", "step A-0",
143 "rev 4", "step B-0", "step A-0", "rev 7",
144 "rev 8", "rev 9", "rev 10", "rev 11",
145 "rev 12", "rev 13", "rev 14", "rev 15",
148 /* Stepping for PXA27x */
149 static const char * const pxa27x_steppings[16] = {
150 "step A-0", "step A-1", "step B-0", "step B-1",
151 "step C-0", "rev 5", "rev 6", "rev 7",
152 "rev 8", "rev 9", "rev 10", "rev 11",
153 "rev 12", "rev 13", "rev 14", "rev 15",
156 static const char * const ixp425_steppings[16] = {
157 "step 0 (A0)", "rev 1 (ARMv5TE)", "rev 2", "rev 3",
158 "rev 4", "rev 5", "rev 6", "rev 7",
159 "rev 8", "rev 9", "rev 10", "rev 11",
160 "rev 12", "rev 13", "rev 14", "rev 15",
165 enum cpu_class cpu_class;
166 const char *cpu_name;
167 const char * const *cpu_steppings;
170 const struct cpuidtab cpuids[] = {
171 { CPU_ID_ARM2, CPU_CLASS_ARM2, "ARM2",
173 { CPU_ID_ARM250, CPU_CLASS_ARM2AS, "ARM250",
176 { CPU_ID_ARM3, CPU_CLASS_ARM3, "ARM3",
179 { CPU_ID_ARM600, CPU_CLASS_ARM6, "ARM600",
181 { CPU_ID_ARM610, CPU_CLASS_ARM6, "ARM610",
183 { CPU_ID_ARM620, CPU_CLASS_ARM6, "ARM620",
186 { CPU_ID_ARM700, CPU_CLASS_ARM7, "ARM700",
188 { CPU_ID_ARM710, CPU_CLASS_ARM7, "ARM710",
190 { CPU_ID_ARM7500, CPU_CLASS_ARM7, "ARM7500",
192 { CPU_ID_ARM710A, CPU_CLASS_ARM7, "ARM710a",
194 { CPU_ID_ARM7500FE, CPU_CLASS_ARM7, "ARM7500FE",
196 { CPU_ID_ARM710T, CPU_CLASS_ARM7TDMI, "ARM710T",
198 { CPU_ID_ARM720T, CPU_CLASS_ARM7TDMI, "ARM720T",
200 { CPU_ID_ARM740T8K, CPU_CLASS_ARM7TDMI, "ARM740T (8 KB cache)",
202 { CPU_ID_ARM740T4K, CPU_CLASS_ARM7TDMI, "ARM740T (4 KB cache)",
205 { CPU_ID_ARM810, CPU_CLASS_ARM8, "ARM810",
208 { CPU_ID_ARM920T, CPU_CLASS_ARM9TDMI, "ARM920T",
210 { CPU_ID_ARM920T_ALT, CPU_CLASS_ARM9TDMI, "ARM920T",
212 { CPU_ID_ARM922T, CPU_CLASS_ARM9TDMI, "ARM922T",
214 { CPU_ID_ARM926EJS, CPU_CLASS_ARM9EJS, "ARM926EJ-S",
216 { CPU_ID_ARM940T, CPU_CLASS_ARM9TDMI, "ARM940T",
218 { CPU_ID_ARM946ES, CPU_CLASS_ARM9ES, "ARM946E-S",
220 { CPU_ID_ARM966ES, CPU_CLASS_ARM9ES, "ARM966E-S",
222 { CPU_ID_ARM966ESR1, CPU_CLASS_ARM9ES, "ARM966E-S",
224 { CPU_ID_FA526, CPU_CLASS_ARM9TDMI, "FA526",
226 { CPU_ID_FA626TE, CPU_CLASS_ARM9ES, "FA626TE",
229 { CPU_ID_TI925T, CPU_CLASS_ARM9TDMI, "TI ARM925T",
232 { CPU_ID_ARM1020E, CPU_CLASS_ARM10E, "ARM1020E",
234 { CPU_ID_ARM1022ES, CPU_CLASS_ARM10E, "ARM1022E-S",
236 { CPU_ID_ARM1026EJS, CPU_CLASS_ARM10EJ, "ARM1026EJ-S",
239 { CPU_ID_CORTEXA7, CPU_CLASS_CORTEXA, "Cortex A7",
241 { CPU_ID_CORTEXA8R1, CPU_CLASS_CORTEXA, "Cortex A8-r1",
243 { CPU_ID_CORTEXA8R2, CPU_CLASS_CORTEXA, "Cortex A8-r2",
245 { CPU_ID_CORTEXA8R3, CPU_CLASS_CORTEXA, "Cortex A8-r3",
247 { CPU_ID_CORTEXA9R1, CPU_CLASS_CORTEXA, "Cortex A9-r1",
249 { CPU_ID_CORTEXA9R2, CPU_CLASS_CORTEXA, "Cortex A9-r2",
251 { CPU_ID_CORTEXA9R3, CPU_CLASS_CORTEXA, "Cortex A9-r3",
253 { CPU_ID_CORTEXA15, CPU_CLASS_CORTEXA, "Cortex A15",
256 { CPU_ID_SA110, CPU_CLASS_SA1, "SA-110",
258 { CPU_ID_SA1100, CPU_CLASS_SA1, "SA-1100",
260 { CPU_ID_SA1110, CPU_CLASS_SA1, "SA-1110",
263 { CPU_ID_IXP1200, CPU_CLASS_SA1, "IXP1200",
266 { CPU_ID_80200, CPU_CLASS_XSCALE, "i80200",
269 { CPU_ID_80321_400, CPU_CLASS_XSCALE, "i80321 400MHz",
271 { CPU_ID_80321_600, CPU_CLASS_XSCALE, "i80321 600MHz",
273 { CPU_ID_80321_400_B0, CPU_CLASS_XSCALE, "i80321 400MHz",
275 { CPU_ID_80321_600_B0, CPU_CLASS_XSCALE, "i80321 600MHz",
278 { CPU_ID_81342, CPU_CLASS_XSCALE, "i81342",
281 { CPU_ID_80219_400, CPU_CLASS_XSCALE, "i80219 400MHz",
283 { CPU_ID_80219_600, CPU_CLASS_XSCALE, "i80219 600MHz",
286 { CPU_ID_PXA27X, CPU_CLASS_XSCALE, "PXA27x",
288 { CPU_ID_PXA250A, CPU_CLASS_XSCALE, "PXA250",
290 { CPU_ID_PXA210A, CPU_CLASS_XSCALE, "PXA210",
292 { CPU_ID_PXA250B, CPU_CLASS_XSCALE, "PXA250",
294 { CPU_ID_PXA210B, CPU_CLASS_XSCALE, "PXA210",
296 { CPU_ID_PXA250C, CPU_CLASS_XSCALE, "PXA255",
298 { CPU_ID_PXA210C, CPU_CLASS_XSCALE, "PXA210",
301 { CPU_ID_IXP425_533, CPU_CLASS_XSCALE, "IXP425 533MHz",
303 { CPU_ID_IXP425_400, CPU_CLASS_XSCALE, "IXP425 400MHz",
305 { CPU_ID_IXP425_266, CPU_CLASS_XSCALE, "IXP425 266MHz",
308 /* XXX ixp435 steppings? */
309 { CPU_ID_IXP435, CPU_CLASS_XSCALE, "IXP435",
312 { CPU_ID_ARM1136JS, CPU_CLASS_ARM11J, "ARM1136J-S",
314 { CPU_ID_ARM1136JSR1, CPU_CLASS_ARM11J, "ARM1136J-S R1",
316 { CPU_ID_ARM1176JZS, CPU_CLASS_ARM11J, "ARM1176JZ-S",
319 { CPU_ID_MV88FR131, CPU_CLASS_MARVELL, "Feroceon 88FR131",
322 { CPU_ID_MV88FR571_VD, CPU_CLASS_MARVELL, "Feroceon 88FR571-VD",
324 { CPU_ID_MV88SV581X_V6, CPU_CLASS_MARVELL, "Sheeva 88SV581x",
326 { CPU_ID_ARM_88SV581X_V6, CPU_CLASS_MARVELL, "Sheeva 88SV581x",
328 { CPU_ID_MV88SV581X_V7, CPU_CLASS_MARVELL, "Sheeva 88SV581x",
330 { CPU_ID_ARM_88SV581X_V7, CPU_CLASS_MARVELL, "Sheeva 88SV581x",
332 { CPU_ID_MV88SV584X_V6, CPU_CLASS_MARVELL, "Sheeva 88SV584x",
334 { CPU_ID_ARM_88SV584X_V6, CPU_CLASS_MARVELL, "Sheeva 88SV584x",
336 { CPU_ID_MV88SV584X_V7, CPU_CLASS_MARVELL, "Sheeva 88SV584x",
339 { 0, CPU_CLASS_NONE, NULL, NULL }
342 struct cpu_classtab {
343 const char *class_name;
344 const char *class_option;
347 const struct cpu_classtab cpu_classes[] = {
348 { "unknown", NULL }, /* CPU_CLASS_NONE */
349 { "ARM2", "CPU_ARM2" }, /* CPU_CLASS_ARM2 */
350 { "ARM2as", "CPU_ARM250" }, /* CPU_CLASS_ARM2AS */
351 { "ARM3", "CPU_ARM3" }, /* CPU_CLASS_ARM3 */
352 { "ARM6", "CPU_ARM6" }, /* CPU_CLASS_ARM6 */
353 { "ARM7", "CPU_ARM7" }, /* CPU_CLASS_ARM7 */
354 { "ARM7TDMI", "CPU_ARM7TDMI" }, /* CPU_CLASS_ARM7TDMI */
355 { "ARM8", "CPU_ARM8" }, /* CPU_CLASS_ARM8 */
356 { "ARM9TDMI", "CPU_ARM9TDMI" }, /* CPU_CLASS_ARM9TDMI */
357 { "ARM9E-S", "CPU_ARM9E" }, /* CPU_CLASS_ARM9ES */
358 { "ARM9EJ-S", "CPU_ARM9E" }, /* CPU_CLASS_ARM9EJS */
359 { "ARM10E", "CPU_ARM10" }, /* CPU_CLASS_ARM10E */
360 { "ARM10EJ", "CPU_ARM10" }, /* CPU_CLASS_ARM10EJ */
361 { "Cortex-A", "CPU_CORTEXA" }, /* CPU_CLASS_CORTEXA */
362 { "SA-1", "CPU_SA110" }, /* CPU_CLASS_SA1 */
363 { "XScale", "CPU_XSCALE_..." }, /* CPU_CLASS_XSCALE */
364 { "ARM11J", "CPU_ARM11" }, /* CPU_CLASS_ARM11J */
365 { "Marvell", "CPU_MARVELL" }, /* CPU_CLASS_MARVELL */
369 * Report the type of the specified arm processor. This uses the generic and
370 * arm specific information in the cpu structure to identify the processor.
371 * The remaining fields in the cpu structure are filled in appropriately.
374 static const char * const wtnames[] = {
380 "write-back-locking", /* XXX XScale-specific? */
381 "write-back-locking-A",
382 "write-back-locking-B",
389 "write-back-locking-C",
394 print_enadis(int enadis, char *s)
397 printf(" %s %sabled", s, (enadis == 0) ? "dis" : "en");
401 enum cpu_class cpu_class = CPU_CLASS_NONE;
403 u_int cpu_pfr(int num)
409 __asm __volatile("mrc p15, 0, %0, c0, c1, 0"
413 __asm __volatile("mrc p15, 0, %0, c0, c1, 1"
417 panic("Processor Feature Register %d not implemented", num);
425 void identify_armv7(void)
429 printf("Supported features:");
430 /* Get Processor Feature Register 0 */
431 feature = cpu_pfr(0);
433 if (feature & ARM_PFR0_ARM_ISA_MASK)
436 if (feature & ARM_PFR0_THUMB2)
438 else if (feature & ARM_PFR0_THUMB)
441 if (feature & ARM_PFR0_JAZELLE_MASK)
444 if (feature & ARM_PFR0_THUMBEE_MASK)
448 /* Get Processor Feature Register 1 */
449 feature = cpu_pfr(1);
451 if (feature & ARM_PFR1_ARMV4_MASK)
454 if (feature & ARM_PFR1_SEC_EXT_MASK)
455 printf(" Security_Ext");
457 if (feature & ARM_PFR1_MICROCTRL_MASK)
458 printf(" M_profile");
464 identify_arm_cpu(void)
466 u_int cpuid, reg, size, sets, ways;
467 u_int8_t type, linesize;
473 printf("Processor failed probe - no CPU ID\n");
477 for (i = 0; cpuids[i].cpuid != 0; i++)
478 if (cpuids[i].cpuid == (cpuid & CPU_ID_CPU_MASK)) {
479 cpu_class = cpuids[i].cpu_class;
480 printf("CPU: %s %s (%s core)\n",
482 cpuids[i].cpu_steppings[cpuid &
483 CPU_ID_REVISION_MASK],
484 cpu_classes[cpu_class].class_name);
487 if (cpuids[i].cpuid == 0)
488 printf("unknown CPU (ID = 0x%x)\n", cpuid);
492 if ((cpuid & CPU_ID_ARCH_MASK) == CPU_ID_CPUID_SCHEME) {
495 if (ctrl & CPU_CONTROL_BEND_ENABLE)
496 printf(" Big-endian");
498 printf(" Little-endian");
503 case CPU_CLASS_ARM7TDMI:
505 print_enadis(ctrl & CPU_CONTROL_IDC_ENABLE, "IDC");
507 case CPU_CLASS_ARM9TDMI:
508 case CPU_CLASS_ARM9ES:
509 case CPU_CLASS_ARM9EJS:
510 case CPU_CLASS_ARM10E:
511 case CPU_CLASS_ARM10EJ:
513 case CPU_CLASS_XSCALE:
514 case CPU_CLASS_ARM11J:
515 case CPU_CLASS_MARVELL:
516 print_enadis(ctrl & CPU_CONTROL_DC_ENABLE, "DC");
517 print_enadis(ctrl & CPU_CONTROL_IC_ENABLE, "IC");
518 #ifdef CPU_XSCALE_81342
519 print_enadis(ctrl & CPU_CONTROL_L2_ENABLE, "L2");
521 #if defined(SOC_MV_KIRKWOOD) || defined(SOC_MV_DISCOVERY)
522 i = sheeva_control_ext(0, 0);
523 print_enadis(i & MV_WA_ENABLE, "WA");
524 print_enadis(i & MV_DC_STREAM_ENABLE, "DC streaming");
526 print_enadis((i & MV_BTB_DISABLE) == 0, "BTB");
527 print_enadis(i & MV_L2_ENABLE, "L2");
528 print_enadis((i & MV_L2_PREFETCH_DISABLE) == 0,
538 print_enadis(ctrl & CPU_CONTROL_WBUF_ENABLE, "WB");
539 if (ctrl & CPU_CONTROL_LABT_ENABLE)
544 print_enadis(ctrl & CPU_CONTROL_BPRD_ENABLE, "branch prediction");
547 if (arm_cache_level) {
548 printf("LoUU:%d LoC:%d LoUIS:%d \n", CPU_CLIDR_LOUU(arm_cache_level) + 1,
549 arm_cache_loc, CPU_CLIDR_LOUIS(arm_cache_level) + 1);
551 while (((type = CPU_CLIDR_CTYPE(arm_cache_level, i)) != 0) && i < 7) {
552 printf("Cache level %d: \n", i + 1);
553 if (type == CACHE_DCACHE || type == CACHE_UNI_CACHE ||
554 type == CACHE_SEP_CACHE) {
555 reg = arm_cache_type[2 * i];
556 ways = CPUV7_CT_xSIZE_ASSOC(reg) + 1;
557 sets = CPUV7_CT_xSIZE_SET(reg) + 1;
558 linesize = 1 << (CPUV7_CT_xSIZE_LEN(reg) + 4);
559 size = (ways * sets * linesize) / 1024;
561 if (type == CACHE_UNI_CACHE)
562 printf(" %dKB/%dB %d-way unified cache", size, linesize,ways);
564 printf(" %dKB/%dB %d-way data cache", size, linesize, ways);
565 if (reg & CPUV7_CT_CTYPE_WT)
567 if (reg & CPUV7_CT_CTYPE_WB)
569 if (reg & CPUV7_CT_CTYPE_RA)
570 printf(" Read-Alloc");
571 if (reg & CPUV7_CT_CTYPE_WA)
572 printf(" Write-Alloc");
576 if (type == CACHE_ICACHE || type == CACHE_SEP_CACHE) {
577 reg = arm_cache_type[(2 * i) + 1];
579 ways = CPUV7_CT_xSIZE_ASSOC(reg) + 1;
580 sets = CPUV7_CT_xSIZE_SET(reg) + 1;
581 linesize = 1 << (CPUV7_CT_xSIZE_LEN(reg) + 4);
582 size = (ways * sets * linesize) / 1024;
584 printf(" %dKB/%dB %d-way instruction cache", size, linesize, ways);
585 if (reg & CPUV7_CT_CTYPE_WT)
587 if (reg & CPUV7_CT_CTYPE_WB)
589 if (reg & CPUV7_CT_CTYPE_RA)
590 printf(" Read-Alloc");
591 if (reg & CPUV7_CT_CTYPE_WA)
592 printf(" Write-Alloc");
598 /* Print cache info. */
599 if (arm_picache_line_size == 0 && arm_pdcache_line_size == 0)
602 if (arm_pcache_unified) {
603 printf(" %dKB/%dB %d-way %s unified cache\n",
604 arm_pdcache_size / 1024,
605 arm_pdcache_line_size, arm_pdcache_ways,
606 wtnames[arm_pcache_type]);
608 printf(" %dKB/%dB %d-way instruction cache\n",
609 arm_picache_size / 1024,
610 arm_picache_line_size, arm_picache_ways);
611 printf(" %dKB/%dB %d-way %s data cache\n",
612 arm_pdcache_size / 1024,
613 arm_pdcache_line_size, arm_pdcache_ways,
614 wtnames[arm_pcache_type]);