linux/arch/sparc/kernel/ebus.c
<<
>>
Prefs
   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