Home | History | Annotate | Line # | Download | only in arm32
cpu.c revision 1.16
      1 /*	$NetBSD: cpu.c,v 1.16 2002/02/17 20:41:02 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 extern int cpuctrl;		/* cpu control register value */
     69 
     70 /* Prototypes */
     71 void identify_master_cpu(struct device *dv, int cpu_number);
     72 void identify_arm_cpu(struct device *dv, int cpu_number);
     73 void identify_arm_fpu(struct device *dv, int cpu_number);
     74 int fpa_test(u_int, u_int, trapframe_t *, int);
     75 int fpa_handler(u_int, u_int, trapframe_t *, int);
     76 
     77 /*
     78  * void cpusattach(struct device *parent, struct device *dev, void *aux)
     79  *
     80  * Attach the main cpu
     81  */
     82 
     83 void
     84 cpu_attach(struct device *dv)
     85 {
     86 
     87 	identify_master_cpu(dv, CPU_MASTER);
     88 }
     89 
     90 /*
     91  * Used to test for an FPA. The following function is installed as a coproc1
     92  * handler on the undefined instruction vector and then we issue a FPA
     93  * instruction. If undefined_test is non zero then the FPA did not handle
     94  * the instruction so must be absent.
     95  */
     96 
     97 int
     98 fpa_test(u_int address, u_int instruction, trapframe_t *frame, int fault_code)
     99 {
    100 
    101 	frame->tf_pc += INSN_SIZE;
    102 	++undefined_test;
    103 	return(0);
    104 }
    105 
    106 /*
    107  * If an FPA was found then this function is installed as the coproc1 handler
    108  * on the undefined instruction vector. Currently we don't support FPA's
    109  * so this just triggers an exception.
    110  */
    111 
    112 int
    113 fpa_handler(u_int address, u_int instruction, trapframe_t *frame,
    114     int fault_code)
    115 {
    116 	u_int fpsr;
    117 
    118 	__asm __volatile("stmfd sp!, {r0};"
    119 	    "rfs r0;"
    120 	    "mov %0, r0;"
    121 	    "ldmfd sp!, {r0}" : "=r" (fpsr));
    122 
    123 	printf("FPA exception: fpsr = %08x\n", fpsr);
    124 
    125 	return(1);
    126 }
    127 
    128 
    129 /*
    130  * Identify the master (boot) CPU
    131  * This also probes for an FPU and will install an FPE if necessary
    132  */
    133 
    134 void
    135 identify_master_cpu(struct device *dv, int cpu_number)
    136 {
    137 	u_int fpsr;
    138 	void *uh;
    139 
    140 	cpus[cpu_number].cpu_ctrl = cpuctrl;
    141 
    142 	/* Get the cpu ID from coprocessor 15 */
    143 
    144 	cpus[cpu_number].cpu_id = cpu_id();
    145 
    146 	identify_arm_cpu(dv, cpu_number);
    147 	strcpy(cpu_model, cpus[cpu_number].cpu_model);
    148 
    149 	if (cpus[CPU_MASTER].cpu_class == CPU_CLASS_SA1
    150 	    && (cpus[CPU_MASTER].cpu_id & 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 ((cpus[CPU_MASTER].cpu_id & 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 static const char *generic_steppings[16] = {
    250 	"rev 0",	"rev 1",	"rev 2",	"rev 3",
    251 	"rev 4",	"rev 5",	"rev 6",	"rev 7",
    252 	"rev 8",	"rev 9",	"rev 10",	"rev 11",
    253 	"rev 12",	"rev 13",	"rev 14",	"rev 15",
    254 };
    255 
    256 static const char *sa110_steppings[16] = {
    257 	"rev 0",	"step J",	"step K",	"step S",
    258 	"step T",	"rev 5",	"rev 6",	"rev 7",
    259 	"rev 8",	"rev 9",	"rev 10",	"rev 11",
    260 	"rev 12",	"rev 13",	"rev 14",	"rev 15",
    261 };
    262 
    263 static const char *sa1100_steppings[16] = {
    264 	"rev 0",	"step B",	"step C",	"rev 3",
    265 	"rev 4",	"rev 5",	"rev 6",	"rev 7",
    266 	"step D",	"step E",	"rev 10"	"step G",
    267 	"rev 12",	"rev 13",	"rev 14",	"rev 15",
    268 };
    269 
    270 static const char *sa1110_steppings[16] = {
    271 	"step A-0",	"rev 1",	"rev 2",	"rev 3",
    272 	"step B-0",	"step B-1",	"step B-2",	"step B-3",
    273 	"step B-4",	"step B-5",	"rev 10",	"rev 11",
    274 	"rev 12",	"rev 13",	"rev 14",	"rev 15",
    275 };
    276 
    277 static const char *i80200_steppings[16] = {
    278 	"step A-0",	"step A-1",	"step B-0",	"step C-0",
    279 	"rev 4",	"rev 5",	"rev 6",	"rev 7",
    280 	"rev 8",	"rev 9",	"rev 10",	"rev 11",
    281 	"rev 12",	"rev 13",	"rev 14",	"rev 15",
    282 };
    283 
    284 struct cpuidtab {
    285 	u_int32_t	cpuid;
    286 	enum		cpu_class cpu_class;
    287 	const char	*cpu_name;
    288 	const char	**cpu_steppings;
    289 };
    290 
    291 const struct cpuidtab cpuids[] = {
    292 	{ CPU_ID_ARM2,		CPU_CLASS_ARM2,		"ARM2",
    293 	  generic_steppings },
    294 	{ CPU_ID_ARM250,	CPU_CLASS_ARM2AS,	"ARM250",
    295 	  generic_steppings },
    296 
    297 	{ CPU_ID_ARM3,		CPU_CLASS_ARM3,		"ARM3",
    298 	  generic_steppings },
    299 
    300 	{ CPU_ID_ARM600,	CPU_CLASS_ARM6,		"ARM600",
    301 	  generic_steppings },
    302 	{ CPU_ID_ARM610,	CPU_CLASS_ARM6,		"ARM610",
    303 	  generic_steppings },
    304 	{ CPU_ID_ARM620,	CPU_CLASS_ARM6,		"ARM620",
    305 	  generic_steppings },
    306 
    307 	{ CPU_ID_ARM700,	CPU_CLASS_ARM7,		"ARM700",
    308 	  generic_steppings },
    309 	{ CPU_ID_ARM710,	CPU_CLASS_ARM7,		"ARM710",
    310 	  generic_steppings },
    311 	{ CPU_ID_ARM7500,	CPU_CLASS_ARM7,		"ARM7500",
    312 	  generic_steppings },
    313 	{ CPU_ID_ARM710A,	CPU_CLASS_ARM7,		"ARM710a",
    314 	  generic_steppings },
    315 	{ CPU_ID_ARM7500FE,	CPU_CLASS_ARM7,		"ARM7500FE",
    316 	  generic_steppings },
    317 	{ CPU_ID_ARM710T,	CPU_CLASS_ARM7TDMI,	"ARM710T",
    318 	  generic_steppings },
    319 	{ CPU_ID_ARM720T,	CPU_CLASS_ARM7TDMI,	"ARM720T",
    320 	  generic_steppings },
    321 	{ CPU_ID_ARM740T8K,	CPU_CLASS_ARM7TDMI, "ARM740T (8 KB cache)",
    322 	  generic_steppings },
    323 	{ CPU_ID_ARM740T4K,	CPU_CLASS_ARM7TDMI, "ARM740T (4 KB cache)",
    324 	  generic_steppings },
    325 
    326 	{ CPU_ID_ARM810,	CPU_CLASS_ARM8,		"ARM810",
    327 	  generic_steppings },
    328 
    329 	{ CPU_ID_ARM920T,	CPU_CLASS_ARM9TDMI,	"ARM920T",
    330 	  generic_steppings },
    331 	{ CPU_ID_ARM922T,	CPU_CLASS_ARM9TDMI,	"ARM922T",
    332 	  generic_steppings },
    333 	{ CPU_ID_ARM940T,	CPU_CLASS_ARM9TDMI,	"ARM940T",
    334 	  generic_steppings },
    335 	{ CPU_ID_ARM946ES,	CPU_CLASS_ARM9ES,	"ARM946E-S",
    336 	  generic_steppings },
    337 	{ CPU_ID_ARM966ES,	CPU_CLASS_ARM9ES,	"ARM966E-S",
    338 	  generic_steppings },
    339 	{ CPU_ID_ARM966ESR1,	CPU_CLASS_ARM9ES,	"ARM966E-S",
    340 	  generic_steppings },
    341 
    342 	{ CPU_ID_SA110,		CPU_CLASS_SA1,		"SA-110",
    343 	  sa110_steppings },
    344 	{ CPU_ID_SA1100,	CPU_CLASS_SA1,		"SA-1100",
    345 	  sa1100_steppings },
    346 	{ CPU_ID_SA1110,	CPU_CLASS_SA1,		"SA-1110",
    347 	  sa1110_steppings },
    348 
    349 	{ CPU_ID_I80200,	CPU_CLASS_XSCALE,	"i80200",
    350 	  i80200_steppings },
    351 
    352 	{ 0, CPU_CLASS_NONE, NULL, NULL }
    353 };
    354 
    355 struct cpu_classtab {
    356 	const char	*class_name;
    357 	const char	*class_option;
    358 };
    359 
    360 const struct cpu_classtab cpu_classes[] = {
    361 	{ "unknown",	NULL },			/* CPU_CLASS_NONE */
    362 	{ "ARM2",	"CPU_ARM2" },		/* CPU_CLASS_ARM2 */
    363 	{ "ARM2as",	"CPU_ARM250" },		/* CPU_CLASS_ARM2AS */
    364 	{ "ARM3",	"CPU_ARM3" },		/* CPU_CLASS_ARM3 */
    365 	{ "ARM6",	"CPU_ARM6" },		/* CPU_CLASS_ARM6 */
    366 	{ "ARM7",	"CPU_ARM7" },		/* CPU_CLASS_ARM7 */
    367 	{ "ARM7TDMI",	"CPU_ARM7TDMI" },	/* CPU_CLASS_ARM7TDMI */
    368 	{ "ARM8",	"CPU_ARM8" },		/* CPU_CLASS_ARM8 */
    369 	{ "ARM9TDMI",	NULL },			/* CPU_CLASS_ARM9TDMI */
    370 	{ "ARM9E-S",	NULL },			/* CPU_CLASS_ARM9ES */
    371 	{ "SA-1",	"CPU_SA110" },		/* CPU_CLASS_SA1 */
    372 	{ "XScale",	"CPU_XSCALE" },		/* CPU_CLASS_XSCALE */
    373 };
    374 
    375 /*
    376  * Report the type of the specifed arm processor. This uses the generic and
    377  * arm specific information in the cpu structure to identify the processor.
    378  * The remaining fields in the cpu structure are filled in appropriately.
    379  */
    380 
    381 static const char *wtnames[] = {
    382 	"write-through",
    383 	"write-back",
    384 	"write-back",
    385 	"**unknown 3**",
    386 	"**unknown 4**",
    387 	"write-back-locking",		/* XXX XScale-specific? */
    388 	"write-back-locking-A",
    389 	"write-back-locking-B",
    390 	"**unknown 8**",
    391 	"**unknown 9**",
    392 	"**unknown 10**",
    393 	"**unknown 11**",
    394 	"**unknown 12**",
    395 	"**unknown 13**",
    396 	"**unknown 14**",
    397 	"**unknown 15**",
    398 };
    399 
    400 void
    401 identify_arm_cpu(struct device *dv, int cpu_number)
    402 {
    403 	cpu_t *cpu;
    404 	u_int cpuid;
    405 	int i;
    406 
    407 	cpu = &cpus[cpu_number];
    408 	cpuid = cpu->cpu_id;
    409 
    410 	if (cpuid == 0) {
    411 		printf("Processor failed probe - no CPU ID\n");
    412 		return;
    413 	}
    414 
    415 	for (i = 0; cpuids[i].cpuid != 0; i++)
    416 		if (cpuids[i].cpuid == (cpuid & CPU_ID_CPU_MASK)) {
    417 			cpu->cpu_class = cpuids[i].cpu_class;
    418 			sprintf(cpu->cpu_model, "%s %s (%s core)",
    419 			    cpuids[i].cpu_name,
    420 			    cpuids[i].cpu_steppings[cpuid &
    421 						    CPU_ID_REVISION_MASK],
    422 			    cpu_classes[cpu->cpu_class].class_name);
    423 			break;
    424 		}
    425 
    426 	if (cpuids[i].cpuid == 0)
    427 		sprintf(cpu->cpu_model, "unknown CPU (ID = 0x%x)", cpuid);
    428 
    429 	switch (cpu->cpu_class) {
    430 	case CPU_CLASS_ARM6:
    431 	case CPU_CLASS_ARM7:
    432 	case CPU_CLASS_ARM7TDMI:
    433 	case CPU_CLASS_ARM8:
    434 		if ((cpu->cpu_ctrl & CPU_CONTROL_IDC_ENABLE) == 0)
    435 			strcat(cpu->cpu_model, " IDC disabled");
    436 		else
    437 			strcat(cpu->cpu_model, " IDC enabled");
    438 		break;
    439 	case CPU_CLASS_ARM9TDMI:
    440 	case CPU_CLASS_SA1:
    441 	case CPU_CLASS_XSCALE:
    442 		if ((cpu->cpu_ctrl & CPU_CONTROL_DC_ENABLE) == 0)
    443 			strcat(cpu->cpu_model, " DC disabled");
    444 		else
    445 			strcat(cpu->cpu_model, " DC enabled");
    446 		if ((cpu->cpu_ctrl & CPU_CONTROL_IC_ENABLE) == 0)
    447 			strcat(cpu->cpu_model, " IC disabled");
    448 		else
    449 			strcat(cpu->cpu_model, " IC enabled");
    450 		break;
    451 	}
    452 	if ((cpu->cpu_ctrl & CPU_CONTROL_WBUF_ENABLE) == 0)
    453 		strcat(cpu->cpu_model, " WB disabled");
    454 	else
    455 		strcat(cpu->cpu_model, " WB enabled");
    456 
    457 	if (cpu->cpu_ctrl & CPU_CONTROL_LABT_ENABLE)
    458 		strcat(cpu->cpu_model, " LABT");
    459 	else
    460 		strcat(cpu->cpu_model, " EABT");
    461 
    462 	if (cpu->cpu_ctrl & CPU_CONTROL_BPRD_ENABLE)
    463 		strcat(cpu->cpu_model, " branch prediction enabled");
    464 
    465 	/* Print the info */
    466 	printf(": %s\n", cpu->cpu_model);
    467 
    468 	/* Print cache info. */
    469 	if (arm_picache_line_size == 0 && arm_pdcache_line_size == 0)
    470 		goto skip_pcache;
    471 
    472 	if (arm_pcache_unified) {
    473 		printf("%s: %dKB/%dB %d-way %s unified cache\n",
    474 		    dv->dv_xname, arm_pdcache_size / 1024,
    475 		    arm_pdcache_line_size, arm_pdcache_ways,
    476 		    wtnames[arm_pcache_type]);
    477 	} else {
    478 		printf("%s: %dKB/%dB %d-way Instruction cache\n",
    479 		    dv->dv_xname, arm_picache_size / 1024,
    480 		    arm_picache_line_size, arm_picache_ways);
    481 		printf("%s: %dKB/%dB %d-way %s Data cache\n",
    482 		    dv->dv_xname, arm_pdcache_size / 1024,
    483 		    arm_pdcache_line_size, arm_pdcache_ways,
    484 		    wtnames[arm_pcache_type]);
    485 	}
    486 
    487  skip_pcache:
    488 
    489 	switch (cpu->cpu_class) {
    490 #ifdef CPU_ARM2
    491 	case CPU_CLASS_ARM2:
    492 #endif
    493 #ifdef CPU_ARM250
    494 	case CPU_CLASS_ARM2AS:
    495 #endif
    496 #ifdef CPU_ARM3
    497 	case CPU_CLASS_ARM3:
    498 #endif
    499 #ifdef CPU_ARM6
    500 	case CPU_CLASS_ARM6:
    501 #endif
    502 #ifdef CPU_ARM7
    503 	case CPU_CLASS_ARM7:
    504 #endif
    505 #ifdef CPU_ARM7TDMI
    506 	case CPU_CLASS_ARM7TDMI:
    507 #endif
    508 #ifdef CPU_ARM8
    509 	case CPU_CLASS_ARM8:
    510 #endif
    511 #ifdef CPU_ARM9
    512 	case CPU_CLASS_ARM9TDMI:
    513 #endif
    514 #ifdef CPU_SA110
    515 	case CPU_CLASS_SA1:
    516 #endif
    517 #ifdef CPU_XSCALE
    518 	case CPU_CLASS_XSCALE:
    519 #endif
    520 		break;
    521 	default:
    522 		if (cpu_classes[cpu->cpu_class].class_option != NULL)
    523 			printf("%s: %s does not fully support this CPU."
    524 			       "\n", dv->dv_xname, ostype);
    525 		else {
    526 			printf("%s: This kernel does not fully support "
    527 			       "this CPU.\n", dv->dv_xname);
    528 			printf("%s: Recompile with \"options %s\" to "
    529 			       "correct this.\n", dv->dv_xname,
    530 			       cpu_classes[cpu->cpu_class].class_option);
    531 		}
    532 		break;
    533 	}
    534 
    535 }
    536 
    537 
    538 /*
    539  * Report the type of the specifed arm fpu. This uses the generic and arm
    540  * specific information in the cpu structure to identify the fpu. The
    541  * remaining fields in the cpu structure are filled in appropriately.
    542  */
    543 
    544 void
    545 identify_arm_fpu(struct device *dv, int cpu_number)
    546 {
    547 	cpu_t *cpu;
    548 
    549 	cpu = &cpus[cpu_number];
    550 
    551 	/* Now for the FP info */
    552 
    553 	switch (cpu->fpu_class) {
    554 	case FPU_CLASS_NONE :
    555 		strcpy(cpu->fpu_model, "None");
    556 		break;
    557 	case FPU_CLASS_FPE :
    558 		printf("%s: FPE: %s\n", dv->dv_xname, cpu->fpu_model);
    559 		printf("%s: no FP hardware found\n", dv->dv_xname);
    560 		break;
    561 	case FPU_CLASS_FPA :
    562 		printf("%s: FPE: %s\n", dv->dv_xname, cpu->fpu_model);
    563 		if (cpu->fpu_type == FPU_TYPE_FPA11) {
    564 			strcpy(cpu->fpu_model, "FPA11");
    565 			printf("%s: FPA11 found\n", dv->dv_xname);
    566 		} else {
    567 			strcpy(cpu->fpu_model, "FPA");
    568 			printf("%s: FPA10 found\n", dv->dv_xname);
    569 		}
    570 		if ((cpu->fpu_flags & 4) == 0)
    571 			strcat(cpu->fpu_model, "");
    572 		else
    573 			strcat(cpu->fpu_model, " clk/2");
    574 		break;
    575 	case FPU_CLASS_FPU :
    576 		sprintf(cpu->fpu_model, "Unknown FPU (ID=%02x)\n",
    577 		    cpu->fpu_type);
    578 		printf("%s: %s\n", dv->dv_xname, cpu->fpu_model);
    579 		break;
    580 	}
    581 }
    582 
    583 /* End of cpu.c */
    584