Home | History | Annotate | Line # | Download | only in arm32
cpu.c revision 1.19
      1 /*	$NetBSD: cpu.c,v 1.19 2002/03/09 23:24:11 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 #include <sys/systm.h>
     49 #include <sys/malloc.h>
     50 #include <sys/device.h>
     51 #include <sys/proc.h>
     52 #include <uvm/uvm_extern.h>
     53 #include <machine/conf.h>
     54 #include <machine/cpu.h>
     55 #include <arm/undefined.h>
     56 
     57 #include <arm/cpus.h>
     58 
     59 #ifdef ARMFPE
     60 #include <machine/bootconfig.h> /* For boot args */
     61 #include <arm/fpe-arm/armfpe.h>
     62 #endif
     63 
     64 cpu_t cpus[MAX_CPUS];
     65 
     66 char cpu_model[64];
     67 volatile int undefined_test;	/* Used for FPA test */
     68 
     69 /* Prototypes */
     70 void identify_master_cpu(struct device *dv, int cpu_number);
     71 void identify_arm_cpu(struct device *dv, int cpu_number, struct cpu_info *);
     72 void identify_arm_fpu(struct device *dv, int cpu_number);
     73 int fpa_test(u_int, u_int, trapframe_t *, int);
     74 int fpa_handler(u_int, u_int, trapframe_t *, int);
     75 
     76 /*
     77  * void cpusattach(struct device *parent, struct device *dev, void *aux)
     78  *
     79  * Attach the main cpu
     80  */
     81 
     82 void
     83 cpu_attach(struct device *dv)
     84 {
     85 
     86 	identify_master_cpu(dv, CPU_MASTER);
     87 }
     88 
     89 /*
     90  * Used to test for an FPA. The following function is installed as a coproc1
     91  * handler on the undefined instruction vector and then we issue a FPA
     92  * instruction. If undefined_test is non zero then the FPA did not handle
     93  * the instruction so must be absent.
     94  */
     95 
     96 int
     97 fpa_test(u_int address, u_int instruction, trapframe_t *frame, int fault_code)
     98 {
     99 
    100 	frame->tf_pc += INSN_SIZE;
    101 	++undefined_test;
    102 	return(0);
    103 }
    104 
    105 /*
    106  * If an FPA was found then this function is installed as the coproc1 handler
    107  * on the undefined instruction vector. Currently we don't support FPA's
    108  * so this just triggers an exception.
    109  */
    110 
    111 int
    112 fpa_handler(u_int address, u_int instruction, trapframe_t *frame,
    113     int fault_code)
    114 {
    115 	u_int fpsr;
    116 
    117 	__asm __volatile("stmfd sp!, {r0};"
    118 	    "rfs r0;"
    119 	    "mov %0, r0;"
    120 	    "ldmfd sp!, {r0}" : "=r" (fpsr));
    121 
    122 	printf("FPA exception: fpsr = %08x\n", fpsr);
    123 
    124 	return(1);
    125 }
    126 
    127 
    128 /*
    129  * Identify the master (boot) CPU
    130  * This also probes for an FPU and will install an FPE if necessary
    131  */
    132 
    133 void
    134 identify_master_cpu(struct device *dv, int cpu_number)
    135 {
    136 	u_int fpsr;
    137 	void *uh;
    138 
    139 	evcnt_attach_dynamic(&curcpu()->ci_arm700bugcount, EVCNT_TYPE_MISC,
    140 	    NULL, dv->dv_xname, "arm700swibug");
    141 
    142 	/* Get the cpu ID from coprocessor 15 */
    143 
    144 	curcpu()->ci_cpuid = cpu_id();
    145 
    146 	identify_arm_cpu(dv, cpu_number, curcpu());
    147 	strcpy(cpu_model, cpus[cpu_number].cpu_model);
    148 
    149 	if ((curcpu()->ci_cpuid & CPU_ID_CPU_MASK) == CPU_ID_SA110
    150 	    && (curcpu()->ci_cpuid & CPU_ID_REVISION_MASK) < 3) {
    151 		printf("%s: SA-110 with bugged STM^ instruction\n",
    152 		       dv->dv_xname);
    153 	}
    154 
    155 #ifdef CPU_ARM8
    156 	if ((curcpu()->ci_cpuid & CPU_ID_CPU_MASK) == CPU_ID_ARM810) {
    157 		int clock = arm8_clock_config(0, 0);
    158 		char *fclk;
    159 		printf("%s: ARM810 cp15=%02x", dv->dv_xname, clock);
    160 		printf(" clock:%s", (clock & 1) ? " dynamic" : "");
    161 		printf("%s", (clock & 2) ? " sync" : "");
    162 		switch ((clock >> 2) & 3) {
    163 		case 0:
    164 			fclk = "bus clock";
    165 			break;
    166 		case 1:
    167 			fclk = "ref clock";
    168 			break;
    169 		case 3:
    170 			fclk = "pll";
    171 			break;
    172 		default:
    173 			fclk = "illegal";
    174 			break;
    175 		}
    176 		printf(" fclk source=%s\n", fclk);
    177  	}
    178 #endif
    179 
    180 	/*
    181 	 * Ok now we test for an FPA
    182 	 * At this point no floating point emulator has been installed.
    183 	 * This means any FP instruction will cause undefined exception.
    184 	 * We install a temporay coproc 1 handler which will modify
    185 	 * undefined_test if it is called.
    186 	 * We then try to read the FP status register. If undefined_test
    187 	 * has been decremented then the instruction was not handled by
    188 	 * an FPA so we know the FPA is missing. If undefined_test is
    189 	 * still 1 then we know the instruction was handled by an FPA.
    190 	 * We then remove our test handler and look at the
    191 	 * FP status register for identification.
    192 	 */
    193 
    194 	uh = install_coproc_handler(FP_COPROC, fpa_test);
    195 
    196 	undefined_test = 0;
    197 
    198 	__asm __volatile("stmfd sp!, {r0};"
    199 	    "rfs r0;"
    200 	    "mov %0, r0;"
    201 	    "ldmfd sp!, {r0}" : "=r" (fpsr));
    202 
    203 	remove_coproc_handler(uh);
    204 
    205 	if (undefined_test == 0) {
    206 		cpus[cpu_number].fpu_type = (fpsr >> 24);
    207 	        switch (fpsr >> 24) {
    208 		case 0x81:
    209 			cpus[cpu_number].fpu_class = FPU_CLASS_FPA;
    210 			break;
    211 
    212 		default:
    213 			cpus[cpu_number].fpu_class = FPU_CLASS_FPU;
    214 			break;
    215 		}
    216 		cpus[cpu_number].fpu_flags = 0;
    217 		install_coproc_handler(FP_COPROC, fpa_handler);
    218 	} else {
    219 		cpus[cpu_number].fpu_class = FPU_CLASS_NONE;
    220 		cpus[cpu_number].fpu_flags = 0;
    221 
    222 		/*
    223 		 * Ok if ARMFPE is defined and the boot options request the
    224 		 * ARM FPE then it will be installed as the FPE.
    225 		 * This is just while I work on integrating the new FPE.
    226 		 * It means the new FPE gets installed if compiled int (ARMFPE
    227 		 * defined) and also gives me a on/off option when I boot in
    228 		 * case the new FPE is causing panics.
    229 		 */
    230 
    231 #ifdef ARMFPE
    232 		if (boot_args) {
    233 			int usearmfpe = 1;
    234 
    235 			get_bootconf_option(boot_args, "armfpe",
    236 			    BOOTOPT_TYPE_BOOLEAN, &usearmfpe);
    237 			if (usearmfpe) {
    238 				if (initialise_arm_fpe(&cpus[cpu_number]) != 0)
    239 					identify_arm_fpu(dv, cpu_number);
    240 			}
    241 		}
    242 
    243 #endif
    244 	}
    245 
    246 	identify_arm_fpu(dv, cpu_number);
    247 }
    248 
    249 enum cpu_class {
    250 	CPU_CLASS_NONE,
    251 	CPU_CLASS_ARM2,
    252 	CPU_CLASS_ARM2AS,
    253 	CPU_CLASS_ARM3,
    254 	CPU_CLASS_ARM6,
    255 	CPU_CLASS_ARM7,
    256 	CPU_CLASS_ARM7TDMI,
    257 	CPU_CLASS_ARM8,
    258 	CPU_CLASS_ARM9TDMI,
    259 	CPU_CLASS_ARM9ES,
    260 	CPU_CLASS_SA1,
    261 	CPU_CLASS_XSCALE,
    262 };
    263 
    264 static const char *generic_steppings[16] = {
    265 	"rev 0",	"rev 1",	"rev 2",	"rev 3",
    266 	"rev 4",	"rev 5",	"rev 6",	"rev 7",
    267 	"rev 8",	"rev 9",	"rev 10",	"rev 11",
    268 	"rev 12",	"rev 13",	"rev 14",	"rev 15",
    269 };
    270 
    271 static const char *sa110_steppings[16] = {
    272 	"rev 0",	"step J",	"step K",	"step S",
    273 	"step T",	"rev 5",	"rev 6",	"rev 7",
    274 	"rev 8",	"rev 9",	"rev 10",	"rev 11",
    275 	"rev 12",	"rev 13",	"rev 14",	"rev 15",
    276 };
    277 
    278 static const char *sa1100_steppings[16] = {
    279 	"rev 0",	"step B",	"step C",	"rev 3",
    280 	"rev 4",	"rev 5",	"rev 6",	"rev 7",
    281 	"step D",	"step E",	"rev 10"	"step G",
    282 	"rev 12",	"rev 13",	"rev 14",	"rev 15",
    283 };
    284 
    285 static const char *sa1110_steppings[16] = {
    286 	"step A-0",	"rev 1",	"rev 2",	"rev 3",
    287 	"step B-0",	"step B-1",	"step B-2",	"step B-3",
    288 	"step B-4",	"step B-5",	"rev 10",	"rev 11",
    289 	"rev 12",	"rev 13",	"rev 14",	"rev 15",
    290 };
    291 
    292 static const char *i80200_steppings[16] = {
    293 	"step A-0",	"step A-1",	"step B-0",	"step C-0",
    294 	"rev 4",	"rev 5",	"rev 6",	"rev 7",
    295 	"rev 8",	"rev 9",	"rev 10",	"rev 11",
    296 	"rev 12",	"rev 13",	"rev 14",	"rev 15",
    297 };
    298 
    299 struct cpuidtab {
    300 	u_int32_t	cpuid;
    301 	enum		cpu_class cpu_class;
    302 	const char	*cpu_name;
    303 	const char	**cpu_steppings;
    304 };
    305 
    306 const struct cpuidtab cpuids[] = {
    307 	{ CPU_ID_ARM2,		CPU_CLASS_ARM2,		"ARM2",
    308 	  generic_steppings },
    309 	{ CPU_ID_ARM250,	CPU_CLASS_ARM2AS,	"ARM250",
    310 	  generic_steppings },
    311 
    312 	{ CPU_ID_ARM3,		CPU_CLASS_ARM3,		"ARM3",
    313 	  generic_steppings },
    314 
    315 	{ CPU_ID_ARM600,	CPU_CLASS_ARM6,		"ARM600",
    316 	  generic_steppings },
    317 	{ CPU_ID_ARM610,	CPU_CLASS_ARM6,		"ARM610",
    318 	  generic_steppings },
    319 	{ CPU_ID_ARM620,	CPU_CLASS_ARM6,		"ARM620",
    320 	  generic_steppings },
    321 
    322 	{ CPU_ID_ARM700,	CPU_CLASS_ARM7,		"ARM700",
    323 	  generic_steppings },
    324 	{ CPU_ID_ARM710,	CPU_CLASS_ARM7,		"ARM710",
    325 	  generic_steppings },
    326 	{ CPU_ID_ARM7500,	CPU_CLASS_ARM7,		"ARM7500",
    327 	  generic_steppings },
    328 	{ CPU_ID_ARM710A,	CPU_CLASS_ARM7,		"ARM710a",
    329 	  generic_steppings },
    330 	{ CPU_ID_ARM7500FE,	CPU_CLASS_ARM7,		"ARM7500FE",
    331 	  generic_steppings },
    332 	{ CPU_ID_ARM710T,	CPU_CLASS_ARM7TDMI,	"ARM710T",
    333 	  generic_steppings },
    334 	{ CPU_ID_ARM720T,	CPU_CLASS_ARM7TDMI,	"ARM720T",
    335 	  generic_steppings },
    336 	{ CPU_ID_ARM740T8K,	CPU_CLASS_ARM7TDMI, "ARM740T (8 KB cache)",
    337 	  generic_steppings },
    338 	{ CPU_ID_ARM740T4K,	CPU_CLASS_ARM7TDMI, "ARM740T (4 KB cache)",
    339 	  generic_steppings },
    340 
    341 	{ CPU_ID_ARM810,	CPU_CLASS_ARM8,		"ARM810",
    342 	  generic_steppings },
    343 
    344 	{ CPU_ID_ARM920T,	CPU_CLASS_ARM9TDMI,	"ARM920T",
    345 	  generic_steppings },
    346 	{ CPU_ID_ARM922T,	CPU_CLASS_ARM9TDMI,	"ARM922T",
    347 	  generic_steppings },
    348 	{ CPU_ID_ARM940T,	CPU_CLASS_ARM9TDMI,	"ARM940T",
    349 	  generic_steppings },
    350 	{ CPU_ID_ARM946ES,	CPU_CLASS_ARM9ES,	"ARM946E-S",
    351 	  generic_steppings },
    352 	{ CPU_ID_ARM966ES,	CPU_CLASS_ARM9ES,	"ARM966E-S",
    353 	  generic_steppings },
    354 	{ CPU_ID_ARM966ESR1,	CPU_CLASS_ARM9ES,	"ARM966E-S",
    355 	  generic_steppings },
    356 
    357 	{ CPU_ID_SA110,		CPU_CLASS_SA1,		"SA-110",
    358 	  sa110_steppings },
    359 	{ CPU_ID_SA1100,	CPU_CLASS_SA1,		"SA-1100",
    360 	  sa1100_steppings },
    361 	{ CPU_ID_SA1110,	CPU_CLASS_SA1,		"SA-1110",
    362 	  sa1110_steppings },
    363 
    364 	{ CPU_ID_I80200,	CPU_CLASS_XSCALE,	"i80200",
    365 	  i80200_steppings },
    366 
    367 	{ 0, CPU_CLASS_NONE, NULL, NULL }
    368 };
    369 
    370 struct cpu_classtab {
    371 	const char	*class_name;
    372 	const char	*class_option;
    373 };
    374 
    375 const struct cpu_classtab cpu_classes[] = {
    376 	{ "unknown",	NULL },			/* CPU_CLASS_NONE */
    377 	{ "ARM2",	"CPU_ARM2" },		/* CPU_CLASS_ARM2 */
    378 	{ "ARM2as",	"CPU_ARM250" },		/* CPU_CLASS_ARM2AS */
    379 	{ "ARM3",	"CPU_ARM3" },		/* CPU_CLASS_ARM3 */
    380 	{ "ARM6",	"CPU_ARM6" },		/* CPU_CLASS_ARM6 */
    381 	{ "ARM7",	"CPU_ARM7" },		/* CPU_CLASS_ARM7 */
    382 	{ "ARM7TDMI",	"CPU_ARM7TDMI" },	/* CPU_CLASS_ARM7TDMI */
    383 	{ "ARM8",	"CPU_ARM8" },		/* CPU_CLASS_ARM8 */
    384 	{ "ARM9TDMI",	NULL },			/* CPU_CLASS_ARM9TDMI */
    385 	{ "ARM9E-S",	NULL },			/* CPU_CLASS_ARM9ES */
    386 	{ "SA-1",	"CPU_SA110" },		/* CPU_CLASS_SA1 */
    387 	{ "XScale",	"CPU_XSCALE" },		/* CPU_CLASS_XSCALE */
    388 };
    389 
    390 /*
    391  * Report the type of the specifed arm processor. This uses the generic and
    392  * arm specific information in the cpu structure to identify the processor.
    393  * The remaining fields in the cpu structure are filled in appropriately.
    394  */
    395 
    396 static const char *wtnames[] = {
    397 	"write-through",
    398 	"write-back",
    399 	"write-back",
    400 	"**unknown 3**",
    401 	"**unknown 4**",
    402 	"write-back-locking",		/* XXX XScale-specific? */
    403 	"write-back-locking-A",
    404 	"write-back-locking-B",
    405 	"**unknown 8**",
    406 	"**unknown 9**",
    407 	"**unknown 10**",
    408 	"**unknown 11**",
    409 	"**unknown 12**",
    410 	"**unknown 13**",
    411 	"**unknown 14**",
    412 	"**unknown 15**",
    413 };
    414 
    415 void
    416 identify_arm_cpu(struct device *dv, int cpu_number, struct cpu_info *ci)
    417 {
    418 	cpu_t *cpu;
    419 	u_int cpuid;
    420 	enum cpu_class cpu_class;
    421 	int i;
    422 
    423 	cpu = &cpus[cpu_number];
    424 	cpuid = ci->ci_cpuid;
    425 
    426 	if (cpuid == 0) {
    427 		printf("Processor failed probe - no CPU ID\n");
    428 		return;
    429 	}
    430 
    431 	for (i = 0; cpuids[i].cpuid != 0; i++)
    432 		if (cpuids[i].cpuid == (cpuid & CPU_ID_CPU_MASK)) {
    433 			cpu_class = cpuids[i].cpu_class;
    434 			sprintf(cpu->cpu_model, "%s %s (%s core)",
    435 			    cpuids[i].cpu_name,
    436 			    cpuids[i].cpu_steppings[cpuid &
    437 						    CPU_ID_REVISION_MASK],
    438 			    cpu_classes[cpu_class].class_name);
    439 			break;
    440 		}
    441 
    442 	if (cpuids[i].cpuid == 0)
    443 		sprintf(cpu->cpu_model, "unknown CPU (ID = 0x%x)", cpuid);
    444 
    445 	switch (cpu_class) {
    446 	case CPU_CLASS_ARM6:
    447 	case CPU_CLASS_ARM7:
    448 	case CPU_CLASS_ARM7TDMI:
    449 	case CPU_CLASS_ARM8:
    450 		if ((ci->ci_ctrl & CPU_CONTROL_IDC_ENABLE) == 0)
    451 			strcat(cpu->cpu_model, " IDC disabled");
    452 		else
    453 			strcat(cpu->cpu_model, " IDC enabled");
    454 		break;
    455 	case CPU_CLASS_ARM9TDMI:
    456 	case CPU_CLASS_SA1:
    457 	case CPU_CLASS_XSCALE:
    458 		if ((ci->ci_ctrl & CPU_CONTROL_DC_ENABLE) == 0)
    459 			strcat(cpu->cpu_model, " DC disabled");
    460 		else
    461 			strcat(cpu->cpu_model, " DC enabled");
    462 		if ((ci->ci_ctrl & CPU_CONTROL_IC_ENABLE) == 0)
    463 			strcat(cpu->cpu_model, " IC disabled");
    464 		else
    465 			strcat(cpu->cpu_model, " IC enabled");
    466 		break;
    467 	default:
    468 		break;
    469 	}
    470 	if ((ci->ci_ctrl & CPU_CONTROL_WBUF_ENABLE) == 0)
    471 		strcat(cpu->cpu_model, " WB disabled");
    472 	else
    473 		strcat(cpu->cpu_model, " WB enabled");
    474 
    475 	if (ci->ci_ctrl & CPU_CONTROL_LABT_ENABLE)
    476 		strcat(cpu->cpu_model, " LABT");
    477 	else
    478 		strcat(cpu->cpu_model, " EABT");
    479 
    480 	if (ci->ci_ctrl & CPU_CONTROL_BPRD_ENABLE)
    481 		strcat(cpu->cpu_model, " branch prediction enabled");
    482 
    483 	/* Print the info */
    484 	printf(": %s\n", cpu->cpu_model);
    485 
    486 	/* Print cache info. */
    487 	if (arm_picache_line_size == 0 && arm_pdcache_line_size == 0)
    488 		goto skip_pcache;
    489 
    490 	if (arm_pcache_unified) {
    491 		printf("%s: %dKB/%dB %d-way %s unified cache\n",
    492 		    dv->dv_xname, arm_pdcache_size / 1024,
    493 		    arm_pdcache_line_size, arm_pdcache_ways,
    494 		    wtnames[arm_pcache_type]);
    495 	} else {
    496 		printf("%s: %dKB/%dB %d-way Instruction cache\n",
    497 		    dv->dv_xname, arm_picache_size / 1024,
    498 		    arm_picache_line_size, arm_picache_ways);
    499 		printf("%s: %dKB/%dB %d-way %s Data cache\n",
    500 		    dv->dv_xname, arm_pdcache_size / 1024,
    501 		    arm_pdcache_line_size, arm_pdcache_ways,
    502 		    wtnames[arm_pcache_type]);
    503 	}
    504 
    505  skip_pcache:
    506 
    507 	switch (cpu_class) {
    508 #ifdef CPU_ARM2
    509 	case CPU_CLASS_ARM2:
    510 #endif
    511 #ifdef CPU_ARM250
    512 	case CPU_CLASS_ARM2AS:
    513 #endif
    514 #ifdef CPU_ARM3
    515 	case CPU_CLASS_ARM3:
    516 #endif
    517 #ifdef CPU_ARM6
    518 	case CPU_CLASS_ARM6:
    519 #endif
    520 #ifdef CPU_ARM7
    521 	case CPU_CLASS_ARM7:
    522 #endif
    523 #ifdef CPU_ARM7TDMI
    524 	case CPU_CLASS_ARM7TDMI:
    525 #endif
    526 #ifdef CPU_ARM8
    527 	case CPU_CLASS_ARM8:
    528 #endif
    529 #ifdef CPU_ARM9
    530 	case CPU_CLASS_ARM9TDMI:
    531 #endif
    532 #ifdef CPU_SA110
    533 	case CPU_CLASS_SA1:
    534 #endif
    535 #ifdef CPU_XSCALE
    536 	case CPU_CLASS_XSCALE:
    537 #endif
    538 		break;
    539 	default:
    540 		if (cpu_classes[cpu_class].class_option != NULL)
    541 			printf("%s: %s does not fully support this CPU."
    542 			       "\n", dv->dv_xname, ostype);
    543 		else {
    544 			printf("%s: This kernel does not fully support "
    545 			       "this CPU.\n", dv->dv_xname);
    546 			printf("%s: Recompile with \"options %s\" to "
    547 			       "correct this.\n", dv->dv_xname,
    548 			       cpu_classes[cpu_class].class_option);
    549 		}
    550 		break;
    551 	}
    552 
    553 }
    554 
    555 
    556 /*
    557  * Report the type of the specifed arm fpu. This uses the generic and arm
    558  * specific information in the cpu structure to identify the fpu. The
    559  * remaining fields in the cpu structure are filled in appropriately.
    560  */
    561 
    562 void
    563 identify_arm_fpu(struct device *dv, int cpu_number)
    564 {
    565 	cpu_t *cpu;
    566 
    567 	cpu = &cpus[cpu_number];
    568 
    569 	/* Now for the FP info */
    570 
    571 	switch (cpu->fpu_class) {
    572 	case FPU_CLASS_NONE :
    573 		strcpy(cpu->fpu_model, "None");
    574 		break;
    575 	case FPU_CLASS_FPE :
    576 		printf("%s: FPE: %s\n", dv->dv_xname, cpu->fpu_model);
    577 		printf("%s: no FP hardware found\n", dv->dv_xname);
    578 		break;
    579 	case FPU_CLASS_FPA :
    580 		printf("%s: FPE: %s\n", dv->dv_xname, cpu->fpu_model);
    581 		if (cpu->fpu_type == FPU_TYPE_FPA11) {
    582 			strcpy(cpu->fpu_model, "FPA11");
    583 			printf("%s: FPA11 found\n", dv->dv_xname);
    584 		} else {
    585 			strcpy(cpu->fpu_model, "FPA");
    586 			printf("%s: FPA10 found\n", dv->dv_xname);
    587 		}
    588 		if ((cpu->fpu_flags & 4) == 0)
    589 			strcat(cpu->fpu_model, "");
    590 		else
    591 			strcat(cpu->fpu_model, " clk/2");
    592 		break;
    593 	case FPU_CLASS_FPU :
    594 		sprintf(cpu->fpu_model, "Unknown FPU (ID=%02x)\n",
    595 		    cpu->fpu_type);
    596 		printf("%s: %s\n", dv->dv_xname, cpu->fpu_model);
    597 		break;
    598 	}
    599 }
    600 
    601 /* End of cpu.c */
    602