xenocara/driver/xf86-video-nv/src/nv_setup.c
2008-07-29 20:04:57 +00:00

722 lines
22 KiB
C

/*
* Copyright (c) 2003 NVIDIA, Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "nv_include.h"
/*
* Override VGA I/O routines.
*/
static void NVWriteCrtc(vgaHWPtr pVga, CARD8 index, CARD8 value)
{
NVPtr pNv = (NVPtr)pVga->MMIOBase;
VGA_WR08(pNv->PCIO, pVga->IOBase + VGA_CRTC_INDEX_OFFSET, index);
VGA_WR08(pNv->PCIO, pVga->IOBase + VGA_CRTC_DATA_OFFSET, value);
}
static CARD8 NVReadCrtc(vgaHWPtr pVga, CARD8 index)
{
NVPtr pNv = (NVPtr)pVga->MMIOBase;
VGA_WR08(pNv->PCIO, pVga->IOBase + VGA_CRTC_INDEX_OFFSET, index);
return (VGA_RD08(pNv->PCIO, pVga->IOBase + VGA_CRTC_DATA_OFFSET));
}
static void NVWriteGr(vgaHWPtr pVga, CARD8 index, CARD8 value)
{
NVPtr pNv = (NVPtr)pVga->MMIOBase;
VGA_WR08(pNv->PVIO, VGA_GRAPH_INDEX, index);
VGA_WR08(pNv->PVIO, VGA_GRAPH_DATA, value);
}
static CARD8 NVReadGr(vgaHWPtr pVga, CARD8 index)
{
NVPtr pNv = (NVPtr)pVga->MMIOBase;
VGA_WR08(pNv->PVIO, VGA_GRAPH_INDEX, index);
return (VGA_RD08(pNv->PVIO, VGA_GRAPH_DATA));
}
static void NVWriteSeq(vgaHWPtr pVga, CARD8 index, CARD8 value)
{
NVPtr pNv = (NVPtr)pVga->MMIOBase;
VGA_WR08(pNv->PVIO, VGA_SEQ_INDEX, index);
VGA_WR08(pNv->PVIO, VGA_SEQ_DATA, value);
}
static CARD8 NVReadSeq(vgaHWPtr pVga, CARD8 index)
{
NVPtr pNv = (NVPtr)pVga->MMIOBase;
VGA_WR08(pNv->PVIO, VGA_SEQ_INDEX, index);
return (VGA_RD08(pNv->PVIO, VGA_SEQ_DATA));
}
static void NVWriteAttr(vgaHWPtr pVga, CARD8 index, CARD8 value)
{
NVPtr pNv = (NVPtr)pVga->MMIOBase;
volatile CARD8 tmp;
tmp = VGA_RD08(pNv->PCIO, pVga->IOBase + VGA_IN_STAT_1_OFFSET);
if (pVga->paletteEnabled)
index &= ~0x20;
else
index |= 0x20;
VGA_WR08(pNv->PCIO, VGA_ATTR_INDEX, index);
VGA_WR08(pNv->PCIO, VGA_ATTR_DATA_W, value);
}
static CARD8 NVReadAttr(vgaHWPtr pVga, CARD8 index)
{
NVPtr pNv = (NVPtr)pVga->MMIOBase;
volatile CARD8 tmp;
tmp = VGA_RD08(pNv->PCIO, pVga->IOBase + VGA_IN_STAT_1_OFFSET);
if (pVga->paletteEnabled)
index &= ~0x20;
else
index |= 0x20;
VGA_WR08(pNv->PCIO, VGA_ATTR_INDEX, index);
return (VGA_RD08(pNv->PCIO, VGA_ATTR_DATA_R));
}
static void NVWriteMiscOut(vgaHWPtr pVga, CARD8 value)
{
NVPtr pNv = (NVPtr)pVga->MMIOBase;
VGA_WR08(pNv->PVIO, VGA_MISC_OUT_W, value);
}
static CARD8 NVReadMiscOut(vgaHWPtr pVga)
{
NVPtr pNv = (NVPtr)pVga->MMIOBase;
return (VGA_RD08(pNv->PVIO, VGA_MISC_OUT_R));
}
static void NVEnablePalette(vgaHWPtr pVga)
{
NVPtr pNv = (NVPtr)pVga->MMIOBase;
volatile CARD8 tmp;
tmp = VGA_RD08(pNv->PCIO, pVga->IOBase + VGA_IN_STAT_1_OFFSET);
VGA_WR08(pNv->PCIO, VGA_ATTR_INDEX, 0x00);
pVga->paletteEnabled = TRUE;
}
static void NVDisablePalette(vgaHWPtr pVga)
{
NVPtr pNv = (NVPtr)pVga->MMIOBase;
volatile CARD8 tmp;
tmp = VGA_RD08(pNv->PCIO, pVga->IOBase + VGA_IN_STAT_1_OFFSET);
VGA_WR08(pNv->PCIO, VGA_ATTR_INDEX, 0x20);
pVga->paletteEnabled = FALSE;
}
static void NVWriteDacMask(vgaHWPtr pVga, CARD8 value)
{
NVPtr pNv = (NVPtr)pVga->MMIOBase;
VGA_WR08(pNv->PDIO, VGA_DAC_MASK, value);
}
static CARD8 NVReadDacMask(vgaHWPtr pVga)
{
NVPtr pNv = (NVPtr)pVga->MMIOBase;
return (VGA_RD08(pNv->PDIO, VGA_DAC_MASK));
}
static void NVWriteDacReadAddr(vgaHWPtr pVga, CARD8 value)
{
NVPtr pNv = (NVPtr)pVga->MMIOBase;
VGA_WR08(pNv->PDIO, VGA_DAC_READ_ADDR, value);
}
static void NVWriteDacWriteAddr(vgaHWPtr pVga, CARD8 value)
{
NVPtr pNv = (NVPtr)pVga->MMIOBase;
VGA_WR08(pNv->PDIO, VGA_DAC_WRITE_ADDR, value);
}
static void NVWriteDacData(vgaHWPtr pVga, CARD8 value)
{
NVPtr pNv = (NVPtr)pVga->MMIOBase;
VGA_WR08(pNv->PDIO, VGA_DAC_DATA, value);
}
static CARD8 NVReadDacData(vgaHWPtr pVga)
{
NVPtr pNv = (NVPtr)pVga->MMIOBase;
return (VGA_RD08(pNv->PDIO, VGA_DAC_DATA));
}
static Bool
NVIsConnected (ScrnInfoPtr pScrn, int output)
{
NVPtr pNv = NVPTR(pScrn);
volatile U032 *PRAMDAC = pNv->PRAMDAC0;
CARD32 reg52C, reg608, dac0_reg608 = 0;
Bool present;
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Probing for analog device on output %s...\n",
output ? "B" : "A");
if(output) {
dac0_reg608 = PRAMDAC[0x0608/4];
PRAMDAC += 0x800;
}
reg52C = PRAMDAC[0x052C/4];
reg608 = PRAMDAC[0x0608/4];
PRAMDAC[0x0608/4] = reg608 & ~0x00010000;
PRAMDAC[0x052C/4] = reg52C & 0x0000FEEE;
usleep(1000);
PRAMDAC[0x052C/4] |= 1;
pNv->PRAMDAC0[0x0610/4] = 0x94050140;
pNv->PRAMDAC0[0x0608/4] |= 0x00001000;
usleep(1000);
present = (PRAMDAC[0x0608/4] & (1 << 28)) ? TRUE : FALSE;
if(present)
xf86DrvMsg(pScrn->scrnIndex, X_PROBED, " ...found one\n");
else
xf86DrvMsg(pScrn->scrnIndex, X_PROBED, " ...can't find one\n");
if(output)
pNv->PRAMDAC0[0x0608/4] = dac0_reg608;
PRAMDAC[0x052C/4] = reg52C;
PRAMDAC[0x0608/4] = reg608;
return present;
}
static void
NVSelectHeadRegisters(ScrnInfoPtr pScrn, int head)
{
NVPtr pNv = NVPTR(pScrn);
if(head) {
pNv->PCIO = pNv->PCIO0 + 0x2000;
pNv->PCRTC = pNv->PCRTC0 + 0x800;
pNv->PRAMDAC = pNv->PRAMDAC0 + 0x800;
pNv->PDIO = pNv->PDIO0 + 0x2000;
} else {
pNv->PCIO = pNv->PCIO0;
pNv->PCRTC = pNv->PCRTC0;
pNv->PRAMDAC = pNv->PRAMDAC0;
pNv->PDIO = pNv->PDIO0;
}
}
static xf86MonPtr
NVProbeDDC (ScrnInfoPtr pScrn, int bus)
{
NVPtr pNv = NVPTR(pScrn);
xf86MonPtr MonInfo = NULL;
if(!pNv->I2C) return NULL;
pNv->DDCBase = bus ? 0x36 : 0x3e;
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Probing for EDID on I2C bus %s...\n", bus ? "B" : "A");
if ((MonInfo = xf86DoEDID_DDC2(pScrn->scrnIndex, pNv->I2C))) {
xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
"DDC detected a %s:\n", MonInfo->features.input_type ?
"DFP" : "CRT");
xf86PrintEDID( MonInfo );
} else {
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
" ... none found\n");
}
return MonInfo;
}
static void nv4GetConfig (NVPtr pNv)
{
if (pNv->PFB[0x0000/4] & 0x00000100) {
pNv->RamAmountKBytes = ((pNv->PFB[0x0000/4] >> 12) & 0x0F) * 1024 * 2
+ 1024 * 2;
} else {
switch (pNv->PFB[0x0000/4] & 0x00000003) {
case 0:
pNv->RamAmountKBytes = 1024 * 32;
break;
case 1:
pNv->RamAmountKBytes = 1024 * 4;
break;
case 2:
pNv->RamAmountKBytes = 1024 * 8;
break;
case 3:
default:
pNv->RamAmountKBytes = 1024 * 16;
break;
}
}
pNv->CrystalFreqKHz = (pNv->PEXTDEV[0x0000/4] & 0x00000040) ? 14318 : 13500;
pNv->CURSOR = &(pNv->PRAMIN[0x1E00]);
pNv->MinVClockFreqKHz = 12000;
pNv->MaxVClockFreqKHz = 350000;
}
static void nv10GetConfig (NVPtr pNv)
{
CARD32 implementation = pNv->Chipset & 0x0ff0;
#if X_BYTE_ORDER == X_BIG_ENDIAN
/* turn on big endian register access */
if(!(pNv->PMC[0x0004/4] & 0x01000001)) {
pNv->PMC[0x0004/4] = 0x01000001;
mem_barrier();
}
#endif
#if XSERVER_LIBPCIACCESS
{
/* [AGP]: I don't know if this is correct */
struct pci_device *dev = pci_device_find_by_slot(0, 0, 0, 1);
if(implementation == 0x01a0) {
uint32_t amt;
pci_device_cfg_read_u32(dev, &amt, 0x7C);
pNv->RamAmountKBytes = (((amt >> 6) & 31) + 1) * 1024;
} else if(implementation == 0x01f0) {
uint32_t amt;
pci_device_cfg_read_u32(dev, &amt, 0x84);
pNv->RamAmountKBytes = (((amt >> 4) & 127) + 1) * 1024;
} else {
pNv->RamAmountKBytes = (pNv->PFB[0x020C/4] & 0xFFF00000) >> 10;
}
}
#else
if(implementation == 0x01a0) {
int amt = pciReadLong(pciTag(0, 0, 1), 0x7C);
pNv->RamAmountKBytes = (((amt >> 6) & 31) + 1) * 1024;
} else if(implementation == 0x01f0) {
int amt = pciReadLong(pciTag(0, 0, 1), 0x84);
pNv->RamAmountKBytes = (((amt >> 4) & 127) + 1) * 1024;
} else {
pNv->RamAmountKBytes = (pNv->PFB[0x020C/4] & 0xFFF00000) >> 10;
}
#endif
if(pNv->RamAmountKBytes > 256*1024)
pNv->RamAmountKBytes = 256*1024;
pNv->CrystalFreqKHz = (pNv->PEXTDEV[0x0000/4] & (1 << 6)) ? 14318 : 13500;
if(pNv->twoHeads && (implementation != 0x0110))
{
if(pNv->PEXTDEV[0x0000/4] & (1 << 22))
pNv->CrystalFreqKHz = 27000;
}
pNv->CURSOR = NULL; /* can't set this here */
pNv->MinVClockFreqKHz = 12000;
pNv->MaxVClockFreqKHz = pNv->twoStagePLL ? 400000 : 350000;
}
void
NVCommonSetup(ScrnInfoPtr pScrn)
{
NVPtr pNv = NVPTR(pScrn);
vgaHWPtr pVga = VGAHWPTR(pScrn);
CARD16 implementation = pNv->Chipset & 0x0ff0;
xf86MonPtr monitorA, monitorB;
Bool mobile = FALSE;
Bool tvA = FALSE;
Bool tvB = FALSE;
int FlatPanel = -1; /* really means the CRTC is slaved */
Bool Television = FALSE;
void *tmp;
/*
* Override VGA I/O routines.
*/
pVga->writeCrtc = NVWriteCrtc;
pVga->readCrtc = NVReadCrtc;
pVga->writeGr = NVWriteGr;
pVga->readGr = NVReadGr;
pVga->writeAttr = NVWriteAttr;
pVga->readAttr = NVReadAttr;
pVga->writeSeq = NVWriteSeq;
pVga->readSeq = NVReadSeq;
pVga->writeMiscOut = NVWriteMiscOut;
pVga->readMiscOut = NVReadMiscOut;
pVga->enablePalette = NVEnablePalette;
pVga->disablePalette = NVDisablePalette;
pVga->writeDacMask = NVWriteDacMask;
pVga->readDacMask = NVReadDacMask;
pVga->writeDacWriteAddr = NVWriteDacWriteAddr;
pVga->writeDacReadAddr = NVWriteDacReadAddr;
pVga->writeDacData = NVWriteDacData;
pVga->readDacData = NVReadDacData;
/*
* Note: There are different pointers to the CRTC/AR and GR/SEQ registers.
* Bastardize the intended uses of these to make it work.
*/
pVga->MMIOBase = (CARD8 *)pNv;
pVga->MMIOOffset = 0;
#if XSERVER_LIBPCIACCESS
pci_device_map_range(pNv->PciInfo, pNv->IOAddress, 0x01000000,
PCI_DEV_MAP_FLAG_WRITABLE, &tmp);
#else
tmp = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO | VIDMEM_READSIDEEFFECT,
pNv->PciTag, pNv->IOAddress, 0x01000000);
#endif
pNv->REGS = tmp;
pNv->PRAMIN = pNv->REGS + (0x00710000/4);
pNv->PCRTC0 = pNv->REGS + (0x00600000/4);
pNv->PRAMDAC0 = pNv->REGS + (0x00680000/4);
pNv->PFB = pNv->REGS + (0x00100000/4);
pNv->PFIFO = pNv->REGS + (0x00002000/4);
pNv->PGRAPH = pNv->REGS + (0x00400000/4);
pNv->PEXTDEV = pNv->REGS + (0x00101000/4);
pNv->PTIMER = pNv->REGS + (0x00009000/4);
pNv->PMC = pNv->REGS + (0x00000000/4);
pNv->FIFO = pNv->REGS + (0x00800000/4);
/* 8 bit registers */
pNv->PCIO0 = (U008*)pNv->REGS + 0x00601000;
pNv->PDIO0 = (U008*)pNv->REGS + 0x00681000;
pNv->PVIO = (U008*)pNv->REGS + 0x000C0000;
pNv->twoHeads = (pNv->Architecture >= NV_ARCH_10) &&
(implementation != 0x0100) &&
(implementation != 0x0150) &&
(implementation != 0x01A0) &&
(implementation != 0x0200);
pNv->fpScaler = (pNv->FpScale && pNv->twoHeads && (implementation!=0x0110));
pNv->twoStagePLL = (implementation == 0x0310) ||
(implementation == 0x0340) ||
(pNv->Architecture >= NV_ARCH_40);
pNv->WaitVSyncPossible = (pNv->Architecture >= NV_ARCH_10) &&
(implementation != 0x0100);
pNv->BlendingPossible = ((pNv->Chipset & 0xffff) != 0x0020);
/* look for known laptop chips */
switch(pNv->Chipset & 0xffff) {
case 0x0112:
case 0x0174:
case 0x0175:
case 0x0176:
case 0x0177:
case 0x0179:
case 0x017C:
case 0x017D:
case 0x0186:
case 0x0187:
case 0x018D:
case 0x0228:
case 0x0286:
case 0x028C:
case 0x0316:
case 0x0317:
case 0x031A:
case 0x031B:
case 0x031C:
case 0x031D:
case 0x031E:
case 0x031F:
case 0x0324:
case 0x0325:
case 0x0328:
case 0x0329:
case 0x032C:
case 0x032D:
case 0x0347:
case 0x0348:
case 0x0349:
case 0x034B:
case 0x034C:
case 0x0160:
case 0x0166:
case 0x0169:
case 0x016B:
case 0x016C:
case 0x016D:
case 0x00C8:
case 0x00CC:
case 0x0144:
case 0x0146:
case 0x0148:
case 0x0098:
case 0x0099:
mobile = TRUE;
break;
default:
break;
}
if(pNv->Architecture == NV_ARCH_04)
nv4GetConfig(pNv);
else
nv10GetConfig(pNv);
NVSelectHeadRegisters(pScrn, 0);
NVLockUnlock(pNv, 0);
NVI2CInit(pScrn);
pNv->Television = FALSE;
if(!pNv->twoHeads) {
pNv->CRTCnumber = 0;
if((monitorA = NVProbeDDC(pScrn, 0))) {
FlatPanel = monitorA->features.input_type ? 1 : 0;
/* NV4 doesn't support FlatPanels */
if((pNv->Chipset & 0x0fff) <= 0x0020)
FlatPanel = 0;
} else {
VGA_WR08(pNv->PCIO, 0x03D4, 0x28);
if(VGA_RD08(pNv->PCIO, 0x03D5) & 0x80) {
VGA_WR08(pNv->PCIO, 0x03D4, 0x33);
if(!(VGA_RD08(pNv->PCIO, 0x03D5) & 0x01))
Television = TRUE;
FlatPanel = 1;
} else {
FlatPanel = 0;
}
xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
"HW is currently programmed for %s\n",
FlatPanel ? (Television ? "TV" : "DFP") : "CRT");
}
if(pNv->FlatPanel == -1) {
pNv->FlatPanel = FlatPanel;
pNv->Television = Television;
} else {
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
"Forcing display type to %s as specified\n",
pNv->FlatPanel ? "DFP" : "CRT");
}
} else {
CARD8 outputAfromCRTC, outputBfromCRTC;
int CRTCnumber = -1;
CARD8 slaved_on_A, slaved_on_B;
Bool analog_on_A, analog_on_B;
CARD32 oldhead;
CARD8 cr44;
if(implementation != 0x0110) {
if(pNv->PRAMDAC0[0x0000052C/4] & 0x100)
outputAfromCRTC = 1;
else
outputAfromCRTC = 0;
if(pNv->PRAMDAC0[0x0000252C/4] & 0x100)
outputBfromCRTC = 1;
else
outputBfromCRTC = 0;
analog_on_A = NVIsConnected(pScrn, 0);
analog_on_B = NVIsConnected(pScrn, 1);
} else {
outputAfromCRTC = 0;
outputBfromCRTC = 1;
analog_on_A = FALSE;
analog_on_B = FALSE;
}
VGA_WR08(pNv->PCIO, 0x03D4, 0x44);
cr44 = VGA_RD08(pNv->PCIO, 0x03D5);
VGA_WR08(pNv->PCIO, 0x03D5, 3);
NVSelectHeadRegisters(pScrn, 1);
NVLockUnlock(pNv, 0);
VGA_WR08(pNv->PCIO, 0x03D4, 0x28);
slaved_on_B = VGA_RD08(pNv->PCIO, 0x03D5) & 0x80;
if(slaved_on_B) {
VGA_WR08(pNv->PCIO, 0x03D4, 0x33);
tvB = !(VGA_RD08(pNv->PCIO, 0x03D5) & 0x01);
}
VGA_WR08(pNv->PCIO, 0x03D4, 0x44);
VGA_WR08(pNv->PCIO, 0x03D5, 0);
NVSelectHeadRegisters(pScrn, 0);
NVLockUnlock(pNv, 0);
VGA_WR08(pNv->PCIO, 0x03D4, 0x28);
slaved_on_A = VGA_RD08(pNv->PCIO, 0x03D5) & 0x80;
if(slaved_on_A) {
VGA_WR08(pNv->PCIO, 0x03D4, 0x33);
tvA = !(VGA_RD08(pNv->PCIO, 0x03D5) & 0x01);
}
oldhead = pNv->PCRTC0[0x00000860/4];
pNv->PCRTC0[0x00000860/4] = oldhead | 0x00000010;
monitorA = NVProbeDDC(pScrn, 0);
monitorB = NVProbeDDC(pScrn, 1);
if(slaved_on_A && !tvA) {
CRTCnumber = 0;
FlatPanel = 1;
xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
"CRTC 0 is currently programmed for DFP\n");
} else
if(slaved_on_B && !tvB) {
CRTCnumber = 1;
FlatPanel = 1;
xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
"CRTC 1 is currently programmed for DFP\n");
} else
if(analog_on_A) {
CRTCnumber = outputAfromCRTC;
FlatPanel = 0;
xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
"CRTC %i appears to have a CRT attached\n", CRTCnumber);
} else
if(analog_on_B) {
CRTCnumber = outputBfromCRTC;
FlatPanel = 0;
xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
"CRTC %i appears to have a CRT attached\n", CRTCnumber);
} else
if(slaved_on_A) {
CRTCnumber = 0;
FlatPanel = 1;
Television = 1;
xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
"CRTC 0 is currently programmed for TV\n");
} else
if(slaved_on_B) {
CRTCnumber = 1;
FlatPanel = 1;
Television = 1;
xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
"CRTC 1 is currently programmed for TV\n");
} else
if(monitorA) {
FlatPanel = monitorA->features.input_type ? 1 : 0;
} else
if(monitorB) {
FlatPanel = monitorB->features.input_type ? 1 : 0;
}
if(pNv->FlatPanel == -1) {
if(FlatPanel != -1) {
pNv->FlatPanel = FlatPanel;
pNv->Television = Television;
} else {
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Unable to detect display type...\n");
if(mobile) {
xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT,
"...On a laptop, assuming DFP\n");
pNv->FlatPanel = 1;
} else {
xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT,
"...Using default of CRT\n");
pNv->FlatPanel = 0;
}
}
} else {
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
"Forcing display type to %s as specified\n",
pNv->FlatPanel ? "DFP" : "CRT");
}
if(pNv->CRTCnumber == -1) {
if(CRTCnumber != -1) pNv->CRTCnumber = CRTCnumber;
else {
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Unable to detect which CRTCNumber...\n");
if(pNv->FlatPanel) pNv->CRTCnumber = 1;
else pNv->CRTCnumber = 0;
xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT,
"...Defaulting to CRTCNumber %i\n", pNv->CRTCnumber);
}
} else {
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
"Forcing CRTCNumber %i as specified\n", pNv->CRTCnumber);
}
if(monitorA) {
if((monitorA->features.input_type && pNv->FlatPanel) ||
(!monitorA->features.input_type && !pNv->FlatPanel))
{
if(monitorB) {
xfree(monitorB);
monitorB = NULL;
}
} else {
xfree(monitorA);
monitorA = NULL;
}
}
if(monitorB) {
if((monitorB->features.input_type && !pNv->FlatPanel) ||
(!monitorB->features.input_type && pNv->FlatPanel))
{
xfree(monitorB);
} else {
monitorA = monitorB;
}
monitorB = NULL;
}
if(implementation == 0x0110)
cr44 = pNv->CRTCnumber * 0x3;
pNv->PCRTC0[0x00000860/4] = oldhead;
VGA_WR08(pNv->PCIO, 0x03D4, 0x44);
VGA_WR08(pNv->PCIO, 0x03D5, cr44);
NVSelectHeadRegisters(pScrn, pNv->CRTCnumber);
}
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Using %s on CRTC %i\n",
pNv->FlatPanel ? (pNv->Television ? "TV" : "DFP") : "CRT",
pNv->CRTCnumber);
if(pNv->FlatPanel && !pNv->Television) {
pNv->fpWidth = pNv->PRAMDAC[0x0820/4] + 1;
pNv->fpHeight = pNv->PRAMDAC[0x0800/4] + 1;
pNv->fpVTotal = pNv->PRAMDAC[0x804/4] + 1;
pNv->fpSyncs = pNv->PRAMDAC[0x0848/4] & 0x30000033;
xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Panel size is %i x %i\n",
pNv->fpWidth, pNv->fpHeight);
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NOTE: This driver cannot "
"reconfigure the BIOS-programmed size.\n");
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "These dimensions will be used as "
"the panel size for mode validation.\n");
}
if(monitorA)
xf86SetDDCproperties(pScrn, monitorA);
if(!pNv->FlatPanel || (pScrn->depth != 24) || !pNv->twoHeads)
pNv->FPDither = FALSE;
pNv->LVDS = FALSE;
if(pNv->FlatPanel && pNv->twoHeads) {
pNv->PRAMDAC0[0x08B0/4] = 0x00010004;
if(pNv->PRAMDAC0[0x08B4/4] & 1)
pNv->LVDS = TRUE;
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Panel is %s\n",
pNv->LVDS ? "LVDS" : "TMDS");
}
}