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