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