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