Linux Audio

Check our new training course

Loading...
v6.8
  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) 2018 Intel Corporation. All rights reserved.
  7//
  8// Authors: Keyon Jie <yang.jie@linux.intel.com>
  9//
 10
 11#include <sound/pcm_params.h>
 12#include <sound/hdaudio_ext.h>
 13#include <sound/hda-mlink.h>
 14#include <sound/hda_register.h>
 15#include <sound/intel-nhlt.h>
 16#include <sound/sof/ipc4/header.h>
 17#include <uapi/sound/sof/header.h>
 18#include "../ipc4-priv.h"
 19#include "../ipc4-topology.h"
 20#include "../sof-priv.h"
 21#include "../sof-audio.h"
 22#include "hda.h"
 23
 24/*
 25 * The default method is to fetch NHLT from BIOS. With this parameter set
 26 * it is possible to override that with NHLT in the SOF topology manifest.
 27 */
 28static bool hda_use_tplg_nhlt;
 29module_param_named(sof_use_tplg_nhlt, hda_use_tplg_nhlt, bool, 0444);
 30MODULE_PARM_DESC(sof_use_tplg_nhlt, "SOF topology nhlt override");
 31
 32static struct snd_sof_dev *widget_to_sdev(struct snd_soc_dapm_widget *w)
 33{
 34	struct snd_sof_widget *swidget = w->dobj.private;
 35	struct snd_soc_component *component = swidget->scomp;
 36
 37	return snd_soc_component_get_drvdata(component);
 38}
 39
 40int hda_dai_config(struct snd_soc_dapm_widget *w, unsigned int flags,
 41		   struct snd_sof_dai_config_data *data)
 42{
 43	struct snd_sof_widget *swidget = w->dobj.private;
 44	const struct sof_ipc_tplg_ops *tplg_ops;
 45	struct snd_sof_dev *sdev;
 46	int ret;
 47
 48	if (!swidget)
 49		return 0;
 50
 51	sdev = widget_to_sdev(w);
 52	tplg_ops = sof_ipc_get_ops(sdev, tplg);
 53
 54	if (tplg_ops && tplg_ops->dai_config) {
 55		ret = tplg_ops->dai_config(sdev, swidget, flags, data);
 56		if (ret < 0) {
 57			dev_err(sdev->dev, "DAI config with flags %x failed for widget %s\n",
 58				flags, w->name);
 59			return ret;
 60		}
 61	}
 62
 63	return 0;
 64}
 
 65
 66#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK)
 67
 68static struct snd_sof_dev *dai_to_sdev(struct snd_pcm_substream *substream,
 69				       struct snd_soc_dai *cpu_dai)
 70{
 71	struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
 72
 73	return widget_to_sdev(w);
 74}
 75
 76static const struct hda_dai_widget_dma_ops *
 77hda_dai_get_ops(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai)
 78{
 79	struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
 80	struct snd_sof_widget *swidget = w->dobj.private;
 81	struct snd_sof_dev *sdev;
 82	struct snd_sof_dai *sdai;
 83
 84	sdev = widget_to_sdev(w);
 85
 86	/*
 87	 * The swidget parameter of hda_select_dai_widget_ops() is ignored in
 88	 * case of DSPless mode
 89	 */
 
 90	if (sdev->dspless_mode_selected)
 91		return hda_select_dai_widget_ops(sdev, NULL);
 92
 93	sdai = swidget->private;
 94
 95	/* select and set the DAI widget ops if not set already */
 96	if (!sdai->platform_private) {
 97		const struct hda_dai_widget_dma_ops *ops =
 98			hda_select_dai_widget_ops(sdev, swidget);
 99		if (!ops)
100			return NULL;
101
102		/* check if mandatory ops are set */
103		if (!ops || !ops->get_hext_stream)
104			return NULL;
105
106		sdai->platform_private = ops;
107	}
108
109	return sdai->platform_private;
110}
111
112int hda_link_dma_cleanup(struct snd_pcm_substream *substream, struct hdac_ext_stream *hext_stream,
113			 struct snd_soc_dai *cpu_dai)
 
 
114{
115	const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, cpu_dai);
116	struct sof_intel_hda_stream *hda_stream;
117	struct hdac_ext_link *hlink;
118	struct snd_sof_dev *sdev;
119	int stream_tag;
120
121	if (!ops) {
122		dev_err(cpu_dai->dev, "DAI widget ops not set\n");
123		return -EINVAL;
124	}
125
126	sdev = dai_to_sdev(substream, cpu_dai);
127
128	hlink = ops->get_hlink(sdev, substream);
129	if (!hlink)
130		return -EINVAL;
131
132	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
133		stream_tag = hdac_stream(hext_stream)->stream_tag;
134		snd_hdac_ext_bus_link_clear_stream_id(hlink, stream_tag);
135	}
136
 
 
 
 
 
 
 
 
 
 
 
137	if (ops->release_hext_stream)
138		ops->release_hext_stream(sdev, cpu_dai, substream);
139
140	hext_stream->link_prepared = 0;
141
142	/* free the host DMA channel reserved by hostless streams */
143	hda_stream = hstream_to_sof_hda_stream(hext_stream);
144	hda_stream->host_reserved = 0;
145
146	return 0;
147}
148
149static int hda_link_dma_hw_params(struct snd_pcm_substream *substream,
150				  struct snd_pcm_hw_params *params, struct snd_soc_dai *cpu_dai)
151{
152	const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, cpu_dai);
153	struct hdac_ext_stream *hext_stream;
154	struct hdac_stream *hstream;
155	struct hdac_ext_link *hlink;
156	struct snd_sof_dev *sdev;
157	int stream_tag;
158
159	if (!ops) {
160		dev_err(cpu_dai->dev, "DAI widget ops not set\n");
161		return -EINVAL;
162	}
163
164	sdev = dai_to_sdev(substream, cpu_dai);
165
166	hlink = ops->get_hlink(sdev, substream);
167	if (!hlink)
168		return -EINVAL;
169
170	hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream);
171
172	if (!hext_stream) {
173		if (ops->assign_hext_stream)
174			hext_stream = ops->assign_hext_stream(sdev, cpu_dai, substream);
175	}
176
177	if (!hext_stream)
178		return -EBUSY;
179
180	hstream = &hext_stream->hstream;
181	stream_tag = hstream->stream_tag;
182
183	if (hext_stream->hstream.direction == SNDRV_PCM_STREAM_PLAYBACK)
184		snd_hdac_ext_bus_link_set_stream_id(hlink, stream_tag);
185
186	/* set the hdac_stream in the codec dai */
187	if (ops->codec_dai_set_stream)
188		ops->codec_dai_set_stream(sdev, substream, hstream);
189
190	if (ops->reset_hext_stream)
191		ops->reset_hext_stream(sdev, hext_stream);
192
193	if (ops->calc_stream_format && ops->setup_hext_stream) {
194		unsigned int format_val = ops->calc_stream_format(sdev, substream, params);
195
196		ops->setup_hext_stream(sdev, hext_stream, format_val);
197	}
198
199	hext_stream->link_prepared = 1;
200
201	return 0;
202}
203
204static int __maybe_unused hda_dai_hw_free(struct snd_pcm_substream *substream,
205					  struct snd_soc_dai *cpu_dai)
206{
207	const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, cpu_dai);
208	struct hdac_ext_stream *hext_stream;
209	struct snd_sof_dev *sdev = dai_to_sdev(substream, cpu_dai);
210
211	if (!ops) {
212		dev_err(cpu_dai->dev, "DAI widget ops not set\n");
213		return -EINVAL;
214	}
215
216	hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream);
217	if (!hext_stream)
218		return 0;
219
220	return hda_link_dma_cleanup(substream, hext_stream, cpu_dai);
221}
222
223static int __maybe_unused hda_dai_hw_params(struct snd_pcm_substream *substream,
224					    struct snd_pcm_hw_params *params,
225					    struct snd_soc_dai *dai)
 
 
226{
227	struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(dai, substream->stream);
228	const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, dai);
229	struct hdac_ext_stream *hext_stream;
230	struct snd_sof_dai_config_data data = { 0 };
231	unsigned int flags = SOF_DAI_CONFIG_FLAGS_HW_PARAMS;
232	struct snd_sof_dev *sdev = widget_to_sdev(w);
233	int ret;
234
235	if (!ops) {
236		dev_err(sdev->dev, "DAI widget ops not set\n");
237		return -EINVAL;
238	}
239
240	hext_stream = ops->get_hext_stream(sdev, dai, substream);
241	if (hext_stream && hext_stream->link_prepared)
242		return 0;
243
244	ret = hda_link_dma_hw_params(substream, params, dai);
245	if (ret < 0)
246		return ret;
247
248	hext_stream = ops->get_hext_stream(sdev, dai, substream);
249
250	flags |= SOF_DAI_CONFIG_FLAGS_2_STEP_STOP << SOF_DAI_CONFIG_FLAGS_QUIRK_SHIFT;
251	data.dai_data = hdac_stream(hext_stream)->stream_tag - 1;
 
 
 
 
 
 
 
 
 
 
252
253	return hda_dai_config(w, flags, &data);
254}
255
256/*
257 * In contrast to IPC3, the dai trigger in IPC4 mixes pipeline state changes
258 * (over IPC channel) and DMA state change (direct host register changes).
259 */
260static int __maybe_unused hda_dai_trigger(struct snd_pcm_substream *substream, int cmd,
261					  struct snd_soc_dai *dai)
262{
263	const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, dai);
264	struct hdac_ext_stream *hext_stream;
265	struct snd_sof_dev *sdev;
266	int ret;
267
268	if (!ops) {
269		dev_err(dai->dev, "DAI widget ops not set\n");
270		return -EINVAL;
271	}
272
273	dev_dbg(dai->dev, "cmd=%d dai %s direction %d\n", cmd,
274		dai->name, substream->stream);
275
276	sdev = dai_to_sdev(substream, dai);
277
278	hext_stream = ops->get_hext_stream(sdev, dai, substream);
279	if (!hext_stream)
280		return -EINVAL;
281
282	if (ops->pre_trigger) {
283		ret = ops->pre_trigger(sdev, dai, substream, cmd);
284		if (ret < 0)
285			return ret;
286	}
287
288	if (ops->trigger) {
289		ret = ops->trigger(sdev, dai, substream, cmd);
290		if (ret < 0)
291			return ret;
292	}
293
294	if (ops->post_trigger) {
295		ret = ops->post_trigger(sdev, dai, substream, cmd);
296		if (ret < 0)
297			return ret;
298	}
299
300	switch (cmd) {
 
301	case SNDRV_PCM_TRIGGER_SUSPEND:
302		ret = hda_link_dma_cleanup(substream, hext_stream, dai);
 
303		if (ret < 0) {
304			dev_err(sdev->dev, "%s: failed to clean up link DMA\n", __func__);
305			return ret;
306		}
307		break;
308	default:
309		break;
310	}
311
312	return 0;
313}
314
315#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
316
317static int hda_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
318{
319	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
320	int stream = substream->stream;
321
322	return hda_dai_hw_params(substream, &rtd->dpcm[stream].hw_params, dai);
323}
324
325static const struct snd_soc_dai_ops hda_dai_ops = {
326	.hw_params = hda_dai_hw_params,
327	.hw_free = hda_dai_hw_free,
328	.trigger = hda_dai_trigger,
329	.prepare = hda_dai_prepare,
330};
331
332#endif
333
334static struct sof_ipc4_copier *widget_to_copier(struct snd_soc_dapm_widget *w)
335{
336	struct snd_sof_widget *swidget = w->dobj.private;
337	struct snd_sof_dai *sdai = swidget->private;
338	struct sof_ipc4_copier *ipc4_copier = (struct sof_ipc4_copier *)sdai->private;
339
340	return ipc4_copier;
341}
342
343static int non_hda_dai_hw_params(struct snd_pcm_substream *substream,
344				 struct snd_pcm_hw_params *params,
345				 struct snd_soc_dai *cpu_dai)
 
 
346{
347	struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
 
348	struct sof_ipc4_dma_config_tlv *dma_config_tlv;
349	const struct hda_dai_widget_dma_ops *ops;
350	struct sof_ipc4_dma_config *dma_config;
351	struct sof_ipc4_copier *ipc4_copier;
352	struct hdac_ext_stream *hext_stream;
353	struct hdac_stream *hstream;
354	struct snd_sof_dev *sdev;
 
 
355	int stream_id;
356	int ret;
357
358	ops = hda_dai_get_ops(substream, cpu_dai);
359	if (!ops) {
360		dev_err(cpu_dai->dev, "DAI widget ops not set\n");
361		return -EINVAL;
362	}
363
 
 
 
 
 
 
 
364	/* use HDaudio stream handling */
365	ret = hda_dai_hw_params(substream, params, cpu_dai);
366	if (ret < 0) {
367		dev_err(cpu_dai->dev, "%s: hda_dai_hw_params failed: %d\n", __func__, ret);
368		return ret;
369	}
370
 
 
 
371	/* get stream_id */
372	sdev = widget_to_sdev(w);
373	hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream);
374
375	if (!hext_stream) {
376		dev_err(cpu_dai->dev, "%s: no hext_stream found\n", __func__);
377		return -ENODEV;
378	}
379
380	hstream = &hext_stream->hstream;
381	stream_id = hstream->stream_tag;
382
383	if (!stream_id) {
384		dev_err(cpu_dai->dev, "%s: no stream_id allocated\n", __func__);
385		return -ENODEV;
386	}
387
388	/* configure TLV */
389	ipc4_copier = widget_to_copier(w);
390
391	dma_config_tlv = &ipc4_copier->dma_config_tlv;
 
 
 
 
 
392	dma_config_tlv->type = SOF_IPC4_GTW_DMA_CONFIG_ID;
393	/* dma_config_priv_size is zero */
394	dma_config_tlv->length = sizeof(dma_config_tlv->dma_config);
395
396	dma_config = &dma_config_tlv->dma_config;
397
398	dma_config->dma_method = SOF_IPC4_DMA_METHOD_HDA;
399	dma_config->pre_allocated_by_host = 1;
400	dma_config->dma_channel_id = stream_id - 1;
401	dma_config->stream_id = stream_id;
402	dma_config->dma_stream_channel_map.device_count = 0; /* mapping not used */
 
 
 
 
403	dma_config->dma_priv_config_size = 0;
404
405	return 0;
406}
407
 
 
 
 
 
 
 
 
 
 
408static int non_hda_dai_prepare(struct snd_pcm_substream *substream,
409			       struct snd_soc_dai *cpu_dai)
410{
411	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
412	int stream = substream->stream;
413
414	return non_hda_dai_hw_params(substream, &rtd->dpcm[stream].hw_params, cpu_dai);
415}
416
417static const struct snd_soc_dai_ops ssp_dai_ops = {
418	.hw_params = non_hda_dai_hw_params,
419	.hw_free = hda_dai_hw_free,
420	.trigger = hda_dai_trigger,
421	.prepare = non_hda_dai_prepare,
422};
423
424static const struct snd_soc_dai_ops dmic_dai_ops = {
425	.hw_params = non_hda_dai_hw_params,
426	.hw_free = hda_dai_hw_free,
427	.trigger = hda_dai_trigger,
428	.prepare = non_hda_dai_prepare,
429};
430
431int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream,
432			  struct snd_pcm_hw_params *params,
433			  struct snd_soc_dai *cpu_dai,
434			  int link_id)
 
435{
436	struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
 
 
 
 
437	const struct hda_dai_widget_dma_ops *ops;
 
 
438	struct hdac_ext_stream *hext_stream;
 
439	struct snd_sof_dev *sdev;
 
 
 
440	int ret;
 
441
442	ret = non_hda_dai_hw_params(substream, params, cpu_dai);
443	if (ret < 0) {
444		dev_err(cpu_dai->dev, "%s: non_hda_dai_hw_params failed %d\n", __func__, ret);
445		return ret;
446	}
447
448	ops = hda_dai_get_ops(substream, cpu_dai);
 
 
 
 
 
449	sdev = widget_to_sdev(w);
450	hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream);
451
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
452	if (!hext_stream)
453		return -ENODEV;
454
455	/* in the case of SoundWire we need to program the PCMSyCM registers */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
456	ret = hdac_bus_eml_sdw_map_stream_ch(sof_to_bus(sdev), link_id, cpu_dai->id,
457					     GENMASK(params_channels(params) - 1, 0),
458					     hdac_stream(hext_stream)->stream_tag,
459					     substream->stream);
460	if (ret < 0) {
461		dev_err(cpu_dai->dev, "%s:  hdac_bus_eml_sdw_map_stream_ch failed %d\n",
462			__func__, ret);
463		return ret;
464	}
465
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
466	return 0;
467}
 
468
469int sdw_hda_dai_hw_free(struct snd_pcm_substream *substream,
470			struct snd_soc_dai *cpu_dai,
471			int link_id)
472{
473	struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
474	struct snd_sof_dev *sdev;
475	int ret;
476
477	ret = hda_dai_hw_free(substream, cpu_dai);
478	if (ret < 0) {
479		dev_err(cpu_dai->dev, "%s: non_hda_dai_hw_free failed %d\n", __func__, ret);
480		return ret;
481	}
482
483	sdev = widget_to_sdev(w);
484
485	/* in the case of SoundWire we need to reset the PCMSyCM registers */
486	ret = hdac_bus_eml_sdw_map_stream_ch(sof_to_bus(sdev), link_id, cpu_dai->id,
487					     0, 0, substream->stream);
488	if (ret < 0) {
489		dev_err(cpu_dai->dev, "%s:  hdac_bus_eml_sdw_map_stream_ch failed %d\n",
490			__func__, ret);
491		return ret;
492	}
493
494	return 0;
495}
 
496
497int sdw_hda_dai_trigger(struct snd_pcm_substream *substream, int cmd,
498			struct snd_soc_dai *cpu_dai)
499{
500	return hda_dai_trigger(substream, cmd, cpu_dai);
501}
 
502
503static int hda_dai_suspend(struct hdac_bus *bus)
504{
505	struct snd_soc_pcm_runtime *rtd;
506	struct hdac_ext_stream *hext_stream;
507	struct hdac_stream *s;
508	int ret;
509
510	/* set internal flag for BE */
511	list_for_each_entry(s, &bus->stream_list, list) {
512
513		hext_stream = stream_to_hdac_ext_stream(s);
514
515		/*
516		 * clear stream. This should already be taken care for running
517		 * streams when the SUSPEND trigger is called. But paused
518		 * streams do not get suspended, so this needs to be done
519		 * explicitly during suspend.
520		 */
521		if (hext_stream->link_substream) {
522			const struct hda_dai_widget_dma_ops *ops;
523			struct snd_sof_widget *swidget;
524			struct snd_soc_dapm_widget *w;
525			struct snd_soc_dai *cpu_dai;
526			struct snd_sof_dev *sdev;
527			struct snd_sof_dai *sdai;
528
529			rtd = snd_soc_substream_to_rtd(hext_stream->link_substream);
530			cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
531			w = snd_soc_dai_get_widget(cpu_dai, hdac_stream(hext_stream)->direction);
532			swidget = w->dobj.private;
533			sdev = widget_to_sdev(w);
534			sdai = swidget->private;
535			ops = sdai->platform_private;
536
537			ret = hda_link_dma_cleanup(hext_stream->link_substream,
538						   hext_stream,
539						   cpu_dai);
540			if (ret < 0)
541				return ret;
542
543			/* for consistency with TRIGGER_SUSPEND  */
544			if (ops->post_trigger) {
545				ret = ops->post_trigger(sdev, cpu_dai,
546							hext_stream->link_substream,
547							SNDRV_PCM_TRIGGER_SUSPEND);
548				if (ret < 0)
549					return ret;
550			}
 
 
 
 
 
551		}
552	}
553
554	return 0;
555}
556
557static void ssp_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops)
558{
559	const struct sof_intel_dsp_desc *chip;
560	int i;
561
562	chip = get_chip_info(sdev->pdata);
563
564	if (chip->hw_ip_version >= SOF_INTEL_ACE_2_0) {
565		for (i = 0; i < ops->num_drv; i++) {
566			if (strstr(ops->drv[i].name, "SSP"))
567				ops->drv[i].ops = &ssp_dai_ops;
568		}
569	}
570}
571
572static void dmic_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops)
573{
574	const struct sof_intel_dsp_desc *chip;
575	int i;
576
577	chip = get_chip_info(sdev->pdata);
578
579	if (chip->hw_ip_version >= SOF_INTEL_ACE_2_0) {
580		for (i = 0; i < ops->num_drv; i++) {
581			if (strstr(ops->drv[i].name, "DMIC"))
582				ops->drv[i].ops = &dmic_dai_ops;
583		}
584	}
585}
586
587#else
588
589static inline void ssp_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) {}
590static inline void dmic_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) {}
591
592#endif /* CONFIG_SND_SOC_SOF_HDA_LINK */
593
594void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops)
595{
596	int i;
597
598	for (i = 0; i < ops->num_drv; i++) {
599#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
600		if (strstr(ops->drv[i].name, "iDisp") ||
601		    strstr(ops->drv[i].name, "Analog") ||
602		    strstr(ops->drv[i].name, "Digital"))
603			ops->drv[i].ops = &hda_dai_ops;
604#endif
605	}
606
607	ssp_set_dai_drv_ops(sdev, ops);
608	dmic_set_dai_drv_ops(sdev, ops);
609
610	if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4 && !hda_use_tplg_nhlt) {
611		struct sof_ipc4_fw_data *ipc4_data = sdev->private;
612
613		ipc4_data->nhlt = intel_nhlt_init(sdev->dev);
614	}
615}
 
616
617void hda_ops_free(struct snd_sof_dev *sdev)
618{
619	if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4) {
620		struct sof_ipc4_fw_data *ipc4_data = sdev->private;
621
622		if (!hda_use_tplg_nhlt)
623			intel_nhlt_free(ipc4_data->nhlt);
624
625		kfree(sdev->private);
626		sdev->private = NULL;
627	}
628}
629EXPORT_SYMBOL_NS(hda_ops_free, SND_SOC_SOF_INTEL_HDA_COMMON);
630
631/*
632 * common dai driver for skl+ platforms.
633 * some products who use this DAI array only physically have a subset of
634 * the DAIs, but no harm is done here by adding the whole set.
635 */
636struct snd_soc_dai_driver skl_dai[] = {
637{
638	.name = "SSP0 Pin",
639	.playback = {
640		.channels_min = 1,
641		.channels_max = 8,
642	},
643	.capture = {
644		.channels_min = 1,
645		.channels_max = 8,
646	},
647},
648{
649	.name = "SSP1 Pin",
650	.playback = {
651		.channels_min = 1,
652		.channels_max = 8,
653	},
654	.capture = {
655		.channels_min = 1,
656		.channels_max = 8,
657	},
658},
659{
660	.name = "SSP2 Pin",
661	.playback = {
662		.channels_min = 1,
663		.channels_max = 8,
664	},
665	.capture = {
666		.channels_min = 1,
667		.channels_max = 8,
668	},
669},
670{
671	.name = "SSP3 Pin",
672	.playback = {
673		.channels_min = 1,
674		.channels_max = 8,
675	},
676	.capture = {
677		.channels_min = 1,
678		.channels_max = 8,
679	},
680},
681{
682	.name = "SSP4 Pin",
683	.playback = {
684		.channels_min = 1,
685		.channels_max = 8,
686	},
687	.capture = {
688		.channels_min = 1,
689		.channels_max = 8,
690	},
691},
692{
693	.name = "SSP5 Pin",
694	.playback = {
695		.channels_min = 1,
696		.channels_max = 8,
697	},
698	.capture = {
699		.channels_min = 1,
700		.channels_max = 8,
701	},
702},
703{
704	.name = "DMIC01 Pin",
705	.capture = {
706		.channels_min = 1,
707		.channels_max = 4,
708	},
709},
710{
711	.name = "DMIC16k Pin",
712	.capture = {
713		.channels_min = 1,
714		.channels_max = 4,
715	},
716},
717#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
718{
719	.name = "iDisp1 Pin",
720	.playback = {
721		.channels_min = 1,
722		.channels_max = 8,
723	},
724},
725{
726	.name = "iDisp2 Pin",
727	.playback = {
728		.channels_min = 1,
729		.channels_max = 8,
730	},
731},
732{
733	.name = "iDisp3 Pin",
734	.playback = {
735		.channels_min = 1,
736		.channels_max = 8,
737	},
738},
739{
740	.name = "iDisp4 Pin",
741	.playback = {
742		.channels_min = 1,
743		.channels_max = 8,
744	},
745},
746{
747	.name = "Analog CPU DAI",
748	.playback = {
749		.channels_min = 1,
750		.channels_max = 16,
751	},
752	.capture = {
753		.channels_min = 1,
754		.channels_max = 16,
755	},
756},
757{
758	.name = "Digital CPU DAI",
759	.playback = {
760		.channels_min = 1,
761		.channels_max = 16,
762	},
763	.capture = {
764		.channels_min = 1,
765		.channels_max = 16,
766	},
767},
768{
769	.name = "Alt Analog CPU DAI",
770	.playback = {
771		.channels_min = 1,
772		.channels_max = 16,
773	},
774	.capture = {
775		.channels_min = 1,
776		.channels_max = 16,
777	},
778},
779#endif
780};
 
781
782int hda_dsp_dais_suspend(struct snd_sof_dev *sdev)
783{
784	/*
785	 * In the corner case where a SUSPEND happens during a PAUSE, the ALSA core
786	 * does not throw the TRIGGER_SUSPEND. This leaves the DAIs in an unbalanced state.
787	 * Since the component suspend is called last, we can trap this corner case
788	 * and force the DAIs to release their resources.
789	 */
790#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK)
791	int ret;
792
793	ret = hda_dai_suspend(sof_to_bus(sdev));
794	if (ret < 0)
795		return ret;
796#endif
797
798	return 0;
799}
v6.13.7
  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) 2018 Intel Corporation
  7//
  8// Authors: Keyon Jie <yang.jie@linux.intel.com>
  9//
 10
 11#include <sound/pcm_params.h>
 12#include <sound/hdaudio_ext.h>
 13#include <sound/hda-mlink.h>
 14#include <sound/hda_register.h>
 15#include <sound/intel-nhlt.h>
 16#include <sound/sof/ipc4/header.h>
 17#include <uapi/sound/sof/header.h>
 18#include "../ipc4-priv.h"
 19#include "../ipc4-topology.h"
 20#include "../sof-priv.h"
 21#include "../sof-audio.h"
 22#include "hda.h"
 23
 24/*
 25 * The default method is to fetch NHLT from BIOS. With this parameter set
 26 * it is possible to override that with NHLT in the SOF topology manifest.
 27 */
 28static bool hda_use_tplg_nhlt;
 29module_param_named(sof_use_tplg_nhlt, hda_use_tplg_nhlt, bool, 0444);
 30MODULE_PARM_DESC(sof_use_tplg_nhlt, "SOF topology nhlt override");
 31
 
 
 
 
 
 
 
 
 32int hda_dai_config(struct snd_soc_dapm_widget *w, unsigned int flags,
 33		   struct snd_sof_dai_config_data *data)
 34{
 35	struct snd_sof_widget *swidget = w->dobj.private;
 36	const struct sof_ipc_tplg_ops *tplg_ops;
 37	struct snd_sof_dev *sdev;
 38	int ret;
 39
 40	if (!swidget)
 41		return 0;
 42
 43	sdev = widget_to_sdev(w);
 44	tplg_ops = sof_ipc_get_ops(sdev, tplg);
 45
 46	if (tplg_ops && tplg_ops->dai_config) {
 47		ret = tplg_ops->dai_config(sdev, swidget, flags, data);
 48		if (ret < 0) {
 49			dev_err(sdev->dev, "DAI config with flags %x failed for widget %s\n",
 50				flags, w->name);
 51			return ret;
 52		}
 53	}
 54
 55	return 0;
 56}
 57EXPORT_SYMBOL_NS(hda_dai_config, "SND_SOC_SOF_INTEL_HDA_COMMON");
 58
 59#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK)
 60
 61static struct snd_sof_dev *dai_to_sdev(struct snd_pcm_substream *substream,
 62				       struct snd_soc_dai *cpu_dai)
 63{
 64	struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
 65
 66	return widget_to_sdev(w);
 67}
 68
 69static const struct hda_dai_widget_dma_ops *
 70hda_dai_get_ops(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai)
 71{
 72	struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
 73	struct snd_sof_widget *swidget = w->dobj.private;
 74	struct snd_sof_dev *sdev;
 75	struct snd_sof_dai *sdai;
 76
 77	sdev = widget_to_sdev(w);
 78
 79	if (!swidget) {
 80		dev_err(sdev->dev, "%s: swidget is NULL\n", __func__);
 81		return NULL;
 82	}
 83
 84	if (sdev->dspless_mode_selected)
 85		return hda_select_dai_widget_ops(sdev, swidget);
 86
 87	sdai = swidget->private;
 88
 89	/* select and set the DAI widget ops if not set already */
 90	if (!sdai->platform_private) {
 91		const struct hda_dai_widget_dma_ops *ops =
 92			hda_select_dai_widget_ops(sdev, swidget);
 93		if (!ops)
 94			return NULL;
 95
 96		/* check if mandatory ops are set */
 97		if (!ops || !ops->get_hext_stream)
 98			return NULL;
 99
100		sdai->platform_private = ops;
101	}
102
103	return sdai->platform_private;
104}
105
106static int
107hda_link_dma_cleanup(struct snd_pcm_substream *substream,
108		     struct hdac_ext_stream *hext_stream,
109		     struct snd_soc_dai *cpu_dai, bool release)
110{
111	const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, cpu_dai);
112	struct sof_intel_hda_stream *hda_stream;
113	struct hdac_ext_link *hlink;
114	struct snd_sof_dev *sdev;
115	int stream_tag;
116
117	if (!ops) {
118		dev_err(cpu_dai->dev, "DAI widget ops not set\n");
119		return -EINVAL;
120	}
121
122	sdev = dai_to_sdev(substream, cpu_dai);
123
124	hlink = ops->get_hlink(sdev, substream);
125	if (!hlink)
126		return -EINVAL;
127
128	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
129		stream_tag = hdac_stream(hext_stream)->stream_tag;
130		snd_hdac_ext_bus_link_clear_stream_id(hlink, stream_tag);
131	}
132
133	if (!release) {
134		/*
135		 * Force stream reconfiguration without releasing the channel on
136		 * subsequent stream restart (without free), including LinkDMA
137		 * reset.
138		 * The stream is released via hda_dai_hw_free()
139		 */
140		hext_stream->link_prepared = 0;
141		return 0;
142	}
143
144	if (ops->release_hext_stream)
145		ops->release_hext_stream(sdev, cpu_dai, substream);
146
147	hext_stream->link_prepared = 0;
148
149	/* free the host DMA channel reserved by hostless streams */
150	hda_stream = hstream_to_sof_hda_stream(hext_stream);
151	hda_stream->host_reserved = 0;
152
153	return 0;
154}
155
156static int hda_link_dma_hw_params(struct snd_pcm_substream *substream,
157				  struct snd_pcm_hw_params *params, struct snd_soc_dai *cpu_dai)
158{
159	const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, cpu_dai);
160	struct hdac_ext_stream *hext_stream;
161	struct hdac_stream *hstream;
162	struct hdac_ext_link *hlink;
163	struct snd_sof_dev *sdev;
164	int stream_tag;
165
166	if (!ops) {
167		dev_err(cpu_dai->dev, "DAI widget ops not set\n");
168		return -EINVAL;
169	}
170
171	sdev = dai_to_sdev(substream, cpu_dai);
172
173	hlink = ops->get_hlink(sdev, substream);
174	if (!hlink)
175		return -EINVAL;
176
177	hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream);
178
179	if (!hext_stream) {
180		if (ops->assign_hext_stream)
181			hext_stream = ops->assign_hext_stream(sdev, cpu_dai, substream);
182	}
183
184	if (!hext_stream)
185		return -EBUSY;
186
187	hstream = &hext_stream->hstream;
188	stream_tag = hstream->stream_tag;
189
190	if (hext_stream->hstream.direction == SNDRV_PCM_STREAM_PLAYBACK)
191		snd_hdac_ext_bus_link_set_stream_id(hlink, stream_tag);
192
193	/* set the hdac_stream in the codec dai */
194	if (ops->codec_dai_set_stream)
195		ops->codec_dai_set_stream(sdev, substream, hstream);
196
197	if (ops->reset_hext_stream)
198		ops->reset_hext_stream(sdev, hext_stream);
199
200	if (ops->calc_stream_format && ops->setup_hext_stream) {
201		unsigned int format_val = ops->calc_stream_format(sdev, substream, params);
202
203		ops->setup_hext_stream(sdev, hext_stream, format_val);
204	}
205
206	hext_stream->link_prepared = 1;
207
208	return 0;
209}
210
211static int __maybe_unused hda_dai_hw_free(struct snd_pcm_substream *substream,
212					  struct snd_soc_dai *cpu_dai)
213{
214	const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, cpu_dai);
215	struct hdac_ext_stream *hext_stream;
216	struct snd_sof_dev *sdev = dai_to_sdev(substream, cpu_dai);
217
218	if (!ops) {
219		dev_err(cpu_dai->dev, "DAI widget ops not set\n");
220		return -EINVAL;
221	}
222
223	hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream);
224	if (!hext_stream)
225		return 0;
226
227	return hda_link_dma_cleanup(substream, hext_stream, cpu_dai, true);
228}
229
230static int __maybe_unused hda_dai_hw_params_data(struct snd_pcm_substream *substream,
231						 struct snd_pcm_hw_params *params,
232						 struct snd_soc_dai *dai,
233						 struct snd_sof_dai_config_data *data,
234						 unsigned int flags)
235{
236	struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(dai, substream->stream);
237	const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, dai);
238	struct hdac_ext_stream *hext_stream;
 
 
239	struct snd_sof_dev *sdev = widget_to_sdev(w);
240	int ret;
241
242	if (!ops) {
243		dev_err(sdev->dev, "DAI widget ops not set\n");
244		return -EINVAL;
245	}
246
247	hext_stream = ops->get_hext_stream(sdev, dai, substream);
248	if (hext_stream && hext_stream->link_prepared)
249		return 0;
250
251	ret = hda_link_dma_hw_params(substream, params, dai);
252	if (ret < 0)
253		return ret;
254
255	hext_stream = ops->get_hext_stream(sdev, dai, substream);
256
257	flags |= SOF_DAI_CONFIG_FLAGS_2_STEP_STOP << SOF_DAI_CONFIG_FLAGS_QUIRK_SHIFT;
258	data->dai_data = hdac_stream(hext_stream)->stream_tag - 1;
259
260	return hda_dai_config(w, flags, data);
261}
262
263static int __maybe_unused hda_dai_hw_params(struct snd_pcm_substream *substream,
264					    struct snd_pcm_hw_params *params,
265					    struct snd_soc_dai *dai)
266{
267	struct snd_sof_dai_config_data data = { 0 };
268	unsigned int flags = SOF_DAI_CONFIG_FLAGS_HW_PARAMS;
269
270	return hda_dai_hw_params_data(substream, params, dai, &data, flags);
271}
272
273/*
274 * In contrast to IPC3, the dai trigger in IPC4 mixes pipeline state changes
275 * (over IPC channel) and DMA state change (direct host register changes).
276 */
277static int __maybe_unused hda_dai_trigger(struct snd_pcm_substream *substream, int cmd,
278					  struct snd_soc_dai *dai)
279{
280	const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, dai);
281	struct hdac_ext_stream *hext_stream;
282	struct snd_sof_dev *sdev;
283	int ret;
284
285	if (!ops) {
286		dev_err(dai->dev, "DAI widget ops not set\n");
287		return -EINVAL;
288	}
289
290	dev_dbg(dai->dev, "cmd=%d dai %s direction %d\n", cmd,
291		dai->name, substream->stream);
292
293	sdev = dai_to_sdev(substream, dai);
294
295	hext_stream = ops->get_hext_stream(sdev, dai, substream);
296	if (!hext_stream)
297		return -EINVAL;
298
299	if (ops->pre_trigger) {
300		ret = ops->pre_trigger(sdev, dai, substream, cmd);
301		if (ret < 0)
302			return ret;
303	}
304
305	if (ops->trigger) {
306		ret = ops->trigger(sdev, dai, substream, cmd);
307		if (ret < 0)
308			return ret;
309	}
310
311	if (ops->post_trigger) {
312		ret = ops->post_trigger(sdev, dai, substream, cmd);
313		if (ret < 0)
314			return ret;
315	}
316
317	switch (cmd) {
318	case SNDRV_PCM_TRIGGER_STOP:
319	case SNDRV_PCM_TRIGGER_SUSPEND:
320		ret = hda_link_dma_cleanup(substream, hext_stream, dai,
321					   cmd == SNDRV_PCM_TRIGGER_STOP ? false : true);
322		if (ret < 0) {
323			dev_err(sdev->dev, "%s: failed to clean up link DMA\n", __func__);
324			return ret;
325		}
326		break;
327	default:
328		break;
329	}
330
331	return 0;
332}
333
334#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
335
336static int hda_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
337{
338	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
339	int stream = substream->stream;
340
341	return hda_dai_hw_params(substream, &rtd->dpcm[stream].hw_params, dai);
342}
343
344static const struct snd_soc_dai_ops hda_dai_ops = {
345	.hw_params = hda_dai_hw_params,
346	.hw_free = hda_dai_hw_free,
347	.trigger = hda_dai_trigger,
348	.prepare = hda_dai_prepare,
349};
350
351#endif
352
353static struct sof_ipc4_copier *widget_to_copier(struct snd_soc_dapm_widget *w)
354{
355	struct snd_sof_widget *swidget = w->dobj.private;
356	struct snd_sof_dai *sdai = swidget->private;
357	struct sof_ipc4_copier *ipc4_copier = (struct sof_ipc4_copier *)sdai->private;
358
359	return ipc4_copier;
360}
361
362static int non_hda_dai_hw_params_data(struct snd_pcm_substream *substream,
363				      struct snd_pcm_hw_params *params,
364				      struct snd_soc_dai *cpu_dai,
365				      struct snd_sof_dai_config_data *data,
366				      unsigned int flags)
367{
368	struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
369	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
370	struct sof_ipc4_dma_config_tlv *dma_config_tlv;
371	const struct hda_dai_widget_dma_ops *ops;
372	struct sof_ipc4_dma_config *dma_config;
373	struct sof_ipc4_copier *ipc4_copier;
374	struct hdac_ext_stream *hext_stream;
375	struct hdac_stream *hstream;
376	struct snd_sof_dev *sdev;
377	struct snd_soc_dai *dai;
378	int cpu_dai_id;
379	int stream_id;
380	int ret;
381
382	ops = hda_dai_get_ops(substream, cpu_dai);
383	if (!ops) {
384		dev_err(cpu_dai->dev, "DAI widget ops not set\n");
385		return -EINVAL;
386	}
387
388	sdev = widget_to_sdev(w);
389	hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream);
390
391	/* nothing more to do if the link is already prepared */
392	if (hext_stream && hext_stream->link_prepared)
393		return 0;
394
395	/* use HDaudio stream handling */
396	ret = hda_dai_hw_params_data(substream, params, cpu_dai, data, flags);
397	if (ret < 0) {
398		dev_err(cpu_dai->dev, "%s: hda_dai_hw_params_data failed: %d\n", __func__, ret);
399		return ret;
400	}
401
402	if (sdev->dspless_mode_selected)
403		return 0;
404
405	/* get stream_id */
 
406	hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream);
407
408	if (!hext_stream) {
409		dev_err(cpu_dai->dev, "%s: no hext_stream found\n", __func__);
410		return -ENODEV;
411	}
412
413	hstream = &hext_stream->hstream;
414	stream_id = hstream->stream_tag;
415
416	if (!stream_id) {
417		dev_err(cpu_dai->dev, "%s: no stream_id allocated\n", __func__);
418		return -ENODEV;
419	}
420
421	/* configure TLV */
422	ipc4_copier = widget_to_copier(w);
423
424	for_each_rtd_cpu_dais(rtd, cpu_dai_id, dai) {
425		if (dai == cpu_dai)
426			break;
427	}
428
429	dma_config_tlv = &ipc4_copier->dma_config_tlv[cpu_dai_id];
430	dma_config_tlv->type = SOF_IPC4_GTW_DMA_CONFIG_ID;
431	/* dma_config_priv_size is zero */
432	dma_config_tlv->length = sizeof(dma_config_tlv->dma_config);
433
434	dma_config = &dma_config_tlv->dma_config;
435
436	dma_config->dma_method = SOF_IPC4_DMA_METHOD_HDA;
437	dma_config->pre_allocated_by_host = 1;
438	dma_config->dma_channel_id = stream_id - 1;
439	dma_config->stream_id = stream_id;
440	/*
441	 * Currently we use a DMA for each device in ALH blob. The device will
442	 * be copied in sof_ipc4_prepare_copier_module.
443	 */
444	dma_config->dma_stream_channel_map.device_count = 1;
445	dma_config->dma_priv_config_size = 0;
446
447	return 0;
448}
449
450static int non_hda_dai_hw_params(struct snd_pcm_substream *substream,
451				 struct snd_pcm_hw_params *params,
452				 struct snd_soc_dai *cpu_dai)
453{
454	struct snd_sof_dai_config_data data = { 0 };
455	unsigned int flags = SOF_DAI_CONFIG_FLAGS_HW_PARAMS;
456
457	return non_hda_dai_hw_params_data(substream, params, cpu_dai, &data, flags);
458}
459
460static int non_hda_dai_prepare(struct snd_pcm_substream *substream,
461			       struct snd_soc_dai *cpu_dai)
462{
463	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
464	int stream = substream->stream;
465
466	return non_hda_dai_hw_params(substream, &rtd->dpcm[stream].hw_params, cpu_dai);
467}
468
469static const struct snd_soc_dai_ops ssp_dai_ops = {
470	.hw_params = non_hda_dai_hw_params,
471	.hw_free = hda_dai_hw_free,
472	.trigger = hda_dai_trigger,
473	.prepare = non_hda_dai_prepare,
474};
475
476static const struct snd_soc_dai_ops dmic_dai_ops = {
477	.hw_params = non_hda_dai_hw_params,
478	.hw_free = hda_dai_hw_free,
479	.trigger = hda_dai_trigger,
480	.prepare = non_hda_dai_prepare,
481};
482
483int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream,
484			  struct snd_pcm_hw_params *params,
485			  struct snd_soc_dai *cpu_dai,
486			  int link_id,
487			  int intel_alh_id)
488{
489	struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
490	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
491	struct sof_ipc4_dma_config_tlv *dma_config_tlv;
492	struct snd_sof_dai_config_data data = { 0 };
493	unsigned int flags = SOF_DAI_CONFIG_FLAGS_HW_PARAMS;
494	const struct hda_dai_widget_dma_ops *ops;
495	struct sof_ipc4_dma_config *dma_config;
496	struct sof_ipc4_copier *ipc4_copier;
497	struct hdac_ext_stream *hext_stream;
498	struct snd_soc_dai *dai;
499	struct snd_sof_dev *sdev;
500	bool cpu_dai_found = false;
501	int cpu_dai_id;
502	int ch_mask;
503	int ret;
504	int i;
505
506	if (!w) {
507		dev_err(cpu_dai->dev, "%s widget not found, check amp link num in the topology\n",
508			cpu_dai->name);
509		return -EINVAL;
510	}
511
512	ops = hda_dai_get_ops(substream, cpu_dai);
513	if (!ops) {
514		dev_err(cpu_dai->dev, "DAI widget ops not set\n");
515		return -EINVAL;
516	}
517
518	sdev = widget_to_sdev(w);
519	hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream);
520
521	/* nothing more to do if the link is already prepared */
522	if (hext_stream && hext_stream->link_prepared)
523		return 0;
524
525	/*
526	 * reset the PCMSyCM registers to handle a prepare callback when the PCM is restarted
527	 * due to xruns or after a call to snd_pcm_drain/drop()
528	 */
529	ret = hdac_bus_eml_sdw_map_stream_ch(sof_to_bus(sdev), link_id, cpu_dai->id,
530					     0, 0, substream->stream);
531	if (ret < 0) {
532		dev_err(cpu_dai->dev, "%s:  hdac_bus_eml_sdw_map_stream_ch failed %d\n",
533			__func__, ret);
534		return ret;
535	}
536
537	data.dai_index = (link_id << 8) | cpu_dai->id;
538	data.dai_node_id = intel_alh_id;
539	ret = non_hda_dai_hw_params_data(substream, params, cpu_dai, &data, flags);
540	if (ret < 0) {
541		dev_err(cpu_dai->dev, "%s: non_hda_dai_hw_params failed %d\n", __func__, ret);
542		return ret;
543	}
544
545	hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream);
546	if (!hext_stream)
547		return -ENODEV;
548
549	/*
550	 * in the case of SoundWire we need to program the PCMSyCM registers. In case
551	 * of aggregated devices, we need to define the channel mask for each sublink
552	 * by reconstructing the split done in soc-pcm.c
553	 */
554	for_each_rtd_cpu_dais(rtd, cpu_dai_id, dai) {
555		if (dai == cpu_dai) {
556			cpu_dai_found = true;
557			break;
558		}
559	}
560
561	if (!cpu_dai_found)
562		return -ENODEV;
563
564	ch_mask = GENMASK(params_channels(params) - 1, 0);
565
566	ret = hdac_bus_eml_sdw_map_stream_ch(sof_to_bus(sdev), link_id, cpu_dai->id,
567					     ch_mask,
568					     hdac_stream(hext_stream)->stream_tag,
569					     substream->stream);
570	if (ret < 0) {
571		dev_err(cpu_dai->dev, "%s:  hdac_bus_eml_sdw_map_stream_ch failed %d\n",
572			__func__, ret);
573		return ret;
574	}
575
576	if (sdev->dspless_mode_selected)
577		return 0;
578
579	ipc4_copier = widget_to_copier(w);
580	dma_config_tlv = &ipc4_copier->dma_config_tlv[cpu_dai_id];
581	dma_config = &dma_config_tlv->dma_config;
582	dma_config->dma_stream_channel_map.mapping[0].device = data.dai_index;
583	dma_config->dma_stream_channel_map.mapping[0].channel_mask = ch_mask;
584
585	/*
586	 * copy the dma_config_tlv to all ipc4_copier in the same link. Because only one copier
587	 * will be handled in sof_ipc4_prepare_copier_module.
588	 */
589	for_each_rtd_cpu_dais(rtd, i, dai) {
590		w = snd_soc_dai_get_widget(dai, substream->stream);
591		if (!w) {
592			dev_err(cpu_dai->dev,
593				"%s widget not found, check amp link num in the topology\n",
594				dai->name);
595			return -EINVAL;
596		}
597		ipc4_copier = widget_to_copier(w);
598		memcpy(&ipc4_copier->dma_config_tlv[cpu_dai_id], dma_config_tlv,
599		       sizeof(*dma_config_tlv));
600	}
601	return 0;
602}
603EXPORT_SYMBOL_NS(sdw_hda_dai_hw_params, "SND_SOC_SOF_INTEL_HDA_COMMON");
604
605int sdw_hda_dai_hw_free(struct snd_pcm_substream *substream,
606			struct snd_soc_dai *cpu_dai,
607			int link_id)
608{
609	struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
610	struct snd_sof_dev *sdev;
611	int ret;
612
613	ret = hda_dai_hw_free(substream, cpu_dai);
614	if (ret < 0) {
615		dev_err(cpu_dai->dev, "%s: non_hda_dai_hw_free failed %d\n", __func__, ret);
616		return ret;
617	}
618
619	sdev = widget_to_sdev(w);
620
621	/* in the case of SoundWire we need to reset the PCMSyCM registers */
622	ret = hdac_bus_eml_sdw_map_stream_ch(sof_to_bus(sdev), link_id, cpu_dai->id,
623					     0, 0, substream->stream);
624	if (ret < 0) {
625		dev_err(cpu_dai->dev, "%s:  hdac_bus_eml_sdw_map_stream_ch failed %d\n",
626			__func__, ret);
627		return ret;
628	}
629
630	return 0;
631}
632EXPORT_SYMBOL_NS(sdw_hda_dai_hw_free, "SND_SOC_SOF_INTEL_HDA_COMMON");
633
634int sdw_hda_dai_trigger(struct snd_pcm_substream *substream, int cmd,
635			struct snd_soc_dai *cpu_dai)
636{
637	return hda_dai_trigger(substream, cmd, cpu_dai);
638}
639EXPORT_SYMBOL_NS(sdw_hda_dai_trigger, "SND_SOC_SOF_INTEL_HDA_COMMON");
640
641static int hda_dai_suspend(struct hdac_bus *bus)
642{
643	struct snd_soc_pcm_runtime *rtd;
644	struct hdac_ext_stream *hext_stream;
645	struct hdac_stream *s;
646	int ret;
647
648	/* set internal flag for BE */
649	list_for_each_entry(s, &bus->stream_list, list) {
650
651		hext_stream = stream_to_hdac_ext_stream(s);
652
653		/*
654		 * clear stream. This should already be taken care for running
655		 * streams when the SUSPEND trigger is called. But paused
656		 * streams do not get suspended, so this needs to be done
657		 * explicitly during suspend.
658		 */
659		if (hext_stream->link_substream) {
660			const struct hda_dai_widget_dma_ops *ops;
661			struct snd_sof_widget *swidget;
662			struct snd_soc_dapm_widget *w;
663			struct snd_soc_dai *cpu_dai;
664			struct snd_sof_dev *sdev;
665			struct snd_sof_dai *sdai;
666
667			rtd = snd_soc_substream_to_rtd(hext_stream->link_substream);
668			cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
669			w = snd_soc_dai_get_widget(cpu_dai, hdac_stream(hext_stream)->direction);
670			swidget = w->dobj.private;
671			sdev = widget_to_sdev(w);
672			sdai = swidget->private;
673			ops = sdai->platform_private;
674
675			if (rtd->dpcm[hext_stream->link_substream->stream].state !=
676			    SND_SOC_DPCM_STATE_PAUSED)
677				continue;
 
 
678
679			/* for consistency with TRIGGER_SUSPEND  */
680			if (ops->post_trigger) {
681				ret = ops->post_trigger(sdev, cpu_dai,
682							hext_stream->link_substream,
683							SNDRV_PCM_TRIGGER_SUSPEND);
684				if (ret < 0)
685					return ret;
686			}
687
688			ret = hda_link_dma_cleanup(hext_stream->link_substream,
689						   hext_stream, cpu_dai, true);
690			if (ret < 0)
691				return ret;
692		}
693	}
694
695	return 0;
696}
697
698static void ssp_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops)
699{
700	const struct sof_intel_dsp_desc *chip;
701	int i;
702
703	chip = get_chip_info(sdev->pdata);
704
705	if (chip->hw_ip_version >= SOF_INTEL_ACE_2_0) {
706		for (i = 0; i < ops->num_drv; i++) {
707			if (strstr(ops->drv[i].name, "SSP"))
708				ops->drv[i].ops = &ssp_dai_ops;
709		}
710	}
711}
712
713static void dmic_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops)
714{
715	const struct sof_intel_dsp_desc *chip;
716	int i;
717
718	chip = get_chip_info(sdev->pdata);
719
720	if (chip->hw_ip_version >= SOF_INTEL_ACE_2_0) {
721		for (i = 0; i < ops->num_drv; i++) {
722			if (strstr(ops->drv[i].name, "DMIC"))
723				ops->drv[i].ops = &dmic_dai_ops;
724		}
725	}
726}
727
728#else
729
730static inline void ssp_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) {}
731static inline void dmic_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) {}
732
733#endif /* CONFIG_SND_SOC_SOF_HDA_LINK */
734
735void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops)
736{
737	int i;
738
739	for (i = 0; i < ops->num_drv; i++) {
740#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
741		if (strstr(ops->drv[i].name, "iDisp") ||
742		    strstr(ops->drv[i].name, "Analog") ||
743		    strstr(ops->drv[i].name, "Digital"))
744			ops->drv[i].ops = &hda_dai_ops;
745#endif
746	}
747
748	ssp_set_dai_drv_ops(sdev, ops);
749	dmic_set_dai_drv_ops(sdev, ops);
750
751	if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4 && !hda_use_tplg_nhlt) {
752		struct sof_ipc4_fw_data *ipc4_data = sdev->private;
753
754		ipc4_data->nhlt = intel_nhlt_init(sdev->dev);
755	}
756}
757EXPORT_SYMBOL_NS(hda_set_dai_drv_ops, "SND_SOC_SOF_INTEL_HDA_COMMON");
758
759void hda_ops_free(struct snd_sof_dev *sdev)
760{
761	if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4) {
762		struct sof_ipc4_fw_data *ipc4_data = sdev->private;
763
764		if (!hda_use_tplg_nhlt)
765			intel_nhlt_free(ipc4_data->nhlt);
766
767		kfree(sdev->private);
768		sdev->private = NULL;
769	}
770}
771EXPORT_SYMBOL_NS(hda_ops_free, "SND_SOC_SOF_INTEL_HDA_COMMON");
772
773/*
774 * common dai driver for skl+ platforms.
775 * some products who use this DAI array only physically have a subset of
776 * the DAIs, but no harm is done here by adding the whole set.
777 */
778struct snd_soc_dai_driver skl_dai[] = {
779{
780	.name = "SSP0 Pin",
781	.playback = {
782		.channels_min = 1,
783		.channels_max = 8,
784	},
785	.capture = {
786		.channels_min = 1,
787		.channels_max = 8,
788	},
789},
790{
791	.name = "SSP1 Pin",
792	.playback = {
793		.channels_min = 1,
794		.channels_max = 8,
795	},
796	.capture = {
797		.channels_min = 1,
798		.channels_max = 8,
799	},
800},
801{
802	.name = "SSP2 Pin",
803	.playback = {
804		.channels_min = 1,
805		.channels_max = 8,
806	},
807	.capture = {
808		.channels_min = 1,
809		.channels_max = 8,
810	},
811},
812{
813	.name = "SSP3 Pin",
814	.playback = {
815		.channels_min = 1,
816		.channels_max = 8,
817	},
818	.capture = {
819		.channels_min = 1,
820		.channels_max = 8,
821	},
822},
823{
824	.name = "SSP4 Pin",
825	.playback = {
826		.channels_min = 1,
827		.channels_max = 8,
828	},
829	.capture = {
830		.channels_min = 1,
831		.channels_max = 8,
832	},
833},
834{
835	.name = "SSP5 Pin",
836	.playback = {
837		.channels_min = 1,
838		.channels_max = 8,
839	},
840	.capture = {
841		.channels_min = 1,
842		.channels_max = 8,
843	},
844},
845{
846	.name = "DMIC01 Pin",
847	.capture = {
848		.channels_min = 1,
849		.channels_max = 4,
850	},
851},
852{
853	.name = "DMIC16k Pin",
854	.capture = {
855		.channels_min = 1,
856		.channels_max = 4,
857	},
858},
859#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
860{
861	.name = "iDisp1 Pin",
862	.playback = {
863		.channels_min = 1,
864		.channels_max = 8,
865	},
866},
867{
868	.name = "iDisp2 Pin",
869	.playback = {
870		.channels_min = 1,
871		.channels_max = 8,
872	},
873},
874{
875	.name = "iDisp3 Pin",
876	.playback = {
877		.channels_min = 1,
878		.channels_max = 8,
879	},
880},
881{
882	.name = "iDisp4 Pin",
883	.playback = {
884		.channels_min = 1,
885		.channels_max = 8,
886	},
887},
888{
889	.name = "Analog CPU DAI",
890	.playback = {
891		.channels_min = 1,
892		.channels_max = 16,
893	},
894	.capture = {
895		.channels_min = 1,
896		.channels_max = 16,
897	},
898},
899{
900	.name = "Digital CPU DAI",
901	.playback = {
902		.channels_min = 1,
903		.channels_max = 16,
904	},
905	.capture = {
906		.channels_min = 1,
907		.channels_max = 16,
908	},
909},
910{
911	.name = "Alt Analog CPU DAI",
912	.playback = {
913		.channels_min = 1,
914		.channels_max = 16,
915	},
916	.capture = {
917		.channels_min = 1,
918		.channels_max = 16,
919	},
920},
921#endif
922};
923EXPORT_SYMBOL_NS(skl_dai, "SND_SOC_SOF_INTEL_HDA_COMMON");
924
925int hda_dsp_dais_suspend(struct snd_sof_dev *sdev)
926{
927	/*
928	 * In the corner case where a SUSPEND happens during a PAUSE, the ALSA core
929	 * does not throw the TRIGGER_SUSPEND. This leaves the DAIs in an unbalanced state.
930	 * Since the component suspend is called last, we can trap this corner case
931	 * and force the DAIs to release their resources.
932	 */
933#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK)
934	int ret;
935
936	ret = hda_dai_suspend(sof_to_bus(sdev));
937	if (ret < 0)
938		return ret;
939#endif
940
941	return 0;
942}