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 */
33 static int
avs_tplg_vendor_array_lookup(struct snd_soc_tplg_vendor_array * tuples,u32 block_size,u32 token,u32 * offset)34 avs_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 */
69 static int
avs_tplg_vendor_array_lookup_next(struct snd_soc_tplg_vendor_array * tuples,u32 block_size,u32 token,u32 * offset)70 avs_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 */
98 static int
avs_tplg_vendor_entry_size(struct snd_soc_tplg_vendor_array * tuples,u32 block_size,u32 entry_id_token,u32 * size)99 avs_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 */
121 struct 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
128 static int
avs_parse_uuid_token(struct snd_soc_component * comp,void * elem,void * object,u32 offset)129 avs_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
139 static int
avs_parse_bool_token(struct snd_soc_component * comp,void * elem,void * object,u32 offset)140 avs_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
150 static int
avs_parse_byte_token(struct snd_soc_component * comp,void * elem,void * object,u32 offset)151 avs_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
161 static int
avs_parse_short_token(struct snd_soc_component * comp,void * elem,void * object,u32 offset)162 avs_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
172 static int
avs_parse_word_token(struct snd_soc_component * comp,void * elem,void * object,u32 offset)173 avs_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
183 static int
avs_parse_string_token(struct snd_soc_component * comp,void * elem,void * object,u32 offset)184 avs_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
avs_parse_uuid_tokens(struct snd_soc_component * comp,void * object,const struct avs_tplg_token_parser * parsers,int count,struct snd_soc_tplg_vendor_array * tuples)194 static 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
avs_parse_string_tokens(struct snd_soc_component * comp,void * object,const struct avs_tplg_token_parser * parsers,int count,struct snd_soc_tplg_vendor_array * tuples)220 static 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
avs_parse_word_tokens(struct snd_soc_component * comp,void * object,const struct avs_tplg_token_parser * parsers,int count,struct snd_soc_tplg_vendor_array * tuples)246 static 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
avs_parse_tokens(struct snd_soc_component * comp,void * object,const struct avs_tplg_token_parser * parsers,size_t count,struct snd_soc_tplg_vendor_array * tuples,int priv_size)277 static 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) \
329 static int \
330 avs_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
346 AVS_DEFINE_PTR_PARSER(audio_format, struct avs_audio_format, fmts);
347 AVS_DEFINE_PTR_PARSER(modcfg_base, struct avs_tplg_modcfg_base, modcfgs_base);
348 AVS_DEFINE_PTR_PARSER(modcfg_ext, struct avs_tplg_modcfg_ext, modcfgs_ext);
349 AVS_DEFINE_PTR_PARSER(pplcfg, struct avs_tplg_pplcfg, pplcfgs);
350 AVS_DEFINE_PTR_PARSER(binding, struct avs_tplg_binding, bindings);
351
352 static int
parse_audio_format_bitfield(struct snd_soc_component * comp,void * elem,void * object,u32 offset)353 parse_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
parse_link_formatted_string(struct snd_soc_component * comp,void * elem,void * object,u32 offset)373 static 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
393 static int
parse_dictionary_header(struct snd_soc_component * comp,struct snd_soc_tplg_vendor_array * tuples,void ** dict,u32 * num_entries,size_t entry_size,u32 num_entries_token)394 parse_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
417 static int
parse_dictionary_entries(struct snd_soc_component * comp,struct snd_soc_tplg_vendor_array * tuples,u32 block_size,void * dict,u32 num_entries,size_t entry_size,u32 entry_id_token,const struct avs_tplg_token_parser * parsers,size_t num_parsers)418 parse_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
parse_dictionary(struct snd_soc_component * comp,struct snd_soc_tplg_vendor_array * tuples,u32 block_size,void ** dict,u32 * num_entries,size_t entry_size,u32 num_entries_token,u32 entry_id_token,const struct avs_tplg_token_parser * parsers,size_t num_parsers)451 static 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
473 static 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
avs_tplg_parse_libraries(struct snd_soc_component * comp,struct snd_soc_tplg_vendor_array * tuples,u32 block_size)482 static 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
495 static 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
avs_tplg_parse_audio_formats(struct snd_soc_component * comp,struct snd_soc_tplg_vendor_array * tuples,u32 block_size)546 static 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
560 static 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
avs_tplg_parse_modcfgs_base(struct snd_soc_component * comp,struct snd_soc_tplg_vendor_array * tuples,u32 block_size)587 static 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
601 static 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
790 static 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
811 static void
assign_copier_gtw_instance(struct snd_soc_component * comp,struct avs_tplg_modcfg_ext * cfg)812 assign_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
avs_tplg_parse_modcfg_ext(struct snd_soc_component * comp,struct avs_tplg_modcfg_ext * cfg,struct snd_soc_tplg_vendor_array * tuples,u32 block_size)835 static 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
avs_tplg_parse_modcfgs_ext(struct snd_soc_component * comp,struct snd_soc_tplg_vendor_array * tuples,u32 block_size)885 static 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
924 static 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
avs_tplg_parse_pplcfgs(struct snd_soc_component * comp,struct snd_soc_tplg_vendor_array * tuples,u32 block_size)957 static 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
971 static 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
avs_tplg_parse_bindings(struct snd_soc_component * comp,struct snd_soc_tplg_vendor_array * tuples,u32 block_size)1022 static 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
1036 static 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
1075 static struct avs_tplg_module *
avs_tplg_module_create(struct snd_soc_component * comp,struct avs_tplg_pipeline * owner,struct snd_soc_tplg_vendor_array * tuples,u32 block_size)1076 avs_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
1097 static 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
1118 static 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
1127 static struct avs_tplg_pipeline *
avs_tplg_pipeline_create(struct snd_soc_component * comp,struct avs_tplg_path * owner,struct snd_soc_tplg_vendor_array * tuples,u32 block_size)1128 avs_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
1213 static 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
1234 static struct avs_tplg_path *
avs_tplg_path_create(struct snd_soc_component * comp,struct avs_tplg_path_template * owner,struct snd_soc_tplg_vendor_array * tuples,u32 block_size,const struct avs_tplg_token_parser * parsers,u32 num_parsers)1235 avs_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
1292 static 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
parse_path_template(struct snd_soc_component * comp,struct snd_soc_tplg_vendor_array * tuples,u32 block_size,struct avs_tplg_path_template * template,const struct avs_tplg_token_parser * tmpl_tokens,u32 num_tmpl_tokens,const struct avs_tplg_token_parser * path_tokens,u32 num_path_tokens)1301 static 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
1347 static struct avs_tplg_path_template *
avs_tplg_path_template_create(struct snd_soc_component * comp,struct avs_tplg * owner,struct snd_soc_tplg_vendor_array * tuples,u32 block_size)1348 avs_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
avs_route_load(struct snd_soc_component * comp,int index,struct snd_soc_dapm_route * route)1371 static 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
avs_widget_load(struct snd_soc_component * comp,int index,struct snd_soc_dapm_widget * w,struct snd_soc_tplg_dapm_widget * dw)1396 static 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 tplg = acomp->tplg;
1409 mach = dev_get_platdata(comp->card->dev);
1410
1411 /* See parse_link_formatted_string() for dynamic naming when(s). */
1412 if (hweight_long(mach->mach_params.i2s_link_mask) == 1) {
1413 kfree(w->name);
1414 /* w->name is freed later by soc_tplg_dapm_widget_create() */
1415 w->name = kasprintf(GFP_KERNEL, dw->name, __ffs(mach->mach_params.i2s_link_mask));
1416 if (!w->name)
1417 return -ENOMEM;
1418 }
1419
1420 template = avs_tplg_path_template_create(comp, tplg, dw->priv.array,
1421 le32_to_cpu(dw->priv.size));
1422 if (IS_ERR(template)) {
1423 dev_err(comp->dev, "widget %s load failed: %ld\n", dw->name,
1424 PTR_ERR(template));
1425 return PTR_ERR(template);
1426 }
1427
1428 w->priv = template; /* link path information to widget */
1429 list_add_tail(&template->node, &tplg->path_tmpl_list);
1430 return 0;
1431 }
1432
avs_dai_load(struct snd_soc_component * comp,int index,struct snd_soc_dai_driver * dai_drv,struct snd_soc_tplg_pcm * pcm,struct snd_soc_dai * dai)1433 static int avs_dai_load(struct snd_soc_component *comp, int index,
1434 struct snd_soc_dai_driver *dai_drv, struct snd_soc_tplg_pcm *pcm,
1435 struct snd_soc_dai *dai)
1436 {
1437 if (pcm)
1438 dai_drv->ops = &avs_dai_fe_ops;
1439 return 0;
1440 }
1441
avs_link_load(struct snd_soc_component * comp,int index,struct snd_soc_dai_link * link,struct snd_soc_tplg_link_config * cfg)1442 static int avs_link_load(struct snd_soc_component *comp, int index, struct snd_soc_dai_link *link,
1443 struct snd_soc_tplg_link_config *cfg)
1444 {
1445 if (!link->no_pcm) {
1446 /* Stream control handled by IPCs. */
1447 link->nonatomic = true;
1448
1449 /* Open LINK (BE) pipes last and close them first to prevent xruns. */
1450 link->trigger[0] = SND_SOC_DPCM_TRIGGER_PRE;
1451 link->trigger[1] = SND_SOC_DPCM_TRIGGER_PRE;
1452 }
1453
1454 return 0;
1455 }
1456
1457 static const struct avs_tplg_token_parser manifest_parsers[] = {
1458 {
1459 .token = AVS_TKN_MANIFEST_NAME_STRING,
1460 .type = SND_SOC_TPLG_TUPLE_TYPE_STRING,
1461 .offset = offsetof(struct avs_tplg, name),
1462 .parse = parse_link_formatted_string,
1463 },
1464 {
1465 .token = AVS_TKN_MANIFEST_VERSION_U32,
1466 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
1467 .offset = offsetof(struct avs_tplg, version),
1468 .parse = avs_parse_word_token,
1469 },
1470 };
1471
avs_manifest(struct snd_soc_component * comp,int index,struct snd_soc_tplg_manifest * manifest)1472 static int avs_manifest(struct snd_soc_component *comp, int index,
1473 struct snd_soc_tplg_manifest *manifest)
1474 {
1475 struct snd_soc_tplg_vendor_array *tuples = manifest->priv.array;
1476 struct avs_soc_component *acomp = to_avs_soc_component(comp);
1477 size_t remaining = le32_to_cpu(manifest->priv.size);
1478 u32 offset;
1479 int ret;
1480
1481 ret = avs_tplg_vendor_array_lookup(tuples, remaining,
1482 AVS_TKN_MANIFEST_NUM_LIBRARIES_U32, &offset);
1483 /* Manifest MUST begin with a header. */
1484 if (!ret && !offset)
1485 ret = -EINVAL;
1486 if (ret) {
1487 dev_err(comp->dev, "incorrect manifest format: %d\n", ret);
1488 return ret;
1489 }
1490
1491 /* Process header which precedes any of the dictionaries. */
1492 ret = avs_parse_tokens(comp, acomp->tplg, manifest_parsers,
1493 ARRAY_SIZE(manifest_parsers), tuples, offset);
1494 if (ret < 0)
1495 return ret;
1496
1497 remaining -= offset;
1498 tuples = avs_tplg_vendor_array_at(tuples, offset);
1499
1500 ret = avs_tplg_vendor_array_lookup(tuples, remaining,
1501 AVS_TKN_MANIFEST_NUM_AFMTS_U32, &offset);
1502 if (ret) {
1503 dev_err(comp->dev, "audio formats lookup failed: %d\n", ret);
1504 return ret;
1505 }
1506
1507 /* Libraries dictionary. */
1508 ret = avs_tplg_parse_libraries(comp, tuples, offset);
1509 if (ret < 0)
1510 return ret;
1511
1512 remaining -= offset;
1513 tuples = avs_tplg_vendor_array_at(tuples, offset);
1514
1515 ret = avs_tplg_vendor_array_lookup(tuples, remaining,
1516 AVS_TKN_MANIFEST_NUM_MODCFGS_BASE_U32, &offset);
1517 if (ret) {
1518 dev_err(comp->dev, "modcfgs_base lookup failed: %d\n", ret);
1519 return ret;
1520 }
1521
1522 /* Audio formats dictionary. */
1523 ret = avs_tplg_parse_audio_formats(comp, tuples, offset);
1524 if (ret < 0)
1525 return ret;
1526
1527 remaining -= offset;
1528 tuples = avs_tplg_vendor_array_at(tuples, offset);
1529
1530 ret = avs_tplg_vendor_array_lookup(tuples, remaining,
1531 AVS_TKN_MANIFEST_NUM_MODCFGS_EXT_U32, &offset);
1532 if (ret) {
1533 dev_err(comp->dev, "modcfgs_ext lookup failed: %d\n", ret);
1534 return ret;
1535 }
1536
1537 /* Module configs-base dictionary. */
1538 ret = avs_tplg_parse_modcfgs_base(comp, tuples, offset);
1539 if (ret < 0)
1540 return ret;
1541
1542 remaining -= offset;
1543 tuples = avs_tplg_vendor_array_at(tuples, offset);
1544
1545 ret = avs_tplg_vendor_array_lookup(tuples, remaining,
1546 AVS_TKN_MANIFEST_NUM_PPLCFGS_U32, &offset);
1547 if (ret) {
1548 dev_err(comp->dev, "pplcfgs lookup failed: %d\n", ret);
1549 return ret;
1550 }
1551
1552 /* Module configs-ext dictionary. */
1553 ret = avs_tplg_parse_modcfgs_ext(comp, tuples, offset);
1554 if (ret < 0)
1555 return ret;
1556
1557 remaining -= offset;
1558 tuples = avs_tplg_vendor_array_at(tuples, offset);
1559
1560 ret = avs_tplg_vendor_array_lookup(tuples, remaining,
1561 AVS_TKN_MANIFEST_NUM_BINDINGS_U32, &offset);
1562 if (ret) {
1563 dev_err(comp->dev, "bindings lookup failed: %d\n", ret);
1564 return ret;
1565 }
1566
1567 /* Pipeline configs dictionary. */
1568 ret = avs_tplg_parse_pplcfgs(comp, tuples, offset);
1569 if (ret < 0)
1570 return ret;
1571
1572 remaining -= offset;
1573 tuples = avs_tplg_vendor_array_at(tuples, offset);
1574
1575 /* Bindings dictionary. */
1576 return avs_tplg_parse_bindings(comp, tuples, remaining);
1577 }
1578
1579 static struct snd_soc_tplg_ops avs_tplg_ops = {
1580 .dapm_route_load = avs_route_load,
1581 .widget_load = avs_widget_load,
1582 .dai_load = avs_dai_load,
1583 .link_load = avs_link_load,
1584 .manifest = avs_manifest,
1585 };
1586
avs_tplg_new(struct snd_soc_component * comp)1587 struct avs_tplg *avs_tplg_new(struct snd_soc_component *comp)
1588 {
1589 struct avs_tplg *tplg;
1590
1591 tplg = devm_kzalloc(comp->card->dev, sizeof(*tplg), GFP_KERNEL);
1592 if (!tplg)
1593 return NULL;
1594
1595 tplg->comp = comp;
1596 INIT_LIST_HEAD(&tplg->path_tmpl_list);
1597
1598 return tplg;
1599 }
1600
avs_load_topology(struct snd_soc_component * comp,const char * filename)1601 int avs_load_topology(struct snd_soc_component *comp, const char *filename)
1602 {
1603 const struct firmware *fw;
1604 int ret;
1605
1606 ret = request_firmware(&fw, filename, comp->dev);
1607 if (ret < 0) {
1608 dev_err(comp->dev, "request topology \"%s\" failed: %d\n", filename, ret);
1609 return ret;
1610 }
1611
1612 ret = snd_soc_tplg_component_load(comp, &avs_tplg_ops, fw);
1613 if (ret < 0)
1614 dev_err(comp->dev, "load topology \"%s\" failed: %d\n", filename, ret);
1615
1616 release_firmware(fw);
1617 return ret;
1618 }
1619
avs_remove_topology(struct snd_soc_component * comp)1620 int avs_remove_topology(struct snd_soc_component *comp)
1621 {
1622 snd_soc_tplg_component_remove(comp);
1623
1624 return 0;
1625 }
1626