0001
0002 #include <linux/bitops.h>
0003 #include <linux/delay.h>
0004 #include <linux/isa-dma.h>
0005 #include <linux/pci.h>
0006 #include <asm/dma.h>
0007 #include <linux/io.h>
0008 #include <asm/processor-cyrix.h>
0009 #include <asm/processor-flags.h>
0010 #include <linux/timer.h>
0011 #include <asm/pci-direct.h>
0012 #include <asm/tsc.h>
0013 #include <asm/cpufeature.h>
0014 #include <linux/sched.h>
0015 #include <linux/sched/clock.h>
0016
0017 #include "cpu.h"
0018
0019
0020
0021
0022 static void __do_cyrix_devid(unsigned char *dir0, unsigned char *dir1)
0023 {
0024 unsigned char ccr2, ccr3;
0025
0026
0027 ccr3 = getCx86(CX86_CCR3);
0028 setCx86(CX86_CCR3, ccr3 ^ 0x80);
0029 getCx86(0xc0);
0030
0031 if (getCx86(CX86_CCR3) == ccr3) {
0032 ccr2 = getCx86(CX86_CCR2);
0033 setCx86(CX86_CCR2, ccr2 ^ 0x04);
0034 getCx86(0xc0);
0035
0036 if (getCx86(CX86_CCR2) == ccr2)
0037 *dir0 = 0xfd;
0038 else {
0039 setCx86(CX86_CCR2, ccr2);
0040 *dir0 = 0xfe;
0041 }
0042 } else {
0043 setCx86(CX86_CCR3, ccr3);
0044
0045
0046 *dir0 = getCx86(CX86_DIR0);
0047 *dir1 = getCx86(CX86_DIR1);
0048 }
0049 }
0050
0051 static void do_cyrix_devid(unsigned char *dir0, unsigned char *dir1)
0052 {
0053 unsigned long flags;
0054
0055 local_irq_save(flags);
0056 __do_cyrix_devid(dir0, dir1);
0057 local_irq_restore(flags);
0058 }
0059
0060
0061
0062
0063
0064
0065
0066 static unsigned char Cx86_dir0_msb = 0;
0067
0068 static const char Cx86_model[][9] = {
0069 "Cx486", "Cx486", "5x86 ", "6x86", "MediaGX ", "6x86MX ",
0070 "M II ", "Unknown"
0071 };
0072 static const char Cx486_name[][5] = {
0073 "SLC", "DLC", "SLC2", "DLC2", "SRx", "DRx",
0074 "SRx2", "DRx2"
0075 };
0076 static const char Cx486S_name[][4] = {
0077 "S", "S2", "Se", "S2e"
0078 };
0079 static const char Cx486D_name[][4] = {
0080 "DX", "DX2", "?", "?", "?", "DX4"
0081 };
0082 static char Cx86_cb[] = "?.5x Core/Bus Clock";
0083 static const char cyrix_model_mult1[] = "12??43";
0084 static const char cyrix_model_mult2[] = "12233445";
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094 static void check_cx686_slop(struct cpuinfo_x86 *c)
0095 {
0096 unsigned long flags;
0097
0098 if (Cx86_dir0_msb == 3) {
0099 unsigned char ccr3, ccr5;
0100
0101 local_irq_save(flags);
0102 ccr3 = getCx86(CX86_CCR3);
0103 setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10);
0104 ccr5 = getCx86(CX86_CCR5);
0105 if (ccr5 & 2)
0106 setCx86(CX86_CCR5, ccr5 & 0xfd);
0107 setCx86(CX86_CCR3, ccr3);
0108 local_irq_restore(flags);
0109
0110 if (ccr5 & 2) {
0111 pr_info("Recalibrating delay loop with SLOP bit reset\n");
0112 calibrate_delay();
0113 c->loops_per_jiffy = loops_per_jiffy;
0114 }
0115 }
0116 }
0117
0118
0119 static void set_cx86_reorder(void)
0120 {
0121 u8 ccr3;
0122
0123 pr_info("Enable Memory access reorder on Cyrix/NSC processor.\n");
0124 ccr3 = getCx86(CX86_CCR3);
0125 setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10);
0126
0127
0128 setCx86(CX86_PCR0, getCx86(CX86_PCR0) & ~0x80);
0129
0130 ccr3 |= 0xe0;
0131 setCx86(CX86_CCR3, ccr3);
0132 }
0133
0134 static void set_cx86_memwb(void)
0135 {
0136 pr_info("Enable Memory-Write-back mode on Cyrix/NSC processor.\n");
0137
0138
0139 setCx86(CX86_CCR2, getCx86(CX86_CCR2) & ~0x04);
0140
0141 write_cr0(read_cr0() | X86_CR0_NW);
0142
0143 setCx86(CX86_CCR2, getCx86(CX86_CCR2) | 0x14);
0144 }
0145
0146
0147
0148
0149
0150 static void geode_configure(void)
0151 {
0152 unsigned long flags;
0153 u8 ccr3;
0154 local_irq_save(flags);
0155
0156
0157 setCx86(CX86_CCR2, getCx86(CX86_CCR2) | 0x88);
0158
0159 ccr3 = getCx86(CX86_CCR3);
0160 setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10);
0161
0162
0163
0164 setCx86(CX86_CCR4, getCx86(CX86_CCR4) | 0x38);
0165 setCx86(CX86_CCR3, ccr3);
0166
0167 set_cx86_memwb();
0168 set_cx86_reorder();
0169
0170 local_irq_restore(flags);
0171 }
0172
0173 static void early_init_cyrix(struct cpuinfo_x86 *c)
0174 {
0175 unsigned char dir0, dir0_msn, dir1 = 0;
0176
0177 __do_cyrix_devid(&dir0, &dir1);
0178 dir0_msn = dir0 >> 4;
0179
0180 switch (dir0_msn) {
0181 case 3:
0182
0183 set_cpu_cap(c, X86_FEATURE_CYRIX_ARR);
0184 break;
0185 case 5:
0186
0187 set_cpu_cap(c, X86_FEATURE_CYRIX_ARR);
0188 break;
0189 }
0190 }
0191
0192 static void init_cyrix(struct cpuinfo_x86 *c)
0193 {
0194 unsigned char dir0, dir0_msn, dir0_lsn, dir1 = 0;
0195 char *buf = c->x86_model_id;
0196 const char *p = NULL;
0197
0198
0199
0200
0201
0202 clear_cpu_cap(c, 0*32+31);
0203
0204
0205 if (test_cpu_cap(c, 1*32+24)) {
0206 clear_cpu_cap(c, 1*32+24);
0207 set_cpu_cap(c, X86_FEATURE_CXMMX);
0208 }
0209
0210 do_cyrix_devid(&dir0, &dir1);
0211
0212 check_cx686_slop(c);
0213
0214 Cx86_dir0_msb = dir0_msn = dir0 >> 4;
0215 dir0_lsn = dir0 & 0xf;
0216
0217
0218 c->x86_model = (dir1 >> 4) + 1;
0219 c->x86_stepping = dir1 & 0xf;
0220
0221
0222
0223
0224
0225
0226
0227 switch (dir0_msn) {
0228 unsigned char tmp;
0229
0230 case 0:
0231 p = Cx486_name[dir0_lsn & 7];
0232 break;
0233
0234 case 1:
0235 p = (dir0_lsn & 8) ? Cx486D_name[dir0_lsn & 5]
0236 : Cx486S_name[dir0_lsn & 3];
0237 break;
0238
0239 case 2:
0240 Cx86_cb[2] = cyrix_model_mult1[dir0_lsn & 5];
0241 p = Cx86_cb+2;
0242 break;
0243
0244 case 3:
0245 Cx86_cb[1] = ' ';
0246 Cx86_cb[2] = cyrix_model_mult1[dir0_lsn & 5];
0247 if (dir1 > 0x21) {
0248 Cx86_cb[0] = 'L';
0249 p = Cx86_cb;
0250 (c->x86_model)++;
0251 } else
0252 p = Cx86_cb+1;
0253
0254 set_cpu_cap(c, X86_FEATURE_CYRIX_ARR);
0255
0256 set_cpu_bug(c, X86_BUG_COMA);
0257 break;
0258
0259 case 4:
0260 case 11:
0261 #ifdef CONFIG_PCI
0262 {
0263 u32 vendor, device;
0264
0265
0266
0267
0268
0269
0270
0271
0272
0273
0274
0275
0276
0277 pr_info("Working around Cyrix MediaGX virtual DMA bugs.\n");
0278 isa_dma_bridge_buggy = 2;
0279
0280
0281
0282
0283 vendor = read_pci_config_16(0, 0, 0x12, PCI_VENDOR_ID);
0284 device = read_pci_config_16(0, 0, 0x12, PCI_DEVICE_ID);
0285
0286
0287
0288
0289 if (vendor == PCI_VENDOR_ID_CYRIX &&
0290 (device == PCI_DEVICE_ID_CYRIX_5510 ||
0291 device == PCI_DEVICE_ID_CYRIX_5520))
0292 mark_tsc_unstable("cyrix 5510/5520 detected");
0293 }
0294 #endif
0295 c->x86_cache_size = 16;
0296
0297
0298 if (c->cpuid_level == 2) {
0299
0300 setCx86(CX86_CCR7, getCx86(CX86_CCR7) | 1);
0301
0302
0303
0304
0305
0306
0307
0308 if ((0x30 <= dir1 && dir1 <= 0x6f) ||
0309 (0x80 <= dir1 && dir1 <= 0x8f))
0310 geode_configure();
0311 return;
0312 } else {
0313 Cx86_cb[2] = (dir0_lsn & 1) ? '3' : '4';
0314 p = Cx86_cb+2;
0315 c->x86_model = (dir1 & 0x20) ? 1 : 2;
0316 }
0317 break;
0318
0319 case 5:
0320 if (dir1 > 7) {
0321 dir0_msn++;
0322
0323 setCx86(CX86_CCR7, getCx86(CX86_CCR7)|1);
0324 } else {
0325
0326 set_cpu_bug(c, X86_BUG_COMA);
0327 }
0328 tmp = (!(dir0_lsn & 7) || dir0_lsn & 1) ? 2 : 0;
0329 Cx86_cb[tmp] = cyrix_model_mult2[dir0_lsn & 7];
0330 p = Cx86_cb+tmp;
0331 if (((dir1 & 0x0f) > 4) || ((dir1 & 0xf0) == 0x20))
0332 (c->x86_model)++;
0333
0334 set_cpu_cap(c, X86_FEATURE_CYRIX_ARR);
0335 break;
0336
0337 case 0xf:
0338 switch (dir0_lsn) {
0339 case 0xd:
0340 dir0_msn = 0;
0341 p = Cx486_name[!!boot_cpu_has(X86_FEATURE_FPU)];
0342 break;
0343
0344 case 0xe:
0345 dir0_msn = 0;
0346 p = Cx486S_name[0];
0347 break;
0348 }
0349 break;
0350
0351 default:
0352 dir0_msn = 7;
0353 break;
0354 }
0355 strcpy(buf, Cx86_model[dir0_msn & 7]);
0356 if (p)
0357 strcat(buf, p);
0358 return;
0359 }
0360
0361
0362
0363
0364 static void init_nsc(struct cpuinfo_x86 *c)
0365 {
0366
0367
0368
0369
0370
0371
0372
0373
0374
0375
0376
0377
0378
0379
0380
0381 if (c->x86 == 5 && c->x86_model == 5)
0382 cpu_detect_cache_sizes(c);
0383 else
0384 init_cyrix(c);
0385 }
0386
0387
0388
0389
0390
0391
0392
0393
0394
0395
0396
0397 static inline int test_cyrix_52div(void)
0398 {
0399 unsigned int test;
0400
0401 __asm__ __volatile__(
0402 "sahf\n\t"
0403 "div %b2\n\t"
0404 "lahf"
0405 : "=a" (test)
0406 : "0" (5), "q" (2)
0407 : "cc");
0408
0409
0410 return (unsigned char) (test >> 8) == 0x02;
0411 }
0412
0413 static void cyrix_identify(struct cpuinfo_x86 *c)
0414 {
0415
0416 if (c->x86 == 4 && test_cyrix_52div()) {
0417 unsigned char dir0, dir1;
0418
0419 strcpy(c->x86_vendor_id, "CyrixInstead");
0420 c->x86_vendor = X86_VENDOR_CYRIX;
0421
0422
0423
0424
0425
0426 do_cyrix_devid(&dir0, &dir1);
0427
0428 dir0 >>= 4;
0429
0430
0431
0432 if (dir0 == 5 || dir0 == 3) {
0433 unsigned char ccr3;
0434 unsigned long flags;
0435 pr_info("Enabling CPUID on Cyrix processor.\n");
0436 local_irq_save(flags);
0437 ccr3 = getCx86(CX86_CCR3);
0438
0439 setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10);
0440
0441 setCx86(CX86_CCR4, getCx86(CX86_CCR4) | 0x80);
0442
0443 setCx86(CX86_CCR3, ccr3);
0444 local_irq_restore(flags);
0445 }
0446 }
0447 }
0448
0449 static const struct cpu_dev cyrix_cpu_dev = {
0450 .c_vendor = "Cyrix",
0451 .c_ident = { "CyrixInstead" },
0452 .c_early_init = early_init_cyrix,
0453 .c_init = init_cyrix,
0454 .c_identify = cyrix_identify,
0455 .c_x86_vendor = X86_VENDOR_CYRIX,
0456 };
0457
0458 cpu_dev_register(cyrix_cpu_dev);
0459
0460 static const struct cpu_dev nsc_cpu_dev = {
0461 .c_vendor = "NSC",
0462 .c_ident = { "Geode by NSC" },
0463 .c_init = init_nsc,
0464 .c_x86_vendor = X86_VENDOR_NSC,
0465 };
0466
0467 cpu_dev_register(nsc_cpu_dev);