diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-08 10:47:46 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-08 10:47:46 -0500 |
commit | a421018e8c10e5593a1fee076af72a66c3fe8ca3 (patch) | |
tree | 2854511845d0e07d33726a13eda6de1059a5c9df /sound/pci/hda/patch_intelhdmi.c | |
parent | 3ad1f3b35e8309ec93454dbf89beaafcdb5312da (diff) | |
parent | 86e1d57e4f24ca27ce813bdc2afaac4adafcbaf4 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6: (294 commits)
S3C64XX: Staticise platform data for PCM devices
ASoC: Rename controls with a / in wm_hubs
snd-fm801: autodetect SF64-PCR (tuner-only) card
ALSA: tea575x-tuner: fix mute
ASoC: au1x: dbdma2: plug memleak in pcm device creation error path
ASoC: au1x: dbdma2: fix oops on soc device removal.
ALSA: hda - Fix memory leaks in the previous patch
ALSA: hda - Add ALC661/259, ALC892/888VD support
ALSA: opti9xx: remove snd_opti9xx fields
ALSA: aaci - Clean up duplicate code
ALSA: usb - Fix mixer map for Hercules Gamesurround Muse Pocket LT
ALSA: hda - Add position_fix quirk for HP dv3
ALSA: hda - Add a pin-fix for FSC Amilo Pi1505
ALSA: hda - Fix Cxt5047 test mode
ASoC: pxa/raumfeld: adopt new snd_soc_dai_set_pll() API
ASoC: sh: fsi: Add runtime PM support
sh: ms7724se: Add runtime PM support for FSI
ALSA: hda - Add a position_fix quirk for MSI Wind U115
ALSA: opti-miro: add PnP detection
ALSA: opti-miro: separate comon probing code
...
Diffstat (limited to 'sound/pci/hda/patch_intelhdmi.c')
-rw-r--r-- | sound/pci/hda/patch_intelhdmi.c | 488 |
1 files changed, 365 insertions, 123 deletions
diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 01a18ed475ac..928df59be5d8 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c | |||
@@ -33,15 +33,41 @@ | |||
33 | #include "hda_codec.h" | 33 | #include "hda_codec.h" |
34 | #include "hda_local.h" | 34 | #include "hda_local.h" |
35 | 35 | ||
36 | static hda_nid_t cvt_nid; /* audio converter */ | 36 | /* |
37 | static hda_nid_t pin_nid; /* HDMI output pin */ | 37 | * The HDMI/DisplayPort configuration can be highly dynamic. A graphics device |
38 | * could support two independent pipes, each of them can be connected to one or | ||
39 | * more ports (DVI, HDMI or DisplayPort). | ||
40 | * | ||
41 | * The HDA correspondence of pipes/ports are converter/pin nodes. | ||
42 | */ | ||
43 | #define INTEL_HDMI_CVTS 2 | ||
44 | #define INTEL_HDMI_PINS 3 | ||
38 | 45 | ||
39 | #define INTEL_HDMI_EVENT_TAG 0x08 | 46 | static char *intel_hdmi_pcm_names[INTEL_HDMI_CVTS] = { |
47 | "INTEL HDMI 0", | ||
48 | "INTEL HDMI 1", | ||
49 | }; | ||
40 | 50 | ||
41 | struct intel_hdmi_spec { | 51 | struct intel_hdmi_spec { |
42 | struct hda_multi_out multiout; | 52 | int num_cvts; |
43 | struct hda_pcm pcm_rec; | 53 | int num_pins; |
44 | struct hdmi_eld sink_eld; | 54 | hda_nid_t cvt[INTEL_HDMI_CVTS+1]; /* audio sources */ |
55 | hda_nid_t pin[INTEL_HDMI_PINS+1]; /* audio sinks */ | ||
56 | |||
57 | /* | ||
58 | * source connection for each pin | ||
59 | */ | ||
60 | hda_nid_t pin_cvt[INTEL_HDMI_PINS+1]; | ||
61 | |||
62 | /* | ||
63 | * HDMI sink attached to each pin | ||
64 | */ | ||
65 | struct hdmi_eld sink_eld[INTEL_HDMI_PINS]; | ||
66 | |||
67 | /* | ||
68 | * export one pcm per pipe | ||
69 | */ | ||
70 | struct hda_pcm pcm_rec[INTEL_HDMI_CVTS]; | ||
45 | }; | 71 | }; |
46 | 72 | ||
47 | struct hdmi_audio_infoframe { | 73 | struct hdmi_audio_infoframe { |
@@ -184,40 +210,186 @@ static struct cea_channel_speaker_allocation channel_allocations[] = { | |||
184 | { .ca_index = 0x31, .speakers = { FRW, FLW, RR, RL, FC, LFE, FR, FL } }, | 210 | { .ca_index = 0x31, .speakers = { FRW, FLW, RR, RL, FC, LFE, FR, FL } }, |
185 | }; | 211 | }; |
186 | 212 | ||
213 | |||
214 | /* | ||
215 | * HDA/HDMI auto parsing | ||
216 | */ | ||
217 | |||
218 | static int hda_node_index(hda_nid_t *nids, hda_nid_t nid) | ||
219 | { | ||
220 | int i; | ||
221 | |||
222 | for (i = 0; nids[i]; i++) | ||
223 | if (nids[i] == nid) | ||
224 | return i; | ||
225 | |||
226 | snd_printk(KERN_WARNING "HDMI: nid %d not registered\n", nid); | ||
227 | return -EINVAL; | ||
228 | } | ||
229 | |||
230 | static int intel_hdmi_read_pin_conn(struct hda_codec *codec, hda_nid_t pin_nid) | ||
231 | { | ||
232 | struct intel_hdmi_spec *spec = codec->spec; | ||
233 | hda_nid_t conn_list[HDA_MAX_CONNECTIONS]; | ||
234 | int conn_len, curr; | ||
235 | int index; | ||
236 | |||
237 | if (!(get_wcaps(codec, pin_nid) & AC_WCAP_CONN_LIST)) { | ||
238 | snd_printk(KERN_WARNING | ||
239 | "HDMI: pin %d wcaps %#x " | ||
240 | "does not support connection list\n", | ||
241 | pin_nid, get_wcaps(codec, pin_nid)); | ||
242 | return -EINVAL; | ||
243 | } | ||
244 | |||
245 | conn_len = snd_hda_get_connections(codec, pin_nid, conn_list, | ||
246 | HDA_MAX_CONNECTIONS); | ||
247 | if (conn_len > 1) | ||
248 | curr = snd_hda_codec_read(codec, pin_nid, 0, | ||
249 | AC_VERB_GET_CONNECT_SEL, 0); | ||
250 | else | ||
251 | curr = 0; | ||
252 | |||
253 | index = hda_node_index(spec->pin, pin_nid); | ||
254 | if (index < 0) | ||
255 | return -EINVAL; | ||
256 | |||
257 | spec->pin_cvt[index] = conn_list[curr]; | ||
258 | |||
259 | return 0; | ||
260 | } | ||
261 | |||
262 | static void hdmi_get_show_eld(struct hda_codec *codec, hda_nid_t pin_nid, | ||
263 | struct hdmi_eld *eld) | ||
264 | { | ||
265 | if (!snd_hdmi_get_eld(eld, codec, pin_nid)) | ||
266 | snd_hdmi_show_eld(eld); | ||
267 | } | ||
268 | |||
269 | static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid, | ||
270 | struct hdmi_eld *eld) | ||
271 | { | ||
272 | int present = snd_hda_pin_sense(codec, pin_nid); | ||
273 | |||
274 | eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE); | ||
275 | eld->eld_valid = !!(present & AC_PINSENSE_ELDV); | ||
276 | |||
277 | if (present & AC_PINSENSE_ELDV) | ||
278 | hdmi_get_show_eld(codec, pin_nid, eld); | ||
279 | } | ||
280 | |||
281 | static int intel_hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) | ||
282 | { | ||
283 | struct intel_hdmi_spec *spec = codec->spec; | ||
284 | |||
285 | if (spec->num_pins >= INTEL_HDMI_PINS) { | ||
286 | snd_printk(KERN_WARNING | ||
287 | "HDMI: no space for pin %d \n", pin_nid); | ||
288 | return -EINVAL; | ||
289 | } | ||
290 | |||
291 | hdmi_present_sense(codec, pin_nid, &spec->sink_eld[spec->num_pins]); | ||
292 | |||
293 | spec->pin[spec->num_pins] = pin_nid; | ||
294 | spec->num_pins++; | ||
295 | |||
296 | /* | ||
297 | * It is assumed that converter nodes come first in the node list and | ||
298 | * hence have been registered and usable now. | ||
299 | */ | ||
300 | return intel_hdmi_read_pin_conn(codec, pin_nid); | ||
301 | } | ||
302 | |||
303 | static int intel_hdmi_add_cvt(struct hda_codec *codec, hda_nid_t nid) | ||
304 | { | ||
305 | struct intel_hdmi_spec *spec = codec->spec; | ||
306 | |||
307 | if (spec->num_cvts >= INTEL_HDMI_CVTS) { | ||
308 | snd_printk(KERN_WARNING | ||
309 | "HDMI: no space for converter %d \n", nid); | ||
310 | return -EINVAL; | ||
311 | } | ||
312 | |||
313 | spec->cvt[spec->num_cvts] = nid; | ||
314 | spec->num_cvts++; | ||
315 | |||
316 | return 0; | ||
317 | } | ||
318 | |||
319 | static int intel_hdmi_parse_codec(struct hda_codec *codec) | ||
320 | { | ||
321 | hda_nid_t nid; | ||
322 | int i, nodes; | ||
323 | |||
324 | nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid); | ||
325 | if (!nid || nodes < 0) { | ||
326 | snd_printk(KERN_WARNING "HDMI: failed to get afg sub nodes\n"); | ||
327 | return -EINVAL; | ||
328 | } | ||
329 | |||
330 | for (i = 0; i < nodes; i++, nid++) { | ||
331 | unsigned int caps; | ||
332 | unsigned int type; | ||
333 | |||
334 | caps = snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP); | ||
335 | type = get_wcaps_type(caps); | ||
336 | |||
337 | if (!(caps & AC_WCAP_DIGITAL)) | ||
338 | continue; | ||
339 | |||
340 | switch (type) { | ||
341 | case AC_WID_AUD_OUT: | ||
342 | if (intel_hdmi_add_cvt(codec, nid) < 0) | ||
343 | return -EINVAL; | ||
344 | break; | ||
345 | case AC_WID_PIN: | ||
346 | caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); | ||
347 | if (!(caps & AC_PINCAP_HDMI)) | ||
348 | continue; | ||
349 | if (intel_hdmi_add_pin(codec, nid) < 0) | ||
350 | return -EINVAL; | ||
351 | break; | ||
352 | } | ||
353 | } | ||
354 | |||
355 | return 0; | ||
356 | } | ||
357 | |||
187 | /* | 358 | /* |
188 | * HDMI routines | 359 | * HDMI routines |
189 | */ | 360 | */ |
190 | 361 | ||
191 | #ifdef BE_PARANOID | 362 | #ifdef BE_PARANOID |
192 | static void hdmi_get_dip_index(struct hda_codec *codec, hda_nid_t nid, | 363 | static void hdmi_get_dip_index(struct hda_codec *codec, hda_nid_t pin_nid, |
193 | int *packet_index, int *byte_index) | 364 | int *packet_index, int *byte_index) |
194 | { | 365 | { |
195 | int val; | 366 | int val; |
196 | 367 | ||
197 | val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_INDEX, 0); | 368 | val = snd_hda_codec_read(codec, pin_nid, 0, |
369 | AC_VERB_GET_HDMI_DIP_INDEX, 0); | ||
198 | 370 | ||
199 | *packet_index = val >> 5; | 371 | *packet_index = val >> 5; |
200 | *byte_index = val & 0x1f; | 372 | *byte_index = val & 0x1f; |
201 | } | 373 | } |
202 | #endif | 374 | #endif |
203 | 375 | ||
204 | static void hdmi_set_dip_index(struct hda_codec *codec, hda_nid_t nid, | 376 | static void hdmi_set_dip_index(struct hda_codec *codec, hda_nid_t pin_nid, |
205 | int packet_index, int byte_index) | 377 | int packet_index, int byte_index) |
206 | { | 378 | { |
207 | int val; | 379 | int val; |
208 | 380 | ||
209 | val = (packet_index << 5) | (byte_index & 0x1f); | 381 | val = (packet_index << 5) | (byte_index & 0x1f); |
210 | 382 | ||
211 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_HDMI_DIP_INDEX, val); | 383 | snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_INDEX, val); |
212 | } | 384 | } |
213 | 385 | ||
214 | static void hdmi_write_dip_byte(struct hda_codec *codec, hda_nid_t nid, | 386 | static void hdmi_write_dip_byte(struct hda_codec *codec, hda_nid_t pin_nid, |
215 | unsigned char val) | 387 | unsigned char val) |
216 | { | 388 | { |
217 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_HDMI_DIP_DATA, val); | 389 | snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_DATA, val); |
218 | } | 390 | } |
219 | 391 | ||
220 | static void hdmi_enable_output(struct hda_codec *codec) | 392 | static void hdmi_enable_output(struct hda_codec *codec, hda_nid_t pin_nid) |
221 | { | 393 | { |
222 | /* Unmute */ | 394 | /* Unmute */ |
223 | if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP) | 395 | if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP) |
@@ -231,7 +403,8 @@ static void hdmi_enable_output(struct hda_codec *codec) | |||
231 | /* | 403 | /* |
232 | * Enable Audio InfoFrame Transmission | 404 | * Enable Audio InfoFrame Transmission |
233 | */ | 405 | */ |
234 | static void hdmi_start_infoframe_trans(struct hda_codec *codec) | 406 | static void hdmi_start_infoframe_trans(struct hda_codec *codec, |
407 | hda_nid_t pin_nid) | ||
235 | { | 408 | { |
236 | hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0); | 409 | hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0); |
237 | snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_XMIT, | 410 | snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_XMIT, |
@@ -241,59 +414,49 @@ static void hdmi_start_infoframe_trans(struct hda_codec *codec) | |||
241 | /* | 414 | /* |
242 | * Disable Audio InfoFrame Transmission | 415 | * Disable Audio InfoFrame Transmission |
243 | */ | 416 | */ |
244 | static void hdmi_stop_infoframe_trans(struct hda_codec *codec) | 417 | static void hdmi_stop_infoframe_trans(struct hda_codec *codec, |
418 | hda_nid_t pin_nid) | ||
245 | { | 419 | { |
246 | hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0); | 420 | hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0); |
247 | snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_XMIT, | 421 | snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_XMIT, |
248 | AC_DIPXMIT_DISABLE); | 422 | AC_DIPXMIT_DISABLE); |
249 | } | 423 | } |
250 | 424 | ||
251 | static int hdmi_get_channel_count(struct hda_codec *codec) | 425 | static int hdmi_get_channel_count(struct hda_codec *codec, hda_nid_t nid) |
252 | { | 426 | { |
253 | return 1 + snd_hda_codec_read(codec, cvt_nid, 0, | 427 | return 1 + snd_hda_codec_read(codec, nid, 0, |
254 | AC_VERB_GET_CVT_CHAN_COUNT, 0); | 428 | AC_VERB_GET_CVT_CHAN_COUNT, 0); |
255 | } | 429 | } |
256 | 430 | ||
257 | static void hdmi_set_channel_count(struct hda_codec *codec, int chs) | 431 | static void hdmi_set_channel_count(struct hda_codec *codec, |
432 | hda_nid_t nid, int chs) | ||
258 | { | 433 | { |
259 | snd_hda_codec_write(codec, cvt_nid, 0, | 434 | if (chs != hdmi_get_channel_count(codec, nid)) |
260 | AC_VERB_SET_CVT_CHAN_COUNT, chs - 1); | 435 | snd_hda_codec_write(codec, nid, 0, |
261 | 436 | AC_VERB_SET_CVT_CHAN_COUNT, chs - 1); | |
262 | if (chs != hdmi_get_channel_count(codec)) | ||
263 | snd_printd(KERN_INFO "HDMI channel count: expect %d, get %d\n", | ||
264 | chs, hdmi_get_channel_count(codec)); | ||
265 | } | 437 | } |
266 | 438 | ||
267 | static void hdmi_debug_channel_mapping(struct hda_codec *codec) | 439 | static void hdmi_debug_channel_mapping(struct hda_codec *codec, hda_nid_t nid) |
268 | { | 440 | { |
269 | #ifdef CONFIG_SND_DEBUG_VERBOSE | 441 | #ifdef CONFIG_SND_DEBUG_VERBOSE |
270 | int i; | 442 | int i; |
271 | int slot; | 443 | int slot; |
272 | 444 | ||
273 | for (i = 0; i < 8; i++) { | 445 | for (i = 0; i < 8; i++) { |
274 | slot = snd_hda_codec_read(codec, cvt_nid, 0, | 446 | slot = snd_hda_codec_read(codec, nid, 0, |
275 | AC_VERB_GET_HDMI_CHAN_SLOT, i); | 447 | AC_VERB_GET_HDMI_CHAN_SLOT, i); |
276 | printk(KERN_DEBUG "HDMI: ASP channel %d => slot %d\n", | 448 | printk(KERN_DEBUG "HDMI: ASP channel %d => slot %d\n", |
277 | slot >> 4, slot & 0x7); | 449 | slot >> 4, slot & 0xf); |
278 | } | 450 | } |
279 | #endif | 451 | #endif |
280 | } | 452 | } |
281 | 453 | ||
282 | static void hdmi_parse_eld(struct hda_codec *codec) | ||
283 | { | ||
284 | struct intel_hdmi_spec *spec = codec->spec; | ||
285 | struct hdmi_eld *eld = &spec->sink_eld; | ||
286 | |||
287 | if (!snd_hdmi_get_eld(eld, codec, pin_nid)) | ||
288 | snd_hdmi_show_eld(eld); | ||
289 | } | ||
290 | |||
291 | 454 | ||
292 | /* | 455 | /* |
293 | * Audio InfoFrame routines | 456 | * Audio InfoFrame routines |
294 | */ | 457 | */ |
295 | 458 | ||
296 | static void hdmi_debug_dip_size(struct hda_codec *codec) | 459 | static void hdmi_debug_dip_size(struct hda_codec *codec, hda_nid_t pin_nid) |
297 | { | 460 | { |
298 | #ifdef CONFIG_SND_DEBUG_VERBOSE | 461 | #ifdef CONFIG_SND_DEBUG_VERBOSE |
299 | int i; | 462 | int i; |
@@ -310,7 +473,7 @@ static void hdmi_debug_dip_size(struct hda_codec *codec) | |||
310 | #endif | 473 | #endif |
311 | } | 474 | } |
312 | 475 | ||
313 | static void hdmi_clear_dip_buffers(struct hda_codec *codec) | 476 | static void hdmi_clear_dip_buffers(struct hda_codec *codec, hda_nid_t pin_nid) |
314 | { | 477 | { |
315 | #ifdef BE_PARANOID | 478 | #ifdef BE_PARANOID |
316 | int i, j; | 479 | int i, j; |
@@ -339,23 +502,35 @@ static void hdmi_clear_dip_buffers(struct hda_codec *codec) | |||
339 | #endif | 502 | #endif |
340 | } | 503 | } |
341 | 504 | ||
342 | static void hdmi_fill_audio_infoframe(struct hda_codec *codec, | 505 | static void hdmi_checksum_audio_infoframe(struct hdmi_audio_infoframe *ai) |
343 | struct hdmi_audio_infoframe *ai) | ||
344 | { | 506 | { |
345 | u8 *params = (u8 *)ai; | 507 | u8 *bytes = (u8 *)ai; |
346 | u8 sum = 0; | 508 | u8 sum = 0; |
347 | int i; | 509 | int i; |
348 | 510 | ||
349 | hdmi_debug_dip_size(codec); | 511 | ai->checksum = 0; |
350 | hdmi_clear_dip_buffers(codec); /* be paranoid */ | 512 | |
513 | for (i = 0; i < sizeof(*ai); i++) | ||
514 | sum += bytes[i]; | ||
351 | 515 | ||
352 | for (i = 0; i < sizeof(ai); i++) | ||
353 | sum += params[i]; | ||
354 | ai->checksum = - sum; | 516 | ai->checksum = - sum; |
517 | } | ||
518 | |||
519 | static void hdmi_fill_audio_infoframe(struct hda_codec *codec, | ||
520 | hda_nid_t pin_nid, | ||
521 | struct hdmi_audio_infoframe *ai) | ||
522 | { | ||
523 | u8 *bytes = (u8 *)ai; | ||
524 | int i; | ||
525 | |||
526 | hdmi_debug_dip_size(codec, pin_nid); | ||
527 | hdmi_clear_dip_buffers(codec, pin_nid); /* be paranoid */ | ||
528 | |||
529 | hdmi_checksum_audio_infoframe(ai); | ||
355 | 530 | ||
356 | hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0); | 531 | hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0); |
357 | for (i = 0; i < sizeof(ai); i++) | 532 | for (i = 0; i < sizeof(*ai); i++) |
358 | hdmi_write_dip_byte(codec, pin_nid, params[i]); | 533 | hdmi_write_dip_byte(codec, pin_nid, bytes[i]); |
359 | } | 534 | } |
360 | 535 | ||
361 | /* | 536 | /* |
@@ -386,11 +561,11 @@ static void init_channel_allocations(void) | |||
386 | * | 561 | * |
387 | * TODO: it could select the wrong CA from multiple candidates. | 562 | * TODO: it could select the wrong CA from multiple candidates. |
388 | */ | 563 | */ |
389 | static int hdmi_setup_channel_allocation(struct hda_codec *codec, | 564 | static int hdmi_setup_channel_allocation(struct hda_codec *codec, hda_nid_t nid, |
390 | struct hdmi_audio_infoframe *ai) | 565 | struct hdmi_audio_infoframe *ai) |
391 | { | 566 | { |
392 | struct intel_hdmi_spec *spec = codec->spec; | 567 | struct intel_hdmi_spec *spec = codec->spec; |
393 | struct hdmi_eld *eld = &spec->sink_eld; | 568 | struct hdmi_eld *eld; |
394 | int i; | 569 | int i; |
395 | int spk_mask = 0; | 570 | int spk_mask = 0; |
396 | int channels = 1 + (ai->CC02_CT47 & 0x7); | 571 | int channels = 1 + (ai->CC02_CT47 & 0x7); |
@@ -402,6 +577,11 @@ static int hdmi_setup_channel_allocation(struct hda_codec *codec, | |||
402 | if (channels <= 2) | 577 | if (channels <= 2) |
403 | return 0; | 578 | return 0; |
404 | 579 | ||
580 | i = hda_node_index(spec->pin_cvt, nid); | ||
581 | if (i < 0) | ||
582 | return 0; | ||
583 | eld = &spec->sink_eld[i]; | ||
584 | |||
405 | /* | 585 | /* |
406 | * HDMI sink's ELD info cannot always be retrieved for now, e.g. | 586 | * HDMI sink's ELD info cannot always be retrieved for now, e.g. |
407 | * in console or for audio devices. Assume the highest speakers | 587 | * in console or for audio devices. Assume the highest speakers |
@@ -439,8 +619,8 @@ static int hdmi_setup_channel_allocation(struct hda_codec *codec, | |||
439 | return ai->CA; | 619 | return ai->CA; |
440 | } | 620 | } |
441 | 621 | ||
442 | static void hdmi_setup_channel_mapping(struct hda_codec *codec, | 622 | static void hdmi_setup_channel_mapping(struct hda_codec *codec, hda_nid_t nid, |
443 | struct hdmi_audio_infoframe *ai) | 623 | struct hdmi_audio_infoframe *ai) |
444 | { | 624 | { |
445 | int i; | 625 | int i; |
446 | 626 | ||
@@ -453,17 +633,41 @@ static void hdmi_setup_channel_mapping(struct hda_codec *codec, | |||
453 | */ | 633 | */ |
454 | 634 | ||
455 | for (i = 0; i < 8; i++) | 635 | for (i = 0; i < 8; i++) |
456 | snd_hda_codec_write(codec, cvt_nid, 0, | 636 | snd_hda_codec_write(codec, nid, 0, |
457 | AC_VERB_SET_HDMI_CHAN_SLOT, | 637 | AC_VERB_SET_HDMI_CHAN_SLOT, |
458 | (i << 4) | i); | 638 | (i << 4) | i); |
459 | 639 | ||
460 | hdmi_debug_channel_mapping(codec); | 640 | hdmi_debug_channel_mapping(codec, nid); |
461 | } | 641 | } |
462 | 642 | ||
643 | static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid, | ||
644 | struct hdmi_audio_infoframe *ai) | ||
645 | { | ||
646 | u8 *bytes = (u8 *)ai; | ||
647 | u8 val; | ||
648 | int i; | ||
649 | |||
650 | if (snd_hda_codec_read(codec, pin_nid, 0, AC_VERB_GET_HDMI_DIP_XMIT, 0) | ||
651 | != AC_DIPXMIT_BEST) | ||
652 | return false; | ||
653 | |||
654 | hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0); | ||
655 | for (i = 0; i < sizeof(*ai); i++) { | ||
656 | val = snd_hda_codec_read(codec, pin_nid, 0, | ||
657 | AC_VERB_GET_HDMI_DIP_DATA, 0); | ||
658 | if (val != bytes[i]) | ||
659 | return false; | ||
660 | } | ||
463 | 661 | ||
464 | static void hdmi_setup_audio_infoframe(struct hda_codec *codec, | 662 | return true; |
663 | } | ||
664 | |||
665 | static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid, | ||
465 | struct snd_pcm_substream *substream) | 666 | struct snd_pcm_substream *substream) |
466 | { | 667 | { |
668 | struct intel_hdmi_spec *spec = codec->spec; | ||
669 | hda_nid_t pin_nid; | ||
670 | int i; | ||
467 | struct hdmi_audio_infoframe ai = { | 671 | struct hdmi_audio_infoframe ai = { |
468 | .type = 0x84, | 672 | .type = 0x84, |
469 | .ver = 0x01, | 673 | .ver = 0x01, |
@@ -471,11 +675,22 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, | |||
471 | .CC02_CT47 = substream->runtime->channels - 1, | 675 | .CC02_CT47 = substream->runtime->channels - 1, |
472 | }; | 676 | }; |
473 | 677 | ||
474 | hdmi_setup_channel_allocation(codec, &ai); | 678 | hdmi_setup_channel_allocation(codec, nid, &ai); |
475 | hdmi_setup_channel_mapping(codec, &ai); | 679 | hdmi_setup_channel_mapping(codec, nid, &ai); |
476 | 680 | ||
477 | hdmi_fill_audio_infoframe(codec, &ai); | 681 | for (i = 0; i < spec->num_pins; i++) { |
478 | hdmi_start_infoframe_trans(codec); | 682 | if (spec->pin_cvt[i] != nid) |
683 | continue; | ||
684 | if (!spec->sink_eld[i].monitor_present) | ||
685 | continue; | ||
686 | |||
687 | pin_nid = spec->pin[i]; | ||
688 | if (!hdmi_infoframe_uptodate(codec, pin_nid, &ai)) { | ||
689 | hdmi_stop_infoframe_trans(codec, pin_nid); | ||
690 | hdmi_fill_audio_infoframe(codec, pin_nid, &ai); | ||
691 | hdmi_start_infoframe_trans(codec, pin_nid); | ||
692 | } | ||
693 | } | ||
479 | } | 694 | } |
480 | 695 | ||
481 | 696 | ||
@@ -485,27 +700,39 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, | |||
485 | 700 | ||
486 | static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) | 701 | static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) |
487 | { | 702 | { |
703 | struct intel_hdmi_spec *spec = codec->spec; | ||
704 | int tag = res >> AC_UNSOL_RES_TAG_SHIFT; | ||
488 | int pind = !!(res & AC_UNSOL_RES_PD); | 705 | int pind = !!(res & AC_UNSOL_RES_PD); |
489 | int eldv = !!(res & AC_UNSOL_RES_ELDV); | 706 | int eldv = !!(res & AC_UNSOL_RES_ELDV); |
707 | int index; | ||
490 | 708 | ||
491 | printk(KERN_INFO | 709 | printk(KERN_INFO |
492 | "HDMI hot plug event: Presence_Detect=%d ELD_Valid=%d\n", | 710 | "HDMI hot plug event: Pin=%d Presence_Detect=%d ELD_Valid=%d\n", |
493 | pind, eldv); | 711 | tag, pind, eldv); |
712 | |||
713 | index = hda_node_index(spec->pin, tag); | ||
714 | if (index < 0) | ||
715 | return; | ||
716 | |||
717 | spec->sink_eld[index].monitor_present = pind; | ||
718 | spec->sink_eld[index].eld_valid = eldv; | ||
494 | 719 | ||
495 | if (pind && eldv) { | 720 | if (pind && eldv) { |
496 | hdmi_parse_eld(codec); | 721 | hdmi_get_show_eld(codec, spec->pin[index], &spec->sink_eld[index]); |
497 | /* TODO: do real things about ELD */ | 722 | /* TODO: do real things about ELD */ |
498 | } | 723 | } |
499 | } | 724 | } |
500 | 725 | ||
501 | static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res) | 726 | static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res) |
502 | { | 727 | { |
728 | int tag = res >> AC_UNSOL_RES_TAG_SHIFT; | ||
503 | int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT; | 729 | int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT; |
504 | int cp_state = !!(res & AC_UNSOL_RES_CP_STATE); | 730 | int cp_state = !!(res & AC_UNSOL_RES_CP_STATE); |
505 | int cp_ready = !!(res & AC_UNSOL_RES_CP_READY); | 731 | int cp_ready = !!(res & AC_UNSOL_RES_CP_READY); |
506 | 732 | ||
507 | printk(KERN_INFO | 733 | printk(KERN_INFO |
508 | "HDMI content protection event: SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n", | 734 | "HDMI CP event: PIN=%d SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n", |
735 | tag, | ||
509 | subtag, | 736 | subtag, |
510 | cp_state, | 737 | cp_state, |
511 | cp_ready); | 738 | cp_ready); |
@@ -520,10 +747,11 @@ static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res) | |||
520 | 747 | ||
521 | static void intel_hdmi_unsol_event(struct hda_codec *codec, unsigned int res) | 748 | static void intel_hdmi_unsol_event(struct hda_codec *codec, unsigned int res) |
522 | { | 749 | { |
750 | struct intel_hdmi_spec *spec = codec->spec; | ||
523 | int tag = res >> AC_UNSOL_RES_TAG_SHIFT; | 751 | int tag = res >> AC_UNSOL_RES_TAG_SHIFT; |
524 | int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT; | 752 | int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT; |
525 | 753 | ||
526 | if (tag != INTEL_HDMI_EVENT_TAG) { | 754 | if (hda_node_index(spec->pin, tag) < 0) { |
527 | snd_printd(KERN_INFO "Unexpected HDMI event tag 0x%x\n", tag); | 755 | snd_printd(KERN_INFO "Unexpected HDMI event tag 0x%x\n", tag); |
528 | return; | 756 | return; |
529 | } | 757 | } |
@@ -538,24 +766,29 @@ static void intel_hdmi_unsol_event(struct hda_codec *codec, unsigned int res) | |||
538 | * Callbacks | 766 | * Callbacks |
539 | */ | 767 | */ |
540 | 768 | ||
541 | static int intel_hdmi_playback_pcm_open(struct hda_pcm_stream *hinfo, | 769 | static void hdmi_setup_stream(struct hda_codec *codec, hda_nid_t nid, |
542 | struct hda_codec *codec, | 770 | u32 stream_tag, int format) |
543 | struct snd_pcm_substream *substream) | ||
544 | { | 771 | { |
545 | struct intel_hdmi_spec *spec = codec->spec; | 772 | int tag; |
546 | 773 | int fmt; | |
547 | return snd_hda_multi_out_dig_open(codec, &spec->multiout); | ||
548 | } | ||
549 | 774 | ||
550 | static int intel_hdmi_playback_pcm_close(struct hda_pcm_stream *hinfo, | 775 | tag = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0) >> 4; |
551 | struct hda_codec *codec, | 776 | fmt = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_STREAM_FORMAT, 0); |
552 | struct snd_pcm_substream *substream) | ||
553 | { | ||
554 | struct intel_hdmi_spec *spec = codec->spec; | ||
555 | 777 | ||
556 | hdmi_stop_infoframe_trans(codec); | 778 | snd_printdd("hdmi_setup_stream: " |
779 | "NID=0x%x, %sstream=0x%x, %sformat=0x%x\n", | ||
780 | nid, | ||
781 | tag == stream_tag ? "" : "new-", | ||
782 | stream_tag, | ||
783 | fmt == format ? "" : "new-", | ||
784 | format); | ||
557 | 785 | ||
558 | return snd_hda_multi_out_dig_close(codec, &spec->multiout); | 786 | if (tag != stream_tag) |
787 | snd_hda_codec_write(codec, nid, 0, | ||
788 | AC_VERB_SET_CHANNEL_STREAMID, stream_tag << 4); | ||
789 | if (fmt != format) | ||
790 | snd_hda_codec_write(codec, nid, 0, | ||
791 | AC_VERB_SET_STREAM_FORMAT, format); | ||
559 | } | 792 | } |
560 | 793 | ||
561 | static int intel_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | 794 | static int intel_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, |
@@ -564,43 +797,53 @@ static int intel_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | |||
564 | unsigned int format, | 797 | unsigned int format, |
565 | struct snd_pcm_substream *substream) | 798 | struct snd_pcm_substream *substream) |
566 | { | 799 | { |
567 | struct intel_hdmi_spec *spec = codec->spec; | 800 | hdmi_set_channel_count(codec, hinfo->nid, |
568 | 801 | substream->runtime->channels); | |
569 | snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag, | ||
570 | format, substream); | ||
571 | 802 | ||
572 | hdmi_set_channel_count(codec, substream->runtime->channels); | 803 | hdmi_setup_audio_infoframe(codec, hinfo->nid, substream); |
573 | 804 | ||
574 | hdmi_setup_audio_infoframe(codec, substream); | 805 | hdmi_setup_stream(codec, hinfo->nid, stream_tag, format); |
806 | return 0; | ||
807 | } | ||
575 | 808 | ||
809 | static int intel_hdmi_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, | ||
810 | struct hda_codec *codec, | ||
811 | struct snd_pcm_substream *substream) | ||
812 | { | ||
576 | return 0; | 813 | return 0; |
577 | } | 814 | } |
578 | 815 | ||
579 | static struct hda_pcm_stream intel_hdmi_pcm_playback = { | 816 | static struct hda_pcm_stream intel_hdmi_pcm_playback = { |
580 | .substreams = 1, | 817 | .substreams = 1, |
581 | .channels_min = 2, | 818 | .channels_min = 2, |
582 | .channels_max = 8, | ||
583 | .ops = { | 819 | .ops = { |
584 | .open = intel_hdmi_playback_pcm_open, | 820 | .prepare = intel_hdmi_playback_pcm_prepare, |
585 | .close = intel_hdmi_playback_pcm_close, | 821 | .cleanup = intel_hdmi_playback_pcm_cleanup, |
586 | .prepare = intel_hdmi_playback_pcm_prepare | ||
587 | }, | 822 | }, |
588 | }; | 823 | }; |
589 | 824 | ||
590 | static int intel_hdmi_build_pcms(struct hda_codec *codec) | 825 | static int intel_hdmi_build_pcms(struct hda_codec *codec) |
591 | { | 826 | { |
592 | struct intel_hdmi_spec *spec = codec->spec; | 827 | struct intel_hdmi_spec *spec = codec->spec; |
593 | struct hda_pcm *info = &spec->pcm_rec; | 828 | struct hda_pcm *info = spec->pcm_rec; |
829 | int i; | ||
594 | 830 | ||
595 | codec->num_pcms = 1; | 831 | codec->num_pcms = spec->num_cvts; |
596 | codec->pcm_info = info; | 832 | codec->pcm_info = info; |
597 | 833 | ||
598 | /* NID to query formats and rates and setup streams */ | 834 | for (i = 0; i < codec->num_pcms; i++, info++) { |
599 | intel_hdmi_pcm_playback.nid = cvt_nid; | 835 | unsigned int chans; |
600 | 836 | ||
601 | info->name = "INTEL HDMI"; | 837 | chans = get_wcaps(codec, spec->cvt[i]); |
602 | info->pcm_type = HDA_PCM_TYPE_HDMI; | 838 | chans = get_wcaps_channels(chans); |
603 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = intel_hdmi_pcm_playback; | 839 | |
840 | info->name = intel_hdmi_pcm_names[i]; | ||
841 | info->pcm_type = HDA_PCM_TYPE_HDMI; | ||
842 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = | ||
843 | intel_hdmi_pcm_playback; | ||
844 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->cvt[i]; | ||
845 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = chans; | ||
846 | } | ||
604 | 847 | ||
605 | return 0; | 848 | return 0; |
606 | } | 849 | } |
@@ -609,29 +852,39 @@ static int intel_hdmi_build_controls(struct hda_codec *codec) | |||
609 | { | 852 | { |
610 | struct intel_hdmi_spec *spec = codec->spec; | 853 | struct intel_hdmi_spec *spec = codec->spec; |
611 | int err; | 854 | int err; |
855 | int i; | ||
612 | 856 | ||
613 | err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); | 857 | for (i = 0; i < codec->num_pcms; i++) { |
614 | if (err < 0) | 858 | err = snd_hda_create_spdif_out_ctls(codec, spec->cvt[i]); |
615 | return err; | 859 | if (err < 0) |
860 | return err; | ||
861 | } | ||
616 | 862 | ||
617 | return 0; | 863 | return 0; |
618 | } | 864 | } |
619 | 865 | ||
620 | static int intel_hdmi_init(struct hda_codec *codec) | 866 | static int intel_hdmi_init(struct hda_codec *codec) |
621 | { | 867 | { |
622 | hdmi_enable_output(codec); | 868 | struct intel_hdmi_spec *spec = codec->spec; |
869 | int i; | ||
623 | 870 | ||
624 | snd_hda_codec_write(codec, pin_nid, 0, | 871 | for (i = 0; spec->pin[i]; i++) { |
625 | AC_VERB_SET_UNSOLICITED_ENABLE, | 872 | hdmi_enable_output(codec, spec->pin[i]); |
626 | AC_USRSP_EN | INTEL_HDMI_EVENT_TAG); | 873 | snd_hda_codec_write(codec, spec->pin[i], 0, |
874 | AC_VERB_SET_UNSOLICITED_ENABLE, | ||
875 | AC_USRSP_EN | spec->pin[i]); | ||
876 | } | ||
627 | return 0; | 877 | return 0; |
628 | } | 878 | } |
629 | 879 | ||
630 | static void intel_hdmi_free(struct hda_codec *codec) | 880 | static void intel_hdmi_free(struct hda_codec *codec) |
631 | { | 881 | { |
632 | struct intel_hdmi_spec *spec = codec->spec; | 882 | struct intel_hdmi_spec *spec = codec->spec; |
883 | int i; | ||
884 | |||
885 | for (i = 0; i < spec->num_pins; i++) | ||
886 | snd_hda_eld_proc_free(codec, &spec->sink_eld[i]); | ||
633 | 887 | ||
634 | snd_hda_eld_proc_free(codec, &spec->sink_eld); | ||
635 | kfree(spec); | 888 | kfree(spec); |
636 | } | 889 | } |
637 | 890 | ||
@@ -643,49 +896,38 @@ static struct hda_codec_ops intel_hdmi_patch_ops = { | |||
643 | .unsol_event = intel_hdmi_unsol_event, | 896 | .unsol_event = intel_hdmi_unsol_event, |
644 | }; | 897 | }; |
645 | 898 | ||
646 | static int do_patch_intel_hdmi(struct hda_codec *codec) | 899 | static int patch_intel_hdmi(struct hda_codec *codec) |
647 | { | 900 | { |
648 | struct intel_hdmi_spec *spec; | 901 | struct intel_hdmi_spec *spec; |
902 | int i; | ||
649 | 903 | ||
650 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 904 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); |
651 | if (spec == NULL) | 905 | if (spec == NULL) |
652 | return -ENOMEM; | 906 | return -ENOMEM; |
653 | 907 | ||
654 | spec->multiout.num_dacs = 0; /* no analog */ | ||
655 | spec->multiout.max_channels = 8; | ||
656 | spec->multiout.dig_out_nid = cvt_nid; | ||
657 | |||
658 | codec->spec = spec; | 908 | codec->spec = spec; |
909 | if (intel_hdmi_parse_codec(codec) < 0) { | ||
910 | codec->spec = NULL; | ||
911 | kfree(spec); | ||
912 | return -EINVAL; | ||
913 | } | ||
659 | codec->patch_ops = intel_hdmi_patch_ops; | 914 | codec->patch_ops = intel_hdmi_patch_ops; |
660 | 915 | ||
661 | snd_hda_eld_proc_new(codec, &spec->sink_eld); | 916 | for (i = 0; i < spec->num_pins; i++) |
917 | snd_hda_eld_proc_new(codec, &spec->sink_eld[i], i); | ||
662 | 918 | ||
663 | init_channel_allocations(); | 919 | init_channel_allocations(); |
664 | 920 | ||
665 | return 0; | 921 | return 0; |
666 | } | 922 | } |
667 | 923 | ||
668 | static int patch_intel_hdmi(struct hda_codec *codec) | ||
669 | { | ||
670 | cvt_nid = 0x02; | ||
671 | pin_nid = 0x03; | ||
672 | return do_patch_intel_hdmi(codec); | ||
673 | } | ||
674 | |||
675 | static int patch_intel_hdmi_ibexpeak(struct hda_codec *codec) | ||
676 | { | ||
677 | cvt_nid = 0x02; | ||
678 | pin_nid = 0x04; | ||
679 | return do_patch_intel_hdmi(codec); | ||
680 | } | ||
681 | |||
682 | static struct hda_codec_preset snd_hda_preset_intelhdmi[] = { | 924 | static struct hda_codec_preset snd_hda_preset_intelhdmi[] = { |
683 | { .id = 0x808629fb, .name = "G45 DEVCL", .patch = patch_intel_hdmi }, | 925 | { .id = 0x808629fb, .name = "G45 DEVCL", .patch = patch_intel_hdmi }, |
684 | { .id = 0x80862801, .name = "G45 DEVBLC", .patch = patch_intel_hdmi }, | 926 | { .id = 0x80862801, .name = "G45 DEVBLC", .patch = patch_intel_hdmi }, |
685 | { .id = 0x80862802, .name = "G45 DEVCTG", .patch = patch_intel_hdmi }, | 927 | { .id = 0x80862802, .name = "G45 DEVCTG", .patch = patch_intel_hdmi }, |
686 | { .id = 0x80862803, .name = "G45 DEVELK", .patch = patch_intel_hdmi }, | 928 | { .id = 0x80862803, .name = "G45 DEVELK", .patch = patch_intel_hdmi }, |
687 | { .id = 0x80862804, .name = "G45 DEVIBX", .patch = patch_intel_hdmi }, | 929 | { .id = 0x80862804, .name = "G45 DEVIBX", .patch = patch_intel_hdmi }, |
688 | { .id = 0x80860054, .name = "Q57 DEVIBX", .patch = patch_intel_hdmi_ibexpeak }, | 930 | { .id = 0x80860054, .name = "Q57 DEVIBX", .patch = patch_intel_hdmi }, |
689 | { .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_intel_hdmi }, | 931 | { .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_intel_hdmi }, |
690 | {} /* terminator */ | 932 | {} /* terminator */ |
691 | }; | 933 | }; |