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 pr_err("ISADMA%u: unable to register: %d\n", 217 chan, ret); 218 } 219 220 request_dma(DMA_ISA_CASCADE, "cascade"); 221 } 222} 223