xref: /freebsd/sys/arm/arm/identcpu-v6.c (revision d0b2dbfa)
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 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/conf.h>
48 #include <sys/kernel.h>
49 #include <sys/sysctl.h>
50 #include <machine/cpu.h>
51 #include <machine/md_var.h>
52 
53 char machine[] = "arm";
54 
55 SYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD | CTLFLAG_CAPRD,
56 	machine, 0, "Machine class");
57 
58 static char cpu_model[64];
59 SYSCTL_STRING(_hw, HW_MODEL, model, CTLFLAG_RD,
60     cpu_model, sizeof(cpu_model), "Machine model");
61 
62 static char hw_buf[81];
63 static int hw_buf_idx;
64 static bool hw_buf_newline;
65 
66 enum cpu_class cpu_class = CPU_CLASS_NONE;
67 
68 static struct {
69 	int	implementer;
70 	int	part_number;
71 	char 	*impl_name;
72 	char 	*core_name;
73 	enum	cpu_class cpu_class;
74 } cpu_names[] =  {
75 	{CPU_IMPLEMENTER_ARM, CPU_ARCH_ARM1176,    "ARM", "ARM1176",
76 	    CPU_CLASS_ARM11J},
77 	{CPU_IMPLEMENTER_ARM, CPU_ARCH_CORTEX_A5 , "ARM", "Cortex-A5",
78 	    CPU_CLASS_CORTEXA},
79 	{CPU_IMPLEMENTER_ARM, CPU_ARCH_CORTEX_A7 , "ARM", "Cortex-A7",
80 	    CPU_CLASS_CORTEXA},
81 	{CPU_IMPLEMENTER_ARM, CPU_ARCH_CORTEX_A8 , "ARM", "Cortex-A8",
82 	    CPU_CLASS_CORTEXA},
83 	{CPU_IMPLEMENTER_ARM, CPU_ARCH_CORTEX_A9 , "ARM", "Cortex-A9",
84 	    CPU_CLASS_CORTEXA},
85 	{CPU_IMPLEMENTER_ARM, CPU_ARCH_CORTEX_A12, "ARM", "Cortex-A12",
86 	    CPU_CLASS_CORTEXA},
87 	{CPU_IMPLEMENTER_ARM, CPU_ARCH_CORTEX_A15, "ARM", "Cortex-A15",
88 	    CPU_CLASS_CORTEXA},
89 	{CPU_IMPLEMENTER_ARM, CPU_ARCH_CORTEX_A17, "ARM", "Cortex-A17",
90 	    CPU_CLASS_CORTEXA},
91 	{CPU_IMPLEMENTER_ARM, CPU_ARCH_CORTEX_A53, "ARM", "Cortex-A53",
92 	    CPU_CLASS_CORTEXA},
93 	{CPU_IMPLEMENTER_ARM, CPU_ARCH_CORTEX_A57, "ARM", "Cortex-A57",
94 	    CPU_CLASS_CORTEXA},
95 	{CPU_IMPLEMENTER_ARM, CPU_ARCH_CORTEX_A72, "ARM", "Cortex-A72",
96 	    CPU_CLASS_CORTEXA},
97 	{CPU_IMPLEMENTER_ARM, CPU_ARCH_CORTEX_A73, "ARM", "Cortex-A73",
98 	    CPU_CLASS_CORTEXA},
99 
100 	{CPU_IMPLEMENTER_MRVL, CPU_ARCH_SHEEVA_581, "Marvell", "PJ4 v7",
101 	    CPU_CLASS_MARVELL},
102 	{CPU_IMPLEMENTER_MRVL, CPU_ARCH_SHEEVA_584, "Marvell", "PJ4MP v7",
103 	    CPU_CLASS_MARVELL},
104 
105 	{CPU_IMPLEMENTER_QCOM, CPU_ARCH_KRAIT_300, "Qualcomm", "Krait 300",
106 	    CPU_CLASS_KRAIT},
107 };
108 
109 static void
110 print_v5_cache(void)
111 {
112 	uint32_t isize, dsize;
113 	uint32_t multiplier;
114 	int pcache_type;
115 	int pcache_unified;
116 	int picache_size;
117 	int picache_line_size;
118 	int picache_ways;
119 	int pdcache_size;
120 	int pdcache_line_size;
121 	int pdcache_ways;
122 
123 	pcache_unified = 0;
124 	picache_size = 0 ;
125 	picache_line_size = 0 ;
126 	picache_ways = 0 ;
127 	pdcache_size = 0;
128 	pdcache_line_size = 0;
129 	pdcache_ways = 0;
130 
131 	if ((cpuinfo.ctr & CPU_CT_S) == 0)
132 		pcache_unified = 1;
133 
134 	/*
135 	 * If you want to know how this code works, go read the ARM ARM.
136 	 */
137 	pcache_type = CPU_CT_CTYPE(cpuinfo.ctr);
138 
139 	if (pcache_unified == 0) {
140 		isize = CPU_CT_ISIZE(cpuinfo.ctr);
141 		multiplier = (isize & CPU_CT_xSIZE_M) ? 3 : 2;
142 		picache_line_size = 1U << (CPU_CT_xSIZE_LEN(isize) + 3);
143 		if (CPU_CT_xSIZE_ASSOC(isize) == 0) {
144 			if (isize & CPU_CT_xSIZE_M)
145 				picache_line_size = 0; /* not present */
146 			else
147 				picache_ways = 1;
148 		} else {
149 			picache_ways = multiplier <<
150 			    (CPU_CT_xSIZE_ASSOC(isize) - 1);
151 		}
152 		picache_size = multiplier << (CPU_CT_xSIZE_SIZE(isize) + 8);
153 	}
154 
155 	dsize = CPU_CT_DSIZE(cpuinfo.ctr);
156 	multiplier = (dsize & CPU_CT_xSIZE_M) ? 3 : 2;
157 	pdcache_line_size = 1U << (CPU_CT_xSIZE_LEN(dsize) + 3);
158 	if (CPU_CT_xSIZE_ASSOC(dsize) == 0) {
159 		if (dsize & CPU_CT_xSIZE_M)
160 			pdcache_line_size = 0; /* not present */
161 		else
162 			pdcache_ways = 1;
163 	} else {
164 		pdcache_ways = multiplier <<
165 		    (CPU_CT_xSIZE_ASSOC(dsize) - 1);
166 		}
167 	pdcache_size = multiplier << (CPU_CT_xSIZE_SIZE(dsize) + 8);
168 
169 	/* Print cache info. */
170 	if (picache_line_size == 0 && pdcache_line_size == 0)
171 		return;
172 
173 	if (pcache_unified) {
174 		printf("  %dKB/%dB %d-way %s unified cache\n",
175 		    pdcache_size / 1024,
176 		    pdcache_line_size, pdcache_ways,
177 		    pcache_type == 0 ? "WT" : "WB");
178 	} else {
179 		printf("  %dKB/%dB %d-way instruction cache\n",
180 		    picache_size / 1024,
181 		    picache_line_size, picache_ways);
182 		printf("  %dKB/%dB %d-way %s data cache\n",
183 		    pdcache_size / 1024,
184 		    pdcache_line_size, pdcache_ways,
185 		    pcache_type == 0 ? "WT" : "WB");
186 	}
187 }
188 
189 static void
190 print_v7_cache(void )
191 {
192 	uint32_t type, val, size, sets, ways, linesize;
193 	int i;
194 
195 	printf("LoUU:%d LoC:%d LoUIS:%d \n",
196 	    CPU_CLIDR_LOUU(cpuinfo.clidr) + 1,
197 	    CPU_CLIDR_LOC(cpuinfo.clidr) + 1,
198 	    CPU_CLIDR_LOUIS(cpuinfo.clidr) + 1);
199 
200 	for (i = 0; i < 7; i++) {
201 		type = CPU_CLIDR_CTYPE(cpuinfo.clidr, i);
202 		if (type == 0)
203 			break;
204 		printf("Cache level %d:\n", i + 1);
205 		if (type == CACHE_DCACHE || type == CACHE_UNI_CACHE ||
206 		    type == CACHE_SEP_CACHE) {
207 			cp15_csselr_set(i << 1);
208 			val = cp15_ccsidr_get();
209 			ways = CPUV7_CT_xSIZE_ASSOC(val) + 1;
210 			sets = CPUV7_CT_xSIZE_SET(val) + 1;
211 			linesize = 1 << (CPUV7_CT_xSIZE_LEN(val) + 4);
212 			size = (ways * sets * linesize) / 1024;
213 
214 			if (type == CACHE_UNI_CACHE)
215 				printf(" %dKB/%dB %d-way unified cache",
216 				    size, linesize,ways);
217 			else
218 				printf(" %dKB/%dB %d-way data cache",
219 				    size, linesize, ways);
220 			if (val & CPUV7_CT_CTYPE_WT)
221 				printf(" WT");
222 			if (val & CPUV7_CT_CTYPE_WB)
223 				printf(" WB");
224 			if (val & CPUV7_CT_CTYPE_RA)
225 				printf(" Read-Alloc");
226 			if (val & CPUV7_CT_CTYPE_WA)
227 				printf(" Write-Alloc");
228 			printf("\n");
229 		}
230 
231 		if (type == CACHE_ICACHE || type == CACHE_SEP_CACHE) {
232 			cp15_csselr_set(i << 1 | 1);
233 			val = cp15_ccsidr_get();
234 			ways = CPUV7_CT_xSIZE_ASSOC(val) + 1;
235 			sets = CPUV7_CT_xSIZE_SET(val) + 1;
236 			linesize = 1 << (CPUV7_CT_xSIZE_LEN(val) + 4);
237 			size = (ways * sets * linesize) / 1024;
238 				printf(" %dKB/%dB %d-way instruction cache",
239 			    size, linesize, ways);
240 			if (val & CPUV7_CT_CTYPE_WT)
241 				printf(" WT");
242 			if (val & CPUV7_CT_CTYPE_WB)
243 				printf(" WB");
244 			if (val & CPUV7_CT_CTYPE_RA)
245 				printf(" Read-Alloc");
246 			if (val & CPUV7_CT_CTYPE_WA)
247 				printf(" Write-Alloc");
248 			printf("\n");
249 		}
250 	}
251 	cp15_csselr_set(0);
252 }
253 
254 static void
255 add_cap(char *cap)
256 {
257 	int len;
258 
259 	len = strlen(cap);
260 
261 	if ((hw_buf_idx + len + 2) >= 79) {
262 		printf("%s,\n", hw_buf);
263 		hw_buf_idx  = 0;
264 		hw_buf_newline = true;
265 	}
266 	if (hw_buf_newline)
267 		hw_buf_idx += sprintf(hw_buf + hw_buf_idx, "  ");
268 	else
269 		hw_buf_idx += sprintf(hw_buf + hw_buf_idx, ", ");
270 	hw_buf_newline = false;
271 
272 	hw_buf_idx += sprintf(hw_buf + hw_buf_idx, "%s", cap);
273 }
274 
275 void
276 identify_arm_cpu(void)
277 {
278 	int i;
279 	u_int val;
280 
281 	/*
282 	 * CPU
283 	 */
284 	for(i = 0; i < nitems(cpu_names); i++) {
285 		if (cpu_names[i].implementer == cpuinfo.implementer &&
286 		    cpu_names[i].part_number == cpuinfo.part_number) {
287 			cpu_class = cpu_names[i].cpu_class;
288 			snprintf(cpu_model, sizeof(cpu_model),
289 			    "%s %s r%dp%d (ECO: 0x%08X)",
290 			    cpu_names[i].impl_name, cpu_names[i].core_name,
291 			    cpuinfo.revision, cpuinfo.patch,
292 			    cpuinfo.midr != cpuinfo.revidr ?
293 			    cpuinfo.revidr : 0);
294 			printf("CPU: %s\n", cpu_model);
295 			break;
296 		}
297 	}
298 	if (i >= nitems(cpu_names))
299 		printf("unknown CPU (ID = 0x%x)\n", cpuinfo.midr);
300 
301 	printf("CPU Features: \n");
302 	hw_buf_idx = 0;
303 	hw_buf_newline = true;
304 
305 	val = (cpuinfo.mpidr >> 4)& 0xF;
306 	if (cpuinfo.mpidr & (1 << 31U))
307 		add_cap("Multiprocessing");
308 	val = (cpuinfo.id_pfr0 >> 4)& 0xF;
309 	if (val == 1)
310 		add_cap("Thumb");
311 	else if (val == 3)
312 		add_cap("Thumb2");
313 
314 	val = (cpuinfo.id_pfr1 >> 4)& 0xF;
315 	if (val == 1 || val == 2)
316 		add_cap("Security");
317 
318 	val = (cpuinfo.id_pfr1 >> 12)& 0xF;
319 	if (val == 1)
320 		add_cap("Virtualization");
321 
322 	val = (cpuinfo.id_pfr1 >> 16)& 0xF;
323 	if (val == 1)
324 		add_cap("Generic Timer");
325 
326 	val = (cpuinfo.id_mmfr0 >> 0)& 0xF;
327 	if (val == 2) {
328 		add_cap("VMSAv6");
329 	} else if (val >= 3) {
330 		add_cap("VMSAv7");
331 		if (val >= 4)
332 			add_cap("PXN");
333 		if (val >= 5)
334 			add_cap("LPAE");
335 	}
336 
337 	val = (cpuinfo.id_mmfr3 >> 20)& 0xF;
338 	if (val == 1)
339 		add_cap("Coherent Walk");
340 
341 	if (hw_buf_idx != 0)
342 		printf("%s\n", hw_buf);
343 
344 	printf("Optional instructions: \n");
345 	hw_buf_idx = 0;
346 	hw_buf_newline = true;
347 	val = (cpuinfo.id_isar0 >> 24)& 0xF;
348 	if (val == 1)
349 		add_cap("SDIV/UDIV (Thumb)");
350 	else if (val == 2)
351 		add_cap("SDIV/UDIV");
352 
353 	val = (cpuinfo.id_isar2 >> 20)& 0xF;
354 	if (val == 1 || val == 2)
355 		add_cap("UMULL");
356 
357 	val = (cpuinfo.id_isar2 >> 16)& 0xF;
358 	if (val == 1 || val == 2 || val == 3)
359 		add_cap("SMULL");
360 
361 	val = (cpuinfo.id_isar2 >> 12)& 0xF;
362 	if (val == 1)
363 		add_cap("MLA");
364 
365 	val = (cpuinfo.id_isar3 >> 4)& 0xF;
366 	if (val == 1)
367 		add_cap("SIMD");
368 	else if (val == 3)
369 		add_cap("SIMD(ext)");
370 	if (hw_buf_idx != 0)
371 		printf("%s\n", hw_buf);
372 
373 	/*
374 	 * Cache
375 	 */
376 	if (CPU_CT_FORMAT(cpuinfo.ctr) == CPU_CT_ARMV7)
377 		print_v7_cache();
378 	else
379 		print_v5_cache();
380 }
381