blob: 338546531c1783bc79d85be18c388dfc0dce7d6b [file] [log] [blame]
Wu Fengguang079d88c2010-03-08 10:44:23 +08001/*
2 *
3 * patch_hdmi.c - routines for HDMI/DisplayPort codecs
4 *
5 * Copyright(c) 2008-2010 Intel Corporation. All rights reserved.
Takashi Iwai84eb01b2010-09-07 12:27:25 +02006 * Copyright (c) 2006 ATI Technologies Inc.
7 * Copyright (c) 2008 NVIDIA Corp. All rights reserved.
8 * Copyright (c) 2008 Wei Ni <wni@nvidia.com>
Wu Fengguang079d88c2010-03-08 10:44:23 +08009 *
10 * Authors:
11 * Wu Fengguang <wfg@linux.intel.com>
12 *
13 * Maintained by:
14 * Wu Fengguang <wfg@linux.intel.com>
15 *
16 * This program is free software; you can redistribute it and/or modify it
17 * under the terms of the GNU General Public License as published by the Free
18 * Software Foundation; either version 2 of the License, or (at your option)
19 * any later version.
20 *
21 * This program is distributed in the hope that it will be useful, but
22 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
23 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24 * for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software Foundation,
28 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29 */
30
Takashi Iwai84eb01b2010-09-07 12:27:25 +020031#include <linux/init.h>
32#include <linux/delay.h>
33#include <linux/slab.h>
Takashi Iwai0ebaa242011-01-11 18:11:04 +010034#include <linux/moduleparam.h>
Takashi Iwai84eb01b2010-09-07 12:27:25 +020035#include <sound/core.h>
David Henningsson07acecc2011-05-19 11:46:03 +020036#include <sound/jack.h>
Takashi Iwai84eb01b2010-09-07 12:27:25 +020037#include "hda_codec.h"
38#include "hda_local.h"
39
Takashi Iwai0ebaa242011-01-11 18:11:04 +010040static bool static_hdmi_pcm;
41module_param(static_hdmi_pcm, bool, 0644);
42MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info");
43
Takashi Iwai84eb01b2010-09-07 12:27:25 +020044/*
45 * The HDMI/DisplayPort configuration can be highly dynamic. A graphics device
46 * could support two independent pipes, each of them can be connected to one or
47 * more ports (DVI, HDMI or DisplayPort).
48 *
49 * The HDA correspondence of pipes/ports are converter/pin nodes.
50 */
Stephen Warren73926652011-05-25 12:42:13 -060051#define MAX_HDMI_CVTS 4
52#define MAX_HDMI_PINS 4
Wu Fengguang079d88c2010-03-08 10:44:23 +080053
54struct hdmi_spec {
55 int num_cvts;
56 int num_pins;
57 hda_nid_t cvt[MAX_HDMI_CVTS+1]; /* audio sources */
58 hda_nid_t pin[MAX_HDMI_PINS+1]; /* audio sinks */
59
60 /*
61 * source connection for each pin
62 */
63 hda_nid_t pin_cvt[MAX_HDMI_PINS+1];
64
65 /*
66 * HDMI sink attached to each pin
67 */
68 struct hdmi_eld sink_eld[MAX_HDMI_PINS];
69
70 /*
71 * export one pcm per pipe
72 */
73 struct hda_pcm pcm_rec[MAX_HDMI_CVTS];
Takashi Iwaibbbe3392010-08-13 08:45:23 +020074 struct hda_pcm_stream codec_pcm_pars[MAX_HDMI_CVTS];
Wu Fengguang079d88c2010-03-08 10:44:23 +080075
76 /*
Takashi Iwai84eb01b2010-09-07 12:27:25 +020077 * ati/nvhdmi specific
Wu Fengguang079d88c2010-03-08 10:44:23 +080078 */
79 struct hda_multi_out multiout;
Takashi Iwaifb79e1e2011-05-02 12:17:41 +020080 const struct hda_pcm_stream *pcm_playback;
Wu Fengguang079d88c2010-03-08 10:44:23 +080081};
82
83
84struct hdmi_audio_infoframe {
85 u8 type; /* 0x84 */
86 u8 ver; /* 0x01 */
87 u8 len; /* 0x0a */
88
Wu Fengguang53d7d692010-09-21 14:25:49 +080089 u8 checksum;
90
Wu Fengguang079d88c2010-03-08 10:44:23 +080091 u8 CC02_CT47; /* CC in bits 0:2, CT in 4:7 */
92 u8 SS01_SF24;
93 u8 CXT04;
94 u8 CA;
95 u8 LFEPBL01_LSV36_DM_INH7;
Wu Fengguang53d7d692010-09-21 14:25:49 +080096};
97
98struct dp_audio_infoframe {
99 u8 type; /* 0x84 */
100 u8 len; /* 0x1b */
101 u8 ver; /* 0x11 << 2 */
102
103 u8 CC02_CT47; /* match with HDMI infoframe from this on */
104 u8 SS01_SF24;
105 u8 CXT04;
106 u8 CA;
107 u8 LFEPBL01_LSV36_DM_INH7;
Wu Fengguang079d88c2010-03-08 10:44:23 +0800108};
109
Takashi Iwai2b203dbb2011-02-11 12:17:30 +0100110union audio_infoframe {
111 struct hdmi_audio_infoframe hdmi;
112 struct dp_audio_infoframe dp;
113 u8 bytes[0];
114};
115
Wu Fengguang079d88c2010-03-08 10:44:23 +0800116/*
117 * CEA speaker placement:
118 *
119 * FLH FCH FRH
120 * FLW FL FLC FC FRC FR FRW
121 *
122 * LFE
123 * TC
124 *
125 * RL RLC RC RRC RR
126 *
127 * The Left/Right Surround channel _notions_ LS/RS in SMPTE 320M corresponds to
128 * CEA RL/RR; The SMPTE channel _assignment_ C/LFE is swapped to CEA LFE/FC.
129 */
130enum cea_speaker_placement {
131 FL = (1 << 0), /* Front Left */
132 FC = (1 << 1), /* Front Center */
133 FR = (1 << 2), /* Front Right */
134 FLC = (1 << 3), /* Front Left Center */
135 FRC = (1 << 4), /* Front Right Center */
136 RL = (1 << 5), /* Rear Left */
137 RC = (1 << 6), /* Rear Center */
138 RR = (1 << 7), /* Rear Right */
139 RLC = (1 << 8), /* Rear Left Center */
140 RRC = (1 << 9), /* Rear Right Center */
141 LFE = (1 << 10), /* Low Frequency Effect */
142 FLW = (1 << 11), /* Front Left Wide */
143 FRW = (1 << 12), /* Front Right Wide */
144 FLH = (1 << 13), /* Front Left High */
145 FCH = (1 << 14), /* Front Center High */
146 FRH = (1 << 15), /* Front Right High */
147 TC = (1 << 16), /* Top Center */
148};
149
150/*
151 * ELD SA bits in the CEA Speaker Allocation data block
152 */
153static int eld_speaker_allocation_bits[] = {
154 [0] = FL | FR,
155 [1] = LFE,
156 [2] = FC,
157 [3] = RL | RR,
158 [4] = RC,
159 [5] = FLC | FRC,
160 [6] = RLC | RRC,
161 /* the following are not defined in ELD yet */
162 [7] = FLW | FRW,
163 [8] = FLH | FRH,
164 [9] = TC,
165 [10] = FCH,
166};
167
168struct cea_channel_speaker_allocation {
169 int ca_index;
170 int speakers[8];
171
172 /* derived values, just for convenience */
173 int channels;
174 int spk_mask;
175};
176
177/*
178 * ALSA sequence is:
179 *
180 * surround40 surround41 surround50 surround51 surround71
181 * ch0 front left = = = =
182 * ch1 front right = = = =
183 * ch2 rear left = = = =
184 * ch3 rear right = = = =
185 * ch4 LFE center center center
186 * ch5 LFE LFE
187 * ch6 side left
188 * ch7 side right
189 *
190 * surround71 = {FL, FR, RLC, RRC, FC, LFE, RL, RR}
191 */
192static int hdmi_channel_mapping[0x32][8] = {
193 /* stereo */
194 [0x00] = { 0x00, 0x11, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7 },
195 /* 2.1 */
196 [0x01] = { 0x00, 0x11, 0x22, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7 },
197 /* Dolby Surround */
198 [0x02] = { 0x00, 0x11, 0x23, 0xf2, 0xf4, 0xf5, 0xf6, 0xf7 },
199 /* surround40 */
200 [0x08] = { 0x00, 0x11, 0x24, 0x35, 0xf3, 0xf2, 0xf6, 0xf7 },
201 /* 4ch */
202 [0x03] = { 0x00, 0x11, 0x23, 0x32, 0x44, 0xf5, 0xf6, 0xf7 },
203 /* surround41 */
Jerry Zhou9396d312010-09-21 14:44:51 +0800204 [0x09] = { 0x00, 0x11, 0x24, 0x35, 0x42, 0xf3, 0xf6, 0xf7 },
Wu Fengguang079d88c2010-03-08 10:44:23 +0800205 /* surround50 */
206 [0x0a] = { 0x00, 0x11, 0x24, 0x35, 0x43, 0xf2, 0xf6, 0xf7 },
207 /* surround51 */
208 [0x0b] = { 0x00, 0x11, 0x24, 0x35, 0x43, 0x52, 0xf6, 0xf7 },
209 /* 7.1 */
210 [0x13] = { 0x00, 0x11, 0x26, 0x37, 0x43, 0x52, 0x64, 0x75 },
211};
212
213/*
214 * This is an ordered list!
215 *
216 * The preceding ones have better chances to be selected by
Wu Fengguang53d7d692010-09-21 14:25:49 +0800217 * hdmi_channel_allocation().
Wu Fengguang079d88c2010-03-08 10:44:23 +0800218 */
219static struct cea_channel_speaker_allocation channel_allocations[] = {
220/* channel: 7 6 5 4 3 2 1 0 */
221{ .ca_index = 0x00, .speakers = { 0, 0, 0, 0, 0, 0, FR, FL } },
222 /* 2.1 */
223{ .ca_index = 0x01, .speakers = { 0, 0, 0, 0, 0, LFE, FR, FL } },
224 /* Dolby Surround */
225{ .ca_index = 0x02, .speakers = { 0, 0, 0, 0, FC, 0, FR, FL } },
226 /* surround40 */
227{ .ca_index = 0x08, .speakers = { 0, 0, RR, RL, 0, 0, FR, FL } },
228 /* surround41 */
229{ .ca_index = 0x09, .speakers = { 0, 0, RR, RL, 0, LFE, FR, FL } },
230 /* surround50 */
231{ .ca_index = 0x0a, .speakers = { 0, 0, RR, RL, FC, 0, FR, FL } },
232 /* surround51 */
233{ .ca_index = 0x0b, .speakers = { 0, 0, RR, RL, FC, LFE, FR, FL } },
234 /* 6.1 */
235{ .ca_index = 0x0f, .speakers = { 0, RC, RR, RL, FC, LFE, FR, FL } },
236 /* surround71 */
237{ .ca_index = 0x13, .speakers = { RRC, RLC, RR, RL, FC, LFE, FR, FL } },
238
239{ .ca_index = 0x03, .speakers = { 0, 0, 0, 0, FC, LFE, FR, FL } },
240{ .ca_index = 0x04, .speakers = { 0, 0, 0, RC, 0, 0, FR, FL } },
241{ .ca_index = 0x05, .speakers = { 0, 0, 0, RC, 0, LFE, FR, FL } },
242{ .ca_index = 0x06, .speakers = { 0, 0, 0, RC, FC, 0, FR, FL } },
243{ .ca_index = 0x07, .speakers = { 0, 0, 0, RC, FC, LFE, FR, FL } },
244{ .ca_index = 0x0c, .speakers = { 0, RC, RR, RL, 0, 0, FR, FL } },
245{ .ca_index = 0x0d, .speakers = { 0, RC, RR, RL, 0, LFE, FR, FL } },
246{ .ca_index = 0x0e, .speakers = { 0, RC, RR, RL, FC, 0, FR, FL } },
247{ .ca_index = 0x10, .speakers = { RRC, RLC, RR, RL, 0, 0, FR, FL } },
248{ .ca_index = 0x11, .speakers = { RRC, RLC, RR, RL, 0, LFE, FR, FL } },
249{ .ca_index = 0x12, .speakers = { RRC, RLC, RR, RL, FC, 0, FR, FL } },
250{ .ca_index = 0x14, .speakers = { FRC, FLC, 0, 0, 0, 0, FR, FL } },
251{ .ca_index = 0x15, .speakers = { FRC, FLC, 0, 0, 0, LFE, FR, FL } },
252{ .ca_index = 0x16, .speakers = { FRC, FLC, 0, 0, FC, 0, FR, FL } },
253{ .ca_index = 0x17, .speakers = { FRC, FLC, 0, 0, FC, LFE, FR, FL } },
254{ .ca_index = 0x18, .speakers = { FRC, FLC, 0, RC, 0, 0, FR, FL } },
255{ .ca_index = 0x19, .speakers = { FRC, FLC, 0, RC, 0, LFE, FR, FL } },
256{ .ca_index = 0x1a, .speakers = { FRC, FLC, 0, RC, FC, 0, FR, FL } },
257{ .ca_index = 0x1b, .speakers = { FRC, FLC, 0, RC, FC, LFE, FR, FL } },
258{ .ca_index = 0x1c, .speakers = { FRC, FLC, RR, RL, 0, 0, FR, FL } },
259{ .ca_index = 0x1d, .speakers = { FRC, FLC, RR, RL, 0, LFE, FR, FL } },
260{ .ca_index = 0x1e, .speakers = { FRC, FLC, RR, RL, FC, 0, FR, FL } },
261{ .ca_index = 0x1f, .speakers = { FRC, FLC, RR, RL, FC, LFE, FR, FL } },
262{ .ca_index = 0x20, .speakers = { 0, FCH, RR, RL, FC, 0, FR, FL } },
263{ .ca_index = 0x21, .speakers = { 0, FCH, RR, RL, FC, LFE, FR, FL } },
264{ .ca_index = 0x22, .speakers = { TC, 0, RR, RL, FC, 0, FR, FL } },
265{ .ca_index = 0x23, .speakers = { TC, 0, RR, RL, FC, LFE, FR, FL } },
266{ .ca_index = 0x24, .speakers = { FRH, FLH, RR, RL, 0, 0, FR, FL } },
267{ .ca_index = 0x25, .speakers = { FRH, FLH, RR, RL, 0, LFE, FR, FL } },
268{ .ca_index = 0x26, .speakers = { FRW, FLW, RR, RL, 0, 0, FR, FL } },
269{ .ca_index = 0x27, .speakers = { FRW, FLW, RR, RL, 0, LFE, FR, FL } },
270{ .ca_index = 0x28, .speakers = { TC, RC, RR, RL, FC, 0, FR, FL } },
271{ .ca_index = 0x29, .speakers = { TC, RC, RR, RL, FC, LFE, FR, FL } },
272{ .ca_index = 0x2a, .speakers = { FCH, RC, RR, RL, FC, 0, FR, FL } },
273{ .ca_index = 0x2b, .speakers = { FCH, RC, RR, RL, FC, LFE, FR, FL } },
274{ .ca_index = 0x2c, .speakers = { TC, FCH, RR, RL, FC, 0, FR, FL } },
275{ .ca_index = 0x2d, .speakers = { TC, FCH, RR, RL, FC, LFE, FR, FL } },
276{ .ca_index = 0x2e, .speakers = { FRH, FLH, RR, RL, FC, 0, FR, FL } },
277{ .ca_index = 0x2f, .speakers = { FRH, FLH, RR, RL, FC, LFE, FR, FL } },
278{ .ca_index = 0x30, .speakers = { FRW, FLW, RR, RL, FC, 0, FR, FL } },
279{ .ca_index = 0x31, .speakers = { FRW, FLW, RR, RL, FC, LFE, FR, FL } },
280};
281
282
283/*
284 * HDMI routines
285 */
286
287static int hda_node_index(hda_nid_t *nids, hda_nid_t nid)
288{
289 int i;
290
291 for (i = 0; nids[i]; i++)
292 if (nids[i] == nid)
293 return i;
294
295 snd_printk(KERN_WARNING "HDMI: nid %d not registered\n", nid);
296 return -EINVAL;
297}
298
Wu Fengguang079d88c2010-03-08 10:44:23 +0800299#ifdef BE_PARANOID
300static void hdmi_get_dip_index(struct hda_codec *codec, hda_nid_t pin_nid,
301 int *packet_index, int *byte_index)
302{
303 int val;
304
305 val = snd_hda_codec_read(codec, pin_nid, 0,
306 AC_VERB_GET_HDMI_DIP_INDEX, 0);
307
308 *packet_index = val >> 5;
309 *byte_index = val & 0x1f;
310}
311#endif
312
313static void hdmi_set_dip_index(struct hda_codec *codec, hda_nid_t pin_nid,
314 int packet_index, int byte_index)
315{
316 int val;
317
318 val = (packet_index << 5) | (byte_index & 0x1f);
319
320 snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_INDEX, val);
321}
322
323static void hdmi_write_dip_byte(struct hda_codec *codec, hda_nid_t pin_nid,
324 unsigned char val)
325{
326 snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_DATA, val);
327}
328
329static void hdmi_enable_output(struct hda_codec *codec, hda_nid_t pin_nid)
330{
331 /* Unmute */
332 if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP)
333 snd_hda_codec_write(codec, pin_nid, 0,
334 AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
335 /* Enable pin out */
336 snd_hda_codec_write(codec, pin_nid, 0,
337 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
338}
339
340static int hdmi_get_channel_count(struct hda_codec *codec, hda_nid_t nid)
341{
342 return 1 + snd_hda_codec_read(codec, nid, 0,
343 AC_VERB_GET_CVT_CHAN_COUNT, 0);
344}
345
346static void hdmi_set_channel_count(struct hda_codec *codec,
347 hda_nid_t nid, int chs)
348{
349 if (chs != hdmi_get_channel_count(codec, nid))
350 snd_hda_codec_write(codec, nid, 0,
351 AC_VERB_SET_CVT_CHAN_COUNT, chs - 1);
352}
353
354
355/*
356 * Channel mapping routines
357 */
358
359/*
360 * Compute derived values in channel_allocations[].
361 */
362static void init_channel_allocations(void)
363{
364 int i, j;
365 struct cea_channel_speaker_allocation *p;
366
367 for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
368 p = channel_allocations + i;
369 p->channels = 0;
370 p->spk_mask = 0;
371 for (j = 0; j < ARRAY_SIZE(p->speakers); j++)
372 if (p->speakers[j]) {
373 p->channels++;
374 p->spk_mask |= p->speakers[j];
375 }
376 }
377}
378
379/*
380 * The transformation takes two steps:
381 *
382 * eld->spk_alloc => (eld_speaker_allocation_bits[]) => spk_mask
383 * spk_mask => (channel_allocations[]) => ai->CA
384 *
385 * TODO: it could select the wrong CA from multiple candidates.
386*/
Wu Fengguang53d7d692010-09-21 14:25:49 +0800387static int hdmi_channel_allocation(struct hda_codec *codec, hda_nid_t nid,
388 int channels)
Wu Fengguang079d88c2010-03-08 10:44:23 +0800389{
390 struct hdmi_spec *spec = codec->spec;
391 struct hdmi_eld *eld;
392 int i;
Wu Fengguang53d7d692010-09-21 14:25:49 +0800393 int ca = 0;
Wu Fengguang079d88c2010-03-08 10:44:23 +0800394 int spk_mask = 0;
Wu Fengguang079d88c2010-03-08 10:44:23 +0800395 char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE];
396
397 /*
398 * CA defaults to 0 for basic stereo audio
399 */
400 if (channels <= 2)
401 return 0;
402
403 i = hda_node_index(spec->pin_cvt, nid);
404 if (i < 0)
405 return 0;
406 eld = &spec->sink_eld[i];
407
408 /*
409 * HDMI sink's ELD info cannot always be retrieved for now, e.g.
410 * in console or for audio devices. Assume the highest speakers
411 * configuration, to _not_ prohibit multi-channel audio playback.
412 */
413 if (!eld->spk_alloc)
414 eld->spk_alloc = 0xffff;
415
416 /*
417 * expand ELD's speaker allocation mask
418 *
419 * ELD tells the speaker mask in a compact(paired) form,
420 * expand ELD's notions to match the ones used by Audio InfoFrame.
421 */
422 for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) {
423 if (eld->spk_alloc & (1 << i))
424 spk_mask |= eld_speaker_allocation_bits[i];
425 }
426
427 /* search for the first working match in the CA table */
428 for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
429 if (channels == channel_allocations[i].channels &&
430 (spk_mask & channel_allocations[i].spk_mask) ==
431 channel_allocations[i].spk_mask) {
Wu Fengguang53d7d692010-09-21 14:25:49 +0800432 ca = channel_allocations[i].ca_index;
Wu Fengguang079d88c2010-03-08 10:44:23 +0800433 break;
434 }
435 }
436
437 snd_print_channel_allocation(eld->spk_alloc, buf, sizeof(buf));
Wu Fengguang2abbf432010-03-08 10:45:38 +0800438 snd_printdd("HDMI: select CA 0x%x for %d-channel allocation: %s\n",
Wu Fengguang53d7d692010-09-21 14:25:49 +0800439 ca, channels, buf);
Wu Fengguang079d88c2010-03-08 10:44:23 +0800440
Wu Fengguang53d7d692010-09-21 14:25:49 +0800441 return ca;
Wu Fengguang079d88c2010-03-08 10:44:23 +0800442}
443
444static void hdmi_debug_channel_mapping(struct hda_codec *codec,
445 hda_nid_t pin_nid)
446{
447#ifdef CONFIG_SND_DEBUG_VERBOSE
448 int i;
449 int slot;
450
451 for (i = 0; i < 8; i++) {
452 slot = snd_hda_codec_read(codec, pin_nid, 0,
453 AC_VERB_GET_HDMI_CHAN_SLOT, i);
454 printk(KERN_DEBUG "HDMI: ASP channel %d => slot %d\n",
455 slot >> 4, slot & 0xf);
456 }
457#endif
458}
459
460
461static void hdmi_setup_channel_mapping(struct hda_codec *codec,
462 hda_nid_t pin_nid,
Wu Fengguang53d7d692010-09-21 14:25:49 +0800463 int ca)
Wu Fengguang079d88c2010-03-08 10:44:23 +0800464{
465 int i;
Wu Fengguang079d88c2010-03-08 10:44:23 +0800466 int err;
467
468 if (hdmi_channel_mapping[ca][1] == 0) {
469 for (i = 0; i < channel_allocations[ca].channels; i++)
470 hdmi_channel_mapping[ca][i] = i | (i << 4);
471 for (; i < 8; i++)
472 hdmi_channel_mapping[ca][i] = 0xf | (i << 4);
473 }
474
475 for (i = 0; i < 8; i++) {
476 err = snd_hda_codec_write(codec, pin_nid, 0,
477 AC_VERB_SET_HDMI_CHAN_SLOT,
478 hdmi_channel_mapping[ca][i]);
479 if (err) {
Wu Fengguang2abbf432010-03-08 10:45:38 +0800480 snd_printdd(KERN_NOTICE
481 "HDMI: channel mapping failed\n");
Wu Fengguang079d88c2010-03-08 10:44:23 +0800482 break;
483 }
484 }
485
486 hdmi_debug_channel_mapping(codec, pin_nid);
487}
488
489
490/*
491 * Audio InfoFrame routines
492 */
493
494/*
495 * Enable Audio InfoFrame Transmission
496 */
497static void hdmi_start_infoframe_trans(struct hda_codec *codec,
498 hda_nid_t pin_nid)
499{
500 hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
501 snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_XMIT,
502 AC_DIPXMIT_BEST);
503}
504
505/*
506 * Disable Audio InfoFrame Transmission
507 */
508static void hdmi_stop_infoframe_trans(struct hda_codec *codec,
509 hda_nid_t pin_nid)
510{
511 hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
512 snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_XMIT,
513 AC_DIPXMIT_DISABLE);
514}
515
516static void hdmi_debug_dip_size(struct hda_codec *codec, hda_nid_t pin_nid)
517{
518#ifdef CONFIG_SND_DEBUG_VERBOSE
519 int i;
520 int size;
521
522 size = snd_hdmi_get_eld_size(codec, pin_nid);
523 printk(KERN_DEBUG "HDMI: ELD buf size is %d\n", size);
524
525 for (i = 0; i < 8; i++) {
526 size = snd_hda_codec_read(codec, pin_nid, 0,
527 AC_VERB_GET_HDMI_DIP_SIZE, i);
528 printk(KERN_DEBUG "HDMI: DIP GP[%d] buf size is %d\n", i, size);
529 }
530#endif
531}
532
533static void hdmi_clear_dip_buffers(struct hda_codec *codec, hda_nid_t pin_nid)
534{
535#ifdef BE_PARANOID
536 int i, j;
537 int size;
538 int pi, bi;
539 for (i = 0; i < 8; i++) {
540 size = snd_hda_codec_read(codec, pin_nid, 0,
541 AC_VERB_GET_HDMI_DIP_SIZE, i);
542 if (size == 0)
543 continue;
544
545 hdmi_set_dip_index(codec, pin_nid, i, 0x0);
546 for (j = 1; j < 1000; j++) {
547 hdmi_write_dip_byte(codec, pin_nid, 0x0);
548 hdmi_get_dip_index(codec, pin_nid, &pi, &bi);
549 if (pi != i)
550 snd_printd(KERN_INFO "dip index %d: %d != %d\n",
551 bi, pi, i);
552 if (bi == 0) /* byte index wrapped around */
553 break;
554 }
555 snd_printd(KERN_INFO
556 "HDMI: DIP GP[%d] buf reported size=%d, written=%d\n",
557 i, size, j);
558 }
559#endif
560}
561
Wu Fengguang53d7d692010-09-21 14:25:49 +0800562static void hdmi_checksum_audio_infoframe(struct hdmi_audio_infoframe *hdmi_ai)
Wu Fengguang079d88c2010-03-08 10:44:23 +0800563{
Wu Fengguang53d7d692010-09-21 14:25:49 +0800564 u8 *bytes = (u8 *)hdmi_ai;
Wu Fengguang079d88c2010-03-08 10:44:23 +0800565 u8 sum = 0;
566 int i;
567
Wu Fengguang53d7d692010-09-21 14:25:49 +0800568 hdmi_ai->checksum = 0;
Wu Fengguang079d88c2010-03-08 10:44:23 +0800569
Wu Fengguang53d7d692010-09-21 14:25:49 +0800570 for (i = 0; i < sizeof(*hdmi_ai); i++)
Wu Fengguang079d88c2010-03-08 10:44:23 +0800571 sum += bytes[i];
572
Wu Fengguang53d7d692010-09-21 14:25:49 +0800573 hdmi_ai->checksum = -sum;
Wu Fengguang079d88c2010-03-08 10:44:23 +0800574}
575
576static void hdmi_fill_audio_infoframe(struct hda_codec *codec,
577 hda_nid_t pin_nid,
Wu Fengguang53d7d692010-09-21 14:25:49 +0800578 u8 *dip, int size)
Wu Fengguang079d88c2010-03-08 10:44:23 +0800579{
Wu Fengguang079d88c2010-03-08 10:44:23 +0800580 int i;
581
582 hdmi_debug_dip_size(codec, pin_nid);
583 hdmi_clear_dip_buffers(codec, pin_nid); /* be paranoid */
584
Wu Fengguang079d88c2010-03-08 10:44:23 +0800585 hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
Wu Fengguang53d7d692010-09-21 14:25:49 +0800586 for (i = 0; i < size; i++)
587 hdmi_write_dip_byte(codec, pin_nid, dip[i]);
Wu Fengguang079d88c2010-03-08 10:44:23 +0800588}
589
590static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid,
Wu Fengguang53d7d692010-09-21 14:25:49 +0800591 u8 *dip, int size)
Wu Fengguang079d88c2010-03-08 10:44:23 +0800592{
Wu Fengguang079d88c2010-03-08 10:44:23 +0800593 u8 val;
594 int i;
595
596 if (snd_hda_codec_read(codec, pin_nid, 0, AC_VERB_GET_HDMI_DIP_XMIT, 0)
597 != AC_DIPXMIT_BEST)
598 return false;
599
600 hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
Wu Fengguang53d7d692010-09-21 14:25:49 +0800601 for (i = 0; i < size; i++) {
Wu Fengguang079d88c2010-03-08 10:44:23 +0800602 val = snd_hda_codec_read(codec, pin_nid, 0,
603 AC_VERB_GET_HDMI_DIP_DATA, 0);
Wu Fengguang53d7d692010-09-21 14:25:49 +0800604 if (val != dip[i])
Wu Fengguang079d88c2010-03-08 10:44:23 +0800605 return false;
606 }
607
608 return true;
609}
610
611static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid,
612 struct snd_pcm_substream *substream)
613{
614 struct hdmi_spec *spec = codec->spec;
615 hda_nid_t pin_nid;
Wu Fengguang53d7d692010-09-21 14:25:49 +0800616 int channels = substream->runtime->channels;
617 int ca;
Wu Fengguang079d88c2010-03-08 10:44:23 +0800618 int i;
Takashi Iwai2b203dbb2011-02-11 12:17:30 +0100619 union audio_infoframe ai;
Wu Fengguang079d88c2010-03-08 10:44:23 +0800620
Wu Fengguang53d7d692010-09-21 14:25:49 +0800621 ca = hdmi_channel_allocation(codec, nid, channels);
Wu Fengguang079d88c2010-03-08 10:44:23 +0800622
623 for (i = 0; i < spec->num_pins; i++) {
624 if (spec->pin_cvt[i] != nid)
625 continue;
626 if (!spec->sink_eld[i].monitor_present)
627 continue;
628
629 pin_nid = spec->pin[i];
Wu Fengguang53d7d692010-09-21 14:25:49 +0800630
Takashi Iwai2b203dbb2011-02-11 12:17:30 +0100631 memset(&ai, 0, sizeof(ai));
Wu Fengguang53d7d692010-09-21 14:25:49 +0800632 if (spec->sink_eld[i].conn_type == 0) { /* HDMI */
Takashi Iwai2b203dbb2011-02-11 12:17:30 +0100633 struct hdmi_audio_infoframe *hdmi_ai = &ai.hdmi;
Wu Fengguang53d7d692010-09-21 14:25:49 +0800634
Wu Fengguang53d7d692010-09-21 14:25:49 +0800635 hdmi_ai->type = 0x84;
636 hdmi_ai->ver = 0x01;
637 hdmi_ai->len = 0x0a;
638 hdmi_ai->CC02_CT47 = channels - 1;
Takashi Iwai11839ae2011-02-08 17:25:49 +0100639 hdmi_ai->CA = ca;
Wu Fengguang53d7d692010-09-21 14:25:49 +0800640 hdmi_checksum_audio_infoframe(hdmi_ai);
641 } else if (spec->sink_eld[i].conn_type == 1) { /* DisplayPort */
Takashi Iwai2b203dbb2011-02-11 12:17:30 +0100642 struct dp_audio_infoframe *dp_ai = &ai.dp;
Wu Fengguang53d7d692010-09-21 14:25:49 +0800643
Wu Fengguang53d7d692010-09-21 14:25:49 +0800644 dp_ai->type = 0x84;
645 dp_ai->len = 0x1b;
646 dp_ai->ver = 0x11 << 2;
647 dp_ai->CC02_CT47 = channels - 1;
Takashi Iwai11839ae2011-02-08 17:25:49 +0100648 dp_ai->CA = ca;
Wu Fengguang53d7d692010-09-21 14:25:49 +0800649 } else {
650 snd_printd("HDMI: unknown connection type at pin %d\n",
651 pin_nid);
652 continue;
653 }
654
655 /*
656 * sizeof(ai) is used instead of sizeof(*hdmi_ai) or
657 * sizeof(*dp_ai) to avoid partial match/update problems when
658 * the user switches between HDMI/DP monitors.
659 */
Takashi Iwai2b203dbb2011-02-11 12:17:30 +0100660 if (!hdmi_infoframe_uptodate(codec, pin_nid, ai.bytes,
661 sizeof(ai))) {
Wu Fengguang2abbf432010-03-08 10:45:38 +0800662 snd_printdd("hdmi_setup_audio_infoframe: "
663 "cvt=%d pin=%d channels=%d\n",
664 nid, pin_nid,
Wu Fengguang53d7d692010-09-21 14:25:49 +0800665 channels);
666 hdmi_setup_channel_mapping(codec, pin_nid, ca);
Wu Fengguang079d88c2010-03-08 10:44:23 +0800667 hdmi_stop_infoframe_trans(codec, pin_nid);
Wu Fengguang53d7d692010-09-21 14:25:49 +0800668 hdmi_fill_audio_infoframe(codec, pin_nid,
Takashi Iwai2b203dbb2011-02-11 12:17:30 +0100669 ai.bytes, sizeof(ai));
Wu Fengguang079d88c2010-03-08 10:44:23 +0800670 hdmi_start_infoframe_trans(codec, pin_nid);
671 }
672 }
673}
674
675
676/*
677 * Unsolicited events
678 */
679
Takashi Iwai38faddb2010-07-28 14:21:55 +0200680static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid,
681 struct hdmi_eld *eld);
682
Wu Fengguang079d88c2010-03-08 10:44:23 +0800683static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
684{
685 struct hdmi_spec *spec = codec->spec;
Stephen Warren5d44f922011-05-24 17:11:17 -0600686 int pin_nid = res >> AC_UNSOL_RES_TAG_SHIFT;
687 int pd = !!(res & AC_UNSOL_RES_PD);
Wu Fengguang079d88c2010-03-08 10:44:23 +0800688 int eldv = !!(res & AC_UNSOL_RES_ELDV);
689 int index;
690
691 printk(KERN_INFO
692 "HDMI hot plug event: Pin=%d Presence_Detect=%d ELD_Valid=%d\n",
Stephen Warren5d44f922011-05-24 17:11:17 -0600693 pin_nid, pd, eldv);
Wu Fengguang079d88c2010-03-08 10:44:23 +0800694
Stephen Warren5d44f922011-05-24 17:11:17 -0600695 index = hda_node_index(spec->pin, pin_nid);
Wu Fengguang079d88c2010-03-08 10:44:23 +0800696 if (index < 0)
697 return;
698
Stephen Warren5d44f922011-05-24 17:11:17 -0600699 hdmi_present_sense(codec, pin_nid, &spec->sink_eld[index]);
Wu Fengguang079d88c2010-03-08 10:44:23 +0800700}
701
702static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
703{
704 int tag = res >> AC_UNSOL_RES_TAG_SHIFT;
705 int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT;
706 int cp_state = !!(res & AC_UNSOL_RES_CP_STATE);
707 int cp_ready = !!(res & AC_UNSOL_RES_CP_READY);
708
709 printk(KERN_INFO
710 "HDMI CP event: PIN=%d SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n",
711 tag,
712 subtag,
713 cp_state,
714 cp_ready);
715
716 /* TODO */
717 if (cp_state)
718 ;
719 if (cp_ready)
720 ;
721}
722
723
724static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res)
725{
726 struct hdmi_spec *spec = codec->spec;
727 int tag = res >> AC_UNSOL_RES_TAG_SHIFT;
728 int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT;
729
730 if (hda_node_index(spec->pin, tag) < 0) {
731 snd_printd(KERN_INFO "Unexpected HDMI event tag 0x%x\n", tag);
732 return;
733 }
734
735 if (subtag == 0)
736 hdmi_intrinsic_event(codec, res);
737 else
738 hdmi_non_intrinsic_event(codec, res);
739}
740
741/*
742 * Callbacks
743 */
744
Takashi Iwai92f10b32010-08-03 14:21:00 +0200745/* HBR should be Non-PCM, 8 channels */
746#define is_hbr_format(format) \
747 ((format & AC_FMT_TYPE_NON_PCM) && (format & AC_FMT_CHAN_MASK) == 7)
748
Anssi Hannulaea87d1c2010-08-03 13:28:58 +0300749static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t nid,
Wu Fengguang079d88c2010-03-08 10:44:23 +0800750 u32 stream_tag, int format)
751{
Anssi Hannulaea87d1c2010-08-03 13:28:58 +0300752 struct hdmi_spec *spec = codec->spec;
Anssi Hannulaea87d1c2010-08-03 13:28:58 +0300753 int pinctl;
754 int new_pinctl = 0;
755 int i;
756
757 for (i = 0; i < spec->num_pins; i++) {
758 if (spec->pin_cvt[i] != nid)
759 continue;
760 if (!(snd_hda_query_pin_caps(codec, spec->pin[i]) & AC_PINCAP_HBR))
761 continue;
762
763 pinctl = snd_hda_codec_read(codec, spec->pin[i], 0,
764 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
765
766 new_pinctl = pinctl & ~AC_PINCTL_EPT;
Takashi Iwai92f10b32010-08-03 14:21:00 +0200767 if (is_hbr_format(format))
Anssi Hannulaea87d1c2010-08-03 13:28:58 +0300768 new_pinctl |= AC_PINCTL_EPT_HBR;
769 else
770 new_pinctl |= AC_PINCTL_EPT_NATIVE;
771
772 snd_printdd("hdmi_setup_stream: "
773 "NID=0x%x, %spinctl=0x%x\n",
774 spec->pin[i],
775 pinctl == new_pinctl ? "" : "new-",
776 new_pinctl);
777
778 if (pinctl != new_pinctl)
779 snd_hda_codec_write(codec, spec->pin[i], 0,
780 AC_VERB_SET_PIN_WIDGET_CONTROL,
781 new_pinctl);
782 }
783
Takashi Iwai92f10b32010-08-03 14:21:00 +0200784 if (is_hbr_format(format) && !new_pinctl) {
Anssi Hannulaea87d1c2010-08-03 13:28:58 +0300785 snd_printdd("hdmi_setup_stream: HBR is not supported\n");
786 return -EINVAL;
787 }
Wu Fengguang079d88c2010-03-08 10:44:23 +0800788
Takashi Iwai4f347602010-08-20 09:41:59 +0200789 snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
Anssi Hannulaea87d1c2010-08-03 13:28:58 +0300790 return 0;
Wu Fengguang079d88c2010-03-08 10:44:23 +0800791}
792
793/*
Takashi Iwaibbbe3392010-08-13 08:45:23 +0200794 * HDA PCM callbacks
795 */
796static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
797 struct hda_codec *codec,
798 struct snd_pcm_substream *substream)
799{
800 struct hdmi_spec *spec = codec->spec;
801 struct hdmi_eld *eld;
802 struct hda_pcm_stream *codec_pars;
Takashi Iwai639cef02011-01-14 10:30:46 +0100803 struct snd_pcm_runtime *runtime = substream->runtime;
Takashi Iwaibbbe3392010-08-13 08:45:23 +0200804 unsigned int idx;
805
806 for (idx = 0; idx < spec->num_cvts; idx++)
807 if (hinfo->nid == spec->cvt[idx])
808 break;
809 if (snd_BUG_ON(idx >= spec->num_cvts) ||
810 snd_BUG_ON(idx >= spec->num_pins))
811 return -EINVAL;
812
813 /* save the PCM info the codec provides */
814 codec_pars = &spec->codec_pcm_pars[idx];
815 if (!codec_pars->rates)
816 *codec_pars = *hinfo;
817
Stephen Warren2def8172011-06-01 11:14:20 -0600818 /* Initially set the converter's capabilities */
819 hinfo->channels_min = codec_pars->channels_min;
820 hinfo->channels_max = codec_pars->channels_max;
821 hinfo->rates = codec_pars->rates;
822 hinfo->formats = codec_pars->formats;
823 hinfo->maxbps = codec_pars->maxbps;
824
Takashi Iwaibbbe3392010-08-13 08:45:23 +0200825 eld = &spec->sink_eld[idx];
Stephen Warrenc3d52102011-06-01 11:14:16 -0600826 if (!static_hdmi_pcm && eld->eld_valid) {
Stephen Warren2def8172011-06-01 11:14:20 -0600827 snd_hdmi_eld_update_pcm_info(eld, hinfo);
Takashi Iwaibbbe3392010-08-13 08:45:23 +0200828 if (hinfo->channels_min > hinfo->channels_max ||
829 !hinfo->rates || !hinfo->formats)
830 return -ENODEV;
Takashi Iwaibbbe3392010-08-13 08:45:23 +0200831 }
Stephen Warren2def8172011-06-01 11:14:20 -0600832
833 /* Store the updated parameters */
Takashi Iwai639cef02011-01-14 10:30:46 +0100834 runtime->hw.channels_min = hinfo->channels_min;
835 runtime->hw.channels_max = hinfo->channels_max;
836 runtime->hw.formats = hinfo->formats;
837 runtime->hw.rates = hinfo->rates;
Takashi Iwai4fe2ca12011-01-14 10:33:26 +0100838
839 snd_pcm_hw_constraint_step(substream->runtime, 0,
840 SNDRV_PCM_HW_PARAM_CHANNELS, 2);
Takashi Iwaibbbe3392010-08-13 08:45:23 +0200841 return 0;
842}
843
844/*
Wu Fengguang079d88c2010-03-08 10:44:23 +0800845 * HDA/HDMI auto parsing
846 */
Wu Fengguang079d88c2010-03-08 10:44:23 +0800847static int hdmi_read_pin_conn(struct hda_codec *codec, hda_nid_t pin_nid)
848{
849 struct hdmi_spec *spec = codec->spec;
850 hda_nid_t conn_list[HDA_MAX_CONNECTIONS];
851 int conn_len, curr;
852 int index;
853
854 if (!(get_wcaps(codec, pin_nid) & AC_WCAP_CONN_LIST)) {
855 snd_printk(KERN_WARNING
856 "HDMI: pin %d wcaps %#x "
857 "does not support connection list\n",
858 pin_nid, get_wcaps(codec, pin_nid));
859 return -EINVAL;
860 }
861
862 conn_len = snd_hda_get_connections(codec, pin_nid, conn_list,
863 HDA_MAX_CONNECTIONS);
864 if (conn_len > 1)
865 curr = snd_hda_codec_read(codec, pin_nid, 0,
866 AC_VERB_GET_CONNECT_SEL, 0);
867 else
868 curr = 0;
869
870 index = hda_node_index(spec->pin, pin_nid);
871 if (index < 0)
872 return -EINVAL;
873
874 spec->pin_cvt[index] = conn_list[curr];
875
876 return 0;
877}
878
879static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid,
880 struct hdmi_eld *eld)
881{
Stephen Warren5d44f922011-05-24 17:11:17 -0600882 /*
883 * Always execute a GetPinSense verb here, even when called from
884 * hdmi_intrinsic_event; for some NVIDIA HW, the unsolicited
885 * response's PD bit is not the real PD value, but indicates that
886 * the real PD value changed. An older version of the HD-audio
887 * specification worked this way. Hence, we just ignore the data in
888 * the unsolicited response to avoid custom WARs.
889 */
Wu Fengguang079d88c2010-03-08 10:44:23 +0800890 int present = snd_hda_pin_sense(codec, pin_nid);
891
Stephen Warren5d44f922011-05-24 17:11:17 -0600892 memset(eld, 0, sizeof(*eld));
Wu Fengguang079d88c2010-03-08 10:44:23 +0800893
Stephen Warren5d44f922011-05-24 17:11:17 -0600894 eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE);
895 if (eld->monitor_present)
896 eld->eld_valid = !!(present & AC_PINSENSE_ELDV);
897 else
898 eld->eld_valid = 0;
899
900 printk(KERN_INFO
901 "HDMI status: Pin=%d Presence_Detect=%d ELD_Valid=%d\n",
902 pin_nid, eld->monitor_present, eld->eld_valid);
903
904 if (eld->eld_valid)
905 if (!snd_hdmi_get_eld(eld, codec, pin_nid))
906 snd_hdmi_show_eld(eld);
907
908 snd_hda_input_jack_report(codec, pin_nid);
Wu Fengguang079d88c2010-03-08 10:44:23 +0800909}
910
911static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
912{
913 struct hdmi_spec *spec = codec->spec;
David Henningsson07acecc2011-05-19 11:46:03 +0200914 int err;
Wu Fengguang079d88c2010-03-08 10:44:23 +0800915
916 if (spec->num_pins >= MAX_HDMI_PINS) {
917 snd_printk(KERN_WARNING
918 "HDMI: no space for pin %d\n", pin_nid);
Wu Fengguang3eaead52010-05-14 16:36:15 +0800919 return -E2BIG;
Wu Fengguang079d88c2010-03-08 10:44:23 +0800920 }
921
David Henningsson07acecc2011-05-19 11:46:03 +0200922 err = snd_hda_input_jack_add(codec, pin_nid,
923 SND_JACK_VIDEOOUT, NULL);
924 if (err < 0)
925 return err;
David Henningsson07acecc2011-05-19 11:46:03 +0200926
Wu Fengguang079d88c2010-03-08 10:44:23 +0800927 hdmi_present_sense(codec, pin_nid, &spec->sink_eld[spec->num_pins]);
928
929 spec->pin[spec->num_pins] = pin_nid;
930 spec->num_pins++;
931
Wu Fengguang079d88c2010-03-08 10:44:23 +0800932 return hdmi_read_pin_conn(codec, pin_nid);
933}
934
935static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t nid)
936{
David Henningsson116dcde2010-11-23 10:23:40 +0100937 int i, found_pin = 0;
Wu Fengguang079d88c2010-03-08 10:44:23 +0800938 struct hdmi_spec *spec = codec->spec;
939
David Henningsson116dcde2010-11-23 10:23:40 +0100940 for (i = 0; i < spec->num_pins; i++)
941 if (nid == spec->pin_cvt[i]) {
942 found_pin = 1;
943 break;
944 }
945
946 if (!found_pin) {
947 snd_printdd("HDMI: Skipping node %d (no connection)\n", nid);
948 return -EINVAL;
Wu Fengguang079d88c2010-03-08 10:44:23 +0800949 }
950
David Henningsson116dcde2010-11-23 10:23:40 +0100951 if (snd_BUG_ON(spec->num_cvts >= MAX_HDMI_CVTS))
952 return -E2BIG;
953
Wu Fengguang079d88c2010-03-08 10:44:23 +0800954 spec->cvt[spec->num_cvts] = nid;
955 spec->num_cvts++;
956
957 return 0;
958}
959
960static int hdmi_parse_codec(struct hda_codec *codec)
961{
962 hda_nid_t nid;
963 int i, nodes;
David Henningsson116dcde2010-11-23 10:23:40 +0100964 int num_tmp_cvts = 0;
965 hda_nid_t tmp_cvt[MAX_HDMI_CVTS];
Wu Fengguang079d88c2010-03-08 10:44:23 +0800966
967 nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid);
968 if (!nid || nodes < 0) {
969 snd_printk(KERN_WARNING "HDMI: failed to get afg sub nodes\n");
970 return -EINVAL;
971 }
972
973 for (i = 0; i < nodes; i++, nid++) {
974 unsigned int caps;
975 unsigned int type;
David Henningsson116dcde2010-11-23 10:23:40 +0100976 unsigned int config;
Wu Fengguang079d88c2010-03-08 10:44:23 +0800977
978 caps = snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP);
979 type = get_wcaps_type(caps);
980
981 if (!(caps & AC_WCAP_DIGITAL))
982 continue;
983
984 switch (type) {
985 case AC_WID_AUD_OUT:
David Henningsson116dcde2010-11-23 10:23:40 +0100986 if (num_tmp_cvts >= MAX_HDMI_CVTS) {
987 snd_printk(KERN_WARNING
988 "HDMI: no space for converter %d\n", nid);
989 continue;
990 }
991 tmp_cvt[num_tmp_cvts] = nid;
992 num_tmp_cvts++;
Wu Fengguang079d88c2010-03-08 10:44:23 +0800993 break;
994 case AC_WID_PIN:
995 caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
996 if (!(caps & (AC_PINCAP_HDMI | AC_PINCAP_DP)))
997 continue;
David Henningsson116dcde2010-11-23 10:23:40 +0100998
999 config = snd_hda_codec_read(codec, nid, 0,
1000 AC_VERB_GET_CONFIG_DEFAULT, 0);
1001 if (get_defcfg_connect(config) == AC_JACK_PORT_NONE)
1002 continue;
1003
Wu Fengguang3eaead52010-05-14 16:36:15 +08001004 hdmi_add_pin(codec, nid);
Wu Fengguang079d88c2010-03-08 10:44:23 +08001005 break;
1006 }
1007 }
1008
David Henningsson116dcde2010-11-23 10:23:40 +01001009 for (i = 0; i < num_tmp_cvts; i++)
1010 hdmi_add_cvt(codec, tmp_cvt[i]);
1011
Wu Fengguang079d88c2010-03-08 10:44:23 +08001012 /*
1013 * G45/IbexPeak don't support EPSS: the unsolicited pin hot plug event
1014 * can be lost and presence sense verb will become inaccurate if the
1015 * HDA link is powered off at hot plug or hw initialization time.
1016 */
1017#ifdef CONFIG_SND_HDA_POWER_SAVE
1018 if (!(snd_hda_param_read(codec, codec->afg, AC_PAR_POWER_STATE) &
1019 AC_PWRST_EPSS))
1020 codec->bus->power_keep_link_on = 1;
1021#endif
1022
1023 return 0;
1024}
1025
Takashi Iwai84eb01b2010-09-07 12:27:25 +02001026/*
1027 */
1028static char *generic_hdmi_pcm_names[MAX_HDMI_CVTS] = {
1029 "HDMI 0",
1030 "HDMI 1",
1031 "HDMI 2",
Stephen Warren73926652011-05-25 12:42:13 -06001032 "HDMI 3",
Takashi Iwai84eb01b2010-09-07 12:27:25 +02001033};
1034
1035/*
1036 * HDMI callbacks
1037 */
1038
1039static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
1040 struct hda_codec *codec,
1041 unsigned int stream_tag,
1042 unsigned int format,
1043 struct snd_pcm_substream *substream)
1044{
1045 hdmi_set_channel_count(codec, hinfo->nid,
1046 substream->runtime->channels);
1047
1048 hdmi_setup_audio_infoframe(codec, hinfo->nid, substream);
1049
1050 return hdmi_setup_stream(codec, hinfo->nid, stream_tag, format);
1051}
1052
Takashi Iwaifb79e1e2011-05-02 12:17:41 +02001053static const struct hda_pcm_stream generic_hdmi_pcm_playback = {
Takashi Iwai84eb01b2010-09-07 12:27:25 +02001054 .substreams = 1,
1055 .channels_min = 2,
1056 .ops = {
1057 .open = hdmi_pcm_open,
1058 .prepare = generic_hdmi_playback_pcm_prepare,
1059 },
1060};
1061
1062static int generic_hdmi_build_pcms(struct hda_codec *codec)
1063{
1064 struct hdmi_spec *spec = codec->spec;
1065 struct hda_pcm *info = spec->pcm_rec;
1066 int i;
1067
1068 codec->num_pcms = spec->num_cvts;
1069 codec->pcm_info = info;
1070
1071 for (i = 0; i < codec->num_pcms; i++, info++) {
1072 unsigned int chans;
1073 struct hda_pcm_stream *pstr;
1074
1075 chans = get_wcaps(codec, spec->cvt[i]);
1076 chans = get_wcaps_channels(chans);
1077
1078 info->name = generic_hdmi_pcm_names[i];
1079 info->pcm_type = HDA_PCM_TYPE_HDMI;
1080 pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
1081 if (spec->pcm_playback)
1082 *pstr = *spec->pcm_playback;
1083 else
1084 *pstr = generic_hdmi_pcm_playback;
1085 pstr->nid = spec->cvt[i];
1086 if (pstr->channels_max <= 2 && chans && chans <= 16)
1087 pstr->channels_max = chans;
1088 }
1089
1090 return 0;
1091}
1092
1093static int generic_hdmi_build_controls(struct hda_codec *codec)
1094{
1095 struct hdmi_spec *spec = codec->spec;
1096 int err;
1097 int i;
1098
1099 for (i = 0; i < codec->num_pcms; i++) {
Stephen Warren74b654c2011-06-01 11:14:18 -06001100 err = snd_hda_create_spdif_out_ctls(codec, spec->cvt[i],
1101 spec->cvt[i]);
Takashi Iwai84eb01b2010-09-07 12:27:25 +02001102 if (err < 0)
1103 return err;
1104 }
1105
1106 return 0;
1107}
1108
1109static int generic_hdmi_init(struct hda_codec *codec)
1110{
1111 struct hdmi_spec *spec = codec->spec;
1112 int i;
1113
1114 for (i = 0; spec->pin[i]; i++) {
1115 hdmi_enable_output(codec, spec->pin[i]);
1116 snd_hda_codec_write(codec, spec->pin[i], 0,
1117 AC_VERB_SET_UNSOLICITED_ENABLE,
1118 AC_USRSP_EN | spec->pin[i]);
1119 }
1120 return 0;
1121}
1122
1123static void generic_hdmi_free(struct hda_codec *codec)
1124{
1125 struct hdmi_spec *spec = codec->spec;
1126 int i;
1127
1128 for (i = 0; i < spec->num_pins; i++)
1129 snd_hda_eld_proc_free(codec, &spec->sink_eld[i]);
David Henningsson07acecc2011-05-19 11:46:03 +02001130 snd_hda_input_jack_free(codec);
Takashi Iwai84eb01b2010-09-07 12:27:25 +02001131
1132 kfree(spec);
1133}
1134
Takashi Iwaifb79e1e2011-05-02 12:17:41 +02001135static const struct hda_codec_ops generic_hdmi_patch_ops = {
Takashi Iwai84eb01b2010-09-07 12:27:25 +02001136 .init = generic_hdmi_init,
1137 .free = generic_hdmi_free,
1138 .build_pcms = generic_hdmi_build_pcms,
1139 .build_controls = generic_hdmi_build_controls,
1140 .unsol_event = hdmi_unsol_event,
1141};
1142
1143static int patch_generic_hdmi(struct hda_codec *codec)
1144{
1145 struct hdmi_spec *spec;
1146 int i;
1147
1148 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
1149 if (spec == NULL)
1150 return -ENOMEM;
1151
1152 codec->spec = spec;
1153 if (hdmi_parse_codec(codec) < 0) {
1154 codec->spec = NULL;
1155 kfree(spec);
1156 return -EINVAL;
1157 }
1158 codec->patch_ops = generic_hdmi_patch_ops;
1159
1160 for (i = 0; i < spec->num_pins; i++)
1161 snd_hda_eld_proc_new(codec, &spec->sink_eld[i], i);
1162
1163 init_channel_allocations();
1164
1165 return 0;
1166}
1167
1168/*
Stephen Warren3aaf8982011-06-01 11:14:19 -06001169 * Shared non-generic implementations
1170 */
1171
1172static int simple_playback_build_pcms(struct hda_codec *codec)
1173{
1174 struct hdmi_spec *spec = codec->spec;
1175 struct hda_pcm *info = spec->pcm_rec;
1176 int i;
1177
1178 codec->num_pcms = spec->num_cvts;
1179 codec->pcm_info = info;
1180
1181 for (i = 0; i < codec->num_pcms; i++, info++) {
1182 unsigned int chans;
1183 struct hda_pcm_stream *pstr;
1184
1185 chans = get_wcaps(codec, spec->cvt[i]);
1186 chans = get_wcaps_channels(chans);
1187
1188 info->name = generic_hdmi_pcm_names[i];
1189 info->pcm_type = HDA_PCM_TYPE_HDMI;
1190 pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
1191 snd_BUG_ON(!spec->pcm_playback);
1192 *pstr = *spec->pcm_playback;
1193 pstr->nid = spec->cvt[i];
1194 if (pstr->channels_max <= 2 && chans && chans <= 16)
1195 pstr->channels_max = chans;
1196 }
1197
1198 return 0;
1199}
1200
1201static int simple_playback_build_controls(struct hda_codec *codec)
1202{
1203 struct hdmi_spec *spec = codec->spec;
1204 int err;
1205 int i;
1206
1207 for (i = 0; i < codec->num_pcms; i++) {
1208 err = snd_hda_create_spdif_out_ctls(codec,
1209 spec->cvt[i],
1210 spec->cvt[i]);
1211 if (err < 0)
1212 return err;
1213 }
1214
1215 return 0;
1216}
1217
1218static void simple_playback_free(struct hda_codec *codec)
1219{
1220 struct hdmi_spec *spec = codec->spec;
1221
1222 kfree(spec);
1223}
1224
1225/*
Takashi Iwai84eb01b2010-09-07 12:27:25 +02001226 * Nvidia specific implementations
1227 */
1228
1229#define Nv_VERB_SET_Channel_Allocation 0xF79
1230#define Nv_VERB_SET_Info_Frame_Checksum 0xF7A
1231#define Nv_VERB_SET_Audio_Protection_On 0xF98
1232#define Nv_VERB_SET_Audio_Protection_Off 0xF99
1233
1234#define nvhdmi_master_con_nid_7x 0x04
1235#define nvhdmi_master_pin_nid_7x 0x05
1236
Takashi Iwaifb79e1e2011-05-02 12:17:41 +02001237static const hda_nid_t nvhdmi_con_nids_7x[4] = {
Takashi Iwai84eb01b2010-09-07 12:27:25 +02001238 /*front, rear, clfe, rear_surr */
1239 0x6, 0x8, 0xa, 0xc,
1240};
1241
Takashi Iwaifb79e1e2011-05-02 12:17:41 +02001242static const struct hda_verb nvhdmi_basic_init_7x[] = {
Takashi Iwai84eb01b2010-09-07 12:27:25 +02001243 /* set audio protect on */
1244 { 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1},
1245 /* enable digital output on pin widget */
1246 { 0x5, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
1247 { 0x7, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
1248 { 0x9, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
1249 { 0xb, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
1250 { 0xd, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
1251 {} /* terminator */
1252};
1253
1254#ifdef LIMITED_RATE_FMT_SUPPORT
1255/* support only the safe format and rate */
1256#define SUPPORTED_RATES SNDRV_PCM_RATE_48000
1257#define SUPPORTED_MAXBPS 16
1258#define SUPPORTED_FORMATS SNDRV_PCM_FMTBIT_S16_LE
1259#else
1260/* support all rates and formats */
1261#define SUPPORTED_RATES \
1262 (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
1263 SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |\
1264 SNDRV_PCM_RATE_192000)
1265#define SUPPORTED_MAXBPS 24
1266#define SUPPORTED_FORMATS \
1267 (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
1268#endif
1269
1270static int nvhdmi_7x_init(struct hda_codec *codec)
1271{
1272 snd_hda_sequence_write(codec, nvhdmi_basic_init_7x);
1273 return 0;
1274}
1275
Nitin Daga393004b2011-01-10 21:49:31 +05301276static unsigned int channels_2_6_8[] = {
1277 2, 6, 8
1278};
1279
1280static unsigned int channels_2_8[] = {
1281 2, 8
1282};
1283
1284static struct snd_pcm_hw_constraint_list hw_constraints_2_6_8_channels = {
1285 .count = ARRAY_SIZE(channels_2_6_8),
1286 .list = channels_2_6_8,
1287 .mask = 0,
1288};
1289
1290static struct snd_pcm_hw_constraint_list hw_constraints_2_8_channels = {
1291 .count = ARRAY_SIZE(channels_2_8),
1292 .list = channels_2_8,
1293 .mask = 0,
1294};
1295
Takashi Iwai84eb01b2010-09-07 12:27:25 +02001296static int simple_playback_pcm_open(struct hda_pcm_stream *hinfo,
1297 struct hda_codec *codec,
1298 struct snd_pcm_substream *substream)
1299{
1300 struct hdmi_spec *spec = codec->spec;
Nitin Daga393004b2011-01-10 21:49:31 +05301301 struct snd_pcm_hw_constraint_list *hw_constraints_channels = NULL;
1302
1303 switch (codec->preset->id) {
1304 case 0x10de0002:
1305 case 0x10de0003:
1306 case 0x10de0005:
1307 case 0x10de0006:
1308 hw_constraints_channels = &hw_constraints_2_8_channels;
1309 break;
1310 case 0x10de0007:
1311 hw_constraints_channels = &hw_constraints_2_6_8_channels;
1312 break;
1313 default:
1314 break;
1315 }
1316
1317 if (hw_constraints_channels != NULL) {
1318 snd_pcm_hw_constraint_list(substream->runtime, 0,
1319 SNDRV_PCM_HW_PARAM_CHANNELS,
1320 hw_constraints_channels);
Takashi Iwaiad09fc92011-01-14 09:42:27 +01001321 } else {
1322 snd_pcm_hw_constraint_step(substream->runtime, 0,
1323 SNDRV_PCM_HW_PARAM_CHANNELS, 2);
Nitin Daga393004b2011-01-10 21:49:31 +05301324 }
1325
Takashi Iwai84eb01b2010-09-07 12:27:25 +02001326 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
1327}
1328
1329static int simple_playback_pcm_close(struct hda_pcm_stream *hinfo,
1330 struct hda_codec *codec,
1331 struct snd_pcm_substream *substream)
1332{
1333 struct hdmi_spec *spec = codec->spec;
1334 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
1335}
1336
1337static int simple_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
1338 struct hda_codec *codec,
1339 unsigned int stream_tag,
1340 unsigned int format,
1341 struct snd_pcm_substream *substream)
1342{
1343 struct hdmi_spec *spec = codec->spec;
1344 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
1345 stream_tag, format, substream);
1346}
1347
Aaron Plattner1f348522011-04-06 17:19:04 -07001348static void nvhdmi_8ch_7x_set_info_frame_parameters(struct hda_codec *codec,
1349 int channels)
1350{
1351 unsigned int chanmask;
1352 int chan = channels ? (channels - 1) : 1;
1353
1354 switch (channels) {
1355 default:
1356 case 0:
1357 case 2:
1358 chanmask = 0x00;
1359 break;
1360 case 4:
1361 chanmask = 0x08;
1362 break;
1363 case 6:
1364 chanmask = 0x0b;
1365 break;
1366 case 8:
1367 chanmask = 0x13;
1368 break;
1369 }
1370
1371 /* Set the audio infoframe channel allocation and checksum fields. The
1372 * channel count is computed implicitly by the hardware. */
1373 snd_hda_codec_write(codec, 0x1, 0,
1374 Nv_VERB_SET_Channel_Allocation, chanmask);
1375
1376 snd_hda_codec_write(codec, 0x1, 0,
1377 Nv_VERB_SET_Info_Frame_Checksum,
1378 (0x71 - chan - chanmask));
1379}
1380
Takashi Iwai84eb01b2010-09-07 12:27:25 +02001381static int nvhdmi_8ch_7x_pcm_close(struct hda_pcm_stream *hinfo,
1382 struct hda_codec *codec,
1383 struct snd_pcm_substream *substream)
1384{
1385 struct hdmi_spec *spec = codec->spec;
1386 int i;
1387
1388 snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x,
1389 0, AC_VERB_SET_CHANNEL_STREAMID, 0);
1390 for (i = 0; i < 4; i++) {
1391 /* set the stream id */
1392 snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0,
1393 AC_VERB_SET_CHANNEL_STREAMID, 0);
1394 /* set the stream format */
1395 snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0,
1396 AC_VERB_SET_STREAM_FORMAT, 0);
1397 }
1398
Aaron Plattner1f348522011-04-06 17:19:04 -07001399 /* The audio hardware sends a channel count of 0x7 (8ch) when all the
1400 * streams are disabled. */
1401 nvhdmi_8ch_7x_set_info_frame_parameters(codec, 8);
1402
Takashi Iwai84eb01b2010-09-07 12:27:25 +02001403 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
1404}
1405
1406static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo,
1407 struct hda_codec *codec,
1408 unsigned int stream_tag,
1409 unsigned int format,
1410 struct snd_pcm_substream *substream)
1411{
1412 int chs;
Aaron Plattner1f348522011-04-06 17:19:04 -07001413 unsigned int dataDCC1, dataDCC2, channel_id;
Takashi Iwai84eb01b2010-09-07 12:27:25 +02001414 int i;
Stephen Warren7c935972011-06-01 11:14:17 -06001415 struct hdmi_spec *spec = codec->spec;
1416 struct hda_spdif_out *spdif =
1417 snd_hda_spdif_out_of_nid(codec, spec->cvt[0]);
Takashi Iwai84eb01b2010-09-07 12:27:25 +02001418
1419 mutex_lock(&codec->spdif_mutex);
1420
1421 chs = substream->runtime->channels;
Takashi Iwai84eb01b2010-09-07 12:27:25 +02001422
Takashi Iwai84eb01b2010-09-07 12:27:25 +02001423 dataDCC1 = AC_DIG1_ENABLE | AC_DIG1_COPYRIGHT;
1424 dataDCC2 = 0x2;
1425
Takashi Iwai84eb01b2010-09-07 12:27:25 +02001426 /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */
Stephen Warren7c935972011-06-01 11:14:17 -06001427 if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE))
Takashi Iwai84eb01b2010-09-07 12:27:25 +02001428 snd_hda_codec_write(codec,
1429 nvhdmi_master_con_nid_7x,
1430 0,
1431 AC_VERB_SET_DIGI_CONVERT_1,
Stephen Warren7c935972011-06-01 11:14:17 -06001432 spdif->ctls & ~AC_DIG1_ENABLE & 0xff);
Takashi Iwai84eb01b2010-09-07 12:27:25 +02001433
1434 /* set the stream id */
1435 snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0,
1436 AC_VERB_SET_CHANNEL_STREAMID, (stream_tag << 4) | 0x0);
1437
1438 /* set the stream format */
1439 snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0,
1440 AC_VERB_SET_STREAM_FORMAT, format);
1441
1442 /* turn on again (if needed) */
1443 /* enable and set the channel status audio/data flag */
Stephen Warren7c935972011-06-01 11:14:17 -06001444 if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE)) {
Takashi Iwai84eb01b2010-09-07 12:27:25 +02001445 snd_hda_codec_write(codec,
1446 nvhdmi_master_con_nid_7x,
1447 0,
1448 AC_VERB_SET_DIGI_CONVERT_1,
Stephen Warren7c935972011-06-01 11:14:17 -06001449 spdif->ctls & 0xff);
Takashi Iwai84eb01b2010-09-07 12:27:25 +02001450 snd_hda_codec_write(codec,
1451 nvhdmi_master_con_nid_7x,
1452 0,
1453 AC_VERB_SET_DIGI_CONVERT_2, dataDCC2);
1454 }
1455
1456 for (i = 0; i < 4; i++) {
1457 if (chs == 2)
1458 channel_id = 0;
1459 else
1460 channel_id = i * 2;
1461
1462 /* turn off SPDIF once;
1463 *otherwise the IEC958 bits won't be updated
1464 */
1465 if (codec->spdif_status_reset &&
Stephen Warren7c935972011-06-01 11:14:17 -06001466 (spdif->ctls & AC_DIG1_ENABLE))
Takashi Iwai84eb01b2010-09-07 12:27:25 +02001467 snd_hda_codec_write(codec,
1468 nvhdmi_con_nids_7x[i],
1469 0,
1470 AC_VERB_SET_DIGI_CONVERT_1,
Stephen Warren7c935972011-06-01 11:14:17 -06001471 spdif->ctls & ~AC_DIG1_ENABLE & 0xff);
Takashi Iwai84eb01b2010-09-07 12:27:25 +02001472 /* set the stream id */
1473 snd_hda_codec_write(codec,
1474 nvhdmi_con_nids_7x[i],
1475 0,
1476 AC_VERB_SET_CHANNEL_STREAMID,
1477 (stream_tag << 4) | channel_id);
1478 /* set the stream format */
1479 snd_hda_codec_write(codec,
1480 nvhdmi_con_nids_7x[i],
1481 0,
1482 AC_VERB_SET_STREAM_FORMAT,
1483 format);
1484 /* turn on again (if needed) */
1485 /* enable and set the channel status audio/data flag */
1486 if (codec->spdif_status_reset &&
Stephen Warren7c935972011-06-01 11:14:17 -06001487 (spdif->ctls & AC_DIG1_ENABLE)) {
Takashi Iwai84eb01b2010-09-07 12:27:25 +02001488 snd_hda_codec_write(codec,
1489 nvhdmi_con_nids_7x[i],
1490 0,
1491 AC_VERB_SET_DIGI_CONVERT_1,
Stephen Warren7c935972011-06-01 11:14:17 -06001492 spdif->ctls & 0xff);
Takashi Iwai84eb01b2010-09-07 12:27:25 +02001493 snd_hda_codec_write(codec,
1494 nvhdmi_con_nids_7x[i],
1495 0,
1496 AC_VERB_SET_DIGI_CONVERT_2, dataDCC2);
1497 }
1498 }
1499
Aaron Plattner1f348522011-04-06 17:19:04 -07001500 nvhdmi_8ch_7x_set_info_frame_parameters(codec, chs);
Takashi Iwai84eb01b2010-09-07 12:27:25 +02001501
1502 mutex_unlock(&codec->spdif_mutex);
1503 return 0;
1504}
1505
Takashi Iwaifb79e1e2011-05-02 12:17:41 +02001506static const struct hda_pcm_stream nvhdmi_pcm_playback_8ch_7x = {
Takashi Iwai84eb01b2010-09-07 12:27:25 +02001507 .substreams = 1,
1508 .channels_min = 2,
1509 .channels_max = 8,
1510 .nid = nvhdmi_master_con_nid_7x,
1511 .rates = SUPPORTED_RATES,
1512 .maxbps = SUPPORTED_MAXBPS,
1513 .formats = SUPPORTED_FORMATS,
1514 .ops = {
1515 .open = simple_playback_pcm_open,
1516 .close = nvhdmi_8ch_7x_pcm_close,
1517 .prepare = nvhdmi_8ch_7x_pcm_prepare
1518 },
1519};
1520
Takashi Iwaifb79e1e2011-05-02 12:17:41 +02001521static const struct hda_pcm_stream nvhdmi_pcm_playback_2ch = {
Takashi Iwai84eb01b2010-09-07 12:27:25 +02001522 .substreams = 1,
1523 .channels_min = 2,
1524 .channels_max = 2,
1525 .nid = nvhdmi_master_con_nid_7x,
1526 .rates = SUPPORTED_RATES,
1527 .maxbps = SUPPORTED_MAXBPS,
1528 .formats = SUPPORTED_FORMATS,
1529 .ops = {
1530 .open = simple_playback_pcm_open,
1531 .close = simple_playback_pcm_close,
1532 .prepare = simple_playback_pcm_prepare
1533 },
1534};
1535
Takashi Iwaifb79e1e2011-05-02 12:17:41 +02001536static const struct hda_codec_ops nvhdmi_patch_ops_8ch_7x = {
Stephen Warren3aaf8982011-06-01 11:14:19 -06001537 .build_controls = simple_playback_build_controls,
1538 .build_pcms = simple_playback_build_pcms,
Takashi Iwai84eb01b2010-09-07 12:27:25 +02001539 .init = nvhdmi_7x_init,
Stephen Warren3aaf8982011-06-01 11:14:19 -06001540 .free = simple_playback_free,
Takashi Iwai84eb01b2010-09-07 12:27:25 +02001541};
1542
Takashi Iwaifb79e1e2011-05-02 12:17:41 +02001543static const struct hda_codec_ops nvhdmi_patch_ops_2ch = {
Stephen Warren3aaf8982011-06-01 11:14:19 -06001544 .build_controls = simple_playback_build_controls,
1545 .build_pcms = simple_playback_build_pcms,
Takashi Iwai84eb01b2010-09-07 12:27:25 +02001546 .init = nvhdmi_7x_init,
Stephen Warren3aaf8982011-06-01 11:14:19 -06001547 .free = simple_playback_free,
Takashi Iwai84eb01b2010-09-07 12:27:25 +02001548};
1549
Takashi Iwai84eb01b2010-09-07 12:27:25 +02001550static int patch_nvhdmi_2ch(struct hda_codec *codec)
1551{
1552 struct hdmi_spec *spec;
1553
1554 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
1555 if (spec == NULL)
1556 return -ENOMEM;
1557
1558 codec->spec = spec;
1559
1560 spec->multiout.num_dacs = 0; /* no analog */
1561 spec->multiout.max_channels = 2;
1562 spec->multiout.dig_out_nid = nvhdmi_master_con_nid_7x;
Takashi Iwai84eb01b2010-09-07 12:27:25 +02001563 spec->num_cvts = 1;
1564 spec->cvt[0] = nvhdmi_master_con_nid_7x;
1565 spec->pcm_playback = &nvhdmi_pcm_playback_2ch;
1566
1567 codec->patch_ops = nvhdmi_patch_ops_2ch;
1568
1569 return 0;
1570}
1571
1572static int patch_nvhdmi_8ch_7x(struct hda_codec *codec)
1573{
1574 struct hdmi_spec *spec;
1575 int err = patch_nvhdmi_2ch(codec);
1576
1577 if (err < 0)
1578 return err;
1579 spec = codec->spec;
1580 spec->multiout.max_channels = 8;
1581 spec->pcm_playback = &nvhdmi_pcm_playback_8ch_7x;
1582 codec->patch_ops = nvhdmi_patch_ops_8ch_7x;
Aaron Plattner1f348522011-04-06 17:19:04 -07001583
1584 /* Initialize the audio infoframe channel mask and checksum to something
1585 * valid */
1586 nvhdmi_8ch_7x_set_info_frame_parameters(codec, 8);
1587
Takashi Iwai84eb01b2010-09-07 12:27:25 +02001588 return 0;
1589}
1590
1591/*
1592 * ATI-specific implementations
1593 *
1594 * FIXME: we may omit the whole this and use the generic code once after
1595 * it's confirmed to work.
1596 */
1597
1598#define ATIHDMI_CVT_NID 0x02 /* audio converter */
1599#define ATIHDMI_PIN_NID 0x03 /* HDMI output pin */
1600
1601static int atihdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
1602 struct hda_codec *codec,
1603 unsigned int stream_tag,
1604 unsigned int format,
1605 struct snd_pcm_substream *substream)
1606{
1607 struct hdmi_spec *spec = codec->spec;
1608 int chans = substream->runtime->channels;
1609 int i, err;
1610
1611 err = simple_playback_pcm_prepare(hinfo, codec, stream_tag, format,
1612 substream);
1613 if (err < 0)
1614 return err;
1615 snd_hda_codec_write(codec, spec->cvt[0], 0, AC_VERB_SET_CVT_CHAN_COUNT,
1616 chans - 1);
1617 /* FIXME: XXX */
1618 for (i = 0; i < chans; i++) {
1619 snd_hda_codec_write(codec, spec->cvt[0], 0,
1620 AC_VERB_SET_HDMI_CHAN_SLOT,
1621 (i << 4) | i);
1622 }
1623 return 0;
1624}
1625
Takashi Iwaifb79e1e2011-05-02 12:17:41 +02001626static const struct hda_pcm_stream atihdmi_pcm_digital_playback = {
Takashi Iwai84eb01b2010-09-07 12:27:25 +02001627 .substreams = 1,
1628 .channels_min = 2,
1629 .channels_max = 2,
1630 .nid = ATIHDMI_CVT_NID,
1631 .ops = {
1632 .open = simple_playback_pcm_open,
1633 .close = simple_playback_pcm_close,
1634 .prepare = atihdmi_playback_pcm_prepare
1635 },
1636};
1637
Takashi Iwaifb79e1e2011-05-02 12:17:41 +02001638static const struct hda_verb atihdmi_basic_init[] = {
Takashi Iwai84eb01b2010-09-07 12:27:25 +02001639 /* enable digital output on pin widget */
1640 { 0x03, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1641 {} /* terminator */
1642};
1643
1644static int atihdmi_init(struct hda_codec *codec)
1645{
1646 struct hdmi_spec *spec = codec->spec;
1647
1648 snd_hda_sequence_write(codec, atihdmi_basic_init);
1649 /* SI codec requires to unmute the pin */
1650 if (get_wcaps(codec, spec->pin[0]) & AC_WCAP_OUT_AMP)
1651 snd_hda_codec_write(codec, spec->pin[0], 0,
1652 AC_VERB_SET_AMP_GAIN_MUTE,
1653 AMP_OUT_UNMUTE);
1654 return 0;
1655}
1656
Takashi Iwaifb79e1e2011-05-02 12:17:41 +02001657static const struct hda_codec_ops atihdmi_patch_ops = {
Stephen Warren3aaf8982011-06-01 11:14:19 -06001658 .build_controls = simple_playback_build_controls,
1659 .build_pcms = simple_playback_build_pcms,
Takashi Iwai84eb01b2010-09-07 12:27:25 +02001660 .init = atihdmi_init,
Stephen Warren3aaf8982011-06-01 11:14:19 -06001661 .free = simple_playback_free,
Takashi Iwai84eb01b2010-09-07 12:27:25 +02001662};
1663
1664
1665static int patch_atihdmi(struct hda_codec *codec)
1666{
1667 struct hdmi_spec *spec;
1668
1669 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
1670 if (spec == NULL)
1671 return -ENOMEM;
1672
1673 codec->spec = spec;
1674
1675 spec->multiout.num_dacs = 0; /* no analog */
1676 spec->multiout.max_channels = 2;
1677 spec->multiout.dig_out_nid = ATIHDMI_CVT_NID;
1678 spec->num_cvts = 1;
1679 spec->cvt[0] = ATIHDMI_CVT_NID;
1680 spec->pin[0] = ATIHDMI_PIN_NID;
1681 spec->pcm_playback = &atihdmi_pcm_digital_playback;
1682
1683 codec->patch_ops = atihdmi_patch_ops;
1684
1685 return 0;
1686}
1687
1688
1689/*
1690 * patch entries
1691 */
Takashi Iwaifb79e1e2011-05-02 12:17:41 +02001692static const struct hda_codec_preset snd_hda_preset_hdmi[] = {
Takashi Iwai84eb01b2010-09-07 12:27:25 +02001693{ .id = 0x1002793c, .name = "RS600 HDMI", .patch = patch_atihdmi },
1694{ .id = 0x10027919, .name = "RS600 HDMI", .patch = patch_atihdmi },
1695{ .id = 0x1002791a, .name = "RS690/780 HDMI", .patch = patch_atihdmi },
Anssi Hannula36e9c132010-12-05 02:34:15 +02001696{ .id = 0x1002aa01, .name = "R6xx HDMI", .patch = patch_generic_hdmi },
Takashi Iwai84eb01b2010-09-07 12:27:25 +02001697{ .id = 0x10951390, .name = "SiI1390 HDMI", .patch = patch_generic_hdmi },
1698{ .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_generic_hdmi },
1699{ .id = 0x17e80047, .name = "Chrontel HDMI", .patch = patch_generic_hdmi },
1700{ .id = 0x10de0002, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x },
1701{ .id = 0x10de0003, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x },
1702{ .id = 0x10de0005, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x },
1703{ .id = 0x10de0006, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x },
1704{ .id = 0x10de0007, .name = "MCP79/7A HDMI", .patch = patch_nvhdmi_8ch_7x },
Stephen Warren5d44f922011-05-24 17:11:17 -06001705{ .id = 0x10de000a, .name = "GPU 0a HDMI/DP", .patch = patch_generic_hdmi },
1706{ .id = 0x10de000b, .name = "GPU 0b HDMI/DP", .patch = patch_generic_hdmi },
1707{ .id = 0x10de000c, .name = "MCP89 HDMI", .patch = patch_generic_hdmi },
1708{ .id = 0x10de000d, .name = "GPU 0d HDMI/DP", .patch = patch_generic_hdmi },
1709{ .id = 0x10de0010, .name = "GPU 10 HDMI/DP", .patch = patch_generic_hdmi },
1710{ .id = 0x10de0011, .name = "GPU 11 HDMI/DP", .patch = patch_generic_hdmi },
1711{ .id = 0x10de0012, .name = "GPU 12 HDMI/DP", .patch = patch_generic_hdmi },
1712{ .id = 0x10de0013, .name = "GPU 13 HDMI/DP", .patch = patch_generic_hdmi },
1713{ .id = 0x10de0014, .name = "GPU 14 HDMI/DP", .patch = patch_generic_hdmi },
1714{ .id = 0x10de0015, .name = "GPU 15 HDMI/DP", .patch = patch_generic_hdmi },
1715{ .id = 0x10de0016, .name = "GPU 16 HDMI/DP", .patch = patch_generic_hdmi },
Richard Samsonc8900a02011-03-03 12:46:13 +01001716/* 17 is known to be absent */
Stephen Warren5d44f922011-05-24 17:11:17 -06001717{ .id = 0x10de0018, .name = "GPU 18 HDMI/DP", .patch = patch_generic_hdmi },
1718{ .id = 0x10de0019, .name = "GPU 19 HDMI/DP", .patch = patch_generic_hdmi },
1719{ .id = 0x10de001a, .name = "GPU 1a HDMI/DP", .patch = patch_generic_hdmi },
1720{ .id = 0x10de001b, .name = "GPU 1b HDMI/DP", .patch = patch_generic_hdmi },
1721{ .id = 0x10de001c, .name = "GPU 1c HDMI/DP", .patch = patch_generic_hdmi },
1722{ .id = 0x10de0040, .name = "GPU 40 HDMI/DP", .patch = patch_generic_hdmi },
1723{ .id = 0x10de0041, .name = "GPU 41 HDMI/DP", .patch = patch_generic_hdmi },
1724{ .id = 0x10de0042, .name = "GPU 42 HDMI/DP", .patch = patch_generic_hdmi },
1725{ .id = 0x10de0043, .name = "GPU 43 HDMI/DP", .patch = patch_generic_hdmi },
1726{ .id = 0x10de0044, .name = "GPU 44 HDMI/DP", .patch = patch_generic_hdmi },
Takashi Iwai84eb01b2010-09-07 12:27:25 +02001727{ .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch },
1728{ .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi_2ch },
1729{ .id = 0x80860054, .name = "IbexPeak HDMI", .patch = patch_generic_hdmi },
1730{ .id = 0x80862801, .name = "Bearlake HDMI", .patch = patch_generic_hdmi },
1731{ .id = 0x80862802, .name = "Cantiga HDMI", .patch = patch_generic_hdmi },
1732{ .id = 0x80862803, .name = "Eaglelake HDMI", .patch = patch_generic_hdmi },
1733{ .id = 0x80862804, .name = "IbexPeak HDMI", .patch = patch_generic_hdmi },
1734{ .id = 0x80862805, .name = "CougarPoint HDMI", .patch = patch_generic_hdmi },
Wu Fengguang591e6102011-05-20 15:35:43 +08001735{ .id = 0x80862806, .name = "PantherPoint HDMI", .patch = patch_generic_hdmi },
Takashi Iwai84eb01b2010-09-07 12:27:25 +02001736{ .id = 0x808629fb, .name = "Crestline HDMI", .patch = patch_generic_hdmi },
1737{} /* terminator */
1738};
1739
1740MODULE_ALIAS("snd-hda-codec-id:1002793c");
1741MODULE_ALIAS("snd-hda-codec-id:10027919");
1742MODULE_ALIAS("snd-hda-codec-id:1002791a");
1743MODULE_ALIAS("snd-hda-codec-id:1002aa01");
1744MODULE_ALIAS("snd-hda-codec-id:10951390");
1745MODULE_ALIAS("snd-hda-codec-id:10951392");
1746MODULE_ALIAS("snd-hda-codec-id:10de0002");
1747MODULE_ALIAS("snd-hda-codec-id:10de0003");
1748MODULE_ALIAS("snd-hda-codec-id:10de0005");
1749MODULE_ALIAS("snd-hda-codec-id:10de0006");
1750MODULE_ALIAS("snd-hda-codec-id:10de0007");
1751MODULE_ALIAS("snd-hda-codec-id:10de000a");
1752MODULE_ALIAS("snd-hda-codec-id:10de000b");
1753MODULE_ALIAS("snd-hda-codec-id:10de000c");
1754MODULE_ALIAS("snd-hda-codec-id:10de000d");
1755MODULE_ALIAS("snd-hda-codec-id:10de0010");
1756MODULE_ALIAS("snd-hda-codec-id:10de0011");
1757MODULE_ALIAS("snd-hda-codec-id:10de0012");
1758MODULE_ALIAS("snd-hda-codec-id:10de0013");
1759MODULE_ALIAS("snd-hda-codec-id:10de0014");
Richard Samsonc8900a02011-03-03 12:46:13 +01001760MODULE_ALIAS("snd-hda-codec-id:10de0015");
1761MODULE_ALIAS("snd-hda-codec-id:10de0016");
Takashi Iwai84eb01b2010-09-07 12:27:25 +02001762MODULE_ALIAS("snd-hda-codec-id:10de0018");
1763MODULE_ALIAS("snd-hda-codec-id:10de0019");
1764MODULE_ALIAS("snd-hda-codec-id:10de001a");
1765MODULE_ALIAS("snd-hda-codec-id:10de001b");
1766MODULE_ALIAS("snd-hda-codec-id:10de001c");
1767MODULE_ALIAS("snd-hda-codec-id:10de0040");
1768MODULE_ALIAS("snd-hda-codec-id:10de0041");
1769MODULE_ALIAS("snd-hda-codec-id:10de0042");
1770MODULE_ALIAS("snd-hda-codec-id:10de0043");
1771MODULE_ALIAS("snd-hda-codec-id:10de0044");
1772MODULE_ALIAS("snd-hda-codec-id:10de0067");
1773MODULE_ALIAS("snd-hda-codec-id:10de8001");
1774MODULE_ALIAS("snd-hda-codec-id:17e80047");
1775MODULE_ALIAS("snd-hda-codec-id:80860054");
1776MODULE_ALIAS("snd-hda-codec-id:80862801");
1777MODULE_ALIAS("snd-hda-codec-id:80862802");
1778MODULE_ALIAS("snd-hda-codec-id:80862803");
1779MODULE_ALIAS("snd-hda-codec-id:80862804");
1780MODULE_ALIAS("snd-hda-codec-id:80862805");
Wu Fengguang591e6102011-05-20 15:35:43 +08001781MODULE_ALIAS("snd-hda-codec-id:80862806");
Takashi Iwai84eb01b2010-09-07 12:27:25 +02001782MODULE_ALIAS("snd-hda-codec-id:808629fb");
1783
1784MODULE_LICENSE("GPL");
1785MODULE_DESCRIPTION("HDMI HD-audio codec");
1786MODULE_ALIAS("snd-hda-codec-intelhdmi");
1787MODULE_ALIAS("snd-hda-codec-nvhdmi");
1788MODULE_ALIAS("snd-hda-codec-atihdmi");
1789
1790static struct hda_codec_preset_list intel_list = {
1791 .preset = snd_hda_preset_hdmi,
1792 .owner = THIS_MODULE,
1793};
1794
1795static int __init patch_hdmi_init(void)
1796{
1797 return snd_hda_add_codec_preset(&intel_list);
1798}
1799
1800static void __exit patch_hdmi_exit(void)
1801{
1802 snd_hda_delete_codec_preset(&intel_list);
1803}
1804
1805module_init(patch_hdmi_init)
1806module_exit(patch_hdmi_exit)