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