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]->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 encoder_info* encoder; 636 637 // External encoders are behind DVO or UNIPHY 638 if (encoder_is_external(encoderID)) { 639 encoder = &connector->encoderExternal; 640 encoder->isExternal = true; 641 encoder->isDPBridge 642 = encoder_is_dp_bridge(encoderID); 643 } else { 644 encoder = &connector->encoder; 645 encoder->isExternal = false; 646 encoder->isDPBridge = false; 647 } 648 649 // Set up found connector encoder generics 650 encoder->valid = true; 651 encoder->capabilities = caps; 652 encoder->objectID = encoderID; 653 encoder->type = encoderType; 654 encoder->linkEnumeration 655 = (encoderObjectRaw & ENUM_ID_MASK) 656 >> ENUM_ID_SHIFT; 657 pll_limit_probe(&encoder->pll); 658 } 659 } 660 // END if object is encoder 661 } else if (graphicObjectType == GRAPH_OBJECT_TYPE_ROUTER) { 662 ERROR("%s: TODO: Found router object?\n", __func__); 663 } // END if object is router 664 } 665 666 // Set up information buses such as ddc 667 if (((connectorFlags & ATOM_DEVICE_TV_SUPPORT) == 0) 668 && (connectorFlags & ATOM_DEVICE_CV_SUPPORT) == 0) { 669 for (j = 0; j < connectorObject->ucNumberOfObjects; j++) { 670 if (B_LENDIAN_TO_HOST_INT16(path->usConnObjectId) 671 == B_LENDIAN_TO_HOST_INT16( 672 connectorObject->asObjects[j].usObjectID)) { 673 ATOM_COMMON_RECORD_HEADER* record 674 = (ATOM_COMMON_RECORD_HEADER*)(gAtomContext->bios 675 + tableOffset + B_LENDIAN_TO_HOST_INT16( 676 connectorObject->asObjects[j].usRecordOffset)); 677 while (record->ucRecordSize > 0 678 && record->ucRecordType > 0 679 && record->ucRecordType 680 <= ATOM_MAX_OBJECT_RECORD_NUMBER) { 681 ATOM_I2C_RECORD* i2cRecord; 682 ATOM_I2C_ID_CONFIG_ACCESS* i2cConfig; 683 //ATOM_HPD_INT_RECORD* hpd_record; 684 685 switch (record->ucRecordType) { 686 case ATOM_I2C_RECORD_TYPE: 687 i2cRecord 688 = (ATOM_I2C_RECORD*)record; 689 i2cConfig 690 = (ATOM_I2C_ID_CONFIG_ACCESS*) 691 &i2cRecord->sucI2cId; 692 // attach i2c gpio information for connector 693 connector_attach_gpio(connectorIndex, 694 i2cConfig->ucAccess); 695 break; 696 case ATOM_HPD_INT_RECORD_TYPE: 697 // TODO: HPD (Hot Plug) 698 break; 699 } 700 701 // move to next record 702 record = (ATOM_COMMON_RECORD_HEADER*) 703 ((char*)record + record->ucRecordSize); 704 } 705 } 706 } 707 } 708 709 // TODO: aux chan transactions 710 711 connector->valid = true; 712 connector->flags = connectorFlags; 713 connector->type = connectorType; 714 connector->objectID = connectorObjectID; 715 716 connectorIndex++; 717 } // END for each valid connector 718 } // end for each display path 719 720 return B_OK; 721 } 722 723 724 bool 725 connector_is_dp(uint32 connectorIndex) 726 { 727 connector_info* connector = gConnector[connectorIndex]; 728 729 // Traditional DisplayPort connector 730 if (connector->type == VIDEO_CONNECTOR_DP 731 || connector->type == VIDEO_CONNECTOR_EDP) { 732 return true; 733 } 734 735 // DisplayPort bridge on external encoder 736 if (connector->encoderExternal.valid == true 737 && connector->encoderExternal.isDPBridge == true) { 738 return true; 739 } 740 741 return false; 742 } 743 744 745 void 746 debug_connectors() 747 { 748 ERROR("Currently detected connectors=============\n"); 749 for (uint32 id = 0; id < ATOM_MAX_SUPPORTED_DEVICE; id++) { 750 if (gConnector[id]->valid == true) { 751 uint32 connectorType = gConnector[id]->type; 752 uint16 gpioID = gConnector[id]->gpioID; 753 754 ERROR("Connector #%" B_PRIu32 ")\n", id); 755 ERROR(" + connector: %s\n", 756 get_connector_name(connectorType)); 757 ERROR(" + gpio table id: %" B_PRIu16 "\n", gpioID); 758 ERROR(" + gpio hw pin: 0x%" B_PRIX32 "\n", 759 gGPIOInfo[gpioID]->hwPin); 760 ERROR(" + gpio valid: %s\n", 761 gGPIOInfo[gpioID]->valid ? "true" : "false"); 762 763 encoder_info* encoder = &gConnector[id]->encoder; 764 ERROR(" + encoder: %s\n", 765 get_encoder_name(encoder->type)); 766 ERROR(" - id: %" B_PRIu16 "\n", encoder->objectID); 767 ERROR(" - type: %s\n", 768 encoder_name_lookup(encoder->objectID)); 769 ERROR(" - capabilities: 0x%" B_PRIX32 "\n", 770 encoder->capabilities); 771 ERROR(" - enumeration: %" B_PRIu32 "\n", 772 encoder->linkEnumeration); 773 774 encoder = &gConnector[id]->encoderExternal; 775 776 ERROR(" - is bridge: %s\n", 777 encoder->valid ? "true" : "false"); 778 779 if (!encoder->valid) 780 ERROR(" + external encoder: none\n"); 781 else { 782 ERROR(" + external encoder: %s\n", 783 get_encoder_name(encoder->type)); 784 ERROR(" - valid: true\n"); 785 ERROR(" - id: %" B_PRIu16 "\n", 786 encoder->objectID); 787 ERROR(" - type: %s\n", 788 encoder_name_lookup(encoder->objectID)); 789 ERROR(" - enumeration: %" B_PRIu32 "\n", 790 encoder->linkEnumeration); 791 } 792 793 uint32 connectorFlags = gConnector[id]->flags; 794 bool flags = false; 795 ERROR(" + flags:\n"); 796 if ((connectorFlags & ATOM_DEVICE_CRT1_SUPPORT) != 0) { 797 ERROR(" * device CRT1 support\n"); 798 flags = true; 799 } 800 if ((connectorFlags & ATOM_DEVICE_CRT2_SUPPORT) != 0) { 801 ERROR(" * device CRT2 support\n"); 802 flags = true; 803 } 804 if ((connectorFlags & ATOM_DEVICE_LCD1_SUPPORT) != 0) { 805 ERROR(" * device LCD1 support\n"); 806 flags = true; 807 } 808 if ((connectorFlags & ATOM_DEVICE_LCD2_SUPPORT) != 0) { 809 ERROR(" * device LCD2 support\n"); 810 flags = true; 811 } 812 if ((connectorFlags & ATOM_DEVICE_TV1_SUPPORT) != 0) { 813 ERROR(" * device TV1 support\n"); 814 flags = true; 815 } 816 if ((connectorFlags & ATOM_DEVICE_CV_SUPPORT) != 0) { 817 ERROR(" * device CV support\n"); 818 flags = true; 819 } 820 if ((connectorFlags & ATOM_DEVICE_DFP1_SUPPORT) != 0) { 821 ERROR(" * device DFP1 support\n"); 822 flags = true; 823 } 824 if ((connectorFlags & ATOM_DEVICE_DFP2_SUPPORT) != 0) { 825 ERROR(" * device DFP2 support\n"); 826 flags = true; 827 } 828 if ((connectorFlags & ATOM_DEVICE_DFP3_SUPPORT) != 0) { 829 ERROR(" * device DFP3 support\n"); 830 flags = true; 831 } 832 if ((connectorFlags & ATOM_DEVICE_DFP4_SUPPORT) != 0) { 833 ERROR(" * device DFP4 support\n"); 834 flags = true; 835 } 836 if ((connectorFlags & ATOM_DEVICE_DFP5_SUPPORT) != 0) { 837 ERROR(" * device DFP5 support\n"); 838 flags = true; 839 } 840 if ((connectorFlags & ATOM_DEVICE_DFP6_SUPPORT) != 0) { 841 ERROR(" * device DFP6 support\n"); 842 flags = true; 843 } 844 if (flags == false) 845 ERROR(" * no known flags\n"); 846 } 847 } 848 ERROR("==========================================\n"); 849 } 850