File Index
Files and directories
Sign in
FILE

hda-dai-ops.c

File preview with syntax highlighting.

linux-6.19.14/sound/soc/sof/intel/hda-dai-ops.c C
  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
  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 */
 27static 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
 44static struct hdac_ext_stream *
 45hda_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
118static 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
125static 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
145static 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 hdac_ext_stream *hext_stream;
150
151	hext_stream = hda_link_stream_assign(sof_to_bus(sdev), substream);
152	if (!hext_stream)
153		return NULL;
154
155	snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)hext_stream);
156
157	return hext_stream;
158}
159
160static void hda_release_hext_stream(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
161				    struct snd_pcm_substream *substream)
162{
163	struct hdac_ext_stream *hext_stream = hda_get_hext_stream(sdev, cpu_dai, substream);
164
165	snd_soc_dai_set_dma_data(cpu_dai, substream, NULL);
166	snd_hdac_ext_stream_release(hext_stream, HDAC_EXT_STREAM_TYPE_LINK);
167}
168
169static void hda_setup_hext_stream(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream,
170				  unsigned int format_val)
171{
172	snd_hdac_ext_stream_setup(hext_stream, format_val);
173}
174
175static void hda_reset_hext_stream(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream)
176{
177	snd_hdac_ext_stream_reset(hext_stream);
178}
179
180static void hda_codec_dai_set_stream(struct snd_sof_dev *sdev,
181				     struct snd_pcm_substream *substream,
182				     struct hdac_stream *hstream)
183{
184	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
185	struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
186
187	/* set the hdac_stream in the codec dai */
188	snd_soc_dai_set_stream(codec_dai, hstream, substream->stream);
189}
190
191static unsigned int hda_calc_stream_format(struct snd_sof_dev *sdev,
192					   struct snd_pcm_substream *substream,
193					   struct snd_pcm_hw_params *params)
194{
195	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
196	struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
197	unsigned int link_bps;
198	unsigned int format_val;
199	unsigned int bits;
200
201	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
202		link_bps = codec_dai->driver->playback.sig_bits;
203	else
204		link_bps = codec_dai->driver->capture.sig_bits;
205
206	bits = snd_hdac_stream_format_bits(params_format(params), SNDRV_PCM_SUBFORMAT_STD,
207					   link_bps);
208	format_val = snd_hdac_stream_format(params_channels(params), bits, params_rate(params));
209
210	dev_dbg(sdev->dev, "format_val=%#x, rate=%d, ch=%d, format=%d\n", format_val,
211		params_rate(params), params_channels(params), params_format(params));
212
213	return format_val;
214}
215
216static struct hdac_ext_link *hda_get_hlink(struct snd_sof_dev *sdev,
217					   struct snd_pcm_substream *substream)
218{
219	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
220	struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
221	struct hdac_bus *bus = sof_to_bus(sdev);
222
223	return snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name);
224}
225
226static unsigned int generic_calc_stream_format(struct snd_sof_dev *sdev,
227					       struct snd_pcm_substream *substream,
228					       struct snd_pcm_hw_params *params)
229{
230	unsigned int format_val;
231	unsigned int bits;
232
233	bits = snd_hdac_stream_format_bits(params_format(params), SNDRV_PCM_SUBFORMAT_STD,
234					   params_physical_width(params));
235	format_val = snd_hdac_stream_format(params_channels(params), bits, params_rate(params));
236
237	dev_dbg(sdev->dev, "format_val=%#x, rate=%d, ch=%d, format=%d\n", format_val,
238		params_rate(params), params_channels(params), params_format(params));
239
240	return format_val;
241}
242
243static unsigned int dmic_calc_stream_format(struct snd_sof_dev *sdev,
244					    struct snd_pcm_substream *substream,
245					    struct snd_pcm_hw_params *params)
246{
247	unsigned int format_val;
248	snd_pcm_format_t format;
249	unsigned int channels;
250	unsigned int width;
251	unsigned int bits;
252
253	channels = params_channels(params);
254	format = params_format(params);
255	width = params_physical_width(params);
256
257	if (format == SNDRV_PCM_FORMAT_S16_LE) {
258		format = SNDRV_PCM_FORMAT_S32_LE;
259		channels /= 2;
260		width = 32;
261	}
262
263	bits = snd_hdac_stream_format_bits(format, SNDRV_PCM_SUBFORMAT_STD, width);
264	format_val = snd_hdac_stream_format(channels, bits, params_rate(params));
265
266	dev_dbg(sdev->dev, "format_val=%#x, rate=%d, ch=%d, format=%d\n", format_val,
267		params_rate(params), channels, format);
268
269	return format_val;
270}
271
272static struct hdac_ext_link *ssp_get_hlink(struct snd_sof_dev *sdev,
273					   struct snd_pcm_substream *substream)
274{
275	struct hdac_bus *bus = sof_to_bus(sdev);
276
277	return hdac_bus_eml_ssp_get_hlink(bus);
278}
279
280static struct hdac_ext_link *dmic_get_hlink(struct snd_sof_dev *sdev,
281					    struct snd_pcm_substream *substream)
282{
283	struct hdac_bus *bus = sof_to_bus(sdev);
284
285	return hdac_bus_eml_dmic_get_hlink(bus);
286}
287
288static struct hdac_ext_link *sdw_get_hlink(struct snd_sof_dev *sdev,
289					   struct snd_pcm_substream *substream)
290{
291	struct hdac_bus *bus = sof_to_bus(sdev);
292
293	return hdac_bus_eml_sdw_get_hlink(bus);
294}
295
296static int hda_ipc4_pre_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
297				struct snd_pcm_substream *substream, int cmd)
298{
299	struct sof_ipc4_fw_data *ipc4_data = sdev->private;
300	struct snd_sof_widget *pipe_widget;
301	struct sof_ipc4_pipeline *pipeline;
302	struct snd_sof_widget *swidget;
303	struct snd_soc_dapm_widget *w;
304	int ret = 0;
305
306	w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
307	swidget = w->dobj.private;
308	pipe_widget = swidget->spipe->pipe_widget;
309	pipeline = pipe_widget->private;
310
311	if (pipe_widget->instance_id < 0)
312		return 0;
313
314	mutex_lock(&ipc4_data->pipeline_state_mutex);
315
316	switch (cmd) {
317	case SNDRV_PCM_TRIGGER_START:
318	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
319		break;
320	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
321	case SNDRV_PCM_TRIGGER_SUSPEND:
322	case SNDRV_PCM_TRIGGER_STOP:
323		ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
324						  SOF_IPC4_PIPE_PAUSED);
325		if (ret < 0)
326			goto out;
327
328		pipeline->state = SOF_IPC4_PIPE_PAUSED;
329		break;
330	default:
331		dev_err(sdev->dev, "unknown trigger command %d\n", cmd);
332		ret = -EINVAL;
333	}
334out:
335	mutex_unlock(&ipc4_data->pipeline_state_mutex);
336	return ret;
337}
338
339static int hda_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
340		       struct snd_pcm_substream *substream, int cmd)
341{
342	struct hdac_ext_stream *hext_stream = snd_soc_dai_get_dma_data(cpu_dai, substream);
343
344	switch (cmd) {
345	case SNDRV_PCM_TRIGGER_START:
346	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
347		snd_hdac_ext_stream_start(hext_stream);
348		break;
349	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
350		/*
351		 * Save the LLP registers since in case of PAUSE the LLP
352		 * register are not reset to 0, the delay calculation will use
353		 * the saved offsets for compensating the delay calculation.
354		 */
355		hext_stream->pplcllpl = readl(hext_stream->pplc_addr + AZX_REG_PPLCLLPL);
356		hext_stream->pplcllpu = readl(hext_stream->pplc_addr + AZX_REG_PPLCLLPU);
357		snd_hdac_ext_stream_clear(hext_stream);
358		break;
359	case SNDRV_PCM_TRIGGER_SUSPEND:
360	case SNDRV_PCM_TRIGGER_STOP:
361		hext_stream->pplcllpl = 0;
362		hext_stream->pplcllpu = 0;
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
373static 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	}
432out:
433	mutex_unlock(&ipc4_data->pipeline_state_mutex);
434	return ret;
435}
436
437static const struct hda_dai_widget_dma_ops hda_ipc4_dma_ops = {
438	.get_hext_stream = hda_ipc4_get_hext_stream,
439	.assign_hext_stream = hda_assign_hext_stream,
440	.release_hext_stream = hda_release_hext_stream,
441	.setup_hext_stream = hda_setup_hext_stream,
442	.reset_hext_stream = hda_reset_hext_stream,
443	.pre_trigger = hda_ipc4_pre_trigger,
444	.trigger = hda_trigger,
445	.post_trigger = hda_ipc4_post_trigger,
446	.codec_dai_set_stream = hda_codec_dai_set_stream,
447	.calc_stream_format = hda_calc_stream_format,
448	.get_hlink = hda_get_hlink,
449};
450
451static const struct hda_dai_widget_dma_ops ssp_ipc4_dma_ops = {
452	.get_hext_stream = hda_ipc4_get_hext_stream,
453	.assign_hext_stream = hda_assign_hext_stream,
454	.release_hext_stream = hda_release_hext_stream,
455	.setup_hext_stream = hda_setup_hext_stream,
456	.reset_hext_stream = hda_reset_hext_stream,
457	.pre_trigger = hda_ipc4_pre_trigger,
458	.trigger = hda_trigger,
459	.post_trigger = hda_ipc4_post_trigger,
460	.calc_stream_format = generic_calc_stream_format,
461	.get_hlink = ssp_get_hlink,
462};
463
464static const struct hda_dai_widget_dma_ops dmic_ipc4_dma_ops = {
465	.get_hext_stream = hda_ipc4_get_hext_stream,
466	.assign_hext_stream = hda_assign_hext_stream,
467	.release_hext_stream = hda_release_hext_stream,
468	.setup_hext_stream = hda_setup_hext_stream,
469	.reset_hext_stream = hda_reset_hext_stream,
470	.pre_trigger = hda_ipc4_pre_trigger,
471	.trigger = hda_trigger,
472	.post_trigger = hda_ipc4_post_trigger,
473	.calc_stream_format = dmic_calc_stream_format,
474	.get_hlink = dmic_get_hlink,
475};
476
477static const struct hda_dai_widget_dma_ops sdw_ipc4_dma_ops = {
478	.get_hext_stream = hda_ipc4_get_hext_stream,
479	.assign_hext_stream = hda_assign_hext_stream,
480	.release_hext_stream = hda_release_hext_stream,
481	.setup_hext_stream = hda_setup_hext_stream,
482	.reset_hext_stream = hda_reset_hext_stream,
483	.pre_trigger = hda_ipc4_pre_trigger,
484	.trigger = hda_trigger,
485	.post_trigger = hda_ipc4_post_trigger,
486	.calc_stream_format = generic_calc_stream_format,
487	.get_hlink = sdw_get_hlink,
488};
489
490static const struct hda_dai_widget_dma_ops hda_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	.codec_dai_set_stream = hda_codec_dai_set_stream,
498	.calc_stream_format = hda_calc_stream_format,
499	.get_hlink = hda_get_hlink,
500};
501
502static const struct hda_dai_widget_dma_ops sdw_ipc4_chain_dma_ops = {
503	.get_hext_stream = hda_get_hext_stream,
504	.assign_hext_stream = hda_assign_hext_stream,
505	.release_hext_stream = hda_release_hext_stream,
506	.setup_hext_stream = hda_setup_hext_stream,
507	.reset_hext_stream = hda_reset_hext_stream,
508	.trigger = hda_trigger,
509	.calc_stream_format = generic_calc_stream_format,
510	.get_hlink = sdw_get_hlink,
511};
512
513static int hda_ipc3_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
514				 struct snd_pcm_substream *substream, int cmd)
515{
516	struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
517
518	switch (cmd) {
519	case SNDRV_PCM_TRIGGER_SUSPEND:
520	case SNDRV_PCM_TRIGGER_STOP:
521	{
522		struct snd_sof_dai_config_data data = { 0 };
523		int ret;
524
525		data.dai_data = DMA_CHAN_INVALID;
526		ret = hda_dai_config(w, SOF_DAI_CONFIG_FLAGS_HW_FREE, &data);
527		if (ret < 0)
528			return ret;
529
530		break;
531	}
532	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
533		return hda_dai_config(w, SOF_DAI_CONFIG_FLAGS_PAUSE, NULL);
534	default:
535		break;
536	}
537
538	return 0;
539}
540
541static const struct hda_dai_widget_dma_ops hda_ipc3_dma_ops = {
542	.get_hext_stream = hda_get_hext_stream,
543	.assign_hext_stream = hda_assign_hext_stream,
544	.release_hext_stream = hda_release_hext_stream,
545	.setup_hext_stream = hda_setup_hext_stream,
546	.reset_hext_stream = hda_reset_hext_stream,
547	.trigger = hda_trigger,
548	.post_trigger = hda_ipc3_post_trigger,
549	.codec_dai_set_stream = hda_codec_dai_set_stream,
550	.calc_stream_format = hda_calc_stream_format,
551	.get_hlink = hda_get_hlink,
552};
553
554static struct hdac_ext_stream *
555hda_dspless_get_hext_stream(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
556			    struct snd_pcm_substream *substream)
557{
558	struct hdac_stream *hstream = substream->runtime->private_data;
559
560	return stream_to_hdac_ext_stream(hstream);
561}
562
563static void hda_dspless_setup_hext_stream(struct snd_sof_dev *sdev,
564					  struct hdac_ext_stream *hext_stream,
565					  unsigned int format_val)
566{
567	/*
568	 * Save the format_val which was adjusted by the maxbps of the codec.
569	 * This information is not available on the FE side since there we are
570	 * using dummy_codec.
571	 */
572	hext_stream->hstream.format_val = format_val;
573}
574
575static const struct hda_dai_widget_dma_ops hda_dspless_dma_ops = {
576	.get_hext_stream = hda_dspless_get_hext_stream,
577	.setup_hext_stream = hda_dspless_setup_hext_stream,
578	.codec_dai_set_stream = hda_codec_dai_set_stream,
579	.calc_stream_format = hda_calc_stream_format,
580	.get_hlink = hda_get_hlink,
581};
582
583static const struct hda_dai_widget_dma_ops sdw_dspless_dma_ops = {
584	.get_hext_stream = hda_dspless_get_hext_stream,
585	.setup_hext_stream = hda_dspless_setup_hext_stream,
586	.calc_stream_format = generic_calc_stream_format,
587	.get_hlink = sdw_get_hlink,
588};
589
590#endif
591
592const struct hda_dai_widget_dma_ops *
593hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
594{
595#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK)
596	struct snd_sof_dai *sdai;
597	const struct sof_intel_dsp_desc *chip;
598
599	chip = get_chip_info(sdev->pdata);
600	sdai = swidget->private;
601
602	if (sdev->dspless_mode_selected) {
603		switch (sdai->type) {
604		case SOF_DAI_INTEL_HDA:
605			return &hda_dspless_dma_ops;
606		case SOF_DAI_INTEL_ALH:
607			if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
608				return NULL;
609			return &sdw_dspless_dma_ops;
610		default:
611			return NULL;
612		}
613	}
614
615	switch (sdev->pdata->ipc_type) {
616	case SOF_IPC_TYPE_3:
617	{
618		struct sof_dai_private_data *private = sdai->private;
619
620		if (private->dai_config->type == SOF_DAI_INTEL_HDA)
621			return &hda_ipc3_dma_ops;
622		break;
623	}
624	case SOF_IPC_TYPE_4:
625	{
626		struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
627		struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
628
629		switch (sdai->type) {
630		case SOF_DAI_INTEL_HDA:
631			if (pipeline->use_chain_dma)
632				return &hda_ipc4_chain_dma_ops;
633
634			return &hda_ipc4_dma_ops;
635		case SOF_DAI_INTEL_SSP:
636			if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
637				return NULL;
638			return &ssp_ipc4_dma_ops;
639		case SOF_DAI_INTEL_DMIC:
640			if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
641				return NULL;
642			return &dmic_ipc4_dma_ops;
643		case SOF_DAI_INTEL_ALH:
644			if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
645				return NULL;
646			if (pipeline->use_chain_dma)
647				return &sdw_ipc4_chain_dma_ops;
648			return &sdw_ipc4_dma_ops;
649
650		default:
651			break;
652		}
653		break;
654	}
655	default:
656		break;
657	}
658#endif
659	return NULL;
660}
~/ Read-only file preview.