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