blob: af654771918cdd0873b5046310c5a0fc77253075 [file] [log] [blame]
Thomas Bogendoerfer90c68c62020-10-08 23:33:26 +02001// 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>
Thomas Bogendoerferbd67b712021-03-08 10:24:47 +010024#include <asm/traps.h>
Thomas Bogendoerfer90c68c62020-10-08 23:33:26 +020025
26#include "fpu-probe.h"
27
28/* Hardware capabilities */
29unsigned int elf_hwcap __read_mostly;
30EXPORT_SYMBOL_GPL(elf_hwcap);
31
32void __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 */
42static 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
59static inline void set_elf_platform(int cpu, const char *plat)
60{
61 if (cpu == 0)
62 __elf_platform = plat;
63}
64
65const char *__cpu_name[NR_CPUS];
66const char *__elf_platform;
67const char *__elf_base_platform;
68
69void cpu_probe(void)
70{
71 struct cpuinfo_mips *c = &current_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);
Thomas Bogendoerferbd67b712021-03-08 10:24:47 +0100162
163 reserve_exception_space(0, 0x400);
Thomas Bogendoerfer90c68c62020-10-08 23:33:26 +0200164}
165
166void cpu_report(void)
167{
168 struct cpuinfo_mips *c = &current_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}