1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) 2 // 3 // This file is provided under a dual BSD/GPLv2 license. When using or 4 // redistributing this file, you may do so under either license. 5 // 6 // Copyright(c) 2025 Intel Corporation. 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 /* The dai link is not supported by separated tplg yet */ 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 /* Check presence of sub-topologies */ 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); 158