g80_output.c revision bd2f6fc9
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(port >= G80_NUM_I2C_PORTS) { 131 xf86DrvMsg(scrnIndex, X_WARNING, 132 "VGA%d: unrecognized port %d\n", or, port); 133 break; 134 } 135 if(pNv->i2cMap[port].dac != -1) { 136 xf86DrvMsg(scrnIndex, X_WARNING, 137 "DDC routing table corrupt! DAC %i -> %i for " 138 "port %i\n", or, pNv->i2cMap[port].dac, port); 139 } 140 pNv->i2cMap[port].dac = or; 141 break; 142 case 1: /* TV */ 143 /* Ignore TVs */ 144 break; 145 146 case 2: /* TMDS */ 147 if(port >= table3Entries) { 148 xf86DrvMsg(scrnIndex, X_WARNING, 149 "DVI%d: invalid port %d\n", or, port); 150 break; 151 } 152 b = *(CARD32*)&table3[table3EntSize * port]; 153 port = b & 0xff; 154 portType = b >> 24; 155 if(portType != 5) { 156 xf86DrvMsg(scrnIndex, X_WARNING, 157 "DVI%d: invalid port type %d\n", or, portType); 158 break; 159 } 160 if(port >= G80_NUM_I2C_PORTS) { 161 xf86DrvMsg(scrnIndex, X_WARNING, 162 "DVI%d: unrecognized port %d\n", or, port); 163 break; 164 } 165 if(pNv->i2cMap[port].sor != -1) 166 xf86DrvMsg(scrnIndex, X_WARNING, 167 "DDC routing table corrupt! SOR %i -> %i for " 168 "port %i\n", or, pNv->i2cMap[port].sor, port); 169 pNv->i2cMap[port].sor = or; 170 break; 171 172 case 3: /* LVDS */ 173 pNv->lvds.present = TRUE; 174 pNv->lvds.or = or; 175 pNv->lvds.i2cPort = -1; 176 177 if(port == 15) { 178 xf86DrvMsg(scrnIndex, X_INFO, "LVDS has no I2C port\n"); 179 break; 180 } 181 if(port >= table3Entries) { 182 xf86DrvMsg(scrnIndex, X_WARNING, 183 "LVDS: invalid port %d\n", port); 184 break; 185 } 186 b = *(CARD32*)&table3[table3EntSize * port]; 187 port = b & 0xff; 188 portType = b >> 24; 189 if(portType != 5) { 190 xf86DrvMsg(scrnIndex, X_WARNING, 191 "LVDS: invalid port type %d\n", portType); 192 break; 193 } 194 if(port >= G80_NUM_I2C_PORTS) { 195 xf86DrvMsg(scrnIndex, X_WARNING, 196 "LVDS: unrecognized port %d\n", port); 197 break; 198 } 199 pNv->lvds.i2cPort = port; 200 201 break; 202 203 default: 204 break; 205 } 206 } 207 208 xf86DrvMsg(scrnIndex, X_PROBED, "Connector map:\n"); 209 if(pNv->lvds.present) { 210 if (pNv->lvds.i2cPort != -1) 211 xf86DrvMsg(scrnIndex, X_PROBED, " Bus %i -> SOR%i (LVDS)\n", pNv->lvds.i2cPort, pNv->lvds.or); 212 else 213 xf86DrvMsg(scrnIndex, X_PROBED, " [N/A] -> SOR%i (LVDS)\n", pNv->lvds.or); 214 } 215 for(i = 0; i < G80_NUM_I2C_PORTS; i++) { 216 if(pNv->i2cMap[i].dac != -1) 217 xf86DrvMsg(scrnIndex, X_PROBED, " Bus %i -> DAC%i\n", i, pNv->i2cMap[i].dac); 218 if(pNv->i2cMap[i].sor != -1) 219 xf86DrvMsg(scrnIndex, X_PROBED, " Bus %i -> SOR%i\n", i, pNv->i2cMap[i].sor); 220 } 221 222 pNv->loadVal = G80FindLoadVal(pNv->table1); 223 xf86DrvMsg(scrnIndex, X_PROBED, "Load detection: %d\n", pNv->loadVal); 224 225 return TRUE; 226 227fail: 228 xf86DrvMsg(scrnIndex, X_ERROR, "Couldn't find the DDC routing table. " 229 "Mode setting will probably fail!\n"); 230 return FALSE; 231} 232 233static CARD32 i2cAddr(const int port) 234{ 235 const CARD32 addrs[G80_NUM_I2C_PORTS] = { 236 0xE138, 0xE150, 0xE168, 0xE180, 0xE254, 0xE274, 0xE764, 0xE780, 0xE79C, 237 0xE7B8 238 }; 239 return addrs[port]; 240} 241 242static void G80_I2CPutBits(I2CBusPtr b, int clock, int data) 243{ 244 G80Ptr pNv = G80PTR(xf86Screens[b->scrnIndex]); 245 pNv->reg[i2cAddr(b->DriverPrivate.val)/4] = 4 | clock | data << 1; 246} 247 248static void G80_I2CGetBits(I2CBusPtr b, int *clock, int *data) 249{ 250 G80Ptr pNv = G80PTR(xf86Screens[b->scrnIndex]); 251 unsigned char val; 252 253 val = pNv->reg[i2cAddr(b->DriverPrivate.val)/4]; 254 *clock = !!(val & 1); 255 *data = !!(val & 2); 256} 257 258static I2CBusPtr 259G80I2CInit(ScrnInfoPtr pScrn, const char *name, const int port) 260{ 261 I2CBusPtr i2c; 262 263 /* Allocate the I2C bus structure */ 264 i2c = xf86CreateI2CBusRec(); 265 if(!i2c) return NULL; 266 267 i2c->BusName = strdup(name); 268 i2c->scrnIndex = pScrn->scrnIndex; 269 i2c->I2CPutBits = G80_I2CPutBits; 270 i2c->I2CGetBits = G80_I2CGetBits; 271 i2c->ByteTimeout = 2200; /* VESA DDC spec 3 p. 43 (+10 %) */ 272 i2c->StartTimeout = 550; 273 i2c->BitTimeout = 40; 274 i2c->ByteTimeout = 40; 275 i2c->AcknTimeout = 40; 276 i2c->DriverPrivate.val = port; 277 278 if(xf86I2CBusInit(i2c)) { 279 return i2c; 280 } else { 281 xfree(i2c); 282 return NULL; 283 } 284} 285 286void 287G80OutputSetPClk(xf86OutputPtr output, int pclk) 288{ 289 G80OutputPrivPtr pPriv = output->driver_private; 290 if(pPriv->set_pclk) 291 pPriv->set_pclk(output, pclk); 292} 293 294int 295G80OutputModeValid(xf86OutputPtr output, DisplayModePtr mode) 296{ 297 if(mode->Clock > 400000) 298 return MODE_CLOCK_HIGH; 299 if(mode->Clock < 25000) 300 return MODE_CLOCK_LOW; 301 302 return MODE_OK; 303} 304 305void 306G80OutputPrepare(xf86OutputPtr output) 307{ 308} 309 310void 311G80OutputCommit(xf86OutputPtr output) 312{ 313} 314 315static xf86MonPtr 316ProbeDDC(I2CBusPtr i2c) 317{ 318 ScrnInfoPtr pScrn = xf86Screens[i2c->scrnIndex]; 319 G80Ptr pNv = G80PTR(pScrn); 320 xf86MonPtr monInfo = NULL; 321 const int bus = i2c->DriverPrivate.val; 322 const CARD32 addr = i2cAddr(bus); 323 324 xf86DrvMsg(pScrn->scrnIndex, X_INFO, 325 "Probing for EDID on I2C bus %i...\n", bus); 326 pNv->reg[addr/4] = 7; 327 /* Should probably use xf86OutputGetEDID here */ 328#ifdef EDID_COMPLETE_RAWDATA 329 monInfo = xf86DoEEDID(pScrn->scrnIndex, i2c, TRUE); 330#else 331 monInfo = xf86DoEDID_DDC2(pScrn->scrnIndex, i2c); 332#endif 333 pNv->reg[addr/4] = 3; 334 335 if(monInfo) { 336 xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 337 "DDC detected a %s:\n", monInfo->features.input_type ? 338 "DFP" : "CRT"); 339 xf86PrintEDID(monInfo); 340 } else { 341 xf86DrvMsg(pScrn->scrnIndex, X_INFO, " ... none found\n"); 342 } 343 344 return monInfo; 345} 346 347/* 348 * Read an EDID from the i2c port. Perform load detection on the DAC (if 349 * present) to see if the display is connected via VGA. Sets the cached status 350 * of both outputs. The status is marked dirty again in the BlockHandler. 351 */ 352void G80OutputPartnersDetect(xf86OutputPtr dac, xf86OutputPtr sor, I2CBusPtr i2c) 353{ 354 xf86MonPtr monInfo = ProbeDDC(i2c); 355 xf86OutputPtr connected = NULL; 356 Bool load = dac && G80DacLoadDetect(dac); 357 358 if(dac) { 359 G80OutputPrivPtr pPriv = dac->driver_private; 360 361 if(load) { 362 pPriv->cached_status = XF86OutputStatusConnected; 363 connected = dac; 364 } else { 365 pPriv->cached_status = XF86OutputStatusDisconnected; 366 } 367 } 368 369 if(sor) { 370 G80OutputPrivPtr pPriv = sor->driver_private; 371 372 if(monInfo && !load) { 373 pPriv->cached_status = XF86OutputStatusConnected; 374 connected = sor; 375 } else { 376 pPriv->cached_status = XF86OutputStatusDisconnected; 377 } 378 } 379 380 if(connected) 381 xf86OutputSetEDID(connected, monInfo); 382} 383 384/* 385 * Reset the cached output status for all outputs. Called from G80BlockHandler. 386 */ 387void 388G80OutputResetCachedStatus(ScrnInfoPtr pScrn) 389{ 390 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 391 int i; 392 393 for(i = 0; i < xf86_config->num_output; i++) { 394 G80OutputPrivPtr pPriv = xf86_config->output[i]->driver_private; 395 pPriv->cached_status = XF86OutputStatusUnknown; 396 } 397} 398 399DisplayModePtr 400G80OutputGetDDCModes(xf86OutputPtr output) 401{ 402 /* The EDID is read as part of the detect step */ 403 output->funcs->detect(output); 404 return xf86OutputGetEDIDModes(output); 405} 406 407void 408G80OutputDestroy(xf86OutputPtr output) 409{ 410 G80OutputPrivPtr pPriv = output->driver_private; 411 412 if(pPriv->partner) 413 ((G80OutputPrivPtr)pPriv->partner->driver_private)->partner = NULL; 414 else 415 xf86DestroyI2CBusRec(pPriv->i2c, TRUE, TRUE); 416 pPriv->i2c = NULL; 417} 418 419Bool 420G80CreateOutputs(ScrnInfoPtr pScrn) 421{ 422 G80Ptr pNv = G80PTR(pScrn); 423 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 424 int i; 425 426 if(!G80ReadPortMapping(pScrn->scrnIndex, pNv)) 427 return FALSE; 428 429 /* For each DDC port, create an output for the attached ORs */ 430 for(i = 0; i < G80_NUM_I2C_PORTS; i++) { 431 xf86OutputPtr dac = NULL, sor = NULL; 432 I2CBusPtr i2c; 433 char i2cName[16]; 434 435 if(pNv->i2cMap[i].dac == -1 && pNv->i2cMap[i].sor == -1) 436 /* No outputs on this port */ 437 continue; 438 439 snprintf(i2cName, sizeof(i2cName), "I2C%i", i); 440 i2c = G80I2CInit(pScrn, i2cName, i); 441 if(!i2c) { 442 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 443 "Failed to initialize I2C for port %i.\n", 444 i); 445 continue; 446 } 447 448 if(pNv->i2cMap[i].dac != -1) 449 dac = G80CreateDac(pScrn, pNv->i2cMap[i].dac); 450 if(pNv->i2cMap[i].sor != -1) 451 sor = G80CreateSor(pScrn, pNv->i2cMap[i].sor, TMDS); 452 453 if(dac) { 454 G80OutputPrivPtr pPriv = dac->driver_private; 455 456 pPriv->partner = sor; 457 pPriv->i2c = i2c; 458 pPriv->scale = G80_SCALE_OFF; 459 } 460 if(sor) { 461 G80OutputPrivPtr pPriv = sor->driver_private; 462 463 pPriv->partner = dac; 464 pPriv->i2c = i2c; 465 pPriv->scale = G80_SCALE_ASPECT; 466 } 467 } 468 469 if(pNv->lvds.present) { 470 xf86OutputPtr lvds = G80CreateSor(pScrn, pNv->lvds.or, LVDS); 471 G80OutputPrivPtr pPriv = lvds->driver_private; 472 473 pPriv->scale = G80_SCALE_ASPECT; 474 475 if(pNv->lvds.i2cPort != -1) { 476 char i2cName[16]; 477 478 snprintf(i2cName, sizeof(i2cName), "I2C%i (LVDS)", pNv->lvds.i2cPort); 479 pPriv->i2c = G80I2CInit(pScrn, i2cName, pNv->lvds.i2cPort); 480 if(!pPriv->i2c) { 481 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 482 "Failed to initialize I2C for port %i (LVDS)!\n", 483 pNv->lvds.i2cPort); 484 } 485 } 486 } 487 488 /* For each output, set the crtc and clone masks */ 489 for(i = 0; i < xf86_config->num_output; i++) { 490 xf86OutputPtr output = xf86_config->output[i]; 491 492 /* Any output can connect to any head */ 493 output->possible_crtcs = 0x3; 494 output->possible_clones = 0; 495 } 496 497 return TRUE; 498} 499