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