// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright ( C ) 1999 - 2000 Russell King
*
* ISA DMA primitives
* Taken from various sources , including :
* linux / include / asm / dma . h : Defines for using and allocating dma channels .
* Written by Hennus Bergman , 1992 .
* High DMA channel support & info by Hannu Savolainen and John Boyd ,
* Nov . 1992 .
* arch / arm / kernel / dma - ebsa285 . c
* Copyright ( C ) 1998 Phil Blundell
*/
#include <linux/dma-map-ops.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/dma-mapping.h>
#include <linux/io.h>
#include <asm /dma.h>
#include <asm /mach/dma.h>
#include <asm /hardware/dec21285.h>
#define ISA_DMA_MASK 0
#define ISA_DMA_MODE 1
#define ISA_DMA_CLRFF 2
#define ISA_DMA_PGHI 3
#define ISA_DMA_PGLO 4
#define ISA_DMA_ADDR 5
#define ISA_DMA_COUNT 6
static unsigned int isa_dma_port[8 ][7 ] = {
/* MASK MODE CLRFF PAGE_HI PAGE_LO ADDR COUNT */
{ 0 x0a, 0 x0b, 0 x0c, 0 x487, 0 x087, 0 x00, 0 x01 },
{ 0 x0a, 0 x0b, 0 x0c, 0 x483, 0 x083, 0 x02, 0 x03 },
{ 0 x0a, 0 x0b, 0 x0c, 0 x481, 0 x081, 0 x04, 0 x05 },
{ 0 x0a, 0 x0b, 0 x0c, 0 x482, 0 x082, 0 x06, 0 x07 },
{ 0 xd4, 0 xd6, 0 xd8, 0 x000, 0 x000, 0 xc0, 0 xc2 },
{ 0 xd4, 0 xd6, 0 xd8, 0 x48b, 0 x08b, 0 xc4, 0 xc6 },
{ 0 xd4, 0 xd6, 0 xd8, 0 x489, 0 x089, 0 xc8, 0 xca },
{ 0 xd4, 0 xd6, 0 xd8, 0 x48a, 0 x08a, 0 xcc, 0 xce }
};
static int isa_get_dma_residue(unsigned int chan, dma_t *dma)
{
unsigned int io_port = isa_dma_port[chan][ISA_DMA_COUNT];
int count;
count = 1 + inb(io_port);
count |= inb(io_port) << 8 ;
return chan < 4 ? count : (count << 1 );
}
static struct device isa_dma_dev = {
.init_name = "fallback device" ,
.coherent_dma_mask = ~(dma_addr_t)0 ,
.dma_mask = &isa_dma_dev.coherent_dma_mask,
};
static void isa_enable_dma(unsigned int chan, dma_t *dma)
{
if (dma->invalid) {
unsigned long address, length;
unsigned int mode;
enum dma_data_direction direction;
mode = (chan & 3 ) | dma->dma_mode;
switch (dma->dma_mode & DMA_MODE_MASK) {
case DMA_MODE_READ:
direction = DMA_FROM_DEVICE;
break ;
case DMA_MODE_WRITE:
direction = DMA_TO_DEVICE;
break ;
case DMA_MODE_CASCADE:
direction = DMA_BIDIRECTIONAL;
break ;
default :
direction = DMA_NONE;
break ;
}
if (!dma->sg) {
/*
* Cope with ISA - style drivers which expect cache
* coherence .
*/
dma->sg = &dma->buf;
dma->sgcount = 1 ;
dma->buf.length = dma->count;
dma->buf.dma_address = dma_map_single(&isa_dma_dev,
dma->addr, dma->count,
direction);
}
address = dma->buf.dma_address;
length = dma->buf.length - 1 ;
outb(address >> 16 , isa_dma_port[chan][ISA_DMA_PGLO]);
outb(address >> 24 , isa_dma_port[chan][ISA_DMA_PGHI]);
if (chan >= 4 ) {
address >>= 1 ;
length >>= 1 ;
}
outb(0 , isa_dma_port[chan][ISA_DMA_CLRFF]);
outb(address, isa_dma_port[chan][ISA_DMA_ADDR]);
outb(address >> 8 , isa_dma_port[chan][ISA_DMA_ADDR]);
outb(length, isa_dma_port[chan][ISA_DMA_COUNT]);
outb(length >> 8 , isa_dma_port[chan][ISA_DMA_COUNT]);
outb(mode, isa_dma_port[chan][ISA_DMA_MODE]);
dma->invalid = 0 ;
}
outb(chan & 3 , isa_dma_port[chan][ISA_DMA_MASK]);
}
static void isa_disable_dma(unsigned int chan, dma_t *dma)
{
outb(chan | 4 , isa_dma_port[chan][ISA_DMA_MASK]);
}
static struct dma_ops isa_dma_ops = {
.type = "ISA" ,
.enable = isa_enable_dma,
.disable = isa_disable_dma,
.residue = isa_get_dma_residue,
};
static struct resource dma_resources[] = { {
.name = "dma1" ,
.start = 0 x0000,
.end = 0 x000f
}, {
.name = "dma low page" ,
.start = 0 x0080,
.end = 0 x008f
}, {
.name = "dma2" ,
.start = 0 x00c0,
.end = 0 x00df
}, {
.name = "dma high page" ,
.start = 0 x0480,
.end = 0 x048f
} };
static dma_t isa_dma[8 ];
/*
* ISA DMA always starts at channel 0
*/
static int __init isa_dma_init(void )
{
/*
* Try to autodetect presence of an ISA DMA controller .
* We do some minimal initialisation , and check that
* channel 0 ' s DMA address registers are writeable .
*/
outb(0 xff, 0 x0d);
outb(0 xff, 0 xda);
/*
* Write high and low address , and then read them back
* in the same order .
*/
outb(0 x55, 0 x00);
outb(0 xaa, 0 x00);
if (inb(0 ) == 0 x55 && inb(0 ) == 0 xaa) {
unsigned int chan, i;
for (chan = 0 ; chan < 8 ; chan++) {
isa_dma[chan].d_ops = &isa_dma_ops;
isa_disable_dma(chan, NULL);
}
outb(0 x40, 0 x0b);
outb(0 x41, 0 x0b);
outb(0 x42, 0 x0b);
outb(0 x43, 0 x0b);
outb(0 xc0, 0 xd6);
outb(0 x41, 0 xd6);
outb(0 x42, 0 xd6);
outb(0 x43, 0 xd6);
outb(0 , 0 xd4);
outb(0 x10, 0 x08);
outb(0 x10, 0 xd0);
/*
* Is this correct ? According to my documentation , it
* doesn ' t appear to be . It should be :
* outb ( 0 x3f , 0 x40b ) ; outb ( 0 x3f , 0 x4d6 ) ;
*/
outb(0 x30, 0 x40b);
outb(0 x31, 0 x40b);
outb(0 x32, 0 x40b);
outb(0 x33, 0 x40b);
outb(0 x31, 0 x4d6);
outb(0 x32, 0 x4d6);
outb(0 x33, 0 x4d6);
for (i = 0 ; i < ARRAY_SIZE(dma_resources); i++)
request_resource(&ioport_resource, dma_resources + i);
for (chan = 0 ; chan < 8 ; chan++) {
int ret = isa_dma_add(chan, &isa_dma[chan]);
if (ret)
pr_err("ISADMA%u: unable to register: %d\n" ,
chan, ret);
}
request_dma(DMA_ISA_CASCADE, "cascade" );
}
dma_direct_set_offset(&isa_dma_dev, PHYS_OFFSET, BUS_OFFSET, SZ_256M);
return 0 ;
}
core_initcall(isa_dma_init);
Messung V0.5 in Prozent C=97 H=80 G=88
¤ Dauer der Verarbeitung: 0.12 Sekunden
(vorverarbeitet am 2026-09-27)
¤
*© Formatika GbR, Deutschland