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: stable/11/sys/arm/arm/identcpu-v4.c 314530 2017-03-02 01:18:46Z ian $");
46314530Sian#include <sys/param.h>
47129198Scognet#include <sys/systm.h>
48129198Scognet#include <sys/conf.h>
49135652Scognet#include <sys/kernel.h>
50135652Scognet#include <sys/sysctl.h>
51129198Scognet#include <machine/cpu.h>
52235050Simp#include <machine/endian.h>
53129198Scognet
54197523Srpaulo#include <machine/md_var.h>
55129198Scognet
56129198Scognetchar machine[] = "arm";
57129198Scognet
58135652ScognetSYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD,
59235062Simp	machine, 0, "Machine class");
60129198Scognet
61129198Scognetstatic const char * const generic_steppings[16] = {
62129198Scognet	"rev 0",	"rev 1",	"rev 2",	"rev 3",
63129198Scognet	"rev 4",	"rev 5",	"rev 6",	"rev 7",
64129198Scognet	"rev 8",	"rev 9",	"rev 10",	"rev 11",
65129198Scognet	"rev 12",	"rev 13",	"rev 14",	"rev 15",
66129198Scognet};
67129198Scognet
68129198Scognetstatic const char * const xscale_steppings[16] = {
69129198Scognet	"step A-0",	"step A-1",	"step B-0",	"step C-0",
70129198Scognet	"step D-0",	"rev 5",	"rev 6",	"rev 7",
71129198Scognet	"rev 8",	"rev 9",	"rev 10",	"rev 11",
72129198Scognet	"rev 12",	"rev 13",	"rev 14",	"rev 15",
73129198Scognet};
74129198Scognet
75172738Simpstatic const char * const i80219_steppings[16] = {
76172738Simp	"step A-0",	"rev 1",	"rev 2",	"rev 3",
77172738Simp	"rev 4",	"rev 5",	"rev 6",	"rev 7",
78172738Simp	"rev 8",	"rev 9",	"rev 10",	"rev 11",
79172738Simp	"rev 12",	"rev 13",	"rev 14",	"rev 15",
80172738Simp};
81172738Simp
82129198Scognetstatic const char * const i80321_steppings[16] = {
83129198Scognet	"step A-0",	"step B-0",	"rev 2",	"rev 3",
84129198Scognet	"rev 4",	"rev 5",	"rev 6",	"rev 7",
85129198Scognet	"rev 8",	"rev 9",	"rev 10",	"rev 11",
86129198Scognet	"rev 12",	"rev 13",	"rev 14",	"rev 15",
87129198Scognet};
88129198Scognet
89164080Scognetstatic const char * const i81342_steppings[16] = {
90164080Scognet	"step A-0",	"rev 1",	"rev 2",	"rev 3",
91164080Scognet	"rev 4",	"rev 5",	"rev 6",	"rev 7",
92164080Scognet	"rev 8",	"rev 9",	"rev 10",	"rev 11",
93164080Scognet	"rev 12",	"rev 13",	"rev 14",	"rev 15",
94164080Scognet};
95164080Scognet
96172738Simp/* Steppings for PXA2[15]0 */
97129198Scognetstatic const char * const pxa2x0_steppings[16] = {
98129198Scognet	"step A-0",	"step A-1",	"step B-0",	"step B-1",
99129198Scognet	"step B-2",	"step C-0",	"rev 6",	"rev 7",
100129198Scognet	"rev 8",	"rev 9",	"rev 10",	"rev 11",
101129198Scognet	"rev 12",	"rev 13",	"rev 14",	"rev 15",
102129198Scognet};
103129198Scognet
104172738Simp/* Steppings for PXA255/26x.
105235062Simp * rev 5: PXA26x B0, rev 6: PXA255 A0
106172738Simp */
107172738Simpstatic const char * const pxa255_steppings[16] = {
108172738Simp	"rev 0",	"rev 1",	"rev 2",	"step A-0",
109172738Simp	"rev 4",	"step B-0",	"step A-0",	"rev 7",
110172738Simp	"rev 8",	"rev 9",	"rev 10",	"rev 11",
111172738Simp	"rev 12",	"rev 13",	"rev 14",	"rev 15",
112172738Simp};
113172738Simp
114172738Simp/* Stepping for PXA27x */
115172738Simpstatic const char * const pxa27x_steppings[16] = {
116172738Simp	"step A-0",	"step A-1",	"step B-0",	"step B-1",
117172738Simp	"step C-0",	"rev 5",	"rev 6",	"rev 7",
118172738Simp	"rev 8",	"rev 9",	"rev 10",	"rev 11",
119172738Simp	"rev 12",	"rev 13",	"rev 14",	"rev 15",
120172738Simp};
121172738Simp
122129198Scognetstatic const char * const ixp425_steppings[16] = {
123164423Ssam	"step 0 (A0)",	"rev 1 (ARMv5TE)", "rev 2",	"rev 3",
124129198Scognet	"rev 4",	"rev 5",	"rev 6",	"rev 7",
125129198Scognet	"rev 8",	"rev 9",	"rev 10",	"rev 11",
126129198Scognet	"rev 12",	"rev 13",	"rev 14",	"rev 15",
127129198Scognet};
128129198Scognet
129129198Scognetstruct cpuidtab {
130129198Scognet	u_int32_t	cpuid;
131129198Scognet	enum		cpu_class cpu_class;
132129198Scognet	const char	*cpu_name;
133129198Scognet	const char * const *cpu_steppings;
134129198Scognet};
135129198Scognet
136129198Scognetconst struct cpuidtab cpuids[] = {
137129198Scognet	{ CPU_ID_ARM920T,	CPU_CLASS_ARM9TDMI,	"ARM920T",
138129198Scognet	  generic_steppings },
139152653Scognet	{ CPU_ID_ARM920T_ALT,	CPU_CLASS_ARM9TDMI,	"ARM920T",
140152653Scognet	  generic_steppings },
141129198Scognet	{ CPU_ID_ARM922T,	CPU_CLASS_ARM9TDMI,	"ARM922T",
142129198Scognet	  generic_steppings },
143172738Simp	{ CPU_ID_ARM926EJS,	CPU_CLASS_ARM9EJS,	"ARM926EJ-S",
144172738Simp	  generic_steppings },
145129198Scognet	{ CPU_ID_ARM940T,	CPU_CLASS_ARM9TDMI,	"ARM940T",
146129198Scognet	  generic_steppings },
147129198Scognet	{ CPU_ID_ARM946ES,	CPU_CLASS_ARM9ES,	"ARM946E-S",
148129198Scognet	  generic_steppings },
149129198Scognet	{ CPU_ID_ARM966ES,	CPU_CLASS_ARM9ES,	"ARM966E-S",
150129198Scognet	  generic_steppings },
151129198Scognet	{ CPU_ID_ARM966ESR1,	CPU_CLASS_ARM9ES,	"ARM966E-S",
152129198Scognet	  generic_steppings },
153207954Skevlo	{ CPU_ID_FA526,		CPU_CLASS_ARM9TDMI,	"FA526",
154204122Skevlo	  generic_steppings },
155207611Skevlo	{ CPU_ID_FA626TE,	CPU_CLASS_ARM9ES,	"FA626TE",
156207611Skevlo	  generic_steppings },
157204122Skevlo
158129198Scognet	{ CPU_ID_TI925T,	CPU_CLASS_ARM9TDMI,	"TI ARM925T",
159129198Scognet	  generic_steppings },
160129198Scognet
161129198Scognet	{ CPU_ID_ARM1020E,	CPU_CLASS_ARM10E,	"ARM1020E",
162129198Scognet	  generic_steppings },
163129198Scognet	{ CPU_ID_ARM1022ES,	CPU_CLASS_ARM10E,	"ARM1022E-S",
164129198Scognet	  generic_steppings },
165172738Simp	{ CPU_ID_ARM1026EJS,	CPU_CLASS_ARM10EJ,	"ARM1026EJ-S",
166172738Simp	  generic_steppings },
167129198Scognet
168129198Scognet	{ CPU_ID_80200,		CPU_CLASS_XSCALE,	"i80200",
169129198Scognet	  xscale_steppings },
170129198Scognet
171129198Scognet	{ CPU_ID_80321_400,	CPU_CLASS_XSCALE,	"i80321 400MHz",
172129198Scognet	  i80321_steppings },
173129198Scognet	{ CPU_ID_80321_600,	CPU_CLASS_XSCALE,	"i80321 600MHz",
174129198Scognet	  i80321_steppings },
175129198Scognet	{ CPU_ID_80321_400_B0,	CPU_CLASS_XSCALE,	"i80321 400MHz",
176129198Scognet	  i80321_steppings },
177129198Scognet	{ CPU_ID_80321_600_B0,	CPU_CLASS_XSCALE,	"i80321 600MHz",
178129198Scognet	  i80321_steppings },
179129198Scognet
180164080Scognet	{ CPU_ID_81342,		CPU_CLASS_XSCALE,	"i81342",
181164080Scognet	  i81342_steppings },
182164080Scognet
183161592Scognet	{ CPU_ID_80219_400,	CPU_CLASS_XSCALE,	"i80219 400MHz",
184172738Simp	  i80219_steppings },
185161592Scognet	{ CPU_ID_80219_600,	CPU_CLASS_XSCALE,	"i80219 600MHz",
186172738Simp	  i80219_steppings },
187161592Scognet
188172738Simp	{ CPU_ID_PXA27X,	CPU_CLASS_XSCALE,	"PXA27x",
189172738Simp	  pxa27x_steppings },
190129198Scognet	{ CPU_ID_PXA250A,	CPU_CLASS_XSCALE,	"PXA250",
191129198Scognet	  pxa2x0_steppings },
192129198Scognet	{ CPU_ID_PXA210A,	CPU_CLASS_XSCALE,	"PXA210",
193129198Scognet	  pxa2x0_steppings },
194129198Scognet	{ CPU_ID_PXA250B,	CPU_CLASS_XSCALE,	"PXA250",
195129198Scognet	  pxa2x0_steppings },
196129198Scognet	{ CPU_ID_PXA210B,	CPU_CLASS_XSCALE,	"PXA210",
197129198Scognet	  pxa2x0_steppings },
198172738Simp	{ CPU_ID_PXA250C, 	CPU_CLASS_XSCALE,	"PXA255",
199172738Simp	  pxa255_steppings },
200129198Scognet	{ CPU_ID_PXA210C, 	CPU_CLASS_XSCALE,	"PXA210",
201129198Scognet	  pxa2x0_steppings },
202129198Scognet
203129198Scognet	{ CPU_ID_IXP425_533,	CPU_CLASS_XSCALE,	"IXP425 533MHz",
204129198Scognet	  ixp425_steppings },
205129198Scognet	{ CPU_ID_IXP425_400,	CPU_CLASS_XSCALE,	"IXP425 400MHz",
206129198Scognet	  ixp425_steppings },
207129198Scognet	{ CPU_ID_IXP425_266,	CPU_CLASS_XSCALE,	"IXP425 266MHz",
208129198Scognet	  ixp425_steppings },
209129198Scognet
210186352Ssam	/* XXX ixp435 steppings? */
211186352Ssam	{ CPU_ID_IXP435,	CPU_CLASS_XSCALE,	"IXP435",
212186352Ssam	  ixp425_steppings },
213186352Ssam
214183835Sraj	{ CPU_ID_MV88FR131,	CPU_CLASS_MARVELL,	"Feroceon 88FR131",
215183835Sraj	  generic_steppings },
216183835Sraj
217183835Sraj	{ CPU_ID_MV88FR571_VD,	CPU_CLASS_MARVELL,	"Feroceon 88FR571-VD",
218183835Sraj	  generic_steppings },
219183835Sraj
220129198Scognet	{ 0, CPU_CLASS_NONE, NULL, NULL }
221129198Scognet};
222129198Scognet
223129198Scognetstruct cpu_classtab {
224129198Scognet	const char	*class_name;
225129198Scognet	const char	*class_option;
226129198Scognet};
227129198Scognet
228129198Scognetconst struct cpu_classtab cpu_classes[] = {
229129198Scognet	{ "unknown",	NULL },			/* CPU_CLASS_NONE */
230155242Simp	{ "ARM9TDMI",	"CPU_ARM9TDMI" },	/* CPU_CLASS_ARM9TDMI */
231172738Simp	{ "ARM9E-S",	"CPU_ARM9E" },		/* CPU_CLASS_ARM9ES */
232172738Simp	{ "ARM9EJ-S",	"CPU_ARM9E" },		/* CPU_CLASS_ARM9EJS */
233129198Scognet	{ "ARM10E",	"CPU_ARM10" },		/* CPU_CLASS_ARM10E */
234172738Simp	{ "ARM10EJ",	"CPU_ARM10" },		/* CPU_CLASS_ARM10EJ */
235129198Scognet	{ "XScale",	"CPU_XSCALE_..." },	/* CPU_CLASS_XSCALE */
236205027Sraj	{ "Marvell",	"CPU_MARVELL" },	/* CPU_CLASS_MARVELL */
237129198Scognet};
238129198Scognet
239129198Scognet/*
240129198Scognet * Report the type of the specified arm processor. This uses the generic and
241129198Scognet * arm specific information in the cpu structure to identify the processor.
242129198Scognet * The remaining fields in the cpu structure are filled in appropriately.
243129198Scognet */
244129198Scognet
245129198Scognetstatic const char * const wtnames[] = {
246129198Scognet	"write-through",
247129198Scognet	"write-back",
248129198Scognet	"write-back",
249129198Scognet	"**unknown 3**",
250129198Scognet	"**unknown 4**",
251129198Scognet	"write-back-locking",		/* XXX XScale-specific? */
252129198Scognet	"write-back-locking-A",
253129198Scognet	"write-back-locking-B",
254129198Scognet	"**unknown 8**",
255129198Scognet	"**unknown 9**",
256129198Scognet	"**unknown 10**",
257129198Scognet	"**unknown 11**",
258129198Scognet	"**unknown 12**",
259129198Scognet	"**unknown 13**",
260172738Simp	"write-back-locking-C",
261129198Scognet	"**unknown 15**",
262129198Scognet};
263129198Scognet
264239268Sgonzostatic void
265239268Sgonzoprint_enadis(int enadis, char *s)
266239268Sgonzo{
267153940Snetchild
268239268Sgonzo	printf(" %s %sabled", s, (enadis == 0) ? "dis" : "en");
269239268Sgonzo}
270239268Sgonzo
271197523Srpauloenum cpu_class cpu_class = CPU_CLASS_NONE;
272239268Sgonzo
273239268Sgonzou_int cpu_pfr(int num)
274239268Sgonzo{
275239268Sgonzo	u_int feat;
276239268Sgonzo
277239268Sgonzo	switch (num) {
278239268Sgonzo	case 0:
279239268Sgonzo		__asm __volatile("mrc p15, 0, %0, c0, c1, 0"
280239268Sgonzo		    : "=r" (feat));
281239268Sgonzo		break;
282239268Sgonzo	case 1:
283239268Sgonzo		__asm __volatile("mrc p15, 0, %0, c0, c1, 1"
284239268Sgonzo		    : "=r" (feat));
285239268Sgonzo		break;
286239268Sgonzo	default:
287239268Sgonzo		panic("Processor Feature Register %d not implemented", num);
288239268Sgonzo		break;
289239268Sgonzo	}
290239268Sgonzo
291239268Sgonzo	return (feat);
292239268Sgonzo}
293239268Sgonzo
294129198Scognetvoid
295129198Scognetidentify_arm_cpu(void)
296129198Scognet{
297306901Smmel	u_int cpuid;
298306901Smmel	u_int8_t ctrl;
299129198Scognet	int i;
300129198Scognet
301295252Smmel	ctrl = cpu_get_control();
302278529Sgnn	cpuid = cpu_ident();
303129198Scognet
304129198Scognet	if (cpuid == 0) {
305129198Scognet		printf("Processor failed probe - no CPU ID\n");
306129198Scognet		return;
307129198Scognet	}
308129198Scognet
309129198Scognet	for (i = 0; cpuids[i].cpuid != 0; i++)
310129198Scognet		if (cpuids[i].cpuid == (cpuid & CPU_ID_CPU_MASK)) {
311129198Scognet			cpu_class = cpuids[i].cpu_class;
312155242Simp			printf("CPU: %s %s (%s core)\n",
313129198Scognet			    cpuids[i].cpu_name,
314129198Scognet			    cpuids[i].cpu_steppings[cpuid &
315129198Scognet			    CPU_ID_REVISION_MASK],
316129198Scognet			    cpu_classes[cpu_class].class_name);
317129198Scognet			break;
318129198Scognet		}
319129198Scognet	if (cpuids[i].cpuid == 0)
320129198Scognet		printf("unknown CPU (ID = 0x%x)\n", cpuid);
321129198Scognet
322155242Simp	printf(" ");
323239268Sgonzo
324306901Smmel	if (ctrl & CPU_CONTROL_BEND_ENABLE)
325306901Smmel		printf(" Big-endian");
326306901Smmel	else
327306901Smmel		printf(" Little-endian");
328239268Sgonzo
329306901Smmel	switch (cpu_class) {
330306901Smmel	case CPU_CLASS_ARM9TDMI:
331306901Smmel	case CPU_CLASS_ARM9ES:
332306901Smmel	case CPU_CLASS_ARM9EJS:
333306901Smmel	case CPU_CLASS_ARM10E:
334306901Smmel	case CPU_CLASS_ARM10EJ:
335306901Smmel	case CPU_CLASS_XSCALE:
336306901Smmel	case CPU_CLASS_MARVELL:
337306901Smmel		print_enadis(ctrl & CPU_CONTROL_DC_ENABLE, "DC");
338306901Smmel		print_enadis(ctrl & CPU_CONTROL_IC_ENABLE, "IC");
339171625Scognet#ifdef CPU_XSCALE_81342
340306901Smmel		print_enadis(ctrl & CPU_CONTROL_L2_ENABLE, "L2");
341171625Scognet#endif
342239268Sgonzo#if defined(SOC_MV_KIRKWOOD) || defined(SOC_MV_DISCOVERY)
343306901Smmel		i = sheeva_control_ext(0, 0);
344306901Smmel		print_enadis(i & MV_WA_ENABLE, "WA");
345306901Smmel		print_enadis(i & MV_DC_STREAM_ENABLE, "DC streaming");
346306901Smmel		printf("\n ");
347306901Smmel		print_enadis((i & MV_BTB_DISABLE) == 0, "BTB");
348306901Smmel		print_enadis(i & MV_L2_ENABLE, "L2");
349306901Smmel		print_enadis((i & MV_L2_PREFETCH_DISABLE) == 0,
350306901Smmel		    "L2 prefetch");
351306901Smmel		printf("\n ");
352239268Sgonzo#endif
353306901Smmel		break;
354306901Smmel	default:
355306901Smmel		break;
356129198Scognet	}
357129198Scognet
358239268Sgonzo	print_enadis(ctrl & CPU_CONTROL_WBUF_ENABLE, "WB");
359129198Scognet	if (ctrl & CPU_CONTROL_LABT_ENABLE)
360129198Scognet		printf(" LABT");
361129198Scognet	else
362129198Scognet		printf(" EABT");
363129198Scognet
364239268Sgonzo	print_enadis(ctrl & CPU_CONTROL_BPRD_ENABLE, "branch prediction");
365239268Sgonzo	printf("\n");
366129198Scognet
367306901Smmel	/* Print cache info. */
368306901Smmel	if (arm_picache_line_size == 0 && arm_pdcache_line_size == 0)
369306901Smmel		return;
370239268Sgonzo
371306901Smmel	if (arm_pcache_unified) {
372306901Smmel		printf("  %dKB/%dB %d-way %s unified cache\n",
373306901Smmel		    arm_pdcache_size / 1024,
374306901Smmel		    arm_pdcache_line_size, arm_pdcache_ways,
375306901Smmel		    wtnames[arm_pcache_type]);
376137272Scognet	} else {
377306901Smmel		printf("  %dKB/%dB %d-way instruction cache\n",
378306901Smmel		    arm_picache_size / 1024,
379306901Smmel		    arm_picache_line_size, arm_picache_ways);
380306901Smmel		printf("  %dKB/%dB %d-way %s data cache\n",
381306901Smmel		    arm_pdcache_size / 1024,
382306901Smmel		    arm_pdcache_line_size, arm_pdcache_ways,
383306901Smmel		    wtnames[arm_pcache_type]);
384137272Scognet	}
385129198Scognet}
386