1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
5 // Author: Daniel Baluta <daniel.baluta@nxp.com>
9 #include <sound/compress_driver.h>
10 #include "sof-audio.h"
12 #include "sof-utils.h"
15 static void sof_set_transferred_bytes(struct sof_compr_stream
*sstream
,
16 u64 host_pos
, u64 buffer_size
)
21 div64_u64_rem(sstream
->copied_total
, buffer_size
, &prev_pos
);
23 if (host_pos
< prev_pos
)
24 copied
= (buffer_size
- prev_pos
) + host_pos
;
26 copied
= host_pos
- prev_pos
;
28 sstream
->copied_total
+= copied
;
31 static void snd_sof_compr_fragment_elapsed_work(struct work_struct
*work
)
33 struct snd_sof_pcm_stream
*sps
=
34 container_of(work
, struct snd_sof_pcm_stream
,
37 snd_compr_fragment_elapsed(sps
->cstream
);
40 void snd_sof_compr_init_elapsed_work(struct work_struct
*work
)
42 INIT_WORK(work
, snd_sof_compr_fragment_elapsed_work
);
46 * sof compr fragment elapse, this could be called in irq thread context
48 void snd_sof_compr_fragment_elapsed(struct snd_compr_stream
*cstream
)
50 struct snd_soc_pcm_runtime
*rtd
;
51 struct snd_compr_runtime
*crtd
;
52 struct snd_soc_component
*component
;
53 struct sof_compr_stream
*sstream
;
54 struct snd_sof_pcm
*spcm
;
59 rtd
= cstream
->private_data
;
60 crtd
= cstream
->runtime
;
61 sstream
= crtd
->private_data
;
62 component
= snd_soc_rtdcom_lookup(rtd
, SOF_AUDIO_PCM_DRV_NAME
);
64 spcm
= snd_sof_find_spcm_dai(component
, rtd
);
66 dev_err(component
->dev
,
67 "fragment elapsed called for unknown stream!\n");
71 sof_set_transferred_bytes(sstream
, spcm
->stream
[cstream
->direction
].posn
.host_posn
,
74 /* use the same workqueue-based solution as for PCM, cf. snd_sof_pcm_elapsed */
75 schedule_work(&spcm
->stream
[cstream
->direction
].period_elapsed_work
);
78 static int create_page_table(struct snd_soc_component
*component
,
79 struct snd_compr_stream
*cstream
,
80 unsigned char *dma_area
, size_t size
)
82 struct snd_dma_buffer
*dmab
= cstream
->runtime
->dma_buffer_p
;
83 struct snd_soc_pcm_runtime
*rtd
= cstream
->private_data
;
84 int dir
= cstream
->direction
;
85 struct snd_sof_pcm
*spcm
;
87 spcm
= snd_sof_find_spcm_dai(component
, rtd
);
91 return snd_sof_create_page_table(component
->dev
, dmab
,
92 spcm
->stream
[dir
].page_table
.area
, size
);
95 static int sof_compr_open(struct snd_soc_component
*component
,
96 struct snd_compr_stream
*cstream
)
98 struct snd_soc_pcm_runtime
*rtd
= cstream
->private_data
;
99 struct snd_compr_runtime
*crtd
= cstream
->runtime
;
100 struct sof_compr_stream
*sstream
;
101 struct snd_sof_pcm
*spcm
;
104 sstream
= kzalloc(sizeof(*sstream
), GFP_KERNEL
);
108 spcm
= snd_sof_find_spcm_dai(component
, rtd
);
114 dir
= cstream
->direction
;
116 if (spcm
->stream
[dir
].cstream
) {
121 spcm
->stream
[dir
].cstream
= cstream
;
122 spcm
->stream
[dir
].posn
.host_posn
= 0;
123 spcm
->stream
[dir
].posn
.dai_posn
= 0;
124 spcm
->prepared
[dir
] = false;
126 crtd
->private_data
= sstream
;
131 static int sof_compr_free(struct snd_soc_component
*component
,
132 struct snd_compr_stream
*cstream
)
134 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(component
);
135 struct sof_compr_stream
*sstream
= cstream
->runtime
->private_data
;
136 struct snd_soc_pcm_runtime
*rtd
= cstream
->private_data
;
137 struct sof_ipc_stream stream
;
138 struct snd_sof_pcm
*spcm
;
141 spcm
= snd_sof_find_spcm_dai(component
, rtd
);
145 stream
.hdr
.size
= sizeof(stream
);
146 stream
.hdr
.cmd
= SOF_IPC_GLB_STREAM_MSG
| SOF_IPC_STREAM_PCM_FREE
;
147 stream
.comp_id
= spcm
->stream
[cstream
->direction
].comp_id
;
149 if (spcm
->prepared
[cstream
->direction
]) {
150 ret
= sof_ipc_tx_message_no_reply(sdev
->ipc
, &stream
, sizeof(stream
));
152 spcm
->prepared
[cstream
->direction
] = false;
155 cancel_work_sync(&spcm
->stream
[cstream
->direction
].period_elapsed_work
);
156 spcm
->stream
[cstream
->direction
].cstream
= NULL
;
162 static int sof_compr_set_params(struct snd_soc_component
*component
,
163 struct snd_compr_stream
*cstream
, struct snd_compr_params
*params
)
165 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(component
);
166 struct snd_soc_pcm_runtime
*rtd
= cstream
->private_data
;
167 struct snd_compr_runtime
*crtd
= cstream
->runtime
;
168 struct sof_ipc_pcm_params_reply ipc_params_reply
;
169 struct sof_ipc_fw_ready
*ready
= &sdev
->fw_ready
;
170 struct sof_ipc_fw_version
*v
= &ready
->version
;
171 struct sof_compr_stream
*sstream
;
172 struct sof_ipc_pcm_params
*pcm
;
173 struct snd_sof_pcm
*spcm
;
174 size_t ext_data_size
;
177 if (v
->abi_version
< SOF_ABI_VER(3, 22, 0)) {
178 dev_err(component
->dev
,
179 "Compress params not supported with FW ABI version %d:%d:%d\n",
180 SOF_ABI_VERSION_MAJOR(v
->abi_version
),
181 SOF_ABI_VERSION_MINOR(v
->abi_version
),
182 SOF_ABI_VERSION_PATCH(v
->abi_version
));
186 sstream
= crtd
->private_data
;
188 spcm
= snd_sof_find_spcm_dai(component
, rtd
);
193 ext_data_size
= sizeof(params
->codec
);
195 if (sizeof(*pcm
) + ext_data_size
> sdev
->ipc
->max_payload_size
)
198 pcm
= kzalloc(sizeof(*pcm
) + ext_data_size
, GFP_KERNEL
);
202 cstream
->dma_buffer
.dev
.type
= SNDRV_DMA_TYPE_DEV_SG
;
203 cstream
->dma_buffer
.dev
.dev
= sdev
->dev
;
204 ret
= snd_compr_malloc_pages(cstream
, crtd
->buffer_size
);
208 ret
= create_page_table(component
, cstream
, crtd
->dma_area
, crtd
->dma_bytes
);
212 pcm
->params
.buffer
.pages
= PFN_UP(crtd
->dma_bytes
);
213 pcm
->hdr
.size
= sizeof(*pcm
) + ext_data_size
;
214 pcm
->hdr
.cmd
= SOF_IPC_GLB_STREAM_MSG
| SOF_IPC_STREAM_PCM_PARAMS
;
216 pcm
->comp_id
= spcm
->stream
[cstream
->direction
].comp_id
;
217 pcm
->params
.hdr
.size
= sizeof(pcm
->params
) + ext_data_size
;
218 pcm
->params
.buffer
.phy_addr
= spcm
->stream
[cstream
->direction
].page_table
.addr
;
219 pcm
->params
.buffer
.size
= crtd
->dma_bytes
;
220 pcm
->params
.direction
= cstream
->direction
;
221 pcm
->params
.channels
= params
->codec
.ch_out
;
222 pcm
->params
.rate
= params
->codec
.sample_rate
;
223 pcm
->params
.buffer_fmt
= SOF_IPC_BUFFER_INTERLEAVED
;
224 pcm
->params
.frame_fmt
= SOF_IPC_FRAME_S32_LE
;
225 pcm
->params
.sample_container_bytes
=
226 snd_pcm_format_physical_width(SNDRV_PCM_FORMAT_S32
) >> 3;
227 pcm
->params
.host_period_bytes
= params
->buffer
.fragment_size
;
228 pcm
->params
.ext_data_length
= ext_data_size
;
230 memcpy((u8
*)pcm
->params
.ext_data
, ¶ms
->codec
, ext_data_size
);
232 ret
= sof_ipc_tx_message(sdev
->ipc
, pcm
, sizeof(*pcm
) + ext_data_size
,
233 &ipc_params_reply
, sizeof(ipc_params_reply
));
235 dev_err(component
->dev
, "error ipc failed\n");
239 ret
= snd_sof_set_stream_data_offset(sdev
, &spcm
->stream
[cstream
->direction
],
240 ipc_params_reply
.posn_offset
);
242 dev_err(component
->dev
, "Invalid stream data offset for Compr %d\n",
247 sstream
->sampling_rate
= params
->codec
.sample_rate
;
248 sstream
->channels
= params
->codec
.ch_out
;
249 sstream
->sample_container_bytes
= pcm
->params
.sample_container_bytes
;
251 spcm
->prepared
[cstream
->direction
] = true;
259 static int sof_compr_get_params(struct snd_soc_component
*component
,
260 struct snd_compr_stream
*cstream
, struct snd_codec
*params
)
262 /* TODO: we don't query the supported codecs for now, if the
263 * application asks for an unsupported codec the set_params() will fail.
268 static int sof_compr_trigger(struct snd_soc_component
*component
,
269 struct snd_compr_stream
*cstream
, int cmd
)
271 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(component
);
272 struct snd_soc_pcm_runtime
*rtd
= cstream
->private_data
;
273 struct sof_ipc_stream stream
;
274 struct snd_sof_pcm
*spcm
;
276 spcm
= snd_sof_find_spcm_dai(component
, rtd
);
280 stream
.hdr
.size
= sizeof(stream
);
281 stream
.hdr
.cmd
= SOF_IPC_GLB_STREAM_MSG
;
282 stream
.comp_id
= spcm
->stream
[cstream
->direction
].comp_id
;
285 case SNDRV_PCM_TRIGGER_START
:
286 stream
.hdr
.cmd
|= SOF_IPC_STREAM_TRIG_START
;
288 case SNDRV_PCM_TRIGGER_STOP
:
289 stream
.hdr
.cmd
|= SOF_IPC_STREAM_TRIG_STOP
;
291 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
292 stream
.hdr
.cmd
|= SOF_IPC_STREAM_TRIG_PAUSE
;
294 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
295 stream
.hdr
.cmd
|= SOF_IPC_STREAM_TRIG_RELEASE
;
298 dev_err(component
->dev
, "error: unhandled trigger cmd %d\n", cmd
);
302 return sof_ipc_tx_message_no_reply(sdev
->ipc
, &stream
, sizeof(stream
));
305 static int sof_compr_copy_playback(struct snd_compr_runtime
*rtd
,
306 char __user
*buf
, size_t count
)
309 unsigned int offset
, n
;
312 div_u64_rem(rtd
->total_bytes_available
, rtd
->buffer_size
, &offset
);
313 ptr
= rtd
->dma_area
+ offset
;
314 n
= rtd
->buffer_size
- offset
;
317 ret
= copy_from_user(ptr
, buf
, count
);
319 ret
= copy_from_user(ptr
, buf
, n
);
320 ret
+= copy_from_user(rtd
->dma_area
, buf
+ n
, count
- n
);
326 static int sof_compr_copy_capture(struct snd_compr_runtime
*rtd
,
327 char __user
*buf
, size_t count
)
330 unsigned int offset
, n
;
333 div_u64_rem(rtd
->total_bytes_transferred
, rtd
->buffer_size
, &offset
);
334 ptr
= rtd
->dma_area
+ offset
;
335 n
= rtd
->buffer_size
- offset
;
338 ret
= copy_to_user(buf
, ptr
, count
);
340 ret
= copy_to_user(buf
, ptr
, n
);
341 ret
+= copy_to_user(buf
+ n
, rtd
->dma_area
, count
- n
);
347 static int sof_compr_copy(struct snd_soc_component
*component
,
348 struct snd_compr_stream
*cstream
,
349 char __user
*buf
, size_t count
)
351 struct snd_compr_runtime
*rtd
= cstream
->runtime
;
353 if (count
> rtd
->buffer_size
)
354 count
= rtd
->buffer_size
;
356 if (cstream
->direction
== SND_COMPRESS_PLAYBACK
)
357 return sof_compr_copy_playback(rtd
, buf
, count
);
359 return sof_compr_copy_capture(rtd
, buf
, count
);
362 static int sof_compr_pointer(struct snd_soc_component
*component
,
363 struct snd_compr_stream
*cstream
,
364 struct snd_compr_tstamp
*tstamp
)
366 struct snd_sof_pcm
*spcm
;
367 struct snd_soc_pcm_runtime
*rtd
= cstream
->private_data
;
368 struct sof_compr_stream
*sstream
= cstream
->runtime
->private_data
;
370 spcm
= snd_sof_find_spcm_dai(component
, rtd
);
374 tstamp
->sampling_rate
= sstream
->sampling_rate
;
375 tstamp
->copied_total
= sstream
->copied_total
;
376 tstamp
->pcm_io_frames
= div_u64(spcm
->stream
[cstream
->direction
].posn
.dai_posn
,
377 sstream
->channels
* sstream
->sample_container_bytes
);
382 struct snd_compress_ops sof_compressed_ops
= {
383 .open
= sof_compr_open
,
384 .free
= sof_compr_free
,
385 .set_params
= sof_compr_set_params
,
386 .get_params
= sof_compr_get_params
,
387 .trigger
= sof_compr_trigger
,
388 .pointer
= sof_compr_pointer
,
389 .copy
= sof_compr_copy
,
391 EXPORT_SYMBOL(sof_compressed_ops
);