cpu.c revision 1.45
1/*	$NetBSD: cpu.c,v 1.45 2002/10/13 21:14:28 chris 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
46#include <sys/param.h>
47
48__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.45 2002/10/13 21:14:28 chris Exp $");
49
50#include <sys/systm.h>
51#include <sys/malloc.h>
52#include <sys/device.h>
53#include <sys/proc.h>
54#include <sys/conf.h>
55#include <uvm/uvm_extern.h>
56#include <machine/cpu.h>
57
58#include <arm/cpuconf.h>
59#include <arm/undefined.h>
60
61#ifdef ARMFPE
62#include <machine/bootconfig.h> /* For boot args */
63#include <arm/fpe-arm/armfpe.h>
64#endif
65
66char cpu_model[256];
67
68/* Prototypes */
69void identify_arm_cpu(struct device *dv, struct cpu_info *);
70
71/*
72 * Identify the master (boot) CPU
73 */
74
75void
76cpu_attach(struct device *dv)
77{
78	int usearmfpe;
79
80	usearmfpe = 1;	/* when compiled in, its enabled by default */
81
82	curcpu()->ci_dev = dv;
83
84	evcnt_attach_dynamic(&curcpu()->ci_arm700bugcount, EVCNT_TYPE_MISC,
85	    NULL, dv->dv_xname, "arm700swibug");
86
87	/* Get the cpu ID from coprocessor 15 */
88
89	curcpu()->ci_arm_cpuid = cpu_id();
90	curcpu()->ci_arm_cputype = curcpu()->ci_arm_cpuid & CPU_ID_CPU_MASK;
91	curcpu()->ci_arm_cpurev =
92	    curcpu()->ci_arm_cpuid & CPU_ID_REVISION_MASK;
93
94	identify_arm_cpu(dv, curcpu());
95
96	if (curcpu()->ci_arm_cputype == CPU_ID_SA110 &&
97	    curcpu()->ci_arm_cpurev < 3) {
98		printf("%s: SA-110 with bugged STM^ instruction\n",
99		       dv->dv_xname);
100	}
101
102#ifdef CPU_ARM8
103	if ((curcpu()->ci_arm_cpuid & CPU_ID_CPU_MASK) == CPU_ID_ARM810) {
104		int clock = arm8_clock_config(0, 0);
105		char *fclk;
106		printf("%s: ARM810 cp15=%02x", dv->dv_xname, clock);
107		printf(" clock:%s", (clock & 1) ? " dynamic" : "");
108		printf("%s", (clock & 2) ? " sync" : "");
109		switch ((clock >> 2) & 3) {
110		case 0:
111			fclk = "bus clock";
112			break;
113		case 1:
114			fclk = "ref clock";
115			break;
116		case 3:
117			fclk = "pll";
118			break;
119		default:
120			fclk = "illegal";
121			break;
122		}
123		printf(" fclk source=%s\n", fclk);
124 	}
125#endif
126
127#ifdef ARMFPE
128	/*
129	 * Ok now we test for an FPA
130	 * At this point no floating point emulator has been installed.
131	 * This means any FP instruction will cause undefined exception.
132	 * We install a temporay coproc 1 handler which will modify
133	 * undefined_test if it is called.
134	 * We then try to read the FP status register. If undefined_test
135	 * has been decremented then the instruction was not handled by
136	 * an FPA so we know the FPA is missing. If undefined_test is
137	 * still 1 then we know the instruction was handled by an FPA.
138	 * We then remove our test handler and look at the
139	 * FP status register for identification.
140	 */
141
142	/*
143	 * Ok if ARMFPE is defined and the boot options request the
144	 * ARM FPE then it will be installed as the FPE.
145	 * This is just while I work on integrating the new FPE.
146	 * It means the new FPE gets installed if compiled int (ARMFPE
147	 * defined) and also gives me a on/off option when I boot in
148	 * case the new FPE is causing panics.
149	 */
150
151
152	if (boot_args)
153		get_bootconf_option(boot_args, "armfpe",
154		    BOOTOPT_TYPE_BOOLEAN, &usearmfpe);
155	if (usearmfpe)
156		initialise_arm_fpe();
157#endif
158}
159
160enum cpu_class {
161	CPU_CLASS_NONE,
162	CPU_CLASS_ARM2,
163	CPU_CLASS_ARM2AS,
164	CPU_CLASS_ARM3,
165	CPU_CLASS_ARM6,
166	CPU_CLASS_ARM7,
167	CPU_CLASS_ARM7TDMI,
168	CPU_CLASS_ARM8,
169	CPU_CLASS_ARM9TDMI,
170	CPU_CLASS_ARM9ES,
171	CPU_CLASS_SA1,
172	CPU_CLASS_XSCALE,
173	CPU_CLASS_ARM10E
174};
175
176static const char * const generic_steppings[16] = {
177	"rev 0",	"rev 1",	"rev 2",	"rev 3",
178	"rev 4",	"rev 5",	"rev 6",	"rev 7",
179	"rev 8",	"rev 9",	"rev 10",	"rev 11",
180	"rev 12",	"rev 13",	"rev 14",	"rev 15",
181};
182
183static const char * const sa110_steppings[16] = {
184	"rev 0",	"step J",	"step K",	"step S",
185	"step T",	"rev 5",	"rev 6",	"rev 7",
186	"rev 8",	"rev 9",	"rev 10",	"rev 11",
187	"rev 12",	"rev 13",	"rev 14",	"rev 15",
188};
189
190static const char * const sa1100_steppings[16] = {
191	"rev 0",	"step B",	"step C",	"rev 3",
192	"rev 4",	"rev 5",	"rev 6",	"rev 7",
193	"step D",	"step E",	"rev 10"	"step G",
194	"rev 12",	"rev 13",	"rev 14",	"rev 15",
195};
196
197static const char * const sa1110_steppings[16] = {
198	"step A-0",	"rev 1",	"rev 2",	"rev 3",
199	"step B-0",	"step B-1",	"step B-2",	"step B-3",
200	"step B-4",	"step B-5",	"rev 10",	"rev 11",
201	"rev 12",	"rev 13",	"rev 14",	"rev 15",
202};
203
204static const char * const ixp12x0_steppings[16] = {
205	"(IXP1200 step A)",		"(IXP1200 step B)",
206	"rev 2",			"(IXP1200 step C)",
207	"(IXP1200 step D)",		"(IXP1240/1250 step A)",
208	"(IXP1240 step B)",		"(IXP1250 step B)",
209	"rev 8",	"rev 9",	"rev 10",	"rev 11",
210	"rev 12",	"rev 13",	"rev 14",	"rev 15",
211};
212
213static const char * const xscale_steppings[16] = {
214	"step A-0",	"step A-1",	"step B-0",	"step C-0",
215	"step D-0",	"rev 5",	"rev 6",	"rev 7",
216	"rev 8",	"rev 9",	"rev 10",	"rev 11",
217	"rev 12",	"rev 13",	"rev 14",	"rev 15",
218};
219
220static const char * const i80321_steppings[16] = {
221	"step A-0",	"step B-0",	"rev 2",	"rev 3",
222	"rev 4",	"rev 5",	"rev 6",	"rev 7",
223	"rev 8",	"rev 9",	"rev 10",	"rev 11",
224	"rev 12",	"rev 13",	"rev 14",	"rev 15",
225};
226
227static const char * const pxa2x0_steppings[16] = {
228	"step A-0",	"step A-1",	"step B-0",	"step B-1",
229	"rev 4",	"rev 5",	"rev 6",	"rev 7",
230	"rev 8",	"rev 9",	"rev 10",	"rev 11",
231	"rev 12",	"rev 13",	"rev 14",	"rev 15",
232};
233
234struct cpuidtab {
235	u_int32_t	cpuid;
236	enum		cpu_class cpu_class;
237	const char	*cpu_name;
238	const char * const *cpu_steppings;
239};
240
241const struct cpuidtab cpuids[] = {
242	{ CPU_ID_ARM2,		CPU_CLASS_ARM2,		"ARM2",
243	  generic_steppings },
244	{ CPU_ID_ARM250,	CPU_CLASS_ARM2AS,	"ARM250",
245	  generic_steppings },
246
247	{ CPU_ID_ARM3,		CPU_CLASS_ARM3,		"ARM3",
248	  generic_steppings },
249
250	{ CPU_ID_ARM600,	CPU_CLASS_ARM6,		"ARM600",
251	  generic_steppings },
252	{ CPU_ID_ARM610,	CPU_CLASS_ARM6,		"ARM610",
253	  generic_steppings },
254	{ CPU_ID_ARM620,	CPU_CLASS_ARM6,		"ARM620",
255	  generic_steppings },
256
257	{ CPU_ID_ARM700,	CPU_CLASS_ARM7,		"ARM700",
258	  generic_steppings },
259	{ CPU_ID_ARM710,	CPU_CLASS_ARM7,		"ARM710",
260	  generic_steppings },
261	{ CPU_ID_ARM7500,	CPU_CLASS_ARM7,		"ARM7500",
262	  generic_steppings },
263	{ CPU_ID_ARM710A,	CPU_CLASS_ARM7,		"ARM710a",
264	  generic_steppings },
265	{ CPU_ID_ARM7500FE,	CPU_CLASS_ARM7,		"ARM7500FE",
266	  generic_steppings },
267	{ CPU_ID_ARM710T,	CPU_CLASS_ARM7TDMI,	"ARM710T",
268	  generic_steppings },
269	{ CPU_ID_ARM720T,	CPU_CLASS_ARM7TDMI,	"ARM720T",
270	  generic_steppings },
271	{ CPU_ID_ARM740T8K,	CPU_CLASS_ARM7TDMI, "ARM740T (8 KB cache)",
272	  generic_steppings },
273	{ CPU_ID_ARM740T4K,	CPU_CLASS_ARM7TDMI, "ARM740T (4 KB cache)",
274	  generic_steppings },
275
276	{ CPU_ID_ARM810,	CPU_CLASS_ARM8,		"ARM810",
277	  generic_steppings },
278
279	{ CPU_ID_ARM920T,	CPU_CLASS_ARM9TDMI,	"ARM920T",
280	  generic_steppings },
281	{ CPU_ID_ARM922T,	CPU_CLASS_ARM9TDMI,	"ARM922T",
282	  generic_steppings },
283	{ CPU_ID_ARM940T,	CPU_CLASS_ARM9TDMI,	"ARM940T",
284	  generic_steppings },
285	{ CPU_ID_ARM946ES,	CPU_CLASS_ARM9ES,	"ARM946E-S",
286	  generic_steppings },
287	{ CPU_ID_ARM966ES,	CPU_CLASS_ARM9ES,	"ARM966E-S",
288	  generic_steppings },
289	{ CPU_ID_ARM966ESR1,	CPU_CLASS_ARM9ES,	"ARM966E-S",
290	  generic_steppings },
291
292	{ CPU_ID_SA110,		CPU_CLASS_SA1,		"SA-110",
293	  sa110_steppings },
294	{ CPU_ID_SA1100,	CPU_CLASS_SA1,		"SA-1100",
295	  sa1100_steppings },
296	{ CPU_ID_SA1110,	CPU_CLASS_SA1,		"SA-1110",
297	  sa1110_steppings },
298
299	{ CPU_ID_IXP1200,	CPU_CLASS_SA1,		"IXP1200",
300	  ixp12x0_steppings },
301
302	{ CPU_ID_80200,		CPU_CLASS_XSCALE,	"i80200",
303	  xscale_steppings },
304
305	{ CPU_ID_80321_400,	CPU_CLASS_XSCALE,	"i80321 400MHz",
306	  i80321_steppings },
307	{ CPU_ID_80321_600,	CPU_CLASS_XSCALE,	"i80321 600MHz",
308	  i80321_steppings },
309	{ CPU_ID_80321_400_B0,	CPU_CLASS_XSCALE,	"i80321 400MHz",
310	  i80321_steppings },
311	{ CPU_ID_80321_600_B0,	CPU_CLASS_XSCALE,	"i80321 600MHz",
312	  i80321_steppings },
313
314	{ CPU_ID_PXA250A,	CPU_CLASS_XSCALE,	"PXA250(1st ver core)",
315	  pxa2x0_steppings },
316	{ CPU_ID_PXA210A,	CPU_CLASS_XSCALE,	"PXA210(1st ver core)",
317	  pxa2x0_steppings },
318	{ CPU_ID_PXA250B,	CPU_CLASS_XSCALE,	"PXA250(3rd ver core)",
319	  pxa2x0_steppings },
320	{ CPU_ID_PXA210B,	CPU_CLASS_XSCALE,	"PXA210(3rd ver core)",
321	  pxa2x0_steppings },
322
323	{ CPU_ID_ARM1022ES,	CPU_CLASS_ARM10E,	"ARM1022ES",
324	  generic_steppings },
325
326	{ 0, CPU_CLASS_NONE, NULL, NULL }
327};
328
329struct cpu_classtab {
330	const char	*class_name;
331	const char	*class_option;
332};
333
334const struct cpu_classtab cpu_classes[] = {
335	{ "unknown",	NULL },			/* CPU_CLASS_NONE */
336	{ "ARM2",	"CPU_ARM2" },		/* CPU_CLASS_ARM2 */
337	{ "ARM2as",	"CPU_ARM250" },		/* CPU_CLASS_ARM2AS */
338	{ "ARM3",	"CPU_ARM3" },		/* CPU_CLASS_ARM3 */
339	{ "ARM6",	"CPU_ARM6" },		/* CPU_CLASS_ARM6 */
340	{ "ARM7",	"CPU_ARM7" },		/* CPU_CLASS_ARM7 */
341	{ "ARM7TDMI",	"CPU_ARM7TDMI" },	/* CPU_CLASS_ARM7TDMI */
342	{ "ARM8",	"CPU_ARM8" },		/* CPU_CLASS_ARM8 */
343	{ "ARM9TDMI",	NULL },			/* CPU_CLASS_ARM9TDMI */
344	{ "ARM9E-S",	NULL },			/* CPU_CLASS_ARM9ES */
345	{ "SA-1",	"CPU_SA110" },		/* CPU_CLASS_SA1 */
346	{ "XScale",	"CPU_XSCALE_..." },	/* CPU_CLASS_XSCALE */
347	{ "ARM10E",	NULL },			/* CPU_CLASS_ARM10E */
348};
349
350/*
351 * Report the type of the specifed arm processor. This uses the generic and
352 * arm specific information in the cpu structure to identify the processor.
353 * The remaining fields in the cpu structure are filled in appropriately.
354 */
355
356static const char * const wtnames[] = {
357	"write-through",
358	"write-back",
359	"write-back",
360	"**unknown 3**",
361	"**unknown 4**",
362	"write-back-locking",		/* XXX XScale-specific? */
363	"write-back-locking-A",
364	"write-back-locking-B",
365	"**unknown 8**",
366	"**unknown 9**",
367	"**unknown 10**",
368	"**unknown 11**",
369	"**unknown 12**",
370	"**unknown 13**",
371	"**unknown 14**",
372	"**unknown 15**",
373};
374
375void
376identify_arm_cpu(struct device *dv, struct cpu_info *ci)
377{
378	u_int cpuid;
379	enum cpu_class cpu_class;
380	int i;
381
382	cpuid = ci->ci_arm_cpuid;
383
384	if (cpuid == 0) {
385		printf("Processor failed probe - no CPU ID\n");
386		return;
387	}
388
389	for (i = 0; cpuids[i].cpuid != 0; i++)
390		if (cpuids[i].cpuid == (cpuid & CPU_ID_CPU_MASK)) {
391			cpu_class = cpuids[i].cpu_class;
392			sprintf(cpu_model, "%s %s (%s core)",
393			    cpuids[i].cpu_name,
394			    cpuids[i].cpu_steppings[cpuid &
395						    CPU_ID_REVISION_MASK],
396			    cpu_classes[cpu_class].class_name);
397			break;
398		}
399
400	if (cpuids[i].cpuid == 0)
401		sprintf(cpu_model, "unknown CPU (ID = 0x%x)", cpuid);
402
403	printf(": %s\n", cpu_model);
404
405	printf("%s:", dv->dv_xname);
406
407	switch (cpu_class) {
408	case CPU_CLASS_ARM6:
409	case CPU_CLASS_ARM7:
410	case CPU_CLASS_ARM7TDMI:
411	case CPU_CLASS_ARM8:
412		if ((ci->ci_ctrl & CPU_CONTROL_IDC_ENABLE) == 0)
413			printf(" IDC disabled");
414		else
415			printf(" IDC enabled");
416		break;
417	case CPU_CLASS_ARM9TDMI:
418	case CPU_CLASS_SA1:
419	case CPU_CLASS_XSCALE:
420		if ((ci->ci_ctrl & CPU_CONTROL_DC_ENABLE) == 0)
421			printf(" DC disabled");
422		else
423			printf(" DC enabled");
424		if ((ci->ci_ctrl & CPU_CONTROL_IC_ENABLE) == 0)
425			printf(" IC disabled");
426		else
427			printf(" IC enabled");
428		break;
429	default:
430		break;
431	}
432	if ((ci->ci_ctrl & CPU_CONTROL_WBUF_ENABLE) == 0)
433		printf(" WB disabled");
434	else
435		printf(" WB enabled");
436
437	if (ci->ci_ctrl & CPU_CONTROL_LABT_ENABLE)
438		printf(" LABT");
439	else
440		printf(" EABT");
441
442	if (ci->ci_ctrl & CPU_CONTROL_BPRD_ENABLE)
443		printf(" branch prediction enabled");
444
445	printf("\n");
446
447	/* Print cache info. */
448	if (arm_picache_line_size == 0 && arm_pdcache_line_size == 0)
449		goto skip_pcache;
450
451	if (arm_pcache_unified) {
452		printf("%s: %dKB/%dB %d-way %s unified cache\n",
453		    dv->dv_xname, arm_pdcache_size / 1024,
454		    arm_pdcache_line_size, arm_pdcache_ways,
455		    wtnames[arm_pcache_type]);
456	} else {
457		printf("%s: %dKB/%dB %d-way Instruction cache\n",
458		    dv->dv_xname, arm_picache_size / 1024,
459		    arm_picache_line_size, arm_picache_ways);
460		printf("%s: %dKB/%dB %d-way %s Data cache\n",
461		    dv->dv_xname, arm_pdcache_size / 1024,
462		    arm_pdcache_line_size, arm_pdcache_ways,
463		    wtnames[arm_pcache_type]);
464	}
465
466 skip_pcache:
467
468	switch (cpu_class) {
469#ifdef CPU_ARM2
470	case CPU_CLASS_ARM2:
471#endif
472#ifdef CPU_ARM250
473	case CPU_CLASS_ARM2AS:
474#endif
475#ifdef CPU_ARM3
476	case CPU_CLASS_ARM3:
477#endif
478#ifdef CPU_ARM6
479	case CPU_CLASS_ARM6:
480#endif
481#ifdef CPU_ARM7
482	case CPU_CLASS_ARM7:
483#endif
484#ifdef CPU_ARM7TDMI
485	case CPU_CLASS_ARM7TDMI:
486#endif
487#ifdef CPU_ARM8
488	case CPU_CLASS_ARM8:
489#endif
490#ifdef CPU_ARM9
491	case CPU_CLASS_ARM9TDMI:
492#endif
493#if defined(CPU_SA110) || defined(CPU_SA1100) || \
494    defined(CPU_SA1110) || defined(CPU_IXP12X0)
495	case CPU_CLASS_SA1:
496#endif
497#if defined(CPU_XSCALE_80200) || defined(CPU_XSCALE_80321) || \
498    defined(CPU_XSCALE_PXA2X0)
499	case CPU_CLASS_XSCALE:
500#endif
501		break;
502	default:
503		if (cpu_classes[cpu_class].class_option != NULL)
504			printf("%s: %s does not fully support this CPU."
505			       "\n", dv->dv_xname, ostype);
506		else {
507			printf("%s: This kernel does not fully support "
508			       "this CPU.\n", dv->dv_xname);
509			printf("%s: Recompile with \"options %s\" to "
510			       "correct this.\n", dv->dv_xname,
511			       cpu_classes[cpu_class].class_option);
512		}
513		break;
514	}
515
516}
517#ifdef MULTIPROCESSOR
518int
519cpu_alloc_idlepcb(struct cpu_info *ci)
520{
521	vaddr_t uaddr;
522	struct pcb *pcb;
523	struct trapframe *tf;
524	int error;
525
526	/*
527	 * Generate a kernel stack and PCB (in essence, a u-area) for the
528	 * new CPU.
529	 */
530	uaddr = uvm_uarea_alloc();
531	error = uvm_fault_wire(kernel_map, uaddr, uaddr + USPACE,
532	    VM_FAULT_WIRE, VM_PROT_READ | VM_PROT_WRITE);
533	if (error)
534		return error;
535	ci->ci_idlepcb = pcb = (struct pcb *)uaddr;
536
537	/*
538	 * This code is largely derived from cpu_fork(), with which it
539	 * should perhaps be shared.
540	 */
541
542	/* Copy the pcb */
543	*pcb = proc0.p_addr->u_pcb;
544
545	/* Set up the undefined stack for the process. */
546	pcb->pcb_un.un_32.pcb32_und_sp = uaddr + USPACE_UNDEF_STACK_TOP;
547	pcb->pcb_un.un_32.pcb32_sp = uaddr + USPACE_SVC_STACK_TOP;
548
549#ifdef STACKCHECKS
550	/* Fill the undefined stack with a known pattern */
551	memset(((u_char *)uaddr) + USPACE_UNDEF_STACK_BOTTOM, 0xdd,
552	    (USPACE_UNDEF_STACK_TOP - USPACE_UNDEF_STACK_BOTTOM));
553	/* Fill the kernel stack with a known pattern */
554	memset(((u_char *)uaddr) + USPACE_SVC_STACK_BOTTOM, 0xdd,
555	    (USPACE_SVC_STACK_TOP - USPACE_SVC_STACK_BOTTOM));
556#endif	/* STACKCHECKS */
557
558	pcb->pcb_tf = tf =
559	    (struct trapframe *)pcb->pcb_un.un_32.pcb32_sp - 1;
560	*tf = *proc0.p_addr->u_pcb.pcb_tf;
561	return 0;
562}
563#endif /* MULTIPROCESSOR */
564
565/* End of cpu.c */
566