Lines Matching +full:no +full:- +full:reset +full:- +full:during +full:- +full:suspend

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"
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()
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()
51 dev_dbg(sdev->dev, "ipc4 set pipeline instance %d state %d", instance_id, state); in sof_ipc4_set_pipeline_state()
61 return sof_ipc_tx_message_no_reply(sdev->ipc, &msg, 0); in sof_ipc4_set_pipeline_state()
70 struct snd_sof_widget *pipe_widget = spipe->pipe_widget; in sof_ipc4_add_pipeline_to_trigger_list()
71 struct sof_ipc4_pipeline *pipeline = pipe_widget->private; in sof_ipc4_add_pipeline_to_trigger_list()
73 if (pipeline->skip_during_fe_trigger && state != SOF_IPC4_PIPE_RESET) in sof_ipc4_add_pipeline_to_trigger_list()
82 if (spipe->started_count == spipe->paused_count) in sof_ipc4_add_pipeline_to_trigger_list()
83 trigger_list->pipeline_instance_ids[trigger_list->count++] = in sof_ipc4_add_pipeline_to_trigger_list()
84 pipe_widget->instance_id; in sof_ipc4_add_pipeline_to_trigger_list()
87 /* RESET if the pipeline is neither running nor paused */ in sof_ipc4_add_pipeline_to_trigger_list()
88 if (!spipe->started_count && !spipe->paused_count) in sof_ipc4_add_pipeline_to_trigger_list()
89 trigger_list->pipeline_instance_ids[trigger_list->count++] = in sof_ipc4_add_pipeline_to_trigger_list()
90 pipe_widget->instance_id; in sof_ipc4_add_pipeline_to_trigger_list()
94 if (spipe->paused_count == (spipe->started_count - 1)) in sof_ipc4_add_pipeline_to_trigger_list()
95 trigger_list->pipeline_instance_ids[trigger_list->count++] = in sof_ipc4_add_pipeline_to_trigger_list()
96 pipe_widget->instance_id; in sof_ipc4_add_pipeline_to_trigger_list()
108 struct snd_sof_widget *pipe_widget = spipe->pipe_widget; in sof_ipc4_update_pipeline_state()
109 struct sof_ipc4_pipeline *pipeline = pipe_widget->private; in sof_ipc4_update_pipeline_state()
112 if (pipeline->skip_during_fe_trigger && state != SOF_IPC4_PIPE_RESET) in sof_ipc4_update_pipeline_state()
116 for (i = 0; i < trigger_list->count; i++) { in sof_ipc4_update_pipeline_state()
117 if (trigger_list->pipeline_instance_ids[i] == pipe_widget->instance_id) { in sof_ipc4_update_pipeline_state()
118 pipeline->state = state; in sof_ipc4_update_pipeline_state()
128 * increment paused_count if the PAUSED is the final state during in sof_ipc4_update_pipeline_state()
131 spipe->paused_count++; in sof_ipc4_update_pipeline_state()
136 * decrement started_count if PAUSED is the final state during the in sof_ipc4_update_pipeline_state()
139 spipe->started_count--; in sof_ipc4_update_pipeline_state()
149 spipe->paused_count--; in sof_ipc4_update_pipeline_state()
154 spipe->started_count++; in sof_ipc4_update_pipeline_state()
168 * +---------------+
172 * +-------+-------+
178 * +----------------+ +------v-------+ +-------------+
180 * | RUNNING <-------------+ PAUSED +--------------> + RESET |
182 * +------+---------+ RELEASE +---------+----+ +-------------+
188 * +---------------------------------+
189 * STOP/SUSPEND
191 * Note that during system suspend, the suspend trigger is followed by a hw_free in
192 * sof_pcm_trigger(). So, the final state during suspend would be RESET.
198 * Chained DMA is a special case where there is no processing on
238 dev_err(sdev->dev, "Unexpected state %d", state); in sof_ipc4_chain_dma_trigger()
239 return -EINVAL; in sof_ipc4_chain_dma_trigger()
247 * To set-up the DMA chain, the host DMA ID and SCS setting in sof_ipc4_chain_dma_trigger()
252 for (i = 0; i < pipeline_list->count; i++) { in sof_ipc4_chain_dma_trigger()
253 struct snd_sof_pipeline *spipe = pipeline_list->pipelines[i]; in sof_ipc4_chain_dma_trigger()
254 struct snd_sof_widget *pipe_widget = spipe->pipe_widget; in sof_ipc4_chain_dma_trigger()
255 struct sof_ipc4_pipeline *pipeline = pipe_widget->private; in sof_ipc4_chain_dma_trigger()
257 if (!pipeline->use_chain_dma) { in sof_ipc4_chain_dma_trigger()
258 dev_err(sdev->dev, in sof_ipc4_chain_dma_trigger()
260 return -EINVAL; in sof_ipc4_chain_dma_trigger()
263 msg.primary |= pipeline->msg.primary; in sof_ipc4_chain_dma_trigger()
267 msg.extension |= pipeline->msg.extension; in sof_ipc4_chain_dma_trigger()
276 return sof_ipc_tx_message_no_reply(sdev->ipc, &msg, 0); in sof_ipc4_chain_dma_trigger()
285 struct sof_ipc4_fw_data *ipc4_data = sdev->private; in sof_ipc4_trigger_pipelines()
294 dev_dbg(sdev->dev, "trigger cmd: %d state: %d\n", cmd, state); in sof_ipc4_trigger_pipelines()
298 return -EINVAL; in sof_ipc4_trigger_pipelines()
300 pipeline_list = &spcm->stream[substream->stream].pipeline_list; in sof_ipc4_trigger_pipelines()
303 if (!pipeline_list->pipelines || !pipeline_list->count) in sof_ipc4_trigger_pipelines()
306 spipe = pipeline_list->pipelines[0]; in sof_ipc4_trigger_pipelines()
307 pipe_widget = spipe->pipe_widget; in sof_ipc4_trigger_pipelines()
308 pipeline = pipe_widget->private; in sof_ipc4_trigger_pipelines()
314 if (pipeline->use_chain_dma) in sof_ipc4_trigger_pipelines()
319 pipeline_list->count), GFP_KERNEL); in sof_ipc4_trigger_pipelines()
321 return -ENOMEM; in sof_ipc4_trigger_pipelines()
323 mutex_lock(&ipc4_data->pipeline_state_mutex); in sof_ipc4_trigger_pipelines()
328 * sink->source when starting PCM's and in the reverse order to pause/stop PCM's. in sof_ipc4_trigger_pipelines()
331 * indeterministic. But the sink->source trigger order sink->source would still be in sof_ipc4_trigger_pipelines()
335 for (i = pipeline_list->count - 1; i >= 0; i--) { in sof_ipc4_trigger_pipelines()
336 spipe = pipeline_list->pipelines[i]; in sof_ipc4_trigger_pipelines()
340 for (i = 0; i < pipeline_list->count; i++) { in sof_ipc4_trigger_pipelines()
341 spipe = pipeline_list->pipelines[i]; in sof_ipc4_trigger_pipelines()
346 if (!trigger_list->count) { in sof_ipc4_trigger_pipelines()
351 /* no need to pause before reset or before pause release */ in sof_ipc4_trigger_pipelines()
361 dev_err(sdev->dev, "failed to pause all pipelines\n"); in sof_ipc4_trigger_pipelines()
366 for (i = 0; i < pipeline_list->count ; i++) { in sof_ipc4_trigger_pipelines()
367 spipe = pipeline_list->pipelines[i]; in sof_ipc4_trigger_pipelines()
376 /* else set the RUNNING/RESET state in the DSP */ in sof_ipc4_trigger_pipelines()
379 dev_err(sdev->dev, "failed to set final state %d for all pipelines\n", state); in sof_ipc4_trigger_pipelines()
382 * pipelines to reset state we must ignore the error code and in sof_ipc4_trigger_pipelines()
383 * reset it to 0. in sof_ipc4_trigger_pipelines()
388 if (sdev->fw_state != SOF_FW_CRASHED || state != SOF_IPC4_PIPE_RESET) in sof_ipc4_trigger_pipelines()
394 /* update RUNNING/RESET state for all pipelines that were just triggered */ in sof_ipc4_trigger_pipelines()
395 for (i = 0; i < pipeline_list->count; i++) { in sof_ipc4_trigger_pipelines()
396 spipe = pipeline_list->pipelines[i]; in sof_ipc4_trigger_pipelines()
401 mutex_unlock(&ipc4_data->pipeline_state_mutex); in sof_ipc4_trigger_pipelines()
426 dev_err(component->dev, "%s: unhandled trigger cmd %d\n", __func__, cmd); in sof_ipc4_pcm_trigger()
427 return -EINVAL; in sof_ipc4_pcm_trigger()
437 /* command is not relevant with RESET, so just pass 0 */ in sof_ipc4_pcm_hw_free()
449 list_for_each_entry(slink, &sdev->dai_link_list, list) { in ipc4_ssp_dai_config_pcm_params_match()
450 if (!strcmp(slink->link->name, link_name)) { in ipc4_ssp_dai_config_pcm_params_match()
459 for (i = 0; i < slink->num_hw_configs; i++) { in ipc4_ssp_dai_config_pcm_params_match()
460 struct snd_soc_tplg_hw_config *hw_config = &slink->hw_configs[i]; in ipc4_ssp_dai_config_pcm_params_match()
462 if (params_rate(params) == le32_to_cpu(hw_config->fsync_rate)) { in ipc4_ssp_dai_config_pcm_params_match()
464 list_for_each_entry(dai, &sdev->dai_list, list) in ipc4_ssp_dai_config_pcm_params_match()
465 if (!strcmp(slink->link->name, dai->name)) in ipc4_ssp_dai_config_pcm_params_match()
466 dai->current_config = le32_to_cpu(hw_config->id); in ipc4_ssp_dai_config_pcm_params_match()
480 struct sof_ipc4_pin_format *pin_fmts = ipc4_copier->available_fmt.input_pin_fmts; in sof_ipc4_pcm_dai_link_fixup_rate()
482 int num_input_formats = ipc4_copier->available_fmt.num_input_formats; in sof_ipc4_pcm_dai_link_fixup_rate()
515 dev_err(sdev->dev, "Unable to select sampling rate for DAI link\n"); in sof_ipc4_pcm_dai_link_fixup_rate()
516 return -EINVAL; in sof_ipc4_pcm_dai_link_fixup_rate()
519 rate->min = be_rate; in sof_ipc4_pcm_dai_link_fixup_rate()
520 rate->max = rate->min; in sof_ipc4_pcm_dai_link_fixup_rate()
530 struct snd_sof_dai *dai = snd_sof_find_dai(component, rtd->dai_link->name); in sof_ipc4_pcm_dai_link_fixup()
538 dev_err(component->dev, "%s: No DAI found with name %s\n", __func__, in sof_ipc4_pcm_dai_link_fixup()
539 rtd->dai_link->name); in sof_ipc4_pcm_dai_link_fixup()
540 return -EINVAL; in sof_ipc4_pcm_dai_link_fixup()
543 ipc4_copier = dai->private; in sof_ipc4_pcm_dai_link_fixup()
545 dev_err(component->dev, "%s: No private data found for DAI %s\n", in sof_ipc4_pcm_dai_link_fixup()
546 __func__, rtd->dai_link->name); in sof_ipc4_pcm_dai_link_fixup()
547 return -EINVAL; in sof_ipc4_pcm_dai_link_fixup()
554 struct snd_sof_widget *swidget = w->dobj.private; in sof_ipc4_pcm_dai_link_fixup()
555 struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; in sof_ipc4_pcm_dai_link_fixup()
556 struct sof_ipc4_pipeline *pipeline = pipe_widget->private; in sof_ipc4_pcm_dai_link_fixup()
558 if (pipeline->use_chain_dma) in sof_ipc4_pcm_dai_link_fixup()
563 /* Chain DMA does not use copiers, so no fixup needed */ in sof_ipc4_pcm_dai_link_fixup()
571 switch (ipc4_copier->dai_type) { in sof_ipc4_pcm_dai_link_fixup()
573 ipc4_ssp_dai_config_pcm_params_match(sdev, (char *)rtd->dai_link->name, params); in sof_ipc4_pcm_dai_link_fixup()
588 pipeline_list = &spcm->stream[stream].pipeline_list; in sof_ipc4_pcm_free()
589 kfree(pipeline_list->pipelines); in sof_ipc4_pcm_free()
590 pipeline_list->pipelines = NULL; in sof_ipc4_pcm_free()
591 kfree(spcm->stream[stream].private); in sof_ipc4_pcm_free()
592 spcm->stream[stream].private = NULL; in sof_ipc4_pcm_free()
599 struct sof_ipc4_fw_data *ipc4_data = sdev->private; in sof_ipc4_pcm_setup()
607 sof_mailbox_read(sdev, sdev->fw_info_box.offset + abi_offset, &abi_version, in sof_ipc4_pcm_setup()
614 pipeline_list = &spcm->stream[stream].pipeline_list; in sof_ipc4_pcm_setup()
617 pipeline_list->pipelines = kcalloc(ipc4_data->max_num_pipelines, in sof_ipc4_pcm_setup()
619 if (!pipeline_list->pipelines) { in sof_ipc4_pcm_setup()
621 return -ENOMEM; in sof_ipc4_pcm_setup()
630 return -ENOMEM; in sof_ipc4_pcm_setup()
633 spcm->stream[stream].private = stream_info; in sof_ipc4_pcm_setup()
650 for_each_dapm_widgets(spcm->list, i, widget) { in sof_ipc4_build_time_info()
651 struct snd_sof_widget *swidget = widget->dobj.private; in sof_ipc4_build_time_info()
656 if (WIDGET_IS_AIF(swidget->widget->id)) { in sof_ipc4_build_time_info()
657 host_copier = swidget->private; in sof_ipc4_build_time_info()
658 } else if (WIDGET_IS_DAI(swidget->widget->id)) { in sof_ipc4_build_time_info()
659 dai = swidget->private; in sof_ipc4_build_time_info()
660 dai_copier = dai->private; in sof_ipc4_build_time_info()
666 dev_err(sdev->dev, "host or dai copier are not found\n"); in sof_ipc4_build_time_info()
670 info = spcm->private; in sof_ipc4_build_time_info()
671 info->host_copier = host_copier; in sof_ipc4_build_time_info()
672 info->dai_copier = dai_copier; in sof_ipc4_build_time_info()
673 info->llp_offset = offsetof(struct sof_ipc4_fw_registers, llp_gpdma_reading_slots) + in sof_ipc4_build_time_info()
674 sdev->fw_info_box.offset; in sof_ipc4_build_time_info()
678 sof_mailbox_read(sdev, info->llp_offset, &llp_slot, sizeof(llp_slot)); in sof_ipc4_build_time_info()
679 if (llp_slot.node_id == dai_copier->data.gtw_cfg.node_id) in sof_ipc4_build_time_info()
682 info->llp_offset += sizeof(llp_slot); in sof_ipc4_build_time_info()
688 /* if no llp gpdma slot is used, check aggregated sdw slot */ in sof_ipc4_build_time_info()
689 info->llp_offset = offsetof(struct sof_ipc4_fw_registers, llp_sndw_reading_slots) + in sof_ipc4_build_time_info()
690 sdev->fw_info_box.offset; in sof_ipc4_build_time_info()
692 sof_mailbox_read(sdev, info->llp_offset, &llp_slot, sizeof(llp_slot)); in sof_ipc4_build_time_info()
693 if (llp_slot.node_id == dai_copier->data.gtw_cfg.node_id) in sof_ipc4_build_time_info()
696 info->llp_offset += sizeof(llp_slot); in sof_ipc4_build_time_info()
703 info->llp_offset = offsetof(struct sof_ipc4_fw_registers, llp_evad_reading_slot) + in sof_ipc4_build_time_info()
704 sdev->fw_info_box.offset; in sof_ipc4_build_time_info()
705 sof_mailbox_read(sdev, info->llp_offset, &llp_slot, sizeof(llp_slot)); in sof_ipc4_build_time_info()
706 if (llp_slot.node_id != dai_copier->data.gtw_cfg.node_id) { in sof_ipc4_build_time_info()
707 dev_info(sdev->dev, "no llp found, fall back to default HDA path"); in sof_ipc4_build_time_info()
708 info->llp_offset = 0; in sof_ipc4_build_time_info()
724 return -EINVAL; in sof_ipc4_pcm_hw_params()
726 time_info = spcm->stream[substream->stream].private; in sof_ipc4_pcm_hw_params()
731 time_info->stream_start_offset = SOF_IPC4_INVALID_STREAM_POSITION; in sof_ipc4_pcm_hw_params()
732 time_info->llp_offset = 0; in sof_ipc4_pcm_hw_params()
734 sof_ipc4_build_time_info(sdev, &spcm->stream[substream->stream]); in sof_ipc4_pcm_hw_params()
744 struct sof_ipc4_copier *host_copier = time_info->host_copier; in sof_ipc4_get_stream_start_offset()
745 struct sof_ipc4_copier *dai_copier = time_info->dai_copier; in sof_ipc4_get_stream_start_offset()
753 return -EINVAL; in sof_ipc4_get_stream_start_offset()
755 if (host_copier->data.gtw_cfg.node_id == SOF_IPC4_INVALID_NODE_ID) in sof_ipc4_get_stream_start_offset()
756 return -EINVAL; in sof_ipc4_get_stream_start_offset()
758 node_index = SOF_IPC4_NODE_INDEX(host_copier->data.gtw_cfg.node_id); in sof_ipc4_get_stream_start_offset()
760 sof_mailbox_read(sdev, sdev->fw_info_box.offset + offset, &ppl_reg, sizeof(ppl_reg)); in sof_ipc4_get_stream_start_offset()
762 return -EINVAL; in sof_ipc4_get_stream_start_offset()
765 ch = dai_copier->data.out_format.fmt_cfg; in sof_ipc4_get_stream_start_offset()
767 dai_sample_size = (dai_copier->data.out_format.bit_depth >> 3) * ch; in sof_ipc4_get_stream_start_offset()
770 time_info->stream_start_offset = stream_start_position; in sof_ipc4_get_stream_start_offset()
792 stream = &spcm->stream[substream->stream]; in sof_ipc4_pcm_delay()
793 time_info = stream->private; in sof_ipc4_pcm_delay()
802 if (time_info->stream_start_offset == SOF_IPC4_INVALID_STREAM_POSITION) { in sof_ipc4_pcm_delay()
812 if (!time_info->llp_offset) { in sof_ipc4_pcm_delay()
817 sof_mailbox_read(sdev, time_info->llp_offset, &llp, sizeof(llp)); in sof_ipc4_pcm_delay()
828 tmp_ptr -= time_info->stream_start_offset; in sof_ipc4_pcm_delay()
831 div64_u64_rem(tmp_ptr, substream->runtime->boundary, &tmp_ptr); in sof_ipc4_pcm_delay()
832 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { in sof_ipc4_pcm_delay()
833 head_ptr = substream->runtime->status->hw_ptr; in sof_ipc4_pcm_delay()
837 tail_ptr = substream->runtime->status->hw_ptr; in sof_ipc4_pcm_delay()
841 return substream->runtime->boundary - tail_ptr + head_ptr; in sof_ipc4_pcm_delay()
843 return head_ptr - tail_ptr; in sof_ipc4_pcm_delay()