1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Processor capabilities determination functions. 4 * 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. 9 */ 10 #include <linux/init.h> 11 #include <linux/kernel.h> 12 #include <linux/ptrace.h> 13 #include <linux/smp.h> 14 #include <linux/stddef.h> 15 #include <linux/export.h> 16 17 #include <asm/bugs.h> 18 #include <asm/cpu.h> 19 #include <asm/cpu-features.h> 20 #include <asm/cpu-type.h> 21 #include <asm/fpu.h> 22 #include <asm/mipsregs.h> 23 #include <asm/elf.h> 24 #include <asm/traps.h> 25 26 #include "fpu-probe.h" 27 28 /* Hardware capabilities */ 29 unsigned int elf_hwcap __read_mostly; 30 EXPORT_SYMBOL_GPL(elf_hwcap); 31 32 void __init check_bugs32(void) 33 { 34 35 } 36 37 /* 38 * Probe whether cpu has config register by trying to play with 39 * alternate cache bit and see whether it matters. 40 * It's used by cpu_probe to distinguish between R3000A and R3081. 41 */ 42 static inline int cpu_has_confreg(void) 43 { 44 #ifdef CONFIG_CPU_R3000 45 extern unsigned long r3k_cache_size(unsigned long); 46 unsigned long size1, size2; 47 unsigned long cfg = read_c0_conf(); 48 49 size1 = r3k_cache_size(ST0_ISC); 50 write_c0_conf(cfg ^ R30XX_CONF_AC); 51 size2 = r3k_cache_size(ST0_ISC); 52 write_c0_conf(cfg); 53 return size1 != size2; 54 #else 55 return 0; 56 #endif 57 } 58 59 static inline void set_elf_platform(int cpu, const char *plat) 60 { 61 if (cpu == 0) 62 __elf_platform = plat; 63 } 64 65 const char *__cpu_name[NR_CPUS]; 66 const char *__elf_platform; 67 const char *__elf_base_platform; 68 69 void cpu_probe(void) 70 { 71 struct cpuinfo_mips *c = ¤t_cpu_data; 72 unsigned int cpu = smp_processor_id(); 73 74 /* 75 * Set a default elf platform, cpu probe may later 76 * overwrite it with a more precise value 77 */ 78 set_elf_platform(cpu, "mips"); 79 80 c->processor_id = PRID_IMP_UNKNOWN; 81 c->fpu_id = FPIR_IMP_NONE; 82 c->cputype = CPU_UNKNOWN; 83 c->writecombine = _CACHE_UNCACHED; 84 85 c->fpu_csr31 = FPU_CSR_RN; 86 c->fpu_msk31 = FPU_CSR_RSVD | FPU_CSR_ABS2008 | FPU_CSR_NAN2008 | 87 FPU_CSR_CONDX | FPU_CSR_FS; 88 89 c->srsets = 1; 90 91 c->processor_id = read_c0_prid(); 92 switch (c->processor_id & (PRID_COMP_MASK | PRID_IMP_MASK)) { 93 case PRID_COMP_LEGACY | PRID_IMP_R2000: 94 c->cputype = CPU_R2000; 95 __cpu_name[cpu] = "R2000"; 96 c->options = MIPS_CPU_TLB | MIPS_CPU_3K_CACHE | 97 MIPS_CPU_NOFPUEX; 98 if (__cpu_has_fpu()) 99 c->options |= MIPS_CPU_FPU; 100 c->tlbsize = 64; 101 break; 102 case PRID_COMP_LEGACY | PRID_IMP_R3000: 103 if ((c->processor_id & PRID_REV_MASK) == PRID_REV_R3000A) { 104 if (cpu_has_confreg()) { 105 c->cputype = CPU_R3081E; 106 __cpu_name[cpu] = "R3081"; 107 } else { 108 c->cputype = CPU_R3000A; 109 __cpu_name[cpu] = "R3000A"; 110 } 111 } else { 112 c->cputype = CPU_R3000; 113 __cpu_name[cpu] = "R3000"; 114 } 115 c->options = MIPS_CPU_TLB | MIPS_CPU_3K_CACHE | 116 MIPS_CPU_NOFPUEX; 117 if (__cpu_has_fpu()) 118 c->options |= MIPS_CPU_FPU; 119 c->tlbsize = 64; 120 break; 121 case PRID_COMP_LEGACY | PRID_IMP_TX39: 122 c->options = MIPS_CPU_TLB | MIPS_CPU_TX39_CACHE; 123 124 if ((c->processor_id & 0xf0) == (PRID_REV_TX3927 & 0xf0)) { 125 c->cputype = CPU_TX3927; 126 __cpu_name[cpu] = "TX3927"; 127 c->tlbsize = 64; 128 } else { 129 switch (c->processor_id & PRID_REV_MASK) { 130 case PRID_REV_TX3912: 131 c->cputype = CPU_TX3912; 132 __cpu_name[cpu] = "TX3912"; 133 c->tlbsize = 32; 134 break; 135 case PRID_REV_TX3922: 136 c->cputype = CPU_TX3922; 137 __cpu_name[cpu] = "TX3922"; 138 c->tlbsize = 64; 139 break; 140 } 141 } 142 break; 143 } 144 145 BUG_ON(!__cpu_name[cpu]); 146 BUG_ON(c->cputype == CPU_UNKNOWN); 147 148 /* 149 * Platform code can force the cpu type to optimize code 150 * generation. In that case be sure the cpu type is correctly 151 * manually setup otherwise it could trigger some nasty bugs. 152 */ 153 BUG_ON(current_cpu_type() != c->cputype); 154 155 if (mips_fpu_disabled) 156 c->options &= ~MIPS_CPU_FPU; 157 158 if (c->options & MIPS_CPU_FPU) 159 cpu_set_fpu_opts(c); 160 else 161 cpu_set_nofpu_opts(c); 162 163 reserve_exception_space(0, 0x400); 164 } 165 166 void cpu_report(void) 167 { 168 struct cpuinfo_mips *c = ¤t_cpu_data; 169 170 pr_info("CPU%d revision is: %08x (%s)\n", 171 smp_processor_id(), c->processor_id, cpu_name_string()); 172 if (c->options & MIPS_CPU_FPU) 173 pr_info("FPU revision is: %08x\n", c->fpu_id); 174 } 175