From 8b89b94d50f08b672cacb6f053dc8dd7ea754183 Mon Sep 17 00:00:00 2001 From: Egbert Eich Date: Mon, 26 Oct 2009 15:56:51 +0100 Subject: 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. --- src/rhd_dac.c | 121 ++++++++++++++++++++++++++++++++++++++---- utils/conntest/rhd_conntest.c | 112 ++++++++++++++++++++++++++++++++++++-- 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, @@ -662,6 +661,74 @@ DACSenseRV620(struct rhdOutput *Output, CARD32 offset, Bool TV) return ret; } +/* + * + */ +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; +} + /* * */ @@ -669,25 +736,41 @@ 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, @@ -932,6 +1021,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; +} + /* * */ -- cgit v1.2.3