diff mbox

[05/11] ASoC: hdac_hdmi: Add multichannel support

Message ID 1460437293-8509-6-git-send-email-subhransu.s.prusty@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Subhransu S. Prusty April 12, 2016, 5:01 a.m. UTC
To support multichannel hdac hdmi driver registers with HDA
channel map framework. Channel count and channel slot verbs are
programmed by using the chmap helpers/ops.  The channel
allocation is then programmed in the audio infoframe as per CEA
spec.

Signed-off-by: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
---
 sound/soc/codecs/hdac_hdmi.c | 52 ++++++++++++++++++++++++++++++++++++--------
 1 file changed, 43 insertions(+), 9 deletions(-)

Comments

Pierre-Louis Bossart April 12, 2016, 12:25 p.m. UTC | #1
-	/* Only stereo supported as of now */
-	cvt->params.channels_min = cvt->params.channels_max = 2;
+	chans = get_wcaps(hdac, cvt->nid);
+	chans = get_wcaps_channels(chans);
+
+	cvt->params.channels_min = 2;
+
+	if (chans <= 16) {
+		cvt->params.channels_max = chans;
+		if (chans > hdmi->chmap.channels_max)
+			hdmi->chmap.channels_max = chans;
+	}t


Are you sure about this? HDMI can only handle 8 channels in Layout 2. 
There's no support for 16 ch.
Subhransu S. Prusty April 12, 2016, 1:36 p.m. UTC | #2
On Tue, Apr 12, 2016 at 07:25:33AM -0500, Pierre-Louis Bossart wrote:
> 
> -	/* Only stereo supported as of now */
> -	cvt->params.channels_min = cvt->params.channels_max = 2;
> +	chans = get_wcaps(hdac, cvt->nid);
> +	chans = get_wcaps_channels(chans);
> +
> +	cvt->params.channels_min = 2;
> +
> +	if (chans <= 16) {
> +		cvt->params.channels_max = chans;
> +		if (chans > hdmi->chmap.channels_max)
> +			hdmi->chmap.channels_max = chans;
> +	}t
> 
> 
> Are you sure about this? HDMI can only handle 8 channels in Layout
> 2. There's no support for 16 ch.

I copied this change form patch_hdmi.c. From the git history I couldn't
find why it is 16 ch. May be Takashi/Mengdong/Libin can confirm on this?

Regards,
Subhransu

>
Takashi Iwai April 12, 2016, 1:50 p.m. UTC | #3
On Tue, 12 Apr 2016 15:36:33 +0200,
Subhransu S. Prusty wrote:
> 
> On Tue, Apr 12, 2016 at 07:25:33AM -0500, Pierre-Louis Bossart wrote:
> > 
> > -	/* Only stereo supported as of now */
> > -	cvt->params.channels_min = cvt->params.channels_max = 2;
> > +	chans = get_wcaps(hdac, cvt->nid);
> > +	chans = get_wcaps_channels(chans);
> > +
> > +	cvt->params.channels_min = 2;
> > +
> > +	if (chans <= 16) {
> > +		cvt->params.channels_max = chans;
> > +		if (chans > hdmi->chmap.channels_max)
> > +			hdmi->chmap.channels_max = chans;
> > +	}t
> > 
> > 
> > Are you sure about this? HDMI can only handle 8 channels in Layout
> > 2. There's no support for 16 ch.
> 
> I copied this change form patch_hdmi.c. From the git history I couldn't
> find why it is 16 ch. May be Takashi/Mengdong/Libin can confirm on this?

It's the max value the HD-audio widget capability bits may give.  We
don't check about the actual device limit there, only about the codec
chip capabilities.

Actually, with the recent code, the check is mostly useless, as it
can't be over 16.  You can apply it unconditionally.


Takashi
diff mbox

Patch

diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c
index 9d3b33b..a2f949c 100644
--- a/sound/soc/codecs/hdac_hdmi.c
+++ b/sound/soc/codecs/hdac_hdmi.c
@@ -29,6 +29,7 @@ 
 #include <sound/hdaudio_ext.h>
 #include <sound/hda_i915.h>
 #include <sound/pcm_drm_eld.h>
+#include <sound/hda_chmap.h>
 #include "../../hda/local.h"
 #include "hdac_hdmi.h"
 
@@ -82,6 +83,10 @@  struct hdac_hdmi_pin {
 	struct hdac_ext_device *edev;
 	int repoll_count;
 	struct delayed_work work;
+	struct mutex lock;
+	bool chmap_set;
+	unsigned char chmap[8]; /* ALSA API channel-map */
+	int channels; /* current number of channels */
 };
 
 struct hdac_hdmi_pcm {
@@ -106,6 +111,7 @@  struct hdac_hdmi_priv {
 	int num_pin;
 	int num_cvt;
 	struct mutex pin_mutex;
+	struct hdac_chmap chmap;
 };
 
 static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev)
@@ -284,26 +290,31 @@  static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac,
 	int i;
 	const u8 *eld_buf;
 	u8 conn_type;
-	int channels = 2;
+	int channels, ca;
 
 	list_for_each_entry(pin, &hdmi->pin_list, head) {
 		if (pin->nid == pin_nid)
 			break;
 	}
 
+	ca = snd_hdac_channel_allocation(&hdac->hdac, pin->eld.info.spk_alloc,
+			pin->channels, pin->chmap_set, true, pin->chmap);
+
+	channels = snd_hdac_get_active_channels(ca);
+	hdmi->chmap.ops.set_channel_count(&hdac->hdac, cvt_nid, channels);
+
+	snd_hdac_setup_channel_mapping(&hdmi->chmap, pin->nid, false, ca,
+				pin->channels, pin->chmap, pin->chmap_set);
+
 	eld_buf = pin->eld.eld_buffer;
 	conn_type = drm_eld_get_conn_type(eld_buf);
 
-	/* setup channel count */
-	snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0,
-			    AC_VERB_SET_CVT_CHAN_COUNT, channels - 1);
-
 	switch (conn_type) {
 	case DRM_ELD_CONN_TYPE_HDMI:
 		hdmi_audio_infoframe_init(&frame);
 
-		/* Default stereo for now */
 		frame.channels = channels;
+		frame.channel_allocation = ca;
 
 		ret = hdmi_audio_infoframe_pack(&frame, buffer, sizeof(buffer));
 		if (ret < 0)
@@ -317,7 +328,7 @@  static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac,
 		dp_ai.len	= 0x1b;
 		dp_ai.ver	= 0x11 << 2;
 		dp_ai.CC02_CT47	= channels - 1;
-		dp_ai.CA	= 0;
+		dp_ai.CA	= ca;
 
 		dip = (u8 *)&dp_ai;
 		break;
@@ -376,17 +387,23 @@  static int hdac_hdmi_playback_prepare(struct snd_pcm_substream *substream,
 	struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
 	struct hdac_hdmi_priv *hdmi = hdac->private_data;
 	struct hdac_hdmi_dai_pin_map *dai_map;
+	struct hdac_hdmi_pin *pin;
 	struct hdac_ext_dma_params *dd;
 	int ret;
 
 	dai_map = &hdmi->dai_map[dai->id];
+	pin = dai_map->pin;
 
 	dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream);
 	dev_dbg(&hdac->hdac.dev, "stream tag from cpu dai %d format in cvt 0x%x\n",
 			dd->stream_tag,	dd->format);
 
+	mutex_lock(&pin->lock);
+	pin->channels = substream->runtime->channels;
+
 	ret = hdac_hdmi_setup_audio_infoframe(hdac, dai_map->cvt->nid,
 						dai_map->pin->nid);
+	mutex_unlock(&pin->lock);
 	if (ret < 0)
 		return ret;
 
@@ -646,6 +663,10 @@  static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream,
 		snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0,
 			AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
 
+		mutex_lock(&dai_map->pin->lock);
+		dai_map->pin->channels = 0;
+		mutex_unlock(&dai_map->pin->lock);
+
 		dai_map->pin = NULL;
 	}
 }
@@ -653,10 +674,21 @@  static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream,
 static int
 hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt)
 {
+	unsigned int chans;
+	struct hdac_ext_device *edev = to_ehdac_device(hdac);
+	struct hdac_hdmi_priv *hdmi = edev->private_data;
 	int err;
 
-	/* Only stereo supported as of now */
-	cvt->params.channels_min = cvt->params.channels_max = 2;
+	chans = get_wcaps(hdac, cvt->nid);
+	chans = get_wcaps_channels(chans);
+
+	cvt->params.channels_min = 2;
+
+	if (chans <= 16) {
+		cvt->params.channels_max = chans;
+		if (chans > hdmi->chmap.channels_max)
+			hdmi->chmap.channels_max = chans;
+	}
 
 	err = snd_hdac_query_supported_pcm(hdac, cvt->nid,
 			&cvt->params.rates,
@@ -1136,6 +1168,7 @@  static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid)
 	hdmi->num_pin++;
 
 	pin->edev = edev;
+	mutex_init(&pin->lock);
 	INIT_DELAYED_WORK(&pin->work, hdac_hdmi_repoll_eld);
 
 	return 0;
@@ -1501,6 +1534,7 @@  static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
 		return -ENOMEM;
 
 	edev->private_data = hdmi_priv;
+	snd_hdac_register_chmap_ops(codec, &hdmi_priv->chmap);
 
 	dev_set_drvdata(&codec->dev, edev);