For Intel iDMA 32-bit the channel can be drained on a suspend. We need to reset the bit on the resume to return a status quo. Signed-off-by: Andy Shevchenko <andriy.shevchenko@xxxxxxxxxxxxxxx> --- drivers/dma/dw/core.c | 10 +++++----- drivers/dma/dw/dw.c | 8 ++++++++ drivers/dma/dw/idma32.c | 13 +++++++++++-- drivers/dma/dw/regs.h | 1 + 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c index 711f4d19bbf1..092d642bec83 100644 --- a/drivers/dma/dw/core.c +++ b/drivers/dma/dw/core.c @@ -846,11 +846,11 @@ static int dwc_pause(struct dma_chan *chan) return 0; } -static inline void dwc_chan_resume(struct dw_dma_chan *dwc) +static inline void dwc_chan_resume(struct dw_dma_chan *dwc, bool drain) { - u32 cfglo = channel_readl(dwc, CFG_LO); + struct dw_dma *dw = to_dw_dma(dwc->chan.device); - channel_writel(dwc, CFG_LO, cfglo & ~DWC_CFGL_CH_SUSP); + dw->resume_chan(dwc, drain); clear_bit(DW_DMA_IS_PAUSED, &dwc->flags); } @@ -863,7 +863,7 @@ static int dwc_resume(struct dma_chan *chan) spin_lock_irqsave(&dwc->lock, flags); if (test_bit(DW_DMA_IS_PAUSED, &dwc->flags)) - dwc_chan_resume(dwc); + dwc_chan_resume(dwc, false); spin_unlock_irqrestore(&dwc->lock, flags); @@ -886,7 +886,7 @@ static int dwc_terminate_all(struct dma_chan *chan) dwc_chan_disable(dw, dwc); - dwc_chan_resume(dwc); + dwc_chan_resume(dwc, true); /* active_list entries will end up before queued entries */ list_splice_init(&dwc->queue, &list); diff --git a/drivers/dma/dw/dw.c b/drivers/dma/dw/dw.c index 998a9eeb561d..92f1e9c7b6f6 100644 --- a/drivers/dma/dw/dw.c +++ b/drivers/dma/dw/dw.c @@ -32,6 +32,13 @@ static void dw_dma_suspend_chan(struct dw_dma_chan *dwc, bool drain) channel_writel(dwc, CFG_LO, cfglo | DWC_CFGL_CH_SUSP); } +static void dw_dma_resume_chan(struct dw_dma_chan *dwc, bool drain) +{ + u32 cfglo = channel_readl(dwc, CFG_LO); + + channel_writel(dwc, CFG_LO, cfglo & ~DWC_CFGL_CH_SUSP); +} + static u32 dw_dma_bytes2block(struct dw_dma_chan *dwc, size_t bytes, unsigned int width, size_t *len) { @@ -88,6 +95,7 @@ int dw_dma_probe(struct dw_dma_chip *chip) /* Channel operations */ dw->initialize_chan = dw_dma_initialize_chan; dw->suspend_chan = dw_dma_suspend_chan; + dw->resume_chan = dw_dma_resume_chan; dw->encode_maxburst = dw_dma_encode_maxburst; dw->bytes2block = dw_dma_bytes2block; dw->block2bytes = dw_dma_block2bytes; diff --git a/drivers/dma/dw/idma32.c b/drivers/dma/dw/idma32.c index d06fb00fb862..7c013b257802 100644 --- a/drivers/dma/dw/idma32.c +++ b/drivers/dma/dw/idma32.c @@ -33,12 +33,20 @@ static void idma32_suspend_chan(struct dw_dma_chan *dwc, bool drain) if (drain) cfglo |= IDMA32C_CFGL_CH_DRAIN; - else - cfglo &= ~IDMA32C_CFGL_CH_DRAIN; channel_writel(dwc, CFG_LO, cfglo | DWC_CFGL_CH_SUSP); } +static void idma32_resume_chan(struct dw_dma_chan *dwc, bool drain) +{ + u32 cfglo = channel_readl(dwc, CFG_LO); + + if (drain) + cfglo &= ~IDMA32C_CFGL_CH_DRAIN; + + channel_writel(dwc, CFG_LO, cfglo & ~DWC_CFGL_CH_SUSP); +} + static u32 idma32_bytes2block(struct dw_dma_chan *dwc, size_t bytes, unsigned int width, size_t *len) { @@ -116,6 +124,7 @@ int idma32_dma_probe(struct dw_dma_chip *chip) /* Channel operations */ dw->initialize_chan = idma32_initialize_chan; dw->suspend_chan = idma32_suspend_chan; + dw->resume_chan = idma32_resume_chan; dw->encode_maxburst = idma32_encode_maxburst; dw->bytes2block = idma32_bytes2block; dw->block2bytes = idma32_block2bytes; diff --git a/drivers/dma/dw/regs.h b/drivers/dma/dw/regs.h index 90e46e69c047..bd26c492507b 100644 --- a/drivers/dma/dw/regs.h +++ b/drivers/dma/dw/regs.h @@ -311,6 +311,7 @@ struct dw_dma { /* Channel operations */ void (*initialize_chan)(struct dw_dma_chan *dwc); void (*suspend_chan)(struct dw_dma_chan *dwc, bool drain); + void (*resume_chan)(struct dw_dma_chan *dwc, bool drain); void (*encode_maxburst)(struct dw_dma_chan *dwc, u32 *maxburst); u32 (*bytes2block)(struct dw_dma_chan *dwc, size_t bytes, unsigned int width, size_t *len); -- 2.19.2