1129198Scognet/*	$NetBSD: cpu.c,v 1.55 2004/02/13 11:36:10 wiz Exp $	*/
2129198Scognet
3139735Simp/*-
4129198Scognet * Copyright (c) 1995 Mark Brinicombe.
5129198Scognet * Copyright (c) 1995 Brini.
6129198Scognet * All rights reserved.
7129198Scognet *
8129198Scognet * Redistribution and use in source and binary forms, with or without
9129198Scognet * modification, are permitted provided that the following conditions
10129198Scognet * are met:
11129198Scognet * 1. Redistributions of source code must retain the above copyright
12129198Scognet *    notice, this list of conditions and the following disclaimer.
13129198Scognet * 2. Redistributions in binary form must reproduce the above copyright
14129198Scognet *    notice, this list of conditions and the following disclaimer in the
15129198Scognet *    documentation and/or other materials provided with the distribution.
16129198Scognet * 3. All advertising materials mentioning features or use of this software
17129198Scognet *    must display the following acknowledgement:
18129198Scognet *	This product includes software developed by Brini.
19129198Scognet * 4. The name of the company nor the name of the author may be used to
20129198Scognet *    endorse or promote products derived from this software without specific
21129198Scognet *    prior written permission.
22129198Scognet *
23129198Scognet * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
24129198Scognet * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25129198Scognet * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26129198Scognet * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27129198Scognet * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28129198Scognet * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29129198Scognet * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30129198Scognet * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31129198Scognet * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32129198Scognet * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33129198Scognet * SUCH DAMAGE.
34129198Scognet *
35129198Scognet * RiscBSD kernel project
36129198Scognet *
37129198Scognet * cpu.c
38129198Scognet *
39129198Scognet * Probing and configuration for the master CPU
40129198Scognet *
41129198Scognet * Created      : 10/10/95
42129198Scognet */
43129198Scognet
44129198Scognet#include <sys/cdefs.h>
45129198Scognet__FBSDID("$FreeBSD$");
46129198Scognet#include <sys/systm.h>
47129198Scognet#include <sys/param.h>
48129198Scognet#include <sys/malloc.h>
49129198Scognet#include <sys/time.h>
50129198Scognet#include <sys/proc.h>
51129198Scognet#include <sys/conf.h>
52135652Scognet#include <sys/kernel.h>
53135652Scognet#include <sys/sysctl.h>
54129198Scognet#include <machine/cpu.h>
55235050Simp#include <machine/endian.h>
56129198Scognet
57129198Scognet#include <machine/cpuconf.h>
58197523Srpaulo#include <machine/md_var.h>
59129198Scognet
60129198Scognetchar machine[] = "arm";
61129198Scognet
62135652ScognetSYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD,
63235062Simp	machine, 0, "Machine class");
64129198Scognet
65129198Scognetstatic const char * const generic_steppings[16] = {
66129198Scognet	"rev 0",	"rev 1",	"rev 2",	"rev 3",
67129198Scognet	"rev 4",	"rev 5",	"rev 6",	"rev 7",
68129198Scognet	"rev 8",	"rev 9",	"rev 10",	"rev 11",
69129198Scognet	"rev 12",	"rev 13",	"rev 14",	"rev 15",
70129198Scognet};
71129198Scognet
72129198Scognetstatic const char * const sa110_steppings[16] = {
73129198Scognet	"rev 0",	"step J",	"step K",	"step S",
74129198Scognet	"step T",	"rev 5",	"rev 6",	"rev 7",
75129198Scognet	"rev 8",	"rev 9",	"rev 10",	"rev 11",
76129198Scognet	"rev 12",	"rev 13",	"rev 14",	"rev 15",
77129198Scognet};
78129198Scognet
79129198Scognetstatic const char * const sa1100_steppings[16] = {
80129198Scognet	"rev 0",	"step B",	"step C",	"rev 3",
81129198Scognet	"rev 4",	"rev 5",	"rev 6",	"rev 7",
82129198Scognet	"step D",	"step E",	"rev 10"	"step G",
83129198Scognet	"rev 12",	"rev 13",	"rev 14",	"rev 15",
84129198Scognet};
85129198Scognet
86129198Scognetstatic const char * const sa1110_steppings[16] = {
87129198Scognet	"step A-0",	"rev 1",	"rev 2",	"rev 3",
88129198Scognet	"step B-0",	"step B-1",	"step B-2",	"step B-3",
89129198Scognet	"step B-4",	"step B-5",	"rev 10",	"rev 11",
90129198Scognet	"rev 12",	"rev 13",	"rev 14",	"rev 15",
91129198Scognet};
92129198Scognet
93129198Scognetstatic const char * const ixp12x0_steppings[16] = {
94129198Scognet	"(IXP1200 step A)",		"(IXP1200 step B)",
95129198Scognet	"rev 2",			"(IXP1200 step C)",
96129198Scognet	"(IXP1200 step D)",		"(IXP1240/1250 step A)",
97129198Scognet	"(IXP1240 step B)",		"(IXP1250 step B)",
98129198Scognet	"rev 8",	"rev 9",	"rev 10",	"rev 11",
99129198Scognet	"rev 12",	"rev 13",	"rev 14",	"rev 15",
100129198Scognet};
101129198Scognet
102129198Scognetstatic const char * const xscale_steppings[16] = {
103129198Scognet	"step A-0",	"step A-1",	"step B-0",	"step C-0",
104129198Scognet	"step D-0",	"rev 5",	"rev 6",	"rev 7",
105129198Scognet	"rev 8",	"rev 9",	"rev 10",	"rev 11",
106129198Scognet	"rev 12",	"rev 13",	"rev 14",	"rev 15",
107129198Scognet};
108129198Scognet
109172738Simpstatic const char * const i80219_steppings[16] = {
110172738Simp	"step A-0",	"rev 1",	"rev 2",	"rev 3",
111172738Simp	"rev 4",	"rev 5",	"rev 6",	"rev 7",
112172738Simp	"rev 8",	"rev 9",	"rev 10",	"rev 11",
113172738Simp	"rev 12",	"rev 13",	"rev 14",	"rev 15",
114172738Simp};
115172738Simp
116129198Scognetstatic const char * const i80321_steppings[16] = {
117129198Scognet	"step A-0",	"step B-0",	"rev 2",	"rev 3",
118129198Scognet	"rev 4",	"rev 5",	"rev 6",	"rev 7",
119129198Scognet	"rev 8",	"rev 9",	"rev 10",	"rev 11",
120129198Scognet	"rev 12",	"rev 13",	"rev 14",	"rev 15",
121129198Scognet};
122129198Scognet
123164080Scognetstatic const char * const i81342_steppings[16] = {
124164080Scognet	"step A-0",	"rev 1",	"rev 2",	"rev 3",
125164080Scognet	"rev 4",	"rev 5",	"rev 6",	"rev 7",
126164080Scognet	"rev 8",	"rev 9",	"rev 10",	"rev 11",
127164080Scognet	"rev 12",	"rev 13",	"rev 14",	"rev 15",
128164080Scognet};
129164080Scognet
130172738Simp/* Steppings for PXA2[15]0 */
131129198Scognetstatic const char * const pxa2x0_steppings[16] = {
132129198Scognet	"step A-0",	"step A-1",	"step B-0",	"step B-1",
133129198Scognet	"step B-2",	"step C-0",	"rev 6",	"rev 7",
134129198Scognet	"rev 8",	"rev 9",	"rev 10",	"rev 11",
135129198Scognet	"rev 12",	"rev 13",	"rev 14",	"rev 15",
136129198Scognet};
137129198Scognet
138172738Simp/* Steppings for PXA255/26x.
139235062Simp * rev 5: PXA26x B0, rev 6: PXA255 A0
140172738Simp */
141172738Simpstatic const char * const pxa255_steppings[16] = {
142172738Simp	"rev 0",	"rev 1",	"rev 2",	"step A-0",
143172738Simp	"rev 4",	"step B-0",	"step A-0",	"rev 7",
144172738Simp	"rev 8",	"rev 9",	"rev 10",	"rev 11",
145172738Simp	"rev 12",	"rev 13",	"rev 14",	"rev 15",
146172738Simp};
147172738Simp
148172738Simp/* Stepping for PXA27x */
149172738Simpstatic const char * const pxa27x_steppings[16] = {
150172738Simp	"step A-0",	"step A-1",	"step B-0",	"step B-1",
151172738Simp	"step C-0",	"rev 5",	"rev 6",	"rev 7",
152172738Simp	"rev 8",	"rev 9",	"rev 10",	"rev 11",
153172738Simp	"rev 12",	"rev 13",	"rev 14",	"rev 15",
154172738Simp};
155172738Simp
156129198Scognetstatic const char * const ixp425_steppings[16] = {
157164423Ssam	"step 0 (A0)",	"rev 1 (ARMv5TE)", "rev 2",	"rev 3",
158129198Scognet	"rev 4",	"rev 5",	"rev 6",	"rev 7",
159129198Scognet	"rev 8",	"rev 9",	"rev 10",	"rev 11",
160129198Scognet	"rev 12",	"rev 13",	"rev 14",	"rev 15",
161129198Scognet};
162129198Scognet
163129198Scognetstruct cpuidtab {
164129198Scognet	u_int32_t	cpuid;
165129198Scognet	enum		cpu_class cpu_class;
166129198Scognet	const char	*cpu_name;
167129198Scognet	const char * const *cpu_steppings;
168129198Scognet};
169129198Scognet
170129198Scognetconst struct cpuidtab cpuids[] = {
171129198Scognet	{ CPU_ID_ARM2,		CPU_CLASS_ARM2,		"ARM2",
172129198Scognet	  generic_steppings },
173129198Scognet	{ CPU_ID_ARM250,	CPU_CLASS_ARM2AS,	"ARM250",
174129198Scognet	  generic_steppings },
175129198Scognet
176129198Scognet	{ CPU_ID_ARM3,		CPU_CLASS_ARM3,		"ARM3",
177129198Scognet	  generic_steppings },
178129198Scognet
179129198Scognet	{ CPU_ID_ARM600,	CPU_CLASS_ARM6,		"ARM600",
180129198Scognet	  generic_steppings },
181129198Scognet	{ CPU_ID_ARM610,	CPU_CLASS_ARM6,		"ARM610",
182129198Scognet	  generic_steppings },
183129198Scognet	{ CPU_ID_ARM620,	CPU_CLASS_ARM6,		"ARM620",
184129198Scognet	  generic_steppings },
185129198Scognet
186129198Scognet	{ CPU_ID_ARM700,	CPU_CLASS_ARM7,		"ARM700",
187129198Scognet	  generic_steppings },
188129198Scognet	{ CPU_ID_ARM710,	CPU_CLASS_ARM7,		"ARM710",
189129198Scognet	  generic_steppings },
190129198Scognet	{ CPU_ID_ARM7500,	CPU_CLASS_ARM7,		"ARM7500",
191129198Scognet	  generic_steppings },
192129198Scognet	{ CPU_ID_ARM710A,	CPU_CLASS_ARM7,		"ARM710a",
193129198Scognet	  generic_steppings },
194129198Scognet	{ CPU_ID_ARM7500FE,	CPU_CLASS_ARM7,		"ARM7500FE",
195129198Scognet	  generic_steppings },
196129198Scognet	{ CPU_ID_ARM710T,	CPU_CLASS_ARM7TDMI,	"ARM710T",
197129198Scognet	  generic_steppings },
198129198Scognet	{ CPU_ID_ARM720T,	CPU_CLASS_ARM7TDMI,	"ARM720T",
199129198Scognet	  generic_steppings },
200129198Scognet	{ CPU_ID_ARM740T8K,	CPU_CLASS_ARM7TDMI, "ARM740T (8 KB cache)",
201129198Scognet	  generic_steppings },
202129198Scognet	{ CPU_ID_ARM740T4K,	CPU_CLASS_ARM7TDMI, "ARM740T (4 KB cache)",
203129198Scognet	  generic_steppings },
204129198Scognet
205129198Scognet	{ CPU_ID_ARM810,	CPU_CLASS_ARM8,		"ARM810",
206129198Scognet	  generic_steppings },
207129198Scognet
208129198Scognet	{ CPU_ID_ARM920T,	CPU_CLASS_ARM9TDMI,	"ARM920T",
209129198Scognet	  generic_steppings },
210152653Scognet	{ CPU_ID_ARM920T_ALT,	CPU_CLASS_ARM9TDMI,	"ARM920T",
211152653Scognet	  generic_steppings },
212129198Scognet	{ CPU_ID_ARM922T,	CPU_CLASS_ARM9TDMI,	"ARM922T",
213129198Scognet	  generic_steppings },
214172738Simp	{ CPU_ID_ARM926EJS,	CPU_CLASS_ARM9EJS,	"ARM926EJ-S",
215172738Simp	  generic_steppings },
216129198Scognet	{ CPU_ID_ARM940T,	CPU_CLASS_ARM9TDMI,	"ARM940T",
217129198Scognet	  generic_steppings },
218129198Scognet	{ CPU_ID_ARM946ES,	CPU_CLASS_ARM9ES,	"ARM946E-S",
219129198Scognet	  generic_steppings },
220129198Scognet	{ CPU_ID_ARM966ES,	CPU_CLASS_ARM9ES,	"ARM966E-S",
221129198Scognet	  generic_steppings },
222129198Scognet	{ CPU_ID_ARM966ESR1,	CPU_CLASS_ARM9ES,	"ARM966E-S",
223129198Scognet	  generic_steppings },
224207954Skevlo	{ CPU_ID_FA526,		CPU_CLASS_ARM9TDMI,	"FA526",
225204122Skevlo	  generic_steppings },
226207611Skevlo	{ CPU_ID_FA626TE,	CPU_CLASS_ARM9ES,	"FA626TE",
227207611Skevlo	  generic_steppings },
228204122Skevlo
229129198Scognet	{ CPU_ID_TI925T,	CPU_CLASS_ARM9TDMI,	"TI ARM925T",
230129198Scognet	  generic_steppings },
231129198Scognet
232129198Scognet	{ CPU_ID_ARM1020E,	CPU_CLASS_ARM10E,	"ARM1020E",
233129198Scognet	  generic_steppings },
234129198Scognet	{ CPU_ID_ARM1022ES,	CPU_CLASS_ARM10E,	"ARM1022E-S",
235129198Scognet	  generic_steppings },
236172738Simp	{ CPU_ID_ARM1026EJS,	CPU_CLASS_ARM10EJ,	"ARM1026EJ-S",
237172738Simp	  generic_steppings },
238129198Scognet
239253857Sganbold	{ CPU_ID_CORTEXA7,	CPU_CLASS_CORTEXA,	"Cortex A7",
240253857Sganbold	  generic_steppings },
241239268Sgonzo	{ CPU_ID_CORTEXA8R1,	CPU_CLASS_CORTEXA,	"Cortex A8-r1",
242239268Sgonzo	  generic_steppings },
243239268Sgonzo	{ CPU_ID_CORTEXA8R2,	CPU_CLASS_CORTEXA,	"Cortex A8-r2",
244239268Sgonzo	  generic_steppings },
245239268Sgonzo	{ CPU_ID_CORTEXA8R3,	CPU_CLASS_CORTEXA,	"Cortex A8-r3",
246239268Sgonzo	  generic_steppings },
247239268Sgonzo	{ CPU_ID_CORTEXA9R1,	CPU_CLASS_CORTEXA,	"Cortex A9-r1",
248239268Sgonzo	  generic_steppings },
249239268Sgonzo	{ CPU_ID_CORTEXA9R2,	CPU_CLASS_CORTEXA,	"Cortex A9-r2",
250239268Sgonzo	  generic_steppings },
251249999Swkoszek	{ CPU_ID_CORTEXA9R3,	CPU_CLASS_CORTEXA,	"Cortex A9-r3",
252249999Swkoszek	  generic_steppings },
253252361Sray	{ CPU_ID_CORTEXA15,     CPU_CLASS_CORTEXA,      "Cortex A15",
254252361Sray	  generic_steppings },
255239268Sgonzo
256129198Scognet	{ CPU_ID_SA110,		CPU_CLASS_SA1,		"SA-110",
257129198Scognet	  sa110_steppings },
258129198Scognet	{ CPU_ID_SA1100,	CPU_CLASS_SA1,		"SA-1100",
259129198Scognet	  sa1100_steppings },
260129198Scognet	{ CPU_ID_SA1110,	CPU_CLASS_SA1,		"SA-1110",
261129198Scognet	  sa1110_steppings },
262129198Scognet
263129198Scognet	{ CPU_ID_IXP1200,	CPU_CLASS_SA1,		"IXP1200",
264129198Scognet	  ixp12x0_steppings },
265129198Scognet
266129198Scognet	{ CPU_ID_80200,		CPU_CLASS_XSCALE,	"i80200",
267129198Scognet	  xscale_steppings },
268129198Scognet
269129198Scognet	{ CPU_ID_80321_400,	CPU_CLASS_XSCALE,	"i80321 400MHz",
270129198Scognet	  i80321_steppings },
271129198Scognet	{ CPU_ID_80321_600,	CPU_CLASS_XSCALE,	"i80321 600MHz",
272129198Scognet	  i80321_steppings },
273129198Scognet	{ CPU_ID_80321_400_B0,	CPU_CLASS_XSCALE,	"i80321 400MHz",
274129198Scognet	  i80321_steppings },
275129198Scognet	{ CPU_ID_80321_600_B0,	CPU_CLASS_XSCALE,	"i80321 600MHz",
276129198Scognet	  i80321_steppings },
277129198Scognet
278164080Scognet	{ CPU_ID_81342,		CPU_CLASS_XSCALE,	"i81342",
279164080Scognet	  i81342_steppings },
280164080Scognet
281161592Scognet	{ CPU_ID_80219_400,	CPU_CLASS_XSCALE,	"i80219 400MHz",
282172738Simp	  i80219_steppings },
283161592Scognet	{ CPU_ID_80219_600,	CPU_CLASS_XSCALE,	"i80219 600MHz",
284172738Simp	  i80219_steppings },
285161592Scognet
286172738Simp	{ CPU_ID_PXA27X,	CPU_CLASS_XSCALE,	"PXA27x",
287172738Simp	  pxa27x_steppings },
288129198Scognet	{ CPU_ID_PXA250A,	CPU_CLASS_XSCALE,	"PXA250",
289129198Scognet	  pxa2x0_steppings },
290129198Scognet	{ CPU_ID_PXA210A,	CPU_CLASS_XSCALE,	"PXA210",
291129198Scognet	  pxa2x0_steppings },
292129198Scognet	{ CPU_ID_PXA250B,	CPU_CLASS_XSCALE,	"PXA250",
293129198Scognet	  pxa2x0_steppings },
294129198Scognet	{ CPU_ID_PXA210B,	CPU_CLASS_XSCALE,	"PXA210",
295129198Scognet	  pxa2x0_steppings },
296172738Simp	{ CPU_ID_PXA250C, 	CPU_CLASS_XSCALE,	"PXA255",
297172738Simp	  pxa255_steppings },
298129198Scognet	{ CPU_ID_PXA210C, 	CPU_CLASS_XSCALE,	"PXA210",
299129198Scognet	  pxa2x0_steppings },
300129198Scognet
301129198Scognet	{ CPU_ID_IXP425_533,	CPU_CLASS_XSCALE,	"IXP425 533MHz",
302129198Scognet	  ixp425_steppings },
303129198Scognet	{ CPU_ID_IXP425_400,	CPU_CLASS_XSCALE,	"IXP425 400MHz",
304129198Scognet	  ixp425_steppings },
305129198Scognet	{ CPU_ID_IXP425_266,	CPU_CLASS_XSCALE,	"IXP425 266MHz",
306129198Scognet	  ixp425_steppings },
307129198Scognet
308186352Ssam	/* XXX ixp435 steppings? */
309186352Ssam	{ CPU_ID_IXP435,	CPU_CLASS_XSCALE,	"IXP435",
310186352Ssam	  ixp425_steppings },
311186352Ssam
312172738Simp	{ CPU_ID_ARM1136JS,	CPU_CLASS_ARM11J,	"ARM1136J-S",
313172738Simp	  generic_steppings },
314172738Simp	{ CPU_ID_ARM1136JSR1,	CPU_CLASS_ARM11J,	"ARM1136J-S R1",
315172738Simp	  generic_steppings },
316244480Sgonzo	{ CPU_ID_ARM1176JZS,	CPU_CLASS_ARM11J,	"ARM1176JZ-S",
317244480Sgonzo	  generic_steppings },
318172738Simp
319183835Sraj	{ CPU_ID_MV88FR131,	CPU_CLASS_MARVELL,	"Feroceon 88FR131",
320183835Sraj	  generic_steppings },
321183835Sraj
322183835Sraj	{ CPU_ID_MV88FR571_VD,	CPU_CLASS_MARVELL,	"Feroceon 88FR571-VD",
323183835Sraj	  generic_steppings },
324239268Sgonzo	{ CPU_ID_MV88SV581X_V6,	CPU_CLASS_MARVELL,	"Sheeva 88SV581x",
325183835Sraj	  generic_steppings },
326239268Sgonzo	{ CPU_ID_ARM_88SV581X_V6, CPU_CLASS_MARVELL,	"Sheeva 88SV581x",
327239268Sgonzo	  generic_steppings },
328239268Sgonzo	{ CPU_ID_MV88SV581X_V7,	CPU_CLASS_MARVELL,	"Sheeva 88SV581x",
329239268Sgonzo	  generic_steppings },
330239268Sgonzo	{ CPU_ID_ARM_88SV581X_V7, CPU_CLASS_MARVELL,	"Sheeva 88SV581x",
331239268Sgonzo	  generic_steppings },
332240486Sgber	{ CPU_ID_MV88SV584X_V6,	CPU_CLASS_MARVELL,	"Sheeva 88SV584x",
333239268Sgonzo	  generic_steppings },
334240486Sgber	{ CPU_ID_ARM_88SV584X_V6, CPU_CLASS_MARVELL,	"Sheeva 88SV584x",
335239268Sgonzo	  generic_steppings },
336240486Sgber	{ CPU_ID_MV88SV584X_V7,	CPU_CLASS_MARVELL,	"Sheeva 88SV584x",
337240486Sgber	  generic_steppings },
338183835Sraj
339129198Scognet	{ 0, CPU_CLASS_NONE, NULL, NULL }
340129198Scognet};
341129198Scognet
342129198Scognetstruct cpu_classtab {
343129198Scognet	const char	*class_name;
344129198Scognet	const char	*class_option;
345129198Scognet};
346129198Scognet
347129198Scognetconst struct cpu_classtab cpu_classes[] = {
348129198Scognet	{ "unknown",	NULL },			/* CPU_CLASS_NONE */
349129198Scognet	{ "ARM2",	"CPU_ARM2" },		/* CPU_CLASS_ARM2 */
350129198Scognet	{ "ARM2as",	"CPU_ARM250" },		/* CPU_CLASS_ARM2AS */
351129198Scognet	{ "ARM3",	"CPU_ARM3" },		/* CPU_CLASS_ARM3 */
352129198Scognet	{ "ARM6",	"CPU_ARM6" },		/* CPU_CLASS_ARM6 */
353129198Scognet	{ "ARM7",	"CPU_ARM7" },		/* CPU_CLASS_ARM7 */
354129198Scognet	{ "ARM7TDMI",	"CPU_ARM7TDMI" },	/* CPU_CLASS_ARM7TDMI */
355129198Scognet	{ "ARM8",	"CPU_ARM8" },		/* CPU_CLASS_ARM8 */
356155242Simp	{ "ARM9TDMI",	"CPU_ARM9TDMI" },	/* CPU_CLASS_ARM9TDMI */
357172738Simp	{ "ARM9E-S",	"CPU_ARM9E" },		/* CPU_CLASS_ARM9ES */
358172738Simp	{ "ARM9EJ-S",	"CPU_ARM9E" },		/* CPU_CLASS_ARM9EJS */
359129198Scognet	{ "ARM10E",	"CPU_ARM10" },		/* CPU_CLASS_ARM10E */
360172738Simp	{ "ARM10EJ",	"CPU_ARM10" },		/* CPU_CLASS_ARM10EJ */
361239268Sgonzo	{ "Cortex-A",	"CPU_CORTEXA" },	/* CPU_CLASS_CORTEXA */
362129198Scognet	{ "SA-1",	"CPU_SA110" },		/* CPU_CLASS_SA1 */
363129198Scognet	{ "XScale",	"CPU_XSCALE_..." },	/* CPU_CLASS_XSCALE */
364172738Simp	{ "ARM11J",	"CPU_ARM11" },		/* CPU_CLASS_ARM11J */
365205027Sraj	{ "Marvell",	"CPU_MARVELL" },	/* CPU_CLASS_MARVELL */
366129198Scognet};
367129198Scognet
368129198Scognet/*
369129198Scognet * Report the type of the specified arm processor. This uses the generic and
370129198Scognet * arm specific information in the cpu structure to identify the processor.
371129198Scognet * The remaining fields in the cpu structure are filled in appropriately.
372129198Scognet */
373129198Scognet
374129198Scognetstatic const char * const wtnames[] = {
375129198Scognet	"write-through",
376129198Scognet	"write-back",
377129198Scognet	"write-back",
378129198Scognet	"**unknown 3**",
379129198Scognet	"**unknown 4**",
380129198Scognet	"write-back-locking",		/* XXX XScale-specific? */
381129198Scognet	"write-back-locking-A",
382129198Scognet	"write-back-locking-B",
383129198Scognet	"**unknown 8**",
384129198Scognet	"**unknown 9**",
385129198Scognet	"**unknown 10**",
386129198Scognet	"**unknown 11**",
387129198Scognet	"**unknown 12**",
388129198Scognet	"**unknown 13**",
389172738Simp	"write-back-locking-C",
390129198Scognet	"**unknown 15**",
391129198Scognet};
392129198Scognet
393239268Sgonzostatic void
394239268Sgonzoprint_enadis(int enadis, char *s)
395239268Sgonzo{
396153940Snetchild
397239268Sgonzo	printf(" %s %sabled", s, (enadis == 0) ? "dis" : "en");
398239268Sgonzo}
399239268Sgonzo
400129198Scognetextern int ctrl;
401197523Srpauloenum cpu_class cpu_class = CPU_CLASS_NONE;
402239268Sgonzo
403239268Sgonzou_int cpu_pfr(int num)
404239268Sgonzo{
405239268Sgonzo	u_int feat;
406239268Sgonzo
407239268Sgonzo	switch (num) {
408239268Sgonzo	case 0:
409239268Sgonzo		__asm __volatile("mrc p15, 0, %0, c0, c1, 0"
410239268Sgonzo		    : "=r" (feat));
411239268Sgonzo		break;
412239268Sgonzo	case 1:
413239268Sgonzo		__asm __volatile("mrc p15, 0, %0, c0, c1, 1"
414239268Sgonzo		    : "=r" (feat));
415239268Sgonzo		break;
416239268Sgonzo	default:
417239268Sgonzo		panic("Processor Feature Register %d not implemented", num);
418239268Sgonzo		break;
419239268Sgonzo	}
420239268Sgonzo
421239268Sgonzo	return (feat);
422239268Sgonzo}
423239268Sgonzo
424239268Sgonzostatic
425239268Sgonzovoid identify_armv7(void)
426239268Sgonzo{
427239268Sgonzo	u_int feature;
428239268Sgonzo
429239268Sgonzo	printf("Supported features:");
430239268Sgonzo	/* Get Processor Feature Register 0 */
431239268Sgonzo	feature = cpu_pfr(0);
432239268Sgonzo
433239268Sgonzo	if (feature & ARM_PFR0_ARM_ISA_MASK)
434239268Sgonzo		printf(" ARM_ISA");
435239268Sgonzo
436239268Sgonzo	if (feature & ARM_PFR0_THUMB2)
437239268Sgonzo		printf(" THUMB2");
438239268Sgonzo	else if (feature & ARM_PFR0_THUMB)
439239268Sgonzo		printf(" THUMB");
440239268Sgonzo
441239268Sgonzo	if (feature & ARM_PFR0_JAZELLE_MASK)
442239268Sgonzo		printf(" JAZELLE");
443239268Sgonzo
444239268Sgonzo	if (feature & ARM_PFR0_THUMBEE_MASK)
445239268Sgonzo		printf(" THUMBEE");
446239268Sgonzo
447239268Sgonzo
448239268Sgonzo	/* Get Processor Feature Register 1 */
449239268Sgonzo	feature = cpu_pfr(1);
450239268Sgonzo
451239268Sgonzo	if (feature & ARM_PFR1_ARMV4_MASK)
452239268Sgonzo		printf(" ARMv4");
453239268Sgonzo
454239268Sgonzo	if (feature & ARM_PFR1_SEC_EXT_MASK)
455239268Sgonzo		printf(" Security_Ext");
456239268Sgonzo
457239268Sgonzo	if (feature & ARM_PFR1_MICROCTRL_MASK)
458239268Sgonzo		printf(" M_profile");
459239268Sgonzo
460239268Sgonzo	printf("\n");
461239268Sgonzo}
462239268Sgonzo
463129198Scognetvoid
464129198Scognetidentify_arm_cpu(void)
465129198Scognet{
466239268Sgonzo	u_int cpuid, reg, size, sets, ways;
467239268Sgonzo	u_int8_t type, linesize;
468129198Scognet	int i;
469129198Scognet
470129198Scognet	cpuid = cpu_id();
471129198Scognet
472129198Scognet	if (cpuid == 0) {
473129198Scognet		printf("Processor failed probe - no CPU ID\n");
474129198Scognet		return;
475129198Scognet	}
476129198Scognet
477129198Scognet	for (i = 0; cpuids[i].cpuid != 0; i++)
478129198Scognet		if (cpuids[i].cpuid == (cpuid & CPU_ID_CPU_MASK)) {
479129198Scognet			cpu_class = cpuids[i].cpu_class;
480155242Simp			printf("CPU: %s %s (%s core)\n",
481129198Scognet			    cpuids[i].cpu_name,
482129198Scognet			    cpuids[i].cpu_steppings[cpuid &
483129198Scognet			    CPU_ID_REVISION_MASK],
484129198Scognet			    cpu_classes[cpu_class].class_name);
485129198Scognet			break;
486129198Scognet		}
487129198Scognet	if (cpuids[i].cpuid == 0)
488129198Scognet		printf("unknown CPU (ID = 0x%x)\n", cpuid);
489129198Scognet
490155242Simp	printf(" ");
491239268Sgonzo
492239268Sgonzo	if ((cpuid & CPU_ID_ARCH_MASK) == CPU_ID_CPUID_SCHEME) {
493239268Sgonzo		identify_armv7();
494239268Sgonzo	} else {
495239268Sgonzo		if (ctrl & CPU_CONTROL_BEND_ENABLE)
496239268Sgonzo			printf(" Big-endian");
497129198Scognet		else
498239268Sgonzo			printf(" Little-endian");
499239268Sgonzo
500239268Sgonzo		switch (cpu_class) {
501239268Sgonzo		case CPU_CLASS_ARM6:
502239268Sgonzo		case CPU_CLASS_ARM7:
503239268Sgonzo		case CPU_CLASS_ARM7TDMI:
504239268Sgonzo		case CPU_CLASS_ARM8:
505239268Sgonzo			print_enadis(ctrl & CPU_CONTROL_IDC_ENABLE, "IDC");
506239268Sgonzo			break;
507239268Sgonzo		case CPU_CLASS_ARM9TDMI:
508239268Sgonzo		case CPU_CLASS_ARM9ES:
509239268Sgonzo		case CPU_CLASS_ARM9EJS:
510239268Sgonzo		case CPU_CLASS_ARM10E:
511239268Sgonzo		case CPU_CLASS_ARM10EJ:
512239268Sgonzo		case CPU_CLASS_SA1:
513239268Sgonzo		case CPU_CLASS_XSCALE:
514239268Sgonzo		case CPU_CLASS_ARM11J:
515239268Sgonzo		case CPU_CLASS_MARVELL:
516239268Sgonzo			print_enadis(ctrl & CPU_CONTROL_DC_ENABLE, "DC");
517239268Sgonzo			print_enadis(ctrl & CPU_CONTROL_IC_ENABLE, "IC");
518171625Scognet#ifdef CPU_XSCALE_81342
519239268Sgonzo			print_enadis(ctrl & CPU_CONTROL_L2_ENABLE, "L2");
520171625Scognet#endif
521239268Sgonzo#if defined(SOC_MV_KIRKWOOD) || defined(SOC_MV_DISCOVERY)
522239268Sgonzo			i = sheeva_control_ext(0, 0);
523239268Sgonzo			print_enadis(i & MV_WA_ENABLE, "WA");
524239268Sgonzo			print_enadis(i & MV_DC_STREAM_ENABLE, "DC streaming");
525239268Sgonzo			printf("\n ");
526239268Sgonzo			print_enadis((i & MV_BTB_DISABLE) == 0, "BTB");
527239268Sgonzo			print_enadis(i & MV_L2_ENABLE, "L2");
528239268Sgonzo			print_enadis((i & MV_L2_PREFETCH_DISABLE) == 0,
529239268Sgonzo			    "L2 prefetch");
530239268Sgonzo			printf("\n ");
531239268Sgonzo#endif
532239268Sgonzo			break;
533239268Sgonzo		default:
534239268Sgonzo			break;
535239268Sgonzo		}
536129198Scognet	}
537129198Scognet
538239268Sgonzo	print_enadis(ctrl & CPU_CONTROL_WBUF_ENABLE, "WB");
539129198Scognet	if (ctrl & CPU_CONTROL_LABT_ENABLE)
540129198Scognet		printf(" LABT");
541129198Scognet	else
542129198Scognet		printf(" EABT");
543129198Scognet
544239268Sgonzo	print_enadis(ctrl & CPU_CONTROL_BPRD_ENABLE, "branch prediction");
545239268Sgonzo	printf("\n");
546129198Scognet
547239268Sgonzo	if (arm_cache_level) {
548239268Sgonzo		printf("LoUU:%d LoC:%d LoUIS:%d \n", CPU_CLIDR_LOUU(arm_cache_level) + 1,
549239268Sgonzo		    arm_cache_loc, CPU_CLIDR_LOUIS(arm_cache_level) + 1);
550239268Sgonzo		i = 0;
551239268Sgonzo		while (((type = CPU_CLIDR_CTYPE(arm_cache_level, i)) != 0) && i < 7) {
552239268Sgonzo			printf("Cache level %d: \n", i + 1);
553239268Sgonzo			if (type == CACHE_DCACHE || type == CACHE_UNI_CACHE ||
554239268Sgonzo			    type == CACHE_SEP_CACHE) {
555239268Sgonzo				reg = arm_cache_type[2 * i];
556239268Sgonzo				ways = CPUV7_CT_xSIZE_ASSOC(reg) + 1;
557239268Sgonzo				sets = CPUV7_CT_xSIZE_SET(reg) + 1;
558239268Sgonzo				linesize = 1 << (CPUV7_CT_xSIZE_LEN(reg) + 4);
559239268Sgonzo				size = (ways * sets * linesize) / 1024;
560239268Sgonzo
561239268Sgonzo				if (type == CACHE_UNI_CACHE)
562239268Sgonzo					printf(" %dKB/%dB %d-way unified cache", size, linesize,ways);
563239268Sgonzo				else
564239268Sgonzo					printf(" %dKB/%dB %d-way data cache", size, linesize, ways);
565239268Sgonzo				if (reg & CPUV7_CT_CTYPE_WT)
566239268Sgonzo					printf(" WT");
567239268Sgonzo				if (reg & CPUV7_CT_CTYPE_WB)
568239268Sgonzo					printf(" WB");
569239268Sgonzo				if (reg & CPUV7_CT_CTYPE_RA)
570239268Sgonzo					printf(" Read-Alloc");
571239268Sgonzo				if (reg & CPUV7_CT_CTYPE_WA)
572239268Sgonzo					printf(" Write-Alloc");
573239268Sgonzo				printf("\n");
574239268Sgonzo			}
575239268Sgonzo
576239268Sgonzo			if (type == CACHE_ICACHE || type == CACHE_SEP_CACHE) {
577239268Sgonzo				reg = arm_cache_type[(2 * i) + 1];
578239268Sgonzo
579239268Sgonzo				ways = CPUV7_CT_xSIZE_ASSOC(reg) + 1;
580239268Sgonzo				sets = CPUV7_CT_xSIZE_SET(reg) + 1;
581239268Sgonzo				linesize = 1 << (CPUV7_CT_xSIZE_LEN(reg) + 4);
582239268Sgonzo				size = (ways * sets * linesize) / 1024;
583239268Sgonzo
584239268Sgonzo				printf(" %dKB/%dB %d-way instruction cache", size, linesize, ways);
585239268Sgonzo				if (reg & CPUV7_CT_CTYPE_WT)
586239268Sgonzo					printf(" WT");
587239268Sgonzo				if (reg & CPUV7_CT_CTYPE_WB)
588239268Sgonzo					printf(" WB");
589239268Sgonzo				if (reg & CPUV7_CT_CTYPE_RA)
590239268Sgonzo					printf(" Read-Alloc");
591239268Sgonzo				if (reg & CPUV7_CT_CTYPE_WA)
592239268Sgonzo					printf(" Write-Alloc");
593239268Sgonzo				printf("\n");
594239268Sgonzo			}
595239268Sgonzo			i++;
596239268Sgonzo		}
597137272Scognet	} else {
598239268Sgonzo		/* Print cache info. */
599239268Sgonzo		if (arm_picache_line_size == 0 && arm_pdcache_line_size == 0)
600239268Sgonzo			return;
601239268Sgonzo
602239268Sgonzo		if (arm_pcache_unified) {
603239268Sgonzo			printf("  %dKB/%dB %d-way %s unified cache\n",
604239268Sgonzo			    arm_pdcache_size / 1024,
605239268Sgonzo			    arm_pdcache_line_size, arm_pdcache_ways,
606239268Sgonzo			    wtnames[arm_pcache_type]);
607239268Sgonzo		} else {
608239268Sgonzo			printf("  %dKB/%dB %d-way instruction cache\n",
609239268Sgonzo			    arm_picache_size / 1024,
610239268Sgonzo			    arm_picache_line_size, arm_picache_ways);
611239268Sgonzo			printf("  %dKB/%dB %d-way %s data cache\n",
612239268Sgonzo			    arm_pdcache_size / 1024,
613239268Sgonzo			    arm_pdcache_line_size, arm_pdcache_ways,
614239268Sgonzo			    wtnames[arm_pcache_type]);
615239268Sgonzo		}
616137272Scognet	}
617129198Scognet}
618