|  | @@ -124,3 +124,130 @@ int s3c2410_dma_config(enum dma_ch channel, int xferunit)
 | 
	
		
			
				|  |  |  	case 1:
 | 
	
		
			
				|  |  |  		chan->hw_width = 0;
 | 
	
		
			
				|  |  |  		break;
 | 
	
		
			
				|  |  | +	case 2:
 | 
	
		
			
				|  |  | +		chan->hw_width = 1;
 | 
	
		
			
				|  |  | +		break;
 | 
	
		
			
				|  |  | +	case 4:
 | 
	
		
			
				|  |  | +		chan->hw_width = 2;
 | 
	
		
			
				|  |  | +		break;
 | 
	
		
			
				|  |  | +	default:
 | 
	
		
			
				|  |  | +		printk(KERN_ERR "%s: illegal width %d\n", __func__, xferunit);
 | 
	
		
			
				|  |  | +		return -EINVAL;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return 0;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +EXPORT_SYMBOL(s3c2410_dma_config);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void s3c64xx_dma_fill_lli(struct s3c2410_dma_chan *chan,
 | 
	
		
			
				|  |  | +				 struct pl080s_lli *lli,
 | 
	
		
			
				|  |  | +				 dma_addr_t data, int size)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	dma_addr_t src, dst;
 | 
	
		
			
				|  |  | +	u32 control0, control1;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	switch (chan->source) {
 | 
	
		
			
				|  |  | +	case DMA_FROM_DEVICE:
 | 
	
		
			
				|  |  | +		src = chan->dev_addr;
 | 
	
		
			
				|  |  | +		dst = data;
 | 
	
		
			
				|  |  | +		control0 = PL080_CONTROL_SRC_AHB2;
 | 
	
		
			
				|  |  | +		control0 |= PL080_CONTROL_DST_INCR;
 | 
	
		
			
				|  |  | +		break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	case DMA_TO_DEVICE:
 | 
	
		
			
				|  |  | +		src = data;
 | 
	
		
			
				|  |  | +		dst = chan->dev_addr;
 | 
	
		
			
				|  |  | +		control0 = PL080_CONTROL_DST_AHB2;
 | 
	
		
			
				|  |  | +		control0 |= PL080_CONTROL_SRC_INCR;
 | 
	
		
			
				|  |  | +		break;
 | 
	
		
			
				|  |  | +	default:
 | 
	
		
			
				|  |  | +		BUG();
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	/* note, we do not currently setup any of the burst controls */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	control1 = size >> chan->hw_width;	/* size in no of xfers */
 | 
	
		
			
				|  |  | +	control0 |= PL080_CONTROL_PROT_SYS;	/* always in priv. mode */
 | 
	
		
			
				|  |  | +	control0 |= PL080_CONTROL_TC_IRQ_EN;	/* always fire IRQ */
 | 
	
		
			
				|  |  | +	control0 |= (u32)chan->hw_width << PL080_CONTROL_DWIDTH_SHIFT;
 | 
	
		
			
				|  |  | +	control0 |= (u32)chan->hw_width << PL080_CONTROL_SWIDTH_SHIFT;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	lli->src_addr = src;
 | 
	
		
			
				|  |  | +	lli->dst_addr = dst;
 | 
	
		
			
				|  |  | +	lli->next_lli = 0;
 | 
	
		
			
				|  |  | +	lli->control0 = control0;
 | 
	
		
			
				|  |  | +	lli->control1 = control1;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void s3c64xx_lli_to_regs(struct s3c2410_dma_chan *chan,
 | 
	
		
			
				|  |  | +				struct pl080s_lli *lli)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	void __iomem *regs = chan->regs;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	pr_debug("%s: LLI %p => regs\n", __func__, lli);
 | 
	
		
			
				|  |  | +	show_lli(lli);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	writel(lli->src_addr, regs + PL080_CH_SRC_ADDR);
 | 
	
		
			
				|  |  | +	writel(lli->dst_addr, regs + PL080_CH_DST_ADDR);
 | 
	
		
			
				|  |  | +	writel(lli->next_lli, regs + PL080_CH_LLI);
 | 
	
		
			
				|  |  | +	writel(lli->control0, regs + PL080_CH_CONTROL);
 | 
	
		
			
				|  |  | +	writel(lli->control1, regs + PL080S_CH_CONTROL2);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static int s3c64xx_dma_start(struct s3c2410_dma_chan *chan)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	struct s3c64xx_dmac *dmac = chan->dmac;
 | 
	
		
			
				|  |  | +	u32 config;
 | 
	
		
			
				|  |  | +	u32 bit = chan->bit;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	dbg_showchan(chan);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	pr_debug("%s: clearing interrupts\n", __func__);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	/* clear interrupts */
 | 
	
		
			
				|  |  | +	writel(bit, dmac->regs + PL080_TC_CLEAR);
 | 
	
		
			
				|  |  | +	writel(bit, dmac->regs + PL080_ERR_CLEAR);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	pr_debug("%s: starting channel\n", __func__);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	config = readl(chan->regs + PL080S_CH_CONFIG);
 | 
	
		
			
				|  |  | +	config |= PL080_CONFIG_ENABLE;
 | 
	
		
			
				|  |  | +	config &= ~PL080_CONFIG_HALT;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	pr_debug("%s: writing config %08x\n", __func__, config);
 | 
	
		
			
				|  |  | +	writel(config, chan->regs + PL080S_CH_CONFIG);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return 0;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static int s3c64xx_dma_stop(struct s3c2410_dma_chan *chan)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	u32 config;
 | 
	
		
			
				|  |  | +	int timeout;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	pr_debug("%s: stopping channel\n", __func__);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	dbg_showchan(chan);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	config = readl(chan->regs + PL080S_CH_CONFIG);
 | 
	
		
			
				|  |  | +	config |= PL080_CONFIG_HALT;
 | 
	
		
			
				|  |  | +	writel(config, chan->regs + PL080S_CH_CONFIG);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	timeout = 1000;
 | 
	
		
			
				|  |  | +	do {
 | 
	
		
			
				|  |  | +		config = readl(chan->regs + PL080S_CH_CONFIG);
 | 
	
		
			
				|  |  | +		pr_debug("%s: %d - config %08x\n", __func__, timeout, config);
 | 
	
		
			
				|  |  | +		if (config & PL080_CONFIG_ACTIVE)
 | 
	
		
			
				|  |  | +			udelay(10);
 | 
	
		
			
				|  |  | +		else
 | 
	
		
			
				|  |  | +			break;
 | 
	
		
			
				|  |  | +		} while (--timeout > 0);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (config & PL080_CONFIG_ACTIVE) {
 | 
	
		
			
				|  |  | +		printk(KERN_ERR "%s: channel still active\n", __func__);
 | 
	
		
			
				|  |  | +		return -EFAULT;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	config = readl(chan->regs + PL080S_CH_CONFIG);
 | 
	
		
			
				|  |  | +	config &= ~PL080_CONFIG_ENABLE;
 | 
	
		
			
				|  |  | +	writel(config, chan->regs + PL080S_CH_CONFIG);
 |