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