xref: /linux/drivers/video/fbdev/matrox/matroxfb_DAC1064.c (revision a641261e999842bee7326b2d0e84bf2214f03022)
1f7018c21STomi Valkeinen /*
2f7018c21STomi Valkeinen  *
3f7018c21STomi Valkeinen  * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450.
4f7018c21STomi Valkeinen  *
5f7018c21STomi Valkeinen  * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
6f7018c21STomi Valkeinen  *
7f7018c21STomi Valkeinen  * Portions Copyright (c) 2001 Matrox Graphics Inc.
8f7018c21STomi Valkeinen  *
9f7018c21STomi Valkeinen  * Version: 1.65 2002/08/14
10f7018c21STomi Valkeinen  *
11f7018c21STomi Valkeinen  * See matroxfb_base.c for contributors.
12f7018c21STomi Valkeinen  *
13f7018c21STomi Valkeinen  */
14f7018c21STomi Valkeinen 
15f7018c21STomi Valkeinen 
16f7018c21STomi Valkeinen #include "matroxfb_DAC1064.h"
17f7018c21STomi Valkeinen #include "matroxfb_misc.h"
18f7018c21STomi Valkeinen #include "matroxfb_accel.h"
19f7018c21STomi Valkeinen #include "g450_pll.h"
20f7018c21STomi Valkeinen #include <linux/matroxfb.h>
21f7018c21STomi Valkeinen 
22f7018c21STomi Valkeinen #ifdef NEED_DAC1064
23f7018c21STomi Valkeinen #define outDAC1064 matroxfb_DAC_out
24f7018c21STomi Valkeinen #define inDAC1064 matroxfb_DAC_in
25f7018c21STomi Valkeinen 
26f7018c21STomi Valkeinen #define DAC1064_OPT_SCLK_PCI	0x00
27f7018c21STomi Valkeinen #define DAC1064_OPT_SCLK_PLL	0x01
28f7018c21STomi Valkeinen #define DAC1064_OPT_SCLK_EXT	0x02
29f7018c21STomi Valkeinen #define DAC1064_OPT_SCLK_MASK	0x03
30f7018c21STomi Valkeinen #define DAC1064_OPT_GDIV1	0x04	/* maybe it is GDIV2 on G100 ?! */
31f7018c21STomi Valkeinen #define DAC1064_OPT_GDIV3	0x00
32f7018c21STomi Valkeinen #define DAC1064_OPT_MDIV1	0x08
33f7018c21STomi Valkeinen #define DAC1064_OPT_MDIV2	0x00
34f7018c21STomi Valkeinen #define DAC1064_OPT_RESERVED	0x10
35f7018c21STomi Valkeinen 
36f7018c21STomi Valkeinen static void DAC1064_calcclock(const struct matrox_fb_info *minfo,
37f7018c21STomi Valkeinen 			      unsigned int freq, unsigned int fmax,
38f7018c21STomi Valkeinen 			      unsigned int *in, unsigned int *feed,
39f7018c21STomi Valkeinen 			      unsigned int *post)
40f7018c21STomi Valkeinen {
41f7018c21STomi Valkeinen 	unsigned int fvco;
42f7018c21STomi Valkeinen 	unsigned int p;
43f7018c21STomi Valkeinen 
44f7018c21STomi Valkeinen 	DBG(__func__)
45f7018c21STomi Valkeinen 
46f7018c21STomi Valkeinen 	/* only for devices older than G450 */
47f7018c21STomi Valkeinen 
48f7018c21STomi Valkeinen 	fvco = PLL_calcclock(minfo, freq, fmax, in, feed, &p);
49f7018c21STomi Valkeinen 
50f7018c21STomi Valkeinen 	p = (1 << p) - 1;
51f7018c21STomi Valkeinen 	if (fvco <= 100000)
52f7018c21STomi Valkeinen 		;
53f7018c21STomi Valkeinen 	else if (fvco <= 140000)
54f7018c21STomi Valkeinen 		p |= 0x08;
55f7018c21STomi Valkeinen 	else if (fvco <= 180000)
56f7018c21STomi Valkeinen 		p |= 0x10;
57f7018c21STomi Valkeinen 	else
58f7018c21STomi Valkeinen 		p |= 0x18;
59f7018c21STomi Valkeinen 	*post = p;
60f7018c21STomi Valkeinen }
61f7018c21STomi Valkeinen 
62f7018c21STomi Valkeinen /* they must be in POS order */
63f7018c21STomi Valkeinen static const unsigned char MGA1064_DAC_regs[] = {
64f7018c21STomi Valkeinen 		M1064_XCURADDL, M1064_XCURADDH, M1064_XCURCTRL,
65f7018c21STomi Valkeinen 		M1064_XCURCOL0RED, M1064_XCURCOL0GREEN, M1064_XCURCOL0BLUE,
66f7018c21STomi Valkeinen 		M1064_XCURCOL1RED, M1064_XCURCOL1GREEN, M1064_XCURCOL1BLUE,
67f7018c21STomi Valkeinen 		M1064_XCURCOL2RED, M1064_XCURCOL2GREEN, M1064_XCURCOL2BLUE,
68f7018c21STomi Valkeinen 		DAC1064_XVREFCTRL, M1064_XMULCTRL, M1064_XPIXCLKCTRL, M1064_XGENCTRL,
69f7018c21STomi Valkeinen 		M1064_XMISCCTRL,
70f7018c21STomi Valkeinen 		M1064_XGENIOCTRL, M1064_XGENIODATA, M1064_XZOOMCTRL, M1064_XSENSETEST,
71f7018c21STomi Valkeinen 		M1064_XCRCBITSEL,
72f7018c21STomi Valkeinen 		M1064_XCOLKEYMASKL, M1064_XCOLKEYMASKH, M1064_XCOLKEYL, M1064_XCOLKEYH };
73f7018c21STomi Valkeinen 
74f7018c21STomi Valkeinen static const unsigned char MGA1064_DAC[] = {
75f7018c21STomi Valkeinen 		0x00, 0x00, M1064_XCURCTRL_DIS,
76f7018c21STomi Valkeinen 		0x00, 0x00, 0x00, 	/* black */
77f7018c21STomi Valkeinen 		0xFF, 0xFF, 0xFF,	/* white */
78f7018c21STomi Valkeinen 		0xFF, 0x00, 0x00,	/* red */
79f7018c21STomi Valkeinen 		0x00, 0,
80f7018c21STomi Valkeinen 		M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL,
81f7018c21STomi Valkeinen 		M1064_XGENCTRL_VS_0 | M1064_XGENCTRL_ALPHA_DIS | M1064_XGENCTRL_BLACK_0IRE | M1064_XGENCTRL_NO_SYNC_ON_GREEN,
82f7018c21STomi Valkeinen 		M1064_XMISCCTRL_DAC_8BIT,
83f7018c21STomi Valkeinen 		0x00, 0x00, M1064_XZOOMCTRL_1, M1064_XSENSETEST_BCOMP | M1064_XSENSETEST_GCOMP | M1064_XSENSETEST_RCOMP | M1064_XSENSETEST_PDOWN,
84f7018c21STomi Valkeinen 		0x00,
85f7018c21STomi Valkeinen 		0x00, 0x00, 0xFF, 0xFF};
86f7018c21STomi Valkeinen 
87f7018c21STomi Valkeinen static void DAC1064_setpclk(struct matrox_fb_info *minfo, unsigned long fout)
88f7018c21STomi Valkeinen {
89f7018c21STomi Valkeinen 	unsigned int m, n, p;
90f7018c21STomi Valkeinen 
91f7018c21STomi Valkeinen 	DBG(__func__)
92f7018c21STomi Valkeinen 
93f7018c21STomi Valkeinen 	DAC1064_calcclock(minfo, fout, minfo->max_pixel_clock, &m, &n, &p);
94f7018c21STomi Valkeinen 	minfo->hw.DACclk[0] = m;
95f7018c21STomi Valkeinen 	minfo->hw.DACclk[1] = n;
96f7018c21STomi Valkeinen 	minfo->hw.DACclk[2] = p;
97f7018c21STomi Valkeinen }
98f7018c21STomi Valkeinen 
99f7018c21STomi Valkeinen static void DAC1064_setmclk(struct matrox_fb_info *minfo, int oscinfo,
100f7018c21STomi Valkeinen 			    unsigned long fmem)
101f7018c21STomi Valkeinen {
102f7018c21STomi Valkeinen 	u_int32_t mx;
103f7018c21STomi Valkeinen 	struct matrox_hw_state *hw = &minfo->hw;
104f7018c21STomi Valkeinen 
105f7018c21STomi Valkeinen 	DBG(__func__)
106f7018c21STomi Valkeinen 
107f7018c21STomi Valkeinen 	if (minfo->devflags.noinit) {
108f7018c21STomi Valkeinen 		/* read MCLK and give up... */
109f7018c21STomi Valkeinen 		hw->DACclk[3] = inDAC1064(minfo, DAC1064_XSYSPLLM);
110f7018c21STomi Valkeinen 		hw->DACclk[4] = inDAC1064(minfo, DAC1064_XSYSPLLN);
111f7018c21STomi Valkeinen 		hw->DACclk[5] = inDAC1064(minfo, DAC1064_XSYSPLLP);
112f7018c21STomi Valkeinen 		return;
113f7018c21STomi Valkeinen 	}
114f7018c21STomi Valkeinen 	mx = hw->MXoptionReg | 0x00000004;
115f7018c21STomi Valkeinen 	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, mx);
116f7018c21STomi Valkeinen 	mx &= ~0x000000BB;
117f7018c21STomi Valkeinen 	if (oscinfo & DAC1064_OPT_GDIV1)
118f7018c21STomi Valkeinen 		mx |= 0x00000008;
119f7018c21STomi Valkeinen 	if (oscinfo & DAC1064_OPT_MDIV1)
120f7018c21STomi Valkeinen 		mx |= 0x00000010;
121f7018c21STomi Valkeinen 	if (oscinfo & DAC1064_OPT_RESERVED)
122f7018c21STomi Valkeinen 		mx |= 0x00000080;
123f7018c21STomi Valkeinen 	if ((oscinfo & DAC1064_OPT_SCLK_MASK) == DAC1064_OPT_SCLK_PLL) {
124f7018c21STomi Valkeinen 		/* select PCI clock until we have setup oscilator... */
125f7018c21STomi Valkeinen 		int clk;
126f7018c21STomi Valkeinen 		unsigned int m, n, p;
127f7018c21STomi Valkeinen 
128f7018c21STomi Valkeinen 		/* powerup system PLL, select PCI clock */
129f7018c21STomi Valkeinen 		mx |= 0x00000020;
130f7018c21STomi Valkeinen 		pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, mx);
131f7018c21STomi Valkeinen 		mx &= ~0x00000004;
132f7018c21STomi Valkeinen 		pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, mx);
133f7018c21STomi Valkeinen 
134f7018c21STomi Valkeinen 		/* !!! you must not access device if MCLK is not running !!!
135f7018c21STomi Valkeinen 		   Doing so cause immediate PCI lockup :-( Maybe they should
136f7018c21STomi Valkeinen 		   generate ABORT or I/O (parity...) error and Linux should
137f7018c21STomi Valkeinen 		   recover from this... (kill driver/process). But world is not
138f7018c21STomi Valkeinen 		   perfect... */
139f7018c21STomi Valkeinen 		/* (bit 2 of PCI_OPTION_REG must be 0... and bits 0,1 must not
140f7018c21STomi Valkeinen 		   select PLL... because of PLL can be stopped at this time) */
141f7018c21STomi Valkeinen 		DAC1064_calcclock(minfo, fmem, minfo->max_pixel_clock, &m, &n, &p);
142f7018c21STomi Valkeinen 		outDAC1064(minfo, DAC1064_XSYSPLLM, hw->DACclk[3] = m);
143f7018c21STomi Valkeinen 		outDAC1064(minfo, DAC1064_XSYSPLLN, hw->DACclk[4] = n);
144f7018c21STomi Valkeinen 		outDAC1064(minfo, DAC1064_XSYSPLLP, hw->DACclk[5] = p);
145f7018c21STomi Valkeinen 		for (clk = 65536; clk; --clk) {
146f7018c21STomi Valkeinen 			if (inDAC1064(minfo, DAC1064_XSYSPLLSTAT) & 0x40)
147f7018c21STomi Valkeinen 				break;
148f7018c21STomi Valkeinen 		}
149f7018c21STomi Valkeinen 		if (!clk)
150f7018c21STomi Valkeinen 			printk(KERN_ERR "matroxfb: aiee, SYSPLL not locked\n");
151f7018c21STomi Valkeinen 		/* select PLL */
152f7018c21STomi Valkeinen 		mx |= 0x00000005;
153f7018c21STomi Valkeinen 	} else {
154f7018c21STomi Valkeinen 		/* select specified system clock source */
155f7018c21STomi Valkeinen 		mx |= oscinfo & DAC1064_OPT_SCLK_MASK;
156f7018c21STomi Valkeinen 	}
157f7018c21STomi Valkeinen 	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, mx);
158f7018c21STomi Valkeinen 	mx &= ~0x00000004;
159f7018c21STomi Valkeinen 	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, mx);
160f7018c21STomi Valkeinen 	hw->MXoptionReg = mx;
161f7018c21STomi Valkeinen }
162f7018c21STomi Valkeinen 
163f7018c21STomi Valkeinen #ifdef CONFIG_FB_MATROX_G
164f7018c21STomi Valkeinen static void g450_set_plls(struct matrox_fb_info *minfo)
165f7018c21STomi Valkeinen {
166f7018c21STomi Valkeinen 	u_int32_t c2_ctl;
167f7018c21STomi Valkeinen 	unsigned int pxc;
168f7018c21STomi Valkeinen 	struct matrox_hw_state *hw = &minfo->hw;
169f7018c21STomi Valkeinen 	int pixelmnp;
170f7018c21STomi Valkeinen 	int videomnp;
171f7018c21STomi Valkeinen 
172f7018c21STomi Valkeinen 	c2_ctl = hw->crtc2.ctl & ~0x4007;	/* Clear PLL + enable for CRTC2 */
173f7018c21STomi Valkeinen 	c2_ctl |= 0x0001;			/* Enable CRTC2 */
174f7018c21STomi Valkeinen 	hw->DACreg[POS1064_XPWRCTRL] &= ~0x02;	/* Stop VIDEO PLL */
175f7018c21STomi Valkeinen 	pixelmnp = minfo->crtc1.mnp;
176f7018c21STomi Valkeinen 	videomnp = minfo->crtc2.mnp;
177f7018c21STomi Valkeinen 	if (videomnp < 0) {
178f7018c21STomi Valkeinen 		c2_ctl &= ~0x0001;			/* Disable CRTC2 */
179f7018c21STomi Valkeinen 		hw->DACreg[POS1064_XPWRCTRL] &= ~0x10;	/* Powerdown CRTC2 */
180f7018c21STomi Valkeinen 	} else if (minfo->crtc2.pixclock == minfo->features.pll.ref_freq) {
181f7018c21STomi Valkeinen 		c2_ctl |=  0x4002;	/* Use reference directly */
182f7018c21STomi Valkeinen 	} else if (videomnp == pixelmnp) {
183f7018c21STomi Valkeinen 		c2_ctl |=  0x0004;	/* Use pixel PLL */
184f7018c21STomi Valkeinen 	} else {
185f7018c21STomi Valkeinen 		if (0 == ((videomnp ^ pixelmnp) & 0xFFFFFF00)) {
186f7018c21STomi Valkeinen 			/* PIXEL and VIDEO PLL must not use same frequency. We modify N
187f7018c21STomi Valkeinen 			   of PIXEL PLL in such case because of VIDEO PLL may be source
188f7018c21STomi Valkeinen 			   of TVO clocks, and chroma subcarrier is derived from its
189f7018c21STomi Valkeinen 			   pixel clocks */
190f7018c21STomi Valkeinen 			pixelmnp += 0x000100;
191f7018c21STomi Valkeinen 		}
192f7018c21STomi Valkeinen 		c2_ctl |=  0x0006;	/* Use video PLL */
193f7018c21STomi Valkeinen 		hw->DACreg[POS1064_XPWRCTRL] |= 0x02;
194f7018c21STomi Valkeinen 
195f7018c21STomi Valkeinen 		outDAC1064(minfo, M1064_XPWRCTRL, hw->DACreg[POS1064_XPWRCTRL]);
196f7018c21STomi Valkeinen 		matroxfb_g450_setpll_cond(minfo, videomnp, M_VIDEO_PLL);
197f7018c21STomi Valkeinen 	}
198f7018c21STomi Valkeinen 
199f7018c21STomi Valkeinen 	hw->DACreg[POS1064_XPIXCLKCTRL] &= ~M1064_XPIXCLKCTRL_PLL_UP;
200f7018c21STomi Valkeinen 	if (pixelmnp >= 0) {
201f7018c21STomi Valkeinen 		hw->DACreg[POS1064_XPIXCLKCTRL] |= M1064_XPIXCLKCTRL_PLL_UP;
202f7018c21STomi Valkeinen 
203f7018c21STomi Valkeinen 		outDAC1064(minfo, M1064_XPIXCLKCTRL, hw->DACreg[POS1064_XPIXCLKCTRL]);
204f7018c21STomi Valkeinen 		matroxfb_g450_setpll_cond(minfo, pixelmnp, M_PIXEL_PLL_C);
205f7018c21STomi Valkeinen 	}
206f7018c21STomi Valkeinen 	if (c2_ctl != hw->crtc2.ctl) {
207f7018c21STomi Valkeinen 		hw->crtc2.ctl = c2_ctl;
208f7018c21STomi Valkeinen 		mga_outl(0x3C10, c2_ctl);
209f7018c21STomi Valkeinen 	}
210f7018c21STomi Valkeinen 
211f7018c21STomi Valkeinen 	pxc = minfo->crtc1.pixclock;
212f7018c21STomi Valkeinen 	if (pxc == 0 || minfo->outputs[2].src == MATROXFB_SRC_CRTC2) {
213f7018c21STomi Valkeinen 		pxc = minfo->crtc2.pixclock;
214f7018c21STomi Valkeinen 	}
215f7018c21STomi Valkeinen 	if (minfo->chip == MGA_G550) {
216f7018c21STomi Valkeinen 		if (pxc < 45000) {
217f7018c21STomi Valkeinen 			hw->DACreg[POS1064_XPANMODE] = 0x00;	/* 0-50 */
218f7018c21STomi Valkeinen 		} else if (pxc < 55000) {
219f7018c21STomi Valkeinen 			hw->DACreg[POS1064_XPANMODE] = 0x08;	/* 34-62 */
220f7018c21STomi Valkeinen 		} else if (pxc < 70000) {
221f7018c21STomi Valkeinen 			hw->DACreg[POS1064_XPANMODE] = 0x10;	/* 42-78 */
222f7018c21STomi Valkeinen 		} else if (pxc < 85000) {
223f7018c21STomi Valkeinen 			hw->DACreg[POS1064_XPANMODE] = 0x18;	/* 62-92 */
224f7018c21STomi Valkeinen 		} else if (pxc < 100000) {
225f7018c21STomi Valkeinen 			hw->DACreg[POS1064_XPANMODE] = 0x20;	/* 74-108 */
226f7018c21STomi Valkeinen 		} else if (pxc < 115000) {
227f7018c21STomi Valkeinen 			hw->DACreg[POS1064_XPANMODE] = 0x28;	/* 94-122 */
228f7018c21STomi Valkeinen 		} else if (pxc < 125000) {
229f7018c21STomi Valkeinen 			hw->DACreg[POS1064_XPANMODE] = 0x30;	/* 108-132 */
230f7018c21STomi Valkeinen 		} else {
231f7018c21STomi Valkeinen 			hw->DACreg[POS1064_XPANMODE] = 0x38;	/* 120-168 */
232f7018c21STomi Valkeinen 		}
233f7018c21STomi Valkeinen 	} else {
234f7018c21STomi Valkeinen 		/* G450 */
235f7018c21STomi Valkeinen 		if (pxc < 45000) {
236f7018c21STomi Valkeinen 			hw->DACreg[POS1064_XPANMODE] = 0x00;	/* 0-54 */
237f7018c21STomi Valkeinen 		} else if (pxc < 65000) {
238f7018c21STomi Valkeinen 			hw->DACreg[POS1064_XPANMODE] = 0x08;	/* 38-70 */
239f7018c21STomi Valkeinen 		} else if (pxc < 85000) {
240f7018c21STomi Valkeinen 			hw->DACreg[POS1064_XPANMODE] = 0x10;	/* 56-96 */
241f7018c21STomi Valkeinen 		} else if (pxc < 105000) {
242f7018c21STomi Valkeinen 			hw->DACreg[POS1064_XPANMODE] = 0x18;	/* 80-114 */
243f7018c21STomi Valkeinen 		} else if (pxc < 135000) {
244f7018c21STomi Valkeinen 			hw->DACreg[POS1064_XPANMODE] = 0x20;	/* 102-144 */
245f7018c21STomi Valkeinen 		} else if (pxc < 160000) {
246f7018c21STomi Valkeinen 			hw->DACreg[POS1064_XPANMODE] = 0x28;	/* 132-166 */
247f7018c21STomi Valkeinen 		} else if (pxc < 175000) {
248f7018c21STomi Valkeinen 			hw->DACreg[POS1064_XPANMODE] = 0x30;	/* 154-182 */
249f7018c21STomi Valkeinen 		} else {
250f7018c21STomi Valkeinen 			hw->DACreg[POS1064_XPANMODE] = 0x38;	/* 170-204 */
251f7018c21STomi Valkeinen 		}
252f7018c21STomi Valkeinen 	}
253f7018c21STomi Valkeinen }
254f7018c21STomi Valkeinen #endif
255f7018c21STomi Valkeinen 
256f7018c21STomi Valkeinen void DAC1064_global_init(struct matrox_fb_info *minfo)
257f7018c21STomi Valkeinen {
258f7018c21STomi Valkeinen 	struct matrox_hw_state *hw = &minfo->hw;
259f7018c21STomi Valkeinen 
260f7018c21STomi Valkeinen 	hw->DACreg[POS1064_XMISCCTRL] &= M1064_XMISCCTRL_DAC_WIDTHMASK;
261f7018c21STomi Valkeinen 	hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_LUT_EN;
262f7018c21STomi Valkeinen 	hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL;
263f7018c21STomi Valkeinen #ifdef CONFIG_FB_MATROX_G
264f7018c21STomi Valkeinen 	if (minfo->devflags.g450dac) {
265f7018c21STomi Valkeinen 		hw->DACreg[POS1064_XPWRCTRL] = 0x1F;	/* powerup everything */
266f7018c21STomi Valkeinen 		hw->DACreg[POS1064_XOUTPUTCONN] = 0x00;	/* disable outputs */
267f7018c21STomi Valkeinen 		hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_DAC_EN;
268f7018c21STomi Valkeinen 		switch (minfo->outputs[0].src) {
269f7018c21STomi Valkeinen 			case MATROXFB_SRC_CRTC1:
270f7018c21STomi Valkeinen 			case MATROXFB_SRC_CRTC2:
271f7018c21STomi Valkeinen 				hw->DACreg[POS1064_XOUTPUTCONN] |= 0x01;	/* enable output; CRTC1/2 selection is in CRTC2 ctl */
272f7018c21STomi Valkeinen 				break;
273f7018c21STomi Valkeinen 			case MATROXFB_SRC_NONE:
274f7018c21STomi Valkeinen 				hw->DACreg[POS1064_XMISCCTRL] &= ~M1064_XMISCCTRL_DAC_EN;
275f7018c21STomi Valkeinen 				break;
276f7018c21STomi Valkeinen 		}
277f7018c21STomi Valkeinen 		switch (minfo->outputs[1].src) {
278f7018c21STomi Valkeinen 			case MATROXFB_SRC_CRTC1:
279f7018c21STomi Valkeinen 				hw->DACreg[POS1064_XOUTPUTCONN] |= 0x04;
280f7018c21STomi Valkeinen 				break;
281f7018c21STomi Valkeinen 			case MATROXFB_SRC_CRTC2:
282f7018c21STomi Valkeinen 				if (minfo->outputs[1].mode == MATROXFB_OUTPUT_MODE_MONITOR) {
283f7018c21STomi Valkeinen 					hw->DACreg[POS1064_XOUTPUTCONN] |= 0x08;
284f7018c21STomi Valkeinen 				} else {
285f7018c21STomi Valkeinen 					hw->DACreg[POS1064_XOUTPUTCONN] |= 0x0C;
286f7018c21STomi Valkeinen 				}
287f7018c21STomi Valkeinen 				break;
288f7018c21STomi Valkeinen 			case MATROXFB_SRC_NONE:
289f7018c21STomi Valkeinen 				hw->DACreg[POS1064_XPWRCTRL] &= ~0x01;		/* Poweroff DAC2 */
290f7018c21STomi Valkeinen 				break;
291f7018c21STomi Valkeinen 		}
292f7018c21STomi Valkeinen 		switch (minfo->outputs[2].src) {
293f7018c21STomi Valkeinen 			case MATROXFB_SRC_CRTC1:
294f7018c21STomi Valkeinen 				hw->DACreg[POS1064_XOUTPUTCONN] |= 0x20;
295f7018c21STomi Valkeinen 				break;
296f7018c21STomi Valkeinen 			case MATROXFB_SRC_CRTC2:
297f7018c21STomi Valkeinen 				hw->DACreg[POS1064_XOUTPUTCONN] |= 0x40;
298f7018c21STomi Valkeinen 				break;
299f7018c21STomi Valkeinen 			case MATROXFB_SRC_NONE:
300f7018c21STomi Valkeinen #if 0
301f7018c21STomi Valkeinen 				/* HELP! If we boot without DFP connected to DVI, we can
302f7018c21STomi Valkeinen 				   poweroff TMDS. But if we boot with DFP connected,
303f7018c21STomi Valkeinen 				   TMDS generated clocks are used instead of ALL pixclocks
304f7018c21STomi Valkeinen 				   available... If someone knows which register
305f7018c21STomi Valkeinen 				   handles it, please reveal this secret to me... */
306f7018c21STomi Valkeinen 				hw->DACreg[POS1064_XPWRCTRL] &= ~0x04;		/* Poweroff TMDS */
307f7018c21STomi Valkeinen #endif
308f7018c21STomi Valkeinen 				break;
309f7018c21STomi Valkeinen 		}
310f7018c21STomi Valkeinen 		/* Now set timming related variables... */
311f7018c21STomi Valkeinen 		g450_set_plls(minfo);
312f7018c21STomi Valkeinen 	} else
313f7018c21STomi Valkeinen #endif
314f7018c21STomi Valkeinen 	{
315f7018c21STomi Valkeinen 		if (minfo->outputs[1].src == MATROXFB_SRC_CRTC1) {
316f7018c21STomi Valkeinen 			hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_EXT;
317f7018c21STomi Valkeinen 			hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_MAFC12;
318f7018c21STomi Valkeinen 		} else if (minfo->outputs[1].src == MATROXFB_SRC_CRTC2) {
319f7018c21STomi Valkeinen 			hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_C2_MAFC12;
320f7018c21STomi Valkeinen 		} else if (minfo->outputs[2].src == MATROXFB_SRC_CRTC1)
321f7018c21STomi Valkeinen 			hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_PANELLINK | G400_XMISCCTRL_VDO_MAFC12;
322f7018c21STomi Valkeinen 		else
323f7018c21STomi Valkeinen 			hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_DIS;
324f7018c21STomi Valkeinen 
325f7018c21STomi Valkeinen 		if (minfo->outputs[0].src != MATROXFB_SRC_NONE)
326f7018c21STomi Valkeinen 			hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_DAC_EN;
327f7018c21STomi Valkeinen 	}
328f7018c21STomi Valkeinen }
329f7018c21STomi Valkeinen 
330f7018c21STomi Valkeinen void DAC1064_global_restore(struct matrox_fb_info *minfo)
331f7018c21STomi Valkeinen {
332f7018c21STomi Valkeinen 	struct matrox_hw_state *hw = &minfo->hw;
333f7018c21STomi Valkeinen 
334f7018c21STomi Valkeinen 	outDAC1064(minfo, M1064_XPIXCLKCTRL, hw->DACreg[POS1064_XPIXCLKCTRL]);
335f7018c21STomi Valkeinen 	outDAC1064(minfo, M1064_XMISCCTRL, hw->DACreg[POS1064_XMISCCTRL]);
336f7018c21STomi Valkeinen 	if (minfo->devflags.accelerator == FB_ACCEL_MATROX_MGAG400) {
337f7018c21STomi Valkeinen 		outDAC1064(minfo, 0x20, 0x04);
338f7018c21STomi Valkeinen 		outDAC1064(minfo, 0x1F, minfo->devflags.dfp_type);
339f7018c21STomi Valkeinen 		if (minfo->devflags.g450dac) {
340f7018c21STomi Valkeinen 			outDAC1064(minfo, M1064_XSYNCCTRL, 0xCC);
341f7018c21STomi Valkeinen 			outDAC1064(minfo, M1064_XPWRCTRL, hw->DACreg[POS1064_XPWRCTRL]);
342f7018c21STomi Valkeinen 			outDAC1064(minfo, M1064_XPANMODE, hw->DACreg[POS1064_XPANMODE]);
343f7018c21STomi Valkeinen 			outDAC1064(minfo, M1064_XOUTPUTCONN, hw->DACreg[POS1064_XOUTPUTCONN]);
344f7018c21STomi Valkeinen 		}
345f7018c21STomi Valkeinen 	}
346f7018c21STomi Valkeinen }
347f7018c21STomi Valkeinen 
348f7018c21STomi Valkeinen static int DAC1064_init_1(struct matrox_fb_info *minfo, struct my_timming *m)
349f7018c21STomi Valkeinen {
350f7018c21STomi Valkeinen 	struct matrox_hw_state *hw = &minfo->hw;
351f7018c21STomi Valkeinen 
352f7018c21STomi Valkeinen 	DBG(__func__)
353f7018c21STomi Valkeinen 
354f7018c21STomi Valkeinen 	memcpy(hw->DACreg, MGA1064_DAC, sizeof(MGA1064_DAC_regs));
355f7018c21STomi Valkeinen 	switch (minfo->fbcon.var.bits_per_pixel) {
356f7018c21STomi Valkeinen 		/* case 4: not supported by MGA1064 DAC */
357f7018c21STomi Valkeinen 		case 8:
358f7018c21STomi Valkeinen 			hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_8BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
359f7018c21STomi Valkeinen 			break;
360f7018c21STomi Valkeinen 		case 16:
361f7018c21STomi Valkeinen 			if (minfo->fbcon.var.green.length == 5)
362f7018c21STomi Valkeinen 				hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_15BPP_1BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
363f7018c21STomi Valkeinen 			else
364f7018c21STomi Valkeinen 				hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_16BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
365f7018c21STomi Valkeinen 			break;
366f7018c21STomi Valkeinen 		case 24:
367f7018c21STomi Valkeinen 			hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_24BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
368f7018c21STomi Valkeinen 			break;
369f7018c21STomi Valkeinen 		case 32:
370f7018c21STomi Valkeinen 			hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_32BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
371f7018c21STomi Valkeinen 			break;
372f7018c21STomi Valkeinen 		default:
373f7018c21STomi Valkeinen 			return 1;	/* unsupported depth */
374f7018c21STomi Valkeinen 	}
375f7018c21STomi Valkeinen 	hw->DACreg[POS1064_XVREFCTRL] = minfo->features.DAC1064.xvrefctrl;
376f7018c21STomi Valkeinen 	hw->DACreg[POS1064_XGENCTRL] &= ~M1064_XGENCTRL_SYNC_ON_GREEN_MASK;
377f7018c21STomi Valkeinen 	hw->DACreg[POS1064_XGENCTRL] |= (m->sync & FB_SYNC_ON_GREEN)?M1064_XGENCTRL_SYNC_ON_GREEN:M1064_XGENCTRL_NO_SYNC_ON_GREEN;
378f7018c21STomi Valkeinen 	hw->DACreg[POS1064_XCURADDL] = 0;
379f7018c21STomi Valkeinen 	hw->DACreg[POS1064_XCURADDH] = 0;
380f7018c21STomi Valkeinen 
381f7018c21STomi Valkeinen 	DAC1064_global_init(minfo);
382f7018c21STomi Valkeinen 	return 0;
383f7018c21STomi Valkeinen }
384f7018c21STomi Valkeinen 
385f7018c21STomi Valkeinen static int DAC1064_init_2(struct matrox_fb_info *minfo, struct my_timming *m)
386f7018c21STomi Valkeinen {
387f7018c21STomi Valkeinen 	struct matrox_hw_state *hw = &minfo->hw;
388f7018c21STomi Valkeinen 
389f7018c21STomi Valkeinen 	DBG(__func__)
390f7018c21STomi Valkeinen 
391f7018c21STomi Valkeinen 	if (minfo->fbcon.var.bits_per_pixel > 16) {	/* 256 entries */
392f7018c21STomi Valkeinen 		int i;
393f7018c21STomi Valkeinen 
394f7018c21STomi Valkeinen 		for (i = 0; i < 256; i++) {
395f7018c21STomi Valkeinen 			hw->DACpal[i * 3 + 0] = i;
396f7018c21STomi Valkeinen 			hw->DACpal[i * 3 + 1] = i;
397f7018c21STomi Valkeinen 			hw->DACpal[i * 3 + 2] = i;
398f7018c21STomi Valkeinen 		}
399f7018c21STomi Valkeinen 	} else if (minfo->fbcon.var.bits_per_pixel > 8) {
400f7018c21STomi Valkeinen 		if (minfo->fbcon.var.green.length == 5) {	/* 0..31, 128..159 */
401f7018c21STomi Valkeinen 			int i;
402f7018c21STomi Valkeinen 
403f7018c21STomi Valkeinen 			for (i = 0; i < 32; i++) {
404f7018c21STomi Valkeinen 				/* with p15 == 0 */
405f7018c21STomi Valkeinen 				hw->DACpal[i * 3 + 0] = i << 3;
406f7018c21STomi Valkeinen 				hw->DACpal[i * 3 + 1] = i << 3;
407f7018c21STomi Valkeinen 				hw->DACpal[i * 3 + 2] = i << 3;
408f7018c21STomi Valkeinen 				/* with p15 == 1 */
409f7018c21STomi Valkeinen 				hw->DACpal[(i + 128) * 3 + 0] = i << 3;
410f7018c21STomi Valkeinen 				hw->DACpal[(i + 128) * 3 + 1] = i << 3;
411f7018c21STomi Valkeinen 				hw->DACpal[(i + 128) * 3 + 2] = i << 3;
412f7018c21STomi Valkeinen 			}
413f7018c21STomi Valkeinen 		} else {
414f7018c21STomi Valkeinen 			int i;
415f7018c21STomi Valkeinen 
416f7018c21STomi Valkeinen 			for (i = 0; i < 64; i++) {		/* 0..63 */
417f7018c21STomi Valkeinen 				hw->DACpal[i * 3 + 0] = i << 3;
418f7018c21STomi Valkeinen 				hw->DACpal[i * 3 + 1] = i << 2;
419f7018c21STomi Valkeinen 				hw->DACpal[i * 3 + 2] = i << 3;
420f7018c21STomi Valkeinen 			}
421f7018c21STomi Valkeinen 		}
422f7018c21STomi Valkeinen 	} else {
423f7018c21STomi Valkeinen 		memset(hw->DACpal, 0, 768);
424f7018c21STomi Valkeinen 	}
425f7018c21STomi Valkeinen 	return 0;
426f7018c21STomi Valkeinen }
427f7018c21STomi Valkeinen 
428f7018c21STomi Valkeinen static void DAC1064_restore_1(struct matrox_fb_info *minfo)
429f7018c21STomi Valkeinen {
430f7018c21STomi Valkeinen 	struct matrox_hw_state *hw = &minfo->hw;
431f7018c21STomi Valkeinen 
432f7018c21STomi Valkeinen 	CRITFLAGS
433f7018c21STomi Valkeinen 
434f7018c21STomi Valkeinen 	DBG(__func__)
435f7018c21STomi Valkeinen 
436f7018c21STomi Valkeinen 	CRITBEGIN
437f7018c21STomi Valkeinen 
438f7018c21STomi Valkeinen 	if ((inDAC1064(minfo, DAC1064_XSYSPLLM) != hw->DACclk[3]) ||
439f7018c21STomi Valkeinen 	    (inDAC1064(minfo, DAC1064_XSYSPLLN) != hw->DACclk[4]) ||
440f7018c21STomi Valkeinen 	    (inDAC1064(minfo, DAC1064_XSYSPLLP) != hw->DACclk[5])) {
441f7018c21STomi Valkeinen 		outDAC1064(minfo, DAC1064_XSYSPLLM, hw->DACclk[3]);
442f7018c21STomi Valkeinen 		outDAC1064(minfo, DAC1064_XSYSPLLN, hw->DACclk[4]);
443f7018c21STomi Valkeinen 		outDAC1064(minfo, DAC1064_XSYSPLLP, hw->DACclk[5]);
444f7018c21STomi Valkeinen 	}
445f7018c21STomi Valkeinen 	{
446f7018c21STomi Valkeinen 		unsigned int i;
447f7018c21STomi Valkeinen 
448f7018c21STomi Valkeinen 		for (i = 0; i < sizeof(MGA1064_DAC_regs); i++) {
449f7018c21STomi Valkeinen 			if ((i != POS1064_XPIXCLKCTRL) && (i != POS1064_XMISCCTRL))
450f7018c21STomi Valkeinen 				outDAC1064(minfo, MGA1064_DAC_regs[i], hw->DACreg[i]);
451f7018c21STomi Valkeinen 		}
452f7018c21STomi Valkeinen 	}
453f7018c21STomi Valkeinen 
454f7018c21STomi Valkeinen 	DAC1064_global_restore(minfo);
455f7018c21STomi Valkeinen 
456f7018c21STomi Valkeinen 	CRITEND
457f7018c21STomi Valkeinen };
458f7018c21STomi Valkeinen 
459f7018c21STomi Valkeinen static void DAC1064_restore_2(struct matrox_fb_info *minfo)
460f7018c21STomi Valkeinen {
461f7018c21STomi Valkeinen #ifdef DEBUG
462f7018c21STomi Valkeinen 	unsigned int i;
463f7018c21STomi Valkeinen #endif
464f7018c21STomi Valkeinen 
465f7018c21STomi Valkeinen 	DBG(__func__)
466f7018c21STomi Valkeinen 
467f7018c21STomi Valkeinen #ifdef DEBUG
468f7018c21STomi Valkeinen 	dprintk(KERN_DEBUG "DAC1064regs ");
469f7018c21STomi Valkeinen 	for (i = 0; i < sizeof(MGA1064_DAC_regs); i++) {
470f7018c21STomi Valkeinen 		dprintk("R%02X=%02X ", MGA1064_DAC_regs[i], minfo->hw.DACreg[i]);
471f7018c21STomi Valkeinen 		if ((i & 0x7) == 0x7) dprintk(KERN_DEBUG "continuing... ");
472f7018c21STomi Valkeinen 	}
473f7018c21STomi Valkeinen 	dprintk(KERN_DEBUG "DAC1064clk ");
474f7018c21STomi Valkeinen 	for (i = 0; i < 6; i++)
475f7018c21STomi Valkeinen 		dprintk("C%02X=%02X ", i, minfo->hw.DACclk[i]);
476f7018c21STomi Valkeinen 	dprintk("\n");
477f7018c21STomi Valkeinen #endif
478f7018c21STomi Valkeinen }
479f7018c21STomi Valkeinen 
480f7018c21STomi Valkeinen static int m1064_compute(void* out, struct my_timming* m) {
481f7018c21STomi Valkeinen #define minfo ((struct matrox_fb_info*)out)
482f7018c21STomi Valkeinen 	{
483f7018c21STomi Valkeinen 		int i;
484f7018c21STomi Valkeinen 		int tmout;
485f7018c21STomi Valkeinen 		CRITFLAGS
486f7018c21STomi Valkeinen 
487f7018c21STomi Valkeinen 		DAC1064_setpclk(minfo, m->pixclock);
488f7018c21STomi Valkeinen 
489f7018c21STomi Valkeinen 		CRITBEGIN
490f7018c21STomi Valkeinen 
491f7018c21STomi Valkeinen 		for (i = 0; i < 3; i++)
492f7018c21STomi Valkeinen 			outDAC1064(minfo, M1064_XPIXPLLCM + i, minfo->hw.DACclk[i]);
493f7018c21STomi Valkeinen 		for (tmout = 500000; tmout; tmout--) {
494f7018c21STomi Valkeinen 			if (inDAC1064(minfo, M1064_XPIXPLLSTAT) & 0x40)
495f7018c21STomi Valkeinen 				break;
496f7018c21STomi Valkeinen 			udelay(10);
497f7018c21STomi Valkeinen 		}
498f7018c21STomi Valkeinen 
499f7018c21STomi Valkeinen 		CRITEND
500f7018c21STomi Valkeinen 
501f7018c21STomi Valkeinen 		if (!tmout)
502f7018c21STomi Valkeinen 			printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n");
503f7018c21STomi Valkeinen 	}
504f7018c21STomi Valkeinen #undef minfo
505f7018c21STomi Valkeinen 	return 0;
506f7018c21STomi Valkeinen }
507f7018c21STomi Valkeinen 
508f7018c21STomi Valkeinen static struct matrox_altout m1064 = {
509f7018c21STomi Valkeinen 	.name	 = "Primary output",
510f7018c21STomi Valkeinen 	.compute = m1064_compute,
511f7018c21STomi Valkeinen };
512f7018c21STomi Valkeinen 
513f7018c21STomi Valkeinen #ifdef CONFIG_FB_MATROX_G
514f7018c21STomi Valkeinen static int g450_compute(void* out, struct my_timming* m) {
515f7018c21STomi Valkeinen #define minfo ((struct matrox_fb_info*)out)
516f7018c21STomi Valkeinen 	if (m->mnp < 0) {
517f7018c21STomi Valkeinen 		m->mnp = matroxfb_g450_setclk(minfo, m->pixclock, (m->crtc == MATROXFB_SRC_CRTC1) ? M_PIXEL_PLL_C : M_VIDEO_PLL);
518f7018c21STomi Valkeinen 		if (m->mnp >= 0) {
519f7018c21STomi Valkeinen 			m->pixclock = g450_mnp2f(minfo, m->mnp);
520f7018c21STomi Valkeinen 		}
521f7018c21STomi Valkeinen 	}
522f7018c21STomi Valkeinen #undef minfo
523f7018c21STomi Valkeinen 	return 0;
524f7018c21STomi Valkeinen }
525f7018c21STomi Valkeinen 
526f7018c21STomi Valkeinen static struct matrox_altout g450out = {
527f7018c21STomi Valkeinen 	.name	 = "Primary output",
528f7018c21STomi Valkeinen 	.compute = g450_compute,
529f7018c21STomi Valkeinen };
530f7018c21STomi Valkeinen #endif
531f7018c21STomi Valkeinen 
532f7018c21STomi Valkeinen #endif /* NEED_DAC1064 */
533f7018c21STomi Valkeinen 
534f7018c21STomi Valkeinen #ifdef CONFIG_FB_MATROX_MYSTIQUE
535f7018c21STomi Valkeinen static int MGA1064_init(struct matrox_fb_info *minfo, struct my_timming *m)
536f7018c21STomi Valkeinen {
537f7018c21STomi Valkeinen 	struct matrox_hw_state *hw = &minfo->hw;
538f7018c21STomi Valkeinen 
539f7018c21STomi Valkeinen 	DBG(__func__)
540f7018c21STomi Valkeinen 
541f7018c21STomi Valkeinen 	if (DAC1064_init_1(minfo, m)) return 1;
542f7018c21STomi Valkeinen 	if (matroxfb_vgaHWinit(minfo, m)) return 1;
543f7018c21STomi Valkeinen 
544f7018c21STomi Valkeinen 	hw->MiscOutReg = 0xCB;
545f7018c21STomi Valkeinen 	if (m->sync & FB_SYNC_HOR_HIGH_ACT)
546f7018c21STomi Valkeinen 		hw->MiscOutReg &= ~0x40;
547f7018c21STomi Valkeinen 	if (m->sync & FB_SYNC_VERT_HIGH_ACT)
548f7018c21STomi Valkeinen 		hw->MiscOutReg &= ~0x80;
549f7018c21STomi Valkeinen 	if (m->sync & FB_SYNC_COMP_HIGH_ACT) /* should be only FB_SYNC_COMP */
550f7018c21STomi Valkeinen 		hw->CRTCEXT[3] |= 0x40;
551f7018c21STomi Valkeinen 
552f7018c21STomi Valkeinen 	if (DAC1064_init_2(minfo, m)) return 1;
553f7018c21STomi Valkeinen 	return 0;
554f7018c21STomi Valkeinen }
555f7018c21STomi Valkeinen #endif
556f7018c21STomi Valkeinen 
557f7018c21STomi Valkeinen #ifdef CONFIG_FB_MATROX_G
558f7018c21STomi Valkeinen static int MGAG100_init(struct matrox_fb_info *minfo, struct my_timming *m)
559f7018c21STomi Valkeinen {
560f7018c21STomi Valkeinen 	struct matrox_hw_state *hw = &minfo->hw;
561f7018c21STomi Valkeinen 
562f7018c21STomi Valkeinen 	DBG(__func__)
563f7018c21STomi Valkeinen 
564f7018c21STomi Valkeinen 	if (DAC1064_init_1(minfo, m)) return 1;
565f7018c21STomi Valkeinen 	hw->MXoptionReg &= ~0x2000;
566f7018c21STomi Valkeinen 	if (matroxfb_vgaHWinit(minfo, m)) return 1;
567f7018c21STomi Valkeinen 
568f7018c21STomi Valkeinen 	hw->MiscOutReg = 0xEF;
569f7018c21STomi Valkeinen 	if (m->sync & FB_SYNC_HOR_HIGH_ACT)
570f7018c21STomi Valkeinen 		hw->MiscOutReg &= ~0x40;
571f7018c21STomi Valkeinen 	if (m->sync & FB_SYNC_VERT_HIGH_ACT)
572f7018c21STomi Valkeinen 		hw->MiscOutReg &= ~0x80;
573f7018c21STomi Valkeinen 	if (m->sync & FB_SYNC_COMP_HIGH_ACT) /* should be only FB_SYNC_COMP */
574f7018c21STomi Valkeinen 		hw->CRTCEXT[3] |= 0x40;
575f7018c21STomi Valkeinen 
576f7018c21STomi Valkeinen 	if (DAC1064_init_2(minfo, m)) return 1;
577f7018c21STomi Valkeinen 	return 0;
578f7018c21STomi Valkeinen }
579f7018c21STomi Valkeinen #endif	/* G */
580f7018c21STomi Valkeinen 
581f7018c21STomi Valkeinen #ifdef CONFIG_FB_MATROX_MYSTIQUE
582f7018c21STomi Valkeinen static void MGA1064_ramdac_init(struct matrox_fb_info *minfo)
583f7018c21STomi Valkeinen {
584f7018c21STomi Valkeinen 
585f7018c21STomi Valkeinen 	DBG(__func__)
586f7018c21STomi Valkeinen 
587f7018c21STomi Valkeinen 	/* minfo->features.DAC1064.vco_freq_min = 120000; */
588f7018c21STomi Valkeinen 	minfo->features.pll.vco_freq_min = 62000;
589f7018c21STomi Valkeinen 	minfo->features.pll.ref_freq	 = 14318;
590f7018c21STomi Valkeinen 	minfo->features.pll.feed_div_min = 100;
591f7018c21STomi Valkeinen 	minfo->features.pll.feed_div_max = 127;
592f7018c21STomi Valkeinen 	minfo->features.pll.in_div_min	 = 1;
593f7018c21STomi Valkeinen 	minfo->features.pll.in_div_max	 = 31;
594f7018c21STomi Valkeinen 	minfo->features.pll.post_shift_max = 3;
595f7018c21STomi Valkeinen 	minfo->features.DAC1064.xvrefctrl = DAC1064_XVREFCTRL_EXTERNAL;
596f7018c21STomi Valkeinen 	/* maybe cmdline MCLK= ?, doc says gclk=44MHz, mclk=66MHz... it was 55/83 with old values */
597f7018c21STomi Valkeinen 	DAC1064_setmclk(minfo, DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV3 | DAC1064_OPT_SCLK_PLL, 133333);
598f7018c21STomi Valkeinen }
599f7018c21STomi Valkeinen #endif
600f7018c21STomi Valkeinen 
601f7018c21STomi Valkeinen #ifdef CONFIG_FB_MATROX_G
602f7018c21STomi Valkeinen /* BIOS environ */
603f7018c21STomi Valkeinen static int x7AF4 = 0x10;	/* flags, maybe 0x10 = SDRAM, 0x00 = SGRAM??? */
604f7018c21STomi Valkeinen 				/* G100 wants 0x10, G200 SGRAM does not care... */
605f7018c21STomi Valkeinen #if 0
606f7018c21STomi Valkeinen static int def50 = 0;	/* reg50, & 0x0F, & 0x3000 (only 0x0000, 0x1000, 0x2000 (0x3000 disallowed and treated as 0) */
607f7018c21STomi Valkeinen #endif
608f7018c21STomi Valkeinen 
609f7018c21STomi Valkeinen static void MGAG100_progPixClock(const struct matrox_fb_info *minfo, int flags,
610f7018c21STomi Valkeinen 				 int m, int n, int p)
611f7018c21STomi Valkeinen {
612f7018c21STomi Valkeinen 	int reg;
613f7018c21STomi Valkeinen 	int selClk;
614f7018c21STomi Valkeinen 	int clk;
615f7018c21STomi Valkeinen 
616f7018c21STomi Valkeinen 	DBG(__func__)
617f7018c21STomi Valkeinen 
618f7018c21STomi Valkeinen 	outDAC1064(minfo, M1064_XPIXCLKCTRL, inDAC1064(minfo, M1064_XPIXCLKCTRL) | M1064_XPIXCLKCTRL_DIS |
619f7018c21STomi Valkeinen 		   M1064_XPIXCLKCTRL_PLL_UP);
620f7018c21STomi Valkeinen 	switch (flags & 3) {
621f7018c21STomi Valkeinen 		case 0:		reg = M1064_XPIXPLLAM; break;
622f7018c21STomi Valkeinen 		case 1:		reg = M1064_XPIXPLLBM; break;
623f7018c21STomi Valkeinen 		default:	reg = M1064_XPIXPLLCM; break;
624f7018c21STomi Valkeinen 	}
625f7018c21STomi Valkeinen 	outDAC1064(minfo, reg++, m);
626f7018c21STomi Valkeinen 	outDAC1064(minfo, reg++, n);
627f7018c21STomi Valkeinen 	outDAC1064(minfo, reg, p);
628f7018c21STomi Valkeinen 	selClk = mga_inb(M_MISC_REG_READ) & ~0xC;
629f7018c21STomi Valkeinen 	/* there should be flags & 0x03 & case 0/1/else */
630f7018c21STomi Valkeinen 	/* and we should first select source and after that we should wait for PLL */
631f7018c21STomi Valkeinen 	/* and we are waiting for PLL with oscilator disabled... Is it right? */
632f7018c21STomi Valkeinen 	switch (flags & 0x03) {
633f7018c21STomi Valkeinen 		case 0x00:	break;
634f7018c21STomi Valkeinen 		case 0x01:	selClk |= 4; break;
635f7018c21STomi Valkeinen 		default:	selClk |= 0x0C; break;
636f7018c21STomi Valkeinen 	}
637f7018c21STomi Valkeinen 	mga_outb(M_MISC_REG, selClk);
638f7018c21STomi Valkeinen 	for (clk = 500000; clk; clk--) {
639f7018c21STomi Valkeinen 		if (inDAC1064(minfo, M1064_XPIXPLLSTAT) & 0x40)
640f7018c21STomi Valkeinen 			break;
641f7018c21STomi Valkeinen 		udelay(10);
642f7018c21STomi Valkeinen 	}
643f7018c21STomi Valkeinen 	if (!clk)
644f7018c21STomi Valkeinen 		printk(KERN_ERR "matroxfb: Pixel PLL%c not locked after usual time\n", (reg-M1064_XPIXPLLAM-2)/4 + 'A');
645f7018c21STomi Valkeinen 	selClk = inDAC1064(minfo, M1064_XPIXCLKCTRL) & ~M1064_XPIXCLKCTRL_SRC_MASK;
646f7018c21STomi Valkeinen 	switch (flags & 0x0C) {
647f7018c21STomi Valkeinen 		case 0x00:	selClk |= M1064_XPIXCLKCTRL_SRC_PCI; break;
648f7018c21STomi Valkeinen 		case 0x04:	selClk |= M1064_XPIXCLKCTRL_SRC_PLL; break;
649f7018c21STomi Valkeinen 		default:	selClk |= M1064_XPIXCLKCTRL_SRC_EXT; break;
650f7018c21STomi Valkeinen 	}
651f7018c21STomi Valkeinen 	outDAC1064(minfo, M1064_XPIXCLKCTRL, selClk);
652f7018c21STomi Valkeinen 	outDAC1064(minfo, M1064_XPIXCLKCTRL, inDAC1064(minfo, M1064_XPIXCLKCTRL) & ~M1064_XPIXCLKCTRL_DIS);
653f7018c21STomi Valkeinen }
654f7018c21STomi Valkeinen 
655f7018c21STomi Valkeinen static void MGAG100_setPixClock(const struct matrox_fb_info *minfo, int flags,
656f7018c21STomi Valkeinen 				int freq)
657f7018c21STomi Valkeinen {
658f7018c21STomi Valkeinen 	unsigned int m, n, p;
659f7018c21STomi Valkeinen 
660f7018c21STomi Valkeinen 	DBG(__func__)
661f7018c21STomi Valkeinen 
662f7018c21STomi Valkeinen 	DAC1064_calcclock(minfo, freq, minfo->max_pixel_clock, &m, &n, &p);
663f7018c21STomi Valkeinen 	MGAG100_progPixClock(minfo, flags, m, n, p);
664f7018c21STomi Valkeinen }
665f7018c21STomi Valkeinen #endif
666f7018c21STomi Valkeinen 
667f7018c21STomi Valkeinen #ifdef CONFIG_FB_MATROX_MYSTIQUE
668f7018c21STomi Valkeinen static int MGA1064_preinit(struct matrox_fb_info *minfo)
669f7018c21STomi Valkeinen {
670f7018c21STomi Valkeinen 	static const int vxres_mystique[] = { 512,        640, 768,  800,  832,  960,
671f7018c21STomi Valkeinen 					     1024, 1152, 1280,      1600, 1664, 1920,
672f7018c21STomi Valkeinen 					     2048,    0};
673f7018c21STomi Valkeinen 	struct matrox_hw_state *hw = &minfo->hw;
674f7018c21STomi Valkeinen 
675f7018c21STomi Valkeinen 	DBG(__func__)
676f7018c21STomi Valkeinen 
677f7018c21STomi Valkeinen 	/* minfo->capable.cfb4 = 0; ... preinitialized by 0 */
678f7018c21STomi Valkeinen 	minfo->capable.text = 1;
679f7018c21STomi Valkeinen 	minfo->capable.vxres = vxres_mystique;
680f7018c21STomi Valkeinen 
681f7018c21STomi Valkeinen 	minfo->outputs[0].output = &m1064;
682f7018c21STomi Valkeinen 	minfo->outputs[0].src = minfo->outputs[0].default_src;
683f7018c21STomi Valkeinen 	minfo->outputs[0].data = minfo;
684f7018c21STomi Valkeinen 	minfo->outputs[0].mode = MATROXFB_OUTPUT_MODE_MONITOR;
685f7018c21STomi Valkeinen 
686f7018c21STomi Valkeinen 	if (minfo->devflags.noinit)
687f7018c21STomi Valkeinen 		return 0;	/* do not modify settings */
688f7018c21STomi Valkeinen 	hw->MXoptionReg &= 0xC0000100;
689f7018c21STomi Valkeinen 	hw->MXoptionReg |= 0x00094E20;
690f7018c21STomi Valkeinen 	if (minfo->devflags.novga)
691f7018c21STomi Valkeinen 		hw->MXoptionReg &= ~0x00000100;
692f7018c21STomi Valkeinen 	if (minfo->devflags.nobios)
693f7018c21STomi Valkeinen 		hw->MXoptionReg &= ~0x40000000;
694f7018c21STomi Valkeinen 	if (minfo->devflags.nopciretry)
695f7018c21STomi Valkeinen 		hw->MXoptionReg |=  0x20000000;
696f7018c21STomi Valkeinen 	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, hw->MXoptionReg);
697f7018c21STomi Valkeinen 	mga_setr(M_SEQ_INDEX, 0x01, 0x20);
698f7018c21STomi Valkeinen 	mga_outl(M_CTLWTST, 0x00000000);
699f7018c21STomi Valkeinen 	udelay(200);
700f7018c21STomi Valkeinen 	mga_outl(M_MACCESS, 0x00008000);
701f7018c21STomi Valkeinen 	udelay(100);
702f7018c21STomi Valkeinen 	mga_outl(M_MACCESS, 0x0000C000);
703f7018c21STomi Valkeinen 	return 0;
704f7018c21STomi Valkeinen }
705f7018c21STomi Valkeinen 
706f7018c21STomi Valkeinen static void MGA1064_reset(struct matrox_fb_info *minfo)
707f7018c21STomi Valkeinen {
708f7018c21STomi Valkeinen 
709f7018c21STomi Valkeinen 	DBG(__func__);
710f7018c21STomi Valkeinen 
711f7018c21STomi Valkeinen 	MGA1064_ramdac_init(minfo);
712f7018c21STomi Valkeinen }
713f7018c21STomi Valkeinen #endif
714f7018c21STomi Valkeinen 
715f7018c21STomi Valkeinen #ifdef CONFIG_FB_MATROX_G
716f7018c21STomi Valkeinen static void g450_mclk_init(struct matrox_fb_info *minfo)
717f7018c21STomi Valkeinen {
718f7018c21STomi Valkeinen 	/* switch all clocks to PCI source */
719f7018c21STomi Valkeinen 	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg | 4);
720f7018c21STomi Valkeinen 	pci_write_config_dword(minfo->pcidev, PCI_OPTION3_REG, minfo->values.reg.opt3 & ~0x00300C03);
721f7018c21STomi Valkeinen 	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg);
722f7018c21STomi Valkeinen 
723f7018c21STomi Valkeinen 	if (((minfo->values.reg.opt3 & 0x000003) == 0x000003) ||
724f7018c21STomi Valkeinen 	    ((minfo->values.reg.opt3 & 0x000C00) == 0x000C00) ||
725f7018c21STomi Valkeinen 	    ((minfo->values.reg.opt3 & 0x300000) == 0x300000)) {
726f7018c21STomi Valkeinen 		matroxfb_g450_setclk(minfo, minfo->values.pll.video, M_VIDEO_PLL);
727f7018c21STomi Valkeinen 	} else {
728f7018c21STomi Valkeinen 		unsigned long flags;
729f7018c21STomi Valkeinen 		unsigned int pwr;
730f7018c21STomi Valkeinen 
731f7018c21STomi Valkeinen 		matroxfb_DAC_lock_irqsave(flags);
732f7018c21STomi Valkeinen 		pwr = inDAC1064(minfo, M1064_XPWRCTRL) & ~0x02;
733f7018c21STomi Valkeinen 		outDAC1064(minfo, M1064_XPWRCTRL, pwr);
734f7018c21STomi Valkeinen 		matroxfb_DAC_unlock_irqrestore(flags);
735f7018c21STomi Valkeinen 	}
736f7018c21STomi Valkeinen 	matroxfb_g450_setclk(minfo, minfo->values.pll.system, M_SYSTEM_PLL);
737f7018c21STomi Valkeinen 
738f7018c21STomi Valkeinen 	/* switch clocks to their real PLL source(s) */
739f7018c21STomi Valkeinen 	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg | 4);
740f7018c21STomi Valkeinen 	pci_write_config_dword(minfo->pcidev, PCI_OPTION3_REG, minfo->values.reg.opt3);
741f7018c21STomi Valkeinen 	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg);
742f7018c21STomi Valkeinen 
743f7018c21STomi Valkeinen }
744f7018c21STomi Valkeinen 
745f7018c21STomi Valkeinen static void g450_memory_init(struct matrox_fb_info *minfo)
746f7018c21STomi Valkeinen {
747f7018c21STomi Valkeinen 	/* disable memory refresh */
748f7018c21STomi Valkeinen 	minfo->hw.MXoptionReg &= ~0x001F8000;
749f7018c21STomi Valkeinen 	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg);
750f7018c21STomi Valkeinen 
751f7018c21STomi Valkeinen 	/* set memory interface parameters */
752f7018c21STomi Valkeinen 	minfo->hw.MXoptionReg &= ~0x00207E00;
753f7018c21STomi Valkeinen 	minfo->hw.MXoptionReg |= 0x00207E00 & minfo->values.reg.opt;
754f7018c21STomi Valkeinen 	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg);
755f7018c21STomi Valkeinen 	pci_write_config_dword(minfo->pcidev, PCI_OPTION2_REG, minfo->values.reg.opt2);
756f7018c21STomi Valkeinen 
757f7018c21STomi Valkeinen 	mga_outl(M_CTLWTST, minfo->values.reg.mctlwtst);
758f7018c21STomi Valkeinen 
759f7018c21STomi Valkeinen 	/* first set up memory interface with disabled memory interface clocks */
760f7018c21STomi Valkeinen 	pci_write_config_dword(minfo->pcidev, PCI_MEMMISC_REG, minfo->values.reg.memmisc & ~0x80000000U);
761f7018c21STomi Valkeinen 	mga_outl(M_MEMRDBK, minfo->values.reg.memrdbk);
762f7018c21STomi Valkeinen 	mga_outl(M_MACCESS, minfo->values.reg.maccess);
763f7018c21STomi Valkeinen 	/* start memory clocks */
764f7018c21STomi Valkeinen 	pci_write_config_dword(minfo->pcidev, PCI_MEMMISC_REG, minfo->values.reg.memmisc | 0x80000000U);
765f7018c21STomi Valkeinen 
766f7018c21STomi Valkeinen 	udelay(200);
767f7018c21STomi Valkeinen 
768f7018c21STomi Valkeinen 	if (minfo->values.memory.ddr && (!minfo->values.memory.emrswen || !minfo->values.memory.dll)) {
769f7018c21STomi Valkeinen 		mga_outl(M_MEMRDBK, minfo->values.reg.memrdbk & ~0x1000);
770f7018c21STomi Valkeinen 	}
771f7018c21STomi Valkeinen 	mga_outl(M_MACCESS, minfo->values.reg.maccess | 0x8000);
772f7018c21STomi Valkeinen 
773f7018c21STomi Valkeinen 	udelay(200);
774f7018c21STomi Valkeinen 
775f7018c21STomi Valkeinen 	minfo->hw.MXoptionReg |= 0x001F8000 & minfo->values.reg.opt;
776f7018c21STomi Valkeinen 	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg);
777f7018c21STomi Valkeinen 
778f7018c21STomi Valkeinen 	/* value is written to memory chips only if old != new */
779f7018c21STomi Valkeinen 	mga_outl(M_PLNWT, 0);
780f7018c21STomi Valkeinen 	mga_outl(M_PLNWT, ~0);
781f7018c21STomi Valkeinen 
782f7018c21STomi Valkeinen 	if (minfo->values.reg.mctlwtst != minfo->values.reg.mctlwtst_core) {
783f7018c21STomi Valkeinen 		mga_outl(M_CTLWTST, minfo->values.reg.mctlwtst_core);
784f7018c21STomi Valkeinen 	}
785f7018c21STomi Valkeinen 
786f7018c21STomi Valkeinen }
787f7018c21STomi Valkeinen 
788f7018c21STomi Valkeinen static void g450_preinit(struct matrox_fb_info *minfo)
789f7018c21STomi Valkeinen {
790f7018c21STomi Valkeinen 	u_int32_t c2ctl;
791f7018c21STomi Valkeinen 	u_int8_t curctl;
792f7018c21STomi Valkeinen 	u_int8_t c1ctl;
793f7018c21STomi Valkeinen 
794f7018c21STomi Valkeinen 	/* minfo->hw.MXoptionReg = minfo->values.reg.opt; */
795f7018c21STomi Valkeinen 	minfo->hw.MXoptionReg &= 0xC0000100;
796f7018c21STomi Valkeinen 	minfo->hw.MXoptionReg |= 0x00000020;
797f7018c21STomi Valkeinen 	if (minfo->devflags.novga)
798f7018c21STomi Valkeinen 		minfo->hw.MXoptionReg &= ~0x00000100;
799f7018c21STomi Valkeinen 	if (minfo->devflags.nobios)
800f7018c21STomi Valkeinen 		minfo->hw.MXoptionReg &= ~0x40000000;
801f7018c21STomi Valkeinen 	if (minfo->devflags.nopciretry)
802f7018c21STomi Valkeinen 		minfo->hw.MXoptionReg |=  0x20000000;
803f7018c21STomi Valkeinen 	minfo->hw.MXoptionReg |= minfo->values.reg.opt & 0x03400040;
804f7018c21STomi Valkeinen 	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg);
805f7018c21STomi Valkeinen 
806f7018c21STomi Valkeinen 	/* Init system clocks */
807f7018c21STomi Valkeinen 
808f7018c21STomi Valkeinen 	/* stop crtc2 */
809f7018c21STomi Valkeinen 	c2ctl = mga_inl(M_C2CTL);
810f7018c21STomi Valkeinen 	mga_outl(M_C2CTL, c2ctl & ~1);
811f7018c21STomi Valkeinen 	/* stop cursor */
812f7018c21STomi Valkeinen 	curctl = inDAC1064(minfo, M1064_XCURCTRL);
813f7018c21STomi Valkeinen 	outDAC1064(minfo, M1064_XCURCTRL, 0);
814f7018c21STomi Valkeinen 	/* stop crtc1 */
815f7018c21STomi Valkeinen 	c1ctl = mga_readr(M_SEQ_INDEX, 1);
816f7018c21STomi Valkeinen 	mga_setr(M_SEQ_INDEX, 1, c1ctl | 0x20);
817f7018c21STomi Valkeinen 
818f7018c21STomi Valkeinen 	g450_mclk_init(minfo);
819f7018c21STomi Valkeinen 	g450_memory_init(minfo);
820f7018c21STomi Valkeinen 
821f7018c21STomi Valkeinen 	/* set legacy VGA clock sources for DOSEmu or VMware... */
822f7018c21STomi Valkeinen 	matroxfb_g450_setclk(minfo, 25175, M_PIXEL_PLL_A);
823f7018c21STomi Valkeinen 	matroxfb_g450_setclk(minfo, 28322, M_PIXEL_PLL_B);
824f7018c21STomi Valkeinen 
825f7018c21STomi Valkeinen 	/* restore crtc1 */
826f7018c21STomi Valkeinen 	mga_setr(M_SEQ_INDEX, 1, c1ctl);
827f7018c21STomi Valkeinen 
828f7018c21STomi Valkeinen 	/* restore cursor */
829f7018c21STomi Valkeinen 	outDAC1064(minfo, M1064_XCURCTRL, curctl);
830f7018c21STomi Valkeinen 
831f7018c21STomi Valkeinen 	/* restore crtc2 */
832f7018c21STomi Valkeinen 	mga_outl(M_C2CTL, c2ctl);
833f7018c21STomi Valkeinen 
834f7018c21STomi Valkeinen 	return;
835f7018c21STomi Valkeinen }
836f7018c21STomi Valkeinen 
837f7018c21STomi Valkeinen static int MGAG100_preinit(struct matrox_fb_info *minfo)
838f7018c21STomi Valkeinen {
839f7018c21STomi Valkeinen 	static const int vxres_g100[] = {  512,        640, 768,  800,  832,  960,
840f7018c21STomi Valkeinen                                           1024, 1152, 1280,      1600, 1664, 1920,
841f7018c21STomi Valkeinen                                           2048, 0};
842f7018c21STomi Valkeinen 	struct matrox_hw_state *hw = &minfo->hw;
843f7018c21STomi Valkeinen 
844f7018c21STomi Valkeinen         u_int32_t reg50;
845f7018c21STomi Valkeinen #if 0
846f7018c21STomi Valkeinen 	u_int32_t q;
847f7018c21STomi Valkeinen #endif
848f7018c21STomi Valkeinen 
849f7018c21STomi Valkeinen 	DBG(__func__)
850f7018c21STomi Valkeinen 
851f7018c21STomi Valkeinen 	/* there are some instabilities if in_div > 19 && vco < 61000 */
852f7018c21STomi Valkeinen 	if (minfo->devflags.g450dac) {
853f7018c21STomi Valkeinen 		minfo->features.pll.vco_freq_min = 130000;	/* my sample: >118 */
854f7018c21STomi Valkeinen 	} else {
855f7018c21STomi Valkeinen 		minfo->features.pll.vco_freq_min = 62000;
856f7018c21STomi Valkeinen 	}
857f7018c21STomi Valkeinen 	if (!minfo->features.pll.ref_freq) {
858f7018c21STomi Valkeinen 		minfo->features.pll.ref_freq	 = 27000;
859f7018c21STomi Valkeinen 	}
860f7018c21STomi Valkeinen 	minfo->features.pll.feed_div_min = 7;
861f7018c21STomi Valkeinen 	minfo->features.pll.feed_div_max = 127;
862f7018c21STomi Valkeinen 	minfo->features.pll.in_div_min	 = 1;
863f7018c21STomi Valkeinen 	minfo->features.pll.in_div_max	 = 31;
864f7018c21STomi Valkeinen 	minfo->features.pll.post_shift_max = 3;
865f7018c21STomi Valkeinen 	minfo->features.DAC1064.xvrefctrl = DAC1064_XVREFCTRL_G100_DEFAULT;
866f7018c21STomi Valkeinen 	/* minfo->capable.cfb4 = 0; ... preinitialized by 0 */
867f7018c21STomi Valkeinen 	minfo->capable.text = 1;
868f7018c21STomi Valkeinen 	minfo->capable.vxres = vxres_g100;
869f7018c21STomi Valkeinen 	minfo->capable.plnwt = minfo->devflags.accelerator == FB_ACCEL_MATROX_MGAG100
870f7018c21STomi Valkeinen 			? minfo->devflags.sgram : 1;
871f7018c21STomi Valkeinen 
872f7018c21STomi Valkeinen 	if (minfo->devflags.g450dac) {
873f7018c21STomi Valkeinen 		minfo->outputs[0].output = &g450out;
874f7018c21STomi Valkeinen 	} else {
875f7018c21STomi Valkeinen 		minfo->outputs[0].output = &m1064;
876f7018c21STomi Valkeinen 	}
877f7018c21STomi Valkeinen 	minfo->outputs[0].src = minfo->outputs[0].default_src;
878f7018c21STomi Valkeinen 	minfo->outputs[0].data = minfo;
879f7018c21STomi Valkeinen 	minfo->outputs[0].mode = MATROXFB_OUTPUT_MODE_MONITOR;
880f7018c21STomi Valkeinen 
881f7018c21STomi Valkeinen 	if (minfo->devflags.g450dac) {
882f7018c21STomi Valkeinen 		/* we must do this always, BIOS does not do it for us
883f7018c21STomi Valkeinen 		   and accelerator dies without it */
884f7018c21STomi Valkeinen 		mga_outl(0x1C0C, 0);
885f7018c21STomi Valkeinen 	}
886f7018c21STomi Valkeinen 	if (minfo->devflags.noinit)
887f7018c21STomi Valkeinen 		return 0;
888f7018c21STomi Valkeinen 	if (minfo->devflags.g450dac) {
889f7018c21STomi Valkeinen 		g450_preinit(minfo);
890f7018c21STomi Valkeinen 		return 0;
891f7018c21STomi Valkeinen 	}
892f7018c21STomi Valkeinen 	hw->MXoptionReg &= 0xC0000100;
893f7018c21STomi Valkeinen 	hw->MXoptionReg |= 0x00000020;
894f7018c21STomi Valkeinen 	if (minfo->devflags.novga)
895f7018c21STomi Valkeinen 		hw->MXoptionReg &= ~0x00000100;
896f7018c21STomi Valkeinen 	if (minfo->devflags.nobios)
897f7018c21STomi Valkeinen 		hw->MXoptionReg &= ~0x40000000;
898f7018c21STomi Valkeinen 	if (minfo->devflags.nopciretry)
899f7018c21STomi Valkeinen 		hw->MXoptionReg |=  0x20000000;
900f7018c21STomi Valkeinen 	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, hw->MXoptionReg);
901f7018c21STomi Valkeinen 	DAC1064_setmclk(minfo, DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV3 | DAC1064_OPT_SCLK_PCI, 133333);
902f7018c21STomi Valkeinen 
903f7018c21STomi Valkeinen 	if (minfo->devflags.accelerator == FB_ACCEL_MATROX_MGAG100) {
904f7018c21STomi Valkeinen 		pci_read_config_dword(minfo->pcidev, PCI_OPTION2_REG, &reg50);
905f7018c21STomi Valkeinen 		reg50 &= ~0x3000;
906f7018c21STomi Valkeinen 		pci_write_config_dword(minfo->pcidev, PCI_OPTION2_REG, reg50);
907f7018c21STomi Valkeinen 
908f7018c21STomi Valkeinen 		hw->MXoptionReg |= 0x1080;
909f7018c21STomi Valkeinen 		pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, hw->MXoptionReg);
910f7018c21STomi Valkeinen 		mga_outl(M_CTLWTST, minfo->values.reg.mctlwtst);
911f7018c21STomi Valkeinen 		udelay(100);
912f7018c21STomi Valkeinen 		mga_outb(0x1C05, 0x00);
913f7018c21STomi Valkeinen 		mga_outb(0x1C05, 0x80);
914f7018c21STomi Valkeinen 		udelay(100);
915f7018c21STomi Valkeinen 		mga_outb(0x1C05, 0x40);
916f7018c21STomi Valkeinen 		mga_outb(0x1C05, 0xC0);
917f7018c21STomi Valkeinen 		udelay(100);
918f7018c21STomi Valkeinen 		reg50 &= ~0xFF;
919f7018c21STomi Valkeinen 		reg50 |=  0x07;
920f7018c21STomi Valkeinen 		pci_write_config_dword(minfo->pcidev, PCI_OPTION2_REG, reg50);
921f7018c21STomi Valkeinen 		/* it should help with G100 */
922f7018c21STomi Valkeinen 		mga_outb(M_GRAPHICS_INDEX, 6);
923f7018c21STomi Valkeinen 		mga_outb(M_GRAPHICS_DATA, (mga_inb(M_GRAPHICS_DATA) & 3) | 4);
924f7018c21STomi Valkeinen 		mga_setr(M_EXTVGA_INDEX, 0x03, 0x81);
925f7018c21STomi Valkeinen 		mga_setr(M_EXTVGA_INDEX, 0x04, 0x00);
926f7018c21STomi Valkeinen 		mga_writeb(minfo->video.vbase, 0x0000, 0xAA);
927f7018c21STomi Valkeinen 		mga_writeb(minfo->video.vbase, 0x0800, 0x55);
928f7018c21STomi Valkeinen 		mga_writeb(minfo->video.vbase, 0x4000, 0x55);
929f7018c21STomi Valkeinen #if 0
930f7018c21STomi Valkeinen 		if (mga_readb(minfo->video.vbase, 0x0000) != 0xAA) {
931f7018c21STomi Valkeinen 			hw->MXoptionReg &= ~0x1000;
932f7018c21STomi Valkeinen 		}
933f7018c21STomi Valkeinen #endif
934f7018c21STomi Valkeinen 		hw->MXoptionReg |= 0x00078020;
935f7018c21STomi Valkeinen 	} else if (minfo->devflags.accelerator == FB_ACCEL_MATROX_MGAG200) {
936f7018c21STomi Valkeinen 		pci_read_config_dword(minfo->pcidev, PCI_OPTION2_REG, &reg50);
937f7018c21STomi Valkeinen 		reg50 &= ~0x3000;
938f7018c21STomi Valkeinen 		pci_write_config_dword(minfo->pcidev, PCI_OPTION2_REG, reg50);
939f7018c21STomi Valkeinen 
940f7018c21STomi Valkeinen 		if (minfo->devflags.memtype == -1)
941f7018c21STomi Valkeinen 			hw->MXoptionReg |= minfo->values.reg.opt & 0x1C00;
942f7018c21STomi Valkeinen 		else
943f7018c21STomi Valkeinen 			hw->MXoptionReg |= (minfo->devflags.memtype & 7) << 10;
944f7018c21STomi Valkeinen 		if (minfo->devflags.sgram)
945f7018c21STomi Valkeinen 			hw->MXoptionReg |= 0x4000;
946f7018c21STomi Valkeinen 		mga_outl(M_CTLWTST, minfo->values.reg.mctlwtst);
947f7018c21STomi Valkeinen 		mga_outl(M_MEMRDBK, minfo->values.reg.memrdbk);
948f7018c21STomi Valkeinen 		udelay(200);
949f7018c21STomi Valkeinen 		mga_outl(M_MACCESS, 0x00000000);
950f7018c21STomi Valkeinen 		mga_outl(M_MACCESS, 0x00008000);
951f7018c21STomi Valkeinen 		udelay(100);
952f7018c21STomi Valkeinen 		mga_outw(M_MEMRDBK, minfo->values.reg.memrdbk);
953f7018c21STomi Valkeinen 		hw->MXoptionReg |= 0x00078020;
954f7018c21STomi Valkeinen 	} else {
955f7018c21STomi Valkeinen 		pci_read_config_dword(minfo->pcidev, PCI_OPTION2_REG, &reg50);
956f7018c21STomi Valkeinen 		reg50 &= ~0x00000100;
957f7018c21STomi Valkeinen 		reg50 |=  0x00000000;
958f7018c21STomi Valkeinen 		pci_write_config_dword(minfo->pcidev, PCI_OPTION2_REG, reg50);
959f7018c21STomi Valkeinen 
960f7018c21STomi Valkeinen 		if (minfo->devflags.memtype == -1)
961f7018c21STomi Valkeinen 			hw->MXoptionReg |= minfo->values.reg.opt & 0x1C00;
962f7018c21STomi Valkeinen 		else
963f7018c21STomi Valkeinen 			hw->MXoptionReg |= (minfo->devflags.memtype & 7) << 10;
964f7018c21STomi Valkeinen 		if (minfo->devflags.sgram)
965f7018c21STomi Valkeinen 			hw->MXoptionReg |= 0x4000;
966f7018c21STomi Valkeinen 		mga_outl(M_CTLWTST, minfo->values.reg.mctlwtst);
967f7018c21STomi Valkeinen 		mga_outl(M_MEMRDBK, minfo->values.reg.memrdbk);
968f7018c21STomi Valkeinen 		udelay(200);
969f7018c21STomi Valkeinen 		mga_outl(M_MACCESS, 0x00000000);
970f7018c21STomi Valkeinen 		mga_outl(M_MACCESS, 0x00008000);
971f7018c21STomi Valkeinen 		udelay(100);
972f7018c21STomi Valkeinen 		mga_outl(M_MEMRDBK, minfo->values.reg.memrdbk);
973f7018c21STomi Valkeinen 		hw->MXoptionReg |= 0x00040020;
974f7018c21STomi Valkeinen 	}
975f7018c21STomi Valkeinen 	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, hw->MXoptionReg);
976f7018c21STomi Valkeinen 	return 0;
977f7018c21STomi Valkeinen }
978f7018c21STomi Valkeinen 
979f7018c21STomi Valkeinen static void MGAG100_reset(struct matrox_fb_info *minfo)
980f7018c21STomi Valkeinen {
981f7018c21STomi Valkeinen 	u_int8_t b;
982f7018c21STomi Valkeinen 	struct matrox_hw_state *hw = &minfo->hw;
983f7018c21STomi Valkeinen 
984f7018c21STomi Valkeinen 	DBG(__func__)
985f7018c21STomi Valkeinen 
986f7018c21STomi Valkeinen 	{
987f7018c21STomi Valkeinen #ifdef G100_BROKEN_IBM_82351
988f7018c21STomi Valkeinen 		u_int32_t d;
989f7018c21STomi Valkeinen 
990f7018c21STomi Valkeinen 		find 1014/22 (IBM/82351); /* if found and bridging Matrox, do some strange stuff */
991f7018c21STomi Valkeinen 		pci_read_config_byte(ibm, PCI_SECONDARY_BUS, &b);
992f7018c21STomi Valkeinen 		if (b == minfo->pcidev->bus->number) {
993f7018c21STomi Valkeinen 			pci_write_config_byte(ibm, PCI_COMMAND+1, 0);	/* disable back-to-back & SERR */
994f7018c21STomi Valkeinen 			pci_write_config_byte(ibm, 0x41, 0xF4);		/* ??? */
995f7018c21STomi Valkeinen 			pci_write_config_byte(ibm, PCI_IO_BASE, 0xF0);	/* ??? */
996f7018c21STomi Valkeinen 			pci_write_config_byte(ibm, PCI_IO_LIMIT, 0x00);	/* ??? */
997f7018c21STomi Valkeinen 		}
998f7018c21STomi Valkeinen #endif
999f7018c21STomi Valkeinen 		if (!minfo->devflags.noinit) {
1000f7018c21STomi Valkeinen 			if (x7AF4 & 8) {
1001f7018c21STomi Valkeinen 				hw->MXoptionReg |= 0x40;	/* FIXME... */
1002f7018c21STomi Valkeinen 				pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, hw->MXoptionReg);
1003f7018c21STomi Valkeinen 			}
1004f7018c21STomi Valkeinen 			mga_setr(M_EXTVGA_INDEX, 0x06, 0x00);
1005f7018c21STomi Valkeinen 		}
1006f7018c21STomi Valkeinen 	}
1007f7018c21STomi Valkeinen 	if (minfo->devflags.g450dac) {
1008f7018c21STomi Valkeinen 		/* either leave MCLK as is... or they were set in preinit */
1009f7018c21STomi Valkeinen 		hw->DACclk[3] = inDAC1064(minfo, DAC1064_XSYSPLLM);
1010f7018c21STomi Valkeinen 		hw->DACclk[4] = inDAC1064(minfo, DAC1064_XSYSPLLN);
1011f7018c21STomi Valkeinen 		hw->DACclk[5] = inDAC1064(minfo, DAC1064_XSYSPLLP);
1012f7018c21STomi Valkeinen 	} else {
1013f7018c21STomi Valkeinen 		DAC1064_setmclk(minfo, DAC1064_OPT_RESERVED | DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV1 | DAC1064_OPT_SCLK_PLL, 133333);
1014f7018c21STomi Valkeinen 	}
1015f7018c21STomi Valkeinen 	if (minfo->devflags.accelerator == FB_ACCEL_MATROX_MGAG400) {
1016f7018c21STomi Valkeinen 		if (minfo->devflags.dfp_type == -1) {
1017f7018c21STomi Valkeinen 			minfo->devflags.dfp_type = inDAC1064(minfo, 0x1F);
1018f7018c21STomi Valkeinen 		}
1019f7018c21STomi Valkeinen 	}
1020f7018c21STomi Valkeinen 	if (minfo->devflags.noinit)
1021f7018c21STomi Valkeinen 		return;
1022f7018c21STomi Valkeinen 	if (minfo->devflags.g450dac) {
1023f7018c21STomi Valkeinen 	} else {
1024f7018c21STomi Valkeinen 		MGAG100_setPixClock(minfo, 4, 25175);
1025f7018c21STomi Valkeinen 		MGAG100_setPixClock(minfo, 5, 28322);
1026f7018c21STomi Valkeinen 		if (x7AF4 & 0x10) {
1027f7018c21STomi Valkeinen 			b = inDAC1064(minfo, M1064_XGENIODATA) & ~1;
1028f7018c21STomi Valkeinen 			outDAC1064(minfo, M1064_XGENIODATA, b);
1029f7018c21STomi Valkeinen 			b = inDAC1064(minfo, M1064_XGENIOCTRL) | 1;
1030f7018c21STomi Valkeinen 			outDAC1064(minfo, M1064_XGENIOCTRL, b);
1031f7018c21STomi Valkeinen 		}
1032f7018c21STomi Valkeinen 	}
1033f7018c21STomi Valkeinen }
1034f7018c21STomi Valkeinen #endif
1035f7018c21STomi Valkeinen 
1036f7018c21STomi Valkeinen #ifdef CONFIG_FB_MATROX_MYSTIQUE
1037f7018c21STomi Valkeinen static void MGA1064_restore(struct matrox_fb_info *minfo)
1038f7018c21STomi Valkeinen {
1039f7018c21STomi Valkeinen 	int i;
1040f7018c21STomi Valkeinen 	struct matrox_hw_state *hw = &minfo->hw;
1041f7018c21STomi Valkeinen 
1042f7018c21STomi Valkeinen 	CRITFLAGS
1043f7018c21STomi Valkeinen 
1044f7018c21STomi Valkeinen 	DBG(__func__)
1045f7018c21STomi Valkeinen 
1046f7018c21STomi Valkeinen 	CRITBEGIN
1047f7018c21STomi Valkeinen 
1048f7018c21STomi Valkeinen 	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, hw->MXoptionReg);
1049f7018c21STomi Valkeinen 	mga_outb(M_IEN, 0x00);
1050f7018c21STomi Valkeinen 	mga_outb(M_CACHEFLUSH, 0x00);
1051f7018c21STomi Valkeinen 
1052f7018c21STomi Valkeinen 	CRITEND
1053f7018c21STomi Valkeinen 
1054f7018c21STomi Valkeinen 	DAC1064_restore_1(minfo);
1055f7018c21STomi Valkeinen 	matroxfb_vgaHWrestore(minfo);
1056f7018c21STomi Valkeinen 	minfo->crtc1.panpos = -1;
1057f7018c21STomi Valkeinen 	for (i = 0; i < 6; i++)
1058f7018c21STomi Valkeinen 		mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
1059f7018c21STomi Valkeinen 	DAC1064_restore_2(minfo);
1060f7018c21STomi Valkeinen }
1061f7018c21STomi Valkeinen #endif
1062f7018c21STomi Valkeinen 
1063f7018c21STomi Valkeinen #ifdef CONFIG_FB_MATROX_G
1064f7018c21STomi Valkeinen static void MGAG100_restore(struct matrox_fb_info *minfo)
1065f7018c21STomi Valkeinen {
1066f7018c21STomi Valkeinen 	int i;
1067f7018c21STomi Valkeinen 	struct matrox_hw_state *hw = &minfo->hw;
1068f7018c21STomi Valkeinen 
1069f7018c21STomi Valkeinen 	CRITFLAGS
1070f7018c21STomi Valkeinen 
1071f7018c21STomi Valkeinen 	DBG(__func__)
1072f7018c21STomi Valkeinen 
1073f7018c21STomi Valkeinen 	CRITBEGIN
1074f7018c21STomi Valkeinen 
1075f7018c21STomi Valkeinen 	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, hw->MXoptionReg);
1076f7018c21STomi Valkeinen 	CRITEND
1077f7018c21STomi Valkeinen 
1078f7018c21STomi Valkeinen 	DAC1064_restore_1(minfo);
1079f7018c21STomi Valkeinen 	matroxfb_vgaHWrestore(minfo);
1080f7018c21STomi Valkeinen 	if (minfo->devflags.support32MB)
1081f7018c21STomi Valkeinen 		mga_setr(M_EXTVGA_INDEX, 8, hw->CRTCEXT[8]);
1082f7018c21STomi Valkeinen 	minfo->crtc1.panpos = -1;
1083f7018c21STomi Valkeinen 	for (i = 0; i < 6; i++)
1084f7018c21STomi Valkeinen 		mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
1085f7018c21STomi Valkeinen 	DAC1064_restore_2(minfo);
1086f7018c21STomi Valkeinen }
1087f7018c21STomi Valkeinen #endif
1088f7018c21STomi Valkeinen 
1089f7018c21STomi Valkeinen #ifdef CONFIG_FB_MATROX_MYSTIQUE
1090f7018c21STomi Valkeinen struct matrox_switch matrox_mystique = {
1091*a641261eSKees Cook 	.preinit	= MGA1064_preinit,
1092*a641261eSKees Cook 	.reset		= MGA1064_reset,
1093*a641261eSKees Cook 	.init		= MGA1064_init,
1094*a641261eSKees Cook 	.restore	= MGA1064_restore,
1095f7018c21STomi Valkeinen };
1096f7018c21STomi Valkeinen EXPORT_SYMBOL(matrox_mystique);
1097f7018c21STomi Valkeinen #endif
1098f7018c21STomi Valkeinen 
1099f7018c21STomi Valkeinen #ifdef CONFIG_FB_MATROX_G
1100f7018c21STomi Valkeinen struct matrox_switch matrox_G100 = {
1101*a641261eSKees Cook 	.preinit	= MGAG100_preinit,
1102*a641261eSKees Cook 	.reset		= MGAG100_reset,
1103*a641261eSKees Cook 	.init		= MGAG100_init,
1104*a641261eSKees Cook 	.restore	= MGAG100_restore,
1105f7018c21STomi Valkeinen };
1106f7018c21STomi Valkeinen EXPORT_SYMBOL(matrox_G100);
1107f7018c21STomi Valkeinen #endif
1108f7018c21STomi Valkeinen 
1109f7018c21STomi Valkeinen #ifdef NEED_DAC1064
1110f7018c21STomi Valkeinen EXPORT_SYMBOL(DAC1064_global_init);
1111f7018c21STomi Valkeinen EXPORT_SYMBOL(DAC1064_global_restore);
1112f7018c21STomi Valkeinen #endif
1113f7018c21STomi Valkeinen MODULE_LICENSE("GPL");
1114