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; }
static void dump_cur_bd(struct xdma_chan *chan) { u32 index; index = (((u32)DMA_IN(&chan->regs->cdr)) - chan->bd_phys_addr) / sizeof(struct xdma_desc_hw); dev_err(chan->dev, "cur bd @ %08x\n", (u32)DMA_IN(&chan->regs->cdr)); dev_err(chan->dev, " buf = 0x%08x\n", chan->bds[index]->src_addr); dev_err(chan->dev, " ctrl = 0x%08x\n", chan->bds[index]->control); dev_err(chan->dev, " sts = 0x%08x\n", chan->bds[index]->status); dev_err(chan->dev, " next = 0x%08x\n", chan->bds[index]->next_desc); }
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 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)); }
static int dma_is_idle(struct xdma_chan *chan) { return DMA_IN(&chan->regs->sr) & XDMA_SR_IDLE_MASK; }
static int dma_is_running(struct xdma_chan *chan) { return !(DMA_IN(&chan->regs->sr) & XDMA_SR_HALTED_MASK) && (DMA_IN(&chan->regs->cr) & XDMA_CR_RUNSTOP_MASK); }
int ap_dma_wait(int ch) { int i = 0; while (DMA_IN(ch+DMA_DMST) & DMA_DMST_AC) i++; return i; }