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