>From 10c1476102a8d7ac933bae30986ad88a65a347f4 Mon Sep 17 00:00:00 2001
From: Christian Koenig <deathsimple@vodafone.de>
Date: Tue, 23 Jun 2009 20:22:13 +0200
Subject: [PATCH] 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.
---
 src/rhd.h         |    1 +
 src/rhd_atomout.c |   10 +++++
 src/rhd_audio.c   |   32 +++++++++------
 src/rhd_audio.h   |    1 -
 src/rhd_dig.c     |   11 +++++
 src/rhd_driver.c  |    4 ++
 src/rhd_hdmi.c    |  116 +++++++++++++++++++++++++++++++++++++++++------------
 src/rhd_hdmi.h    |   10 ++++-
 src/rhd_lvtma.c   |   10 +++++
 src/rhd_output.c  |   19 +++++++++
 src/rhd_output.h  |    3 +-
 src/rhd_randr.c   |   52 +++++++++++++++++++++++-
 src/rhd_regs.h    |    1 +
 src/rhd_tmds.c    |   10 +++++
 14 files changed, 237 insertions(+), 43 deletions(-)

diff --git a/src/rhd.h b/src/rhd.h
index 6b08261..d94ec1d 100644
--- a/src/rhd.h
+++ b/src/rhd.h
@@ -245,6 +245,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 1d1662a..1319edb 100644
--- a/src/rhd_atomout.c
+++ b/src/rhd_atomout.c
@@ -715,6 +715,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;
@@ -727,6 +728,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;
 	    }
@@ -739,6 +743,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;
 	    }
@@ -750,6 +757,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 1c86ad0..cb403b3 100644
--- a/src/rhd_dig.c
+++ b/src/rhd_dig.c
@@ -245,6 +245,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;
@@ -257,6 +258,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;
 	    }
@@ -269,6 +273,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;
 	    }
@@ -280,6 +287,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;
 	    }
@@ -1455,6 +1465,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 ba60253..88c9efa 100644
--- a/src/rhd_driver.c
+++ b/src/rhd_driver.c
@@ -252,6 +252,7 @@ typedef enum {
 #endif
     OPTION_UNVERIFIED_FEAT,
     OPTION_AUDIO,
+    OPTION_AUDIO_WORKAROUND,
     OPTION_HDMI,
     OPTION_COHERENT,
     OPTION_FORCE_LOW_POWER,
@@ -283,6 +284,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 },
@@ -2767,6 +2769,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 cf3e8b1..9652ab0 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" : "stoped", channels, rate, bps);
+	__func__, IsAudioBufferFilled(hdmi) ? "playing" : "stoped",
+	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 b24bf5f..dacbcc4 100644
--- a/src/rhd_lvtma.c
+++ b/src/rhd_lvtma.c
@@ -1048,6 +1048,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;
@@ -1060,6 +1061,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;
 	    }
@@ -1072,6 +1076,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;
 	    }
@@ -1083,6 +1090,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 d1fbde4..4078f2b 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 21a49d2..c95fe68 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 3ad0363..038d00c 100644
--- a/src/rhd_randr.c
+++ b/src/rhd_randr.c
@@ -125,11 +125,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;
@@ -719,6 +720,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);
+	    }
+	}
 
     }
 }
@@ -1414,6 +1439,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;
     } else if (property == atom_AtomBIOS) {
 	if (value->type != XA_STRING || value->format != 8)
 	    return FALSE;
@@ -1589,6 +1628,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 fd59bcd..c6167a0 100644
--- a/src/rhd_regs.h
+++ b/src/rhd_regs.h
@@ -1090,6 +1090,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;
 	    }
-- 
1.6.0.4

