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