| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | #include <linux/init.h> | 
|  | 2 | #include <linux/bitops.h> | 
|  | 3 | #include <linux/delay.h> | 
|  | 4 | #include <linux/pci.h> | 
|  | 5 | #include <asm/dma.h> | 
| Alan Cox | 8bdbd96 | 2009-07-04 00:35:45 +0100 | [diff] [blame] | 6 | #include <linux/io.h> | 
| Juergen Beisert | f25f64e | 2007-07-22 11:12:38 +0200 | [diff] [blame] | 7 | #include <asm/processor-cyrix.h> | 
| Dave Jones | 7ebad70 | 2008-01-30 13:30:39 +0100 | [diff] [blame] | 8 | #include <asm/processor-flags.h> | 
| Alan Cox | 8bdbd96 | 2009-07-04 00:35:45 +0100 | [diff] [blame] | 9 | #include <linux/timer.h> | 
| Alan | 120fad7 | 2007-02-13 13:26:26 +0100 | [diff] [blame] | 10 | #include <asm/pci-direct.h> | 
| Alexey Dobriyan | e8edc6e | 2007-05-21 01:22:52 +0400 | [diff] [blame] | 11 | #include <asm/tsc.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 12 |  | 
|  | 13 | #include "cpu.h" | 
|  | 14 |  | 
|  | 15 | /* | 
|  | 16 | * Read NSC/Cyrix DEVID registers (DIR) to get more detailed info. about the CPU | 
|  | 17 | */ | 
| Yinghai Lu | 5fef55f | 2008-09-04 21:09:43 +0200 | [diff] [blame] | 18 | static void __cpuinit __do_cyrix_devid(unsigned char *dir0, unsigned char *dir1) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 19 | { | 
|  | 20 | unsigned char ccr2, ccr3; | 
| Paolo Ciarrocchi | adf8526 | 2008-02-22 23:11:23 +0100 | [diff] [blame] | 21 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 22 | /* we test for DEVID by checking whether CCR3 is writable */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 23 | ccr3 = getCx86(CX86_CCR3); | 
|  | 24 | setCx86(CX86_CCR3, ccr3 ^ 0x80); | 
|  | 25 | getCx86(0xc0);   /* dummy to change bus */ | 
|  | 26 |  | 
|  | 27 | if (getCx86(CX86_CCR3) == ccr3) {       /* no DEVID regs. */ | 
|  | 28 | ccr2 = getCx86(CX86_CCR2); | 
|  | 29 | setCx86(CX86_CCR2, ccr2 ^ 0x04); | 
|  | 30 | getCx86(0xc0);  /* dummy */ | 
|  | 31 |  | 
|  | 32 | if (getCx86(CX86_CCR2) == ccr2) /* old Cx486SLC/DLC */ | 
|  | 33 | *dir0 = 0xfd; | 
|  | 34 | else {                          /* Cx486S A step */ | 
|  | 35 | setCx86(CX86_CCR2, ccr2); | 
|  | 36 | *dir0 = 0xfe; | 
|  | 37 | } | 
| Paolo Ciarrocchi | adf8526 | 2008-02-22 23:11:23 +0100 | [diff] [blame] | 38 | } else { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 39 | setCx86(CX86_CCR3, ccr3);  /* restore CCR3 */ | 
|  | 40 |  | 
|  | 41 | /* read DIR0 and DIR1 CPU registers */ | 
|  | 42 | *dir0 = getCx86(CX86_DIR0); | 
|  | 43 | *dir1 = getCx86(CX86_DIR1); | 
|  | 44 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 45 | } | 
|  | 46 |  | 
| Yinghai Lu | 5fef55f | 2008-09-04 21:09:43 +0200 | [diff] [blame] | 47 | static void __cpuinit do_cyrix_devid(unsigned char *dir0, unsigned char *dir1) | 
|  | 48 | { | 
|  | 49 | unsigned long flags; | 
|  | 50 |  | 
|  | 51 | local_irq_save(flags); | 
|  | 52 | __do_cyrix_devid(dir0, dir1); | 
|  | 53 | local_irq_restore(flags); | 
|  | 54 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 55 | /* | 
|  | 56 | * Cx86_dir0_msb is a HACK needed by check_cx686_cpuid/slop in bugs.h in | 
|  | 57 | * order to identify the Cyrix CPU model after we're out of setup.c | 
|  | 58 | * | 
|  | 59 | * Actually since bugs.h doesn't even reference this perhaps someone should | 
|  | 60 | * fix the documentation ??? | 
|  | 61 | */ | 
| Magnus Damm | b4af3f7 | 2006-09-26 10:52:36 +0200 | [diff] [blame] | 62 | static unsigned char Cx86_dir0_msb __cpuinitdata = 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 63 |  | 
| Jan Beulich | 02dde8b | 2009-03-12 12:08:49 +0000 | [diff] [blame] | 64 | static const char __cpuinitconst Cx86_model[][9] = { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 65 | "Cx486", "Cx486", "5x86 ", "6x86", "MediaGX ", "6x86MX ", | 
|  | 66 | "M II ", "Unknown" | 
|  | 67 | }; | 
| Jan Beulich | 02dde8b | 2009-03-12 12:08:49 +0000 | [diff] [blame] | 68 | static const char __cpuinitconst Cx486_name[][5] = { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 69 | "SLC", "DLC", "SLC2", "DLC2", "SRx", "DRx", | 
|  | 70 | "SRx2", "DRx2" | 
|  | 71 | }; | 
| Jan Beulich | 02dde8b | 2009-03-12 12:08:49 +0000 | [diff] [blame] | 72 | static const char __cpuinitconst Cx486S_name[][4] = { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 73 | "S", "S2", "Se", "S2e" | 
|  | 74 | }; | 
| Jan Beulich | 02dde8b | 2009-03-12 12:08:49 +0000 | [diff] [blame] | 75 | static const char __cpuinitconst Cx486D_name[][4] = { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 76 | "DX", "DX2", "?", "?", "?", "DX4" | 
|  | 77 | }; | 
| Magnus Damm | b4af3f7 | 2006-09-26 10:52:36 +0200 | [diff] [blame] | 78 | static char Cx86_cb[] __cpuinitdata = "?.5x Core/Bus Clock"; | 
| Jan Beulich | 02dde8b | 2009-03-12 12:08:49 +0000 | [diff] [blame] | 79 | static const char __cpuinitconst cyrix_model_mult1[] = "12??43"; | 
|  | 80 | static const char __cpuinitconst cyrix_model_mult2[] = "12233445"; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 81 |  | 
|  | 82 | /* | 
|  | 83 | * Reset the slow-loop (SLOP) bit on the 686(L) which is set by some old | 
|  | 84 | * BIOSes for compatibility with DOS games.  This makes the udelay loop | 
|  | 85 | * work correctly, and improves performance. | 
|  | 86 | * | 
|  | 87 | * FIXME: our newer udelay uses the tsc. We don't need to frob with SLOP | 
|  | 88 | */ | 
|  | 89 |  | 
| Magnus Damm | b4af3f7 | 2006-09-26 10:52:36 +0200 | [diff] [blame] | 90 | static void __cpuinit check_cx686_slop(struct cpuinfo_x86 *c) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 91 | { | 
|  | 92 | unsigned long flags; | 
| Paolo Ciarrocchi | adf8526 | 2008-02-22 23:11:23 +0100 | [diff] [blame] | 93 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 94 | if (Cx86_dir0_msb == 3) { | 
|  | 95 | unsigned char ccr3, ccr5; | 
|  | 96 |  | 
|  | 97 | local_irq_save(flags); | 
|  | 98 | ccr3 = getCx86(CX86_CCR3); | 
| Marcin Garski | db95517 | 2007-10-19 23:22:11 +0200 | [diff] [blame] | 99 | setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 100 | ccr5 = getCx86(CX86_CCR5); | 
|  | 101 | if (ccr5 & 2) | 
|  | 102 | setCx86(CX86_CCR5, ccr5 & 0xfd);  /* reset SLOP */ | 
|  | 103 | setCx86(CX86_CCR3, ccr3);                 /* disable MAPEN */ | 
|  | 104 | local_irq_restore(flags); | 
|  | 105 |  | 
|  | 106 | if (ccr5 & 2) { /* possible wrong calibration done */ | 
|  | 107 | printk(KERN_INFO "Recalibrating delay loop with SLOP bit reset\n"); | 
|  | 108 | calibrate_delay(); | 
|  | 109 | c->loops_per_jiffy = loops_per_jiffy; | 
|  | 110 | } | 
|  | 111 | } | 
|  | 112 | } | 
|  | 113 |  | 
|  | 114 |  | 
| Magnus Damm | b4af3f7 | 2006-09-26 10:52:36 +0200 | [diff] [blame] | 115 | static void __cpuinit set_cx86_reorder(void) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 116 | { | 
|  | 117 | u8 ccr3; | 
|  | 118 |  | 
|  | 119 | printk(KERN_INFO "Enable Memory access reorder on Cyrix/NSC processor.\n"); | 
|  | 120 | ccr3 = getCx86(CX86_CCR3); | 
| Jan Engelhardt | 96de0e2 | 2007-10-19 23:21:04 +0200 | [diff] [blame] | 121 | setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 122 |  | 
| Jan Engelhardt | 96de0e2 | 2007-10-19 23:21:04 +0200 | [diff] [blame] | 123 | /* Load/Store Serialize to mem access disable (=reorder it) */ | 
| Ingo Molnar | 026e2c0 | 2008-07-22 11:58:14 +0200 | [diff] [blame] | 124 | setCx86_old(CX86_PCR0, getCx86_old(CX86_PCR0) & ~0x80); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 125 | /* set load/store serialize from 1GB to 4GB */ | 
|  | 126 | ccr3 |= 0xe0; | 
|  | 127 | setCx86(CX86_CCR3, ccr3); | 
|  | 128 | } | 
|  | 129 |  | 
| Magnus Damm | b4af3f7 | 2006-09-26 10:52:36 +0200 | [diff] [blame] | 130 | static void __cpuinit set_cx86_memwb(void) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 131 | { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 132 | printk(KERN_INFO "Enable Memory-Write-back mode on Cyrix/NSC processor.\n"); | 
|  | 133 |  | 
|  | 134 | /* CCR2 bit 2: unlock NW bit */ | 
| Ingo Molnar | 026e2c0 | 2008-07-22 11:58:14 +0200 | [diff] [blame] | 135 | setCx86_old(CX86_CCR2, getCx86_old(CX86_CCR2) & ~0x04); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 136 | /* set 'Not Write-through' */ | 
| Dave Jones | 7ebad70 | 2008-01-30 13:30:39 +0100 | [diff] [blame] | 137 | write_cr0(read_cr0() | X86_CR0_NW); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 138 | /* CCR2 bit 2: lock NW bit and set WT1 */ | 
| Ingo Molnar | 026e2c0 | 2008-07-22 11:58:14 +0200 | [diff] [blame] | 139 | setCx86_old(CX86_CCR2, getCx86_old(CX86_CCR2) | 0x14); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 140 | } | 
|  | 141 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 142 | /* | 
|  | 143 | *	Configure later MediaGX and/or Geode processor. | 
|  | 144 | */ | 
|  | 145 |  | 
| Magnus Damm | b4af3f7 | 2006-09-26 10:52:36 +0200 | [diff] [blame] | 146 | static void __cpuinit geode_configure(void) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 147 | { | 
|  | 148 | unsigned long flags; | 
| TAKADA Yoshihito | bcde1eb | 2007-02-13 13:26:25 +0100 | [diff] [blame] | 149 | u8 ccr3; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 150 | local_irq_save(flags); | 
|  | 151 |  | 
|  | 152 | /* Suspend on halt power saving and enable #SUSP pin */ | 
| Ingo Molnar | 026e2c0 | 2008-07-22 11:58:14 +0200 | [diff] [blame] | 153 | setCx86_old(CX86_CCR2, getCx86_old(CX86_CCR2) | 0x88); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 154 |  | 
|  | 155 | ccr3 = getCx86(CX86_CCR3); | 
| TAKADA Yoshihito | bcde1eb | 2007-02-13 13:26:25 +0100 | [diff] [blame] | 156 | setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10);	/* enable MAPEN */ | 
| Paolo Ciarrocchi | adf8526 | 2008-02-22 23:11:23 +0100 | [diff] [blame] | 157 |  | 
| TAKADA Yoshihito | bcde1eb | 2007-02-13 13:26:25 +0100 | [diff] [blame] | 158 |  | 
|  | 159 | /* FPU fast, DTE cache, Mem bypass */ | 
| Ingo Molnar | 026e2c0 | 2008-07-22 11:58:14 +0200 | [diff] [blame] | 160 | setCx86_old(CX86_CCR4, getCx86_old(CX86_CCR4) | 0x38); | 
| TAKADA Yoshihito | bcde1eb | 2007-02-13 13:26:25 +0100 | [diff] [blame] | 161 | setCx86(CX86_CCR3, ccr3);			/* disable MAPEN */ | 
| Paolo Ciarrocchi | adf8526 | 2008-02-22 23:11:23 +0100 | [diff] [blame] | 162 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 163 | set_cx86_memwb(); | 
| Paolo Ciarrocchi | adf8526 | 2008-02-22 23:11:23 +0100 | [diff] [blame] | 164 | set_cx86_reorder(); | 
| Paolo Ciarrocchi | adf8526 | 2008-02-22 23:11:23 +0100 | [diff] [blame] | 165 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 166 | local_irq_restore(flags); | 
|  | 167 | } | 
|  | 168 |  | 
| Yinghai Lu | 5fef55f | 2008-09-04 21:09:43 +0200 | [diff] [blame] | 169 | static void __cpuinit early_init_cyrix(struct cpuinfo_x86 *c) | 
|  | 170 | { | 
|  | 171 | unsigned char dir0, dir0_msn, dir1 = 0; | 
|  | 172 |  | 
|  | 173 | __do_cyrix_devid(&dir0, &dir1); | 
|  | 174 | dir0_msn = dir0 >> 4; /* identifies CPU "family"   */ | 
|  | 175 |  | 
|  | 176 | switch (dir0_msn) { | 
|  | 177 | case 3: /* 6x86/6x86L */ | 
|  | 178 | /* Emulate MTRRs using Cyrix's ARRs. */ | 
|  | 179 | set_cpu_cap(c, X86_FEATURE_CYRIX_ARR); | 
|  | 180 | break; | 
|  | 181 | case 5: /* 6x86MX/M II */ | 
|  | 182 | /* Emulate MTRRs using Cyrix's ARRs. */ | 
|  | 183 | set_cpu_cap(c, X86_FEATURE_CYRIX_ARR); | 
|  | 184 | break; | 
|  | 185 | } | 
|  | 186 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 187 |  | 
| Magnus Damm | b4af3f7 | 2006-09-26 10:52:36 +0200 | [diff] [blame] | 188 | static void __cpuinit init_cyrix(struct cpuinfo_x86 *c) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 189 | { | 
|  | 190 | unsigned char dir0, dir0_msn, dir0_lsn, dir1 = 0; | 
|  | 191 | char *buf = c->x86_model_id; | 
|  | 192 | const char *p = NULL; | 
|  | 193 |  | 
| Paolo Ciarrocchi | adf8526 | 2008-02-22 23:11:23 +0100 | [diff] [blame] | 194 | /* | 
|  | 195 | * Bit 31 in normal CPUID used for nonstandard 3DNow ID; | 
|  | 196 | * 3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway | 
|  | 197 | */ | 
| Ingo Molnar | 1d007cd | 2008-02-26 08:52:27 +0100 | [diff] [blame] | 198 | clear_cpu_cap(c, 0*32+31); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 199 |  | 
|  | 200 | /* Cyrix used bit 24 in extended (AMD) CPUID for Cyrix MMX extensions */ | 
| Ingo Molnar | 1d007cd | 2008-02-26 08:52:27 +0100 | [diff] [blame] | 201 | if (test_cpu_cap(c, 1*32+24)) { | 
|  | 202 | clear_cpu_cap(c, 1*32+24); | 
|  | 203 | set_cpu_cap(c, X86_FEATURE_CXMMX); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 204 | } | 
|  | 205 |  | 
|  | 206 | do_cyrix_devid(&dir0, &dir1); | 
|  | 207 |  | 
|  | 208 | check_cx686_slop(c); | 
|  | 209 |  | 
|  | 210 | Cx86_dir0_msb = dir0_msn = dir0 >> 4; /* identifies CPU "family"   */ | 
|  | 211 | dir0_lsn = dir0 & 0xf;                /* model or clock multiplier */ | 
|  | 212 |  | 
|  | 213 | /* common case step number/rev -- exceptions handled below */ | 
|  | 214 | c->x86_model = (dir1 >> 4) + 1; | 
|  | 215 | c->x86_mask = dir1 & 0xf; | 
|  | 216 |  | 
|  | 217 | /* Now cook; the original recipe is by Channing Corn, from Cyrix. | 
|  | 218 | * We do the same thing for each generation: we work out | 
|  | 219 | * the model, multiplier and stepping.  Black magic included, | 
|  | 220 | * to make the silicon step/rev numbers match the printed ones. | 
|  | 221 | */ | 
| Paolo Ciarrocchi | adf8526 | 2008-02-22 23:11:23 +0100 | [diff] [blame] | 222 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 223 | switch (dir0_msn) { | 
|  | 224 | unsigned char tmp; | 
|  | 225 |  | 
|  | 226 | case 0: /* Cx486SLC/DLC/SRx/DRx */ | 
|  | 227 | p = Cx486_name[dir0_lsn & 7]; | 
|  | 228 | break; | 
|  | 229 |  | 
|  | 230 | case 1: /* Cx486S/DX/DX2/DX4 */ | 
|  | 231 | p = (dir0_lsn & 8) ? Cx486D_name[dir0_lsn & 5] | 
|  | 232 | : Cx486S_name[dir0_lsn & 3]; | 
|  | 233 | break; | 
|  | 234 |  | 
|  | 235 | case 2: /* 5x86 */ | 
|  | 236 | Cx86_cb[2] = cyrix_model_mult1[dir0_lsn & 5]; | 
|  | 237 | p = Cx86_cb+2; | 
|  | 238 | break; | 
|  | 239 |  | 
|  | 240 | case 3: /* 6x86/6x86L */ | 
|  | 241 | Cx86_cb[1] = ' '; | 
|  | 242 | Cx86_cb[2] = cyrix_model_mult1[dir0_lsn & 5]; | 
|  | 243 | if (dir1 > 0x21) { /* 686L */ | 
|  | 244 | Cx86_cb[0] = 'L'; | 
|  | 245 | p = Cx86_cb; | 
|  | 246 | (c->x86_model)++; | 
|  | 247 | } else             /* 686 */ | 
|  | 248 | p = Cx86_cb+1; | 
|  | 249 | /* Emulate MTRRs using Cyrix's ARRs. */ | 
| Ingo Molnar | 1d007cd | 2008-02-26 08:52:27 +0100 | [diff] [blame] | 250 | set_cpu_cap(c, X86_FEATURE_CYRIX_ARR); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 251 | /* 6x86's contain this bug */ | 
|  | 252 | c->coma_bug = 1; | 
|  | 253 | break; | 
|  | 254 |  | 
|  | 255 | case 4: /* MediaGX/GXm or Geode GXM/GXLV/GX1 */ | 
|  | 256 | #ifdef CONFIG_PCI | 
| Alan | 120fad7 | 2007-02-13 13:26:26 +0100 | [diff] [blame] | 257 | { | 
|  | 258 | u32 vendor, device; | 
| Paolo Ciarrocchi | adf8526 | 2008-02-22 23:11:23 +0100 | [diff] [blame] | 259 | /* | 
|  | 260 | * It isn't really a PCI quirk directly, but the cure is the | 
|  | 261 | * same. The MediaGX has deep magic SMM stuff that handles the | 
|  | 262 | * SB emulation. It throws away the fifo on disable_dma() which | 
|  | 263 | * is wrong and ruins the audio. | 
|  | 264 | * | 
|  | 265 | *  Bug2: VSA1 has a wrap bug so that using maximum sized DMA | 
|  | 266 | *  causes bad things. According to NatSemi VSA2 has another | 
|  | 267 | *  bug to do with 'hlt'. I've not seen any boards using VSA2 | 
|  | 268 | *  and X doesn't seem to support it either so who cares 8). | 
|  | 269 | *  VSA1 we work around however. | 
|  | 270 | */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 271 |  | 
|  | 272 | printk(KERN_INFO "Working around Cyrix MediaGX virtual DMA bugs.\n"); | 
|  | 273 | isa_dma_bridge_buggy = 2; | 
| Andreas Mohr | cefc011 | 2006-06-23 02:04:26 -0700 | [diff] [blame] | 274 |  | 
| Alan | 120fad7 | 2007-02-13 13:26:26 +0100 | [diff] [blame] | 275 | /* We do this before the PCI layer is running. However we | 
|  | 276 | are safe here as we know the bridge must be a Cyrix | 
|  | 277 | companion and must be present */ | 
|  | 278 | vendor = read_pci_config_16(0, 0, 0x12, PCI_VENDOR_ID); | 
|  | 279 | device = read_pci_config_16(0, 0, 0x12, PCI_DEVICE_ID); | 
| Andreas Mohr | cefc011 | 2006-06-23 02:04:26 -0700 | [diff] [blame] | 280 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 281 | /* | 
|  | 282 | *  The 5510/5520 companion chips have a funky PIT. | 
| Paolo Ciarrocchi | adf8526 | 2008-02-22 23:11:23 +0100 | [diff] [blame] | 283 | */ | 
| Alan | 120fad7 | 2007-02-13 13:26:26 +0100 | [diff] [blame] | 284 | if (vendor == PCI_VENDOR_ID_CYRIX && | 
| Alan Cox | 8bdbd96 | 2009-07-04 00:35:45 +0100 | [diff] [blame] | 285 | (device == PCI_DEVICE_ID_CYRIX_5510 || | 
|  | 286 | device == PCI_DEVICE_ID_CYRIX_5520)) | 
| john stultz | 5a90cf2 | 2007-05-02 19:27:08 +0200 | [diff] [blame] | 287 | mark_tsc_unstable("cyrix 5510/5520 detected"); | 
| Alan | 120fad7 | 2007-02-13 13:26:26 +0100 | [diff] [blame] | 288 | } | 
| Andreas Mohr | cefc011 | 2006-06-23 02:04:26 -0700 | [diff] [blame] | 289 | #endif | 
| Paolo Ciarrocchi | adf8526 | 2008-02-22 23:11:23 +0100 | [diff] [blame] | 290 | c->x86_cache_size = 16;	/* Yep 16K integrated cache thats it */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 291 |  | 
|  | 292 | /* GXm supports extended cpuid levels 'ala' AMD */ | 
|  | 293 | if (c->cpuid_level == 2) { | 
|  | 294 | /* Enable cxMMX extensions (GX1 Datasheet 54) */ | 
| Ingo Molnar | 026e2c0 | 2008-07-22 11:58:14 +0200 | [diff] [blame] | 295 | setCx86_old(CX86_CCR7, getCx86_old(CX86_CCR7) | 1); | 
| Paolo Ciarrocchi | adf8526 | 2008-02-22 23:11:23 +0100 | [diff] [blame] | 296 |  | 
| takada | 2632f01 | 2007-02-13 13:26:24 +0100 | [diff] [blame] | 297 | /* | 
|  | 298 | * GXm : 0x30 ... 0x5f GXm  datasheet 51 | 
|  | 299 | * GXlv: 0x6x          GXlv datasheet 54 | 
|  | 300 | *  ?  : 0x7x | 
|  | 301 | * GX1 : 0x8x          GX1  datasheet 56 | 
|  | 302 | */ | 
| Alan Cox | 8bdbd96 | 2009-07-04 00:35:45 +0100 | [diff] [blame] | 303 | if ((0x30 <= dir1 && dir1 <= 0x6f) || | 
|  | 304 | (0x80 <= dir1 && dir1 <= 0x8f)) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 305 | geode_configure(); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 306 | return; | 
| Paolo Ciarrocchi | adf8526 | 2008-02-22 23:11:23 +0100 | [diff] [blame] | 307 | } else { /* MediaGX */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 308 | Cx86_cb[2] = (dir0_lsn & 1) ? '3' : '4'; | 
|  | 309 | p = Cx86_cb+2; | 
|  | 310 | c->x86_model = (dir1 & 0x20) ? 1 : 2; | 
|  | 311 | } | 
|  | 312 | break; | 
|  | 313 |  | 
| Paolo Ciarrocchi | adf8526 | 2008-02-22 23:11:23 +0100 | [diff] [blame] | 314 | case 5: /* 6x86MX/M II */ | 
|  | 315 | if (dir1 > 7) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 316 | dir0_msn++;  /* M II */ | 
|  | 317 | /* Enable MMX extensions (App note 108) */ | 
| Ingo Molnar | 026e2c0 | 2008-07-22 11:58:14 +0200 | [diff] [blame] | 318 | setCx86_old(CX86_CCR7, getCx86_old(CX86_CCR7)|1); | 
| Paolo Ciarrocchi | adf8526 | 2008-02-22 23:11:23 +0100 | [diff] [blame] | 319 | } else { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 320 | c->coma_bug = 1;      /* 6x86MX, it has the bug. */ | 
|  | 321 | } | 
|  | 322 | tmp = (!(dir0_lsn & 7) || dir0_lsn & 1) ? 2 : 0; | 
|  | 323 | Cx86_cb[tmp] = cyrix_model_mult2[dir0_lsn & 7]; | 
|  | 324 | p = Cx86_cb+tmp; | 
| Paolo Ciarrocchi | adf8526 | 2008-02-22 23:11:23 +0100 | [diff] [blame] | 325 | if (((dir1 & 0x0f) > 4) || ((dir1 & 0xf0) == 0x20)) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 326 | (c->x86_model)++; | 
|  | 327 | /* Emulate MTRRs using Cyrix's ARRs. */ | 
| Ingo Molnar | 1d007cd | 2008-02-26 08:52:27 +0100 | [diff] [blame] | 328 | set_cpu_cap(c, X86_FEATURE_CYRIX_ARR); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 329 | break; | 
|  | 330 |  | 
|  | 331 | case 0xf:  /* Cyrix 486 without DEVID registers */ | 
|  | 332 | switch (dir0_lsn) { | 
|  | 333 | case 0xd:  /* either a 486SLC or DLC w/o DEVID */ | 
|  | 334 | dir0_msn = 0; | 
|  | 335 | p = Cx486_name[(c->hard_math) ? 1 : 0]; | 
|  | 336 | break; | 
|  | 337 |  | 
|  | 338 | case 0xe:  /* a 486S A step */ | 
|  | 339 | dir0_msn = 0; | 
|  | 340 | p = Cx486S_name[0]; | 
|  | 341 | break; | 
|  | 342 | } | 
|  | 343 | break; | 
|  | 344 |  | 
|  | 345 | default:  /* unknown (shouldn't happen, we know everyone ;-) */ | 
|  | 346 | dir0_msn = 7; | 
|  | 347 | break; | 
|  | 348 | } | 
|  | 349 | strcpy(buf, Cx86_model[dir0_msn & 7]); | 
| Paolo Ciarrocchi | adf8526 | 2008-02-22 23:11:23 +0100 | [diff] [blame] | 350 | if (p) | 
|  | 351 | strcat(buf, p); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 352 | return; | 
|  | 353 | } | 
|  | 354 |  | 
|  | 355 | /* | 
| Jordan Crouse | f90b811 | 2006-01-06 00:12:14 -0800 | [diff] [blame] | 356 | * Handle National Semiconductor branded processors | 
|  | 357 | */ | 
| Magnus Damm | b4af3f7 | 2006-09-26 10:52:36 +0200 | [diff] [blame] | 358 | static void __cpuinit init_nsc(struct cpuinfo_x86 *c) | 
| Jordan Crouse | f90b811 | 2006-01-06 00:12:14 -0800 | [diff] [blame] | 359 | { | 
| Paolo Ciarrocchi | adf8526 | 2008-02-22 23:11:23 +0100 | [diff] [blame] | 360 | /* | 
|  | 361 | * There may be GX1 processors in the wild that are branded | 
| Jordan Crouse | f90b811 | 2006-01-06 00:12:14 -0800 | [diff] [blame] | 362 | * NSC and not Cyrix. | 
|  | 363 | * | 
|  | 364 | * This function only handles the GX processor, and kicks every | 
|  | 365 | * thing else to the Cyrix init function above - that should | 
|  | 366 | * cover any processors that might have been branded differently | 
| Andreas Mohr | d6e05ed | 2006-06-26 18:35:02 +0200 | [diff] [blame] | 367 | * after NSC acquired Cyrix. | 
| Jordan Crouse | f90b811 | 2006-01-06 00:12:14 -0800 | [diff] [blame] | 368 | * | 
|  | 369 | * If this breaks your GX1 horribly, please e-mail | 
|  | 370 | * info-linux@ldcmail.amd.com to tell us. | 
|  | 371 | */ | 
|  | 372 |  | 
|  | 373 | /* Handle the GX (Formally known as the GX2) */ | 
|  | 374 |  | 
|  | 375 | if (c->x86 == 5 && c->x86_model == 5) | 
| Borislav Petkov | 27c13ec | 2009-11-21 14:01:45 +0100 | [diff] [blame] | 376 | cpu_detect_cache_sizes(c); | 
| Jordan Crouse | f90b811 | 2006-01-06 00:12:14 -0800 | [diff] [blame] | 377 | else | 
|  | 378 | init_cyrix(c); | 
|  | 379 | } | 
|  | 380 |  | 
|  | 381 | /* | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 382 | * Cyrix CPUs without cpuid or with cpuid not yet enabled can be detected | 
|  | 383 | * by the fact that they preserve the flags across the division of 5/2. | 
|  | 384 | * PII and PPro exhibit this behavior too, but they have cpuid available. | 
|  | 385 | */ | 
| Paolo Ciarrocchi | adf8526 | 2008-02-22 23:11:23 +0100 | [diff] [blame] | 386 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 387 | /* | 
|  | 388 | * Perform the Cyrix 5/2 test. A Cyrix won't change | 
|  | 389 | * the flags, while other 486 chips will. | 
|  | 390 | */ | 
|  | 391 | static inline int test_cyrix_52div(void) | 
|  | 392 | { | 
|  | 393 | unsigned int test; | 
|  | 394 |  | 
|  | 395 | __asm__ __volatile__( | 
|  | 396 | "sahf\n\t"		/* clear flags (%eax = 0x0005) */ | 
|  | 397 | "div %b2\n\t"	/* divide 5 by 2 */ | 
|  | 398 | "lahf"		/* store flags into %ah */ | 
|  | 399 | : "=a" (test) | 
|  | 400 | : "0" (5), "q" (2) | 
|  | 401 | : "cc"); | 
|  | 402 |  | 
|  | 403 | /* AH is 0x02 on Cyrix after the divide.. */ | 
|  | 404 | return (unsigned char) (test >> 8) == 0x02; | 
|  | 405 | } | 
|  | 406 |  | 
| Paolo Ciarrocchi | adf8526 | 2008-02-22 23:11:23 +0100 | [diff] [blame] | 407 | static void __cpuinit cyrix_identify(struct cpuinfo_x86 *c) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 408 | { | 
|  | 409 | /* Detect Cyrix with disabled CPUID */ | 
| Paolo Ciarrocchi | adf8526 | 2008-02-22 23:11:23 +0100 | [diff] [blame] | 410 | if (c->x86 == 4 && test_cyrix_52div()) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 411 | unsigned char dir0, dir1; | 
| Paolo Ciarrocchi | adf8526 | 2008-02-22 23:11:23 +0100 | [diff] [blame] | 412 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 413 | strcpy(c->x86_vendor_id, "CyrixInstead"); | 
| Paolo Ciarrocchi | adf8526 | 2008-02-22 23:11:23 +0100 | [diff] [blame] | 414 | c->x86_vendor = X86_VENDOR_CYRIX; | 
|  | 415 |  | 
|  | 416 | /* Actually enable cpuid on the older cyrix */ | 
|  | 417 |  | 
|  | 418 | /* Retrieve CPU revisions */ | 
|  | 419 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 420 | do_cyrix_devid(&dir0, &dir1); | 
|  | 421 |  | 
| Paolo Ciarrocchi | adf8526 | 2008-02-22 23:11:23 +0100 | [diff] [blame] | 422 | dir0 >>= 4; | 
|  | 423 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 424 | /* Check it is an affected model */ | 
| Paolo Ciarrocchi | adf8526 | 2008-02-22 23:11:23 +0100 | [diff] [blame] | 425 |  | 
|  | 426 | if (dir0 == 5 || dir0 == 3) { | 
| TAKADA Yoshihito | bcde1eb | 2007-02-13 13:26:25 +0100 | [diff] [blame] | 427 | unsigned char ccr3; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 428 | unsigned long flags; | 
|  | 429 | printk(KERN_INFO "Enabling CPUID on Cyrix processor.\n"); | 
|  | 430 | local_irq_save(flags); | 
|  | 431 | ccr3 = getCx86(CX86_CCR3); | 
| Alan Cox | 8bdbd96 | 2009-07-04 00:35:45 +0100 | [diff] [blame] | 432 | /* enable MAPEN  */ | 
|  | 433 | setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); | 
|  | 434 | /* enable cpuid  */ | 
|  | 435 | setCx86_old(CX86_CCR4, getCx86_old(CX86_CCR4) | 0x80); | 
|  | 436 | /* disable MAPEN */ | 
|  | 437 | setCx86(CX86_CCR3, ccr3); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 438 | local_irq_restore(flags); | 
|  | 439 | } | 
|  | 440 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 441 | } | 
|  | 442 |  | 
| Jan Beulich | 02dde8b | 2009-03-12 12:08:49 +0000 | [diff] [blame] | 443 | static const struct cpu_dev __cpuinitconst cyrix_cpu_dev = { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 444 | .c_vendor	= "Cyrix", | 
| Paolo Ciarrocchi | adf8526 | 2008-02-22 23:11:23 +0100 | [diff] [blame] | 445 | .c_ident	= { "CyrixInstead" }, | 
| Yinghai Lu | 5fef55f | 2008-09-04 21:09:43 +0200 | [diff] [blame] | 446 | .c_early_init	= early_init_cyrix, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 447 | .c_init		= init_cyrix, | 
|  | 448 | .c_identify	= cyrix_identify, | 
| Yinghai Lu | 10a434f | 2008-09-04 21:09:45 +0200 | [diff] [blame] | 449 | .c_x86_vendor	= X86_VENDOR_CYRIX, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 450 | }; | 
|  | 451 |  | 
| Yinghai Lu | 10a434f | 2008-09-04 21:09:45 +0200 | [diff] [blame] | 452 | cpu_dev_register(cyrix_cpu_dev); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 453 |  | 
| Jan Beulich | 02dde8b | 2009-03-12 12:08:49 +0000 | [diff] [blame] | 454 | static const struct cpu_dev __cpuinitconst nsc_cpu_dev = { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 455 | .c_vendor	= "NSC", | 
| Paolo Ciarrocchi | adf8526 | 2008-02-22 23:11:23 +0100 | [diff] [blame] | 456 | .c_ident	= { "Geode by NSC" }, | 
| Jordan Crouse | f90b811 | 2006-01-06 00:12:14 -0800 | [diff] [blame] | 457 | .c_init		= init_nsc, | 
| Yinghai Lu | 10a434f | 2008-09-04 21:09:45 +0200 | [diff] [blame] | 458 | .c_x86_vendor	= X86_VENDOR_NSC, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 459 | }; | 
|  | 460 |  | 
| Yinghai Lu | 10a434f | 2008-09-04 21:09:45 +0200 | [diff] [blame] | 461 | cpu_dev_register(nsc_cpu_dev); |