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

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.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 1fba2036
Loading
Loading
Loading
Loading
+177 −0
Original line number Diff line number Diff line
@@ -1004,3 +1004,180 @@ static int avs_tplg_parse_bindings(struct snd_soc_component *comp,
				AVS_TKN_BINDING_ID_U32,
				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;
}
+31 −0
Original line number Diff line number Diff line
@@ -128,4 +128,35 @@ struct avs_tplg_binding {
	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