Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / arch / unicore32 / kernel / dma.c
1 /*
2  * linux/arch/unicore32/kernel/dma.c
3  *
4  * Code specific to PKUnity SoC and UniCore ISA
5  *
6  *      Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
7  *      Copyright (C) 2001-2010 Guan Xuetao
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License version 2 as
11  * published by the Free Software Foundation.
12  */
13
14 #include <linux/module.h>
15 #include <linux/init.h>
16 #include <linux/kernel.h>
17 #include <linux/interrupt.h>
18 #include <linux/errno.h>
19 #include <linux/io.h>
20
21 #include <asm/irq.h>
22 #include <mach/hardware.h>
23 #include <mach/dma.h>
24
25 struct dma_channel {
26         char *name;
27         puv3_dma_prio prio;
28         void (*irq_handler)(int, void *);
29         void (*err_handler)(int, void *);
30         void *data;
31 };
32
33 static struct dma_channel dma_channels[MAX_DMA_CHANNELS];
34
35 int puv3_request_dma(char *name, puv3_dma_prio prio,
36                          void (*irq_handler)(int, void *),
37                          void (*err_handler)(int, void *),
38                          void *data)
39 {
40         unsigned long flags;
41         int i, found = 0;
42
43         /* basic sanity checks */
44         if (!name)
45                 return -EINVAL;
46
47         local_irq_save(flags);
48
49         do {
50                 /* try grabbing a DMA channel with the requested priority */
51                 for (i = 0; i < MAX_DMA_CHANNELS; i++) {
52                         if ((dma_channels[i].prio == prio) &&
53                             !dma_channels[i].name) {
54                                 found = 1;
55                                 break;
56                         }
57                 }
58                 /* if requested prio group is full, try a hier priority */
59         } while (!found && prio--);
60
61         if (found) {
62                 dma_channels[i].name = name;
63                 dma_channels[i].irq_handler = irq_handler;
64                 dma_channels[i].err_handler = err_handler;
65                 dma_channels[i].data = data;
66         } else {
67                 printk(KERN_WARNING "No more available DMA channels for %s\n",
68                                 name);
69                 i = -ENODEV;
70         }
71
72         local_irq_restore(flags);
73         return i;
74 }
75 EXPORT_SYMBOL(puv3_request_dma);
76
77 void puv3_free_dma(int dma_ch)
78 {
79         unsigned long flags;
80
81         if (!dma_channels[dma_ch].name) {
82                 printk(KERN_CRIT
83                         "%s: trying to free channel %d which is already freed\n",
84                         __func__, dma_ch);
85                 return;
86         }
87
88         local_irq_save(flags);
89         dma_channels[dma_ch].name = NULL;
90         dma_channels[dma_ch].err_handler = NULL;
91         local_irq_restore(flags);
92 }
93 EXPORT_SYMBOL(puv3_free_dma);
94
95 static irqreturn_t dma_irq_handler(int irq, void *dev_id)
96 {
97         int i, dint;
98
99         dint = readl(DMAC_ITCSR);
100         for (i = 0; i < MAX_DMA_CHANNELS; i++) {
101                 if (dint & DMAC_CHANNEL(i)) {
102                         struct dma_channel *channel = &dma_channels[i];
103
104                         /* Clear TC interrupt of channel i */
105                         writel(DMAC_CHANNEL(i), DMAC_ITCCR);
106                         writel(0, DMAC_ITCCR);
107
108                         if (channel->name && channel->irq_handler) {
109                                 channel->irq_handler(i, channel->data);
110                         } else {
111                                 /*
112                                  * IRQ for an unregistered DMA channel:
113                                  * let's clear the interrupts and disable it.
114                                  */
115                                 printk(KERN_WARNING "spurious IRQ for"
116                                                 " DMA channel %d\n", i);
117                         }
118                 }
119         }
120         return IRQ_HANDLED;
121 }
122
123 static irqreturn_t dma_err_handler(int irq, void *dev_id)
124 {
125         int i, dint;
126
127         dint = readl(DMAC_IESR);
128         for (i = 0; i < MAX_DMA_CHANNELS; i++) {
129                 if (dint & DMAC_CHANNEL(i)) {
130                         struct dma_channel *channel = &dma_channels[i];
131
132                         /* Clear Err interrupt of channel i */
133                         writel(DMAC_CHANNEL(i), DMAC_IECR);
134                         writel(0, DMAC_IECR);
135
136                         if (channel->name && channel->err_handler) {
137                                 channel->err_handler(i, channel->data);
138                         } else {
139                                 /*
140                                  * IRQ for an unregistered DMA channel:
141                                  * let's clear the interrupts and disable it.
142                                  */
143                                 printk(KERN_WARNING "spurious IRQ for"
144                                                 " DMA channel %d\n", i);
145                         }
146                 }
147         }
148         return IRQ_HANDLED;
149 }
150
151 int __init puv3_init_dma(void)
152 {
153         int i, ret;
154
155         /* dma channel priorities on v8 processors:
156          * ch 0 - 1  <--> (0) DMA_PRIO_HIGH
157          * ch 2 - 3  <--> (1) DMA_PRIO_MEDIUM
158          * ch 4 - 5  <--> (2) DMA_PRIO_LOW
159          */
160         for (i = 0; i < MAX_DMA_CHANNELS; i++) {
161                 puv3_stop_dma(i);
162                 dma_channels[i].name = NULL;
163                 dma_channels[i].prio = min((i & 0x7) >> 1, DMA_PRIO_LOW);
164         }
165
166         ret = request_irq(IRQ_DMA, dma_irq_handler, 0, "DMA", NULL);
167         if (ret) {
168                 printk(KERN_CRIT "Can't register IRQ for DMA\n");
169                 return ret;
170         }
171
172         ret = request_irq(IRQ_DMAERR, dma_err_handler, 0, "DMAERR", NULL);
173         if (ret) {
174                 printk(KERN_CRIT "Can't register IRQ for DMAERR\n");
175                 free_irq(IRQ_DMA, "DMA");
176                 return ret;
177         }
178
179         return 0;
180 }
181
182 postcore_initcall(puv3_init_dma);