xref: /openbmc/linux/sound/soc/sof/loader.c (revision 22d55f02)
1 // SPDX-License-Identifier: (GPL-2.0 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) 2018 Intel Corporation. All rights reserved.
7 //
8 // Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
9 //
10 // Generic firmware loader.
11 //
12 
13 #include <linux/firmware.h>
14 #include <sound/sof.h>
15 #include "ops.h"
16 
17 static int get_ext_windows(struct snd_sof_dev *sdev,
18 			   struct sof_ipc_ext_data_hdr *ext_hdr)
19 {
20 	struct sof_ipc_window *w =
21 		container_of(ext_hdr, struct sof_ipc_window, ext_hdr);
22 	size_t size;
23 
24 	if (w->num_windows == 0 || w->num_windows > SOF_IPC_MAX_ELEMS)
25 		return -EINVAL;
26 
27 	size = sizeof(*w) + sizeof(struct sof_ipc_window_elem) * w->num_windows;
28 
29 	/* keep a local copy of the data */
30 	sdev->info_window = kmemdup(w, size, GFP_KERNEL);
31 	if (!sdev->info_window)
32 		return -ENOMEM;
33 
34 	return 0;
35 }
36 
37 /* parse the extended FW boot data structures from FW boot message */
38 int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 bar, u32 offset)
39 {
40 	struct sof_ipc_ext_data_hdr *ext_hdr;
41 	void *ext_data;
42 	int ret = 0;
43 
44 	ext_data = kzalloc(PAGE_SIZE, GFP_KERNEL);
45 	if (!ext_data)
46 		return -ENOMEM;
47 
48 	/* get first header */
49 	snd_sof_dsp_block_read(sdev, bar, offset, ext_data,
50 			       sizeof(*ext_hdr));
51 	ext_hdr = ext_data;
52 
53 	while (ext_hdr->hdr.cmd == SOF_IPC_FW_READY) {
54 		/* read in ext structure */
55 		offset += sizeof(*ext_hdr);
56 		snd_sof_dsp_block_read(sdev, bar, offset,
57 				   (void *)((u8 *)ext_data + sizeof(*ext_hdr)),
58 				   ext_hdr->hdr.size - sizeof(*ext_hdr));
59 
60 		dev_dbg(sdev->dev, "found ext header type %d size 0x%x\n",
61 			ext_hdr->type, ext_hdr->hdr.size);
62 
63 		/* process structure data */
64 		switch (ext_hdr->type) {
65 		case SOF_IPC_EXT_DMA_BUFFER:
66 			break;
67 		case SOF_IPC_EXT_WINDOW:
68 			ret = get_ext_windows(sdev, ext_hdr);
69 			break;
70 		default:
71 			break;
72 		}
73 
74 		if (ret < 0) {
75 			dev_err(sdev->dev, "error: failed to parse ext data type %d\n",
76 				ext_hdr->type);
77 			break;
78 		}
79 
80 		/* move to next header */
81 		offset += ext_hdr->hdr.size;
82 		snd_sof_dsp_block_read(sdev, bar, offset, ext_data,
83 				       sizeof(*ext_hdr));
84 		ext_hdr = ext_data;
85 	}
86 
87 	kfree(ext_data);
88 	return ret;
89 }
90 EXPORT_SYMBOL(snd_sof_fw_parse_ext_data);
91 
92 /* generic module parser for mmaped DSPs */
93 int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev,
94 				struct snd_sof_mod_hdr *module)
95 {
96 	struct snd_sof_blk_hdr *block;
97 	int count;
98 	u32 offset;
99 	size_t remaining;
100 
101 	dev_dbg(sdev->dev, "new module size 0x%x blocks 0x%x type 0x%x\n",
102 		module->size, module->num_blocks, module->type);
103 
104 	block = (struct snd_sof_blk_hdr *)((u8 *)module + sizeof(*module));
105 
106 	/* module->size doesn't include header size */
107 	remaining = module->size;
108 	for (count = 0; count < module->num_blocks; count++) {
109 		/* check for wrap */
110 		if (remaining < sizeof(*block)) {
111 			dev_err(sdev->dev, "error: not enough data remaining\n");
112 			return -EINVAL;
113 		}
114 
115 		/* minus header size of block */
116 		remaining -= sizeof(*block);
117 
118 		if (block->size == 0) {
119 			dev_warn(sdev->dev,
120 				 "warning: block %d size zero\n", count);
121 			dev_warn(sdev->dev, " type 0x%x offset 0x%x\n",
122 				 block->type, block->offset);
123 			continue;
124 		}
125 
126 		switch (block->type) {
127 		case SOF_FW_BLK_TYPE_RSRVD0:
128 		case SOF_FW_BLK_TYPE_SRAM...SOF_FW_BLK_TYPE_RSRVD14:
129 			continue;	/* not handled atm */
130 		case SOF_FW_BLK_TYPE_IRAM:
131 		case SOF_FW_BLK_TYPE_DRAM:
132 			offset = block->offset;
133 			break;
134 		default:
135 			dev_err(sdev->dev, "error: bad type 0x%x for block 0x%x\n",
136 				block->type, count);
137 			return -EINVAL;
138 		}
139 
140 		dev_dbg(sdev->dev,
141 			"block %d type 0x%x size 0x%x ==>  offset 0x%x\n",
142 			count, block->type, block->size, offset);
143 
144 		/* checking block->size to avoid unaligned access */
145 		if (block->size % sizeof(u32)) {
146 			dev_err(sdev->dev, "error: invalid block size 0x%x\n",
147 				block->size);
148 			return -EINVAL;
149 		}
150 		snd_sof_dsp_block_write(sdev, sdev->mmio_bar, offset,
151 					block + 1, block->size);
152 
153 		if (remaining < block->size) {
154 			dev_err(sdev->dev, "error: not enough data remaining\n");
155 			return -EINVAL;
156 		}
157 
158 		/* minus body size of block */
159 		remaining -= block->size;
160 		/* next block */
161 		block = (struct snd_sof_blk_hdr *)((u8 *)block + sizeof(*block)
162 			+ block->size);
163 	}
164 
165 	return 0;
166 }
167 EXPORT_SYMBOL(snd_sof_parse_module_memcpy);
168 
169 static int check_header(struct snd_sof_dev *sdev, const struct firmware *fw)
170 {
171 	struct snd_sof_fw_header *header;
172 
173 	/* Read the header information from the data pointer */
174 	header = (struct snd_sof_fw_header *)fw->data;
175 
176 	/* verify FW sig */
177 	if (strncmp(header->sig, SND_SOF_FW_SIG, SND_SOF_FW_SIG_SIZE) != 0) {
178 		dev_err(sdev->dev, "error: invalid firmware signature\n");
179 		return -EINVAL;
180 	}
181 
182 	/* check size is valid */
183 	if (fw->size != header->file_size + sizeof(*header)) {
184 		dev_err(sdev->dev, "error: invalid filesize mismatch got 0x%zx expected 0x%zx\n",
185 			fw->size, header->file_size + sizeof(*header));
186 		return -EINVAL;
187 	}
188 
189 	dev_dbg(sdev->dev, "header size=0x%x modules=0x%x abi=0x%x size=%zu\n",
190 		header->file_size, header->num_modules,
191 		header->abi, sizeof(*header));
192 
193 	return 0;
194 }
195 
196 static int load_modules(struct snd_sof_dev *sdev, const struct firmware *fw)
197 {
198 	struct snd_sof_fw_header *header;
199 	struct snd_sof_mod_hdr *module;
200 	int (*load_module)(struct snd_sof_dev *sof_dev,
201 			   struct snd_sof_mod_hdr *hdr);
202 	int ret, count;
203 	size_t remaining;
204 
205 	header = (struct snd_sof_fw_header *)fw->data;
206 	load_module = sof_ops(sdev)->load_module;
207 	if (!load_module)
208 		return -EINVAL;
209 
210 	/* parse each module */
211 	module = (struct snd_sof_mod_hdr *)((u8 *)(fw->data) + sizeof(*header));
212 	remaining = fw->size - sizeof(*header);
213 	/* check for wrap */
214 	if (remaining > fw->size) {
215 		dev_err(sdev->dev, "error: fw size smaller than header size\n");
216 		return -EINVAL;
217 	}
218 
219 	for (count = 0; count < header->num_modules; count++) {
220 		/* check for wrap */
221 		if (remaining < sizeof(*module)) {
222 			dev_err(sdev->dev, "error: not enough data remaining\n");
223 			return -EINVAL;
224 		}
225 
226 		/* minus header size of module */
227 		remaining -= sizeof(*module);
228 
229 		/* module */
230 		ret = load_module(sdev, module);
231 		if (ret < 0) {
232 			dev_err(sdev->dev, "error: invalid module %d\n", count);
233 			return ret;
234 		}
235 
236 		if (remaining < module->size) {
237 			dev_err(sdev->dev, "error: not enough data remaining\n");
238 			return -EINVAL;
239 		}
240 
241 		/* minus body size of module */
242 		remaining -=  module->size;
243 		module = (struct snd_sof_mod_hdr *)((u8 *)module
244 			+ sizeof(*module) + module->size);
245 	}
246 
247 	return 0;
248 }
249 
250 int snd_sof_load_firmware_raw(struct snd_sof_dev *sdev)
251 {
252 	struct snd_sof_pdata *plat_data = sdev->pdata;
253 	const char *fw_filename;
254 	int ret;
255 
256 	/* set code loading condition to true */
257 	sdev->code_loading = 1;
258 
259 	/* Don't request firmware again if firmware is already requested */
260 	if (plat_data->fw)
261 		return 0;
262 
263 	fw_filename = kasprintf(GFP_KERNEL, "%s/%s",
264 				plat_data->fw_filename_prefix,
265 				plat_data->fw_filename);
266 	if (!fw_filename)
267 		return -ENOMEM;
268 
269 	ret = request_firmware(&plat_data->fw, fw_filename, sdev->dev);
270 
271 	if (ret < 0) {
272 		dev_err(sdev->dev, "error: request firmware %s failed err: %d\n",
273 			fw_filename, ret);
274 	}
275 
276 	kfree(fw_filename);
277 
278 	return ret;
279 }
280 EXPORT_SYMBOL(snd_sof_load_firmware_raw);
281 
282 int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev)
283 {
284 	struct snd_sof_pdata *plat_data = sdev->pdata;
285 	int ret;
286 
287 	ret = snd_sof_load_firmware_raw(sdev);
288 	if (ret < 0)
289 		return ret;
290 
291 	/* make sure the FW header and file is valid */
292 	ret = check_header(sdev, plat_data->fw);
293 	if (ret < 0) {
294 		dev_err(sdev->dev, "error: invalid FW header\n");
295 		goto error;
296 	}
297 
298 	/* prepare the DSP for FW loading */
299 	ret = snd_sof_dsp_reset(sdev);
300 	if (ret < 0) {
301 		dev_err(sdev->dev, "error: failed to reset DSP\n");
302 		goto error;
303 	}
304 
305 	/* parse and load firmware modules to DSP */
306 	ret = load_modules(sdev, plat_data->fw);
307 	if (ret < 0) {
308 		dev_err(sdev->dev, "error: invalid FW modules\n");
309 		goto error;
310 	}
311 
312 	return 0;
313 
314 error:
315 	release_firmware(plat_data->fw);
316 	plat_data->fw = NULL;
317 	return ret;
318 
319 }
320 EXPORT_SYMBOL(snd_sof_load_firmware_memcpy);
321 
322 int snd_sof_load_firmware(struct snd_sof_dev *sdev)
323 {
324 	dev_dbg(sdev->dev, "loading firmware\n");
325 
326 	if (sof_ops(sdev)->load_firmware)
327 		return sof_ops(sdev)->load_firmware(sdev);
328 	return 0;
329 }
330 EXPORT_SYMBOL(snd_sof_load_firmware);
331 
332 int snd_sof_run_firmware(struct snd_sof_dev *sdev)
333 {
334 	int ret;
335 	int init_core_mask;
336 
337 	init_waitqueue_head(&sdev->boot_wait);
338 	sdev->boot_complete = false;
339 
340 	/* create fw_version debugfs to store boot version info */
341 	if (sdev->first_boot) {
342 		ret = snd_sof_debugfs_buf_item(sdev, &sdev->fw_version,
343 					       sizeof(sdev->fw_version),
344 					       "fw_version");
345 		/* errors are only due to memory allocation, not debugfs */
346 		if (ret < 0) {
347 			dev_err(sdev->dev, "error: snd_sof_debugfs_buf_item failed\n");
348 			return ret;
349 		}
350 	}
351 
352 	/* perform pre fw run operations */
353 	ret = snd_sof_dsp_pre_fw_run(sdev);
354 	if (ret < 0) {
355 		dev_err(sdev->dev, "error: failed pre fw run op\n");
356 		return ret;
357 	}
358 
359 	dev_dbg(sdev->dev, "booting DSP firmware\n");
360 
361 	/* boot the firmware on the DSP */
362 	ret = snd_sof_dsp_run(sdev);
363 	if (ret < 0) {
364 		dev_err(sdev->dev, "error: failed to reset DSP\n");
365 		return ret;
366 	}
367 
368 	init_core_mask = ret;
369 
370 	/* now wait for the DSP to boot */
371 	ret = wait_event_timeout(sdev->boot_wait, sdev->boot_complete,
372 				 msecs_to_jiffies(sdev->boot_timeout));
373 	if (ret == 0) {
374 		dev_err(sdev->dev, "error: firmware boot failure\n");
375 		/* after this point FW_READY msg should be ignored */
376 		sdev->boot_complete = true;
377 		snd_sof_dsp_dbg_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX |
378 			SOF_DBG_TEXT | SOF_DBG_PCI);
379 		return -EIO;
380 	}
381 
382 	dev_info(sdev->dev, "firmware boot complete\n");
383 
384 	/* perform post fw run operations */
385 	ret = snd_sof_dsp_post_fw_run(sdev);
386 	if (ret < 0) {
387 		dev_err(sdev->dev, "error: failed post fw run op\n");
388 		return ret;
389 	}
390 
391 	/* fw boot is complete. Update the active cores mask */
392 	sdev->enabled_cores_mask = init_core_mask;
393 
394 	return 0;
395 }
396 EXPORT_SYMBOL(snd_sof_run_firmware);
397 
398 void snd_sof_fw_unload(struct snd_sof_dev *sdev)
399 {
400 	/* TODO: support module unloading at runtime */
401 }
402 EXPORT_SYMBOL(snd_sof_fw_unload);
403