Skip to content

Commit

Permalink
ALSA: hda - Add support for HDMI HBR passthrough
Browse files Browse the repository at this point in the history
Passing IEC 61937 encapsulated compressed audio at bitrates over 6.144
Mbps (i.e. more than a single 2-channel 16-bit 192kHz IEC 60958 link)
over HDMI requires the use of HBR Audio Stream Packets instead of Audio
Sample Packets.

Enable HBR mode when the stream has 8 channels and the Non-PCM bit is
set.

If the audio converter is not connected to any HBR-capable pins, return
-EINVAL in prepare().

Signed-off-by: Anssi Hannula <anssi.hannula@iki.fi>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
  • Loading branch information
Anssi Hannula authored and Takashi Iwai committed Aug 3, 2010
1 parent 32c168c commit ea87d1c
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 5 deletions.
3 changes: 3 additions & 0 deletions sound/pci/hda/hda_codec.h
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,9 @@ enum {
#define AC_DIG2_CC (0x7f<<0)

/* Pin widget control - 8bit */
#define AC_PINCTL_EPT (0x3<<0)
#define AC_PINCTL_EPT_NATIVE 0
#define AC_PINCTL_EPT_HBR 3
#define AC_PINCTL_VREFEN (0x7<<0)
#define AC_PINCTL_VREF_HIZ 0 /* Hi-Z */
#define AC_PINCTL_VREF_50 1 /* 50% */
Expand Down
40 changes: 39 additions & 1 deletion sound/pci/hda/patch_hdmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -698,11 +698,48 @@ static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res)
* Callbacks
*/

static void hdmi_setup_stream(struct hda_codec *codec, hda_nid_t nid,
static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t nid,
u32 stream_tag, int format)
{
struct hdmi_spec *spec = codec->spec;
int tag;
int fmt;
int pinctl;
int new_pinctl = 0;
int i;

for (i = 0; i < spec->num_pins; i++) {
if (spec->pin_cvt[i] != nid)
continue;
if (!(snd_hda_query_pin_caps(codec, spec->pin[i]) & AC_PINCAP_HBR))
continue;

pinctl = snd_hda_codec_read(codec, spec->pin[i], 0,
AC_VERB_GET_PIN_WIDGET_CONTROL, 0);

new_pinctl = pinctl & ~AC_PINCTL_EPT;
/* Non-PCM, 8 channels */
if ((format & 0x8000) && (format & 0x0f) == 7)
new_pinctl |= AC_PINCTL_EPT_HBR;
else
new_pinctl |= AC_PINCTL_EPT_NATIVE;

snd_printdd("hdmi_setup_stream: "
"NID=0x%x, %spinctl=0x%x\n",
spec->pin[i],
pinctl == new_pinctl ? "" : "new-",
new_pinctl);

if (pinctl != new_pinctl)
snd_hda_codec_write(codec, spec->pin[i], 0,
AC_VERB_SET_PIN_WIDGET_CONTROL,
new_pinctl);
}

if ((format & 0x8000) && (format & 0x0f) == 7 && !new_pinctl) {
snd_printdd("hdmi_setup_stream: HBR is not supported\n");
return -EINVAL;
}

tag = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0) >> 4;
fmt = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_STREAM_FORMAT, 0);
Expand All @@ -722,6 +759,7 @@ static void hdmi_setup_stream(struct hda_codec *codec, hda_nid_t nid,
if (fmt != format)
snd_hda_codec_write(codec, nid, 0,
AC_VERB_SET_STREAM_FORMAT, format);
return 0;
}

/*
Expand Down
3 changes: 1 addition & 2 deletions sound/pci/hda/patch_intelhdmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,7 @@ static int intel_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,

hdmi_setup_audio_infoframe(codec, hinfo->nid, substream);

hdmi_setup_stream(codec, hinfo->nid, stream_tag, format);
return 0;
return hdmi_setup_stream(codec, hinfo->nid, stream_tag, format);
}

static int intel_hdmi_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
Expand Down
3 changes: 1 addition & 2 deletions sound/pci/hda/patch_nvhdmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -202,8 +202,7 @@ static int nvhdmi_dig_playback_pcm_prepare_8ch_89(struct hda_pcm_stream *hinfo,

hdmi_setup_audio_infoframe(codec, hinfo->nid, substream);

hdmi_setup_stream(codec, hinfo->nid, stream_tag, format);
return 0;
return hdmi_setup_stream(codec, hinfo->nid, stream_tag, format);
}

static int nvhdmi_dig_playback_pcm_prepare_8ch(struct hda_pcm_stream *hinfo,
Expand Down

0 comments on commit ea87d1c

Please sign in to comment.