|  | @@ -0,0 +1,126 @@
 | 
	
		
			
				|  |  | +/* linux/arch/arm/plat-s3c64xx/dma.c
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * Copyright 2009 Openmoko, Inc.
 | 
	
		
			
				|  |  | + * Copyright 2009 Simtec Electronics
 | 
	
		
			
				|  |  | + *	Ben Dooks <ben@simtec.co.uk>
 | 
	
		
			
				|  |  | + *	http://armlinux.simtec.co.uk/
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * S3C64XX DMA core
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * This program is free software; you can redistribute it and/or modify
 | 
	
		
			
				|  |  | + * it under the terms of the GNU General Public License version 2 as
 | 
	
		
			
				|  |  | + * published by the Free Software Foundation.
 | 
	
		
			
				|  |  | +*/
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#include <linux/kernel.h>
 | 
	
		
			
				|  |  | +#include <linux/module.h>
 | 
	
		
			
				|  |  | +#include <linux/interrupt.h>
 | 
	
		
			
				|  |  | +#include <linux/dmapool.h>
 | 
	
		
			
				|  |  | +#include <linux/device.h>
 | 
	
		
			
				|  |  | +#include <linux/errno.h>
 | 
	
		
			
				|  |  | +#include <linux/slab.h>
 | 
	
		
			
				|  |  | +#include <linux/delay.h>
 | 
	
		
			
				|  |  | +#include <linux/clk.h>
 | 
	
		
			
				|  |  | +#include <linux/err.h>
 | 
	
		
			
				|  |  | +#include <linux/io.h>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#include <mach/dma.h>
 | 
	
		
			
				|  |  | +#include <mach/map.h>
 | 
	
		
			
				|  |  | +#include <mach/irqs.h>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#include <mach/regs-sys.h>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#include <asm/hardware/pl080.h>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* dma channel state information */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +struct s3c64xx_dmac {
 | 
	
		
			
				|  |  | +	struct device		dev;
 | 
	
		
			
				|  |  | +	struct clk		*clk;
 | 
	
		
			
				|  |  | +	void __iomem		*regs;
 | 
	
		
			
				|  |  | +	struct s3c2410_dma_chan *channels;
 | 
	
		
			
				|  |  | +	enum dma_ch		 chanbase;
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* pool to provide LLI buffers */
 | 
	
		
			
				|  |  | +static struct dma_pool *dma_pool;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* Debug configuration and code */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static unsigned char debug_show_buffs = 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void dbg_showchan(struct s3c2410_dma_chan *chan)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	pr_debug("DMA%d: %08x->%08x L %08x C %08x,%08x S %08x\n",
 | 
	
		
			
				|  |  | +		 chan->number,
 | 
	
		
			
				|  |  | +		 readl(chan->regs + PL080_CH_SRC_ADDR),
 | 
	
		
			
				|  |  | +		 readl(chan->regs + PL080_CH_DST_ADDR),
 | 
	
		
			
				|  |  | +		 readl(chan->regs + PL080_CH_LLI),
 | 
	
		
			
				|  |  | +		 readl(chan->regs + PL080_CH_CONTROL),
 | 
	
		
			
				|  |  | +		 readl(chan->regs + PL080S_CH_CONTROL2),
 | 
	
		
			
				|  |  | +		 readl(chan->regs + PL080S_CH_CONFIG));
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void show_lli(struct pl080s_lli *lli)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	pr_debug("LLI[%p] %08x->%08x, NL %08x C %08x,%08x\n",
 | 
	
		
			
				|  |  | +		 lli, lli->src_addr, lli->dst_addr, lli->next_lli,
 | 
	
		
			
				|  |  | +		 lli->control0, lli->control1);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void dbg_showbuffs(struct s3c2410_dma_chan *chan)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	struct s3c64xx_dma_buff *ptr;
 | 
	
		
			
				|  |  | +	struct s3c64xx_dma_buff *end;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	pr_debug("DMA%d: buffs next %p, curr %p, end %p\n",
 | 
	
		
			
				|  |  | +		 chan->number, chan->next, chan->curr, chan->end);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	ptr = chan->next;
 | 
	
		
			
				|  |  | +	end = chan->end;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (debug_show_buffs) {
 | 
	
		
			
				|  |  | +		for (; ptr != NULL; ptr = ptr->next) {
 | 
	
		
			
				|  |  | +			pr_debug("DMA%d: %08x ",
 | 
	
		
			
				|  |  | +				 chan->number, ptr->lli_dma);
 | 
	
		
			
				|  |  | +			show_lli(ptr->lli);
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* End of Debug */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static struct s3c2410_dma_chan *s3c64xx_dma_map_channel(unsigned int channel)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	struct s3c2410_dma_chan *chan;
 | 
	
		
			
				|  |  | +	unsigned int start, offs;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	start = 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (channel >= DMACH_PCM1_TX)
 | 
	
		
			
				|  |  | +		start = 8;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	for (offs = 0; offs < 8; offs++) {
 | 
	
		
			
				|  |  | +		chan = &s3c2410_chans[start + offs];
 | 
	
		
			
				|  |  | +		if (!chan->in_use)
 | 
	
		
			
				|  |  | +			goto found;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return NULL;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +found:
 | 
	
		
			
				|  |  | +	s3c_dma_chan_map[channel] = chan;
 | 
	
		
			
				|  |  | +	return chan;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +int s3c2410_dma_config(enum dma_ch channel, int xferunit)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (chan == NULL)
 | 
	
		
			
				|  |  | +		return -EINVAL;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	switch (xferunit) {
 | 
	
		
			
				|  |  | +	case 1:
 | 
	
		
			
				|  |  | +		chan->hw_width = 0;
 | 
	
		
			
				|  |  | +		break;
 |