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