Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ea87d1c4 authored by Anssi Hannula's avatar Anssi Hannula Committed by Takashi Iwai
Browse files

ALSA: hda - Add support for HDMI HBR passthrough



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: default avatarAnssi Hannula <anssi.hannula@iki.fi>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 32c168c8
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -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% */
+39 −1
Original line number Diff line number Diff line
@@ -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);
@@ -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;
}

/*
+1 −2
Original line number Diff line number Diff line
@@ -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,
+1 −2
Original line number Diff line number Diff line
@@ -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,