aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
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 cb997ca0fdf..1f4ae1aeca4 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 }