|
@@ -829,3 +829,146 @@ EXPORT_SYMBOL(s3c2410_dma_free);
|
|
|
static int s3c2410_dma_dostop(struct s3c2410_dma_chan *chan)
|
|
|
{
|
|
|
unsigned long flags;
|
|
|
+ unsigned long tmp;
|
|
|
+
|
|
|
+ pr_debug("%s:\n", __func__);
|
|
|
+
|
|
|
+ dbg_showchan(chan);
|
|
|
+
|
|
|
+ local_irq_save(flags);
|
|
|
+
|
|
|
+ s3c2410_dma_call_op(chan, S3C2410_DMAOP_STOP);
|
|
|
+
|
|
|
+ tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
|
|
|
+ tmp |= S3C2410_DMASKTRIG_STOP;
|
|
|
+ //tmp &= ~S3C2410_DMASKTRIG_ON;
|
|
|
+ dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp);
|
|
|
+
|
|
|
+#if 0
|
|
|
+ /* should also clear interrupts, according to WinCE BSP */
|
|
|
+ tmp = dma_rdreg(chan, S3C2410_DMA_DCON);
|
|
|
+ tmp |= S3C2410_DCON_NORELOAD;
|
|
|
+ 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;
|
|
|
+
|
|
|
+ local_irq_restore(flags);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static void s3c2410_dma_waitforstop(struct s3c2410_dma_chan *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
|
|
|
+*/
|
|
|
+
|
|
|
+static int s3c2410_dma_flush(struct s3c2410_dma_chan *chan)
|
|
|
+{
|
|
|
+ struct s3c2410_dma_buf *buf, *next;
|
|
|
+ unsigned long flags;
|
|
|
+
|
|
|
+ pr_debug("%s: chan %p (%d)\n", __func__, chan, chan->number);
|
|
|
+
|
|
|
+ dbg_showchan(chan);
|
|
|
+
|
|
|
+ local_irq_save(flags);
|
|
|
+
|
|
|
+ if (chan->state != S3C2410_DMA_IDLE) {
|
|
|
+ pr_debug("%s: stopping channel...\n", __func__ );
|
|
|
+ s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_STOP);
|
|
|
+ }
|
|
|
+
|
|
|
+ buf = chan->curr;
|
|
|
+ if (buf == NULL)
|
|
|
+ buf = chan->next;
|
|
|
+
|
|
|
+ chan->curr = chan->next = chan->end = NULL;
|
|
|
+
|
|
|
+ if (buf != NULL) {
|
|
|
+ for ( ; buf != NULL; buf = next) {
|
|
|
+ next = buf->next;
|
|
|
+
|
|
|
+ pr_debug("%s: free buffer %p, next %p\n",
|
|
|
+ __func__, buf, buf->next);
|
|
|
+
|
|
|
+ s3c2410_dma_buffdone(chan, buf, S3C2410_RES_ABORT);
|
|
|
+ s3c2410_dma_freebuf(buf);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ 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;
|
|
|
+}
|
|
|
+
|
|
|
+static int s3c2410_dma_started(struct s3c2410_dma_chan *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",
|
|
|
+ __func__);
|
|
|
+ } 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;
|
|
|
+
|
|
|
+}
|