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