Commit | Line | Data |
---|---|---|
310355c1 VB |
1 | /* |
2 | * ALSA PCM interface for the TI DAVINCI processor | |
3 | * | |
d6b52039 | 4 | * Author: Vladimir Barinov, <vbarinov@embeddedalley.com> |
310355c1 | 5 | * Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.com> |
1e224f32 | 6 | * added SRAM ping/pong (C) 2008 Troy Kisky <troy.kisky@boundarydevices.com> |
310355c1 VB |
7 | * |
8 | * This program is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License version 2 as | |
10 | * published by the Free Software Foundation. | |
11 | */ | |
12 | ||
13 | #include <linux/module.h> | |
14 | #include <linux/init.h> | |
15 | #include <linux/platform_device.h> | |
16 | #include <linux/slab.h> | |
17 | #include <linux/dma-mapping.h> | |
9cd28ab0 | 18 | #include <linux/kernel.h> |
b8ec56d8 | 19 | #include <linux/genalloc.h> |
3ad7a42d | 20 | #include <linux/platform_data/edma.h> |
310355c1 VB |
21 | |
22 | #include <sound/core.h> | |
23 | #include <sound/pcm.h> | |
24 | #include <sound/pcm_params.h> | |
25 | #include <sound/soc.h> | |
26 | ||
27 | #include <asm/dma.h> | |
28 | ||
29 | #include "davinci-pcm.h" | |
30 | ||
1e224f32 TK |
31 | #ifdef DEBUG |
32 | static void print_buf_info(int slot, char *name) | |
33 | { | |
34 | struct edmacc_param p; | |
35 | if (slot < 0) | |
36 | return; | |
37 | edma_read_slot(slot, &p); | |
38 | printk(KERN_DEBUG "%s: 0x%x, opt=%x, src=%x, a_b_cnt=%x dst=%x\n", | |
39 | name, slot, p.opt, p.src, p.a_b_cnt, p.dst); | |
40 | printk(KERN_DEBUG " src_dst_bidx=%x link_bcntrld=%x src_dst_cidx=%x ccnt=%x\n", | |
41 | p.src_dst_bidx, p.link_bcntrld, p.src_dst_cidx, p.ccnt); | |
42 | } | |
43 | #else | |
44 | static void print_buf_info(int slot, char *name) | |
45 | { | |
46 | } | |
47 | #endif | |
48 | ||
8e56d5b8 BG |
49 | #define DAVINCI_PCM_FMTBITS (\ |
50 | SNDRV_PCM_FMTBIT_S8 |\ | |
51 | SNDRV_PCM_FMTBIT_U8 |\ | |
52 | SNDRV_PCM_FMTBIT_S16_LE |\ | |
53 | SNDRV_PCM_FMTBIT_S16_BE |\ | |
54 | SNDRV_PCM_FMTBIT_U16_LE |\ | |
55 | SNDRV_PCM_FMTBIT_U16_BE |\ | |
56 | SNDRV_PCM_FMTBIT_S24_LE |\ | |
57 | SNDRV_PCM_FMTBIT_S24_BE |\ | |
58 | SNDRV_PCM_FMTBIT_U24_LE |\ | |
59 | SNDRV_PCM_FMTBIT_U24_BE |\ | |
60 | SNDRV_PCM_FMTBIT_S32_LE |\ | |
61 | SNDRV_PCM_FMTBIT_S32_BE |\ | |
62 | SNDRV_PCM_FMTBIT_U32_LE |\ | |
63 | SNDRV_PCM_FMTBIT_U32_BE) | |
64 | ||
1e224f32 | 65 | static struct snd_pcm_hardware pcm_hardware_playback = { |
310355c1 VB |
66 | .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | |
67 | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | | |
52e2c5d3 BG |
68 | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME| |
69 | SNDRV_PCM_INFO_BATCH), | |
8e56d5b8 | 70 | .formats = DAVINCI_PCM_FMTBITS, |
393a53cb | 71 | .rates = SNDRV_PCM_RATE_8000_192000 | SNDRV_PCM_RATE_KNOT, |
310355c1 | 72 | .rate_min = 8000, |
393a53cb | 73 | .rate_max = 192000, |
310355c1 | 74 | .channels_min = 2, |
acb8e266 | 75 | .channels_max = 384, |
310355c1 VB |
76 | .buffer_bytes_max = 128 * 1024, |
77 | .period_bytes_min = 32, | |
78 | .period_bytes_max = 8 * 1024, | |
79 | .periods_min = 16, | |
80 | .periods_max = 255, | |
81 | .fifo_size = 0, | |
82 | }; | |
83 | ||
1e224f32 TK |
84 | static struct snd_pcm_hardware pcm_hardware_capture = { |
85 | .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | | |
86 | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | | |
52e2c5d3 BG |
87 | SNDRV_PCM_INFO_PAUSE | |
88 | SNDRV_PCM_INFO_BATCH), | |
8e56d5b8 | 89 | .formats = DAVINCI_PCM_FMTBITS, |
393a53cb | 90 | .rates = SNDRV_PCM_RATE_8000_192000 | SNDRV_PCM_RATE_KNOT, |
1e224f32 | 91 | .rate_min = 8000, |
393a53cb | 92 | .rate_max = 192000, |
1e224f32 | 93 | .channels_min = 2, |
acb8e266 | 94 | .channels_max = 384, |
1e224f32 TK |
95 | .buffer_bytes_max = 128 * 1024, |
96 | .period_bytes_min = 32, | |
97 | .period_bytes_max = 8 * 1024, | |
98 | .periods_min = 16, | |
99 | .periods_max = 255, | |
100 | .fifo_size = 0, | |
101 | }; | |
102 | ||
103 | /* | |
104 | * How ping/pong works.... | |
105 | * | |
106 | * Playback: | |
107 | * ram_params - copys 2*ping_size from start of SDRAM to iram, | |
108 | * links to ram_link2 | |
109 | * ram_link2 - copys rest of SDRAM to iram in ping_size units, | |
110 | * links to ram_link | |
111 | * ram_link - copys entire SDRAM to iram in ping_size uints, | |
112 | * links to self | |
113 | * | |
114 | * asp_params - same as asp_link[0] | |
115 | * asp_link[0] - copys from lower half of iram to asp port | |
116 | * links to asp_link[1], triggers iram copy event on completion | |
117 | * asp_link[1] - copys from upper half of iram to asp port | |
118 | * links to asp_link[0], triggers iram copy event on completion | |
119 | * triggers interrupt only needed to let upper SOC levels update position | |
120 | * in stream on completion | |
121 | * | |
122 | * When playback is started: | |
123 | * ram_params started | |
124 | * asp_params started | |
125 | * | |
126 | * Capture: | |
127 | * ram_params - same as ram_link, | |
128 | * links to ram_link | |
129 | * ram_link - same as playback | |
130 | * links to self | |
131 | * | |
132 | * asp_params - same as playback | |
133 | * asp_link[0] - same as playback | |
134 | * asp_link[1] - same as playback | |
135 | * | |
136 | * When capture is started: | |
137 | * asp_params started | |
138 | */ | |
310355c1 VB |
139 | struct davinci_runtime_data { |
140 | spinlock_t lock; | |
141 | int period; /* current DMA period */ | |
1587ea31 TK |
142 | int asp_channel; /* Master DMA channel */ |
143 | int asp_link[2]; /* asp parameter link channel, ping/pong */ | |
310355c1 | 144 | struct davinci_pcm_dma_params *params; /* DMA params */ |
1e224f32 TK |
145 | int ram_channel; |
146 | int ram_link; | |
147 | int ram_link2; | |
148 | struct edmacc_param asp_params; | |
149 | struct edmacc_param ram_params; | |
310355c1 VB |
150 | }; |
151 | ||
10ab3bfd BG |
152 | static void davinci_pcm_period_elapsed(struct snd_pcm_substream *substream) |
153 | { | |
154 | struct davinci_runtime_data *prtd = substream->runtime->private_data; | |
155 | struct snd_pcm_runtime *runtime = substream->runtime; | |
156 | ||
157 | prtd->period++; | |
158 | if (unlikely(prtd->period >= runtime->periods)) | |
159 | prtd->period = 0; | |
160 | } | |
161 | ||
162 | static void davinci_pcm_period_reset(struct snd_pcm_substream *substream) | |
163 | { | |
164 | struct davinci_runtime_data *prtd = substream->runtime->private_data; | |
165 | ||
166 | prtd->period = 0; | |
167 | } | |
1e224f32 TK |
168 | /* |
169 | * Not used with ping/pong | |
170 | */ | |
310355c1 VB |
171 | static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream) |
172 | { | |
173 | struct davinci_runtime_data *prtd = substream->runtime->private_data; | |
174 | struct snd_pcm_runtime *runtime = substream->runtime; | |
310355c1 VB |
175 | unsigned int period_size; |
176 | unsigned int dma_offset; | |
177 | dma_addr_t dma_pos; | |
178 | dma_addr_t src, dst; | |
179 | unsigned short src_bidx, dst_bidx; | |
4fa9c1a5 | 180 | unsigned short src_cidx, dst_cidx; |
310355c1 | 181 | unsigned int data_type; |
6a99fb5f | 182 | unsigned short acnt; |
310355c1 | 183 | unsigned int count; |
4fa9c1a5 | 184 | unsigned int fifo_level; |
310355c1 VB |
185 | |
186 | period_size = snd_pcm_lib_period_bytes(substream); | |
187 | dma_offset = prtd->period * period_size; | |
188 | dma_pos = runtime->dma_addr + dma_offset; | |
4fa9c1a5 | 189 | fifo_level = prtd->params->fifo_level; |
310355c1 | 190 | |
9cd28ab0 | 191 | pr_debug("davinci_pcm: audio_set_dma_params_play channel = %d " |
be4ff961 BG |
192 | "dma_ptr = %x period_size=%x\n", prtd->asp_link[0], dma_pos, |
193 | period_size); | |
310355c1 VB |
194 | |
195 | data_type = prtd->params->data_type; | |
196 | count = period_size / data_type; | |
4fa9c1a5 | 197 | if (fifo_level) |
7c21a781 | 198 | count /= fifo_level; |
310355c1 VB |
199 | |
200 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | |
201 | src = dma_pos; | |
202 | dst = prtd->params->dma_addr; | |
203 | src_bidx = data_type; | |
2952b27e | 204 | dst_bidx = 4; |
7c21a781 | 205 | src_cidx = data_type * fifo_level; |
4fa9c1a5 | 206 | dst_cidx = 0; |
310355c1 VB |
207 | } else { |
208 | src = prtd->params->dma_addr; | |
209 | dst = dma_pos; | |
210 | src_bidx = 0; | |
211 | dst_bidx = data_type; | |
4fa9c1a5 | 212 | src_cidx = 0; |
7c21a781 | 213 | dst_cidx = data_type * fifo_level; |
310355c1 VB |
214 | } |
215 | ||
6a99fb5f | 216 | acnt = prtd->params->acnt; |
be4ff961 BG |
217 | edma_set_src(prtd->asp_link[0], src, INCR, W8BIT); |
218 | edma_set_dest(prtd->asp_link[0], dst, INCR, W8BIT); | |
4fa9c1a5 | 219 | |
be4ff961 BG |
220 | edma_set_src_index(prtd->asp_link[0], src_bidx, src_cidx); |
221 | edma_set_dest_index(prtd->asp_link[0], dst_bidx, dst_cidx); | |
4fa9c1a5 C |
222 | |
223 | if (!fifo_level) | |
be4ff961 BG |
224 | edma_set_transfer_params(prtd->asp_link[0], acnt, count, 1, 0, |
225 | ASYNC); | |
4fa9c1a5 | 226 | else |
2952b27e | 227 | edma_set_transfer_params(prtd->asp_link[0], acnt, |
7c21a781 MB |
228 | fifo_level, |
229 | count, fifo_level, | |
2952b27e | 230 | ABSYNC); |
310355c1 VB |
231 | } |
232 | ||
1587ea31 | 233 | static void davinci_pcm_dma_irq(unsigned link, u16 ch_status, void *data) |
310355c1 VB |
234 | { |
235 | struct snd_pcm_substream *substream = data; | |
236 | struct davinci_runtime_data *prtd = substream->runtime->private_data; | |
237 | ||
1e224f32 | 238 | print_buf_info(prtd->ram_channel, "i ram_channel"); |
1587ea31 | 239 | pr_debug("davinci_pcm: link=%d, status=0x%x\n", link, ch_status); |
310355c1 VB |
240 | |
241 | if (unlikely(ch_status != DMA_COMPLETE)) | |
242 | return; | |
243 | ||
244 | if (snd_pcm_running(substream)) { | |
52e2c5d3 | 245 | spin_lock(&prtd->lock); |
1e224f32 TK |
246 | if (prtd->ram_channel < 0) { |
247 | /* No ping/pong must fix up link dma data*/ | |
1e224f32 | 248 | davinci_pcm_enqueue_dma(substream); |
1e224f32 | 249 | } |
52e2c5d3 BG |
250 | davinci_pcm_period_elapsed(substream); |
251 | spin_unlock(&prtd->lock); | |
310355c1 | 252 | snd_pcm_period_elapsed(substream); |
1e224f32 TK |
253 | } |
254 | } | |
255 | ||
b8ec56d8 MP |
256 | #ifdef CONFIG_GENERIC_ALLOCATOR |
257 | static int allocate_sram(struct snd_pcm_substream *substream, | |
258 | struct gen_pool *sram_pool, unsigned size, | |
1e224f32 TK |
259 | struct snd_pcm_hardware *ppcm) |
260 | { | |
261 | struct snd_dma_buffer *buf = &substream->dma_buffer; | |
262 | struct snd_dma_buffer *iram_dma = NULL; | |
263 | dma_addr_t iram_phys = 0; | |
264 | void *iram_virt = NULL; | |
265 | ||
266 | if (buf->private_data || !size) | |
267 | return 0; | |
268 | ||
269 | ppcm->period_bytes_max = size; | |
b8ec56d8 | 270 | iram_virt = (void *)gen_pool_alloc(sram_pool, size); |
1e224f32 TK |
271 | if (!iram_virt) |
272 | goto exit1; | |
b8ec56d8 | 273 | iram_phys = gen_pool_virt_to_phys(sram_pool, (unsigned)iram_virt); |
1e224f32 TK |
274 | iram_dma = kzalloc(sizeof(*iram_dma), GFP_KERNEL); |
275 | if (!iram_dma) | |
276 | goto exit2; | |
277 | iram_dma->area = iram_virt; | |
278 | iram_dma->addr = iram_phys; | |
279 | memset(iram_dma->area, 0, size); | |
280 | iram_dma->bytes = size; | |
281 | buf->private_data = iram_dma; | |
282 | return 0; | |
283 | exit2: | |
284 | if (iram_virt) | |
b8ec56d8 | 285 | gen_pool_free(sram_pool, (unsigned)iram_virt, size); |
1e224f32 TK |
286 | exit1: |
287 | return -ENOMEM; | |
288 | } | |
310355c1 | 289 | |
b8ec56d8 MP |
290 | static void davinci_free_sram(struct snd_pcm_substream *substream, |
291 | struct snd_dma_buffer *iram_dma) | |
292 | { | |
293 | struct davinci_runtime_data *prtd = substream->runtime->private_data; | |
294 | struct gen_pool *sram_pool = prtd->params->sram_pool; | |
295 | ||
296 | gen_pool_free(sram_pool, (unsigned) iram_dma->area, iram_dma->bytes); | |
297 | } | |
298 | #else | |
299 | static int allocate_sram(struct snd_pcm_substream *substream, | |
300 | struct gen_pool *sram_pool, unsigned size, | |
301 | struct snd_pcm_hardware *ppcm) | |
302 | { | |
303 | return 0; | |
304 | } | |
305 | ||
306 | static void davinci_free_sram(struct snd_pcm_substream *substream, | |
307 | struct snd_dma_buffer *iram_dma) | |
308 | { | |
309 | } | |
310 | #endif | |
311 | ||
1e224f32 TK |
312 | /* |
313 | * Only used with ping/pong. | |
314 | * This is called after runtime->dma_addr, period_bytes and data_type are valid | |
315 | */ | |
316 | static int ping_pong_dma_setup(struct snd_pcm_substream *substream) | |
317 | { | |
318 | unsigned short ram_src_cidx, ram_dst_cidx; | |
319 | struct snd_pcm_runtime *runtime = substream->runtime; | |
320 | struct davinci_runtime_data *prtd = runtime->private_data; | |
321 | struct snd_dma_buffer *iram_dma = | |
322 | (struct snd_dma_buffer *)substream->dma_buffer.private_data; | |
323 | struct davinci_pcm_dma_params *params = prtd->params; | |
324 | unsigned int data_type = params->data_type; | |
325 | unsigned int acnt = params->acnt; | |
326 | /* divide by 2 for ping/pong */ | |
327 | unsigned int ping_size = snd_pcm_lib_period_bytes(substream) >> 1; | |
1e224f32 TK |
328 | unsigned int fifo_level = prtd->params->fifo_level; |
329 | unsigned int count; | |
330 | if ((data_type == 0) || (data_type > 4)) { | |
331 | printk(KERN_ERR "%s: data_type=%i\n", __func__, data_type); | |
332 | return -EINVAL; | |
333 | } | |
334 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | |
335 | dma_addr_t asp_src_pong = iram_dma->addr + ping_size; | |
336 | ram_src_cidx = ping_size; | |
337 | ram_dst_cidx = -ping_size; | |
be4ff961 | 338 | edma_set_src(prtd->asp_link[1], asp_src_pong, INCR, W8BIT); |
1e224f32 | 339 | |
be4ff961 BG |
340 | edma_set_src_index(prtd->asp_link[0], data_type, |
341 | data_type * fifo_level); | |
342 | edma_set_src_index(prtd->asp_link[1], data_type, | |
343 | data_type * fifo_level); | |
1e224f32 | 344 | |
be4ff961 | 345 | edma_set_src(prtd->ram_link, runtime->dma_addr, INCR, W32BIT); |
1e224f32 TK |
346 | } else { |
347 | dma_addr_t asp_dst_pong = iram_dma->addr + ping_size; | |
348 | ram_src_cidx = -ping_size; | |
349 | ram_dst_cidx = ping_size; | |
be4ff961 | 350 | edma_set_dest(prtd->asp_link[1], asp_dst_pong, INCR, W8BIT); |
1e224f32 | 351 | |
be4ff961 BG |
352 | edma_set_dest_index(prtd->asp_link[0], data_type, |
353 | data_type * fifo_level); | |
354 | edma_set_dest_index(prtd->asp_link[1], data_type, | |
355 | data_type * fifo_level); | |
1e224f32 | 356 | |
be4ff961 | 357 | edma_set_dest(prtd->ram_link, runtime->dma_addr, INCR, W32BIT); |
1e224f32 TK |
358 | } |
359 | ||
360 | if (!fifo_level) { | |
361 | count = ping_size / data_type; | |
362 | edma_set_transfer_params(prtd->asp_link[0], acnt, count, | |
363 | 1, 0, ASYNC); | |
364 | edma_set_transfer_params(prtd->asp_link[1], acnt, count, | |
365 | 1, 0, ASYNC); | |
366 | } else { | |
367 | count = ping_size / (data_type * fifo_level); | |
368 | edma_set_transfer_params(prtd->asp_link[0], acnt, fifo_level, | |
369 | count, fifo_level, ABSYNC); | |
370 | edma_set_transfer_params(prtd->asp_link[1], acnt, fifo_level, | |
371 | count, fifo_level, ABSYNC); | |
372 | } | |
373 | ||
be4ff961 BG |
374 | edma_set_src_index(prtd->ram_link, ping_size, ram_src_cidx); |
375 | edma_set_dest_index(prtd->ram_link, ping_size, ram_dst_cidx); | |
376 | edma_set_transfer_params(prtd->ram_link, ping_size, 2, | |
1e224f32 TK |
377 | runtime->periods, 2, ASYNC); |
378 | ||
379 | /* init master params */ | |
380 | edma_read_slot(prtd->asp_link[0], &prtd->asp_params); | |
381 | edma_read_slot(prtd->ram_link, &prtd->ram_params); | |
382 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | |
383 | struct edmacc_param p_ram; | |
384 | /* Copy entire iram buffer before playback started */ | |
385 | prtd->ram_params.a_b_cnt = (1 << 16) | (ping_size << 1); | |
386 | /* 0 dst_bidx */ | |
387 | prtd->ram_params.src_dst_bidx = (ping_size << 1); | |
388 | /* 0 dst_cidx */ | |
389 | prtd->ram_params.src_dst_cidx = (ping_size << 1); | |
390 | prtd->ram_params.ccnt = 1; | |
391 | ||
392 | /* Skip 1st period */ | |
393 | edma_read_slot(prtd->ram_link, &p_ram); | |
394 | p_ram.src += (ping_size << 1); | |
395 | p_ram.ccnt -= 1; | |
396 | edma_write_slot(prtd->ram_link2, &p_ram); | |
397 | /* | |
398 | * When 1st started, ram -> iram dma channel will fill the | |
399 | * entire iram. Then, whenever a ping/pong asp buffer finishes, | |
400 | * 1/2 iram will be filled. | |
401 | */ | |
402 | prtd->ram_params.link_bcntrld = | |
403 | EDMA_CHAN_SLOT(prtd->ram_link2) << 5; | |
404 | } | |
405 | return 0; | |
406 | } | |
407 | ||
408 | /* 1 asp tx or rx channel using 2 parameter channels | |
409 | * 1 ram to/from iram channel using 1 parameter channel | |
410 | * | |
411 | * Playback | |
412 | * ram copy channel kicks off first, | |
413 | * 1st ram copy of entire iram buffer completion kicks off asp channel | |
414 | * asp tcc always kicks off ram copy of 1/2 iram buffer | |
415 | * | |
416 | * Record | |
417 | * asp channel starts, tcc kicks off ram copy | |
418 | */ | |
419 | static int request_ping_pong(struct snd_pcm_substream *substream, | |
420 | struct davinci_runtime_data *prtd, | |
421 | struct snd_dma_buffer *iram_dma) | |
422 | { | |
423 | dma_addr_t asp_src_ping; | |
424 | dma_addr_t asp_dst_ping; | |
be4ff961 | 425 | int ret; |
1e224f32 TK |
426 | struct davinci_pcm_dma_params *params = prtd->params; |
427 | ||
428 | /* Request ram master channel */ | |
be4ff961 | 429 | ret = prtd->ram_channel = edma_alloc_channel(EDMA_CHANNEL_ANY, |
1e224f32 | 430 | davinci_pcm_dma_irq, substream, |
48519f0a | 431 | prtd->params->ram_chan_q); |
be4ff961 | 432 | if (ret < 0) |
1e224f32 TK |
433 | goto exit1; |
434 | ||
435 | /* Request ram link channel */ | |
be4ff961 | 436 | ret = prtd->ram_link = edma_alloc_slot( |
1e224f32 | 437 | EDMA_CTLR(prtd->ram_channel), EDMA_SLOT_ANY); |
be4ff961 | 438 | if (ret < 0) |
1e224f32 TK |
439 | goto exit2; |
440 | ||
be4ff961 | 441 | ret = prtd->asp_link[1] = edma_alloc_slot( |
1e224f32 | 442 | EDMA_CTLR(prtd->asp_channel), EDMA_SLOT_ANY); |
be4ff961 | 443 | if (ret < 0) |
1e224f32 TK |
444 | goto exit3; |
445 | ||
446 | prtd->ram_link2 = -1; | |
447 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | |
be4ff961 | 448 | ret = prtd->ram_link2 = edma_alloc_slot( |
1e224f32 | 449 | EDMA_CTLR(prtd->ram_channel), EDMA_SLOT_ANY); |
be4ff961 | 450 | if (ret < 0) |
1e224f32 TK |
451 | goto exit4; |
452 | } | |
453 | /* circle ping-pong buffers */ | |
454 | edma_link(prtd->asp_link[0], prtd->asp_link[1]); | |
455 | edma_link(prtd->asp_link[1], prtd->asp_link[0]); | |
456 | /* circle ram buffers */ | |
457 | edma_link(prtd->ram_link, prtd->ram_link); | |
458 | ||
459 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | |
460 | asp_src_ping = iram_dma->addr; | |
461 | asp_dst_ping = params->dma_addr; /* fifo */ | |
462 | } else { | |
463 | asp_src_ping = params->dma_addr; /* fifo */ | |
464 | asp_dst_ping = iram_dma->addr; | |
310355c1 | 465 | } |
1e224f32 | 466 | /* ping */ |
be4ff961 BG |
467 | edma_set_src(prtd->asp_link[0], asp_src_ping, INCR, W16BIT); |
468 | edma_set_dest(prtd->asp_link[0], asp_dst_ping, INCR, W16BIT); | |
469 | edma_set_src_index(prtd->asp_link[0], 0, 0); | |
470 | edma_set_dest_index(prtd->asp_link[0], 0, 0); | |
1e224f32 | 471 | |
be4ff961 | 472 | edma_read_slot(prtd->asp_link[0], &prtd->asp_params); |
1e224f32 | 473 | prtd->asp_params.opt &= ~(TCCMODE | EDMA_TCC(0x3f) | TCINTEN); |
fb1e9703 BG |
474 | prtd->asp_params.opt |= TCCHEN | |
475 | EDMA_TCC(prtd->ram_channel & 0x3f); | |
be4ff961 | 476 | edma_write_slot(prtd->asp_link[0], &prtd->asp_params); |
1e224f32 TK |
477 | |
478 | /* pong */ | |
be4ff961 BG |
479 | edma_set_src(prtd->asp_link[1], asp_src_ping, INCR, W16BIT); |
480 | edma_set_dest(prtd->asp_link[1], asp_dst_ping, INCR, W16BIT); | |
481 | edma_set_src_index(prtd->asp_link[1], 0, 0); | |
482 | edma_set_dest_index(prtd->asp_link[1], 0, 0); | |
1e224f32 | 483 | |
be4ff961 | 484 | edma_read_slot(prtd->asp_link[1], &prtd->asp_params); |
1e224f32 TK |
485 | prtd->asp_params.opt &= ~(TCCMODE | EDMA_TCC(0x3f)); |
486 | /* interrupt after every pong completion */ | |
487 | prtd->asp_params.opt |= TCINTEN | TCCHEN | | |
fb1e9703 | 488 | EDMA_TCC(prtd->ram_channel & 0x3f); |
be4ff961 | 489 | edma_write_slot(prtd->asp_link[1], &prtd->asp_params); |
1e224f32 TK |
490 | |
491 | /* ram */ | |
be4ff961 BG |
492 | edma_set_src(prtd->ram_link, iram_dma->addr, INCR, W32BIT); |
493 | edma_set_dest(prtd->ram_link, iram_dma->addr, INCR, W32BIT); | |
1e224f32 TK |
494 | pr_debug("%s: audio dma channels/slots in use for ram:%u %u %u," |
495 | "for asp:%u %u %u\n", __func__, | |
496 | prtd->ram_channel, prtd->ram_link, prtd->ram_link2, | |
497 | prtd->asp_channel, prtd->asp_link[0], | |
498 | prtd->asp_link[1]); | |
499 | return 0; | |
500 | exit4: | |
501 | edma_free_channel(prtd->asp_link[1]); | |
502 | prtd->asp_link[1] = -1; | |
503 | exit3: | |
504 | edma_free_channel(prtd->ram_link); | |
505 | prtd->ram_link = -1; | |
506 | exit2: | |
507 | edma_free_channel(prtd->ram_channel); | |
508 | prtd->ram_channel = -1; | |
509 | exit1: | |
be4ff961 | 510 | return ret; |
310355c1 VB |
511 | } |
512 | ||
513 | static int davinci_pcm_dma_request(struct snd_pcm_substream *substream) | |
514 | { | |
1e224f32 | 515 | struct snd_dma_buffer *iram_dma; |
310355c1 | 516 | struct davinci_runtime_data *prtd = substream->runtime->private_data; |
1e224f32 | 517 | struct davinci_pcm_dma_params *params = prtd->params; |
be4ff961 | 518 | int ret; |
310355c1 | 519 | |
1e224f32 TK |
520 | if (!params) |
521 | return -ENODEV; | |
310355c1 | 522 | |
1e224f32 | 523 | /* Request asp master DMA channel */ |
be4ff961 | 524 | ret = prtd->asp_channel = edma_alloc_channel(params->channel, |
48519f0a SN |
525 | davinci_pcm_dma_irq, substream, |
526 | prtd->params->asp_chan_q); | |
be4ff961 | 527 | if (ret < 0) |
1e224f32 TK |
528 | goto exit1; |
529 | ||
530 | /* Request asp link channels */ | |
be4ff961 | 531 | ret = prtd->asp_link[0] = edma_alloc_slot( |
1e224f32 | 532 | EDMA_CTLR(prtd->asp_channel), EDMA_SLOT_ANY); |
be4ff961 | 533 | if (ret < 0) |
1e224f32 TK |
534 | goto exit2; |
535 | ||
536 | iram_dma = (struct snd_dma_buffer *)substream->dma_buffer.private_data; | |
537 | if (iram_dma) { | |
538 | if (request_ping_pong(substream, prtd, iram_dma) == 0) | |
539 | return 0; | |
540 | printk(KERN_WARNING "%s: dma channel allocation failed," | |
541 | "not using sram\n", __func__); | |
310355c1 | 542 | } |
82075af6 DB |
543 | |
544 | /* Issue transfer completion IRQ when the channel completes a | |
545 | * transfer, then always reload from the same slot (by a kind | |
546 | * of loopback link). The completion IRQ handler will update | |
547 | * the reload slot with a new buffer. | |
548 | * | |
549 | * REVISIT save p_ram here after setting up everything except | |
550 | * the buffer and its length (ccnt) ... use it as a template | |
551 | * so davinci_pcm_enqueue_dma() takes less time in IRQ. | |
552 | */ | |
be4ff961 | 553 | edma_read_slot(prtd->asp_link[0], &prtd->asp_params); |
1e224f32 TK |
554 | prtd->asp_params.opt |= TCINTEN | |
555 | EDMA_TCC(EDMA_CHAN_SLOT(prtd->asp_channel)); | |
be4ff961 BG |
556 | prtd->asp_params.link_bcntrld = EDMA_CHAN_SLOT(prtd->asp_link[0]) << 5; |
557 | edma_write_slot(prtd->asp_link[0], &prtd->asp_params); | |
310355c1 | 558 | return 0; |
1e224f32 TK |
559 | exit2: |
560 | edma_free_channel(prtd->asp_channel); | |
561 | prtd->asp_channel = -1; | |
562 | exit1: | |
be4ff961 | 563 | return ret; |
310355c1 VB |
564 | } |
565 | ||
566 | static int davinci_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | |
567 | { | |
568 | struct davinci_runtime_data *prtd = substream->runtime->private_data; | |
569 | int ret = 0; | |
570 | ||
571 | spin_lock(&prtd->lock); | |
572 | ||
573 | switch (cmd) { | |
574 | case SNDRV_PCM_TRIGGER_START: | |
ef39eb6f BG |
575 | edma_start(prtd->asp_channel); |
576 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && | |
577 | prtd->ram_channel >= 0) { | |
578 | /* copy 1st iram buffer */ | |
579 | edma_start(prtd->ram_channel); | |
580 | } | |
581 | break; | |
310355c1 VB |
582 | case SNDRV_PCM_TRIGGER_RESUME: |
583 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | |
2b7b250d | 584 | edma_resume(prtd->asp_channel); |
310355c1 VB |
585 | break; |
586 | case SNDRV_PCM_TRIGGER_STOP: | |
587 | case SNDRV_PCM_TRIGGER_SUSPEND: | |
588 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | |
2b7b250d | 589 | edma_pause(prtd->asp_channel); |
310355c1 VB |
590 | break; |
591 | default: | |
592 | ret = -EINVAL; | |
593 | break; | |
594 | } | |
595 | ||
596 | spin_unlock(&prtd->lock); | |
597 | ||
598 | return ret; | |
599 | } | |
600 | ||
601 | static int davinci_pcm_prepare(struct snd_pcm_substream *substream) | |
602 | { | |
603 | struct davinci_runtime_data *prtd = substream->runtime->private_data; | |
310355c1 | 604 | |
52e2c5d3 | 605 | davinci_pcm_period_reset(substream); |
1e224f32 TK |
606 | if (prtd->ram_channel >= 0) { |
607 | int ret = ping_pong_dma_setup(substream); | |
608 | if (ret < 0) | |
609 | return ret; | |
610 | ||
611 | edma_write_slot(prtd->ram_channel, &prtd->ram_params); | |
612 | edma_write_slot(prtd->asp_channel, &prtd->asp_params); | |
613 | ||
614 | print_buf_info(prtd->ram_channel, "ram_channel"); | |
615 | print_buf_info(prtd->ram_link, "ram_link"); | |
616 | print_buf_info(prtd->ram_link2, "ram_link2"); | |
617 | print_buf_info(prtd->asp_channel, "asp_channel"); | |
618 | print_buf_info(prtd->asp_link[0], "asp_link[0]"); | |
619 | print_buf_info(prtd->asp_link[1], "asp_link[1]"); | |
620 | ||
bb5b5fd4 BG |
621 | /* |
622 | * There is a phase offset of 2 periods between the position | |
623 | * used by dma setup and the position reported in the pointer | |
624 | * function. | |
625 | * | |
626 | * The phase offset, when not using ping-pong buffers, is due to | |
627 | * the two consecutive calls to davinci_pcm_enqueue_dma() below. | |
628 | * | |
629 | * Whereas here, with ping-pong buffers, the phase is due to | |
630 | * there being an entire buffer transfer complete before the | |
631 | * first dma completion event triggers davinci_pcm_dma_irq(). | |
632 | */ | |
52e2c5d3 BG |
633 | davinci_pcm_period_elapsed(substream); |
634 | davinci_pcm_period_elapsed(substream); | |
635 | ||
1e224f32 TK |
636 | return 0; |
637 | } | |
310355c1 | 638 | davinci_pcm_enqueue_dma(substream); |
52e2c5d3 | 639 | davinci_pcm_period_elapsed(substream); |
310355c1 | 640 | |
82075af6 | 641 | /* Copy self-linked parameter RAM entry into master channel */ |
1e224f32 TK |
642 | edma_read_slot(prtd->asp_link[0], &prtd->asp_params); |
643 | edma_write_slot(prtd->asp_channel, &prtd->asp_params); | |
6e541475 | 644 | davinci_pcm_enqueue_dma(substream); |
52e2c5d3 | 645 | davinci_pcm_period_elapsed(substream); |
310355c1 VB |
646 | |
647 | return 0; | |
648 | } | |
649 | ||
650 | static snd_pcm_uframes_t | |
651 | davinci_pcm_pointer(struct snd_pcm_substream *substream) | |
652 | { | |
653 | struct snd_pcm_runtime *runtime = substream->runtime; | |
654 | struct davinci_runtime_data *prtd = runtime->private_data; | |
655 | unsigned int offset; | |
1587ea31 | 656 | int asp_count; |
52e2c5d3 | 657 | unsigned int period_size = snd_pcm_lib_period_bytes(substream); |
310355c1 | 658 | |
bb5b5fd4 BG |
659 | /* |
660 | * There is a phase offset of 2 periods between the position used by dma | |
661 | * setup and the position reported in the pointer function. Either +2 in | |
662 | * the dma setup or -2 here in the pointer function (with wrapping, | |
663 | * both) accounts for this offset -- choose the latter since it makes | |
664 | * the first-time setup clearer. | |
665 | */ | |
310355c1 | 666 | spin_lock(&prtd->lock); |
52e2c5d3 | 667 | asp_count = prtd->period - 2; |
310355c1 VB |
668 | spin_unlock(&prtd->lock); |
669 | ||
52e2c5d3 BG |
670 | if (asp_count < 0) |
671 | asp_count += runtime->periods; | |
672 | asp_count *= period_size; | |
673 | ||
1587ea31 | 674 | offset = bytes_to_frames(runtime, asp_count); |
310355c1 VB |
675 | if (offset >= runtime->buffer_size) |
676 | offset = 0; | |
677 | ||
678 | return offset; | |
679 | } | |
680 | ||
681 | static int davinci_pcm_open(struct snd_pcm_substream *substream) | |
682 | { | |
683 | struct snd_pcm_runtime *runtime = substream->runtime; | |
684 | struct davinci_runtime_data *prtd; | |
1e224f32 | 685 | struct snd_pcm_hardware *ppcm; |
310355c1 | 686 | int ret = 0; |
81ac55aa | 687 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
5f712b2b | 688 | struct davinci_pcm_dma_params *pa; |
57512c64 | 689 | struct davinci_pcm_dma_params *params; |
5f712b2b | 690 | |
f0fba2ad | 691 | pa = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); |
57512c64 | 692 | if (!pa) |
81ac55aa | 693 | return -ENODEV; |
57512c64 | 694 | params = &pa[substream->stream]; |
310355c1 | 695 | |
1e224f32 TK |
696 | ppcm = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? |
697 | &pcm_hardware_playback : &pcm_hardware_capture; | |
b8ec56d8 | 698 | allocate_sram(substream, params->sram_pool, params->sram_size, ppcm); |
1e224f32 | 699 | snd_soc_set_runtime_hwparams(substream, ppcm); |
6a90d536 TK |
700 | /* ensure that buffer size is a multiple of period size */ |
701 | ret = snd_pcm_hw_constraint_integer(runtime, | |
702 | SNDRV_PCM_HW_PARAM_PERIODS); | |
703 | if (ret < 0) | |
704 | return ret; | |
310355c1 VB |
705 | |
706 | prtd = kzalloc(sizeof(struct davinci_runtime_data), GFP_KERNEL); | |
707 | if (prtd == NULL) | |
708 | return -ENOMEM; | |
709 | ||
710 | spin_lock_init(&prtd->lock); | |
81ac55aa | 711 | prtd->params = params; |
1e224f32 TK |
712 | prtd->asp_channel = -1; |
713 | prtd->asp_link[0] = prtd->asp_link[1] = -1; | |
714 | prtd->ram_channel = -1; | |
715 | prtd->ram_link = -1; | |
716 | prtd->ram_link2 = -1; | |
310355c1 VB |
717 | |
718 | runtime->private_data = prtd; | |
719 | ||
720 | ret = davinci_pcm_dma_request(substream); | |
721 | if (ret) { | |
722 | printk(KERN_ERR "davinci_pcm: Failed to get dma channels\n"); | |
723 | kfree(prtd); | |
724 | } | |
725 | ||
726 | return ret; | |
727 | } | |
728 | ||
729 | static int davinci_pcm_close(struct snd_pcm_substream *substream) | |
730 | { | |
731 | struct snd_pcm_runtime *runtime = substream->runtime; | |
732 | struct davinci_runtime_data *prtd = runtime->private_data; | |
733 | ||
1e224f32 TK |
734 | if (prtd->ram_channel >= 0) |
735 | edma_stop(prtd->ram_channel); | |
736 | if (prtd->asp_channel >= 0) | |
737 | edma_stop(prtd->asp_channel); | |
738 | if (prtd->asp_link[0] >= 0) | |
739 | edma_unlink(prtd->asp_link[0]); | |
740 | if (prtd->asp_link[1] >= 0) | |
741 | edma_unlink(prtd->asp_link[1]); | |
742 | if (prtd->ram_link >= 0) | |
743 | edma_unlink(prtd->ram_link); | |
744 | ||
745 | if (prtd->asp_link[0] >= 0) | |
746 | edma_free_slot(prtd->asp_link[0]); | |
747 | if (prtd->asp_link[1] >= 0) | |
748 | edma_free_slot(prtd->asp_link[1]); | |
749 | if (prtd->asp_channel >= 0) | |
750 | edma_free_channel(prtd->asp_channel); | |
751 | if (prtd->ram_link >= 0) | |
752 | edma_free_slot(prtd->ram_link); | |
753 | if (prtd->ram_link2 >= 0) | |
754 | edma_free_slot(prtd->ram_link2); | |
755 | if (prtd->ram_channel >= 0) | |
756 | edma_free_channel(prtd->ram_channel); | |
310355c1 VB |
757 | |
758 | kfree(prtd); | |
759 | ||
760 | return 0; | |
761 | } | |
762 | ||
763 | static int davinci_pcm_hw_params(struct snd_pcm_substream *substream, | |
764 | struct snd_pcm_hw_params *hw_params) | |
765 | { | |
766 | return snd_pcm_lib_malloc_pages(substream, | |
767 | params_buffer_bytes(hw_params)); | |
768 | } | |
769 | ||
770 | static int davinci_pcm_hw_free(struct snd_pcm_substream *substream) | |
771 | { | |
772 | return snd_pcm_lib_free_pages(substream); | |
773 | } | |
774 | ||
775 | static int davinci_pcm_mmap(struct snd_pcm_substream *substream, | |
776 | struct vm_area_struct *vma) | |
777 | { | |
778 | struct snd_pcm_runtime *runtime = substream->runtime; | |
779 | ||
780 | return dma_mmap_writecombine(substream->pcm->card->dev, vma, | |
781 | runtime->dma_area, | |
782 | runtime->dma_addr, | |
783 | runtime->dma_bytes); | |
784 | } | |
785 | ||
b2a19d02 | 786 | static struct snd_pcm_ops davinci_pcm_ops = { |
310355c1 VB |
787 | .open = davinci_pcm_open, |
788 | .close = davinci_pcm_close, | |
789 | .ioctl = snd_pcm_lib_ioctl, | |
790 | .hw_params = davinci_pcm_hw_params, | |
791 | .hw_free = davinci_pcm_hw_free, | |
792 | .prepare = davinci_pcm_prepare, | |
793 | .trigger = davinci_pcm_trigger, | |
794 | .pointer = davinci_pcm_pointer, | |
795 | .mmap = davinci_pcm_mmap, | |
796 | }; | |
797 | ||
1e224f32 TK |
798 | static int davinci_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream, |
799 | size_t size) | |
310355c1 VB |
800 | { |
801 | struct snd_pcm_substream *substream = pcm->streams[stream].substream; | |
802 | struct snd_dma_buffer *buf = &substream->dma_buffer; | |
310355c1 VB |
803 | |
804 | buf->dev.type = SNDRV_DMA_TYPE_DEV; | |
805 | buf->dev.dev = pcm->card->dev; | |
806 | buf->private_data = NULL; | |
807 | buf->area = dma_alloc_writecombine(pcm->card->dev, size, | |
808 | &buf->addr, GFP_KERNEL); | |
809 | ||
9cd28ab0 AB |
810 | pr_debug("davinci_pcm: preallocate_dma_buffer: area=%p, addr=%p, " |
811 | "size=%d\n", (void *) buf->area, (void *) buf->addr, size); | |
310355c1 VB |
812 | |
813 | if (!buf->area) | |
814 | return -ENOMEM; | |
815 | ||
816 | buf->bytes = size; | |
817 | return 0; | |
818 | } | |
819 | ||
820 | static void davinci_pcm_free(struct snd_pcm *pcm) | |
821 | { | |
822 | struct snd_pcm_substream *substream; | |
823 | struct snd_dma_buffer *buf; | |
824 | int stream; | |
825 | ||
826 | for (stream = 0; stream < 2; stream++) { | |
1e224f32 | 827 | struct snd_dma_buffer *iram_dma; |
310355c1 VB |
828 | substream = pcm->streams[stream].substream; |
829 | if (!substream) | |
830 | continue; | |
831 | ||
832 | buf = &substream->dma_buffer; | |
833 | if (!buf->area) | |
834 | continue; | |
835 | ||
836 | dma_free_writecombine(pcm->card->dev, buf->bytes, | |
837 | buf->area, buf->addr); | |
838 | buf->area = NULL; | |
4726a57b | 839 | iram_dma = buf->private_data; |
1e224f32 | 840 | if (iram_dma) { |
b8ec56d8 | 841 | davinci_free_sram(substream, iram_dma); |
1e224f32 TK |
842 | kfree(iram_dma); |
843 | } | |
310355c1 VB |
844 | } |
845 | } | |
846 | ||
350e16d5 | 847 | static u64 davinci_pcm_dmamask = DMA_BIT_MASK(32); |
310355c1 | 848 | |
552d1ef6 | 849 | static int davinci_pcm_new(struct snd_soc_pcm_runtime *rtd) |
310355c1 | 850 | { |
552d1ef6 | 851 | struct snd_card *card = rtd->card->snd_card; |
552d1ef6 | 852 | struct snd_pcm *pcm = rtd->pcm; |
310355c1 VB |
853 | int ret; |
854 | ||
855 | if (!card->dev->dma_mask) | |
856 | card->dev->dma_mask = &davinci_pcm_dmamask; | |
857 | if (!card->dev->coherent_dma_mask) | |
350e16d5 | 858 | card->dev->coherent_dma_mask = DMA_BIT_MASK(32); |
310355c1 | 859 | |
25e9e756 | 860 | if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { |
310355c1 | 861 | ret = davinci_pcm_preallocate_dma_buffer(pcm, |
1e224f32 TK |
862 | SNDRV_PCM_STREAM_PLAYBACK, |
863 | pcm_hardware_playback.buffer_bytes_max); | |
310355c1 VB |
864 | if (ret) |
865 | return ret; | |
866 | } | |
867 | ||
25e9e756 | 868 | if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { |
310355c1 | 869 | ret = davinci_pcm_preallocate_dma_buffer(pcm, |
1e224f32 TK |
870 | SNDRV_PCM_STREAM_CAPTURE, |
871 | pcm_hardware_capture.buffer_bytes_max); | |
310355c1 VB |
872 | if (ret) |
873 | return ret; | |
874 | } | |
875 | ||
876 | return 0; | |
877 | } | |
878 | ||
f0fba2ad LG |
879 | static struct snd_soc_platform_driver davinci_soc_platform = { |
880 | .ops = &davinci_pcm_ops, | |
310355c1 VB |
881 | .pcm_new = davinci_pcm_new, |
882 | .pcm_free = davinci_pcm_free, | |
883 | }; | |
310355c1 | 884 | |
f08095a4 | 885 | int davinci_soc_platform_register(struct device *dev) |
958e792c | 886 | { |
f08095a4 | 887 | return snd_soc_register_platform(dev, &davinci_soc_platform); |
958e792c | 888 | } |
f08095a4 | 889 | EXPORT_SYMBOL_GPL(davinci_soc_platform_register); |
958e792c | 890 | |
f08095a4 | 891 | void davinci_soc_platform_unregister(struct device *dev) |
958e792c | 892 | { |
f08095a4 | 893 | snd_soc_unregister_platform(dev); |
f0fba2ad | 894 | } |
f08095a4 | 895 | EXPORT_SYMBOL_GPL(davinci_soc_platform_unregister); |
958e792c | 896 | |
310355c1 VB |
897 | MODULE_AUTHOR("Vladimir Barinov"); |
898 | MODULE_DESCRIPTION("TI DAVINCI PCM DMA module"); | |
899 | MODULE_LICENSE("GPL"); |