xref: /openbmc/linux/sound/soc/intel/avs/topology.c (revision 6f85e9b7)
134ae2cd5SCezary Rojewski // SPDX-License-Identifier: GPL-2.0-only
234ae2cd5SCezary Rojewski //
334ae2cd5SCezary Rojewski // Copyright(c) 2021 Intel Corporation. All rights reserved.
434ae2cd5SCezary Rojewski //
534ae2cd5SCezary Rojewski // Authors: Cezary Rojewski <cezary.rojewski@intel.com>
634ae2cd5SCezary Rojewski //          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
734ae2cd5SCezary Rojewski //
834ae2cd5SCezary Rojewski 
9d73d1b67SCezary Rojewski #include <linux/firmware.h>
1034ae2cd5SCezary Rojewski #include <linux/uuid.h>
1134ae2cd5SCezary Rojewski #include <sound/soc.h>
1234ae2cd5SCezary Rojewski #include <sound/soc-acpi.h>
1334ae2cd5SCezary Rojewski #include <sound/soc-topology.h>
1434ae2cd5SCezary Rojewski #include <uapi/sound/intel/avs/tokens.h>
1534ae2cd5SCezary Rojewski #include "avs.h"
16be2b81b5SAmadeusz Sławiński #include "control.h"
1734ae2cd5SCezary Rojewski #include "topology.h"
1834ae2cd5SCezary Rojewski 
1934ae2cd5SCezary Rojewski /* Get pointer to vendor array at the specified offset. */
2034ae2cd5SCezary Rojewski #define avs_tplg_vendor_array_at(array, offset) \
2134ae2cd5SCezary Rojewski 	((struct snd_soc_tplg_vendor_array *)((u8 *)array + offset))
2234ae2cd5SCezary Rojewski 
2334ae2cd5SCezary Rojewski /* Get pointer to vendor array that is next in line. */
2434ae2cd5SCezary Rojewski #define avs_tplg_vendor_array_next(array) \
2534ae2cd5SCezary Rojewski 	(avs_tplg_vendor_array_at(array, le32_to_cpu((array)->size)))
2634ae2cd5SCezary Rojewski 
2734ae2cd5SCezary Rojewski /*
2834ae2cd5SCezary Rojewski  * Scan provided block of tuples for the specified token. If found,
2934ae2cd5SCezary Rojewski  * @offset is updated with position at which first matching token is
3034ae2cd5SCezary Rojewski  * located.
3134ae2cd5SCezary Rojewski  *
3234ae2cd5SCezary Rojewski  * Returns 0 on success, -ENOENT if not found and error code otherwise.
3334ae2cd5SCezary Rojewski  */
3434ae2cd5SCezary Rojewski static int
avs_tplg_vendor_array_lookup(struct snd_soc_tplg_vendor_array * tuples,u32 block_size,u32 token,u32 * offset)3534ae2cd5SCezary Rojewski avs_tplg_vendor_array_lookup(struct snd_soc_tplg_vendor_array *tuples,
3634ae2cd5SCezary Rojewski 			     u32 block_size, u32 token, u32 *offset)
3734ae2cd5SCezary Rojewski {
3834ae2cd5SCezary Rojewski 	u32 pos = 0;
3934ae2cd5SCezary Rojewski 
4034ae2cd5SCezary Rojewski 	while (block_size > 0) {
4134ae2cd5SCezary Rojewski 		struct snd_soc_tplg_vendor_value_elem *tuple;
4234ae2cd5SCezary Rojewski 		u32 tuples_size = le32_to_cpu(tuples->size);
4334ae2cd5SCezary Rojewski 
4434ae2cd5SCezary Rojewski 		if (tuples_size > block_size)
4534ae2cd5SCezary Rojewski 			return -EINVAL;
4634ae2cd5SCezary Rojewski 
4734ae2cd5SCezary Rojewski 		tuple = tuples->value;
4834ae2cd5SCezary Rojewski 		if (le32_to_cpu(tuple->token) == token) {
4934ae2cd5SCezary Rojewski 			*offset = pos;
5034ae2cd5SCezary Rojewski 			return 0;
5134ae2cd5SCezary Rojewski 		}
5234ae2cd5SCezary Rojewski 
5334ae2cd5SCezary Rojewski 		block_size -= tuples_size;
5434ae2cd5SCezary Rojewski 		pos += tuples_size;
5534ae2cd5SCezary Rojewski 		tuples = avs_tplg_vendor_array_next(tuples);
5634ae2cd5SCezary Rojewski 	}
5734ae2cd5SCezary Rojewski 
5834ae2cd5SCezary Rojewski 	return -ENOENT;
5934ae2cd5SCezary Rojewski }
6034ae2cd5SCezary Rojewski 
6134ae2cd5SCezary Rojewski /*
6234ae2cd5SCezary Rojewski  * See avs_tplg_vendor_array_lookup() for description.
6334ae2cd5SCezary Rojewski  *
6434ae2cd5SCezary Rojewski  * Behaves exactly like avs_tplg_vendor_lookup() but starts from the
6534ae2cd5SCezary Rojewski  * next vendor array in line. Useful when searching for the finish line
6634ae2cd5SCezary Rojewski  * of an arbitrary entry in a list of entries where each is composed of
6734ae2cd5SCezary Rojewski  * several vendor tuples and a specific token marks the beginning of
6834ae2cd5SCezary Rojewski  * a new entry block.
6934ae2cd5SCezary Rojewski  */
7034ae2cd5SCezary Rojewski static int
avs_tplg_vendor_array_lookup_next(struct snd_soc_tplg_vendor_array * tuples,u32 block_size,u32 token,u32 * offset)7134ae2cd5SCezary Rojewski avs_tplg_vendor_array_lookup_next(struct snd_soc_tplg_vendor_array *tuples,
7234ae2cd5SCezary Rojewski 				  u32 block_size, u32 token, u32 *offset)
7334ae2cd5SCezary Rojewski {
7434ae2cd5SCezary Rojewski 	u32 tuples_size = le32_to_cpu(tuples->size);
7534ae2cd5SCezary Rojewski 	int ret;
7634ae2cd5SCezary Rojewski 
7734ae2cd5SCezary Rojewski 	if (tuples_size > block_size)
7834ae2cd5SCezary Rojewski 		return -EINVAL;
7934ae2cd5SCezary Rojewski 
8034ae2cd5SCezary Rojewski 	tuples = avs_tplg_vendor_array_next(tuples);
8134ae2cd5SCezary Rojewski 	block_size -= tuples_size;
8234ae2cd5SCezary Rojewski 
8334ae2cd5SCezary Rojewski 	ret = avs_tplg_vendor_array_lookup(tuples, block_size, token, offset);
8434ae2cd5SCezary Rojewski 	if (!ret)
8534ae2cd5SCezary Rojewski 		*offset += tuples_size;
8634ae2cd5SCezary Rojewski 	return ret;
8734ae2cd5SCezary Rojewski }
8834ae2cd5SCezary Rojewski 
8934ae2cd5SCezary Rojewski /*
9034ae2cd5SCezary Rojewski  * Scan provided block of tuples for the specified token which marks
9134ae2cd5SCezary Rojewski  * the border of an entry block. Behavior is similar to
9234ae2cd5SCezary Rojewski  * avs_tplg_vendor_array_lookup() except 0 is also returned if no
9334ae2cd5SCezary Rojewski  * matching token has been found. In such case, returned @size is
9434ae2cd5SCezary Rojewski  * assigned to @block_size as the entire block belongs to the current
9534ae2cd5SCezary Rojewski  * entry.
9634ae2cd5SCezary Rojewski  *
9734ae2cd5SCezary Rojewski  * Returns 0 on success, error code otherwise.
9834ae2cd5SCezary Rojewski  */
9934ae2cd5SCezary Rojewski static int
avs_tplg_vendor_entry_size(struct snd_soc_tplg_vendor_array * tuples,u32 block_size,u32 entry_id_token,u32 * size)10034ae2cd5SCezary Rojewski avs_tplg_vendor_entry_size(struct snd_soc_tplg_vendor_array *tuples,
10134ae2cd5SCezary Rojewski 			   u32 block_size, u32 entry_id_token, u32 *size)
10234ae2cd5SCezary Rojewski {
10334ae2cd5SCezary Rojewski 	int ret;
10434ae2cd5SCezary Rojewski 
10534ae2cd5SCezary Rojewski 	ret = avs_tplg_vendor_array_lookup_next(tuples, block_size, entry_id_token, size);
10634ae2cd5SCezary Rojewski 	if (ret == -ENOENT) {
10734ae2cd5SCezary Rojewski 		*size = block_size;
10834ae2cd5SCezary Rojewski 		ret = 0;
10934ae2cd5SCezary Rojewski 	}
11034ae2cd5SCezary Rojewski 
11134ae2cd5SCezary Rojewski 	return ret;
11234ae2cd5SCezary Rojewski }
11334ae2cd5SCezary Rojewski 
11434ae2cd5SCezary Rojewski /*
11534ae2cd5SCezary Rojewski  * Vendor tuple parsing descriptor.
11634ae2cd5SCezary Rojewski  *
11734ae2cd5SCezary Rojewski  * @token: vendor specific token that identifies tuple
11834ae2cd5SCezary Rojewski  * @type: tuple type, one of SND_SOC_TPLG_TUPLE_TYPE_XXX
11934ae2cd5SCezary Rojewski  * @offset: offset of a struct's field to initialize
12034ae2cd5SCezary Rojewski  * @parse: parsing function, extracts and assigns value to object's field
12134ae2cd5SCezary Rojewski  */
12234ae2cd5SCezary Rojewski struct avs_tplg_token_parser {
12334ae2cd5SCezary Rojewski 	enum avs_tplg_token token;
12434ae2cd5SCezary Rojewski 	u32 type;
12534ae2cd5SCezary Rojewski 	u32 offset;
12634ae2cd5SCezary Rojewski 	int (*parse)(struct snd_soc_component *comp, void *elem, void *object, u32 offset);
12734ae2cd5SCezary Rojewski };
12834ae2cd5SCezary Rojewski 
12934ae2cd5SCezary Rojewski static int
avs_parse_uuid_token(struct snd_soc_component * comp,void * elem,void * object,u32 offset)13034ae2cd5SCezary Rojewski avs_parse_uuid_token(struct snd_soc_component *comp, void *elem, void *object, u32 offset)
13134ae2cd5SCezary Rojewski {
13246c80e72SAmadeusz Sławiński 	struct snd_soc_tplg_vendor_uuid_elem *tuple = elem;
13334ae2cd5SCezary Rojewski 	guid_t *val = (guid_t *)((u8 *)object + offset);
13434ae2cd5SCezary Rojewski 
13546c80e72SAmadeusz Sławiński 	guid_copy((guid_t *)val, (const guid_t *)&tuple->uuid);
13634ae2cd5SCezary Rojewski 
13734ae2cd5SCezary Rojewski 	return 0;
13834ae2cd5SCezary Rojewski }
13934ae2cd5SCezary Rojewski 
14034ae2cd5SCezary Rojewski static int
avs_parse_bool_token(struct snd_soc_component * comp,void * elem,void * object,u32 offset)14134ae2cd5SCezary Rojewski avs_parse_bool_token(struct snd_soc_component *comp, void *elem, void *object, u32 offset)
14234ae2cd5SCezary Rojewski {
14334ae2cd5SCezary Rojewski 	struct snd_soc_tplg_vendor_value_elem *tuple = elem;
14434ae2cd5SCezary Rojewski 	bool *val = (bool *)((u8 *)object + offset);
14534ae2cd5SCezary Rojewski 
14634ae2cd5SCezary Rojewski 	*val = le32_to_cpu(tuple->value);
14734ae2cd5SCezary Rojewski 
14834ae2cd5SCezary Rojewski 	return 0;
14934ae2cd5SCezary Rojewski }
15034ae2cd5SCezary Rojewski 
15134ae2cd5SCezary Rojewski static int
avs_parse_byte_token(struct snd_soc_component * comp,void * elem,void * object,u32 offset)15234ae2cd5SCezary Rojewski avs_parse_byte_token(struct snd_soc_component *comp, void *elem, void *object, u32 offset)
15334ae2cd5SCezary Rojewski {
15434ae2cd5SCezary Rojewski 	struct snd_soc_tplg_vendor_value_elem *tuple = elem;
15534ae2cd5SCezary Rojewski 	u8 *val = ((u8 *)object + offset);
15634ae2cd5SCezary Rojewski 
15734ae2cd5SCezary Rojewski 	*val = le32_to_cpu(tuple->value);
15834ae2cd5SCezary Rojewski 
15934ae2cd5SCezary Rojewski 	return 0;
16034ae2cd5SCezary Rojewski }
16134ae2cd5SCezary Rojewski 
16234ae2cd5SCezary Rojewski static int
avs_parse_short_token(struct snd_soc_component * comp,void * elem,void * object,u32 offset)16334ae2cd5SCezary Rojewski avs_parse_short_token(struct snd_soc_component *comp, void *elem, void *object, u32 offset)
16434ae2cd5SCezary Rojewski {
16534ae2cd5SCezary Rojewski 	struct snd_soc_tplg_vendor_value_elem *tuple = elem;
16634ae2cd5SCezary Rojewski 	u16 *val = (u16 *)((u8 *)object + offset);
16734ae2cd5SCezary Rojewski 
16834ae2cd5SCezary Rojewski 	*val = le32_to_cpu(tuple->value);
16934ae2cd5SCezary Rojewski 
17034ae2cd5SCezary Rojewski 	return 0;
17134ae2cd5SCezary Rojewski }
17234ae2cd5SCezary Rojewski 
17334ae2cd5SCezary Rojewski static int
avs_parse_word_token(struct snd_soc_component * comp,void * elem,void * object,u32 offset)17434ae2cd5SCezary Rojewski avs_parse_word_token(struct snd_soc_component *comp, void *elem, void *object, u32 offset)
17534ae2cd5SCezary Rojewski {
17634ae2cd5SCezary Rojewski 	struct snd_soc_tplg_vendor_value_elem *tuple = elem;
17734ae2cd5SCezary Rojewski 	u32 *val = (u32 *)((u8 *)object + offset);
17834ae2cd5SCezary Rojewski 
17934ae2cd5SCezary Rojewski 	*val = le32_to_cpu(tuple->value);
18034ae2cd5SCezary Rojewski 
18134ae2cd5SCezary Rojewski 	return 0;
18234ae2cd5SCezary Rojewski }
18334ae2cd5SCezary Rojewski 
18434ae2cd5SCezary Rojewski static int
avs_parse_string_token(struct snd_soc_component * comp,void * elem,void * object,u32 offset)18534ae2cd5SCezary Rojewski avs_parse_string_token(struct snd_soc_component *comp, void *elem, void *object, u32 offset)
18634ae2cd5SCezary Rojewski {
18734ae2cd5SCezary Rojewski 	struct snd_soc_tplg_vendor_string_elem *tuple = elem;
18834ae2cd5SCezary Rojewski 	char *val = (char *)((u8 *)object + offset);
18934ae2cd5SCezary Rojewski 
19034ae2cd5SCezary Rojewski 	snprintf(val, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s", tuple->string);
19134ae2cd5SCezary Rojewski 
19234ae2cd5SCezary Rojewski 	return 0;
19334ae2cd5SCezary Rojewski }
19434ae2cd5SCezary Rojewski 
avs_parse_uuid_tokens(struct snd_soc_component * comp,void * object,const struct avs_tplg_token_parser * parsers,int count,struct snd_soc_tplg_vendor_array * tuples)19534ae2cd5SCezary Rojewski static int avs_parse_uuid_tokens(struct snd_soc_component *comp, void *object,
19634ae2cd5SCezary Rojewski 				 const struct avs_tplg_token_parser *parsers, int count,
19734ae2cd5SCezary Rojewski 				 struct snd_soc_tplg_vendor_array *tuples)
19834ae2cd5SCezary Rojewski {
19934ae2cd5SCezary Rojewski 	struct snd_soc_tplg_vendor_uuid_elem *tuple;
20034ae2cd5SCezary Rojewski 	int ret, i, j;
20134ae2cd5SCezary Rojewski 
20234ae2cd5SCezary Rojewski 	/* Parse element by element. */
20334ae2cd5SCezary Rojewski 	for (i = 0; i < le32_to_cpu(tuples->num_elems); i++) {
20434ae2cd5SCezary Rojewski 		tuple = &tuples->uuid[i];
20534ae2cd5SCezary Rojewski 
20634ae2cd5SCezary Rojewski 		for (j = 0; j < count; j++) {
20734ae2cd5SCezary Rojewski 			/* Ignore non-UUID tokens. */
20834ae2cd5SCezary Rojewski 			if (parsers[j].type != SND_SOC_TPLG_TUPLE_TYPE_UUID ||
20934ae2cd5SCezary Rojewski 			    parsers[j].token != le32_to_cpu(tuple->token))
21034ae2cd5SCezary Rojewski 				continue;
21134ae2cd5SCezary Rojewski 
21234ae2cd5SCezary Rojewski 			ret = parsers[j].parse(comp, tuple, object, parsers[j].offset);
21334ae2cd5SCezary Rojewski 			if (ret)
21434ae2cd5SCezary Rojewski 				return ret;
21534ae2cd5SCezary Rojewski 		}
21634ae2cd5SCezary Rojewski 	}
21734ae2cd5SCezary Rojewski 
21834ae2cd5SCezary Rojewski 	return 0;
21934ae2cd5SCezary Rojewski }
22034ae2cd5SCezary Rojewski 
avs_parse_string_tokens(struct snd_soc_component * comp,void * object,const struct avs_tplg_token_parser * parsers,int count,struct snd_soc_tplg_vendor_array * tuples)22134ae2cd5SCezary Rojewski static int avs_parse_string_tokens(struct snd_soc_component *comp, void *object,
22234ae2cd5SCezary Rojewski 				   const struct avs_tplg_token_parser *parsers, int count,
22334ae2cd5SCezary Rojewski 				   struct snd_soc_tplg_vendor_array *tuples)
22434ae2cd5SCezary Rojewski {
22534ae2cd5SCezary Rojewski 	struct snd_soc_tplg_vendor_string_elem *tuple;
22634ae2cd5SCezary Rojewski 	int ret, i, j;
22734ae2cd5SCezary Rojewski 
22834ae2cd5SCezary Rojewski 	/* Parse element by element. */
22934ae2cd5SCezary Rojewski 	for (i = 0; i < le32_to_cpu(tuples->num_elems); i++) {
23034ae2cd5SCezary Rojewski 		tuple = &tuples->string[i];
23134ae2cd5SCezary Rojewski 
23234ae2cd5SCezary Rojewski 		for (j = 0; j < count; j++) {
23334ae2cd5SCezary Rojewski 			/* Ignore non-string tokens. */
23434ae2cd5SCezary Rojewski 			if (parsers[j].type != SND_SOC_TPLG_TUPLE_TYPE_STRING ||
23534ae2cd5SCezary Rojewski 			    parsers[j].token != le32_to_cpu(tuple->token))
23634ae2cd5SCezary Rojewski 				continue;
23734ae2cd5SCezary Rojewski 
23834ae2cd5SCezary Rojewski 			ret = parsers[j].parse(comp, tuple, object, parsers[j].offset);
23934ae2cd5SCezary Rojewski 			if (ret)
24034ae2cd5SCezary Rojewski 				return ret;
24134ae2cd5SCezary Rojewski 		}
24234ae2cd5SCezary Rojewski 	}
24334ae2cd5SCezary Rojewski 
24434ae2cd5SCezary Rojewski 	return 0;
24534ae2cd5SCezary Rojewski }
24634ae2cd5SCezary Rojewski 
avs_parse_word_tokens(struct snd_soc_component * comp,void * object,const struct avs_tplg_token_parser * parsers,int count,struct snd_soc_tplg_vendor_array * tuples)24734ae2cd5SCezary Rojewski static int avs_parse_word_tokens(struct snd_soc_component *comp, void *object,
24834ae2cd5SCezary Rojewski 				 const struct avs_tplg_token_parser *parsers, int count,
24934ae2cd5SCezary Rojewski 				 struct snd_soc_tplg_vendor_array *tuples)
25034ae2cd5SCezary Rojewski {
25134ae2cd5SCezary Rojewski 	struct snd_soc_tplg_vendor_value_elem *tuple;
25234ae2cd5SCezary Rojewski 	int ret, i, j;
25334ae2cd5SCezary Rojewski 
25434ae2cd5SCezary Rojewski 	/* Parse element by element. */
25534ae2cd5SCezary Rojewski 	for (i = 0; i < le32_to_cpu(tuples->num_elems); i++) {
25634ae2cd5SCezary Rojewski 		tuple = &tuples->value[i];
25734ae2cd5SCezary Rojewski 
25834ae2cd5SCezary Rojewski 		for (j = 0; j < count; j++) {
25934ae2cd5SCezary Rojewski 			/* Ignore non-integer tokens. */
26034ae2cd5SCezary Rojewski 			if (!(parsers[j].type == SND_SOC_TPLG_TUPLE_TYPE_WORD ||
26134ae2cd5SCezary Rojewski 			      parsers[j].type == SND_SOC_TPLG_TUPLE_TYPE_SHORT ||
26234ae2cd5SCezary Rojewski 			      parsers[j].type == SND_SOC_TPLG_TUPLE_TYPE_BYTE ||
26334ae2cd5SCezary Rojewski 			      parsers[j].type == SND_SOC_TPLG_TUPLE_TYPE_BOOL))
26434ae2cd5SCezary Rojewski 				continue;
26534ae2cd5SCezary Rojewski 
26634ae2cd5SCezary Rojewski 			if (parsers[j].token != le32_to_cpu(tuple->token))
26734ae2cd5SCezary Rojewski 				continue;
26834ae2cd5SCezary Rojewski 
26934ae2cd5SCezary Rojewski 			ret = parsers[j].parse(comp, tuple, object, parsers[j].offset);
27034ae2cd5SCezary Rojewski 			if (ret)
27134ae2cd5SCezary Rojewski 				return ret;
27234ae2cd5SCezary Rojewski 		}
27334ae2cd5SCezary Rojewski 	}
27434ae2cd5SCezary Rojewski 
27534ae2cd5SCezary Rojewski 	return 0;
27634ae2cd5SCezary Rojewski }
27734ae2cd5SCezary Rojewski 
avs_parse_tokens(struct snd_soc_component * comp,void * object,const struct avs_tplg_token_parser * parsers,size_t count,struct snd_soc_tplg_vendor_array * tuples,int priv_size)27834ae2cd5SCezary Rojewski static int avs_parse_tokens(struct snd_soc_component *comp, void *object,
27934ae2cd5SCezary Rojewski 			    const struct avs_tplg_token_parser *parsers, size_t count,
28034ae2cd5SCezary Rojewski 			    struct snd_soc_tplg_vendor_array *tuples, int priv_size)
28134ae2cd5SCezary Rojewski {
28234ae2cd5SCezary Rojewski 	int array_size, ret;
28334ae2cd5SCezary Rojewski 
28434ae2cd5SCezary Rojewski 	while (priv_size > 0) {
28534ae2cd5SCezary Rojewski 		array_size = le32_to_cpu(tuples->size);
28634ae2cd5SCezary Rojewski 
28734ae2cd5SCezary Rojewski 		if (array_size <= 0) {
28834ae2cd5SCezary Rojewski 			dev_err(comp->dev, "invalid array size 0x%x\n", array_size);
28934ae2cd5SCezary Rojewski 			return -EINVAL;
29034ae2cd5SCezary Rojewski 		}
29134ae2cd5SCezary Rojewski 
29234ae2cd5SCezary Rojewski 		/* Make sure there is enough data before parsing. */
29334ae2cd5SCezary Rojewski 		priv_size -= array_size;
29434ae2cd5SCezary Rojewski 		if (priv_size < 0) {
29534ae2cd5SCezary Rojewski 			dev_err(comp->dev, "invalid array size 0x%x\n", array_size);
29634ae2cd5SCezary Rojewski 			return -EINVAL;
29734ae2cd5SCezary Rojewski 		}
29834ae2cd5SCezary Rojewski 
29934ae2cd5SCezary Rojewski 		switch (le32_to_cpu(tuples->type)) {
30034ae2cd5SCezary Rojewski 		case SND_SOC_TPLG_TUPLE_TYPE_UUID:
30134ae2cd5SCezary Rojewski 			ret = avs_parse_uuid_tokens(comp, object, parsers, count, tuples);
30234ae2cd5SCezary Rojewski 			break;
30334ae2cd5SCezary Rojewski 		case SND_SOC_TPLG_TUPLE_TYPE_STRING:
30434ae2cd5SCezary Rojewski 			ret = avs_parse_string_tokens(comp, object, parsers, count, tuples);
30534ae2cd5SCezary Rojewski 			break;
30634ae2cd5SCezary Rojewski 		case SND_SOC_TPLG_TUPLE_TYPE_BOOL:
30734ae2cd5SCezary Rojewski 		case SND_SOC_TPLG_TUPLE_TYPE_BYTE:
30834ae2cd5SCezary Rojewski 		case SND_SOC_TPLG_TUPLE_TYPE_SHORT:
30934ae2cd5SCezary Rojewski 		case SND_SOC_TPLG_TUPLE_TYPE_WORD:
31034ae2cd5SCezary Rojewski 			ret = avs_parse_word_tokens(comp, object, parsers, count, tuples);
31134ae2cd5SCezary Rojewski 			break;
31234ae2cd5SCezary Rojewski 		default:
31334ae2cd5SCezary Rojewski 			dev_err(comp->dev, "unknown token type %d\n", tuples->type);
31434ae2cd5SCezary Rojewski 			ret = -EINVAL;
31534ae2cd5SCezary Rojewski 		}
31634ae2cd5SCezary Rojewski 
31734ae2cd5SCezary Rojewski 		if (ret) {
31834ae2cd5SCezary Rojewski 			dev_err(comp->dev, "parsing %zu tokens of %d type failed: %d\n",
31934ae2cd5SCezary Rojewski 				count, tuples->type, ret);
32034ae2cd5SCezary Rojewski 			return ret;
32134ae2cd5SCezary Rojewski 		}
32234ae2cd5SCezary Rojewski 
32334ae2cd5SCezary Rojewski 		tuples = avs_tplg_vendor_array_next(tuples);
32434ae2cd5SCezary Rojewski 	}
32534ae2cd5SCezary Rojewski 
32634ae2cd5SCezary Rojewski 	return 0;
32734ae2cd5SCezary Rojewski }
32834ae2cd5SCezary Rojewski 
32934ae2cd5SCezary Rojewski #define AVS_DEFINE_PTR_PARSER(name, type, member) \
33034ae2cd5SCezary Rojewski static int \
33134ae2cd5SCezary Rojewski avs_parse_##name##_ptr(struct snd_soc_component *comp, void *elem, void *object, u32 offset) \
33234ae2cd5SCezary Rojewski { \
33334ae2cd5SCezary Rojewski 	struct snd_soc_tplg_vendor_value_elem *tuple = elem;		\
33434ae2cd5SCezary Rojewski 	struct avs_soc_component *acomp = to_avs_soc_component(comp);	\
33534ae2cd5SCezary Rojewski 	type **val = (type **)(object + offset);			\
33634ae2cd5SCezary Rojewski 	u32 idx;							\
33734ae2cd5SCezary Rojewski 									\
33834ae2cd5SCezary Rojewski 	idx = le32_to_cpu(tuple->value);				\
33934ae2cd5SCezary Rojewski 	if (idx >= acomp->tplg->num_##member)				\
34034ae2cd5SCezary Rojewski 		return -EINVAL;						\
34134ae2cd5SCezary Rojewski 									\
34234ae2cd5SCezary Rojewski 	*val = &acomp->tplg->member[idx];				\
34334ae2cd5SCezary Rojewski 									\
34434ae2cd5SCezary Rojewski 	return 0;							\
34534ae2cd5SCezary Rojewski }
34634ae2cd5SCezary Rojewski 
34734ae2cd5SCezary Rojewski AVS_DEFINE_PTR_PARSER(audio_format, struct avs_audio_format, fmts);
34834ae2cd5SCezary Rojewski AVS_DEFINE_PTR_PARSER(modcfg_base, struct avs_tplg_modcfg_base, modcfgs_base);
3499e85ec40SCezary Rojewski AVS_DEFINE_PTR_PARSER(modcfg_ext, struct avs_tplg_modcfg_ext, modcfgs_ext);
3501fba2036SCezary Rojewski AVS_DEFINE_PTR_PARSER(pplcfg, struct avs_tplg_pplcfg, pplcfgs);
3511fba2036SCezary Rojewski AVS_DEFINE_PTR_PARSER(binding, struct avs_tplg_binding, bindings);
35234ae2cd5SCezary Rojewski 
35334ae2cd5SCezary Rojewski static int
parse_audio_format_bitfield(struct snd_soc_component * comp,void * elem,void * object,u32 offset)35434ae2cd5SCezary Rojewski parse_audio_format_bitfield(struct snd_soc_component *comp, void *elem, void *object, u32 offset)
35534ae2cd5SCezary Rojewski {
35634ae2cd5SCezary Rojewski 	struct snd_soc_tplg_vendor_value_elem *velem = elem;
35734ae2cd5SCezary Rojewski 	struct avs_audio_format *audio_format = object;
35834ae2cd5SCezary Rojewski 
35934ae2cd5SCezary Rojewski 	switch (offset) {
36034ae2cd5SCezary Rojewski 	case AVS_TKN_AFMT_NUM_CHANNELS_U32:
36134ae2cd5SCezary Rojewski 		audio_format->num_channels = le32_to_cpu(velem->value);
36234ae2cd5SCezary Rojewski 		break;
36334ae2cd5SCezary Rojewski 	case AVS_TKN_AFMT_VALID_BIT_DEPTH_U32:
36434ae2cd5SCezary Rojewski 		audio_format->valid_bit_depth = le32_to_cpu(velem->value);
36534ae2cd5SCezary Rojewski 		break;
36634ae2cd5SCezary Rojewski 	case AVS_TKN_AFMT_SAMPLE_TYPE_U32:
36734ae2cd5SCezary Rojewski 		audio_format->sample_type = le32_to_cpu(velem->value);
36834ae2cd5SCezary Rojewski 		break;
36934ae2cd5SCezary Rojewski 	}
37034ae2cd5SCezary Rojewski 
37134ae2cd5SCezary Rojewski 	return 0;
37234ae2cd5SCezary Rojewski }
37334ae2cd5SCezary Rojewski 
parse_link_formatted_string(struct snd_soc_component * comp,void * elem,void * object,u32 offset)374d48c1adaSCezary Rojewski static int parse_link_formatted_string(struct snd_soc_component *comp, void *elem,
375d48c1adaSCezary Rojewski 				       void *object, u32 offset)
376d48c1adaSCezary Rojewski {
377d48c1adaSCezary Rojewski 	struct snd_soc_tplg_vendor_string_elem *tuple = elem;
378d48c1adaSCezary Rojewski 	struct snd_soc_acpi_mach *mach = dev_get_platdata(comp->card->dev);
379d48c1adaSCezary Rojewski 	char *val = (char *)((u8 *)object + offset);
380d48c1adaSCezary Rojewski 
381d48c1adaSCezary Rojewski 	/*
382d48c1adaSCezary Rojewski 	 * Dynamic naming - string formats, e.g.: ssp%d - supported only for
383d48c1adaSCezary Rojewski 	 * topologies describing single device e.g.: an I2S codec on SSP0.
384d48c1adaSCezary Rojewski 	 */
38525b552f1SPiotr Maziarz 	if (hweight_long(mach->mach_params.i2s_link_mask) != 1)
386d48c1adaSCezary Rojewski 		return avs_parse_string_token(comp, elem, object, offset);
387d48c1adaSCezary Rojewski 
388d48c1adaSCezary Rojewski 	snprintf(val, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, tuple->string,
38925b552f1SPiotr Maziarz 		 __ffs(mach->mach_params.i2s_link_mask));
390d48c1adaSCezary Rojewski 
391d48c1adaSCezary Rojewski 	return 0;
392d48c1adaSCezary Rojewski }
393d48c1adaSCezary Rojewski 
39434ae2cd5SCezary Rojewski static int
parse_dictionary_header(struct snd_soc_component * comp,struct snd_soc_tplg_vendor_array * tuples,void ** dict,u32 * num_entries,size_t entry_size,u32 num_entries_token)39534ae2cd5SCezary Rojewski parse_dictionary_header(struct snd_soc_component *comp,
39634ae2cd5SCezary Rojewski 			struct snd_soc_tplg_vendor_array *tuples,
39734ae2cd5SCezary Rojewski 			void **dict, u32 *num_entries, size_t entry_size,
39834ae2cd5SCezary Rojewski 			u32 num_entries_token)
39934ae2cd5SCezary Rojewski {
40034ae2cd5SCezary Rojewski 	struct snd_soc_tplg_vendor_value_elem *tuple;
40134ae2cd5SCezary Rojewski 
40234ae2cd5SCezary Rojewski 	/* Dictionary header consists of single tuple - entry count. */
40334ae2cd5SCezary Rojewski 	tuple = tuples->value;
40434ae2cd5SCezary Rojewski 	if (le32_to_cpu(tuple->token) != num_entries_token) {
40534ae2cd5SCezary Rojewski 		dev_err(comp->dev, "invalid dictionary header, expected: %d\n",
40634ae2cd5SCezary Rojewski 			num_entries_token);
40734ae2cd5SCezary Rojewski 		return -EINVAL;
40834ae2cd5SCezary Rojewski 	}
40934ae2cd5SCezary Rojewski 
41034ae2cd5SCezary Rojewski 	*num_entries = le32_to_cpu(tuple->value);
41134ae2cd5SCezary Rojewski 	*dict = devm_kcalloc(comp->card->dev, *num_entries, entry_size, GFP_KERNEL);
41234ae2cd5SCezary Rojewski 	if (!*dict)
41334ae2cd5SCezary Rojewski 		return -ENOMEM;
41434ae2cd5SCezary Rojewski 
41534ae2cd5SCezary Rojewski 	return 0;
41634ae2cd5SCezary Rojewski }
41734ae2cd5SCezary Rojewski 
41834ae2cd5SCezary Rojewski static int
parse_dictionary_entries(struct snd_soc_component * comp,struct snd_soc_tplg_vendor_array * tuples,u32 block_size,void * dict,u32 num_entries,size_t entry_size,u32 entry_id_token,const struct avs_tplg_token_parser * parsers,size_t num_parsers)41934ae2cd5SCezary Rojewski parse_dictionary_entries(struct snd_soc_component *comp,
42034ae2cd5SCezary Rojewski 			 struct snd_soc_tplg_vendor_array *tuples, u32 block_size,
42134ae2cd5SCezary Rojewski 			 void *dict, u32 num_entries, size_t entry_size,
42234ae2cd5SCezary Rojewski 			 u32 entry_id_token,
42334ae2cd5SCezary Rojewski 			 const struct avs_tplg_token_parser *parsers, size_t num_parsers)
42434ae2cd5SCezary Rojewski {
42534ae2cd5SCezary Rojewski 	void *pos = dict;
42634ae2cd5SCezary Rojewski 	int i;
42734ae2cd5SCezary Rojewski 
42834ae2cd5SCezary Rojewski 	for (i = 0; i < num_entries; i++) {
42934ae2cd5SCezary Rojewski 		u32 esize;
43034ae2cd5SCezary Rojewski 		int ret;
43134ae2cd5SCezary Rojewski 
43234ae2cd5SCezary Rojewski 		ret = avs_tplg_vendor_entry_size(tuples, block_size,
43334ae2cd5SCezary Rojewski 						 entry_id_token, &esize);
43434ae2cd5SCezary Rojewski 		if (ret)
43534ae2cd5SCezary Rojewski 			return ret;
43634ae2cd5SCezary Rojewski 
43734ae2cd5SCezary Rojewski 		ret = avs_parse_tokens(comp, pos, parsers, num_parsers, tuples, esize);
43834ae2cd5SCezary Rojewski 		if (ret < 0) {
43934ae2cd5SCezary Rojewski 			dev_err(comp->dev, "parse entry: %d of type: %d failed: %d\n",
44034ae2cd5SCezary Rojewski 				i, entry_id_token, ret);
44134ae2cd5SCezary Rojewski 			return ret;
44234ae2cd5SCezary Rojewski 		}
44334ae2cd5SCezary Rojewski 
44434ae2cd5SCezary Rojewski 		pos += entry_size;
44534ae2cd5SCezary Rojewski 		block_size -= esize;
44634ae2cd5SCezary Rojewski 		tuples = avs_tplg_vendor_array_at(tuples, esize);
44734ae2cd5SCezary Rojewski 	}
44834ae2cd5SCezary Rojewski 
44934ae2cd5SCezary Rojewski 	return 0;
45034ae2cd5SCezary Rojewski }
45134ae2cd5SCezary Rojewski 
parse_dictionary(struct snd_soc_component * comp,struct snd_soc_tplg_vendor_array * tuples,u32 block_size,void ** dict,u32 * num_entries,size_t entry_size,u32 num_entries_token,u32 entry_id_token,const struct avs_tplg_token_parser * parsers,size_t num_parsers)45234ae2cd5SCezary Rojewski static int parse_dictionary(struct snd_soc_component *comp,
45334ae2cd5SCezary Rojewski 			    struct snd_soc_tplg_vendor_array *tuples, u32 block_size,
45434ae2cd5SCezary Rojewski 			    void **dict, u32 *num_entries, size_t entry_size,
45534ae2cd5SCezary Rojewski 			    u32 num_entries_token, u32 entry_id_token,
45634ae2cd5SCezary Rojewski 			    const struct avs_tplg_token_parser *parsers, size_t num_parsers)
45734ae2cd5SCezary Rojewski {
45834ae2cd5SCezary Rojewski 	int ret;
45934ae2cd5SCezary Rojewski 
46034ae2cd5SCezary Rojewski 	ret = parse_dictionary_header(comp, tuples, dict, num_entries,
46134ae2cd5SCezary Rojewski 				      entry_size, num_entries_token);
46234ae2cd5SCezary Rojewski 	if (ret)
46334ae2cd5SCezary Rojewski 		return ret;
46434ae2cd5SCezary Rojewski 
46534ae2cd5SCezary Rojewski 	block_size -= le32_to_cpu(tuples->size);
46634ae2cd5SCezary Rojewski 	/* With header parsed, move on to parsing entries. */
46734ae2cd5SCezary Rojewski 	tuples = avs_tplg_vendor_array_next(tuples);
46834ae2cd5SCezary Rojewski 
46934ae2cd5SCezary Rojewski 	return parse_dictionary_entries(comp, tuples, block_size, *dict,
47034ae2cd5SCezary Rojewski 					*num_entries, entry_size,
47134ae2cd5SCezary Rojewski 					entry_id_token, parsers, num_parsers);
47234ae2cd5SCezary Rojewski }
47334ae2cd5SCezary Rojewski 
47434ae2cd5SCezary Rojewski static const struct avs_tplg_token_parser library_parsers[] = {
47534ae2cd5SCezary Rojewski 	{
47634ae2cd5SCezary Rojewski 		.token = AVS_TKN_LIBRARY_NAME_STRING,
47734ae2cd5SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_STRING,
47834ae2cd5SCezary Rojewski 		.offset = offsetof(struct avs_tplg_library, name),
47934ae2cd5SCezary Rojewski 		.parse = avs_parse_string_token,
48034ae2cd5SCezary Rojewski 	},
48134ae2cd5SCezary Rojewski };
48234ae2cd5SCezary Rojewski 
avs_tplg_parse_libraries(struct snd_soc_component * comp,struct snd_soc_tplg_vendor_array * tuples,u32 block_size)48334ae2cd5SCezary Rojewski static int avs_tplg_parse_libraries(struct snd_soc_component *comp,
48434ae2cd5SCezary Rojewski 				    struct snd_soc_tplg_vendor_array *tuples, u32 block_size)
48534ae2cd5SCezary Rojewski {
48634ae2cd5SCezary Rojewski 	struct avs_soc_component *acomp = to_avs_soc_component(comp);
48734ae2cd5SCezary Rojewski 	struct avs_tplg *tplg = acomp->tplg;
48834ae2cd5SCezary Rojewski 
48934ae2cd5SCezary Rojewski 	return parse_dictionary(comp, tuples, block_size, (void **)&tplg->libs,
49034ae2cd5SCezary Rojewski 				&tplg->num_libs, sizeof(*tplg->libs),
49134ae2cd5SCezary Rojewski 				AVS_TKN_MANIFEST_NUM_LIBRARIES_U32,
49234ae2cd5SCezary Rojewski 				AVS_TKN_LIBRARY_ID_U32,
49334ae2cd5SCezary Rojewski 				library_parsers, ARRAY_SIZE(library_parsers));
49434ae2cd5SCezary Rojewski }
49534ae2cd5SCezary Rojewski 
49634ae2cd5SCezary Rojewski static const struct avs_tplg_token_parser audio_format_parsers[] = {
49734ae2cd5SCezary Rojewski 	{
49834ae2cd5SCezary Rojewski 		.token = AVS_TKN_AFMT_SAMPLE_RATE_U32,
49934ae2cd5SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
50034ae2cd5SCezary Rojewski 		.offset = offsetof(struct avs_audio_format, sampling_freq),
50134ae2cd5SCezary Rojewski 		.parse = avs_parse_word_token,
50234ae2cd5SCezary Rojewski 	},
50334ae2cd5SCezary Rojewski 	{
50434ae2cd5SCezary Rojewski 		.token = AVS_TKN_AFMT_BIT_DEPTH_U32,
50534ae2cd5SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
50634ae2cd5SCezary Rojewski 		.offset = offsetof(struct avs_audio_format, bit_depth),
50734ae2cd5SCezary Rojewski 		.parse = avs_parse_word_token,
50834ae2cd5SCezary Rojewski 	},
50934ae2cd5SCezary Rojewski 	{
51034ae2cd5SCezary Rojewski 		.token = AVS_TKN_AFMT_CHANNEL_MAP_U32,
51134ae2cd5SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
51234ae2cd5SCezary Rojewski 		.offset = offsetof(struct avs_audio_format, channel_map),
51334ae2cd5SCezary Rojewski 		.parse = avs_parse_word_token,
51434ae2cd5SCezary Rojewski 	},
51534ae2cd5SCezary Rojewski 	{
51634ae2cd5SCezary Rojewski 		.token = AVS_TKN_AFMT_CHANNEL_CFG_U32,
51734ae2cd5SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
51834ae2cd5SCezary Rojewski 		.offset = offsetof(struct avs_audio_format, channel_config),
51934ae2cd5SCezary Rojewski 		.parse = avs_parse_word_token,
52034ae2cd5SCezary Rojewski 	},
52134ae2cd5SCezary Rojewski 	{
52234ae2cd5SCezary Rojewski 		.token = AVS_TKN_AFMT_INTERLEAVING_U32,
52334ae2cd5SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
52434ae2cd5SCezary Rojewski 		.offset = offsetof(struct avs_audio_format, interleaving),
52534ae2cd5SCezary Rojewski 		.parse = avs_parse_word_token,
52634ae2cd5SCezary Rojewski 	},
52734ae2cd5SCezary Rojewski 	{
52834ae2cd5SCezary Rojewski 		.token = AVS_TKN_AFMT_NUM_CHANNELS_U32,
52934ae2cd5SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
53034ae2cd5SCezary Rojewski 		.offset = AVS_TKN_AFMT_NUM_CHANNELS_U32,
53134ae2cd5SCezary Rojewski 		.parse = parse_audio_format_bitfield,
53234ae2cd5SCezary Rojewski 	},
53334ae2cd5SCezary Rojewski 	{
53434ae2cd5SCezary Rojewski 		.token = AVS_TKN_AFMT_VALID_BIT_DEPTH_U32,
53534ae2cd5SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
53634ae2cd5SCezary Rojewski 		.offset = AVS_TKN_AFMT_VALID_BIT_DEPTH_U32,
53734ae2cd5SCezary Rojewski 		.parse = parse_audio_format_bitfield,
53834ae2cd5SCezary Rojewski 	},
53934ae2cd5SCezary Rojewski 	{
54034ae2cd5SCezary Rojewski 		.token = AVS_TKN_AFMT_SAMPLE_TYPE_U32,
54134ae2cd5SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
54234ae2cd5SCezary Rojewski 		.offset = AVS_TKN_AFMT_SAMPLE_TYPE_U32,
54334ae2cd5SCezary Rojewski 		.parse = parse_audio_format_bitfield,
54434ae2cd5SCezary Rojewski 	},
54534ae2cd5SCezary Rojewski };
54634ae2cd5SCezary Rojewski 
avs_tplg_parse_audio_formats(struct snd_soc_component * comp,struct snd_soc_tplg_vendor_array * tuples,u32 block_size)54734ae2cd5SCezary Rojewski static int avs_tplg_parse_audio_formats(struct snd_soc_component *comp,
54834ae2cd5SCezary Rojewski 					struct snd_soc_tplg_vendor_array *tuples,
54934ae2cd5SCezary Rojewski 					u32 block_size)
55034ae2cd5SCezary Rojewski {
55134ae2cd5SCezary Rojewski 	struct avs_soc_component *acomp = to_avs_soc_component(comp);
55234ae2cd5SCezary Rojewski 	struct avs_tplg *tplg = acomp->tplg;
55334ae2cd5SCezary Rojewski 
55434ae2cd5SCezary Rojewski 	return parse_dictionary(comp, tuples, block_size, (void **)&tplg->fmts,
55534ae2cd5SCezary Rojewski 				&tplg->num_fmts, sizeof(*tplg->fmts),
55634ae2cd5SCezary Rojewski 				AVS_TKN_MANIFEST_NUM_AFMTS_U32,
55734ae2cd5SCezary Rojewski 				AVS_TKN_AFMT_ID_U32,
55834ae2cd5SCezary Rojewski 				audio_format_parsers, ARRAY_SIZE(audio_format_parsers));
55934ae2cd5SCezary Rojewski }
56034ae2cd5SCezary Rojewski 
56134ae2cd5SCezary Rojewski static const struct avs_tplg_token_parser modcfg_base_parsers[] = {
56234ae2cd5SCezary Rojewski 	{
56334ae2cd5SCezary Rojewski 		.token = AVS_TKN_MODCFG_BASE_CPC_U32,
56434ae2cd5SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
56534ae2cd5SCezary Rojewski 		.offset = offsetof(struct avs_tplg_modcfg_base, cpc),
56634ae2cd5SCezary Rojewski 		.parse = avs_parse_word_token,
56734ae2cd5SCezary Rojewski 	},
56834ae2cd5SCezary Rojewski 	{
56934ae2cd5SCezary Rojewski 		.token = AVS_TKN_MODCFG_BASE_IBS_U32,
57034ae2cd5SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
57134ae2cd5SCezary Rojewski 		.offset = offsetof(struct avs_tplg_modcfg_base, ibs),
57234ae2cd5SCezary Rojewski 		.parse = avs_parse_word_token,
57334ae2cd5SCezary Rojewski 	},
57434ae2cd5SCezary Rojewski 	{
57534ae2cd5SCezary Rojewski 		.token = AVS_TKN_MODCFG_BASE_OBS_U32,
57634ae2cd5SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
57734ae2cd5SCezary Rojewski 		.offset = offsetof(struct avs_tplg_modcfg_base, obs),
57834ae2cd5SCezary Rojewski 		.parse = avs_parse_word_token,
57934ae2cd5SCezary Rojewski 	},
58034ae2cd5SCezary Rojewski 	{
58134ae2cd5SCezary Rojewski 		.token = AVS_TKN_MODCFG_BASE_PAGES_U32,
58234ae2cd5SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
58334ae2cd5SCezary Rojewski 		.offset = offsetof(struct avs_tplg_modcfg_base, is_pages),
58434ae2cd5SCezary Rojewski 		.parse = avs_parse_word_token,
58534ae2cd5SCezary Rojewski 	},
58634ae2cd5SCezary Rojewski };
58734ae2cd5SCezary Rojewski 
avs_tplg_parse_modcfgs_base(struct snd_soc_component * comp,struct snd_soc_tplg_vendor_array * tuples,u32 block_size)58834ae2cd5SCezary Rojewski static int avs_tplg_parse_modcfgs_base(struct snd_soc_component *comp,
58934ae2cd5SCezary Rojewski 				       struct snd_soc_tplg_vendor_array *tuples,
59034ae2cd5SCezary Rojewski 				       u32 block_size)
59134ae2cd5SCezary Rojewski {
59234ae2cd5SCezary Rojewski 	struct avs_soc_component *acomp = to_avs_soc_component(comp);
59334ae2cd5SCezary Rojewski 	struct avs_tplg *tplg = acomp->tplg;
59434ae2cd5SCezary Rojewski 
59534ae2cd5SCezary Rojewski 	return parse_dictionary(comp, tuples, block_size, (void **)&tplg->modcfgs_base,
59634ae2cd5SCezary Rojewski 				&tplg->num_modcfgs_base, sizeof(*tplg->modcfgs_base),
59734ae2cd5SCezary Rojewski 				AVS_TKN_MANIFEST_NUM_MODCFGS_BASE_U32,
59834ae2cd5SCezary Rojewski 				AVS_TKN_MODCFG_BASE_ID_U32,
59934ae2cd5SCezary Rojewski 				modcfg_base_parsers, ARRAY_SIZE(modcfg_base_parsers));
60034ae2cd5SCezary Rojewski }
6019e85ec40SCezary Rojewski 
6029e85ec40SCezary Rojewski static const struct avs_tplg_token_parser modcfg_ext_parsers[] = {
6039e85ec40SCezary Rojewski 	{
6049e85ec40SCezary Rojewski 		.token = AVS_TKN_MODCFG_EXT_TYPE_UUID,
6059e85ec40SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_UUID,
6069e85ec40SCezary Rojewski 		.offset = offsetof(struct avs_tplg_modcfg_ext, type),
6079e85ec40SCezary Rojewski 		.parse = avs_parse_uuid_token,
6089e85ec40SCezary Rojewski 	},
6099e85ec40SCezary Rojewski 	{
6109e85ec40SCezary Rojewski 		.token = AVS_TKN_MODCFG_CPR_OUT_AFMT_ID_U32,
6119e85ec40SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
6129e85ec40SCezary Rojewski 		.offset = offsetof(struct avs_tplg_modcfg_ext, copier.out_fmt),
6139e85ec40SCezary Rojewski 		.parse = avs_parse_audio_format_ptr,
6149e85ec40SCezary Rojewski 	},
6159e85ec40SCezary Rojewski 	{
6169e85ec40SCezary Rojewski 		.token = AVS_TKN_MODCFG_CPR_FEATURE_MASK_U32,
6179e85ec40SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
6189e85ec40SCezary Rojewski 		.offset = offsetof(struct avs_tplg_modcfg_ext, copier.feature_mask),
6199e85ec40SCezary Rojewski 		.parse = avs_parse_word_token,
6209e85ec40SCezary Rojewski 	},
6219e85ec40SCezary Rojewski 	{
6229e85ec40SCezary Rojewski 		.token = AVS_TKN_MODCFG_CPR_VINDEX_U8,
6239e85ec40SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_BYTE,
6249e85ec40SCezary Rojewski 		.offset = offsetof(struct avs_tplg_modcfg_ext, copier.vindex),
6259e85ec40SCezary Rojewski 		.parse = avs_parse_byte_token,
6269e85ec40SCezary Rojewski 	},
6279e85ec40SCezary Rojewski 	{
6289e85ec40SCezary Rojewski 		.token = AVS_TKN_MODCFG_CPR_DMA_TYPE_U32,
6299e85ec40SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
6309e85ec40SCezary Rojewski 		.offset = offsetof(struct avs_tplg_modcfg_ext, copier.dma_type),
6319e85ec40SCezary Rojewski 		.parse = avs_parse_word_token,
6329e85ec40SCezary Rojewski 	},
6339e85ec40SCezary Rojewski 	{
6349e85ec40SCezary Rojewski 		.token = AVS_TKN_MODCFG_CPR_DMABUFF_SIZE_U32,
6359e85ec40SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
6369e85ec40SCezary Rojewski 		.offset = offsetof(struct avs_tplg_modcfg_ext, copier.dma_buffer_size),
6379e85ec40SCezary Rojewski 		.parse = avs_parse_word_token,
6389e85ec40SCezary Rojewski 	},
6399e85ec40SCezary Rojewski 	{
6409e85ec40SCezary Rojewski 		.token = AVS_TKN_MODCFG_CPR_BLOB_FMT_ID_U32,
6419e85ec40SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
6429e85ec40SCezary Rojewski 		.offset = offsetof(struct avs_tplg_modcfg_ext, copier.blob_fmt),
6439e85ec40SCezary Rojewski 		.parse = avs_parse_audio_format_ptr,
6449e85ec40SCezary Rojewski 	},
6459e85ec40SCezary Rojewski 	{
6469e85ec40SCezary Rojewski 		.token = AVS_TKN_MODCFG_MICSEL_OUT_AFMT_ID_U32,
6479e85ec40SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
6489e85ec40SCezary Rojewski 		.offset = offsetof(struct avs_tplg_modcfg_ext, micsel.out_fmt),
6499e85ec40SCezary Rojewski 		.parse = avs_parse_audio_format_ptr,
6509e85ec40SCezary Rojewski 	},
6519e85ec40SCezary Rojewski 	{
6529e85ec40SCezary Rojewski 		.token = AVS_TKN_MODCFG_INTELWOV_CPC_LP_MODE_U32,
6539e85ec40SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
6549e85ec40SCezary Rojewski 		.offset = offsetof(struct avs_tplg_modcfg_ext, wov.cpc_lp_mode),
6559e85ec40SCezary Rojewski 		.parse = avs_parse_word_token,
6569e85ec40SCezary Rojewski 	},
6579e85ec40SCezary Rojewski 	{
6589e85ec40SCezary Rojewski 		.token = AVS_TKN_MODCFG_SRC_OUT_FREQ_U32,
6599e85ec40SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
6609e85ec40SCezary Rojewski 		.offset = offsetof(struct avs_tplg_modcfg_ext, src.out_freq),
6619e85ec40SCezary Rojewski 		.parse = avs_parse_word_token,
6629e85ec40SCezary Rojewski 	},
6639e85ec40SCezary Rojewski 	{
6649e85ec40SCezary Rojewski 		.token = AVS_TKN_MODCFG_MUX_REF_AFMT_ID_U32,
6659e85ec40SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
6669e85ec40SCezary Rojewski 		.offset = offsetof(struct avs_tplg_modcfg_ext, mux.ref_fmt),
6679e85ec40SCezary Rojewski 		.parse = avs_parse_audio_format_ptr,
6689e85ec40SCezary Rojewski 	},
6699e85ec40SCezary Rojewski 	{
6709e85ec40SCezary Rojewski 		.token = AVS_TKN_MODCFG_MUX_OUT_AFMT_ID_U32,
6719e85ec40SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
6729e85ec40SCezary Rojewski 		.offset = offsetof(struct avs_tplg_modcfg_ext, mux.out_fmt),
6739e85ec40SCezary Rojewski 		.parse = avs_parse_audio_format_ptr,
6749e85ec40SCezary Rojewski 	},
6759e85ec40SCezary Rojewski 	{
6769e85ec40SCezary Rojewski 		.token = AVS_TKN_MODCFG_AEC_REF_AFMT_ID_U32,
6779e85ec40SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
6789e85ec40SCezary Rojewski 		.offset = offsetof(struct avs_tplg_modcfg_ext, aec.ref_fmt),
6799e85ec40SCezary Rojewski 		.parse = avs_parse_audio_format_ptr,
6809e85ec40SCezary Rojewski 	},
6819e85ec40SCezary Rojewski 	{
6829e85ec40SCezary Rojewski 		.token = AVS_TKN_MODCFG_AEC_OUT_AFMT_ID_U32,
6839e85ec40SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
6849e85ec40SCezary Rojewski 		.offset = offsetof(struct avs_tplg_modcfg_ext, aec.out_fmt),
6859e85ec40SCezary Rojewski 		.parse = avs_parse_audio_format_ptr,
6869e85ec40SCezary Rojewski 	},
6879e85ec40SCezary Rojewski 	{
6889e85ec40SCezary Rojewski 		.token = AVS_TKN_MODCFG_AEC_CPC_LP_MODE_U32,
6899e85ec40SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
6909e85ec40SCezary Rojewski 		.offset = offsetof(struct avs_tplg_modcfg_ext, aec.cpc_lp_mode),
6919e85ec40SCezary Rojewski 		.parse = avs_parse_word_token,
6929e85ec40SCezary Rojewski 	},
6939e85ec40SCezary Rojewski 	{
6949e85ec40SCezary Rojewski 		.token = AVS_TKN_MODCFG_ASRC_OUT_FREQ_U32,
6959e85ec40SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
6969e85ec40SCezary Rojewski 		.offset = offsetof(struct avs_tplg_modcfg_ext, asrc.out_freq),
6979e85ec40SCezary Rojewski 		.parse = avs_parse_word_token,
6989e85ec40SCezary Rojewski 	},
6999e85ec40SCezary Rojewski 	{
7009e85ec40SCezary Rojewski 		.token = AVS_TKN_MODCFG_ASRC_MODE_U8,
7019e85ec40SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_BYTE,
7029e85ec40SCezary Rojewski 		.offset = offsetof(struct avs_tplg_modcfg_ext, asrc.mode),
7039e85ec40SCezary Rojewski 		.parse = avs_parse_byte_token,
7049e85ec40SCezary Rojewski 	},
7059e85ec40SCezary Rojewski 	{
7069e85ec40SCezary Rojewski 		.token = AVS_TKN_MODCFG_ASRC_DISABLE_JITTER_U8,
7079e85ec40SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_BYTE,
7089e85ec40SCezary Rojewski 		.offset = offsetof(struct avs_tplg_modcfg_ext, asrc.disable_jitter_buffer),
7099e85ec40SCezary Rojewski 		.parse = avs_parse_byte_token,
7109e85ec40SCezary Rojewski 	},
7119e85ec40SCezary Rojewski 	{
7129e85ec40SCezary Rojewski 		.token = AVS_TKN_MODCFG_UPDOWN_MIX_OUT_CHAN_CFG_U32,
7139e85ec40SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
7149e85ec40SCezary Rojewski 		.offset = offsetof(struct avs_tplg_modcfg_ext, updown_mix.out_channel_config),
7159e85ec40SCezary Rojewski 		.parse = avs_parse_word_token,
7169e85ec40SCezary Rojewski 	},
7179e85ec40SCezary Rojewski 	{
7189e85ec40SCezary Rojewski 		.token = AVS_TKN_MODCFG_UPDOWN_MIX_COEFF_SELECT_U32,
7199e85ec40SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
7209e85ec40SCezary Rojewski 		.offset = offsetof(struct avs_tplg_modcfg_ext, updown_mix.coefficients_select),
7219e85ec40SCezary Rojewski 		.parse = avs_parse_word_token,
7229e85ec40SCezary Rojewski 	},
7239e85ec40SCezary Rojewski 	{
7249e85ec40SCezary Rojewski 		.token = AVS_TKN_MODCFG_UPDOWN_MIX_COEFF_0_S32,
7259e85ec40SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
7269e85ec40SCezary Rojewski 		.offset = offsetof(struct avs_tplg_modcfg_ext, updown_mix.coefficients[0]),
7279e85ec40SCezary Rojewski 		.parse = avs_parse_word_token,
7289e85ec40SCezary Rojewski 	},
7299e85ec40SCezary Rojewski 	{
7309e85ec40SCezary Rojewski 		.token = AVS_TKN_MODCFG_UPDOWN_MIX_COEFF_1_S32,
7319e85ec40SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
7329e85ec40SCezary Rojewski 		.offset = offsetof(struct avs_tplg_modcfg_ext, updown_mix.coefficients[1]),
7339e85ec40SCezary Rojewski 		.parse = avs_parse_word_token,
7349e85ec40SCezary Rojewski 	},
7359e85ec40SCezary Rojewski 	{
7369e85ec40SCezary Rojewski 		.token = AVS_TKN_MODCFG_UPDOWN_MIX_COEFF_2_S32,
7379e85ec40SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
7389e85ec40SCezary Rojewski 		.offset = offsetof(struct avs_tplg_modcfg_ext, updown_mix.coefficients[2]),
7399e85ec40SCezary Rojewski 		.parse = avs_parse_word_token,
7409e85ec40SCezary Rojewski 	},
7419e85ec40SCezary Rojewski 	{
7429e85ec40SCezary Rojewski 		.token = AVS_TKN_MODCFG_UPDOWN_MIX_COEFF_3_S32,
7439e85ec40SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
7449e85ec40SCezary Rojewski 		.offset = offsetof(struct avs_tplg_modcfg_ext, updown_mix.coefficients[3]),
7459e85ec40SCezary Rojewski 		.parse = avs_parse_word_token,
7469e85ec40SCezary Rojewski 	},
7479e85ec40SCezary Rojewski 	{
7489e85ec40SCezary Rojewski 		.token = AVS_TKN_MODCFG_UPDOWN_MIX_COEFF_4_S32,
7499e85ec40SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
7509e85ec40SCezary Rojewski 		.offset = offsetof(struct avs_tplg_modcfg_ext, updown_mix.coefficients[4]),
7519e85ec40SCezary Rojewski 		.parse = avs_parse_word_token,
7529e85ec40SCezary Rojewski 	},
7539e85ec40SCezary Rojewski 	{
7549e85ec40SCezary Rojewski 		.token = AVS_TKN_MODCFG_UPDOWN_MIX_COEFF_5_S32,
7559e85ec40SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
7569e85ec40SCezary Rojewski 		.offset = offsetof(struct avs_tplg_modcfg_ext, updown_mix.coefficients[5]),
7579e85ec40SCezary Rojewski 		.parse = avs_parse_word_token,
7589e85ec40SCezary Rojewski 	},
7599e85ec40SCezary Rojewski 	{
7609e85ec40SCezary Rojewski 		.token = AVS_TKN_MODCFG_UPDOWN_MIX_COEFF_6_S32,
7619e85ec40SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
7629e85ec40SCezary Rojewski 		.offset = offsetof(struct avs_tplg_modcfg_ext, updown_mix.coefficients[6]),
7639e85ec40SCezary Rojewski 		.parse = avs_parse_word_token,
7649e85ec40SCezary Rojewski 	},
7659e85ec40SCezary Rojewski 	{
7669e85ec40SCezary Rojewski 		.token = AVS_TKN_MODCFG_UPDOWN_MIX_COEFF_7_S32,
7679e85ec40SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
7689e85ec40SCezary Rojewski 		.offset = offsetof(struct avs_tplg_modcfg_ext, updown_mix.coefficients[7]),
7699e85ec40SCezary Rojewski 		.parse = avs_parse_word_token,
7709e85ec40SCezary Rojewski 	},
7719e85ec40SCezary Rojewski 	{
7729e85ec40SCezary Rojewski 		.token = AVS_TKN_MODCFG_UPDOWN_MIX_CHAN_MAP_U32,
7739e85ec40SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
7749e85ec40SCezary Rojewski 		.offset = offsetof(struct avs_tplg_modcfg_ext, updown_mix.channel_map),
7759e85ec40SCezary Rojewski 		.parse = avs_parse_word_token,
7769e85ec40SCezary Rojewski 	},
7779e85ec40SCezary Rojewski 	{
7789e85ec40SCezary Rojewski 		.token = AVS_TKN_MODCFG_EXT_NUM_INPUT_PINS_U16,
7799e85ec40SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_SHORT,
7809e85ec40SCezary Rojewski 		.offset = offsetof(struct avs_tplg_modcfg_ext, generic.num_input_pins),
7819e85ec40SCezary Rojewski 		.parse = avs_parse_short_token,
7829e85ec40SCezary Rojewski 	},
7839e85ec40SCezary Rojewski 	{
7849e85ec40SCezary Rojewski 		.token = AVS_TKN_MODCFG_EXT_NUM_OUTPUT_PINS_U16,
7859e85ec40SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_SHORT,
7869e85ec40SCezary Rojewski 		.offset = offsetof(struct avs_tplg_modcfg_ext, generic.num_output_pins),
7879e85ec40SCezary Rojewski 		.parse = avs_parse_short_token,
7889e85ec40SCezary Rojewski 	},
7899e85ec40SCezary Rojewski };
7909e85ec40SCezary Rojewski 
7919e85ec40SCezary Rojewski static const struct avs_tplg_token_parser pin_format_parsers[] = {
7929e85ec40SCezary Rojewski 	{
7939e85ec40SCezary Rojewski 		.token = AVS_TKN_PIN_FMT_INDEX_U32,
7949e85ec40SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
7959e85ec40SCezary Rojewski 		.offset = offsetof(struct avs_tplg_pin_format, pin_index),
7969e85ec40SCezary Rojewski 		.parse = avs_parse_word_token,
7979e85ec40SCezary Rojewski 	},
7989e85ec40SCezary Rojewski 	{
7999e85ec40SCezary Rojewski 		.token = AVS_TKN_PIN_FMT_IOBS_U32,
8009e85ec40SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
8019e85ec40SCezary Rojewski 		.offset = offsetof(struct avs_tplg_pin_format, iobs),
8029e85ec40SCezary Rojewski 		.parse = avs_parse_word_token,
8039e85ec40SCezary Rojewski 	},
8049e85ec40SCezary Rojewski 	{
8059e85ec40SCezary Rojewski 		.token = AVS_TKN_PIN_FMT_AFMT_ID_U32,
8069e85ec40SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
8079e85ec40SCezary Rojewski 		.offset = offsetof(struct avs_tplg_pin_format, fmt),
8089e85ec40SCezary Rojewski 		.parse = avs_parse_audio_format_ptr,
8099e85ec40SCezary Rojewski 	},
8109e85ec40SCezary Rojewski };
8119e85ec40SCezary Rojewski 
8125f267aa4SCezary Rojewski static void
assign_copier_gtw_instance(struct snd_soc_component * comp,struct avs_tplg_modcfg_ext * cfg)8135f267aa4SCezary Rojewski assign_copier_gtw_instance(struct snd_soc_component *comp, struct avs_tplg_modcfg_ext *cfg)
8145f267aa4SCezary Rojewski {
8155f267aa4SCezary Rojewski 	struct snd_soc_acpi_mach *mach;
8165f267aa4SCezary Rojewski 
8175f267aa4SCezary Rojewski 	if (!guid_equal(&cfg->type, &AVS_COPIER_MOD_UUID))
8185f267aa4SCezary Rojewski 		return;
8195f267aa4SCezary Rojewski 
8205f267aa4SCezary Rojewski 	/* Only I2S boards assign port instance in ->i2s_link_mask. */
8215f267aa4SCezary Rojewski 	switch (cfg->copier.dma_type) {
8225f267aa4SCezary Rojewski 	case AVS_DMA_I2S_LINK_OUTPUT:
8235f267aa4SCezary Rojewski 	case AVS_DMA_I2S_LINK_INPUT:
8245f267aa4SCezary Rojewski 		break;
8255f267aa4SCezary Rojewski 	default:
8265f267aa4SCezary Rojewski 		return;
8275f267aa4SCezary Rojewski 	}
8285f267aa4SCezary Rojewski 
8295f267aa4SCezary Rojewski 	mach = dev_get_platdata(comp->card->dev);
8305f267aa4SCezary Rojewski 
8315f267aa4SCezary Rojewski 	/* Automatic assignment only when board describes single SSP. */
8325f267aa4SCezary Rojewski 	if (hweight_long(mach->mach_params.i2s_link_mask) == 1 && !cfg->copier.vindex.i2s.instance)
8335f267aa4SCezary Rojewski 		cfg->copier.vindex.i2s.instance = __ffs(mach->mach_params.i2s_link_mask);
8345f267aa4SCezary Rojewski }
8355f267aa4SCezary Rojewski 
avs_tplg_parse_modcfg_ext(struct snd_soc_component * comp,struct avs_tplg_modcfg_ext * cfg,struct snd_soc_tplg_vendor_array * tuples,u32 block_size)8369e85ec40SCezary Rojewski static int avs_tplg_parse_modcfg_ext(struct snd_soc_component *comp,
8379e85ec40SCezary Rojewski 				     struct avs_tplg_modcfg_ext *cfg,
8389e85ec40SCezary Rojewski 				     struct snd_soc_tplg_vendor_array *tuples,
8399e85ec40SCezary Rojewski 				     u32 block_size)
8409e85ec40SCezary Rojewski {
8419e85ec40SCezary Rojewski 	u32 esize;
8429e85ec40SCezary Rojewski 	int ret;
8439e85ec40SCezary Rojewski 
8449e85ec40SCezary Rojewski 	/* See where pin block starts. */
8459e85ec40SCezary Rojewski 	ret = avs_tplg_vendor_entry_size(tuples, block_size,
8469e85ec40SCezary Rojewski 					 AVS_TKN_PIN_FMT_INDEX_U32, &esize);
8479e85ec40SCezary Rojewski 	if (ret)
8489e85ec40SCezary Rojewski 		return ret;
8499e85ec40SCezary Rojewski 
8509e85ec40SCezary Rojewski 	ret = avs_parse_tokens(comp, cfg, modcfg_ext_parsers,
8519e85ec40SCezary Rojewski 			       ARRAY_SIZE(modcfg_ext_parsers), tuples, esize);
8529e85ec40SCezary Rojewski 	if (ret)
8539e85ec40SCezary Rojewski 		return ret;
8549e85ec40SCezary Rojewski 
8555f267aa4SCezary Rojewski 	/* Update copier gateway based on board's i2s_link_mask. */
8565f267aa4SCezary Rojewski 	assign_copier_gtw_instance(comp, cfg);
8575f267aa4SCezary Rojewski 
8589e85ec40SCezary Rojewski 	block_size -= esize;
8599e85ec40SCezary Rojewski 	/* Parse trailing in/out pin formats if any. */
8609e85ec40SCezary Rojewski 	if (block_size) {
8619e85ec40SCezary Rojewski 		struct avs_tplg_pin_format *pins;
8629e85ec40SCezary Rojewski 		u32 num_pins;
8639e85ec40SCezary Rojewski 
8649e85ec40SCezary Rojewski 		num_pins = cfg->generic.num_input_pins + cfg->generic.num_output_pins;
8659e85ec40SCezary Rojewski 		if (!num_pins)
8669e85ec40SCezary Rojewski 			return -EINVAL;
8679e85ec40SCezary Rojewski 
8689e85ec40SCezary Rojewski 		pins = devm_kcalloc(comp->card->dev, num_pins, sizeof(*pins), GFP_KERNEL);
8699e85ec40SCezary Rojewski 		if (!pins)
8709e85ec40SCezary Rojewski 			return -ENOMEM;
8719e85ec40SCezary Rojewski 
8729e85ec40SCezary Rojewski 		tuples = avs_tplg_vendor_array_at(tuples, esize);
8739e85ec40SCezary Rojewski 		ret = parse_dictionary_entries(comp, tuples, block_size,
8749e85ec40SCezary Rojewski 					       pins, num_pins, sizeof(*pins),
8759e85ec40SCezary Rojewski 					       AVS_TKN_PIN_FMT_INDEX_U32,
8769e85ec40SCezary Rojewski 					       pin_format_parsers,
8779e85ec40SCezary Rojewski 					       ARRAY_SIZE(pin_format_parsers));
8789e85ec40SCezary Rojewski 		if (ret)
8799e85ec40SCezary Rojewski 			return ret;
8809e85ec40SCezary Rojewski 		cfg->generic.pin_fmts = pins;
8819e85ec40SCezary Rojewski 	}
8829e85ec40SCezary Rojewski 
8839e85ec40SCezary Rojewski 	return 0;
8849e85ec40SCezary Rojewski }
8859e85ec40SCezary Rojewski 
avs_tplg_parse_modcfgs_ext(struct snd_soc_component * comp,struct snd_soc_tplg_vendor_array * tuples,u32 block_size)8869e85ec40SCezary Rojewski static int avs_tplg_parse_modcfgs_ext(struct snd_soc_component *comp,
8879e85ec40SCezary Rojewski 				      struct snd_soc_tplg_vendor_array *tuples,
8889e85ec40SCezary Rojewski 				      u32 block_size)
8899e85ec40SCezary Rojewski {
8909e85ec40SCezary Rojewski 	struct avs_soc_component *acomp = to_avs_soc_component(comp);
8919e85ec40SCezary Rojewski 	struct avs_tplg *tplg = acomp->tplg;
8929e85ec40SCezary Rojewski 	int ret, i;
8939e85ec40SCezary Rojewski 
8949e85ec40SCezary Rojewski 	ret = parse_dictionary_header(comp, tuples, (void **)&tplg->modcfgs_ext,
8959e85ec40SCezary Rojewski 				      &tplg->num_modcfgs_ext,
8969e85ec40SCezary Rojewski 				      sizeof(*tplg->modcfgs_ext),
8979e85ec40SCezary Rojewski 				      AVS_TKN_MANIFEST_NUM_MODCFGS_EXT_U32);
8989e85ec40SCezary Rojewski 	if (ret)
8999e85ec40SCezary Rojewski 		return ret;
9009e85ec40SCezary Rojewski 
9019e85ec40SCezary Rojewski 	block_size -= le32_to_cpu(tuples->size);
9029e85ec40SCezary Rojewski 	/* With header parsed, move on to parsing entries. */
9039e85ec40SCezary Rojewski 	tuples = avs_tplg_vendor_array_next(tuples);
9049e85ec40SCezary Rojewski 
9059e85ec40SCezary Rojewski 	for (i = 0; i < tplg->num_modcfgs_ext; i++) {
9069e85ec40SCezary Rojewski 		struct avs_tplg_modcfg_ext *cfg = &tplg->modcfgs_ext[i];
9079e85ec40SCezary Rojewski 		u32 esize;
9089e85ec40SCezary Rojewski 
9099e85ec40SCezary Rojewski 		ret = avs_tplg_vendor_entry_size(tuples, block_size,
9109e85ec40SCezary Rojewski 						 AVS_TKN_MODCFG_EXT_ID_U32, &esize);
9119e85ec40SCezary Rojewski 		if (ret)
9129e85ec40SCezary Rojewski 			return ret;
9139e85ec40SCezary Rojewski 
9149e85ec40SCezary Rojewski 		ret = avs_tplg_parse_modcfg_ext(comp, cfg, tuples, esize);
9159e85ec40SCezary Rojewski 		if (ret)
9169e85ec40SCezary Rojewski 			return ret;
9179e85ec40SCezary Rojewski 
9189e85ec40SCezary Rojewski 		block_size -= esize;
9199e85ec40SCezary Rojewski 		tuples = avs_tplg_vendor_array_at(tuples, esize);
9209e85ec40SCezary Rojewski 	}
9219e85ec40SCezary Rojewski 
9229e85ec40SCezary Rojewski 	return 0;
9239e85ec40SCezary Rojewski }
9241fba2036SCezary Rojewski 
9251fba2036SCezary Rojewski static const struct avs_tplg_token_parser pplcfg_parsers[] = {
9261fba2036SCezary Rojewski 	{
9271fba2036SCezary Rojewski 		.token = AVS_TKN_PPLCFG_REQ_SIZE_U16,
9281fba2036SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_SHORT,
9291fba2036SCezary Rojewski 		.offset = offsetof(struct avs_tplg_pplcfg, req_size),
9301fba2036SCezary Rojewski 		.parse = avs_parse_short_token,
9311fba2036SCezary Rojewski 	},
9321fba2036SCezary Rojewski 	{
9331fba2036SCezary Rojewski 		.token = AVS_TKN_PPLCFG_PRIORITY_U8,
9341fba2036SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_BYTE,
9351fba2036SCezary Rojewski 		.offset = offsetof(struct avs_tplg_pplcfg, priority),
9361fba2036SCezary Rojewski 		.parse = avs_parse_byte_token,
9371fba2036SCezary Rojewski 	},
9381fba2036SCezary Rojewski 	{
9391fba2036SCezary Rojewski 		.token = AVS_TKN_PPLCFG_LOW_POWER_BOOL,
9401fba2036SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_BOOL,
9411fba2036SCezary Rojewski 		.offset = offsetof(struct avs_tplg_pplcfg, lp),
9421fba2036SCezary Rojewski 		.parse = avs_parse_bool_token,
9431fba2036SCezary Rojewski 	},
9441fba2036SCezary Rojewski 	{
9451fba2036SCezary Rojewski 		.token = AVS_TKN_PPLCFG_ATTRIBUTES_U16,
9461fba2036SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_SHORT,
9471fba2036SCezary Rojewski 		.offset = offsetof(struct avs_tplg_pplcfg, attributes),
9481fba2036SCezary Rojewski 		.parse = avs_parse_short_token,
9491fba2036SCezary Rojewski 	},
9501fba2036SCezary Rojewski 	{
9511fba2036SCezary Rojewski 		.token = AVS_TKN_PPLCFG_TRIGGER_U32,
9521fba2036SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
9531fba2036SCezary Rojewski 		.offset = offsetof(struct avs_tplg_pplcfg, trigger),
9541fba2036SCezary Rojewski 		.parse = avs_parse_word_token,
9551fba2036SCezary Rojewski 	},
9561fba2036SCezary Rojewski };
9571fba2036SCezary Rojewski 
avs_tplg_parse_pplcfgs(struct snd_soc_component * comp,struct snd_soc_tplg_vendor_array * tuples,u32 block_size)9581fba2036SCezary Rojewski static int avs_tplg_parse_pplcfgs(struct snd_soc_component *comp,
9591fba2036SCezary Rojewski 				  struct snd_soc_tplg_vendor_array *tuples,
9601fba2036SCezary Rojewski 				  u32 block_size)
9611fba2036SCezary Rojewski {
9621fba2036SCezary Rojewski 	struct avs_soc_component *acomp = to_avs_soc_component(comp);
9631fba2036SCezary Rojewski 	struct avs_tplg *tplg = acomp->tplg;
9641fba2036SCezary Rojewski 
9651fba2036SCezary Rojewski 	return parse_dictionary(comp, tuples, block_size, (void **)&tplg->pplcfgs,
9661fba2036SCezary Rojewski 				&tplg->num_pplcfgs, sizeof(*tplg->pplcfgs),
9671fba2036SCezary Rojewski 				AVS_TKN_MANIFEST_NUM_PPLCFGS_U32,
9681fba2036SCezary Rojewski 				AVS_TKN_PPLCFG_ID_U32,
9691fba2036SCezary Rojewski 				pplcfg_parsers, ARRAY_SIZE(pplcfg_parsers));
9701fba2036SCezary Rojewski }
9711fba2036SCezary Rojewski 
9721fba2036SCezary Rojewski static const struct avs_tplg_token_parser binding_parsers[] = {
9731fba2036SCezary Rojewski 	{
9741fba2036SCezary Rojewski 		.token = AVS_TKN_BINDING_TARGET_TPLG_NAME_STRING,
9751fba2036SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_STRING,
9761fba2036SCezary Rojewski 		.offset = offsetof(struct avs_tplg_binding, target_tplg_name),
977d48c1adaSCezary Rojewski 		.parse = parse_link_formatted_string,
9781fba2036SCezary Rojewski 	},
9791fba2036SCezary Rojewski 	{
9801fba2036SCezary Rojewski 		.token = AVS_TKN_BINDING_TARGET_PATH_TMPL_ID_U32,
9811fba2036SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
9821fba2036SCezary Rojewski 		.offset = offsetof(struct avs_tplg_binding, target_path_tmpl_id),
9831fba2036SCezary Rojewski 		.parse = avs_parse_word_token,
9841fba2036SCezary Rojewski 	},
9851fba2036SCezary Rojewski 	{
9861fba2036SCezary Rojewski 		.token = AVS_TKN_BINDING_TARGET_PPL_ID_U32,
9871fba2036SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
9881fba2036SCezary Rojewski 		.offset = offsetof(struct avs_tplg_binding, target_ppl_id),
9891fba2036SCezary Rojewski 		.parse = avs_parse_word_token,
9901fba2036SCezary Rojewski 	},
9911fba2036SCezary Rojewski 	{
9921fba2036SCezary Rojewski 		.token = AVS_TKN_BINDING_TARGET_MOD_ID_U32,
9931fba2036SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
9941fba2036SCezary Rojewski 		.offset = offsetof(struct avs_tplg_binding, target_mod_id),
9951fba2036SCezary Rojewski 		.parse = avs_parse_word_token,
9961fba2036SCezary Rojewski 	},
9971fba2036SCezary Rojewski 	{
9981fba2036SCezary Rojewski 		.token = AVS_TKN_BINDING_TARGET_MOD_PIN_U8,
9991fba2036SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_BYTE,
10001fba2036SCezary Rojewski 		.offset = offsetof(struct avs_tplg_binding, target_mod_pin),
10011fba2036SCezary Rojewski 		.parse = avs_parse_byte_token,
10021fba2036SCezary Rojewski 	},
10031fba2036SCezary Rojewski 	{
10041fba2036SCezary Rojewski 		.token = AVS_TKN_BINDING_MOD_ID_U32,
10051fba2036SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
10061fba2036SCezary Rojewski 		.offset = offsetof(struct avs_tplg_binding, mod_id),
10071fba2036SCezary Rojewski 		.parse = avs_parse_word_token,
10081fba2036SCezary Rojewski 	},
10091fba2036SCezary Rojewski 	{
10101fba2036SCezary Rojewski 		.token = AVS_TKN_BINDING_MOD_PIN_U8,
10111fba2036SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_BYTE,
10121fba2036SCezary Rojewski 		.offset = offsetof(struct avs_tplg_binding, mod_pin),
10131fba2036SCezary Rojewski 		.parse = avs_parse_byte_token,
10141fba2036SCezary Rojewski 	},
10151fba2036SCezary Rojewski 	{
10161fba2036SCezary Rojewski 		.token = AVS_TKN_BINDING_IS_SINK_U8,
10171fba2036SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_BYTE,
10181fba2036SCezary Rojewski 		.offset = offsetof(struct avs_tplg_binding, is_sink),
10191fba2036SCezary Rojewski 		.parse = avs_parse_byte_token,
10201fba2036SCezary Rojewski 	},
10211fba2036SCezary Rojewski };
10221fba2036SCezary Rojewski 
avs_tplg_parse_bindings(struct snd_soc_component * comp,struct snd_soc_tplg_vendor_array * tuples,u32 block_size)10231fba2036SCezary Rojewski static int avs_tplg_parse_bindings(struct snd_soc_component *comp,
10241fba2036SCezary Rojewski 				   struct snd_soc_tplg_vendor_array *tuples,
10251fba2036SCezary Rojewski 				   u32 block_size)
10261fba2036SCezary Rojewski {
10271fba2036SCezary Rojewski 	struct avs_soc_component *acomp = to_avs_soc_component(comp);
10281fba2036SCezary Rojewski 	struct avs_tplg *tplg = acomp->tplg;
10291fba2036SCezary Rojewski 
10301fba2036SCezary Rojewski 	return parse_dictionary(comp, tuples, block_size, (void **)&tplg->bindings,
10311fba2036SCezary Rojewski 				&tplg->num_bindings, sizeof(*tplg->bindings),
10321fba2036SCezary Rojewski 				AVS_TKN_MANIFEST_NUM_BINDINGS_U32,
10331fba2036SCezary Rojewski 				AVS_TKN_BINDING_ID_U32,
10341fba2036SCezary Rojewski 				binding_parsers, ARRAY_SIZE(binding_parsers));
10351fba2036SCezary Rojewski }
1036276b83c8SCezary Rojewski 
1037276b83c8SCezary Rojewski static const struct avs_tplg_token_parser module_parsers[] = {
1038276b83c8SCezary Rojewski 	{
1039276b83c8SCezary Rojewski 		.token = AVS_TKN_MOD_ID_U32,
1040276b83c8SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
1041276b83c8SCezary Rojewski 		.offset = offsetof(struct avs_tplg_module, id),
1042276b83c8SCezary Rojewski 		.parse = avs_parse_word_token,
1043276b83c8SCezary Rojewski 	},
1044276b83c8SCezary Rojewski 	{
1045276b83c8SCezary Rojewski 		.token = AVS_TKN_MOD_MODCFG_BASE_ID_U32,
1046276b83c8SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
1047276b83c8SCezary Rojewski 		.offset = offsetof(struct avs_tplg_module, cfg_base),
1048276b83c8SCezary Rojewski 		.parse = avs_parse_modcfg_base_ptr,
1049276b83c8SCezary Rojewski 	},
1050276b83c8SCezary Rojewski 	{
1051276b83c8SCezary Rojewski 		.token = AVS_TKN_MOD_IN_AFMT_ID_U32,
1052276b83c8SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
1053276b83c8SCezary Rojewski 		.offset = offsetof(struct avs_tplg_module, in_fmt),
1054276b83c8SCezary Rojewski 		.parse = avs_parse_audio_format_ptr,
1055276b83c8SCezary Rojewski 	},
1056276b83c8SCezary Rojewski 	{
1057276b83c8SCezary Rojewski 		.token = AVS_TKN_MOD_CORE_ID_U8,
1058276b83c8SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_BYTE,
1059276b83c8SCezary Rojewski 		.offset = offsetof(struct avs_tplg_module, core_id),
1060276b83c8SCezary Rojewski 		.parse = avs_parse_byte_token,
1061276b83c8SCezary Rojewski 	},
1062276b83c8SCezary Rojewski 	{
1063276b83c8SCezary Rojewski 		.token = AVS_TKN_MOD_PROC_DOMAIN_U8,
1064276b83c8SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_BYTE,
1065276b83c8SCezary Rojewski 		.offset = offsetof(struct avs_tplg_module, domain),
1066276b83c8SCezary Rojewski 		.parse = avs_parse_byte_token,
1067276b83c8SCezary Rojewski 	},
1068276b83c8SCezary Rojewski 	{
1069276b83c8SCezary Rojewski 		.token = AVS_TKN_MOD_MODCFG_EXT_ID_U32,
1070276b83c8SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
1071276b83c8SCezary Rojewski 		.offset = offsetof(struct avs_tplg_module, cfg_ext),
1072276b83c8SCezary Rojewski 		.parse = avs_parse_modcfg_ext_ptr,
1073276b83c8SCezary Rojewski 	},
1074be2b81b5SAmadeusz Sławiński 	{
1075be2b81b5SAmadeusz Sławiński 		.token = AVS_TKN_MOD_KCONTROL_ID_U32,
1076be2b81b5SAmadeusz Sławiński 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
1077be2b81b5SAmadeusz Sławiński 		.offset = offsetof(struct avs_tplg_module, ctl_id),
1078be2b81b5SAmadeusz Sławiński 		.parse = avs_parse_byte_token,
1079be2b81b5SAmadeusz Sławiński 	},
1080276b83c8SCezary Rojewski };
1081276b83c8SCezary Rojewski 
1082276b83c8SCezary Rojewski static struct avs_tplg_module *
avs_tplg_module_create(struct snd_soc_component * comp,struct avs_tplg_pipeline * owner,struct snd_soc_tplg_vendor_array * tuples,u32 block_size)1083276b83c8SCezary Rojewski avs_tplg_module_create(struct snd_soc_component *comp, struct avs_tplg_pipeline *owner,
1084276b83c8SCezary Rojewski 		       struct snd_soc_tplg_vendor_array *tuples, u32 block_size)
1085276b83c8SCezary Rojewski {
1086276b83c8SCezary Rojewski 	struct avs_tplg_module *module;
1087276b83c8SCezary Rojewski 	int ret;
1088276b83c8SCezary Rojewski 
1089276b83c8SCezary Rojewski 	module = devm_kzalloc(comp->card->dev, sizeof(*module), GFP_KERNEL);
1090276b83c8SCezary Rojewski 	if (!module)
1091276b83c8SCezary Rojewski 		return ERR_PTR(-ENOMEM);
1092276b83c8SCezary Rojewski 
1093276b83c8SCezary Rojewski 	ret = avs_parse_tokens(comp, module, module_parsers,
1094276b83c8SCezary Rojewski 			       ARRAY_SIZE(module_parsers), tuples, block_size);
1095276b83c8SCezary Rojewski 	if (ret < 0)
1096276b83c8SCezary Rojewski 		return ERR_PTR(ret);
1097276b83c8SCezary Rojewski 
1098276b83c8SCezary Rojewski 	module->owner = owner;
1099276b83c8SCezary Rojewski 	INIT_LIST_HEAD(&module->node);
1100276b83c8SCezary Rojewski 
1101276b83c8SCezary Rojewski 	return module;
1102276b83c8SCezary Rojewski }
1103276b83c8SCezary Rojewski 
1104276b83c8SCezary Rojewski static const struct avs_tplg_token_parser pipeline_parsers[] = {
1105276b83c8SCezary Rojewski 	{
1106276b83c8SCezary Rojewski 		.token = AVS_TKN_PPL_ID_U32,
1107276b83c8SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
1108276b83c8SCezary Rojewski 		.offset = offsetof(struct avs_tplg_pipeline, id),
1109276b83c8SCezary Rojewski 		.parse = avs_parse_word_token,
1110276b83c8SCezary Rojewski 	},
1111276b83c8SCezary Rojewski 	{
1112276b83c8SCezary Rojewski 		.token = AVS_TKN_PPL_PPLCFG_ID_U32,
1113276b83c8SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
1114276b83c8SCezary Rojewski 		.offset = offsetof(struct avs_tplg_pipeline, cfg),
1115276b83c8SCezary Rojewski 		.parse = avs_parse_pplcfg_ptr,
1116276b83c8SCezary Rojewski 	},
1117276b83c8SCezary Rojewski 	{
1118276b83c8SCezary Rojewski 		.token = AVS_TKN_PPL_NUM_BINDING_IDS_U32,
1119276b83c8SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
1120276b83c8SCezary Rojewski 		.offset = offsetof(struct avs_tplg_pipeline, num_bindings),
1121276b83c8SCezary Rojewski 		.parse = avs_parse_word_token,
1122276b83c8SCezary Rojewski 	},
1123276b83c8SCezary Rojewski };
1124276b83c8SCezary Rojewski 
1125276b83c8SCezary Rojewski static const struct avs_tplg_token_parser bindings_parsers[] = {
1126276b83c8SCezary Rojewski 	{
1127276b83c8SCezary Rojewski 		.token = AVS_TKN_PPL_BINDING_ID_U32,
1128276b83c8SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
1129276b83c8SCezary Rojewski 		.offset = 0, /* to treat pipeline->bindings as dictionary */
1130276b83c8SCezary Rojewski 		.parse = avs_parse_binding_ptr,
1131276b83c8SCezary Rojewski 	},
1132276b83c8SCezary Rojewski };
1133276b83c8SCezary Rojewski 
1134276b83c8SCezary Rojewski static struct avs_tplg_pipeline *
avs_tplg_pipeline_create(struct snd_soc_component * comp,struct avs_tplg_path * owner,struct snd_soc_tplg_vendor_array * tuples,u32 block_size)1135276b83c8SCezary Rojewski avs_tplg_pipeline_create(struct snd_soc_component *comp, struct avs_tplg_path *owner,
1136276b83c8SCezary Rojewski 			 struct snd_soc_tplg_vendor_array *tuples, u32 block_size)
1137276b83c8SCezary Rojewski {
1138276b83c8SCezary Rojewski 	struct avs_tplg_pipeline *pipeline;
1139276b83c8SCezary Rojewski 	u32 modblk_size, offset;
1140276b83c8SCezary Rojewski 	int ret;
1141276b83c8SCezary Rojewski 
1142276b83c8SCezary Rojewski 	pipeline = devm_kzalloc(comp->card->dev, sizeof(*pipeline), GFP_KERNEL);
1143276b83c8SCezary Rojewski 	if (!pipeline)
1144276b83c8SCezary Rojewski 		return ERR_PTR(-ENOMEM);
1145276b83c8SCezary Rojewski 
1146276b83c8SCezary Rojewski 	pipeline->owner = owner;
1147276b83c8SCezary Rojewski 	INIT_LIST_HEAD(&pipeline->mod_list);
1148276b83c8SCezary Rojewski 
1149276b83c8SCezary Rojewski 	/* Pipeline header MUST be followed by at least one module. */
1150276b83c8SCezary Rojewski 	ret = avs_tplg_vendor_array_lookup(tuples, block_size,
1151276b83c8SCezary Rojewski 					   AVS_TKN_MOD_ID_U32, &offset);
1152276b83c8SCezary Rojewski 	if (!ret && !offset)
1153276b83c8SCezary Rojewski 		ret = -EINVAL;
1154276b83c8SCezary Rojewski 	if (ret)
1155276b83c8SCezary Rojewski 		return ERR_PTR(ret);
1156276b83c8SCezary Rojewski 
1157276b83c8SCezary Rojewski 	/* Process header which precedes module sections. */
1158276b83c8SCezary Rojewski 	ret = avs_parse_tokens(comp, pipeline, pipeline_parsers,
1159276b83c8SCezary Rojewski 			       ARRAY_SIZE(pipeline_parsers), tuples, offset);
1160276b83c8SCezary Rojewski 	if (ret < 0)
1161276b83c8SCezary Rojewski 		return ERR_PTR(ret);
1162276b83c8SCezary Rojewski 
1163276b83c8SCezary Rojewski 	block_size -= offset;
1164276b83c8SCezary Rojewski 	tuples = avs_tplg_vendor_array_at(tuples, offset);
1165276b83c8SCezary Rojewski 
1166276b83c8SCezary Rojewski 	/* Optionally, binding sections follow module ones. */
1167276b83c8SCezary Rojewski 	ret = avs_tplg_vendor_array_lookup_next(tuples, block_size,
1168276b83c8SCezary Rojewski 						AVS_TKN_PPL_BINDING_ID_U32, &offset);
1169276b83c8SCezary Rojewski 	if (ret) {
1170276b83c8SCezary Rojewski 		if (ret != -ENOENT)
1171276b83c8SCezary Rojewski 			return ERR_PTR(ret);
1172276b83c8SCezary Rojewski 
1173276b83c8SCezary Rojewski 		/* Does header information match actual block layout? */
1174276b83c8SCezary Rojewski 		if (pipeline->num_bindings)
1175276b83c8SCezary Rojewski 			return ERR_PTR(-EINVAL);
1176276b83c8SCezary Rojewski 
1177276b83c8SCezary Rojewski 		modblk_size = block_size;
1178276b83c8SCezary Rojewski 	} else {
1179276b83c8SCezary Rojewski 		pipeline->bindings = devm_kcalloc(comp->card->dev, pipeline->num_bindings,
1180276b83c8SCezary Rojewski 						  sizeof(*pipeline->bindings), GFP_KERNEL);
1181276b83c8SCezary Rojewski 		if (!pipeline->bindings)
1182276b83c8SCezary Rojewski 			return ERR_PTR(-ENOMEM);
1183276b83c8SCezary Rojewski 
1184276b83c8SCezary Rojewski 		modblk_size = offset;
1185276b83c8SCezary Rojewski 	}
1186276b83c8SCezary Rojewski 
1187276b83c8SCezary Rojewski 	block_size -= modblk_size;
1188276b83c8SCezary Rojewski 	do {
1189276b83c8SCezary Rojewski 		struct avs_tplg_module *module;
1190276b83c8SCezary Rojewski 		u32 esize;
1191276b83c8SCezary Rojewski 
1192276b83c8SCezary Rojewski 		ret = avs_tplg_vendor_entry_size(tuples, modblk_size,
1193276b83c8SCezary Rojewski 						 AVS_TKN_MOD_ID_U32, &esize);
1194276b83c8SCezary Rojewski 		if (ret)
1195276b83c8SCezary Rojewski 			return ERR_PTR(ret);
1196276b83c8SCezary Rojewski 
1197276b83c8SCezary Rojewski 		module = avs_tplg_module_create(comp, pipeline, tuples, esize);
1198276b83c8SCezary Rojewski 		if (IS_ERR(module)) {
1199276b83c8SCezary Rojewski 			dev_err(comp->dev, "parse module failed: %ld\n",
1200276b83c8SCezary Rojewski 				PTR_ERR(module));
1201276b83c8SCezary Rojewski 			return ERR_CAST(module);
1202276b83c8SCezary Rojewski 		}
1203276b83c8SCezary Rojewski 
1204276b83c8SCezary Rojewski 		list_add_tail(&module->node, &pipeline->mod_list);
1205276b83c8SCezary Rojewski 		modblk_size -= esize;
1206276b83c8SCezary Rojewski 		tuples = avs_tplg_vendor_array_at(tuples, esize);
1207276b83c8SCezary Rojewski 	} while (modblk_size > 0);
1208276b83c8SCezary Rojewski 
1209276b83c8SCezary Rojewski 	/* What's left is optional range of bindings. */
1210276b83c8SCezary Rojewski 	ret = parse_dictionary_entries(comp, tuples, block_size, pipeline->bindings,
1211276b83c8SCezary Rojewski 				       pipeline->num_bindings, sizeof(*pipeline->bindings),
1212276b83c8SCezary Rojewski 				       AVS_TKN_PPL_BINDING_ID_U32,
1213276b83c8SCezary Rojewski 				       bindings_parsers, ARRAY_SIZE(bindings_parsers));
1214276b83c8SCezary Rojewski 	if (ret)
1215276b83c8SCezary Rojewski 		return ERR_PTR(ret);
1216276b83c8SCezary Rojewski 
1217276b83c8SCezary Rojewski 	return pipeline;
1218276b83c8SCezary Rojewski }
1219eee475bbSCezary Rojewski 
1220eee475bbSCezary Rojewski static const struct avs_tplg_token_parser path_parsers[] = {
1221eee475bbSCezary Rojewski 	{
1222eee475bbSCezary Rojewski 		.token = AVS_TKN_PATH_ID_U32,
1223eee475bbSCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
1224eee475bbSCezary Rojewski 		.offset = offsetof(struct avs_tplg_path, id),
1225eee475bbSCezary Rojewski 		.parse = avs_parse_word_token,
1226eee475bbSCezary Rojewski 	},
1227eee475bbSCezary Rojewski 	{
1228eee475bbSCezary Rojewski 		.token = AVS_TKN_PATH_FE_FMT_ID_U32,
1229eee475bbSCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
1230eee475bbSCezary Rojewski 		.offset = offsetof(struct avs_tplg_path, fe_fmt),
1231eee475bbSCezary Rojewski 		.parse = avs_parse_audio_format_ptr,
1232eee475bbSCezary Rojewski 	},
1233eee475bbSCezary Rojewski 	{
1234eee475bbSCezary Rojewski 		.token = AVS_TKN_PATH_BE_FMT_ID_U32,
1235eee475bbSCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
1236eee475bbSCezary Rojewski 		.offset = offsetof(struct avs_tplg_path, be_fmt),
1237eee475bbSCezary Rojewski 		.parse = avs_parse_audio_format_ptr,
1238eee475bbSCezary Rojewski 	},
1239eee475bbSCezary Rojewski };
1240eee475bbSCezary Rojewski 
1241eee475bbSCezary Rojewski static struct avs_tplg_path *
avs_tplg_path_create(struct snd_soc_component * comp,struct avs_tplg_path_template * owner,struct snd_soc_tplg_vendor_array * tuples,u32 block_size,const struct avs_tplg_token_parser * parsers,u32 num_parsers)1242eee475bbSCezary Rojewski avs_tplg_path_create(struct snd_soc_component *comp, struct avs_tplg_path_template *owner,
1243eee475bbSCezary Rojewski 		     struct snd_soc_tplg_vendor_array *tuples, u32 block_size,
1244eee475bbSCezary Rojewski 		     const struct avs_tplg_token_parser *parsers, u32 num_parsers)
1245eee475bbSCezary Rojewski {
1246eee475bbSCezary Rojewski 	struct avs_tplg_pipeline *pipeline;
1247eee475bbSCezary Rojewski 	struct avs_tplg_path *path;
1248eee475bbSCezary Rojewski 	u32 offset;
1249eee475bbSCezary Rojewski 	int ret;
1250eee475bbSCezary Rojewski 
1251eee475bbSCezary Rojewski 	path = devm_kzalloc(comp->card->dev, sizeof(*path), GFP_KERNEL);
1252eee475bbSCezary Rojewski 	if (!path)
1253eee475bbSCezary Rojewski 		return ERR_PTR(-ENOMEM);
1254eee475bbSCezary Rojewski 
1255eee475bbSCezary Rojewski 	path->owner = owner;
1256eee475bbSCezary Rojewski 	INIT_LIST_HEAD(&path->ppl_list);
1257eee475bbSCezary Rojewski 	INIT_LIST_HEAD(&path->node);
1258eee475bbSCezary Rojewski 
1259eee475bbSCezary Rojewski 	/* Path header MAY be followed by one or more pipelines. */
1260eee475bbSCezary Rojewski 	ret = avs_tplg_vendor_array_lookup(tuples, block_size,
1261eee475bbSCezary Rojewski 					   AVS_TKN_PPL_ID_U32, &offset);
1262eee475bbSCezary Rojewski 	if (ret == -ENOENT)
1263eee475bbSCezary Rojewski 		offset = block_size;
1264eee475bbSCezary Rojewski 	else if (ret)
1265eee475bbSCezary Rojewski 		return ERR_PTR(ret);
1266eee475bbSCezary Rojewski 	else if (!offset)
1267eee475bbSCezary Rojewski 		return ERR_PTR(-EINVAL);
1268eee475bbSCezary Rojewski 
1269eee475bbSCezary Rojewski 	/* Process header which precedes pipeline sections. */
1270eee475bbSCezary Rojewski 	ret = avs_parse_tokens(comp, path, parsers, num_parsers, tuples, offset);
1271eee475bbSCezary Rojewski 	if (ret < 0)
1272eee475bbSCezary Rojewski 		return ERR_PTR(ret);
1273eee475bbSCezary Rojewski 
1274eee475bbSCezary Rojewski 	block_size -= offset;
1275eee475bbSCezary Rojewski 	tuples = avs_tplg_vendor_array_at(tuples, offset);
1276eee475bbSCezary Rojewski 	while (block_size > 0) {
1277eee475bbSCezary Rojewski 		u32 esize;
1278eee475bbSCezary Rojewski 
1279eee475bbSCezary Rojewski 		ret = avs_tplg_vendor_entry_size(tuples, block_size,
1280eee475bbSCezary Rojewski 						 AVS_TKN_PPL_ID_U32, &esize);
1281eee475bbSCezary Rojewski 		if (ret)
1282eee475bbSCezary Rojewski 			return ERR_PTR(ret);
1283eee475bbSCezary Rojewski 
1284eee475bbSCezary Rojewski 		pipeline = avs_tplg_pipeline_create(comp, path, tuples, esize);
1285eee475bbSCezary Rojewski 		if (IS_ERR(pipeline)) {
1286eee475bbSCezary Rojewski 			dev_err(comp->dev, "parse pipeline failed: %ld\n",
1287eee475bbSCezary Rojewski 				PTR_ERR(pipeline));
1288eee475bbSCezary Rojewski 			return ERR_CAST(pipeline);
1289eee475bbSCezary Rojewski 		}
1290eee475bbSCezary Rojewski 
1291eee475bbSCezary Rojewski 		list_add_tail(&pipeline->node, &path->ppl_list);
1292eee475bbSCezary Rojewski 		block_size -= esize;
1293eee475bbSCezary Rojewski 		tuples = avs_tplg_vendor_array_at(tuples, esize);
1294eee475bbSCezary Rojewski 	}
1295eee475bbSCezary Rojewski 
1296eee475bbSCezary Rojewski 	return path;
1297eee475bbSCezary Rojewski }
1298eee475bbSCezary Rojewski 
1299eee475bbSCezary Rojewski static const struct avs_tplg_token_parser path_tmpl_parsers[] = {
1300eee475bbSCezary Rojewski 	{
1301eee475bbSCezary Rojewski 		.token = AVS_TKN_PATH_TMPL_ID_U32,
1302eee475bbSCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
1303eee475bbSCezary Rojewski 		.offset = offsetof(struct avs_tplg_path_template, id),
1304eee475bbSCezary Rojewski 		.parse = avs_parse_word_token,
1305eee475bbSCezary Rojewski 	},
1306eee475bbSCezary Rojewski };
1307eee475bbSCezary Rojewski 
parse_path_template(struct snd_soc_component * comp,struct snd_soc_tplg_vendor_array * tuples,u32 block_size,struct avs_tplg_path_template * template,const struct avs_tplg_token_parser * tmpl_tokens,u32 num_tmpl_tokens,const struct avs_tplg_token_parser * path_tokens,u32 num_path_tokens)1308eee475bbSCezary Rojewski static int parse_path_template(struct snd_soc_component *comp,
1309eee475bbSCezary Rojewski 			       struct snd_soc_tplg_vendor_array *tuples, u32 block_size,
1310eee475bbSCezary Rojewski 			       struct avs_tplg_path_template *template,
1311eee475bbSCezary Rojewski 			       const struct avs_tplg_token_parser *tmpl_tokens, u32 num_tmpl_tokens,
1312eee475bbSCezary Rojewski 			       const struct avs_tplg_token_parser *path_tokens, u32 num_path_tokens)
1313eee475bbSCezary Rojewski {
1314eee475bbSCezary Rojewski 	struct avs_tplg_path *path;
1315eee475bbSCezary Rojewski 	u32 offset;
1316eee475bbSCezary Rojewski 	int ret;
1317eee475bbSCezary Rojewski 
1318eee475bbSCezary Rojewski 	/* Path template header MUST be followed by at least one path variant. */
1319eee475bbSCezary Rojewski 	ret = avs_tplg_vendor_array_lookup(tuples, block_size,
1320eee475bbSCezary Rojewski 					   AVS_TKN_PATH_ID_U32, &offset);
1321eee475bbSCezary Rojewski 	if (ret)
1322eee475bbSCezary Rojewski 		return ret;
1323eee475bbSCezary Rojewski 
1324eee475bbSCezary Rojewski 	/* Process header which precedes path variants sections. */
1325eee475bbSCezary Rojewski 	ret = avs_parse_tokens(comp, template, tmpl_tokens, num_tmpl_tokens, tuples, offset);
1326eee475bbSCezary Rojewski 	if (ret < 0)
1327eee475bbSCezary Rojewski 		return ret;
1328eee475bbSCezary Rojewski 
1329eee475bbSCezary Rojewski 	block_size -= offset;
1330eee475bbSCezary Rojewski 	tuples = avs_tplg_vendor_array_at(tuples, offset);
1331eee475bbSCezary Rojewski 	do {
1332eee475bbSCezary Rojewski 		u32 esize;
1333eee475bbSCezary Rojewski 
1334eee475bbSCezary Rojewski 		ret = avs_tplg_vendor_entry_size(tuples, block_size,
1335eee475bbSCezary Rojewski 						 AVS_TKN_PATH_ID_U32, &esize);
1336eee475bbSCezary Rojewski 		if (ret)
1337eee475bbSCezary Rojewski 			return ret;
1338eee475bbSCezary Rojewski 
1339eee475bbSCezary Rojewski 		path = avs_tplg_path_create(comp, template, tuples, esize, path_tokens,
1340eee475bbSCezary Rojewski 					    num_path_tokens);
1341eee475bbSCezary Rojewski 		if (IS_ERR(path)) {
1342eee475bbSCezary Rojewski 			dev_err(comp->dev, "parse path failed: %ld\n", PTR_ERR(path));
1343eee475bbSCezary Rojewski 			return PTR_ERR(path);
1344eee475bbSCezary Rojewski 		}
1345eee475bbSCezary Rojewski 
1346eee475bbSCezary Rojewski 		list_add_tail(&path->node, &template->path_list);
1347eee475bbSCezary Rojewski 		block_size -= esize;
1348eee475bbSCezary Rojewski 		tuples = avs_tplg_vendor_array_at(tuples, esize);
1349eee475bbSCezary Rojewski 	} while (block_size > 0);
1350eee475bbSCezary Rojewski 
1351eee475bbSCezary Rojewski 	return 0;
1352eee475bbSCezary Rojewski }
1353eee475bbSCezary Rojewski 
1354eee475bbSCezary Rojewski static struct avs_tplg_path_template *
avs_tplg_path_template_create(struct snd_soc_component * comp,struct avs_tplg * owner,struct snd_soc_tplg_vendor_array * tuples,u32 block_size)1355eee475bbSCezary Rojewski avs_tplg_path_template_create(struct snd_soc_component *comp, struct avs_tplg *owner,
1356eee475bbSCezary Rojewski 			      struct snd_soc_tplg_vendor_array *tuples, u32 block_size)
1357eee475bbSCezary Rojewski {
1358eee475bbSCezary Rojewski 	struct avs_tplg_path_template *template;
1359eee475bbSCezary Rojewski 	int ret;
1360eee475bbSCezary Rojewski 
1361eee475bbSCezary Rojewski 	template = devm_kzalloc(comp->card->dev, sizeof(*template), GFP_KERNEL);
1362eee475bbSCezary Rojewski 	if (!template)
1363eee475bbSCezary Rojewski 		return ERR_PTR(-ENOMEM);
1364eee475bbSCezary Rojewski 
1365eee475bbSCezary Rojewski 	template->owner = owner; /* Used to access component tplg is assigned to. */
1366eee475bbSCezary Rojewski 	INIT_LIST_HEAD(&template->path_list);
1367eee475bbSCezary Rojewski 	INIT_LIST_HEAD(&template->node);
1368eee475bbSCezary Rojewski 
1369eee475bbSCezary Rojewski 	ret = parse_path_template(comp, tuples, block_size, template, path_tmpl_parsers,
1370eee475bbSCezary Rojewski 				  ARRAY_SIZE(path_tmpl_parsers), path_parsers,
1371eee475bbSCezary Rojewski 				  ARRAY_SIZE(path_parsers));
1372eee475bbSCezary Rojewski 	if (ret)
1373eee475bbSCezary Rojewski 		return ERR_PTR(ret);
1374eee475bbSCezary Rojewski 
1375eee475bbSCezary Rojewski 	return template;
1376eee475bbSCezary Rojewski }
1377d73d1b67SCezary Rojewski 
avs_route_load(struct snd_soc_component * comp,int index,struct snd_soc_dapm_route * route)1378d48c1adaSCezary Rojewski static int avs_route_load(struct snd_soc_component *comp, int index,
1379d48c1adaSCezary Rojewski 			  struct snd_soc_dapm_route *route)
1380d48c1adaSCezary Rojewski {
1381d48c1adaSCezary Rojewski 	struct snd_soc_acpi_mach *mach = dev_get_platdata(comp->card->dev);
1382d48c1adaSCezary Rojewski 	size_t len = SNDRV_CTL_ELEM_ID_NAME_MAXLEN;
1383d48c1adaSCezary Rojewski 	char buf[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
1384d48c1adaSCezary Rojewski 	u32 port;
1385d48c1adaSCezary Rojewski 
1386d48c1adaSCezary Rojewski 	/* See parse_link_formatted_string() for dynamic naming when(s). */
138725b552f1SPiotr Maziarz 	if (hweight_long(mach->mach_params.i2s_link_mask) == 1) {
138825b552f1SPiotr Maziarz 		port = __ffs(mach->mach_params.i2s_link_mask);
1389d48c1adaSCezary Rojewski 
1390d48c1adaSCezary Rojewski 		snprintf(buf, len, route->source, port);
1391f6500ec1Sjustinstitt@google.com 		strscpy((char *)route->source, buf, len);
1392d48c1adaSCezary Rojewski 		snprintf(buf, len, route->sink, port);
1393f6500ec1Sjustinstitt@google.com 		strscpy((char *)route->sink, buf, len);
1394d48c1adaSCezary Rojewski 		if (route->control) {
1395d48c1adaSCezary Rojewski 			snprintf(buf, len, route->control, port);
1396f6500ec1Sjustinstitt@google.com 			strscpy((char *)route->control, buf, len);
1397d48c1adaSCezary Rojewski 		}
1398d48c1adaSCezary Rojewski 	}
1399d48c1adaSCezary Rojewski 
1400d48c1adaSCezary Rojewski 	return 0;
1401d48c1adaSCezary Rojewski }
1402d48c1adaSCezary Rojewski 
avs_widget_load(struct snd_soc_component * comp,int index,struct snd_soc_dapm_widget * w,struct snd_soc_tplg_dapm_widget * dw)1403d73d1b67SCezary Rojewski static int avs_widget_load(struct snd_soc_component *comp, int index,
1404d73d1b67SCezary Rojewski 			   struct snd_soc_dapm_widget *w,
1405d73d1b67SCezary Rojewski 			   struct snd_soc_tplg_dapm_widget *dw)
1406d73d1b67SCezary Rojewski {
1407d73d1b67SCezary Rojewski 	struct snd_soc_acpi_mach *mach;
1408d73d1b67SCezary Rojewski 	struct avs_tplg_path_template *template;
1409d73d1b67SCezary Rojewski 	struct avs_soc_component *acomp = to_avs_soc_component(comp);
1410d73d1b67SCezary Rojewski 	struct avs_tplg *tplg;
1411d73d1b67SCezary Rojewski 
1412d73d1b67SCezary Rojewski 	if (!le32_to_cpu(dw->priv.size))
1413d73d1b67SCezary Rojewski 		return 0;
1414d73d1b67SCezary Rojewski 
14156f85e9b7SAmadeusz Sławiński 	w->no_wname_in_kcontrol_name = true;
14166f85e9b7SAmadeusz Sławiński 
1417d56829e9SPiotr Maziarz 	if (w->ignore_suspend && !AVS_S0IX_SUPPORTED) {
1418d56829e9SPiotr Maziarz 		dev_info_once(comp->dev, "Device does not support S0IX, check BIOS settings\n");
1419d56829e9SPiotr Maziarz 		w->ignore_suspend = false;
1420d56829e9SPiotr Maziarz 	}
1421d56829e9SPiotr Maziarz 
1422d73d1b67SCezary Rojewski 	tplg = acomp->tplg;
1423d73d1b67SCezary Rojewski 	mach = dev_get_platdata(comp->card->dev);
1424d73d1b67SCezary Rojewski 
1425d48c1adaSCezary Rojewski 	/* See parse_link_formatted_string() for dynamic naming when(s). */
142625b552f1SPiotr Maziarz 	if (hweight_long(mach->mach_params.i2s_link_mask) == 1) {
1427d48c1adaSCezary Rojewski 		kfree(w->name);
1428d48c1adaSCezary Rojewski 		/* w->name is freed later by soc_tplg_dapm_widget_create() */
142925b552f1SPiotr Maziarz 		w->name = kasprintf(GFP_KERNEL, dw->name, __ffs(mach->mach_params.i2s_link_mask));
1430d48c1adaSCezary Rojewski 		if (!w->name)
1431d48c1adaSCezary Rojewski 			return -ENOMEM;
1432d48c1adaSCezary Rojewski 	}
1433d48c1adaSCezary Rojewski 
1434d73d1b67SCezary Rojewski 	template = avs_tplg_path_template_create(comp, tplg, dw->priv.array,
1435d73d1b67SCezary Rojewski 						 le32_to_cpu(dw->priv.size));
1436d73d1b67SCezary Rojewski 	if (IS_ERR(template)) {
1437d73d1b67SCezary Rojewski 		dev_err(comp->dev, "widget %s load failed: %ld\n", dw->name,
1438d73d1b67SCezary Rojewski 			PTR_ERR(template));
1439d73d1b67SCezary Rojewski 		return PTR_ERR(template);
1440d73d1b67SCezary Rojewski 	}
1441d73d1b67SCezary Rojewski 
1442d73d1b67SCezary Rojewski 	w->priv = template; /* link path information to widget */
1443d73d1b67SCezary Rojewski 	list_add_tail(&template->node, &tplg->path_tmpl_list);
1444d73d1b67SCezary Rojewski 	return 0;
1445d73d1b67SCezary Rojewski }
1446d73d1b67SCezary Rojewski 
avs_widget_ready(struct snd_soc_component * comp,int index,struct snd_soc_dapm_widget * w,struct snd_soc_tplg_dapm_widget * dw)1447be2b81b5SAmadeusz Sławiński static int avs_widget_ready(struct snd_soc_component *comp, int index,
1448be2b81b5SAmadeusz Sławiński 			    struct snd_soc_dapm_widget *w,
1449be2b81b5SAmadeusz Sławiński 			    struct snd_soc_tplg_dapm_widget *dw)
1450be2b81b5SAmadeusz Sławiński {
1451be2b81b5SAmadeusz Sławiński 	struct avs_tplg_path_template *template = w->priv;
1452be2b81b5SAmadeusz Sławiński 
1453be2b81b5SAmadeusz Sławiński 	template->w = w;
1454be2b81b5SAmadeusz Sławiński 	return 0;
1455be2b81b5SAmadeusz Sławiński }
1456be2b81b5SAmadeusz Sławiński 
avs_dai_load(struct snd_soc_component * comp,int index,struct snd_soc_dai_driver * dai_drv,struct snd_soc_tplg_pcm * pcm,struct snd_soc_dai * dai)1457d73d1b67SCezary Rojewski static int avs_dai_load(struct snd_soc_component *comp, int index,
1458d73d1b67SCezary Rojewski 			struct snd_soc_dai_driver *dai_drv, struct snd_soc_tplg_pcm *pcm,
1459d73d1b67SCezary Rojewski 			struct snd_soc_dai *dai)
1460d73d1b67SCezary Rojewski {
1461d73d1b67SCezary Rojewski 	if (pcm)
1462d73d1b67SCezary Rojewski 		dai_drv->ops = &avs_dai_fe_ops;
1463d73d1b67SCezary Rojewski 	return 0;
1464d73d1b67SCezary Rojewski }
1465d73d1b67SCezary Rojewski 
avs_link_load(struct snd_soc_component * comp,int index,struct snd_soc_dai_link * link,struct snd_soc_tplg_link_config * cfg)1466d73d1b67SCezary Rojewski static int avs_link_load(struct snd_soc_component *comp, int index, struct snd_soc_dai_link *link,
1467d73d1b67SCezary Rojewski 			 struct snd_soc_tplg_link_config *cfg)
1468d73d1b67SCezary Rojewski {
1469d56829e9SPiotr Maziarz 	if (link->ignore_suspend && !AVS_S0IX_SUPPORTED) {
1470d56829e9SPiotr Maziarz 		dev_info_once(comp->dev, "Device does not support S0IX, check BIOS settings\n");
1471d56829e9SPiotr Maziarz 		link->ignore_suspend = false;
1472d56829e9SPiotr Maziarz 	}
1473d56829e9SPiotr Maziarz 
1474d73d1b67SCezary Rojewski 	if (!link->no_pcm) {
1475d73d1b67SCezary Rojewski 		/* Stream control handled by IPCs. */
1476d73d1b67SCezary Rojewski 		link->nonatomic = true;
1477d73d1b67SCezary Rojewski 
1478d73d1b67SCezary Rojewski 		/* Open LINK (BE) pipes last and close them first to prevent xruns. */
1479d73d1b67SCezary Rojewski 		link->trigger[0] = SND_SOC_DPCM_TRIGGER_PRE;
1480d73d1b67SCezary Rojewski 		link->trigger[1] = SND_SOC_DPCM_TRIGGER_PRE;
1481d73d1b67SCezary Rojewski 	}
1482d73d1b67SCezary Rojewski 
1483d73d1b67SCezary Rojewski 	return 0;
1484d73d1b67SCezary Rojewski }
1485d73d1b67SCezary Rojewski 
1486d73d1b67SCezary Rojewski static const struct avs_tplg_token_parser manifest_parsers[] = {
1487d73d1b67SCezary Rojewski 	{
1488d73d1b67SCezary Rojewski 		.token = AVS_TKN_MANIFEST_NAME_STRING,
1489d73d1b67SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_STRING,
1490d73d1b67SCezary Rojewski 		.offset = offsetof(struct avs_tplg, name),
1491d48c1adaSCezary Rojewski 		.parse = parse_link_formatted_string,
1492d73d1b67SCezary Rojewski 	},
1493d73d1b67SCezary Rojewski 	{
1494d73d1b67SCezary Rojewski 		.token = AVS_TKN_MANIFEST_VERSION_U32,
1495d73d1b67SCezary Rojewski 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
1496d73d1b67SCezary Rojewski 		.offset = offsetof(struct avs_tplg, version),
1497d73d1b67SCezary Rojewski 		.parse = avs_parse_word_token,
1498d73d1b67SCezary Rojewski 	},
1499d73d1b67SCezary Rojewski };
1500d73d1b67SCezary Rojewski 
avs_manifest(struct snd_soc_component * comp,int index,struct snd_soc_tplg_manifest * manifest)1501d73d1b67SCezary Rojewski static int avs_manifest(struct snd_soc_component *comp, int index,
1502d73d1b67SCezary Rojewski 			struct snd_soc_tplg_manifest *manifest)
1503d73d1b67SCezary Rojewski {
1504d73d1b67SCezary Rojewski 	struct snd_soc_tplg_vendor_array *tuples = manifest->priv.array;
1505d73d1b67SCezary Rojewski 	struct avs_soc_component *acomp = to_avs_soc_component(comp);
1506d73d1b67SCezary Rojewski 	size_t remaining = le32_to_cpu(manifest->priv.size);
1507d73d1b67SCezary Rojewski 	u32 offset;
1508d73d1b67SCezary Rojewski 	int ret;
1509d73d1b67SCezary Rojewski 
1510d73d1b67SCezary Rojewski 	ret = avs_tplg_vendor_array_lookup(tuples, remaining,
1511d73d1b67SCezary Rojewski 					   AVS_TKN_MANIFEST_NUM_LIBRARIES_U32, &offset);
1512d73d1b67SCezary Rojewski 	/* Manifest MUST begin with a header. */
1513d73d1b67SCezary Rojewski 	if (!ret && !offset)
1514d73d1b67SCezary Rojewski 		ret = -EINVAL;
1515d73d1b67SCezary Rojewski 	if (ret) {
1516d73d1b67SCezary Rojewski 		dev_err(comp->dev, "incorrect manifest format: %d\n", ret);
1517d73d1b67SCezary Rojewski 		return ret;
1518d73d1b67SCezary Rojewski 	}
1519d73d1b67SCezary Rojewski 
1520d73d1b67SCezary Rojewski 	/* Process header which precedes any of the dictionaries. */
1521d73d1b67SCezary Rojewski 	ret = avs_parse_tokens(comp, acomp->tplg, manifest_parsers,
1522d73d1b67SCezary Rojewski 			       ARRAY_SIZE(manifest_parsers), tuples, offset);
1523d73d1b67SCezary Rojewski 	if (ret < 0)
1524d73d1b67SCezary Rojewski 		return ret;
1525d73d1b67SCezary Rojewski 
1526d73d1b67SCezary Rojewski 	remaining -= offset;
1527d73d1b67SCezary Rojewski 	tuples = avs_tplg_vendor_array_at(tuples, offset);
1528d73d1b67SCezary Rojewski 
1529d73d1b67SCezary Rojewski 	ret = avs_tplg_vendor_array_lookup(tuples, remaining,
1530d73d1b67SCezary Rojewski 					   AVS_TKN_MANIFEST_NUM_AFMTS_U32, &offset);
1531d73d1b67SCezary Rojewski 	if (ret) {
1532d73d1b67SCezary Rojewski 		dev_err(comp->dev, "audio formats lookup failed: %d\n", ret);
1533d73d1b67SCezary Rojewski 		return ret;
1534d73d1b67SCezary Rojewski 	}
1535d73d1b67SCezary Rojewski 
1536d73d1b67SCezary Rojewski 	/* Libraries dictionary. */
1537d73d1b67SCezary Rojewski 	ret = avs_tplg_parse_libraries(comp, tuples, offset);
1538d73d1b67SCezary Rojewski 	if (ret < 0)
1539d73d1b67SCezary Rojewski 		return ret;
1540d73d1b67SCezary Rojewski 
1541d73d1b67SCezary Rojewski 	remaining -= offset;
1542d73d1b67SCezary Rojewski 	tuples = avs_tplg_vendor_array_at(tuples, offset);
1543d73d1b67SCezary Rojewski 
1544d73d1b67SCezary Rojewski 	ret = avs_tplg_vendor_array_lookup(tuples, remaining,
1545d73d1b67SCezary Rojewski 					   AVS_TKN_MANIFEST_NUM_MODCFGS_BASE_U32, &offset);
1546d73d1b67SCezary Rojewski 	if (ret) {
1547d73d1b67SCezary Rojewski 		dev_err(comp->dev, "modcfgs_base lookup failed: %d\n", ret);
1548d73d1b67SCezary Rojewski 		return ret;
1549d73d1b67SCezary Rojewski 	}
1550d73d1b67SCezary Rojewski 
1551d73d1b67SCezary Rojewski 	/* Audio formats dictionary. */
1552d73d1b67SCezary Rojewski 	ret = avs_tplg_parse_audio_formats(comp, tuples, offset);
1553d73d1b67SCezary Rojewski 	if (ret < 0)
1554d73d1b67SCezary Rojewski 		return ret;
1555d73d1b67SCezary Rojewski 
1556d73d1b67SCezary Rojewski 	remaining -= offset;
1557d73d1b67SCezary Rojewski 	tuples = avs_tplg_vendor_array_at(tuples, offset);
1558d73d1b67SCezary Rojewski 
1559d73d1b67SCezary Rojewski 	ret = avs_tplg_vendor_array_lookup(tuples, remaining,
1560d73d1b67SCezary Rojewski 					   AVS_TKN_MANIFEST_NUM_MODCFGS_EXT_U32, &offset);
1561d73d1b67SCezary Rojewski 	if (ret) {
1562d73d1b67SCezary Rojewski 		dev_err(comp->dev, "modcfgs_ext lookup failed: %d\n", ret);
1563d73d1b67SCezary Rojewski 		return ret;
1564d73d1b67SCezary Rojewski 	}
1565d73d1b67SCezary Rojewski 
1566d73d1b67SCezary Rojewski 	/* Module configs-base dictionary. */
1567d73d1b67SCezary Rojewski 	ret = avs_tplg_parse_modcfgs_base(comp, tuples, offset);
1568d73d1b67SCezary Rojewski 	if (ret < 0)
1569d73d1b67SCezary Rojewski 		return ret;
1570d73d1b67SCezary Rojewski 
1571d73d1b67SCezary Rojewski 	remaining -= offset;
1572d73d1b67SCezary Rojewski 	tuples = avs_tplg_vendor_array_at(tuples, offset);
1573d73d1b67SCezary Rojewski 
1574d73d1b67SCezary Rojewski 	ret = avs_tplg_vendor_array_lookup(tuples, remaining,
1575d73d1b67SCezary Rojewski 					   AVS_TKN_MANIFEST_NUM_PPLCFGS_U32, &offset);
1576d73d1b67SCezary Rojewski 	if (ret) {
1577d73d1b67SCezary Rojewski 		dev_err(comp->dev, "pplcfgs lookup failed: %d\n", ret);
1578d73d1b67SCezary Rojewski 		return ret;
1579d73d1b67SCezary Rojewski 	}
1580d73d1b67SCezary Rojewski 
1581d73d1b67SCezary Rojewski 	/* Module configs-ext dictionary. */
1582d73d1b67SCezary Rojewski 	ret = avs_tplg_parse_modcfgs_ext(comp, tuples, offset);
1583d73d1b67SCezary Rojewski 	if (ret < 0)
1584d73d1b67SCezary Rojewski 		return ret;
1585d73d1b67SCezary Rojewski 
1586d73d1b67SCezary Rojewski 	remaining -= offset;
1587d73d1b67SCezary Rojewski 	tuples = avs_tplg_vendor_array_at(tuples, offset);
1588d73d1b67SCezary Rojewski 
1589d73d1b67SCezary Rojewski 	ret = avs_tplg_vendor_array_lookup(tuples, remaining,
1590d73d1b67SCezary Rojewski 					   AVS_TKN_MANIFEST_NUM_BINDINGS_U32, &offset);
1591d73d1b67SCezary Rojewski 	if (ret) {
1592d73d1b67SCezary Rojewski 		dev_err(comp->dev, "bindings lookup failed: %d\n", ret);
1593d73d1b67SCezary Rojewski 		return ret;
1594d73d1b67SCezary Rojewski 	}
1595d73d1b67SCezary Rojewski 
1596d73d1b67SCezary Rojewski 	/* Pipeline configs dictionary. */
1597d73d1b67SCezary Rojewski 	ret = avs_tplg_parse_pplcfgs(comp, tuples, offset);
1598d73d1b67SCezary Rojewski 	if (ret < 0)
1599d73d1b67SCezary Rojewski 		return ret;
1600d73d1b67SCezary Rojewski 
1601d73d1b67SCezary Rojewski 	remaining -= offset;
1602d73d1b67SCezary Rojewski 	tuples = avs_tplg_vendor_array_at(tuples, offset);
1603d73d1b67SCezary Rojewski 
1604d73d1b67SCezary Rojewski 	/* Bindings dictionary. */
1605d73d1b67SCezary Rojewski 	return avs_tplg_parse_bindings(comp, tuples, remaining);
1606d73d1b67SCezary Rojewski }
1607d73d1b67SCezary Rojewski 
1608be2b81b5SAmadeusz Sławiński #define AVS_CONTROL_OPS_VOLUME	257
1609be2b81b5SAmadeusz Sławiński 
1610be2b81b5SAmadeusz Sławiński static const struct snd_soc_tplg_kcontrol_ops avs_control_ops[] = {
1611be2b81b5SAmadeusz Sławiński 	{
1612be2b81b5SAmadeusz Sławiński 		.id = AVS_CONTROL_OPS_VOLUME,
1613be2b81b5SAmadeusz Sławiński 		.get = avs_control_volume_get,
1614be2b81b5SAmadeusz Sławiński 		.put = avs_control_volume_put,
1615be2b81b5SAmadeusz Sławiński 	},
1616be2b81b5SAmadeusz Sławiński };
1617be2b81b5SAmadeusz Sławiński 
1618be2b81b5SAmadeusz Sławiński static const struct avs_tplg_token_parser control_parsers[] = {
1619be2b81b5SAmadeusz Sławiński 	{
1620be2b81b5SAmadeusz Sławiński 		.token = AVS_TKN_KCONTROL_ID_U32,
1621be2b81b5SAmadeusz Sławiński 		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
1622be2b81b5SAmadeusz Sławiński 		.offset = offsetof(struct avs_control_data, id),
1623be2b81b5SAmadeusz Sławiński 		.parse = avs_parse_word_token,
1624be2b81b5SAmadeusz Sławiński 	},
1625be2b81b5SAmadeusz Sławiński };
1626be2b81b5SAmadeusz Sławiński 
1627be2b81b5SAmadeusz Sławiński static int
avs_control_load(struct snd_soc_component * comp,int index,struct snd_kcontrol_new * ctmpl,struct snd_soc_tplg_ctl_hdr * hdr)1628be2b81b5SAmadeusz Sławiński avs_control_load(struct snd_soc_component *comp, int index, struct snd_kcontrol_new *ctmpl,
1629be2b81b5SAmadeusz Sławiński 		 struct snd_soc_tplg_ctl_hdr *hdr)
1630be2b81b5SAmadeusz Sławiński {
1631be2b81b5SAmadeusz Sławiński 	struct snd_soc_tplg_vendor_array *tuples;
1632be2b81b5SAmadeusz Sławiński 	struct snd_soc_tplg_mixer_control *tmc;
1633be2b81b5SAmadeusz Sławiński 	struct avs_control_data *ctl_data;
1634be2b81b5SAmadeusz Sławiński 	struct soc_mixer_control *mc;
1635be2b81b5SAmadeusz Sławiński 	size_t block_size;
1636be2b81b5SAmadeusz Sławiński 	int ret;
1637be2b81b5SAmadeusz Sławiński 
163819cfd69cSAmadeusz Sławiński 	switch (le32_to_cpu(hdr->type)) {
1639be2b81b5SAmadeusz Sławiński 	case SND_SOC_TPLG_TYPE_MIXER:
1640be2b81b5SAmadeusz Sławiński 		tmc = container_of(hdr, typeof(*tmc), hdr);
1641be2b81b5SAmadeusz Sławiński 		tuples = tmc->priv.array;
1642be2b81b5SAmadeusz Sławiński 		block_size = le32_to_cpu(tmc->priv.size);
1643be2b81b5SAmadeusz Sławiński 		break;
1644be2b81b5SAmadeusz Sławiński 	default:
1645be2b81b5SAmadeusz Sławiński 		return -EINVAL;
1646be2b81b5SAmadeusz Sławiński 	}
1647be2b81b5SAmadeusz Sławiński 
1648be2b81b5SAmadeusz Sławiński 	ctl_data = devm_kzalloc(comp->card->dev, sizeof(*ctl_data), GFP_KERNEL);
1649be2b81b5SAmadeusz Sławiński 	if (!ctl_data)
1650be2b81b5SAmadeusz Sławiński 		return -ENOMEM;
1651be2b81b5SAmadeusz Sławiński 
1652be2b81b5SAmadeusz Sławiński 	ret = parse_dictionary_entries(comp, tuples, block_size, ctl_data, 1, sizeof(*ctl_data),
1653be2b81b5SAmadeusz Sławiński 				       AVS_TKN_KCONTROL_ID_U32, control_parsers,
1654be2b81b5SAmadeusz Sławiński 				       ARRAY_SIZE(control_parsers));
1655be2b81b5SAmadeusz Sławiński 	if (ret)
1656be2b81b5SAmadeusz Sławiński 		return ret;
1657be2b81b5SAmadeusz Sławiński 
1658be2b81b5SAmadeusz Sławiński 	mc = (struct soc_mixer_control *)ctmpl->private_value;
1659be2b81b5SAmadeusz Sławiński 	mc->dobj.private = ctl_data;
1660be2b81b5SAmadeusz Sławiński 	return 0;
1661be2b81b5SAmadeusz Sławiński }
1662be2b81b5SAmadeusz Sławiński 
1663d73d1b67SCezary Rojewski static struct snd_soc_tplg_ops avs_tplg_ops = {
1664be2b81b5SAmadeusz Sławiński 	.io_ops			= avs_control_ops,
1665be2b81b5SAmadeusz Sławiński 	.io_ops_count		= ARRAY_SIZE(avs_control_ops),
1666be2b81b5SAmadeusz Sławiński 	.control_load		= avs_control_load,
1667d48c1adaSCezary Rojewski 	.dapm_route_load	= avs_route_load,
1668d73d1b67SCezary Rojewski 	.widget_load		= avs_widget_load,
1669be2b81b5SAmadeusz Sławiński 	.widget_ready		= avs_widget_ready,
1670d73d1b67SCezary Rojewski 	.dai_load		= avs_dai_load,
1671d73d1b67SCezary Rojewski 	.link_load		= avs_link_load,
1672d73d1b67SCezary Rojewski 	.manifest		= avs_manifest,
1673d73d1b67SCezary Rojewski };
1674d73d1b67SCezary Rojewski 
avs_tplg_new(struct snd_soc_component * comp)1675d73d1b67SCezary Rojewski struct avs_tplg *avs_tplg_new(struct snd_soc_component *comp)
1676d73d1b67SCezary Rojewski {
1677d73d1b67SCezary Rojewski 	struct avs_tplg *tplg;
1678d73d1b67SCezary Rojewski 
1679d73d1b67SCezary Rojewski 	tplg = devm_kzalloc(comp->card->dev, sizeof(*tplg), GFP_KERNEL);
1680d73d1b67SCezary Rojewski 	if (!tplg)
1681d73d1b67SCezary Rojewski 		return NULL;
1682d73d1b67SCezary Rojewski 
1683d73d1b67SCezary Rojewski 	tplg->comp = comp;
1684d73d1b67SCezary Rojewski 	INIT_LIST_HEAD(&tplg->path_tmpl_list);
1685d73d1b67SCezary Rojewski 
1686d73d1b67SCezary Rojewski 	return tplg;
1687d73d1b67SCezary Rojewski }
1688d73d1b67SCezary Rojewski 
avs_load_topology(struct snd_soc_component * comp,const char * filename)1689d73d1b67SCezary Rojewski int avs_load_topology(struct snd_soc_component *comp, const char *filename)
1690d73d1b67SCezary Rojewski {
1691d73d1b67SCezary Rojewski 	const struct firmware *fw;
1692d73d1b67SCezary Rojewski 	int ret;
1693d73d1b67SCezary Rojewski 
1694d73d1b67SCezary Rojewski 	ret = request_firmware(&fw, filename, comp->dev);
1695d73d1b67SCezary Rojewski 	if (ret < 0) {
1696d73d1b67SCezary Rojewski 		dev_err(comp->dev, "request topology \"%s\" failed: %d\n", filename, ret);
1697d73d1b67SCezary Rojewski 		return ret;
1698d73d1b67SCezary Rojewski 	}
1699d73d1b67SCezary Rojewski 
1700d73d1b67SCezary Rojewski 	ret = snd_soc_tplg_component_load(comp, &avs_tplg_ops, fw);
1701d73d1b67SCezary Rojewski 	if (ret < 0)
1702d73d1b67SCezary Rojewski 		dev_err(comp->dev, "load topology \"%s\" failed: %d\n", filename, ret);
1703d73d1b67SCezary Rojewski 
1704d73d1b67SCezary Rojewski 	release_firmware(fw);
1705d73d1b67SCezary Rojewski 	return ret;
1706d73d1b67SCezary Rojewski }
1707d73d1b67SCezary Rojewski 
avs_remove_topology(struct snd_soc_component * comp)1708d73d1b67SCezary Rojewski int avs_remove_topology(struct snd_soc_component *comp)
1709d73d1b67SCezary Rojewski {
1710d73d1b67SCezary Rojewski 	snd_soc_tplg_component_remove(comp);
1711d73d1b67SCezary Rojewski 
1712d73d1b67SCezary Rojewski 	return 0;
1713d73d1b67SCezary Rojewski }
1714