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, ®50);
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, ®50);
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, ®50);
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