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