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