Linux 6.7-rc7
[linux-modified.git] / sound / soc / sof / ipc3-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) 2021 Intel Corporation. All rights reserved.
7 //
8 //
9
10 #include <sound/pcm_params.h>
11 #include "ipc3-priv.h"
12 #include "ops.h"
13 #include "sof-priv.h"
14 #include "sof-audio.h"
15
16 static int sof_ipc3_pcm_hw_free(struct snd_soc_component *component,
17                                 struct snd_pcm_substream *substream)
18 {
19         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
20         struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
21         struct sof_ipc_stream stream;
22         struct snd_sof_pcm *spcm;
23
24         spcm = snd_sof_find_spcm_dai(component, rtd);
25         if (!spcm)
26                 return -EINVAL;
27
28         if (!spcm->prepared[substream->stream])
29                 return 0;
30
31         stream.hdr.size = sizeof(stream);
32         stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_FREE;
33         stream.comp_id = spcm->stream[substream->stream].comp_id;
34
35         /* send IPC to the DSP */
36         return sof_ipc_tx_message_no_reply(sdev->ipc, &stream, sizeof(stream));
37 }
38
39 static int sof_ipc3_pcm_hw_params(struct snd_soc_component *component,
40                                   struct snd_pcm_substream *substream,
41                                   struct snd_pcm_hw_params *params,
42                                   struct snd_sof_platform_stream_params *platform_params)
43 {
44         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
45         struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
46         struct sof_ipc_fw_version *v = &sdev->fw_ready.version;
47         struct snd_pcm_runtime *runtime = substream->runtime;
48         struct sof_ipc_pcm_params_reply ipc_params_reply;
49         struct sof_ipc_pcm_params pcm;
50         struct snd_sof_pcm *spcm;
51         int ret;
52
53         spcm = snd_sof_find_spcm_dai(component, rtd);
54         if (!spcm)
55                 return -EINVAL;
56
57         memset(&pcm, 0, sizeof(pcm));
58
59         /* number of pages should be rounded up */
60         pcm.params.buffer.pages = PFN_UP(runtime->dma_bytes);
61
62         /* set IPC PCM parameters */
63         pcm.hdr.size = sizeof(pcm);
64         pcm.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_PARAMS;
65         pcm.comp_id = spcm->stream[substream->stream].comp_id;
66         pcm.params.hdr.size = sizeof(pcm.params);
67         pcm.params.buffer.phy_addr = spcm->stream[substream->stream].page_table.addr;
68         pcm.params.buffer.size = runtime->dma_bytes;
69         pcm.params.direction = substream->stream;
70         pcm.params.sample_valid_bytes = params_width(params) >> 3;
71         pcm.params.buffer_fmt = SOF_IPC_BUFFER_INTERLEAVED;
72         pcm.params.rate = params_rate(params);
73         pcm.params.channels = params_channels(params);
74         pcm.params.host_period_bytes = params_period_bytes(params);
75
76         /* container size */
77         ret = snd_pcm_format_physical_width(params_format(params));
78         if (ret < 0)
79                 return ret;
80         pcm.params.sample_container_bytes = ret >> 3;
81
82         /* format */
83         switch (params_format(params)) {
84         case SNDRV_PCM_FORMAT_S16:
85                 pcm.params.frame_fmt = SOF_IPC_FRAME_S16_LE;
86                 break;
87         case SNDRV_PCM_FORMAT_S24:
88                 pcm.params.frame_fmt = SOF_IPC_FRAME_S24_4LE;
89                 break;
90         case SNDRV_PCM_FORMAT_S32:
91                 pcm.params.frame_fmt = SOF_IPC_FRAME_S32_LE;
92                 break;
93         case SNDRV_PCM_FORMAT_FLOAT:
94                 pcm.params.frame_fmt = SOF_IPC_FRAME_FLOAT;
95                 break;
96         default:
97                 return -EINVAL;
98         }
99
100         /* Update the IPC message with information from the platform */
101         pcm.params.stream_tag = platform_params->stream_tag;
102
103         if (platform_params->use_phy_address)
104                 pcm.params.buffer.phy_addr = platform_params->phy_addr;
105
106         if (platform_params->no_ipc_position) {
107                 /* For older ABIs set host_period_bytes to zero to inform
108                  * FW we don't want position updates. Newer versions use
109                  * no_stream_position for this purpose.
110                  */
111                 if (v->abi_version < SOF_ABI_VER(3, 10, 0))
112                         pcm.params.host_period_bytes = 0;
113                 else
114                         pcm.params.no_stream_position = 1;
115         }
116
117         if (platform_params->cont_update_posn)
118                 pcm.params.cont_update_posn = 1;
119
120         dev_dbg(component->dev, "stream_tag %d", pcm.params.stream_tag);
121
122         /* send hw_params IPC to the DSP */
123         ret = sof_ipc_tx_message(sdev->ipc, &pcm, sizeof(pcm),
124                                  &ipc_params_reply, sizeof(ipc_params_reply));
125         if (ret < 0) {
126                 dev_err(component->dev, "HW params ipc failed for stream %d\n",
127                         pcm.params.stream_tag);
128                 return ret;
129         }
130
131         ret = snd_sof_set_stream_data_offset(sdev, &spcm->stream[substream->stream],
132                                              ipc_params_reply.posn_offset);
133         if (ret < 0) {
134                 dev_err(component->dev, "%s: invalid stream data offset for PCM %d\n",
135                         __func__, spcm->pcm.pcm_id);
136                 return ret;
137         }
138
139         return ret;
140 }
141
142 static int sof_ipc3_pcm_trigger(struct snd_soc_component *component,
143                                 struct snd_pcm_substream *substream, int cmd)
144 {
145         struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
146         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
147         struct sof_ipc_stream stream;
148         struct snd_sof_pcm *spcm;
149
150         spcm = snd_sof_find_spcm_dai(component, rtd);
151         if (!spcm)
152                 return -EINVAL;
153
154         stream.hdr.size = sizeof(stream);
155         stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG;
156         stream.comp_id = spcm->stream[substream->stream].comp_id;
157
158         switch (cmd) {
159         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
160                 stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_PAUSE;
161                 break;
162         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
163                 stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_RELEASE;
164                 break;
165         case SNDRV_PCM_TRIGGER_START:
166                 stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_START;
167                 break;
168         case SNDRV_PCM_TRIGGER_SUSPEND:
169                 fallthrough;
170         case SNDRV_PCM_TRIGGER_STOP:
171                 stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_STOP;
172                 break;
173         default:
174                 dev_err(component->dev, "Unhandled trigger cmd %d\n", cmd);
175                 return -EINVAL;
176         }
177
178         /* send IPC to the DSP */
179         return sof_ipc_tx_message_no_reply(sdev->ipc, &stream, sizeof(stream));
180 }
181
182 static void ssp_dai_config_pcm_params_match(struct snd_sof_dev *sdev, const char *link_name,
183                                             struct snd_pcm_hw_params *params)
184 {
185         struct sof_ipc_dai_config *config;
186         struct snd_sof_dai *dai;
187         int i;
188
189         /*
190          * Search for all matching DAIs as we can have both playback and capture DAI
191          * associated with the same link.
192          */
193         list_for_each_entry(dai, &sdev->dai_list, list) {
194                 if (!dai->name || strcmp(link_name, dai->name))
195                         continue;
196                 for (i = 0; i < dai->number_configs; i++) {
197                         struct sof_dai_private_data *private = dai->private;
198
199                         config = &private->dai_config[i];
200                         if (config->ssp.fsync_rate == params_rate(params)) {
201                                 dev_dbg(sdev->dev, "DAI config %d matches pcm hw params\n", i);
202                                 dai->current_config = i;
203                                 break;
204                         }
205                 }
206         }
207 }
208
209 static int sof_ipc3_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
210                                        struct snd_pcm_hw_params *params)
211 {
212         struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME);
213         struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
214         struct snd_sof_dai *dai = snd_sof_find_dai(component, (char *)rtd->dai_link->name);
215         struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
216         struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
217         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
218         struct sof_dai_private_data *private;
219         struct snd_soc_dpcm *dpcm;
220
221         if (!dai) {
222                 dev_err(component->dev, "%s: No DAI found with name %s\n", __func__,
223                         rtd->dai_link->name);
224                 return -EINVAL;
225         }
226
227         private = dai->private;
228         if (!private) {
229                 dev_err(component->dev, "%s: No private data found for DAI %s\n", __func__,
230                         rtd->dai_link->name);
231                 return -EINVAL;
232         }
233
234         /* read format from topology */
235         snd_mask_none(fmt);
236
237         switch (private->comp_dai->config.frame_fmt) {
238         case SOF_IPC_FRAME_S16_LE:
239                 snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
240                 break;
241         case SOF_IPC_FRAME_S24_4LE:
242                 snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
243                 break;
244         case SOF_IPC_FRAME_S32_LE:
245                 snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE);
246                 break;
247         default:
248                 dev_err(component->dev, "No available DAI format!\n");
249                 return -EINVAL;
250         }
251
252         /* read rate and channels from topology */
253         switch (private->dai_config->type) {
254         case SOF_DAI_INTEL_SSP:
255                 /* search for config to pcm params match, if not found use default */
256                 ssp_dai_config_pcm_params_match(sdev, (char *)rtd->dai_link->name, params);
257
258                 rate->min = private->dai_config[dai->current_config].ssp.fsync_rate;
259                 rate->max = private->dai_config[dai->current_config].ssp.fsync_rate;
260                 channels->min = private->dai_config[dai->current_config].ssp.tdm_slots;
261                 channels->max = private->dai_config[dai->current_config].ssp.tdm_slots;
262
263                 dev_dbg(component->dev, "rate_min: %d rate_max: %d\n", rate->min, rate->max);
264                 dev_dbg(component->dev, "channels_min: %d channels_max: %d\n",
265                         channels->min, channels->max);
266
267                 break;
268         case SOF_DAI_INTEL_DMIC:
269                 /* DMIC only supports 16 or 32 bit formats */
270                 if (private->comp_dai->config.frame_fmt == SOF_IPC_FRAME_S24_4LE) {
271                         dev_err(component->dev, "Invalid fmt %d for DAI type %d\n",
272                                 private->comp_dai->config.frame_fmt,
273                                 private->dai_config->type);
274                 }
275                 break;
276         case SOF_DAI_INTEL_HDA:
277                 /*
278                  * HDAudio does not follow the default trigger
279                  * sequence due to firmware implementation
280                  */
281                 for_each_dpcm_fe(rtd, SNDRV_PCM_STREAM_PLAYBACK, dpcm) {
282                         struct snd_soc_pcm_runtime *fe = dpcm->fe;
283
284                         fe->dai_link->trigger[SNDRV_PCM_STREAM_PLAYBACK] =
285                                 SND_SOC_DPCM_TRIGGER_POST;
286                 }
287                 break;
288         case SOF_DAI_INTEL_ALH:
289                 /*
290                  * Dai could run with different channel count compared with
291                  * front end, so get dai channel count from topology
292                  */
293                 channels->min = private->dai_config->alh.channels;
294                 channels->max = private->dai_config->alh.channels;
295                 break;
296         case SOF_DAI_IMX_ESAI:
297                 rate->min = private->dai_config->esai.fsync_rate;
298                 rate->max = private->dai_config->esai.fsync_rate;
299                 channels->min = private->dai_config->esai.tdm_slots;
300                 channels->max = private->dai_config->esai.tdm_slots;
301
302                 dev_dbg(component->dev, "rate_min: %d rate_max: %d\n", rate->min, rate->max);
303                 dev_dbg(component->dev, "channels_min: %d channels_max: %d\n",
304                         channels->min, channels->max);
305                 break;
306         case SOF_DAI_MEDIATEK_AFE:
307                 rate->min = private->dai_config->afe.rate;
308                 rate->max = private->dai_config->afe.rate;
309                 channels->min = private->dai_config->afe.channels;
310                 channels->max = private->dai_config->afe.channels;
311
312                 snd_mask_none(fmt);
313
314                 switch (private->dai_config->afe.format) {
315                 case SOF_IPC_FRAME_S16_LE:
316                         snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
317                         break;
318                 case SOF_IPC_FRAME_S24_4LE:
319                         snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
320                         break;
321                 case SOF_IPC_FRAME_S32_LE:
322                         snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE);
323                         break;
324                 default:
325                         dev_err(component->dev, "Not available format!\n");
326                         return -EINVAL;
327                 }
328
329                 dev_dbg(component->dev, "rate_min: %d rate_max: %d\n", rate->min, rate->max);
330                 dev_dbg(component->dev, "channels_min: %d channels_max: %d\n",
331                         channels->min, channels->max);
332                 break;
333         case SOF_DAI_IMX_SAI:
334                 rate->min = private->dai_config->sai.fsync_rate;
335                 rate->max = private->dai_config->sai.fsync_rate;
336                 channels->min = private->dai_config->sai.tdm_slots;
337                 channels->max = private->dai_config->sai.tdm_slots;
338
339                 dev_dbg(component->dev, "rate_min: %d rate_max: %d\n", rate->min, rate->max);
340                 dev_dbg(component->dev, "channels_min: %d channels_max: %d\n",
341                         channels->min, channels->max);
342                 break;
343         case SOF_DAI_AMD_BT:
344                 rate->min = private->dai_config->acpbt.fsync_rate;
345                 rate->max = private->dai_config->acpbt.fsync_rate;
346                 channels->min = private->dai_config->acpbt.tdm_slots;
347                 channels->max = private->dai_config->acpbt.tdm_slots;
348
349                 dev_dbg(component->dev,
350                         "AMD_BT rate_min: %d rate_max: %d\n", rate->min, rate->max);
351                 dev_dbg(component->dev, "AMD_BT channels_min: %d channels_max: %d\n",
352                         channels->min, channels->max);
353                 break;
354         case SOF_DAI_AMD_SP:
355         case SOF_DAI_AMD_SP_VIRTUAL:
356                 rate->min = private->dai_config->acpsp.fsync_rate;
357                 rate->max = private->dai_config->acpsp.fsync_rate;
358                 channels->min = private->dai_config->acpsp.tdm_slots;
359                 channels->max = private->dai_config->acpsp.tdm_slots;
360
361                 dev_dbg(component->dev,
362                         "AMD_SP rate_min: %d rate_max: %d\n", rate->min, rate->max);
363                 dev_dbg(component->dev, "AMD_SP channels_min: %d channels_max: %d\n",
364                         channels->min, channels->max);
365                 break;
366         case SOF_DAI_AMD_HS:
367         case SOF_DAI_AMD_HS_VIRTUAL:
368                 rate->min = private->dai_config->acphs.fsync_rate;
369                 rate->max = private->dai_config->acphs.fsync_rate;
370                 channels->min = private->dai_config->acphs.tdm_slots;
371                 channels->max = private->dai_config->acphs.tdm_slots;
372
373                 dev_dbg(component->dev,
374                         "AMD_HS channel_max: %d rate_max: %d\n", channels->max, rate->max);
375                 break;
376         case SOF_DAI_AMD_DMIC:
377                 rate->min = private->dai_config->acpdmic.pdm_rate;
378                 rate->max = private->dai_config->acpdmic.pdm_rate;
379                 channels->min = private->dai_config->acpdmic.pdm_ch;
380                 channels->max = private->dai_config->acpdmic.pdm_ch;
381
382                 dev_dbg(component->dev,
383                         "AMD_DMIC rate_min: %d rate_max: %d\n", rate->min, rate->max);
384                 dev_dbg(component->dev, "AMD_DMIC channels_min: %d channels_max: %d\n",
385                         channels->min, channels->max);
386                 break;
387         default:
388                 dev_err(component->dev, "Invalid DAI type %d\n", private->dai_config->type);
389                 break;
390         }
391
392         return 0;
393 }
394
395 const struct sof_ipc_pcm_ops ipc3_pcm_ops = {
396         .hw_params = sof_ipc3_pcm_hw_params,
397         .hw_free = sof_ipc3_pcm_hw_free,
398         .trigger = sof_ipc3_pcm_trigger,
399         .dai_link_fixup = sof_ipc3_pcm_dai_link_fixup,
400         .reset_hw_params_during_stop = true,
401 };