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