diff options
Diffstat (limited to 'sound/soc/intel/avs/topology.c')
| -rw-r--r-- | sound/soc/intel/avs/topology.c | 113 |
1 files changed, 110 insertions, 3 deletions
diff --git a/sound/soc/intel/avs/topology.c b/sound/soc/intel/avs/topology.c index dfe8cf505381..9033f683393c 100644 --- a/sound/soc/intel/avs/topology.c +++ b/sound/soc/intel/avs/topology.c @@ -350,6 +350,7 @@ AVS_DEFINE_PTR_PARSER(modcfg_base, struct avs_tplg_modcfg_base, modcfgs_base); AVS_DEFINE_PTR_PARSER(modcfg_ext, struct avs_tplg_modcfg_ext, modcfgs_ext); AVS_DEFINE_PTR_PARSER(pplcfg, struct avs_tplg_pplcfg, pplcfgs); AVS_DEFINE_PTR_PARSER(binding, struct avs_tplg_binding, bindings); +AVS_DEFINE_PTR_PARSER(nhlt_config, struct avs_tplg_nhlt_config, nhlt_configs); static int parse_audio_format_bitfield(struct snd_soc_component *comp, void *elem, void *object, u32 offset) @@ -420,6 +421,22 @@ static int parse_link_formatted_string(struct snd_soc_component *comp, void *ele return 0; } +static int avs_parse_nhlt_config_size(struct snd_soc_component *comp, void *elem, void *object, + u32 offset) +{ + struct snd_soc_tplg_vendor_value_elem *tuple = elem; + struct acpi_nhlt_config **blob = (struct acpi_nhlt_config **)((u8 *)object + offset); + u32 size; + + size = le32_to_cpu(tuple->value); + *blob = devm_kzalloc(comp->card->dev, struct_size(*blob, capabilities, size), GFP_KERNEL); + if (!*blob) + return -ENOMEM; + + (*blob)->capabilities_size = size; + return 0; +} + static int parse_dictionary_header(struct snd_soc_component *comp, struct snd_soc_tplg_vendor_array *tuples, @@ -1184,6 +1201,12 @@ static const struct avs_tplg_token_parser module_parsers[] = { .offset = offsetof(struct avs_tplg_module, num_config_ids), .parse = avs_parse_byte_token, }, + { + .token = AVS_TKN_MOD_NHLT_CONFIG_ID_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_tplg_module, nhlt_config), + .parse = avs_parse_nhlt_config_ptr, + }, }; static const struct avs_tplg_token_parser init_config_parsers[] = { @@ -1651,12 +1674,14 @@ static const struct avs_tplg_token_parser mod_init_config_parsers[] = { static int avs_tplg_parse_initial_configs(struct snd_soc_component *comp, struct snd_soc_tplg_vendor_array *tuples, - u32 block_size) + u32 block_size, u32 *offset) { struct avs_soc_component *acomp = to_avs_soc_component(comp); struct avs_tplg *tplg = acomp->tplg; int ret, i; + *offset = 0; + /* Parse tuple section telling how many init configs there are. */ ret = parse_dictionary_header(comp, tuples, (void **)&tplg->init_configs, &tplg->num_init_configs, @@ -1666,6 +1691,7 @@ static int avs_tplg_parse_initial_configs(struct snd_soc_component *comp, return ret; block_size -= le32_to_cpu(tuples->size); + *offset += le32_to_cpu(tuples->size); /* With header parsed, move on to parsing entries. */ tuples = avs_tplg_vendor_array_next(tuples); @@ -1681,6 +1707,7 @@ static int avs_tplg_parse_initial_configs(struct snd_soc_component *comp, */ tmp = avs_tplg_vendor_array_next(tuples); esize = le32_to_cpu(tuples->size) + le32_to_cpu(tmp->size); + *offset += esize; ret = parse_dictionary_entries(comp, tuples, esize, config, 1, sizeof(*config), AVS_TKN_INIT_CONFIG_ID_U32, @@ -1692,6 +1719,7 @@ static int avs_tplg_parse_initial_configs(struct snd_soc_component *comp, /* handle raw data section */ init_config_data = (void *)tuples + esize; esize = config->length; + *offset += esize; config->data = devm_kmemdup(comp->card->dev, init_config_data, esize, GFP_KERNEL); if (!config->data) @@ -1704,6 +1732,70 @@ static int avs_tplg_parse_initial_configs(struct snd_soc_component *comp, return 0; } +static const struct avs_tplg_token_parser mod_nhlt_config_parsers[] = { + { + .token = AVS_TKN_NHLT_CONFIG_ID_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_tplg_nhlt_config, id), + .parse = avs_parse_word_token, + }, + { + .token = AVS_TKN_NHLT_CONFIG_SIZE_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_tplg_nhlt_config, blob), + .parse = avs_parse_nhlt_config_size, + }, +}; + +static int avs_tplg_parse_nhlt_configs(struct snd_soc_component *comp, + struct snd_soc_tplg_vendor_array *tuples, + u32 block_size) +{ + struct avs_soc_component *acomp = to_avs_soc_component(comp); + struct avs_tplg *tplg = acomp->tplg; + int ret, i; + + /* Parse the header section to know how many entries there are. */ + ret = parse_dictionary_header(comp, tuples, (void **)&tplg->nhlt_configs, + &tplg->num_nhlt_configs, + sizeof(*tplg->nhlt_configs), + AVS_TKN_MANIFEST_NUM_NHLT_CONFIGS_U32); + if (ret) + return ret; + + block_size -= le32_to_cpu(tuples->size); + /* With the header parsed, move on to parsing entries. */ + tuples = avs_tplg_vendor_array_next(tuples); + + for (i = 0; i < tplg->num_nhlt_configs && block_size > 0; i++) { + struct avs_tplg_nhlt_config *config; + u32 esize; + + config = &tplg->nhlt_configs[i]; + esize = le32_to_cpu(tuples->size); + + ret = parse_dictionary_entries(comp, tuples, esize, config, 1, sizeof(*config), + AVS_TKN_NHLT_CONFIG_ID_U32, + mod_nhlt_config_parsers, + ARRAY_SIZE(mod_nhlt_config_parsers)); + if (ret) + return ret; + /* With tuples parsed, the blob shall be allocated. */ + if (!config->blob) + return -EINVAL; + + /* Consume the raw data and move to the next entry. */ + memcpy(config->blob->capabilities, (u8 *)tuples + esize, + config->blob->capabilities_size); + esize += config->blob->capabilities_size; + + block_size -= esize; + tuples = avs_tplg_vendor_array_at(tuples, esize); + } + + return 0; +} + static int avs_route_load(struct snd_soc_component *comp, int index, struct snd_soc_dapm_route *route) { @@ -2008,11 +2100,26 @@ static int avs_manifest(struct snd_soc_component *comp, int index, tuples = avs_tplg_vendor_array_at(tuples, offset); /* Initial configs dictionary. */ - ret = avs_tplg_parse_initial_configs(comp, tuples, remaining); + ret = avs_tplg_parse_initial_configs(comp, tuples, remaining, &offset); if (ret < 0) return ret; - return 0; + remaining -= offset; + tuples = avs_tplg_vendor_array_at(tuples, offset); + + ret = avs_tplg_vendor_array_lookup(tuples, remaining, + AVS_TKN_MANIFEST_NUM_NHLT_CONFIGS_U32, &offset); + if (ret == -ENOENT) + return 0; + if (ret) { + dev_err(comp->dev, "NHLT config lookup failed: %d\n", ret); + return ret; + } + + tuples = avs_tplg_vendor_array_at(tuples, offset); + + /* NHLT configs dictionary. */ + return avs_tplg_parse_nhlt_configs(comp, tuples, remaining); } enum { |
