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