1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Processor capabilities determination functions.
5 * Copyright (C) xxxx the Anonymous
6 * Copyright (C) 1994 - 2006 Ralf Baechle
7 * Copyright (C) 2003, 2004 Maciej W. Rozycki
8 * Copyright (C) 2001, 2004, 2011, 2012 MIPS Technologies, Inc.
11 #include <linux/init.h>
12 #include <linux/kernel.h>
16 #include <asm/cpu-features.h>
17 #include <asm/cpu-type.h>
20 #include <asm/mipsregs.h>
22 #include "fpu-probe.h"
25 * Get the FPU Implementation/Revision.
27 static inline unsigned long cpu_get_fpu_id(void)
29 unsigned long tmp
, fpu_id
;
31 tmp
= read_c0_status();
32 __enable_fpu(FPU_AS_IS
);
33 fpu_id
= read_32bit_cp1_register(CP1_REVISION
);
39 * Check if the CPU has an external FPU.
41 int __cpu_has_fpu(void)
43 return (cpu_get_fpu_id() & FPIR_IMP_MASK
) != FPIR_IMP_NONE
;
47 * Determine the FCSR mask for FPU hardware.
49 static inline void cpu_set_fpu_fcsr_mask(struct cpuinfo_mips
*c
)
51 unsigned long sr
, mask
, fcsr
, fcsr0
, fcsr1
;
54 mask
= FPU_CSR_ALL_X
| FPU_CSR_ALL_E
| FPU_CSR_ALL_S
| FPU_CSR_RM
;
56 sr
= read_c0_status();
57 __enable_fpu(FPU_AS_IS
);
60 write_32bit_cp1_register(CP1_STATUS
, fcsr0
);
61 fcsr0
= read_32bit_cp1_register(CP1_STATUS
);
64 write_32bit_cp1_register(CP1_STATUS
, fcsr1
);
65 fcsr1
= read_32bit_cp1_register(CP1_STATUS
);
67 write_32bit_cp1_register(CP1_STATUS
, fcsr
);
71 c
->fpu_msk31
= ~(fcsr0
^ fcsr1
) & ~mask
;
75 * Determine the IEEE 754 NaN encodings and ABS.fmt/NEG.fmt execution modes
76 * supported by FPU hardware.
78 static void cpu_set_fpu_2008(struct cpuinfo_mips
*c
)
80 if (c
->isa_level
& (MIPS_CPU_ISA_M32R1
| MIPS_CPU_ISA_M64R1
|
81 MIPS_CPU_ISA_M32R2
| MIPS_CPU_ISA_M64R2
|
82 MIPS_CPU_ISA_M32R5
| MIPS_CPU_ISA_M64R5
|
83 MIPS_CPU_ISA_M32R6
| MIPS_CPU_ISA_M64R6
)) {
84 unsigned long sr
, fir
, fcsr
, fcsr0
, fcsr1
;
86 sr
= read_c0_status();
87 __enable_fpu(FPU_AS_IS
);
89 fir
= read_32bit_cp1_register(CP1_REVISION
);
90 if (fir
& MIPS_FPIR_HAS2008
) {
91 fcsr
= read_32bit_cp1_register(CP1_STATUS
);
94 * MAC2008 toolchain never landed in real world, so
95 * we're only testing whether it can be disabled and
96 * don't try to enabled it.
98 fcsr0
= fcsr
& ~(FPU_CSR_ABS2008
| FPU_CSR_NAN2008
|
100 write_32bit_cp1_register(CP1_STATUS
, fcsr0
);
101 fcsr0
= read_32bit_cp1_register(CP1_STATUS
);
103 fcsr1
= fcsr
| FPU_CSR_ABS2008
| FPU_CSR_NAN2008
;
104 write_32bit_cp1_register(CP1_STATUS
, fcsr1
);
105 fcsr1
= read_32bit_cp1_register(CP1_STATUS
);
107 write_32bit_cp1_register(CP1_STATUS
, fcsr
);
109 if (c
->isa_level
& (MIPS_CPU_ISA_M32R2
|
110 MIPS_CPU_ISA_M64R2
)) {
112 * The bit for MAC2008 might be reused by R6
113 * in future, so we only test for R2-R5.
115 if (fcsr0
& FPU_CSR_MAC2008
)
116 c
->options
|= MIPS_CPU_MAC_2008_ONLY
;
119 if (!(fcsr0
& FPU_CSR_NAN2008
))
120 c
->options
|= MIPS_CPU_NAN_LEGACY
;
121 if (fcsr1
& FPU_CSR_NAN2008
)
122 c
->options
|= MIPS_CPU_NAN_2008
;
124 if ((fcsr0
^ fcsr1
) & FPU_CSR_ABS2008
)
125 c
->fpu_msk31
&= ~FPU_CSR_ABS2008
;
127 c
->fpu_csr31
|= fcsr
& FPU_CSR_ABS2008
;
129 if ((fcsr0
^ fcsr1
) & FPU_CSR_NAN2008
)
130 c
->fpu_msk31
&= ~FPU_CSR_NAN2008
;
132 c
->fpu_csr31
|= fcsr
& FPU_CSR_NAN2008
;
134 c
->options
|= MIPS_CPU_NAN_LEGACY
;
139 c
->options
|= MIPS_CPU_NAN_LEGACY
;
144 * IEEE 754 conformance mode to use. Affects the NaN encoding and the
145 * ABS.fmt/NEG.fmt execution mode.
147 static enum { STRICT
, LEGACY
, STD2008
, RELAXED
} ieee754
= STRICT
;
150 * Set the IEEE 754 NaN encodings and the ABS.fmt/NEG.fmt execution modes
151 * to support by the FPU emulator according to the IEEE 754 conformance
152 * mode selected. Note that "relaxed" straps the emulator so that it
153 * allows 2008-NaN binaries even for legacy processors.
155 static void cpu_set_nofpu_2008(struct cpuinfo_mips
*c
)
157 c
->options
&= ~(MIPS_CPU_NAN_2008
| MIPS_CPU_NAN_LEGACY
);
158 c
->fpu_csr31
&= ~(FPU_CSR_ABS2008
| FPU_CSR_NAN2008
);
159 c
->fpu_msk31
&= ~(FPU_CSR_ABS2008
| FPU_CSR_NAN2008
);
163 if (c
->isa_level
& (MIPS_CPU_ISA_M32R1
| MIPS_CPU_ISA_M64R1
|
164 MIPS_CPU_ISA_M32R2
| MIPS_CPU_ISA_M64R2
|
165 MIPS_CPU_ISA_M32R5
| MIPS_CPU_ISA_M64R5
|
166 MIPS_CPU_ISA_M32R6
| MIPS_CPU_ISA_M64R6
)) {
167 c
->options
|= MIPS_CPU_NAN_2008
| MIPS_CPU_NAN_LEGACY
;
169 c
->options
|= MIPS_CPU_NAN_LEGACY
;
170 c
->fpu_msk31
|= FPU_CSR_ABS2008
| FPU_CSR_NAN2008
;
174 c
->options
|= MIPS_CPU_NAN_LEGACY
;
175 c
->fpu_msk31
|= FPU_CSR_ABS2008
| FPU_CSR_NAN2008
;
178 c
->options
|= MIPS_CPU_NAN_2008
;
179 c
->fpu_csr31
|= FPU_CSR_ABS2008
| FPU_CSR_NAN2008
;
180 c
->fpu_msk31
|= FPU_CSR_ABS2008
| FPU_CSR_NAN2008
;
183 c
->options
|= MIPS_CPU_NAN_2008
| MIPS_CPU_NAN_LEGACY
;
189 * Override the IEEE 754 NaN encoding and ABS.fmt/NEG.fmt execution mode
190 * according to the "ieee754=" parameter.
192 static void cpu_set_nan_2008(struct cpuinfo_mips
*c
)
196 mips_use_nan_legacy
= !!cpu_has_nan_legacy
;
197 mips_use_nan_2008
= !!cpu_has_nan_2008
;
200 mips_use_nan_legacy
= !!cpu_has_nan_legacy
;
201 mips_use_nan_2008
= !cpu_has_nan_legacy
;
204 mips_use_nan_legacy
= !cpu_has_nan_2008
;
205 mips_use_nan_2008
= !!cpu_has_nan_2008
;
208 mips_use_nan_legacy
= true;
209 mips_use_nan_2008
= true;
215 * IEEE 754 NaN encoding and ABS.fmt/NEG.fmt execution mode override
218 * strict: accept binaries that request a NaN encoding supported by the FPU
219 * legacy: only accept legacy-NaN binaries
220 * 2008: only accept 2008-NaN binaries
221 * relaxed: accept any binaries regardless of whether supported by the FPU
223 static int __init
ieee754_setup(char *s
)
227 else if (!strcmp(s
, "strict"))
229 else if (!strcmp(s
, "legacy"))
231 else if (!strcmp(s
, "2008"))
233 else if (!strcmp(s
, "relaxed"))
238 if (!(boot_cpu_data
.options
& MIPS_CPU_FPU
))
239 cpu_set_nofpu_2008(&boot_cpu_data
);
240 cpu_set_nan_2008(&boot_cpu_data
);
245 early_param("ieee754", ieee754_setup
);
248 * Set the FIR feature flags for the FPU emulator.
250 static void cpu_set_nofpu_id(struct cpuinfo_mips
*c
)
255 if (c
->isa_level
& (MIPS_CPU_ISA_M32R1
| MIPS_CPU_ISA_M64R1
|
256 MIPS_CPU_ISA_M32R2
| MIPS_CPU_ISA_M64R2
|
257 MIPS_CPU_ISA_M32R5
| MIPS_CPU_ISA_M64R5
|
258 MIPS_CPU_ISA_M32R6
| MIPS_CPU_ISA_M64R6
))
259 value
|= MIPS_FPIR_D
| MIPS_FPIR_S
;
260 if (c
->isa_level
& (MIPS_CPU_ISA_M32R2
| MIPS_CPU_ISA_M64R2
|
261 MIPS_CPU_ISA_M32R5
| MIPS_CPU_ISA_M64R5
|
262 MIPS_CPU_ISA_M32R6
| MIPS_CPU_ISA_M64R6
))
263 value
|= MIPS_FPIR_F64
| MIPS_FPIR_L
| MIPS_FPIR_W
;
264 if (c
->options
& MIPS_CPU_NAN_2008
)
265 value
|= MIPS_FPIR_HAS2008
;
269 /* Determined FPU emulator mask to use for the boot CPU with "nofpu". */
270 static unsigned int mips_nofpu_msk31
;
273 * Set options for FPU hardware.
275 void cpu_set_fpu_opts(struct cpuinfo_mips
*c
)
277 c
->fpu_id
= cpu_get_fpu_id();
278 mips_nofpu_msk31
= c
->fpu_msk31
;
280 if (c
->isa_level
& (MIPS_CPU_ISA_M32R1
| MIPS_CPU_ISA_M64R1
|
281 MIPS_CPU_ISA_M32R2
| MIPS_CPU_ISA_M64R2
|
282 MIPS_CPU_ISA_M32R5
| MIPS_CPU_ISA_M64R5
|
283 MIPS_CPU_ISA_M32R6
| MIPS_CPU_ISA_M64R6
)) {
284 if (c
->fpu_id
& MIPS_FPIR_3D
)
285 c
->ases
|= MIPS_ASE_MIPS3D
;
286 if (c
->fpu_id
& MIPS_FPIR_UFRP
)
287 c
->options
|= MIPS_CPU_UFR
;
288 if (c
->fpu_id
& MIPS_FPIR_FREP
)
289 c
->options
|= MIPS_CPU_FRE
;
292 cpu_set_fpu_fcsr_mask(c
);
298 * Set options for the FPU emulator.
300 void cpu_set_nofpu_opts(struct cpuinfo_mips
*c
)
302 c
->options
&= ~MIPS_CPU_FPU
;
303 c
->fpu_msk31
= mips_nofpu_msk31
;
305 cpu_set_nofpu_2008(c
);
310 int mips_fpu_disabled
;
312 static int __init
fpu_disable(char *s
)
314 cpu_set_nofpu_opts(&boot_cpu_data
);
315 mips_fpu_disabled
= 1;
320 __setup("nofpu", fpu_disable
);