1a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* linux/arch/arm/plat-s3c24xx/dma.c 2a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * 3e02f866456ec31d20649670e3af048ddc2a3892bBen Dooks * Copyright 2003-2006 Simtec Electronics 4a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * Ben Dooks <ben@simtec.co.uk> 5a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * 6a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * S3C2410 DMA core 7a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * 8a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * http://armlinux.simtec.co.uk/ 9a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * 10a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * This program is free software; you can redistribute it and/or modify 11a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * it under the terms of the GNU General Public License version 2 as 12a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * published by the Free Software Foundation. 13a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks*/ 14a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 15a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 16a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#ifdef CONFIG_S3C2410_DMA_DEBUG 17a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#define DEBUG 18a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#endif 19a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 20a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#include <linux/module.h> 21a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#include <linux/init.h> 22a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#include <linux/sched.h> 23a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#include <linux/spinlock.h> 24a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#include <linux/interrupt.h> 25bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysocki#include <linux/syscore_ops.h> 26a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#include <linux/slab.h> 27a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#include <linux/errno.h> 28fced80c735941fa518ac67c0b61bbe153fb8c050Russell King#include <linux/io.h> 29a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 30a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#include <asm/irq.h> 31a09e64fbc0094e3073dbb09c3b4bfe4ab669244bRussell King#include <mach/hardware.h> 32dcea83adc666061864b82c96e059dffe7268b512Russell King#include <mach/dma.h> 33a09e64fbc0094e3073dbb09c3b4bfe4ab669244bRussell King#include <mach/map.h> 34a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 35992426bfe98e71db1ce767fd66f6c68ed18fcc14Ben Dooks#include <plat/dma-s3c24xx.h> 3644dc94045f6ddbc07db3e0eb3448c2efc13ac2cfBen Dooks#include <plat/regs-dma.h> 37a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 38a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* io map for dma */ 39a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksstatic void __iomem *dma_base; 40a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksstatic struct kmem_cache *dma_kmem; 41a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 4248adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooksstatic int dma_channels; 4348adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooks 44a7717435656c874843b1742383cc37540f5ff91eBen Dooksstatic struct s3c24xx_dma_selection dma_sel; 45a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 46a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 47a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* debugging functions */ 48a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 49a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#define BUF_MAGIC (0xcafebabe) 50a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 51a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#define dmawarn(fmt...) printk(KERN_DEBUG fmt) 52a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 53a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#define dma_regaddr(chan, reg) ((chan)->regs + (reg)) 54a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 55a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#if 1 56a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#define dma_wrreg(chan, reg, val) writel((val), (chan)->regs + (reg)) 57a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#else 58a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksstatic inline void 59a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksdma_wrreg(struct s3c2410_dma_chan *chan, int reg, unsigned long val) 60a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{ 61a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks pr_debug("writing %08x to register %08x\n",(unsigned int)val,reg); 62a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks writel(val, dma_regaddr(chan, reg)); 63a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks} 64a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#endif 65a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 66a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#define dma_rdreg(chan, reg) readl((chan)->regs + (reg)) 67a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 68a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* captured register state for debug */ 69a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 70a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksstruct s3c2410_dma_regstate { 71a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks unsigned long dcsrc; 72a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks unsigned long disrc; 73a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks unsigned long dstat; 74a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks unsigned long dcon; 75a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks unsigned long dmsktrig; 76a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks}; 77a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 78a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#ifdef CONFIG_S3C2410_DMA_DEBUG 79a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 80a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* dmadbg_showregs 81a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * 82a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * simple debug routine to print the current state of the dma registers 83a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks*/ 84a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 85a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksstatic void 86a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksdmadbg_capture(struct s3c2410_dma_chan *chan, struct s3c2410_dma_regstate *regs) 87a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{ 88a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks regs->dcsrc = dma_rdreg(chan, S3C2410_DMA_DCSRC); 89a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks regs->disrc = dma_rdreg(chan, S3C2410_DMA_DISRC); 90a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks regs->dstat = dma_rdreg(chan, S3C2410_DMA_DSTAT); 91a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks regs->dcon = dma_rdreg(chan, S3C2410_DMA_DCON); 92a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks regs->dmsktrig = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG); 93a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks} 94a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 95a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksstatic void 96a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksdmadbg_dumpregs(const char *fname, int line, struct s3c2410_dma_chan *chan, 97a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks struct s3c2410_dma_regstate *regs) 98a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{ 99a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks printk(KERN_DEBUG "dma%d: %s:%d: DCSRC=%08lx, DISRC=%08lx, DSTAT=%08lx DMT=%02lx, DCON=%08lx\n", 100a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->number, fname, line, 101a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks regs->dcsrc, regs->disrc, regs->dstat, regs->dmsktrig, 102a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks regs->dcon); 103a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks} 104a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 105a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksstatic void 106a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksdmadbg_showchan(const char *fname, int line, struct s3c2410_dma_chan *chan) 107a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{ 108a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks struct s3c2410_dma_regstate state; 109a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 110a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks dmadbg_capture(chan, &state); 111a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 112a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks printk(KERN_DEBUG "dma%d: %s:%d: ls=%d, cur=%p, %p %p\n", 113a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->number, fname, line, chan->load_state, 114a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->curr, chan->next, chan->end); 115a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 116a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks dmadbg_dumpregs(fname, line, chan, &state); 117a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks} 118a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 119a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksstatic void 120a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksdmadbg_showregs(const char *fname, int line, struct s3c2410_dma_chan *chan) 121a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{ 122a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks struct s3c2410_dma_regstate state; 123a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 124a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks dmadbg_capture(chan, &state); 125a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks dmadbg_dumpregs(fname, line, chan, &state); 126a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks} 127a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1288e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison#define dbg_showregs(chan) dmadbg_showregs(__func__, __LINE__, (chan)) 1298e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison#define dbg_showchan(chan) dmadbg_showchan(__func__, __LINE__, (chan)) 130a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#else 131a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#define dbg_showregs(chan) do { } while(0) 132a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#define dbg_showchan(chan) do { } while(0) 133a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#endif /* CONFIG_S3C2410_DMA_DEBUG */ 134a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 135a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* s3c2410_dma_stats_timeout 136a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * 137a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * Update DMA stats from timeout info 138a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks*/ 139a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 140a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksstatic void 141a21765a70ec06be175d3997320a83fa66fcc8955Ben Dookss3c2410_dma_stats_timeout(struct s3c2410_dma_stats *stats, int val) 142a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{ 143a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (stats == NULL) 144a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return; 145a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 146a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (val > stats->timeout_longest) 147a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks stats->timeout_longest = val; 148a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (val < stats->timeout_shortest) 149a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks stats->timeout_shortest = val; 150a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 151a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks stats->timeout_avg += val; 152a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks} 153a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 154a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* s3c2410_dma_waitforload 155a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * 156a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * wait for the DMA engine to load a buffer, and update the state accordingly 157a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks*/ 158a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 159a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksstatic int 160a21765a70ec06be175d3997320a83fa66fcc8955Ben Dookss3c2410_dma_waitforload(struct s3c2410_dma_chan *chan, int line) 161a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{ 162a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks int timeout = chan->load_timeout; 163a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks int took; 164a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 165a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (chan->load_state != S3C2410_DMALOAD_1LOADED) { 166a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks printk(KERN_ERR "dma%d: s3c2410_dma_waitforload() called in loadstate %d from line %d\n", chan->number, chan->load_state, line); 167a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return 0; 168a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 169a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 170a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (chan->stats != NULL) 171a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->stats->loads++; 172a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 173a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks while (--timeout > 0) { 174a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if ((dma_rdreg(chan, S3C2410_DMA_DSTAT) << (32-20)) != 0) { 175a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks took = chan->load_timeout - timeout; 176a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 177a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks s3c2410_dma_stats_timeout(chan->stats, took); 178a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 179a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks switch (chan->load_state) { 180a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks case S3C2410_DMALOAD_1LOADED: 181a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->load_state = S3C2410_DMALOAD_1RUNNING; 182a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks break; 183a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 184a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks default: 185a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks printk(KERN_ERR "dma%d: unknown load_state in s3c2410_dma_waitforload() %d\n", chan->number, chan->load_state); 186a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 187a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 188a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return 1; 189a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 190a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 191a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 192a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (chan->stats != NULL) { 193a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->stats->timeout_failed++; 194a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 195a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 196a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return 0; 197a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks} 198a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 199a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* s3c2410_dma_loadbuffer 200a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * 201a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * load a buffer, and update the channel state 202a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks*/ 203a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 204a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksstatic inline int 205a21765a70ec06be175d3997320a83fa66fcc8955Ben Dookss3c2410_dma_loadbuffer(struct s3c2410_dma_chan *chan, 206a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks struct s3c2410_dma_buf *buf) 207a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{ 208a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks unsigned long reload; 209a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 210a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (buf == NULL) { 211a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks dmawarn("buffer is NULL\n"); 212a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return -EINVAL; 213a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 214a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 21560e5c1b5ecd99e06d3133a2a20d58d3c2b9968acJulia Lawall pr_debug("s3c2410_chan_loadbuffer: loading buff %p (0x%08lx,0x%06x)\n", 21660e5c1b5ecd99e06d3133a2a20d58d3c2b9968acJulia Lawall buf, (unsigned long)buf->data, buf->size); 21760e5c1b5ecd99e06d3133a2a20d58d3c2b9968acJulia Lawall 218a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks /* check the state of the channel before we do anything */ 219a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 220a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (chan->load_state == S3C2410_DMALOAD_1LOADED) { 221a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks dmawarn("load_state is S3C2410_DMALOAD_1LOADED\n"); 222a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 223a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 224a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (chan->load_state == S3C2410_DMALOAD_1LOADED_1RUNNING) { 225a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks dmawarn("state is S3C2410_DMALOAD_1LOADED_1RUNNING\n"); 226a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 227a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 228a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks /* it would seem sensible if we are the last buffer to not bother 229a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * with the auto-reload bit, so that the DMA engine will not try 230a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * and load another transfer after this one has finished... 231a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks */ 232a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (chan->load_state == S3C2410_DMALOAD_NONE) { 233a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks pr_debug("load_state is none, checking for noreload (next=%p)\n", 234a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks buf->next); 235a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks reload = (buf->next == NULL) ? S3C2410_DCON_NORELOAD : 0; 236a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } else { 237a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks //pr_debug("load_state is %d => autoreload\n", chan->load_state); 238a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks reload = S3C2410_DCON_AUTORELOAD; 239a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 240a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 241a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if ((buf->data & 0xf0000000) != 0x30000000) { 242a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks dmawarn("dmaload: buffer is %p\n", (void *)buf->data); 243a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 244a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 245a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks writel(buf->data, chan->addr_reg); 246a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 247a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks dma_wrreg(chan, S3C2410_DMA_DCON, 248a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->dcon | reload | (buf->size/chan->xfer_unit)); 249a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 250a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->next = buf->next; 251a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 252a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks /* update the state of the channel */ 253a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 254a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks switch (chan->load_state) { 255a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks case S3C2410_DMALOAD_NONE: 256a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->load_state = S3C2410_DMALOAD_1LOADED; 257a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks break; 258a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 259a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks case S3C2410_DMALOAD_1RUNNING: 260a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->load_state = S3C2410_DMALOAD_1LOADED_1RUNNING; 261a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks break; 262a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 263a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks default: 264a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks dmawarn("dmaload: unknown state %d in loadbuffer\n", 265a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->load_state); 266a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks break; 267a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 268a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 269a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return 0; 270a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks} 271a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 272a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* s3c2410_dma_call_op 273a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * 274a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * small routine to call the op routine with the given op if it has been 275a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * registered 276a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks*/ 277a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 278a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksstatic void 279a21765a70ec06be175d3997320a83fa66fcc8955Ben Dookss3c2410_dma_call_op(struct s3c2410_dma_chan *chan, enum s3c2410_chan_op op) 280a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{ 281a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (chan->op_fn != NULL) { 282a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks (chan->op_fn)(chan, op); 283a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 284a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks} 285a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 286a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* s3c2410_dma_buffdone 287a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * 288a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * small wrapper to check if callback routine needs to be called, and 289a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * if so, call it 290a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks*/ 291a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 292a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksstatic inline void 293a21765a70ec06be175d3997320a83fa66fcc8955Ben Dookss3c2410_dma_buffdone(struct s3c2410_dma_chan *chan, struct s3c2410_dma_buf *buf, 294a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks enum s3c2410_dma_buffresult result) 295a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{ 296a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#if 0 297a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks pr_debug("callback_fn=%p, buf=%p, id=%p, size=%d, result=%d\n", 298a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->callback_fn, buf, buf->id, buf->size, result); 299a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#endif 300a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 301a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (chan->callback_fn != NULL) { 302a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks (chan->callback_fn)(chan, buf->id, buf->size, result); 303a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 304a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks} 305a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 306a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* s3c2410_dma_start 307a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * 308a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * start a dma channel going 309a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks*/ 310a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 311a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksstatic int s3c2410_dma_start(struct s3c2410_dma_chan *chan) 312a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{ 313a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks unsigned long tmp; 314a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks unsigned long flags; 315a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 316a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks pr_debug("s3c2410_start_dma: channel=%d\n", chan->number); 317a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 318a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks local_irq_save(flags); 319a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 320a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (chan->state == S3C2410_DMA_RUNNING) { 321a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks pr_debug("s3c2410_start_dma: already running (%d)\n", chan->state); 322a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks local_irq_restore(flags); 323a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return 0; 324a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 325a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 326a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->state = S3C2410_DMA_RUNNING; 327a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 328a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks /* check wether there is anything to load, and if not, see 329a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * if we can find anything to load 330a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks */ 331a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 332a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (chan->load_state == S3C2410_DMALOAD_NONE) { 333a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (chan->next == NULL) { 334a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks printk(KERN_ERR "dma%d: channel has nothing loaded\n", 335a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->number); 336a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->state = S3C2410_DMA_IDLE; 337a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks local_irq_restore(flags); 338a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return -EINVAL; 339a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 340a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 341a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks s3c2410_dma_loadbuffer(chan, chan->next); 342a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 343a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 344a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks dbg_showchan(chan); 345a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 346a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks /* enable the channel */ 347a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 348a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (!chan->irq_enabled) { 349a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks enable_irq(chan->irq); 350a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->irq_enabled = 1; 351a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 352a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 353a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks /* start the channel going */ 354a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 355a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG); 356a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks tmp &= ~S3C2410_DMASKTRIG_STOP; 357a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks tmp |= S3C2410_DMASKTRIG_ON; 358a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp); 359a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 360a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks pr_debug("dma%d: %08lx to DMASKTRIG\n", chan->number, tmp); 361a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 362a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#if 0 363a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks /* the dma buffer loads should take care of clearing the AUTO 364a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * reloading feature */ 365a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks tmp = dma_rdreg(chan, S3C2410_DMA_DCON); 366a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks tmp &= ~S3C2410_DCON_NORELOAD; 367a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks dma_wrreg(chan, S3C2410_DMA_DCON, tmp); 368a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#endif 369a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 370a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks s3c2410_dma_call_op(chan, S3C2410_DMAOP_START); 371a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 372a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks dbg_showchan(chan); 373a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 374a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks /* if we've only loaded one buffer onto the channel, then chec 375a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * to see if we have another, and if so, try and load it so when 376a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * the first buffer is finished, the new one will be loaded onto 377a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * the channel */ 378a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 379a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (chan->next != NULL) { 380a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (chan->load_state == S3C2410_DMALOAD_1LOADED) { 381a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 382a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (s3c2410_dma_waitforload(chan, __LINE__) == 0) { 383a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks pr_debug("%s: buff not yet loaded, no more todo\n", 3848e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison __func__); 385a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } else { 386a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->load_state = S3C2410_DMALOAD_1RUNNING; 387a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks s3c2410_dma_loadbuffer(chan, chan->next); 388a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 389a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 390a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } else if (chan->load_state == S3C2410_DMALOAD_1RUNNING) { 391a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks s3c2410_dma_loadbuffer(chan, chan->next); 392a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 393a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 394a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 395a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 396a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks local_irq_restore(flags); 397a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 398a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return 0; 399a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks} 400a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 401a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* s3c2410_dma_canload 402a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * 403a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * work out if we can queue another buffer into the DMA engine 404a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks*/ 405a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 406a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksstatic int 407a21765a70ec06be175d3997320a83fa66fcc8955Ben Dookss3c2410_dma_canload(struct s3c2410_dma_chan *chan) 408a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{ 409a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (chan->load_state == S3C2410_DMALOAD_NONE || 410a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->load_state == S3C2410_DMALOAD_1RUNNING) 411a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return 1; 412a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 413a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return 0; 414a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks} 415a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 416a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* s3c2410_dma_enqueue 417a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * 418a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * queue an given buffer for dma transfer. 419a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * 420a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * id the device driver's id information for this buffer 421a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * data the physical address of the buffer data 422a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * size the size of the buffer in bytes 423a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * 424a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * If the channel is not running, then the flag S3C2410_DMAF_AUTOSTART 425a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * is checked, and if set, the channel is started. If this flag isn't set, 426a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * then an error will be returned. 427a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * 428a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * It is possible to queue more than one DMA buffer onto a channel at 429a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * once, and the code will deal with the re-loading of the next buffer 430a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * when necessary. 431a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks*/ 432a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 433a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksint s3c2410_dma_enqueue(unsigned int channel, void *id, 434a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks dma_addr_t data, int size) 435a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{ 43697c1b145231730e62dd71921ec653315a1da3aadBen Dooks struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); 437a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks struct s3c2410_dma_buf *buf; 438a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks unsigned long flags; 439a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 440a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (chan == NULL) 441a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return -EINVAL; 442a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 443a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks pr_debug("%s: id=%p, data=%08x, size=%d\n", 4448e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison __func__, id, (unsigned int)data, size); 445a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 446a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks buf = kmem_cache_alloc(dma_kmem, GFP_ATOMIC); 447a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (buf == NULL) { 448a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks pr_debug("%s: out of memory (%ld alloc)\n", 4498e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison __func__, (long)sizeof(*buf)); 450a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return -ENOMEM; 451a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 452a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 4538e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison //pr_debug("%s: new buffer %p\n", __func__, buf); 454a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks //dbg_showchan(chan); 455a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 456a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks buf->next = NULL; 457a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks buf->data = buf->ptr = data; 458a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks buf->size = size; 459a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks buf->id = id; 460a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks buf->magic = BUF_MAGIC; 461a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 462a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks local_irq_save(flags); 463a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 464a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (chan->curr == NULL) { 465a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks /* we've got nothing loaded... */ 466a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks pr_debug("%s: buffer %p queued onto empty channel\n", 4678e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison __func__, buf); 468a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 469a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->curr = buf; 470a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->end = buf; 471a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->next = NULL; 472a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } else { 473a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks pr_debug("dma%d: %s: buffer %p queued onto non-empty channel\n", 4748e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison chan->number, __func__, buf); 475a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 476a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (chan->end == NULL) 477a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks pr_debug("dma%d: %s: %p not empty, and chan->end==NULL?\n", 4788e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison chan->number, __func__, chan); 479a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 480a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->end->next = buf; 481a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->end = buf; 482a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 483a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 484a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks /* if necessary, update the next buffer field */ 485a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (chan->next == NULL) 486a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->next = buf; 487a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 488a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks /* check to see if we can load a buffer */ 489a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (chan->state == S3C2410_DMA_RUNNING) { 490a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (chan->load_state == S3C2410_DMALOAD_1LOADED && 1) { 491a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (s3c2410_dma_waitforload(chan, __LINE__) == 0) { 492a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks printk(KERN_ERR "dma%d: loadbuffer:" 493a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks "timeout loading buffer\n", 494a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->number); 495a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks dbg_showchan(chan); 496a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks local_irq_restore(flags); 497a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return -EINVAL; 498a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 499a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 500a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 501a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks while (s3c2410_dma_canload(chan) && chan->next != NULL) { 502a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks s3c2410_dma_loadbuffer(chan, chan->next); 503a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 504a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } else if (chan->state == S3C2410_DMA_IDLE) { 505a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (chan->flags & S3C2410_DMAF_AUTOSTART) { 506046c9d321fd5f5ce1c89c9d0f1a519c26a096486Ben Dooks s3c2410_dma_ctrl(chan->number | DMACH_LOW_LEVEL, 507046c9d321fd5f5ce1c89c9d0f1a519c26a096486Ben Dooks S3C2410_DMAOP_START); 508a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 509a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 510a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 511a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks local_irq_restore(flags); 512a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return 0; 513a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks} 514a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 515a21765a70ec06be175d3997320a83fa66fcc8955Ben DooksEXPORT_SYMBOL(s3c2410_dma_enqueue); 516a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 517a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksstatic inline void 518a21765a70ec06be175d3997320a83fa66fcc8955Ben Dookss3c2410_dma_freebuf(struct s3c2410_dma_buf *buf) 519a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{ 520a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks int magicok = (buf->magic == BUF_MAGIC); 521a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 522a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks buf->magic = -1; 523a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 524a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (magicok) { 525a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks kmem_cache_free(dma_kmem, buf); 526a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } else { 527a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks printk("s3c2410_dma_freebuf: buff %p with bad magic\n", buf); 528a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 529a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks} 530a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 531a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* s3c2410_dma_lastxfer 532a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * 533a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * called when the system is out of buffers, to ensure that the channel 534a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * is prepared for shutdown. 535a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks*/ 536a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 537a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksstatic inline void 538a21765a70ec06be175d3997320a83fa66fcc8955Ben Dookss3c2410_dma_lastxfer(struct s3c2410_dma_chan *chan) 539a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{ 540a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#if 0 541a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks pr_debug("dma%d: s3c2410_dma_lastxfer: load_state %d\n", 542a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->number, chan->load_state); 543a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#endif 544a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 545a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks switch (chan->load_state) { 546a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks case S3C2410_DMALOAD_NONE: 547a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks break; 548a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 549a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks case S3C2410_DMALOAD_1LOADED: 550a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (s3c2410_dma_waitforload(chan, __LINE__) == 0) { 551a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks /* flag error? */ 552a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks printk(KERN_ERR "dma%d: timeout waiting for load (%s)\n", 5538e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison chan->number, __func__); 554a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return; 555a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 556a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks break; 557a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 558a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks case S3C2410_DMALOAD_1LOADED_1RUNNING: 55925985edcedea6396277003854657b5f3cb31a628Lucas De Marchi /* I believe in this case we do not have anything to do 560a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * until the next buffer comes along, and we turn off the 561a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * reload */ 562a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return; 563a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 564a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks default: 565a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks pr_debug("dma%d: lastxfer: unhandled load_state %d with no next\n", 566a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->number, chan->load_state); 567a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return; 568a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 569a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 570a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 571a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks /* hopefully this'll shut the damned thing up after the transfer... */ 572a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks dma_wrreg(chan, S3C2410_DMA_DCON, chan->dcon | S3C2410_DCON_NORELOAD); 573a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks} 574a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 575a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 576a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#define dmadbg2(x...) 577a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 578a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksstatic irqreturn_t 579a21765a70ec06be175d3997320a83fa66fcc8955Ben Dookss3c2410_dma_irq(int irq, void *devpw) 580a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{ 581a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks struct s3c2410_dma_chan *chan = (struct s3c2410_dma_chan *)devpw; 582a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks struct s3c2410_dma_buf *buf; 583a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 584a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks buf = chan->curr; 585a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 586a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks dbg_showchan(chan); 587a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 588a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks /* modify the channel state */ 589a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 590a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks switch (chan->load_state) { 591a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks case S3C2410_DMALOAD_1RUNNING: 592a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks /* TODO - if we are running only one buffer, we probably 593a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * want to reload here, and then worry about the buffer 594a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * callback */ 595a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 596a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->load_state = S3C2410_DMALOAD_NONE; 597a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks break; 598a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 599a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks case S3C2410_DMALOAD_1LOADED: 600a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks /* iirc, we should go back to NONE loaded here, we 601a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * had a buffer, and it was never verified as being 602a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * loaded. 603a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks */ 604a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 605a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->load_state = S3C2410_DMALOAD_NONE; 606a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks break; 607a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 608a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks case S3C2410_DMALOAD_1LOADED_1RUNNING: 609a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks /* we'll worry about checking to see if another buffer is 610a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * ready after we've called back the owner. This should 611a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * ensure we do not wait around too long for the DMA 612a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * engine to start the next transfer 613a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks */ 614a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 615a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->load_state = S3C2410_DMALOAD_1LOADED; 616a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks break; 617a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 618a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks case S3C2410_DMALOAD_NONE: 619a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks printk(KERN_ERR "dma%d: IRQ with no loaded buffer?\n", 620a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->number); 621a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks break; 622a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 623a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks default: 624a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks printk(KERN_ERR "dma%d: IRQ in invalid load_state %d\n", 625a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->number, chan->load_state); 626a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks break; 627a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 628a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 629a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (buf != NULL) { 630a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks /* update the chain to make sure that if we load any more 631a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * buffers when we call the callback function, things should 632a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * work properly */ 633a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 634a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->curr = buf->next; 635a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks buf->next = NULL; 636a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 637a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (buf->magic != BUF_MAGIC) { 638a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks printk(KERN_ERR "dma%d: %s: buf %p incorrect magic\n", 6398e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison chan->number, __func__, buf); 640a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return IRQ_HANDLED; 641a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 642a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 643a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks s3c2410_dma_buffdone(chan, buf, S3C2410_RES_OK); 644a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 645a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks /* free resouces */ 646a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks s3c2410_dma_freebuf(buf); 647a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } else { 648a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 649a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 650a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks /* only reload if the channel is still running... our buffer done 651a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * routine may have altered the state by requesting the dma channel 652a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * to stop or shutdown... */ 653a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 654a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks /* todo: check that when the channel is shut-down from inside this 655a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * function, we cope with unsetting reload, etc */ 656a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 657a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (chan->next != NULL && chan->state != S3C2410_DMA_IDLE) { 658a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks unsigned long flags; 659a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 660a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks switch (chan->load_state) { 661a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks case S3C2410_DMALOAD_1RUNNING: 662a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks /* don't need to do anything for this state */ 663a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks break; 664a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 665a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks case S3C2410_DMALOAD_NONE: 666a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks /* can load buffer immediately */ 667a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks break; 668a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 669a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks case S3C2410_DMALOAD_1LOADED: 670a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (s3c2410_dma_waitforload(chan, __LINE__) == 0) { 671a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks /* flag error? */ 672a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks printk(KERN_ERR "dma%d: timeout waiting for load (%s)\n", 6738e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison chan->number, __func__); 674a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return IRQ_HANDLED; 675a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 676a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 677a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks break; 678a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 679a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks case S3C2410_DMALOAD_1LOADED_1RUNNING: 680a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks goto no_load; 681a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 682a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks default: 683a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks printk(KERN_ERR "dma%d: unknown load_state in irq, %d\n", 684a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->number, chan->load_state); 685a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return IRQ_HANDLED; 686a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 687a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 688a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks local_irq_save(flags); 689a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks s3c2410_dma_loadbuffer(chan, chan->next); 690a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks local_irq_restore(flags); 691a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } else { 692a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks s3c2410_dma_lastxfer(chan); 693a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 694a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks /* see if we can stop this channel.. */ 695a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (chan->load_state == S3C2410_DMALOAD_NONE) { 696a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks pr_debug("dma%d: end of transfer, stopping channel (%ld)\n", 697a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->number, jiffies); 698a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks s3c2410_dma_ctrl(chan->number | DMACH_LOW_LEVEL, 699a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks S3C2410_DMAOP_STOP); 700a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 701a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 702a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 703a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks no_load: 704a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return IRQ_HANDLED; 705a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks} 706a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 707a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksstatic struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel); 708a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 709a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* s3c2410_request_dma 710a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * 711a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * get control of an dma channel 712a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks*/ 713a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 714d670ac019f60e4932ba329bb0800bf2929e6d77cSangwook Leeint s3c2410_dma_request(enum dma_ch channel, 715a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks struct s3c2410_dma_client *client, 716a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks void *dev) 717a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{ 718a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks struct s3c2410_dma_chan *chan; 719a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks unsigned long flags; 720a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks int err; 721a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 722a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks pr_debug("dma%d: s3c2410_request_dma: client=%s, dev=%p\n", 723a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks channel, client->name, dev); 724a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 725a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks local_irq_save(flags); 726a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 727a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan = s3c2410_dma_map_channel(channel); 728a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (chan == NULL) { 729a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks local_irq_restore(flags); 730a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return -EBUSY; 731a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 732a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 733a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks dbg_showchan(chan); 734a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 735a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->client = client; 736a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->in_use = 1; 737a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 738a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (!chan->irq_claimed) { 739a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks pr_debug("dma%d: %s : requesting irq %d\n", 7408e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison channel, __func__, chan->irq); 741a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 742a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->irq_claimed = 1; 743a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks local_irq_restore(flags); 744a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 745a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks err = request_irq(chan->irq, s3c2410_dma_irq, IRQF_DISABLED, 746a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks client->name, (void *)chan); 747a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 748a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks local_irq_save(flags); 749a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 750a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (err) { 751a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->in_use = 0; 752a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->irq_claimed = 0; 753a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks local_irq_restore(flags); 754a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 755a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks printk(KERN_ERR "%s: cannot get IRQ %d for DMA %d\n", 756a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks client->name, chan->irq, chan->number); 757a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return err; 758a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 759a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 760a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->irq_enabled = 1; 761a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 762a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 763a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks local_irq_restore(flags); 764a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 765a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks /* need to setup */ 766a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 7678e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison pr_debug("%s: channel initialised, %p\n", __func__, chan); 768a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 769a07c438faf952643f79983fb16a10f111c9df0dfBen Dooks return chan->number | DMACH_LOW_LEVEL; 770a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks} 771a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 772a21765a70ec06be175d3997320a83fa66fcc8955Ben DooksEXPORT_SYMBOL(s3c2410_dma_request); 773a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 774a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* s3c2410_dma_free 775a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * 776a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * release the given channel back to the system, will stop and flush 777a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * any outstanding transfers, and ensure the channel is ready for the 778a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * next claimant. 779a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * 780a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * Note, although a warning is currently printed if the freeing client 781a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * info is not the same as the registrant's client info, the free is still 782a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * allowed to go through. 783a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks*/ 784a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 785d670ac019f60e4932ba329bb0800bf2929e6d77cSangwook Leeint s3c2410_dma_free(enum dma_ch channel, struct s3c2410_dma_client *client) 786a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{ 78797c1b145231730e62dd71921ec653315a1da3aadBen Dooks struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); 788a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks unsigned long flags; 789a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 790a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (chan == NULL) 791a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return -EINVAL; 792a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 793a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks local_irq_save(flags); 794a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 795a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (chan->client != client) { 796a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks printk(KERN_WARNING "dma%d: possible free from different client (channel %p, passed %p)\n", 797a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks channel, chan->client, client); 798a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 799a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 800a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks /* sort out stopping and freeing the channel */ 801a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 802a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (chan->state != S3C2410_DMA_IDLE) { 803a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks pr_debug("%s: need to stop dma channel %p\n", 8048e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison __func__, chan); 805a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 806a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks /* possibly flush the channel */ 807a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STOP); 808a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 809a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 810a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->client = NULL; 811a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->in_use = 0; 812a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 813a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (chan->irq_claimed) 814a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks free_irq(chan->irq, (void *)chan); 815a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 816a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->irq_claimed = 0; 817a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 818a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (!(channel & DMACH_LOW_LEVEL)) 81997c1b145231730e62dd71921ec653315a1da3aadBen Dooks s3c_dma_chan_map[channel] = NULL; 820a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 821a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks local_irq_restore(flags); 822a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 823a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return 0; 824a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks} 825a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 826a21765a70ec06be175d3997320a83fa66fcc8955Ben DooksEXPORT_SYMBOL(s3c2410_dma_free); 827a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 828a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksstatic int s3c2410_dma_dostop(struct s3c2410_dma_chan *chan) 829a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{ 830a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks unsigned long flags; 831a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks unsigned long tmp; 832a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 8338e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison pr_debug("%s:\n", __func__); 834a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 835a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks dbg_showchan(chan); 836a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 837a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks local_irq_save(flags); 838a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 839a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks s3c2410_dma_call_op(chan, S3C2410_DMAOP_STOP); 840a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 841a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG); 842a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks tmp |= S3C2410_DMASKTRIG_STOP; 843a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks //tmp &= ~S3C2410_DMASKTRIG_ON; 844a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp); 845a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 846a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#if 0 847a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks /* should also clear interrupts, according to WinCE BSP */ 848a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks tmp = dma_rdreg(chan, S3C2410_DMA_DCON); 849a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks tmp |= S3C2410_DCON_NORELOAD; 850a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks dma_wrreg(chan, S3C2410_DMA_DCON, tmp); 851a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#endif 852a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 853a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks /* should stop do this, or should we wait for flush? */ 854a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->state = S3C2410_DMA_IDLE; 855a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->load_state = S3C2410_DMALOAD_NONE; 856a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 857a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks local_irq_restore(flags); 858a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 859a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return 0; 860a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks} 861a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 862a7717435656c874843b1742383cc37540f5ff91eBen Dooksstatic void s3c2410_dma_waitforstop(struct s3c2410_dma_chan *chan) 863a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{ 864a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks unsigned long tmp; 865a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks unsigned int timeout = 0x10000; 866a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 867a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks while (timeout-- > 0) { 868a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG); 869a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 870a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (!(tmp & S3C2410_DMASKTRIG_ON)) 871a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return; 872a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 873a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 874a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks pr_debug("dma%d: failed to stop?\n", chan->number); 875a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks} 876a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 877a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 878a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* s3c2410_dma_flush 879a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * 880a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * stop the channel, and remove all current and pending transfers 881a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks*/ 882a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 883a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksstatic int s3c2410_dma_flush(struct s3c2410_dma_chan *chan) 884a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{ 885a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks struct s3c2410_dma_buf *buf, *next; 886a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks unsigned long flags; 887a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 8888e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison pr_debug("%s: chan %p (%d)\n", __func__, chan, chan->number); 889a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 890a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks dbg_showchan(chan); 891a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 892a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks local_irq_save(flags); 893a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 894a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (chan->state != S3C2410_DMA_IDLE) { 8958e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison pr_debug("%s: stopping channel...\n", __func__ ); 896a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_STOP); 897a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 898a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 899a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks buf = chan->curr; 900a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (buf == NULL) 901a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks buf = chan->next; 902a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 903a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->curr = chan->next = chan->end = NULL; 904a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 905a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (buf != NULL) { 906a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks for ( ; buf != NULL; buf = next) { 907a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks next = buf->next; 908a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 909a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks pr_debug("%s: free buffer %p, next %p\n", 9108e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison __func__, buf, buf->next); 911a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 912a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks s3c2410_dma_buffdone(chan, buf, S3C2410_RES_ABORT); 913a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks s3c2410_dma_freebuf(buf); 914a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 915a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 916a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 917a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks dbg_showregs(chan); 918a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 919a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks s3c2410_dma_waitforstop(chan); 920a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 921a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#if 0 922a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks /* should also clear interrupts, according to WinCE BSP */ 923a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks { 924a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks unsigned long tmp; 925a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 926a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks tmp = dma_rdreg(chan, S3C2410_DMA_DCON); 927a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks tmp |= S3C2410_DCON_NORELOAD; 928a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks dma_wrreg(chan, S3C2410_DMA_DCON, tmp); 929a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 930a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#endif 931a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 932a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks dbg_showregs(chan); 933a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 934a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks local_irq_restore(flags); 935a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 936a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return 0; 937a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks} 938a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 939a7717435656c874843b1742383cc37540f5ff91eBen Dooksstatic int s3c2410_dma_started(struct s3c2410_dma_chan *chan) 940a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{ 941a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks unsigned long flags; 942a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 943a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks local_irq_save(flags); 944a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 945a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks dbg_showchan(chan); 946a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 947a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks /* if we've only loaded one buffer onto the channel, then chec 948a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * to see if we have another, and if so, try and load it so when 949a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * the first buffer is finished, the new one will be loaded onto 950a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * the channel */ 951a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 952a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (chan->next != NULL) { 953a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (chan->load_state == S3C2410_DMALOAD_1LOADED) { 954a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 955a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (s3c2410_dma_waitforload(chan, __LINE__) == 0) { 956a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks pr_debug("%s: buff not yet loaded, no more todo\n", 9578e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison __func__); 958a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } else { 959a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->load_state = S3C2410_DMALOAD_1RUNNING; 960a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks s3c2410_dma_loadbuffer(chan, chan->next); 961a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 962a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 963a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } else if (chan->load_state == S3C2410_DMALOAD_1RUNNING) { 964a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks s3c2410_dma_loadbuffer(chan, chan->next); 965a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 966a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 967a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 968a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 969a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks local_irq_restore(flags); 970a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 971a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return 0; 972a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 973a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks} 974a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 975a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksint 976d670ac019f60e4932ba329bb0800bf2929e6d77cSangwook Lees3c2410_dma_ctrl(enum dma_ch channel, enum s3c2410_chan_op op) 977a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{ 97897c1b145231730e62dd71921ec653315a1da3aadBen Dooks struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); 979a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 980a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (chan == NULL) 981a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return -EINVAL; 982a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 983a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks switch (op) { 984a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks case S3C2410_DMAOP_START: 985a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return s3c2410_dma_start(chan); 986a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 987a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks case S3C2410_DMAOP_STOP: 988a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return s3c2410_dma_dostop(chan); 989a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 990a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks case S3C2410_DMAOP_PAUSE: 991a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks case S3C2410_DMAOP_RESUME: 992a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return -ENOENT; 993a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 994a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks case S3C2410_DMAOP_FLUSH: 995a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return s3c2410_dma_flush(chan); 996a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 997a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks case S3C2410_DMAOP_STARTED: 998a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return s3c2410_dma_started(chan); 999a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1000a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks case S3C2410_DMAOP_TIMEOUT: 1001a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return 0; 1002a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1003a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 1004a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1005a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return -ENOENT; /* unknown, don't bother */ 1006a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks} 1007a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1008a21765a70ec06be175d3997320a83fa66fcc8955Ben DooksEXPORT_SYMBOL(s3c2410_dma_ctrl); 1009a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1010a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* DMA configuration for each channel 1011a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * 1012a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * DISRCC -> source of the DMA (AHB,APB) 1013a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * DISRC -> source address of the DMA 1014a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * DIDSTC -> destination of the DMA (AHB,APD) 1015a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * DIDST -> destination address of the DMA 1016a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks*/ 1017a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1018a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* s3c2410_dma_config 1019a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * 1020a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * xfersize: size of unit in bytes (1,2,4) 1021a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks*/ 1022a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1023d670ac019f60e4932ba329bb0800bf2929e6d77cSangwook Leeint s3c2410_dma_config(enum dma_ch channel, 10248970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks int xferunit) 1025a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{ 102697c1b145231730e62dd71921ec653315a1da3aadBen Dooks struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); 10278970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks unsigned int dcon; 1028a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 10295838e9b8dada491278db48ff9162e25125fa89d6Wolfram Sang pr_debug("%s: chan=%d, xfer_unit=%d\n", __func__, channel, xferunit); 1030a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1031a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (chan == NULL) 1032a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return -EINVAL; 1033a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 10348970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks dcon = chan->dcon & dma_sel.dcon_mask; 10355838e9b8dada491278db48ff9162e25125fa89d6Wolfram Sang pr_debug("%s: dcon is %08x\n", __func__, dcon); 1036a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 10378970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks switch (chan->req_ch) { 10388970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks case DMACH_I2S_IN: 10398970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks case DMACH_I2S_OUT: 10408970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks case DMACH_PCM_IN: 10418970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks case DMACH_PCM_OUT: 10428970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks case DMACH_MIC_IN: 10438970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks default: 10448970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks dcon |= S3C2410_DCON_HANDSHAKE; 10458970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks dcon |= S3C2410_DCON_SYNC_PCLK; 10468970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks break; 10478970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks 10488970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks case DMACH_SDI: 10498970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks /* note, ensure if need HANDSHAKE or not */ 10508970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks dcon |= S3C2410_DCON_SYNC_PCLK; 10518970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks break; 10528970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks 10538970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks case DMACH_XD0: 10548970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks case DMACH_XD1: 10558970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks dcon |= S3C2410_DCON_HANDSHAKE; 10568970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks dcon |= S3C2410_DCON_SYNC_HCLK; 10578970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks break; 10588970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks } 10598970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks 1060a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks switch (xferunit) { 1061a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks case 1: 1062a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks dcon |= S3C2410_DCON_BYTE; 1063a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks break; 1064a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1065a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks case 2: 1066a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks dcon |= S3C2410_DCON_HALFWORD; 1067a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks break; 1068a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1069a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks case 4: 1070a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks dcon |= S3C2410_DCON_WORD; 1071a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks break; 1072a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1073a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks default: 10748e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison pr_debug("%s: bad transfer size %d\n", __func__, xferunit); 1075a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return -EINVAL; 1076a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 1077a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1078a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks dcon |= S3C2410_DCON_HWTRIG; 1079a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks dcon |= S3C2410_DCON_INTREQ; 1080a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 10818e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison pr_debug("%s: dcon now %08x\n", __func__, dcon); 1082a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1083a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->dcon = dcon; 1084a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->xfer_unit = xferunit; 1085a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1086a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return 0; 1087a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks} 1088a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1089a21765a70ec06be175d3997320a83fa66fcc8955Ben DooksEXPORT_SYMBOL(s3c2410_dma_config); 1090a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1091a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1092a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* s3c2410_dma_devconfig 1093a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * 1094a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * configure the dma source/destination hardware type and address 1095a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * 109651ddf31da16b1ab9da861eafedad6d263faf4388Boojin Kim * source: DMA_FROM_DEVICE: source is hardware 109751ddf31da16b1ab9da861eafedad6d263faf4388Boojin Kim * DMA_TO_DEVICE: source is memory 1098a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * 1099a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * devaddr: physical address of the source 1100a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks*/ 1101a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1102d670ac019f60e4932ba329bb0800bf2929e6d77cSangwook Leeint s3c2410_dma_devconfig(enum dma_ch channel, 110351ddf31da16b1ab9da861eafedad6d263faf4388Boojin Kim enum dma_data_direction source, 1104a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks unsigned long devaddr) 1105a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{ 110697c1b145231730e62dd71921ec653315a1da3aadBen Dooks struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); 11078970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks unsigned int hwcfg; 1108a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1109a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (chan == NULL) 1110a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return -EINVAL; 1111a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 11128970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks pr_debug("%s: source=%d, devaddr=%08lx\n", 11138970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks __func__, (int)source, devaddr); 1114a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1115a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->source = source; 1116a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->dev_addr = devaddr; 11178970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks 11188970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks switch (chan->req_ch) { 11198970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks case DMACH_XD0: 11208970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks case DMACH_XD1: 11218970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks hwcfg = 0; /* AHB */ 11228970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks break; 11238970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks 11248970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks default: 11258970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks hwcfg = S3C2410_DISRCC_APB; 11268970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks } 11278970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks 11288970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks /* always assume our peripheral desintation is a fixed 11298970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks * address in memory. */ 11308970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks hwcfg |= S3C2410_DISRCC_INC; 1131a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1132a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks switch (source) { 113351ddf31da16b1ab9da861eafedad6d263faf4388Boojin Kim case DMA_FROM_DEVICE: 1134a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks /* source is hardware */ 1135a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks pr_debug("%s: hw source, devaddr=%08lx, hwcfg=%d\n", 11368e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison __func__, devaddr, hwcfg); 1137a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks dma_wrreg(chan, S3C2410_DMA_DISRCC, hwcfg & 3); 1138a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks dma_wrreg(chan, S3C2410_DMA_DISRC, devaddr); 1139a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks dma_wrreg(chan, S3C2410_DMA_DIDSTC, (0<<1) | (0<<0)); 1140a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1141a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DIDST); 1142c6709e8ef5752314c22c75bc7575f9be390e215bBen Dooks break; 1143a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 114451ddf31da16b1ab9da861eafedad6d263faf4388Boojin Kim case DMA_TO_DEVICE: 1145a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks /* source is memory */ 11468e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison pr_debug("%s: mem source, devaddr=%08lx, hwcfg=%d\n", 11478e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison __func__, devaddr, hwcfg); 1148a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks dma_wrreg(chan, S3C2410_DMA_DISRCC, (0<<1) | (0<<0)); 1149a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks dma_wrreg(chan, S3C2410_DMA_DIDST, devaddr); 1150a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks dma_wrreg(chan, S3C2410_DMA_DIDSTC, hwcfg & 3); 1151a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1152a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DISRC); 1153c6709e8ef5752314c22c75bc7575f9be390e215bBen Dooks break; 1154c6709e8ef5752314c22c75bc7575f9be390e215bBen Dooks 1155c6709e8ef5752314c22c75bc7575f9be390e215bBen Dooks default: 1156c6709e8ef5752314c22c75bc7575f9be390e215bBen Dooks printk(KERN_ERR "dma%d: invalid source type (%d)\n", 1157c6709e8ef5752314c22c75bc7575f9be390e215bBen Dooks channel, source); 1158c6709e8ef5752314c22c75bc7575f9be390e215bBen Dooks 1159c6709e8ef5752314c22c75bc7575f9be390e215bBen Dooks return -EINVAL; 1160a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 1161a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1162c6709e8ef5752314c22c75bc7575f9be390e215bBen Dooks if (dma_sel.direction != NULL) 1163c6709e8ef5752314c22c75bc7575f9be390e215bBen Dooks (dma_sel.direction)(chan, chan->map, source); 1164c6709e8ef5752314c22c75bc7575f9be390e215bBen Dooks 1165c6709e8ef5752314c22c75bc7575f9be390e215bBen Dooks return 0; 1166a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks} 1167a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1168a21765a70ec06be175d3997320a83fa66fcc8955Ben DooksEXPORT_SYMBOL(s3c2410_dma_devconfig); 1169a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1170a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* s3c2410_dma_getposition 1171a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * 1172a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * returns the current transfer points for the dma source and destination 1173a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks*/ 1174a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1175d670ac019f60e4932ba329bb0800bf2929e6d77cSangwook Leeint s3c2410_dma_getposition(enum dma_ch channel, dma_addr_t *src, dma_addr_t *dst) 1176a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{ 117797c1b145231730e62dd71921ec653315a1da3aadBen Dooks struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); 1178a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1179a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (chan == NULL) 1180a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return -EINVAL; 1181a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1182a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (src != NULL) 1183a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks *src = dma_rdreg(chan, S3C2410_DMA_DCSRC); 1184a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1185a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (dst != NULL) 1186a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks *dst = dma_rdreg(chan, S3C2410_DMA_DCDST); 1187a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1188a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return 0; 1189a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks} 1190a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1191a21765a70ec06be175d3997320a83fa66fcc8955Ben DooksEXPORT_SYMBOL(s3c2410_dma_getposition); 1192a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1193bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysocki/* system core operations */ 1194a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1195a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#ifdef CONFIG_PM 1196a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1197e4698188444a639ac9a3cfb3e06006dd1d4e7fccHeiko Stuebnerstatic void s3c2410_dma_suspend_chan(struct s3c2410_dma_chan *cp) 1198a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{ 1199a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks printk(KERN_DEBUG "suspending dma channel %d\n", cp->number); 1200a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1201a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (dma_rdreg(cp, S3C2410_DMA_DMASKTRIG) & S3C2410_DMASKTRIG_ON) { 1202a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks /* the dma channel is still working, which is probably 1203a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * a bad thing to do over suspend/resume. We stop the 1204a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * channel and assume that the client is either going to 1205a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * retry after resume, or that it is broken. 1206a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks */ 1207a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1208a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks printk(KERN_INFO "dma: stopping channel %d due to suspend\n", 1209a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks cp->number); 1210a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1211a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks s3c2410_dma_dostop(cp); 1212a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 1213bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysocki} 1214bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysocki 1215bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysockistatic int s3c2410_dma_suspend(void) 1216bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysocki{ 1217bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysocki struct s3c2410_dma_chan *cp = s3c2410_chans; 1218bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysocki int channel; 1219bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysocki 1220bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysocki for (channel = 0; channel < dma_channels; cp++, channel++) 1221bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysocki s3c2410_dma_suspend_chan(cp); 1222a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1223a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return 0; 1224a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks} 1225a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1226bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysockistatic void s3c2410_dma_resume_chan(struct s3c2410_dma_chan *cp) 1227a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{ 1228c58f7a1d36709e50398c05df9419386befef2c59Ben Dooks unsigned int no = cp->number | DMACH_LOW_LEVEL; 1229c58f7a1d36709e50398c05df9419386befef2c59Ben Dooks 1230c58f7a1d36709e50398c05df9419386befef2c59Ben Dooks /* restore channel's hardware configuration */ 1231c58f7a1d36709e50398c05df9419386befef2c59Ben Dooks 1232c58f7a1d36709e50398c05df9419386befef2c59Ben Dooks if (!cp->in_use) 1233cb26a7b1c18857d14913040b45f3fe51b513f936Wolfram Sang return; 1234c58f7a1d36709e50398c05df9419386befef2c59Ben Dooks 1235c58f7a1d36709e50398c05df9419386befef2c59Ben Dooks printk(KERN_INFO "dma%d: restoring configuration\n", cp->number); 1236c58f7a1d36709e50398c05df9419386befef2c59Ben Dooks 12378970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks s3c2410_dma_config(no, cp->xfer_unit); 12388970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks s3c2410_dma_devconfig(no, cp->source, cp->dev_addr); 1239c58f7a1d36709e50398c05df9419386befef2c59Ben Dooks 1240c58f7a1d36709e50398c05df9419386befef2c59Ben Dooks /* re-select the dma source for this channel */ 1241c58f7a1d36709e50398c05df9419386befef2c59Ben Dooks 1242c58f7a1d36709e50398c05df9419386befef2c59Ben Dooks if (cp->map != NULL) 1243c58f7a1d36709e50398c05df9419386befef2c59Ben Dooks dma_sel.select(cp, cp->map); 1244a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks} 1245a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1246bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysockistatic void s3c2410_dma_resume(void) 1247bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysocki{ 1248bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysocki struct s3c2410_dma_chan *cp = s3c2410_chans + dma_channels - 1; 1249bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysocki int channel; 1250bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysocki 1251e39d40c65dfd8390b50c03482ae9e289b8a8f351Gusakov Andrey for (channel = dma_channels - 1; channel >= 0; cp--, channel--) 1252bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysocki s3c2410_dma_resume_chan(cp); 1253bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysocki} 1254bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysocki 1255a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#else 1256a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#define s3c2410_dma_suspend NULL 1257a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#define s3c2410_dma_resume NULL 1258a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#endif /* CONFIG_PM */ 1259a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1260bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysockistruct syscore_ops dma_syscore_ops = { 1261a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks .suspend = s3c2410_dma_suspend, 1262a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks .resume = s3c2410_dma_resume, 1263a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks}; 1264a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1265a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* kmem cache implementation */ 1266a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 126751cc50685a4275c6a02653670af9f108a64e01cfAlexey Dobriyanstatic void s3c2410_dma_cache_ctor(void *p) 1268a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{ 1269a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks memset(p, 0, sizeof(struct s3c2410_dma_buf)); 1270a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks} 1271a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1272a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* initialisation code */ 1273a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1274bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysockistatic int __init s3c24xx_dma_syscore_init(void) 127548adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooks{ 1276bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysocki register_syscore_ops(&dma_syscore_ops); 127748adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooks 127848adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooks return 0; 127948adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooks} 128048adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooks 1281bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysockilate_initcall(s3c24xx_dma_syscore_init); 128248adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooks 128348adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooksint __init s3c24xx_dma_init(unsigned int channels, unsigned int irq, 128448adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooks unsigned int stride) 1285a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{ 1286a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks struct s3c2410_dma_chan *cp; 1287a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks int channel; 1288a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks int ret; 1289a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1290e02f866456ec31d20649670e3af048ddc2a3892bBen Dooks printk("S3C24XX DMA Driver, Copyright 2003-2006 Simtec Electronics\n"); 1291a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 129248adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooks dma_channels = channels; 129348adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooks 129448adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooks dma_base = ioremap(S3C24XX_PA_DMA, stride * channels); 1295a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (dma_base == NULL) { 1296a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks printk(KERN_ERR "dma failed to remap register block\n"); 1297a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return -ENOMEM; 1298a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 1299a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 130048adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooks dma_kmem = kmem_cache_create("dma_desc", 130148adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooks sizeof(struct s3c2410_dma_buf), 0, 1302a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks SLAB_HWCACHE_ALIGN, 130320c2df83d25c6a95affe6157a4c9cac4cf5ffaacPaul Mundt s3c2410_dma_cache_ctor); 1304a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1305a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (dma_kmem == NULL) { 1306a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks printk(KERN_ERR "dma failed to make kmem cache\n"); 1307a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks ret = -ENOMEM; 1308a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks goto err; 1309a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 1310a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 131148adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooks for (channel = 0; channel < channels; channel++) { 1312a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks cp = &s3c2410_chans[channel]; 1313a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1314a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks memset(cp, 0, sizeof(struct s3c2410_dma_chan)); 1315a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1316a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks /* dma channel irqs are in order.. */ 1317a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks cp->number = channel; 131848adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooks cp->irq = channel + irq; 131948adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooks cp->regs = dma_base + (channel * stride); 1320a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1321a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks /* point current stats somewhere */ 1322a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks cp->stats = &cp->stats_store; 1323a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks cp->stats_store.timeout_shortest = LONG_MAX; 1324a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1325a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks /* basic channel configuration */ 1326a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1327a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks cp->load_timeout = 1<<18; 1328a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1329a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks printk("DMA channel %d at %p, irq %d\n", 1330a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks cp->number, cp->regs, cp->irq); 1331a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 1332a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1333a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return 0; 1334a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1335a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks err: 1336a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks kmem_cache_destroy(dma_kmem); 1337a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks iounmap(dma_base); 1338a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks dma_base = NULL; 1339a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return ret; 1340a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks} 1341a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1342f2c10d6c669e5b792c48e86da37ec7fde0a2e302Krzysztof Heltint __init s3c2410_dma_init(void) 134348adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooks{ 134448adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooks return s3c24xx_dma_init(4, IRQ_DMA0, 0x40); 134548adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooks} 1346a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1347a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksstatic inline int is_channel_valid(unsigned int channel) 1348a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{ 1349a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return (channel & DMA_CH_VALID); 1350a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks} 1351a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 13520c6022d453ecebdace0ce15434c7108e158149caBen Dooksstatic struct s3c24xx_dma_order *dma_order; 13530c6022d453ecebdace0ce15434c7108e158149caBen Dooks 13540c6022d453ecebdace0ce15434c7108e158149caBen Dooks 1355a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* s3c2410_dma_map_channel() 1356a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * 1357a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * turn the virtual channel number into a real, and un-used hardware 1358a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * channel. 1359a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * 13600c6022d453ecebdace0ce15434c7108e158149caBen Dooks * first, try the dma ordering given to us by either the relevant 13610c6022d453ecebdace0ce15434c7108e158149caBen Dooks * dma code, or the board. Then just find the first usable free 13620c6022d453ecebdace0ce15434c7108e158149caBen Dooks * channel 1363a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks*/ 1364a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1365a7717435656c874843b1742383cc37540f5ff91eBen Dooksstatic struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel) 1366a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{ 13670c6022d453ecebdace0ce15434c7108e158149caBen Dooks struct s3c24xx_dma_order_ch *ord = NULL; 1368a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks struct s3c24xx_dma_map *ch_map; 1369a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks struct s3c2410_dma_chan *dmach; 1370a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks int ch; 1371a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1372a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (dma_sel.map == NULL || channel > dma_sel.map_size) 1373a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return NULL; 1374a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1375a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks ch_map = dma_sel.map + channel; 1376a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 13770c6022d453ecebdace0ce15434c7108e158149caBen Dooks /* first, try the board mapping */ 13780c6022d453ecebdace0ce15434c7108e158149caBen Dooks 13790c6022d453ecebdace0ce15434c7108e158149caBen Dooks if (dma_order) { 13800c6022d453ecebdace0ce15434c7108e158149caBen Dooks ord = &dma_order->channels[channel]; 13810c6022d453ecebdace0ce15434c7108e158149caBen Dooks 138248adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooks for (ch = 0; ch < dma_channels; ch++) { 1383947a2462792a89b8aa168a1108288e0d0ae36d12Ramax Lo int tmp; 13840c6022d453ecebdace0ce15434c7108e158149caBen Dooks if (!is_channel_valid(ord->list[ch])) 13850c6022d453ecebdace0ce15434c7108e158149caBen Dooks continue; 13860c6022d453ecebdace0ce15434c7108e158149caBen Dooks 1387947a2462792a89b8aa168a1108288e0d0ae36d12Ramax Lo tmp = ord->list[ch] & ~DMA_CH_VALID; 1388947a2462792a89b8aa168a1108288e0d0ae36d12Ramax Lo if (s3c2410_chans[tmp].in_use == 0) { 1389947a2462792a89b8aa168a1108288e0d0ae36d12Ramax Lo ch = tmp; 13900c6022d453ecebdace0ce15434c7108e158149caBen Dooks goto found; 13910c6022d453ecebdace0ce15434c7108e158149caBen Dooks } 13920c6022d453ecebdace0ce15434c7108e158149caBen Dooks } 13930c6022d453ecebdace0ce15434c7108e158149caBen Dooks 13940c6022d453ecebdace0ce15434c7108e158149caBen Dooks if (ord->flags & DMA_CH_NEVER) 13950c6022d453ecebdace0ce15434c7108e158149caBen Dooks return NULL; 13960c6022d453ecebdace0ce15434c7108e158149caBen Dooks } 13970c6022d453ecebdace0ce15434c7108e158149caBen Dooks 13980c6022d453ecebdace0ce15434c7108e158149caBen Dooks /* second, search the channel map for first free */ 13990c6022d453ecebdace0ce15434c7108e158149caBen Dooks 140048adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooks for (ch = 0; ch < dma_channels; ch++) { 1401a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (!is_channel_valid(ch_map->channels[ch])) 1402a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks continue; 1403a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1404a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (s3c2410_chans[ch].in_use == 0) { 1405a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks printk("mapped channel %d to %d\n", channel, ch); 1406a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks break; 1407a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 1408a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks } 1409a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 141048adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooks if (ch >= dma_channels) 1411a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return NULL; 1412a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1413a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks /* update our channel mapping */ 1414a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 14150c6022d453ecebdace0ce15434c7108e158149caBen Dooks found: 1416a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks dmach = &s3c2410_chans[ch]; 1417c58f7a1d36709e50398c05df9419386befef2c59Ben Dooks dmach->map = ch_map; 14188970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks dmach->req_ch = channel; 141997c1b145231730e62dd71921ec653315a1da3aadBen Dooks s3c_dma_chan_map[channel] = dmach; 1420a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1421a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks /* select the channel */ 1422a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1423a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks (dma_sel.select)(dmach, ch_map); 1424a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1425a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return dmach; 1426a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks} 1427a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1428a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksstatic int s3c24xx_dma_check_entry(struct s3c24xx_dma_map *map, int ch) 1429a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{ 1430a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return 0; 1431a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks} 1432a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1433a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksint __init s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel) 1434a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{ 1435a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks struct s3c24xx_dma_map *nmap; 1436a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks size_t map_sz = sizeof(*nmap) * sel->map_size; 1437a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks int ptr; 1438a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 14397803c7aa8ef262a63e91ee0b04470715a7dc2eb0Thomas Meyer nmap = kmemdup(sel->map, map_sz, GFP_KERNEL); 1440a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks if (nmap == NULL) 1441a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return -ENOMEM; 1442a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1443a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks memcpy(&dma_sel, sel, sizeof(*sel)); 1444a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1445a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks dma_sel.map = nmap; 1446a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1447a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks for (ptr = 0; ptr < sel->map_size; ptr++) 1448a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks s3c24xx_dma_check_entry(nmap+ptr, ptr); 1449a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 1450a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks return 0; 1451a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks} 14520c6022d453ecebdace0ce15434c7108e158149caBen Dooks 14530c6022d453ecebdace0ce15434c7108e158149caBen Dooksint __init s3c24xx_dma_order_set(struct s3c24xx_dma_order *ord) 14540c6022d453ecebdace0ce15434c7108e158149caBen Dooks{ 14550c6022d453ecebdace0ce15434c7108e158149caBen Dooks struct s3c24xx_dma_order *nord = dma_order; 14560c6022d453ecebdace0ce15434c7108e158149caBen Dooks 14570c6022d453ecebdace0ce15434c7108e158149caBen Dooks if (nord == NULL) 14580c6022d453ecebdace0ce15434c7108e158149caBen Dooks nord = kmalloc(sizeof(struct s3c24xx_dma_order), GFP_KERNEL); 14590c6022d453ecebdace0ce15434c7108e158149caBen Dooks 14600c6022d453ecebdace0ce15434c7108e158149caBen Dooks if (nord == NULL) { 14610c6022d453ecebdace0ce15434c7108e158149caBen Dooks printk(KERN_ERR "no memory to store dma channel order\n"); 14620c6022d453ecebdace0ce15434c7108e158149caBen Dooks return -ENOMEM; 14630c6022d453ecebdace0ce15434c7108e158149caBen Dooks } 14640c6022d453ecebdace0ce15434c7108e158149caBen Dooks 14650c6022d453ecebdace0ce15434c7108e158149caBen Dooks dma_order = nord; 14660c6022d453ecebdace0ce15434c7108e158149caBen Dooks memcpy(nord, ord, sizeof(struct s3c24xx_dma_order)); 14670c6022d453ecebdace0ce15434c7108e158149caBen Dooks return 0; 14680c6022d453ecebdace0ce15434c7108e158149caBen Dooks} 1469