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