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