1313#include "ipc4-priv.h"
1414#include "ipc4-topology.h"
1515
16+ static int sof_ipc4_set_multi_pipeline_state (struct snd_sof_dev * sdev , u32 state ,
17+ struct sof_ipc4_multi_pipeline_info * info )
18+ {
19+ struct ipc4_pipeline_set_state_data data ;
20+ struct sof_ipc4_msg msg = {{ 0 }};
21+ u32 primary , ipc_size ;
22+ int i ;
23+
24+ primary = state ;
25+ primary |= SOF_IPC4_MSG_TYPE_SET (SOF_IPC4_GLB_SET_PIPELINE_STATE );
26+ primary |= SOF_IPC4_MSG_DIR (SOF_IPC4_MSG_REQUEST );
27+ primary |= SOF_IPC4_MSG_TARGET (SOF_IPC4_FW_GEN_MSG );
28+
29+ msg .primary = primary ;
30+
31+ msg .extension = SOF_IPC4_GLB_PIPE_MULTI ;
32+
33+ data .count = info -> count ;
34+ for (i = 0 ; i < info -> count ; i ++ )
35+ data .pipeline_ids [i ] = info -> pipelines [i ]-> instance_id ;
36+
37+ ipc_size = sizeof (u32 ) * (info -> count + 1 );
38+ msg .data_size = ipc_size ;
39+ msg .data_ptr = & data ;
40+
41+ return sof_ipc_tx_message (sdev -> ipc , & msg , ipc_size , NULL , 0 );
42+ }
43+
1644int sof_ipc4_set_pipeline_state (struct snd_sof_dev * sdev , u32 id , u32 state )
1745{
1846 struct sof_ipc4_msg msg = {{ 0 }};
@@ -32,65 +60,184 @@ int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 id, u32 state)
3260}
3361EXPORT_SYMBOL (sof_ipc4_set_pipeline_state );
3462
63+ /* helper function to get the list of pipeline widgets that need to be triggered */
64+ static int
65+ sof_ipc4_get_pipelines_in_order (struct snd_sof_dev * sdev , struct snd_soc_dapm_widget * widget ,
66+ struct snd_soc_dapm_widget_list * list ,
67+ struct sof_ipc4_multi_pipeline_info * pipeline_info )
68+ {
69+ struct snd_sof_widget * swidget = widget -> dobj .private ;
70+ struct snd_sof_widget * pipeline_widget ;
71+ struct sof_ipc4_pipeline * pipeline ;
72+ struct snd_soc_dapm_path * p ;
73+ uint32_t pipeline_count ;
74+ int ret , i ;
75+
76+ if (!swidget )
77+ goto src_add ;
78+
79+ /* find pipeline widget for the pipeline that this widget belongs to */
80+ pipeline_widget = swidget -> pipe_widget ;
81+ pipeline = pipeline_widget -> private ;
82+
83+ /* do not add backend pipelines */
84+ if (pipeline -> is_backend )
85+ goto src_add ;
86+
87+ /* check if pipeline has already been added to the list */
88+ for (i = 0 ; i < pipeline_info -> count ; i ++ )
89+ if (pipeline_info -> pipelines [i ] == pipeline_widget )
90+ goto src_add ;
91+
92+ pipeline_count = pipeline_info -> count ++ ;
93+ if (pipeline_info -> count > SOF_IPC4_TRIGGER_MAX_PIPELINE_COUNT ) {
94+ dev_err (sdev -> dev , "Cannot trigger %d pipelines at once\n" , pipeline_info -> count );
95+ return - EINVAL ;
96+ }
97+
98+ pipeline_info -> pipelines [pipeline_count ] = pipeline_widget ;
99+
100+ src_add :
101+ /* add pipelines in the source paths */
102+ snd_soc_dapm_widget_for_each_source_path (widget , p ) {
103+ if (!widget_in_list (list , p -> source ))
104+ continue ;
105+
106+ if (!p -> walking && p -> source -> dobj .private ) {
107+ p -> walking = true;
108+ ret = sof_ipc4_get_pipelines_in_order (sdev , p -> source , list , pipeline_info );
109+ p -> walking = false;
110+ if (ret < 0 )
111+ return ret ;
112+ }
113+ }
114+
115+ return 0 ;
116+ }
117+
35118static int sof_ipc4_trigger_pipelines (struct snd_soc_component * component ,
36119 struct snd_pcm_substream * substream , int state )
37120{
38121 struct snd_sof_dev * sdev = snd_soc_component_get_drvdata (component );
39122 struct snd_soc_pcm_runtime * rtd = asoc_substream_to_rtd (substream );
123+ struct sof_ipc4_multi_pipeline_info pipeline_info ;
40124 struct snd_sof_widget * pipeline_widget ;
41125 struct snd_soc_dapm_widget_list * list ;
42126 struct snd_soc_dapm_widget * widget ;
43127 struct sof_ipc4_pipeline * pipeline ;
44128 struct snd_sof_widget * swidget ;
45129 struct snd_sof_pcm * spcm ;
46130 int ret = 0 ;
47- int num_widgets ;
131+ int num_widgets , i ;
48132
49133 spcm = snd_sof_find_spcm_dai (component , rtd );
50134 if (!spcm )
51135 return - EINVAL ;
52136
53137 list = spcm -> stream [substream -> stream ].list ;
54138
139+ pipeline_info .count = 0 ;
140+
141+ /* get the list of pipeline widgets that need to be triggered */
55142 for_each_dapm_widgets (list , num_widgets , widget ) {
56143 swidget = widget -> dobj .private ;
57144
58145 if (!swidget )
59146 continue ;
60147
61- /* find pipeline widget for the pipeline that this widget belongs to */
62- pipeline_widget = swidget -> pipe_widget ;
63- pipeline = pipeline_widget -> private ;
148+ /*
149+ * IPC4 requires pipelines to be triggered in order starting at the sink and
150+ * walking all the way to the source. So the starting widget for playback is of
151+ * DAI type and for capture, it is of AIF type.
152+ */
153+ if (substream -> stream == SNDRV_PCM_STREAM_PLAYBACK && !WIDGET_IS_DAI (widget -> id ))
154+ continue ;
64155
65- /* skip triggering backend pipelines */
66- if (pipeline -> is_backend || pipeline -> state == state )
156+ if (substream -> stream == SNDRV_PCM_STREAM_CAPTURE && !WIDGET_IS_AIF (widget -> id ))
67157 continue ;
68158
159+ ret = sof_ipc4_get_pipelines_in_order (sdev , widget , list , & pipeline_info );
160+ if (ret < 0 )
161+ return ret ;
162+ }
163+
164+ if (!pipeline_info .count )
165+ return ret ;
166+
167+ /* trigger a single pipeline if count is 1 */
168+ if (pipeline_info .count == 1 ) {
169+ pipeline_widget = pipeline_info .pipelines [0 ];
170+ pipeline = pipeline_widget -> private ;
171+
69172 /* first set the pipeline to PAUSED state */
70173 if (pipeline -> state != SOF_IPC4_PIPE_PAUSED ) {
71174 ret = sof_ipc4_set_pipeline_state (sdev , pipeline_widget -> instance_id ,
72175 SOF_IPC4_PIPE_PAUSED );
176+
73177 if (ret < 0 ) {
74178 dev_err (sdev -> dev , "failed to pause pipeline %d\n" ,
75- swidget -> pipeline_id );
179+ pipeline_widget -> pipeline_id );
76180 return ret ;
77181 }
78182 }
79183
80184 pipeline -> state = SOF_IPC4_PIPE_PAUSED ;
81185
82186 if (pipeline -> state == state )
83- continue ;
187+ return ret ;
188+
84189
85190 /* then set the final state */
86191 ret = sof_ipc4_set_pipeline_state (sdev , pipeline_widget -> instance_id , state );
87192 if (ret < 0 ) {
88- dev_err (sdev -> dev , "failed to set state %d for pipeline %d\n" ,
89- state , swidget -> pipeline_id );
90- break ;
193+ dev_err (sdev -> dev , "failed to set state %d pipeline %d\n" ,
194+ state , pipeline_widget -> pipeline_id );
195+ return ret ;
91196 }
92197
93198 pipeline -> state = state ;
199+ return ret ;
200+ }
201+
202+ /*
203+ * check if the pipelines are paused already.
204+ * It's enough to check the first pipeline's state
205+ */
206+ pipeline_widget = pipeline_info .pipelines [0 ];
207+ pipeline = pipeline_widget -> private ;
208+ if (pipeline -> state == SOF_IPC4_PIPE_PAUSED )
209+ goto out ;
210+
211+ /* pause all pipelines */
212+ ret = sof_ipc4_set_multi_pipeline_state (sdev , SOF_IPC4_PIPE_PAUSED , & pipeline_info );
213+ if (ret < 0 ) {
214+ dev_err (sdev -> dev , "failed to pause all pipelines\n" );
215+ return ret ;
216+ }
217+
218+ for (i = 0 ; i < pipeline_info .count ; i ++ ) {
219+ pipeline_widget = pipeline_info .pipelines [i ];
220+ pipeline = pipeline_widget -> private ;
221+ pipeline -> state = SOF_IPC4_PIPE_PAUSED ;
222+ }
223+
224+ out :
225+ /* check if the pipelines are in the final state already */
226+ pipeline_widget = pipeline_info .pipelines [0 ];
227+ pipeline = pipeline_widget -> private ;
228+ if (pipeline -> state == state )
229+ return ret ;
230+
231+ ret = sof_ipc4_set_multi_pipeline_state (sdev , state , & pipeline_info );
232+ if (ret < 0 ) {
233+ dev_err (sdev -> dev , "failed to set final state %d for all pipelines\n" , state );
234+ return ret ;
235+ }
236+
237+ for (i = 0 ; i < pipeline_info .count ; i ++ ) {
238+ pipeline_widget = pipeline_info .pipelines [i ];
239+ pipeline = pipeline_widget -> private ;
240+ pipeline -> state = state ;
94241 }
95242
96243 return ret ;
0 commit comments