aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/hda_eld.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/hda/hda_eld.c')
-rw-r--r--sound/pci/hda/hda_eld.c199
1 files changed, 156 insertions, 43 deletions
diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c
index d0d7ac1e99d2..32d3e3855a6e 100644
--- a/sound/pci/hda/hda_eld.c
+++ b/sound/pci/hda/hda_eld.c
@@ -2,6 +2,7 @@
2 * Generic routines and proc interface for ELD(EDID Like Data) information 2 * Generic routines and proc interface for ELD(EDID Like Data) information
3 * 3 *
4 * Copyright(c) 2008 Intel Corporation. 4 * Copyright(c) 2008 Intel Corporation.
5 * Copyright (c) 2013 Anssi Hannula <anssi.hannula@iki.fi>
5 * 6 *
6 * Authors: 7 * Authors:
7 * Wu Fengguang <wfg@linux.intel.com> 8 * Wu Fengguang <wfg@linux.intel.com>
@@ -478,10 +479,9 @@ static void hdmi_print_sad_info(int i, struct cea_sad *a,
478 snd_iprintf(buffer, "sad%d_profile\t\t%d\n", i, a->profile); 479 snd_iprintf(buffer, "sad%d_profile\t\t%d\n", i, a->profile);
479} 480}
480 481
481static void hdmi_print_eld_info(struct snd_info_entry *entry, 482void snd_hdmi_print_eld_info(struct hdmi_eld *eld,
482 struct snd_info_buffer *buffer) 483 struct snd_info_buffer *buffer)
483{ 484{
484 struct hdmi_eld *eld = entry->private_data;
485 struct parsed_hdmi_eld *e = &eld->info; 485 struct parsed_hdmi_eld *e = &eld->info;
486 char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; 486 char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE];
487 int i; 487 int i;
@@ -500,13 +500,10 @@ static void hdmi_print_eld_info(struct snd_info_entry *entry,
500 [4 ... 7] = "reserved" 500 [4 ... 7] = "reserved"
501 }; 501 };
502 502
503 mutex_lock(&eld->lock);
504 snd_iprintf(buffer, "monitor_present\t\t%d\n", eld->monitor_present); 503 snd_iprintf(buffer, "monitor_present\t\t%d\n", eld->monitor_present);
505 snd_iprintf(buffer, "eld_valid\t\t%d\n", eld->eld_valid); 504 snd_iprintf(buffer, "eld_valid\t\t%d\n", eld->eld_valid);
506 if (!eld->eld_valid) { 505 if (!eld->eld_valid)
507 mutex_unlock(&eld->lock);
508 return; 506 return;
509 }
510 snd_iprintf(buffer, "monitor_name\t\t%s\n", e->monitor_name); 507 snd_iprintf(buffer, "monitor_name\t\t%s\n", e->monitor_name);
511 snd_iprintf(buffer, "connection_type\t\t%s\n", 508 snd_iprintf(buffer, "connection_type\t\t%s\n",
512 eld_connection_type_names[e->conn_type]); 509 eld_connection_type_names[e->conn_type]);
@@ -528,13 +525,11 @@ static void hdmi_print_eld_info(struct snd_info_entry *entry,
528 525
529 for (i = 0; i < e->sad_count; i++) 526 for (i = 0; i < e->sad_count; i++)
530 hdmi_print_sad_info(i, e->sad + i, buffer); 527 hdmi_print_sad_info(i, e->sad + i, buffer);
531 mutex_unlock(&eld->lock);
532} 528}
533 529
534static void hdmi_write_eld_info(struct snd_info_entry *entry, 530void snd_hdmi_write_eld_info(struct hdmi_eld *eld,
535 struct snd_info_buffer *buffer) 531 struct snd_info_buffer *buffer)
536{ 532{
537 struct hdmi_eld *eld = entry->private_data;
538 struct parsed_hdmi_eld *e = &eld->info; 533 struct parsed_hdmi_eld *e = &eld->info;
539 char line[64]; 534 char line[64];
540 char name[64]; 535 char name[64];
@@ -542,7 +537,6 @@ static void hdmi_write_eld_info(struct snd_info_entry *entry,
542 long long val; 537 long long val;
543 unsigned int n; 538 unsigned int n;
544 539
545 mutex_lock(&eld->lock);
546 while (!snd_info_get_line(buffer, line, sizeof(line))) { 540 while (!snd_info_get_line(buffer, line, sizeof(line))) {
547 if (sscanf(line, "%s %llx", name, &val) != 2) 541 if (sscanf(line, "%s %llx", name, &val) != 2)
548 continue; 542 continue;
@@ -594,38 +588,7 @@ static void hdmi_write_eld_info(struct snd_info_entry *entry,
594 e->sad_count = n + 1; 588 e->sad_count = n + 1;
595 } 589 }
596 } 590 }
597 mutex_unlock(&eld->lock);
598}
599
600
601int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld,
602 int index)
603{
604 char name[32];
605 struct snd_info_entry *entry;
606 int err;
607
608 snprintf(name, sizeof(name), "eld#%d.%d", codec->addr, index);
609 err = snd_card_proc_new(codec->bus->card, name, &entry);
610 if (err < 0)
611 return err;
612
613 snd_info_set_text_ops(entry, eld, hdmi_print_eld_info);
614 entry->c.text.write = hdmi_write_eld_info;
615 entry->mode |= S_IWUSR;
616 eld->proc_entry = entry;
617
618 return 0;
619}
620
621void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld)
622{
623 if (!codec->bus->shutdown && eld->proc_entry) {
624 snd_device_free(codec->bus->card, eld->proc_entry);
625 eld->proc_entry = NULL;
626 }
627} 591}
628
629#endif /* CONFIG_PROC_FS */ 592#endif /* CONFIG_PROC_FS */
630 593
631/* update PCM info based on ELD */ 594/* update PCM info based on ELD */
@@ -671,3 +634,153 @@ void snd_hdmi_eld_update_pcm_info(struct parsed_hdmi_eld *e,
671 hinfo->maxbps = min(hinfo->maxbps, maxbps); 634 hinfo->maxbps = min(hinfo->maxbps, maxbps);
672 hinfo->channels_max = min(hinfo->channels_max, channels_max); 635 hinfo->channels_max = min(hinfo->channels_max, channels_max);
673} 636}
637
638
639/* ATI/AMD specific stuff (ELD emulation) */
640
641#define ATI_VERB_SET_AUDIO_DESCRIPTOR 0x776
642#define ATI_VERB_SET_SINK_INFO_INDEX 0x780
643#define ATI_VERB_GET_SPEAKER_ALLOCATION 0xf70
644#define ATI_VERB_GET_AUDIO_DESCRIPTOR 0xf76
645#define ATI_VERB_GET_AUDIO_VIDEO_DELAY 0xf7b
646#define ATI_VERB_GET_SINK_INFO_INDEX 0xf80
647#define ATI_VERB_GET_SINK_INFO_DATA 0xf81
648
649#define ATI_SPKALLOC_SPKALLOC 0x007f
650#define ATI_SPKALLOC_TYPE_HDMI 0x0100
651#define ATI_SPKALLOC_TYPE_DISPLAYPORT 0x0200
652
653/* first three bytes are just standard SAD */
654#define ATI_AUDIODESC_CHANNELS 0x00000007
655#define ATI_AUDIODESC_RATES 0x0000ff00
656#define ATI_AUDIODESC_LPCM_STEREO_RATES 0xff000000
657
658/* in standard HDMI VSDB format */
659#define ATI_DELAY_VIDEO_LATENCY 0x000000ff
660#define ATI_DELAY_AUDIO_LATENCY 0x0000ff00
661
662enum ati_sink_info_idx {
663 ATI_INFO_IDX_MANUFACTURER_ID = 0,
664 ATI_INFO_IDX_PRODUCT_ID = 1,
665 ATI_INFO_IDX_SINK_DESC_LEN = 2,
666 ATI_INFO_IDX_PORT_ID_LOW = 3,
667 ATI_INFO_IDX_PORT_ID_HIGH = 4,
668 ATI_INFO_IDX_SINK_DESC_FIRST = 5,
669 ATI_INFO_IDX_SINK_DESC_LAST = 22, /* max len 18 bytes */
670};
671
672int snd_hdmi_get_eld_ati(struct hda_codec *codec, hda_nid_t nid,
673 unsigned char *buf, int *eld_size, bool rev3_or_later)
674{
675 int spkalloc, ati_sad, aud_synch;
676 int sink_desc_len = 0;
677 int pos, i;
678
679 /* ATI/AMD does not have ELD, emulate it */
680
681 spkalloc = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SPEAKER_ALLOCATION, 0);
682
683 if (!spkalloc) {
684 snd_printd(KERN_INFO "HDMI ATI/AMD: no speaker allocation for ELD\n");
685 return -EINVAL;
686 }
687
688 memset(buf, 0, ELD_FIXED_BYTES + ELD_MAX_MNL + ELD_MAX_SAD * 3);
689
690 /* version */
691 buf[0] = ELD_VER_CEA_861D << 3;
692
693 /* speaker allocation from EDID */
694 buf[7] = spkalloc & ATI_SPKALLOC_SPKALLOC;
695
696 /* is DisplayPort? */
697 if (spkalloc & ATI_SPKALLOC_TYPE_DISPLAYPORT)
698 buf[5] |= 0x04;
699
700 pos = ELD_FIXED_BYTES;
701
702 if (rev3_or_later) {
703 int sink_info;
704
705 snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_PORT_ID_LOW);
706 sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
707 put_unaligned_le32(sink_info, buf + 8);
708
709 snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_PORT_ID_HIGH);
710 sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
711 put_unaligned_le32(sink_info, buf + 12);
712
713 snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_MANUFACTURER_ID);
714 sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
715 put_unaligned_le16(sink_info, buf + 16);
716
717 snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_PRODUCT_ID);
718 sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
719 put_unaligned_le16(sink_info, buf + 18);
720
721 snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_SINK_DESC_LEN);
722 sink_desc_len = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
723
724 if (sink_desc_len > ELD_MAX_MNL) {
725 snd_printd(KERN_INFO "HDMI ATI/AMD: Truncating HDMI sink description with length %d\n",
726 sink_desc_len);
727 sink_desc_len = ELD_MAX_MNL;
728 }
729
730 buf[4] |= sink_desc_len;
731
732 for (i = 0; i < sink_desc_len; i++) {
733 snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_SINK_DESC_FIRST + i);
734 buf[pos++] = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
735 }
736 }
737
738 for (i = AUDIO_CODING_TYPE_LPCM; i <= AUDIO_CODING_TYPE_WMAPRO; i++) {
739 if (i == AUDIO_CODING_TYPE_SACD || i == AUDIO_CODING_TYPE_DST)
740 continue; /* not handled by ATI/AMD */
741
742 snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_AUDIO_DESCRIPTOR, i << 3);
743 ati_sad = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_AUDIO_DESCRIPTOR, 0);
744
745 if (ati_sad & ATI_AUDIODESC_RATES) {
746 /* format is supported, copy SAD as-is */
747 buf[pos++] = (ati_sad & 0x0000ff) >> 0;
748 buf[pos++] = (ati_sad & 0x00ff00) >> 8;
749 buf[pos++] = (ati_sad & 0xff0000) >> 16;
750 }
751
752 if (i == AUDIO_CODING_TYPE_LPCM
753 && (ati_sad & ATI_AUDIODESC_LPCM_STEREO_RATES)
754 && (ati_sad & ATI_AUDIODESC_LPCM_STEREO_RATES) >> 16 != (ati_sad & ATI_AUDIODESC_RATES)) {
755 /* for PCM there is a separate stereo rate mask */
756 buf[pos++] = ((ati_sad & 0x000000ff) & ~ATI_AUDIODESC_CHANNELS) | 0x1;
757 /* rates from the extra byte */
758 buf[pos++] = (ati_sad & 0xff000000) >> 24;
759 buf[pos++] = (ati_sad & 0x00ff0000) >> 16;
760 }
761 }
762
763 if (pos == ELD_FIXED_BYTES + sink_desc_len) {
764 snd_printd(KERN_INFO "HDMI ATI/AMD: no audio descriptors for ELD\n");
765 return -EINVAL;
766 }
767
768 aud_synch = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_AUDIO_VIDEO_DELAY, 0);
769 if ((aud_synch & ATI_DELAY_VIDEO_LATENCY) && (aud_synch & ATI_DELAY_AUDIO_LATENCY)) {
770 int video_latency = (aud_synch & ATI_DELAY_VIDEO_LATENCY) - 1;
771 int audio_latency = ((aud_synch & ATI_DELAY_AUDIO_LATENCY) >> 8) - 1;
772
773 if (video_latency > audio_latency)
774 buf[6] = min(video_latency - audio_latency, 0xfa);
775 }
776
777 /* Baseline length */
778 buf[2] = pos - 4;
779
780 /* SAD count */
781 buf[5] |= ((pos - ELD_FIXED_BYTES - sink_desc_len) / 3) << 4;
782
783 *eld_size = pos;
784
785 return 0;
786}