linux/arch/arm/kernel/dma-isa.c
<<
>>
Prefs
   1/*
   2 *  linux/arch/arm/kernel/dma-isa.c
   3 *
   4 *  Copyright (C) 1999-2000 Russell King
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 as
   8 * published by the Free Software Foundation.
   9 *
  10 *  ISA DMA primitives
  11 *  Taken from various sources, including:
  12 *   linux/include/asm/dma.h: Defines for using and allocating dma channels.
  13 *     Written by Hennus Bergman, 1992.
  14 *     High DMA channel support & info by Hannu Savolainen and John Boyd,
  15 *     Nov. 1992.
  16 *   arch/arm/kernel/dma-ebsa285.c
  17 *   Copyright (C) 1998 Phil Blundell
  18 */
  19#include <linux/ioport.h>
  20#include <linux/init.h>
  21#include <linux/dma-mapping.h>
  22#include <linux/io.h>
  23
  24#include <asm/dma.h>
  25#include <asm/mach/dma.h>
  26
  27#define ISA_DMA_MASK            0
  28#define ISA_DMA_MODE            1
  29#define ISA_DMA_CLRFF           2
  30#define ISA_DMA_PGHI            3
  31#define ISA_DMA_PGLO            4
  32#define ISA_DMA_ADDR            5
  33#define ISA_DMA_COUNT           6
  34
  35static unsigned int isa_dma_port[8][7] = {
  36        /* MASK   MODE   CLRFF  PAGE_HI PAGE_LO ADDR COUNT */
  37        {  0x0a,  0x0b,  0x0c,  0x487,  0x087,  0x00, 0x01 },
  38        {  0x0a,  0x0b,  0x0c,  0x483,  0x083,  0x02, 0x03 },
  39        {  0x0a,  0x0b,  0x0c,  0x481,  0x081,  0x04, 0x05 },
  40        {  0x0a,  0x0b,  0x0c,  0x482,  0x082,  0x06, 0x07 },
  41        {  0xd4,  0xd6,  0xd8,  0x000,  0x000,  0xc0, 0xc2 },
  42        {  0xd4,  0xd6,  0xd8,  0x48b,  0x08b,  0xc4, 0xc6 },
  43        {  0xd4,  0xd6,  0xd8,  0x489,  0x089,  0xc8, 0xca },
  44        {  0xd4,  0xd6,  0xd8,  0x48a,  0x08a,  0xcc, 0xce }
  45};
  46
  47static int isa_get_dma_residue(unsigned int chan, dma_t *dma)
  48{
  49        unsigned int io_port = isa_dma_port[chan][ISA_DMA_COUNT];
  50        int count;
  51
  52        count = 1 + inb(io_port);
  53        count |= inb(io_port) << 8;
  54
  55        return chan < 4 ? count : (count << 1);
  56}
  57
  58static void isa_enable_dma(unsigned int chan, dma_t *dma)
  59{
  60        if (dma->invalid) {
  61                unsigned long address, length;
  62                unsigned int mode;
  63                enum dma_data_direction direction;
  64
  65                mode = (chan & 3) | dma->dma_mode;
  66                switch (dma->dma_mode & DMA_MODE_MASK) {
  67                case DMA_MODE_READ:
  68                        direction = DMA_FROM_DEVICE;
  69                        break;
  70
  71                case DMA_MODE_WRITE:
  72                        direction = DMA_TO_DEVICE;
  73                        break;
  74
  75                case DMA_MODE_CASCADE:
  76                        direction = DMA_BIDIRECTIONAL;
  77                        break;
  78
  79                default:
  80                        direction = DMA_NONE;
  81                        break;
  82                }
  83
  84                if (!dma->sg) {
  85                        /*
  86                         * Cope with ISA-style drivers which expect cache
  87                         * coherence.
  88                         */
  89                        dma->sg = &dma->buf;
  90                        dma->sgcount = 1;
  91                        dma->buf.length = dma->count;
  92                        dma->buf.dma_address = dma_map_single(NULL,
  93                                dma->addr, dma->count,
  94                                direction);
  95                }
  96
  97                address = dma->buf.dma_address;
  98                length  = dma->buf.length - 1;
  99
 100                outb(address >> 16, isa_dma_port[chan][ISA_DMA_PGLO]);
 101                outb(address >> 24, isa_dma_port[chan][ISA_DMA_PGHI]);
 102
 103                if (chan >= 4) {
 104                        address >>= 1;
 105                        length >>= 1;
 106                }
 107
 108                outb(0, isa_dma_port[chan][ISA_DMA_CLRFF]);
 109
 110                outb(address, isa_dma_port[chan][ISA_DMA_ADDR]);
 111                outb(address >> 8, isa_dma_port[chan][ISA_DMA_ADDR]);
 112
 113                outb(length, isa_dma_port[chan][ISA_DMA_COUNT]);
 114                outb(length >> 8, isa_dma_port[chan][ISA_DMA_COUNT]);
 115
 116                outb(mode, isa_dma_port[chan][ISA_DMA_MODE]);
 117                dma->invalid = 0;
 118        }
 119        outb(chan & 3, isa_dma_port[chan][ISA_DMA_MASK]);
 120}
 121
 122static void isa_disable_dma(unsigned int chan, dma_t *dma)
 123{
 124        outb(chan | 4, isa_dma_port[chan][ISA_DMA_MASK]);
 125}
 126
 127static struct dma_ops isa_dma_ops = {
 128        .type           = "ISA",
 129        .enable         = isa_enable_dma,
 130        .disable        = isa_disable_dma,
 131        .residue        = isa_get_dma_residue,
 132};
 133
 134static struct resource dma_resources[] = { {
 135        .name   = "dma1",
 136        .start  = 0x0000,
 137        .end    = 0x000f
 138}, {
 139        .name   = "dma low page",
 140        .start  = 0x0080,
 141        .end    = 0x008f
 142}, {
 143        .name   = "dma2",
 144        .start  = 0x00c0,
 145        .end    = 0x00df
 146}, {
 147        .name   = "dma high page",
 148        .start  = 0x0480,
 149        .end    = 0x048f
 150} };
 151
 152static dma_t isa_dma[8];
 153
 154/*
 155 * ISA DMA always starts at channel 0
 156 */
 157void __init isa_init_dma(void)
 158{
 159        /*
 160         * Try to autodetect presence of an ISA DMA controller.
 161         * We do some minimal initialisation, and check that
 162         * channel 0's DMA address registers are writeable.
 163         */
 164        outb(0xff, 0x0d);
 165        outb(0xff, 0xda);
 166
 167        /*
 168         * Write high and low address, and then read them back
 169         * in the same order.
 170         */
 171        outb(0x55, 0x00);
 172        outb(0xaa, 0x00);
 173
 174        if (inb(0) == 0x55 && inb(0) == 0xaa) {
 175                unsigned int chan, i;
 176
 177                for (chan = 0; chan < 8; chan++) {
 178                        isa_dma[chan].d_ops = &isa_dma_ops;
 179                        isa_disable_dma(chan, NULL);
 180                }
 181
 182                outb(0x40, 0x0b);
 183                outb(0x41, 0x0b);
 184                outb(0x42, 0x0b);
 185                outb(0x43, 0x0b);
 186
 187                outb(0xc0, 0xd6);
 188                outb(0x41, 0xd6);
 189                outb(0x42, 0xd6);
 190                outb(0x43, 0xd6);
 191
 192                outb(0, 0xd4);
 193
 194                outb(0x10, 0x08);
 195                outb(0x10, 0xd0);
 196
 197                /*
 198                 * Is this correct?  According to my documentation, it
 199                 * doesn't appear to be.  It should be:
 200                 *  outb(0x3f, 0x40b); outb(0x3f, 0x4d6);
 201                 */
 202                outb(0x30, 0x40b);
 203                outb(0x31, 0x40b);
 204                outb(0x32, 0x40b);
 205                outb(0x33, 0x40b);
 206                outb(0x31, 0x4d6);
 207                outb(0x32, 0x4d6);
 208                outb(0x33, 0x4d6);
 209
 210                for (i = 0; i < ARRAY_SIZE(dma_resources); i++)
 211                        request_resource(&ioport_resource, dma_resources + i);
 212
 213                for (chan = 0; chan < 8; chan++) {
 214                        int ret = isa_dma_add(chan, &isa_dma[chan]);
 215                        if (ret)
 216                                printk(KERN_ERR "ISADMA%u: unable to register: %d\n",
 217                                        chan, ret);
 218                }
 219
 220                request_dma(DMA_ISA_CASCADE, "cascade");
 221        }
 222}
 223