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