2d12e8bab76903090f91b16c6f7c0e0b2c7e729d
[linux-2.6-microblaze.git] / sound / soc / sof / core.c
1 // SPDX-License-Identifier: (GPL-2.0-only 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
11 #include <linux/firmware.h>
12 #include <linux/module.h>
13 #include <sound/soc.h>
14 #include <sound/sof.h>
15 #include "sof-priv.h"
16 #include "ops.h"
17
18 /* see SOF_DBG_ flags */
19 static int sof_core_debug =  IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_FIRMWARE_TRACE);
20 module_param_named(sof_debug, sof_core_debug, int, 0444);
21 MODULE_PARM_DESC(sof_debug, "SOF core debug options (0x0 all off)");
22
23 /* SOF defaults if not provided by the platform in ms */
24 #define TIMEOUT_DEFAULT_IPC_MS  500
25 #define TIMEOUT_DEFAULT_BOOT_MS 2000
26
27 /**
28  * sof_debug_check_flag - check if a given flag(s) is set in sof_core_debug
29  * @mask: Flag or combination of flags to check
30  *
31  * Returns true if all bits set in mask is also set in sof_core_debug, otherwise
32  * false
33  */
34 bool sof_debug_check_flag(int mask)
35 {
36         if ((sof_core_debug & mask) == mask)
37                 return true;
38
39         return false;
40 }
41 EXPORT_SYMBOL(sof_debug_check_flag);
42
43 /*
44  * FW Panic/fault handling.
45  */
46
47 struct sof_panic_msg {
48         u32 id;
49         const char *msg;
50 };
51
52 /* standard FW panic types */
53 static const struct sof_panic_msg panic_msg[] = {
54         {SOF_IPC_PANIC_MEM, "out of memory"},
55         {SOF_IPC_PANIC_WORK, "work subsystem init failed"},
56         {SOF_IPC_PANIC_IPC, "IPC subsystem init failed"},
57         {SOF_IPC_PANIC_ARCH, "arch init failed"},
58         {SOF_IPC_PANIC_PLATFORM, "platform init failed"},
59         {SOF_IPC_PANIC_TASK, "scheduler init failed"},
60         {SOF_IPC_PANIC_EXCEPTION, "runtime exception"},
61         {SOF_IPC_PANIC_DEADLOCK, "deadlock"},
62         {SOF_IPC_PANIC_STACK, "stack overflow"},
63         {SOF_IPC_PANIC_IDLE, "can't enter idle"},
64         {SOF_IPC_PANIC_WFI, "invalid wait state"},
65         {SOF_IPC_PANIC_ASSERT, "assertion failed"},
66 };
67
68 /**
69  * sof_print_oops_and_stack - Handle the printing of DSP oops and stack trace
70  * @sdev: Pointer to the device's sdev
71  * @level: prink log level to use for the printing
72  * @panic_code: the panic code
73  * @tracep_code: tracepoint code
74  * @oops: Pointer to DSP specific oops data
75  * @panic_info: Pointer to the received panic information message
76  * @stack: Pointer to the call stack data
77  * @stack_words: Number of words in the stack data
78  *
79  * helper to be called from .dbg_dump callbacks. No error code is
80  * provided, it's left as an exercise for the caller of .dbg_dump
81  * (typically IPC or loader)
82  */
83 void sof_print_oops_and_stack(struct snd_sof_dev *sdev, const char *level,
84                               u32 panic_code, u32 tracep_code, void *oops,
85                               struct sof_ipc_panic_info *panic_info,
86                               void *stack, size_t stack_words)
87 {
88         u32 code;
89         int i;
90
91         /* is firmware dead ? */
92         if ((panic_code & SOF_IPC_PANIC_MAGIC_MASK) != SOF_IPC_PANIC_MAGIC) {
93                 dev_printk(level, sdev->dev, "unexpected fault %#010x trace %#010x\n",
94                            panic_code, tracep_code);
95                 return; /* no fault ? */
96         }
97
98         code = panic_code & (SOF_IPC_PANIC_MAGIC_MASK | SOF_IPC_PANIC_CODE_MASK);
99
100         for (i = 0; i < ARRAY_SIZE(panic_msg); i++) {
101                 if (panic_msg[i].id == code) {
102                         dev_printk(level, sdev->dev, "reason: %s (%#x)\n",
103                                    panic_msg[i].msg, code & SOF_IPC_PANIC_CODE_MASK);
104                         dev_printk(level, sdev->dev, "trace point: %#010x\n", tracep_code);
105                         goto out;
106                 }
107         }
108
109         /* unknown error */
110         dev_printk(level, sdev->dev, "unknown panic code: %#x\n",
111                    code & SOF_IPC_PANIC_CODE_MASK);
112         dev_printk(level, sdev->dev, "trace point: %#010x\n", tracep_code);
113
114 out:
115         dev_printk(level, sdev->dev, "panic at %s:%d\n", panic_info->filename,
116                    panic_info->linenum);
117         sof_oops(sdev, level, oops);
118         sof_stack(sdev, level, oops, stack, stack_words);
119 }
120 EXPORT_SYMBOL(sof_print_oops_and_stack);
121
122 /* Helper to manage DSP state */
123 void sof_set_fw_state(struct snd_sof_dev *sdev, enum sof_fw_state new_state)
124 {
125         if (sdev->fw_state == new_state)
126                 return;
127
128         dev_dbg(sdev->dev, "fw_state change: %d -> %d\n", sdev->fw_state, new_state);
129         sdev->fw_state = new_state;
130
131         switch (new_state) {
132         case SOF_FW_BOOT_NOT_STARTED:
133         case SOF_FW_BOOT_COMPLETE:
134         case SOF_FW_CRASHED:
135                 sof_client_fw_state_dispatcher(sdev);
136                 fallthrough;
137         default:
138                 break;
139         }
140 }
141 EXPORT_SYMBOL(sof_set_fw_state);
142
143 /*
144  *                      FW Boot State Transition Diagram
145  *
146  *    +----------------------------------------------------------------------+
147  *    |                                                                      |
148  * ------------------        ------------------                              |
149  * |                |        |                |                              |
150  * |   BOOT_FAILED  |<-------|  READY_FAILED  |                              |
151  * |                |<--+    |                |    ------------------        |
152  * ------------------   |    ------------------    |                |        |
153  *      ^               |           ^              |    CRASHED     |---+    |
154  *      |               |           |              |                |   |    |
155  * (FW Boot Timeout)    |       (FW_READY FAIL)    ------------------   |    |
156  *      |               |           |                ^                  |    |
157  *      |               |           |                |(DSP Panic)       |    |
158  * ------------------   |           |              ------------------   |    |
159  * |                |   |           |              |                |   |    |
160  * |   IN_PROGRESS  |---------------+------------->|    COMPLETE    |   |    |
161  * |                | (FW Boot OK)   (FW_READY OK) |                |   |    |
162  * ------------------   |                          ------------------   |    |
163  *      ^               |                               |               |    |
164  *      |               |                               |               |    |
165  * (FW Loading OK)      |                       (System Suspend/Runtime Suspend)
166  *      |               |                               |               |    |
167  *      |       (FW Loading Fail)                       |               |    |
168  * ------------------   |       ------------------      |               |    |
169  * |                |   |       |                |<-----+               |    |
170  * |   PREPARE      |---+       |   NOT_STARTED  |<---------------------+    |
171  * |                |           |                |<--------------------------+
172  * ------------------           ------------------
173  *    |     ^                       |      ^
174  *    |     |                       |      |
175  *    |     +-----------------------+      |
176  *    |         (DSP Probe OK)             |
177  *    |                                    |
178  *    |                                    |
179  *    +------------------------------------+
180  *      (System Suspend/Runtime Suspend)
181  */
182
183 static int sof_probe_continue(struct snd_sof_dev *sdev)
184 {
185         struct snd_sof_pdata *plat_data = sdev->pdata;
186         int ret;
187
188         /* probe the DSP hardware */
189         ret = snd_sof_probe(sdev);
190         if (ret < 0) {
191                 dev_err(sdev->dev, "error: failed to probe DSP %d\n", ret);
192                 return ret;
193         }
194
195         sof_set_fw_state(sdev, SOF_FW_BOOT_PREPARE);
196
197         /* check machine info */
198         ret = sof_machine_check(sdev);
199         if (ret < 0) {
200                 dev_err(sdev->dev, "error: failed to get machine info %d\n",
201                         ret);
202                 goto dsp_err;
203         }
204
205         /* set up platform component driver */
206         snd_sof_new_platform_drv(sdev);
207
208         /* register any debug/trace capabilities */
209         ret = snd_sof_dbg_init(sdev);
210         if (ret < 0) {
211                 /*
212                  * debugfs issues are suppressed in snd_sof_dbg_init() since
213                  * we cannot rely on debugfs
214                  * here we trap errors due to memory allocation only.
215                  */
216                 dev_err(sdev->dev, "error: failed to init DSP trace/debug %d\n",
217                         ret);
218                 goto dbg_err;
219         }
220
221         /* init the IPC */
222         sdev->ipc = snd_sof_ipc_init(sdev);
223         if (!sdev->ipc) {
224                 ret = -ENOMEM;
225                 dev_err(sdev->dev, "error: failed to init DSP IPC %d\n", ret);
226                 goto ipc_err;
227         }
228
229         /* load the firmware */
230         ret = snd_sof_load_firmware(sdev);
231         if (ret < 0) {
232                 dev_err(sdev->dev, "error: failed to load DSP firmware %d\n",
233                         ret);
234                 sof_set_fw_state(sdev, SOF_FW_BOOT_FAILED);
235                 goto fw_load_err;
236         }
237
238         sof_set_fw_state(sdev, SOF_FW_BOOT_IN_PROGRESS);
239
240         /*
241          * Boot the firmware. The FW boot status will be modified
242          * in snd_sof_run_firmware() depending on the outcome.
243          */
244         ret = snd_sof_run_firmware(sdev);
245         if (ret < 0) {
246                 dev_err(sdev->dev, "error: failed to boot DSP firmware %d\n",
247                         ret);
248                 sof_set_fw_state(sdev, SOF_FW_BOOT_FAILED);
249                 goto fw_run_err;
250         }
251
252         if (sof_debug_check_flag(SOF_DBG_ENABLE_TRACE)) {
253                 sdev->dtrace_is_supported = true;
254
255                 /* init DMA trace */
256                 ret = snd_sof_init_trace(sdev);
257                 if (ret < 0) {
258                         /* non fatal */
259                         dev_warn(sdev->dev,
260                                  "warning: failed to initialize trace %d\n",
261                                  ret);
262                 }
263         } else {
264                 dev_dbg(sdev->dev, "SOF firmware trace disabled\n");
265         }
266
267         /* hereafter all FW boot flows are for PM reasons */
268         sdev->first_boot = false;
269
270         /* now register audio DSP platform driver and dai */
271         ret = devm_snd_soc_register_component(sdev->dev, &sdev->plat_drv,
272                                               sof_ops(sdev)->drv,
273                                               sof_ops(sdev)->num_drv);
274         if (ret < 0) {
275                 dev_err(sdev->dev,
276                         "error: failed to register DSP DAI driver %d\n", ret);
277                 goto fw_trace_err;
278         }
279
280         ret = snd_sof_machine_register(sdev, plat_data);
281         if (ret < 0) {
282                 dev_err(sdev->dev,
283                         "error: failed to register machine driver %d\n", ret);
284                 goto fw_trace_err;
285         }
286
287         ret = sof_register_clients(sdev);
288         if (ret < 0) {
289                 dev_err(sdev->dev, "failed to register clients %d\n", ret);
290                 goto sof_machine_err;
291         }
292
293         /*
294          * Some platforms in SOF, ex: BYT, may not have their platform PM
295          * callbacks set. Increment the usage count so as to
296          * prevent the device from entering runtime suspend.
297          */
298         if (!sof_ops(sdev)->runtime_suspend || !sof_ops(sdev)->runtime_resume)
299                 pm_runtime_get_noresume(sdev->dev);
300
301         if (plat_data->sof_probe_complete)
302                 plat_data->sof_probe_complete(sdev->dev);
303
304         sdev->probe_completed = true;
305
306         return 0;
307
308 sof_machine_err:
309         snd_sof_machine_unregister(sdev, plat_data);
310 fw_trace_err:
311         snd_sof_free_trace(sdev);
312 fw_run_err:
313         snd_sof_fw_unload(sdev);
314 fw_load_err:
315         snd_sof_ipc_free(sdev);
316 ipc_err:
317 dbg_err:
318         snd_sof_free_debug(sdev);
319 dsp_err:
320         snd_sof_remove(sdev);
321
322         /* all resources freed, update state to match */
323         sof_set_fw_state(sdev, SOF_FW_BOOT_NOT_STARTED);
324         sdev->first_boot = true;
325
326         return ret;
327 }
328
329 static void sof_probe_work(struct work_struct *work)
330 {
331         struct snd_sof_dev *sdev =
332                 container_of(work, struct snd_sof_dev, probe_work);
333         int ret;
334
335         ret = sof_probe_continue(sdev);
336         if (ret < 0) {
337                 /* errors cannot be propagated, log */
338                 dev_err(sdev->dev, "error: %s failed err: %d\n", __func__, ret);
339         }
340 }
341
342 int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data)
343 {
344         struct snd_sof_dev *sdev;
345         int ret;
346
347         sdev = devm_kzalloc(dev, sizeof(*sdev), GFP_KERNEL);
348         if (!sdev)
349                 return -ENOMEM;
350
351         /* initialize sof device */
352         sdev->dev = dev;
353
354         /* initialize default DSP power state */
355         sdev->dsp_power_state.state = SOF_DSP_PM_D0;
356
357         sdev->pdata = plat_data;
358         sdev->first_boot = true;
359         dev_set_drvdata(dev, sdev);
360
361         /* check IPC support */
362         if (!(BIT(plat_data->ipc_type) & plat_data->desc->ipc_supported_mask)) {
363                 dev_err(dev, "ipc_type %d is not supported on this platform, mask is %#x\n",
364                         plat_data->ipc_type, plat_data->desc->ipc_supported_mask);
365                 return -EINVAL;
366         }
367
368         /* init ops, if necessary */
369         ret = sof_ops_init(sdev);
370         if (ret < 0)
371                 return ret;
372
373         /* check all mandatory ops */
374         if (!sof_ops(sdev) || !sof_ops(sdev)->probe || !sof_ops(sdev)->run ||
375             !sof_ops(sdev)->block_read || !sof_ops(sdev)->block_write ||
376             !sof_ops(sdev)->send_msg || !sof_ops(sdev)->load_firmware ||
377             !sof_ops(sdev)->ipc_msg_data) {
378                 dev_err(dev, "error: missing mandatory ops\n");
379                 return -EINVAL;
380         }
381
382         INIT_LIST_HEAD(&sdev->pcm_list);
383         INIT_LIST_HEAD(&sdev->kcontrol_list);
384         INIT_LIST_HEAD(&sdev->widget_list);
385         INIT_LIST_HEAD(&sdev->dai_list);
386         INIT_LIST_HEAD(&sdev->dai_link_list);
387         INIT_LIST_HEAD(&sdev->route_list);
388         INIT_LIST_HEAD(&sdev->ipc_client_list);
389         INIT_LIST_HEAD(&sdev->ipc_rx_handler_list);
390         INIT_LIST_HEAD(&sdev->fw_state_handler_list);
391         spin_lock_init(&sdev->ipc_lock);
392         spin_lock_init(&sdev->hw_lock);
393         mutex_init(&sdev->power_state_access);
394         mutex_init(&sdev->ipc_client_mutex);
395         mutex_init(&sdev->client_event_handler_mutex);
396
397         /* set default timeouts if none provided */
398         if (plat_data->desc->ipc_timeout == 0)
399                 sdev->ipc_timeout = TIMEOUT_DEFAULT_IPC_MS;
400         else
401                 sdev->ipc_timeout = plat_data->desc->ipc_timeout;
402         if (plat_data->desc->boot_timeout == 0)
403                 sdev->boot_timeout = TIMEOUT_DEFAULT_BOOT_MS;
404         else
405                 sdev->boot_timeout = plat_data->desc->boot_timeout;
406
407         sof_set_fw_state(sdev, SOF_FW_BOOT_NOT_STARTED);
408
409         if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)) {
410                 INIT_WORK(&sdev->probe_work, sof_probe_work);
411                 schedule_work(&sdev->probe_work);
412                 return 0;
413         }
414
415         return sof_probe_continue(sdev);
416 }
417 EXPORT_SYMBOL(snd_sof_device_probe);
418
419 bool snd_sof_device_probe_completed(struct device *dev)
420 {
421         struct snd_sof_dev *sdev = dev_get_drvdata(dev);
422
423         return sdev->probe_completed;
424 }
425 EXPORT_SYMBOL(snd_sof_device_probe_completed);
426
427 int snd_sof_device_remove(struct device *dev)
428 {
429         struct snd_sof_dev *sdev = dev_get_drvdata(dev);
430         struct snd_sof_pdata *pdata = sdev->pdata;
431         int ret;
432
433         if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE))
434                 cancel_work_sync(&sdev->probe_work);
435
436         /*
437          * Unregister any registered client device first before IPC and debugfs
438          * to allow client drivers to be removed cleanly
439          */
440         sof_unregister_clients(sdev);
441
442         /*
443          * Unregister machine driver. This will unbind the snd_card which
444          * will remove the component driver and unload the topology
445          * before freeing the snd_card.
446          */
447         snd_sof_machine_unregister(sdev, pdata);
448
449         if (sdev->fw_state > SOF_FW_BOOT_NOT_STARTED) {
450                 snd_sof_free_trace(sdev);
451                 ret = snd_sof_dsp_power_down_notify(sdev);
452                 if (ret < 0)
453                         dev_warn(dev, "error: %d failed to prepare DSP for device removal",
454                                  ret);
455
456                 snd_sof_ipc_free(sdev);
457                 snd_sof_free_debug(sdev);
458                 snd_sof_remove(sdev);
459         }
460
461         /* release firmware */
462         snd_sof_fw_unload(sdev);
463
464         return 0;
465 }
466 EXPORT_SYMBOL(snd_sof_device_remove);
467
468 int snd_sof_device_shutdown(struct device *dev)
469 {
470         struct snd_sof_dev *sdev = dev_get_drvdata(dev);
471         struct snd_sof_pdata *pdata = sdev->pdata;
472
473         if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE))
474                 cancel_work_sync(&sdev->probe_work);
475
476         /*
477          * make sure clients and machine driver(s) are unregistered to force
478          * all userspace devices to be closed prior to the DSP shutdown sequence
479          */
480         sof_unregister_clients(sdev);
481
482         snd_sof_machine_unregister(sdev, pdata);
483
484         if (sdev->fw_state == SOF_FW_BOOT_COMPLETE)
485                 return snd_sof_shutdown(sdev);
486
487         return 0;
488 }
489 EXPORT_SYMBOL(snd_sof_device_shutdown);
490
491 MODULE_AUTHOR("Liam Girdwood");
492 MODULE_DESCRIPTION("Sound Open Firmware (SOF) Core");
493 MODULE_LICENSE("Dual BSD/GPL");
494 MODULE_ALIAS("platform:sof-audio");
495 MODULE_IMPORT_NS(SND_SOC_SOF_CLIENT);