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