0001
0002
0003 #include <linux/smp.h>
0004 #include <linux/types.h>
0005 #include <asm/cpu.h>
0006 #include <asm/cpu-info.h>
0007 #include <asm/elf.h>
0008
0009 #include <loongson_regs.h>
0010 #include <cpucfg-emul.h>
0011
0012 static bool is_loongson(struct cpuinfo_mips *c)
0013 {
0014 switch (c->processor_id & PRID_COMP_MASK) {
0015 case PRID_COMP_LEGACY:
0016 return ((c->processor_id & PRID_IMP_MASK) ==
0017 PRID_IMP_LOONGSON_64C);
0018
0019 case PRID_COMP_LOONGSON:
0020 return true;
0021
0022 default:
0023 return false;
0024 }
0025 }
0026
0027 static u32 get_loongson_fprev(struct cpuinfo_mips *c)
0028 {
0029 return c->fpu_id & LOONGSON_FPREV_MASK;
0030 }
0031
0032 static bool cpu_has_uca(void)
0033 {
0034 u32 diag = read_c0_diag();
0035 u32 new_diag;
0036
0037 if (diag & LOONGSON_DIAG_UCAC)
0038
0039 return true;
0040
0041
0042 new_diag = diag | LOONGSON_DIAG_UCAC;
0043 write_c0_diag(new_diag);
0044 new_diag = read_c0_diag();
0045 write_c0_diag(diag);
0046
0047 return (new_diag & LOONGSON_DIAG_UCAC) != 0;
0048 }
0049
0050 static void probe_uca(struct cpuinfo_mips *c)
0051 {
0052 if (cpu_has_uca())
0053 c->loongson3_cpucfg_data[0] |= LOONGSON_CFG1_LSUCA;
0054 }
0055
0056 static void decode_loongson_config6(struct cpuinfo_mips *c)
0057 {
0058 u32 config6 = read_c0_config6();
0059
0060 if (config6 & LOONGSON_CONF6_SFBEN)
0061 c->loongson3_cpucfg_data[0] |= LOONGSON_CFG1_SFBP;
0062 if (config6 & LOONGSON_CONF6_LLEXC)
0063 c->loongson3_cpucfg_data[0] |= LOONGSON_CFG1_LLEXC;
0064 if (config6 & LOONGSON_CONF6_SCRAND)
0065 c->loongson3_cpucfg_data[0] |= LOONGSON_CFG1_SCRAND;
0066 }
0067
0068 static void patch_cpucfg_sel1(struct cpuinfo_mips *c)
0069 {
0070 u64 ases = c->ases;
0071 u64 options = c->options;
0072 u32 data = c->loongson3_cpucfg_data[0];
0073
0074 if (options & MIPS_CPU_FPU) {
0075 data |= LOONGSON_CFG1_FP;
0076 data |= get_loongson_fprev(c) << LOONGSON_CFG1_FPREV_OFFSET;
0077 }
0078 if (ases & MIPS_ASE_LOONGSON_MMI)
0079 data |= LOONGSON_CFG1_MMI;
0080 if (ases & MIPS_ASE_MSA)
0081 data |= LOONGSON_CFG1_MSA1;
0082
0083 c->loongson3_cpucfg_data[0] = data;
0084 }
0085
0086 static void patch_cpucfg_sel2(struct cpuinfo_mips *c)
0087 {
0088 u64 ases = c->ases;
0089 u64 options = c->options;
0090 u32 data = c->loongson3_cpucfg_data[1];
0091
0092 if (ases & MIPS_ASE_LOONGSON_EXT)
0093 data |= LOONGSON_CFG2_LEXT1;
0094 if (ases & MIPS_ASE_LOONGSON_EXT2)
0095 data |= LOONGSON_CFG2_LEXT2;
0096 if (options & MIPS_CPU_LDPTE)
0097 data |= LOONGSON_CFG2_LSPW;
0098
0099 if (ases & MIPS_ASE_VZ)
0100 data |= LOONGSON_CFG2_LVZP;
0101 else
0102 data &= ~LOONGSON_CFG2_LVZREV;
0103
0104 c->loongson3_cpucfg_data[1] = data;
0105 }
0106
0107 static void patch_cpucfg_sel3(struct cpuinfo_mips *c)
0108 {
0109 u64 ases = c->ases;
0110 u32 data = c->loongson3_cpucfg_data[2];
0111
0112 if (ases & MIPS_ASE_LOONGSON_CAM) {
0113 data |= LOONGSON_CFG3_LCAMP;
0114 } else {
0115 data &= ~LOONGSON_CFG3_LCAMREV;
0116 data &= ~LOONGSON_CFG3_LCAMNUM;
0117 data &= ~LOONGSON_CFG3_LCAMKW;
0118 data &= ~LOONGSON_CFG3_LCAMVW;
0119 }
0120
0121 c->loongson3_cpucfg_data[2] = data;
0122 }
0123
0124 void loongson3_cpucfg_synthesize_data(struct cpuinfo_mips *c)
0125 {
0126
0127 if (!is_loongson(c))
0128 return;
0129
0130
0131 if (cpu_has_cfg())
0132 goto have_cpucfg_now;
0133
0134 c->loongson3_cpucfg_data[0] = 0;
0135 c->loongson3_cpucfg_data[1] = 0;
0136 c->loongson3_cpucfg_data[2] = 0;
0137
0138
0139 switch (c->processor_id & (PRID_IMP_MASK | PRID_REV_MASK)) {
0140 case PRID_IMP_LOONGSON_64R | PRID_REV_LOONGSON2K_R1_0:
0141 case PRID_IMP_LOONGSON_64R | PRID_REV_LOONGSON2K_R1_1:
0142 case PRID_IMP_LOONGSON_64R | PRID_REV_LOONGSON2K_R1_2:
0143 case PRID_IMP_LOONGSON_64R | PRID_REV_LOONGSON2K_R1_3:
0144 decode_loongson_config6(c);
0145 probe_uca(c);
0146
0147 c->loongson3_cpucfg_data[0] |= (LOONGSON_CFG1_LSLDR0 |
0148 LOONGSON_CFG1_LSSYNCI | LOONGSON_CFG1_LLSYNC |
0149 LOONGSON_CFG1_TGTSYNC);
0150 c->loongson3_cpucfg_data[1] |= (LOONGSON_CFG2_LBT1 |
0151 LOONGSON_CFG2_LBT2 | LOONGSON_CFG2_LPMP |
0152 LOONGSON_CFG2_LPM_REV2);
0153 c->loongson3_cpucfg_data[2] = 0;
0154 break;
0155
0156 case PRID_IMP_LOONGSON_64C | PRID_REV_LOONGSON3A_R1:
0157 c->loongson3_cpucfg_data[0] |= (LOONGSON_CFG1_LSLDR0 |
0158 LOONGSON_CFG1_LSSYNCI | LOONGSON_CFG1_LSUCA |
0159 LOONGSON_CFG1_LLSYNC | LOONGSON_CFG1_TGTSYNC);
0160 c->loongson3_cpucfg_data[1] |= (LOONGSON_CFG2_LBT1 |
0161 LOONGSON_CFG2_LPMP | LOONGSON_CFG2_LPM_REV1);
0162 c->loongson3_cpucfg_data[2] |= (
0163 LOONGSON_CFG3_LCAM_REV1 |
0164 LOONGSON_CFG3_LCAMNUM_REV1 |
0165 LOONGSON_CFG3_LCAMKW_REV1 |
0166 LOONGSON_CFG3_LCAMVW_REV1);
0167 break;
0168
0169 case PRID_IMP_LOONGSON_64C | PRID_REV_LOONGSON3B_R1:
0170 case PRID_IMP_LOONGSON_64C | PRID_REV_LOONGSON3B_R2:
0171 c->loongson3_cpucfg_data[0] |= (LOONGSON_CFG1_LSLDR0 |
0172 LOONGSON_CFG1_LSSYNCI | LOONGSON_CFG1_LSUCA |
0173 LOONGSON_CFG1_LLSYNC | LOONGSON_CFG1_TGTSYNC);
0174 c->loongson3_cpucfg_data[1] |= (LOONGSON_CFG2_LBT1 |
0175 LOONGSON_CFG2_LPMP | LOONGSON_CFG2_LPM_REV1);
0176 c->loongson3_cpucfg_data[2] |= (
0177 LOONGSON_CFG3_LCAM_REV1 |
0178 LOONGSON_CFG3_LCAMNUM_REV1 |
0179 LOONGSON_CFG3_LCAMKW_REV1 |
0180 LOONGSON_CFG3_LCAMVW_REV1);
0181 break;
0182
0183 case PRID_IMP_LOONGSON_64C | PRID_REV_LOONGSON3A_R2_0:
0184 case PRID_IMP_LOONGSON_64C | PRID_REV_LOONGSON3A_R2_1:
0185 case PRID_IMP_LOONGSON_64C | PRID_REV_LOONGSON3A_R3_0:
0186 case PRID_IMP_LOONGSON_64C | PRID_REV_LOONGSON3A_R3_1:
0187 decode_loongson_config6(c);
0188 probe_uca(c);
0189
0190 c->loongson3_cpucfg_data[0] |= (LOONGSON_CFG1_CNT64 |
0191 LOONGSON_CFG1_LSLDR0 | LOONGSON_CFG1_LSPREF |
0192 LOONGSON_CFG1_LSPREFX | LOONGSON_CFG1_LSSYNCI |
0193 LOONGSON_CFG1_LLSYNC | LOONGSON_CFG1_TGTSYNC);
0194 c->loongson3_cpucfg_data[1] |= (LOONGSON_CFG2_LBT1 |
0195 LOONGSON_CFG2_LBT2 | LOONGSON_CFG2_LBTMMU |
0196 LOONGSON_CFG2_LPMP | LOONGSON_CFG2_LPM_REV1 |
0197 LOONGSON_CFG2_LVZ_REV1);
0198 c->loongson3_cpucfg_data[2] |= (LOONGSON_CFG3_LCAM_REV1 |
0199 LOONGSON_CFG3_LCAMNUM_REV1 |
0200 LOONGSON_CFG3_LCAMKW_REV1 |
0201 LOONGSON_CFG3_LCAMVW_REV1);
0202 break;
0203
0204 default:
0205
0206
0207
0208
0209 return;
0210 }
0211
0212
0213
0214
0215 c->loongson3_cpucfg_data[0] |= LOONGSON_CFG1_CDMAP;
0216
0217
0218 patch_cpucfg_sel1(c);
0219 patch_cpucfg_sel2(c);
0220 patch_cpucfg_sel3(c);
0221
0222 have_cpucfg_now:
0223
0224
0225
0226 elf_hwcap |= HWCAP_LOONGSON_CPUCFG;
0227 }