2 * arch/nios2nommu/kernel/dma.c
4 * Copyright (C) 2005 Microtronix Datacom Ltd
6 * PC like DMA API for Nios's DMAC.
8 * This file is subject to the terms and conditions of the GNU General Public
9 * License. See the file "COPYING" in the main directory of this archive
12 * Written by Wentao Xu <wentao@microtronix.com>
15 #include <linux/init.h>
16 #include <linux/irq.h>
17 #include <linux/interrupt.h>
18 #include <linux/module.h>
20 #include <linux/seq_file.h>
21 #include <linux/proc_fs.h>
25 /* nios2 dma controller register map */
26 #define REG_DMA_STATUS 0
27 #define REG_DMA_READADDR 4
28 #define REG_DMA_WRITEADDR 8
29 #define REG_DMA_LENGTH 12
30 #define REG_DMA_CONTROL 24
32 /* status register bits definition */
39 /* control register bits definition */
50 #define CT_DOUBLE 0x400
54 unsigned int addr
; /* control address */
55 unsigned int irq
; /* interrupt number */
57 unsigned int mode
; /* dma mode: width, stream etc */
58 int (*handler
)(void*, int );
64 static struct dma_channel dma_channels
[]={
69 .idle
= ATOMIC_INIT(1),
76 .idle
= ATOMIC_INIT(1),
80 #define MAX_DMA_CHANNELS sizeof(dma_channels)/sizeof(struct dma_channel)
82 void enable_dma(unsigned int dmanr
)
84 if (dmanr
< MAX_DMA_CHANNELS
) {
85 unsigned int ctl
= dma_channels
[dmanr
].mode
;
86 ctl
|= CT_GO
| CT_IEEN
;
87 outl(ctl
, dma_channels
[dmanr
].addr
+REG_DMA_CONTROL
);
91 void disable_dma(unsigned int dmanr
)
93 if (dmanr
< MAX_DMA_CHANNELS
) {
94 unsigned int ctl
= dma_channels
[dmanr
].mode
;
95 ctl
&= ~(CT_GO
| CT_IEEN
);
96 outl(ctl
, dma_channels
[dmanr
].addr
+REG_DMA_CONTROL
);
100 void set_dma_count(unsigned int dmanr
, unsigned int count
)
102 if (dmanr
< MAX_DMA_CHANNELS
) {
103 dma_channels
[dmanr
].mode
|= CT_LEEN
;
104 outl(count
, dma_channels
[dmanr
].addr
+REG_DMA_LENGTH
);
108 int get_dma_residue(unsigned int dmanr
)
111 if (dmanr
< MAX_DMA_CHANNELS
) {
112 result
= inl(dma_channels
[dmanr
].addr
+REG_DMA_LENGTH
);
117 int request_dma(unsigned int chan
, const char *dev_id
)
119 struct dma_channel
*channel
;
121 if ( chan
>= MAX_DMA_CHANNELS
) {
125 channel
= &dma_channels
[chan
];
127 if (!atomic_dec_and_test(&channel
->idle
)) {
131 strlcpy(channel
->dev_id
, dev_id
, sizeof(channel
->dev_id
));
132 channel
->handler
=NULL
;
139 void free_dma(unsigned int chan
)
141 if ( chan
< MAX_DMA_CHANNELS
) {
142 dma_channels
[chan
].handler
=NULL
;
143 dma_channels
[chan
].user
=NULL
;
144 atomic_set(&dma_channels
[chan
].idle
, 1);
148 int nios2_request_dma(const char *dev_id
)
152 for ( chann
=0; chann
< MAX_DMA_CHANNELS
; chann
++) {
153 if (request_dma(chann
, dev_id
)==0)
159 void nios2_set_dma_handler(unsigned int dmanr
, int (*handler
)(void*, int), void* user
)
161 if (dmanr
< MAX_DMA_CHANNELS
) {
162 dma_channels
[dmanr
].handler
=handler
;
163 dma_channels
[dmanr
].user
=user
;
166 #define NIOS2_DMA_WIDTH_MASK (CT_BYTE | CT_HW | CT_WORD | CT_DOUBLE | CT_QUAD)
167 #define NIOS2_MODE_MASK (NIOS2_DMA_WIDTH_MASK | CT_REEN | CT_WEEN | CT_LEEN | CT_RCON | CT_WCON)
168 void nios2_set_dma_data_width(unsigned int dmanr
, unsigned int width
)
170 if (dmanr
< MAX_DMA_CHANNELS
) {
171 dma_channels
[dmanr
].mode
&= ~NIOS2_DMA_WIDTH_MASK
;
174 dma_channels
[dmanr
].mode
|= CT_BYTE
;
177 dma_channels
[dmanr
].mode
|= CT_HW
;
180 dma_channels
[dmanr
].mode
|= CT_DOUBLE
;
183 dma_channels
[dmanr
].mode
|= CT_QUAD
;
187 dma_channels
[dmanr
].mode
|= CT_WORD
;
193 void nios2_set_dma_rcon(unsigned int dmanr
,unsigned int set
)
195 if (dmanr
< MAX_DMA_CHANNELS
) {
196 dma_channels
[dmanr
].mode
&= ~(CT_REEN
| CT_RCON
);
198 dma_channels
[dmanr
].mode
|= (CT_REEN
| CT_RCON
);
201 void nios2_set_dma_wcon(unsigned int dmanr
,unsigned int set
)
203 if (dmanr
< MAX_DMA_CHANNELS
) {
204 dma_channels
[dmanr
].mode
&= ~(CT_WEEN
| CT_WCON
);
206 dma_channels
[dmanr
].mode
|= (CT_WEEN
| CT_WCON
);
209 void nios2_set_dma_mode(unsigned int dmanr
, unsigned int mode
)
211 if (dmanr
< MAX_DMA_CHANNELS
) {
212 /* set_dma_mode is only allowed to change the bus width,
215 mode
&= NIOS2_MODE_MASK
;
216 dma_channels
[dmanr
].mode
&= ~NIOS2_MODE_MASK
;
217 dma_channels
[dmanr
].mode
|= mode
;
221 void nios2_set_dma_raddr(unsigned int dmanr
, unsigned int a
)
223 if (dmanr
< MAX_DMA_CHANNELS
) {
224 outl(a
, dma_channels
[dmanr
].addr
+REG_DMA_READADDR
);
227 void nios2_set_dma_waddr(unsigned int dmanr
, unsigned int a
)
229 if (dmanr
< MAX_DMA_CHANNELS
) {
230 outl(a
, dma_channels
[dmanr
].addr
+REG_DMA_WRITEADDR
);
235 static irqreturn_t
dma_isr(int irq
, void *dev_id
)
237 struct dma_channel
*chann
=(struct dma_channel
*)dev_id
;
240 int status
= inl(chann
->addr
+REG_DMA_STATUS
);
241 /* ack the interrupt, and clear the DONE bit */
242 outl(0, chann
->addr
+REG_DMA_STATUS
);
243 /* call the peripheral callback */
245 chann
->handler(chann
->user
, status
);
253 #ifdef CONFIG_PROC_FS
254 static int proc_dma_show(struct seq_file
*m
, void *v
)
258 for (i
= 0 ; i
< MAX_DMA_CHANNELS
; i
++) {
259 if (!atomic_read(&dma_channels
[i
].idle
)) {
260 seq_printf(m
, "%2d: %s\n", i
,
261 dma_channels
[i
].dev_id
);
267 static int proc_dma_open(struct inode
*inode
, struct file
*file
)
269 return single_open(file
, proc_dma_show
, NULL
);
271 static struct file_operations proc_dma_operations
= {
272 .open
= proc_dma_open
,
275 .release
= single_release
,
278 static int __init
proc_dma_init(void)
280 struct proc_dir_entry
*e
;
282 e
= create_proc_entry("dma", 0, NULL
);
284 e
->proc_fops
= &proc_dma_operations
;
289 __initcall(proc_dma_init
);
291 #endif /* CONFIG_PROC_FS */
293 int __init
init_dma(void)
297 for (i
= 0 ; i
< MAX_DMA_CHANNELS
; i
++) {
298 sprintf(dma_channels
[i
].id
, "dmac-%d", i
);
299 /* disable the dmac channel */
302 if (request_irq(dma_channels
[i
].irq
, dma_isr
, 0, dma_channels
[i
].id
, (void*)&dma_channels
[i
])){
303 printk("DMA controller %d failed to get irq %d\n", i
, dma_channels
[i
].irq
);
304 atomic_set(&dma_channels
[i
].idle
, 0);
310 static void __exit
exit_dma(void)
314 for (i
= 0 ; i
< MAX_DMA_CHANNELS
; i
++) {
315 /* disable the dmac channel */
317 free_irq(dma_channels
[i
].irq
, dma_channels
[i
].id
);
321 module_init(init_dma
);
322 module_exit(exit_dma
);
324 MODULE_LICENSE("GPL");
326 //EXPORT_SYMBOL(claim_dma_lock);
327 //EXPORT_SYMBOL(release_dma_lock);
328 EXPORT_SYMBOL(enable_dma
);
329 EXPORT_SYMBOL(disable_dma
);
330 EXPORT_SYMBOL(set_dma_count
);
331 EXPORT_SYMBOL(get_dma_residue
);
332 EXPORT_SYMBOL(request_dma
);
333 EXPORT_SYMBOL(free_dma
);
334 EXPORT_SYMBOL(nios2_request_dma
);
335 EXPORT_SYMBOL(nios2_set_dma_handler
);
336 EXPORT_SYMBOL(nios2_set_dma_data_width
);
337 EXPORT_SYMBOL(nios2_set_dma_rcon
);
338 EXPORT_SYMBOL(nios2_set_dma_wcon
);
339 EXPORT_SYMBOL(nios2_set_dma_mode
);
340 EXPORT_SYMBOL(nios2_set_dma_raddr
);
341 EXPORT_SYMBOL(nios2_set_dma_waddr
);