Lines Matching +full:primary +full:- +full:dai +full:- +full:link

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"
22 u32 primary, ipc_size; in sof_ipc4_set_multi_pipeline_state() local
25 if (trigger_list->count == 1) in sof_ipc4_set_multi_pipeline_state()
26 return sof_ipc4_set_pipeline_state(sdev, trigger_list->pipeline_instance_ids[0], in sof_ipc4_set_multi_pipeline_state()
29 primary = state; in sof_ipc4_set_multi_pipeline_state()
30 primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_SET_PIPELINE_STATE); in sof_ipc4_set_multi_pipeline_state()
31 primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); in sof_ipc4_set_multi_pipeline_state()
32 primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG); in sof_ipc4_set_multi_pipeline_state()
33 msg.primary = primary; in sof_ipc4_set_multi_pipeline_state()
39 ipc_size = sizeof(u32) * (trigger_list->count + 1); in sof_ipc4_set_multi_pipeline_state()
43 return sof_ipc_tx_message_no_reply(sdev->ipc, &msg, ipc_size); in sof_ipc4_set_multi_pipeline_state()
49 u32 primary; in sof_ipc4_set_pipeline_state() local
51 dev_dbg(sdev->dev, "ipc4 set pipeline instance %d state %d", instance_id, state); in sof_ipc4_set_pipeline_state()
53 primary = state; in sof_ipc4_set_pipeline_state()
54 primary |= SOF_IPC4_GLB_PIPE_STATE_ID(instance_id); in sof_ipc4_set_pipeline_state()
55 primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_SET_PIPELINE_STATE); in sof_ipc4_set_pipeline_state()
56 primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); in sof_ipc4_set_pipeline_state()
57 primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG); in sof_ipc4_set_pipeline_state()
59 msg.primary = primary; in sof_ipc4_set_pipeline_state()
61 return sof_ipc_tx_message_no_reply(sdev->ipc, &msg, 0); in sof_ipc4_set_pipeline_state()
69 struct sof_ipc4_pipeline *pipeline = pipe_widget->private; in sof_ipc4_add_pipeline_by_priority()
72 for (i = 0; i < trigger_list->count; i++) { in sof_ipc4_add_pipeline_by_priority()
74 if (ascend && pipeline->priority < pipe_priority[i]) in sof_ipc4_add_pipeline_by_priority()
77 else if (!ascend && pipeline->priority > pipe_priority[i]) in sof_ipc4_add_pipeline_by_priority()
81 for (j = trigger_list->count - 1; j >= i; j--) { in sof_ipc4_add_pipeline_by_priority()
82 trigger_list->pipeline_instance_ids[j + 1] = trigger_list->pipeline_instance_ids[j]; in sof_ipc4_add_pipeline_by_priority()
86 trigger_list->pipeline_instance_ids[i] = pipe_widget->instance_id; in sof_ipc4_add_pipeline_by_priority()
87 trigger_list->count++; in sof_ipc4_add_pipeline_by_priority()
88 pipe_priority[i] = pipeline->priority; in sof_ipc4_add_pipeline_by_priority()
97 struct snd_sof_widget *pipe_widget = spipe->pipe_widget; in sof_ipc4_add_pipeline_to_trigger_list()
98 struct sof_ipc4_pipeline *pipeline = pipe_widget->private; in sof_ipc4_add_pipeline_to_trigger_list()
100 if (pipeline->skip_during_fe_trigger && state != SOF_IPC4_PIPE_RESET) in sof_ipc4_add_pipeline_to_trigger_list()
109 if (spipe->started_count == spipe->paused_count) in sof_ipc4_add_pipeline_to_trigger_list()
115 if (!spipe->started_count && !spipe->paused_count) in sof_ipc4_add_pipeline_to_trigger_list()
121 if (spipe->paused_count == (spipe->started_count - 1)) in sof_ipc4_add_pipeline_to_trigger_list()
135 struct snd_sof_widget *pipe_widget = spipe->pipe_widget; in sof_ipc4_update_pipeline_state()
136 struct sof_ipc4_pipeline *pipeline = pipe_widget->private; in sof_ipc4_update_pipeline_state()
139 if (pipeline->skip_during_fe_trigger && state != SOF_IPC4_PIPE_RESET) in sof_ipc4_update_pipeline_state()
143 for (i = 0; i < trigger_list->count; i++) { in sof_ipc4_update_pipeline_state()
144 if (trigger_list->pipeline_instance_ids[i] == pipe_widget->instance_id) { in sof_ipc4_update_pipeline_state()
145 pipeline->state = state; in sof_ipc4_update_pipeline_state()
158 spipe->paused_count++; in sof_ipc4_update_pipeline_state()
166 spipe->started_count--; in sof_ipc4_update_pipeline_state()
176 spipe->paused_count--; in sof_ipc4_update_pipeline_state()
181 spipe->started_count++; in sof_ipc4_update_pipeline_state()
195 * +---------------+
199 * +-------+-------+
205 * +----------------+ +------v-------+ +-------------+
207 * | RUNNING <-------------+ PAUSED +--------------> + RESET |
209 * +------+---------+ RELEASE +---------+----+ +-------------+
215 * +---------------------------------+
227 * buffer on DSP and directly from there to link DMA. However, the
228 * model on SOF driver has two notional pipelines, one at host DAI,
229 * and another at link DAI. They both shall have the use_chain_dma
265 dev_err(sdev->dev, "Unexpected state %d", state); in sof_ipc4_chain_dma_trigger()
266 return -EINVAL; in sof_ipc4_chain_dma_trigger()
269 msg.primary = SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_CHAIN_DMA); in sof_ipc4_chain_dma_trigger()
270 msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); in sof_ipc4_chain_dma_trigger()
271 msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG); in sof_ipc4_chain_dma_trigger()
274 * To set-up the DMA chain, the host DMA ID and SCS setting in sof_ipc4_chain_dma_trigger()
276 * the link DMA ID and fifo_size are retrieved from the link in sof_ipc4_chain_dma_trigger()
279 for (i = 0; i < pipeline_list->count; i++) { in sof_ipc4_chain_dma_trigger()
280 struct snd_sof_pipeline *spipe = pipeline_list->pipelines[i]; in sof_ipc4_chain_dma_trigger()
281 struct snd_sof_widget *pipe_widget = spipe->pipe_widget; in sof_ipc4_chain_dma_trigger()
282 struct sof_ipc4_pipeline *pipeline = pipe_widget->private; in sof_ipc4_chain_dma_trigger()
284 if (!pipeline->use_chain_dma) { in sof_ipc4_chain_dma_trigger()
285 dev_err(sdev->dev, in sof_ipc4_chain_dma_trigger()
287 return -EINVAL; in sof_ipc4_chain_dma_trigger()
290 msg.primary |= pipeline->msg.primary; in sof_ipc4_chain_dma_trigger()
294 msg.extension |= pipeline->msg.extension; in sof_ipc4_chain_dma_trigger()
298 msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_ALLOCATE_MASK; in sof_ipc4_chain_dma_trigger()
301 msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_ENABLE_MASK; in sof_ipc4_chain_dma_trigger()
303 return sof_ipc_tx_message_no_reply(sdev->ipc, &msg, 0); in sof_ipc4_chain_dma_trigger()
312 struct sof_ipc4_fw_data *ipc4_data = sdev->private; in sof_ipc4_trigger_pipelines()
322 dev_dbg(sdev->dev, "trigger cmd: %d state: %d\n", cmd, state); in sof_ipc4_trigger_pipelines()
326 return -EINVAL; in sof_ipc4_trigger_pipelines()
328 pipeline_list = &spcm->stream[substream->stream].pipeline_list; in sof_ipc4_trigger_pipelines()
331 if (!pipeline_list->pipelines || !pipeline_list->count) in sof_ipc4_trigger_pipelines()
334 spipe = pipeline_list->pipelines[0]; in sof_ipc4_trigger_pipelines()
335 pipe_widget = spipe->pipe_widget; in sof_ipc4_trigger_pipelines()
336 pipeline = pipe_widget->private; in sof_ipc4_trigger_pipelines()
342 if (pipeline->use_chain_dma) in sof_ipc4_trigger_pipelines()
347 pipeline_list->count), GFP_KERNEL); in sof_ipc4_trigger_pipelines()
349 return -ENOMEM; in sof_ipc4_trigger_pipelines()
351 pipe_priority = kzalloc(pipeline_list->count, GFP_KERNEL); in sof_ipc4_trigger_pipelines()
354 return -ENOMEM; in sof_ipc4_trigger_pipelines()
357 mutex_lock(&ipc4_data->pipeline_state_mutex); in sof_ipc4_trigger_pipelines()
362 * sink->source when starting PCM's and in the reverse order to pause/stop PCM's. in sof_ipc4_trigger_pipelines()
365 * indeterministic. But the sink->source trigger order sink->source would still be in sof_ipc4_trigger_pipelines()
369 for (i = pipeline_list->count - 1; i >= 0; i--) { in sof_ipc4_trigger_pipelines()
370 spipe = pipeline_list->pipelines[i]; in sof_ipc4_trigger_pipelines()
375 for (i = 0; i < pipeline_list->count; i++) { in sof_ipc4_trigger_pipelines()
376 spipe = pipeline_list->pipelines[i]; in sof_ipc4_trigger_pipelines()
382 if (!trigger_list->count) { in sof_ipc4_trigger_pipelines()
397 dev_err(sdev->dev, "failed to pause all pipelines\n"); in sof_ipc4_trigger_pipelines()
402 for (i = 0; i < pipeline_list->count ; i++) { in sof_ipc4_trigger_pipelines()
403 spipe = pipeline_list->pipelines[i]; in sof_ipc4_trigger_pipelines()
415 dev_err(sdev->dev, "failed to set final state %d for all pipelines\n", state); in sof_ipc4_trigger_pipelines()
424 if (sdev->fw_state != SOF_FW_CRASHED || state != SOF_IPC4_PIPE_RESET) in sof_ipc4_trigger_pipelines()
431 for (i = 0; i < pipeline_list->count; i++) { in sof_ipc4_trigger_pipelines()
432 spipe = pipeline_list->pipelines[i]; in sof_ipc4_trigger_pipelines()
437 mutex_unlock(&ipc4_data->pipeline_state_mutex); in sof_ipc4_trigger_pipelines()
463 dev_err(component->dev, "%s: unhandled trigger cmd %d\n", __func__, cmd); in sof_ipc4_pcm_trigger()
464 return -EINVAL; in sof_ipc4_pcm_trigger()
482 struct snd_sof_dai *dai; in ipc4_ssp_dai_config_pcm_params_match() local
486 list_for_each_entry(slink, &sdev->dai_link_list, list) { in ipc4_ssp_dai_config_pcm_params_match()
487 if (!strcmp(slink->link->name, link_name)) { in ipc4_ssp_dai_config_pcm_params_match()
496 for (i = 0; i < slink->num_hw_configs; i++) { in ipc4_ssp_dai_config_pcm_params_match()
497 struct snd_soc_tplg_hw_config *hw_config = &slink->hw_configs[i]; in ipc4_ssp_dai_config_pcm_params_match()
499 if (params_rate(params) == le32_to_cpu(hw_config->fsync_rate)) { in ipc4_ssp_dai_config_pcm_params_match()
500 /* set current config for all DAI's with matching name */ in ipc4_ssp_dai_config_pcm_params_match()
501 list_for_each_entry(dai, &sdev->dai_list, list) in ipc4_ssp_dai_config_pcm_params_match()
502 if (!strcmp(slink->link->name, dai->name)) in ipc4_ssp_dai_config_pcm_params_match()
503 dai->current_config = le32_to_cpu(hw_config->id); in ipc4_ssp_dai_config_pcm_params_match()
510 * Fixup DAI link parameters for sampling rate based on
511 * DAI copier configuration.
517 struct sof_ipc4_pin_format *pin_fmts = ipc4_copier->available_fmt.input_pin_fmts; in sof_ipc4_pcm_dai_link_fixup_rate()
519 int num_input_formats = ipc4_copier->available_fmt.num_input_formats; in sof_ipc4_pcm_dai_link_fixup_rate()
547 * define a single rate in the DAI copier config in in sof_ipc4_pcm_dai_link_fixup_rate()
552 dev_err(sdev->dev, "Unable to select sampling rate for DAI link\n"); in sof_ipc4_pcm_dai_link_fixup_rate()
553 return -EINVAL; in sof_ipc4_pcm_dai_link_fixup_rate()
556 rate->min = be_rate; in sof_ipc4_pcm_dai_link_fixup_rate()
557 rate->max = rate->min; in sof_ipc4_pcm_dai_link_fixup_rate()
567 struct snd_sof_dai *dai = snd_sof_find_dai(component, rtd->dai_link->name); in sof_ipc4_pcm_dai_link_fixup() local
577 if (!dai) { in sof_ipc4_pcm_dai_link_fixup()
578 dev_err(component->dev, "%s: No DAI found with name %s\n", __func__, in sof_ipc4_pcm_dai_link_fixup()
579 rtd->dai_link->name); in sof_ipc4_pcm_dai_link_fixup()
580 return -EINVAL; in sof_ipc4_pcm_dai_link_fixup()
583 ipc4_copier = dai->private; in sof_ipc4_pcm_dai_link_fixup()
585 dev_err(component->dev, "%s: No private data found for DAI %s\n", in sof_ipc4_pcm_dai_link_fixup()
586 __func__, rtd->dai_link->name); in sof_ipc4_pcm_dai_link_fixup()
587 return -EINVAL; in sof_ipc4_pcm_dai_link_fixup()
595 &ipc4_copier->available_fmt; in sof_ipc4_pcm_dai_link_fixup()
596 struct snd_sof_widget *swidget = w->dobj.private; in sof_ipc4_pcm_dai_link_fixup()
597 struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; in sof_ipc4_pcm_dai_link_fixup()
598 struct sof_ipc4_pipeline *pipeline = pipe_widget->private; in sof_ipc4_pcm_dai_link_fixup()
601 if (pipeline->use_chain_dma) in sof_ipc4_pcm_dai_link_fixup()
606 available_fmt->output_pin_fmts, in sof_ipc4_pcm_dai_link_fixup()
607 available_fmt->num_output_formats)) { in sof_ipc4_pcm_dai_link_fixup()
608 ipc4_fmt = &available_fmt->output_pin_fmts->audio_fmt; in sof_ipc4_pcm_dai_link_fixup()
613 available_fmt->input_pin_fmts, in sof_ipc4_pcm_dai_link_fixup()
614 available_fmt->num_input_formats)) { in sof_ipc4_pcm_dai_link_fixup()
615 ipc4_fmt = &available_fmt->input_pin_fmts->audio_fmt; in sof_ipc4_pcm_dai_link_fixup()
628 valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(ipc4_fmt->fmt_cfg); in sof_ipc4_pcm_dai_link_fixup()
629 dev_dbg(component->dev, "Set %s to %d bit format\n", dai->name, valid_bits); in sof_ipc4_pcm_dai_link_fixup()
647 switch (ipc4_copier->dai_type) { in sof_ipc4_pcm_dai_link_fixup()
649 ipc4_ssp_dai_config_pcm_params_match(sdev, (char *)rtd->dai_link->name, params); in sof_ipc4_pcm_dai_link_fixup()
664 pipeline_list = &spcm->stream[stream].pipeline_list; in sof_ipc4_pcm_free()
665 kfree(pipeline_list->pipelines); in sof_ipc4_pcm_free()
666 pipeline_list->pipelines = NULL; in sof_ipc4_pcm_free()
667 kfree(spcm->stream[stream].private); in sof_ipc4_pcm_free()
668 spcm->stream[stream].private = NULL; in sof_ipc4_pcm_free()
675 struct sof_ipc4_fw_data *ipc4_data = sdev->private; in sof_ipc4_pcm_setup()
683 sof_mailbox_read(sdev, sdev->fw_info_box.offset + abi_offset, &abi_version, in sof_ipc4_pcm_setup()
690 pipeline_list = &spcm->stream[stream].pipeline_list; in sof_ipc4_pcm_setup()
693 pipeline_list->pipelines = kcalloc(ipc4_data->max_num_pipelines, in sof_ipc4_pcm_setup()
695 if (!pipeline_list->pipelines) { in sof_ipc4_pcm_setup()
697 return -ENOMEM; in sof_ipc4_pcm_setup()
706 return -ENOMEM; in sof_ipc4_pcm_setup()
709 spcm->stream[stream].private = stream_info; in sof_ipc4_pcm_setup()
722 struct snd_sof_dai *dai; in sof_ipc4_build_time_info() local
725 /* find host & dai to locate info in memory window */ in sof_ipc4_build_time_info()
726 for_each_dapm_widgets(spcm->list, i, widget) { in sof_ipc4_build_time_info()
727 struct snd_sof_widget *swidget = widget->dobj.private; in sof_ipc4_build_time_info()
732 if (WIDGET_IS_AIF(swidget->widget->id)) { in sof_ipc4_build_time_info()
733 host_copier = swidget->private; in sof_ipc4_build_time_info()
734 } else if (WIDGET_IS_DAI(swidget->widget->id)) { in sof_ipc4_build_time_info()
735 dai = swidget->private; in sof_ipc4_build_time_info()
736 dai_copier = dai->private; in sof_ipc4_build_time_info()
740 /* both host and dai copier must be valid for time_info */ in sof_ipc4_build_time_info()
742 dev_err(sdev->dev, "host or dai copier are not found\n"); in sof_ipc4_build_time_info()
746 info = spcm->private; in sof_ipc4_build_time_info()
747 info->host_copier = host_copier; in sof_ipc4_build_time_info()
748 info->dai_copier = dai_copier; in sof_ipc4_build_time_info()
749 info->llp_offset = offsetof(struct sof_ipc4_fw_registers, llp_gpdma_reading_slots) + in sof_ipc4_build_time_info()
750 sdev->fw_info_box.offset; in sof_ipc4_build_time_info()
752 /* find llp slot used by current dai */ in sof_ipc4_build_time_info()
754 sof_mailbox_read(sdev, info->llp_offset, &llp_slot, sizeof(llp_slot)); in sof_ipc4_build_time_info()
755 if (llp_slot.node_id == dai_copier->data.gtw_cfg.node_id) in sof_ipc4_build_time_info()
758 info->llp_offset += sizeof(llp_slot); in sof_ipc4_build_time_info()
765 info->llp_offset = offsetof(struct sof_ipc4_fw_registers, llp_sndw_reading_slots) + in sof_ipc4_build_time_info()
766 sdev->fw_info_box.offset; in sof_ipc4_build_time_info()
768 sof_mailbox_read(sdev, info->llp_offset, &llp_slot, sizeof(llp_slot)); in sof_ipc4_build_time_info()
769 if (llp_slot.node_id == dai_copier->data.gtw_cfg.node_id) in sof_ipc4_build_time_info()
772 info->llp_offset += sizeof(llp_slot); in sof_ipc4_build_time_info()
779 info->llp_offset = offsetof(struct sof_ipc4_fw_registers, llp_evad_reading_slot) + in sof_ipc4_build_time_info()
780 sdev->fw_info_box.offset; in sof_ipc4_build_time_info()
781 sof_mailbox_read(sdev, info->llp_offset, &llp_slot, sizeof(llp_slot)); in sof_ipc4_build_time_info()
782 if (llp_slot.node_id != dai_copier->data.gtw_cfg.node_id) in sof_ipc4_build_time_info()
783 info->llp_offset = 0; in sof_ipc4_build_time_info()
798 return -EINVAL; in sof_ipc4_pcm_hw_params()
800 time_info = spcm->stream[substream->stream].private; in sof_ipc4_pcm_hw_params()
805 time_info->stream_start_offset = SOF_IPC4_INVALID_STREAM_POSITION; in sof_ipc4_pcm_hw_params()
806 time_info->llp_offset = 0; in sof_ipc4_pcm_hw_params()
808 sof_ipc4_build_time_info(sdev, &spcm->stream[substream->stream]); in sof_ipc4_pcm_hw_params()
818 struct sof_ipc4_copier *host_copier = time_info->host_copier; in sof_ipc4_get_stream_start_offset()
819 struct sof_ipc4_copier *dai_copier = time_info->dai_copier; in sof_ipc4_get_stream_start_offset()
827 return -EINVAL; in sof_ipc4_get_stream_start_offset()
829 if (host_copier->data.gtw_cfg.node_id == SOF_IPC4_INVALID_NODE_ID) in sof_ipc4_get_stream_start_offset()
830 return -EINVAL; in sof_ipc4_get_stream_start_offset()
832 node_index = SOF_IPC4_NODE_INDEX(host_copier->data.gtw_cfg.node_id); in sof_ipc4_get_stream_start_offset()
834 sof_mailbox_read(sdev, sdev->fw_info_box.offset + offset, &ppl_reg, sizeof(ppl_reg)); in sof_ipc4_get_stream_start_offset()
836 return -EINVAL; in sof_ipc4_get_stream_start_offset()
839 ch = dai_copier->data.out_format.fmt_cfg; in sof_ipc4_get_stream_start_offset()
841 dai_sample_size = (dai_copier->data.out_format.bit_depth >> 3) * ch; in sof_ipc4_get_stream_start_offset()
844 time_info->stream_start_offset = stream_start_position; in sof_ipc4_get_stream_start_offset()
866 stream = &spcm->stream[substream->stream]; in sof_ipc4_pcm_delay()
867 time_info = stream->private; in sof_ipc4_pcm_delay()
876 if (time_info->stream_start_offset == SOF_IPC4_INVALID_STREAM_POSITION) { in sof_ipc4_pcm_delay()
884 * the link position is read directly from hardware registers. in sof_ipc4_pcm_delay()
886 if (!time_info->llp_offset) { in sof_ipc4_pcm_delay()
891 sof_mailbox_read(sdev, time_info->llp_offset, &llp, sizeof(llp)); in sof_ipc4_pcm_delay()
895 /* In two cases dai dma position is not accurate in sof_ipc4_pcm_delay()
896 * (1) dai pipeline is started before host pipeline in sof_ipc4_pcm_delay()
897 * (2) multiple streams mixed into one. Each stream has the same dai dma position in sof_ipc4_pcm_delay()
900 * Driver subtracts stream_start_offset from dai dma position to get accurate one in sof_ipc4_pcm_delay()
902 tmp_ptr -= time_info->stream_start_offset; in sof_ipc4_pcm_delay()
905 div64_u64_rem(tmp_ptr, substream->runtime->boundary, &tmp_ptr); in sof_ipc4_pcm_delay()
906 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { in sof_ipc4_pcm_delay()
907 head_ptr = substream->runtime->status->hw_ptr; in sof_ipc4_pcm_delay()
911 tail_ptr = substream->runtime->status->hw_ptr; in sof_ipc4_pcm_delay()
915 return substream->runtime->boundary - tail_ptr + head_ptr; in sof_ipc4_pcm_delay()
917 return head_ptr - tail_ptr; in sof_ipc4_pcm_delay()