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