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