arm64: dts: qcom: sm8550: add TRNG node
[linux-modified.git] / arch / mips / loongson64 / cpucfg-emul.c
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 }