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