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
49static 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
69static 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
96int 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}
121EXPORT_SYMBOL(ebus_dma_register);
122
123int 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}
153EXPORT_SYMBOL(ebus_dma_irq_enable);
154
155void 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}
173EXPORT_SYMBOL(ebus_dma_unregister);
174
175int 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
197out:
198	spin_unlock_irqrestore(&p->lock, flags);
199
200	return err;
201}
202EXPORT_SYMBOL(ebus_dma_request);
203
204void 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}
226EXPORT_SYMBOL(ebus_dma_prepare);
227
228unsigned int ebus_dma_residue(struct ebus_dma_info *p)
229{
230	return readl(p->regs + EBDMA_COUNT);
231}
232EXPORT_SYMBOL(ebus_dma_residue);
233
234unsigned int ebus_dma_addr(struct ebus_dma_info *p)
235{
236	return readl(p->regs + EBDMA_ADDR);
237}
238EXPORT_SYMBOL(ebus_dma_addr);
239
240void 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}
256EXPORT_SYMBOL(ebus_dma_enable);
257