mga_dac3026.c revision 4a32b415
1/*
2 * Copyright 1994 by Robin Cutshaw <robin@XFree86.org>
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 Robin Cutshaw not be used in
9 * advertising or publicity pertaining to distribution of the software without
10 * specific, written prior permission.  Robin Cutshaw 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 * ROBIN CUTSHAW DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL ROBIN CUTSHAW 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 *
23 * Modified for TVP3026 by Harald Koenig <koenig@tat.physik.uni-tuebingen.de>
24 *
25 * Modified for MGA Millennium by Xavier Ducoin <xavier@rd.lectra.fr>
26 *
27 * Doug Merritt <doug@netcom.com>
28 * 24bpp: fixed high res stripe glitches, clock glitches on all res
29 *
30 */
31
32#ifdef HAVE_CONFIG_H
33#include "config.h"
34#endif
35
36/*
37 * This is a first cut at a non-accelerated version to work with the
38 * new server design (DHD).
39 */
40
41/* All drivers should typically include these */
42#include "xorg-server.h"
43#include "xf86.h"
44#include "xf86_OSproc.h"
45
46/* Drivers that need to access the PCI config space directly need this */
47#include "xf86Pci.h"
48
49#include "mga_reg.h"
50#include "mga.h"
51#include "mga_macros.h"
52
53#include "xf86DDC.h"
54
55/*
56 * Only change these bits in the Option register.  Make sure that the
57 * vgaioen bit is never in this mask because it is controlled elsewhere
58 */
59#define OPTION_MASK 0xFFEFFEFF	/* ~(eepromwt | vgaioen) */
60
61static void MGA3026LoadPalette(ScrnInfoPtr, int, int*, LOCO*, VisualPtr);
62static void MGA3026SavePalette(ScrnInfoPtr, unsigned char*);
63static void MGA3026RestorePalette(ScrnInfoPtr, unsigned char*);
64static void MGA3026RamdacInit(ScrnInfoPtr);
65static void MGA3026Save(ScrnInfoPtr, vgaRegPtr, MGARegPtr, Bool);
66static void MGA3026Restore(ScrnInfoPtr, vgaRegPtr, MGARegPtr, Bool);
67static Bool MGA3026Init(ScrnInfoPtr, DisplayModePtr);
68static Bool MGA3026_i2cInit(ScrnInfoPtr pScrn);
69
70
71/*
72 * implementation
73 */
74
75/*
76 * indexes to ti3026 registers (the order is important)
77 */
78const static unsigned char MGADACregs[] = {
79	0x0F, 0x18, 0x19, 0x1A, 0x1C,   0x1D, 0x1E, 0x2A, 0x2B, 0x30,
80	0x31, 0x32, 0x33, 0x34, 0x35,   0x36, 0x37, 0x38, 0x39, 0x3A,
81	0x06
82};
83
84/* note: to fix a cursor hw glitch, register 0x37 (blue color key) needs
85   to be set to magic numbers, even though they are "never" used because
86   blue keying disabled in 0x38.
87
88   Matrox sez:
89
90   ...The more precise statement of the software workaround is to insure
91   that bits 7-5 of register 0x37 (Blue Color Key High) and bits 7-5 of
92   register 0x38 (HZOOM)are the same...
93*/
94
95/* also note: the values of the MUX control register 0x19 (index [2]) can be
96   found in table 2-17 of the 3026 manual. If interlace is set, the values
97   listed here are incremented by one.
98*/
99
100#define DACREGSIZE sizeof(MGADACregs)
101/*
102 * initial values of ti3026 registers
103 */
104const static unsigned char MGADACbpp8[DACREGSIZE] = {
105	0x06, 0x80, 0x4b, 0x25, 0x00,   0x00, 0x0C, 0x00, 0x1E, 0xFF,
106	0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   0xFF, 0x00, 0x00,    0, 0x00,
107	0x00
108};
109const static unsigned char MGADACbpp16[DACREGSIZE] = {
110	0x07, 0x45, 0x53, 0x15, 0x00,   0x00, 0x2C, 0x00, 0x1E, 0xFF,
111	0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   0xFF, 0x00, 0x10,    0, 0x00,
112	0x00
113};
114/*
115 * [0] value was 0x07, but changed to 0x06 by Doug Merrit to fix high res
116 * stripe glitches and clock glitches at 24bpp.
117 */
118/* [0] value is now set inside of MGA3026Init, based on the silicon revision
119   It is still set to 7 or 6 based on the revision, though, since setting to
120   8 as in the documentation makes (some?) revB chips get the colors wrong...
121   maybe BGR instead of RGB? This only applies to 24bpp, since it is the only
122   one documented as depending on revision.
123 */
124
125const static unsigned char MGADACbpp24[DACREGSIZE] = {
126	0x06, 0x56, 0x5b, 0x25, 0x00,   0x00, 0x2C, 0x00, 0x1E, 0xFF,
127	0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   0xFF, 0x00, 0x10,    0, 0x00,
128	0x00
129};
130const static unsigned char MGADACbpp32[DACREGSIZE] = {
131	0x07, 0x46, 0x5b, 0x05, 0x00,   0x00, 0x2C, 0x00, 0x1E, 0xFF,
132	0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   0xFF, 0x00, 0x10,    0, 0x00,
133	0x00
134};
135
136
137/*
138 * Read/write to the DAC via MMIO
139 */
140
141/*
142 * These were functions.  Use macros instead to avoid the need to
143 * pass pMga to them.
144 */
145
146#define inTi3026dreg(reg) INREG8(RAMDAC_OFFSET + (reg))
147
148#define outTi3026dreg(reg, val) OUTREG8(RAMDAC_OFFSET + (reg), val)
149
150#define inTi3026(reg) \
151	(outTi3026dreg(TVP3026_INDEX, reg), inTi3026dreg(TVP3026_DATA))
152
153#define outTi3026(reg, mask, val) \
154	do { /* note: mask and reg may get evaluated twice */ \
155	    unsigned char tmp = (mask) ? (inTi3026(reg) & (mask)) : 0; \
156	    outTi3026dreg(TVP3026_INDEX, reg); \
157	    outTi3026dreg(TVP3026_DATA, tmp | (val)); \
158	} while (0)
159
160
161/*
162 * MGATi3026CalcClock - Calculate the PLL settings (m, n, p).
163 *
164 * DESCRIPTION
165 *   For more information, refer to the Texas Instruments
166 *   "TVP3026 Data Manual" (document SLAS098B).
167 *     Section 2.4 "PLL Clock Generators"
168 *     Appendix A "Frequency Synthesis PLL Register Settings"
169 *     Appendix B "PLL Programming Examples"
170 *
171 * PARAMETERS
172 *   f_out		IN	Desired clock frequency.
173 *   f_max		IN	Maximum allowed clock frequency.
174 *   m			OUT	Value of PLL 'm' register.
175 *   n			OUT	Value of PLL 'n' register.
176 *   p			OUT	Value of PLL 'p' register.
177 *
178 * HISTORY
179 *   January 11, 1997 - [aem] Andrew E. Mileski
180 *   Split off from MGATi3026SetClock.
181 */
182
183/* The following values are in kHz */
184#define TI_MIN_VCO_FREQ  110000
185#define TI_MAX_VCO_FREQ  220000
186#define TI_MAX_MCLK_FREQ 100000
187#define TI_REF_FREQ      14318.18
188
189static double
190MGATi3026CalcClock (
191   long f_out, long f_max,
192   int *m, int *n, int *p
193){
194	int best_m = 0, best_n = 0;
195	double f_pll, f_vco;
196	double m_err, inc_m, calc_m;
197
198	/* Make sure that f_min <= f_out <= f_max */
199	if ( f_out < ( TI_MIN_VCO_FREQ / 8 ))
200		f_out = TI_MIN_VCO_FREQ / 8;
201	if ( f_out > f_max )
202		f_out = f_max;
203
204	/*
205	 * f_pll = f_vco / 2 ^ p
206	 * Choose p so that TI_MIN_VCO_FREQ <= f_vco <= TI_MAX_VCO_FREQ
207	 * Note that since TI_MAX_VCO_FREQ = 2 * TI_MIN_VCO_FREQ
208	 * we don't have to bother checking for this maximum limit.
209	 */
210	f_vco = ( double ) f_out;
211	for ( *p = 0; *p < 3 && f_vco < TI_MIN_VCO_FREQ; ( *p )++ )
212		f_vco *= 2.0;
213
214	/*
215	 * We avoid doing multiplications by ( 65 - n ),
216	 * and add an increment instead - this keeps any error small.
217	 */
218	inc_m = f_vco / ( TI_REF_FREQ * 8.0 );
219
220	/* Initial value of calc_m for the loop */
221	calc_m = inc_m + inc_m + inc_m;
222
223	/* Initial amount of error for an integer - impossibly large */
224	m_err = 2.0;
225
226	/* Search for the closest INTEGER value of ( 65 - m ) */
227	for ( *n = 3; *n <= 25; ( *n )++, calc_m += inc_m ) {
228
229		/* Ignore values of ( 65 - m ) which we can't use */
230		if ( calc_m < 3.0 || calc_m > 64.0 )
231			continue;
232
233		/*
234		 * Pick the closest INTEGER (has smallest fractional part).
235		 * The optimizer should clean this up for us.
236		 */
237		if (( calc_m - ( int ) calc_m ) < m_err ) {
238			m_err = calc_m - ( int ) calc_m;
239			best_m = ( int ) calc_m;
240			best_n = *n;
241		}
242	}
243
244	/* 65 - ( 65 - x ) = x */
245	*m = 65 - best_m;
246	*n = 65 - best_n;
247
248	/* Now all the calculations can be completed */
249	f_vco = 8.0 * TI_REF_FREQ * best_m / best_n;
250	f_pll = f_vco / ( 1 << *p );
251
252#ifdef DEBUG
253	ErrorF( "f_out=%ld f_pll=%.1f f_vco=%.1f n=%d m=%d p=%d\n",
254		f_out, f_pll, f_vco, *n, *m, *p );
255#endif
256
257	return f_pll;
258}
259
260/*
261 * MGATi3026SetMCLK - Set the memory clock (MCLK) PLL.
262 *
263 * HISTORY
264 *   January 11, 1997 - [aem] Andrew E. Mileski
265 *   Written and tested.
266 */
267static void
268MGATi3026SetMCLK( ScrnInfoPtr pScrn, long f_out )
269{
270	int mclk_m, mclk_n, mclk_p;
271	int pclk_m, pclk_n, pclk_p;
272	int mclk_ctl;
273	MGAPtr pMga = MGAPTR(pScrn);
274
275	MGATi3026CalcClock(f_out, TI_MAX_MCLK_FREQ, &mclk_m, &mclk_n, &mclk_p);
276
277	/* Save PCLK settings */
278	outTi3026( TVP3026_PLL_ADDR, 0, 0xfc );
279	pclk_n = inTi3026( TVP3026_PIX_CLK_DATA );
280	outTi3026( TVP3026_PLL_ADDR, 0, 0xfd );
281	pclk_m = inTi3026( TVP3026_PIX_CLK_DATA );
282	outTi3026( TVP3026_PLL_ADDR, 0, 0xfe );
283	pclk_p = inTi3026( TVP3026_PIX_CLK_DATA );
284
285	/* Stop PCLK (PLLEN = 0, PCLKEN = 0) */
286	outTi3026( TVP3026_PLL_ADDR, 0, 0xfe );
287	outTi3026( TVP3026_PIX_CLK_DATA, 0, 0x00 );
288
289	/* Set PCLK to the new MCLK frequency (PLLEN = 1, PCLKEN = 0 ) */
290	outTi3026( TVP3026_PLL_ADDR, 0, 0xfc );
291	outTi3026( TVP3026_PIX_CLK_DATA, 0, ( mclk_n & 0x3f ) | 0xc0 );
292	outTi3026( TVP3026_PIX_CLK_DATA, 0, mclk_m & 0x3f );
293	outTi3026( TVP3026_PIX_CLK_DATA, 0, ( mclk_p & 0x03 ) | 0xb0 );
294
295	/* Wait for PCLK PLL to lock on frequency */
296	while (( inTi3026( TVP3026_PIX_CLK_DATA ) & 0x40 ) == 0 ) {
297		;
298	}
299
300	/* Output PCLK on MCLK pin */
301	mclk_ctl = inTi3026( TVP3026_MCLK_CTL );
302	outTi3026( TVP3026_MCLK_CTL, 0, mclk_ctl & 0xe7 );
303	outTi3026( TVP3026_MCLK_CTL, 0, ( mclk_ctl & 0xe7 ) | 0x08 );
304
305	/* Stop MCLK (PLLEN = 0 ) */
306	outTi3026( TVP3026_PLL_ADDR, 0, 0xfb );
307	outTi3026( TVP3026_MEM_CLK_DATA, 0, 0x00 );
308
309	/* Set MCLK to the new frequency (PLLEN = 1) */
310	outTi3026( TVP3026_PLL_ADDR, 0, 0xf3 );
311	outTi3026( TVP3026_MEM_CLK_DATA, 0, ( mclk_n & 0x3f ) | 0xc0 );
312	outTi3026( TVP3026_MEM_CLK_DATA, 0, mclk_m & 0x3f );
313	outTi3026( TVP3026_MEM_CLK_DATA, 0, ( mclk_p & 0x03 ) | 0xb0 );
314
315	/* Wait for MCLK PLL to lock on frequency */
316	while (( inTi3026( TVP3026_MEM_CLK_DATA ) & 0x40 ) == 0 ) {
317		;
318	}
319
320	/* Output MCLK PLL on MCLK pin */
321	outTi3026( TVP3026_MCLK_CTL, 0, ( mclk_ctl & 0xe7 ) | 0x10 );
322	outTi3026( TVP3026_MCLK_CTL, 0, ( mclk_ctl & 0xe7 ) | 0x18 );
323
324	/* Stop PCLK (PLLEN = 0, PCLKEN = 0 ) */
325	outTi3026( TVP3026_PLL_ADDR, 0, 0xfe );
326	outTi3026( TVP3026_PIX_CLK_DATA, 0, 0x00 );
327
328	/* Restore PCLK (PLLEN = ?, PCLKEN = ?) */
329	outTi3026( TVP3026_PLL_ADDR, 0, 0xfc );
330	outTi3026( TVP3026_PIX_CLK_DATA, 0, pclk_n );
331	outTi3026( TVP3026_PIX_CLK_DATA, 0, pclk_m );
332	outTi3026( TVP3026_PIX_CLK_DATA, 0, pclk_p );
333
334	/* Wait for PCLK PLL to lock on frequency */
335	while (( inTi3026( TVP3026_PIX_CLK_DATA ) & 0x40 ) == 0 ) {
336		;
337	}
338}
339
340/*
341 * MGATi3026SetPCLK - Set the pixel (PCLK) and loop (LCLK) clocks.
342 *
343 * PARAMETERS
344 *   f_pll			IN	Pixel clock PLL frequencly in kHz.
345 *   bpp			IN	Bytes per pixel.
346 *
347 * HISTORY
348 *   January 11, 1997 - [aem] Andrew E. Mileski
349 *   Split to simplify code for MCLK (=GCLK) setting.
350 *
351 *   December 14, 1996 - [aem] Andrew E. Mileski
352 *   Fixed loop clock to be based on the calculated, not requested,
353 *   pixel clock. Added f_max = maximum f_vco frequency.
354 *
355 *   October 19, 1996 - [aem] Andrew E. Mileski
356 *   Commented the loop clock code (wow, I understand everything now),
357 *   and simplified it a bit. This should really be two separate functions.
358 *
359 *   October 1, 1996 - [aem] Andrew E. Mileski
360 *   Optimized the m & n picking algorithm. Added maxClock detection.
361 *   Low speed pixel clock fix (per the docs). Documented what I understand.
362 *
363 *   ?????, ??, ???? - [???] ????????????
364 *   Based on the TVP3026 code in the S3 driver.
365 */
366
367static void
368MGATi3026SetPCLK( ScrnInfoPtr pScrn, long f_out, int bpp )
369{
370	/* Pixel clock values */
371	int m, n, p;
372
373	/* Loop clock values */
374	int lm, ln, lp, lq;
375	double z;
376
377	/* The actual frequency output by the clock */
378	double f_pll;
379
380	long f_max = TI_MAX_VCO_FREQ;
381
382	MGAPtr pMga = MGAPTR(pScrn);
383	MGARegPtr pReg = &pMga->ModeReg;
384
385	/* Get the maximum pixel clock frequency */
386	if ( pMga->MaxClock > TI_MAX_VCO_FREQ )
387		f_max = pMga->MaxClock;
388
389	/* Do the calculations for m, n, and p */
390	f_pll = MGATi3026CalcClock( f_out, f_max, & m, & n, & p );
391
392	/* Values for the pixel clock PLL registers */
393	pReg->DacClk[ 0 ] = ( n & 0x3f ) | 0xc0;
394	pReg->DacClk[ 1 ] = ( m & 0x3f );
395	pReg->DacClk[ 2 ] = ( p & 0x03 ) | 0xb0;
396
397	/*
398	 * Now that the pixel clock PLL is setup,
399	 * the loop clock PLL must be setup.
400	 */
401
402	/*
403	 * First we figure out lm, ln, and z.
404	 * Things are different in packed pixel mode (24bpp) though.
405	 */
406	 if ( pMga->CurrentLayout.bitsPerPixel == 24 ) {
407
408		/* ln:lm = ln:3 */
409		lm = 65 - 3;
410
411		/* Check for interleaved mode */
412		if ( bpp == 2 )
413			/* ln:lm = 4:3 */
414			ln = 65 - 4;
415		else
416			/* ln:lm = 8:3 */
417			ln = 65 - 8;
418
419		/* Note: this is actually 100 * z for more precision */
420		z = ( 11000 * ( 65 - ln )) / (( f_pll / 1000 ) * ( 65 - lm ));
421	}
422	else {
423		/* ln:lm = ln:4 */
424		lm = 65 - 4;
425
426		/* Note: bpp = bytes per pixel */
427		ln = 65 - 4 * ( 64 / 8 ) / bpp;
428
429		/* Note: this is actually 100 * z for more precision */
430		z = (( 11000 / 4 ) * ( 65 - ln )) / ( f_pll / 1000 );
431	}
432
433	/*
434	 * Now we choose dividers lp and lq so that the VCO frequency
435	 * is within the operating range of 110 MHz to 220 MHz.
436	 */
437
438	/* Assume no lq divider */
439	lq = 0;
440
441	/* Note: z is actually 100 * z for more precision */
442	if ( z <= 200.0 )
443		lp = 0;
444	else if ( z <= 400.0 )
445		lp = 1;
446	else if ( z <= 800.0 )
447		lp = 2;
448	else if ( z <= 1600.0 )
449		lp = 3;
450	else {
451		lp = 3;
452		lq = ( int )( z / 1600.0 );
453	}
454
455	/* Values for the loop clock PLL registers */
456	if ( pMga->CurrentLayout.bitsPerPixel == 24 ) {
457		/* Packed pixel mode values */
458		pReg->DacClk[ 3 ] = ( ln & 0x3f ) | 0x80;
459		pReg->DacClk[ 4 ] = ( lm & 0x3f ) | 0x80;
460		pReg->DacClk[ 5 ] = ( lp & 0x03 ) | 0xf8;
461 	} else {
462		/* Non-packed pixel mode values */
463		pReg->DacClk[ 3 ] = ( ln & 0x3f ) | 0xc0;
464		pReg->DacClk[ 4 ] = ( lm & 0x3f );
465		pReg->DacClk[ 5 ] = ( lp & 0x03 ) | 0xf0;
466	}
467	pReg->DacRegs[ 18 ] = lq | 0x38;
468
469#ifdef DEBUG
470	ErrorF( "bpp=%d z=%.1f ln=%d lm=%d lp=%d lq=%d\n",
471		bpp, z, ln, lm, lp, lq );
472#endif
473}
474
475/*
476 * MGA3026Init -- for mga2064 with ti3026
477 *
478 * The 'mode' parameter describes the video mode.	The 'mode' structure
479 * as well as the 'vga256InfoRec' structure can be dereferenced for
480 * information that is needed to initialize the mode.	The 'new' macro
481 * (see definition above) is used to simply fill in the structure.
482 */
483static Bool
484MGA3026Init(ScrnInfoPtr pScrn, DisplayModePtr mode)
485{
486	int hd, hs, he, ht, vd, vs, ve, vt, wd;
487	int i, BppShift, index_1d = 0;
488	const unsigned char* initDAC;
489	MGAPtr pMga = MGAPTR(pScrn);
490	MGARamdacPtr MGAdac = &pMga->Dac;
491	MGAFBLayout *pLayout = &pMga->CurrentLayout;
492	MGARegPtr pReg = &pMga->ModeReg;
493	vgaRegPtr pVga = &VGAHWPTR(pScrn)->ModeReg;
494
495	BppShift = pMga->BppShifts[(pLayout->bitsPerPixel >> 3) - 1];
496
497	switch(pLayout->bitsPerPixel)
498	{
499	case 8:
500		initDAC = MGADACbpp8;
501		break;
502	case 16:
503		initDAC = MGADACbpp16;
504		break;
505	case 24:
506		initDAC = MGADACbpp24;
507		break;
508	case 32:
509	    initDAC = MGADACbpp32;
510	    break;
511	default:
512		FatalError("MGA: unsupported bits per pixel\n");
513	}
514
515	/* Allocate the DacRegs space if not done already */
516	if (pReg->DacRegs == NULL) {
517		pReg->DacRegs = xnfcalloc(DACREGSIZE, 1);
518	}
519	for (i = 0; i < DACREGSIZE; i++) {
520	    pReg->DacRegs[i] = initDAC[i];
521	    if (MGADACregs[i] == 0x1D)
522		index_1d = i;
523	}
524
525	if ( (pLayout->bitsPerPixel == 16) && (pLayout->weight.red == 5)
526	    && (pLayout->weight.green == 5) && (pLayout->weight.blue == 5) ) {
527	    pReg->DacRegs[1] &= ~0x01;
528	}
529	if (pMga->Interleave ) 	pReg->DacRegs[2] += 1;
530
531
532	if ( pLayout->bitsPerPixel == 24 ) {
533	  int silicon_rev;
534	  /* we need to set DacRegs[0] differently based on the silicon
535	   * revision of the 3026 RAMDAC, as per page 2-14 of tvp3026.pdf.
536	   * If we have rev A silicon, we want 0x07; rev B silicon wants
537	   * 0x06.
538	   */
539	  silicon_rev = inTi3026(TVP3026_SILICON_REV);
540
541#ifdef DEBUG
542	    ErrorF("TVP3026 revision 0x%x (rev %s)\n",
543		   silicon_rev, (silicon_rev <= 0x20) ? "A" : "B");
544#endif
545
546	    if(silicon_rev <= 0x20) {
547	      /* rev A */
548	      pReg->DacRegs[0] = 0x07;
549	    } else {
550	      /* rev B */
551	      pReg->DacRegs[0] = 0x06;
552	    }
553	}
554
555	/*
556	 * This will initialize all of the generic VGA registers.
557	 */
558	if (!vgaHWInit(pScrn, mode))
559		return(FALSE);
560
561	/*
562	 * Here all of the MGA registers get filled in.
563	 */
564	hd = (mode->CrtcHDisplay	>> 3)	- 1;
565	hs = (mode->CrtcHSyncStart	>> 3)	- 1;
566	he = (mode->CrtcHSyncEnd	>> 3)	- 1;
567	ht = (mode->CrtcHTotal		>> 3)	- 1;
568	vd = mode->CrtcVDisplay			- 1;
569	vs = mode->CrtcVSyncStart		- 1;
570	ve = mode->CrtcVSyncEnd			- 1;
571	vt = mode->CrtcVTotal			- 2;
572
573        /* HTOTAL & 0x7 equal to 0x6 in 8bpp or 0x4 in 24bpp causes strange
574         * vertical stripes
575         */
576        if((ht & 0x07) == 0x06 || (ht & 0x07) == 0x04)
577                ht++;
578
579        if (pLayout->bitsPerPixel == 24)
580		wd = (pLayout->displayWidth * 3) >> (4 - BppShift);
581	else
582		wd = pLayout->displayWidth >> (4 - BppShift);
583
584	pReg->ExtVga[0] = 0;
585	pReg->ExtVga[5] = 0;
586
587	if (mode->Flags & V_INTERLACE)
588	{
589		pReg->ExtVga[0] = 0x80;
590		pReg->ExtVga[5] = (hs + he - ht) >> 1;
591		wd <<= 1;
592		vt &= 0xFFFE;
593
594		/* enable interlaced cursor */
595		pReg->DacRegs[20] |= 0x20;
596	}
597
598	pReg->ExtVga[0]	|= (wd & 0x300) >> 4;
599	pReg->ExtVga[1]	= (((ht - 4) & 0x100) >> 8) |
600				((hd & 0x100) >> 7) |
601				((hs & 0x100) >> 6) |
602				(ht & 0x40);
603	pReg->ExtVga[2]	= ((vt & 0xc00) >> 10) |
604				((vd & 0x400) >> 8) |
605				((vd & 0xc00) >> 7) |
606				((vs & 0xc00) >> 5);
607	if (pLayout->bitsPerPixel == 24)
608		pReg->ExtVga[3]	= (((1 << BppShift) * 3) - 1) | 0x80;
609	else
610		pReg->ExtVga[3]	= ((1 << BppShift) - 1) | 0x80;
611
612	/* Set viddelay (CRTCEXT3 Bits 3-4). */
613	pReg->ExtVga[3] |= (pScrn->videoRam == 8192 ? 0x10
614			     : pScrn->videoRam == 2048 ? 0x08 : 0x00);
615
616	pReg->ExtVga[4]	= 0;
617
618	pVga->CRTC[0]	= ht - 4;
619	pVga->CRTC[1]	= hd;
620	pVga->CRTC[2]	= hd;
621	pVga->CRTC[3]	= (ht & 0x1F) | 0x80;
622	pVga->CRTC[4]	= hs;
623	pVga->CRTC[5]	= ((ht & 0x20) << 2) | (he & 0x1F);
624	pVga->CRTC[6]	= vt & 0xFF;
625	pVga->CRTC[7]	= ((vt & 0x100) >> 8 ) |
626				((vd & 0x100) >> 7 ) |
627				((vs & 0x100) >> 6 ) |
628				((vd & 0x100) >> 5 ) |
629				0x10 |
630				((vt & 0x200) >> 4 ) |
631				((vd & 0x200) >> 3 ) |
632				((vs & 0x200) >> 2 );
633	pVga->CRTC[9]	= ((vd & 0x200) >> 4) | 0x40;
634	pVga->CRTC[16] = vs & 0xFF;
635	pVga->CRTC[17] = (ve & 0x0F) | 0x20;
636	pVga->CRTC[18] = vd & 0xFF;
637	pVga->CRTC[19] = wd & 0xFF;
638	pVga->CRTC[21] = vd & 0xFF;
639	pVga->CRTC[22] = (vt + 1) & 0xFF;
640
641	if (mode->Flags & V_DBLSCAN)
642		pVga->CRTC[9] |= 0x80;
643
644	/* Per DDK vid.c line 75, sync polarity should be controlled
645	 * via the TVP3026 RAMDAC register 1D and so MISC Output Register
646	 * should always have bits 6 and 7 set. */
647
648	pVga->MiscOutReg |= 0xC0;
649	if ((mode->Flags & (V_PHSYNC | V_NHSYNC)) &&
650	    (mode->Flags & (V_PVSYNC | V_NVSYNC)))
651	{
652	    if (mode->Flags & V_PHSYNC)
653		pReg->DacRegs[index_1d] |= 0x01;
654	    if (mode->Flags & V_PVSYNC)
655		pReg->DacRegs[index_1d] |= 0x02;
656	}
657	else
658	{
659	  int VDisplay = mode->VDisplay;
660	  if (mode->Flags & V_DBLSCAN)
661	    VDisplay *= 2;
662	  if      (VDisplay < 400)
663		  pReg->DacRegs[index_1d] |= 0x01; /* +hsync -vsync */
664	  else if (VDisplay < 480)
665		  pReg->DacRegs[index_1d] |= 0x02; /* -hsync +vsync */
666	  else if (VDisplay < 768)
667		  pReg->DacRegs[index_1d] |= 0x00; /* -hsync -vsync */
668	  else
669		  pReg->DacRegs[index_1d] |= 0x03; /* +hsync +vsync */
670	}
671
672	if (pMga->SyncOnGreen)
673	    pReg->DacRegs[index_1d] |= 0x20;
674
675	pReg->Option = 0x402C0100;  /* fine for 2064 and 2164 */
676
677	if (pMga->Interleave)
678	  pReg->Option |= 0x1000;
679	else
680	  pReg->Option &= ~0x1000;
681
682	/* must always have the pci retries on but rely on
683	   polling to keep them from occuring */
684	pReg->Option &= ~0x20000000;
685
686	pVga->MiscOutReg |= 0x0C;
687	/* XXX Need to check the first argument */
688	MGATi3026SetPCLK( pScrn, mode->Clock, 1 << BppShift );
689
690	/* this one writes registers rather than writing to the
691	   mgaReg->ModeReg and letting Restore write to the hardware
692	   but that's no big deal since we will Restore right after
693	   this function */
694
695	MGA_NOT_HAL(MGATi3026SetMCLK(pScrn, MGAdac->MemoryClock));
696
697#ifdef DEBUG
698	ErrorF("%6ld: %02X %02X %02X	%02X %02X %02X	%08lX\n", mode->Clock,
699		pReg->DacClk[0], pReg->DacClk[1], pReg->DacClk[2], pReg->DacClk[3], pReg->DacClk[4], pReg->DacClk[5], pReg->Option);
700	for (i=0; i<sizeof(MGADACregs); i++) ErrorF("%02X ", pReg->DacRegs[i]);
701	for (i=0; i<6; i++) ErrorF(" %02X", pReg->ExtVga[i]);
702	ErrorF("\n");
703#endif
704
705	/* This disables the VGA memory aperture */
706	pVga->MiscOutReg &= ~0x02;
707	return(TRUE);
708}
709
710/*
711 * MGA3026Restore -- for mga2064 with ti3026
712 *
713 * This function restores a video mode.	 It basically writes out all of
714 * the registers that have previously been saved in the vgaMGARec data
715 * structure.
716 */
717static void
718MGA3026Restore(ScrnInfoPtr pScrn, vgaRegPtr vgaReg, MGARegPtr mgaReg,
719	       Bool restoreFonts)
720{
721	int i;
722	MGAPtr pMga = MGAPTR(pScrn);
723
724	/*
725	 * Code is needed to get things back to bank zero.
726	 */
727	for (i = 0; i < 6; i++)
728		OUTREG16(0x1FDE, (mgaReg->ExtVga[i] << 8) | i);
729
730#ifdef XSERVER_LIBPCIACCESS
731	pci_device_cfg_write_bits(pMga->PciInfo, OPTION_MASK, mgaReg->Option,
732				  PCI_OPTION_REG);
733#else
734	pciSetBitsLong(pMga->PciTag, PCI_OPTION_REG, OPTION_MASK,
735		       mgaReg->Option);
736#endif
737
738	MGA_NOT_HAL(
739	/* select pixel clock PLL as clock source */
740	outTi3026(TVP3026_CLK_SEL, 0, mgaReg->DacRegs[3]);
741
742	/* set loop and pixel clock PLL PLLEN bits to 0 */
743	outTi3026(TVP3026_PLL_ADDR, 0, 0x2A);
744	outTi3026(TVP3026_LOAD_CLK_DATA, 0, 0);
745	outTi3026(TVP3026_PIX_CLK_DATA, 0, 0);
746	);	/* MGA_NOT_HAL */
747
748	/*
749	 * This function handles restoring the generic VGA registers.
750	 */
751	vgaHWRestore(pScrn, vgaReg,
752			VGA_SR_MODE | (restoreFonts ? VGA_SR_FONTS : 0));
753	MGA3026RestorePalette(pScrn, vgaReg->DAC);
754
755	/*
756	 * Code to restore SVGA registers that have been saved/modified
757	 * goes here.
758	 */
759
760	MGA_NOT_HAL(
761	/* program pixel clock PLL */
762	outTi3026(TVP3026_PLL_ADDR, 0, 0x00);
763	for (i = 0; i < 3; i++)
764		outTi3026(TVP3026_PIX_CLK_DATA, 0, mgaReg->DacClk[i]);
765
766	if (vgaReg->MiscOutReg & 0x08) {
767		/* poll until pixel clock PLL LOCK bit is set */
768		outTi3026(TVP3026_PLL_ADDR, 0, 0x3F);
769		while ( ! (inTi3026(TVP3026_PIX_CLK_DATA) & 0x40) );
770	}
771
772	/* set Q divider for loop clock PLL */
773	outTi3026(TVP3026_MCLK_CTL, 0, mgaReg->DacRegs[18]);
774	);	/* MGA_NOT_HAL */
775
776	/* program loop PLL */
777	outTi3026(TVP3026_PLL_ADDR, 0, 0x00);
778	for (i = 3; i < 6; i++)
779		outTi3026(TVP3026_LOAD_CLK_DATA, 0, mgaReg->DacClk[i]);
780
781	MGA_NOT_HAL(
782	if ((vgaReg->MiscOutReg & 0x08) && ((mgaReg->DacClk[3] & 0xC0) == 0xC0) ) {
783		/* poll until loop PLL LOCK bit is set */
784		outTi3026(TVP3026_PLL_ADDR, 0, 0x3F);
785		while ( ! (inTi3026(TVP3026_LOAD_CLK_DATA) & 0x40) );
786	}
787	);	/* MGA_NOT_HAL */
788
789	/*
790	 * restore other DAC registers
791	 */
792	for (i = 0; i < DACREGSIZE; i++)
793		outTi3026(MGADACregs[i], 0, mgaReg->DacRegs[i]);
794
795#ifdef DEBUG
796	ErrorF("PCI retry (0-enabled / 1-disabled): %d\n",
797		!!(mgaReg->Option & 0x20000000));
798#endif
799}
800
801/*
802 * MGA3026Save -- for mga2064 with ti3026
803 *
804 * This function saves the video state.
805 */
806static void
807MGA3026Save(ScrnInfoPtr pScrn, vgaRegPtr vgaReg, MGARegPtr mgaReg,
808	    Bool saveFonts)
809{
810	int i;
811	MGAPtr pMga = MGAPTR(pScrn);
812
813	/* Allocate the DacRegs space if not done already */
814	if (mgaReg->DacRegs == NULL) {
815		mgaReg->DacRegs = xnfcalloc(DACREGSIZE, 1);
816	}
817
818	/*
819	 * Code is needed to get back to bank zero.
820	 */
821	OUTREG16(0x1FDE, 0x0004);
822
823	/*
824	 * This function will handle creating the data structure and filling
825	 * in the generic VGA portion.
826	 */
827	vgaHWSave(pScrn, vgaReg, VGA_SR_MODE | (saveFonts ? VGA_SR_FONTS : 0));
828	MGA3026SavePalette(pScrn, vgaReg->DAC);
829
830	/*
831	 * The port I/O code necessary to read in the extended registers
832	 * into the fields of the vgaMGARec structure.
833	 */
834	for (i = 0; i < 6; i++)
835	{
836		OUTREG8(0x1FDE, i);
837		mgaReg->ExtVga[i] = INREG8(0x1FDF);
838	}
839
840	MGA_NOT_HAL(
841	outTi3026(TVP3026_PLL_ADDR, 0, 0x00);
842	for (i = 0; i < 3; i++)
843		outTi3026(TVP3026_PIX_CLK_DATA, 0, mgaReg->DacClk[i] =
844					inTi3026(TVP3026_PIX_CLK_DATA));
845
846	outTi3026(TVP3026_PLL_ADDR, 0, 0x00);
847	for (i = 3; i < 6; i++)
848		outTi3026(TVP3026_LOAD_CLK_DATA, 0, mgaReg->DacClk[i] =
849					inTi3026(TVP3026_LOAD_CLK_DATA));
850	);	/* MGA_NOT_HAL */
851
852	for (i = 0; i < DACREGSIZE; i++)
853		mgaReg->DacRegs[i]	 = inTi3026(MGADACregs[i]);
854
855#ifdef XSERVER_LIBPCIACCESS
856    {
857	uint32_t Option;
858	pci_device_cfg_read_u32(pMga->PciInfo, & Option,
859				PCI_OPTION_REG);
860        mgaReg->Option = Option;
861    }
862#else
863	mgaReg->Option = pciReadLong(pMga->PciTag, PCI_OPTION_REG);
864#endif
865
866#ifdef DEBUG
867	ErrorF("read: %02X %02X %02X	%02X %02X %02X	%08lX\n",
868		mgaReg->DacClk[0], mgaReg->DacClk[1], mgaReg->DacClk[2], mgaReg->DacClk[3], mgaReg->DacClk[4], mgaReg->DacClk[5], mgaReg->Option);
869	for (i=0; i<sizeof(MGADACregs); i++) ErrorF("%02X ", mgaReg->DacRegs[i]);
870	for (i=0; i<6; i++) ErrorF(" %02X", mgaReg->ExtVga[i]);
871	ErrorF("\n");
872#endif
873}
874
875
876static void
877MGA3026LoadCursorImage(
878    ScrnInfoPtr pScrn,
879    unsigned char *src
880)
881{
882    MGAPtr pMga = MGAPTR(pScrn);
883    int i = 1024;
884
885    outTi3026(TVP3026_CURSOR_CTL, 0xf3, 0x00); /* reset A9,A8 */
886    /* reset cursor RAM load address A7..A0 */
887    outTi3026dreg(TVP3026_WADR_PAL, 0x00);
888
889    while(i--) {
890	while (INREG8(0x1FDA) & 0x01);
891	while (!(INREG8(0x1FDA) & 0x01));
892        outTi3026dreg(TVP3026_CUR_RAM, *(src++));
893    }
894}
895
896
897static void
898MGA3026ShowCursor(ScrnInfoPtr pScrn)
899{
900    MGAPtr pMga = MGAPTR(pScrn);
901    /* Enable cursor - X11 mode */
902    outTi3026(TVP3026_CURSOR_CTL, 0x6c, 0x13);
903}
904
905static void
906MGA3026HideCursor(ScrnInfoPtr pScrn)
907{
908    MGAPtr pMga = MGAPTR(pScrn);
909    /* Disable cursor */
910    outTi3026(TVP3026_CURSOR_CTL, 0xfc, 0x00);
911}
912
913static void
914MGA3026SetCursorPosition(
915   ScrnInfoPtr pScrn,
916   int x, int y
917)
918{
919    MGAPtr pMga = MGAPTR(pScrn);
920    x += 64;
921    y += 64;
922
923    /* Output position - "only" 12 bits of location documented */
924
925    outTi3026dreg(TVP3026_CUR_XLOW, x & 0xFF);
926    outTi3026dreg(TVP3026_CUR_XHI, (x >> 8) & 0x0F);
927    outTi3026dreg(TVP3026_CUR_YLOW, y & 0xFF);
928    outTi3026dreg(TVP3026_CUR_YHI, (y >> 8) & 0x0F);
929}
930
931static void
932MGA3026SetCursorColors(
933   ScrnInfoPtr pScrn,
934   int bg, int fg
935)
936{
937    MGAPtr pMga = MGAPTR(pScrn);
938    /* The TI 3026 cursor is always 8 bits so shift 8, not 10 */
939
940    /* Background color */
941    outTi3026dreg(TVP3026_CUR_COL_ADDR, 1);
942    outTi3026dreg(TVP3026_CUR_COL_DATA, (bg & 0x00FF0000) >> 16);
943    outTi3026dreg(TVP3026_CUR_COL_DATA, (bg & 0x0000FF00) >> 8);
944    outTi3026dreg(TVP3026_CUR_COL_DATA, (bg & 0x000000FF));
945
946    /* Foreground color */
947    outTi3026dreg(TVP3026_CUR_COL_ADDR, 2);
948    outTi3026dreg(TVP3026_CUR_COL_DATA, (fg & 0x00FF0000) >> 16);
949    outTi3026dreg(TVP3026_CUR_COL_DATA, (fg & 0x0000FF00) >> 8);
950    outTi3026dreg(TVP3026_CUR_COL_DATA, (fg & 0x000000FF));
951}
952
953static Bool
954MGA3026UseHWCursor(ScreenPtr pScrn, CursorPtr pCurs)
955{
956    if( XF86SCRNINFO(pScrn)->currentMode->Flags & V_DBLSCAN )
957    	return FALSE;
958    return TRUE;
959}
960
961static const int DDC_SDA_MASK = 1 << 2;
962static const int DDC_SCL_MASK = 1 << 4;
963
964static unsigned int
965MGA3026_ddc1Read(ScrnInfoPtr pScrn)
966{
967  MGAPtr pMga = MGAPTR(pScrn);
968
969  /* Define the SDA as an input */
970  outTi3026(TVP3026_GEN_IO_CTL, 0xfb, 0);
971
972  /* wait for Vsync */
973  while( INREG( MGAREG_Status ) & 0x08 );
974  while( ! (INREG( MGAREG_Status ) & 0x08) );
975
976  /* Get the result */
977  return (inTi3026(TVP3026_GEN_IO_DATA) & DDC_SDA_MASK) >> 2 ;
978}
979
980static void
981MGA3026_I2CGetBits(I2CBusPtr b, int *clock, int *data)
982{
983  ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex];
984  MGAPtr pMga = MGAPTR(pScrn);
985  unsigned char val;
986
987  /* Get the result. */
988  val = inTi3026(TVP3026_GEN_IO_DATA);
989  *clock = (val & DDC_SCL_MASK) != 0;
990  *data  = (val & DDC_SDA_MASK) != 0;
991
992#ifdef DEBUG
993	 ErrorF("MGA3026_I2CGetBits(%p,...) val=0x%x, returns clock %d, data %d\n", b, val, *clock, *data);
994#endif
995}
996
997/*
998 * ATTENTION! - the DATA and CLOCK lines need to be tri-stated when
999 * high. Therefore turn off output driver for the line to set line
1000 * to high. High signal is maintained by a 15k Ohm pll-up resistor.
1001 */
1002static void
1003MGA3026_I2CPutBits(I2CBusPtr b, int clock, int data)
1004{
1005  ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex];
1006  MGAPtr pMga = MGAPTR(pScrn);
1007  unsigned char val,drv;
1008
1009  /* Write the values */
1010  val = (clock ? DDC_SCL_MASK : 0) | (data ? DDC_SDA_MASK : 0);
1011  drv = ((!clock) ? DDC_SCL_MASK : 0) | ((!data) ? DDC_SDA_MASK : 0);
1012  /* Define the SDA (Data) and SCL (clock) as outputs */
1013  outTi3026(TVP3026_GEN_IO_CTL, ~(DDC_SDA_MASK | DDC_SCL_MASK), drv);
1014  outTi3026(TVP3026_GEN_IO_DATA, ~(DDC_SDA_MASK | DDC_SCL_MASK), val);
1015
1016#ifdef DEBUG
1017  ErrorF("MGA3026_I2CPutBits(%p, %d, %d) val=0x%x\n", b, clock, data, val);
1018#endif
1019
1020}
1021
1022
1023Bool
1024MGA3026_i2cInit(ScrnInfoPtr pScrn)
1025{
1026    MGAPtr pMga = MGAPTR(pScrn);
1027    I2CBusPtr I2CPtr;
1028
1029    I2CPtr = xf86CreateI2CBusRec();
1030    if(!I2CPtr) return FALSE;
1031
1032    pMga->DDC_Bus1 = I2CPtr;
1033
1034    I2CPtr->BusName    = "DDC";
1035    I2CPtr->scrnIndex  = pScrn->scrnIndex;
1036    I2CPtr->I2CPutBits = MGA3026_I2CPutBits;
1037    I2CPtr->I2CGetBits = MGA3026_I2CGetBits;
1038
1039    /* I2CPutByte is timing out, experimenting with AcknTimeout
1040     * default is 2CPtr->AcknTimeout = 5;
1041     */
1042    /* I2CPtr->AcknTimeout = 10; */
1043
1044    if (!xf86I2CBusInit(I2CPtr)) {
1045	return FALSE;
1046    }
1047    return TRUE;
1048}
1049
1050static void
1051MGA3026RamdacInit(ScrnInfoPtr pScrn)
1052{
1053    MGAPtr pMga;
1054    MGARamdacPtr MGAdac;
1055
1056    pMga = MGAPTR(pScrn);
1057    MGAdac = &pMga->Dac;
1058
1059    MGAdac->isHwCursor		= TRUE;
1060    MGAdac->CursorMaxWidth	= 64;
1061    MGAdac->CursorMaxHeight	= 64;
1062    MGAdac->SetCursorColors	= MGA3026SetCursorColors;
1063    MGAdac->SetCursorPosition	= MGA3026SetCursorPosition;
1064    MGAdac->LoadCursorImage	= MGA3026LoadCursorImage;
1065    MGAdac->HideCursor		= MGA3026HideCursor;
1066    MGAdac->ShowCursor		= MGA3026ShowCursor;
1067    MGAdac->UseHWCursor		= MGA3026UseHWCursor;
1068    MGAdac->CursorFlags		=
1069#if X_BYTE_ORDER == X_LITTLE_ENDIAN
1070				HARDWARE_CURSOR_BIT_ORDER_MSBFIRST |
1071#endif
1072				HARDWARE_CURSOR_TRUECOLOR_AT_8BPP |
1073				HARDWARE_CURSOR_SOURCE_MASK_NOT_INTERLEAVED;
1074
1075    MGAdac->LoadPalette 	= MGA3026LoadPalette;
1076    MGAdac->RestorePalette	= MGA3026RestorePalette;
1077
1078    MGAdac->maxPixelClock = pMga->bios.pixel.max_freq;
1079    MGAdac->ClockFrom = X_PROBED;
1080
1081    MGAdac->MemoryClock = pMga->bios.mem_clock;
1082    MGAdac->MemClkFrom = X_PROBED;
1083    MGAdac->SetMemClk = TRUE;
1084
1085
1086    /* safety check */
1087    if ( (MGAdac->MemoryClock < 40000) ||
1088         (MGAdac->MemoryClock > 70000) )
1089	MGAdac->MemoryClock = 50000;
1090
1091    /*
1092     * Should initialise a sane default when the probed value is
1093     * obviously garbage.
1094     */
1095
1096    /* Check if interleaving can be used and set the rounding value */
1097    if (pScrn->videoRam > 2048)
1098        pMga->Interleave = TRUE;
1099    else {
1100        pMga->Interleave = FALSE;
1101        pMga->BppShifts[0]++;
1102        pMga->BppShifts[1]++;
1103        pMga->BppShifts[2]++;
1104        pMga->BppShifts[3]++;
1105    }
1106
1107    pMga->Roundings[0] = 128 >> pMga->BppShifts[0];
1108    pMga->Roundings[1] = 128 >> pMga->BppShifts[1];
1109    pMga->Roundings[2] = 128 >> pMga->BppShifts[2];
1110    pMga->Roundings[3] = 128 >> pMga->BppShifts[3];
1111
1112    /* Set Fast bitblt flag */
1113    pMga->HasFBitBlt = pMga->bios.fast_bitblt;
1114}
1115
1116void MGA3026LoadPalette(
1117    ScrnInfoPtr pScrn,
1118    int numColors,
1119    int *indices,
1120    LOCO *colors,
1121    VisualPtr pVisual
1122){
1123    MGAPtr pMga = MGAPTR(pScrn);
1124    int i, index;
1125
1126    if (pVisual->nplanes == 16) {
1127	for(i = 0; i < numColors; i++) {
1128	    index = indices[i];
1129            outTi3026dreg(MGA1064_WADR_PAL, index << 2);
1130            outTi3026dreg(MGA1064_COL_PAL, colors[index >> 1].red);
1131            outTi3026dreg(MGA1064_COL_PAL, colors[index].green);
1132            outTi3026dreg(MGA1064_COL_PAL, colors[index >> 1].blue);
1133
1134	/* we have to write 2 indices since the pixel X on the
1135	   TVP3026 has green colors at different locations from
1136	   the red and blue colors */
1137	    if(index <= 31) {
1138		outTi3026dreg(MGA1064_WADR_PAL, index << 3);
1139		outTi3026dreg(MGA1064_COL_PAL, colors[index].red);
1140		outTi3026dreg(MGA1064_COL_PAL, colors[(index << 1) + 1].green);
1141		outTi3026dreg(MGA1064_COL_PAL, colors[index].blue);
1142	    }
1143	}
1144    } else {
1145	int shift = (pVisual->nplanes == 15) ? 3 : 0;
1146
1147	for(i = 0; i < numColors; i++) {
1148	    index = indices[i];
1149            outTi3026dreg(MGA1064_WADR_PAL, index << shift);
1150            outTi3026dreg(MGA1064_COL_PAL, colors[index].red);
1151            outTi3026dreg(MGA1064_COL_PAL, colors[index].green);
1152            outTi3026dreg(MGA1064_COL_PAL, colors[index].blue);
1153	}
1154    }
1155}
1156
1157
1158static void
1159MGA3026SavePalette(ScrnInfoPtr pScrn, unsigned char* pntr)
1160{
1161    MGAPtr pMga = MGAPTR(pScrn);
1162    int i = 768;
1163
1164    outTi3026dreg(TVP3026_RADR_PAL, 0x00);
1165    while(i--)
1166        *(pntr++) = inTi3026dreg(TVP3026_COL_PAL);
1167}
1168
1169static void
1170MGA3026RestorePalette(ScrnInfoPtr pScrn, unsigned char* pntr)
1171{
1172    MGAPtr pMga = MGAPTR(pScrn);
1173    int i = 768;
1174
1175    outTi3026dreg(TVP3026_WADR_PAL, 0x00);
1176    while(i--)
1177        outTi3026dreg(TVP3026_COL_PAL, *(pntr++));
1178}
1179
1180
1181void MGA2064SetupFuncs(ScrnInfoPtr pScrn)
1182{
1183    MGAPtr pMga = MGAPTR(pScrn);
1184
1185    pMga->PreInit = MGA3026RamdacInit;
1186    pMga->Save = MGA3026Save;
1187    pMga->Restore = MGA3026Restore;
1188    pMga->ModeInit = MGA3026Init;
1189    pMga->ddc1Read = MGA3026_ddc1Read;
1190    /* vgaHWddc1SetSpeed will only work if the card is in VGA mode */
1191    pMga->DDC1SetSpeed = vgaHWddc1SetSpeedWeak();
1192    pMga->i2cInit = MGA3026_i2cInit;
1193}
1194