1 // SPDX-License-Identifier: GPL-2.0-only
3 // Copyright(c) 2021 Intel Corporation. All rights reserved.
5 // Authors: Cezary Rojewski <cezary.rojewski@intel.com>
6 // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
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>
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))
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)))
27 * Scan provided block of tuples for the specified token. If found,
28 * @offset is updated with position at which first matching token is
31 * Returns 0 on success, -ENOENT if not found and error code otherwise.
34 avs_tplg_vendor_array_lookup(struct snd_soc_tplg_vendor_array *tuples,
35 u32 block_size, u32 token, u32 *offset)
39 while (block_size > 0) {
40 struct snd_soc_tplg_vendor_value_elem *tuple;
41 u32 tuples_size = le32_to_cpu(tuples->size);
43 if (tuples_size > block_size)
46 tuple = tuples->value;
47 if (le32_to_cpu(tuple->token) == token) {
52 block_size -= tuples_size;
54 tuples = avs_tplg_vendor_array_next(tuples);
61 * See avs_tplg_vendor_array_lookup() for description.
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
70 avs_tplg_vendor_array_lookup_next(struct snd_soc_tplg_vendor_array *tuples,
71 u32 block_size, u32 token, u32 *offset)
73 u32 tuples_size = le32_to_cpu(tuples->size);
76 if (tuples_size > block_size)
79 tuples = avs_tplg_vendor_array_next(tuples);
80 block_size -= tuples_size;
82 ret = avs_tplg_vendor_array_lookup(tuples, block_size, token, offset);
84 *offset += tuples_size;
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
96 * Returns 0 on success, error code otherwise.
99 avs_tplg_vendor_entry_size(struct snd_soc_tplg_vendor_array *tuples,
100 u32 block_size, u32 entry_id_token, u32 *size)
104 ret = avs_tplg_vendor_array_lookup_next(tuples, block_size, entry_id_token, size);
105 if (ret == -ENOENT) {
114 * Vendor tuple parsing descriptor.
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
121 struct avs_tplg_token_parser {
122 enum avs_tplg_token token;
125 int (*parse)(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)
131 struct snd_soc_tplg_vendor_uuid_elem *tuple = elem;
132 guid_t *val = (guid_t *)((u8 *)object + offset);
134 guid_copy((guid_t *)val, (const guid_t *)&tuple->uuid);
140 avs_parse_bool_token(struct snd_soc_component *comp, void *elem, void *object, u32 offset)
142 struct snd_soc_tplg_vendor_value_elem *tuple = elem;
143 bool *val = (bool *)((u8 *)object + offset);
145 *val = le32_to_cpu(tuple->value);
151 avs_parse_byte_token(struct snd_soc_component *comp, void *elem, void *object, u32 offset)
153 struct snd_soc_tplg_vendor_value_elem *tuple = elem;
154 u8 *val = ((u8 *)object + offset);
156 *val = le32_to_cpu(tuple->value);
162 avs_parse_short_token(struct snd_soc_component *comp, void *elem, void *object, u32 offset)
164 struct snd_soc_tplg_vendor_value_elem *tuple = elem;
165 u16 *val = (u16 *)((u8 *)object + offset);
167 *val = le32_to_cpu(tuple->value);
173 avs_parse_word_token(struct snd_soc_component *comp, void *elem, void *object, u32 offset)
175 struct snd_soc_tplg_vendor_value_elem *tuple = elem;
176 u32 *val = (u32 *)((u8 *)object + offset);
178 *val = le32_to_cpu(tuple->value);
184 avs_parse_string_token(struct snd_soc_component *comp, void *elem, void *object, u32 offset)
186 struct snd_soc_tplg_vendor_string_elem *tuple = elem;
187 char *val = (char *)((u8 *)object + offset);
189 snprintf(val, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s", tuple->string);
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)
198 struct snd_soc_tplg_vendor_uuid_elem *tuple;
201 /* Parse element by element. */
202 for (i = 0; i < le32_to_cpu(tuples->num_elems); i++) {
203 tuple = &tuples->uuid[i];
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))
211 ret = parsers[j].parse(comp, tuple, object, parsers[j].offset);
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)
224 struct snd_soc_tplg_vendor_string_elem *tuple;
227 /* Parse element by element. */
228 for (i = 0; i < le32_to_cpu(tuples->num_elems); i++) {
229 tuple = &tuples->string[i];
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))
237 ret = parsers[j].parse(comp, tuple, object, parsers[j].offset);
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)
250 struct snd_soc_tplg_vendor_value_elem *tuple;
253 /* Parse element by element. */
254 for (i = 0; i < le32_to_cpu(tuples->num_elems); i++) {
255 tuple = &tuples->value[i];
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))
265 if (parsers[j].token != le32_to_cpu(tuple->token))
268 ret = parsers[j].parse(comp, tuple, object, parsers[j].offset);
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)
283 while (priv_size > 0) {
284 array_size = le32_to_cpu(tuples->size);
286 if (array_size <= 0) {
287 dev_err(comp->dev, "invalid array size 0x%x\n", array_size);
291 /* Make sure there is enough data before parsing. */
292 priv_size -= array_size;
294 dev_err(comp->dev, "invalid array size 0x%x\n", array_size);
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);
302 case SND_SOC_TPLG_TUPLE_TYPE_STRING:
303 ret = avs_parse_string_tokens(comp, object, parsers, count, tuples);
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);
312 dev_err(comp->dev, "unknown token type %d\n", tuples->type);
317 dev_err(comp->dev, "parsing %zu tokens of %d type failed: %d\n",
318 count, tuples->type, ret);
322 tuples = avs_tplg_vendor_array_next(tuples);
328 #define AVS_DEFINE_PTR_PARSER(name, type, member) \
330 avs_parse_##name##_ptr(struct snd_soc_component *comp, void *elem, void *object, u32 offset) \
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); \
337 idx = le32_to_cpu(tuple->value); \
338 if (idx >= acomp->tplg->num_##member) \
341 *val = &acomp->tplg->member[idx]; \
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);
353 parse_audio_format_bitfield(struct snd_soc_component *comp, void *elem, void *object, u32 offset)
355 struct snd_soc_tplg_vendor_value_elem *velem = elem;
356 struct avs_audio_format *audio_format = object;
359 case AVS_TKN_AFMT_NUM_CHANNELS_U32:
360 audio_format->num_channels = le32_to_cpu(velem->value);
362 case AVS_TKN_AFMT_VALID_BIT_DEPTH_U32:
363 audio_format->valid_bit_depth = le32_to_cpu(velem->value);
365 case AVS_TKN_AFMT_SAMPLE_TYPE_U32:
366 audio_format->sample_type = le32_to_cpu(velem->value);
373 static int parse_link_formatted_string(struct snd_soc_component *comp, void *elem,
374 void *object, u32 offset)
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);
381 * Dynamic naming - string formats, e.g.: ssp%d - supported only for
382 * topologies describing single device e.g.: an I2S codec on SSP0.
384 if (hweight_long(mach->mach_params.i2s_link_mask) != 1)
385 return avs_parse_string_token(comp, elem, object, offset);
387 snprintf(val, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, tuple->string,
388 __ffs(mach->mach_params.i2s_link_mask));
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)
399 struct snd_soc_tplg_vendor_value_elem *tuple;
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",
409 *num_entries = le32_to_cpu(tuple->value);
410 *dict = devm_kcalloc(comp->card->dev, *num_entries, entry_size, GFP_KERNEL);
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,
422 const struct avs_tplg_token_parser *parsers, size_t num_parsers)
427 for (i = 0; i < num_entries; i++) {
431 ret = avs_tplg_vendor_entry_size(tuples, block_size,
432 entry_id_token, &esize);
436 ret = avs_parse_tokens(comp, pos, parsers, num_parsers, tuples, esize);
438 dev_err(comp->dev, "parse entry: %d of type: %d failed: %d\n",
439 i, entry_id_token, ret);
445 tuples = avs_tplg_vendor_array_at(tuples, esize);
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)
459 ret = parse_dictionary_header(comp, tuples, dict, num_entries,
460 entry_size, num_entries_token);
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);
468 return parse_dictionary_entries(comp, tuples, block_size, *dict,
469 *num_entries, entry_size,
470 entry_id_token, parsers, num_parsers);
473 static const struct avs_tplg_token_parser library_parsers[] = {
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,
482 static int avs_tplg_parse_libraries(struct snd_soc_component *comp,
483 struct snd_soc_tplg_vendor_array *tuples, u32 block_size)
485 struct avs_soc_component *acomp = to_avs_soc_component(comp);
486 struct avs_tplg *tplg = acomp->tplg;
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));
495 static const struct avs_tplg_token_parser audio_format_parsers[] = {
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,
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,
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,
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,
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,
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,
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,
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,
546 static int avs_tplg_parse_audio_formats(struct snd_soc_component *comp,
547 struct snd_soc_tplg_vendor_array *tuples,
550 struct avs_soc_component *acomp = to_avs_soc_component(comp);
551 struct avs_tplg *tplg = acomp->tplg;
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,
557 audio_format_parsers, ARRAY_SIZE(audio_format_parsers));
560 static const struct avs_tplg_token_parser modcfg_base_parsers[] = {
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,
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,
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,
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,
587 static int avs_tplg_parse_modcfgs_base(struct snd_soc_component *comp,
588 struct snd_soc_tplg_vendor_array *tuples,
591 struct avs_soc_component *acomp = to_avs_soc_component(comp);
592 struct avs_tplg *tplg = acomp->tplg;
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));
601 static const struct avs_tplg_token_parser modcfg_ext_parsers[] = {
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
790 static const struct avs_tplg_token_parser pin_format_parsers[] = {
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,
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,
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,
811 static int avs_tplg_parse_modcfg_ext(struct snd_soc_component *comp,
812 struct avs_tplg_modcfg_ext *cfg,
813 struct snd_soc_tplg_vendor_array *tuples,
819 /* See where pin block starts. */
820 ret = avs_tplg_vendor_entry_size(tuples, block_size,
821 AVS_TKN_PIN_FMT_INDEX_U32, &esize);
825 ret = avs_parse_tokens(comp, cfg, modcfg_ext_parsers,
826 ARRAY_SIZE(modcfg_ext_parsers), tuples, esize);
831 /* Parse trailing in/out pin formats if any. */
833 struct avs_tplg_pin_format *pins;
836 num_pins = cfg->generic.num_input_pins + cfg->generic.num_output_pins;
840 pins = devm_kcalloc(comp->card->dev, num_pins, sizeof(*pins), GFP_KERNEL);
844 tuples = avs_tplg_vendor_array_at(tuples, esize);
845 ret = parse_dictionary_entries(comp, tuples, block_size,
846 pins, num_pins, sizeof(*pins),
847 AVS_TKN_PIN_FMT_INDEX_U32,
849 ARRAY_SIZE(pin_format_parsers));
852 cfg->generic.pin_fmts = pins;
858 static int avs_tplg_parse_modcfgs_ext(struct snd_soc_component *comp,
859 struct snd_soc_tplg_vendor_array *tuples,
862 struct avs_soc_component *acomp = to_avs_soc_component(comp);
863 struct avs_tplg *tplg = acomp->tplg;
866 ret = parse_dictionary_header(comp, tuples, (void **)&tplg->modcfgs_ext,
867 &tplg->num_modcfgs_ext,
868 sizeof(*tplg->modcfgs_ext),
869 AVS_TKN_MANIFEST_NUM_MODCFGS_EXT_U32);
873 block_size -= le32_to_cpu(tuples->size);
874 /* With header parsed, move on to parsing entries. */
875 tuples = avs_tplg_vendor_array_next(tuples);
877 for (i = 0; i < tplg->num_modcfgs_ext; i++) {
878 struct avs_tplg_modcfg_ext *cfg = &tplg->modcfgs_ext[i];
881 ret = avs_tplg_vendor_entry_size(tuples, block_size,
882 AVS_TKN_MODCFG_EXT_ID_U32, &esize);
886 ret = avs_tplg_parse_modcfg_ext(comp, cfg, tuples, esize);
891 tuples = avs_tplg_vendor_array_at(tuples, esize);
897 static const struct avs_tplg_token_parser pplcfg_parsers[] = {
899 .token = AVS_TKN_PPLCFG_REQ_SIZE_U16,
900 .type = SND_SOC_TPLG_TUPLE_TYPE_SHORT,
901 .offset = offsetof(struct avs_tplg_pplcfg, req_size),
902 .parse = avs_parse_short_token,
905 .token = AVS_TKN_PPLCFG_PRIORITY_U8,
906 .type = SND_SOC_TPLG_TUPLE_TYPE_BYTE,
907 .offset = offsetof(struct avs_tplg_pplcfg, priority),
908 .parse = avs_parse_byte_token,
911 .token = AVS_TKN_PPLCFG_LOW_POWER_BOOL,
912 .type = SND_SOC_TPLG_TUPLE_TYPE_BOOL,
913 .offset = offsetof(struct avs_tplg_pplcfg, lp),
914 .parse = avs_parse_bool_token,
917 .token = AVS_TKN_PPLCFG_ATTRIBUTES_U16,
918 .type = SND_SOC_TPLG_TUPLE_TYPE_SHORT,
919 .offset = offsetof(struct avs_tplg_pplcfg, attributes),
920 .parse = avs_parse_short_token,
923 .token = AVS_TKN_PPLCFG_TRIGGER_U32,
924 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
925 .offset = offsetof(struct avs_tplg_pplcfg, trigger),
926 .parse = avs_parse_word_token,
930 static int avs_tplg_parse_pplcfgs(struct snd_soc_component *comp,
931 struct snd_soc_tplg_vendor_array *tuples,
934 struct avs_soc_component *acomp = to_avs_soc_component(comp);
935 struct avs_tplg *tplg = acomp->tplg;
937 return parse_dictionary(comp, tuples, block_size, (void **)&tplg->pplcfgs,
938 &tplg->num_pplcfgs, sizeof(*tplg->pplcfgs),
939 AVS_TKN_MANIFEST_NUM_PPLCFGS_U32,
940 AVS_TKN_PPLCFG_ID_U32,
941 pplcfg_parsers, ARRAY_SIZE(pplcfg_parsers));
944 static const struct avs_tplg_token_parser binding_parsers[] = {
946 .token = AVS_TKN_BINDING_TARGET_TPLG_NAME_STRING,
947 .type = SND_SOC_TPLG_TUPLE_TYPE_STRING,
948 .offset = offsetof(struct avs_tplg_binding, target_tplg_name),
949 .parse = parse_link_formatted_string,
952 .token = AVS_TKN_BINDING_TARGET_PATH_TMPL_ID_U32,
953 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
954 .offset = offsetof(struct avs_tplg_binding, target_path_tmpl_id),
955 .parse = avs_parse_word_token,
958 .token = AVS_TKN_BINDING_TARGET_PPL_ID_U32,
959 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
960 .offset = offsetof(struct avs_tplg_binding, target_ppl_id),
961 .parse = avs_parse_word_token,
964 .token = AVS_TKN_BINDING_TARGET_MOD_ID_U32,
965 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
966 .offset = offsetof(struct avs_tplg_binding, target_mod_id),
967 .parse = avs_parse_word_token,
970 .token = AVS_TKN_BINDING_TARGET_MOD_PIN_U8,
971 .type = SND_SOC_TPLG_TUPLE_TYPE_BYTE,
972 .offset = offsetof(struct avs_tplg_binding, target_mod_pin),
973 .parse = avs_parse_byte_token,
976 .token = AVS_TKN_BINDING_MOD_ID_U32,
977 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
978 .offset = offsetof(struct avs_tplg_binding, mod_id),
979 .parse = avs_parse_word_token,
982 .token = AVS_TKN_BINDING_MOD_PIN_U8,
983 .type = SND_SOC_TPLG_TUPLE_TYPE_BYTE,
984 .offset = offsetof(struct avs_tplg_binding, mod_pin),
985 .parse = avs_parse_byte_token,
988 .token = AVS_TKN_BINDING_IS_SINK_U8,
989 .type = SND_SOC_TPLG_TUPLE_TYPE_BYTE,
990 .offset = offsetof(struct avs_tplg_binding, is_sink),
991 .parse = avs_parse_byte_token,
995 static int avs_tplg_parse_bindings(struct snd_soc_component *comp,
996 struct snd_soc_tplg_vendor_array *tuples,
999 struct avs_soc_component *acomp = to_avs_soc_component(comp);
1000 struct avs_tplg *tplg = acomp->tplg;
1002 return parse_dictionary(comp, tuples, block_size, (void **)&tplg->bindings,
1003 &tplg->num_bindings, sizeof(*tplg->bindings),
1004 AVS_TKN_MANIFEST_NUM_BINDINGS_U32,
1005 AVS_TKN_BINDING_ID_U32,
1006 binding_parsers, ARRAY_SIZE(binding_parsers));
1009 static const struct avs_tplg_token_parser module_parsers[] = {
1011 .token = AVS_TKN_MOD_ID_U32,
1012 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
1013 .offset = offsetof(struct avs_tplg_module, id),
1014 .parse = avs_parse_word_token,
1017 .token = AVS_TKN_MOD_MODCFG_BASE_ID_U32,
1018 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
1019 .offset = offsetof(struct avs_tplg_module, cfg_base),
1020 .parse = avs_parse_modcfg_base_ptr,
1023 .token = AVS_TKN_MOD_IN_AFMT_ID_U32,
1024 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
1025 .offset = offsetof(struct avs_tplg_module, in_fmt),
1026 .parse = avs_parse_audio_format_ptr,
1029 .token = AVS_TKN_MOD_CORE_ID_U8,
1030 .type = SND_SOC_TPLG_TUPLE_TYPE_BYTE,
1031 .offset = offsetof(struct avs_tplg_module, core_id),
1032 .parse = avs_parse_byte_token,
1035 .token = AVS_TKN_MOD_PROC_DOMAIN_U8,
1036 .type = SND_SOC_TPLG_TUPLE_TYPE_BYTE,
1037 .offset = offsetof(struct avs_tplg_module, domain),
1038 .parse = avs_parse_byte_token,
1041 .token = AVS_TKN_MOD_MODCFG_EXT_ID_U32,
1042 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
1043 .offset = offsetof(struct avs_tplg_module, cfg_ext),
1044 .parse = avs_parse_modcfg_ext_ptr,
1048 static struct avs_tplg_module *
1049 avs_tplg_module_create(struct snd_soc_component *comp, struct avs_tplg_pipeline *owner,
1050 struct snd_soc_tplg_vendor_array *tuples, u32 block_size)
1052 struct avs_tplg_module *module;
1055 module = devm_kzalloc(comp->card->dev, sizeof(*module), GFP_KERNEL);
1057 return ERR_PTR(-ENOMEM);
1059 ret = avs_parse_tokens(comp, module, module_parsers,
1060 ARRAY_SIZE(module_parsers), tuples, block_size);
1062 return ERR_PTR(ret);
1064 module->owner = owner;
1065 INIT_LIST_HEAD(&module->node);
1070 static const struct avs_tplg_token_parser pipeline_parsers[] = {
1072 .token = AVS_TKN_PPL_ID_U32,
1073 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
1074 .offset = offsetof(struct avs_tplg_pipeline, id),
1075 .parse = avs_parse_word_token,
1078 .token = AVS_TKN_PPL_PPLCFG_ID_U32,
1079 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
1080 .offset = offsetof(struct avs_tplg_pipeline, cfg),
1081 .parse = avs_parse_pplcfg_ptr,
1084 .token = AVS_TKN_PPL_NUM_BINDING_IDS_U32,
1085 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
1086 .offset = offsetof(struct avs_tplg_pipeline, num_bindings),
1087 .parse = avs_parse_word_token,
1091 static const struct avs_tplg_token_parser bindings_parsers[] = {
1093 .token = AVS_TKN_PPL_BINDING_ID_U32,
1094 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
1095 .offset = 0, /* to treat pipeline->bindings as dictionary */
1096 .parse = avs_parse_binding_ptr,
1100 static struct avs_tplg_pipeline *
1101 avs_tplg_pipeline_create(struct snd_soc_component *comp, struct avs_tplg_path *owner,
1102 struct snd_soc_tplg_vendor_array *tuples, u32 block_size)
1104 struct avs_tplg_pipeline *pipeline;
1105 u32 modblk_size, offset;
1108 pipeline = devm_kzalloc(comp->card->dev, sizeof(*pipeline), GFP_KERNEL);
1110 return ERR_PTR(-ENOMEM);
1112 pipeline->owner = owner;
1113 INIT_LIST_HEAD(&pipeline->mod_list);
1115 /* Pipeline header MUST be followed by at least one module. */
1116 ret = avs_tplg_vendor_array_lookup(tuples, block_size,
1117 AVS_TKN_MOD_ID_U32, &offset);
1118 if (!ret && !offset)
1121 return ERR_PTR(ret);
1123 /* Process header which precedes module sections. */
1124 ret = avs_parse_tokens(comp, pipeline, pipeline_parsers,
1125 ARRAY_SIZE(pipeline_parsers), tuples, offset);
1127 return ERR_PTR(ret);
1129 block_size -= offset;
1130 tuples = avs_tplg_vendor_array_at(tuples, offset);
1132 /* Optionally, binding sections follow module ones. */
1133 ret = avs_tplg_vendor_array_lookup_next(tuples, block_size,
1134 AVS_TKN_PPL_BINDING_ID_U32, &offset);
1137 return ERR_PTR(ret);
1139 /* Does header information match actual block layout? */
1140 if (pipeline->num_bindings)
1141 return ERR_PTR(-EINVAL);
1143 modblk_size = block_size;
1145 pipeline->bindings = devm_kcalloc(comp->card->dev, pipeline->num_bindings,
1146 sizeof(*pipeline->bindings), GFP_KERNEL);
1147 if (!pipeline->bindings)
1148 return ERR_PTR(-ENOMEM);
1150 modblk_size = offset;
1153 block_size -= modblk_size;
1155 struct avs_tplg_module *module;
1158 ret = avs_tplg_vendor_entry_size(tuples, modblk_size,
1159 AVS_TKN_MOD_ID_U32, &esize);
1161 return ERR_PTR(ret);
1163 module = avs_tplg_module_create(comp, pipeline, tuples, esize);
1164 if (IS_ERR(module)) {
1165 dev_err(comp->dev, "parse module failed: %ld\n",
1167 return ERR_CAST(module);
1170 list_add_tail(&module->node, &pipeline->mod_list);
1171 modblk_size -= esize;
1172 tuples = avs_tplg_vendor_array_at(tuples, esize);
1173 } while (modblk_size > 0);
1175 /* What's left is optional range of bindings. */
1176 ret = parse_dictionary_entries(comp, tuples, block_size, pipeline->bindings,
1177 pipeline->num_bindings, sizeof(*pipeline->bindings),
1178 AVS_TKN_PPL_BINDING_ID_U32,
1179 bindings_parsers, ARRAY_SIZE(bindings_parsers));
1181 return ERR_PTR(ret);
1186 static const struct avs_tplg_token_parser path_parsers[] = {
1188 .token = AVS_TKN_PATH_ID_U32,
1189 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
1190 .offset = offsetof(struct avs_tplg_path, id),
1191 .parse = avs_parse_word_token,
1194 .token = AVS_TKN_PATH_FE_FMT_ID_U32,
1195 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
1196 .offset = offsetof(struct avs_tplg_path, fe_fmt),
1197 .parse = avs_parse_audio_format_ptr,
1200 .token = AVS_TKN_PATH_BE_FMT_ID_U32,
1201 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
1202 .offset = offsetof(struct avs_tplg_path, be_fmt),
1203 .parse = avs_parse_audio_format_ptr,
1207 static struct avs_tplg_path *
1208 avs_tplg_path_create(struct snd_soc_component *comp, struct avs_tplg_path_template *owner,
1209 struct snd_soc_tplg_vendor_array *tuples, u32 block_size,
1210 const struct avs_tplg_token_parser *parsers, u32 num_parsers)
1212 struct avs_tplg_pipeline *pipeline;
1213 struct avs_tplg_path *path;
1217 path = devm_kzalloc(comp->card->dev, sizeof(*path), GFP_KERNEL);
1219 return ERR_PTR(-ENOMEM);
1221 path->owner = owner;
1222 INIT_LIST_HEAD(&path->ppl_list);
1223 INIT_LIST_HEAD(&path->node);
1225 /* Path header MAY be followed by one or more pipelines. */
1226 ret = avs_tplg_vendor_array_lookup(tuples, block_size,
1227 AVS_TKN_PPL_ID_U32, &offset);
1229 offset = block_size;
1231 return ERR_PTR(ret);
1233 return ERR_PTR(-EINVAL);
1235 /* Process header which precedes pipeline sections. */
1236 ret = avs_parse_tokens(comp, path, parsers, num_parsers, tuples, offset);
1238 return ERR_PTR(ret);
1240 block_size -= offset;
1241 tuples = avs_tplg_vendor_array_at(tuples, offset);
1242 while (block_size > 0) {
1245 ret = avs_tplg_vendor_entry_size(tuples, block_size,
1246 AVS_TKN_PPL_ID_U32, &esize);
1248 return ERR_PTR(ret);
1250 pipeline = avs_tplg_pipeline_create(comp, path, tuples, esize);
1251 if (IS_ERR(pipeline)) {
1252 dev_err(comp->dev, "parse pipeline failed: %ld\n",
1254 return ERR_CAST(pipeline);
1257 list_add_tail(&pipeline->node, &path->ppl_list);
1258 block_size -= esize;
1259 tuples = avs_tplg_vendor_array_at(tuples, esize);
1265 static const struct avs_tplg_token_parser path_tmpl_parsers[] = {
1267 .token = AVS_TKN_PATH_TMPL_ID_U32,
1268 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
1269 .offset = offsetof(struct avs_tplg_path_template, id),
1270 .parse = avs_parse_word_token,
1274 static int parse_path_template(struct snd_soc_component *comp,
1275 struct snd_soc_tplg_vendor_array *tuples, u32 block_size,
1276 struct avs_tplg_path_template *template,
1277 const struct avs_tplg_token_parser *tmpl_tokens, u32 num_tmpl_tokens,
1278 const struct avs_tplg_token_parser *path_tokens, u32 num_path_tokens)
1280 struct avs_tplg_path *path;
1284 /* Path template header MUST be followed by at least one path variant. */
1285 ret = avs_tplg_vendor_array_lookup(tuples, block_size,
1286 AVS_TKN_PATH_ID_U32, &offset);
1290 /* Process header which precedes path variants sections. */
1291 ret = avs_parse_tokens(comp, template, tmpl_tokens, num_tmpl_tokens, tuples, offset);
1295 block_size -= offset;
1296 tuples = avs_tplg_vendor_array_at(tuples, offset);
1300 ret = avs_tplg_vendor_entry_size(tuples, block_size,
1301 AVS_TKN_PATH_ID_U32, &esize);
1305 path = avs_tplg_path_create(comp, template, tuples, esize, path_tokens,
1308 dev_err(comp->dev, "parse path failed: %ld\n", PTR_ERR(path));
1309 return PTR_ERR(path);
1312 list_add_tail(&path->node, &template->path_list);
1313 block_size -= esize;
1314 tuples = avs_tplg_vendor_array_at(tuples, esize);
1315 } while (block_size > 0);
1320 static struct avs_tplg_path_template *
1321 avs_tplg_path_template_create(struct snd_soc_component *comp, struct avs_tplg *owner,
1322 struct snd_soc_tplg_vendor_array *tuples, u32 block_size)
1324 struct avs_tplg_path_template *template;
1327 template = devm_kzalloc(comp->card->dev, sizeof(*template), GFP_KERNEL);
1329 return ERR_PTR(-ENOMEM);
1331 template->owner = owner; /* Used to access component tplg is assigned to. */
1332 INIT_LIST_HEAD(&template->path_list);
1333 INIT_LIST_HEAD(&template->node);
1335 ret = parse_path_template(comp, tuples, block_size, template, path_tmpl_parsers,
1336 ARRAY_SIZE(path_tmpl_parsers), path_parsers,
1337 ARRAY_SIZE(path_parsers));
1339 return ERR_PTR(ret);
1344 static int avs_route_load(struct snd_soc_component *comp, int index,
1345 struct snd_soc_dapm_route *route)
1347 struct snd_soc_acpi_mach *mach = dev_get_platdata(comp->card->dev);
1348 size_t len = SNDRV_CTL_ELEM_ID_NAME_MAXLEN;
1349 char buf[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
1352 /* See parse_link_formatted_string() for dynamic naming when(s). */
1353 if (hweight_long(mach->mach_params.i2s_link_mask) == 1) {
1354 port = __ffs(mach->mach_params.i2s_link_mask);
1356 snprintf(buf, len, route->source, port);
1357 strncpy((char *)route->source, buf, len);
1358 snprintf(buf, len, route->sink, port);
1359 strncpy((char *)route->sink, buf, len);
1360 if (route->control) {
1361 snprintf(buf, len, route->control, port);
1362 strncpy((char *)route->control, buf, len);
1369 static int avs_widget_load(struct snd_soc_component *comp, int index,
1370 struct snd_soc_dapm_widget *w,
1371 struct snd_soc_tplg_dapm_widget *dw)
1373 struct snd_soc_acpi_mach *mach;
1374 struct avs_tplg_path_template *template;
1375 struct avs_soc_component *acomp = to_avs_soc_component(comp);
1376 struct avs_tplg *tplg;
1378 if (!le32_to_cpu(dw->priv.size))
1382 mach = dev_get_platdata(comp->card->dev);
1384 /* See parse_link_formatted_string() for dynamic naming when(s). */
1385 if (hweight_long(mach->mach_params.i2s_link_mask) == 1) {
1387 /* w->name is freed later by soc_tplg_dapm_widget_create() */
1388 w->name = kasprintf(GFP_KERNEL, dw->name, __ffs(mach->mach_params.i2s_link_mask));
1393 template = avs_tplg_path_template_create(comp, tplg, dw->priv.array,
1394 le32_to_cpu(dw->priv.size));
1395 if (IS_ERR(template)) {
1396 dev_err(comp->dev, "widget %s load failed: %ld\n", dw->name,
1398 return PTR_ERR(template);
1401 w->priv = template; /* link path information to widget */
1402 list_add_tail(&template->node, &tplg->path_tmpl_list);
1406 static int avs_dai_load(struct snd_soc_component *comp, int index,
1407 struct snd_soc_dai_driver *dai_drv, struct snd_soc_tplg_pcm *pcm,
1408 struct snd_soc_dai *dai)
1411 dai_drv->ops = &avs_dai_fe_ops;
1415 static int avs_link_load(struct snd_soc_component *comp, int index, struct snd_soc_dai_link *link,
1416 struct snd_soc_tplg_link_config *cfg)
1418 if (!link->no_pcm) {
1419 /* Stream control handled by IPCs. */
1420 link->nonatomic = true;
1422 /* Open LINK (BE) pipes last and close them first to prevent xruns. */
1423 link->trigger[0] = SND_SOC_DPCM_TRIGGER_PRE;
1424 link->trigger[1] = SND_SOC_DPCM_TRIGGER_PRE;
1430 static const struct avs_tplg_token_parser manifest_parsers[] = {
1432 .token = AVS_TKN_MANIFEST_NAME_STRING,
1433 .type = SND_SOC_TPLG_TUPLE_TYPE_STRING,
1434 .offset = offsetof(struct avs_tplg, name),
1435 .parse = parse_link_formatted_string,
1438 .token = AVS_TKN_MANIFEST_VERSION_U32,
1439 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
1440 .offset = offsetof(struct avs_tplg, version),
1441 .parse = avs_parse_word_token,
1445 static int avs_manifest(struct snd_soc_component *comp, int index,
1446 struct snd_soc_tplg_manifest *manifest)
1448 struct snd_soc_tplg_vendor_array *tuples = manifest->priv.array;
1449 struct avs_soc_component *acomp = to_avs_soc_component(comp);
1450 size_t remaining = le32_to_cpu(manifest->priv.size);
1454 ret = avs_tplg_vendor_array_lookup(tuples, remaining,
1455 AVS_TKN_MANIFEST_NUM_LIBRARIES_U32, &offset);
1456 /* Manifest MUST begin with a header. */
1457 if (!ret && !offset)
1460 dev_err(comp->dev, "incorrect manifest format: %d\n", ret);
1464 /* Process header which precedes any of the dictionaries. */
1465 ret = avs_parse_tokens(comp, acomp->tplg, manifest_parsers,
1466 ARRAY_SIZE(manifest_parsers), tuples, offset);
1470 remaining -= offset;
1471 tuples = avs_tplg_vendor_array_at(tuples, offset);
1473 ret = avs_tplg_vendor_array_lookup(tuples, remaining,
1474 AVS_TKN_MANIFEST_NUM_AFMTS_U32, &offset);
1476 dev_err(comp->dev, "audio formats lookup failed: %d\n", ret);
1480 /* Libraries dictionary. */
1481 ret = avs_tplg_parse_libraries(comp, tuples, offset);
1485 remaining -= offset;
1486 tuples = avs_tplg_vendor_array_at(tuples, offset);
1488 ret = avs_tplg_vendor_array_lookup(tuples, remaining,
1489 AVS_TKN_MANIFEST_NUM_MODCFGS_BASE_U32, &offset);
1491 dev_err(comp->dev, "modcfgs_base lookup failed: %d\n", ret);
1495 /* Audio formats dictionary. */
1496 ret = avs_tplg_parse_audio_formats(comp, tuples, offset);
1500 remaining -= offset;
1501 tuples = avs_tplg_vendor_array_at(tuples, offset);
1503 ret = avs_tplg_vendor_array_lookup(tuples, remaining,
1504 AVS_TKN_MANIFEST_NUM_MODCFGS_EXT_U32, &offset);
1506 dev_err(comp->dev, "modcfgs_ext lookup failed: %d\n", ret);
1510 /* Module configs-base dictionary. */
1511 ret = avs_tplg_parse_modcfgs_base(comp, tuples, offset);
1515 remaining -= offset;
1516 tuples = avs_tplg_vendor_array_at(tuples, offset);
1518 ret = avs_tplg_vendor_array_lookup(tuples, remaining,
1519 AVS_TKN_MANIFEST_NUM_PPLCFGS_U32, &offset);
1521 dev_err(comp->dev, "pplcfgs lookup failed: %d\n", ret);
1525 /* Module configs-ext dictionary. */
1526 ret = avs_tplg_parse_modcfgs_ext(comp, tuples, offset);
1530 remaining -= offset;
1531 tuples = avs_tplg_vendor_array_at(tuples, offset);
1533 ret = avs_tplg_vendor_array_lookup(tuples, remaining,
1534 AVS_TKN_MANIFEST_NUM_BINDINGS_U32, &offset);
1536 dev_err(comp->dev, "bindings lookup failed: %d\n", ret);
1540 /* Pipeline configs dictionary. */
1541 ret = avs_tplg_parse_pplcfgs(comp, tuples, offset);
1545 remaining -= offset;
1546 tuples = avs_tplg_vendor_array_at(tuples, offset);
1548 /* Bindings dictionary. */
1549 return avs_tplg_parse_bindings(comp, tuples, remaining);
1552 static struct snd_soc_tplg_ops avs_tplg_ops = {
1553 .dapm_route_load = avs_route_load,
1554 .widget_load = avs_widget_load,
1555 .dai_load = avs_dai_load,
1556 .link_load = avs_link_load,
1557 .manifest = avs_manifest,
1560 struct avs_tplg *avs_tplg_new(struct snd_soc_component *comp)
1562 struct avs_tplg *tplg;
1564 tplg = devm_kzalloc(comp->card->dev, sizeof(*tplg), GFP_KERNEL);
1569 INIT_LIST_HEAD(&tplg->path_tmpl_list);
1574 int avs_load_topology(struct snd_soc_component *comp, const char *filename)
1576 const struct firmware *fw;
1579 ret = request_firmware(&fw, filename, comp->dev);
1581 dev_err(comp->dev, "request topology \"%s\" failed: %d\n", filename, ret);
1585 ret = snd_soc_tplg_component_load(comp, &avs_tplg_ops, fw);
1587 dev_err(comp->dev, "load topology \"%s\" failed: %d\n", filename, ret);
1589 release_firmware(fw);
1593 int avs_remove_topology(struct snd_soc_component *comp)
1595 snd_soc_tplg_component_remove(comp);