nv_setup.c revision 6257f37d
1fc5a983dSmrg/* 2fc5a983dSmrg * Copyright (c) 2003 NVIDIA, Corporation 3fc5a983dSmrg * 4fc5a983dSmrg * Permission is hereby granted, free of charge, to any person obtaining a 5fc5a983dSmrg * copy of this software and associated documentation files (the 6fc5a983dSmrg * "Software"), to deal in the Software without restriction, including 7fc5a983dSmrg * without limitation the rights to use, copy, modify, merge, publish, 8fc5a983dSmrg * distribute, sublicense, and/or sell copies of the Software, and to 9fc5a983dSmrg * permit persons to whom the Software is furnished to do so, subject to 10fc5a983dSmrg * the following conditions: 11fc5a983dSmrg * 12fc5a983dSmrg * The above copyright notice and this permission notice shall be included 13fc5a983dSmrg * in all copies or substantial portions of the Software. 14fc5a983dSmrg * 15fc5a983dSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16fc5a983dSmrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17fc5a983dSmrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18fc5a983dSmrg * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19fc5a983dSmrg * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20fc5a983dSmrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21fc5a983dSmrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22fc5a983dSmrg */ 23fc5a983dSmrg 24fc5a983dSmrg#ifdef HAVE_CONFIG_H 25fc5a983dSmrg#include "config.h" 26fc5a983dSmrg#endif 27fc5a983dSmrg 28fc5a983dSmrg#include "nv_include.h" 29fc5a983dSmrg 30fc5a983dSmrg/* 31fc5a983dSmrg * Override VGA I/O routines. 32fc5a983dSmrg */ 33fc5a983dSmrgstatic void NVWriteCrtc(vgaHWPtr pVga, CARD8 index, CARD8 value) 34fc5a983dSmrg{ 35fc5a983dSmrg NVPtr pNv = (NVPtr)pVga->MMIOBase; 36fc5a983dSmrg VGA_WR08(pNv->PCIO, pVga->IOBase + VGA_CRTC_INDEX_OFFSET, index); 37fc5a983dSmrg VGA_WR08(pNv->PCIO, pVga->IOBase + VGA_CRTC_DATA_OFFSET, value); 38fc5a983dSmrg} 39fc5a983dSmrgstatic CARD8 NVReadCrtc(vgaHWPtr pVga, CARD8 index) 40fc5a983dSmrg{ 41fc5a983dSmrg NVPtr pNv = (NVPtr)pVga->MMIOBase; 42fc5a983dSmrg VGA_WR08(pNv->PCIO, pVga->IOBase + VGA_CRTC_INDEX_OFFSET, index); 43fc5a983dSmrg return (VGA_RD08(pNv->PCIO, pVga->IOBase + VGA_CRTC_DATA_OFFSET)); 44fc5a983dSmrg} 45fc5a983dSmrgstatic void NVWriteGr(vgaHWPtr pVga, CARD8 index, CARD8 value) 46fc5a983dSmrg{ 47fc5a983dSmrg NVPtr pNv = (NVPtr)pVga->MMIOBase; 48fc5a983dSmrg VGA_WR08(pNv->PVIO, VGA_GRAPH_INDEX, index); 49fc5a983dSmrg VGA_WR08(pNv->PVIO, VGA_GRAPH_DATA, value); 50fc5a983dSmrg} 51fc5a983dSmrgstatic CARD8 NVReadGr(vgaHWPtr pVga, CARD8 index) 52fc5a983dSmrg{ 53fc5a983dSmrg NVPtr pNv = (NVPtr)pVga->MMIOBase; 54fc5a983dSmrg VGA_WR08(pNv->PVIO, VGA_GRAPH_INDEX, index); 55fc5a983dSmrg return (VGA_RD08(pNv->PVIO, VGA_GRAPH_DATA)); 56fc5a983dSmrg} 57fc5a983dSmrgstatic void NVWriteSeq(vgaHWPtr pVga, CARD8 index, CARD8 value) 58fc5a983dSmrg{ 59fc5a983dSmrg NVPtr pNv = (NVPtr)pVga->MMIOBase; 60fc5a983dSmrg VGA_WR08(pNv->PVIO, VGA_SEQ_INDEX, index); 61fc5a983dSmrg VGA_WR08(pNv->PVIO, VGA_SEQ_DATA, value); 62fc5a983dSmrg} 63fc5a983dSmrgstatic CARD8 NVReadSeq(vgaHWPtr pVga, CARD8 index) 64fc5a983dSmrg{ 65fc5a983dSmrg NVPtr pNv = (NVPtr)pVga->MMIOBase; 66fc5a983dSmrg VGA_WR08(pNv->PVIO, VGA_SEQ_INDEX, index); 67fc5a983dSmrg return (VGA_RD08(pNv->PVIO, VGA_SEQ_DATA)); 68fc5a983dSmrg} 69fc5a983dSmrgstatic void NVWriteAttr(vgaHWPtr pVga, CARD8 index, CARD8 value) 70fc5a983dSmrg{ 71fc5a983dSmrg NVPtr pNv = (NVPtr)pVga->MMIOBase; 72fc5a983dSmrg volatile CARD8 tmp; 73fc5a983dSmrg 74fc5a983dSmrg tmp = VGA_RD08(pNv->PCIO, pVga->IOBase + VGA_IN_STAT_1_OFFSET); 75fc5a983dSmrg if (pVga->paletteEnabled) 76fc5a983dSmrg index &= ~0x20; 77fc5a983dSmrg else 78fc5a983dSmrg index |= 0x20; 79fc5a983dSmrg VGA_WR08(pNv->PCIO, VGA_ATTR_INDEX, index); 80fc5a983dSmrg VGA_WR08(pNv->PCIO, VGA_ATTR_DATA_W, value); 81fc5a983dSmrg} 82fc5a983dSmrgstatic CARD8 NVReadAttr(vgaHWPtr pVga, CARD8 index) 83fc5a983dSmrg{ 84fc5a983dSmrg NVPtr pNv = (NVPtr)pVga->MMIOBase; 85fc5a983dSmrg volatile CARD8 tmp; 86fc5a983dSmrg 87fc5a983dSmrg tmp = VGA_RD08(pNv->PCIO, pVga->IOBase + VGA_IN_STAT_1_OFFSET); 88fc5a983dSmrg if (pVga->paletteEnabled) 89fc5a983dSmrg index &= ~0x20; 90fc5a983dSmrg else 91fc5a983dSmrg index |= 0x20; 92fc5a983dSmrg VGA_WR08(pNv->PCIO, VGA_ATTR_INDEX, index); 93fc5a983dSmrg return (VGA_RD08(pNv->PCIO, VGA_ATTR_DATA_R)); 94fc5a983dSmrg} 95fc5a983dSmrgstatic void NVWriteMiscOut(vgaHWPtr pVga, CARD8 value) 96fc5a983dSmrg{ 97fc5a983dSmrg NVPtr pNv = (NVPtr)pVga->MMIOBase; 98fc5a983dSmrg VGA_WR08(pNv->PVIO, VGA_MISC_OUT_W, value); 99fc5a983dSmrg} 100fc5a983dSmrgstatic CARD8 NVReadMiscOut(vgaHWPtr pVga) 101fc5a983dSmrg{ 102fc5a983dSmrg NVPtr pNv = (NVPtr)pVga->MMIOBase; 103fc5a983dSmrg return (VGA_RD08(pNv->PVIO, VGA_MISC_OUT_R)); 104fc5a983dSmrg} 105fc5a983dSmrgstatic void NVEnablePalette(vgaHWPtr pVga) 106fc5a983dSmrg{ 107fc5a983dSmrg NVPtr pNv = (NVPtr)pVga->MMIOBase; 108fc5a983dSmrg volatile CARD8 tmp; 109fc5a983dSmrg 110fc5a983dSmrg tmp = VGA_RD08(pNv->PCIO, pVga->IOBase + VGA_IN_STAT_1_OFFSET); 111fc5a983dSmrg VGA_WR08(pNv->PCIO, VGA_ATTR_INDEX, 0x00); 112fc5a983dSmrg pVga->paletteEnabled = TRUE; 113fc5a983dSmrg} 114fc5a983dSmrgstatic void NVDisablePalette(vgaHWPtr pVga) 115fc5a983dSmrg{ 116fc5a983dSmrg NVPtr pNv = (NVPtr)pVga->MMIOBase; 117fc5a983dSmrg volatile CARD8 tmp; 118fc5a983dSmrg 119fc5a983dSmrg tmp = VGA_RD08(pNv->PCIO, pVga->IOBase + VGA_IN_STAT_1_OFFSET); 120fc5a983dSmrg VGA_WR08(pNv->PCIO, VGA_ATTR_INDEX, 0x20); 121fc5a983dSmrg pVga->paletteEnabled = FALSE; 122fc5a983dSmrg} 123fc5a983dSmrgstatic void NVWriteDacMask(vgaHWPtr pVga, CARD8 value) 124fc5a983dSmrg{ 125fc5a983dSmrg NVPtr pNv = (NVPtr)pVga->MMIOBase; 126fc5a983dSmrg VGA_WR08(pNv->PDIO, VGA_DAC_MASK, value); 127fc5a983dSmrg} 128fc5a983dSmrgstatic CARD8 NVReadDacMask(vgaHWPtr pVga) 129fc5a983dSmrg{ 130fc5a983dSmrg NVPtr pNv = (NVPtr)pVga->MMIOBase; 131fc5a983dSmrg return (VGA_RD08(pNv->PDIO, VGA_DAC_MASK)); 132fc5a983dSmrg} 133fc5a983dSmrgstatic void NVWriteDacReadAddr(vgaHWPtr pVga, CARD8 value) 134fc5a983dSmrg{ 135fc5a983dSmrg NVPtr pNv = (NVPtr)pVga->MMIOBase; 136fc5a983dSmrg VGA_WR08(pNv->PDIO, VGA_DAC_READ_ADDR, value); 137fc5a983dSmrg} 138fc5a983dSmrgstatic void NVWriteDacWriteAddr(vgaHWPtr pVga, CARD8 value) 139fc5a983dSmrg{ 140fc5a983dSmrg NVPtr pNv = (NVPtr)pVga->MMIOBase; 141fc5a983dSmrg VGA_WR08(pNv->PDIO, VGA_DAC_WRITE_ADDR, value); 142fc5a983dSmrg} 143fc5a983dSmrgstatic void NVWriteDacData(vgaHWPtr pVga, CARD8 value) 144fc5a983dSmrg{ 145fc5a983dSmrg NVPtr pNv = (NVPtr)pVga->MMIOBase; 146fc5a983dSmrg VGA_WR08(pNv->PDIO, VGA_DAC_DATA, value); 147fc5a983dSmrg} 148fc5a983dSmrgstatic CARD8 NVReadDacData(vgaHWPtr pVga) 149fc5a983dSmrg{ 150fc5a983dSmrg NVPtr pNv = (NVPtr)pVga->MMIOBase; 151fc5a983dSmrg return (VGA_RD08(pNv->PDIO, VGA_DAC_DATA)); 152fc5a983dSmrg} 153fc5a983dSmrg 154fc5a983dSmrgstatic Bool 155fc5a983dSmrgNVIsConnected (ScrnInfoPtr pScrn, int output) 156fc5a983dSmrg{ 157fc5a983dSmrg NVPtr pNv = NVPTR(pScrn); 158fc5a983dSmrg volatile U032 *PRAMDAC = pNv->PRAMDAC0; 159fc5a983dSmrg CARD32 reg52C, reg608, dac0_reg608 = 0; 160fc5a983dSmrg Bool present; 161fc5a983dSmrg 162fc5a983dSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 163fc5a983dSmrg "Probing for analog device on output %s...\n", 164fc5a983dSmrg output ? "B" : "A"); 165fc5a983dSmrg 166fc5a983dSmrg if(output) { 167fc5a983dSmrg dac0_reg608 = PRAMDAC[0x0608/4]; 168fc5a983dSmrg PRAMDAC += 0x800; 169fc5a983dSmrg } 170fc5a983dSmrg 171fc5a983dSmrg reg52C = PRAMDAC[0x052C/4]; 172fc5a983dSmrg reg608 = PRAMDAC[0x0608/4]; 173fc5a983dSmrg 174fc5a983dSmrg PRAMDAC[0x0608/4] = reg608 & ~0x00010000; 175fc5a983dSmrg 176fc5a983dSmrg PRAMDAC[0x052C/4] = reg52C & 0x0000FEEE; 177fc5a983dSmrg usleep(1000); 178fc5a983dSmrg PRAMDAC[0x052C/4] |= 1; 179fc5a983dSmrg 180fc5a983dSmrg pNv->PRAMDAC0[0x0610/4] = 0x94050140; 181fc5a983dSmrg pNv->PRAMDAC0[0x0608/4] |= 0x00001000; 182fc5a983dSmrg 183fc5a983dSmrg usleep(1000); 184fc5a983dSmrg 185fc5a983dSmrg present = (PRAMDAC[0x0608/4] & (1 << 28)) ? TRUE : FALSE; 186fc5a983dSmrg 187fc5a983dSmrg if(present) 188fc5a983dSmrg xf86DrvMsg(pScrn->scrnIndex, X_PROBED, " ...found one\n"); 189fc5a983dSmrg else 190fc5a983dSmrg xf86DrvMsg(pScrn->scrnIndex, X_PROBED, " ...can't find one\n"); 191fc5a983dSmrg 192fc5a983dSmrg if(output) 193fc5a983dSmrg pNv->PRAMDAC0[0x0608/4] = dac0_reg608; 194fc5a983dSmrg 195fc5a983dSmrg PRAMDAC[0x052C/4] = reg52C; 196fc5a983dSmrg PRAMDAC[0x0608/4] = reg608; 197fc5a983dSmrg 198fc5a983dSmrg return present; 199fc5a983dSmrg} 200fc5a983dSmrg 201fc5a983dSmrgstatic void 202fc5a983dSmrgNVSelectHeadRegisters(ScrnInfoPtr pScrn, int head) 203fc5a983dSmrg{ 204fc5a983dSmrg NVPtr pNv = NVPTR(pScrn); 205fc5a983dSmrg 206fc5a983dSmrg if(head) { 207fc5a983dSmrg pNv->PCIO = pNv->PCIO0 + 0x2000; 208fc5a983dSmrg pNv->PCRTC = pNv->PCRTC0 + 0x800; 209fc5a983dSmrg pNv->PRAMDAC = pNv->PRAMDAC0 + 0x800; 210fc5a983dSmrg pNv->PDIO = pNv->PDIO0 + 0x2000; 211fc5a983dSmrg } else { 212fc5a983dSmrg pNv->PCIO = pNv->PCIO0; 213fc5a983dSmrg pNv->PCRTC = pNv->PCRTC0; 214fc5a983dSmrg pNv->PRAMDAC = pNv->PRAMDAC0; 215fc5a983dSmrg pNv->PDIO = pNv->PDIO0; 216fc5a983dSmrg } 217fc5a983dSmrg} 218fc5a983dSmrg 219fc5a983dSmrgstatic xf86MonPtr 220fc5a983dSmrgNVProbeDDC (ScrnInfoPtr pScrn, int bus) 221fc5a983dSmrg{ 222fc5a983dSmrg NVPtr pNv = NVPTR(pScrn); 223fc5a983dSmrg xf86MonPtr MonInfo = NULL; 224fc5a983dSmrg 225fc5a983dSmrg if(!pNv->I2C) return NULL; 226fc5a983dSmrg 227fc5a983dSmrg pNv->DDCBase = bus ? 0x36 : 0x3e; 228fc5a983dSmrg 229fc5a983dSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 230fc5a983dSmrg "Probing for EDID on I2C bus %s...\n", bus ? "B" : "A"); 231fc5a983dSmrg 232f3561b8bSmrg#ifdef EDID_COMPLETE_RAWDATA 233bd304fc0Smrg MonInfo = xf86DoEEDID(XF86_SCRN_ARG(pScrn), pNv->I2C, TRUE); 234f3561b8bSmrg#else 235bd304fc0Smrg MonInfo = xf86DoEDID_DDC2(XF86_SCRN_ARG(pScrn), pNv->I2C); 236f3561b8bSmrg#endif 237f3561b8bSmrg if (MonInfo) { 238fc5a983dSmrg xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 239fc5a983dSmrg "DDC detected a %s:\n", MonInfo->features.input_type ? 240fc5a983dSmrg "DFP" : "CRT"); 241fc5a983dSmrg xf86PrintEDID( MonInfo ); 242fc5a983dSmrg } else { 243fc5a983dSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 244fc5a983dSmrg " ... none found\n"); 245fc5a983dSmrg } 246fc5a983dSmrg 247fc5a983dSmrg return MonInfo; 248fc5a983dSmrg} 249fc5a983dSmrg 250fc5a983dSmrgstatic void nv4GetConfig (NVPtr pNv) 251fc5a983dSmrg{ 252fc5a983dSmrg if (pNv->PFB[0x0000/4] & 0x00000100) { 253fc5a983dSmrg pNv->RamAmountKBytes = ((pNv->PFB[0x0000/4] >> 12) & 0x0F) * 1024 * 2 254fc5a983dSmrg + 1024 * 2; 255fc5a983dSmrg } else { 256fc5a983dSmrg switch (pNv->PFB[0x0000/4] & 0x00000003) { 257fc5a983dSmrg case 0: 258fc5a983dSmrg pNv->RamAmountKBytes = 1024 * 32; 259fc5a983dSmrg break; 260fc5a983dSmrg case 1: 261fc5a983dSmrg pNv->RamAmountKBytes = 1024 * 4; 262fc5a983dSmrg break; 263fc5a983dSmrg case 2: 264fc5a983dSmrg pNv->RamAmountKBytes = 1024 * 8; 265fc5a983dSmrg break; 266fc5a983dSmrg case 3: 267fc5a983dSmrg default: 268fc5a983dSmrg pNv->RamAmountKBytes = 1024 * 16; 269fc5a983dSmrg break; 270fc5a983dSmrg } 271fc5a983dSmrg } 272fc5a983dSmrg pNv->CrystalFreqKHz = (pNv->PEXTDEV[0x0000/4] & 0x00000040) ? 14318 : 13500; 273fc5a983dSmrg pNv->CURSOR = &(pNv->PRAMIN[0x1E00]); 274fc5a983dSmrg pNv->MinVClockFreqKHz = 12000; 275fc5a983dSmrg pNv->MaxVClockFreqKHz = 350000; 276fc5a983dSmrg} 277fc5a983dSmrg 278fc5a983dSmrgstatic void nv10GetConfig (NVPtr pNv) 279fc5a983dSmrg{ 280fc5a983dSmrg CARD32 implementation = pNv->Chipset & 0x0ff0; 281fc5a983dSmrg 282fc5a983dSmrg#if X_BYTE_ORDER == X_BIG_ENDIAN 283fc5a983dSmrg /* turn on big endian register access */ 284fc5a983dSmrg if(!(pNv->PMC[0x0004/4] & 0x01000001)) { 285fc5a983dSmrg pNv->PMC[0x0004/4] = 0x01000001; 286fc5a983dSmrg mem_barrier(); 287fc5a983dSmrg } 288fc5a983dSmrg#endif 289fc5a983dSmrg 290fc5a983dSmrg#if XSERVER_LIBPCIACCESS 291fc5a983dSmrg { 292fc5a983dSmrg /* [AGP]: I don't know if this is correct */ 293fc5a983dSmrg struct pci_device *dev = pci_device_find_by_slot(0, 0, 0, 1); 294fc5a983dSmrg 295fc5a983dSmrg if(implementation == 0x01a0) { 296fc5a983dSmrg uint32_t amt; 297fc5a983dSmrg pci_device_cfg_read_u32(dev, &amt, 0x7C); 298fc5a983dSmrg pNv->RamAmountKBytes = (((amt >> 6) & 31) + 1) * 1024; 299fc5a983dSmrg } else if(implementation == 0x01f0) { 300fc5a983dSmrg uint32_t amt; 301fc5a983dSmrg pci_device_cfg_read_u32(dev, &amt, 0x84); 302fc5a983dSmrg pNv->RamAmountKBytes = (((amt >> 4) & 127) + 1) * 1024; 303fc5a983dSmrg } else { 304fc5a983dSmrg pNv->RamAmountKBytes = (pNv->PFB[0x020C/4] & 0xFFF00000) >> 10; 305fc5a983dSmrg } 306fc5a983dSmrg } 307fc5a983dSmrg#else 308fc5a983dSmrg if(implementation == 0x01a0) { 309fc5a983dSmrg int amt = pciReadLong(pciTag(0, 0, 1), 0x7C); 310fc5a983dSmrg pNv->RamAmountKBytes = (((amt >> 6) & 31) + 1) * 1024; 311fc5a983dSmrg } else if(implementation == 0x01f0) { 312fc5a983dSmrg int amt = pciReadLong(pciTag(0, 0, 1), 0x84); 313fc5a983dSmrg pNv->RamAmountKBytes = (((amt >> 4) & 127) + 1) * 1024; 314fc5a983dSmrg } else { 315fc5a983dSmrg pNv->RamAmountKBytes = (pNv->PFB[0x020C/4] & 0xFFF00000) >> 10; 316fc5a983dSmrg } 317fc5a983dSmrg#endif 318fc5a983dSmrg 319fc5a983dSmrg if(pNv->RamAmountKBytes > 256*1024) 320fc5a983dSmrg pNv->RamAmountKBytes = 256*1024; 321fc5a983dSmrg 322fc5a983dSmrg pNv->CrystalFreqKHz = (pNv->PEXTDEV[0x0000/4] & (1 << 6)) ? 14318 : 13500; 323fc5a983dSmrg 324fc5a983dSmrg if(pNv->twoHeads && (implementation != 0x0110)) 325fc5a983dSmrg { 326fc5a983dSmrg if(pNv->PEXTDEV[0x0000/4] & (1 << 22)) 327fc5a983dSmrg pNv->CrystalFreqKHz = 27000; 328fc5a983dSmrg } 329fc5a983dSmrg 330fc5a983dSmrg pNv->CURSOR = NULL; /* can't set this here */ 331fc5a983dSmrg pNv->MinVClockFreqKHz = 12000; 332fc5a983dSmrg pNv->MaxVClockFreqKHz = pNv->twoStagePLL ? 400000 : 350000; 333fc5a983dSmrg} 334fc5a983dSmrg 335fc5a983dSmrg 336fc5a983dSmrgvoid 337fc5a983dSmrgNVCommonSetup(ScrnInfoPtr pScrn) 338fc5a983dSmrg{ 339fc5a983dSmrg NVPtr pNv = NVPTR(pScrn); 340fc5a983dSmrg vgaHWPtr pVga = VGAHWPTR(pScrn); 341fc5a983dSmrg CARD16 implementation = pNv->Chipset & 0x0ff0; 342fc5a983dSmrg xf86MonPtr monitorA, monitorB; 343fc5a983dSmrg Bool mobile = FALSE; 344fc5a983dSmrg Bool tvA = FALSE; 345fc5a983dSmrg Bool tvB = FALSE; 346fc5a983dSmrg int FlatPanel = -1; /* really means the CRTC is slaved */ 347fc5a983dSmrg Bool Television = FALSE; 348fc5a983dSmrg void *tmp; 349f3561b8bSmrg#if XSERVER_LIBPCIACCESS 350f3561b8bSmrg int err; 351f3561b8bSmrg#endif 352f3561b8bSmrg 353fc5a983dSmrg /* 354fc5a983dSmrg * Override VGA I/O routines. 355fc5a983dSmrg */ 356fc5a983dSmrg pVga->writeCrtc = NVWriteCrtc; 357fc5a983dSmrg pVga->readCrtc = NVReadCrtc; 358fc5a983dSmrg pVga->writeGr = NVWriteGr; 359fc5a983dSmrg pVga->readGr = NVReadGr; 360fc5a983dSmrg pVga->writeAttr = NVWriteAttr; 361fc5a983dSmrg pVga->readAttr = NVReadAttr; 362fc5a983dSmrg pVga->writeSeq = NVWriteSeq; 363fc5a983dSmrg pVga->readSeq = NVReadSeq; 364fc5a983dSmrg pVga->writeMiscOut = NVWriteMiscOut; 365fc5a983dSmrg pVga->readMiscOut = NVReadMiscOut; 366fc5a983dSmrg pVga->enablePalette = NVEnablePalette; 367fc5a983dSmrg pVga->disablePalette = NVDisablePalette; 368fc5a983dSmrg pVga->writeDacMask = NVWriteDacMask; 369fc5a983dSmrg pVga->readDacMask = NVReadDacMask; 370fc5a983dSmrg pVga->writeDacWriteAddr = NVWriteDacWriteAddr; 371fc5a983dSmrg pVga->writeDacReadAddr = NVWriteDacReadAddr; 372fc5a983dSmrg pVga->writeDacData = NVWriteDacData; 373fc5a983dSmrg pVga->readDacData = NVReadDacData; 374fc5a983dSmrg /* 375fc5a983dSmrg * Note: There are different pointers to the CRTC/AR and GR/SEQ registers. 376fc5a983dSmrg * Bastardize the intended uses of these to make it work. 377fc5a983dSmrg */ 378fc5a983dSmrg pVga->MMIOBase = (CARD8 *)pNv; 379fc5a983dSmrg pVga->MMIOOffset = 0; 380fc5a983dSmrg 381fc5a983dSmrg#if XSERVER_LIBPCIACCESS 382f3561b8bSmrg err = pci_device_map_range(pNv->PciInfo, pNv->IOAddress, 0x01000000, 383f3561b8bSmrg PCI_DEV_MAP_FLAG_WRITABLE, &tmp); 384f3561b8bSmrg if (err != 0) { 385f3561b8bSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 386f3561b8bSmrg "pci_device_map_range failed: %s\n", strerror(err)); 387f3561b8bSmrg } 388fc5a983dSmrg#else 389fc5a983dSmrg tmp = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO | VIDMEM_READSIDEEFFECT, 390fc5a983dSmrg pNv->PciTag, pNv->IOAddress, 0x01000000); 391fc5a983dSmrg#endif 392fc5a983dSmrg pNv->REGS = tmp; 393fc5a983dSmrg 394fc5a983dSmrg pNv->PRAMIN = pNv->REGS + (0x00710000/4); 395fc5a983dSmrg pNv->PCRTC0 = pNv->REGS + (0x00600000/4); 396fc5a983dSmrg pNv->PRAMDAC0 = pNv->REGS + (0x00680000/4); 397fc5a983dSmrg pNv->PFB = pNv->REGS + (0x00100000/4); 398fc5a983dSmrg pNv->PFIFO = pNv->REGS + (0x00002000/4); 399fc5a983dSmrg pNv->PGRAPH = pNv->REGS + (0x00400000/4); 400fc5a983dSmrg pNv->PEXTDEV = pNv->REGS + (0x00101000/4); 401fc5a983dSmrg pNv->PTIMER = pNv->REGS + (0x00009000/4); 402fc5a983dSmrg pNv->PMC = pNv->REGS + (0x00000000/4); 403fc5a983dSmrg pNv->FIFO = pNv->REGS + (0x00800000/4); 404fc5a983dSmrg 405fc5a983dSmrg /* 8 bit registers */ 406fc5a983dSmrg pNv->PCIO0 = (U008*)pNv->REGS + 0x00601000; 407fc5a983dSmrg pNv->PDIO0 = (U008*)pNv->REGS + 0x00681000; 408fc5a983dSmrg pNv->PVIO = (U008*)pNv->REGS + 0x000C0000; 409fc5a983dSmrg 410fc5a983dSmrg pNv->twoHeads = (pNv->Architecture >= NV_ARCH_10) && 411fc5a983dSmrg (implementation != 0x0100) && 412fc5a983dSmrg (implementation != 0x0150) && 413fc5a983dSmrg (implementation != 0x01A0) && 414fc5a983dSmrg (implementation != 0x0200); 415fc5a983dSmrg 416fc5a983dSmrg pNv->fpScaler = (pNv->FpScale && pNv->twoHeads && (implementation!=0x0110)); 417fc5a983dSmrg 418fc5a983dSmrg pNv->twoStagePLL = (implementation == 0x0310) || 419fc5a983dSmrg (implementation == 0x0340) || 420fc5a983dSmrg (pNv->Architecture >= NV_ARCH_40); 421fc5a983dSmrg 422fc5a983dSmrg pNv->WaitVSyncPossible = (pNv->Architecture >= NV_ARCH_10) && 423fc5a983dSmrg (implementation != 0x0100); 424fc5a983dSmrg 425fc5a983dSmrg pNv->BlendingPossible = ((pNv->Chipset & 0xffff) != 0x0020); 426fc5a983dSmrg 427fc5a983dSmrg /* look for known laptop chips */ 428fc5a983dSmrg switch(pNv->Chipset & 0xffff) { 429fc5a983dSmrg case 0x0112: 430fc5a983dSmrg case 0x0174: 431fc5a983dSmrg case 0x0175: 432fc5a983dSmrg case 0x0176: 433fc5a983dSmrg case 0x0177: 434fc5a983dSmrg case 0x0179: 435fc5a983dSmrg case 0x017C: 436fc5a983dSmrg case 0x017D: 437fc5a983dSmrg case 0x0186: 438fc5a983dSmrg case 0x0187: 439fc5a983dSmrg case 0x018D: 440fc5a983dSmrg case 0x0228: 441fc5a983dSmrg case 0x0286: 442fc5a983dSmrg case 0x028C: 443fc5a983dSmrg case 0x0316: 444fc5a983dSmrg case 0x0317: 445fc5a983dSmrg case 0x031A: 446fc5a983dSmrg case 0x031B: 447fc5a983dSmrg case 0x031C: 448fc5a983dSmrg case 0x031D: 449fc5a983dSmrg case 0x031E: 450fc5a983dSmrg case 0x031F: 451fc5a983dSmrg case 0x0324: 452fc5a983dSmrg case 0x0325: 453fc5a983dSmrg case 0x0328: 454fc5a983dSmrg case 0x0329: 455fc5a983dSmrg case 0x032C: 456fc5a983dSmrg case 0x032D: 457fc5a983dSmrg case 0x0347: 458fc5a983dSmrg case 0x0348: 459fc5a983dSmrg case 0x0349: 460fc5a983dSmrg case 0x034B: 461fc5a983dSmrg case 0x034C: 462fc5a983dSmrg case 0x0160: 463fc5a983dSmrg case 0x0166: 464fc5a983dSmrg case 0x0169: 465fc5a983dSmrg case 0x016B: 466fc5a983dSmrg case 0x016C: 467fc5a983dSmrg case 0x016D: 468fc5a983dSmrg case 0x00C8: 469fc5a983dSmrg case 0x00CC: 470fc5a983dSmrg case 0x0144: 471fc5a983dSmrg case 0x0146: 472fc5a983dSmrg case 0x0148: 473fc5a983dSmrg case 0x0098: 474fc5a983dSmrg case 0x0099: 475fc5a983dSmrg mobile = TRUE; 476fc5a983dSmrg break; 477fc5a983dSmrg default: 478fc5a983dSmrg break; 479fc5a983dSmrg } 480fc5a983dSmrg 481fc5a983dSmrg if(pNv->Architecture == NV_ARCH_04) 482fc5a983dSmrg nv4GetConfig(pNv); 483fc5a983dSmrg else 484fc5a983dSmrg nv10GetConfig(pNv); 485fc5a983dSmrg 486fc5a983dSmrg NVSelectHeadRegisters(pScrn, 0); 487fc5a983dSmrg 488fc5a983dSmrg NVLockUnlock(pNv, 0); 489fc5a983dSmrg 490fc5a983dSmrg NVI2CInit(pScrn); 491fc5a983dSmrg 492fc5a983dSmrg pNv->Television = FALSE; 493fc5a983dSmrg 4946257f37dSmrg vgaHWGetIOBase(pVga); 4956257f37dSmrg 496fc5a983dSmrg if(!pNv->twoHeads) { 497fc5a983dSmrg pNv->CRTCnumber = 0; 498fc5a983dSmrg if((monitorA = NVProbeDDC(pScrn, 0))) { 499fc5a983dSmrg FlatPanel = monitorA->features.input_type ? 1 : 0; 500fc5a983dSmrg 501fc5a983dSmrg /* NV4 doesn't support FlatPanels */ 502fc5a983dSmrg if((pNv->Chipset & 0x0fff) <= 0x0020) 503fc5a983dSmrg FlatPanel = 0; 504fc5a983dSmrg } else { 505fc5a983dSmrg VGA_WR08(pNv->PCIO, 0x03D4, 0x28); 506fc5a983dSmrg if(VGA_RD08(pNv->PCIO, 0x03D5) & 0x80) { 507fc5a983dSmrg VGA_WR08(pNv->PCIO, 0x03D4, 0x33); 508fc5a983dSmrg if(!(VGA_RD08(pNv->PCIO, 0x03D5) & 0x01)) 509fc5a983dSmrg Television = TRUE; 510fc5a983dSmrg FlatPanel = 1; 511fc5a983dSmrg } else { 512fc5a983dSmrg FlatPanel = 0; 513fc5a983dSmrg } 514fc5a983dSmrg xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 515fc5a983dSmrg "HW is currently programmed for %s\n", 516fc5a983dSmrg FlatPanel ? (Television ? "TV" : "DFP") : "CRT"); 517fc5a983dSmrg } 518fc5a983dSmrg 519fc5a983dSmrg if(pNv->FlatPanel == -1) { 520fc5a983dSmrg pNv->FlatPanel = FlatPanel; 521fc5a983dSmrg pNv->Television = Television; 522fc5a983dSmrg } else { 523fc5a983dSmrg xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, 524fc5a983dSmrg "Forcing display type to %s as specified\n", 525fc5a983dSmrg pNv->FlatPanel ? "DFP" : "CRT"); 526fc5a983dSmrg } 527fc5a983dSmrg } else { 528fc5a983dSmrg CARD8 outputAfromCRTC, outputBfromCRTC; 529fc5a983dSmrg int CRTCnumber = -1; 530fc5a983dSmrg CARD8 slaved_on_A, slaved_on_B; 531fc5a983dSmrg Bool analog_on_A, analog_on_B; 532fc5a983dSmrg CARD32 oldhead; 533fc5a983dSmrg CARD8 cr44; 534fc5a983dSmrg 535fc5a983dSmrg if(implementation != 0x0110) { 536fc5a983dSmrg if(pNv->PRAMDAC0[0x0000052C/4] & 0x100) 537fc5a983dSmrg outputAfromCRTC = 1; 538fc5a983dSmrg else 539fc5a983dSmrg outputAfromCRTC = 0; 540fc5a983dSmrg if(pNv->PRAMDAC0[0x0000252C/4] & 0x100) 541fc5a983dSmrg outputBfromCRTC = 1; 542fc5a983dSmrg else 543fc5a983dSmrg outputBfromCRTC = 0; 544fc5a983dSmrg analog_on_A = NVIsConnected(pScrn, 0); 545fc5a983dSmrg analog_on_B = NVIsConnected(pScrn, 1); 546fc5a983dSmrg } else { 547fc5a983dSmrg outputAfromCRTC = 0; 548fc5a983dSmrg outputBfromCRTC = 1; 549fc5a983dSmrg analog_on_A = FALSE; 550fc5a983dSmrg analog_on_B = FALSE; 551fc5a983dSmrg } 552fc5a983dSmrg 553fc5a983dSmrg VGA_WR08(pNv->PCIO, 0x03D4, 0x44); 554fc5a983dSmrg cr44 = VGA_RD08(pNv->PCIO, 0x03D5); 555fc5a983dSmrg 556fc5a983dSmrg VGA_WR08(pNv->PCIO, 0x03D5, 3); 557fc5a983dSmrg NVSelectHeadRegisters(pScrn, 1); 558fc5a983dSmrg NVLockUnlock(pNv, 0); 559fc5a983dSmrg 560fc5a983dSmrg VGA_WR08(pNv->PCIO, 0x03D4, 0x28); 561fc5a983dSmrg slaved_on_B = VGA_RD08(pNv->PCIO, 0x03D5) & 0x80; 562fc5a983dSmrg if(slaved_on_B) { 563fc5a983dSmrg VGA_WR08(pNv->PCIO, 0x03D4, 0x33); 564fc5a983dSmrg tvB = !(VGA_RD08(pNv->PCIO, 0x03D5) & 0x01); 565fc5a983dSmrg } 566fc5a983dSmrg 567fc5a983dSmrg VGA_WR08(pNv->PCIO, 0x03D4, 0x44); 568fc5a983dSmrg VGA_WR08(pNv->PCIO, 0x03D5, 0); 569fc5a983dSmrg NVSelectHeadRegisters(pScrn, 0); 570fc5a983dSmrg NVLockUnlock(pNv, 0); 571fc5a983dSmrg 572fc5a983dSmrg VGA_WR08(pNv->PCIO, 0x03D4, 0x28); 573fc5a983dSmrg slaved_on_A = VGA_RD08(pNv->PCIO, 0x03D5) & 0x80; 574fc5a983dSmrg if(slaved_on_A) { 575fc5a983dSmrg VGA_WR08(pNv->PCIO, 0x03D4, 0x33); 576fc5a983dSmrg tvA = !(VGA_RD08(pNv->PCIO, 0x03D5) & 0x01); 577fc5a983dSmrg } 578fc5a983dSmrg 579fc5a983dSmrg oldhead = pNv->PCRTC0[0x00000860/4]; 580fc5a983dSmrg pNv->PCRTC0[0x00000860/4] = oldhead | 0x00000010; 581fc5a983dSmrg 582fc5a983dSmrg monitorA = NVProbeDDC(pScrn, 0); 583fc5a983dSmrg monitorB = NVProbeDDC(pScrn, 1); 584fc5a983dSmrg 585fc5a983dSmrg if(slaved_on_A && !tvA) { 586fc5a983dSmrg CRTCnumber = 0; 587fc5a983dSmrg FlatPanel = 1; 588fc5a983dSmrg xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 589fc5a983dSmrg "CRTC 0 is currently programmed for DFP\n"); 590fc5a983dSmrg } else 591fc5a983dSmrg if(slaved_on_B && !tvB) { 592fc5a983dSmrg CRTCnumber = 1; 593fc5a983dSmrg FlatPanel = 1; 594fc5a983dSmrg xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 595fc5a983dSmrg "CRTC 1 is currently programmed for DFP\n"); 596fc5a983dSmrg } else 597fc5a983dSmrg if(analog_on_A) { 598fc5a983dSmrg CRTCnumber = outputAfromCRTC; 599fc5a983dSmrg FlatPanel = 0; 600fc5a983dSmrg xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 601fc5a983dSmrg "CRTC %i appears to have a CRT attached\n", CRTCnumber); 602fc5a983dSmrg } else 603fc5a983dSmrg if(analog_on_B) { 604fc5a983dSmrg CRTCnumber = outputBfromCRTC; 605fc5a983dSmrg FlatPanel = 0; 606fc5a983dSmrg xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 607fc5a983dSmrg "CRTC %i appears to have a CRT attached\n", CRTCnumber); 608fc5a983dSmrg } else 609fc5a983dSmrg if(slaved_on_A) { 610fc5a983dSmrg CRTCnumber = 0; 611fc5a983dSmrg FlatPanel = 1; 612fc5a983dSmrg Television = 1; 613fc5a983dSmrg xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 614fc5a983dSmrg "CRTC 0 is currently programmed for TV\n"); 615fc5a983dSmrg } else 616fc5a983dSmrg if(slaved_on_B) { 617fc5a983dSmrg CRTCnumber = 1; 618fc5a983dSmrg FlatPanel = 1; 619fc5a983dSmrg Television = 1; 620fc5a983dSmrg xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 621fc5a983dSmrg "CRTC 1 is currently programmed for TV\n"); 622fc5a983dSmrg } else 623fc5a983dSmrg if(monitorA) { 624fc5a983dSmrg FlatPanel = monitorA->features.input_type ? 1 : 0; 625fc5a983dSmrg } else 626fc5a983dSmrg if(monitorB) { 627fc5a983dSmrg FlatPanel = monitorB->features.input_type ? 1 : 0; 628fc5a983dSmrg } 629fc5a983dSmrg 630fc5a983dSmrg if(pNv->FlatPanel == -1) { 631fc5a983dSmrg if(FlatPanel != -1) { 632fc5a983dSmrg pNv->FlatPanel = FlatPanel; 633fc5a983dSmrg pNv->Television = Television; 634fc5a983dSmrg } else { 635fc5a983dSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 636fc5a983dSmrg "Unable to detect display type...\n"); 637fc5a983dSmrg if(mobile) { 638fc5a983dSmrg xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, 639fc5a983dSmrg "...On a laptop, assuming DFP\n"); 640fc5a983dSmrg pNv->FlatPanel = 1; 641fc5a983dSmrg } else { 642fc5a983dSmrg xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, 643fc5a983dSmrg "...Using default of CRT\n"); 644fc5a983dSmrg pNv->FlatPanel = 0; 645fc5a983dSmrg } 646fc5a983dSmrg } 647fc5a983dSmrg } else { 648fc5a983dSmrg xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, 649fc5a983dSmrg "Forcing display type to %s as specified\n", 650fc5a983dSmrg pNv->FlatPanel ? "DFP" : "CRT"); 651fc5a983dSmrg } 652fc5a983dSmrg 653fc5a983dSmrg if(pNv->CRTCnumber == -1) { 654fc5a983dSmrg if(CRTCnumber != -1) pNv->CRTCnumber = CRTCnumber; 655fc5a983dSmrg else { 656fc5a983dSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 657fc5a983dSmrg "Unable to detect which CRTCNumber...\n"); 658fc5a983dSmrg if(pNv->FlatPanel) pNv->CRTCnumber = 1; 659fc5a983dSmrg else pNv->CRTCnumber = 0; 660fc5a983dSmrg xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, 661fc5a983dSmrg "...Defaulting to CRTCNumber %i\n", pNv->CRTCnumber); 662fc5a983dSmrg } 663fc5a983dSmrg } else { 664fc5a983dSmrg xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, 665fc5a983dSmrg "Forcing CRTCNumber %i as specified\n", pNv->CRTCnumber); 666fc5a983dSmrg } 667fc5a983dSmrg 668fc5a983dSmrg if(monitorA) { 669fc5a983dSmrg if((monitorA->features.input_type && pNv->FlatPanel) || 670fc5a983dSmrg (!monitorA->features.input_type && !pNv->FlatPanel)) 671fc5a983dSmrg { 672fc5a983dSmrg if(monitorB) { 6736086d97eSmrg free(monitorB); 674fc5a983dSmrg monitorB = NULL; 675fc5a983dSmrg } 676fc5a983dSmrg } else { 6776086d97eSmrg free(monitorA); 678fc5a983dSmrg monitorA = NULL; 679fc5a983dSmrg } 680fc5a983dSmrg } 681fc5a983dSmrg 682fc5a983dSmrg if(monitorB) { 683fc5a983dSmrg if((monitorB->features.input_type && !pNv->FlatPanel) || 684fc5a983dSmrg (!monitorB->features.input_type && pNv->FlatPanel)) 685fc5a983dSmrg { 6866086d97eSmrg free(monitorB); 687fc5a983dSmrg } else { 688fc5a983dSmrg monitorA = monitorB; 689fc5a983dSmrg } 690fc5a983dSmrg monitorB = NULL; 691fc5a983dSmrg } 692fc5a983dSmrg 693fc5a983dSmrg if(implementation == 0x0110) 694fc5a983dSmrg cr44 = pNv->CRTCnumber * 0x3; 695fc5a983dSmrg 696fc5a983dSmrg pNv->PCRTC0[0x00000860/4] = oldhead; 697fc5a983dSmrg 698fc5a983dSmrg VGA_WR08(pNv->PCIO, 0x03D4, 0x44); 699fc5a983dSmrg VGA_WR08(pNv->PCIO, 0x03D5, cr44); 700fc5a983dSmrg NVSelectHeadRegisters(pScrn, pNv->CRTCnumber); 701fc5a983dSmrg } 702fc5a983dSmrg 703fc5a983dSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 704fc5a983dSmrg "Using %s on CRTC %i\n", 705fc5a983dSmrg pNv->FlatPanel ? (pNv->Television ? "TV" : "DFP") : "CRT", 706fc5a983dSmrg pNv->CRTCnumber); 707fc5a983dSmrg 708fc5a983dSmrg if(pNv->FlatPanel && !pNv->Television) { 709fc5a983dSmrg pNv->fpWidth = pNv->PRAMDAC[0x0820/4] + 1; 710fc5a983dSmrg pNv->fpHeight = pNv->PRAMDAC[0x0800/4] + 1; 711fc5a983dSmrg pNv->fpVTotal = pNv->PRAMDAC[0x804/4] + 1; 712fc5a983dSmrg pNv->fpSyncs = pNv->PRAMDAC[0x0848/4] & 0x30000033; 713fc5a983dSmrg xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Panel size is %i x %i\n", 714fc5a983dSmrg pNv->fpWidth, pNv->fpHeight); 715fc5a983dSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NOTE: This driver cannot " 716fc5a983dSmrg "reconfigure the BIOS-programmed size.\n"); 717fc5a983dSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, "These dimensions will be used as " 718fc5a983dSmrg "the panel size for mode validation.\n"); 719fc5a983dSmrg } 720fc5a983dSmrg 721fc5a983dSmrg if(monitorA) 722fc5a983dSmrg xf86SetDDCproperties(pScrn, monitorA); 723fc5a983dSmrg 724fc5a983dSmrg if(!pNv->FlatPanel || (pScrn->depth != 24) || !pNv->twoHeads) 725fc5a983dSmrg pNv->FPDither = FALSE; 726fc5a983dSmrg 727fc5a983dSmrg pNv->LVDS = FALSE; 728fc5a983dSmrg if(pNv->FlatPanel && pNv->twoHeads) { 729fc5a983dSmrg pNv->PRAMDAC0[0x08B0/4] = 0x00010004; 730fc5a983dSmrg if(pNv->PRAMDAC0[0x08B4/4] & 1) 731fc5a983dSmrg pNv->LVDS = TRUE; 732fc5a983dSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Panel is %s\n", 733fc5a983dSmrg pNv->LVDS ? "LVDS" : "TMDS"); 734fc5a983dSmrg } 735fc5a983dSmrg} 736