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"
24 * sof pcm period elapse work
32 snd_pcm_period_elapsed(sps->substream); in snd_sof_pcm_period_elapsed_work()
41 * sof pcm period elapse, this could be called at irq thread context.
52 dev_err(component->dev, in snd_sof_pcm_period_elapsed()
60 * when the PCM is done draining or xrun happened, a STOP IPC will in snd_sof_pcm_period_elapsed()
65 schedule_work(&spcm->stream[substream->stream].period_elapsed_work); in snd_sof_pcm_period_elapsed()
85 dai->name, snd_pcm_direction_name(dir)); in sof_pcm_setup_connected_widgets()
89 spcm->stream[dir].list = list; in sof_pcm_setup_connected_widgets()
94 spcm->stream[dir].list = NULL; in sof_pcm_setup_connected_widgets()
109 const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm); in sof_pcm_hw_params()
111 struct snd_pcm_runtime *runtime = substream->runtime; in sof_pcm_hw_params()
116 if (rtd->dai_link->no_pcm) in sof_pcm_hw_params()
121 return -EINVAL; in sof_pcm_hw_params()
123 spcm_dbg(spcm, substream->stream, "Entry: hw_params\n"); in sof_pcm_hw_params()
129 if (spcm->prepared[substream->stream] && pcm_ops && pcm_ops->hw_free) { in sof_pcm_hw_params()
130 ret = pcm_ops->hw_free(component, substream); in sof_pcm_hw_params()
134 spcm->prepared[substream->stream] = false; in sof_pcm_hw_params()
139 spcm_err(spcm, substream->stream, "platform hw params failed\n"); in sof_pcm_hw_params()
144 if (!spcm->stream[substream->stream].list) { in sof_pcm_hw_params()
146 substream->stream); in sof_pcm_hw_params()
152 if (runtime->buffer_changed) { in sof_pcm_hw_params()
155 ret = snd_sof_create_page_table(component->dev, dmab, in sof_pcm_hw_params()
156 spcm->stream[substream->stream].page_table.area, in sof_pcm_hw_params()
157 runtime->dma_bytes); in sof_pcm_hw_params()
162 if (pcm_ops && pcm_ops->hw_params) { in sof_pcm_hw_params()
163 ret = pcm_ops->hw_params(component, substream, params, &platform_params); in sof_pcm_hw_params()
168 spcm->prepared[substream->stream] = true; in sof_pcm_hw_params()
170 /* save pcm hw_params */ in sof_pcm_hw_params()
171 memcpy(&spcm->params[substream->stream], params, sizeof(*params)); in sof_pcm_hw_params()
181 const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm); in sof_pcm_stream_free()
185 if (spcm->prepared[substream->stream]) { in sof_pcm_stream_free()
187 if (pcm_ops && pcm_ops->platform_stop_during_hw_free) in sof_pcm_stream_free()
191 /* free PCM in the DSP */ in sof_pcm_stream_free()
192 if (pcm_ops && pcm_ops->hw_free) { in sof_pcm_stream_free()
193 ret = pcm_ops->hw_free(sdev->component, substream); in sof_pcm_stream_free()
195 spcm_err(spcm, substream->stream, in sof_pcm_stream_free()
196 "pcm_ops->hw_free failed %d\n", ret); in sof_pcm_stream_free()
201 spcm->prepared[substream->stream] = false; in sof_pcm_stream_free()
202 spcm->pending_stop[substream->stream] = false; in sof_pcm_stream_free()
208 spcm_err(spcm, substream->stream, in sof_pcm_stream_free()
209 "platform hw free failed %d\n", ret); in sof_pcm_stream_free()
218 spcm_err(spcm, substream->stream, in sof_pcm_stream_free()
234 list_for_each_entry(spcm, &sdev->pcm_list, list) { in sof_pcm_free_all_streams()
236 substream = spcm->stream[dir].substream; in sof_pcm_free_all_streams()
238 if (!substream || !substream->runtime || in sof_pcm_free_all_streams()
239 spcm->stream[dir].suspend_ignored) in sof_pcm_free_all_streams()
242 if (spcm->stream[dir].list) { in sof_pcm_free_all_streams()
263 if (rtd->dai_link->no_pcm) in sof_pcm_hw_free()
268 return -EINVAL; in sof_pcm_hw_free()
270 spcm_dbg(spcm, substream->stream, "Entry: hw_free\n"); in sof_pcm_hw_free()
272 ret = sof_pcm_stream_free(sdev, substream, spcm, substream->stream, true); in sof_pcm_hw_free()
274 cancel_work_sync(&spcm->stream[substream->stream].period_elapsed_work); in sof_pcm_hw_free()
288 if (rtd->dai_link->no_pcm) in sof_pcm_prepare()
293 return -EINVAL; in sof_pcm_prepare()
295 spcm_dbg(spcm, substream->stream, "Entry: prepare\n"); in sof_pcm_prepare()
297 if (spcm->prepared[substream->stream]) { in sof_pcm_prepare()
298 if (!spcm->pending_stop[substream->stream]) in sof_pcm_prepare()
303 * want to free-up and reset all PCM/DMA resources in sof_pcm_prepare()
305 ret = sof_pcm_stream_free(sdev, substream, spcm, substream->stream, true); in sof_pcm_prepare()
312 substream, &spcm->params[substream->stream]); in sof_pcm_prepare()
314 spcm_err(spcm, substream->stream, in sof_pcm_prepare()
323 * FE dai link trigger actions are always executed in non-atomic context because
331 const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm); in sof_pcm_trigger()
338 if (rtd->dai_link->no_pcm) in sof_pcm_trigger()
343 return -EINVAL; in sof_pcm_trigger()
345 spcm_dbg(spcm, substream->stream, "Entry: trigger (cmd: %d)\n", cmd); in sof_pcm_trigger()
347 spcm->pending_stop[substream->stream] = false; in sof_pcm_trigger()
354 if (pcm_ops && pcm_ops->ipc_first_on_start) in sof_pcm_trigger()
358 if (spcm->stream[substream->stream].suspend_ignored) { in sof_pcm_trigger()
361 * not supported, no need to re-start streams that in sof_pcm_trigger()
364 spcm->stream[substream->stream].suspend_ignored = false; in sof_pcm_trigger()
368 if (pcm_ops && pcm_ops->ipc_first_on_start) in sof_pcm_trigger()
374 * D0I3-compatible streams to keep the firmware pipeline running in sof_pcm_trigger()
376 if (pcm_ops && pcm_ops->d0i3_supported_in_s0ix && in sof_pcm_trigger()
377 sdev->system_suspend_target == SOF_SUSPEND_S0IX && in sof_pcm_trigger()
378 spcm->stream[substream->stream].d0i3_compatible) { in sof_pcm_trigger()
379 spcm->stream[substream->stream].suspend_ignored = true; in sof_pcm_trigger()
384 if (sdev->dspless_mode_selected) in sof_pcm_trigger()
390 if (pcm_ops && pcm_ops->reset_hw_params_during_stop) in sof_pcm_trigger()
394 spcm_err(spcm, substream->stream, "Unhandled trigger cmd %d\n", cmd); in sof_pcm_trigger()
395 return -EINVAL; in sof_pcm_trigger()
401 if (pcm_ops && pcm_ops->trigger) in sof_pcm_trigger()
402 ret = pcm_ops->trigger(component, substream, cmd); in sof_pcm_trigger()
407 /* invoke platform trigger to start DMA only if pcm_ops is successful */ in sof_pcm_trigger()
414 /* invoke platform trigger to stop DMA even if pcm_ops isn't set or if it failed */ in sof_pcm_trigger()
415 if (!pcm_ops || !pcm_ops->platform_stop_during_hw_free) in sof_pcm_trigger()
423 if (pcm_ops && pcm_ops->platform_stop_during_hw_free && in sof_pcm_trigger()
425 spcm->pending_stop[substream->stream] = true; in sof_pcm_trigger()
431 /* free PCM if reset_hw_params is set and the STOP IPC is successful */ in sof_pcm_trigger()
433 ret = sof_pcm_stream_free(sdev, substream, spcm, substream->stream, false); in sof_pcm_trigger()
443 const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm); in sof_pcm_pointer()
446 int ret = -EOPNOTSUPP; in sof_pcm_pointer()
449 if (rtd->dai_link->no_pcm) in sof_pcm_pointer()
452 if (pcm_ops && pcm_ops->pointer) in sof_pcm_pointer()
453 ret = pcm_ops->pointer(component, substream, &host); in sof_pcm_pointer()
455 if (ret != -EOPNOTSUPP) in sof_pcm_pointer()
459 if (sof_ops(sdev)->pcm_pointer) in sof_pcm_pointer()
460 return sof_ops(sdev)->pcm_pointer(sdev, substream); in sof_pcm_pointer()
464 return -EINVAL; in sof_pcm_pointer()
467 host = bytes_to_frames(substream->runtime, in sof_pcm_pointer()
468 spcm->stream[substream->stream].posn.host_posn); in sof_pcm_pointer()
469 dai = bytes_to_frames(substream->runtime, in sof_pcm_pointer()
470 spcm->stream[substream->stream].posn.dai_posn); in sof_pcm_pointer()
481 struct snd_pcm_runtime *runtime = substream->runtime; in sof_pcm_open()
489 if (rtd->dai_link->no_pcm) in sof_pcm_open()
494 return -EINVAL; in sof_pcm_open()
496 spcm_dbg(spcm, substream->stream, "Entry: open\n"); in sof_pcm_open()
498 caps = &spcm->pcm.caps[substream->stream]; in sof_pcm_open()
501 runtime->hw.info = ops->hw_info; /* platform-specific */ in sof_pcm_open()
504 runtime->hw.formats = le64_to_cpu(caps->formats); in sof_pcm_open()
505 runtime->hw.period_bytes_min = le32_to_cpu(caps->period_size_min); in sof_pcm_open()
506 runtime->hw.period_bytes_max = le32_to_cpu(caps->period_size_max); in sof_pcm_open()
507 runtime->hw.periods_min = le32_to_cpu(caps->periods_min); in sof_pcm_open()
508 runtime->hw.periods_max = le32_to_cpu(caps->periods_max); in sof_pcm_open()
511 * caps->buffer_size_min is not used since the in sof_pcm_open()
514 runtime->hw.buffer_bytes_max = le32_to_cpu(caps->buffer_size_max); in sof_pcm_open()
516 /* set wait time - TODO: come from topology */ in sof_pcm_open()
517 substream->wait_time = 500; in sof_pcm_open()
519 spcm->stream[substream->stream].posn.host_posn = 0; in sof_pcm_open()
520 spcm->stream[substream->stream].posn.dai_posn = 0; in sof_pcm_open()
521 spcm->stream[substream->stream].substream = substream; in sof_pcm_open()
522 spcm->prepared[substream->stream] = false; in sof_pcm_open()
526 spcm_err(spcm, substream->stream, in sof_pcm_open()
527 "platform pcm open failed %d\n", ret); in sof_pcm_open()
531 spcm_dbg(spcm, substream->stream, "period bytes min %zd, max %zd\n", in sof_pcm_open()
532 runtime->hw.period_bytes_min, runtime->hw.period_bytes_max); in sof_pcm_open()
533 spcm_dbg(spcm, substream->stream, "period count min %d, max %d\n", in sof_pcm_open()
534 runtime->hw.periods_min, runtime->hw.periods_max); in sof_pcm_open()
535 spcm_dbg(spcm, substream->stream, "buffer bytes max %zd\n", runtime->hw.buffer_bytes_max); in sof_pcm_open()
549 if (rtd->dai_link->no_pcm) in sof_pcm_close()
554 return -EINVAL; in sof_pcm_close()
556 spcm_dbg(spcm, substream->stream, "Entry: close\n"); in sof_pcm_close()
560 spcm_err(spcm, substream->stream, in sof_pcm_close()
561 "platform pcm close failed %d\n", err); in sof_pcm_close()
568 spcm->stream[substream->stream].substream = NULL; in sof_pcm_close()
574 * Pre-allocate playback/capture audio buffer pages.
583 struct snd_pcm *pcm = rtd->pcm; in sof_pcm_new() local
587 /* find SOF PCM for this RTD */ in sof_pcm_new()
590 dev_warn(component->dev, "warn: can't find PCM with DAI ID %d\n", in sof_pcm_new()
591 rtd->dai_link->id); in sof_pcm_new()
595 dev_dbg(spcm->scomp->dev, "pcm%u (%s): Entry: pcm_construct\n", in sof_pcm_new()
596 spcm->pcm.pcm_id, spcm->pcm.pcm_name); in sof_pcm_new()
598 /* do we need to pre-allocate playback audio buffer pages */ in sof_pcm_new()
599 if (!spcm->pcm.playback) in sof_pcm_new()
602 caps = &spcm->pcm.caps[stream]; in sof_pcm_new()
604 if (!pcm->streams[stream].substream) { in sof_pcm_new()
606 return -EINVAL; in sof_pcm_new()
609 /* pre-allocate playback audio buffer pages */ in sof_pcm_new()
611 caps->name, caps->buffer_size_min, caps->buffer_size_max); in sof_pcm_new()
613 snd_pcm_set_managed_buffer(pcm->streams[stream].substream, in sof_pcm_new()
614 SNDRV_DMA_TYPE_DEV_SG, sdev->dev, in sof_pcm_new()
615 0, le32_to_cpu(caps->buffer_size_max)); in sof_pcm_new()
619 /* do we need to pre-allocate capture audio buffer pages */ in sof_pcm_new()
620 if (!spcm->pcm.capture) in sof_pcm_new()
623 caps = &spcm->pcm.caps[stream]; in sof_pcm_new()
625 if (!pcm->streams[stream].substream) { in sof_pcm_new()
627 return -EINVAL; in sof_pcm_new()
630 /* pre-allocate capture audio buffer pages */ in sof_pcm_new()
632 caps->name, caps->buffer_size_min, caps->buffer_size_max); in sof_pcm_new()
634 snd_pcm_set_managed_buffer(pcm->streams[stream].substream, in sof_pcm_new()
635 SNDRV_DMA_TYPE_DEV_SG, sdev->dev, in sof_pcm_new()
636 0, le32_to_cpu(caps->buffer_size_max)); in sof_pcm_new()
652 snd_sof_find_dai(component, (char *)rtd->dai_link->name); in sof_pcm_dai_link_fixup()
654 const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm); in sof_pcm_dai_link_fixup()
658 dev_warn(component->dev, in sof_pcm_dai_link_fixup()
660 rtd->dai_link->name); in sof_pcm_dai_link_fixup()
663 rate->min = 48000; in sof_pcm_dai_link_fixup()
664 rate->max = 48000; in sof_pcm_dai_link_fixup()
666 channels->min = 2; in sof_pcm_dai_link_fixup()
667 channels->max = 2; in sof_pcm_dai_link_fixup()
675 if (pcm_ops && pcm_ops->dai_link_fixup) in sof_pcm_dai_link_fixup()
676 return pcm_ops->dai_link_fixup(rtd, params); in sof_pcm_dai_link_fixup()
685 struct snd_sof_pdata *plat_data = sdev->pdata; in sof_pcm_probe()
693 ret = pm_runtime_resume_and_get(component->dev); in sof_pcm_probe()
694 if (ret < 0 && ret != -EACCES) in sof_pcm_probe()
698 sdev->component = component; in sof_pcm_probe()
700 tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL, in sof_pcm_probe()
702 plat_data->tplg_filename_prefix, in sof_pcm_probe()
703 plat_data->tplg_filename); in sof_pcm_probe()
705 ret = -ENOMEM; in sof_pcm_probe()
711 dev_err(component->dev, "error: failed to load DSP topology %d\n", in sof_pcm_probe()
715 pm_runtime_put_autosuspend(component->dev); in sof_pcm_probe()
738 const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm); in sof_pcm_delay()
740 if (pcm_ops && pcm_ops->delay) in sof_pcm_delay()
741 return pcm_ops->delay(component, substream); in sof_pcm_delay()
748 struct snd_soc_component_driver *pd = &sdev->plat_drv; in snd_sof_new_platform_drv()
749 struct snd_sof_pdata *plat_data = sdev->pdata; in snd_sof_new_platform_drv()
752 if (plat_data->machine) in snd_sof_new_platform_drv()
753 drv_name = plat_data->machine->drv_name; in snd_sof_new_platform_drv()
754 else if (plat_data->of_machine) in snd_sof_new_platform_drv()
755 drv_name = plat_data->of_machine->drv_name; in snd_sof_new_platform_drv()
759 pd->name = "sof-audio-component"; in snd_sof_new_platform_drv()
760 pd->probe = sof_pcm_probe; in snd_sof_new_platform_drv()
761 pd->remove = sof_pcm_remove; in snd_sof_new_platform_drv()
762 pd->open = sof_pcm_open; in snd_sof_new_platform_drv()
763 pd->close = sof_pcm_close; in snd_sof_new_platform_drv()
764 pd->hw_params = sof_pcm_hw_params; in snd_sof_new_platform_drv()
765 pd->prepare = sof_pcm_prepare; in snd_sof_new_platform_drv()
766 pd->hw_free = sof_pcm_hw_free; in snd_sof_new_platform_drv()
767 pd->trigger = sof_pcm_trigger; in snd_sof_new_platform_drv()
768 pd->pointer = sof_pcm_pointer; in snd_sof_new_platform_drv()
769 pd->ack = sof_pcm_ack; in snd_sof_new_platform_drv()
770 pd->delay = sof_pcm_delay; in snd_sof_new_platform_drv()
773 pd->compress_ops = &sof_compressed_ops; in snd_sof_new_platform_drv()
776 pd->pcm_construct = sof_pcm_new; in snd_sof_new_platform_drv()
777 pd->ignore_machine = drv_name; in snd_sof_new_platform_drv()
778 pd->be_pcm_base = SOF_BE_PCM_BASE; in snd_sof_new_platform_drv()
779 pd->use_dai_pcm_id = true; in snd_sof_new_platform_drv()
780 pd->topology_name_prefix = "sof"; in snd_sof_new_platform_drv()
782 /* increment module refcount when a pcm is opened */ in snd_sof_new_platform_drv()
783 pd->module_get_upon_open = 1; in snd_sof_new_platform_drv()
785 pd->legacy_dai_naming = 1; in snd_sof_new_platform_drv()
791 if (!sdev->dspless_mode_selected) in snd_sof_new_platform_drv()
792 pd->be_hw_params_fixup = sof_pcm_dai_link_fixup; in snd_sof_new_platform_drv()