xref: /linux/sound/soc/sof/fw-file-profile.c (revision 67f8bc848ee31831336bd478e57d2f993551902e)
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) 2023 Intel Corporation
7 //
8 
9 #include <linux/firmware.h>
10 #include <sound/sof.h>
11 #include <sound/sof/ext_manifest4.h>
12 #include "sof-priv.h"
13 
14 static int sof_test_firmware_file(struct device *dev,
15 				  struct sof_loadable_file_profile *profile,
16 				  enum sof_ipc_type *ipc_type_to_adjust)
17 {
18 	enum sof_ipc_type fw_ipc_type;
19 	const u32 *magic;
20 	int ret;
21 
22 	const char *fw_filename __free(kfree) =
23 		kasprintf(GFP_KERNEL, "%s/%s", profile->fw_path,
24 			  profile->fw_name);
25 	if (!fw_filename)
26 		return -ENOMEM;
27 
28 	const struct firmware *fw __free(firmware) = NULL;
29 	ret = firmware_request_nowarn(&fw, fw_filename, dev);
30 	if (ret < 0) {
31 		dev_dbg(dev, "Failed to open firmware file: %s\n", fw_filename);
32 		return ret;
33 	}
34 
35 	/* firmware file exists, check the magic number */
36 	magic = (const u32 *)fw->data;
37 	switch (*magic) {
38 	case SOF_EXT_MAN_MAGIC_NUMBER:
39 		fw_ipc_type = SOF_IPC_TYPE_3;
40 		break;
41 	case SOF_EXT_MAN4_MAGIC_NUMBER:
42 		fw_ipc_type = SOF_IPC_TYPE_4;
43 		break;
44 	default:
45 		dev_err(dev, "Invalid firmware magic: %#x\n", *magic);
46 		return -EINVAL;
47 	}
48 
49 	if (ipc_type_to_adjust) {
50 		*ipc_type_to_adjust = fw_ipc_type;
51 	} else if (fw_ipc_type != profile->ipc_type) {
52 		dev_err(dev,
53 			"ipc type mismatch between %s and expected: %d vs %d\n",
54 			fw_filename, fw_ipc_type, profile->ipc_type);
55 		return -EINVAL;
56 	}
57 
58 	return 0;
59 }
60 
61 static int sof_test_topology_file(struct device *dev,
62 				  struct sof_loadable_file_profile *profile)
63 {
64 	const struct firmware *fw;
65 	const char *tplg_filename;
66 	int ret;
67 
68 	if (!profile->tplg_path || !profile->tplg_name)
69 		return 0;
70 
71 	/* Dummy topology does not exist and should not be used */
72 	if (strstr(profile->tplg_name, "dummy"))
73 		return 0;
74 
75 	tplg_filename = kasprintf(GFP_KERNEL, "%s/%s", profile->tplg_path,
76 				  profile->tplg_name);
77 	if (!tplg_filename)
78 		return -ENOMEM;
79 
80 	ret = firmware_request_nowarn(&fw, tplg_filename, dev);
81 	if (!ret)
82 		release_firmware(fw);
83 	else
84 		dev_dbg(dev, "Failed to open topology file: %s\n", tplg_filename);
85 
86 	kfree(tplg_filename);
87 
88 	return ret;
89 }
90 
91 static bool sof_platform_uses_generic_loader(struct snd_sof_dev *sdev)
92 {
93 	return (sdev->pdata->desc->ops->load_firmware == snd_sof_load_firmware_raw ||
94 		sdev->pdata->desc->ops->load_firmware == snd_sof_load_firmware_memcpy);
95 }
96 
97 static int
98 sof_file_profile_for_ipc_type(struct snd_sof_dev *sdev,
99 			      enum sof_ipc_type ipc_type,
100 			      const struct sof_dev_desc *desc,
101 			      struct sof_loadable_file_profile *base_profile,
102 			      struct sof_loadable_file_profile *out_profile)
103 {
104 	struct snd_sof_pdata *plat_data = sdev->pdata;
105 	bool fw_lib_path_allocated = false;
106 	struct device *dev = sdev->dev;
107 	bool fw_path_allocated = false;
108 	int ret = 0;
109 
110 	/* firmware path */
111 	if (base_profile->fw_path) {
112 		out_profile->fw_path = base_profile->fw_path;
113 	} else if (base_profile->fw_path_postfix) {
114 		out_profile->fw_path = devm_kasprintf(dev, GFP_KERNEL, "%s/%s",
115 							desc->default_fw_path[ipc_type],
116 							base_profile->fw_path_postfix);
117 		if (!out_profile->fw_path)
118 			return -ENOMEM;
119 
120 		fw_path_allocated = true;
121 	} else {
122 		out_profile->fw_path = desc->default_fw_path[ipc_type];
123 	}
124 
125 	/* firmware filename */
126 	if (base_profile->fw_name)
127 		out_profile->fw_name = base_profile->fw_name;
128 	else
129 		out_profile->fw_name = desc->default_fw_filename[ipc_type];
130 
131 	/*
132 	 * Check the custom firmware path/filename and adjust the ipc_type to
133 	 * match with the existing file for the remaining path configuration.
134 	 *
135 	 * For default path and firmware name do a verification before
136 	 * continuing further.
137 	 */
138 	if ((base_profile->fw_path || base_profile->fw_name) &&
139 	    sof_platform_uses_generic_loader(sdev)) {
140 		ret = sof_test_firmware_file(dev, out_profile, &ipc_type);
141 		if (ret)
142 			return ret;
143 
144 		if (!(desc->ipc_supported_mask & BIT(ipc_type))) {
145 			dev_err(dev, "Unsupported IPC type %d needed by %s/%s\n",
146 				ipc_type, out_profile->fw_path,
147 				out_profile->fw_name);
148 			return -EINVAL;
149 		}
150 	}
151 
152 	/* firmware library path */
153 	if (base_profile->fw_lib_path) {
154 		out_profile->fw_lib_path = base_profile->fw_lib_path;
155 	} else if (desc->default_lib_path[ipc_type]) {
156 		if (base_profile->fw_lib_path_postfix) {
157 			out_profile->fw_lib_path = devm_kasprintf(dev,
158 							GFP_KERNEL, "%s/%s",
159 							desc->default_lib_path[ipc_type],
160 							base_profile->fw_lib_path_postfix);
161 			if (!out_profile->fw_lib_path) {
162 				ret = -ENOMEM;
163 				goto out;
164 			}
165 
166 			fw_lib_path_allocated = true;
167 		} else {
168 			out_profile->fw_lib_path = desc->default_lib_path[ipc_type];
169 		}
170 	}
171 
172 	if (base_profile->fw_path_postfix)
173 		out_profile->fw_path_postfix = base_profile->fw_path_postfix;
174 
175 	if (base_profile->fw_lib_path_postfix)
176 		out_profile->fw_lib_path_postfix = base_profile->fw_lib_path_postfix;
177 
178 	/* topology path */
179 	if (base_profile->tplg_path)
180 		out_profile->tplg_path = base_profile->tplg_path;
181 	else
182 		out_profile->tplg_path = desc->default_tplg_path[ipc_type];
183 
184 	/* topology name */
185 	out_profile->tplg_name = plat_data->tplg_filename;
186 
187 	out_profile->ipc_type = ipc_type;
188 
189 	/* Test only default firmware file */
190 	if ((!base_profile->fw_path && !base_profile->fw_name) &&
191 	    sof_platform_uses_generic_loader(sdev))
192 		ret = sof_test_firmware_file(dev, out_profile, NULL);
193 
194 	if (!ret)
195 		ret = sof_test_topology_file(dev, out_profile);
196 
197 out:
198 	if (ret) {
199 		/* Free up path strings created with devm_kasprintf */
200 		if (fw_path_allocated)
201 			devm_kfree(dev, out_profile->fw_path);
202 		if (fw_lib_path_allocated)
203 			devm_kfree(dev, out_profile->fw_lib_path);
204 
205 		memset(out_profile, 0, sizeof(*out_profile));
206 	}
207 
208 	return ret;
209 }
210 
211 static void
212 sof_print_missing_firmware_info(struct snd_sof_dev *sdev,
213 				enum sof_ipc_type ipc_type,
214 				struct sof_loadable_file_profile *base_profile)
215 {
216 	struct snd_sof_pdata *plat_data = sdev->pdata;
217 	const struct sof_dev_desc *desc = plat_data->desc;
218 	struct device *dev = sdev->dev;
219 	int ipc_type_count, i;
220 	char *marker;
221 
222 	dev_err(dev, "SOF firmware and/or topology file not found.\n");
223 	dev_info(dev, "Supported default profiles\n");
224 
225 	if (IS_ENABLED(CONFIG_SND_SOC_SOF_ALLOW_FALLBACK_TO_NEWER_IPC_VERSION))
226 		ipc_type_count = SOF_IPC_TYPE_COUNT - 1;
227 	else
228 		ipc_type_count = base_profile->ipc_type;
229 
230 	for (i = 0; i <= ipc_type_count; i++) {
231 		if (!(desc->ipc_supported_mask & BIT(i)))
232 			continue;
233 
234 		if (i == ipc_type)
235 			marker = "Requested";
236 		else
237 			marker = "Fallback";
238 
239 		dev_info(dev, "- ipc type %d (%s):\n", i, marker);
240 		if (base_profile->fw_path_postfix)
241 			dev_info(dev, " Firmware file: %s/%s/%s\n",
242 				 desc->default_fw_path[i],
243 				 base_profile->fw_path_postfix,
244 				 desc->default_fw_filename[i]);
245 		else
246 			dev_info(dev, " Firmware file: %s/%s\n",
247 				 desc->default_fw_path[i],
248 				 desc->default_fw_filename[i]);
249 
250 		dev_info(dev, " Topology file: %s/%s\n",
251 			 desc->default_tplg_path[i],
252 			 plat_data->tplg_filename);
253 	}
254 
255 	if (base_profile->fw_path || base_profile->fw_name ||
256 	    base_profile->tplg_path || base_profile->tplg_name)
257 		dev_info(dev, "Verify the path/name override module parameters.\n");
258 
259 	dev_info(dev, "Check if you have 'sof-firmware' package installed.\n");
260 	dev_info(dev, "Optionally it can be manually downloaded from:\n");
261 	dev_info(dev, "   https://github.com/thesofproject/sof-bin/\n");
262 }
263 
264 static void sof_print_profile_info(struct snd_sof_dev *sdev,
265 				   enum sof_ipc_type ipc_type,
266 				   struct sof_loadable_file_profile *profile)
267 {
268 	struct snd_sof_pdata *plat_data = sdev->pdata;
269 	struct device *dev = sdev->dev;
270 
271 	if (ipc_type != profile->ipc_type)
272 		dev_info(dev,
273 			 "Using fallback IPC type %d (requested type was %d)\n",
274 			 profile->ipc_type, ipc_type);
275 
276 	dev_info(dev, "Firmware paths/files for ipc type %d:\n", profile->ipc_type);
277 
278 	/* The firmware path is only valid when generic loader is used */
279 	if (sof_platform_uses_generic_loader(sdev))
280 		dev_info(dev, " Firmware file:     %s/%s\n",
281 			 profile->fw_path, profile->fw_name);
282 
283 	if (profile->fw_lib_path)
284 		dev_info(dev, " Firmware lib path: %s\n", profile->fw_lib_path);
285 
286 	if (plat_data->machine && plat_data->machine->get_function_tplg_files &&
287 	    !plat_data->disable_function_topology)
288 		dev_info(dev, " Topology file:     function topologies\n");
289 	else
290 		dev_info(dev, " Topology file:     %s/%s\n",
291 			 profile->tplg_path, profile->tplg_name);
292 }
293 
294 int sof_create_ipc_file_profile(struct snd_sof_dev *sdev,
295 				struct sof_loadable_file_profile *base_profile,
296 				struct sof_loadable_file_profile *out_profile)
297 {
298 	const struct sof_dev_desc *desc = sdev->pdata->desc;
299 	int ipc_fallback_start, ret, i;
300 
301 	memset(out_profile, 0, sizeof(*out_profile));
302 
303 	ret = sof_file_profile_for_ipc_type(sdev, base_profile->ipc_type, desc,
304 					    base_profile, out_profile);
305 	if (!ret)
306 		goto out;
307 
308 	/*
309 	 * No firmware file was found for the requested IPC type, as fallback
310 	 * if SND_SOC_SOF_ALLOW_FALLBACK_TO_NEWER_IPC_VERSION is selected, check
311 	 * all IPC versions in a backwards direction (from newer to older)
312 	 * if SND_SOC_SOF_ALLOW_FALLBACK_TO_NEWER_IPC_VERSION is not selected,
313 	 * check only older IPC versions than the selected/default version
314 	 */
315 	if (IS_ENABLED(CONFIG_SND_SOC_SOF_ALLOW_FALLBACK_TO_NEWER_IPC_VERSION))
316 		ipc_fallback_start = SOF_IPC_TYPE_COUNT - 1;
317 	else
318 		ipc_fallback_start = (int)base_profile->ipc_type - 1;
319 
320 	for (i = ipc_fallback_start; i >= 0 ; i--) {
321 		if (i == base_profile->ipc_type ||
322 		    !(desc->ipc_supported_mask & BIT(i)))
323 			continue;
324 
325 		ret = sof_file_profile_for_ipc_type(sdev, i, desc, base_profile,
326 						    out_profile);
327 		if (!ret)
328 			break;
329 	}
330 
331 out:
332 	if (ret)
333 		sof_print_missing_firmware_info(sdev, base_profile->ipc_type,
334 						base_profile);
335 	else
336 		sof_print_profile_info(sdev, base_profile->ipc_type, out_profile);
337 
338 	return ret;
339 }
340 EXPORT_SYMBOL(sof_create_ipc_file_profile);
341