ASoC: SOF: topology: load multiple topologies

Currently, we always use single topology file to describe the widgets.
However, with SDCA, we want to be able to load sub-topologies based on
the supported device functions.

Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Reviewed-by: Liam Girdwood <liam.r.girdwood@intel.com>
Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
Link: https://patch.msgid.link/20250414063239.85200-5-yung-chuan.liao@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Bard Liao 2025-04-14 14:32:32 +08:00 committed by Mark Brown
parent d1e70eed0b
commit 6d5997c412
No known key found for this signature in database
GPG key ID: 24D68B725D5487D0

View file

@ -2310,8 +2310,10 @@ static const struct snd_soc_tplg_ops sof_tplg_ops = {
.link_load = sof_link_load,
.link_unload = sof_link_unload,
/* completion - called at completion of firmware loading */
.complete = sof_complete,
/*
* No need to set the complete callback. sof_complete will be called explicitly after
* topology loading is complete.
*/
/* manifest - optional to inform component of manifest */
.manifest = sof_manifest,
@ -2467,34 +2469,82 @@ static const struct snd_soc_tplg_ops sof_dspless_tplg_ops = {
int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file)
{
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct snd_sof_pdata *sof_pdata = sdev->pdata;
const char *tplg_filename_prefix = sof_pdata->tplg_filename_prefix;
const struct firmware *fw;
const char **tplg_files;
int tplg_cnt = 0;
int ret;
int i;
dev_dbg(scomp->dev, "loading topology:%s\n", file);
tplg_files = kcalloc(scomp->card->num_links, sizeof(char *), GFP_KERNEL);
if (!tplg_files)
return -ENOMEM;
ret = request_firmware(&fw, file, scomp->dev);
if (ret < 0) {
dev_err(scomp->dev, "error: tplg request firmware %s failed err: %d\n",
file, ret);
dev_err(scomp->dev,
"you may need to download the firmware from https://github.com/thesofproject/sof-bin/\n");
return ret;
if (sof_pdata->machine->get_function_tplg_files) {
tplg_cnt = sof_pdata->machine->get_function_tplg_files(scomp->card,
sof_pdata->machine,
tplg_filename_prefix,
&tplg_files);
if (tplg_cnt < 0) {
kfree(tplg_files);
return tplg_cnt;
}
}
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);
/*
* The monolithic topology will be used if there is no get_function_tplg_files
* callback or the callback returns 0.
*/
if (!tplg_cnt) {
tplg_files[0] = file;
tplg_cnt = 1;
dev_dbg(scomp->dev, "loading topology: %s\n", file);
} else {
dev_info(scomp->dev, "Using function topologies instead %s\n", file);
}
if (ret < 0)
dev_err(scomp->dev, "error: tplg component load failed %d\n",
ret);
for (i = 0; i < tplg_cnt; i++) {
/* Only print the file names if the function topologies are used */
if (tplg_files[0] != file)
dev_info(scomp->dev, "loading topology %d: %s\n", i, tplg_files[i]);
release_firmware(fw);
ret = request_firmware(&fw, tplg_files[i], 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_err(scomp->dev, "tplg request firmware %s failed err: %d\n",
tplg_files[i], ret);
goto out;
}
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, "tplg %s component load failed %d\n",
tplg_files[i], ret);
goto out;
}
}
/* call sof_complete when topologies are loaded successfully */
ret = sof_complete(scomp);
out:
if (ret >= 0 && sdev->led_present)
ret = snd_ctl_led_request();
kfree(tplg_files);
return ret;
}
EXPORT_SYMBOL(snd_sof_load_topology);