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
@@ -247,6 +247,7 @@ typedef struct RHDRec {
247 RHDOpt scaleTypeOpt; 247 RHDOpt scaleTypeOpt;
248 RHDOpt unverifiedFeatures; 248 RHDOpt unverifiedFeatures;
249 RHDOpt audio; 249 RHDOpt audio;
250 RHDOpt audioWorkaround;
250 RHDOpt hdmi; 251 RHDOpt hdmi;
251 RHDOpt coherent; 252 RHDOpt coherent;
252 RHDOpt lowPowerMode; 253 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,
745 switch (Property) { 745 switch (Property) {
746 case RHD_OUTPUT_COHERENT: 746 case RHD_OUTPUT_COHERENT:
747 case RHD_OUTPUT_HDMI: 747 case RHD_OUTPUT_HDMI:
748 case RHD_OUTPUT_AUDIO_WORKAROUND:
748 return TRUE; 749 return TRUE;
749 default: 750 default:
750 return FALSE; 751 return FALSE;
@@ -757,6 +758,9 @@ atomTMDSPropertyControl(struct rhdOutput *Output,
757 case RHD_OUTPUT_HDMI: 758 case RHD_OUTPUT_HDMI:
758 val->Bool = atomIsHdmiEnabled(Output); 759 val->Bool = atomIsHdmiEnabled(Output);
759 return TRUE; 760 return TRUE;
761 case RHD_OUTPUT_AUDIO_WORKAROUND:
762 val->Bool = RHDHdmiGetAudioWorkaround(Private->Hdmi);
763 return TRUE;
760 default: 764 default:
761 return FALSE; 765 return FALSE;
762 } 766 }
@@ -769,6 +773,9 @@ atomTMDSPropertyControl(struct rhdOutput *Output,
769 case RHD_OUTPUT_HDMI: 773 case RHD_OUTPUT_HDMI:
770 atomSetHdmiEnabled(Output, val->Bool); 774 atomSetHdmiEnabled(Output, val->Bool);
771 break; 775 break;
776 case RHD_OUTPUT_AUDIO_WORKAROUND:
777 RHDHdmiSetAudioWorkaround(Private->Hdmi, val->Bool);
778 break;
772 default: 779 default:
773 return FALSE; 780 return FALSE;
774 } 781 }
@@ -780,6 +787,9 @@ atomTMDSPropertyControl(struct rhdOutput *Output,
780 Output->Mode(Output, Private->Mode); 787 Output->Mode(Output, Private->Mode);
781 Output->Power(Output, RHD_POWER_ON); 788 Output->Power(Output, RHD_POWER_ON);
782 break; 789 break;
790 case RHD_OUTPUT_AUDIO_WORKAROUND:
791 RHDHdmiCommitAudioWorkaround(Private->Hdmi);
792 break;
783 default: 793 default:
784 return FALSE; 794 return FALSE;
785 } 795 }
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)
90 return result; 90 return result;
91} 91}
92 92
93#if 0
93/* 94/*
94 * something playing ? 95 * something playing ? (not used anymore)
95 */ 96 */
96static Bool 97static Bool
97AudioPlaying(struct rhdAudio* Audio) 98AudioPlaying(struct rhdAudio* Audio)
98{ 99{
99 return (RHDRegRead(Audio, AUDIO_PLAYING) >> 4) & 1; 100 return (RHDRegRead(Audio, AUDIO_PLAYING) >> 4) & 1;
100} 101}
102#endif
101 103
102/* 104/*
103 * iec 60958 status bits 105 * iec 60958 status bits
@@ -124,35 +126,36 @@ static CARD32
124AudioUpdateHdmi(OsTimerPtr timer, CARD32 time, pointer ptr) 126AudioUpdateHdmi(OsTimerPtr timer, CARD32 time, pointer ptr)
125{ 127{
126 struct rhdAudio *Audio = (struct rhdAudio*)ptr; 128 struct rhdAudio *Audio = (struct rhdAudio*)ptr;
127 Bool playing = AudioPlaying(Audio);
128 int channels = AudioChannels(Audio); 129 int channels = AudioChannels(Audio);
129 int rate = AudioRate(Audio); 130 int rate = AudioRate(Audio);
130 int bps = AudioBitsPerSample(Audio); 131 int bps = AudioBitsPerSample(Audio);
131 CARD8 status_bits = AudioStatusBits(Audio); 132 CARD8 status_bits = AudioStatusBits(Audio);
132 CARD8 category_code = AudioCategoryCode(Audio); 133 CARD8 category_code = AudioCategoryCode(Audio);
133 134
135 Bool changes = FALSE;
136
134 struct rhdHdmi* hdmi; 137 struct rhdHdmi* hdmi;
135 138
136 if(playing != Audio->SavedPlaying || 139 changes |= channels != Audio->SavedChannels;
137 channels != Audio->SavedChannels || 140 changes |= rate != Audio->SavedRate;
138 rate != Audio->SavedRate || 141 changes |= bps != Audio->SavedBitsPerSample;
139 bps != Audio->SavedBitsPerSample || 142 changes |= status_bits != Audio->SavedStatusBits;
140 status_bits != Audio->SavedStatusBits || 143 changes |= category_code != Audio->SavedCategoryCode;
141 category_code != Audio->SavedCategoryCode) {
142 144
143 Audio->SavedPlaying = playing; 145 if(changes) {
144 Audio->SavedChannels = channels; 146 Audio->SavedChannels = channels;
145 Audio->SavedRate = rate; 147 Audio->SavedRate = rate;
146 Audio->SavedBitsPerSample = bps; 148 Audio->SavedBitsPerSample = bps;
147 Audio->SavedStatusBits = status_bits; 149 Audio->SavedStatusBits = status_bits;
148 Audio->SavedCategoryCode = category_code; 150 Audio->SavedCategoryCode = category_code;
151 }
149 152
150 for(hdmi=Audio->Registered; hdmi != NULL; hdmi=hdmi->Next) 153 for(hdmi=Audio->Registered; hdmi != NULL; hdmi=hdmi->Next)
154 if(changes || RHDHdmiBufferStatusChanged(hdmi))
151 RHDHdmiUpdateAudioSettings( 155 RHDHdmiUpdateAudioSettings(
152 hdmi, playing, channels, 156 hdmi, channels,
153 rate, bps, status_bits, 157 rate, bps, status_bits,
154 category_code); 158 category_code);
155 }
156 159
157 return AUDIO_TIMER_INTERVALL; 160 return AUDIO_TIMER_INTERVALL;
158} 161}
@@ -303,6 +306,9 @@ RHDAudioRegisterHdmi(RHDPtr rhdPtr, struct rhdHdmi* rhdHdmi)
303 if(!rhdHdmi) 306 if(!rhdHdmi)
304 return; 307 return;
305 308
309 /* make shure the HDMI interface is not registered */
310 RHDAudioUnregisterHdmi(rhdPtr, rhdHdmi);
311
306 rhdHdmi->Next = Audio->Registered; 312 rhdHdmi->Next = Audio->Registered;
307 Audio->Registered = rhdHdmi; 313 Audio->Registered = rhdHdmi;
308} 314}
@@ -318,7 +324,7 @@ void RHDAudioUnregisterHdmi(RHDPtr rhdPtr, struct rhdHdmi* rhdHdmi)
318 if (!Audio) return; 324 if (!Audio) return;
319 RHDFUNC(Audio); 325 RHDFUNC(Audio);
320 326
321 for(hdmiPtr=&Audio->Registered; hdmiPtr!=NULL;hdmiPtr=&(*hdmiPtr)->Next) 327 for(hdmiPtr=&Audio->Registered; *hdmiPtr!=NULL;hdmiPtr=&(*hdmiPtr)->Next)
322 if(*hdmiPtr == rhdHdmi) { 328 if(*hdmiPtr == rhdHdmi) {
323 *hdmiPtr = rhdHdmi->Next; 329 *hdmiPtr = rhdHdmi->Next;
324 rhdHdmi->Next = NULL; 330 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 {
34 struct rhdHdmi* Registered; 34 struct rhdHdmi* Registered;
35 OsTimerPtr Timer; 35 OsTimerPtr Timer;
36 36
37 Bool SavedPlaying;
38 int SavedChannels; 37 int SavedChannels;
39 int SavedRate; 38 int SavedRate;
40 int SavedBitsPerSample; 39 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,
262 switch (Property) { 262 switch (Property) {
263 case RHD_OUTPUT_COHERENT: 263 case RHD_OUTPUT_COHERENT:
264 case RHD_OUTPUT_HDMI: 264 case RHD_OUTPUT_HDMI:
265 case RHD_OUTPUT_AUDIO_WORKAROUND:
265 return TRUE; 266 return TRUE;
266 default: 267 default:
267 return FALSE; 268 return FALSE;
@@ -274,6 +275,9 @@ TMDSTransmitterPropertyControl(struct rhdOutput *Output,
274 case RHD_OUTPUT_HDMI: 275 case RHD_OUTPUT_HDMI:
275 val->Bool = Private->EncoderMode == TMDS_HDMI; 276 val->Bool = Private->EncoderMode == TMDS_HDMI;
276 return TRUE; 277 return TRUE;
278 case RHD_OUTPUT_AUDIO_WORKAROUND:
279 val->Bool = RHDHdmiGetAudioWorkaround(Private->Hdmi);
280 return TRUE;
277 default: 281 default:
278 return FALSE; 282 return FALSE;
279 } 283 }
@@ -286,6 +290,9 @@ TMDSTransmitterPropertyControl(struct rhdOutput *Output,
286 case RHD_OUTPUT_HDMI: 290 case RHD_OUTPUT_HDMI:
287 Private->EncoderMode = val->Bool ? TMDS_HDMI : TMDS_DVI; 291 Private->EncoderMode = val->Bool ? TMDS_HDMI : TMDS_DVI;
288 break; 292 break;
293 case RHD_OUTPUT_AUDIO_WORKAROUND:
294 RHDHdmiSetAudioWorkaround(Private->Hdmi, val->Bool);
295 break;
289 default: 296 default:
290 return FALSE; 297 return FALSE;
291 } 298 }
@@ -297,6 +304,9 @@ TMDSTransmitterPropertyControl(struct rhdOutput *Output,
297 Output->Mode(Output, Private->Mode); 304 Output->Mode(Output, Private->Mode);
298 Output->Power(Output, RHD_POWER_ON); 305 Output->Power(Output, RHD_POWER_ON);
299 break; 306 break;
307 case RHD_OUTPUT_AUDIO_WORKAROUND:
308 RHDHdmiCommitAudioWorkaround(Private->Hdmi);
309 break;
300 default: 310 default:
301 return FALSE; 311 return FALSE;
302 } 312 }
@@ -1472,6 +1482,7 @@ DigPropertyControl(struct rhdOutput *Output,
1472 case RHD_OUTPUT_COHERENT: 1482 case RHD_OUTPUT_COHERENT:
1473 case RHD_OUTPUT_BACKLIGHT: 1483 case RHD_OUTPUT_BACKLIGHT:
1474 case RHD_OUTPUT_HDMI: 1484 case RHD_OUTPUT_HDMI:
1485 case RHD_OUTPUT_AUDIO_WORKAROUND:
1475 { 1486 {
1476 if (!Private->Transmitter.Property) 1487 if (!Private->Transmitter.Property)
1477 return FALSE; 1488 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 {
261#endif 261#endif
262 OPTION_UNVERIFIED_FEAT, 262 OPTION_UNVERIFIED_FEAT,
263 OPTION_AUDIO, 263 OPTION_AUDIO,
264 OPTION_AUDIO_WORKAROUND,
264 OPTION_HDMI, 265 OPTION_HDMI,
265 OPTION_COHERENT, 266 OPTION_COHERENT,
266 OPTION_FORCE_LOW_POWER, 267 OPTION_FORCE_LOW_POWER,
@@ -292,6 +293,7 @@ static const OptionInfoRec RHDOptions[] = {
292#endif 293#endif
293 { OPTION_UNVERIFIED_FEAT, "UnverifiedFeatures", OPTV_BOOLEAN, {0}, FALSE }, 294 { OPTION_UNVERIFIED_FEAT, "UnverifiedFeatures", OPTV_BOOLEAN, {0}, FALSE },
294 { OPTION_AUDIO, "Audio", OPTV_BOOLEAN, {0}, FALSE }, 295 { OPTION_AUDIO, "Audio", OPTV_BOOLEAN, {0}, FALSE },
296 { OPTION_AUDIO_WORKAROUND, "AudioStreamSilence", OPTV_ANYSTR, {0}, FALSE },
295 { OPTION_HDMI, "HDMI", OPTV_ANYSTR, {0}, FALSE }, 297 { OPTION_HDMI, "HDMI", OPTV_ANYSTR, {0}, FALSE },
296 { OPTION_COHERENT, "COHERENT", OPTV_ANYSTR, {0}, FALSE }, 298 { OPTION_COHERENT, "COHERENT", OPTV_ANYSTR, {0}, FALSE },
297 { OPTION_FORCE_LOW_POWER, "ForceLowPowerMode", OPTV_BOOLEAN, {0}, FALSE }, 299 { OPTION_FORCE_LOW_POWER, "ForceLowPowerMode", OPTV_BOOLEAN, {0}, FALSE },
@@ -2844,6 +2846,8 @@ rhdProcessOptions(ScrnInfoPtr pScrn)
2844 &rhdPtr->unverifiedFeatures, FALSE); 2846 &rhdPtr->unverifiedFeatures, FALSE);
2845 RhdGetOptValBool (rhdPtr->Options, OPTION_AUDIO, 2847 RhdGetOptValBool (rhdPtr->Options, OPTION_AUDIO,
2846 &rhdPtr->audio, TRUE); 2848 &rhdPtr->audio, TRUE);
2849 RhdGetOptValString (rhdPtr->Options, OPTION_AUDIO_WORKAROUND,
2850 &rhdPtr->audioWorkaround, "none");
2847 RhdGetOptValString (rhdPtr->Options, OPTION_HDMI, 2851 RhdGetOptValString (rhdPtr->Options, OPTION_HDMI,
2848 &rhdPtr->hdmi, "none"); 2852 &rhdPtr->hdmi, "none");
2849 RhdGetOptValString(rhdPtr->Options, OPTION_COHERENT, 2853 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(
229} 229}
230 230
231/* 231/*
232 * it's unknown what these bits do excatly, but it's indeed quite usefull for debugging 232 * test if audio buffer is filled enough to start playing
233 */ 233 */
234static void 234static Bool
235HdmiAudioDebugWorkaround(struct rhdHdmi* hdmi, Bool Enable) 235IsAudioBufferFilled(struct rhdHdmi *hdmi)
236{ 236{
237 RHDRegWrite(hdmi, hdmi->Offset+HDMI_AUDIO_DEBUG_0, 0x00FFFFFF); 237 return (RHDRegRead(hdmi, hdmi->Offset+HDMI_STATUS) & 0x10) != 0;
238 RHDRegWrite(hdmi, hdmi->Offset+HDMI_AUDIO_DEBUG_1, 0x007FFFFF);
239 RHDRegWrite(hdmi, hdmi->Offset+HDMI_AUDIO_DEBUG_2, 0x00000001);
240 RHDRegWrite(hdmi, hdmi->Offset+HDMI_AUDIO_DEBUG_3, 0x00000001);
241
242 if(Enable) {
243 RHDRegMask(hdmi, hdmi->Offset+HDMI_CNTL, 0x1000, 0x1000);
244 } else {
245 RHDRegMask(hdmi, hdmi->Offset+HDMI_CNTL, 0, 0x1000);
246 }
247} 238}
248 239
249/* 240/*
250 * allocate/initialize the HDMI structure 241 * allocate/initialize the HDMI structure
251 * and register with audio engine
252 * output selects which engine is used 242 * output selects which engine is used
253 */ 243 */
254struct rhdHdmi* 244struct rhdHdmi*
@@ -291,7 +281,6 @@ RHDHdmiInit(RHDPtr rhdPtr, struct rhdOutput* Output)
291 break; 281 break;
292 } 282 }
293 hdmi->Stored = FALSE; 283 hdmi->Stored = FALSE;
294 RHDAudioRegisterHdmi(rhdPtr, hdmi);
295 return hdmi; 284 return hdmi;
296 } else 285 } else
297 return NULL; 286 return NULL;
@@ -308,8 +297,6 @@ RHDHdmiSetMode(struct rhdHdmi *hdmi, DisplayModePtr Mode)
308 297
309 RHDAudioSetClock(RHDPTRI(hdmi), hdmi->Output, Mode->Clock); 298 RHDAudioSetClock(RHDPTRI(hdmi), hdmi->Output, Mode->Clock);
310 299
311 HdmiAudioDebugWorkaround(hdmi, FALSE);
312
313 RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_0, 0x1000); 300 RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_0, 0x1000);
314 RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_1, 0x0); 301 RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_1, 0x0);
315 RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_2, 0x1000); 302 RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_2, 0x1000);
@@ -323,20 +310,45 @@ RHDHdmiSetMode(struct rhdHdmi *hdmi, DisplayModePtr Mode)
323 HdmiVideoInfoFrame(hdmi, RGB, FALSE, 0, 0, 0, 310 HdmiVideoInfoFrame(hdmi, RGB, FALSE, 0, 0, 0,
324 0, 0, FALSE, 0, 0, 0, 0, 0, 0, 0, 0, 0); 311 0, 0, FALSE, 0, 0, 0, 0, 0, 0, 0, 0, 0);
325 312
313 /* it's unknown what these bits do excatly, but it's indeed quite usefull for debugging */
314 RHDRegWrite(hdmi, hdmi->Offset+HDMI_AUDIO_DEBUG_0, 0x00FFFFFF);
315 RHDRegWrite(hdmi, hdmi->Offset+HDMI_AUDIO_DEBUG_1, 0x007FFFFF);
316 RHDRegWrite(hdmi, hdmi->Offset+HDMI_AUDIO_DEBUG_2, 0x00000001);
317 RHDRegWrite(hdmi, hdmi->Offset+HDMI_AUDIO_DEBUG_3, 0x00000001);
318
319 RHDHdmiCommitAudioWorkaround(hdmi);
320
326 /* audio packets per line, does anyone know how to calc this ? */ 321 /* audio packets per line, does anyone know how to calc this ? */
327 RHDRegMask(hdmi, hdmi->Offset+HDMI_CNTL, 0x020000, 0x1F0000); 322 RHDRegMask(hdmi, hdmi->Offset+HDMI_CNTL, 0x00040000, 0x001F0000);
328 323
329 /* update? reset? don't realy know */ 324 /* update? reset? don't realy know */
330 RHDRegMask(hdmi, hdmi->Offset+HDMI_CNTL, 0x14000000, 0x14000000); 325 RHDRegMask(hdmi, hdmi->Offset+HDMI_CNTL, 0x14000000, 0x14000000);
331} 326}
332 327
333/* 328/*
329 * have buffer status changed since last call?
330 */
331Bool
332RHDHdmiBufferStatusChanged(struct rhdHdmi* hdmi)
333{
334 Bool status, result;
335
336 if(!hdmi) return FALSE;
337 RHDFUNC(hdmi);
338
339 status = IsAudioBufferFilled(hdmi);
340 result = hdmi->SavedBufferStatus != status;
341 hdmi->SavedBufferStatus = status;
342
343 return result;
344}
345
346/*
334 * update settings with current parameters from audio engine 347 * update settings with current parameters from audio engine
335 */ 348 */
336void 349void
337RHDHdmiUpdateAudioSettings( 350RHDHdmiUpdateAudioSettings(
338 struct rhdHdmi* hdmi, 351 struct rhdHdmi* hdmi,
339 Bool playing,
340 int channels, 352 int channels,
341 int rate, 353 int rate,
342 int bps, 354 int bps,
@@ -351,13 +363,11 @@ RHDHdmiUpdateAudioSettings(
351 363
352 xf86DrvMsg(hdmi->scrnIndex, X_INFO, "%s: %s with " 364 xf86DrvMsg(hdmi->scrnIndex, X_INFO, "%s: %s with "
353 "%d channels, %d Hz sampling rate, %d bits per sample,\n", 365 "%d channels, %d Hz sampling rate, %d bits per sample,\n",
354 __func__, playing ? "playing" : "stopped", channels, rate, bps); 366 __func__, IsAudioBufferFilled(hdmi) ? "playing" : "stopped",
367 channels, rate, bps);
355 xf86DrvMsg(hdmi->scrnIndex, X_INFO, "%s: " 368 xf86DrvMsg(hdmi->scrnIndex, X_INFO, "%s: "
356 "0x%02x IEC60958 status bits and 0x%02x category code\n", 369 "0x%02x IEC60958 status bits and 0x%02x category code\n",
357 __func__, (int)status_bits, (int)category_code); 370 __func__, (int)status_bits, (int)category_code);
358
359 /* start delivering audio frames */
360 RHDRegMask(hdmi, hdmi->Offset+HDMI_CNTL, playing ? 1 : 0, 0x1);
361 371
362 iec = 0; 372 iec = 0;
363 if(status_bits & AUDIO_STATUS_PROFESSIONAL) iec |= 1 << 0; 373 if(status_bits & AUDIO_STATUS_PROFESSIONAL) iec |= 1 << 0;
@@ -395,12 +405,15 @@ RHDHdmiUpdateAudioSettings(
395 RHDRegWrite(hdmi, hdmi->Offset+HDMI_AUDIOCNTL, 0x31); 405 RHDRegWrite(hdmi, hdmi->Offset+HDMI_AUDIOCNTL, 0x31);
396 HdmiAudioInfoFrame(hdmi, channels-1, 0, 0, 0, 0, 0, 0, FALSE); 406 HdmiAudioInfoFrame(hdmi, channels-1, 0, 0, 0, 0, 0, 0, FALSE);
397 407
398 /* RHDRegMask(hdmi, hdmi->Offset+HDMI_CNTL, 0x4000000, 0x4000000); */ 408 RHDHdmiCommitAudioWorkaround(hdmi);
399 RHDRegMask(hdmi, hdmi->Offset+HDMI_CNTL, 0x400000, 0x400000); 409
410 /* update? reset? don't realy know */
411 RHDRegMask(hdmi, hdmi->Offset+HDMI_CNTL, 0x04000000, 0x04000000);
400} 412}
401 413
402/* 414/*
403 * enable/disable the HDMI engine 415 * enable/disable the HDMI engine
416 * and register with audio engine
404 */ 417 */
405void 418void
406RHDHdmiEnable(struct rhdHdmi *hdmi, Bool Enable) 419RHDHdmiEnable(struct rhdHdmi *hdmi, Bool Enable)
@@ -432,6 +445,57 @@ RHDHdmiEnable(struct rhdHdmi *hdmi, Bool Enable)
432 xf86DrvMsg(hdmi->scrnIndex, X_ERROR, "%s: unknown HDMI output type\n", __func__); 445 xf86DrvMsg(hdmi->scrnIndex, X_ERROR, "%s: unknown HDMI output type\n", __func__);
433 break; 446 break;
434 } 447 }
448 if(Enable)
449 RHDAudioRegisterHdmi(RHDPTRI(hdmi), hdmi);
450 else
451 RHDAudioUnregisterHdmi(RHDPTRI(hdmi), hdmi);
452}
453
454/*
455 * enable/disable the audio workaround function
456 */
457void
458RHDHdmiSetAudioWorkaround(struct rhdHdmi* hdmi, Bool Enable)
459{
460 if(!hdmi) return;
461 RHDFUNC(hdmi);
462
463 hdmi->AudioDebugWorkaround = Enable;
464}
465
466/*
467 * get status of the audio workaround function
468 */
469Bool
470RHDHdmiGetAudioWorkaround(struct rhdHdmi* hdmi)
471{
472 if(!hdmi) return FALSE;
473 RHDFUNC(hdmi);
474
475 return hdmi->AudioDebugWorkaround;
476}
477
478/*
479 * commit the audio workaround status to the hardware
480 */
481void
482RHDHdmiCommitAudioWorkaround(struct rhdHdmi* hdmi)
483{
484 if(!hdmi) return;
485 RHDFUNC(hdmi);
486
487 if(IsAudioBufferFilled(hdmi)) {
488 /* disable audio workaround and start delivering of audio frames */
489 RHDRegMask(hdmi, hdmi->Offset+HDMI_CNTL, 0x00000001, 0x00001001);
490
491 } else if(hdmi->AudioDebugWorkaround) {
492 /* enable audio workaround and start delivering of audio frames */
493 RHDRegMask(hdmi, hdmi->Offset+HDMI_CNTL, 0x00001001, 0x00001001);
494
495 } else {
496 /* disable audio workaround and stop delivering of audio frames */
497 RHDRegMask(hdmi, hdmi->Offset+HDMI_CNTL, 0x00000000, 0x00001001);
498 }
435} 499}
436 500
437/* 501/*
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 {
35 struct rhdOutput* Output; 35 struct rhdOutput* Output;
36 CARD16 Offset; 36 CARD16 Offset;
37 37
38 Bool SavedBufferStatus;
39 Bool AudioDebugWorkaround;
40
38 Bool Stored; 41 Bool Stored;
39 CARD32 StoreEnable; 42 CARD32 StoreEnable;
40 CARD32 StoreControl; 43 CARD32 StoreControl;
@@ -63,9 +66,10 @@ struct rhdHdmi* RHDHdmiInit(RHDPtr rhdPtr, struct rhdOutput* Output);
63 66
64void RHDHdmiSetMode(struct rhdHdmi* rhdHdmi, DisplayModePtr Mode); 67void RHDHdmiSetMode(struct rhdHdmi* rhdHdmi, DisplayModePtr Mode);
65void RHDHdmiEnable(struct rhdHdmi* rhdHdmi, Bool Enable); 68void RHDHdmiEnable(struct rhdHdmi* rhdHdmi, Bool Enable);
69
70Bool RHDHdmiBufferStatusChanged(struct rhdHdmi* hdmi);
66void RHDHdmiUpdateAudioSettings( 71void RHDHdmiUpdateAudioSettings(
67 struct rhdHdmi* rhdHdmi, 72 struct rhdHdmi* rhdHdmi,
68 Bool playing,
69 int channels, 73 int channels,
70 int rate, 74 int rate,
71 int bps, 75 int bps,
@@ -73,6 +77,10 @@ void RHDHdmiUpdateAudioSettings(
73 CARD8 catgory_code 77 CARD8 catgory_code
74); 78);
75 79
80void RHDHdmiSetAudioWorkaround(struct rhdHdmi* rhdHdmi, Bool Enabled);
81Bool RHDHdmiGetAudioWorkaround(struct rhdHdmi* rhdHdmi);
82void RHDHdmiCommitAudioWorkaround(struct rhdHdmi* rhdHdmi);
83
76void RHDHdmiSave(struct rhdHdmi* rhdHdmi); 84void RHDHdmiSave(struct rhdHdmi* rhdHdmi);
77void RHDHdmiRestore(struct rhdHdmi* rhdHdmi); 85void RHDHdmiRestore(struct rhdHdmi* rhdHdmi);
78 86
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,
1069 switch (Property) { 1069 switch (Property) {
1070 case RHD_OUTPUT_COHERENT: 1070 case RHD_OUTPUT_COHERENT:
1071 case RHD_OUTPUT_HDMI: 1071 case RHD_OUTPUT_HDMI:
1072 case RHD_OUTPUT_AUDIO_WORKAROUND:
1072 return TRUE; 1073 return TRUE;
1073 default: 1074 default:
1074 return FALSE; 1075 return FALSE;
@@ -1081,6 +1082,9 @@ TMDSBPropertyControl(struct rhdOutput *Output,
1081 case RHD_OUTPUT_HDMI: 1082 case RHD_OUTPUT_HDMI:
1082 val->Bool = Private->HdmiEnabled; 1083 val->Bool = Private->HdmiEnabled;
1083 return TRUE; 1084 return TRUE;
1085 case RHD_OUTPUT_AUDIO_WORKAROUND:
1086 val->Bool = RHDHdmiGetAudioWorkaround(Private->Hdmi);
1087 return TRUE;
1084 default: 1088 default:
1085 return FALSE; 1089 return FALSE;
1086 } 1090 }
@@ -1093,6 +1097,9 @@ TMDSBPropertyControl(struct rhdOutput *Output,
1093 case RHD_OUTPUT_HDMI: 1097 case RHD_OUTPUT_HDMI:
1094 Private->HdmiEnabled = val->Bool; 1098 Private->HdmiEnabled = val->Bool;
1095 break; 1099 break;
1100 case RHD_OUTPUT_AUDIO_WORKAROUND:
1101 RHDHdmiSetAudioWorkaround(Private->Hdmi, val->Bool);
1102 break;
1096 default: 1103 default:
1097 return FALSE; 1104 return FALSE;
1098 } 1105 }
@@ -1104,6 +1111,9 @@ TMDSBPropertyControl(struct rhdOutput *Output,
1104 Output->Mode(Output, Private->Mode); 1111 Output->Mode(Output, Private->Mode);
1105 Output->Power(Output, RHD_POWER_ON); 1112 Output->Power(Output, RHD_POWER_ON);
1106 break; 1113 break;
1114 case RHD_OUTPUT_AUDIO_WORKAROUND:
1115 RHDHdmiCommitAudioWorkaround(Private->Hdmi);
1116 break;
1107 default: 1117 default:
1108 return FALSE; 1118 return FALSE;
1109 } 1119 }
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
260 if(!Output->Property(Output, rhdPropertySet, RHD_OUTPUT_HDMI, &val)) 260 if(!Output->Property(Output, rhdPropertySet, RHD_OUTPUT_HDMI, &val))
261 xf86DrvMsg(rhdPtr->scrnIndex, X_WARNING, "Failed to %s HDMI on %s\n", val.Bool ? "disable" : "enable", Output->Name); 261 xf86DrvMsg(rhdPtr->scrnIndex, X_WARNING, "Failed to %s HDMI on %s\n", val.Bool ? "disable" : "enable", Output->Name);
262 } 262 }
263
264 /* check config option if we should enable audio workaround */
265 if (Output->Property(Output, rhdPropertyCheck, RHD_OUTPUT_AUDIO_WORKAROUND, NULL)) {
266 union rhdPropertyData val;
267 switch(RhdParseBooleanOption(&rhdPtr->audioWorkaround, Connector->Name)) {
268 case RHD_OPTION_NOT_SET:
269 case RHD_OPTION_OFF:
270 val.Bool = FALSE;
271 break;
272 case RHD_OPTION_ON:
273 case RHD_OPTION_DEFAULT:
274 val.Bool = TRUE;
275 break;
276 }
277 if(!Output->Property(Output, rhdPropertySet, RHD_OUTPUT_AUDIO_WORKAROUND, &val))
278 xf86DrvMsg(rhdPtr->scrnIndex, X_WARNING,
279 "Failed to %s audio workaorund on %s\n",
280 val.Bool ? "disable" : "enable", Output->Name);
281 }
263} 282}
264 283
265/* 284/*
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 {
59enum rhdOutputProperty { 59enum rhdOutputProperty {
60 RHD_OUTPUT_BACKLIGHT, 60 RHD_OUTPUT_BACKLIGHT,
61 RHD_OUTPUT_COHERENT, 61 RHD_OUTPUT_COHERENT,
62 RHD_OUTPUT_HDMI 62 RHD_OUTPUT_HDMI,
63 RHD_OUTPUT_AUDIO_WORKAROUND
63}; 64};
64 65
65enum rhdOutputAllocation { 66enum 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 {
130#define ATOM_BACKLIGHT "Backlight" 130#define ATOM_BACKLIGHT "Backlight"
131#define ATOM_COHERENT "_Coherent" 131#define ATOM_COHERENT "_Coherent"
132#define ATOM_HDMI "_HDMI" 132#define ATOM_HDMI "_HDMI"
133#define ATOM_AUDIO_WORKAROUND "_AudioStreamSilence"
133#define ATOM_ATOMBIOS "_AtomBIOS" 134#define ATOM_ATOMBIOS "_AtomBIOS"
134 135
135static Atom atom_SignalFormat, atom_ConnectorType, atom_ConnectorNumber, 136static Atom atom_SignalFormat, atom_ConnectorType, atom_ConnectorNumber,
136 atom_OutputNumber, atom_PanningArea, atom_Backlight, atom_Coherent, 137 atom_OutputNumber, atom_PanningArea, atom_Backlight, atom_Coherent,
137 atom_HdmiProperty; 138 atom_HdmiProperty, atom_AudioWorkaround;
138static Atom atom_unknown, atom_VGA, atom_TMDS, atom_LVDS, atom_DisplayPort, atom_TV; 139static Atom atom_unknown, atom_VGA, atom_TMDS, atom_LVDS, atom_DisplayPort, atom_TV;
139static Atom atom_DVI, atom_DVII, atom_DVID, atom_DVIA, atom_HDMI, atom_Panel; 140static Atom atom_DVI, atom_DVII, atom_DVID, atom_DVIA, atom_HDMI, atom_Panel;
140static Atom atom_EDID, atom_EDID2, atom_AtomBIOS; 141static Atom atom_EDID, atom_EDID2, atom_AtomBIOS;
@@ -713,6 +714,30 @@ rhdRROutputCreateResources(xf86OutputPtr out)
713 __func__, err); 714 __func__, err);
714 } 715 }
715 } 716 }
717 if (rout->Output->Property(rout->Output, rhdPropertyCheck, RHD_OUTPUT_AUDIO_WORKAROUND, NULL)) {
718 atom_AudioWorkaround = MakeAtom(ATOM_AUDIO_WORKAROUND, sizeof(ATOM_AUDIO_WORKAROUND)-1, TRUE);
719
720 range[0] = 0;
721 range[1] = 1;
722 err = RRConfigureOutputProperty(out->randr_output, atom_AudioWorkaround,
723 FALSE, TRUE, FALSE, 2, range);
724 if (err != 0)
725 xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR,
726 "RRConfigureOutputProperty error: %d\n", err);
727 else {
728 union rhdPropertyData val;
729
730 if (!rout->Output->Property(rout->Output, rhdPropertyGet, RHD_OUTPUT_AUDIO_WORKAROUND, &val))
731 val.Bool = 1;
732 err = RRChangeOutputProperty(out->randr_output, atom_AudioWorkaround,
733 XA_INTEGER, 32, PropModeReplace,
734 1, &val.Bool, FALSE, FALSE);
735 if (err != 0)
736 xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR,
737 "In %s RRChangeOutputProperty error: %d\n",
738 __func__, err);
739 }
740 }
716 741
717 } 742 }
718} 743}
@@ -1408,6 +1433,20 @@ rhdRROutputSetProperty(xf86OutputPtr out, Atom property,
1408 RHD_OUTPUT_HDMI, NULL); 1433 RHD_OUTPUT_HDMI, NULL);
1409 } 1434 }
1410 return FALSE; 1435 return FALSE;
1436 } else if (property == atom_AudioWorkaround) {
1437 if (value->type != XA_INTEGER || value->format != 32) {
1438 xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "%s: wrong value\n", __func__);
1439 return FALSE;
1440 }
1441 if (rout->Output->Property) {
1442 union rhdPropertyData val;
1443 val.Bool = *(int*)(value->data);
1444 if(rout->Output->Property(rout->Output, rhdPropertySet,
1445 RHD_OUTPUT_AUDIO_WORKAROUND, &val))
1446 return rout->Output->Property(rout->Output, rhdPropertyCommit,
1447 RHD_OUTPUT_AUDIO_WORKAROUND, NULL);
1448 }
1449 return FALSE;
1411#if ENABLE_PROPERTY_ATOMBIOS 1450#if ENABLE_PROPERTY_ATOMBIOS
1412 } else if (property == atom_AtomBIOS) { 1451 } else if (property == atom_AtomBIOS) {
1413 if (value->type != XA_STRING || value->format != 8) 1452 if (value->type != XA_STRING || value->format != 8)
@@ -1585,6 +1624,17 @@ rhdRROutputGetProperty(xf86OutputPtr out, Atom property)
1585 err = RRChangeOutputProperty(out->randr_output, atom_HdmiProperty, 1624 err = RRChangeOutputProperty(out->randr_output, atom_HdmiProperty,
1586 XA_INTEGER, 32, PropModeReplace, 1625 XA_INTEGER, 32, PropModeReplace,
1587 1, &val.Bool, FALSE, FALSE); 1626 1, &val.Bool, FALSE, FALSE);
1627 } else if (property == atom_AudioWorkaround) {
1628 if (rout->Output->Property == NULL)
1629 return FALSE;
1630
1631 if (!rout->Output->Property(rout->Output, rhdPropertyGet,
1632 RHD_OUTPUT_AUDIO_WORKAROUND, &val))
1633 return FALSE;
1634
1635 err = RRChangeOutputProperty(out->randr_output, atom_AudioWorkaround,
1636 XA_INTEGER, 32, PropModeReplace,
1637 1, &val.Bool, FALSE, FALSE);
1588 } 1638 }
1589 1639
1590 RHDDebug(rhdPtr->scrnIndex, "%s 0x%x returns %d\n", __func__, property, err); 1640 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 {
1119enum { 1119enum {
1120 /* HDMI registers */ 1120 /* HDMI registers */
1121 HDMI_ENABLE = 0x00, 1121 HDMI_ENABLE = 0x00,
1122 HDMI_STATUS = 0x04,
1122 HDMI_CNTL = 0x08, 1123 HDMI_CNTL = 0x08,
1123 HDMI_UNKNOWN_0 = 0x0C, 1124 HDMI_UNKNOWN_0 = 0x0C,
1124 HDMI_AUDIOCNTL = 0x10, 1125 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,
243 switch (Property) { 243 switch (Property) {
244 case RHD_OUTPUT_COHERENT: 244 case RHD_OUTPUT_COHERENT:
245 case RHD_OUTPUT_HDMI: 245 case RHD_OUTPUT_HDMI:
246 case RHD_OUTPUT_AUDIO_WORKAROUND:
246 return TRUE; 247 return TRUE;
247 default: 248 default:
248 return FALSE; 249 return FALSE;
@@ -255,6 +256,9 @@ TMDSAPropertyControl(struct rhdOutput *Output,
255 case RHD_OUTPUT_HDMI: 256 case RHD_OUTPUT_HDMI:
256 val->Bool = Private->HdmiEnabled; 257 val->Bool = Private->HdmiEnabled;
257 return TRUE; 258 return TRUE;
259 case RHD_OUTPUT_AUDIO_WORKAROUND:
260 val->Bool = RHDHdmiGetAudioWorkaround(Private->Hdmi);
261 return TRUE;
258 default: 262 default:
259 return FALSE; 263 return FALSE;
260 } 264 }
@@ -267,6 +271,9 @@ TMDSAPropertyControl(struct rhdOutput *Output,
267 case RHD_OUTPUT_HDMI: 271 case RHD_OUTPUT_HDMI:
268 Private->HdmiEnabled = val->Bool; 272 Private->HdmiEnabled = val->Bool;
269 break; 273 break;
274 case RHD_OUTPUT_AUDIO_WORKAROUND:
275 RHDHdmiSetAudioWorkaround(Private->Hdmi, val->Bool);
276 break;
270 default: 277 default:
271 return FALSE; 278 return FALSE;
272 } 279 }
@@ -278,6 +285,9 @@ TMDSAPropertyControl(struct rhdOutput *Output,
278 Output->Mode(Output, Private->Mode); 285 Output->Mode(Output, Private->Mode);
279 Output->Power(Output, RHD_POWER_ON); 286 Output->Power(Output, RHD_POWER_ON);
280 break; 287 break;
288 case RHD_OUTPUT_AUDIO_WORKAROUND:
289 RHDHdmiCommitAudioWorkaround(Private->Hdmi);
290 break;
281 default: 291 default:
282 return FALSE; 292 return FALSE;
283 } 293 }