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