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