summaryrefslogtreecommitdiff
path: root/sound/soc/intel/common/sof-function-topology-lib.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/intel/common/sof-function-topology-lib.c')
-rw-r--r--sound/soc/intel/common/sof-function-topology-lib.c281
1 files changed, 229 insertions, 52 deletions
diff --git a/sound/soc/intel/common/sof-function-topology-lib.c b/sound/soc/intel/common/sof-function-topology-lib.c
index b6e5a40b78cc..57e089f8e721 100644
--- a/sound/soc/intel/common/sof-function-topology-lib.c
+++ b/sound/soc/intel/common/sof-function-topology-lib.c
@@ -19,6 +19,10 @@ enum tplg_device_id {
TPLG_DEVICE_SDCA_MIC,
TPLG_DEVICE_INTEL_PCH_DMIC,
TPLG_DEVICE_HDMI,
+ TPLG_DEVICE_SSP_JACK,
+ TPLG_DEVICE_SSP_AMP,
+ TPLG_DEVICE_SSP_BT,
+ TPLG_DEVICE_SSP_HDMI_IN,
TPLG_DEVICE_LOOPBACK_VIRTUAL,
TPLG_DEVICE_MAX
};
@@ -28,6 +32,137 @@ enum tplg_device_id {
#define SOF_INTEL_PLATFORM_NAME_MAX 4
+static int get_platform_name(struct snd_soc_card *card,
+ const struct snd_soc_acpi_mach *mach, char *platform)
+{
+ int ret;
+
+ ret = sscanf(mach->sof_tplg_filename, "sof-%3s-*.tplg", platform);
+ if (ret != 1) {
+ dev_err(card->dev, "Invalid platform name of tplg %s\n",
+ mach->sof_tplg_filename);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static bool tplg_files_exist(struct device *dev, const char *tplg_files)
+{
+ const struct firmware *fw;
+ int ret;
+
+ ret = firmware_request_nowarn(&fw, tplg_files, dev);
+ if (!ret) {
+ release_firmware(fw);
+ return true;
+ }
+
+ dev_warn(dev,
+ "Failed to open topology file: %s, you might need to\n",
+ tplg_files);
+ dev_warn(dev,
+ "download it from https://github.com/thesofproject/sof-bin/\n");
+ return false;
+}
+
+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;
+
+ /*
+ * The tplg file naming rule is sof-<platform>-<function>-id<BE id number>.tplg
+ * where <platform> is required for functions that depend on NHLT blobs (e.g. DMIC/SSP)
+ * as the nhlt blob is platform dependent.
+ */
+ switch (tplg_dev) {
+ case TPLG_DEVICE_INTEL_PCH_DMIC:
+ case TPLG_DEVICE_SSP_JACK:
+ 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",
+ prefix, platform, tplg_dev_name, dai_link_id);
+ break;
+ default:
+ filename = devm_kasprintf(dev, GFP_KERNEL, "%s/sof-%s-id%d.tplg",
+ prefix, tplg_dev_name, dai_link_id);
+ break;
+ }
+
+ return filename;
+}
+
+static int get_dmic_tplg_dev(struct device *dev, int dmic_num,
+ int *tplg_dev, char **tplg_dev_name)
+{
+ switch (dmic_num) {
+ case 2:
+ *tplg_dev_name = "dmic-2ch";
+ break;
+ case 4:
+ *tplg_dev_name = "dmic-4ch";
+ break;
+ default:
+ dev_warn(dev,
+ "unsupported number of dmics: %d\n",
+ dmic_num);
+ return -EINVAL;
+ }
+ *tplg_dev = TPLG_DEVICE_INTEL_PCH_DMIC;
+
+ return 0;
+}
+
+static int get_ssp_tplg_dev(struct device *dev, struct snd_soc_dai_link *dai_link,
+ u16 *hdmi_in_mask, int *tplg_dev, char **tplg_dev_name)
+{
+ unsigned int ssp_port;
+
+ if (sscanf(dai_link->name, "SSP%u", &ssp_port) != 1) {
+ dev_err(dev, "Can't get SSP port from dai_link->name %s\n", dai_link->name);
+ return -EINVAL;
+ }
+ if (strstr(dai_link->name, "Codec")) {
+ /*
+ * Assume DAI link 0 is jack which is true in all existing
+ * machine drivers
+ */
+ if (dai_link->id == 0) {
+ *tplg_dev = TPLG_DEVICE_SSP_JACK;
+ *tplg_dev_name = devm_kasprintf(dev, GFP_KERNEL,
+ "ssp%d-jack", ssp_port);
+ } else {
+ *tplg_dev = TPLG_DEVICE_SSP_AMP;
+ *tplg_dev_name = devm_kasprintf(dev, GFP_KERNEL,
+ "ssp%d-amp", ssp_port);
+ }
+ } else if (strstr(dai_link->name, "BT")) {
+ *tplg_dev = TPLG_DEVICE_SSP_BT;
+ *tplg_dev_name = devm_kasprintf(dev, GFP_KERNEL,
+ "ssp%d-bt", ssp_port);
+ } else if (strstr(dai_link->name, "HDMI")) {
+ *hdmi_in_mask |= BIT(ssp_port);
+ /* The number of HDMI in dai link is always 2 right now */
+ if (hweight16(*hdmi_in_mask) != 2)
+ return -EINVAL;
+
+ *tplg_dev = TPLG_DEVICE_SSP_HDMI_IN;
+ *tplg_dev_name = devm_kasprintf(dev, GFP_KERNEL,
+ "ssp%x-hdmiin", *hdmi_in_mask);
+ } else {
+ dev_warn(dev,
+ "unsupported SSP link %s\n", dai_link->name);
+ return -EINVAL;
+ }
+ if (!*tplg_dev_name)
+ return -ENOMEM;
+
+ return 0;
+}
+
int sof_sdw_get_tplg_files(struct snd_soc_card *card, const struct snd_soc_acpi_mach *mach,
const char *prefix, const char ***tplg_files, bool best_effort)
{
@@ -38,20 +173,18 @@ int sof_sdw_get_tplg_files(struct snd_soc_card *card, const struct snd_soc_acpi_
*/
struct snd_soc_acpi_mach_params mach_params = card_mach->mach_params;
struct snd_soc_dai_link *dai_link;
- const struct firmware *fw;
char platform[SOF_INTEL_PLATFORM_NAME_MAX];
unsigned long tplg_mask = 0;
+ u16 hdmi_in_mask = 0;
int tplg_num = 0;
+ char *tplg_file;
int tplg_dev;
int ret;
int i;
- ret = sscanf(mach->sof_tplg_filename, "sof-%3s-*.tplg", platform);
- if (ret != 1) {
- dev_err(card->dev, "Invalid platform name %s of tplg %s\n",
- platform, mach->sof_tplg_filename);
- return -EINVAL;
- }
+ ret = get_platform_name(card, mach, platform);
+ if (ret < 0)
+ return ret;
for_each_card_prelinks(card, i, dai_link) {
char *tplg_dev_name;
@@ -70,23 +203,16 @@ int sof_sdw_get_tplg_files(struct snd_soc_card *card, const struct snd_soc_acpi_
tplg_dev = TPLG_DEVICE_SDCA_MIC;
tplg_dev_name = "sdca-mic";
} else if (strstr(dai_link->name, "dmic")) {
- switch (mach_params.dmic_num) {
- case 2:
- tplg_dev_name = "dmic-2ch";
- break;
- case 4:
- tplg_dev_name = "dmic-4ch";
- break;
- default:
- dev_warn(card->dev,
- "unsupported number of dmics: %d\n",
- mach_params.dmic_num);
+ if (get_dmic_tplg_dev(card->dev, mach_params.dmic_num,
+ &tplg_dev, &tplg_dev_name) < 0)
continue;
- }
- tplg_dev = TPLG_DEVICE_INTEL_PCH_DMIC;
} else if (strstr(dai_link->name, "iDisp")) {
tplg_dev = TPLG_DEVICE_HDMI;
tplg_dev_name = "hdmi-pcm5";
+ } else if (strstr(dai_link->name, "SSP")) {
+ if (get_ssp_tplg_dev(card->dev, dai_link, &hdmi_in_mask,
+ &tplg_dev, &tplg_dev_name) < 0)
+ continue;
} else if (strstr(dai_link->name, "Loopback_Virtual")) {
tplg_dev = TPLG_DEVICE_LOOPBACK_VIRTUAL;
/*
@@ -109,49 +235,100 @@ int sof_sdw_get_tplg_files(struct snd_soc_card *card, const struct snd_soc_acpi_
if (tplg_mask & BIT(tplg_dev))
continue;
- tplg_mask |= BIT(tplg_dev);
+ tplg_file = get_tplg_filename(card->dev, prefix, platform, tplg_dev_name,
+ dai_link->id, tplg_dev);
+ if (!tplg_file)
+ return -ENOMEM;
- /*
- * The tplg file naming rule is sof-<platform>-<function>-id<BE id number>.tplg
- * where <platform> is only required for the DMIC function as the nhlt blob
- * is platform dependent.
- */
- switch (tplg_dev) {
- case TPLG_DEVICE_INTEL_PCH_DMIC:
- (*tplg_files)[tplg_num] = devm_kasprintf(card->dev, GFP_KERNEL,
- "%s/sof-%s-%s-id%d.tplg",
- prefix, platform,
- tplg_dev_name, dai_link->id);
- break;
- default:
- (*tplg_files)[tplg_num] = devm_kasprintf(card->dev, GFP_KERNEL,
- "%s/sof-%s-id%d.tplg",
- prefix, tplg_dev_name,
- dai_link->id);
- break;
+ /* Check presence of sub-topologies */
+ if (!tplg_files_exist(card->dev, tplg_file)) {
+ devm_kfree(card->dev, tplg_file);
+ if (best_effort)
+ continue;
+
+ return 0;
}
- if (!(*tplg_files)[tplg_num])
- return -ENOMEM;
+
+ tplg_mask |= BIT(tplg_dev);
+
+ (*tplg_files)[tplg_num] = tplg_file;
tplg_num++;
}
dev_dbg(card->dev, "tplg_mask %#lx tplg_num %d\n", tplg_mask, tplg_num);
- /* Check presence of sub-topologies */
- for (i = 0; i < tplg_num; i++) {
- ret = firmware_request_nowarn(&fw, (*tplg_files)[i], card->dev);
- if (!ret) {
- release_firmware(fw);
+ return tplg_num;
+}
+EXPORT_SYMBOL_GPL(sof_sdw_get_tplg_files);
+
+int sof_i2s_get_tplg_files(struct snd_soc_card *card, const struct snd_soc_acpi_mach *mach,
+ const char *prefix, const char ***tplg_files, bool best_effort)
+{
+ struct snd_soc_acpi_mach_params mach_params = mach->mach_params;
+ struct snd_soc_dai_link *dai_link;
+ char platform[SOF_INTEL_PLATFORM_NAME_MAX];
+ unsigned long tplg_mask = 0;
+ u16 hdmi_in_mask = 0;
+ int tplg_num = 0;
+ char *tplg_file;
+ int tplg_dev;
+ int ret;
+ int i;
+
+ ret = get_platform_name(card, mach, platform);
+ if (ret < 0)
+ return ret;
+
+ for_each_card_prelinks(card, i, dai_link) {
+ char *tplg_dev_name;
+
+ dev_dbg(card->dev, "dai_link %s id %d\n", dai_link->name, dai_link->id);
+ if (strstr(dai_link->name, "SSP")) {
+ if (get_ssp_tplg_dev(card->dev, dai_link, &hdmi_in_mask,
+ &tplg_dev, &tplg_dev_name) < 0)
+ continue;
+ } else if (strstr(dai_link->name, "dmic")) {
+ if (get_dmic_tplg_dev(card->dev, mach_params.dmic_num,
+ &tplg_dev, &tplg_dev_name) < 0)
+ continue;
+ } else if (strstr(dai_link->name, "iDisp")) {
+ tplg_dev = TPLG_DEVICE_HDMI;
+ tplg_dev_name = "hdmi-pcm5";
} else {
- dev_warn(card->dev,
- "Failed to open topology file: %s, you might need to\n",
- (*tplg_files)[i]);
- dev_warn(card->dev,
- "download it from https://github.com/thesofproject/sof-bin/\n");
+ /* The dai link is not supported by separated tplg yet */
+ dev_dbg(card->dev,
+ "dai_link %s is not supported by separated tplg yet\n",
+ dai_link->name);
+ if (best_effort)
+ continue;
+
+ return 0;
+ }
+ if (tplg_mask & BIT(tplg_dev))
+ continue;
+
+ tplg_file = get_tplg_filename(card->dev, prefix, platform, tplg_dev_name,
+ dai_link->id, tplg_dev);
+ if (!tplg_file)
+ return -ENOMEM;
+
+ /* Check presence of sub-topologies */
+ if (!tplg_files_exist(card->dev, tplg_file)) {
+ devm_kfree(card->dev, tplg_file);
+ if (best_effort)
+ continue;
+
return 0;
}
+
+ tplg_mask |= BIT(tplg_dev);
+
+ (*tplg_files)[tplg_num] = tplg_file;
+ tplg_num++;
}
+ dev_dbg(card->dev, "tplg_mask %#lx tplg_num %d\n", tplg_mask, tplg_num);
+
return tplg_num;
}
-EXPORT_SYMBOL_GPL(sof_sdw_get_tplg_files);
+EXPORT_SYMBOL_GPL(sof_i2s_get_tplg_files);