18c2ecf20Sopenharmony_ci /***************************************************************************\
28c2ecf20Sopenharmony_ci|*                                                                           *|
38c2ecf20Sopenharmony_ci|*       Copyright 2003 NVIDIA, Corporation.  All rights reserved.           *|
48c2ecf20Sopenharmony_ci|*                                                                           *|
58c2ecf20Sopenharmony_ci|*     NOTICE TO USER:   The source code  is copyrighted under  U.S. and     *|
68c2ecf20Sopenharmony_ci|*     international laws.  Users and possessors of this source code are     *|
78c2ecf20Sopenharmony_ci|*     hereby granted a nonexclusive,  royalty-free copyright license to     *|
88c2ecf20Sopenharmony_ci|*     use this code in individual and commercial software.                  *|
98c2ecf20Sopenharmony_ci|*                                                                           *|
108c2ecf20Sopenharmony_ci|*     Any use of this source code must include,  in the user documenta-     *|
118c2ecf20Sopenharmony_ci|*     tion and  internal comments to the code,  notices to the end user     *|
128c2ecf20Sopenharmony_ci|*     as follows:                                                           *|
138c2ecf20Sopenharmony_ci|*                                                                           *|
148c2ecf20Sopenharmony_ci|*       Copyright 2003 NVIDIA, Corporation.  All rights reserved.           *|
158c2ecf20Sopenharmony_ci|*                                                                           *|
168c2ecf20Sopenharmony_ci|*     NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY     *|
178c2ecf20Sopenharmony_ci|*     OF  THIS SOURCE  CODE  FOR ANY PURPOSE.  IT IS  PROVIDED  "AS IS"     *|
188c2ecf20Sopenharmony_ci|*     WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND.  NVIDIA, CORPOR-     *|
198c2ecf20Sopenharmony_ci|*     ATION DISCLAIMS ALL WARRANTIES  WITH REGARD  TO THIS SOURCE CODE,     *|
208c2ecf20Sopenharmony_ci|*     INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE-     *|
218c2ecf20Sopenharmony_ci|*     MENT,  AND FITNESS  FOR A PARTICULAR PURPOSE.   IN NO EVENT SHALL     *|
228c2ecf20Sopenharmony_ci|*     NVIDIA, CORPORATION  BE LIABLE FOR ANY SPECIAL,  INDIRECT,  INCI-     *|
238c2ecf20Sopenharmony_ci|*     DENTAL, OR CONSEQUENTIAL DAMAGES,  OR ANY DAMAGES  WHATSOEVER RE-     *|
248c2ecf20Sopenharmony_ci|*     SULTING FROM LOSS OF USE,  DATA OR PROFITS,  WHETHER IN AN ACTION     *|
258c2ecf20Sopenharmony_ci|*     OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,  ARISING OUT OF     *|
268c2ecf20Sopenharmony_ci|*     OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE.     *|
278c2ecf20Sopenharmony_ci|*                                                                           *|
288c2ecf20Sopenharmony_ci|*     U.S. Government  End  Users.   This source code  is a "commercial     *|
298c2ecf20Sopenharmony_ci|*     item,"  as that  term is  defined at  48 C.F.R. 2.101 (OCT 1995),     *|
308c2ecf20Sopenharmony_ci|*     consisting  of "commercial  computer  software"  and  "commercial     *|
318c2ecf20Sopenharmony_ci|*     computer  software  documentation,"  as such  terms  are  used in     *|
328c2ecf20Sopenharmony_ci|*     48 C.F.R. 12.212 (SEPT 1995)  and is provided to the U.S. Govern-     *|
338c2ecf20Sopenharmony_ci|*     ment only as  a commercial end item.   Consistent with  48 C.F.R.     *|
348c2ecf20Sopenharmony_ci|*     12.212 and  48 C.F.R. 227.7202-1 through  227.7202-4 (JUNE 1995),     *|
358c2ecf20Sopenharmony_ci|*     all U.S. Government End Users  acquire the source code  with only     *|
368c2ecf20Sopenharmony_ci|*     those rights set forth herein.                                        *|
378c2ecf20Sopenharmony_ci|*                                                                           *|
388c2ecf20Sopenharmony_ci \***************************************************************************/
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci/*
418c2ecf20Sopenharmony_ci * GPL Licensing Note - According to Mark Vojkovich, author of the Xorg/
428c2ecf20Sopenharmony_ci * XFree86 'nv' driver, this source code is provided under MIT-style licensing
438c2ecf20Sopenharmony_ci * where the source code is provided "as is" without warranty of any kind.
448c2ecf20Sopenharmony_ci * The only usage restriction is for the copyright notices to be retained
458c2ecf20Sopenharmony_ci * whenever code is used.
468c2ecf20Sopenharmony_ci *
478c2ecf20Sopenharmony_ci * Antonino Daplas <adaplas@pol.net> 2005-03-11
488c2ecf20Sopenharmony_ci */
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci#include <video/vga.h>
518c2ecf20Sopenharmony_ci#include <linux/delay.h>
528c2ecf20Sopenharmony_ci#include <linux/pci.h>
538c2ecf20Sopenharmony_ci#include <linux/slab.h>
548c2ecf20Sopenharmony_ci#include "nv_type.h"
558c2ecf20Sopenharmony_ci#include "nv_local.h"
568c2ecf20Sopenharmony_ci#include "nv_proto.h"
578c2ecf20Sopenharmony_ci/*
588c2ecf20Sopenharmony_ci * Override VGA I/O routines.
598c2ecf20Sopenharmony_ci */
608c2ecf20Sopenharmony_civoid NVWriteCrtc(struct nvidia_par *par, u8 index, u8 value)
618c2ecf20Sopenharmony_ci{
628c2ecf20Sopenharmony_ci	VGA_WR08(par->PCIO, par->IOBase + 0x04, index);
638c2ecf20Sopenharmony_ci	VGA_WR08(par->PCIO, par->IOBase + 0x05, value);
648c2ecf20Sopenharmony_ci}
658c2ecf20Sopenharmony_ciu8 NVReadCrtc(struct nvidia_par *par, u8 index)
668c2ecf20Sopenharmony_ci{
678c2ecf20Sopenharmony_ci	VGA_WR08(par->PCIO, par->IOBase + 0x04, index);
688c2ecf20Sopenharmony_ci	return (VGA_RD08(par->PCIO, par->IOBase + 0x05));
698c2ecf20Sopenharmony_ci}
708c2ecf20Sopenharmony_civoid NVWriteGr(struct nvidia_par *par, u8 index, u8 value)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	VGA_WR08(par->PVIO, VGA_GFX_I, index);
738c2ecf20Sopenharmony_ci	VGA_WR08(par->PVIO, VGA_GFX_D, value);
748c2ecf20Sopenharmony_ci}
758c2ecf20Sopenharmony_ciu8 NVReadGr(struct nvidia_par *par, u8 index)
768c2ecf20Sopenharmony_ci{
778c2ecf20Sopenharmony_ci	VGA_WR08(par->PVIO, VGA_GFX_I, index);
788c2ecf20Sopenharmony_ci	return (VGA_RD08(par->PVIO, VGA_GFX_D));
798c2ecf20Sopenharmony_ci}
808c2ecf20Sopenharmony_civoid NVWriteSeq(struct nvidia_par *par, u8 index, u8 value)
818c2ecf20Sopenharmony_ci{
828c2ecf20Sopenharmony_ci	VGA_WR08(par->PVIO, VGA_SEQ_I, index);
838c2ecf20Sopenharmony_ci	VGA_WR08(par->PVIO, VGA_SEQ_D, value);
848c2ecf20Sopenharmony_ci}
858c2ecf20Sopenharmony_ciu8 NVReadSeq(struct nvidia_par *par, u8 index)
868c2ecf20Sopenharmony_ci{
878c2ecf20Sopenharmony_ci	VGA_WR08(par->PVIO, VGA_SEQ_I, index);
888c2ecf20Sopenharmony_ci	return (VGA_RD08(par->PVIO, VGA_SEQ_D));
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_civoid NVWriteAttr(struct nvidia_par *par, u8 index, u8 value)
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci	volatile u8 tmp;
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	tmp = VGA_RD08(par->PCIO, par->IOBase + 0x0a);
958c2ecf20Sopenharmony_ci	if (par->paletteEnabled)
968c2ecf20Sopenharmony_ci		index &= ~0x20;
978c2ecf20Sopenharmony_ci	else
988c2ecf20Sopenharmony_ci		index |= 0x20;
998c2ecf20Sopenharmony_ci	VGA_WR08(par->PCIO, VGA_ATT_IW, index);
1008c2ecf20Sopenharmony_ci	VGA_WR08(par->PCIO, VGA_ATT_W, value);
1018c2ecf20Sopenharmony_ci}
1028c2ecf20Sopenharmony_ciu8 NVReadAttr(struct nvidia_par *par, u8 index)
1038c2ecf20Sopenharmony_ci{
1048c2ecf20Sopenharmony_ci	volatile u8 tmp;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	tmp = VGA_RD08(par->PCIO, par->IOBase + 0x0a);
1078c2ecf20Sopenharmony_ci	if (par->paletteEnabled)
1088c2ecf20Sopenharmony_ci		index &= ~0x20;
1098c2ecf20Sopenharmony_ci	else
1108c2ecf20Sopenharmony_ci		index |= 0x20;
1118c2ecf20Sopenharmony_ci	VGA_WR08(par->PCIO, VGA_ATT_IW, index);
1128c2ecf20Sopenharmony_ci	return (VGA_RD08(par->PCIO, VGA_ATT_R));
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_civoid NVWriteMiscOut(struct nvidia_par *par, u8 value)
1158c2ecf20Sopenharmony_ci{
1168c2ecf20Sopenharmony_ci	VGA_WR08(par->PVIO, VGA_MIS_W, value);
1178c2ecf20Sopenharmony_ci}
1188c2ecf20Sopenharmony_ciu8 NVReadMiscOut(struct nvidia_par *par)
1198c2ecf20Sopenharmony_ci{
1208c2ecf20Sopenharmony_ci	return (VGA_RD08(par->PVIO, VGA_MIS_R));
1218c2ecf20Sopenharmony_ci}
1228c2ecf20Sopenharmony_civoid NVWriteDacMask(struct nvidia_par *par, u8 value)
1238c2ecf20Sopenharmony_ci{
1248c2ecf20Sopenharmony_ci	VGA_WR08(par->PDIO, VGA_PEL_MSK, value);
1258c2ecf20Sopenharmony_ci}
1268c2ecf20Sopenharmony_civoid NVWriteDacReadAddr(struct nvidia_par *par, u8 value)
1278c2ecf20Sopenharmony_ci{
1288c2ecf20Sopenharmony_ci	VGA_WR08(par->PDIO, VGA_PEL_IR, value);
1298c2ecf20Sopenharmony_ci}
1308c2ecf20Sopenharmony_civoid NVWriteDacWriteAddr(struct nvidia_par *par, u8 value)
1318c2ecf20Sopenharmony_ci{
1328c2ecf20Sopenharmony_ci	VGA_WR08(par->PDIO, VGA_PEL_IW, value);
1338c2ecf20Sopenharmony_ci}
1348c2ecf20Sopenharmony_civoid NVWriteDacData(struct nvidia_par *par, u8 value)
1358c2ecf20Sopenharmony_ci{
1368c2ecf20Sopenharmony_ci	VGA_WR08(par->PDIO, VGA_PEL_D, value);
1378c2ecf20Sopenharmony_ci}
1388c2ecf20Sopenharmony_ciu8 NVReadDacData(struct nvidia_par *par)
1398c2ecf20Sopenharmony_ci{
1408c2ecf20Sopenharmony_ci	return (VGA_RD08(par->PDIO, VGA_PEL_D));
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cistatic int NVIsConnected(struct nvidia_par *par, int output)
1448c2ecf20Sopenharmony_ci{
1458c2ecf20Sopenharmony_ci	volatile u32 __iomem *PRAMDAC = par->PRAMDAC0;
1468c2ecf20Sopenharmony_ci	u32 reg52C, reg608, dac0_reg608 = 0;
1478c2ecf20Sopenharmony_ci	int present;
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	if (output) {
1508c2ecf20Sopenharmony_ci	    dac0_reg608 = NV_RD32(PRAMDAC, 0x0608);
1518c2ecf20Sopenharmony_ci	    PRAMDAC += 0x800;
1528c2ecf20Sopenharmony_ci	}
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	reg52C = NV_RD32(PRAMDAC, 0x052C);
1558c2ecf20Sopenharmony_ci	reg608 = NV_RD32(PRAMDAC, 0x0608);
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	NV_WR32(PRAMDAC, 0x0608, reg608 & ~0x00010000);
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	NV_WR32(PRAMDAC, 0x052C, reg52C & 0x0000FEEE);
1608c2ecf20Sopenharmony_ci	msleep(1);
1618c2ecf20Sopenharmony_ci	NV_WR32(PRAMDAC, 0x052C, NV_RD32(PRAMDAC, 0x052C) | 1);
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	NV_WR32(par->PRAMDAC0, 0x0610, 0x94050140);
1648c2ecf20Sopenharmony_ci	NV_WR32(par->PRAMDAC0, 0x0608, NV_RD32(par->PRAMDAC0, 0x0608) |
1658c2ecf20Sopenharmony_ci		0x00001000);
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	msleep(1);
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	present = (NV_RD32(PRAMDAC, 0x0608) & (1 << 28)) ? 1 : 0;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	if (present)
1728c2ecf20Sopenharmony_ci		printk("nvidiafb: CRTC%i analog found\n", output);
1738c2ecf20Sopenharmony_ci	else
1748c2ecf20Sopenharmony_ci		printk("nvidiafb: CRTC%i analog not found\n", output);
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	if (output)
1778c2ecf20Sopenharmony_ci	    NV_WR32(par->PRAMDAC0, 0x0608, dac0_reg608);
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	NV_WR32(PRAMDAC, 0x052C, reg52C);
1808c2ecf20Sopenharmony_ci	NV_WR32(PRAMDAC, 0x0608, reg608);
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	return present;
1838c2ecf20Sopenharmony_ci}
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_cistatic void NVSelectHeadRegisters(struct nvidia_par *par, int head)
1868c2ecf20Sopenharmony_ci{
1878c2ecf20Sopenharmony_ci	if (head) {
1888c2ecf20Sopenharmony_ci		par->PCIO = par->PCIO0 + 0x2000;
1898c2ecf20Sopenharmony_ci		par->PCRTC = par->PCRTC0 + 0x800;
1908c2ecf20Sopenharmony_ci		par->PRAMDAC = par->PRAMDAC0 + 0x800;
1918c2ecf20Sopenharmony_ci		par->PDIO = par->PDIO0 + 0x2000;
1928c2ecf20Sopenharmony_ci	} else {
1938c2ecf20Sopenharmony_ci		par->PCIO = par->PCIO0;
1948c2ecf20Sopenharmony_ci		par->PCRTC = par->PCRTC0;
1958c2ecf20Sopenharmony_ci		par->PRAMDAC = par->PRAMDAC0;
1968c2ecf20Sopenharmony_ci		par->PDIO = par->PDIO0;
1978c2ecf20Sopenharmony_ci	}
1988c2ecf20Sopenharmony_ci}
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_cistatic void nv4GetConfig(struct nvidia_par *par)
2018c2ecf20Sopenharmony_ci{
2028c2ecf20Sopenharmony_ci	if (NV_RD32(par->PFB, 0x0000) & 0x00000100) {
2038c2ecf20Sopenharmony_ci		par->RamAmountKBytes =
2048c2ecf20Sopenharmony_ci		    ((NV_RD32(par->PFB, 0x0000) >> 12) & 0x0F) * 1024 * 2 +
2058c2ecf20Sopenharmony_ci		    1024 * 2;
2068c2ecf20Sopenharmony_ci	} else {
2078c2ecf20Sopenharmony_ci		switch (NV_RD32(par->PFB, 0x0000) & 0x00000003) {
2088c2ecf20Sopenharmony_ci		case 0:
2098c2ecf20Sopenharmony_ci			par->RamAmountKBytes = 1024 * 32;
2108c2ecf20Sopenharmony_ci			break;
2118c2ecf20Sopenharmony_ci		case 1:
2128c2ecf20Sopenharmony_ci			par->RamAmountKBytes = 1024 * 4;
2138c2ecf20Sopenharmony_ci			break;
2148c2ecf20Sopenharmony_ci		case 2:
2158c2ecf20Sopenharmony_ci			par->RamAmountKBytes = 1024 * 8;
2168c2ecf20Sopenharmony_ci			break;
2178c2ecf20Sopenharmony_ci		case 3:
2188c2ecf20Sopenharmony_ci		default:
2198c2ecf20Sopenharmony_ci			par->RamAmountKBytes = 1024 * 16;
2208c2ecf20Sopenharmony_ci			break;
2218c2ecf20Sopenharmony_ci		}
2228c2ecf20Sopenharmony_ci	}
2238c2ecf20Sopenharmony_ci	par->CrystalFreqKHz = (NV_RD32(par->PEXTDEV, 0x0000) & 0x00000040) ?
2248c2ecf20Sopenharmony_ci	    14318 : 13500;
2258c2ecf20Sopenharmony_ci	par->CURSOR = &par->PRAMIN[0x1E00];
2268c2ecf20Sopenharmony_ci	par->MinVClockFreqKHz = 12000;
2278c2ecf20Sopenharmony_ci	par->MaxVClockFreqKHz = 350000;
2288c2ecf20Sopenharmony_ci}
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_cistatic void nv10GetConfig(struct nvidia_par *par)
2318c2ecf20Sopenharmony_ci{
2328c2ecf20Sopenharmony_ci	struct pci_dev *dev;
2338c2ecf20Sopenharmony_ci	u32 implementation = par->Chipset & 0x0ff0;
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN
2368c2ecf20Sopenharmony_ci	/* turn on big endian register access */
2378c2ecf20Sopenharmony_ci	if (!(NV_RD32(par->PMC, 0x0004) & 0x01000001)) {
2388c2ecf20Sopenharmony_ci		NV_WR32(par->PMC, 0x0004, 0x01000001);
2398c2ecf20Sopenharmony_ci		mb();
2408c2ecf20Sopenharmony_ci	}
2418c2ecf20Sopenharmony_ci#endif
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	dev = pci_get_domain_bus_and_slot(pci_domain_nr(par->pci_dev->bus),
2448c2ecf20Sopenharmony_ci					  0, 1);
2458c2ecf20Sopenharmony_ci	if ((par->Chipset & 0xffff) == 0x01a0) {
2468c2ecf20Sopenharmony_ci		u32 amt;
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci		pci_read_config_dword(dev, 0x7c, &amt);
2498c2ecf20Sopenharmony_ci		par->RamAmountKBytes = (((amt >> 6) & 31) + 1) * 1024;
2508c2ecf20Sopenharmony_ci	} else if ((par->Chipset & 0xffff) == 0x01f0) {
2518c2ecf20Sopenharmony_ci		u32 amt;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci		pci_read_config_dword(dev, 0x84, &amt);
2548c2ecf20Sopenharmony_ci		par->RamAmountKBytes = (((amt >> 4) & 127) + 1) * 1024;
2558c2ecf20Sopenharmony_ci	} else {
2568c2ecf20Sopenharmony_ci		par->RamAmountKBytes =
2578c2ecf20Sopenharmony_ci		    (NV_RD32(par->PFB, 0x020C) & 0xFFF00000) >> 10;
2588c2ecf20Sopenharmony_ci	}
2598c2ecf20Sopenharmony_ci	pci_dev_put(dev);
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	par->CrystalFreqKHz = (NV_RD32(par->PEXTDEV, 0x0000) & (1 << 6)) ?
2628c2ecf20Sopenharmony_ci	    14318 : 13500;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	if (par->twoHeads && (implementation != 0x0110)) {
2658c2ecf20Sopenharmony_ci		if (NV_RD32(par->PEXTDEV, 0x0000) & (1 << 22))
2668c2ecf20Sopenharmony_ci			par->CrystalFreqKHz = 27000;
2678c2ecf20Sopenharmony_ci	}
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	par->CURSOR = NULL;	/* can't set this here */
2708c2ecf20Sopenharmony_ci	par->MinVClockFreqKHz = 12000;
2718c2ecf20Sopenharmony_ci	par->MaxVClockFreqKHz = par->twoStagePLL ? 400000 : 350000;
2728c2ecf20Sopenharmony_ci}
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ciint NVCommonSetup(struct fb_info *info)
2758c2ecf20Sopenharmony_ci{
2768c2ecf20Sopenharmony_ci	struct nvidia_par *par = info->par;
2778c2ecf20Sopenharmony_ci	struct fb_var_screeninfo *var;
2788c2ecf20Sopenharmony_ci	u16 implementation = par->Chipset & 0x0ff0;
2798c2ecf20Sopenharmony_ci	u8 *edidA = NULL, *edidB = NULL;
2808c2ecf20Sopenharmony_ci	struct fb_monspecs *monitorA, *monitorB;
2818c2ecf20Sopenharmony_ci	struct fb_monspecs *monA = NULL, *monB = NULL;
2828c2ecf20Sopenharmony_ci	int mobile = 0;
2838c2ecf20Sopenharmony_ci	int tvA = 0;
2848c2ecf20Sopenharmony_ci	int tvB = 0;
2858c2ecf20Sopenharmony_ci	int FlatPanel = -1;	/* really means the CRTC is slaved */
2868c2ecf20Sopenharmony_ci	int Television = 0;
2878c2ecf20Sopenharmony_ci	int err = 0;
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	var = kzalloc(sizeof(struct fb_var_screeninfo), GFP_KERNEL);
2908c2ecf20Sopenharmony_ci	monitorA = kzalloc(sizeof(struct fb_monspecs), GFP_KERNEL);
2918c2ecf20Sopenharmony_ci	monitorB = kzalloc(sizeof(struct fb_monspecs), GFP_KERNEL);
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	if (!var || !monitorA || !monitorB) {
2948c2ecf20Sopenharmony_ci		err = -ENOMEM;
2958c2ecf20Sopenharmony_ci		goto done;
2968c2ecf20Sopenharmony_ci	}
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	par->PRAMIN = par->REGS + (0x00710000 / 4);
2998c2ecf20Sopenharmony_ci	par->PCRTC0 = par->REGS + (0x00600000 / 4);
3008c2ecf20Sopenharmony_ci	par->PRAMDAC0 = par->REGS + (0x00680000 / 4);
3018c2ecf20Sopenharmony_ci	par->PFB = par->REGS + (0x00100000 / 4);
3028c2ecf20Sopenharmony_ci	par->PFIFO = par->REGS + (0x00002000 / 4);
3038c2ecf20Sopenharmony_ci	par->PGRAPH = par->REGS + (0x00400000 / 4);
3048c2ecf20Sopenharmony_ci	par->PEXTDEV = par->REGS + (0x00101000 / 4);
3058c2ecf20Sopenharmony_ci	par->PTIMER = par->REGS + (0x00009000 / 4);
3068c2ecf20Sopenharmony_ci	par->PMC = par->REGS + (0x00000000 / 4);
3078c2ecf20Sopenharmony_ci	par->FIFO = par->REGS + (0x00800000 / 4);
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	/* 8 bit registers */
3108c2ecf20Sopenharmony_ci	par->PCIO0 = (u8 __iomem *) par->REGS + 0x00601000;
3118c2ecf20Sopenharmony_ci	par->PDIO0 = (u8 __iomem *) par->REGS + 0x00681000;
3128c2ecf20Sopenharmony_ci	par->PVIO = (u8 __iomem *) par->REGS + 0x000C0000;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	par->twoHeads = (par->Architecture >= NV_ARCH_10) &&
3158c2ecf20Sopenharmony_ci	    (implementation != 0x0100) &&
3168c2ecf20Sopenharmony_ci	    (implementation != 0x0150) &&
3178c2ecf20Sopenharmony_ci	    (implementation != 0x01A0) && (implementation != 0x0200);
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	par->fpScaler = (par->FpScale && par->twoHeads &&
3208c2ecf20Sopenharmony_ci			 (implementation != 0x0110));
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	par->twoStagePLL = (implementation == 0x0310) ||
3238c2ecf20Sopenharmony_ci	    (implementation == 0x0340) || (par->Architecture >= NV_ARCH_40);
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	par->WaitVSyncPossible = (par->Architecture >= NV_ARCH_10) &&
3268c2ecf20Sopenharmony_ci	    (implementation != 0x0100);
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	par->BlendingPossible = ((par->Chipset & 0xffff) != 0x0020);
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	/* look for known laptop chips */
3318c2ecf20Sopenharmony_ci	switch (par->Chipset & 0xffff) {
3328c2ecf20Sopenharmony_ci	case 0x0112:
3338c2ecf20Sopenharmony_ci	case 0x0174:
3348c2ecf20Sopenharmony_ci	case 0x0175:
3358c2ecf20Sopenharmony_ci	case 0x0176:
3368c2ecf20Sopenharmony_ci	case 0x0177:
3378c2ecf20Sopenharmony_ci	case 0x0179:
3388c2ecf20Sopenharmony_ci	case 0x017C:
3398c2ecf20Sopenharmony_ci	case 0x017D:
3408c2ecf20Sopenharmony_ci	case 0x0186:
3418c2ecf20Sopenharmony_ci	case 0x0187:
3428c2ecf20Sopenharmony_ci	case 0x018D:
3438c2ecf20Sopenharmony_ci	case 0x01D7:
3448c2ecf20Sopenharmony_ci	case 0x0228:
3458c2ecf20Sopenharmony_ci	case 0x0286:
3468c2ecf20Sopenharmony_ci	case 0x028C:
3478c2ecf20Sopenharmony_ci	case 0x0316:
3488c2ecf20Sopenharmony_ci	case 0x0317:
3498c2ecf20Sopenharmony_ci	case 0x031A:
3508c2ecf20Sopenharmony_ci	case 0x031B:
3518c2ecf20Sopenharmony_ci	case 0x031C:
3528c2ecf20Sopenharmony_ci	case 0x031D:
3538c2ecf20Sopenharmony_ci	case 0x031E:
3548c2ecf20Sopenharmony_ci	case 0x031F:
3558c2ecf20Sopenharmony_ci	case 0x0324:
3568c2ecf20Sopenharmony_ci	case 0x0325:
3578c2ecf20Sopenharmony_ci	case 0x0328:
3588c2ecf20Sopenharmony_ci	case 0x0329:
3598c2ecf20Sopenharmony_ci	case 0x032C:
3608c2ecf20Sopenharmony_ci	case 0x032D:
3618c2ecf20Sopenharmony_ci	case 0x0347:
3628c2ecf20Sopenharmony_ci	case 0x0348:
3638c2ecf20Sopenharmony_ci	case 0x0349:
3648c2ecf20Sopenharmony_ci	case 0x034B:
3658c2ecf20Sopenharmony_ci	case 0x034C:
3668c2ecf20Sopenharmony_ci	case 0x0160:
3678c2ecf20Sopenharmony_ci	case 0x0166:
3688c2ecf20Sopenharmony_ci	case 0x0169:
3698c2ecf20Sopenharmony_ci	case 0x016B:
3708c2ecf20Sopenharmony_ci	case 0x016C:
3718c2ecf20Sopenharmony_ci	case 0x016D:
3728c2ecf20Sopenharmony_ci	case 0x00C8:
3738c2ecf20Sopenharmony_ci	case 0x00CC:
3748c2ecf20Sopenharmony_ci	case 0x0144:
3758c2ecf20Sopenharmony_ci	case 0x0146:
3768c2ecf20Sopenharmony_ci	case 0x0147:
3778c2ecf20Sopenharmony_ci	case 0x0148:
3788c2ecf20Sopenharmony_ci	case 0x0098:
3798c2ecf20Sopenharmony_ci	case 0x0099:
3808c2ecf20Sopenharmony_ci		mobile = 1;
3818c2ecf20Sopenharmony_ci		break;
3828c2ecf20Sopenharmony_ci	default:
3838c2ecf20Sopenharmony_ci		break;
3848c2ecf20Sopenharmony_ci	}
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	if (par->Architecture == NV_ARCH_04)
3878c2ecf20Sopenharmony_ci		nv4GetConfig(par);
3888c2ecf20Sopenharmony_ci	else
3898c2ecf20Sopenharmony_ci		nv10GetConfig(par);
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	NVSelectHeadRegisters(par, 0);
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	NVLockUnlock(par, 0);
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	par->IOBase = (NVReadMiscOut(par) & 0x01) ? 0x3d0 : 0x3b0;
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	par->Television = 0;
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	nvidia_create_i2c_busses(par);
4008c2ecf20Sopenharmony_ci	if (!par->twoHeads) {
4018c2ecf20Sopenharmony_ci		par->CRTCnumber = 0;
4028c2ecf20Sopenharmony_ci		if (nvidia_probe_i2c_connector(info, 1, &edidA))
4038c2ecf20Sopenharmony_ci			nvidia_probe_of_connector(info, 1, &edidA);
4048c2ecf20Sopenharmony_ci		if (edidA && !fb_parse_edid(edidA, var)) {
4058c2ecf20Sopenharmony_ci			printk("nvidiafb: EDID found from BUS1\n");
4068c2ecf20Sopenharmony_ci			monA = monitorA;
4078c2ecf20Sopenharmony_ci			fb_edid_to_monspecs(edidA, monA);
4088c2ecf20Sopenharmony_ci			FlatPanel = (monA->input & FB_DISP_DDI) ? 1 : 0;
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci			/* NV4 doesn't support FlatPanels */
4118c2ecf20Sopenharmony_ci			if ((par->Chipset & 0x0fff) <= 0x0020)
4128c2ecf20Sopenharmony_ci				FlatPanel = 0;
4138c2ecf20Sopenharmony_ci		} else {
4148c2ecf20Sopenharmony_ci			VGA_WR08(par->PCIO, 0x03D4, 0x28);
4158c2ecf20Sopenharmony_ci			if (VGA_RD08(par->PCIO, 0x03D5) & 0x80) {
4168c2ecf20Sopenharmony_ci				VGA_WR08(par->PCIO, 0x03D4, 0x33);
4178c2ecf20Sopenharmony_ci				if (!(VGA_RD08(par->PCIO, 0x03D5) & 0x01))
4188c2ecf20Sopenharmony_ci					Television = 1;
4198c2ecf20Sopenharmony_ci				FlatPanel = 1;
4208c2ecf20Sopenharmony_ci			} else {
4218c2ecf20Sopenharmony_ci				FlatPanel = 0;
4228c2ecf20Sopenharmony_ci			}
4238c2ecf20Sopenharmony_ci			printk("nvidiafb: HW is currently programmed for %s\n",
4248c2ecf20Sopenharmony_ci			       FlatPanel ? (Television ? "TV" : "DFP") :
4258c2ecf20Sopenharmony_ci			       "CRT");
4268c2ecf20Sopenharmony_ci		}
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci		if (par->FlatPanel == -1) {
4298c2ecf20Sopenharmony_ci			par->FlatPanel = FlatPanel;
4308c2ecf20Sopenharmony_ci			par->Television = Television;
4318c2ecf20Sopenharmony_ci		} else {
4328c2ecf20Sopenharmony_ci			printk("nvidiafb: Forcing display type to %s as "
4338c2ecf20Sopenharmony_ci			       "specified\n", par->FlatPanel ? "DFP" : "CRT");
4348c2ecf20Sopenharmony_ci		}
4358c2ecf20Sopenharmony_ci	} else {
4368c2ecf20Sopenharmony_ci		u8 outputAfromCRTC, outputBfromCRTC;
4378c2ecf20Sopenharmony_ci		int CRTCnumber = -1;
4388c2ecf20Sopenharmony_ci		u8 slaved_on_A, slaved_on_B;
4398c2ecf20Sopenharmony_ci		int analog_on_A, analog_on_B;
4408c2ecf20Sopenharmony_ci		u32 oldhead;
4418c2ecf20Sopenharmony_ci		u8 cr44;
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci		if (implementation != 0x0110) {
4448c2ecf20Sopenharmony_ci			if (NV_RD32(par->PRAMDAC0, 0x0000052C) & 0x100)
4458c2ecf20Sopenharmony_ci				outputAfromCRTC = 1;
4468c2ecf20Sopenharmony_ci			else
4478c2ecf20Sopenharmony_ci				outputAfromCRTC = 0;
4488c2ecf20Sopenharmony_ci			if (NV_RD32(par->PRAMDAC0, 0x0000252C) & 0x100)
4498c2ecf20Sopenharmony_ci				outputBfromCRTC = 1;
4508c2ecf20Sopenharmony_ci			else
4518c2ecf20Sopenharmony_ci				outputBfromCRTC = 0;
4528c2ecf20Sopenharmony_ci			analog_on_A = NVIsConnected(par, 0);
4538c2ecf20Sopenharmony_ci			analog_on_B = NVIsConnected(par, 1);
4548c2ecf20Sopenharmony_ci		} else {
4558c2ecf20Sopenharmony_ci			outputAfromCRTC = 0;
4568c2ecf20Sopenharmony_ci			outputBfromCRTC = 1;
4578c2ecf20Sopenharmony_ci			analog_on_A = 0;
4588c2ecf20Sopenharmony_ci			analog_on_B = 0;
4598c2ecf20Sopenharmony_ci		}
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci		VGA_WR08(par->PCIO, 0x03D4, 0x44);
4628c2ecf20Sopenharmony_ci		cr44 = VGA_RD08(par->PCIO, 0x03D5);
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci		VGA_WR08(par->PCIO, 0x03D5, 3);
4658c2ecf20Sopenharmony_ci		NVSelectHeadRegisters(par, 1);
4668c2ecf20Sopenharmony_ci		NVLockUnlock(par, 0);
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci		VGA_WR08(par->PCIO, 0x03D4, 0x28);
4698c2ecf20Sopenharmony_ci		slaved_on_B = VGA_RD08(par->PCIO, 0x03D5) & 0x80;
4708c2ecf20Sopenharmony_ci		if (slaved_on_B) {
4718c2ecf20Sopenharmony_ci			VGA_WR08(par->PCIO, 0x03D4, 0x33);
4728c2ecf20Sopenharmony_ci			tvB = !(VGA_RD08(par->PCIO, 0x03D5) & 0x01);
4738c2ecf20Sopenharmony_ci		}
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci		VGA_WR08(par->PCIO, 0x03D4, 0x44);
4768c2ecf20Sopenharmony_ci		VGA_WR08(par->PCIO, 0x03D5, 0);
4778c2ecf20Sopenharmony_ci		NVSelectHeadRegisters(par, 0);
4788c2ecf20Sopenharmony_ci		NVLockUnlock(par, 0);
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci		VGA_WR08(par->PCIO, 0x03D4, 0x28);
4818c2ecf20Sopenharmony_ci		slaved_on_A = VGA_RD08(par->PCIO, 0x03D5) & 0x80;
4828c2ecf20Sopenharmony_ci		if (slaved_on_A) {
4838c2ecf20Sopenharmony_ci			VGA_WR08(par->PCIO, 0x03D4, 0x33);
4848c2ecf20Sopenharmony_ci			tvA = !(VGA_RD08(par->PCIO, 0x03D5) & 0x01);
4858c2ecf20Sopenharmony_ci		}
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci		oldhead = NV_RD32(par->PCRTC0, 0x00000860);
4888c2ecf20Sopenharmony_ci		NV_WR32(par->PCRTC0, 0x00000860, oldhead | 0x00000010);
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci		if (nvidia_probe_i2c_connector(info, 1, &edidA))
4918c2ecf20Sopenharmony_ci			nvidia_probe_of_connector(info, 1, &edidA);
4928c2ecf20Sopenharmony_ci		if (edidA && !fb_parse_edid(edidA, var)) {
4938c2ecf20Sopenharmony_ci			printk("nvidiafb: EDID found from BUS1\n");
4948c2ecf20Sopenharmony_ci			monA = monitorA;
4958c2ecf20Sopenharmony_ci			fb_edid_to_monspecs(edidA, monA);
4968c2ecf20Sopenharmony_ci		}
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci		if (nvidia_probe_i2c_connector(info, 2, &edidB))
4998c2ecf20Sopenharmony_ci			nvidia_probe_of_connector(info, 2, &edidB);
5008c2ecf20Sopenharmony_ci		if (edidB && !fb_parse_edid(edidB, var)) {
5018c2ecf20Sopenharmony_ci			printk("nvidiafb: EDID found from BUS2\n");
5028c2ecf20Sopenharmony_ci			monB = monitorB;
5038c2ecf20Sopenharmony_ci			fb_edid_to_monspecs(edidB, monB);
5048c2ecf20Sopenharmony_ci		}
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci		if (slaved_on_A && !tvA) {
5078c2ecf20Sopenharmony_ci			CRTCnumber = 0;
5088c2ecf20Sopenharmony_ci			FlatPanel = 1;
5098c2ecf20Sopenharmony_ci			printk("nvidiafb: CRTC 0 is currently programmed for "
5108c2ecf20Sopenharmony_ci			       "DFP\n");
5118c2ecf20Sopenharmony_ci		} else if (slaved_on_B && !tvB) {
5128c2ecf20Sopenharmony_ci			CRTCnumber = 1;
5138c2ecf20Sopenharmony_ci			FlatPanel = 1;
5148c2ecf20Sopenharmony_ci			printk("nvidiafb: CRTC 1 is currently programmed "
5158c2ecf20Sopenharmony_ci			       "for DFP\n");
5168c2ecf20Sopenharmony_ci		} else if (analog_on_A) {
5178c2ecf20Sopenharmony_ci			CRTCnumber = outputAfromCRTC;
5188c2ecf20Sopenharmony_ci			FlatPanel = 0;
5198c2ecf20Sopenharmony_ci			printk("nvidiafb: CRTC %i appears to have a "
5208c2ecf20Sopenharmony_ci			       "CRT attached\n", CRTCnumber);
5218c2ecf20Sopenharmony_ci		} else if (analog_on_B) {
5228c2ecf20Sopenharmony_ci			CRTCnumber = outputBfromCRTC;
5238c2ecf20Sopenharmony_ci			FlatPanel = 0;
5248c2ecf20Sopenharmony_ci			printk("nvidiafb: CRTC %i appears to have a "
5258c2ecf20Sopenharmony_ci			       "CRT attached\n", CRTCnumber);
5268c2ecf20Sopenharmony_ci		} else if (slaved_on_A) {
5278c2ecf20Sopenharmony_ci			CRTCnumber = 0;
5288c2ecf20Sopenharmony_ci			FlatPanel = 1;
5298c2ecf20Sopenharmony_ci			Television = 1;
5308c2ecf20Sopenharmony_ci			printk("nvidiafb: CRTC 0 is currently programmed "
5318c2ecf20Sopenharmony_ci			       "for TV\n");
5328c2ecf20Sopenharmony_ci		} else if (slaved_on_B) {
5338c2ecf20Sopenharmony_ci			CRTCnumber = 1;
5348c2ecf20Sopenharmony_ci			FlatPanel = 1;
5358c2ecf20Sopenharmony_ci			Television = 1;
5368c2ecf20Sopenharmony_ci			printk("nvidiafb: CRTC 1 is currently programmed for "
5378c2ecf20Sopenharmony_ci			       "TV\n");
5388c2ecf20Sopenharmony_ci		} else if (monA) {
5398c2ecf20Sopenharmony_ci			FlatPanel = (monA->input & FB_DISP_DDI) ? 1 : 0;
5408c2ecf20Sopenharmony_ci		} else if (monB) {
5418c2ecf20Sopenharmony_ci			FlatPanel = (monB->input & FB_DISP_DDI) ? 1 : 0;
5428c2ecf20Sopenharmony_ci		}
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci		if (par->FlatPanel == -1) {
5458c2ecf20Sopenharmony_ci			if (FlatPanel != -1) {
5468c2ecf20Sopenharmony_ci				par->FlatPanel = FlatPanel;
5478c2ecf20Sopenharmony_ci				par->Television = Television;
5488c2ecf20Sopenharmony_ci			} else {
5498c2ecf20Sopenharmony_ci				printk("nvidiafb: Unable to detect display "
5508c2ecf20Sopenharmony_ci				       "type...\n");
5518c2ecf20Sopenharmony_ci				if (mobile) {
5528c2ecf20Sopenharmony_ci					printk("...On a laptop, assuming "
5538c2ecf20Sopenharmony_ci					       "DFP\n");
5548c2ecf20Sopenharmony_ci					par->FlatPanel = 1;
5558c2ecf20Sopenharmony_ci				} else {
5568c2ecf20Sopenharmony_ci					printk("...Using default of CRT\n");
5578c2ecf20Sopenharmony_ci					par->FlatPanel = 0;
5588c2ecf20Sopenharmony_ci				}
5598c2ecf20Sopenharmony_ci			}
5608c2ecf20Sopenharmony_ci		} else {
5618c2ecf20Sopenharmony_ci			printk("nvidiafb: Forcing display type to %s as "
5628c2ecf20Sopenharmony_ci			       "specified\n", par->FlatPanel ? "DFP" : "CRT");
5638c2ecf20Sopenharmony_ci		}
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci		if (par->CRTCnumber == -1) {
5668c2ecf20Sopenharmony_ci			if (CRTCnumber != -1)
5678c2ecf20Sopenharmony_ci				par->CRTCnumber = CRTCnumber;
5688c2ecf20Sopenharmony_ci			else {
5698c2ecf20Sopenharmony_ci				printk("nvidiafb: Unable to detect which "
5708c2ecf20Sopenharmony_ci				       "CRTCNumber...\n");
5718c2ecf20Sopenharmony_ci				if (par->FlatPanel)
5728c2ecf20Sopenharmony_ci					par->CRTCnumber = 1;
5738c2ecf20Sopenharmony_ci				else
5748c2ecf20Sopenharmony_ci					par->CRTCnumber = 0;
5758c2ecf20Sopenharmony_ci				printk("...Defaulting to CRTCNumber %i\n",
5768c2ecf20Sopenharmony_ci				       par->CRTCnumber);
5778c2ecf20Sopenharmony_ci			}
5788c2ecf20Sopenharmony_ci		} else {
5798c2ecf20Sopenharmony_ci			printk("nvidiafb: Forcing CRTCNumber %i as "
5808c2ecf20Sopenharmony_ci			       "specified\n", par->CRTCnumber);
5818c2ecf20Sopenharmony_ci		}
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci		if (monA) {
5848c2ecf20Sopenharmony_ci			if (((monA->input & FB_DISP_DDI) &&
5858c2ecf20Sopenharmony_ci			     par->FlatPanel) ||
5868c2ecf20Sopenharmony_ci			    ((!(monA->input & FB_DISP_DDI)) &&
5878c2ecf20Sopenharmony_ci			     !par->FlatPanel)) {
5888c2ecf20Sopenharmony_ci				if (monB) {
5898c2ecf20Sopenharmony_ci					fb_destroy_modedb(monB->modedb);
5908c2ecf20Sopenharmony_ci					monB = NULL;
5918c2ecf20Sopenharmony_ci				}
5928c2ecf20Sopenharmony_ci			} else {
5938c2ecf20Sopenharmony_ci				fb_destroy_modedb(monA->modedb);
5948c2ecf20Sopenharmony_ci				monA = NULL;
5958c2ecf20Sopenharmony_ci			}
5968c2ecf20Sopenharmony_ci		}
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci		if (monB) {
5998c2ecf20Sopenharmony_ci			if (((monB->input & FB_DISP_DDI) &&
6008c2ecf20Sopenharmony_ci			     !par->FlatPanel) ||
6018c2ecf20Sopenharmony_ci			    ((!(monB->input & FB_DISP_DDI)) &&
6028c2ecf20Sopenharmony_ci			     par->FlatPanel)) {
6038c2ecf20Sopenharmony_ci				fb_destroy_modedb(monB->modedb);
6048c2ecf20Sopenharmony_ci				monB = NULL;
6058c2ecf20Sopenharmony_ci			} else
6068c2ecf20Sopenharmony_ci				monA = monB;
6078c2ecf20Sopenharmony_ci		}
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci		if (implementation == 0x0110)
6108c2ecf20Sopenharmony_ci			cr44 = par->CRTCnumber * 0x3;
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci		NV_WR32(par->PCRTC0, 0x00000860, oldhead);
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci		VGA_WR08(par->PCIO, 0x03D4, 0x44);
6158c2ecf20Sopenharmony_ci		VGA_WR08(par->PCIO, 0x03D5, cr44);
6168c2ecf20Sopenharmony_ci		NVSelectHeadRegisters(par, par->CRTCnumber);
6178c2ecf20Sopenharmony_ci	}
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	printk("nvidiafb: Using %s on CRTC %i\n",
6208c2ecf20Sopenharmony_ci	       par->FlatPanel ? (par->Television ? "TV" : "DFP") : "CRT",
6218c2ecf20Sopenharmony_ci	       par->CRTCnumber);
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci	if (par->FlatPanel && !par->Television) {
6248c2ecf20Sopenharmony_ci		par->fpWidth = NV_RD32(par->PRAMDAC, 0x0820) + 1;
6258c2ecf20Sopenharmony_ci		par->fpHeight = NV_RD32(par->PRAMDAC, 0x0800) + 1;
6268c2ecf20Sopenharmony_ci		par->fpSyncs = NV_RD32(par->PRAMDAC, 0x0848) & 0x30000033;
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci		printk("nvidiafb: Panel size is %i x %i\n", par->fpWidth, par->fpHeight);
6298c2ecf20Sopenharmony_ci	}
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci	if (monA)
6328c2ecf20Sopenharmony_ci		info->monspecs = *monA;
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci	if (!par->FlatPanel || !par->twoHeads)
6358c2ecf20Sopenharmony_ci		par->FPDither = 0;
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci	par->LVDS = 0;
6388c2ecf20Sopenharmony_ci	if (par->FlatPanel && par->twoHeads) {
6398c2ecf20Sopenharmony_ci		NV_WR32(par->PRAMDAC0, 0x08B0, 0x00010004);
6408c2ecf20Sopenharmony_ci		if (NV_RD32(par->PRAMDAC0, 0x08b4) & 1)
6418c2ecf20Sopenharmony_ci			par->LVDS = 1;
6428c2ecf20Sopenharmony_ci		printk("nvidiafb: Panel is %s\n", par->LVDS ? "LVDS" : "TMDS");
6438c2ecf20Sopenharmony_ci	}
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci	kfree(edidA);
6468c2ecf20Sopenharmony_ci	kfree(edidB);
6478c2ecf20Sopenharmony_cidone:
6488c2ecf20Sopenharmony_ci	kfree(var);
6498c2ecf20Sopenharmony_ci	kfree(monitorA);
6508c2ecf20Sopenharmony_ci	kfree(monitorB);
6518c2ecf20Sopenharmony_ci	return err;
6528c2ecf20Sopenharmony_ci}
653