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