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_params mach_params = mach->mach_params; 35 struct snd_soc_dai_link *dai_link; 36 const struct firmware *fw; 37 char platform[SOF_INTEL_PLATFORM_NAME_MAX]; 38 unsigned long tplg_mask = 0; 39 int tplg_num = 0; 40 int tplg_dev; 41 int ret; 42 int i; 43 44 ret = sscanf(mach->sof_tplg_filename, "sof-%3s-*.tplg", platform); 45 if (ret != 1) { 46 dev_err(card->dev, "Invalid platform name %s of tplg %s\n", 47 platform, mach->sof_tplg_filename); 48 return -EINVAL; 49 } 50 51 for_each_card_prelinks(card, i, dai_link) { 52 char *tplg_dev_name; 53 54 dev_dbg(card->dev, "dai_link %s id %d\n", dai_link->name, dai_link->id); 55 if (strstr(dai_link->name, "SimpleJack")) { 56 tplg_dev = TPLG_DEVICE_SDCA_JACK; 57 tplg_dev_name = "sdca-jack"; 58 } else if (strstr(dai_link->name, "SmartAmp")) { 59 tplg_dev = TPLG_DEVICE_SDCA_AMP; 60 tplg_dev_name = devm_kasprintf(card->dev, GFP_KERNEL, 61 "sdca-%damp", dai_link->num_cpus); 62 if (!tplg_dev_name) 63 return -ENOMEM; 64 } else if (strstr(dai_link->name, "SmartMic")) { 65 tplg_dev = TPLG_DEVICE_SDCA_MIC; 66 tplg_dev_name = "sdca-mic"; 67 } else if (strstr(dai_link->name, "dmic")) { 68 switch (mach_params.dmic_num) { 69 case 2: 70 tplg_dev_name = "dmic-2ch"; 71 break; 72 case 4: 73 tplg_dev_name = "dmic-4ch"; 74 break; 75 default: 76 dev_warn(card->dev, 77 "unsupported number of dmics: %d\n", 78 mach_params.dmic_num); 79 continue; 80 } 81 tplg_dev = TPLG_DEVICE_INTEL_PCH_DMIC; 82 } else if (strstr(dai_link->name, "iDisp")) { 83 tplg_dev = TPLG_DEVICE_HDMI; 84 tplg_dev_name = "hdmi-pcm5"; 85 } else if (strstr(dai_link->name, "Loopback_Virtual")) { 86 tplg_dev = TPLG_DEVICE_LOOPBACK_VIRTUAL; 87 /* 88 * Mark the LOOPBACK_VIRTUAL device but no need to create the 89 * LOOPBACK_VIRTUAL topology. Just to avoid the dai_link is not supported 90 * error. 91 */ 92 tplg_mask |= BIT(tplg_dev); 93 continue; 94 } else { 95 /* The dai link is not supported by separated tplg yet */ 96 dev_dbg(card->dev, 97 "dai_link %s is not supported by separated tplg yet\n", 98 dai_link->name); 99 if (best_effort) 100 continue; 101 102 return 0; 103 } 104 if (tplg_mask & BIT(tplg_dev)) 105 continue; 106 107 tplg_mask |= BIT(tplg_dev); 108 109 /* 110 * The tplg file naming rule is sof-<platform>-<function>-id<BE id number>.tplg 111 * where <platform> is only required for the DMIC function as the nhlt blob 112 * is platform dependent. 113 */ 114 switch (tplg_dev) { 115 case TPLG_DEVICE_INTEL_PCH_DMIC: 116 (*tplg_files)[tplg_num] = devm_kasprintf(card->dev, GFP_KERNEL, 117 "%s/sof-%s-%s-id%d.tplg", 118 prefix, platform, 119 tplg_dev_name, dai_link->id); 120 break; 121 default: 122 (*tplg_files)[tplg_num] = devm_kasprintf(card->dev, GFP_KERNEL, 123 "%s/sof-%s-id%d.tplg", 124 prefix, tplg_dev_name, 125 dai_link->id); 126 break; 127 } 128 if (!(*tplg_files)[tplg_num]) 129 return -ENOMEM; 130 tplg_num++; 131 } 132 133 dev_dbg(card->dev, "tplg_mask %#lx tplg_num %d\n", tplg_mask, tplg_num); 134 135 /* Check presence of sub-topologies */ 136 for (i = 0; i < tplg_num; i++) { 137 ret = firmware_request_nowarn(&fw, (*tplg_files)[i], card->dev); 138 if (!ret) { 139 release_firmware(fw); 140 } else { 141 dev_warn(card->dev, 142 "Failed to open topology file: %s, you might need to\n", 143 (*tplg_files)[i]); 144 dev_warn(card->dev, 145 "download it from https://github.com/thesofproject/sof-bin/\n"); 146 return 0; 147 } 148 } 149 150 return tplg_num; 151 } 152 EXPORT_SYMBOL_GPL(sof_sdw_get_tplg_files); 153