1// SPDX-License-Identifier: GPL-2.0
2/* ebus.c: EBUS DMA library code.
3 *
4 * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
5 * Copyright (C) 1999  David S. Miller (davem@redhat.com)
6 */
7
8#include <linux/export.h>
9#include <linux/kernel.h>
10#include <linux/types.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);
258