cpu.c revision 1.99
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
63char cpu_model[256];
64extern const char *cpu_arch;
65
66#ifdef MULTIPROCESSOR
67volatile u_int arm_cpu_hatched = 0;
68u_int arm_cpu_max = 0;
69uint32_t arm_cpu_mbox __cacheline_aligned = 0;
70uint32_t arm_cpu_marker __cacheline_aligned = 1;
71#endif
72
73/* Prototypes */
74void identify_arm_cpu(device_t dv, struct cpu_info *);
75void identify_cortex_caches(device_t dv);
76void identify_features(device_t dv);
77
78/*
79 * Identify the master (boot) CPU
80 */
81
82void
83cpu_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
211enum 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
233static 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
240static 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
245static 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
252static 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
259static 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
266static 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
275static 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
282static 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
289static 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 */
297static 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 */
307static 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 */
315static 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
322static 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
329struct 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
337const 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
512struct cpu_classtab {
513	const char	*class_name;
514	const char	*class_option;
515};
516
517const 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
545static 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
564static void
565print_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
583void
584identify_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
759extern int cpu_instruction_set_attributes[6];
760extern int cpu_memory_model_features[4];
761extern int cpu_processor_features[2];
762extern int cpu_simd_present;
763extern int cpu_simdex_present;
764
765void
766identify_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