Linux Audio

Check our new training course

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