1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright 2009 by Bob Cousins
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
28 #include "dma-target.h"
29 #include "system-target.h"
31 #define NUM_CHANNELS 4
33 static int dma_used
= 0;
36 #define STATUS_CHANNEL_ACTIVE (1<<0)
38 struct dma_channel_state
40 volatile unsigned status
;
41 void (*callback
)(void);
42 } dma_state
[NUM_CHANNELS
];
44 struct dma_channel_regs
46 volatile unsigned long disrc
;
47 volatile unsigned long disrcc
;
48 volatile unsigned long didst
;
49 volatile unsigned long didstc
;
50 volatile unsigned long dcon
;
51 volatile unsigned long dstat
;
52 volatile unsigned long dcsrc
;
53 volatile unsigned long dcdst
;
54 volatile unsigned long dmasktrig
;
55 volatile unsigned long reserved
[7]; /* pad to 0x40 bytes */
59 struct dma_channel_regs
*dma_regs
[4] =
61 (struct dma_channel_regs
*) &DISRC0
,
62 (struct dma_channel_regs
*) &DISRC1
,
63 (struct dma_channel_regs
*) &DISRC2
,
64 (struct dma_channel_regs
*) &DISRC3
73 /* Enable interupt on DMA Finish */
74 /* Clear pending source */
75 SRCPND
= DMA0_MASK
| DMA1_MASK
| DMA2_MASK
| DMA3_MASK
;
76 INTPND
= DMA0_MASK
| DMA1_MASK
| DMA2_MASK
| DMA3_MASK
;
78 /* Enable interrupt in controller */
79 s3c_regclr32(&INTMOD
, DMA0_MASK
| DMA1_MASK
| DMA2_MASK
| DMA3_MASK
);
80 s3c_regclr32(&INTMSK
, DMA0_MASK
| DMA1_MASK
| DMA2_MASK
| DMA3_MASK
);
89 /* Enable DMA controller, clock? */
93 void dma_release(void)
105 inline void dma_disable_channel(int channel
)
107 struct dma_channel_regs
*regs
= dma_regs
[channel
];
109 /* disable the specified channel */
111 /* Reset the channel */
112 regs
->dmasktrig
|= DMASKTRIG_STOP
;
114 /* Wait for DMA controller to be ready */
115 while(regs
->dmasktrig
& DMASKTRIG_ON
)
117 while(regs
->dstat
& DSTAT_STAT_BUSY
)
121 void dma_enable_channel(int channel
, struct dma_request
*request
)
123 struct dma_channel_regs
*regs
= dma_regs
[channel
];
125 /* TODO - transfer sizes (assumes word) */
127 if (DMA_GET_SRC(request
->source_map
, channel
) == DMA_INVALID
)
128 panicf ("DMA: invalid channel");
130 /* setup a transfer on specified channel */
131 dma_disable_channel (channel
);
133 if((unsigned long)request
->source_addr
< UNCACHED_BASE_ADDR
)
134 regs
->disrc
= (unsigned long)request
->source_addr
+ UNCACHED_BASE_ADDR
;
136 regs
->disrc
= (unsigned long)request
->source_addr
;
137 regs
->disrcc
= request
->source_control
;
139 if((unsigned long)request
->dest_addr
< UNCACHED_BASE_ADDR
)
140 regs
->didst
= (unsigned long)request
->dest_addr
+ UNCACHED_BASE_ADDR
;
142 regs
->didst
= (unsigned long)request
->dest_addr
;
143 regs
->didstc
= request
->dest_control
;
145 regs
->dcon
= request
->control
| request
->count
|
146 DMA_GET_SRC(request
->source_map
, channel
) * DCON_HWSRCSEL
;
148 dma_state
[channel
].callback
= request
->callback
;
150 /* Activate the channel */
151 invalidate_dcache_range((void *)request
->dest_addr
, request
->count
* 4);
153 dma_state
[channel
].status
|= STATUS_CHANNEL_ACTIVE
;
154 regs
->dmasktrig
= DMASKTRIG_ON
;
156 if ((request
->control
& DCON_HW_SEL
) == 0)
159 regs
->dmasktrig
|= DMASKTRIG_SW_TRIG
;
165 inline void generic_isr (unsigned channel
)
167 if (dma_state
[channel
].status
| STATUS_CHANNEL_ACTIVE
)
169 if (dma_state
[channel
].callback
)
170 /* call callback for relevant channel */
171 dma_state
[channel
].callback();
173 dma_state
[channel
].status
&= ~STATUS_CHANNEL_ACTIVE
;
180 /* Ack the interrupt */
188 /* Ack the interrupt */
196 /* Ack the interrupt */
204 /* Ack the interrupt */