aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc/kernel/ebus.c
diff options
context:
space:
mode:
authorSam Ravnborg <sam@ravnborg.org>2008-12-03 06:11:52 -0500
committerDavid S. Miller <davem@davemloft.net>2008-12-04 12:17:21 -0500
commita88b5ba8bd8ac18aad65ee6c6a254e2e74876db3 (patch)
treeeb3d0ffaf53c3f7ec6083752c2097cecd1cb892a /arch/sparc/kernel/ebus.c
parentd670bd4f803c8b646acd20f3ba21e65458293faf (diff)
sparc,sparc64: unify kernel/
o Move all files from sparc64/kernel/ to sparc/kernel - rename as appropriate o Update sparc/Makefile to the changes o Update sparc/kernel/Makefile to include the sparc64 files NOTE: This commit changes link order on sparc64! Link order had to change for either of sparc32 and sparc64. And assuming sparc64 see more testing than sparc32 change link order on sparc64 where issues will be caught faster. Signed-off-by: Sam Ravnborg <sam@ravnborg.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc/kernel/ebus.c')
-rw-r--r--arch/sparc/kernel/ebus.c257
1 files changed, 257 insertions, 0 deletions
diff --git a/arch/sparc/kernel/ebus.c b/arch/sparc/kernel/ebus.c
new file mode 100644
index 000000000000..77dbf6d45faf
--- /dev/null
+++ b/arch/sparc/kernel/ebus.c
@@ -0,0 +1,257 @@
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/module.h>
8#include <linux/kernel.h>
9#include <linux/types.h>
10#include <linux/init.h>
11#include <linux/interrupt.h>
12#include <linux/delay.h>
13
14#include <asm/ebus_dma.h>
15#include <asm/io.h>
16
17#define EBDMA_CSR 0x00UL /* Control/Status */
18#define EBDMA_ADDR 0x04UL /* DMA Address */
19#define EBDMA_COUNT 0x08UL /* DMA Count */
20
21#define EBDMA_CSR_INT_PEND 0x00000001
22#define EBDMA_CSR_ERR_PEND 0x00000002
23#define EBDMA_CSR_DRAIN 0x00000004
24#define EBDMA_CSR_INT_EN 0x00000010
25#define EBDMA_CSR_RESET 0x00000080
26#define EBDMA_CSR_WRITE 0x00000100
27#define EBDMA_CSR_EN_DMA 0x00000200
28#define EBDMA_CSR_CYC_PEND 0x00000400
29#define EBDMA_CSR_DIAG_RD_DONE 0x00000800
30#define EBDMA_CSR_DIAG_WR_DONE 0x00001000
31#define EBDMA_CSR_EN_CNT 0x00002000
32#define EBDMA_CSR_TC 0x00004000
33#define EBDMA_CSR_DIS_CSR_DRN 0x00010000
34#define EBDMA_CSR_BURST_SZ_MASK 0x000c0000
35#define EBDMA_CSR_BURST_SZ_1 0x00080000
36#define EBDMA_CSR_BURST_SZ_4 0x00000000
37#define EBDMA_CSR_BURST_SZ_8 0x00040000
38#define EBDMA_CSR_BURST_SZ_16 0x000c0000
39#define EBDMA_CSR_DIAG_EN 0x00100000
40#define EBDMA_CSR_DIS_ERR_PEND 0x00400000
41#define EBDMA_CSR_TCI_DIS 0x00800000
42#define EBDMA_CSR_EN_NEXT 0x01000000
43#define EBDMA_CSR_DMA_ON 0x02000000
44#define EBDMA_CSR_A_LOADED 0x04000000
45#define EBDMA_CSR_NA_LOADED 0x08000000
46#define EBDMA_CSR_DEV_ID_MASK 0xf0000000
47
48#define EBUS_DMA_RESET_TIMEOUT 10000
49
50static void __ebus_dma_reset(struct ebus_dma_info *p, int no_drain)
51{
52 int i;
53 u32 val = 0;
54
55 writel(EBDMA_CSR_RESET, p->regs + EBDMA_CSR);
56 udelay(1);
57
58 if (no_drain)
59 return;
60
61 for (i = EBUS_DMA_RESET_TIMEOUT; i > 0; i--) {
62 val = readl(p->regs + EBDMA_CSR);
63
64 if (!(val & (EBDMA_CSR_DRAIN | EBDMA_CSR_CYC_PEND)))
65 break;
66 udelay(10);
67 }
68}
69
70static irqreturn_t ebus_dma_irq(int irq, void *dev_id)
71{
72 struct ebus_dma_info *p = dev_id;
73 unsigned long flags;
74 u32 csr = 0;
75
76 spin_lock_irqsave(&p->lock, flags);
77 csr = readl(p->regs + EBDMA_CSR);
78 writel(csr, p->regs + EBDMA_CSR);
79 spin_unlock_irqrestore(&p->lock, flags);
80
81 if (csr & EBDMA_CSR_ERR_PEND) {
82 printk(KERN_CRIT "ebus_dma(%s): DMA error!\n", p->name);
83 p->callback(p, EBUS_DMA_EVENT_ERROR, p->client_cookie);
84 return IRQ_HANDLED;
85 } else if (csr & EBDMA_CSR_INT_PEND) {
86 p->callback(p,
87 (csr & EBDMA_CSR_TC) ?
88 EBUS_DMA_EVENT_DMA : EBUS_DMA_EVENT_DEVICE,
89 p->client_cookie);
90 return IRQ_HANDLED;
91 }
92
93 return IRQ_NONE;
94
95}
96
97int ebus_dma_register(struct ebus_dma_info *p)
98{
99 u32 csr;
100
101 if (!p->regs)
102 return -EINVAL;
103 if (p->flags & ~(EBUS_DMA_FLAG_USE_EBDMA_HANDLER |
104 EBUS_DMA_FLAG_TCI_DISABLE))
105 return -EINVAL;
106 if ((p->flags & EBUS_DMA_FLAG_USE_EBDMA_HANDLER) && !p->callback)
107 return -EINVAL;
108 if (!strlen(p->name))
109 return -EINVAL;
110
111 __ebus_dma_reset(p, 1);
112
113 csr = EBDMA_CSR_BURST_SZ_16 | EBDMA_CSR_EN_CNT;
114
115 if (p->flags & EBUS_DMA_FLAG_TCI_DISABLE)
116 csr |= EBDMA_CSR_TCI_DIS;
117
118 writel(csr, p->regs + EBDMA_CSR);
119
120 return 0;
121}
122EXPORT_SYMBOL(ebus_dma_register);
123
124int ebus_dma_irq_enable(struct ebus_dma_info *p, int on)
125{
126 unsigned long flags;
127 u32 csr;
128
129 if (on) {
130 if (p->flags & EBUS_DMA_FLAG_USE_EBDMA_HANDLER) {
131 if (request_irq(p->irq, ebus_dma_irq, IRQF_SHARED, p->name, p))
132 return -EBUSY;
133 }
134
135 spin_lock_irqsave(&p->lock, flags);
136 csr = readl(p->regs + EBDMA_CSR);
137 csr |= EBDMA_CSR_INT_EN;
138 writel(csr, p->regs + EBDMA_CSR);
139 spin_unlock_irqrestore(&p->lock, flags);
140 } else {
141 spin_lock_irqsave(&p->lock, flags);
142 csr = readl(p->regs + EBDMA_CSR);
143 csr &= ~EBDMA_CSR_INT_EN;
144 writel(csr, p->regs + EBDMA_CSR);
145 spin_unlock_irqrestore(&p->lock, flags);
146
147 if (p->flags & EBUS_DMA_FLAG_USE_EBDMA_HANDLER) {
148 free_irq(p->irq, p);
149 }
150 }
151
152 return 0;
153}
154EXPORT_SYMBOL(ebus_dma_irq_enable);
155
156void ebus_dma_unregister(struct ebus_dma_info *p)
157{
158 unsigned long flags;
159 u32 csr;
160 int irq_on = 0;
161
162 spin_lock_irqsave(&p->lock, flags);
163 csr = readl(p->regs + EBDMA_CSR);
164 if (csr & EBDMA_CSR_INT_EN) {
165 csr &= ~EBDMA_CSR_INT_EN;
166 writel(csr, p->regs + EBDMA_CSR);
167 irq_on = 1;
168 }
169 spin_unlock_irqrestore(&p->lock, flags);
170
171 if (irq_on)
172 free_irq(p->irq, p);
173}
174EXPORT_SYMBOL(ebus_dma_unregister);
175
176int ebus_dma_request(struct ebus_dma_info *p, dma_addr_t bus_addr, size_t len)
177{
178 unsigned long flags;
179 u32 csr;
180 int err;
181
182 if (len >= (1 << 24))
183 return -EINVAL;
184
185 spin_lock_irqsave(&p->lock, flags);
186 csr = readl(p->regs + EBDMA_CSR);
187 err = -EINVAL;
188 if (!(csr & EBDMA_CSR_EN_DMA))
189 goto out;
190 err = -EBUSY;
191 if (csr & EBDMA_CSR_NA_LOADED)
192 goto out;
193
194 writel(len, p->regs + EBDMA_COUNT);
195 writel(bus_addr, p->regs + EBDMA_ADDR);
196 err = 0;
197
198out:
199 spin_unlock_irqrestore(&p->lock, flags);
200
201 return err;
202}
203EXPORT_SYMBOL(ebus_dma_request);
204
205void ebus_dma_prepare(struct ebus_dma_info *p, int write)
206{
207 unsigned long flags;
208 u32 csr;
209
210 spin_lock_irqsave(&p->lock, flags);
211 __ebus_dma_reset(p, 0);
212
213 csr = (EBDMA_CSR_INT_EN |
214 EBDMA_CSR_EN_CNT |
215 EBDMA_CSR_BURST_SZ_16 |
216 EBDMA_CSR_EN_NEXT);
217
218 if (write)
219 csr |= EBDMA_CSR_WRITE;
220 if (p->flags & EBUS_DMA_FLAG_TCI_DISABLE)
221 csr |= EBDMA_CSR_TCI_DIS;
222
223 writel(csr, p->regs + EBDMA_CSR);
224
225 spin_unlock_irqrestore(&p->lock, flags);
226}
227EXPORT_SYMBOL(ebus_dma_prepare);
228
229unsigned int ebus_dma_residue(struct ebus_dma_info *p)
230{
231 return readl(p->regs + EBDMA_COUNT);
232}
233EXPORT_SYMBOL(ebus_dma_residue);
234
235unsigned int ebus_dma_addr(struct ebus_dma_info *p)
236{
237 return readl(p->regs + EBDMA_ADDR);
238}
239EXPORT_SYMBOL(ebus_dma_addr);
240
241void ebus_dma_enable(struct ebus_dma_info *p, int on)
242{
243 unsigned long flags;
244 u32 orig_csr, csr;
245
246 spin_lock_irqsave(&p->lock, flags);
247 orig_csr = csr = readl(p->regs + EBDMA_CSR);
248 if (on)
249 csr |= EBDMA_CSR_EN_DMA;
250 else
251 csr &= ~EBDMA_CSR_EN_DMA;
252 if ((orig_csr & EBDMA_CSR_EN_DMA) !=
253 (csr & EBDMA_CSR_EN_DMA))
254 writel(csr, p->regs + EBDMA_CSR);
255 spin_unlock_irqrestore(&p->lock, flags);
256}
257EXPORT_SYMBOL(ebus_dma_enable);