|
28 | 28 | #include <asm/spram.h> |
29 | 29 | #include <linux/uaccess.h> |
30 | 30 |
|
| 31 | +#include "fpu-probe.h" |
| 32 | + |
31 | 33 | #include <asm/mach-loongson64/cpucfg-emul.h> |
32 | 34 |
|
33 | 35 | /* Hardware capabilities */ |
34 | 36 | unsigned int elf_hwcap __read_mostly; |
35 | 37 | EXPORT_SYMBOL_GPL(elf_hwcap); |
36 | 38 |
|
37 | | -#ifdef CONFIG_MIPS_FP_SUPPORT |
38 | | - |
39 | | -/* |
40 | | - * Get the FPU Implementation/Revision. |
41 | | - */ |
42 | | -static inline unsigned long cpu_get_fpu_id(void) |
43 | | -{ |
44 | | - unsigned long tmp, fpu_id; |
45 | | - |
46 | | - tmp = read_c0_status(); |
47 | | - __enable_fpu(FPU_AS_IS); |
48 | | - fpu_id = read_32bit_cp1_register(CP1_REVISION); |
49 | | - write_c0_status(tmp); |
50 | | - return fpu_id; |
51 | | -} |
52 | | - |
53 | | -/* |
54 | | - * Check if the CPU has an external FPU. |
55 | | - */ |
56 | | -static inline int __cpu_has_fpu(void) |
57 | | -{ |
58 | | - return (cpu_get_fpu_id() & FPIR_IMP_MASK) != FPIR_IMP_NONE; |
59 | | -} |
60 | | - |
61 | | -/* |
62 | | - * Determine the FCSR mask for FPU hardware. |
63 | | - */ |
64 | | -static inline void cpu_set_fpu_fcsr_mask(struct cpuinfo_mips *c) |
65 | | -{ |
66 | | - unsigned long sr, mask, fcsr, fcsr0, fcsr1; |
67 | | - |
68 | | - fcsr = c->fpu_csr31; |
69 | | - mask = FPU_CSR_ALL_X | FPU_CSR_ALL_E | FPU_CSR_ALL_S | FPU_CSR_RM; |
70 | | - |
71 | | - sr = read_c0_status(); |
72 | | - __enable_fpu(FPU_AS_IS); |
73 | | - |
74 | | - fcsr0 = fcsr & mask; |
75 | | - write_32bit_cp1_register(CP1_STATUS, fcsr0); |
76 | | - fcsr0 = read_32bit_cp1_register(CP1_STATUS); |
77 | | - |
78 | | - fcsr1 = fcsr | ~mask; |
79 | | - write_32bit_cp1_register(CP1_STATUS, fcsr1); |
80 | | - fcsr1 = read_32bit_cp1_register(CP1_STATUS); |
81 | | - |
82 | | - write_32bit_cp1_register(CP1_STATUS, fcsr); |
83 | | - |
84 | | - write_c0_status(sr); |
85 | | - |
86 | | - c->fpu_msk31 = ~(fcsr0 ^ fcsr1) & ~mask; |
87 | | -} |
88 | | - |
89 | | -/* |
90 | | - * Determine the IEEE 754 NaN encodings and ABS.fmt/NEG.fmt execution modes |
91 | | - * supported by FPU hardware. |
92 | | - */ |
93 | | -static void cpu_set_fpu_2008(struct cpuinfo_mips *c) |
94 | | -{ |
95 | | - if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1 | |
96 | | - MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 | |
97 | | - MIPS_CPU_ISA_M32R5 | MIPS_CPU_ISA_M64R5 | |
98 | | - MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6)) { |
99 | | - unsigned long sr, fir, fcsr, fcsr0, fcsr1; |
100 | | - |
101 | | - sr = read_c0_status(); |
102 | | - __enable_fpu(FPU_AS_IS); |
103 | | - |
104 | | - fir = read_32bit_cp1_register(CP1_REVISION); |
105 | | - if (fir & MIPS_FPIR_HAS2008) { |
106 | | - fcsr = read_32bit_cp1_register(CP1_STATUS); |
107 | | - |
108 | | - /* |
109 | | - * MAC2008 toolchain never landed in real world, so we're only |
110 | | - * testing wether it can be disabled and don't try to enabled |
111 | | - * it. |
112 | | - */ |
113 | | - fcsr0 = fcsr & ~(FPU_CSR_ABS2008 | FPU_CSR_NAN2008 | FPU_CSR_MAC2008); |
114 | | - write_32bit_cp1_register(CP1_STATUS, fcsr0); |
115 | | - fcsr0 = read_32bit_cp1_register(CP1_STATUS); |
116 | | - |
117 | | - fcsr1 = fcsr | FPU_CSR_ABS2008 | FPU_CSR_NAN2008; |
118 | | - write_32bit_cp1_register(CP1_STATUS, fcsr1); |
119 | | - fcsr1 = read_32bit_cp1_register(CP1_STATUS); |
120 | | - |
121 | | - write_32bit_cp1_register(CP1_STATUS, fcsr); |
122 | | - |
123 | | - if (c->isa_level & (MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2)) { |
124 | | - /* |
125 | | - * The bit for MAC2008 might be reused by R6 in future, |
126 | | - * so we only test for R2-R5. |
127 | | - */ |
128 | | - if (fcsr0 & FPU_CSR_MAC2008) |
129 | | - c->options |= MIPS_CPU_MAC_2008_ONLY; |
130 | | - } |
131 | | - |
132 | | - if (!(fcsr0 & FPU_CSR_NAN2008)) |
133 | | - c->options |= MIPS_CPU_NAN_LEGACY; |
134 | | - if (fcsr1 & FPU_CSR_NAN2008) |
135 | | - c->options |= MIPS_CPU_NAN_2008; |
136 | | - |
137 | | - if ((fcsr0 ^ fcsr1) & FPU_CSR_ABS2008) |
138 | | - c->fpu_msk31 &= ~FPU_CSR_ABS2008; |
139 | | - else |
140 | | - c->fpu_csr31 |= fcsr & FPU_CSR_ABS2008; |
141 | | - |
142 | | - if ((fcsr0 ^ fcsr1) & FPU_CSR_NAN2008) |
143 | | - c->fpu_msk31 &= ~FPU_CSR_NAN2008; |
144 | | - else |
145 | | - c->fpu_csr31 |= fcsr & FPU_CSR_NAN2008; |
146 | | - } else { |
147 | | - c->options |= MIPS_CPU_NAN_LEGACY; |
148 | | - } |
149 | | - |
150 | | - write_c0_status(sr); |
151 | | - } else { |
152 | | - c->options |= MIPS_CPU_NAN_LEGACY; |
153 | | - } |
154 | | -} |
155 | | - |
156 | | -/* |
157 | | - * IEEE 754 conformance mode to use. Affects the NaN encoding and the |
158 | | - * ABS.fmt/NEG.fmt execution mode. |
159 | | - */ |
160 | | -static enum { STRICT, LEGACY, STD2008, RELAXED } ieee754 = STRICT; |
161 | | - |
162 | | -/* |
163 | | - * Set the IEEE 754 NaN encodings and the ABS.fmt/NEG.fmt execution modes |
164 | | - * to support by the FPU emulator according to the IEEE 754 conformance |
165 | | - * mode selected. Note that "relaxed" straps the emulator so that it |
166 | | - * allows 2008-NaN binaries even for legacy processors. |
167 | | - */ |
168 | | -static void cpu_set_nofpu_2008(struct cpuinfo_mips *c) |
169 | | -{ |
170 | | - c->options &= ~(MIPS_CPU_NAN_2008 | MIPS_CPU_NAN_LEGACY); |
171 | | - c->fpu_csr31 &= ~(FPU_CSR_ABS2008 | FPU_CSR_NAN2008); |
172 | | - c->fpu_msk31 &= ~(FPU_CSR_ABS2008 | FPU_CSR_NAN2008); |
173 | | - |
174 | | - switch (ieee754) { |
175 | | - case STRICT: |
176 | | - if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1 | |
177 | | - MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 | |
178 | | - MIPS_CPU_ISA_M32R5 | MIPS_CPU_ISA_M64R5 | |
179 | | - MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6)) { |
180 | | - c->options |= MIPS_CPU_NAN_2008 | MIPS_CPU_NAN_LEGACY; |
181 | | - } else { |
182 | | - c->options |= MIPS_CPU_NAN_LEGACY; |
183 | | - c->fpu_msk31 |= FPU_CSR_ABS2008 | FPU_CSR_NAN2008; |
184 | | - } |
185 | | - break; |
186 | | - case LEGACY: |
187 | | - c->options |= MIPS_CPU_NAN_LEGACY; |
188 | | - c->fpu_msk31 |= FPU_CSR_ABS2008 | FPU_CSR_NAN2008; |
189 | | - break; |
190 | | - case STD2008: |
191 | | - c->options |= MIPS_CPU_NAN_2008; |
192 | | - c->fpu_csr31 |= FPU_CSR_ABS2008 | FPU_CSR_NAN2008; |
193 | | - c->fpu_msk31 |= FPU_CSR_ABS2008 | FPU_CSR_NAN2008; |
194 | | - break; |
195 | | - case RELAXED: |
196 | | - c->options |= MIPS_CPU_NAN_2008 | MIPS_CPU_NAN_LEGACY; |
197 | | - break; |
198 | | - } |
199 | | -} |
200 | | - |
201 | | -/* |
202 | | - * Override the IEEE 754 NaN encoding and ABS.fmt/NEG.fmt execution mode |
203 | | - * according to the "ieee754=" parameter. |
204 | | - */ |
205 | | -static void cpu_set_nan_2008(struct cpuinfo_mips *c) |
206 | | -{ |
207 | | - switch (ieee754) { |
208 | | - case STRICT: |
209 | | - mips_use_nan_legacy = !!cpu_has_nan_legacy; |
210 | | - mips_use_nan_2008 = !!cpu_has_nan_2008; |
211 | | - break; |
212 | | - case LEGACY: |
213 | | - mips_use_nan_legacy = !!cpu_has_nan_legacy; |
214 | | - mips_use_nan_2008 = !cpu_has_nan_legacy; |
215 | | - break; |
216 | | - case STD2008: |
217 | | - mips_use_nan_legacy = !cpu_has_nan_2008; |
218 | | - mips_use_nan_2008 = !!cpu_has_nan_2008; |
219 | | - break; |
220 | | - case RELAXED: |
221 | | - mips_use_nan_legacy = true; |
222 | | - mips_use_nan_2008 = true; |
223 | | - break; |
224 | | - } |
225 | | -} |
226 | | - |
227 | | -/* |
228 | | - * IEEE 754 NaN encoding and ABS.fmt/NEG.fmt execution mode override |
229 | | - * settings: |
230 | | - * |
231 | | - * strict: accept binaries that request a NaN encoding supported by the FPU |
232 | | - * legacy: only accept legacy-NaN binaries |
233 | | - * 2008: only accept 2008-NaN binaries |
234 | | - * relaxed: accept any binaries regardless of whether supported by the FPU |
235 | | - */ |
236 | | -static int __init ieee754_setup(char *s) |
237 | | -{ |
238 | | - if (!s) |
239 | | - return -1; |
240 | | - else if (!strcmp(s, "strict")) |
241 | | - ieee754 = STRICT; |
242 | | - else if (!strcmp(s, "legacy")) |
243 | | - ieee754 = LEGACY; |
244 | | - else if (!strcmp(s, "2008")) |
245 | | - ieee754 = STD2008; |
246 | | - else if (!strcmp(s, "relaxed")) |
247 | | - ieee754 = RELAXED; |
248 | | - else |
249 | | - return -1; |
250 | | - |
251 | | - if (!(boot_cpu_data.options & MIPS_CPU_FPU)) |
252 | | - cpu_set_nofpu_2008(&boot_cpu_data); |
253 | | - cpu_set_nan_2008(&boot_cpu_data); |
254 | | - |
255 | | - return 0; |
256 | | -} |
257 | | - |
258 | | -early_param("ieee754", ieee754_setup); |
259 | | - |
260 | | -/* |
261 | | - * Set the FIR feature flags for the FPU emulator. |
262 | | - */ |
263 | | -static void cpu_set_nofpu_id(struct cpuinfo_mips *c) |
264 | | -{ |
265 | | - u32 value; |
266 | | - |
267 | | - value = 0; |
268 | | - if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1 | |
269 | | - MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 | |
270 | | - MIPS_CPU_ISA_M32R5 | MIPS_CPU_ISA_M64R5 | |
271 | | - MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6)) |
272 | | - value |= MIPS_FPIR_D | MIPS_FPIR_S; |
273 | | - if (c->isa_level & (MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 | |
274 | | - MIPS_CPU_ISA_M32R5 | MIPS_CPU_ISA_M64R5 | |
275 | | - MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6)) |
276 | | - value |= MIPS_FPIR_F64 | MIPS_FPIR_L | MIPS_FPIR_W; |
277 | | - if (c->options & MIPS_CPU_NAN_2008) |
278 | | - value |= MIPS_FPIR_HAS2008; |
279 | | - c->fpu_id = value; |
280 | | -} |
281 | | - |
282 | | -/* Determined FPU emulator mask to use for the boot CPU with "nofpu". */ |
283 | | -static unsigned int mips_nofpu_msk31; |
284 | | - |
285 | | -/* |
286 | | - * Set options for FPU hardware. |
287 | | - */ |
288 | | -static void cpu_set_fpu_opts(struct cpuinfo_mips *c) |
289 | | -{ |
290 | | - c->fpu_id = cpu_get_fpu_id(); |
291 | | - mips_nofpu_msk31 = c->fpu_msk31; |
292 | | - |
293 | | - if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1 | |
294 | | - MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 | |
295 | | - MIPS_CPU_ISA_M32R5 | MIPS_CPU_ISA_M64R5 | |
296 | | - MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6)) { |
297 | | - if (c->fpu_id & MIPS_FPIR_3D) |
298 | | - c->ases |= MIPS_ASE_MIPS3D; |
299 | | - if (c->fpu_id & MIPS_FPIR_UFRP) |
300 | | - c->options |= MIPS_CPU_UFR; |
301 | | - if (c->fpu_id & MIPS_FPIR_FREP) |
302 | | - c->options |= MIPS_CPU_FRE; |
303 | | - } |
304 | | - |
305 | | - cpu_set_fpu_fcsr_mask(c); |
306 | | - cpu_set_fpu_2008(c); |
307 | | - cpu_set_nan_2008(c); |
308 | | -} |
309 | | - |
310 | | -/* |
311 | | - * Set options for the FPU emulator. |
312 | | - */ |
313 | | -static void cpu_set_nofpu_opts(struct cpuinfo_mips *c) |
314 | | -{ |
315 | | - c->options &= ~MIPS_CPU_FPU; |
316 | | - c->fpu_msk31 = mips_nofpu_msk31; |
317 | | - |
318 | | - cpu_set_nofpu_2008(c); |
319 | | - cpu_set_nan_2008(c); |
320 | | - cpu_set_nofpu_id(c); |
321 | | -} |
322 | | - |
323 | | -static int mips_fpu_disabled; |
324 | | - |
325 | | -static int __init fpu_disable(char *s) |
326 | | -{ |
327 | | - cpu_set_nofpu_opts(&boot_cpu_data); |
328 | | - mips_fpu_disabled = 1; |
329 | | - |
330 | | - return 1; |
331 | | -} |
332 | | - |
333 | | -__setup("nofpu", fpu_disable); |
334 | | - |
335 | | -#else /* !CONFIG_MIPS_FP_SUPPORT */ |
336 | | - |
337 | | -#define mips_fpu_disabled 1 |
338 | | - |
339 | | -static inline unsigned long cpu_get_fpu_id(void) |
340 | | -{ |
341 | | - return FPIR_IMP_NONE; |
342 | | -} |
343 | | - |
344 | | -static inline int __cpu_has_fpu(void) |
345 | | -{ |
346 | | - return 0; |
347 | | -} |
348 | | - |
349 | | -static void cpu_set_fpu_opts(struct cpuinfo_mips *c) |
350 | | -{ |
351 | | - /* no-op */ |
352 | | -} |
353 | | - |
354 | | -static void cpu_set_nofpu_opts(struct cpuinfo_mips *c) |
355 | | -{ |
356 | | - /* no-op */ |
357 | | -} |
358 | | - |
359 | | -#endif /* CONFIG_MIPS_FP_SUPPORT */ |
360 | | - |
361 | 39 | static inline unsigned long cpu_get_msa_id(void) |
362 | 40 | { |
363 | 41 | unsigned long status, msa_id; |
|
0 commit comments