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