Home | History | Annotate | Line # | Download | only in arm32
cpu.c revision 1.30
      1 /*	$NetBSD: cpu.c,v 1.30 2002/03/24 22:02:58 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.30 2002/03/24 22:02:58 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 *i80200_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_I80200,	CPU_CLASS_XSCALE,	"i80200",
    274 	  i80200_steppings },
    275 
    276 	{ CPU_ID_ARM1022ES,	CPU_CLASS_ARM10E,	"ARM1022ES",
    277 	  generic_steppings },
    278 
    279 	{ 0, CPU_CLASS_NONE, NULL, NULL }
    280 };
    281 
    282 struct cpu_classtab {
    283 	const char	*class_name;
    284 	const char	*class_option;
    285 };
    286 
    287 const struct cpu_classtab cpu_classes[] = {
    288 	{ "unknown",	NULL },			/* CPU_CLASS_NONE */
    289 	{ "ARM2",	"CPU_ARM2" },		/* CPU_CLASS_ARM2 */
    290 	{ "ARM2as",	"CPU_ARM250" },		/* CPU_CLASS_ARM2AS */
    291 	{ "ARM3",	"CPU_ARM3" },		/* CPU_CLASS_ARM3 */
    292 	{ "ARM6",	"CPU_ARM6" },		/* CPU_CLASS_ARM6 */
    293 	{ "ARM7",	"CPU_ARM7" },		/* CPU_CLASS_ARM7 */
    294 	{ "ARM7TDMI",	"CPU_ARM7TDMI" },	/* CPU_CLASS_ARM7TDMI */
    295 	{ "ARM8",	"CPU_ARM8" },		/* CPU_CLASS_ARM8 */
    296 	{ "ARM9TDMI",	NULL },			/* CPU_CLASS_ARM9TDMI */
    297 	{ "ARM9E-S",	NULL },			/* CPU_CLASS_ARM9ES */
    298 	{ "SA-1",	"CPU_SA110" },		/* CPU_CLASS_SA1 */
    299 	{ "XScale",	"CPU_XSCALE" },		/* CPU_CLASS_XSCALE */
    300 	{ "ARM10E",	NULL },			/* CPU_CLASS_ARM10E */
    301 };
    302 
    303 /*
    304  * Report the type of the specifed arm processor. This uses the generic and
    305  * arm specific information in the cpu structure to identify the processor.
    306  * The remaining fields in the cpu structure are filled in appropriately.
    307  */
    308 
    309 static const char *wtnames[] = {
    310 	"write-through",
    311 	"write-back",
    312 	"write-back",
    313 	"**unknown 3**",
    314 	"**unknown 4**",
    315 	"write-back-locking",		/* XXX XScale-specific? */
    316 	"write-back-locking-A",
    317 	"write-back-locking-B",
    318 	"**unknown 8**",
    319 	"**unknown 9**",
    320 	"**unknown 10**",
    321 	"**unknown 11**",
    322 	"**unknown 12**",
    323 	"**unknown 13**",
    324 	"**unknown 14**",
    325 	"**unknown 15**",
    326 };
    327 
    328 void
    329 identify_arm_cpu(struct device *dv, struct cpu_info *ci)
    330 {
    331 	u_int cpuid;
    332 	enum cpu_class cpu_class;
    333 	int i;
    334 
    335 	cpuid = ci->ci_cpuid;
    336 
    337 	if (cpuid == 0) {
    338 		printf("Processor failed probe - no CPU ID\n");
    339 		return;
    340 	}
    341 
    342 	for (i = 0; cpuids[i].cpuid != 0; i++)
    343 		if (cpuids[i].cpuid == (cpuid & CPU_ID_CPU_MASK)) {
    344 			cpu_class = cpuids[i].cpu_class;
    345 			sprintf(cpu_model, "%s %s (%s core)",
    346 			    cpuids[i].cpu_name,
    347 			    cpuids[i].cpu_steppings[cpuid &
    348 						    CPU_ID_REVISION_MASK],
    349 			    cpu_classes[cpu_class].class_name);
    350 			break;
    351 		}
    352 
    353 	if (cpuids[i].cpuid == 0)
    354 		sprintf(cpu_model, "unknown CPU (ID = 0x%x)", cpuid);
    355 
    356 	printf(": %s\n", cpu_model);
    357 
    358 	printf("%s:", dv->dv_xname);
    359 
    360 	switch (cpu_class) {
    361 	case CPU_CLASS_ARM6:
    362 	case CPU_CLASS_ARM7:
    363 	case CPU_CLASS_ARM7TDMI:
    364 	case CPU_CLASS_ARM8:
    365 		if ((ci->ci_ctrl & CPU_CONTROL_IDC_ENABLE) == 0)
    366 			printf(" IDC disabled");
    367 		else
    368 			printf(" IDC enabled");
    369 		break;
    370 	case CPU_CLASS_ARM9TDMI:
    371 	case CPU_CLASS_SA1:
    372 	case CPU_CLASS_XSCALE:
    373 		if ((ci->ci_ctrl & CPU_CONTROL_DC_ENABLE) == 0)
    374 			printf(" DC disabled");
    375 		else
    376 			printf(" DC enabled");
    377 		if ((ci->ci_ctrl & CPU_CONTROL_IC_ENABLE) == 0)
    378 			printf(" IC disabled");
    379 		else
    380 			printf(" IC enabled");
    381 		break;
    382 	default:
    383 		break;
    384 	}
    385 	if ((ci->ci_ctrl & CPU_CONTROL_WBUF_ENABLE) == 0)
    386 		printf(" WB disabled");
    387 	else
    388 		printf(" WB enabled");
    389 
    390 	if (ci->ci_ctrl & CPU_CONTROL_LABT_ENABLE)
    391 		printf(" LABT");
    392 	else
    393 		printf(" EABT");
    394 
    395 	if (ci->ci_ctrl & CPU_CONTROL_BPRD_ENABLE)
    396 		printf(" branch prediction enabled");
    397 
    398 	printf("\n");
    399 
    400 	/* Print cache info. */
    401 	if (arm_picache_line_size == 0 && arm_pdcache_line_size == 0)
    402 		goto skip_pcache;
    403 
    404 	if (arm_pcache_unified) {
    405 		printf("%s: %dKB/%dB %d-way %s unified cache\n",
    406 		    dv->dv_xname, arm_pdcache_size / 1024,
    407 		    arm_pdcache_line_size, arm_pdcache_ways,
    408 		    wtnames[arm_pcache_type]);
    409 	} else {
    410 		printf("%s: %dKB/%dB %d-way Instruction cache\n",
    411 		    dv->dv_xname, arm_picache_size / 1024,
    412 		    arm_picache_line_size, arm_picache_ways);
    413 		printf("%s: %dKB/%dB %d-way %s Data cache\n",
    414 		    dv->dv_xname, arm_pdcache_size / 1024,
    415 		    arm_pdcache_line_size, arm_pdcache_ways,
    416 		    wtnames[arm_pcache_type]);
    417 	}
    418 
    419  skip_pcache:
    420 
    421 	switch (cpu_class) {
    422 #ifdef CPU_ARM2
    423 	case CPU_CLASS_ARM2:
    424 #endif
    425 #ifdef CPU_ARM250
    426 	case CPU_CLASS_ARM2AS:
    427 #endif
    428 #ifdef CPU_ARM3
    429 	case CPU_CLASS_ARM3:
    430 #endif
    431 #ifdef CPU_ARM6
    432 	case CPU_CLASS_ARM6:
    433 #endif
    434 #ifdef CPU_ARM7
    435 	case CPU_CLASS_ARM7:
    436 #endif
    437 #ifdef CPU_ARM7TDMI
    438 	case CPU_CLASS_ARM7TDMI:
    439 #endif
    440 #ifdef CPU_ARM8
    441 	case CPU_CLASS_ARM8:
    442 #endif
    443 #ifdef CPU_ARM9
    444 	case CPU_CLASS_ARM9TDMI:
    445 #endif
    446 #ifdef CPU_SA110
    447 	case CPU_CLASS_SA1:
    448 #endif
    449 #ifdef CPU_XSCALE
    450 	case CPU_CLASS_XSCALE:
    451 #endif
    452 		break;
    453 	default:
    454 		if (cpu_classes[cpu_class].class_option != NULL)
    455 			printf("%s: %s does not fully support this CPU."
    456 			       "\n", dv->dv_xname, ostype);
    457 		else {
    458 			printf("%s: This kernel does not fully support "
    459 			       "this CPU.\n", dv->dv_xname);
    460 			printf("%s: Recompile with \"options %s\" to "
    461 			       "correct this.\n", dv->dv_xname,
    462 			       cpu_classes[cpu_class].class_option);
    463 		}
    464 		break;
    465 	}
    466 
    467 }
    468 
    469 /* End of cpu.c */
    470