Beispiel #1
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;
}
Beispiel #2
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;
}
/* 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 CH %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;
	}

	start_DMA_channel(dma_regaddr(chan->dma_con, S3C_DMAC_DBGSTATUS), chan->number,
					chan->curr->mcptr, PL330_NON_SECURE_DMA);

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

	dbg_showchan(chan);

	local_irq_restore(flags);
	return 0;
}
static int s3c_dma_dostop(struct s3c2410_dma_chan *chan)
{
	unsigned long flags;

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

	dbg_showchan(chan);

	local_irq_save(flags);

	s3c_dma_call_op(chan, S3C2410_DMAOP_STOP);

	stop_DMA_channel(dma_regaddr(chan->dma_con, S3C_DMAC_DBGSTATUS), chan->number);

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

	local_irq_restore(flags);

	return 0;
}
Beispiel #5
0
static inline void
dma_wrreg(struct s3c2410_dma_chan *chan, int reg, unsigned long val)
{
    pr_debug("writing %08x to register %08x\n",(unsigned int)val,reg);
    writel(val, dma_regaddr(chan, reg));
}
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_INTSTATUS);
	pr_debug("# s3c_dma_irq: IRQ 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("# DMAC %d: requestor %d\n", dcon_num, i);

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

			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 CH %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 {
			}

			/* 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... */

			if (chan->next != NULL && chan->state != S3C_DMA_IDLE) {
				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 CH %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 CH %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);
				start_DMA_channel(dma_regaddr(chan->dma_con, S3C_DMAC_DBGSTATUS), chan->number,
								chan->curr->mcptr, PL330_NON_SECURE_DMA);

				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;
}
void s3c_disable_dmac(unsigned int dcon_num)
{
	s3c_dma_controller_t *dma_controller = &s3c_dma_cntlrs[dcon_num];

	stop_DMA_controller(dma_regaddr(dma_controller, S3C_DMAC_DBGSTATUS));
}
Beispiel #8
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;
	}
	
}
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;
}