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_router(uint32 connectorIndex, uint8 hwPin) 330 { 331 gConnector[connectorIndex]->router.i2cPinIndex = 0; 332 for (uint32 i = 0; i < MAX_GPIO_PINS; i++) { 333 if (gGPIOInfo[i]->hwPin != hwPin) 334 continue; 335 gConnector[connectorIndex]->router.i2cPinIndex = i; 336 return B_OK; 337 } 338 339 // We couldnt find the GPIO pin in the known GPIO pins. 340 TRACE("%s: can't find GPIO pin 0x%" B_PRIX8 " for connector %" B_PRIu32 "\n", 341 __func__, hwPin, connectorIndex); 342 return B_ERROR; 343 } 344 345 346 static status_t 347 connector_attach_gpio_hpd(uint32 connectorIndex, uint8 hwPin) 348 { 349 gConnector[connectorIndex]->hpdPinIndex = 0; 350 351 for (uint32 i = 0; i < MAX_GPIO_PINS; i++) { 352 if (gGPIOInfo[i]->hwPin != hwPin) 353 continue; 354 gConnector[connectorIndex]->hpdPinIndex = i; 355 return B_OK; 356 } 357 358 // We couldnt find the GPIO pin in the known GPIO pins. 359 TRACE("%s: can't find GPIO pin 0x%" B_PRIX8 " for connector %" B_PRIu32 "\n", 360 __func__, hwPin, connectorIndex); 361 return B_ERROR; 362 } 363 364 365 static status_t 366 gpio_general_populate() 367 { 368 int index = GetIndexIntoMasterTable(DATA, GPIO_Pin_LUT); 369 uint16 tableOffset; 370 uint16 tableSize; 371 372 struct _ATOM_GPIO_PIN_LUT* gpioInfo; 373 374 if (atom_parse_data_header(gAtomContext, index, &tableSize, NULL, NULL, 375 &tableOffset)) { 376 ERROR("%s: could't read GPIO_Pin_LUT table from AtomBIOS index %d!\n", 377 __func__, index); 378 } 379 gpioInfo = (struct _ATOM_GPIO_PIN_LUT*)(gAtomContext->bios + tableOffset); 380 381 int numIndices = (tableSize - sizeof(ATOM_COMMON_TABLE_HEADER)) / 382 sizeof(ATOM_GPIO_PIN_ASSIGNMENT); 383 384 // Find the next available GPIO pin index 385 int32 gpioIndex = -1; 386 for(int32 pin = 0; pin < MAX_GPIO_PINS; pin++) { 387 if (!gGPIOInfo[pin]->valid) { 388 gpioIndex = pin; 389 break; 390 } 391 } 392 if (gpioIndex < 0) { 393 ERROR("%s: ERROR: Out of space for additional GPIO pins!\n", __func__); 394 return B_ERROR; 395 } 396 397 ATOM_GPIO_PIN_ASSIGNMENT* pin = gpioInfo->asGPIO_Pin; 398 for (int i = 0; i < numIndices; i++) { 399 if (gGPIOInfo[gpioIndex]->valid) { 400 ERROR("%s: BUG: Attempting to fill already populated gpio pin!\n", 401 __func__); 402 return B_ERROR; 403 } 404 gGPIOInfo[gpioIndex]->valid = true; 405 gGPIOInfo[gpioIndex]->i2c.valid = false; 406 gGPIOInfo[gpioIndex]->hwPin = pin->ucGPIO_ID; 407 gGPIOInfo[gpioIndex]->hwReg 408 = B_LENDIAN_TO_HOST_INT16(pin->usGpioPin_AIndex) * 4; 409 gGPIOInfo[gpioIndex]->hwMask 410 = (1 << pin->ucGpioPinBitShift); 411 pin = (ATOM_GPIO_PIN_ASSIGNMENT*)((uint8*)pin 412 + sizeof(ATOM_GPIO_PIN_ASSIGNMENT)); 413 414 TRACE("%s: general GPIO @ %" B_PRId32 ", valid: %s, " 415 "hwPin: 0x%" B_PRIX32 "\n", __func__, gpioIndex, 416 gGPIOInfo[gpioIndex]->valid ? "true" : "false", 417 gGPIOInfo[gpioIndex]->hwPin); 418 419 gpioIndex++; 420 } 421 return B_OK; 422 } 423 424 425 static status_t 426 gpio_i2c_populate() 427 { 428 radeon_shared_info &info = *gInfo->shared_info; 429 430 int index = GetIndexIntoMasterTable(DATA, GPIO_I2C_Info); 431 uint16 tableOffset; 432 uint16 tableSize; 433 434 if (atom_parse_data_header(gAtomContext, index, &tableSize, 435 NULL, NULL, &tableOffset) != B_OK) { 436 ERROR("%s: could't read GPIO_I2C_Info table from AtomBIOS index %d!\n", 437 __func__, index); 438 return B_ERROR; 439 } 440 441 struct _ATOM_GPIO_I2C_INFO* i2cInfo 442 = (struct _ATOM_GPIO_I2C_INFO*)(gAtomContext->bios + tableOffset); 443 444 uint32 numIndices = (tableSize - sizeof(ATOM_COMMON_TABLE_HEADER)) 445 / sizeof(ATOM_GPIO_I2C_ASSIGMENT); 446 447 if (numIndices > ATOM_MAX_SUPPORTED_DEVICE) { 448 ERROR("%s: ERROR: AtomBIOS contains more GPIO_Info items then I" 449 "was prepared for! (seen: %" B_PRIu32 "; max: %" B_PRIu32 ")\n", 450 __func__, numIndices, (uint32)ATOM_MAX_SUPPORTED_DEVICE); 451 return B_ERROR; 452 } 453 454 // Find the next available GPIO pin index 455 int32 gpioIndex = -1; 456 for(int32 pin = 0; pin < MAX_GPIO_PINS; pin++) { 457 if (!gGPIOInfo[pin]->valid) { 458 gpioIndex = pin; 459 break; 460 } 461 } 462 if (gpioIndex < 0) { 463 ERROR("%s: ERROR: Out of space for additional GPIO pins!\n", __func__); 464 return B_ERROR; 465 } 466 467 for (uint32 i = 0; i < numIndices; i++) { 468 if (gGPIOInfo[gpioIndex]->valid) { 469 ERROR("%s: BUG: Attempting to fill already populated gpio pin!\n", 470 __func__); 471 return B_ERROR; 472 } 473 ATOM_GPIO_I2C_ASSIGMENT* gpio = &i2cInfo->asGPIO_Info[i]; 474 475 if (info.dceMajor >= 3) { 476 if (i == 4 && B_LENDIAN_TO_HOST_INT16(gpio->usClkMaskRegisterIndex) 477 == 0x1fda && gpio->sucI2cId.ucAccess == 0x94) { 478 gpio->sucI2cId.ucAccess = 0x14; 479 TRACE("%s: BUG: GPIO override for DCE 3 occured\n", __func__); 480 } 481 } 482 483 if (info.dceMajor >= 4) { 484 if (i == 7 && B_LENDIAN_TO_HOST_INT16(gpio->usClkMaskRegisterIndex) 485 == 0x1936 && gpio->sucI2cId.ucAccess == 0) { 486 gpio->sucI2cId.ucAccess = 0x97; 487 gpio->ucDataMaskShift = 8; 488 gpio->ucDataEnShift = 8; 489 gpio->ucDataY_Shift = 8; 490 gpio->ucDataA_Shift = 8; 491 TRACE("%s: BUG: GPIO override for DCE 4 occured\n", __func__); 492 } 493 } 494 495 // populate gpio information 496 gGPIOInfo[gpioIndex]->hwPin = gpio->sucI2cId.ucAccess; 497 gGPIOInfo[gpioIndex]->i2c.hwCapable 498 = (gpio->sucI2cId.sbfAccess.bfHW_Capable) ? true : false; 499 500 // GPIO mask (Allows software to control the GPIO pad) 501 // 0 = chip access; 1 = only software; 502 gGPIOInfo[gpioIndex]->i2c.sclMaskReg 503 = B_LENDIAN_TO_HOST_INT16(gpio->usClkMaskRegisterIndex) * 4; 504 gGPIOInfo[gpioIndex]->i2c.sdaMaskReg 505 = B_LENDIAN_TO_HOST_INT16(gpio->usDataMaskRegisterIndex) * 4; 506 gGPIOInfo[gpioIndex]->i2c.sclMask = 1 << gpio->ucClkMaskShift; 507 gGPIOInfo[gpioIndex]->i2c.sdaMask = 1 << gpio->ucDataMaskShift; 508 509 // GPIO output / write (A) enable 510 // 0 = GPIO input (Y); 1 = GPIO output (A); 511 gGPIOInfo[gpioIndex]->i2c.sclEnReg 512 = B_LENDIAN_TO_HOST_INT16(gpio->usClkEnRegisterIndex) * 4; 513 gGPIOInfo[gpioIndex]->i2c.sdaEnReg 514 = B_LENDIAN_TO_HOST_INT16(gpio->usDataEnRegisterIndex) * 4; 515 gGPIOInfo[gpioIndex]->i2c.sclEnMask = 1 << gpio->ucClkEnShift; 516 gGPIOInfo[gpioIndex]->i2c.sdaEnMask = 1 << gpio->ucDataEnShift; 517 518 // GPIO output / write (A) 519 gGPIOInfo[gpioIndex]->i2c.sclAReg 520 = B_LENDIAN_TO_HOST_INT16(gpio->usClkA_RegisterIndex) * 4; 521 gGPIOInfo[gpioIndex]->i2c.sdaAReg 522 = B_LENDIAN_TO_HOST_INT16(gpio->usDataA_RegisterIndex) * 4; 523 gGPIOInfo[gpioIndex]->i2c.sclAMask = 1 << gpio->ucClkA_Shift; 524 gGPIOInfo[gpioIndex]->i2c.sdaAMask = 1 << gpio->ucDataA_Shift; 525 526 // GPIO input / read (Y) 527 gGPIOInfo[gpioIndex]->i2c.sclYReg 528 = B_LENDIAN_TO_HOST_INT16(gpio->usClkY_RegisterIndex) * 4; 529 gGPIOInfo[gpioIndex]->i2c.sdaYReg 530 = B_LENDIAN_TO_HOST_INT16(gpio->usDataY_RegisterIndex) * 4; 531 gGPIOInfo[gpioIndex]->i2c.sclYMask = 1 << gpio->ucClkY_Shift; 532 gGPIOInfo[gpioIndex]->i2c.sdaYMask = 1 << gpio->ucDataY_Shift; 533 534 // ensure data is valid 535 gGPIOInfo[gpioIndex]->i2c.valid 536 = gGPIOInfo[gpioIndex]->i2c.sclMaskReg ? true : false; 537 gGPIOInfo[gpioIndex]->valid = gGPIOInfo[gpioIndex]->i2c.valid; 538 539 TRACE("%s: i2c GPIO @ %" B_PRIu32 ", valid: %s, hwPin: 0x%" B_PRIX32 "\n", 540 __func__, gpioIndex, gGPIOInfo[gpioIndex]->valid ? "true" : "false", 541 gGPIOInfo[gpioIndex]->hwPin); 542 543 gpioIndex++; 544 } 545 546 return B_OK; 547 } 548 549 550 status_t 551 gpio_populate() 552 { 553 status_t result = gpio_general_populate(); 554 if (result != B_OK) 555 return result; 556 557 result = gpio_i2c_populate(); 558 return result; 559 } 560 561 562 status_t 563 connector_probe_legacy() 564 { 565 int index = GetIndexIntoMasterTable(DATA, SupportedDevicesInfo); 566 uint8 tableMajor; 567 uint8 tableMinor; 568 uint16 tableSize; 569 uint16 tableOffset; 570 571 if (atom_parse_data_header(gAtomContext, index, &tableSize, 572 &tableMajor, &tableMinor, &tableOffset) != B_OK) { 573 ERROR("%s: unable to parse data header!\n", __func__); 574 return B_ERROR; 575 } 576 577 union atomSupportedDevices { 578 struct _ATOM_SUPPORTED_DEVICES_INFO info; 579 struct _ATOM_SUPPORTED_DEVICES_INFO_2 info_2; 580 struct _ATOM_SUPPORTED_DEVICES_INFO_2d1 info_2d1; 581 }; 582 union atomSupportedDevices* supportedDevices; 583 supportedDevices = (union atomSupportedDevices*) 584 (gAtomContext->bios + tableOffset); 585 586 uint16 deviceSupport 587 = B_LENDIAN_TO_HOST_INT16(supportedDevices->info.usDeviceSupport); 588 589 uint32 maxDevice; 590 591 if (tableMajor > 1) 592 maxDevice = ATOM_MAX_SUPPORTED_DEVICE; 593 else 594 maxDevice = ATOM_MAX_SUPPORTED_DEVICE_INFO; 595 596 uint32 i; 597 uint32 connectorIndex = 0; 598 for (i = 0; i < maxDevice; i++) { 599 600 gConnector[connectorIndex]->valid = false; 601 602 // check if this connector is used 603 if ((deviceSupport & (1 << i)) == 0) 604 continue; 605 606 if (i == ATOM_DEVICE_CV_INDEX) { 607 TRACE("%s: skipping component video\n", 608 __func__); 609 continue; 610 } 611 612 ATOM_CONNECTOR_INFO_I2C ci 613 = supportedDevices->info.asConnInfo[i]; 614 615 gConnector[connectorIndex]->type = kConnectorConvertLegacy[ 616 ci.sucConnectorInfo.sbfAccess.bfConnectorType]; 617 618 if (gConnector[connectorIndex]->type == VIDEO_CONNECTOR_UNKNOWN) { 619 TRACE("%s: skipping unknown connector at %" B_PRId32 620 " of 0x%" B_PRIX8 "\n", __func__, i, 621 ci.sucConnectorInfo.sbfAccess.bfConnectorType); 622 continue; 623 } 624 625 // TODO: give tv unique connector ids 626 627 // Always set CRT1 and CRT2 as VGA, some cards incorrectly set 628 // VGA ports as DVI 629 if (i == ATOM_DEVICE_CRT1_INDEX || i == ATOM_DEVICE_CRT2_INDEX) 630 gConnector[connectorIndex]->type = VIDEO_CONNECTOR_VGA; 631 632 uint8 dac = ci.sucConnectorInfo.sbfAccess.bfAssociatedDAC; 633 uint32 encoderObject = encoder_object_lookup((1 << i), dac); 634 uint32 encoderID = (encoderObject & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; 635 636 gConnector[connectorIndex]->valid = true; 637 gConnector[connectorIndex]->flags = (1 << i); 638 gConnector[connectorIndex]->encoder.valid = true; 639 gConnector[connectorIndex]->encoder.objectID = encoderID; 640 gConnector[connectorIndex]->encoder.type 641 = encoder_type_lookup(encoderID, (1 << i)); 642 643 // TODO: Eval external encoders on legacy connector probe 644 gConnector[connectorIndex]->encoderExternal.valid = false; 645 // encoder_is_external(encoderID); 646 647 connector_attach_gpio_i2c(connectorIndex, ci.sucI2cId.ucAccess); 648 649 pll_limit_probe(&gConnector[connectorIndex]->encoder.pll); 650 651 connectorIndex++; 652 } 653 654 // TODO: combine shared connectors 655 656 if (connectorIndex == 0) { 657 TRACE("%s: zero connectors found using legacy detection\n", __func__); 658 return B_ERROR; 659 } 660 661 return B_OK; 662 } 663 664 665 // r600+ 666 status_t 667 connector_probe() 668 { 669 int index = GetIndexIntoMasterTable(DATA, Object_Header); 670 uint8 tableMajor; 671 uint8 tableMinor; 672 uint16 tableSize; 673 uint16 tableOffset; 674 675 if (atom_parse_data_header(gAtomContext, index, &tableSize, 676 &tableMajor, &tableMinor, &tableOffset) != B_OK) { 677 ERROR("%s: ERROR: parsing data header failed!\n", __func__); 678 return B_ERROR; 679 } 680 681 if (tableMinor < 2) { 682 ERROR("%s: ERROR: table minor version unknown! " 683 "(%" B_PRIu8 ".%" B_PRIu8 ")\n", __func__, tableMajor, tableMinor); 684 return B_ERROR; 685 } 686 687 ATOM_CONNECTOR_OBJECT_TABLE* connectorObject; 688 ATOM_ENCODER_OBJECT_TABLE* encoderObject; 689 ATOM_OBJECT_TABLE* routerObject; 690 ATOM_DISPLAY_OBJECT_PATH_TABLE* pathObject; 691 ATOM_OBJECT_HEADER* objectHeader; 692 693 objectHeader = (ATOM_OBJECT_HEADER*)(gAtomContext->bios + tableOffset); 694 pathObject = (ATOM_DISPLAY_OBJECT_PATH_TABLE*) 695 (gAtomContext->bios + tableOffset 696 + B_LENDIAN_TO_HOST_INT16(objectHeader->usDisplayPathTableOffset)); 697 connectorObject = (ATOM_CONNECTOR_OBJECT_TABLE*) 698 (gAtomContext->bios + tableOffset 699 + B_LENDIAN_TO_HOST_INT16(objectHeader->usConnectorObjectTableOffset)); 700 encoderObject = (ATOM_ENCODER_OBJECT_TABLE*) 701 (gAtomContext->bios + tableOffset 702 + B_LENDIAN_TO_HOST_INT16(objectHeader->usEncoderObjectTableOffset)); 703 routerObject = (ATOM_OBJECT_TABLE*) 704 (gAtomContext->bios + tableOffset 705 + B_LENDIAN_TO_HOST_INT16(objectHeader->usRouterObjectTableOffset)); 706 int deviceSupport = B_LENDIAN_TO_HOST_INT16(objectHeader->usDeviceSupport); 707 708 int pathSize = 0; 709 int32 i = 0; 710 711 TRACE("%s: found %" B_PRIu8 " potential display paths.\n", __func__, 712 pathObject->ucNumOfDispPath); 713 714 uint32 connectorIndex = 0; 715 for (i = 0; i < pathObject->ucNumOfDispPath; i++) { 716 717 if (connectorIndex >= ATOM_MAX_SUPPORTED_DEVICE) 718 continue; 719 720 uint8* address = (uint8*)pathObject->asDispPath; 721 ATOM_DISPLAY_OBJECT_PATH* path; 722 address += pathSize; 723 path = (ATOM_DISPLAY_OBJECT_PATH*)address; 724 pathSize += B_LENDIAN_TO_HOST_INT16(path->usSize); 725 726 uint32 connectorType; 727 uint16 connectorFlags = B_LENDIAN_TO_HOST_INT16(path->usDeviceTag); 728 729 if ((deviceSupport & connectorFlags) != 0) { 730 731 uint16 connectorObjectID 732 = (B_LENDIAN_TO_HOST_INT16(path->usConnObjectId) 733 & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; 734 //uint8 con_obj_num 735 // = (B_LENDIAN_TO_HOST_INT16(path->usConnObjectId) 736 // & ENUM_ID_MASK) >> ENUM_ID_SHIFT; 737 //uint8 con_obj_type 738 // = (B_LENDIAN_TO_HOST_INT16(path->usConnObjectId) 739 // & OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT; 740 741 if (connectorFlags == ATOM_DEVICE_CV_SUPPORT) { 742 TRACE("%s: Path #%" B_PRId32 ": skipping component video.\n", 743 __func__, i); 744 continue; 745 } 746 747 radeon_shared_info &info = *gInfo->shared_info; 748 749 // protect kConnectorConvert 750 if (connectorObjectID >= B_COUNT_OF(kConnectorConvert)) { 751 // This can happen when new atombios revisions introduce 752 // new CONNECTOR_OBJECT_ID_* defines (rare) 753 ERROR("%s: Path #%" B_PRId32 ": Unknown connector object ID!\n", 754 __func__, i); 755 continue; 756 } 757 758 uint16 igpLaneInfo; 759 if ((info.chipsetFlags & CHIP_IGP) != 0) { 760 ERROR("%s: TODO: IGP chip connector detection\n", __func__); 761 // try non-IGP method for now 762 igpLaneInfo = 0; 763 connectorType = kConnectorConvert[connectorObjectID]; 764 } else { 765 igpLaneInfo = 0; 766 connectorType = kConnectorConvert[connectorObjectID]; 767 } 768 769 if (connectorType == VIDEO_CONNECTOR_UNKNOWN) { 770 ERROR("%s: Path #%" B_PRId32 ": skipping unknown connector.\n", 771 __func__, i); 772 continue; 773 } 774 775 connector_info* connector = gConnector[connectorIndex]; 776 777 int32 j; 778 for (j = 0; j < ((B_LENDIAN_TO_HOST_INT16(path->usSize) - 8) / 2); 779 j++) { 780 //uint16 grph_obj_id 781 // = (B_LENDIAN_TO_HOST_INT16(path->usGraphicObjIds[j]) 782 // & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; 783 //uint8 grph_obj_num 784 // = (B_LENDIAN_TO_HOST_INT16(path->usGraphicObjIds[j]) & 785 // ENUM_ID_MASK) >> ENUM_ID_SHIFT; 786 uint8 graphicObjectType 787 = (B_LENDIAN_TO_HOST_INT16(path->usGraphicObjIds[j]) & 788 OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT; 789 790 if (graphicObjectType == GRAPH_OBJECT_TYPE_ENCODER) { 791 // Found an encoder 792 int32 k; 793 for (k = 0; k < encoderObject->ucNumberOfObjects; k++) { 794 uint16 encoderObjectRaw 795 = B_LENDIAN_TO_HOST_INT16( 796 encoderObject->asObjects[k].usObjectID); 797 if (B_LENDIAN_TO_HOST_INT16(path->usGraphicObjIds[j]) 798 == encoderObjectRaw) { 799 ATOM_COMMON_RECORD_HEADER* record 800 = (ATOM_COMMON_RECORD_HEADER*) 801 ((uint16*)gAtomContext->bios + tableOffset 802 + B_LENDIAN_TO_HOST_INT16( 803 encoderObject->asObjects[k].usRecordOffset)); 804 ATOM_ENCODER_CAP_RECORD* capRecord; 805 uint16 caps = 0; 806 while (record->ucRecordSize > 0 807 && record->ucRecordType > 0 808 && record->ucRecordType 809 <= ATOM_MAX_OBJECT_RECORD_NUMBER) { 810 switch (record->ucRecordType) { 811 case ATOM_ENCODER_CAP_RECORD_TYPE: 812 capRecord = (ATOM_ENCODER_CAP_RECORD*) 813 record; 814 caps = B_LENDIAN_TO_HOST_INT16( 815 capRecord->usEncoderCap); 816 break; 817 } 818 record = (ATOM_COMMON_RECORD_HEADER*) 819 ((char*)record + record->ucRecordSize); 820 } 821 822 uint32 encoderID 823 = (encoderObjectRaw & OBJECT_ID_MASK) 824 >> OBJECT_ID_SHIFT; 825 826 uint32 encoderType = encoder_type_lookup(encoderID, 827 connectorFlags); 828 829 if (encoderType == VIDEO_ENCODER_NONE) { 830 ERROR("%s: Path #%" B_PRId32 ":" 831 "skipping unknown encoder.\n", 832 __func__, i); 833 continue; 834 } 835 836 encoder_info* encoder; 837 838 // External encoders are behind DVO or UNIPHY 839 if (encoder_is_external(encoderID)) { 840 encoder = &connector->encoderExternal; 841 encoder->isExternal = true; 842 encoder->isDPBridge 843 = encoder_is_dp_bridge(encoderID); 844 } else { 845 encoder = &connector->encoder; 846 encoder->isExternal = false; 847 encoder->isDPBridge = false; 848 } 849 850 // Set up found connector encoder generics 851 encoder->valid = true; 852 encoder->capabilities = caps; 853 encoder->objectID = encoderID; 854 encoder->type = encoderType; 855 encoder->linkEnumeration 856 = (encoderObjectRaw & ENUM_ID_MASK) 857 >> ENUM_ID_SHIFT; 858 pll_limit_probe(&encoder->pll); 859 } 860 } 861 // END if object is encoder 862 } else if (graphicObjectType == GRAPH_OBJECT_TYPE_ROUTER) { 863 int32 k; 864 for (k = 0; k < routerObject->ucNumberOfObjects; k++) { 865 uint16 routerObjectID 866 = B_LENDIAN_TO_HOST_INT16(routerObject->asObjects[k].usObjectID); 867 if (B_LENDIAN_TO_HOST_INT16(path->usGraphicObjIds[j]) == routerObjectID) { 868 ATOM_COMMON_RECORD_HEADER* record = (ATOM_COMMON_RECORD_HEADER*) 869 ((uint16*)gAtomContext->bios + tableOffset 870 + B_LENDIAN_TO_HOST_INT16( 871 routerObject->asObjects[k].usRecordOffset)); 872 ATOM_I2C_RECORD* i2cRecord; 873 ATOM_I2C_ID_CONFIG_ACCESS* i2cConfig; 874 ATOM_ROUTER_DDC_PATH_SELECT_RECORD* ddcPath; 875 ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD* cdPath; 876 ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT* routerConnTable 877 = (ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT *) 878 ((uint16*)gAtomContext->bios + tableOffset 879 + B_LENDIAN_TO_HOST_INT16( 880 routerObject->asObjects[k].usSrcDstTableOffset)); 881 uint8* destObjCount = (uint8*)((uint8*)routerConnTable + 1 882 + (routerConnTable->ucNumberOfSrc * 2)); 883 uint16 *dstObjs = (uint16 *)(destObjCount + 1); 884 885 int enumId; 886 router_info* router = &connector->router; 887 router->objectID = routerObjectID; 888 for (enumId = 0; enumId < (*destObjCount); enumId++) { 889 if (B_LENDIAN_TO_HOST_INT16(path->usConnObjectId) 890 == B_LENDIAN_TO_HOST_INT16(dstObjs[enumId])) 891 break; 892 } 893 while (record->ucRecordSize > 0 && 894 record->ucRecordType > 0 && 895 record->ucRecordType <= ATOM_MAX_OBJECT_RECORD_NUMBER) { 896 switch (record->ucRecordType) { 897 case ATOM_I2C_RECORD_TYPE: 898 i2cRecord = (ATOM_I2C_RECORD*)record; 899 i2cConfig 900 = (ATOM_I2C_ID_CONFIG_ACCESS*)&i2cRecord->sucI2cId; 901 connector_attach_gpio_router(connectorIndex, 902 i2cConfig->ucAccess); 903 router->i2cAddr = i2cRecord->ucI2CAddr >> 1; // ?? 904 break; 905 case ATOM_ROUTER_DDC_PATH_SELECT_RECORD_TYPE: 906 ddcPath = (ATOM_ROUTER_DDC_PATH_SELECT_RECORD*)record; 907 router->ddcValid = true; 908 router->ddcMuxType = ddcPath->ucMuxType; 909 router->ddcMuxControlPin = ddcPath->ucMuxControlPin; 910 router->ddcMuxState = ddcPath->ucMuxState[enumId]; 911 break; 912 case ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD_TYPE: 913 cdPath 914 = (ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD *)record; 915 router->cdValid = true; 916 router->cdMuxType = cdPath->ucMuxType; 917 router->cdMuxControlPin = cdPath->ucMuxControlPin; 918 router->cdMuxState = cdPath->ucMuxState[enumId]; 919 break; 920 } 921 922 // move to next record 923 record = (ATOM_COMMON_RECORD_HEADER*) 924 ((char *)record + record->ucRecordSize); 925 } 926 } 927 } 928 } // END if object is router 929 } 930 931 // Set up information buses such as ddc 932 if (((connectorFlags & ATOM_DEVICE_TV_SUPPORT) == 0) 933 && (connectorFlags & ATOM_DEVICE_CV_SUPPORT) == 0) { 934 for (j = 0; j < connectorObject->ucNumberOfObjects; j++) { 935 if (B_LENDIAN_TO_HOST_INT16(path->usConnObjectId) 936 == B_LENDIAN_TO_HOST_INT16( 937 connectorObject->asObjects[j].usObjectID)) { 938 ATOM_COMMON_RECORD_HEADER* record 939 = (ATOM_COMMON_RECORD_HEADER*)(gAtomContext->bios 940 + tableOffset + B_LENDIAN_TO_HOST_INT16( 941 connectorObject->asObjects[j].usRecordOffset)); 942 while (record->ucRecordSize > 0 943 && record->ucRecordType > 0 944 && record->ucRecordType 945 <= ATOM_MAX_OBJECT_RECORD_NUMBER) { 946 ATOM_I2C_RECORD* i2cRecord; 947 ATOM_I2C_ID_CONFIG_ACCESS* i2cConfig; 948 ATOM_HPD_INT_RECORD* hpdRecord; 949 950 switch (record->ucRecordType) { 951 case ATOM_I2C_RECORD_TYPE: 952 i2cRecord 953 = (ATOM_I2C_RECORD*)record; 954 i2cConfig 955 = (ATOM_I2C_ID_CONFIG_ACCESS*) 956 &i2cRecord->sucI2cId; 957 connector_attach_gpio_i2c(connectorIndex, 958 i2cConfig->ucAccess); 959 break; 960 case ATOM_HPD_INT_RECORD_TYPE: 961 hpdRecord = (ATOM_HPD_INT_RECORD*)record; 962 connector_attach_gpio_hpd(connectorIndex, 963 hpdRecord->ucHPDIntGPIOID); 964 break; 965 } 966 967 // move to next record 968 record = (ATOM_COMMON_RECORD_HEADER*) 969 ((char*)record + record->ucRecordSize); 970 } 971 } 972 } 973 } 974 975 connector->valid = true; 976 connector->flags = connectorFlags; 977 connector->type = connectorType; 978 connector->objectID = connectorObjectID; 979 980 connectorIndex++; 981 } // END for each valid connector 982 } // end for each display path 983 984 return B_OK; 985 } 986 987 988 bool 989 connector_is_dp(uint32 connectorIndex) 990 { 991 connector_info* connector = gConnector[connectorIndex]; 992 993 // Traditional DisplayPort connector 994 if (connector->type == VIDEO_CONNECTOR_DP 995 || connector->type == VIDEO_CONNECTOR_EDP) { 996 return true; 997 } 998 999 // DisplayPort bridge on external encoder 1000 if (connector->encoderExternal.valid == true 1001 && connector->encoderExternal.isDPBridge == true) { 1002 return true; 1003 } 1004 1005 return false; 1006 } 1007 1008 1009 void 1010 debug_connectors() 1011 { 1012 ERROR("Currently detected connectors=============\n"); 1013 for (uint32 id = 0; id < ATOM_MAX_SUPPORTED_DEVICE; id++) { 1014 if (gConnector[id]->valid == true) { 1015 uint32 connectorType = gConnector[id]->type; 1016 uint16 i2cPinIndex = gConnector[id]->i2cPinIndex; 1017 uint16 hpdPinIndex = gConnector[id]->hpdPinIndex; 1018 1019 ERROR("Connector #%" B_PRIu32 ")\n", id); 1020 ERROR(" + connector: %s\n", 1021 get_connector_name(connectorType)); 1022 ERROR(" + i2c gpio table id: %" B_PRIu16 "\n", i2cPinIndex); 1023 ERROR(" - gpio hw pin: 0x%" B_PRIX32 "\n", 1024 gGPIOInfo[i2cPinIndex]->hwPin); 1025 ERROR(" - gpio valid: %s\n", 1026 gGPIOInfo[i2cPinIndex]->valid ? "true" : "false"); 1027 ERROR(" - i2c valid: %s\n", 1028 gGPIOInfo[i2cPinIndex]->i2c.valid ? "true" : "false"); 1029 1030 // hot plug detection info 1031 ERROR(" + hpd gpio table id: %" B_PRIu16 "\n", hpdPinIndex); 1032 ERROR(" - gpio hw pin: 0x%" B_PRIX32 "\n", 1033 gGPIOInfo[hpdPinIndex]->hwPin); 1034 ERROR(" - gpio valid: %s\n", 1035 gGPIOInfo[hpdPinIndex]->valid ? "true" : "false"); 1036 1037 // router info 1038 router_info* router = &gConnector[id]->router; 1039 ERROR(" + router gpio table id: %" B_PRIu16 "\n", router->i2cPinIndex); 1040 ERROR(" + router (ddc): %s\n", 1041 router->ddcValid ? "true" : "false"); 1042 if (router->ddcValid) { 1043 ERROR(" - mux type: 0x%" B_PRIX8 "\n", router->ddcMuxType); 1044 ERROR(" - mux pin: 0x%" B_PRIX8 "\n", router->ddcMuxControlPin); 1045 ERROR(" - mux state: 0x%" B_PRIX8 "\n", router->ddcMuxState); 1046 } 1047 ERROR(" + router (c/d): %s\n", 1048 router->cdValid ? "true" : "false"); 1049 if (router->cdValid) { 1050 ERROR(" - mux type: 0x%" B_PRIX8 "\n", router->cdMuxType); 1051 ERROR(" - mux pin: 0x%" B_PRIX8 "\n", router->cdMuxControlPin); 1052 ERROR(" - mux state: 0x%" B_PRIX8 "\n", router->cdMuxState); 1053 } 1054 1055 // encoder info 1056 encoder_info* encoder = &gConnector[id]->encoder; 1057 ERROR(" + encoder: %s\n", 1058 get_encoder_name(encoder->type)); 1059 ERROR(" - id: %" B_PRIu16 "\n", encoder->objectID); 1060 ERROR(" - type: %s\n", 1061 encoder_name_lookup(encoder->objectID)); 1062 ERROR(" - capabilities: 0x%" B_PRIX32 "\n", 1063 encoder->capabilities); 1064 ERROR(" - enumeration: %" B_PRIu32 "\n", 1065 encoder->linkEnumeration); 1066 1067 encoder = &gConnector[id]->encoderExternal; 1068 1069 ERROR(" - is bridge: %s\n", 1070 encoder->valid ? "true" : "false"); 1071 1072 if (!encoder->valid) 1073 ERROR(" + external encoder: none\n"); 1074 else { 1075 ERROR(" + external encoder: %s\n", 1076 get_encoder_name(encoder->type)); 1077 ERROR(" - valid: true\n"); 1078 ERROR(" - id: %" B_PRIu16 "\n", 1079 encoder->objectID); 1080 ERROR(" - type: %s\n", 1081 encoder_name_lookup(encoder->objectID)); 1082 ERROR(" - enumeration: %" B_PRIu32 "\n", 1083 encoder->linkEnumeration); 1084 } 1085 1086 uint32 connectorFlags = gConnector[id]->flags; 1087 bool flags = false; 1088 ERROR(" + flags:\n"); 1089 if ((connectorFlags & ATOM_DEVICE_CRT1_SUPPORT) != 0) { 1090 ERROR(" * device CRT1 support\n"); 1091 flags = true; 1092 } 1093 if ((connectorFlags & ATOM_DEVICE_CRT2_SUPPORT) != 0) { 1094 ERROR(" * device CRT2 support\n"); 1095 flags = true; 1096 } 1097 if ((connectorFlags & ATOM_DEVICE_LCD1_SUPPORT) != 0) { 1098 ERROR(" * device LCD1 support\n"); 1099 flags = true; 1100 } 1101 if ((connectorFlags & ATOM_DEVICE_LCD2_SUPPORT) != 0) { 1102 ERROR(" * device LCD2 support\n"); 1103 flags = true; 1104 } 1105 if ((connectorFlags & ATOM_DEVICE_TV1_SUPPORT) != 0) { 1106 ERROR(" * device TV1 support\n"); 1107 flags = true; 1108 } 1109 if ((connectorFlags & ATOM_DEVICE_CV_SUPPORT) != 0) { 1110 ERROR(" * device CV support\n"); 1111 flags = true; 1112 } 1113 if ((connectorFlags & ATOM_DEVICE_DFP1_SUPPORT) != 0) { 1114 ERROR(" * device DFP1 support\n"); 1115 flags = true; 1116 } 1117 if ((connectorFlags & ATOM_DEVICE_DFP2_SUPPORT) != 0) { 1118 ERROR(" * device DFP2 support\n"); 1119 flags = true; 1120 } 1121 if ((connectorFlags & ATOM_DEVICE_DFP3_SUPPORT) != 0) { 1122 ERROR(" * device DFP3 support\n"); 1123 flags = true; 1124 } 1125 if ((connectorFlags & ATOM_DEVICE_DFP4_SUPPORT) != 0) { 1126 ERROR(" * device DFP4 support\n"); 1127 flags = true; 1128 } 1129 if ((connectorFlags & ATOM_DEVICE_DFP5_SUPPORT) != 0) { 1130 ERROR(" * device DFP5 support\n"); 1131 flags = true; 1132 } 1133 if ((connectorFlags & ATOM_DEVICE_DFP6_SUPPORT) != 0) { 1134 ERROR(" * device DFP6 support\n"); 1135 flags = true; 1136 } 1137 if (flags == false) 1138 ERROR(" * no known flags\n"); 1139 } 1140 } 1141 ERROR("==========================================\n"); 1142 } 1143