| // SPDX-License-Identifier: GPL-2.0-or-later | |
| /* | |
| * Processor capabilities determination functions. | |
| * | |
| * Copyright (C) xxxx the Anonymous | |
| * Copyright (C) 1994 - 2006 Ralf Baechle | |
| * Copyright (C) 2003, 2004 Maciej W. Rozycki | |
| * Copyright (C) 2001, 2004, 2011, 2012 MIPS Technologies, Inc. | |
| */ | |
| #include <linux/init.h> | |
| #include <linux/kernel.h> | |
| #include <linux/ptrace.h> | |
| #include <linux/smp.h> | |
| #include <linux/stddef.h> | |
| #include <linux/export.h> | |
| #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/elf.h> | |
| #include <asm/traps.h> | |
| #include "fpu-probe.h" | |
| /* Hardware capabilities */ | |
| unsigned int elf_hwcap __read_mostly; | |
| EXPORT_SYMBOL_GPL(elf_hwcap); | |
| void __init check_bugs32(void) | |
| { | |
| } | |
| /* | |
| * Probe whether cpu has config register by trying to play with | |
| * alternate cache bit and see whether it matters. | |
| * It's used by cpu_probe to distinguish between R3000A and R3081. | |
| */ | |
| static inline int cpu_has_confreg(void) | |
| { | |
| #ifdef CONFIG_CPU_R3000 | |
| unsigned long size1, size2; | |
| unsigned long cfg = read_c0_conf(); | |
| size1 = r3k_cache_size(ST0_ISC); | |
| write_c0_conf(cfg ^ R30XX_CONF_AC); | |
| size2 = r3k_cache_size(ST0_ISC); | |
| write_c0_conf(cfg); | |
| return size1 != size2; | |
| #else | |
| return 0; | |
| #endif | |
| } | |
| static inline void set_elf_platform(int cpu, const char *plat) | |
| { | |
| if (cpu == 0) | |
| __elf_platform = plat; | |
| } | |
| const char *__cpu_name[NR_CPUS]; | |
| const char *__elf_platform; | |
| const char *__elf_base_platform; | |
| void cpu_probe(void) | |
| { | |
| struct cpuinfo_mips *c = ¤t_cpu_data; | |
| unsigned int cpu = smp_processor_id(); | |
| /* | |
| * Set a default elf platform, cpu probe may later | |
| * overwrite it with a more precise value | |
| */ | |
| set_elf_platform(cpu, "mips"); | |
| c->processor_id = PRID_IMP_UNKNOWN; | |
| c->fpu_id = FPIR_IMP_NONE; | |
| 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 | | |
| FPU_CSR_CONDX | FPU_CSR_FS; | |
| c->srsets = 1; | |
| c->processor_id = read_c0_prid(); | |
| switch (c->processor_id & (PRID_COMP_MASK | PRID_IMP_MASK)) { | |
| case PRID_COMP_LEGACY | PRID_IMP_R2000: | |
| c->cputype = CPU_R2000; | |
| __cpu_name[cpu] = "R2000"; | |
| c->options = MIPS_CPU_TLB | MIPS_CPU_3K_CACHE | | |
| MIPS_CPU_NOFPUEX; | |
| if (__cpu_has_fpu()) | |
| c->options |= MIPS_CPU_FPU; | |
| c->tlbsize = 64; | |
| break; | |
| case PRID_COMP_LEGACY | PRID_IMP_R3000: | |
| if ((c->processor_id & PRID_REV_MASK) == PRID_REV_R3000A) { | |
| if (cpu_has_confreg()) { | |
| c->cputype = CPU_R3081E; | |
| __cpu_name[cpu] = "R3081"; | |
| } else { | |
| c->cputype = CPU_R3000A; | |
| __cpu_name[cpu] = "R3000A"; | |
| } | |
| } else { | |
| c->cputype = CPU_R3000; | |
| __cpu_name[cpu] = "R3000"; | |
| } | |
| c->options = MIPS_CPU_TLB | MIPS_CPU_3K_CACHE | | |
| MIPS_CPU_NOFPUEX; | |
| if (__cpu_has_fpu()) | |
| c->options |= MIPS_CPU_FPU; | |
| c->tlbsize = 64; | |
| break; | |
| } | |
| BUG_ON(!__cpu_name[cpu]); | |
| BUG_ON(c->cputype == CPU_UNKNOWN); | |
| /* | |
| * Platform code can force the cpu type to optimize code | |
| * generation. In that case be sure the cpu type is correctly | |
| * manually setup otherwise it could trigger some nasty bugs. | |
| */ | |
| BUG_ON(current_cpu_type() != c->cputype); | |
| if (mips_fpu_disabled) | |
| c->options &= ~MIPS_CPU_FPU; | |
| if (c->options & MIPS_CPU_FPU) | |
| cpu_set_fpu_opts(c); | |
| else | |
| cpu_set_nofpu_opts(c); | |
| c->vmbits = 31; | |
| reserve_exception_space(0, 0x400); | |
| } | |
| void cpu_report(void) | |
| { | |
| struct cpuinfo_mips *c = ¤t_cpu_data; | |
| pr_info("CPU%d revision is: %08x (%s)\n", | |
| smp_processor_id(), c->processor_id, cpu_name_string()); | |
| if (c->options & MIPS_CPU_FPU) | |
| pr_info("FPU revision is: %08x\n", c->fpu_id); | |
| } |