Unverified Commit 6d5997c4 authored by Bard Liao's avatar Bard Liao Committed by Mark Brown
Browse files

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: default avatarBard Liao <yung-chuan.liao@linux.intel.com>
Reviewed-by: default avatarLiam Girdwood <liam.r.girdwood@intel.com>
Reviewed-by: default avatarRanjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: default avatarPéter Ujfalusi <peter.ujfalusi@linux.intel.com>
Link: https://patch.msgid.link/20250414063239.85200-5-yung-chuan.liao@linux.intel.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent d1e70eed
Loading
Loading
Loading
Loading
+68 −18
Original line number Diff line number Diff line
@@ -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,18 +2469,57 @@ 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;

	tplg_files = kcalloc(scomp->card->num_links, sizeof(char *), GFP_KERNEL);
	if (!tplg_files)
		return -ENOMEM;

	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;
		}
	}

	/*
	 * 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);
	}

	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]);

	ret = request_firmware(&fw, file, scomp->dev);
		ret = request_firmware(&fw, tplg_files[i], 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;
			/*
			 * 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)
@@ -2486,15 +2527,24 @@ int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file)
		else
			ret = snd_soc_tplg_component_load(scomp, &sof_tplg_ops, fw);

	if (ret < 0)
		dev_err(scomp->dev, "error: tplg component load failed %d\n",
			ret);

		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);