xref: /linux/sound/soc/sof/sof-audio.c (revision 021bc4b9)
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) 2019 Intel Corporation. All rights reserved.
7 //
8 // Author: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
9 //
10 
11 #include <linux/bitfield.h>
12 #include <trace/events/sof.h>
13 #include "sof-audio.h"
14 #include "ops.h"
15 
16 static bool is_virtual_widget(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *widget,
17 			      const char *func)
18 {
19 	switch (widget->id) {
20 	case snd_soc_dapm_out_drv:
21 	case snd_soc_dapm_output:
22 	case snd_soc_dapm_input:
23 		dev_dbg(sdev->dev, "%s: %s is a virtual widget\n", func, widget->name);
24 		return true;
25 	default:
26 		return false;
27 	}
28 }
29 
30 static void sof_reset_route_setup_status(struct snd_sof_dev *sdev, struct snd_sof_widget *widget)
31 {
32 	const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
33 	struct snd_sof_route *sroute;
34 
35 	list_for_each_entry(sroute, &sdev->route_list, list)
36 		if (sroute->src_widget == widget || sroute->sink_widget == widget) {
37 			if (sroute->setup && tplg_ops && tplg_ops->route_free)
38 				tplg_ops->route_free(sdev, sroute);
39 
40 			sroute->setup = false;
41 		}
42 }
43 
44 static int sof_widget_free_unlocked(struct snd_sof_dev *sdev,
45 				    struct snd_sof_widget *swidget)
46 {
47 	const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
48 	struct snd_sof_pipeline *spipe = swidget->spipe;
49 	struct snd_sof_widget *pipe_widget;
50 	int err = 0;
51 	int ret;
52 
53 	if (!swidget->private)
54 		return 0;
55 
56 	trace_sof_widget_free(swidget);
57 
58 	/* only free when use_count is 0 */
59 	if (--swidget->use_count)
60 		return 0;
61 
62 	pipe_widget = swidget->spipe->pipe_widget;
63 
64 	/* reset route setup status for all routes that contain this widget */
65 	sof_reset_route_setup_status(sdev, swidget);
66 
67 	/* free DAI config and continue to free widget even if it fails */
68 	if (WIDGET_IS_DAI(swidget->id)) {
69 		struct snd_sof_dai_config_data data;
70 		unsigned int flags = SOF_DAI_CONFIG_FLAGS_HW_FREE;
71 
72 		data.dai_data = DMA_CHAN_INVALID;
73 
74 		if (tplg_ops && tplg_ops->dai_config) {
75 			err = tplg_ops->dai_config(sdev, swidget, flags, &data);
76 			if (err < 0)
77 				dev_err(sdev->dev, "failed to free config for widget %s\n",
78 					swidget->widget->name);
79 		}
80 	}
81 
82 	/* continue to disable core even if IPC fails */
83 	if (tplg_ops && tplg_ops->widget_free) {
84 		ret = tplg_ops->widget_free(sdev, swidget);
85 		if (ret < 0 && !err)
86 			err = ret;
87 	}
88 
89 	/*
90 	 * decrement ref count for cores associated with all modules in the pipeline and clear
91 	 * the complete flag
92 	 */
93 	if (swidget->id == snd_soc_dapm_scheduler) {
94 		int i;
95 
96 		for_each_set_bit(i, &spipe->core_mask, sdev->num_cores) {
97 			ret = snd_sof_dsp_core_put(sdev, i);
98 			if (ret < 0) {
99 				dev_err(sdev->dev, "failed to disable target core: %d for pipeline %s\n",
100 					i, swidget->widget->name);
101 				if (!err)
102 					err = ret;
103 			}
104 		}
105 		swidget->spipe->complete = 0;
106 	}
107 
108 	/*
109 	 * free the scheduler widget (same as pipe_widget) associated with the current swidget.
110 	 * skip for static pipelines
111 	 */
112 	if (swidget->dynamic_pipeline_widget && swidget->id != snd_soc_dapm_scheduler) {
113 		ret = sof_widget_free_unlocked(sdev, pipe_widget);
114 		if (ret < 0 && !err)
115 			err = ret;
116 	}
117 
118 	if (!err)
119 		dev_dbg(sdev->dev, "widget %s freed\n", swidget->widget->name);
120 
121 	return err;
122 }
123 
124 int sof_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
125 {
126 	int ret;
127 
128 	mutex_lock(&swidget->setup_mutex);
129 	ret = sof_widget_free_unlocked(sdev, swidget);
130 	mutex_unlock(&swidget->setup_mutex);
131 
132 	return ret;
133 }
134 EXPORT_SYMBOL(sof_widget_free);
135 
136 static int sof_widget_setup_unlocked(struct snd_sof_dev *sdev,
137 				     struct snd_sof_widget *swidget)
138 {
139 	const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
140 	struct snd_sof_pipeline *spipe = swidget->spipe;
141 	bool use_count_decremented = false;
142 	int ret;
143 	int i;
144 
145 	/* skip if there is no private data */
146 	if (!swidget->private)
147 		return 0;
148 
149 	trace_sof_widget_setup(swidget);
150 
151 	/* widget already set up */
152 	if (++swidget->use_count > 1)
153 		return 0;
154 
155 	/*
156 	 * The scheduler widget for a pipeline is not part of the connected DAPM
157 	 * widget list and it needs to be set up before the widgets in the pipeline
158 	 * are set up. The use_count for the scheduler widget is incremented for every
159 	 * widget in a given pipeline to ensure that it is freed only after the last
160 	 * widget in the pipeline is freed. Skip setting up scheduler widget for static pipelines.
161 	 */
162 	if (swidget->dynamic_pipeline_widget && swidget->id != snd_soc_dapm_scheduler) {
163 		if (!swidget->spipe || !swidget->spipe->pipe_widget) {
164 			dev_err(sdev->dev, "No pipeline set for %s\n", swidget->widget->name);
165 			ret = -EINVAL;
166 			goto use_count_dec;
167 		}
168 
169 		ret = sof_widget_setup_unlocked(sdev, swidget->spipe->pipe_widget);
170 		if (ret < 0)
171 			goto use_count_dec;
172 	}
173 
174 	/* update ref count for cores associated with all modules in the pipeline */
175 	if (swidget->id == snd_soc_dapm_scheduler) {
176 		for_each_set_bit(i, &spipe->core_mask, sdev->num_cores) {
177 			ret = snd_sof_dsp_core_get(sdev, i);
178 			if (ret < 0) {
179 				dev_err(sdev->dev, "failed to enable target core %d for pipeline %s\n",
180 					i, swidget->widget->name);
181 				goto pipe_widget_free;
182 			}
183 		}
184 	}
185 
186 	/* setup widget in the DSP */
187 	if (tplg_ops && tplg_ops->widget_setup) {
188 		ret = tplg_ops->widget_setup(sdev, swidget);
189 		if (ret < 0)
190 			goto pipe_widget_free;
191 	}
192 
193 	/* send config for DAI components */
194 	if (WIDGET_IS_DAI(swidget->id)) {
195 		unsigned int flags = SOF_DAI_CONFIG_FLAGS_HW_PARAMS;
196 
197 		/*
198 		 * The config flags saved during BE DAI hw_params will be used for IPC3. IPC4 does
199 		 * not use the flags argument.
200 		 */
201 		if (tplg_ops && tplg_ops->dai_config) {
202 			ret = tplg_ops->dai_config(sdev, swidget, flags, NULL);
203 			if (ret < 0)
204 				goto widget_free;
205 		}
206 	}
207 
208 	/* restore kcontrols for widget */
209 	if (tplg_ops && tplg_ops->control && tplg_ops->control->widget_kcontrol_setup) {
210 		ret = tplg_ops->control->widget_kcontrol_setup(sdev, swidget);
211 		if (ret < 0)
212 			goto widget_free;
213 	}
214 
215 	dev_dbg(sdev->dev, "widget %s setup complete\n", swidget->widget->name);
216 
217 	return 0;
218 
219 widget_free:
220 	/* widget use_count will be decremented by sof_widget_free() */
221 	sof_widget_free_unlocked(sdev, swidget);
222 	use_count_decremented = true;
223 pipe_widget_free:
224 	if (swidget->id != snd_soc_dapm_scheduler) {
225 		sof_widget_free_unlocked(sdev, swidget->spipe->pipe_widget);
226 	} else {
227 		int j;
228 
229 		/* decrement ref count for all cores that were updated previously */
230 		for_each_set_bit(j, &spipe->core_mask, sdev->num_cores) {
231 			if (j >= i)
232 				break;
233 			snd_sof_dsp_core_put(sdev, j);
234 		}
235 	}
236 use_count_dec:
237 	if (!use_count_decremented)
238 		swidget->use_count--;
239 
240 	return ret;
241 }
242 
243 int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
244 {
245 	int ret;
246 
247 	mutex_lock(&swidget->setup_mutex);
248 	ret = sof_widget_setup_unlocked(sdev, swidget);
249 	mutex_unlock(&swidget->setup_mutex);
250 
251 	return ret;
252 }
253 EXPORT_SYMBOL(sof_widget_setup);
254 
255 int sof_route_setup(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *wsource,
256 		    struct snd_soc_dapm_widget *wsink)
257 {
258 	const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
259 	struct snd_sof_widget *src_widget = wsource->dobj.private;
260 	struct snd_sof_widget *sink_widget = wsink->dobj.private;
261 	struct snd_sof_route *sroute;
262 	bool route_found = false;
263 
264 	/* ignore routes involving virtual widgets in topology */
265 	if (is_virtual_widget(sdev, src_widget->widget, __func__) ||
266 	    is_virtual_widget(sdev, sink_widget->widget, __func__))
267 		return 0;
268 
269 	/* find route matching source and sink widgets */
270 	list_for_each_entry(sroute, &sdev->route_list, list)
271 		if (sroute->src_widget == src_widget && sroute->sink_widget == sink_widget) {
272 			route_found = true;
273 			break;
274 		}
275 
276 	if (!route_found) {
277 		dev_err(sdev->dev, "error: cannot find SOF route for source %s -> %s sink\n",
278 			wsource->name, wsink->name);
279 		return -EINVAL;
280 	}
281 
282 	/* nothing to do if route is already set up */
283 	if (sroute->setup)
284 		return 0;
285 
286 	if (tplg_ops && tplg_ops->route_setup) {
287 		int ret = tplg_ops->route_setup(sdev, sroute);
288 
289 		if (ret < 0)
290 			return ret;
291 	}
292 
293 	sroute->setup = true;
294 	return 0;
295 }
296 
297 static int sof_setup_pipeline_connections(struct snd_sof_dev *sdev,
298 					  struct snd_soc_dapm_widget_list *list, int dir)
299 {
300 	const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
301 	struct snd_soc_dapm_widget *widget;
302 	struct snd_sof_route *sroute;
303 	struct snd_soc_dapm_path *p;
304 	int ret = 0;
305 	int i;
306 
307 	/*
308 	 * Set up connections between widgets in the sink/source paths based on direction.
309 	 * Some non-SOF widgets exist in topology either for compatibility or for the
310 	 * purpose of connecting a pipeline from a host to a DAI in order to receive the DAPM
311 	 * events. But they are not handled by the firmware. So ignore them.
312 	 */
313 	if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
314 		for_each_dapm_widgets(list, i, widget) {
315 			if (!widget->dobj.private)
316 				continue;
317 
318 			snd_soc_dapm_widget_for_each_sink_path(widget, p) {
319 				if (!widget_in_list(list, p->sink))
320 					continue;
321 
322 				if (p->sink->dobj.private) {
323 					ret = sof_route_setup(sdev, widget, p->sink);
324 					if (ret < 0)
325 						return ret;
326 				}
327 			}
328 		}
329 	} else {
330 		for_each_dapm_widgets(list, i, widget) {
331 			if (!widget->dobj.private)
332 				continue;
333 
334 			snd_soc_dapm_widget_for_each_source_path(widget, p) {
335 				if (!widget_in_list(list, p->source))
336 					continue;
337 
338 				if (p->source->dobj.private) {
339 					ret = sof_route_setup(sdev, p->source, widget);
340 					if (ret < 0)
341 						return ret;
342 				}
343 			}
344 		}
345 	}
346 
347 	/*
348 	 * The above loop handles connections between widgets that belong to the DAPM widget list.
349 	 * This is not sufficient to handle loopback cases between pipelines configured with
350 	 * different directions, e.g. a sidetone or an amplifier feedback connected to a speaker
351 	 * protection module.
352 	 */
353 	list_for_each_entry(sroute, &sdev->route_list, list) {
354 		bool src_widget_in_dapm_list, sink_widget_in_dapm_list;
355 		struct snd_sof_widget *swidget;
356 
357 		if (sroute->setup)
358 			continue;
359 
360 		src_widget_in_dapm_list = widget_in_list(list, sroute->src_widget->widget);
361 		sink_widget_in_dapm_list = widget_in_list(list, sroute->sink_widget->widget);
362 
363 		/*
364 		 * if both source and sink are in the DAPM list, the route must already have been
365 		 * set up above. And if neither are in the DAPM list, the route shouldn't be
366 		 * handled now.
367 		 */
368 		if (src_widget_in_dapm_list == sink_widget_in_dapm_list)
369 			continue;
370 
371 		/*
372 		 * At this point either the source widget or the sink widget is in the DAPM list
373 		 * with a route that might need to be set up. Check the use_count of the widget
374 		 * that is not in the DAPM list to confirm if it is in use currently before setting
375 		 * up the route.
376 		 */
377 		if (src_widget_in_dapm_list)
378 			swidget = sroute->sink_widget;
379 		else
380 			swidget = sroute->src_widget;
381 
382 		mutex_lock(&swidget->setup_mutex);
383 		if (!swidget->use_count) {
384 			mutex_unlock(&swidget->setup_mutex);
385 			continue;
386 		}
387 
388 		if (tplg_ops && tplg_ops->route_setup) {
389 			/*
390 			 * this route will get freed when either the source widget or the sink
391 			 * widget is freed during hw_free
392 			 */
393 			ret = tplg_ops->route_setup(sdev, sroute);
394 			if (!ret)
395 				sroute->setup = true;
396 		}
397 
398 		mutex_unlock(&swidget->setup_mutex);
399 
400 		if (ret < 0)
401 			return ret;
402 	}
403 
404 	return 0;
405 }
406 
407 static void
408 sof_unprepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *widget,
409 			      struct snd_soc_dapm_widget_list *list)
410 {
411 	const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
412 	struct snd_sof_widget *swidget = widget->dobj.private;
413 	const struct sof_ipc_tplg_widget_ops *widget_ops;
414 	struct snd_soc_dapm_path *p;
415 
416 	if (is_virtual_widget(sdev, widget, __func__))
417 		return;
418 
419 	/* skip if the widget is in use or if it is already unprepared */
420 	if (!swidget || !swidget->prepared || swidget->use_count > 0)
421 		goto sink_unprepare;
422 
423 	widget_ops = tplg_ops ? tplg_ops->widget : NULL;
424 	if (widget_ops && widget_ops[widget->id].ipc_unprepare)
425 		/* unprepare the source widget */
426 		widget_ops[widget->id].ipc_unprepare(swidget);
427 
428 	swidget->prepared = false;
429 
430 sink_unprepare:
431 	/* unprepare all widgets in the sink paths */
432 	snd_soc_dapm_widget_for_each_sink_path(widget, p) {
433 		if (!widget_in_list(list, p->sink))
434 			continue;
435 		if (!p->walking && p->sink->dobj.private) {
436 			p->walking = true;
437 			sof_unprepare_widgets_in_path(sdev, p->sink, list);
438 			p->walking = false;
439 		}
440 	}
441 }
442 
443 static int
444 sof_prepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *widget,
445 			    struct snd_pcm_hw_params *fe_params,
446 			    struct snd_sof_platform_stream_params *platform_params,
447 			    struct snd_pcm_hw_params *pipeline_params, int dir,
448 			    struct snd_soc_dapm_widget_list *list)
449 {
450 	const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
451 	struct snd_sof_widget *swidget = widget->dobj.private;
452 	const struct sof_ipc_tplg_widget_ops *widget_ops;
453 	struct snd_soc_dapm_path *p;
454 	int ret;
455 
456 	if (is_virtual_widget(sdev, widget, __func__))
457 		return 0;
458 
459 	widget_ops = tplg_ops ? tplg_ops->widget : NULL;
460 	if (!widget_ops)
461 		return 0;
462 
463 	if (!swidget || !widget_ops[widget->id].ipc_prepare || swidget->prepared)
464 		goto sink_prepare;
465 
466 	/* prepare the source widget */
467 	ret = widget_ops[widget->id].ipc_prepare(swidget, fe_params, platform_params,
468 					     pipeline_params, dir);
469 	if (ret < 0) {
470 		dev_err(sdev->dev, "failed to prepare widget %s\n", widget->name);
471 		return ret;
472 	}
473 
474 	swidget->prepared = true;
475 
476 sink_prepare:
477 	/* prepare all widgets in the sink paths */
478 	snd_soc_dapm_widget_for_each_sink_path(widget, p) {
479 		if (!widget_in_list(list, p->sink))
480 			continue;
481 		if (!p->walking && p->sink->dobj.private) {
482 			p->walking = true;
483 			ret = sof_prepare_widgets_in_path(sdev, p->sink,  fe_params,
484 							  platform_params, pipeline_params, dir,
485 							  list);
486 			p->walking = false;
487 			if (ret < 0) {
488 				/* unprepare the source widget */
489 				if (widget_ops[widget->id].ipc_unprepare &&
490 				    swidget && swidget->prepared) {
491 					widget_ops[widget->id].ipc_unprepare(swidget);
492 					swidget->prepared = false;
493 				}
494 				return ret;
495 			}
496 		}
497 	}
498 
499 	return 0;
500 }
501 
502 /*
503  * free all widgets in the sink path starting from the source widget
504  * (DAI type for capture, AIF type for playback)
505  */
506 static int sof_free_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *widget,
507 				    int dir, struct snd_sof_pcm *spcm)
508 {
509 	struct snd_soc_dapm_widget_list *list = spcm->stream[dir].list;
510 	struct snd_soc_dapm_path *p;
511 	int err;
512 	int ret = 0;
513 
514 	if (is_virtual_widget(sdev, widget, __func__))
515 		return 0;
516 
517 	if (widget->dobj.private) {
518 		err = sof_widget_free(sdev, widget->dobj.private);
519 		if (err < 0)
520 			ret = err;
521 	}
522 
523 	/* free all widgets in the sink paths even in case of error to keep use counts balanced */
524 	snd_soc_dapm_widget_for_each_sink_path(widget, p) {
525 		if (!p->walking) {
526 			if (!widget_in_list(list, p->sink))
527 				continue;
528 
529 			p->walking = true;
530 
531 			err = sof_free_widgets_in_path(sdev, p->sink, dir, spcm);
532 			if (err < 0)
533 				ret = err;
534 			p->walking = false;
535 		}
536 	}
537 
538 	return ret;
539 }
540 
541 /*
542  * set up all widgets in the sink path starting from the source widget
543  * (DAI type for capture, AIF type for playback).
544  * The error path in this function ensures that all successfully set up widgets getting freed.
545  */
546 static int sof_set_up_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *widget,
547 				      int dir, struct snd_sof_pcm *spcm)
548 {
549 	struct snd_sof_pcm_stream_pipeline_list *pipeline_list = &spcm->stream[dir].pipeline_list;
550 	struct snd_soc_dapm_widget_list *list = spcm->stream[dir].list;
551 	struct snd_sof_widget *swidget = widget->dobj.private;
552 	struct snd_sof_pipeline *spipe;
553 	struct snd_soc_dapm_path *p;
554 	int ret;
555 
556 	if (is_virtual_widget(sdev, widget, __func__))
557 		return 0;
558 
559 	if (swidget) {
560 		int i;
561 
562 		ret = sof_widget_setup(sdev, widget->dobj.private);
563 		if (ret < 0)
564 			return ret;
565 
566 		/* skip populating the pipe_widgets array if it is NULL */
567 		if (!pipeline_list->pipelines)
568 			goto sink_setup;
569 
570 		/*
571 		 * Add the widget's pipe_widget to the list of pipelines to be triggered if not
572 		 * already in the list. This will result in the pipelines getting added in the
573 		 * order source to sink.
574 		 */
575 		for (i = 0; i < pipeline_list->count; i++) {
576 			spipe = pipeline_list->pipelines[i];
577 			if (spipe == swidget->spipe)
578 				break;
579 		}
580 
581 		if (i == pipeline_list->count) {
582 			pipeline_list->count++;
583 			pipeline_list->pipelines[i] = swidget->spipe;
584 		}
585 	}
586 
587 sink_setup:
588 	snd_soc_dapm_widget_for_each_sink_path(widget, p) {
589 		if (!p->walking) {
590 			if (!widget_in_list(list, p->sink))
591 				continue;
592 
593 			p->walking = true;
594 
595 			ret = sof_set_up_widgets_in_path(sdev, p->sink, dir, spcm);
596 			p->walking = false;
597 			if (ret < 0) {
598 				if (swidget)
599 					sof_widget_free(sdev, swidget);
600 				return ret;
601 			}
602 		}
603 	}
604 
605 	return 0;
606 }
607 
608 static int
609 sof_walk_widgets_in_order(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm,
610 			  struct snd_pcm_hw_params *fe_params,
611 			  struct snd_sof_platform_stream_params *platform_params, int dir,
612 			  enum sof_widget_op op)
613 {
614 	struct snd_soc_dapm_widget_list *list = spcm->stream[dir].list;
615 	struct snd_soc_dapm_widget *widget;
616 	char *str;
617 	int ret = 0;
618 	int i;
619 
620 	if (!list)
621 		return 0;
622 
623 	for_each_dapm_widgets(list, i, widget) {
624 		if (is_virtual_widget(sdev, widget, __func__))
625 			continue;
626 
627 		/* starting widget for playback is AIF type */
628 		if (dir == SNDRV_PCM_STREAM_PLAYBACK && widget->id != snd_soc_dapm_aif_in)
629 			continue;
630 
631 		/* starting widget for capture is DAI type */
632 		if (dir == SNDRV_PCM_STREAM_CAPTURE && widget->id != snd_soc_dapm_dai_out)
633 			continue;
634 
635 		switch (op) {
636 		case SOF_WIDGET_SETUP:
637 			ret = sof_set_up_widgets_in_path(sdev, widget, dir, spcm);
638 			str = "set up";
639 			break;
640 		case SOF_WIDGET_FREE:
641 			ret = sof_free_widgets_in_path(sdev, widget, dir, spcm);
642 			str = "free";
643 			break;
644 		case SOF_WIDGET_PREPARE:
645 		{
646 			struct snd_pcm_hw_params pipeline_params;
647 
648 			str = "prepare";
649 			/*
650 			 * When walking the list of connected widgets, the pipeline_params for each
651 			 * widget is modified by the source widget in the path. Use a local
652 			 * copy of the runtime params as the pipeline_params so that the runtime
653 			 * params does not get overwritten.
654 			 */
655 			memcpy(&pipeline_params, fe_params, sizeof(*fe_params));
656 
657 			ret = sof_prepare_widgets_in_path(sdev, widget, fe_params, platform_params,
658 							  &pipeline_params, dir, list);
659 			break;
660 		}
661 		case SOF_WIDGET_UNPREPARE:
662 			sof_unprepare_widgets_in_path(sdev, widget, list);
663 			break;
664 		default:
665 			dev_err(sdev->dev, "Invalid widget op %d\n", op);
666 			return -EINVAL;
667 		}
668 		if (ret < 0) {
669 			dev_err(sdev->dev, "Failed to %s connected widgets\n", str);
670 			return ret;
671 		}
672 	}
673 
674 	return 0;
675 }
676 
677 int sof_widget_list_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm,
678 			  struct snd_pcm_hw_params *fe_params,
679 			  struct snd_sof_platform_stream_params *platform_params,
680 			  int dir)
681 {
682 	const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
683 	struct snd_soc_dapm_widget_list *list = spcm->stream[dir].list;
684 	struct snd_soc_dapm_widget *widget;
685 	int i, ret;
686 
687 	/* nothing to set up */
688 	if (!list)
689 		return 0;
690 
691 	/*
692 	 * Prepare widgets for set up. The prepare step is used to allocate memory, assign
693 	 * instance ID and pick the widget configuration based on the runtime PCM params.
694 	 */
695 	ret = sof_walk_widgets_in_order(sdev, spcm, fe_params, platform_params,
696 					dir, SOF_WIDGET_PREPARE);
697 	if (ret < 0)
698 		return ret;
699 
700 	/* Set up is used to send the IPC to the DSP to create the widget */
701 	ret = sof_walk_widgets_in_order(sdev, spcm, fe_params, platform_params,
702 					dir, SOF_WIDGET_SETUP);
703 	if (ret < 0) {
704 		sof_walk_widgets_in_order(sdev, spcm, fe_params, platform_params,
705 					  dir, SOF_WIDGET_UNPREPARE);
706 		return ret;
707 	}
708 
709 	/*
710 	 * error in setting pipeline connections will result in route status being reset for
711 	 * routes that were successfully set up when the widgets are freed.
712 	 */
713 	ret = sof_setup_pipeline_connections(sdev, list, dir);
714 	if (ret < 0)
715 		goto widget_free;
716 
717 	/* complete pipelines */
718 	for_each_dapm_widgets(list, i, widget) {
719 		struct snd_sof_widget *swidget = widget->dobj.private;
720 		struct snd_sof_widget *pipe_widget;
721 		struct snd_sof_pipeline *spipe;
722 
723 		if (!swidget || sdev->dspless_mode_selected)
724 			continue;
725 
726 		spipe = swidget->spipe;
727 		if (!spipe) {
728 			dev_err(sdev->dev, "no pipeline found for %s\n",
729 				swidget->widget->name);
730 			ret = -EINVAL;
731 			goto widget_free;
732 		}
733 
734 		pipe_widget = spipe->pipe_widget;
735 		if (!pipe_widget) {
736 			dev_err(sdev->dev, "error: no pipeline widget found for %s\n",
737 				swidget->widget->name);
738 			ret = -EINVAL;
739 			goto widget_free;
740 		}
741 
742 		if (spipe->complete)
743 			continue;
744 
745 		if (tplg_ops && tplg_ops->pipeline_complete) {
746 			spipe->complete = tplg_ops->pipeline_complete(sdev, pipe_widget);
747 			if (spipe->complete < 0) {
748 				ret = spipe->complete;
749 				goto widget_free;
750 			}
751 		}
752 	}
753 
754 	return 0;
755 
756 widget_free:
757 	sof_walk_widgets_in_order(sdev, spcm, fe_params, platform_params, dir,
758 				  SOF_WIDGET_FREE);
759 	sof_walk_widgets_in_order(sdev, spcm, NULL, NULL, dir, SOF_WIDGET_UNPREPARE);
760 
761 	return ret;
762 }
763 
764 int sof_widget_list_free(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, int dir)
765 {
766 	struct snd_sof_pcm_stream_pipeline_list *pipeline_list = &spcm->stream[dir].pipeline_list;
767 	struct snd_soc_dapm_widget_list *list = spcm->stream[dir].list;
768 	int ret;
769 
770 	/* nothing to free */
771 	if (!list)
772 		return 0;
773 
774 	/* send IPC to free widget in the DSP */
775 	ret = sof_walk_widgets_in_order(sdev, spcm, NULL, NULL, dir, SOF_WIDGET_FREE);
776 
777 	/* unprepare the widget */
778 	sof_walk_widgets_in_order(sdev, spcm, NULL, NULL, dir, SOF_WIDGET_UNPREPARE);
779 
780 	snd_soc_dapm_dai_free_widgets(&list);
781 	spcm->stream[dir].list = NULL;
782 
783 	pipeline_list->count = 0;
784 
785 	return ret;
786 }
787 
788 /*
789  * helper to determine if there are only D0i3 compatible
790  * streams active
791  */
792 bool snd_sof_dsp_only_d0i3_compatible_stream_active(struct snd_sof_dev *sdev)
793 {
794 	struct snd_pcm_substream *substream;
795 	struct snd_sof_pcm *spcm;
796 	bool d0i3_compatible_active = false;
797 	int dir;
798 
799 	list_for_each_entry(spcm, &sdev->pcm_list, list) {
800 		for_each_pcm_streams(dir) {
801 			substream = spcm->stream[dir].substream;
802 			if (!substream || !substream->runtime)
803 				continue;
804 
805 			/*
806 			 * substream->runtime being not NULL indicates
807 			 * that the stream is open. No need to check the
808 			 * stream state.
809 			 */
810 			if (!spcm->stream[dir].d0i3_compatible)
811 				return false;
812 
813 			d0i3_compatible_active = true;
814 		}
815 	}
816 
817 	return d0i3_compatible_active;
818 }
819 EXPORT_SYMBOL(snd_sof_dsp_only_d0i3_compatible_stream_active);
820 
821 bool snd_sof_stream_suspend_ignored(struct snd_sof_dev *sdev)
822 {
823 	struct snd_sof_pcm *spcm;
824 
825 	list_for_each_entry(spcm, &sdev->pcm_list, list) {
826 		if (spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].suspend_ignored ||
827 		    spcm->stream[SNDRV_PCM_STREAM_CAPTURE].suspend_ignored)
828 			return true;
829 	}
830 
831 	return false;
832 }
833 
834 int sof_pcm_stream_free(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream,
835 			struct snd_sof_pcm *spcm, int dir, bool free_widget_list)
836 {
837 	const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm);
838 	int ret;
839 
840 	if (spcm->prepared[substream->stream]) {
841 		/* stop DMA first if needed */
842 		if (pcm_ops && pcm_ops->platform_stop_during_hw_free)
843 			snd_sof_pcm_platform_trigger(sdev, substream, SNDRV_PCM_TRIGGER_STOP);
844 
845 		/* Send PCM_FREE IPC to reset pipeline */
846 		if (pcm_ops && pcm_ops->hw_free) {
847 			ret = pcm_ops->hw_free(sdev->component, substream);
848 			if (ret < 0)
849 				return ret;
850 		}
851 
852 		spcm->prepared[substream->stream] = false;
853 	}
854 
855 	/* reset the DMA */
856 	ret = snd_sof_pcm_platform_hw_free(sdev, substream);
857 	if (ret < 0)
858 		return ret;
859 
860 	/* free widget list */
861 	if (free_widget_list) {
862 		ret = sof_widget_list_free(sdev, spcm, dir);
863 		if (ret < 0)
864 			dev_err(sdev->dev, "failed to free widgets during suspend\n");
865 	}
866 
867 	return ret;
868 }
869 
870 /*
871  * Generic object lookup APIs.
872  */
873 
874 struct snd_sof_pcm *snd_sof_find_spcm_name(struct snd_soc_component *scomp,
875 					   const char *name)
876 {
877 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
878 	struct snd_sof_pcm *spcm;
879 
880 	list_for_each_entry(spcm, &sdev->pcm_list, list) {
881 		/* match with PCM dai name */
882 		if (strcmp(spcm->pcm.dai_name, name) == 0)
883 			return spcm;
884 
885 		/* match with playback caps name if set */
886 		if (*spcm->pcm.caps[0].name &&
887 		    !strcmp(spcm->pcm.caps[0].name, name))
888 			return spcm;
889 
890 		/* match with capture caps name if set */
891 		if (*spcm->pcm.caps[1].name &&
892 		    !strcmp(spcm->pcm.caps[1].name, name))
893 			return spcm;
894 	}
895 
896 	return NULL;
897 }
898 
899 struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_soc_component *scomp,
900 					   unsigned int comp_id,
901 					   int *direction)
902 {
903 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
904 	struct snd_sof_pcm *spcm;
905 	int dir;
906 
907 	list_for_each_entry(spcm, &sdev->pcm_list, list) {
908 		for_each_pcm_streams(dir) {
909 			if (spcm->stream[dir].comp_id == comp_id) {
910 				*direction = dir;
911 				return spcm;
912 			}
913 		}
914 	}
915 
916 	return NULL;
917 }
918 
919 struct snd_sof_widget *snd_sof_find_swidget(struct snd_soc_component *scomp,
920 					    const char *name)
921 {
922 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
923 	struct snd_sof_widget *swidget;
924 
925 	list_for_each_entry(swidget, &sdev->widget_list, list) {
926 		if (strcmp(name, swidget->widget->name) == 0)
927 			return swidget;
928 	}
929 
930 	return NULL;
931 }
932 
933 /* find widget by stream name and direction */
934 struct snd_sof_widget *
935 snd_sof_find_swidget_sname(struct snd_soc_component *scomp,
936 			   const char *pcm_name, int dir)
937 {
938 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
939 	struct snd_sof_widget *swidget;
940 	enum snd_soc_dapm_type type;
941 
942 	if (dir == SNDRV_PCM_STREAM_PLAYBACK)
943 		type = snd_soc_dapm_aif_in;
944 	else
945 		type = snd_soc_dapm_aif_out;
946 
947 	list_for_each_entry(swidget, &sdev->widget_list, list) {
948 		if (!strcmp(pcm_name, swidget->widget->sname) &&
949 		    swidget->id == type)
950 			return swidget;
951 	}
952 
953 	return NULL;
954 }
955 
956 struct snd_sof_dai *snd_sof_find_dai(struct snd_soc_component *scomp,
957 				     const char *name)
958 {
959 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
960 	struct snd_sof_dai *dai;
961 
962 	list_for_each_entry(dai, &sdev->dai_list, list) {
963 		if (dai->name && (strcmp(name, dai->name) == 0))
964 			return dai;
965 	}
966 
967 	return NULL;
968 }
969 
970 static int sof_dai_get_clk(struct snd_soc_pcm_runtime *rtd, int clk_type)
971 {
972 	struct snd_soc_component *component =
973 		snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME);
974 	struct snd_sof_dai *dai =
975 		snd_sof_find_dai(component, (char *)rtd->dai_link->name);
976 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
977 	const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
978 
979 	/* use the tplg configured mclk if existed */
980 	if (!dai)
981 		return 0;
982 
983 	if (tplg_ops && tplg_ops->dai_get_clk)
984 		return tplg_ops->dai_get_clk(sdev, dai, clk_type);
985 
986 	return 0;
987 }
988 
989 /*
990  * Helper to get SSP MCLK from a pcm_runtime.
991  * Return 0 if not exist.
992  */
993 int sof_dai_get_mclk(struct snd_soc_pcm_runtime *rtd)
994 {
995 	return sof_dai_get_clk(rtd, SOF_DAI_CLK_INTEL_SSP_MCLK);
996 }
997 EXPORT_SYMBOL(sof_dai_get_mclk);
998 
999 /*
1000  * Helper to get SSP BCLK from a pcm_runtime.
1001  * Return 0 if not exist.
1002  */
1003 int sof_dai_get_bclk(struct snd_soc_pcm_runtime *rtd)
1004 {
1005 	return sof_dai_get_clk(rtd, SOF_DAI_CLK_INTEL_SSP_BCLK);
1006 }
1007 EXPORT_SYMBOL(sof_dai_get_bclk);
1008