Skip to content

Commit

Permalink
dmaengine/dw_dmac: Reconfigure interrupt and chan_cfg register on resume
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Viresh Kumar authored and Vinod Koul committed Nov 28, 2011
1 parent e696643 commit 61e183f
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 28 deletions.
69 changes: 41 additions & 28 deletions drivers/dma/dw_dmac.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand All @@ -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);
Expand Down Expand Up @@ -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");
Expand All @@ -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
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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)
Expand Down Expand Up @@ -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;
}

Expand Down
1 change: 1 addition & 0 deletions drivers/dma/dw_dmac_regs.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ struct dw_dma_chan {
u8 mask;
u8 priority;
bool paused;
bool initialized;

spinlock_t lock;

Expand Down

0 comments on commit 61e183f

Please sign in to comment.