Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gerg/m68knommu
[linux-2.6-microblaze.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 static int get_cc_info(struct snd_sof_dev *sdev,
36                        struct sof_ipc_ext_data_hdr *ext_hdr)
37 {
38         int ret;
39
40         struct sof_ipc_cc_version *cc =
41                 container_of(ext_hdr, struct sof_ipc_cc_version, ext_hdr);
42
43         dev_dbg(sdev->dev, "Firmware info: used compiler %s %d:%d:%d%s used optimization flags %s\n",
44                 cc->name, cc->major, cc->minor, cc->micro, cc->desc,
45                 cc->optim);
46
47         /* create read-only cc_version debugfs to store compiler version info */
48         /* use local copy of the cc_version to prevent data corruption */
49         if (sdev->first_boot) {
50                 sdev->cc_version = devm_kmalloc(sdev->dev, cc->ext_hdr.hdr.size,
51                                                 GFP_KERNEL);
52
53                 if (!sdev->cc_version)
54                         return -ENOMEM;
55
56                 memcpy(sdev->cc_version, cc, cc->ext_hdr.hdr.size);
57                 ret = snd_sof_debugfs_buf_item(sdev, sdev->cc_version,
58                                                cc->ext_hdr.hdr.size,
59                                                "cc_version", 0444);
60
61                 /* errors are only due to memory allocation, not debugfs */
62                 if (ret < 0) {
63                         dev_err(sdev->dev, "error: snd_sof_debugfs_buf_item failed\n");
64                         return ret;
65                 }
66         }
67
68         return 0;
69 }
70
71 /* parse the extended FW boot data structures from FW boot message */
72 int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 bar, u32 offset)
73 {
74         struct sof_ipc_ext_data_hdr *ext_hdr;
75         void *ext_data;
76         int ret = 0;
77
78         ext_data = kzalloc(PAGE_SIZE, GFP_KERNEL);
79         if (!ext_data)
80                 return -ENOMEM;
81
82         /* get first header */
83         snd_sof_dsp_block_read(sdev, bar, offset, ext_data,
84                                sizeof(*ext_hdr));
85         ext_hdr = ext_data;
86
87         while (ext_hdr->hdr.cmd == SOF_IPC_FW_READY) {
88                 /* read in ext structure */
89                 snd_sof_dsp_block_read(sdev, bar, offset + sizeof(*ext_hdr),
90                                    (void *)((u8 *)ext_data + sizeof(*ext_hdr)),
91                                    ext_hdr->hdr.size - sizeof(*ext_hdr));
92
93                 dev_dbg(sdev->dev, "found ext header type %d size 0x%x\n",
94                         ext_hdr->type, ext_hdr->hdr.size);
95
96                 /* process structure data */
97                 switch (ext_hdr->type) {
98                 case SOF_IPC_EXT_WINDOW:
99                         ret = get_ext_windows(sdev, ext_hdr);
100                         break;
101                 case SOF_IPC_EXT_CC_INFO:
102                         ret = get_cc_info(sdev, ext_hdr);
103                         break;
104                 default:
105                         dev_warn(sdev->dev, "warning: unknown ext header type %d size 0x%x\n",
106                                  ext_hdr->type, ext_hdr->hdr.size);
107                         ret = 0;
108                         break;
109                 }
110
111                 if (ret < 0) {
112                         dev_err(sdev->dev, "error: failed to parse ext data type %d\n",
113                                 ext_hdr->type);
114                         break;
115                 }
116
117                 /* move to next header */
118                 offset += ext_hdr->hdr.size;
119                 snd_sof_dsp_block_read(sdev, bar, offset, ext_data,
120                                        sizeof(*ext_hdr));
121                 ext_hdr = ext_data;
122         }
123
124         kfree(ext_data);
125         return ret;
126 }
127 EXPORT_SYMBOL(snd_sof_fw_parse_ext_data);
128
129 /*
130  * IPC Firmware ready.
131  */
132 static void sof_get_windows(struct snd_sof_dev *sdev)
133 {
134         struct sof_ipc_window_elem *elem;
135         u32 outbox_offset = 0;
136         u32 stream_offset = 0;
137         u32 inbox_offset = 0;
138         u32 outbox_size = 0;
139         u32 stream_size = 0;
140         u32 inbox_size = 0;
141         int window_offset;
142         int bar;
143         int i;
144
145         if (!sdev->info_window) {
146                 dev_err(sdev->dev, "error: have no window info\n");
147                 return;
148         }
149
150         bar = snd_sof_dsp_get_bar_index(sdev, SOF_FW_BLK_TYPE_SRAM);
151         if (bar < 0) {
152                 dev_err(sdev->dev, "error: have no bar mapping\n");
153                 return;
154         }
155
156         for (i = 0; i < sdev->info_window->num_windows; i++) {
157                 elem = &sdev->info_window->window[i];
158
159                 window_offset = snd_sof_dsp_get_window_offset(sdev, elem->id);
160                 if (window_offset < 0) {
161                         dev_warn(sdev->dev, "warn: no offset for window %d\n",
162                                  elem->id);
163                         continue;
164                 }
165
166                 switch (elem->type) {
167                 case SOF_IPC_REGION_UPBOX:
168                         inbox_offset = window_offset + elem->offset;
169                         inbox_size = elem->size;
170                         snd_sof_debugfs_io_item(sdev,
171                                                 sdev->bar[bar] +
172                                                 inbox_offset,
173                                                 elem->size, "inbox",
174                                                 SOF_DEBUGFS_ACCESS_D0_ONLY);
175                         break;
176                 case SOF_IPC_REGION_DOWNBOX:
177                         outbox_offset = window_offset + elem->offset;
178                         outbox_size = elem->size;
179                         snd_sof_debugfs_io_item(sdev,
180                                                 sdev->bar[bar] +
181                                                 outbox_offset,
182                                                 elem->size, "outbox",
183                                                 SOF_DEBUGFS_ACCESS_D0_ONLY);
184                         break;
185                 case SOF_IPC_REGION_TRACE:
186                         snd_sof_debugfs_io_item(sdev,
187                                                 sdev->bar[bar] +
188                                                 window_offset +
189                                                 elem->offset,
190                                                 elem->size, "etrace",
191                                                 SOF_DEBUGFS_ACCESS_D0_ONLY);
192                         break;
193                 case SOF_IPC_REGION_DEBUG:
194                         snd_sof_debugfs_io_item(sdev,
195                                                 sdev->bar[bar] +
196                                                 window_offset +
197                                                 elem->offset,
198                                                 elem->size, "debug",
199                                                 SOF_DEBUGFS_ACCESS_D0_ONLY);
200                         break;
201                 case SOF_IPC_REGION_STREAM:
202                         stream_offset = window_offset + elem->offset;
203                         stream_size = elem->size;
204                         snd_sof_debugfs_io_item(sdev,
205                                                 sdev->bar[bar] +
206                                                 stream_offset,
207                                                 elem->size, "stream",
208                                                 SOF_DEBUGFS_ACCESS_D0_ONLY);
209                         break;
210                 case SOF_IPC_REGION_REGS:
211                         snd_sof_debugfs_io_item(sdev,
212                                                 sdev->bar[bar] +
213                                                 window_offset +
214                                                 elem->offset,
215                                                 elem->size, "regs",
216                                                 SOF_DEBUGFS_ACCESS_D0_ONLY);
217                         break;
218                 case SOF_IPC_REGION_EXCEPTION:
219                         sdev->dsp_oops_offset = window_offset + elem->offset;
220                         snd_sof_debugfs_io_item(sdev,
221                                                 sdev->bar[bar] +
222                                                 window_offset +
223                                                 elem->offset,
224                                                 elem->size, "exception",
225                                                 SOF_DEBUGFS_ACCESS_D0_ONLY);
226                         break;
227                 default:
228                         dev_err(sdev->dev, "error: get illegal window info\n");
229                         return;
230                 }
231         }
232
233         if (outbox_size == 0 || inbox_size == 0) {
234                 dev_err(sdev->dev, "error: get illegal mailbox window\n");
235                 return;
236         }
237
238         snd_sof_dsp_mailbox_init(sdev, inbox_offset, inbox_size,
239                                  outbox_offset, outbox_size);
240         sdev->stream_box.offset = stream_offset;
241         sdev->stream_box.size = stream_size;
242
243         dev_dbg(sdev->dev, " mailbox upstream 0x%x - size 0x%x\n",
244                 inbox_offset, inbox_size);
245         dev_dbg(sdev->dev, " mailbox downstream 0x%x - size 0x%x\n",
246                 outbox_offset, outbox_size);
247         dev_dbg(sdev->dev, " stream region 0x%x - size 0x%x\n",
248                 stream_offset, stream_size);
249 }
250
251 /* check for ABI compatibility and create memory windows on first boot */
252 int sof_fw_ready(struct snd_sof_dev *sdev, u32 msg_id)
253 {
254         struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready;
255         int offset;
256         int bar;
257         int ret;
258
259         /* mailbox must be on 4k boundary */
260         offset = snd_sof_dsp_get_mailbox_offset(sdev);
261         if (offset < 0) {
262                 dev_err(sdev->dev, "error: have no mailbox offset\n");
263                 return offset;
264         }
265
266         bar = snd_sof_dsp_get_bar_index(sdev, SOF_FW_BLK_TYPE_SRAM);
267         if (bar < 0) {
268                 dev_err(sdev->dev, "error: have no bar mapping\n");
269                 return -EINVAL;
270         }
271
272         dev_dbg(sdev->dev, "ipc: DSP is ready 0x%8.8x offset 0x%x\n",
273                 msg_id, offset);
274
275         /* no need to re-check version/ABI for subsequent boots */
276         if (!sdev->first_boot)
277                 return 0;
278
279         /* copy data from the DSP FW ready offset */
280         sof_block_read(sdev, bar, offset, fw_ready, sizeof(*fw_ready));
281
282         /* make sure ABI version is compatible */
283         ret = snd_sof_ipc_valid(sdev);
284         if (ret < 0)
285                 return ret;
286
287         /* now check for extended data */
288         snd_sof_fw_parse_ext_data(sdev, bar, offset +
289                                   sizeof(struct sof_ipc_fw_ready));
290
291         sof_get_windows(sdev);
292
293         return 0;
294 }
295 EXPORT_SYMBOL(sof_fw_ready);
296
297 /* generic module parser for mmaped DSPs */
298 int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev,
299                                 struct snd_sof_mod_hdr *module)
300 {
301         struct snd_sof_blk_hdr *block;
302         int count, bar;
303         u32 offset;
304         size_t remaining;
305
306         dev_dbg(sdev->dev, "new module size 0x%x blocks 0x%x type 0x%x\n",
307                 module->size, module->num_blocks, module->type);
308
309         block = (struct snd_sof_blk_hdr *)((u8 *)module + sizeof(*module));
310
311         /* module->size doesn't include header size */
312         remaining = module->size;
313         for (count = 0; count < module->num_blocks; count++) {
314                 /* check for wrap */
315                 if (remaining < sizeof(*block)) {
316                         dev_err(sdev->dev, "error: not enough data remaining\n");
317                         return -EINVAL;
318                 }
319
320                 /* minus header size of block */
321                 remaining -= sizeof(*block);
322
323                 if (block->size == 0) {
324                         dev_warn(sdev->dev,
325                                  "warning: block %d size zero\n", count);
326                         dev_warn(sdev->dev, " type 0x%x offset 0x%x\n",
327                                  block->type, block->offset);
328                         continue;
329                 }
330
331                 switch (block->type) {
332                 case SOF_FW_BLK_TYPE_RSRVD0:
333                 case SOF_FW_BLK_TYPE_ROM...SOF_FW_BLK_TYPE_RSRVD14:
334                         continue;       /* not handled atm */
335                 case SOF_FW_BLK_TYPE_IRAM:
336                 case SOF_FW_BLK_TYPE_DRAM:
337                 case SOF_FW_BLK_TYPE_SRAM:
338                         offset = block->offset;
339                         bar = snd_sof_dsp_get_bar_index(sdev, block->type);
340                         if (bar < 0) {
341                                 dev_err(sdev->dev,
342                                         "error: no BAR mapping for block type 0x%x\n",
343                                         block->type);
344                                 return bar;
345                         }
346                         break;
347                 default:
348                         dev_err(sdev->dev, "error: bad type 0x%x for block 0x%x\n",
349                                 block->type, count);
350                         return -EINVAL;
351                 }
352
353                 dev_dbg(sdev->dev,
354                         "block %d type 0x%x size 0x%x ==>  offset 0x%x\n",
355                         count, block->type, block->size, offset);
356
357                 /* checking block->size to avoid unaligned access */
358                 if (block->size % sizeof(u32)) {
359                         dev_err(sdev->dev, "error: invalid block size 0x%x\n",
360                                 block->size);
361                         return -EINVAL;
362                 }
363                 snd_sof_dsp_block_write(sdev, bar, offset,
364                                         block + 1, block->size);
365
366                 if (remaining < block->size) {
367                         dev_err(sdev->dev, "error: not enough data remaining\n");
368                         return -EINVAL;
369                 }
370
371                 /* minus body size of block */
372                 remaining -= block->size;
373                 /* next block */
374                 block = (struct snd_sof_blk_hdr *)((u8 *)block + sizeof(*block)
375                         + block->size);
376         }
377
378         return 0;
379 }
380 EXPORT_SYMBOL(snd_sof_parse_module_memcpy);
381
382 static int check_header(struct snd_sof_dev *sdev, const struct firmware *fw)
383 {
384         struct snd_sof_fw_header *header;
385
386         /* Read the header information from the data pointer */
387         header = (struct snd_sof_fw_header *)fw->data;
388
389         /* verify FW sig */
390         if (strncmp(header->sig, SND_SOF_FW_SIG, SND_SOF_FW_SIG_SIZE) != 0) {
391                 dev_err(sdev->dev, "error: invalid firmware signature\n");
392                 return -EINVAL;
393         }
394
395         /* check size is valid */
396         if (fw->size != header->file_size + sizeof(*header)) {
397                 dev_err(sdev->dev, "error: invalid filesize mismatch got 0x%zx expected 0x%zx\n",
398                         fw->size, header->file_size + sizeof(*header));
399                 return -EINVAL;
400         }
401
402         dev_dbg(sdev->dev, "header size=0x%x modules=0x%x abi=0x%x size=%zu\n",
403                 header->file_size, header->num_modules,
404                 header->abi, sizeof(*header));
405
406         return 0;
407 }
408
409 static int load_modules(struct snd_sof_dev *sdev, const struct firmware *fw)
410 {
411         struct snd_sof_fw_header *header;
412         struct snd_sof_mod_hdr *module;
413         int (*load_module)(struct snd_sof_dev *sof_dev,
414                            struct snd_sof_mod_hdr *hdr);
415         int ret, count;
416         size_t remaining;
417
418         header = (struct snd_sof_fw_header *)fw->data;
419         load_module = sof_ops(sdev)->load_module;
420         if (!load_module)
421                 return -EINVAL;
422
423         /* parse each module */
424         module = (struct snd_sof_mod_hdr *)((u8 *)(fw->data) + sizeof(*header));
425         remaining = fw->size - sizeof(*header);
426         /* check for wrap */
427         if (remaining > fw->size) {
428                 dev_err(sdev->dev, "error: fw size smaller than header size\n");
429                 return -EINVAL;
430         }
431
432         for (count = 0; count < header->num_modules; count++) {
433                 /* check for wrap */
434                 if (remaining < sizeof(*module)) {
435                         dev_err(sdev->dev, "error: not enough data remaining\n");
436                         return -EINVAL;
437                 }
438
439                 /* minus header size of module */
440                 remaining -= sizeof(*module);
441
442                 /* module */
443                 ret = load_module(sdev, module);
444                 if (ret < 0) {
445                         dev_err(sdev->dev, "error: invalid module %d\n", count);
446                         return ret;
447                 }
448
449                 if (remaining < module->size) {
450                         dev_err(sdev->dev, "error: not enough data remaining\n");
451                         return -EINVAL;
452                 }
453
454                 /* minus body size of module */
455                 remaining -=  module->size;
456                 module = (struct snd_sof_mod_hdr *)((u8 *)module
457                         + sizeof(*module) + module->size);
458         }
459
460         return 0;
461 }
462
463 int snd_sof_load_firmware_raw(struct snd_sof_dev *sdev)
464 {
465         struct snd_sof_pdata *plat_data = sdev->pdata;
466         const char *fw_filename;
467         int ret;
468
469         /* Don't request firmware again if firmware is already requested */
470         if (plat_data->fw)
471                 return 0;
472
473         fw_filename = kasprintf(GFP_KERNEL, "%s/%s",
474                                 plat_data->fw_filename_prefix,
475                                 plat_data->fw_filename);
476         if (!fw_filename)
477                 return -ENOMEM;
478
479         ret = request_firmware(&plat_data->fw, fw_filename, sdev->dev);
480
481         if (ret < 0) {
482                 dev_err(sdev->dev, "error: request firmware %s failed err: %d\n",
483                         fw_filename, ret);
484         } else {
485                 dev_dbg(sdev->dev, "request_firmware %s successful\n",
486                         fw_filename);
487         }
488
489         kfree(fw_filename);
490
491         return ret;
492 }
493 EXPORT_SYMBOL(snd_sof_load_firmware_raw);
494
495 int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev)
496 {
497         struct snd_sof_pdata *plat_data = sdev->pdata;
498         int ret;
499
500         ret = snd_sof_load_firmware_raw(sdev);
501         if (ret < 0)
502                 return ret;
503
504         /* make sure the FW header and file is valid */
505         ret = check_header(sdev, plat_data->fw);
506         if (ret < 0) {
507                 dev_err(sdev->dev, "error: invalid FW header\n");
508                 goto error;
509         }
510
511         /* prepare the DSP for FW loading */
512         ret = snd_sof_dsp_reset(sdev);
513         if (ret < 0) {
514                 dev_err(sdev->dev, "error: failed to reset DSP\n");
515                 goto error;
516         }
517
518         /* parse and load firmware modules to DSP */
519         ret = load_modules(sdev, plat_data->fw);
520         if (ret < 0) {
521                 dev_err(sdev->dev, "error: invalid FW modules\n");
522                 goto error;
523         }
524
525         return 0;
526
527 error:
528         release_firmware(plat_data->fw);
529         plat_data->fw = NULL;
530         return ret;
531
532 }
533 EXPORT_SYMBOL(snd_sof_load_firmware_memcpy);
534
535 int snd_sof_load_firmware(struct snd_sof_dev *sdev)
536 {
537         dev_dbg(sdev->dev, "loading firmware\n");
538
539         if (sof_ops(sdev)->load_firmware)
540                 return sof_ops(sdev)->load_firmware(sdev);
541         return 0;
542 }
543 EXPORT_SYMBOL(snd_sof_load_firmware);
544
545 int snd_sof_run_firmware(struct snd_sof_dev *sdev)
546 {
547         int ret;
548         int init_core_mask;
549
550         init_waitqueue_head(&sdev->boot_wait);
551
552         /* create read-only fw_version debugfs to store boot version info */
553         if (sdev->first_boot) {
554                 ret = snd_sof_debugfs_buf_item(sdev, &sdev->fw_version,
555                                                sizeof(sdev->fw_version),
556                                                "fw_version", 0444);
557                 /* errors are only due to memory allocation, not debugfs */
558                 if (ret < 0) {
559                         dev_err(sdev->dev, "error: snd_sof_debugfs_buf_item failed\n");
560                         return ret;
561                 }
562         }
563
564         /* perform pre fw run operations */
565         ret = snd_sof_dsp_pre_fw_run(sdev);
566         if (ret < 0) {
567                 dev_err(sdev->dev, "error: failed pre fw run op\n");
568                 return ret;
569         }
570
571         dev_dbg(sdev->dev, "booting DSP firmware\n");
572
573         /* boot the firmware on the DSP */
574         ret = snd_sof_dsp_run(sdev);
575         if (ret < 0) {
576                 dev_err(sdev->dev, "error: failed to reset DSP\n");
577                 return ret;
578         }
579
580         init_core_mask = ret;
581
582         /*
583          * now wait for the DSP to boot. There are 3 possible outcomes:
584          * 1. Boot wait times out indicating FW boot failure.
585          * 2. FW boots successfully and fw_ready op succeeds.
586          * 3. FW boots but fw_ready op fails.
587          */
588         ret = wait_event_timeout(sdev->boot_wait,
589                                  sdev->fw_state > SOF_FW_BOOT_IN_PROGRESS,
590                                  msecs_to_jiffies(sdev->boot_timeout));
591         if (ret == 0) {
592                 dev_err(sdev->dev, "error: firmware boot failure\n");
593                 snd_sof_dsp_dbg_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX |
594                         SOF_DBG_TEXT | SOF_DBG_PCI);
595                 sdev->fw_state = SOF_FW_BOOT_FAILED;
596                 return -EIO;
597         }
598
599         if (sdev->fw_state == SOF_FW_BOOT_COMPLETE)
600                 dev_info(sdev->dev, "firmware boot complete\n");
601         else
602                 return -EIO; /* FW boots but fw_ready op failed */
603
604         /* perform post fw run operations */
605         ret = snd_sof_dsp_post_fw_run(sdev);
606         if (ret < 0) {
607                 dev_err(sdev->dev, "error: failed post fw run op\n");
608                 return ret;
609         }
610
611         /* fw boot is complete. Update the active cores mask */
612         sdev->enabled_cores_mask = init_core_mask;
613
614         return 0;
615 }
616 EXPORT_SYMBOL(snd_sof_run_firmware);
617
618 void snd_sof_fw_unload(struct snd_sof_dev *sdev)
619 {
620         /* TODO: support module unloading at runtime */
621 }
622 EXPORT_SYMBOL(snd_sof_fw_unload);