Merge tag 'gpio-fixes-for-v5.19-rc6' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-block.git] / sound / soc / intel / avs / topology.c
CommitLineData
34ae2cd5
CR
1// SPDX-License-Identifier: GPL-2.0-only
2//
3// Copyright(c) 2021 Intel Corporation. All rights reserved.
4//
5// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
6// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
7//
8
d73d1b67 9#include <linux/firmware.h>
34ae2cd5
CR
10#include <linux/uuid.h>
11#include <sound/soc.h>
12#include <sound/soc-acpi.h>
13#include <sound/soc-topology.h>
14#include <uapi/sound/intel/avs/tokens.h>
15#include "avs.h"
16#include "topology.h"
17
18/* Get pointer to vendor array at the specified offset. */
19#define avs_tplg_vendor_array_at(array, offset) \
20 ((struct snd_soc_tplg_vendor_array *)((u8 *)array + offset))
21
22/* Get pointer to vendor array that is next in line. */
23#define avs_tplg_vendor_array_next(array) \
24 (avs_tplg_vendor_array_at(array, le32_to_cpu((array)->size)))
25
26/*
27 * Scan provided block of tuples for the specified token. If found,
28 * @offset is updated with position at which first matching token is
29 * located.
30 *
31 * Returns 0 on success, -ENOENT if not found and error code otherwise.
32 */
33static int
34avs_tplg_vendor_array_lookup(struct snd_soc_tplg_vendor_array *tuples,
35 u32 block_size, u32 token, u32 *offset)
36{
37 u32 pos = 0;
38
39 while (block_size > 0) {
40 struct snd_soc_tplg_vendor_value_elem *tuple;
41 u32 tuples_size = le32_to_cpu(tuples->size);
42
43 if (tuples_size > block_size)
44 return -EINVAL;
45
46 tuple = tuples->value;
47 if (le32_to_cpu(tuple->token) == token) {
48 *offset = pos;
49 return 0;
50 }
51
52 block_size -= tuples_size;
53 pos += tuples_size;
54 tuples = avs_tplg_vendor_array_next(tuples);
55 }
56
57 return -ENOENT;
58}
59
60/*
61 * See avs_tplg_vendor_array_lookup() for description.
62 *
63 * Behaves exactly like avs_tplg_vendor_lookup() but starts from the
64 * next vendor array in line. Useful when searching for the finish line
65 * of an arbitrary entry in a list of entries where each is composed of
66 * several vendor tuples and a specific token marks the beginning of
67 * a new entry block.
68 */
69static int
70avs_tplg_vendor_array_lookup_next(struct snd_soc_tplg_vendor_array *tuples,
71 u32 block_size, u32 token, u32 *offset)
72{
73 u32 tuples_size = le32_to_cpu(tuples->size);
74 int ret;
75
76 if (tuples_size > block_size)
77 return -EINVAL;
78
79 tuples = avs_tplg_vendor_array_next(tuples);
80 block_size -= tuples_size;
81
82 ret = avs_tplg_vendor_array_lookup(tuples, block_size, token, offset);
83 if (!ret)
84 *offset += tuples_size;
85 return ret;
86}
87
88/*
89 * Scan provided block of tuples for the specified token which marks
90 * the border of an entry block. Behavior is similar to
91 * avs_tplg_vendor_array_lookup() except 0 is also returned if no
92 * matching token has been found. In such case, returned @size is
93 * assigned to @block_size as the entire block belongs to the current
94 * entry.
95 *
96 * Returns 0 on success, error code otherwise.
97 */
98static int
99avs_tplg_vendor_entry_size(struct snd_soc_tplg_vendor_array *tuples,
100 u32 block_size, u32 entry_id_token, u32 *size)
101{
102 int ret;
103
104 ret = avs_tplg_vendor_array_lookup_next(tuples, block_size, entry_id_token, size);
105 if (ret == -ENOENT) {
106 *size = block_size;
107 ret = 0;
108 }
109
110 return ret;
111}
112
113/*
114 * Vendor tuple parsing descriptor.
115 *
116 * @token: vendor specific token that identifies tuple
117 * @type: tuple type, one of SND_SOC_TPLG_TUPLE_TYPE_XXX
118 * @offset: offset of a struct's field to initialize
119 * @parse: parsing function, extracts and assigns value to object's field
120 */
121struct avs_tplg_token_parser {
122 enum avs_tplg_token token;
123 u32 type;
124 u32 offset;
125 int (*parse)(struct snd_soc_component *comp, void *elem, void *object, u32 offset);
126};
127
128static int
129avs_parse_uuid_token(struct snd_soc_component *comp, void *elem, void *object, u32 offset)
130{
af2d146a 131 struct snd_soc_tplg_vendor_uuid_elem *tuple = elem;
34ae2cd5
CR
132 guid_t *val = (guid_t *)((u8 *)object + offset);
133
af2d146a 134 guid_copy((guid_t *)val, (const guid_t *)&tuple->uuid);
34ae2cd5
CR
135
136 return 0;
137}
138
139static int
140avs_parse_bool_token(struct snd_soc_component *comp, void *elem, void *object, u32 offset)
141{
142 struct snd_soc_tplg_vendor_value_elem *tuple = elem;
143 bool *val = (bool *)((u8 *)object + offset);
144
145 *val = le32_to_cpu(tuple->value);
146
147 return 0;
148}
149
150static int
151avs_parse_byte_token(struct snd_soc_component *comp, void *elem, void *object, u32 offset)
152{
153 struct snd_soc_tplg_vendor_value_elem *tuple = elem;
154 u8 *val = ((u8 *)object + offset);
155
156 *val = le32_to_cpu(tuple->value);
157
158 return 0;
159}
160
161static int
162avs_parse_short_token(struct snd_soc_component *comp, void *elem, void *object, u32 offset)
163{
164 struct snd_soc_tplg_vendor_value_elem *tuple = elem;
165 u16 *val = (u16 *)((u8 *)object + offset);
166
167 *val = le32_to_cpu(tuple->value);
168
169 return 0;
170}
171
172static int
173avs_parse_word_token(struct snd_soc_component *comp, void *elem, void *object, u32 offset)
174{
175 struct snd_soc_tplg_vendor_value_elem *tuple = elem;
176 u32 *val = (u32 *)((u8 *)object + offset);
177
178 *val = le32_to_cpu(tuple->value);
179
180 return 0;
181}
182
183static int
184avs_parse_string_token(struct snd_soc_component *comp, void *elem, void *object, u32 offset)
185{
186 struct snd_soc_tplg_vendor_string_elem *tuple = elem;
187 char *val = (char *)((u8 *)object + offset);
188
189 snprintf(val, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s", tuple->string);
190
191 return 0;
192}
193
194static int avs_parse_uuid_tokens(struct snd_soc_component *comp, void *object,
195 const struct avs_tplg_token_parser *parsers, int count,
196 struct snd_soc_tplg_vendor_array *tuples)
197{
198 struct snd_soc_tplg_vendor_uuid_elem *tuple;
199 int ret, i, j;
200
201 /* Parse element by element. */
202 for (i = 0; i < le32_to_cpu(tuples->num_elems); i++) {
203 tuple = &tuples->uuid[i];
204
205 for (j = 0; j < count; j++) {
206 /* Ignore non-UUID tokens. */
207 if (parsers[j].type != SND_SOC_TPLG_TUPLE_TYPE_UUID ||
208 parsers[j].token != le32_to_cpu(tuple->token))
209 continue;
210
211 ret = parsers[j].parse(comp, tuple, object, parsers[j].offset);
212 if (ret)
213 return ret;
214 }
215 }
216
217 return 0;
218}
219
220static int avs_parse_string_tokens(struct snd_soc_component *comp, void *object,
221 const struct avs_tplg_token_parser *parsers, int count,
222 struct snd_soc_tplg_vendor_array *tuples)
223{
224 struct snd_soc_tplg_vendor_string_elem *tuple;
225 int ret, i, j;
226
227 /* Parse element by element. */
228 for (i = 0; i < le32_to_cpu(tuples->num_elems); i++) {
229 tuple = &tuples->string[i];
230
231 for (j = 0; j < count; j++) {
232 /* Ignore non-string tokens. */
233 if (parsers[j].type != SND_SOC_TPLG_TUPLE_TYPE_STRING ||
234 parsers[j].token != le32_to_cpu(tuple->token))
235 continue;
236
237 ret = parsers[j].parse(comp, tuple, object, parsers[j].offset);
238 if (ret)
239 return ret;
240 }
241 }
242
243 return 0;
244}
245
246static int avs_parse_word_tokens(struct snd_soc_component *comp, void *object,
247 const struct avs_tplg_token_parser *parsers, int count,
248 struct snd_soc_tplg_vendor_array *tuples)
249{
250 struct snd_soc_tplg_vendor_value_elem *tuple;
251 int ret, i, j;
252
253 /* Parse element by element. */
254 for (i = 0; i < le32_to_cpu(tuples->num_elems); i++) {
255 tuple = &tuples->value[i];
256
257 for (j = 0; j < count; j++) {
258 /* Ignore non-integer tokens. */
259 if (!(parsers[j].type == SND_SOC_TPLG_TUPLE_TYPE_WORD ||
260 parsers[j].type == SND_SOC_TPLG_TUPLE_TYPE_SHORT ||
261 parsers[j].type == SND_SOC_TPLG_TUPLE_TYPE_BYTE ||
262 parsers[j].type == SND_SOC_TPLG_TUPLE_TYPE_BOOL))
263 continue;
264
265 if (parsers[j].token != le32_to_cpu(tuple->token))
266 continue;
267
268 ret = parsers[j].parse(comp, tuple, object, parsers[j].offset);
269 if (ret)
270 return ret;
271 }
272 }
273
274 return 0;
275}
276
277static int avs_parse_tokens(struct snd_soc_component *comp, void *object,
278 const struct avs_tplg_token_parser *parsers, size_t count,
279 struct snd_soc_tplg_vendor_array *tuples, int priv_size)
280{
281 int array_size, ret;
282
283 while (priv_size > 0) {
284 array_size = le32_to_cpu(tuples->size);
285
286 if (array_size <= 0) {
287 dev_err(comp->dev, "invalid array size 0x%x\n", array_size);
288 return -EINVAL;
289 }
290
291 /* Make sure there is enough data before parsing. */
292 priv_size -= array_size;
293 if (priv_size < 0) {
294 dev_err(comp->dev, "invalid array size 0x%x\n", array_size);
295 return -EINVAL;
296 }
297
298 switch (le32_to_cpu(tuples->type)) {
299 case SND_SOC_TPLG_TUPLE_TYPE_UUID:
300 ret = avs_parse_uuid_tokens(comp, object, parsers, count, tuples);
301 break;
302 case SND_SOC_TPLG_TUPLE_TYPE_STRING:
303 ret = avs_parse_string_tokens(comp, object, parsers, count, tuples);
304 break;
305 case SND_SOC_TPLG_TUPLE_TYPE_BOOL:
306 case SND_SOC_TPLG_TUPLE_TYPE_BYTE:
307 case SND_SOC_TPLG_TUPLE_TYPE_SHORT:
308 case SND_SOC_TPLG_TUPLE_TYPE_WORD:
309 ret = avs_parse_word_tokens(comp, object, parsers, count, tuples);
310 break;
311 default:
312 dev_err(comp->dev, "unknown token type %d\n", tuples->type);
313 ret = -EINVAL;
314 }
315
316 if (ret) {
317 dev_err(comp->dev, "parsing %zu tokens of %d type failed: %d\n",
318 count, tuples->type, ret);
319 return ret;
320 }
321
322 tuples = avs_tplg_vendor_array_next(tuples);
323 }
324
325 return 0;
326}
327
328#define AVS_DEFINE_PTR_PARSER(name, type, member) \
329static int \
330avs_parse_##name##_ptr(struct snd_soc_component *comp, void *elem, void *object, u32 offset) \
331{ \
332 struct snd_soc_tplg_vendor_value_elem *tuple = elem; \
333 struct avs_soc_component *acomp = to_avs_soc_component(comp); \
334 type **val = (type **)(object + offset); \
335 u32 idx; \
336 \
337 idx = le32_to_cpu(tuple->value); \
338 if (idx >= acomp->tplg->num_##member) \
339 return -EINVAL; \
340 \
341 *val = &acomp->tplg->member[idx]; \
342 \
343 return 0; \
344}
345
346AVS_DEFINE_PTR_PARSER(audio_format, struct avs_audio_format, fmts);
347AVS_DEFINE_PTR_PARSER(modcfg_base, struct avs_tplg_modcfg_base, modcfgs_base);
9e85ec40 348AVS_DEFINE_PTR_PARSER(modcfg_ext, struct avs_tplg_modcfg_ext, modcfgs_ext);
1fba2036
CR
349AVS_DEFINE_PTR_PARSER(pplcfg, struct avs_tplg_pplcfg, pplcfgs);
350AVS_DEFINE_PTR_PARSER(binding, struct avs_tplg_binding, bindings);
34ae2cd5
CR
351
352static int
353parse_audio_format_bitfield(struct snd_soc_component *comp, void *elem, void *object, u32 offset)
354{
355 struct snd_soc_tplg_vendor_value_elem *velem = elem;
356 struct avs_audio_format *audio_format = object;
357
358 switch (offset) {
359 case AVS_TKN_AFMT_NUM_CHANNELS_U32:
360 audio_format->num_channels = le32_to_cpu(velem->value);
361 break;
362 case AVS_TKN_AFMT_VALID_BIT_DEPTH_U32:
363 audio_format->valid_bit_depth = le32_to_cpu(velem->value);
364 break;
365 case AVS_TKN_AFMT_SAMPLE_TYPE_U32:
366 audio_format->sample_type = le32_to_cpu(velem->value);
367 break;
368 }
369
370 return 0;
371}
372
d48c1ada
CR
373static int parse_link_formatted_string(struct snd_soc_component *comp, void *elem,
374 void *object, u32 offset)
375{
376 struct snd_soc_tplg_vendor_string_elem *tuple = elem;
377 struct snd_soc_acpi_mach *mach = dev_get_platdata(comp->card->dev);
378 char *val = (char *)((u8 *)object + offset);
379
380 /*
381 * Dynamic naming - string formats, e.g.: ssp%d - supported only for
382 * topologies describing single device e.g.: an I2S codec on SSP0.
383 */
25b552f1 384 if (hweight_long(mach->mach_params.i2s_link_mask) != 1)
d48c1ada
CR
385 return avs_parse_string_token(comp, elem, object, offset);
386
387 snprintf(val, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, tuple->string,
25b552f1 388 __ffs(mach->mach_params.i2s_link_mask));
d48c1ada
CR
389
390 return 0;
391}
392
34ae2cd5
CR
393static int
394parse_dictionary_header(struct snd_soc_component *comp,
395 struct snd_soc_tplg_vendor_array *tuples,
396 void **dict, u32 *num_entries, size_t entry_size,
397 u32 num_entries_token)
398{
399 struct snd_soc_tplg_vendor_value_elem *tuple;
400
401 /* Dictionary header consists of single tuple - entry count. */
402 tuple = tuples->value;
403 if (le32_to_cpu(tuple->token) != num_entries_token) {
404 dev_err(comp->dev, "invalid dictionary header, expected: %d\n",
405 num_entries_token);
406 return -EINVAL;
407 }
408
409 *num_entries = le32_to_cpu(tuple->value);
410 *dict = devm_kcalloc(comp->card->dev, *num_entries, entry_size, GFP_KERNEL);
411 if (!*dict)
412 return -ENOMEM;
413
414 return 0;
415}
416
417static int
418parse_dictionary_entries(struct snd_soc_component *comp,
419 struct snd_soc_tplg_vendor_array *tuples, u32 block_size,
420 void *dict, u32 num_entries, size_t entry_size,
421 u32 entry_id_token,
422 const struct avs_tplg_token_parser *parsers, size_t num_parsers)
423{
424 void *pos = dict;
425 int i;
426
427 for (i = 0; i < num_entries; i++) {
428 u32 esize;
429 int ret;
430
431 ret = avs_tplg_vendor_entry_size(tuples, block_size,
432 entry_id_token, &esize);
433 if (ret)
434 return ret;
435
436 ret = avs_parse_tokens(comp, pos, parsers, num_parsers, tuples, esize);
437 if (ret < 0) {
438 dev_err(comp->dev, "parse entry: %d of type: %d failed: %d\n",
439 i, entry_id_token, ret);
440 return ret;
441 }
442
443 pos += entry_size;
444 block_size -= esize;
445 tuples = avs_tplg_vendor_array_at(tuples, esize);
446 }
447
448 return 0;
449}
450
451static int parse_dictionary(struct snd_soc_component *comp,
452 struct snd_soc_tplg_vendor_array *tuples, u32 block_size,
453 void **dict, u32 *num_entries, size_t entry_size,
454 u32 num_entries_token, u32 entry_id_token,
455 const struct avs_tplg_token_parser *parsers, size_t num_parsers)
456{
457 int ret;
458
459 ret = parse_dictionary_header(comp, tuples, dict, num_entries,
460 entry_size, num_entries_token);
461 if (ret)
462 return ret;
463
464 block_size -= le32_to_cpu(tuples->size);
465 /* With header parsed, move on to parsing entries. */
466 tuples = avs_tplg_vendor_array_next(tuples);
467
468 return parse_dictionary_entries(comp, tuples, block_size, *dict,
469 *num_entries, entry_size,
470 entry_id_token, parsers, num_parsers);
471}
472
473static const struct avs_tplg_token_parser library_parsers[] = {
474 {
475 .token = AVS_TKN_LIBRARY_NAME_STRING,
476 .type = SND_SOC_TPLG_TUPLE_TYPE_STRING,
477 .offset = offsetof(struct avs_tplg_library, name),
478 .parse = avs_parse_string_token,
479 },
480};
481
482static int avs_tplg_parse_libraries(struct snd_soc_component *comp,
483 struct snd_soc_tplg_vendor_array *tuples, u32 block_size)
484{
485 struct avs_soc_component *acomp = to_avs_soc_component(comp);
486 struct avs_tplg *tplg = acomp->tplg;
487
488 return parse_dictionary(comp, tuples, block_size, (void **)&tplg->libs,
489 &tplg->num_libs, sizeof(*tplg->libs),
490 AVS_TKN_MANIFEST_NUM_LIBRARIES_U32,
491 AVS_TKN_LIBRARY_ID_U32,
492 library_parsers, ARRAY_SIZE(library_parsers));
493}
494
495static const struct avs_tplg_token_parser audio_format_parsers[] = {
496 {
497 .token = AVS_TKN_AFMT_SAMPLE_RATE_U32,
498 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
499 .offset = offsetof(struct avs_audio_format, sampling_freq),
500 .parse = avs_parse_word_token,
501 },
502 {
503 .token = AVS_TKN_AFMT_BIT_DEPTH_U32,
504 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
505 .offset = offsetof(struct avs_audio_format, bit_depth),
506 .parse = avs_parse_word_token,
507 },
508 {
509 .token = AVS_TKN_AFMT_CHANNEL_MAP_U32,
510 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
511 .offset = offsetof(struct avs_audio_format, channel_map),
512 .parse = avs_parse_word_token,
513 },
514 {
515 .token = AVS_TKN_AFMT_CHANNEL_CFG_U32,
516 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
517 .offset = offsetof(struct avs_audio_format, channel_config),
518 .parse = avs_parse_word_token,
519 },
520 {
521 .token = AVS_TKN_AFMT_INTERLEAVING_U32,
522 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
523 .offset = offsetof(struct avs_audio_format, interleaving),
524 .parse = avs_parse_word_token,
525 },
526 {
527 .token = AVS_TKN_AFMT_NUM_CHANNELS_U32,
528 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
529 .offset = AVS_TKN_AFMT_NUM_CHANNELS_U32,
530 .parse = parse_audio_format_bitfield,
531 },
532 {
533 .token = AVS_TKN_AFMT_VALID_BIT_DEPTH_U32,
534 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
535 .offset = AVS_TKN_AFMT_VALID_BIT_DEPTH_U32,
536 .parse = parse_audio_format_bitfield,
537 },
538 {
539 .token = AVS_TKN_AFMT_SAMPLE_TYPE_U32,
540 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
541 .offset = AVS_TKN_AFMT_SAMPLE_TYPE_U32,
542 .parse = parse_audio_format_bitfield,
543 },
544};
545
546static int avs_tplg_parse_audio_formats(struct snd_soc_component *comp,
547 struct snd_soc_tplg_vendor_array *tuples,
548 u32 block_size)
549{
550 struct avs_soc_component *acomp = to_avs_soc_component(comp);
551 struct avs_tplg *tplg = acomp->tplg;
552
553 return parse_dictionary(comp, tuples, block_size, (void **)&tplg->fmts,
554 &tplg->num_fmts, sizeof(*tplg->fmts),
555 AVS_TKN_MANIFEST_NUM_AFMTS_U32,
556 AVS_TKN_AFMT_ID_U32,
557 audio_format_parsers, ARRAY_SIZE(audio_format_parsers));
558}
559
560static const struct avs_tplg_token_parser modcfg_base_parsers[] = {
561 {
562 .token = AVS_TKN_MODCFG_BASE_CPC_U32,
563 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
564 .offset = offsetof(struct avs_tplg_modcfg_base, cpc),
565 .parse = avs_parse_word_token,
566 },
567 {
568 .token = AVS_TKN_MODCFG_BASE_IBS_U32,
569 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
570 .offset = offsetof(struct avs_tplg_modcfg_base, ibs),
571 .parse = avs_parse_word_token,
572 },
573 {
574 .token = AVS_TKN_MODCFG_BASE_OBS_U32,
575 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
576 .offset = offsetof(struct avs_tplg_modcfg_base, obs),
577 .parse = avs_parse_word_token,
578 },
579 {
580 .token = AVS_TKN_MODCFG_BASE_PAGES_U32,
581 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
582 .offset = offsetof(struct avs_tplg_modcfg_base, is_pages),
583 .parse = avs_parse_word_token,
584 },
585};
586
587static int avs_tplg_parse_modcfgs_base(struct snd_soc_component *comp,
588 struct snd_soc_tplg_vendor_array *tuples,
589 u32 block_size)
590{
591 struct avs_soc_component *acomp = to_avs_soc_component(comp);
592 struct avs_tplg *tplg = acomp->tplg;
593
594 return parse_dictionary(comp, tuples, block_size, (void **)&tplg->modcfgs_base,
595 &tplg->num_modcfgs_base, sizeof(*tplg->modcfgs_base),
596 AVS_TKN_MANIFEST_NUM_MODCFGS_BASE_U32,
597 AVS_TKN_MODCFG_BASE_ID_U32,
598 modcfg_base_parsers, ARRAY_SIZE(modcfg_base_parsers));
599}
9e85ec40
CR
600
601static const struct avs_tplg_token_parser modcfg_ext_parsers[] = {
602 {
603 .token = AVS_TKN_MODCFG_EXT_TYPE_UUID,
604 .type = SND_SOC_TPLG_TUPLE_TYPE_UUID,
605 .offset = offsetof(struct avs_tplg_modcfg_ext, type),
606 .parse = avs_parse_uuid_token,
607 },
608 {
609 .token = AVS_TKN_MODCFG_CPR_OUT_AFMT_ID_U32,
610 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
611 .offset = offsetof(struct avs_tplg_modcfg_ext, copier.out_fmt),
612 .parse = avs_parse_audio_format_ptr,
613 },
614 {
615 .token = AVS_TKN_MODCFG_CPR_FEATURE_MASK_U32,
616 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
617 .offset = offsetof(struct avs_tplg_modcfg_ext, copier.feature_mask),
618 .parse = avs_parse_word_token,
619 },
620 {
621 .token = AVS_TKN_MODCFG_CPR_VINDEX_U8,
622 .type = SND_SOC_TPLG_TUPLE_TYPE_BYTE,
623 .offset = offsetof(struct avs_tplg_modcfg_ext, copier.vindex),
624 .parse = avs_parse_byte_token,
625 },
626 {
627 .token = AVS_TKN_MODCFG_CPR_DMA_TYPE_U32,
628 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
629 .offset = offsetof(struct avs_tplg_modcfg_ext, copier.dma_type),
630 .parse = avs_parse_word_token,
631 },
632 {
633 .token = AVS_TKN_MODCFG_CPR_DMABUFF_SIZE_U32,
634 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
635 .offset = offsetof(struct avs_tplg_modcfg_ext, copier.dma_buffer_size),
636 .parse = avs_parse_word_token,
637 },
638 {
639 .token = AVS_TKN_MODCFG_CPR_BLOB_FMT_ID_U32,
640 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
641 .offset = offsetof(struct avs_tplg_modcfg_ext, copier.blob_fmt),
642 .parse = avs_parse_audio_format_ptr,
643 },
644 {
645 .token = AVS_TKN_MODCFG_MICSEL_OUT_AFMT_ID_U32,
646 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
647 .offset = offsetof(struct avs_tplg_modcfg_ext, micsel.out_fmt),
648 .parse = avs_parse_audio_format_ptr,
649 },
650 {
651 .token = AVS_TKN_MODCFG_INTELWOV_CPC_LP_MODE_U32,
652 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
653 .offset = offsetof(struct avs_tplg_modcfg_ext, wov.cpc_lp_mode),
654 .parse = avs_parse_word_token,
655 },
656 {
657 .token = AVS_TKN_MODCFG_SRC_OUT_FREQ_U32,
658 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
659 .offset = offsetof(struct avs_tplg_modcfg_ext, src.out_freq),
660 .parse = avs_parse_word_token,
661 },
662 {
663 .token = AVS_TKN_MODCFG_MUX_REF_AFMT_ID_U32,
664 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
665 .offset = offsetof(struct avs_tplg_modcfg_ext, mux.ref_fmt),
666 .parse = avs_parse_audio_format_ptr,
667 },
668 {
669 .token = AVS_TKN_MODCFG_MUX_OUT_AFMT_ID_U32,
670 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
671 .offset = offsetof(struct avs_tplg_modcfg_ext, mux.out_fmt),
672 .parse = avs_parse_audio_format_ptr,
673 },
674 {
675 .token = AVS_TKN_MODCFG_AEC_REF_AFMT_ID_U32,
676 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
677 .offset = offsetof(struct avs_tplg_modcfg_ext, aec.ref_fmt),
678 .parse = avs_parse_audio_format_ptr,
679 },
680 {
681 .token = AVS_TKN_MODCFG_AEC_OUT_AFMT_ID_U32,
682 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
683 .offset = offsetof(struct avs_tplg_modcfg_ext, aec.out_fmt),
684 .parse = avs_parse_audio_format_ptr,
685 },
686 {
687 .token = AVS_TKN_MODCFG_AEC_CPC_LP_MODE_U32,
688 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
689 .offset = offsetof(struct avs_tplg_modcfg_ext, aec.cpc_lp_mode),
690 .parse = avs_parse_word_token,
691 },
692 {
693 .token = AVS_TKN_MODCFG_ASRC_OUT_FREQ_U32,
694 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
695 .offset = offsetof(struct avs_tplg_modcfg_ext, asrc.out_freq),
696 .parse = avs_parse_word_token,
697 },
698 {
699 .token = AVS_TKN_MODCFG_ASRC_MODE_U8,
700 .type = SND_SOC_TPLG_TUPLE_TYPE_BYTE,
701 .offset = offsetof(struct avs_tplg_modcfg_ext, asrc.mode),
702 .parse = avs_parse_byte_token,
703 },
704 {
705 .token = AVS_TKN_MODCFG_ASRC_DISABLE_JITTER_U8,
706 .type = SND_SOC_TPLG_TUPLE_TYPE_BYTE,
707 .offset = offsetof(struct avs_tplg_modcfg_ext, asrc.disable_jitter_buffer),
708 .parse = avs_parse_byte_token,
709 },
710 {
711 .token = AVS_TKN_MODCFG_UPDOWN_MIX_OUT_CHAN_CFG_U32,
712 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
713 .offset = offsetof(struct avs_tplg_modcfg_ext, updown_mix.out_channel_config),
714 .parse = avs_parse_word_token,
715 },
716 {
717 .token = AVS_TKN_MODCFG_UPDOWN_MIX_COEFF_SELECT_U32,
718 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
719 .offset = offsetof(struct avs_tplg_modcfg_ext, updown_mix.coefficients_select),
720 .parse = avs_parse_word_token,
721 },
722 {
723 .token = AVS_TKN_MODCFG_UPDOWN_MIX_COEFF_0_S32,
724 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
725 .offset = offsetof(struct avs_tplg_modcfg_ext, updown_mix.coefficients[0]),
726 .parse = avs_parse_word_token,
727 },
728 {
729 .token = AVS_TKN_MODCFG_UPDOWN_MIX_COEFF_1_S32,
730 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
731 .offset = offsetof(struct avs_tplg_modcfg_ext, updown_mix.coefficients[1]),
732 .parse = avs_parse_word_token,
733 },
734 {
735 .token = AVS_TKN_MODCFG_UPDOWN_MIX_COEFF_2_S32,
736 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
737 .offset = offsetof(struct avs_tplg_modcfg_ext, updown_mix.coefficients[2]),
738 .parse = avs_parse_word_token,
739 },
740 {
741 .token = AVS_TKN_MODCFG_UPDOWN_MIX_COEFF_3_S32,
742 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
743 .offset = offsetof(struct avs_tplg_modcfg_ext, updown_mix.coefficients[3]),
744 .parse = avs_parse_word_token,
745 },
746 {
747 .token = AVS_TKN_MODCFG_UPDOWN_MIX_COEFF_4_S32,
748 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
749 .offset = offsetof(struct avs_tplg_modcfg_ext, updown_mix.coefficients[4]),
750 .parse = avs_parse_word_token,
751 },
752 {
753 .token = AVS_TKN_MODCFG_UPDOWN_MIX_COEFF_5_S32,
754 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
755 .offset = offsetof(struct avs_tplg_modcfg_ext, updown_mix.coefficients[5]),
756 .parse = avs_parse_word_token,
757 },
758 {
759 .token = AVS_TKN_MODCFG_UPDOWN_MIX_COEFF_6_S32,
760 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
761 .offset = offsetof(struct avs_tplg_modcfg_ext, updown_mix.coefficients[6]),
762 .parse = avs_parse_word_token,
763 },
764 {
765 .token = AVS_TKN_MODCFG_UPDOWN_MIX_COEFF_7_S32,
766 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
767 .offset = offsetof(struct avs_tplg_modcfg_ext, updown_mix.coefficients[7]),
768 .parse = avs_parse_word_token,
769 },
770 {
771 .token = AVS_TKN_MODCFG_UPDOWN_MIX_CHAN_MAP_U32,
772 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
773 .offset = offsetof(struct avs_tplg_modcfg_ext, updown_mix.channel_map),
774 .parse = avs_parse_word_token,
775 },
776 {
777 .token = AVS_TKN_MODCFG_EXT_NUM_INPUT_PINS_U16,
778 .type = SND_SOC_TPLG_TUPLE_TYPE_SHORT,
779 .offset = offsetof(struct avs_tplg_modcfg_ext, generic.num_input_pins),
780 .parse = avs_parse_short_token,
781 },
782 {
783 .token = AVS_TKN_MODCFG_EXT_NUM_OUTPUT_PINS_U16,
784 .type = SND_SOC_TPLG_TUPLE_TYPE_SHORT,
785 .offset = offsetof(struct avs_tplg_modcfg_ext, generic.num_output_pins),
786 .parse = avs_parse_short_token,
787 },
788};
789
790static const struct avs_tplg_token_parser pin_format_parsers[] = {
791 {
792 .token = AVS_TKN_PIN_FMT_INDEX_U32,
793 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
794 .offset = offsetof(struct avs_tplg_pin_format, pin_index),
795 .parse = avs_parse_word_token,
796 },
797 {
798 .token = AVS_TKN_PIN_FMT_IOBS_U32,
799 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
800 .offset = offsetof(struct avs_tplg_pin_format, iobs),
801 .parse = avs_parse_word_token,
802 },
803 {
804 .token = AVS_TKN_PIN_FMT_AFMT_ID_U32,
805 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
806 .offset = offsetof(struct avs_tplg_pin_format, fmt),
807 .parse = avs_parse_audio_format_ptr,
808 },
809};
810
811static int avs_tplg_parse_modcfg_ext(struct snd_soc_component *comp,
812 struct avs_tplg_modcfg_ext *cfg,
813 struct snd_soc_tplg_vendor_array *tuples,
814 u32 block_size)
815{
816 u32 esize;
817 int ret;
818
819 /* See where pin block starts. */
820 ret = avs_tplg_vendor_entry_size(tuples, block_size,
821 AVS_TKN_PIN_FMT_INDEX_U32, &esize);
822 if (ret)
823 return ret;
824
825 ret = avs_parse_tokens(comp, cfg, modcfg_ext_parsers,
826 ARRAY_SIZE(modcfg_ext_parsers), tuples, esize);
827 if (ret)
828 return ret;
829
830 block_size -= esize;
831 /* Parse trailing in/out pin formats if any. */
832 if (block_size) {
833 struct avs_tplg_pin_format *pins;
834 u32 num_pins;
835
836 num_pins = cfg->generic.num_input_pins + cfg->generic.num_output_pins;
837 if (!num_pins)
838 return -EINVAL;
839
840 pins = devm_kcalloc(comp->card->dev, num_pins, sizeof(*pins), GFP_KERNEL);
841 if (!pins)
842 return -ENOMEM;
843
844 tuples = avs_tplg_vendor_array_at(tuples, esize);
845 ret = parse_dictionary_entries(comp, tuples, block_size,
846 pins, num_pins, sizeof(*pins),
847 AVS_TKN_PIN_FMT_INDEX_U32,
848 pin_format_parsers,
849 ARRAY_SIZE(pin_format_parsers));
850 if (ret)
851 return ret;
852 cfg->generic.pin_fmts = pins;
853 }
854
855 return 0;
856}
857
858static int avs_tplg_parse_modcfgs_ext(struct snd_soc_component *comp,
859 struct snd_soc_tplg_vendor_array *tuples,
860 u32 block_size)
861{
862 struct avs_soc_component *acomp = to_avs_soc_component(comp);
863 struct avs_tplg *tplg = acomp->tplg;
864 int ret, i;
865
866 ret = parse_dictionary_header(comp, tuples, (void **)&tplg->modcfgs_ext,
867 &tplg->num_modcfgs_ext,
868 sizeof(*tplg->modcfgs_ext),
869 AVS_TKN_MANIFEST_NUM_MODCFGS_EXT_U32);
870 if (ret)
871 return ret;
872
873 block_size -= le32_to_cpu(tuples->size);
874 /* With header parsed, move on to parsing entries. */
875 tuples = avs_tplg_vendor_array_next(tuples);
876
877 for (i = 0; i < tplg->num_modcfgs_ext; i++) {
878 struct avs_tplg_modcfg_ext *cfg = &tplg->modcfgs_ext[i];
879 u32 esize;
880
881 ret = avs_tplg_vendor_entry_size(tuples, block_size,
882 AVS_TKN_MODCFG_EXT_ID_U32, &esize);
883 if (ret)
884 return ret;
885
886 ret = avs_tplg_parse_modcfg_ext(comp, cfg, tuples, esize);
887 if (ret)
888 return ret;
889
890 block_size -= esize;
891 tuples = avs_tplg_vendor_array_at(tuples, esize);
892 }
893
894 return 0;
895}
1fba2036
CR
896
897static const struct avs_tplg_token_parser pplcfg_parsers[] = {
898 {
899 .token = AVS_TKN_PPLCFG_REQ_SIZE_U16,
900 .type = SND_SOC_TPLG_TUPLE_TYPE_SHORT,
901 .offset = offsetof(struct avs_tplg_pplcfg, req_size),
902 .parse = avs_parse_short_token,
903 },
904 {
905 .token = AVS_TKN_PPLCFG_PRIORITY_U8,
906 .type = SND_SOC_TPLG_TUPLE_TYPE_BYTE,
907 .offset = offsetof(struct avs_tplg_pplcfg, priority),
908 .parse = avs_parse_byte_token,
909 },
910 {
911 .token = AVS_TKN_PPLCFG_LOW_POWER_BOOL,
912 .type = SND_SOC_TPLG_TUPLE_TYPE_BOOL,
913 .offset = offsetof(struct avs_tplg_pplcfg, lp),
914 .parse = avs_parse_bool_token,
915 },
916 {
917 .token = AVS_TKN_PPLCFG_ATTRIBUTES_U16,
918 .type = SND_SOC_TPLG_TUPLE_TYPE_SHORT,
919 .offset = offsetof(struct avs_tplg_pplcfg, attributes),
920 .parse = avs_parse_short_token,
921 },
922 {
923 .token = AVS_TKN_PPLCFG_TRIGGER_U32,
924 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
925 .offset = offsetof(struct avs_tplg_pplcfg, trigger),
926 .parse = avs_parse_word_token,
927 },
928};
929
930static int avs_tplg_parse_pplcfgs(struct snd_soc_component *comp,
931 struct snd_soc_tplg_vendor_array *tuples,
932 u32 block_size)
933{
934 struct avs_soc_component *acomp = to_avs_soc_component(comp);
935 struct avs_tplg *tplg = acomp->tplg;
936
937 return parse_dictionary(comp, tuples, block_size, (void **)&tplg->pplcfgs,
938 &tplg->num_pplcfgs, sizeof(*tplg->pplcfgs),
939 AVS_TKN_MANIFEST_NUM_PPLCFGS_U32,
940 AVS_TKN_PPLCFG_ID_U32,
941 pplcfg_parsers, ARRAY_SIZE(pplcfg_parsers));
942}
943
944static const struct avs_tplg_token_parser binding_parsers[] = {
945 {
946 .token = AVS_TKN_BINDING_TARGET_TPLG_NAME_STRING,
947 .type = SND_SOC_TPLG_TUPLE_TYPE_STRING,
948 .offset = offsetof(struct avs_tplg_binding, target_tplg_name),
d48c1ada 949 .parse = parse_link_formatted_string,
1fba2036
CR
950 },
951 {
952 .token = AVS_TKN_BINDING_TARGET_PATH_TMPL_ID_U32,
953 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
954 .offset = offsetof(struct avs_tplg_binding, target_path_tmpl_id),
955 .parse = avs_parse_word_token,
956 },
957 {
958 .token = AVS_TKN_BINDING_TARGET_PPL_ID_U32,
959 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
960 .offset = offsetof(struct avs_tplg_binding, target_ppl_id),
961 .parse = avs_parse_word_token,
962 },
963 {
964 .token = AVS_TKN_BINDING_TARGET_MOD_ID_U32,
965 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
966 .offset = offsetof(struct avs_tplg_binding, target_mod_id),
967 .parse = avs_parse_word_token,
968 },
969 {
970 .token = AVS_TKN_BINDING_TARGET_MOD_PIN_U8,
971 .type = SND_SOC_TPLG_TUPLE_TYPE_BYTE,
972 .offset = offsetof(struct avs_tplg_binding, target_mod_pin),
973 .parse = avs_parse_byte_token,
974 },
975 {
976 .token = AVS_TKN_BINDING_MOD_ID_U32,
977 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
978 .offset = offsetof(struct avs_tplg_binding, mod_id),
979 .parse = avs_parse_word_token,
980 },
981 {
982 .token = AVS_TKN_BINDING_MOD_PIN_U8,
983 .type = SND_SOC_TPLG_TUPLE_TYPE_BYTE,
984 .offset = offsetof(struct avs_tplg_binding, mod_pin),
985 .parse = avs_parse_byte_token,
986 },
987 {
988 .token = AVS_TKN_BINDING_IS_SINK_U8,
989 .type = SND_SOC_TPLG_TUPLE_TYPE_BYTE,
990 .offset = offsetof(struct avs_tplg_binding, is_sink),
991 .parse = avs_parse_byte_token,
992 },
993};
994
995static int avs_tplg_parse_bindings(struct snd_soc_component *comp,
996 struct snd_soc_tplg_vendor_array *tuples,
997 u32 block_size)
998{
999 struct avs_soc_component *acomp = to_avs_soc_component(comp);
1000 struct avs_tplg *tplg = acomp->tplg;
1001
1002 return parse_dictionary(comp, tuples, block_size, (void **)&tplg->bindings,
1003 &tplg->num_bindings, sizeof(*tplg->bindings),
1004 AVS_TKN_MANIFEST_NUM_BINDINGS_U32,
1005 AVS_TKN_BINDING_ID_U32,
1006 binding_parsers, ARRAY_SIZE(binding_parsers));
1007}
276b83c8
CR
1008
1009static const struct avs_tplg_token_parser module_parsers[] = {
1010 {
1011 .token = AVS_TKN_MOD_ID_U32,
1012 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
1013 .offset = offsetof(struct avs_tplg_module, id),
1014 .parse = avs_parse_word_token,
1015 },
1016 {
1017 .token = AVS_TKN_MOD_MODCFG_BASE_ID_U32,
1018 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
1019 .offset = offsetof(struct avs_tplg_module, cfg_base),
1020 .parse = avs_parse_modcfg_base_ptr,
1021 },
1022 {
1023 .token = AVS_TKN_MOD_IN_AFMT_ID_U32,
1024 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
1025 .offset = offsetof(struct avs_tplg_module, in_fmt),
1026 .parse = avs_parse_audio_format_ptr,
1027 },
1028 {
1029 .token = AVS_TKN_MOD_CORE_ID_U8,
1030 .type = SND_SOC_TPLG_TUPLE_TYPE_BYTE,
1031 .offset = offsetof(struct avs_tplg_module, core_id),
1032 .parse = avs_parse_byte_token,
1033 },
1034 {
1035 .token = AVS_TKN_MOD_PROC_DOMAIN_U8,
1036 .type = SND_SOC_TPLG_TUPLE_TYPE_BYTE,
1037 .offset = offsetof(struct avs_tplg_module, domain),
1038 .parse = avs_parse_byte_token,
1039 },
1040 {
1041 .token = AVS_TKN_MOD_MODCFG_EXT_ID_U32,
1042 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
1043 .offset = offsetof(struct avs_tplg_module, cfg_ext),
1044 .parse = avs_parse_modcfg_ext_ptr,
1045 },
1046};
1047
1048static struct avs_tplg_module *
1049avs_tplg_module_create(struct snd_soc_component *comp, struct avs_tplg_pipeline *owner,
1050 struct snd_soc_tplg_vendor_array *tuples, u32 block_size)
1051{
1052 struct avs_tplg_module *module;
1053 int ret;
1054
1055 module = devm_kzalloc(comp->card->dev, sizeof(*module), GFP_KERNEL);
1056 if (!module)
1057 return ERR_PTR(-ENOMEM);
1058
1059 ret = avs_parse_tokens(comp, module, module_parsers,
1060 ARRAY_SIZE(module_parsers), tuples, block_size);
1061 if (ret < 0)
1062 return ERR_PTR(ret);
1063
1064 module->owner = owner;
1065 INIT_LIST_HEAD(&module->node);
1066
1067 return module;
1068}
1069
1070static const struct avs_tplg_token_parser pipeline_parsers[] = {
1071 {
1072 .token = AVS_TKN_PPL_ID_U32,
1073 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
1074 .offset = offsetof(struct avs_tplg_pipeline, id),
1075 .parse = avs_parse_word_token,
1076 },
1077 {
1078 .token = AVS_TKN_PPL_PPLCFG_ID_U32,
1079 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
1080 .offset = offsetof(struct avs_tplg_pipeline, cfg),
1081 .parse = avs_parse_pplcfg_ptr,
1082 },
1083 {
1084 .token = AVS_TKN_PPL_NUM_BINDING_IDS_U32,
1085 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
1086 .offset = offsetof(struct avs_tplg_pipeline, num_bindings),
1087 .parse = avs_parse_word_token,
1088 },
1089};
1090
1091static const struct avs_tplg_token_parser bindings_parsers[] = {
1092 {
1093 .token = AVS_TKN_PPL_BINDING_ID_U32,
1094 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
1095 .offset = 0, /* to treat pipeline->bindings as dictionary */
1096 .parse = avs_parse_binding_ptr,
1097 },
1098};
1099
1100static struct avs_tplg_pipeline *
1101avs_tplg_pipeline_create(struct snd_soc_component *comp, struct avs_tplg_path *owner,
1102 struct snd_soc_tplg_vendor_array *tuples, u32 block_size)
1103{
1104 struct avs_tplg_pipeline *pipeline;
1105 u32 modblk_size, offset;
1106 int ret;
1107
1108 pipeline = devm_kzalloc(comp->card->dev, sizeof(*pipeline), GFP_KERNEL);
1109 if (!pipeline)
1110 return ERR_PTR(-ENOMEM);
1111
1112 pipeline->owner = owner;
1113 INIT_LIST_HEAD(&pipeline->mod_list);
1114
1115 /* Pipeline header MUST be followed by at least one module. */
1116 ret = avs_tplg_vendor_array_lookup(tuples, block_size,
1117 AVS_TKN_MOD_ID_U32, &offset);
1118 if (!ret && !offset)
1119 ret = -EINVAL;
1120 if (ret)
1121 return ERR_PTR(ret);
1122
1123 /* Process header which precedes module sections. */
1124 ret = avs_parse_tokens(comp, pipeline, pipeline_parsers,
1125 ARRAY_SIZE(pipeline_parsers), tuples, offset);
1126 if (ret < 0)
1127 return ERR_PTR(ret);
1128
1129 block_size -= offset;
1130 tuples = avs_tplg_vendor_array_at(tuples, offset);
1131
1132 /* Optionally, binding sections follow module ones. */
1133 ret = avs_tplg_vendor_array_lookup_next(tuples, block_size,
1134 AVS_TKN_PPL_BINDING_ID_U32, &offset);
1135 if (ret) {
1136 if (ret != -ENOENT)
1137 return ERR_PTR(ret);
1138
1139 /* Does header information match actual block layout? */
1140 if (pipeline->num_bindings)
1141 return ERR_PTR(-EINVAL);
1142
1143 modblk_size = block_size;
1144 } else {
1145 pipeline->bindings = devm_kcalloc(comp->card->dev, pipeline->num_bindings,
1146 sizeof(*pipeline->bindings), GFP_KERNEL);
1147 if (!pipeline->bindings)
1148 return ERR_PTR(-ENOMEM);
1149
1150 modblk_size = offset;
1151 }
1152
1153 block_size -= modblk_size;
1154 do {
1155 struct avs_tplg_module *module;
1156 u32 esize;
1157
1158 ret = avs_tplg_vendor_entry_size(tuples, modblk_size,
1159 AVS_TKN_MOD_ID_U32, &esize);
1160 if (ret)
1161 return ERR_PTR(ret);
1162
1163 module = avs_tplg_module_create(comp, pipeline, tuples, esize);
1164 if (IS_ERR(module)) {
1165 dev_err(comp->dev, "parse module failed: %ld\n",
1166 PTR_ERR(module));
1167 return ERR_CAST(module);
1168 }
1169
1170 list_add_tail(&module->node, &pipeline->mod_list);
1171 modblk_size -= esize;
1172 tuples = avs_tplg_vendor_array_at(tuples, esize);
1173 } while (modblk_size > 0);
1174
1175 /* What's left is optional range of bindings. */
1176 ret = parse_dictionary_entries(comp, tuples, block_size, pipeline->bindings,
1177 pipeline->num_bindings, sizeof(*pipeline->bindings),
1178 AVS_TKN_PPL_BINDING_ID_U32,
1179 bindings_parsers, ARRAY_SIZE(bindings_parsers));
1180 if (ret)
1181 return ERR_PTR(ret);
1182
1183 return pipeline;
1184}
eee475bb
CR
1185
1186static const struct avs_tplg_token_parser path_parsers[] = {
1187 {
1188 .token = AVS_TKN_PATH_ID_U32,
1189 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
1190 .offset = offsetof(struct avs_tplg_path, id),
1191 .parse = avs_parse_word_token,
1192 },
1193 {
1194 .token = AVS_TKN_PATH_FE_FMT_ID_U32,
1195 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
1196 .offset = offsetof(struct avs_tplg_path, fe_fmt),
1197 .parse = avs_parse_audio_format_ptr,
1198 },
1199 {
1200 .token = AVS_TKN_PATH_BE_FMT_ID_U32,
1201 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
1202 .offset = offsetof(struct avs_tplg_path, be_fmt),
1203 .parse = avs_parse_audio_format_ptr,
1204 },
1205};
1206
1207static struct avs_tplg_path *
1208avs_tplg_path_create(struct snd_soc_component *comp, struct avs_tplg_path_template *owner,
1209 struct snd_soc_tplg_vendor_array *tuples, u32 block_size,
1210 const struct avs_tplg_token_parser *parsers, u32 num_parsers)
1211{
1212 struct avs_tplg_pipeline *pipeline;
1213 struct avs_tplg_path *path;
1214 u32 offset;
1215 int ret;
1216
1217 path = devm_kzalloc(comp->card->dev, sizeof(*path), GFP_KERNEL);
1218 if (!path)
1219 return ERR_PTR(-ENOMEM);
1220
1221 path->owner = owner;
1222 INIT_LIST_HEAD(&path->ppl_list);
1223 INIT_LIST_HEAD(&path->node);
1224
1225 /* Path header MAY be followed by one or more pipelines. */
1226 ret = avs_tplg_vendor_array_lookup(tuples, block_size,
1227 AVS_TKN_PPL_ID_U32, &offset);
1228 if (ret == -ENOENT)
1229 offset = block_size;
1230 else if (ret)
1231 return ERR_PTR(ret);
1232 else if (!offset)
1233 return ERR_PTR(-EINVAL);
1234
1235 /* Process header which precedes pipeline sections. */
1236 ret = avs_parse_tokens(comp, path, parsers, num_parsers, tuples, offset);
1237 if (ret < 0)
1238 return ERR_PTR(ret);
1239
1240 block_size -= offset;
1241 tuples = avs_tplg_vendor_array_at(tuples, offset);
1242 while (block_size > 0) {
1243 u32 esize;
1244
1245 ret = avs_tplg_vendor_entry_size(tuples, block_size,
1246 AVS_TKN_PPL_ID_U32, &esize);
1247 if (ret)
1248 return ERR_PTR(ret);
1249
1250 pipeline = avs_tplg_pipeline_create(comp, path, tuples, esize);
1251 if (IS_ERR(pipeline)) {
1252 dev_err(comp->dev, "parse pipeline failed: %ld\n",
1253 PTR_ERR(pipeline));
1254 return ERR_CAST(pipeline);
1255 }
1256
1257 list_add_tail(&pipeline->node, &path->ppl_list);
1258 block_size -= esize;
1259 tuples = avs_tplg_vendor_array_at(tuples, esize);
1260 }
1261
1262 return path;
1263}
1264
1265static const struct avs_tplg_token_parser path_tmpl_parsers[] = {
1266 {
1267 .token = AVS_TKN_PATH_TMPL_ID_U32,
1268 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
1269 .offset = offsetof(struct avs_tplg_path_template, id),
1270 .parse = avs_parse_word_token,
1271 },
1272};
1273
1274static int parse_path_template(struct snd_soc_component *comp,
1275 struct snd_soc_tplg_vendor_array *tuples, u32 block_size,
1276 struct avs_tplg_path_template *template,
1277 const struct avs_tplg_token_parser *tmpl_tokens, u32 num_tmpl_tokens,
1278 const struct avs_tplg_token_parser *path_tokens, u32 num_path_tokens)
1279{
1280 struct avs_tplg_path *path;
1281 u32 offset;
1282 int ret;
1283
1284 /* Path template header MUST be followed by at least one path variant. */
1285 ret = avs_tplg_vendor_array_lookup(tuples, block_size,
1286 AVS_TKN_PATH_ID_U32, &offset);
1287 if (ret)
1288 return ret;
1289
1290 /* Process header which precedes path variants sections. */
1291 ret = avs_parse_tokens(comp, template, tmpl_tokens, num_tmpl_tokens, tuples, offset);
1292 if (ret < 0)
1293 return ret;
1294
1295 block_size -= offset;
1296 tuples = avs_tplg_vendor_array_at(tuples, offset);
1297 do {
1298 u32 esize;
1299
1300 ret = avs_tplg_vendor_entry_size(tuples, block_size,
1301 AVS_TKN_PATH_ID_U32, &esize);
1302 if (ret)
1303 return ret;
1304
1305 path = avs_tplg_path_create(comp, template, tuples, esize, path_tokens,
1306 num_path_tokens);
1307 if (IS_ERR(path)) {
1308 dev_err(comp->dev, "parse path failed: %ld\n", PTR_ERR(path));
1309 return PTR_ERR(path);
1310 }
1311
1312 list_add_tail(&path->node, &template->path_list);
1313 block_size -= esize;
1314 tuples = avs_tplg_vendor_array_at(tuples, esize);
1315 } while (block_size > 0);
1316
1317 return 0;
1318}
1319
1320static struct avs_tplg_path_template *
1321avs_tplg_path_template_create(struct snd_soc_component *comp, struct avs_tplg *owner,
1322 struct snd_soc_tplg_vendor_array *tuples, u32 block_size)
1323{
1324 struct avs_tplg_path_template *template;
1325 int ret;
1326
1327 template = devm_kzalloc(comp->card->dev, sizeof(*template), GFP_KERNEL);
1328 if (!template)
1329 return ERR_PTR(-ENOMEM);
1330
1331 template->owner = owner; /* Used to access component tplg is assigned to. */
1332 INIT_LIST_HEAD(&template->path_list);
1333 INIT_LIST_HEAD(&template->node);
1334
1335 ret = parse_path_template(comp, tuples, block_size, template, path_tmpl_parsers,
1336 ARRAY_SIZE(path_tmpl_parsers), path_parsers,
1337 ARRAY_SIZE(path_parsers));
1338 if (ret)
1339 return ERR_PTR(ret);
1340
1341 return template;
1342}
d73d1b67 1343
d48c1ada
CR
1344static int avs_route_load(struct snd_soc_component *comp, int index,
1345 struct snd_soc_dapm_route *route)
1346{
1347 struct snd_soc_acpi_mach *mach = dev_get_platdata(comp->card->dev);
1348 size_t len = SNDRV_CTL_ELEM_ID_NAME_MAXLEN;
1349 char buf[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
1350 u32 port;
1351
1352 /* See parse_link_formatted_string() for dynamic naming when(s). */
25b552f1
PM
1353 if (hweight_long(mach->mach_params.i2s_link_mask) == 1) {
1354 port = __ffs(mach->mach_params.i2s_link_mask);
d48c1ada
CR
1355
1356 snprintf(buf, len, route->source, port);
1357 strncpy((char *)route->source, buf, len);
1358 snprintf(buf, len, route->sink, port);
1359 strncpy((char *)route->sink, buf, len);
1360 if (route->control) {
1361 snprintf(buf, len, route->control, port);
1362 strncpy((char *)route->control, buf, len);
1363 }
1364 }
1365
1366 return 0;
1367}
1368
d73d1b67
CR
1369static int avs_widget_load(struct snd_soc_component *comp, int index,
1370 struct snd_soc_dapm_widget *w,
1371 struct snd_soc_tplg_dapm_widget *dw)
1372{
1373 struct snd_soc_acpi_mach *mach;
1374 struct avs_tplg_path_template *template;
1375 struct avs_soc_component *acomp = to_avs_soc_component(comp);
1376 struct avs_tplg *tplg;
1377
1378 if (!le32_to_cpu(dw->priv.size))
1379 return 0;
1380
1381 tplg = acomp->tplg;
1382 mach = dev_get_platdata(comp->card->dev);
1383
d48c1ada 1384 /* See parse_link_formatted_string() for dynamic naming when(s). */
25b552f1 1385 if (hweight_long(mach->mach_params.i2s_link_mask) == 1) {
d48c1ada
CR
1386 kfree(w->name);
1387 /* w->name is freed later by soc_tplg_dapm_widget_create() */
25b552f1 1388 w->name = kasprintf(GFP_KERNEL, dw->name, __ffs(mach->mach_params.i2s_link_mask));
d48c1ada
CR
1389 if (!w->name)
1390 return -ENOMEM;
1391 }
1392
d73d1b67
CR
1393 template = avs_tplg_path_template_create(comp, tplg, dw->priv.array,
1394 le32_to_cpu(dw->priv.size));
1395 if (IS_ERR(template)) {
1396 dev_err(comp->dev, "widget %s load failed: %ld\n", dw->name,
1397 PTR_ERR(template));
1398 return PTR_ERR(template);
1399 }
1400
1401 w->priv = template; /* link path information to widget */
1402 list_add_tail(&template->node, &tplg->path_tmpl_list);
1403 return 0;
1404}
1405
1406static int avs_dai_load(struct snd_soc_component *comp, int index,
1407 struct snd_soc_dai_driver *dai_drv, struct snd_soc_tplg_pcm *pcm,
1408 struct snd_soc_dai *dai)
1409{
1410 if (pcm)
1411 dai_drv->ops = &avs_dai_fe_ops;
1412 return 0;
1413}
1414
1415static int avs_link_load(struct snd_soc_component *comp, int index, struct snd_soc_dai_link *link,
1416 struct snd_soc_tplg_link_config *cfg)
1417{
1418 if (!link->no_pcm) {
1419 /* Stream control handled by IPCs. */
1420 link->nonatomic = true;
1421
1422 /* Open LINK (BE) pipes last and close them first to prevent xruns. */
1423 link->trigger[0] = SND_SOC_DPCM_TRIGGER_PRE;
1424 link->trigger[1] = SND_SOC_DPCM_TRIGGER_PRE;
1425 }
1426
1427 return 0;
1428}
1429
1430static const struct avs_tplg_token_parser manifest_parsers[] = {
1431 {
1432 .token = AVS_TKN_MANIFEST_NAME_STRING,
1433 .type = SND_SOC_TPLG_TUPLE_TYPE_STRING,
1434 .offset = offsetof(struct avs_tplg, name),
d48c1ada 1435 .parse = parse_link_formatted_string,
d73d1b67
CR
1436 },
1437 {
1438 .token = AVS_TKN_MANIFEST_VERSION_U32,
1439 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
1440 .offset = offsetof(struct avs_tplg, version),
1441 .parse = avs_parse_word_token,
1442 },
1443};
1444
1445static int avs_manifest(struct snd_soc_component *comp, int index,
1446 struct snd_soc_tplg_manifest *manifest)
1447{
1448 struct snd_soc_tplg_vendor_array *tuples = manifest->priv.array;
1449 struct avs_soc_component *acomp = to_avs_soc_component(comp);
1450 size_t remaining = le32_to_cpu(manifest->priv.size);
1451 u32 offset;
1452 int ret;
1453
1454 ret = avs_tplg_vendor_array_lookup(tuples, remaining,
1455 AVS_TKN_MANIFEST_NUM_LIBRARIES_U32, &offset);
1456 /* Manifest MUST begin with a header. */
1457 if (!ret && !offset)
1458 ret = -EINVAL;
1459 if (ret) {
1460 dev_err(comp->dev, "incorrect manifest format: %d\n", ret);
1461 return ret;
1462 }
1463
1464 /* Process header which precedes any of the dictionaries. */
1465 ret = avs_parse_tokens(comp, acomp->tplg, manifest_parsers,
1466 ARRAY_SIZE(manifest_parsers), tuples, offset);
1467 if (ret < 0)
1468 return ret;
1469
1470 remaining -= offset;
1471 tuples = avs_tplg_vendor_array_at(tuples, offset);
1472
1473 ret = avs_tplg_vendor_array_lookup(tuples, remaining,
1474 AVS_TKN_MANIFEST_NUM_AFMTS_U32, &offset);
1475 if (ret) {
1476 dev_err(comp->dev, "audio formats lookup failed: %d\n", ret);
1477 return ret;
1478 }
1479
1480 /* Libraries dictionary. */
1481 ret = avs_tplg_parse_libraries(comp, tuples, offset);
1482 if (ret < 0)
1483 return ret;
1484
1485 remaining -= offset;
1486 tuples = avs_tplg_vendor_array_at(tuples, offset);
1487
1488 ret = avs_tplg_vendor_array_lookup(tuples, remaining,
1489 AVS_TKN_MANIFEST_NUM_MODCFGS_BASE_U32, &offset);
1490 if (ret) {
1491 dev_err(comp->dev, "modcfgs_base lookup failed: %d\n", ret);
1492 return ret;
1493 }
1494
1495 /* Audio formats dictionary. */
1496 ret = avs_tplg_parse_audio_formats(comp, tuples, offset);
1497 if (ret < 0)
1498 return ret;
1499
1500 remaining -= offset;
1501 tuples = avs_tplg_vendor_array_at(tuples, offset);
1502
1503 ret = avs_tplg_vendor_array_lookup(tuples, remaining,
1504 AVS_TKN_MANIFEST_NUM_MODCFGS_EXT_U32, &offset);
1505 if (ret) {
1506 dev_err(comp->dev, "modcfgs_ext lookup failed: %d\n", ret);
1507 return ret;
1508 }
1509
1510 /* Module configs-base dictionary. */
1511 ret = avs_tplg_parse_modcfgs_base(comp, tuples, offset);
1512 if (ret < 0)
1513 return ret;
1514
1515 remaining -= offset;
1516 tuples = avs_tplg_vendor_array_at(tuples, offset);
1517
1518 ret = avs_tplg_vendor_array_lookup(tuples, remaining,
1519 AVS_TKN_MANIFEST_NUM_PPLCFGS_U32, &offset);
1520 if (ret) {
1521 dev_err(comp->dev, "pplcfgs lookup failed: %d\n", ret);
1522 return ret;
1523 }
1524
1525 /* Module configs-ext dictionary. */
1526 ret = avs_tplg_parse_modcfgs_ext(comp, tuples, offset);
1527 if (ret < 0)
1528 return ret;
1529
1530 remaining -= offset;
1531 tuples = avs_tplg_vendor_array_at(tuples, offset);
1532
1533 ret = avs_tplg_vendor_array_lookup(tuples, remaining,
1534 AVS_TKN_MANIFEST_NUM_BINDINGS_U32, &offset);
1535 if (ret) {
1536 dev_err(comp->dev, "bindings lookup failed: %d\n", ret);
1537 return ret;
1538 }
1539
1540 /* Pipeline configs dictionary. */
1541 ret = avs_tplg_parse_pplcfgs(comp, tuples, offset);
1542 if (ret < 0)
1543 return ret;
1544
1545 remaining -= offset;
1546 tuples = avs_tplg_vendor_array_at(tuples, offset);
1547
1548 /* Bindings dictionary. */
1549 return avs_tplg_parse_bindings(comp, tuples, remaining);
1550}
1551
1552static struct snd_soc_tplg_ops avs_tplg_ops = {
d48c1ada 1553 .dapm_route_load = avs_route_load,
d73d1b67
CR
1554 .widget_load = avs_widget_load,
1555 .dai_load = avs_dai_load,
1556 .link_load = avs_link_load,
1557 .manifest = avs_manifest,
1558};
1559
1560struct avs_tplg *avs_tplg_new(struct snd_soc_component *comp)
1561{
1562 struct avs_tplg *tplg;
1563
1564 tplg = devm_kzalloc(comp->card->dev, sizeof(*tplg), GFP_KERNEL);
1565 if (!tplg)
1566 return NULL;
1567
1568 tplg->comp = comp;
1569 INIT_LIST_HEAD(&tplg->path_tmpl_list);
1570
1571 return tplg;
1572}
1573
1574int avs_load_topology(struct snd_soc_component *comp, const char *filename)
1575{
1576 const struct firmware *fw;
1577 int ret;
1578
1579 ret = request_firmware(&fw, filename, comp->dev);
1580 if (ret < 0) {
1581 dev_err(comp->dev, "request topology \"%s\" failed: %d\n", filename, ret);
1582 return ret;
1583 }
1584
1585 ret = snd_soc_tplg_component_load(comp, &avs_tplg_ops, fw);
1586 if (ret < 0)
1587 dev_err(comp->dev, "load topology \"%s\" failed: %d\n", filename, ret);
1588
1589 release_firmware(fw);
1590 return ret;
1591}
1592
1593int avs_remove_topology(struct snd_soc_component *comp)
1594{
1595 snd_soc_tplg_component_remove(comp);
1596
1597 return 0;
1598}