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