Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/mips/loongson64/cpucfg-emul.c
26451 views
1
// SPDX-License-Identifier: GPL-2.0
2
3
#include <linux/smp.h>
4
#include <linux/types.h>
5
#include <asm/cpu.h>
6
#include <asm/cpu-info.h>
7
#include <asm/elf.h>
8
9
#include <loongson_regs.h>
10
#include <cpucfg-emul.h>
11
12
static bool is_loongson(struct cpuinfo_mips *c)
13
{
14
switch (c->processor_id & PRID_COMP_MASK) {
15
case PRID_COMP_LEGACY:
16
return ((c->processor_id & PRID_IMP_MASK) ==
17
PRID_IMP_LOONGSON_64C);
18
19
case PRID_COMP_LOONGSON:
20
return true;
21
22
default:
23
return false;
24
}
25
}
26
27
static u32 get_loongson_fprev(struct cpuinfo_mips *c)
28
{
29
return c->fpu_id & LOONGSON_FPREV_MASK;
30
}
31
32
static bool cpu_has_uca(void)
33
{
34
u32 diag = read_c0_diag();
35
u32 new_diag;
36
37
if (diag & LOONGSON_DIAG_UCAC)
38
/* UCA is already enabled. */
39
return true;
40
41
/* See if UCAC bit can be flipped on. This should be safe. */
42
new_diag = diag | LOONGSON_DIAG_UCAC;
43
write_c0_diag(new_diag);
44
new_diag = read_c0_diag();
45
write_c0_diag(diag);
46
47
return (new_diag & LOONGSON_DIAG_UCAC) != 0;
48
}
49
50
static void probe_uca(struct cpuinfo_mips *c)
51
{
52
if (cpu_has_uca())
53
c->loongson3_cpucfg_data[0] |= LOONGSON_CFG1_LSUCA;
54
}
55
56
static void decode_loongson_config6(struct cpuinfo_mips *c)
57
{
58
u32 config6 = read_c0_config6();
59
60
if (config6 & LOONGSON_CONF6_SFBEN)
61
c->loongson3_cpucfg_data[0] |= LOONGSON_CFG1_SFBP;
62
if (config6 & LOONGSON_CONF6_LLEXC)
63
c->loongson3_cpucfg_data[0] |= LOONGSON_CFG1_LLEXC;
64
if (config6 & LOONGSON_CONF6_SCRAND)
65
c->loongson3_cpucfg_data[0] |= LOONGSON_CFG1_SCRAND;
66
}
67
68
static void patch_cpucfg_sel1(struct cpuinfo_mips *c)
69
{
70
u64 ases = c->ases;
71
u64 options = c->options;
72
u32 data = c->loongson3_cpucfg_data[0];
73
74
if (options & MIPS_CPU_FPU) {
75
data |= LOONGSON_CFG1_FP;
76
data |= get_loongson_fprev(c) << LOONGSON_CFG1_FPREV_OFFSET;
77
}
78
if (ases & MIPS_ASE_LOONGSON_MMI)
79
data |= LOONGSON_CFG1_MMI;
80
if (ases & MIPS_ASE_MSA)
81
data |= LOONGSON_CFG1_MSA1;
82
83
c->loongson3_cpucfg_data[0] = data;
84
}
85
86
static void patch_cpucfg_sel2(struct cpuinfo_mips *c)
87
{
88
u64 ases = c->ases;
89
u64 options = c->options;
90
u32 data = c->loongson3_cpucfg_data[1];
91
92
if (ases & MIPS_ASE_LOONGSON_EXT)
93
data |= LOONGSON_CFG2_LEXT1;
94
if (ases & MIPS_ASE_LOONGSON_EXT2)
95
data |= LOONGSON_CFG2_LEXT2;
96
if (options & MIPS_CPU_LDPTE)
97
data |= LOONGSON_CFG2_LSPW;
98
99
if (ases & MIPS_ASE_VZ)
100
data |= LOONGSON_CFG2_LVZP;
101
else
102
data &= ~LOONGSON_CFG2_LVZREV;
103
104
c->loongson3_cpucfg_data[1] = data;
105
}
106
107
static void patch_cpucfg_sel3(struct cpuinfo_mips *c)
108
{
109
u64 ases = c->ases;
110
u32 data = c->loongson3_cpucfg_data[2];
111
112
if (ases & MIPS_ASE_LOONGSON_CAM) {
113
data |= LOONGSON_CFG3_LCAMP;
114
} else {
115
data &= ~LOONGSON_CFG3_LCAMREV;
116
data &= ~LOONGSON_CFG3_LCAMNUM;
117
data &= ~LOONGSON_CFG3_LCAMKW;
118
data &= ~LOONGSON_CFG3_LCAMVW;
119
}
120
121
c->loongson3_cpucfg_data[2] = data;
122
}
123
124
void loongson3_cpucfg_synthesize_data(struct cpuinfo_mips *c)
125
{
126
/* Only engage the logic on Loongson processors. */
127
if (!is_loongson(c))
128
return;
129
130
/* CPUs with CPUCFG support don't need to synthesize anything. */
131
if (cpu_has_cfg())
132
goto have_cpucfg_now;
133
134
c->loongson3_cpucfg_data[0] = 0;
135
c->loongson3_cpucfg_data[1] = 0;
136
c->loongson3_cpucfg_data[2] = 0;
137
138
/* Add CPUCFG features non-discoverable otherwise. */
139
switch (c->processor_id & (PRID_IMP_MASK | PRID_REV_MASK)) {
140
case PRID_IMP_LOONGSON_64R | PRID_REV_LOONGSON2K_R1_0:
141
case PRID_IMP_LOONGSON_64R | PRID_REV_LOONGSON2K_R1_1:
142
case PRID_IMP_LOONGSON_64R | PRID_REV_LOONGSON2K_R1_2:
143
case PRID_IMP_LOONGSON_64R | PRID_REV_LOONGSON2K_R1_3:
144
decode_loongson_config6(c);
145
probe_uca(c);
146
147
c->loongson3_cpucfg_data[0] |= (LOONGSON_CFG1_LSLDR0 |
148
LOONGSON_CFG1_LSSYNCI | LOONGSON_CFG1_LLSYNC |
149
LOONGSON_CFG1_TGTSYNC);
150
c->loongson3_cpucfg_data[1] |= (LOONGSON_CFG2_LBT1 |
151
LOONGSON_CFG2_LBT2 | LOONGSON_CFG2_LPMP |
152
LOONGSON_CFG2_LPM_REV2);
153
c->loongson3_cpucfg_data[2] = 0;
154
break;
155
156
case PRID_IMP_LOONGSON_64C | PRID_REV_LOONGSON3A_R1:
157
c->loongson3_cpucfg_data[0] |= (LOONGSON_CFG1_LSLDR0 |
158
LOONGSON_CFG1_LSSYNCI | LOONGSON_CFG1_LSUCA |
159
LOONGSON_CFG1_LLSYNC | LOONGSON_CFG1_TGTSYNC);
160
c->loongson3_cpucfg_data[1] |= (LOONGSON_CFG2_LBT1 |
161
LOONGSON_CFG2_LPMP | LOONGSON_CFG2_LPM_REV1);
162
c->loongson3_cpucfg_data[2] |= (
163
LOONGSON_CFG3_LCAM_REV1 |
164
LOONGSON_CFG3_LCAMNUM_REV1 |
165
LOONGSON_CFG3_LCAMKW_REV1 |
166
LOONGSON_CFG3_LCAMVW_REV1);
167
break;
168
169
case PRID_IMP_LOONGSON_64C | PRID_REV_LOONGSON3B_R1:
170
case PRID_IMP_LOONGSON_64C | PRID_REV_LOONGSON3B_R2:
171
c->loongson3_cpucfg_data[0] |= (LOONGSON_CFG1_LSLDR0 |
172
LOONGSON_CFG1_LSSYNCI | LOONGSON_CFG1_LSUCA |
173
LOONGSON_CFG1_LLSYNC | LOONGSON_CFG1_TGTSYNC);
174
c->loongson3_cpucfg_data[1] |= (LOONGSON_CFG2_LBT1 |
175
LOONGSON_CFG2_LPMP | LOONGSON_CFG2_LPM_REV1);
176
c->loongson3_cpucfg_data[2] |= (
177
LOONGSON_CFG3_LCAM_REV1 |
178
LOONGSON_CFG3_LCAMNUM_REV1 |
179
LOONGSON_CFG3_LCAMKW_REV1 |
180
LOONGSON_CFG3_LCAMVW_REV1);
181
break;
182
183
case PRID_IMP_LOONGSON_64C | PRID_REV_LOONGSON3A_R2_0:
184
case PRID_IMP_LOONGSON_64C | PRID_REV_LOONGSON3A_R2_1:
185
case PRID_IMP_LOONGSON_64C | PRID_REV_LOONGSON3A_R3_0:
186
case PRID_IMP_LOONGSON_64C | PRID_REV_LOONGSON3A_R3_1:
187
decode_loongson_config6(c);
188
probe_uca(c);
189
190
c->loongson3_cpucfg_data[0] |= (LOONGSON_CFG1_CNT64 |
191
LOONGSON_CFG1_LSLDR0 | LOONGSON_CFG1_LSPREF |
192
LOONGSON_CFG1_LSPREFX | LOONGSON_CFG1_LSSYNCI |
193
LOONGSON_CFG1_LLSYNC | LOONGSON_CFG1_TGTSYNC);
194
c->loongson3_cpucfg_data[1] |= (LOONGSON_CFG2_LBT1 |
195
LOONGSON_CFG2_LBT2 | LOONGSON_CFG2_LBTMMU |
196
LOONGSON_CFG2_LPMP | LOONGSON_CFG2_LPM_REV1 |
197
LOONGSON_CFG2_LVZ_REV1);
198
c->loongson3_cpucfg_data[2] |= (LOONGSON_CFG3_LCAM_REV1 |
199
LOONGSON_CFG3_LCAMNUM_REV1 |
200
LOONGSON_CFG3_LCAMKW_REV1 |
201
LOONGSON_CFG3_LCAMVW_REV1);
202
break;
203
204
default:
205
/* It is possible that some future Loongson cores still do
206
* not have CPUCFG, so do not emulate anything for these
207
* cores.
208
*/
209
return;
210
}
211
212
/* This feature is set by firmware, but all known Loongson-64 systems
213
* are configured this way.
214
*/
215
c->loongson3_cpucfg_data[0] |= LOONGSON_CFG1_CDMAP;
216
217
/* Patch in dynamically probed bits. */
218
patch_cpucfg_sel1(c);
219
patch_cpucfg_sel2(c);
220
patch_cpucfg_sel3(c);
221
222
have_cpucfg_now:
223
/* We have usable CPUCFG now, emulated or not.
224
* Announce CPUCFG availability to userspace via hwcap.
225
*/
226
elf_hwcap |= HWCAP_LOONGSON_CPUCFG;
227
}
228
229