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