cpu.c revision 1.144
1/*	$NetBSD: cpu.c,v 1.144 2020/02/15 08:16:11 skrll 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_cputypes.h"
46#include "opt_multiprocessor.h"
47
48#include <sys/cdefs.h>
49__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.144 2020/02/15 08:16:11 skrll Exp $");
50
51#include <sys/param.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#include <sys/reboot.h>
58#include <sys/systm.h>
59
60#include <uvm/uvm_extern.h>
61
62#include <arm/locore.h>
63#include <arm/undefined.h>
64#include <arm/cpu_topology.h>
65
66extern const char *cpu_arch;
67
68#ifdef MULTIPROCESSOR
69#ifdef MPDEBUG
70uint32_t arm_cpu_marker[2] __cacheline_aligned = { 0, 0 };
71#endif
72
73#endif
74
75/* Prototypes */
76void identify_arm_cpu(device_t, struct cpu_info *);
77void identify_cortex_caches(device_t);
78void identify_features(device_t);
79
80/*
81 * Identify the master (boot) CPU
82 */
83
84void
85cpu_attach(device_t dv, cpuid_t id)
86{
87	const char * const xname = device_xname(dv);
88	const int unit = device_unit(dv);
89	struct cpu_info *ci;
90
91	if (unit == 0) {
92		ci = curcpu();
93
94		/* Read SCTLR from cpu */
95		ci->ci_ctrl = cpu_control(0, 0);
96
97		/* Get the CPU ID from coprocessor 15 */
98
99		ci->ci_cpuid = id;
100		ci->ci_arm_cpuid = cpu_idnum();
101		ci->ci_arm_cputype = ci->ci_arm_cpuid & CPU_ID_CPU_MASK;
102		ci->ci_arm_cpurev = ci->ci_arm_cpuid & CPU_ID_REVISION_MASK;
103	} else {
104#ifdef MULTIPROCESSOR
105		if ((boothowto & RB_MD1) != 0) {
106			aprint_naive("\n");
107			aprint_normal(": multiprocessor boot disabled\n");
108			return;
109		}
110
111		KASSERT(unit < MAXCPUS);
112		ci = &cpu_info_store[unit];
113
114		KASSERT(cpu_info[unit] == NULL);
115		ci->ci_cpl = IPL_HIGH;
116		ci->ci_cpuid = id;
117		ci->ci_data.cpu_cc_freq = cpu_info_store[0].ci_data.cpu_cc_freq;
118
119		ci->ci_undefsave[2] = cpu_info_store[0].ci_undefsave[2];
120
121		cpu_info[unit] = ci;
122		if (cpu_hatched_p(unit) == false) {
123			ci->ci_dev = dv;
124			dv->dv_private = ci;
125			aprint_naive(": disabled\n");
126			aprint_normal(": disabled (unresponsive)\n");
127			return;
128		}
129#else
130		aprint_naive(": disabled\n");
131		aprint_normal(": disabled (uniprocessor kernel)\n");
132		return;
133#endif
134	}
135
136	ci->ci_dev = dv;
137	dv->dv_private = ci;
138
139	arm_cpu_do_topology(ci);
140
141	evcnt_attach_dynamic(&ci->ci_arm700bugcount, EVCNT_TYPE_MISC,
142	    NULL, xname, "arm700swibug");
143
144	evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_WRTBUF_0], EVCNT_TYPE_TRAP,
145	    NULL, xname, "vector abort");
146	evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_WRTBUF_1], EVCNT_TYPE_TRAP,
147	    NULL, xname, "terminal abort");
148	evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_BUSERR_0], EVCNT_TYPE_TRAP,
149	    NULL, xname, "external linefetch abort (S)");
150	evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_BUSERR_1], EVCNT_TYPE_TRAP,
151	    NULL, xname, "external linefetch abort (P)");
152	evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_BUSERR_2], EVCNT_TYPE_TRAP,
153	    NULL, xname, "external non-linefetch abort (S)");
154	evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_BUSERR_3], EVCNT_TYPE_TRAP,
155	    NULL, xname, "external non-linefetch abort (P)");
156	evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_BUSTRNL1], EVCNT_TYPE_TRAP,
157	    NULL, xname, "external translation abort (L1)");
158	evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_BUSTRNL2], EVCNT_TYPE_TRAP,
159	    NULL, xname, "external translation abort (L2)");
160	evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_ALIGN_0], EVCNT_TYPE_TRAP,
161	    NULL, xname, "alignment abort (0)");
162	evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_ALIGN_1], EVCNT_TYPE_TRAP,
163	    NULL, xname, "alignment abort (1)");
164	evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_TRANS_S], EVCNT_TYPE_TRAP,
165	    NULL, xname, "translation abort (S)");
166	evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_TRANS_P], EVCNT_TYPE_TRAP,
167	    NULL, xname, "translation abort (P)");
168	evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_DOMAIN_S], EVCNT_TYPE_TRAP,
169	    NULL, xname, "domain abort (S)");
170	evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_DOMAIN_P], EVCNT_TYPE_TRAP,
171	    NULL, xname, "domain abort (P)");
172	evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_PERM_S], EVCNT_TYPE_TRAP,
173	    NULL, xname, "permission abort (S)");
174	evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_PERM_P], EVCNT_TYPE_TRAP,
175	    NULL, xname, "permission abort (P)");
176	evcnt_attach_dynamic_nozero(&ci->ci_und_ev, EVCNT_TYPE_TRAP,
177	    NULL, xname, "undefined insn traps");
178	evcnt_attach_dynamic_nozero(&ci->ci_und_cp15_ev, EVCNT_TYPE_TRAP,
179	    NULL, xname, "undefined cp15 insn traps");
180
181#ifdef MULTIPROCESSOR
182	/*
183	 * and we are done if this is a secondary processor.
184	 */
185	if (unit != 0) {
186		aprint_naive("\n");
187		aprint_normal("\n");
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_CORTEXA9R1,	CPU_CLASS_CORTEX,	"Cortex-A9 r1",
505	  pN_steppings, "7A" },
506	{ CPU_ID_CORTEXA9R2,	CPU_CLASS_CORTEX,	"Cortex-A9 r2",
507	  pN_steppings, "7A" },
508	{ CPU_ID_CORTEXA9R3,	CPU_CLASS_CORTEX,	"Cortex-A9 r3",
509	  pN_steppings, "7A" },
510	{ CPU_ID_CORTEXA9R4,	CPU_CLASS_CORTEX,	"Cortex-A9 r4",
511	  pN_steppings, "7A" },
512	{ CPU_ID_CORTEXA12R0,	CPU_CLASS_CORTEX,	"Cortex-A17(A12) r0",	/* A12 was rebranded A17 */
513	  pN_steppings, "7A" },
514	{ CPU_ID_CORTEXA15R2,	CPU_CLASS_CORTEX,	"Cortex-A15 r2",
515	  pN_steppings, "7A" },
516	{ CPU_ID_CORTEXA15R3,	CPU_CLASS_CORTEX,	"Cortex-A15 r3",
517	  pN_steppings, "7A" },
518	{ CPU_ID_CORTEXA15R4,	CPU_CLASS_CORTEX,	"Cortex-A15 r4",
519	  pN_steppings, "7A" },
520	{ CPU_ID_CORTEXA17R1,	CPU_CLASS_CORTEX,	"Cortex-A17 r1",
521	  pN_steppings, "7A" },
522	{ CPU_ID_CORTEXA35R0,	CPU_CLASS_CORTEX,	"Cortex-A35 r0",
523	  pN_steppings, "8A" },
524	{ CPU_ID_CORTEXA53R0,	CPU_CLASS_CORTEX,	"Cortex-A53 r0",
525	  pN_steppings, "8A" },
526	{ CPU_ID_CORTEXA57R0,	CPU_CLASS_CORTEX,	"Cortex-A57 r0",
527	  pN_steppings, "8A" },
528	{ CPU_ID_CORTEXA57R1,	CPU_CLASS_CORTEX,	"Cortex-A57 r1",
529	  pN_steppings, "8A" },
530	{ CPU_ID_CORTEXA72R0,	CPU_CLASS_CORTEX,	"Cortex-A72 r0",
531	  pN_steppings, "8A" },
532
533	{ CPU_ID_MV88SV581X_V6, CPU_CLASS_PJ4B,      "Sheeva 88SV581x",
534	  generic_steppings },
535	{ CPU_ID_ARM_88SV581X_V6, CPU_CLASS_PJ4B,    "Sheeva 88SV581x",
536	  generic_steppings },
537	{ CPU_ID_MV88SV581X_V7, CPU_CLASS_PJ4B,      "Sheeva 88SV581x",
538	  generic_steppings },
539	{ CPU_ID_ARM_88SV581X_V7, CPU_CLASS_PJ4B,    "Sheeva 88SV581x",
540	  generic_steppings },
541	{ CPU_ID_MV88SV584X_V6, CPU_CLASS_PJ4B,      "Sheeva 88SV584x",
542	  generic_steppings },
543	{ CPU_ID_ARM_88SV584X_V6, CPU_CLASS_PJ4B,    "Sheeva 88SV584x",
544	  generic_steppings },
545	{ CPU_ID_MV88SV584X_V7, CPU_CLASS_PJ4B,      "Sheeva 88SV584x",
546	  generic_steppings },
547
548
549	{ 0, CPU_CLASS_NONE, NULL, NULL, "" }
550};
551
552struct cpu_classtab {
553	const char	*class_name;
554	const char	*class_option;
555};
556
557const struct cpu_classtab cpu_classes[] = {
558	[CPU_CLASS_NONE] =	{ "unknown",	NULL },
559	[CPU_CLASS_ARM2] =	{ "ARM2",	"CPU_ARM2" },
560	[CPU_CLASS_ARM2AS] =	{ "ARM2as",	"CPU_ARM250" },
561	[CPU_CLASS_ARM3] =	{ "ARM3",	"CPU_ARM3" },
562	[CPU_CLASS_ARM6] =	{ "ARM6",	"CPU_ARM6" },
563	[CPU_CLASS_ARM7] =	{ "ARM7",	"CPU_ARM7" },
564	[CPU_CLASS_ARM7TDMI] =	{ "ARM7TDMI",	"CPU_ARM7TDMI" },
565	[CPU_CLASS_ARM8] =	{ "ARM8",	"CPU_ARM8" },
566	[CPU_CLASS_ARM9TDMI] =	{ "ARM9TDMI",	NULL },
567	[CPU_CLASS_ARM9ES] =	{ "ARM9E-S",	"CPU_ARM9E" },
568	[CPU_CLASS_ARM9EJS] =	{ "ARM9EJ-S",	"CPU_ARM9E" },
569	[CPU_CLASS_ARM10E] =	{ "ARM10E",	"CPU_ARM10" },
570	[CPU_CLASS_ARM10EJ] =	{ "ARM10EJ",	"CPU_ARM10" },
571	[CPU_CLASS_SA1] =	{ "SA-1",	"CPU_SA110" },
572	[CPU_CLASS_XSCALE] =	{ "XScale",	"CPU_XSCALE_..." },
573	[CPU_CLASS_ARM11J] =	{ "ARM11J",	"CPU_ARM11" },
574	[CPU_CLASS_ARMV4] =	{ "ARMv4",	"CPU_ARMV4" },
575	[CPU_CLASS_CORTEX] =	{ "Cortex",	"CPU_CORTEX" },
576	[CPU_CLASS_PJ4B] =	{ "Marvell",	"CPU_PJ4B" },
577};
578
579/*
580 * Report the type of the specified arm processor. This uses the generic and
581 * arm specific information in the CPU structure to identify the processor.
582 * The remaining fields in the CPU structure are filled in appropriately.
583 */
584
585static const char * const wtnames[] = {
586	"write-through",
587	"write-back",
588	"write-back",
589	"**unknown 3**",
590	"**unknown 4**",
591	"write-back-locking",		/* XXX XScale-specific? */
592	"write-back-locking-A",
593	"write-back-locking-B",
594	"**unknown 8**",
595	"**unknown 9**",
596	"**unknown 10**",
597	"**unknown 11**",
598	"write-back",
599	"write-back-locking-line",
600	"write-back-locking-C",
601	"write-back-locking-D",
602};
603
604static void
605print_cache_info(device_t dv, struct arm_cache_info *info, u_int level)
606{
607	if (info->cache_unified) {
608		aprint_normal_dev(dv, "%dKB/%dB %d-way %s L%u %cI%cT Unified cache\n",
609		    info->dcache_size / 1024,
610		    info->dcache_line_size, info->dcache_ways,
611		    wtnames[info->cache_type], level + 1,
612		    info->dcache_type & CACHE_TYPE_PIxx ? 'P' : 'V',
613		    info->dcache_type & CACHE_TYPE_xxPT ? 'P' : 'V');
614	} else {
615		aprint_normal_dev(dv, "%dKB/%dB %d-way L%u %cI%cT Instruction cache\n",
616		    info->icache_size / 1024,
617		    info->icache_line_size, info->icache_ways, level + 1,
618		    info->icache_type & CACHE_TYPE_PIxx ? 'P' : 'V',
619		    info->icache_type & CACHE_TYPE_xxPT ? 'P' : 'V');
620		aprint_normal_dev(dv, "%dKB/%dB %d-way %s L%u %cI%cT Data cache\n",
621		    info->dcache_size / 1024,
622		    info->dcache_line_size, info->dcache_ways,
623		    wtnames[info->cache_type], level + 1,
624		    info->dcache_type & CACHE_TYPE_PIxx ? 'P' : 'V',
625		    info->dcache_type & CACHE_TYPE_xxPT ? 'P' : 'V');
626	}
627}
628
629static enum cpu_class
630identify_arm_model(uint32_t cpuid, char *buf, size_t len)
631{
632	enum cpu_class cpu_class = CPU_CLASS_NONE;
633	for (const struct cpuidtab *id = cpuids; id->cpuid != 0; id++) {
634		if (id->cpuid == (cpuid & CPU_ID_CPU_MASK)) {
635			const char *steppingstr =
636			    id->cpu_steppings[cpuid & CPU_ID_REVISION_MASK];
637			cpu_arch = id->cpu_arch;
638			cpu_class = id->cpu_class;
639			snprintf(buf, len, "%s%s%s (%s V%s core)",
640			    id->cpu_classname,
641			    steppingstr[0] == '*' ? "" : " ",
642			    &steppingstr[steppingstr[0] == '*'],
643			    cpu_classes[cpu_class].class_name,
644			    cpu_arch);
645			return cpu_class;
646		}
647	}
648
649	snprintf(buf, len, "unknown CPU (ID = 0x%x)", cpuid);
650	return cpu_class;
651}
652
653void
654identify_arm_cpu(device_t dv, struct cpu_info *ci)
655{
656	const uint32_t arm_cpuid = ci->ci_arm_cpuid;
657	const char * const xname = device_xname(dv);
658	char model[128];
659	const char *m;
660
661	if (arm_cpuid == 0) {
662		aprint_error("Processor failed probe - no CPU ID\n");
663		return;
664	}
665
666	const enum cpu_class cpu_class = identify_arm_model(arm_cpuid,
667	     model, sizeof(model));
668	if (ci->ci_cpuid == 0) {
669		m = cpu_getmodel();
670		if (m == NULL || *m == 0)
671			cpu_setmodel("%s", model);
672	}
673
674	if (ci->ci_data.cpu_cc_freq != 0) {
675		char freqbuf[10];
676		humanize_number(freqbuf, sizeof(freqbuf), ci->ci_data.cpu_cc_freq,
677		    "Hz", 1000);
678
679		aprint_naive(": %s %s\n", freqbuf, model);
680		aprint_normal(": %s %s\n", freqbuf, model);
681	} else {
682		aprint_naive(": %s\n", model);
683		aprint_normal(": %s\n", model);
684	}
685
686	aprint_debug_dev(dv, "midr:   %#x\n", arm_cpuid);
687
688	aprint_normal("%s:", xname);
689
690	switch (cpu_class) {
691	case CPU_CLASS_ARM6:
692	case CPU_CLASS_ARM7:
693	case CPU_CLASS_ARM7TDMI:
694	case CPU_CLASS_ARM8:
695		if ((ci->ci_ctrl & CPU_CONTROL_IDC_ENABLE) == 0)
696			aprint_normal(" IDC disabled");
697		else
698			aprint_normal(" IDC enabled");
699		break;
700	case CPU_CLASS_ARM9TDMI:
701	case CPU_CLASS_ARM9ES:
702	case CPU_CLASS_ARM9EJS:
703	case CPU_CLASS_ARM10E:
704	case CPU_CLASS_ARM10EJ:
705	case CPU_CLASS_SA1:
706	case CPU_CLASS_XSCALE:
707	case CPU_CLASS_ARM11J:
708	case CPU_CLASS_ARMV4:
709	case CPU_CLASS_CORTEX:
710	case CPU_CLASS_PJ4B:
711		if ((ci->ci_ctrl & CPU_CONTROL_DC_ENABLE) == 0)
712			aprint_normal(" DC disabled");
713		else
714			aprint_normal(" DC enabled");
715		if ((ci->ci_ctrl & CPU_CONTROL_IC_ENABLE) == 0)
716			aprint_normal(" IC disabled");
717		else
718			aprint_normal(" IC enabled");
719		break;
720	default:
721		break;
722	}
723	if ((ci->ci_ctrl & CPU_CONTROL_WBUF_ENABLE) == 0)
724		aprint_normal(" WB disabled");
725	else
726		aprint_normal(" WB enabled");
727
728	if (ci->ci_ctrl & CPU_CONTROL_LABT_ENABLE)
729		aprint_normal(" LABT");
730	else
731		aprint_normal(" EABT");
732
733	if (ci->ci_ctrl & CPU_CONTROL_BPRD_ENABLE)
734		aprint_normal(" branch prediction enabled");
735
736	aprint_normal("\n");
737
738	if (CPU_ID_CORTEX_P(arm_cpuid) || CPU_ID_ARM11_P(arm_cpuid) || CPU_ID_MV88SV58XX_P(arm_cpuid)) {
739		identify_features(dv);
740	}
741
742	/* Print cache info. */
743	if (arm_pcache.icache_line_size != 0 || arm_pcache.dcache_line_size != 0) {
744		print_cache_info(dv, &arm_pcache, 0);
745	}
746	if (arm_scache.icache_line_size != 0 || arm_scache.dcache_line_size != 0) {
747		print_cache_info(dv, &arm_scache, 1);
748	}
749
750
751	switch (cpu_class) {
752#ifdef CPU_ARM6
753	case CPU_CLASS_ARM6:
754#endif
755#ifdef CPU_ARM7
756	case CPU_CLASS_ARM7:
757#endif
758#ifdef CPU_ARM7TDMI
759	case CPU_CLASS_ARM7TDMI:
760#endif
761#ifdef CPU_ARM8
762	case CPU_CLASS_ARM8:
763#endif
764#ifdef CPU_ARM9
765	case CPU_CLASS_ARM9TDMI:
766#endif
767#if defined(CPU_ARM9E) || defined(CPU_SHEEVA)
768	case CPU_CLASS_ARM9ES:
769	case CPU_CLASS_ARM9EJS:
770#endif
771#ifdef CPU_ARM10
772	case CPU_CLASS_ARM10E:
773	case CPU_CLASS_ARM10EJ:
774#endif
775#if defined(CPU_SA110) || defined(CPU_SA1100) || \
776    defined(CPU_SA1110) || defined(CPU_IXP12X0)
777	case CPU_CLASS_SA1:
778#endif
779#if defined(CPU_XSCALE_80200) || defined(CPU_XSCALE_80321) || \
780    defined(__CPU_XSCALE_PXA2XX) || defined(CPU_XSCALE_IXP425)
781	case CPU_CLASS_XSCALE:
782#endif
783#if defined(CPU_ARM11)
784	case CPU_CLASS_ARM11J:
785#endif
786#if defined(CPU_CORTEX)
787	case CPU_CLASS_CORTEX:
788#endif
789#if defined(CPU_PJ4B)
790	case CPU_CLASS_PJ4B:
791#endif
792#if defined(CPU_FA526)
793	case CPU_CLASS_ARMV4:
794#endif
795		break;
796	default:
797		if (cpu_classes[cpu_class].class_option == NULL) {
798			aprint_error_dev(dv, "%s does not fully support this CPU.\n",
799			     ostype);
800		} else {
801			aprint_error_dev(dv, "This kernel does not fully support "
802			       "this CPU.\n");
803			aprint_normal_dev(dv, "Recompile with \"options %s\" to "
804			       "correct this.\n", cpu_classes[cpu_class].class_option);
805		}
806		break;
807	}
808}
809
810extern int cpu_instruction_set_attributes[6];
811extern int cpu_memory_model_features[4];
812extern int cpu_processor_features[2];
813extern int cpu_simd_present;
814extern int cpu_simdex_present;
815
816void
817identify_features(device_t dv)
818{
819	cpu_instruction_set_attributes[0] = armreg_isar0_read();
820	cpu_instruction_set_attributes[1] = armreg_isar1_read();
821	cpu_instruction_set_attributes[2] = armreg_isar2_read();
822	cpu_instruction_set_attributes[3] = armreg_isar3_read();
823	cpu_instruction_set_attributes[4] = armreg_isar4_read();
824	cpu_instruction_set_attributes[5] = armreg_isar5_read();
825
826	cpu_hwdiv_present =
827	    ((cpu_instruction_set_attributes[0] >> 24) & 0x0f) >= 2;
828	cpu_simd_present =
829	    ((cpu_instruction_set_attributes[3] >> 4) & 0x0f) >= 3;
830	cpu_simdex_present = cpu_simd_present
831	    && ((cpu_instruction_set_attributes[1] >> 12) & 0x0f) >= 2;
832	cpu_synchprim_present =
833	    ((cpu_instruction_set_attributes[3] >> 8) & 0xf0)
834	    | ((cpu_instruction_set_attributes[4] >> 20) & 0x0f);
835
836	cpu_memory_model_features[0] = armreg_mmfr0_read();
837	cpu_memory_model_features[1] = armreg_mmfr1_read();
838	cpu_memory_model_features[2] = armreg_mmfr2_read();
839	cpu_memory_model_features[3] = armreg_mmfr3_read();
840
841#if 0
842	if (__SHIFTOUT(cpu_memory_model_features[3], __BITS(23,20))) {
843		/*
844		 * Updates to the translation tables do not require a clean
845		 * to the point of unification to ensure visibility by
846		 * subsequent translation table walks.
847		 */
848		pmap_needs_pte_sync = 0;
849	}
850#endif
851
852	cpu_processor_features[0] = armreg_pfr0_read();
853	cpu_processor_features[1] = armreg_pfr1_read();
854
855	aprint_debug_dev(dv, "sctlr:  %#x\n", armreg_sctlr_read());
856	aprint_debug_dev(dv, "actlr:  %#x\n", armreg_auxctl_read());
857	aprint_debug_dev(dv, "revidr: %#x\n", armreg_revidr_read());
858#ifdef MULTIPROCESSOR
859	aprint_debug_dev(dv, "mpidr:  %#x\n", armreg_mpidr_read());
860#endif
861	aprint_debug_dev(dv,
862	    "isar: [0]=%#x [1]=%#x [2]=%#x [3]=%#x, [4]=%#x, [5]=%#x\n",
863	    cpu_instruction_set_attributes[0],
864	    cpu_instruction_set_attributes[1],
865	    cpu_instruction_set_attributes[2],
866	    cpu_instruction_set_attributes[3],
867	    cpu_instruction_set_attributes[4],
868	    cpu_instruction_set_attributes[5]);
869	aprint_debug_dev(dv,
870	    "mmfr: [0]=%#x [1]=%#x [2]=%#x [3]=%#x\n",
871	    cpu_memory_model_features[0], cpu_memory_model_features[1],
872	    cpu_memory_model_features[2], cpu_memory_model_features[3]);
873	aprint_debug_dev(dv,
874	    "pfr: [0]=%#x [1]=%#x\n",
875	    cpu_processor_features[0], cpu_processor_features[1]);
876}
877
878#ifdef _ARM_ARCH_6
879int
880cpu_maxproc_hook(int nmaxproc)
881{
882
883#ifdef ARM_MMU_EXTENDED
884	return pmap_maxproc_set(nmaxproc);
885#else
886	return 0;
887#endif
888}
889#endif
890