aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorWu Fengguang <fengguang.wu@intel.com>2010-09-21 02:25:49 -0400
committerTakashi Iwai <tiwai@suse.de>2010-09-21 03:49:57 -0400
commit53d7d69d8ffdfa60c5b66cc2e9ee0774aaaef5c0 (patch)
treecfb3d48fe7e4a11cdae0a3adae67cdcc38461e59 /sound
parent0ec33d1f952934ea3251cefc6d108b47818eedd0 (diff)
ALSA: hdmi - support infoframe for DisplayPort
DisplayPort works mostly in the same way as HDMI, except that it expects a slightly different audio infoframe format. Citations from "HDA036-A: Display Port Support and HDMI Miscellaneous Corrections": The HDMI specification defines a data island packet with a header of 4 bytes (3 bytes content + 1 byte ECC) and packet body of 32 bytes (28 bytes content and 4 bytes ECC). Display Port specification on the other hand defines a data island packet (secondary data packet) with header of 4 bytes protected by 4 bytes of parity, and data of theoretically up to 1024 bytes with each 16 bytes chunk of data protected by 4 bytes of parity. Note that the ECC or parity bytes are not present in the DIP content populated by software and are hardware generated. It tests DP connection based on the ELD conn_type field, which will be set by the graphics driver and can be overriden manually by users through the /proc/asound/card0/eld* interface. The DP infoframe is tested OK on Intel SandyBridge/CougarPoint platform. Signed-off-by: Wu Fengguang <fengguang.wu@intel.com> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r--sound/pci/hda/patch_hdmi.c110
1 files changed, 73 insertions, 37 deletions
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index cb997ca0fdfa..1f4ae1aeca44 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -84,13 +84,25 @@ struct hdmi_audio_infoframe {
84 u8 ver; /* 0x01 */ 84 u8 ver; /* 0x01 */
85 u8 len; /* 0x0a */ 85 u8 len; /* 0x0a */
86 86
87 u8 checksum; /* PB0 */ 87 u8 checksum;
88
88 u8 CC02_CT47; /* CC in bits 0:2, CT in 4:7 */ 89 u8 CC02_CT47; /* CC in bits 0:2, CT in 4:7 */
89 u8 SS01_SF24; 90 u8 SS01_SF24;
90 u8 CXT04; 91 u8 CXT04;
91 u8 CA; 92 u8 CA;
92 u8 LFEPBL01_LSV36_DM_INH7; 93 u8 LFEPBL01_LSV36_DM_INH7;
93 u8 reserved[5]; /* PB6 - PB10 */ 94};
95
96struct dp_audio_infoframe {
97 u8 type; /* 0x84 */
98 u8 len; /* 0x1b */
99 u8 ver; /* 0x11 << 2 */
100
101 u8 CC02_CT47; /* match with HDMI infoframe from this on */
102 u8 SS01_SF24;
103 u8 CXT04;
104 u8 CA;
105 u8 LFEPBL01_LSV36_DM_INH7;
94}; 106};
95 107
96/* 108/*
@@ -194,7 +206,7 @@ static int hdmi_channel_mapping[0x32][8] = {
194 * This is an ordered list! 206 * This is an ordered list!
195 * 207 *
196 * The preceding ones have better chances to be selected by 208 * The preceding ones have better chances to be selected by
197 * hdmi_setup_channel_allocation(). 209 * hdmi_channel_allocation().
198 */ 210 */
199static struct cea_channel_speaker_allocation channel_allocations[] = { 211static struct cea_channel_speaker_allocation channel_allocations[] = {
200/* channel: 7 6 5 4 3 2 1 0 */ 212/* channel: 7 6 5 4 3 2 1 0 */
@@ -371,14 +383,14 @@ static void init_channel_allocations(void)
371 * 383 *
372 * TODO: it could select the wrong CA from multiple candidates. 384 * TODO: it could select the wrong CA from multiple candidates.
373*/ 385*/
374static int hdmi_setup_channel_allocation(struct hda_codec *codec, hda_nid_t nid, 386static int hdmi_channel_allocation(struct hda_codec *codec, hda_nid_t nid,
375 struct hdmi_audio_infoframe *ai) 387 int channels)
376{ 388{
377 struct hdmi_spec *spec = codec->spec; 389 struct hdmi_spec *spec = codec->spec;
378 struct hdmi_eld *eld; 390 struct hdmi_eld *eld;
379 int i; 391 int i;
392 int ca = 0;
380 int spk_mask = 0; 393 int spk_mask = 0;
381 int channels = 1 + (ai->CC02_CT47 & 0x7);
382 char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; 394 char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE];
383 395
384 /* 396 /*
@@ -416,16 +428,16 @@ static int hdmi_setup_channel_allocation(struct hda_codec *codec, hda_nid_t nid,
416 if (channels == channel_allocations[i].channels && 428 if (channels == channel_allocations[i].channels &&
417 (spk_mask & channel_allocations[i].spk_mask) == 429 (spk_mask & channel_allocations[i].spk_mask) ==
418 channel_allocations[i].spk_mask) { 430 channel_allocations[i].spk_mask) {
419 ai->CA = channel_allocations[i].ca_index; 431 ca = channel_allocations[i].ca_index;
420 break; 432 break;
421 } 433 }
422 } 434 }
423 435
424 snd_print_channel_allocation(eld->spk_alloc, buf, sizeof(buf)); 436 snd_print_channel_allocation(eld->spk_alloc, buf, sizeof(buf));
425 snd_printdd("HDMI: select CA 0x%x for %d-channel allocation: %s\n", 437 snd_printdd("HDMI: select CA 0x%x for %d-channel allocation: %s\n",
426 ai->CA, channels, buf); 438 ca, channels, buf);
427 439
428 return ai->CA; 440 return ca;
429} 441}
430 442
431static void hdmi_debug_channel_mapping(struct hda_codec *codec, 443static void hdmi_debug_channel_mapping(struct hda_codec *codec,
@@ -447,10 +459,9 @@ static void hdmi_debug_channel_mapping(struct hda_codec *codec,
447 459
448static void hdmi_setup_channel_mapping(struct hda_codec *codec, 460static void hdmi_setup_channel_mapping(struct hda_codec *codec,
449 hda_nid_t pin_nid, 461 hda_nid_t pin_nid,
450 struct hdmi_audio_infoframe *ai) 462 int ca)
451{ 463{
452 int i; 464 int i;
453 int ca = ai->CA;
454 int err; 465 int err;
455 466
456 if (hdmi_channel_mapping[ca][1] == 0) { 467 if (hdmi_channel_mapping[ca][1] == 0) {
@@ -547,41 +558,37 @@ static void hdmi_clear_dip_buffers(struct hda_codec *codec, hda_nid_t pin_nid)
547#endif 558#endif
548} 559}
549 560
550static void hdmi_checksum_audio_infoframe(struct hdmi_audio_infoframe *ai) 561static void hdmi_checksum_audio_infoframe(struct hdmi_audio_infoframe *hdmi_ai)
551{ 562{
552 u8 *bytes = (u8 *)ai; 563 u8 *bytes = (u8 *)hdmi_ai;
553 u8 sum = 0; 564 u8 sum = 0;
554 int i; 565 int i;
555 566
556 ai->checksum = 0; 567 hdmi_ai->checksum = 0;
557 568
558 for (i = 0; i < sizeof(*ai); i++) 569 for (i = 0; i < sizeof(*hdmi_ai); i++)
559 sum += bytes[i]; 570 sum += bytes[i];
560 571
561 ai->checksum = -sum; 572 hdmi_ai->checksum = -sum;
562} 573}
563 574
564static void hdmi_fill_audio_infoframe(struct hda_codec *codec, 575static void hdmi_fill_audio_infoframe(struct hda_codec *codec,
565 hda_nid_t pin_nid, 576 hda_nid_t pin_nid,
566 struct hdmi_audio_infoframe *ai) 577 u8 *dip, int size)
567{ 578{
568 u8 *bytes = (u8 *)ai;
569 int i; 579 int i;
570 580
571 hdmi_debug_dip_size(codec, pin_nid); 581 hdmi_debug_dip_size(codec, pin_nid);
572 hdmi_clear_dip_buffers(codec, pin_nid); /* be paranoid */ 582 hdmi_clear_dip_buffers(codec, pin_nid); /* be paranoid */
573 583
574 hdmi_checksum_audio_infoframe(ai);
575
576 hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0); 584 hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
577 for (i = 0; i < sizeof(*ai); i++) 585 for (i = 0; i < size; i++)
578 hdmi_write_dip_byte(codec, pin_nid, bytes[i]); 586 hdmi_write_dip_byte(codec, pin_nid, dip[i]);
579} 587}
580 588
581static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid, 589static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid,
582 struct hdmi_audio_infoframe *ai) 590 u8 *dip, int size)
583{ 591{
584 u8 *bytes = (u8 *)ai;
585 u8 val; 592 u8 val;
586 int i; 593 int i;
587 594
@@ -590,10 +597,10 @@ static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid,
590 return false; 597 return false;
591 598
592 hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0); 599 hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
593 for (i = 0; i < sizeof(*ai); i++) { 600 for (i = 0; i < size; i++) {
594 val = snd_hda_codec_read(codec, pin_nid, 0, 601 val = snd_hda_codec_read(codec, pin_nid, 0,
595 AC_VERB_GET_HDMI_DIP_DATA, 0); 602 AC_VERB_GET_HDMI_DIP_DATA, 0);
596 if (val != bytes[i]) 603 if (val != dip[i])
597 return false; 604 return false;
598 } 605 }
599 606
@@ -605,15 +612,13 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid,
605{ 612{
606 struct hdmi_spec *spec = codec->spec; 613 struct hdmi_spec *spec = codec->spec;
607 hda_nid_t pin_nid; 614 hda_nid_t pin_nid;
615 int channels = substream->runtime->channels;
616 int ca;
608 int i; 617 int i;
609 struct hdmi_audio_infoframe ai = { 618 u8 ai[max(sizeof(struct hdmi_audio_infoframe),
610 .type = 0x84, 619 sizeof(struct dp_audio_infoframe))];
611 .ver = 0x01,
612 .len = 0x0a,
613 .CC02_CT47 = substream->runtime->channels - 1,
614 };
615 620
616 hdmi_setup_channel_allocation(codec, nid, &ai); 621 ca = hdmi_channel_allocation(codec, nid, channels);
617 622
618 for (i = 0; i < spec->num_pins; i++) { 623 for (i = 0; i < spec->num_pins; i++) {
619 if (spec->pin_cvt[i] != nid) 624 if (spec->pin_cvt[i] != nid)
@@ -622,14 +627,45 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid,
622 continue; 627 continue;
623 628
624 pin_nid = spec->pin[i]; 629 pin_nid = spec->pin[i];
625 if (!hdmi_infoframe_uptodate(codec, pin_nid, &ai)) { 630
631 memset(ai, 0, sizeof(ai));
632 if (spec->sink_eld[i].conn_type == 0) { /* HDMI */
633 struct hdmi_audio_infoframe *hdmi_ai;
634
635 hdmi_ai = (struct hdmi_audio_infoframe *)ai;
636 hdmi_ai->type = 0x84;
637 hdmi_ai->ver = 0x01;
638 hdmi_ai->len = 0x0a;
639 hdmi_ai->CC02_CT47 = channels - 1;
640 hdmi_checksum_audio_infoframe(hdmi_ai);
641 } else if (spec->sink_eld[i].conn_type == 1) { /* DisplayPort */
642 struct dp_audio_infoframe *dp_ai;
643
644 dp_ai = (struct dp_audio_infoframe *)ai;
645 dp_ai->type = 0x84;
646 dp_ai->len = 0x1b;
647 dp_ai->ver = 0x11 << 2;
648 dp_ai->CC02_CT47 = channels - 1;
649 } 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 */
660 if (!hdmi_infoframe_uptodate(codec, pin_nid, ai, sizeof(ai))) {
626 snd_printdd("hdmi_setup_audio_infoframe: " 661 snd_printdd("hdmi_setup_audio_infoframe: "
627 "cvt=%d pin=%d channels=%d\n", 662 "cvt=%d pin=%d channels=%d\n",
628 nid, pin_nid, 663 nid, pin_nid,
629 substream->runtime->channels); 664 channels);
630 hdmi_setup_channel_mapping(codec, pin_nid, &ai); 665 hdmi_setup_channel_mapping(codec, pin_nid, ca);
631 hdmi_stop_infoframe_trans(codec, pin_nid); 666 hdmi_stop_infoframe_trans(codec, pin_nid);
632 hdmi_fill_audio_infoframe(codec, pin_nid, &ai); 667 hdmi_fill_audio_infoframe(codec, pin_nid,
668 ai, sizeof(ai));
633 hdmi_start_infoframe_trans(codec, pin_nid); 669 hdmi_start_infoframe_trans(codec, pin_nid);
634 } 670 }
635 } 671 }