summaryrefslogtreecommitdiff
authorChristian K├Ânig <deathsimple@vodafone.de>2009-10-07 22:04:01 (GMT)
committer Matthias Hopf <mhopf@suse.de>2009-10-08 09:34:23 (GMT)
commit422ac06b69cfcbfbaa802fdc916d3b87f40eeb41 (patch) (side-by-side diff)
treee49fa7b4522b06ab2babacc250b26896c2d77d7d
parent3cef2a6553359b063b760a2f436ce84365c60682 (diff)
downloadxf86-video-radeonhd-422ac06b69cfcbfbaa802fdc916d3b87f40eeb41.zip
xf86-video-radeonhd-422ac06b69cfcbfbaa802fdc916d3b87f40eeb41.tar.gz
Silence audio stream option.
This patch adds an option to play silence instead of playing no sound at all. This fixes some issues where a receiver needs 1-2 seconds to adjust to a new audio stream. This option can be enabled by setting AudioStreamSilence in xorg.conf or by xrandr.
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--src/rhd.h1
-rw-r--r--src/rhd_atomout.c10
-rw-r--r--src/rhd_audio.c32
-rw-r--r--src/rhd_audio.h1
-rw-r--r--src/rhd_dig.c11
-rw-r--r--src/rhd_driver.c4
-rw-r--r--src/rhd_hdmi.c116
-rw-r--r--src/rhd_hdmi.h10
-rw-r--r--src/rhd_lvtma.c10
-rw-r--r--src/rhd_output.c19
-rw-r--r--src/rhd_output.h3
-rw-r--r--src/rhd_randr.c52
-rw-r--r--src/rhd_regs.h1
-rw-r--r--src/rhd_tmds.c10
14 files changed, 237 insertions, 43 deletions
diff --git a/src/rhd.h b/src/rhd.h
index 43adb30..efa6bc2 100644
--- a/src/rhd.h
+++ b/src/rhd.h
@@ -247,6 +247,7 @@ typedef struct RHDRec {
RHDOpt scaleTypeOpt;
RHDOpt unverifiedFeatures;
RHDOpt audio;
+ RHDOpt audioWorkaround;
RHDOpt hdmi;
RHDOpt coherent;
RHDOpt lowPowerMode;
diff --git a/src/rhd_atomout.c b/src/rhd_atomout.c
index b88b1bd..9d50ade 100644
--- a/src/rhd_atomout.c
+++ b/src/rhd_atomout.c
@@ -745,6 +745,7 @@ atomTMDSPropertyControl(struct rhdOutput *Output,
switch (Property) {
case RHD_OUTPUT_COHERENT:
case RHD_OUTPUT_HDMI:
+ case RHD_OUTPUT_AUDIO_WORKAROUND:
return TRUE;
default:
return FALSE;
@@ -757,6 +758,9 @@ atomTMDSPropertyControl(struct rhdOutput *Output,
case RHD_OUTPUT_HDMI:
val->Bool = atomIsHdmiEnabled(Output);
return TRUE;
+ case RHD_OUTPUT_AUDIO_WORKAROUND:
+ val->Bool = RHDHdmiGetAudioWorkaround(Private->Hdmi);
+ return TRUE;
default:
return FALSE;
}
@@ -769,6 +773,9 @@ atomTMDSPropertyControl(struct rhdOutput *Output,
case RHD_OUTPUT_HDMI:
atomSetHdmiEnabled(Output, val->Bool);
break;
+ case RHD_OUTPUT_AUDIO_WORKAROUND:
+ RHDHdmiSetAudioWorkaround(Private->Hdmi, val->Bool);
+ break;
default:
return FALSE;
}
@@ -780,6 +787,9 @@ atomTMDSPropertyControl(struct rhdOutput *Output,
Output->Mode(Output, Private->Mode);
Output->Power(Output, RHD_POWER_ON);
break;
+ case RHD_OUTPUT_AUDIO_WORKAROUND:
+ RHDHdmiCommitAudioWorkaround(Private->Hdmi);
+ break;
default:
return FALSE;
}
diff --git a/src/rhd_audio.c b/src/rhd_audio.c
index de5f5ce..5e3c4e2 100644
--- a/src/rhd_audio.c
+++ b/src/rhd_audio.c
@@ -90,14 +90,16 @@ AudioRate(struct rhdAudio* Audio)
return result;
}
+#if 0
/*
- * something playing ?
+ * something playing ? (not used anymore)
*/
static Bool
AudioPlaying(struct rhdAudio* Audio)
{
return (RHDRegRead(Audio, AUDIO_PLAYING) >> 4) & 1;
}
+#endif
/*
* iec 60958 status bits
@@ -124,35 +126,36 @@ static CARD32
AudioUpdateHdmi(OsTimerPtr timer, CARD32 time, pointer ptr)
{
struct rhdAudio *Audio = (struct rhdAudio*)ptr;
- Bool playing = AudioPlaying(Audio);
int channels = AudioChannels(Audio);
int rate = AudioRate(Audio);
int bps = AudioBitsPerSample(Audio);
CARD8 status_bits = AudioStatusBits(Audio);
CARD8 category_code = AudioCategoryCode(Audio);
+ Bool changes = FALSE;
+
struct rhdHdmi* hdmi;
- if(playing != Audio->SavedPlaying ||
- channels != Audio->SavedChannels ||
- rate != Audio->SavedRate ||
- bps != Audio->SavedBitsPerSample ||
- status_bits != Audio->SavedStatusBits ||
- category_code != Audio->SavedCategoryCode) {
+ changes |= channels != Audio->SavedChannels;
+ changes |= rate != Audio->SavedRate;
+ changes |= bps != Audio->SavedBitsPerSample;
+ changes |= status_bits != Audio->SavedStatusBits;
+ changes |= category_code != Audio->SavedCategoryCode;
- Audio->SavedPlaying = playing;
+ if(changes) {
Audio->SavedChannels = channels;
Audio->SavedRate = rate;
Audio->SavedBitsPerSample = bps;
Audio->SavedStatusBits = status_bits;
Audio->SavedCategoryCode = category_code;
+ }
- for(hdmi=Audio->Registered; hdmi != NULL; hdmi=hdmi->Next)
+ for(hdmi=Audio->Registered; hdmi != NULL; hdmi=hdmi->Next)
+ if(changes || RHDHdmiBufferStatusChanged(hdmi))
RHDHdmiUpdateAudioSettings(
- hdmi, playing, channels,
+ hdmi, channels,
rate, bps, status_bits,
category_code);
- }
return AUDIO_TIMER_INTERVALL;
}
@@ -303,6 +306,9 @@ RHDAudioRegisterHdmi(RHDPtr rhdPtr, struct rhdHdmi* rhdHdmi)
if(!rhdHdmi)
return;
+ /* make shure the HDMI interface is not registered */
+ RHDAudioUnregisterHdmi(rhdPtr, rhdHdmi);
+
rhdHdmi->Next = Audio->Registered;
Audio->Registered = rhdHdmi;
}
@@ -318,7 +324,7 @@ void RHDAudioUnregisterHdmi(RHDPtr rhdPtr, struct rhdHdmi* rhdHdmi)
if (!Audio) return;
RHDFUNC(Audio);
- for(hdmiPtr=&Audio->Registered; hdmiPtr!=NULL;hdmiPtr=&(*hdmiPtr)->Next)
+ for(hdmiPtr=&Audio->Registered; *hdmiPtr!=NULL;hdmiPtr=&(*hdmiPtr)->Next)
if(*hdmiPtr == rhdHdmi) {
*hdmiPtr = rhdHdmi->Next;
rhdHdmi->Next = NULL;
diff --git a/src/rhd_audio.h b/src/rhd_audio.h
index d74016c..82932e9 100644
--- a/src/rhd_audio.h
+++ b/src/rhd_audio.h
@@ -34,7 +34,6 @@ struct rhdAudio {
struct rhdHdmi* Registered;
OsTimerPtr Timer;
- Bool SavedPlaying;
int SavedChannels;
int SavedRate;
int SavedBitsPerSample;
diff --git a/src/rhd_dig.c b/src/rhd_dig.c
index 6e75fd0..782c8db 100644
--- a/src/rhd_dig.c
+++ b/src/rhd_dig.c
@@ -262,6 +262,7 @@ TMDSTransmitterPropertyControl(struct rhdOutput *Output,
switch (Property) {
case RHD_OUTPUT_COHERENT:
case RHD_OUTPUT_HDMI:
+ case RHD_OUTPUT_AUDIO_WORKAROUND:
return TRUE;
default:
return FALSE;
@@ -274,6 +275,9 @@ TMDSTransmitterPropertyControl(struct rhdOutput *Output,
case RHD_OUTPUT_HDMI:
val->Bool = Private->EncoderMode == TMDS_HDMI;
return TRUE;
+ case RHD_OUTPUT_AUDIO_WORKAROUND:
+ val->Bool = RHDHdmiGetAudioWorkaround(Private->Hdmi);
+ return TRUE;
default:
return FALSE;
}
@@ -286,6 +290,9 @@ TMDSTransmitterPropertyControl(struct rhdOutput *Output,
case RHD_OUTPUT_HDMI:
Private->EncoderMode = val->Bool ? TMDS_HDMI : TMDS_DVI;
break;
+ case RHD_OUTPUT_AUDIO_WORKAROUND:
+ RHDHdmiSetAudioWorkaround(Private->Hdmi, val->Bool);
+ break;
default:
return FALSE;
}
@@ -297,6 +304,9 @@ TMDSTransmitterPropertyControl(struct rhdOutput *Output,
Output->Mode(Output, Private->Mode);
Output->Power(Output, RHD_POWER_ON);
break;
+ case RHD_OUTPUT_AUDIO_WORKAROUND:
+ RHDHdmiCommitAudioWorkaround(Private->Hdmi);
+ break;
default:
return FALSE;
}
@@ -1472,6 +1482,7 @@ DigPropertyControl(struct rhdOutput *Output,
case RHD_OUTPUT_COHERENT:
case RHD_OUTPUT_BACKLIGHT:
case RHD_OUTPUT_HDMI:
+ case RHD_OUTPUT_AUDIO_WORKAROUND:
{
if (!Private->Transmitter.Property)
return FALSE;
diff --git a/src/rhd_driver.c b/src/rhd_driver.c
index 649cadb..e502c5f 100644
--- a/src/rhd_driver.c
+++ b/src/rhd_driver.c
@@ -261,6 +261,7 @@ typedef enum {
#endif
OPTION_UNVERIFIED_FEAT,
OPTION_AUDIO,
+ OPTION_AUDIO_WORKAROUND,
OPTION_HDMI,
OPTION_COHERENT,
OPTION_FORCE_LOW_POWER,
@@ -292,6 +293,7 @@ static const OptionInfoRec RHDOptions[] = {
#endif
{ OPTION_UNVERIFIED_FEAT, "UnverifiedFeatures", OPTV_BOOLEAN, {0}, FALSE },
{ OPTION_AUDIO, "Audio", OPTV_BOOLEAN, {0}, FALSE },
+ { OPTION_AUDIO_WORKAROUND, "AudioStreamSilence", OPTV_ANYSTR, {0}, FALSE },
{ OPTION_HDMI, "HDMI", OPTV_ANYSTR, {0}, FALSE },
{ OPTION_COHERENT, "COHERENT", OPTV_ANYSTR, {0}, FALSE },
{ OPTION_FORCE_LOW_POWER, "ForceLowPowerMode", OPTV_BOOLEAN, {0}, FALSE },
@@ -2844,6 +2846,8 @@ rhdProcessOptions(ScrnInfoPtr pScrn)
&rhdPtr->unverifiedFeatures, FALSE);
RhdGetOptValBool (rhdPtr->Options, OPTION_AUDIO,
&rhdPtr->audio, TRUE);
+ RhdGetOptValString (rhdPtr->Options, OPTION_AUDIO_WORKAROUND,
+ &rhdPtr->audioWorkaround, "none");
RhdGetOptValString (rhdPtr->Options, OPTION_HDMI,
&rhdPtr->hdmi, "none");
RhdGetOptValString(rhdPtr->Options, OPTION_COHERENT,
diff --git a/src/rhd_hdmi.c b/src/rhd_hdmi.c
index 62ab861..c786fcd 100644
--- a/src/rhd_hdmi.c
+++ b/src/rhd_hdmi.c
@@ -229,26 +229,16 @@ HdmiAudioInfoFrame(
}
/*
- * it's unknown what these bits do excatly, but it's indeed quite usefull for debugging
+ * test if audio buffer is filled enough to start playing
*/
-static void
-HdmiAudioDebugWorkaround(struct rhdHdmi* hdmi, Bool Enable)
+static Bool
+IsAudioBufferFilled(struct rhdHdmi *hdmi)
{
- RHDRegWrite(hdmi, hdmi->Offset+HDMI_AUDIO_DEBUG_0, 0x00FFFFFF);
- RHDRegWrite(hdmi, hdmi->Offset+HDMI_AUDIO_DEBUG_1, 0x007FFFFF);
- RHDRegWrite(hdmi, hdmi->Offset+HDMI_AUDIO_DEBUG_2, 0x00000001);
- RHDRegWrite(hdmi, hdmi->Offset+HDMI_AUDIO_DEBUG_3, 0x00000001);
-
- if(Enable) {
- RHDRegMask(hdmi, hdmi->Offset+HDMI_CNTL, 0x1000, 0x1000);
- } else {
- RHDRegMask(hdmi, hdmi->Offset+HDMI_CNTL, 0, 0x1000);
- }
+ return (RHDRegRead(hdmi, hdmi->Offset+HDMI_STATUS) & 0x10) != 0;
}
/*
* allocate/initialize the HDMI structure
- * and register with audio engine
* output selects which engine is used
*/
struct rhdHdmi*
@@ -291,7 +281,6 @@ RHDHdmiInit(RHDPtr rhdPtr, struct rhdOutput* Output)
break;
}
hdmi->Stored = FALSE;
- RHDAudioRegisterHdmi(rhdPtr, hdmi);
return hdmi;
} else
return NULL;
@@ -308,8 +297,6 @@ RHDHdmiSetMode(struct rhdHdmi *hdmi, DisplayModePtr Mode)
RHDAudioSetClock(RHDPTRI(hdmi), hdmi->Output, Mode->Clock);
- HdmiAudioDebugWorkaround(hdmi, FALSE);
-
RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_0, 0x1000);
RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_1, 0x0);
RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_2, 0x1000);
@@ -323,20 +310,45 @@ RHDHdmiSetMode(struct rhdHdmi *hdmi, DisplayModePtr Mode)
HdmiVideoInfoFrame(hdmi, RGB, FALSE, 0, 0, 0,
0, 0, FALSE, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ /* it's unknown what these bits do excatly, but it's indeed quite usefull for debugging */
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_AUDIO_DEBUG_0, 0x00FFFFFF);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_AUDIO_DEBUG_1, 0x007FFFFF);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_AUDIO_DEBUG_2, 0x00000001);
+ RHDRegWrite(hdmi, hdmi->Offset+HDMI_AUDIO_DEBUG_3, 0x00000001);
+
+ RHDHdmiCommitAudioWorkaround(hdmi);
+
/* audio packets per line, does anyone know how to calc this ? */
- RHDRegMask(hdmi, hdmi->Offset+HDMI_CNTL, 0x020000, 0x1F0000);
+ RHDRegMask(hdmi, hdmi->Offset+HDMI_CNTL, 0x00040000, 0x001F0000);
/* update? reset? don't realy know */
RHDRegMask(hdmi, hdmi->Offset+HDMI_CNTL, 0x14000000, 0x14000000);
}
/*
+ * have buffer status changed since last call?
+ */
+Bool
+RHDHdmiBufferStatusChanged(struct rhdHdmi* hdmi)
+{
+ Bool status, result;
+
+ if(!hdmi) return FALSE;
+ RHDFUNC(hdmi);
+
+ status = IsAudioBufferFilled(hdmi);
+ result = hdmi->SavedBufferStatus != status;
+ hdmi->SavedBufferStatus = status;
+
+ return result;
+}
+
+/*
* update settings with current parameters from audio engine
*/
void
RHDHdmiUpdateAudioSettings(
struct rhdHdmi* hdmi,
- Bool playing,
int channels,
int rate,
int bps,
@@ -351,13 +363,11 @@ RHDHdmiUpdateAudioSettings(
xf86DrvMsg(hdmi->scrnIndex, X_INFO, "%s: %s with "
"%d channels, %d Hz sampling rate, %d bits per sample,\n",
- __func__, playing ? "playing" : "stopped", channels, rate, bps);
+ __func__, IsAudioBufferFilled(hdmi) ? "playing" : "stopped",
+ channels, rate, bps);
xf86DrvMsg(hdmi->scrnIndex, X_INFO, "%s: "
"0x%02x IEC60958 status bits and 0x%02x category code\n",
- __func__, (int)status_bits, (int)category_code);
-
- /* start delivering audio frames */
- RHDRegMask(hdmi, hdmi->Offset+HDMI_CNTL, playing ? 1 : 0, 0x1);
+ __func__, (int)status_bits, (int)category_code);
iec = 0;
if(status_bits & AUDIO_STATUS_PROFESSIONAL) iec |= 1 << 0;
@@ -395,12 +405,15 @@ RHDHdmiUpdateAudioSettings(
RHDRegWrite(hdmi, hdmi->Offset+HDMI_AUDIOCNTL, 0x31);
HdmiAudioInfoFrame(hdmi, channels-1, 0, 0, 0, 0, 0, 0, FALSE);
- /* RHDRegMask(hdmi, hdmi->Offset+HDMI_CNTL, 0x4000000, 0x4000000); */
- RHDRegMask(hdmi, hdmi->Offset+HDMI_CNTL, 0x400000, 0x400000);
+ RHDHdmiCommitAudioWorkaround(hdmi);
+
+ /* update? reset? don't realy know */
+ RHDRegMask(hdmi, hdmi->Offset+HDMI_CNTL, 0x04000000, 0x04000000);
}
/*
* enable/disable the HDMI engine
+ * and register with audio engine
*/
void
RHDHdmiEnable(struct rhdHdmi *hdmi, Bool Enable)
@@ -432,6 +445,57 @@ RHDHdmiEnable(struct rhdHdmi *hdmi, Bool Enable)
xf86DrvMsg(hdmi->scrnIndex, X_ERROR, "%s: unknown HDMI output type\n", __func__);
break;
}
+ if(Enable)
+ RHDAudioRegisterHdmi(RHDPTRI(hdmi), hdmi);
+ else
+ RHDAudioUnregisterHdmi(RHDPTRI(hdmi), hdmi);
+}
+
+/*
+ * enable/disable the audio workaround function
+ */
+void
+RHDHdmiSetAudioWorkaround(struct rhdHdmi* hdmi, Bool Enable)
+{
+ if(!hdmi) return;
+ RHDFUNC(hdmi);
+
+ hdmi->AudioDebugWorkaround = Enable;
+}
+
+/*
+ * get status of the audio workaround function
+ */
+Bool
+RHDHdmiGetAudioWorkaround(struct rhdHdmi* hdmi)
+{
+ if(!hdmi) return FALSE;
+ RHDFUNC(hdmi);
+
+ return hdmi->AudioDebugWorkaround;
+}
+
+/*
+ * commit the audio workaround status to the hardware
+ */
+void
+RHDHdmiCommitAudioWorkaround(struct rhdHdmi* hdmi)
+{
+ if(!hdmi) return;
+ RHDFUNC(hdmi);
+
+ if(IsAudioBufferFilled(hdmi)) {
+ /* disable audio workaround and start delivering of audio frames */
+ RHDRegMask(hdmi, hdmi->Offset+HDMI_CNTL, 0x00000001, 0x00001001);
+
+ } else if(hdmi->AudioDebugWorkaround) {
+ /* enable audio workaround and start delivering of audio frames */
+ RHDRegMask(hdmi, hdmi->Offset+HDMI_CNTL, 0x00001001, 0x00001001);
+
+ } else {
+ /* disable audio workaround and stop delivering of audio frames */
+ RHDRegMask(hdmi, hdmi->Offset+HDMI_CNTL, 0x00000000, 0x00001001);
+ }
}
/*
diff --git a/src/rhd_hdmi.h b/src/rhd_hdmi.h
index 5b1e8f0..e86b5e2 100644
--- a/src/rhd_hdmi.h
+++ b/src/rhd_hdmi.h
@@ -35,6 +35,9 @@ struct rhdHdmi {
struct rhdOutput* Output;
CARD16 Offset;
+ Bool SavedBufferStatus;
+ Bool AudioDebugWorkaround;
+
Bool Stored;
CARD32 StoreEnable;
CARD32 StoreControl;
@@ -63,9 +66,10 @@ struct rhdHdmi* RHDHdmiInit(RHDPtr rhdPtr, struct rhdOutput* Output);
void RHDHdmiSetMode(struct rhdHdmi* rhdHdmi, DisplayModePtr Mode);
void RHDHdmiEnable(struct rhdHdmi* rhdHdmi, Bool Enable);
+
+Bool RHDHdmiBufferStatusChanged(struct rhdHdmi* hdmi);
void RHDHdmiUpdateAudioSettings(
struct rhdHdmi* rhdHdmi,
- Bool playing,
int channels,
int rate,
int bps,
@@ -73,6 +77,10 @@ void RHDHdmiUpdateAudioSettings(
CARD8 catgory_code
);
+void RHDHdmiSetAudioWorkaround(struct rhdHdmi* rhdHdmi, Bool Enabled);
+Bool RHDHdmiGetAudioWorkaround(struct rhdHdmi* rhdHdmi);
+void RHDHdmiCommitAudioWorkaround(struct rhdHdmi* rhdHdmi);
+
void RHDHdmiSave(struct rhdHdmi* rhdHdmi);
void RHDHdmiRestore(struct rhdHdmi* rhdHdmi);
diff --git a/src/rhd_lvtma.c b/src/rhd_lvtma.c
index 685aef6..a4aeb9e 100644
--- a/src/rhd_lvtma.c
+++ b/src/rhd_lvtma.c
@@ -1069,6 +1069,7 @@ TMDSBPropertyControl(struct rhdOutput *Output,
switch (Property) {
case RHD_OUTPUT_COHERENT:
case RHD_OUTPUT_HDMI:
+ case RHD_OUTPUT_AUDIO_WORKAROUND:
return TRUE;
default:
return FALSE;
@@ -1081,6 +1082,9 @@ TMDSBPropertyControl(struct rhdOutput *Output,
case RHD_OUTPUT_HDMI:
val->Bool = Private->HdmiEnabled;
return TRUE;
+ case RHD_OUTPUT_AUDIO_WORKAROUND:
+ val->Bool = RHDHdmiGetAudioWorkaround(Private->Hdmi);
+ return TRUE;
default:
return FALSE;
}
@@ -1093,6 +1097,9 @@ TMDSBPropertyControl(struct rhdOutput *Output,
case RHD_OUTPUT_HDMI:
Private->HdmiEnabled = val->Bool;
break;
+ case RHD_OUTPUT_AUDIO_WORKAROUND:
+ RHDHdmiSetAudioWorkaround(Private->Hdmi, val->Bool);
+ break;
default:
return FALSE;
}
@@ -1104,6 +1111,9 @@ TMDSBPropertyControl(struct rhdOutput *Output,
Output->Mode(Output, Private->Mode);
Output->Power(Output, RHD_POWER_ON);
break;
+ case RHD_OUTPUT_AUDIO_WORKAROUND:
+ RHDHdmiCommitAudioWorkaround(Private->Hdmi);
+ break;
default:
return FALSE;
}
diff --git a/src/rhd_output.c b/src/rhd_output.c
index 2219582..0e33d4e 100644
--- a/src/rhd_output.c
+++ b/src/rhd_output.c
@@ -260,6 +260,25 @@ RHDOutputAttachConnector(struct rhdOutput *Output, struct rhdConnector *Connecto
if(!Output->Property(Output, rhdPropertySet, RHD_OUTPUT_HDMI, &val))
xf86DrvMsg(rhdPtr->scrnIndex, X_WARNING, "Failed to %s HDMI on %s\n", val.Bool ? "disable" : "enable", Output->Name);
}
+
+ /* check config option if we should enable audio workaround */
+ if (Output->Property(Output, rhdPropertyCheck, RHD_OUTPUT_AUDIO_WORKAROUND, NULL)) {
+ union rhdPropertyData val;
+ switch(RhdParseBooleanOption(&rhdPtr->audioWorkaround, Connector->Name)) {
+ case RHD_OPTION_NOT_SET:
+ case RHD_OPTION_OFF:
+ val.Bool = FALSE;
+ break;
+ case RHD_OPTION_ON:
+ case RHD_OPTION_DEFAULT:
+ val.Bool = TRUE;
+ break;
+ }
+ if(!Output->Property(Output, rhdPropertySet, RHD_OUTPUT_AUDIO_WORKAROUND, &val))
+ xf86DrvMsg(rhdPtr->scrnIndex, X_WARNING,
+ "Failed to %s audio workaorund on %s\n",
+ val.Bool ? "disable" : "enable", Output->Name);
+ }
}
/*
diff --git a/src/rhd_output.h b/src/rhd_output.h
index 0e7b6a2..4862478 100644
--- a/src/rhd_output.h
+++ b/src/rhd_output.h
@@ -59,7 +59,8 @@ typedef enum rhdSensedOutput {
enum rhdOutputProperty {
RHD_OUTPUT_BACKLIGHT,
RHD_OUTPUT_COHERENT,
- RHD_OUTPUT_HDMI
+ RHD_OUTPUT_HDMI,
+ RHD_OUTPUT_AUDIO_WORKAROUND
};
enum rhdOutputAllocation {
diff --git a/src/rhd_randr.c b/src/rhd_randr.c
index 568c0cd..956119b 100644
--- a/src/rhd_randr.c
+++ b/src/rhd_randr.c
@@ -130,11 +130,12 @@ struct rhdRandrCrtc {
#define ATOM_BACKLIGHT "Backlight"
#define ATOM_COHERENT "_Coherent"
#define ATOM_HDMI "_HDMI"
+#define ATOM_AUDIO_WORKAROUND "_AudioStreamSilence"
#define ATOM_ATOMBIOS "_AtomBIOS"
static Atom atom_SignalFormat, atom_ConnectorType, atom_ConnectorNumber,
atom_OutputNumber, atom_PanningArea, atom_Backlight, atom_Coherent,
- atom_HdmiProperty;
+ atom_HdmiProperty, atom_AudioWorkaround;
static Atom atom_unknown, atom_VGA, atom_TMDS, atom_LVDS, atom_DisplayPort, atom_TV;
static Atom atom_DVI, atom_DVII, atom_DVID, atom_DVIA, atom_HDMI, atom_Panel;
static Atom atom_EDID, atom_EDID2, atom_AtomBIOS;
@@ -713,6 +714,30 @@ rhdRROutputCreateResources(xf86OutputPtr out)
__func__, err);
}
}
+ if (rout->Output->Property(rout->Output, rhdPropertyCheck, RHD_OUTPUT_AUDIO_WORKAROUND, NULL)) {
+ atom_AudioWorkaround = MakeAtom(ATOM_AUDIO_WORKAROUND, sizeof(ATOM_AUDIO_WORKAROUND)-1, TRUE);
+
+ range[0] = 0;
+ range[1] = 1;
+ err = RRConfigureOutputProperty(out->randr_output, atom_AudioWorkaround,
+ FALSE, TRUE, FALSE, 2, range);
+ if (err != 0)
+ xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR,
+ "RRConfigureOutputProperty error: %d\n", err);
+ else {
+ union rhdPropertyData val;
+
+ if (!rout->Output->Property(rout->Output, rhdPropertyGet, RHD_OUTPUT_AUDIO_WORKAROUND, &val))
+ val.Bool = 1;
+ err = RRChangeOutputProperty(out->randr_output, atom_AudioWorkaround,
+ XA_INTEGER, 32, PropModeReplace,
+ 1, &val.Bool, FALSE, FALSE);
+ if (err != 0)
+ xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR,
+ "In %s RRChangeOutputProperty error: %d\n",
+ __func__, err);
+ }
+ }
}
}
@@ -1408,6 +1433,20 @@ rhdRROutputSetProperty(xf86OutputPtr out, Atom property,
RHD_OUTPUT_HDMI, NULL);
}
return FALSE;
+ } else if (property == atom_AudioWorkaround) {
+ if (value->type != XA_INTEGER || value->format != 32) {
+ xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "%s: wrong value\n", __func__);
+ return FALSE;
+ }
+ if (rout->Output->Property) {
+ union rhdPropertyData val;
+ val.Bool = *(int*)(value->data);
+ if(rout->Output->Property(rout->Output, rhdPropertySet,
+ RHD_OUTPUT_AUDIO_WORKAROUND, &val))
+ return rout->Output->Property(rout->Output, rhdPropertyCommit,
+ RHD_OUTPUT_AUDIO_WORKAROUND, NULL);
+ }
+ return FALSE;
#if ENABLE_PROPERTY_ATOMBIOS
} else if (property == atom_AtomBIOS) {
if (value->type != XA_STRING || value->format != 8)
@@ -1585,6 +1624,17 @@ rhdRROutputGetProperty(xf86OutputPtr out, Atom property)
err = RRChangeOutputProperty(out->randr_output, atom_HdmiProperty,
XA_INTEGER, 32, PropModeReplace,
1, &val.Bool, FALSE, FALSE);
+ } else if (property == atom_AudioWorkaround) {
+ if (rout->Output->Property == NULL)
+ return FALSE;
+
+ if (!rout->Output->Property(rout->Output, rhdPropertyGet,
+ RHD_OUTPUT_AUDIO_WORKAROUND, &val))
+ return FALSE;
+
+ err = RRChangeOutputProperty(out->randr_output, atom_AudioWorkaround,
+ XA_INTEGER, 32, PropModeReplace,
+ 1, &val.Bool, FALSE, FALSE);
}
RHDDebug(rhdPtr->scrnIndex, "%s 0x%x returns %d\n", __func__, property, err);
diff --git a/src/rhd_regs.h b/src/rhd_regs.h
index 3ca5e98..0e75d06 100644
--- a/src/rhd_regs.h
+++ b/src/rhd_regs.h
@@ -1119,6 +1119,7 @@ enum AGP_STATUS_BITS {
enum {
/* HDMI registers */
HDMI_ENABLE = 0x00,
+ HDMI_STATUS = 0x04,
HDMI_CNTL = 0x08,
HDMI_UNKNOWN_0 = 0x0C,
HDMI_AUDIOCNTL = 0x10,
diff --git a/src/rhd_tmds.c b/src/rhd_tmds.c
index 77529a5..7148ff5 100644
--- a/src/rhd_tmds.c
+++ b/src/rhd_tmds.c
@@ -243,6 +243,7 @@ TMDSAPropertyControl(struct rhdOutput *Output,
switch (Property) {
case RHD_OUTPUT_COHERENT:
case RHD_OUTPUT_HDMI:
+ case RHD_OUTPUT_AUDIO_WORKAROUND:
return TRUE;
default:
return FALSE;
@@ -255,6 +256,9 @@ TMDSAPropertyControl(struct rhdOutput *Output,
case RHD_OUTPUT_HDMI:
val->Bool = Private->HdmiEnabled;
return TRUE;
+ case RHD_OUTPUT_AUDIO_WORKAROUND:
+ val->Bool = RHDHdmiGetAudioWorkaround(Private->Hdmi);
+ return TRUE;
default:
return FALSE;
}
@@ -267,6 +271,9 @@ TMDSAPropertyControl(struct rhdOutput *Output,
case RHD_OUTPUT_HDMI:
Private->HdmiEnabled = val->Bool;
break;
+ case RHD_OUTPUT_AUDIO_WORKAROUND:
+ RHDHdmiSetAudioWorkaround(Private->Hdmi, val->Bool);
+ break;
default:
return FALSE;
}
@@ -278,6 +285,9 @@ TMDSAPropertyControl(struct rhdOutput *Output,
Output->Mode(Output, Private->Mode);
Output->Power(Output, RHD_POWER_ON);
break;
+ case RHD_OUTPUT_AUDIO_WORKAROUND:
+ RHDHdmiCommitAudioWorkaround(Private->Hdmi);
+ break;
default:
return FALSE;
}