1 /*	$NetBSD: cpu.c,v 1.55 2004/02/13 11:36:10 wiz 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 <sys/cdefs.h>
45 __FBSDID("$FreeBSD: stable/12/sys/arm/arm/identcpu-v4.c 337762 2018-08-14 16:01:25Z andrew $");
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/conf.h>
49 #include <sys/kernel.h>
50 #include <sys/sysctl.h>
51 #include <machine/cpu.h>
52 #include <machine/endian.h>
53 
54 #include <machine/md_var.h>
55 
56 char machine[] = "arm";
57 
58 SYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD,
59 	machine, 0, "Machine class");
60 
61 static const char * const generic_steppings[16] = {
62 	"rev 0",	"rev 1",	"rev 2",	"rev 3",
63 	"rev 4",	"rev 5",	"rev 6",	"rev 7",
64 	"rev 8",	"rev 9",	"rev 10",	"rev 11",
65 	"rev 12",	"rev 13",	"rev 14",	"rev 15",
66 };
67 
68 static const char * const xscale_steppings[16] = {
69 	"step A-0",	"step A-1",	"step B-0",	"step C-0",
70 	"step D-0",	"rev 5",	"rev 6",	"rev 7",
71 	"rev 8",	"rev 9",	"rev 10",	"rev 11",
72 	"rev 12",	"rev 13",	"rev 14",	"rev 15",
73 };
74 
75 static const char * const i80219_steppings[16] = {
76 	"step A-0",	"rev 1",	"rev 2",	"rev 3",
77 	"rev 4",	"rev 5",	"rev 6",	"rev 7",
78 	"rev 8",	"rev 9",	"rev 10",	"rev 11",
79 	"rev 12",	"rev 13",	"rev 14",	"rev 15",
80 };
81 
82 static const char * const i80321_steppings[16] = {
83 	"step A-0",	"step B-0",	"rev 2",	"rev 3",
84 	"rev 4",	"rev 5",	"rev 6",	"rev 7",
85 	"rev 8",	"rev 9",	"rev 10",	"rev 11",
86 	"rev 12",	"rev 13",	"rev 14",	"rev 15",
87 };
88 
89 static const char * const i81342_steppings[16] = {
90 	"step A-0",	"rev 1",	"rev 2",	"rev 3",
91 	"rev 4",	"rev 5",	"rev 6",	"rev 7",
92 	"rev 8",	"rev 9",	"rev 10",	"rev 11",
93 	"rev 12",	"rev 13",	"rev 14",	"rev 15",
94 };
95 
96 /* Steppings for PXA2[15]0 */
97 static const char * const pxa2x0_steppings[16] = {
98 	"step A-0",	"step A-1",	"step B-0",	"step B-1",
99 	"step B-2",	"step C-0",	"rev 6",	"rev 7",
100 	"rev 8",	"rev 9",	"rev 10",	"rev 11",
101 	"rev 12",	"rev 13",	"rev 14",	"rev 15",
102 };
103 
104 /* Steppings for PXA255/26x.
105  * rev 5: PXA26x B0, rev 6: PXA255 A0
106  */
107 static const char * const pxa255_steppings[16] = {
108 	"rev 0",	"rev 1",	"rev 2",	"step A-0",
109 	"rev 4",	"step B-0",	"step A-0",	"rev 7",
110 	"rev 8",	"rev 9",	"rev 10",	"rev 11",
111 	"rev 12",	"rev 13",	"rev 14",	"rev 15",
112 };
113 
114 /* Stepping for PXA27x */
115 static const char * const pxa27x_steppings[16] = {
116 	"step A-0",	"step A-1",	"step B-0",	"step B-1",
117 	"step C-0",	"rev 5",	"rev 6",	"rev 7",
118 	"rev 8",	"rev 9",	"rev 10",	"rev 11",
119 	"rev 12",	"rev 13",	"rev 14",	"rev 15",
120 };
121 
122 struct cpuidtab {
123 	u_int32_t	cpuid;
124 	enum		cpu_class cpu_class;
125 	const char	*cpu_name;
126 	const char * const *cpu_steppings;
127 };
128 
129 const struct cpuidtab cpuids[] = {
130 	{ CPU_ID_ARM920T,	CPU_CLASS_ARM9TDMI,	"ARM920T",
131 	  generic_steppings },
132 	{ CPU_ID_ARM920T_ALT,	CPU_CLASS_ARM9TDMI,	"ARM920T",
133 	  generic_steppings },
134 	{ CPU_ID_ARM922T,	CPU_CLASS_ARM9TDMI,	"ARM922T",
135 	  generic_steppings },
136 	{ CPU_ID_ARM926EJS,	CPU_CLASS_ARM9EJS,	"ARM926EJ-S",
137 	  generic_steppings },
138 	{ CPU_ID_ARM940T,	CPU_CLASS_ARM9TDMI,	"ARM940T",
139 	  generic_steppings },
140 	{ CPU_ID_ARM946ES,	CPU_CLASS_ARM9ES,	"ARM946E-S",
141 	  generic_steppings },
142 	{ CPU_ID_ARM966ES,	CPU_CLASS_ARM9ES,	"ARM966E-S",
143 	  generic_steppings },
144 	{ CPU_ID_ARM966ESR1,	CPU_CLASS_ARM9ES,	"ARM966E-S",
145 	  generic_steppings },
146 	{ CPU_ID_FA526,		CPU_CLASS_ARM9TDMI,	"FA526",
147 	  generic_steppings },
148 	{ CPU_ID_FA626TE,	CPU_CLASS_ARM9ES,	"FA626TE",
149 	  generic_steppings },
150 
151 	{ CPU_ID_TI925T,	CPU_CLASS_ARM9TDMI,	"TI ARM925T",
152 	  generic_steppings },
153 
154 	{ CPU_ID_ARM1020E,	CPU_CLASS_ARM10E,	"ARM1020E",
155 	  generic_steppings },
156 	{ CPU_ID_ARM1022ES,	CPU_CLASS_ARM10E,	"ARM1022E-S",
157 	  generic_steppings },
158 	{ CPU_ID_ARM1026EJS,	CPU_CLASS_ARM10EJ,	"ARM1026EJ-S",
159 	  generic_steppings },
160 
161 	{ CPU_ID_80200,		CPU_CLASS_XSCALE,	"i80200",
162 	  xscale_steppings },
163 
164 	{ CPU_ID_80321_400,	CPU_CLASS_XSCALE,	"i80321 400MHz",
165 	  i80321_steppings },
166 	{ CPU_ID_80321_600,	CPU_CLASS_XSCALE,	"i80321 600MHz",
167 	  i80321_steppings },
168 	{ CPU_ID_80321_400_B0,	CPU_CLASS_XSCALE,	"i80321 400MHz",
169 	  i80321_steppings },
170 	{ CPU_ID_80321_600_B0,	CPU_CLASS_XSCALE,	"i80321 600MHz",
171 	  i80321_steppings },
172 
173 	{ CPU_ID_81342,		CPU_CLASS_XSCALE,	"i81342",
174 	  i81342_steppings },
175 
176 	{ CPU_ID_80219_400,	CPU_CLASS_XSCALE,	"i80219 400MHz",
177 	  i80219_steppings },
178 	{ CPU_ID_80219_600,	CPU_CLASS_XSCALE,	"i80219 600MHz",
179 	  i80219_steppings },
180 
181 	{ CPU_ID_PXA27X,	CPU_CLASS_XSCALE,	"PXA27x",
182 	  pxa27x_steppings },
183 	{ CPU_ID_PXA250A,	CPU_CLASS_XSCALE,	"PXA250",
184 	  pxa2x0_steppings },
185 	{ CPU_ID_PXA210A,	CPU_CLASS_XSCALE,	"PXA210",
186 	  pxa2x0_steppings },
187 	{ CPU_ID_PXA250B,	CPU_CLASS_XSCALE,	"PXA250",
188 	  pxa2x0_steppings },
189 	{ CPU_ID_PXA210B,	CPU_CLASS_XSCALE,	"PXA210",
190 	  pxa2x0_steppings },
191 	{ CPU_ID_PXA250C, 	CPU_CLASS_XSCALE,	"PXA255",
192 	  pxa255_steppings },
193 	{ CPU_ID_PXA210C, 	CPU_CLASS_XSCALE,	"PXA210",
194 	  pxa2x0_steppings },
195 
196 	{ CPU_ID_MV88FR131,	CPU_CLASS_MARVELL,	"Feroceon 88FR131",
197 	  generic_steppings },
198 
199 	{ CPU_ID_MV88FR571_VD,	CPU_CLASS_MARVELL,	"Feroceon 88FR571-VD",
200 	  generic_steppings },
201 
202 	{ 0, CPU_CLASS_NONE, NULL, NULL }
203 };
204 
205 struct cpu_classtab {
206 	const char	*class_name;
207 	const char	*class_option;
208 };
209 
210 const struct cpu_classtab cpu_classes[] = {
211 	{ "unknown",	NULL },			/* CPU_CLASS_NONE */
212 	{ "ARM9TDMI",	"CPU_ARM9TDMI" },	/* CPU_CLASS_ARM9TDMI */
213 	{ "ARM9E-S",	"CPU_ARM9E" },		/* CPU_CLASS_ARM9ES */
214 	{ "ARM9EJ-S",	"CPU_ARM9E" },		/* CPU_CLASS_ARM9EJS */
215 	{ "ARM10E",	"CPU_ARM10" },		/* CPU_CLASS_ARM10E */
216 	{ "ARM10EJ",	"CPU_ARM10" },		/* CPU_CLASS_ARM10EJ */
217 	{ "XScale",	"CPU_XSCALE_..." },	/* CPU_CLASS_XSCALE */
218 	{ "Marvell",	"CPU_MARVELL" },	/* CPU_CLASS_MARVELL */
219 };
220 
221 /*
222  * Report the type of the specified arm processor. This uses the generic and
223  * arm specific information in the cpu structure to identify the processor.
224  * The remaining fields in the cpu structure are filled in appropriately.
225  */
226 
227 static const char * const wtnames[] = {
228 	"write-through",
229 	"write-back",
230 	"write-back",
231 	"**unknown 3**",
232 	"**unknown 4**",
233 	"write-back-locking",		/* XXX XScale-specific? */
234 	"write-back-locking-A",
235 	"write-back-locking-B",
236 	"**unknown 8**",
237 	"**unknown 9**",
238 	"**unknown 10**",
239 	"**unknown 11**",
240 	"**unknown 12**",
241 	"**unknown 13**",
242 	"write-back-locking-C",
243 	"**unknown 15**",
244 };
245 
246 static void
print_enadis(int enadis,char * s)247 print_enadis(int enadis, char *s)
248 {
249 
250 	printf(" %s %sabled", s, (enadis == 0) ? "dis" : "en");
251 }
252 
253 enum cpu_class cpu_class = CPU_CLASS_NONE;
254 
255 void
identify_arm_cpu(void)256 identify_arm_cpu(void)
257 {
258 	u_int cpuid, ctrl;
259 	int i;
260 
261 	ctrl = cp15_sctlr_get();
262 	cpuid = cp15_midr_get();
263 
264 	if (cpuid == 0) {
265 		printf("Processor failed probe - no CPU ID\n");
266 		return;
267 	}
268 
269 	for (i = 0; cpuids[i].cpuid != 0; i++)
270 		if (cpuids[i].cpuid == (cpuid & CPU_ID_CPU_MASK)) {
271 			cpu_class = cpuids[i].cpu_class;
272 			printf("CPU: %s %s (%s core)\n",
273 			    cpuids[i].cpu_name,
274 			    cpuids[i].cpu_steppings[cpuid &
275 			    CPU_ID_REVISION_MASK],
276 			    cpu_classes[cpu_class].class_name);
277 			break;
278 		}
279 	if (cpuids[i].cpuid == 0)
280 		printf("unknown CPU (ID = 0x%x)\n", cpuid);
281 
282 	printf(" ");
283 
284 	if (ctrl & CPU_CONTROL_BEND_ENABLE)
285 		printf(" Big-endian");
286 	else
287 		printf(" Little-endian");
288 
289 	switch (cpu_class) {
290 	case CPU_CLASS_ARM9TDMI:
291 	case CPU_CLASS_ARM9ES:
292 	case CPU_CLASS_ARM9EJS:
293 	case CPU_CLASS_ARM10E:
294 	case CPU_CLASS_ARM10EJ:
295 	case CPU_CLASS_XSCALE:
296 	case CPU_CLASS_MARVELL:
297 		print_enadis(ctrl & CPU_CONTROL_DC_ENABLE, "DC");
298 		print_enadis(ctrl & CPU_CONTROL_IC_ENABLE, "IC");
299 #if defined(SOC_MV_KIRKWOOD) || defined(SOC_MV_DISCOVERY)
300 		i = sheeva_control_ext(0, 0);
301 		print_enadis(i & MV_WA_ENABLE, "WA");
302 		print_enadis(i & MV_DC_STREAM_ENABLE, "DC streaming");
303 		printf("\n ");
304 		print_enadis((i & MV_BTB_DISABLE) == 0, "BTB");
305 		print_enadis(i & MV_L2_ENABLE, "L2");
306 		print_enadis((i & MV_L2_PREFETCH_DISABLE) == 0,
307 		    "L2 prefetch");
308 		printf("\n ");
309 #endif
310 		break;
311 	default:
312 		break;
313 	}
314 
315 	print_enadis(ctrl & CPU_CONTROL_WBUF_ENABLE, "WB");
316 	if (ctrl & CPU_CONTROL_LABT_ENABLE)
317 		printf(" LABT");
318 	else
319 		printf(" EABT");
320 
321 	print_enadis(ctrl & CPU_CONTROL_BPRD_ENABLE, "branch prediction");
322 	printf("\n");
323 
324 	/* Print cache info. */
325 	if (arm_picache_line_size == 0 && arm_pdcache_line_size == 0)
326 		return;
327 
328 	if (arm_pcache_unified) {
329 		printf("  %dKB/%dB %d-way %s unified cache\n",
330 		    arm_pdcache_size / 1024,
331 		    arm_pdcache_line_size, arm_pdcache_ways,
332 		    wtnames[arm_pcache_type]);
333 	} else {
334 		printf("  %dKB/%dB %d-way instruction cache\n",
335 		    arm_picache_size / 1024,
336 		    arm_picache_line_size, arm_picache_ways);
337 		printf("  %dKB/%dB %d-way %s data cache\n",
338 		    arm_pdcache_size / 1024,
339 		    arm_pdcache_line_size, arm_pdcache_ways,
340 		    wtnames[arm_pcache_type]);
341 	}
342 }
343