Merge tag 'drm-misc-next-fixes-2023-09-01' of git://anongit.freedesktop.org/drm/drm...
[platform/kernel/linux-rpi.git] / sound / soc / sof / intel / hda-dai-ops.c
1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
2 //
3 // This file is provided under a dual BSD/GPLv2 license.  When using or
4 // redistributing this file, you may do so under either license.
5 //
6 // Copyright(c) 2022 Intel Corporation. All rights reserved.
7
8 #include <sound/pcm_params.h>
9 #include <sound/hdaudio_ext.h>
10 #include <sound/sof/ipc4/header.h>
11 #include <uapi/sound/sof/header.h>
12 #include "../ipc4-priv.h"
13 #include "../ipc4-topology.h"
14 #include "../sof-priv.h"
15 #include "../sof-audio.h"
16 #include "hda.h"
17
18 /* These ops are only applicable for the HDA DAI's in their current form */
19 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK)
20 /*
21  * This function checks if the host dma channel corresponding
22  * to the link DMA stream_tag argument is assigned to one
23  * of the FEs connected to the BE DAI.
24  */
25 static bool hda_check_fes(struct snd_soc_pcm_runtime *rtd,
26                           int dir, int stream_tag)
27 {
28         struct snd_pcm_substream *fe_substream;
29         struct hdac_stream *fe_hstream;
30         struct snd_soc_dpcm *dpcm;
31
32         for_each_dpcm_fe(rtd, dir, dpcm) {
33                 fe_substream = snd_soc_dpcm_get_substream(dpcm->fe, dir);
34                 fe_hstream = fe_substream->runtime->private_data;
35                 if (fe_hstream->stream_tag == stream_tag)
36                         return true;
37         }
38
39         return false;
40 }
41
42 static struct hdac_ext_stream *
43 hda_link_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream)
44 {
45         struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
46         struct sof_intel_hda_stream *hda_stream;
47         const struct sof_intel_dsp_desc *chip;
48         struct snd_sof_dev *sdev;
49         struct hdac_ext_stream *res = NULL;
50         struct hdac_stream *hstream = NULL;
51
52         int stream_dir = substream->stream;
53
54         if (!bus->ppcap) {
55                 dev_err(bus->dev, "stream type not supported\n");
56                 return NULL;
57         }
58
59         spin_lock_irq(&bus->reg_lock);
60         list_for_each_entry(hstream, &bus->stream_list, list) {
61                 struct hdac_ext_stream *hext_stream =
62                         stream_to_hdac_ext_stream(hstream);
63                 if (hstream->direction != substream->stream)
64                         continue;
65
66                 hda_stream = hstream_to_sof_hda_stream(hext_stream);
67                 sdev = hda_stream->sdev;
68                 chip = get_chip_info(sdev->pdata);
69
70                 /* check if link is available */
71                 if (!hext_stream->link_locked) {
72                         /*
73                          * choose the first available link for platforms that do not have the
74                          * PROCEN_FMT_QUIRK set.
75                          */
76                         if (!(chip->quirks & SOF_INTEL_PROCEN_FMT_QUIRK)) {
77                                 res = hext_stream;
78                                 break;
79                         }
80
81                         if (hstream->opened) {
82                                 /*
83                                  * check if the stream tag matches the stream
84                                  * tag of one of the connected FEs
85                                  */
86                                 if (hda_check_fes(rtd, stream_dir,
87                                                   hstream->stream_tag)) {
88                                         res = hext_stream;
89                                         break;
90                                 }
91                         } else {
92                                 res = hext_stream;
93
94                                 /*
95                                  * This must be a hostless stream.
96                                  * So reserve the host DMA channel.
97                                  */
98                                 hda_stream->host_reserved = 1;
99                                 break;
100                         }
101                 }
102         }
103
104         if (res) {
105                 /* Make sure that host and link DMA is decoupled. */
106                 snd_hdac_ext_stream_decouple_locked(bus, res, true);
107
108                 res->link_locked = 1;
109                 res->link_substream = substream;
110         }
111         spin_unlock_irq(&bus->reg_lock);
112
113         return res;
114 }
115
116 static struct hdac_ext_stream *hda_get_hext_stream(struct snd_sof_dev *sdev,
117                                                    struct snd_soc_dai *cpu_dai,
118                                                    struct snd_pcm_substream *substream)
119 {
120         return snd_soc_dai_get_dma_data(cpu_dai, substream);
121 }
122
123 static struct hdac_ext_stream *hda_ipc4_get_hext_stream(struct snd_sof_dev *sdev,
124                                                         struct snd_soc_dai *cpu_dai,
125                                                         struct snd_pcm_substream *substream)
126 {
127         struct snd_sof_widget *pipe_widget;
128         struct sof_ipc4_pipeline *pipeline;
129         struct snd_sof_widget *swidget;
130         struct snd_soc_dapm_widget *w;
131
132         w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
133         swidget = w->dobj.private;
134         pipe_widget = swidget->spipe->pipe_widget;
135         pipeline = pipe_widget->private;
136
137         /* mark pipeline so that it can be skipped during FE trigger */
138         pipeline->skip_during_fe_trigger = true;
139
140         return snd_soc_dai_get_dma_data(cpu_dai, substream);
141 }
142
143 static struct hdac_ext_stream *hda_assign_hext_stream(struct snd_sof_dev *sdev,
144                                                       struct snd_soc_dai *cpu_dai,
145                                                       struct snd_pcm_substream *substream)
146 {
147         struct hdac_ext_stream *hext_stream;
148
149         hext_stream = hda_link_stream_assign(sof_to_bus(sdev), substream);
150         if (!hext_stream)
151                 return NULL;
152
153         snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)hext_stream);
154
155         return hext_stream;
156 }
157
158 static void hda_release_hext_stream(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
159                                     struct snd_pcm_substream *substream)
160 {
161         struct hdac_ext_stream *hext_stream = hda_get_hext_stream(sdev, cpu_dai, substream);
162
163         snd_soc_dai_set_dma_data(cpu_dai, substream, NULL);
164         snd_hdac_ext_stream_release(hext_stream, HDAC_EXT_STREAM_TYPE_LINK);
165 }
166
167 static void hda_setup_hext_stream(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream,
168                                   unsigned int format_val)
169 {
170         snd_hdac_ext_stream_setup(hext_stream, format_val);
171 }
172
173 static void hda_reset_hext_stream(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream)
174 {
175         snd_hdac_ext_stream_reset(hext_stream);
176 }
177
178 static void hda_codec_dai_set_stream(struct snd_sof_dev *sdev,
179                                      struct snd_pcm_substream *substream,
180                                      struct hdac_stream *hstream)
181 {
182         struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
183         struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
184
185         /* set the hdac_stream in the codec dai */
186         snd_soc_dai_set_stream(codec_dai, hstream, substream->stream);
187 }
188
189 static unsigned int hda_calc_stream_format(struct snd_sof_dev *sdev,
190                                            struct snd_pcm_substream *substream,
191                                            struct snd_pcm_hw_params *params)
192 {
193         struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
194         struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
195         unsigned int link_bps;
196         unsigned int format_val;
197
198         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
199                 link_bps = codec_dai->driver->playback.sig_bits;
200         else
201                 link_bps = codec_dai->driver->capture.sig_bits;
202
203         format_val = snd_hdac_calc_stream_format(params_rate(params), params_channels(params),
204                                                  params_format(params), link_bps, 0);
205
206         dev_dbg(sdev->dev, "format_val=%#x, rate=%d, ch=%d, format=%d\n", format_val,
207                 params_rate(params), params_channels(params), params_format(params));
208
209         return format_val;
210 }
211
212 static struct hdac_ext_link *hda_get_hlink(struct snd_sof_dev *sdev,
213                                            struct snd_pcm_substream *substream)
214 {
215         struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
216         struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
217         struct hdac_bus *bus = sof_to_bus(sdev);
218
219         return snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name);
220 }
221
222 static int hda_ipc4_pre_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
223                                 struct snd_pcm_substream *substream, int cmd)
224 {
225         struct sof_ipc4_fw_data *ipc4_data = sdev->private;
226         struct snd_sof_widget *pipe_widget;
227         struct sof_ipc4_pipeline *pipeline;
228         struct snd_sof_widget *swidget;
229         struct snd_soc_dapm_widget *w;
230         int ret = 0;
231
232         w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
233         swidget = w->dobj.private;
234         pipe_widget = swidget->spipe->pipe_widget;
235         pipeline = pipe_widget->private;
236
237         mutex_lock(&ipc4_data->pipeline_state_mutex);
238
239         switch (cmd) {
240         case SNDRV_PCM_TRIGGER_START:
241         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
242                 break;
243         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
244         case SNDRV_PCM_TRIGGER_SUSPEND:
245         case SNDRV_PCM_TRIGGER_STOP:
246                 ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
247                                                   SOF_IPC4_PIPE_PAUSED);
248                 if (ret < 0)
249                         goto out;
250
251                 pipeline->state = SOF_IPC4_PIPE_PAUSED;
252                 break;
253         default:
254                 dev_err(sdev->dev, "unknown trigger command %d\n", cmd);
255                 ret = -EINVAL;
256         }
257 out:
258         mutex_unlock(&ipc4_data->pipeline_state_mutex);
259         return ret;
260 }
261
262 static int hda_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
263                        struct snd_pcm_substream *substream, int cmd)
264 {
265         struct hdac_ext_stream *hext_stream = snd_soc_dai_get_dma_data(cpu_dai, substream);
266
267         switch (cmd) {
268         case SNDRV_PCM_TRIGGER_START:
269         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
270                 snd_hdac_ext_stream_start(hext_stream);
271                 break;
272         case SNDRV_PCM_TRIGGER_SUSPEND:
273         case SNDRV_PCM_TRIGGER_STOP:
274         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
275                 snd_hdac_ext_stream_clear(hext_stream);
276                 break;
277         default:
278                 dev_err(sdev->dev, "unknown trigger command %d\n", cmd);
279                 return -EINVAL;
280         }
281
282         return 0;
283 }
284
285 static int hda_ipc4_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
286                                  struct snd_pcm_substream *substream, int cmd)
287 {
288         struct sof_ipc4_fw_data *ipc4_data = sdev->private;
289         struct snd_sof_widget *pipe_widget;
290         struct sof_ipc4_pipeline *pipeline;
291         struct snd_sof_widget *swidget;
292         struct snd_soc_dapm_widget *w;
293         int ret = 0;
294
295         w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
296         swidget = w->dobj.private;
297         pipe_widget = swidget->spipe->pipe_widget;
298         pipeline = pipe_widget->private;
299
300         mutex_lock(&ipc4_data->pipeline_state_mutex);
301
302         switch (cmd) {
303         case SNDRV_PCM_TRIGGER_START:
304                 if (pipeline->state != SOF_IPC4_PIPE_PAUSED) {
305                         ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
306                                                           SOF_IPC4_PIPE_PAUSED);
307                         if (ret < 0)
308                                 goto out;
309                         pipeline->state = SOF_IPC4_PIPE_PAUSED;
310                 }
311
312                 ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
313                                                   SOF_IPC4_PIPE_RUNNING);
314                 if (ret < 0)
315                         goto out;
316                 pipeline->state = SOF_IPC4_PIPE_RUNNING;
317                 swidget->spipe->started_count++;
318                 break;
319         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
320                 ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
321                                                   SOF_IPC4_PIPE_RUNNING);
322                 if (ret < 0)
323                         goto out;
324                 pipeline->state = SOF_IPC4_PIPE_RUNNING;
325                 break;
326         case SNDRV_PCM_TRIGGER_SUSPEND:
327         case SNDRV_PCM_TRIGGER_STOP:
328                 /*
329                  * STOP/SUSPEND trigger is invoked only once when all users of this pipeline have
330                  * been stopped. So, clear the started_count so that the pipeline can be reset
331                  */
332                 swidget->spipe->started_count = 0;
333                 break;
334         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
335                 break;
336         default:
337                 dev_err(sdev->dev, "unknown trigger command %d\n", cmd);
338                 ret = -EINVAL;
339                 break;
340         }
341 out:
342         mutex_unlock(&ipc4_data->pipeline_state_mutex);
343         return ret;
344 }
345
346 static const struct hda_dai_widget_dma_ops hda_ipc4_dma_ops = {
347         .get_hext_stream = hda_ipc4_get_hext_stream,
348         .assign_hext_stream = hda_assign_hext_stream,
349         .release_hext_stream = hda_release_hext_stream,
350         .setup_hext_stream = hda_setup_hext_stream,
351         .reset_hext_stream = hda_reset_hext_stream,
352         .pre_trigger = hda_ipc4_pre_trigger,
353         .trigger = hda_trigger,
354         .post_trigger = hda_ipc4_post_trigger,
355         .codec_dai_set_stream = hda_codec_dai_set_stream,
356         .calc_stream_format = hda_calc_stream_format,
357         .get_hlink = hda_get_hlink,
358 };
359
360 static const struct hda_dai_widget_dma_ops hda_ipc4_chain_dma_ops = {
361         .get_hext_stream = hda_get_hext_stream,
362         .assign_hext_stream = hda_assign_hext_stream,
363         .release_hext_stream = hda_release_hext_stream,
364         .setup_hext_stream = hda_setup_hext_stream,
365         .reset_hext_stream = hda_reset_hext_stream,
366         .trigger = hda_trigger,
367         .codec_dai_set_stream = hda_codec_dai_set_stream,
368         .calc_stream_format = hda_calc_stream_format,
369         .get_hlink = hda_get_hlink,
370 };
371
372 static int hda_ipc3_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
373                                  struct snd_pcm_substream *substream, int cmd)
374 {
375         struct hdac_ext_stream *hext_stream = hda_get_hext_stream(sdev, cpu_dai, substream);
376         struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
377
378         switch (cmd) {
379         case SNDRV_PCM_TRIGGER_SUSPEND:
380         case SNDRV_PCM_TRIGGER_STOP:
381         {
382                 struct snd_sof_dai_config_data data = { 0 };
383                 int ret;
384
385                 data.dai_data = DMA_CHAN_INVALID;
386                 ret = hda_dai_config(w, SOF_DAI_CONFIG_FLAGS_HW_FREE, &data);
387                 if (ret < 0)
388                         return ret;
389
390                 if (cmd == SNDRV_PCM_TRIGGER_STOP)
391                         return hda_link_dma_cleanup(substream, hext_stream, cpu_dai);
392
393                 break;
394         }
395         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
396                 return hda_dai_config(w, SOF_DAI_CONFIG_FLAGS_PAUSE, NULL);
397         default:
398                 break;
399         }
400
401         return 0;
402 }
403
404 static const struct hda_dai_widget_dma_ops hda_ipc3_dma_ops = {
405         .get_hext_stream = hda_get_hext_stream,
406         .assign_hext_stream = hda_assign_hext_stream,
407         .release_hext_stream = hda_release_hext_stream,
408         .setup_hext_stream = hda_setup_hext_stream,
409         .reset_hext_stream = hda_reset_hext_stream,
410         .trigger = hda_trigger,
411         .post_trigger = hda_ipc3_post_trigger,
412         .codec_dai_set_stream = hda_codec_dai_set_stream,
413         .calc_stream_format = hda_calc_stream_format,
414         .get_hlink = hda_get_hlink,
415 };
416
417 static struct hdac_ext_stream *
418 hda_dspless_get_hext_stream(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
419                             struct snd_pcm_substream *substream)
420 {
421         struct hdac_stream *hstream = substream->runtime->private_data;
422
423         return stream_to_hdac_ext_stream(hstream);
424 }
425
426 static void hda_dspless_setup_hext_stream(struct snd_sof_dev *sdev,
427                                           struct hdac_ext_stream *hext_stream,
428                                           unsigned int format_val)
429 {
430         /*
431          * Save the format_val which was adjusted by the maxbps of the codec.
432          * This information is not available on the FE side since there we are
433          * using dummy_codec.
434          */
435         hext_stream->hstream.format_val = format_val;
436 }
437
438 static const struct hda_dai_widget_dma_ops hda_dspless_dma_ops = {
439         .get_hext_stream = hda_dspless_get_hext_stream,
440         .setup_hext_stream = hda_dspless_setup_hext_stream,
441         .codec_dai_set_stream = hda_codec_dai_set_stream,
442         .calc_stream_format = hda_calc_stream_format,
443         .get_hlink = hda_get_hlink,
444 };
445
446 #endif
447
448 const struct hda_dai_widget_dma_ops *
449 hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
450 {
451 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK)
452         struct snd_sof_dai *sdai;
453
454         if (sdev->dspless_mode_selected)
455                 return &hda_dspless_dma_ops;
456
457         sdai = swidget->private;
458
459         switch (sdev->pdata->ipc_type) {
460         case SOF_IPC:
461         {
462                 struct sof_dai_private_data *private = sdai->private;
463
464                 if (private->dai_config->type == SOF_DAI_INTEL_HDA)
465                         return &hda_ipc3_dma_ops;
466                 break;
467         }
468         case SOF_INTEL_IPC4:
469         {
470                 struct sof_ipc4_copier *ipc4_copier = sdai->private;
471
472                 if (ipc4_copier->dai_type == SOF_DAI_INTEL_HDA) {
473                         struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
474                         struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
475
476                         if (pipeline->use_chain_dma)
477                                 return &hda_ipc4_chain_dma_ops;
478
479                         return &hda_ipc4_dma_ops;
480                 }
481                 break;
482         }
483         default:
484                 break;
485         }
486 #endif
487         return NULL;
488 }