matroxfb_DAC1064.c 32.5 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
/*
 *
 * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450.
 *
 * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
 *
 * Portions Copyright (c) 2001 Matrox Graphics Inc.
 *
 * Version: 1.65 2002/08/14
 *
 * See matroxfb_base.c for contributors.
 *
 */


#include "matroxfb_DAC1064.h"
#include "matroxfb_misc.h"
#include "matroxfb_accel.h"
#include "g450_pll.h"
#include <linux/matroxfb.h>

#ifdef NEED_DAC1064
#define outDAC1064 matroxfb_DAC_out
#define inDAC1064 matroxfb_DAC_in

#define DAC1064_OPT_SCLK_PCI	0x00
#define DAC1064_OPT_SCLK_PLL	0x01
#define DAC1064_OPT_SCLK_EXT	0x02
#define DAC1064_OPT_SCLK_MASK	0x03
#define DAC1064_OPT_GDIV1	0x04	/* maybe it is GDIV2 on G100 ?! */
#define DAC1064_OPT_GDIV3	0x00
#define DAC1064_OPT_MDIV1	0x08
#define DAC1064_OPT_MDIV2	0x00
#define DAC1064_OPT_RESERVED	0x10

static void DAC1064_calcclock(CPMINFO unsigned int freq, unsigned int fmax, unsigned int* in, unsigned int* feed, unsigned int* post) {
	unsigned int fvco;
	unsigned int p;

40
	DBG(__func__)
L
Linus Torvalds 已提交
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
	
	/* only for devices older than G450 */

	fvco = PLL_calcclock(PMINFO freq, fmax, in, feed, &p);
	
	p = (1 << p) - 1;
	if (fvco <= 100000)
		;
	else if (fvco <= 140000)
		p |= 0x08;
	else if (fvco <= 180000)
		p |= 0x10;
	else
		p |= 0x18;
	*post = p;
}

/* they must be in POS order */
static const unsigned char MGA1064_DAC_regs[] = {
		M1064_XCURADDL, M1064_XCURADDH, M1064_XCURCTRL,
		M1064_XCURCOL0RED, M1064_XCURCOL0GREEN, M1064_XCURCOL0BLUE,
		M1064_XCURCOL1RED, M1064_XCURCOL1GREEN, M1064_XCURCOL1BLUE,
		M1064_XCURCOL2RED, M1064_XCURCOL2GREEN, M1064_XCURCOL2BLUE,
		DAC1064_XVREFCTRL, M1064_XMULCTRL, M1064_XPIXCLKCTRL, M1064_XGENCTRL,
		M1064_XMISCCTRL,
		M1064_XGENIOCTRL, M1064_XGENIODATA, M1064_XZOOMCTRL, M1064_XSENSETEST,
		M1064_XCRCBITSEL,
		M1064_XCOLKEYMASKL, M1064_XCOLKEYMASKH, M1064_XCOLKEYL, M1064_XCOLKEYH };

static const unsigned char MGA1064_DAC[] = {
		0x00, 0x00, M1064_XCURCTRL_DIS,
		0x00, 0x00, 0x00, 	/* black */
		0xFF, 0xFF, 0xFF,	/* white */
		0xFF, 0x00, 0x00,	/* red */
		0x00, 0,
		M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL,
		M1064_XGENCTRL_VS_0 | M1064_XGENCTRL_ALPHA_DIS | M1064_XGENCTRL_BLACK_0IRE | M1064_XGENCTRL_NO_SYNC_ON_GREEN,
		M1064_XMISCCTRL_DAC_8BIT,
		0x00, 0x00, M1064_XZOOMCTRL_1, M1064_XSENSETEST_BCOMP | M1064_XSENSETEST_GCOMP | M1064_XSENSETEST_RCOMP | M1064_XSENSETEST_PDOWN,
		0x00,
		0x00, 0x00, 0xFF, 0xFF};

static void DAC1064_setpclk(WPMINFO unsigned long fout) {
	unsigned int m, n, p;

86
	DBG(__func__)
L
Linus Torvalds 已提交
87

88 89 90 91
	DAC1064_calcclock(PMINFO fout, minfo->max_pixel_clock, &m, &n, &p);
	minfo->hw.DACclk[0] = m;
	minfo->hw.DACclk[1] = n;
	minfo->hw.DACclk[2] = p;
L
Linus Torvalds 已提交
92 93 94 95
}

static void DAC1064_setmclk(WPMINFO int oscinfo, unsigned long fmem) {
	u_int32_t mx;
96
	struct matrox_hw_state *hw = &minfo->hw;
L
Linus Torvalds 已提交
97

98
	DBG(__func__)
L
Linus Torvalds 已提交
99

100
	if (minfo->devflags.noinit) {
L
Linus Torvalds 已提交
101 102 103 104 105 106 107
		/* read MCLK and give up... */
		hw->DACclk[3] = inDAC1064(PMINFO DAC1064_XSYSPLLM);
		hw->DACclk[4] = inDAC1064(PMINFO DAC1064_XSYSPLLN);
		hw->DACclk[5] = inDAC1064(PMINFO DAC1064_XSYSPLLP);
		return;
	}
	mx = hw->MXoptionReg | 0x00000004;
108
	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, mx);
L
Linus Torvalds 已提交
109 110 111 112 113 114 115 116 117 118 119 120 121 122
	mx &= ~0x000000BB;
	if (oscinfo & DAC1064_OPT_GDIV1)
		mx |= 0x00000008;
	if (oscinfo & DAC1064_OPT_MDIV1)
		mx |= 0x00000010;
	if (oscinfo & DAC1064_OPT_RESERVED)
		mx |= 0x00000080;
	if ((oscinfo & DAC1064_OPT_SCLK_MASK) == DAC1064_OPT_SCLK_PLL) {
		/* select PCI clock until we have setup oscilator... */
		int clk;
		unsigned int m, n, p;

		/* powerup system PLL, select PCI clock */
		mx |= 0x00000020;
123
		pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, mx);
L
Linus Torvalds 已提交
124
		mx &= ~0x00000004;
125
		pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, mx);
L
Linus Torvalds 已提交
126 127 128 129 130 131 132 133

		/* !!! you must not access device if MCLK is not running !!!
		   Doing so cause immediate PCI lockup :-( Maybe they should
		   generate ABORT or I/O (parity...) error and Linux should
		   recover from this... (kill driver/process). But world is not
		   perfect... */
		/* (bit 2 of PCI_OPTION_REG must be 0... and bits 0,1 must not
		   select PLL... because of PLL can be stopped at this time) */
134
		DAC1064_calcclock(PMINFO fmem, minfo->max_pixel_clock, &m, &n, &p);
L
Linus Torvalds 已提交
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
		outDAC1064(PMINFO DAC1064_XSYSPLLM, hw->DACclk[3] = m);
		outDAC1064(PMINFO DAC1064_XSYSPLLN, hw->DACclk[4] = n);
		outDAC1064(PMINFO DAC1064_XSYSPLLP, hw->DACclk[5] = p);
		for (clk = 65536; clk; --clk) {
			if (inDAC1064(PMINFO DAC1064_XSYSPLLSTAT) & 0x40)
				break;
		}
		if (!clk)
			printk(KERN_ERR "matroxfb: aiee, SYSPLL not locked\n");
		/* select PLL */
		mx |= 0x00000005;
	} else {
		/* select specified system clock source */
		mx |= oscinfo & DAC1064_OPT_SCLK_MASK;
	}
150
	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, mx);
L
Linus Torvalds 已提交
151
	mx &= ~0x00000004;
152
	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, mx);
L
Linus Torvalds 已提交
153 154 155 156 157 158 159
	hw->MXoptionReg = mx;
}

#ifdef CONFIG_FB_MATROX_G
static void g450_set_plls(WPMINFO2) {
	u_int32_t c2_ctl;
	unsigned int pxc;
160
	struct matrox_hw_state *hw = &minfo->hw;
L
Linus Torvalds 已提交
161 162 163 164 165 166
	int pixelmnp;
	int videomnp;
	
	c2_ctl = hw->crtc2.ctl & ~0x4007;	/* Clear PLL + enable for CRTC2 */
	c2_ctl |= 0x0001;			/* Enable CRTC2 */
	hw->DACreg[POS1064_XPWRCTRL] &= ~0x02;	/* Stop VIDEO PLL */
167 168
	pixelmnp = minfo->crtc1.mnp;
	videomnp = minfo->crtc2.mnp;
L
Linus Torvalds 已提交
169 170 171
	if (videomnp < 0) {
		c2_ctl &= ~0x0001;			/* Disable CRTC2 */
		hw->DACreg[POS1064_XPWRCTRL] &= ~0x10;	/* Powerdown CRTC2 */
172
	} else if (minfo->crtc2.pixclock == minfo->features.pll.ref_freq) {
L
Linus Torvalds 已提交
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
		c2_ctl |=  0x4002;	/* Use reference directly */
	} else if (videomnp == pixelmnp) {
		c2_ctl |=  0x0004;	/* Use pixel PLL */
	} else {
		if (0 == ((videomnp ^ pixelmnp) & 0xFFFFFF00)) {
			/* PIXEL and VIDEO PLL must not use same frequency. We modify N
			   of PIXEL PLL in such case because of VIDEO PLL may be source
			   of TVO clocks, and chroma subcarrier is derived from its
			   pixel clocks */
			pixelmnp += 0x000100;
		}
		c2_ctl |=  0x0006;	/* Use video PLL */
		hw->DACreg[POS1064_XPWRCTRL] |= 0x02;
		
		outDAC1064(PMINFO M1064_XPWRCTRL, hw->DACreg[POS1064_XPWRCTRL]);
		matroxfb_g450_setpll_cond(PMINFO videomnp, M_VIDEO_PLL);
	}

	hw->DACreg[POS1064_XPIXCLKCTRL] &= ~M1064_XPIXCLKCTRL_PLL_UP;
	if (pixelmnp >= 0) {
		hw->DACreg[POS1064_XPIXCLKCTRL] |= M1064_XPIXCLKCTRL_PLL_UP;
		
		outDAC1064(PMINFO M1064_XPIXCLKCTRL, hw->DACreg[POS1064_XPIXCLKCTRL]);
		matroxfb_g450_setpll_cond(PMINFO pixelmnp, M_PIXEL_PLL_C);
	}
	if (c2_ctl != hw->crtc2.ctl) {
		hw->crtc2.ctl = c2_ctl;
		mga_outl(0x3C10, c2_ctl);
	}

203 204 205
	pxc = minfo->crtc1.pixclock;
	if (pxc == 0 || minfo->outputs[2].src == MATROXFB_SRC_CRTC2) {
		pxc = minfo->crtc2.pixclock;
L
Linus Torvalds 已提交
206
	}
207
	if (minfo->chip == MGA_G550) {
L
Linus Torvalds 已提交
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
		if (pxc < 45000) {
			hw->DACreg[POS1064_XPANMODE] = 0x00;	/* 0-50 */
		} else if (pxc < 55000) {
			hw->DACreg[POS1064_XPANMODE] = 0x08;	/* 34-62 */
		} else if (pxc < 70000) {
			hw->DACreg[POS1064_XPANMODE] = 0x10;	/* 42-78 */
		} else if (pxc < 85000) {
			hw->DACreg[POS1064_XPANMODE] = 0x18;	/* 62-92 */
		} else if (pxc < 100000) {
			hw->DACreg[POS1064_XPANMODE] = 0x20;	/* 74-108 */
		} else if (pxc < 115000) {
			hw->DACreg[POS1064_XPANMODE] = 0x28;	/* 94-122 */
		} else if (pxc < 125000) {
			hw->DACreg[POS1064_XPANMODE] = 0x30;	/* 108-132 */
		} else {
			hw->DACreg[POS1064_XPANMODE] = 0x38;	/* 120-168 */
		}
	} else {
		/* G450 */
		if (pxc < 45000) {
			hw->DACreg[POS1064_XPANMODE] = 0x00;	/* 0-54 */
		} else if (pxc < 65000) {
			hw->DACreg[POS1064_XPANMODE] = 0x08;	/* 38-70 */
		} else if (pxc < 85000) {
			hw->DACreg[POS1064_XPANMODE] = 0x10;	/* 56-96 */
		} else if (pxc < 105000) {
			hw->DACreg[POS1064_XPANMODE] = 0x18;	/* 80-114 */
		} else if (pxc < 135000) {
			hw->DACreg[POS1064_XPANMODE] = 0x20;	/* 102-144 */
		} else if (pxc < 160000) {
			hw->DACreg[POS1064_XPANMODE] = 0x28;	/* 132-166 */
		} else if (pxc < 175000) {
			hw->DACreg[POS1064_XPANMODE] = 0x30;	/* 154-182 */
		} else {
			hw->DACreg[POS1064_XPANMODE] = 0x38;	/* 170-204 */
		}
	}
}
#endif

void DAC1064_global_init(WPMINFO2) {
249
	struct matrox_hw_state *hw = &minfo->hw;
L
Linus Torvalds 已提交
250 251 252 253 254

	hw->DACreg[POS1064_XMISCCTRL] &= M1064_XMISCCTRL_DAC_WIDTHMASK;
	hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_LUT_EN;
	hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL;
#ifdef CONFIG_FB_MATROX_G
255
	if (minfo->devflags.g450dac) {
L
Linus Torvalds 已提交
256 257 258
		hw->DACreg[POS1064_XPWRCTRL] = 0x1F;	/* powerup everything */
		hw->DACreg[POS1064_XOUTPUTCONN] = 0x00;	/* disable outputs */
		hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_DAC_EN;
259
		switch (minfo->outputs[0].src) {
L
Linus Torvalds 已提交
260 261 262 263 264 265 266 267
			case MATROXFB_SRC_CRTC1:
			case MATROXFB_SRC_CRTC2:
				hw->DACreg[POS1064_XOUTPUTCONN] |= 0x01;	/* enable output; CRTC1/2 selection is in CRTC2 ctl */
				break;
			case MATROXFB_SRC_NONE:
				hw->DACreg[POS1064_XMISCCTRL] &= ~M1064_XMISCCTRL_DAC_EN;
				break;
		}
268
		switch (minfo->outputs[1].src) {
L
Linus Torvalds 已提交
269 270 271 272
			case MATROXFB_SRC_CRTC1:
				hw->DACreg[POS1064_XOUTPUTCONN] |= 0x04;
				break;
			case MATROXFB_SRC_CRTC2:
273
				if (minfo->outputs[1].mode == MATROXFB_OUTPUT_MODE_MONITOR) {
L
Linus Torvalds 已提交
274 275 276 277 278 279 280 281 282
					hw->DACreg[POS1064_XOUTPUTCONN] |= 0x08;
				} else {
					hw->DACreg[POS1064_XOUTPUTCONN] |= 0x0C;
				}
				break;
			case MATROXFB_SRC_NONE:
				hw->DACreg[POS1064_XPWRCTRL] &= ~0x01;		/* Poweroff DAC2 */
				break;
		}
283
		switch (minfo->outputs[2].src) {
L
Linus Torvalds 已提交
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
			case MATROXFB_SRC_CRTC1:
				hw->DACreg[POS1064_XOUTPUTCONN] |= 0x20;
				break;
			case MATROXFB_SRC_CRTC2:
				hw->DACreg[POS1064_XOUTPUTCONN] |= 0x40;
				break;
			case MATROXFB_SRC_NONE:
#if 0
				/* HELP! If we boot without DFP connected to DVI, we can
				   poweroff TMDS. But if we boot with DFP connected,
				   TMDS generated clocks are used instead of ALL pixclocks
				   available... If someone knows which register
				   handles it, please reveal this secret to me... */			
				hw->DACreg[POS1064_XPWRCTRL] &= ~0x04;		/* Poweroff TMDS */
#endif				
				break;
		}
		/* Now set timming related variables... */
		g450_set_plls(PMINFO2);
	} else
#endif
	{
306
		if (minfo->outputs[1].src == MATROXFB_SRC_CRTC1) {
L
Linus Torvalds 已提交
307 308
			hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_EXT;
			hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_MAFC12;
309
		} else if (minfo->outputs[1].src == MATROXFB_SRC_CRTC2) {
L
Linus Torvalds 已提交
310
			hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_C2_MAFC12;
311
		} else if (minfo->outputs[2].src == MATROXFB_SRC_CRTC1)
L
Linus Torvalds 已提交
312 313 314 315
			hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_PANELLINK | G400_XMISCCTRL_VDO_MAFC12;
		else
			hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_DIS;

316
		if (minfo->outputs[0].src != MATROXFB_SRC_NONE)
L
Linus Torvalds 已提交
317 318 319 320 321
			hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_DAC_EN;
	}
}

void DAC1064_global_restore(WPMINFO2) {
322
	struct matrox_hw_state *hw = &minfo->hw;
L
Linus Torvalds 已提交
323 324 325

	outDAC1064(PMINFO M1064_XPIXCLKCTRL, hw->DACreg[POS1064_XPIXCLKCTRL]);
	outDAC1064(PMINFO M1064_XMISCCTRL, hw->DACreg[POS1064_XMISCCTRL]);
326
	if (minfo->devflags.accelerator == FB_ACCEL_MATROX_MGAG400) {
L
Linus Torvalds 已提交
327
		outDAC1064(PMINFO 0x20, 0x04);
328 329
		outDAC1064(PMINFO 0x1F, minfo->devflags.dfp_type);
		if (minfo->devflags.g450dac) {
L
Linus Torvalds 已提交
330 331 332 333 334 335 336 337 338
			outDAC1064(PMINFO M1064_XSYNCCTRL, 0xCC);
			outDAC1064(PMINFO M1064_XPWRCTRL, hw->DACreg[POS1064_XPWRCTRL]);
			outDAC1064(PMINFO M1064_XPANMODE, hw->DACreg[POS1064_XPANMODE]);
			outDAC1064(PMINFO M1064_XOUTPUTCONN, hw->DACreg[POS1064_XOUTPUTCONN]);
		}
	}
}

static int DAC1064_init_1(WPMINFO struct my_timming* m) {
339
	struct matrox_hw_state *hw = &minfo->hw;
L
Linus Torvalds 已提交
340

341
	DBG(__func__)
L
Linus Torvalds 已提交
342 343

	memcpy(hw->DACreg, MGA1064_DAC, sizeof(MGA1064_DAC_regs));
344
	switch (minfo->fbcon.var.bits_per_pixel) {
L
Linus Torvalds 已提交
345 346 347 348 349
		/* case 4: not supported by MGA1064 DAC */
		case 8:
			hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_8BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
			break;
		case 16:
350
			if (minfo->fbcon.var.green.length == 5)
L
Linus Torvalds 已提交
351 352 353 354 355 356 357 358 359 360 361 362 363
				hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_15BPP_1BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
			else
				hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_16BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
			break;
		case 24:
			hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_24BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
			break;
		case 32:
			hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_32BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
			break;
		default:
			return 1;	/* unsupported depth */
	}
364
	hw->DACreg[POS1064_XVREFCTRL] = minfo->features.DAC1064.xvrefctrl;
L
Linus Torvalds 已提交
365 366 367 368 369 370 371 372 373 374
	hw->DACreg[POS1064_XGENCTRL] &= ~M1064_XGENCTRL_SYNC_ON_GREEN_MASK;
	hw->DACreg[POS1064_XGENCTRL] |= (m->sync & FB_SYNC_ON_GREEN)?M1064_XGENCTRL_SYNC_ON_GREEN:M1064_XGENCTRL_NO_SYNC_ON_GREEN;
	hw->DACreg[POS1064_XCURADDL] = 0;
	hw->DACreg[POS1064_XCURADDH] = 0;

	DAC1064_global_init(PMINFO2);
	return 0;
}

static int DAC1064_init_2(WPMINFO struct my_timming* m) {
375
	struct matrox_hw_state *hw = &minfo->hw;
L
Linus Torvalds 已提交
376

377
	DBG(__func__)
L
Linus Torvalds 已提交
378

379
	if (minfo->fbcon.var.bits_per_pixel > 16) {	/* 256 entries */
L
Linus Torvalds 已提交
380 381 382 383 384 385 386
		int i;

		for (i = 0; i < 256; i++) {
			hw->DACpal[i * 3 + 0] = i;
			hw->DACpal[i * 3 + 1] = i;
			hw->DACpal[i * 3 + 2] = i;
		}
387 388
	} else if (minfo->fbcon.var.bits_per_pixel > 8) {
		if (minfo->fbcon.var.green.length == 5) {	/* 0..31, 128..159 */
L
Linus Torvalds 已提交
389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416
			int i;

			for (i = 0; i < 32; i++) {
				/* with p15 == 0 */
				hw->DACpal[i * 3 + 0] = i << 3;
				hw->DACpal[i * 3 + 1] = i << 3;
				hw->DACpal[i * 3 + 2] = i << 3;
				/* with p15 == 1 */
				hw->DACpal[(i + 128) * 3 + 0] = i << 3;
				hw->DACpal[(i + 128) * 3 + 1] = i << 3;
				hw->DACpal[(i + 128) * 3 + 2] = i << 3;
			}
		} else {
			int i;

			for (i = 0; i < 64; i++) {		/* 0..63 */
				hw->DACpal[i * 3 + 0] = i << 3;
				hw->DACpal[i * 3 + 1] = i << 2;
				hw->DACpal[i * 3 + 2] = i << 3;
			}
		}
	} else {
		memset(hw->DACpal, 0, 768);
	}
	return 0;
}

static void DAC1064_restore_1(WPMINFO2) {
417
	struct matrox_hw_state *hw = &minfo->hw;
L
Linus Torvalds 已提交
418 419 420

	CRITFLAGS

421
	DBG(__func__)
L
Linus Torvalds 已提交
422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450

	CRITBEGIN

	if ((inDAC1064(PMINFO DAC1064_XSYSPLLM) != hw->DACclk[3]) ||
	    (inDAC1064(PMINFO DAC1064_XSYSPLLN) != hw->DACclk[4]) ||
	    (inDAC1064(PMINFO DAC1064_XSYSPLLP) != hw->DACclk[5])) {
		outDAC1064(PMINFO DAC1064_XSYSPLLM, hw->DACclk[3]);
		outDAC1064(PMINFO DAC1064_XSYSPLLN, hw->DACclk[4]);
		outDAC1064(PMINFO DAC1064_XSYSPLLP, hw->DACclk[5]);
	}
	{
		unsigned int i;

		for (i = 0; i < sizeof(MGA1064_DAC_regs); i++) {
			if ((i != POS1064_XPIXCLKCTRL) && (i != POS1064_XMISCCTRL))
				outDAC1064(PMINFO MGA1064_DAC_regs[i], hw->DACreg[i]);
		}
	}

	DAC1064_global_restore(PMINFO2);

	CRITEND
};

static void DAC1064_restore_2(WPMINFO2) {
#ifdef DEBUG
	unsigned int i;
#endif

451
	DBG(__func__)
L
Linus Torvalds 已提交
452 453 454 455

#ifdef DEBUG
	dprintk(KERN_DEBUG "DAC1064regs ");
	for (i = 0; i < sizeof(MGA1064_DAC_regs); i++) {
456
		dprintk("R%02X=%02X ", MGA1064_DAC_regs[i], minfo->hw.DACreg[i]);
457
		if ((i & 0x7) == 0x7) dprintk(KERN_DEBUG "continuing... ");
L
Linus Torvalds 已提交
458
	}
459
	dprintk(KERN_DEBUG "DAC1064clk ");
L
Linus Torvalds 已提交
460
	for (i = 0; i < 6; i++)
461
		dprintk("C%02X=%02X ", i, minfo->hw.DACclk[i]);
L
Linus Torvalds 已提交
462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477
	dprintk("\n");
#endif
}

static int m1064_compute(void* out, struct my_timming* m) {
#define minfo ((struct matrox_fb_info*)out)
	{
		int i;
		int tmout;
		CRITFLAGS

		DAC1064_setpclk(PMINFO m->pixclock);

		CRITBEGIN

		for (i = 0; i < 3; i++)
478
			outDAC1064(PMINFO M1064_XPIXPLLCM + i, minfo->hw.DACclk[i]);
L
Linus Torvalds 已提交
479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521
		for (tmout = 500000; tmout; tmout--) {
			if (inDAC1064(PMINFO M1064_XPIXPLLSTAT) & 0x40)
				break;
			udelay(10);
		};

		CRITEND

		if (!tmout)
			printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n");
	}
#undef minfo
	return 0;
}

static struct matrox_altout m1064 = {
	.name	 = "Primary output",
	.compute = m1064_compute,
};

#ifdef CONFIG_FB_MATROX_G
static int g450_compute(void* out, struct my_timming* m) {
#define minfo ((struct matrox_fb_info*)out)
	if (m->mnp < 0) {
		m->mnp = matroxfb_g450_setclk(PMINFO m->pixclock, (m->crtc == MATROXFB_SRC_CRTC1) ? M_PIXEL_PLL_C : M_VIDEO_PLL);
		if (m->mnp >= 0) {
			m->pixclock = g450_mnp2f(PMINFO m->mnp);
		}
	}
#undef minfo
	return 0;
}

static struct matrox_altout g450out = {
	.name	 = "Primary output",
	.compute = g450_compute,
};
#endif

#endif /* NEED_DAC1064 */

#ifdef CONFIG_FB_MATROX_MYSTIQUE
static int MGA1064_init(WPMINFO struct my_timming* m) {
522
	struct matrox_hw_state *hw = &minfo->hw;
L
Linus Torvalds 已提交
523

524
	DBG(__func__)
L
Linus Torvalds 已提交
525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543

	if (DAC1064_init_1(PMINFO m)) return 1;
	if (matroxfb_vgaHWinit(PMINFO m)) return 1;

	hw->MiscOutReg = 0xCB;
	if (m->sync & FB_SYNC_HOR_HIGH_ACT)
		hw->MiscOutReg &= ~0x40;
	if (m->sync & FB_SYNC_VERT_HIGH_ACT)
		hw->MiscOutReg &= ~0x80;
	if (m->sync & FB_SYNC_COMP_HIGH_ACT) /* should be only FB_SYNC_COMP */
		hw->CRTCEXT[3] |= 0x40;

	if (DAC1064_init_2(PMINFO m)) return 1;
	return 0;
}
#endif

#ifdef CONFIG_FB_MATROX_G
static int MGAG100_init(WPMINFO struct my_timming* m) {
544
	struct matrox_hw_state *hw = &minfo->hw;
L
Linus Torvalds 已提交
545

546
	DBG(__func__)
L
Linus Torvalds 已提交
547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567

	if (DAC1064_init_1(PMINFO m)) return 1;
	hw->MXoptionReg &= ~0x2000;
	if (matroxfb_vgaHWinit(PMINFO m)) return 1;

	hw->MiscOutReg = 0xEF;
	if (m->sync & FB_SYNC_HOR_HIGH_ACT)
		hw->MiscOutReg &= ~0x40;
	if (m->sync & FB_SYNC_VERT_HIGH_ACT)
		hw->MiscOutReg &= ~0x80;
	if (m->sync & FB_SYNC_COMP_HIGH_ACT) /* should be only FB_SYNC_COMP */
		hw->CRTCEXT[3] |= 0x40;

	if (DAC1064_init_2(PMINFO m)) return 1;
	return 0;
}
#endif	/* G */

#ifdef CONFIG_FB_MATROX_MYSTIQUE
static void MGA1064_ramdac_init(WPMINFO2) {

568
	DBG(__func__)
L
Linus Torvalds 已提交
569

570 571 572 573 574 575 576 577 578
	/* minfo->features.DAC1064.vco_freq_min = 120000; */
	minfo->features.pll.vco_freq_min = 62000;
	minfo->features.pll.ref_freq	 = 14318;
	minfo->features.pll.feed_div_min = 100;
	minfo->features.pll.feed_div_max = 127;
	minfo->features.pll.in_div_min	 = 1;
	minfo->features.pll.in_div_max	 = 31;
	minfo->features.pll.post_shift_max = 3;
	minfo->features.DAC1064.xvrefctrl = DAC1064_XVREFCTRL_EXTERNAL;
L
Linus Torvalds 已提交
579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596
	/* maybe cmdline MCLK= ?, doc says gclk=44MHz, mclk=66MHz... it was 55/83 with old values */
	DAC1064_setmclk(PMINFO DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV3 | DAC1064_OPT_SCLK_PLL, 133333);
}
#endif

#ifdef CONFIG_FB_MATROX_G
/* BIOS environ */
static int x7AF4 = 0x10;	/* flags, maybe 0x10 = SDRAM, 0x00 = SGRAM??? */
				/* G100 wants 0x10, G200 SGRAM does not care... */
#if 0
static int def50 = 0;	/* reg50, & 0x0F, & 0x3000 (only 0x0000, 0x1000, 0x2000 (0x3000 disallowed and treated as 0) */
#endif

static void MGAG100_progPixClock(CPMINFO int flags, int m, int n, int p) {
	int reg;
	int selClk;
	int clk;

597
	DBG(__func__)
L
Linus Torvalds 已提交
598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638

	outDAC1064(PMINFO M1064_XPIXCLKCTRL, inDAC1064(PMINFO M1064_XPIXCLKCTRL) | M1064_XPIXCLKCTRL_DIS |
		   M1064_XPIXCLKCTRL_PLL_UP);
	switch (flags & 3) {
		case 0:		reg = M1064_XPIXPLLAM; break;
		case 1:		reg = M1064_XPIXPLLBM; break;
		default:	reg = M1064_XPIXPLLCM; break;
	}
	outDAC1064(PMINFO reg++, m);
	outDAC1064(PMINFO reg++, n);
	outDAC1064(PMINFO reg, p);
	selClk = mga_inb(M_MISC_REG_READ) & ~0xC;
	/* there should be flags & 0x03 & case 0/1/else */
	/* and we should first select source and after that we should wait for PLL */
	/* and we are waiting for PLL with oscilator disabled... Is it right? */
	switch (flags & 0x03) {
		case 0x00:	break;
		case 0x01:	selClk |= 4; break;
		default:	selClk |= 0x0C; break;
	}
	mga_outb(M_MISC_REG, selClk);
	for (clk = 500000; clk; clk--) {
		if (inDAC1064(PMINFO M1064_XPIXPLLSTAT) & 0x40)
			break;
		udelay(10);
	};
	if (!clk)
		printk(KERN_ERR "matroxfb: Pixel PLL%c not locked after usual time\n", (reg-M1064_XPIXPLLAM-2)/4 + 'A');
	selClk = inDAC1064(PMINFO M1064_XPIXCLKCTRL) & ~M1064_XPIXCLKCTRL_SRC_MASK;
	switch (flags & 0x0C) {
		case 0x00:	selClk |= M1064_XPIXCLKCTRL_SRC_PCI; break;
		case 0x04:	selClk |= M1064_XPIXCLKCTRL_SRC_PLL; break;
		default:	selClk |= M1064_XPIXCLKCTRL_SRC_EXT; break;
	}
	outDAC1064(PMINFO M1064_XPIXCLKCTRL, selClk);
	outDAC1064(PMINFO M1064_XPIXCLKCTRL, inDAC1064(PMINFO M1064_XPIXCLKCTRL) & ~M1064_XPIXCLKCTRL_DIS);
}

static void MGAG100_setPixClock(CPMINFO int flags, int freq) {
	unsigned int m, n, p;

639
	DBG(__func__)
L
Linus Torvalds 已提交
640

641
	DAC1064_calcclock(PMINFO freq, minfo->max_pixel_clock, &m, &n, &p);
L
Linus Torvalds 已提交
642 643 644 645 646 647 648 649 650
	MGAG100_progPixClock(PMINFO flags, m, n, p);
}
#endif

#ifdef CONFIG_FB_MATROX_MYSTIQUE
static int MGA1064_preinit(WPMINFO2) {
	static const int vxres_mystique[] = { 512,        640, 768,  800,  832,  960,
					     1024, 1152, 1280,      1600, 1664, 1920,
					     2048,    0};
651
	struct matrox_hw_state *hw = &minfo->hw;
L
Linus Torvalds 已提交
652

653
	DBG(__func__)
L
Linus Torvalds 已提交
654

655 656 657
	/* minfo->capable.cfb4 = 0; ... preinitialized by 0 */
	minfo->capable.text = 1;
	minfo->capable.vxres = vxres_mystique;
L
Linus Torvalds 已提交
658

659 660 661 662
	minfo->outputs[0].output = &m1064;
	minfo->outputs[0].src = minfo->outputs[0].default_src;
	minfo->outputs[0].data = minfo;
	minfo->outputs[0].mode = MATROXFB_OUTPUT_MODE_MONITOR;
L
Linus Torvalds 已提交
663

664
	if (minfo->devflags.noinit)
L
Linus Torvalds 已提交
665 666 667
		return 0;	/* do not modify settings */
	hw->MXoptionReg &= 0xC0000100;
	hw->MXoptionReg |= 0x00094E20;
668
	if (minfo->devflags.novga)
L
Linus Torvalds 已提交
669
		hw->MXoptionReg &= ~0x00000100;
670
	if (minfo->devflags.nobios)
L
Linus Torvalds 已提交
671
		hw->MXoptionReg &= ~0x40000000;
672
	if (minfo->devflags.nopciretry)
L
Linus Torvalds 已提交
673
		hw->MXoptionReg |=  0x20000000;
674
	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, hw->MXoptionReg);
L
Linus Torvalds 已提交
675 676 677 678 679 680 681 682 683 684 685
	mga_setr(M_SEQ_INDEX, 0x01, 0x20);
	mga_outl(M_CTLWTST, 0x00000000);
	udelay(200);
	mga_outl(M_MACCESS, 0x00008000);
	udelay(100);
	mga_outl(M_MACCESS, 0x0000C000);
	return 0;
}

static void MGA1064_reset(WPMINFO2) {

686
	DBG(__func__);
L
Linus Torvalds 已提交
687 688 689 690 691 692 693 694

	MGA1064_ramdac_init(PMINFO2);
}
#endif

#ifdef CONFIG_FB_MATROX_G
static void g450_mclk_init(WPMINFO2) {
	/* switch all clocks to PCI source */
695 696 697 698 699 700 701 702
	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg | 4);
	pci_write_config_dword(minfo->pcidev, PCI_OPTION3_REG, minfo->values.reg.opt3 & ~0x00300C03);
	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg);

	if (((minfo->values.reg.opt3 & 0x000003) == 0x000003) ||
	    ((minfo->values.reg.opt3 & 0x000C00) == 0x000C00) ||
	    ((minfo->values.reg.opt3 & 0x300000) == 0x300000)) {
		matroxfb_g450_setclk(PMINFO minfo->values.pll.video, M_VIDEO_PLL);
L
Linus Torvalds 已提交
703 704 705 706 707 708 709 710 711
	} else {
		unsigned long flags;
		unsigned int pwr;
		
		matroxfb_DAC_lock_irqsave(flags);
		pwr = inDAC1064(PMINFO M1064_XPWRCTRL) & ~0x02;
		outDAC1064(PMINFO M1064_XPWRCTRL, pwr);
		matroxfb_DAC_unlock_irqrestore(flags);
	}
712
	matroxfb_g450_setclk(PMINFO minfo->values.pll.system, M_SYSTEM_PLL);
L
Linus Torvalds 已提交
713 714
	
	/* switch clocks to their real PLL source(s) */
715 716 717
	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg | 4);
	pci_write_config_dword(minfo->pcidev, PCI_OPTION3_REG, minfo->values.reg.opt3);
	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg);
L
Linus Torvalds 已提交
718 719 720 721 722

}

static void g450_memory_init(WPMINFO2) {
	/* disable memory refresh */
723 724
	minfo->hw.MXoptionReg &= ~0x001F8000;
	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg);
L
Linus Torvalds 已提交
725 726
	
	/* set memory interface parameters */
727 728 729 730
	minfo->hw.MXoptionReg &= ~0x00207E00;
	minfo->hw.MXoptionReg |= 0x00207E00 & minfo->values.reg.opt;
	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg);
	pci_write_config_dword(minfo->pcidev, PCI_OPTION2_REG, minfo->values.reg.opt2);
L
Linus Torvalds 已提交
731
	
732
	mga_outl(M_CTLWTST, minfo->values.reg.mctlwtst);
L
Linus Torvalds 已提交
733 734
	
	/* first set up memory interface with disabled memory interface clocks */
735 736 737
	pci_write_config_dword(minfo->pcidev, PCI_MEMMISC_REG, minfo->values.reg.memmisc & ~0x80000000U);
	mga_outl(M_MEMRDBK, minfo->values.reg.memrdbk);
	mga_outl(M_MACCESS, minfo->values.reg.maccess);
L
Linus Torvalds 已提交
738
	/* start memory clocks */
739
	pci_write_config_dword(minfo->pcidev, PCI_MEMMISC_REG, minfo->values.reg.memmisc | 0x80000000U);
L
Linus Torvalds 已提交
740 741 742

	udelay(200);
	
743 744
	if (minfo->values.memory.ddr && (!minfo->values.memory.emrswen || !minfo->values.memory.dll)) {
		mga_outl(M_MEMRDBK, minfo->values.reg.memrdbk & ~0x1000);
L
Linus Torvalds 已提交
745
	}
746
	mga_outl(M_MACCESS, minfo->values.reg.maccess | 0x8000);
L
Linus Torvalds 已提交
747 748 749
	
	udelay(200);
	
750 751
	minfo->hw.MXoptionReg |= 0x001F8000 & minfo->values.reg.opt;
	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg);
L
Linus Torvalds 已提交
752 753 754 755 756
	
	/* value is written to memory chips only if old != new */
	mga_outl(M_PLNWT, 0);
	mga_outl(M_PLNWT, ~0);
	
757 758
	if (minfo->values.reg.mctlwtst != minfo->values.reg.mctlwtst_core) {
		mga_outl(M_CTLWTST, minfo->values.reg.mctlwtst_core);
L
Linus Torvalds 已提交
759 760 761 762 763 764 765 766 767
	}
	
}

static void g450_preinit(WPMINFO2) {
	u_int32_t c2ctl;
	u_int8_t curctl;
	u_int8_t c1ctl;
	
768 769 770 771 772 773 774 775 776 777 778
	/* minfo->hw.MXoptionReg = minfo->values.reg.opt; */
	minfo->hw.MXoptionReg &= 0xC0000100;
	minfo->hw.MXoptionReg |= 0x00000020;
	if (minfo->devflags.novga)
		minfo->hw.MXoptionReg &= ~0x00000100;
	if (minfo->devflags.nobios)
		minfo->hw.MXoptionReg &= ~0x40000000;
	if (minfo->devflags.nopciretry)
		minfo->hw.MXoptionReg |=  0x20000000;
	minfo->hw.MXoptionReg |= minfo->values.reg.opt & 0x03400040;
	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg);
L
Linus Torvalds 已提交
779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814

	/* Init system clocks */
		
	/* stop crtc2 */
	c2ctl = mga_inl(M_C2CTL);
	mga_outl(M_C2CTL, c2ctl & ~1);
	/* stop cursor */
	curctl = inDAC1064(PMINFO M1064_XCURCTRL);
	outDAC1064(PMINFO M1064_XCURCTRL, 0);
	/* stop crtc1 */
	c1ctl = mga_readr(M_SEQ_INDEX, 1);
	mga_setr(M_SEQ_INDEX, 1, c1ctl | 0x20);

	g450_mclk_init(PMINFO2);
	g450_memory_init(PMINFO2);
	
	/* set legacy VGA clock sources for DOSEmu or VMware... */
	matroxfb_g450_setclk(PMINFO 25175, M_PIXEL_PLL_A);
	matroxfb_g450_setclk(PMINFO 28322, M_PIXEL_PLL_B);

	/* restore crtc1 */
	mga_setr(M_SEQ_INDEX, 1, c1ctl);
	
	/* restore cursor */
	outDAC1064(PMINFO M1064_XCURCTRL, curctl);

	/* restore crtc2 */
	mga_outl(M_C2CTL, c2ctl);
	
	return;
}

static int MGAG100_preinit(WPMINFO2) {
	static const int vxres_g100[] = {  512,        640, 768,  800,  832,  960,
                                          1024, 1152, 1280,      1600, 1664, 1920,
                                          2048, 0};
815
	struct matrox_hw_state *hw = &minfo->hw;
L
Linus Torvalds 已提交
816 817 818 819 820 821

        u_int32_t reg50;
#if 0
	u_int32_t q;
#endif

822
	DBG(__func__)
L
Linus Torvalds 已提交
823 824

	/* there are some instabilities if in_div > 19 && vco < 61000 */
825 826
	if (minfo->devflags.g450dac) {
		minfo->features.pll.vco_freq_min = 130000;	/* my sample: >118 */
L
Linus Torvalds 已提交
827
	} else {
828
		minfo->features.pll.vco_freq_min = 62000;
L
Linus Torvalds 已提交
829
	}
830 831
	if (!minfo->features.pll.ref_freq) {
		minfo->features.pll.ref_freq	 = 27000;
L
Linus Torvalds 已提交
832
	}
833 834 835 836 837 838 839 840 841 842 843
	minfo->features.pll.feed_div_min = 7;
	minfo->features.pll.feed_div_max = 127;
	minfo->features.pll.in_div_min	 = 1;
	minfo->features.pll.in_div_max	 = 31;
	minfo->features.pll.post_shift_max = 3;
	minfo->features.DAC1064.xvrefctrl = DAC1064_XVREFCTRL_G100_DEFAULT;
	/* minfo->capable.cfb4 = 0; ... preinitialized by 0 */
	minfo->capable.text = 1;
	minfo->capable.vxres = vxres_g100;
	minfo->capable.plnwt = minfo->devflags.accelerator == FB_ACCEL_MATROX_MGAG100
			? minfo->devflags.sgram : 1;
L
Linus Torvalds 已提交
844 845

#ifdef CONFIG_FB_MATROX_G
846 847
	if (minfo->devflags.g450dac) {
		minfo->outputs[0].output = &g450out;
L
Linus Torvalds 已提交
848 849 850
	} else
#endif
	{
851
		minfo->outputs[0].output = &m1064;
L
Linus Torvalds 已提交
852
	}
853 854 855
	minfo->outputs[0].src = minfo->outputs[0].default_src;
	minfo->outputs[0].data = minfo;
	minfo->outputs[0].mode = MATROXFB_OUTPUT_MODE_MONITOR;
L
Linus Torvalds 已提交
856

857
	if (minfo->devflags.g450dac) {
L
Linus Torvalds 已提交
858 859 860 861
		/* we must do this always, BIOS does not do it for us
		   and accelerator dies without it */
		mga_outl(0x1C0C, 0);
	}
862
	if (minfo->devflags.noinit)
L
Linus Torvalds 已提交
863
		return 0;
864
	if (minfo->devflags.g450dac) {
L
Linus Torvalds 已提交
865 866 867 868 869
		g450_preinit(PMINFO2);
		return 0;
	}
	hw->MXoptionReg &= 0xC0000100;
	hw->MXoptionReg |= 0x00000020;
870
	if (minfo->devflags.novga)
L
Linus Torvalds 已提交
871
		hw->MXoptionReg &= ~0x00000100;
872
	if (minfo->devflags.nobios)
L
Linus Torvalds 已提交
873
		hw->MXoptionReg &= ~0x40000000;
874
	if (minfo->devflags.nopciretry)
L
Linus Torvalds 已提交
875
		hw->MXoptionReg |=  0x20000000;
876
	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, hw->MXoptionReg);
L
Linus Torvalds 已提交
877 878
	DAC1064_setmclk(PMINFO DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV3 | DAC1064_OPT_SCLK_PCI, 133333);

879 880
	if (minfo->devflags.accelerator == FB_ACCEL_MATROX_MGAG100) {
		pci_read_config_dword(minfo->pcidev, PCI_OPTION2_REG, &reg50);
L
Linus Torvalds 已提交
881
		reg50 &= ~0x3000;
882
		pci_write_config_dword(minfo->pcidev, PCI_OPTION2_REG, reg50);
L
Linus Torvalds 已提交
883 884

		hw->MXoptionReg |= 0x1080;
885 886
		pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, hw->MXoptionReg);
		mga_outl(M_CTLWTST, minfo->values.reg.mctlwtst);
L
Linus Torvalds 已提交
887 888 889 890 891 892 893 894 895
		udelay(100);
		mga_outb(0x1C05, 0x00);
		mga_outb(0x1C05, 0x80);
		udelay(100);
		mga_outb(0x1C05, 0x40);
		mga_outb(0x1C05, 0xC0);
		udelay(100);
		reg50 &= ~0xFF;
		reg50 |=  0x07;
896
		pci_write_config_dword(minfo->pcidev, PCI_OPTION2_REG, reg50);
L
Linus Torvalds 已提交
897 898 899 900 901
		/* it should help with G100 */
		mga_outb(M_GRAPHICS_INDEX, 6);
		mga_outb(M_GRAPHICS_DATA, (mga_inb(M_GRAPHICS_DATA) & 3) | 4);
		mga_setr(M_EXTVGA_INDEX, 0x03, 0x81);
		mga_setr(M_EXTVGA_INDEX, 0x04, 0x00);
902 903 904
		mga_writeb(minfo->video.vbase, 0x0000, 0xAA);
		mga_writeb(minfo->video.vbase, 0x0800, 0x55);
		mga_writeb(minfo->video.vbase, 0x4000, 0x55);
L
Linus Torvalds 已提交
905
#if 0
906
		if (mga_readb(minfo->video.vbase, 0x0000) != 0xAA) {
L
Linus Torvalds 已提交
907 908 909 910
			hw->MXoptionReg &= ~0x1000;
		}
#endif
		hw->MXoptionReg |= 0x00078020;
911 912
	} else if (minfo->devflags.accelerator == FB_ACCEL_MATROX_MGAG200) {
		pci_read_config_dword(minfo->pcidev, PCI_OPTION2_REG, &reg50);
L
Linus Torvalds 已提交
913
		reg50 &= ~0x3000;
914
		pci_write_config_dword(minfo->pcidev, PCI_OPTION2_REG, reg50);
L
Linus Torvalds 已提交
915

916 917
		if (minfo->devflags.memtype == -1)
			hw->MXoptionReg |= minfo->values.reg.opt & 0x1C00;
L
Linus Torvalds 已提交
918
		else
919 920
			hw->MXoptionReg |= (minfo->devflags.memtype & 7) << 10;
		if (minfo->devflags.sgram)
L
Linus Torvalds 已提交
921
			hw->MXoptionReg |= 0x4000;
922 923
		mga_outl(M_CTLWTST, minfo->values.reg.mctlwtst);
		mga_outl(M_MEMRDBK, minfo->values.reg.memrdbk);
L
Linus Torvalds 已提交
924 925 926 927
		udelay(200);
		mga_outl(M_MACCESS, 0x00000000);
		mga_outl(M_MACCESS, 0x00008000);
		udelay(100);
928
		mga_outw(M_MEMRDBK, minfo->values.reg.memrdbk);
L
Linus Torvalds 已提交
929 930
		hw->MXoptionReg |= 0x00078020;
	} else {
931
		pci_read_config_dword(minfo->pcidev, PCI_OPTION2_REG, &reg50);
L
Linus Torvalds 已提交
932 933
		reg50 &= ~0x00000100;
		reg50 |=  0x00000000;
934
		pci_write_config_dword(minfo->pcidev, PCI_OPTION2_REG, reg50);
L
Linus Torvalds 已提交
935

936 937
		if (minfo->devflags.memtype == -1)
			hw->MXoptionReg |= minfo->values.reg.opt & 0x1C00;
L
Linus Torvalds 已提交
938
		else
939 940
			hw->MXoptionReg |= (minfo->devflags.memtype & 7) << 10;
		if (minfo->devflags.sgram)
L
Linus Torvalds 已提交
941
			hw->MXoptionReg |= 0x4000;
942 943
		mga_outl(M_CTLWTST, minfo->values.reg.mctlwtst);
		mga_outl(M_MEMRDBK, minfo->values.reg.memrdbk);
L
Linus Torvalds 已提交
944 945 946 947
		udelay(200);
		mga_outl(M_MACCESS, 0x00000000);
		mga_outl(M_MACCESS, 0x00008000);
		udelay(100);
948
		mga_outl(M_MEMRDBK, minfo->values.reg.memrdbk);
L
Linus Torvalds 已提交
949 950
		hw->MXoptionReg |= 0x00040020;
	}
951
	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, hw->MXoptionReg);
L
Linus Torvalds 已提交
952 953 954 955 956
	return 0;
}

static void MGAG100_reset(WPMINFO2) {
	u_int8_t b;
957
	struct matrox_hw_state *hw = &minfo->hw;
L
Linus Torvalds 已提交
958

959
	DBG(__func__)
L
Linus Torvalds 已提交
960 961 962 963 964 965 966

	{
#ifdef G100_BROKEN_IBM_82351
		u_int32_t d;

		find 1014/22 (IBM/82351); /* if found and bridging Matrox, do some strange stuff */
		pci_read_config_byte(ibm, PCI_SECONDARY_BUS, &b);
967
		if (b == minfo->pcidev->bus->number) {
L
Linus Torvalds 已提交
968 969 970 971 972 973
			pci_write_config_byte(ibm, PCI_COMMAND+1, 0);	/* disable back-to-back & SERR */
			pci_write_config_byte(ibm, 0x41, 0xF4);		/* ??? */
			pci_write_config_byte(ibm, PCI_IO_BASE, 0xF0);	/* ??? */
			pci_write_config_byte(ibm, PCI_IO_LIMIT, 0x00);	/* ??? */
		}
#endif
974
		if (!minfo->devflags.noinit) {
L
Linus Torvalds 已提交
975 976
			if (x7AF4 & 8) {
				hw->MXoptionReg |= 0x40;	/* FIXME... */
977
				pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, hw->MXoptionReg);
L
Linus Torvalds 已提交
978
			}
979
			mga_setr(M_EXTVGA_INDEX, 0x06, 0x00);
L
Linus Torvalds 已提交
980 981
		}
	}
982
	if (minfo->devflags.g450dac) {
L
Linus Torvalds 已提交
983 984 985 986 987 988 989
		/* either leave MCLK as is... or they were set in preinit */
		hw->DACclk[3] = inDAC1064(PMINFO DAC1064_XSYSPLLM);
		hw->DACclk[4] = inDAC1064(PMINFO DAC1064_XSYSPLLN);
		hw->DACclk[5] = inDAC1064(PMINFO DAC1064_XSYSPLLP);
	} else {
		DAC1064_setmclk(PMINFO DAC1064_OPT_RESERVED | DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV1 | DAC1064_OPT_SCLK_PLL, 133333);
	}
990 991 992
	if (minfo->devflags.accelerator == FB_ACCEL_MATROX_MGAG400) {
		if (minfo->devflags.dfp_type == -1) {
			minfo->devflags.dfp_type = inDAC1064(PMINFO 0x1F);
L
Linus Torvalds 已提交
993 994
		}
	}
995
	if (minfo->devflags.noinit)
L
Linus Torvalds 已提交
996
		return;
997
	if (minfo->devflags.g450dac) {
L
Linus Torvalds 已提交
998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013
	} else {
		MGAG100_setPixClock(PMINFO 4, 25175);
		MGAG100_setPixClock(PMINFO 5, 28322);
		if (x7AF4 & 0x10) {
			b = inDAC1064(PMINFO M1064_XGENIODATA) & ~1;
			outDAC1064(PMINFO M1064_XGENIODATA, b);
			b = inDAC1064(PMINFO M1064_XGENIOCTRL) | 1;
			outDAC1064(PMINFO M1064_XGENIOCTRL, b);
		}
	}
}
#endif

#ifdef CONFIG_FB_MATROX_MYSTIQUE
static void MGA1064_restore(WPMINFO2) {
	int i;
1014
	struct matrox_hw_state *hw = &minfo->hw;
L
Linus Torvalds 已提交
1015 1016 1017

	CRITFLAGS

1018
	DBG(__func__)
L
Linus Torvalds 已提交
1019 1020 1021

	CRITBEGIN

1022
	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, hw->MXoptionReg);
L
Linus Torvalds 已提交
1023 1024 1025 1026 1027 1028 1029
	mga_outb(M_IEN, 0x00);
	mga_outb(M_CACHEFLUSH, 0x00);

	CRITEND

	DAC1064_restore_1(PMINFO2);
	matroxfb_vgaHWrestore(PMINFO2);
1030
	minfo->crtc1.panpos = -1;
L
Linus Torvalds 已提交
1031 1032 1033 1034 1035 1036 1037 1038 1039
	for (i = 0; i < 6; i++)
		mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
	DAC1064_restore_2(PMINFO2);
}
#endif

#ifdef CONFIG_FB_MATROX_G
static void MGAG100_restore(WPMINFO2) {
	int i;
1040
	struct matrox_hw_state *hw = &minfo->hw;
L
Linus Torvalds 已提交
1041 1042 1043

	CRITFLAGS

1044
	DBG(__func__)
L
Linus Torvalds 已提交
1045 1046 1047

	CRITBEGIN

1048
	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, hw->MXoptionReg);
L
Linus Torvalds 已提交
1049 1050 1051 1052 1053
	CRITEND

	DAC1064_restore_1(PMINFO2);
	matroxfb_vgaHWrestore(PMINFO2);
#ifdef CONFIG_FB_MATROX_32MB
1054
	if (minfo->devflags.support32MB)
L
Linus Torvalds 已提交
1055 1056
		mga_setr(M_EXTVGA_INDEX, 8, hw->CRTCEXT[8]);
#endif
1057
	minfo->crtc1.panpos = -1;
L
Linus Torvalds 已提交
1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082
	for (i = 0; i < 6; i++)
		mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
	DAC1064_restore_2(PMINFO2);
}
#endif

#ifdef CONFIG_FB_MATROX_MYSTIQUE
struct matrox_switch matrox_mystique = {
	MGA1064_preinit, MGA1064_reset, MGA1064_init, MGA1064_restore,
};
EXPORT_SYMBOL(matrox_mystique);
#endif

#ifdef CONFIG_FB_MATROX_G
struct matrox_switch matrox_G100 = {
	MGAG100_preinit, MGAG100_reset, MGAG100_init, MGAG100_restore,
};
EXPORT_SYMBOL(matrox_G100);
#endif

#ifdef NEED_DAC1064
EXPORT_SYMBOL(DAC1064_global_init);
EXPORT_SYMBOL(DAC1064_global_restore);
#endif
MODULE_LICENSE("GPL");