summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEgbert Eich <eich@freedesktop.org>2009-10-26 15:56:51 +0100
committerEgbert Eich <eich@freedesktop.org>2009-10-26 15:56:51 +0100
commit8b89b94d50f08b672cacb6f053dc8dd7ea754183 (patch)
tree072b7ff96899a68df80dd98a9d239bf7bce362b3
parent7f896deecf82bca550c57d8079ec10c041926548 (diff)
Add Fallback DAC Load Detection Method for chips >= RV620.
There are two methods of doing DAC load detection on DCE3.x chips: one works 'on the fly' ie doesn't produce noticeable flickering but doesn't work as reliably on some chips RS780 especially in connection with a KVM switch where it may produce a false negative, the other may produce some visible artefacts but also seems to work reliably with KVM switches. It's the one used in most AtomBIOSes. We now use both methods: if the 'on the fly' one produces a negative result we fall back to the other one and let it decide wether something is connected or not.
-rw-r--r--src/rhd_dac.c121
-rw-r--r--utils/conntest/rhd_conntest.c112
2 files changed, 217 insertions, 16 deletions
diff --git a/src/rhd_dac.c b/src/rhd_dac.c
index 8d05fe5..62f5a4a 100644
--- a/src/rhd_dac.c
+++ b/src/rhd_dac.c
@@ -614,12 +614,11 @@ DACBRestore(struct rhdOutput *Output)
}
/* ----------------------------------------------------------- */
-
/*
*
*/
static CARD32
-DACSenseRV620(struct rhdOutput *Output, CARD32 offset, Bool TV)
+DACSenseRV620_MethA(struct rhdOutput *Output, CARD32 offset, Bool TV)
{
CARD32 ret;
CARD32 DetectControl, AutodetectIntCtl, ForceData,
@@ -665,29 +664,113 @@ DACSenseRV620(struct rhdOutput *Output, CARD32 offset, Bool TV)
/*
*
*/
+static CARD32
+DACSenseRV620_MethB(struct rhdOutput *Output, CARD32 offset, Bool TV)
+{
+ CARD32 CompEnable, Control1, Control2, DetectControl, Enable;
+ CARD8 ret;
+
+ RHDFUNC(Output);
+
+ CompEnable = RHDRegRead(Output, offset + RV620_DACA_COMPARATOR_ENABLE);
+ Control1 = RHDRegRead(Output, offset + RV620_DACA_MACRO_CNTL);
+ Control2 = RHDRegRead(Output, offset + RV620_DACA_CONTROL2);
+ DetectControl = RHDRegRead(Output, offset + RV620_DACA_AUTODETECT_CONTROL);
+ Enable = RHDRegRead(Output, offset + RV620_DACA_ENABLE);
+
+ RHDRegWrite(Output, offset + RV620_DACA_ENABLE, 1);
+ /* ack autodetect */
+ // RHDRegMask(Output, offset + RV620_DACA_AUTODETECT_INT_CONTROL, 0x01, 0x01);
+ RHDRegMask(Output, offset + RV620_DACA_AUTODETECT_CONTROL, 0, 0x00000003);
+ RHDRegMask(Output, offset + RV620_DACA_CONTROL2, 0, 0x00000001);
+ RHDRegMask(Output, offset + RV620_DACA_CONTROL2, 0, 0x00ff0000);
+
+ if (offset) { /* We can do TV on DACA but only DACB has mux for separate connector */
+ if (TV)
+ RHDRegMask(Output, offset + RV620_DACA_CONTROL2, 0x00000100, 0x00000100);
+ else
+ RHDRegMask(Output, offset + RV620_DACA_CONTROL2, 0, 0x00000100);
+ }
+ RHDRegWrite(Output, offset + RV620_DACA_FORCE_DATA, 0);
+ RHDRegMask(Output, offset + RV620_DACA_CONTROL2, 0x00000001, 0x0000001);
+
+ RHDRegMask(Output, offset + RV620_DACA_COMPARATOR_ENABLE, 0x00070000, 0x00070101);
+ RHDRegWrite(Output, offset + RV620_DACA_MACRO_CNTL, offset ? 0x00052202 : 0x00052102);
+ RHDRegMask(Output, offset + RV620_DACA_POWERDOWN, 0, 0x00000001); /* Shut down Bandgap Voltage Reference Power */
+ usleep(5);
+
+ RHDRegMask(Output, offset + RV620_DACA_POWERDOWN, 0, 0x01010100); /* Shut down RGB */
+
+ RHDRegWrite(Output, offset + RV620_DACA_FORCE_DATA, 0x1e6); /* 486 out of 1024 */
+ usleep(200);
+
+ RHDRegMask(Output, offset + RV620_DACA_POWERDOWN, 0x01010100, 0x01010100); /* Enable RGB */
+ usleep(88);
+
+ RHDRegMask(Output, offset + RV620_DACA_POWERDOWN, 0, 0x01010100); /* Shut down RGB */
+
+ RHDRegMask(Output, offset + RV620_DACA_COMPARATOR_ENABLE, 0x00000100, 0x00000100);
+ usleep(100);
+
+ /* Get RGB detect values
+ * If only G is detected, we could have a monochrome monitor,
+ * but we don't bother with this at the moment.
+ */
+ ret = (RHDRegRead(Output, offset + RV620_DAC_COMPARATOR_OUTPUT) & 0x0E0000) >> 17;
+
+ RHDRegMask(Output, offset + RV620_DACA_COMPARATOR_ENABLE, CompEnable, 0x00FFFFFF);
+ RHDRegWrite(Output, offset + RV620_DACA_MACRO_CNTL, Control1);
+ RHDRegMask(Output, offset + RV620_DACA_CONTROL2, Control2, 0x000001FF);
+ RHDRegMask(Output, offset + RV620_DACA_AUTODETECT_CONTROL, DetectControl, 0x000000FF);
+ RHDRegMask(Output, offset + RV620_DACA_ENABLE, Enable, 0x000000FF);
+
+ RHDDebug(Output->scrnIndex, "%s: DAC: 0x0%1X\n", __func__, ret);
+
+ return ret;
+}
+
+/*
+ *
+ */
static enum rhdSensedOutput
DACASenseRV620(struct rhdOutput *Output, struct rhdConnector *Connector)
{
enum rhdConnectorType Type = Connector->Type;
+ CARD32 sense;
RHDFUNC(Output);
switch (Type) {
case RHD_CONNECTOR_DVI:
case RHD_CONNECTOR_DVI_SINGLE:
case RHD_CONNECTOR_VGA:
- return (DACSenseRV620(Output, RV620_REG_DACA_OFFSET, FALSE)
- & 0x1010100) ? RHD_SENSED_VGA : RHD_SENSED_NONE;
+ sense = DACSenseRV620_MethA(Output, RV620_REG_DACA_OFFSET, FALSE);
+ if (sense & 0x1010100)
+ return RHD_SENSED_VGA;
+ sense = DACSenseRV620_MethB(Output, RV620_REG_DACA_OFFSET, FALSE);
+ if (sense & 0x7)
+ return RHD_SENSED_VGA;
+ else
+ return RHD_SENSED_NONE;
case RHD_CONNECTOR_TV:
- switch (DACSenseRV620(Output, RV620_REG_DACA_OFFSET, TRUE)
+ switch (DACSenseRV620_MethA(Output, RV620_REG_DACA_OFFSET, TRUE)
& 0x1010100) {
case 0x1010100:
- return RHD_SENSED_NONE; /* on DAC A we cannot distinguish VGA and CV */
+ return RHD_SENSED_NONE; /* on DAC A we cannot distinguish VGA and CV */
case 0x10100:
return RHD_SENSED_TV_SVIDEO;
case 0x1000000:
return RHD_SENSED_TV_COMPOSITE;
default:
- return RHD_SENSED_NONE;
+ switch (DACSenseRV620_MethB(Output, RV620_REG_DACA_OFFSET, TRUE) & 0x7) {
+ case 0x7:
+ return RHD_SENSED_TV_COMPONENT;
+ case 0x6:
+ return RHD_SENSED_TV_SVIDEO;
+ case 0x1:
+ return RHD_SENSED_TV_COMPOSITE;
+ default:
+ return RHD_SENSED_NONE;
+ }
}
default:
xf86DrvMsg(Output->scrnIndex, X_WARNING,
@@ -704,16 +787,23 @@ static enum rhdSensedOutput
DACBSenseRV620(struct rhdOutput *Output, struct rhdConnector *Connector)
{
enum rhdConnectorType Type = Connector->Type;
+ CARD32 sense;
RHDFUNC(Output);
switch (Type) {
case RHD_CONNECTOR_DVI:
case RHD_CONNECTOR_DVI_SINGLE:
case RHD_CONNECTOR_VGA:
- return (DACSenseRV620(Output, RV620_REG_DACB_OFFSET, FALSE)
- & 0x1010100) ? RHD_SENSED_VGA : RHD_SENSED_NONE;
+ sense = DACSenseRV620_MethA(Output, RV620_REG_DACB_OFFSET, FALSE);
+ if (sense & 0x1010100)
+ return RHD_SENSED_VGA;
+ sense = DACSenseRV620_MethB(Output, RV620_REG_DACB_OFFSET, FALSE);
+ if (sense & 0x7)
+ return RHD_SENSED_VGA;
+ else
+ return RHD_SENSED_NONE;
case RHD_CONNECTOR_TV:
- switch (DACSenseRV620(Output, RV620_REG_DACB_OFFSET, TRUE)
+ switch (DACSenseRV620_MethA(Output, RV620_REG_DACB_OFFSET, TRUE)
& 0x1010100) {
case 0x1000000:
return RHD_SENSED_TV_COMPONENT;
@@ -722,7 +812,16 @@ DACBSenseRV620(struct rhdOutput *Output, struct rhdConnector *Connector)
case 0x10100:
return RHD_SENSED_TV_COMPOSITE;
default:
- return RHD_SENSED_NONE;
+ switch (DACSenseRV620_MethB(Output, RV620_REG_DACB_OFFSET, TRUE) & 0x7) {
+ case 0x7:
+ return RHD_SENSED_TV_COMPONENT;
+ case 0x6:
+ return RHD_SENSED_TV_SVIDEO;
+ case 0x1:
+ return RHD_SENSED_TV_COMPOSITE;
+ default:
+ return RHD_SENSED_NONE;
+ }
}
default:
xf86DrvMsg(Output->scrnIndex, X_WARNING,
diff --git a/utils/conntest/rhd_conntest.c b/utils/conntest/rhd_conntest.c
index f1db552..1c095ed 100644
--- a/utils/conntest/rhd_conntest.c
+++ b/utils/conntest/rhd_conntest.c
@@ -129,7 +129,7 @@ enum {
RV620_DACA_CONTROL2 = 0x7058,
RV620_DACA_COMPARATOR_ENABLE = 0x705C,
- RV620_DACA_CONTROL1 = 0x7ef4,
+ RV620_DACA_MACRO_CNTL = 0x7ef4,
/* DAC B */
DACB_ENABLE = 0x7A00,
@@ -845,14 +845,103 @@ RS690DACLoadDetect(void *map, Bool tv, int dac)
*
*/
static dacOutput
-RV620DACLoadDetect(void *map, Bool tv, int dac)
+RV620DACLoadDetect_MethB(void *map, Bool tv, int dac)
+{
+ CARD32 CompEnable, Control1, Control2, DetectControl, Enable;
+ CARD8 ret;
+ unsigned int offset = 0;
+
+ if (dac) offset = 0x200;
+
+ CompEnable = RegRead(map, offset + RV620_DACA_COMPARATOR_ENABLE);
+ Control1 = RegRead(map, offset + RV620_DACA_MACRO_CNTL);
+ Control2 = RegRead(map, offset + RV620_DACA_CONTROL2);
+ DetectControl = RegRead(map, offset + RV620_DACA_AUTODETECT_CONTROL);
+ Enable = RegRead(map, offset + RV620_DACA_ENABLE);
+
+ /* enable */
+ RegWrite(map, offset + RV620_DACA_ENABLE, 1);
+ /* ack autodetect */
+ RegMask(map, offset + RV620_DACA_AUTODETECT_INT_CONTROL, 0x01, 0x01);
+ /* autodetect off */
+ RegMask(map, offset + RV620_DACA_AUTODETECT_CONTROL, 0, 0x3);
+ /* zscale shift off */
+ RegMask(map, offset + RV620_DACA_CONTROL2, 0, 0xff0000);
+ /* dac force off */
+ RegMask(map, offset + RV620_DACA_CONTROL2, 0, 0x1);
+
+ /* set TV */
+ RegMask(map, offset + RV620_DACA_CONTROL2, tv ? 0x100 : 0, 0x100);
+
+ RegWrite(map, offset + RV620_DACA_FORCE_DATA, 0);
+ RegMask(map, offset + RV620_DACA_CONTROL2, 0x1, 0x1);
+
+ RegMask(map, offset + RV620_DACA_COMPARATOR_ENABLE, 0x00070000, 0x00070101);
+ RegWrite(map, offset + RV620_DACA_MACRO_CNTL, offset ? 0x00052202 : 0x00052102);
+
+ RegMask(map, offset + RV620_DACA_POWERDOWN, 0, 0x1); /* Shut down Bandgap Voltage Reference Power */
+ usleep(5000);
+
+ RegMask(map, offset + RV620_DACA_POWERDOWN, 0, 0x01010100); /* Shut down RGB */
+
+ RegWrite(map, offset + RV620_DACA_FORCE_DATA, 0x1e6); /* 486 out of 1024 */
+ usleep(200);
+
+ RegMask(map, offset + RV620_DACA_POWERDOWN, 0x01010100, 0x01010100); /* Enable RGB */
+ usleep(88);
+
+ RegMask(map, offset + RV620_DACA_POWERDOWN, 0, 0x01010100); /* Shut down RGB */
+
+ RegMask(map, offset + RV620_DACA_COMPARATOR_ENABLE, 0x100, 0x100);
+ usleep(100);
+
+ /* Get RGB detect values
+ * If only G is detected, we could have a monochrome monitor,
+ * but we don't bother with this at the moment.
+ */
+ ret = (RegRead(map, offset + RV620_DAC_COMPARATOR_OUTPUT) & 0x0E0000) >> 17;
+#ifdef DEBUG
+ fprintf(stderr, "DAC%s: %x %s\n", dac ? "B" : "A", ret, tv ? "TV" : "");
+#endif
+ RegMask(map, offset + RV620_DACA_COMPARATOR_ENABLE, CompEnable, 0x00FFFFFF);
+ RegWrite(map, offset + RV620_DACA_MACRO_CNTL, Control1);
+ RegMask(map, offset + RV620_DACA_CONTROL2, Control2, 0x1FF);
+ RegMask(map, offset + RV620_DACA_AUTODETECT_CONTROL, DetectControl, 0xFF);
+ RegMask(map, offset + RV620_DACA_ENABLE, Enable, 0xFF);
+
+ switch (ret & 0x7) {
+ case 0x7:
+ if (tv)
+ return DAC_COMPONENT;
+ else
+ return DAC_VGA;
+ case 0x1:
+ if (tv)
+ return DAC_COMPOSITE;
+ else
+ return DAC_NONE;
+ case 0x6:
+ if (tv)
+ return DAC_SVIDEO;
+ else
+ return DAC_NONE;
+ default:
+ return DAC_NONE;
+ }
+}
+
+/*
+ *
+ */
+static dacOutput
+RV620DACLoadDetect_MethA(void *map, Bool tv, int dac)
{
CARD32 offset = 0;
CARD32 ret;
CARD32 DetectControl, AutodetectIntCtl, ForceData, Control1, Control2, CompEnable;
if (dac == 1)
offset = 0x100;
- Control1 = RegRead(map, offset + RV620_DACA_CONTROL1); /* 7ef4 */
+ Control1 = RegRead(map, offset + RV620_DACA_MACRO_CNTL); /* 7ef4 */
Control2 = RegRead(map, offset + RV620_DACA_CONTROL2); /* 7058 */
ForceData = RegRead(map, offset + RV620_DACA_FORCE_DATA);
AutodetectIntCtl = RegRead(map, offset + RV620_DACA_AUTODETECT_INT_CONTROL);
@@ -893,7 +982,7 @@ RV620DACLoadDetect(void *map, Bool tv, int dac)
/* autodetect off */
RegMask(map, offset + RV620_DACA_AUTODETECT_CONTROL, 0x00, 0xff);
/* bandgap */
- RegMask(map, offset + RV620_DACA_CONTROL1, dac ? 0x2502 : 0x2002, 0xffff);
+ RegMask(map, offset + RV620_DACA_MACRO_CNTL, dac ? 0x2502 : 0x2002, 0xffff);
/* DAC RGB async enable */
RegMask(map, offset + RV620_DACA_CONTROL2, 0x1, 0x1);
/* enable r/g/b comparators, disable D/SDET ref */
@@ -906,7 +995,7 @@ RV620DACLoadDetect(void *map, Bool tv, int dac)
ret = RegRead(map, offset + RV620_DACA_AUTODETECT_STATUS);
RegWrite(map, offset + RV620_DACA_AUTODETECT_CONTROL, DetectControl);
- RegWrite(map, offset + RV620_DACA_CONTROL1, Control1);
+ RegWrite(map, offset + RV620_DACA_MACRO_CNTL, Control1);
RegWrite(map, offset + RV620_DACA_CONTROL2, Control2);
RegWrite(map, offset + RV620_DACA_FORCE_DATA, ForceData);
RegWrite(map, offset + RV620_DACA_AUTODETECT_INT_CONTROL,
@@ -935,6 +1024,19 @@ RV620DACLoadDetect(void *map, Bool tv, int dac)
/*
*
*/
+static dacOutput
+RV620DACLoadDetect(void *map, Bool tv, int dac)
+{
+ dacOutput dacType = RV620DACLoadDetect_MethA(map, tv, dac);
+ if (dacType == DAC_NONE)
+ return RV620DACLoadDetect_MethB(map, tv, dac);
+ else
+ return dacType;
+}
+
+/*
+ *
+ */
static Bool
TMDSALoadDetect(void *map)
{