Commit 276b83c8 authored by Cezary Rojewski's avatar Cezary Rojewski Committed by Mark Brown

ASoC: Intel: avs: Parse pipeline and module tuples

Shape of a path on DSP side, that is, the number and the layout of its
pipelines and modules is paramount for streaming to be efficient and low
power-consuming. Add parsing helpers to support loading such information
from the topology file.
Signed-off-by: default avatarAmadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
Signed-off-by: default avatarCezary Rojewski <cezary.rojewski@intel.com>
Link: https://lore.kernel.org/r/20220331135246.993089-6-cezary.rojewski@intel.comSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent 1fba2036
...@@ -1004,3 +1004,180 @@ static int avs_tplg_parse_bindings(struct snd_soc_component *comp, ...@@ -1004,3 +1004,180 @@ static int avs_tplg_parse_bindings(struct snd_soc_component *comp,
AVS_TKN_BINDING_ID_U32, AVS_TKN_BINDING_ID_U32,
binding_parsers, ARRAY_SIZE(binding_parsers)); binding_parsers, ARRAY_SIZE(binding_parsers));
} }
static const struct avs_tplg_token_parser module_parsers[] = {
{
.token = AVS_TKN_MOD_ID_U32,
.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
.offset = offsetof(struct avs_tplg_module, id),
.parse = avs_parse_word_token,
},
{
.token = AVS_TKN_MOD_MODCFG_BASE_ID_U32,
.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
.offset = offsetof(struct avs_tplg_module, cfg_base),
.parse = avs_parse_modcfg_base_ptr,
},
{
.token = AVS_TKN_MOD_IN_AFMT_ID_U32,
.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
.offset = offsetof(struct avs_tplg_module, in_fmt),
.parse = avs_parse_audio_format_ptr,
},
{
.token = AVS_TKN_MOD_CORE_ID_U8,
.type = SND_SOC_TPLG_TUPLE_TYPE_BYTE,
.offset = offsetof(struct avs_tplg_module, core_id),
.parse = avs_parse_byte_token,
},
{
.token = AVS_TKN_MOD_PROC_DOMAIN_U8,
.type = SND_SOC_TPLG_TUPLE_TYPE_BYTE,
.offset = offsetof(struct avs_tplg_module, domain),
.parse = avs_parse_byte_token,
},
{
.token = AVS_TKN_MOD_MODCFG_EXT_ID_U32,
.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
.offset = offsetof(struct avs_tplg_module, cfg_ext),
.parse = avs_parse_modcfg_ext_ptr,
},
};
static struct avs_tplg_module *
avs_tplg_module_create(struct snd_soc_component *comp, struct avs_tplg_pipeline *owner,
struct snd_soc_tplg_vendor_array *tuples, u32 block_size)
{
struct avs_tplg_module *module;
int 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);
if (ret < 0)
return ERR_PTR(ret);
module->owner = owner;
INIT_LIST_HEAD(&module->node);
return module;
}
static const struct avs_tplg_token_parser pipeline_parsers[] = {
{
.token = AVS_TKN_PPL_ID_U32,
.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
.offset = offsetof(struct avs_tplg_pipeline, id),
.parse = avs_parse_word_token,
},
{
.token = AVS_TKN_PPL_PPLCFG_ID_U32,
.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
.offset = offsetof(struct avs_tplg_pipeline, cfg),
.parse = avs_parse_pplcfg_ptr,
},
{
.token = AVS_TKN_PPL_NUM_BINDING_IDS_U32,
.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
.offset = offsetof(struct avs_tplg_pipeline, num_bindings),
.parse = avs_parse_word_token,
},
};
static const struct avs_tplg_token_parser bindings_parsers[] = {
{
.token = AVS_TKN_PPL_BINDING_ID_U32,
.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
.offset = 0, /* to treat pipeline->bindings as dictionary */
.parse = avs_parse_binding_ptr,
},
};
static struct avs_tplg_pipeline *
avs_tplg_pipeline_create(struct snd_soc_component *comp, struct avs_tplg_path *owner,
struct snd_soc_tplg_vendor_array *tuples, u32 block_size)
{
struct avs_tplg_pipeline *pipeline;
u32 modblk_size, offset;
int ret;
pipeline = devm_kzalloc(comp->card->dev, sizeof(*pipeline), GFP_KERNEL);
if (!pipeline)
return ERR_PTR(-ENOMEM);
pipeline->owner = owner;
INIT_LIST_HEAD(&pipeline->mod_list);
/* Pipeline header MUST be followed by at least one module. */
ret = avs_tplg_vendor_array_lookup(tuples, block_size,
AVS_TKN_MOD_ID_U32, &offset);
if (!ret && !offset)
ret = -EINVAL;
if (ret)
return ERR_PTR(ret);
/* Process header which precedes module sections. */
ret = avs_parse_tokens(comp, pipeline, pipeline_parsers,
ARRAY_SIZE(pipeline_parsers), tuples, offset);
if (ret < 0)
return ERR_PTR(ret);
block_size -= offset;
tuples = avs_tplg_vendor_array_at(tuples, offset);
/* Optionally, binding sections follow module ones. */
ret = avs_tplg_vendor_array_lookup_next(tuples, block_size,
AVS_TKN_PPL_BINDING_ID_U32, &offset);
if (ret) {
if (ret != -ENOENT)
return ERR_PTR(ret);
/* Does header information match actual block layout? */
if (pipeline->num_bindings)
return ERR_PTR(-EINVAL);
modblk_size = block_size;
} else {
pipeline->bindings = devm_kcalloc(comp->card->dev, pipeline->num_bindings,
sizeof(*pipeline->bindings), GFP_KERNEL);
if (!pipeline->bindings)
return ERR_PTR(-ENOMEM);
modblk_size = offset;
}
block_size -= modblk_size;
do {
struct avs_tplg_module *module;
u32 esize;
ret = avs_tplg_vendor_entry_size(tuples, modblk_size,
AVS_TKN_MOD_ID_U32, &esize);
if (ret)
return ERR_PTR(ret);
module = avs_tplg_module_create(comp, pipeline, tuples, esize);
if (IS_ERR(module)) {
dev_err(comp->dev, "parse module failed: %ld\n",
PTR_ERR(module));
return ERR_CAST(module);
}
list_add_tail(&module->node, &pipeline->mod_list);
modblk_size -= esize;
tuples = avs_tplg_vendor_array_at(tuples, esize);
} while (modblk_size > 0);
/* What's left is optional range of bindings. */
ret = parse_dictionary_entries(comp, tuples, block_size, pipeline->bindings,
pipeline->num_bindings, sizeof(*pipeline->bindings),
AVS_TKN_PPL_BINDING_ID_U32,
bindings_parsers, ARRAY_SIZE(bindings_parsers));
if (ret)
return ERR_PTR(ret);
return pipeline;
}
...@@ -128,4 +128,35 @@ struct avs_tplg_binding { ...@@ -128,4 +128,35 @@ struct avs_tplg_binding {
u8 is_sink; u8 is_sink;
}; };
struct avs_tplg_path {
u32 id;
};
struct avs_tplg_pipeline {
u32 id;
struct avs_tplg_pplcfg *cfg;
struct avs_tplg_binding **bindings;
u32 num_bindings;
struct list_head mod_list;
struct avs_tplg_path *owner;
/* Path pipelines management. */
struct list_head node;
};
struct avs_tplg_module {
u32 id;
struct avs_tplg_modcfg_base *cfg_base;
struct avs_audio_format *in_fmt;
u8 core_id;
u8 domain;
struct avs_tplg_modcfg_ext *cfg_ext;
struct avs_tplg_pipeline *owner;
/* Pipeline modules management. */
struct list_head node;
};
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment