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