~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/soc/sof/intel/hda-dai-ops.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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
  7 
  8 #include <sound/pcm_params.h>
  9 #include <sound/hdaudio_ext.h>
 10 #include <sound/hda_register.h>
 11 #include <sound/hda-mlink.h>
 12 #include <sound/sof/ipc4/header.h>
 13 #include <uapi/sound/sof/header.h>
 14 #include "../ipc4-priv.h"
 15 #include "../ipc4-topology.h"
 16 #include "../sof-priv.h"
 17 #include "../sof-audio.h"
 18 #include "hda.h"
 19 
 20 /* These ops are only applicable for the HDA DAI's in their current form */
 21 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK)
 22 /*
 23  * This function checks if the host dma channel corresponding
 24  * to the link DMA stream_tag argument is assigned to one
 25  * of the FEs connected to the BE DAI.
 26  */
 27 static bool hda_check_fes(struct snd_soc_pcm_runtime *rtd,
 28                           int dir, int stream_tag)
 29 {
 30         struct snd_pcm_substream *fe_substream;
 31         struct hdac_stream *fe_hstream;
 32         struct snd_soc_dpcm *dpcm;
 33 
 34         for_each_dpcm_fe(rtd, dir, dpcm) {
 35                 fe_substream = snd_soc_dpcm_get_substream(dpcm->fe, dir);
 36                 fe_hstream = fe_substream->runtime->private_data;
 37                 if (fe_hstream->stream_tag == stream_tag)
 38                         return true;
 39         }
 40 
 41         return false;
 42 }
 43 
 44 static struct hdac_ext_stream *
 45 hda_link_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream)
 46 {
 47         struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
 48         struct sof_intel_hda_stream *hda_stream;
 49         const struct sof_intel_dsp_desc *chip;
 50         struct snd_sof_dev *sdev;
 51         struct hdac_ext_stream *res = NULL;
 52         struct hdac_stream *hstream = NULL;
 53 
 54         int stream_dir = substream->stream;
 55 
 56         if (!bus->ppcap) {
 57                 dev_err(bus->dev, "stream type not supported\n");
 58                 return NULL;
 59         }
 60 
 61         spin_lock_irq(&bus->reg_lock);
 62         list_for_each_entry(hstream, &bus->stream_list, list) {
 63                 struct hdac_ext_stream *hext_stream =
 64                         stream_to_hdac_ext_stream(hstream);
 65                 if (hstream->direction != substream->stream)
 66                         continue;
 67 
 68                 hda_stream = hstream_to_sof_hda_stream(hext_stream);
 69                 sdev = hda_stream->sdev;
 70                 chip = get_chip_info(sdev->pdata);
 71 
 72                 /* check if link is available */
 73                 if (!hext_stream->link_locked) {
 74                         /*
 75                          * choose the first available link for platforms that do not have the
 76                          * PROCEN_FMT_QUIRK set.
 77                          */
 78                         if (!(chip->quirks & SOF_INTEL_PROCEN_FMT_QUIRK)) {
 79                                 res = hext_stream;
 80                                 break;
 81                         }
 82 
 83                         if (hstream->opened) {
 84                                 /*
 85                                  * check if the stream tag matches the stream
 86                                  * tag of one of the connected FEs
 87                                  */
 88                                 if (hda_check_fes(rtd, stream_dir,
 89                                                   hstream->stream_tag)) {
 90                                         res = hext_stream;
 91                                         break;
 92                                 }
 93                         } else {
 94                                 res = hext_stream;
 95 
 96                                 /*
 97                                  * This must be a hostless stream.
 98                                  * So reserve the host DMA channel.
 99                                  */
100                                 hda_stream->host_reserved = 1;
101                                 break;
102                         }
103                 }
104         }
105 
106         if (res) {
107                 /* Make sure that host and link DMA is decoupled. */
108                 snd_hdac_ext_stream_decouple_locked(bus, res, true);
109 
110                 res->link_locked = 1;
111                 res->link_substream = substream;
112         }
113         spin_unlock_irq(&bus->reg_lock);
114 
115         return res;
116 }
117 
118 static struct hdac_ext_stream *hda_get_hext_stream(struct snd_sof_dev *sdev,
119                                                    struct snd_soc_dai *cpu_dai,
120                                                    struct snd_pcm_substream *substream)
121 {
122         return snd_soc_dai_get_dma_data(cpu_dai, substream);
123 }
124 
125 static struct hdac_ext_stream *hda_ipc4_get_hext_stream(struct snd_sof_dev *sdev,
126                                                         struct snd_soc_dai *cpu_dai,
127                                                         struct snd_pcm_substream *substream)
128 {
129         struct snd_sof_widget *pipe_widget;
130         struct sof_ipc4_pipeline *pipeline;
131         struct snd_sof_widget *swidget;
132         struct snd_soc_dapm_widget *w;
133 
134         w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
135         swidget = w->dobj.private;
136         pipe_widget = swidget->spipe->pipe_widget;
137         pipeline = pipe_widget->private;
138 
139         /* mark pipeline so that it can be skipped during FE trigger */
140         pipeline->skip_during_fe_trigger = true;
141 
142         return snd_soc_dai_get_dma_data(cpu_dai, substream);
143 }
144 
145 static struct hdac_ext_stream *hda_assign_hext_stream(struct snd_sof_dev *sdev,
146                                                       struct snd_soc_dai *cpu_dai,
147                                                       struct snd_pcm_substream *substream)
148 {
149         struct hdac_ext_stream *hext_stream;
150 
151         hext_stream = hda_link_stream_assign(sof_to_bus(sdev), substream);
152         if (!hext_stream)
153                 return NULL;
154 
155         snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)hext_stream);
156 
157         return hext_stream;
158 }
159 
160 static void hda_release_hext_stream(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
161                                     struct snd_pcm_substream *substream)
162 {
163         struct hdac_ext_stream *hext_stream = hda_get_hext_stream(sdev, cpu_dai, substream);
164 
165         snd_soc_dai_set_dma_data(cpu_dai, substream, NULL);
166         snd_hdac_ext_stream_release(hext_stream, HDAC_EXT_STREAM_TYPE_LINK);
167 }
168 
169 static void hda_setup_hext_stream(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream,
170                                   unsigned int format_val)
171 {
172         snd_hdac_ext_stream_setup(hext_stream, format_val);
173 }
174 
175 static void hda_reset_hext_stream(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream)
176 {
177         snd_hdac_ext_stream_reset(hext_stream);
178 }
179 
180 static void hda_codec_dai_set_stream(struct snd_sof_dev *sdev,
181                                      struct snd_pcm_substream *substream,
182                                      struct hdac_stream *hstream)
183 {
184         struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
185         struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
186 
187         /* set the hdac_stream in the codec dai */
188         snd_soc_dai_set_stream(codec_dai, hstream, substream->stream);
189 }
190 
191 static unsigned int hda_calc_stream_format(struct snd_sof_dev *sdev,
192                                            struct snd_pcm_substream *substream,
193                                            struct snd_pcm_hw_params *params)
194 {
195         struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
196         struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
197         unsigned int link_bps;
198         unsigned int format_val;
199         unsigned int bits;
200 
201         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
202                 link_bps = codec_dai->driver->playback.sig_bits;
203         else
204                 link_bps = codec_dai->driver->capture.sig_bits;
205 
206         bits = snd_hdac_stream_format_bits(params_format(params), SNDRV_PCM_SUBFORMAT_STD,
207                                            link_bps);
208         format_val = snd_hdac_stream_format(params_channels(params), bits, params_rate(params));
209 
210         dev_dbg(sdev->dev, "format_val=%#x, rate=%d, ch=%d, format=%d\n", format_val,
211                 params_rate(params), params_channels(params), params_format(params));
212 
213         return format_val;
214 }
215 
216 static struct hdac_ext_link *hda_get_hlink(struct snd_sof_dev *sdev,
217                                            struct snd_pcm_substream *substream)
218 {
219         struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
220         struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
221         struct hdac_bus *bus = sof_to_bus(sdev);
222 
223         return snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name);
224 }
225 
226 static unsigned int generic_calc_stream_format(struct snd_sof_dev *sdev,
227                                                struct snd_pcm_substream *substream,
228                                                struct snd_pcm_hw_params *params)
229 {
230         unsigned int format_val;
231         unsigned int bits;
232 
233         bits = snd_hdac_stream_format_bits(params_format(params), SNDRV_PCM_SUBFORMAT_STD,
234                                            params_physical_width(params));
235         format_val = snd_hdac_stream_format(params_channels(params), bits, params_rate(params));
236 
237         dev_dbg(sdev->dev, "format_val=%#x, rate=%d, ch=%d, format=%d\n", format_val,
238                 params_rate(params), params_channels(params), params_format(params));
239 
240         return format_val;
241 }
242 
243 static unsigned int dmic_calc_stream_format(struct snd_sof_dev *sdev,
244                                             struct snd_pcm_substream *substream,
245                                             struct snd_pcm_hw_params *params)
246 {
247         unsigned int format_val;
248         snd_pcm_format_t format;
249         unsigned int channels;
250         unsigned int width;
251         unsigned int bits;
252 
253         channels = params_channels(params);
254         format = params_format(params);
255         width = params_physical_width(params);
256 
257         if (format == SNDRV_PCM_FORMAT_S16_LE) {
258                 format = SNDRV_PCM_FORMAT_S32_LE;
259                 channels /= 2;
260                 width = 32;
261         }
262 
263         bits = snd_hdac_stream_format_bits(format, SNDRV_PCM_SUBFORMAT_STD, width);
264         format_val = snd_hdac_stream_format(channels, bits, params_rate(params));
265 
266         dev_dbg(sdev->dev, "format_val=%#x, rate=%d, ch=%d, format=%d\n", format_val,
267                 params_rate(params), channels, format);
268 
269         return format_val;
270 }
271 
272 static struct hdac_ext_link *ssp_get_hlink(struct snd_sof_dev *sdev,
273                                            struct snd_pcm_substream *substream)
274 {
275         struct hdac_bus *bus = sof_to_bus(sdev);
276 
277         return hdac_bus_eml_ssp_get_hlink(bus);
278 }
279 
280 static struct hdac_ext_link *dmic_get_hlink(struct snd_sof_dev *sdev,
281                                             struct snd_pcm_substream *substream)
282 {
283         struct hdac_bus *bus = sof_to_bus(sdev);
284 
285         return hdac_bus_eml_dmic_get_hlink(bus);
286 }
287 
288 static struct hdac_ext_link *sdw_get_hlink(struct snd_sof_dev *sdev,
289                                            struct snd_pcm_substream *substream)
290 {
291         struct hdac_bus *bus = sof_to_bus(sdev);
292 
293         return hdac_bus_eml_sdw_get_hlink(bus);
294 }
295 
296 static int hda_ipc4_pre_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
297                                 struct snd_pcm_substream *substream, int cmd)
298 {
299         struct sof_ipc4_fw_data *ipc4_data = sdev->private;
300         struct snd_sof_widget *pipe_widget;
301         struct sof_ipc4_pipeline *pipeline;
302         struct snd_sof_widget *swidget;
303         struct snd_soc_dapm_widget *w;
304         int ret = 0;
305 
306         w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
307         swidget = w->dobj.private;
308         pipe_widget = swidget->spipe->pipe_widget;
309         pipeline = pipe_widget->private;
310 
311         if (pipe_widget->instance_id < 0)
312                 return 0;
313 
314         mutex_lock(&ipc4_data->pipeline_state_mutex);
315 
316         switch (cmd) {
317         case SNDRV_PCM_TRIGGER_START:
318         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
319                 break;
320         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
321         case SNDRV_PCM_TRIGGER_SUSPEND:
322         case SNDRV_PCM_TRIGGER_STOP:
323                 ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
324                                                   SOF_IPC4_PIPE_PAUSED);
325                 if (ret < 0)
326                         goto out;
327 
328                 pipeline->state = SOF_IPC4_PIPE_PAUSED;
329                 break;
330         default:
331                 dev_err(sdev->dev, "unknown trigger command %d\n", cmd);
332                 ret = -EINVAL;
333         }
334 out:
335         mutex_unlock(&ipc4_data->pipeline_state_mutex);
336         return ret;
337 }
338 
339 static int hda_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
340                        struct snd_pcm_substream *substream, int cmd)
341 {
342         struct hdac_ext_stream *hext_stream = snd_soc_dai_get_dma_data(cpu_dai, substream);
343 
344         switch (cmd) {
345         case SNDRV_PCM_TRIGGER_START:
346         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
347                 snd_hdac_ext_stream_start(hext_stream);
348                 break;
349         case SNDRV_PCM_TRIGGER_SUSPEND:
350         case SNDRV_PCM_TRIGGER_STOP:
351         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
352                 snd_hdac_ext_stream_clear(hext_stream);
353 
354                 /*
355                  * Save the LLP registers in case the stream is
356                  * restarting due PAUSE_RELEASE, or START without a pcm
357                  * close/open since in this case the LLP register is not reset
358                  * to 0 and the delay calculation will return with invalid
359                  * results.
360                  */
361                 hext_stream->pplcllpl = readl(hext_stream->pplc_addr + AZX_REG_PPLCLLPL);
362                 hext_stream->pplcllpu = readl(hext_stream->pplc_addr + AZX_REG_PPLCLLPU);
363                 break;
364         default:
365                 dev_err(sdev->dev, "unknown trigger command %d\n", cmd);
366                 return -EINVAL;
367         }
368 
369         return 0;
370 }
371 
372 static int hda_ipc4_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
373                                  struct snd_pcm_substream *substream, int cmd)
374 {
375         struct sof_ipc4_fw_data *ipc4_data = sdev->private;
376         struct snd_sof_widget *pipe_widget;
377         struct sof_ipc4_pipeline *pipeline;
378         struct snd_sof_widget *swidget;
379         struct snd_soc_dapm_widget *w;
380         int ret = 0;
381 
382         w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
383         swidget = w->dobj.private;
384         pipe_widget = swidget->spipe->pipe_widget;
385         pipeline = pipe_widget->private;
386 
387         if (pipe_widget->instance_id < 0)
388                 return 0;
389 
390         mutex_lock(&ipc4_data->pipeline_state_mutex);
391 
392         switch (cmd) {
393         case SNDRV_PCM_TRIGGER_START:
394                 if (pipeline->state != SOF_IPC4_PIPE_PAUSED) {
395                         ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
396                                                           SOF_IPC4_PIPE_PAUSED);
397                         if (ret < 0)
398                                 goto out;
399                         pipeline->state = SOF_IPC4_PIPE_PAUSED;
400                 }
401 
402                 ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
403                                                   SOF_IPC4_PIPE_RUNNING);
404                 if (ret < 0)
405                         goto out;
406                 pipeline->state = SOF_IPC4_PIPE_RUNNING;
407                 swidget->spipe->started_count++;
408                 break;
409         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
410                 ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
411                                                   SOF_IPC4_PIPE_RUNNING);
412                 if (ret < 0)
413                         goto out;
414                 pipeline->state = SOF_IPC4_PIPE_RUNNING;
415                 break;
416         case SNDRV_PCM_TRIGGER_SUSPEND:
417         case SNDRV_PCM_TRIGGER_STOP:
418                 /*
419                  * STOP/SUSPEND trigger is invoked only once when all users of this pipeline have
420                  * been stopped. So, clear the started_count so that the pipeline can be reset
421                  */
422                 swidget->spipe->started_count = 0;
423                 break;
424         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
425                 break;
426         default:
427                 dev_err(sdev->dev, "unknown trigger command %d\n", cmd);
428                 ret = -EINVAL;
429                 break;
430         }
431 out:
432         mutex_unlock(&ipc4_data->pipeline_state_mutex);
433         return ret;
434 }
435 
436 static const struct hda_dai_widget_dma_ops hda_ipc4_dma_ops = {
437         .get_hext_stream = hda_ipc4_get_hext_stream,
438         .assign_hext_stream = hda_assign_hext_stream,
439         .release_hext_stream = hda_release_hext_stream,
440         .setup_hext_stream = hda_setup_hext_stream,
441         .reset_hext_stream = hda_reset_hext_stream,
442         .pre_trigger = hda_ipc4_pre_trigger,
443         .trigger = hda_trigger,
444         .post_trigger = hda_ipc4_post_trigger,
445         .codec_dai_set_stream = hda_codec_dai_set_stream,
446         .calc_stream_format = hda_calc_stream_format,
447         .get_hlink = hda_get_hlink,
448 };
449 
450 static const struct hda_dai_widget_dma_ops ssp_ipc4_dma_ops = {
451         .get_hext_stream = hda_ipc4_get_hext_stream,
452         .assign_hext_stream = hda_assign_hext_stream,
453         .release_hext_stream = hda_release_hext_stream,
454         .setup_hext_stream = hda_setup_hext_stream,
455         .reset_hext_stream = hda_reset_hext_stream,
456         .pre_trigger = hda_ipc4_pre_trigger,
457         .trigger = hda_trigger,
458         .post_trigger = hda_ipc4_post_trigger,
459         .calc_stream_format = generic_calc_stream_format,
460         .get_hlink = ssp_get_hlink,
461 };
462 
463 static const struct hda_dai_widget_dma_ops dmic_ipc4_dma_ops = {
464         .get_hext_stream = hda_ipc4_get_hext_stream,
465         .assign_hext_stream = hda_assign_hext_stream,
466         .release_hext_stream = hda_release_hext_stream,
467         .setup_hext_stream = hda_setup_hext_stream,
468         .reset_hext_stream = hda_reset_hext_stream,
469         .pre_trigger = hda_ipc4_pre_trigger,
470         .trigger = hda_trigger,
471         .post_trigger = hda_ipc4_post_trigger,
472         .calc_stream_format = dmic_calc_stream_format,
473         .get_hlink = dmic_get_hlink,
474 };
475 
476 static const struct hda_dai_widget_dma_ops sdw_ipc4_dma_ops = {
477         .get_hext_stream = hda_ipc4_get_hext_stream,
478         .assign_hext_stream = hda_assign_hext_stream,
479         .release_hext_stream = hda_release_hext_stream,
480         .setup_hext_stream = hda_setup_hext_stream,
481         .reset_hext_stream = hda_reset_hext_stream,
482         .pre_trigger = hda_ipc4_pre_trigger,
483         .trigger = hda_trigger,
484         .post_trigger = hda_ipc4_post_trigger,
485         .calc_stream_format = generic_calc_stream_format,
486         .get_hlink = sdw_get_hlink,
487 };
488 
489 static const struct hda_dai_widget_dma_ops hda_ipc4_chain_dma_ops = {
490         .get_hext_stream = hda_get_hext_stream,
491         .assign_hext_stream = hda_assign_hext_stream,
492         .release_hext_stream = hda_release_hext_stream,
493         .setup_hext_stream = hda_setup_hext_stream,
494         .reset_hext_stream = hda_reset_hext_stream,
495         .trigger = hda_trigger,
496         .codec_dai_set_stream = hda_codec_dai_set_stream,
497         .calc_stream_format = hda_calc_stream_format,
498         .get_hlink = hda_get_hlink,
499 };
500 
501 static const struct hda_dai_widget_dma_ops sdw_ipc4_chain_dma_ops = {
502         .get_hext_stream = hda_get_hext_stream,
503         .assign_hext_stream = hda_assign_hext_stream,
504         .release_hext_stream = hda_release_hext_stream,
505         .setup_hext_stream = hda_setup_hext_stream,
506         .reset_hext_stream = hda_reset_hext_stream,
507         .trigger = hda_trigger,
508         .calc_stream_format = generic_calc_stream_format,
509         .get_hlink = sdw_get_hlink,
510 };
511 
512 static int hda_ipc3_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
513                                  struct snd_pcm_substream *substream, int cmd)
514 {
515         struct hdac_ext_stream *hext_stream = hda_get_hext_stream(sdev, cpu_dai, substream);
516         struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
517 
518         switch (cmd) {
519         case SNDRV_PCM_TRIGGER_SUSPEND:
520         case SNDRV_PCM_TRIGGER_STOP:
521         {
522                 struct snd_sof_dai_config_data data = { 0 };
523                 int ret;
524 
525                 data.dai_data = DMA_CHAN_INVALID;
526                 ret = hda_dai_config(w, SOF_DAI_CONFIG_FLAGS_HW_FREE, &data);
527                 if (ret < 0)
528                         return ret;
529 
530                 if (cmd == SNDRV_PCM_TRIGGER_STOP)
531                         return hda_link_dma_cleanup(substream, hext_stream, cpu_dai);
532 
533                 break;
534         }
535         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
536                 return hda_dai_config(w, SOF_DAI_CONFIG_FLAGS_PAUSE, NULL);
537         default:
538                 break;
539         }
540 
541         return 0;
542 }
543 
544 static const struct hda_dai_widget_dma_ops hda_ipc3_dma_ops = {
545         .get_hext_stream = hda_get_hext_stream,
546         .assign_hext_stream = hda_assign_hext_stream,
547         .release_hext_stream = hda_release_hext_stream,
548         .setup_hext_stream = hda_setup_hext_stream,
549         .reset_hext_stream = hda_reset_hext_stream,
550         .trigger = hda_trigger,
551         .post_trigger = hda_ipc3_post_trigger,
552         .codec_dai_set_stream = hda_codec_dai_set_stream,
553         .calc_stream_format = hda_calc_stream_format,
554         .get_hlink = hda_get_hlink,
555 };
556 
557 static struct hdac_ext_stream *
558 hda_dspless_get_hext_stream(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
559                             struct snd_pcm_substream *substream)
560 {
561         struct hdac_stream *hstream = substream->runtime->private_data;
562 
563         return stream_to_hdac_ext_stream(hstream);
564 }
565 
566 static void hda_dspless_setup_hext_stream(struct snd_sof_dev *sdev,
567                                           struct hdac_ext_stream *hext_stream,
568                                           unsigned int format_val)
569 {
570         /*
571          * Save the format_val which was adjusted by the maxbps of the codec.
572          * This information is not available on the FE side since there we are
573          * using dummy_codec.
574          */
575         hext_stream->hstream.format_val = format_val;
576 }
577 
578 static const struct hda_dai_widget_dma_ops hda_dspless_dma_ops = {
579         .get_hext_stream = hda_dspless_get_hext_stream,
580         .setup_hext_stream = hda_dspless_setup_hext_stream,
581         .codec_dai_set_stream = hda_codec_dai_set_stream,
582         .calc_stream_format = hda_calc_stream_format,
583         .get_hlink = hda_get_hlink,
584 };
585 
586 static const struct hda_dai_widget_dma_ops sdw_dspless_dma_ops = {
587         .get_hext_stream = hda_dspless_get_hext_stream,
588         .setup_hext_stream = hda_dspless_setup_hext_stream,
589         .calc_stream_format = generic_calc_stream_format,
590         .get_hlink = sdw_get_hlink,
591 };
592 
593 #endif
594 
595 const struct hda_dai_widget_dma_ops *
596 hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
597 {
598 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK)
599         struct snd_sof_dai *sdai;
600         const struct sof_intel_dsp_desc *chip;
601 
602         chip = get_chip_info(sdev->pdata);
603         sdai = swidget->private;
604 
605         if (sdev->dspless_mode_selected) {
606                 switch (sdai->type) {
607                 case SOF_DAI_INTEL_HDA:
608                         return &hda_dspless_dma_ops;
609                 case SOF_DAI_INTEL_ALH:
610                         if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
611                                 return NULL;
612                         return &sdw_dspless_dma_ops;
613                 default:
614                         return NULL;
615                 }
616         }
617 
618         switch (sdev->pdata->ipc_type) {
619         case SOF_IPC_TYPE_3:
620         {
621                 struct sof_dai_private_data *private = sdai->private;
622 
623                 if (private->dai_config->type == SOF_DAI_INTEL_HDA)
624                         return &hda_ipc3_dma_ops;
625                 break;
626         }
627         case SOF_IPC_TYPE_4:
628         {
629                 struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
630                 struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
631 
632                 switch (sdai->type) {
633                 case SOF_DAI_INTEL_HDA:
634                         if (pipeline->use_chain_dma)
635                                 return &hda_ipc4_chain_dma_ops;
636 
637                         return &hda_ipc4_dma_ops;
638                 case SOF_DAI_INTEL_SSP:
639                         if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
640                                 return NULL;
641                         return &ssp_ipc4_dma_ops;
642                 case SOF_DAI_INTEL_DMIC:
643                         if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
644                                 return NULL;
645                         return &dmic_ipc4_dma_ops;
646                 case SOF_DAI_INTEL_ALH:
647                         if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
648                                 return NULL;
649                         if (pipeline->use_chain_dma)
650                                 return &sdw_ipc4_chain_dma_ops;
651                         return &sdw_ipc4_dma_ops;
652 
653                 default:
654                         break;
655                 }
656                 break;
657         }
658         default:
659                 break;
660         }
661 #endif
662         return NULL;
663 }
664 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php