722 lines
22 KiB
C
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");
|
|
}
|
|
}
|