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.
This commit is contained in:
Alexander von Gluck IV
2012-03-15 14:47:13 -05:00
parent ced3b516ea
commit 72f6869e9e
3 changed files with 106 additions and 72 deletions
@@ -167,6 +167,7 @@ typedef struct {
uint32 lvdsFlags; uint32 lvdsFlags;
uint16 gpioID; uint16 gpioID;
struct encoder_info encoder; struct encoder_info encoder;
struct encoder_info encoderExternal;
// TODO struct radeon_hpd hpd; // TODO struct radeon_hpd hpd;
} connector_info; } connector_info;
+61 -32
View File
@@ -445,8 +445,10 @@ connector_probe_legacy()
gConnector[connectorIndex]->encoder.objectID = encoderID; gConnector[connectorIndex]->encoder.objectID = encoderID;
gConnector[connectorIndex]->encoder.type gConnector[connectorIndex]->encoder.type
= encoder_type_lookup(encoderID, (1 << i)); = 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); connector_attach_gpio(connectorIndex, ci.sucI2cId.ucAccess);
@@ -584,7 +586,6 @@ connector_probe()
if (graphicObjectType == GRAPH_OBJECT_TYPE_ENCODER) { if (graphicObjectType == GRAPH_OBJECT_TYPE_ENCODER) {
// Found an encoder // Found an encoder
// TODO: it may be possible to have more then one encoder
int32 k; int32 k;
for (k = 0; k < encoderObject->ucNumberOfObjects; k++) { for (k = 0; k < encoderObject->ucNumberOfObjects; k++) {
uint16 encoderObjectRaw uint16 encoderObjectRaw
@@ -629,20 +630,42 @@ connector_probe()
continue; continue;
} }
// External encoders are behind DVO or UNIPHY
if(encoder_is_external(encoderID)) {
encoder_info* encoder
= &connector->encoderExternal;
encoder->isExternal = true;
// Set up found connector // Set up found connector
connector->encoder.valid = true; encoder->valid = true;
connector->encoder.flags = connectorFlags; encoder->flags = connectorFlags;
connector->encoder.objectID = encoderID; encoder->objectID = encoderID;
connector->encoder.type = encoderType; encoder->type = encoderType;
connector->encoder.linkEnumeration encoder->linkEnumeration
= (encoderObjectRaw & ENUM_ID_MASK) = (encoderObjectRaw & ENUM_ID_MASK)
>> ENUM_ID_SHIFT; >> ENUM_ID_SHIFT;
connector->encoder.isExternal encoder->isDPBridge
= encoder_is_external(encoderID);
connector->encoder.isDPBridge
= encoder_is_dp_bridge(encoderID); = encoder_is_dp_bridge(encoderID);
pll_limit_probe(&connector->encoder.pll); 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 // END if object is encoder
@@ -728,9 +751,6 @@ debug_connectors()
for (uint32 id = 0; id < ATOM_MAX_SUPPORTED_DEVICE; id++) { for (uint32 id = 0; id < ATOM_MAX_SUPPORTED_DEVICE; id++) {
if (gConnector[id]->valid == true) { if (gConnector[id]->valid == true) {
uint32 connectorType = gConnector[id]->type; 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; uint16 gpioID = gConnector[id]->gpioID;
ERROR("Connector #%" B_PRIu32 ")\n", id); ERROR("Connector #%" B_PRIu32 ")\n", id);
@@ -740,28 +760,37 @@ debug_connectors()
gGPIOInfo[gpioID]->hwPin); gGPIOInfo[gpioID]->hwPin);
ERROR(" + gpio valid: %s\n", ERROR(" + gpio valid: %s\n",
gGPIOInfo[gpioID]->valid ? "true" : "false"); gGPIOInfo[gpioID]->valid ? "true" : "false");
ERROR(" + encoder: %s\n", get_encoder_name(encoderType));
ERROR(" - id: %" B_PRIu16 "\n", encoderID); 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", ERROR(" - type: %s\n",
encoder_name_lookup(encoderID)); encoder_name_lookup(encoder->objectID));
ERROR(" - enumeration: %" B_PRIu32 "\n", ERROR(" - enumeration: %" B_PRIu32 "\n",
gConnector[id]->encoder.linkEnumeration); encoder->linkEnumeration);
bool attribute = false; encoder = &gConnector[id]->encoderExternal;
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");
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; bool flags = false;
ERROR(" - flags:\n"); ERROR(" + flags:\n");
if ((encoderFlags & ATOM_DEVICE_CRT1_SUPPORT) != 0) { if ((encoderFlags & ATOM_DEVICE_CRT1_SUPPORT) != 0) {
ERROR(" * device CRT1 support\n"); ERROR(" * device CRT1 support\n");
flags = true; flags = true;
+19 -15
View File
@@ -55,12 +55,13 @@ encoder_init()
break; break;
} }
if ((info.chipsetFlags & CHIP_APU) != 0 if ((info.chipsetFlags & CHIP_APU) != 0) {
&& gConnector[id]->encoder.isExternal) { if (gConnector[id]->encoderExternal.valid == true) {
encoder_external_setup(id, 0, encoder_external_setup(id, 0,
EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT); EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT);
} }
} }
}
} }
@@ -352,7 +353,7 @@ encoder_mode_set(uint8 id, uint32 pixelClock)
break; break;
} }
if (gConnector[connectorIndex]->encoder.isExternal == true) { if (gConnector[connectorIndex]->encoderExternal.valid == true) {
if ((info.chipsetFlags & CHIP_APU) != 0) { if ((info.chipsetFlags & CHIP_APU) != 0) {
// aka DCE 4.1 // aka DCE 4.1
encoder_external_setup(connectorIndex, pixelClock, encoder_external_setup(connectorIndex, pixelClock,
@@ -709,6 +710,15 @@ encoder_external_setup(uint32 connectorIndex, uint32 pixelClock, int command)
{ {
TRACE("%s\n", __func__); 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 tableMajor;
uint8 tableMinor; uint8 tableMinor;
@@ -790,8 +800,8 @@ encoder_external_setup(uint32 connectorIndex, uint32 pixelClock, int command)
args.v3.sExtEncoder.ucLaneNum = 4; args.v3.sExtEncoder.ucLaneNum = 4;
} }
uint16 encoderFlags uint16 encoderFlags = encoder->flags;
= gConnector[connectorIndex]->encoder.flags;
switch ((encoderFlags & ENUM_ID_MASK) >> ENUM_ID_SHIFT) { switch ((encoderFlags & ENUM_ID_MASK) >> ENUM_ID_SHIFT) {
case GRAPH_OBJECT_ENUM_ID1: case GRAPH_OBJECT_ENUM_ID1:
TRACE("%s: external encoder 1\n", __func__); TRACE("%s: external encoder 1\n", __func__);
@@ -909,9 +919,7 @@ encoder_analog_load_detect(uint32 connectorIndex)
{ {
TRACE("%s\n", __func__); TRACE("%s\n", __func__);
uint32 encoderID = gConnector[connectorIndex]->encoder.objectID; if (gConnector[connectorIndex]->encoderExternal.valid == true)
if (encoder_is_external(encoderID))
return encoder_dig_load_detect(connectorIndex); return encoder_dig_load_detect(connectorIndex);
return encoder_dac_load_detect(connectorIndex); return encoder_dac_load_detect(connectorIndex);
@@ -1074,12 +1082,8 @@ transmitter_dig_setup(uint32 connectorIndex, uint32 pixelClock,
index = GetIndexIntoMasterTable(COMMAND, LVTMATransmitterControl); index = GetIndexIntoMasterTable(COMMAND, LVTMATransmitterControl);
break; break;
default: default:
// Multiple encoders can be wired to a single connector ERROR("%s: BUG: dig setup run on non-dig encoder!\n", __func__);
// An example is UNIPHY -> DP -> TRAVIS -> LVDS return B_ERROR;
ERROR("%s: BUG: guessing UNIPHY as this isn't a dig encoder!\n",
__func__);
index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl);
break;
} }
if (index < 0) { if (index < 0) {
@@ -1116,7 +1120,7 @@ transmitter_dig_setup(uint32 connectorIndex, uint32 pixelClock,
pll_info* pll = &gConnector[connectorIndex]->encoder.pll; pll_info* pll = &gConnector[connectorIndex]->encoder.pll;
bool isDP = connector_is_dp(connectorIndex); bool isDP = connector_is_dp(connectorIndex);
bool linkB = gConnector[connectorIndex]->encoder.linkEnumeration bool linkB = gConnector[connectorIndex]->encoderExternal.linkEnumeration
== GRAPH_OBJECT_ENUM_ID2 ? true : false; == GRAPH_OBJECT_ENUM_ID2 ? true : false;
uint8 dpClock = 0; uint8 dpClock = 0;