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