MOXA linux-2.6.x / linux-2.6.9-uc0 from sdlinux-moxaart.tgz
[linux-2.6.9-moxart.git] / arch / arm / mach-moxacpu / apb_dma.c.old
blob2fd6993aa0be481ace3d6a9b133c9d0b7bfd659c
2 /*
3  * Copyright (C) 2005 Moxa Group All Rights Reserved.
4  *
5  * History:
6  *      Date            Author                  Comment
7  *      12-01-2005      Victor Yu.              Create it.
8  */
9 #include        <linux/config.h>
10 #include        <asm/arch/cpe/cpe.h>
11 #include        <linux/module.h>
12 #include        <linux/init.h>
13 #include        <linux/interrupt.h>
14 #include        <linux/mm.h>
15 #include        <linux/slab.h>
16 #include        <asm/io.h>
17 #include        <asm/dma.h>
18 #include        <asm/cacheflush.h>
19 #include        <asm/irq.h>
20 #include        <asm/arch/cpe_int.h>
22 //#define MOXA_DEBUG
23 #ifdef MOXA_DEBUG
24 #define DBG(x...)       printk(x)
25 #else
26 #define DBG(x...)
27 #endif
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)
34         int             i;
35         unsigned long   flags;
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 ) {
41                         priv->used_flag = 1;
42                         priv->irq_handler = NULL;
43                         priv->irq_handler_param = NULL;
44                         priv->conf_param = NULL;
45                         priv->error_flag = 0;
46                         priv->req_no = req_no;
47                         switch ( req_no ) {
48                         case APB_DMA_SPI_TX_REQ_NO :
49                                 *(unsigned int *)(CPE_PMU_VA_BASE+0xA0) = 0;
50                                 break;
51                         case APB_DMA_SPI_RX_REQ_NO :
52                                 *(unsigned int *)(CPE_PMU_VA_BASE+0xA4) = 0;
53                                 break;
54                         case APB_DMA_SD_REQ_NO :
55                                 *(unsigned int *)(CPE_PMU_VA_BASE+0xB8) = 0;
56                                 break;
57                         case APB_DMA_AC97_TX_REQ_NO :
58                                 *(unsigned int *)(CPE_PMU_VA_BASE+0xBC) = 0;
59                                 break;
60                         case APB_DMA_AC97_RX_REQ_NO :
61                                 *(unsigned int *)(CPE_PMU_VA_BASE+0xC0) = 0;
62                                 break;
63                         case APB_DMA_USB_DEVICE_REQ_NO :
64                                 *(unsigned int *)(CPE_PMU_VA_BASE+0xCC) = 0;
65                                 break;
66                         }
67                         spin_unlock_irqrestore(&apb_dma_lock, flags);
68                         DBG("apb_dma_alloc uses DMA channel %d\n", i);
69                         return priv;
70                 }
71         }
72         spin_unlock_irqrestore(&apb_dma_lock, flags);
73         return NULL;
75 EXPORT_SYMBOL(apb_dma_alloc);
77 void    apb_dma_release(apb_dma_priv *priv)
79         unsigned long   flags;
81         spin_lock_irqsave(&apb_dma_lock, flags);
82         if ( priv == NULL ) {
83                 spin_unlock_irqrestore(&apb_dma_lock, flags);
84                 return;
85         }
86         priv->used_flag = 0;
87         priv->error_flag = 0;
88         priv->irq_handler = NULL;
89         priv->irq_handler_param = NULL;
90         priv->conf_param = NULL;
91         priv->req_no = 0;
92         spin_unlock_irqrestore(&apb_dma_lock, flags);
94 EXPORT_SYMBOL(apb_dma_release);
96 void    apb_dma_set_irq(apb_dma_priv *priv, void (*func)(void *param), void *param)
98         unsigned long   flags;
99         unsigned int    cmd;
101         spin_lock_irqsave(&apb_dma_lock, flags);
102         if ( priv == NULL ) {
103                 spin_unlock_irqrestore(&apb_dma_lock, flags);
104                 return;
105         }
106         priv->irq_handler = func;
107         priv->irq_handler_param = param;
108         priv->error_flag = 0;
109         cmd = readl(&priv->reg->command.ul);
110         cmd |= (APB_DMA_FIN_INT_EN | APB_DMA_ERR_INT_EN);
111         writel(cmd, &priv->reg->command.ul);
112         spin_unlock_irqrestore(&apb_dma_lock, flags);
114 EXPORT_SYMBOL(apb_dma_set_irq);
116 void    apb_dma_release_irq(apb_dma_priv *priv)
118         unsigned long   flags;
119         unsigned int    cmd;
121         spin_lock_irqsave(&apb_dma_lock, flags);
122         if ( priv == NULL ) {
123                 spin_unlock_irqrestore(&apb_dma_lock, flags);
124                 return;
125         }
126         cmd = readl(&priv->reg->command.ul);
127         cmd &= ~(APB_DMA_FIN_INT_EN | APB_DMA_ERR_INT_EN);
128         writel(cmd, &priv->reg->command.ul);
129         priv->irq_handler = NULL;
130         priv->irq_handler_param = NULL;
131         priv->error_flag = 0;
132         spin_unlock_irqrestore(&apb_dma_lock, flags);
134 EXPORT_SYMBOL(apb_dma_release_irq);
136 void    apb_dma_conf(apb_dma_priv *priv, apb_dma_conf_param *param)
138         unsigned long   flags;
139         union _command  cmd;
140         unsigned int    size;
142         if ( param == NULL || priv == NULL )
143                 return;
144         spin_lock_irqsave(&apb_dma_lock, flags);
145 #ifdef CONFIG_UCLINUX
146         writel(param->source_addr, &priv->reg->source_addr);
147         writel(param->dest_addr, &priv->reg->dest_addr);
148 #else   // CONFIG_UCLINUX
149         priv->conf_param = param;
150         if ( param->source_sel == APB_DMAB_SOURCE_AHB )
151                 writel(virt_to_phys((void *)param->source_addr), &priv->reg->source_addr);
152         else
153                 writel(PHY_ADDRESS(param->source_addr), &priv->reg->source_addr);
154         if ( param->dest_sel == APB_DMAB_DEST_AHB )
155                 writel(virt_to_phys((void *)param->dest_addr), &priv->reg->dest_addr);
156         else
157                 writel(PHY_ADDRESS(param->dest_addr), &priv->reg->dest_addr);
158 #endif  // CONFIG_UCLINUX
159         size = param->size;
160         switch ( param->data_width ) {
161         case APB_DMAB_DATA_WIDTH_1 :
162                 break;
163         case APB_DMAB_DATA_WIDTH_2 :
164                 size >>= 1;
165                 break;
166         case APB_DMAB_DATA_WIDTH_4 :
167         default :
168                 size >>= 2;
169                 break;
170         }
171         if ( param->burst_mode )
172                 size >>= 2;
173         writel(size, &priv->reg->cycles);
174         cmd.ul = readl(&priv->reg->command.ul);
175         cmd.bits.data_width = param->data_width;
176         if ( param->dest_sel == APB_DMAB_DEST_AHB ) {   // AHB
177                 cmd.bits.dest_req_no = 0;
178         } else {        // APB
179                 cmd.bits.dest_req_no = priv->req_no;
180         }
181         cmd.bits.dest_sel = param->dest_sel;
182         if ( param->source_sel == APB_DMAB_SOURCE_AHB ) {       // AHB
183 #ifndef CONFIG_UCLINUX
184                 dmac_flush_range(param->source_addr, param->source_addr+param->size);
185 #endif  // CONFIG_UCLINUX
186                 cmd.bits.source_req_no = 0;
187         } else {        // APB
188                 cmd.bits.source_req_no = priv->req_no;
189         }
190         cmd.bits.source_sel = param->source_sel;
191         cmd.bits.burst = param->burst_mode;
192         cmd.bits.dest_inc = param->dest_inc;
193         cmd.bits.source_inc = param->source_inc;
194         writel(cmd.ul, &priv->reg->command.ul);
195         spin_unlock_irqrestore(&apb_dma_lock, flags);
197 EXPORT_SYMBOL(apb_dma_conf);
199 void    apb_dma_enable(apb_dma_priv *priv)
201         unsigned long   flags;
202         unsigned int    cmd;
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);
210 EXPORT_SYMBOL(apb_dma_enable);
212 void    apb_dma_disable(apb_dma_priv *priv)
214         unsigned long   flags;
215         unsigned int    cmd;
217         spin_lock_irqsave(&apb_dma_lock, flags);
218         cmd = readl(&priv->reg->command.ul);
219         cmd &= ~APB_DMA_ENABLE;
220         writel(cmd, &priv->reg->command.ul);    
221         spin_unlock_irqrestore(&apb_dma_lock, flags);
223 EXPORT_SYMBOL(apb_dma_disable);
225 static irqreturn_t apb_dma_irq(int irq, void *devid, struct pt_regs *regs)
227         int             i;
228         unsigned int    cmd;
229         apb_dma_priv    *priv=apb_dma_channel;
231         DBG("apb_dma_irq test01\n");
232         for ( i=0; i<APB_DMA_MAX_CHANNEL; i++, priv++ ) {
233                 cmd = readl(&priv->reg->command.ul);
234                 if ( cmd & APB_DMA_FIN_INT_STS ) {
235                         DBG("apb_dma_irq finish interrupt channel [%d]\n", i);
236                         cmd &= ~APB_DMA_FIN_INT_STS;
237 #ifndef CONFIG_UCLINUX
238                         {
239                         apb_dma_conf_param      *conf;
240                         if ( (conf=priv->conf_param) != NULL ) {
241                                 if ( conf->dest_sel == APB_DMAB_DEST_AHB ) {    // to DRAM
242                                         dmac_inv_range(conf->dest_addr, conf->dest_addr+conf->size);
243                                 }
244                                 priv->conf_param = NULL;
245                         }
246                         }
247 #endif  // CONFIG_UCLINUX
248                 }
249                 if ( cmd & APB_DMA_ERR_INT_STS ) {
250                         DBG("apb_dma_irq error interrupt channel [%d]\n", i);
251                         cmd &= ~APB_DMA_ERR_INT_STS;
252                         priv->error_flag = 1;
253                 }
254                 if ( priv->used_flag && priv->irq_handler ) {
255                         priv->irq_handler(priv->irq_handler_param);
256                 }
257                 priv->error_flag = 0;
258                 writel(cmd, &priv->reg->command.ul);
259         }
261         return IRQ_HANDLED;
264 static int __init       apb_dma_init(void)
266         int             ret, i;
267         apb_dma_priv    *priv=apb_dma_channel;
269         printk("Moxa CPU APB DMA Device Driver V1.0 load ");
271         memset(apb_dma_channel, 0, sizeof(apb_dma_channel));
272         spin_lock_init(&apb_dma_lock);
274         for ( i=0; i<APB_DMA_MAX_CHANNEL; i++, priv++ ) {
275                 priv->reg = (apb_dma_reg *)(CPE_APBDMA_VA_BASE+0x80+i*sizeof(apb_dma_reg));
276         }
278         cpe_int_set_irq(IRQ_APBDMA, EDGE, H_ACTIVE);
279         ret = request_irq(IRQ_APBDMA, apb_dma_irq, SA_INTERRUPT, "APB DMA", NULL);
280         if ( ret )
281                 printk("fail !\n");
282         else
283                 printk("OK.\n");
285         return ret;
288 module_init(apb_dma_init);