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