9a9a381a908dee467665c979fecc7d31fb58e3bc
[sfrench/cifs-2.6.git] / sound / soc / sof / loader.c
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 /*
91  * IPC Firmware ready.
92  */
93 static void sof_get_windows(struct snd_sof_dev *sdev)
94 {
95         struct sof_ipc_window_elem *elem;
96         u32 outbox_offset = 0;
97         u32 stream_offset = 0;
98         u32 inbox_offset = 0;
99         u32 outbox_size = 0;
100         u32 stream_size = 0;
101         u32 inbox_size = 0;
102         int window_offset;
103         int bar;
104         int i;
105
106         if (!sdev->info_window) {
107                 dev_err(sdev->dev, "error: have no window info\n");
108                 return;
109         }
110
111         bar = snd_sof_dsp_get_bar_index(sdev, SOF_FW_BLK_TYPE_SRAM);
112         if (bar < 0) {
113                 dev_err(sdev->dev, "error: have no bar mapping\n");
114                 return;
115         }
116
117         for (i = 0; i < sdev->info_window->num_windows; i++) {
118                 elem = &sdev->info_window->window[i];
119
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",
123                                  elem->id);
124                         continue;
125                 }
126
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,
132                                                 sdev->bar[bar] +
133                                                 inbox_offset,
134                                                 elem->size, "inbox",
135                                                 SOF_DEBUGFS_ACCESS_D0_ONLY);
136                         break;
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,
141                                                 sdev->bar[bar] +
142                                                 outbox_offset,
143                                                 elem->size, "outbox",
144                                                 SOF_DEBUGFS_ACCESS_D0_ONLY);
145                         break;
146                 case SOF_IPC_REGION_TRACE:
147                         snd_sof_debugfs_io_item(sdev,
148                                                 sdev->bar[bar] +
149                                                 window_offset +
150                                                 elem->offset,
151                                                 elem->size, "etrace",
152                                                 SOF_DEBUGFS_ACCESS_D0_ONLY);
153                         break;
154                 case SOF_IPC_REGION_DEBUG:
155                         snd_sof_debugfs_io_item(sdev,
156                                                 sdev->bar[bar] +
157                                                 window_offset +
158                                                 elem->offset,
159                                                 elem->size, "debug",
160                                                 SOF_DEBUGFS_ACCESS_D0_ONLY);
161                         break;
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,
166                                                 sdev->bar[bar] +
167                                                 stream_offset,
168                                                 elem->size, "stream",
169                                                 SOF_DEBUGFS_ACCESS_D0_ONLY);
170                         break;
171                 case SOF_IPC_REGION_REGS:
172                         snd_sof_debugfs_io_item(sdev,
173                                                 sdev->bar[bar] +
174                                                 window_offset +
175                                                 elem->offset,
176                                                 elem->size, "regs",
177                                                 SOF_DEBUGFS_ACCESS_D0_ONLY);
178                         break;
179                 case SOF_IPC_REGION_EXCEPTION:
180                         sdev->dsp_oops_offset = window_offset + elem->offset;
181                         snd_sof_debugfs_io_item(sdev,
182                                                 sdev->bar[bar] +
183                                                 window_offset +
184                                                 elem->offset,
185                                                 elem->size, "exception",
186                                                 SOF_DEBUGFS_ACCESS_D0_ONLY);
187                         break;
188                 default:
189                         dev_err(sdev->dev, "error: get illegal window info\n");
190                         return;
191                 }
192         }
193
194         if (outbox_size == 0 || inbox_size == 0) {
195                 dev_err(sdev->dev, "error: get illegal mailbox window\n");
196                 return;
197         }
198
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;
203
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);
210 }
211
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)
214 {
215         struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready;
216         int offset;
217         int bar;
218         int ret;
219
220         /* mailbox must be on 4k boundary */
221         offset = snd_sof_dsp_get_mailbox_offset(sdev);
222         if (offset < 0) {
223                 dev_err(sdev->dev, "error: have no mailbox offset\n");
224                 return offset;
225         }
226
227         bar = snd_sof_dsp_get_bar_index(sdev, SOF_FW_BLK_TYPE_SRAM);
228         if (bar < 0) {
229                 dev_err(sdev->dev, "error: have no bar mapping\n");
230                 return -EINVAL;
231         }
232
233         dev_dbg(sdev->dev, "ipc: DSP is ready 0x%8.8x offset 0x%x\n",
234                 msg_id, offset);
235
236         /* no need to re-check version/ABI for subsequent boots */
237         if (!sdev->first_boot)
238                 return 0;
239
240         /* copy data from the DSP FW ready offset */
241         sof_block_read(sdev, bar, offset, fw_ready, sizeof(*fw_ready));
242
243         /* make sure ABI version is compatible */
244         ret = snd_sof_ipc_valid(sdev);
245         if (ret < 0)
246                 return ret;
247
248         /* now check for extended data */
249         snd_sof_fw_parse_ext_data(sdev, bar, offset +
250                                   sizeof(struct sof_ipc_fw_ready));
251
252         sof_get_windows(sdev);
253
254         return 0;
255 }
256 EXPORT_SYMBOL(sof_fw_ready);
257
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)
261 {
262         struct snd_sof_blk_hdr *block;
263         int count, bar;
264         u32 offset;
265         size_t remaining;
266
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);
269
270         block = (struct snd_sof_blk_hdr *)((u8 *)module + sizeof(*module));
271
272         /* module->size doesn't include header size */
273         remaining = module->size;
274         for (count = 0; count < module->num_blocks; count++) {
275                 /* check for wrap */
276                 if (remaining < sizeof(*block)) {
277                         dev_err(sdev->dev, "error: not enough data remaining\n");
278                         return -EINVAL;
279                 }
280
281                 /* minus header size of block */
282                 remaining -= sizeof(*block);
283
284                 if (block->size == 0) {
285                         dev_warn(sdev->dev,
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);
289                         continue;
290                 }
291
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);
301                         if (bar < 0) {
302                                 dev_err(sdev->dev,
303                                         "error: no BAR mapping for block type 0x%x\n",
304                                         block->type);
305                                 return bar;
306                         }
307                         break;
308                 default:
309                         dev_err(sdev->dev, "error: bad type 0x%x for block 0x%x\n",
310                                 block->type, count);
311                         return -EINVAL;
312                 }
313
314                 dev_dbg(sdev->dev,
315                         "block %d type 0x%x size 0x%x ==>  offset 0x%x\n",
316                         count, block->type, block->size, offset);
317
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",
321                                 block->size);
322                         return -EINVAL;
323                 }
324                 snd_sof_dsp_block_write(sdev, bar, offset,
325                                         block + 1, block->size);
326
327                 if (remaining < block->size) {
328                         dev_err(sdev->dev, "error: not enough data remaining\n");
329                         return -EINVAL;
330                 }
331
332                 /* minus body size of block */
333                 remaining -= block->size;
334                 /* next block */
335                 block = (struct snd_sof_blk_hdr *)((u8 *)block + sizeof(*block)
336                         + block->size);
337         }
338
339         return 0;
340 }
341 EXPORT_SYMBOL(snd_sof_parse_module_memcpy);
342
343 static int check_header(struct snd_sof_dev *sdev, const struct firmware *fw)
344 {
345         struct snd_sof_fw_header *header;
346
347         /* Read the header information from the data pointer */
348         header = (struct snd_sof_fw_header *)fw->data;
349
350         /* verify FW sig */
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");
353                 return -EINVAL;
354         }
355
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));
360                 return -EINVAL;
361         }
362
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));
366
367         return 0;
368 }
369
370 static int load_modules(struct snd_sof_dev *sdev, const struct firmware *fw)
371 {
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);
376         int ret, count;
377         size_t remaining;
378
379         header = (struct snd_sof_fw_header *)fw->data;
380         load_module = sof_ops(sdev)->load_module;
381         if (!load_module)
382                 return -EINVAL;
383
384         /* parse each module */
385         module = (struct snd_sof_mod_hdr *)((u8 *)(fw->data) + sizeof(*header));
386         remaining = fw->size - sizeof(*header);
387         /* check for wrap */
388         if (remaining > fw->size) {
389                 dev_err(sdev->dev, "error: fw size smaller than header size\n");
390                 return -EINVAL;
391         }
392
393         for (count = 0; count < header->num_modules; count++) {
394                 /* check for wrap */
395                 if (remaining < sizeof(*module)) {
396                         dev_err(sdev->dev, "error: not enough data remaining\n");
397                         return -EINVAL;
398                 }
399
400                 /* minus header size of module */
401                 remaining -= sizeof(*module);
402
403                 /* module */
404                 ret = load_module(sdev, module);
405                 if (ret < 0) {
406                         dev_err(sdev->dev, "error: invalid module %d\n", count);
407                         return ret;
408                 }
409
410                 if (remaining < module->size) {
411                         dev_err(sdev->dev, "error: not enough data remaining\n");
412                         return -EINVAL;
413                 }
414
415                 /* minus body size of module */
416                 remaining -=  module->size;
417                 module = (struct snd_sof_mod_hdr *)((u8 *)module
418                         + sizeof(*module) + module->size);
419         }
420
421         return 0;
422 }
423
424 int snd_sof_load_firmware_raw(struct snd_sof_dev *sdev)
425 {
426         struct snd_sof_pdata *plat_data = sdev->pdata;
427         const char *fw_filename;
428         int ret;
429
430         /* set code loading condition to true */
431         sdev->code_loading = 1;
432
433         /* Don't request firmware again if firmware is already requested */
434         if (plat_data->fw)
435                 return 0;
436
437         fw_filename = kasprintf(GFP_KERNEL, "%s/%s",
438                                 plat_data->fw_filename_prefix,
439                                 plat_data->fw_filename);
440         if (!fw_filename)
441                 return -ENOMEM;
442
443         ret = request_firmware(&plat_data->fw, fw_filename, sdev->dev);
444
445         if (ret < 0) {
446                 dev_err(sdev->dev, "error: request firmware %s failed err: %d\n",
447                         fw_filename, ret);
448         }
449
450         kfree(fw_filename);
451
452         return ret;
453 }
454 EXPORT_SYMBOL(snd_sof_load_firmware_raw);
455
456 int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev)
457 {
458         struct snd_sof_pdata *plat_data = sdev->pdata;
459         int ret;
460
461         ret = snd_sof_load_firmware_raw(sdev);
462         if (ret < 0)
463                 return ret;
464
465         /* make sure the FW header and file is valid */
466         ret = check_header(sdev, plat_data->fw);
467         if (ret < 0) {
468                 dev_err(sdev->dev, "error: invalid FW header\n");
469                 goto error;
470         }
471
472         /* prepare the DSP for FW loading */
473         ret = snd_sof_dsp_reset(sdev);
474         if (ret < 0) {
475                 dev_err(sdev->dev, "error: failed to reset DSP\n");
476                 goto error;
477         }
478
479         /* parse and load firmware modules to DSP */
480         ret = load_modules(sdev, plat_data->fw);
481         if (ret < 0) {
482                 dev_err(sdev->dev, "error: invalid FW modules\n");
483                 goto error;
484         }
485
486         return 0;
487
488 error:
489         release_firmware(plat_data->fw);
490         plat_data->fw = NULL;
491         return ret;
492
493 }
494 EXPORT_SYMBOL(snd_sof_load_firmware_memcpy);
495
496 int snd_sof_load_firmware(struct snd_sof_dev *sdev)
497 {
498         dev_dbg(sdev->dev, "loading firmware\n");
499
500         if (sof_ops(sdev)->load_firmware)
501                 return sof_ops(sdev)->load_firmware(sdev);
502         return 0;
503 }
504 EXPORT_SYMBOL(snd_sof_load_firmware);
505
506 int snd_sof_run_firmware(struct snd_sof_dev *sdev)
507 {
508         int ret;
509         int init_core_mask;
510
511         init_waitqueue_head(&sdev->boot_wait);
512         sdev->boot_complete = false;
513
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),
518                                                "fw_version", 0444);
519                 /* errors are only due to memory allocation, not debugfs */
520                 if (ret < 0) {
521                         dev_err(sdev->dev, "error: snd_sof_debugfs_buf_item failed\n");
522                         return ret;
523                 }
524         }
525
526         /* perform pre fw run operations */
527         ret = snd_sof_dsp_pre_fw_run(sdev);
528         if (ret < 0) {
529                 dev_err(sdev->dev, "error: failed pre fw run op\n");
530                 return ret;
531         }
532
533         dev_dbg(sdev->dev, "booting DSP firmware\n");
534
535         /* boot the firmware on the DSP */
536         ret = snd_sof_dsp_run(sdev);
537         if (ret < 0) {
538                 dev_err(sdev->dev, "error: failed to reset DSP\n");
539                 return ret;
540         }
541
542         init_core_mask = ret;
543
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));
547         if (ret == 0) {
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;
553                 return -EIO;
554         }
555
556         dev_info(sdev->dev, "firmware boot complete\n");
557
558         /* perform post fw run operations */
559         ret = snd_sof_dsp_post_fw_run(sdev);
560         if (ret < 0) {
561                 dev_err(sdev->dev, "error: failed post fw run op\n");
562                 return ret;
563         }
564
565         /* fw boot is complete. Update the active cores mask */
566         sdev->enabled_cores_mask = init_core_mask;
567
568         return 0;
569 }
570 EXPORT_SYMBOL(snd_sof_run_firmware);
571
572 void snd_sof_fw_unload(struct snd_sof_dev *sdev)
573 {
574         /* TODO: support module unloading at runtime */
575 }
576 EXPORT_SYMBOL(snd_sof_fw_unload);