// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)//// This file is provided under a dual BSD/GPLv2 license. When using or// redistributing this file, you may do so under either license.//// Copyright(c) 2025 Intel Corporation.// #include <linux/device.h>#include <linux/errno.h>#include <linux/firmware.h>#include <sound/soc.h>#include <sound/soc-acpi.h>#include "sof-function-topology-lib.h" enum tplg_device_id { TPLG_DEVICE_SDCA_JACK, TPLG_DEVICE_SDCA_AMP, TPLG_DEVICE_SDCA_MIC, TPLG_DEVICE_INTEL_PCH_DMIC, TPLG_DEVICE_HDMI, TPLG_DEVICE_LOOPBACK_VIRTUAL, TPLG_DEVICE_MAX}; #define SDCA_DEVICE_MASK (BIT(TPLG_DEVICE_SDCA_JACK) | BIT(TPLG_DEVICE_SDCA_AMP) | \ BIT(TPLG_DEVICE_SDCA_MIC)) #define SOF_INTEL_PLATFORM_NAME_MAX 4 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){ struct snd_soc_acpi_mach *card_mach = dev_get_platdata(card->dev); /* * Use the acpi mach from the machine driver because the machine driver * may change the dmic_num based on the machine driver quirk. */ 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; int tplg_num = 0; 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; } 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, "SimpleJack")) { tplg_dev = TPLG_DEVICE_SDCA_JACK; tplg_dev_name = "sdca-jack"; } else if (strstr(dai_link->name, "SmartAmp")) { tplg_dev = TPLG_DEVICE_SDCA_AMP; tplg_dev_name = devm_kasprintf(card->dev, GFP_KERNEL, "sdca-%damp", dai_link->num_cpus); if (!tplg_dev_name) return -ENOMEM; } else if (strstr(dai_link->name, "SmartMic")) { 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); 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, "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, "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_mask |= BIT(tplg_dev); /* * 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; } if (!(*tplg_files)[tplg_num]) return -ENOMEM; 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); } 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"); return 0; } } return tplg_num;}EXPORT_SYMBOL_GPL(sof_sdw_get_tplg_files);
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
//
// Copyright(c) 2025 Intel Corporation.
//
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/firmware.h>
#include <sound/soc.h>
#include <sound/soc-acpi.h>
#include "sof-function-topology-lib.h"
enum tplg_device_id {
TPLG_DEVICE_SDCA_JACK,
TPLG_DEVICE_SDCA_AMP,
TPLG_DEVICE_SDCA_MIC,
TPLG_DEVICE_INTEL_PCH_DMIC,
TPLG_DEVICE_HDMI,
TPLG_DEVICE_LOOPBACK_VIRTUAL,
TPLG_DEVICE_MAX
};
#define SDCA_DEVICE_MASK (BIT(TPLG_DEVICE_SDCA_JACK) | BIT(TPLG_DEVICE_SDCA_AMP) | \
BIT(TPLG_DEVICE_SDCA_MIC))
#define SOF_INTEL_PLATFORM_NAME_MAX 4
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)
{
struct snd_soc_acpi_mach *card_mach = dev_get_platdata(card->dev);
/*
* Use the acpi mach from the machine driver because the machine driver
* may change the dmic_num based on the machine driver quirk.
*/
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;
int tplg_num = 0;
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;
}
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, "SimpleJack")) {
tplg_dev = TPLG_DEVICE_SDCA_JACK;
tplg_dev_name = "sdca-jack";
} else if (strstr(dai_link->name, "SmartAmp")) {
tplg_dev = TPLG_DEVICE_SDCA_AMP;
tplg_dev_name = devm_kasprintf(card->dev, GFP_KERNEL,
"sdca-%damp", dai_link->num_cpus);
if (!tplg_dev_name)
return -ENOMEM;
} else if (strstr(dai_link->name, "SmartMic")) {
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);
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, "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,
"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_mask |= BIT(tplg_dev);
/*
* 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;
}
if (!(*tplg_files)[tplg_num])
return -ENOMEM;
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);
} 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");
return 0;
}
}
return tplg_num;
}
EXPORT_SYMBOL_GPL(sof_sdw_get_tplg_files);