]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - arch/sparc/kernel/ebus.c
sun4M: add include of slab.h for kzalloc
[karo-tx-linux.git] / arch / sparc / kernel / ebus.c
1 /* ebus.c: EBUS DMA library code.
2  *
3  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
4  * Copyright (C) 1999  David S. Miller (davem@redhat.com)
5  */
6
7 #include <linux/export.h>
8 #include <linux/kernel.h>
9 #include <linux/types.h>
10 #include <linux/interrupt.h>
11 #include <linux/delay.h>
12
13 #include <asm/ebus_dma.h>
14 #include <asm/io.h>
15
16 #define EBDMA_CSR       0x00UL  /* Control/Status */
17 #define EBDMA_ADDR      0x04UL  /* DMA Address */
18 #define EBDMA_COUNT     0x08UL  /* DMA Count */
19
20 #define EBDMA_CSR_INT_PEND      0x00000001
21 #define EBDMA_CSR_ERR_PEND      0x00000002
22 #define EBDMA_CSR_DRAIN         0x00000004
23 #define EBDMA_CSR_INT_EN        0x00000010
24 #define EBDMA_CSR_RESET         0x00000080
25 #define EBDMA_CSR_WRITE         0x00000100
26 #define EBDMA_CSR_EN_DMA        0x00000200
27 #define EBDMA_CSR_CYC_PEND      0x00000400
28 #define EBDMA_CSR_DIAG_RD_DONE  0x00000800
29 #define EBDMA_CSR_DIAG_WR_DONE  0x00001000
30 #define EBDMA_CSR_EN_CNT        0x00002000
31 #define EBDMA_CSR_TC            0x00004000
32 #define EBDMA_CSR_DIS_CSR_DRN   0x00010000
33 #define EBDMA_CSR_BURST_SZ_MASK 0x000c0000
34 #define EBDMA_CSR_BURST_SZ_1    0x00080000
35 #define EBDMA_CSR_BURST_SZ_4    0x00000000
36 #define EBDMA_CSR_BURST_SZ_8    0x00040000
37 #define EBDMA_CSR_BURST_SZ_16   0x000c0000
38 #define EBDMA_CSR_DIAG_EN       0x00100000
39 #define EBDMA_CSR_DIS_ERR_PEND  0x00400000
40 #define EBDMA_CSR_TCI_DIS       0x00800000
41 #define EBDMA_CSR_EN_NEXT       0x01000000
42 #define EBDMA_CSR_DMA_ON        0x02000000
43 #define EBDMA_CSR_A_LOADED      0x04000000
44 #define EBDMA_CSR_NA_LOADED     0x08000000
45 #define EBDMA_CSR_DEV_ID_MASK   0xf0000000
46
47 #define EBUS_DMA_RESET_TIMEOUT  10000
48
49 static void __ebus_dma_reset(struct ebus_dma_info *p, int no_drain)
50 {
51         int i;
52         u32 val = 0;
53
54         writel(EBDMA_CSR_RESET, p->regs + EBDMA_CSR);
55         udelay(1);
56
57         if (no_drain)
58                 return;
59
60         for (i = EBUS_DMA_RESET_TIMEOUT; i > 0; i--) {
61                 val = readl(p->regs + EBDMA_CSR);
62
63                 if (!(val & (EBDMA_CSR_DRAIN | EBDMA_CSR_CYC_PEND)))
64                         break;
65                 udelay(10);
66         }
67 }
68
69 static irqreturn_t ebus_dma_irq(int irq, void *dev_id)
70 {
71         struct ebus_dma_info *p = dev_id;
72         unsigned long flags;
73         u32 csr = 0;
74
75         spin_lock_irqsave(&p->lock, flags);
76         csr = readl(p->regs + EBDMA_CSR);
77         writel(csr, p->regs + EBDMA_CSR);
78         spin_unlock_irqrestore(&p->lock, flags);
79
80         if (csr & EBDMA_CSR_ERR_PEND) {
81                 printk(KERN_CRIT "ebus_dma(%s): DMA error!\n", p->name);
82                 p->callback(p, EBUS_DMA_EVENT_ERROR, p->client_cookie);
83                 return IRQ_HANDLED;
84         } else if (csr & EBDMA_CSR_INT_PEND) {
85                 p->callback(p,
86                             (csr & EBDMA_CSR_TC) ?
87                             EBUS_DMA_EVENT_DMA : EBUS_DMA_EVENT_DEVICE,
88                             p->client_cookie);
89                 return IRQ_HANDLED;
90         }
91
92         return IRQ_NONE;
93
94 }
95
96 int ebus_dma_register(struct ebus_dma_info *p)
97 {
98         u32 csr;
99
100         if (!p->regs)
101                 return -EINVAL;
102         if (p->flags & ~(EBUS_DMA_FLAG_USE_EBDMA_HANDLER |
103                          EBUS_DMA_FLAG_TCI_DISABLE))
104                 return -EINVAL;
105         if ((p->flags & EBUS_DMA_FLAG_USE_EBDMA_HANDLER) && !p->callback)
106                 return -EINVAL;
107         if (!strlen(p->name))
108                 return -EINVAL;
109
110         __ebus_dma_reset(p, 1);
111
112         csr = EBDMA_CSR_BURST_SZ_16 | EBDMA_CSR_EN_CNT;
113
114         if (p->flags & EBUS_DMA_FLAG_TCI_DISABLE)
115                 csr |= EBDMA_CSR_TCI_DIS;
116
117         writel(csr, p->regs + EBDMA_CSR);
118
119         return 0;
120 }
121 EXPORT_SYMBOL(ebus_dma_register);
122
123 int ebus_dma_irq_enable(struct ebus_dma_info *p, int on)
124 {
125         unsigned long flags;
126         u32 csr;
127
128         if (on) {
129                 if (p->flags & EBUS_DMA_FLAG_USE_EBDMA_HANDLER) {
130                         if (request_irq(p->irq, ebus_dma_irq, IRQF_SHARED, p->name, p))
131                                 return -EBUSY;
132                 }
133
134                 spin_lock_irqsave(&p->lock, flags);
135                 csr = readl(p->regs + EBDMA_CSR);
136                 csr |= EBDMA_CSR_INT_EN;
137                 writel(csr, p->regs + EBDMA_CSR);
138                 spin_unlock_irqrestore(&p->lock, flags);
139         } else {
140                 spin_lock_irqsave(&p->lock, flags);
141                 csr = readl(p->regs + EBDMA_CSR);
142                 csr &= ~EBDMA_CSR_INT_EN;
143                 writel(csr, p->regs + EBDMA_CSR);
144                 spin_unlock_irqrestore(&p->lock, flags);
145
146                 if (p->flags & EBUS_DMA_FLAG_USE_EBDMA_HANDLER) {
147                         free_irq(p->irq, p);
148                 }
149         }
150
151         return 0;
152 }
153 EXPORT_SYMBOL(ebus_dma_irq_enable);
154
155 void ebus_dma_unregister(struct ebus_dma_info *p)
156 {
157         unsigned long flags;
158         u32 csr;
159         int irq_on = 0;
160
161         spin_lock_irqsave(&p->lock, flags);
162         csr = readl(p->regs + EBDMA_CSR);
163         if (csr & EBDMA_CSR_INT_EN) {
164                 csr &= ~EBDMA_CSR_INT_EN;
165                 writel(csr, p->regs + EBDMA_CSR);
166                 irq_on = 1;
167         }
168         spin_unlock_irqrestore(&p->lock, flags);
169
170         if (irq_on)
171                 free_irq(p->irq, p);
172 }
173 EXPORT_SYMBOL(ebus_dma_unregister);
174
175 int ebus_dma_request(struct ebus_dma_info *p, dma_addr_t bus_addr, size_t len)
176 {
177         unsigned long flags;
178         u32 csr;
179         int err;
180
181         if (len >= (1 << 24))
182                 return -EINVAL;
183
184         spin_lock_irqsave(&p->lock, flags);
185         csr = readl(p->regs + EBDMA_CSR);
186         err = -EINVAL;
187         if (!(csr & EBDMA_CSR_EN_DMA))
188                 goto out;
189         err = -EBUSY;
190         if (csr & EBDMA_CSR_NA_LOADED)
191                 goto out;
192
193         writel(len,      p->regs + EBDMA_COUNT);
194         writel(bus_addr, p->regs + EBDMA_ADDR);
195         err = 0;
196
197 out:
198         spin_unlock_irqrestore(&p->lock, flags);
199
200         return err;
201 }
202 EXPORT_SYMBOL(ebus_dma_request);
203
204 void ebus_dma_prepare(struct ebus_dma_info *p, int write)
205 {
206         unsigned long flags;
207         u32 csr;
208
209         spin_lock_irqsave(&p->lock, flags);
210         __ebus_dma_reset(p, 0);
211
212         csr = (EBDMA_CSR_INT_EN |
213                EBDMA_CSR_EN_CNT |
214                EBDMA_CSR_BURST_SZ_16 |
215                EBDMA_CSR_EN_NEXT);
216
217         if (write)
218                 csr |= EBDMA_CSR_WRITE;
219         if (p->flags & EBUS_DMA_FLAG_TCI_DISABLE)
220                 csr |= EBDMA_CSR_TCI_DIS;
221
222         writel(csr, p->regs + EBDMA_CSR);
223
224         spin_unlock_irqrestore(&p->lock, flags);
225 }
226 EXPORT_SYMBOL(ebus_dma_prepare);
227
228 unsigned int ebus_dma_residue(struct ebus_dma_info *p)
229 {
230         return readl(p->regs + EBDMA_COUNT);
231 }
232 EXPORT_SYMBOL(ebus_dma_residue);
233
234 unsigned int ebus_dma_addr(struct ebus_dma_info *p)
235 {
236         return readl(p->regs + EBDMA_ADDR);
237 }
238 EXPORT_SYMBOL(ebus_dma_addr);
239
240 void ebus_dma_enable(struct ebus_dma_info *p, int on)
241 {
242         unsigned long flags;
243         u32 orig_csr, csr;
244
245         spin_lock_irqsave(&p->lock, flags);
246         orig_csr = csr = readl(p->regs + EBDMA_CSR);
247         if (on)
248                 csr |= EBDMA_CSR_EN_DMA;
249         else
250                 csr &= ~EBDMA_CSR_EN_DMA;
251         if ((orig_csr & EBDMA_CSR_EN_DMA) !=
252             (csr & EBDMA_CSR_EN_DMA))
253                 writel(csr, p->regs + EBDMA_CSR);
254         spin_unlock_irqrestore(&p->lock, flags);
255 }
256 EXPORT_SYMBOL(ebus_dma_enable);