3 * Copyright (C) 2005 Moxa Group All Rights Reserved.
7 * 12-01-2005 Victor Yu. Create it.
9 #include <linux/version.h>
10 #include <linux/config.h>
11 #include <asm/arch/moxa.h>
12 #include <linux/module.h>
13 #include <linux/init.h>
14 #include <linux/interrupt.h>
16 #include <linux/slab.h>
17 #include <asm/arch/cpe_int.h>
18 #include <asm/arch/dma.h>
19 #include <asm/cacheflush.h>
24 #define DBG(x...) printk(x)
29 static apb_dma_priv apb_dma_channel
[APB_DMA_MAX_CHANNEL
];
30 static spinlock_t apb_dma_lock
;
32 apb_dma_priv
*apb_dma_alloc(int req_no
)
36 apb_dma_priv
*priv
=apb_dma_channel
;
38 spin_lock_irqsave(&apb_dma_lock
, flags
);
39 for ( i
=0; i
<APB_DMA_MAX_CHANNEL
; i
++, priv
++ ) {
40 if ( priv
->used_flag
== 0 ) {
42 priv
->irq_handler
= NULL
;
43 priv
->irq_handler_param
= NULL
;
45 priv
->req_no
= req_no
;
47 case APB_DMA_SPI_TX_REQ_NO
:
48 *(unsigned int *)(CPE_PMU_BASE
+0xA0) = 0;
50 case APB_DMA_SPI_RX_REQ_NO
:
51 *(unsigned int *)(CPE_PMU_BASE
+0xA4) = 0;
53 case APB_DMA_SD_REQ_NO
:
54 *(unsigned int *)(CPE_PMU_BASE
+0xB8) = 0;
56 case APB_DMA_AC97_TX_REQ_NO
:
57 *(unsigned int *)(CPE_PMU_BASE
+0xBC) = 0;
59 case APB_DMA_AC97_RX_REQ_NO
:
60 *(unsigned int *)(CPE_PMU_BASE
+0xC0) = 0;
62 case APB_DMA_USB_DEVICE_REQ_NO
:
63 *(unsigned int *)(CPE_PMU_BASE
+0xCC) = 0;
66 spin_unlock_irqrestore(&apb_dma_lock
, flags
);
67 DBG("apb_dma_alloc uses DMA channel %d\n", i
);
71 spin_unlock_irqrestore(&apb_dma_lock
, flags
);
74 EXPORT_SYMBOL(apb_dma_alloc
);
76 void apb_dma_release(apb_dma_priv
*priv
)
80 spin_lock_irqsave(&apb_dma_lock
, flags
);
82 spin_unlock_irqrestore(&apb_dma_lock
, flags
);
87 priv
->irq_handler
= NULL
;
88 priv
->irq_handler_param
= NULL
;
90 spin_unlock_irqrestore(&apb_dma_lock
, flags
);
92 EXPORT_SYMBOL(apb_dma_release
);
94 void apb_dma_set_irq(apb_dma_priv
*priv
, void (*func
)(void *param
), void *param
)
99 spin_lock_irqsave(&apb_dma_lock
, flags
);
100 if ( priv
== NULL
) {
101 spin_unlock_irqrestore(&apb_dma_lock
, flags
);
104 priv
->irq_handler
= func
;
105 priv
->irq_handler_param
= param
;
106 priv
->error_flag
= 0;
107 cmd
= readl(&priv
->reg
->command
.ul
);
108 cmd
|= (APB_DMA_FIN_INT_EN
| APB_DMA_ERR_INT_EN
);
109 writel(cmd
, &priv
->reg
->command
.ul
);
110 spin_unlock_irqrestore(&apb_dma_lock
, flags
);
112 EXPORT_SYMBOL(apb_dma_set_irq
);
114 void apb_dma_release_irq(apb_dma_priv
*priv
)
119 spin_lock_irqsave(&apb_dma_lock
, flags
);
120 if ( priv
== NULL
) {
121 spin_unlock_irqrestore(&apb_dma_lock
, flags
);
124 cmd
= readl(&priv
->reg
->command
.ul
);
125 cmd
&= ~(APB_DMA_FIN_INT_EN
| APB_DMA_ERR_INT_EN
);
126 writel(cmd
, &priv
->reg
->command
.ul
);
127 priv
->irq_handler
= NULL
;
128 priv
->irq_handler_param
= NULL
;
129 priv
->error_flag
= 0;
130 spin_unlock_irqrestore(&apb_dma_lock
, flags
);
132 EXPORT_SYMBOL(apb_dma_release_irq
);
134 void apb_dma_conf(apb_dma_priv
*priv
, apb_dma_conf_param
*param
)
140 spin_lock_irqsave(&apb_dma_lock
, flags
);
141 writel(param
->source_addr
, &priv
->reg
->source_addr
);
142 writel(param
->dest_addr
, &priv
->reg
->dest_addr
);
144 switch ( param
->data_width
) {
145 case APB_DMAB_DATA_WIDTH_1
:
147 case APB_DMAB_DATA_WIDTH_2
:
150 case APB_DMAB_DATA_WIDTH_4
:
155 if ( param
->burst_mode
)
157 writel(size
, &priv
->reg
->cycles
);
158 cmd
.ul
= readl(&priv
->reg
->command
.ul
);
159 cmd
.bits
.data_width
= param
->data_width
;
160 if ( param
->dest_sel
) { // AHB
161 #if 1 // add by Victor Yu. 07-12-2007
162 dmac_inv_range(param
->dest_addr
, param
->dest_addr
+param
->size
);
164 cmd
.bits
.dest_req_no
= 0;
166 cmd
.bits
.dest_req_no
= priv
->req_no
;
168 cmd
.bits
.dest_sel
= param
->dest_sel
;
169 if ( param
->source_sel
) { // AHB
170 #if 1 // add by Victor Yu. 07-12-2007
171 dmac_flush_range(param
->source_addr
, param
->source_addr
+param
->size
);
173 cmd
.bits
.source_req_no
= 0;
175 cmd
.bits
.source_req_no
= priv
->req_no
;
177 cmd
.bits
.source_sel
= param
->source_sel
;
178 cmd
.bits
.burst
= param
->burst_mode
;
179 cmd
.bits
.dest_inc
= param
->dest_inc
;
180 cmd
.bits
.source_inc
= param
->source_inc
;
181 writel(cmd
.ul
, &priv
->reg
->command
.ul
);
182 spin_unlock_irqrestore(&apb_dma_lock
, flags
);
184 EXPORT_SYMBOL(apb_dma_conf
);
186 void apb_dma_enable(apb_dma_priv
*priv
)
191 spin_lock_irqsave(&apb_dma_lock
, flags
);
192 cmd
= readl(&priv
->reg
->command
.ul
);
193 cmd
|= APB_DMA_ENABLE
;
194 writel(cmd
, &priv
->reg
->command
.ul
);
195 spin_unlock_irqrestore(&apb_dma_lock
, flags
);
197 EXPORT_SYMBOL(apb_dma_enable
);
198 EXPORT_SYMBOL(apb_dma_disable
);
199 void apb_dma_disable(apb_dma_priv
*priv
)
204 spin_lock_irqsave(&apb_dma_lock
, flags
);
205 cmd
= readl(&priv
->reg
->command
.ul
);
206 cmd
&= ~APB_DMA_ENABLE
;
207 writel(cmd
, &priv
->reg
->command
.ul
);
208 spin_unlock_irqrestore(&apb_dma_lock
, flags
);
211 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 03-08-2007
212 static irqreturn_t
apb_dma_irq(int irq
, void *devid
)
214 static irqreturn_t
apb_dma_irq(int irq
, void *devid
, struct pt_regs
*regs
)
215 #endif // LINUX_VERSION_CODE
219 apb_dma_priv
*priv
=apb_dma_channel
;
221 DBG("apb_dma_irq test01\n");
222 for ( i
=0; i
<APB_DMA_MAX_CHANNEL
; i
++, priv
++ ) {
223 cmd
= readl(&priv
->reg
->command
.ul
);
224 if ( cmd
& APB_DMA_FIN_INT_STS
) {
225 DBG("apb_dma_irq finish interrupt channel [%d]\n", i
);
226 cmd
&= ~APB_DMA_FIN_INT_STS
;
228 if ( cmd
& APB_DMA_ERR_INT_STS
) {
229 DBG("apb_dma_irq error interrupt channel [%d]\n", i
);
230 cmd
&= ~APB_DMA_ERR_INT_STS
;
231 priv
->error_flag
= 1;
233 if ( priv
->used_flag
&& priv
->irq_handler
) {
234 priv
->irq_handler(priv
->irq_handler_param
);
236 priv
->error_flag
= 0;
237 writel(cmd
, &priv
->reg
->command
.ul
);
243 static int __init
apb_dma_init(void)
246 apb_dma_priv
*priv
=apb_dma_channel
;
248 printk("Moxa CPU APB DMA Device Driver V1.0 load ");
250 memset(apb_dma_channel
, 0, sizeof(apb_dma_channel
));
251 spin_lock_init(&apb_dma_lock
);
253 for ( i
=0; i
<APB_DMA_MAX_CHANNEL
; i
++, priv
++ ) {
254 priv
->reg
= (apb_dma_reg
*)(CPE_APBDMA_BASE
+0x80+i
*sizeof(apb_dma_reg
));
257 cpe_int_set_irq(IRQ_APBDMA
, EDGE
, H_ACTIVE
);
258 ret
= request_irq(IRQ_APBDMA
, apb_dma_irq
, SA_INTERRUPT
, "APB DMA", NULL
);
267 module_init(apb_dma_init
);