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
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 "sof-of-dev.h"
17  #include "ops.h"
18  
19  #define CREATE_TRACE_POINTS
20  #include <trace/events/sof.h>
21  
22  /* see SOF_DBG_ flags */
23  static int sof_core_debug =  IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_FIRMWARE_TRACE);
24  module_param_named(sof_debug, sof_core_debug, int, 0444);
25  MODULE_PARM_DESC(sof_debug, "SOF core debug options (0x0 all off)");
26  
27  /* SOF defaults if not provided by the platform in ms */
28  #define TIMEOUT_DEFAULT_IPC_MS  500
29  #define TIMEOUT_DEFAULT_BOOT_MS 2000
30  
31  /**
32   * sof_debug_check_flag - check if a given flag(s) is set in sof_core_debug
33   * @mask: Flag or combination of flags to check
34   *
35   * Returns true if all bits set in mask is also set in sof_core_debug, otherwise
36   * false
37   */
sof_debug_check_flag(int mask)38  bool sof_debug_check_flag(int mask)
39  {
40  	if ((sof_core_debug & mask) == mask)
41  		return true;
42  
43  	return false;
44  }
45  EXPORT_SYMBOL(sof_debug_check_flag);
46  
47  /*
48   * FW Panic/fault handling.
49   */
50  
51  struct sof_panic_msg {
52  	u32 id;
53  	const char *msg;
54  };
55  
56  /* standard FW panic types */
57  static const struct sof_panic_msg panic_msg[] = {
58  	{SOF_IPC_PANIC_MEM, "out of memory"},
59  	{SOF_IPC_PANIC_WORK, "work subsystem init failed"},
60  	{SOF_IPC_PANIC_IPC, "IPC subsystem init failed"},
61  	{SOF_IPC_PANIC_ARCH, "arch init failed"},
62  	{SOF_IPC_PANIC_PLATFORM, "platform init failed"},
63  	{SOF_IPC_PANIC_TASK, "scheduler init failed"},
64  	{SOF_IPC_PANIC_EXCEPTION, "runtime exception"},
65  	{SOF_IPC_PANIC_DEADLOCK, "deadlock"},
66  	{SOF_IPC_PANIC_STACK, "stack overflow"},
67  	{SOF_IPC_PANIC_IDLE, "can't enter idle"},
68  	{SOF_IPC_PANIC_WFI, "invalid wait state"},
69  	{SOF_IPC_PANIC_ASSERT, "assertion failed"},
70  };
71  
72  /**
73   * sof_print_oops_and_stack - Handle the printing of DSP oops and stack trace
74   * @sdev: Pointer to the device's sdev
75   * @level: prink log level to use for the printing
76   * @panic_code: the panic code
77   * @tracep_code: tracepoint code
78   * @oops: Pointer to DSP specific oops data
79   * @panic_info: Pointer to the received panic information message
80   * @stack: Pointer to the call stack data
81   * @stack_words: Number of words in the stack data
82   *
83   * helper to be called from .dbg_dump callbacks. No error code is
84   * provided, it's left as an exercise for the caller of .dbg_dump
85   * (typically IPC or loader)
86   */
sof_print_oops_and_stack(struct snd_sof_dev * sdev,const char * level,u32 panic_code,u32 tracep_code,void * oops,struct sof_ipc_panic_info * panic_info,void * stack,size_t stack_words)87  void sof_print_oops_and_stack(struct snd_sof_dev *sdev, const char *level,
88  			      u32 panic_code, u32 tracep_code, void *oops,
89  			      struct sof_ipc_panic_info *panic_info,
90  			      void *stack, size_t stack_words)
91  {
92  	u32 code;
93  	int i;
94  
95  	/* is firmware dead ? */
96  	if ((panic_code & SOF_IPC_PANIC_MAGIC_MASK) != SOF_IPC_PANIC_MAGIC) {
97  		dev_printk(level, sdev->dev, "unexpected fault %#010x trace %#010x\n",
98  			   panic_code, tracep_code);
99  		return; /* no fault ? */
100  	}
101  
102  	code = panic_code & (SOF_IPC_PANIC_MAGIC_MASK | SOF_IPC_PANIC_CODE_MASK);
103  
104  	for (i = 0; i < ARRAY_SIZE(panic_msg); i++) {
105  		if (panic_msg[i].id == code) {
106  			dev_printk(level, sdev->dev, "reason: %s (%#x)\n",
107  				   panic_msg[i].msg, code & SOF_IPC_PANIC_CODE_MASK);
108  			dev_printk(level, sdev->dev, "trace point: %#010x\n", tracep_code);
109  			goto out;
110  		}
111  	}
112  
113  	/* unknown error */
114  	dev_printk(level, sdev->dev, "unknown panic code: %#x\n",
115  		   code & SOF_IPC_PANIC_CODE_MASK);
116  	dev_printk(level, sdev->dev, "trace point: %#010x\n", tracep_code);
117  
118  out:
119  	dev_printk(level, sdev->dev, "panic at %s:%d\n", panic_info->filename,
120  		   panic_info->linenum);
121  	sof_oops(sdev, level, oops);
122  	sof_stack(sdev, level, oops, stack, stack_words);
123  }
124  EXPORT_SYMBOL(sof_print_oops_and_stack);
125  
126  /* Helper to manage DSP state */
sof_set_fw_state(struct snd_sof_dev * sdev,enum sof_fw_state new_state)127  void sof_set_fw_state(struct snd_sof_dev *sdev, enum sof_fw_state new_state)
128  {
129  	if (sdev->fw_state == new_state)
130  		return;
131  
132  	dev_dbg(sdev->dev, "fw_state change: %d -> %d\n", sdev->fw_state, new_state);
133  	sdev->fw_state = new_state;
134  
135  	switch (new_state) {
136  	case SOF_FW_BOOT_NOT_STARTED:
137  	case SOF_FW_BOOT_COMPLETE:
138  	case SOF_FW_CRASHED:
139  		sof_client_fw_state_dispatcher(sdev);
140  		fallthrough;
141  	default:
142  		break;
143  	}
144  }
145  EXPORT_SYMBOL(sof_set_fw_state);
146  
sof_of_machine_select(struct snd_sof_dev * sdev)147  static struct snd_sof_of_mach *sof_of_machine_select(struct snd_sof_dev *sdev)
148  {
149  	struct snd_sof_pdata *sof_pdata = sdev->pdata;
150  	const struct sof_dev_desc *desc = sof_pdata->desc;
151  	struct snd_sof_of_mach *mach = desc->of_machines;
152  
153  	if (!mach)
154  		return NULL;
155  
156  	for (; mach->compatible; mach++) {
157  		if (of_machine_is_compatible(mach->compatible)) {
158  			sof_pdata->tplg_filename = mach->sof_tplg_filename;
159  			if (mach->fw_filename)
160  				sof_pdata->fw_filename = mach->fw_filename;
161  
162  			return mach;
163  		}
164  	}
165  
166  	return NULL;
167  }
168  
169  /* SOF Driver enumeration */
sof_machine_check(struct snd_sof_dev * sdev)170  static int sof_machine_check(struct snd_sof_dev *sdev)
171  {
172  	struct snd_sof_pdata *sof_pdata = sdev->pdata;
173  	const struct sof_dev_desc *desc = sof_pdata->desc;
174  	struct snd_soc_acpi_mach *mach;
175  
176  	if (!IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE)) {
177  		const struct snd_sof_of_mach *of_mach;
178  
179  		if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
180  		    sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
181  			goto nocodec;
182  
183  		/* find machine */
184  		mach = snd_sof_machine_select(sdev);
185  		if (mach) {
186  			sof_pdata->machine = mach;
187  
188  			if (sof_pdata->subsystem_id_set) {
189  				mach->mach_params.subsystem_vendor = sof_pdata->subsystem_vendor;
190  				mach->mach_params.subsystem_device = sof_pdata->subsystem_device;
191  				mach->mach_params.subsystem_id_set = true;
192  			}
193  
194  			snd_sof_set_mach_params(mach, sdev);
195  			return 0;
196  		}
197  
198  		of_mach = sof_of_machine_select(sdev);
199  		if (of_mach) {
200  			sof_pdata->of_machine = of_mach;
201  			return 0;
202  		}
203  
204  		if (!IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC)) {
205  			dev_err(sdev->dev, "error: no matching ASoC machine driver found - aborting probe\n");
206  			return -ENODEV;
207  		}
208  	} else {
209  		dev_warn(sdev->dev, "Force to use nocodec mode\n");
210  	}
211  
212  nocodec:
213  	/* select nocodec mode */
214  	dev_warn(sdev->dev, "Using nocodec machine driver\n");
215  	mach = devm_kzalloc(sdev->dev, sizeof(*mach), GFP_KERNEL);
216  	if (!mach)
217  		return -ENOMEM;
218  
219  	mach->drv_name = "sof-nocodec";
220  	if (!sof_pdata->tplg_filename)
221  		sof_pdata->tplg_filename = desc->nocodec_tplg_filename;
222  
223  	sof_pdata->machine = mach;
224  	snd_sof_set_mach_params(mach, sdev);
225  
226  	return 0;
227  }
228  
sof_select_ipc_and_paths(struct snd_sof_dev * sdev)229  static int sof_select_ipc_and_paths(struct snd_sof_dev *sdev)
230  {
231  	struct snd_sof_pdata *plat_data = sdev->pdata;
232  	struct sof_loadable_file_profile *base_profile = &plat_data->ipc_file_profile_base;
233  	struct sof_loadable_file_profile out_profile;
234  	struct device *dev = sdev->dev;
235  	int ret;
236  
237  	if (base_profile->ipc_type != plat_data->desc->ipc_default)
238  		dev_info(dev,
239  			 "Module parameter used, overriding default IPC %d to %d\n",
240  			 plat_data->desc->ipc_default, base_profile->ipc_type);
241  
242  	if (base_profile->fw_path)
243  		dev_dbg(dev, "Module parameter used, changed fw path to %s\n",
244  			base_profile->fw_path);
245  	else if (base_profile->fw_path_postfix)
246  		dev_dbg(dev, "Path postfix appended to default fw path: %s\n",
247  			base_profile->fw_path_postfix);
248  
249  	if (base_profile->fw_lib_path)
250  		dev_dbg(dev, "Module parameter used, changed fw_lib path to %s\n",
251  			base_profile->fw_lib_path);
252  	else if (base_profile->fw_lib_path_postfix)
253  		dev_dbg(dev, "Path postfix appended to default fw_lib path: %s\n",
254  			base_profile->fw_lib_path_postfix);
255  
256  	if (base_profile->fw_name)
257  		dev_dbg(dev, "Module parameter used, changed fw filename to %s\n",
258  			base_profile->fw_name);
259  
260  	if (base_profile->tplg_path)
261  		dev_dbg(dev, "Module parameter used, changed tplg path to %s\n",
262  			base_profile->tplg_path);
263  
264  	if (base_profile->tplg_name)
265  		dev_dbg(dev, "Module parameter used, changed tplg name to %s\n",
266  			base_profile->tplg_name);
267  
268  	ret = sof_create_ipc_file_profile(sdev, base_profile, &out_profile);
269  	if (ret)
270  		return ret;
271  
272  	plat_data->ipc_type = out_profile.ipc_type;
273  	plat_data->fw_filename = out_profile.fw_name;
274  	plat_data->fw_filename_prefix = out_profile.fw_path;
275  	plat_data->fw_lib_prefix = out_profile.fw_lib_path;
276  	plat_data->tplg_filename_prefix = out_profile.tplg_path;
277  
278  	return 0;
279  }
280  
validate_sof_ops(struct snd_sof_dev * sdev)281  static int validate_sof_ops(struct snd_sof_dev *sdev)
282  {
283  	int ret;
284  
285  	/* init ops, if necessary */
286  	ret = sof_ops_init(sdev);
287  	if (ret < 0)
288  		return ret;
289  
290  	/* check all mandatory ops */
291  	if (!sof_ops(sdev) || !sof_ops(sdev)->probe) {
292  		dev_err(sdev->dev, "missing mandatory ops\n");
293  		sof_ops_free(sdev);
294  		return -EINVAL;
295  	}
296  
297  	if (!sdev->dspless_mode_selected &&
298  	    (!sof_ops(sdev)->run || !sof_ops(sdev)->block_read ||
299  	     !sof_ops(sdev)->block_write || !sof_ops(sdev)->send_msg ||
300  	     !sof_ops(sdev)->load_firmware || !sof_ops(sdev)->ipc_msg_data)) {
301  		dev_err(sdev->dev, "missing mandatory DSP ops\n");
302  		sof_ops_free(sdev);
303  		return -EINVAL;
304  	}
305  
306  	return 0;
307  }
308  
sof_init_sof_ops(struct snd_sof_dev * sdev)309  static int sof_init_sof_ops(struct snd_sof_dev *sdev)
310  {
311  	struct snd_sof_pdata *plat_data = sdev->pdata;
312  	struct sof_loadable_file_profile *base_profile = &plat_data->ipc_file_profile_base;
313  
314  	/* check IPC support */
315  	if (!(BIT(base_profile->ipc_type) & plat_data->desc->ipc_supported_mask)) {
316  		dev_err(sdev->dev,
317  			"ipc_type %d is not supported on this platform, mask is %#x\n",
318  			base_profile->ipc_type, plat_data->desc->ipc_supported_mask);
319  		return -EINVAL;
320  	}
321  
322  	/*
323  	 * Save the selected IPC type and a topology name override before
324  	 * selecting ops since platform code might need this information
325  	 */
326  	plat_data->ipc_type = base_profile->ipc_type;
327  	plat_data->tplg_filename = base_profile->tplg_name;
328  
329  	return validate_sof_ops(sdev);
330  }
331  
sof_init_environment(struct snd_sof_dev * sdev)332  static int sof_init_environment(struct snd_sof_dev *sdev)
333  {
334  	struct snd_sof_pdata *plat_data = sdev->pdata;
335  	struct sof_loadable_file_profile *base_profile = &plat_data->ipc_file_profile_base;
336  	int ret;
337  
338  	/* probe the DSP hardware */
339  	ret = snd_sof_probe(sdev);
340  	if (ret < 0) {
341  		dev_err(sdev->dev, "failed to probe DSP %d\n", ret);
342  		goto err_sof_probe;
343  	}
344  
345  	/* check machine info */
346  	ret = sof_machine_check(sdev);
347  	if (ret < 0) {
348  		dev_err(sdev->dev, "failed to get machine info %d\n", ret);
349  		goto err_machine_check;
350  	}
351  
352  	ret = sof_select_ipc_and_paths(sdev);
353  	if (ret) {
354  		goto err_machine_check;
355  	} else if (plat_data->ipc_type != base_profile->ipc_type) {
356  		/* IPC type changed, re-initialize the ops */
357  		sof_ops_free(sdev);
358  
359  		ret = validate_sof_ops(sdev);
360  		if (ret < 0) {
361  			snd_sof_remove(sdev);
362  			snd_sof_remove_late(sdev);
363  			return ret;
364  		}
365  	}
366  
367  	return 0;
368  
369  err_machine_check:
370  	snd_sof_remove(sdev);
371  err_sof_probe:
372  	snd_sof_remove_late(sdev);
373  	sof_ops_free(sdev);
374  
375  	return ret;
376  }
377  
378  /*
379   *			FW Boot State Transition Diagram
380   *
381   *    +----------------------------------------------------------------------+
382   *    |									     |
383   * ------------------	     ------------------				     |
384   * |		    |	     |		      |				     |
385   * |   BOOT_FAILED  |<-------|  READY_FAILED  |				     |
386   * |		    |<--+    |	              |	   ------------------	     |
387   * ------------------	|    ------------------	   |		    |	     |
388   *	^		|	    ^		   |	CRASHED	    |---+    |
389   *	|		|	    |		   |		    |	|    |
390   * (FW Boot Timeout)	|	(FW_READY FAIL)	   ------------------	|    |
391   *	|		|	    |		     ^			|    |
392   *	|		|	    |		     |(DSP Panic)	|    |
393   * ------------------	|	    |		   ------------------	|    |
394   * |		    |	|	    |		   |		    |	|    |
395   * |   IN_PROGRESS  |---------------+------------->|    COMPLETE    |	|    |
396   * |		    | (FW Boot OK)   (FW_READY OK) |		    |	|    |
397   * ------------------	|			   ------------------	|    |
398   *	^		|				|		|    |
399   *	|		|				|		|    |
400   * (FW Loading OK)	|			(System Suspend/Runtime Suspend)
401   *	|		|				|		|    |
402   *	|	(FW Loading Fail)			|		|    |
403   * ------------------	|	------------------	|		|    |
404   * |		    |	|	|		 |<-----+		|    |
405   * |   PREPARE	    |---+	|   NOT_STARTED  |<---------------------+    |
406   * |		    |		|		 |<--------------------------+
407   * ------------------		------------------
408   *    |	    ^			    |	   ^
409   *    |	    |			    |	   |
410   *    |	    +-----------------------+	   |
411   *    |		(DSP Probe OK)		   |
412   *    |					   |
413   *    |					   |
414   *    +------------------------------------+
415   *	(System Suspend/Runtime Suspend)
416   */
417  
sof_probe_continue(struct snd_sof_dev * sdev)418  static int sof_probe_continue(struct snd_sof_dev *sdev)
419  {
420  	struct snd_sof_pdata *plat_data = sdev->pdata;
421  	int ret;
422  
423  	/* Initialize loadable file paths and check the environment validity */
424  	ret = sof_init_environment(sdev);
425  	if (ret)
426  		return ret;
427  
428  	sof_set_fw_state(sdev, SOF_FW_BOOT_PREPARE);
429  
430  	/* set up platform component driver */
431  	snd_sof_new_platform_drv(sdev);
432  
433  	if (sdev->dspless_mode_selected) {
434  		sof_set_fw_state(sdev, SOF_DSPLESS_MODE);
435  		goto skip_dsp_init;
436  	}
437  
438  	/* register any debug/trace capabilities */
439  	ret = snd_sof_dbg_init(sdev);
440  	if (ret < 0) {
441  		/*
442  		 * debugfs issues are suppressed in snd_sof_dbg_init() since
443  		 * we cannot rely on debugfs
444  		 * here we trap errors due to memory allocation only.
445  		 */
446  		dev_err(sdev->dev, "error: failed to init DSP trace/debug %d\n",
447  			ret);
448  		goto dbg_err;
449  	}
450  
451  	/* init the IPC */
452  	sdev->ipc = snd_sof_ipc_init(sdev);
453  	if (!sdev->ipc) {
454  		ret = -ENOMEM;
455  		dev_err(sdev->dev, "error: failed to init DSP IPC %d\n", ret);
456  		goto ipc_err;
457  	}
458  
459  	/* load the firmware */
460  	ret = snd_sof_load_firmware(sdev);
461  	if (ret < 0) {
462  		dev_err(sdev->dev, "error: failed to load DSP firmware %d\n",
463  			ret);
464  		sof_set_fw_state(sdev, SOF_FW_BOOT_FAILED);
465  		goto fw_load_err;
466  	}
467  
468  	sof_set_fw_state(sdev, SOF_FW_BOOT_IN_PROGRESS);
469  
470  	/*
471  	 * Boot the firmware. The FW boot status will be modified
472  	 * in snd_sof_run_firmware() depending on the outcome.
473  	 */
474  	ret = snd_sof_run_firmware(sdev);
475  	if (ret < 0) {
476  		dev_err(sdev->dev, "error: failed to boot DSP firmware %d\n",
477  			ret);
478  		sof_set_fw_state(sdev, SOF_FW_BOOT_FAILED);
479  		goto fw_run_err;
480  	}
481  
482  	if (sof_debug_check_flag(SOF_DBG_ENABLE_TRACE)) {
483  		sdev->fw_trace_is_supported = true;
484  
485  		/* init firmware tracing */
486  		ret = sof_fw_trace_init(sdev);
487  		if (ret < 0) {
488  			/* non fatal */
489  			dev_warn(sdev->dev, "failed to initialize firmware tracing %d\n",
490  				 ret);
491  		}
492  	} else {
493  		dev_dbg(sdev->dev, "SOF firmware trace disabled\n");
494  	}
495  
496  skip_dsp_init:
497  	/* hereafter all FW boot flows are for PM reasons */
498  	sdev->first_boot = false;
499  
500  	/* now register audio DSP platform driver and dai */
501  	ret = devm_snd_soc_register_component(sdev->dev, &sdev->plat_drv,
502  					      sof_ops(sdev)->drv,
503  					      sof_ops(sdev)->num_drv);
504  	if (ret < 0) {
505  		dev_err(sdev->dev,
506  			"error: failed to register DSP DAI driver %d\n", ret);
507  		goto fw_trace_err;
508  	}
509  
510  	ret = snd_sof_machine_register(sdev, plat_data);
511  	if (ret < 0) {
512  		dev_err(sdev->dev,
513  			"error: failed to register machine driver %d\n", ret);
514  		goto fw_trace_err;
515  	}
516  
517  	ret = sof_register_clients(sdev);
518  	if (ret < 0) {
519  		dev_err(sdev->dev, "failed to register clients %d\n", ret);
520  		goto sof_machine_err;
521  	}
522  
523  	/*
524  	 * Some platforms in SOF, ex: BYT, may not have their platform PM
525  	 * callbacks set. Increment the usage count so as to
526  	 * prevent the device from entering runtime suspend.
527  	 */
528  	if (!sof_ops(sdev)->runtime_suspend || !sof_ops(sdev)->runtime_resume)
529  		pm_runtime_get_noresume(sdev->dev);
530  
531  	if (plat_data->sof_probe_complete)
532  		plat_data->sof_probe_complete(sdev->dev);
533  
534  	sdev->probe_completed = true;
535  
536  	return 0;
537  
538  sof_machine_err:
539  	snd_sof_machine_unregister(sdev, plat_data);
540  fw_trace_err:
541  	sof_fw_trace_free(sdev);
542  fw_run_err:
543  	snd_sof_fw_unload(sdev);
544  fw_load_err:
545  	snd_sof_ipc_free(sdev);
546  ipc_err:
547  dbg_err:
548  	snd_sof_free_debug(sdev);
549  	snd_sof_remove(sdev);
550  	snd_sof_remove_late(sdev);
551  	sof_ops_free(sdev);
552  
553  	/* all resources freed, update state to match */
554  	sof_set_fw_state(sdev, SOF_FW_BOOT_NOT_STARTED);
555  	sdev->first_boot = true;
556  
557  	return ret;
558  }
559  
sof_probe_work(struct work_struct * work)560  static void sof_probe_work(struct work_struct *work)
561  {
562  	struct snd_sof_dev *sdev =
563  		container_of(work, struct snd_sof_dev, probe_work);
564  	int ret;
565  
566  	ret = sof_probe_continue(sdev);
567  	if (ret < 0) {
568  		/* errors cannot be propagated, log */
569  		dev_err(sdev->dev, "error: %s failed err: %d\n", __func__, ret);
570  	}
571  }
572  
snd_sof_device_probe(struct device * dev,struct snd_sof_pdata * plat_data)573  int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data)
574  {
575  	struct snd_sof_dev *sdev;
576  	int ret;
577  
578  	sdev = devm_kzalloc(dev, sizeof(*sdev), GFP_KERNEL);
579  	if (!sdev)
580  		return -ENOMEM;
581  
582  	/* initialize sof device */
583  	sdev->dev = dev;
584  
585  	/* initialize default DSP power state */
586  	sdev->dsp_power_state.state = SOF_DSP_PM_D0;
587  
588  	sdev->pdata = plat_data;
589  	sdev->first_boot = true;
590  	dev_set_drvdata(dev, sdev);
591  
592  	if (sof_core_debug)
593  		dev_info(dev, "sof_debug value: %#x\n", sof_core_debug);
594  
595  	if (sof_debug_check_flag(SOF_DBG_DSPLESS_MODE)) {
596  		if (plat_data->desc->dspless_mode_supported) {
597  			dev_info(dev, "Switching to DSPless mode\n");
598  			sdev->dspless_mode_selected = true;
599  		} else {
600  			dev_info(dev, "DSPless mode is not supported by the platform\n");
601  		}
602  	}
603  
604  	/* Initialize sof_ops based on the initial selected IPC version */
605  	ret = sof_init_sof_ops(sdev);
606  	if (ret)
607  		return ret;
608  
609  	INIT_LIST_HEAD(&sdev->pcm_list);
610  	INIT_LIST_HEAD(&sdev->kcontrol_list);
611  	INIT_LIST_HEAD(&sdev->widget_list);
612  	INIT_LIST_HEAD(&sdev->pipeline_list);
613  	INIT_LIST_HEAD(&sdev->dai_list);
614  	INIT_LIST_HEAD(&sdev->dai_link_list);
615  	INIT_LIST_HEAD(&sdev->route_list);
616  	INIT_LIST_HEAD(&sdev->ipc_client_list);
617  	INIT_LIST_HEAD(&sdev->ipc_rx_handler_list);
618  	INIT_LIST_HEAD(&sdev->fw_state_handler_list);
619  	spin_lock_init(&sdev->ipc_lock);
620  	spin_lock_init(&sdev->hw_lock);
621  	mutex_init(&sdev->power_state_access);
622  	mutex_init(&sdev->ipc_client_mutex);
623  	mutex_init(&sdev->client_event_handler_mutex);
624  
625  	/* set default timeouts if none provided */
626  	if (plat_data->desc->ipc_timeout == 0)
627  		sdev->ipc_timeout = TIMEOUT_DEFAULT_IPC_MS;
628  	else
629  		sdev->ipc_timeout = plat_data->desc->ipc_timeout;
630  	if (plat_data->desc->boot_timeout == 0)
631  		sdev->boot_timeout = TIMEOUT_DEFAULT_BOOT_MS;
632  	else
633  		sdev->boot_timeout = plat_data->desc->boot_timeout;
634  
635  	sof_set_fw_state(sdev, SOF_FW_BOOT_NOT_STARTED);
636  
637  	/*
638  	 * first pass of probe which isn't allowed to run in a work-queue,
639  	 * typically to rely on -EPROBE_DEFER dependencies
640  	 */
641  	ret = snd_sof_probe_early(sdev);
642  	if (ret < 0)
643  		return ret;
644  
645  	if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)) {
646  		INIT_WORK(&sdev->probe_work, sof_probe_work);
647  		schedule_work(&sdev->probe_work);
648  		return 0;
649  	}
650  
651  	return sof_probe_continue(sdev);
652  }
653  EXPORT_SYMBOL(snd_sof_device_probe);
654  
snd_sof_device_probe_completed(struct device * dev)655  bool snd_sof_device_probe_completed(struct device *dev)
656  {
657  	struct snd_sof_dev *sdev = dev_get_drvdata(dev);
658  
659  	return sdev->probe_completed;
660  }
661  EXPORT_SYMBOL(snd_sof_device_probe_completed);
662  
snd_sof_device_remove(struct device * dev)663  int snd_sof_device_remove(struct device *dev)
664  {
665  	struct snd_sof_dev *sdev = dev_get_drvdata(dev);
666  	struct snd_sof_pdata *pdata = sdev->pdata;
667  	int ret;
668  	bool aborted = false;
669  
670  	if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE))
671  		aborted = cancel_work_sync(&sdev->probe_work);
672  
673  	/*
674  	 * Unregister any registered client device first before IPC and debugfs
675  	 * to allow client drivers to be removed cleanly
676  	 */
677  	sof_unregister_clients(sdev);
678  
679  	/*
680  	 * Unregister machine driver. This will unbind the snd_card which
681  	 * will remove the component driver and unload the topology
682  	 * before freeing the snd_card.
683  	 */
684  	snd_sof_machine_unregister(sdev, pdata);
685  
686  	/*
687  	 * Balance the runtime pm usage count in case we are faced with an
688  	 * exception and we forcably prevented D3 power state to preserve
689  	 * context
690  	 */
691  	if (sdev->d3_prevented) {
692  		sdev->d3_prevented = false;
693  		pm_runtime_put_noidle(sdev->dev);
694  	}
695  
696  	if (sdev->fw_state > SOF_FW_BOOT_NOT_STARTED) {
697  		sof_fw_trace_free(sdev);
698  		ret = snd_sof_dsp_power_down_notify(sdev);
699  		if (ret < 0)
700  			dev_warn(dev, "error: %d failed to prepare DSP for device removal",
701  				 ret);
702  
703  		snd_sof_ipc_free(sdev);
704  		snd_sof_free_debug(sdev);
705  		snd_sof_remove(sdev);
706  		snd_sof_remove_late(sdev);
707  		sof_ops_free(sdev);
708  	} else if (aborted) {
709  		/* probe_work never ran */
710  		snd_sof_remove_late(sdev);
711  		sof_ops_free(sdev);
712  	}
713  
714  	/* release firmware */
715  	snd_sof_fw_unload(sdev);
716  
717  	return 0;
718  }
719  EXPORT_SYMBOL(snd_sof_device_remove);
720  
snd_sof_device_shutdown(struct device * dev)721  int snd_sof_device_shutdown(struct device *dev)
722  {
723  	struct snd_sof_dev *sdev = dev_get_drvdata(dev);
724  
725  	if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE))
726  		cancel_work_sync(&sdev->probe_work);
727  
728  	if (sdev->fw_state == SOF_FW_BOOT_COMPLETE) {
729  		sof_fw_trace_free(sdev);
730  		return snd_sof_shutdown(sdev);
731  	}
732  
733  	return 0;
734  }
735  EXPORT_SYMBOL(snd_sof_device_shutdown);
736  
737  /* Machine driver registering and unregistering */
sof_machine_register(struct snd_sof_dev * sdev,void * pdata)738  int sof_machine_register(struct snd_sof_dev *sdev, void *pdata)
739  {
740  	struct snd_sof_pdata *plat_data = pdata;
741  	const char *drv_name;
742  	const void *mach;
743  	int size;
744  
745  	drv_name = plat_data->machine->drv_name;
746  	mach = plat_data->machine;
747  	size = sizeof(*plat_data->machine);
748  
749  	/* register machine driver, pass machine info as pdata */
750  	plat_data->pdev_mach =
751  		platform_device_register_data(sdev->dev, drv_name,
752  					      PLATFORM_DEVID_NONE, mach, size);
753  	if (IS_ERR(plat_data->pdev_mach))
754  		return PTR_ERR(plat_data->pdev_mach);
755  
756  	dev_dbg(sdev->dev, "created machine %s\n",
757  		dev_name(&plat_data->pdev_mach->dev));
758  
759  	return 0;
760  }
761  EXPORT_SYMBOL(sof_machine_register);
762  
sof_machine_unregister(struct snd_sof_dev * sdev,void * pdata)763  void sof_machine_unregister(struct snd_sof_dev *sdev, void *pdata)
764  {
765  	struct snd_sof_pdata *plat_data = pdata;
766  
767  	platform_device_unregister(plat_data->pdev_mach);
768  }
769  EXPORT_SYMBOL(sof_machine_unregister);
770  
771  MODULE_AUTHOR("Liam Girdwood");
772  MODULE_LICENSE("Dual BSD/GPL");
773  MODULE_DESCRIPTION("Sound Open Firmware (SOF) Core");
774  MODULE_ALIAS("platform:sof-audio");
775  MODULE_IMPORT_NS(SND_SOC_SOF_CLIENT);
776