Blob Blame History Raw
From a1687c68c3089ed746c18f2121c8e63e2cf22c00 Mon Sep 17 00:00:00 2001
From: Jaska Uimonen <jaska.uimonen@linux.intel.com>
Date: Wed, 15 Apr 2020 15:28:16 -0500
Subject: [PATCH] ASoC: SOF: topology: handle multiple sets of tuple arrays
Git-commit: a1687c68c3089ed746c18f2121c8e63e2cf22c00
Patch-mainline: v5.8-rc1
References: jsc#SLE-16518

Widget's parameters are set in topology and they usually consist of
several different types of tuple arrays like strings, words and bytes.
Here this kind of combination is called a "set".

Lately we've seen more complex widget definitions with multiple
identical sets of tuple arrays. One example is the dmic pdm
configuration, which is currently handled as a special case in token
parsing. This is not scalable for other components with multiple sets.

So add a new function sof_parse_token_sets, which can be used to parse
multiple sets. This function defines the number of sets and an offset to
copy the tokens to correct positions in the destination ipc struct. Old
sof_parse_token function will be a special case of calling
sof_parse_token_sets to parse 1 set with offset 0.

Finally modify the dmic dai link loading to use the new
sof_parse_array_sets to load multiple pdm configs.

Signed-off-by: Jaska Uimonen <jaska.uimonen@linux.intel.com>
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Reviewed-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Link: https://lore.kernel.org/r/20200415202816.934-25-pierre-louis.bossart@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Acked-by: Takashi Iwai <tiwai@suse.de>

---
 sound/soc/sof/topology.c | 123 ++++++++++++++++++++++++++---------------------
 1 file changed, 67 insertions(+), 56 deletions(-)

diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c
index d4d0c39d6e6e..e88ffc25025f 100644
--- a/sound/soc/sof/topology.c
+++ b/sound/soc/sof/topology.c
@@ -773,7 +773,8 @@ static int sof_parse_uuid_tokens(struct snd_soc_component *scomp,
 				 void *object,
 				 const struct sof_topology_token *tokens,
 				 int count,
-				 struct snd_soc_tplg_vendor_array *array)
+				 struct snd_soc_tplg_vendor_array *array,
+				 size_t offset)
 {
 	struct snd_soc_tplg_vendor_uuid_elem *elem;
 	int found = 0;
@@ -794,7 +795,8 @@ static int sof_parse_uuid_tokens(struct snd_soc_component *scomp,
 				continue;
 
 			/* matched - now load token */
-			tokens[j].get_token(elem, object, tokens[j].offset,
+			tokens[j].get_token(elem, object,
+					    offset + tokens[j].offset,
 					    tokens[j].size);
 
 			found++;
@@ -808,7 +810,8 @@ static int sof_parse_string_tokens(struct snd_soc_component *scomp,
 				   void *object,
 				   const struct sof_topology_token *tokens,
 				   int count,
-				   struct snd_soc_tplg_vendor_array *array)
+				   struct snd_soc_tplg_vendor_array *array,
+				   size_t offset)
 {
 	struct snd_soc_tplg_vendor_string_elem *elem;
 	int found = 0;
@@ -829,7 +832,8 @@ static int sof_parse_string_tokens(struct snd_soc_component *scomp,
 				continue;
 
 			/* matched - now load token */
-			tokens[j].get_token(elem, object, tokens[j].offset,
+			tokens[j].get_token(elem, object,
+					    offset + tokens[j].offset,
 					    tokens[j].size);
 
 			found++;
@@ -843,15 +847,12 @@ static int sof_parse_word_tokens(struct snd_soc_component *scomp,
 				 void *object,
 				 const struct sof_topology_token *tokens,
 				 int count,
-				 struct snd_soc_tplg_vendor_array *array)
+				 struct snd_soc_tplg_vendor_array *array,
+				 size_t offset)
 {
-	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
 	struct snd_soc_tplg_vendor_value_elem *elem;
-	size_t size = sizeof(struct sof_ipc_dai_dmic_pdm_ctrl);
 	int found = 0;
 	int i, j;
-	u32 offset;
-	u32 *index = NULL;
 
 	/* parse element by element */
 	for (i = 0; i < le32_to_cpu(array->num_elems); i++) {
@@ -870,40 +871,6 @@ static int sof_parse_word_tokens(struct snd_soc_component *scomp,
 			if (tokens[j].token != le32_to_cpu(elem->token))
 				continue;
 
-			/* pdm config array index */
-			if (sdev->private)
-				index = sdev->private;
-
-			/* matched - determine offset */
-			switch (tokens[j].token) {
-			case SOF_TKN_INTEL_DMIC_PDM_CTRL_ID:
-
-				/* inc number of pdm array index */
-				if (index)
-					(*index)++;
-				/* fallthrough */
-			case SOF_TKN_INTEL_DMIC_PDM_MIC_A_Enable:
-			case SOF_TKN_INTEL_DMIC_PDM_MIC_B_Enable:
-			case SOF_TKN_INTEL_DMIC_PDM_POLARITY_A:
-			case SOF_TKN_INTEL_DMIC_PDM_POLARITY_B:
-			case SOF_TKN_INTEL_DMIC_PDM_CLK_EDGE:
-			case SOF_TKN_INTEL_DMIC_PDM_SKEW:
-
-				/* check if array index is valid */
-				if (!index || *index == 0) {
-					dev_err(scomp->dev,
-						"error: invalid array offset\n");
-					continue;
-				} else {
-					/* offset within the pdm config array */
-					offset = size * (*index - 1);
-				}
-				break;
-			default:
-				offset = 0;
-				break;
-			}
-
 			/* load token */
 			tokens[j].get_token(elem, object,
 					    offset + tokens[j].offset,
@@ -916,17 +883,33 @@ static int sof_parse_word_tokens(struct snd_soc_component *scomp,
 	return found;
 }
 
-static int sof_parse_tokens(struct snd_soc_component *scomp,
-			    void *object,
-			    const struct sof_topology_token *tokens,
-			    int count,
-			    struct snd_soc_tplg_vendor_array *array,
-			    int priv_size)
-{
+/**
+ * sof_parse_token_sets - Parse multiple sets of tokens
+ * @scomp: pointer to soc component
+ * @object: target ipc struct for parsed values
+ * @tokens: token definition array describing what tokens to parse
+ * @count: number of tokens in definition array
+ * @array: source pointer to consecutive vendor arrays to be parsed
+ * @priv_size: total size of the consecutive source arrays
+ * @sets: number of similar token sets to be parsed, 1 set has count elements
+ * @object_size: offset to next target ipc struct with multiple sets
+ *
+ * This function parses multiple sets of tokens in vendor arrays into
+ * consecutive ipc structs.
+ */
+static int sof_parse_token_sets(struct snd_soc_component *scomp,
+				void *object,
+				const struct sof_topology_token *tokens,
+				int count,
+				struct snd_soc_tplg_vendor_array *array,
+				int priv_size, int sets, size_t object_size)
+{
+	size_t offset = 0;
 	int found = 0;
+	int total = 0;
 	int asize;
 
-	while (priv_size > 0 && found < count) {
+	while (priv_size > 0 && total < count * sets) {
 		asize = le32_to_cpu(array->size);
 
 		/* validate asize */
@@ -948,18 +931,18 @@ static int sof_parse_tokens(struct snd_soc_component *scomp,
 		switch (le32_to_cpu(array->type)) {
 		case SND_SOC_TPLG_TUPLE_TYPE_UUID:
 			found += sof_parse_uuid_tokens(scomp, object, tokens,
-						       count, array);
+						       count, array, offset);
 			break;
 		case SND_SOC_TPLG_TUPLE_TYPE_STRING:
 			found += sof_parse_string_tokens(scomp, object, tokens,
-							 count, array);
+							 count, array, offset);
 			break;
 		case SND_SOC_TPLG_TUPLE_TYPE_BOOL:
 		case SND_SOC_TPLG_TUPLE_TYPE_BYTE:
 		case SND_SOC_TPLG_TUPLE_TYPE_WORD:
 		case SND_SOC_TPLG_TUPLE_TYPE_SHORT:
 			found += sof_parse_word_tokens(scomp, object, tokens,
-						       count, array);
+						       count, array, offset);
 			break;
 		default:
 			dev_err(scomp->dev, "error: unknown token type %d\n",
@@ -970,10 +953,35 @@ static int sof_parse_tokens(struct snd_soc_component *scomp,
 		/* next array */
 		array = (struct snd_soc_tplg_vendor_array *)((u8 *)array
 			+ asize);
+
+		/* move to next target struct */
+		if (found >= count) {
+			offset += object_size;
+			total += found;
+			found = 0;
+		}
 	}
+
 	return 0;
 }
 
+static int sof_parse_tokens(struct snd_soc_component *scomp,
+			    void *object,
+			    const struct sof_topology_token *tokens,
+			    int count,
+			    struct snd_soc_tplg_vendor_array *array,
+			    int priv_size)
+{
+	/*
+	 * sof_parse_tokens is used when topology contains only a single set of
+	 * identical tuples arrays. So additional parameters to
+	 * sof_parse_token_sets are sets = 1 (only 1 set) and
+	 * object_size = 0 (irrelevant).
+	 */
+	return sof_parse_token_sets(scomp, object, tokens, count, array,
+				    priv_size, 1, 0);
+}
+
 static void sof_dbg_comp_config(struct snd_soc_component *scomp,
 				struct sof_ipc_comp_config *config)
 {
@@ -2951,9 +2959,12 @@ static int sof_link_dmic_load(struct snd_soc_component *scomp, int index,
 		return -ENOMEM;
 
 	/* get DMIC PDM tokens */
-	ret = sof_parse_tokens(scomp, &config->dmic.pdm[0], dmic_pdm_tokens,
+	ret = sof_parse_token_sets(scomp, &config->dmic.pdm[0], dmic_pdm_tokens,
 			       ARRAY_SIZE(dmic_pdm_tokens), private->array,
-			       le32_to_cpu(private->size));
+			       le32_to_cpu(private->size),
+			       config->dmic.num_pdm_active,
+			       sizeof(struct sof_ipc_dai_dmic_pdm_ctrl));
+
 	if (ret != 0) {
 		dev_err(scomp->dev, "error: parse dmic pdm tokens failed %d\n",
 			le32_to_cpu(private->size));
-- 
2.16.4