From a5766cd479fd212e9831ceef8e9ab630c91445ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Thu, 8 Feb 2024 11:23:58 +0100 Subject: [PATCH 1/3] ASoC: Intel: avs: UAPI: Add tokens for initial config feature MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow for defining initial config which will be send after module initialization to configure initial module state. This is only useful for modules which need to be configured on init. Reviewed-by: Cezary Rojewski Signed-off-by: Amadeusz Sławiński Link: https://lore.kernel.org/r/20240208102400.2497791-2-amadeuszx.slawinski@linux.intel.com Signed-off-by: Mark Brown --- include/uapi/sound/intel/avs/tokens.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/uapi/sound/intel/avs/tokens.h b/include/uapi/sound/intel/avs/tokens.h index 4ffe546aa409..4beca03405c0 100644 --- a/include/uapi/sound/intel/avs/tokens.h +++ b/include/uapi/sound/intel/avs/tokens.h @@ -19,6 +19,8 @@ enum avs_tplg_token { AVS_TKN_MANIFEST_NUM_MODCFGS_EXT_U32 = 6, AVS_TKN_MANIFEST_NUM_PPLCFGS_U32 = 7, AVS_TKN_MANIFEST_NUM_BINDINGS_U32 = 8, + AVS_TKN_MANIFEST_NUM_CONDPATH_TMPLS_U32 = 9, + AVS_TKN_MANIFEST_NUM_INIT_CONFIGS_U32 = 10, /* struct avs_tplg_library */ AVS_TKN_LIBRARY_ID_U32 = 101, @@ -109,6 +111,8 @@ enum avs_tplg_token { AVS_TKN_MOD_PROC_DOMAIN_U8 = 1705, AVS_TKN_MOD_MODCFG_EXT_ID_U32 = 1706, AVS_TKN_MOD_KCONTROL_ID_U32 = 1707, + AVS_TKN_MOD_INIT_CONFIG_NUM_IDS_U32 = 1708, + AVS_TKN_MOD_INIT_CONFIG_ID_U32 = 1709, /* struct avs_tplg_path_template */ AVS_TKN_PATH_TMPL_ID_U32 = 1801, @@ -125,6 +129,11 @@ enum avs_tplg_token { /* struct avs_tplg_kcontrol */ AVS_TKN_KCONTROL_ID_U32 = 2301, + + /* struct avs_tplg_init_config */ + AVS_TKN_INIT_CONFIG_ID_U32 = 2401, + AVS_TKN_INIT_CONFIG_PARAM_U8 = 2402, + AVS_TKN_INIT_CONFIG_LENGTH_U32 = 2403, }; #endif From 1b4217ebbb3e9d9b014db660618a4ddb61b3c321 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Thu, 8 Feb 2024 11:23:59 +0100 Subject: [PATCH 2/3] ASoC: Intel: avs: Add topology parsing support for initial config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add topology parsing for initial config. Reviewed-by: Cezary Rojewski Signed-off-by: Amadeusz Sławiński Link: https://lore.kernel.org/r/20240208102400.2497791-3-amadeuszx.slawinski@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/avs/topology.c | 164 ++++++++++++++++++++++++++++++++- sound/soc/intel/avs/topology.h | 13 +++ 2 files changed, 175 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/avs/topology.c b/sound/soc/intel/avs/topology.c index 778236d3fd28..e5376a939dbd 100644 --- a/sound/soc/intel/avs/topology.c +++ b/sound/soc/intel/avs/topology.c @@ -1118,6 +1118,21 @@ static const struct avs_tplg_token_parser module_parsers[] = { .offset = offsetof(struct avs_tplg_module, ctl_id), .parse = avs_parse_byte_token, }, + { + .token = AVS_TKN_MOD_INIT_CONFIG_NUM_IDS_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_tplg_module, num_config_ids), + .parse = avs_parse_byte_token, + }, +}; + +static const struct avs_tplg_token_parser init_config_parsers[] = { + { + .token = AVS_TKN_MOD_INIT_CONFIG_ID_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = 0, + .parse = avs_parse_word_token, + }, }; static struct avs_tplg_module * @@ -1125,17 +1140,50 @@ avs_tplg_module_create(struct snd_soc_component *comp, struct avs_tplg_pipeline struct snd_soc_tplg_vendor_array *tuples, u32 block_size) { struct avs_tplg_module *module; + u32 esize; int ret; + /* See where config id block starts. */ + ret = avs_tplg_vendor_entry_size(tuples, block_size, + AVS_TKN_MOD_INIT_CONFIG_ID_U32, &esize); + if (ret) + return ERR_PTR(ret); + module = devm_kzalloc(comp->card->dev, sizeof(*module), GFP_KERNEL); if (!module) return ERR_PTR(-ENOMEM); ret = avs_parse_tokens(comp, module, module_parsers, - ARRAY_SIZE(module_parsers), tuples, block_size); + ARRAY_SIZE(module_parsers), tuples, esize); if (ret < 0) return ERR_PTR(ret); + block_size -= esize; + /* Parse trailing config ids if any. */ + if (block_size) { + u32 num_config_ids = module->num_config_ids; + u32 *config_ids; + + if (!num_config_ids) + return ERR_PTR(-EINVAL); + + config_ids = devm_kcalloc(comp->card->dev, num_config_ids, sizeof(*config_ids), + GFP_KERNEL); + if (!config_ids) + return ERR_PTR(-ENOMEM); + + tuples = avs_tplg_vendor_array_at(tuples, esize); + ret = parse_dictionary_entries(comp, tuples, block_size, + config_ids, num_config_ids, sizeof(*config_ids), + AVS_TKN_MOD_INIT_CONFIG_ID_U32, + init_config_parsers, + ARRAY_SIZE(init_config_parsers)); + if (ret) + return ERR_PTR(ret); + + module->config_ids = config_ids; + } + module->owner = owner; INIT_LIST_HEAD(&module->node); @@ -1416,6 +1464,82 @@ avs_tplg_path_template_create(struct snd_soc_component *comp, struct avs_tplg *o return template; } +static const struct avs_tplg_token_parser mod_init_config_parsers[] = { + { + .token = AVS_TKN_MOD_INIT_CONFIG_ID_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_tplg_init_config, id), + .parse = avs_parse_word_token, + }, + { + .token = AVS_TKN_INIT_CONFIG_PARAM_U8, + .type = SND_SOC_TPLG_TUPLE_TYPE_BYTE, + .offset = offsetof(struct avs_tplg_init_config, param), + .parse = avs_parse_byte_token, + }, + { + .token = AVS_TKN_INIT_CONFIG_LENGTH_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_tplg_init_config, length), + .parse = avs_parse_word_token, + }, +}; + +static int avs_tplg_parse_initial_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 tuple section telling how many init configs there are. */ + ret = parse_dictionary_header(comp, tuples, (void **)&tplg->init_configs, + &tplg->num_init_configs, + sizeof(*tplg->init_configs), + AVS_TKN_MANIFEST_NUM_INIT_CONFIGS_U32); + if (ret) + return ret; + + block_size -= le32_to_cpu(tuples->size); + /* With header parsed, move on to parsing entries. */ + tuples = avs_tplg_vendor_array_next(tuples); + + for (i = 0; i < tplg->num_init_configs && block_size > 0; i++) { + struct avs_tplg_init_config *config = &tplg->init_configs[i]; + struct snd_soc_tplg_vendor_array *tmp; + void *init_config_data; + u32 esize; + + /* + * Usually to get section length we search for first token of next group of data, + * but in this case we can't as tuples are followed by raw data. + */ + tmp = avs_tplg_vendor_array_next(tuples); + esize = le32_to_cpu(tuples->size) + le32_to_cpu(tmp->size); + + ret = parse_dictionary_entries(comp, tuples, esize, config, 1, sizeof(*config), + AVS_TKN_MOD_INIT_CONFIG_ID_U32, + mod_init_config_parsers, + ARRAY_SIZE(mod_init_config_parsers)); + + block_size -= esize; + + /* handle raw data section */ + init_config_data = (void *)tuples + esize; + esize = config->length; + + config->data = devm_kmemdup(comp->card->dev, init_config_data, esize, GFP_KERNEL); + if (!config->data) + return -ENOMEM; + + tuples = init_config_data + esize; + block_size -= esize; + } + + return 0; +} + static int avs_route_load(struct snd_soc_component *comp, int index, struct snd_soc_dapm_route *route) { @@ -1571,6 +1695,7 @@ static int avs_manifest(struct snd_soc_component *comp, int index, struct snd_soc_tplg_vendor_array *tuples = manifest->priv.array; struct avs_soc_component *acomp = to_avs_soc_component(comp); size_t remaining = le32_to_cpu(manifest->priv.size); + bool has_init_config = true; u32 offset; int ret; @@ -1668,8 +1793,43 @@ static int avs_manifest(struct snd_soc_component *comp, int index, remaining -= offset; tuples = avs_tplg_vendor_array_at(tuples, offset); + ret = avs_tplg_vendor_array_lookup(tuples, remaining, + AVS_TKN_MANIFEST_NUM_CONDPATH_TMPLS_U32, &offset); + if (ret) { + dev_err(comp->dev, "condpath lookup failed: %d\n", ret); + return ret; + } + /* Bindings dictionary. */ - return avs_tplg_parse_bindings(comp, tuples, remaining); + ret = avs_tplg_parse_bindings(comp, tuples, offset); + if (ret < 0) + return ret; + + remaining -= offset; + tuples = avs_tplg_vendor_array_at(tuples, offset); + + ret = avs_tplg_vendor_array_lookup(tuples, remaining, + AVS_TKN_MANIFEST_NUM_INIT_CONFIGS_U32, &offset); + if (ret == -ENOENT) { + dev_dbg(comp->dev, "init config lookup failed: %d\n", ret); + has_init_config = false; + } else if (ret) { + dev_err(comp->dev, "init config lookup failed: %d\n", ret); + return ret; + } + + if (!has_init_config) + return 0; + + remaining -= offset; + tuples = avs_tplg_vendor_array_at(tuples, offset); + + /* Initial configs dictionary. */ + ret = avs_tplg_parse_initial_configs(comp, tuples, remaining); + if (ret < 0) + return ret; + + return 0; } #define AVS_CONTROL_OPS_VOLUME 257 diff --git a/sound/soc/intel/avs/topology.h b/sound/soc/intel/avs/topology.h index 6e1c8e9b2496..6a59dd766603 100644 --- a/sound/soc/intel/avs/topology.h +++ b/sound/soc/intel/avs/topology.h @@ -33,6 +33,9 @@ struct avs_tplg { u32 num_pplcfgs; struct avs_tplg_binding *bindings; u32 num_bindings; + u32 num_condpath_tmpls; + struct avs_tplg_init_config *init_configs; + u32 num_init_configs; struct list_head path_tmpl_list; }; @@ -147,6 +150,14 @@ struct avs_tplg_path_template { struct list_head node; }; +struct avs_tplg_init_config { + u32 id; + + u8 param; + size_t length; + void *data; +}; + struct avs_tplg_path { u32 id; @@ -183,6 +194,8 @@ struct avs_tplg_module { u8 domain; struct avs_tplg_modcfg_ext *cfg_ext; u32 ctl_id; + u32 num_config_ids; + u32 *config_ids; struct avs_tplg_pipeline *owner; /* Pipeline modules management. */ From 8a49ef789b1be68242624d460df2ada8087308a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Thu, 8 Feb 2024 11:24:00 +0100 Subject: [PATCH 3/3] ASoC: Intel: avs: Send initial config to module if present MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If there are initial configs to send to module on init do send them. Reviewed-by: Cezary Rojewski Signed-off-by: Amadeusz Sławiński Link: https://lore.kernel.org/r/20240208102400.2497791-4-amadeuszx.slawinski@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/avs/path.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/sound/soc/intel/avs/path.c b/sound/soc/intel/avs/path.c index 3aa16ee8d34c..e785fc2a7008 100644 --- a/sound/soc/intel/avs/path.c +++ b/sound/soc/intel/avs/path.c @@ -547,6 +547,33 @@ static int avs_path_module_type_create(struct avs_dev *adev, struct avs_path_mod return avs_modext_create(adev, mod); } +static int avs_path_module_send_init_configs(struct avs_dev *adev, struct avs_path_module *mod) +{ + struct avs_soc_component *acomp; + + acomp = to_avs_soc_component(mod->template->owner->owner->owner->owner->comp); + + u32 num_ids = mod->template->num_config_ids; + u32 *ids = mod->template->config_ids; + + for (int i = 0; i < num_ids; i++) { + struct avs_tplg_init_config *config = &acomp->tplg->init_configs[ids[i]]; + size_t len = config->length; + void *data = config->data; + u32 param = config->param; + int ret; + + ret = avs_ipc_set_large_config(adev, mod->module_id, mod->instance_id, + param, data, len); + if (ret) { + dev_err(adev->dev, "send initial module config failed: %d\n", ret); + return AVS_IPC_RET(ret); + } + } + + return 0; +} + static void avs_path_module_free(struct avs_dev *adev, struct avs_path_module *mod) { kfree(mod); @@ -580,6 +607,12 @@ avs_path_module_create(struct avs_dev *adev, return ERR_PTR(ret); } + ret = avs_path_module_send_init_configs(adev, mod); + if (ret) { + kfree(mod); + return ERR_PTR(ret); + } + return mod; }