cpu.c revision 1.10 1 1.10 thorpej /* $NetBSD: cpu.c,v 1.10 2001/11/23 21:18:30 thorpej Exp $ */
2 1.1 matt
3 1.1 matt /*
4 1.1 matt * Copyright (c) 1995 Mark Brinicombe.
5 1.1 matt * Copyright (c) 1995 Brini.
6 1.1 matt * All rights reserved.
7 1.1 matt *
8 1.1 matt * Redistribution and use in source and binary forms, with or without
9 1.1 matt * modification, are permitted provided that the following conditions
10 1.1 matt * are met:
11 1.1 matt * 1. Redistributions of source code must retain the above copyright
12 1.1 matt * notice, this list of conditions and the following disclaimer.
13 1.1 matt * 2. Redistributions in binary form must reproduce the above copyright
14 1.1 matt * notice, this list of conditions and the following disclaimer in the
15 1.1 matt * documentation and/or other materials provided with the distribution.
16 1.1 matt * 3. All advertising materials mentioning features or use of this software
17 1.1 matt * must display the following acknowledgement:
18 1.1 matt * This product includes software developed by Brini.
19 1.1 matt * 4. The name of the company nor the name of the author may be used to
20 1.1 matt * endorse or promote products derived from this software without specific
21 1.1 matt * prior written permission.
22 1.1 matt *
23 1.1 matt * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
24 1.1 matt * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 1.1 matt * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 1.1 matt * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27 1.1 matt * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 1.1 matt * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29 1.1 matt * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 1.1 matt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 1.1 matt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 1.1 matt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 1.1 matt * SUCH DAMAGE.
34 1.1 matt *
35 1.1 matt * RiscBSD kernel project
36 1.1 matt *
37 1.1 matt * cpu.c
38 1.1 matt *
39 1.1 matt * Probing and configuration for the master cpu
40 1.1 matt *
41 1.1 matt * Created : 10/10/95
42 1.1 matt */
43 1.1 matt
44 1.1 matt #include "opt_armfpe.h"
45 1.1 matt #include "opt_cputypes.h"
46 1.1 matt
47 1.1 matt #include <sys/param.h>
48 1.1 matt #include <sys/systm.h>
49 1.1 matt #include <sys/malloc.h>
50 1.1 matt #include <sys/device.h>
51 1.1 matt #include <sys/proc.h>
52 1.1 matt #include <uvm/uvm_extern.h>
53 1.1 matt #include <machine/conf.h>
54 1.1 matt #include <machine/cpu.h>
55 1.10 thorpej #include <arm/undefined.h>
56 1.10 thorpej
57 1.10 thorpej #include <arm/cpus.h>
58 1.1 matt
59 1.1 matt #ifdef ARMFPE
60 1.1 matt #include <machine/bootconfig.h> /* For boot args */
61 1.1 matt #include <arm32/fpe-arm/armfpe.h>
62 1.1 matt #endif /* ARMFPE */
63 1.1 matt
64 1.1 matt cpu_t cpus[MAX_CPUS];
65 1.1 matt
66 1.1 matt char cpu_model[64];
67 1.1 matt volatile int undefined_test; /* Used for FPA test */
68 1.1 matt extern int cpuctrl; /* cpu control register value */
69 1.1 matt
70 1.1 matt /* Prototypes */
71 1.1 matt void identify_master_cpu __P((struct device *dv, int cpu_number));
72 1.1 matt void identify_arm_cpu __P((struct device *dv, int cpu_number));
73 1.1 matt void identify_arm_fpu __P((struct device *dv, int cpu_number));
74 1.5 chris int fpa_test __P((u_int, u_int, trapframe_t *, int));
75 1.5 chris int fpa_handler __P((u_int, u_int, trapframe_t *, int));
76 1.1 matt
77 1.1 matt /*
78 1.1 matt * void cpusattach(struct device *parent, struct device *dev, void *aux)
79 1.1 matt *
80 1.1 matt * Attach the main cpu
81 1.1 matt */
82 1.1 matt
83 1.1 matt void
84 1.1 matt cpu_attach(dv)
85 1.1 matt struct device *dv;
86 1.1 matt {
87 1.1 matt identify_master_cpu(dv, CPU_MASTER);
88 1.1 matt }
89 1.1 matt
90 1.1 matt /*
91 1.1 matt * Used to test for an FPA. The following function is installed as a coproc1
92 1.1 matt * handler on the undefined instruction vector and then we issue a FPA
93 1.1 matt * instruction. If undefined_test is non zero then the FPA did not handle
94 1.1 matt * the instruction so must be absent.
95 1.1 matt */
96 1.1 matt
97 1.1 matt int
98 1.5 chris fpa_test(address, instruction, frame, fault_code)
99 1.1 matt u_int address;
100 1.1 matt u_int instruction;
101 1.1 matt trapframe_t *frame;
102 1.5 chris int fault_code;
103 1.1 matt {
104 1.1 matt
105 1.1 matt frame->tf_pc += INSN_SIZE;
106 1.1 matt ++undefined_test;
107 1.1 matt return(0);
108 1.1 matt }
109 1.1 matt
110 1.1 matt /*
111 1.1 matt * If an FPA was found then this function is installed as the coproc1 handler
112 1.1 matt * on the undefined instruction vector. Currently we don't support FPA's
113 1.1 matt * so this just triggers an exception.
114 1.1 matt */
115 1.1 matt
116 1.1 matt int
117 1.1 matt fpa_handler(address, instruction, frame, fault_code)
118 1.1 matt u_int address;
119 1.1 matt u_int instruction;
120 1.1 matt trapframe_t *frame;
121 1.1 matt int fault_code;
122 1.1 matt {
123 1.1 matt u_int fpsr;
124 1.1 matt
125 1.1 matt __asm __volatile("stmfd sp!, {r0}; .word 0xee300110; mov %0, r0; ldmfd sp!, {r0}" : "=r" (fpsr));
126 1.1 matt
127 1.1 matt printf("FPA exception: fpsr = %08x\n", fpsr);
128 1.1 matt
129 1.1 matt return(1);
130 1.1 matt }
131 1.1 matt
132 1.1 matt
133 1.1 matt /*
134 1.1 matt * Identify the master (boot) CPU
135 1.1 matt * This also probes for an FPU and will install an FPE if necessary
136 1.1 matt */
137 1.1 matt
138 1.1 matt void
139 1.1 matt identify_master_cpu(dv, cpu_number)
140 1.1 matt struct device *dv;
141 1.1 matt int cpu_number;
142 1.1 matt {
143 1.1 matt u_int fpsr;
144 1.1 matt void *uh;
145 1.1 matt
146 1.1 matt cpus[cpu_number].cpu_ctrl = cpuctrl;
147 1.1 matt
148 1.1 matt /* Get the cpu ID from coprocessor 15 */
149 1.1 matt
150 1.1 matt cpus[cpu_number].cpu_id = cpu_id();
151 1.1 matt
152 1.1 matt identify_arm_cpu(dv, cpu_number);
153 1.1 matt strcpy(cpu_model, cpus[cpu_number].cpu_model);
154 1.1 matt
155 1.1 matt if (cpus[CPU_MASTER].cpu_class == CPU_CLASS_SA1
156 1.1 matt && (cpus[CPU_MASTER].cpu_id & CPU_ID_REVISION_MASK) < 3) {
157 1.1 matt printf("%s: SA-110 with bugged STM^ instruction\n",
158 1.1 matt dv->dv_xname);
159 1.1 matt }
160 1.1 matt
161 1.1 matt #ifdef CPU_ARM8
162 1.1 matt if ((cpus[CPU_MASTER].cpu_id & CPU_ID_CPU_MASK) == CPU_ID_ARM810) {
163 1.1 matt int clock = arm8_clock_config(0, 0);
164 1.1 matt char *fclk;
165 1.1 matt printf("%s: ARM810 cp15=%02x", dv->dv_xname, clock);
166 1.1 matt printf(" clock:%s", (clock & 1) ? " dynamic" : "");
167 1.1 matt printf("%s", (clock & 2) ? " sync" : "");
168 1.1 matt switch ((clock >> 2) & 3) {
169 1.1 matt case 0 :
170 1.1 matt fclk = "bus clock";
171 1.1 matt break;
172 1.1 matt case 1 :
173 1.1 matt fclk = "ref clock";
174 1.1 matt break;
175 1.1 matt case 3 :
176 1.1 matt fclk = "pll";
177 1.1 matt break;
178 1.1 matt default :
179 1.1 matt fclk = "illegal";
180 1.1 matt break;
181 1.1 matt }
182 1.1 matt printf(" fclk source=%s\n", fclk);
183 1.1 matt }
184 1.1 matt #endif
185 1.1 matt
186 1.1 matt /*
187 1.1 matt * Ok now we test for an FPA
188 1.1 matt * At this point no floating point emulator has been installed.
189 1.1 matt * This means any FP instruction will cause undefined exception.
190 1.1 matt * We install a temporay coproc 1 handler which will modify
191 1.1 matt * undefined_test if it is called.
192 1.1 matt * We then try to read the FP status register. If undefined_test
193 1.1 matt * has been decremented then the instruction was not handled by
194 1.1 matt * an FPA so we know the FPA is missing. If undefined_test is
195 1.1 matt * still 1 then we know the instruction was handled by an FPA.
196 1.1 matt * We then remove our test handler and look at the
197 1.1 matt * FP status register for identification.
198 1.1 matt */
199 1.1 matt
200 1.1 matt uh = install_coproc_handler(FP_COPROC, fpa_test);
201 1.1 matt
202 1.1 matt undefined_test = 0;
203 1.1 matt
204 1.1 matt __asm __volatile("stmfd sp!, {r0}; .word 0xee300110; mov %0, r0; ldmfd sp!, {r0}" : "=r" (fpsr));
205 1.1 matt
206 1.1 matt remove_coproc_handler(uh);
207 1.1 matt
208 1.1 matt if (undefined_test == 0) {
209 1.1 matt cpus[cpu_number].fpu_type = (fpsr >> 24);
210 1.1 matt switch (fpsr >> 24) {
211 1.1 matt case 0x81 :
212 1.1 matt cpus[cpu_number].fpu_class = FPU_CLASS_FPA;
213 1.1 matt break;
214 1.1 matt
215 1.1 matt default :
216 1.1 matt cpus[cpu_number].fpu_class = FPU_CLASS_FPU;
217 1.1 matt break;
218 1.1 matt }
219 1.1 matt cpus[cpu_number].fpu_flags = 0;
220 1.1 matt install_coproc_handler(FP_COPROC, fpa_handler);
221 1.1 matt } else {
222 1.1 matt cpus[cpu_number].fpu_class = FPU_CLASS_NONE;
223 1.1 matt cpus[cpu_number].fpu_flags = 0;
224 1.1 matt
225 1.1 matt /*
226 1.1 matt * Ok if ARMFPE is defined and the boot options request the
227 1.1 matt * ARM FPE then it will be installed as the FPE.
228 1.1 matt * This is just while I work on integrating the new FPE.
229 1.1 matt * It means the new FPE gets installed if compiled int (ARMFPE
230 1.1 matt * defined) and also gives me a on/off option when I boot in
231 1.1 matt * case the new FPE is causing panics.
232 1.1 matt */
233 1.1 matt
234 1.1 matt #ifdef ARMFPE
235 1.1 matt if (boot_args) {
236 1.2 bjh21 int usearmfpe = 1;
237 1.1 matt
238 1.2 bjh21 get_bootconf_option(boot_args, "armfpe",
239 1.2 bjh21 BOOTOPT_TYPE_BOOLEAN, &usearmfpe);
240 1.2 bjh21 if (usearmfpe) {
241 1.1 matt if (initialise_arm_fpe(&cpus[cpu_number]) != 0)
242 1.1 matt identify_arm_fpu(dv, cpu_number);
243 1.1 matt }
244 1.1 matt }
245 1.1 matt
246 1.1 matt #endif
247 1.1 matt }
248 1.1 matt
249 1.1 matt identify_arm_fpu(dv, cpu_number);
250 1.1 matt }
251 1.1 matt
252 1.1 matt struct cpuidtab {
253 1.1 matt u_int32_t cpuid;
254 1.1 matt enum cpu_class cpu_class;
255 1.9 thorpej const char *cpu_name;
256 1.1 matt };
257 1.1 matt
258 1.1 matt const struct cpuidtab cpuids[] = {
259 1.1 matt { CPU_ID_ARM2, CPU_CLASS_ARM2, "ARM2" },
260 1.1 matt { CPU_ID_ARM250, CPU_CLASS_ARM2AS, "ARM250" },
261 1.1 matt { CPU_ID_ARM3, CPU_CLASS_ARM3, "ARM3" },
262 1.1 matt { CPU_ID_ARM600, CPU_CLASS_ARM6, "ARM600" },
263 1.1 matt { CPU_ID_ARM610, CPU_CLASS_ARM6, "ARM610" },
264 1.1 matt { CPU_ID_ARM620, CPU_CLASS_ARM6, "ARM620" },
265 1.1 matt { CPU_ID_ARM700, CPU_CLASS_ARM7, "ARM700" },
266 1.1 matt { CPU_ID_ARM710, CPU_CLASS_ARM7, "ARM710" },
267 1.1 matt { CPU_ID_ARM7500, CPU_CLASS_ARM7, "ARM7500" },
268 1.1 matt { CPU_ID_ARM710A, CPU_CLASS_ARM7, "ARM710a" },
269 1.1 matt { CPU_ID_ARM7500FE, CPU_CLASS_ARM7, "ARM7500FE" },
270 1.1 matt { CPU_ID_ARM710T, CPU_CLASS_ARM7TDMI, "ARM710T" },
271 1.1 matt { CPU_ID_ARM720T, CPU_CLASS_ARM7TDMI, "ARM720T" },
272 1.1 matt { CPU_ID_ARM740T8K, CPU_CLASS_ARM7TDMI, "ARM740T (8 KB cache)" },
273 1.1 matt { CPU_ID_ARM740T4K, CPU_CLASS_ARM7TDMI, "ARM740T (4 KB cache)" },
274 1.1 matt { CPU_ID_ARM810, CPU_CLASS_ARM8, "ARM810" },
275 1.1 matt { CPU_ID_ARM920T, CPU_CLASS_ARM9TDMI, "ARM920T" },
276 1.1 matt { CPU_ID_ARM922T, CPU_CLASS_ARM9TDMI, "ARM922T" },
277 1.1 matt { CPU_ID_ARM940T, CPU_CLASS_ARM9TDMI, "ARM940T" },
278 1.1 matt { CPU_ID_ARM946ES, CPU_CLASS_ARM9ES, "ARM946E-S" },
279 1.1 matt { CPU_ID_ARM966ES, CPU_CLASS_ARM9ES, "ARM966E-S" },
280 1.6 rearnsha { CPU_ID_ARM966ESR1, CPU_CLASS_ARM9ES, "ARM966E-S" },
281 1.1 matt { CPU_ID_SA110, CPU_CLASS_SA1, "SA-110" },
282 1.1 matt { CPU_ID_SA1100, CPU_CLASS_SA1, "SA-1100" },
283 1.1 matt { CPU_ID_SA1110, CPU_CLASS_SA1, "SA-1110" },
284 1.8 thorpej { CPU_ID_I80200, CPU_CLASS_XSCALE, "i80200" },
285 1.1 matt { 0, CPU_CLASS_NONE, NULL }
286 1.1 matt };
287 1.1 matt
288 1.1 matt struct cpu_classtab {
289 1.9 thorpej const char *class_name;
290 1.9 thorpej const char *class_option;
291 1.1 matt };
292 1.1 matt
293 1.1 matt const struct cpu_classtab cpu_classes[] = {
294 1.6 rearnsha { "unknown", NULL }, /* CPU_CLASS_NONE */
295 1.6 rearnsha { "ARM2", "CPU_ARM2" }, /* CPU_CLASS_ARM2 */
296 1.6 rearnsha { "ARM2as", "CPU_ARM250" }, /* CPU_CLASS_ARM2AS */
297 1.6 rearnsha { "ARM3", "CPU_ARM3" }, /* CPU_CLASS_ARM3 */
298 1.6 rearnsha { "ARM6", "CPU_ARM6" }, /* CPU_CLASS_ARM6 */
299 1.6 rearnsha { "ARM7", "CPU_ARM7" }, /* CPU_CLASS_ARM7 */
300 1.6 rearnsha { "ARM7TDMI", "CPU_ARM7TDMI" }, /* CPU_CLASS_ARM7TDMI */
301 1.6 rearnsha { "ARM8", "CPU_ARM8" }, /* CPU_CLASS_ARM8 */
302 1.6 rearnsha { "ARM9TDMI", NULL }, /* CPU_CLASS_ARM9TDMI */
303 1.6 rearnsha { "ARM9E-S", NULL }, /* CPU_CLASS_ARM9ES */
304 1.6 rearnsha { "SA-1", "CPU_SA110" }, /* CPU_CLASS_SA1 */
305 1.7 thorpej { "XScale", "CPU_XSCALE" }, /* CPU_CLASS_XSCALE */
306 1.1 matt };
307 1.1 matt
308 1.1 matt /*
309 1.1 matt * Report the type of the specifed arm processor. This uses the generic and
310 1.1 matt * arm specific information in the cpu structure to identify the processor.
311 1.1 matt * The remaining fields in the cpu structure are filled in appropriately.
312 1.1 matt */
313 1.1 matt
314 1.1 matt void
315 1.1 matt identify_arm_cpu(dv, cpu_number)
316 1.1 matt struct device *dv;
317 1.1 matt int cpu_number;
318 1.1 matt {
319 1.1 matt cpu_t *cpu;
320 1.1 matt u_int cpuid;
321 1.1 matt int i;
322 1.1 matt
323 1.1 matt cpu = &cpus[cpu_number];
324 1.1 matt cpuid = cpu->cpu_id;
325 1.1 matt
326 1.1 matt if (cpuid == 0) {
327 1.1 matt printf("Processor failed probe - no CPU ID\n");
328 1.1 matt return;
329 1.1 matt }
330 1.1 matt
331 1.1 matt for (i = 0; cpuids[i].cpuid != 0; i++)
332 1.1 matt if (cpuids[i].cpuid == (cpuid & CPU_ID_CPU_MASK)) {
333 1.1 matt cpu->cpu_class = cpuids[i].cpu_class;
334 1.1 matt sprintf(cpu->cpu_model, "%s rev %d (%s core)",
335 1.1 matt cpuids[i].cpu_name, cpuid & CPU_ID_REVISION_MASK,
336 1.1 matt cpu_classes[cpu->cpu_class].class_name);
337 1.1 matt break;
338 1.1 matt }
339 1.1 matt
340 1.1 matt if (cpuids[i].cpuid == 0)
341 1.1 matt sprintf(cpu->cpu_model, "unknown CPU (ID = 0x%x)", cpuid);
342 1.1 matt
343 1.1 matt switch (cpu->cpu_class) {
344 1.1 matt case CPU_CLASS_ARM6:
345 1.1 matt case CPU_CLASS_ARM7:
346 1.3 chris case CPU_CLASS_ARM7TDMI:
347 1.1 matt case CPU_CLASS_ARM8:
348 1.1 matt if ((cpu->cpu_ctrl & CPU_CONTROL_IDC_ENABLE) == 0)
349 1.1 matt strcat(cpu->cpu_model, " IDC disabled");
350 1.1 matt else
351 1.1 matt strcat(cpu->cpu_model, " IDC enabled");
352 1.1 matt break;
353 1.6 rearnsha case CPU_CLASS_ARM9TDMI:
354 1.1 matt case CPU_CLASS_SA1:
355 1.4 matt case CPU_CLASS_XSCALE:
356 1.1 matt if ((cpu->cpu_ctrl & CPU_CONTROL_DC_ENABLE) == 0)
357 1.1 matt strcat(cpu->cpu_model, " DC disabled");
358 1.1 matt else
359 1.1 matt strcat(cpu->cpu_model, " DC enabled");
360 1.1 matt if ((cpu->cpu_ctrl & CPU_CONTROL_IC_ENABLE) == 0)
361 1.1 matt strcat(cpu->cpu_model, " IC disabled");
362 1.1 matt else
363 1.1 matt strcat(cpu->cpu_model, " IC enabled");
364 1.1 matt break;
365 1.1 matt }
366 1.1 matt if ((cpu->cpu_ctrl & CPU_CONTROL_WBUF_ENABLE) == 0)
367 1.1 matt strcat(cpu->cpu_model, " WB disabled");
368 1.1 matt else
369 1.1 matt strcat(cpu->cpu_model, " WB enabled");
370 1.1 matt
371 1.1 matt if (cpu->cpu_ctrl & CPU_CONTROL_LABT_ENABLE)
372 1.1 matt strcat(cpu->cpu_model, " LABT");
373 1.1 matt else
374 1.1 matt strcat(cpu->cpu_model, " EABT");
375 1.1 matt
376 1.1 matt if (cpu->cpu_ctrl & CPU_CONTROL_BPRD_ENABLE)
377 1.1 matt strcat(cpu->cpu_model, " branch prediction enabled");
378 1.1 matt
379 1.1 matt /* Print the info */
380 1.1 matt
381 1.1 matt printf(": %s\n", cpu->cpu_model);
382 1.1 matt
383 1.1 matt switch (cpu->cpu_class) {
384 1.1 matt #ifdef CPU_ARM2
385 1.1 matt case CPU_CLASS_ARM2:
386 1.1 matt #endif
387 1.1 matt #ifdef CPU_ARM250
388 1.1 matt case CPU_CLASS_ARM2AS:
389 1.1 matt #endif
390 1.1 matt #ifdef CPU_ARM3
391 1.1 matt case CPU_CLASS_ARM3:
392 1.1 matt #endif
393 1.1 matt #ifdef CPU_ARM6
394 1.1 matt case CPU_CLASS_ARM6:
395 1.1 matt #endif
396 1.1 matt #ifdef CPU_ARM7
397 1.1 matt case CPU_CLASS_ARM7:
398 1.1 matt #endif
399 1.3 chris #ifdef CPU_ARM7TDMI
400 1.3 chris case CPU_CLASS_ARM7TDMI:
401 1.3 chris #endif
402 1.1 matt #ifdef CPU_ARM8
403 1.1 matt case CPU_CLASS_ARM8:
404 1.6 rearnsha #endif
405 1.6 rearnsha #ifdef CPU_ARM9
406 1.6 rearnsha case CPU_CLASS_ARM9TDMI:
407 1.1 matt #endif
408 1.1 matt #ifdef CPU_SA110
409 1.1 matt case CPU_CLASS_SA1:
410 1.4 matt #endif
411 1.4 matt #ifdef CPU_XSCALE
412 1.4 matt case CPU_CLASS_XSCALE:
413 1.1 matt #endif
414 1.1 matt break;
415 1.1 matt default:
416 1.1 matt if (cpu_classes[cpu->cpu_class].class_option != NULL)
417 1.1 matt printf("%s: %s does not fully support this CPU."
418 1.1 matt "\n", dv->dv_xname, ostype);
419 1.1 matt else {
420 1.1 matt printf("%s: This kernel does not fully support "
421 1.1 matt "this CPU.\n", dv->dv_xname);
422 1.1 matt printf("%s: Recompile with \"options %s\" to "
423 1.1 matt "correct this.\n", dv->dv_xname,
424 1.1 matt cpu_classes[cpu->cpu_class].class_option);
425 1.1 matt }
426 1.1 matt break;
427 1.1 matt }
428 1.1 matt
429 1.1 matt }
430 1.1 matt
431 1.1 matt
432 1.1 matt /*
433 1.1 matt * Report the type of the specifed arm fpu. This uses the generic and arm
434 1.1 matt * specific information in the cpu structure to identify the fpu. The
435 1.1 matt * remaining fields in the cpu structure are filled in appropriately.
436 1.1 matt */
437 1.1 matt
438 1.1 matt void
439 1.1 matt identify_arm_fpu(dv, cpu_number)
440 1.1 matt struct device *dv;
441 1.1 matt int cpu_number;
442 1.1 matt {
443 1.1 matt cpu_t *cpu;
444 1.1 matt
445 1.1 matt cpu = &cpus[cpu_number];
446 1.1 matt
447 1.1 matt /* Now for the FP info */
448 1.1 matt
449 1.1 matt switch (cpu->fpu_class) {
450 1.1 matt case FPU_CLASS_NONE :
451 1.1 matt strcpy(cpu->fpu_model, "None");
452 1.1 matt break;
453 1.1 matt case FPU_CLASS_FPE :
454 1.1 matt printf("%s: FPE: %s\n", dv->dv_xname, cpu->fpu_model);
455 1.1 matt printf("%s: no FP hardware found\n", dv->dv_xname);
456 1.1 matt break;
457 1.1 matt case FPU_CLASS_FPA :
458 1.1 matt printf("%s: FPE: %s\n", dv->dv_xname, cpu->fpu_model);
459 1.1 matt if (cpu->fpu_type == FPU_TYPE_FPA11) {
460 1.1 matt strcpy(cpu->fpu_model, "FPA11");
461 1.1 matt printf("%s: FPA11 found\n", dv->dv_xname);
462 1.1 matt } else {
463 1.1 matt strcpy(cpu->fpu_model, "FPA");
464 1.1 matt printf("%s: FPA10 found\n", dv->dv_xname);
465 1.1 matt }
466 1.1 matt if ((cpu->fpu_flags & 4) == 0)
467 1.1 matt strcat(cpu->fpu_model, "");
468 1.1 matt else
469 1.1 matt strcat(cpu->fpu_model, " clk/2");
470 1.1 matt break;
471 1.1 matt case FPU_CLASS_FPU :
472 1.1 matt sprintf(cpu->fpu_model, "Unknown FPU (ID=%02x)\n",
473 1.1 matt cpu->fpu_type);
474 1.1 matt printf("%s: %s\n", dv->dv_xname, cpu->fpu_model);
475 1.1 matt break;
476 1.1 matt }
477 1.1 matt }
478 1.1 matt
479 1.1 matt /* End of cpu.c */
480