xref: /openbmc/linux/arch/sparc/kernel/ebus.c (revision 483eb062)
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);
257