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