1 /*
2 * This is the X11R5 x386 driver for ATI VGA WONDER video adapters. At
3 * present, this drive works best with ATI VGA WONDER PLUS and ATI VGA
4 * WONDER XL cards with the ATI18810 dot clock and the ATI28800-5 chip.
5 * ATI VGA WONDER cards with other chips revisions may not function as
6 * desired.
7 *
8 * Revised: Sat Feb 13 13:23:18 1993 by root@winter
9 *
10 */
11
12 /*
13 * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
14 *
15 * Permission to use, copy, modify, distribute, and sell this software and its
16 * documentation for any purpose is hereby granted without fee, provided that
17 * the above copyright notice appear in all copies and that both that
18 * copyright notice and this permission notice appear in supporting
19 * documentation, and that the name of Thomas Roell not be used in
20 * advertising or publicity pertaining to distribution of the software without
21 * specific, written prior permission. Thomas Roell makes no representations
22 * about the suitability of this software for any purpose. It is provided
23 * "as is" without express or implied warranty.
24 *
25 * THOMAS ROELL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
26 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
27 * EVENT SHALL THOMAS ROELL BE LIABLE FOR ANY SPECIAL, INDIRECT OR
28 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
29 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
30 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
31 * PERFORMANCE OF THIS SOFTWARE.
32 *
33 * Author: Thomas Roell, roell@informatik.tu-muenchen.de
34 *
35 * $XFree86: mit/server/ddx/x386/vga256/drivers/ati/driver.c,v 2.12 1993/10/18 12:18:47 dawes Exp $
36 */
37
38 /*
39 * Hacked, to get it working by:
40 * Per Lindqvist, pgd@compuram.bbt.se
41 *
42 * Enhancements to support most VGA Wonder cards (including Plus and XL)
43 * by Doug Evans, dje@sspiff.UUCP.
44 * ALL DISCLAIMERS APPLY TO THESE ADDITIONS AS WELL.
45 *
46 * I've come to believe the people who design these cards couldn't
47 * allow for future enhancements if their life depended on it!
48 * The register set architecture is a joke!
49 *
50 */
51
52 /*
53 * Hacked for X11R5 by Rik Faith (faith@cs.unc.edu), Thu Aug 6 21:35:18 1992
54 * ALL DISCLAIMERS APPLY TO MY ADDITIONS AS WELL.
55 *
56 * I wrote the ATIProbe and ATIEnterLeave routines from scratch. I also
57 * re-organized the ATISave and ATIRestore routines. This was necessary,
58 * since the vgaHWSave routine did not save the DAC values. There also
59 * appeared to be a timing problem associated with the 486-33, but this is
60 * not well understood at this time.
61 *
62 * Change log, faith@cs.unc.edu:
63 * 3Feb93: ER_B0 in extregPlusXLAndOrMasks changed from 0x28 to 0x31.
64 * 3Feb93: ER_BE in extregPlusXLAndOrMasks changed from 0x08 to 0x18,
65 * but ONLY for chips BEFORE the 28800-5. This required adding
66 * the ATIChipVersion variable.
67 * 3Feb93: Added message stating correct clocks line.
68 * 13Feb93: Fixed warning message for unsupported boards.
69 * 13Feb93: Added comments and shortened lines over 80 characters long.
70 * 13Feb93: Added the Graphics Ultra Plus \'a\' chip version
71 */
72
73 /*
74 * NOTES:
75 *
76 * 1) The ATI 18800/28800 use a special registers for their extended
77 * features. There is one index and one data register. Under MS-DOS this
78 * should be specified by reading C000:10. But since we cannot read this
79 * now, let's use the same fixed address as our unix kernel does:
80 * 0x1CE/0x1CF. I also got these ports form a second source, thus it seems
81 * to be safe to use them.
82 *
83 * This comment is no longer valid. We read C000:10.
84 *
85 * 2) The ATI 18800/28800 extended registers differ in their i/o behaviour
86 * from the normal ones:
87 *
88 * write: outw(0x1CE, (data << 8) | index);
89 * read: outb(0x1CE, index); data = inb(0x1CF);
90 *
91 * Two consecutive byte-writes are NOT allowed. Furthermore is a index
92 * written to 0x1CE only usable ONCE !!!
93 *
94 * More notes by dje ...
95 *
96 * 3) I've tried to allow for a future when this code drives all VGA Wonder
97 * cards. To do this I had decide what to do with the clock values. Boards
98 * prior to V5 use 4 crystals. Boards V5 and later use a clock generator
99 * chip. Just to complicate things a bit, V3 and V4 boards aren't
100 * compatible when it comes to choosing clock frequencies. :-(
101 *
102 * V3/V4 Board Clock Frequencies
103 * R E G I S T E R S
104 * 1CE(*) 3C2 3C2 Frequency
105 * B2h/BEh
106 * Bit 6/4 Bit 3 Bit 2
107 * --------- ------- ------- ---------
108 * 0 0 0 50.175
109 * 0 0 1 56.644
110 * 0 1 0 Spare 1
111 * 0 1 1 44.900
112 * 1 0 0 44.900
113 * 1 0 1 50.175
114 * 1 1 0 Spare 2
115 * 1 1 1 36.000
116 *
117 * (*): V3 uses Index B2h, bit 6; V4 uses Index BEh, bit 4.
118 *
119 * V5,Plus,XL Board Clock Frequencies
120 * R E G I S T E R S
121 * 1CE 1CE 3C2 3C2 Frequency
122 * BEh B9h
123 * Bit 4 Bit 1 Bit 3 Bit 2
124 * ------- ------- ------- ------- ---------
125 * 1 0 0 0 42.954
126 * 1 0 0 1 48.771
127 * 1 0 1 0 External 0 (16.657)
128 * 1 0 1 1 36.000
129 * 1 1 0 0 50.350
130 * 1 1 0 1 56.640
131 * 1 1 1 0 External 1 (28.322)
132 * 1 1 1 1 44.900
133 * 0 0 0 0 30.240
134 * 0 0 0 1 32.000
135 * 0 0 1 0 37.500
136 * 0 0 1 1 39.000
137 * 0 1 0 0 40.000
138 * 0 1 0 1 56.644
139 * 0 1 1 0 75.000
140 * 0 1 1 1 65.000
141 *
142 * For all of the above (V3,V4,V5,Plus,XL), these frequencies can be
143 * divided by 1, 2, 3, or 4:
144 *
145 * Reg 1CE, Index B8h
146 * Bit 7 Bit 6
147 * 0 0 Divide by 1
148 * 0 1 Divide by 2
149 * 1 0 Divide by 3
150 * 1 1 Divide by 4
151 *
152 * What I've done is the following. The clock values specified in Xconfig
153 * shall be:
154 *
155 * 18 22 25 28 36 44 50 56
156 * 30 32 37 39 40 0 75 65 (duplicate 56: --> 0)
157 *
158 * The first row is usable on all VGA Wonder cards. The second row is
159 * only usable on V5,Plus,XL cards. The code in ATIInit() will map these
160 * clock values into the appropriate bit settings for each of the cards.
161 * Some of these clock choices aren't really usable, think of these as
162 * place holders.
163 *
164 * 4) The ATI Programmer's Reference Manual lacked enough prose to explain
165 * what the various bits of all of the various registers do. It is
166 * entirely reasonable to believe some of the choices I've made are
167 * imperfect because I didn't understand what I was doing.
168 *
169 * 5) V3 board support needs a lot of work. I suspect it isn't worth it.
170 */
171
172
173 #include "X.h"
174 #include "input.h"
175 #include "screenint.h"
176
177 #include "compiler.h"
178
179 #include "x386.h"
180 #include "x386Priv.h"
181 #include "xf86_OSlib.h"
182 #include "xf86_HWlib.h"
183 #include "vga.h"
184 #include <sys/types.h>
185
186 #define DEBUG 0
187
188 #if DEBUG
189 #define TRACE(a) ErrorF a /* Enable TRACE statements */
190 #define DEBUG_PROBE 0 /* Debug the ATIProbe() routine */
191 #else
192 #define TRACE(a) /* Disable TRACE statements */
193 #endif
194
195 typedef struct {
196 vgaHWRec std; /* good old IBM VGA */
197 unsigned char ATIExtRegBank[11]; /* ATI Registers B0,B1,B2,B3,B5,B6,B8,B9,BE,A6,A7 */
198 } vgaATIRec, *vgaATIPtr;
199
200 #define ATI_BOARD_V3 0 /* which ATI board does the user have? */
201 #define ATI_BOARD_V4 1 /* keep these chronologically increasing */
202 #define ATI_BOARD_V5 2
203 #define ATI_BOARD_PLUS 3
204 #define ATI_BOARD_XL 4
205
206 #define ER_B0 0 /* Extended Register indices (ATIExtRegBank) */
207 #define ER_B1 1
208 #define ER_B2 2
209 #define ER_B3 3
210 #define ER_B5 4
211 #define ER_B6 5
212 #define ER_B8 6
213 #define ER_B9 7
214 #define ER_BE 8
215 #define ER_A6 9
216 #define ER_A7 10
217
218 #define ATIReg0 ATIExtRegBank[ER_B0] /* simplifies dje's additions */
219 #define ATIReg1 ATIExtRegBank[ER_B1]
220 #define ATIReg2 ATIExtRegBank[ER_B2]
221 #define ATIReg3 ATIExtRegBank[ER_B3]
222 #define ATIReg5 ATIExtRegBank[ER_B5]
223 #define ATIReg6 ATIExtRegBank[ER_B6]
224 #define ATIReg8 ATIExtRegBank[ER_B8]
225 #define ATIReg9 ATIExtRegBank[ER_B9]
226 #define ATIRegE ATIExtRegBank[ER_BE]
227 #define ATIRegA6 ATIExtRegBank[ER_A6]
228 #define ATIRegA7 ATIExtRegBank[ER_A7]
229
230 static Bool ATIProbe();
231 static char *ATIIdent();
232 static void ATIEnterLeave();
233 static Bool ATIInit();
234 static void *ATISave();
235 static void ATIRestore();
236 static void ATIAdjust();
237 extern void ATISetRead();
238 extern void ATISetWrite();
239 extern void ATISetReadWrite();
240 static int inATI();
241
242 vgaVideoChipRec ATI = {
243 ATIProbe,
244 ATIIdent,
245 ATIEnterLeave,
246 ATIInit,
247 ATISave,
248 ATIRestore,
249 ATIAdjust,
250 NoopDDA,
251 NoopDDA,
252 NoopDDA,
253 ATISetRead,
254 ATISetWrite,
255 ATISetReadWrite,
256 0x10000,
257 0x10000,
258 16,
259 0xFFFF,
260 0x00000, 0x10000,
261 0x00000, 0x10000,
262 TRUE, /* uses 2 banks */
263 VGA_DIVIDE_VERT,
264 {0,},
265 16,
266 };
267
268 short ATIExtReg = 0x1ce; /* used by bank.s (must be short!) */
269
270 static int ATIBoard; /* one of ATI_BOARD_XXX */
271 static int ATIChipVersion; /* chip version number */
272
273 /*
274 * ATIIdent --
275 */
276 static char *
ATIIdent(n)277 ATIIdent(n)
278 int n;
279 {
280 static char *chipsets[] = {"ati"};
281
282 if (n + 1 > sizeof(chipsets) / sizeof(char *))
283 return(NULL);
284 else
285 return(chipsets[n]);
286 }
287
288 /*
289 * ATIRestore --
290 * restore a video mode
291 *
292 * Results:
293 * nope.
294 *
295 * Side Effects:
296 * the display enters a new graphics mode.
297 */
298
299 static void
ATIRestore(restore)300 ATIRestore(restore)
301 vgaATIPtr restore;
302 {
303 int i;
304
305 TRACE(("ATIRestore(restore=0x%x)\n", restore));
306
307 if (vgaIOBase == 0x3B0)
308 restore->std.MiscOutReg &= 0xFE;
309 else
310 restore->std.MiscOutReg |= 0x01;
311
312 /* Disable video */
313 (void) inb(vgaIOBase + 0x0A); /* reset flip-flop */
314 outb(0x3C0, 0x00);
315
316 /* Unlock ATI specials */
317 outw(ATIExtReg, ((inATI(0xb8) & 0xC0) << 8) | 0xb8);
318
319 /* Load Miscellaneous Output External Register */
320 outb(0x3C2, restore->std.MiscOutReg);
321
322 outw(ATIExtReg, 0x00b2); /* segment select 0 */
323
324 /* For text modes, download Character Generator into Plane 2 */
325 if (restore->std.FontInfo1 || restore->std.FontInfo2 ||
326 restore->std.TextInfo) {
327 /*
328 * here we switch temporary to 16 color-plane-mode, to simply
329 * copy the font-info and saved text
330 *
331 * BUGALLERT:
332 * The vga's segment-select register MUST be set appropriate !
333 */
334
335 inb(vgaIOBase + 0x0A); /* reset flip-flop */
336 outb(0x3C0,0x10); outb(0x3C0, 0x01); /* graphics mode */
337
338 #if 0
339 outw(0x3c3, 0x0001);
340 #endif
341
342 if (restore->std.FontInfo1) {
343 outw(0x3C4, 0x0402); /* write to plane 2 */
344 outw(0x3C4, 0x0604); /* enable plane graphics */
345 outw(0x3CE, 0x0204); /* read plane 2 */
346 outw(0x3CE, 0x0005); /* write mode 0, read mode 0 */
347 outw(0x3CE, 0x0506); /* set graphics */
348
349 bcopy(restore->std.FontInfo1, vgaBase, 8192);
350 }
351
352 if (restore->std.FontInfo2) {
353 outw(0x3C4, 0x0802); /* write to plane 3 */
354 outw(0x3C4, 0x0604); /* enable plane grp */
355 outw(0x3CE, 0x0304); /* read plane 3 */
356 outw(0x3CE, 0x0005); /* read/write mode 0 */
357 outw(0x3CE, 0x0506); /* set graphics */
358 bcopy(restore->std.FontInfo2, vgaBase, 8192);
359 }
360
361 if (restore->std.TextInfo) {
362 outw(0x3C4, 0x0202); /* write to plane 1 */
363 outw(0x3C4, 0x0604); /* enable plane grp */
364 outw(0x3CE, 0x0104); /* read plane 1 */
365 outw(0x3CE, 0x0005); /* read/write mode 0 */
366 outw(0x3CE, 0x0506); /* set graphics */
367 bcopy(restore->std.TextInfo, vgaBase, 4096);
368
369 outw(0x3C4, 0x0102); /* write to plane 0 */
370 outw(0x3C4, 0x0604); /* enable plane grp */
371 outw(0x3CE, 0x0004); /* read plane 0 */
372 outw(0x3CE, 0x0005); /* read/write mode 0 */
373 outw(0x3CE, 0x0506); /* set graphics */
374 bcopy(restore->std.TextInfo + 4096, vgaBase, 4096);
375 }
376 }
377
378 /* This sequence is from the "VGA Wonder Programmer's
379 Reference Manual." I assume it is correct :-)
380 faith@cs.unc.edu (7Aug92) */
381
382 /* Place Sequencer into Reset condition using its Reset Register */
383 outw(0x3C4, 0x0100);
384
385 /* Load ATI Extended Registers */
386 outw(ATIExtReg, (restore->ATIReg0 << 8) | 0xb0);
387 outw(ATIExtReg, (restore->ATIReg1 << 8) | 0xb1);
388 outw(ATIExtReg, (restore->ATIReg2 << 8) | 0xb2);
389 outw(ATIExtReg, (restore->ATIReg5 << 8) | 0xb5);
390 outw(ATIExtReg, (restore->ATIReg6 << 8) | 0xb6);
391 outw(ATIExtReg, (restore->ATIRegE << 8) | 0xbe);
392 outw(ATIExtReg, (restore->ATIReg3 << 8) | 0xb3);
393 outw(ATIExtReg, (restore->ATIReg8 << 8) | 0xb8);
394 if (ATIBoard >= ATI_BOARD_PLUS) {
395 outw(ATIExtReg, (restore->ATIReg9 << 8) | 0xb9);
396 outw(ATIExtReg, (restore->ATIRegA6 << 8) | 0xa6);
397 outw(ATIExtReg, (restore->ATIRegA7 << 8) | 0xa7);
398 }
399
400 /* Load Miscellaneous Output External Register */
401 outb(0x3C2, restore->std.MiscOutReg);
402
403 /* Load Sequence Registers 1 through 4 */
404 for (i=1; i<5; i++) outw(0x3C4, (restore->std.Sequencer[i] << 8) | i);
405
406 /* Restart Sequencer using Reset Register */
407 outw(0x3C4, 0x0300);
408
409 /* Load all 25 CRT Control Registers */
410 /* But first, unlock CRTC registers 0 to 7 */
411 outw(vgaIOBase + 4, ((restore->std.CRTC[0x11] & 0x7F) << 8) | 0x11);
412 for (i=0; i<25; i++)
413 outw(vgaIOBase + 4,(restore->std.CRTC[i] << 8) | i);
414
415 /* Reset Attribute Controller address/data flip-flop */
416 (void) inb(vgaIOBase + 0x0A);
417
418 /* Load all 20 Attribute Controller Registers */
419 for (i=0; i<21; i++) {
420 (void) inb(vgaIOBase + 0x0A);
421 outb(0x3C0,i);
422 outb(0x3C0, restore->std.Attribute[i]);
423 }
424
425 /* Load all 9 Graphics Controller Registers */
426 for (i=0; i<9; i++) outw(0x3CE, (restore->std.Graphics[i] << 8) | i);
427
428 /* Load all 768 DAC Registers */
429 outb(0x3C8,0x00);
430 for (i=0; i<768; i++) outb(0x3C9, restore->std.DAC[i]);
431
432 /* Reset Attribute Controller address/data flip-flop */
433 (void) inb(vgaIOBase + 0x0A);
434
435 /* Turn Attribute Controller on */
436 outb(0x3C0, 0x20);
437 }
438
439 /*
440 * ATISave --
441 * save the current video mode
442 *
443 * Results:
444 * pointer to the current mode record.
445 *
446 * Side Effects:
447 * None.
448 */
449
450 static void *
ATISave(save)451 ATISave(save)
452 vgaATIPtr save;
453 {
454 unsigned char b2_save,b8_save;
455 int i;
456
457 TRACE(("ATISave(save=0x%x)\n", save));
458
459 vgaIOBase = (inb(0x3cc) & 0x01) ? 0x3D0 : 0x3B0;
460
461 /* Disable video */
462 inb(vgaIOBase + 0x0A); /* reset flip-flop */
463 outb( 0x3c0, 0x00 );
464
465 /* Unlock ATI specials */
466 outw(ATIExtReg, (((b8_save = inATI(0xb8)) & 0xC0) << 8) | 0xb8);
467
468 if (save == NULL) {
469 save = (vgaATIPtr)Xcalloc(sizeof(vgaATIRec));
470 TRACE(("ATISave: save = 0x%x\n",save));
471 }
472
473 /*
474 * now get the fuck'in register
475 */
476 save->std.MiscOutReg = inb(0x3CC);
477
478
479 b2_save = inATI(0xb2);
480 outw(ATIExtReg, 0x00b2); /* segment select 0 */
481
482 save->ATIReg0 = inATI(0xb0);
483 save->ATIReg1 = inATI(0xb1);
484 save->ATIReg2 = b2_save;
485 save->ATIReg3 = inATI(0xb3);
486 save->ATIReg5 = inATI(0xb5);
487 save->ATIReg6 = inATI(0xb6);
488 save->ATIReg8 = b8_save;
489 save->ATIRegE = inATI(0xbe);
490 if (ATIBoard >= ATI_BOARD_PLUS) {
491 save->ATIReg9 = inATI(0xb9);
492 save->ATIRegA6 = inATI(0xa6);
493 save->ATIRegA7 = inATI(0xa7);
494 }
495
496 for (i=0; i<25; i++) {
497 outb(vgaIOBase + 4,i);
498 save->std.CRTC[i] = inb(vgaIOBase + 5);
499 }
500
501 for (i=0; i<21; i++) {
502 inb(vgaIOBase + 0x0A); /* reset flip-flop */
503 outb(0x3C0,i);
504 save->std.Attribute[i] = inb(0x3C1);
505 }
506
507 for (i=0; i<9; i++) {
508 outb(0x3CE,i); save->std.Graphics[i] = inb(0x3CF);
509 }
510
511 for (i=0; i<5; i++) {
512 outb(0x3C4,i); save->std.Sequencer[i] = inb(0x3C5);
513 }
514
515 /*
516 * save the colorlookuptable
517 */
518 outb(0x3C6,0xFF);
519 outb(0x3C7,0x00);
520 for (i=0; i<768; i++) save->std.DAC[i] = inb(0x3C9);
521
522 /*
523 * get the character set of the first non-graphics application
524 */
525 if (((save->std.Attribute[0x10] & 0x01) == 0) &&
526 (save->std.FontInfo1 == NULL)) {
527 /*
528 * Here we switch temporary to 16 color-plane-mode, to simply
529 * copy the font-info
530 *
531 * BUGALLERT: The vga's segment-select register
532 * MUST be set appropriate !
533 */
534 save->std.FontInfo1 = (pointer)xalloc(8192);
535 inb(vgaIOBase + 0x0A); /* reset flip-flop */
536 outb(0x3C0,0x10); outb(0x3C0, 0x01); /* graphics mode */
537 outw(0x3C4, 0x0402); /* write to plane 2 */
538 outw(0x3C4, 0x0604); /* enable plane graphics */
539 outw(0x3CE, 0x0204); /* read plane 2 */
540 outw(0x3CE, 0x0005); /* write mode 0, read mode 0 */
541 outw(0x3CE, 0x0506); /* set graphics */
542
543 bcopy(vgaBase, save->std.FontInfo1, 8192);
544
545 #ifndef HAS_USL_VTS
546 if (save->std.FontInfo2 == NULL) {
547 save->std.FontInfo2 = (pointer)xalloc(8192);
548 /* plane 3 */
549 outw(0x3C4, 0x0802);
550 outw(0x3C4, 0x0604);
551 outw(0x3CE, 0x0304);
552 outw(0x3CE, 0x0005);
553 outw(0x3CE, 0x0506);
554 bcopy(vgaBase, save->std.FontInfo2, 8192);
555 }
556
557 if (save->std.TextInfo == NULL) {
558 save->std.TextInfo = (pointer)xalloc(8192);
559 /* plane 1 */
560 outw(0x3C4, 0x0202);
561 outw(0x3C4, 0x0604);
562 outw(0x3CE, 0x0104);
563 outw(0x3CE, 0x0005);
564 outw(0x3CE, 0x0506);
565 bcopy(vgaBase, save->std.TextInfo, 4096);
566
567 /* plane 0 */
568 outw(0x3C4, 0x0102);
569 outw(0x3C4, 0x0604);
570 outw(0x3CE, 0x0004);
571 outw(0x3CE, 0x0005);
572 outw(0x3CE, 0x0506);
573 bcopy(vgaBase, save->std.TextInfo + 4096, 4096);
574 }
575 #endif /* HAS_USL_VTS */
576 }
577
578 /* Enable video */
579 inb(vgaIOBase + 0x0A); /* reset flip-flop */
580 outb( 0x3c0, 0x20 );
581
582 return ((void *) save);
583 }
584
585 /*
586 * ATIInit --
587 * Handle the initialization, etc. of a screen.
588 *
589 * Results:
590 * None.
591 *
592 * Side Effects:
593 *
594 */
595
596 #define TABLE_END 255 /* denotes end of extended register table */
597
598 /*
599 * Various bit values for mapping the clock values in Xconfig to bit masks for
600 * the various registers.
601 * WARNING: The bits are carefully chosen. They must not collide.
602 *
603 * See the discussion at the beginning of this file.
604 */
605
606 #define CLOCK_0 (0 << 2) /* values for Reg 3C2, bits 2,3 */
607 #define CLOCK_1 (1 << 2)
608 #define CLOCK_2 (2 << 2)
609 #define CLOCK_3 (3 << 2)
610 #define CLOCK_MASK 0x0c
611
612 #define DIVIDE_BY_2 0x40 /* divide freq. by 2 */
613 #define DIVIDE_MASK 0xc0 /* for all of Reg 1CE, Index B8h, bits 6,7 */
614
615 #define V3V4_BIT64 0x10 /* V3 Reg 1CE, Index B2h, Bit 6; and
616 V4 Reg 1CE, Index BEh, Bit 4 */
617
618 #define V5_BE_BIT4 0x10 /* V5,Plus,XL Reg 1CE, Index BEh, bit 4 */
619 #define V5_B9_BIT1 0x02 /* V5,Plus,XL Reg 1CE, Index B9h, bit 1 */
620
621 static Bool
ATIInit(mode)622 ATIInit(mode)
623 DisplayModePtr mode;
624 {
625 /*
626 * We use a table lookup method for setting the extended registers.
627 * These values are taken from the Programmer's Ref. Manual and are
628 * based on Mode 62h. Support for higher resolutions on earlier boards
629 * is not complete (but I have documented what's missing).
630 */
631 static unsigned char extregV3AndOrMasks[][3] = {
632 { ER_B0, 0xc1, 0x30 }, /* 30 is 38 for mode 63h */
633 { ER_B1, 0x87, 0x00 },
634 { ER_B2, 0xbe, 0x00 }, /* 00 is 40 for mode 63h */
635 { ER_B5, 0x7f, 0x00 },
636 { ER_B6, 0xe7, 0x00 },
637 { ER_B8, 0x3f, 0x00 },
638 { TABLE_END }
639 };
640 static unsigned char extregV4AndOrMasks[][3] = {
641 { ER_B0, 0xc1, 0x30 }, /* FIXME: 30 is 38 for mode 63h */
642 { ER_B1, 0x87, 0x00 },
643 { ER_B3, 0xaf, 0x00 },
644 { ER_B5, 0x7f, 0x00 },
645 { ER_B6, 0xe7, 0x00 },
646 { ER_B8, 0x3f, 0x00 },
647 { ER_BE, 0xe5, 0x08 },
648 { TABLE_END }
649 };
650 static unsigned char extregV5AndOrMasks[][3] = {
651 { ER_B0, 0xc1, 0x30 }, /* FIXME: 30 is 38 for mode 63h */
652 { ER_B1, 0x87, 0x00 },
653 { ER_B3, 0xaf, 0x00 },
654 { ER_B5, 0x7f, 0x00 },
655 { ER_B6, 0xe7, 0x00 },
656 { ER_B8, 0x3f, 0x00 },
657 { ER_B9, 0xfd, 0x00 },
658 { ER_BE, 0xe5, 0x08 },
659 { TABLE_END }
660 };
661 /*
662 * Plus and XL Extended Registers ...
663 *
664 * The Programmer's Reference Manual has lots of contradictions. Sigh.
665 * ER_B0: Page 16-5 says AND mask is 0xd8. Page 16-33 has 0xd1.
666 * ER_B8: Page 16-5 has an AND mask of 0x7f which is wrong.
667 * ER_B9: Page 16-5 has an AND mask of 0xff which is wrong.
668 * ER_BE: Page 16-5 has an AND mask of 0xf5 which is wrong.
669 */
670 static unsigned char extregPlusXLAndOrMasks[][3] = {
671 /* Changed ER_B0 entry from 0x28 to 0x31, Wed Feb 3 09:22:13 1993,
672 based on patch by ruhtra@turing.toronto.edu (Arthur Tateishi). */
673 { ER_B0, 0xd9, 0x31 }, /* Experiment: 28 was 20 */
674 { ER_B1, 0x87, 0x00 },
675 { ER_B3, 0xaf, 0x00 },
676 { ER_B5, 0x7f, 0x00 },
677 { ER_B6, 0xe2, 0x04 },
678 { ER_B8, 0x3f, 0x00 },
679 { ER_B9, 0xfd, 0x00 },
680 { ER_BE, 0xe5, 0x08 },
681 { ER_A6, 0xfe, 0x01 }, /* Experiment */
682 { ER_A7, 0xf4, 0x08 },
683 { TABLE_END }
684 };
685 static unsigned char extregIndices[11] = {
686 /* These values must coincide with the ER_x values. */
687 0xb0, 0xb1, 0xb2, 0xb3, 0xb5, 0xb6, 0xb8, 0xb9, 0xbe,
688 0xa6, 0xa7
689 };
690 static unsigned char clockV3V4Table[] = {
691 /* clock values: 18 22 25 28 36 44 50 56 */
692 V3V4_BIT64 | CLOCK_3 | DIVIDE_BY_2, /*18*/
693 0 | CLOCK_3 | DIVIDE_BY_2, /*22*/
694 0 | CLOCK_0 | DIVIDE_BY_2, /*25*/
695 0 | CLOCK_1 | DIVIDE_BY_2, /*28*/
696 V3V4_BIT64 | CLOCK_3, /*36*/
697 0 | CLOCK_3, /*44*/
698 0 | CLOCK_0, /*50*/
699 0 | CLOCK_1 /*56*/
700 };
701 static unsigned char clockV5PlusXLTable[] = {
702 /* clock values: 18 22 25 28 36 44 50 56
703 30 32 37 39 40 56 75 65 */
704 V5_BE_BIT4 | 0 | CLOCK_3 | DIVIDE_BY_2, /*18*/
705 V5_BE_BIT4 | V5_B9_BIT1 | CLOCK_3 | DIVIDE_BY_2, /*22*/
706 V5_BE_BIT4 | V5_B9_BIT1 | CLOCK_0 | DIVIDE_BY_2, /*25*/
707 V5_BE_BIT4 | V5_B9_BIT1 | CLOCK_1 | DIVIDE_BY_2, /*28*/
708 V5_BE_BIT4 | 0 | CLOCK_3, /*36*/
709 V5_BE_BIT4 | V5_B9_BIT1 | CLOCK_3, /*44*/
710 V5_BE_BIT4 | V5_B9_BIT1 | CLOCK_0, /*50*/
711 V5_BE_BIT4 | V5_B9_BIT1 | CLOCK_1, /*56*/
712 0 | 0 | CLOCK_0, /*30*/
713 0 | 0 | CLOCK_1, /*32*/
714 0 | 0 | CLOCK_2, /*37*/
715 0 | 0 | CLOCK_3, /*39*/
716 0 | V5_B9_BIT1 | CLOCK_0, /*40*/
717 0 | V5_B9_BIT1 | CLOCK_1, /*56*/
718 0 | V5_B9_BIT1 | CLOCK_2, /*75*/
719 0 | V5_B9_BIT1 | CLOCK_3 /*65*/
720 };
721 int i,fd;
722 unsigned char byte_42,byte_43,byte_44;
723 unsigned char (*extregTabPtr)[3];
724 unsigned char *clockTabPtr;
725 vgaATIPtr new; /* was: #define new ((vgaATIPtr)vgaNewVideoState)
726 - made a variable to ease debugging */
727
728 TRACE(("ATIInit(mode=0x%x)\n", mode));
729
730 /*
731 * Set the default values ...
732 */
733
734 if (!vgaHWInit(mode, sizeof(vgaATIRec)))
735 return(FALSE);
736
737 new = (vgaATIPtr) vgaNewVideoState; /* must do after vgaHWInit() */
738
739 /*
740 * On with ATI specific stuff ...
741 */
742
743 switch (ATIBoard) {
744 case ATI_BOARD_V3 :
745 extregTabPtr = extregV3AndOrMasks;
746 clockTabPtr = clockV3V4Table;
747 break;
748 case ATI_BOARD_V4 :
749 extregTabPtr = extregV4AndOrMasks;
750 clockTabPtr = clockV3V4Table;
751 break;
752 case ATI_BOARD_V5 :
753 extregTabPtr = extregV5AndOrMasks;
754 clockTabPtr = clockV5PlusXLTable;
755 break;
756 case ATI_BOARD_PLUS :
757 case ATI_BOARD_XL :
758 default :
759 extregTabPtr = extregPlusXLAndOrMasks;
760 clockTabPtr = clockV5PlusXLTable;
761 break;
762 }
763
764 /*
765 * The VGA Wonder/XL has a bit that says "multiply vertical values by
766 * 2". This applies to CRTC[8,10h,12h,15h,18h]. At least that's what
767 * the manual says. I suspect it applies elsewhere, and that even a few
768 * of these values may be wrong. Unfortunately, their 1024x768 examples
769 * don't set this bit, so what is going on?
770 *
771 * We use this feature when the vertical display size is > 480. This
772 * means that odd values in the vertical timing field in Xconfig are
773 * truncated (modulo 2).
774 *
775 * I've duplicated all of vgaHWInit()'s setting of CRTC for
776 * completeness. Down the road we may have to add more stuff, so I've
777 * brought it all in here just in case.
778 */
779
780 if (mode->VDisplay > 480) {
781 int shift = 1 + ((ATIBoard > ATI_BOARD_V3) &&
782 (mode->Flags & V_INTERLACE));
783
784 mode->VDisplay >>= shift;
785 mode->VSyncStart >>= shift;
786 mode->VSyncEnd >>= shift;
787 mode->VTotal >>= shift;
788
789 new->std.CRTC[0] = (mode->HTotal >> 3) - 5;
790 new->std.CRTC[1] = (mode->HDisplay >> 3) - 1;
791 new->std.CRTC[2] = (mode->HSyncStart >> 3) - 1;
792 new->std.CRTC[3] = ((mode->HSyncEnd >> 3) & 0x1f) | 0x80;
793 new->std.CRTC[4] = (mode->HSyncStart >> 3);
794 new->std.CRTC[5] = (((mode->HSyncEnd >> 3) & 0x20) << 2)
795 | (((mode->HSyncEnd >> 3)) & 0x1f);
796 new->std.CRTC[6] = (mode->VTotal - 2) & 0xff;
797 new->std.CRTC[7] = (((mode->VTotal - 2) & 0x100) >> 8)
798 | (((mode->VDisplay - 1) & 0x100) >> 7)
799 | ((mode->VSyncStart & 0x100) >> 6)
800 | (((mode->VSyncStart) & 0x100) >> 5)
801 | 0x10
802 | (((mode->VTotal - 2) & 0x200) >> 4)
803 | (((mode->VDisplay - 1) & 0x200) >> 3)
804 | ((mode->VSyncStart & 0x200) >> 2);
805 new->std.CRTC[8] = 0x00;
806 new->std.CRTC[9] = ((mode->VSyncStart & 0x200) >> 4 ) | 0x40;
807 new->std.CRTC[10] = 0x00;
808 new->std.CRTC[11] = 0x00;
809 new->std.CRTC[12] = 0x00;
810 new->std.CRTC[13] = 0x00;
811 new->std.CRTC[14] = 0x00;
812 new->std.CRTC[15] = 0x00;
813 new->std.CRTC[16] = mode->VSyncStart & 0xff;
814 new->std.CRTC[17] = (mode->VSyncEnd & 0x0f) | 0x20;
815 new->std.CRTC[18] = (mode->VDisplay -1) & 0xff;
816 new->std.CRTC[19] = vga256InfoRec.virtualX >> 4;
817 new->std.CRTC[20] = 0x00;
818 new->std.CRTC[21] = mode->VSyncStart & 0xff;
819 new->std.CRTC[22] = (mode->VSyncStart + 1) & 0xff;
820 new->std.CRTC[23] = 0xe7; /* bit 0x04 sets "*2 vert. values" */
821 new->std.CRTC[24] = 0xff;
822
823 mode->VDisplay <<= shift;
824 mode->VSyncStart <<= shift;
825 mode->VSyncEnd <<= shift;
826 mode->VTotal <<= shift;
827 } else {
828 new->std.CRTC[23] = 0xe3; /* ATI uses an even/odd bank
829 256 color mode */
830 }
831
832 new->std.Sequencer[4] = 0x0a;
833 new->std.Graphics[5] = 0x00;
834 new->std.Attribute[16] = 0x01;
835
836 /*
837 * Experiment. It looks like MiscOutReg is a little different for
838 * the high resolution modes. I've duplicated the code from
839 * vgaHWInit() because it looks like they have different handling
840 * if the syncs are explicitly mentioned, and I want to preserve
841 * this.
842
843 if ((mode->Flags & (V_PHSYNC | V_NHSYNC))
844 && (mode->Flags & (V_PVSYNC | V_NVSYNC)))
845 {
846 new->MiscOutReg = 0x23;
847 if (mode->Flags & V_NHSYNC) new->MiscOutReg |= 0x40;
848 if (mode->Flags & V_NVSYNC) new->MiscOutReg |= 0x80;
849 } else {
850 if (mode->VDisplay < 400) new->MiscOutReg = 0xA3;
851 else if (mode->VDisplay < 480) new->MiscOutReg = 0x63;
852 else if (mode->VDisplay < 768) new->MiscOutReg = 0xE3;
853 else new->MiscOutReg = 0xE3;
854 }
855
856 /*
857 * Get the extended register values ...
858 */
859
860 bzero(new->ATIExtRegBank, sizeof(new->ATIExtRegBank));
861 for (i = 0; extregTabPtr[i][0] != TABLE_END; i++) {
862 new->ATIExtRegBank[extregTabPtr[i][0]] =
863 (inATI(extregIndices[extregTabPtr[i][0]]) &
864 extregTabPtr[i][1]) |
865 extregTabPtr[i][2];
866 }
867
868 if ((ATIBoard > ATI_BOARD_V3) && (mode->Flags & V_INTERLACE))
869 new->ATIRegE |= 0x02; /* FIXME: doesn't work */
870
871 /*
872 * Handle the oddballs ...
873 *
874 * It appears that bit 0 of extended register 0xb6 enables the upper
875 * 512KB. ATI's MSWindows driver sets this bit to 1, and it appears
876 * to work here as well (previously I was getting duplicate images:
877 * the lower 512KB being used twice).
878 */
879
880 switch (ATIBoard) {
881 case ATI_BOARD_V3 :
882 case ATI_BOARD_V4 :
883 case ATI_BOARD_V5 :
884 break;
885 case ATI_BOARD_PLUS :
886 case ATI_BOARD_XL :
887 default :
888 if (ATIChipVersion < '5' || ATIChipVersion >= 'a') {
889 /* Changed ER_BE entry from 0x08 to 0x18,
890 Wed Feb 3 12:11:27 1993, based on patch by
891 aal@broue.rot.qc.ca (Alain Hebert). */
892 new->ATIExtRegBank[ER_BE] |= 0x10;
893 }
894
895 if (vga256InfoRec.videoRam == 1024)
896 new->ATIReg6 |= 0x01;
897 break;
898 }
899
900 /*
901 * Get the clock value ...
902 * See the discussion at the beginning of this file.
903 */
904
905 new->std.MiscOutReg &= ~CLOCK_MASK;
906 new->std.MiscOutReg |= clockTabPtr[mode->Clock] & CLOCK_MASK;
907
908 if (ATIBoard == ATI_BOARD_V3) {
909 if (clockTabPtr[mode->Clock] & V3V4_BIT64)
910 new->ATIReg2 |= 0x40;
911 } else if (ATIBoard == ATI_BOARD_V4) {
912 if (clockTabPtr[mode->Clock] & V3V4_BIT64)
913 new->ATIRegE |= 0x10;
914 } else {
915 if (clockTabPtr[mode->Clock] & V5_BE_BIT4)
916 new->ATIRegE |= 0x10;
917 if (clockTabPtr[mode->Clock] & V5_B9_BIT1)
918 new->ATIReg9 |= 0x02;
919 }
920
921 new->ATIReg8 |= clockTabPtr[mode->Clock] & DIVIDE_MASK;
922 return(TRUE);
923 }
924
925 /*
926 * ATIAdjust --
927 * adjust the current video frame to display the mousecursor
928 *
929 * Results:
930 * nope.
931 *
932 * Side Effects:
933 * the display scrolls
934 */
935
936 static void
ATIAdjust(x,y)937 ATIAdjust(x, y)
938 int x, y;
939 {
940 int Base;
941
942 /**
943 ** TODO: Adjust the shift-count here !!!
944 ** Ferraro writes, that there may be no shift at all. But this
945 ** would kill our panning feature.
946 **/
947
948 Base = (y * vga256InfoRec.virtualX + x + 3) >> 3;
949
950 outw(vgaIOBase + 4, (Base & 0x00FF00) | 0x0C);
951 outw(vgaIOBase + 4, ((Base & 0x00FF) << 8) | 0x0D);
952 }
953
954 static int
inATI(index)955 inATI(index)
956 {
957 outb(ATIExtReg, index);
958 return inb(ATIExtReg + 1);
959 }
960
961 /*
962 * ATIProbe() checks for an ATI card.
963 *
964 * Returns TRUE or FALSE on exit.
965 *
966 * Makes sure the following are set in vga256InofRec:
967 * chipset
968 * videoRam
969 * clocks
970 *
971 * Also sets:
972 * ATIBoard
973 * ATIExtREG
974 *
975 * References:
976 * "VGA WONDER Programmer's Reference,"
977 * ATI Technologies, 1991.
978 * Release 1.2 -- Reference #PRG28800
979 * (Part No. 10709B0412)
980 * Chapter 7: Identification and Configuration
981 *
982 * George Sutty and Steve Blair's "Advanced Programmer's
983 * Guide to SuperVGAs," Brady/Simon & Schuster, 1990.
984 * Chapter 11: ATI 18800 ATI VGAWONDER
985 *
986 * Some random document from the ATI BBS dated 3Jun91,
987 * which may have been called PROGINGO.DOC.
988 *
989 * Written by:
990 * Rik Faith (faith@cs.unc.edu), Sun Aug 9 09:27:40 1992
991 *
992 */
993
994 #define SIGNATURE_LENGTH 9
995 #define BIOS_DATA_SIZE 0x50
996 static Bool
ATIProbe()997 ATIProbe()
998 {
999 char *signature = "761295520";
1000 /* const char signature[] = "761295520"; */
1001 const char signature_length = SIGNATURE_LENGTH;
1002 const int bios_data_size = BIOS_DATA_SIZE;
1003 char bios_signature[SIGNATURE_LENGTH];
1004 char bios_data[BIOS_DATA_SIZE];
1005 unsigned ports[2];
1006 int fd;
1007
1008 TRACE(("ATIProbe()\n"));
1009
1010 /*
1011 * Set up I/O ports to be used by this card
1012 */
1013 xf86ClearIOPortList(vga256InfoRec.scrnIndex);
1014 xf86AddIOPorts(vga256InfoRec.scrnIndex, Num_VGA_IOPorts, VGA_IOPorts);
1015
1016 if (vga256InfoRec.chipset) {
1017 if (StrCaseCmp(vga256InfoRec.chipset, ATIIdent(0)))
1018 return FALSE;
1019 } else {
1020 if (xf86ReadBIOS(vga256InfoRec.BIOSbase, 0x31,
1021 (unsigned char *)bios_signature,
1022 signature_length) != signature_length)
1023 return FALSE;
1024 if (strncmp( signature, bios_signature, signature_length )) {
1025 TRACE(("ATIProbe: Incorrect Signature\n"));
1026 return FALSE;
1027 }
1028 }
1029
1030 /* Assume an ATI card. */
1031 vga256InfoRec.chipset = ATIIdent(0);
1032
1033 /* Now look in the BIOS for magic numbers. */
1034 if (xf86ReadBIOS(vga256InfoRec.BIOSbase, 0x00, (unsigned char *)bios_data,
1035 bios_data_size) != bios_data_size)
1036 return FALSE;
1037
1038 ErrorF( "ATI BIOS Information Block:\n" );
1039 ErrorF( " Signature code: %c%c = ",
1040 bios_data[ 0x40 ], bios_data[ 0x41 ] );
1041 if (bios_data[ 0x40 ] != '3') ErrorF( "Unknown\n" );
1042 else switch( bios_data[ 0x41 ] ) {
1043 case '1':
1044 ErrorF( "VGA WONDER\n" );
1045 break;
1046 case '2':
1047 ErrorF( "EGA WONDER800+\n" );
1048 break;
1049 case '3':
1050 ErrorF( "VGA BASIC-16\n" );
1051 break;
1052 default:
1053 ErrorF( "Unknown\n" );
1054 break;
1055 }
1056 ErrorF( " Chip version: %c = ",
1057 bios_data[ 0x43 ] );
1058 switch (bios_data[ 0x43 ] ) {
1059 case '1':
1060 ErrorF( "ATI 18800\n" );
1061 break;
1062 case '2':
1063 ErrorF( "ATI 18800-1\n" );
1064 break;
1065 case '3':
1066 ErrorF( "ATI 28800-2\n" );
1067 break;
1068 case '4': case '5':
1069 ErrorF( "ATI 28800-%c\n", bios_data[ 0x43 ] );
1070 break;
1071 case 'a':
1072 ErrorF( "Mach-32\n" );
1073 break;
1074 default:
1075 ErrorF( "Unknown\n" );
1076 break;
1077 }
1078 ErrorF( " BIOS version: %d.%d\n",
1079 bios_data[ 0x4c ], bios_data[ 0x4d ] );
1080
1081
1082 #if DEBUG_PROBE
1083 ErrorF( "\n" );
1084 #endif
1085
1086 ErrorF( " Byte at offset 0x42 = 0x%02x\n",
1087 bios_data[ 0x42 ] );
1088
1089 #if DEBUG_PROBE
1090 ErrorF( " 8 and 16 bit ROM supported: %s\n",
1091 bios_data[ 0x42 ] & 0x01 ? "Yes" : "No" );
1092 ErrorF( " Mouse chip present: %s\n",
1093 bios_data[ 0x42 ] & 0x02 ? "Yes" : "No" );
1094 ErrorF( " Inport compatible mouse port : %s\n",
1095 bios_data[ 0x42 ] & 0x04 ? "Yes" : "No" );
1096 ErrorF( " Micro Channel supported: %s\n",
1097 bios_data[ 0x42 ] & 0x08 ? "Yes" : "No" );
1098 ErrorF( " Clock chip present: %s\n",
1099 bios_data[ 0x42 ] & 0x10 ? "Yes" : "No" );
1100 ErrorF( " Uses c000:0 to d000:ffff: %s\n",
1101 bios_data[ 0x42 ] & 0x80 ? "Yes" : "No" );
1102 ErrorF( "\n" );
1103 #endif
1104
1105 ErrorF( " Byte at offset 0x44 = 0x%02x\n",
1106 bios_data[ 0x44 ] );
1107
1108 #if DEBUG_PROBE
1109 ErrorF( " Supports 70Hz non-interlaced: %s\n",
1110 bios_data[ 0x44 ] & 0x01 ? "No" : "Yes" );
1111 ErrorF( " Supports Korean characters: %s\n",
1112 bios_data[ 0x44 ] & 0x02 ? "Yes" : "No" );
1113 ErrorF( " Uses 45Mhz memory clock: %s\n",
1114 bios_data[ 0x44 ] & 0x04 ? "Yes" : "No" );
1115 ErrorF( " Supports zero wait states: %s\n",
1116 bios_data[ 0x44 ] & 0x08 ? "Yes" : "No" );
1117 ErrorF( " Uses paged ROMS: %s\n",
1118 bios_data[ 0x44 ] & 0x10 ? "Yes" : "No" );
1119 ErrorF( " 8514/A hardware on board: %s\n",
1120 bios_data[ 0x44 ] & 0x40 ? "No" : "Yes" );
1121 ErrorF( " 32K color DAC on board: %s\n",
1122 bios_data[ 0x44 ] & 0x80 ? "Yes" : "No" );
1123 #endif
1124
1125 ATIExtReg = *((short int *)bios_data + 0x08);
1126 ports[0] = ATIExtReg;
1127 ports[1] = ATIExtReg+1;
1128 xf86AddIOPorts(vga256InfoRec.scrnIndex, 2, ports);
1129
1130 ATIChipVersion = bios_data[ 0x43 ];
1131
1132 switch( bios_data[ 0x43 ] ) {
1133 case '1':
1134 ATIBoard = ATI_BOARD_V3;
1135 break;
1136 case '2':
1137 if (bios_data[ 0x42 ] & 0x10) ATIBoard = ATI_BOARD_V5;
1138 else ATIBoard = ATI_BOARD_V4;
1139 break;
1140 case '3':
1141 case '4':
1142 ATIBoard = ATI_BOARD_PLUS;
1143 break;
1144 case '5':
1145 case 'a': /* Graphics Ultra Plus */
1146 default:
1147 if (bios_data[ 0x44 ] & 0x80) ATIBoard = ATI_BOARD_XL;
1148 else ATIBoard = ATI_BOARD_PLUS;
1149 }
1150
1151 ErrorF( "\n This video adapter is a: " );
1152 switch (ATIBoard) {
1153 case ATI_BOARD_V3: ErrorF( "VGA WONDER V3\n" ); break;
1154 case ATI_BOARD_V4: ErrorF( "VGA WONDER V4\n" ); break;
1155 case ATI_BOARD_V5: ErrorF( "VGA WONDER V5\n" ); break;
1156 case ATI_BOARD_PLUS: ErrorF( "VGA WONDER PLUS (V6)\n" ); break;
1157 case ATI_BOARD_XL: ErrorF( "VGA WONDER XL (V7)\n" ); break;
1158 default: ErrorF( "Unknown\n" ); break;
1159 }
1160
1161 ATIEnterLeave( ENTER );
1162
1163 if (!vga256InfoRec.videoRam) {
1164 if (bios_data[ 0x43 ] <= '2') {
1165 outb( ATIExtReg, 0xbb );
1166 vga256InfoRec.videoRam = (inb( ATIExtReg + 1 ) & 0x20) ? 512 : 256;
1167 } else {
1168 outb( ATIExtReg, 0xb0 );
1169 switch (inb( ATIExtReg + 1 ) & 0x18) {
1170 case 0x00:
1171 vga256InfoRec.videoRam = 256;
1172 break;
1173 case 0x10:
1174 vga256InfoRec.videoRam = 512;
1175 break;
1176 case 0x08:
1177 vga256InfoRec.videoRam = 1024;
1178 break;
1179 }
1180 }
1181 }
1182
1183 ErrorF( " Amount of RAM on video adapter: %dk\n",
1184 vga256InfoRec.videoRam );
1185 if (bios_data[ 0x43 ] < '4') {
1186 ErrorF( " WARNING: Driver may not work correctly with your board!\n" );
1187 }
1188 ErrorF( "\n" );
1189
1190 #if DEBUG_PROBE
1191 ErrorF( "\nThe extended registers (ATIExtREG) are at 0x%x\n", ATIExtReg );
1192 ErrorF( "The x386 ATI driver will set ATIBoard = %d\n", ATIBoard );
1193 #endif
1194
1195 if (vga256InfoRec.videoRam < 512) {
1196 ErrorF( "ATI driver requires at least 512k video RAM!\n" );
1197 ATIEnterLeave( LEAVE );
1198 return FALSE;
1199 }
1200
1201 if (!vga256InfoRec.clocks) {
1202 ErrorF( "ATI driver requires \"clocks\" to be set in Xconfig!\n" );
1203 ErrorF( "Clocks 18 22 25 28 36 44 50 56\n" );
1204 ErrorF( " 30 32 37 39 40 0 75 65\n" );
1205 ATIEnterLeave( LEAVE );
1206 return FALSE;
1207 }
1208
1209 vga256InfoRec.bankedMono = FALSE;
1210 return TRUE;
1211 }
1212
1213 /*
1214 * ATIEnterLeave()
1215 *
1216 * This routine is used when entering or leaving X (i.e., when starting or
1217 * exiting an X session, or when switching to or from a vt which does not
1218 * have an X session running.
1219 *
1220 * Assumptions:
1221 * ATIProbe() has been called first, so that ATIExtReg is valid.
1222 *
1223 * Written by:
1224 * Rik Faith (faith@cs.unc.edu), Sun Aug 9 13:50:33 1992
1225 *
1226 */
1227
1228 static void
ATIEnterLeave(enter)1229 ATIEnterLeave( enter )
1230 Bool enter;
1231 {
1232 unsigned char temp;
1233
1234 TRACE(("ATIEnterLeave(%d)\n",enter));
1235
1236 if (enter)
1237 {
1238 xf86EnableIOPorts(vga256InfoRec.scrnIndex);
1239 vgaIOBase = (inb(0x3CC) & 0x01) ? 0x3D0 : 0x3B0;
1240 }
1241 else
1242 {
1243 xf86DisableIOPorts(vga256InfoRec.scrnIndex);
1244 }
1245 }
1246
1247