1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
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.
6 // Copyright(c) 2018 Intel Corporation. All rights reserved.
8 // Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
10 // Generic firmware loader.
13 #include <linux/firmware.h>
14 #include <sound/sof.h>
15 #include <sound/sof/ext_manifest.h>
18 static int get_ext_windows(struct snd_sof_dev *sdev,
19 const struct sof_ipc_ext_data_hdr *ext_hdr)
21 const struct sof_ipc_window *w =
22 container_of(ext_hdr, struct sof_ipc_window, ext_hdr);
23 size_t w_size = struct_size(w, window, w->num_windows);
25 if (w->num_windows == 0 || w->num_windows > SOF_IPC_MAX_ELEMS)
28 if (sdev->info_window) {
29 if (memcmp(sdev->info_window, w, w_size)) {
30 dev_err(sdev->dev, "error: mismatch between window descriptor from extended manifest and mailbox");
36 /* keep a local copy of the data */
37 sdev->info_window = kmemdup(w, w_size, GFP_KERNEL);
38 if (!sdev->info_window)
44 static int get_cc_info(struct snd_sof_dev *sdev,
45 const struct sof_ipc_ext_data_hdr *ext_hdr)
49 const struct sof_ipc_cc_version *cc =
50 container_of(ext_hdr, struct sof_ipc_cc_version, ext_hdr);
52 if (sdev->cc_version) {
53 if (memcmp(sdev->cc_version, cc, cc->ext_hdr.hdr.size)) {
54 dev_err(sdev->dev, "error: receive diverged cc_version descriptions");
60 dev_dbg(sdev->dev, "Firmware info: used compiler %s %d:%d:%d%s used optimization flags %s\n",
61 cc->name, cc->major, cc->minor, cc->micro, cc->desc,
64 /* create read-only cc_version debugfs to store compiler version info */
65 /* use local copy of the cc_version to prevent data corruption */
66 if (sdev->first_boot) {
67 sdev->cc_version = devm_kmalloc(sdev->dev, cc->ext_hdr.hdr.size,
70 if (!sdev->cc_version)
73 memcpy(sdev->cc_version, cc, cc->ext_hdr.hdr.size);
74 ret = snd_sof_debugfs_buf_item(sdev, sdev->cc_version,
78 /* errors are only due to memory allocation, not debugfs */
80 dev_err(sdev->dev, "error: snd_sof_debugfs_buf_item failed\n");
88 /* parse the extended FW boot data structures from FW boot message */
89 int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 bar, u32 offset)
91 struct sof_ipc_ext_data_hdr *ext_hdr;
95 ext_data = kzalloc(PAGE_SIZE, GFP_KERNEL);
99 /* get first header */
100 snd_sof_dsp_block_read(sdev, bar, offset, ext_data,
104 while (ext_hdr->hdr.cmd == SOF_IPC_FW_READY) {
105 /* read in ext structure */
106 snd_sof_dsp_block_read(sdev, bar, offset + sizeof(*ext_hdr),
107 (void *)((u8 *)ext_data + sizeof(*ext_hdr)),
108 ext_hdr->hdr.size - sizeof(*ext_hdr));
110 dev_dbg(sdev->dev, "found ext header type %d size 0x%x\n",
111 ext_hdr->type, ext_hdr->hdr.size);
113 /* process structure data */
114 switch (ext_hdr->type) {
115 case SOF_IPC_EXT_WINDOW:
116 ret = get_ext_windows(sdev, ext_hdr);
118 case SOF_IPC_EXT_CC_INFO:
119 ret = get_cc_info(sdev, ext_hdr);
122 dev_warn(sdev->dev, "warning: unknown ext header type %d size 0x%x\n",
123 ext_hdr->type, ext_hdr->hdr.size);
129 dev_err(sdev->dev, "error: failed to parse ext data type %d\n",
134 /* move to next header */
135 offset += ext_hdr->hdr.size;
136 snd_sof_dsp_block_read(sdev, bar, offset, ext_data,
144 EXPORT_SYMBOL(snd_sof_fw_parse_ext_data);
146 static int ext_man_get_fw_version(struct snd_sof_dev *sdev,
147 const struct sof_ext_man_elem_header *hdr)
149 const struct sof_ext_man_fw_version *v =
150 container_of(hdr, struct sof_ext_man_fw_version, hdr);
152 memcpy(&sdev->fw_ready.version, &v->version, sizeof(v->version));
153 sdev->fw_ready.flags = v->flags;
155 /* log ABI versions and check FW compatibility */
156 return snd_sof_ipc_valid(sdev);
159 static int ext_man_get_windows(struct snd_sof_dev *sdev,
160 const struct sof_ext_man_elem_header *hdr)
162 const struct sof_ext_man_window *w;
164 w = container_of(hdr, struct sof_ext_man_window, hdr);
166 return get_ext_windows(sdev, &w->ipc_window.ext_hdr);
169 static int ext_man_get_cc_info(struct snd_sof_dev *sdev,
170 const struct sof_ext_man_elem_header *hdr)
172 const struct sof_ext_man_cc_version *cc;
174 cc = container_of(hdr, struct sof_ext_man_cc_version, hdr);
176 return get_cc_info(sdev, &cc->cc_version.ext_hdr);
179 static ssize_t snd_sof_ext_man_size(const struct firmware *fw)
181 const struct sof_ext_man_header *head;
183 head = (struct sof_ext_man_header *)fw->data;
186 * assert fw size is big enough to contain extended manifest header,
187 * it prevents from reading unallocated memory from `head` in following
190 if (fw->size < sizeof(*head))
194 * When fw points to extended manifest,
195 * then first u32 must be equal SOF_EXT_MAN_MAGIC_NUMBER.
197 if (head->magic == SOF_EXT_MAN_MAGIC_NUMBER)
198 return head->full_size;
200 /* otherwise given fw don't have an extended manifest */
204 /* parse extended FW manifest data structures */
205 static int snd_sof_fw_ext_man_parse(struct snd_sof_dev *sdev,
206 const struct firmware *fw)
208 const struct sof_ext_man_elem_header *elem_hdr;
209 const struct sof_ext_man_header *head;
210 ssize_t ext_man_size;
215 head = (struct sof_ext_man_header *)fw->data;
216 remaining = head->full_size - head->header_size;
217 ext_man_size = snd_sof_ext_man_size(fw);
219 /* Assert firmware starts with extended manifest */
220 if (ext_man_size <= 0)
223 /* incompatible version */
224 if (SOF_EXT_MAN_VERSION_INCOMPATIBLE(SOF_EXT_MAN_VERSION,
225 head->header_version)) {
226 dev_err(sdev->dev, "error: extended manifest version 0x%X differ from used 0x%X\n",
227 head->header_version, SOF_EXT_MAN_VERSION);
231 /* get first extended manifest element header */
232 iptr = (uintptr_t)fw->data + head->header_size;
234 while (remaining > sizeof(*elem_hdr)) {
235 elem_hdr = (struct sof_ext_man_elem_header *)iptr;
237 dev_dbg(sdev->dev, "found sof_ext_man header type %d size 0x%X\n",
238 elem_hdr->type, elem_hdr->size);
240 if (elem_hdr->size < sizeof(*elem_hdr) ||
241 elem_hdr->size > remaining) {
242 dev_err(sdev->dev, "error: invalid sof_ext_man header size, type %d size 0x%X\n",
243 elem_hdr->type, elem_hdr->size);
247 /* process structure data */
248 switch (elem_hdr->type) {
249 case SOF_EXT_MAN_ELEM_FW_VERSION:
250 ret = ext_man_get_fw_version(sdev, elem_hdr);
252 case SOF_EXT_MAN_ELEM_WINDOW:
253 ret = ext_man_get_windows(sdev, elem_hdr);
255 case SOF_EXT_MAN_ELEM_CC_VERSION:
256 ret = ext_man_get_cc_info(sdev, elem_hdr);
259 dev_warn(sdev->dev, "warning: unknown sof_ext_man header type %d size 0x%X\n",
260 elem_hdr->type, elem_hdr->size);
265 dev_err(sdev->dev, "error: failed to parse sof_ext_man header type %d size 0x%X\n",
266 elem_hdr->type, elem_hdr->size);
270 remaining -= elem_hdr->size;
271 iptr += elem_hdr->size;
275 dev_err(sdev->dev, "error: sof_ext_man header is inconsistent\n");
283 * IPC Firmware ready.
285 static void sof_get_windows(struct snd_sof_dev *sdev)
287 struct sof_ipc_window_elem *elem;
288 u32 outbox_offset = 0;
289 u32 stream_offset = 0;
290 u32 inbox_offset = 0;
298 if (!sdev->info_window) {
299 dev_err(sdev->dev, "error: have no window info\n");
303 bar = snd_sof_dsp_get_bar_index(sdev, SOF_FW_BLK_TYPE_SRAM);
305 dev_err(sdev->dev, "error: have no bar mapping\n");
309 for (i = 0; i < sdev->info_window->num_windows; i++) {
310 elem = &sdev->info_window->window[i];
312 window_offset = snd_sof_dsp_get_window_offset(sdev, elem->id);
313 if (window_offset < 0) {
314 dev_warn(sdev->dev, "warn: no offset for window %d\n",
319 switch (elem->type) {
320 case SOF_IPC_REGION_UPBOX:
321 inbox_offset = window_offset + elem->offset;
322 inbox_size = elem->size;
323 snd_sof_debugfs_io_item(sdev,
327 SOF_DEBUGFS_ACCESS_D0_ONLY);
329 case SOF_IPC_REGION_DOWNBOX:
330 outbox_offset = window_offset + elem->offset;
331 outbox_size = elem->size;
332 snd_sof_debugfs_io_item(sdev,
335 elem->size, "outbox",
336 SOF_DEBUGFS_ACCESS_D0_ONLY);
338 case SOF_IPC_REGION_TRACE:
339 snd_sof_debugfs_io_item(sdev,
343 elem->size, "etrace",
344 SOF_DEBUGFS_ACCESS_D0_ONLY);
346 case SOF_IPC_REGION_DEBUG:
347 snd_sof_debugfs_io_item(sdev,
352 SOF_DEBUGFS_ACCESS_D0_ONLY);
354 case SOF_IPC_REGION_STREAM:
355 stream_offset = window_offset + elem->offset;
356 stream_size = elem->size;
357 snd_sof_debugfs_io_item(sdev,
360 elem->size, "stream",
361 SOF_DEBUGFS_ACCESS_D0_ONLY);
363 case SOF_IPC_REGION_REGS:
364 snd_sof_debugfs_io_item(sdev,
369 SOF_DEBUGFS_ACCESS_D0_ONLY);
371 case SOF_IPC_REGION_EXCEPTION:
372 sdev->dsp_oops_offset = window_offset + elem->offset;
373 snd_sof_debugfs_io_item(sdev,
377 elem->size, "exception",
378 SOF_DEBUGFS_ACCESS_D0_ONLY);
381 dev_err(sdev->dev, "error: get illegal window info\n");
386 if (outbox_size == 0 || inbox_size == 0) {
387 dev_err(sdev->dev, "error: get illegal mailbox window\n");
391 snd_sof_dsp_mailbox_init(sdev, inbox_offset, inbox_size,
392 outbox_offset, outbox_size);
393 sdev->stream_box.offset = stream_offset;
394 sdev->stream_box.size = stream_size;
396 dev_dbg(sdev->dev, " mailbox upstream 0x%x - size 0x%x\n",
397 inbox_offset, inbox_size);
398 dev_dbg(sdev->dev, " mailbox downstream 0x%x - size 0x%x\n",
399 outbox_offset, outbox_size);
400 dev_dbg(sdev->dev, " stream region 0x%x - size 0x%x\n",
401 stream_offset, stream_size);
404 /* check for ABI compatibility and create memory windows on first boot */
405 int sof_fw_ready(struct snd_sof_dev *sdev, u32 msg_id)
407 struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready;
412 /* mailbox must be on 4k boundary */
413 offset = snd_sof_dsp_get_mailbox_offset(sdev);
415 dev_err(sdev->dev, "error: have no mailbox offset\n");
419 bar = snd_sof_dsp_get_bar_index(sdev, SOF_FW_BLK_TYPE_SRAM);
421 dev_err(sdev->dev, "error: have no bar mapping\n");
425 dev_dbg(sdev->dev, "ipc: DSP is ready 0x%8.8x offset 0x%x\n",
428 /* no need to re-check version/ABI for subsequent boots */
429 if (!sdev->first_boot)
432 /* copy data from the DSP FW ready offset */
433 sof_block_read(sdev, bar, offset, fw_ready, sizeof(*fw_ready));
435 /* make sure ABI version is compatible */
436 ret = snd_sof_ipc_valid(sdev);
440 /* now check for extended data */
441 snd_sof_fw_parse_ext_data(sdev, bar, offset +
442 sizeof(struct sof_ipc_fw_ready));
444 sof_get_windows(sdev);
448 EXPORT_SYMBOL(sof_fw_ready);
450 /* generic module parser for mmaped DSPs */
451 int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev,
452 struct snd_sof_mod_hdr *module)
454 struct snd_sof_blk_hdr *block;
459 dev_dbg(sdev->dev, "new module size 0x%x blocks 0x%x type 0x%x\n",
460 module->size, module->num_blocks, module->type);
462 block = (struct snd_sof_blk_hdr *)((u8 *)module + sizeof(*module));
464 /* module->size doesn't include header size */
465 remaining = module->size;
466 for (count = 0; count < module->num_blocks; count++) {
468 if (remaining < sizeof(*block)) {
469 dev_err(sdev->dev, "error: not enough data remaining\n");
473 /* minus header size of block */
474 remaining -= sizeof(*block);
476 if (block->size == 0) {
478 "warning: block %d size zero\n", count);
479 dev_warn(sdev->dev, " type 0x%x offset 0x%x\n",
480 block->type, block->offset);
484 switch (block->type) {
485 case SOF_FW_BLK_TYPE_RSRVD0:
486 case SOF_FW_BLK_TYPE_ROM...SOF_FW_BLK_TYPE_RSRVD14:
487 continue; /* not handled atm */
488 case SOF_FW_BLK_TYPE_IRAM:
489 case SOF_FW_BLK_TYPE_DRAM:
490 case SOF_FW_BLK_TYPE_SRAM:
491 offset = block->offset;
492 bar = snd_sof_dsp_get_bar_index(sdev, block->type);
495 "error: no BAR mapping for block type 0x%x\n",
501 dev_err(sdev->dev, "error: bad type 0x%x for block 0x%x\n",
507 "block %d type 0x%x size 0x%x ==> offset 0x%x\n",
508 count, block->type, block->size, offset);
510 /* checking block->size to avoid unaligned access */
511 if (block->size % sizeof(u32)) {
512 dev_err(sdev->dev, "error: invalid block size 0x%x\n",
516 snd_sof_dsp_block_write(sdev, bar, offset,
517 block + 1, block->size);
519 if (remaining < block->size) {
520 dev_err(sdev->dev, "error: not enough data remaining\n");
524 /* minus body size of block */
525 remaining -= block->size;
527 block = (struct snd_sof_blk_hdr *)((u8 *)block + sizeof(*block)
533 EXPORT_SYMBOL(snd_sof_parse_module_memcpy);
535 static int check_header(struct snd_sof_dev *sdev, const struct firmware *fw,
538 struct snd_sof_fw_header *header;
539 size_t fw_size = fw->size - fw_offset;
541 if (fw->size <= fw_offset) {
542 dev_err(sdev->dev, "error: firmware size must be greater than firmware offset\n");
546 /* Read the header information from the data pointer */
547 header = (struct snd_sof_fw_header *)(fw->data + fw_offset);
550 if (strncmp(header->sig, SND_SOF_FW_SIG, SND_SOF_FW_SIG_SIZE) != 0) {
551 dev_err(sdev->dev, "error: invalid firmware signature\n");
555 /* check size is valid */
556 if (fw_size != header->file_size + sizeof(*header)) {
557 dev_err(sdev->dev, "error: invalid filesize mismatch got 0x%zx expected 0x%zx\n",
558 fw_size, header->file_size + sizeof(*header));
562 dev_dbg(sdev->dev, "header size=0x%x modules=0x%x abi=0x%x size=%zu\n",
563 header->file_size, header->num_modules,
564 header->abi, sizeof(*header));
569 static int load_modules(struct snd_sof_dev *sdev, const struct firmware *fw,
572 struct snd_sof_fw_header *header;
573 struct snd_sof_mod_hdr *module;
574 int (*load_module)(struct snd_sof_dev *sof_dev,
575 struct snd_sof_mod_hdr *hdr);
579 header = (struct snd_sof_fw_header *)(fw->data + fw_offset);
580 load_module = sof_ops(sdev)->load_module;
584 /* parse each module */
585 module = (struct snd_sof_mod_hdr *)(fw->data + fw_offset +
587 remaining = fw->size - sizeof(*header) - fw_offset;
589 if (remaining > fw->size) {
590 dev_err(sdev->dev, "error: fw size smaller than header size\n");
594 for (count = 0; count < header->num_modules; count++) {
596 if (remaining < sizeof(*module)) {
597 dev_err(sdev->dev, "error: not enough data remaining\n");
601 /* minus header size of module */
602 remaining -= sizeof(*module);
605 ret = load_module(sdev, module);
607 dev_err(sdev->dev, "error: invalid module %d\n", count);
611 if (remaining < module->size) {
612 dev_err(sdev->dev, "error: not enough data remaining\n");
616 /* minus body size of module */
617 remaining -= module->size;
618 module = (struct snd_sof_mod_hdr *)((u8 *)module
619 + sizeof(*module) + module->size);
625 int snd_sof_load_firmware_raw(struct snd_sof_dev *sdev)
627 struct snd_sof_pdata *plat_data = sdev->pdata;
628 const char *fw_filename;
629 ssize_t ext_man_size;
632 /* Don't request firmware again if firmware is already requested */
636 fw_filename = kasprintf(GFP_KERNEL, "%s/%s",
637 plat_data->fw_filename_prefix,
638 plat_data->fw_filename);
642 ret = request_firmware(&plat_data->fw, fw_filename, sdev->dev);
645 dev_err(sdev->dev, "error: request firmware %s failed err: %d\n",
649 dev_dbg(sdev->dev, "request_firmware %s successful\n",
653 /* check for extended manifest */
654 ext_man_size = snd_sof_fw_ext_man_parse(sdev, plat_data->fw);
655 if (ext_man_size > 0) {
656 /* when no error occurred, drop extended manifest */
657 plat_data->fw_offset = ext_man_size;
658 } else if (!ext_man_size) {
659 /* No extended manifest, so nothing to skip during FW load */
660 dev_dbg(sdev->dev, "firmware doesn't contain extended manifest\n");
663 dev_err(sdev->dev, "error: firmware %s contains unsupported or invalid extended manifest: %d\n",
672 EXPORT_SYMBOL(snd_sof_load_firmware_raw);
674 int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev)
676 struct snd_sof_pdata *plat_data = sdev->pdata;
679 ret = snd_sof_load_firmware_raw(sdev);
683 /* make sure the FW header and file is valid */
684 ret = check_header(sdev, plat_data->fw, plat_data->fw_offset);
686 dev_err(sdev->dev, "error: invalid FW header\n");
690 /* prepare the DSP for FW loading */
691 ret = snd_sof_dsp_reset(sdev);
693 dev_err(sdev->dev, "error: failed to reset DSP\n");
697 /* parse and load firmware modules to DSP */
698 ret = load_modules(sdev, plat_data->fw, plat_data->fw_offset);
700 dev_err(sdev->dev, "error: invalid FW modules\n");
707 release_firmware(plat_data->fw);
708 plat_data->fw = NULL;
712 EXPORT_SYMBOL(snd_sof_load_firmware_memcpy);
714 int snd_sof_load_firmware(struct snd_sof_dev *sdev)
716 dev_dbg(sdev->dev, "loading firmware\n");
718 if (sof_ops(sdev)->load_firmware)
719 return sof_ops(sdev)->load_firmware(sdev);
722 EXPORT_SYMBOL(snd_sof_load_firmware);
724 int snd_sof_run_firmware(struct snd_sof_dev *sdev)
729 init_waitqueue_head(&sdev->boot_wait);
731 /* create read-only fw_version debugfs to store boot version info */
732 if (sdev->first_boot) {
733 ret = snd_sof_debugfs_buf_item(sdev, &sdev->fw_version,
734 sizeof(sdev->fw_version),
736 /* errors are only due to memory allocation, not debugfs */
738 dev_err(sdev->dev, "error: snd_sof_debugfs_buf_item failed\n");
743 /* perform pre fw run operations */
744 ret = snd_sof_dsp_pre_fw_run(sdev);
746 dev_err(sdev->dev, "error: failed pre fw run op\n");
750 dev_dbg(sdev->dev, "booting DSP firmware\n");
752 /* boot the firmware on the DSP */
753 ret = snd_sof_dsp_run(sdev);
755 dev_err(sdev->dev, "error: failed to reset DSP\n");
759 init_core_mask = ret;
762 * now wait for the DSP to boot. There are 3 possible outcomes:
763 * 1. Boot wait times out indicating FW boot failure.
764 * 2. FW boots successfully and fw_ready op succeeds.
765 * 3. FW boots but fw_ready op fails.
767 ret = wait_event_timeout(sdev->boot_wait,
768 sdev->fw_state > SOF_FW_BOOT_IN_PROGRESS,
769 msecs_to_jiffies(sdev->boot_timeout));
771 dev_err(sdev->dev, "error: firmware boot failure\n");
772 snd_sof_dsp_dbg_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX |
773 SOF_DBG_TEXT | SOF_DBG_PCI);
774 sdev->fw_state = SOF_FW_BOOT_FAILED;
778 if (sdev->fw_state == SOF_FW_BOOT_COMPLETE)
779 dev_dbg(sdev->dev, "firmware boot complete\n");
781 return -EIO; /* FW boots but fw_ready op failed */
783 /* perform post fw run operations */
784 ret = snd_sof_dsp_post_fw_run(sdev);
786 dev_err(sdev->dev, "error: failed post fw run op\n");
790 /* fw boot is complete. Update the active cores mask */
791 sdev->enabled_cores_mask = init_core_mask;
795 EXPORT_SYMBOL(snd_sof_run_firmware);
797 void snd_sof_fw_unload(struct snd_sof_dev *sdev)
799 /* TODO: support module unloading at runtime */
801 EXPORT_SYMBOL(snd_sof_fw_unload);