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

TOMOYO Linux Cross Reference
Linux/sound/soc/sof/pcm.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) 2018 Intel Corporation
  7 //
  8 // Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
  9 //
 10 // PCM Layer, interface between ALSA and IPC.
 11 //
 12 
 13 #include <linux/pm_runtime.h>
 14 #include <sound/pcm_params.h>
 15 #include <sound/sof.h>
 16 #include <trace/events/sof.h>
 17 #include "sof-of-dev.h"
 18 #include "sof-priv.h"
 19 #include "sof-audio.h"
 20 #include "sof-utils.h"
 21 #include "ops.h"
 22 
 23 /* Create DMA buffer page table for DSP */
 24 static int create_page_table(struct snd_soc_component *component,
 25                              struct snd_pcm_substream *substream,
 26                              unsigned char *dma_area, size_t size)
 27 {
 28         struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
 29         struct snd_sof_pcm *spcm;
 30         struct snd_dma_buffer *dmab = snd_pcm_get_dma_buf(substream);
 31         int stream = substream->stream;
 32 
 33         spcm = snd_sof_find_spcm_dai(component, rtd);
 34         if (!spcm)
 35                 return -EINVAL;
 36 
 37         return snd_sof_create_page_table(component->dev, dmab,
 38                 spcm->stream[stream].page_table.area, size);
 39 }
 40 
 41 /*
 42  * sof pcm period elapse work
 43  */
 44 static void snd_sof_pcm_period_elapsed_work(struct work_struct *work)
 45 {
 46         struct snd_sof_pcm_stream *sps =
 47                 container_of(work, struct snd_sof_pcm_stream,
 48                              period_elapsed_work);
 49 
 50         snd_pcm_period_elapsed(sps->substream);
 51 }
 52 
 53 void snd_sof_pcm_init_elapsed_work(struct work_struct *work)
 54 {
 55          INIT_WORK(work, snd_sof_pcm_period_elapsed_work);
 56 }
 57 
 58 /*
 59  * sof pcm period elapse, this could be called at irq thread context.
 60  */
 61 void snd_sof_pcm_period_elapsed(struct snd_pcm_substream *substream)
 62 {
 63         struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
 64         struct snd_soc_component *component =
 65                 snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME);
 66         struct snd_sof_pcm *spcm;
 67 
 68         spcm = snd_sof_find_spcm_dai(component, rtd);
 69         if (!spcm) {
 70                 dev_err(component->dev,
 71                         "error: period elapsed for unknown stream!\n");
 72                 return;
 73         }
 74 
 75         /*
 76          * snd_pcm_period_elapsed() can be called in interrupt context
 77          * before IRQ_HANDLED is returned. Inside snd_pcm_period_elapsed(),
 78          * when the PCM is done draining or xrun happened, a STOP IPC will
 79          * then be sent and this IPC will hit IPC timeout.
 80          * To avoid sending IPC before the previous IPC is handled, we
 81          * schedule delayed work here to call the snd_pcm_period_elapsed().
 82          */
 83         schedule_work(&spcm->stream[substream->stream].period_elapsed_work);
 84 }
 85 EXPORT_SYMBOL(snd_sof_pcm_period_elapsed);
 86 
 87 static int
 88 sof_pcm_setup_connected_widgets(struct snd_sof_dev *sdev, struct snd_soc_pcm_runtime *rtd,
 89                                 struct snd_sof_pcm *spcm, struct snd_pcm_hw_params *params,
 90                                 struct snd_sof_platform_stream_params *platform_params, int dir)
 91 {
 92         struct snd_soc_dai *dai;
 93         int ret, j;
 94 
 95         /* query DAPM for list of connected widgets and set them up */
 96         for_each_rtd_cpu_dais(rtd, j, dai) {
 97                 struct snd_soc_dapm_widget_list *list;
 98 
 99                 ret = snd_soc_dapm_dai_get_connected_widgets(dai, dir, &list,
100                                                              dpcm_end_walk_at_be);
101                 if (ret < 0) {
102                         dev_err(sdev->dev, "error: dai %s has no valid %s path\n", dai->name,
103                                 dir == SNDRV_PCM_STREAM_PLAYBACK ? "playback" : "capture");
104                         return ret;
105                 }
106 
107                 spcm->stream[dir].list = list;
108 
109                 ret = sof_widget_list_setup(sdev, spcm, params, platform_params, dir);
110                 if (ret < 0) {
111                         dev_err(sdev->dev, "error: failed widget list set up for pcm %d dir %d\n",
112                                 spcm->pcm.pcm_id, dir);
113                         spcm->stream[dir].list = NULL;
114                         snd_soc_dapm_dai_free_widgets(&list);
115                         return ret;
116                 }
117         }
118 
119         return 0;
120 }
121 
122 static int sof_pcm_hw_params(struct snd_soc_component *component,
123                              struct snd_pcm_substream *substream,
124                              struct snd_pcm_hw_params *params)
125 {
126         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
127         struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
128         const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm);
129         struct snd_sof_platform_stream_params platform_params = { 0 };
130         struct snd_pcm_runtime *runtime = substream->runtime;
131         struct snd_sof_pcm *spcm;
132         int ret;
133 
134         /* nothing to do for BE */
135         if (rtd->dai_link->no_pcm)
136                 return 0;
137 
138         spcm = snd_sof_find_spcm_dai(component, rtd);
139         if (!spcm)
140                 return -EINVAL;
141 
142         /*
143          * Handle repeated calls to hw_params() without free_pcm() in
144          * between. At least ALSA OSS emulation depends on this.
145          */
146         if (pcm_ops && pcm_ops->hw_free && spcm->prepared[substream->stream]) {
147                 ret = pcm_ops->hw_free(component, substream);
148                 if (ret < 0)
149                         return ret;
150 
151                 spcm->prepared[substream->stream] = false;
152         }
153 
154         dev_dbg(component->dev, "pcm: hw params stream %d dir %d\n",
155                 spcm->pcm.pcm_id, substream->stream);
156 
157         ret = snd_sof_pcm_platform_hw_params(sdev, substream, params, &platform_params);
158         if (ret < 0) {
159                 dev_err(component->dev, "platform hw params failed\n");
160                 return ret;
161         }
162 
163         /* if this is a repeated hw_params without hw_free, skip setting up widgets */
164         if (!spcm->stream[substream->stream].list) {
165                 ret = sof_pcm_setup_connected_widgets(sdev, rtd, spcm, params, &platform_params,
166                                                       substream->stream);
167                 if (ret < 0)
168                         return ret;
169         }
170 
171         /* create compressed page table for audio firmware */
172         if (runtime->buffer_changed) {
173                 ret = create_page_table(component, substream, runtime->dma_area,
174                                         runtime->dma_bytes);
175 
176                 if (ret < 0)
177                         return ret;
178         }
179 
180         if (pcm_ops && pcm_ops->hw_params) {
181                 ret = pcm_ops->hw_params(component, substream, params, &platform_params);
182                 if (ret < 0)
183                         return ret;
184         }
185 
186         spcm->prepared[substream->stream] = true;
187 
188         /* save pcm hw_params */
189         memcpy(&spcm->params[substream->stream], params, sizeof(*params));
190 
191         return 0;
192 }
193 
194 static int sof_pcm_hw_free(struct snd_soc_component *component,
195                            struct snd_pcm_substream *substream)
196 {
197         struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
198         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
199         struct snd_sof_pcm *spcm;
200         int ret;
201 
202         /* nothing to do for BE */
203         if (rtd->dai_link->no_pcm)
204                 return 0;
205 
206         spcm = snd_sof_find_spcm_dai(component, rtd);
207         if (!spcm)
208                 return -EINVAL;
209 
210         dev_dbg(component->dev, "pcm: free stream %d dir %d\n",
211                 spcm->pcm.pcm_id, substream->stream);
212 
213         ret = sof_pcm_stream_free(sdev, substream, spcm, substream->stream, true);
214 
215         cancel_work_sync(&spcm->stream[substream->stream].period_elapsed_work);
216 
217         return ret;
218 }
219 
220 static int sof_pcm_prepare(struct snd_soc_component *component,
221                            struct snd_pcm_substream *substream)
222 {
223         struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
224         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
225         struct snd_sof_pcm *spcm;
226         int ret;
227 
228         /* nothing to do for BE */
229         if (rtd->dai_link->no_pcm)
230                 return 0;
231 
232         spcm = snd_sof_find_spcm_dai(component, rtd);
233         if (!spcm)
234                 return -EINVAL;
235 
236         if (spcm->prepared[substream->stream]) {
237                 if (!spcm->pending_stop[substream->stream])
238                         return 0;
239 
240                 /*
241                  * this case should be reached in case of xruns where we absolutely
242                  * want to free-up and reset all PCM/DMA resources
243                  */
244                 ret = sof_pcm_stream_free(sdev, substream, spcm, substream->stream, true);
245                 if (ret < 0)
246                         return ret;
247         }
248 
249         dev_dbg(component->dev, "pcm: prepare stream %d dir %d\n",
250                 spcm->pcm.pcm_id, substream->stream);
251 
252         /* set hw_params */
253         ret = sof_pcm_hw_params(component,
254                                 substream, &spcm->params[substream->stream]);
255         if (ret < 0) {
256                 dev_err(component->dev,
257                         "error: set pcm hw_params after resume\n");
258                 return ret;
259         }
260 
261         return 0;
262 }
263 
264 /*
265  * FE dai link trigger actions are always executed in non-atomic context because
266  * they involve IPC's.
267  */
268 static int sof_pcm_trigger(struct snd_soc_component *component,
269                            struct snd_pcm_substream *substream, int cmd)
270 {
271         struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
272         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
273         const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm);
274         struct snd_sof_pcm *spcm;
275         bool reset_hw_params = false;
276         bool ipc_first = false;
277         int ret = 0;
278 
279         /* nothing to do for BE */
280         if (rtd->dai_link->no_pcm)
281                 return 0;
282 
283         spcm = snd_sof_find_spcm_dai(component, rtd);
284         if (!spcm)
285                 return -EINVAL;
286 
287         dev_dbg(component->dev, "pcm: trigger stream %d dir %d cmd %d\n",
288                 spcm->pcm.pcm_id, substream->stream, cmd);
289 
290         spcm->pending_stop[substream->stream] = false;
291 
292         switch (cmd) {
293         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
294                 ipc_first = true;
295                 break;
296         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
297                 if (pcm_ops && pcm_ops->ipc_first_on_start)
298                         ipc_first = true;
299                 break;
300         case SNDRV_PCM_TRIGGER_START:
301                 if (spcm->stream[substream->stream].suspend_ignored) {
302                         /*
303                          * This case will be triggered when INFO_RESUME is
304                          * not supported, no need to re-start streams that
305                          * remained enabled in D0ix.
306                          */
307                         spcm->stream[substream->stream].suspend_ignored = false;
308                         return 0;
309                 }
310 
311                 if (pcm_ops && pcm_ops->ipc_first_on_start)
312                         ipc_first = true;
313                 break;
314         case SNDRV_PCM_TRIGGER_SUSPEND:
315                 /*
316                  * If DSP D0I3 is allowed during S0iX, set the suspend_ignored flag for
317                  * D0I3-compatible streams to keep the firmware pipeline running
318                  */
319                 if (pcm_ops && pcm_ops->d0i3_supported_in_s0ix &&
320                     sdev->system_suspend_target == SOF_SUSPEND_S0IX &&
321                     spcm->stream[substream->stream].d0i3_compatible) {
322                         spcm->stream[substream->stream].suspend_ignored = true;
323                         return 0;
324                 }
325 
326                 /* On suspend the DMA must be stopped in DSPless mode */
327                 if (sdev->dspless_mode_selected)
328                         reset_hw_params = true;
329 
330                 fallthrough;
331         case SNDRV_PCM_TRIGGER_STOP:
332                 ipc_first = true;
333                 if (pcm_ops && pcm_ops->reset_hw_params_during_stop)
334                         reset_hw_params = true;
335                 break;
336         default:
337                 dev_err(component->dev, "Unhandled trigger cmd %d\n", cmd);
338                 return -EINVAL;
339         }
340 
341         if (!ipc_first)
342                 snd_sof_pcm_platform_trigger(sdev, substream, cmd);
343 
344         if (pcm_ops && pcm_ops->trigger)
345                 ret = pcm_ops->trigger(component, substream, cmd);
346 
347         switch (cmd) {
348         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
349         case SNDRV_PCM_TRIGGER_START:
350                 /* invoke platform trigger to start DMA only if pcm_ops is successful */
351                 if (ipc_first && !ret)
352                         snd_sof_pcm_platform_trigger(sdev, substream, cmd);
353                 break;
354         case SNDRV_PCM_TRIGGER_SUSPEND:
355         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
356         case SNDRV_PCM_TRIGGER_STOP:
357                 /* invoke platform trigger to stop DMA even if pcm_ops isn't set or if it failed */
358                 if (!pcm_ops || !pcm_ops->platform_stop_during_hw_free)
359                         snd_sof_pcm_platform_trigger(sdev, substream, cmd);
360 
361                 /*
362                  * set the pending_stop flag to indicate that pipeline stop has been delayed.
363                  * This will be used later to stop the pipelines during prepare when recovering
364                  * from xruns.
365                  */
366                 if (pcm_ops && pcm_ops->platform_stop_during_hw_free &&
367                     cmd == SNDRV_PCM_TRIGGER_STOP)
368                         spcm->pending_stop[substream->stream] = true;
369                 break;
370         default:
371                 break;
372         }
373 
374         /* free PCM if reset_hw_params is set and the STOP IPC is successful */
375         if (!ret && reset_hw_params)
376                 ret = sof_pcm_stream_free(sdev, substream, spcm, substream->stream, false);
377 
378         return ret;
379 }
380 
381 static snd_pcm_uframes_t sof_pcm_pointer(struct snd_soc_component *component,
382                                          struct snd_pcm_substream *substream)
383 {
384         struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
385         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
386         const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm);
387         struct snd_sof_pcm *spcm;
388         snd_pcm_uframes_t host, dai;
389         int ret = -EOPNOTSUPP;
390 
391         /* nothing to do for BE */
392         if (rtd->dai_link->no_pcm)
393                 return 0;
394 
395         if (pcm_ops && pcm_ops->pointer)
396                 ret = pcm_ops->pointer(component, substream, &host);
397 
398         if (ret != -EOPNOTSUPP)
399                 return ret ? ret : host;
400 
401         /* use dsp ops pointer callback directly if set */
402         if (sof_ops(sdev)->pcm_pointer)
403                 return sof_ops(sdev)->pcm_pointer(sdev, substream);
404 
405         spcm = snd_sof_find_spcm_dai(component, rtd);
406         if (!spcm)
407                 return -EINVAL;
408 
409         /* read position from DSP */
410         host = bytes_to_frames(substream->runtime,
411                                spcm->stream[substream->stream].posn.host_posn);
412         dai = bytes_to_frames(substream->runtime,
413                               spcm->stream[substream->stream].posn.dai_posn);
414 
415         trace_sof_pcm_pointer_position(sdev, spcm, substream, host, dai);
416 
417         return host;
418 }
419 
420 static int sof_pcm_open(struct snd_soc_component *component,
421                         struct snd_pcm_substream *substream)
422 {
423         struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
424         struct snd_pcm_runtime *runtime = substream->runtime;
425         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
426         const struct snd_sof_dsp_ops *ops = sof_ops(sdev);
427         struct snd_sof_pcm *spcm;
428         struct snd_soc_tplg_stream_caps *caps;
429         int ret;
430 
431         /* nothing to do for BE */
432         if (rtd->dai_link->no_pcm)
433                 return 0;
434 
435         spcm = snd_sof_find_spcm_dai(component, rtd);
436         if (!spcm)
437                 return -EINVAL;
438 
439         dev_dbg(component->dev, "pcm: open stream %d dir %d\n",
440                 spcm->pcm.pcm_id, substream->stream);
441 
442 
443         caps = &spcm->pcm.caps[substream->stream];
444 
445         /* set runtime config */
446         runtime->hw.info = ops->hw_info; /* platform-specific */
447 
448         /* set any runtime constraints based on topology */
449         runtime->hw.formats = le64_to_cpu(caps->formats);
450         runtime->hw.period_bytes_min = le32_to_cpu(caps->period_size_min);
451         runtime->hw.period_bytes_max = le32_to_cpu(caps->period_size_max);
452         runtime->hw.periods_min = le32_to_cpu(caps->periods_min);
453         runtime->hw.periods_max = le32_to_cpu(caps->periods_max);
454 
455         /*
456          * caps->buffer_size_min is not used since the
457          * snd_pcm_hardware structure only defines buffer_bytes_max
458          */
459         runtime->hw.buffer_bytes_max = le32_to_cpu(caps->buffer_size_max);
460 
461         dev_dbg(component->dev, "period min %zd max %zd bytes\n",
462                 runtime->hw.period_bytes_min,
463                 runtime->hw.period_bytes_max);
464         dev_dbg(component->dev, "period count %d max %d\n",
465                 runtime->hw.periods_min,
466                 runtime->hw.periods_max);
467         dev_dbg(component->dev, "buffer max %zd bytes\n",
468                 runtime->hw.buffer_bytes_max);
469 
470         /* set wait time - TODO: come from topology */
471         substream->wait_time = 500;
472 
473         spcm->stream[substream->stream].posn.host_posn = 0;
474         spcm->stream[substream->stream].posn.dai_posn = 0;
475         spcm->stream[substream->stream].substream = substream;
476         spcm->prepared[substream->stream] = false;
477 
478         ret = snd_sof_pcm_platform_open(sdev, substream);
479         if (ret < 0)
480                 dev_err(component->dev, "error: pcm open failed %d\n", ret);
481 
482         return ret;
483 }
484 
485 static int sof_pcm_close(struct snd_soc_component *component,
486                          struct snd_pcm_substream *substream)
487 {
488         struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
489         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
490         struct snd_sof_pcm *spcm;
491         int err;
492 
493         /* nothing to do for BE */
494         if (rtd->dai_link->no_pcm)
495                 return 0;
496 
497         spcm = snd_sof_find_spcm_dai(component, rtd);
498         if (!spcm)
499                 return -EINVAL;
500 
501         dev_dbg(component->dev, "pcm: close stream %d dir %d\n",
502                 spcm->pcm.pcm_id, substream->stream);
503 
504         err = snd_sof_pcm_platform_close(sdev, substream);
505         if (err < 0) {
506                 dev_err(component->dev, "error: pcm close failed %d\n",
507                         err);
508                 /*
509                  * keep going, no point in preventing the close
510                  * from happening
511                  */
512         }
513 
514         return 0;
515 }
516 
517 /*
518  * Pre-allocate playback/capture audio buffer pages.
519  * no need to explicitly release memory preallocated by sof_pcm_new in pcm_free
520  * snd_pcm_lib_preallocate_free_for_all() is called by the core.
521  */
522 static int sof_pcm_new(struct snd_soc_component *component,
523                        struct snd_soc_pcm_runtime *rtd)
524 {
525         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
526         struct snd_sof_pcm *spcm;
527         struct snd_pcm *pcm = rtd->pcm;
528         struct snd_soc_tplg_stream_caps *caps;
529         int stream = SNDRV_PCM_STREAM_PLAYBACK;
530 
531         /* find SOF PCM for this RTD */
532         spcm = snd_sof_find_spcm_dai(component, rtd);
533         if (!spcm) {
534                 dev_warn(component->dev, "warn: can't find PCM with DAI ID %d\n",
535                          rtd->dai_link->id);
536                 return 0;
537         }
538 
539         dev_dbg(component->dev, "creating new PCM %s\n", spcm->pcm.pcm_name);
540 
541         /* do we need to pre-allocate playback audio buffer pages */
542         if (!spcm->pcm.playback)
543                 goto capture;
544 
545         caps = &spcm->pcm.caps[stream];
546 
547         /* pre-allocate playback audio buffer pages */
548         dev_dbg(component->dev,
549                 "spcm: allocate %s playback DMA buffer size 0x%x max 0x%x\n",
550                 caps->name, caps->buffer_size_min, caps->buffer_size_max);
551 
552         if (!pcm->streams[stream].substream) {
553                 dev_err(component->dev, "error: NULL playback substream!\n");
554                 return -EINVAL;
555         }
556 
557         snd_pcm_set_managed_buffer(pcm->streams[stream].substream,
558                                    SNDRV_DMA_TYPE_DEV_SG, sdev->dev,
559                                    0, le32_to_cpu(caps->buffer_size_max));
560 capture:
561         stream = SNDRV_PCM_STREAM_CAPTURE;
562 
563         /* do we need to pre-allocate capture audio buffer pages */
564         if (!spcm->pcm.capture)
565                 return 0;
566 
567         caps = &spcm->pcm.caps[stream];
568 
569         /* pre-allocate capture audio buffer pages */
570         dev_dbg(component->dev,
571                 "spcm: allocate %s capture DMA buffer size 0x%x max 0x%x\n",
572                 caps->name, caps->buffer_size_min, caps->buffer_size_max);
573 
574         if (!pcm->streams[stream].substream) {
575                 dev_err(component->dev, "error: NULL capture substream!\n");
576                 return -EINVAL;
577         }
578 
579         snd_pcm_set_managed_buffer(pcm->streams[stream].substream,
580                                    SNDRV_DMA_TYPE_DEV_SG, sdev->dev,
581                                    0, le32_to_cpu(caps->buffer_size_max));
582 
583         return 0;
584 }
585 
586 /* fixup the BE DAI link to match any values from topology */
587 int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params)
588 {
589         struct snd_interval *rate = hw_param_interval(params,
590                         SNDRV_PCM_HW_PARAM_RATE);
591         struct snd_interval *channels = hw_param_interval(params,
592                                                 SNDRV_PCM_HW_PARAM_CHANNELS);
593         struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
594         struct snd_soc_component *component =
595                 snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME);
596         struct snd_sof_dai *dai =
597                 snd_sof_find_dai(component, (char *)rtd->dai_link->name);
598         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
599         const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm);
600 
601         /* no topology exists for this BE, try a common configuration */
602         if (!dai) {
603                 dev_warn(component->dev,
604                          "warning: no topology found for BE DAI %s config\n",
605                          rtd->dai_link->name);
606 
607                 /*  set 48k, stereo, 16bits by default */
608                 rate->min = 48000;
609                 rate->max = 48000;
610 
611                 channels->min = 2;
612                 channels->max = 2;
613 
614                 snd_mask_none(fmt);
615                 snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
616 
617                 return 0;
618         }
619 
620         if (pcm_ops && pcm_ops->dai_link_fixup)
621                 return pcm_ops->dai_link_fixup(rtd, params);
622 
623         return 0;
624 }
625 EXPORT_SYMBOL(sof_pcm_dai_link_fixup);
626 
627 static int sof_pcm_probe(struct snd_soc_component *component)
628 {
629         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
630         struct snd_sof_pdata *plat_data = sdev->pdata;
631         const char *tplg_filename;
632         int ret;
633 
634         /*
635          * make sure the device is pm_runtime_active before loading the
636          * topology and initiating IPC or bus transactions
637          */
638         ret = pm_runtime_resume_and_get(component->dev);
639         if (ret < 0 && ret != -EACCES)
640                 return ret;
641 
642         /* load the default topology */
643         sdev->component = component;
644 
645         tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
646                                        "%s/%s",
647                                        plat_data->tplg_filename_prefix,
648                                        plat_data->tplg_filename);
649         if (!tplg_filename) {
650                 ret = -ENOMEM;
651                 goto pm_error;
652         }
653 
654         ret = snd_sof_load_topology(component, tplg_filename);
655         if (ret < 0)
656                 dev_err(component->dev, "error: failed to load DSP topology %d\n",
657                         ret);
658 
659 pm_error:
660         pm_runtime_mark_last_busy(component->dev);
661         pm_runtime_put_autosuspend(component->dev);
662 
663         return ret;
664 }
665 
666 static void sof_pcm_remove(struct snd_soc_component *component)
667 {
668         /* remove topology */
669         snd_soc_tplg_component_remove(component);
670 }
671 
672 static int sof_pcm_ack(struct snd_soc_component *component,
673                        struct snd_pcm_substream *substream)
674 {
675         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
676 
677         return snd_sof_pcm_platform_ack(sdev, substream);
678 }
679 
680 static snd_pcm_sframes_t sof_pcm_delay(struct snd_soc_component *component,
681                                        struct snd_pcm_substream *substream)
682 {
683         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
684         const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm);
685 
686         if (pcm_ops && pcm_ops->delay)
687                 return pcm_ops->delay(component, substream);
688 
689         return 0;
690 }
691 
692 void snd_sof_new_platform_drv(struct snd_sof_dev *sdev)
693 {
694         struct snd_soc_component_driver *pd = &sdev->plat_drv;
695         struct snd_sof_pdata *plat_data = sdev->pdata;
696         const char *drv_name;
697 
698         if (plat_data->machine)
699                 drv_name = plat_data->machine->drv_name;
700         else if (plat_data->of_machine)
701                 drv_name = plat_data->of_machine->drv_name;
702         else
703                 drv_name = NULL;
704 
705         pd->name = "sof-audio-component";
706         pd->probe = sof_pcm_probe;
707         pd->remove = sof_pcm_remove;
708         pd->open = sof_pcm_open;
709         pd->close = sof_pcm_close;
710         pd->hw_params = sof_pcm_hw_params;
711         pd->prepare = sof_pcm_prepare;
712         pd->hw_free = sof_pcm_hw_free;
713         pd->trigger = sof_pcm_trigger;
714         pd->pointer = sof_pcm_pointer;
715         pd->ack = sof_pcm_ack;
716         pd->delay = sof_pcm_delay;
717 
718 #if IS_ENABLED(CONFIG_SND_SOC_SOF_COMPRESS)
719         pd->compress_ops = &sof_compressed_ops;
720 #endif
721 
722         pd->pcm_construct = sof_pcm_new;
723         pd->ignore_machine = drv_name;
724         pd->be_pcm_base = SOF_BE_PCM_BASE;
725         pd->use_dai_pcm_id = true;
726         pd->topology_name_prefix = "sof";
727 
728          /* increment module refcount when a pcm is opened */
729         pd->module_get_upon_open = 1;
730 
731         pd->legacy_dai_naming = 1;
732 
733         /*
734          * The fixup is only needed when the DSP is in use as with the DSPless
735          * mode we are directly using the audio interface
736          */
737         if (!sdev->dspless_mode_selected)
738                 pd->be_hw_params_fixup = sof_pcm_dai_link_fixup;
739 }
740 

~ [ 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