Esempio n. 1
0
static int imapx200_dma_stop(struct imapx200_dma_chan *chan)
{
    struct imapx200_dmac *dmac= chan->dmac;
    u32 config;
    int timeout;

    pr_debug("%s: stopping channel\n", __func__);

    config = chan_readl(chan,CFG_LO);
    config |= DWC_CFGL_CH_SUSP;
    chan_writel(chan,CFG_LO,config);

    timeout = 1000;
    do {
        config = chan_readl(chan,CFG_LO);
        pr_debug("%s: %d - config %08x\n", __func__, timeout, config);
        if (config & DWC_CFGL_CH_SUSP)
            udelay(10);
        else
            break;
    } while (--timeout > 0);

    if (config & DWC_CFGL_CH_SUSP) {
        printk(KERN_ERR "%s: channel still active\n", __func__);
        return -EFAULT;
    }

    dma_clear_bit(dmac,CH_EN,chan->bit);
    return 0;
}
Esempio n. 2
0
static void dbg_showchan(struct imapx200_dma_chan *chan)
{

    pr_debug("DMA%d: %08x->%08x L %08x CTL_L0 %08x, CTL_H0%08x \n",
             chan->number,
             chan_readl(chan,SAR),
             chan_readl(chan,DAR),
             chan_readl(chan,LLP),
             chan_readl(chan,CTL_LO),
             chan_readl(chan,CTL_HI)
            );
}
Esempio n. 3
0
static inline void dma_chan_irq(struct hsu_dma_chan *chan)
{
	struct uart_hsu_port *up = chan->uport;
	unsigned long flags;
	u32 int_sts;

	spin_lock_irqsave(&up->port.lock, flags);

	if (!up->use_dma || !up->running)
		goto exit;

	/*
	 * No matter what situation, need read clear the IRQ status
	 * There is a bug, see Errata 5, HSD 2900918
	 */
	int_sts = chan_readl(chan, HSU_CH_SR);

	/* Rx channel */
	if (chan->dirt == DMA_FROM_DEVICE)
		hsu_dma_rx(up, int_sts);

	/* Tx channel */
	if (chan->dirt == DMA_TO_DEVICE) {
		chan_writel(chan, HSU_CH_CR, 0x0);
		up->dma_tx_on = 0;
		hsu_dma_tx(up);
	}

exit:
	spin_unlock_irqrestore(&up->port.lock, flags);
	return;
}
Esempio n. 4
0
/* This is always called in spinlock protected mode, so
 * modify timeout timer is safe here */
void hsu_dma_rx(struct uart_hsu_port *up, u32 int_sts)
{
	struct hsu_dma_buffer *dbuf = &up->rxbuf;
	struct hsu_dma_chan *chan = up->rxc;
	struct uart_port *port = &up->port;
	struct tty_struct *tty = port->state->port.tty;
	int count;

	if (!tty)
		return;

	/*
	 * First need to know how many is already transferred,
	 * then check if its a timeout DMA irq, and return
	 * the trail bytes out, push them up and reenable the
	 * channel
	 */

	/* Timeout IRQ, need wait some time, see Errata 2 */
	if (int_sts & 0xf00)
		udelay(2);

	/* Stop the channel */
	chan_writel(chan, HSU_CH_CR, 0x0);

	count = chan_readl(chan, HSU_CH_D0SAR) - dbuf->dma_addr;
	if (!count) {
		/* Restart the channel before we leave */
		chan_writel(chan, HSU_CH_CR, 0x3);
		return;
	}

	dma_sync_single_for_cpu(port->dev, dbuf->dma_addr,
			dbuf->dma_size, DMA_FROM_DEVICE);

	/*
	 * Head will only wrap around when we recycle
	 * the DMA buffer, and when that happens, we
	 * explicitly set tail to 0. So head will
	 * always be greater than tail.
	 */
	tty_insert_flip_string(tty, dbuf->buf, count);
	port->icount.rx += count;

	dma_sync_single_for_device(up->port.dev, dbuf->dma_addr,
			dbuf->dma_size, DMA_FROM_DEVICE);

	/* Reprogram the channel */
	chan_writel(chan, HSU_CH_D0SAR, dbuf->dma_addr);
	chan_writel(chan, HSU_CH_D0TSR, dbuf->dma_size);
	chan_writel(chan, HSU_CH_DCR, 0x1
					 | (0x1 << 8)
					 | (0x1 << 16)
					 | (0x1 << 24)	/* timeout bit, see HSU Errata 1 */
					 );
	tty_flip_buffer_push(tty);

	chan_writel(chan, HSU_CH_CR, 0x3);

}
Esempio n. 5
0
int imapx200_dma_getposition(unsigned int channel,
                             dma_addr_t *src, dma_addr_t *dst)
{
    struct imapx200_dma_chan *chan = imap_dma_lookup_channel(channel);

    WARN_ON(!chan);
    if (!chan)
        return -EINVAL;

    if (src != NULL)
        *src = chan_readl(chan,SAR);

    if (dst != NULL)
        *dst = chan_readl(chan,DAR);

    return 0;
}
Esempio n. 6
0
static void hsu_dma_rx_timeout(unsigned long data)
{
	struct hsu_dma_chan *chan = (void *)data;
	struct uart_hsu_port *up = chan->uport;
	struct hsu_dma_buffer *dbuf = &up->rxbuf;
	int count = 0;
	unsigned long flags;

	spin_lock_irqsave(&up->port.lock, flags);

	count = chan_readl(chan, HSU_CH_D0SAR) - dbuf->dma_addr;

	if (!count) {
		mod_timer(&chan->rx_timer, jiffies + HSU_DMA_TIMEOUT_CHECK_FREQ);
		goto exit;
	}

	hsu_dma_rx(up, 0);
exit:
	spin_unlock_irqrestore(&up->port.lock, flags);
}
Esempio n. 7
0
static void imapx200_dma_fill_lli(struct imapx200_dma_chan *chan,
                                  struct dw_lli *lli,
                                  dma_addr_t data, int size)
{
    dma_addr_t src, dst;
    u32 control0, control1;

    control0 = chan_readl(chan,CTL_LO);

    switch (chan->source) {
    case IMAPX200_DMA_P2M:
        src = chan->dev_addr;
        dst = data;
        control0 |= DWC_CTLL_DST_WIDTH(chan->hw_width);
        control0 |= DWC_CTLL_SRC_WIDTH(2);
        control0 |= DWC_CTLL_DST_INC;
        break;

    case IMAPX200_DMA_M2P:
        src = data;
        dst = chan->dev_addr;
        control0 |= DWC_CTLL_DST_WIDTH(2);
        control0 |= DWC_CTLL_SRC_WIDTH(chan->hw_width);
        control0 |= DWC_CTLL_SRC_INC;
        break;
    default:
        BUG();
    }

    /* note, we do not currently setup any of the burst controls */

    control1 = size >> chan->hw_width;	/* size in no of xfers */

    lli->sar = src;
    lli->dar = dst;
    lli->llp = 0;
    lli->ctllo = control0;
    lli->ctlhi = control1;
}
Esempio n. 8
0
static ssize_t dma_show_regs(struct file *file, char __user *user_buf,
				size_t count, loff_t *ppos)
{
	struct hsu_dma_chan *chan = file->private_data;
	char *buf;
	u32 len = 0;
	ssize_t ret;

	buf = kzalloc(HSU_REGS_BUFSIZE, GFP_KERNEL);
	if (!buf)
		return 0;

	len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
			"MFD HSU DMA channel [%d] regs:\n", chan->id);

	len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
			"=================================\n");
	len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
			"CR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_CR));
	len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
			"DCR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_DCR));
	len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
			"BSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_BSR));
	len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
			"MOTSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_MOTSR));
	len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
			"D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D0SAR));
	len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
			"D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D0TSR));
	len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
			"D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D1SAR));
	len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
			"D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D1TSR));
	len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
			"D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D2SAR));
	len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
			"D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D2TSR));
	len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
			"D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D3SAR));
	len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
			"D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D3TSR));

	if (len > HSU_REGS_BUFSIZE)
		len = HSU_REGS_BUFSIZE;

	ret =  simple_read_from_buffer(user_buf, count, ppos, buf, len);
	kfree(buf);
	return ret;
}
Esempio n. 9
0
int imapx200_dma_devconfig(int channel,
                           enum imapx200_dmafc source,
                           unsigned long devaddr)
{
    struct imapx200_dma_chan *chan = imap_dma_lookup_channel(channel);
    u32 peripheral;
    u32 ctlx = 0;
    u32 intrx = 0;
    u32 cfg_hi = 0;
    u32 cfg_lo = 0;

    pr_debug("%s: channel %d, source %d, dev %08lx, chan %p\n",
             __func__, channel, source, devaddr, chan);

    WARN_ON(!chan);
    if (!chan)
        return -EINVAL;

    peripheral = (chan->peripheral & 0x7);
    chan->source = source;
    chan->dev_addr = devaddr;

    pr_debug("%s: peripheral %d\n", __func__, peripheral);
    ctlx = chan_readl(chan,CTL_LO);
    pr_debug("devconfig_1\n");
    ctlx &= ~DWC_CTLL_FC_MASK;
    cfg_hi = chan_readl(chan,CFG_HI);
    pr_debug("CFG_HI is %x\n", cfg_hi);
    cfg_lo = chan_readl(chan,CFG_LO);
    pr_debug("devconfig_3\n");
    switch (source) {
    case IMAPX200_DMA_M2M:
        ctlx |= DWC_CTLL_FC_M2M;
        break;
    case IMAPX200_DMA_M2P:
        ctlx |= DWC_CTLL_FC_M2P;
        cfg_lo &= ~DWC_CFGL_HS_DST;
        cfg_hi |= DWC_CFGH_DST_PER(chan->client->handshake);
        break;
    case IMAPX200_DMA_P2M:
        ctlx |= DWC_CTLL_FC_P2M;
        cfg_lo &= ~DWC_CFGL_HS_SRC;
        cfg_hi |= DWC_CFGH_SRC_PER(chan->client->handshake);
        break;
    default:
        printk(KERN_ERR "%s: bad source\n", __func__);
        return -EINVAL;
    }
    /*set dma flow control bit*/
    chan_writel(chan,CTL_LO,ctlx);
    pr_debug("devconfig_4\n");
    chan_writel(chan,CFG_LO,cfg_lo);
    pr_debug("devconfig_5\n");
    chan_writel(chan,CFG_HI,cfg_hi);
//	cfg_hi = chan_readl(chan,CFG_HI);
//	pr_debug("CFG_HI is %x\n", cfg_hi);
    /* allow TC and ERR interrupts */
    intrx = 1<<(chan->number);
    pr_debug("devconfig_6\n");
    dma_set_bit(chan->dmac,MASK.XFER,intrx);
    pr_debug("devconfig_7\n");
    dma_set_bit(chan->dmac,MASK.BLOCK,intrx);
    dma_set_bit(chan->dmac,MASK.ERROR,intrx);

    pr_debug("devconfig_8\n");
    return 0;
}