diff options
author | Christian König <deathsimple@vodafone.de> | 2009-12-18 19:33:43 +0100 |
---|---|---|
committer | Matthias Hopf <mhopf@suse.de> | 2009-12-28 13:01:36 +0100 |
commit | ace8f44f6cbd7fd393b5a8a30468471ccee3726c (patch) | |
tree | 18927d433b5b543a5130ed04f134c1cb3d1572c4 | |
parent | ffc141e2b9adbcf94780b877bf0e4d93d83f41a7 (diff) |
HDMI audio support for RV710 and RV730.
This patch adds audio support for the RV710 and RV730 chipsets.
A special "Thank you" goes to Andrew Wasielewski, for finding the
0x7604 register dependency, submitting a bunch of logs and testing
really a lot of different patches until we figured this out completely.
Signed-off-by: Matthias Hopf <mhopf@suse.de>
-rw-r--r-- | src/rhd_atomout.c | 39 | ||||
-rw-r--r-- | src/rhd_audio.c | 12 | ||||
-rw-r--r-- | src/rhd_dig.c | 29 | ||||
-rw-r--r-- | src/rhd_hdmi.c | 37 | ||||
-rw-r--r-- | src/rhd_output.c | 16 | ||||
-rw-r--r-- | src/rhd_regs.h | 2 |
6 files changed, 90 insertions, 45 deletions
diff --git a/src/rhd_atomout.c b/src/rhd_atomout.c index 5f3db26..9f879a8 100644 --- a/src/rhd_atomout.c +++ b/src/rhd_atomout.c @@ -805,13 +805,12 @@ static void rhdAtomOutputDestroy(struct rhdOutput *Output) { struct rhdAtomOutputPrivate *Private = (struct rhdAtomOutputPrivate *) Output->Private; RHDFUNC(Output); if (Private->Save) xfree(Private->Save); - RHDHdmiDestroy(Private->Hdmi); if (Private) xfree(Private); Output->Private = NULL; xfree(Output->Name); } @@ -861,36 +860,44 @@ RHDAtomOutputAllocFree(struct rhdOutput *Output, enum rhdOutputAllocation Alloc) * LVTMA can only use DIG2. Thus exclude * DIG1 for LVTMA and prefer it for the * UNIPHYs. */ if (Private->EncoderId != atomEncoderNone) return TRUE; + if (Output->Id != RHD_OUTPUT_KLDSKP_LVTMA && !rhdPtr->DigEncoderOutput[0]) { rhdPtr->DigEncoderOutput[0] = Output; TransmitterConfig->Encoder = Private->EncoderId = atomEncoderDIG1; xf86DrvMsg(Output->scrnIndex, X_INFO, "Mapping DIG1 encoder to %s\n",TransmitterName); - return TRUE; } else if (!rhdPtr->DigEncoderOutput[1]) { rhdPtr->DigEncoderOutput[1] = Output; TransmitterConfig->Encoder = Private->EncoderId = atomEncoderDIG2; xf86DrvMsg(Output->scrnIndex, X_INFO, "Mapping DIG2 encoder to %s\n",TransmitterName); - return TRUE; } else return FALSE; + + Private->Hdmi = RHDHdmiInit(rhdPtr, Output); + RHDHdmiSave(Private->Hdmi); + RHDHdmiCommitAudioWorkaround(Private->Hdmi); + return TRUE; + case RHD_OUTPUT_FREE: - TransmitterConfig->Encoder = Private->EncoderId = atomEncoderNone; - if (rhdPtr->DigEncoderOutput[0] == Output) { + TransmitterConfig->Encoder = Private->EncoderId = atomEncoderNone; + if (rhdPtr->DigEncoderOutput[0] == Output) rhdPtr->DigEncoderOutput[0] = NULL; - return TRUE; - } else if (rhdPtr->DigEncoderOutput[1] == Output) { + else if (rhdPtr->DigEncoderOutput[1] == Output) rhdPtr->DigEncoderOutput[1] = NULL; - return TRUE; - } else + else return FALSE; - break; + + RHDHdmiRestore(Private->Hdmi); + RHDHdmiDestroy(Private->Hdmi); + Private->Hdmi = NULL; + return TRUE; + default: return FALSE; } } /* @@ -960,29 +967,28 @@ RHDAtomOutputInit(RHDPtr rhdPtr, rhdConnectorType ConnectorType, Private = xnfcalloc(sizeof(struct rhdAtomOutputPrivate), 1); Output->Private = Private; Output->OutputDriverPrivate = NULL; EncoderConfig = &Private->EncoderConfig; Private->PixelClock = 0; + Private->Hdmi = NULL; switch (OutputType) { case RHD_OUTPUT_NONE: xfree(Output); xfree(Private); return NULL; case RHD_OUTPUT_DACA: Output->Sense = RHDBIOSScratchDACSense; Private->EncoderId = atomEncoderDACA; Private->OutputControlId = atomDAC1Output; - Private->Hdmi = NULL; break; case RHD_OUTPUT_DACB: Output->Sense = RHDBIOSScratchDACSense; Private->EncoderId = atomEncoderDACB; Private->OutputControlId = atomDAC2Output; - Private->Hdmi = NULL; break; case RHD_OUTPUT_TMDSA: case RHD_OUTPUT_LVTMA: if (OutputType == RHD_OUTPUT_LVTMA) { if (ConnectorType == RHD_CONNECTOR_PANEL) { Private->OutputControlId = atomLCDOutput; @@ -1002,17 +1008,12 @@ RHDAtomOutputInit(RHDPtr rhdPtr, rhdConnectorType ConnectorType, if (OutputType == RHD_CONNECTOR_DVI) Private->DualLink = TRUE; else Private->DualLink = FALSE; - if (ConnectorType != RHD_CONNECTOR_PANEL) - Private->Hdmi = RHDHdmiInit(rhdPtr, Output); - else - Private->Hdmi = NULL; - Private->EncoderVersion = rhdAtomEncoderControlVersion(rhdPtr->atomBIOS, Private->EncoderId); switch (Private->EncoderVersion.cref) { case 1: EncoderConfig->u.lvds.Is24bit = Private->LVDS24Bit; break; case 2: @@ -1089,18 +1090,16 @@ RHDAtomOutputInit(RHDPtr rhdPtr, rhdConnectorType ConnectorType, TransmitterConfig->Link = atomTransLinkA; TransmitterConfig->Encoder = Private->TransmitterId; if (ConnectorType == RHD_CONNECTOR_PANEL) { TransmitterConfig->Mode = EncoderConfig->u.dig.EncoderMode = atomLVDS; LVDSInfoRetrieve(Output, Private); - Private->Hdmi = NULL; } else { TransmitterConfig->Mode = EncoderConfig->u.dig.EncoderMode = atomDVI; TMDSInfoRetrieve(rhdPtr, Private); Private->Coherent = FALSE; - Private->Hdmi = RHDHdmiInit(rhdPtr, Output); } break; case RHD_OUTPUT_UNIPHYA: case RHD_OUTPUT_UNIPHYB: case RHD_OUTPUT_UNIPHYC: @@ -1170,13 +1169,12 @@ RHDAtomOutputInit(RHDPtr rhdPtr, rhdConnectorType ConnectorType, TMDSInfoRetrieve(rhdPtr, Private); switch (ConnectorType) { case RHD_CONNECTOR_DVI: case RHD_CONNECTOR_DVI_SINGLE: TransmitterConfig->Mode = EncoderConfig->u.dig.EncoderMode = atomDVI; - Private->Hdmi = RHDHdmiInit(rhdPtr, Output); break; case RHD_CONNECTOR_PANEL: TransmitterConfig->Mode = EncoderConfig->u.dig.EncoderMode = atomLVDS; break; #if 0 case RHD_CONNECTOR_DP: @@ -1268,13 +1266,12 @@ RhdAtomSetupBacklightControlProperty(struct rhdOutput *Output, else if (rhdPtr->DigEncoderOutput[1] == Output) TransmitterConfig->Encoder = Private->EncoderId = atomEncoderDIG2; else TransmitterConfig->Encoder = Private->EncoderId = atomEncoderNone; LVDSInfoRetrieve(Output, Private); Private->PixelClock = 0; - Private->Hdmi = NULL; break; case RHD_OUTPUT_LVTMA: Private->OutputControlId = atomLCDOutput; break; default: xfree(Private); diff --git a/src/rhd_audio.c b/src/rhd_audio.c index 5e3c4e2..aac7d62 100644 --- a/src/rhd_audio.c +++ b/src/rhd_audio.c @@ -207,12 +207,20 @@ RHDAudioSetEnable(RHDPtr rhdPtr, Bool Enable) /* 48kHz and 16/20 bits per sample are always supported */ RHDAudioSetSupported(rhdPtr, TRUE, AUDIO_RATE_48000_HZ| AUDIO_BPS_16|AUDIO_BPS_20, AUDIO_CODEC_PCM ); + + + if(RHDPTRI(Audio)->ChipSet >= RHD_R700) + { + /* another bit which use is unknown, but is needed at least on RV710 and RV730 to get audio working */ + RHDRegMask(Audio, R700_AUDIO_UNKNOWN, 0x00000001, 0x00000001); + } + } else { TimerFree(Audio->Timer); Audio->Timer = NULL; } } @@ -236,12 +244,16 @@ RHDAudioSetClock(RHDPtr rhdPtr, struct rhdOutput* Output, CARD32 Clock) case RHD_OUTPUT_LVTMA: RHDRegMask(Audio, AUDIO_TIMING, 0, 0x301); break; case RHD_OUTPUT_UNIPHYA: case RHD_OUTPUT_UNIPHYB: + case RHD_OUTPUT_UNIPHYC: + case RHD_OUTPUT_UNIPHYD: + case RHD_OUTPUT_UNIPHYE: + case RHD_OUTPUT_UNIPHYF: case RHD_OUTPUT_KLDSKP_LVTMA: RHDRegMask(Audio, AUDIO_TIMING, 0x100, 0x301); break; default: xf86DrvMsg(Audio->scrnIndex, X_ERROR, "%s: unsupported output type\n", __func__); diff --git a/src/rhd_dig.c b/src/rhd_dig.c index 3458d4b..3156c37 100644 --- a/src/rhd_dig.c +++ b/src/rhd_dig.c @@ -1568,13 +1568,12 @@ DigDestroy(struct rhdOutput *Output) struct encoder *Encoder = &Private->Encoder; RHDFUNC(Output); Encoder->Destroy(Output); Transmitter->Destroy(Output); - RHDHdmiDestroy(Private->Hdmi); if (Transmitter->PropertyPrivate) RhdAtomDestroyBacklightControlProperty(Output, Transmitter->PropertyPrivate); xfree(Private); Output->Private = NULL; } @@ -1617,13 +1616,12 @@ DigAllocFree(struct rhdOutput *Output, enum rhdOutputAllocation Alloc) if (Output->Id == RHD_OUTPUT_KLDSKP_LVTMA) { if (!rhdPtr->DigEncoderOutput[1]) { rhdPtr->DigEncoderOutput[1] = Output; Private->EncoderID = ENCODER_DIG2; xf86DrvMsg(Output->scrnIndex, X_INFO, "Mapping DIG2 encoder to %s\n",TransmitterName); - return TRUE; } else return FALSE; } else #if defined(ATOM_BIOS) && defined(ATOM_BIOS_PARSER) { struct ATOMTransmitterPrivate *transPrivate = @@ -1632,36 +1630,43 @@ DigAllocFree(struct rhdOutput *Output, enum rhdOutputAllocation Alloc) if (!rhdPtr->DigEncoderOutput[0]) { rhdPtr->DigEncoderOutput[0] = Output; Private->EncoderID = ENCODER_DIG1; atc->Encoder = atomEncoderDIG1; xf86DrvMsg(Output->scrnIndex, X_INFO, "Mapping DIG1 encoder to %s\n",TransmitterName); - return TRUE; } else if (!rhdPtr->DigEncoderOutput[1]) { rhdPtr->DigEncoderOutput[1] = Output; Private->EncoderID = ENCODER_DIG2; atc->Encoder = atomEncoderDIG2; xf86DrvMsg(Output->scrnIndex, X_INFO, "Mapping DIG2 encoder to %s\n",TransmitterName); - return TRUE; } else return FALSE; } #else return FALSE; #endif + if(Private->EncoderMode == TMDS_DVI || Private->EncoderMode == TMDS_HDMI) { + Private->Hdmi = RHDHdmiInit(rhdPtr, Output); + RHDHdmiSave(Private->Hdmi); + RHDHdmiCommitAudioWorkaround(Private->Hdmi); + } + case RHD_OUTPUT_FREE: - Private->EncoderID = ENCODER_NONE; - if (rhdPtr->DigEncoderOutput[0] == Output) { + Private->EncoderID = ENCODER_NONE; + if (rhdPtr->DigEncoderOutput[0] == Output) rhdPtr->DigEncoderOutput[0] = NULL; - return TRUE; - } else if (rhdPtr->DigEncoderOutput[1] == Output) { + else if (rhdPtr->DigEncoderOutput[1] == Output) rhdPtr->DigEncoderOutput[1] = NULL; - return TRUE; - } else + else return FALSE; + + RHDHdmiRestore(Private->Hdmi); + RHDHdmiDestroy(Private->Hdmi); + Private->Hdmi = NULL; + return TRUE; break; default: return FALSE; } } @@ -1715,12 +1720,13 @@ RHDDIGInit(RHDPtr rhdPtr, enum rhdOutputType outputType, CARD8 ConnectorType) Output->AllocFree = DigAllocFree; Private = xnfcalloc(sizeof(struct DIGPrivate), 1); Output->Private = Private; Private->EncoderID = ENCODER_NONE; + Private->Hdmi = NULL; switch (outputType) { case RHD_OUTPUT_UNIPHYA: #if defined (ATOM_BIOS) && defined (ATOM_BIOS_PARSER) Output->Name = "UNIPHY_A"; Private->Transmitter.Private = @@ -1877,22 +1883,19 @@ RHDDIGInit(RHDPtr rhdPtr, enum rhdOutputType outputType, CARD8 ConnectorType) xf86DrvMsg(Output->scrnIndex,X_INFO, "Falling back to AtomBIOS controlled Backlight.\n"); } #endif } - Private->Hdmi = NULL; break; case RHD_CONNECTOR_DVI: Private->RunDualLink = FALSE; /* will be set later acc to pxclk */ Private->EncoderMode = TMDS_DVI; - Private->Hdmi = RHDHdmiInit(rhdPtr, Output); break; case RHD_CONNECTOR_DVI_SINGLE: Private->RunDualLink = FALSE; Private->EncoderMode = TMDS_DVI; /* changed later to HDMI if aplicateable */ - Private->Hdmi = RHDHdmiInit(rhdPtr, Output); break; } return Output; } diff --git a/src/rhd_hdmi.c b/src/rhd_hdmi.c index c786fcd..bafbc9d 100644 --- a/src/rhd_hdmi.c +++ b/src/rhd_hdmi.c @@ -255,28 +255,45 @@ RHDHdmiInit(RHDPtr rhdPtr, struct rhdOutput* Output) switch(Output->Id) { case RHD_OUTPUT_TMDSA: hdmi->Offset = HDMI_TMDS; break; case RHD_OUTPUT_LVTMA: - if(RHDOutputTmdsIndex(Output) == 0) + switch(RHDOutputTmdsIndex(Output)) { + case 0: hdmi->Offset = HDMI_TMDS; - else + break; + case 1: hdmi->Offset = HDMI_LVTMA; + break; + default: + xfree(hdmi); + return NULL; + } break; case RHD_OUTPUT_UNIPHYA: - hdmi->Offset = HDMI_TMDS; - break; - + case RHD_OUTPUT_UNIPHYB: + case RHD_OUTPUT_UNIPHYC: + case RHD_OUTPUT_UNIPHYD: + case RHD_OUTPUT_UNIPHYE: + case RHD_OUTPUT_UNIPHYF: case RHD_OUTPUT_KLDSKP_LVTMA: - hdmi->Offset = HDMI_DIG; + switch(RHDOutputTmdsIndex(Output)) { + case 0: + hdmi->Offset = HDMI_TMDS; + break; + case 1: + hdmi->Offset = HDMI_DIG; + break; + default: + xfree(hdmi); + return NULL; + } break; - /*case RHD_OUTPUT_UNIPHYB: */ - default: xf86DrvMsg(hdmi->scrnIndex, X_ERROR, "%s: unknown HDMI output type\n", __func__); xfree(hdmi); return NULL; break; } @@ -433,12 +450,16 @@ RHDHdmiEnable(struct rhdHdmi *hdmi, Bool Enable) RHDRegMask(hdmi, LVTMA_CNTL, Enable ? 0x4 : 0x0, 0x4); RHDRegWrite(hdmi, hdmi->Offset+HDMI_ENABLE, Enable ? 0x105 : 0x0); break; case RHD_OUTPUT_UNIPHYA: case RHD_OUTPUT_UNIPHYB: + case RHD_OUTPUT_UNIPHYC: + case RHD_OUTPUT_UNIPHYD: + case RHD_OUTPUT_UNIPHYE: + case RHD_OUTPUT_UNIPHYF: case RHD_OUTPUT_KLDSKP_LVTMA: /* This part is doubtfull in my opinion */ RHDRegWrite(hdmi, hdmi->Offset+HDMI_ENABLE, Enable ? 0x110 : 0x0); break; default: diff --git a/src/rhd_output.c b/src/rhd_output.c index 0e33d4e..4a767aa 100644 --- a/src/rhd_output.c +++ b/src/rhd_output.c @@ -284,18 +284,18 @@ RHDOutputAttachConnector(struct rhdOutput *Output, struct rhdConnector *Connecto /* * Returns the TMDS index of the given output, important for HDMI/Audio setup */ int RHDOutputTmdsIndex(struct rhdOutput *Output) { - struct rhdOutput *i = RHDPTRI(Output)->Outputs; + RHDPtr rhdPtr = RHDPTRI(Output); + struct rhdOutput *i = rhdPtr->Outputs; int index; switch(Output->Id) { case RHD_OUTPUT_TMDSA: - case RHD_OUTPUT_UNIPHYA: index=0; break; case RHD_OUTPUT_LVTMA: /* special case check if an TMDSA is present */ index=0; @@ -303,15 +303,25 @@ RHDOutputTmdsIndex(struct rhdOutput *Output) if(i->Id==RHD_OUTPUT_TMDSA) index++; i = i->Next; } break; + case RHD_OUTPUT_UNIPHYA: case RHD_OUTPUT_UNIPHYB: + case RHD_OUTPUT_UNIPHYC: + case RHD_OUTPUT_UNIPHYD: + case RHD_OUTPUT_UNIPHYE: + case RHD_OUTPUT_UNIPHYF: case RHD_OUTPUT_KLDSKP_LVTMA: - index=1; + for(index=0; index<2; index++) + if(rhdPtr->DigEncoderOutput[index] == Output) + return index; + + xf86DrvMsg(Output->scrnIndex, X_ERROR, "%s: output not assigned to encoder\n", __func__); + index=-1; break; default: xf86DrvMsg(Output->scrnIndex, X_ERROR, "%s: unsupported output type\n", __func__); index=-1; break; diff --git a/src/rhd_regs.h b/src/rhd_regs.h index a233153..ba474df 100644 --- a/src/rhd_regs.h +++ b/src/rhd_regs.h @@ -302,12 +302,14 @@ enum { AUDIO_IMPLEMENTATION_ID = 0x73c8, /* RW */ AUDIO_CONFIG_DEFAULT = 0x73cc, /* RW */ AUDIO_PIN_SENSE = 0x73d0, /* RW */ AUDIO_PIN_WIDGET_CNTL = 0x73d4, /* RO */ AUDIO_STATUS_BITS = 0x73d8, /* RO */ + R700_AUDIO_UNKNOWN = 0x7604, + /* HDMI */ HDMI_TMDS = 0x7400, HDMI_LVTMA = 0x7700, HDMI_DIG = 0x7800, /* R500 DAC A */ |