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