]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - arch/mips/kernel/cpu-probe.c
Merge branch '4.0-fixes' into mips-for-linux-next
[karo-tx-linux.git] / arch / mips / kernel / cpu-probe.c
index ac96817d1f997508fe1e202d610b10e5a4ca1a16..e36515dcd3b29efcdb0014c7dfd4541805eb4e4c 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <asm/bugs.h>
 #include <asm/cpu.h>
+#include <asm/cpu-features.h>
 #include <asm/cpu-type.h>
 #include <asm/fpu.h>
 #include <asm/mipsregs.h>
 #include <asm/spram.h>
 #include <asm/uaccess.h>
 
+/*
+ * Get the FPU Implementation/Revision.
+ */
+static inline unsigned long cpu_get_fpu_id(void)
+{
+       unsigned long tmp, fpu_id;
+
+       tmp = read_c0_status();
+       __enable_fpu(FPU_AS_IS);
+       fpu_id = read_32bit_cp1_register(CP1_REVISION);
+       write_c0_status(tmp);
+       return fpu_id;
+}
+
+/*
+ * Check if the CPU has an external FPU.
+ */
+static inline int __cpu_has_fpu(void)
+{
+       return (cpu_get_fpu_id() & FPIR_IMP_MASK) != FPIR_IMP_NONE;
+}
+
+static inline unsigned long cpu_get_msa_id(void)
+{
+       unsigned long status, msa_id;
+
+       status = read_c0_status();
+       __enable_fpu(FPU_64BIT);
+       enable_msa();
+       msa_id = read_msa_ir();
+       disable_msa();
+       write_c0_status(status);
+       return msa_id;
+}
+
+/*
+ * Determine the FCSR mask for FPU hardware.
+ */
+static inline void cpu_set_fpu_fcsr_mask(struct cpuinfo_mips *c)
+{
+       unsigned long sr, mask, fcsr, fcsr0, fcsr1;
+
+       mask = FPU_CSR_ALL_X | FPU_CSR_ALL_E | FPU_CSR_ALL_S | FPU_CSR_RM;
+
+       sr = read_c0_status();
+       __enable_fpu(FPU_AS_IS);
+
+       fcsr = read_32bit_cp1_register(CP1_STATUS);
+
+       fcsr0 = fcsr & mask;
+       write_32bit_cp1_register(CP1_STATUS, fcsr0);
+       fcsr0 = read_32bit_cp1_register(CP1_STATUS);
+
+       fcsr1 = fcsr | ~mask;
+       write_32bit_cp1_register(CP1_STATUS, fcsr1);
+       fcsr1 = read_32bit_cp1_register(CP1_STATUS);
+
+       write_32bit_cp1_register(CP1_STATUS, fcsr);
+
+       write_c0_status(sr);
+
+       c->fpu_msk31 = ~(fcsr0 ^ fcsr1) & ~mask;
+}
+
+/*
+ * Set the FIR feature flags for the FPU emulator.
+ */
+static void cpu_set_nofpu_id(struct cpuinfo_mips *c)
+{
+       u32 value;
+
+       value = 0;
+       if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1 |
+                           MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 |
+                           MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6))
+               value |= MIPS_FPIR_D | MIPS_FPIR_S;
+       if (c->isa_level & (MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 |
+                           MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6))
+               value |= MIPS_FPIR_F64 | MIPS_FPIR_L | MIPS_FPIR_W;
+       c->fpu_id = value;
+}
+
+/* Determined FPU emulator mask to use for the boot CPU with "nofpu".  */
+static unsigned int mips_nofpu_msk31;
+
+/*
+ * Set options for FPU hardware.
+ */
+static void cpu_set_fpu_opts(struct cpuinfo_mips *c)
+{
+       c->fpu_id = cpu_get_fpu_id();
+       mips_nofpu_msk31 = c->fpu_msk31;
+
+       if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1 |
+                           MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 |
+                           MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6)) {
+               if (c->fpu_id & MIPS_FPIR_3D)
+                       c->ases |= MIPS_ASE_MIPS3D;
+               if (c->fpu_id & MIPS_FPIR_FREP)
+                       c->options |= MIPS_CPU_FRE;
+       }
+
+       cpu_set_fpu_fcsr_mask(c);
+}
+
+/*
+ * Set options for the FPU emulator.
+ */
+static void cpu_set_nofpu_opts(struct cpuinfo_mips *c)
+{
+       c->options &= ~MIPS_CPU_FPU;
+       c->fpu_msk31 = mips_nofpu_msk31;
+
+       cpu_set_nofpu_id(c);
+}
+
 static int mips_fpu_disabled;
 
 static int __init fpu_disable(char *s)
 {
-       cpu_data[0].options &= ~MIPS_CPU_FPU;
+       cpu_set_nofpu_opts(&boot_cpu_data);
        mips_fpu_disabled = 1;
 
        return 1;
@@ -178,41 +295,6 @@ static inline void set_elf_platform(int cpu, const char *plat)
                __elf_platform = plat;
 }
 
-/*
- * Get the FPU Implementation/Revision.
- */
-static inline unsigned long cpu_get_fpu_id(void)
-{
-       unsigned long tmp, fpu_id;
-
-       tmp = read_c0_status();
-       __enable_fpu(FPU_AS_IS);
-       fpu_id = read_32bit_cp1_register(CP1_REVISION);
-       write_c0_status(tmp);
-       return fpu_id;
-}
-
-/*
- * Check the CPU has an FPU the official way.
- */
-static inline int __cpu_has_fpu(void)
-{
-       return (cpu_get_fpu_id() & FPIR_IMP_MASK) != FPIR_IMP_NONE;
-}
-
-static inline unsigned long cpu_get_msa_id(void)
-{
-       unsigned long status, msa_id;
-
-       status = read_c0_status();
-       __enable_fpu(FPU_64BIT);
-       enable_msa();
-       msa_id = read_msa_ir();
-       disable_msa();
-       write_c0_status(status);
-       return msa_id;
-}
-
 static inline void cpu_probe_vmbits(struct cpuinfo_mips *c)
 {
 #ifdef __NEED_VMBITS_PROBE
@@ -441,6 +523,8 @@ static inline unsigned int decode_config3(struct cpuinfo_mips *c)
                c->htw_seq = 0;
                c->options |= MIPS_CPU_HTW;
        }
+       if (config3 & MIPS_CONF3_CDMM)
+               c->options |= MIPS_CPU_CDMM;
 
        return config3 & MIPS_CONF_M;
 }
@@ -579,6 +663,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
        case PRID_IMP_R2000:
                c->cputype = CPU_R2000;
                __cpu_name[cpu] = "R2000";
+               c->fpu_msk31 |= FPU_CSR_CONDX | FPU_CSR_FS;
                c->options = MIPS_CPU_TLB | MIPS_CPU_3K_CACHE |
                             MIPS_CPU_NOFPUEX;
                if (__cpu_has_fpu())
@@ -598,6 +683,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
                        c->cputype = CPU_R3000;
                        __cpu_name[cpu] = "R3000";
                }
+               c->fpu_msk31 |= FPU_CSR_CONDX | FPU_CSR_FS;
                c->options = MIPS_CPU_TLB | MIPS_CPU_3K_CACHE |
                             MIPS_CPU_NOFPUEX;
                if (__cpu_has_fpu())
@@ -646,6 +732,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
                }
 
                set_isa(c, MIPS_CPU_ISA_III);
+               c->fpu_msk31 |= FPU_CSR_CONDX;
                c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
                             MIPS_CPU_WATCH | MIPS_CPU_VCE |
                             MIPS_CPU_LLSC;
@@ -653,6 +740,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
                break;
        case PRID_IMP_VR41XX:
                set_isa(c, MIPS_CPU_ISA_III);
+               c->fpu_msk31 |= FPU_CSR_CONDX;
                c->options = R4K_OPTS;
                c->tlbsize = 32;
                switch (c->processor_id & 0xf0) {
@@ -694,6 +782,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
                c->cputype = CPU_R4300;
                __cpu_name[cpu] = "R4300";
                set_isa(c, MIPS_CPU_ISA_III);
+               c->fpu_msk31 |= FPU_CSR_CONDX;
                c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
                             MIPS_CPU_LLSC;
                c->tlbsize = 32;
@@ -702,6 +791,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
                c->cputype = CPU_R4600;
                __cpu_name[cpu] = "R4600";
                set_isa(c, MIPS_CPU_ISA_III);
+               c->fpu_msk31 |= FPU_CSR_CONDX;
                c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
                             MIPS_CPU_LLSC;
                c->tlbsize = 48;
@@ -717,11 +807,13 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
                c->cputype = CPU_R4650;
                __cpu_name[cpu] = "R4650";
                set_isa(c, MIPS_CPU_ISA_III);
+               c->fpu_msk31 |= FPU_CSR_CONDX;
                c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_LLSC;
                c->tlbsize = 48;
                break;
        #endif
        case PRID_IMP_TX39:
+               c->fpu_msk31 |= FPU_CSR_CONDX | FPU_CSR_FS;
                c->options = MIPS_CPU_TLB | MIPS_CPU_TX39_CACHE;
 
                if ((c->processor_id & 0xf0) == (PRID_REV_TX3927 & 0xf0)) {
@@ -747,6 +839,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
                c->cputype = CPU_R4700;
                __cpu_name[cpu] = "R4700";
                set_isa(c, MIPS_CPU_ISA_III);
+               c->fpu_msk31 |= FPU_CSR_CONDX;
                c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
                             MIPS_CPU_LLSC;
                c->tlbsize = 48;
@@ -755,6 +848,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
                c->cputype = CPU_TX49XX;
                __cpu_name[cpu] = "R49XX";
                set_isa(c, MIPS_CPU_ISA_III);
+               c->fpu_msk31 |= FPU_CSR_CONDX;
                c->options = R4K_OPTS | MIPS_CPU_LLSC;
                if (!(c->processor_id & 0x08))
                        c->options |= MIPS_CPU_FPU | MIPS_CPU_32FPR;
@@ -796,6 +890,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
                c->cputype = CPU_R6000;
                __cpu_name[cpu] = "R6000";
                set_isa(c, MIPS_CPU_ISA_II);
+               c->fpu_msk31 |= FPU_CSR_CONDX | FPU_CSR_FS;
                c->options = MIPS_CPU_TLB | MIPS_CPU_FPU |
                             MIPS_CPU_LLSC;
                c->tlbsize = 32;
@@ -804,6 +899,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
                c->cputype = CPU_R6000A;
                __cpu_name[cpu] = "R6000A";
                set_isa(c, MIPS_CPU_ISA_II);
+               c->fpu_msk31 |= FPU_CSR_CONDX | FPU_CSR_FS;
                c->options = MIPS_CPU_TLB | MIPS_CPU_FPU |
                             MIPS_CPU_LLSC;
                c->tlbsize = 32;
@@ -854,8 +950,13 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
                c->tlbsize = 64;
                break;
        case PRID_IMP_R14000:
-               c->cputype = CPU_R14000;
-               __cpu_name[cpu] = "R14000";
+               if (((c->processor_id >> 4) & 0x0f) > 2) {
+                       c->cputype = CPU_R16000;
+                       __cpu_name[cpu] = "R16000";
+               } else {
+                       c->cputype = CPU_R14000;
+                       __cpu_name[cpu] = "R14000";
+               }
                set_isa(c, MIPS_CPU_ISA_IV);
                c->options = MIPS_CPU_TLB | MIPS_CPU_4K_CACHE | MIPS_CPU_4KEX |
                             MIPS_CPU_FPU | MIPS_CPU_32FPR |
@@ -870,12 +971,14 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
                        __cpu_name[cpu] = "ICT Loongson-2";
                        set_elf_platform(cpu, "loongson2e");
                        set_isa(c, MIPS_CPU_ISA_III);
+                       c->fpu_msk31 |= FPU_CSR_CONDX;
                        break;
                case PRID_REV_LOONGSON2F:
                        c->cputype = CPU_LOONGSON2;
                        __cpu_name[cpu] = "ICT Loongson-2";
                        set_elf_platform(cpu, "loongson2f");
                        set_isa(c, MIPS_CPU_ISA_III);
+                       c->fpu_msk31 |= FPU_CSR_CONDX;
                        break;
                case PRID_REV_LOONGSON3A:
                        c->cputype = CPU_LOONGSON3;
@@ -1312,6 +1415,9 @@ void cpu_probe(void)
        c->cputype      = CPU_UNKNOWN;
        c->writecombine = _CACHE_UNCACHED;
 
+       c->fpu_csr31    = FPU_CSR_RN;
+       c->fpu_msk31    = FPU_CSR_RSVD | FPU_CSR_ABS2008 | FPU_CSR_NAN2008;
+
        c->processor_id = read_c0_prid();
        switch (c->processor_id & PRID_COMP_MASK) {
        case PRID_COMP_LEGACY:
@@ -1368,16 +1474,10 @@ void cpu_probe(void)
                               ~(1 << MIPS_PWCTL_PWEN_SHIFT));
        }
 
-       if (c->options & MIPS_CPU_FPU) {
-               c->fpu_id = cpu_get_fpu_id();
-
-               if (c->isa_level & cpu_has_mips_r) {
-                       if (c->fpu_id & MIPS_FPIR_3D)
-                               c->ases |= MIPS_ASE_MIPS3D;
-                       if (c->fpu_id & MIPS_FPIR_FREP)
-                               c->options |= MIPS_CPU_FRE;
-               }
-       }
+       if (c->options & MIPS_CPU_FPU)
+               cpu_set_fpu_opts(c);
+       else
+               cpu_set_nofpu_opts(c);
 
        if (cpu_has_mips_r2_r6) {
                c->srsets = ((read_c0_srsctl() >> 26) & 0x0f) + 1;