Lines Matching +full:pcm +full:- +full:platform
1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
10 // PCM Layer, interface between ALSA and IPC.
17 #include "sof-of-dev.h"
18 #include "sof-priv.h"
19 #include "sof-audio.h"
20 #include "sof-utils.h"
31 int stream = substream->stream; in create_page_table()
35 return -EINVAL; in create_page_table()
37 return snd_sof_create_page_table(component->dev, dmab, in create_page_table()
38 spcm->stream[stream].page_table.area, size); in create_page_table()
42 * sof pcm period elapse work
50 snd_pcm_period_elapsed(sps->substream); in snd_sof_pcm_period_elapsed_work()
59 * sof pcm period elapse, this could be called at irq thread context.
70 dev_err(component->dev, in snd_sof_pcm_period_elapsed()
78 * when the PCM is done draining or xrun happened, a STOP IPC will in snd_sof_pcm_period_elapsed()
83 schedule_work(&spcm->stream[substream->stream].period_elapsed_work); in snd_sof_pcm_period_elapsed()
102 dev_err(sdev->dev, "error: dai %s has no valid %s path\n", dai->name, in sof_pcm_setup_connected_widgets()
107 spcm->stream[dir].list = list; in sof_pcm_setup_connected_widgets()
111 dev_err(sdev->dev, "error: failed widget list set up for pcm %d dir %d\n", in sof_pcm_setup_connected_widgets()
112 spcm->pcm.pcm_id, dir); in sof_pcm_setup_connected_widgets()
113 spcm->stream[dir].list = NULL; in sof_pcm_setup_connected_widgets()
128 const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm); in sof_pcm_hw_params()
130 struct snd_pcm_runtime *runtime = substream->runtime; in sof_pcm_hw_params()
135 if (rtd->dai_link->no_pcm) in sof_pcm_hw_params()
140 return -EINVAL; in sof_pcm_hw_params()
146 if (pcm_ops && pcm_ops->hw_free && spcm->prepared[substream->stream]) { in sof_pcm_hw_params()
147 ret = pcm_ops->hw_free(component, substream); in sof_pcm_hw_params()
151 spcm->prepared[substream->stream] = false; in sof_pcm_hw_params()
154 dev_dbg(component->dev, "pcm: hw params stream %d dir %d\n", in sof_pcm_hw_params()
155 spcm->pcm.pcm_id, substream->stream); in sof_pcm_hw_params()
159 dev_err(component->dev, "platform hw params failed\n"); in sof_pcm_hw_params()
164 if (!spcm->stream[substream->stream].list) { in sof_pcm_hw_params()
166 substream->stream); in sof_pcm_hw_params()
172 if (runtime->buffer_changed) { in sof_pcm_hw_params()
173 ret = create_page_table(component, substream, runtime->dma_area, in sof_pcm_hw_params()
174 runtime->dma_bytes); in sof_pcm_hw_params()
180 if (pcm_ops && pcm_ops->hw_params) { in sof_pcm_hw_params()
181 ret = pcm_ops->hw_params(component, substream, params, &platform_params); in sof_pcm_hw_params()
186 spcm->prepared[substream->stream] = true; in sof_pcm_hw_params()
188 /* save pcm hw_params */ in sof_pcm_hw_params()
189 memcpy(&spcm->params[substream->stream], params, sizeof(*params)); in sof_pcm_hw_params()
203 if (rtd->dai_link->no_pcm) in sof_pcm_hw_free()
208 return -EINVAL; in sof_pcm_hw_free()
210 dev_dbg(component->dev, "pcm: free stream %d dir %d\n", in sof_pcm_hw_free()
211 spcm->pcm.pcm_id, substream->stream); in sof_pcm_hw_free()
213 ret = sof_pcm_stream_free(sdev, substream, spcm, substream->stream, true); in sof_pcm_hw_free()
215 cancel_work_sync(&spcm->stream[substream->stream].period_elapsed_work); in sof_pcm_hw_free()
229 if (rtd->dai_link->no_pcm) in sof_pcm_prepare()
234 return -EINVAL; in sof_pcm_prepare()
236 if (spcm->prepared[substream->stream]) { in sof_pcm_prepare()
237 if (!spcm->pending_stop[substream->stream]) in sof_pcm_prepare()
242 * want to free-up and reset all PCM/DMA resources in sof_pcm_prepare()
244 ret = sof_pcm_stream_free(sdev, substream, spcm, substream->stream, true); in sof_pcm_prepare()
249 dev_dbg(component->dev, "pcm: prepare stream %d dir %d\n", in sof_pcm_prepare()
250 spcm->pcm.pcm_id, substream->stream); in sof_pcm_prepare()
254 substream, &spcm->params[substream->stream]); in sof_pcm_prepare()
256 dev_err(component->dev, in sof_pcm_prepare()
257 "error: set pcm hw_params after resume\n"); in sof_pcm_prepare()
265 * FE dai link trigger actions are always executed in non-atomic context because
273 const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm); in sof_pcm_trigger()
280 if (rtd->dai_link->no_pcm) in sof_pcm_trigger()
285 return -EINVAL; in sof_pcm_trigger()
287 dev_dbg(component->dev, "pcm: trigger stream %d dir %d cmd %d\n", in sof_pcm_trigger()
288 spcm->pcm.pcm_id, substream->stream, cmd); in sof_pcm_trigger()
290 spcm->pending_stop[substream->stream] = false; in sof_pcm_trigger()
297 if (pcm_ops && pcm_ops->ipc_first_on_start) in sof_pcm_trigger()
301 if (spcm->stream[substream->stream].suspend_ignored) { in sof_pcm_trigger()
304 * not supported, no need to re-start streams that in sof_pcm_trigger()
307 spcm->stream[substream->stream].suspend_ignored = false; in sof_pcm_trigger()
311 if (pcm_ops && pcm_ops->ipc_first_on_start) in sof_pcm_trigger()
317 * D0I3-compatible streams to keep the firmware pipeline running in sof_pcm_trigger()
319 if (pcm_ops && pcm_ops->d0i3_supported_in_s0ix && in sof_pcm_trigger()
320 sdev->system_suspend_target == SOF_SUSPEND_S0IX && in sof_pcm_trigger()
321 spcm->stream[substream->stream].d0i3_compatible) { in sof_pcm_trigger()
322 spcm->stream[substream->stream].suspend_ignored = true; in sof_pcm_trigger()
327 if (sdev->dspless_mode_selected) in sof_pcm_trigger()
333 if (pcm_ops && pcm_ops->reset_hw_params_during_stop) in sof_pcm_trigger()
337 dev_err(component->dev, "Unhandled trigger cmd %d\n", cmd); in sof_pcm_trigger()
338 return -EINVAL; in sof_pcm_trigger()
344 if (pcm_ops && pcm_ops->trigger) in sof_pcm_trigger()
345 ret = pcm_ops->trigger(component, substream, cmd); in sof_pcm_trigger()
350 /* invoke platform trigger to start DMA only if pcm_ops is successful */ in sof_pcm_trigger()
357 /* invoke platform trigger to stop DMA even if pcm_ops isn't set or if it failed */ in sof_pcm_trigger()
358 if (!pcm_ops || !pcm_ops->platform_stop_during_hw_free) in sof_pcm_trigger()
366 if (pcm_ops && pcm_ops->platform_stop_during_hw_free && in sof_pcm_trigger()
368 spcm->pending_stop[substream->stream] = true; in sof_pcm_trigger()
374 /* free PCM if reset_hw_params is set and the STOP IPC is successful */ in sof_pcm_trigger()
376 ret = sof_pcm_stream_free(sdev, substream, spcm, substream->stream, false); in sof_pcm_trigger()
386 const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm); in sof_pcm_pointer()
389 int ret = -EOPNOTSUPP; in sof_pcm_pointer()
392 if (rtd->dai_link->no_pcm) in sof_pcm_pointer()
395 if (pcm_ops && pcm_ops->pointer) in sof_pcm_pointer()
396 ret = pcm_ops->pointer(component, substream, &host); in sof_pcm_pointer()
398 if (ret != -EOPNOTSUPP) in sof_pcm_pointer()
402 if (sof_ops(sdev)->pcm_pointer) in sof_pcm_pointer()
403 return sof_ops(sdev)->pcm_pointer(sdev, substream); in sof_pcm_pointer()
407 return -EINVAL; in sof_pcm_pointer()
410 host = bytes_to_frames(substream->runtime, in sof_pcm_pointer()
411 spcm->stream[substream->stream].posn.host_posn); in sof_pcm_pointer()
412 dai = bytes_to_frames(substream->runtime, in sof_pcm_pointer()
413 spcm->stream[substream->stream].posn.dai_posn); in sof_pcm_pointer()
424 struct snd_pcm_runtime *runtime = substream->runtime; in sof_pcm_open()
432 if (rtd->dai_link->no_pcm) in sof_pcm_open()
437 return -EINVAL; in sof_pcm_open()
439 dev_dbg(component->dev, "pcm: open stream %d dir %d\n", in sof_pcm_open()
440 spcm->pcm.pcm_id, substream->stream); in sof_pcm_open()
443 caps = &spcm->pcm.caps[substream->stream]; in sof_pcm_open()
446 runtime->hw.info = ops->hw_info; /* platform-specific */ in sof_pcm_open()
449 runtime->hw.formats = le64_to_cpu(caps->formats); in sof_pcm_open()
450 runtime->hw.period_bytes_min = le32_to_cpu(caps->period_size_min); in sof_pcm_open()
451 runtime->hw.period_bytes_max = le32_to_cpu(caps->period_size_max); in sof_pcm_open()
452 runtime->hw.periods_min = le32_to_cpu(caps->periods_min); in sof_pcm_open()
453 runtime->hw.periods_max = le32_to_cpu(caps->periods_max); in sof_pcm_open()
456 * caps->buffer_size_min is not used since the in sof_pcm_open()
459 runtime->hw.buffer_bytes_max = le32_to_cpu(caps->buffer_size_max); in sof_pcm_open()
461 dev_dbg(component->dev, "period min %zd max %zd bytes\n", in sof_pcm_open()
462 runtime->hw.period_bytes_min, in sof_pcm_open()
463 runtime->hw.period_bytes_max); in sof_pcm_open()
464 dev_dbg(component->dev, "period count %d max %d\n", in sof_pcm_open()
465 runtime->hw.periods_min, in sof_pcm_open()
466 runtime->hw.periods_max); in sof_pcm_open()
467 dev_dbg(component->dev, "buffer max %zd bytes\n", in sof_pcm_open()
468 runtime->hw.buffer_bytes_max); in sof_pcm_open()
470 /* set wait time - TODO: come from topology */ in sof_pcm_open()
471 substream->wait_time = 500; in sof_pcm_open()
473 spcm->stream[substream->stream].posn.host_posn = 0; in sof_pcm_open()
474 spcm->stream[substream->stream].posn.dai_posn = 0; in sof_pcm_open()
475 spcm->stream[substream->stream].substream = substream; in sof_pcm_open()
476 spcm->prepared[substream->stream] = false; in sof_pcm_open()
480 dev_err(component->dev, "error: pcm open failed %d\n", ret); in sof_pcm_open()
494 if (rtd->dai_link->no_pcm) in sof_pcm_close()
499 return -EINVAL; in sof_pcm_close()
501 dev_dbg(component->dev, "pcm: close stream %d dir %d\n", in sof_pcm_close()
502 spcm->pcm.pcm_id, substream->stream); in sof_pcm_close()
506 dev_err(component->dev, "error: pcm close failed %d\n", in sof_pcm_close()
514 spcm->stream[substream->stream].substream = NULL; in sof_pcm_close()
520 * Pre-allocate playback/capture audio buffer pages.
529 struct snd_pcm *pcm = rtd->pcm; in sof_pcm_new() local
533 /* find SOF PCM for this RTD */ in sof_pcm_new()
536 dev_warn(component->dev, "warn: can't find PCM with DAI ID %d\n", in sof_pcm_new()
537 rtd->dai_link->id); in sof_pcm_new()
541 dev_dbg(component->dev, "creating new PCM %s\n", spcm->pcm.pcm_name); in sof_pcm_new()
543 /* do we need to pre-allocate playback audio buffer pages */ in sof_pcm_new()
544 if (!spcm->pcm.playback) in sof_pcm_new()
547 caps = &spcm->pcm.caps[stream]; in sof_pcm_new()
549 /* pre-allocate playback audio buffer pages */ in sof_pcm_new()
550 dev_dbg(component->dev, in sof_pcm_new()
552 caps->name, caps->buffer_size_min, caps->buffer_size_max); in sof_pcm_new()
554 if (!pcm->streams[stream].substream) { in sof_pcm_new()
555 dev_err(component->dev, "error: NULL playback substream!\n"); in sof_pcm_new()
556 return -EINVAL; in sof_pcm_new()
559 snd_pcm_set_managed_buffer(pcm->streams[stream].substream, in sof_pcm_new()
560 SNDRV_DMA_TYPE_DEV_SG, sdev->dev, in sof_pcm_new()
561 0, le32_to_cpu(caps->buffer_size_max)); in sof_pcm_new()
565 /* do we need to pre-allocate capture audio buffer pages */ in sof_pcm_new()
566 if (!spcm->pcm.capture) in sof_pcm_new()
569 caps = &spcm->pcm.caps[stream]; in sof_pcm_new()
571 /* pre-allocate capture audio buffer pages */ in sof_pcm_new()
572 dev_dbg(component->dev, in sof_pcm_new()
574 caps->name, caps->buffer_size_min, caps->buffer_size_max); in sof_pcm_new()
576 if (!pcm->streams[stream].substream) { in sof_pcm_new()
577 dev_err(component->dev, "error: NULL capture substream!\n"); in sof_pcm_new()
578 return -EINVAL; in sof_pcm_new()
581 snd_pcm_set_managed_buffer(pcm->streams[stream].substream, in sof_pcm_new()
582 SNDRV_DMA_TYPE_DEV_SG, sdev->dev, in sof_pcm_new()
583 0, le32_to_cpu(caps->buffer_size_max)); in sof_pcm_new()
599 snd_sof_find_dai(component, (char *)rtd->dai_link->name); in sof_pcm_dai_link_fixup()
601 const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm); in sof_pcm_dai_link_fixup()
605 dev_warn(component->dev, in sof_pcm_dai_link_fixup()
607 rtd->dai_link->name); in sof_pcm_dai_link_fixup()
610 rate->min = 48000; in sof_pcm_dai_link_fixup()
611 rate->max = 48000; in sof_pcm_dai_link_fixup()
613 channels->min = 2; in sof_pcm_dai_link_fixup()
614 channels->max = 2; in sof_pcm_dai_link_fixup()
622 if (pcm_ops && pcm_ops->dai_link_fixup) in sof_pcm_dai_link_fixup()
623 return pcm_ops->dai_link_fixup(rtd, params); in sof_pcm_dai_link_fixup()
632 struct snd_sof_pdata *plat_data = sdev->pdata; in sof_pcm_probe()
640 ret = pm_runtime_resume_and_get(component->dev); in sof_pcm_probe()
641 if (ret < 0 && ret != -EACCES) in sof_pcm_probe()
645 sdev->component = component; in sof_pcm_probe()
647 tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL, in sof_pcm_probe()
649 plat_data->tplg_filename_prefix, in sof_pcm_probe()
650 plat_data->tplg_filename); in sof_pcm_probe()
652 ret = -ENOMEM; in sof_pcm_probe()
658 dev_err(component->dev, "error: failed to load DSP topology %d\n", in sof_pcm_probe()
662 pm_runtime_mark_last_busy(component->dev); in sof_pcm_probe()
663 pm_runtime_put_autosuspend(component->dev); in sof_pcm_probe()
686 const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm); in sof_pcm_delay()
688 if (pcm_ops && pcm_ops->delay) in sof_pcm_delay()
689 return pcm_ops->delay(component, substream); in sof_pcm_delay()
696 struct snd_soc_component_driver *pd = &sdev->plat_drv; in snd_sof_new_platform_drv()
697 struct snd_sof_pdata *plat_data = sdev->pdata; in snd_sof_new_platform_drv()
700 if (plat_data->machine) in snd_sof_new_platform_drv()
701 drv_name = plat_data->machine->drv_name; in snd_sof_new_platform_drv()
702 else if (plat_data->of_machine) in snd_sof_new_platform_drv()
703 drv_name = plat_data->of_machine->drv_name; in snd_sof_new_platform_drv()
707 pd->name = "sof-audio-component"; in snd_sof_new_platform_drv()
708 pd->probe = sof_pcm_probe; in snd_sof_new_platform_drv()
709 pd->remove = sof_pcm_remove; in snd_sof_new_platform_drv()
710 pd->open = sof_pcm_open; in snd_sof_new_platform_drv()
711 pd->close = sof_pcm_close; in snd_sof_new_platform_drv()
712 pd->hw_params = sof_pcm_hw_params; in snd_sof_new_platform_drv()
713 pd->prepare = sof_pcm_prepare; in snd_sof_new_platform_drv()
714 pd->hw_free = sof_pcm_hw_free; in snd_sof_new_platform_drv()
715 pd->trigger = sof_pcm_trigger; in snd_sof_new_platform_drv()
716 pd->pointer = sof_pcm_pointer; in snd_sof_new_platform_drv()
717 pd->ack = sof_pcm_ack; in snd_sof_new_platform_drv()
718 pd->delay = sof_pcm_delay; in snd_sof_new_platform_drv()
721 pd->compress_ops = &sof_compressed_ops; in snd_sof_new_platform_drv()
724 pd->pcm_construct = sof_pcm_new; in snd_sof_new_platform_drv()
725 pd->ignore_machine = drv_name; in snd_sof_new_platform_drv()
726 pd->be_pcm_base = SOF_BE_PCM_BASE; in snd_sof_new_platform_drv()
727 pd->use_dai_pcm_id = true; in snd_sof_new_platform_drv()
728 pd->topology_name_prefix = "sof"; in snd_sof_new_platform_drv()
730 /* increment module refcount when a pcm is opened */ in snd_sof_new_platform_drv()
731 pd->module_get_upon_open = 1; in snd_sof_new_platform_drv()
733 pd->legacy_dai_naming = 1; in snd_sof_new_platform_drv()
739 if (!sdev->dspless_mode_selected) in snd_sof_new_platform_drv()
740 pd->be_hw_params_fixup = sof_pcm_dai_link_fixup; in snd_sof_new_platform_drv()