xref: /openbmc/linux/sound/soc/sof/intel/hda-dai.c (revision 55b37d9c)
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/intel-nhlt.h>
14 #include <sound/sof/ipc4/header.h>
15 #include <uapi/sound/sof/header.h>
16 #include "../ipc4-priv.h"
17 #include "../ipc4-topology.h"
18 #include "../sof-priv.h"
19 #include "../sof-audio.h"
20 #include "hda.h"
21 
22 /*
23  * The default method is to fetch NHLT from BIOS. With this parameter set
24  * it is possible to override that with NHLT in the SOF topology manifest.
25  */
26 static bool hda_use_tplg_nhlt;
27 module_param_named(sof_use_tplg_nhlt, hda_use_tplg_nhlt, bool, 0444);
28 MODULE_PARM_DESC(sof_use_tplg_nhlt, "SOF topology nhlt override");
29 
30 int hda_dai_config(struct snd_soc_dapm_widget *w, unsigned int flags,
31 		   struct snd_sof_dai_config_data *data)
32 {
33 	struct snd_sof_widget *swidget = w->dobj.private;
34 	const struct sof_ipc_tplg_ops *tplg_ops;
35 	struct snd_soc_component *component;
36 	struct snd_sof_dev *sdev;
37 	int ret;
38 
39 	if (!swidget)
40 		return 0;
41 
42 	component = swidget->scomp;
43 	sdev = snd_soc_component_get_drvdata(component);
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 
58 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
59 
60 static const struct hda_dai_widget_dma_ops *
61 hda_dai_get_ops(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai)
62 {
63 	struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
64 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(cpu_dai->component);
65 	struct snd_sof_widget *swidget = w->dobj.private;
66 	struct snd_sof_dai *sdai;
67 
68 	/*
69 	 * The swidget parameter of hda_select_dai_widget_ops() is ignored in
70 	 * case of DSPless mode
71 	 */
72 	if (sdev->dspless_mode_selected)
73 		return hda_select_dai_widget_ops(sdev, NULL);
74 
75 	sdai = swidget->private;
76 
77 	/* select and set the DAI widget ops if not set already */
78 	if (!sdai->platform_private) {
79 		const struct hda_dai_widget_dma_ops *ops =
80 			hda_select_dai_widget_ops(sdev, swidget);
81 		if (!ops)
82 			return NULL;
83 
84 		/* check if mandatory ops are set */
85 		if (!ops || !ops->get_hext_stream)
86 			return NULL;
87 
88 		sdai->platform_private = ops;
89 	}
90 
91 	return sdai->platform_private;
92 }
93 
94 static int hda_link_dma_cleanup(struct snd_pcm_substream *substream,
95 				struct hdac_ext_stream *hext_stream,
96 				struct snd_soc_dai *cpu_dai,
97 				struct snd_soc_dai *codec_dai)
98 {
99 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(cpu_dai->component);
100 	const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, cpu_dai);
101 	struct hdac_stream *hstream = &hext_stream->hstream;
102 	struct hdac_bus *bus = hstream->bus;
103 	struct sof_intel_hda_stream *hda_stream;
104 	struct hdac_ext_link *hlink;
105 	int stream_tag;
106 
107 	hlink = snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name);
108 	if (!hlink)
109 		return -EINVAL;
110 
111 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
112 		stream_tag = hdac_stream(hext_stream)->stream_tag;
113 		snd_hdac_ext_bus_link_clear_stream_id(hlink, stream_tag);
114 	}
115 
116 	if (ops->release_hext_stream)
117 		ops->release_hext_stream(sdev, cpu_dai, substream);
118 
119 	hext_stream->link_prepared = 0;
120 
121 	/* free the host DMA channel reserved by hostless streams */
122 	hda_stream = hstream_to_sof_hda_stream(hext_stream);
123 	hda_stream->host_reserved = 0;
124 
125 	return 0;
126 }
127 
128 static int hda_link_dma_hw_params(struct snd_pcm_substream *substream,
129 				  struct snd_pcm_hw_params *params, struct snd_soc_dai *cpu_dai)
130 {
131 	const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, cpu_dai);
132 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
133 	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
134 	struct hdac_ext_stream *hext_stream;
135 	struct hdac_stream *hstream;
136 	struct hdac_ext_link *hlink;
137 	struct snd_sof_dev *sdev;
138 	struct hdac_bus *bus;
139 	unsigned int format_val;
140 	unsigned int link_bps;
141 	int stream_tag;
142 
143 	sdev = snd_soc_component_get_drvdata(cpu_dai->component);
144 	bus = sof_to_bus(sdev);
145 
146 	hlink = snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name);
147 	if (!hlink)
148 		return -EINVAL;
149 
150 	hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream);
151 
152 	if (!hext_stream) {
153 		if (ops->assign_hext_stream)
154 			hext_stream = ops->assign_hext_stream(sdev, cpu_dai, substream);
155 	}
156 
157 	if (!hext_stream)
158 		return -EBUSY;
159 
160 	hstream = &hext_stream->hstream;
161 	stream_tag = hstream->stream_tag;
162 
163 	if (hext_stream->hstream.direction == SNDRV_PCM_STREAM_PLAYBACK)
164 		snd_hdac_ext_bus_link_set_stream_id(hlink, stream_tag);
165 
166 	/* set the hdac_stream in the codec dai */
167 	snd_soc_dai_set_stream(codec_dai, hdac_stream(hext_stream), substream->stream);
168 
169 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
170 		link_bps = codec_dai->driver->playback.sig_bits;
171 	else
172 		link_bps = codec_dai->driver->capture.sig_bits;
173 
174 	if (ops->reset_hext_stream)
175 		ops->reset_hext_stream(sdev, hext_stream);
176 
177 	format_val = snd_hdac_calc_stream_format(params_rate(params), params_channels(params),
178 						 params_format(params), link_bps, 0);
179 
180 	dev_dbg(bus->dev, "format_val=%#x, rate=%d, ch=%d, format=%d\n", format_val,
181 		params_rate(params), params_channels(params), params_format(params));
182 
183 	if (ops->setup_hext_stream)
184 		ops->setup_hext_stream(sdev, hext_stream, format_val);
185 
186 	hext_stream->link_prepared = 1;
187 
188 	return 0;
189 }
190 
191 static int hda_link_dma_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai)
192 {
193 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
194 	int stream = substream->stream;
195 
196 	return hda_link_dma_hw_params(substream, &rtd->dpcm[stream].hw_params, cpu_dai);
197 }
198 
199 static int hda_dai_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai)
200 {
201 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(cpu_dai->component);
202 	const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, cpu_dai);
203 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
204 	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
205 	struct hdac_ext_stream *hext_stream;
206 
207 	if (!ops) {
208 		dev_err(sdev->dev, "DAI widget ops not set\n");
209 		return -EINVAL;
210 	}
211 
212 	hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream);
213 	if (!hext_stream)
214 		return 0;
215 
216 	return hda_link_dma_cleanup(substream, hext_stream, cpu_dai, codec_dai);
217 }
218 
219 static int hda_dai_hw_params(struct snd_pcm_substream *substream,
220 			     struct snd_pcm_hw_params *params,
221 			     struct snd_soc_dai *dai)
222 {
223 	struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(dai, substream->stream);
224 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component);
225 	const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, dai);
226 	struct hdac_ext_stream *hext_stream;
227 	struct snd_sof_dai_config_data data = { 0 };
228 	unsigned int flags = SOF_DAI_CONFIG_FLAGS_HW_PARAMS;
229 	int ret;
230 
231 	if (!ops) {
232 		dev_err(sdev->dev, "DAI widget ops not set\n");
233 		return -EINVAL;
234 	}
235 
236 	hext_stream = ops->get_hext_stream(sdev, dai, substream);
237 	if (hext_stream && hext_stream->link_prepared)
238 		return 0;
239 
240 	ret = hda_link_dma_hw_params(substream, params, dai);
241 	if (ret < 0)
242 		return ret;
243 
244 	hext_stream = ops->get_hext_stream(sdev, dai, substream);
245 
246 	flags |= SOF_DAI_CONFIG_FLAGS_2_STEP_STOP << SOF_DAI_CONFIG_FLAGS_QUIRK_SHIFT;
247 	data.dai_data = hdac_stream(hext_stream)->stream_tag - 1;
248 
249 	return hda_dai_config(w, flags, &data);
250 }
251 
252 static int hda_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
253 {
254 	struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(dai, substream->stream);
255 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component);
256 	const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, dai);
257 	struct hdac_ext_stream *hext_stream;
258 	struct snd_sof_dai_config_data data = { 0 };
259 	unsigned int flags = SOF_DAI_CONFIG_FLAGS_HW_PARAMS;
260 	int ret;
261 
262 	hext_stream = ops->get_hext_stream(sdev, dai, substream);
263 	if (hext_stream && hext_stream->link_prepared)
264 		return 0;
265 
266 	dev_dbg(sdev->dev, "prepare stream dir %d\n", substream->stream);
267 
268 	ret = hda_link_dma_prepare(substream, dai);
269 	if (ret < 0)
270 		return ret;
271 
272 	hext_stream = ops->get_hext_stream(sdev, dai, substream);
273 
274 	flags |= SOF_DAI_CONFIG_FLAGS_2_STEP_STOP << SOF_DAI_CONFIG_FLAGS_QUIRK_SHIFT;
275 	data.dai_data = hdac_stream(hext_stream)->stream_tag - 1;
276 
277 	return hda_dai_config(w, flags, &data);
278 }
279 
280 /*
281  * In contrast to IPC3, the dai trigger in IPC4 mixes pipeline state changes
282  * (over IPC channel) and DMA state change (direct host register changes).
283  */
284 static int hda_dai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
285 {
286 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component);
287 	const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, dai);
288 	struct hdac_ext_stream *hext_stream;
289 	struct snd_soc_pcm_runtime *rtd;
290 	struct snd_soc_dai *codec_dai;
291 	int ret;
292 
293 	dev_dbg(dai->dev, "cmd=%d dai %s direction %d\n", cmd,
294 		dai->name, substream->stream);
295 
296 	hext_stream = ops->get_hext_stream(sdev, dai, substream);
297 	if (!hext_stream)
298 		return -EINVAL;
299 
300 	rtd = asoc_substream_to_rtd(substream);
301 	codec_dai = asoc_rtd_to_codec(rtd, 0);
302 
303 	if (ops->pre_trigger) {
304 		ret = ops->pre_trigger(sdev, dai, substream, cmd);
305 		if (ret < 0)
306 			return ret;
307 	}
308 
309 	if (ops->trigger) {
310 		ret = ops->trigger(sdev, dai, substream, cmd);
311 		if (ret < 0)
312 			return ret;
313 	}
314 
315 	if (ops->post_trigger) {
316 		ret = ops->post_trigger(sdev, dai, substream, cmd);
317 		if (ret < 0)
318 			return ret;
319 	}
320 
321 	switch (cmd) {
322 	case SNDRV_PCM_TRIGGER_SUSPEND:
323 		ret = hda_link_dma_cleanup(substream, hext_stream, dai, codec_dai);
324 		if (ret < 0) {
325 			dev_err(sdev->dev, "%s: failed to clean up link DMA\n", __func__);
326 			return ret;
327 		}
328 		break;
329 	default:
330 		break;
331 	}
332 
333 	return 0;
334 }
335 
336 static const struct snd_soc_dai_ops hda_dai_ops = {
337 	.hw_params = hda_dai_hw_params,
338 	.hw_free = hda_dai_hw_free,
339 	.trigger = hda_dai_trigger,
340 	.prepare = hda_dai_prepare,
341 };
342 
343 static int hda_dai_suspend(struct hdac_bus *bus)
344 {
345 	struct snd_soc_pcm_runtime *rtd;
346 	struct hdac_ext_stream *hext_stream;
347 	struct hdac_stream *s;
348 	int ret;
349 
350 	/* set internal flag for BE */
351 	list_for_each_entry(s, &bus->stream_list, list) {
352 
353 		hext_stream = stream_to_hdac_ext_stream(s);
354 
355 		/*
356 		 * clear stream. This should already be taken care for running
357 		 * streams when the SUSPEND trigger is called. But paused
358 		 * streams do not get suspended, so this needs to be done
359 		 * explicitly during suspend.
360 		 */
361 		if (hext_stream->link_substream) {
362 			const struct hda_dai_widget_dma_ops *ops;
363 			struct snd_sof_widget *swidget;
364 			struct snd_soc_dapm_widget *w;
365 			struct snd_soc_dai *codec_dai;
366 			struct snd_soc_dai *cpu_dai;
367 			struct snd_sof_dev *sdev;
368 			struct snd_sof_dai *sdai;
369 
370 			rtd = asoc_substream_to_rtd(hext_stream->link_substream);
371 			cpu_dai = asoc_rtd_to_cpu(rtd, 0);
372 			codec_dai = asoc_rtd_to_codec(rtd, 0);
373 			w = snd_soc_dai_get_widget(cpu_dai, hdac_stream(hext_stream)->direction);
374 			swidget = w->dobj.private;
375 			sdev = snd_soc_component_get_drvdata(swidget->scomp);
376 			sdai = swidget->private;
377 			ops = sdai->platform_private;
378 
379 			ret = hda_link_dma_cleanup(hext_stream->link_substream,
380 						   hext_stream,
381 						   cpu_dai, codec_dai);
382 			if (ret < 0)
383 				return ret;
384 
385 			/* for consistency with TRIGGER_SUSPEND  */
386 			if (ops->post_trigger) {
387 				ret = ops->post_trigger(sdev, cpu_dai,
388 							hext_stream->link_substream,
389 							SNDRV_PCM_TRIGGER_SUSPEND);
390 				if (ret < 0)
391 					return ret;
392 			}
393 		}
394 	}
395 
396 	return 0;
397 }
398 
399 #endif
400 
401 void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops)
402 {
403 	int i;
404 
405 	for (i = 0; i < ops->num_drv; i++) {
406 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
407 		if (strstr(ops->drv[i].name, "iDisp") ||
408 		    strstr(ops->drv[i].name, "Analog") ||
409 		    strstr(ops->drv[i].name, "Digital"))
410 			ops->drv[i].ops = &hda_dai_ops;
411 #endif
412 	}
413 
414 	if (sdev->pdata->ipc_type == SOF_INTEL_IPC4 && !hda_use_tplg_nhlt) {
415 		struct sof_ipc4_fw_data *ipc4_data = sdev->private;
416 
417 		ipc4_data->nhlt = intel_nhlt_init(sdev->dev);
418 	}
419 }
420 
421 void hda_ops_free(struct snd_sof_dev *sdev)
422 {
423 	if (sdev->pdata->ipc_type == SOF_INTEL_IPC4) {
424 		struct sof_ipc4_fw_data *ipc4_data = sdev->private;
425 
426 		if (!hda_use_tplg_nhlt)
427 			intel_nhlt_free(ipc4_data->nhlt);
428 	}
429 }
430 EXPORT_SYMBOL_NS(hda_ops_free, SND_SOC_SOF_INTEL_HDA_COMMON);
431 
432 /*
433  * common dai driver for skl+ platforms.
434  * some products who use this DAI array only physically have a subset of
435  * the DAIs, but no harm is done here by adding the whole set.
436  */
437 struct snd_soc_dai_driver skl_dai[] = {
438 {
439 	.name = "SSP0 Pin",
440 	.playback = {
441 		.channels_min = 1,
442 		.channels_max = 8,
443 	},
444 	.capture = {
445 		.channels_min = 1,
446 		.channels_max = 8,
447 	},
448 },
449 {
450 	.name = "SSP1 Pin",
451 	.playback = {
452 		.channels_min = 1,
453 		.channels_max = 8,
454 	},
455 	.capture = {
456 		.channels_min = 1,
457 		.channels_max = 8,
458 	},
459 },
460 {
461 	.name = "SSP2 Pin",
462 	.playback = {
463 		.channels_min = 1,
464 		.channels_max = 8,
465 	},
466 	.capture = {
467 		.channels_min = 1,
468 		.channels_max = 8,
469 	},
470 },
471 {
472 	.name = "SSP3 Pin",
473 	.playback = {
474 		.channels_min = 1,
475 		.channels_max = 8,
476 	},
477 	.capture = {
478 		.channels_min = 1,
479 		.channels_max = 8,
480 	},
481 },
482 {
483 	.name = "SSP4 Pin",
484 	.playback = {
485 		.channels_min = 1,
486 		.channels_max = 8,
487 	},
488 	.capture = {
489 		.channels_min = 1,
490 		.channels_max = 8,
491 	},
492 },
493 {
494 	.name = "SSP5 Pin",
495 	.playback = {
496 		.channels_min = 1,
497 		.channels_max = 8,
498 	},
499 	.capture = {
500 		.channels_min = 1,
501 		.channels_max = 8,
502 	},
503 },
504 {
505 	.name = "DMIC01 Pin",
506 	.capture = {
507 		.channels_min = 1,
508 		.channels_max = 4,
509 	},
510 },
511 {
512 	.name = "DMIC16k Pin",
513 	.capture = {
514 		.channels_min = 1,
515 		.channels_max = 4,
516 	},
517 },
518 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
519 {
520 	.name = "iDisp1 Pin",
521 	.playback = {
522 		.channels_min = 1,
523 		.channels_max = 8,
524 	},
525 },
526 {
527 	.name = "iDisp2 Pin",
528 	.playback = {
529 		.channels_min = 1,
530 		.channels_max = 8,
531 	},
532 },
533 {
534 	.name = "iDisp3 Pin",
535 	.playback = {
536 		.channels_min = 1,
537 		.channels_max = 8,
538 	},
539 },
540 {
541 	.name = "iDisp4 Pin",
542 	.playback = {
543 		.channels_min = 1,
544 		.channels_max = 8,
545 	},
546 },
547 {
548 	.name = "Analog CPU DAI",
549 	.playback = {
550 		.channels_min = 1,
551 		.channels_max = 16,
552 	},
553 	.capture = {
554 		.channels_min = 1,
555 		.channels_max = 16,
556 	},
557 },
558 {
559 	.name = "Digital CPU DAI",
560 	.playback = {
561 		.channels_min = 1,
562 		.channels_max = 16,
563 	},
564 	.capture = {
565 		.channels_min = 1,
566 		.channels_max = 16,
567 	},
568 },
569 {
570 	.name = "Alt Analog CPU DAI",
571 	.playback = {
572 		.channels_min = 1,
573 		.channels_max = 16,
574 	},
575 	.capture = {
576 		.channels_min = 1,
577 		.channels_max = 16,
578 	},
579 },
580 #endif
581 };
582 
583 int hda_dsp_dais_suspend(struct snd_sof_dev *sdev)
584 {
585 	/*
586 	 * In the corner case where a SUSPEND happens during a PAUSE, the ALSA core
587 	 * does not throw the TRIGGER_SUSPEND. This leaves the DAIs in an unbalanced state.
588 	 * Since the component suspend is called last, we can trap this corner case
589 	 * and force the DAIs to release their resources.
590 	 */
591 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
592 	int ret;
593 
594 	ret = hda_dai_suspend(sof_to_bus(sdev));
595 	if (ret < 0)
596 		return ret;
597 #endif
598 
599 	return 0;
600 }
601