alsa-devel.alsa-project.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH 0/4] MST DP audio support
@ 2016-03-07 14:57 libin.yang
  2016-03-07 14:57 ` [RFC PATCH 1/4] ALSA: hda - codec add DP MST support for connection list libin.yang
                   ` (3 more replies)
  0 siblings, 4 replies; 13+ messages in thread
From: libin.yang @ 2016-03-07 14:57 UTC (permalink / raw)
  To: alsa-devel, tiwai; +Cc: libin.yang, mengdong.lin, Libin Yang

From: Libin Yang <libin.yang@linux.intel.com>

The patchset are tmp patches. The API between audio and gfx is
still in discussion.

Libin Yang (4):
  ALSA: hda - codec add DP MST support for connection list
  ALSA: hda - add DP mst verb support
  ALSA - hda: add devid support in acom
  ALSA - hda: add DP MST support

 drivers/gpu/drm/i915/intel_audio.c |   2 +-
 include/drm/i915_component.h       |   2 +-
 include/sound/hda_i915.h           |   6 +-
 sound/hda/hdac_i915.c              |   7 +-
 sound/pci/hda/hda_codec.c          | 217 ++++++++++++++++++++++++++++++++++---
 sound/pci/hda/hda_codec.h          |   8 ++
 sound/pci/hda/patch_hdmi.c         | 172 ++++++++++++++++++++---------
 7 files changed, 340 insertions(+), 74 deletions(-)

-- 
1.9.1

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [RFC PATCH 1/4] ALSA: hda - codec add DP MST support for connection list
  2016-03-07 14:57 [RFC PATCH 0/4] MST DP audio support libin.yang
@ 2016-03-07 14:57 ` libin.yang
  2016-03-07 16:40   ` Takashi Iwai
  2016-03-07 14:57 ` [PATCH 2/4] ALSA: hda - add DP mst verb support libin.yang
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 13+ messages in thread
From: libin.yang @ 2016-03-07 14:57 UTC (permalink / raw)
  To: alsa-devel, tiwai; +Cc: libin.yang, mengdong.lin, Libin Yang

From: Libin Yang <libin.yang@linux.intel.com>

This patches adds the support of connection list for DP MST.
With this, hdmi driver in DP MST mode can easily reuse
the connection list mechanism.

Signed-off-by: Libin Yang <libin.yang@linux.intel.com>
---
 sound/pci/hda/hda_codec.c | 134 ++++++++++++++++++++++++++++++++++++++++++----
 sound/pci/hda/hda_codec.h |   5 ++
 2 files changed, 128 insertions(+), 11 deletions(-)

diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 8374188..d4c81f7 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -110,23 +110,24 @@ struct hda_conn_list {
 	struct list_head list;
 	int len;
 	hda_nid_t nid;
+	int dev_id;
 	hda_nid_t conns[0];
 };
 
 /* look up the cached results */
 static struct hda_conn_list *
-lookup_conn_list(struct hda_codec *codec, hda_nid_t nid)
+lookup_conn_list(struct hda_codec *codec, hda_nid_t nid, int dev_id)
 {
 	struct hda_conn_list *p;
 	list_for_each_entry(p, &codec->conn_list, list) {
-		if (p->nid == nid)
+		if ((p->nid == nid) && (p->dev_id == dev_id))
 			return p;
 	}
 	return NULL;
 }
 
-static int add_conn_list(struct hda_codec *codec, hda_nid_t nid, int len,
-			 const hda_nid_t *list)
+static int add_conn_list(struct hda_codec *codec, hda_nid_t nid,
+			 int dev_id, int len, const hda_nid_t *list)
 {
 	struct hda_conn_list *p;
 
@@ -135,6 +136,7 @@ static int add_conn_list(struct hda_codec *codec, hda_nid_t nid, int len,
 		return -ENOMEM;
 	p->len = len;
 	p->nid = nid;
+	p->dev_id = dev_id;
 	memcpy(p->conns, list, len * sizeof(hda_nid_t));
 	list_add(&p->list, &codec->conn_list);
 	return 0;
@@ -150,8 +152,13 @@ static void remove_conn_list(struct hda_codec *codec)
 	}
 }
 
-/* read the connection and add to the cache */
-static int read_and_add_raw_conns(struct hda_codec *codec, hda_nid_t nid)
+/*
+ * read the connection and add to the cache
+ * the caller should select the device entry by sending the
+ * corresponding verb if necessary before calling this function
+ */
+static int read_and_add_raw_conns(struct hda_codec *codec, hda_nid_t nid,
+				  int dev_id)
 {
 	hda_nid_t list[32];
 	hda_nid_t *result = list;
@@ -166,7 +173,8 @@ static int read_and_add_raw_conns(struct hda_codec *codec, hda_nid_t nid)
 		len = snd_hda_get_raw_connections(codec, nid, result, len);
 	}
 	if (len >= 0)
-		len = snd_hda_override_conn_list(codec, nid, len, result);
+		len = snd_hda_override_conn_list_mst(codec, nid,
+					     dev_id, len, result);
 	if (result != list)
 		kfree(result);
 	return len;
@@ -197,7 +205,7 @@ int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid,
 		const struct hda_conn_list *p;
 
 		/* if the connection-list is already cached, read it */
-		p = lookup_conn_list(codec, nid);
+		p = lookup_conn_list(codec, nid, 0);
 		if (p) {
 			if (listp)
 				*listp = p->conns;
@@ -206,7 +214,7 @@ int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid,
 		if (snd_BUG_ON(added))
 			return -EINVAL;
 
-		err = read_and_add_raw_conns(codec, nid);
+		err = read_and_add_raw_conns(codec, nid, 0);
 		if (err < 0)
 			return err;
 		added = true;
@@ -215,6 +223,49 @@ int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid,
 EXPORT_SYMBOL_GPL(snd_hda_get_conn_list);
 
 /**
+ * snd_hda_get_conn_list_mst - get connection list in mst mode
+ * @codec: the HDA codec
+ * @nid: NID to parse
+ * @dev_id: device entry id
+ * @listp: the pointer to store NID list
+ *
+ * Parses the connection list of the given widget and stores the pointer
+ * to the list of NIDs.
+ *
+ * Returns the number of connections, or a negative error code.
+ *
+ * Note that the returned pointer isn't protected against the list
+ * modification.  If snd_hda_override_conn_list() might be called
+ * concurrently, protect with a mutex appropriately.
+ */
+int snd_hda_get_conn_list_mst(struct hda_codec *codec, hda_nid_t nid,
+			      int dev_id, const hda_nid_t **listp)
+{
+	bool added = false;
+
+	for (;;) {
+		int err;
+		const struct hda_conn_list *p;
+
+		/* if the connection-list is already cached, read it */
+		p = lookup_conn_list(codec, nid, dev_id);
+		if (p) {
+			if (listp)
+				*listp = p->conns;
+			return p->len;
+		}
+		if (snd_BUG_ON(added))
+			return -EINVAL;
+
+		err = read_and_add_raw_conns(codec, nid, dev_id);
+		if (err < 0)
+			return err;
+		added = true;
+	}
+}
+EXPORT_SYMBOL_GPL(snd_hda_get_conn_list_mst);
+
+/**
  * snd_hda_get_connections - copy connection list
  * @codec: the HDA codec
  * @nid: NID to parse
@@ -246,6 +297,39 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
 EXPORT_SYMBOL_GPL(snd_hda_get_connections);
 
 /**
+ * snd_hda_get_connections_mst - copy connection list in mst mode
+ * @codec: the HDA codec
+ * @nid: NID to parse
+ * @dev_id: device entry id
+ * @conn_list: connection list array; when NULL, checks only the size
+ * @max_conns: max. number of connections to store
+ *
+ * Parses the connection list of the given widget and stores the list
+ * of NIDs.
+ *
+ * Returns the number of connections, or a negative error code.
+ */
+int snd_hda_get_connections_mst(struct hda_codec *codec, hda_nid_t nid,
+				int dev_id, hda_nid_t *conn_list,
+				int max_conns)
+{
+	const hda_nid_t *list;
+	int len = snd_hda_get_conn_list_mst(codec, nid, dev_id, &list);
+
+	if (len > 0 && conn_list) {
+		if (len > max_conns) {
+			codec_err(codec, "Too many connections %d for NID 0x%x\n",
+				   len, nid);
+			return -EINVAL;
+		}
+		memcpy(conn_list, list, len * sizeof(hda_nid_t));
+	}
+
+	return len;
+}
+EXPORT_SYMBOL_GPL(snd_hda_get_connections_mst);
+
+/**
  * snd_hda_override_conn_list - add/modify the connection-list to cache
  * @codec: the HDA codec
  * @nid: NID to parse
@@ -262,17 +346,45 @@ int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int len,
 {
 	struct hda_conn_list *p;
 
-	p = lookup_conn_list(codec, nid);
+	p = lookup_conn_list(codec, nid, 0);
 	if (p) {
 		list_del(&p->list);
 		kfree(p);
 	}
 
-	return add_conn_list(codec, nid, len, list);
+	return add_conn_list(codec, nid, 0, len, list);
 }
 EXPORT_SYMBOL_GPL(snd_hda_override_conn_list);
 
 /**
+ * snd_hda_override_conn_list_mst - add/modify the connection-list to cache
+ * @codec: the HDA codec
+ * @nid: NID to parse
+ * @dev_id: device entry id
+ * @len: number of connection list entries
+ * @list: the list of connection entries
+ *
+ * Add or modify the given connection-list to the cache.  If the corresponding
+ * cache already exists, invalidate it and append a new one.
+ *
+ * Returns zero or a negative error code.
+ */
+int snd_hda_override_conn_list_mst(struct hda_codec *codec, hda_nid_t nid,
+			   int dev_id, int len, const hda_nid_t *list)
+{
+	struct hda_conn_list *p;
+
+	p = lookup_conn_list(codec, nid, dev_id);
+	if (p) {
+		list_del(&p->list);
+		kfree(p);
+	}
+
+	return add_conn_list(codec, nid, dev_id, len, list);
+}
+EXPORT_SYMBOL_GPL(snd_hda_override_conn_list_mst);
+
+/**
  * snd_hda_get_conn_index - get the connection index of the given NID
  * @codec: the HDA codec
  * @mux: NID containing the list
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 373fcad..deeed35 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -330,6 +330,9 @@ snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int flags,
 	snd_hdac_get_sub_nodes(&(codec)->core, nid, start_nid)
 int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
 			    hda_nid_t *conn_list, int max_conns);
+int snd_hda_get_connections_mst(struct hda_codec *codec, hda_nid_t nid,
+				int dev_id, hda_nid_t *conn_list,
+				int max_conns);
 static inline int
 snd_hda_get_num_conns(struct hda_codec *codec, hda_nid_t nid)
 {
@@ -345,6 +348,8 @@ int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid,
 			  const hda_nid_t **listp);
 int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int nums,
 			  const hda_nid_t *list);
+int snd_hda_override_conn_list_mst(struct hda_codec *codec, hda_nid_t nid,
+			   int dev_id, int len, const hda_nid_t *list);
 int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux,
 			   hda_nid_t nid, int recursive);
 int snd_hda_get_devices(struct hda_codec *codec, hda_nid_t nid,
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 2/4] ALSA: hda - add DP mst verb support
  2016-03-07 14:57 [RFC PATCH 0/4] MST DP audio support libin.yang
  2016-03-07 14:57 ` [RFC PATCH 1/4] ALSA: hda - codec add DP MST support for connection list libin.yang
@ 2016-03-07 14:57 ` libin.yang
  2016-03-07 16:45   ` Takashi Iwai
  2016-03-07 14:57 ` [RFC PATCH 3/4] ALSA - hda: add devid support in acom libin.yang
  2016-03-07 14:57 ` [RFC PATCH 4/4] ALSA - hda: add DP MST support libin.yang
  3 siblings, 1 reply; 13+ messages in thread
From: libin.yang @ 2016-03-07 14:57 UTC (permalink / raw)
  To: alsa-devel, tiwai; +Cc: libin.yang, mengdong.lin, Libin Yang

From: Libin Yang <libin.yang@linux.intel.com>

Add snd_hda_get_dev_select() and snd_hda_set_dev_select() functions
for DP MST audio support.

Signed-off-by: Libin Yang <libin.yang@linux.intel.com>
---
 sound/pci/hda/hda_codec.c | 80 +++++++++++++++++++++++++++++++++++++++++++++--
 sound/pci/hda/hda_codec.h |  3 ++
 2 files changed, 80 insertions(+), 3 deletions(-)

diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index d4c81f7..1a42c51 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -424,8 +424,16 @@ int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux,
 EXPORT_SYMBOL_GPL(snd_hda_get_conn_index);
 
 
-/* return DEVLIST_LEN parameter of the given widget */
-static unsigned int get_num_devices(struct hda_codec *codec, hda_nid_t nid)
+/**
+ * snd_hda_get_num_devices - get DEVLIST_LEN parameter of the given widget
+ *  @codec: the HDA codec
+ *  @nid: NID of the pin to parse
+ *
+ * Get the device entry number on the given widget.
+ * This is a feature of DP MST audio. Each pin can
+ * have several device entries in it.
+ */
+unsigned int snd_hda_get_num_devices(struct hda_codec *codec, hda_nid_t nid)
 {
 	unsigned int wcaps = get_wcaps(codec, nid);
 	unsigned int parm;
@@ -439,6 +447,7 @@ static unsigned int get_num_devices(struct hda_codec *codec, hda_nid_t nid)
 		parm = 0;
 	return parm & AC_DEV_LIST_LEN_MASK;
 }
+EXPORT_SYMBOL_GPL(snd_hda_get_num_devices);
 
 /**
  * snd_hda_get_devices - copy device list without cache
@@ -456,7 +465,7 @@ int snd_hda_get_devices(struct hda_codec *codec, hda_nid_t nid,
 	unsigned int parm;
 	int i, dev_len, devices;
 
-	parm = get_num_devices(codec, nid);
+	parm = snd_hda_get_num_devices(codec, nid);
 	if (!parm)	/* not multi-stream capable */
 		return 0;
 
@@ -480,6 +489,71 @@ int snd_hda_get_devices(struct hda_codec *codec, hda_nid_t nid,
 	return devices;
 }
 
+/**
+ * snd_hda_get_dev_select - get device entry select on the pin
+ * @codec: the HDA codec
+ * @nid: NID of the pin to get device entry select
+ *
+ * Get the devcie entry select on the pin. Return the device entry
+ * id selected on the pin. Return 0 means the first device entry
+ * is selected or MST is not supported.
+ */
+int snd_hda_get_dev_select(struct hda_codec *codec, hda_nid_t nid)
+{
+	/* not support dp_mst will always return 0, using first dev_entry */
+	if (!codec->dp_mst)
+		return 0;
+
+	return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_DEVICE_SEL, 0);
+}
+EXPORT_SYMBOL_GPL(snd_hda_get_dev_select);
+
+/**
+ * snd_hda_set_dev_select - set device entry select on the pin
+ * @codec: the HDA codec
+ * @nid: NID of the pin to set device entry select
+ * @dev_id: device entry id to be set
+ *
+ * Set the device entry select on the pin nid.
+ */
+int snd_hda_set_dev_select(struct hda_codec *codec, hda_nid_t nid, int dev_id)
+{
+	int ret, dev;
+	unsigned long timeout;
+
+	/* not support dp_mst will always return 0, using first dev_entry */
+	if (!codec->dp_mst)
+		return 0;
+
+	/* If Device List Length is 0, the pin is not multi stream capable.
+	 */
+	if ((snd_hda_get_num_devices(codec, nid) + 1) == 0)
+		return 0;
+
+	/* Behavior of setting index being equal to or greater than
+	 * Device List Length is not predictable
+	 */
+	if ((snd_hda_get_num_devices(codec, nid) + 1) <= dev_id)
+		return 0;
+
+	timeout = jiffies + msecs_to_jiffies(500);
+
+	/* make sure the device entry selection takes effect */
+	do {
+		ret = snd_hda_codec_write(codec, nid, 0,
+			AC_VERB_SET_DEVICE_SEL, dev_id);
+		udelay(20);
+
+		dev = snd_hda_get_dev_select(codec, nid);
+		if (dev == dev_id)
+			break;
+		msleep(20);
+	} while (time_before(jiffies, timeout));
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(snd_hda_set_dev_select);
+
 /*
  * read widget caps for each widget and store in cache
  */
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index deeed35..8362cb6 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -352,8 +352,11 @@ int snd_hda_override_conn_list_mst(struct hda_codec *codec, hda_nid_t nid,
 			   int dev_id, int len, const hda_nid_t *list);
 int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux,
 			   hda_nid_t nid, int recursive);
+unsigned int snd_hda_get_num_devices(struct hda_codec *codec, hda_nid_t nid);
 int snd_hda_get_devices(struct hda_codec *codec, hda_nid_t nid,
 			u8 *dev_list, int max_devices);
+int snd_hda_get_dev_select(struct hda_codec *codec, hda_nid_t nid);
+int snd_hda_set_dev_select(struct hda_codec *codec, hda_nid_t nid, int dev_id);
 
 struct hda_verb {
 	hda_nid_t nid;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [RFC PATCH 3/4] ALSA - hda: add devid support in acom
  2016-03-07 14:57 [RFC PATCH 0/4] MST DP audio support libin.yang
  2016-03-07 14:57 ` [RFC PATCH 1/4] ALSA: hda - codec add DP MST support for connection list libin.yang
  2016-03-07 14:57 ` [PATCH 2/4] ALSA: hda - add DP mst verb support libin.yang
@ 2016-03-07 14:57 ` libin.yang
  2016-03-07 14:57 ` [RFC PATCH 4/4] ALSA - hda: add DP MST support libin.yang
  3 siblings, 0 replies; 13+ messages in thread
From: libin.yang @ 2016-03-07 14:57 UTC (permalink / raw)
  To: alsa-devel, tiwai; +Cc: libin.yang, mengdong.lin, Libin Yang

From: Libin Yang <libin.yang@linux.intel.com>

This is a tmp API patch for gfx. Detail is still in discussion
---
 drivers/gpu/drm/i915/intel_audio.c | 2 +-
 include/drm/i915_component.h       | 2 +-
 include/sound/hda_i915.h           | 6 +++---
 sound/hda/hdac_i915.c              | 7 ++++---
 sound/pci/hda/patch_hdmi.c         | 5 +++--
 5 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c
index 31f6d21..3fdb6d9 100644
--- a/drivers/gpu/drm/i915/intel_audio.c
+++ b/drivers/gpu/drm/i915/intel_audio.c
@@ -710,7 +710,7 @@ static int i915_audio_component_sync_audio_rate(struct device *dev,
 }
 
 static int i915_audio_component_get_eld(struct device *dev, int port,
-					bool *enabled,
+					int dev_id, bool *enabled,
 					unsigned char *buf, int max_bytes)
 {
 	struct drm_i915_private *dev_priv = dev_to_i915(dev);
diff --git a/include/drm/i915_component.h b/include/drm/i915_component.h
index b46fa0e..3c4475a 100644
--- a/include/drm/i915_component.h
+++ b/include/drm/i915_component.h
@@ -77,7 +77,7 @@ struct i915_audio_component_ops {
 	 * Note that the returned size may be over @max_bytes.  Then it
 	 * implies that only a part of ELD has been copied to the buffer.
 	 */
-	int (*get_eld)(struct device *, int port, bool *enabled,
+	int (*get_eld)(struct device *, int port, int dev_id, bool *enabled,
 		       unsigned char *buf, int max_bytes);
 };
 
diff --git a/include/sound/hda_i915.h b/include/sound/hda_i915.h
index fa341fc..07403f7 100644
--- a/include/sound/hda_i915.h
+++ b/include/sound/hda_i915.h
@@ -11,7 +11,7 @@ int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable);
 int snd_hdac_display_power(struct hdac_bus *bus, bool enable);
 int snd_hdac_get_display_clk(struct hdac_bus *bus);
 int snd_hdac_sync_audio_rate(struct hdac_bus *bus, hda_nid_t nid, int rate);
-int snd_hdac_acomp_get_eld(struct hdac_bus *bus, hda_nid_t nid,
+int snd_hdac_acomp_get_eld(struct hdac_bus *bus, hda_nid_t nid, int dev_id,
 			   bool *audio_enabled, char *buffer, int max_bytes);
 int snd_hdac_i915_init(struct hdac_bus *bus);
 int snd_hdac_i915_exit(struct hdac_bus *bus);
@@ -35,8 +35,8 @@ static inline int snd_hdac_sync_audio_rate(struct hdac_bus *bus, hda_nid_t nid,
 	return 0;
 }
 static inline int snd_hdac_acomp_get_eld(struct hdac_bus *bus, hda_nid_t nid,
-					 bool *audio_enabled, char *buffer,
-					 int max_bytes)
+					 int dev_id, bool *audio_enabled,
+					 char *buffer, int max_bytes)
 {
 	return -ENODEV;
 }
diff --git a/sound/hda/hdac_i915.c b/sound/hda/hdac_i915.c
index f6854db..18173c7 100644
--- a/sound/hda/hdac_i915.c
+++ b/sound/hda/hdac_i915.c
@@ -155,6 +155,7 @@ EXPORT_SYMBOL_GPL(snd_hdac_sync_audio_rate);
  * snd_hdac_acomp_get_eld - Get the audio state and ELD via component
  * @bus: HDA core bus
  * @nid: the pin widget NID
+ * @dev_id: the device entry id
  * @audio_enabled: the pointer to store the current audio state
  * @buffer: the buffer pointer to store ELD bytes
  * @max_bytes: the max bytes to be stored on @buffer
@@ -171,7 +172,7 @@ EXPORT_SYMBOL_GPL(snd_hdac_sync_audio_rate);
  * thus it may be over @max_bytes.  If it's over @max_bytes, it implies
  * that only a part of ELD bytes have been fetched.
  */
-int snd_hdac_acomp_get_eld(struct hdac_bus *bus, hda_nid_t nid,
+int snd_hdac_acomp_get_eld(struct hdac_bus *bus, hda_nid_t nid, int dev_id,
 			   bool *audio_enabled, char *buffer, int max_bytes)
 {
 	struct i915_audio_component *acomp = bus->audio_component;
@@ -179,8 +180,8 @@ int snd_hdac_acomp_get_eld(struct hdac_bus *bus, hda_nid_t nid,
 	if (!acomp || !acomp->ops || !acomp->ops->get_eld)
 		return -ENODEV;
 
-	return acomp->ops->get_eld(acomp->dev, pin2port(nid), audio_enabled,
-				   buffer, max_bytes);
+	return acomp->ops->get_eld(acomp->dev, pin2port(nid), dev_id,
+				   audio_enabled, buffer, max_bytes);
 }
 EXPORT_SYMBOL_GPL(snd_hdac_acomp_get_eld);
 
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index fe4141c..11be04a 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -75,6 +75,7 @@ struct hdmi_spec_per_cvt {
 
 struct hdmi_spec_per_pin {
 	hda_nid_t pin_nid;
+	int dev_id;
 	/* pin idx, different device entries on the same pin use the same idx */
 	int pin_nid_idx;
 	int num_mux_nids;
@@ -2013,8 +2014,8 @@ static void sync_eld_via_acomp(struct hda_codec *codec,
 
 	mutex_lock(&per_pin->lock);
 	size = snd_hdac_acomp_get_eld(&codec->bus->core, per_pin->pin_nid,
-				      &eld->monitor_present, eld->eld_buffer,
-				      ELD_MAX_SIZE);
+				      per_pin->dev_id, &eld->monitor_present,
+				      eld->eld_buffer, ELD_MAX_SIZE);
 	if (size < 0)
 		goto unlock;
 	if (size > 0) {
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [RFC PATCH 4/4] ALSA - hda: add DP MST support
  2016-03-07 14:57 [RFC PATCH 0/4] MST DP audio support libin.yang
                   ` (2 preceding siblings ...)
  2016-03-07 14:57 ` [RFC PATCH 3/4] ALSA - hda: add devid support in acom libin.yang
@ 2016-03-07 14:57 ` libin.yang
  2016-03-07 15:19   ` Takashi Iwai
  3 siblings, 1 reply; 13+ messages in thread
From: libin.yang @ 2016-03-07 14:57 UTC (permalink / raw)
  To: alsa-devel, tiwai; +Cc: libin.yang, mengdong.lin, Libin Yang

From: Libin Yang <libin.yang@linux.intel.com>

This patch adds the DP MST support in hdmi audio driver.
---
 sound/pci/hda/hda_codec.c  |   3 +
 sound/pci/hda/patch_hdmi.c | 167 +++++++++++++++++++++++++++++++--------------
 2 files changed, 120 insertions(+), 50 deletions(-)

diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 1a42c51..7244f87 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -589,6 +589,9 @@ static int read_pin_defaults(struct hda_codec *codec)
 		pin->nid = nid;
 		pin->cfg = snd_hda_codec_read(codec, nid, 0,
 					      AC_VERB_GET_CONFIG_DEFAULT, 0);
+		/* all device entries are the same widget control so far
+		 * fixme: if any codec is different, need fix here
+		 */
 		pin->ctrl = snd_hda_codec_read(codec, nid, 0,
 					       AC_VERB_GET_PIN_WIDGET_CONTROL,
 					       0);
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 11be04a..26f5efd 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -144,7 +144,9 @@ struct hdmi_spec {
 	struct snd_array cvts; /* struct hdmi_spec_per_cvt */
 	hda_nid_t cvt_nids[4]; /* only for haswell fix */
 
-	int num_pins;
+	int num_pins; /* number of pins (including device entries) */
+	int num_nids; /* number of pin nids*/
+	int dev_num;
 	struct snd_array pins; /* struct hdmi_spec_per_pin */
 	struct hdmi_pcm pcm_rec[16];
 	struct mutex pcm_lock;
@@ -1248,6 +1250,10 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec,
 
 static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll);
 
+/* todo:
+ * To fully support DP MST, check_presence_and_report need param dev_id
+ * to tell which device entry occurs monitor connection event
+ */
 static void check_presence_and_report(struct hda_codec *codec, hda_nid_t nid)
 {
 	struct hdmi_spec *spec = codec->spec;
@@ -1271,6 +1277,11 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
 	struct hda_jack_tbl *jack;
 	int dev_entry = (res & AC_UNSOL_RES_DE) >> AC_UNSOL_RES_DE_SHIFT;
 
+	/* assume DP MST uses dyn_pcm_assign and acomp and
+	 * never comes here
+	 * if DP MST supports unsol event, below code need
+	 * consider dev_entry
+	 */
 	jack = snd_hda_jack_tbl_get_from_tag(codec, tag);
 	if (!jack)
 		return;
@@ -1499,28 +1510,40 @@ static int intel_cvt_id_to_mux_idx(struct hdmi_spec *spec,
  * by any other pins.
  */
 static void intel_not_share_assigned_cvt(struct hda_codec *codec,
-			hda_nid_t pin_nid, int mux_idx)
+					 hda_nid_t pin_nid, int dev_id, int mux_idx)
 {
 	struct hdmi_spec *spec = codec->spec;
 	hda_nid_t nid;
 	int cvt_idx, curr;
 	struct hdmi_spec_per_cvt *per_cvt;
+	struct hdmi_spec_per_pin *per_pin;
+	int pin_idx;
 
 	/* configure all pins, including "no physical connection" ones */
-	for_each_hda_codec_node(nid, codec) {
-		unsigned int wid_caps = get_wcaps(codec, nid);
-		unsigned int wid_type = get_wcaps_type(wid_caps);
-
-		if (wid_type != AC_WID_PIN)
+	for (pin_idx = 0; pin_idx <= spec->num_pins; pin_idx++) {
+		int dev_id_saved;
+		per_pin = get_pin(spec, pin_idx);
+		/* pin not connected to monitor
+		 * no need to operate on it
+		 */
+		if (!per_pin->pcm)
 			continue;
 
-		if (nid == pin_nid)
+		if ((per_pin->pin_nid == pin_nid) &&
+			(per_pin->dev_id == dev_id))
 			continue;
 
+		nid = per_pin->pin_nid;
+
+		/* save the dev id for echo pin, and restore it when return */
+		dev_id_saved = snd_hda_get_dev_select(codec, nid);
+		snd_hda_set_dev_select(codec, nid, per_pin->dev_id);
 		curr = snd_hda_codec_read(codec, nid, 0,
 					  AC_VERB_GET_CONNECT_SEL, 0);
-		if (curr != mux_idx)
+		if (curr != mux_idx) {
+			snd_hda_set_dev_select(codec, nid, dev_id_saved);
 			continue;
+		}
 
 		/* choose an unassigned converter. The conveters in the
 		 * connection list are in the same order as in the codec.
@@ -1537,12 +1560,13 @@ static void intel_not_share_assigned_cvt(struct hda_codec *codec,
 				break;
 			}
 		}
+		snd_hda_set_dev_select(codec, nid, dev_id_saved);
 	}
 }
 
 /* A wrapper of intel_not_share_asigned_cvt() */
 static void intel_not_share_assigned_cvt_nid(struct hda_codec *codec,
-			hda_nid_t pin_nid, hda_nid_t cvt_nid)
+			hda_nid_t pin_nid, int dev_id, hda_nid_t cvt_nid)
 {
 	int mux_idx;
 	struct hdmi_spec *spec = codec->spec;
@@ -1557,7 +1581,7 @@ static void intel_not_share_assigned_cvt_nid(struct hda_codec *codec,
 	 */
 	mux_idx = intel_cvt_id_to_mux_idx(spec, cvt_nid);
 	if (mux_idx >= 0)
-		intel_not_share_assigned_cvt(codec, pin_nid, mux_idx);
+		intel_not_share_assigned_cvt(codec, pin_nid, dev_id, mux_idx);
 }
 
 /* called in hdmi_pcm_open when no pin is assigned to the PCM
@@ -1585,7 +1609,7 @@ static int hdmi_pcm_open_no_pin(struct hda_pcm_stream *hinfo,
 	per_cvt->assigned = 1;
 	hinfo->nid = per_cvt->cvt_nid;
 
-	intel_not_share_assigned_cvt_nid(codec, 0, per_cvt->cvt_nid);
+	intel_not_share_assigned_cvt_nid(codec, 0, 0, per_cvt->cvt_nid);
 
 	set_bit(pcm_idx, &spec->pcm_in_use);
 	/* todo: setup spdif ctls assign */
@@ -1661,13 +1685,15 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
 	per_pin->cvt_nid = per_cvt->cvt_nid;
 	hinfo->nid = per_cvt->cvt_nid;
 
+	snd_hda_set_dev_select(codec, per_pin->pin_nid, per_pin->dev_id);
 	snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0,
 			    AC_VERB_SET_CONNECT_SEL,
 			    mux_idx);
 
 	/* configure unused pins to choose other converters */
 	if (is_haswell_plus(codec) || is_valleyview_plus(codec))
-		intel_not_share_assigned_cvt(codec, per_pin->pin_nid, mux_idx);
+		intel_not_share_assigned_cvt(codec, per_pin->pin_nid,
+					     per_pin->dev_id, mux_idx);
 
 	snd_hda_spdif_ctls_assign(codec, pcm_idx, per_cvt->cvt_nid);
 
@@ -1737,13 +1763,13 @@ static int hdmi_find_pcm_slot(struct hdmi_spec *spec,
 		return per_pin->pin_nid_idx;
 
 	/* have a second try; check the "reserved area" over num_pins */
-	for (i = spec->num_pins; i < spec->pcm_used; i++) {
+	for (i = spec->num_nids; i < spec->pcm_used; i++) {
 		if (!test_bit(i, &spec->pcm_bitmap))
 			return i;
 	}
 
 	/* the last try; check the empty slots in pins */
-	for (i = 0; i < spec->num_pins; i++) {
+	for (i = 0; i < spec->num_nids; i++) {
 		if (!test_bit(i, &spec->pcm_bitmap))
 			return i;
 	}
@@ -1818,10 +1844,12 @@ static void hdmi_pcm_setup_pin(struct hdmi_spec *spec,
 	per_pin->cvt_nid = hinfo->nid;
 
 	mux_idx = hdmi_get_pin_cvt_mux(spec, per_pin, hinfo->nid);
-	if (mux_idx < per_pin->num_mux_nids)
+	if (mux_idx < per_pin->num_mux_nids) {
+		snd_hda_set_dev_select(codec, per_pin->pin_nid, per_pin->dev_id);
 		snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0,
 				AC_VERB_SET_CONNECT_SEL,
 				mux_idx);
+	}
 	snd_hda_spdif_ctls_assign(codec, per_pin->pcm_idx, hinfo->nid);
 
 	non_pcm = check_non_pcm_per_cvt(codec, hinfo->nid);
@@ -1902,7 +1930,7 @@ static void update_eld(struct hda_codec *codec,
 		if (is_haswell_plus(codec) || is_valleyview_plus(codec)) {
 			intel_verify_pin_cvt_connect(codec, per_pin);
 			intel_not_share_assigned_cvt(codec, per_pin->pin_nid,
-						     per_pin->mux_idx);
+				per_pin->dev_id, per_pin->mux_idx);
 		}
 
 		hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm);
@@ -1996,6 +2024,7 @@ static struct snd_jack *pin_idx_to_jack(struct hda_codec *codec,
 	if (per_pin->pcm_idx >= 0 && spec->dyn_pcm_assign)
 		jack = spec->pcm_rec[per_pin->pcm_idx].jack;
 	else if (!spec->dyn_pcm_assign) {
+		//jack tbl not support mst
 		jack_tbl = snd_hda_jack_tbl_get(codec, per_pin->pin_nid);
 		if (jack_tbl)
 			jack = jack_tbl->jack;
@@ -2013,6 +2042,9 @@ static void sync_eld_via_acomp(struct hda_codec *codec,
 	int size;
 
 	mutex_lock(&per_pin->lock);
+	/* todo:
+	 * to fully support DP MST, need add param dev_id
+	 */
 	size = snd_hdac_acomp_get_eld(&codec->bus->core, per_pin->pin_nid,
 				      per_pin->dev_id, &eld->monitor_present,
 				      eld->eld_buffer, ELD_MAX_SIZE);
@@ -2079,7 +2111,7 @@ static void hdmi_repoll_eld(struct work_struct *work)
 }
 
 static void intel_haswell_fixup_connect_list(struct hda_codec *codec,
-					     hda_nid_t nid);
+					     hda_nid_t nid, int dev_id);
 
 static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
 {
@@ -2088,38 +2120,59 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
 	int pin_idx;
 	struct hdmi_spec_per_pin *per_pin;
 	int err;
+	int dev_num, i;
 
 	caps = snd_hda_query_pin_caps(codec, pin_nid);
 	if (!(caps & (AC_PINCAP_HDMI | AC_PINCAP_DP)))
 		return 0;
 
+	/* For DP MST audio, Configuration Default is the same for
+	   all device entries on the same pin
+	 */
 	config = snd_hda_codec_get_pincfg(codec, pin_nid);
 	if (get_defcfg_connect(config) == AC_JACK_PORT_NONE)
 		return 0;
 
-	if (is_haswell_plus(codec))
-		intel_haswell_fixup_connect_list(codec, pin_nid);
-
-	pin_idx = spec->num_pins;
-	per_pin = snd_array_new(&spec->pins);
-	if (!per_pin)
-		return -ENOMEM;
-
-	per_pin->pin_nid = pin_nid;
-	per_pin->non_pcm = false;
-	if (spec->dyn_pcm_assign)
-		per_pin->pcm_idx = -1;
-	else {
-		per_pin->pcm = get_hdmi_pcm(spec, pin_idx);
-		per_pin->pcm_idx = pin_idx;
+	if (is_haswell_plus(codec)) {
+		dev_num = 3;
+		spec->dev_num = 3;
+	} else {
+		dev_num = snd_hda_get_num_devices(codec, pin_nid) + 1;
+		/* spec->dev_num is the maxinum number of device entries
+		 * among all the pins
+		 */
+		spec->dev_num = (spec->dev_num > dev_num) ?
+			spec->dev_num : dev_num;
 	}
-	per_pin->pin_nid_idx = pin_idx;
 
-	err = hdmi_read_pin_conn(codec, pin_idx);
-	if (err < 0)
-		return err;
+	for (i = 0; i < dev_num; i++) {
+		pin_idx = spec->num_pins;
+		per_pin = snd_array_new(&spec->pins);
+
+		if (!per_pin)
+			return -ENOMEM;
 
-	spec->num_pins++;
+		if (spec->dyn_pcm_assign) {
+			per_pin->pcm = NULL;
+			per_pin->pcm_idx = -1;
+		} else {
+			per_pin->pcm = get_hdmi_pcm(spec, pin_idx);
+			per_pin->pcm_idx = pin_idx;
+		}
+		per_pin->pin_nid = pin_nid;
+		per_pin->pin_nid_idx = spec->num_nids;
+		per_pin->dev_id = i;
+		per_pin->non_pcm = false;
+		snd_hda_set_dev_select(codec, pin_nid, i);
+		if (is_haswell_plus(codec))
+			intel_haswell_fixup_connect_list(codec, pin_nid, i);
+		//need check here
+		err = hdmi_read_pin_conn(codec, pin_idx);
+		if (err < 0)
+			return err;
+		spec->num_pins++;
+	}
+	spec->num_nids++;
 
 	return 0;
 }
@@ -2235,7 +2288,7 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
 		 * skip pin setup and return 0 to make audio playback
 		 * be ongoing
 		 */
-		intel_not_share_assigned_cvt_nid(codec, 0, cvt_nid);
+		intel_not_share_assigned_cvt_nid(codec, 0, 0, cvt_nid);
 		snd_hda_codec_setup_stream(codec, cvt_nid,
 					stream_tag, 0, format);
 		mutex_unlock(&spec->pcm_lock);
@@ -2257,8 +2310,10 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
 		 * which can cause a resumed audio playback become silent
 		 * after S3.
 		 */
+		snd_hda_set_dev_select(codec, pin_nid, per_pin->dev_id);
 		intel_verify_pin_cvt_connect(codec, per_pin);
-		intel_not_share_assigned_cvt(codec, pin_nid, per_pin->mux_idx);
+		intel_not_share_assigned_cvt(codec, pin_nid, per_pin->dev_id,
+				     per_pin->mux_idx);
 	}
 
 	/* Call sync_audio_rate to set the N/CTS/M manually if necessary */
@@ -2280,6 +2335,7 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
 				    pinctl | PIN_OUT);
 	}
 
+	//need call snd_hda_set_dev_select()???
 	err = spec->ops.setup_stream(codec, cvt_nid, pin_nid,
 				 stream_tag, format);
 	mutex_unlock(&spec->pcm_lock);
@@ -2533,17 +2589,22 @@ static int hdmi_chmap_ctl_put(struct snd_kcontrol *kcontrol,
 static int generic_hdmi_build_pcms(struct hda_codec *codec)
 {
 	struct hdmi_spec *spec = codec->spec;
-	int pin_idx;
+	int idx;
 
-	for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+	/* for non-mst mode, pcm number is the same as before
+	 * for DP MST mode, pcm number is (nid number + dev_num - 1)
+	 *  dev_num is the device entry number in a pin
+	 *
+	 */
+	for (idx = 0; idx < spec->num_nids + spec->dev_num - 1; idx++) {
 		struct hda_pcm *info;
 		struct hda_pcm_stream *pstr;
 
-		info = snd_hda_codec_pcm_new(codec, "HDMI %d", pin_idx);
+		info = snd_hda_codec_pcm_new(codec, "HDMI %d", idx);
 		if (!info)
 			return -ENOMEM;
 
-		spec->pcm_rec[pin_idx].pcm = info;
+		spec->pcm_rec[idx].pcm = info;
 		spec->pcm_used++;
 		info->pcm_type = HDA_PCM_TYPE_HDMI;
 		info->own_chmap = true;
@@ -2551,6 +2612,9 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec)
 		pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
 		pstr->substreams = 1;
 		pstr->ops = generic_ops;
+		/* pcm number is less than 16 */
+		if (spec->pcm_used >= 16)
+			break;
 		/* other pstr fields are set in open */
 	}
 
@@ -2720,7 +2784,9 @@ static int generic_hdmi_init(struct hda_codec *codec)
 	for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
 		struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
 		hda_nid_t pin_nid = per_pin->pin_nid;
+		int dev_id = per_pin->dev_id;
 
+		snd_hda_set_dev_select(codec, pin_nid, dev_id);
 		hdmi_init_pin(codec, pin_nid);
 		if (!codec_has_acomp(codec))
 			snd_hda_jack_detect_enable_callback(codec, pin_nid,
@@ -2813,20 +2879,20 @@ static const struct hdmi_ops generic_standard_hdmi_ops = {
 
 
 static void intel_haswell_fixup_connect_list(struct hda_codec *codec,
-					     hda_nid_t nid)
+					     hda_nid_t nid, int dev_id)
 {
 	struct hdmi_spec *spec = codec->spec;
 	hda_nid_t conns[4];
 	int nconns;
 
-	nconns = snd_hda_get_connections(codec, nid, conns, ARRAY_SIZE(conns));
+	nconns = snd_hda_get_connections_mst(codec, nid, dev_id, conns, ARRAY_SIZE(conns));
 	if (nconns == spec->num_cvts &&
 	    !memcmp(conns, spec->cvt_nids, spec->num_cvts * sizeof(hda_nid_t)))
 		return;
 
 	/* override pins connection list */
 	codec_dbg(codec, "hdmi: haswell: override pin connection 0x%x\n", nid);
-	snd_hda_override_conn_list(codec, nid, spec->num_cvts, spec->cvt_nids);
+	snd_hda_override_conn_list_mst(codec, nid, dev_id, spec->num_cvts, spec->cvt_nids);
 }
 
 #define INTEL_VENDOR_NID 0x08
@@ -2912,6 +2978,7 @@ static int patch_generic_hdmi(struct hda_codec *codec)
 		return -ENOMEM;
 
 	spec->ops = generic_standard_hdmi_ops;
+	spec->dev_num = 1;	/* initialize to 1 */
 	mutex_init(&spec->pcm_lock);
 	codec->spec = spec;
 	hdmi_array_init(spec, 4);
@@ -2925,6 +2992,8 @@ static int patch_generic_hdmi(struct hda_codec *codec)
 	if (is_haswell_plus(codec)) {
 		intel_haswell_enable_all_pins(codec, true);
 		intel_haswell_fixup_enable_dp12(codec);
+		codec->dp_mst = true;
+		spec->dyn_pcm_assign = true;
 	}
 
 	/* For Valleyview/Cherryview, only the display codec is in the display
@@ -2945,10 +3014,8 @@ static int patch_generic_hdmi(struct hda_codec *codec)
 		return -EINVAL;
 	}
 	codec->patch_ops = generic_hdmi_patch_ops;
-	if (is_haswell_plus(codec)) {
+	if (is_haswell_plus(codec))
 		codec->patch_ops.set_power_state = haswell_set_power_state;
-		codec->dp_mst = true;
-	}
 
 	/* Enable runtime pm for HDMI audio codec of HSW/BDW/SKL/BYT/BSW */
 	if (is_haswell_plus(codec) || is_valleyview_plus(codec))
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [RFC PATCH 4/4] ALSA - hda: add DP MST support
  2016-03-07 14:57 ` [RFC PATCH 4/4] ALSA - hda: add DP MST support libin.yang
@ 2016-03-07 15:19   ` Takashi Iwai
  2016-03-08  6:47     ` Yang, Libin
  0 siblings, 1 reply; 13+ messages in thread
From: Takashi Iwai @ 2016-03-07 15:19 UTC (permalink / raw)
  To: libin.yang; +Cc: libin.yang, mengdong.lin, alsa-devel

On Mon, 07 Mar 2016 15:57:46 +0100,
libin.yang@linux.intel.com wrote:
> 
> From: Libin Yang <libin.yang@linux.intel.com>
> 
> This patch adds the DP MST support in hdmi audio driver.
> ---
>  sound/pci/hda/hda_codec.c  |   3 +
>  sound/pci/hda/patch_hdmi.c | 167 +++++++++++++++++++++++++++++++--------------
>  2 files changed, 120 insertions(+), 50 deletions(-)
> 
> diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
> index 1a42c51..7244f87 100644
> --- a/sound/pci/hda/hda_codec.c
> +++ b/sound/pci/hda/hda_codec.c
> @@ -589,6 +589,9 @@ static int read_pin_defaults(struct hda_codec *codec)
>  		pin->nid = nid;
>  		pin->cfg = snd_hda_codec_read(codec, nid, 0,
>  					      AC_VERB_GET_CONFIG_DEFAULT, 0);
> +		/* all device entries are the same widget control so far
> +		 * fixme: if any codec is different, need fix here
> +		 */
>  		pin->ctrl = snd_hda_codec_read(codec, nid, 0,
>  					       AC_VERB_GET_PIN_WIDGET_CONTROL,
>  					       0);
> diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
> index 11be04a..26f5efd 100644
> --- a/sound/pci/hda/patch_hdmi.c
> +++ b/sound/pci/hda/patch_hdmi.c
> @@ -144,7 +144,9 @@ struct hdmi_spec {
>  	struct snd_array cvts; /* struct hdmi_spec_per_cvt */
>  	hda_nid_t cvt_nids[4]; /* only for haswell fix */
>  
> -	int num_pins;
> +	int num_pins; /* number of pins (including device entries) */
> +	int num_nids; /* number of pin nids*/
> +	int dev_num;

These new definitions are unclear to me.  Please give a bit more
detailed comments there.  e.g. what actually means "including device
entries"?  You can give some example there.  I suppose num_nids is the
actual number of pins, right?  Also what is dev_num?  It's not an
index, right? 


thanks,

Takashi

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFC PATCH 1/4] ALSA: hda - codec add DP MST support for connection list
  2016-03-07 14:57 ` [RFC PATCH 1/4] ALSA: hda - codec add DP MST support for connection list libin.yang
@ 2016-03-07 16:40   ` Takashi Iwai
  2016-03-08  6:47     ` Yang, Libin
  0 siblings, 1 reply; 13+ messages in thread
From: Takashi Iwai @ 2016-03-07 16:40 UTC (permalink / raw)
  To: libin.yang; +Cc: libin.yang, mengdong.lin, alsa-devel

On Mon, 07 Mar 2016 15:57:43 +0100,
libin.yang@linux.intel.com wrote:
> 
> From: Libin Yang <libin.yang@linux.intel.com>
> 
> This patches adds the support of connection list for DP MST.
> With this, hdmi driver in DP MST mode can easily reuse
> the connection list mechanism.
> 
> Signed-off-by: Libin Yang <libin.yang@linux.intel.com>

I would just replace the function with *_mst() and provide the old
ones via static inline wrappers instead of having two copies.


Takashi

> ---
>  sound/pci/hda/hda_codec.c | 134 ++++++++++++++++++++++++++++++++++++++++++----
>  sound/pci/hda/hda_codec.h |   5 ++
>  2 files changed, 128 insertions(+), 11 deletions(-)
> 
> diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
> index 8374188..d4c81f7 100644
> --- a/sound/pci/hda/hda_codec.c
> +++ b/sound/pci/hda/hda_codec.c
> @@ -110,23 +110,24 @@ struct hda_conn_list {
>  	struct list_head list;
>  	int len;
>  	hda_nid_t nid;
> +	int dev_id;
>  	hda_nid_t conns[0];
>  };
>  
>  /* look up the cached results */
>  static struct hda_conn_list *
> -lookup_conn_list(struct hda_codec *codec, hda_nid_t nid)
> +lookup_conn_list(struct hda_codec *codec, hda_nid_t nid, int dev_id)
>  {
>  	struct hda_conn_list *p;
>  	list_for_each_entry(p, &codec->conn_list, list) {
> -		if (p->nid == nid)
> +		if ((p->nid == nid) && (p->dev_id == dev_id))
>  			return p;
>  	}
>  	return NULL;
>  }
>  
> -static int add_conn_list(struct hda_codec *codec, hda_nid_t nid, int len,
> -			 const hda_nid_t *list)
> +static int add_conn_list(struct hda_codec *codec, hda_nid_t nid,
> +			 int dev_id, int len, const hda_nid_t *list)
>  {
>  	struct hda_conn_list *p;
>  
> @@ -135,6 +136,7 @@ static int add_conn_list(struct hda_codec *codec, hda_nid_t nid, int len,
>  		return -ENOMEM;
>  	p->len = len;
>  	p->nid = nid;
> +	p->dev_id = dev_id;
>  	memcpy(p->conns, list, len * sizeof(hda_nid_t));
>  	list_add(&p->list, &codec->conn_list);
>  	return 0;
> @@ -150,8 +152,13 @@ static void remove_conn_list(struct hda_codec *codec)
>  	}
>  }
>  
> -/* read the connection and add to the cache */
> -static int read_and_add_raw_conns(struct hda_codec *codec, hda_nid_t nid)
> +/*
> + * read the connection and add to the cache
> + * the caller should select the device entry by sending the
> + * corresponding verb if necessary before calling this function
> + */
> +static int read_and_add_raw_conns(struct hda_codec *codec, hda_nid_t nid,
> +				  int dev_id)
>  {
>  	hda_nid_t list[32];
>  	hda_nid_t *result = list;
> @@ -166,7 +173,8 @@ static int read_and_add_raw_conns(struct hda_codec *codec, hda_nid_t nid)
>  		len = snd_hda_get_raw_connections(codec, nid, result, len);
>  	}
>  	if (len >= 0)
> -		len = snd_hda_override_conn_list(codec, nid, len, result);
> +		len = snd_hda_override_conn_list_mst(codec, nid,
> +					     dev_id, len, result);
>  	if (result != list)
>  		kfree(result);
>  	return len;
> @@ -197,7 +205,7 @@ int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid,
>  		const struct hda_conn_list *p;
>  
>  		/* if the connection-list is already cached, read it */
> -		p = lookup_conn_list(codec, nid);
> +		p = lookup_conn_list(codec, nid, 0);
>  		if (p) {
>  			if (listp)
>  				*listp = p->conns;
> @@ -206,7 +214,7 @@ int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid,
>  		if (snd_BUG_ON(added))
>  			return -EINVAL;
>  
> -		err = read_and_add_raw_conns(codec, nid);
> +		err = read_and_add_raw_conns(codec, nid, 0);
>  		if (err < 0)
>  			return err;
>  		added = true;
> @@ -215,6 +223,49 @@ int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid,
>  EXPORT_SYMBOL_GPL(snd_hda_get_conn_list);
>  
>  /**
> + * snd_hda_get_conn_list_mst - get connection list in mst mode
> + * @codec: the HDA codec
> + * @nid: NID to parse
> + * @dev_id: device entry id
> + * @listp: the pointer to store NID list
> + *
> + * Parses the connection list of the given widget and stores the pointer
> + * to the list of NIDs.
> + *
> + * Returns the number of connections, or a negative error code.
> + *
> + * Note that the returned pointer isn't protected against the list
> + * modification.  If snd_hda_override_conn_list() might be called
> + * concurrently, protect with a mutex appropriately.
> + */
> +int snd_hda_get_conn_list_mst(struct hda_codec *codec, hda_nid_t nid,
> +			      int dev_id, const hda_nid_t **listp)
> +{
> +	bool added = false;
> +
> +	for (;;) {
> +		int err;
> +		const struct hda_conn_list *p;
> +
> +		/* if the connection-list is already cached, read it */
> +		p = lookup_conn_list(codec, nid, dev_id);
> +		if (p) {
> +			if (listp)
> +				*listp = p->conns;
> +			return p->len;
> +		}
> +		if (snd_BUG_ON(added))
> +			return -EINVAL;
> +
> +		err = read_and_add_raw_conns(codec, nid, dev_id);
> +		if (err < 0)
> +			return err;
> +		added = true;
> +	}
> +}
> +EXPORT_SYMBOL_GPL(snd_hda_get_conn_list_mst);
> +
> +/**
>   * snd_hda_get_connections - copy connection list
>   * @codec: the HDA codec
>   * @nid: NID to parse
> @@ -246,6 +297,39 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
>  EXPORT_SYMBOL_GPL(snd_hda_get_connections);
>  
>  /**
> + * snd_hda_get_connections_mst - copy connection list in mst mode
> + * @codec: the HDA codec
> + * @nid: NID to parse
> + * @dev_id: device entry id
> + * @conn_list: connection list array; when NULL, checks only the size
> + * @max_conns: max. number of connections to store
> + *
> + * Parses the connection list of the given widget and stores the list
> + * of NIDs.
> + *
> + * Returns the number of connections, or a negative error code.
> + */
> +int snd_hda_get_connections_mst(struct hda_codec *codec, hda_nid_t nid,
> +				int dev_id, hda_nid_t *conn_list,
> +				int max_conns)
> +{
> +	const hda_nid_t *list;
> +	int len = snd_hda_get_conn_list_mst(codec, nid, dev_id, &list);
> +
> +	if (len > 0 && conn_list) {
> +		if (len > max_conns) {
> +			codec_err(codec, "Too many connections %d for NID 0x%x\n",
> +				   len, nid);
> +			return -EINVAL;
> +		}
> +		memcpy(conn_list, list, len * sizeof(hda_nid_t));
> +	}
> +
> +	return len;
> +}
> +EXPORT_SYMBOL_GPL(snd_hda_get_connections_mst);
> +
> +/**
>   * snd_hda_override_conn_list - add/modify the connection-list to cache
>   * @codec: the HDA codec
>   * @nid: NID to parse
> @@ -262,17 +346,45 @@ int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int len,
>  {
>  	struct hda_conn_list *p;
>  
> -	p = lookup_conn_list(codec, nid);
> +	p = lookup_conn_list(codec, nid, 0);
>  	if (p) {
>  		list_del(&p->list);
>  		kfree(p);
>  	}
>  
> -	return add_conn_list(codec, nid, len, list);
> +	return add_conn_list(codec, nid, 0, len, list);
>  }
>  EXPORT_SYMBOL_GPL(snd_hda_override_conn_list);
>  
>  /**
> + * snd_hda_override_conn_list_mst - add/modify the connection-list to cache
> + * @codec: the HDA codec
> + * @nid: NID to parse
> + * @dev_id: device entry id
> + * @len: number of connection list entries
> + * @list: the list of connection entries
> + *
> + * Add or modify the given connection-list to the cache.  If the corresponding
> + * cache already exists, invalidate it and append a new one.
> + *
> + * Returns zero or a negative error code.
> + */
> +int snd_hda_override_conn_list_mst(struct hda_codec *codec, hda_nid_t nid,
> +			   int dev_id, int len, const hda_nid_t *list)
> +{
> +	struct hda_conn_list *p;
> +
> +	p = lookup_conn_list(codec, nid, dev_id);
> +	if (p) {
> +		list_del(&p->list);
> +		kfree(p);
> +	}
> +
> +	return add_conn_list(codec, nid, dev_id, len, list);
> +}
> +EXPORT_SYMBOL_GPL(snd_hda_override_conn_list_mst);
> +
> +/**
>   * snd_hda_get_conn_index - get the connection index of the given NID
>   * @codec: the HDA codec
>   * @mux: NID containing the list
> diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
> index 373fcad..deeed35 100644
> --- a/sound/pci/hda/hda_codec.h
> +++ b/sound/pci/hda/hda_codec.h
> @@ -330,6 +330,9 @@ snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int flags,
>  	snd_hdac_get_sub_nodes(&(codec)->core, nid, start_nid)
>  int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
>  			    hda_nid_t *conn_list, int max_conns);
> +int snd_hda_get_connections_mst(struct hda_codec *codec, hda_nid_t nid,
> +				int dev_id, hda_nid_t *conn_list,
> +				int max_conns);
>  static inline int
>  snd_hda_get_num_conns(struct hda_codec *codec, hda_nid_t nid)
>  {
> @@ -345,6 +348,8 @@ int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid,
>  			  const hda_nid_t **listp);
>  int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int nums,
>  			  const hda_nid_t *list);
> +int snd_hda_override_conn_list_mst(struct hda_codec *codec, hda_nid_t nid,
> +			   int dev_id, int len, const hda_nid_t *list);
>  int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux,
>  			   hda_nid_t nid, int recursive);
>  int snd_hda_get_devices(struct hda_codec *codec, hda_nid_t nid,
> -- 
> 1.9.1
> 

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 2/4] ALSA: hda - add DP mst verb support
  2016-03-07 14:57 ` [PATCH 2/4] ALSA: hda - add DP mst verb support libin.yang
@ 2016-03-07 16:45   ` Takashi Iwai
  2016-03-08  6:54     ` Yang, Libin
  0 siblings, 1 reply; 13+ messages in thread
From: Takashi Iwai @ 2016-03-07 16:45 UTC (permalink / raw)
  To: libin.yang; +Cc: libin.yang, mengdong.lin, alsa-devel

On Mon, 07 Mar 2016 15:57:44 +0100,
libin.yang@linux.intel.com wrote:
> 
> +int snd_hda_set_dev_select(struct hda_codec *codec, hda_nid_t nid, int dev_id)
> +{
> +	int ret, dev;
> +	unsigned long timeout;
> +
> +	/* not support dp_mst will always return 0, using first dev_entry */
> +	if (!codec->dp_mst)
> +		return 0;
> +
> +	/* If Device List Length is 0, the pin is not multi stream capable.
> +	 */
> +	if ((snd_hda_get_num_devices(codec, nid) + 1) == 0)
> +		return 0;

I don't understand what this code is for.  Why +1?

> +
> +	/* Behavior of setting index being equal to or greater than
> +	 * Device List Length is not predictable
> +	 */
> +	if ((snd_hda_get_num_devices(codec, nid) + 1) <= dev_id)
> +		return 0;

Ditto.  And, calling the same function twice?


thanks,

Takashi

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFC PATCH 4/4] ALSA - hda: add DP MST support
  2016-03-07 15:19   ` Takashi Iwai
@ 2016-03-08  6:47     ` Yang, Libin
  0 siblings, 0 replies; 13+ messages in thread
From: Yang, Libin @ 2016-03-08  6:47 UTC (permalink / raw)
  To: Takashi Iwai, libin.yang@linux.intel.com
  Cc: Lin, Mengdong, alsa-devel@alsa-project.org

Hi Takashi,

> -----Original Message-----
> From: Takashi Iwai [mailto:tiwai@suse.de]
> Sent: Monday, March 07, 2016 11:19 PM
> To: libin.yang@linux.intel.com
> Cc: alsa-devel@alsa-project.org; Lin, Mengdong; Yang, Libin
> Subject: Re: [alsa-devel] [RFC PATCH 4/4] ALSA - hda: add DP MST
> support
> 
> On Mon, 07 Mar 2016 15:57:46 +0100,
> libin.yang@linux.intel.com wrote:
> >
> > From: Libin Yang <libin.yang@linux.intel.com>
> >
> > This patch adds the DP MST support in hdmi audio driver.
> > ---
> >  sound/pci/hda/hda_codec.c  |   3 +
> >  sound/pci/hda/patch_hdmi.c | 167
> +++++++++++++++++++++++++++++++--------------
> >  2 files changed, 120 insertions(+), 50 deletions(-)
> >
> > diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
> > index 1a42c51..7244f87 100644
> > --- a/sound/pci/hda/hda_codec.c
> > +++ b/sound/pci/hda/hda_codec.c
> > @@ -589,6 +589,9 @@ static int read_pin_defaults(struct hda_codec
> *codec)
> >  		pin->nid = nid;
> >  		pin->cfg = snd_hda_codec_read(codec, nid, 0,
> >
> AC_VERB_GET_CONFIG_DEFAULT, 0);
> > +		/* all device entries are the same widget control so far
> > +		 * fixme: if any codec is different, need fix here
> > +		 */
> >  		pin->ctrl = snd_hda_codec_read(codec, nid, 0,
> >
> AC_VERB_GET_PIN_WIDGET_CONTROL,
> >  					       0);
> > diff --git a/sound/pci/hda/patch_hdmi.c
> b/sound/pci/hda/patch_hdmi.c
> > index 11be04a..26f5efd 100644
> > --- a/sound/pci/hda/patch_hdmi.c
> > +++ b/sound/pci/hda/patch_hdmi.c
> > @@ -144,7 +144,9 @@ struct hdmi_spec {
> >  	struct snd_array cvts; /* struct hdmi_spec_per_cvt */
> >  	hda_nid_t cvt_nids[4]; /* only for haswell fix */
> >
> > -	int num_pins;
> > +	int num_pins; /* number of pins (including device entries) */
> > +	int num_nids; /* number of pin nids*/
> > +	int dev_num;
> 
> These new definitions are unclear to me.  Please give a bit more
> detailed comments there.  e.g. what actually means "including device
> entries"?  You can give some example there.  I suppose num_nids is the
> actual number of pins, right?  Also what is dev_num?  It's not an
> index, right?

OK. I will add more comments in the code. For this case:
1. num_pins is the virtual pin number. For example, 
    there are 3 pins and each pin has 4 device entry, the num_pins will be 12.
2. num_nids is the actual number of pins. For the above case it will be 3
3. dev_num is the device entry number on each pin. For the above case, it is 4.
    dev_num is used to decide to create how many pcms (as we talked before,
    num_nids + dev_num - 1, on Intel platform, it is 5 pcms)
    For more complex case (not sure there is such case in reality), pin 1 has 2
    device entries, pin 2 and pin 3 has 3 device entries. The dev_num is 3.
    And 5 pcms will be created.

For device entry index, the index is located in per_pin struct.

Regards,
Libin

> 
> 
> thanks,
> 
> Takashi

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFC PATCH 1/4] ALSA: hda - codec add DP MST support for connection list
  2016-03-07 16:40   ` Takashi Iwai
@ 2016-03-08  6:47     ` Yang, Libin
  0 siblings, 0 replies; 13+ messages in thread
From: Yang, Libin @ 2016-03-08  6:47 UTC (permalink / raw)
  To: Takashi Iwai, libin.yang@linux.intel.com
  Cc: Lin, Mengdong, alsa-devel@alsa-project.org

Hi Takashi,

> -----Original Message-----
> From: Takashi Iwai [mailto:tiwai@suse.de]
> Sent: Tuesday, March 08, 2016 12:41 AM
> To: libin.yang@linux.intel.com
> Cc: alsa-devel@alsa-project.org; Lin, Mengdong; Yang, Libin
> Subject: Re: [alsa-devel] [RFC PATCH 1/4] ALSA: hda - codec add DP MST
> support for connection list
> 
> On Mon, 07 Mar 2016 15:57:43 +0100,
> libin.yang@linux.intel.com wrote:
> >
> > From: Libin Yang <libin.yang@linux.intel.com>
> >
> > This patches adds the support of connection list for DP MST.
> > With this, hdmi driver in DP MST mode can easily reuse
> > the connection list mechanism.
> >
> > Signed-off-by: Libin Yang <libin.yang@linux.intel.com>
> 
> I would just replace the function with *_mst() and provide the old
> ones via static inline wrappers instead of having two copies.

I see. I will change it.

Regards,
Libin

> 
> 
> Takashi
> 
> > ---
> >  sound/pci/hda/hda_codec.c | 134
> ++++++++++++++++++++++++++++++++++++++++++----
> >  sound/pci/hda/hda_codec.h |   5 ++
> >  2 files changed, 128 insertions(+), 11 deletions(-)
> >
> > diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
> > index 8374188..d4c81f7 100644
> > --- a/sound/pci/hda/hda_codec.c
> > +++ b/sound/pci/hda/hda_codec.c
> > @@ -110,23 +110,24 @@ struct hda_conn_list {
> >  	struct list_head list;
> >  	int len;
> >  	hda_nid_t nid;
> > +	int dev_id;
> >  	hda_nid_t conns[0];
> >  };
> >
> >  /* look up the cached results */
> >  static struct hda_conn_list *
> > -lookup_conn_list(struct hda_codec *codec, hda_nid_t nid)
> > +lookup_conn_list(struct hda_codec *codec, hda_nid_t nid, int dev_id)
> >  {
> >  	struct hda_conn_list *p;
> >  	list_for_each_entry(p, &codec->conn_list, list) {
> > -		if (p->nid == nid)
> > +		if ((p->nid == nid) && (p->dev_id == dev_id))
> >  			return p;
> >  	}
> >  	return NULL;
> >  }
> >
> > -static int add_conn_list(struct hda_codec *codec, hda_nid_t nid, int
> len,
> > -			 const hda_nid_t *list)
> > +static int add_conn_list(struct hda_codec *codec, hda_nid_t nid,
> > +			 int dev_id, int len, const hda_nid_t *list)
> >  {
> >  	struct hda_conn_list *p;
> >
> > @@ -135,6 +136,7 @@ static int add_conn_list(struct hda_codec
> *codec, hda_nid_t nid, int len,
> >  		return -ENOMEM;
> >  	p->len = len;
> >  	p->nid = nid;
> > +	p->dev_id = dev_id;
> >  	memcpy(p->conns, list, len * sizeof(hda_nid_t));
> >  	list_add(&p->list, &codec->conn_list);
> >  	return 0;
> > @@ -150,8 +152,13 @@ static void remove_conn_list(struct
> hda_codec *codec)
> >  	}
> >  }
> >
> > -/* read the connection and add to the cache */
> > -static int read_and_add_raw_conns(struct hda_codec *codec,
> hda_nid_t nid)
> > +/*
> > + * read the connection and add to the cache
> > + * the caller should select the device entry by sending the
> > + * corresponding verb if necessary before calling this function
> > + */
> > +static int read_and_add_raw_conns(struct hda_codec *codec,
> hda_nid_t nid,
> > +				  int dev_id)
> >  {
> >  	hda_nid_t list[32];
> >  	hda_nid_t *result = list;
> > @@ -166,7 +173,8 @@ static int read_and_add_raw_conns(struct
> hda_codec *codec, hda_nid_t nid)
> >  		len = snd_hda_get_raw_connections(codec, nid, result,
> len);
> >  	}
> >  	if (len >= 0)
> > -		len = snd_hda_override_conn_list(codec, nid, len, result);
> > +		len = snd_hda_override_conn_list_mst(codec, nid,
> > +					     dev_id, len, result);
> >  	if (result != list)
> >  		kfree(result);
> >  	return len;
> > @@ -197,7 +205,7 @@ int snd_hda_get_conn_list(struct hda_codec
> *codec, hda_nid_t nid,
> >  		const struct hda_conn_list *p;
> >
> >  		/* if the connection-list is already cached, read it */
> > -		p = lookup_conn_list(codec, nid);
> > +		p = lookup_conn_list(codec, nid, 0);
> >  		if (p) {
> >  			if (listp)
> >  				*listp = p->conns;
> > @@ -206,7 +214,7 @@ int snd_hda_get_conn_list(struct hda_codec
> *codec, hda_nid_t nid,
> >  		if (snd_BUG_ON(added))
> >  			return -EINVAL;
> >
> > -		err = read_and_add_raw_conns(codec, nid);
> > +		err = read_and_add_raw_conns(codec, nid, 0);
> >  		if (err < 0)
> >  			return err;
> >  		added = true;
> > @@ -215,6 +223,49 @@ int snd_hda_get_conn_list(struct hda_codec
> *codec, hda_nid_t nid,
> >  EXPORT_SYMBOL_GPL(snd_hda_get_conn_list);
> >
> >  /**
> > + * snd_hda_get_conn_list_mst - get connection list in mst mode
> > + * @codec: the HDA codec
> > + * @nid: NID to parse
> > + * @dev_id: device entry id
> > + * @listp: the pointer to store NID list
> > + *
> > + * Parses the connection list of the given widget and stores the pointer
> > + * to the list of NIDs.
> > + *
> > + * Returns the number of connections, or a negative error code.
> > + *
> > + * Note that the returned pointer isn't protected against the list
> > + * modification.  If snd_hda_override_conn_list() might be called
> > + * concurrently, protect with a mutex appropriately.
> > + */
> > +int snd_hda_get_conn_list_mst(struct hda_codec *codec, hda_nid_t
> nid,
> > +			      int dev_id, const hda_nid_t **listp)
> > +{
> > +	bool added = false;
> > +
> > +	for (;;) {
> > +		int err;
> > +		const struct hda_conn_list *p;
> > +
> > +		/* if the connection-list is already cached, read it */
> > +		p = lookup_conn_list(codec, nid, dev_id);
> > +		if (p) {
> > +			if (listp)
> > +				*listp = p->conns;
> > +			return p->len;
> > +		}
> > +		if (snd_BUG_ON(added))
> > +			return -EINVAL;
> > +
> > +		err = read_and_add_raw_conns(codec, nid, dev_id);
> > +		if (err < 0)
> > +			return err;
> > +		added = true;
> > +	}
> > +}
> > +EXPORT_SYMBOL_GPL(snd_hda_get_conn_list_mst);
> > +
> > +/**
> >   * snd_hda_get_connections - copy connection list
> >   * @codec: the HDA codec
> >   * @nid: NID to parse
> > @@ -246,6 +297,39 @@ int snd_hda_get_connections(struct
> hda_codec *codec, hda_nid_t nid,
> >  EXPORT_SYMBOL_GPL(snd_hda_get_connections);
> >
> >  /**
> > + * snd_hda_get_connections_mst - copy connection list in mst mode
> > + * @codec: the HDA codec
> > + * @nid: NID to parse
> > + * @dev_id: device entry id
> > + * @conn_list: connection list array; when NULL, checks only the size
> > + * @max_conns: max. number of connections to store
> > + *
> > + * Parses the connection list of the given widget and stores the list
> > + * of NIDs.
> > + *
> > + * Returns the number of connections, or a negative error code.
> > + */
> > +int snd_hda_get_connections_mst(struct hda_codec *codec,
> hda_nid_t nid,
> > +				int dev_id, hda_nid_t *conn_list,
> > +				int max_conns)
> > +{
> > +	const hda_nid_t *list;
> > +	int len = snd_hda_get_conn_list_mst(codec, nid, dev_id, &list);
> > +
> > +	if (len > 0 && conn_list) {
> > +		if (len > max_conns) {
> > +			codec_err(codec, "Too many connections %d for
> NID 0x%x\n",
> > +				   len, nid);
> > +			return -EINVAL;
> > +		}
> > +		memcpy(conn_list, list, len * sizeof(hda_nid_t));
> > +	}
> > +
> > +	return len;
> > +}
> > +EXPORT_SYMBOL_GPL(snd_hda_get_connections_mst);
> > +
> > +/**
> >   * snd_hda_override_conn_list - add/modify the connection-list to
> cache
> >   * @codec: the HDA codec
> >   * @nid: NID to parse
> > @@ -262,17 +346,45 @@ int snd_hda_override_conn_list(struct
> hda_codec *codec, hda_nid_t nid, int len,
> >  {
> >  	struct hda_conn_list *p;
> >
> > -	p = lookup_conn_list(codec, nid);
> > +	p = lookup_conn_list(codec, nid, 0);
> >  	if (p) {
> >  		list_del(&p->list);
> >  		kfree(p);
> >  	}
> >
> > -	return add_conn_list(codec, nid, len, list);
> > +	return add_conn_list(codec, nid, 0, len, list);
> >  }
> >  EXPORT_SYMBOL_GPL(snd_hda_override_conn_list);
> >
> >  /**
> > + * snd_hda_override_conn_list_mst - add/modify the connection-list
> to cache
> > + * @codec: the HDA codec
> > + * @nid: NID to parse
> > + * @dev_id: device entry id
> > + * @len: number of connection list entries
> > + * @list: the list of connection entries
> > + *
> > + * Add or modify the given connection-list to the cache.  If the
> corresponding
> > + * cache already exists, invalidate it and append a new one.
> > + *
> > + * Returns zero or a negative error code.
> > + */
> > +int snd_hda_override_conn_list_mst(struct hda_codec *codec,
> hda_nid_t nid,
> > +			   int dev_id, int len, const hda_nid_t *list)
> > +{
> > +	struct hda_conn_list *p;
> > +
> > +	p = lookup_conn_list(codec, nid, dev_id);
> > +	if (p) {
> > +		list_del(&p->list);
> > +		kfree(p);
> > +	}
> > +
> > +	return add_conn_list(codec, nid, dev_id, len, list);
> > +}
> > +EXPORT_SYMBOL_GPL(snd_hda_override_conn_list_mst);
> > +
> > +/**
> >   * snd_hda_get_conn_index - get the connection index of the given NID
> >   * @codec: the HDA codec
> >   * @mux: NID containing the list
> > diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
> > index 373fcad..deeed35 100644
> > --- a/sound/pci/hda/hda_codec.h
> > +++ b/sound/pci/hda/hda_codec.h
> > @@ -330,6 +330,9 @@ snd_hda_codec_write(struct hda_codec
> *codec, hda_nid_t nid, int flags,
> >  	snd_hdac_get_sub_nodes(&(codec)->core, nid, start_nid)
> >  int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
> >  			    hda_nid_t *conn_list, int max_conns);
> > +int snd_hda_get_connections_mst(struct hda_codec *codec,
> hda_nid_t nid,
> > +				int dev_id, hda_nid_t *conn_list,
> > +				int max_conns);
> >  static inline int
> >  snd_hda_get_num_conns(struct hda_codec *codec, hda_nid_t nid)
> >  {
> > @@ -345,6 +348,8 @@ int snd_hda_get_conn_list(struct hda_codec
> *codec, hda_nid_t nid,
> >  			  const hda_nid_t **listp);
> >  int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t
> nid, int nums,
> >  			  const hda_nid_t *list);
> > +int snd_hda_override_conn_list_mst(struct hda_codec *codec,
> hda_nid_t nid,
> > +			   int dev_id, int len, const hda_nid_t *list);
> >  int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux,
> >  			   hda_nid_t nid, int recursive);
> >  int snd_hda_get_devices(struct hda_codec *codec, hda_nid_t nid,
> > --
> > 1.9.1
> >

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 2/4] ALSA: hda - add DP mst verb support
  2016-03-07 16:45   ` Takashi Iwai
@ 2016-03-08  6:54     ` Yang, Libin
  2016-03-08  7:39       ` Takashi Iwai
  0 siblings, 1 reply; 13+ messages in thread
From: Yang, Libin @ 2016-03-08  6:54 UTC (permalink / raw)
  To: Takashi Iwai, libin.yang@linux.intel.com
  Cc: Lin, Mengdong, alsa-devel@alsa-project.org

Hi Takashi,

> -----Original Message-----
> From: Takashi Iwai [mailto:tiwai@suse.de]
> Sent: Tuesday, March 08, 2016 12:46 AM
> To: libin.yang@linux.intel.com
> Cc: alsa-devel@alsa-project.org; Lin, Mengdong; Yang, Libin
> Subject: Re: [alsa-devel] [PATCH 2/4] ALSA: hda - add DP mst verb
> support
> 
> On Mon, 07 Mar 2016 15:57:44 +0100,
> libin.yang@linux.intel.com wrote:
> >
> > +int snd_hda_set_dev_select(struct hda_codec *codec, hda_nid_t nid,
> int dev_id)
> > +{
> > +	int ret, dev;
> > +	unsigned long timeout;
> > +
> > +	/* not support dp_mst will always return 0, using first dev_entry
> */
> > +	if (!codec->dp_mst)
> > +		return 0;
> > +
> > +	/* If Device List Length is 0, the pin is not multi stream capable.
> > +	 */
> > +	if ((snd_hda_get_num_devices(codec, nid) + 1) == 0)
> > +		return 0;
> 
> I don't understand what this code is for.  Why +1?

Sorry, it should be if ((snd_hda_get_num_devices(codec, nid)) == 0).
0 means not MST capable. Thanks for point it out. 

> 
> > +
> > +	/* Behavior of setting index being equal to or greater than
> > +	 * Device List Length is not predictable
> > +	 */
> > +	if ((snd_hda_get_num_devices(codec, nid) + 1) <= dev_id)
> > +		return 0;
> 
> Ditto.  And, calling the same function twice?

(snd_hda_get_num_devices(codec, nid) + 1) means the device entry number.
If the (snd_hda_get_num_devices(codec, nid) + 1) == 3, it means there are
only 3 device entries. And dev_id being 0, 1, 2 is legal. It dev_id is 3 or greater,
it is illegal. 

Regards,
Libin

> 
> 
> thanks,
> 
> Takashi

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 2/4] ALSA: hda - add DP mst verb support
  2016-03-08  6:54     ` Yang, Libin
@ 2016-03-08  7:39       ` Takashi Iwai
  2016-03-08  7:49         ` Yang, Libin
  0 siblings, 1 reply; 13+ messages in thread
From: Takashi Iwai @ 2016-03-08  7:39 UTC (permalink / raw)
  To: Yang, Libin
  Cc: Lin, Mengdong, libin.yang@linux.intel.com,
	alsa-devel@alsa-project.org

On Tue, 08 Mar 2016 07:54:44 +0100,
Yang, Libin wrote:
> 
> Hi Takashi,
> 
> > -----Original Message-----
> > From: Takashi Iwai [mailto:tiwai@suse.de]
> > Sent: Tuesday, March 08, 2016 12:46 AM
> > To: libin.yang@linux.intel.com
> > Cc: alsa-devel@alsa-project.org; Lin, Mengdong; Yang, Libin
> > Subject: Re: [alsa-devel] [PATCH 2/4] ALSA: hda - add DP mst verb
> > support
> > 
> > On Mon, 07 Mar 2016 15:57:44 +0100,
> > libin.yang@linux.intel.com wrote:
> > >
> > > +int snd_hda_set_dev_select(struct hda_codec *codec, hda_nid_t nid,
> > int dev_id)
> > > +{
> > > +	int ret, dev;
> > > +	unsigned long timeout;
> > > +
> > > +	/* not support dp_mst will always return 0, using first dev_entry
> > */
> > > +	if (!codec->dp_mst)
> > > +		return 0;
> > > +
> > > +	/* If Device List Length is 0, the pin is not multi stream capable.
> > > +	 */
> > > +	if ((snd_hda_get_num_devices(codec, nid) + 1) == 0)
> > > +		return 0;
> > 
> > I don't understand what this code is for.  Why +1?
> 
> Sorry, it should be if ((snd_hda_get_num_devices(codec, nid)) == 0).
> 0 means not MST capable. Thanks for point it out. 
> 
> > 
> > > +
> > > +	/* Behavior of setting index being equal to or greater than
> > > +	 * Device List Length is not predictable
> > > +	 */
> > > +	if ((snd_hda_get_num_devices(codec, nid) + 1) <= dev_id)
> > > +		return 0;
> > 
> > Ditto.  And, calling the same function twice?
> 
> (snd_hda_get_num_devices(codec, nid) + 1) means the device entry number.
> If the (snd_hda_get_num_devices(codec, nid) + 1) == 3, it means there are
> only 3 device entries. And dev_id being 0, 1, 2 is legal. It dev_id is 3 or greater,
> it is illegal. 

So, shouldn't it be like below?
    if (dev_id >= num_devices)
        return 0;

Also my point is that you don't need to call snd_hda_get_num_devices()
twice.  It can be stored locally.


Takashi

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 2/4] ALSA: hda - add DP mst verb support
  2016-03-08  7:39       ` Takashi Iwai
@ 2016-03-08  7:49         ` Yang, Libin
  0 siblings, 0 replies; 13+ messages in thread
From: Yang, Libin @ 2016-03-08  7:49 UTC (permalink / raw)
  To: Takashi Iwai
  Cc: Lin, Mengdong, libin.yang@linux.intel.com,
	alsa-devel@alsa-project.org


> -----Original Message-----
> From: Takashi Iwai [mailto:tiwai@suse.de]
> Sent: Tuesday, March 08, 2016 3:39 PM
> To: Yang, Libin
> Cc: libin.yang@linux.intel.com; alsa-devel@alsa-project.org; Lin,
> Mengdong
> Subject: Re: [alsa-devel] [PATCH 2/4] ALSA: hda - add DP mst verb
> support
> 
> On Tue, 08 Mar 2016 07:54:44 +0100,
> Yang, Libin wrote:
> >
> > Hi Takashi,
> >
> > > -----Original Message-----
> > > From: Takashi Iwai [mailto:tiwai@suse.de]
> > > Sent: Tuesday, March 08, 2016 12:46 AM
> > > To: libin.yang@linux.intel.com
> > > Cc: alsa-devel@alsa-project.org; Lin, Mengdong; Yang, Libin
> > > Subject: Re: [alsa-devel] [PATCH 2/4] ALSA: hda - add DP mst verb
> > > support
> > >
> > > On Mon, 07 Mar 2016 15:57:44 +0100,
> > > libin.yang@linux.intel.com wrote:
> > > >
> > > > +int snd_hda_set_dev_select(struct hda_codec *codec, hda_nid_t
> nid,
> > > int dev_id)
> > > > +{
> > > > +	int ret, dev;
> > > > +	unsigned long timeout;
> > > > +
> > > > +	/* not support dp_mst will always return 0, using first dev_entry
> > > */
> > > > +	if (!codec->dp_mst)
> > > > +		return 0;
> > > > +
> > > > +	/* If Device List Length is 0, the pin is not multi stream capable.
> > > > +	 */
> > > > +	if ((snd_hda_get_num_devices(codec, nid) + 1) == 0)
> > > > +		return 0;
> > >
> > > I don't understand what this code is for.  Why +1?
> >
> > Sorry, it should be if ((snd_hda_get_num_devices(codec, nid)) == 0).
> > 0 means not MST capable. Thanks for point it out.
> >
> > >
> > > > +
> > > > +	/* Behavior of setting index being equal to or greater than
> > > > +	 * Device List Length is not predictable
> > > > +	 */
> > > > +	if ((snd_hda_get_num_devices(codec, nid) + 1) <= dev_id)
> > > > +		return 0;
> > >
> > > Ditto.  And, calling the same function twice?
> >
> > (snd_hda_get_num_devices(codec, nid) + 1) means the device entry
> number.
> > If the (snd_hda_get_num_devices(codec, nid) + 1) == 3, it means there
> are
> > only 3 device entries. And dev_id being 0, 1, 2 is legal. It dev_id is 3 or
> greater,
> > it is illegal.
> 
> So, shouldn't it be like below?
>     if (dev_id >= num_devices)
>         return 0;
> 
> Also my point is that you don't need to call snd_hda_get_num_devices()
> twice.  It can be stored locally.

Get it. I will store it locally.

Regards,
Libin

> 
> 
> Takashi

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2016-03-08  7:49 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-03-07 14:57 [RFC PATCH 0/4] MST DP audio support libin.yang
2016-03-07 14:57 ` [RFC PATCH 1/4] ALSA: hda - codec add DP MST support for connection list libin.yang
2016-03-07 16:40   ` Takashi Iwai
2016-03-08  6:47     ` Yang, Libin
2016-03-07 14:57 ` [PATCH 2/4] ALSA: hda - add DP mst verb support libin.yang
2016-03-07 16:45   ` Takashi Iwai
2016-03-08  6:54     ` Yang, Libin
2016-03-08  7:39       ` Takashi Iwai
2016-03-08  7:49         ` Yang, Libin
2016-03-07 14:57 ` [RFC PATCH 3/4] ALSA - hda: add devid support in acom libin.yang
2016-03-07 14:57 ` [RFC PATCH 4/4] ALSA - hda: add DP MST support libin.yang
2016-03-07 15:19   ` Takashi Iwai
2016-03-08  6:47     ` Yang, Libin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).