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