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;
uint16 gpioID;
struct encoder_info encoder;
struct encoder_info encoderExternal;
// TODO struct radeon_hpd hpd;
} connector_info;
+84 -55
View File
@@ -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");
+21 -17
View File
@@ -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;