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