From 72f6869e9e21913556544612ea275112ad416b5c Mon Sep 17 00:00:00 2001 From: Alexander von Gluck IV Date: Thu, 15 Mar 2012 14:46:27 -0500 Subject: [PATCH] radeon_hd: Add support for external encoders * Some encoders are bridges (DVO) and some encoders can act like bridges (UNIPHY). Probe for encoders further out in the display path and set them up properly. * Debug output support for external encoders * Fix cases where we should use external encoder information vs main encoder info. --- .../accelerants/radeon_hd/accelerant.h | 1 + .../accelerants/radeon_hd/connector.cpp | 139 +++++++++++------- src/add-ons/accelerants/radeon_hd/encoder.cpp | 38 ++--- 3 files changed, 106 insertions(+), 72 deletions(-) diff --git a/src/add-ons/accelerants/radeon_hd/accelerant.h b/src/add-ons/accelerants/radeon_hd/accelerant.h index 6812da2139..ddc467a847 100644 --- a/src/add-ons/accelerants/radeon_hd/accelerant.h +++ b/src/add-ons/accelerants/radeon_hd/accelerant.h @@ -167,6 +167,7 @@ typedef struct { uint32 lvdsFlags; uint16 gpioID; struct encoder_info encoder; + struct encoder_info encoderExternal; // TODO struct radeon_hpd hpd; } connector_info; diff --git a/src/add-ons/accelerants/radeon_hd/connector.cpp b/src/add-ons/accelerants/radeon_hd/connector.cpp index 0473acfe06..a89380b4e0 100644 --- a/src/add-ons/accelerants/radeon_hd/connector.cpp +++ b/src/add-ons/accelerants/radeon_hd/connector.cpp @@ -445,8 +445,10 @@ connector_probe_legacy() gConnector[connectorIndex]->encoder.objectID = encoderID; gConnector[connectorIndex]->encoder.type = encoder_type_lookup(encoderID, (1 << i)); - gConnector[connectorIndex]->encoder.isExternal - = encoder_is_external(encoderID); + + // TODO: Eval external encoders on legacy connector probe + gConnector[connectorIndex]->encoderExternal.valid = false; + // encoder_is_external(encoderID); connector_attach_gpio(connectorIndex, ci.sucI2cId.ucAccess); @@ -584,7 +586,6 @@ connector_probe() if (graphicObjectType == GRAPH_OBJECT_TYPE_ENCODER) { // Found an encoder - // TODO: it may be possible to have more then one encoder int32 k; for (k = 0; k < encoderObject->ucNumberOfObjects; k++) { uint16 encoderObjectRaw @@ -629,20 +630,42 @@ connector_probe() continue; } - // Set up found connector - connector->encoder.valid = true; - connector->encoder.flags = connectorFlags; - connector->encoder.objectID = encoderID; - connector->encoder.type = encoderType; - connector->encoder.linkEnumeration - = (encoderObjectRaw & ENUM_ID_MASK) - >> ENUM_ID_SHIFT; - connector->encoder.isExternal - = encoder_is_external(encoderID); - connector->encoder.isDPBridge - = encoder_is_dp_bridge(encoderID); + // External encoders are behind DVO or UNIPHY + if(encoder_is_external(encoderID)) { + encoder_info* encoder + = &connector->encoderExternal; + encoder->isExternal = true; - pll_limit_probe(&connector->encoder.pll); + // Set up found connector + encoder->valid = true; + encoder->flags = connectorFlags; + encoder->objectID = encoderID; + encoder->type = encoderType; + encoder->linkEnumeration + = (encoderObjectRaw & ENUM_ID_MASK) + >> ENUM_ID_SHIFT; + encoder->isDPBridge + = encoder_is_dp_bridge(encoderID); + + pll_limit_probe(&encoder->pll); + } else { + encoder_info* encoder + = &connector->encoder; + encoder->isExternal = false; + + // Set up found connector + encoder->valid = true; + encoder->flags = connectorFlags; + encoder->objectID = encoderID; + encoder->type = encoderType; + encoder->linkEnumeration + = (encoderObjectRaw & ENUM_ID_MASK) + >> ENUM_ID_SHIFT; + encoder->isDPBridge + = encoder_is_dp_bridge(encoderID); + + pll_limit_probe(&encoder->pll); + } } } // END if object is encoder @@ -728,90 +751,96 @@ debug_connectors() for (uint32 id = 0; id < ATOM_MAX_SUPPORTED_DEVICE; id++) { if (gConnector[id]->valid == true) { uint32 connectorType = gConnector[id]->type; - uint32 encoderType = gConnector[id]->encoder.type; - uint16 encoderID = gConnector[id]->encoder.objectID; - uint32 encoderFlags = gConnector[id]->encoder.flags; uint16 gpioID = gConnector[id]->gpioID; ERROR("Connector #%" B_PRIu32 ")\n", id); - ERROR(" + connector: %s\n", get_connector_name(connectorType)); - ERROR(" + gpio table id: %" B_PRIu16 "\n", gpioID); - ERROR(" + gpio hw pin: 0x%" B_PRIX32 "\n", + ERROR(" + connector: %s\n", get_connector_name(connectorType)); + ERROR(" + gpio table id: %" B_PRIu16 "\n", gpioID); + ERROR(" + gpio hw pin: 0x%" B_PRIX32 "\n", gGPIOInfo[gpioID]->hwPin); - ERROR(" + gpio valid: %s\n", + ERROR(" + gpio valid: %s\n", gGPIOInfo[gpioID]->valid ? "true" : "false"); - ERROR(" + encoder: %s\n", get_encoder_name(encoderType)); - ERROR(" - id: %" B_PRIu16 "\n", encoderID); - ERROR(" - type: %s\n", - encoder_name_lookup(encoderID)); - ERROR(" - enumeration: %" B_PRIu32 "\n", - gConnector[id]->encoder.linkEnumeration); - bool attribute = false; - ERROR(" - attributes:\n"); - if (gConnector[id]->encoder.isExternal == true) { - attribute = true; - ERROR(" * is external\n"); - } - if (gConnector[id]->encoder.isDPBridge == true) { - attribute = true; - ERROR(" * is DisplayPort bridge\n"); - } - if (attribute == false) - ERROR(" * no extra attributes\n"); + encoder_info* encoder = &gConnector[id]->encoder; + ERROR(" + encoder: %s\n", get_encoder_name(encoder->type)); + ERROR(" - id: %" B_PRIu16 "\n", encoder->objectID); + ERROR(" - type: %s\n", + encoder_name_lookup(encoder->objectID)); + ERROR(" - enumeration: %" B_PRIu32 "\n", + encoder->linkEnumeration); + encoder = &gConnector[id]->encoderExternal; + + ERROR(" - is bridge: %s\n", + encoder->valid ? "true" : "false"); + + if (!encoder->valid) + ERROR(" + external encoder: none\n"); + else { + ERROR(" + external encoder: %s\n", + get_encoder_name(encoder->type)); + ERROR(" - valid: true\n"); + ERROR(" - id: %" B_PRIu16 "\n", + encoder->objectID); + ERROR(" - type: %s\n", + encoder_name_lookup(encoder->objectID)); + ERROR(" - enumeration: %" B_PRIu32 "\n", + encoder->linkEnumeration); + } + + uint32 encoderFlags = gConnector[id]->encoder.flags; bool flags = false; - ERROR(" - flags:\n"); + ERROR(" + flags:\n"); if ((encoderFlags & ATOM_DEVICE_CRT1_SUPPORT) != 0) { - ERROR(" * device CRT1 support\n"); + ERROR(" * device CRT1 support\n"); flags = true; } if ((encoderFlags & ATOM_DEVICE_CRT2_SUPPORT) != 0) { - ERROR(" * device CRT2 support\n"); + ERROR(" * device CRT2 support\n"); flags = true; } if ((encoderFlags & ATOM_DEVICE_LCD1_SUPPORT) != 0) { - ERROR(" * device LCD1 support\n"); + ERROR(" * device LCD1 support\n"); flags = true; } if ((encoderFlags & ATOM_DEVICE_LCD2_SUPPORT) != 0) { - ERROR(" * device LCD2 support\n"); + ERROR(" * device LCD2 support\n"); flags = true; } if ((encoderFlags & ATOM_DEVICE_TV1_SUPPORT) != 0) { - ERROR(" * device TV1 support\n"); + ERROR(" * device TV1 support\n"); flags = true; } if ((encoderFlags & ATOM_DEVICE_CV_SUPPORT) != 0) { - ERROR(" * device CV support\n"); + ERROR(" * device CV support\n"); flags = true; } if ((encoderFlags & ATOM_DEVICE_DFP1_SUPPORT) != 0) { - ERROR(" * device DFP1 support\n"); + ERROR(" * device DFP1 support\n"); flags = true; } if ((encoderFlags & ATOM_DEVICE_DFP2_SUPPORT) != 0) { - ERROR(" * device DFP2 support\n"); + ERROR(" * device DFP2 support\n"); flags = true; } if ((encoderFlags & ATOM_DEVICE_DFP3_SUPPORT) != 0) { - ERROR(" * device DFP3 support\n"); + ERROR(" * device DFP3 support\n"); flags = true; } if ((encoderFlags & ATOM_DEVICE_DFP4_SUPPORT) != 0) { - ERROR(" * device DFP4 support\n"); + ERROR(" * device DFP4 support\n"); flags = true; } if ((encoderFlags & ATOM_DEVICE_DFP5_SUPPORT) != 0) { - ERROR(" * device DFP5 support\n"); + ERROR(" * device DFP5 support\n"); flags = true; } if ((encoderFlags & ATOM_DEVICE_DFP6_SUPPORT) != 0) { - ERROR(" * device DFP6 support\n"); + ERROR(" * device DFP6 support\n"); flags = true; } if (flags == false) - ERROR(" * no known flags\n"); + ERROR(" * no known flags\n"); } } ERROR("==========================================\n"); diff --git a/src/add-ons/accelerants/radeon_hd/encoder.cpp b/src/add-ons/accelerants/radeon_hd/encoder.cpp index 69d9c6f735..6600055e12 100644 --- a/src/add-ons/accelerants/radeon_hd/encoder.cpp +++ b/src/add-ons/accelerants/radeon_hd/encoder.cpp @@ -55,10 +55,11 @@ encoder_init() break; } - if ((info.chipsetFlags & CHIP_APU) != 0 - && gConnector[id]->encoder.isExternal) { - encoder_external_setup(id, 0, - EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT); + if ((info.chipsetFlags & CHIP_APU) != 0) { + if (gConnector[id]->encoderExternal.valid == true) { + encoder_external_setup(id, 0, + EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT); + } } } } @@ -352,7 +353,7 @@ encoder_mode_set(uint8 id, uint32 pixelClock) break; } - if (gConnector[connectorIndex]->encoder.isExternal == true) { + if (gConnector[connectorIndex]->encoderExternal.valid == true) { if ((info.chipsetFlags & CHIP_APU) != 0) { // aka DCE 4.1 encoder_external_setup(connectorIndex, pixelClock, @@ -709,6 +710,15 @@ encoder_external_setup(uint32 connectorIndex, uint32 pixelClock, int command) { TRACE("%s\n", __func__); + encoder_info* encoder + = &gConnector[connectorIndex]->encoderExternal; + + if (encoder->valid != true) { + ERROR("%s: connector %" B_PRIu32 " doesn't have a valid " + "external encoder!", __func__, connectorIndex); + return B_ERROR; + } + uint8 tableMajor; uint8 tableMinor; @@ -790,8 +800,8 @@ encoder_external_setup(uint32 connectorIndex, uint32 pixelClock, int command) args.v3.sExtEncoder.ucLaneNum = 4; } - uint16 encoderFlags - = gConnector[connectorIndex]->encoder.flags; + uint16 encoderFlags = encoder->flags; + switch ((encoderFlags & ENUM_ID_MASK) >> ENUM_ID_SHIFT) { case GRAPH_OBJECT_ENUM_ID1: TRACE("%s: external encoder 1\n", __func__); @@ -909,9 +919,7 @@ encoder_analog_load_detect(uint32 connectorIndex) { TRACE("%s\n", __func__); - uint32 encoderID = gConnector[connectorIndex]->encoder.objectID; - - if (encoder_is_external(encoderID)) + if (gConnector[connectorIndex]->encoderExternal.valid == true) return encoder_dig_load_detect(connectorIndex); return encoder_dac_load_detect(connectorIndex); @@ -1074,12 +1082,8 @@ transmitter_dig_setup(uint32 connectorIndex, uint32 pixelClock, index = GetIndexIntoMasterTable(COMMAND, LVTMATransmitterControl); break; default: - // Multiple encoders can be wired to a single connector - // An example is UNIPHY -> DP -> TRAVIS -> LVDS - ERROR("%s: BUG: guessing UNIPHY as this isn't a dig encoder!\n", - __func__); - index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl); - break; + ERROR("%s: BUG: dig setup run on non-dig encoder!\n", __func__); + return B_ERROR; } if (index < 0) { @@ -1116,7 +1120,7 @@ transmitter_dig_setup(uint32 connectorIndex, uint32 pixelClock, pll_info* pll = &gConnector[connectorIndex]->encoder.pll; bool isDP = connector_is_dp(connectorIndex); - bool linkB = gConnector[connectorIndex]->encoder.linkEnumeration + bool linkB = gConnector[connectorIndex]->encoderExternal.linkEnumeration == GRAPH_OBJECT_ENUM_ID2 ? true : false; uint8 dpClock = 0;