| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
 | 2 |  * | 
 | 3 |  * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400 | 
 | 4 |  * | 
 | 5 |  * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz> | 
 | 6 |  * | 
 | 7 |  * Portions Copyright (c) 2001 Matrox Graphics Inc. | 
 | 8 |  * | 
 | 9 |  * Version: 1.65 2002/08/14 | 
 | 10 |  * | 
 | 11 |  * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org> | 
 | 12 |  * | 
 | 13 |  * Contributors: "menion?" <menion@mindless.com> | 
 | 14 |  *                     Betatesting, fixes, ideas | 
 | 15 |  * | 
 | 16 |  *               "Kurt Garloff" <garloff@suse.de> | 
 | 17 |  *                     Betatesting, fixes, ideas, videomodes, videomodes timmings | 
 | 18 |  * | 
 | 19 |  *               "Tom Rini" <trini@kernel.crashing.org> | 
 | 20 |  *                     MTRR stuff, PPC cleanups, betatesting, fixes, ideas | 
 | 21 |  * | 
 | 22 |  *               "Bibek Sahu" <scorpio@dodds.net> | 
 | 23 |  *                     Access device through readb|w|l and write b|w|l | 
 | 24 |  *                     Extensive debugging stuff | 
 | 25 |  * | 
 | 26 |  *               "Daniel Haun" <haund@usa.net> | 
 | 27 |  *                     Testing, hardware cursor fixes | 
 | 28 |  * | 
 | 29 |  *               "Scott Wood" <sawst46+@pitt.edu> | 
 | 30 |  *                     Fixes | 
 | 31 |  * | 
 | 32 |  *               "Gerd Knorr" <kraxel@goldbach.isdn.cs.tu-berlin.de> | 
 | 33 |  *                     Betatesting | 
 | 34 |  * | 
 | 35 |  *               "Kelly French" <targon@hazmat.com> | 
 | 36 |  *               "Fernando Herrera" <fherrera@eurielec.etsit.upm.es> | 
 | 37 |  *                     Betatesting, bug reporting | 
 | 38 |  * | 
 | 39 |  *               "Pablo Bianucci" <pbian@pccp.com.ar> | 
 | 40 |  *                     Fixes, ideas, betatesting | 
 | 41 |  * | 
 | 42 |  *               "Inaky Perez Gonzalez" <inaky@peloncho.fis.ucm.es> | 
 | 43 |  *                     Fixes, enhandcements, ideas, betatesting | 
 | 44 |  * | 
 | 45 |  *               "Ryuichi Oikawa" <roikawa@rr.iiij4u.or.jp> | 
 | 46 |  *                     PPC betatesting, PPC support, backward compatibility | 
 | 47 |  * | 
 | 48 |  *               "Paul Womar" <Paul@pwomar.demon.co.uk> | 
 | 49 |  *               "Owen Waller" <O.Waller@ee.qub.ac.uk> | 
 | 50 |  *                     PPC betatesting | 
 | 51 |  * | 
 | 52 |  *               "Thomas Pornin" <pornin@bolet.ens.fr> | 
 | 53 |  *                     Alpha betatesting | 
 | 54 |  * | 
 | 55 |  *               "Pieter van Leuven" <pvl@iae.nl> | 
 | 56 |  *               "Ulf Jaenicke-Roessler" <ujr@physik.phy.tu-dresden.de> | 
 | 57 |  *                     G100 testing | 
 | 58 |  * | 
 | 59 |  *               "H. Peter Arvin" <hpa@transmeta.com> | 
 | 60 |  *                     Ideas | 
 | 61 |  * | 
 | 62 |  *               "Cort Dougan" <cort@cs.nmt.edu> | 
 | 63 |  *                     CHRP fixes and PReP cleanup | 
 | 64 |  * | 
 | 65 |  *               "Mark Vojkovich" <mvojkovi@ucsd.edu> | 
 | 66 |  *                     G400 support | 
 | 67 |  * | 
 | 68 |  *               "David C. Hansen" <haveblue@us.ibm.com> | 
 | 69 |  *                     Fixes | 
 | 70 |  * | 
| Ian Romanick | 5c06e2a | 2005-09-09 13:04:42 -0700 | [diff] [blame] | 71 |  *               "Ian Romanick" <idr@us.ibm.com> | 
 | 72 |  *                     Find PInS data in BIOS on PowerPC systems. | 
 | 73 |  * | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 74 |  * (following author is not in any relation with this code, but his code | 
 | 75 |  *  is included in this driver) | 
 | 76 |  * | 
 | 77 |  * Based on framebuffer driver for VBE 2.0 compliant graphic boards | 
 | 78 |  *     (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de> | 
 | 79 |  * | 
 | 80 |  * (following author is not in any relation with this code, but his ideas | 
| Robert P. J. Day | beb7dd8 | 2007-05-09 07:14:03 +0200 | [diff] [blame] | 81 |  *  were used when writing this driver) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 82 |  * | 
 | 83 |  *		 FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk> | 
 | 84 |  * | 
 | 85 |  */ | 
 | 86 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 87 |  | 
 | 88 | #include "matroxfb_misc.h" | 
 | 89 | #include <linux/interrupt.h> | 
 | 90 | #include <linux/matroxfb.h> | 
 | 91 |  | 
 | 92 | void matroxfb_DAC_out(CPMINFO int reg, int val) { | 
| Harvey Harrison | 5ae1217 | 2008-04-28 02:15:47 -0700 | [diff] [blame] | 93 | 	DBG_REG(__func__) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 94 | 	mga_outb(M_RAMDAC_BASE+M_X_INDEX, reg); | 
 | 95 | 	mga_outb(M_RAMDAC_BASE+M_X_DATAREG, val); | 
 | 96 | } | 
 | 97 |  | 
 | 98 | int matroxfb_DAC_in(CPMINFO int reg) { | 
| Harvey Harrison | 5ae1217 | 2008-04-28 02:15:47 -0700 | [diff] [blame] | 99 | 	DBG_REG(__func__) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 100 | 	mga_outb(M_RAMDAC_BASE+M_X_INDEX, reg); | 
 | 101 | 	return mga_inb(M_RAMDAC_BASE+M_X_DATAREG); | 
 | 102 | } | 
 | 103 |  | 
 | 104 | void matroxfb_var2my(struct fb_var_screeninfo* var, struct my_timming* mt) { | 
 | 105 | 	unsigned int pixclock = var->pixclock; | 
 | 106 |  | 
| Harvey Harrison | 5ae1217 | 2008-04-28 02:15:47 -0700 | [diff] [blame] | 107 | 	DBG(__func__) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 108 |  | 
 | 109 | 	if (!pixclock) pixclock = 10000;	/* 10ns = 100MHz */ | 
 | 110 | 	mt->pixclock = 1000000000 / pixclock; | 
 | 111 | 	if (mt->pixclock < 1) mt->pixclock = 1; | 
 | 112 | 	mt->mnp = -1; | 
 | 113 | 	mt->dblscan = var->vmode & FB_VMODE_DOUBLE; | 
 | 114 | 	mt->interlaced = var->vmode & FB_VMODE_INTERLACED; | 
 | 115 | 	mt->HDisplay = var->xres; | 
 | 116 | 	mt->HSyncStart = mt->HDisplay + var->right_margin; | 
 | 117 | 	mt->HSyncEnd = mt->HSyncStart + var->hsync_len; | 
 | 118 | 	mt->HTotal = mt->HSyncEnd + var->left_margin; | 
 | 119 | 	mt->VDisplay = var->yres; | 
 | 120 | 	mt->VSyncStart = mt->VDisplay + var->lower_margin; | 
 | 121 | 	mt->VSyncEnd = mt->VSyncStart + var->vsync_len; | 
 | 122 | 	mt->VTotal = mt->VSyncEnd + var->upper_margin; | 
 | 123 | 	mt->sync = var->sync; | 
 | 124 | } | 
 | 125 |  | 
 | 126 | int matroxfb_PLL_calcclock(const struct matrox_pll_features* pll, unsigned int freq, unsigned int fmax, | 
 | 127 | 		unsigned int* in, unsigned int* feed, unsigned int* post) { | 
 | 128 | 	unsigned int bestdiff = ~0; | 
 | 129 | 	unsigned int bestvco = 0; | 
 | 130 | 	unsigned int fxtal = pll->ref_freq; | 
 | 131 | 	unsigned int fwant; | 
 | 132 | 	unsigned int p; | 
 | 133 |  | 
| Harvey Harrison | 5ae1217 | 2008-04-28 02:15:47 -0700 | [diff] [blame] | 134 | 	DBG(__func__) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 135 |  | 
 | 136 | 	fwant = freq; | 
 | 137 |  | 
 | 138 | #ifdef DEBUG | 
 | 139 | 	printk(KERN_ERR "post_shift_max: %d\n", pll->post_shift_max); | 
 | 140 | 	printk(KERN_ERR "ref_freq: %d\n", pll->ref_freq); | 
 | 141 | 	printk(KERN_ERR "freq: %d\n", freq); | 
 | 142 | 	printk(KERN_ERR "vco_freq_min: %d\n", pll->vco_freq_min); | 
 | 143 | 	printk(KERN_ERR "in_div_min: %d\n", pll->in_div_min); | 
 | 144 | 	printk(KERN_ERR "in_div_max: %d\n", pll->in_div_max); | 
 | 145 | 	printk(KERN_ERR "feed_div_min: %d\n", pll->feed_div_min); | 
 | 146 | 	printk(KERN_ERR "feed_div_max: %d\n", pll->feed_div_max); | 
 | 147 | 	printk(KERN_ERR "fmax: %d\n", fmax); | 
 | 148 | #endif | 
 | 149 | 	for (p = 1; p <= pll->post_shift_max; p++) { | 
 | 150 | 		if (fwant * 2 > fmax) | 
 | 151 | 			break; | 
 | 152 | 		fwant *= 2; | 
 | 153 | 	} | 
 | 154 | 	if (fwant < pll->vco_freq_min) fwant = pll->vco_freq_min; | 
 | 155 | 	if (fwant > fmax) fwant = fmax; | 
 | 156 | 	for (; p-- > 0; fwant >>= 1, bestdiff >>= 1) { | 
 | 157 | 		unsigned int m; | 
 | 158 |  | 
 | 159 | 		if (fwant < pll->vco_freq_min) break; | 
 | 160 | 		for (m = pll->in_div_min; m <= pll->in_div_max; m++) { | 
 | 161 | 			unsigned int diff, fvco; | 
 | 162 | 			unsigned int n; | 
 | 163 |  | 
 | 164 | 			n = (fwant * (m + 1) + (fxtal >> 1)) / fxtal - 1; | 
 | 165 | 			if (n > pll->feed_div_max) | 
 | 166 | 				break; | 
 | 167 | 			if (n < pll->feed_div_min) | 
 | 168 | 				n = pll->feed_div_min; | 
 | 169 | 			fvco = (fxtal * (n + 1)) / (m + 1); | 
 | 170 | 			if (fvco < fwant) | 
 | 171 | 				diff = fwant - fvco; | 
 | 172 | 			else | 
 | 173 | 				diff = fvco - fwant; | 
 | 174 | 			if (diff < bestdiff) { | 
 | 175 | 				bestdiff = diff; | 
 | 176 | 				*post = p; | 
 | 177 | 				*in = m; | 
 | 178 | 				*feed = n; | 
 | 179 | 				bestvco = fvco; | 
 | 180 | 			} | 
 | 181 | 		} | 
 | 182 | 	} | 
 | 183 | 	dprintk(KERN_ERR "clk: %02X %02X %02X %d %d %d\n", *in, *feed, *post, fxtal, bestvco, fwant); | 
 | 184 | 	return bestvco; | 
 | 185 | } | 
 | 186 |  | 
 | 187 | int matroxfb_vgaHWinit(WPMINFO struct my_timming* m) { | 
 | 188 | 	unsigned int hd, hs, he, hbe, ht; | 
 | 189 | 	unsigned int vd, vs, ve, vt, lc; | 
 | 190 | 	unsigned int wd; | 
 | 191 | 	unsigned int divider; | 
 | 192 | 	int i; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 193 | 	struct matrox_hw_state * const hw = &ACCESS_FBINFO(hw); | 
 | 194 |  | 
| Harvey Harrison | 5ae1217 | 2008-04-28 02:15:47 -0700 | [diff] [blame] | 195 | 	DBG(__func__) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 196 |  | 
 | 197 | 	hw->SEQ[0] = 0x00; | 
| Adrian Bunk | 67da54c | 2005-06-25 14:59:08 -0700 | [diff] [blame] | 198 | 	hw->SEQ[1] = 0x01;	/* or 0x09 */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 199 | 	hw->SEQ[2] = 0x0F;	/* bitplanes */ | 
 | 200 | 	hw->SEQ[3] = 0x00; | 
 | 201 | 	hw->SEQ[4] = 0x0E; | 
 | 202 | 	/* CRTC 0..7, 9, 16..19, 21, 22 are reprogrammed by Matrox Millennium code... Hope that by MGA1064 too */ | 
 | 203 | 	if (m->dblscan) { | 
 | 204 | 		m->VTotal <<= 1; | 
 | 205 | 		m->VDisplay <<= 1; | 
 | 206 | 		m->VSyncStart <<= 1; | 
 | 207 | 		m->VSyncEnd <<= 1; | 
 | 208 | 	} | 
 | 209 | 	if (m->interlaced) { | 
 | 210 | 		m->VTotal >>= 1; | 
 | 211 | 		m->VDisplay >>= 1; | 
 | 212 | 		m->VSyncStart >>= 1; | 
 | 213 | 		m->VSyncEnd >>= 1; | 
 | 214 | 	} | 
 | 215 |  | 
 | 216 | 	/* GCTL is ignored when not using 0xA0000 aperture */ | 
 | 217 | 	hw->GCTL[0] = 0x00; | 
 | 218 | 	hw->GCTL[1] = 0x00; | 
 | 219 | 	hw->GCTL[2] = 0x00; | 
 | 220 | 	hw->GCTL[3] = 0x00; | 
 | 221 | 	hw->GCTL[4] = 0x00; | 
 | 222 | 	hw->GCTL[5] = 0x40; | 
 | 223 | 	hw->GCTL[6] = 0x05; | 
 | 224 | 	hw->GCTL[7] = 0x0F; | 
 | 225 | 	hw->GCTL[8] = 0xFF; | 
 | 226 |  | 
 | 227 | 	/* Whole ATTR is ignored in PowerGraphics mode */ | 
 | 228 | 	for (i = 0; i < 16; i++) | 
 | 229 | 		hw->ATTR[i] = i; | 
 | 230 | 	hw->ATTR[16] = 0x41; | 
 | 231 | 	hw->ATTR[17] = 0xFF; | 
 | 232 | 	hw->ATTR[18] = 0x0F; | 
| Adrian Bunk | 51d53bd | 2006-01-09 20:54:48 -0800 | [diff] [blame] | 233 | 	hw->ATTR[19] = 0x00; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 234 | 	hw->ATTR[20] = 0x00; | 
 | 235 |  | 
 | 236 | 	hd = m->HDisplay >> 3; | 
 | 237 | 	hs = m->HSyncStart >> 3; | 
 | 238 | 	he = m->HSyncEnd >> 3; | 
 | 239 | 	ht = m->HTotal >> 3; | 
 | 240 | 	/* standard timmings are in 8pixels, but for interleaved we cannot */ | 
 | 241 | 	/* do it for 4bpp (because of (4bpp >> 1(interleaved))/4 == 0) */ | 
 | 242 | 	/* using 16 or more pixels per unit can save us */ | 
 | 243 | 	divider = ACCESS_FBINFO(curr.final_bppShift); | 
 | 244 | 	while (divider & 3) { | 
 | 245 | 		hd >>= 1; | 
 | 246 | 		hs >>= 1; | 
 | 247 | 		he >>= 1; | 
 | 248 | 		ht >>= 1; | 
 | 249 | 		divider <<= 1; | 
 | 250 | 	} | 
 | 251 | 	divider = divider / 4; | 
 | 252 | 	/* divider can be from 1 to 8 */ | 
 | 253 | 	while (divider > 8) { | 
 | 254 | 		hd <<= 1; | 
 | 255 | 		hs <<= 1; | 
 | 256 | 		he <<= 1; | 
 | 257 | 		ht <<= 1; | 
 | 258 | 		divider >>= 1; | 
 | 259 | 	} | 
 | 260 | 	hd = hd - 1; | 
 | 261 | 	hs = hs - 1; | 
 | 262 | 	he = he - 1; | 
 | 263 | 	ht = ht - 1; | 
 | 264 | 	vd = m->VDisplay - 1; | 
 | 265 | 	vs = m->VSyncStart - 1; | 
 | 266 | 	ve = m->VSyncEnd - 1; | 
 | 267 | 	vt = m->VTotal - 2; | 
 | 268 | 	lc = vd; | 
 | 269 | 	/* G200 cannot work with (ht & 7) == 6 */ | 
 | 270 | 	if (((ht & 0x07) == 0x06) || ((ht & 0x0F) == 0x04)) | 
 | 271 | 		ht++; | 
 | 272 | 	hbe = ht; | 
 | 273 | 	wd = ACCESS_FBINFO(fbcon).var.xres_virtual * ACCESS_FBINFO(curr.final_bppShift) / 64; | 
 | 274 |  | 
 | 275 | 	hw->CRTCEXT[0] = 0; | 
 | 276 | 	hw->CRTCEXT[5] = 0; | 
 | 277 | 	if (m->interlaced) { | 
 | 278 | 		hw->CRTCEXT[0] = 0x80; | 
 | 279 | 		hw->CRTCEXT[5] = (hs + he - ht) >> 1; | 
 | 280 | 		if (!m->dblscan) | 
 | 281 | 			wd <<= 1; | 
 | 282 | 		vt &= ~1; | 
 | 283 | 	} | 
 | 284 | 	hw->CRTCEXT[0] |=  (wd & 0x300) >> 4; | 
 | 285 | 	hw->CRTCEXT[1] = (((ht - 4) & 0x100) >> 8) | | 
 | 286 | 			  ((hd      & 0x100) >> 7) | /* blanking */ | 
 | 287 | 			  ((hs      & 0x100) >> 6) | /* sync start */ | 
 | 288 | 			   (hbe     & 0x040);	 /* end hor. blanking */ | 
 | 289 | 	/* FIXME: Enable vidrst only on G400, and only if TV-out is used */ | 
 | 290 | 	if (ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_CRTC1) | 
 | 291 | 		hw->CRTCEXT[1] |= 0x88;		/* enable horizontal and vertical vidrst */ | 
 | 292 | 	hw->CRTCEXT[2] =  ((vt & 0xC00) >> 10) | | 
 | 293 | 			  ((vd & 0x400) >>  8) |	/* disp end */ | 
 | 294 | 			  ((vd & 0xC00) >>  7) |	/* vblanking start */ | 
 | 295 | 			  ((vs & 0xC00) >>  5) | | 
 | 296 | 			  ((lc & 0x400) >>  3); | 
 | 297 | 	hw->CRTCEXT[3] = (divider - 1) | 0x80; | 
 | 298 | 	hw->CRTCEXT[4] = 0; | 
 | 299 |  | 
 | 300 | 	hw->CRTC[0] = ht-4; | 
 | 301 | 	hw->CRTC[1] = hd; | 
 | 302 | 	hw->CRTC[2] = hd; | 
 | 303 | 	hw->CRTC[3] = (hbe & 0x1F) | 0x80; | 
 | 304 | 	hw->CRTC[4] = hs; | 
 | 305 | 	hw->CRTC[5] = ((hbe & 0x20) << 2) | (he & 0x1F); | 
 | 306 | 	hw->CRTC[6] = vt & 0xFF; | 
 | 307 | 	hw->CRTC[7] = ((vt & 0x100) >> 8) | | 
 | 308 | 		      ((vd & 0x100) >> 7) | | 
 | 309 | 		      ((vs & 0x100) >> 6) | | 
 | 310 | 		      ((vd & 0x100) >> 5) | | 
 | 311 | 		      ((lc & 0x100) >> 4) | | 
 | 312 | 		      ((vt & 0x200) >> 4) | | 
 | 313 | 		      ((vd & 0x200) >> 3) | | 
 | 314 | 		      ((vs & 0x200) >> 2); | 
 | 315 | 	hw->CRTC[8] = 0x00; | 
 | 316 | 	hw->CRTC[9] = ((vd & 0x200) >> 4) | | 
 | 317 | 		      ((lc & 0x200) >> 3); | 
 | 318 | 	if (m->dblscan && !m->interlaced) | 
 | 319 | 		hw->CRTC[9] |= 0x80; | 
 | 320 | 	for (i = 10; i < 16; i++) | 
 | 321 | 		hw->CRTC[i] = 0x00; | 
 | 322 | 	hw->CRTC[16] = vs /* & 0xFF */; | 
 | 323 | 	hw->CRTC[17] = (ve & 0x0F) | 0x20; | 
 | 324 | 	hw->CRTC[18] = vd /* & 0xFF */; | 
 | 325 | 	hw->CRTC[19] = wd /* & 0xFF */; | 
 | 326 | 	hw->CRTC[20] = 0x00; | 
 | 327 | 	hw->CRTC[21] = vd /* & 0xFF */; | 
 | 328 | 	hw->CRTC[22] = (vt + 1) /* & 0xFF */; | 
 | 329 | 	hw->CRTC[23] = 0xC3; | 
 | 330 | 	hw->CRTC[24] = lc; | 
 | 331 | 	return 0; | 
 | 332 | }; | 
 | 333 |  | 
 | 334 | void matroxfb_vgaHWrestore(WPMINFO2) { | 
 | 335 | 	int i; | 
 | 336 | 	struct matrox_hw_state * const hw = &ACCESS_FBINFO(hw); | 
 | 337 | 	CRITFLAGS | 
 | 338 |  | 
| Harvey Harrison | 5ae1217 | 2008-04-28 02:15:47 -0700 | [diff] [blame] | 339 | 	DBG(__func__) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 340 |  | 
 | 341 | 	dprintk(KERN_INFO "MiscOutReg: %02X\n", hw->MiscOutReg); | 
 | 342 | 	dprintk(KERN_INFO "SEQ regs:   "); | 
 | 343 | 	for (i = 0; i < 5; i++) | 
 | 344 | 		dprintk("%02X:", hw->SEQ[i]); | 
 | 345 | 	dprintk("\n"); | 
 | 346 | 	dprintk(KERN_INFO "GDC regs:   "); | 
 | 347 | 	for (i = 0; i < 9; i++) | 
 | 348 | 		dprintk("%02X:", hw->GCTL[i]); | 
 | 349 | 	dprintk("\n"); | 
 | 350 | 	dprintk(KERN_INFO "CRTC regs: "); | 
 | 351 | 	for (i = 0; i < 25; i++) | 
 | 352 | 		dprintk("%02X:", hw->CRTC[i]); | 
 | 353 | 	dprintk("\n"); | 
 | 354 | 	dprintk(KERN_INFO "ATTR regs: "); | 
 | 355 | 	for (i = 0; i < 21; i++) | 
 | 356 | 		dprintk("%02X:", hw->ATTR[i]); | 
 | 357 | 	dprintk("\n"); | 
 | 358 |  | 
 | 359 | 	CRITBEGIN | 
 | 360 |  | 
 | 361 | 	mga_inb(M_ATTR_RESET); | 
 | 362 | 	mga_outb(M_ATTR_INDEX, 0); | 
 | 363 | 	mga_outb(M_MISC_REG, hw->MiscOutReg); | 
 | 364 | 	for (i = 1; i < 5; i++) | 
 | 365 | 		mga_setr(M_SEQ_INDEX, i, hw->SEQ[i]); | 
 | 366 | 	mga_setr(M_CRTC_INDEX, 17, hw->CRTC[17] & 0x7F); | 
 | 367 | 	for (i = 0; i < 25; i++) | 
 | 368 | 		mga_setr(M_CRTC_INDEX, i, hw->CRTC[i]); | 
 | 369 | 	for (i = 0; i < 9; i++) | 
 | 370 | 		mga_setr(M_GRAPHICS_INDEX, i, hw->GCTL[i]); | 
 | 371 | 	for (i = 0; i < 21; i++) { | 
 | 372 | 		mga_inb(M_ATTR_RESET); | 
 | 373 | 		mga_outb(M_ATTR_INDEX, i); | 
 | 374 | 		mga_outb(M_ATTR_INDEX, hw->ATTR[i]); | 
 | 375 | 	} | 
 | 376 | 	mga_outb(M_PALETTE_MASK, 0xFF); | 
 | 377 | 	mga_outb(M_DAC_REG, 0x00); | 
 | 378 | 	for (i = 0; i < 768; i++) | 
 | 379 | 		mga_outb(M_DAC_VAL, hw->DACpal[i]); | 
 | 380 | 	mga_inb(M_ATTR_RESET); | 
 | 381 | 	mga_outb(M_ATTR_INDEX, 0x20); | 
 | 382 |  | 
 | 383 | 	CRITEND | 
 | 384 | } | 
 | 385 |  | 
 | 386 | static void get_pins(unsigned char __iomem* pins, struct matrox_bios* bd) { | 
 | 387 | 	unsigned int b0 = readb(pins); | 
 | 388 | 	 | 
 | 389 | 	if (b0 == 0x2E && readb(pins+1) == 0x41) { | 
 | 390 | 		unsigned int pins_len = readb(pins+2); | 
 | 391 | 		unsigned int i; | 
 | 392 | 		unsigned char cksum; | 
 | 393 | 		unsigned char* dst = bd->pins; | 
 | 394 |  | 
 | 395 | 		if (pins_len < 3 || pins_len > 128) { | 
 | 396 | 			return; | 
 | 397 | 		} | 
 | 398 | 		*dst++ = 0x2E; | 
 | 399 | 		*dst++ = 0x41; | 
 | 400 | 		*dst++ = pins_len; | 
 | 401 | 		cksum = 0x2E + 0x41 + pins_len; | 
 | 402 | 		for (i = 3; i < pins_len; i++) { | 
 | 403 | 			cksum += *dst++ = readb(pins+i); | 
 | 404 | 		} | 
 | 405 | 		if (cksum) { | 
 | 406 | 			return; | 
 | 407 | 		} | 
 | 408 | 		bd->pins_len = pins_len; | 
 | 409 | 	} else if (b0 == 0x40 && readb(pins+1) == 0x00) { | 
 | 410 | 		unsigned int i; | 
 | 411 | 		unsigned char* dst = bd->pins; | 
 | 412 |  | 
 | 413 | 		*dst++ = 0x40; | 
 | 414 | 		*dst++ = 0; | 
 | 415 | 		for (i = 2; i < 0x40; i++) { | 
 | 416 | 			*dst++ = readb(pins+i); | 
 | 417 | 		} | 
 | 418 | 		bd->pins_len = 0x40; | 
 | 419 | 	} | 
 | 420 | } | 
 | 421 |  | 
 | 422 | static void get_bios_version(unsigned char __iomem * vbios, struct matrox_bios* bd) { | 
 | 423 | 	unsigned int pcir_offset; | 
 | 424 | 	 | 
 | 425 | 	pcir_offset = readb(vbios + 24) | (readb(vbios + 25) << 8); | 
 | 426 | 	if (pcir_offset >= 26 && pcir_offset < 0xFFE0 && | 
 | 427 | 	    readb(vbios + pcir_offset    ) == 'P' && | 
 | 428 | 	    readb(vbios + pcir_offset + 1) == 'C' && | 
 | 429 | 	    readb(vbios + pcir_offset + 2) == 'I' && | 
 | 430 | 	    readb(vbios + pcir_offset + 3) == 'R') { | 
 | 431 | 		unsigned char h; | 
 | 432 |  | 
 | 433 | 		h = readb(vbios + pcir_offset + 0x12); | 
 | 434 | 		bd->version.vMaj = (h >> 4) & 0xF; | 
 | 435 | 		bd->version.vMin = h & 0xF; | 
 | 436 | 		bd->version.vRev = readb(vbios + pcir_offset + 0x13); | 
 | 437 | 	} else { | 
 | 438 | 		unsigned char h; | 
 | 439 |  | 
 | 440 | 		h = readb(vbios + 5); | 
 | 441 | 		bd->version.vMaj = (h >> 4) & 0xF; | 
 | 442 | 		bd->version.vMin = h & 0xF; | 
 | 443 | 		bd->version.vRev = 0; | 
 | 444 | 	} | 
 | 445 | } | 
 | 446 |  | 
 | 447 | static void get_bios_output(unsigned char __iomem* vbios, struct matrox_bios* bd) { | 
 | 448 | 	unsigned char b; | 
 | 449 | 	 | 
 | 450 | 	b = readb(vbios + 0x7FF1); | 
 | 451 | 	if (b == 0xFF) { | 
 | 452 | 		b = 0; | 
 | 453 | 	} | 
 | 454 | 	bd->output.state = b; | 
 | 455 | } | 
 | 456 |  | 
 | 457 | static void get_bios_tvout(unsigned char __iomem* vbios, struct matrox_bios* bd) { | 
 | 458 | 	unsigned int i; | 
 | 459 | 	 | 
 | 460 | 	/* Check for 'IBM .*(V....TVO' string - it means TVO BIOS */ | 
 | 461 | 	bd->output.tvout = 0; | 
 | 462 | 	if (readb(vbios + 0x1D) != 'I' || | 
 | 463 | 	    readb(vbios + 0x1E) != 'B' || | 
 | 464 | 	    readb(vbios + 0x1F) != 'M' || | 
 | 465 | 	    readb(vbios + 0x20) != ' ') { | 
 | 466 | 	    	return; | 
 | 467 | 	} | 
 | 468 | 	for (i = 0x2D; i < 0x2D + 128; i++) { | 
 | 469 | 		unsigned char b = readb(vbios + i); | 
 | 470 | 		 | 
 | 471 | 		if (b == '(' && readb(vbios + i + 1) == 'V') { | 
 | 472 | 			if (readb(vbios + i + 6) == 'T' && | 
 | 473 | 			    readb(vbios + i + 7) == 'V' && | 
 | 474 | 			    readb(vbios + i + 8) == 'O') { | 
 | 475 | 				bd->output.tvout = 1; | 
 | 476 | 			} | 
 | 477 | 			return; | 
 | 478 | 		} | 
 | 479 | 		if (b == 0) | 
 | 480 | 			break; | 
 | 481 | 	} | 
 | 482 | } | 
 | 483 |  | 
 | 484 | static void parse_bios(unsigned char __iomem* vbios, struct matrox_bios* bd) { | 
 | 485 | 	unsigned int pins_offset; | 
 | 486 | 	 | 
 | 487 | 	if (readb(vbios) != 0x55 || readb(vbios + 1) != 0xAA) { | 
 | 488 | 		return; | 
 | 489 | 	} | 
 | 490 | 	bd->bios_valid = 1; | 
 | 491 | 	get_bios_version(vbios, bd); | 
 | 492 | 	get_bios_output(vbios, bd); | 
 | 493 | 	get_bios_tvout(vbios, bd); | 
| Ian Romanick | 5c06e2a | 2005-09-09 13:04:42 -0700 | [diff] [blame] | 494 | #if defined(__powerpc__) | 
 | 495 | 	/* On PowerPC cards, the PInS offset isn't stored at the end of the | 
 | 496 | 	 * BIOS image.  Instead, you must search the entire BIOS image for | 
 | 497 | 	 * the magic PInS signature. | 
 | 498 | 	 * | 
 | 499 | 	 * This actually applies to all OpenFirmware base cards.  Since these | 
 | 500 | 	 * cards could be put in a MIPS or SPARC system, should the condition | 
 | 501 | 	 * be something different? | 
 | 502 | 	 */ | 
 | 503 | 	for ( pins_offset = 0 ; pins_offset <= 0xFF80 ; pins_offset++ ) { | 
 | 504 | 		unsigned char header[3]; | 
 | 505 |  | 
 | 506 | 		header[0] = readb(vbios + pins_offset); | 
 | 507 | 		header[1] = readb(vbios + pins_offset + 1); | 
 | 508 | 		header[2] = readb(vbios + pins_offset + 2); | 
 | 509 | 		if ( (header[0] == 0x2E) && (header[1] == 0x41) | 
 | 510 | 		     && ((header[2] == 0x40) || (header[2] == 0x80)) ) { | 
 | 511 | 			printk(KERN_INFO "PInS data found at offset %u\n", | 
 | 512 | 			       pins_offset); | 
 | 513 | 			get_pins(vbios + pins_offset, bd); | 
 | 514 | 			break; | 
 | 515 | 		} | 
 | 516 | 	} | 
 | 517 | #else | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 518 | 	pins_offset = readb(vbios + 0x7FFC) | (readb(vbios + 0x7FFD) << 8); | 
 | 519 | 	if (pins_offset <= 0xFF80) { | 
 | 520 | 		get_pins(vbios + pins_offset, bd); | 
 | 521 | 	} | 
| Ian Romanick | 5c06e2a | 2005-09-09 13:04:42 -0700 | [diff] [blame] | 522 | #endif | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 523 | } | 
 | 524 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 525 | static int parse_pins1(WPMINFO const struct matrox_bios* bd) { | 
 | 526 | 	unsigned int maxdac; | 
 | 527 |  | 
 | 528 | 	switch (bd->pins[22]) { | 
 | 529 | 		case 0:		maxdac = 175000; break; | 
 | 530 | 		case 1:		maxdac = 220000; break; | 
 | 531 | 		default:	maxdac = 240000; break; | 
 | 532 | 	} | 
| Harvey Harrison | d15c0a4 | 2008-04-29 01:03:41 -0700 | [diff] [blame] | 533 | 	if (get_unaligned_le16(bd->pins + 24)) { | 
 | 534 | 		maxdac = get_unaligned_le16(bd->pins + 24) * 10; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 535 | 	} | 
 | 536 | 	MINFO->limits.pixel.vcomax = maxdac; | 
| Harvey Harrison | d15c0a4 | 2008-04-29 01:03:41 -0700 | [diff] [blame] | 537 | 	MINFO->values.pll.system = get_unaligned_le16(bd->pins + 28) ? | 
 | 538 | 		get_unaligned_le16(bd->pins + 28) * 10 : 50000; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 539 | 	/* ignore 4MB, 8MB, module clocks */ | 
 | 540 | 	MINFO->features.pll.ref_freq = 14318; | 
 | 541 | 	MINFO->values.reg.mctlwtst	= 0x00030101; | 
 | 542 | 	return 0; | 
 | 543 | } | 
 | 544 |  | 
 | 545 | static void default_pins1(WPMINFO2) { | 
 | 546 | 	/* Millennium */ | 
 | 547 | 	MINFO->limits.pixel.vcomax	= 220000; | 
 | 548 | 	MINFO->values.pll.system	=  50000; | 
 | 549 | 	MINFO->features.pll.ref_freq	=  14318; | 
 | 550 | 	MINFO->values.reg.mctlwtst	= 0x00030101; | 
 | 551 | } | 
 | 552 |  | 
 | 553 | static int parse_pins2(WPMINFO const struct matrox_bios* bd) { | 
 | 554 | 	MINFO->limits.pixel.vcomax	= | 
 | 555 | 	MINFO->limits.system.vcomax	= (bd->pins[41] == 0xFF) ? 230000 : ((bd->pins[41] + 100) * 1000); | 
 | 556 | 	MINFO->values.reg.mctlwtst	= ((bd->pins[51] & 0x01) ? 0x00000001 : 0) | | 
 | 557 | 					  ((bd->pins[51] & 0x02) ? 0x00000100 : 0) | | 
 | 558 | 					  ((bd->pins[51] & 0x04) ? 0x00010000 : 0) | | 
 | 559 | 					  ((bd->pins[51] & 0x08) ? 0x00020000 : 0); | 
 | 560 | 	MINFO->values.pll.system	= (bd->pins[43] == 0xFF) ? 50000 : ((bd->pins[43] + 100) * 1000); | 
 | 561 | 	MINFO->features.pll.ref_freq	= 14318; | 
 | 562 | 	return 0; | 
 | 563 | } | 
 | 564 |  | 
 | 565 | static void default_pins2(WPMINFO2) { | 
 | 566 | 	/* Millennium II, Mystique */ | 
 | 567 | 	MINFO->limits.pixel.vcomax	= | 
 | 568 | 	MINFO->limits.system.vcomax	= 230000; | 
 | 569 | 	MINFO->values.reg.mctlwtst	= 0x00030101; | 
 | 570 | 	MINFO->values.pll.system	=  50000; | 
 | 571 | 	MINFO->features.pll.ref_freq	=  14318; | 
 | 572 | } | 
 | 573 |  | 
 | 574 | static int parse_pins3(WPMINFO const struct matrox_bios* bd) { | 
 | 575 | 	MINFO->limits.pixel.vcomax	= | 
 | 576 | 	MINFO->limits.system.vcomax	= (bd->pins[36] == 0xFF) ? 230000			: ((bd->pins[36] + 100) * 1000); | 
| Harvey Harrison | d15c0a4 | 2008-04-29 01:03:41 -0700 | [diff] [blame] | 577 | 	MINFO->values.reg.mctlwtst	= get_unaligned_le32(bd->pins + 48) == 0xFFFFFFFF ? | 
 | 578 | 		0x01250A21 : get_unaligned_le32(bd->pins + 48); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 579 | 	/* memory config */ | 
 | 580 | 	MINFO->values.reg.memrdbk	= ((bd->pins[57] << 21) & 0x1E000000) | | 
 | 581 | 					  ((bd->pins[57] << 22) & 0x00C00000) | | 
 | 582 | 					  ((bd->pins[56] <<  1) & 0x000001E0) | | 
 | 583 | 					  ( bd->pins[56]        & 0x0000000F); | 
 | 584 | 	MINFO->values.reg.opt		= (bd->pins[54] & 7) << 10; | 
 | 585 | 	MINFO->values.reg.opt2		= bd->pins[58] << 12; | 
 | 586 | 	MINFO->features.pll.ref_freq	= (bd->pins[52] & 0x20) ? 14318 : 27000; | 
 | 587 | 	return 0; | 
 | 588 | } | 
 | 589 |  | 
 | 590 | static void default_pins3(WPMINFO2) { | 
 | 591 | 	/* G100, G200 */ | 
 | 592 | 	MINFO->limits.pixel.vcomax	= | 
 | 593 | 	MINFO->limits.system.vcomax	= 230000; | 
 | 594 | 	MINFO->values.reg.mctlwtst	= 0x01250A21; | 
 | 595 | 	MINFO->values.reg.memrdbk	= 0x00000000; | 
 | 596 | 	MINFO->values.reg.opt		= 0x00000C00; | 
 | 597 | 	MINFO->values.reg.opt2		= 0x00000000; | 
 | 598 | 	MINFO->features.pll.ref_freq	=  27000; | 
 | 599 | } | 
 | 600 |  | 
 | 601 | static int parse_pins4(WPMINFO const struct matrox_bios* bd) { | 
 | 602 | 	MINFO->limits.pixel.vcomax	= (bd->pins[ 39] == 0xFF) ? 230000			: bd->pins[ 39] * 4000; | 
 | 603 | 	MINFO->limits.system.vcomax	= (bd->pins[ 38] == 0xFF) ? MINFO->limits.pixel.vcomax	: bd->pins[ 38] * 4000; | 
| Harvey Harrison | d15c0a4 | 2008-04-29 01:03:41 -0700 | [diff] [blame] | 604 | 	MINFO->values.reg.mctlwtst	= get_unaligned_le32(bd->pins + 71); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 605 | 	MINFO->values.reg.memrdbk	= ((bd->pins[87] << 21) & 0x1E000000) | | 
 | 606 | 					  ((bd->pins[87] << 22) & 0x00C00000) | | 
 | 607 | 					  ((bd->pins[86] <<  1) & 0x000001E0) | | 
 | 608 | 					  ( bd->pins[86]        & 0x0000000F); | 
 | 609 | 	MINFO->values.reg.opt		= ((bd->pins[53] << 15) & 0x00400000) | | 
 | 610 | 					  ((bd->pins[53] << 22) & 0x10000000) | | 
 | 611 | 					  ((bd->pins[53] <<  7) & 0x00001C00); | 
| Harvey Harrison | d15c0a4 | 2008-04-29 01:03:41 -0700 | [diff] [blame] | 612 | 	MINFO->values.reg.opt3		= get_unaligned_le32(bd->pins + 67); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 613 | 	MINFO->values.pll.system	= (bd->pins[ 65] == 0xFF) ? 200000 			: bd->pins[ 65] * 4000; | 
 | 614 | 	MINFO->features.pll.ref_freq	= (bd->pins[ 92] & 0x01) ? 14318 : 27000; | 
 | 615 | 	return 0; | 
 | 616 | } | 
 | 617 |  | 
 | 618 | static void default_pins4(WPMINFO2) { | 
 | 619 | 	/* G400 */ | 
 | 620 | 	MINFO->limits.pixel.vcomax	= | 
 | 621 | 	MINFO->limits.system.vcomax	= 252000; | 
 | 622 | 	MINFO->values.reg.mctlwtst	= 0x04A450A1; | 
 | 623 | 	MINFO->values.reg.memrdbk	= 0x000000E7; | 
 | 624 | 	MINFO->values.reg.opt		= 0x10000400; | 
 | 625 | 	MINFO->values.reg.opt3		= 0x0190A419; | 
 | 626 | 	MINFO->values.pll.system	= 200000; | 
 | 627 | 	MINFO->features.pll.ref_freq	= 27000; | 
 | 628 | } | 
 | 629 |  | 
 | 630 | static int parse_pins5(WPMINFO const struct matrox_bios* bd) { | 
 | 631 | 	unsigned int mult; | 
 | 632 | 	 | 
 | 633 | 	mult = bd->pins[4]?8000:6000; | 
 | 634 | 	 | 
 | 635 | 	MINFO->limits.pixel.vcomax	= (bd->pins[ 38] == 0xFF) ? 600000			: bd->pins[ 38] * mult; | 
 | 636 | 	MINFO->limits.system.vcomax	= (bd->pins[ 36] == 0xFF) ? MINFO->limits.pixel.vcomax	: bd->pins[ 36] * mult; | 
 | 637 | 	MINFO->limits.video.vcomax	= (bd->pins[ 37] == 0xFF) ? MINFO->limits.system.vcomax	: bd->pins[ 37] * mult; | 
 | 638 | 	MINFO->limits.pixel.vcomin	= (bd->pins[123] == 0xFF) ? 256000			: bd->pins[123] * mult; | 
 | 639 | 	MINFO->limits.system.vcomin	= (bd->pins[121] == 0xFF) ? MINFO->limits.pixel.vcomin	: bd->pins[121] * mult; | 
 | 640 | 	MINFO->limits.video.vcomin	= (bd->pins[122] == 0xFF) ? MINFO->limits.system.vcomin	: bd->pins[122] * mult; | 
 | 641 | 	MINFO->values.pll.system	= | 
 | 642 | 	MINFO->values.pll.video		= (bd->pins[ 92] == 0xFF) ? 284000			: bd->pins[ 92] * 4000; | 
| Harvey Harrison | d15c0a4 | 2008-04-29 01:03:41 -0700 | [diff] [blame] | 643 | 	MINFO->values.reg.opt		= get_unaligned_le32(bd->pins + 48); | 
 | 644 | 	MINFO->values.reg.opt2		= get_unaligned_le32(bd->pins + 52); | 
 | 645 | 	MINFO->values.reg.opt3		= get_unaligned_le32(bd->pins + 94); | 
 | 646 | 	MINFO->values.reg.mctlwtst	= get_unaligned_le32(bd->pins + 98); | 
 | 647 | 	MINFO->values.reg.memmisc	= get_unaligned_le32(bd->pins + 102); | 
 | 648 | 	MINFO->values.reg.memrdbk	= get_unaligned_le32(bd->pins + 106); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 649 | 	MINFO->features.pll.ref_freq	= (bd->pins[110] & 0x01) ? 14318 : 27000; | 
 | 650 | 	MINFO->values.memory.ddr	= (bd->pins[114] & 0x60) == 0x20; | 
 | 651 | 	MINFO->values.memory.dll	= (bd->pins[115] & 0x02) != 0; | 
 | 652 | 	MINFO->values.memory.emrswen	= (bd->pins[115] & 0x01) != 0; | 
 | 653 | 	MINFO->values.reg.maccess	= MINFO->values.memory.emrswen ? 0x00004000 : 0x00000000; | 
 | 654 | 	if (bd->pins[115] & 4) { | 
 | 655 | 		MINFO->values.reg.mctlwtst_core = MINFO->values.reg.mctlwtst; | 
 | 656 | 	} else { | 
 | 657 | 		u_int32_t wtst_xlat[] = { 0, 1, 5, 6, 7, 5, 2, 3 }; | 
 | 658 | 		MINFO->values.reg.mctlwtst_core = (MINFO->values.reg.mctlwtst & ~7) | | 
 | 659 | 		                                  wtst_xlat[MINFO->values.reg.mctlwtst & 7]; | 
 | 660 | 	} | 
| Paul A. Clarke | e798bd9 | 2007-08-10 13:00:49 -0700 | [diff] [blame] | 661 | 	MINFO->max_pixel_clock_panellink = bd->pins[47] * 4000; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 662 | 	return 0; | 
 | 663 | } | 
 | 664 |  | 
 | 665 | static void default_pins5(WPMINFO2) { | 
 | 666 | 	/* Mine 16MB G450 with SDRAM DDR */ | 
 | 667 | 	MINFO->limits.pixel.vcomax	= | 
 | 668 | 	MINFO->limits.system.vcomax	= | 
 | 669 | 	MINFO->limits.video.vcomax	= 600000; | 
 | 670 | 	MINFO->limits.pixel.vcomin	= | 
 | 671 | 	MINFO->limits.system.vcomin	= | 
 | 672 | 	MINFO->limits.video.vcomin	= 256000; | 
 | 673 | 	MINFO->values.pll.system	= | 
 | 674 | 	MINFO->values.pll.video		= 284000; | 
 | 675 | 	MINFO->values.reg.opt		= 0x404A1160; | 
 | 676 | 	MINFO->values.reg.opt2		= 0x0000AC00; | 
 | 677 | 	MINFO->values.reg.opt3		= 0x0090A409; | 
 | 678 | 	MINFO->values.reg.mctlwtst_core	= | 
 | 679 | 	MINFO->values.reg.mctlwtst	= 0x0C81462B; | 
 | 680 | 	MINFO->values.reg.memmisc	= 0x80000004; | 
 | 681 | 	MINFO->values.reg.memrdbk	= 0x01001103; | 
 | 682 | 	MINFO->features.pll.ref_freq	= 27000; | 
 | 683 | 	MINFO->values.memory.ddr	= 1; | 
 | 684 | 	MINFO->values.memory.dll	= 1; | 
 | 685 | 	MINFO->values.memory.emrswen	= 1; | 
 | 686 | 	MINFO->values.reg.maccess	= 0x00004000; | 
 | 687 | } | 
 | 688 |  | 
 | 689 | static int matroxfb_set_limits(WPMINFO const struct matrox_bios* bd) { | 
 | 690 | 	unsigned int pins_version; | 
 | 691 | 	static const unsigned int pinslen[] = { 64, 64, 64, 128, 128 }; | 
 | 692 |  | 
 | 693 | 	switch (ACCESS_FBINFO(chip)) { | 
 | 694 | 		case MGA_2064:	default_pins1(PMINFO2); break; | 
 | 695 | 		case MGA_2164: | 
 | 696 | 		case MGA_1064: | 
 | 697 | 		case MGA_1164:	default_pins2(PMINFO2); break; | 
 | 698 | 		case MGA_G100: | 
 | 699 | 		case MGA_G200:	default_pins3(PMINFO2); break; | 
 | 700 | 		case MGA_G400:	default_pins4(PMINFO2); break; | 
 | 701 | 		case MGA_G450: | 
 | 702 | 		case MGA_G550:	default_pins5(PMINFO2); break; | 
 | 703 | 	} | 
 | 704 | 	if (!bd->bios_valid) { | 
 | 705 | 		printk(KERN_INFO "matroxfb: Your Matrox device does not have BIOS\n"); | 
 | 706 | 		return -1; | 
 | 707 | 	} | 
 | 708 | 	if (bd->pins_len < 64) { | 
 | 709 | 		printk(KERN_INFO "matroxfb: BIOS on your Matrox device does not contain powerup info\n"); | 
 | 710 | 		return -1; | 
 | 711 | 	} | 
 | 712 | 	if (bd->pins[0] == 0x2E && bd->pins[1] == 0x41) { | 
 | 713 | 		pins_version = bd->pins[5]; | 
 | 714 | 		if (pins_version < 2 || pins_version > 5) { | 
 | 715 | 			printk(KERN_INFO "matroxfb: Unknown version (%u) of powerup info\n", pins_version); | 
 | 716 | 			return -1; | 
 | 717 | 		} | 
 | 718 | 	} else { | 
 | 719 | 		pins_version = 1; | 
 | 720 | 	} | 
 | 721 | 	if (bd->pins_len != pinslen[pins_version - 1]) { | 
 | 722 | 		printk(KERN_INFO "matroxfb: Invalid powerup info\n"); | 
 | 723 | 		return -1; | 
 | 724 | 	} | 
 | 725 | 	switch (pins_version) { | 
 | 726 | 		case 1: | 
 | 727 | 			return parse_pins1(PMINFO bd); | 
 | 728 | 		case 2: | 
 | 729 | 			return parse_pins2(PMINFO bd); | 
 | 730 | 		case 3: | 
 | 731 | 			return parse_pins3(PMINFO bd); | 
 | 732 | 		case 4: | 
 | 733 | 			return parse_pins4(PMINFO bd); | 
 | 734 | 		case 5: | 
 | 735 | 			return parse_pins5(PMINFO bd); | 
 | 736 | 		default: | 
 | 737 | 			printk(KERN_DEBUG "matroxfb: Powerup info version %u is not yet supported\n", pins_version); | 
 | 738 | 			return -1; | 
 | 739 | 	} | 
 | 740 | } | 
 | 741 |  | 
 | 742 | void matroxfb_read_pins(WPMINFO2) { | 
 | 743 | 	u32 opt; | 
 | 744 | 	u32 biosbase; | 
 | 745 | 	u32 fbbase; | 
 | 746 | 	struct pci_dev* pdev = ACCESS_FBINFO(pcidev); | 
 | 747 | 	 | 
 | 748 | 	memset(&ACCESS_FBINFO(bios), 0, sizeof(ACCESS_FBINFO(bios))); | 
 | 749 | 	pci_read_config_dword(pdev, PCI_OPTION_REG, &opt); | 
 | 750 | 	pci_write_config_dword(pdev, PCI_OPTION_REG, opt | PCI_OPTION_ENABLE_ROM); | 
 | 751 | 	pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &biosbase); | 
 | 752 | 	pci_read_config_dword(pdev, ACCESS_FBINFO(devflags.fbResource), &fbbase); | 
 | 753 | 	pci_write_config_dword(pdev, PCI_ROM_ADDRESS, (fbbase & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE); | 
 | 754 | 	parse_bios(vaddr_va(ACCESS_FBINFO(video).vbase), &ACCESS_FBINFO(bios)); | 
 | 755 | 	pci_write_config_dword(pdev, PCI_ROM_ADDRESS, biosbase); | 
 | 756 | 	pci_write_config_dword(pdev, PCI_OPTION_REG, opt); | 
 | 757 | #ifdef CONFIG_X86 | 
 | 758 | 	if (!ACCESS_FBINFO(bios).bios_valid) { | 
 | 759 | 		unsigned char __iomem* b; | 
 | 760 |  | 
 | 761 | 		b = ioremap(0x000C0000, 65536); | 
 | 762 | 		if (!b) { | 
 | 763 | 			printk(KERN_INFO "matroxfb: Unable to map legacy BIOS\n"); | 
 | 764 | 		} else { | 
 | 765 | 			unsigned int ven = readb(b+0x64+0) | (readb(b+0x64+1) << 8); | 
 | 766 | 			unsigned int dev = readb(b+0x64+2) | (readb(b+0x64+3) << 8); | 
 | 767 | 			 | 
 | 768 | 			if (ven != pdev->vendor || dev != pdev->device) { | 
 | 769 | 				printk(KERN_INFO "matroxfb: Legacy BIOS is for %04X:%04X, while this device is %04X:%04X\n", | 
 | 770 | 					ven, dev, pdev->vendor, pdev->device); | 
 | 771 | 			} else { | 
 | 772 | 				parse_bios(b, &ACCESS_FBINFO(bios)); | 
 | 773 | 			} | 
 | 774 | 			iounmap(b); | 
 | 775 | 		} | 
 | 776 | 	} | 
 | 777 | #endif | 
 | 778 | 	matroxfb_set_limits(PMINFO &ACCESS_FBINFO(bios)); | 
| Ian Romanick | 5c06e2a | 2005-09-09 13:04:42 -0700 | [diff] [blame] | 779 | 	printk(KERN_INFO "PInS memtype = %u\n", | 
 | 780 | 	       (ACCESS_FBINFO(values).reg.opt & 0x1C00) >> 10); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 781 | } | 
 | 782 |  | 
 | 783 | EXPORT_SYMBOL(matroxfb_DAC_in); | 
 | 784 | EXPORT_SYMBOL(matroxfb_DAC_out); | 
 | 785 | EXPORT_SYMBOL(matroxfb_var2my); | 
 | 786 | EXPORT_SYMBOL(matroxfb_PLL_calcclock); | 
 | 787 | #ifndef CONFIG_FB_MATROX_MULTIHEAD | 
 | 788 | struct matrox_fb_info matroxfb_global_mxinfo; | 
 | 789 | EXPORT_SYMBOL(matroxfb_global_mxinfo); | 
 | 790 | #endif | 
 | 791 | EXPORT_SYMBOL(matroxfb_vgaHWinit);		/* DAC1064, Ti3026 */ | 
 | 792 | EXPORT_SYMBOL(matroxfb_vgaHWrestore);		/* DAC1064, Ti3026 */ | 
 | 793 | EXPORT_SYMBOL(matroxfb_read_pins); | 
 | 794 |  | 
 | 795 | MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>"); | 
 | 796 | MODULE_DESCRIPTION("Miscellaneous support for Matrox video cards"); | 
 | 797 | MODULE_LICENSE("GPL"); |