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