summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian König <deathsimple@vodafone.de>2009-10-08 00:04:01 +0200
committerMatthias Hopf <mhopf@suse.de>2009-10-08 11:34:23 +0200
commit422ac06b69cfcbfbaa802fdc916d3b87f40eeb41 (patch)
treee49fa7b4522b06ab2babacc250b26896c2d77d7d
parent3cef2a6553359b063b760a2f436ce84365c60682 (diff)
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.
-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
@@ -244,12 +244,13 @@ typedef struct RHDRec {
RHDOpt rrOutputOrder;
RHDOpt useDRI;
RHDOpt tvModeName;
RHDOpt scaleTypeOpt;
RHDOpt unverifiedFeatures;
RHDOpt audio;
+ RHDOpt audioWorkaround;
RHDOpt hdmi;
RHDOpt coherent;
RHDOpt lowPowerMode;
RHDOpt lowPowerModeEngineClock;
RHDOpt lowPowerModeMemoryClock;
enum RHD_HPD_USAGE hpdUsage;
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
@@ -742,47 +742,57 @@ atomTMDSPropertyControl(struct rhdOutput *Output,
RHDFUNC(Output);
switch (Action) {
case rhdPropertyCheck:
switch (Property) {
case RHD_OUTPUT_COHERENT:
case RHD_OUTPUT_HDMI:
+ case RHD_OUTPUT_AUDIO_WORKAROUND:
return TRUE;
default:
return FALSE;
}
case rhdPropertyGet:
switch (Property) {
case RHD_OUTPUT_COHERENT:
val->Bool = Private->Coherent;
return TRUE;
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;
}
break;
case rhdPropertySet:
switch (Property) {
case RHD_OUTPUT_COHERENT:
Private->Coherent = val->Bool;
break;
case RHD_OUTPUT_HDMI:
atomSetHdmiEnabled(Output, val->Bool);
break;
+ case RHD_OUTPUT_AUDIO_WORKAROUND:
+ RHDHdmiSetAudioWorkaround(Private->Hdmi, val->Bool);
+ break;
default:
return FALSE;
}
break;
case rhdPropertyCommit:
switch (Property) {
case RHD_OUTPUT_COHERENT:
case RHD_OUTPUT_HDMI:
Output->Mode(Output, Private->Mode);
Output->Power(Output, RHD_POWER_ON);
break;
+ case RHD_OUTPUT_AUDIO_WORKAROUND:
+ RHDHdmiCommitAudioWorkaround(Private->Hdmi);
+ break;
default:
return FALSE;
}
break;
}
return TRUE;
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
@@ -87,20 +87,22 @@ AudioRate(struct rhdAudio* Audio)
result *= ((value >> 11) & 0x7) + 1;
result /= ((value >> 8) & 0x7) + 1;
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
*/
static CARD8
AudioStatusBits(struct rhdAudio* Audio)
@@ -121,41 +123,42 @@ AudioCategoryCode(struct rhdAudio* Audio)
* update all registered hdmi interfaces with current audio parameters
*/
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;
}
/*
* allocate and init the audio structure
@@ -300,12 +303,15 @@ RHDAudioRegisterHdmi(RHDPtr rhdPtr, struct rhdHdmi* rhdHdmi)
if (!Audio) return;
RHDFUNC(Audio);
if(!rhdHdmi)
return;
+ /* make shure the HDMI interface is not registered */
+ RHDAudioUnregisterHdmi(rhdPtr, rhdHdmi);
+
rhdHdmi->Next = Audio->Registered;
Audio->Registered = rhdHdmi;
}
/*
@@ -315,13 +321,13 @@ void RHDAudioUnregisterHdmi(RHDPtr rhdPtr, struct rhdHdmi* rhdHdmi)
{
struct rhdAudio *Audio = rhdPtr->Audio;
struct rhdHdmi** hdmiPtr;
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;
return;
}
}
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
@@ -31,13 +31,12 @@ struct rhdAudio {
int scrnIndex;
struct rhdHdmi* Registered;
OsTimerPtr Timer;
- Bool SavedPlaying;
int SavedChannels;
int SavedRate;
int SavedBitsPerSample;
CARD8 SavedStatusBits;
CARD8 SavedCategoryCode;
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
@@ -259,47 +259,57 @@ TMDSTransmitterPropertyControl(struct rhdOutput *Output,
RHDFUNC(Output);
switch (Action) {
case rhdPropertyCheck:
switch (Property) {
case RHD_OUTPUT_COHERENT:
case RHD_OUTPUT_HDMI:
+ case RHD_OUTPUT_AUDIO_WORKAROUND:
return TRUE;
default:
return FALSE;
}
case rhdPropertyGet:
switch (Property) {
case RHD_OUTPUT_COHERENT:
val->Bool = Private->Coherent;
return TRUE;
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;
}
break;
case rhdPropertySet:
switch (Property) {
case RHD_OUTPUT_COHERENT:
Private->Coherent = val->Bool;
break;
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;
}
break;
case rhdPropertyCommit:
switch (Property) {
case RHD_OUTPUT_COHERENT:
case RHD_OUTPUT_HDMI:
Output->Mode(Output, Private->Mode);
Output->Power(Output, RHD_POWER_ON);
break;
+ case RHD_OUTPUT_AUDIO_WORKAROUND:
+ RHDHdmiCommitAudioWorkaround(Private->Hdmi);
+ break;
default:
return FALSE;
}
break;
}
return TRUE;
@@ -1469,12 +1479,13 @@ DigPropertyControl(struct rhdOutput *Output,
RHDFUNC(Output);
switch(Property) {
case RHD_OUTPUT_COHERENT:
case RHD_OUTPUT_BACKLIGHT:
case RHD_OUTPUT_HDMI:
+ case RHD_OUTPUT_AUDIO_WORKAROUND:
{
if (!Private->Transmitter.Property)
return FALSE;
return Private->Transmitter.Property(Output, Action, Property, val);
}
default:
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
@@ -258,12 +258,13 @@ typedef enum {
#ifdef ATOM_BIOS
OPTION_USE_ATOMBIOS,
OPTION_ATOMBIOS, /* only for testing, don't document in man page! */
#endif
OPTION_UNVERIFIED_FEAT,
OPTION_AUDIO,
+ OPTION_AUDIO_WORKAROUND,
OPTION_HDMI,
OPTION_COHERENT,
OPTION_FORCE_LOW_POWER,
OPTION_LOW_POWER_CLOCK
} RHDOpts;
@@ -289,12 +290,13 @@ static const OptionInfoRec RHDOptions[] = {
#ifdef ATOM_BIOS
{ OPTION_USE_ATOMBIOS, "UseAtomBIOS", OPTV_BOOLEAN, {0}, FALSE },
{ OPTION_ATOMBIOS, "AtomBIOS", OPTV_ANYSTR, {0}, FALSE },
#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 },
{ OPTION_LOW_POWER_CLOCK, "LowPowerModeEngineClock", OPTV_INTEGER, {0}, FALSE },
{ -1, NULL, OPTV_NONE, {0}, FALSE }
};
@@ -2841,12 +2843,14 @@ rhdProcessOptions(ScrnInfoPtr pScrn)
RhdGetOptValString (rhdPtr->Options, OPTION_SCALE_TYPE,
&rhdPtr->scaleTypeOpt, "default");
RhdGetOptValBool (rhdPtr->Options, OPTION_UNVERIFIED_FEAT,
&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,
&rhdPtr->coherent, NULL);
RhdGetOptValBool (rhdPtr->Options, OPTION_FORCE_LOW_POWER,
&rhdPtr->lowPowerMode, FALSE);
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
@@ -226,32 +226,22 @@ HdmiAudioInfoFrame(
frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24));
RHDRegWrite(hdmi, hdmi->Offset+HDMI_AUDIOINFOFRAME_1,
frame[0x4] | (frame[0x5] << 8) | (frame[0x6] << 16) | (frame[0x8] << 24));
}
/*
- * 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*
RHDHdmiInit(RHDPtr rhdPtr, struct rhdOutput* Output)
{
struct rhdHdmi *hdmi;
@@ -288,13 +278,12 @@ RHDHdmiInit(RHDPtr rhdPtr, struct rhdOutput* Output)
xf86DrvMsg(hdmi->scrnIndex, X_ERROR, "%s: unknown HDMI output type\n", __func__);
xfree(hdmi);
return NULL;
break;
}
hdmi->Stored = FALSE;
- RHDAudioRegisterHdmi(rhdPtr, hdmi);
return hdmi;
} else
return NULL;
}
/*
@@ -305,14 +294,12 @@ RHDHdmiSetMode(struct rhdHdmi *hdmi, DisplayModePtr Mode)
{
if(!hdmi) return;
RHDFUNC(hdmi);
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);
HdmiAudioClockRegeneration(hdmi, Mode->Clock);
@@ -320,26 +307,51 @@ RHDHdmiSetMode(struct rhdHdmi *hdmi, DisplayModePtr Mode)
RHDRegWrite(hdmi, hdmi->Offset+HDMI_VERSION, 0x202);
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,
CARD8 status_bits,
CARD8 category_code
)
@@ -348,19 +360,17 @@ RHDHdmiUpdateAudioSettings(
if(!hdmi) return;
RHDFUNC(hdmi);
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;
if(status_bits & AUDIO_STATUS_NONAUDIO) iec |= 1 << 1;
if(status_bits & AUDIO_STATUS_COPYRIGHT) iec |= 1 << 2;
if(status_bits & AUDIO_STATUS_EMPHASIS) iec |= 1 << 3;
@@ -392,18 +402,21 @@ RHDHdmiUpdateAudioSettings(
RHDRegMask(hdmi, hdmi->Offset+HDMI_IEC60958_2, iec, 0x5000f);
/* 0x021 or 0x031 sets the audio frame length */
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)
{
if(!hdmi) return;
RHDFUNC(hdmi);
@@ -429,12 +442,63 @@ RHDHdmiEnable(struct rhdHdmi *hdmi, Bool Enable)
break;
default:
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);
+ }
}
/*
* save the current config of HDMI engine
*/
void
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
@@ -32,12 +32,15 @@ struct rhdHdmi {
int scrnIndex;
struct rhdOutput* Output;
CARD16 Offset;
+ Bool SavedBufferStatus;
+ Bool AudioDebugWorkaround;
+
Bool Stored;
CARD32 StoreEnable;
CARD32 StoreControl;
CARD32 StoreUnknown[0x3];
CARD32 StoredAudioDebugWorkaround[0x4];
@@ -60,22 +63,27 @@ struct rhdHdmi {
};
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,
CARD8 status_bits,
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);
void RHDHdmiDestroy(struct rhdHdmi* rhdHdmi);
#endif /* _RHD_HDMI_H */
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
@@ -1066,47 +1066,57 @@ TMDSBPropertyControl(struct rhdOutput *Output,
RHDFUNC(Output);
switch (Action) {
case rhdPropertyCheck:
switch (Property) {
case RHD_OUTPUT_COHERENT:
case RHD_OUTPUT_HDMI:
+ case RHD_OUTPUT_AUDIO_WORKAROUND:
return TRUE;
default:
return FALSE;
}
case rhdPropertyGet:
switch (Property) {
case RHD_OUTPUT_COHERENT:
val->Bool = Private->Coherent;
return TRUE;
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;
}
break;
case rhdPropertySet:
switch (Property) {
case RHD_OUTPUT_COHERENT:
Private->Coherent = val->Bool;
break;
case RHD_OUTPUT_HDMI:
Private->HdmiEnabled = val->Bool;
break;
+ case RHD_OUTPUT_AUDIO_WORKAROUND:
+ RHDHdmiSetAudioWorkaround(Private->Hdmi, val->Bool);
+ break;
default:
return FALSE;
}
break;
case rhdPropertyCommit:
switch (Property) {
case RHD_OUTPUT_COHERENT:
case RHD_OUTPUT_HDMI:
Output->Mode(Output, Private->Mode);
Output->Power(Output, RHD_POWER_ON);
break;
+ case RHD_OUTPUT_AUDIO_WORKAROUND:
+ RHDHdmiCommitAudioWorkaround(Private->Hdmi);
+ break;
default:
return FALSE;
}
break;
}
return TRUE;
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
@@ -257,12 +257,31 @@ RHDOutputAttachConnector(struct rhdOutput *Output, struct rhdConnector *Connecto
if (Output->Property(Output, rhdPropertyCheck, RHD_OUTPUT_HDMI, NULL)) {
union rhdPropertyData val;
val.Bool = RHDConnectorEnableHDMI(Connector);
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);
+ }
}
/*
* Returns the TMDS index of the given output, important for HDMI/Audio setup
*/
int
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
@@ -56,13 +56,14 @@ typedef enum rhdSensedOutput {
RHD_SENSED_TV_COMPONENT
} rhdSensedOutput;
enum rhdOutputProperty {
RHD_OUTPUT_BACKLIGHT,
RHD_OUTPUT_COHERENT,
- RHD_OUTPUT_HDMI
+ RHD_OUTPUT_HDMI,
+ RHD_OUTPUT_AUDIO_WORKAROUND
};
enum rhdOutputAllocation {
RHD_OUTPUT_ALLOC,
RHD_OUTPUT_FREE
};
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
@@ -127,17 +127,18 @@ struct rhdRandrCrtc {
#define ATOM_CONNECTOR_NUMBER "ConnectorNumber"
#define ATOM_OUTPUT_NUMBER "_OutputNumber"
#define ATOM_PANNING_AREA "_PanningArea"
#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;
/* Get RandR property values */
@@ -710,12 +711,36 @@ rhdRROutputCreateResources(xf86OutputPtr out)
if (err != 0)
xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR,
"In %s RRChangeOutputProperty error: %d\n",
__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);
+ }
+ }
}
}
/* Turns the output on/off, or sets intermediate power levels if available. */
/* Something that cannot be solved with the current RandR model is that
@@ -1405,12 +1430,26 @@ rhdRROutputSetProperty(xf86OutputPtr out, Atom property,
if(rout->Output->Property(rout->Output, rhdPropertySet,
RHD_OUTPUT_HDMI, &val))
return rout->Output->Property(rout->Output, rhdPropertyCommit,
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)
return FALSE;
if (rhdUpdateAtomBIOSUsage(rhdPtr, buf)) {
free (value->data);
@@ -1582,12 +1621,23 @@ rhdRROutputGetProperty(xf86OutputPtr out, Atom property)
RHD_OUTPUT_HDMI, &val))
return FALSE;
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);
if (err != 0)
return FALSE;
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
@@ -1116,12 +1116,13 @@ enum AGP_STATUS_BITS {
AGPv3_8X_MODE = 0x02
};
enum {
/* HDMI registers */
HDMI_ENABLE = 0x00,
+ HDMI_STATUS = 0x04,
HDMI_CNTL = 0x08,
HDMI_UNKNOWN_0 = 0x0C,
HDMI_AUDIOCNTL = 0x10,
HDMI_VIDEOCNTL = 0x14,
HDMI_VERSION = 0x18,
HDMI_UNKNOWN_1 = 0x28,
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
@@ -240,47 +240,57 @@ TMDSAPropertyControl(struct rhdOutput *Output,
RHDFUNC(Output);
switch (Action) {
case rhdPropertyCheck:
switch (Property) {
case RHD_OUTPUT_COHERENT:
case RHD_OUTPUT_HDMI:
+ case RHD_OUTPUT_AUDIO_WORKAROUND:
return TRUE;
default:
return FALSE;
}
case rhdPropertyGet:
switch (Property) {
case RHD_OUTPUT_COHERENT:
val->Bool = Private->Coherent;
return TRUE;
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;
}
break;
case rhdPropertySet:
switch (Property) {
case RHD_OUTPUT_COHERENT:
Private->Coherent = val->Bool;
break;
case RHD_OUTPUT_HDMI:
Private->HdmiEnabled = val->Bool;
break;
+ case RHD_OUTPUT_AUDIO_WORKAROUND:
+ RHDHdmiSetAudioWorkaround(Private->Hdmi, val->Bool);
+ break;
default:
return FALSE;
}
break;
case rhdPropertyCommit:
switch (Property) {
case RHD_OUTPUT_COHERENT:
case RHD_OUTPUT_HDMI:
Output->Mode(Output, Private->Mode);
Output->Power(Output, RHD_POWER_ON);
break;
+ case RHD_OUTPUT_AUDIO_WORKAROUND:
+ RHDHdmiCommitAudioWorkaround(Private->Hdmi);
+ break;
default:
return FALSE;
}
break;
}
return TRUE;