| 1 | |
| 2 | |
| 3 | |
| 4 | |
| 5 | |
| 6 | |
| 7 | |
| 8 |
|
| 9 | #include <linux/device.h>
|
| 10 | #include <linux/errno.h>
|
| 11 | #include <linux/firmware.h>
|
| 12 | #include <sound/soc.h>
|
| 13 | #include <sound/soc-acpi.h>
|
| 14 | #include "sof-function-topology-lib.h"
|
| 15 |
|
| 16 | enum tplg_device_id {
|
| 17 | TPLG_DEVICE_SDCA_JACK,
|
| 18 | TPLG_DEVICE_SDCA_AMP,
|
| 19 | TPLG_DEVICE_SDCA_MIC,
|
| 20 | TPLG_DEVICE_INTEL_PCH_DMIC,
|
| 21 | TPLG_DEVICE_HDMI,
|
| 22 | TPLG_DEVICE_LOOPBACK_VIRTUAL,
|
| 23 | TPLG_DEVICE_MAX
|
| 24 | };
|
| 25 |
|
| 26 | #define SDCA_DEVICE_MASK (BIT(TPLG_DEVICE_SDCA_JACK) | BIT(TPLG_DEVICE_SDCA_AMP) | \
|
| 27 | BIT(TPLG_DEVICE_SDCA_MIC))
|
| 28 |
|
| 29 | #define SOF_INTEL_PLATFORM_NAME_MAX 4
|
| 30 |
|
| 31 | int sof_sdw_get_tplg_files(struct snd_soc_card *card, const struct snd_soc_acpi_mach *mach,
|
| 32 | const char *prefix, const char ***tplg_files, bool best_effort)
|
| 33 | {
|
| 34 | struct snd_soc_acpi_mach *card_mach = dev_get_platdata(card->dev);
|
| 35 | |
| 36 | * Use the acpi mach from the machine driver because the machine driver
|
| 37 | * may change the dmic_num based on the machine driver quirk.
|
| 38 |
|
| 39 | struct snd_soc_acpi_mach_params mach_params = card_mach->mach_params;
|
| 40 | struct snd_soc_dai_link *dai_link;
|
| 41 | const struct firmware *fw;
|
| 42 | char platform[SOF_INTEL_PLATFORM_NAME_MAX];
|
| 43 | unsigned long tplg_mask = 0;
|
| 44 | int tplg_num = 0;
|
| 45 | int tplg_dev;
|
| 46 | int ret;
|
| 47 | int i;
|
| 48 |
|
| 49 | ret = sscanf(mach->sof_tplg_filename, "sof-%3s-*.tplg", platform);
|
| 50 | if (ret != 1) {
|
| 51 | dev_err(card->dev, "Invalid platform name %s of tplg %s\n",
|
| 52 | platform, mach->sof_tplg_filename);
|
| 53 | return -EINVAL;
|
| 54 | }
|
| 55 |
|
| 56 | for_each_card_prelinks(card, i, dai_link) {
|
| 57 | char *tplg_dev_name;
|
| 58 |
|
| 59 | dev_dbg(card->dev, "dai_link %s id %d\n", dai_link->name, dai_link->id);
|
| 60 | if (strstr(dai_link->name, "SimpleJack")) {
|
| 61 | tplg_dev = TPLG_DEVICE_SDCA_JACK;
|
| 62 | tplg_dev_name = "sdca-jack";
|
| 63 | } else if (strstr(dai_link->name, "SmartAmp")) {
|
| 64 | tplg_dev = TPLG_DEVICE_SDCA_AMP;
|
| 65 | tplg_dev_name = devm_kasprintf(card->dev, GFP_KERNEL,
|
| 66 | "sdca-%damp", dai_link->num_cpus);
|
| 67 | if (!tplg_dev_name)
|
| 68 | return -ENOMEM;
|
| 69 | } else if (strstr(dai_link->name, "SmartMic")) {
|
| 70 | tplg_dev = TPLG_DEVICE_SDCA_MIC;
|
| 71 | tplg_dev_name = "sdca-mic";
|
| 72 | } else if (strstr(dai_link->name, "dmic")) {
|
| 73 | switch (mach_params.dmic_num) {
|
| 74 | case 2:
|
| 75 | tplg_dev_name = "dmic-2ch";
|
| 76 | break;
|
| 77 | case 4:
|
| 78 | tplg_dev_name = "dmic-4ch";
|
| 79 | break;
|
| 80 | default:
|
| 81 | dev_warn(card->dev,
|
| 82 | "unsupported number of dmics: %d\n",
|
| 83 | mach_params.dmic_num);
|
| 84 | continue;
|
| 85 | }
|
| 86 | tplg_dev = TPLG_DEVICE_INTEL_PCH_DMIC;
|
| 87 | } else if (strstr(dai_link->name, "iDisp")) {
|
| 88 | tplg_dev = TPLG_DEVICE_HDMI;
|
| 89 | tplg_dev_name = "hdmi-pcm5";
|
| 90 | } else if (strstr(dai_link->name, "Loopback_Virtual")) {
|
| 91 | tplg_dev = TPLG_DEVICE_LOOPBACK_VIRTUAL;
|
| 92 | |
| 93 | * Mark the LOOPBACK_VIRTUAL device but no need to create the
|
| 94 | * LOOPBACK_VIRTUAL topology. Just to avoid the dai_link is not supported
|
| 95 | * error.
|
| 96 |
|
| 97 | tplg_mask |= BIT(tplg_dev);
|
| 98 | continue;
|
| 99 | } else {
|
| 100 |
|
| 101 | dev_dbg(card->dev,
|
| 102 | "dai_link %s is not supported by separated tplg yet\n",
|
| 103 | dai_link->name);
|
| 104 | if (best_effort)
|
| 105 | continue;
|
| 106 |
|
| 107 | return 0;
|
| 108 | }
|
| 109 | if (tplg_mask & BIT(tplg_dev))
|
| 110 | continue;
|
| 111 |
|
| 112 | tplg_mask |= BIT(tplg_dev);
|
| 113 |
|
| 114 | |
| 115 | * The tplg file naming rule is sof-<platform>-<function>-id<BE id number>.tplg
|
| 116 | * where <platform> is only required for the DMIC function as the nhlt blob
|
| 117 | * is platform dependent.
|
| 118 |
|
| 119 | switch (tplg_dev) {
|
| 120 | case TPLG_DEVICE_INTEL_PCH_DMIC:
|
| 121 | (*tplg_files)[tplg_num] = devm_kasprintf(card->dev, GFP_KERNEL,
|
| 122 | "%s/sof-%s-%s-id%d.tplg",
|
| 123 | prefix, platform,
|
| 124 | tplg_dev_name, dai_link->id);
|
| 125 | break;
|
| 126 | default:
|
| 127 | (*tplg_files)[tplg_num] = devm_kasprintf(card->dev, GFP_KERNEL,
|
| 128 | "%s/sof-%s-id%d.tplg",
|
| 129 | prefix, tplg_dev_name,
|
| 130 | dai_link->id);
|
| 131 | break;
|
| 132 | }
|
| 133 | if (!(*tplg_files)[tplg_num])
|
| 134 | return -ENOMEM;
|
| 135 | tplg_num++;
|
| 136 | }
|
| 137 |
|
| 138 | dev_dbg(card->dev, "tplg_mask %#lx tplg_num %d\n", tplg_mask, tplg_num);
|
| 139 |
|
| 140 |
|
| 141 | for (i = 0; i < tplg_num; i++) {
|
| 142 | ret = firmware_request_nowarn(&fw, (*tplg_files)[i], card->dev);
|
| 143 | if (!ret) {
|
| 144 | release_firmware(fw);
|
| 145 | } else {
|
| 146 | dev_warn(card->dev,
|
| 147 | "Failed to open topology file: %s, you might need to\n",
|
| 148 | (*tplg_files)[i]);
|
| 149 | dev_warn(card->dev,
|
| 150 | "download it from https://github.com/thesofproject/sof-bin/\n");
|
| 151 | return 0;
|
| 152 | }
|
| 153 | }
|
| 154 |
|
| 155 | return tplg_num;
|
| 156 | }
|
| 157 | EXPORT_SYMBOL_GPL(sof_sdw_get_tplg_files);
|