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