ASoC: SOF: ipc4-pcm: Do not run the trigger pipelines if no spipe is stored
[platform/kernel/linux-rpi.git] / sound / soc / sof / ipc4-pcm.c
1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
2 //
3 // This file is provided under a dual BSD/GPLv2 license.  When using or
4 // redistributing this file, you may do so under either license.
5 //
6 // Copyright(c) 2022 Intel Corporation. All rights reserved.
7 //
8
9 #include <sound/pcm_params.h>
10 #include <sound/sof/ipc4/header.h>
11 #include "sof-audio.h"
12 #include "sof-priv.h"
13 #include "ipc4-priv.h"
14 #include "ipc4-topology.h"
15
16 static int sof_ipc4_set_multi_pipeline_state(struct snd_sof_dev *sdev, u32 state,
17                                              struct ipc4_pipeline_set_state_data *trigger_list)
18 {
19         struct sof_ipc4_msg msg = {{ 0 }};
20         u32 primary, ipc_size;
21
22         /* trigger a single pipeline */
23         if (trigger_list->count == 1)
24                 return sof_ipc4_set_pipeline_state(sdev, trigger_list->pipeline_ids[0], state);
25
26         primary = state;
27         primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_SET_PIPELINE_STATE);
28         primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
29         primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG);
30         msg.primary = primary;
31
32         /* trigger multiple pipelines with a single IPC */
33         msg.extension = SOF_IPC4_GLB_PIPE_STATE_EXT_MULTI;
34
35         /* ipc_size includes the count and the pipeline IDs for the number of pipelines */
36         ipc_size = sizeof(u32) * (trigger_list->count + 1);
37         msg.data_size = ipc_size;
38         msg.data_ptr = trigger_list;
39
40         return sof_ipc_tx_message(sdev->ipc, &msg, ipc_size, NULL, 0);
41 }
42
43 int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 id, u32 state)
44 {
45         struct sof_ipc4_msg msg = {{ 0 }};
46         u32 primary;
47
48         dev_dbg(sdev->dev, "ipc4 set pipeline %d state %d", id, state);
49
50         primary = state;
51         primary |= SOF_IPC4_GLB_PIPE_STATE_ID(id);
52         primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_SET_PIPELINE_STATE);
53         primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
54         primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG);
55
56         msg.primary = primary;
57
58         return sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0);
59 }
60 EXPORT_SYMBOL(sof_ipc4_set_pipeline_state);
61
62 static void
63 sof_ipc4_add_pipeline_to_trigger_list(struct snd_sof_dev *sdev, int state,
64                                       struct snd_sof_pipeline *spipe,
65                                       struct ipc4_pipeline_set_state_data *trigger_list)
66 {
67         struct snd_sof_widget *pipe_widget = spipe->pipe_widget;
68         struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
69
70         if (pipeline->skip_during_fe_trigger)
71                 return;
72
73         switch (state) {
74         case SOF_IPC4_PIPE_RUNNING:
75                 /*
76                  * Trigger pipeline if all PCMs containing it are paused or if it is RUNNING
77                  * for the first time
78                  */
79                 if (spipe->started_count == spipe->paused_count)
80                         trigger_list->pipeline_ids[trigger_list->count++] =
81                                 pipe_widget->instance_id;
82                 break;
83         case SOF_IPC4_PIPE_RESET:
84                 /* RESET if the pipeline is neither running nor paused */
85                 if (!spipe->started_count && !spipe->paused_count)
86                         trigger_list->pipeline_ids[trigger_list->count++] =
87                                 pipe_widget->instance_id;
88                 break;
89         case SOF_IPC4_PIPE_PAUSED:
90                 /* Pause the pipeline only when its started_count is 1 more than paused_count */
91                 if (spipe->paused_count == (spipe->started_count - 1))
92                         trigger_list->pipeline_ids[trigger_list->count++] =
93                                 pipe_widget->instance_id;
94                 break;
95         default:
96                 break;
97         }
98 }
99
100 static void
101 sof_ipc4_update_pipeline_state(struct snd_sof_dev *sdev, int state, int cmd,
102                                struct snd_sof_pipeline *spipe,
103                                struct ipc4_pipeline_set_state_data *trigger_list)
104 {
105         struct snd_sof_widget *pipe_widget = spipe->pipe_widget;
106         struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
107         int i;
108
109         if (pipeline->skip_during_fe_trigger)
110                 return;
111
112         /* set state for pipeline if it was just triggered */
113         for (i = 0; i < trigger_list->count; i++) {
114                 if (trigger_list->pipeline_ids[i] == pipe_widget->instance_id) {
115                         pipeline->state = state;
116                         break;
117                 }
118         }
119
120         switch (state) {
121         case SOF_IPC4_PIPE_PAUSED:
122                 switch (cmd) {
123                 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
124                         /*
125                          * increment paused_count if the PAUSED is the final state during
126                          * the PAUSE trigger
127                          */
128                         spipe->paused_count++;
129                         break;
130                 case SNDRV_PCM_TRIGGER_STOP:
131                 case SNDRV_PCM_TRIGGER_SUSPEND:
132                         /*
133                          * decrement started_count if PAUSED is the final state during the
134                          * STOP trigger
135                          */
136                         spipe->started_count--;
137                         break;
138                 default:
139                         break;
140                 }
141                 break;
142         case SOF_IPC4_PIPE_RUNNING:
143                 switch (cmd) {
144                 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
145                         /* decrement paused_count for RELEASE */
146                         spipe->paused_count--;
147                         break;
148                 case SNDRV_PCM_TRIGGER_START:
149                 case SNDRV_PCM_TRIGGER_RESUME:
150                         /* increment started_count for START/RESUME */
151                         spipe->started_count++;
152                         break;
153                 default:
154                         break;
155                 }
156                 break;
157         default:
158                 break;
159         }
160 }
161
162 /*
163  * The picture below represents the pipeline state machine wrt PCM actions corresponding to the
164  * triggers and ioctls
165  *                              +---------------+
166  *                              |               |
167  *                              |    INIT       |
168  *                              |               |
169  *                              +-------+-------+
170  *                                      |
171  *                                      |
172  *                                      | START
173  *                                      |
174  *                                      |
175  * +----------------+              +------v-------+               +-------------+
176  * |                |   START     |              |   HW_FREE      |             |
177  * |   RUNNING      <-------------+  PAUSED      +--------------> +   RESET     |
178  * |                |   PAUSE     |              |                |             |
179  * +------+---------+   RELEASE   +---------+----+                +-------------+
180  *        |                                  ^
181  *        |                                  |
182  *        |                                  |
183  *        |                                  |
184  *        |             PAUSE                |
185  *        +---------------------------------+
186  *                      STOP/SUSPEND
187  *
188  * Note that during system suspend, the suspend trigger is followed by a hw_free in
189  * sof_pcm_trigger(). So, the final state during suspend would be RESET.
190  * Also, since the SOF driver doesn't support full resume, streams would be restarted with the
191  * prepare ioctl before the START trigger.
192  */
193
194 static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,
195                                       struct snd_pcm_substream *substream, int state, int cmd)
196 {
197         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
198         struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
199         struct snd_sof_pcm_stream_pipeline_list *pipeline_list;
200         struct sof_ipc4_fw_data *ipc4_data = sdev->private;
201         struct ipc4_pipeline_set_state_data *trigger_list;
202         struct snd_sof_pipeline *spipe;
203         struct snd_sof_pcm *spcm;
204         int ret;
205         int i;
206
207         dev_dbg(sdev->dev, "trigger cmd: %d state: %d\n", cmd, state);
208
209         spcm = snd_sof_find_spcm_dai(component, rtd);
210         if (!spcm)
211                 return -EINVAL;
212
213         pipeline_list = &spcm->stream[substream->stream].pipeline_list;
214
215         /* nothing to trigger if the list is empty */
216         if (!pipeline_list->pipelines || !pipeline_list->count)
217                 return 0;
218
219         /* allocate memory for the pipeline data */
220         trigger_list = kzalloc(struct_size(trigger_list, pipeline_ids, pipeline_list->count),
221                                GFP_KERNEL);
222         if (!trigger_list)
223                 return -ENOMEM;
224
225         mutex_lock(&ipc4_data->pipeline_state_mutex);
226
227         /*
228          * IPC4 requires pipelines to be triggered in order starting at the sink and
229          * walking all the way to the source. So traverse the pipeline_list in the order
230          * sink->source when starting PCM's and in the reverse order to pause/stop PCM's.
231          * Skip the pipelines that have their skip_during_fe_trigger flag set. If there is a fork
232          * in the pipeline, the order of triggering between the left/right paths will be
233          * indeterministic. But the sink->source trigger order sink->source would still be
234          * guaranteed for each fork independently.
235          */
236         if (state == SOF_IPC4_PIPE_RUNNING || state == SOF_IPC4_PIPE_RESET)
237                 for (i = pipeline_list->count - 1; i >= 0; i--) {
238                         spipe = pipeline_list->pipelines[i];
239                         sof_ipc4_add_pipeline_to_trigger_list(sdev, state, spipe, trigger_list);
240                 }
241         else
242                 for (i = 0; i < pipeline_list->count; i++) {
243                         spipe = pipeline_list->pipelines[i];
244                         sof_ipc4_add_pipeline_to_trigger_list(sdev, state, spipe, trigger_list);
245                 }
246
247         /* return if all pipelines are in the requested state already */
248         if (!trigger_list->count) {
249                 ret = 0;
250                 goto free;
251         }
252
253         /* no need to pause before reset or before pause release */
254         if (state == SOF_IPC4_PIPE_RESET || cmd == SNDRV_PCM_TRIGGER_PAUSE_RELEASE)
255                 goto skip_pause_transition;
256
257         /*
258          * set paused state for pipelines if the final state is PAUSED or when the pipeline
259          * is set to RUNNING for the first time after the PCM is started.
260          */
261         ret = sof_ipc4_set_multi_pipeline_state(sdev, SOF_IPC4_PIPE_PAUSED, trigger_list);
262         if (ret < 0) {
263                 dev_err(sdev->dev, "failed to pause all pipelines\n");
264                 goto free;
265         }
266
267         /* update PAUSED state for all pipelines just triggered */
268         for (i = 0; i < pipeline_list->count ; i++) {
269                 spipe = pipeline_list->pipelines[i];
270                 sof_ipc4_update_pipeline_state(sdev, SOF_IPC4_PIPE_PAUSED, cmd, spipe,
271                                                trigger_list);
272         }
273
274         /* return if this is the final state */
275         if (state == SOF_IPC4_PIPE_PAUSED)
276                 goto free;
277 skip_pause_transition:
278         /* else set the RUNNING/RESET state in the DSP */
279         ret = sof_ipc4_set_multi_pipeline_state(sdev, state, trigger_list);
280         if (ret < 0) {
281                 dev_err(sdev->dev, "failed to set final state %d for all pipelines\n", state);
282                 goto free;
283         }
284
285         /* update RUNNING/RESET state for all pipelines that were just triggered */
286         for (i = 0; i < pipeline_list->count; i++) {
287                 spipe = pipeline_list->pipelines[i];
288                 sof_ipc4_update_pipeline_state(sdev, state, cmd, spipe, trigger_list);
289         }
290
291 free:
292         mutex_unlock(&ipc4_data->pipeline_state_mutex);
293         kfree(trigger_list);
294         return ret;
295 }
296
297 static int sof_ipc4_pcm_trigger(struct snd_soc_component *component,
298                                 struct snd_pcm_substream *substream, int cmd)
299 {
300         int state;
301
302         /* determine the pipeline state */
303         switch (cmd) {
304         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
305                 state = SOF_IPC4_PIPE_PAUSED;
306                 break;
307         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
308         case SNDRV_PCM_TRIGGER_RESUME:
309         case SNDRV_PCM_TRIGGER_START:
310                 state = SOF_IPC4_PIPE_RUNNING;
311                 break;
312         case SNDRV_PCM_TRIGGER_SUSPEND:
313         case SNDRV_PCM_TRIGGER_STOP:
314                 state = SOF_IPC4_PIPE_PAUSED;
315                 break;
316         default:
317                 dev_err(component->dev, "%s: unhandled trigger cmd %d\n", __func__, cmd);
318                 return -EINVAL;
319         }
320
321         /* set the pipeline state */
322         return sof_ipc4_trigger_pipelines(component, substream, state, cmd);
323 }
324
325 static int sof_ipc4_pcm_hw_free(struct snd_soc_component *component,
326                                 struct snd_pcm_substream *substream)
327 {
328         /* command is not relevant with RESET, so just pass 0 */
329         return sof_ipc4_trigger_pipelines(component, substream, SOF_IPC4_PIPE_RESET, 0);
330 }
331
332 static void ipc4_ssp_dai_config_pcm_params_match(struct snd_sof_dev *sdev, const char *link_name,
333                                                  struct snd_pcm_hw_params *params)
334 {
335         struct snd_sof_dai_link *slink;
336         struct snd_sof_dai *dai;
337         bool dai_link_found = false;
338         int i;
339
340         list_for_each_entry(slink, &sdev->dai_link_list, list) {
341                 if (!strcmp(slink->link->name, link_name)) {
342                         dai_link_found = true;
343                         break;
344                 }
345         }
346
347         if (!dai_link_found)
348                 return;
349
350         for (i = 0; i < slink->num_hw_configs; i++) {
351                 struct snd_soc_tplg_hw_config *hw_config = &slink->hw_configs[i];
352
353                 if (params_rate(params) == le32_to_cpu(hw_config->fsync_rate)) {
354                         /* set current config for all DAI's with matching name */
355                         list_for_each_entry(dai, &sdev->dai_list, list)
356                                 if (!strcmp(slink->link->name, dai->name))
357                                         dai->current_config = le32_to_cpu(hw_config->id);
358                         break;
359                 }
360         }
361 }
362
363 static int sof_ipc4_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
364                                        struct snd_pcm_hw_params *params)
365 {
366         struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME);
367         struct snd_sof_dai *dai = snd_sof_find_dai(component, rtd->dai_link->name);
368         struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
369         struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
370         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
371         struct sof_ipc4_copier *ipc4_copier;
372
373         if (!dai) {
374                 dev_err(component->dev, "%s: No DAI found with name %s\n", __func__,
375                         rtd->dai_link->name);
376                 return -EINVAL;
377         }
378
379         ipc4_copier = dai->private;
380         if (!ipc4_copier) {
381                 dev_err(component->dev, "%s: No private data found for DAI %s\n",
382                         __func__, rtd->dai_link->name);
383                 return -EINVAL;
384         }
385
386         /* always set BE format to 32-bits for both playback and capture */
387         snd_mask_none(fmt);
388         snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE);
389
390         rate->min = ipc4_copier->available_fmt.base_config->audio_fmt.sampling_frequency;
391         rate->max = rate->min;
392
393         switch (ipc4_copier->dai_type) {
394         case SOF_DAI_INTEL_SSP:
395                 ipc4_ssp_dai_config_pcm_params_match(sdev, (char *)rtd->dai_link->name, params);
396                 break;
397         default:
398                 break;
399         }
400
401         return 0;
402 }
403
404 static void sof_ipc4_pcm_free(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm)
405 {
406         struct snd_sof_pcm_stream_pipeline_list *pipeline_list;
407         int stream;
408
409         for_each_pcm_streams(stream) {
410                 pipeline_list = &spcm->stream[stream].pipeline_list;
411                 kfree(pipeline_list->pipelines);
412                 pipeline_list->pipelines = NULL;
413         }
414 }
415
416 static int sof_ipc4_pcm_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm)
417 {
418         struct snd_sof_pcm_stream_pipeline_list *pipeline_list;
419         struct sof_ipc4_fw_data *ipc4_data = sdev->private;
420         int stream;
421
422         for_each_pcm_streams(stream) {
423                 pipeline_list = &spcm->stream[stream].pipeline_list;
424
425                 /* allocate memory for max number of pipeline IDs */
426                 pipeline_list->pipelines = kcalloc(ipc4_data->max_num_pipelines,
427                                                    sizeof(struct snd_sof_widget *), GFP_KERNEL);
428                 if (!pipeline_list->pipelines) {
429                         sof_ipc4_pcm_free(sdev, spcm);
430                         return -ENOMEM;
431                 }
432         }
433
434         return 0;
435 }
436
437 const struct sof_ipc_pcm_ops ipc4_pcm_ops = {
438         .trigger = sof_ipc4_pcm_trigger,
439         .hw_free = sof_ipc4_pcm_hw_free,
440         .dai_link_fixup = sof_ipc4_pcm_dai_link_fixup,
441         .pcm_setup = sof_ipc4_pcm_setup,
442         .pcm_free = sof_ipc4_pcm_free,
443 };