From a37af8b4d05bbf14c4f999b15c4a7668b2e0019f Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Thu, 22 Oct 2026 23:01:19 +0800 Subject: [PATCH 1/2] ASoC: Intel: sof-function-topology-lib: Provide option to skip function topology loading Allow users to skip loading specific function topologies when the BE links are problematic or not required. Signed-off-by: Bard Liao --- .../intel/common/sof-function-topology-lib.c | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/sound/soc/intel/common/sof-function-topology-lib.c b/sound/soc/intel/common/sof-function-topology-lib.c index 57e089f8e721dc..cdbaf62ab6fc96 100644 --- a/sound/soc/intel/common/sof-function-topology-lib.c +++ b/sound/soc/intel/common/sof-function-topology-lib.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include "sof-function-topology-lib.h" @@ -27,6 +28,11 @@ enum tplg_device_id { TPLG_DEVICE_MAX }; +static int function_tplg_mask = -1; +module_param(function_tplg_mask, int, 0444); +MODULE_PARM_DESC(function_tplg_mask, + "Function topology selection mask, BIT(tplg_device_id); -1: all devices"); + #define SDCA_DEVICE_MASK (BIT(TPLG_DEVICE_SDCA_JACK) | BIT(TPLG_DEVICE_SDCA_AMP) | \ BIT(TPLG_DEVICE_SDCA_MIC)) @@ -182,6 +188,11 @@ int sof_sdw_get_tplg_files(struct snd_soc_card *card, const struct snd_soc_acpi_ int ret; int i; + if (function_tplg_mask >= 0) { + tplg_mask = ~(unsigned long)function_tplg_mask; + best_effort = true; + } + ret = get_platform_name(card, mach, platform); if (ret < 0) return ret; @@ -257,6 +268,12 @@ int sof_sdw_get_tplg_files(struct snd_soc_card *card, const struct snd_soc_acpi_ dev_dbg(card->dev, "tplg_mask %#lx tplg_num %d\n", tplg_mask, tplg_num); + if (function_tplg_mask >= 0 && !tplg_num) { + dev_err(card->dev, "No function topology available for mask %#x\n", + function_tplg_mask); + return -ENOENT; + } + return tplg_num; } EXPORT_SYMBOL_GPL(sof_sdw_get_tplg_files); @@ -275,6 +292,11 @@ int sof_i2s_get_tplg_files(struct snd_soc_card *card, const struct snd_soc_acpi_ int ret; int i; + if (function_tplg_mask >= 0) { + tplg_mask = ~(unsigned long)function_tplg_mask; + best_effort = true; + } + ret = get_platform_name(card, mach, platform); if (ret < 0) return ret; @@ -329,6 +351,12 @@ int sof_i2s_get_tplg_files(struct snd_soc_card *card, const struct snd_soc_acpi_ dev_dbg(card->dev, "tplg_mask %#lx tplg_num %d\n", tplg_mask, tplg_num); + if (function_tplg_mask >= 0 && !tplg_num) { + dev_err(card->dev, "No function topology available for mask %#x\n", + function_tplg_mask); + return -ENOENT; + } + return tplg_num; } EXPORT_SYMBOL_GPL(sof_i2s_get_tplg_files); From 01cbec4e8f667d338c9e9e1d1d566ed5db715eba Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Fri, 23 Oct 2026 16:06:47 +0800 Subject: [PATCH 2/2] ASoC: Intel: SOF: Add function topology variants parameter While we can load feature topologies to add features to the generial function topology, we can not change the modules in the function topology. This commit allow selecting function topology variants through the feature_variant module parameter to use the variant function topology instead of the generic function topology. Fall back to the generic topology when a configured variant is unavailable. Signed-off-by: Bard Liao --- .../intel/common/sof-function-topology-lib.c | 78 ++++++++++++++++++- 1 file changed, 74 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/common/sof-function-topology-lib.c b/sound/soc/intel/common/sof-function-topology-lib.c index cdbaf62ab6fc96..9a91801642f979 100644 --- a/sound/soc/intel/common/sof-function-topology-lib.c +++ b/sound/soc/intel/common/sof-function-topology-lib.c @@ -33,6 +33,15 @@ module_param(function_tplg_mask, int, 0444); MODULE_PARM_DESC(function_tplg_mask, "Function topology selection mask, BIT(tplg_device_id); -1: all devices"); +#define MAX_FEATURE_VARIANTS 16 + +static char *function_variant[MAX_FEATURE_VARIANTS]; +static int function_variant_count; +module_param_array(function_variant, charp, &function_variant_count, 0444); +MODULE_PARM_DESC(function_variant, + "Feature topology variants as feature-name:variant pairs separated by commas; " + "variant is appended before .tplg"); + #define SDCA_DEVICE_MASK (BIT(TPLG_DEVICE_SDCA_JACK) | BIT(TPLG_DEVICE_SDCA_AMP) | \ BIT(TPLG_DEVICE_SDCA_MIC)) @@ -76,7 +85,12 @@ static char *get_tplg_filename(struct device *dev, const char *prefix, const char *platform, const char *tplg_dev_name, int dai_link_id, int tplg_dev) { - char *filename = NULL; + const struct firmware *fw; + char *variant_name = NULL; + char *tplg_filename; + char *filename; + int i; + int ret; /* * The tplg file naming rule is sof---id.tplg @@ -89,16 +103,72 @@ static char *get_tplg_filename(struct device *dev, const char *prefix, case TPLG_DEVICE_SSP_AMP: case TPLG_DEVICE_SSP_BT: case TPLG_DEVICE_SSP_HDMI_IN: - filename = devm_kasprintf(dev, GFP_KERNEL, "%s/sof-%s-%s-id%d.tplg", + filename = devm_kasprintf(dev, GFP_KERNEL, "%s/sof-%s-%s-id%d", prefix, platform, tplg_dev_name, dai_link_id); + if (function_variant_count) + variant_name = devm_kasprintf(dev, GFP_KERNEL, + "sof-%s-%s-id%d", platform, + tplg_dev_name, dai_link_id); break; default: - filename = devm_kasprintf(dev, GFP_KERNEL, "%s/sof-%s-id%d.tplg", + filename = devm_kasprintf(dev, GFP_KERNEL, "%s/sof-%s-id%d", prefix, tplg_dev_name, dai_link_id); + if (function_variant_count) + variant_name = devm_kasprintf(dev, GFP_KERNEL, "sof-%s-id%d", + tplg_dev_name, dai_link_id); break; } - return filename; + if (!filename) + return NULL; + + if (function_variant_count && !variant_name) { + dev_warn(dev, "Failed to allocate memory for variant_name, using %s.tplg\n", filename); + goto add_extension; + } + + for (i = 0; i < function_variant_count; i++) { + const char *entry = function_variant[i]; + const char *separator = strchr(entry, ':'); + + if (separator && separator != entry && separator[1]) { + if (separator - entry == strlen(variant_name) && + !strncmp(entry, variant_name, separator - entry)) { + char *variant_filename; + + devm_kfree(dev, variant_name); + variant_name = NULL; + variant_filename = devm_kasprintf(dev, GFP_KERNEL, "%s-%s.tplg", + filename, separator + 1); + if (!variant_filename) + return NULL; + ret = firmware_request_nowarn(&fw, variant_filename, dev); + if (!ret) { + release_firmware(fw); + devm_kfree(dev, filename); + return variant_filename; + } else { + dev_dbg(dev, + "Variant topology %s not found, using %s.tplg\n", + variant_filename, filename); + devm_kfree(dev, variant_filename); + } + break; + } + } + } + + if (variant_name) + devm_kfree(dev, variant_name); + +add_extension: + tplg_filename = devm_kasprintf(dev, GFP_KERNEL, "%s.tplg", filename); + + if (!tplg_filename) + return NULL; + + devm_kfree(dev, filename); + return tplg_filename; } static int get_dmic_tplg_dev(struct device *dev, int dmic_num,