1 /* 2 * Copyright 2006-2011, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Alexander von Gluck, kallisti5@unixzen.com 7 */ 8 9 10 #include "connector.h" 11 12 #include <assert.h> 13 #include <Debug.h> 14 15 #include "accelerant_protos.h" 16 #include "accelerant.h" 17 #include "bios.h" 18 #include "encoder.h" 19 #include "gpu.h" 20 #include "utility.h" 21 22 23 #undef TRACE 24 25 #define TRACE_CONNECTOR 26 #ifdef TRACE_CONNECTOR 27 # define TRACE(x...) _sPrintf("radeon_hd: " x) 28 #else 29 # define TRACE(x...) ; 30 #endif 31 32 #define ERROR(x...) _sPrintf("radeon_hd: " x) 33 34 35 static void 36 gpio_lock_i2c(void* cookie, bool lock) 37 { 38 gpio_info* info = (gpio_info*)cookie; 39 40 uint32 buffer = 0; 41 42 if (lock == true) { 43 // hwCapable and > DCE3 44 if (info->i2c.hwCapable == true && gInfo->shared_info->dceMajor >= 3) { 45 // Switch GPIO pads to ddc mode 46 buffer = Read32(OUT, info->i2c.sclMaskReg); 47 buffer &= ~(1 << 16); 48 Write32(OUT, info->i2c.sclMaskReg, buffer); 49 } 50 51 // Clear pins 52 buffer = Read32(OUT, info->i2c.sclAReg) & ~info->i2c.sclAMask; 53 Write32(OUT, info->i2c.sclAReg, buffer); 54 buffer = Read32(OUT, info->i2c.sdaAReg) & ~info->i2c.sdaAMask; 55 Write32(OUT, info->i2c.sdaAReg, buffer); 56 } 57 58 // Set pins to input 59 buffer = Read32(OUT, info->i2c.sclEnReg) & ~info->i2c.sclEnMask; 60 Write32(OUT, info->i2c.sclEnReg, buffer); 61 buffer = Read32(OUT, info->i2c.sdaEnReg) & ~info->i2c.sdaEnMask; 62 Write32(OUT, info->i2c.sdaEnReg, buffer); 63 64 // mask clock GPIO pins for software use 65 buffer = Read32(OUT, info->i2c.sclMaskReg); 66 if (lock == true) 67 buffer |= info->i2c.sclMask; 68 else 69 buffer &= ~info->i2c.sclMask; 70 71 Write32(OUT, info->i2c.sclMaskReg, buffer); 72 Read32(OUT, info->i2c.sclMaskReg); 73 74 // mask data GPIO pins for software use 75 buffer = Read32(OUT, info->i2c.sdaMaskReg); 76 if (lock == true) 77 buffer |= info->i2c.sdaMask; 78 else 79 buffer &= ~info->i2c.sdaMask; 80 81 Write32(OUT, info->i2c.sdaMaskReg, buffer); 82 Read32(OUT, info->i2c.sdaMaskReg); 83 } 84 85 86 static status_t 87 gpio_get_i2c_bit(void* cookie, int* _clock, int* _data) 88 { 89 gpio_info* info = (gpio_info*)cookie; 90 91 uint32 scl = Read32(OUT, info->i2c.sclYReg) & info->i2c.sclYMask; 92 uint32 sda = Read32(OUT, info->i2c.sdaYReg) & info->i2c.sdaYMask; 93 94 *_clock = scl != 0; 95 *_data = sda != 0; 96 97 return B_OK; 98 } 99 100 101 static status_t 102 gpio_set_i2c_bit(void* cookie, int clock, int data) 103 { 104 gpio_info* info = (gpio_info*)cookie; 105 106 uint32 scl = Read32(OUT, info->i2c.sclEnReg) & ~info->i2c.sclEnMask; 107 scl |= clock ? 0 : info->i2c.sclEnMask; 108 Write32(OUT, info->i2c.sclEnReg, scl); 109 Read32(OUT, info->i2c.sclEnReg); 110 111 uint32 sda = Read32(OUT, info->i2c.sdaEnReg) & ~info->i2c.sdaEnMask; 112 sda |= data ? 0 : info->i2c.sdaEnMask; 113 Write32(OUT, info->i2c.sdaEnReg, sda); 114 Read32(OUT, info->i2c.sdaEnReg); 115 116 return B_OK; 117 } 118 119 120 bool 121 connector_read_edid(uint32 connectorIndex, edid1_info* edid) 122 { 123 // ensure things are sane 124 uint32 i2cPinIndex = gConnector[connectorIndex]->i2cPinIndex; 125 if (gGPIOInfo[i2cPinIndex]->valid == false 126 || gGPIOInfo[i2cPinIndex]->i2c.valid == false) { 127 ERROR("%s: invalid gpio %" B_PRIu32 " for connector %" B_PRIu32 "\n", 128 __func__, i2cPinIndex, connectorIndex); 129 return false; 130 } 131 132 i2c_bus bus; 133 134 ddc2_init_timing(&bus); 135 bus.cookie = (void*)gGPIOInfo[i2cPinIndex]; 136 bus.set_signals = &gpio_set_i2c_bit; 137 bus.get_signals = &gpio_get_i2c_bit; 138 139 gpio_lock_i2c(bus.cookie, true); 140 status_t edid_result = ddc2_read_edid1(&bus, edid, NULL, NULL); 141 gpio_lock_i2c(bus.cookie, false); 142 143 if (edid_result != B_OK) 144 return false; 145 146 TRACE("%s: found edid monitor on connector #%" B_PRId32 "\n", 147 __func__, connectorIndex); 148 149 return true; 150 } 151 152 153 bool 154 connector_read_mode_lvds(uint32 connectorIndex, display_mode* mode) 155 { 156 assert(mode); 157 158 uint8 dceMajor; 159 uint8 dceMinor; 160 int index = GetIndexIntoMasterTable(DATA, LVDS_Info); 161 uint16 offset; 162 163 union atomLVDSInfo { 164 struct _ATOM_LVDS_INFO info; 165 struct _ATOM_LVDS_INFO_V12 info_12; 166 }; 167 168 // Wipe out display_mode 169 memset(mode, 0, sizeof(display_mode)); 170 171 if (atom_parse_data_header(gAtomContext, index, NULL, 172 &dceMajor, &dceMinor, &offset) == B_OK) { 173 174 union atomLVDSInfo* lvdsInfo 175 = (union atomLVDSInfo*)(gAtomContext->bios + offset); 176 177 display_timing* timing = &mode->timing; 178 179 // Pixel Clock 180 timing->pixel_clock 181 = B_LENDIAN_TO_HOST_INT16(lvdsInfo->info.sLCDTiming.usPixClk) * 10; 182 // Horizontal 183 timing->h_display 184 = B_LENDIAN_TO_HOST_INT16(lvdsInfo->info.sLCDTiming.usHActive); 185 timing->h_total = timing->h_display + B_LENDIAN_TO_HOST_INT16( 186 lvdsInfo->info.sLCDTiming.usHBlanking_Time); 187 timing->h_sync_start = timing->h_display 188 + B_LENDIAN_TO_HOST_INT16(lvdsInfo->info.sLCDTiming.usHSyncOffset); 189 timing->h_sync_end = timing->h_sync_start 190 + B_LENDIAN_TO_HOST_INT16(lvdsInfo->info.sLCDTiming.usHSyncWidth); 191 // Vertical 192 timing->v_display 193 = B_LENDIAN_TO_HOST_INT16(lvdsInfo->info.sLCDTiming.usVActive); 194 timing->v_total = timing->v_display + B_LENDIAN_TO_HOST_INT16( 195 lvdsInfo->info.sLCDTiming.usVBlanking_Time); 196 timing->v_sync_start = timing->v_display 197 + B_LENDIAN_TO_HOST_INT16(lvdsInfo->info.sLCDTiming.usVSyncOffset); 198 timing->v_sync_end = timing->v_sync_start 199 + B_LENDIAN_TO_HOST_INT16(lvdsInfo->info.sLCDTiming.usVSyncWidth); 200 201 #if 0 202 // Who cares. 203 uint32 powerDelay 204 = B_LENDIAN_TO_HOST_INT16(lvdsInfo->info.usOffDelayInMs); 205 #endif 206 207 // Store special lvds flags the encoder setup needs 208 gConnector[connectorIndex]->lvdsFlags = lvdsInfo->info.ucLVDS_Misc; 209 210 // Spread Spectrum ID (in SS table) 211 gInfo->lvdsSpreadSpectrumID = lvdsInfo->info.ucSS_Id; 212 213 uint16 flags = B_LENDIAN_TO_HOST_INT16( 214 lvdsInfo->info.sLCDTiming.susModeMiscInfo.usAccess); 215 216 if ((flags & ATOM_VSYNC_POLARITY) == 0) 217 timing->flags |= B_POSITIVE_VSYNC; 218 if ((flags & ATOM_HSYNC_POLARITY) == 0) 219 timing->flags |= B_POSITIVE_HSYNC; 220 221 // Extra flags 222 if ((flags & ATOM_INTERLACE) != 0) 223 timing->flags |= B_TIMING_INTERLACED; 224 225 #if 0 226 // We don't use these timing flags at the moment 227 if ((flags & ATOM_COMPOSITESYNC) != 0) 228 timing->flags |= MODE_FLAG_CSYNC; 229 if ((flags & ATOM_DOUBLE_CLOCK_MODE) != 0) 230 timing->flags |= MODE_FLAG_DBLSCAN; 231 #endif 232 233 mode->h_display_start = 0; 234 mode->v_display_start = 0; 235 mode->virtual_width = timing->h_display; 236 mode->virtual_height = timing->v_display; 237 238 // Assume 32-bit color 239 mode->space = B_RGB32_LITTLE; 240 241 TRACE("%s: %" B_PRIu32 " %" B_PRIu16 " %" B_PRIu16 " %" B_PRIu16 242 " %" B_PRIu16 " %" B_PRIu16 " %" B_PRIu16 " %" B_PRIu16 243 " %" B_PRIu16 "\n", __func__, timing->pixel_clock, 244 timing->h_display, timing->h_sync_start, timing->h_sync_end, 245 timing->h_total, timing->v_display, timing->v_sync_start, 246 timing->v_sync_end, timing->v_total); 247 248 return true; 249 } 250 return false; 251 } 252 253 254 static status_t 255 connector_attach_gpio_i2c(uint32 connectorIndex, uint8 hwPin) 256 { 257 gConnector[connectorIndex]->i2cPinIndex = 0; 258 for (uint32 i = 0; i < MAX_GPIO_PINS; i++) { 259 if (gGPIOInfo[i]->hwPin != hwPin) 260 continue; 261 gConnector[connectorIndex]->i2cPinIndex = i; 262 return B_OK; 263 } 264 265 // We couldnt find the GPIO pin in the known GPIO pins. 266 TRACE("%s: can't find GPIO pin 0x%" B_PRIX8 " for connector %" B_PRIu32 "\n", 267 __func__, hwPin, connectorIndex); 268 return B_ERROR; 269 } 270 271 272 static status_t 273 connector_attach_gpio_hpd(uint32 connectorIndex, uint8 hwPin) 274 { 275 gConnector[connectorIndex]->hpdPinIndex = 0; 276 277 for (uint32 i = 0; i < MAX_GPIO_PINS; i++) { 278 if (gGPIOInfo[i]->hwPin != hwPin) 279 continue; 280 gConnector[connectorIndex]->hpdPinIndex = i; 281 return B_OK; 282 } 283 284 // We couldnt find the GPIO pin in the known GPIO pins. 285 TRACE("%s: can't find GPIO pin 0x%" B_PRIX8 " for connector %" B_PRIu32 "\n", 286 __func__, hwPin, connectorIndex); 287 return B_ERROR; 288 } 289 290 291 static status_t 292 gpio_general_populate() 293 { 294 int index = GetIndexIntoMasterTable(DATA, GPIO_Pin_LUT); 295 uint16 tableOffset; 296 uint16 tableSize; 297 298 struct _ATOM_GPIO_PIN_LUT* gpioInfo; 299 300 if (atom_parse_data_header(gAtomContext, index, &tableSize, NULL, NULL, 301 &tableOffset)) { 302 ERROR("%s: could't read GPIO_Pin_LUT table from AtomBIOS index %d!\n", 303 __func__, index); 304 } 305 gpioInfo = (struct _ATOM_GPIO_PIN_LUT*)(gAtomContext->bios + tableOffset); 306 307 int numIndices = (tableSize - sizeof(ATOM_COMMON_TABLE_HEADER)) / 308 sizeof(ATOM_GPIO_PIN_ASSIGNMENT); 309 310 // Find the next available GPIO pin index 311 int32 gpioIndex = -1; 312 for(int32 pin = 0; pin < MAX_GPIO_PINS; pin++) { 313 if (!gGPIOInfo[pin]->valid) { 314 gpioIndex = pin; 315 break; 316 } 317 } 318 if (gpioIndex < 0) { 319 ERROR("%s: ERROR: Out of space for additional GPIO pins!\n", __func__); 320 return B_ERROR; 321 } 322 323 ATOM_GPIO_PIN_ASSIGNMENT* pin = gpioInfo->asGPIO_Pin; 324 for (int i = 0; i < numIndices; i++) { 325 if (gGPIOInfo[gpioIndex]->valid) { 326 ERROR("%s: BUG: Attempting to fill already populated gpio pin!\n", 327 __func__); 328 return B_ERROR; 329 } 330 gGPIOInfo[gpioIndex]->valid = true; 331 gGPIOInfo[gpioIndex]->i2c.valid = false; 332 gGPIOInfo[gpioIndex]->hwPin = pin->ucGPIO_ID; 333 gGPIOInfo[gpioIndex]->hwReg 334 = B_LENDIAN_TO_HOST_INT16(pin->usGpioPin_AIndex) * 4; 335 gGPIOInfo[gpioIndex]->hwMask 336 = (1 << pin->ucGpioPinBitShift); 337 pin = (ATOM_GPIO_PIN_ASSIGNMENT*)((uint8*)pin 338 + sizeof(ATOM_GPIO_PIN_ASSIGNMENT)); 339 340 TRACE("%s: general GPIO @ %" B_PRId32 ", valid: %s, " 341 "hwPin: 0x%" B_PRIX32 "\n", __func__, gpioIndex, 342 gGPIOInfo[gpioIndex]->valid ? "true" : "false", 343 gGPIOInfo[gpioIndex]->hwPin); 344 345 gpioIndex++; 346 } 347 return B_OK; 348 } 349 350 351 static status_t 352 gpio_i2c_populate() 353 { 354 radeon_shared_info &info = *gInfo->shared_info; 355 356 int index = GetIndexIntoMasterTable(DATA, GPIO_I2C_Info); 357 uint16 tableOffset; 358 uint16 tableSize; 359 360 if (atom_parse_data_header(gAtomContext, index, &tableSize, 361 NULL, NULL, &tableOffset) != B_OK) { 362 ERROR("%s: could't read GPIO_I2C_Info table from AtomBIOS index %d!\n", 363 __func__, index); 364 return B_ERROR; 365 } 366 367 struct _ATOM_GPIO_I2C_INFO* i2cInfo 368 = (struct _ATOM_GPIO_I2C_INFO*)(gAtomContext->bios + tableOffset); 369 370 uint32 numIndices = (tableSize - sizeof(ATOM_COMMON_TABLE_HEADER)) 371 / sizeof(ATOM_GPIO_I2C_ASSIGMENT); 372 373 if (numIndices > ATOM_MAX_SUPPORTED_DEVICE) { 374 ERROR("%s: ERROR: AtomBIOS contains more GPIO_Info items then I" 375 "was prepared for! (seen: %" B_PRIu32 "; max: %" B_PRIu32 ")\n", 376 __func__, numIndices, (uint32)ATOM_MAX_SUPPORTED_DEVICE); 377 return B_ERROR; 378 } 379 380 // Find the next available GPIO pin index 381 int32 gpioIndex = -1; 382 for(int32 pin = 0; pin < MAX_GPIO_PINS; pin++) { 383 if (!gGPIOInfo[pin]->valid) { 384 gpioIndex = pin; 385 break; 386 } 387 } 388 if (gpioIndex < 0) { 389 ERROR("%s: ERROR: Out of space for additional GPIO pins!\n", __func__); 390 return B_ERROR; 391 } 392 393 for (uint32 i = 0; i < numIndices; i++) { 394 if (gGPIOInfo[gpioIndex]->valid) { 395 ERROR("%s: BUG: Attempting to fill already populated gpio pin!\n", 396 __func__); 397 return B_ERROR; 398 } 399 ATOM_GPIO_I2C_ASSIGMENT* gpio = &i2cInfo->asGPIO_Info[i]; 400 401 if (info.dceMajor >= 3) { 402 if (i == 4 && B_LENDIAN_TO_HOST_INT16(gpio->usClkMaskRegisterIndex) 403 == 0x1fda && gpio->sucI2cId.ucAccess == 0x94) { 404 gpio->sucI2cId.ucAccess = 0x14; 405 TRACE("%s: BUG: GPIO override for DCE 3 occured\n", __func__); 406 } 407 } 408 409 if (info.dceMajor >= 4) { 410 if (i == 7 && B_LENDIAN_TO_HOST_INT16(gpio->usClkMaskRegisterIndex) 411 == 0x1936 && gpio->sucI2cId.ucAccess == 0) { 412 gpio->sucI2cId.ucAccess = 0x97; 413 gpio->ucDataMaskShift = 8; 414 gpio->ucDataEnShift = 8; 415 gpio->ucDataY_Shift = 8; 416 gpio->ucDataA_Shift = 8; 417 TRACE("%s: BUG: GPIO override for DCE 4 occured\n", __func__); 418 } 419 } 420 421 // populate gpio information 422 gGPIOInfo[gpioIndex]->hwPin = gpio->sucI2cId.ucAccess; 423 gGPIOInfo[gpioIndex]->i2c.hwCapable 424 = (gpio->sucI2cId.sbfAccess.bfHW_Capable) ? true : false; 425 426 // GPIO mask (Allows software to control the GPIO pad) 427 // 0 = chip access; 1 = only software; 428 gGPIOInfo[gpioIndex]->i2c.sclMaskReg 429 = B_LENDIAN_TO_HOST_INT16(gpio->usClkMaskRegisterIndex) * 4; 430 gGPIOInfo[gpioIndex]->i2c.sdaMaskReg 431 = B_LENDIAN_TO_HOST_INT16(gpio->usDataMaskRegisterIndex) * 4; 432 gGPIOInfo[gpioIndex]->i2c.sclMask = 1 << gpio->ucClkMaskShift; 433 gGPIOInfo[gpioIndex]->i2c.sdaMask = 1 << gpio->ucDataMaskShift; 434 435 // GPIO output / write (A) enable 436 // 0 = GPIO input (Y); 1 = GPIO output (A); 437 gGPIOInfo[gpioIndex]->i2c.sclEnReg 438 = B_LENDIAN_TO_HOST_INT16(gpio->usClkEnRegisterIndex) * 4; 439 gGPIOInfo[gpioIndex]->i2c.sdaEnReg 440 = B_LENDIAN_TO_HOST_INT16(gpio->usDataEnRegisterIndex) * 4; 441 gGPIOInfo[gpioIndex]->i2c.sclEnMask = 1 << gpio->ucClkEnShift; 442 gGPIOInfo[gpioIndex]->i2c.sdaEnMask = 1 << gpio->ucDataEnShift; 443 444 // GPIO output / write (A) 445 gGPIOInfo[gpioIndex]->i2c.sclAReg 446 = B_LENDIAN_TO_HOST_INT16(gpio->usClkA_RegisterIndex) * 4; 447 gGPIOInfo[gpioIndex]->i2c.sdaAReg 448 = B_LENDIAN_TO_HOST_INT16(gpio->usDataA_RegisterIndex) * 4; 449 gGPIOInfo[gpioIndex]->i2c.sclAMask = 1 << gpio->ucClkA_Shift; 450 gGPIOInfo[gpioIndex]->i2c.sdaAMask = 1 << gpio->ucDataA_Shift; 451 452 // GPIO input / read (Y) 453 gGPIOInfo[gpioIndex]->i2c.sclYReg 454 = B_LENDIAN_TO_HOST_INT16(gpio->usClkY_RegisterIndex) * 4; 455 gGPIOInfo[gpioIndex]->i2c.sdaYReg 456 = B_LENDIAN_TO_HOST_INT16(gpio->usDataY_RegisterIndex) * 4; 457 gGPIOInfo[gpioIndex]->i2c.sclYMask = 1 << gpio->ucClkY_Shift; 458 gGPIOInfo[gpioIndex]->i2c.sdaYMask = 1 << gpio->ucDataY_Shift; 459 460 // ensure data is valid 461 gGPIOInfo[gpioIndex]->i2c.valid 462 = gGPIOInfo[gpioIndex]->i2c.sclMaskReg ? true : false; 463 gGPIOInfo[gpioIndex]->valid = gGPIOInfo[gpioIndex]->i2c.valid; 464 465 TRACE("%s: i2c GPIO @ %" B_PRIu32 ", valid: %s, hwPin: 0x%" B_PRIX32 "\n", 466 __func__, gpioIndex, gGPIOInfo[gpioIndex]->valid ? "true" : "false", 467 gGPIOInfo[gpioIndex]->hwPin); 468 469 gpioIndex++; 470 } 471 472 return B_OK; 473 } 474 475 476 status_t 477 gpio_populate() 478 { 479 status_t result = gpio_general_populate(); 480 if (result != B_OK) 481 return result; 482 483 result = gpio_i2c_populate(); 484 return result; 485 } 486 487 488 status_t 489 connector_probe_legacy() 490 { 491 int index = GetIndexIntoMasterTable(DATA, SupportedDevicesInfo); 492 uint8 tableMajor; 493 uint8 tableMinor; 494 uint16 tableSize; 495 uint16 tableOffset; 496 497 if (atom_parse_data_header(gAtomContext, index, &tableSize, 498 &tableMajor, &tableMinor, &tableOffset) != B_OK) { 499 ERROR("%s: unable to parse data header!\n", __func__); 500 return B_ERROR; 501 } 502 503 union atomSupportedDevices { 504 struct _ATOM_SUPPORTED_DEVICES_INFO info; 505 struct _ATOM_SUPPORTED_DEVICES_INFO_2 info_2; 506 struct _ATOM_SUPPORTED_DEVICES_INFO_2d1 info_2d1; 507 }; 508 union atomSupportedDevices* supportedDevices; 509 supportedDevices = (union atomSupportedDevices*) 510 (gAtomContext->bios + tableOffset); 511 512 uint16 deviceSupport 513 = B_LENDIAN_TO_HOST_INT16(supportedDevices->info.usDeviceSupport); 514 515 uint32 maxDevice; 516 517 if (tableMajor > 1) 518 maxDevice = ATOM_MAX_SUPPORTED_DEVICE; 519 else 520 maxDevice = ATOM_MAX_SUPPORTED_DEVICE_INFO; 521 522 uint32 i; 523 uint32 connectorIndex = 0; 524 for (i = 0; i < maxDevice; i++) { 525 526 gConnector[connectorIndex]->valid = false; 527 528 // check if this connector is used 529 if ((deviceSupport & (1 << i)) == 0) 530 continue; 531 532 if (i == ATOM_DEVICE_CV_INDEX) { 533 TRACE("%s: skipping component video\n", 534 __func__); 535 continue; 536 } 537 538 ATOM_CONNECTOR_INFO_I2C ci 539 = supportedDevices->info.asConnInfo[i]; 540 541 gConnector[connectorIndex]->type = kConnectorConvertLegacy[ 542 ci.sucConnectorInfo.sbfAccess.bfConnectorType]; 543 544 if (gConnector[connectorIndex]->type == VIDEO_CONNECTOR_UNKNOWN) { 545 TRACE("%s: skipping unknown connector at %" B_PRId32 546 " of 0x%" B_PRIX8 "\n", __func__, i, 547 ci.sucConnectorInfo.sbfAccess.bfConnectorType); 548 continue; 549 } 550 551 // TODO: give tv unique connector ids 552 553 // Always set CRT1 and CRT2 as VGA, some cards incorrectly set 554 // VGA ports as DVI 555 if (i == ATOM_DEVICE_CRT1_INDEX || i == ATOM_DEVICE_CRT2_INDEX) 556 gConnector[connectorIndex]->type = VIDEO_CONNECTOR_VGA; 557 558 uint8 dac = ci.sucConnectorInfo.sbfAccess.bfAssociatedDAC; 559 uint32 encoderObject = encoder_object_lookup((1 << i), dac); 560 uint32 encoderID = (encoderObject & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; 561 562 gConnector[connectorIndex]->valid = true; 563 gConnector[connectorIndex]->flags = (1 << i); 564 gConnector[connectorIndex]->encoder.valid = true; 565 gConnector[connectorIndex]->encoder.objectID = encoderID; 566 gConnector[connectorIndex]->encoder.type 567 = encoder_type_lookup(encoderID, (1 << i)); 568 569 // TODO: Eval external encoders on legacy connector probe 570 gConnector[connectorIndex]->encoderExternal.valid = false; 571 // encoder_is_external(encoderID); 572 573 connector_attach_gpio_i2c(connectorIndex, ci.sucI2cId.ucAccess); 574 575 pll_limit_probe(&gConnector[connectorIndex]->encoder.pll); 576 577 connectorIndex++; 578 } 579 580 // TODO: combine shared connectors 581 582 if (connectorIndex == 0) { 583 TRACE("%s: zero connectors found using legacy detection\n", __func__); 584 return B_ERROR; 585 } 586 587 return B_OK; 588 } 589 590 591 // r600+ 592 status_t 593 connector_probe() 594 { 595 int index = GetIndexIntoMasterTable(DATA, Object_Header); 596 uint8 tableMajor; 597 uint8 tableMinor; 598 uint16 tableSize; 599 uint16 tableOffset; 600 601 if (atom_parse_data_header(gAtomContext, index, &tableSize, 602 &tableMajor, &tableMinor, &tableOffset) != B_OK) { 603 ERROR("%s: ERROR: parsing data header failed!\n", __func__); 604 return B_ERROR; 605 } 606 607 if (tableMinor < 2) { 608 ERROR("%s: ERROR: table minor version unknown! " 609 "(%" B_PRIu8 ".%" B_PRIu8 ")\n", __func__, tableMajor, tableMinor); 610 return B_ERROR; 611 } 612 613 ATOM_CONNECTOR_OBJECT_TABLE* connectorObject; 614 ATOM_ENCODER_OBJECT_TABLE* encoderObject; 615 ATOM_OBJECT_TABLE* routerObject; 616 ATOM_DISPLAY_OBJECT_PATH_TABLE* pathObject; 617 ATOM_OBJECT_HEADER* objectHeader; 618 619 objectHeader = (ATOM_OBJECT_HEADER*)(gAtomContext->bios + tableOffset); 620 pathObject = (ATOM_DISPLAY_OBJECT_PATH_TABLE*) 621 (gAtomContext->bios + tableOffset 622 + B_LENDIAN_TO_HOST_INT16(objectHeader->usDisplayPathTableOffset)); 623 connectorObject = (ATOM_CONNECTOR_OBJECT_TABLE*) 624 (gAtomContext->bios + tableOffset 625 + B_LENDIAN_TO_HOST_INT16(objectHeader->usConnectorObjectTableOffset)); 626 encoderObject = (ATOM_ENCODER_OBJECT_TABLE*) 627 (gAtomContext->bios + tableOffset 628 + B_LENDIAN_TO_HOST_INT16(objectHeader->usEncoderObjectTableOffset)); 629 routerObject = (ATOM_OBJECT_TABLE*) 630 (gAtomContext->bios + tableOffset 631 + B_LENDIAN_TO_HOST_INT16(objectHeader->usRouterObjectTableOffset)); 632 int deviceSupport = B_LENDIAN_TO_HOST_INT16(objectHeader->usDeviceSupport); 633 634 int pathSize = 0; 635 int32 i = 0; 636 637 TRACE("%s: found %" B_PRIu8 " potential display paths.\n", __func__, 638 pathObject->ucNumOfDispPath); 639 640 uint32 connectorIndex = 0; 641 for (i = 0; i < pathObject->ucNumOfDispPath; i++) { 642 643 if (connectorIndex >= ATOM_MAX_SUPPORTED_DEVICE) 644 continue; 645 646 uint8* address = (uint8*)pathObject->asDispPath; 647 ATOM_DISPLAY_OBJECT_PATH* path; 648 address += pathSize; 649 path = (ATOM_DISPLAY_OBJECT_PATH*)address; 650 pathSize += B_LENDIAN_TO_HOST_INT16(path->usSize); 651 652 uint32 connectorType; 653 uint16 connectorFlags = B_LENDIAN_TO_HOST_INT16(path->usDeviceTag); 654 655 if ((deviceSupport & connectorFlags) != 0) { 656 657 uint16 connectorObjectID 658 = (B_LENDIAN_TO_HOST_INT16(path->usConnObjectId) 659 & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; 660 //uint8 con_obj_num 661 // = (B_LENDIAN_TO_HOST_INT16(path->usConnObjectId) 662 // & ENUM_ID_MASK) >> ENUM_ID_SHIFT; 663 //uint8 con_obj_type 664 // = (B_LENDIAN_TO_HOST_INT16(path->usConnObjectId) 665 // & OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT; 666 667 if (connectorFlags == ATOM_DEVICE_CV_SUPPORT) { 668 TRACE("%s: Path #%" B_PRId32 ": skipping component video.\n", 669 __func__, i); 670 continue; 671 } 672 673 radeon_shared_info &info = *gInfo->shared_info; 674 675 uint16 igpLaneInfo; 676 if ((info.chipsetFlags & CHIP_IGP) != 0) { 677 ERROR("%s: TODO: IGP chip connector detection\n", __func__); 678 // try non-IGP method for now 679 igpLaneInfo = 0; 680 connectorType = kConnectorConvert[connectorObjectID]; 681 } else { 682 igpLaneInfo = 0; 683 connectorType = kConnectorConvert[connectorObjectID]; 684 } 685 686 if (connectorType == VIDEO_CONNECTOR_UNKNOWN) { 687 ERROR("%s: Path #%" B_PRId32 ": skipping unknown connector.\n", 688 __func__, i); 689 continue; 690 } 691 692 connector_info* connector = gConnector[connectorIndex]; 693 694 int32 j; 695 for (j = 0; j < ((B_LENDIAN_TO_HOST_INT16(path->usSize) - 8) / 2); 696 j++) { 697 //uint16 grph_obj_id 698 // = (B_LENDIAN_TO_HOST_INT16(path->usGraphicObjIds[j]) 699 // & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; 700 //uint8 grph_obj_num 701 // = (B_LENDIAN_TO_HOST_INT16(path->usGraphicObjIds[j]) & 702 // ENUM_ID_MASK) >> ENUM_ID_SHIFT; 703 uint8 graphicObjectType 704 = (B_LENDIAN_TO_HOST_INT16(path->usGraphicObjIds[j]) & 705 OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT; 706 707 if (graphicObjectType == GRAPH_OBJECT_TYPE_ENCODER) { 708 // Found an encoder 709 int32 k; 710 for (k = 0; k < encoderObject->ucNumberOfObjects; k++) { 711 uint16 encoderObjectRaw 712 = B_LENDIAN_TO_HOST_INT16( 713 encoderObject->asObjects[k].usObjectID); 714 if (B_LENDIAN_TO_HOST_INT16(path->usGraphicObjIds[j]) 715 == encoderObjectRaw) { 716 ATOM_COMMON_RECORD_HEADER* record 717 = (ATOM_COMMON_RECORD_HEADER*) 718 ((uint16*)gAtomContext->bios + tableOffset 719 + B_LENDIAN_TO_HOST_INT16( 720 encoderObject->asObjects[k].usRecordOffset)); 721 ATOM_ENCODER_CAP_RECORD* capRecord; 722 uint16 caps = 0; 723 while (record->ucRecordSize > 0 724 && record->ucRecordType > 0 725 && record->ucRecordType 726 <= ATOM_MAX_OBJECT_RECORD_NUMBER) { 727 switch (record->ucRecordType) { 728 case ATOM_ENCODER_CAP_RECORD_TYPE: 729 capRecord = (ATOM_ENCODER_CAP_RECORD*) 730 record; 731 caps = B_LENDIAN_TO_HOST_INT16( 732 capRecord->usEncoderCap); 733 break; 734 } 735 record = (ATOM_COMMON_RECORD_HEADER*) 736 ((char*)record + record->ucRecordSize); 737 } 738 739 uint32 encoderID 740 = (encoderObjectRaw & OBJECT_ID_MASK) 741 >> OBJECT_ID_SHIFT; 742 743 uint32 encoderType = encoder_type_lookup(encoderID, 744 connectorFlags); 745 746 if (encoderType == VIDEO_ENCODER_NONE) { 747 ERROR("%s: Path #%" B_PRId32 ":" 748 "skipping unknown encoder.\n", 749 __func__, i); 750 continue; 751 } 752 753 encoder_info* encoder; 754 755 // External encoders are behind DVO or UNIPHY 756 if (encoder_is_external(encoderID)) { 757 encoder = &connector->encoderExternal; 758 encoder->isExternal = true; 759 encoder->isDPBridge 760 = encoder_is_dp_bridge(encoderID); 761 } else { 762 encoder = &connector->encoder; 763 encoder->isExternal = false; 764 encoder->isDPBridge = false; 765 } 766 767 // Set up found connector encoder generics 768 encoder->valid = true; 769 encoder->capabilities = caps; 770 encoder->objectID = encoderID; 771 encoder->type = encoderType; 772 encoder->linkEnumeration 773 = (encoderObjectRaw & ENUM_ID_MASK) 774 >> ENUM_ID_SHIFT; 775 pll_limit_probe(&encoder->pll); 776 } 777 } 778 // END if object is encoder 779 } else if (graphicObjectType == GRAPH_OBJECT_TYPE_ROUTER) { 780 ERROR("%s: TODO: Found router object?\n", __func__); 781 } // END if object is router 782 } 783 784 // Set up information buses such as ddc 785 if (((connectorFlags & ATOM_DEVICE_TV_SUPPORT) == 0) 786 && (connectorFlags & ATOM_DEVICE_CV_SUPPORT) == 0) { 787 for (j = 0; j < connectorObject->ucNumberOfObjects; j++) { 788 if (B_LENDIAN_TO_HOST_INT16(path->usConnObjectId) 789 == B_LENDIAN_TO_HOST_INT16( 790 connectorObject->asObjects[j].usObjectID)) { 791 ATOM_COMMON_RECORD_HEADER* record 792 = (ATOM_COMMON_RECORD_HEADER*)(gAtomContext->bios 793 + tableOffset + B_LENDIAN_TO_HOST_INT16( 794 connectorObject->asObjects[j].usRecordOffset)); 795 while (record->ucRecordSize > 0 796 && record->ucRecordType > 0 797 && record->ucRecordType 798 <= ATOM_MAX_OBJECT_RECORD_NUMBER) { 799 ATOM_I2C_RECORD* i2cRecord; 800 ATOM_I2C_ID_CONFIG_ACCESS* i2cConfig; 801 ATOM_HPD_INT_RECORD* hpdRecord; 802 803 switch (record->ucRecordType) { 804 case ATOM_I2C_RECORD_TYPE: 805 i2cRecord 806 = (ATOM_I2C_RECORD*)record; 807 i2cConfig 808 = (ATOM_I2C_ID_CONFIG_ACCESS*) 809 &i2cRecord->sucI2cId; 810 connector_attach_gpio_i2c(connectorIndex, 811 i2cConfig->ucAccess); 812 break; 813 case ATOM_HPD_INT_RECORD_TYPE: 814 hpdRecord = (ATOM_HPD_INT_RECORD*)record; 815 connector_attach_gpio_hpd(connectorIndex, 816 hpdRecord->ucHPDIntGPIOID); 817 break; 818 } 819 820 // move to next record 821 record = (ATOM_COMMON_RECORD_HEADER*) 822 ((char*)record + record->ucRecordSize); 823 } 824 } 825 } 826 } 827 828 connector->valid = true; 829 connector->flags = connectorFlags; 830 connector->type = connectorType; 831 connector->objectID = connectorObjectID; 832 833 connectorIndex++; 834 } // END for each valid connector 835 } // end for each display path 836 837 return B_OK; 838 } 839 840 841 bool 842 connector_is_dp(uint32 connectorIndex) 843 { 844 connector_info* connector = gConnector[connectorIndex]; 845 846 // Traditional DisplayPort connector 847 if (connector->type == VIDEO_CONNECTOR_DP 848 || connector->type == VIDEO_CONNECTOR_EDP) { 849 return true; 850 } 851 852 // DisplayPort bridge on external encoder 853 if (connector->encoderExternal.valid == true 854 && connector->encoderExternal.isDPBridge == true) { 855 return true; 856 } 857 858 return false; 859 } 860 861 862 void 863 debug_connectors() 864 { 865 ERROR("Currently detected connectors=============\n"); 866 for (uint32 id = 0; id < ATOM_MAX_SUPPORTED_DEVICE; id++) { 867 if (gConnector[id]->valid == true) { 868 uint32 connectorType = gConnector[id]->type; 869 uint16 i2cPinIndex = gConnector[id]->i2cPinIndex; 870 uint16 hpdPinIndex = gConnector[id]->hpdPinIndex; 871 872 ERROR("Connector #%" B_PRIu32 ")\n", id); 873 ERROR(" + connector: %s\n", 874 get_connector_name(connectorType)); 875 ERROR(" + i2c gpio table id: %" B_PRIu16 "\n", i2cPinIndex); 876 ERROR(" - gpio hw pin: 0x%" B_PRIX32 "\n", 877 gGPIOInfo[i2cPinIndex]->hwPin); 878 ERROR(" - gpio valid: %s\n", 879 gGPIOInfo[i2cPinIndex]->valid ? "true" : "false"); 880 ERROR(" - i2c valid: %s\n", 881 gGPIOInfo[i2cPinIndex]->i2c.valid ? "true" : "false"); 882 ERROR(" + hpd gpio table id: %" B_PRIu16 "\n", hpdPinIndex); 883 ERROR(" - gpio hw pin: 0x%" B_PRIX32 "\n", 884 gGPIOInfo[hpdPinIndex]->hwPin); 885 ERROR(" - gpio valid: %s\n", 886 gGPIOInfo[hpdPinIndex]->valid ? "true" : "false"); 887 encoder_info* encoder = &gConnector[id]->encoder; 888 ERROR(" + encoder: %s\n", 889 get_encoder_name(encoder->type)); 890 ERROR(" - id: %" B_PRIu16 "\n", encoder->objectID); 891 ERROR(" - type: %s\n", 892 encoder_name_lookup(encoder->objectID)); 893 ERROR(" - capabilities: 0x%" B_PRIX32 "\n", 894 encoder->capabilities); 895 ERROR(" - enumeration: %" B_PRIu32 "\n", 896 encoder->linkEnumeration); 897 898 encoder = &gConnector[id]->encoderExternal; 899 900 ERROR(" - is bridge: %s\n", 901 encoder->valid ? "true" : "false"); 902 903 if (!encoder->valid) 904 ERROR(" + external encoder: none\n"); 905 else { 906 ERROR(" + external encoder: %s\n", 907 get_encoder_name(encoder->type)); 908 ERROR(" - valid: true\n"); 909 ERROR(" - id: %" B_PRIu16 "\n", 910 encoder->objectID); 911 ERROR(" - type: %s\n", 912 encoder_name_lookup(encoder->objectID)); 913 ERROR(" - enumeration: %" B_PRIu32 "\n", 914 encoder->linkEnumeration); 915 } 916 917 uint32 connectorFlags = gConnector[id]->flags; 918 bool flags = false; 919 ERROR(" + flags:\n"); 920 if ((connectorFlags & ATOM_DEVICE_CRT1_SUPPORT) != 0) { 921 ERROR(" * device CRT1 support\n"); 922 flags = true; 923 } 924 if ((connectorFlags & ATOM_DEVICE_CRT2_SUPPORT) != 0) { 925 ERROR(" * device CRT2 support\n"); 926 flags = true; 927 } 928 if ((connectorFlags & ATOM_DEVICE_LCD1_SUPPORT) != 0) { 929 ERROR(" * device LCD1 support\n"); 930 flags = true; 931 } 932 if ((connectorFlags & ATOM_DEVICE_LCD2_SUPPORT) != 0) { 933 ERROR(" * device LCD2 support\n"); 934 flags = true; 935 } 936 if ((connectorFlags & ATOM_DEVICE_TV1_SUPPORT) != 0) { 937 ERROR(" * device TV1 support\n"); 938 flags = true; 939 } 940 if ((connectorFlags & ATOM_DEVICE_CV_SUPPORT) != 0) { 941 ERROR(" * device CV support\n"); 942 flags = true; 943 } 944 if ((connectorFlags & ATOM_DEVICE_DFP1_SUPPORT) != 0) { 945 ERROR(" * device DFP1 support\n"); 946 flags = true; 947 } 948 if ((connectorFlags & ATOM_DEVICE_DFP2_SUPPORT) != 0) { 949 ERROR(" * device DFP2 support\n"); 950 flags = true; 951 } 952 if ((connectorFlags & ATOM_DEVICE_DFP3_SUPPORT) != 0) { 953 ERROR(" * device DFP3 support\n"); 954 flags = true; 955 } 956 if ((connectorFlags & ATOM_DEVICE_DFP4_SUPPORT) != 0) { 957 ERROR(" * device DFP4 support\n"); 958 flags = true; 959 } 960 if ((connectorFlags & ATOM_DEVICE_DFP5_SUPPORT) != 0) { 961 ERROR(" * device DFP5 support\n"); 962 flags = true; 963 } 964 if ((connectorFlags & ATOM_DEVICE_DFP6_SUPPORT) != 0) { 965 ERROR(" * device DFP6 support\n"); 966 flags = true; 967 } 968 if (flags == false) 969 ERROR(" * no known flags\n"); 970 } 971 } 972 ERROR("==========================================\n"); 973 } 974