brintos

brintos / linux-shallow public Read only

0
0
Text · 18.0 KiB · 5404017 Raw
650 lines · c
1 /***************************************************************************\2|*                                                                           *|3|*       Copyright 2003 NVIDIA, Corporation.  All rights reserved.           *|4|*                                                                           *|5|*     NOTICE TO USER:   The source code  is copyrighted under  U.S. and     *|6|*     international laws.  Users and possessors of this source code are     *|7|*     hereby granted a nonexclusive,  royalty-free copyright license to     *|8|*     use this code in individual and commercial software.                  *|9|*                                                                           *|10|*     Any use of this source code must include,  in the user documenta-     *|11|*     tion and  internal comments to the code,  notices to the end user     *|12|*     as follows:                                                           *|13|*                                                                           *|14|*       Copyright 2003 NVIDIA, Corporation.  All rights reserved.           *|15|*                                                                           *|16|*     NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY     *|17|*     OF  THIS SOURCE  CODE  FOR ANY PURPOSE.  IT IS  PROVIDED  "AS IS"     *|18|*     WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND.  NVIDIA, CORPOR-     *|19|*     ATION DISCLAIMS ALL WARRANTIES  WITH REGARD  TO THIS SOURCE CODE,     *|20|*     INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE-     *|21|*     MENT,  AND FITNESS  FOR A PARTICULAR PURPOSE.   IN NO EVENT SHALL     *|22|*     NVIDIA, CORPORATION  BE LIABLE FOR ANY SPECIAL,  INDIRECT,  INCI-     *|23|*     DENTAL, OR CONSEQUENTIAL DAMAGES,  OR ANY DAMAGES  WHATSOEVER RE-     *|24|*     SULTING FROM LOSS OF USE,  DATA OR PROFITS,  WHETHER IN AN ACTION     *|25|*     OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,  ARISING OUT OF     *|26|*     OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE.     *|27|*                                                                           *|28|*     U.S. Government  End  Users.   This source code  is a "commercial     *|29|*     item,"  as that  term is  defined at  48 C.F.R. 2.101 (OCT 1995),     *|30|*     consisting  of "commercial  computer  software"  and  "commercial     *|31|*     computer  software  documentation,"  as such  terms  are  used in     *|32|*     48 C.F.R. 12.212 (SEPT 1995)  and is provided to the U.S. Govern-     *|33|*     ment only as  a commercial end item.   Consistent with  48 C.F.R.     *|34|*     12.212 and  48 C.F.R. 227.7202-1 through  227.7202-4 (JUNE 1995),     *|35|*     all U.S. Government End Users  acquire the source code  with only     *|36|*     those rights set forth herein.                                        *|37|*                                                                           *|38 \***************************************************************************/39 40/*41 * GPL Licensing Note - According to Mark Vojkovich, author of the Xorg/42 * XFree86 'nv' driver, this source code is provided under MIT-style licensing43 * where the source code is provided "as is" without warranty of any kind.44 * The only usage restriction is for the copyright notices to be retained45 * whenever code is used.46 *47 * Antonino Daplas <adaplas@pol.net> 2005-03-1148 */49 50#include <video/vga.h>51#include <linux/delay.h>52#include <linux/pci.h>53#include <linux/slab.h>54#include "nv_type.h"55#include "nv_local.h"56#include "nv_proto.h"57/*58 * Override VGA I/O routines.59 */60void NVWriteCrtc(struct nvidia_par *par, u8 index, u8 value)61{62	VGA_WR08(par->PCIO, par->IOBase + 0x04, index);63	VGA_WR08(par->PCIO, par->IOBase + 0x05, value);64}65u8 NVReadCrtc(struct nvidia_par *par, u8 index)66{67	VGA_WR08(par->PCIO, par->IOBase + 0x04, index);68	return (VGA_RD08(par->PCIO, par->IOBase + 0x05));69}70void NVWriteGr(struct nvidia_par *par, u8 index, u8 value)71{72	VGA_WR08(par->PVIO, VGA_GFX_I, index);73	VGA_WR08(par->PVIO, VGA_GFX_D, value);74}75u8 NVReadGr(struct nvidia_par *par, u8 index)76{77	VGA_WR08(par->PVIO, VGA_GFX_I, index);78	return (VGA_RD08(par->PVIO, VGA_GFX_D));79}80void NVWriteSeq(struct nvidia_par *par, u8 index, u8 value)81{82	VGA_WR08(par->PVIO, VGA_SEQ_I, index);83	VGA_WR08(par->PVIO, VGA_SEQ_D, value);84}85u8 NVReadSeq(struct nvidia_par *par, u8 index)86{87	VGA_WR08(par->PVIO, VGA_SEQ_I, index);88	return (VGA_RD08(par->PVIO, VGA_SEQ_D));89}90void NVWriteAttr(struct nvidia_par *par, u8 index, u8 value)91{92 93	VGA_RD08(par->PCIO, par->IOBase + 0x0a);94	if (par->paletteEnabled)95		index &= ~0x20;96	else97		index |= 0x20;98	VGA_WR08(par->PCIO, VGA_ATT_IW, index);99	VGA_WR08(par->PCIO, VGA_ATT_W, value);100}101u8 NVReadAttr(struct nvidia_par *par, u8 index)102{103	VGA_RD08(par->PCIO, par->IOBase + 0x0a);104	if (par->paletteEnabled)105		index &= ~0x20;106	else107		index |= 0x20;108	VGA_WR08(par->PCIO, VGA_ATT_IW, index);109	return (VGA_RD08(par->PCIO, VGA_ATT_R));110}111void NVWriteMiscOut(struct nvidia_par *par, u8 value)112{113	VGA_WR08(par->PVIO, VGA_MIS_W, value);114}115u8 NVReadMiscOut(struct nvidia_par *par)116{117	return (VGA_RD08(par->PVIO, VGA_MIS_R));118}119void NVWriteDacMask(struct nvidia_par *par, u8 value)120{121	VGA_WR08(par->PDIO, VGA_PEL_MSK, value);122}123void NVWriteDacReadAddr(struct nvidia_par *par, u8 value)124{125	VGA_WR08(par->PDIO, VGA_PEL_IR, value);126}127void NVWriteDacWriteAddr(struct nvidia_par *par, u8 value)128{129	VGA_WR08(par->PDIO, VGA_PEL_IW, value);130}131void NVWriteDacData(struct nvidia_par *par, u8 value)132{133	VGA_WR08(par->PDIO, VGA_PEL_D, value);134}135u8 NVReadDacData(struct nvidia_par *par)136{137	return (VGA_RD08(par->PDIO, VGA_PEL_D));138}139 140static int NVIsConnected(struct nvidia_par *par, int output)141{142	volatile u32 __iomem *PRAMDAC = par->PRAMDAC0;143	u32 reg52C, reg608, dac0_reg608 = 0;144	int present;145 146	if (output) {147	    dac0_reg608 = NV_RD32(PRAMDAC, 0x0608);148	    PRAMDAC += 0x800;149	}150 151	reg52C = NV_RD32(PRAMDAC, 0x052C);152	reg608 = NV_RD32(PRAMDAC, 0x0608);153 154	NV_WR32(PRAMDAC, 0x0608, reg608 & ~0x00010000);155 156	NV_WR32(PRAMDAC, 0x052C, reg52C & 0x0000FEEE);157	msleep(1);158	NV_WR32(PRAMDAC, 0x052C, NV_RD32(PRAMDAC, 0x052C) | 1);159 160	NV_WR32(par->PRAMDAC0, 0x0610, 0x94050140);161	NV_WR32(par->PRAMDAC0, 0x0608, NV_RD32(par->PRAMDAC0, 0x0608) |162		0x00001000);163 164	msleep(1);165 166	present = (NV_RD32(PRAMDAC, 0x0608) & (1 << 28)) ? 1 : 0;167 168	if (present)169		printk("nvidiafb: CRTC%i analog found\n", output);170	else171		printk("nvidiafb: CRTC%i analog not found\n", output);172 173	if (output)174	    NV_WR32(par->PRAMDAC0, 0x0608, dac0_reg608);175 176	NV_WR32(PRAMDAC, 0x052C, reg52C);177	NV_WR32(PRAMDAC, 0x0608, reg608);178 179	return present;180}181 182static void NVSelectHeadRegisters(struct nvidia_par *par, int head)183{184	if (head) {185		par->PCIO = par->PCIO0 + 0x2000;186		par->PCRTC = par->PCRTC0 + 0x800;187		par->PRAMDAC = par->PRAMDAC0 + 0x800;188		par->PDIO = par->PDIO0 + 0x2000;189	} else {190		par->PCIO = par->PCIO0;191		par->PCRTC = par->PCRTC0;192		par->PRAMDAC = par->PRAMDAC0;193		par->PDIO = par->PDIO0;194	}195}196 197static void nv4GetConfig(struct nvidia_par *par)198{199	if (NV_RD32(par->PFB, 0x0000) & 0x00000100) {200		par->RamAmountKBytes =201		    ((NV_RD32(par->PFB, 0x0000) >> 12) & 0x0F) * 1024 * 2 +202		    1024 * 2;203	} else {204		switch (NV_RD32(par->PFB, 0x0000) & 0x00000003) {205		case 0:206			par->RamAmountKBytes = 1024 * 32;207			break;208		case 1:209			par->RamAmountKBytes = 1024 * 4;210			break;211		case 2:212			par->RamAmountKBytes = 1024 * 8;213			break;214		case 3:215		default:216			par->RamAmountKBytes = 1024 * 16;217			break;218		}219	}220	par->CrystalFreqKHz = (NV_RD32(par->PEXTDEV, 0x0000) & 0x00000040) ?221	    14318 : 13500;222	par->CURSOR = &par->PRAMIN[0x1E00];223	par->MinVClockFreqKHz = 12000;224	par->MaxVClockFreqKHz = 350000;225}226 227static void nv10GetConfig(struct nvidia_par *par)228{229	struct pci_dev *dev;230	u32 implementation = par->Chipset & 0x0ff0;231 232#ifdef __BIG_ENDIAN233	/* turn on big endian register access */234	if (!(NV_RD32(par->PMC, 0x0004) & 0x01000001)) {235		NV_WR32(par->PMC, 0x0004, 0x01000001);236		mb();237	}238#endif239 240	dev = pci_get_domain_bus_and_slot(pci_domain_nr(par->pci_dev->bus),241					  0, 1);242	if ((par->Chipset & 0xffff) == 0x01a0) {243		u32 amt;244 245		pci_read_config_dword(dev, 0x7c, &amt);246		par->RamAmountKBytes = (((amt >> 6) & 31) + 1) * 1024;247	} else if ((par->Chipset & 0xffff) == 0x01f0) {248		u32 amt;249 250		pci_read_config_dword(dev, 0x84, &amt);251		par->RamAmountKBytes = (((amt >> 4) & 127) + 1) * 1024;252	} else {253		par->RamAmountKBytes =254		    (NV_RD32(par->PFB, 0x020C) & 0xFFF00000) >> 10;255	}256	pci_dev_put(dev);257 258	par->CrystalFreqKHz = (NV_RD32(par->PEXTDEV, 0x0000) & (1 << 6)) ?259	    14318 : 13500;260 261	if (par->twoHeads && (implementation != 0x0110)) {262		if (NV_RD32(par->PEXTDEV, 0x0000) & (1 << 22))263			par->CrystalFreqKHz = 27000;264	}265 266	par->CURSOR = NULL;	/* can't set this here */267	par->MinVClockFreqKHz = 12000;268	par->MaxVClockFreqKHz = par->twoStagePLL ? 400000 : 350000;269}270 271int NVCommonSetup(struct fb_info *info)272{273	struct nvidia_par *par = info->par;274	struct fb_var_screeninfo *var;275	u16 implementation = par->Chipset & 0x0ff0;276	u8 *edidA = NULL, *edidB = NULL;277	struct fb_monspecs *monitorA, *monitorB;278	struct fb_monspecs *monA = NULL, *monB = NULL;279	int mobile = 0;280	int tvA = 0;281	int tvB = 0;282	int FlatPanel = -1;	/* really means the CRTC is slaved */283	int Television = 0;284	int err = 0;285 286	var = kzalloc(sizeof(struct fb_var_screeninfo), GFP_KERNEL);287	monitorA = kzalloc(sizeof(struct fb_monspecs), GFP_KERNEL);288	monitorB = kzalloc(sizeof(struct fb_monspecs), GFP_KERNEL);289 290	if (!var || !monitorA || !monitorB) {291		err = -ENOMEM;292		goto done;293	}294 295	par->PRAMIN = par->REGS + (0x00710000 / 4);296	par->PCRTC0 = par->REGS + (0x00600000 / 4);297	par->PRAMDAC0 = par->REGS + (0x00680000 / 4);298	par->PFB = par->REGS + (0x00100000 / 4);299	par->PFIFO = par->REGS + (0x00002000 / 4);300	par->PGRAPH = par->REGS + (0x00400000 / 4);301	par->PEXTDEV = par->REGS + (0x00101000 / 4);302	par->PTIMER = par->REGS + (0x00009000 / 4);303	par->PMC = par->REGS + (0x00000000 / 4);304	par->FIFO = par->REGS + (0x00800000 / 4);305 306	/* 8 bit registers */307	par->PCIO0 = (u8 __iomem *) par->REGS + 0x00601000;308	par->PDIO0 = (u8 __iomem *) par->REGS + 0x00681000;309	par->PVIO = (u8 __iomem *) par->REGS + 0x000C0000;310 311	par->twoHeads = (par->Architecture >= NV_ARCH_10) &&312	    (implementation != 0x0100) &&313	    (implementation != 0x0150) &&314	    (implementation != 0x01A0) && (implementation != 0x0200);315 316	par->fpScaler = (par->FpScale && par->twoHeads &&317			 (implementation != 0x0110));318 319	par->twoStagePLL = (implementation == 0x0310) ||320	    (implementation == 0x0340) || (par->Architecture >= NV_ARCH_40);321 322	par->WaitVSyncPossible = (par->Architecture >= NV_ARCH_10) &&323	    (implementation != 0x0100);324 325	par->BlendingPossible = ((par->Chipset & 0xffff) != 0x0020);326 327	/* look for known laptop chips */328	switch (par->Chipset & 0xffff) {329	case 0x0112:330	case 0x0174:331	case 0x0175:332	case 0x0176:333	case 0x0177:334	case 0x0179:335	case 0x017C:336	case 0x017D:337	case 0x0186:338	case 0x0187:339	case 0x018D:340	case 0x01D7:341	case 0x0228:342	case 0x0286:343	case 0x028C:344	case 0x0316:345	case 0x0317:346	case 0x031A:347	case 0x031B:348	case 0x031C:349	case 0x031D:350	case 0x031E:351	case 0x031F:352	case 0x0324:353	case 0x0325:354	case 0x0328:355	case 0x0329:356	case 0x032C:357	case 0x032D:358	case 0x0347:359	case 0x0348:360	case 0x0349:361	case 0x034B:362	case 0x034C:363	case 0x0160:364	case 0x0166:365	case 0x0169:366	case 0x016B:367	case 0x016C:368	case 0x016D:369	case 0x00C8:370	case 0x00CC:371	case 0x0144:372	case 0x0146:373	case 0x0147:374	case 0x0148:375	case 0x0098:376	case 0x0099:377		mobile = 1;378		break;379	default:380		break;381	}382 383	if (par->Architecture == NV_ARCH_04)384		nv4GetConfig(par);385	else386		nv10GetConfig(par);387 388	NVSelectHeadRegisters(par, 0);389 390	NVLockUnlock(par, 0);391 392	par->IOBase = (NVReadMiscOut(par) & 0x01) ? 0x3d0 : 0x3b0;393 394	par->Television = 0;395 396	nvidia_create_i2c_busses(par);397	if (!par->twoHeads) {398		par->CRTCnumber = 0;399		if (nvidia_probe_i2c_connector(info, 1, &edidA))400			nvidia_probe_of_connector(info, 1, &edidA);401		if (edidA && !fb_parse_edid(edidA, var)) {402			printk("nvidiafb: EDID found from BUS1\n");403			monA = monitorA;404			fb_edid_to_monspecs(edidA, monA);405			FlatPanel = (monA->input & FB_DISP_DDI) ? 1 : 0;406 407			/* NV4 doesn't support FlatPanels */408			if ((par->Chipset & 0x0fff) <= 0x0020)409				FlatPanel = 0;410		} else {411			VGA_WR08(par->PCIO, 0x03D4, 0x28);412			if (VGA_RD08(par->PCIO, 0x03D5) & 0x80) {413				VGA_WR08(par->PCIO, 0x03D4, 0x33);414				if (!(VGA_RD08(par->PCIO, 0x03D5) & 0x01))415					Television = 1;416				FlatPanel = 1;417			} else {418				FlatPanel = 0;419			}420			printk("nvidiafb: HW is currently programmed for %s\n",421			       FlatPanel ? (Television ? "TV" : "DFP") :422			       "CRT");423		}424 425		if (par->FlatPanel == -1) {426			par->FlatPanel = FlatPanel;427			par->Television = Television;428		} else {429			printk("nvidiafb: Forcing display type to %s as "430			       "specified\n", par->FlatPanel ? "DFP" : "CRT");431		}432	} else {433		u8 outputAfromCRTC, outputBfromCRTC;434		int CRTCnumber = -1;435		u8 slaved_on_A, slaved_on_B;436		int analog_on_A, analog_on_B;437		u32 oldhead;438		u8 cr44;439 440		if (implementation != 0x0110) {441			if (NV_RD32(par->PRAMDAC0, 0x0000052C) & 0x100)442				outputAfromCRTC = 1;443			else444				outputAfromCRTC = 0;445			if (NV_RD32(par->PRAMDAC0, 0x0000252C) & 0x100)446				outputBfromCRTC = 1;447			else448				outputBfromCRTC = 0;449			analog_on_A = NVIsConnected(par, 0);450			analog_on_B = NVIsConnected(par, 1);451		} else {452			outputAfromCRTC = 0;453			outputBfromCRTC = 1;454			analog_on_A = 0;455			analog_on_B = 0;456		}457 458		VGA_WR08(par->PCIO, 0x03D4, 0x44);459		cr44 = VGA_RD08(par->PCIO, 0x03D5);460 461		VGA_WR08(par->PCIO, 0x03D5, 3);462		NVSelectHeadRegisters(par, 1);463		NVLockUnlock(par, 0);464 465		VGA_WR08(par->PCIO, 0x03D4, 0x28);466		slaved_on_B = VGA_RD08(par->PCIO, 0x03D5) & 0x80;467		if (slaved_on_B) {468			VGA_WR08(par->PCIO, 0x03D4, 0x33);469			tvB = !(VGA_RD08(par->PCIO, 0x03D5) & 0x01);470		}471 472		VGA_WR08(par->PCIO, 0x03D4, 0x44);473		VGA_WR08(par->PCIO, 0x03D5, 0);474		NVSelectHeadRegisters(par, 0);475		NVLockUnlock(par, 0);476 477		VGA_WR08(par->PCIO, 0x03D4, 0x28);478		slaved_on_A = VGA_RD08(par->PCIO, 0x03D5) & 0x80;479		if (slaved_on_A) {480			VGA_WR08(par->PCIO, 0x03D4, 0x33);481			tvA = !(VGA_RD08(par->PCIO, 0x03D5) & 0x01);482		}483 484		oldhead = NV_RD32(par->PCRTC0, 0x00000860);485		NV_WR32(par->PCRTC0, 0x00000860, oldhead | 0x00000010);486 487		if (nvidia_probe_i2c_connector(info, 1, &edidA))488			nvidia_probe_of_connector(info, 1, &edidA);489		if (edidA && !fb_parse_edid(edidA, var)) {490			printk("nvidiafb: EDID found from BUS1\n");491			monA = monitorA;492			fb_edid_to_monspecs(edidA, monA);493		}494 495		if (nvidia_probe_i2c_connector(info, 2, &edidB))496			nvidia_probe_of_connector(info, 2, &edidB);497		if (edidB && !fb_parse_edid(edidB, var)) {498			printk("nvidiafb: EDID found from BUS2\n");499			monB = monitorB;500			fb_edid_to_monspecs(edidB, monB);501		}502 503		if (slaved_on_A && !tvA) {504			CRTCnumber = 0;505			FlatPanel = 1;506			printk("nvidiafb: CRTC 0 is currently programmed for "507			       "DFP\n");508		} else if (slaved_on_B && !tvB) {509			CRTCnumber = 1;510			FlatPanel = 1;511			printk("nvidiafb: CRTC 1 is currently programmed "512			       "for DFP\n");513		} else if (analog_on_A) {514			CRTCnumber = outputAfromCRTC;515			FlatPanel = 0;516			printk("nvidiafb: CRTC %i appears to have a "517			       "CRT attached\n", CRTCnumber);518		} else if (analog_on_B) {519			CRTCnumber = outputBfromCRTC;520			FlatPanel = 0;521			printk("nvidiafb: CRTC %i appears to have a "522			       "CRT attached\n", CRTCnumber);523		} else if (slaved_on_A) {524			CRTCnumber = 0;525			FlatPanel = 1;526			Television = 1;527			printk("nvidiafb: CRTC 0 is currently programmed "528			       "for TV\n");529		} else if (slaved_on_B) {530			CRTCnumber = 1;531			FlatPanel = 1;532			Television = 1;533			printk("nvidiafb: CRTC 1 is currently programmed for "534			       "TV\n");535		} else if (monA) {536			FlatPanel = (monA->input & FB_DISP_DDI) ? 1 : 0;537		} else if (monB) {538			FlatPanel = (monB->input & FB_DISP_DDI) ? 1 : 0;539		}540 541		if (par->FlatPanel == -1) {542			if (FlatPanel != -1) {543				par->FlatPanel = FlatPanel;544				par->Television = Television;545			} else {546				printk("nvidiafb: Unable to detect display "547				       "type...\n");548				if (mobile) {549					printk("...On a laptop, assuming "550					       "DFP\n");551					par->FlatPanel = 1;552				} else {553					printk("...Using default of CRT\n");554					par->FlatPanel = 0;555				}556			}557		} else {558			printk("nvidiafb: Forcing display type to %s as "559			       "specified\n", par->FlatPanel ? "DFP" : "CRT");560		}561 562		if (par->CRTCnumber == -1) {563			if (CRTCnumber != -1)564				par->CRTCnumber = CRTCnumber;565			else {566				printk("nvidiafb: Unable to detect which "567				       "CRTCNumber...\n");568				if (par->FlatPanel)569					par->CRTCnumber = 1;570				else571					par->CRTCnumber = 0;572				printk("...Defaulting to CRTCNumber %i\n",573				       par->CRTCnumber);574			}575		} else {576			printk("nvidiafb: Forcing CRTCNumber %i as "577			       "specified\n", par->CRTCnumber);578		}579 580		if (monA) {581			if (((monA->input & FB_DISP_DDI) &&582			     par->FlatPanel) ||583			    ((!(monA->input & FB_DISP_DDI)) &&584			     !par->FlatPanel)) {585				if (monB) {586					fb_destroy_modedb(monB->modedb);587					monB = NULL;588				}589			} else {590				fb_destroy_modedb(monA->modedb);591				monA = NULL;592			}593		}594 595		if (monB) {596			if (((monB->input & FB_DISP_DDI) &&597			     !par->FlatPanel) ||598			    ((!(monB->input & FB_DISP_DDI)) &&599			     par->FlatPanel)) {600				fb_destroy_modedb(monB->modedb);601				monB = NULL;602			} else603				monA = monB;604		}605 606		if (implementation == 0x0110)607			cr44 = par->CRTCnumber * 0x3;608 609		NV_WR32(par->PCRTC0, 0x00000860, oldhead);610 611		VGA_WR08(par->PCIO, 0x03D4, 0x44);612		VGA_WR08(par->PCIO, 0x03D5, cr44);613		NVSelectHeadRegisters(par, par->CRTCnumber);614	}615 616	printk("nvidiafb: Using %s on CRTC %i\n",617	       par->FlatPanel ? (par->Television ? "TV" : "DFP") : "CRT",618	       par->CRTCnumber);619 620	if (par->FlatPanel && !par->Television) {621		par->fpWidth = NV_RD32(par->PRAMDAC, 0x0820) + 1;622		par->fpHeight = NV_RD32(par->PRAMDAC, 0x0800) + 1;623		par->fpSyncs = NV_RD32(par->PRAMDAC, 0x0848) & 0x30000033;624 625		printk("nvidiafb: Panel size is %i x %i\n", par->fpWidth, par->fpHeight);626	}627 628	if (monA)629		info->monspecs = *monA;630 631	if (!par->FlatPanel || !par->twoHeads)632		par->FPDither = 0;633 634	par->LVDS = 0;635	if (par->FlatPanel && par->twoHeads) {636		NV_WR32(par->PRAMDAC0, 0x08B0, 0x00010004);637		if (NV_RD32(par->PRAMDAC0, 0x08b4) & 1)638			par->LVDS = 1;639		printk("nvidiafb: Panel is %s\n", par->LVDS ? "LVDS" : "TMDS");640	}641 642	kfree(edidA);643	kfree(edidB);644done:645	kfree(var);646	kfree(monitorA);647	kfree(monitorB);648	return err;649}650