Пример #1
0
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;
}
Пример #2
0
static int s3c2410_dma_dostop(s3c2410_dma_chan_t *chan)
{
	unsigned long tmp;
	unsigned long flags;

	pr_debug("%s:\n", __FUNCTION__);

	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;
	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

	chan->state      = S3C2410_DMA_IDLE;
	chan->load_state = S3C2410_DMALOAD_NONE;

	local_irq_restore(flags);

	return 0;
}
Пример #3
0
static int s3c2410_dma_start(struct s3c2410_dma_chan *chan)
{
    unsigned long tmp;
    unsigned long flags;

    pr_debug("s3c2410_start_dma: channel=%d\n", chan->number);

    local_irq_save(flags);

    if (chan->state == S3C2410_DMA_RUNNING) {
        pr_debug("s3c2410_start_dma: already running (%d)\n", chan->state);
        local_irq_restore(flags);
        return 0;
    }

    chan->state = S3C2410_DMA_RUNNING;

    /* check wether there is anything to load, and if not, see
     * if we can find anything to load
     */

    if (chan->load_state == S3C2410_DMALOAD_NONE) {
        if (chan->next == NULL) {
            printk(KERN_ERR "dma%d: channel has nothing loaded\n",
                   chan->number);
            chan->state = S3C2410_DMA_IDLE;
            local_irq_restore(flags);
            return -EINVAL;
        }

        s3c2410_dma_loadbuffer(chan, chan->next);
    }

    dbg_showchan(chan);

    /* enable the channel */

    if (!chan->irq_enabled) {
        enable_irq(chan->irq);
        chan->irq_enabled = 1;
    }

    /* start the channel going */

    tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
    tmp &= ~S3C2410_DMASKTRIG_STOP;
    tmp |= S3C2410_DMASKTRIG_ON;
    dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, 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
     * reloading feature */
    tmp = dma_rdreg(chan, S3C2410_DMA_DCON);
    tmp &= ~S3C2410_DCON_NORELOAD;
    dma_wrreg(chan, S3C2410_DMA_DCON, tmp);
#endif

    s3c2410_dma_call_op(chan, S3C2410_DMAOP_START);

    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;
}
Пример #4
0
static int s3c2410_dma_start(s3c2410_dma_chan_t *chan)
{
	unsigned long tmp;
	unsigned long flags;

	pr_debug("s3c2410_start_dma: channel=%d\n", chan->number);

	local_irq_save(flags);

	if (chan->state == S3C2410_DMA_RUNNING) {
		pr_debug("s3c2410_start_dma: already running (%d)\n", chan->state);
		local_irq_restore(flags);
		return 0;
	}

	chan->state = S3C2410_DMA_RUNNING;

	/* check wether there is anything to load, and if not, see
	 * if we can find anything to load
	 */

	if (chan->load_state == S3C2410_DMALOAD_NONE) {
		if (chan->next == NULL) {
			printk(KERN_ERR "dma%d: channel has nothing loaded\n",
			       chan->number);
			chan->state = S3C2410_DMA_IDLE;
			local_irq_restore(flags);
			return -EINVAL;
		}

		s3c2410_dma_loadbuffer(chan, chan->next);
	}

	dbg_showchan(chan);

	/* enable the channel */

	if (!chan->irq_enabled) {
		enable_irq(chan->irq);
		chan->irq_enabled = 1;
	}

	/* start the channel going */

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

	pr_debug("wrote %08lx to DMASKTRIG\n", tmp);

#if 0
	/* the dma buffer loads should take care of clearing the AUTO
	 * reloading feature */
	tmp = dma_rdreg(chan, S3C2410_DMA_DCON);
	tmp &= ~S3C2410_DCON_NORELOAD;
	dma_wrreg(chan, S3C2410_DMA_DCON, tmp);
#endif

	s3c2410_dma_call_op(chan, S3C2410_DMAOP_START);

	dbg_showchan(chan);

	local_irq_restore(flags);
	return 0;
}
Пример #5
0
static irqreturn_t
s3c2410_dma_irq(int irq, void *devpw)
{
	struct s3c2410_dma_chan *chan = (struct s3c2410_dma_chan *)devpw;
	struct s3c2410_dma_buf  *buf;

	buf = chan->curr;

	dbg_showchan(chan);

	/* modify the channel state */

	switch (chan->load_state) {
	case S3C2410_DMALOAD_1RUNNING:
		/* TODO - if we are running only one buffer, we probably
		 * want to reload here, and then worry about the buffer
		 * callback */

		chan->load_state = S3C2410_DMALOAD_NONE;
		break;

	case S3C2410_DMALOAD_1LOADED:
		/* iirc, we should go back to NONE loaded here, we
		 * had a buffer, and it was never verified as being
		 * loaded.
		 */

		chan->load_state = S3C2410_DMALOAD_NONE;
		break;

	case S3C2410_DMALOAD_1LOADED_1RUNNING:
		/* we'll worry about checking to see if another buffer is
		 * ready after we've called back the owner. This should
		 * ensure we do not wait around too long for the DMA
		 * engine to start the next transfer
		 */

		chan->load_state = S3C2410_DMALOAD_1LOADED;
		break;

	case S3C2410_DMALOAD_NONE:
		printk(KERN_ERR "dma%d: IRQ with no loaded buffer?\n",
		       chan->number);
		break;

	default:
		printk(KERN_ERR "dma%d: IRQ in invalid load_state %d\n",
		       chan->number, chan->load_state);
		break;
	}

	if (buf != NULL) {
		/* update the chain to make sure that if we load any more
		 * buffers when we call the callback function, things should
		 * work properly */

		chan->curr = buf->next;
		buf->next  = NULL;

		if (buf->magic != BUF_MAGIC) {
			printk(KERN_ERR "dma%d: %s: buf %p incorrect magic\n",
			       chan->number, __func__, buf);
			return IRQ_HANDLED;
		}

		s3c2410_dma_buffdone(chan, buf, S3C2410_RES_OK);

		/* free resouces */
		s3c2410_dma_freebuf(buf);
	} else {
	}

	/* 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;
		unsigned long tmp;

		switch (chan->load_state) {
		case S3C2410_DMALOAD_1RUNNING:
			/* don't need to do anything for this state */
			break;

		case S3C2410_DMALOAD_NONE:
			/* can load buffer immediately */
			break;

		case S3C2410_DMALOAD_1LOADED:
			/* printk(KERN_INFO "DMA: 1 LOADED\n"); */
			//if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
			//	/* flag error? */
			//	printk(KERN_ERR "dma%d: timeout waiting for load (%s)\n",
			//	       chan->number, __func__);
			//	return IRQ_HANDLED;
			//}

			break;

		case S3C2410_DMALOAD_1LOADED_1RUNNING:
			goto no_load;

		default:
			printk(KERN_ERR "dma%d: unknown load_state in irq, %d\n",
			       chan->number, chan->load_state);
			return IRQ_HANDLED;
		}

		/*
		 * Since we are not using the auto-reload feature, we must restart
		 * the DMA-channel at this point
		 * (Luis Galdos)
		 */
		local_irq_save(flags);
		chan->load_state = S3C2410_DMALOAD_NONE;
		s3c2410_dma_loadbuffer(chan, chan->curr);
		tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
		tmp &= ~S3C2410_DMASKTRIG_STOP;
		tmp |= S3C2410_DMASKTRIG_ON;
		dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp);
		s3c2410_dma_call_op(chan, S3C2410_DMAOP_START);
		local_irq_restore(flags);
	} else {
		s3c2410_dma_lastxfer(chan);

		/* see if we can stop this channel.. */
		if (chan->load_state == S3C2410_DMALOAD_NONE) {
			pr_debug("dma%d: end of transfer, stopping channel (%ld)\n",
				 chan->number, jiffies);
			s3c2410_dma_ctrl(chan->number | DMACH_LOW_LEVEL,
					 S3C2410_DMAOP_STOP);
		}
	}

 no_load:
	return IRQ_HANDLED;
}