1fc5a983dSmrg/* 2fc5a983dSmrg * Copyright (c) 2007-2008 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 25fc5a983dSmrg#ifdef HAVE_CONFIG_H 26fc5a983dSmrg#include "config.h" 27fc5a983dSmrg#endif 28fc5a983dSmrg 29fc5a983dSmrg#include <strings.h> 30fc5a983dSmrg 31fc5a983dSmrg#include "g80_type.h" 32fc5a983dSmrg#include "g80_display.h" 33fc5a983dSmrg#include "g80_output.h" 34fc5a983dSmrg 35fc5a983dSmrgstatic unsigned G80FindLoadVal(const unsigned char *table1) 36fc5a983dSmrg{ 37fc5a983dSmrg const unsigned char *p = table1; 38fc5a983dSmrg int count; 39fc5a983dSmrg const CARD32 def = 340; 40fc5a983dSmrg 41fc5a983dSmrg for(p = table1; *(CARD16*)p != 0xb8ff && p < table1 + 64000; p += 2); 42fc5a983dSmrg if(p == table1 + 64000) 43fc5a983dSmrg return def; 44fc5a983dSmrg p += 2; 45fc5a983dSmrg if(*(CARD32*)p != 0x544942) 46fc5a983dSmrg return def; 47fc5a983dSmrg p += 4; 48fc5a983dSmrg if(*(CARD16*)p != 0x100) 49fc5a983dSmrg return def; 50fc5a983dSmrg p += 2; 51fc5a983dSmrg if(*p != 12) 52fc5a983dSmrg return def; 53fc5a983dSmrg p++; 54fc5a983dSmrg if(*p != 6) 55fc5a983dSmrg return def; 56fc5a983dSmrg p++; 57fc5a983dSmrg count = *p; 58fc5a983dSmrg p += 2; 59fc5a983dSmrg for(; *p != 'A' && count >= 0; count--, p += 6); 60fc5a983dSmrg if(count == -1) 61fc5a983dSmrg return def; 62fc5a983dSmrg p += 4; 63fc5a983dSmrg p = table1 + *(CARD16*)p; 64fc5a983dSmrg p = table1 + *(CARD16*)p; 65fc5a983dSmrg if(p[0] != 0x10 || p[1] != 4 || p[2] != 4 || p[3] != 2) 66fc5a983dSmrg return def; 67fc5a983dSmrg return *(CARD32*)(p + 4) & 0x3ff; 68fc5a983dSmrg} 69fc5a983dSmrg 70fc5a983dSmrgstatic Bool G80ReadPortMapping(int scrnIndex, G80Ptr pNv) 71fc5a983dSmrg{ 72fc5a983dSmrg unsigned char *table2, *table3; 73fc5a983dSmrg unsigned char headerSize, entries, table3Entries, table3EntSize; 74fc5a983dSmrg int i; 75fc5a983dSmrg CARD16 a; 76fc5a983dSmrg CARD32 b; 77fc5a983dSmrg 78fc5a983dSmrg /* Clear the i2c map to invalid */ 79fc5a983dSmrg for(i = 0; i < G80_NUM_I2C_PORTS; i++) 80fc5a983dSmrg pNv->i2cMap[i].dac = pNv->i2cMap[i].sor = -1; 81fc5a983dSmrg 82fc5a983dSmrg if(*(CARD16*)pNv->table1 != 0xaa55) goto fail; 83fc5a983dSmrg 84fc5a983dSmrg a = *(CARD16*)(pNv->table1 + 0x36); 85fc5a983dSmrg table2 = (unsigned char*)pNv->table1 + a; 86fc5a983dSmrg 87fc5a983dSmrg if(table2[0] != 0x40) goto fail; 88fc5a983dSmrg 89fc5a983dSmrg b = *(CARD32*)(table2 + 6); 90fc5a983dSmrg if(b != 0x4edcbdcb) goto fail; 91fc5a983dSmrg 92fc5a983dSmrg table3 = (unsigned char*)pNv->table1 + *(CARD16*)(table2 + 4); 93fc5a983dSmrg table3Entries = table3[2]; 94fc5a983dSmrg table3EntSize = table3[3]; 95fc5a983dSmrg table3 += table3[1]; 96fc5a983dSmrg 97fc5a983dSmrg headerSize = table2[1]; 98fc5a983dSmrg entries = table2[2]; 99fc5a983dSmrg 100fc5a983dSmrg for(i = 0; i < entries; i++) { 101fc5a983dSmrg int type, port, portType; 102fc5a983dSmrg ORNum or; 103fc5a983dSmrg 104fc5a983dSmrg b = *(CARD32*)&table2[headerSize + 8*i]; 105fc5a983dSmrg type = b & 0xf; 106fc5a983dSmrg port = (b >> 4) & 0xf; 107fc5a983dSmrg or = ffs((b >> 24) & 0xf) - 1; 108fc5a983dSmrg 10971ba42d0Smrg if(b & 0x300000) { 110fc5a983dSmrg /* Can't handle this type of output yet */ 11171ba42d0Smrg xf86DrvMsg(scrnIndex, X_INFO, 11271ba42d0Smrg "Ignoring unsupported external output type %d at output " 11371ba42d0Smrg "%d\n", type, or); 114fc5a983dSmrg continue; 11571ba42d0Smrg } 116fc5a983dSmrg 117fc5a983dSmrg if(type == 0xe) break; 118fc5a983dSmrg 119fc5a983dSmrg switch(type) { 120fc5a983dSmrg case 0: /* CRT */ 121fc5a983dSmrg if(port >= table3Entries) { 122fc5a983dSmrg xf86DrvMsg(scrnIndex, X_WARNING, 123fc5a983dSmrg "VGA%d: invalid port %d\n", or, port); 124fc5a983dSmrg break; 125fc5a983dSmrg } 126fc5a983dSmrg b = *(CARD32*)&table3[table3EntSize * port]; 127fc5a983dSmrg port = b & 0xff; 128fc5a983dSmrg portType = b >> 24; 129fc5a983dSmrg if(portType != 5) { 130fc5a983dSmrg xf86DrvMsg(scrnIndex, X_WARNING, 131fc5a983dSmrg "VGA%d: invalid port type %d\n", or, portType); 132fc5a983dSmrg break; 133fc5a983dSmrg } 134bd2f6fc9Smrg if(port >= G80_NUM_I2C_PORTS) { 135bd2f6fc9Smrg xf86DrvMsg(scrnIndex, X_WARNING, 136bd2f6fc9Smrg "VGA%d: unrecognized port %d\n", or, port); 137bd2f6fc9Smrg break; 138bd2f6fc9Smrg } 1392eed41b2Sapb if(pNv->i2cMap[port].dac != (ORNum)-1) { 140fc5a983dSmrg xf86DrvMsg(scrnIndex, X_WARNING, 141fc5a983dSmrg "DDC routing table corrupt! DAC %i -> %i for " 142fc5a983dSmrg "port %i\n", or, pNv->i2cMap[port].dac, port); 143fc5a983dSmrg } 144fc5a983dSmrg pNv->i2cMap[port].dac = or; 145fc5a983dSmrg break; 146fc5a983dSmrg case 1: /* TV */ 14771ba42d0Smrg xf86DrvMsg(scrnIndex, X_INFO, 14871ba42d0Smrg "Ignoring unsupported TV output %d\n", or); 149fc5a983dSmrg break; 150fc5a983dSmrg 151fc5a983dSmrg case 2: /* TMDS */ 152fc5a983dSmrg if(port >= table3Entries) { 153fc5a983dSmrg xf86DrvMsg(scrnIndex, X_WARNING, 154fc5a983dSmrg "DVI%d: invalid port %d\n", or, port); 155fc5a983dSmrg break; 156fc5a983dSmrg } 157fc5a983dSmrg b = *(CARD32*)&table3[table3EntSize * port]; 158fc5a983dSmrg port = b & 0xff; 159fc5a983dSmrg portType = b >> 24; 160fc5a983dSmrg if(portType != 5) { 161fc5a983dSmrg xf86DrvMsg(scrnIndex, X_WARNING, 162fc5a983dSmrg "DVI%d: invalid port type %d\n", or, portType); 163fc5a983dSmrg break; 164fc5a983dSmrg } 165bd2f6fc9Smrg if(port >= G80_NUM_I2C_PORTS) { 166bd2f6fc9Smrg xf86DrvMsg(scrnIndex, X_WARNING, 167bd2f6fc9Smrg "DVI%d: unrecognized port %d\n", or, port); 168bd2f6fc9Smrg break; 169bd2f6fc9Smrg } 1702eed41b2Sapb if(pNv->i2cMap[port].sor != (ORNum)-1) 171fc5a983dSmrg xf86DrvMsg(scrnIndex, X_WARNING, 172fc5a983dSmrg "DDC routing table corrupt! SOR %i -> %i for " 173fc5a983dSmrg "port %i\n", or, pNv->i2cMap[port].sor, port); 174fc5a983dSmrg pNv->i2cMap[port].sor = or; 175fc5a983dSmrg break; 176fc5a983dSmrg 177fc5a983dSmrg case 3: /* LVDS */ 178fc5a983dSmrg pNv->lvds.present = TRUE; 179fc5a983dSmrg pNv->lvds.or = or; 180fc5a983dSmrg pNv->lvds.i2cPort = -1; 181fc5a983dSmrg 182fc5a983dSmrg if(port == 15) { 183fc5a983dSmrg xf86DrvMsg(scrnIndex, X_INFO, "LVDS has no I2C port\n"); 184fc5a983dSmrg break; 185fc5a983dSmrg } 186fc5a983dSmrg if(port >= table3Entries) { 187fc5a983dSmrg xf86DrvMsg(scrnIndex, X_WARNING, 188fc5a983dSmrg "LVDS: invalid port %d\n", port); 189fc5a983dSmrg break; 190fc5a983dSmrg } 191fc5a983dSmrg b = *(CARD32*)&table3[table3EntSize * port]; 192fc5a983dSmrg port = b & 0xff; 193fc5a983dSmrg portType = b >> 24; 194fc5a983dSmrg if(portType != 5) { 195fc5a983dSmrg xf86DrvMsg(scrnIndex, X_WARNING, 196fc5a983dSmrg "LVDS: invalid port type %d\n", portType); 197fc5a983dSmrg break; 198fc5a983dSmrg } 199bd2f6fc9Smrg if(port >= G80_NUM_I2C_PORTS) { 200bd2f6fc9Smrg xf86DrvMsg(scrnIndex, X_WARNING, 201bd2f6fc9Smrg "LVDS: unrecognized port %d\n", port); 202bd2f6fc9Smrg break; 203bd2f6fc9Smrg } 204fc5a983dSmrg pNv->lvds.i2cPort = port; 205fc5a983dSmrg 206fc5a983dSmrg break; 207fc5a983dSmrg 20871ba42d0Smrg case 6: /* DisplayPort */ 20971ba42d0Smrg xf86DrvMsg(scrnIndex, X_INFO, 21071ba42d0Smrg "Ignoring unsupported DisplayPort output %d\n", or); 21171ba42d0Smrg break; 21271ba42d0Smrg 213fc5a983dSmrg default: 21471ba42d0Smrg xf86DrvMsg(scrnIndex, X_INFO, 21571ba42d0Smrg "Ignoring unsupported output type %d at port %d\n", 21671ba42d0Smrg type, or); 217fc5a983dSmrg break; 218fc5a983dSmrg } 219fc5a983dSmrg } 220fc5a983dSmrg 221fc5a983dSmrg xf86DrvMsg(scrnIndex, X_PROBED, "Connector map:\n"); 222f3561b8bSmrg if(pNv->lvds.present) { 223f3561b8bSmrg if (pNv->lvds.i2cPort != -1) 224f3561b8bSmrg xf86DrvMsg(scrnIndex, X_PROBED, " Bus %i -> SOR%i (LVDS)\n", pNv->lvds.i2cPort, pNv->lvds.or); 225f3561b8bSmrg else 226f3561b8bSmrg xf86DrvMsg(scrnIndex, X_PROBED, " [N/A] -> SOR%i (LVDS)\n", pNv->lvds.or); 227f3561b8bSmrg } 228fc5a983dSmrg for(i = 0; i < G80_NUM_I2C_PORTS; i++) { 2292eed41b2Sapb if(pNv->i2cMap[i].dac != (ORNum)-1) 230fc5a983dSmrg xf86DrvMsg(scrnIndex, X_PROBED, " Bus %i -> DAC%i\n", i, pNv->i2cMap[i].dac); 2312eed41b2Sapb if(pNv->i2cMap[i].sor != (ORNum)-1) 232fc5a983dSmrg xf86DrvMsg(scrnIndex, X_PROBED, " Bus %i -> SOR%i\n", i, pNv->i2cMap[i].sor); 233fc5a983dSmrg } 234fc5a983dSmrg 235fc5a983dSmrg pNv->loadVal = G80FindLoadVal(pNv->table1); 236fc5a983dSmrg xf86DrvMsg(scrnIndex, X_PROBED, "Load detection: %d\n", pNv->loadVal); 237fc5a983dSmrg 238fc5a983dSmrg return TRUE; 239fc5a983dSmrg 240fc5a983dSmrgfail: 241fc5a983dSmrg xf86DrvMsg(scrnIndex, X_ERROR, "Couldn't find the DDC routing table. " 242fc5a983dSmrg "Mode setting will probably fail!\n"); 243fc5a983dSmrg return FALSE; 244fc5a983dSmrg} 245fc5a983dSmrg 246fc5a983dSmrgstatic CARD32 i2cAddr(const int port) 247fc5a983dSmrg{ 248bd2f6fc9Smrg const CARD32 addrs[G80_NUM_I2C_PORTS] = { 249bd2f6fc9Smrg 0xE138, 0xE150, 0xE168, 0xE180, 0xE254, 0xE274, 0xE764, 0xE780, 0xE79C, 250bd2f6fc9Smrg 0xE7B8 251bd2f6fc9Smrg }; 252bd2f6fc9Smrg return addrs[port]; 253fc5a983dSmrg} 254fc5a983dSmrg 255fc5a983dSmrgstatic void G80_I2CPutBits(I2CBusPtr b, int clock, int data) 256fc5a983dSmrg{ 25784354367Smrg#ifdef XF86_SCRN_INTERFACE 25884354367Smrg G80Ptr pNv = G80PTR(b->pScrn); 25984354367Smrg#else 260fc5a983dSmrg G80Ptr pNv = G80PTR(xf86Screens[b->scrnIndex]); 26184354367Smrg#endif 262fc5a983dSmrg pNv->reg[i2cAddr(b->DriverPrivate.val)/4] = 4 | clock | data << 1; 263fc5a983dSmrg} 264fc5a983dSmrg 265fc5a983dSmrgstatic void G80_I2CGetBits(I2CBusPtr b, int *clock, int *data) 266fc5a983dSmrg{ 26784354367Smrg#ifdef XF86_SCRN_INTERFACE 26884354367Smrg G80Ptr pNv = G80PTR(b->pScrn); 26984354367Smrg#else 270fc5a983dSmrg G80Ptr pNv = G80PTR(xf86Screens[b->scrnIndex]); 27184354367Smrg#endif 272fc5a983dSmrg unsigned char val; 273fc5a983dSmrg 274fc5a983dSmrg val = pNv->reg[i2cAddr(b->DriverPrivate.val)/4]; 275fc5a983dSmrg *clock = !!(val & 1); 276fc5a983dSmrg *data = !!(val & 2); 277fc5a983dSmrg} 278fc5a983dSmrg 279fc5a983dSmrgstatic I2CBusPtr 280fc5a983dSmrgG80I2CInit(ScrnInfoPtr pScrn, const char *name, const int port) 281fc5a983dSmrg{ 282fc5a983dSmrg I2CBusPtr i2c; 283fc5a983dSmrg 284fc5a983dSmrg /* Allocate the I2C bus structure */ 285fc5a983dSmrg i2c = xf86CreateI2CBusRec(); 286fc5a983dSmrg if(!i2c) return NULL; 287fc5a983dSmrg 288fc5a983dSmrg i2c->BusName = strdup(name); 289fc5a983dSmrg i2c->scrnIndex = pScrn->scrnIndex; 29084354367Smrg#ifdef XF86_SCRN_INTERFACE 29184354367Smrg i2c->pScrn = pScrn; 29284354367Smrg#endif 293fc5a983dSmrg i2c->I2CPutBits = G80_I2CPutBits; 294fc5a983dSmrg i2c->I2CGetBits = G80_I2CGetBits; 295fc5a983dSmrg i2c->ByteTimeout = 2200; /* VESA DDC spec 3 p. 43 (+10 %) */ 296fc5a983dSmrg i2c->StartTimeout = 550; 297fc5a983dSmrg i2c->BitTimeout = 40; 298fc5a983dSmrg i2c->ByteTimeout = 40; 299fc5a983dSmrg i2c->AcknTimeout = 40; 300fc5a983dSmrg i2c->DriverPrivate.val = port; 301fc5a983dSmrg 302fc5a983dSmrg if(xf86I2CBusInit(i2c)) { 303fc5a983dSmrg return i2c; 304fc5a983dSmrg } else { 3056086d97eSmrg free(i2c); 306fc5a983dSmrg return NULL; 307fc5a983dSmrg } 308fc5a983dSmrg} 309fc5a983dSmrg 310fc5a983dSmrgvoid 311fc5a983dSmrgG80OutputSetPClk(xf86OutputPtr output, int pclk) 312fc5a983dSmrg{ 313fc5a983dSmrg G80OutputPrivPtr pPriv = output->driver_private; 314fc5a983dSmrg if(pPriv->set_pclk) 315fc5a983dSmrg pPriv->set_pclk(output, pclk); 316fc5a983dSmrg} 317fc5a983dSmrg 318fc5a983dSmrgint 319fc5a983dSmrgG80OutputModeValid(xf86OutputPtr output, DisplayModePtr mode) 320fc5a983dSmrg{ 321fc5a983dSmrg if(mode->Clock > 400000) 322fc5a983dSmrg return MODE_CLOCK_HIGH; 323fc5a983dSmrg if(mode->Clock < 25000) 324fc5a983dSmrg return MODE_CLOCK_LOW; 325fc5a983dSmrg 326fc5a983dSmrg return MODE_OK; 327fc5a983dSmrg} 328fc5a983dSmrg 329fc5a983dSmrgvoid 330fc5a983dSmrgG80OutputPrepare(xf86OutputPtr output) 331fc5a983dSmrg{ 332fc5a983dSmrg} 333fc5a983dSmrg 334fc5a983dSmrgvoid 335fc5a983dSmrgG80OutputCommit(xf86OutputPtr output) 336fc5a983dSmrg{ 337fc5a983dSmrg} 338fc5a983dSmrg 339fc5a983dSmrgstatic xf86MonPtr 340fc5a983dSmrgProbeDDC(I2CBusPtr i2c) 341fc5a983dSmrg{ 342fc5a983dSmrg ScrnInfoPtr pScrn = xf86Screens[i2c->scrnIndex]; 343fc5a983dSmrg G80Ptr pNv = G80PTR(pScrn); 344fc5a983dSmrg xf86MonPtr monInfo = NULL; 345fc5a983dSmrg const int bus = i2c->DriverPrivate.val; 346fc5a983dSmrg const CARD32 addr = i2cAddr(bus); 347fc5a983dSmrg 348fc5a983dSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 349fc5a983dSmrg "Probing for EDID on I2C bus %i...\n", bus); 350fc5a983dSmrg pNv->reg[addr/4] = 7; 351fc5a983dSmrg /* Should probably use xf86OutputGetEDID here */ 352f3561b8bSmrg#ifdef EDID_COMPLETE_RAWDATA 35384354367Smrg monInfo = xf86DoEEDID(XF86_SCRN_ARG(pScrn), i2c, TRUE); 354f3561b8bSmrg#else 35584354367Smrg monInfo = xf86DoEDID_DDC2(XF86_SCRN_ARG(pScrn), i2c); 356f3561b8bSmrg#endif 357fc5a983dSmrg pNv->reg[addr/4] = 3; 358fc5a983dSmrg 359fc5a983dSmrg if(monInfo) { 360fc5a983dSmrg xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 361fc5a983dSmrg "DDC detected a %s:\n", monInfo->features.input_type ? 362fc5a983dSmrg "DFP" : "CRT"); 363fc5a983dSmrg xf86PrintEDID(monInfo); 364fc5a983dSmrg } else { 365fc5a983dSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, " ... none found\n"); 366fc5a983dSmrg } 367fc5a983dSmrg 368fc5a983dSmrg return monInfo; 369fc5a983dSmrg} 370fc5a983dSmrg 371fc5a983dSmrg/* 372fc5a983dSmrg * Read an EDID from the i2c port. Perform load detection on the DAC (if 373fc5a983dSmrg * present) to see if the display is connected via VGA. Sets the cached status 374fc5a983dSmrg * of both outputs. The status is marked dirty again in the BlockHandler. 375fc5a983dSmrg */ 376fc5a983dSmrgvoid G80OutputPartnersDetect(xf86OutputPtr dac, xf86OutputPtr sor, I2CBusPtr i2c) 377fc5a983dSmrg{ 378fc5a983dSmrg xf86MonPtr monInfo = ProbeDDC(i2c); 379fc5a983dSmrg xf86OutputPtr connected = NULL; 380fc5a983dSmrg Bool load = dac && G80DacLoadDetect(dac); 381fc5a983dSmrg 382fc5a983dSmrg if(dac) { 383fc5a983dSmrg G80OutputPrivPtr pPriv = dac->driver_private; 384fc5a983dSmrg 385fc5a983dSmrg if(load) { 386fc5a983dSmrg pPriv->cached_status = XF86OutputStatusConnected; 387fc5a983dSmrg connected = dac; 388fc5a983dSmrg } else { 389fc5a983dSmrg pPriv->cached_status = XF86OutputStatusDisconnected; 390fc5a983dSmrg } 391fc5a983dSmrg } 392fc5a983dSmrg 393fc5a983dSmrg if(sor) { 394fc5a983dSmrg G80OutputPrivPtr pPriv = sor->driver_private; 395fc5a983dSmrg 396fc5a983dSmrg if(monInfo && !load) { 397fc5a983dSmrg pPriv->cached_status = XF86OutputStatusConnected; 398fc5a983dSmrg connected = sor; 399fc5a983dSmrg } else { 400fc5a983dSmrg pPriv->cached_status = XF86OutputStatusDisconnected; 401fc5a983dSmrg } 402fc5a983dSmrg } 403fc5a983dSmrg 404fc5a983dSmrg if(connected) 405fc5a983dSmrg xf86OutputSetEDID(connected, monInfo); 406fc5a983dSmrg} 407fc5a983dSmrg 408fc5a983dSmrg/* 409fc5a983dSmrg * Reset the cached output status for all outputs. Called from G80BlockHandler. 410fc5a983dSmrg */ 411fc5a983dSmrgvoid 412fc5a983dSmrgG80OutputResetCachedStatus(ScrnInfoPtr pScrn) 413fc5a983dSmrg{ 414fc5a983dSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 415fc5a983dSmrg int i; 416fc5a983dSmrg 417fc5a983dSmrg for(i = 0; i < xf86_config->num_output; i++) { 418fc5a983dSmrg G80OutputPrivPtr pPriv = xf86_config->output[i]->driver_private; 419fc5a983dSmrg pPriv->cached_status = XF86OutputStatusUnknown; 420fc5a983dSmrg } 421fc5a983dSmrg} 422fc5a983dSmrg 423fc5a983dSmrgDisplayModePtr 424fc5a983dSmrgG80OutputGetDDCModes(xf86OutputPtr output) 425fc5a983dSmrg{ 426fc5a983dSmrg /* The EDID is read as part of the detect step */ 427fc5a983dSmrg output->funcs->detect(output); 428fc5a983dSmrg return xf86OutputGetEDIDModes(output); 429fc5a983dSmrg} 430fc5a983dSmrg 431fc5a983dSmrgvoid 432fc5a983dSmrgG80OutputDestroy(xf86OutputPtr output) 433fc5a983dSmrg{ 434fc5a983dSmrg G80OutputPrivPtr pPriv = output->driver_private; 435fc5a983dSmrg 436fc5a983dSmrg if(pPriv->partner) 437fc5a983dSmrg ((G80OutputPrivPtr)pPriv->partner->driver_private)->partner = NULL; 438fc5a983dSmrg else 439fc5a983dSmrg xf86DestroyI2CBusRec(pPriv->i2c, TRUE, TRUE); 440fc5a983dSmrg pPriv->i2c = NULL; 441fc5a983dSmrg} 442fc5a983dSmrg 443fc5a983dSmrgBool 444fc5a983dSmrgG80CreateOutputs(ScrnInfoPtr pScrn) 445fc5a983dSmrg{ 446fc5a983dSmrg G80Ptr pNv = G80PTR(pScrn); 447fc5a983dSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 448fc5a983dSmrg int i; 449fc5a983dSmrg 450fc5a983dSmrg if(!G80ReadPortMapping(pScrn->scrnIndex, pNv)) 451fc5a983dSmrg return FALSE; 452fc5a983dSmrg 453fc5a983dSmrg /* For each DDC port, create an output for the attached ORs */ 454fc5a983dSmrg for(i = 0; i < G80_NUM_I2C_PORTS; i++) { 455fc5a983dSmrg xf86OutputPtr dac = NULL, sor = NULL; 456fc5a983dSmrg I2CBusPtr i2c; 457fc5a983dSmrg char i2cName[16]; 458fc5a983dSmrg 4592eed41b2Sapb if(pNv->i2cMap[i].dac == (ORNum)-1 && pNv->i2cMap[i].sor == (ORNum)-1) 460fc5a983dSmrg /* No outputs on this port */ 461fc5a983dSmrg continue; 462fc5a983dSmrg 463fc5a983dSmrg snprintf(i2cName, sizeof(i2cName), "I2C%i", i); 464fc5a983dSmrg i2c = G80I2CInit(pScrn, i2cName, i); 465fc5a983dSmrg if(!i2c) { 466fc5a983dSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 467fc5a983dSmrg "Failed to initialize I2C for port %i.\n", 468fc5a983dSmrg i); 469fc5a983dSmrg continue; 470fc5a983dSmrg } 471fc5a983dSmrg 4722eed41b2Sapb if(pNv->i2cMap[i].dac != (ORNum)-1) 473fc5a983dSmrg dac = G80CreateDac(pScrn, pNv->i2cMap[i].dac); 4742eed41b2Sapb if(pNv->i2cMap[i].sor != (ORNum)-1) 475fc5a983dSmrg sor = G80CreateSor(pScrn, pNv->i2cMap[i].sor, TMDS); 476fc5a983dSmrg 477fc5a983dSmrg if(dac) { 478fc5a983dSmrg G80OutputPrivPtr pPriv = dac->driver_private; 479fc5a983dSmrg 480fc5a983dSmrg pPriv->partner = sor; 481fc5a983dSmrg pPriv->i2c = i2c; 482fc5a983dSmrg pPriv->scale = G80_SCALE_OFF; 483fc5a983dSmrg } 484fc5a983dSmrg if(sor) { 485fc5a983dSmrg G80OutputPrivPtr pPriv = sor->driver_private; 486fc5a983dSmrg 487fc5a983dSmrg pPriv->partner = dac; 488fc5a983dSmrg pPriv->i2c = i2c; 489fc5a983dSmrg pPriv->scale = G80_SCALE_ASPECT; 490fc5a983dSmrg } 491fc5a983dSmrg } 492fc5a983dSmrg 493fc5a983dSmrg if(pNv->lvds.present) { 494fc5a983dSmrg xf86OutputPtr lvds = G80CreateSor(pScrn, pNv->lvds.or, LVDS); 495fc5a983dSmrg 4966086d97eSmrg if (lvds) { 4976086d97eSmrg G80OutputPrivPtr pPriv = lvds->driver_private; 498fc5a983dSmrg 4996086d97eSmrg pPriv->scale = G80_SCALE_ASPECT; 5006086d97eSmrg 5016086d97eSmrg if(pNv->lvds.i2cPort != -1) { 5026086d97eSmrg char i2cName[16]; 503fc5a983dSmrg 5046086d97eSmrg snprintf(i2cName, sizeof(i2cName), "I2C%i (LVDS)", pNv->lvds.i2cPort); 5056086d97eSmrg pPriv->i2c = G80I2CInit(pScrn, i2cName, pNv->lvds.i2cPort); 5066086d97eSmrg if(!pPriv->i2c) { 5076086d97eSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 5086086d97eSmrg "Failed to initialize I2C for port %i (LVDS)!\n", 5096086d97eSmrg pNv->lvds.i2cPort); 5106086d97eSmrg } 511fc5a983dSmrg } 512fc5a983dSmrg } 513fc5a983dSmrg } 514fc5a983dSmrg 515fc5a983dSmrg /* For each output, set the crtc and clone masks */ 516fc5a983dSmrg for(i = 0; i < xf86_config->num_output; i++) { 517fc5a983dSmrg xf86OutputPtr output = xf86_config->output[i]; 518fc5a983dSmrg 519fc5a983dSmrg /* Any output can connect to any head */ 520fc5a983dSmrg output->possible_crtcs = 0x3; 521fc5a983dSmrg output->possible_clones = 0; 522fc5a983dSmrg } 523fc5a983dSmrg 524fc5a983dSmrg return TRUE; 525fc5a983dSmrg} 526