xref: /linux/sound/soc/sof/intel/hda-dai-ops.c (revision 27aa58180473f81990f35238dc8aec40d34c778d)
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) 2022 Intel Corporation. All rights reserved.
7 
8 #include <sound/pcm_params.h>
9 #include <sound/hdaudio_ext.h>
10 #include <sound/hda-mlink.h>
11 #include <sound/sof/ipc4/header.h>
12 #include <uapi/sound/sof/header.h>
13 #include "../ipc4-priv.h"
14 #include "../ipc4-topology.h"
15 #include "../sof-priv.h"
16 #include "../sof-audio.h"
17 #include "hda.h"
18 
19 /* These ops are only applicable for the HDA DAI's in their current form */
20 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK)
21 /*
22  * This function checks if the host dma channel corresponding
23  * to the link DMA stream_tag argument is assigned to one
24  * of the FEs connected to the BE DAI.
25  */
26 static bool hda_check_fes(struct snd_soc_pcm_runtime *rtd,
27 			  int dir, int stream_tag)
28 {
29 	struct snd_pcm_substream *fe_substream;
30 	struct hdac_stream *fe_hstream;
31 	struct snd_soc_dpcm *dpcm;
32 
33 	for_each_dpcm_fe(rtd, dir, dpcm) {
34 		fe_substream = snd_soc_dpcm_get_substream(dpcm->fe, dir);
35 		fe_hstream = fe_substream->runtime->private_data;
36 		if (fe_hstream->stream_tag == stream_tag)
37 			return true;
38 	}
39 
40 	return false;
41 }
42 
43 static struct hdac_ext_stream *
44 hda_link_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream)
45 {
46 	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
47 	struct sof_intel_hda_stream *hda_stream;
48 	const struct sof_intel_dsp_desc *chip;
49 	struct snd_sof_dev *sdev;
50 	struct hdac_ext_stream *res = NULL;
51 	struct hdac_stream *hstream = NULL;
52 
53 	int stream_dir = substream->stream;
54 
55 	if (!bus->ppcap) {
56 		dev_err(bus->dev, "stream type not supported\n");
57 		return NULL;
58 	}
59 
60 	spin_lock_irq(&bus->reg_lock);
61 	list_for_each_entry(hstream, &bus->stream_list, list) {
62 		struct hdac_ext_stream *hext_stream =
63 			stream_to_hdac_ext_stream(hstream);
64 		if (hstream->direction != substream->stream)
65 			continue;
66 
67 		hda_stream = hstream_to_sof_hda_stream(hext_stream);
68 		sdev = hda_stream->sdev;
69 		chip = get_chip_info(sdev->pdata);
70 
71 		/* check if link is available */
72 		if (!hext_stream->link_locked) {
73 			/*
74 			 * choose the first available link for platforms that do not have the
75 			 * PROCEN_FMT_QUIRK set.
76 			 */
77 			if (!(chip->quirks & SOF_INTEL_PROCEN_FMT_QUIRK)) {
78 				res = hext_stream;
79 				break;
80 			}
81 
82 			if (hstream->opened) {
83 				/*
84 				 * check if the stream tag matches the stream
85 				 * tag of one of the connected FEs
86 				 */
87 				if (hda_check_fes(rtd, stream_dir,
88 						  hstream->stream_tag)) {
89 					res = hext_stream;
90 					break;
91 				}
92 			} else {
93 				res = hext_stream;
94 
95 				/*
96 				 * This must be a hostless stream.
97 				 * So reserve the host DMA channel.
98 				 */
99 				hda_stream->host_reserved = 1;
100 				break;
101 			}
102 		}
103 	}
104 
105 	if (res) {
106 		/* Make sure that host and link DMA is decoupled. */
107 		snd_hdac_ext_stream_decouple_locked(bus, res, true);
108 
109 		res->link_locked = 1;
110 		res->link_substream = substream;
111 	}
112 	spin_unlock_irq(&bus->reg_lock);
113 
114 	return res;
115 }
116 
117 static struct hdac_ext_stream *hda_get_hext_stream(struct snd_sof_dev *sdev,
118 						   struct snd_soc_dai *cpu_dai,
119 						   struct snd_pcm_substream *substream)
120 {
121 	return snd_soc_dai_get_dma_data(cpu_dai, substream);
122 }
123 
124 static struct hdac_ext_stream *hda_ipc4_get_hext_stream(struct snd_sof_dev *sdev,
125 							struct snd_soc_dai *cpu_dai,
126 							struct snd_pcm_substream *substream)
127 {
128 	struct snd_sof_widget *pipe_widget;
129 	struct sof_ipc4_pipeline *pipeline;
130 	struct snd_sof_widget *swidget;
131 	struct snd_soc_dapm_widget *w;
132 
133 	w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
134 	swidget = w->dobj.private;
135 	pipe_widget = swidget->spipe->pipe_widget;
136 	pipeline = pipe_widget->private;
137 
138 	/* mark pipeline so that it can be skipped during FE trigger */
139 	pipeline->skip_during_fe_trigger = true;
140 
141 	return snd_soc_dai_get_dma_data(cpu_dai, substream);
142 }
143 
144 static struct hdac_ext_stream *hda_assign_hext_stream(struct snd_sof_dev *sdev,
145 						      struct snd_soc_dai *cpu_dai,
146 						      struct snd_pcm_substream *substream)
147 {
148 	struct hdac_ext_stream *hext_stream;
149 
150 	hext_stream = hda_link_stream_assign(sof_to_bus(sdev), substream);
151 	if (!hext_stream)
152 		return NULL;
153 
154 	snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)hext_stream);
155 
156 	return hext_stream;
157 }
158 
159 static void hda_release_hext_stream(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
160 				    struct snd_pcm_substream *substream)
161 {
162 	struct hdac_ext_stream *hext_stream = hda_get_hext_stream(sdev, cpu_dai, substream);
163 
164 	snd_soc_dai_set_dma_data(cpu_dai, substream, NULL);
165 	snd_hdac_ext_stream_release(hext_stream, HDAC_EXT_STREAM_TYPE_LINK);
166 }
167 
168 static void hda_setup_hext_stream(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream,
169 				  unsigned int format_val)
170 {
171 	snd_hdac_ext_stream_setup(hext_stream, format_val);
172 }
173 
174 static void hda_reset_hext_stream(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream)
175 {
176 	snd_hdac_ext_stream_reset(hext_stream);
177 }
178 
179 static void hda_codec_dai_set_stream(struct snd_sof_dev *sdev,
180 				     struct snd_pcm_substream *substream,
181 				     struct hdac_stream *hstream)
182 {
183 	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
184 	struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
185 
186 	/* set the hdac_stream in the codec dai */
187 	snd_soc_dai_set_stream(codec_dai, hstream, substream->stream);
188 }
189 
190 static unsigned int hda_calc_stream_format(struct snd_sof_dev *sdev,
191 					   struct snd_pcm_substream *substream,
192 					   struct snd_pcm_hw_params *params)
193 {
194 	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
195 	struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
196 	unsigned int link_bps;
197 	unsigned int format_val;
198 	unsigned int bits;
199 
200 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
201 		link_bps = codec_dai->driver->playback.sig_bits;
202 	else
203 		link_bps = codec_dai->driver->capture.sig_bits;
204 
205 	bits = snd_hdac_stream_format_bits(params_format(params), SNDRV_PCM_SUBFORMAT_STD,
206 					   link_bps);
207 	format_val = snd_hdac_stream_format(params_channels(params), bits, params_rate(params));
208 
209 	dev_dbg(sdev->dev, "format_val=%#x, rate=%d, ch=%d, format=%d\n", format_val,
210 		params_rate(params), params_channels(params), params_format(params));
211 
212 	return format_val;
213 }
214 
215 static struct hdac_ext_link *hda_get_hlink(struct snd_sof_dev *sdev,
216 					   struct snd_pcm_substream *substream)
217 {
218 	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
219 	struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
220 	struct hdac_bus *bus = sof_to_bus(sdev);
221 
222 	return snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name);
223 }
224 
225 static unsigned int generic_calc_stream_format(struct snd_sof_dev *sdev,
226 					       struct snd_pcm_substream *substream,
227 					       struct snd_pcm_hw_params *params)
228 {
229 	unsigned int format_val;
230 	unsigned int bits;
231 
232 	bits = snd_hdac_stream_format_bits(params_format(params), SNDRV_PCM_SUBFORMAT_STD,
233 					   params_physical_width(params));
234 	format_val = snd_hdac_stream_format(params_channels(params), bits, params_rate(params));
235 
236 	dev_dbg(sdev->dev, "format_val=%#x, rate=%d, ch=%d, format=%d\n", format_val,
237 		params_rate(params), params_channels(params), params_format(params));
238 
239 	return format_val;
240 }
241 
242 static unsigned int dmic_calc_stream_format(struct snd_sof_dev *sdev,
243 					    struct snd_pcm_substream *substream,
244 					    struct snd_pcm_hw_params *params)
245 {
246 	unsigned int format_val;
247 	snd_pcm_format_t format;
248 	unsigned int channels;
249 	unsigned int width;
250 	unsigned int bits;
251 
252 	channels = params_channels(params);
253 	format = params_format(params);
254 	width = params_physical_width(params);
255 
256 	if (format == SNDRV_PCM_FORMAT_S16_LE) {
257 		format = SNDRV_PCM_FORMAT_S32_LE;
258 		channels /= 2;
259 		width = 32;
260 	}
261 
262 	bits = snd_hdac_stream_format_bits(format, SNDRV_PCM_SUBFORMAT_STD, width);
263 	format_val = snd_hdac_stream_format(channels, bits, params_rate(params));
264 
265 	dev_dbg(sdev->dev, "format_val=%#x, rate=%d, ch=%d, format=%d\n", format_val,
266 		params_rate(params), channels, format);
267 
268 	return format_val;
269 }
270 
271 static struct hdac_ext_link *ssp_get_hlink(struct snd_sof_dev *sdev,
272 					   struct snd_pcm_substream *substream)
273 {
274 	struct hdac_bus *bus = sof_to_bus(sdev);
275 
276 	return hdac_bus_eml_ssp_get_hlink(bus);
277 }
278 
279 static struct hdac_ext_link *dmic_get_hlink(struct snd_sof_dev *sdev,
280 					    struct snd_pcm_substream *substream)
281 {
282 	struct hdac_bus *bus = sof_to_bus(sdev);
283 
284 	return hdac_bus_eml_dmic_get_hlink(bus);
285 }
286 
287 static struct hdac_ext_link *sdw_get_hlink(struct snd_sof_dev *sdev,
288 					   struct snd_pcm_substream *substream)
289 {
290 	struct hdac_bus *bus = sof_to_bus(sdev);
291 
292 	return hdac_bus_eml_sdw_get_hlink(bus);
293 }
294 
295 static int hda_ipc4_pre_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
296 				struct snd_pcm_substream *substream, int cmd)
297 {
298 	struct sof_ipc4_fw_data *ipc4_data = sdev->private;
299 	struct snd_sof_widget *pipe_widget;
300 	struct sof_ipc4_pipeline *pipeline;
301 	struct snd_sof_widget *swidget;
302 	struct snd_soc_dapm_widget *w;
303 	int ret = 0;
304 
305 	w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
306 	swidget = w->dobj.private;
307 	pipe_widget = swidget->spipe->pipe_widget;
308 	pipeline = pipe_widget->private;
309 
310 	if (pipe_widget->instance_id < 0)
311 		return 0;
312 
313 	mutex_lock(&ipc4_data->pipeline_state_mutex);
314 
315 	switch (cmd) {
316 	case SNDRV_PCM_TRIGGER_START:
317 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
318 		break;
319 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
320 	case SNDRV_PCM_TRIGGER_SUSPEND:
321 	case SNDRV_PCM_TRIGGER_STOP:
322 		ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
323 						  SOF_IPC4_PIPE_PAUSED);
324 		if (ret < 0)
325 			goto out;
326 
327 		pipeline->state = SOF_IPC4_PIPE_PAUSED;
328 		break;
329 	default:
330 		dev_err(sdev->dev, "unknown trigger command %d\n", cmd);
331 		ret = -EINVAL;
332 	}
333 out:
334 	mutex_unlock(&ipc4_data->pipeline_state_mutex);
335 	return ret;
336 }
337 
338 static int hda_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
339 		       struct snd_pcm_substream *substream, int cmd)
340 {
341 	struct hdac_ext_stream *hext_stream = snd_soc_dai_get_dma_data(cpu_dai, substream);
342 
343 	switch (cmd) {
344 	case SNDRV_PCM_TRIGGER_START:
345 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
346 		snd_hdac_ext_stream_start(hext_stream);
347 		break;
348 	case SNDRV_PCM_TRIGGER_SUSPEND:
349 	case SNDRV_PCM_TRIGGER_STOP:
350 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
351 		snd_hdac_ext_stream_clear(hext_stream);
352 		break;
353 	default:
354 		dev_err(sdev->dev, "unknown trigger command %d\n", cmd);
355 		return -EINVAL;
356 	}
357 
358 	return 0;
359 }
360 
361 static int hda_ipc4_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
362 				 struct snd_pcm_substream *substream, int cmd)
363 {
364 	struct sof_ipc4_fw_data *ipc4_data = sdev->private;
365 	struct snd_sof_widget *pipe_widget;
366 	struct sof_ipc4_pipeline *pipeline;
367 	struct snd_sof_widget *swidget;
368 	struct snd_soc_dapm_widget *w;
369 	int ret = 0;
370 
371 	w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
372 	swidget = w->dobj.private;
373 	pipe_widget = swidget->spipe->pipe_widget;
374 	pipeline = pipe_widget->private;
375 
376 	if (pipe_widget->instance_id < 0)
377 		return 0;
378 
379 	mutex_lock(&ipc4_data->pipeline_state_mutex);
380 
381 	switch (cmd) {
382 	case SNDRV_PCM_TRIGGER_START:
383 		if (pipeline->state != SOF_IPC4_PIPE_PAUSED) {
384 			ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
385 							  SOF_IPC4_PIPE_PAUSED);
386 			if (ret < 0)
387 				goto out;
388 			pipeline->state = SOF_IPC4_PIPE_PAUSED;
389 		}
390 
391 		ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
392 						  SOF_IPC4_PIPE_RUNNING);
393 		if (ret < 0)
394 			goto out;
395 		pipeline->state = SOF_IPC4_PIPE_RUNNING;
396 		swidget->spipe->started_count++;
397 		break;
398 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
399 		ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
400 						  SOF_IPC4_PIPE_RUNNING);
401 		if (ret < 0)
402 			goto out;
403 		pipeline->state = SOF_IPC4_PIPE_RUNNING;
404 		break;
405 	case SNDRV_PCM_TRIGGER_SUSPEND:
406 	case SNDRV_PCM_TRIGGER_STOP:
407 		/*
408 		 * STOP/SUSPEND trigger is invoked only once when all users of this pipeline have
409 		 * been stopped. So, clear the started_count so that the pipeline can be reset
410 		 */
411 		swidget->spipe->started_count = 0;
412 		break;
413 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
414 		break;
415 	default:
416 		dev_err(sdev->dev, "unknown trigger command %d\n", cmd);
417 		ret = -EINVAL;
418 		break;
419 	}
420 out:
421 	mutex_unlock(&ipc4_data->pipeline_state_mutex);
422 	return ret;
423 }
424 
425 static const struct hda_dai_widget_dma_ops hda_ipc4_dma_ops = {
426 	.get_hext_stream = hda_ipc4_get_hext_stream,
427 	.assign_hext_stream = hda_assign_hext_stream,
428 	.release_hext_stream = hda_release_hext_stream,
429 	.setup_hext_stream = hda_setup_hext_stream,
430 	.reset_hext_stream = hda_reset_hext_stream,
431 	.pre_trigger = hda_ipc4_pre_trigger,
432 	.trigger = hda_trigger,
433 	.post_trigger = hda_ipc4_post_trigger,
434 	.codec_dai_set_stream = hda_codec_dai_set_stream,
435 	.calc_stream_format = hda_calc_stream_format,
436 	.get_hlink = hda_get_hlink,
437 };
438 
439 static const struct hda_dai_widget_dma_ops ssp_ipc4_dma_ops = {
440 	.get_hext_stream = hda_ipc4_get_hext_stream,
441 	.assign_hext_stream = hda_assign_hext_stream,
442 	.release_hext_stream = hda_release_hext_stream,
443 	.setup_hext_stream = hda_setup_hext_stream,
444 	.reset_hext_stream = hda_reset_hext_stream,
445 	.pre_trigger = hda_ipc4_pre_trigger,
446 	.trigger = hda_trigger,
447 	.post_trigger = hda_ipc4_post_trigger,
448 	.calc_stream_format = generic_calc_stream_format,
449 	.get_hlink = ssp_get_hlink,
450 };
451 
452 static const struct hda_dai_widget_dma_ops dmic_ipc4_dma_ops = {
453 	.get_hext_stream = hda_ipc4_get_hext_stream,
454 	.assign_hext_stream = hda_assign_hext_stream,
455 	.release_hext_stream = hda_release_hext_stream,
456 	.setup_hext_stream = hda_setup_hext_stream,
457 	.reset_hext_stream = hda_reset_hext_stream,
458 	.pre_trigger = hda_ipc4_pre_trigger,
459 	.trigger = hda_trigger,
460 	.post_trigger = hda_ipc4_post_trigger,
461 	.calc_stream_format = dmic_calc_stream_format,
462 	.get_hlink = dmic_get_hlink,
463 };
464 
465 static const struct hda_dai_widget_dma_ops sdw_ipc4_dma_ops = {
466 	.get_hext_stream = hda_ipc4_get_hext_stream,
467 	.assign_hext_stream = hda_assign_hext_stream,
468 	.release_hext_stream = hda_release_hext_stream,
469 	.setup_hext_stream = hda_setup_hext_stream,
470 	.reset_hext_stream = hda_reset_hext_stream,
471 	.pre_trigger = hda_ipc4_pre_trigger,
472 	.trigger = hda_trigger,
473 	.post_trigger = hda_ipc4_post_trigger,
474 	.calc_stream_format = generic_calc_stream_format,
475 	.get_hlink = sdw_get_hlink,
476 };
477 
478 static const struct hda_dai_widget_dma_ops hda_ipc4_chain_dma_ops = {
479 	.get_hext_stream = hda_get_hext_stream,
480 	.assign_hext_stream = hda_assign_hext_stream,
481 	.release_hext_stream = hda_release_hext_stream,
482 	.setup_hext_stream = hda_setup_hext_stream,
483 	.reset_hext_stream = hda_reset_hext_stream,
484 	.trigger = hda_trigger,
485 	.codec_dai_set_stream = hda_codec_dai_set_stream,
486 	.calc_stream_format = hda_calc_stream_format,
487 	.get_hlink = hda_get_hlink,
488 };
489 
490 static const struct hda_dai_widget_dma_ops sdw_ipc4_chain_dma_ops = {
491 	.get_hext_stream = hda_get_hext_stream,
492 	.assign_hext_stream = hda_assign_hext_stream,
493 	.release_hext_stream = hda_release_hext_stream,
494 	.setup_hext_stream = hda_setup_hext_stream,
495 	.reset_hext_stream = hda_reset_hext_stream,
496 	.trigger = hda_trigger,
497 	.calc_stream_format = generic_calc_stream_format,
498 	.get_hlink = sdw_get_hlink,
499 };
500 
501 static int hda_ipc3_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
502 				 struct snd_pcm_substream *substream, int cmd)
503 {
504 	struct hdac_ext_stream *hext_stream = hda_get_hext_stream(sdev, cpu_dai, substream);
505 	struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
506 
507 	switch (cmd) {
508 	case SNDRV_PCM_TRIGGER_SUSPEND:
509 	case SNDRV_PCM_TRIGGER_STOP:
510 	{
511 		struct snd_sof_dai_config_data data = { 0 };
512 		int ret;
513 
514 		data.dai_data = DMA_CHAN_INVALID;
515 		ret = hda_dai_config(w, SOF_DAI_CONFIG_FLAGS_HW_FREE, &data);
516 		if (ret < 0)
517 			return ret;
518 
519 		if (cmd == SNDRV_PCM_TRIGGER_STOP)
520 			return hda_link_dma_cleanup(substream, hext_stream, cpu_dai);
521 
522 		break;
523 	}
524 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
525 		return hda_dai_config(w, SOF_DAI_CONFIG_FLAGS_PAUSE, NULL);
526 	default:
527 		break;
528 	}
529 
530 	return 0;
531 }
532 
533 static const struct hda_dai_widget_dma_ops hda_ipc3_dma_ops = {
534 	.get_hext_stream = hda_get_hext_stream,
535 	.assign_hext_stream = hda_assign_hext_stream,
536 	.release_hext_stream = hda_release_hext_stream,
537 	.setup_hext_stream = hda_setup_hext_stream,
538 	.reset_hext_stream = hda_reset_hext_stream,
539 	.trigger = hda_trigger,
540 	.post_trigger = hda_ipc3_post_trigger,
541 	.codec_dai_set_stream = hda_codec_dai_set_stream,
542 	.calc_stream_format = hda_calc_stream_format,
543 	.get_hlink = hda_get_hlink,
544 };
545 
546 static struct hdac_ext_stream *
547 hda_dspless_get_hext_stream(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
548 			    struct snd_pcm_substream *substream)
549 {
550 	struct hdac_stream *hstream = substream->runtime->private_data;
551 
552 	return stream_to_hdac_ext_stream(hstream);
553 }
554 
555 static void hda_dspless_setup_hext_stream(struct snd_sof_dev *sdev,
556 					  struct hdac_ext_stream *hext_stream,
557 					  unsigned int format_val)
558 {
559 	/*
560 	 * Save the format_val which was adjusted by the maxbps of the codec.
561 	 * This information is not available on the FE side since there we are
562 	 * using dummy_codec.
563 	 */
564 	hext_stream->hstream.format_val = format_val;
565 }
566 
567 static const struct hda_dai_widget_dma_ops hda_dspless_dma_ops = {
568 	.get_hext_stream = hda_dspless_get_hext_stream,
569 	.setup_hext_stream = hda_dspless_setup_hext_stream,
570 	.codec_dai_set_stream = hda_codec_dai_set_stream,
571 	.calc_stream_format = hda_calc_stream_format,
572 	.get_hlink = hda_get_hlink,
573 };
574 
575 static const struct hda_dai_widget_dma_ops sdw_dspless_dma_ops = {
576 	.get_hext_stream = hda_dspless_get_hext_stream,
577 	.setup_hext_stream = hda_dspless_setup_hext_stream,
578 	.calc_stream_format = generic_calc_stream_format,
579 	.get_hlink = sdw_get_hlink,
580 };
581 
582 #endif
583 
584 const struct hda_dai_widget_dma_ops *
585 hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
586 {
587 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK)
588 	struct snd_sof_dai *sdai;
589 	const struct sof_intel_dsp_desc *chip;
590 
591 	chip = get_chip_info(sdev->pdata);
592 	sdai = swidget->private;
593 
594 	if (sdev->dspless_mode_selected) {
595 		switch (sdai->type) {
596 		case SOF_DAI_INTEL_HDA:
597 			return &hda_dspless_dma_ops;
598 		case SOF_DAI_INTEL_ALH:
599 			if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
600 				return NULL;
601 			return &sdw_dspless_dma_ops;
602 		default:
603 			return NULL;
604 		}
605 	}
606 
607 	switch (sdev->pdata->ipc_type) {
608 	case SOF_IPC_TYPE_3:
609 	{
610 		struct sof_dai_private_data *private = sdai->private;
611 
612 		if (private->dai_config->type == SOF_DAI_INTEL_HDA)
613 			return &hda_ipc3_dma_ops;
614 		break;
615 	}
616 	case SOF_IPC_TYPE_4:
617 	{
618 		struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
619 		struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
620 
621 		switch (sdai->type) {
622 		case SOF_DAI_INTEL_HDA:
623 			if (pipeline->use_chain_dma)
624 				return &hda_ipc4_chain_dma_ops;
625 
626 			return &hda_ipc4_dma_ops;
627 		case SOF_DAI_INTEL_SSP:
628 			if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
629 				return NULL;
630 			return &ssp_ipc4_dma_ops;
631 		case SOF_DAI_INTEL_DMIC:
632 			if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
633 				return NULL;
634 			return &dmic_ipc4_dma_ops;
635 		case SOF_DAI_INTEL_ALH:
636 			if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
637 				return NULL;
638 			if (pipeline->use_chain_dma)
639 				return &sdw_ipc4_chain_dma_ops;
640 			return &sdw_ipc4_dma_ops;
641 
642 		default:
643 			break;
644 		}
645 		break;
646 	}
647 	default:
648 		break;
649 	}
650 #endif
651 	return NULL;
652 }
653