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