1 // SPDX-License-Identifier: GPL-2.0 1 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_MA 15 case PRID_COMP_LEGACY: 16 return ((c->processor_id & PRI 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_m 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. 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) 48 } 49 50 static void probe_uca(struct cpuinfo_mips *c) 51 { 52 if (cpu_has_uca()) 53 c->loongson3_cpucfg_data[0] |= 54 } 55 56 static void decode_loongson_config6(struct cpu 57 { 58 u32 config6 = read_c0_config6(); 59 60 if (config6 & LOONGSON_CONF6_SFBEN) 61 c->loongson3_cpucfg_data[0] |= 62 if (config6 & LOONGSON_CONF6_LLEXC) 63 c->loongson3_cpucfg_data[0] |= 64 if (config6 & LOONGSON_CONF6_SCRAND) 65 c->loongson3_cpucfg_data[0] |= 66 } 67 68 static void patch_cpucfg_sel1(struct cpuinfo_m 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) 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_m 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_m 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 c 125 { 126 /* Only engage the logic on Loongson p 127 if (!is_loongson(c)) 128 return; 129 130 /* CPUs with CPUCFG support don't need 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-discoverabl 139 switch (c->processor_id & (PRID_IMP_MA 140 case PRID_IMP_LOONGSON_64R | PRID_REV_ 141 case PRID_IMP_LOONGSON_64R | PRID_REV_ 142 case PRID_IMP_LOONGSON_64R | PRID_REV_ 143 case PRID_IMP_LOONGSON_64R | PRID_REV_ 144 decode_loongson_config6(c); 145 probe_uca(c); 146 147 c->loongson3_cpucfg_data[0] |= 148 LOONGSON_CFG1_LSSYNCI 149 LOONGSON_CFG1_TGTSYNC) 150 c->loongson3_cpucfg_data[1] |= 151 LOONGSON_CFG2_LBT2 | L 152 LOONGSON_CFG2_LPM_REV2 153 c->loongson3_cpucfg_data[2] = 154 break; 155 156 case PRID_IMP_LOONGSON_64C | PRID_REV_ 157 c->loongson3_cpucfg_data[0] |= 158 LOONGSON_CFG1_LSSYNCI 159 LOONGSON_CFG1_LLSYNC | 160 c->loongson3_cpucfg_data[1] |= 161 LOONGSON_CFG2_LPMP | L 162 c->loongson3_cpucfg_data[2] |= 163 LOONGSON_CFG3_LCAM_REV 164 LOONGSON_CFG3_LCAMNUM_ 165 LOONGSON_CFG3_LCAMKW_R 166 LOONGSON_CFG3_LCAMVW_R 167 break; 168 169 case PRID_IMP_LOONGSON_64C | PRID_REV_ 170 case PRID_IMP_LOONGSON_64C | PRID_REV_ 171 c->loongson3_cpucfg_data[0] |= 172 LOONGSON_CFG1_LSSYNCI 173 LOONGSON_CFG1_LLSYNC | 174 c->loongson3_cpucfg_data[1] |= 175 LOONGSON_CFG2_LPMP | L 176 c->loongson3_cpucfg_data[2] |= 177 LOONGSON_CFG3_LCAM_REV 178 LOONGSON_CFG3_LCAMNUM_ 179 LOONGSON_CFG3_LCAMKW_R 180 LOONGSON_CFG3_LCAMVW_R 181 break; 182 183 case PRID_IMP_LOONGSON_64C | PRID_REV_ 184 case PRID_IMP_LOONGSON_64C | PRID_REV_ 185 case PRID_IMP_LOONGSON_64C | PRID_REV_ 186 case PRID_IMP_LOONGSON_64C | PRID_REV_ 187 decode_loongson_config6(c); 188 probe_uca(c); 189 190 c->loongson3_cpucfg_data[0] |= 191 LOONGSON_CFG1_LSLDR0 | 192 LOONGSON_CFG1_LSPREFX 193 LOONGSON_CFG1_LLSYNC | 194 c->loongson3_cpucfg_data[1] |= 195 LOONGSON_CFG2_LBT2 | L 196 LOONGSON_CFG2_LPMP | L 197 LOONGSON_CFG2_LVZ_REV1 198 c->loongson3_cpucfg_data[2] |= 199 LOONGSON_CFG3_LCAMNUM_ 200 LOONGSON_CFG3_LCAMKW_R 201 LOONGSON_CFG3_LCAMVW_R 202 break; 203 204 default: 205 /* It is possible that some fu 206 * not have CPUCFG, so do not 207 * cores. 208 */ 209 return; 210 } 211 212 /* This feature is set by firmware, bu 213 * are configured this way. 214 */ 215 c->loongson3_cpucfg_data[0] |= LOONGSO 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 224 * Announce CPUCFG availability to use 225 */ 226 elf_hwcap |= HWCAP_LOONGSON_CPUCFG; 227 } 228
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.