Lines Matching +full:link +full:- +full:trigger +full:- +full:order +full:- +full:stop
1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
11 #include "sof-audio.h"
12 #include "sof-priv.h"
14 #include "ipc4-priv.h"
15 #include "ipc4-topology.h"
16 #include "ipc4-fw-reg.h"
19 * struct sof_ipc4_timestamp_info - IPC4 timestamp info
42 * struct sof_ipc4_pcm_stream_priv - IPC4 specific private data
53 * Modulus to use to compare host and link position counters. The sampling
57 * the wrap-around point of any hardware counter, and larger than any
67 struct sof_ipc4_pcm_stream_priv *stream_priv = sps->private; in sof_ipc4_sps_to_time_info()
69 return stream_priv->time_info; in sof_ipc4_sps_to_time_info()
78 for (i = 0; i < trigger_list->count; i++) { in sof_ipc4_set_multi_pipeline_state_debug()
79 offset += snprintf(buf + offset, size - offset, " %d", in sof_ipc4_set_multi_pipeline_state_debug()
80 trigger_list->pipeline_instance_ids[i]); in sof_ipc4_set_multi_pipeline_state_debug()
82 if (offset >= size - 1) { in sof_ipc4_set_multi_pipeline_state_debug()
83 buf[size - 1] = '\0'; in sof_ipc4_set_multi_pipeline_state_debug()
97 /* trigger a single pipeline */ in sof_ipc4_set_multi_pipeline_state()
98 if (trigger_list->count == 1) in sof_ipc4_set_multi_pipeline_state()
99 return sof_ipc4_set_pipeline_state(sdev, trigger_list->pipeline_instance_ids[0], in sof_ipc4_set_multi_pipeline_state()
102 dev_dbg(sdev->dev, "Set pipelines %s to state %d%s", in sof_ipc4_set_multi_pipeline_state()
113 /* trigger multiple pipelines with a single IPC */ in sof_ipc4_set_multi_pipeline_state()
117 ipc_size = sizeof(u32) * (trigger_list->count + 1); in sof_ipc4_set_multi_pipeline_state()
121 return sof_ipc_tx_message_no_reply(sdev->ipc, &msg, ipc_size); in sof_ipc4_set_multi_pipeline_state()
129 dev_dbg(sdev->dev, "Set pipeline %d to state %d%s", instance_id, state, in sof_ipc4_set_pipeline_state()
140 return sof_ipc_tx_message_no_reply(sdev->ipc, &msg, 0); in sof_ipc4_set_pipeline_state()
148 struct sof_ipc4_pipeline *pipeline = pipe_widget->private; in sof_ipc4_add_pipeline_by_priority()
151 for (i = 0; i < trigger_list->count; i++) { in sof_ipc4_add_pipeline_by_priority()
153 if (ascend && pipeline->priority < pipe_priority[i]) in sof_ipc4_add_pipeline_by_priority()
156 else if (!ascend && pipeline->priority > pipe_priority[i]) in sof_ipc4_add_pipeline_by_priority()
160 for (j = trigger_list->count - 1; j >= i; j--) { in sof_ipc4_add_pipeline_by_priority()
161 trigger_list->pipeline_instance_ids[j + 1] = trigger_list->pipeline_instance_ids[j]; in sof_ipc4_add_pipeline_by_priority()
165 trigger_list->pipeline_instance_ids[i] = pipe_widget->instance_id; in sof_ipc4_add_pipeline_by_priority()
166 trigger_list->count++; in sof_ipc4_add_pipeline_by_priority()
167 pipe_priority[i] = pipeline->priority; in sof_ipc4_add_pipeline_by_priority()
176 struct snd_sof_widget *pipe_widget = spipe->pipe_widget; in sof_ipc4_add_pipeline_to_trigger_list()
177 struct sof_ipc4_pipeline *pipeline = pipe_widget->private; in sof_ipc4_add_pipeline_to_trigger_list()
179 if (pipeline->skip_during_fe_trigger && state != SOF_IPC4_PIPE_RESET) in sof_ipc4_add_pipeline_to_trigger_list()
185 * Trigger pipeline if all PCMs containing it are paused or if it is RUNNING in sof_ipc4_add_pipeline_to_trigger_list()
188 if (spipe->started_count == spipe->paused_count) in sof_ipc4_add_pipeline_to_trigger_list()
194 if (!spipe->started_count && !spipe->paused_count) in sof_ipc4_add_pipeline_to_trigger_list()
200 if (spipe->paused_count == (spipe->started_count - 1)) in sof_ipc4_add_pipeline_to_trigger_list()
214 struct snd_sof_widget *pipe_widget = spipe->pipe_widget; in sof_ipc4_update_pipeline_state()
215 struct sof_ipc4_pipeline *pipeline = pipe_widget->private; in sof_ipc4_update_pipeline_state()
218 if (pipeline->skip_during_fe_trigger && state != SOF_IPC4_PIPE_RESET) in sof_ipc4_update_pipeline_state()
222 for (i = 0; i < trigger_list->count; i++) { in sof_ipc4_update_pipeline_state()
223 if (trigger_list->pipeline_instance_ids[i] == pipe_widget->instance_id) { in sof_ipc4_update_pipeline_state()
224 pipeline->state = state; in sof_ipc4_update_pipeline_state()
235 * the PAUSE trigger in sof_ipc4_update_pipeline_state()
237 spipe->paused_count++; in sof_ipc4_update_pipeline_state()
243 * STOP trigger in sof_ipc4_update_pipeline_state()
245 spipe->started_count--; in sof_ipc4_update_pipeline_state()
255 spipe->paused_count--; in sof_ipc4_update_pipeline_state()
260 spipe->started_count++; in sof_ipc4_update_pipeline_state()
274 * +---------------+
278 * +-------+-------+
284 * +----------------+ +------v-------+ +-------------+
286 * | RUNNING <-------------+ PAUSED +--------------> + RESET |
288 * +------+---------+ RELEASE +---------+----+ +-------------+
294 * +---------------------------------+
295 * STOP/SUSPEND
297 * Note that during system suspend, the suspend trigger is followed by a hw_free in
300 * prepare ioctl before the START trigger.
306 * buffer on DSP and directly from there to link DMA. However, the
308 * and another at link DAI. They both shall have the use_chain_dma
317 struct sof_ipc4_fw_data *ipc4_data = sdev->private; in sof_ipc4_chain_dma_trigger()
323 stream_priv = spcm->stream[direction].private; in sof_ipc4_chain_dma_trigger()
346 if (!stream_priv->chain_dma_allocated) in sof_ipc4_chain_dma_trigger()
355 return -EINVAL; in sof_ipc4_chain_dma_trigger()
363 * To set-up the DMA chain, the host DMA ID and SCS setting in sof_ipc4_chain_dma_trigger()
365 * the link DMA ID and fifo_size are retrieved from the link in sof_ipc4_chain_dma_trigger()
368 for (i = 0; i < pipeline_list->count; i++) { in sof_ipc4_chain_dma_trigger()
369 struct snd_sof_pipeline *spipe = pipeline_list->pipelines[i]; in sof_ipc4_chain_dma_trigger()
370 struct snd_sof_widget *pipe_widget = spipe->pipe_widget; in sof_ipc4_chain_dma_trigger()
371 struct sof_ipc4_pipeline *pipeline = pipe_widget->private; in sof_ipc4_chain_dma_trigger()
373 if (!pipeline->use_chain_dma) { in sof_ipc4_chain_dma_trigger()
376 return -EINVAL; in sof_ipc4_chain_dma_trigger()
379 msg.primary |= pipeline->msg.primary; in sof_ipc4_chain_dma_trigger()
383 msg.extension |= pipeline->msg.extension; in sof_ipc4_chain_dma_trigger()
389 * playback: 0 - (num_playback_streams - 1) in sof_ipc4_chain_dma_trigger()
390 * capture: num_playback_streams - (num_playback_streams + in sof_ipc4_chain_dma_trigger()
391 * num_capture_streams - 1) in sof_ipc4_chain_dma_trigger()
396 msg.primary += SOF_IPC4_GLB_CHAIN_DMA_HOST_ID(ipc4_data->num_playback_streams); in sof_ipc4_chain_dma_trigger()
397 msg.primary += SOF_IPC4_GLB_CHAIN_DMA_LINK_ID(ipc4_data->num_playback_streams); in sof_ipc4_chain_dma_trigger()
406 ret = sof_ipc_tx_message_no_reply(sdev->ipc, &msg, 0); in sof_ipc4_chain_dma_trigger()
409 stream_priv->chain_dma_allocated = allocate; in sof_ipc4_chain_dma_trigger()
420 struct sof_ipc4_fw_data *ipc4_data = sdev->private; in sof_ipc4_trigger_pipelines()
432 return -EINVAL; in sof_ipc4_trigger_pipelines()
434 spcm_dbg(spcm, substream->stream, "cmd: %d, state: %d\n", cmd, state); in sof_ipc4_trigger_pipelines()
436 pipeline_list = &spcm->stream[substream->stream].pipeline_list; in sof_ipc4_trigger_pipelines()
438 /* nothing to trigger if the list is empty */ in sof_ipc4_trigger_pipelines()
439 if (!pipeline_list->pipelines || !pipeline_list->count) in sof_ipc4_trigger_pipelines()
442 spipe = pipeline_list->pipelines[0]; in sof_ipc4_trigger_pipelines()
443 pipe_widget = spipe->pipe_widget; in sof_ipc4_trigger_pipelines()
444 pipeline = pipe_widget->private; in sof_ipc4_trigger_pipelines()
448 * trigger function that handles the rest for the substream. in sof_ipc4_trigger_pipelines()
450 if (pipeline->use_chain_dma) { in sof_ipc4_trigger_pipelines()
453 time_info = sof_ipc4_sps_to_time_info(&spcm->stream[substream->stream]); in sof_ipc4_trigger_pipelines()
455 ret = sof_ipc4_chain_dma_trigger(sdev, spcm, substream->stream, in sof_ipc4_trigger_pipelines()
469 time_info->stream_end_offset += pos; in sof_ipc4_trigger_pipelines()
472 time_info->stream_end_offset = 0; in sof_ipc4_trigger_pipelines()
480 pipeline_list->count), GFP_KERNEL); in sof_ipc4_trigger_pipelines()
482 return -ENOMEM; in sof_ipc4_trigger_pipelines()
484 pipe_priority = kzalloc(pipeline_list->count, GFP_KERNEL); in sof_ipc4_trigger_pipelines()
487 return -ENOMEM; in sof_ipc4_trigger_pipelines()
490 mutex_lock(&ipc4_data->pipeline_state_mutex); in sof_ipc4_trigger_pipelines()
493 * IPC4 requires pipelines to be triggered in order starting at the sink and in sof_ipc4_trigger_pipelines()
494 * walking all the way to the source. So traverse the pipeline_list in the order in sof_ipc4_trigger_pipelines()
495 * sink->source when starting PCM's and in the reverse order to pause/stop PCM's. in sof_ipc4_trigger_pipelines()
497 * in the pipeline, the order of triggering between the left/right paths will be in sof_ipc4_trigger_pipelines()
498 * indeterministic. But the sink->source trigger order sink->source would still be in sof_ipc4_trigger_pipelines()
502 for (i = pipeline_list->count - 1; i >= 0; i--) { in sof_ipc4_trigger_pipelines()
503 spipe = pipeline_list->pipelines[i]; in sof_ipc4_trigger_pipelines()
508 for (i = 0; i < pipeline_list->count; i++) { in sof_ipc4_trigger_pipelines()
509 spipe = pipeline_list->pipelines[i]; in sof_ipc4_trigger_pipelines()
515 if (!trigger_list->count) { in sof_ipc4_trigger_pipelines()
530 spcm_err(spcm, substream->stream, "failed to pause all pipelines\n"); in sof_ipc4_trigger_pipelines()
535 for (i = 0; i < pipeline_list->count ; i++) { in sof_ipc4_trigger_pipelines()
536 spipe = pipeline_list->pipelines[i]; in sof_ipc4_trigger_pipelines()
549 time_info = sof_ipc4_sps_to_time_info(&spcm->stream[substream->stream]); in sof_ipc4_trigger_pipelines()
551 time_info->stream_start_offset = SOF_IPC4_INVALID_STREAM_POSITION; in sof_ipc4_trigger_pipelines()
559 spcm_err(spcm, substream->stream, in sof_ipc4_trigger_pipelines()
570 if (sdev->fw_state != SOF_FW_CRASHED || state != SOF_IPC4_PIPE_RESET) in sof_ipc4_trigger_pipelines()
577 for (i = 0; i < pipeline_list->count; i++) { in sof_ipc4_trigger_pipelines()
578 spipe = pipeline_list->pipelines[i]; in sof_ipc4_trigger_pipelines()
583 mutex_unlock(&ipc4_data->pipeline_state_mutex); in sof_ipc4_trigger_pipelines()
607 dev_err(component->dev, "%s: unhandled trigger cmd %d\n", __func__, cmd); in sof_ipc4_pcm_trigger()
608 return -EINVAL; in sof_ipc4_pcm_trigger()
629 int current_config = -1; in ipc4_ssp_dai_config_pcm_params_match()
633 list_for_each_entry(slink, &sdev->dai_link_list, list) { in ipc4_ssp_dai_config_pcm_params_match()
634 if (!strcmp(slink->link->name, link_name)) { in ipc4_ssp_dai_config_pcm_params_match()
650 for (i = 0; i < slink->num_hw_configs; i++) { in ipc4_ssp_dai_config_pcm_params_match()
651 struct snd_soc_tplg_hw_config *hw_config = &slink->hw_configs[i]; in ipc4_ssp_dai_config_pcm_params_match()
653 if (params_rate(params) == le32_to_cpu(hw_config->fsync_rate) && in ipc4_ssp_dai_config_pcm_params_match()
654 params_width(params) == le32_to_cpu(hw_config->tdm_slot_width) && in ipc4_ssp_dai_config_pcm_params_match()
655 params_channels(params) <= le32_to_cpu(hw_config->tdm_slots)) { in ipc4_ssp_dai_config_pcm_params_match()
656 current_config = le32_to_cpu(hw_config->id); in ipc4_ssp_dai_config_pcm_params_match()
661 params_rate(params) == le32_to_cpu(hw_config->fsync_rate) && in ipc4_ssp_dai_config_pcm_params_match()
662 params_channels(params) <= le32_to_cpu(hw_config->tdm_slots)) { in ipc4_ssp_dai_config_pcm_params_match()
663 current_config = le32_to_cpu(hw_config->id); in ipc4_ssp_dai_config_pcm_params_match()
670 dev_err(sdev->dev, in ipc4_ssp_dai_config_pcm_params_match()
672 __func__, slink->link->name, slink->num_hw_configs); in ipc4_ssp_dai_config_pcm_params_match()
673 return -EINVAL; in ipc4_ssp_dai_config_pcm_params_match()
676 dev_dbg(sdev->dev, in ipc4_ssp_dai_config_pcm_params_match()
678 slink->link->name, current_config, slink->num_hw_configs, in ipc4_ssp_dai_config_pcm_params_match()
680 list_for_each_entry(dai, &sdev->dai_list, list) in ipc4_ssp_dai_config_pcm_params_match()
681 if (!strcmp(slink->link->name, dai->name)) in ipc4_ssp_dai_config_pcm_params_match()
682 dai->current_config = current_config; in ipc4_ssp_dai_config_pcm_params_match()
688 * Fixup DAI link parameters for sampling rate based on
695 struct sof_ipc4_pin_format *pin_fmts = ipc4_copier->available_fmt.input_pin_fmts; in sof_ipc4_pcm_dai_link_fixup_rate()
697 int num_input_formats = ipc4_copier->available_fmt.num_input_formats; in sof_ipc4_pcm_dai_link_fixup_rate()
705 return -EINVAL; in sof_ipc4_pcm_dai_link_fixup_rate()
732 dev_err(sdev->dev, "Unable to select sampling rate for DAI link\n"); in sof_ipc4_pcm_dai_link_fixup_rate()
733 return -EINVAL; in sof_ipc4_pcm_dai_link_fixup_rate()
736 rate->min = be_rate; in sof_ipc4_pcm_dai_link_fixup_rate()
737 rate->max = rate->min; in sof_ipc4_pcm_dai_link_fixup_rate()
747 struct sof_ipc4_pin_format *pin_fmts = ipc4_copier->available_fmt.input_pin_fmts; in sof_ipc4_pcm_dai_link_fixup_channels()
749 int num_input_formats = ipc4_copier->available_fmt.num_input_formats; in sof_ipc4_pcm_dai_link_fixup_channels()
757 return -EINVAL; in sof_ipc4_pcm_dai_link_fixup_channels()
784 dev_err(sdev->dev, "Unable to select channels for DAI link\n"); in sof_ipc4_pcm_dai_link_fixup_channels()
785 return -EINVAL; in sof_ipc4_pcm_dai_link_fixup_channels()
788 channels->min = be_channels; in sof_ipc4_pcm_dai_link_fixup_channels()
789 channels->max = be_channels; in sof_ipc4_pcm_dai_link_fixup_channels()
799 struct snd_sof_dai *dai = snd_sof_find_dai(component, rtd->dai_link->name); in sof_ipc4_pcm_dai_link_fixup()
810 dev_err(component->dev, "%s: No DAI found with name %s\n", __func__, in sof_ipc4_pcm_dai_link_fixup()
811 rtd->dai_link->name); in sof_ipc4_pcm_dai_link_fixup()
812 return -EINVAL; in sof_ipc4_pcm_dai_link_fixup()
815 ipc4_copier = dai->private; in sof_ipc4_pcm_dai_link_fixup()
817 dev_err(component->dev, "%s: No private data found for DAI %s\n", in sof_ipc4_pcm_dai_link_fixup()
818 __func__, rtd->dai_link->name); in sof_ipc4_pcm_dai_link_fixup()
819 return -EINVAL; in sof_ipc4_pcm_dai_link_fixup()
827 &ipc4_copier->available_fmt; in sof_ipc4_pcm_dai_link_fixup()
828 struct snd_sof_widget *swidget = w->dobj.private; in sof_ipc4_pcm_dai_link_fixup()
829 struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; in sof_ipc4_pcm_dai_link_fixup()
830 struct sof_ipc4_pipeline *pipeline = pipe_widget->private; in sof_ipc4_pcm_dai_link_fixup()
833 if (pipeline->use_chain_dma) in sof_ipc4_pcm_dai_link_fixup()
838 available_fmt->output_pin_fmts, in sof_ipc4_pcm_dai_link_fixup()
839 available_fmt->num_output_formats)) { in sof_ipc4_pcm_dai_link_fixup()
840 ipc4_fmt = &available_fmt->output_pin_fmts->audio_fmt; in sof_ipc4_pcm_dai_link_fixup()
845 available_fmt->input_pin_fmts, in sof_ipc4_pcm_dai_link_fixup()
846 available_fmt->num_input_formats)) { in sof_ipc4_pcm_dai_link_fixup()
847 ipc4_fmt = &available_fmt->input_pin_fmts->audio_fmt; in sof_ipc4_pcm_dai_link_fixup()
864 valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(ipc4_fmt->fmt_cfg); in sof_ipc4_pcm_dai_link_fixup()
865 dev_dbg(component->dev, "Set %s to %d bit format\n", dai->name, valid_bits); in sof_ipc4_pcm_dai_link_fixup()
883 if (ipc4_copier->dai_type == SOF_DAI_INTEL_SSP) in sof_ipc4_pcm_dai_link_fixup()
885 (char *)rtd->dai_link->name, in sof_ipc4_pcm_dai_link_fixup()
898 pipeline_list = &spcm->stream[stream].pipeline_list; in sof_ipc4_pcm_free()
899 kfree(pipeline_list->pipelines); in sof_ipc4_pcm_free()
900 pipeline_list->pipelines = NULL; in sof_ipc4_pcm_free()
902 stream_priv = spcm->stream[stream].private; in sof_ipc4_pcm_free()
903 kfree(stream_priv->time_info); in sof_ipc4_pcm_free()
904 kfree(spcm->stream[stream].private); in sof_ipc4_pcm_free()
905 spcm->stream[stream].private = NULL; in sof_ipc4_pcm_free()
912 struct sof_ipc4_fw_data *ipc4_data = sdev->private; in sof_ipc4_pcm_setup()
921 sof_mailbox_read(sdev, sdev->fw_info_box.offset + abi_offset, &abi_version, in sof_ipc4_pcm_setup()
928 if (!sof_ops(sdev) || !sof_ops(sdev)->get_host_byte_counter) in sof_ipc4_pcm_setup()
932 pipeline_list = &spcm->stream[stream].pipeline_list; in sof_ipc4_pcm_setup()
935 pipeline_list->pipelines = kcalloc(ipc4_data->max_num_pipelines, in sof_ipc4_pcm_setup()
936 sizeof(*pipeline_list->pipelines), in sof_ipc4_pcm_setup()
938 if (!pipeline_list->pipelines) { in sof_ipc4_pcm_setup()
940 return -ENOMEM; in sof_ipc4_pcm_setup()
946 return -ENOMEM; in sof_ipc4_pcm_setup()
949 spcm->stream[stream].private = stream_priv; in sof_ipc4_pcm_setup()
958 return -ENOMEM; in sof_ipc4_pcm_setup()
961 stream_priv->time_info = time_info; in sof_ipc4_pcm_setup()
978 for_each_dapm_widgets(sps->list, i, widget) { in sof_ipc4_build_time_info()
979 struct snd_sof_widget *swidget = widget->dobj.private; in sof_ipc4_build_time_info()
984 if (WIDGET_IS_AIF(swidget->widget->id)) { in sof_ipc4_build_time_info()
985 host_copier = swidget->private; in sof_ipc4_build_time_info()
986 } else if (WIDGET_IS_DAI(swidget->widget->id)) { in sof_ipc4_build_time_info()
987 dai = swidget->private; in sof_ipc4_build_time_info()
988 dai_copier = dai->private; in sof_ipc4_build_time_info()
994 dev_err(sdev->dev, "host or dai copier are not found\n"); in sof_ipc4_build_time_info()
999 time_info->host_copier = host_copier; in sof_ipc4_build_time_info()
1000 time_info->dai_copier = dai_copier; in sof_ipc4_build_time_info()
1001 time_info->llp_offset = offsetof(struct sof_ipc4_fw_registers, in sof_ipc4_build_time_info()
1002 llp_gpdma_reading_slots) + sdev->fw_info_box.offset; in sof_ipc4_build_time_info()
1006 sof_mailbox_read(sdev, time_info->llp_offset, &llp_slot, sizeof(llp_slot)); in sof_ipc4_build_time_info()
1007 if (llp_slot.node_id == dai_copier->data.gtw_cfg.node_id) in sof_ipc4_build_time_info()
1010 time_info->llp_offset += sizeof(llp_slot); in sof_ipc4_build_time_info()
1017 time_info->llp_offset = offsetof(struct sof_ipc4_fw_registers, in sof_ipc4_build_time_info()
1018 llp_sndw_reading_slots) + sdev->fw_info_box.offset; in sof_ipc4_build_time_info()
1020 sof_mailbox_read(sdev, time_info->llp_offset, &llp_slot, sizeof(llp_slot)); in sof_ipc4_build_time_info()
1021 if (llp_slot.node_id == dai_copier->data.gtw_cfg.node_id) in sof_ipc4_build_time_info()
1024 time_info->llp_offset += sizeof(llp_slot); in sof_ipc4_build_time_info()
1031 time_info->llp_offset = offsetof(struct sof_ipc4_fw_registers, in sof_ipc4_build_time_info()
1032 llp_evad_reading_slot) + sdev->fw_info_box.offset; in sof_ipc4_build_time_info()
1033 sof_mailbox_read(sdev, time_info->llp_offset, &llp_slot, sizeof(llp_slot)); in sof_ipc4_build_time_info()
1034 if (llp_slot.node_id != dai_copier->data.gtw_cfg.node_id) in sof_ipc4_build_time_info()
1035 time_info->llp_offset = 0; in sof_ipc4_build_time_info()
1050 return -EINVAL; in sof_ipc4_pcm_hw_params()
1052 time_info = sof_ipc4_sps_to_time_info(&spcm->stream[substream->stream]); in sof_ipc4_pcm_hw_params()
1057 time_info->stream_start_offset = SOF_IPC4_INVALID_STREAM_POSITION; in sof_ipc4_pcm_hw_params()
1058 time_info->llp_offset = 0; in sof_ipc4_pcm_hw_params()
1060 sof_ipc4_build_time_info(sdev, &spcm->stream[substream->stream]); in sof_ipc4_pcm_hw_params()
1069 if (!time_info->dai_copier || !time_info->host_copier) in sof_ipc4_frames_dai_to_host()
1076 dai_rate = time_info->dai_copier->data.out_format.sampling_frequency; in sof_ipc4_frames_dai_to_host()
1077 host_rate = time_info->host_copier->data.out_format.sampling_frequency; in sof_ipc4_frames_dai_to_host()
1099 struct sof_ipc4_copier *host_copier = time_info->host_copier; in sof_ipc4_get_stream_start_offset()
1100 struct sof_ipc4_copier *dai_copier = time_info->dai_copier; in sof_ipc4_get_stream_start_offset()
1107 return -EINVAL; in sof_ipc4_get_stream_start_offset()
1109 if (host_copier->data.gtw_cfg.node_id == SOF_IPC4_INVALID_NODE_ID) { in sof_ipc4_get_stream_start_offset()
1110 return -EINVAL; in sof_ipc4_get_stream_start_offset()
1111 } else if (host_copier->data.gtw_cfg.node_id == SOF_IPC4_CHAIN_DMA_NODE_ID) { in sof_ipc4_get_stream_start_offset()
1115 * be used on Host+Link pairs where the link position is in sof_ipc4_get_stream_start_offset()
1121 * The ChainDMA prefills the link DMA with a preamble in sof_ipc4_get_stream_start_offset()
1130 time_info->stream_start_offset = pre_ms * substream->runtime->rate / MSEC_PER_SEC; in sof_ipc4_get_stream_start_offset()
1134 node_index = SOF_IPC4_NODE_INDEX(host_copier->data.gtw_cfg.node_id); in sof_ipc4_get_stream_start_offset()
1136 sof_mailbox_read(sdev, sdev->fw_info_box.offset + offset, &ppl_reg, sizeof(ppl_reg)); in sof_ipc4_get_stream_start_offset()
1138 return -EINVAL; in sof_ipc4_get_stream_start_offset()
1140 ch = dai_copier->data.out_format.fmt_cfg; in sof_ipc4_get_stream_start_offset()
1142 dai_sample_size = (dai_copier->data.out_format.bit_depth >> 3) * ch; in sof_ipc4_get_stream_start_offset()
1145 time_info->stream_start_offset = ppl_reg.stream_start_offset; in sof_ipc4_get_stream_start_offset()
1146 do_div(time_info->stream_start_offset, dai_sample_size); in sof_ipc4_get_stream_start_offset()
1147 time_info->stream_end_offset = ppl_reg.stream_end_offset; in sof_ipc4_get_stream_start_offset()
1148 do_div(time_info->stream_end_offset, dai_sample_size); in sof_ipc4_get_stream_start_offset()
1151 time_info->stream_start_offset = in sof_ipc4_get_stream_start_offset()
1152 sof_ipc4_frames_dai_to_host(time_info, time_info->stream_start_offset); in sof_ipc4_get_stream_start_offset()
1153 time_info->stream_end_offset = in sof_ipc4_get_stream_start_offset()
1154 sof_ipc4_frames_dai_to_host(time_info, time_info->stream_end_offset); in sof_ipc4_get_stream_start_offset()
1158 time_info->delay = 0; in sof_ipc4_get_stream_start_offset()
1179 return -EOPNOTSUPP; in sof_ipc4_pcm_pointer()
1181 sps = &spcm->stream[substream->stream]; in sof_ipc4_pcm_pointer()
1184 return -EOPNOTSUPP; in sof_ipc4_pcm_pointer()
1191 if (time_info->stream_start_offset == SOF_IPC4_INVALID_STREAM_POSITION) { in sof_ipc4_pcm_pointer()
1194 return -EOPNOTSUPP; in sof_ipc4_pcm_pointer()
1204 host_cnt = div64_u64(host_cnt, frames_to_bytes(substream->runtime, 1)); in sof_ipc4_pcm_pointer()
1208 * then read the dai (link) counter via host accessible means if in sof_ipc4_pcm_pointer()
1211 if (!time_info->llp_offset) { in sof_ipc4_pcm_pointer()
1214 return -EOPNOTSUPP; in sof_ipc4_pcm_pointer()
1216 sof_mailbox_read(sdev, time_info->llp_offset, &llp, sizeof(llp)); in sof_ipc4_pcm_pointer()
1221 dai_cnt += time_info->stream_end_offset; in sof_ipc4_pcm_pointer()
1240 * increasing the host counter by (offset - dai_counter). in sof_ipc4_pcm_pointer()
1247 if (dai_cnt < time_info->stream_start_offset) { in sof_ipc4_pcm_pointer()
1248 host_cnt += time_info->stream_start_offset - dai_cnt; in sof_ipc4_pcm_pointer()
1251 dai_cnt -= time_info->stream_start_offset; in sof_ipc4_pcm_pointer()
1258 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { in sof_ipc4_pcm_pointer()
1267 time_info->delay = DELAY_BOUNDARY - tail_cnt + head_cnt; in sof_ipc4_pcm_pointer()
1269 time_info->delay = head_cnt - tail_cnt; in sof_ipc4_pcm_pointer()
1271 if (time_info->delay > DELAY_MAX) { in sof_ipc4_pcm_pointer()
1272 spcm_dbg_ratelimited(spcm, substream->stream, in sof_ipc4_pcm_pointer()
1275 time_info->delay = 0; in sof_ipc4_pcm_pointer()
1283 *pointer = bytes_to_frames(substream->runtime, host_ptr); in sof_ipc4_pcm_pointer()
1299 time_info = sof_ipc4_sps_to_time_info(&spcm->stream[substream->stream]); in sof_ipc4_pcm_delay()
1306 return time_info->delay; in sof_ipc4_pcm_delay()
1315 .trigger = sof_ipc4_pcm_trigger,