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