ASoC: SOF: topology: allow user to add topologies

Bard Liao <yung-chuan.liao@linux.intel.com> says:

This series adds a module parameter array to allow users to load specific
feature topologies.
This commit is contained in:
Mark Brown 2026-04-27 08:29:02 +09:00
commit 0d13279992
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0
2 changed files with 65 additions and 1 deletions

View File

@ -19,6 +19,7 @@ enum tplg_device_id {
TPLG_DEVICE_SDCA_MIC,
TPLG_DEVICE_INTEL_PCH_DMIC,
TPLG_DEVICE_HDMI,
TPLG_DEVICE_LOOPBACK_VIRTUAL,
TPLG_DEVICE_MAX
};
@ -81,7 +82,15 @@ int sof_sdw_get_tplg_files(struct snd_soc_card *card, const struct snd_soc_acpi_
} else if (strstr(dai_link->name, "iDisp")) {
tplg_dev = TPLG_DEVICE_HDMI;
tplg_dev_name = "hdmi-pcm5";
} else if (strstr(dai_link->name, "Loopback_Virtual")) {
tplg_dev = TPLG_DEVICE_LOOPBACK_VIRTUAL;
/*
* Mark the LOOPBACK_VIRTUAL device but no need to create the
* LOOPBACK_VIRTUAL topology. Just to avoid the dai_link is not supported
* error.
*/
tplg_mask |= BIT(tplg_dev);
continue;
} else {
/* The dai link is not supported by separated tplg yet */
dev_dbg(card->dev,

View File

@ -23,6 +23,13 @@ static bool disable_function_topology;
module_param(disable_function_topology, bool, 0444);
MODULE_PARM_DESC(disable_function_topology, "Disable function topology loading");
#define MAX_FEATURE_TPLG_COUNT 16
static char *feature_topologies[MAX_FEATURE_TPLG_COUNT];
static int feature_tplg_cnt;
module_param_array(feature_topologies, charp, &feature_tplg_cnt, 0444);
MODULE_PARM_DESC(feature_topologies, "Topology list for virtual loop DAI link");
#define COMP_ID_UNASSIGNED 0xffffffff
/*
* Constants used in the computation of linear volume gain
@ -2575,6 +2582,54 @@ int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file)
}
}
/* Loading user defined topologies */
for (i = 0; i < feature_tplg_cnt; i++) {
const char *feature_topology = devm_kasprintf(scomp->dev, GFP_KERNEL, "%s/%s",
tplg_filename_prefix,
feature_topologies[i]);
if (!feature_topology) {
ret = -ENOMEM;
goto out;
}
dev_info(scomp->dev, "loading feature topology %d: %s\n", i, feature_topology);
ret = request_firmware(&fw, feature_topology, scomp->dev);
if (ret < 0) {
/*
* snd_soc_tplg_component_remove(scomp) will be called
* if snd_soc_tplg_component_load(scomp) failed and all
* objects in the scomp will be removed. No need to call
* snd_soc_tplg_component_remove(scomp) here.
*/
dev_warn(scomp->dev, "feature tplg request firmware %s failed err: %d\n",
feature_topologies[i], ret);
/*
* We don't return error here because we can still have the basic
* audio feature when the function topology load complete. No need
* to convert the error code because we will get new 'ret' out of the
* loop.
*/
continue;
}
if (sdev->dspless_mode_selected)
ret = snd_soc_tplg_component_load(scomp, &sof_dspless_tplg_ops, fw);
else
ret = snd_soc_tplg_component_load(scomp, &sof_tplg_ops, fw);
release_firmware(fw);
if (ret < 0) {
dev_err(scomp->dev, "feature tplg %s component load failed %d\n",
feature_topologies[i], ret);
/*
* We need to return error here because it may lead to kernel NULL pointer
* dereference if we continue the remaining tasks.
*/
goto out;
}
}
/* call sof_complete when topologies are loaded successfully */
ret = sof_complete(scomp);