Example #1
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;
}
Example #2
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;
}
Example #3
0
/* s3c_dma_loadbuffer
 *
 * load a buffer, and update the channel state
 */
static inline int s3c_dma_loadbuffer(struct s3c2410_dma_chan *chan,
		       struct s3c_dma_buf *buf)
{
	unsigned long reload;

	pr_debug("s3c_chan_loadbuffer: loading buffer %p (0x%08lx,0x%06x)\n",
		 buf, (unsigned long) buf->data, buf->size);

	if (buf == NULL) {
		dmawarn("buffer is NULL\n");
		return -EINVAL;
	}

	/* check the state of the channel before we do anything */

	if (chan->load_state == S3C_DMALOAD_1LOADED) {
		dmawarn("load_state is S3C2410_DMALOAD_1LOADED\n");
		reload = (buf->next == NULL) ? S3C2410_DCON_NORELOAD : 0;
	}

	if (chan->load_state == S3C_DMALOAD_1LOADED_1RUNNING) {
		dmawarn("state is S3C2410_DMALOAD_1LOADED_1RUNNING\n");
		reload = S3C2410_DCON_AUTORELOAD;
	}

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

	pr_debug("%s: DMA control0 - %08x\n", __FUNCTION__, chan->dcon);
	pr_debug("%s: DMA control1 - %08x\n", __FUNCTION__, (buf->size / chan->xfer_unit));
	
	dma_wrreg(chan, S3C_DMAC_CxCONTROL0, chan->dcon);
	dma_wrreg(chan, S3C_DMAC_CxCONTROL1, (buf->size / chan->xfer_unit));
	
	chan->next = buf->next;

	/* update the state of the channel */

	switch (chan->load_state) {
	case S3C_DMALOAD_NONE:
		chan->load_state = S3C_DMALOAD_1LOADED;
		break;

	case S3C_DMALOAD_1RUNNING:
		chan->load_state = S3C_DMALOAD_1LOADED_1RUNNING;
		break;

	default:
		dmawarn("dmaload: unknown state %d in loadbuffer\n", chan->load_state);
		break;
	}

	return 0;
}
Example #4
0
void s3c_clear_interrupts (int dcon_num, int channel)
{
	unsigned long tmp;
	s3c_dma_controller_t *dma_controller = &s3c_dma_cntlrs[dcon_num];
	
	tmp = dma_rdreg(dma_controller, S3C_DMAC_INT_TCCLEAR);
	tmp |= (1 << channel);
	dma_wrreg(dma_controller, S3C_DMAC_INT_TCCLEAR, tmp);

	tmp = dma_rdreg(dma_controller, S3C_DMAC_INT_ERRORCLEAR);
	tmp |= (1 << channel);
	dma_wrreg(dma_controller, S3C_DMAC_INT_ERRORCLEAR, tmp);
}
Example #5
0
static int s3c_dma_dostop(struct s3c2410_dma_chan *chan) 
{
	unsigned long tmp;
	unsigned long flags;

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

	dbg_showchan(chan);

	local_irq_save(flags);

	s3c_dma_flush_fifo(chan);
	
	s3c_dma_call_op(chan, S3C2410_DMAOP_STOP);

	tmp = dma_rdreg(chan, S3C_DMAC_CxCONFIGURATION);
	
	tmp &= ~S3C_DMACONFIG_CHANNEL_ENABLE;
	dma_wrreg(chan, S3C_DMAC_CxCONFIGURATION, tmp);
	
	pr_debug("%s: S3C_DMAC_CxCONFIGURATION : %08x\n", __FUNCTION__, tmp);

	chan->state = S3C_DMA_IDLE;
	chan->load_state = S3C_DMALOAD_NONE;

	local_irq_restore(flags);

	return 0;
}
Example #6
0
static inline void
s3c2410_dma_lastxfer(s3c2410_dma_chan_t *chan)
{
	pr_debug("dma%d: s3c2410_dma_lastxfer: load_state %d\n",
		 chan->number, chan->load_state);

	switch (chan->load_state) {
	case S3C2410_DMALOAD_NONE:
		break;

	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);
			return;
		}
		break;

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

	}

	/* hopefully this'll shut the damned thing up after the transfer... */
	dma_wrreg(chan, S3C2410_DMA_DCON, chan->dcon | S3C2410_DCON_NORELOAD);
}
static int s3c_dma_dostop(struct s3c2410_dma_chan *chan) 
{
	unsigned long tmp;
	unsigned long flags;

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

	dbg_showchan(chan);

	local_irq_save(flags);

    //Commenting out this function call(as its causing freeze) and even without this it adheres to  
    //ARM Primecell 080's disabling a DMA channel and losing data in the FIFO method 
	//s3c_dma_flush_fifo(chan);
	
	s3c_dma_call_op(chan, S3C2410_DMAOP_STOP);

	tmp = dma_rdreg(chan, S3C_DMAC_CxCONFIGURATION);
	
	tmp &= ~S3C_DMACONFIG_CHANNEL_ENABLE;
	dma_wrreg(chan, S3C_DMAC_CxCONFIGURATION, tmp);
	
	pr_debug("%s: S3C_DMAC_CxCONFIGURATION : %08x\n", __FUNCTION__, tmp);

	chan->state = S3C_DMA_IDLE;
	chan->load_state = S3C_DMALOAD_NONE;

	local_irq_restore(flags);

	return 0;
}
Example #8
0
static inline void
s3c2410_dma_lastxfer(struct s3c2410_dma_chan *chan)
{

	switch (chan->load_state) {
	case S3C2410_DMALOAD_NONE:
		break;

	case S3C2410_DMALOAD_1LOADED:
		if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
				/* flag error? */
			printk(KERN_ERR "dma%d: timeout waiting for load (%s)\n",
			       chan->number, __func__);
			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\n",
			 chan->number, chan->load_state);
		return;

	}

	/* hopefully this'll shut the damned thing up after the transfer... */
	dma_wrreg(chan, S3C2410_DMA_DCON, chan->dcon | S3C2410_DCON_NORELOAD);
}
Example #9
0
void s3c_disable_dmac(unsigned int dcon_num)
{
	unsigned long tmp;
	s3c_dma_controller_t *dma_controller = &s3c_dma_cntlrs[dcon_num];
	tmp = dma_rdreg(dma_controller, S3C_DMAC_CONFIGURATION);
	tmp &= ~S3C_DMA_CONTROLLER_ENABLE;
	dma_wrreg(dma_controller, S3C_DMAC_CONFIGURATION, tmp);
}
Example #10
0
void dma_test (int dcon_num, int channel)
{
	int tmp;
	
	s3c_dma_controller_t *dma_controller = &s3c_dma_cntlrs[dcon_num];

	dma_wrreg(dma_controller, S3C_DMAC_CONFIGURATION, S3C_DMA_CONTROLLER_ENABLE);
	tmp = dma_rdreg(dma_controller, S3C_DMAC_CONFIGURATION);
	printk("reg val %d\n", tmp);
	dma_wrreg(dma_controller, S3C_DMAC_CCONFIGURATION(channel), 0x01);
	tmp = dma_rdreg(dma_controller, S3C_DMAC_CCONFIGURATION(channel));

	printk("reg conf %x\n", tmp);
	dma_wrreg(dma_controller, S3C_DMAC_CCONTROL0(channel), 0x8ff02064);

	tmp = dma_rdreg(dma_controller, S3C_DMAC_CCONTROL0(channel));
	printk("reg ctrl %x\n", tmp);
}
Example #11
0
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;
}
Example #12
0
/* s3c_dma_start
 *
 * start a dma channel going
 */
static int s3c_dma_start(struct s3c2410_dma_chan *chan)
{
	unsigned long flags;

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

	local_irq_save(flags);

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

	chan->state = S3C_DMA_RUNNING;

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

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

		s3c_dma_loadbuffer(chan, chan->next);
	}

	dbg_showchan(chan);

	/* enable the channel */

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

	/* Get the DMA channel  started ...*/
	dma_wrreg(chan, S3C_DMAC_CxCONFIGURATION, chan->config_flags);

	pr_debug("%s:wrote %08lx to S3C_DMAC_CxCONFIGURATION.\n",__FUNCTION__, chan->config_flags);

	/* Start the DMA operation on Peripheral */
	s3c_dma_call_op(chan, S3C2410_DMAOP_START);

	dbg_showchan(chan);

	local_irq_restore(flags);
	return 0;
}
Example #13
0
/*actively polling for the A bit can block the cpu*/
void s3c_dma_flush_fifo(struct s3c2410_dma_chan *chan)
{
	unsigned long tmp;
	
	tmp = dma_rdreg(chan, S3C_DMAC_CxCONFIGURATION);
	tmp |= S3C_DMACONFIG_HALT;
	dma_wrreg(chan, S3C_DMAC_CxCONFIGURATION, tmp);

	tmp = dma_rdreg(chan, S3C_DMAC_CxCONFIGURATION);
	
	/*this while loop can be very dangerous..may be put the process to sleep rather than waiting till fifo is drained */
	while (tmp & S3C_DMACONFIG_ACTIVE) {
		tmp = dma_rdreg(chan, S3C_DMAC_CxCONFIGURATION);
	}
}
Example #14
0
int s3c2410_dma_devconfig(int channel,
                          enum s3c2410_dmasrc source,
                          int hwcfg,
                          unsigned long devaddr)
{
    struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);

    if (chan == NULL)
        return -EINVAL;

    pr_debug("%s: source=%d, hwcfg=%08x, devaddr=%08lx\n",
             __func__, (int)source, hwcfg, devaddr);

    chan->source = source;
    chan->dev_addr = devaddr;
    chan->hw_cfg = hwcfg;

    switch (source) {
    case S3C2410_DMASRC_HW:
        /* source is hardware */
        pr_debug("%s: hw source, devaddr=%08lx, hwcfg=%d\n",
                 __func__, devaddr, hwcfg);
        dma_wrreg(chan, S3C2410_DMA_DISRCC, hwcfg & 3);
        dma_wrreg(chan, S3C2410_DMA_DISRC,  devaddr);
        dma_wrreg(chan, S3C2410_DMA_DIDSTC, (0<<1) | (0<<0));

        chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DIDST);
        break;

    case S3C2410_DMASRC_MEM:
        /* source is memory */
        pr_debug("%s: mem source, devaddr=%08lx, hwcfg=%d\n",
                 __func__, devaddr, hwcfg);
        dma_wrreg(chan, S3C2410_DMA_DISRCC, (0<<1) | (0<<0));
        dma_wrreg(chan, S3C2410_DMA_DIDST,  devaddr);
        dma_wrreg(chan, S3C2410_DMA_DIDSTC, hwcfg & 3);

        chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DISRC);
        break;

    default:
        printk(KERN_ERR "dma%d: invalid source type (%d)\n",
               channel, source);

        return -EINVAL;
    }

    if (dma_sel.direction != NULL)
        (dma_sel.direction)(chan, chan->map, source);

    return 0;
}
Example #15
0
int s3c2410_dma_devconfig(int channel,
			  s3c2410_dmasrc_t source,
			  int hwcfg,
			  unsigned long devaddr)
{
	s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];

	check_channel(channel);

	pr_debug("%s: source=%d, hwcfg=%08x, devaddr=%08lx\n",
		 __FUNCTION__, (int)source, hwcfg, devaddr);

	chan->source = source;
	chan->dev_addr = devaddr;

	switch (source) {
	case S3C2410_DMASRC_HW:
		/* source is hardware */
		pr_debug("%s: hw source, devaddr=%08lx, hwcfg=%d\n",
			 __FUNCTION__, devaddr, hwcfg);
		dma_wrreg(chan, S3C2410_DMA_DISRCC, hwcfg & 3);
		dma_wrreg(chan, S3C2410_DMA_DISRC,  devaddr);
		dma_wrreg(chan, S3C2410_DMA_DIDSTC, (0<<1) | (0<<0));

		chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DIDST);
		return 0;

	case S3C2410_DMASRC_MEM:
		/* source is memory */
		pr_debug( "%s: mem source, devaddr=%08lx, hwcfg=%d\n",
			  __FUNCTION__, devaddr, hwcfg);
		dma_wrreg(chan, S3C2410_DMA_DISRCC, (0<<1) | (0<<0));
		dma_wrreg(chan, S3C2410_DMA_DIDST,  devaddr);
		dma_wrreg(chan, S3C2410_DMA_DIDSTC, hwcfg & 3);

		chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DISRC);
		return 0;
	}

	printk(KERN_ERR "dma%d: invalid source type (%d)\n", channel, source);
	return -EINVAL;
}
Example #16
0
static irqreturn_t s3c_dma_irq(int irq, void *devpw)
{
	unsigned int channel = 0, dcon_num, i;
	unsigned long tmp;
	s3c_dma_controller_t *dma_controller = (s3c_dma_controller_t *) devpw;
	
	struct s3c2410_dma_chan *chan=NULL;
	struct s3c_dma_buf *buf;

	dcon_num = dma_controller->number;
	tmp = dma_rdreg(dma_controller, S3C_DMAC_INT_TCSTATUS);
	pr_debug("# s3c_dma_irq: TC status : 0x%x\n", tmp);

	if (tmp == 0)
		return IRQ_HANDLED;

	for (i = 0; i < S3C_CHANNELS_PER_DMA; i++) {
		if (tmp & 0x01) {

			pr_debug("# DMA Controller %d: requestor %d\n", dcon_num, i);
			
			channel = i;
			chan = &s3c_dma_chans[channel + dcon_num * S3C_CHANNELS_PER_DMA];
			pr_debug("# DMA channel number : %d, index : %d\n", chan->number, chan->index);
			
			buf = chan->curr;
			
			dbg_showchan(chan);

			/* modify the channel state */
			switch (chan->load_state) {
			case S3C_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 = S3C_DMALOAD_NONE;
				break;

			case S3C_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 = S3C_DMALOAD_NONE;
				break;

			case S3C_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 = S3C_DMALOAD_1LOADED;
				break;

			case S3C_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, __FUNCTION__, buf);
					goto next_channel;
				}

				s3c_dma_buffdone(chan, buf, S3C2410_RES_OK);

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

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

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

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

				case S3C_DMALOAD_1LOADED:
					if (s3c_dma_waitforload(chan, __LINE__) == 0) {
						/* flag error? */
						printk(KERN_ERR "dma%d: timeout waiting for load\n",
						       chan->number);
						goto next_channel;
					}

					break;

				case S3C_DMALOAD_1LOADED_1RUNNING:
					goto next_channel;

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

				local_irq_save(flags);
				s3c_dma_loadbuffer(chan, chan->next);
				
				//shaju added for dbg
				dma_wrreg(chan, S3C_DMAC_CxCONFIGURATION, chan->config_flags);
				
				local_irq_restore(flags);
				
			} else {
				s3c_dma_lastxfer(chan);
				
				/* see if we can stop this channel.. */
				if (chan->load_state == S3C_DMALOAD_NONE) {
					pr_debug("# DMA CH %d(index:%d): end of transfer, stopping channel (%ld)\n",
						 chan->number, chan->index, jiffies);
					s3c2410_dma_ctrl(chan->index | DMACH_LOW_LEVEL, S3C2410_DMAOP_STOP);
				}
			}
			s3c_clear_interrupts(chan->dma_con->number, chan->number);

		}

next_channel:
		tmp >>= 1;
	}

	return IRQ_HANDLED;
}
Example #17
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;
}
Example #18
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;
}
Example #19
0
static inline int
s3c2410_dma_loadbuffer(struct s3c2410_dma_chan *chan,
                       struct s3c2410_dma_buf *buf)
{
    unsigned long reload;

    pr_debug("s3c2410_chan_loadbuffer: loading buff %p (0x%08lx,0x%06x)\n",
             buf, (unsigned long)buf->data, buf->size);

    if (buf == NULL) {
        dmawarn("buffer is NULL\n");
        return -EINVAL;
    }

    /* check the state of the channel before we do anything */

    if (chan->load_state == S3C2410_DMALOAD_1LOADED) {
        dmawarn("load_state is S3C2410_DMALOAD_1LOADED\n");
    }

    if (chan->load_state == S3C2410_DMALOAD_1LOADED_1RUNNING) {
        dmawarn("state is S3C2410_DMALOAD_1LOADED_1RUNNING\n");
    }

    /* it would seem sensible if we are the last buffer to not bother
     * with the auto-reload bit, so that the DMA engine will not try
     * and load another transfer after this one has finished...
     */
    if (chan->load_state == S3C2410_DMALOAD_NONE) {
        pr_debug("load_state is none, checking for noreload (next=%p)\n",
                 buf->next);
        reload = (buf->next == NULL) ? S3C2410_DCON_NORELOAD : 0;
    } else {
        //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,
              chan->dcon | reload | (buf->size/chan->xfer_unit));

    chan->next = buf->next;

    /* update the state of the channel */

    switch (chan->load_state) {
    case S3C2410_DMALOAD_NONE:
        chan->load_state = S3C2410_DMALOAD_1LOADED;
        break;

    case S3C2410_DMALOAD_1RUNNING:
        chan->load_state = S3C2410_DMALOAD_1LOADED_1RUNNING;
        break;

    default:
        dmawarn("dmaload: unknown state %d in loadbuffer\n",
                chan->load_state);
        break;
    }

    return 0;
}
Example #20
0
/* s3c_dma_loadbuffer
 *
 * load a buffer, and update the channel state
 */
static inline int s3c_dma_loadbuffer(struct s3c2410_dma_chan *chan,
		       struct s3c_dma_buf *buf)
{
	unsigned long tmp;
	pl330_DMA_parameters_t dma_param;
	struct s3c_dma_buf *firstbuf;
	int bwJump = 0;

	memset(&dma_param, 0, sizeof(pl330_DMA_parameters_t));
	pr_debug("s3c_chan_loadbuffer: loading buffer %p (0x%08lx,0x%06x)\n",
		 buf, (unsigned long) buf->data, buf->size);

	if (buf == NULL) {
		dmawarn("buffer is NULL\n");
		return -EINVAL;
	}

	pr_debug("%s: DMA CCR - %08x\n", __FUNCTION__, chan->dcon);
	pr_debug("%s: DMA Loop count - %08x\n", __FUNCTION__, (buf->size / chan->xfer_unit));

	firstbuf = buf;

	do {
		dma_param.mPeriNum = chan->config_flags;
		dma_param.mDirection = chan->source;

		switch (dma_param.mDirection) {
		case S3C2410_DMASRC_MEM:	/* source is Memory : Mem-to-Peri (Write into FIFO) */
			dma_param.mSrcAddr = buf->data;
			dma_param.mDstAddr = chan->dev_addr;
			break;

		case S3C2410_DMASRC_HW:		/* source is peripheral : Peri-to-Mem (Read from FIFO) */
			dma_param.mSrcAddr = chan->dev_addr;
			dma_param.mDstAddr = buf->data;
			break;

		case S3C_DMA_MEM2MEM:		/* source & Destination : Mem-to-Mem  */
			dma_param.mSrcAddr = chan->dev_addr;
			dma_param.mDstAddr = buf->data;
			break;

		case S3C_DMA_MEM2MEM_SET:		/* source & Destination : Mem-to-Mem  */
			dma_param.mDirection = S3C_DMA_MEM2MEM;
			dma_param.mSrcAddr = chan->dev_addr;
			dma_param.mDstAddr = buf->data;
			break;

		case S3C_DMA_PER2PER:
		default:
			printk("Peripheral-to-Peripheral DMA NOT YET implemented !! \n");
			return -EINVAL;
		}

		dma_param.mTrSize = buf->size;

		dma_param.mLoop = 0;
		dma_param.mControl = *(pl330_DMA_control_t *) &chan->dcon;

		chan->next = buf->next;
		buf = chan->next;

		if(buf==NULL) {
			firstbuf->next = NULL;
			dma_param.mLastReq = 1;
			dma_param.mIrqEnable = 1;
		}
		else {
			dma_param.mLastReq = 0;
			dma_param.mIrqEnable = 0;
		}

		bwJump += setup_DMA_channel(((u8 *)firstbuf->mcptr_cpu)+bwJump, dma_param, chan->number);
		pr_debug("%s: DMA bwJump - %d\n", __FUNCTION__, bwJump);

	}while(buf != NULL);

	if(dma_param.mIrqEnable) {
		tmp = dma_rdreg(chan->dma_con, S3C_DMAC_INTEN);
		tmp |= (1 << chan->number);
		dma_wrreg(chan->dma_con, S3C_DMAC_INTEN, tmp);
	}

	/* update the state of the channel */

	switch (chan->load_state) {
	case S3C_DMALOAD_NONE:
		chan->load_state = S3C_DMALOAD_1LOADED;
		break;

	case S3C_DMALOAD_1RUNNING:
		chan->load_state = S3C_DMALOAD_1LOADED_1RUNNING;
		break;

	default:
		dmawarn("dmaload: unknown state %d in loadbuffer\n", chan->load_state);
		break;
	}

	return 0;
}
int s3c2410_dma_devconfig(enum dma_ch channel,
			  enum s3c2410_dmasrc source,
			  unsigned long devaddr)
{
	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
	unsigned int hwcfg;

	if (chan == NULL)
		return -EINVAL;

	pr_debug("%s: source=%d, devaddr=%08lx\n",
		 __func__, (int)source, devaddr);

	chan->source = source;
	chan->dev_addr = devaddr;

	switch (chan->req_ch) {
	case DMACH_XD0:
	case DMACH_XD1:
		hwcfg = 0; /* AHB */
		break;

	default:
		hwcfg = S3C2410_DISRCC_APB;
	}

	/* always assume our peripheral desintation is a fixed
	 * address in memory. */
	 hwcfg |= S3C2410_DISRCC_INC;

	switch (source) {
	case S3C2410_DMASRC_HW:
		/* source is hardware */
		pr_debug("%s: hw source, devaddr=%08lx, hwcfg=%d\n",
			 __func__, devaddr, hwcfg);
		dma_wrreg(chan, S3C2410_DMA_DISRCC, hwcfg & 3);
		dma_wrreg(chan, S3C2410_DMA_DISRC,  devaddr);
		dma_wrreg(chan, S3C2410_DMA_DIDSTC, (0<<1) | (0<<0));

		chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DIDST);
		break;

	case S3C2410_DMASRC_MEM:
		/* source is memory */
		pr_debug("%s: mem source, devaddr=%08lx, hwcfg=%d\n",
			 __func__, devaddr, hwcfg);
		dma_wrreg(chan, S3C2410_DMA_DISRCC, (0<<1) | (0<<0));
		dma_wrreg(chan, S3C2410_DMA_DIDST,  devaddr);
		dma_wrreg(chan, S3C2410_DMA_DIDSTC, hwcfg & 3);

		chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DISRC);
		break;

	default:
		printk(KERN_ERR "dma%d: invalid source type (%d)\n",
		       channel, source);

		return -EINVAL;
	}

	if (dma_sel.direction != NULL)
		(dma_sel.direction)(chan, chan->map, source);

	return 0;
}
Example #22
0
int s3c2410_dma_devconfig(int channel,
			  enum s3c2410_dmasrc source,
			  int hwcfg,
			  unsigned long devaddr)
{
	unsigned long tmp;

	struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);

	if (chan == NULL)
		return -EINVAL;

	pr_debug("%s: source=%d, hwcfg=%08x, devaddr=%08lx\n",
		 __FUNCTION__, (int)source, hwcfg, devaddr);

	chan->source = source;
	chan->dev_addr = devaddr;

	switch (source) {
	case S3C2410_DMASRC_MEM:
		/* source is Memory : Mem-to-Peri ( Write into FIFO) */
		tmp = S3C_DMACONFIG_TCMASK | S3C_DMACONFIG_FLOWCTRL_MEM2PER | (chan->map->hw_addr.to) <<
			S3C_DEST_SHIFT | S3C_DMACONFIG_CHANNEL_ENABLE;
		
		chan->config_flags = tmp;

		/* TODO : Now, Scatter&Gather DMA NOT supported */
		dma_wrreg(chan, S3C_DMAC_CxLLI, 0);
		
		/* devaddr : Periperal address (destination) */
		dma_wrreg(chan, S3C_DMAC_CxDESTADDR, devaddr);

		/* source address : memory(buffer) address */
		chan->addr_reg = dma_regaddr(chan, S3C_DMAC_CxSRCADDR);
		
		chan->control_flags = S3C_DMACONTROL_SRC_INC | S3C_DMACONTROL_DEST_AXI_PERI ;
		//chan->control_flags = hwcfg;
		return 0;

	case S3C2410_DMASRC_HW:
		/* source is peripheral : Peri-to-Mem ( Read from FIFO) */
		tmp = S3C_DMACONFIG_TCMASK | S3C_DMACONFIG_FLOWCTRL_PER2MEM | (chan->map->hw_addr.from) <<
			S3C_SRC_SHIFT | S3C_DMACONFIG_CHANNEL_ENABLE;
		
		chan->config_flags = tmp;

		/* TODO : Now, Scatter&Gather DMA NOT supported */
		dma_wrreg(chan, S3C_DMAC_CxLLI, 0);
		
		/* devaddr : Periperal address (source) */
		dma_wrreg(chan, S3C_DMAC_CxSRCADDR, devaddr);

		/* destination address : memory(buffer) address */
		chan->addr_reg = dma_regaddr(chan, S3C_DMAC_CxDESTADDR);
		
		chan->control_flags = S3C_DMACONTROL_DEST_INC | S3C_DMACONTROL_SRC_AXI_PERI;
		//chan->control_flags = hwcfg;
		
		return 0;

	case S3C_DMA_MEM2MEM:
		/* this is temporary for G3D */
		tmp = S3C_DMACONFIG_TCMASK | S3C_DMACONFIG_FLOWCTRL_MEM2MEM | S3C_DMACONFIG_CHANNEL_ENABLE;
		
		chan->config_flags = tmp;

		/* TODO : Now, Scatter&Gather DMA NOT YET supported */
		dma_wrreg(chan, S3C_DMAC_CxLLI, 0);
		
		/* devaddr : memory/onenand address (source) */
		dma_wrreg(chan, S3C_DMAC_CxSRCADDR, devaddr);

		/* destination address : memory(buffer) address */
		chan->addr_reg = dma_regaddr(chan, S3C_DMAC_CxDESTADDR);
	
		chan->control_flags |= (S3C_DMACONTROL_SRC_INC | S3C_DMACONTROL_DEST_AXI_PERI
				| S3C_DMACONTROL_SBSIZE_4 | S3C_DMACONTROL_DBSIZE_4);
		//chan->control_flags = hwcfg;
		
		return 0;

	case S3C_DMA_MEM2MEM_P:
		/* source is memory : Memory-to-Mem ( Read/Write) */
		tmp = S3C_DMACONFIG_TCMASK | S3C_DMACONFIG_FLOWCTRL_MEM2MEM | S3C_DMACONFIG_CHANNEL_ENABLE;

		//if(chan->map->hw_addr.from == S3C_DMA0_ONENAND_RX) {
			//tmp |= S3C_DMACONFIG_ONENANDMODESRC;
		//}
		
		chan->config_flags = tmp;

		/* TODO : Now, Scatter&Gather DMA NOT YET supported */
		dma_wrreg(chan, S3C_DMAC_CxLLI, 0);
		
		/* devaddr : memory/onenand address (source) */
		dma_wrreg(chan, S3C_DMAC_CxSRCADDR, devaddr);

		/* destination address : memory(buffer) address */
		chan->addr_reg = dma_regaddr(chan, S3C_DMAC_CxDESTADDR);
		
		chan->control_flags |= (S3C_DMACONTROL_SRC_INC | S3C_DMACONTROL_DEST_INC 
				| S3C_DMACONTROL_SBSIZE_4 | S3C_DMACONTROL_DBSIZE_4);
		//chan->control_flags = hwcfg;
		
		return 0;

	case S3C_DMA_PER2PER:
		printk("Peripheral-to-Peripheral DMA NOT YET implemented !! \n");
		return -EINVAL;

	default:
		printk(KERN_ERR "DMA CH :%d - invalid source type ()\n", channel);
		printk("Unsupported DMA configuration from the device driver using DMA driver \n");
		return -EINVAL;
	}
	
}
Example #23
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;
}
Example #24
0
void s3c_enable_dmac(unsigned int dcon_num)
{
	s3c_dma_controller_t *dma_controller = &s3c_dma_cntlrs[dcon_num];
	dma_wrreg(dma_controller, S3C_DMAC_CONFIGURATION, S3C_DMA_CONTROLLER_ENABLE);
}
Example #25
0
/* s3c2410_dma_enqueue_sg
 *
 * queue an given buffer for dma transfer.
 *
 * id         the device driver's id information for this buffer
 * data       the physical address of the buffer data
 * size       the size of the buffer in bytes
 * sg_reg     the scatter&gather list
 *
 * If the channel is not running, then the flag S3C2410_DMAF_AUTOSTART
 * is checked, and if set, the channel is started. If this flag isn't set,
 * then an error will be returned.
 *
 * It is possible to queue more than one DMA buffer onto a channel at
 * once, and the code will deal with the re-loading of the next buffer
 * when necessary.
 */
int s3c2410_dma_enqueue_sg(unsigned int channel, void *id,
			dma_addr_t data, int size, struct s3c_sg_list *sg_list)
{
	struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
	struct s3c_dma_buf *buf;
	unsigned long flags;

	pr_debug("%s: id=%p, data=%08x, size=%d\n", __FUNCTION__, id, (unsigned int) data, size);

	buf = kmem_cache_alloc(dma_kmem, GFP_ATOMIC);
	if (buf == NULL) {
		printk(KERN_ERR "dma<%d> no memory for buffer\n", channel);
		return -ENOMEM;
	}

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

	//dbg_showchan(chan);

	buf->next = NULL;
	buf->data = buf->ptr = data;
	buf->size = size;
	buf->id = id;
	buf->magic = BUF_MAGIC;

	local_irq_save(flags);

	if (chan->curr == NULL) {
		/* we've got nothing loaded... */
		pr_debug("%s: buffer %p queued onto empty channel\n", __FUNCTION__, buf);

		chan->curr = buf;
		chan->end = buf;
		chan->next = NULL;
	} else {
		pr_debug("dma%d: %s: buffer %p queued onto non-empty channel\n",
			 chan->number, __FUNCTION__, buf);

		if (chan->end == NULL)   /* In case of flushing */
			pr_debug("dma%d: %s: %p not empty, and chan->end==NULL?\n",
				 chan->number, __FUNCTION__, chan);
		else {
			chan->end->next = buf;
			chan->end = buf;
		}
	}

	/* if necessary, update the next buffer field */
	if (chan->next == NULL)
		chan->next = buf;

	/* check to see if we can load a buffer */
	if (chan->state == S3C_DMA_RUNNING) {
		if (chan->load_state == S3C_DMALOAD_1LOADED && 1) {
			if (s3c_dma_waitforload(chan, __LINE__) == 0) {
				printk(KERN_ERR "dma%d: loadbuffer:"
				       "timeout loading buffer\n", chan->number);
				dbg_showchan(chan);
				local_irq_restore(flags);
				return -EINVAL;
			}
		}
	} else if (chan->state == S3C_DMA_IDLE) {
		dma_wrreg(chan, S3C_DMAC_CxLLI, virt_to_phys(&sg_list));
		
		if (chan->flags & S3C2410_DMAF_AUTOSTART) {
			s3c2410_dma_ctrl(channel, S3C2410_DMAOP_START);
		} else {
			pr_debug("loading onto stopped channel\n");
		}
	}

	local_irq_restore(flags);
	return 0;
}