trident_dac.c revision ff89ac2b
1/*
2 * Copyright 1992-2003 by Alan Hourihane, North Wales, UK.
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of Alan Hourihane not be used in
9 * advertising or publicity pertaining to distribution of the software without
10 * specific, written prior permission.  Alan Hourihane makes no representations
11 * about the suitability of this software for any purpose.  It is provided
12 * "as is" without express or implied warranty.
13 *
14 * ALAN HOURIHANE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL ALAN HOURIHANE BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
21 *
22 * Author:  Alan Hourihane, alanh@fairlite.demon.co.uk
23 */
24
25#ifdef HAVE_CONFIG_H
26#include "config.h"
27#endif
28
29#include "xf86.h"
30#include "xf86_OSproc.h"
31#include "xf86PciInfo.h"
32#include "xf86Pci.h"
33
34#include "vgaHW.h"
35
36#include "trident.h"
37#include "trident_regs.h"
38
39
40static biosMode bios1[] = {
41    { 640, 480, 0x11 }
42};
43
44static biosMode bios4[] = {
45    { 320, 200, 0xd },
46    { 640, 200, 0xe },
47    { 640, 350, 0x11 },
48    { 640, 480, 0x12 },
49    { 800, 600, 0x5b },
50    { 1024, 768 , 0x5f },
51    { 1280, 1024, 0x63 },
52    { 1600, 1200, 0x65 }
53};
54
55static biosMode bios8[] = {
56    { 320, 200, 0x13 },
57    { 640, 400, 0x5c },
58    { 640, 480, 0x5d },
59    { 720, 480, 0x60 },
60    { 800, 600, 0x5e },
61    { 1024, 768, 0x62 },
62    { 1280, 1024, 0x64 },
63    { 1600, 1200, 0x66 }
64};
65
66static biosMode bios15[] = {
67    { 640, 400, 0x72 },
68    { 640, 480, 0x74 },
69    { 720, 480, 0x70 },
70    { 800, 600, 0x76 },
71    { 1024, 768, 0x78 },
72    { 1280, 1024, 0x7a },
73    { 1600, 1200, 0x7c }
74};
75
76static biosMode bios16[] = {
77    { 640, 400, 0x73 },
78    { 640, 480, 0x75 },
79    { 720, 480, 0x71 },
80    { 800, 600, 0x77 },
81    { 1024, 768, 0x79 },
82    { 1280, 1024, 0x7b },
83    { 1600, 1200, 0x7d }
84};
85
86static biosMode bios24[] = {
87    { 640, 400, 0x6b },
88    { 640, 480, 0x6c },
89    { 720, 480, 0x61 },
90    { 800, 600, 0x6d },
91    { 1024, 768, 0x6e }
92};
93
94static newModes newModeRegs [] = {
95  { 320, 200, 0x13, 0x30 },
96  { 640, 480, 0x13, 0x61 },
97  { 800, 600, 0x13, 0x62 },
98  { 1024, 768, 0x31, 0x63 },
99  { 1280, 1024, 0x7b, 0x64 },
100  { 1400, 1050, 0x11, 0x7b }
101};
102
103int
104TridentFindMode(int xres, int yres, int depth)
105{
106    int xres_s;
107    int i, size;
108    biosMode *mode;
109
110    switch (depth) {
111    case 8:
112	size = sizeof(bios8) / sizeof(biosMode);
113	mode = bios8;
114	break;
115    case 15:
116	size = sizeof(bios15) / sizeof(biosMode);
117	mode = bios15;
118	break;
119    case 16:
120	size = sizeof(bios16) / sizeof(biosMode);
121	mode = bios16;
122	break;
123    case 24:
124	size = sizeof(bios24) / sizeof(biosMode);
125	mode = bios24;
126	break;
127    default:
128	return 0;
129    }
130
131    for (i = 0; i < size; i++) {
132	if (xres <= mode[i].x_res) {
133	    xres_s = mode[i].x_res;
134	    for (; i < size; i++) {
135		if (mode[i].x_res != xres_s)
136		    return mode[i-1].mode;
137		if (yres <= mode[i].y_res)
138		    return mode[i].mode;
139	    }
140	}
141    }
142    return mode[size - 1].mode;
143}
144
145static void
146TridentFindNewMode(int xres, int yres, CARD8 *gr5a, CARD8 *gr5c)
147{
148    int xres_s;
149    int i, size;
150
151    size = sizeof(newModeRegs) / sizeof(newModes);
152
153    for (i = 0; i < size; i++) {
154	if (xres <= newModeRegs[i].x_res) {
155	    xres_s = newModeRegs[i].x_res;
156	    for (; i < size; i++) {
157	        if (newModeRegs[i].x_res != xres_s
158		    || yres <= newModeRegs[i].y_res) {
159		  *gr5a = newModeRegs[i].GR5a;
160		  *gr5c = newModeRegs[i].GR5c;
161		  return;
162		}
163	    }
164	}
165    }
166    *gr5a = newModeRegs[size - 1].GR5a;
167    *gr5c = newModeRegs[size - 1].GR5c;
168    return;
169}
170
171static void
172tridentSetBrightnessAndGamma(TRIDENTRegPtr tridentReg,
173			     Bool on, double exp,int brightness)
174{
175    int pivots[] = {0,3,15,63,255};
176
177    double slope;
178    double y_0;
179    double x, x_prev = 0, y, y_prev = 0;
180    int i;
181    CARD8 i_slopes[4];
182    CARD8 intercepts[4];
183
184    if (!on) {
185	tridentReg->tridentRegs3C4[0xB4] &= ~0x80;
186	return;
187    }
188
189    for (i = 0; i < 4; i++) {
190	x = pivots[i + 1] / 255.0;
191	y = pow(x,exp);
192	slope = (y - y_prev) / (x - x_prev);
193	y_0 = y - x * slope;
194	{
195#define RND(x) ((((x) - (int) (x)) < 0.5) ? (int)(x) : (int)(x) + 1)
196	    int val = slope;
197	    if (val > 7)
198		i_slopes[i] = (3 << 4) | (RND(slope) & 0xf);
199	    else if (val > 3)
200		i_slopes[i] = (2 << 4) | (RND(slope * 2) & 0xf);
201	    else if (val > 1)
202		i_slopes[i] = (1 << 4) | (RND(slope * 4) & 0xf);
203	    else
204		i_slopes[i] = (RND(slope * 8) & 0xf);
205#undef RND
206	}
207	intercepts[i] = (char)(y_0 * 256 / 4);
208	x_prev = x;
209	y_prev = y;
210    }
211
212    tridentReg->tridentRegs3C4[0xB4] = 0x80 | i_slopes[0];
213    tridentReg->tridentRegs3C4[0xB5] = i_slopes[1];
214    tridentReg->tridentRegs3C4[0xB6] = i_slopes[2];
215    tridentReg->tridentRegs3C4[0xB7] = i_slopes[3];
216    tridentReg->tridentRegs3C4[0xB8] = (intercepts[0] + brightness);
217    tridentReg->tridentRegs3C4[0xB9] = (intercepts[1] + brightness);
218    tridentReg->tridentRegs3C4[0xBA] = (intercepts[2] + brightness);
219    tridentReg->tridentRegs3C4[0xBB] = (intercepts[3] + brightness);
220}
221
222Bool
223TridentInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
224{
225    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
226    TRIDENTRegPtr pReg = &pTrident->ModeReg;
227
228    int vgaIOBase;
229    int offset = 0;
230    int clock = pTrident->currentClock;
231    CARD8 protect = 0;
232    Bool fullSize = FALSE;
233
234    vgaHWPtr hwp = VGAHWPTR(pScrn);
235    vgaRegPtr regp = &hwp->ModeReg;
236    vgaRegPtr vgaReg = &hwp->ModeReg;
237    vgaIOBase = VGAHWPTR(pScrn)->IOBase;
238
239    /* Unprotect */
240    if (pTrident->Chipset > PROVIDIA9685) {
241    	OUTB(0x3C4, Protection);
242    	protect = INB(0x3C5);
243    	OUTB(0x3C5, 0x92);
244    }
245
246    OUTB(0x3C4, 0x0B); INB(0x3C5); /* Ensure we are in New Mode */
247
248    pReg->tridentRegs3x4[PixelBusReg] = 0x00;
249    pReg->tridentRegsDAC[0x00] = 0x00;
250    pReg->tridentRegs3C4[NewMode2] = 0x20;
251    OUTB(0x3CE, MiscExtFunc);
252    pReg->tridentRegs3CE[MiscExtFunc] = INB(0x3CF) & 0xF0;
253    pReg->tridentRegs3x4[GraphEngReg] = 0x00;
254    pReg->tridentRegs3x4[PreEndControl] = 0;
255    pReg->tridentRegs3x4[PreEndFetch] = 0;
256
257    pReg->tridentRegs3x4[CRTHiOrd] = (((mode->CrtcVBlankEnd-1) & 0x400)>>4) |
258 				     (((mode->CrtcVTotal - 2) & 0x400) >> 3) |
259 				     ((mode->CrtcVSyncStart & 0x400) >> 5) |
260 				     (((mode->CrtcVDisplay - 1) & 0x400) >> 6)|
261 				     0x08;
262
263    pReg->tridentRegs3x4[HorizOverflow] = ((mode->CrtcHTotal & 0x800) >> 11) |
264	    				  ((mode->CrtcHBlankStart & 0x800)>>7);
265
266    if (pTrident->IsCyber) {
267	Bool LCDActive;
268#ifdef READOUT
269	Bool ShadowModeActive;
270#endif
271	int i = pTrident->lcdMode;
272#ifdef READOUT
273	OUTB(0x3CE, CyberControl);
274	ShadowModeActive = ((INB(0x3CF) & 0x81) == 0x81);
275#endif
276	OUTB(0x3CE, FPConfig);
277	pReg->tridentRegs3CE[FPConfig] = INB(0x3CF);
278	if (pTrident->dspOverride) {
279	    if (pTrident->dspOverride & LCD_ACTIVE) {
280		pReg->tridentRegs3CE[FPConfig] |= 0x10;
281		    LCDActive = TRUE;
282	    } else {
283		pReg->tridentRegs3CE[FPConfig] &= ~0x10;
284		    LCDActive = FALSE;
285	    }
286	    if (pTrident->dspOverride & CRT_ACTIVE)
287		pReg->tridentRegs3CE[FPConfig] |= 0x20;
288	    else
289		pReg->tridentRegs3CE[FPConfig] &= ~0x20;
290	} else {
291	    LCDActive = (pReg->tridentRegs3CE[FPConfig] & 0x10);
292	}
293
294	OUTB(0x3CE, CyberEnhance);
295#if 0
296	pReg->tridentRegs3CE[CyberEnhance] = INB(0x3CF);
297#else
298	pReg->tridentRegs3CE[CyberEnhance] = INB(0x3CF) & 0x8F;
299 	if (mode->CrtcVDisplay > 1024)
300	    pReg->tridentRegs3CE[CyberEnhance] |= 0x50;
301	else
302	if (mode->CrtcVDisplay > 768)
303	    pReg->tridentRegs3CE[CyberEnhance] |= 0x30;
304	else
305	if (mode->CrtcVDisplay > 600)
306	    pReg->tridentRegs3CE[CyberEnhance] |= 0x20;
307	else
308	if (mode->CrtcVDisplay > 480)
309	    pReg->tridentRegs3CE[CyberEnhance] |= 0x10;
310#endif
311	OUTB(0x3CE, CyberControl);
312	pReg->tridentRegs3CE[CyberControl] = INB(0x3CF);
313
314	OUTB(0x3CE,HorStretch);
315	pReg->tridentRegs3CE[HorStretch] = INB(0x3CF);
316	OUTB(0x3CE,VertStretch);
317	pReg->tridentRegs3CE[VertStretch] = INB(0x3CF);
318
319#ifdef READOUT
320	if ((!((pReg->tridentRegs3CE[VertStretch] & 1) ||
321	       (pReg->tridentRegs3CE[HorStretch] & 1)))
322	    && (!LCDActive || ShadowModeActive))
323	  {
324	    unsigned char tmp;
325
326	    SHADOW_ENABLE(tmp);
327	    OUTB(vgaIOBase + 4,0);
328	    pReg->tridentRegs3x4[0x0] = INB(vgaIOBase + 5);
329	    OUTB(vgaIOBase + 4,3);
330	    pReg->tridentRegs3x4[0x3] = INB(vgaIOBase + 5);
331	    OUTB(vgaIOBase + 4,4);
332	    pReg->tridentRegs3x4[0x4] = INB(vgaIOBase + 5);
333	    OUTB(vgaIOBase + 4,5);
334  	    pReg->tridentRegs3x4[0x5] = INB(vgaIOBase + 5);
335  	    OUTB(vgaIOBase + 4,0x6);
336  	    pReg->tridentRegs3x4[0x6] = INB(vgaIOBase + 5);
337  	    SHADOW_RESTORE(tmp);
338 	} else
339#endif
340 	{
341 	    if (i != 0xff) {
342  		pReg->tridentRegs3x4[0x0] = LCD[i].shadow_0;
343  		pReg->tridentRegs3x4[0x1] = regp->CRTC[1];
344  		pReg->tridentRegs3x4[0x2] = regp->CRTC[2];
345  		pReg->tridentRegs3x4[0x3] = LCD[i].shadow_3;
346  		pReg->tridentRegs3x4[0x4] = LCD[i].shadow_4;
347  		pReg->tridentRegs3x4[0x5] = LCD[i].shadow_5;
348  		pReg->tridentRegs3x4[0x6] = LCD[i].shadow_6;
349 		xf86DrvMsgVerb(pScrn->scrnIndex,X_INFO,1,
350 			       "Overriding Horizontal timings.\n");
351  	    }
352  	}
353
354 	if (i != 0xff) {
355 	    pReg->tridentRegs3x4[0x7] = LCD[i].shadow_7;
356 	    pReg->tridentRegs3x4[0x10] = LCD[i].shadow_10;
357 	    pReg->tridentRegs3x4[0x11] = LCD[i].shadow_11;
358 	    pReg->tridentRegs3x4[0x12] = regp->CRTC[0x12];
359 	    pReg->tridentRegs3x4[0x15] = regp->CRTC[0x15];
360 	    pReg->tridentRegs3x4[0x16] = LCD[i].shadow_16;
361 	    if (LCDActive) {
362		/* use current screen size not panel size for display area */
363 		pReg->tridentRegs3x4[CRTHiOrd] =
364		    (pReg->tridentRegs3x4[CRTHiOrd] & 0x10)
365		    | (LCD[i].shadow_HiOrd & ~0x10);
366	    }
367
368	    fullSize = (mode->HDisplay == LCD[i].display_x)
369	        && (mode->VDisplay == LCD[i].display_y);
370 	}
371
372  	/* copy over common bits from normal VGA */
373
374  	pReg->tridentRegs3x4[0x7] &= ~0x4A;
375	pReg->tridentRegs3x4[0x7] |= (vgaReg->CRTC[0x7] & 0x4A);
376	if (LCDActive && fullSize) {
377	    regp->CRTC[0] = pReg->tridentRegs3x4[0];
378	    regp->CRTC[3] = pReg->tridentRegs3x4[3];
379	    regp->CRTC[4] = pReg->tridentRegs3x4[4];
380	    regp->CRTC[5] = pReg->tridentRegs3x4[5];
381	    regp->CRTC[6] = pReg->tridentRegs3x4[6];
382	    regp->CRTC[7] = pReg->tridentRegs3x4[7];
383	    regp->CRTC[0x10] = pReg->tridentRegs3x4[0x10];
384	    regp->CRTC[0x11] = pReg->tridentRegs3x4[0x11];
385	    regp->CRTC[0x16] = pReg->tridentRegs3x4[0x16];
386	}
387	if (LCDActive && !fullSize) {
388	    /*
389	     * Set negative h/vsync polarity to center display nicely
390	     * Seems to work on several systems.
391	     */
392	    regp->MiscOutReg |= 0xC0;
393	  /*
394	   * If the LCD is active and we don't fill the entire screen
395	   * and the previous mode was stretched we may need help from
396	   * the BIOS to set all registers for the unstreched mode.
397	   */
398	    pTrident->doInit =  ((pReg->tridentRegs3CE[HorStretch] & 1)
399				|| (pReg->tridentRegs3CE[VertStretch] & 1));
400	    pReg->tridentRegs3CE[CyberControl] |= 0x81;
401	    xf86DrvMsgVerb(pScrn->scrnIndex,X_INFO,1,"Shadow on\n");
402	} else {
403	    pReg->tridentRegs3CE[CyberControl] &= 0x7E;
404	    xf86DrvMsgVerb(pScrn->scrnIndex,X_INFO,1,"Shadow off\n");
405	}
406	if (pTrident->FPDelay < 6) {
407	    pReg->tridentRegs3CE[CyberControl] &= 0xC7;
408	    pReg->tridentRegs3CE[CyberControl] |= (pTrident->FPDelay + 2) << 3;
409	}
410
411	if (pTrident->CyberShadow) {
412	    pReg->tridentRegs3CE[CyberControl] &= 0x7E;
413	    xf86DrvMsgVerb(pScrn->scrnIndex,X_INFO,1,"Forcing Shadow off\n");
414	}
415
416 	xf86DrvMsgVerb(pScrn->scrnIndex,X_INFO,1,"H-timing shadow registers:"
417 		       " 0x%2.2x           0x%2.2x 0x%2.2x 0x%2.2x\n",
418 		       pReg->tridentRegs3x4[0], pReg->tridentRegs3x4[3],
419 		       pReg->tridentRegs3x4[4], pReg->tridentRegs3x4[5]);
420 	xf86DrvMsgVerb(pScrn->scrnIndex,X_INFO,1,"H-timing registers:       "
421 		       " 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x\n",
422 		       regp->CRTC[0], regp->CRTC[1], regp->CRTC[2],
423		       regp->CRTC[3], regp->CRTC[4], regp->CRTC[5]);
424 	xf86DrvMsgVerb(pScrn->scrnIndex,X_INFO,1,"V-timing shadow registers: "
425 		       "0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x"
426		       "           0x%2.2x (0x%2.2x)\n",
427		       pReg->tridentRegs3x4[6], pReg->tridentRegs3x4[7],
428 		       pReg->tridentRegs3x4[0x10],pReg->tridentRegs3x4[0x11],
429 		       pReg->tridentRegs3x4[0x16],
430 		       pReg->tridentRegs3x4[CRTHiOrd]);
431 	xf86DrvMsgVerb(pScrn->scrnIndex,X_INFO,1,"V-timing registers:        "
432 		       "0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x "
433		       "0x%2.2x 0x%2.2x 0x%2.2x\n",
434 		       regp->CRTC[6], regp->CRTC[7], regp->CRTC[0x10],
435		       regp->CRTC[0x11],regp->CRTC[0x12],
436 		       regp->CRTC[0x14],regp->CRTC[0x16]);
437
438
439	/* disable stretching, enable centering for default sizes */
440	pReg->tridentRegs3CE[VertStretch] &= 0x7C;
441	switch (mode->VDisplay) {
442	    case 768:
443	    case 600:
444	    case 480:
445	    case 240:
446	pReg->tridentRegs3CE[VertStretch] |= 0x80;
447	}
448	pReg->tridentRegs3CE[HorStretch] &= 0x7C;
449	switch (mode->HDisplay) {
450	    case 1024:
451	    case 800:
452	    case 640:
453	    case 320:
454	pReg->tridentRegs3CE[HorStretch] |= 0x80;
455	}
456#if 1
457	{
458  	    int mul = pScrn->bitsPerPixel >> 3;
459	    int val;
460
461	    if (!mul) mul = 1;
462
463	    /* this is what my BIOS does */
464	    val = (mode->HDisplay * mul / 8) + 16;
465
466	    pReg->tridentRegs3x4[PreEndControl] = ((val >> 8) < 2 ? 2 :0)
467	      | ((val >> 8) & 0x01);
468	    pReg->tridentRegs3x4[PreEndFetch] = val & 0xff;
469	}
470#else
471	OUTB(vgaIOBase + 4,PreEndControl);
472	pReg->tridentRegs3x4[PreEndControl] = INB(vgaIOBase + 5);
473	OUTB(vgaIOBase + 4,PreEndFetch);
474	pReg->tridentRegs3x4[PreEndFetch] = INB(vgaIOBase + 5);
475#endif
476	/* set mode */
477	if (pTrident->Chipset < BLADEXP) {
478	  pReg->tridentRegs3CE[BiosMode] = TridentFindMode(
479					   mode->HDisplay,
480					   mode->VDisplay,
481					   pScrn->depth);
482	  xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 1,
483			 "Setting BIOS Mode: %x for: %ix%i\n",
484			 pReg->tridentRegs3CE[BiosMode],
485			 mode->HDisplay,
486			 mode->VDisplay);
487	} else {
488	  TridentFindNewMode(mode->HDisplay,
489			     mode->VDisplay,
490			     &pReg->tridentRegs3CE[BiosNewMode1],
491			     &pReg->tridentRegs3CE[BiosNewMode2]);
492	  xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 1,
493			 "Setting BIOS Mode Regs: %x %x for: %ix%i\n",
494			 pReg->tridentRegs3CE[BiosNewMode1],
495			 pReg->tridentRegs3CE[BiosNewMode2],
496			 mode->HDisplay,
497			 mode->VDisplay);
498	};
499
500	/* no stretch */
501	if (pTrident->Chipset == CYBERBLADEXPAI1
502	    || pTrident->Chipset == BLADEXP)
503	    pReg->tridentRegs3CE[BiosReg] = 8;
504	else
505	    pReg->tridentRegs3CE[BiosReg] = 0;
506
507	if (pTrident->CyberStretch) {
508	    pReg->tridentRegs3CE[VertStretch] |= 0x01;
509	    pReg->tridentRegs3CE[HorStretch] |= 0x01;
510	    xf86DrvMsgVerb(pScrn->scrnIndex,X_INFO,1,"Enabling StretchMode\n");
511	}
512    }
513
514    /* Enable Chipset specific options */
515    switch (pTrident->Chipset) {
516	case XP5:
517	case CYBERBLADEXP4:
518	case CYBERBLADEXPAI1:
519	case BLADEXP:
520	case CYBERBLADEI7:
521	case CYBERBLADEI7D:
522	case CYBERBLADEI1:
523	case CYBERBLADEI1D:
524	case CYBERBLADEAI1:
525	case CYBERBLADEAI1D:
526	case CYBERBLADEE4:
527	case BLADE3D:
528	    OUTB(vgaIOBase + 4, RAMDACTiming);
529	    pReg->tridentRegs3x4[RAMDACTiming] = INB(vgaIOBase + 5) | 0x0F;
530	    /* Fall Through */
531	case CYBER9520:
532	case CYBER9525DVD:
533	case CYBER9397DVD:
534	case CYBER9397:
535	case IMAGE975:
536	case IMAGE985:
537	case CYBER9388:
538    	    	pReg->tridentRegs3CE[MiscExtFunc] |= 0x10;
539	    if (!pReg->tridentRegs3x4[PreEndControl])
540	    	pReg->tridentRegs3x4[PreEndControl] = 0x01;
541	    if (!pReg->tridentRegs3x4[PreEndFetch])
542	    	pReg->tridentRegs3x4[PreEndFetch] = 0xFF;
543	    /* Fall Through */
544	case PROVIDIA9685:
545	case CYBER9385:
546	    pReg->tridentRegs3x4[Enhancement0] = 0x40;
547	    /* Fall Through */
548	case PROVIDIA9682:
549	case CYBER9382:
550	    if (pTrident->UsePCIRetry)
551	    	pReg->tridentRegs3x4[PCIRetry] = 0xDF;
552	    else
553	    	pReg->tridentRegs3x4[PCIRetry] = 0x1F;
554	    /* Fall Through */
555	case TGUI9660:
556	case TGUI9680:
557	    if (pTrident->MUX && pScrn->bitsPerPixel == 8) {
558	    	pReg->tridentRegs3x4[PixelBusReg] |= 0x01; /* 16bit bus */
559	    	pReg->tridentRegs3C4[NewMode2] |= 0x02; /* half clock */
560    		pReg->tridentRegsDAC[0x00] |= 0x20;	/* mux mode */
561	    }
562    }
563
564    /* Defaults for all trident chipsets follows */
565    switch (pScrn->bitsPerPixel) {
566	case 8:
567	    pReg->tridentRegs3CE[MiscExtFunc] |= 0x02;
568    	    offset = pScrn->displayWidth >> 3;
569	    break;
570	case 16:
571	    pReg->tridentRegs3CE[MiscExtFunc] |= 0x02;
572    	    offset = pScrn->displayWidth >> 2;
573	    if (pScrn->depth == 15)
574    	    	pReg->tridentRegsDAC[0x00] = 0x10;
575	    else
576	    	pReg->tridentRegsDAC[0x00] = 0x30;
577    	    pReg->tridentRegs3x4[PixelBusReg] = 0x04;
578	    /* Reload with any chipset specific stuff here */
579	    if (pTrident->Chipset >= TGUI9660)
580		pReg->tridentRegs3x4[PixelBusReg] |= 0x01;
581	    if (pTrident->Chipset == TGUI9440AGi) {
582    	        pReg->tridentRegs3CE[MiscExtFunc] |= 0x08;/*Clock Division / 2*/
583	        clock *= 2;	/* Double the clock */
584	    }
585	    break;
586	case 24:
587	    pReg->tridentRegs3CE[MiscExtFunc] |= 0x02;
588    	    offset = (pScrn->displayWidth * 3) >> 3;
589    	    pReg->tridentRegs3x4[PixelBusReg] = 0x29;
590	    pReg->tridentRegsDAC[0x00] = 0xD0;
591	    if (pTrident->Chipset == CYBERBLADEXP4 ||
592	        pTrident->Chipset == XP5 ||
593	        pTrident->Chipset == CYBERBLADEE4) {
594    		OUTB(vgaIOBase+ 4, New32);
595		pReg->tridentRegs3x4[New32] = INB(vgaIOBase + 5) & 0x7F;
596	    }
597	    break;
598	case 32:
599	    pReg->tridentRegs3CE[MiscExtFunc] |= 0x02;
600	    if (pTrident->Chipset != CYBERBLADEXP4
601	        && pTrident->Chipset != BLADEXP
602	        && pTrident->Chipset != XP5
603	        && pTrident->Chipset != CYBERBLADEE4
604		&& pTrident->Chipset != CYBERBLADEXPAI1) {
605	        /* Clock Division by 2*/
606	        pReg->tridentRegs3CE[MiscExtFunc] |= 0x08;
607		clock *= 2;	/* Double the clock */
608	    }
609    	    offset = pScrn->displayWidth >> 1;
610    	    pReg->tridentRegs3x4[PixelBusReg] = 0x09;
611	    pReg->tridentRegsDAC[0x00] = 0xD0;
612	    if (pTrident->Chipset == CYBERBLADEXP4
613	        || pTrident->Chipset == BLADEXP
614	        || pTrident->Chipset == XP5
615	        || pTrident->Chipset == CYBERBLADEE4
616		|| pTrident->Chipset == CYBERBLADEXPAI1) {
617    		OUTB(vgaIOBase+ 4, New32);
618		pReg->tridentRegs3x4[New32] = INB(vgaIOBase + 5) | 0x80;
619		/* With new mode 32bpp we set the packed flag */
620      	    	pReg->tridentRegs3x4[PixelBusReg] |= 0x20;
621	    }
622	    break;
623    }
624    pReg->tridentRegs3x4[Offset] = offset & 0xFF;
625
626    {
627	CARD8 a, b;
628	TGUISetClock(pScrn, clock, &a, &b);
629	pReg->tridentRegsClock[0x00] = (regp->MiscOutReg & 0xF3) | 0x08;
630	pReg->tridentRegsClock[0x01] = a;
631	pReg->tridentRegsClock[0x02] = b;
632	if (pTrident->MCLK > 0) {
633	    TGUISetMCLK(pScrn, pTrident->MCLK, &a, &b);
634	    pReg->tridentRegsClock[0x03] = a;
635	    pReg->tridentRegsClock[0x04] = b;
636	}
637    }
638
639    pReg->tridentRegs3C4[NewMode1] = 0xC0;
640    pReg->tridentRegs3C4[Protection] = 0x92;
641
642    pReg->tridentRegs3x4[LinearAddReg] = 0;
643    if (pTrident->Linear) {
644	/* This is used for VLB, when we support it again in 4.0 */
645	if (pTrident->Chipset < CYBER9385)
646    	    pReg->tridentRegs3x4[LinearAddReg] |=
647					((pTrident->FbAddress >> 24) << 6)|
648					((pTrident->FbAddress >> 20) & 0x0F);
649	/* Turn on linear mapping */
650    	pReg->tridentRegs3x4[LinearAddReg] |= 0x20;
651    } else {
652	pReg->tridentRegs3CE[MiscExtFunc] |= 0x04;
653    }
654
655    pReg->tridentRegs3x4[CRTCModuleTest] =
656				(mode->Flags & V_INTERLACE ? 0x84 : 0x80);
657
658    OUTB(vgaIOBase+ 4, InterfaceSel);
659    pReg->tridentRegs3x4[InterfaceSel] = INB(vgaIOBase + 5) | 0x40;
660
661    OUTB(vgaIOBase+ 4, Performance);
662    pReg->tridentRegs3x4[Performance] = INB(vgaIOBase + 5);
663    if (pTrident->Chipset < BLADEXP)
664	pReg->tridentRegs3x4[Performance] |= 0x10;
665
666    OUTB(vgaIOBase+ 4, DRAMControl);
667    if (pTrident->Chipset >= CYBER9388)
668    	pReg->tridentRegs3x4[DRAMControl] = INB(vgaIOBase + 5) | 0x10;
669
670    if (pTrident->IsCyber && !pTrident->MMIOonly)
671	pReg->tridentRegs3x4[DRAMControl] |= 0x20;
672
673    if (pTrident->NewClockCode && pTrident->Chipset <= CYBER9397DVD) {
674	    OUTB(vgaIOBase + 4, ClockControl);
675	    pReg->tridentRegs3x4[ClockControl] = INB(vgaIOBase + 5) | 0x01;
676    }
677
678    OUTB(vgaIOBase+ 4, AddColReg);
679    pReg->tridentRegs3x4[AddColReg] = INB(vgaIOBase + 5) & 0xEF;
680    pReg->tridentRegs3x4[AddColReg] |= (offset & 0x100) >> 4;
681
682    if (pTrident->Chipset >= TGUI9660) {
683    	pReg->tridentRegs3x4[AddColReg] &= 0xDF;
684    	pReg->tridentRegs3x4[AddColReg] |= (offset & 0x200) >> 4;
685    }
686
687    if (IsPciCard && UseMMIO) {
688    	if (!pTrident->NoAccel)
689	    pReg->tridentRegs3x4[GraphEngReg] |= 0x80;
690    } else {
691    	if (!pTrident->NoAccel)
692	    pReg->tridentRegs3x4[GraphEngReg] |= 0x82;
693    }
694
695    OUTB(0x3CE, MiscIntContReg);
696    pReg->tridentRegs3CE[MiscIntContReg] = INB(0x3CF) | 0x04;
697
698    /* Fix hashing problem in > 8bpp on 9320 chipset */
699    if (pTrident->Chipset == CYBER9320 && pScrn->bitsPerPixel > 8)
700    	pReg->tridentRegs3CE[MiscIntContReg] &= ~0x80;
701
702    OUTB(vgaIOBase+ 4, PCIReg);
703    if (IsPciCard && UseMMIO)
704    	pReg->tridentRegs3x4[PCIReg] = INB(vgaIOBase + 5) & 0xF9;
705    else
706    	pReg->tridentRegs3x4[PCIReg] = INB(vgaIOBase + 5) & 0xF8;
707
708    /* Enable PCI Bursting on capable chips */
709    if (pTrident->Chipset >= TGUI9660) {
710	if(pTrident->UsePCIBurst) {
711	    pReg->tridentRegs3x4[PCIReg] |= 0x06;
712	} else {
713	    pReg->tridentRegs3x4[PCIReg] &= 0xF9;
714	}
715    }
716
717    if (pTrident->Chipset >= CYBER9388) {
718	if (pTrident->GammaBrightnessOn)
719	    xf86DrvMsgVerb(pScrn->scrnIndex,X_INFO,1,
720			   "Setting Gamma: %f Brightness: %i\n",
721			   pTrident->gamma, pTrident->brightness);
722	tridentSetBrightnessAndGamma(pReg,
723				     pTrident->GammaBrightnessOn,
724				     pTrident->gamma, pTrident->brightness);
725    }
726
727    /* Video */
728    OUTB(0x3C4,0x20);
729    pReg->tridentRegs3C4[SSetup] = INB(0x3C5) | 0x4;
730    pReg->tridentRegs3C4[SKey] = 0x00;
731    pReg->tridentRegs3C4[SPKey] = 0xC0;
732    OUTB(0x3C4,0x12);
733    pReg->tridentRegs3C4[Threshold] = INB(0x3C5);
734    if (pScrn->bitsPerPixel > 16)
735	pReg->tridentRegs3C4[Threshold] =
736	    (pReg->tridentRegs3C4[Threshold] & 0xf0) | 0x2;
737
738     /* restore */
739    if (pTrident->Chipset > PROVIDIA9685) {
740    	OUTB(0x3C4, Protection);
741    	OUTB(0x3C5, protect);
742    }
743
744    if (pTrident->Chipset == CYBERBLADEXP4 ||
745        pTrident->Chipset == XP5)
746    	pReg->tridentRegs3CE[DisplayEngCont] = 0x08;
747
748    /* Avoid lockup on Blade3D, PCI Retry is permanently on */
749    if (pTrident->Chipset == BLADE3D)
750    	pReg->tridentRegs3x4[PCIRetry] = 0x9F;
751
752    return(TRUE);
753}
754
755void
756TridentRestore(ScrnInfoPtr pScrn, TRIDENTRegPtr tridentReg)
757{
758    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
759    int vgaIOBase;
760    vgaIOBase = VGAHWPTR(pScrn)->IOBase;
761
762    if (pTrident->Chipset > PROVIDIA9685) {
763    	OUTB(0x3C4, Protection);
764    	OUTB(0x3C5, 0x92);
765    }
766#if 0
767    if (pTrident->doInit && pTrident->Int10) {
768        OUTW_3CE(BiosReg);
769    }
770#endif
771    /* Goto New Mode */
772    OUTB(0x3C4, 0x0B);
773    (void) INB(0x3C5);
774
775    /* Unprotect registers */
776    OUTW(0x3C4, ((0xC0 ^ 0x02) << 8) | NewMode1);
777
778    (void) INB(0x3C8);
779    (void) INB(0x3C6);
780    (void) INB(0x3C6);
781    (void) INB(0x3C6);
782    (void) INB(0x3C6);
783    OUTB(0x3C6, tridentReg->tridentRegsDAC[0x00]);
784    (void) INB(0x3C8);
785
786    OUTW_3x4(CRTCModuleTest);
787    OUTW_3x4(LinearAddReg);
788    OUTW_3C4(NewMode2);
789    OUTW_3x4(CursorControl);
790    OUTW_3x4(CRTHiOrd);
791    OUTW_3x4(HorizOverflow);
792    OUTW_3x4(AddColReg);
793    OUTW_3x4(GraphEngReg);
794    OUTW_3x4(Performance);
795    OUTW_3x4(InterfaceSel);
796    OUTW_3x4(DRAMControl);
797    OUTW_3x4(PixelBusReg);
798    OUTW_3x4(PCIReg);
799    OUTW_3x4(PCIRetry);
800    OUTW_3CE(MiscIntContReg);
801    OUTW_3CE(MiscExtFunc);
802    OUTW_3x4(Offset);
803    if (pTrident->NewClockCode && pTrident->Chipset <= CYBER9397DVD)
804	OUTW_3x4(ClockControl);
805    if (pTrident->Chipset >= CYBER9388) {
806	OUTW_3C4(Threshold);
807	OUTW_3C4(SSetup);
808	OUTW_3C4(SKey);
809	OUTW_3C4(SPKey);
810	OUTW_3x4(PreEndControl);
811	OUTW_3x4(PreEndFetch);
812	OUTW_3C4(GBslope1);
813	OUTW_3C4(GBslope2);
814	OUTW_3C4(GBslope3);
815	OUTW_3C4(GBslope4);
816	OUTW_3C4(GBintercept1);
817	OUTW_3C4(GBintercept2);
818	OUTW_3C4(GBintercept3);
819	OUTW_3C4(GBintercept4);
820    }
821    if (pTrident->Chipset >= CYBER9385)    OUTW_3x4(Enhancement0);
822    if (pTrident->Chipset >= BLADE3D)      OUTW_3x4(RAMDACTiming);
823    if (pTrident->Chipset == CYBERBLADEXP4 ||
824        pTrident->Chipset == XP5 ||
825        pTrident->Chipset == CYBERBLADEE4) OUTW_3x4(New32);
826    if (pTrident->Chipset == CYBERBLADEXP4 ||
827        pTrident->Chipset == XP5) OUTW_3CE(DisplayEngCont);
828    if (pTrident->IsCyber) {
829	CARD8 tmp;
830
831	OUTW_3CE(VertStretch);
832	OUTW_3CE(HorStretch);
833	if (pTrident->Chipset < BLADEXP) {
834	    OUTW_3CE(BiosMode);
835	} else {
836	    OUTW_3CE(BiosNewMode1);
837	    OUTW_3CE(BiosNewMode2);
838	};
839	OUTW_3CE(BiosReg);
840	OUTW_3CE(FPConfig);
841    	OUTW_3CE(CyberControl);
842    	OUTW_3CE(CyberEnhance);
843	SHADOW_ENABLE(tmp);
844	OUTW_3x4(0x0);
845	if (pTrident->shadowNew) {
846	    OUTW_3x4(0x1);
847	    OUTW_3x4(0x2);
848	}
849	OUTW_3x4(0x3);
850	OUTW_3x4(0x4);
851	OUTW_3x4(0x5);
852	OUTW_3x4(0x6);
853	OUTW_3x4(0x7);
854	OUTW_3x4(0x10);
855	OUTW_3x4(0x11);
856	if (pTrident->shadowNew) {
857	    OUTW_3x4(0x12);
858	    OUTW_3x4(0x15);
859	}
860	OUTW_3x4(0x16);
861	SHADOW_RESTORE(tmp);
862    }
863
864    if (Is3Dchip) {
865#ifdef READOUT
866	if (!pTrident->DontSetClock)
867#endif
868	{
869	    OUTW(0x3C4, (tridentReg->tridentRegsClock[0x01])<<8 | ClockLow);
870	    OUTW(0x3C4, (tridentReg->tridentRegsClock[0x02])<<8 | ClockHigh);
871	}
872	if (pTrident->MCLK > 0) {
873	    OUTW(0x3C4,(tridentReg->tridentRegsClock[0x03])<<8 | MCLKLow);
874	    OUTW(0x3C4,(tridentReg->tridentRegsClock[0x04])<<8 | MCLKHigh);
875	}
876    } else {
877#ifdef READOUT
878	if (!pTrident->DontSetClock)
879#endif
880	{
881	    OUTB(0x43C8, tridentReg->tridentRegsClock[0x01]);
882	    OUTB(0x43C9, tridentReg->tridentRegsClock[0x02]);
883	}
884	if (pTrident->MCLK > 0) {
885	    OUTB(0x43C6, tridentReg->tridentRegsClock[0x03]);
886	    OUTB(0x43C7, tridentReg->tridentRegsClock[0x04]);
887	}
888    }
889#ifdef READOUT
890    if (!pTrident->DontSetClock)
891#endif
892    {
893	OUTB(0x3C2, tridentReg->tridentRegsClock[0x00]);
894    }
895
896    if (pTrident->Chipset > PROVIDIA9685) {
897    	OUTB(0x3C4, Protection);
898    	OUTB(0x3C5, tridentReg->tridentRegs3C4[Protection]);
899    }
900
901    OUTW(0x3C4, ((tridentReg->tridentRegs3C4[NewMode1] ^ 0x02) << 8)| NewMode1);
902}
903
904void
905TridentSave(ScrnInfoPtr pScrn, TRIDENTRegPtr tridentReg)
906{
907    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
908    int vgaIOBase;
909    vgaIOBase = VGAHWPTR(pScrn)->IOBase;
910
911    /* Goto New Mode */
912    OUTB(0x3C4, 0x0B);
913    (void) INB(0x3C5);
914
915    INB_3C4(NewMode1);
916    if (pTrident->Chipset > PROVIDIA9685)
917    	INB_3C4(Protection);
918
919    /* Unprotect registers */
920    OUTW(0x3C4, ((0xC0 ^ 0x02) << 8) | NewMode1);
921    if (pTrident->Chipset > PROVIDIA9685)
922    	OUTW(0x3C4, (0x92 << 8) | Protection);
923
924    INB_3x4(Offset);
925    INB_3x4(LinearAddReg);
926    INB_3x4(CRTCModuleTest);
927    INB_3x4(CRTHiOrd);
928    INB_3x4(HorizOverflow);
929    INB_3x4(Performance);
930    INB_3x4(InterfaceSel);
931    INB_3x4(DRAMControl);
932    INB_3x4(AddColReg);
933    INB_3x4(PixelBusReg);
934    INB_3x4(GraphEngReg);
935    INB_3x4(PCIReg);
936    INB_3x4(PCIRetry);
937    if (pTrident->NewClockCode && pTrident->Chipset <= CYBER9397DVD)
938	INB_3x4(ClockControl);
939    if (pTrident->Chipset >= CYBER9388) {
940	INB_3C4(Threshold);
941	INB_3C4(SSetup);
942	INB_3C4(SKey);
943	INB_3C4(SPKey);
944	INB_3x4(PreEndControl);
945	INB_3x4(PreEndFetch);
946	INB_3C4(GBslope1);
947	INB_3C4(GBslope2);
948	INB_3C4(GBslope3);
949	INB_3C4(GBslope4);
950	INB_3C4(GBintercept1);
951	INB_3C4(GBintercept2);
952	INB_3C4(GBintercept3);
953	INB_3C4(GBintercept4);
954    }
955    if (pTrident->Chipset >= CYBER9385)    INB_3x4(Enhancement0);
956    if (pTrident->Chipset >= BLADE3D)      INB_3x4(RAMDACTiming);
957    if (pTrident->Chipset == CYBERBLADEXP4 ||
958        pTrident->Chipset == XP5 ||
959        pTrident->Chipset == CYBERBLADEE4) INB_3x4(New32);
960    if (pTrident->Chipset == CYBERBLADEXP4 ||
961        pTrident->Chipset == XP5) INB_3CE(DisplayEngCont);
962    if (pTrident->IsCyber) {
963	CARD8 tmp;
964	INB_3CE(VertStretch);
965	INB_3CE(HorStretch);
966	if (pTrident->Chipset < BLADEXP) {
967    	    INB_3CE(BiosMode);
968	} else {
969	INB_3CE(BiosNewMode1);
970	INB_3CE(BiosNewMode2);
971	}
972	INB_3CE(BiosReg);
973	INB_3CE(FPConfig);
974    	INB_3CE(CyberControl);
975    	INB_3CE(CyberEnhance);
976	SHADOW_ENABLE(tmp);
977	INB_3x4(0x0);
978	if (pTrident->shadowNew) {
979	    INB_3x4(0x1);
980	    INB_3x4(0x2);
981	}
982	INB_3x4(0x3);
983	INB_3x4(0x4);
984	INB_3x4(0x5);
985	INB_3x4(0x6);
986	INB_3x4(0x7);
987	INB_3x4(0x10);
988	INB_3x4(0x11);
989	if (pTrident->shadowNew) {
990	    INB_3x4(0x12);
991	    INB_3x4(0x15);
992	}
993	INB_3x4(0x16);
994	SHADOW_RESTORE(tmp);
995    }
996
997    /* save cursor registers */
998    INB_3x4(CursorControl);
999
1000    INB_3CE(MiscExtFunc);
1001    INB_3CE(MiscIntContReg);
1002
1003    (void) INB(0x3C8);
1004    (void) INB(0x3C6);
1005    (void) INB(0x3C6);
1006    (void) INB(0x3C6);
1007    (void) INB(0x3C6);
1008    tridentReg->tridentRegsDAC[0x00] = INB(0x3C6);
1009    (void) INB(0x3C8);
1010
1011    tridentReg->tridentRegsClock[0x00] = INB(0x3CC);
1012    if (Is3Dchip) {
1013	OUTB(0x3C4, ClockLow);
1014	tridentReg->tridentRegsClock[0x01] = INB(0x3C5);
1015	OUTB(0x3C4, ClockHigh);
1016	tridentReg->tridentRegsClock[0x02] = INB(0x3C5);
1017	if (pTrident->MCLK > 0) {
1018	    OUTB(0x3C4, MCLKLow);
1019	    tridentReg->tridentRegsClock[0x03] = INB(0x3C5);
1020	    OUTB(0x3C4, MCLKHigh);
1021	    tridentReg->tridentRegsClock[0x04] = INB(0x3C5);
1022	}
1023    } else {
1024	tridentReg->tridentRegsClock[0x01] = INB(0x43C8);
1025	tridentReg->tridentRegsClock[0x02] = INB(0x43C9);
1026	if (pTrident->MCLK > 0) {
1027	    tridentReg->tridentRegsClock[0x03] = INB(0x43C6);
1028	    tridentReg->tridentRegsClock[0x04] = INB(0x43C7);
1029	}
1030    }
1031
1032    INB_3C4(NewMode2);
1033
1034    /* Protect registers */
1035    OUTW_3C4(NewMode1);
1036}
1037
1038static void
1039TridentShowCursor(ScrnInfoPtr pScrn)
1040{
1041    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
1042    int vgaIOBase;
1043    vgaIOBase = VGAHWPTR(pScrn)->IOBase;
1044
1045    /* 64x64 */
1046    OUTW(vgaIOBase + 4, 0xC150);
1047}
1048
1049static void
1050TridentHideCursor(ScrnInfoPtr pScrn) {
1051    int vgaIOBase;
1052    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
1053    vgaIOBase = VGAHWPTR(pScrn)->IOBase;
1054
1055    OUTW(vgaIOBase + 4, 0x4150);
1056}
1057
1058static void
1059TridentSetCursorPosition(ScrnInfoPtr pScrn, int x, int y)
1060{
1061    int vgaIOBase;
1062    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
1063    vgaIOBase = VGAHWPTR(pScrn)->IOBase;
1064
1065    if (x < 0) {
1066    	OUTW(vgaIOBase + 4, (-x)<<8 | 0x46);
1067	x = 0;
1068    } else
1069    	OUTW(vgaIOBase + 4, 0x0046);
1070
1071    if (y < 0) {
1072    	OUTW(vgaIOBase + 4, (-y)<<8 | 0x47);
1073	y = 0;
1074    } else
1075    	OUTW(vgaIOBase + 4, 0x0047);
1076
1077    OUTW(vgaIOBase + 4, (x&0xFF)<<8 | 0x40);
1078    OUTW(vgaIOBase + 4, (x&0x0F00)  | 0x41);
1079    OUTW(vgaIOBase + 4, (y&0xFF)<<8 | 0x42);
1080    OUTW(vgaIOBase + 4, (y&0x0F00)  | 0x43);
1081}
1082
1083static void
1084TridentSetCursorColors(ScrnInfoPtr pScrn, int bg, int fg)
1085{
1086    int vgaIOBase;
1087    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
1088    vgaIOBase = VGAHWPTR(pScrn)->IOBase;
1089    OUTW(vgaIOBase + 4, (fg & 0x000000FF)<<8  | 0x48);
1090    OUTW(vgaIOBase + 4, (fg & 0x0000FF00)     | 0x49);
1091    OUTW(vgaIOBase + 4, (fg & 0x00FF0000)>>8  | 0x4A);
1092    OUTW(vgaIOBase + 4, (fg & 0xFF000000)>>16 | 0x4B);
1093    OUTW(vgaIOBase + 4, (bg & 0x000000FF)<<8  | 0x4C);
1094    OUTW(vgaIOBase + 4, (bg & 0x0000FF00)     | 0x4D);
1095    OUTW(vgaIOBase + 4, (bg & 0x00FF0000)>>8  | 0x4E);
1096    OUTW(vgaIOBase + 4, (bg & 0xFF000000)>>16 | 0x4F);
1097}
1098
1099static void
1100TridentLoadCursorImage(
1101    ScrnInfoPtr pScrn,
1102    CARD8 *src
1103)
1104{
1105    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
1106    int vgaIOBase;
1107    int programmed_offset = pTrident->CursorOffset / 1024;
1108    vgaIOBase = VGAHWPTR(pScrn)->IOBase;
1109
1110    memcpy((CARD8 *)pTrident->FbBase + pTrident->CursorOffset,
1111			src, pTrident->CursorInfoRec->MaxWidth *
1112			pTrident->CursorInfoRec->MaxHeight / 4);
1113
1114    OUTW(vgaIOBase + 4, ((programmed_offset & 0xFF) << 8) | 0x44);
1115    OUTW(vgaIOBase + 4, (programmed_offset & 0xFF00) | 0x45);
1116}
1117
1118static Bool
1119TridentUseHWCursor(ScreenPtr pScreen, CursorPtr pCurs)
1120{
1121    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
1122    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
1123
1124    if (pTrident->MUX && pScrn->bitsPerPixel == 8) return FALSE;
1125
1126    if (!pTrident->HWCursor) return FALSE;
1127
1128    return TRUE;
1129}
1130
1131#define CURSOR_WIDTH 64
1132#define CURSOR_HEIGHT 64
1133#define CURSOR_ALIGN(x,bytes) (((x) + ((bytes) - 1)) & ~((bytes) - 1))
1134
1135Bool
1136TridentHWCursorInit(ScreenPtr pScreen)
1137{
1138    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
1139    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
1140    xf86CursorInfoPtr infoPtr;
1141    FBAreaPtr          fbarea;
1142    int                width;
1143    int		       width_bytes;
1144    int                height;
1145    int                size_bytes;
1146
1147    size_bytes                = CURSOR_WIDTH * 4 * CURSOR_HEIGHT;
1148    width                     = pScrn->displayWidth;
1149    width_bytes		      = width * (pScrn->bitsPerPixel / 8);
1150    height                    = (size_bytes + width_bytes - 1) / width_bytes;
1151    fbarea                    = xf86AllocateOffscreenArea(pScreen,
1152							  width,
1153							  height,
1154							  1024,
1155							  NULL,
1156							  NULL,
1157							  NULL);
1158
1159    if (!fbarea) {
1160	pTrident->CursorOffset = 0;
1161	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1162		   "Hardware cursor disabled"
1163		   " due to insufficient offscreen memory\n");
1164	return FALSE;
1165    } else {
1166	pTrident->CursorOffset = CURSOR_ALIGN((fbarea->box.x1 +
1167					       fbarea->box.y1 * width) *
1168					       pScrn->bitsPerPixel / 8,
1169					       1024);
1170    }
1171
1172    if ((pTrident->Chipset != CYBER9397DVD) &&
1173      			    (pTrident->Chipset < CYBERBLADEE4)) {
1174	/* Can't deal with an offset more than 4MB - 4096 bytes */
1175	if (pTrident->CursorOffset >= ((4096*1024) - 4096)) {
1176	    pTrident->CursorOffset = 0;
1177    	    xf86FreeOffscreenArea(fbarea);
1178	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1179		   "Hardware cursor disabled"
1180		   " due to cursor offset constraints.\n");
1181		return FALSE;
1182	}
1183    }
1184
1185    infoPtr = xf86CreateCursorInfoRec();
1186    if(!infoPtr) return FALSE;
1187
1188    pTrident->CursorInfoRec = infoPtr;
1189
1190    infoPtr->MaxWidth = 64;
1191    infoPtr->MaxHeight = 64;
1192    infoPtr->Flags = HARDWARE_CURSOR_BIT_ORDER_MSBFIRST |
1193		HARDWARE_CURSOR_SWAP_SOURCE_AND_MASK |
1194		HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_32 |
1195                ((pTrident->Chipset == CYBERBLADEXP4 ||
1196                  pTrident->Chipset == BLADEXP ||
1197                  pTrident->Chipset == XP5 ||
1198                  pTrident->Chipset == CYBERBLADEE4) ?
1199                HARDWARE_CURSOR_TRUECOLOR_AT_8BPP : 0);
1200    infoPtr->SetCursorColors = TridentSetCursorColors;
1201    infoPtr->SetCursorPosition = TridentSetCursorPosition;
1202    infoPtr->LoadCursorImage = TridentLoadCursorImage;
1203    infoPtr->HideCursor = TridentHideCursor;
1204    infoPtr->ShowCursor = TridentShowCursor;
1205    infoPtr->UseHWCursor = TridentUseHWCursor;
1206
1207    return(xf86InitCursor(pScreen, infoPtr));
1208}
1209
1210unsigned int
1211Tridentddc1Read(ScrnInfoPtr pScrn)
1212{
1213    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
1214    int vgaIOBase = VGAHWPTR(pScrn)->IOBase;
1215    CARD8 temp;
1216
1217    /* New mode */
1218    OUTB(0x3C4, 0x0B); temp = INB(0x3C5);
1219
1220    OUTB(0x3C4, NewMode1);
1221    temp = INB(0x3C5);
1222    OUTB(0x3C5, temp | 0x80);
1223
1224    /* Define SDA as input */
1225    OUTW(vgaIOBase + 4, (0x04 << 8) | I2C);
1226
1227    OUTW(0x3C4, (temp << 8) | NewMode1);
1228
1229    /* Wait until vertical retrace is in progress. */
1230    while (INB(vgaIOBase + 0xA) & 0x08);
1231    while (!(INB(vgaIOBase + 0xA) & 0x08));
1232
1233    /* Get the result */
1234    OUTB(vgaIOBase + 4, I2C);
1235    return ( INB(vgaIOBase + 5) & 0x01 );
1236}
1237
1238void TridentSetOverscan(
1239    ScrnInfoPtr pScrn,
1240    int overscan
1241){
1242    vgaHWPtr hwp = VGAHWPTR(pScrn);
1243
1244    if (overscan < 0 || overscan > 255)
1245	return;
1246
1247    hwp->enablePalette(hwp);
1248    hwp->writeAttr(hwp, OVERSCAN, overscan);
1249    hwp->disablePalette(hwp);
1250}
1251
1252void TridentLoadPalette(
1253    ScrnInfoPtr pScrn,
1254    int numColors,
1255    int *indicies,
1256    LOCO *colors,
1257    VisualPtr pVisual
1258){
1259    vgaHWPtr hwp = VGAHWPTR(pScrn);
1260    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
1261    int i, index;
1262    for(i = 0; i < numColors; i++) {
1263	index = indicies[i];
1264    	OUTB(0x3C6, 0xFF);
1265	DACDelay(hwp);
1266        OUTB(0x3c8, index);
1267	DACDelay(hwp);
1268        OUTB(0x3c9, colors[index].red);
1269	DACDelay(hwp);
1270        OUTB(0x3c9, colors[index].green);
1271	DACDelay(hwp);
1272        OUTB(0x3c9, colors[index].blue);
1273	DACDelay(hwp);
1274    }
1275}
1276