1 /* VGAlib version 1.2 - (c) 1993 Tommy Frandsen */
2 /* */
3 /* This library is free software; you can redistribute it and/or */
4 /* modify it without any restrictions. This library is distributed */
5 /* in the hope that it will be useful, but without any warranty. */
6
7 /* Multi-chipset support Copyright (c) 1993 Harm Hanemaayer */
8 /* partially copyrighted (C) 1993 by Hartmut Schirmer */
9
10 /* ET4000 code taken from VGAlib
11 * ET4000 code modified to handle HiColor modes better by David Monro
12 * Dynamic register loading by Hartmut Schirmer
13 * HH: ET4000/W32 detection added and support for more than 1Mb (based on
14 * vgadoc3) (untested).
15 * HH: Detect newer ET4000/W32p.
16 */
17
18
19 /* Note that the clock detection stuff is currently not used. */
20
21 /* ET4000 registers description (from vgadoc2)
22 **
23 **
24 **
25 ** 102h: Microchannel Setup Control
26 ** bit 0 Disable Card if set
27 **
28 ** 3BFh (R/W): Hercules Compatability register
29 **
30 ** 3C0h index 16h: ATC Miscellaneous
31 ** (Write data to 3C0h, Read from 3C1h (May not be needed))
32 ** bit 4,5 High resolution timings.
33 ** 7 Bypass the internal palette if set
34 **
35 ** 3C3h (R/W): Microchannel Video Subsystem Enable Register:
36 ** bit 0 Enable Microchannel VGA if set
37 **
38 ** 3C4h index 6 (R/W): TS State Control
39 ** bit 1-2 dots per characters in text mode
40 ** (bit 0: 3c4 index 1, bit 0)
41 ** bit <2:0> ! dots/char
42 ** 111 ! 16
43 ** 100 ! 12
44 ** 011 ! 11
45 ** 010 ! 10
46 ** 001 ! 8
47 ** 000 ! 9
48 **
49 ** 3C4h index 7 (R/W): TS Auxiliary Mode
50 ** bit 0 If set select MCLK/4 (if bit 6 is also set to 1)
51 ** 1 If set select SCLK input from MCLK
52 ** 3,5 Rom Bios Enable/Disable:
53 ** 0 0 C000-C3FF Enabled
54 ** 0 1 Rom disabled
55 ** 1 0 C000-C5FF,C680-C7FF Enabled
56 ** 1 1 C000-C7FF Enabled
57 ** 6 MCLK/2 if set
58 ** 7 VGA compatible if set EGA else.
59 **
60 ** 3CBh (R/W): PEL Address/Data Wd
61 **
62 ** 3CDh (R/W): Segment Select
63 ** 0-3 64k Write bank nr (0..15)
64 ** 4-7 64k Read bank nr (0..15)
65 **
66 ** 3CEh index Dh (R/W): Microsequencer Mode
67 **
68 ** 3CEh index Eh (R/W): Microsequencer Reset
69 **
70 ** 3d4h index 24h (R/W): Compatibility Control
71 ** bit 0 Enable Clock Translate
72 ** 1 Additional Master Clock Select
73 ** 2 Enable tri-state for all output pins
74 ** 3 Enable input A8 of 1MB DRAMs
75 ** 4 Reserved
76 ** 5 Enable external ROM CRTC translation
77 ** 6 Enable Double Scan and Underline Attribute
78 ** 7 CGA/MDA/Hercules
79 **
80 ** 3d4h index 32h (R/W): RAS/CAS Video Config
81 ** Ram timing, System clock and Ram type. Sample values:
82 ** 00h VRAM 80nsec
83 ** 09h VRAM 100nsec
84 ** 00h VRAM 28MHz
85 ** 08h VRAM 36MHz
86 ** 70h DRAM 40MHz
87 **
88 ** 3d4h index 33h (R/W): Extended start ET4000
89 ** bit 0-1 Display start address bits 16-17
90 ** 2-3 Cursor start address bits 16-17
91 ** Can be used to ID ET4000
92 **
93 ** 3d4h index 34h (R/W): Compatibility Control Register
94 ** bit 2 bit 3 of clock select (bit 1-0 in misc output)
95 ** 3 if set Video Subsystem Enable Register at 46E8h
96 ** else at 3C3h.
97 **
98 ** 3d4h index 35h (R/W): Overflow High ET4000
99 ** bit 0 Vertical Blank Start Bit 10
100 ** 1 Vertical Total Bit 10
101 ** 2 Vertical Display End Bit 10
102 ** 3 Vertical Sync Start Bit 10
103 ** 4 Line Compare Bit 10
104 ** 5 Gen-Lock Enabled if set (External sync)
105 ** 6 Read/Modify/Write Enabled if set. Currently not implemented.
106 ** 7 Vertical interlace if set
107 **
108 ** 3d4h index 36h (R/W): Video System Configuration 1
109 ** bit 0-2 Refresh count per line - 1
110 ** 3 16 bit wide fonts if set, else 8 bit wide
111 ** 4 Linear addressing if set. Video Memory is
112 ** mapped as a 1 Meg block above 1MB. (set
113 ** GDC index 6 bits 3,2 to zero (128k))
114 ** 5 TLI addressing mode if set
115 ** 6 16 bit data path (video memory) if set
116 ** 7 16 bit data (I/O operations) if set
117 **
118 ** 3d4h index 37h (R/W): Video System Configuration 2
119 ** bit 0-1 Display memory data bus width
120 ** 0,1=8bit, 2=16bit, 3=32bit; may be
121 ** read as number of memory banks (1,2,4)
122 ** 2 Bus read data latch control. If set latches
123 ** databus at end of CAS cycle else one clock delay
124 ** 3 Clear if 64kx4 RAMs ???
125 ** if set RAM size = (bit 0-1)*256k
126 ** else RAM size = (bit 0-1)* 64k
127 ** 4 16 bit ROM access if set
128 ** 5 Memory bandwidth (0 better than 1) ???
129 ** 6 TLI internal test mode if set
130 ** 7 VRAM installed if set DRAM else.
131 **
132 ** 3d4h index 3Fh (R/W):
133 ** bit 7 This bit seems to be bit 8 of the CRTC offset register (3d4h index 13h).
134 **
135 ** 3d8h (R/W): Display Mode Control
136 **
137 ** 46E8h (R): Video Subsystem Enable Register
138 ** bit 3 Enable VGA if set
139 **
140 **
141 ** 3C4h index 05 used.
142 **
143 **
144 ** Bank Switching:
145 **
146 ** 64k banks are selected by the Segment Select Register at 3CDh.
147 ** Both a Read and a Write segment can be selected.
148 **
149 ** The sequence:
150 **
151 ** port[$3BF]:=3;
152 ** port[$3D8]:=$A0;
153 **
154 ** is apparently needed to enable the extensions in the Tseng 4000.
155 **
156 **
157 ** Used extended ET4000 registers (EXT+xx) :
158 **
159 ** 00 : CRT (3d4) index 30
160 ** 01 : CRT (3d4) index 31
161 ** 02 : CRT (3d4) index 32
162 ** 03 : CRT (3d4) index 33
163 ** 04 : CRT (3d4) index 34
164 ** 05 : CRT (3d4) index 35
165 ** 06 : CRT (3d4) index 36
166 ** 07 : CRT (3d4) index 37
167 ** 08 : CRT (3d4) index 3f
168 ** 09 : SEQ (3c4) index 07
169 ** 0A : Microchannel register (3c3)
170 ** 0B : Segment select (3cd)
171 ** 0C : ATT (3c0) index 16
172 **
173 */
174
175 #include <stdlib.h>
176 #include <stdio.h>
177 #include <unistd.h>
178 #include <stdarg.h>
179 #include <string.h>
180 #include "vga.h"
181 #include "libvga.h"
182 #include "driver.h"
183 #include "ramdac/ramdac.h"
184
185 #define SEG_SELECT 0x3CD
186
187 #define CHIP_ET4000 0 /* Chip types. */
188 #define CHIP_ET4000W32 1
189 #define CHIP_ET4000W32i 2
190 #define CHIP_ET4000W32p 3
191
192 static char *chipname[] =
193 {
194 "ET4000",
195 "ET4000/W32",
196 "ET4000/W32i",
197 "ET4000/W32p"
198 };
199
200 static int et4000_memory;
201 static int et4000_chiptype;
202
203 static int et4000_init(int, int, int);
204 static int et4000_interlaced(int mode);
205 static void et4000_unlock(void);
206
207 static void et4000_setlinear(int addr);
208
209 static int et4000_extdac;
210 static int pos_ext_settings, ext_settings;
211
212 /* Mode table */
213 #if defined(DYNAMIC)
214
215 static ModeTable *et4000_modes = NULL;
216 static ModeTable No_Modes = END_OF_MODE_TABLE;
217
218 #else /* !defined(DYNAMIC) */
219
220 #include "et4000.regs"
221
222 #ifdef DAC_TYPE
223 static int et4000_dac = DAC_TYPE;
224 #endif
225
226 static ModeTable et4000_modes[] =
227 {
228 /* *INDENT-OFF* */
229 OneModeEntry(320x200x32K),
230 OneModeEntry(320x200x64K),
231 OneModeEntry(320x200x16M),
232 OneModeEntry(640x480x256),
233 OneModeEntry(640x480x32K),
234 OneModeEntry(640x480x64K),
235 OneModeEntry(640x480x16M),
236 OneModeEntry(800x600x16),
237 OneModeEntry(800x600x256),
238 OneModeEntry(800x600x32K),
239 OneModeEntry(800x600x64K),
240 OneModeEntry(1024x768x16),
241 OneModeEntry(1024x768x256),
242 OneModeEntry(1280x1024x16),
243 END_OF_MODE_TABLE
244 /* *INDENT-ON* */
245 };
246
247 #endif /* !defined(DYNAMIC) */
248
249 #ifndef DAC_TYPE
250 static int et4000_dac = -1;
251 #endif
252
253 /* Fill in chipset specific mode information */
254
et4000_getmodeinfo(int mode,vga_modeinfo * modeinfo)255 static void et4000_getmodeinfo(int mode, vga_modeinfo * modeinfo)
256 {
257 switch (modeinfo->colors) {
258 case 16: /* 4-plane 16 color mode */
259 modeinfo->maxpixels = 65536 * 8;
260 break;
261 default:
262 if (modeinfo->bytesperpixel > 0)
263 modeinfo->maxpixels = et4000_memory * 1024 /
264 modeinfo->bytesperpixel;
265 else
266 modeinfo->maxpixels = et4000_memory * 1024;
267 break;
268 }
269 modeinfo->maxlogicalwidth = 4088;
270 modeinfo->startaddressrange = 0xfffff;
271 if (mode == G320x200x256)
272 modeinfo->startaddressrange = 0;
273 modeinfo->haveblit = 0;
274 modeinfo->memory = et4000_memory * 1024;
275 modeinfo->flags |= HAVE_RWPAGE | HAVE_EXT_SET;
276 if (et4000_interlaced(mode))
277 modeinfo->flags |= IS_INTERLACED;
278 if (et4000_chiptype != CHIP_ET4000)
279 modeinfo->flags |= EXT_INFO_AVAILABLE | CAPABLE_LINEAR;
280 }
281
282
283 /* ----------------------------------------------------------------- */
284 /* Set/get the actual clock frequency */
285
286 #if defined(USE_CLOCKS) || defined(DYNAMIC)
287 #ifndef CLOCKS
288 #define CLOCKS 24
289 #endif
290 #ifndef CLOCK_VALUES
291 #define CLOCK_VALUES { 0 }
292 #endif
293
294 static unsigned clocks[CLOCKS] = CLOCK_VALUES;
295 #endif
296
297
298 #ifdef USE_CLOCKS
299
300 /* Only include the rest of the clock stuff if USE_CLOCKS is defined. */
301
et4000_clocks(int clk)302 static int et4000_clocks(int clk)
303 {
304 unsigned char temp;
305 int res;
306
307 /* get actual clock */
308 res = (inb(MIS_R) >> 2) & 3; /* bit 0..1 */
309 outb(__svgalib_CRT_I, 0x34);
310 res |= (inb(__svgalib_CRT_D) & 2) << 1; /* bit 2 */
311 outb(SEQ_I, 0x07);
312 temp = inb(SEQ_D);
313 if (temp & 0x41 == 0x41)
314 res |= 0x10; /* bit 3..4 */
315 else
316 res |= (temp & 0x40) >> 3; /* bit 3 */
317
318 if (clk >= CLOCKS)
319 clk = CLOCKS - 1;
320 if (clk >= 0) {
321 /* Set clock */
322 temp = inb(MIS_R) & 0xF3;
323 outb(MIS_W, temp | ((clk & 3) << 2));
324 outb(__svgalib_CRT_I, 0x34);
325 temp = inb(__svgalib_CRT_D) & 0xFD;
326 outb(__svgalib_CRT_D, temp | ((clk & 4) >> 1));
327 outb(SEQ_I, 0x07);
328 temp = inb(SEQ_D) & 0xBE;
329 temp |= (clk & 0x10 ? 0x41 : 0x00);
330 temp |= (clk & 0x08) << 3;
331 outb(SEQ_D, temp);
332 usleep(5000);
333 }
334 return res;
335 }
336
337 #define FRAMES 2
338
339 /* I think the Xfree86 uses a similar BAD HACK ... */
measure(int frames)340 static int measure(int frames)
341 {
342 unsigned counter;
343 __asm__ volatile (
344 " xorl %0,%0 \n"
345 "__W1: inb %1,%%al \n"
346 " testb $8,%%al \n"
347 " jne __W1 \n"
348 "__W2: inb %1,%%al \n"
349 " testb $8,%%al \n"
350 " je __W2 \n"
351 "__L1: inb %1,%%al \n"
352 " incl %0 \n"
353 " testb $8,%%al \n"
354 " jne __L1 \n"
355 "__L2: inb %1,%%al \n"
356 " incl %0 \n"
357 " testb $8,%%al \n"
358 " je __L2 \n"
359 "__L3: decl %2 \n"
360 " jns __L1 \n"
361 :"=b" (counter)
362 :"d"((unsigned short) (0x3da)), "c"(frames)
363 :"ax", "cx"
364 );
365 return counter;
366 }
367
368 #define BASIS_FREQUENCY 28322
369
measure_clk(int clk)370 static int measure_clk(int clk)
371 {
372 unsigned new;
373 int old_clk, state;
374 static unsigned act = 0;
375
376 old_clk = et4000_clocks(-1);
377 if ((state = SCREENON))
378 vga_screenoff();
379 if (act == 0) {
380 unsigned char save = inb(MIS_R);
381 outb(MIS_W, (save & 0xF3) | 0x04);
382 act = measure(FRAMES);
383 outb(MIS_W, save);
384 }
385 et4000_clocks(clk);
386 new = measure(FRAMES);
387 et4000_clocks(old_clk);
388 if (state)
389 vga_screenon();
390
391 return (((long long) BASIS_FREQUENCY) * act) / new;
392 }
393
394 #define set1(f,v) ({ if ((f)==0) (f)=(v); })
395
set3(unsigned * f,int clk,unsigned base)396 static void set3(unsigned *f, int clk, unsigned base)
397 {
398 if (clk - 16 >= 0)
399 set1(f[clk - 16], 4 * base);
400 if (clk - 8 >= 0)
401 set1(f[clk - 8], 2 * base);
402 set1(f[clk], base);
403 if (clk + 8 < CLOCKS)
404 set1(f[clk + 8], base / 2);
405 if (clk + 16 < CLOCKS)
406 set1(f[clk + 16], base / 4);
407 }
408
get_clock(int clk)409 static int get_clock(int clk)
410 {
411 static int first = 1;
412
413 if (clk < 0 || clk >= CLOCKS)
414 return 0;
415 if (first) {
416 int act_clk;
417 first = 0;
418 act_clk = et4000_clocks(-1);
419 act_clk &= 0xFC;
420 set3(clocks, act_clk, 25175); /* act_clk : 25175 KHz */
421 set3(clocks, act_clk + 1, 28322); /* act_clk+1: 28322 KHz */
422 for (act_clk = 0; act_clk < CLOCKS; ++act_clk)
423 if (clocks[act_clk] != 0)
424 set3(clocks, act_clk, clocks[act_clk]);
425 }
426 if (clocks[clk] == 0) {
427 int c = clk & 7;
428 clocks[16 + c] = measure_clk(16 + c);
429 clocks[8 + c] = 2 * clocks[16 + c];
430 clocks[c] = 2 * clocks[8 + c];
431 }
432 return clocks[clk];
433 }
434
435 #endif /* defined(USE_CLOCKS) */
436
437 /* ----------------------------------------------------------------- */
438
439
440 /* Read and store chipset-specific registers */
441
et4000_saveregs(unsigned char regs[])442 static int et4000_saveregs(unsigned char regs[])
443 {
444 int i;
445
446 et4000_unlock();
447 /* save extended CRT registers */
448 for (i = 0; i < 8; i++) {
449 port_out(0x30 + i, __svgalib_CRT_I);
450 regs[EXT + i] = port_in(__svgalib_CRT_D);
451 }
452 port_out(0x3f, __svgalib_CRT_I);
453 regs[EXT + 8] = port_in(__svgalib_CRT_D);
454
455 /* save extended sequencer register */
456 port_out(7, SEQ_I);
457 regs[EXT + 9] = port_in(SEQ_D);
458
459 /* save some other ET4000 specific registers */
460 regs[EXT + 10] = port_in(0x3c3);
461 regs[EXT + 11] = port_in(0x3cd);
462
463 /* save extended attribute register */
464 port_in(__svgalib_IS1_R); /* reset flip flop */
465 port_out(0x16, ATT_IW);
466 regs[EXT + 12] = port_in(ATT_R);
467
468 if (et4000_extdac) {
469 _ramdac_dactocomm();
470 regs[EXT + 13] = inb(PEL_MSK);
471 _ramdac_dactocomm();
472 outb(PEL_MSK, regs[EXT + 13] | 0x10);
473 _ramdac_dactocomm();
474 inb(PEL_MSK);
475 outb(PEL_MSK, 3); /* write index low */
476 outb(PEL_MSK, 0); /* write index high */
477 regs[EXT + 14] = inb(PEL_MSK); /* primary ext. pixel select */
478 regs[EXT + 15] = inb(PEL_MSK); /* secondary ext. pixel select */
479 regs[EXT + 16] = inb(PEL_MSK); /* PLL control register */
480 _ramdac_dactocomm();
481 outb(PEL_MSK, regs[EXT + 13]);
482 return 17;
483 }
484 return 13; /* ET4000 requires 13 additional registers */
485 }
486
487
488 /* Set chipset-specific registers */
489
et4000_setregs(const unsigned char regs[],int mode)490 static void et4000_setregs(const unsigned char regs[], int mode)
491 {
492 int i;
493 unsigned char save;
494
495 /* make sure linear mode is forced off */
496 et4000_setlinear(0);
497
498 et4000_unlock();
499 /* write some ET4000 specific registers */
500 port_out(regs[EXT + 10], 0x3c3);
501 port_out(regs[EXT + 11], 0x3cd);
502
503 /* write extended sequencer register */
504 port_out(7, SEQ_I);
505 port_out(regs[EXT + 9], SEQ_D);
506
507 #if 0 /* This writes to registers we shouldn't write to. */
508 /* write extended CRT registers */
509 for (i = 0; i < 6; i++) {
510 port_out(0x32 + i, __svgalib_CRT_I);
511 port_out(regs[EXT + i], __svgalib_CRT_D);
512 }
513 port_out(0x3f, __svgalib_CRT_I);
514 port_out(regs[EXT + 6], __svgalib_CRT_D);
515 #endif
516
517 /* deprotect CRT register 0x35 */
518 port_out(0x11, __svgalib_CRT_I);
519 save = port_in(__svgalib_CRT_D);
520 port_out(save & 0x7F, __svgalib_CRT_D);
521
522 /* write extended CRT registers */
523 for (i = 0; i < 6; i++) {
524 port_out(0x30 + i, __svgalib_CRT_I);
525 port_out(regs[EXT + i], __svgalib_CRT_D);
526 }
527 port_out(0x36, __svgalib_CRT_I);
528 port_out((port_in(__svgalib_CRT_D) & 0x40) | (regs[EXT + 6] & 0xbf), __svgalib_CRT_D);
529 port_out(0x37, __svgalib_CRT_I);
530 port_out((port_in(__svgalib_CRT_D) & 0xbb) | (regs[EXT + 7] & 0x44), __svgalib_CRT_D);
531 port_out(0x3f, __svgalib_CRT_I);
532 port_out(regs[EXT + 8], __svgalib_CRT_D);
533
534 /* set original CRTC 0x11 */
535 port_out(0x11, __svgalib_CRT_I);
536 port_out(save, __svgalib_CRT_D);
537
538 /* write extended attribute register */
539 port_in(__svgalib_IS1_R); /* reset flip flop */
540 port_out(0x16, ATT_IW);
541 port_out(regs[EXT + 12], ATT_IW);
542
543 if (et4000_extdac) {
544 _ramdac_dactocomm();
545 outb(PEL_MSK, regs[EXT + 13] | 0x10);
546 _ramdac_dactocomm();
547 inb(PEL_MSK);
548 outb(PEL_MSK, 3); /* write index low */
549 outb(PEL_MSK, 0); /* write index high */
550 outb(PEL_MSK, regs[EXT + 14]); /* primary ext. pixel select */
551 outb(PEL_MSK, regs[EXT + 15]); /* secondary ext. pixel select */
552 outb(PEL_MSK, regs[EXT + 16]); /* PLL control register */
553 _ramdac_dactocomm();
554 outb(PEL_MSK, regs[EXT + 13]);
555 }
556 }
557
558
559 /* Return non-zero if mode is available */
560
et4000_modeavailable(int mode)561 static int et4000_modeavailable(int mode)
562 {
563 const unsigned char *regs;
564 struct info *info;
565
566 regs = LOOKUPMODE(et4000_modes, mode);
567 if (regs == NULL || mode == GPLANE16)
568 return __svgalib_vga_driverspecs.modeavailable(mode);
569 if (regs == DISABLE_MODE || mode <= TEXT || mode > GLASTMODE)
570 return 0;
571
572 info = &__svgalib_infotable[mode];
573 if (et4000_memory * 1024 < info->ydim * info->xbytes)
574 return 0;
575
576 switch (info->colors) {
577 case 1 << 15:
578 /* All HiColor dacs handle 15 bit */
579 if ((et4000_dac & 1) == 0)
580 return 0;
581 break;
582 case 1 << 16:
583 /* Unfortunately, we can't tell the difference between a Sierra Mark 2 */
584 /* and a Mark 3, and the mark 2 is only 15 bit. If this gives you trouble */
585 /* change it to (8|16) rather than (2|8|16) */
586 /* Currently allow Sierra Mark2/3, AT&T, STG-170x and AcuMos */
587 if ((et4000_dac & (2 | 8 | 16 | 32 | 64)) == 0)
588 return 0;
589 break;
590 case 1 << 24:
591 /* Don't know how to set dac command register for Diamond SS2410 Dac */
592 /* Only allow AT&T, STG-170x and AcuMos */
593 if ((et4000_dac & (8 | 16 | 32 | 64)) == 0)
594 return 0;
595 break;
596 }
597 return SVGADRV;
598 }
599
600
601 /* Check if mode is interlaced */
602
et4000_interlaced(int mode)603 static int et4000_interlaced(int mode)
604 {
605 const unsigned char *regs;
606
607 if (et4000_modeavailable(mode) != SVGADRV)
608 return 0;
609 regs = LOOKUPMODE(et4000_modes, mode);
610 if (regs == NULL || regs == DISABLE_MODE)
611 return 0;
612 return (regs[EXT + 5] & 0x80) != 0; /* CRTC 35H */
613 }
614
615
616 /* Set a mode */
617
et4000_setmode(int mode,int prv_mode)618 static int et4000_setmode(int mode, int prv_mode)
619 {
620 const unsigned char *regs;
621 unsigned char i;
622
623 if (et4000_dac)
624 /* Standard dac behaviour */
625 __svgalib_hicolor(et4000_dac, STD_DAC);
626 switch (et4000_modeavailable(mode)) {
627 case STDVGADRV:
628 /* Reset extended register that is set to non-VGA */
629 /* compatible value for 132-column textmodes (at */
630 /* least on some cards). */
631 et4000_unlock();
632 outb(__svgalib_CRT_I, 0x34);
633 i = inb(__svgalib_CRT_D);
634 if ((i & 0x02) == 0x02)
635 outb(__svgalib_CRT_D, (i & 0xfd)); /* DS */
636 return __svgalib_vga_driverspecs.setmode(mode, prv_mode);
637 case SVGADRV:
638 regs = LOOKUPMODE(et4000_modes, mode);
639 if (regs != NULL)
640 break;
641 default:
642 return 1; /* mode not available */
643 }
644
645 if (et4000_dac && !et4000_extdac)
646 switch (vga_getmodeinfo(mode)->colors) {
647 case 1 << 15:
648 __svgalib_hicolor(et4000_dac, HI15_DAC);
649 break;
650 case 1 << 16:
651 __svgalib_hicolor(et4000_dac, HI16_DAC);
652 break;
653 case 1 << 24:
654 __svgalib_hicolor(et4000_dac, TC24_DAC);
655 break;
656 }
657 __svgalib_setregs(regs);
658 et4000_setregs(regs, mode);
659 return 0;
660 }
661
662 /* Unlock chipset-specific registers */
663
et4000_unlock(void)664 static void et4000_unlock(void)
665 {
666 /* get access to extended registers */
667 port_out(3, 0x3bf);
668 if (port_in(0x3cc) & 1)
669 port_out(0xa0, 0x3d8);
670 else
671 port_out(0xa0, 0x3b8);
672 }
673
674
675 /* Relock chipset-specific registers */
676
et4000_lock(void)677 static void et4000_lock(void)
678 {
679 }
680
681 /* Enable linear mode at a particular 4M page (0 to turn off) */
682
et4000_setlinear(int addr)683 static void et4000_setlinear(int addr)
684 {
685 et4000_unlock();
686 outb(CRT_IC, 0x36);
687 if (addr)
688 outb(CRT_DC, inb(CRT_DC) | 16); /* enable linear mode */
689 else
690 outb(CRT_DC, inb(CRT_DC) & ~16); /* disable linear mode */
691 outb(CRT_IC, 0x30);
692 outb(CRT_DC, addr);
693 et4000_lock();
694 }
695
696
697 /* Indentify chipset; return non-zero if detected */
698
et4000_test(void)699 static int et4000_test(void)
700 {
701 unsigned char new, old, val;
702 int base;
703
704 et4000_unlock();
705
706 /* test for Tseng clues */
707 old = port_in(0x3cd);
708 port_out(0x55, 0x3cd);
709 new = port_in(0x3cd);
710 port_out(old, 0x3cd);
711
712 /* return false if not Tseng */
713 if (new != 0x55)
714 return 0;
715
716 /* test for ET4000 clues */
717 if (port_in(0x3cc) & 1)
718 base = CRT_IC;
719 else
720 base = 0x3b4;
721 port_out(0x33, base);
722 old = port_in(base + 1);
723 new = old ^ 0xf;
724 port_out(new, base + 1);
725 val = port_in(base + 1);
726 port_out(old, base + 1);
727
728 /* return true if ET4000 */
729 if (val == new) {
730 et4000_init(0, 0, 0);
731 return 1;
732 }
733 return 0;
734 }
735
736
737
738 static unsigned char last_page = 0;
739
740 /* Bank switching function - set 64K bank number */
et4000_setpage(int page)741 static void et4000_setpage(int page)
742 {
743 /* Set both read and write bank. */
744 port_out(last_page = (page | ((page & 15) << 4)), SEG_SELECT);
745 if (et4000_chiptype >= CHIP_ET4000W32i) {
746 /* Write page4-5 to bits 0-1 of ext. bank register, */
747 /* and to bits 4-5. */
748 outb(0x3cb, (inb(0x3cb) & ~0x33) | (page >> 4) | (page & 0x30));
749 }
750 }
751
752
753 /* Bank switching function - set 64K read bank number */
et4000_setrdpage(int page)754 static void et4000_setrdpage(int page)
755 {
756 last_page &= 0x0F;
757 last_page |= (page << 4);
758 port_out(last_page, SEG_SELECT);
759 if (et4000_chiptype >= CHIP_ET4000W32i) {
760 /* Write page4-5 to bits 4-5 of ext. bank register. */
761 outb(0x3cb, (inb(0x3cb) & ~0x30) | (page & 0x30));
762 }
763 }
764
765 /* Bank switching function - set 64K write bank number */
et4000_setwrpage(int page)766 static void et4000_setwrpage(int page)
767 {
768 last_page &= 0xF0;
769 last_page |= page;
770 port_out(last_page, SEG_SELECT);
771 if (et4000_chiptype >= CHIP_ET4000W32i) {
772 /* Write page4-5 to bits 0-1 of ext. bank register. */
773 outb(0x3cb, (inb(0x3cb) & ~0x03) | (page >> 4));
774 }
775 }
776
777
778 /* Set display start address (not for 16 color modes) */
779 /* ET4000 supports any address in video memory (up to 1Mb) */
780 /* ET4000/W32i/p supports up to 4Mb */
781
et4000_setdisplaystart(int address)782 static void et4000_setdisplaystart(int address)
783 {
784 outw(CRT_IC, 0x0d + ((address >> 2) & 0x00ff) * 256); /* sa2-sa9 */
785 outw(CRT_IC, 0x0c + ((address >> 2) & 0xff00)); /* sa10-sa17 */
786 inb(0x3da); /* set ATC to addressing mode */
787 outb(ATT_IW, 0x13 + 0x20); /* select ATC reg 0x13 */
788 outb(ATT_IW, (inb(ATT_R) & 0xf0) | ((address & 3) << 1));
789 /* write sa0-1 to bits 1-2 */
790 outb(CRT_IC, 0x33);
791 if (et4000_chiptype >= CHIP_ET4000W32i)
792 /* write sa18-21 to bit 0-3 */
793 outb(CRT_DC, (inb(CRT_DC) & 0xf0) | ((address & 0x3c0000) >> 18));
794 else
795 /* write sa18-19 to bit 0-3 */
796 outb(CRT_DC, (inb(CRT_DC) & 0xfc) | ((address & 0xc0000) >> 18));
797 }
798
799
800 /* Set logical scanline length (usually multiple of 8) */
801 /* ET4000 supports multiples of 8 to 4088 */
802
et4000_setlogicalwidth(int width)803 static void et4000_setlogicalwidth(int width)
804 {
805 outw(CRT_IC, 0x13 + (width >> 3) * 256); /* lw3-lw11 */
806 outb(CRT_IC, 0x3f);
807 outb(CRT_DC, (inb(CRT_DC) & 0x7f)
808 | ((width & 0x800) >> 5)); /* write lw12 to bit 7 */
809 }
810
et4000_ext_set(unsigned what,va_list params)811 static int et4000_ext_set(unsigned what, va_list params)
812 {
813 int param2, old_values;
814
815 switch (what) {
816 case VGA_EXT_AVAILABLE:
817 param2 = va_arg(params, int);
818 switch (param2) {
819 case VGA_AVAIL_SET:
820 return VGA_EXT_AVAILABLE | VGA_EXT_SET | VGA_EXT_CLEAR | VGA_EXT_RESET;
821 case VGA_AVAIL_ACCEL:
822 return 0;
823 case VGA_AVAIL_FLAGS:
824 return pos_ext_settings;
825 }
826 return 0;
827 case VGA_EXT_SET:
828 old_values = ext_settings;
829 ext_settings |= (va_arg(params, int)) & pos_ext_settings;
830 params_changed:
831 if (((old_values ^ ext_settings) & pos_ext_settings)) {
832 int cmd;
833 CRITICAL = 1;
834 vga_lockvc();
835 _ramdac_dactocomm();
836 cmd = inb(PEL_MSK);
837 _ramdac_dactocomm();
838 if (ext_settings & VGA_CLUT8)
839 cmd |= 2;
840 else
841 cmd &= ~2;
842 outb(PEL_MSK, cmd);
843 vga_unlockvc();
844 CRITICAL = 0;
845 }
846 return old_values;
847 case VGA_EXT_CLEAR:
848 old_values = ext_settings;
849 ext_settings &= ~((va_arg(params, int)) & pos_ext_settings);
850 goto params_changed;
851 case VGA_EXT_RESET:
852 old_values = ext_settings;
853 ext_settings = (va_arg(params, int)) & pos_ext_settings;
854 goto params_changed;
855 default:
856 return 0;
857 }
858 }
859
et4000_linear(int op,int param)860 static int et4000_linear(int op, int param)
861 {
862 /* linear mode not supported on original chipset */
863 if (et4000_chiptype == CHIP_ET4000)
864 return -1;
865 else if (op == LINEAR_QUERY_GRANULARITY)
866 return 4 * 1024 * 1024;
867 else if (op == LINEAR_QUERY_RANGE)
868 return 256;
869 else if (op == LINEAR_ENABLE) {
870 et4000_setlinear(param / (4 * 1024 * 1024));
871 return 0;
872 } else if (op == LINEAR_DISABLE) {
873 et4000_setlinear(0);
874 return 0;
875 } else
876 return -1;
877 }
878
879 /* Function table (exported) */
880
881 DriverSpecs __svgalib_et4000_driverspecs =
882 {
883 et4000_saveregs,
884 et4000_setregs,
885 et4000_unlock,
886 et4000_lock,
887 et4000_test,
888 et4000_init,
889 et4000_setpage,
890 et4000_setrdpage,
891 et4000_setwrpage,
892 et4000_setmode,
893 et4000_modeavailable,
894 et4000_setdisplaystart,
895 et4000_setlogicalwidth,
896 et4000_getmodeinfo,
897 0, /* bitblt */
898 0, /* imageblt */
899 0, /* fillblt */
900 0, /* hlinelistblt */
901 0, /* bltwait */
902 et4000_ext_set,
903 0,
904 et4000_linear,
905 NULL, /* Accelspecs */
906 NULL, /* Emulation */
907 };
908
909
910 /* Hicolor DAC detection derived from vgadoc (looks tricky) */
911
912
913 #ifndef DAC_TYPE
testdac(void)914 static int testdac(void)
915 {
916 int x, y, z, v, oldcommreg, oldpelreg, retval;
917
918 /* Use the following return values:
919 * 0: Ordinary DAC
920 * 1: Sierra SC11486 (32k)
921 * 3: Sierra 32k/64k
922 * 5: SS2410 15/24bit DAC
923 * 9: AT&T 20c491/2
924 * 10: STG-170x
925 */
926
927 retval = 0; /* default to no fancy dac */
928 _ramdac_dactopel();
929 x = inb(PEL_MSK);
930 do { /* wait for repeat of value */
931 y = x;
932 x = inb(PEL_MSK);
933 } while (x != y);
934 z = x;
935 inb(PEL_IW);
936 inb(PEL_MSK);
937 inb(PEL_MSK);
938 inb(PEL_MSK);
939 x = inb(PEL_MSK);
940 y = 8;
941 while ((x != 0x8e) && (y > 0)) {
942 x = inb(PEL_MSK);
943 y--;
944 }
945 if (x == 0x8e) {
946 /* We have an SS2410 */
947 retval = 1 | 4;
948 _ramdac_dactopel();
949 } else {
950 _ramdac_dactocomm();
951 oldcommreg = inb(PEL_MSK);
952 _ramdac_dactopel();
953 oldpelreg = inb(PEL_MSK);
954 x = oldcommreg ^ 0xFF;
955 outb(PEL_MSK, x);
956 _ramdac_dactocomm();
957 v = inb(PEL_MSK);
958 if (v != x) {
959 v = _ramdac_setcomm(x = oldcommreg ^ 0x60);
960 /* We have a Sierra SC11486 */
961 retval = 1;
962
963 if ((x & 0xe0) == (v & 0xe0)) {
964 /* We have a Sierra 32k/64k */
965 x = inb(PEL_MSK);
966 _ramdac_dactopel();
967 retval = 1 | 2;
968
969 if (x == inb(PEL_MSK)) {
970 /* We have an ATT 20c491 or 20c492 */
971 retval = 1 | 8;
972 if (_ramdac_setcomm(0xFF) != 0xFF) {
973 /* We have a weird dac, AcuMos ADAC1 */
974 retval = 1 | 16;
975 } else { /* maybe an STG-170x */
976 /* try to enable ext. registers */
977 _ramdac_setcomm(oldcommreg | 0x10);
978 outb(PEL_MSK, 0);
979 outb(PEL_MSK, 0);
980 if (inb(PEL_MSK) == 0x44) {
981 /* it's a 170x */
982 /* Another read from PEL_MSK gets the chiptype, 0x02 == 1702. */
983 retval = 1 | 64;
984 et4000_extdac = 1;
985 }
986 }
987 }
988 }
989 _ramdac_dactocomm();
990 outb(PEL_MSK, oldcommreg);
991 }
992 _ramdac_dactopel();
993 outb(PEL_MSK, oldpelreg);
994 }
995 return retval;
996 }
997 #endif /* !defined(DAC_TYPE) */
998
999
1000 /* Initialize chipset (called after detection) */
1001
et4000_init(int force,int par1,int par2)1002 static int et4000_init(int force, int par1, int par2)
1003 {
1004 int value;
1005 int old, new, val;
1006 #ifdef USE_CLOCKS
1007 int i;
1008 #endif
1009
1010 #ifdef DYNAMIC
1011 if (et4000_modes == NULL) {
1012 FILE *regs;
1013
1014 regs = fopen(ET4000_REGS, "r");
1015 if (regs != 0) {
1016 et4000_modes = NULL;
1017 __svgalib_readmodes(regs, &et4000_modes, &et4000_dac, &clocks[0]);
1018 fclose(regs);
1019 } else
1020 et4000_modes = &No_Modes;
1021 }
1022 #endif
1023
1024 /* Determine the ET4000 chip type. */
1025
1026 /* Test for ET4000/W32. */
1027 old = inb(0x3cb);
1028 outb(0x3cb, 0x33);
1029 new = inb(0x3cb);
1030 outb(0x3cb, old);
1031 if (new != 0x33)
1032 et4000_chiptype = CHIP_ET4000;
1033 else {
1034 /* ET4000/W32. */
1035 if (getenv("IOPERM") == NULL && iopl(3) < 0)
1036 /* Can't get further I/O permissions -- */
1037 /* assume ET4000/W32. */
1038 et4000_chiptype = CHIP_ET4000W32;
1039 else {
1040 outb(0x217a, 0xec);
1041 val = inb(0x217b) >> 4;
1042 switch (val) {
1043 case 0:
1044 et4000_chiptype = CHIP_ET4000W32;
1045 break;
1046 case 1:
1047 case 3:
1048 et4000_chiptype = CHIP_ET4000W32i;
1049 break;
1050 case 2:
1051 case 5:
1052 default:
1053 et4000_chiptype = CHIP_ET4000W32p;
1054 }
1055 /* Do NOT set back iopl if set before, since */
1056 /* caller most likely still needs it! */
1057 if (getenv("IOPERM") == NULL)
1058 iopl(0);
1059 }
1060 }
1061
1062 if (force)
1063 et4000_memory = par1;
1064 else {
1065 outb(CRT_IC, 0x37);
1066 value = inb(CRT_DC);
1067 et4000_memory = (value & 0x08) ? 256 : 64;
1068 switch (value & 3) {
1069 case 2:
1070 et4000_memory *= 2;
1071 break;
1072 case 3:
1073 et4000_memory *= 4;
1074 break;
1075 }
1076 if (value & 0x80)
1077 et4000_memory *= 2;
1078 outb(CRT_IC, 0x32);
1079 if (inb(CRT_DC) & 0x80) {
1080 /* Interleaved memory on ET4000/W32i/p: */
1081 /* Multiply by 2. */
1082 et4000_memory *= 2;
1083 }
1084 }
1085 #ifndef DAC_TYPE
1086 if (et4000_dac < 0)
1087 et4000_dac = testdac();
1088 #endif
1089
1090 #ifdef USE_CLOCKS
1091 /* Measure clock frequencies */
1092 for (i = 0; i < CLOCKS; ++i)
1093 get_clock(i);
1094 #endif
1095
1096 if (__svgalib_driver_report) {
1097 char dacname[60];
1098 switch (et4000_dac & ~1) {
1099 case 0:
1100 strcpy(dacname, ", Hicolor Dac: Sierra SC11486");
1101 break;
1102 case 2:
1103 strcpy(dacname, ", Hicolor Dac: Sierra 32k/64k");
1104 break;
1105 case 4:
1106 strcpy(dacname, ", Hicolor Dac: SS2410");
1107 break;
1108 case 8:
1109 strcpy(dacname, ", Hicolor Dac: ATT20c491/2");
1110 break;
1111 case 16:
1112 strcpy(dacname, ", Hicolor Dac: ACUMOS ADAC1");
1113 break;
1114 case 32:
1115 strcpy(dacname, ", Hicolor Dac: Sierra 15025/6 (24-bit)");
1116 break;
1117 case 64:
1118 strcpy(dacname, ", Hicolor Dac: STG-170x (24-bit)");
1119 break;
1120 default:
1121 strcpy(dacname, ", Hicolor Dac: Unknown");
1122 break;
1123 }
1124
1125 printf("Using Tseng ET4000 driver (%s %d%s).",
1126 chipname[et4000_chiptype], et4000_memory,
1127 et4000_dac & 1 ? dacname : "");
1128 #ifdef USE_CLOCKS
1129 printf(" Clocks:");
1130 for (i = 0; i < 8; ++i)
1131 printf(" %d", (clocks[i] + 500) / 1000);
1132 #endif
1133 printf("\n");
1134 }
1135 __svgalib_driverspecs = &__svgalib_et4000_driverspecs;
1136
1137 __svgalib_banked_mem_base=0xa0000;
1138 __svgalib_banked_mem_size=0x10000;
1139 /* __svgalib_linear_mem_base=LINEARBASE;
1140 __svgalib_linear_mem_size=nv3_memory*0x400; */
1141
1142 pos_ext_settings = 0;
1143 if (et4000_dac & (8 | 16 | 32 | 64))
1144 pos_ext_settings = VGA_CLUT8;
1145
1146 return 0;
1147 }
1148