xref: /linux/sound/soc/intel/common/sof-function-topology-lib.c (revision ebb8719c1a7dd3d0c6f49e38a95bb6ac89f7f7e1)
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 
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, bool best_effort)
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 			if (best_effort)
91 				continue;
92 
93 			return 0;
94 		}
95 		if (tplg_mask & BIT(tplg_dev))
96 			continue;
97 
98 		tplg_mask |= BIT(tplg_dev);
99 
100 		/*
101 		 * The tplg file naming rule is sof-<platform>-<function>-id<BE id number>.tplg
102 		 * where <platform> is only required for the DMIC function as the nhlt blob
103 		 * is platform dependent.
104 		 */
105 		switch (tplg_dev) {
106 		case TPLG_DEVICE_INTEL_PCH_DMIC:
107 			(*tplg_files)[tplg_num] = devm_kasprintf(card->dev, GFP_KERNEL,
108 								 "%s/sof-%s-%s-id%d.tplg",
109 								 prefix, platform,
110 								 tplg_dev_name, dai_link->id);
111 			break;
112 		default:
113 			(*tplg_files)[tplg_num] = devm_kasprintf(card->dev, GFP_KERNEL,
114 								 "%s/sof-%s-id%d.tplg",
115 								 prefix, tplg_dev_name,
116 								 dai_link->id);
117 			break;
118 		}
119 		if (!(*tplg_files)[tplg_num])
120 			return -ENOMEM;
121 		tplg_num++;
122 	}
123 
124 	dev_dbg(card->dev, "tplg_mask %#lx tplg_num %d\n", tplg_mask, tplg_num);
125 
126 	/* Check presence of sub-topologies */
127 	for (i = 0; i < tplg_num; i++) {
128 		ret = firmware_request_nowarn(&fw, (*tplg_files)[i], card->dev);
129 		if (!ret) {
130 			release_firmware(fw);
131 		} else {
132 			dev_warn(card->dev,
133 				 "Failed to open topology file: %s, you might need to\n",
134 				 (*tplg_files)[i]);
135 			dev_warn(card->dev,
136 				 "download it from https://github.com/thesofproject/sof-bin/\n");
137 			return 0;
138 		}
139 	}
140 
141 	return tplg_num;
142 }
143 EXPORT_SYMBOL_GPL(sof_sdw_get_tplg_files);
144