aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/pci/hda/patch_intelhdmi.c205
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 */
105enum 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 */
128static 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
143struct 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 */
158static 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 */
392static 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*/
417static 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
263static void hdmi_setup_audio_infoframe(struct hda_codec *codec, 464static 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