aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnssi Hannula <anssi.hannula@iki.fi>2013-10-28 19:19:16 -0400
committerAlex Deucher <alexander.deucher@amd.com>2013-11-08 12:33:35 -0500
commit0f57bca922ed2180056aa1f948536236488b4a0d (patch)
tree0d26a99b5d8a027f9e6c7275264ccbe511a2c474
parent91915260ea5ed9d9b19bfb75d53c989c8ada2ab0 (diff)
drm/radeon/audio: fix missing multichannel PCM SAD in some cases
The current code writing SADs to the audio registers seems to assume that there is at most a single SAD per audio format. However, that is not the case. Especially for PCM it is somewhat common for sinks to have two SADs, one for 8-channel and one for 2-channel audio, which may have different supported sample rates (i.e. the sink supports stereo audio at higher sample rates than multichannel audio). Because of this, only the 2-channel SAD may be used if it appears before the 8-channel SAD. Unless other SADs require otherwise, this may cause the ALSA HDA driver to allow stereo playback only. Fix the code to pick the PCM SAD with the highest number of channels, while merging the rate masks of PCM SADs with lower amount of channels into the additional stereo rate mask byte. Technically there are even more cases to handle (multiple non-PCM SADs of the same type, more than two PCM SADs with varying channel counts, etc), but those have not actually been encountered in the field and handling them would be non-trivial. Example affected EDID from Onkyo TX-SR674 specifying 192kHz stereo support and 96kHz 8-channel support (and other 8-channel compressed formats): 00ffffffffffff003dcb010000000001 ffff0103800000780a0dc9a057479827 12484c00000001010101010101010101 010101010101011d8018711c1620582c 2500c48e2100009e011d007251d01e20 6e285500c48e2100001e000000fc0054 582d53523637342020202020000000fd 00313d0f2e08000a202020202020019b 02032f724f8504030f0e07069413121e 1d1615012f097f070f1f071707503707 503f07c0834f000066030c00ffff808c 0ad08a20e02d10103e9600c48e210000 18011d80d0721c1620102c2580c48e21 00009e011d00bc52d01e20b8285540c4 8e2100001e8c0ad090204031200c4055 00c48e210000180000000000000000a8 Signed-off-by: Anssi Hannula <anssi.hannula@iki.fi> Tested-by: Andre Heider <a.heider@gmail.com> Cc: Rafał Miłecki <zajec5@gmail.com> Acked-by: Rafał Miłecki <zajec5@gmail.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
-rw-r--r--drivers/gpu/drm/radeon/dce6_afmt.c20
-rw-r--r--drivers/gpu/drm/radeon/evergreen_hdmi.c20
-rw-r--r--drivers/gpu/drm/radeon/r600_hdmi.c20
3 files changed, 45 insertions, 15 deletions
diff --git a/drivers/gpu/drm/radeon/dce6_afmt.c b/drivers/gpu/drm/radeon/dce6_afmt.c
index ab92620ed83a..85c4993b53e1 100644
--- a/drivers/gpu/drm/radeon/dce6_afmt.c
+++ b/drivers/gpu/drm/radeon/dce6_afmt.c
@@ -244,20 +244,30 @@ void dce6_afmt_write_sad_regs(struct drm_encoder *encoder)
244 244
245 for (i = 0; i < ARRAY_SIZE(eld_reg_to_type); i++) { 245 for (i = 0; i < ARRAY_SIZE(eld_reg_to_type); i++) {
246 u32 value = 0; 246 u32 value = 0;
247 u8 stereo_freqs = 0;
248 int max_channels = -1;
247 int j; 249 int j;
248 250
249 for (j = 0; j < sad_count; j++) { 251 for (j = 0; j < sad_count; j++) {
250 struct cea_sad *sad = &sads[j]; 252 struct cea_sad *sad = &sads[j];
251 253
252 if (sad->format == eld_reg_to_type[i][1]) { 254 if (sad->format == eld_reg_to_type[i][1]) {
253 value = MAX_CHANNELS(sad->channels) | 255 if (sad->channels > max_channels) {
254 DESCRIPTOR_BYTE_2(sad->byte2) | 256 value = MAX_CHANNELS(sad->channels) |
255 SUPPORTED_FREQUENCIES(sad->freq); 257 DESCRIPTOR_BYTE_2(sad->byte2) |
258 SUPPORTED_FREQUENCIES(sad->freq);
259 max_channels = sad->channels;
260 }
261
256 if (sad->format == HDMI_AUDIO_CODING_TYPE_PCM) 262 if (sad->format == HDMI_AUDIO_CODING_TYPE_PCM)
257 value |= SUPPORTED_FREQUENCIES_STEREO(sad->freq); 263 stereo_freqs |= sad->freq;
258 break; 264 else
265 break;
259 } 266 }
260 } 267 }
268
269 value |= SUPPORTED_FREQUENCIES_STEREO(stereo_freqs);
270
261 WREG32_ENDPOINT(offset, eld_reg_to_type[i][0], value); 271 WREG32_ENDPOINT(offset, eld_reg_to_type[i][0], value);
262 } 272 }
263 273
diff --git a/drivers/gpu/drm/radeon/evergreen_hdmi.c b/drivers/gpu/drm/radeon/evergreen_hdmi.c
index a82b6f78d7f2..adbfef870501 100644
--- a/drivers/gpu/drm/radeon/evergreen_hdmi.c
+++ b/drivers/gpu/drm/radeon/evergreen_hdmi.c
@@ -184,20 +184,30 @@ static void evergreen_hdmi_write_sad_regs(struct drm_encoder *encoder)
184 184
185 for (i = 0; i < ARRAY_SIZE(eld_reg_to_type); i++) { 185 for (i = 0; i < ARRAY_SIZE(eld_reg_to_type); i++) {
186 u32 value = 0; 186 u32 value = 0;
187 u8 stereo_freqs = 0;
188 int max_channels = -1;
187 int j; 189 int j;
188 190
189 for (j = 0; j < sad_count; j++) { 191 for (j = 0; j < sad_count; j++) {
190 struct cea_sad *sad = &sads[j]; 192 struct cea_sad *sad = &sads[j];
191 193
192 if (sad->format == eld_reg_to_type[i][1]) { 194 if (sad->format == eld_reg_to_type[i][1]) {
193 value = MAX_CHANNELS(sad->channels) | 195 if (sad->channels > max_channels) {
194 DESCRIPTOR_BYTE_2(sad->byte2) | 196 value = MAX_CHANNELS(sad->channels) |
195 SUPPORTED_FREQUENCIES(sad->freq); 197 DESCRIPTOR_BYTE_2(sad->byte2) |
198 SUPPORTED_FREQUENCIES(sad->freq);
199 max_channels = sad->channels;
200 }
201
196 if (sad->format == HDMI_AUDIO_CODING_TYPE_PCM) 202 if (sad->format == HDMI_AUDIO_CODING_TYPE_PCM)
197 value |= SUPPORTED_FREQUENCIES_STEREO(sad->freq); 203 stereo_freqs |= sad->freq;
198 break; 204 else
205 break;
199 } 206 }
200 } 207 }
208
209 value |= SUPPORTED_FREQUENCIES_STEREO(stereo_freqs);
210
201 WREG32(eld_reg_to_type[i][0], value); 211 WREG32(eld_reg_to_type[i][0], value);
202 } 212 }
203 213
diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c
index 0977c303aeec..ace4dec21bc2 100644
--- a/drivers/gpu/drm/radeon/r600_hdmi.c
+++ b/drivers/gpu/drm/radeon/r600_hdmi.c
@@ -388,20 +388,30 @@ static void dce3_2_afmt_write_sad_regs(struct drm_encoder *encoder)
388 388
389 for (i = 0; i < ARRAY_SIZE(eld_reg_to_type); i++) { 389 for (i = 0; i < ARRAY_SIZE(eld_reg_to_type); i++) {
390 u32 value = 0; 390 u32 value = 0;
391 u8 stereo_freqs = 0;
392 int max_channels = -1;
391 int j; 393 int j;
392 394
393 for (j = 0; j < sad_count; j++) { 395 for (j = 0; j < sad_count; j++) {
394 struct cea_sad *sad = &sads[j]; 396 struct cea_sad *sad = &sads[j];
395 397
396 if (sad->format == eld_reg_to_type[i][1]) { 398 if (sad->format == eld_reg_to_type[i][1]) {
397 value = MAX_CHANNELS(sad->channels) | 399 if (sad->channels > max_channels) {
398 DESCRIPTOR_BYTE_2(sad->byte2) | 400 value = MAX_CHANNELS(sad->channels) |
399 SUPPORTED_FREQUENCIES(sad->freq); 401 DESCRIPTOR_BYTE_2(sad->byte2) |
402 SUPPORTED_FREQUENCIES(sad->freq);
403 max_channels = sad->channels;
404 }
405
400 if (sad->format == HDMI_AUDIO_CODING_TYPE_PCM) 406 if (sad->format == HDMI_AUDIO_CODING_TYPE_PCM)
401 value |= SUPPORTED_FREQUENCIES_STEREO(sad->freq); 407 stereo_freqs |= sad->freq;
402 break; 408 else
409 break;
403 } 410 }
404 } 411 }
412
413 value |= SUPPORTED_FREQUENCIES_STEREO(stereo_freqs);
414
405 WREG32(eld_reg_to_type[i][0], value); 415 WREG32(eld_reg_to_type[i][0], value);
406 } 416 }
407 417