| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Processor capabilities determination functions. |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 5 | 6 | * Copyright (C) 1994 - 2006 Ralf Baechle |
|---|
| 6 | 7 | * Copyright (C) 2003, 2004 Maciej W. Rozycki |
|---|
| 7 | 8 | * Copyright (C) 2001, 2004, 2011, 2012 MIPS Technologies, Inc. |
|---|
| 8 | | - * |
|---|
| 9 | | - * This program is free software; you can redistribute it and/or |
|---|
| 10 | | - * modify it under the terms of the GNU General Public License |
|---|
| 11 | | - * as published by the Free Software Foundation; either version |
|---|
| 12 | | - * 2 of the License, or (at your option) any later version. |
|---|
| 13 | 9 | */ |
|---|
| 14 | 10 | #include <linux/init.h> |
|---|
| 15 | 11 | #include <linux/kernel.h> |
|---|
| .. | .. |
|---|
| 32 | 28 | #include <asm/spram.h> |
|---|
| 33 | 29 | #include <linux/uaccess.h> |
|---|
| 34 | 30 | |
|---|
| 31 | +#include "fpu-probe.h" |
|---|
| 32 | + |
|---|
| 33 | +#include <asm/mach-loongson64/cpucfg-emul.h> |
|---|
| 34 | + |
|---|
| 35 | 35 | /* Hardware capabilities */ |
|---|
| 36 | 36 | unsigned int elf_hwcap __read_mostly; |
|---|
| 37 | 37 | EXPORT_SYMBOL_GPL(elf_hwcap); |
|---|
| 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 | 38 | |
|---|
| 61 | 39 | static inline unsigned long cpu_get_msa_id(void) |
|---|
| 62 | 40 | { |
|---|
| .. | .. |
|---|
| 70 | 48 | write_c0_status(status); |
|---|
| 71 | 49 | return msa_id; |
|---|
| 72 | 50 | } |
|---|
| 73 | | - |
|---|
| 74 | | -/* |
|---|
| 75 | | - * Determine the FCSR mask for FPU hardware. |
|---|
| 76 | | - */ |
|---|
| 77 | | -static inline void cpu_set_fpu_fcsr_mask(struct cpuinfo_mips *c) |
|---|
| 78 | | -{ |
|---|
| 79 | | - unsigned long sr, mask, fcsr, fcsr0, fcsr1; |
|---|
| 80 | | - |
|---|
| 81 | | - fcsr = c->fpu_csr31; |
|---|
| 82 | | - mask = FPU_CSR_ALL_X | FPU_CSR_ALL_E | FPU_CSR_ALL_S | FPU_CSR_RM; |
|---|
| 83 | | - |
|---|
| 84 | | - sr = read_c0_status(); |
|---|
| 85 | | - __enable_fpu(FPU_AS_IS); |
|---|
| 86 | | - |
|---|
| 87 | | - fcsr0 = fcsr & mask; |
|---|
| 88 | | - write_32bit_cp1_register(CP1_STATUS, fcsr0); |
|---|
| 89 | | - fcsr0 = read_32bit_cp1_register(CP1_STATUS); |
|---|
| 90 | | - |
|---|
| 91 | | - fcsr1 = fcsr | ~mask; |
|---|
| 92 | | - write_32bit_cp1_register(CP1_STATUS, fcsr1); |
|---|
| 93 | | - fcsr1 = read_32bit_cp1_register(CP1_STATUS); |
|---|
| 94 | | - |
|---|
| 95 | | - write_32bit_cp1_register(CP1_STATUS, fcsr); |
|---|
| 96 | | - |
|---|
| 97 | | - write_c0_status(sr); |
|---|
| 98 | | - |
|---|
| 99 | | - c->fpu_msk31 = ~(fcsr0 ^ fcsr1) & ~mask; |
|---|
| 100 | | -} |
|---|
| 101 | | - |
|---|
| 102 | | -/* |
|---|
| 103 | | - * Determine the IEEE 754 NaN encodings and ABS.fmt/NEG.fmt execution modes |
|---|
| 104 | | - * supported by FPU hardware. |
|---|
| 105 | | - */ |
|---|
| 106 | | -static void cpu_set_fpu_2008(struct cpuinfo_mips *c) |
|---|
| 107 | | -{ |
|---|
| 108 | | - if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1 | |
|---|
| 109 | | - MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 | |
|---|
| 110 | | - MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6)) { |
|---|
| 111 | | - unsigned long sr, fir, fcsr, fcsr0, fcsr1; |
|---|
| 112 | | - |
|---|
| 113 | | - sr = read_c0_status(); |
|---|
| 114 | | - __enable_fpu(FPU_AS_IS); |
|---|
| 115 | | - |
|---|
| 116 | | - fir = read_32bit_cp1_register(CP1_REVISION); |
|---|
| 117 | | - if (fir & MIPS_FPIR_HAS2008) { |
|---|
| 118 | | - fcsr = read_32bit_cp1_register(CP1_STATUS); |
|---|
| 119 | | - |
|---|
| 120 | | - fcsr0 = fcsr & ~(FPU_CSR_ABS2008 | FPU_CSR_NAN2008); |
|---|
| 121 | | - write_32bit_cp1_register(CP1_STATUS, fcsr0); |
|---|
| 122 | | - fcsr0 = read_32bit_cp1_register(CP1_STATUS); |
|---|
| 123 | | - |
|---|
| 124 | | - fcsr1 = fcsr | FPU_CSR_ABS2008 | FPU_CSR_NAN2008; |
|---|
| 125 | | - write_32bit_cp1_register(CP1_STATUS, fcsr1); |
|---|
| 126 | | - fcsr1 = read_32bit_cp1_register(CP1_STATUS); |
|---|
| 127 | | - |
|---|
| 128 | | - write_32bit_cp1_register(CP1_STATUS, fcsr); |
|---|
| 129 | | - |
|---|
| 130 | | - if (!(fcsr0 & FPU_CSR_NAN2008)) |
|---|
| 131 | | - c->options |= MIPS_CPU_NAN_LEGACY; |
|---|
| 132 | | - if (fcsr1 & FPU_CSR_NAN2008) |
|---|
| 133 | | - c->options |= MIPS_CPU_NAN_2008; |
|---|
| 134 | | - |
|---|
| 135 | | - if ((fcsr0 ^ fcsr1) & FPU_CSR_ABS2008) |
|---|
| 136 | | - c->fpu_msk31 &= ~FPU_CSR_ABS2008; |
|---|
| 137 | | - else |
|---|
| 138 | | - c->fpu_csr31 |= fcsr & FPU_CSR_ABS2008; |
|---|
| 139 | | - |
|---|
| 140 | | - if ((fcsr0 ^ fcsr1) & FPU_CSR_NAN2008) |
|---|
| 141 | | - c->fpu_msk31 &= ~FPU_CSR_NAN2008; |
|---|
| 142 | | - else |
|---|
| 143 | | - c->fpu_csr31 |= fcsr & FPU_CSR_NAN2008; |
|---|
| 144 | | - } else { |
|---|
| 145 | | - c->options |= MIPS_CPU_NAN_LEGACY; |
|---|
| 146 | | - } |
|---|
| 147 | | - |
|---|
| 148 | | - write_c0_status(sr); |
|---|
| 149 | | - } else { |
|---|
| 150 | | - c->options |= MIPS_CPU_NAN_LEGACY; |
|---|
| 151 | | - } |
|---|
| 152 | | -} |
|---|
| 153 | | - |
|---|
| 154 | | -/* |
|---|
| 155 | | - * IEEE 754 conformance mode to use. Affects the NaN encoding and the |
|---|
| 156 | | - * ABS.fmt/NEG.fmt execution mode. |
|---|
| 157 | | - */ |
|---|
| 158 | | -static enum { STRICT, LEGACY, STD2008, RELAXED } ieee754 = STRICT; |
|---|
| 159 | | - |
|---|
| 160 | | -/* |
|---|
| 161 | | - * Set the IEEE 754 NaN encodings and the ABS.fmt/NEG.fmt execution modes |
|---|
| 162 | | - * to support by the FPU emulator according to the IEEE 754 conformance |
|---|
| 163 | | - * mode selected. Note that "relaxed" straps the emulator so that it |
|---|
| 164 | | - * allows 2008-NaN binaries even for legacy processors. |
|---|
| 165 | | - */ |
|---|
| 166 | | -static void cpu_set_nofpu_2008(struct cpuinfo_mips *c) |
|---|
| 167 | | -{ |
|---|
| 168 | | - c->options &= ~(MIPS_CPU_NAN_2008 | MIPS_CPU_NAN_LEGACY); |
|---|
| 169 | | - c->fpu_csr31 &= ~(FPU_CSR_ABS2008 | FPU_CSR_NAN2008); |
|---|
| 170 | | - c->fpu_msk31 &= ~(FPU_CSR_ABS2008 | FPU_CSR_NAN2008); |
|---|
| 171 | | - |
|---|
| 172 | | - switch (ieee754) { |
|---|
| 173 | | - case STRICT: |
|---|
| 174 | | - if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1 | |
|---|
| 175 | | - MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 | |
|---|
| 176 | | - MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6)) { |
|---|
| 177 | | - c->options |= MIPS_CPU_NAN_2008 | MIPS_CPU_NAN_LEGACY; |
|---|
| 178 | | - } else { |
|---|
| 179 | | - c->options |= MIPS_CPU_NAN_LEGACY; |
|---|
| 180 | | - c->fpu_msk31 |= FPU_CSR_ABS2008 | FPU_CSR_NAN2008; |
|---|
| 181 | | - } |
|---|
| 182 | | - break; |
|---|
| 183 | | - case LEGACY: |
|---|
| 184 | | - c->options |= MIPS_CPU_NAN_LEGACY; |
|---|
| 185 | | - c->fpu_msk31 |= FPU_CSR_ABS2008 | FPU_CSR_NAN2008; |
|---|
| 186 | | - break; |
|---|
| 187 | | - case STD2008: |
|---|
| 188 | | - c->options |= MIPS_CPU_NAN_2008; |
|---|
| 189 | | - c->fpu_csr31 |= FPU_CSR_ABS2008 | FPU_CSR_NAN2008; |
|---|
| 190 | | - c->fpu_msk31 |= FPU_CSR_ABS2008 | FPU_CSR_NAN2008; |
|---|
| 191 | | - break; |
|---|
| 192 | | - case RELAXED: |
|---|
| 193 | | - c->options |= MIPS_CPU_NAN_2008 | MIPS_CPU_NAN_LEGACY; |
|---|
| 194 | | - break; |
|---|
| 195 | | - } |
|---|
| 196 | | -} |
|---|
| 197 | | - |
|---|
| 198 | | -/* |
|---|
| 199 | | - * Override the IEEE 754 NaN encoding and ABS.fmt/NEG.fmt execution mode |
|---|
| 200 | | - * according to the "ieee754=" parameter. |
|---|
| 201 | | - */ |
|---|
| 202 | | -static void cpu_set_nan_2008(struct cpuinfo_mips *c) |
|---|
| 203 | | -{ |
|---|
| 204 | | - switch (ieee754) { |
|---|
| 205 | | - case STRICT: |
|---|
| 206 | | - mips_use_nan_legacy = !!cpu_has_nan_legacy; |
|---|
| 207 | | - mips_use_nan_2008 = !!cpu_has_nan_2008; |
|---|
| 208 | | - break; |
|---|
| 209 | | - case LEGACY: |
|---|
| 210 | | - mips_use_nan_legacy = !!cpu_has_nan_legacy; |
|---|
| 211 | | - mips_use_nan_2008 = !cpu_has_nan_legacy; |
|---|
| 212 | | - break; |
|---|
| 213 | | - case STD2008: |
|---|
| 214 | | - mips_use_nan_legacy = !cpu_has_nan_2008; |
|---|
| 215 | | - mips_use_nan_2008 = !!cpu_has_nan_2008; |
|---|
| 216 | | - break; |
|---|
| 217 | | - case RELAXED: |
|---|
| 218 | | - mips_use_nan_legacy = true; |
|---|
| 219 | | - mips_use_nan_2008 = true; |
|---|
| 220 | | - break; |
|---|
| 221 | | - } |
|---|
| 222 | | -} |
|---|
| 223 | | - |
|---|
| 224 | | -/* |
|---|
| 225 | | - * IEEE 754 NaN encoding and ABS.fmt/NEG.fmt execution mode override |
|---|
| 226 | | - * settings: |
|---|
| 227 | | - * |
|---|
| 228 | | - * strict: accept binaries that request a NaN encoding supported by the FPU |
|---|
| 229 | | - * legacy: only accept legacy-NaN binaries |
|---|
| 230 | | - * 2008: only accept 2008-NaN binaries |
|---|
| 231 | | - * relaxed: accept any binaries regardless of whether supported by the FPU |
|---|
| 232 | | - */ |
|---|
| 233 | | -static int __init ieee754_setup(char *s) |
|---|
| 234 | | -{ |
|---|
| 235 | | - if (!s) |
|---|
| 236 | | - return -1; |
|---|
| 237 | | - else if (!strcmp(s, "strict")) |
|---|
| 238 | | - ieee754 = STRICT; |
|---|
| 239 | | - else if (!strcmp(s, "legacy")) |
|---|
| 240 | | - ieee754 = LEGACY; |
|---|
| 241 | | - else if (!strcmp(s, "2008")) |
|---|
| 242 | | - ieee754 = STD2008; |
|---|
| 243 | | - else if (!strcmp(s, "relaxed")) |
|---|
| 244 | | - ieee754 = RELAXED; |
|---|
| 245 | | - else |
|---|
| 246 | | - return -1; |
|---|
| 247 | | - |
|---|
| 248 | | - if (!(boot_cpu_data.options & MIPS_CPU_FPU)) |
|---|
| 249 | | - cpu_set_nofpu_2008(&boot_cpu_data); |
|---|
| 250 | | - cpu_set_nan_2008(&boot_cpu_data); |
|---|
| 251 | | - |
|---|
| 252 | | - return 0; |
|---|
| 253 | | -} |
|---|
| 254 | | - |
|---|
| 255 | | -early_param("ieee754", ieee754_setup); |
|---|
| 256 | | - |
|---|
| 257 | | -/* |
|---|
| 258 | | - * Set the FIR feature flags for the FPU emulator. |
|---|
| 259 | | - */ |
|---|
| 260 | | -static void cpu_set_nofpu_id(struct cpuinfo_mips *c) |
|---|
| 261 | | -{ |
|---|
| 262 | | - u32 value; |
|---|
| 263 | | - |
|---|
| 264 | | - value = 0; |
|---|
| 265 | | - if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1 | |
|---|
| 266 | | - MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 | |
|---|
| 267 | | - MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6)) |
|---|
| 268 | | - value |= MIPS_FPIR_D | MIPS_FPIR_S; |
|---|
| 269 | | - if (c->isa_level & (MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 | |
|---|
| 270 | | - MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6)) |
|---|
| 271 | | - value |= MIPS_FPIR_F64 | MIPS_FPIR_L | MIPS_FPIR_W; |
|---|
| 272 | | - if (c->options & MIPS_CPU_NAN_2008) |
|---|
| 273 | | - value |= MIPS_FPIR_HAS2008; |
|---|
| 274 | | - c->fpu_id = value; |
|---|
| 275 | | -} |
|---|
| 276 | | - |
|---|
| 277 | | -/* Determined FPU emulator mask to use for the boot CPU with "nofpu". */ |
|---|
| 278 | | -static unsigned int mips_nofpu_msk31; |
|---|
| 279 | | - |
|---|
| 280 | | -/* |
|---|
| 281 | | - * Set options for FPU hardware. |
|---|
| 282 | | - */ |
|---|
| 283 | | -static void cpu_set_fpu_opts(struct cpuinfo_mips *c) |
|---|
| 284 | | -{ |
|---|
| 285 | | - c->fpu_id = cpu_get_fpu_id(); |
|---|
| 286 | | - mips_nofpu_msk31 = c->fpu_msk31; |
|---|
| 287 | | - |
|---|
| 288 | | - if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1 | |
|---|
| 289 | | - MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 | |
|---|
| 290 | | - MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6)) { |
|---|
| 291 | | - if (c->fpu_id & MIPS_FPIR_3D) |
|---|
| 292 | | - c->ases |= MIPS_ASE_MIPS3D; |
|---|
| 293 | | - if (c->fpu_id & MIPS_FPIR_UFRP) |
|---|
| 294 | | - c->options |= MIPS_CPU_UFR; |
|---|
| 295 | | - if (c->fpu_id & MIPS_FPIR_FREP) |
|---|
| 296 | | - c->options |= MIPS_CPU_FRE; |
|---|
| 297 | | - } |
|---|
| 298 | | - |
|---|
| 299 | | - cpu_set_fpu_fcsr_mask(c); |
|---|
| 300 | | - cpu_set_fpu_2008(c); |
|---|
| 301 | | - cpu_set_nan_2008(c); |
|---|
| 302 | | -} |
|---|
| 303 | | - |
|---|
| 304 | | -/* |
|---|
| 305 | | - * Set options for the FPU emulator. |
|---|
| 306 | | - */ |
|---|
| 307 | | -static void cpu_set_nofpu_opts(struct cpuinfo_mips *c) |
|---|
| 308 | | -{ |
|---|
| 309 | | - c->options &= ~MIPS_CPU_FPU; |
|---|
| 310 | | - c->fpu_msk31 = mips_nofpu_msk31; |
|---|
| 311 | | - |
|---|
| 312 | | - cpu_set_nofpu_2008(c); |
|---|
| 313 | | - cpu_set_nan_2008(c); |
|---|
| 314 | | - cpu_set_nofpu_id(c); |
|---|
| 315 | | -} |
|---|
| 316 | | - |
|---|
| 317 | | -static int mips_fpu_disabled; |
|---|
| 318 | | - |
|---|
| 319 | | -static int __init fpu_disable(char *s) |
|---|
| 320 | | -{ |
|---|
| 321 | | - cpu_set_nofpu_opts(&boot_cpu_data); |
|---|
| 322 | | - mips_fpu_disabled = 1; |
|---|
| 323 | | - |
|---|
| 324 | | - return 1; |
|---|
| 325 | | -} |
|---|
| 326 | | - |
|---|
| 327 | | -__setup("nofpu", fpu_disable); |
|---|
| 328 | 51 | |
|---|
| 329 | 52 | static int mips_dsp_disabled; |
|---|
| 330 | 53 | |
|---|
| .. | .. |
|---|
| 475 | 198 | __elf_platform = plat; |
|---|
| 476 | 199 | } |
|---|
| 477 | 200 | |
|---|
| 201 | +static inline void set_elf_base_platform(const char *plat) |
|---|
| 202 | +{ |
|---|
| 203 | + if (__elf_base_platform == NULL) { |
|---|
| 204 | + __elf_base_platform = plat; |
|---|
| 205 | + } |
|---|
| 206 | +} |
|---|
| 207 | + |
|---|
| 478 | 208 | static inline void cpu_probe_vmbits(struct cpuinfo_mips *c) |
|---|
| 479 | 209 | { |
|---|
| 480 | 210 | #ifdef __NEED_VMBITS_PROBE |
|---|
| .. | .. |
|---|
| 487 | 217 | static void set_isa(struct cpuinfo_mips *c, unsigned int isa) |
|---|
| 488 | 218 | { |
|---|
| 489 | 219 | switch (isa) { |
|---|
| 220 | + case MIPS_CPU_ISA_M64R5: |
|---|
| 221 | + c->isa_level |= MIPS_CPU_ISA_M32R5 | MIPS_CPU_ISA_M64R5; |
|---|
| 222 | + set_elf_base_platform("mips64r5"); |
|---|
| 223 | + fallthrough; |
|---|
| 490 | 224 | case MIPS_CPU_ISA_M64R2: |
|---|
| 491 | 225 | c->isa_level |= MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2; |
|---|
| 226 | + set_elf_base_platform("mips64r2"); |
|---|
| 227 | + fallthrough; |
|---|
| 492 | 228 | case MIPS_CPU_ISA_M64R1: |
|---|
| 493 | 229 | c->isa_level |= MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1; |
|---|
| 230 | + set_elf_base_platform("mips64"); |
|---|
| 231 | + fallthrough; |
|---|
| 494 | 232 | case MIPS_CPU_ISA_V: |
|---|
| 495 | 233 | c->isa_level |= MIPS_CPU_ISA_V; |
|---|
| 234 | + set_elf_base_platform("mips5"); |
|---|
| 235 | + fallthrough; |
|---|
| 496 | 236 | case MIPS_CPU_ISA_IV: |
|---|
| 497 | 237 | c->isa_level |= MIPS_CPU_ISA_IV; |
|---|
| 238 | + set_elf_base_platform("mips4"); |
|---|
| 239 | + fallthrough; |
|---|
| 498 | 240 | case MIPS_CPU_ISA_III: |
|---|
| 499 | 241 | c->isa_level |= MIPS_CPU_ISA_II | MIPS_CPU_ISA_III; |
|---|
| 242 | + set_elf_base_platform("mips3"); |
|---|
| 500 | 243 | break; |
|---|
| 501 | 244 | |
|---|
| 502 | 245 | /* R6 incompatible with everything else */ |
|---|
| 503 | 246 | case MIPS_CPU_ISA_M64R6: |
|---|
| 504 | 247 | c->isa_level |= MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6; |
|---|
| 248 | + set_elf_base_platform("mips64r6"); |
|---|
| 249 | + fallthrough; |
|---|
| 505 | 250 | case MIPS_CPU_ISA_M32R6: |
|---|
| 506 | 251 | c->isa_level |= MIPS_CPU_ISA_M32R6; |
|---|
| 252 | + set_elf_base_platform("mips32r6"); |
|---|
| 507 | 253 | /* Break here so we don't add incompatible ISAs */ |
|---|
| 508 | 254 | break; |
|---|
| 255 | + case MIPS_CPU_ISA_M32R5: |
|---|
| 256 | + c->isa_level |= MIPS_CPU_ISA_M32R5; |
|---|
| 257 | + set_elf_base_platform("mips32r5"); |
|---|
| 258 | + fallthrough; |
|---|
| 509 | 259 | case MIPS_CPU_ISA_M32R2: |
|---|
| 510 | 260 | c->isa_level |= MIPS_CPU_ISA_M32R2; |
|---|
| 261 | + set_elf_base_platform("mips32r2"); |
|---|
| 262 | + fallthrough; |
|---|
| 511 | 263 | case MIPS_CPU_ISA_M32R1: |
|---|
| 512 | 264 | c->isa_level |= MIPS_CPU_ISA_M32R1; |
|---|
| 265 | + set_elf_base_platform("mips32"); |
|---|
| 266 | + fallthrough; |
|---|
| 513 | 267 | case MIPS_CPU_ISA_II: |
|---|
| 514 | 268 | c->isa_level |= MIPS_CPU_ISA_II; |
|---|
| 269 | + set_elf_base_platform("mips2"); |
|---|
| 515 | 270 | break; |
|---|
| 516 | 271 | } |
|---|
| 517 | 272 | } |
|---|
| .. | .. |
|---|
| 558 | 313 | config = read_c0_config6(); |
|---|
| 559 | 314 | |
|---|
| 560 | 315 | if (flags & FTLB_EN) |
|---|
| 561 | | - config |= MIPS_CONF6_FTLBEN; |
|---|
| 316 | + config |= MTI_CONF6_FTLBEN; |
|---|
| 562 | 317 | else |
|---|
| 563 | | - config &= ~MIPS_CONF6_FTLBEN; |
|---|
| 318 | + config &= ~MTI_CONF6_FTLBEN; |
|---|
| 564 | 319 | |
|---|
| 565 | 320 | if (flags & FTLB_SET_PROB) { |
|---|
| 566 | | - config &= ~(3 << MIPS_CONF6_FTLBP_SHIFT); |
|---|
| 321 | + config &= ~(3 << MTI_CONF6_FTLBP_SHIFT); |
|---|
| 567 | 322 | config |= calculate_ftlb_probability(c) |
|---|
| 568 | | - << MIPS_CONF6_FTLBP_SHIFT; |
|---|
| 323 | + << MTI_CONF6_FTLBP_SHIFT; |
|---|
| 569 | 324 | } |
|---|
| 570 | 325 | |
|---|
| 571 | 326 | write_c0_config6(config); |
|---|
| .. | .. |
|---|
| 577 | 332 | if (!(flags & FTLB_EN)) |
|---|
| 578 | 333 | return 1; |
|---|
| 579 | 334 | return 0; |
|---|
| 580 | | - case CPU_LOONGSON3: |
|---|
| 335 | + case CPU_LOONGSON64: |
|---|
| 581 | 336 | /* Flush ITLB, DTLB, VTLB and FTLB */ |
|---|
| 582 | 337 | write_c0_diag(LOONGSON_DIAG_ITLB | LOONGSON_DIAG_DTLB | |
|---|
| 583 | 338 | LOONGSON_DIAG_VTLB | LOONGSON_DIAG_FTLB); |
|---|
| .. | .. |
|---|
| 585 | 340 | config = read_c0_config6(); |
|---|
| 586 | 341 | if (flags & FTLB_EN) |
|---|
| 587 | 342 | /* Enable FTLB */ |
|---|
| 588 | | - write_c0_config6(config & ~MIPS_CONF6_FTLBDIS); |
|---|
| 343 | + write_c0_config6(config & ~LOONGSON_CONF6_FTLBDIS); |
|---|
| 589 | 344 | else |
|---|
| 590 | 345 | /* Disable FTLB */ |
|---|
| 591 | | - write_c0_config6(config | MIPS_CONF6_FTLBDIS); |
|---|
| 346 | + write_c0_config6(config | LOONGSON_CONF6_FTLBDIS); |
|---|
| 592 | 347 | break; |
|---|
| 593 | 348 | default: |
|---|
| 594 | 349 | return 1; |
|---|
| 350 | + } |
|---|
| 351 | + |
|---|
| 352 | + return 0; |
|---|
| 353 | +} |
|---|
| 354 | + |
|---|
| 355 | +static int mm_config(struct cpuinfo_mips *c) |
|---|
| 356 | +{ |
|---|
| 357 | + unsigned int config0, update, mm; |
|---|
| 358 | + |
|---|
| 359 | + config0 = read_c0_config(); |
|---|
| 360 | + mm = config0 & MIPS_CONF_MM; |
|---|
| 361 | + |
|---|
| 362 | + /* |
|---|
| 363 | + * It's implementation dependent what type of write-merge is supported |
|---|
| 364 | + * and whether it can be enabled/disabled. If it is settable lets make |
|---|
| 365 | + * the merging allowed by default. Some platforms might have |
|---|
| 366 | + * write-through caching unsupported. In this case just ignore the |
|---|
| 367 | + * CP0.Config.MM bit field value. |
|---|
| 368 | + */ |
|---|
| 369 | + switch (c->cputype) { |
|---|
| 370 | + case CPU_24K: |
|---|
| 371 | + case CPU_34K: |
|---|
| 372 | + case CPU_74K: |
|---|
| 373 | + case CPU_P5600: |
|---|
| 374 | + case CPU_P6600: |
|---|
| 375 | + c->options |= MIPS_CPU_MM_FULL; |
|---|
| 376 | + update = MIPS_CONF_MM_FULL; |
|---|
| 377 | + break; |
|---|
| 378 | + case CPU_1004K: |
|---|
| 379 | + case CPU_1074K: |
|---|
| 380 | + case CPU_INTERAPTIV: |
|---|
| 381 | + case CPU_PROAPTIV: |
|---|
| 382 | + mm = 0; |
|---|
| 383 | + fallthrough; |
|---|
| 384 | + default: |
|---|
| 385 | + update = 0; |
|---|
| 386 | + break; |
|---|
| 387 | + } |
|---|
| 388 | + |
|---|
| 389 | + if (update) { |
|---|
| 390 | + config0 = (config0 & ~MIPS_CONF_MM) | update; |
|---|
| 391 | + write_c0_config(config0); |
|---|
| 392 | + } else if (mm == MIPS_CONF_MM_SYSAD) { |
|---|
| 393 | + c->options |= MIPS_CPU_MM_SYSAD; |
|---|
| 394 | + } else if (mm == MIPS_CONF_MM_FULL) { |
|---|
| 395 | + c->options |= MIPS_CPU_MM_FULL; |
|---|
| 595 | 396 | } |
|---|
| 596 | 397 | |
|---|
| 597 | 398 | return 0; |
|---|
| .. | .. |
|---|
| 788 | 589 | MIPS_CONF4_VTLBSIZEEXT_SHIFT) * 0x40; |
|---|
| 789 | 590 | c->tlbsize = c->tlbsizevtlb; |
|---|
| 790 | 591 | ftlb_page = MIPS_CONF4_VFTLBPAGESIZE; |
|---|
| 791 | | - /* fall through */ |
|---|
| 592 | + fallthrough; |
|---|
| 792 | 593 | case MIPS_CONF4_MMUEXTDEF_FTLBSIZEEXT: |
|---|
| 793 | 594 | if (mips_ftlb_disabled) |
|---|
| 794 | 595 | break; |
|---|
| .. | .. |
|---|
| 837 | 638 | |
|---|
| 838 | 639 | static inline unsigned int decode_config5(struct cpuinfo_mips *c) |
|---|
| 839 | 640 | { |
|---|
| 840 | | - unsigned int config5; |
|---|
| 641 | + unsigned int config5, max_mmid_width; |
|---|
| 642 | + unsigned long asid_mask; |
|---|
| 841 | 643 | |
|---|
| 842 | 644 | config5 = read_c0_config5(); |
|---|
| 843 | 645 | config5 &= ~(MIPS_CONF5_UFR | MIPS_CONF5_UFE); |
|---|
| 646 | + |
|---|
| 647 | + if (cpu_has_mips_r6) { |
|---|
| 648 | + if (!__builtin_constant_p(cpu_has_mmid) || cpu_has_mmid) |
|---|
| 649 | + config5 |= MIPS_CONF5_MI; |
|---|
| 650 | + else |
|---|
| 651 | + config5 &= ~MIPS_CONF5_MI; |
|---|
| 652 | + } |
|---|
| 653 | + |
|---|
| 844 | 654 | write_c0_config5(config5); |
|---|
| 845 | 655 | |
|---|
| 846 | 656 | if (config5 & MIPS_CONF5_EVA) |
|---|
| .. | .. |
|---|
| 858 | 668 | |
|---|
| 859 | 669 | if (config5 & MIPS_CONF5_CRCP) |
|---|
| 860 | 670 | elf_hwcap |= HWCAP_MIPS_CRC32; |
|---|
| 671 | + |
|---|
| 672 | + if (cpu_has_mips_r6) { |
|---|
| 673 | + /* Ensure the write to config5 above takes effect */ |
|---|
| 674 | + back_to_back_c0_hazard(); |
|---|
| 675 | + |
|---|
| 676 | + /* Check whether we successfully enabled MMID support */ |
|---|
| 677 | + config5 = read_c0_config5(); |
|---|
| 678 | + if (config5 & MIPS_CONF5_MI) |
|---|
| 679 | + c->options |= MIPS_CPU_MMID; |
|---|
| 680 | + |
|---|
| 681 | + /* |
|---|
| 682 | + * Warn if we've hardcoded cpu_has_mmid to a value unsuitable |
|---|
| 683 | + * for the CPU we're running on, or if CPUs in an SMP system |
|---|
| 684 | + * have inconsistent MMID support. |
|---|
| 685 | + */ |
|---|
| 686 | + WARN_ON(!!cpu_has_mmid != !!(config5 & MIPS_CONF5_MI)); |
|---|
| 687 | + |
|---|
| 688 | + if (cpu_has_mmid) { |
|---|
| 689 | + write_c0_memorymapid(~0ul); |
|---|
| 690 | + back_to_back_c0_hazard(); |
|---|
| 691 | + asid_mask = read_c0_memorymapid(); |
|---|
| 692 | + |
|---|
| 693 | + /* |
|---|
| 694 | + * We maintain a bitmap to track MMID allocation, and |
|---|
| 695 | + * need a sensible upper bound on the size of that |
|---|
| 696 | + * bitmap. The initial CPU with MMID support (I6500) |
|---|
| 697 | + * supports 16 bit MMIDs, which gives us an 8KiB |
|---|
| 698 | + * bitmap. The architecture recommends that hardware |
|---|
| 699 | + * support 32 bit MMIDs, which would give us a 512MiB |
|---|
| 700 | + * bitmap - that's too big in most cases. |
|---|
| 701 | + * |
|---|
| 702 | + * Cap MMID width at 16 bits for now & we can revisit |
|---|
| 703 | + * this if & when hardware supports anything wider. |
|---|
| 704 | + */ |
|---|
| 705 | + max_mmid_width = 16; |
|---|
| 706 | + if (asid_mask > GENMASK(max_mmid_width - 1, 0)) { |
|---|
| 707 | + pr_info("Capping MMID width at %d bits", |
|---|
| 708 | + max_mmid_width); |
|---|
| 709 | + asid_mask = GENMASK(max_mmid_width - 1, 0); |
|---|
| 710 | + } |
|---|
| 711 | + |
|---|
| 712 | + set_cpu_asid_mask(c, asid_mask); |
|---|
| 713 | + } |
|---|
| 714 | + } |
|---|
| 861 | 715 | |
|---|
| 862 | 716 | return config5 & MIPS_CONF_M; |
|---|
| 863 | 717 | } |
|---|
| .. | .. |
|---|
| 1300 | 1154 | break; |
|---|
| 1301 | 1155 | } |
|---|
| 1302 | 1156 | break; |
|---|
| 1303 | | - case PRID_IMP_R4300: |
|---|
| 1304 | | - c->cputype = CPU_R4300; |
|---|
| 1305 | | - __cpu_name[cpu] = "R4300"; |
|---|
| 1306 | | - set_isa(c, MIPS_CPU_ISA_III); |
|---|
| 1307 | | - c->fpu_msk31 |= FPU_CSR_CONDX; |
|---|
| 1308 | | - c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR | |
|---|
| 1309 | | - MIPS_CPU_LLSC; |
|---|
| 1310 | | - c->tlbsize = 32; |
|---|
| 1311 | | - break; |
|---|
| 1312 | 1157 | case PRID_IMP_R4600: |
|---|
| 1313 | 1158 | c->cputype = CPU_R4600; |
|---|
| 1314 | 1159 | __cpu_name[cpu] = "R4600"; |
|---|
| .. | .. |
|---|
| 1384 | 1229 | MIPS_CPU_LLSC; |
|---|
| 1385 | 1230 | c->tlbsize = 48; |
|---|
| 1386 | 1231 | break; |
|---|
| 1387 | | - case PRID_IMP_R5432: |
|---|
| 1388 | | - c->cputype = CPU_R5432; |
|---|
| 1389 | | - __cpu_name[cpu] = "R5432"; |
|---|
| 1390 | | - set_isa(c, MIPS_CPU_ISA_IV); |
|---|
| 1391 | | - c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR | |
|---|
| 1392 | | - MIPS_CPU_WATCH | MIPS_CPU_LLSC; |
|---|
| 1393 | | - c->tlbsize = 48; |
|---|
| 1394 | | - break; |
|---|
| 1395 | 1232 | case PRID_IMP_R5500: |
|---|
| 1396 | 1233 | c->cputype = CPU_R5500; |
|---|
| 1397 | 1234 | __cpu_name[cpu] = "R5500"; |
|---|
| .. | .. |
|---|
| 1424 | 1261 | */ |
|---|
| 1425 | 1262 | c->tlbsize = (read_c0_info() & (1 << 29)) ? 64 : 48; |
|---|
| 1426 | 1263 | break; |
|---|
| 1427 | | - case PRID_IMP_R8000: |
|---|
| 1428 | | - c->cputype = CPU_R8000; |
|---|
| 1429 | | - __cpu_name[cpu] = "RM8000"; |
|---|
| 1430 | | - set_isa(c, MIPS_CPU_ISA_IV); |
|---|
| 1431 | | - c->options = MIPS_CPU_TLB | MIPS_CPU_4KEX | |
|---|
| 1432 | | - MIPS_CPU_FPU | MIPS_CPU_32FPR | |
|---|
| 1433 | | - MIPS_CPU_LLSC; |
|---|
| 1434 | | - c->tlbsize = 384; /* has weird TLB: 3-way x 128 */ |
|---|
| 1435 | | - break; |
|---|
| 1436 | 1264 | case PRID_IMP_R10000: |
|---|
| 1437 | 1265 | c->cputype = CPU_R10000; |
|---|
| 1438 | 1266 | __cpu_name[cpu] = "R10000"; |
|---|
| .. | .. |
|---|
| 1450 | 1278 | c->options = MIPS_CPU_TLB | MIPS_CPU_4K_CACHE | MIPS_CPU_4KEX | |
|---|
| 1451 | 1279 | MIPS_CPU_FPU | MIPS_CPU_32FPR | |
|---|
| 1452 | 1280 | MIPS_CPU_COUNTER | MIPS_CPU_WATCH | |
|---|
| 1453 | | - MIPS_CPU_LLSC | MIPS_CPU_BP_GHIST; |
|---|
| 1281 | + MIPS_CPU_LLSC; |
|---|
| 1454 | 1282 | c->tlbsize = 64; |
|---|
| 1283 | + write_c0_r10k_diag(read_c0_r10k_diag() | R10K_DIAG_E_GHIST); |
|---|
| 1455 | 1284 | break; |
|---|
| 1456 | 1285 | case PRID_IMP_R14000: |
|---|
| 1457 | 1286 | if (((c->processor_id >> 4) & 0x0f) > 2) { |
|---|
| .. | .. |
|---|
| 1465 | 1294 | c->options = MIPS_CPU_TLB | MIPS_CPU_4K_CACHE | MIPS_CPU_4KEX | |
|---|
| 1466 | 1295 | MIPS_CPU_FPU | MIPS_CPU_32FPR | |
|---|
| 1467 | 1296 | MIPS_CPU_COUNTER | MIPS_CPU_WATCH | |
|---|
| 1468 | | - MIPS_CPU_LLSC | MIPS_CPU_BP_GHIST; |
|---|
| 1297 | + MIPS_CPU_LLSC; |
|---|
| 1469 | 1298 | c->tlbsize = 64; |
|---|
| 1299 | + write_c0_r10k_diag(read_c0_r10k_diag() | R10K_DIAG_E_GHIST); |
|---|
| 1470 | 1300 | break; |
|---|
| 1471 | | - case PRID_IMP_LOONGSON_64: /* Loongson-2/3 */ |
|---|
| 1301 | + case PRID_IMP_LOONGSON_64C: /* Loongson-2/3 */ |
|---|
| 1472 | 1302 | switch (c->processor_id & PRID_REV_MASK) { |
|---|
| 1473 | 1303 | case PRID_REV_LOONGSON2E: |
|---|
| 1474 | | - c->cputype = CPU_LOONGSON2; |
|---|
| 1304 | + c->cputype = CPU_LOONGSON2EF; |
|---|
| 1475 | 1305 | __cpu_name[cpu] = "ICT Loongson-2"; |
|---|
| 1476 | 1306 | set_elf_platform(cpu, "loongson2e"); |
|---|
| 1477 | 1307 | set_isa(c, MIPS_CPU_ISA_III); |
|---|
| 1478 | 1308 | c->fpu_msk31 |= FPU_CSR_CONDX; |
|---|
| 1479 | 1309 | break; |
|---|
| 1480 | 1310 | case PRID_REV_LOONGSON2F: |
|---|
| 1481 | | - c->cputype = CPU_LOONGSON2; |
|---|
| 1311 | + c->cputype = CPU_LOONGSON2EF; |
|---|
| 1482 | 1312 | __cpu_name[cpu] = "ICT Loongson-2"; |
|---|
| 1483 | 1313 | set_elf_platform(cpu, "loongson2f"); |
|---|
| 1484 | 1314 | set_isa(c, MIPS_CPU_ISA_III); |
|---|
| 1485 | 1315 | c->fpu_msk31 |= FPU_CSR_CONDX; |
|---|
| 1486 | 1316 | break; |
|---|
| 1487 | 1317 | case PRID_REV_LOONGSON3A_R1: |
|---|
| 1488 | | - c->cputype = CPU_LOONGSON3; |
|---|
| 1318 | + c->cputype = CPU_LOONGSON64; |
|---|
| 1489 | 1319 | __cpu_name[cpu] = "ICT Loongson-3"; |
|---|
| 1490 | 1320 | set_elf_platform(cpu, "loongson3a"); |
|---|
| 1491 | 1321 | set_isa(c, MIPS_CPU_ISA_M64R1); |
|---|
| .. | .. |
|---|
| 1494 | 1324 | break; |
|---|
| 1495 | 1325 | case PRID_REV_LOONGSON3B_R1: |
|---|
| 1496 | 1326 | case PRID_REV_LOONGSON3B_R2: |
|---|
| 1497 | | - c->cputype = CPU_LOONGSON3; |
|---|
| 1327 | + c->cputype = CPU_LOONGSON64; |
|---|
| 1498 | 1328 | __cpu_name[cpu] = "ICT Loongson-3"; |
|---|
| 1499 | 1329 | set_elf_platform(cpu, "loongson3b"); |
|---|
| 1500 | 1330 | set_isa(c, MIPS_CPU_ISA_M64R1); |
|---|
| .. | .. |
|---|
| 1507 | 1337 | MIPS_CPU_FPU | MIPS_CPU_LLSC | |
|---|
| 1508 | 1338 | MIPS_CPU_32FPR; |
|---|
| 1509 | 1339 | c->tlbsize = 64; |
|---|
| 1340 | + set_cpu_asid_mask(c, MIPS_ENTRYHI_ASID); |
|---|
| 1510 | 1341 | c->writecombine = _CACHE_UNCACHED_ACCELERATED; |
|---|
| 1511 | 1342 | break; |
|---|
| 1512 | 1343 | case PRID_IMP_LOONGSON_32: /* Loongson-1 */ |
|---|
| 1513 | 1344 | decode_configs(c); |
|---|
| 1514 | 1345 | |
|---|
| 1515 | | - c->cputype = CPU_LOONGSON1; |
|---|
| 1346 | + c->cputype = CPU_LOONGSON32; |
|---|
| 1516 | 1347 | |
|---|
| 1517 | 1348 | switch (c->processor_id & PRID_REV_MASK) { |
|---|
| 1518 | 1349 | case PRID_REV_LOONGSON1B: |
|---|
| .. | .. |
|---|
| 1660 | 1491 | |
|---|
| 1661 | 1492 | spram_config(); |
|---|
| 1662 | 1493 | |
|---|
| 1494 | + mm_config(c); |
|---|
| 1495 | + |
|---|
| 1663 | 1496 | switch (__get_cpu_type(c->cputype)) { |
|---|
| 1497 | + case CPU_M5150: |
|---|
| 1498 | + case CPU_P5600: |
|---|
| 1499 | + set_isa(c, MIPS_CPU_ISA_M32R5); |
|---|
| 1500 | + break; |
|---|
| 1664 | 1501 | case CPU_I6500: |
|---|
| 1665 | 1502 | c->options |= MIPS_CPU_SHARED_FTLB_ENTRIES; |
|---|
| 1666 | | - /* fall-through */ |
|---|
| 1503 | + fallthrough; |
|---|
| 1667 | 1504 | case CPU_I6400: |
|---|
| 1668 | 1505 | c->options |= MIPS_CPU_SHARED_FTLB_RAM; |
|---|
| 1669 | | - /* fall-through */ |
|---|
| 1506 | + fallthrough; |
|---|
| 1670 | 1507 | default: |
|---|
| 1508 | + break; |
|---|
| 1509 | + } |
|---|
| 1510 | + |
|---|
| 1511 | + /* Recent MIPS cores use the implementation-dependent ExcCode 16 for |
|---|
| 1512 | + * cache/FTLB parity exceptions. |
|---|
| 1513 | + */ |
|---|
| 1514 | + switch (__get_cpu_type(c->cputype)) { |
|---|
| 1515 | + case CPU_PROAPTIV: |
|---|
| 1516 | + case CPU_P5600: |
|---|
| 1517 | + case CPU_P6600: |
|---|
| 1518 | + case CPU_I6400: |
|---|
| 1519 | + case CPU_I6500: |
|---|
| 1520 | + c->options |= MIPS_CPU_FTLBPAREX; |
|---|
| 1671 | 1521 | break; |
|---|
| 1672 | 1522 | } |
|---|
| 1673 | 1523 | } |
|---|
| .. | .. |
|---|
| 1842 | 1692 | } |
|---|
| 1843 | 1693 | } |
|---|
| 1844 | 1694 | |
|---|
| 1695 | +#ifdef CONFIG_CPU_LOONGSON64 |
|---|
| 1696 | +#include <loongson_regs.h> |
|---|
| 1697 | + |
|---|
| 1698 | +static inline void decode_cpucfg(struct cpuinfo_mips *c) |
|---|
| 1699 | +{ |
|---|
| 1700 | + u32 cfg1 = read_cpucfg(LOONGSON_CFG1); |
|---|
| 1701 | + u32 cfg2 = read_cpucfg(LOONGSON_CFG2); |
|---|
| 1702 | + u32 cfg3 = read_cpucfg(LOONGSON_CFG3); |
|---|
| 1703 | + |
|---|
| 1704 | + if (cfg1 & LOONGSON_CFG1_MMI) |
|---|
| 1705 | + c->ases |= MIPS_ASE_LOONGSON_MMI; |
|---|
| 1706 | + |
|---|
| 1707 | + if (cfg2 & LOONGSON_CFG2_LEXT1) |
|---|
| 1708 | + c->ases |= MIPS_ASE_LOONGSON_EXT; |
|---|
| 1709 | + |
|---|
| 1710 | + if (cfg2 & LOONGSON_CFG2_LEXT2) |
|---|
| 1711 | + c->ases |= MIPS_ASE_LOONGSON_EXT2; |
|---|
| 1712 | + |
|---|
| 1713 | + if (cfg2 & LOONGSON_CFG2_LSPW) { |
|---|
| 1714 | + c->options |= MIPS_CPU_LDPTE; |
|---|
| 1715 | + c->guest.options |= MIPS_CPU_LDPTE; |
|---|
| 1716 | + } |
|---|
| 1717 | + |
|---|
| 1718 | + if (cfg3 & LOONGSON_CFG3_LCAMP) |
|---|
| 1719 | + c->ases |= MIPS_ASE_LOONGSON_CAM; |
|---|
| 1720 | +} |
|---|
| 1721 | + |
|---|
| 1845 | 1722 | static inline void cpu_probe_loongson(struct cpuinfo_mips *c, unsigned int cpu) |
|---|
| 1846 | 1723 | { |
|---|
| 1724 | + /* All Loongson processors covered here define ExcCode 16 as GSExc. */ |
|---|
| 1725 | + c->options |= MIPS_CPU_GSEXCEX; |
|---|
| 1726 | + |
|---|
| 1847 | 1727 | switch (c->processor_id & PRID_IMP_MASK) { |
|---|
| 1848 | | - case PRID_IMP_LOONGSON_64: /* Loongson-2/3 */ |
|---|
| 1728 | + case PRID_IMP_LOONGSON_64R: /* Loongson-64 Reduced */ |
|---|
| 1849 | 1729 | switch (c->processor_id & PRID_REV_MASK) { |
|---|
| 1850 | | - case PRID_REV_LOONGSON3A_R2: |
|---|
| 1851 | | - c->cputype = CPU_LOONGSON3; |
|---|
| 1730 | + case PRID_REV_LOONGSON2K_R1_0: |
|---|
| 1731 | + case PRID_REV_LOONGSON2K_R1_1: |
|---|
| 1732 | + case PRID_REV_LOONGSON2K_R1_2: |
|---|
| 1733 | + case PRID_REV_LOONGSON2K_R1_3: |
|---|
| 1734 | + c->cputype = CPU_LOONGSON64; |
|---|
| 1735 | + __cpu_name[cpu] = "Loongson-2K"; |
|---|
| 1736 | + set_elf_platform(cpu, "gs264e"); |
|---|
| 1737 | + set_isa(c, MIPS_CPU_ISA_M64R2); |
|---|
| 1738 | + break; |
|---|
| 1739 | + } |
|---|
| 1740 | + c->ases |= (MIPS_ASE_LOONGSON_MMI | MIPS_ASE_LOONGSON_EXT | |
|---|
| 1741 | + MIPS_ASE_LOONGSON_EXT2); |
|---|
| 1742 | + break; |
|---|
| 1743 | + case PRID_IMP_LOONGSON_64C: /* Loongson-3 Classic */ |
|---|
| 1744 | + switch (c->processor_id & PRID_REV_MASK) { |
|---|
| 1745 | + case PRID_REV_LOONGSON3A_R2_0: |
|---|
| 1746 | + case PRID_REV_LOONGSON3A_R2_1: |
|---|
| 1747 | + c->cputype = CPU_LOONGSON64; |
|---|
| 1852 | 1748 | __cpu_name[cpu] = "ICT Loongson-3"; |
|---|
| 1853 | 1749 | set_elf_platform(cpu, "loongson3a"); |
|---|
| 1854 | 1750 | set_isa(c, MIPS_CPU_ISA_M64R2); |
|---|
| 1855 | 1751 | break; |
|---|
| 1856 | 1752 | case PRID_REV_LOONGSON3A_R3_0: |
|---|
| 1857 | 1753 | case PRID_REV_LOONGSON3A_R3_1: |
|---|
| 1858 | | - c->cputype = CPU_LOONGSON3; |
|---|
| 1754 | + c->cputype = CPU_LOONGSON64; |
|---|
| 1859 | 1755 | __cpu_name[cpu] = "ICT Loongson-3"; |
|---|
| 1860 | 1756 | set_elf_platform(cpu, "loongson3a"); |
|---|
| 1861 | 1757 | set_isa(c, MIPS_CPU_ISA_M64R2); |
|---|
| 1862 | 1758 | break; |
|---|
| 1863 | 1759 | } |
|---|
| 1864 | | - |
|---|
| 1865 | | - decode_configs(c); |
|---|
| 1760 | + /* |
|---|
| 1761 | + * Loongson-3 Classic did not implement MIPS standard TLBINV |
|---|
| 1762 | + * but implemented TLBINVF and EHINV. As currently we're only |
|---|
| 1763 | + * using these two features, enable MIPS_CPU_TLBINV as well. |
|---|
| 1764 | + * |
|---|
| 1765 | + * Also some early Loongson-3A2000 had wrong TLB type in Config |
|---|
| 1766 | + * register, we correct it here. |
|---|
| 1767 | + */ |
|---|
| 1866 | 1768 | c->options |= MIPS_CPU_FTLB | MIPS_CPU_TLBINV | MIPS_CPU_LDPTE; |
|---|
| 1867 | | - c->writecombine = _CACHE_UNCACHED_ACCELERATED; |
|---|
| 1868 | 1769 | c->ases |= (MIPS_ASE_LOONGSON_MMI | MIPS_ASE_LOONGSON_CAM | |
|---|
| 1869 | 1770 | MIPS_ASE_LOONGSON_EXT | MIPS_ASE_LOONGSON_EXT2); |
|---|
| 1771 | + c->ases &= ~MIPS_ASE_VZ; /* VZ of Loongson-3A2000/3000 is incomplete */ |
|---|
| 1772 | + break; |
|---|
| 1773 | + case PRID_IMP_LOONGSON_64G: |
|---|
| 1774 | + c->cputype = CPU_LOONGSON64; |
|---|
| 1775 | + __cpu_name[cpu] = "ICT Loongson-3"; |
|---|
| 1776 | + set_elf_platform(cpu, "loongson3a"); |
|---|
| 1777 | + set_isa(c, MIPS_CPU_ISA_M64R2); |
|---|
| 1778 | + decode_cpucfg(c); |
|---|
| 1870 | 1779 | break; |
|---|
| 1871 | 1780 | default: |
|---|
| 1872 | 1781 | panic("Unknown Loongson Processor ID!"); |
|---|
| 1873 | 1782 | break; |
|---|
| 1874 | 1783 | } |
|---|
| 1784 | + |
|---|
| 1785 | + decode_configs(c); |
|---|
| 1875 | 1786 | } |
|---|
| 1787 | +#else |
|---|
| 1788 | +static inline void cpu_probe_loongson(struct cpuinfo_mips *c, unsigned int cpu) { } |
|---|
| 1789 | +#endif |
|---|
| 1876 | 1790 | |
|---|
| 1877 | 1791 | static inline void cpu_probe_ingenic(struct cpuinfo_mips *c, unsigned int cpu) |
|---|
| 1878 | 1792 | { |
|---|
| 1879 | 1793 | decode_configs(c); |
|---|
| 1880 | | - /* JZRISC does not implement the CP0 counter. */ |
|---|
| 1794 | + |
|---|
| 1795 | + /* |
|---|
| 1796 | + * XBurst misses a config2 register, so config3 decode was skipped in |
|---|
| 1797 | + * decode_configs(). |
|---|
| 1798 | + */ |
|---|
| 1799 | + decode_config3(c); |
|---|
| 1800 | + |
|---|
| 1801 | + /* XBurst does not implement the CP0 counter. */ |
|---|
| 1881 | 1802 | c->options &= ~MIPS_CPU_COUNTER; |
|---|
| 1882 | | - BUG_ON(!__builtin_constant_p(cpu_has_counter) || cpu_has_counter); |
|---|
| 1803 | + BUG_ON(__builtin_constant_p(cpu_has_counter) && cpu_has_counter); |
|---|
| 1804 | + |
|---|
| 1805 | + /* XBurst has virtually tagged icache */ |
|---|
| 1806 | + c->icache.flags |= MIPS_CACHE_VTAG; |
|---|
| 1807 | + |
|---|
| 1883 | 1808 | switch (c->processor_id & PRID_IMP_MASK) { |
|---|
| 1884 | | - case PRID_IMP_JZRISC: |
|---|
| 1885 | | - c->cputype = CPU_JZRISC; |
|---|
| 1886 | | - c->writecombine = _CACHE_UNCACHED_ACCELERATED; |
|---|
| 1887 | | - __cpu_name[cpu] = "Ingenic JZRISC"; |
|---|
| 1809 | + |
|---|
| 1810 | + /* XBurst®1 with MXU1.0/MXU1.1 SIMD ISA */ |
|---|
| 1811 | + case PRID_IMP_XBURST_REV1: |
|---|
| 1812 | + |
|---|
| 1888 | 1813 | /* |
|---|
| 1889 | 1814 | * The XBurst core by default attempts to avoid branch target |
|---|
| 1890 | 1815 | * buffer lookups by detecting & special casing loops. This |
|---|
| .. | .. |
|---|
| 1892 | 1817 | * Set cp0 config7 bit 4 to disable this feature. |
|---|
| 1893 | 1818 | */ |
|---|
| 1894 | 1819 | set_c0_config7(MIPS_CONF7_BTB_LOOP_EN); |
|---|
| 1820 | + |
|---|
| 1821 | + switch (c->processor_id & PRID_COMP_MASK) { |
|---|
| 1822 | + |
|---|
| 1823 | + /* |
|---|
| 1824 | + * The config0 register in the XBurst CPUs with a processor ID of |
|---|
| 1825 | + * PRID_COMP_INGENIC_D0 report themselves as MIPS32r2 compatible, |
|---|
| 1826 | + * but they don't actually support this ISA. |
|---|
| 1827 | + */ |
|---|
| 1828 | + case PRID_COMP_INGENIC_D0: |
|---|
| 1829 | + c->isa_level &= ~MIPS_CPU_ISA_M32R2; |
|---|
| 1830 | + |
|---|
| 1831 | + /* FPU is not properly detected on JZ4760(B). */ |
|---|
| 1832 | + if (c->processor_id == 0x2ed0024f) |
|---|
| 1833 | + c->options |= MIPS_CPU_FPU; |
|---|
| 1834 | + |
|---|
| 1835 | + fallthrough; |
|---|
| 1836 | + |
|---|
| 1837 | + /* |
|---|
| 1838 | + * The config0 register in the XBurst CPUs with a processor ID of |
|---|
| 1839 | + * PRID_COMP_INGENIC_D0 or PRID_COMP_INGENIC_D1 has an abandoned |
|---|
| 1840 | + * huge page tlb mode, this mode is not compatible with the MIPS |
|---|
| 1841 | + * standard, it will cause tlbmiss and into an infinite loop |
|---|
| 1842 | + * (line 21 in the tlb-funcs.S) when starting the init process. |
|---|
| 1843 | + * After chip reset, the default is HPTLB mode, Write 0xa9000000 |
|---|
| 1844 | + * to cp0 register 5 sel 4 to switch back to VTLB mode to prevent |
|---|
| 1845 | + * getting stuck. |
|---|
| 1846 | + */ |
|---|
| 1847 | + case PRID_COMP_INGENIC_D1: |
|---|
| 1848 | + write_c0_page_ctrl(XBURST_PAGECTRL_HPTLB_DIS); |
|---|
| 1849 | + break; |
|---|
| 1850 | + |
|---|
| 1851 | + default: |
|---|
| 1852 | + break; |
|---|
| 1853 | + } |
|---|
| 1854 | + fallthrough; |
|---|
| 1855 | + |
|---|
| 1856 | + /* XBurst®1 with MXU2.0 SIMD ISA */ |
|---|
| 1857 | + case PRID_IMP_XBURST_REV2: |
|---|
| 1858 | + /* Ingenic uses the WA bit to achieve write-combine memory writes */ |
|---|
| 1859 | + c->writecombine = _CACHE_CACHABLE_WA; |
|---|
| 1860 | + c->cputype = CPU_XBURST; |
|---|
| 1861 | + __cpu_name[cpu] = "Ingenic XBurst"; |
|---|
| 1895 | 1862 | break; |
|---|
| 1863 | + |
|---|
| 1864 | + /* XBurst®2 with MXU2.1 SIMD ISA */ |
|---|
| 1865 | + case PRID_IMP_XBURST2: |
|---|
| 1866 | + c->cputype = CPU_XBURST; |
|---|
| 1867 | + __cpu_name[cpu] = "Ingenic XBurst II"; |
|---|
| 1868 | + break; |
|---|
| 1869 | + |
|---|
| 1896 | 1870 | default: |
|---|
| 1897 | 1871 | panic("Unknown Ingenic Processor ID!"); |
|---|
| 1898 | 1872 | break; |
|---|
| .. | .. |
|---|
| 1988 | 1962 | |
|---|
| 1989 | 1963 | const char *__cpu_name[NR_CPUS]; |
|---|
| 1990 | 1964 | const char *__elf_platform; |
|---|
| 1965 | +const char *__elf_base_platform; |
|---|
| 1991 | 1966 | |
|---|
| 1992 | 1967 | void cpu_probe(void) |
|---|
| 1993 | 1968 | { |
|---|
| .. | .. |
|---|
| 2037 | 2012 | case PRID_COMP_LOONGSON: |
|---|
| 2038 | 2013 | cpu_probe_loongson(c, cpu); |
|---|
| 2039 | 2014 | break; |
|---|
| 2015 | + case PRID_COMP_INGENIC_13: |
|---|
| 2040 | 2016 | case PRID_COMP_INGENIC_D0: |
|---|
| 2041 | 2017 | case PRID_COMP_INGENIC_D1: |
|---|
| 2042 | 2018 | case PRID_COMP_INGENIC_E1: |
|---|
| .. | .. |
|---|
| 2082 | 2058 | cpu_set_fpu_opts(c); |
|---|
| 2083 | 2059 | else |
|---|
| 2084 | 2060 | cpu_set_nofpu_opts(c); |
|---|
| 2085 | | - |
|---|
| 2086 | | - if (cpu_has_bp_ghist) |
|---|
| 2087 | | - write_c0_r10k_diag(read_c0_r10k_diag() | |
|---|
| 2088 | | - R10K_DIAG_E_GHIST); |
|---|
| 2089 | 2061 | |
|---|
| 2090 | 2062 | if (cpu_has_mips_r2_r6) { |
|---|
| 2091 | 2063 | c->srsets = ((read_c0_srsctl() >> 26) & 0x0f) + 1; |
|---|
| .. | .. |
|---|
| 2143 | 2115 | |
|---|
| 2144 | 2116 | cpu_probe_vmbits(c); |
|---|
| 2145 | 2117 | |
|---|
| 2118 | + /* Synthesize CPUCFG data if running on Loongson processors; |
|---|
| 2119 | + * no-op otherwise. |
|---|
| 2120 | + * |
|---|
| 2121 | + * This looks at previously probed features, so keep this at bottom. |
|---|
| 2122 | + */ |
|---|
| 2123 | + loongson3_cpucfg_synthesize_data(c); |
|---|
| 2124 | + |
|---|
| 2146 | 2125 | #ifdef CONFIG_64BIT |
|---|
| 2147 | 2126 | if (cpu == 0) |
|---|
| 2148 | 2127 | __ua_limit = ~((1ull << cpu_vmbits) - 1); |
|---|