cpu.c revision 1.85 1 /* $NetBSD: cpu.c,v 1.85 2012/08/29 17:44:25 matt 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 "opt_armfpe.h"
45 #include "opt_multiprocessor.h"
46
47 #include <sys/param.h>
48
49 __KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.85 2012/08/29 17:44:25 matt Exp $");
50
51 #include <sys/systm.h>
52 #include <sys/conf.h>
53 #include <sys/cpu.h>
54 #include <sys/device.h>
55 #include <sys/kmem.h>
56 #include <sys/proc.h>
57
58 #include <uvm/uvm_extern.h>
59
60 #include <arm/cpuconf.h>
61 #include <arm/undefined.h>
62
63 #ifdef ARMFPE
64 #include <machine/bootconfig.h> /* For boot args */
65 #include <arm/fpe-arm/armfpe.h>
66 #endif
67
68 char cpu_model[256];
69
70 #ifdef MULTIPROCESSOR
71 volatile u_int arm_cpu_hatched = 0;
72 u_int arm_cpu_max = 0;
73 uint32_t arm_cpu_mbox __cacheline_aligned = 0;
74 uint32_t arm_cpu_marker __cacheline_aligned = 1;
75 #endif
76
77 /* Prototypes */
78 void identify_arm_cpu(device_t dv, struct cpu_info *);
79 void identify_cortex_caches(device_t dv);
80 void identify_features(device_t dv);
81
82 /*
83 * Identify the master (boot) CPU
84 */
85
86 void
87 cpu_attach(device_t dv, cpuid_t id)
88 {
89 struct cpu_info *ci;
90
91 if (id == 0) {
92 ci = curcpu();
93
94 /* Get the CPU ID from coprocessor 15 */
95
96 ci->ci_arm_cpuid = cpu_id();
97 ci->ci_arm_cputype = ci->ci_arm_cpuid & CPU_ID_CPU_MASK;
98 ci->ci_arm_cpurev = ci->ci_arm_cpuid & CPU_ID_REVISION_MASK;
99 } else {
100 #ifdef MULTIPROCESSOR
101 KASSERT(cpu_info[id] == NULL);
102 ci = kmem_zalloc(sizeof(*ci), KM_SLEEP);
103 KASSERT(ci != NULL);
104 ci->ci_cpl = IPL_HIGH;
105 ci->ci_cpuid = id;
106 ci->ci_data.cpu_core_id = id;
107 ci->ci_data.cpu_cc_freq = cpu_info_store.ci_data.cpu_cc_freq;
108 ci->ci_arm_cpuid = cpu_info_store.ci_arm_cpuid;
109 ci->ci_arm_cputype = cpu_info_store.ci_arm_cputype;
110 ci->ci_arm_cpurev = cpu_info_store.ci_arm_cpurev;
111 cpu_info[ci->ci_cpuid] = ci;
112 if ((arm_cpu_hatched & (1 << id)) == 0) {
113 ci->ci_dev = dv;
114 dv->dv_private = ci;
115 aprint_naive(": disabled\n");
116 aprint_normal(": disabled (unresponsive)\n");
117 return;
118 }
119 #else
120 aprint_naive(": disabled\n");
121 aprint_normal(": disabled (uniprocessor kernel)\n");
122 return;
123 #endif
124 }
125
126 ci->ci_dev = dv;
127 dv->dv_private = ci;
128
129 evcnt_attach_dynamic(&ci->ci_arm700bugcount, EVCNT_TYPE_MISC,
130 NULL, device_xname(dv), "arm700swibug");
131
132 #ifdef MULTIPROCESSOR
133 /*
134 * and we are done if this is a secondary processor.
135 */
136 if (!CPU_IS_PRIMARY(ci)) {
137 aprint_naive(": %s\n", cpu_model);
138 aprint_normal(": %s\n", cpu_model);
139 mi_cpu_attach(ci);
140 return;
141 }
142 #endif
143
144 identify_arm_cpu(dv, ci);
145
146 #ifdef CPU_STRONGARM
147 if (ci->ci_arm_cputype == CPU_ID_SA110 &&
148 ci->ci_arm_cpurev < 3) {
149 aprint_normal_dev(dv, "SA-110 with bugged STM^ instruction\n");
150 }
151 #endif
152
153 #ifdef CPU_ARM8
154 if ((ci->ci_arm_cpuid & CPU_ID_CPU_MASK) == CPU_ID_ARM810) {
155 int clock = arm8_clock_config(0, 0);
156 char *fclk;
157 aprint_normal_dev(dv, "ARM810 cp15=%02x", clock);
158 aprint_normal(" clock:%s", (clock & 1) ? " dynamic" : "");
159 aprint_normal("%s", (clock & 2) ? " sync" : "");
160 switch ((clock >> 2) & 3) {
161 case 0:
162 fclk = "bus clock";
163 break;
164 case 1:
165 fclk = "ref clock";
166 break;
167 case 3:
168 fclk = "pll";
169 break;
170 default:
171 fclk = "illegal";
172 break;
173 }
174 aprint_normal(" fclk source=%s\n", fclk);
175 }
176 #endif
177
178 #ifdef ARMFPE
179 /*
180 * Ok now we test for an FPA
181 * At this point no floating point emulator has been installed.
182 * This means any FP instruction will cause undefined exception.
183 * We install a temporay coproc 1 handler which will modify
184 * undefined_test if it is called.
185 * We then try to read the FP status register. If undefined_test
186 * has been decremented then the instruction was not handled by
187 * an FPA so we know the FPA is missing. If undefined_test is
188 * still 1 then we know the instruction was handled by an FPA.
189 * We then remove our test handler and look at the
190 * FP status register for identification.
191 */
192
193 /*
194 * Ok if ARMFPE is defined and the boot options request the
195 * ARM FPE then it will be installed as the FPE.
196 * This is just while I work on integrating the new FPE.
197 * It means the new FPE gets installed if compiled int (ARMFPE
198 * defined) and also gives me a on/off option when I boot in
199 * case the new FPE is causing panics.
200 */
201
202
203 int usearmfpe = 1;
204 if (boot_args)
205 get_bootconf_option(boot_args, "armfpe",
206 BOOTOPT_TYPE_BOOLEAN, &usearmfpe);
207 if (usearmfpe)
208 initialise_arm_fpe();
209 #endif
210
211 vfp_attach(); /* XXX SMP */
212 }
213
214 enum cpu_class {
215 CPU_CLASS_NONE,
216 CPU_CLASS_ARM2,
217 CPU_CLASS_ARM2AS,
218 CPU_CLASS_ARM3,
219 CPU_CLASS_ARM6,
220 CPU_CLASS_ARM7,
221 CPU_CLASS_ARM7TDMI,
222 CPU_CLASS_ARM8,
223 CPU_CLASS_ARM9TDMI,
224 CPU_CLASS_ARM9ES,
225 CPU_CLASS_ARM9EJS,
226 CPU_CLASS_ARM10E,
227 CPU_CLASS_ARM10EJ,
228 CPU_CLASS_SA1,
229 CPU_CLASS_XSCALE,
230 CPU_CLASS_ARM11J,
231 CPU_CLASS_ARMV4,
232 CPU_CLASS_CORTEX,
233 };
234
235 static const char * const generic_steppings[16] = {
236 "rev 0", "rev 1", "rev 2", "rev 3",
237 "rev 4", "rev 5", "rev 6", "rev 7",
238 "rev 8", "rev 9", "rev 10", "rev 11",
239 "rev 12", "rev 13", "rev 14", "rev 15",
240 };
241
242 static const char * const pN_steppings[16] = {
243 "*p0", "*p1", "*p2", "*p3", "*p4", "*p5", "*p6", "*p7",
244 "*p8", "*p9", "*p10", "*p11", "*p12", "*p13", "*p14", "*p15",
245 };
246
247 static const char * const sa110_steppings[16] = {
248 "rev 0", "step J", "step K", "step S",
249 "step T", "rev 5", "rev 6", "rev 7",
250 "rev 8", "rev 9", "rev 10", "rev 11",
251 "rev 12", "rev 13", "rev 14", "rev 15",
252 };
253
254 static const char * const sa1100_steppings[16] = {
255 "rev 0", "step B", "step C", "rev 3",
256 "rev 4", "rev 5", "rev 6", "rev 7",
257 "step D", "step E", "rev 10" "step G",
258 "rev 12", "rev 13", "rev 14", "rev 15",
259 };
260
261 static const char * const sa1110_steppings[16] = {
262 "step A-0", "rev 1", "rev 2", "rev 3",
263 "step B-0", "step B-1", "step B-2", "step B-3",
264 "step B-4", "step B-5", "rev 10", "rev 11",
265 "rev 12", "rev 13", "rev 14", "rev 15",
266 };
267
268 static const char * const ixp12x0_steppings[16] = {
269 "(IXP1200 step A)", "(IXP1200 step B)",
270 "rev 2", "(IXP1200 step C)",
271 "(IXP1200 step D)", "(IXP1240/1250 step A)",
272 "(IXP1240 step B)", "(IXP1250 step B)",
273 "rev 8", "rev 9", "rev 10", "rev 11",
274 "rev 12", "rev 13", "rev 14", "rev 15",
275 };
276
277 static const char * const xscale_steppings[16] = {
278 "step A-0", "step A-1", "step B-0", "step C-0",
279 "step D-0", "rev 5", "rev 6", "rev 7",
280 "rev 8", "rev 9", "rev 10", "rev 11",
281 "rev 12", "rev 13", "rev 14", "rev 15",
282 };
283
284 static const char * const i80321_steppings[16] = {
285 "step A-0", "step B-0", "rev 2", "rev 3",
286 "rev 4", "rev 5", "rev 6", "rev 7",
287 "rev 8", "rev 9", "rev 10", "rev 11",
288 "rev 12", "rev 13", "rev 14", "rev 15",
289 };
290
291 static const char * const i80219_steppings[16] = {
292 "step A-0", "rev 1", "rev 2", "rev 3",
293 "rev 4", "rev 5", "rev 6", "rev 7",
294 "rev 8", "rev 9", "rev 10", "rev 11",
295 "rev 12", "rev 13", "rev 14", "rev 15",
296 };
297
298 /* Steppings for PXA2[15]0 */
299 static const char * const pxa2x0_steppings[16] = {
300 "step A-0", "step A-1", "step B-0", "step B-1",
301 "step B-2", "step C-0", "rev 6", "rev 7",
302 "rev 8", "rev 9", "rev 10", "rev 11",
303 "rev 12", "rev 13", "rev 14", "rev 15",
304 };
305
306 /* Steppings for PXA255/26x.
307 * rev 5: PXA26x B0, rev 6: PXA255 A0
308 */
309 static const char * const pxa255_steppings[16] = {
310 "rev 0", "rev 1", "rev 2", "step A-0",
311 "rev 4", "step B-0", "step A-0", "rev 7",
312 "rev 8", "rev 9", "rev 10", "rev 11",
313 "rev 12", "rev 13", "rev 14", "rev 15",
314 };
315
316 /* Stepping for PXA27x */
317 static const char * const pxa27x_steppings[16] = {
318 "step A-0", "step A-1", "step B-0", "step B-1",
319 "step C-0", "rev 5", "rev 6", "rev 7",
320 "rev 8", "rev 9", "rev 10", "rev 11",
321 "rev 12", "rev 13", "rev 14", "rev 15",
322 };
323
324 static const char * const ixp425_steppings[16] = {
325 "step 0", "rev 1", "rev 2", "rev 3",
326 "rev 4", "rev 5", "rev 6", "rev 7",
327 "rev 8", "rev 9", "rev 10", "rev 11",
328 "rev 12", "rev 13", "rev 14", "rev 15",
329 };
330
331 struct cpuidtab {
332 u_int32_t cpuid;
333 enum cpu_class cpu_class;
334 const char *cpu_classname;
335 const char * const *cpu_steppings;
336 };
337
338 const struct cpuidtab cpuids[] = {
339 { CPU_ID_ARM2, CPU_CLASS_ARM2, "ARM2",
340 generic_steppings },
341 { CPU_ID_ARM250, CPU_CLASS_ARM2AS, "ARM250",
342 generic_steppings },
343
344 { CPU_ID_ARM3, CPU_CLASS_ARM3, "ARM3",
345 generic_steppings },
346
347 { CPU_ID_ARM600, CPU_CLASS_ARM6, "ARM600",
348 generic_steppings },
349 { CPU_ID_ARM610, CPU_CLASS_ARM6, "ARM610",
350 generic_steppings },
351 { CPU_ID_ARM620, CPU_CLASS_ARM6, "ARM620",
352 generic_steppings },
353
354 { CPU_ID_ARM700, CPU_CLASS_ARM7, "ARM700",
355 generic_steppings },
356 { CPU_ID_ARM710, CPU_CLASS_ARM7, "ARM710",
357 generic_steppings },
358 { CPU_ID_ARM7500, CPU_CLASS_ARM7, "ARM7500",
359 generic_steppings },
360 { CPU_ID_ARM710A, CPU_CLASS_ARM7, "ARM710a",
361 generic_steppings },
362 { CPU_ID_ARM7500FE, CPU_CLASS_ARM7, "ARM7500FE",
363 generic_steppings },
364 { CPU_ID_ARM710T, CPU_CLASS_ARM7TDMI, "ARM710T",
365 generic_steppings },
366 { CPU_ID_ARM720T, CPU_CLASS_ARM7TDMI, "ARM720T",
367 generic_steppings },
368 { CPU_ID_ARM740T8K, CPU_CLASS_ARM7TDMI, "ARM740T (8 KB cache)",
369 generic_steppings },
370 { CPU_ID_ARM740T4K, CPU_CLASS_ARM7TDMI, "ARM740T (4 KB cache)",
371 generic_steppings },
372
373 { CPU_ID_ARM810, CPU_CLASS_ARM8, "ARM810",
374 generic_steppings },
375
376 { CPU_ID_ARM920T, CPU_CLASS_ARM9TDMI, "ARM920T",
377 generic_steppings },
378 { CPU_ID_ARM922T, CPU_CLASS_ARM9TDMI, "ARM922T",
379 generic_steppings },
380 { CPU_ID_ARM926EJS, CPU_CLASS_ARM9EJS, "ARM926EJ-S",
381 generic_steppings },
382 { CPU_ID_ARM940T, CPU_CLASS_ARM9TDMI, "ARM940T",
383 generic_steppings },
384 { CPU_ID_ARM946ES, CPU_CLASS_ARM9ES, "ARM946E-S",
385 generic_steppings },
386 { CPU_ID_ARM966ES, CPU_CLASS_ARM9ES, "ARM966E-S",
387 generic_steppings },
388 { CPU_ID_ARM966ESR1, CPU_CLASS_ARM9ES, "ARM966E-S",
389 generic_steppings },
390 { CPU_ID_TI925T, CPU_CLASS_ARM9TDMI, "TI ARM925T",
391 generic_steppings },
392 { CPU_ID_MV88SV131, CPU_CLASS_ARM9ES, "Sheeva 88SV131",
393 generic_steppings },
394 { CPU_ID_MV88FR571_VD, CPU_CLASS_ARM9ES, "Sheeva 88FR571-vd",
395 generic_steppings },
396
397 { CPU_ID_ARM1020E, CPU_CLASS_ARM10E, "ARM1020E",
398 generic_steppings },
399 { CPU_ID_ARM1022ES, CPU_CLASS_ARM10E, "ARM1022E-S",
400 generic_steppings },
401 { CPU_ID_ARM1026EJS, CPU_CLASS_ARM10EJ, "ARM1026EJ-S",
402 generic_steppings },
403
404 { CPU_ID_SA110, CPU_CLASS_SA1, "SA-110",
405 sa110_steppings },
406 { CPU_ID_SA1100, CPU_CLASS_SA1, "SA-1100",
407 sa1100_steppings },
408 { CPU_ID_SA1110, CPU_CLASS_SA1, "SA-1110",
409 sa1110_steppings },
410
411 { CPU_ID_IXP1200, CPU_CLASS_SA1, "IXP1200",
412 ixp12x0_steppings },
413
414 { CPU_ID_80200, CPU_CLASS_XSCALE, "i80200",
415 xscale_steppings },
416
417 { CPU_ID_80321_400, CPU_CLASS_XSCALE, "i80321 400MHz",
418 i80321_steppings },
419 { CPU_ID_80321_600, CPU_CLASS_XSCALE, "i80321 600MHz",
420 i80321_steppings },
421 { CPU_ID_80321_400_B0, CPU_CLASS_XSCALE, "i80321 400MHz",
422 i80321_steppings },
423 { CPU_ID_80321_600_B0, CPU_CLASS_XSCALE, "i80321 600MHz",
424 i80321_steppings },
425
426 { CPU_ID_80219_400, CPU_CLASS_XSCALE, "i80219 400MHz",
427 i80219_steppings },
428 { CPU_ID_80219_600, CPU_CLASS_XSCALE, "i80219 600MHz",
429 i80219_steppings },
430
431 { CPU_ID_PXA27X, CPU_CLASS_XSCALE, "PXA27x",
432 pxa27x_steppings },
433 { CPU_ID_PXA250A, CPU_CLASS_XSCALE, "PXA250",
434 pxa2x0_steppings },
435 { CPU_ID_PXA210A, CPU_CLASS_XSCALE, "PXA210",
436 pxa2x0_steppings },
437 { CPU_ID_PXA250B, CPU_CLASS_XSCALE, "PXA250",
438 pxa2x0_steppings },
439 { CPU_ID_PXA210B, CPU_CLASS_XSCALE, "PXA210",
440 pxa2x0_steppings },
441 { CPU_ID_PXA250C, CPU_CLASS_XSCALE, "PXA255/26x",
442 pxa255_steppings },
443 { CPU_ID_PXA210C, CPU_CLASS_XSCALE, "PXA210",
444 pxa2x0_steppings },
445
446 { CPU_ID_IXP425_533, CPU_CLASS_XSCALE, "IXP425 533MHz",
447 ixp425_steppings },
448 { CPU_ID_IXP425_400, CPU_CLASS_XSCALE, "IXP425 400MHz",
449 ixp425_steppings },
450 { CPU_ID_IXP425_266, CPU_CLASS_XSCALE, "IXP425 266MHz",
451 ixp425_steppings },
452
453 { CPU_ID_ARM1136JS, CPU_CLASS_ARM11J, "ARM1136J-S r0",
454 pN_steppings },
455 { CPU_ID_ARM1136JSR1, CPU_CLASS_ARM11J, "ARM1136J-S r1",
456 pN_steppings },
457 #if 0
458 /* The ARM1156T2-S only has a memory protection unit */
459 { CPU_ID_ARM1156T2S, CPU_CLASS_ARM11J, "ARM1156T2-S r0",
460 pN_steppings },
461 #endif
462 { CPU_ID_ARM1176JZS, CPU_CLASS_ARM11J, "ARM1176JZ-S r0",
463 pN_steppings },
464
465 { CPU_ID_ARM11MPCORE, CPU_CLASS_ARM11J, "ARM11 MPCore",
466 generic_steppings },
467
468 { CPU_ID_CORTEXA5R0, CPU_CLASS_CORTEX, "Cortex-A5 r0",
469 pN_steppings },
470 { CPU_ID_CORTEXA8R1, CPU_CLASS_CORTEX, "Cortex-A8 r1",
471 pN_steppings },
472 { CPU_ID_CORTEXA8R2, CPU_CLASS_CORTEX, "Cortex-A8 r2",
473 pN_steppings },
474 { CPU_ID_CORTEXA8R3, CPU_CLASS_CORTEX, "Cortex-A8 r3",
475 pN_steppings },
476 { CPU_ID_CORTEXA9R2, CPU_CLASS_CORTEX, "Cortex-A9 r2",
477 pN_steppings },
478 { CPU_ID_CORTEXA9R3, CPU_CLASS_CORTEX, "Cortex-A9 r3",
479 pN_steppings },
480 { CPU_ID_CORTEXA9R4, CPU_CLASS_CORTEX, "Cortex-A9 r4",
481 pN_steppings },
482 { CPU_ID_CORTEXA15R2, CPU_CLASS_CORTEX, "Cortex-A15 r2",
483 pN_steppings },
484 { CPU_ID_CORTEXA15R3, CPU_CLASS_CORTEX, "Cortex-A15 r3",
485 pN_steppings },
486
487 { CPU_ID_FA526, CPU_CLASS_ARMV4, "FA526",
488 generic_steppings },
489
490 { 0, CPU_CLASS_NONE, NULL, NULL }
491 };
492
493 struct cpu_classtab {
494 const char *class_name;
495 const char *class_option;
496 };
497
498 const struct cpu_classtab cpu_classes[] = {
499 [CPU_CLASS_NONE] = { "unknown", NULL },
500 [CPU_CLASS_ARM2] = { "ARM2", "CPU_ARM2" },
501 [CPU_CLASS_ARM2AS] = { "ARM2as", "CPU_ARM250" },
502 [CPU_CLASS_ARM3] = { "ARM3", "CPU_ARM3" },
503 [CPU_CLASS_ARM6] = { "ARM6", "CPU_ARM6" },
504 [CPU_CLASS_ARM7] = { "ARM7", "CPU_ARM7" },
505 [CPU_CLASS_ARM7TDMI] = { "ARM7TDMI", "CPU_ARM7TDMI" },
506 [CPU_CLASS_ARM8] = { "ARM8", "CPU_ARM8" },
507 [CPU_CLASS_ARM9TDMI] = { "ARM9TDMI", NULL },
508 [CPU_CLASS_ARM9ES] = { "ARM9E-S", "CPU_ARM9E" },
509 [CPU_CLASS_ARM9EJS] = { "ARM9EJ-S", "CPU_ARM9E" },
510 [CPU_CLASS_ARM10E] = { "ARM10E", "CPU_ARM10" },
511 [CPU_CLASS_ARM10EJ] = { "ARM10EJ", "CPU_ARM10" },
512 [CPU_CLASS_SA1] = { "SA-1", "CPU_SA110" },
513 [CPU_CLASS_XSCALE] = { "XScale", "CPU_XSCALE_..." },
514 [CPU_CLASS_ARM11J] = { "ARM11J", "CPU_ARM11" },
515 [CPU_CLASS_ARMV4] = { "ARMv4", "CPU_ARMV4" },
516 [CPU_CLASS_CORTEX] = { "Cortex", "CPU_CORTEX" },
517 };
518
519 /*
520 * Report the type of the specified arm processor. This uses the generic and
521 * arm specific information in the CPU structure to identify the processor.
522 * The remaining fields in the CPU structure are filled in appropriately.
523 */
524
525 static const char * const wtnames[] = {
526 "write-through",
527 "write-back",
528 "write-back",
529 "**unknown 3**",
530 "**unknown 4**",
531 "write-back-locking", /* XXX XScale-specific? */
532 "write-back-locking-A",
533 "write-back-locking-B",
534 "**unknown 8**",
535 "**unknown 9**",
536 "**unknown 10**",
537 "**unknown 11**",
538 "**unknown 12**",
539 "**unknown 13**",
540 "write-back-locking-C",
541 "**unknown 15**",
542 };
543
544 void
545 identify_arm_cpu(device_t dv, struct cpu_info *ci)
546 {
547 enum cpu_class cpu_class = CPU_CLASS_NONE;
548 const u_int cpuid = ci->ci_arm_cpuid;
549 const char * const xname = device_xname(dv);
550 const char *steppingstr;
551 int i;
552
553 if (cpuid == 0) {
554 aprint_error("Processor failed probe - no CPU ID\n");
555 return;
556 }
557
558 for (i = 0; cpuids[i].cpuid != 0; i++)
559 if (cpuids[i].cpuid == (cpuid & CPU_ID_CPU_MASK)) {
560 cpu_class = cpuids[i].cpu_class;
561 steppingstr = cpuids[i].cpu_steppings[cpuid &
562 CPU_ID_REVISION_MASK],
563 sprintf(cpu_model, "%s%s%s (%s core)",
564 cpuids[i].cpu_classname,
565 steppingstr[0] == '*' ? "" : " ",
566 &steppingstr[steppingstr[0] == '*'],
567 cpu_classes[cpu_class].class_name);
568 break;
569 }
570
571 if (cpuids[i].cpuid == 0)
572 sprintf(cpu_model, "unknown CPU (ID = 0x%x)", cpuid);
573
574 if (ci->ci_data.cpu_cc_freq != 0) {
575 char freqbuf[8];
576 humanize_number(freqbuf, sizeof(freqbuf), ci->ci_data.cpu_cc_freq,
577 "Hz", 1000);
578
579 aprint_naive(": %s %s\n", freqbuf, cpu_model);
580 aprint_normal(": %s %s\n", freqbuf, cpu_model);
581 } else {
582 aprint_naive(": %s\n", cpu_model);
583 aprint_normal(": %s\n", cpu_model);
584 }
585
586 aprint_normal("%s:", xname);
587
588 switch (cpu_class) {
589 case CPU_CLASS_ARM6:
590 case CPU_CLASS_ARM7:
591 case CPU_CLASS_ARM7TDMI:
592 case CPU_CLASS_ARM8:
593 if ((ci->ci_ctrl & CPU_CONTROL_IDC_ENABLE) == 0)
594 aprint_normal(" IDC disabled");
595 else
596 aprint_normal(" IDC enabled");
597 break;
598 case CPU_CLASS_ARM9TDMI:
599 case CPU_CLASS_ARM9ES:
600 case CPU_CLASS_ARM9EJS:
601 case CPU_CLASS_ARM10E:
602 case CPU_CLASS_ARM10EJ:
603 case CPU_CLASS_SA1:
604 case CPU_CLASS_XSCALE:
605 case CPU_CLASS_ARM11J:
606 case CPU_CLASS_ARMV4:
607 case CPU_CLASS_CORTEX:
608 if ((ci->ci_ctrl & CPU_CONTROL_DC_ENABLE) == 0)
609 aprint_normal(" DC disabled");
610 else
611 aprint_normal(" DC enabled");
612 if ((ci->ci_ctrl & CPU_CONTROL_IC_ENABLE) == 0)
613 aprint_normal(" IC disabled");
614 else
615 aprint_normal(" IC enabled");
616 break;
617 default:
618 break;
619 }
620 if ((ci->ci_ctrl & CPU_CONTROL_WBUF_ENABLE) == 0)
621 aprint_normal(" WB disabled");
622 else
623 aprint_normal(" WB enabled");
624
625 if (ci->ci_ctrl & CPU_CONTROL_LABT_ENABLE)
626 aprint_normal(" LABT");
627 else
628 aprint_normal(" EABT");
629
630 if (ci->ci_ctrl & CPU_CONTROL_BPRD_ENABLE)
631 aprint_normal(" branch prediction enabled");
632
633 aprint_normal("\n");
634
635 #ifdef CPU_CORTEX
636 if (CPU_ID_CORTEX_P(cpuid)) {
637 identify_cortex_caches(dv);
638 if (0)
639 identify_features(dv);
640 } else
641 #endif
642 /* Print cache info. */
643 if (arm_picache_line_size != 0 || arm_pdcache_line_size != 0) {
644
645 if (arm_pcache_unified) {
646 aprint_normal_dev(dv, "%dKB/%dB %d-way %s unified cache\n",
647 arm_pdcache_size / 1024,
648 arm_pdcache_line_size, arm_pdcache_ways,
649 wtnames[arm_pcache_type]);
650 } else {
651 aprint_normal_dev(dv, "%dKB/%dB %d-way Instruction cache\n",
652 arm_picache_size / 1024,
653 arm_picache_line_size, arm_picache_ways);
654 aprint_normal_dev(dv, "%dKB/%dB %d-way %s Data cache\n",
655 arm_pdcache_size / 1024,
656 arm_pdcache_line_size, arm_pdcache_ways,
657 wtnames[arm_pcache_type]);
658 }
659
660 }
661
662
663 switch (cpu_class) {
664 #ifdef CPU_ARM2
665 case CPU_CLASS_ARM2:
666 #endif
667 #ifdef CPU_ARM250
668 case CPU_CLASS_ARM2AS:
669 #endif
670 #ifdef CPU_ARM3
671 case CPU_CLASS_ARM3:
672 #endif
673 #ifdef CPU_ARM6
674 case CPU_CLASS_ARM6:
675 #endif
676 #ifdef CPU_ARM7
677 case CPU_CLASS_ARM7:
678 #endif
679 #ifdef CPU_ARM7TDMI
680 case CPU_CLASS_ARM7TDMI:
681 #endif
682 #ifdef CPU_ARM8
683 case CPU_CLASS_ARM8:
684 #endif
685 #ifdef CPU_ARM9
686 case CPU_CLASS_ARM9TDMI:
687 #endif
688 #if defined(CPU_ARM9E) || defined(CPU_SHEEVA)
689 case CPU_CLASS_ARM9ES:
690 case CPU_CLASS_ARM9EJS:
691 #endif
692 #ifdef CPU_ARM10
693 case CPU_CLASS_ARM10E:
694 case CPU_CLASS_ARM10EJ:
695 #endif
696 #if defined(CPU_SA110) || defined(CPU_SA1100) || \
697 defined(CPU_SA1110) || defined(CPU_IXP12X0)
698 case CPU_CLASS_SA1:
699 #endif
700 #if defined(CPU_XSCALE_80200) || defined(CPU_XSCALE_80321) || \
701 defined(__CPU_XSCALE_PXA2XX) || defined(CPU_XSCALE_IXP425)
702 case CPU_CLASS_XSCALE:
703 #endif
704 #if defined(CPU_ARM11)
705 case CPU_CLASS_ARM11J:
706 #endif
707 #if defined(CPU_CORTEX)
708 case CPU_CLASS_CORTEX:
709 #endif
710 #if defined(CPU_FA526)
711 case CPU_CLASS_ARMV4:
712 #endif
713 break;
714 default:
715 if (cpu_classes[cpu_class].class_option == NULL) {
716 aprint_error_dev(dv, "%s does not fully support this CPU.\n",
717 ostype);
718 } else {
719 aprint_error_dev(dv, "This kernel does not fully support "
720 "this CPU.\n");
721 aprint_normal_dev(dv, "Recompile with \"options %s\" to "
722 "correct this.\n", cpu_classes[cpu_class].class_option);
723 }
724 break;
725 }
726 }
727
728 #ifdef CPU_CORTEX
729 static void
730 print_cortex_cache(device_t dv, u_int level, const char *desc)
731 {
732 uint32_t ccsidr = armreg_ccsidr_read();
733 u_int linesize = 1 << ((ccsidr & 7) + 4);
734 u_int nways = ((ccsidr >> 3) & 0x3ff) + 1;
735 u_int nsets = ((ccsidr >> 13) & 0x7fff) + 1;
736 u_int totalsize = linesize * nways * nsets;
737 static const char * const wstrings[] = {
738 "", " write-back", " write-through", ""
739 };
740 static const char * const astrings[] = {
741 "",
742 " with write allocate",
743 " with read allocate",
744 " with read and write allocate"
745 };
746
747 //aprint_debug_dev(dv, "ccsidr=%#x\n", ccsidr);
748
749 u_int wtype = (ccsidr >> 30) & 3;
750 u_int atype = (ccsidr >> 28) & 3;
751
752 aprint_normal_dev(dv, "%uKB/%uB %u-way%s L%u %s cache%s\n",
753 totalsize / 1024, linesize, nways, wstrings[wtype], level + 1,
754 desc, astrings[atype]);
755 }
756
757 void
758 identify_cortex_caches(device_t dv)
759 {
760 const uint32_t orig_csselr = armreg_csselr_read();
761 uint32_t clidr = armreg_clidr_read();
762 u_int level;
763
764 //aprint_debug_dev(dv, "clidr=%011o\n", clidr);
765
766 for (level = 0, clidr &= 077777777; clidr & 7; clidr >>= 3, level++) {
767 if (clidr & 1) {
768 armreg_csselr_write(2*level + 1);
769 print_cortex_cache(dv, level, "Instruction");
770 }
771 if (clidr & 6) {
772 armreg_csselr_write(2*level + 0);
773 print_cortex_cache(dv, level,
774 (clidr & 4) ? "Unified" : "Data");
775 }
776 }
777
778 armreg_csselr_write(orig_csselr);
779
780
781 }
782
783 void
784 identify_features(device_t dv)
785 {
786 uint32_t isar0 = armreg_isar0_read();
787 uint32_t isar1 = armreg_isar1_read();
788 uint32_t isar2 = armreg_isar2_read();
789 uint32_t isar3 = armreg_isar3_read();
790 uint32_t isar4 = armreg_isar4_read();
791 uint32_t isar5 = armreg_isar5_read();
792
793 uint32_t mmfr0 = armreg_mmfr0_read();
794 uint32_t mmfr1 = armreg_mmfr1_read();
795 uint32_t mmfr2 = armreg_mmfr2_read();
796 uint32_t mmfr3 = armreg_mmfr3_read();
797
798 uint32_t pfr0 = armreg_pfr0_read();
799 uint32_t pfr1 = armreg_pfr1_read();
800
801 aprint_normal_dev(dv,
802 "isar: [0]=%#x [1]=%#x [2]=%#x [3]=%#x, [4]=%#x, [5]=%#x\n",
803 isar0, isar1, isar2, isar3, isar4, isar5);
804 aprint_normal_dev(dv,
805 "mmfr: [0]=%#x [1]=%#x [2]=%#x [3]=%#x\n",
806 mmfr0, mmfr1, mmfr2, mmfr3);
807 aprint_normal_dev(dv,
808 "pfr: [0]=%#x [1]=%#x\n",
809 pfr0, pfr1);
810 }
811 #endif /* CPU_CORTEX */
812