blob: fedca81b67b4d29d7f741f71afd4e7830169ff84 [file] [log] [blame]
Vladimir Barinov310355c2008-02-18 11:40:22 +01001/*
2 * ALSA PCM interface for the TI DAVINCI processor
3 *
Vladimir Barinovd6b52032008-09-29 23:14:11 +04004 * Author: Vladimir Barinov, <vbarinov@embeddedalley.com>
Vladimir Barinov310355c2008-02-18 11:40:22 +01005 * Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.com>
Troy Kisky1e224f32009-11-18 17:49:53 -07006 * added SRAM ping/pong (C) 2008 Troy Kisky <troy.kisky@boundarydevices.com>
Vladimir Barinov310355c2008-02-18 11:40:22 +01007 *
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>
Alexander Beregalov9cd28ab2008-12-13 16:25:27 +030018#include <linux/kernel.h>
Vladimir Barinov310355c2008-02-18 11:40:22 +010019
20#include <sound/core.h>
21#include <sound/pcm.h>
22#include <sound/pcm_params.h>
23#include <sound/soc.h>
24
25#include <asm/dma.h>
David Brownell82075af2009-05-14 12:41:22 -070026#include <mach/edma.h>
Troy Kisky1e224f32009-11-18 17:49:53 -070027#include <mach/sram.h>
Vladimir Barinov310355c2008-02-18 11:40:22 +010028
29#include "davinci-pcm.h"
30
Troy Kisky1e224f32009-11-18 17:49:53 -070031#ifdef DEBUG
32static 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
44static void print_buf_info(int slot, char *name)
45{
46}
47#endif
48
Ben Gardiner8e56d5b2011-05-24 14:50:16 -040049#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
Troy Kisky1e224f32009-11-18 17:49:53 -070065static struct snd_pcm_hardware pcm_hardware_playback = {
Vladimir Barinov310355c2008-02-18 11:40:22 +010066 .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
67 SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
Chaithrika U Sa47979b2009-12-03 18:56:56 +053068 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
Ben Gardiner8e56d5b2011-05-24 14:50:16 -040069 .formats = DAVINCI_PCM_FMTBITS,
Vladimir Barinov310355c2008-02-18 11:40:22 +010070 .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
71 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
72 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
73 SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
74 SNDRV_PCM_RATE_KNOT),
75 .rate_min = 8000,
76 .rate_max = 96000,
77 .channels_min = 2,
Ben Gardineracb8e262011-05-24 14:50:17 -040078 .channels_max = 384,
Vladimir Barinov310355c2008-02-18 11:40:22 +010079 .buffer_bytes_max = 128 * 1024,
80 .period_bytes_min = 32,
81 .period_bytes_max = 8 * 1024,
82 .periods_min = 16,
83 .periods_max = 255,
84 .fifo_size = 0,
85};
86
Troy Kisky1e224f32009-11-18 17:49:53 -070087static struct snd_pcm_hardware pcm_hardware_capture = {
88 .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
89 SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
90 SNDRV_PCM_INFO_PAUSE),
Ben Gardiner8e56d5b2011-05-24 14:50:16 -040091 .formats = DAVINCI_PCM_FMTBITS,
Troy Kisky1e224f32009-11-18 17:49:53 -070092 .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
93 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
94 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
95 SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
96 SNDRV_PCM_RATE_KNOT),
97 .rate_min = 8000,
98 .rate_max = 96000,
99 .channels_min = 2,
Ben Gardineracb8e262011-05-24 14:50:17 -0400100 .channels_max = 384,
Troy Kisky1e224f32009-11-18 17:49:53 -0700101 .buffer_bytes_max = 128 * 1024,
102 .period_bytes_min = 32,
103 .period_bytes_max = 8 * 1024,
104 .periods_min = 16,
105 .periods_max = 255,
106 .fifo_size = 0,
107};
108
109/*
110 * How ping/pong works....
111 *
112 * Playback:
113 * ram_params - copys 2*ping_size from start of SDRAM to iram,
114 * links to ram_link2
115 * ram_link2 - copys rest of SDRAM to iram in ping_size units,
116 * links to ram_link
117 * ram_link - copys entire SDRAM to iram in ping_size uints,
118 * links to self
119 *
120 * asp_params - same as asp_link[0]
121 * asp_link[0] - copys from lower half of iram to asp port
122 * links to asp_link[1], triggers iram copy event on completion
123 * asp_link[1] - copys from upper half of iram to asp port
124 * links to asp_link[0], triggers iram copy event on completion
125 * triggers interrupt only needed to let upper SOC levels update position
126 * in stream on completion
127 *
128 * When playback is started:
129 * ram_params started
130 * asp_params started
131 *
132 * Capture:
133 * ram_params - same as ram_link,
134 * links to ram_link
135 * ram_link - same as playback
136 * links to self
137 *
138 * asp_params - same as playback
139 * asp_link[0] - same as playback
140 * asp_link[1] - same as playback
141 *
142 * When capture is started:
143 * asp_params started
144 */
Vladimir Barinov310355c2008-02-18 11:40:22 +0100145struct davinci_runtime_data {
146 spinlock_t lock;
147 int period; /* current DMA period */
Troy Kisky1587ea312009-11-18 17:49:52 -0700148 int asp_channel; /* Master DMA channel */
149 int asp_link[2]; /* asp parameter link channel, ping/pong */
Vladimir Barinov310355c2008-02-18 11:40:22 +0100150 struct davinci_pcm_dma_params *params; /* DMA params */
Troy Kisky1e224f32009-11-18 17:49:53 -0700151 int ram_channel;
152 int ram_link;
153 int ram_link2;
154 struct edmacc_param asp_params;
155 struct edmacc_param ram_params;
Vladimir Barinov310355c2008-02-18 11:40:22 +0100156};
157
Ben Gardiner10ab3bf2011-05-24 14:50:19 -0400158static void davinci_pcm_period_elapsed(struct snd_pcm_substream *substream)
159{
160 struct davinci_runtime_data *prtd = substream->runtime->private_data;
161 struct snd_pcm_runtime *runtime = substream->runtime;
162
163 prtd->period++;
164 if (unlikely(prtd->period >= runtime->periods))
165 prtd->period = 0;
166}
167
168static void davinci_pcm_period_reset(struct snd_pcm_substream *substream)
169{
170 struct davinci_runtime_data *prtd = substream->runtime->private_data;
171
172 prtd->period = 0;
173}
Troy Kisky1e224f32009-11-18 17:49:53 -0700174/*
175 * Not used with ping/pong
176 */
Vladimir Barinov310355c2008-02-18 11:40:22 +0100177static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream)
178{
179 struct davinci_runtime_data *prtd = substream->runtime->private_data;
180 struct snd_pcm_runtime *runtime = substream->runtime;
Troy Kisky1587ea312009-11-18 17:49:52 -0700181 int link = prtd->asp_link[0];
Vladimir Barinov310355c2008-02-18 11:40:22 +0100182 unsigned int period_size;
183 unsigned int dma_offset;
184 dma_addr_t dma_pos;
185 dma_addr_t src, dst;
186 unsigned short src_bidx, dst_bidx;
Chaithrika U S4fa9c1a2009-09-30 17:32:27 -0400187 unsigned short src_cidx, dst_cidx;
Vladimir Barinov310355c2008-02-18 11:40:22 +0100188 unsigned int data_type;
Chaithrika U S6a99fb52009-08-11 16:58:52 -0400189 unsigned short acnt;
Vladimir Barinov310355c2008-02-18 11:40:22 +0100190 unsigned int count;
Chaithrika U S4fa9c1a2009-09-30 17:32:27 -0400191 unsigned int fifo_level;
Vladimir Barinov310355c2008-02-18 11:40:22 +0100192
193 period_size = snd_pcm_lib_period_bytes(substream);
194 dma_offset = prtd->period * period_size;
195 dma_pos = runtime->dma_addr + dma_offset;
Chaithrika U S4fa9c1a2009-09-30 17:32:27 -0400196 fifo_level = prtd->params->fifo_level;
Vladimir Barinov310355c2008-02-18 11:40:22 +0100197
Alexander Beregalov9cd28ab2008-12-13 16:25:27 +0300198 pr_debug("davinci_pcm: audio_set_dma_params_play channel = %d "
Troy Kisky1587ea312009-11-18 17:49:52 -0700199 "dma_ptr = %x period_size=%x\n", link, dma_pos, period_size);
Vladimir Barinov310355c2008-02-18 11:40:22 +0100200
201 data_type = prtd->params->data_type;
202 count = period_size / data_type;
Chaithrika U S4fa9c1a2009-09-30 17:32:27 -0400203 if (fifo_level)
204 count /= fifo_level;
Vladimir Barinov310355c2008-02-18 11:40:22 +0100205
206 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
207 src = dma_pos;
208 dst = prtd->params->dma_addr;
209 src_bidx = data_type;
210 dst_bidx = 0;
Chaithrika U S4fa9c1a2009-09-30 17:32:27 -0400211 src_cidx = data_type * fifo_level;
212 dst_cidx = 0;
Vladimir Barinov310355c2008-02-18 11:40:22 +0100213 } else {
214 src = prtd->params->dma_addr;
215 dst = dma_pos;
216 src_bidx = 0;
217 dst_bidx = data_type;
Chaithrika U S4fa9c1a2009-09-30 17:32:27 -0400218 src_cidx = 0;
219 dst_cidx = data_type * fifo_level;
Vladimir Barinov310355c2008-02-18 11:40:22 +0100220 }
221
Chaithrika U S6a99fb52009-08-11 16:58:52 -0400222 acnt = prtd->params->acnt;
Troy Kisky1587ea312009-11-18 17:49:52 -0700223 edma_set_src(link, src, INCR, W8BIT);
224 edma_set_dest(link, dst, INCR, W8BIT);
Chaithrika U S4fa9c1a2009-09-30 17:32:27 -0400225
Troy Kisky1587ea312009-11-18 17:49:52 -0700226 edma_set_src_index(link, src_bidx, src_cidx);
227 edma_set_dest_index(link, dst_bidx, dst_cidx);
Chaithrika U S4fa9c1a2009-09-30 17:32:27 -0400228
229 if (!fifo_level)
Troy Kisky1587ea312009-11-18 17:49:52 -0700230 edma_set_transfer_params(link, acnt, count, 1, 0, ASYNC);
Chaithrika U S4fa9c1a2009-09-30 17:32:27 -0400231 else
Troy Kisky1587ea312009-11-18 17:49:52 -0700232 edma_set_transfer_params(link, acnt, fifo_level, count,
Chaithrika U S4fa9c1a2009-09-30 17:32:27 -0400233 fifo_level, ABSYNC);
Vladimir Barinov310355c2008-02-18 11:40:22 +0100234
Ben Gardiner10ab3bf2011-05-24 14:50:19 -0400235 davinci_pcm_period_elapsed(substream);
Vladimir Barinov310355c2008-02-18 11:40:22 +0100236}
237
Troy Kisky1587ea312009-11-18 17:49:52 -0700238static void davinci_pcm_dma_irq(unsigned link, u16 ch_status, void *data)
Vladimir Barinov310355c2008-02-18 11:40:22 +0100239{
240 struct snd_pcm_substream *substream = data;
241 struct davinci_runtime_data *prtd = substream->runtime->private_data;
242
Troy Kisky1e224f32009-11-18 17:49:53 -0700243 print_buf_info(prtd->ram_channel, "i ram_channel");
Troy Kisky1587ea312009-11-18 17:49:52 -0700244 pr_debug("davinci_pcm: link=%d, status=0x%x\n", link, ch_status);
Vladimir Barinov310355c2008-02-18 11:40:22 +0100245
246 if (unlikely(ch_status != DMA_COMPLETE))
247 return;
248
249 if (snd_pcm_running(substream)) {
Troy Kisky1e224f32009-11-18 17:49:53 -0700250 if (prtd->ram_channel < 0) {
251 /* No ping/pong must fix up link dma data*/
252 spin_lock(&prtd->lock);
253 davinci_pcm_enqueue_dma(substream);
254 spin_unlock(&prtd->lock);
255 }
Vladimir Barinov310355c2008-02-18 11:40:22 +0100256 snd_pcm_period_elapsed(substream);
Vladimir Barinov310355c2008-02-18 11:40:22 +0100257 }
258}
259
Troy Kisky1e224f32009-11-18 17:49:53 -0700260static int allocate_sram(struct snd_pcm_substream *substream, unsigned size,
261 struct snd_pcm_hardware *ppcm)
262{
263 struct snd_dma_buffer *buf = &substream->dma_buffer;
264 struct snd_dma_buffer *iram_dma = NULL;
265 dma_addr_t iram_phys = 0;
266 void *iram_virt = NULL;
267
268 if (buf->private_data || !size)
269 return 0;
270
271 ppcm->period_bytes_max = size;
272 iram_virt = sram_alloc(size, &iram_phys);
273 if (!iram_virt)
274 goto exit1;
275 iram_dma = kzalloc(sizeof(*iram_dma), GFP_KERNEL);
276 if (!iram_dma)
277 goto exit2;
278 iram_dma->area = iram_virt;
279 iram_dma->addr = iram_phys;
280 memset(iram_dma->area, 0, size);
281 iram_dma->bytes = size;
282 buf->private_data = iram_dma;
283 return 0;
284exit2:
285 if (iram_virt)
286 sram_free(iram_virt, size);
287exit1:
288 return -ENOMEM;
289}
290
291/*
292 * Only used with ping/pong.
293 * This is called after runtime->dma_addr, period_bytes and data_type are valid
294 */
295static int ping_pong_dma_setup(struct snd_pcm_substream *substream)
296{
297 unsigned short ram_src_cidx, ram_dst_cidx;
298 struct snd_pcm_runtime *runtime = substream->runtime;
299 struct davinci_runtime_data *prtd = runtime->private_data;
300 struct snd_dma_buffer *iram_dma =
301 (struct snd_dma_buffer *)substream->dma_buffer.private_data;
302 struct davinci_pcm_dma_params *params = prtd->params;
303 unsigned int data_type = params->data_type;
304 unsigned int acnt = params->acnt;
305 /* divide by 2 for ping/pong */
306 unsigned int ping_size = snd_pcm_lib_period_bytes(substream) >> 1;
307 int link = prtd->asp_link[1];
308 unsigned int fifo_level = prtd->params->fifo_level;
309 unsigned int count;
310 if ((data_type == 0) || (data_type > 4)) {
311 printk(KERN_ERR "%s: data_type=%i\n", __func__, data_type);
312 return -EINVAL;
313 }
314 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
315 dma_addr_t asp_src_pong = iram_dma->addr + ping_size;
316 ram_src_cidx = ping_size;
317 ram_dst_cidx = -ping_size;
318 edma_set_src(link, asp_src_pong, INCR, W8BIT);
319
320 link = prtd->asp_link[0];
321 edma_set_src_index(link, data_type, data_type * fifo_level);
322 link = prtd->asp_link[1];
323 edma_set_src_index(link, data_type, data_type * fifo_level);
324
325 link = prtd->ram_link;
326 edma_set_src(link, runtime->dma_addr, INCR, W32BIT);
327 } else {
328 dma_addr_t asp_dst_pong = iram_dma->addr + ping_size;
329 ram_src_cidx = -ping_size;
330 ram_dst_cidx = ping_size;
331 edma_set_dest(link, asp_dst_pong, INCR, W8BIT);
332
333 link = prtd->asp_link[0];
334 edma_set_dest_index(link, data_type, data_type * fifo_level);
335 link = prtd->asp_link[1];
336 edma_set_dest_index(link, data_type, data_type * fifo_level);
337
338 link = prtd->ram_link;
339 edma_set_dest(link, runtime->dma_addr, INCR, W32BIT);
340 }
341
342 if (!fifo_level) {
343 count = ping_size / data_type;
344 edma_set_transfer_params(prtd->asp_link[0], acnt, count,
345 1, 0, ASYNC);
346 edma_set_transfer_params(prtd->asp_link[1], acnt, count,
347 1, 0, ASYNC);
348 } else {
349 count = ping_size / (data_type * fifo_level);
350 edma_set_transfer_params(prtd->asp_link[0], acnt, fifo_level,
351 count, fifo_level, ABSYNC);
352 edma_set_transfer_params(prtd->asp_link[1], acnt, fifo_level,
353 count, fifo_level, ABSYNC);
354 }
355
356 link = prtd->ram_link;
357 edma_set_src_index(link, ping_size, ram_src_cidx);
358 edma_set_dest_index(link, ping_size, ram_dst_cidx);
359 edma_set_transfer_params(link, ping_size, 2,
360 runtime->periods, 2, ASYNC);
361
362 /* init master params */
363 edma_read_slot(prtd->asp_link[0], &prtd->asp_params);
364 edma_read_slot(prtd->ram_link, &prtd->ram_params);
365 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
366 struct edmacc_param p_ram;
367 /* Copy entire iram buffer before playback started */
368 prtd->ram_params.a_b_cnt = (1 << 16) | (ping_size << 1);
369 /* 0 dst_bidx */
370 prtd->ram_params.src_dst_bidx = (ping_size << 1);
371 /* 0 dst_cidx */
372 prtd->ram_params.src_dst_cidx = (ping_size << 1);
373 prtd->ram_params.ccnt = 1;
374
375 /* Skip 1st period */
376 edma_read_slot(prtd->ram_link, &p_ram);
377 p_ram.src += (ping_size << 1);
378 p_ram.ccnt -= 1;
379 edma_write_slot(prtd->ram_link2, &p_ram);
380 /*
381 * When 1st started, ram -> iram dma channel will fill the
382 * entire iram. Then, whenever a ping/pong asp buffer finishes,
383 * 1/2 iram will be filled.
384 */
385 prtd->ram_params.link_bcntrld =
386 EDMA_CHAN_SLOT(prtd->ram_link2) << 5;
387 }
388 return 0;
389}
390
391/* 1 asp tx or rx channel using 2 parameter channels
392 * 1 ram to/from iram channel using 1 parameter channel
393 *
394 * Playback
395 * ram copy channel kicks off first,
396 * 1st ram copy of entire iram buffer completion kicks off asp channel
397 * asp tcc always kicks off ram copy of 1/2 iram buffer
398 *
399 * Record
400 * asp channel starts, tcc kicks off ram copy
401 */
402static int request_ping_pong(struct snd_pcm_substream *substream,
403 struct davinci_runtime_data *prtd,
404 struct snd_dma_buffer *iram_dma)
405{
406 dma_addr_t asp_src_ping;
407 dma_addr_t asp_dst_ping;
408 int link;
409 struct davinci_pcm_dma_params *params = prtd->params;
410
411 /* Request ram master channel */
412 link = prtd->ram_channel = edma_alloc_channel(EDMA_CHANNEL_ANY,
413 davinci_pcm_dma_irq, substream,
Sekhar Nori48519f02010-07-19 12:31:16 +0530414 prtd->params->ram_chan_q);
Troy Kisky1e224f32009-11-18 17:49:53 -0700415 if (link < 0)
416 goto exit1;
417
418 /* Request ram link channel */
419 link = prtd->ram_link = edma_alloc_slot(
420 EDMA_CTLR(prtd->ram_channel), EDMA_SLOT_ANY);
421 if (link < 0)
422 goto exit2;
423
424 link = prtd->asp_link[1] = edma_alloc_slot(
425 EDMA_CTLR(prtd->asp_channel), EDMA_SLOT_ANY);
426 if (link < 0)
427 goto exit3;
428
429 prtd->ram_link2 = -1;
430 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
431 link = prtd->ram_link2 = edma_alloc_slot(
432 EDMA_CTLR(prtd->ram_channel), EDMA_SLOT_ANY);
433 if (link < 0)
434 goto exit4;
435 }
436 /* circle ping-pong buffers */
437 edma_link(prtd->asp_link[0], prtd->asp_link[1]);
438 edma_link(prtd->asp_link[1], prtd->asp_link[0]);
439 /* circle ram buffers */
440 edma_link(prtd->ram_link, prtd->ram_link);
441
442 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
443 asp_src_ping = iram_dma->addr;
444 asp_dst_ping = params->dma_addr; /* fifo */
445 } else {
446 asp_src_ping = params->dma_addr; /* fifo */
447 asp_dst_ping = iram_dma->addr;
448 }
449 /* ping */
450 link = prtd->asp_link[0];
451 edma_set_src(link, asp_src_ping, INCR, W16BIT);
452 edma_set_dest(link, asp_dst_ping, INCR, W16BIT);
453 edma_set_src_index(link, 0, 0);
454 edma_set_dest_index(link, 0, 0);
455
456 edma_read_slot(link, &prtd->asp_params);
457 prtd->asp_params.opt &= ~(TCCMODE | EDMA_TCC(0x3f) | TCINTEN);
Ben Gardinerfb1e97032011-05-24 14:50:15 -0400458 prtd->asp_params.opt |= TCCHEN |
459 EDMA_TCC(prtd->ram_channel & 0x3f);
Troy Kisky1e224f32009-11-18 17:49:53 -0700460 edma_write_slot(link, &prtd->asp_params);
461
462 /* pong */
463 link = prtd->asp_link[1];
464 edma_set_src(link, asp_src_ping, INCR, W16BIT);
465 edma_set_dest(link, asp_dst_ping, INCR, W16BIT);
466 edma_set_src_index(link, 0, 0);
467 edma_set_dest_index(link, 0, 0);
468
469 edma_read_slot(link, &prtd->asp_params);
470 prtd->asp_params.opt &= ~(TCCMODE | EDMA_TCC(0x3f));
471 /* interrupt after every pong completion */
472 prtd->asp_params.opt |= TCINTEN | TCCHEN |
Ben Gardinerfb1e97032011-05-24 14:50:15 -0400473 EDMA_TCC(prtd->ram_channel & 0x3f);
Troy Kisky1e224f32009-11-18 17:49:53 -0700474 edma_write_slot(link, &prtd->asp_params);
475
476 /* ram */
477 link = prtd->ram_link;
478 edma_set_src(link, iram_dma->addr, INCR, W32BIT);
479 edma_set_dest(link, iram_dma->addr, INCR, W32BIT);
480 pr_debug("%s: audio dma channels/slots in use for ram:%u %u %u,"
481 "for asp:%u %u %u\n", __func__,
482 prtd->ram_channel, prtd->ram_link, prtd->ram_link2,
483 prtd->asp_channel, prtd->asp_link[0],
484 prtd->asp_link[1]);
485 return 0;
486exit4:
487 edma_free_channel(prtd->asp_link[1]);
488 prtd->asp_link[1] = -1;
489exit3:
490 edma_free_channel(prtd->ram_link);
491 prtd->ram_link = -1;
492exit2:
493 edma_free_channel(prtd->ram_channel);
494 prtd->ram_channel = -1;
495exit1:
496 return link;
497}
498
Vladimir Barinov310355c2008-02-18 11:40:22 +0100499static int davinci_pcm_dma_request(struct snd_pcm_substream *substream)
500{
Troy Kisky1e224f32009-11-18 17:49:53 -0700501 struct snd_dma_buffer *iram_dma;
Vladimir Barinov310355c2008-02-18 11:40:22 +0100502 struct davinci_runtime_data *prtd = substream->runtime->private_data;
Troy Kisky1e224f32009-11-18 17:49:53 -0700503 struct davinci_pcm_dma_params *params = prtd->params;
504 int link;
Vladimir Barinov310355c2008-02-18 11:40:22 +0100505
Troy Kisky1e224f32009-11-18 17:49:53 -0700506 if (!params)
507 return -ENODEV;
Vladimir Barinov310355c2008-02-18 11:40:22 +0100508
Troy Kisky1e224f32009-11-18 17:49:53 -0700509 /* Request asp master DMA channel */
510 link = prtd->asp_channel = edma_alloc_channel(params->channel,
Sekhar Nori48519f02010-07-19 12:31:16 +0530511 davinci_pcm_dma_irq, substream,
512 prtd->params->asp_chan_q);
Troy Kisky1e224f32009-11-18 17:49:53 -0700513 if (link < 0)
514 goto exit1;
515
516 /* Request asp link channels */
517 link = prtd->asp_link[0] = edma_alloc_slot(
518 EDMA_CTLR(prtd->asp_channel), EDMA_SLOT_ANY);
519 if (link < 0)
520 goto exit2;
521
522 iram_dma = (struct snd_dma_buffer *)substream->dma_buffer.private_data;
523 if (iram_dma) {
524 if (request_ping_pong(substream, prtd, iram_dma) == 0)
525 return 0;
526 printk(KERN_WARNING "%s: dma channel allocation failed,"
527 "not using sram\n", __func__);
Vladimir Barinov310355c2008-02-18 11:40:22 +0100528 }
529
David Brownell82075af2009-05-14 12:41:22 -0700530 /* Issue transfer completion IRQ when the channel completes a
531 * transfer, then always reload from the same slot (by a kind
532 * of loopback link). The completion IRQ handler will update
533 * the reload slot with a new buffer.
534 *
535 * REVISIT save p_ram here after setting up everything except
536 * the buffer and its length (ccnt) ... use it as a template
537 * so davinci_pcm_enqueue_dma() takes less time in IRQ.
538 */
Troy Kisky1e224f32009-11-18 17:49:53 -0700539 edma_read_slot(link, &prtd->asp_params);
540 prtd->asp_params.opt |= TCINTEN |
541 EDMA_TCC(EDMA_CHAN_SLOT(prtd->asp_channel));
542 prtd->asp_params.link_bcntrld = EDMA_CHAN_SLOT(link) << 5;
543 edma_write_slot(link, &prtd->asp_params);
Vladimir Barinov310355c2008-02-18 11:40:22 +0100544 return 0;
Troy Kisky1e224f32009-11-18 17:49:53 -0700545exit2:
546 edma_free_channel(prtd->asp_channel);
547 prtd->asp_channel = -1;
548exit1:
549 return link;
Vladimir Barinov310355c2008-02-18 11:40:22 +0100550}
551
552static int davinci_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
553{
554 struct davinci_runtime_data *prtd = substream->runtime->private_data;
555 int ret = 0;
556
557 spin_lock(&prtd->lock);
558
559 switch (cmd) {
560 case SNDRV_PCM_TRIGGER_START:
Ben Gardineref39eb62011-05-24 14:50:18 -0400561 edma_start(prtd->asp_channel);
562 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
563 prtd->ram_channel >= 0) {
564 /* copy 1st iram buffer */
565 edma_start(prtd->ram_channel);
566 }
567 break;
Vladimir Barinov310355c2008-02-18 11:40:22 +0100568 case SNDRV_PCM_TRIGGER_RESUME:
569 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
Troy Kisky2b7b2502009-11-18 17:49:54 -0700570 edma_resume(prtd->asp_channel);
Vladimir Barinov310355c2008-02-18 11:40:22 +0100571 break;
572 case SNDRV_PCM_TRIGGER_STOP:
573 case SNDRV_PCM_TRIGGER_SUSPEND:
574 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
Troy Kisky2b7b2502009-11-18 17:49:54 -0700575 edma_pause(prtd->asp_channel);
Vladimir Barinov310355c2008-02-18 11:40:22 +0100576 break;
577 default:
578 ret = -EINVAL;
579 break;
580 }
581
582 spin_unlock(&prtd->lock);
583
584 return ret;
585}
586
587static int davinci_pcm_prepare(struct snd_pcm_substream *substream)
588{
589 struct davinci_runtime_data *prtd = substream->runtime->private_data;
Vladimir Barinov310355c2008-02-18 11:40:22 +0100590
Troy Kisky1e224f32009-11-18 17:49:53 -0700591 if (prtd->ram_channel >= 0) {
592 int ret = ping_pong_dma_setup(substream);
593 if (ret < 0)
594 return ret;
595
596 edma_write_slot(prtd->ram_channel, &prtd->ram_params);
597 edma_write_slot(prtd->asp_channel, &prtd->asp_params);
598
599 print_buf_info(prtd->ram_channel, "ram_channel");
600 print_buf_info(prtd->ram_link, "ram_link");
601 print_buf_info(prtd->ram_link2, "ram_link2");
602 print_buf_info(prtd->asp_channel, "asp_channel");
603 print_buf_info(prtd->asp_link[0], "asp_link[0]");
604 print_buf_info(prtd->asp_link[1], "asp_link[1]");
605
Troy Kisky1e224f32009-11-18 17:49:53 -0700606 return 0;
607 }
Ben Gardiner10ab3bf2011-05-24 14:50:19 -0400608 davinci_pcm_period_reset(substream);
Vladimir Barinov310355c2008-02-18 11:40:22 +0100609 davinci_pcm_enqueue_dma(substream);
610
David Brownell82075af2009-05-14 12:41:22 -0700611 /* Copy self-linked parameter RAM entry into master channel */
Troy Kisky1e224f32009-11-18 17:49:53 -0700612 edma_read_slot(prtd->asp_link[0], &prtd->asp_params);
613 edma_write_slot(prtd->asp_channel, &prtd->asp_params);
Troy Kisky6e541472009-07-07 17:36:06 -0700614 davinci_pcm_enqueue_dma(substream);
Vladimir Barinov310355c2008-02-18 11:40:22 +0100615
616 return 0;
617}
618
619static snd_pcm_uframes_t
620davinci_pcm_pointer(struct snd_pcm_substream *substream)
621{
622 struct snd_pcm_runtime *runtime = substream->runtime;
623 struct davinci_runtime_data *prtd = runtime->private_data;
624 unsigned int offset;
Troy Kisky1587ea312009-11-18 17:49:52 -0700625 int asp_count;
626 dma_addr_t asp_src, asp_dst;
Vladimir Barinov310355c2008-02-18 11:40:22 +0100627
628 spin_lock(&prtd->lock);
Troy Kisky1e224f32009-11-18 17:49:53 -0700629 if (prtd->ram_channel >= 0) {
630 int ram_count;
631 int mod_ram;
632 dma_addr_t ram_src, ram_dst;
633 unsigned int period_size = snd_pcm_lib_period_bytes(substream);
634 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
635 /* reading ram before asp should be safe
636 * as long as the asp transfers less than a ping size
637 * of bytes between the 2 reads
638 */
639 edma_get_position(prtd->ram_channel,
640 &ram_src, &ram_dst);
641 edma_get_position(prtd->asp_channel,
642 &asp_src, &asp_dst);
643 asp_count = asp_src - prtd->asp_params.src;
644 ram_count = ram_src - prtd->ram_params.src;
645 mod_ram = ram_count % period_size;
646 mod_ram -= asp_count;
647 if (mod_ram < 0)
648 mod_ram += period_size;
649 else if (mod_ram == 0) {
650 if (snd_pcm_running(substream))
651 mod_ram += period_size;
652 }
653 ram_count -= mod_ram;
654 if (ram_count < 0)
655 ram_count += period_size * runtime->periods;
656 } else {
657 edma_get_position(prtd->ram_channel,
658 &ram_src, &ram_dst);
659 ram_count = ram_dst - prtd->ram_params.dst;
660 }
661 asp_count = ram_count;
662 } else {
663 edma_get_position(prtd->asp_channel, &asp_src, &asp_dst);
664 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
665 asp_count = asp_src - runtime->dma_addr;
666 else
667 asp_count = asp_dst - runtime->dma_addr;
668 }
Vladimir Barinov310355c2008-02-18 11:40:22 +0100669 spin_unlock(&prtd->lock);
670
Troy Kisky1587ea312009-11-18 17:49:52 -0700671 offset = bytes_to_frames(runtime, asp_count);
Vladimir Barinov310355c2008-02-18 11:40:22 +0100672 if (offset >= runtime->buffer_size)
673 offset = 0;
674
675 return offset;
676}
677
678static int davinci_pcm_open(struct snd_pcm_substream *substream)
679{
680 struct snd_pcm_runtime *runtime = substream->runtime;
681 struct davinci_runtime_data *prtd;
Troy Kisky1e224f32009-11-18 17:49:53 -0700682 struct snd_pcm_hardware *ppcm;
Vladimir Barinov310355c2008-02-18 11:40:22 +0100683 int ret = 0;
Troy Kisky81ac55a2009-09-11 14:29:02 -0700684 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Daniel Mack5f712b22010-03-22 10:11:15 +0100685 struct davinci_pcm_dma_params *pa;
Troy Kisky57512c62009-11-16 16:52:31 -0700686 struct davinci_pcm_dma_params *params;
Daniel Mack5f712b22010-03-22 10:11:15 +0100687
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000688 pa = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
Troy Kisky57512c62009-11-16 16:52:31 -0700689 if (!pa)
Troy Kisky81ac55a2009-09-11 14:29:02 -0700690 return -ENODEV;
Troy Kisky57512c62009-11-16 16:52:31 -0700691 params = &pa[substream->stream];
Vladimir Barinov310355c2008-02-18 11:40:22 +0100692
Troy Kisky1e224f32009-11-18 17:49:53 -0700693 ppcm = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
694 &pcm_hardware_playback : &pcm_hardware_capture;
695 allocate_sram(substream, params->sram_size, ppcm);
696 snd_soc_set_runtime_hwparams(substream, ppcm);
Troy Kisky6a90d532009-08-06 16:55:32 -0700697 /* ensure that buffer size is a multiple of period size */
698 ret = snd_pcm_hw_constraint_integer(runtime,
699 SNDRV_PCM_HW_PARAM_PERIODS);
700 if (ret < 0)
701 return ret;
Vladimir Barinov310355c2008-02-18 11:40:22 +0100702
703 prtd = kzalloc(sizeof(struct davinci_runtime_data), GFP_KERNEL);
704 if (prtd == NULL)
705 return -ENOMEM;
706
707 spin_lock_init(&prtd->lock);
Troy Kisky81ac55a2009-09-11 14:29:02 -0700708 prtd->params = params;
Troy Kisky1e224f32009-11-18 17:49:53 -0700709 prtd->asp_channel = -1;
710 prtd->asp_link[0] = prtd->asp_link[1] = -1;
711 prtd->ram_channel = -1;
712 prtd->ram_link = -1;
713 prtd->ram_link2 = -1;
Vladimir Barinov310355c2008-02-18 11:40:22 +0100714
715 runtime->private_data = prtd;
716
717 ret = davinci_pcm_dma_request(substream);
718 if (ret) {
719 printk(KERN_ERR "davinci_pcm: Failed to get dma channels\n");
720 kfree(prtd);
721 }
722
723 return ret;
724}
725
726static int davinci_pcm_close(struct snd_pcm_substream *substream)
727{
728 struct snd_pcm_runtime *runtime = substream->runtime;
729 struct davinci_runtime_data *prtd = runtime->private_data;
730
Troy Kisky1e224f32009-11-18 17:49:53 -0700731 if (prtd->ram_channel >= 0)
732 edma_stop(prtd->ram_channel);
733 if (prtd->asp_channel >= 0)
734 edma_stop(prtd->asp_channel);
735 if (prtd->asp_link[0] >= 0)
736 edma_unlink(prtd->asp_link[0]);
737 if (prtd->asp_link[1] >= 0)
738 edma_unlink(prtd->asp_link[1]);
739 if (prtd->ram_link >= 0)
740 edma_unlink(prtd->ram_link);
Vladimir Barinov310355c2008-02-18 11:40:22 +0100741
Troy Kisky1e224f32009-11-18 17:49:53 -0700742 if (prtd->asp_link[0] >= 0)
743 edma_free_slot(prtd->asp_link[0]);
744 if (prtd->asp_link[1] >= 0)
745 edma_free_slot(prtd->asp_link[1]);
746 if (prtd->asp_channel >= 0)
747 edma_free_channel(prtd->asp_channel);
748 if (prtd->ram_link >= 0)
749 edma_free_slot(prtd->ram_link);
750 if (prtd->ram_link2 >= 0)
751 edma_free_slot(prtd->ram_link2);
752 if (prtd->ram_channel >= 0)
753 edma_free_channel(prtd->ram_channel);
Vladimir Barinov310355c2008-02-18 11:40:22 +0100754
755 kfree(prtd);
756
757 return 0;
758}
759
760static int davinci_pcm_hw_params(struct snd_pcm_substream *substream,
761 struct snd_pcm_hw_params *hw_params)
762{
763 return snd_pcm_lib_malloc_pages(substream,
764 params_buffer_bytes(hw_params));
765}
766
767static int davinci_pcm_hw_free(struct snd_pcm_substream *substream)
768{
769 return snd_pcm_lib_free_pages(substream);
770}
771
772static int davinci_pcm_mmap(struct snd_pcm_substream *substream,
773 struct vm_area_struct *vma)
774{
775 struct snd_pcm_runtime *runtime = substream->runtime;
776
777 return dma_mmap_writecombine(substream->pcm->card->dev, vma,
778 runtime->dma_area,
779 runtime->dma_addr,
780 runtime->dma_bytes);
781}
782
Mark Brownb2a19d02009-01-17 19:14:26 +0000783static struct snd_pcm_ops davinci_pcm_ops = {
Vladimir Barinov310355c2008-02-18 11:40:22 +0100784 .open = davinci_pcm_open,
785 .close = davinci_pcm_close,
786 .ioctl = snd_pcm_lib_ioctl,
787 .hw_params = davinci_pcm_hw_params,
788 .hw_free = davinci_pcm_hw_free,
789 .prepare = davinci_pcm_prepare,
790 .trigger = davinci_pcm_trigger,
791 .pointer = davinci_pcm_pointer,
792 .mmap = davinci_pcm_mmap,
793};
794
Troy Kisky1e224f32009-11-18 17:49:53 -0700795static int davinci_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream,
796 size_t size)
Vladimir Barinov310355c2008-02-18 11:40:22 +0100797{
798 struct snd_pcm_substream *substream = pcm->streams[stream].substream;
799 struct snd_dma_buffer *buf = &substream->dma_buffer;
Vladimir Barinov310355c2008-02-18 11:40:22 +0100800
801 buf->dev.type = SNDRV_DMA_TYPE_DEV;
802 buf->dev.dev = pcm->card->dev;
803 buf->private_data = NULL;
804 buf->area = dma_alloc_writecombine(pcm->card->dev, size,
805 &buf->addr, GFP_KERNEL);
806
Alexander Beregalov9cd28ab2008-12-13 16:25:27 +0300807 pr_debug("davinci_pcm: preallocate_dma_buffer: area=%p, addr=%p, "
808 "size=%d\n", (void *) buf->area, (void *) buf->addr, size);
Vladimir Barinov310355c2008-02-18 11:40:22 +0100809
810 if (!buf->area)
811 return -ENOMEM;
812
813 buf->bytes = size;
814 return 0;
815}
816
817static void davinci_pcm_free(struct snd_pcm *pcm)
818{
819 struct snd_pcm_substream *substream;
820 struct snd_dma_buffer *buf;
821 int stream;
822
823 for (stream = 0; stream < 2; stream++) {
Troy Kisky1e224f32009-11-18 17:49:53 -0700824 struct snd_dma_buffer *iram_dma;
Vladimir Barinov310355c2008-02-18 11:40:22 +0100825 substream = pcm->streams[stream].substream;
826 if (!substream)
827 continue;
828
829 buf = &substream->dma_buffer;
830 if (!buf->area)
831 continue;
832
833 dma_free_writecombine(pcm->card->dev, buf->bytes,
834 buf->area, buf->addr);
835 buf->area = NULL;
Joe Perches4726a572010-07-12 13:50:27 -0700836 iram_dma = buf->private_data;
Troy Kisky1e224f32009-11-18 17:49:53 -0700837 if (iram_dma) {
838 sram_free(iram_dma->area, iram_dma->bytes);
839 kfree(iram_dma);
840 }
Vladimir Barinov310355c2008-02-18 11:40:22 +0100841 }
842}
843
844static u64 davinci_pcm_dmamask = 0xffffffff;
845
846static int davinci_pcm_new(struct snd_card *card,
Liam Girdwood9cb132d2008-07-07 16:07:42 +0100847 struct snd_soc_dai *dai, struct snd_pcm *pcm)
Vladimir Barinov310355c2008-02-18 11:40:22 +0100848{
849 int ret;
850
851 if (!card->dev->dma_mask)
852 card->dev->dma_mask = &davinci_pcm_dmamask;
853 if (!card->dev->coherent_dma_mask)
854 card->dev->coherent_dma_mask = 0xffffffff;
855
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000856 if (dai->driver->playback.channels_min) {
Vladimir Barinov310355c2008-02-18 11:40:22 +0100857 ret = davinci_pcm_preallocate_dma_buffer(pcm,
Troy Kisky1e224f32009-11-18 17:49:53 -0700858 SNDRV_PCM_STREAM_PLAYBACK,
859 pcm_hardware_playback.buffer_bytes_max);
Vladimir Barinov310355c2008-02-18 11:40:22 +0100860 if (ret)
861 return ret;
862 }
863
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000864 if (dai->driver->capture.channels_min) {
Vladimir Barinov310355c2008-02-18 11:40:22 +0100865 ret = davinci_pcm_preallocate_dma_buffer(pcm,
Troy Kisky1e224f32009-11-18 17:49:53 -0700866 SNDRV_PCM_STREAM_CAPTURE,
867 pcm_hardware_capture.buffer_bytes_max);
Vladimir Barinov310355c2008-02-18 11:40:22 +0100868 if (ret)
869 return ret;
870 }
871
872 return 0;
873}
874
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000875static struct snd_soc_platform_driver davinci_soc_platform = {
876 .ops = &davinci_pcm_ops,
Vladimir Barinov310355c2008-02-18 11:40:22 +0100877 .pcm_new = davinci_pcm_new,
878 .pcm_free = davinci_pcm_free,
879};
Vladimir Barinov310355c2008-02-18 11:40:22 +0100880
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000881static int __devinit davinci_soc_platform_probe(struct platform_device *pdev)
Mark Brown958e7922008-12-03 19:58:17 +0000882{
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000883 return snd_soc_register_platform(&pdev->dev, &davinci_soc_platform);
Mark Brown958e7922008-12-03 19:58:17 +0000884}
Mark Brown958e7922008-12-03 19:58:17 +0000885
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000886static int __devexit davinci_soc_platform_remove(struct platform_device *pdev)
Mark Brown958e7922008-12-03 19:58:17 +0000887{
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000888 snd_soc_unregister_platform(&pdev->dev);
889 return 0;
Mark Brown958e7922008-12-03 19:58:17 +0000890}
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000891
892static struct platform_driver davinci_pcm_driver = {
893 .driver = {
894 .name = "davinci-pcm-audio",
895 .owner = THIS_MODULE,
896 },
897
898 .probe = davinci_soc_platform_probe,
899 .remove = __devexit_p(davinci_soc_platform_remove),
900};
901
902static int __init snd_davinci_pcm_init(void)
903{
904 return platform_driver_register(&davinci_pcm_driver);
905}
906module_init(snd_davinci_pcm_init);
907
908static void __exit snd_davinci_pcm_exit(void)
909{
910 platform_driver_unregister(&davinci_pcm_driver);
911}
912module_exit(snd_davinci_pcm_exit);
Mark Brown958e7922008-12-03 19:58:17 +0000913
Vladimir Barinov310355c2008-02-18 11:40:22 +0100914MODULE_AUTHOR("Vladimir Barinov");
915MODULE_DESCRIPTION("TI DAVINCI PCM DMA module");
916MODULE_LICENSE("GPL");