Linux-libre 5.7.6-gnu
[librecmc/linux-libre.git] / sound / soc / sof / core.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
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 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES)
18 #include "probe.h"
19 #endif
20
21 /* see SOF_DBG_ flags */
22 int sof_core_debug;
23 module_param_named(sof_debug, sof_core_debug, int, 0444);
24 MODULE_PARM_DESC(sof_debug, "SOF core debug options (0x0 all off)");
25
26 /* SOF defaults if not provided by the platform in ms */
27 #define TIMEOUT_DEFAULT_IPC_MS  500
28 #define TIMEOUT_DEFAULT_BOOT_MS 2000
29
30 /*
31  * FW Panic/fault handling.
32  */
33
34 struct sof_panic_msg {
35         u32 id;
36         const char *msg;
37 };
38
39 /* standard FW panic types */
40 static const struct sof_panic_msg panic_msg[] = {
41         {SOF_IPC_PANIC_MEM, "out of memory"},
42         {SOF_IPC_PANIC_WORK, "work subsystem init failed"},
43         {SOF_IPC_PANIC_IPC, "IPC subsystem init failed"},
44         {SOF_IPC_PANIC_ARCH, "arch init failed"},
45         {SOF_IPC_PANIC_PLATFORM, "platform init failed"},
46         {SOF_IPC_PANIC_TASK, "scheduler init failed"},
47         {SOF_IPC_PANIC_EXCEPTION, "runtime exception"},
48         {SOF_IPC_PANIC_DEADLOCK, "deadlock"},
49         {SOF_IPC_PANIC_STACK, "stack overflow"},
50         {SOF_IPC_PANIC_IDLE, "can't enter idle"},
51         {SOF_IPC_PANIC_WFI, "invalid wait state"},
52         {SOF_IPC_PANIC_ASSERT, "assertion failed"},
53 };
54
55 /*
56  * helper to be called from .dbg_dump callbacks. No error code is
57  * provided, it's left as an exercise for the caller of .dbg_dump
58  * (typically IPC or loader)
59  */
60 void snd_sof_get_status(struct snd_sof_dev *sdev, u32 panic_code,
61                         u32 tracep_code, void *oops,
62                         struct sof_ipc_panic_info *panic_info,
63                         void *stack, size_t stack_words)
64 {
65         u32 code;
66         int i;
67
68         /* is firmware dead ? */
69         if ((panic_code & SOF_IPC_PANIC_MAGIC_MASK) != SOF_IPC_PANIC_MAGIC) {
70                 dev_err(sdev->dev, "error: unexpected fault 0x%8.8x trace 0x%8.8x\n",
71                         panic_code, tracep_code);
72                 return; /* no fault ? */
73         }
74
75         code = panic_code & (SOF_IPC_PANIC_MAGIC_MASK | SOF_IPC_PANIC_CODE_MASK);
76
77         for (i = 0; i < ARRAY_SIZE(panic_msg); i++) {
78                 if (panic_msg[i].id == code) {
79                         dev_err(sdev->dev, "error: %s\n", panic_msg[i].msg);
80                         dev_err(sdev->dev, "error: trace point %8.8x\n",
81                                 tracep_code);
82                         goto out;
83                 }
84         }
85
86         /* unknown error */
87         dev_err(sdev->dev, "error: unknown reason %8.8x\n", panic_code);
88         dev_err(sdev->dev, "error: trace point %8.8x\n", tracep_code);
89
90 out:
91         dev_err(sdev->dev, "error: panic at %s:%d\n",
92                 panic_info->filename, panic_info->linenum);
93         sof_oops(sdev, oops);
94         sof_stack(sdev, oops, stack, stack_words);
95 }
96 EXPORT_SYMBOL(snd_sof_get_status);
97
98 /*
99  *                      FW Boot State Transition Diagram
100  *
101  *    +-----------------------------------------------------------------------+
102  *    |                                                                       |
103  * ------------------        ------------------                               |
104  * |                |        |                |                               |
105  * |   BOOT_FAILED  |        |  READY_FAILED  |-------------------------+     |
106  * |                |        |                |                         |     |
107  * ------------------        ------------------                         |     |
108  *      ^                           ^                                   |     |
109  *      |                           |                                   |     |
110  * (FW Boot Timeout)            (FW_READY FAIL)                         |     |
111  *      |                           |                                   |     |
112  *      |                           |                                   |     |
113  * ------------------               |              ------------------   |     |
114  * |                |               |              |                |   |     |
115  * |   IN_PROGRESS  |---------------+------------->|    COMPLETE    |   |     |
116  * |                | (FW Boot OK)   (FW_READY OK) |                |   |     |
117  * ------------------                              ------------------   |     |
118  *      ^                                               |               |     |
119  *      |                                               |               |     |
120  * (FW Loading OK)                             (System Suspend/Runtime Suspend)
121  *      |                                               |               |     |
122  *      |                                               |               |     |
123  * ------------------           ------------------      |               |     |
124  * |                |           |                |<-----+               |     |
125  * |   PREPARE      |           |   NOT_STARTED  |<---------------------+     |
126  * |                |           |                |<---------------------------+
127  * ------------------           ------------------
128  *    |     ^                       |      ^
129  *    |     |                       |      |
130  *    |     +-----------------------+      |
131  *    |         (DSP Probe OK)             |
132  *    |                                    |
133  *    |                                    |
134  *    +------------------------------------+
135  *      (System Suspend/Runtime Suspend)
136  */
137
138 static int sof_probe_continue(struct snd_sof_dev *sdev)
139 {
140         struct snd_sof_pdata *plat_data = sdev->pdata;
141         int ret;
142
143         /* probe the DSP hardware */
144         ret = snd_sof_probe(sdev);
145         if (ret < 0) {
146                 dev_err(sdev->dev, "error: failed to probe DSP %d\n", ret);
147                 return ret;
148         }
149
150         sdev->fw_state = SOF_FW_BOOT_PREPARE;
151
152         /* check machine info */
153         ret = sof_machine_check(sdev);
154         if (ret < 0) {
155                 dev_err(sdev->dev, "error: failed to get machine info %d\n",
156                         ret);
157                 goto dbg_err;
158         }
159
160         /* set up platform component driver */
161         snd_sof_new_platform_drv(sdev);
162
163         /* register any debug/trace capabilities */
164         ret = snd_sof_dbg_init(sdev);
165         if (ret < 0) {
166                 /*
167                  * debugfs issues are suppressed in snd_sof_dbg_init() since
168                  * we cannot rely on debugfs
169                  * here we trap errors due to memory allocation only.
170                  */
171                 dev_err(sdev->dev, "error: failed to init DSP trace/debug %d\n",
172                         ret);
173                 goto dbg_err;
174         }
175
176         /* init the IPC */
177         sdev->ipc = snd_sof_ipc_init(sdev);
178         if (!sdev->ipc) {
179                 ret = -ENOMEM;
180                 dev_err(sdev->dev, "error: failed to init DSP IPC %d\n", ret);
181                 goto ipc_err;
182         }
183
184         /* load the firmware */
185         ret = snd_sof_load_firmware(sdev);
186         if (ret < 0) {
187                 dev_err(sdev->dev, "error: failed to load DSP firmware %d\n",
188                         ret);
189                 goto fw_load_err;
190         }
191
192         sdev->fw_state = SOF_FW_BOOT_IN_PROGRESS;
193
194         /*
195          * Boot the firmware. The FW boot status will be modified
196          * in snd_sof_run_firmware() depending on the outcome.
197          */
198         ret = snd_sof_run_firmware(sdev);
199         if (ret < 0) {
200                 dev_err(sdev->dev, "error: failed to boot DSP firmware %d\n",
201                         ret);
202                 goto fw_run_err;
203         }
204
205         if (IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_FIRMWARE_TRACE) ||
206             (sof_core_debug & SOF_DBG_ENABLE_TRACE)) {
207                 sdev->dtrace_is_supported = true;
208
209                 /* init DMA trace */
210                 ret = snd_sof_init_trace(sdev);
211                 if (ret < 0) {
212                         /* non fatal */
213                         dev_warn(sdev->dev,
214                                  "warning: failed to initialize trace %d\n",
215                                  ret);
216                 }
217         } else {
218                 dev_dbg(sdev->dev, "SOF firmware trace disabled\n");
219         }
220
221         /* hereafter all FW boot flows are for PM reasons */
222         sdev->first_boot = false;
223
224         /* now register audio DSP platform driver and dai */
225         ret = devm_snd_soc_register_component(sdev->dev, &sdev->plat_drv,
226                                               sof_ops(sdev)->drv,
227                                               sof_ops(sdev)->num_drv);
228         if (ret < 0) {
229                 dev_err(sdev->dev,
230                         "error: failed to register DSP DAI driver %d\n", ret);
231                 goto fw_trace_err;
232         }
233
234         ret = snd_sof_machine_register(sdev, plat_data);
235         if (ret < 0)
236                 goto fw_trace_err;
237
238         /*
239          * Some platforms in SOF, ex: BYT, may not have their platform PM
240          * callbacks set. Increment the usage count so as to
241          * prevent the device from entering runtime suspend.
242          */
243         if (!sof_ops(sdev)->runtime_suspend || !sof_ops(sdev)->runtime_resume)
244                 pm_runtime_get_noresume(sdev->dev);
245
246         if (plat_data->sof_probe_complete)
247                 plat_data->sof_probe_complete(sdev->dev);
248
249         return 0;
250
251 fw_trace_err:
252         snd_sof_free_trace(sdev);
253 fw_run_err:
254         snd_sof_fw_unload(sdev);
255 fw_load_err:
256         snd_sof_ipc_free(sdev);
257 ipc_err:
258         snd_sof_free_debug(sdev);
259 dbg_err:
260         snd_sof_remove(sdev);
261
262         /* all resources freed, update state to match */
263         sdev->fw_state = SOF_FW_BOOT_NOT_STARTED;
264         sdev->first_boot = true;
265
266         return ret;
267 }
268
269 static void sof_probe_work(struct work_struct *work)
270 {
271         struct snd_sof_dev *sdev =
272                 container_of(work, struct snd_sof_dev, probe_work);
273         int ret;
274
275         ret = sof_probe_continue(sdev);
276         if (ret < 0) {
277                 /* errors cannot be propagated, log */
278                 dev_err(sdev->dev, "error: %s failed err: %d\n", __func__, ret);
279         }
280 }
281
282 int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data)
283 {
284         struct snd_sof_dev *sdev;
285
286         sdev = devm_kzalloc(dev, sizeof(*sdev), GFP_KERNEL);
287         if (!sdev)
288                 return -ENOMEM;
289
290         /* initialize sof device */
291         sdev->dev = dev;
292
293         /* initialize default DSP power state */
294         sdev->dsp_power_state.state = SOF_DSP_PM_D0;
295
296         sdev->pdata = plat_data;
297         sdev->first_boot = true;
298         sdev->fw_state = SOF_FW_BOOT_NOT_STARTED;
299 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES)
300         sdev->extractor_stream_tag = SOF_PROBE_INVALID_NODE_ID;
301 #endif
302         dev_set_drvdata(dev, sdev);
303
304         /* check all mandatory ops */
305         if (!sof_ops(sdev) || !sof_ops(sdev)->probe || !sof_ops(sdev)->run ||
306             !sof_ops(sdev)->block_read || !sof_ops(sdev)->block_write ||
307             !sof_ops(sdev)->send_msg || !sof_ops(sdev)->load_firmware ||
308             !sof_ops(sdev)->ipc_msg_data || !sof_ops(sdev)->ipc_pcm_params ||
309             !sof_ops(sdev)->fw_ready)
310                 return -EINVAL;
311
312         INIT_LIST_HEAD(&sdev->pcm_list);
313         INIT_LIST_HEAD(&sdev->kcontrol_list);
314         INIT_LIST_HEAD(&sdev->widget_list);
315         INIT_LIST_HEAD(&sdev->dai_list);
316         INIT_LIST_HEAD(&sdev->route_list);
317         spin_lock_init(&sdev->ipc_lock);
318         spin_lock_init(&sdev->hw_lock);
319
320         if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE))
321                 INIT_WORK(&sdev->probe_work, sof_probe_work);
322
323         /* set default timeouts if none provided */
324         if (plat_data->desc->ipc_timeout == 0)
325                 sdev->ipc_timeout = TIMEOUT_DEFAULT_IPC_MS;
326         else
327                 sdev->ipc_timeout = plat_data->desc->ipc_timeout;
328         if (plat_data->desc->boot_timeout == 0)
329                 sdev->boot_timeout = TIMEOUT_DEFAULT_BOOT_MS;
330         else
331                 sdev->boot_timeout = plat_data->desc->boot_timeout;
332
333         if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)) {
334                 schedule_work(&sdev->probe_work);
335                 return 0;
336         }
337
338         return sof_probe_continue(sdev);
339 }
340 EXPORT_SYMBOL(snd_sof_device_probe);
341
342 int snd_sof_device_remove(struct device *dev)
343 {
344         struct snd_sof_dev *sdev = dev_get_drvdata(dev);
345         struct snd_sof_pdata *pdata = sdev->pdata;
346
347         if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE))
348                 cancel_work_sync(&sdev->probe_work);
349
350         if (sdev->fw_state > SOF_FW_BOOT_NOT_STARTED) {
351                 snd_sof_fw_unload(sdev);
352                 snd_sof_ipc_free(sdev);
353                 snd_sof_free_debug(sdev);
354                 snd_sof_free_trace(sdev);
355         }
356
357         /*
358          * Unregister machine driver. This will unbind the snd_card which
359          * will remove the component driver and unload the topology
360          * before freeing the snd_card.
361          */
362         snd_sof_machine_unregister(sdev, pdata);
363
364         /*
365          * Unregistering the machine driver results in unloading the topology.
366          * Some widgets, ex: scheduler, attempt to power down the core they are
367          * scheduled on, when they are unloaded. Therefore, the DSP must be
368          * removed only after the topology has been unloaded.
369          */
370         if (sdev->fw_state > SOF_FW_BOOT_NOT_STARTED)
371                 snd_sof_remove(sdev);
372
373         /* release firmware */
374         release_firmware(pdata->fw);
375         pdata->fw = NULL;
376
377         return 0;
378 }
379 EXPORT_SYMBOL(snd_sof_device_remove);
380
381 MODULE_AUTHOR("Liam Girdwood");
382 MODULE_DESCRIPTION("Sound Open Firmware (SOF) Core");
383 MODULE_LICENSE("Dual BSD/GPL");
384 MODULE_ALIAS("platform:sof-audio");