diff options
-rw-r--r-- | sound/pci/hda/patch_intelhdmi.c | 205 |
1 files changed, 205 insertions, 0 deletions
diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 028fce996aa2..6b5c3e2cf93b 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c | |||
@@ -89,6 +89,132 @@ struct hdmi_audio_infoframe { | |||
89 | }; | 89 | }; |
90 | 90 | ||
91 | /* | 91 | /* |
92 | * CEA speaker placement: | ||
93 | * | ||
94 | * FLH FCH FRH | ||
95 | * FLW FL FLC FC FRC FR FRW | ||
96 | * | ||
97 | * LFE | ||
98 | * TC | ||
99 | * | ||
100 | * RL RLC RC RRC RR | ||
101 | * | ||
102 | * The Left/Right Surround channel _notions_ LS/RS in SMPTE 320M corresponds to | ||
103 | * CEA RL/RR; The SMPTE channel _assignment_ C/LFE is swapped to CEA LFE/FC. | ||
104 | */ | ||
105 | enum cea_speaker_placement { | ||
106 | FL = (1 << 0), /* Front Left */ | ||
107 | FC = (1 << 1), /* Front Center */ | ||
108 | FR = (1 << 2), /* Front Right */ | ||
109 | FLC = (1 << 3), /* Front Left Center */ | ||
110 | FRC = (1 << 4), /* Front Right Center */ | ||
111 | RL = (1 << 5), /* Rear Left */ | ||
112 | RC = (1 << 6), /* Rear Center */ | ||
113 | RR = (1 << 7), /* Rear Right */ | ||
114 | RLC = (1 << 8), /* Rear Left Center */ | ||
115 | RRC = (1 << 9), /* Rear Right Center */ | ||
116 | LFE = (1 << 10), /* Low Frequency Effect */ | ||
117 | FLW = (1 << 11), /* Front Left Wide */ | ||
118 | FRW = (1 << 12), /* Front Right Wide */ | ||
119 | FLH = (1 << 13), /* Front Left High */ | ||
120 | FCH = (1 << 14), /* Front Center High */ | ||
121 | FRH = (1 << 15), /* Front Right High */ | ||
122 | TC = (1 << 16), /* Top Center */ | ||
123 | }; | ||
124 | |||
125 | /* | ||
126 | * ELD SA bits in the CEA Speaker Allocation data block | ||
127 | */ | ||
128 | static int eld_speaker_allocation_bits[] = { | ||
129 | [0] = FL | FR, | ||
130 | [1] = LFE, | ||
131 | [2] = FC, | ||
132 | [3] = RL | RR, | ||
133 | [4] = RC, | ||
134 | [5] = FLC | FRC, | ||
135 | [6] = RLC | RRC, | ||
136 | /* the following are not defined in ELD yet */ | ||
137 | [7] = FLW | FRW, | ||
138 | [8] = FLH | FRH, | ||
139 | [9] = TC, | ||
140 | [10] = FCH, | ||
141 | }; | ||
142 | |||
143 | struct cea_channel_speaker_allocation { | ||
144 | int ca_index; | ||
145 | int speakers[8]; | ||
146 | |||
147 | /* derived values, just for convenience */ | ||
148 | int channels; | ||
149 | int spk_mask; | ||
150 | }; | ||
151 | |||
152 | /* | ||
153 | * This is an ordered list! | ||
154 | * | ||
155 | * The preceding ones have better chances to be selected by | ||
156 | * hdmi_setup_channel_allocation(). | ||
157 | */ | ||
158 | static struct cea_channel_speaker_allocation channel_allocations[] = { | ||
159 | /* channel: 8 7 6 5 4 3 2 1 */ | ||
160 | { .ca_index = 0x00, .speakers = { 0, 0, 0, 0, 0, 0, FR, FL } }, | ||
161 | /* 2.1 */ | ||
162 | { .ca_index = 0x01, .speakers = { 0, 0, 0, 0, 0, LFE, FR, FL } }, | ||
163 | /* dolby surround */ | ||
164 | { .ca_index = 0x02, .speakers = { 0, 0, 0, 0, FC, 0, FR, FL } }, | ||
165 | { .ca_index = 0x03, .speakers = { 0, 0, 0, 0, FC, LFE, FR, FL } }, | ||
166 | { .ca_index = 0x04, .speakers = { 0, 0, 0, RC, 0, 0, FR, FL } }, | ||
167 | { .ca_index = 0x05, .speakers = { 0, 0, 0, RC, 0, LFE, FR, FL } }, | ||
168 | { .ca_index = 0x06, .speakers = { 0, 0, 0, RC, FC, 0, FR, FL } }, | ||
169 | { .ca_index = 0x07, .speakers = { 0, 0, 0, RC, FC, LFE, FR, FL } }, | ||
170 | { .ca_index = 0x08, .speakers = { 0, 0, RR, RL, 0, 0, FR, FL } }, | ||
171 | { .ca_index = 0x09, .speakers = { 0, 0, RR, RL, 0, LFE, FR, FL } }, | ||
172 | { .ca_index = 0x0a, .speakers = { 0, 0, RR, RL, FC, 0, FR, FL } }, | ||
173 | /* 5.1 */ | ||
174 | { .ca_index = 0x0b, .speakers = { 0, 0, RR, RL, FC, LFE, FR, FL } }, | ||
175 | { .ca_index = 0x0c, .speakers = { 0, RC, RR, RL, 0, 0, FR, FL } }, | ||
176 | { .ca_index = 0x0d, .speakers = { 0, RC, RR, RL, 0, LFE, FR, FL } }, | ||
177 | { .ca_index = 0x0e, .speakers = { 0, RC, RR, RL, FC, 0, FR, FL } }, | ||
178 | /* 6.1 */ | ||
179 | { .ca_index = 0x0f, .speakers = { 0, RC, RR, RL, FC, LFE, FR, FL } }, | ||
180 | { .ca_index = 0x10, .speakers = { RRC, RLC, RR, RL, 0, 0, FR, FL } }, | ||
181 | { .ca_index = 0x11, .speakers = { RRC, RLC, RR, RL, 0, LFE, FR, FL } }, | ||
182 | { .ca_index = 0x12, .speakers = { RRC, RLC, RR, RL, FC, 0, FR, FL } }, | ||
183 | /* 7.1 */ | ||
184 | { .ca_index = 0x13, .speakers = { RRC, RLC, RR, RL, FC, LFE, FR, FL } }, | ||
185 | { .ca_index = 0x14, .speakers = { FRC, FLC, 0, 0, 0, 0, FR, FL } }, | ||
186 | { .ca_index = 0x15, .speakers = { FRC, FLC, 0, 0, 0, LFE, FR, FL } }, | ||
187 | { .ca_index = 0x16, .speakers = { FRC, FLC, 0, 0, FC, 0, FR, FL } }, | ||
188 | { .ca_index = 0x17, .speakers = { FRC, FLC, 0, 0, FC, LFE, FR, FL } }, | ||
189 | { .ca_index = 0x18, .speakers = { FRC, FLC, 0, RC, 0, 0, FR, FL } }, | ||
190 | { .ca_index = 0x19, .speakers = { FRC, FLC, 0, RC, 0, LFE, FR, FL } }, | ||
191 | { .ca_index = 0x1a, .speakers = { FRC, FLC, 0, RC, FC, 0, FR, FL } }, | ||
192 | { .ca_index = 0x1b, .speakers = { FRC, FLC, 0, RC, FC, LFE, FR, FL } }, | ||
193 | { .ca_index = 0x1c, .speakers = { FRC, FLC, RR, RL, 0, 0, FR, FL } }, | ||
194 | { .ca_index = 0x1d, .speakers = { FRC, FLC, RR, RL, 0, LFE, FR, FL } }, | ||
195 | { .ca_index = 0x1e, .speakers = { FRC, FLC, RR, RL, FC, 0, FR, FL } }, | ||
196 | { .ca_index = 0x1f, .speakers = { FRC, FLC, RR, RL, FC, LFE, FR, FL } }, | ||
197 | { .ca_index = 0x20, .speakers = { 0, FCH, RR, RL, FC, 0, FR, FL } }, | ||
198 | { .ca_index = 0x21, .speakers = { 0, FCH, RR, RL, FC, LFE, FR, FL } }, | ||
199 | { .ca_index = 0x22, .speakers = { TC, 0, RR, RL, FC, 0, FR, FL } }, | ||
200 | { .ca_index = 0x23, .speakers = { TC, 0, RR, RL, FC, LFE, FR, FL } }, | ||
201 | { .ca_index = 0x24, .speakers = { FRH, FLH, RR, RL, 0, 0, FR, FL } }, | ||
202 | { .ca_index = 0x25, .speakers = { FRH, FLH, RR, RL, 0, LFE, FR, FL } }, | ||
203 | { .ca_index = 0x26, .speakers = { FRW, FLW, RR, RL, 0, 0, FR, FL } }, | ||
204 | { .ca_index = 0x27, .speakers = { FRW, FLW, RR, RL, 0, LFE, FR, FL } }, | ||
205 | { .ca_index = 0x28, .speakers = { TC, RC, RR, RL, FC, 0, FR, FL } }, | ||
206 | { .ca_index = 0x29, .speakers = { TC, RC, RR, RL, FC, LFE, FR, FL } }, | ||
207 | { .ca_index = 0x2a, .speakers = { FCH, RC, RR, RL, FC, 0, FR, FL } }, | ||
208 | { .ca_index = 0x2b, .speakers = { FCH, RC, RR, RL, FC, LFE, FR, FL } }, | ||
209 | { .ca_index = 0x2c, .speakers = { TC, FCH, RR, RL, FC, 0, FR, FL } }, | ||
210 | { .ca_index = 0x2d, .speakers = { TC, FCH, RR, RL, FC, LFE, FR, FL } }, | ||
211 | { .ca_index = 0x2e, .speakers = { FRH, FLH, RR, RL, FC, 0, FR, FL } }, | ||
212 | { .ca_index = 0x2f, .speakers = { FRH, FLH, RR, RL, FC, LFE, FR, FL } }, | ||
213 | { .ca_index = 0x30, .speakers = { FRW, FLW, RR, RL, FC, 0, FR, FL } }, | ||
214 | { .ca_index = 0x31, .speakers = { FRW, FLW, RR, RL, FC, LFE, FR, FL } }, | ||
215 | }; | ||
216 | |||
217 | /* | ||
92 | * HDMI routines | 218 | * HDMI routines |
93 | */ | 219 | */ |
94 | 220 | ||
@@ -260,6 +386,81 @@ static void hdmi_fill_audio_infoframe(struct hda_codec *codec, | |||
260 | hdmi_write_dip_byte(codec, PIN_NID, params[i]); | 386 | hdmi_write_dip_byte(codec, PIN_NID, params[i]); |
261 | } | 387 | } |
262 | 388 | ||
389 | /* | ||
390 | * Compute derived values in channel_allocations[]. | ||
391 | */ | ||
392 | static void init_channel_allocations(void) | ||
393 | { | ||
394 | int i, j; | ||
395 | struct cea_channel_speaker_allocation *p; | ||
396 | |||
397 | for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) { | ||
398 | p = channel_allocations + i; | ||
399 | p->channels = 0; | ||
400 | p->spk_mask = 0; | ||
401 | for (j = 0; j < ARRAY_SIZE(p->speakers); j++) | ||
402 | if (p->speakers[j]) { | ||
403 | p->channels++; | ||
404 | p->spk_mask |= p->speakers[j]; | ||
405 | } | ||
406 | } | ||
407 | } | ||
408 | |||
409 | /* | ||
410 | * The transformation takes two steps: | ||
411 | * | ||
412 | * eld->spk_alloc => (eld_speaker_allocation_bits[]) => spk_mask | ||
413 | * spk_mask => (channel_allocations[]) => ai->CA | ||
414 | * | ||
415 | * TODO: it could select the wrong CA from multiple candidates. | ||
416 | */ | ||
417 | static int hdmi_setup_channel_allocation(struct hda_codec *codec, | ||
418 | struct hdmi_audio_infoframe *ai) | ||
419 | { | ||
420 | struct intel_hdmi_spec *spec = codec->spec; | ||
421 | struct sink_eld *eld = &spec->sink; | ||
422 | int i; | ||
423 | int spk_mask = 0; | ||
424 | int channels = 1 + (ai->CC02_CT47 & 0x7); | ||
425 | char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; | ||
426 | |||
427 | /* | ||
428 | * CA defaults to 0 for basic stereo audio | ||
429 | */ | ||
430 | if (!eld->eld_ver) | ||
431 | return 0; | ||
432 | if (!eld->spk_alloc) | ||
433 | return 0; | ||
434 | if (channels <= 2) | ||
435 | return 0; | ||
436 | |||
437 | /* | ||
438 | * expand ELD's speaker allocation mask | ||
439 | * | ||
440 | * ELD tells the speaker mask in a compact(paired) form, | ||
441 | * expand ELD's notions to match the ones used by audio infoframe. | ||
442 | */ | ||
443 | for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) { | ||
444 | if (eld->spk_alloc & (1 << i)) | ||
445 | spk_mask |= eld_speaker_allocation_bits[i]; | ||
446 | } | ||
447 | |||
448 | /* search for the first working match in the CA table */ | ||
449 | for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) { | ||
450 | if (channels == channel_allocations[i].channels && | ||
451 | (spk_mask & channel_allocations[i].spk_mask) == | ||
452 | channel_allocations[i].spk_mask) { | ||
453 | ai->CA = channel_allocations[i].ca_index; | ||
454 | return 0; | ||
455 | } | ||
456 | } | ||
457 | |||
458 | snd_print_channel_allocation(eld->spk_alloc, buf, sizeof(buf)); | ||
459 | snd_printd(KERN_INFO "failed to setup channel allocation: %d of %s\n", | ||
460 | channels, buf); | ||
461 | return -1; | ||
462 | } | ||
463 | |||
263 | static void hdmi_setup_audio_infoframe(struct hda_codec *codec, | 464 | static void hdmi_setup_audio_infoframe(struct hda_codec *codec, |
264 | struct snd_pcm_substream *substream) | 465 | struct snd_pcm_substream *substream) |
265 | { | 466 | { |
@@ -270,6 +471,8 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, | |||
270 | .CC02_CT47 = substream->runtime->channels - 1, | 471 | .CC02_CT47 = substream->runtime->channels - 1, |
271 | }; | 472 | }; |
272 | 473 | ||
474 | hdmi_setup_channel_allocation(codec, &ai); | ||
475 | |||
273 | hdmi_fill_audio_infoframe(codec, &ai); | 476 | hdmi_fill_audio_infoframe(codec, &ai); |
274 | } | 477 | } |
275 | 478 | ||
@@ -455,6 +658,8 @@ static int patch_intel_hdmi(struct hda_codec *codec) | |||
455 | 658 | ||
456 | snd_hda_eld_proc_new(codec, &spec->sink); | 659 | snd_hda_eld_proc_new(codec, &spec->sink); |
457 | 660 | ||
661 | init_channel_allocations(); | ||
662 | |||
458 | return 0; | 663 | return 0; |
459 | } | 664 | } |
460 | 665 | ||