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