From 422ac06b69cfcbfbaa802fdc916d3b87f40eeb41 Mon Sep 17 00:00:00 2001 From: Christian König Date: Thu, 8 Oct 2009 00:04:01 +0200 Subject: 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 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; } -- cgit v1.2.3