.. | .. |
---|
1 | | -// SPDX-License-Identifier: GPL-2.0 |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
2 | 2 | /* |
---|
3 | 3 | * ALSA SoC Audio Layer - Rockchip Multi-DAIS-PCM driver |
---|
4 | 4 | * |
---|
.. | .. |
---|
16 | 16 | #include <sound/soc.h> |
---|
17 | 17 | |
---|
18 | 18 | #include "rockchip_multi_dais.h" |
---|
| 19 | +#include "rockchip_dlp.h" |
---|
19 | 20 | |
---|
20 | | -#define MAX_FIFO_SIZE 32 /* max fifo size in frames */ |
---|
21 | | -#define SND_DMAENGINE_MPCM_DRV_NAME "snd_dmaengine_mpcm" |
---|
| 21 | +#define I2S_TXFIFOLR 0xc |
---|
| 22 | +#define I2S_RXFIFOLR 0x2c |
---|
| 23 | +#define SAI_TXFIFOLR 0x1c |
---|
| 24 | +#define SAI_RXFIFOLR 0x20 |
---|
| 25 | + |
---|
| 26 | +/* XFL4 is compatible for old version */ |
---|
| 27 | +#define I2S_FIFOLR_XFL4(v) (((v) & GENMASK(29, 24)) >> 24) |
---|
| 28 | +#define I2S_FIFOLR_XFL3(v) (((v) & GENMASK(23, 18)) >> 18) |
---|
| 29 | +#define I2S_FIFOLR_XFL2(v) (((v) & GENMASK(17, 12)) >> 12) |
---|
| 30 | +#define I2S_FIFOLR_XFL1(v) (((v) & GENMASK(11, 6)) >> 6) |
---|
| 31 | +#define I2S_FIFOLR_XFL0(v) (((v) & GENMASK(5, 0)) >> 0) |
---|
| 32 | + |
---|
| 33 | +/* XFIFOLR: Transfer / Receive FIFO Level Register */ |
---|
| 34 | +#define SAI_FIFOLR_XFL3(v) (((v) & GENMASK(23, 18)) >> 18) |
---|
| 35 | +#define SAI_FIFOLR_XFL2(v) (((v) & GENMASK(17, 12)) >> 12) |
---|
| 36 | +#define SAI_FIFOLR_XFL1(v) (((v) & GENMASK(11, 6)) >> 6) |
---|
| 37 | +#define SAI_FIFOLR_XFL0(v) (((v) & GENMASK(5, 0)) >> 0) |
---|
| 38 | + |
---|
| 39 | +#define MAX_FIFO_SIZE 32 /* max fifo size in frames */ |
---|
| 40 | +#define SND_DMAENGINE_MPCM_DRV_NAME "snd_dmaengine_mpcm" |
---|
22 | 41 | |
---|
23 | 42 | static unsigned int prealloc_buffer_size_kbytes = 512; |
---|
24 | 43 | module_param(prealloc_buffer_size_kbytes, uint, 0444); |
---|
25 | 44 | MODULE_PARM_DESC(prealloc_buffer_size_kbytes, "Preallocate DMA buffer size (KB)."); |
---|
26 | 45 | |
---|
27 | 46 | struct dmaengine_mpcm { |
---|
| 47 | + struct dlp dlp; |
---|
28 | 48 | struct rk_mdais_dev *mdais; |
---|
29 | 49 | struct dma_chan *tx_chans[MAX_DAIS]; |
---|
30 | 50 | struct dma_chan *rx_chans[MAX_DAIS]; |
---|
31 | | - struct snd_soc_component component; |
---|
32 | 51 | }; |
---|
33 | 52 | |
---|
34 | 53 | struct dmaengine_mpcm_runtime_data { |
---|
| 54 | + struct dlp_runtime_data drd; |
---|
35 | 55 | struct dma_chan *chans[MAX_DAIS]; |
---|
| 56 | + struct dma_interleaved_template *xt; |
---|
36 | 57 | dma_cookie_t cookies[MAX_DAIS]; |
---|
37 | 58 | unsigned int *channel_maps; |
---|
38 | 59 | int num_chans; |
---|
.. | .. |
---|
48 | 69 | static inline struct dmaengine_mpcm_runtime_data *substream_to_prtd( |
---|
49 | 70 | const struct snd_pcm_substream *substream) |
---|
50 | 71 | { |
---|
51 | | - return substream->runtime->private_data; |
---|
| 72 | + struct dlp_runtime_data *drd = substream_to_drd(substream); |
---|
| 73 | + |
---|
| 74 | + if (!drd) |
---|
| 75 | + return NULL; |
---|
| 76 | + |
---|
| 77 | + return container_of(drd, struct dmaengine_mpcm_runtime_data, drd); |
---|
52 | 78 | } |
---|
53 | 79 | |
---|
54 | 80 | static struct dmaengine_mpcm *soc_component_to_mpcm(struct snd_soc_component *p) |
---|
55 | 81 | { |
---|
56 | | - return container_of(p, struct dmaengine_mpcm, component); |
---|
| 82 | + return container_of(soc_component_to_dlp(p), struct dmaengine_mpcm, dlp); |
---|
57 | 83 | } |
---|
58 | 84 | |
---|
59 | 85 | static struct dma_chan *to_chan(struct dmaengine_mpcm *pcm, |
---|
.. | .. |
---|
105 | 131 | { |
---|
106 | 132 | struct snd_pcm_substream *substream = arg; |
---|
107 | 133 | #ifdef CONFIG_SND_SOC_ROCKCHIP_VAD |
---|
108 | | - struct dmaengine_mpcm_runtime_data *prtd = substream_to_prtd(substream); |
---|
| 134 | + struct dmaengine_mpcm_runtime_data *prtd; |
---|
| 135 | +#endif |
---|
| 136 | + struct dlp_runtime_data *drd; |
---|
| 137 | + struct dlp *dlp; |
---|
| 138 | + |
---|
| 139 | + snd_pcm_stream_lock_irq(substream); |
---|
| 140 | + if (!substream->runtime) { |
---|
| 141 | + snd_pcm_stream_unlock_irq(substream); |
---|
| 142 | + return; |
---|
| 143 | + } |
---|
| 144 | +#ifdef CONFIG_SND_SOC_ROCKCHIP_VAD |
---|
| 145 | + prtd = substream_to_prtd(substream); |
---|
| 146 | + if (unlikely(!prtd)) |
---|
| 147 | + return; |
---|
109 | 148 | |
---|
110 | 149 | if (snd_pcm_vad_attached(substream) && |
---|
111 | 150 | substream->stream == SNDRV_PCM_STREAM_CAPTURE) { |
---|
.. | .. |
---|
120 | 159 | prtd->pos = 0; |
---|
121 | 160 | |
---|
122 | 161 | #endif |
---|
| 162 | + drd = substream_to_drd(substream); |
---|
| 163 | + dlp = drd->parent; |
---|
| 164 | + |
---|
| 165 | + dlp_dma_complete(dlp, drd); |
---|
| 166 | + snd_pcm_stream_unlock_irq(substream); |
---|
| 167 | + |
---|
123 | 168 | snd_pcm_period_elapsed(substream); |
---|
124 | 169 | } |
---|
125 | 170 | |
---|
126 | 171 | static void dmaengine_mpcm_get_master_chan(struct dmaengine_mpcm_runtime_data *prtd) |
---|
127 | 172 | { |
---|
128 | 173 | int i; |
---|
| 174 | + |
---|
| 175 | + if (unlikely(!prtd)) |
---|
| 176 | + return; |
---|
129 | 177 | |
---|
130 | 178 | for (i = prtd->num_chans; i > 0; i--) { |
---|
131 | 179 | if (prtd->chans[i - 1]) { |
---|
.. | .. |
---|
135 | 183 | } |
---|
136 | 184 | } |
---|
137 | 185 | |
---|
| 186 | +static int dmaengine_config_interleaved(struct snd_pcm_substream *substream, |
---|
| 187 | + struct dma_interleaved_template *xt, |
---|
| 188 | + int offset, int sample_bytes, int nump, int numf) |
---|
| 189 | +{ |
---|
| 190 | + struct snd_pcm_runtime *runtime = substream->runtime; |
---|
| 191 | + int frame_bytes; |
---|
| 192 | + |
---|
| 193 | + frame_bytes = frames_to_bytes(runtime, 1); |
---|
| 194 | + |
---|
| 195 | + xt->frame_size = 1; |
---|
| 196 | + xt->sgl[0].size = sample_bytes; |
---|
| 197 | + xt->sgl[0].icg = frame_bytes - sample_bytes; |
---|
| 198 | + |
---|
| 199 | +#ifdef CONFIG_NO_GKI |
---|
| 200 | + xt->nump = nump; |
---|
| 201 | +#endif |
---|
| 202 | + xt->numf = numf; |
---|
| 203 | + |
---|
| 204 | + xt->dir = snd_pcm_substream_to_dma_direction(substream); |
---|
| 205 | + |
---|
| 206 | + if (xt->dir == DMA_MEM_TO_DEV) { |
---|
| 207 | + xt->src_start = runtime->dma_addr + offset; |
---|
| 208 | + xt->src_inc = true; |
---|
| 209 | + xt->src_sgl = true; |
---|
| 210 | + xt->dst_inc = false; |
---|
| 211 | + xt->dst_sgl = false; |
---|
| 212 | + } else { |
---|
| 213 | + xt->dst_start = runtime->dma_addr + offset; |
---|
| 214 | + xt->src_inc = false; |
---|
| 215 | + xt->src_sgl = false; |
---|
| 216 | + xt->dst_inc = true; |
---|
| 217 | + xt->dst_sgl = true; |
---|
| 218 | + } |
---|
| 219 | + |
---|
| 220 | + return 0; |
---|
| 221 | +} |
---|
| 222 | + |
---|
138 | 223 | static int dmaengine_mpcm_prepare_and_submit(struct snd_pcm_substream *substream) |
---|
139 | 224 | { |
---|
140 | 225 | struct dmaengine_mpcm_runtime_data *prtd = substream_to_prtd(substream); |
---|
141 | 226 | struct snd_pcm_runtime *runtime = substream->runtime; |
---|
142 | 227 | struct dma_async_tx_descriptor *desc = NULL; |
---|
143 | | - enum dma_transfer_direction direction; |
---|
| 228 | + struct dma_interleaved_template *xt; |
---|
144 | 229 | unsigned long flags = DMA_CTRL_ACK; |
---|
145 | | - unsigned int *maps = prtd->channel_maps; |
---|
146 | | - int offset, buffer_bytes, period_bytes; |
---|
| 230 | + unsigned int *maps; |
---|
| 231 | + int offset; |
---|
147 | 232 | int i; |
---|
148 | 233 | |
---|
149 | | - direction = snd_pcm_substream_to_dma_direction(substream); |
---|
| 234 | + if (unlikely(!prtd || !runtime)) |
---|
| 235 | + return -EINVAL; |
---|
150 | 236 | |
---|
151 | 237 | if (!substream->runtime->no_period_wakeup) |
---|
152 | 238 | flags |= DMA_PREP_INTERRUPT; |
---|
153 | 239 | |
---|
154 | 240 | prtd->pos = 0; |
---|
155 | 241 | offset = 0; |
---|
156 | | - period_bytes = snd_pcm_lib_period_bytes(substream); |
---|
157 | | - buffer_bytes = snd_pcm_lib_buffer_bytes(substream); |
---|
| 242 | + |
---|
| 243 | + xt = prtd->xt; |
---|
| 244 | + maps = prtd->channel_maps; |
---|
158 | 245 | for (i = 0; i < prtd->num_chans; i++) { |
---|
159 | 246 | if (!prtd->chans[i]) |
---|
160 | 247 | continue; |
---|
161 | | - desc = dmaengine_prep_dma_cyclic(prtd->chans[i], |
---|
162 | | - runtime->dma_addr + offset, |
---|
163 | | - buffer_bytes, period_bytes, |
---|
164 | | - direction, flags); |
---|
| 248 | + |
---|
| 249 | + dmaengine_config_interleaved(substream, xt, offset, |
---|
| 250 | + samples_to_bytes(runtime, maps[i]), |
---|
| 251 | + runtime->period_size, |
---|
| 252 | + runtime->buffer_size); |
---|
| 253 | + |
---|
| 254 | + desc = dmaengine_prep_interleaved_dma(prtd->chans[i], xt, |
---|
| 255 | + flags | DMA_PREP_REPEAT); |
---|
165 | 256 | |
---|
166 | 257 | if (!desc) |
---|
167 | 258 | return -ENOMEM; |
---|
.. | .. |
---|
185 | 276 | { |
---|
186 | 277 | int i; |
---|
187 | 278 | |
---|
| 279 | + if (unlikely(!prtd)) |
---|
| 280 | + return; |
---|
| 281 | + |
---|
188 | 282 | for (i = 0; i < prtd->num_chans; i++) { |
---|
189 | 283 | if (prtd->chans[i]) |
---|
190 | 284 | dma_async_issue_pending(prtd->chans[i]); |
---|
.. | .. |
---|
194 | 288 | static void mpcm_dmaengine_resume(struct dmaengine_mpcm_runtime_data *prtd) |
---|
195 | 289 | { |
---|
196 | 290 | int i; |
---|
| 291 | + |
---|
| 292 | + if (unlikely(!prtd)) |
---|
| 293 | + return; |
---|
197 | 294 | |
---|
198 | 295 | for (i = 0; i < prtd->num_chans; i++) { |
---|
199 | 296 | if (prtd->chans[i]) |
---|
.. | .. |
---|
205 | 302 | { |
---|
206 | 303 | int i; |
---|
207 | 304 | |
---|
| 305 | + if (unlikely(!prtd)) |
---|
| 306 | + return; |
---|
| 307 | + |
---|
208 | 308 | for (i = 0; i < prtd->num_chans; i++) { |
---|
209 | 309 | if (prtd->chans[i]) |
---|
210 | 310 | dmaengine_pause(prtd->chans[i]); |
---|
.. | .. |
---|
214 | 314 | static void mpcm_dmaengine_terminate_all(struct dmaengine_mpcm_runtime_data *prtd) |
---|
215 | 315 | { |
---|
216 | 316 | int i; |
---|
| 317 | + |
---|
| 318 | + if (unlikely(!prtd)) |
---|
| 319 | + return; |
---|
217 | 320 | |
---|
218 | 321 | for (i = 0; i < prtd->num_chans; i++) { |
---|
219 | 322 | if (prtd->chans[i]) |
---|
.. | .. |
---|
228 | 331 | struct dmaengine_mpcm_runtime_data *prtd = substream_to_prtd(substream); |
---|
229 | 332 | unsigned int pos, size; |
---|
230 | 333 | void *buf; |
---|
| 334 | + |
---|
| 335 | + if (unlikely(!prtd)) |
---|
| 336 | + return; |
---|
231 | 337 | |
---|
232 | 338 | if (snd_pcm_vad_attached(substream) && |
---|
233 | 339 | substream->stream == SNDRV_PCM_STREAM_CAPTURE) { |
---|
.. | .. |
---|
249 | 355 | } |
---|
250 | 356 | |
---|
251 | 357 | static int __mpcm_prepare_single_and_submit(struct snd_pcm_substream *substream, |
---|
252 | | - dma_addr_t buf_start, int size) |
---|
| 358 | + int buf_offset, int size) |
---|
253 | 359 | { |
---|
254 | 360 | struct dmaengine_mpcm_runtime_data *prtd = substream_to_prtd(substream); |
---|
| 361 | + struct dma_interleaved_template *xt; |
---|
255 | 362 | struct snd_pcm_runtime *runtime = substream->runtime; |
---|
256 | 363 | struct dma_async_tx_descriptor *desc; |
---|
257 | | - enum dma_transfer_direction direction; |
---|
258 | 364 | unsigned long flags = DMA_CTRL_ACK; |
---|
259 | | - unsigned int *maps = prtd->channel_maps; |
---|
| 365 | + unsigned int *maps; |
---|
260 | 366 | int offset, i; |
---|
261 | 367 | bool callback = false; |
---|
262 | 368 | |
---|
263 | | - direction = snd_pcm_substream_to_dma_direction(substream); |
---|
| 369 | + if (unlikely(!prtd || !runtime)) |
---|
| 370 | + return -EINVAL; |
---|
264 | 371 | |
---|
265 | 372 | if (!substream->runtime->no_period_wakeup) |
---|
266 | 373 | flags |= DMA_PREP_INTERRUPT; |
---|
267 | 374 | |
---|
268 | | - offset = 0; |
---|
| 375 | + offset = buf_offset; |
---|
| 376 | + xt = prtd->xt; |
---|
| 377 | + maps = prtd->channel_maps; |
---|
269 | 378 | for (i = 0; i < prtd->num_chans; i++) { |
---|
270 | 379 | if (!prtd->chans[i]) |
---|
271 | 380 | continue; |
---|
272 | | - desc = dmaengine_prep_slave_single(prtd->chans[i], |
---|
273 | | - buf_start + offset, |
---|
274 | | - size, |
---|
275 | | - direction, flags); |
---|
276 | 381 | |
---|
| 382 | + dmaengine_config_interleaved(substream, xt, offset, |
---|
| 383 | + samples_to_bytes(runtime, maps[i]), |
---|
| 384 | + 0, |
---|
| 385 | + bytes_to_frames(runtime, size)); |
---|
| 386 | + |
---|
| 387 | + desc = dmaengine_prep_interleaved_dma(prtd->chans[i], xt, flags); |
---|
277 | 388 | if (!desc) |
---|
278 | 389 | return -ENOMEM; |
---|
| 390 | + |
---|
279 | 391 | if (!callback) { |
---|
280 | 392 | desc->callback = dmaengine_mpcm_single_dma_complete; |
---|
281 | 393 | desc->callback_param = substream; |
---|
.. | .. |
---|
298 | 410 | int offset, i, count, ret; |
---|
299 | 411 | int buffer_bytes, period_bytes, residue_bytes; |
---|
300 | 412 | |
---|
| 413 | + if (unlikely(!prtd)) |
---|
| 414 | + return -EINVAL; |
---|
| 415 | + |
---|
301 | 416 | direction = snd_pcm_substream_to_dma_direction(substream); |
---|
302 | 417 | |
---|
303 | 418 | if (!substream->runtime->no_period_wakeup) |
---|
.. | .. |
---|
316 | 431 | pr_debug("%s: offset: %d, buffer_bytes: %d\n", __func__, offset, buffer_bytes); |
---|
317 | 432 | pr_debug("%s: count: %d, residue_bytes: %d\n", __func__, count, residue_bytes); |
---|
318 | 433 | for (i = 0; i < count; i++) { |
---|
319 | | - ret = __mpcm_prepare_single_and_submit(substream, buf_start, |
---|
| 434 | + ret = __mpcm_prepare_single_and_submit(substream, offset, |
---|
320 | 435 | period_bytes); |
---|
321 | 436 | if (ret) |
---|
322 | 437 | return ret; |
---|
323 | | - buf_start += period_bytes; |
---|
| 438 | + offset += period_bytes; |
---|
324 | 439 | } |
---|
325 | 440 | |
---|
326 | 441 | if (residue_bytes) { |
---|
327 | | - ret = __mpcm_prepare_single_and_submit(substream, buf_start, |
---|
| 442 | + ret = __mpcm_prepare_single_and_submit(substream, offset, |
---|
328 | 443 | residue_bytes); |
---|
329 | 444 | if (ret) |
---|
330 | 445 | return ret; |
---|
.. | .. |
---|
334 | 449 | } |
---|
335 | 450 | #endif |
---|
336 | 451 | |
---|
337 | | -static int snd_dmaengine_mpcm_trigger(struct snd_soc_component *component, |
---|
338 | | - struct snd_pcm_substream *substream, int cmd) |
---|
| 452 | +static snd_pcm_uframes_t dmaengine_mpcm_raw_pointer(struct snd_soc_component *component, |
---|
| 453 | + struct snd_pcm_substream *substream) |
---|
| 454 | +{ |
---|
| 455 | + struct dmaengine_mpcm_runtime_data *prtd = substream_to_prtd(substream); |
---|
| 456 | + struct dma_tx_state state; |
---|
| 457 | + unsigned int buf_size; |
---|
| 458 | + unsigned int pos = 0; |
---|
| 459 | + unsigned int master; |
---|
| 460 | + |
---|
| 461 | + if (unlikely(!prtd)) |
---|
| 462 | + return 0; |
---|
| 463 | + |
---|
| 464 | + master = prtd->master_chan; |
---|
| 465 | + buf_size = snd_pcm_lib_buffer_bytes(substream); |
---|
| 466 | + dmaengine_tx_status(prtd->chans[master], prtd->cookies[master], &state); |
---|
| 467 | + if (state.residue > 0 && state.residue <= buf_size) |
---|
| 468 | + pos = buf_size - state.residue; |
---|
| 469 | + |
---|
| 470 | + return bytes_to_frames(substream->runtime, pos); |
---|
| 471 | +} |
---|
| 472 | + |
---|
| 473 | +static int dmaengine_mpcm_dlp_start(struct snd_soc_component *component, |
---|
| 474 | + struct snd_pcm_substream *substream) |
---|
| 475 | +{ |
---|
| 476 | + struct dmaengine_mpcm *pcm = soc_component_to_mpcm(component); |
---|
| 477 | + |
---|
| 478 | + return dlp_start(component, substream, pcm->mdais->dev, dmaengine_mpcm_raw_pointer); |
---|
| 479 | +} |
---|
| 480 | + |
---|
| 481 | +static void dmaengine_mpcm_dlp_stop(struct snd_soc_component *component, |
---|
| 482 | + struct snd_pcm_substream *substream) |
---|
| 483 | +{ |
---|
| 484 | + dlp_stop(component, substream, dmaengine_mpcm_raw_pointer); |
---|
| 485 | +} |
---|
| 486 | + |
---|
| 487 | +static int dmaengine_mpcm_trigger(struct snd_soc_component *component, |
---|
| 488 | + struct snd_pcm_substream *substream, int cmd) |
---|
339 | 489 | { |
---|
340 | 490 | struct dmaengine_mpcm_runtime_data *prtd = substream_to_prtd(substream); |
---|
341 | 491 | struct snd_pcm_runtime *runtime = substream->runtime; |
---|
342 | 492 | int ret; |
---|
| 493 | + |
---|
| 494 | + if (unlikely(!prtd || !runtime)) |
---|
| 495 | + return -EINVAL; |
---|
343 | 496 | |
---|
344 | 497 | switch (cmd) { |
---|
345 | 498 | case SNDRV_PCM_TRIGGER_START: |
---|
.. | .. |
---|
355 | 508 | if (ret) |
---|
356 | 509 | return ret; |
---|
357 | 510 | mpcm_dma_async_issue_pending(prtd); |
---|
| 511 | + dmaengine_mpcm_dlp_start(component, substream); |
---|
358 | 512 | break; |
---|
359 | 513 | case SNDRV_PCM_TRIGGER_RESUME: |
---|
360 | 514 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
---|
361 | 515 | mpcm_dmaengine_resume(prtd); |
---|
362 | 516 | break; |
---|
363 | 517 | case SNDRV_PCM_TRIGGER_SUSPEND: |
---|
364 | | - if (runtime->info & SNDRV_PCM_INFO_PAUSE) |
---|
| 518 | + if (runtime->info & SNDRV_PCM_INFO_PAUSE) { |
---|
365 | 519 | mpcm_dmaengine_pause(prtd); |
---|
366 | | - else |
---|
| 520 | + } else { |
---|
| 521 | + dmaengine_mpcm_dlp_stop(component, substream); |
---|
367 | 522 | mpcm_dmaengine_terminate_all(prtd); |
---|
| 523 | + } |
---|
368 | 524 | prtd->start_flag = false; |
---|
369 | 525 | break; |
---|
370 | 526 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
---|
.. | .. |
---|
372 | 528 | prtd->start_flag = false; |
---|
373 | 529 | break; |
---|
374 | 530 | case SNDRV_PCM_TRIGGER_STOP: |
---|
| 531 | + dmaengine_mpcm_dlp_stop(component, substream); |
---|
375 | 532 | mpcm_dmaengine_terminate_all(prtd); |
---|
376 | 533 | prtd->start_flag = false; |
---|
377 | 534 | break; |
---|
.. | .. |
---|
423 | 580 | sz = snd_pcm_format_size(format, maps[i]); |
---|
424 | 581 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
---|
425 | 582 | chan = pcm->tx_chans[i]; |
---|
426 | | -#ifdef CONFIG_NO_GKI |
---|
427 | | - if (sz) { |
---|
428 | | - slave_config.src_interlace_size = frame_bytes - sz; |
---|
429 | | - if (slave_config.src_interlace_size) |
---|
430 | | - slave_config.dst_maxburst = sz / slave_config.dst_addr_width; |
---|
431 | | - } |
---|
432 | | -#endif |
---|
| 583 | + if (sz && (frame_bytes - sz) > 0) |
---|
| 584 | + slave_config.dst_maxburst = sz / slave_config.dst_addr_width; |
---|
433 | 585 | } else { |
---|
434 | 586 | chan = pcm->rx_chans[i]; |
---|
435 | | -#ifdef CONFIG_NO_GKI |
---|
436 | | - if (sz) { |
---|
437 | | - slave_config.dst_interlace_size = frame_bytes - sz; |
---|
438 | | - if (slave_config.dst_interlace_size) |
---|
439 | | - slave_config.src_maxburst = sz / slave_config.src_addr_width; |
---|
440 | | - } |
---|
441 | | -#endif |
---|
| 587 | + if (sz && (frame_bytes - sz) > 0) |
---|
| 588 | + slave_config.src_maxburst = sz / slave_config.src_addr_width; |
---|
442 | 589 | } |
---|
443 | 590 | if (!chan) |
---|
444 | 591 | continue; |
---|
.. | .. |
---|
447 | 594 | if (ret) |
---|
448 | 595 | return ret; |
---|
449 | 596 | } |
---|
| 597 | + |
---|
| 598 | + ret = dlp_hw_params(component, substream, params); |
---|
| 599 | + if (ret) |
---|
| 600 | + return ret; |
---|
| 601 | + |
---|
450 | 602 | return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); |
---|
451 | 603 | } |
---|
452 | 604 | |
---|
.. | .. |
---|
467 | 619 | int ret; |
---|
468 | 620 | |
---|
469 | 621 | chan = to_chan(pcm, substream); |
---|
470 | | - if (!chan) |
---|
| 622 | + if (!chan || !dma_dev) |
---|
471 | 623 | return -EINVAL; |
---|
472 | 624 | |
---|
473 | 625 | memset(&hw, 0, sizeof(hw)); |
---|
474 | 626 | hw.info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | |
---|
475 | | - SNDRV_PCM_INFO_INTERLEAVED; |
---|
| 627 | + SNDRV_PCM_INFO_INTERLEAVED; |
---|
476 | 628 | hw.periods_min = 2; |
---|
477 | 629 | hw.periods_max = UINT_MAX; |
---|
478 | 630 | hw.period_bytes_min = 256; |
---|
.. | .. |
---|
542 | 694 | if (!prtd) |
---|
543 | 695 | return -ENOMEM; |
---|
544 | 696 | |
---|
| 697 | + prtd->xt = kzalloc(sizeof(struct dma_interleaved_template) + |
---|
| 698 | + sizeof(struct data_chunk), GFP_KERNEL); |
---|
| 699 | + if (!prtd->xt) { |
---|
| 700 | + kfree(prtd); |
---|
| 701 | + return -ENOMEM; |
---|
| 702 | + } |
---|
| 703 | + |
---|
545 | 704 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
---|
546 | 705 | prtd->channel_maps = pcm->mdais->playback_channel_maps; |
---|
547 | 706 | for (i = 0; i < pcm->mdais->num_dais; i++) |
---|
.. | .. |
---|
554 | 713 | |
---|
555 | 714 | prtd->num_chans = pcm->mdais->num_dais; |
---|
556 | 715 | prtd->start_flag = false; |
---|
557 | | - substream->runtime->private_data = prtd; |
---|
| 716 | + |
---|
| 717 | + dlp_open(&pcm->dlp, &prtd->drd, substream); |
---|
558 | 718 | |
---|
559 | 719 | return 0; |
---|
560 | 720 | } |
---|
.. | .. |
---|
563 | 723 | { |
---|
564 | 724 | struct dmaengine_mpcm *pcm = soc_component_to_mpcm(component); |
---|
565 | 725 | struct snd_pcm_substream *substream; |
---|
| 726 | + struct device *dma_dev; |
---|
566 | 727 | size_t prealloc_buffer_size; |
---|
567 | 728 | size_t max_buffer_size; |
---|
568 | 729 | unsigned int i; |
---|
.. | .. |
---|
575 | 736 | if (!substream) |
---|
576 | 737 | continue; |
---|
577 | 738 | |
---|
| 739 | + dma_dev = dmaengine_dma_dev(pcm, substream); |
---|
| 740 | + if (!dma_dev) { |
---|
| 741 | + dev_err(component->dev, "No chan found, should assign 'rockchip,no-dmaengine' in DT\n"); |
---|
| 742 | + return -EINVAL; |
---|
| 743 | + } |
---|
| 744 | + |
---|
578 | 745 | snd_pcm_lib_preallocate_pages(substream, |
---|
579 | 746 | SNDRV_DMA_TYPE_DEV_IRAM, |
---|
580 | | - dmaengine_dma_dev(pcm, substream), |
---|
| 747 | + dma_dev, |
---|
581 | 748 | prealloc_buffer_size, |
---|
582 | 749 | max_buffer_size); |
---|
583 | 750 | } |
---|
.. | .. |
---|
594 | 761 | snd_pcm_uframes_t frames; |
---|
595 | 762 | unsigned int buf_size; |
---|
596 | 763 | unsigned int pos = 0; |
---|
597 | | - unsigned int master = prtd->master_chan; |
---|
| 764 | + unsigned int master; |
---|
598 | 765 | |
---|
| 766 | + if (unlikely(!prtd || !runtime)) |
---|
| 767 | + return 0; |
---|
| 768 | + |
---|
| 769 | + master = prtd->master_chan; |
---|
599 | 770 | buf_size = snd_pcm_lib_buffer_bytes(substream); |
---|
600 | 771 | dmaengine_tx_status(prtd->chans[master], prtd->cookies[master], &state); |
---|
601 | 772 | if (state.residue > 0 && state.residue <= buf_size) |
---|
.. | .. |
---|
640 | 811 | static int dmaengine_mpcm_close(struct snd_soc_component *component, |
---|
641 | 812 | struct snd_pcm_substream *substream) |
---|
642 | 813 | { |
---|
| 814 | + struct dmaengine_mpcm *pcm = soc_component_to_mpcm(component); |
---|
643 | 815 | struct dmaengine_mpcm_runtime_data *prtd = substream_to_prtd(substream); |
---|
644 | 816 | |
---|
| 817 | + if (unlikely(!prtd)) |
---|
| 818 | + return -EINVAL; |
---|
| 819 | + |
---|
| 820 | + dlp_close(&pcm->dlp, &prtd->drd, substream); |
---|
| 821 | + |
---|
| 822 | + kfree(prtd->xt); |
---|
645 | 823 | kfree(prtd); |
---|
646 | 824 | |
---|
647 | 825 | return 0; |
---|
648 | 826 | } |
---|
649 | 827 | |
---|
| 828 | +static int dmaengine_mpcm_copy_user(struct snd_soc_component *component, |
---|
| 829 | + struct snd_pcm_substream *substream, |
---|
| 830 | + int channel, unsigned long hwoff, |
---|
| 831 | + void __user *buf, unsigned long bytes) |
---|
| 832 | +{ |
---|
| 833 | + return dlp_copy_user(component, substream, channel, hwoff, buf, bytes); |
---|
| 834 | +} |
---|
| 835 | + |
---|
| 836 | + |
---|
| 837 | +static int dmaengine_mpcm_prepare(struct snd_soc_component *component, |
---|
| 838 | + struct snd_pcm_substream *substream) |
---|
| 839 | +{ |
---|
| 840 | + return dlp_prepare(component, substream); |
---|
| 841 | +} |
---|
| 842 | + |
---|
| 843 | +static int dmaengine_mpcm_probe(struct snd_soc_component *component) |
---|
| 844 | +{ |
---|
| 845 | + return dlp_probe(component); |
---|
| 846 | +} |
---|
| 847 | + |
---|
650 | 848 | static const struct snd_soc_component_driver dmaengine_mpcm_platform = { |
---|
651 | 849 | .name = SND_DMAENGINE_MPCM_DRV_NAME, |
---|
652 | 850 | .probe_order = SND_SOC_COMP_ORDER_LATE, |
---|
| 851 | + .probe = dmaengine_mpcm_probe, |
---|
653 | 852 | .pcm_construct = dmaengine_mpcm_new, |
---|
654 | 853 | .open = dmaengine_mpcm_open, |
---|
655 | 854 | .close = dmaengine_mpcm_close, |
---|
656 | 855 | .ioctl = dmaengine_mpcm_ioctl, |
---|
657 | 856 | .hw_params = dmaengine_mpcm_hw_params, |
---|
658 | 857 | .hw_free = dmaengine_mpcm_hw_free, |
---|
659 | | - .trigger = snd_dmaengine_mpcm_trigger, |
---|
| 858 | + .prepare = dmaengine_mpcm_prepare, |
---|
| 859 | + .trigger = dmaengine_mpcm_trigger, |
---|
660 | 860 | .pointer = dmaengine_mpcm_pointer, |
---|
| 861 | + .copy_user = dmaengine_mpcm_copy_user, |
---|
661 | 862 | }; |
---|
662 | 863 | |
---|
663 | 864 | static void dmaengine_mpcm_release_chan(struct dmaengine_mpcm *pcm) |
---|
.. | .. |
---|
671 | 872 | dma_release_channel(pcm->rx_chans[i]); |
---|
672 | 873 | } |
---|
673 | 874 | } |
---|
| 875 | + |
---|
| 876 | +static int dmaengine_mpcm_get_fifo_count(struct device *dev, |
---|
| 877 | + struct snd_pcm_substream *substream) |
---|
| 878 | +{ |
---|
| 879 | + struct rk_mdais_dev *mdais = dev_get_drvdata(dev); |
---|
| 880 | + struct dmaengine_mpcm_runtime_data *prtd = substream_to_prtd(substream); |
---|
| 881 | + struct snd_soc_component *component; |
---|
| 882 | + unsigned int tx, rx, reg; |
---|
| 883 | + int val = 0; |
---|
| 884 | + |
---|
| 885 | + if (unlikely(!prtd)) |
---|
| 886 | + return -EINVAL; |
---|
| 887 | + |
---|
| 888 | + component = mdais->dais[prtd->master_chan].dai->component; |
---|
| 889 | + if (unlikely(!component)) |
---|
| 890 | + return -EINVAL; |
---|
| 891 | + |
---|
| 892 | + if (strstr(dev_driver_string(component->dev), "i2s")) { |
---|
| 893 | + /* compatible for both I2S and I2STDM controller */ |
---|
| 894 | + tx = snd_soc_component_read(component, I2S_TXFIFOLR); |
---|
| 895 | + rx = snd_soc_component_read(component, I2S_RXFIFOLR); |
---|
| 896 | + |
---|
| 897 | + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
---|
| 898 | + val = I2S_FIFOLR_XFL3(tx) + |
---|
| 899 | + I2S_FIFOLR_XFL2(tx) + |
---|
| 900 | + I2S_FIFOLR_XFL1(tx) + |
---|
| 901 | + I2S_FIFOLR_XFL0(tx); |
---|
| 902 | + else |
---|
| 903 | + /* XFL4 is compatible for old version */ |
---|
| 904 | + val = I2S_FIFOLR_XFL4(tx) + |
---|
| 905 | + I2S_FIFOLR_XFL3(rx) + |
---|
| 906 | + I2S_FIFOLR_XFL2(rx) + |
---|
| 907 | + I2S_FIFOLR_XFL1(rx) + |
---|
| 908 | + I2S_FIFOLR_XFL0(rx); |
---|
| 909 | + } else if (strstr(dev_driver_string(component->dev), "sai")) { |
---|
| 910 | + reg = substream->stream ? SAI_RXFIFOLR : SAI_TXFIFOLR; |
---|
| 911 | + |
---|
| 912 | + val = SAI_FIFOLR_XFL3(reg) + |
---|
| 913 | + SAI_FIFOLR_XFL2(reg) + |
---|
| 914 | + SAI_FIFOLR_XFL1(reg) + |
---|
| 915 | + SAI_FIFOLR_XFL0(reg); |
---|
| 916 | + } |
---|
| 917 | + |
---|
| 918 | + return val; |
---|
| 919 | +} |
---|
| 920 | + |
---|
| 921 | +static const struct snd_dlp_config dconfig = { |
---|
| 922 | + .get_fifo_count = dmaengine_mpcm_get_fifo_count, |
---|
| 923 | +}; |
---|
674 | 924 | |
---|
675 | 925 | int snd_dmaengine_mpcm_register(struct rk_mdais_dev *mdais) |
---|
676 | 926 | { |
---|
.. | .. |
---|
689 | 939 | if (!pcm) |
---|
690 | 940 | return -ENOMEM; |
---|
691 | 941 | |
---|
692 | | -#ifdef CONFIG_DEBUG_FS |
---|
693 | | - pcm->component.debugfs_prefix = "dma"; |
---|
694 | | -#endif |
---|
695 | 942 | pcm->mdais = mdais; |
---|
696 | 943 | for (i = 0; i < num; i++) { |
---|
697 | 944 | child = mdais->dais[i].dev; |
---|
.. | .. |
---|
710 | 957 | } |
---|
711 | 958 | } |
---|
712 | 959 | |
---|
713 | | - ret = snd_soc_component_initialize(&pcm->component, &dmaengine_mpcm_platform, |
---|
714 | | - dev); |
---|
715 | | - if (ret) |
---|
716 | | - goto err_free_dma; |
---|
717 | | - |
---|
718 | | - ret = snd_soc_add_component(&pcm->component, NULL, 0); |
---|
| 960 | + ret = dlp_register(&pcm->dlp, dev, &dmaengine_mpcm_platform, &dconfig); |
---|
719 | 961 | if (ret) |
---|
720 | 962 | goto err_free_dma; |
---|
721 | 963 | |
---|