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