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