diff options
author | Egbert Eich <eich@freedesktop.org> | 2009-10-26 15:56:51 +0100 |
---|---|---|
committer | Egbert Eich <eich@freedesktop.org> | 2009-10-26 15:56:51 +0100 |
commit | 8b89b94d50f08b672cacb6f053dc8dd7ea754183 (patch) | |
tree | 072b7ff96899a68df80dd98a9d239bf7bce362b3 | |
parent | 7f896deecf82bca550c57d8079ec10c041926548 (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.c | 121 | ||||
-rw-r--r-- | 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, @@ -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) { |