static void xdma_start_transfer(struct xdma_chan *chan, int start_index, int end_index) { dma_addr_t cur_phys; dma_addr_t tail_phys; u32 regval; if (chan->err) return; cur_phys = chan->bd_phys_addr + (start_index * sizeof(struct xdma_desc_hw)); tail_phys = chan->bd_phys_addr + (end_index * sizeof(struct xdma_desc_hw)); /* If hardware is busy, move the tail & return */ if (dma_is_running(chan) || dma_is_idle(chan)) { /* Update tail ptr register and start the transfer */ DMA_OUT(&chan->regs->tdr, tail_phys); return; } DMA_OUT(&chan->regs->cdr, cur_phys); dma_start(chan); /* Enable interrupts */ regval = DMA_IN(&chan->regs->cr); regval |= (chan->poll_mode ? XDMA_XR_IRQ_ERROR_MASK : XDMA_XR_IRQ_ALL_MASK); DMA_OUT(&chan->regs->cr, regval); /* Update tail ptr register and start the transfer */ DMA_OUT(&chan->regs->tdr, tail_phys); }
static irqreturn_t xdma_tx_intr_handler(int irq, void *data) { struct xdma_chan *chan = data; u32 stat; stat = DMA_IN(&chan->regs->sr); if (!(stat & XDMA_XR_IRQ_ALL_MASK)) { return IRQ_NONE; } /* Ack the interrupts */ DMA_OUT(&chan->regs->sr, (stat & XDMA_XR_IRQ_ALL_MASK)); if (stat & XDMA_XR_IRQ_ERROR_MASK) { dev_err(chan->dev, "Channel %s has errors %x, cdr %x tdr %x\n", chan->name, (unsigned int)stat, (unsigned int)DMA_IN(&chan->regs->cdr), (unsigned int)DMA_IN(&chan->regs->tdr)); dump_cur_bd(chan); chan->err = 1; tasklet_schedule(&chan->dma_err_tasklet); } if (!(chan->poll_mode) && ((stat & XDMA_XR_IRQ_DELAY_MASK) || (stat & XDMA_XR_IRQ_IOC_MASK))) tasklet_schedule(&chan->tasklet); return IRQ_HANDLED; }
/* send some data out a dma channel */ int ap_dma_go(unsigned long ch,unsigned int p,int size,unsigned long cmd) { int rest; p = mmu_v2p(p); cmd |= DMA_DCMD_ST | DMA_DCMD_TYP_AUTO; #if 0 if (ap_dma_wait(ch)) { printk("WARNING: dma started when not complete\n"); } if (cmd == DMA_DCMD_TD_MD && !(BIF_IN(BIF_SDCSR) & BIF_SDCSR_BG)) { ap_led(0xAA); printk("attempt to dma without holding the bus\n"); return -1; } #endif /* reset the dma system */ DMA_OUT(ch + DMA_DMST,DMA_DMST_RST); if (size <= DMA_MAX_TRANS_SIZE) { DMA_OUT(ch + DMA_MADDR,(unsigned long)p); DMA_OUT(ch + DMA_HSKIP,1); DMA_OUT(ch + DMA_VSKIP,1); DMA_OUT(ch + DMA_DCMD,cmd | B2W(size)); return 0; } if (size <= DMA_MAX_TRANS_SIZE2) { if(size & 0x3) size += 4; rest = (size & (DMA_TRANS_BLOCK_SIZE - 1)) >> 2; if (rest) { DMA_OUT(ch + DMA_HDRP,(unsigned)p); p += rest << 2; } DMA_OUT(ch + DMA_MADDR,(unsigned)p); DMA_OUT(ch + DMA_HSKIP,size >> (2 + 6)); DMA_OUT(ch + DMA_VSKIP,1); DMA_OUT(ch + DMA_DCMD,cmd | (rest << 16) | 64); return 0; } printk("AP1000 DMA operation too big (%d bytes) - aborting\n",size); return(-1); }
static int dma_init(struct xdma_chan *chan) { int loop = XDMA_RESET_LOOP; DMA_OUT(&chan->regs->cr, (DMA_IN(&chan->regs->cr) | XDMA_CR_RESET_MASK)); /* Wait for the hardware to finish reset */ while (loop) { if (!(DMA_IN(&chan->regs->cr) & XDMA_CR_RESET_MASK)) break; loop -= 1; } if (!loop) return 1; return 0; }
static void dma_start(struct xdma_chan *chan) { DMA_OUT(&chan->regs->cr, (DMA_IN(&chan->regs->cr) | XDMA_CR_RUNSTOP_MASK)); }