1 // SPDX-License-Identifier: (GPL-2.0 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>
17 static int get_ext_windows(struct snd_sof_dev
*sdev
,
18 struct sof_ipc_ext_data_hdr
*ext_hdr
)
20 struct sof_ipc_window
*w
=
21 container_of(ext_hdr
, struct sof_ipc_window
, ext_hdr
);
23 if (w
->num_windows
== 0 || w
->num_windows
> SOF_IPC_MAX_ELEMS
)
26 /* keep a local copy of the data */
27 sdev
->info_window
= kmemdup(w
, struct_size(w
, window
, w
->num_windows
),
29 if (!sdev
->info_window
)
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
)
38 struct sof_ipc_ext_data_hdr
*ext_hdr
;
42 ext_data
= kzalloc(PAGE_SIZE
, GFP_KERNEL
);
46 /* get first header */
47 snd_sof_dsp_block_read(sdev
, bar
, offset
, ext_data
,
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
));
58 dev_dbg(sdev
->dev
, "found ext header type %d size 0x%x\n",
59 ext_hdr
->type
, ext_hdr
->hdr
.size
);
61 /* process structure data */
62 switch (ext_hdr
->type
) {
63 case SOF_IPC_EXT_DMA_BUFFER
:
65 case SOF_IPC_EXT_WINDOW
:
66 ret
= get_ext_windows(sdev
, ext_hdr
);
73 dev_err(sdev
->dev
, "error: failed to parse ext data type %d\n",
78 /* move to next header */
79 offset
+= ext_hdr
->hdr
.size
;
80 snd_sof_dsp_block_read(sdev
, bar
, offset
, ext_data
,
88 EXPORT_SYMBOL(snd_sof_fw_parse_ext_data
);
93 static void sof_get_windows(struct snd_sof_dev
*sdev
)
95 struct sof_ipc_window_elem
*elem
;
96 u32 outbox_offset
= 0;
97 u32 stream_offset
= 0;
106 if (!sdev
->info_window
) {
107 dev_err(sdev
->dev
, "error: have no window info\n");
111 bar
= snd_sof_dsp_get_bar_index(sdev
, SOF_FW_BLK_TYPE_SRAM
);
113 dev_err(sdev
->dev
, "error: have no bar mapping\n");
117 for (i
= 0; i
< sdev
->info_window
->num_windows
; i
++) {
118 elem
= &sdev
->info_window
->window
[i
];
120 window_offset
= snd_sof_dsp_get_window_offset(sdev
, elem
->id
);
121 if (window_offset
< 0) {
122 dev_warn(sdev
->dev
, "warn: no offset for window %d\n",
127 switch (elem
->type
) {
128 case SOF_IPC_REGION_UPBOX
:
129 inbox_offset
= window_offset
+ elem
->offset
;
130 inbox_size
= elem
->size
;
131 snd_sof_debugfs_io_item(sdev
,
135 SOF_DEBUGFS_ACCESS_D0_ONLY
);
137 case SOF_IPC_REGION_DOWNBOX
:
138 outbox_offset
= window_offset
+ elem
->offset
;
139 outbox_size
= elem
->size
;
140 snd_sof_debugfs_io_item(sdev
,
143 elem
->size
, "outbox",
144 SOF_DEBUGFS_ACCESS_D0_ONLY
);
146 case SOF_IPC_REGION_TRACE
:
147 snd_sof_debugfs_io_item(sdev
,
151 elem
->size
, "etrace",
152 SOF_DEBUGFS_ACCESS_D0_ONLY
);
154 case SOF_IPC_REGION_DEBUG
:
155 snd_sof_debugfs_io_item(sdev
,
160 SOF_DEBUGFS_ACCESS_D0_ONLY
);
162 case SOF_IPC_REGION_STREAM
:
163 stream_offset
= window_offset
+ elem
->offset
;
164 stream_size
= elem
->size
;
165 snd_sof_debugfs_io_item(sdev
,
168 elem
->size
, "stream",
169 SOF_DEBUGFS_ACCESS_D0_ONLY
);
171 case SOF_IPC_REGION_REGS
:
172 snd_sof_debugfs_io_item(sdev
,
177 SOF_DEBUGFS_ACCESS_D0_ONLY
);
179 case SOF_IPC_REGION_EXCEPTION
:
180 sdev
->dsp_oops_offset
= window_offset
+ elem
->offset
;
181 snd_sof_debugfs_io_item(sdev
,
185 elem
->size
, "exception",
186 SOF_DEBUGFS_ACCESS_D0_ONLY
);
189 dev_err(sdev
->dev
, "error: get illegal window info\n");
194 if (outbox_size
== 0 || inbox_size
== 0) {
195 dev_err(sdev
->dev
, "error: get illegal mailbox window\n");
199 snd_sof_dsp_mailbox_init(sdev
, inbox_offset
, inbox_size
,
200 outbox_offset
, outbox_size
);
201 sdev
->stream_box
.offset
= stream_offset
;
202 sdev
->stream_box
.size
= stream_size
;
204 dev_dbg(sdev
->dev
, " mailbox upstream 0x%x - size 0x%x\n",
205 inbox_offset
, inbox_size
);
206 dev_dbg(sdev
->dev
, " mailbox downstream 0x%x - size 0x%x\n",
207 outbox_offset
, outbox_size
);
208 dev_dbg(sdev
->dev
, " stream region 0x%x - size 0x%x\n",
209 stream_offset
, stream_size
);
212 /* check for ABI compatibility and create memory windows on first boot */
213 int sof_fw_ready(struct snd_sof_dev
*sdev
, u32 msg_id
)
215 struct sof_ipc_fw_ready
*fw_ready
= &sdev
->fw_ready
;
220 /* mailbox must be on 4k boundary */
221 offset
= snd_sof_dsp_get_mailbox_offset(sdev
);
223 dev_err(sdev
->dev
, "error: have no mailbox offset\n");
227 bar
= snd_sof_dsp_get_bar_index(sdev
, SOF_FW_BLK_TYPE_SRAM
);
229 dev_err(sdev
->dev
, "error: have no bar mapping\n");
233 dev_dbg(sdev
->dev
, "ipc: DSP is ready 0x%8.8x offset 0x%x\n",
236 /* no need to re-check version/ABI for subsequent boots */
237 if (!sdev
->first_boot
)
240 /* copy data from the DSP FW ready offset */
241 sof_block_read(sdev
, bar
, offset
, fw_ready
, sizeof(*fw_ready
));
243 /* make sure ABI version is compatible */
244 ret
= snd_sof_ipc_valid(sdev
);
248 /* now check for extended data */
249 snd_sof_fw_parse_ext_data(sdev
, bar
, offset
+
250 sizeof(struct sof_ipc_fw_ready
));
252 sof_get_windows(sdev
);
256 EXPORT_SYMBOL(sof_fw_ready
);
258 /* generic module parser for mmaped DSPs */
259 int snd_sof_parse_module_memcpy(struct snd_sof_dev
*sdev
,
260 struct snd_sof_mod_hdr
*module
)
262 struct snd_sof_blk_hdr
*block
;
267 dev_dbg(sdev
->dev
, "new module size 0x%x blocks 0x%x type 0x%x\n",
268 module
->size
, module
->num_blocks
, module
->type
);
270 block
= (struct snd_sof_blk_hdr
*)((u8
*)module
+ sizeof(*module
));
272 /* module->size doesn't include header size */
273 remaining
= module
->size
;
274 for (count
= 0; count
< module
->num_blocks
; count
++) {
276 if (remaining
< sizeof(*block
)) {
277 dev_err(sdev
->dev
, "error: not enough data remaining\n");
281 /* minus header size of block */
282 remaining
-= sizeof(*block
);
284 if (block
->size
== 0) {
286 "warning: block %d size zero\n", count
);
287 dev_warn(sdev
->dev
, " type 0x%x offset 0x%x\n",
288 block
->type
, block
->offset
);
292 switch (block
->type
) {
293 case SOF_FW_BLK_TYPE_RSRVD0
:
294 case SOF_FW_BLK_TYPE_ROM
...SOF_FW_BLK_TYPE_RSRVD14
:
295 continue; /* not handled atm */
296 case SOF_FW_BLK_TYPE_IRAM
:
297 case SOF_FW_BLK_TYPE_DRAM
:
298 case SOF_FW_BLK_TYPE_SRAM
:
299 offset
= block
->offset
;
300 bar
= snd_sof_dsp_get_bar_index(sdev
, block
->type
);
303 "error: no BAR mapping for block type 0x%x\n",
309 dev_err(sdev
->dev
, "error: bad type 0x%x for block 0x%x\n",
315 "block %d type 0x%x size 0x%x ==> offset 0x%x\n",
316 count
, block
->type
, block
->size
, offset
);
318 /* checking block->size to avoid unaligned access */
319 if (block
->size
% sizeof(u32
)) {
320 dev_err(sdev
->dev
, "error: invalid block size 0x%x\n",
324 snd_sof_dsp_block_write(sdev
, bar
, offset
,
325 block
+ 1, block
->size
);
327 if (remaining
< block
->size
) {
328 dev_err(sdev
->dev
, "error: not enough data remaining\n");
332 /* minus body size of block */
333 remaining
-= block
->size
;
335 block
= (struct snd_sof_blk_hdr
*)((u8
*)block
+ sizeof(*block
)
341 EXPORT_SYMBOL(snd_sof_parse_module_memcpy
);
343 static int check_header(struct snd_sof_dev
*sdev
, const struct firmware
*fw
)
345 struct snd_sof_fw_header
*header
;
347 /* Read the header information from the data pointer */
348 header
= (struct snd_sof_fw_header
*)fw
->data
;
351 if (strncmp(header
->sig
, SND_SOF_FW_SIG
, SND_SOF_FW_SIG_SIZE
) != 0) {
352 dev_err(sdev
->dev
, "error: invalid firmware signature\n");
356 /* check size is valid */
357 if (fw
->size
!= header
->file_size
+ sizeof(*header
)) {
358 dev_err(sdev
->dev
, "error: invalid filesize mismatch got 0x%zx expected 0x%zx\n",
359 fw
->size
, header
->file_size
+ sizeof(*header
));
363 dev_dbg(sdev
->dev
, "header size=0x%x modules=0x%x abi=0x%x size=%zu\n",
364 header
->file_size
, header
->num_modules
,
365 header
->abi
, sizeof(*header
));
370 static int load_modules(struct snd_sof_dev
*sdev
, const struct firmware
*fw
)
372 struct snd_sof_fw_header
*header
;
373 struct snd_sof_mod_hdr
*module
;
374 int (*load_module
)(struct snd_sof_dev
*sof_dev
,
375 struct snd_sof_mod_hdr
*hdr
);
379 header
= (struct snd_sof_fw_header
*)fw
->data
;
380 load_module
= sof_ops(sdev
)->load_module
;
384 /* parse each module */
385 module
= (struct snd_sof_mod_hdr
*)((u8
*)(fw
->data
) + sizeof(*header
));
386 remaining
= fw
->size
- sizeof(*header
);
388 if (remaining
> fw
->size
) {
389 dev_err(sdev
->dev
, "error: fw size smaller than header size\n");
393 for (count
= 0; count
< header
->num_modules
; count
++) {
395 if (remaining
< sizeof(*module
)) {
396 dev_err(sdev
->dev
, "error: not enough data remaining\n");
400 /* minus header size of module */
401 remaining
-= sizeof(*module
);
404 ret
= load_module(sdev
, module
);
406 dev_err(sdev
->dev
, "error: invalid module %d\n", count
);
410 if (remaining
< module
->size
) {
411 dev_err(sdev
->dev
, "error: not enough data remaining\n");
415 /* minus body size of module */
416 remaining
-= module
->size
;
417 module
= (struct snd_sof_mod_hdr
*)((u8
*)module
418 + sizeof(*module
) + module
->size
);
424 int snd_sof_load_firmware_raw(struct snd_sof_dev
*sdev
)
426 struct snd_sof_pdata
*plat_data
= sdev
->pdata
;
427 const char *fw_filename
;
430 /* set code loading condition to true */
431 sdev
->code_loading
= 1;
433 /* Don't request firmware again if firmware is already requested */
437 fw_filename
= kasprintf(GFP_KERNEL
, "%s/%s",
438 plat_data
->fw_filename_prefix
,
439 plat_data
->fw_filename
);
443 ret
= request_firmware(&plat_data
->fw
, fw_filename
, sdev
->dev
);
446 dev_err(sdev
->dev
, "error: request firmware %s failed err: %d\n",
454 EXPORT_SYMBOL(snd_sof_load_firmware_raw
);
456 int snd_sof_load_firmware_memcpy(struct snd_sof_dev
*sdev
)
458 struct snd_sof_pdata
*plat_data
= sdev
->pdata
;
461 ret
= snd_sof_load_firmware_raw(sdev
);
465 /* make sure the FW header and file is valid */
466 ret
= check_header(sdev
, plat_data
->fw
);
468 dev_err(sdev
->dev
, "error: invalid FW header\n");
472 /* prepare the DSP for FW loading */
473 ret
= snd_sof_dsp_reset(sdev
);
475 dev_err(sdev
->dev
, "error: failed to reset DSP\n");
479 /* parse and load firmware modules to DSP */
480 ret
= load_modules(sdev
, plat_data
->fw
);
482 dev_err(sdev
->dev
, "error: invalid FW modules\n");
489 release_firmware(plat_data
->fw
);
490 plat_data
->fw
= NULL
;
494 EXPORT_SYMBOL(snd_sof_load_firmware_memcpy
);
496 int snd_sof_load_firmware(struct snd_sof_dev
*sdev
)
498 dev_dbg(sdev
->dev
, "loading firmware\n");
500 if (sof_ops(sdev
)->load_firmware
)
501 return sof_ops(sdev
)->load_firmware(sdev
);
504 EXPORT_SYMBOL(snd_sof_load_firmware
);
506 int snd_sof_run_firmware(struct snd_sof_dev
*sdev
)
511 init_waitqueue_head(&sdev
->boot_wait
);
512 sdev
->boot_complete
= false;
514 /* create read-only fw_version debugfs to store boot version info */
515 if (sdev
->first_boot
) {
516 ret
= snd_sof_debugfs_buf_item(sdev
, &sdev
->fw_version
,
517 sizeof(sdev
->fw_version
),
519 /* errors are only due to memory allocation, not debugfs */
521 dev_err(sdev
->dev
, "error: snd_sof_debugfs_buf_item failed\n");
526 /* perform pre fw run operations */
527 ret
= snd_sof_dsp_pre_fw_run(sdev
);
529 dev_err(sdev
->dev
, "error: failed pre fw run op\n");
533 dev_dbg(sdev
->dev
, "booting DSP firmware\n");
535 /* boot the firmware on the DSP */
536 ret
= snd_sof_dsp_run(sdev
);
538 dev_err(sdev
->dev
, "error: failed to reset DSP\n");
542 init_core_mask
= ret
;
544 /* now wait for the DSP to boot */
545 ret
= wait_event_timeout(sdev
->boot_wait
, sdev
->boot_complete
,
546 msecs_to_jiffies(sdev
->boot_timeout
));
548 dev_err(sdev
->dev
, "error: firmware boot failure\n");
549 snd_sof_dsp_dbg_dump(sdev
, SOF_DBG_REGS
| SOF_DBG_MBOX
|
550 SOF_DBG_TEXT
| SOF_DBG_PCI
);
551 /* after this point FW_READY msg should be ignored */
552 sdev
->boot_complete
= true;
556 dev_info(sdev
->dev
, "firmware boot complete\n");
558 /* perform post fw run operations */
559 ret
= snd_sof_dsp_post_fw_run(sdev
);
561 dev_err(sdev
->dev
, "error: failed post fw run op\n");
565 /* fw boot is complete. Update the active cores mask */
566 sdev
->enabled_cores_mask
= init_core_mask
;
570 EXPORT_SYMBOL(snd_sof_run_firmware
);
572 void snd_sof_fw_unload(struct snd_sof_dev
*sdev
)
574 /* TODO: support module unloading at runtime */
576 EXPORT_SYMBOL(snd_sof_fw_unload
);