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