Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 33435
b: refs/heads/master
c: f57e1ab
h: refs/heads/master
i:
  33433: 0371b59
  33431: 038d8b0
v: v3
  • Loading branch information
Ben Dooks authored and Russell King committed Aug 18, 2006
1 parent b4f499c commit d2093b3
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 20 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: a0c5a64552e3c57d7f9eb593c6ce21a285ac86b4
refs/heads/master: f57e1abd1bb297994c7398478b4c37e628095243
163 changes: 144 additions & 19 deletions trunk/arch/arm/mach-s3c2410/dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ dmadbg_capture(s3c2410_dma_chan_t *chan, struct s3c2410_dma_regstate *regs)
}

static void
dmadbg_showregs(const char *fname, int line, s3c2410_dma_chan_t *chan,
dmadbg_dumpregs(const char *fname, int line, s3c2410_dma_chan_t *chan,
struct s3c2410_dma_regstate *regs)
{
printk(KERN_DEBUG "dma%d: %s:%d: DCSRC=%08lx, DISRC=%08lx, DSTAT=%08lx DMT=%02lx, DCON=%08lx\n",
Expand All @@ -132,7 +132,16 @@ dmadbg_showchan(const char *fname, int line, s3c2410_dma_chan_t *chan)
chan->number, fname, line, chan->load_state,
chan->curr, chan->next, chan->end);

dmadbg_showregs(fname, line, chan, &state);
dmadbg_dumpregs(fname, line, chan, &state);
}

static void
dmadbg_showregs(const char *fname, int line, s3c2410_dma_chan_t *chan)
{
struct s3c2410_dma_regstate state;

dmadbg_capture(chan, &state);
dmadbg_dumpregs(fname, line, chan, &state);
}

#define dbg_showregs(chan) dmadbg_showregs(__FUNCTION__, __LINE__, (chan))
Expand Down Expand Up @@ -253,10 +262,14 @@ s3c2410_dma_loadbuffer(s3c2410_dma_chan_t *chan,
buf->next);
reload = (buf->next == NULL) ? S3C2410_DCON_NORELOAD : 0;
} else {
pr_debug("load_state is %d => autoreload\n", chan->load_state);
//pr_debug("load_state is %d => autoreload\n", chan->load_state);
reload = S3C2410_DCON_AUTORELOAD;
}

if ((buf->data & 0xf0000000) != 0x30000000) {
dmawarn("dmaload: buffer is %p\n", (void *)buf->data);
}

writel(buf->data, chan->addr_reg);

dma_wrreg(chan, S3C2410_DMA_DCON,
Expand Down Expand Up @@ -370,7 +383,7 @@ static int s3c2410_dma_start(s3c2410_dma_chan_t *chan)
tmp |= S3C2410_DMASKTRIG_ON;
dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp);

pr_debug("wrote %08lx to DMASKTRIG\n", tmp);
pr_debug("dma%d: %08lx to DMASKTRIG\n", chan->number, tmp);

#if 0
/* the dma buffer loads should take care of clearing the AUTO
Expand All @@ -384,7 +397,30 @@ static int s3c2410_dma_start(s3c2410_dma_chan_t *chan)

dbg_showchan(chan);

/* if we've only loaded one buffer onto the channel, then chec
* to see if we have another, and if so, try and load it so when
* the first buffer is finished, the new one will be loaded onto
* the channel */

if (chan->next != NULL) {
if (chan->load_state == S3C2410_DMALOAD_1LOADED) {

if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
pr_debug("%s: buff not yet loaded, no more todo\n",
__FUNCTION__);
} else {
chan->load_state = S3C2410_DMALOAD_1RUNNING;
s3c2410_dma_loadbuffer(chan, chan->next);
}

} else if (chan->load_state == S3C2410_DMALOAD_1RUNNING) {
s3c2410_dma_loadbuffer(chan, chan->next);
}
}


local_irq_restore(flags);

return 0;
}

Expand Down Expand Up @@ -436,12 +472,11 @@ int s3c2410_dma_enqueue(unsigned int channel, void *id,
buf = kmem_cache_alloc(dma_kmem, GFP_ATOMIC);
if (buf == NULL) {
pr_debug("%s: out of memory (%ld alloc)\n",
__FUNCTION__, sizeof(*buf));
__FUNCTION__, (long)sizeof(*buf));
return -ENOMEM;
}

pr_debug("%s: new buffer %p\n", __FUNCTION__, buf);

//pr_debug("%s: new buffer %p\n", __FUNCTION__, buf);
//dbg_showchan(chan);

buf->next = NULL;
Expand Down Expand Up @@ -537,14 +572,20 @@ s3c2410_dma_lastxfer(s3c2410_dma_chan_t *chan)
case S3C2410_DMALOAD_1LOADED:
if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
/* flag error? */
printk(KERN_ERR "dma%d: timeout waiting for load\n",
chan->number);
printk(KERN_ERR "dma%d: timeout waiting for load (%s)\n",
chan->number, __FUNCTION__);
return;
}
break;

case S3C2410_DMALOAD_1LOADED_1RUNNING:
/* I belive in this case we do not have anything to do
* until the next buffer comes along, and we turn off the
* reload */
return;

default:
pr_debug("dma%d: lastxfer: unhandled load_state %d with no next",
pr_debug("dma%d: lastxfer: unhandled load_state %d with no next\n",
chan->number, chan->load_state);
return;

Expand Down Expand Up @@ -629,7 +670,14 @@ s3c2410_dma_irq(int irq, void *devpw, struct pt_regs *regs)
} else {
}

if (chan->next != NULL) {
/* only reload if the channel is still running... our buffer done
* routine may have altered the state by requesting the dma channel
* to stop or shutdown... */

/* todo: check that when the channel is shut-down from inside this
* function, we cope with unsetting reload, etc */

if (chan->next != NULL && chan->state != S3C2410_DMA_IDLE) {
unsigned long flags;

switch (chan->load_state) {
Expand All @@ -644,8 +692,8 @@ s3c2410_dma_irq(int irq, void *devpw, struct pt_regs *regs)
case S3C2410_DMALOAD_1LOADED:
if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
/* flag error? */
printk(KERN_ERR "dma%d: timeout waiting for load\n",
chan->number);
printk(KERN_ERR "dma%d: timeout waiting for load (%s)\n",
chan->number, __FUNCTION__);
return IRQ_HANDLED;
}

Expand Down Expand Up @@ -678,8 +726,6 @@ s3c2410_dma_irq(int irq, void *devpw, struct pt_regs *regs)
return IRQ_HANDLED;
}



/* s3c2410_request_dma
*
* get control of an dma channel
Expand Down Expand Up @@ -718,19 +764,24 @@ int s3c2410_dma_request(unsigned int channel, s3c2410_dma_client_t *client,
pr_debug("dma%d: %s : requesting irq %d\n",
channel, __FUNCTION__, chan->irq);

chan->irq_claimed = 1;
local_irq_restore(flags);

err = request_irq(chan->irq, s3c2410_dma_irq, IRQF_DISABLED,
client->name, (void *)chan);

local_irq_save(flags);

if (err) {
chan->in_use = 0;
chan->irq_claimed = 0;
local_irq_restore(flags);

printk(KERN_ERR "%s: cannot get IRQ %d for DMA %d\n",
client->name, chan->irq, chan->number);
return err;
}

chan->irq_claimed = 1;
chan->irq_enabled = 1;
}

Expand Down Expand Up @@ -810,6 +861,7 @@ static int s3c2410_dma_dostop(s3c2410_dma_chan_t *chan)

tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
tmp |= S3C2410_DMASKTRIG_STOP;
//tmp &= ~S3C2410_DMASKTRIG_ON;
dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp);

#if 0
Expand All @@ -819,6 +871,7 @@ static int s3c2410_dma_dostop(s3c2410_dma_chan_t *chan)
dma_wrreg(chan, S3C2410_DMA_DCON, tmp);
#endif

/* should stop do this, or should we wait for flush? */
chan->state = S3C2410_DMA_IDLE;
chan->load_state = S3C2410_DMALOAD_NONE;

Expand All @@ -827,6 +880,22 @@ static int s3c2410_dma_dostop(s3c2410_dma_chan_t *chan)
return 0;
}

void s3c2410_dma_waitforstop(s3c2410_dma_chan_t *chan)
{
unsigned long tmp;
unsigned int timeout = 0x10000;

while (timeout-- > 0) {
tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);

if (!(tmp & S3C2410_DMASKTRIG_ON))
return;
}

pr_debug("dma%d: failed to stop?\n", chan->number);
}


/* s3c2410_dma_flush
*
* stop the channel, and remove all current and pending transfers
Expand All @@ -837,7 +906,9 @@ static int s3c2410_dma_flush(s3c2410_dma_chan_t *chan)
s3c2410_dma_buf_t *buf, *next;
unsigned long flags;

pr_debug("%s:\n", __FUNCTION__);
pr_debug("%s: chan %p (%d)\n", __FUNCTION__, chan, chan->number);

dbg_showchan(chan);

local_irq_save(flags);

Expand All @@ -864,11 +935,64 @@ static int s3c2410_dma_flush(s3c2410_dma_chan_t *chan)
}
}

dbg_showregs(chan);

s3c2410_dma_waitforstop(chan);

#if 0
/* should also clear interrupts, according to WinCE BSP */
{
unsigned long tmp;

tmp = dma_rdreg(chan, S3C2410_DMA_DCON);
tmp |= S3C2410_DCON_NORELOAD;
dma_wrreg(chan, S3C2410_DMA_DCON, tmp);
}
#endif

dbg_showregs(chan);

local_irq_restore(flags);

return 0;
}

int
s3c2410_dma_started(s3c2410_dma_chan_t *chan)
{
unsigned long flags;

local_irq_save(flags);

dbg_showchan(chan);

/* if we've only loaded one buffer onto the channel, then chec
* to see if we have another, and if so, try and load it so when
* the first buffer is finished, the new one will be loaded onto
* the channel */

if (chan->next != NULL) {
if (chan->load_state == S3C2410_DMALOAD_1LOADED) {

if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
pr_debug("%s: buff not yet loaded, no more todo\n",
__FUNCTION__);
} else {
chan->load_state = S3C2410_DMALOAD_1RUNNING;
s3c2410_dma_loadbuffer(chan, chan->next);
}

} else if (chan->load_state == S3C2410_DMALOAD_1RUNNING) {
s3c2410_dma_loadbuffer(chan, chan->next);
}
}


local_irq_restore(flags);

return 0;

}

int
s3c2410_dma_ctrl(dmach_t channel, s3c2410_chan_op_t op)
Expand All @@ -885,14 +1009,15 @@ s3c2410_dma_ctrl(dmach_t channel, s3c2410_chan_op_t op)
return s3c2410_dma_dostop(chan);

case S3C2410_DMAOP_PAUSE:
return -ENOENT;

case S3C2410_DMAOP_RESUME:
return -ENOENT;

case S3C2410_DMAOP_FLUSH:
return s3c2410_dma_flush(chan);

case S3C2410_DMAOP_STARTED:
return s3c2410_dma_started(chan);

case S3C2410_DMAOP_TIMEOUT:
return 0;

Expand Down
1 change: 1 addition & 0 deletions trunk/include/asm-arm/arch-s3c2410/dma.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ enum s3c2410_chan_op_e {
S3C2410_DMAOP_RESUME,
S3C2410_DMAOP_FLUSH,
S3C2410_DMAOP_TIMEOUT, /* internal signal to handler */
S3C2410_DMAOP_STARTED, /* indicate channel started */
};

typedef enum s3c2410_chan_op_e s3c2410_chan_op_t;
Expand Down

0 comments on commit d2093b3

Please sign in to comment.