summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian König <deathsimple@vodafone.de>2009-12-18 19:33:43 +0100
committerMatthias Hopf <mhopf@suse.de>2009-12-28 13:01:36 +0100
commitace8f44f6cbd7fd393b5a8a30468471ccee3726c (patch)
tree18927d433b5b543a5130ed04f134c1cb3d1572c4
parentffc141e2b9adbcf94780b877bf0e4d93d83f41a7 (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.c39
-rw-r--r--src/rhd_audio.c12
-rw-r--r--src/rhd_dig.c29
-rw-r--r--src/rhd_hdmi.c37
-rw-r--r--src/rhd_output.c16
-rw-r--r--src/rhd_regs.h2
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 */