Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 22b61a11 authored by Russell King's avatar Russell King Committed by Russell King
Browse files

Merge branch 'dma' into devel

Conflicts:

	arch/arm/plat-mxc/dma-mx1-mx2.c
parents 423145a5 fa4e9989
Loading
Loading
Loading
Loading
+21 −25
Original line number Diff line number Diff line
@@ -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;

@@ -52,44 +48,44 @@ 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
 *
@@ -97,7 +93,7 @@ extern int dma_channel_active(dmach_t channel);
 * 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
 *
@@ -105,9 +101,9 @@ extern void set_dma_sg(dmach_t channel, struct scatterlist *sg, int nr_sg);
 * 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
 *
@@ -115,7 +111,7 @@ extern void __set_dma_addr(dmach_t channel, void *addr);
 * 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
 *
@@ -124,11 +120,11 @@ 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
@@ -136,7 +132,7 @@ extern void set_dma_speed(dmach_t channel, int cycle_ns);
 * 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
+16 −19
Original line number Diff line number Diff line
@@ -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 {
@@ -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);
+34 −33
Original line number Diff line number Diff line
@@ -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
@@ -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;

@@ -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 = {
@@ -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.
@@ -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);
@@ -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);
		}
	}
}
+67 −52
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/errno.h>
#include <linux/scatterlist.h>

#include <asm/dma.h>

@@ -23,19 +24,40 @@
DEFINE_SPINLOCK(dma_spin_lock);
EXPORT_SYMBOL(dma_spin_lock);

static dma_t dma_chan[MAX_DMA_CHANNELS];
static dma_t *dma_chan[MAX_DMA_CHANNELS];

static inline dma_t *dma_channel(unsigned int chan)
{
	if (chan >= MAX_DMA_CHANNELS)
		return NULL;

	return dma_chan[chan];
}

int __init isa_dma_add(unsigned int chan, dma_t *dma)
{
	if (!dma->d_ops)
		return -EINVAL;

	sg_init_table(&dma->buf, 1);

	if (dma_chan[chan])
		return -EBUSY;
	dma_chan[chan] = dma;
	return 0;
}

/*
 * Request DMA channel
 *
 * On certain platforms, we have to allocate an interrupt as well...
 */
int request_dma(dmach_t channel, const char *device_id)
int request_dma(unsigned int chan, const char *device_id)
{
	dma_t *dma = dma_chan + channel;
	dma_t *dma = dma_channel(chan);
	int ret;

	if (channel >= MAX_DMA_CHANNELS || !dma->d_ops)
	if (!dma)
		goto bad_dma;

	if (xchg(&dma->lock, 1) != 0)
@@ -47,7 +69,7 @@ int request_dma(dmach_t channel, const char *device_id)

	ret = 0;
	if (dma->d_ops->request)
		ret = dma->d_ops->request(channel, dma);
		ret = dma->d_ops->request(chan, dma);

	if (ret)
		xchg(&dma->lock, 0);
@@ -55,7 +77,7 @@ int request_dma(dmach_t channel, const char *device_id)
	return ret;

bad_dma:
	printk(KERN_ERR "dma: trying to allocate DMA%d\n", channel);
	printk(KERN_ERR "dma: trying to allocate DMA%d\n", chan);
	return -EINVAL;

busy:
@@ -68,42 +90,42 @@ EXPORT_SYMBOL(request_dma);
 *
 * On certain platforms, we have to free interrupt as well...
 */
void free_dma(dmach_t channel)
void free_dma(unsigned int chan)
{
	dma_t *dma = dma_chan + channel;
	dma_t *dma = dma_channel(chan);

	if (channel >= MAX_DMA_CHANNELS || !dma->d_ops)
	if (!dma)
		goto bad_dma;

	if (dma->active) {
		printk(KERN_ERR "dma%d: freeing active DMA\n", channel);
		dma->d_ops->disable(channel, dma);
		printk(KERN_ERR "dma%d: freeing active DMA\n", chan);
		dma->d_ops->disable(chan, dma);
		dma->active = 0;
	}

	if (xchg(&dma->lock, 0) != 0) {
		if (dma->d_ops->free)
			dma->d_ops->free(channel, dma);
			dma->d_ops->free(chan, dma);
		return;
	}

	printk(KERN_ERR "dma%d: trying to free free DMA\n", channel);
	printk(KERN_ERR "dma%d: trying to free free DMA\n", chan);
	return;

bad_dma:
	printk(KERN_ERR "dma: trying to free DMA%d\n", channel);
	printk(KERN_ERR "dma: trying to free DMA%d\n", chan);
}
EXPORT_SYMBOL(free_dma);

/* Set DMA Scatter-Gather list
 */
void set_dma_sg (dmach_t channel, struct scatterlist *sg, int nr_sg)
void set_dma_sg (unsigned int chan, struct scatterlist *sg, int nr_sg)
{
	dma_t *dma = dma_chan + channel;
	dma_t *dma = dma_channel(chan);

	if (dma->active)
		printk(KERN_ERR "dma%d: altering DMA SG while "
		       "DMA active\n", channel);
		       "DMA active\n", chan);

	dma->sg = sg;
	dma->sgcount = nr_sg;
@@ -115,13 +137,13 @@ EXPORT_SYMBOL(set_dma_sg);
 *
 * Copy address to the structure, and set the invalid bit
 */
void __set_dma_addr (dmach_t channel, void *addr)
void __set_dma_addr (unsigned int chan, void *addr)
{
	dma_t *dma = dma_chan + channel;
	dma_t *dma = dma_channel(chan);

	if (dma->active)
		printk(KERN_ERR "dma%d: altering DMA address while "
		       "DMA active\n", channel);
		       "DMA active\n", chan);

	dma->sg = NULL;
	dma->addr = addr;
@@ -133,13 +155,13 @@ EXPORT_SYMBOL(__set_dma_addr);
 *
 * Copy address to the structure, and set the invalid bit
 */
void set_dma_count (dmach_t channel, unsigned long count)
void set_dma_count (unsigned int chan, unsigned long count)
{
	dma_t *dma = dma_chan + channel;
	dma_t *dma = dma_channel(chan);

	if (dma->active)
		printk(KERN_ERR "dma%d: altering DMA count while "
		       "DMA active\n", channel);
		       "DMA active\n", chan);

	dma->sg = NULL;
	dma->count = count;
@@ -149,13 +171,13 @@ EXPORT_SYMBOL(set_dma_count);

/* Set DMA direction mode
 */
void set_dma_mode (dmach_t channel, dmamode_t mode)
void set_dma_mode (unsigned int chan, unsigned int mode)
{
	dma_t *dma = dma_chan + channel;
	dma_t *dma = dma_channel(chan);

	if (dma->active)
		printk(KERN_ERR "dma%d: altering DMA mode while "
		       "DMA active\n", channel);
		       "DMA active\n", chan);

	dma->dma_mode = mode;
	dma->invalid = 1;
@@ -164,42 +186,42 @@ EXPORT_SYMBOL(set_dma_mode);

/* Enable DMA channel
 */
void enable_dma (dmach_t channel)
void enable_dma (unsigned int chan)
{
	dma_t *dma = dma_chan + channel;
	dma_t *dma = dma_channel(chan);

	if (!dma->lock)
		goto free_dma;

	if (dma->active == 0) {
		dma->active = 1;
		dma->d_ops->enable(channel, dma);
		dma->d_ops->enable(chan, dma);
	}
	return;

free_dma:
	printk(KERN_ERR "dma%d: trying to enable free DMA\n", channel);
	printk(KERN_ERR "dma%d: trying to enable free DMA\n", chan);
	BUG();
}
EXPORT_SYMBOL(enable_dma);

/* Disable DMA channel
 */
void disable_dma (dmach_t channel)
void disable_dma (unsigned int chan)
{
	dma_t *dma = dma_chan + channel;
	dma_t *dma = dma_channel(chan);

	if (!dma->lock)
		goto free_dma;

	if (dma->active == 1) {
		dma->active = 0;
		dma->d_ops->disable(channel, dma);
		dma->d_ops->disable(chan, dma);
	}
	return;

free_dma:
	printk(KERN_ERR "dma%d: trying to disable free DMA\n", channel);
	printk(KERN_ERR "dma%d: trying to disable free DMA\n", chan);
	BUG();
}
EXPORT_SYMBOL(disable_dma);
@@ -207,45 +229,38 @@ EXPORT_SYMBOL(disable_dma);
/*
 * Is the specified DMA channel active?
 */
int dma_channel_active(dmach_t channel)
int dma_channel_active(unsigned int chan)
{
	return dma_chan[channel].active;
	dma_t *dma = dma_channel(chan);
	return dma->active;
}
EXPORT_SYMBOL(dma_channel_active);

void set_dma_page(dmach_t channel, char pagenr)
void set_dma_page(unsigned int chan, char pagenr)
{
	printk(KERN_ERR "dma%d: trying to set_dma_page\n", channel);
	printk(KERN_ERR "dma%d: trying to set_dma_page\n", chan);
}
EXPORT_SYMBOL(set_dma_page);

void set_dma_speed(dmach_t channel, int cycle_ns)
void set_dma_speed(unsigned int chan, int cycle_ns)
{
	dma_t *dma = dma_chan + channel;
	dma_t *dma = dma_channel(chan);
	int ret = 0;

	if (dma->d_ops->setspeed)
		ret = dma->d_ops->setspeed(channel, dma, cycle_ns);
		ret = dma->d_ops->setspeed(chan, dma, cycle_ns);
	dma->speed = ret;
}
EXPORT_SYMBOL(set_dma_speed);

int get_dma_residue(dmach_t channel)
int get_dma_residue(unsigned int chan)
{
	dma_t *dma = dma_chan + channel;
	dma_t *dma = dma_channel(chan);
	int ret = 0;

	if (dma->d_ops->residue)
		ret = dma->d_ops->residue(channel, dma);
		ret = dma->d_ops->residue(chan, dma);

	return ret;
}
EXPORT_SYMBOL(get_dma_residue);

static int __init init_dma(void)
{
	arch_dma_init(dma_chan);
	return 0;
}

core_initcall(init_dma);
+7 −5
Original line number Diff line number Diff line
@@ -21,16 +21,16 @@
#include <asm/hardware/dec21285.h>

#if 0
static int fb_dma_request(dmach_t channel, dma_t *dma)
static int fb_dma_request(unsigned int chan, dma_t *dma)
{
	return -EINVAL;
}

static void fb_dma_enable(dmach_t channel, dma_t *dma)
static void fb_dma_enable(unsigned int chan, dma_t *dma)
{
}

static void fb_dma_disable(dmach_t channel, dma_t *dma)
static void fb_dma_disable(unsigned int chan, dma_t *dma)
{
}

@@ -42,7 +42,7 @@ static struct dma_ops fb_dma_ops = {
};
#endif

void __init arch_dma_init(dma_t *dma)
static int __init fb_dma_init(void)
{
#if 0
	dma[_DC21285_DMA(0)].d_ops = &fb_dma_ops;
@@ -50,6 +50,8 @@ void __init arch_dma_init(dma_t *dma)
#endif
#ifdef CONFIG_ISA_DMA
	if (footbridge_cfn_mode())
		isa_init_dma(dma + _ISA_DMA(0));
		isa_init_dma();
#endif
	return 0;
}
core_initcall(fb_dma_init);
Loading