1 // SPDX-License-Identifier: GPL-2.0
4 #include <linux/types.h>
6 #include <asm/cpu-info.h>
9 #include <loongson_regs.h>
10 #include <cpucfg-emul.h>
12 static bool is_loongson(struct cpuinfo_mips
*c
)
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
);
19 case PRID_COMP_LOONGSON
:
27 static u32
get_loongson_fprev(struct cpuinfo_mips
*c
)
29 return c
->fpu_id
& LOONGSON_FPREV_MASK
;
32 static bool cpu_has_uca(void)
34 u32 diag
= read_c0_diag();
37 if (diag
& LOONGSON_DIAG_UCAC
)
38 /* UCA is already enabled. */
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();
47 return (new_diag
& LOONGSON_DIAG_UCAC
) != 0;
50 static void probe_uca(struct cpuinfo_mips
*c
)
53 c
->loongson3_cpucfg_data
[0] |= LOONGSON_CFG1_LSUCA
;
56 static void decode_loongson_config6(struct cpuinfo_mips
*c
)
58 u32 config6
= read_c0_config6();
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
;
68 static void patch_cpucfg_sel1(struct cpuinfo_mips
*c
)
71 u64 options
= c
->options
;
72 u32 data
= c
->loongson3_cpucfg_data
[0];
74 if (options
& MIPS_CPU_FPU
) {
75 data
|= LOONGSON_CFG1_FP
;
76 data
|= get_loongson_fprev(c
) << LOONGSON_CFG1_FPREV_OFFSET
;
78 if (ases
& MIPS_ASE_LOONGSON_MMI
)
79 data
|= LOONGSON_CFG1_MMI
;
80 if (ases
& MIPS_ASE_MSA
)
81 data
|= LOONGSON_CFG1_MSA1
;
83 c
->loongson3_cpucfg_data
[0] = data
;
86 static void patch_cpucfg_sel2(struct cpuinfo_mips
*c
)
89 u64 options
= c
->options
;
90 u32 data
= c
->loongson3_cpucfg_data
[1];
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
;
99 if (ases
& MIPS_ASE_VZ
)
100 data
|= LOONGSON_CFG2_LVZP
;
102 data
&= ~LOONGSON_CFG2_LVZREV
;
104 c
->loongson3_cpucfg_data
[1] = data
;
107 static void patch_cpucfg_sel3(struct cpuinfo_mips
*c
)
110 u32 data
= c
->loongson3_cpucfg_data
[2];
112 if (ases
& MIPS_ASE_LOONGSON_CAM
) {
113 data
|= LOONGSON_CFG3_LCAMP
;
115 data
&= ~LOONGSON_CFG3_LCAMREV
;
116 data
&= ~LOONGSON_CFG3_LCAMNUM
;
117 data
&= ~LOONGSON_CFG3_LCAMKW
;
118 data
&= ~LOONGSON_CFG3_LCAMVW
;
121 c
->loongson3_cpucfg_data
[2] = data
;
124 void loongson3_cpucfg_synthesize_data(struct cpuinfo_mips
*c
)
126 /* Only engage the logic on Loongson processors. */
130 /* CPUs with CPUCFG support don't need to synthesize anything. */
132 goto have_cpucfg_now
;
134 c
->loongson3_cpucfg_data
[0] = 0;
135 c
->loongson3_cpucfg_data
[1] = 0;
136 c
->loongson3_cpucfg_data
[2] = 0;
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
);
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;
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
);
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
);
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
);
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
);
205 /* It is possible that some future Loongson cores still do
206 * not have CPUCFG, so do not emulate anything for these
212 /* This feature is set by firmware, but all known Loongson-64 systems
213 * are configured this way.
215 c
->loongson3_cpucfg_data
[0] |= LOONGSON_CFG1_CDMAP
;
217 /* Patch in dynamically probed bits. */
218 patch_cpucfg_sel1(c
);
219 patch_cpucfg_sel2(c
);
220 patch_cpucfg_sel3(c
);
223 /* We have usable CPUCFG now, emulated or not.
224 * Announce CPUCFG availability to userspace via hwcap.
226 elf_hwcap
|= HWCAP_LOONGSON_CPUCFG
;