diff options
author | Wang Xingchao <xingchao.wang@intel.com> | 2012-09-05 22:02:37 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2012-09-06 02:50:33 -0400 |
commit | 433968da4d93a194b79da552f4ca707f979ef33b (patch) | |
tree | 848adec2f796dc999f2bbaff2c061db23810521d /sound/pci/hda | |
parent | 72357c78b75d39ee9e8d9fb4308957d9525aa674 (diff) |
ALSA: HDMI - Enable HBR feature on Intel chips
HDMI channel remapping apparently effects HBR packets on Intel's chips.
For compressed non-PCM audio, use "straight-through" channel mapping.
For uncompressed multi-channel pcm audio, use normal channel mapping.
Signed-off-by: Wang Xingchao <xingchao.wang@intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda')
-rw-r--r-- | sound/pci/hda/patch_hdmi.c | 36 |
1 files changed, 32 insertions, 4 deletions
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 4fb8199d813a..a6835bd9d9b5 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/module.h> | 34 | #include <linux/module.h> |
35 | #include <sound/core.h> | 35 | #include <sound/core.h> |
36 | #include <sound/jack.h> | 36 | #include <sound/jack.h> |
37 | #include <sound/asoundef.h> | ||
37 | #include "hda_codec.h" | 38 | #include "hda_codec.h" |
38 | #include "hda_local.h" | 39 | #include "hda_local.h" |
39 | #include "hda_jack.h" | 40 | #include "hda_jack.h" |
@@ -60,6 +61,7 @@ struct hdmi_spec_per_cvt { | |||
60 | u32 rates; | 61 | u32 rates; |
61 | u64 formats; | 62 | u64 formats; |
62 | unsigned int maxbps; | 63 | unsigned int maxbps; |
64 | bool non_pcm; | ||
63 | }; | 65 | }; |
64 | 66 | ||
65 | struct hdmi_spec_per_pin { | 67 | struct hdmi_spec_per_pin { |
@@ -548,13 +550,17 @@ static void hdmi_debug_channel_mapping(struct hda_codec *codec, | |||
548 | 550 | ||
549 | static void hdmi_setup_channel_mapping(struct hda_codec *codec, | 551 | static void hdmi_setup_channel_mapping(struct hda_codec *codec, |
550 | hda_nid_t pin_nid, | 552 | hda_nid_t pin_nid, |
553 | hda_nid_t cvt_nid, | ||
554 | bool non_pcm, | ||
551 | int ca) | 555 | int ca) |
552 | { | 556 | { |
553 | int i; | 557 | int i; |
554 | int err; | 558 | int err; |
555 | int order; | 559 | int order; |
560 | int non_pcm_mapping[8]; | ||
556 | 561 | ||
557 | order = get_channel_allocation_order(ca); | 562 | order = get_channel_allocation_order(ca); |
563 | |||
558 | if (hdmi_channel_mapping[ca][1] == 0) { | 564 | if (hdmi_channel_mapping[ca][1] == 0) { |
559 | for (i = 0; i < channel_allocations[order].channels; i++) | 565 | for (i = 0; i < channel_allocations[order].channels; i++) |
560 | hdmi_channel_mapping[ca][i] = i | (i << 4); | 566 | hdmi_channel_mapping[ca][i] = i | (i << 4); |
@@ -562,10 +568,17 @@ static void hdmi_setup_channel_mapping(struct hda_codec *codec, | |||
562 | hdmi_channel_mapping[ca][i] = 0xf | (i << 4); | 568 | hdmi_channel_mapping[ca][i] = 0xf | (i << 4); |
563 | } | 569 | } |
564 | 570 | ||
571 | if (non_pcm) { | ||
572 | for (i = 0; i < channel_allocations[order].channels; i++) | ||
573 | non_pcm_mapping[i] = i | (i << 4); | ||
574 | for (; i < 8; i++) | ||
575 | non_pcm_mapping[i] = 0xf | (i << 4); | ||
576 | } | ||
577 | |||
565 | for (i = 0; i < 8; i++) { | 578 | for (i = 0; i < 8; i++) { |
566 | err = snd_hda_codec_write(codec, pin_nid, 0, | 579 | err = snd_hda_codec_write(codec, pin_nid, 0, |
567 | AC_VERB_SET_HDMI_CHAN_SLOT, | 580 | AC_VERB_SET_HDMI_CHAN_SLOT, |
568 | hdmi_channel_mapping[ca][i]); | 581 | non_pcm ? non_pcm_mapping[i] : hdmi_channel_mapping[ca][i]); |
569 | if (err) { | 582 | if (err) { |
570 | snd_printdd(KERN_NOTICE | 583 | snd_printdd(KERN_NOTICE |
571 | "HDMI: channel mapping failed\n"); | 584 | "HDMI: channel mapping failed\n"); |
@@ -699,15 +712,27 @@ static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid, | |||
699 | } | 712 | } |
700 | 713 | ||
701 | static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx, | 714 | static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx, |
702 | struct snd_pcm_substream *substream) | 715 | hda_nid_t cvt_nid, struct snd_pcm_substream *substream) |
703 | { | 716 | { |
704 | struct hdmi_spec *spec = codec->spec; | 717 | struct hdmi_spec *spec = codec->spec; |
705 | struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; | 718 | struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; |
719 | struct hdmi_spec_per_cvt *per_cvt; | ||
720 | struct hda_spdif_out *spdif; | ||
706 | hda_nid_t pin_nid = per_pin->pin_nid; | 721 | hda_nid_t pin_nid = per_pin->pin_nid; |
707 | int channels = substream->runtime->channels; | 722 | int channels = substream->runtime->channels; |
708 | struct hdmi_eld *eld; | 723 | struct hdmi_eld *eld; |
709 | int ca; | 724 | int ca; |
725 | int cvt_idx; | ||
710 | union audio_infoframe ai; | 726 | union audio_infoframe ai; |
727 | bool non_pcm = false; | ||
728 | |||
729 | cvt_idx = cvt_nid_to_cvt_index(spec, cvt_nid); | ||
730 | per_cvt = &spec->cvts[cvt_idx]; | ||
731 | |||
732 | mutex_lock(&codec->spdif_mutex); | ||
733 | spdif = snd_hda_spdif_out_of_nid(codec, cvt_nid); | ||
734 | non_pcm = !!(spdif->status & IEC958_AES0_NONAUDIO); | ||
735 | mutex_unlock(&codec->spdif_mutex); | ||
711 | 736 | ||
712 | eld = &spec->pins[pin_idx].sink_eld; | 737 | eld = &spec->pins[pin_idx].sink_eld; |
713 | if (!eld->monitor_present) | 738 | if (!eld->monitor_present) |
@@ -750,12 +775,14 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx, | |||
750 | "pin=%d channels=%d\n", | 775 | "pin=%d channels=%d\n", |
751 | pin_nid, | 776 | pin_nid, |
752 | channels); | 777 | channels); |
753 | hdmi_setup_channel_mapping(codec, pin_nid, ca); | 778 | hdmi_setup_channel_mapping(codec, pin_nid, cvt_nid, non_pcm, ca); |
754 | hdmi_stop_infoframe_trans(codec, pin_nid); | 779 | hdmi_stop_infoframe_trans(codec, pin_nid); |
755 | hdmi_fill_audio_infoframe(codec, pin_nid, | 780 | hdmi_fill_audio_infoframe(codec, pin_nid, |
756 | ai.bytes, sizeof(ai)); | 781 | ai.bytes, sizeof(ai)); |
757 | hdmi_start_infoframe_trans(codec, pin_nid); | 782 | hdmi_start_infoframe_trans(codec, pin_nid); |
758 | } | 783 | } |
784 | |||
785 | per_cvt->non_pcm = non_pcm; | ||
759 | } | 786 | } |
760 | 787 | ||
761 | 788 | ||
@@ -1077,6 +1104,7 @@ static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t cvt_nid) | |||
1077 | 1104 | ||
1078 | per_cvt->cvt_nid = cvt_nid; | 1105 | per_cvt->cvt_nid = cvt_nid; |
1079 | per_cvt->channels_min = 2; | 1106 | per_cvt->channels_min = 2; |
1107 | per_cvt->non_pcm = false; | ||
1080 | if (chans <= 16) | 1108 | if (chans <= 16) |
1081 | per_cvt->channels_max = chans; | 1109 | per_cvt->channels_max = chans; |
1082 | 1110 | ||
@@ -1164,7 +1192,7 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | |||
1164 | 1192 | ||
1165 | hdmi_set_channel_count(codec, cvt_nid, substream->runtime->channels); | 1193 | hdmi_set_channel_count(codec, cvt_nid, substream->runtime->channels); |
1166 | 1194 | ||
1167 | hdmi_setup_audio_infoframe(codec, pin_idx, substream); | 1195 | hdmi_setup_audio_infoframe(codec, pin_idx, cvt_nid, substream); |
1168 | 1196 | ||
1169 | pinctl = snd_hda_codec_read(codec, pin_nid, 0, | 1197 | pinctl = snd_hda_codec_read(codec, pin_nid, 0, |
1170 | AC_VERB_GET_PIN_WIDGET_CONTROL, 0); | 1198 | AC_VERB_GET_PIN_WIDGET_CONTROL, 0); |