| .. | .. |
|---|
| 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 | |
|---|