Skip to content

Commit

Permalink
Merge branch 'dma' into devel
Browse files Browse the repository at this point in the history
Conflicts:

	arch/arm/plat-mxc/dma-mx1-mx2.c
  • Loading branch information
Russell King authored and Russell King committed Feb 21, 2009
2 parents 423145a + fa4e998 commit 22b61a1
Show file tree
Hide file tree
Showing 13 changed files with 292 additions and 238 deletions.
46 changes: 21 additions & 25 deletions arch/arm/include/asm/dma.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,17 @@
#include <asm/system.h>
#include <asm/scatterlist.h>

typedef unsigned int dmach_t;

#include <mach/isa-dma.h>

/*
* DMA modes
* The DMA modes reflect the settings for the ISA DMA controller
*/
typedef unsigned int dmamode_t;

#define DMA_MODE_MASK 3
#define DMA_MODE_MASK 0xcc

#define DMA_MODE_READ 0
#define DMA_MODE_WRITE 1
#define DMA_MODE_CASCADE 2
#define DMA_AUTOINIT 4
#define DMA_MODE_READ 0x44
#define DMA_MODE_WRITE 0x48
#define DMA_MODE_CASCADE 0xc0
#define DMA_AUTOINIT 0x10

extern spinlock_t dma_spin_lock;

Expand All @@ -52,70 +48,70 @@ static inline void release_dma_lock(unsigned long flags)
/* Clear the 'DMA Pointer Flip Flop'.
* Write 0 for LSB/MSB, 1 for MSB/LSB access.
*/
#define clear_dma_ff(channel)
#define clear_dma_ff(chan)

/* Set only the page register bits of the transfer address.
*
* NOTE: This is an architecture specific function, and should
* be hidden from the drivers
*/
extern void set_dma_page(dmach_t channel, char pagenr);
extern void set_dma_page(unsigned int chan, char pagenr);

/* Request a DMA channel
*
* Some architectures may need to do allocate an interrupt
*/
extern int request_dma(dmach_t channel, const char * device_id);
extern int request_dma(unsigned int chan, const char * device_id);

/* Free a DMA channel
*
* Some architectures may need to do free an interrupt
*/
extern void free_dma(dmach_t channel);
extern void free_dma(unsigned int chan);

/* Enable DMA for this channel
*
* On some architectures, this may have other side effects like
* enabling an interrupt and setting the DMA registers.
*/
extern void enable_dma(dmach_t channel);
extern void enable_dma(unsigned int chan);

/* Disable DMA for this channel
*
* On some architectures, this may have other side effects like
* disabling an interrupt or whatever.
*/
extern void disable_dma(dmach_t channel);
extern void disable_dma(unsigned int chan);

/* Test whether the specified channel has an active DMA transfer
*/
extern int dma_channel_active(dmach_t channel);
extern int dma_channel_active(unsigned int chan);

/* Set the DMA scatter gather list for this channel
*
* This should not be called if a DMA channel is enabled,
* especially since some DMA architectures don't update the
* DMA address immediately, but defer it to the enable_dma().
*/
extern void set_dma_sg(dmach_t channel, struct scatterlist *sg, int nr_sg);
extern void set_dma_sg(unsigned int chan, struct scatterlist *sg, int nr_sg);

/* Set the DMA address for this channel
*
* This should not be called if a DMA channel is enabled,
* especially since some DMA architectures don't update the
* DMA address immediately, but defer it to the enable_dma().
*/
extern void __set_dma_addr(dmach_t channel, void *addr);
#define set_dma_addr(channel, addr) \
__set_dma_addr(channel, bus_to_virt(addr))
extern void __set_dma_addr(unsigned int chan, void *addr);
#define set_dma_addr(chan, addr) \
__set_dma_addr(chan, bus_to_virt(addr))

/* Set the DMA byte count for this channel
*
* This should not be called if a DMA channel is enabled,
* especially since some DMA architectures don't update the
* DMA count immediately, but defer it to the enable_dma().
*/
extern void set_dma_count(dmach_t channel, unsigned long count);
extern void set_dma_count(unsigned int chan, unsigned long count);

/* Set the transfer direction for this channel
*
Expand All @@ -124,19 +120,19 @@ extern void set_dma_count(dmach_t channel, unsigned long count);
* DMA transfer direction immediately, but defer it to the
* enable_dma().
*/
extern void set_dma_mode(dmach_t channel, dmamode_t mode);
extern void set_dma_mode(unsigned int chan, unsigned int mode);

/* Set the transfer speed for this channel
*/
extern void set_dma_speed(dmach_t channel, int cycle_ns);
extern void set_dma_speed(unsigned int chan, int cycle_ns);

/* Get DMA residue count. After a DMA transfer, this
* should return zero. Reading this while a DMA transfer is
* still in progress will return unpredictable results.
* If called before the channel has been used, it may return 1.
* Otherwise, it returns the number of _bytes_ left to transfer.
*/
extern int get_dma_residue(dmach_t channel);
extern int get_dma_residue(unsigned int chan);

#ifndef NO_DMA
#define NO_DMA 255
Expand Down
35 changes: 16 additions & 19 deletions arch/arm/include/asm/mach/dma.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ struct dma_struct;
typedef struct dma_struct dma_t;

struct dma_ops {
int (*request)(dmach_t, dma_t *); /* optional */
void (*free)(dmach_t, dma_t *); /* optional */
void (*enable)(dmach_t, dma_t *); /* mandatory */
void (*disable)(dmach_t, dma_t *); /* mandatory */
int (*residue)(dmach_t, dma_t *); /* optional */
int (*setspeed)(dmach_t, dma_t *, int); /* optional */
char *type;
int (*request)(unsigned int, dma_t *); /* optional */
void (*free)(unsigned int, dma_t *); /* optional */
void (*enable)(unsigned int, dma_t *); /* mandatory */
void (*disable)(unsigned int, dma_t *); /* mandatory */
int (*residue)(unsigned int, dma_t *); /* optional */
int (*setspeed)(unsigned int, dma_t *, int); /* optional */
const char *type;
};

struct dma_struct {
Expand All @@ -34,24 +34,21 @@ struct dma_struct {
unsigned int active:1; /* Transfer active */
unsigned int invalid:1; /* Address/Count changed */

dmamode_t dma_mode; /* DMA mode */
unsigned int dma_mode; /* DMA mode */
int speed; /* DMA speed */

unsigned int lock; /* Device is allocated */
const char *device_id; /* Device name */

unsigned int dma_base; /* Controller base address */
int dma_irq; /* Controller IRQ */
struct scatterlist cur_sg; /* Current controller buffer */
unsigned int state;

struct dma_ops *d_ops;
const struct dma_ops *d_ops;
};

/* Prototype: void arch_dma_init(dma)
* Purpose : Initialise architecture specific DMA
* Params : dma - pointer to array of DMA structures
/*
* isa_dma_add - add an ISA-style DMA channel
*/
extern void arch_dma_init(dma_t *dma);
extern int isa_dma_add(unsigned int, dma_t *dma);

extern void isa_init_dma(dma_t *dma);
/*
* Add the ISA DMA controller. Always takes channels 0-7.
*/
extern void isa_init_dma(void);
67 changes: 34 additions & 33 deletions arch/arm/kernel/dma-isa.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,6 @@
#include <asm/dma.h>
#include <asm/mach/dma.h>

#define ISA_DMA_MODE_READ 0x44
#define ISA_DMA_MODE_WRITE 0x48
#define ISA_DMA_MODE_CASCADE 0xc0
#define ISA_DMA_AUTOINIT 0x10

#define ISA_DMA_MASK 0
#define ISA_DMA_MODE 1
#define ISA_DMA_CLRFF 2
Expand All @@ -49,38 +44,35 @@ static unsigned int isa_dma_port[8][7] = {
{ 0xd4, 0xd6, 0xd8, 0x48a, 0x08a, 0xcc, 0xce }
};

static int isa_get_dma_residue(dmach_t channel, dma_t *dma)
static int isa_get_dma_residue(unsigned int chan, dma_t *dma)
{
unsigned int io_port = isa_dma_port[channel][ISA_DMA_COUNT];
unsigned int io_port = isa_dma_port[chan][ISA_DMA_COUNT];
int count;

count = 1 + inb(io_port);
count |= inb(io_port) << 8;

return channel < 4 ? count : (count << 1);
return chan < 4 ? count : (count << 1);
}

static void isa_enable_dma(dmach_t channel, dma_t *dma)
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 = channel & 3;
mode = (chan & 3) | dma->dma_mode;
switch (dma->dma_mode & DMA_MODE_MASK) {
case DMA_MODE_READ:
mode |= ISA_DMA_MODE_READ;
direction = DMA_FROM_DEVICE;
break;

case DMA_MODE_WRITE:
mode |= ISA_DMA_MODE_WRITE;
direction = DMA_TO_DEVICE;
break;

case DMA_MODE_CASCADE:
mode |= ISA_DMA_MODE_CASCADE;
direction = DMA_BIDIRECTIONAL;
break;

Expand All @@ -105,34 +97,31 @@ static void isa_enable_dma(dmach_t channel, dma_t *dma)
address = dma->buf.dma_address;
length = dma->buf.length - 1;

outb(address >> 16, isa_dma_port[channel][ISA_DMA_PGLO]);
outb(address >> 24, isa_dma_port[channel][ISA_DMA_PGHI]);
outb(address >> 16, isa_dma_port[chan][ISA_DMA_PGLO]);
outb(address >> 24, isa_dma_port[chan][ISA_DMA_PGHI]);

if (channel >= 4) {
if (chan >= 4) {
address >>= 1;
length >>= 1;
}

outb(0, isa_dma_port[channel][ISA_DMA_CLRFF]);

outb(address, isa_dma_port[channel][ISA_DMA_ADDR]);
outb(address >> 8, isa_dma_port[channel][ISA_DMA_ADDR]);
outb(0, isa_dma_port[chan][ISA_DMA_CLRFF]);

outb(length, isa_dma_port[channel][ISA_DMA_COUNT]);
outb(length >> 8, isa_dma_port[channel][ISA_DMA_COUNT]);
outb(address, isa_dma_port[chan][ISA_DMA_ADDR]);
outb(address >> 8, isa_dma_port[chan][ISA_DMA_ADDR]);

if (dma->dma_mode & DMA_AUTOINIT)
mode |= ISA_DMA_AUTOINIT;
outb(length, isa_dma_port[chan][ISA_DMA_COUNT]);
outb(length >> 8, isa_dma_port[chan][ISA_DMA_COUNT]);

outb(mode, isa_dma_port[channel][ISA_DMA_MODE]);
outb(mode, isa_dma_port[chan][ISA_DMA_MODE]);
dma->invalid = 0;
}
outb(channel & 3, isa_dma_port[channel][ISA_DMA_MASK]);
outb(chan & 3, isa_dma_port[chan][ISA_DMA_MASK]);
}

static void isa_disable_dma(dmach_t channel, dma_t *dma)
static void isa_disable_dma(unsigned int chan, dma_t *dma)
{
outb(channel | 4, isa_dma_port[channel][ISA_DMA_MASK]);
outb(chan | 4, isa_dma_port[chan][ISA_DMA_MASK]);
}

static struct dma_ops isa_dma_ops = {
Expand Down Expand Up @@ -160,7 +149,12 @@ static struct resource dma_resources[] = { {
.end = 0x048f
} };

void __init isa_init_dma(dma_t *dma)
static dma_t isa_dma[8];

/*
* ISA DMA always starts at channel 0
*/
void __init isa_init_dma(void)
{
/*
* Try to autodetect presence of an ISA DMA controller.
Expand All @@ -178,11 +172,11 @@ void __init isa_init_dma(dma_t *dma)
outb(0xaa, 0x00);

if (inb(0) == 0x55 && inb(0) == 0xaa) {
int channel, i;
unsigned int chan, i;

for (channel = 0; channel < 8; channel++) {
dma[channel].d_ops = &isa_dma_ops;
isa_disable_dma(channel, NULL);
for (chan = 0; chan < 8; chan++) {
isa_dma[chan].d_ops = &isa_dma_ops;
isa_disable_dma(chan, NULL);
}

outb(0x40, 0x0b);
Expand Down Expand Up @@ -217,5 +211,12 @@ void __init isa_init_dma(dma_t *dma)

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)
printk(KERN_ERR "ISADMA%u: unable to register: %d\n",
chan, ret);
}
}
}
Loading

0 comments on commit 22b61a1

Please sign in to comment.