2 * sound/arm/omap-alsa-dma.c
4 * Common audio DMA handling for the OMAP processors
6 * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
8 * Copyright (C) 2004 Texas Instruments, Inc.
10 * Copyright (C) 2000, 2001 Nicolas Pitre <nico@cam.org>
12 * This package is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2 as
14 * published by the Free Software Foundation.
16 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22 * 2004-06-07 Sriram Kannan - Created new file from omap_audio_dma_intfc.c. This file
23 * will contain only the DMA interface and buffer handling of OMAP
26 * 2004-06-22 Sriram Kannan - removed legacy code (auto-init). Self-linking of DMA logical channel.
28 * 2004-08-12 Nishanth Menon - Modified to integrate Audio requirements on 1610,1710 platforms
30 * 2004-11-01 Nishanth Menon - 16xx platform code base modified to support multi channel chaining.
32 * 2004-12-15 Nishanth Menon - Improved 16xx platform channel logic introduced - tasklets, queue handling updated
34 * 2005-07-19 INdT Kernel Team - Alsa port. Creation of new file omap-alsa-dma.c based in
35 * omap-audio-dma-intfc.c oss file. Support for aic23 codec.
36 * Removal of buffer handling (Alsa does that), modifications
37 * in dma handling and port to alsa structures.
40 #include <linux/config.h>
41 #include <linux/module.h>
42 #include <linux/init.h>
43 #include <linux/types.h>
46 #include <linux/slab.h>
47 #include <linux/sched.h>
48 #include <linux/poll.h>
50 #include <linux/errno.h>
51 #include <linux/sound.h>
52 #include <linux/soundcard.h>
53 #include <linux/sysrq.h>
54 #include <linux/interrupt.h>
55 #include <linux/dma-mapping.h>
57 #include <asm/uaccess.h>
59 #include <asm/hardware.h>
60 #include <asm/semaphore.h>
62 #include <asm/arch/dma.h>
63 #include "omap-alsa-dma.h"
65 #include <asm/arch/mcbsp.h>
67 #include "omap-aic23.h"
72 #define DPRINTK(ARGS...) printk(KERN_INFO "<%s>: ",__FUNCTION__);printk(ARGS)
73 #define FN_IN printk(KERN_INFO "[%s]: start\n", __FUNCTION__)
74 #define FN_OUT(n) printk(KERN_INFO "[%s]: end(%u)\n",__FUNCTION__, n)
77 #define DPRINTK( x... )
82 #define ERR(ARGS...) printk(KERN_ERR "{%s}-ERROR: ", __FUNCTION__);printk(ARGS);
84 /* Channel Queue Handling macros
85 * tail always points to the current free entry
86 * Head always points to the current entry being used
87 * end is either head or tail
90 #define AUDIO_QUEUE_INIT(s) s->dma_q_head = s->dma_q_tail = s->dma_q_count = 0;
91 #define AUDIO_QUEUE_FULL(s) (nr_linked_channels == s->dma_q_count)
92 #define AUDIO_QUEUE_LAST(s) (1 == s->dma_q_count)
93 #define AUDIO_QUEUE_EMPTY(s) (0 == s->dma_q_count)
94 #define __AUDIO_INCREMENT_QUEUE(end) ((end)=((end)+1) % nr_linked_channels)
95 #define AUDIO_INCREMENT_HEAD(s) __AUDIO_INCREMENT_QUEUE(s->dma_q_head); s->dma_q_count--;
96 #define AUDIO_INCREMENT_TAIL(s) __AUDIO_INCREMENT_QUEUE(s->dma_q_tail); s->dma_q_count++;
98 /* DMA buffer fragmentation sizes */
99 #define MAX_DMA_SIZE 0x1000000 /* todo: sync with alsa */
100 //#define CUT_DMA_SIZE 0x1000
101 /* TODO: To be moved to more appropriate location */
102 #define DCSR_ERROR 0x3
103 #define DCSR_END_BLOCK (1 << 5)
104 #define DCSR_SYNC_SET (1 << 6)
106 #define DCCR_FS (1 << 5)
107 #define DCCR_PRIO (1 << 6)
108 #define DCCR_EN (1 << 7)
109 #define DCCR_AI (1 << 8)
110 #define DCCR_REPEAT (1 << 9)
111 /* if 0 the channel works in 3.1 compatible mode*/
112 #define DCCR_N31COMP (1 << 10)
113 #define DCCR_EP (1 << 11)
114 #define DCCR_SRC_AMODE_BIT 12
115 #define DCCR_SRC_AMODE_MASK (0x3<<12)
116 #define DCCR_DST_AMODE_BIT 14
117 #define DCCR_DST_AMODE_MASK (0x3<<14)
118 #define AMODE_CONST 0x0
119 #define AMODE_POST_INC 0x1
120 #define AMODE_SINGLE_INDEX 0x2
121 #define AMODE_DOUBLE_INDEX 0x3
123 /**************************** DATA STRUCTURES *****************************************/
125 static spinlock_t dma_list_lock = SPIN_LOCK_UNLOCKED;
127 static char nr_linked_channels = 1;
129 /*********************************** MODULE SPECIFIC FUNCTIONS ***********************/
131 static void sound_dma_irq_handler(int lch, u16 ch_status, void *data);
132 static int audio_set_dma_params_play(int channel, dma_addr_t dma_ptr,
134 static int audio_set_dma_params_capture(int channel, dma_addr_t dma_ptr,
136 static int audio_start_dma_chain(struct audio_stream * s);
138 /***************************************************************************************
140 * DMA channel requests
142 **************************************************************************************/
143 static void omap_sound_dma_link_lch(void *data)
146 struct audio_stream *s = (struct audio_stream *) data;
155 for (i = 0; i < nr_linked_channels; i++) {
156 int cur_chan = chan[i];
158 ((nr_linked_channels - 1 ==
159 i) ? chan[0] : chan[i + 1]);
160 omap_dma_link_lch(cur_chan, nex_chan);
166 int omap_request_sound_dma(int device_id, const char *device_name,
167 void *data, int **channels)
172 if (unlikely((NULL == channels) || (NULL == device_name))) {
176 /* Try allocate memory for the num channels */
178 (int *) kmalloc(sizeof(int) * nr_linked_channels, GFP_KERNEL);
181 ERR("No Memory for channel allocs!\n");
185 spin_lock(&dma_list_lock);
186 for (i = 0; i < nr_linked_channels; i++) {
188 omap_request_dma(device_id, device_name,
189 sound_dma_irq_handler, data,
192 /* Handle Failure condition here */
195 for (j = 0; j < i; j++) {
196 omap_free_dma(chan[j]);
198 spin_unlock(&dma_list_lock);
201 ERR("Error in requesting channel %d=0x%x\n", i,
208 /* Chain the channels together */
209 if (!cpu_is_omap1510())
210 omap_sound_dma_link_lch(data);
212 spin_unlock(&dma_list_lock);
217 /***************************************************************************************
219 * DMA channel requests Freeing
221 **************************************************************************************/
222 static void omap_sound_dma_unlink_lch(void *data)
224 struct audio_stream *s = (struct audio_stream *) data;
233 for (i = 0; i < nr_linked_channels; i++) {
234 int cur_chan = chan[i];
236 ((nr_linked_channels - 1 ==
237 i) ? chan[0] : chan[i + 1]);
238 omap_dma_unlink_lch(cur_chan, nex_chan);
244 int omap_free_sound_dma(void *data, int **channels)
250 if (unlikely(NULL == channels)) {
254 if (unlikely(NULL == *channels)) {
260 if (!cpu_is_omap1510())
261 omap_sound_dma_unlink_lch(data);
262 for (i = 0; i < nr_linked_channels; i++) {
263 int cur_chan = chan[i];
264 omap_stop_dma(cur_chan);
265 omap_free_dma(cur_chan);
273 /***************************************************************************************
275 * Stop all the DMA channels of the stream
277 **************************************************************************************/
278 void omap_audio_stop_dma(struct audio_stream *s)
283 if (unlikely(NULL == chan)) {
287 for (i = 0; i < nr_linked_channels; i++) {
288 int cur_chan = chan[i];
289 omap_stop_dma(cur_chan);
295 /***************************************************************************************
297 * Clear any pending transfers
299 **************************************************************************************/
300 void omap_clear_sound_dma(struct audio_stream * s)
303 omap_clear_dma(s->lch[s->dma_q_head]);
308 /*********************************** MODULE FUNCTIONS DEFINTIONS ***********************/
310 #ifdef OMAP1610_MCBSP1_BASE
311 #undef OMAP1610_MCBSP1_BASE
313 #define OMAP1610_MCBSP1_BASE 0xE1011000
315 /***************************************************************************************
317 * DMA related functions
319 **************************************************************************************/
320 static int audio_set_dma_params_play(int channel, dma_addr_t dma_ptr,
323 int dt = 0x1; /* data type 16 */
324 int cen = 32; /* Stereo */
325 int cfn = dma_size / (2 * cen);
327 omap_set_dma_dest_params(channel, 0x05, 0x00,
328 (OMAP1610_MCBSP1_BASE + 0x806));
329 omap_set_dma_src_params(channel, 0x00, 0x01, dma_ptr);
330 omap_set_dma_transfer_params(channel, dt, cen, cfn, 0x00);
335 static int audio_set_dma_params_capture(int channel, dma_addr_t dma_ptr,
338 int dt = 0x1; /* data type 16 */
339 int cen = 32; /* stereo */
341 int cfn = dma_size / (2 * cen);
343 omap_set_dma_src_params(channel, 0x05, 0x00,
344 (OMAP1610_MCBSP1_BASE + 0x802));
345 omap_set_dma_dest_params(channel, 0x00, 0x01, dma_ptr);
346 omap_set_dma_transfer_params(channel, dt, cen, cfn, 0x00);
351 static int audio_start_dma_chain(struct audio_stream *s)
353 int channel = s->lch[s->dma_q_head];
356 omap_start_dma(channel);
359 /* else the dma itself will progress forward with out our help */
365 * Do the initial set of work to initialize all the channels as required.
366 * We shall then initate a transfer
368 int omap_start_sound_dma(struct audio_stream *s, dma_addr_t dma_ptr,
375 if (unlikely(dma_size > MAX_DMA_SIZE)) {
376 ERR("DmaSoundDma: Start: overflowed %d-%d\n", dma_size,
380 //if (AUDIO_QUEUE_FULL(s)) {
385 if (s->stream_id == SNDRV_PCM_STREAM_PLAYBACK) {
388 audio_set_dma_params_play(s->lch[s->dma_q_tail],
392 audio_set_dma_params_capture(s->lch[s->dma_q_tail],
396 ret = -3; /* indicate queue full */
399 AUDIO_INCREMENT_TAIL(s);
400 ret = audio_start_dma_chain(s);
402 ERR("dma start failed");
411 * ISRs have to be short and smart..
412 * Here we call alsa handling, after some error checking
414 static void sound_dma_irq_handler(int sound_curr_lch, u16 ch_status,
417 int dma_status = ch_status;
418 struct audio_stream *s = (struct audio_stream *) data;
422 * some register checkings
424 DPRINTK("lch=%d,status=0x%x, dma_status=%d, data=%p\n",
425 sound_curr_lch, ch_status, dma_status, data);
427 if (dma_status & (DCSR_ERROR)) {
428 omap_writew(omap_readw(OMAP_DMA_CCR(sound_curr_lch)) &
429 ~DCCR_EN, OMAP_DMA_CCR(sound_curr_lch));
430 ERR("DCSR_ERROR!\n");
435 if (ch_status & DCSR_END_BLOCK)
436 audio_dma_callback(s);
441 MODULE_AUTHOR("Texas Instruments");
443 ("Common DMA handling for Audio driver on OMAP processors");
444 MODULE_LICENSE("GPL");
446 EXPORT_SYMBOL(omap_start_sound_dma);
447 EXPORT_SYMBOL(omap_clear_sound_dma);
448 EXPORT_SYMBOL(omap_request_sound_dma);
449 EXPORT_SYMBOL(omap_free_sound_dma);
450 EXPORT_SYMBOL(omap_audio_stop_dma);