]> Git Repo - linux.git/blob - sound/soc/sof/intel/hda-dai.c
Merge tag 'amd-drm-next-6.5-2023-06-09' of https://gitlab.freedesktop.org/agd5f/linux...
[linux.git] / sound / soc / sof / intel / hda-dai.c
1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
2 //
3 // This file is provided under a dual BSD/GPLv2 license.  When using or
4 // redistributing this file, you may do so under either license.
5 //
6 // Copyright(c) 2018 Intel Corporation. All rights reserved.
7 //
8 // Authors: Keyon Jie <[email protected]>
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 }
This page took 0.066499 seconds and 4 git commands to generate.