]> git.karo-electronics.de Git - linux-beck.git/commitdiff
dmaengine/dw_dmac: Reconfigure interrupt and chan_cfg register on resume
authorViresh Kumar <viresh.kumar@st.com>
Thu, 17 Nov 2011 10:31:29 +0000 (16:01 +0530)
committerVinod Koul <vinod.koul@linux.intel.com>
Mon, 28 Nov 2011 03:18:02 +0000 (08:48 +0530)
In S2R all DMA registers are reset by hardware and thus they are required to be
reprogrammed. The channels which aren't reprogrammed are channel configuration
and interrupt enable registers, which are currently programmed at chan_alloc
time.

This patch creates another routine to initialize a channel. It will try to
initialize channel on every dwc_dostart() call. If channel is already
initialised then it simply returns, otherwise it configures registers.

This routine will also initialize registers on wakeup from S2R, as we mark
channels as uninitialized on suspend.

Signed-off-by: Viresh Kumar <viresh.kumar@st.com>
Signed-off-by: Vinod Koul <vinod.koul@linux.intel.com>
drivers/dma/dw_dmac.c
drivers/dma/dw_dmac_regs.h

index decca1c3c83d728156f2d8de70a6329bcc09b441..9b592b02b5f49a3023cdc883322af7c451448a0a 100644 (file)
@@ -166,6 +166,38 @@ dwc_assign_cookie(struct dw_dma_chan *dwc, struct dw_desc *desc)
        return cookie;
 }
 
+static void dwc_initialize(struct dw_dma_chan *dwc)
+{
+       struct dw_dma *dw = to_dw_dma(dwc->chan.device);
+       struct dw_dma_slave *dws = dwc->chan.private;
+       u32 cfghi = DWC_CFGH_FIFO_MODE;
+       u32 cfglo = DWC_CFGL_CH_PRIOR(dwc->priority);
+
+       if (dwc->initialized == true)
+               return;
+
+       if (dws) {
+               /*
+                * We need controller-specific data to set up slave
+                * transfers.
+                */
+               BUG_ON(!dws->dma_dev || dws->dma_dev != dw->dma.dev);
+
+               cfghi = dws->cfg_hi;
+               cfglo |= dws->cfg_lo & ~DWC_CFGL_CH_PRIOR_MASK;
+       }
+
+       channel_writel(dwc, CFG_LO, cfglo);
+       channel_writel(dwc, CFG_HI, cfghi);
+
+       /* Enable interrupts */
+       channel_set_bit(dw, MASK.XFER, dwc->mask);
+       channel_set_bit(dw, MASK.BLOCK, dwc->mask);
+       channel_set_bit(dw, MASK.ERROR, dwc->mask);
+
+       dwc->initialized = true;
+}
+
 /*----------------------------------------------------------------------*/
 
 /* Called with dwc->lock held and bh disabled */
@@ -189,6 +221,8 @@ static void dwc_dostart(struct dw_dma_chan *dwc, struct dw_desc *first)
                return;
        }
 
+       dwc_initialize(dwc);
+
        channel_writel(dwc, LLP, first->txd.phys);
        channel_writel(dwc, CTL_LO,
                        DWC_CTLL_LLP_D_EN | DWC_CTLL_LLP_S_EN);
@@ -959,10 +993,7 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan)
        struct dw_dma_chan      *dwc = to_dw_dma_chan(chan);
        struct dw_dma           *dw = to_dw_dma(chan->device);
        struct dw_desc          *desc;
-       struct dw_dma_slave     *dws;
        int                     i;
-       u32                     cfghi;
-       u32                     cfglo;
        unsigned long           flags;
 
        dev_vdbg(chan2dev(chan), "alloc_chan_resources\n");
@@ -975,26 +1006,6 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan)
 
        dwc->completed = chan->cookie = 1;
 
-       cfghi = DWC_CFGH_FIFO_MODE;
-       cfglo = 0;
-
-       dws = chan->private;
-       if (dws) {
-               /*
-                * We need controller-specific data to set up slave
-                * transfers.
-                */
-               BUG_ON(!dws->dma_dev || dws->dma_dev != dw->dma.dev);
-
-               cfghi = dws->cfg_hi;
-               cfglo = dws->cfg_lo & ~DWC_CFGL_CH_PRIOR_MASK;
-       }
-
-       cfglo |= DWC_CFGL_CH_PRIOR(dwc->priority);
-
-       channel_writel(dwc, CFG_LO, cfglo);
-       channel_writel(dwc, CFG_HI, cfghi);
-
        /*
         * NOTE: some controllers may have additional features that we
         * need to initialize here, like "scatter-gather" (which
@@ -1026,11 +1037,6 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan)
                i = ++dwc->descs_allocated;
        }
 
-       /* Enable interrupts */
-       channel_set_bit(dw, MASK.XFER, dwc->mask);
-       channel_set_bit(dw, MASK.BLOCK, dwc->mask);
-       channel_set_bit(dw, MASK.ERROR, dwc->mask);
-
        spin_unlock_irqrestore(&dwc->lock, flags);
 
        dev_dbg(chan2dev(chan),
@@ -1058,6 +1064,7 @@ static void dwc_free_chan_resources(struct dma_chan *chan)
        spin_lock_irqsave(&dwc->lock, flags);
        list_splice_init(&dwc->free_list, &list);
        dwc->descs_allocated = 0;
+       dwc->initialized = false;
 
        /* Disable interrupts */
        channel_clear_bit(dw, MASK.XFER, dwc->mask);
@@ -1335,6 +1342,8 @@ EXPORT_SYMBOL(dw_dma_cyclic_free);
 
 static void dw_dma_off(struct dw_dma *dw)
 {
+       int i;
+
        dma_writel(dw, CFG, 0);
 
        channel_clear_bit(dw, MASK.XFER, dw->all_chan_mask);
@@ -1345,6 +1354,9 @@ static void dw_dma_off(struct dw_dma *dw)
 
        while (dma_readl(dw, CFG) & DW_CFG_DMA_EN)
                cpu_relax();
+
+       for (i = 0; i < dw->dma.chancnt; i++)
+               dw->chan[i].initialized = false;
 }
 
 static int __init dw_probe(struct platform_device *pdev)
@@ -1533,6 +1545,7 @@ static int dw_suspend_noirq(struct device *dev)
 
        dw_dma_off(platform_get_drvdata(pdev));
        clk_disable(dw->clk);
+
        return 0;
 }
 
index c3419518d701dbe3a0671cbc906a88c7ee3823a3..5eef6946a36713bd7413ecd29c1751291c4cc41c 100644 (file)
@@ -140,6 +140,7 @@ struct dw_dma_chan {
        u8                      mask;
        u8                      priority;
        bool                    paused;
+       bool                    initialized;
 
        spinlock_t              lock;