aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/patch_intelhdmi.c
diff options
context:
space:
mode:
authorWu Fengguang <wfg@linux.intel.com>2008-11-18 19:56:17 -0500
committerTakashi Iwai <tiwai@suse.de>2008-11-19 01:35:36 -0500
commit698544de8a31a7cadc26c27cbaa69ae82dd4f86c (patch)
tree6a12a06f9fa95af1ef1ad94eb1db59dac453a683 /sound/pci/hda/patch_intelhdmi.c
parent903b21d8b7bb49d3438abdd7b9d4145511e1cba2 (diff)
ALSA: hda: HDMI channel allocations for audio infoframe
To play a 3+ channels LPCM/DSD stream via HDMI, - HDMI sink must tell HDMI source about its speaker placements (via ELD, speaker-allocation field) - HDMI source must tell the HDMI sink about channel allocation (via audio infoframe, channel-allocation field) (related docs: HDMI 1.3a spec section 7.4, CEA-861-D section 7.5.3 and 6.6) This patch attempts to set the CA(channel-allocation) byte in the audio infoframe according to - the number of channels in the current stream - the speakers attached to the HDMI sink A channel_allocations[] line must meet the following two criteria to be considered as a valid candidate for CA: 1) its number of allocated channels = substream->runtime->channels 2) its speakers are a subset of the available ones on the sink side If there are multiple candidates, the first one is selected. This simple policy shall cheat the sink into playing music, but may direct data to the wrong speakers. Signed-off-by: Wu Fengguang <wfg@linux.intel.com> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda/patch_intelhdmi.c')
-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