linux/arch/arm/mach-rpc/dma.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 *  linux/arch/arm/mach-rpc/dma.c
   4 *
   5 *  Copyright (C) 1998 Russell King
   6 *
   7 *  DMA functions specific to RiscPC architecture
   8 */
   9#include <linux/mman.h>
  10#include <linux/init.h>
  11#include <linux/interrupt.h>
  12#include <linux/dma-mapping.h>
  13#include <linux/io.h>
  14
  15#include <asm/page.h>
  16#include <asm/dma.h>
  17#include <asm/fiq.h>
  18#include <asm/irq.h>
  19#include <mach/hardware.h>
  20#include <linux/uaccess.h>
  21
  22#include <asm/mach/dma.h>
  23#include <asm/hardware/iomd.h>
  24
  25struct iomd_dma {
  26        struct dma_struct       dma;
  27        void __iomem            *base;          /* Controller base address */
  28        int                     irq;            /* Controller IRQ */
  29        unsigned int            state;
  30        dma_addr_t              cur_addr;
  31        unsigned int            cur_len;
  32        dma_addr_t              dma_addr;
  33        unsigned int            dma_len;
  34};
  35
  36#if 0
  37typedef enum {
  38        dma_size_8      = 1,
  39        dma_size_16     = 2,
  40        dma_size_32     = 4,
  41        dma_size_128    = 16
  42} dma_size_t;
  43#endif
  44
  45#define TRANSFER_SIZE   2
  46
  47#define CURA    (0)
  48#define ENDA    (IOMD_IO0ENDA - IOMD_IO0CURA)
  49#define CURB    (IOMD_IO0CURB - IOMD_IO0CURA)
  50#define ENDB    (IOMD_IO0ENDB - IOMD_IO0CURA)
  51#define CR      (IOMD_IO0CR - IOMD_IO0CURA)
  52#define ST      (IOMD_IO0ST - IOMD_IO0CURA)
  53
  54static void iomd_get_next_sg(struct iomd_dma *idma)
  55{
  56        unsigned long end, offset, flags = 0;
  57
  58        if (idma->dma.sg) {
  59                idma->cur_addr = idma->dma_addr;
  60                offset = idma->cur_addr & ~PAGE_MASK;
  61
  62                end = offset + idma->dma_len;
  63
  64                if (end > PAGE_SIZE)
  65                        end = PAGE_SIZE;
  66
  67                if (offset + TRANSFER_SIZE >= end)
  68                        flags |= DMA_END_L;
  69
  70                idma->cur_len = end - TRANSFER_SIZE;
  71
  72                idma->dma_len -= end - offset;
  73                idma->dma_addr += end - offset;
  74
  75                if (idma->dma_len == 0) {
  76                        if (idma->dma.sgcount > 1) {
  77                                idma->dma.sg = sg_next(idma->dma.sg);
  78                                idma->dma_addr = idma->dma.sg->dma_address;
  79                                idma->dma_len = idma->dma.sg->length;
  80                                idma->dma.sgcount--;
  81                        } else {
  82                                idma->dma.sg = NULL;
  83                                flags |= DMA_END_S;
  84                        }
  85                }
  86        } else {
  87                flags = DMA_END_S | DMA_END_L;
  88                idma->cur_addr = 0;
  89                idma->cur_len = 0;
  90        }
  91
  92        idma->cur_len |= flags;
  93}
  94
  95static irqreturn_t iomd_dma_handle(int irq, void *dev_id)
  96{
  97        struct iomd_dma *idma = dev_id;
  98        void __iomem *base = idma->base;
  99        unsigned int state = idma->state;
 100        unsigned int status, cur, end;
 101
 102        do {
 103                status = readb(base + ST);
 104                if (!(status & DMA_ST_INT))
 105                        goto out;
 106
 107                if ((state ^ status) & DMA_ST_AB)
 108                        iomd_get_next_sg(idma);
 109
 110                // This efficiently implements state = OFL != AB ? AB : 0
 111                state = ((status >> 2) ^ status) & DMA_ST_AB;
 112                if (state) {
 113                        cur = CURA;
 114                        end = ENDA;
 115                } else {
 116                        cur = CURB;
 117                        end = ENDB;
 118                }
 119                writel(idma->cur_addr, base + cur);
 120                writel(idma->cur_len, base + end);
 121
 122                if (status & DMA_ST_OFL &&
 123                    idma->cur_len == (DMA_END_S|DMA_END_L))
 124                        break;
 125        } while (1);
 126
 127        state = ~DMA_ST_AB;
 128        disable_irq_nosync(irq);
 129out:
 130        idma->state = state;
 131        return IRQ_HANDLED;
 132}
 133
 134static int iomd_request_dma(unsigned int chan, dma_t *dma)
 135{
 136        struct iomd_dma *idma = container_of(dma, struct iomd_dma, dma);
 137
 138        return request_irq(idma->irq, iomd_dma_handle,
 139                           0, idma->dma.device_id, idma);
 140}
 141
 142static void iomd_free_dma(unsigned int chan, dma_t *dma)
 143{
 144        struct iomd_dma *idma = container_of(dma, struct iomd_dma, dma);
 145
 146        free_irq(idma->irq, idma);
 147}
 148
 149static struct device isa_dma_dev = {
 150        .init_name              = "fallback device",
 151        .coherent_dma_mask      = ~(dma_addr_t)0,
 152        .dma_mask               = &isa_dma_dev.coherent_dma_mask,
 153};
 154
 155static void iomd_enable_dma(unsigned int chan, dma_t *dma)
 156{
 157        struct iomd_dma *idma = container_of(dma, struct iomd_dma, dma);
 158        void __iomem *base = idma->base;
 159        unsigned int ctrl = TRANSFER_SIZE | DMA_CR_E;
 160
 161        if (idma->dma.invalid) {
 162                idma->dma.invalid = 0;
 163
 164                /*
 165                 * Cope with ISA-style drivers which expect cache
 166                 * coherence.
 167                 */
 168                if (!idma->dma.sg) {
 169                        idma->dma.sg = &idma->dma.buf;
 170                        idma->dma.sgcount = 1;
 171                        idma->dma.buf.length = idma->dma.count;
 172                        idma->dma.buf.dma_address = dma_map_single(&isa_dma_dev,
 173                                idma->dma.addr, idma->dma.count,
 174                                idma->dma.dma_mode == DMA_MODE_READ ?
 175                                DMA_FROM_DEVICE : DMA_TO_DEVICE);
 176                }
 177
 178                idma->dma_addr = idma->dma.sg->dma_address;
 179                idma->dma_len = idma->dma.sg->length;
 180
 181                writeb(DMA_CR_C, base + CR);
 182                idma->state = DMA_ST_AB;
 183        }
 184
 185        if (idma->dma.dma_mode == DMA_MODE_READ)
 186                ctrl |= DMA_CR_D;
 187
 188        writeb(ctrl, base + CR);
 189        enable_irq(idma->irq);
 190}
 191
 192static void iomd_disable_dma(unsigned int chan, dma_t *dma)
 193{
 194        struct iomd_dma *idma = container_of(dma, struct iomd_dma, dma);
 195        void __iomem *base = idma->base;
 196        unsigned long flags;
 197
 198        local_irq_save(flags);
 199        if (idma->state != ~DMA_ST_AB)
 200                disable_irq(idma->irq);
 201        writeb(0, base + CR);
 202        local_irq_restore(flags);
 203}
 204
 205static int iomd_set_dma_speed(unsigned int chan, dma_t *dma, int cycle)
 206{
 207        int tcr, speed;
 208
 209        if (cycle < 188)
 210                speed = 3;
 211        else if (cycle <= 250)
 212                speed = 2;
 213        else if (cycle < 438)
 214                speed = 1;
 215        else
 216                speed = 0;
 217
 218        tcr = iomd_readb(IOMD_DMATCR);
 219        speed &= 3;
 220
 221        switch (chan) {
 222        case DMA_0:
 223                tcr = (tcr & ~0x03) | speed;
 224                break;
 225
 226        case DMA_1:
 227                tcr = (tcr & ~0x0c) | (speed << 2);
 228                break;
 229
 230        case DMA_2:
 231                tcr = (tcr & ~0x30) | (speed << 4);
 232                break;
 233
 234        case DMA_3:
 235                tcr = (tcr & ~0xc0) | (speed << 6);
 236                break;
 237
 238        default:
 239                break;
 240        }
 241
 242        iomd_writeb(tcr, IOMD_DMATCR);
 243
 244        return speed;
 245}
 246
 247static struct dma_ops iomd_dma_ops = {
 248        .type           = "IOMD",
 249        .request        = iomd_request_dma,
 250        .free           = iomd_free_dma,
 251        .enable         = iomd_enable_dma,
 252        .disable        = iomd_disable_dma,
 253        .setspeed       = iomd_set_dma_speed,
 254};
 255
 256static struct fiq_handler fh = {
 257        .name   = "floppydma"
 258};
 259
 260struct floppy_dma {
 261        struct dma_struct       dma;
 262        unsigned int            fiq;
 263};
 264
 265static void floppy_enable_dma(unsigned int chan, dma_t *dma)
 266{
 267        struct floppy_dma *fdma = container_of(dma, struct floppy_dma, dma);
 268        void *fiqhandler_start;
 269        unsigned int fiqhandler_length;
 270        struct pt_regs regs;
 271
 272        if (fdma->dma.sg)
 273                BUG();
 274
 275        if (fdma->dma.dma_mode == DMA_MODE_READ) {
 276                extern unsigned char floppy_fiqin_start, floppy_fiqin_end;
 277                fiqhandler_start = &floppy_fiqin_start;
 278                fiqhandler_length = &floppy_fiqin_end - &floppy_fiqin_start;
 279        } else {
 280                extern unsigned char floppy_fiqout_start, floppy_fiqout_end;
 281                fiqhandler_start = &floppy_fiqout_start;
 282                fiqhandler_length = &floppy_fiqout_end - &floppy_fiqout_start;
 283        }
 284
 285        regs.ARM_r9  = fdma->dma.count;
 286        regs.ARM_r10 = (unsigned long)fdma->dma.addr;
 287        regs.ARM_fp  = (unsigned long)FLOPPYDMA_BASE;
 288
 289        if (claim_fiq(&fh)) {
 290                printk("floppydma: couldn't claim FIQ.\n");
 291                return;
 292        }
 293
 294        set_fiq_handler(fiqhandler_start, fiqhandler_length);
 295        set_fiq_regs(&regs);
 296        enable_fiq(fdma->fiq);
 297}
 298
 299static void floppy_disable_dma(unsigned int chan, dma_t *dma)
 300{
 301        struct floppy_dma *fdma = container_of(dma, struct floppy_dma, dma);
 302        disable_fiq(fdma->fiq);
 303        release_fiq(&fh);
 304}
 305
 306static int floppy_get_residue(unsigned int chan, dma_t *dma)
 307{
 308        struct pt_regs regs;
 309        get_fiq_regs(&regs);
 310        return regs.ARM_r9;
 311}
 312
 313static struct dma_ops floppy_dma_ops = {
 314        .type           = "FIQDMA",
 315        .enable         = floppy_enable_dma,
 316        .disable        = floppy_disable_dma,
 317        .residue        = floppy_get_residue,
 318};
 319
 320/*
 321 * This is virtual DMA - we don't need anything here.
 322 */
 323static void sound_enable_disable_dma(unsigned int chan, dma_t *dma)
 324{
 325}
 326
 327static struct dma_ops sound_dma_ops = {
 328        .type           = "VIRTUAL",
 329        .enable         = sound_enable_disable_dma,
 330        .disable        = sound_enable_disable_dma,
 331};
 332
 333static struct iomd_dma iomd_dma[6];
 334
 335static struct floppy_dma floppy_dma = {
 336        .dma            = {
 337                .d_ops  = &floppy_dma_ops,
 338        },
 339        .fiq            = FIQ_FLOPPYDATA,
 340};
 341
 342static dma_t sound_dma = {
 343        .d_ops          = &sound_dma_ops,
 344};
 345
 346static int __init rpc_dma_init(void)
 347{
 348        unsigned int i;
 349        int ret;
 350
 351        iomd_writeb(0, IOMD_IO0CR);
 352        iomd_writeb(0, IOMD_IO1CR);
 353        iomd_writeb(0, IOMD_IO2CR);
 354        iomd_writeb(0, IOMD_IO3CR);
 355
 356        iomd_writeb(0xa0, IOMD_DMATCR);
 357
 358        /*
 359         * Setup DMA channels 2,3 to be for podules
 360         * and channels 0,1 for internal devices
 361         */
 362        iomd_writeb(DMA_EXT_IO3|DMA_EXT_IO2, IOMD_DMAEXT);
 363
 364        iomd_dma[DMA_0].base    = IOMD_BASE + IOMD_IO0CURA;
 365        iomd_dma[DMA_0].irq     = IRQ_DMA0;
 366        iomd_dma[DMA_1].base    = IOMD_BASE + IOMD_IO1CURA;
 367        iomd_dma[DMA_1].irq     = IRQ_DMA1;
 368        iomd_dma[DMA_2].base    = IOMD_BASE + IOMD_IO2CURA;
 369        iomd_dma[DMA_2].irq     = IRQ_DMA2;
 370        iomd_dma[DMA_3].base    = IOMD_BASE + IOMD_IO3CURA;
 371        iomd_dma[DMA_3].irq     = IRQ_DMA3;
 372        iomd_dma[DMA_S0].base   = IOMD_BASE + IOMD_SD0CURA;
 373        iomd_dma[DMA_S0].irq    = IRQ_DMAS0;
 374        iomd_dma[DMA_S1].base   = IOMD_BASE + IOMD_SD1CURA;
 375        iomd_dma[DMA_S1].irq    = IRQ_DMAS1;
 376
 377        for (i = DMA_0; i <= DMA_S1; i++) {
 378                iomd_dma[i].dma.d_ops = &iomd_dma_ops;
 379
 380                ret = isa_dma_add(i, &iomd_dma[i].dma);
 381                if (ret)
 382                        printk("IOMDDMA%u: unable to register: %d\n", i, ret);
 383        }
 384
 385        ret = isa_dma_add(DMA_VIRTUAL_FLOPPY, &floppy_dma.dma);
 386        if (ret)
 387                printk("IOMDFLOPPY: unable to register: %d\n", ret);
 388        ret = isa_dma_add(DMA_VIRTUAL_SOUND, &sound_dma);
 389        if (ret)
 390                printk("IOMDSOUND: unable to register: %d\n", ret);
 391        return 0;
 392}
 393core_initcall(rpc_dma_init);
 394