xref: /openbmc/linux/sound/soc/sof/intel/hda-dai-ops.c (revision c4c3c32d)
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 = asoc_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 snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
149 	struct snd_soc_dai *dai;
150 	struct hdac_ext_stream *hext_stream;
151 
152 	/* only allocate a stream_tag for the first DAI in the dailink */
153 	dai = asoc_rtd_to_cpu(rtd, 0);
154 	if (dai == cpu_dai)
155 		hext_stream = hda_link_stream_assign(sof_to_bus(sdev), substream);
156 	else
157 		hext_stream = snd_soc_dai_get_dma_data(dai, substream);
158 
159 	if (!hext_stream)
160 		return NULL;
161 
162 	snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)hext_stream);
163 
164 	return hext_stream;
165 }
166 
167 static void hda_release_hext_stream(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
168 				    struct snd_pcm_substream *substream)
169 {
170 	struct hdac_ext_stream *hext_stream = hda_get_hext_stream(sdev, cpu_dai, substream);
171 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
172 	struct snd_soc_dai *dai;
173 
174 	/* only release a stream_tag for the first DAI in the dailink */
175 	dai = asoc_rtd_to_cpu(rtd, 0);
176 	if (dai == cpu_dai)
177 		snd_hdac_ext_stream_release(hext_stream, HDAC_EXT_STREAM_TYPE_LINK);
178 	snd_soc_dai_set_dma_data(cpu_dai, substream, NULL);
179 }
180 
181 static void hda_setup_hext_stream(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream,
182 				  unsigned int format_val)
183 {
184 	snd_hdac_ext_stream_setup(hext_stream, format_val);
185 }
186 
187 static void hda_reset_hext_stream(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream)
188 {
189 	snd_hdac_ext_stream_reset(hext_stream);
190 }
191 
192 static void hda_codec_dai_set_stream(struct snd_sof_dev *sdev,
193 				     struct snd_pcm_substream *substream,
194 				     struct hdac_stream *hstream)
195 {
196 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
197 	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
198 
199 	/* set the hdac_stream in the codec dai */
200 	snd_soc_dai_set_stream(codec_dai, hstream, substream->stream);
201 }
202 
203 static unsigned int hda_calc_stream_format(struct snd_sof_dev *sdev,
204 					   struct snd_pcm_substream *substream,
205 					   struct snd_pcm_hw_params *params)
206 {
207 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
208 	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
209 	unsigned int link_bps;
210 	unsigned int format_val;
211 
212 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
213 		link_bps = codec_dai->driver->playback.sig_bits;
214 	else
215 		link_bps = codec_dai->driver->capture.sig_bits;
216 
217 	format_val = snd_hdac_calc_stream_format(params_rate(params), params_channels(params),
218 						 params_format(params), link_bps, 0);
219 
220 	dev_dbg(sdev->dev, "format_val=%#x, rate=%d, ch=%d, format=%d\n", format_val,
221 		params_rate(params), params_channels(params), params_format(params));
222 
223 	return format_val;
224 }
225 
226 static struct hdac_ext_link *hda_get_hlink(struct snd_sof_dev *sdev,
227 					   struct snd_pcm_substream *substream)
228 {
229 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
230 	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
231 	struct hdac_bus *bus = sof_to_bus(sdev);
232 
233 	return snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name);
234 }
235 
236 static unsigned int generic_calc_stream_format(struct snd_sof_dev *sdev,
237 					       struct snd_pcm_substream *substream,
238 					       struct snd_pcm_hw_params *params)
239 {
240 	unsigned int format_val;
241 
242 	format_val = snd_hdac_calc_stream_format(params_rate(params), params_channels(params),
243 						 params_format(params),
244 						 params_physical_width(params),
245 						 0);
246 
247 	dev_dbg(sdev->dev, "format_val=%#x, rate=%d, ch=%d, format=%d\n", format_val,
248 		params_rate(params), params_channels(params), params_format(params));
249 
250 	return format_val;
251 }
252 
253 static unsigned int dmic_calc_stream_format(struct snd_sof_dev *sdev,
254 					    struct snd_pcm_substream *substream,
255 					    struct snd_pcm_hw_params *params)
256 {
257 	unsigned int format_val;
258 	snd_pcm_format_t format;
259 	unsigned int channels;
260 	unsigned int width;
261 
262 	channels = params_channels(params);
263 	format = params_format(params);
264 	width = params_physical_width(params);
265 
266 	if (format == SNDRV_PCM_FORMAT_S16_LE) {
267 		format = SNDRV_PCM_FORMAT_S32_LE;
268 		channels /= 2;
269 		width = 32;
270 	}
271 
272 	format_val = snd_hdac_calc_stream_format(params_rate(params), channels,
273 						 format,
274 						 width,
275 						 0);
276 
277 	dev_dbg(sdev->dev, "format_val=%#x, rate=%d, ch=%d, format=%d\n", format_val,
278 		params_rate(params), channels, format);
279 
280 	return format_val;
281 }
282 
283 static struct hdac_ext_link *ssp_get_hlink(struct snd_sof_dev *sdev,
284 					   struct snd_pcm_substream *substream)
285 {
286 	struct hdac_bus *bus = sof_to_bus(sdev);
287 
288 	return hdac_bus_eml_ssp_get_hlink(bus);
289 }
290 
291 static struct hdac_ext_link *dmic_get_hlink(struct snd_sof_dev *sdev,
292 					    struct snd_pcm_substream *substream)
293 {
294 	struct hdac_bus *bus = sof_to_bus(sdev);
295 
296 	return hdac_bus_eml_dmic_get_hlink(bus);
297 }
298 
299 static struct hdac_ext_link *sdw_get_hlink(struct snd_sof_dev *sdev,
300 					   struct snd_pcm_substream *substream)
301 {
302 	struct hdac_bus *bus = sof_to_bus(sdev);
303 
304 	return hdac_bus_eml_sdw_get_hlink(bus);
305 }
306 
307 static int hda_ipc4_pre_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
308 				struct snd_pcm_substream *substream, int cmd)
309 {
310 	struct sof_ipc4_fw_data *ipc4_data = sdev->private;
311 	struct snd_sof_widget *pipe_widget;
312 	struct sof_ipc4_pipeline *pipeline;
313 	struct snd_sof_widget *swidget;
314 	struct snd_soc_dapm_widget *w;
315 	int ret = 0;
316 
317 	w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
318 	swidget = w->dobj.private;
319 	pipe_widget = swidget->spipe->pipe_widget;
320 	pipeline = pipe_widget->private;
321 
322 	if (pipe_widget->instance_id < 0)
323 		return 0;
324 
325 	mutex_lock(&ipc4_data->pipeline_state_mutex);
326 
327 	switch (cmd) {
328 	case SNDRV_PCM_TRIGGER_START:
329 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
330 		break;
331 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
332 	case SNDRV_PCM_TRIGGER_SUSPEND:
333 	case SNDRV_PCM_TRIGGER_STOP:
334 		ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
335 						  SOF_IPC4_PIPE_PAUSED);
336 		if (ret < 0)
337 			goto out;
338 
339 		pipeline->state = SOF_IPC4_PIPE_PAUSED;
340 		break;
341 	default:
342 		dev_err(sdev->dev, "unknown trigger command %d\n", cmd);
343 		ret = -EINVAL;
344 	}
345 out:
346 	mutex_unlock(&ipc4_data->pipeline_state_mutex);
347 	return ret;
348 }
349 
350 static int hda_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
351 		       struct snd_pcm_substream *substream, int cmd)
352 {
353 	struct hdac_ext_stream *hext_stream = snd_soc_dai_get_dma_data(cpu_dai, substream);
354 
355 	switch (cmd) {
356 	case SNDRV_PCM_TRIGGER_START:
357 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
358 		snd_hdac_ext_stream_start(hext_stream);
359 		break;
360 	case SNDRV_PCM_TRIGGER_SUSPEND:
361 	case SNDRV_PCM_TRIGGER_STOP:
362 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
363 		snd_hdac_ext_stream_clear(hext_stream);
364 		break;
365 	default:
366 		dev_err(sdev->dev, "unknown trigger command %d\n", cmd);
367 		return -EINVAL;
368 	}
369 
370 	return 0;
371 }
372 
373 static int hda_ipc4_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
374 				 struct snd_pcm_substream *substream, int cmd)
375 {
376 	struct sof_ipc4_fw_data *ipc4_data = sdev->private;
377 	struct snd_sof_widget *pipe_widget;
378 	struct sof_ipc4_pipeline *pipeline;
379 	struct snd_sof_widget *swidget;
380 	struct snd_soc_dapm_widget *w;
381 	int ret = 0;
382 
383 	w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
384 	swidget = w->dobj.private;
385 	pipe_widget = swidget->spipe->pipe_widget;
386 	pipeline = pipe_widget->private;
387 
388 	if (pipe_widget->instance_id < 0)
389 		return 0;
390 
391 	mutex_lock(&ipc4_data->pipeline_state_mutex);
392 
393 	switch (cmd) {
394 	case SNDRV_PCM_TRIGGER_START:
395 		if (pipeline->state != SOF_IPC4_PIPE_PAUSED) {
396 			ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
397 							  SOF_IPC4_PIPE_PAUSED);
398 			if (ret < 0)
399 				goto out;
400 			pipeline->state = SOF_IPC4_PIPE_PAUSED;
401 		}
402 
403 		ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
404 						  SOF_IPC4_PIPE_RUNNING);
405 		if (ret < 0)
406 			goto out;
407 		pipeline->state = SOF_IPC4_PIPE_RUNNING;
408 		swidget->spipe->started_count++;
409 		break;
410 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
411 		ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
412 						  SOF_IPC4_PIPE_RUNNING);
413 		if (ret < 0)
414 			goto out;
415 		pipeline->state = SOF_IPC4_PIPE_RUNNING;
416 		break;
417 	case SNDRV_PCM_TRIGGER_SUSPEND:
418 	case SNDRV_PCM_TRIGGER_STOP:
419 		/*
420 		 * STOP/SUSPEND trigger is invoked only once when all users of this pipeline have
421 		 * been stopped. So, clear the started_count so that the pipeline can be reset
422 		 */
423 		swidget->spipe->started_count = 0;
424 		break;
425 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
426 		break;
427 	default:
428 		dev_err(sdev->dev, "unknown trigger command %d\n", cmd);
429 		ret = -EINVAL;
430 		break;
431 	}
432 out:
433 	mutex_unlock(&ipc4_data->pipeline_state_mutex);
434 	return ret;
435 }
436 
437 static struct hdac_ext_stream *sdw_hda_ipc4_get_hext_stream(struct snd_sof_dev *sdev,
438 							    struct snd_soc_dai *cpu_dai,
439 							    struct snd_pcm_substream *substream)
440 {
441 	struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
442 	struct snd_sof_widget *swidget = w->dobj.private;
443 	struct snd_sof_dai *dai = swidget->private;
444 	struct sof_ipc4_copier *ipc4_copier = dai->private;
445 	struct sof_ipc4_alh_configuration_blob *blob;
446 
447 	blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config;
448 
449 	/*
450 	 * Starting with ACE_2_0, re-setting the device_count is mandatory to avoid using
451 	 * the multi-gateway firmware configuration. The DMA hardware can take care of
452 	 * multiple links without needing any firmware assistance
453 	 */
454 	blob->alh_cfg.device_count = 1;
455 
456 	return hda_ipc4_get_hext_stream(sdev, cpu_dai, substream);
457 }
458 
459 static const struct hda_dai_widget_dma_ops hda_ipc4_dma_ops = {
460 	.get_hext_stream = hda_ipc4_get_hext_stream,
461 	.assign_hext_stream = hda_assign_hext_stream,
462 	.release_hext_stream = hda_release_hext_stream,
463 	.setup_hext_stream = hda_setup_hext_stream,
464 	.reset_hext_stream = hda_reset_hext_stream,
465 	.pre_trigger = hda_ipc4_pre_trigger,
466 	.trigger = hda_trigger,
467 	.post_trigger = hda_ipc4_post_trigger,
468 	.codec_dai_set_stream = hda_codec_dai_set_stream,
469 	.calc_stream_format = hda_calc_stream_format,
470 	.get_hlink = hda_get_hlink,
471 };
472 
473 static const struct hda_dai_widget_dma_ops ssp_ipc4_dma_ops = {
474 	.get_hext_stream = hda_ipc4_get_hext_stream,
475 	.assign_hext_stream = hda_assign_hext_stream,
476 	.release_hext_stream = hda_release_hext_stream,
477 	.setup_hext_stream = hda_setup_hext_stream,
478 	.reset_hext_stream = hda_reset_hext_stream,
479 	.pre_trigger = hda_ipc4_pre_trigger,
480 	.trigger = hda_trigger,
481 	.post_trigger = hda_ipc4_post_trigger,
482 	.calc_stream_format = generic_calc_stream_format,
483 	.get_hlink = ssp_get_hlink,
484 };
485 
486 static const struct hda_dai_widget_dma_ops dmic_ipc4_dma_ops = {
487 	.get_hext_stream = hda_ipc4_get_hext_stream,
488 	.assign_hext_stream = hda_assign_hext_stream,
489 	.release_hext_stream = hda_release_hext_stream,
490 	.setup_hext_stream = hda_setup_hext_stream,
491 	.reset_hext_stream = hda_reset_hext_stream,
492 	.pre_trigger = hda_ipc4_pre_trigger,
493 	.trigger = hda_trigger,
494 	.post_trigger = hda_ipc4_post_trigger,
495 	.calc_stream_format = dmic_calc_stream_format,
496 	.get_hlink = dmic_get_hlink,
497 };
498 
499 static const struct hda_dai_widget_dma_ops sdw_ipc4_dma_ops = {
500 	.get_hext_stream = sdw_hda_ipc4_get_hext_stream,
501 	.assign_hext_stream = hda_assign_hext_stream,
502 	.release_hext_stream = hda_release_hext_stream,
503 	.setup_hext_stream = hda_setup_hext_stream,
504 	.reset_hext_stream = hda_reset_hext_stream,
505 	.pre_trigger = hda_ipc4_pre_trigger,
506 	.trigger = hda_trigger,
507 	.post_trigger = hda_ipc4_post_trigger,
508 	.calc_stream_format = generic_calc_stream_format,
509 	.get_hlink = sdw_get_hlink,
510 };
511 
512 static const struct hda_dai_widget_dma_ops hda_ipc4_chain_dma_ops = {
513 	.get_hext_stream = hda_get_hext_stream,
514 	.assign_hext_stream = hda_assign_hext_stream,
515 	.release_hext_stream = hda_release_hext_stream,
516 	.setup_hext_stream = hda_setup_hext_stream,
517 	.reset_hext_stream = hda_reset_hext_stream,
518 	.trigger = hda_trigger,
519 	.codec_dai_set_stream = hda_codec_dai_set_stream,
520 	.calc_stream_format = hda_calc_stream_format,
521 	.get_hlink = hda_get_hlink,
522 };
523 
524 static int hda_ipc3_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
525 				 struct snd_pcm_substream *substream, int cmd)
526 {
527 	struct hdac_ext_stream *hext_stream = hda_get_hext_stream(sdev, cpu_dai, substream);
528 	struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
529 
530 	switch (cmd) {
531 	case SNDRV_PCM_TRIGGER_SUSPEND:
532 	case SNDRV_PCM_TRIGGER_STOP:
533 	{
534 		struct snd_sof_dai_config_data data = { 0 };
535 		int ret;
536 
537 		data.dai_data = DMA_CHAN_INVALID;
538 		ret = hda_dai_config(w, SOF_DAI_CONFIG_FLAGS_HW_FREE, &data);
539 		if (ret < 0)
540 			return ret;
541 
542 		if (cmd == SNDRV_PCM_TRIGGER_STOP)
543 			return hda_link_dma_cleanup(substream, hext_stream, cpu_dai);
544 
545 		break;
546 	}
547 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
548 		return hda_dai_config(w, SOF_DAI_CONFIG_FLAGS_PAUSE, NULL);
549 	default:
550 		break;
551 	}
552 
553 	return 0;
554 }
555 
556 static const struct hda_dai_widget_dma_ops hda_ipc3_dma_ops = {
557 	.get_hext_stream = hda_get_hext_stream,
558 	.assign_hext_stream = hda_assign_hext_stream,
559 	.release_hext_stream = hda_release_hext_stream,
560 	.setup_hext_stream = hda_setup_hext_stream,
561 	.reset_hext_stream = hda_reset_hext_stream,
562 	.trigger = hda_trigger,
563 	.post_trigger = hda_ipc3_post_trigger,
564 	.codec_dai_set_stream = hda_codec_dai_set_stream,
565 	.calc_stream_format = hda_calc_stream_format,
566 	.get_hlink = hda_get_hlink,
567 };
568 
569 static struct hdac_ext_stream *
570 hda_dspless_get_hext_stream(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
571 			    struct snd_pcm_substream *substream)
572 {
573 	struct hdac_stream *hstream = substream->runtime->private_data;
574 
575 	return stream_to_hdac_ext_stream(hstream);
576 }
577 
578 static void hda_dspless_setup_hext_stream(struct snd_sof_dev *sdev,
579 					  struct hdac_ext_stream *hext_stream,
580 					  unsigned int format_val)
581 {
582 	/*
583 	 * Save the format_val which was adjusted by the maxbps of the codec.
584 	 * This information is not available on the FE side since there we are
585 	 * using dummy_codec.
586 	 */
587 	hext_stream->hstream.format_val = format_val;
588 }
589 
590 static const struct hda_dai_widget_dma_ops hda_dspless_dma_ops = {
591 	.get_hext_stream = hda_dspless_get_hext_stream,
592 	.setup_hext_stream = hda_dspless_setup_hext_stream,
593 	.codec_dai_set_stream = hda_codec_dai_set_stream,
594 	.calc_stream_format = hda_calc_stream_format,
595 	.get_hlink = hda_get_hlink,
596 };
597 
598 #endif
599 
600 const struct hda_dai_widget_dma_ops *
601 hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
602 {
603 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK)
604 	struct snd_sof_dai *sdai;
605 
606 	if (sdev->dspless_mode_selected)
607 		return &hda_dspless_dma_ops;
608 
609 	sdai = swidget->private;
610 
611 	switch (sdev->pdata->ipc_type) {
612 	case SOF_IPC:
613 	{
614 		struct sof_dai_private_data *private = sdai->private;
615 
616 		if (private->dai_config->type == SOF_DAI_INTEL_HDA)
617 			return &hda_ipc3_dma_ops;
618 		break;
619 	}
620 	case SOF_INTEL_IPC4:
621 	{
622 		struct sof_ipc4_copier *ipc4_copier = sdai->private;
623 		const struct sof_intel_dsp_desc *chip;
624 
625 		chip = get_chip_info(sdev->pdata);
626 
627 		switch (ipc4_copier->dai_type) {
628 		case SOF_DAI_INTEL_HDA:
629 		{
630 			struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
631 			struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
632 
633 			if (pipeline->use_chain_dma)
634 				return &hda_ipc4_chain_dma_ops;
635 
636 			return &hda_ipc4_dma_ops;
637 		}
638 		case SOF_DAI_INTEL_SSP:
639 			if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
640 				return NULL;
641 			return &ssp_ipc4_dma_ops;
642 		case SOF_DAI_INTEL_DMIC:
643 			if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
644 				return NULL;
645 			return &dmic_ipc4_dma_ops;
646 		case SOF_DAI_INTEL_ALH:
647 			if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
648 				return NULL;
649 			return &sdw_ipc4_dma_ops;
650 
651 		default:
652 			break;
653 		}
654 		break;
655 	}
656 	default:
657 		break;
658 	}
659 #endif
660 	return NULL;
661 }
662