direct-io.hg

view xen/arch/x86/cpu/cyrix.c @ 11135:88e6bd5e2b54

Whitespace clean-ups.

Signed-off-by: Steven Hand <steven@xensource.com>
author shand@kneesaa.uk.xensource.com
date Wed Aug 16 11:36:13 2006 +0100 (2006-08-16)
parents 41a5c6143c83
children bef7fbe25a9f
line source
1 #include <xen/config.h>
2 #include <xen/init.h>
3 #include <xen/irq.h>
4 #include <xen/bitops.h>
5 #include <xen/delay.h>
6 #include <asm/io.h>
7 #include <asm/processor.h>
9 #include "cpu.h"
11 /*
12 * Read NSC/Cyrix DEVID registers (DIR) to get more detailed info. about the CPU
13 */
14 void __init do_cyrix_devid(unsigned char *dir0, unsigned char *dir1)
15 {
16 unsigned char ccr2, ccr3;
17 unsigned long flags;
19 /* we test for DEVID by checking whether CCR3 is writable */
20 local_irq_save(flags);
21 ccr3 = getCx86(CX86_CCR3);
22 setCx86(CX86_CCR3, ccr3 ^ 0x80);
23 getCx86(0xc0); /* dummy to change bus */
25 if (getCx86(CX86_CCR3) == ccr3) { /* no DEVID regs. */
26 ccr2 = getCx86(CX86_CCR2);
27 setCx86(CX86_CCR2, ccr2 ^ 0x04);
28 getCx86(0xc0); /* dummy */
30 if (getCx86(CX86_CCR2) == ccr2) /* old Cx486SLC/DLC */
31 *dir0 = 0xfd;
32 else { /* Cx486S A step */
33 setCx86(CX86_CCR2, ccr2);
34 *dir0 = 0xfe;
35 }
36 }
37 else {
38 setCx86(CX86_CCR3, ccr3); /* restore CCR3 */
40 /* read DIR0 and DIR1 CPU registers */
41 *dir0 = getCx86(CX86_DIR0);
42 *dir1 = getCx86(CX86_DIR1);
43 }
44 local_irq_restore(flags);
45 }
47 /*
48 * Cx86_dir0_msb is a HACK needed by check_cx686_cpuid/slop in bugs.h in
49 * order to identify the Cyrix CPU model after we're out of setup.c
50 *
51 * Actually since bugs.h doesn't even reference this perhaps someone should
52 * fix the documentation ???
53 */
54 static unsigned char Cx86_dir0_msb __initdata = 0;
56 static char Cx86_model[][9] __initdata = {
57 "Cx486", "Cx486", "5x86 ", "6x86", "MediaGX ", "6x86MX ",
58 "M II ", "Unknown"
59 };
60 static char Cx486_name[][5] __initdata = {
61 "SLC", "DLC", "SLC2", "DLC2", "SRx", "DRx",
62 "SRx2", "DRx2"
63 };
64 static char Cx486S_name[][4] __initdata = {
65 "S", "S2", "Se", "S2e"
66 };
67 static char Cx486D_name[][4] __initdata = {
68 "DX", "DX2", "?", "?", "?", "DX4"
69 };
70 static char Cx86_cb[] __initdata = "?.5x Core/Bus Clock";
71 static char cyrix_model_mult1[] __initdata = "12??43";
72 static char cyrix_model_mult2[] __initdata = "12233445";
74 /*
75 * Reset the slow-loop (SLOP) bit on the 686(L) which is set by some old
76 * BIOSes for compatibility with DOS games. This makes the udelay loop
77 * work correctly, and improves performance.
78 *
79 * FIXME: our newer udelay uses the tsc. We don't need to frob with SLOP
80 */
82 static void __init check_cx686_slop(struct cpuinfo_x86 *c)
83 {
84 unsigned long flags;
86 if (Cx86_dir0_msb == 3) {
87 unsigned char ccr3, ccr5;
89 local_irq_save(flags);
90 ccr3 = getCx86(CX86_CCR3);
91 setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN */
92 ccr5 = getCx86(CX86_CCR5);
93 if (ccr5 & 2)
94 setCx86(CX86_CCR5, ccr5 & 0xfd); /* reset SLOP */
95 setCx86(CX86_CCR3, ccr3); /* disable MAPEN */
96 local_irq_restore(flags);
97 }
98 }
101 static void __init set_cx86_reorder(void)
102 {
103 u8 ccr3;
105 printk(KERN_INFO "Enable Memory access reorder on Cyrix/NSC processor.\n");
106 ccr3 = getCx86(CX86_CCR3);
107 setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN  */
109 /* Load/Store Serialize to mem access disable (=reorder it)  */
110 setCx86(CX86_PCR0, getCx86(CX86_PCR0) & ~0x80);
111 /* set load/store serialize from 1GB to 4GB */
112 ccr3 |= 0xe0;
113 setCx86(CX86_CCR3, ccr3);
114 }
116 static void __init set_cx86_memwb(void)
117 {
118 u32 cr0;
120 printk(KERN_INFO "Enable Memory-Write-back mode on Cyrix/NSC processor.\n");
122 /* CCR2 bit 2: unlock NW bit */
123 setCx86(CX86_CCR2, getCx86(CX86_CCR2) & ~0x04);
124 /* set 'Not Write-through' */
125 cr0 = 0x20000000;
126 __asm__("movl %%cr0,%%eax\n\t"
127 "orl %0,%%eax\n\t"
128 "movl %%eax,%%cr0\n"
129 : : "r" (cr0)
130 :"ax");
131 /* CCR2 bit 2: lock NW bit and set WT1 */
132 setCx86(CX86_CCR2, getCx86(CX86_CCR2) | 0x14 );
133 }
135 static void __init set_cx86_inc(void)
136 {
137 unsigned char ccr3;
139 printk(KERN_INFO "Enable Incrementor on Cyrix/NSC processor.\n");
141 ccr3 = getCx86(CX86_CCR3);
142 setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN  */
143 /* PCR1 -- Performance Control */
144 /* Incrementor on, whatever that is */
145 setCx86(CX86_PCR1, getCx86(CX86_PCR1) | 0x02);
146 /* PCR0 -- Performance Control */
147 /* Incrementor Margin 10 */
148 setCx86(CX86_PCR0, getCx86(CX86_PCR0) | 0x04);
149 setCx86(CX86_CCR3, ccr3); /* disable MAPEN */
150 }
152 /*
153 * Configure later MediaGX and/or Geode processor.
154 */
156 static void __init geode_configure(void)
157 {
158 unsigned long flags;
159 u8 ccr3, ccr4;
160 local_irq_save(flags);
162 /* Suspend on halt power saving and enable #SUSP pin */
163 setCx86(CX86_CCR2, getCx86(CX86_CCR2) | 0x88);
165 ccr3 = getCx86(CX86_CCR3);
166 setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* Enable */
168 ccr4 = getCx86(CX86_CCR4);
169 ccr4 |= 0x38; /* FPU fast, DTE cache, Mem bypass */
171 setCx86(CX86_CCR3, ccr3);
173 set_cx86_memwb();
174 set_cx86_reorder();
175 set_cx86_inc();
177 local_irq_restore(flags);
178 }
181 static void __init init_cyrix(struct cpuinfo_x86 *c)
182 {
183 unsigned char dir0, dir0_msn, dir0_lsn, dir1 = 0;
184 char *buf = c->x86_model_id;
185 const char *p = NULL;
187 /* Bit 31 in normal CPUID used for nonstandard 3DNow ID;
188 3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway */
189 clear_bit(0*32+31, c->x86_capability);
191 /* Cyrix used bit 24 in extended (AMD) CPUID for Cyrix MMX extensions */
192 if ( test_bit(1*32+24, c->x86_capability) ) {
193 clear_bit(1*32+24, c->x86_capability);
194 set_bit(X86_FEATURE_CXMMX, c->x86_capability);
195 }
197 do_cyrix_devid(&dir0, &dir1);
199 check_cx686_slop(c);
201 Cx86_dir0_msb = dir0_msn = dir0 >> 4; /* identifies CPU "family" */
202 dir0_lsn = dir0 & 0xf; /* model or clock multiplier */
204 /* common case step number/rev -- exceptions handled below */
205 c->x86_model = (dir1 >> 4) + 1;
206 c->x86_mask = dir1 & 0xf;
208 /* Now cook; the original recipe is by Channing Corn, from Cyrix.
209 * We do the same thing for each generation: we work out
210 * the model, multiplier and stepping. Black magic included,
211 * to make the silicon step/rev numbers match the printed ones.
212 */
214 switch (dir0_msn) {
215 unsigned char tmp;
217 case 0: /* Cx486SLC/DLC/SRx/DRx */
218 p = Cx486_name[dir0_lsn & 7];
219 break;
221 case 1: /* Cx486S/DX/DX2/DX4 */
222 p = (dir0_lsn & 8) ? Cx486D_name[dir0_lsn & 5]
223 : Cx486S_name[dir0_lsn & 3];
224 break;
226 case 2: /* 5x86 */
227 Cx86_cb[2] = cyrix_model_mult1[dir0_lsn & 5];
228 p = Cx86_cb+2;
229 break;
231 case 3: /* 6x86/6x86L */
232 Cx86_cb[1] = ' ';
233 Cx86_cb[2] = cyrix_model_mult1[dir0_lsn & 5];
234 if (dir1 > 0x21) { /* 686L */
235 Cx86_cb[0] = 'L';
236 p = Cx86_cb;
237 (c->x86_model)++;
238 } else /* 686 */
239 p = Cx86_cb+1;
240 /* Emulate MTRRs using Cyrix's ARRs. */
241 set_bit(X86_FEATURE_CYRIX_ARR, c->x86_capability);
242 /* 6x86's contain this bug */
243 c->coma_bug = 1;
244 break;
246 case 4: /* MediaGX/GXm or Geode GXM/GXLV/GX1 */
247 c->x86_cache_size=16; /* Yep 16K integrated cache thats it */
249 /* GXm supports extended cpuid levels 'ala' AMD */
250 if (c->cpuid_level == 2) {
251 /* Enable cxMMX extensions (GX1 Datasheet 54) */
252 setCx86(CX86_CCR7, getCx86(CX86_CCR7)|1);
254 /* GXlv/GXm/GX1 */
255 if((dir1 >= 0x50 && dir1 <= 0x54) || dir1 >= 0x63)
256 geode_configure();
257 get_model_name(c); /* get CPU marketing name */
258 return;
259 }
260 else { /* MediaGX */
261 Cx86_cb[2] = (dir0_lsn & 1) ? '3' : '4';
262 p = Cx86_cb+2;
263 c->x86_model = (dir1 & 0x20) ? 1 : 2;
264 }
265 break;
267 case 5: /* 6x86MX/M II */
268 if (dir1 > 7)
269 {
270 dir0_msn++; /* M II */
271 /* Enable MMX extensions (App note 108) */
272 setCx86(CX86_CCR7, getCx86(CX86_CCR7)|1);
273 }
274 else
275 {
276 c->coma_bug = 1; /* 6x86MX, it has the bug. */
277 }
278 tmp = (!(dir0_lsn & 7) || dir0_lsn & 1) ? 2 : 0;
279 Cx86_cb[tmp] = cyrix_model_mult2[dir0_lsn & 7];
280 p = Cx86_cb+tmp;
281 if (((dir1 & 0x0f) > 4) || ((dir1 & 0xf0) == 0x20))
282 (c->x86_model)++;
283 /* Emulate MTRRs using Cyrix's ARRs. */
284 set_bit(X86_FEATURE_CYRIX_ARR, c->x86_capability);
285 break;
287 case 0xf: /* Cyrix 486 without DEVID registers */
288 switch (dir0_lsn) {
289 case 0xd: /* either a 486SLC or DLC w/o DEVID */
290 dir0_msn = 0;
291 p = Cx486_name[(c->hard_math) ? 1 : 0];
292 break;
294 case 0xe: /* a 486S A step */
295 dir0_msn = 0;
296 p = Cx486S_name[0];
297 break;
298 }
299 break;
301 default: /* unknown (shouldn't happen, we know everyone ;-) */
302 dir0_msn = 7;
303 break;
304 }
305 strcpy(buf, Cx86_model[dir0_msn & 7]);
306 if (p) strcat(buf, p);
307 return;
308 }
310 /*
311 * Cyrix CPUs without cpuid or with cpuid not yet enabled can be detected
312 * by the fact that they preserve the flags across the division of 5/2.
313 * PII and PPro exhibit this behavior too, but they have cpuid available.
314 */
316 /*
317 * Perform the Cyrix 5/2 test. A Cyrix won't change
318 * the flags, while other 486 chips will.
319 */
320 static inline int test_cyrix_52div(void)
321 {
322 unsigned int test;
324 __asm__ __volatile__(
325 "sahf\n\t" /* clear flags (%eax = 0x0005) */
326 "div %b2\n\t" /* divide 5 by 2 */
327 "lahf" /* store flags into %ah */
328 : "=a" (test)
329 : "0" (5), "q" (2)
330 : "cc");
332 /* AH is 0x02 on Cyrix after the divide.. */
333 return (unsigned char) (test >> 8) == 0x02;
334 }
336 static void cyrix_identify(struct cpuinfo_x86 * c)
337 {
338 /* Detect Cyrix with disabled CPUID */
339 if ( c->x86 == 4 && test_cyrix_52div() ) {
340 unsigned char dir0, dir1;
342 strcpy(c->x86_vendor_id, "CyrixInstead");
343 c->x86_vendor = X86_VENDOR_CYRIX;
345 /* Actually enable cpuid on the older cyrix */
347 /* Retrieve CPU revisions */
349 do_cyrix_devid(&dir0, &dir1);
351 dir0>>=4;
353 /* Check it is an affected model */
355 if (dir0 == 5 || dir0 == 3)
356 {
357 unsigned char ccr3, ccr4;
358 unsigned long flags;
359 printk(KERN_INFO "Enabling CPUID on Cyrix processor.\n");
360 local_irq_save(flags);
361 ccr3 = getCx86(CX86_CCR3);
362 setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN */
363 ccr4 = getCx86(CX86_CCR4);
364 setCx86(CX86_CCR4, ccr4 | 0x80); /* enable cpuid */
365 setCx86(CX86_CCR3, ccr3); /* disable MAPEN */
366 local_irq_restore(flags);
367 }
368 }
369 generic_identify(c);
370 }
372 static struct cpu_dev cyrix_cpu_dev __initdata = {
373 .c_vendor = "Cyrix",
374 .c_ident = { "CyrixInstead" },
375 .c_init = init_cyrix,
376 .c_identify = cyrix_identify,
377 };
379 int __init cyrix_init_cpu(void)
380 {
381 cpu_devs[X86_VENDOR_CYRIX] = &cyrix_cpu_dev;
382 return 0;
383 }
385 //early_arch_initcall(cyrix_init_cpu);
387 static struct cpu_dev nsc_cpu_dev __initdata = {
388 .c_vendor = "NSC",
389 .c_ident = { "Geode by NSC" },
390 .c_init = init_cyrix,
391 .c_identify = generic_identify,
392 };
394 int __init nsc_init_cpu(void)
395 {
396 cpu_devs[X86_VENDOR_NSC] = &nsc_cpu_dev;
397 return 0;
398 }
400 //early_arch_initcall(nsc_init_cpu);