All the mail mirrored from lore.kernel.org
 help / color / mirror / Atom feed
From: "Subhransu S. Prusty" <subhransu.s.prusty@intel.com>
To: alsa-devel@alsa-project.org
Cc: tiwai@suse.de, lgirdwood@gmail.com, patches.audio@intel.com,
	broonie@kernel.org, Vinod Koul <vinod.koul@intel.com>,
	"Subhransu S. Prusty" <subhransu.s.prusty@intel.com>
Subject: [PATCH v3 09/15] ASoC: hdac_hdmi: Assign pin for stream based on dapm connection
Date: Tue,  8 Dec 2015 02:54:23 +0530	[thread overview]
Message-ID: <1449523469-4395-9-git-send-email-subhransu.s.prusty@intel.com> (raw)
In-Reply-To: <1449523469-4395-1-git-send-email-subhransu.s.prusty@intel.com>

Now that we have all the widgets enumerated we can route the stream
to any pin widget based on Mux connection. So map the pin to stream
accordingly.

Also seems the connection list to the pin widgets are not static
and is updated runtime based on type of display attached to the port.
This looks to be a hardware behavior.

So querying of the connection list is removed from pin initialization
and used in selecting the pin for a dai map.

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 | 212 +++++++++++++++++++++++++++++++------------
 1 file changed, 153 insertions(+), 59 deletions(-)

diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c
index 467143cc..2d971c4 100644
--- a/sound/soc/codecs/hdac_hdmi.c
+++ b/sound/soc/codecs/hdac_hdmi.c
@@ -38,6 +38,8 @@
 
 #define HDA_MAX_CONNECTIONS     32
 
+#define HDA_MAX_CVTS		3
+
 #define ELD_MAX_SIZE    256
 #define ELD_FIXED_BYTES	20
 
@@ -80,7 +82,7 @@ struct hdac_hdmi_dai_pin_map {
 };
 
 struct hdac_hdmi_priv {
-	struct hdac_hdmi_dai_pin_map dai_map[3];
+	struct hdac_hdmi_dai_pin_map dai_map[HDA_MAX_CVTS];
 	struct list_head pin_list;
 	struct list_head cvt_list;
 	int num_pin;
@@ -369,12 +371,125 @@ static int hdac_hdmi_playback_cleanup(struct snd_pcm_substream *substream,
 	return 0;
 }
 
+static int hdac_hdmi_enable_pin(struct hdac_ext_device *hdac,
+		struct hdac_hdmi_dai_pin_map *dai_map)
+{
+	int mux_idx;
+	struct hdac_hdmi_pin *pin = dai_map->pin;
+
+	for (mux_idx = 0; mux_idx < pin->num_mux_nids; mux_idx++) {
+		if (pin->mux_nids[mux_idx] == dai_map->cvt->nid) {
+			snd_hdac_codec_write(&hdac->hdac, pin->nid, 0,
+					AC_VERB_SET_CONNECT_SEL, mux_idx);
+			break;
+		}
+	}
+
+	if (mux_idx == pin->num_mux_nids)
+		return -EIO;
+
+	/* Enable out path for this pin widget */
+	snd_hdac_codec_write(&hdac->hdac, pin->nid, 0,
+			AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+
+	hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D0);
+
+	snd_hdac_codec_write(&hdac->hdac, pin->nid, 0,
+			AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
+
+	return 0;
+}
+
+static int hdac_hdmi_query_pin_connlist(struct hdac_ext_device *hdac,
+					struct hdac_hdmi_pin *pin)
+{
+	if (!(get_wcaps(&hdac->hdac, pin->nid) & AC_WCAP_CONN_LIST)) {
+		dev_warn(&hdac->hdac.dev,
+			"HDMI: pin %d wcaps %#x does not support connection list\n",
+			pin->nid, get_wcaps(&hdac->hdac, pin->nid));
+		return -EINVAL;
+	}
+
+	pin->num_mux_nids = snd_hdac_get_connections(&hdac->hdac, pin->nid,
+			pin->mux_nids, HDA_MAX_CONNECTIONS);
+	if (pin->num_mux_nids == 0)
+		dev_warn(&hdac->hdac.dev, "No connections found for pin: %d\n", pin->nid);
+
+	dev_dbg(&hdac->hdac.dev, "num_mux_nids %d for pin: %d\n",
+			pin->num_mux_nids, pin->nid);
+
+	return pin->num_mux_nids;
+}
+
+static inline struct hdac_hdmi_pin *hdac_hdmi_get_pin(
+			struct hdac_ext_device *edev,
+			struct snd_soc_dapm_path *p,
+			struct hdac_hdmi_cvt *cvt)
+{
+	struct hdac_hdmi_priv *hdmi = edev->private_data;
+	struct hdac_hdmi_pin *pin;
+	hda_nid_t *nid;
+	int ret, i;
+
+	nid = (hda_nid_t *)p->sink->priv;
+	list_for_each_entry(pin, &hdmi->pin_list, head) {
+		if (pin->nid == *nid) {
+			ret = hdac_hdmi_query_pin_connlist(edev, pin);
+			if (ret < 0)
+				continue;
+
+			for (i = 0; i < pin->num_mux_nids; i++) {
+				if (pin->mux_nids[i] == cvt->nid)
+					return pin;
+			}
+		}
+	}
+
+	return NULL;
+}
+
+/*
+ * This queries mux widgets in each sink path of the dai widget and returns
+ * a matching pin widget to which the stream may be routed.
+ *
+ * The converter may be input to multiple pin muxes. So each
+ * pin mux (basically each pin widget) is queried to identify if
+ * the converter as one of the input, then the first pin match
+ * is selected for rendering.
+ *
+ * Same stream rendering to multiple pins simultaneously can be done
+ * possibly, but not supported for now.
+ *
+ * So return the first pin connected
+ */
+static struct hdac_hdmi_pin *hdac_hdmi_get_pin_from_daistream(
+			struct hdac_ext_device *edev,
+			struct snd_soc_dapm_widget *strm_w,
+			struct hdac_hdmi_cvt *cvt)
+{
+	struct snd_soc_dapm_path *p;
+
+	snd_soc_dapm_widget_for_each_sink_path(strm_w, p) {
+		if (!p->connect)
+			continue;
+
+		if (strstr(p->sink->name, "Mux"))
+			return hdac_hdmi_get_pin(edev, p, cvt);
+		else
+			return hdac_hdmi_get_pin_from_daistream(edev, p->sink, cvt);
+	}
+
+	return NULL;
+}
+
 static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream,
 			struct snd_soc_dai *dai)
 {
 	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_cvt *cvt;
+	struct hdac_hdmi_pin *pin;
 	int ret;
 
 	if (dai->id > 0) {
@@ -384,26 +499,32 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream,
 
 	dai_map = &hdmi->dai_map[dai->id];
 
-	if ((!dai_map->pin->eld.monitor_present) ||
-		(!dai_map->pin->eld.eld_valid)) {
-		dev_err(&hdac->hdac.dev, "Failed: montior present? %d eld valid?: %d\n",
-				dai_map->pin->eld.monitor_present,
-				dai_map->pin->eld.eld_valid);
+	cvt = dai_map->cvt;
+	pin = hdac_hdmi_get_pin_from_daistream(hdac, dai->playback_widget, cvt);
+	if (!pin)
+		return -EIO;
+
+	if ((!pin->eld.monitor_present) ||
+		(!pin->eld.eld_valid)) {
+		dev_err(&hdac->hdac.dev,
+			"failed: montior present? %d eld valid?: %d for pin: %d\n",
+			pin->eld.monitor_present, pin->eld.eld_valid, pin->nid);
 		return -ENODEV;
 	}
 
-	hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D0);
+	dai_map->pin = pin;
 
-	snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0,
-			AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
+	ret = hdac_hdmi_enable_pin(hdac, dai_map);
+	if (ret < 0)
+		return ret;
 
 	ret = hdac_hdmi_eld_limit_formats(substream->runtime,
-				dai_map->pin->eld.eld_buffer);
+				pin->eld.eld_buffer);
 	if (ret < 0)
 		return ret;
 
 	return snd_pcm_hw_constraint_eld(substream->runtime,
-				dai_map->pin->eld.eld_buffer);
+				pin->eld.eld_buffer);
 }
 
 static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream,
@@ -419,6 +540,8 @@ 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);
+
+	dai_map->pin = NULL;
 }
 
 static int
@@ -441,28 +564,6 @@ hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt)
 	return err;
 }
 
-static int hdac_hdmi_query_pin_connlist(struct hdac_ext_device *hdac,
-					struct hdac_hdmi_pin *pin)
-{
-	if (!(get_wcaps(&hdac->hdac, pin->nid) & AC_WCAP_CONN_LIST)) {
-		dev_warn(&hdac->hdac.dev,
-			"HDMI: pin %d wcaps %#x does not support connection list\n",
-			pin->nid, get_wcaps(&hdac->hdac, pin->nid));
-		return -EINVAL;
-	}
-
-	pin->num_mux_nids = snd_hdac_get_connections(&hdac->hdac, pin->nid,
-			pin->mux_nids, HDA_MAX_CONNECTIONS);
-	if (pin->num_mux_nids == 0)
-		dev_warn(&hdac->hdac.dev, "No connections found for pin: %d\n",
-								pin->nid);
-
-	dev_dbg(&hdac->hdac.dev, "num_mux_nids %d for pin: %d\n",
-			pin->num_mux_nids, pin->nid);
-
-	return pin->num_mux_nids;
-}
-
 static void hdac_hdmi_fill_widget_info(struct device *dev,
 				struct snd_soc_dapm_widget *w,
 				enum snd_soc_dapm_type id, void *priv,
@@ -686,40 +787,33 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm)
 static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev)
 {
 	struct hdac_hdmi_priv *hdmi = edev->private_data;
-	struct hdac_hdmi_dai_pin_map *dai_map = &hdmi->dai_map[0];
+	struct hdac_hdmi_dai_pin_map *dai_map;
 	struct hdac_hdmi_cvt *cvt;
-	struct hdac_hdmi_pin *pin;
+	int dai_id = 0;
 
-	if (list_empty(&hdmi->cvt_list) || list_empty(&hdmi->pin_list))
+	if (list_empty(&hdmi->cvt_list))
 		return -EINVAL;
 
-	/*
-	 * Currently on board only 1 pin and 1 converter is enabled for
-	 * simplification, more will be added eventually
-	 * So using fixed map for dai_id:pin:cvt
-	 */
-	cvt = list_first_entry(&hdmi->cvt_list, struct hdac_hdmi_cvt, head);
-	pin = list_first_entry(&hdmi->pin_list, struct hdac_hdmi_pin, head);
-
-	dai_map->dai_id = 0;
-	dai_map->pin = pin;
-
-	dai_map->cvt = cvt;
+	list_for_each_entry(cvt, &hdmi->cvt_list, head) {
+		dai_map = &hdmi->dai_map[dai_id];
+		dai_map->dai_id = dai_id;
+		dai_map->cvt = cvt;
 
-	/* Enable out path for this pin widget */
-	snd_hdac_codec_write(&edev->hdac, pin->nid, 0,
-			AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+		/* Enable transmission */
+		snd_hdac_codec_write(&edev->hdac, cvt->nid, 0,
+				AC_VERB_SET_DIGI_CONVERT_1, 1);
 
-	/* Enable transmission */
-	snd_hdac_codec_write(&edev->hdac, cvt->nid, 0,
-			AC_VERB_SET_DIGI_CONVERT_1, 1);
+		/* Category Code (CC) to zero */
+		snd_hdac_codec_write(&edev->hdac, cvt->nid, 0,
+				AC_VERB_SET_DIGI_CONVERT_2, 0);
 
-	/* Category Code (CC) to zero */
-	snd_hdac_codec_write(&edev->hdac, cvt->nid, 0,
-			AC_VERB_SET_DIGI_CONVERT_2, 0);
+		dai_id++;
 
-	snd_hdac_codec_write(&edev->hdac, pin->nid, 0,
-			AC_VERB_SET_CONNECT_SEL, 0);
+		if (dai_id == HDA_MAX_CVTS) {
+			dev_warn(&edev->hdac.dev, "Max dais supported: %d\n", dai_id);
+			break;
+		}
+	}
 
 	return 0;
 }
-- 
1.9.1

  parent reply	other threads:[~2015-12-07 15:54 UTC|newest]

Thread overview: 40+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-12-07 21:17 [PATCH v3 00/15] ASoC: hdac_hdmi: Add DP & notification support Subhransu S. Prusty
2015-12-07 20:12 ` Mark Brown
2015-12-08 11:24   ` Subhransu S. Prusty
2015-12-07 21:24 ` [PATCH v3 01/15] ASoC: hdac_hdmi: Fix to check num nodes correctly Subhransu S. Prusty
2015-12-07 21:24   ` [PATCH v3 02/15] ASoC: hdac_hdmi: Fix to warn instead of err for no connected nids Subhransu S. Prusty
2015-12-07 21:24   ` [PATCH v3 03/15] ASoC: hdac_hdmi: Use list to add pins and converters Subhransu S. Prusty
2016-01-08 13:44     ` Applied "ASoC: hdac_hdmi: Use list to add pins and converters" to the asoc tree Mark Brown
2015-12-07 21:24   ` [PATCH v3 04/15] ASoC: hdac_hdmi: Add hotplug notification and read eld Subhransu S. Prusty
2015-12-07 21:24   ` [PATCH v3 05/15] ASoC: hdac_hdmi: Apply constraints based on ELD Subhransu S. Prusty
2015-12-07 21:24   ` [PATCH v3 06/15] ASoC: hdac_hdmi: Enable DP1.2 and all converters/pins Subhransu S. Prusty
2015-12-07 21:24   ` [PATCH v3 07/15] ASoC: hdac_hdmi: create dais based on number of streams Subhransu S. Prusty
2015-12-07 16:11     ` Takashi Iwai
2015-12-07 21:24   ` [PATCH v3 08/15] ASoC: hdac_hdmi: Create widget/route based on nodes enumerated Subhransu S. Prusty
2015-12-07 16:14     ` Takashi Iwai
2015-12-08 11:28       ` Subhransu S. Prusty
2015-12-07 21:24   ` Subhransu S. Prusty [this message]
2015-12-07 21:24   ` [PATCH v3 10/15] drm/edid: Add API to help find connection type Subhransu S. Prusty
2015-12-08 14:01     ` Jani Nikula
2015-12-07 21:24   ` [PATCH v3 11/15] ASoC: hdac_hdmi: Add infoframe support for dp audio Subhransu S. Prusty
2015-12-07 21:24   ` [PATCH v3 12/15] ASoC: hdac_hdmi: Add codec suspend/resume handler Subhransu S. Prusty
2015-12-07 21:24   ` [PATCH v3 13/15] ASoC: hdac_hdmi: Fix to keep display active while enumerating codec Subhransu S. Prusty
2015-12-07 21:24   ` [PATCH v3 14/15] ASoC: hdac_hdmi: Add jack reporting for user space Subhransu S. Prusty
2015-12-07 16:18     ` Takashi Iwai
2015-12-08  6:31       ` Vinod Koul
2015-12-08  6:38         ` Takashi Iwai
2015-12-08  7:42           ` Vinod Koul
2015-12-08  7:52             ` Takashi Iwai
2015-12-08  8:38               ` Vinod Koul
2015-12-08  8:42                 ` Takashi Iwai
2015-12-08 10:20                   ` Vinod Koul
2015-12-08 10:28                     ` Takashi Iwai
2015-12-08 10:42                       ` Vinod Koul
2015-12-08 10:51                         ` Takashi Iwai
2015-12-08 10:59                           ` Takashi Iwai
2015-12-09  5:44                             ` Vinod Koul
2015-12-09  8:03                   ` Subhransu S. Prusty
2015-12-09  8:13                     ` Takashi Iwai
2015-12-09 11:14                       ` Subhransu S. Prusty
2015-12-09 11:37                         ` Takashi Iwai
2015-12-07 21:24   ` [PATCH v3 15/15] ASoC: hdac_hdmi: Fix to enable device configuration in hw_params Subhransu S. Prusty

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1449523469-4395-9-git-send-email-subhransu.s.prusty@intel.com \
    --to=subhransu.s.prusty@intel.com \
    --cc=alsa-devel@alsa-project.org \
    --cc=broonie@kernel.org \
    --cc=lgirdwood@gmail.com \
    --cc=patches.audio@intel.com \
    --cc=tiwai@suse.de \
    --cc=vinod.koul@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.