diff --git a/src/drivers/dw-dma.c b/src/drivers/dw-dma.c index fc90f0283160..41b1587fdacb 100644 --- a/src/drivers/dw-dma.c +++ b/src/drivers/dw-dma.c @@ -119,6 +119,7 @@ #define INT_UNMASK_ALL 0xFFFF #define CHAN_ENABLE(chan) (0x101 << chan) #define CHAN_DISABLE(chan) (0x100 << chan) +#define CHAN_MASK(chan) (0x1 << chan) #define DW_CFG_CH_SUSPEND 0x100 #define DW_CFG_CH_FIFO_EMPTY 0x200 @@ -474,6 +475,31 @@ static int dw_dma_pause(struct dma *dma, int channel) return 0; } +#if defined CONFIG_BAYTRAIL || defined CONFIG_CHERRYTRAIL +static int dw_dma_stop(struct dma *dma, int channel) +{ + struct dma_pdata *p = dma_get_drvdata(dma); + int ret = 0; + uint32_t flags; + uint32_t val = 0; + + spin_lock_irq(&dma->lock, flags); + + trace_dma("DDi"); + + ret = poll_for_register_delay(dma_base(dma) + DW_DMA_CHAN_EN, + CHAN_MASK(channel), val, + PLATFORM_DMA_TIMEOUT); + if (ret < 0) + trace_dma_error("esp"); + + dw_write(dma, DW_CLEAR_BLOCK, 0x1 << channel); + p->chan[channel].status = COMP_STATE_PREPARE; + + spin_unlock_irq(&dma->lock, flags); + return ret; +} +#else static int dw_dma_stop(struct dma *dma, int channel) { struct dma_pdata *p = dma_get_drvdata(dma); @@ -508,6 +534,7 @@ static int dw_dma_stop(struct dma *dma, int channel) spin_unlock_irq(&dma->lock, flags); return ret; } +#endif /* fill in "status" with current DMA channel state and position */ static int dw_dma_status(struct dma *dma, int channel, diff --git a/src/include/sof/wait.h b/src/include/sof/wait.h index b07302e76286..b075e38bea60 100644 --- a/src/include/sof/wait.h +++ b/src/include/sof/wait.h @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -185,4 +186,27 @@ static inline int poll_for_completion_delay(completion_t *comp, uint64_t us) return 0; } +static inline int poll_for_register_delay(uint32_t reg, + uint32_t mask, + uint32_t val, uint64_t us) +{ + uint64_t tick = clock_us_to_ticks(CLK_CPU, us); + uint32_t tries = DEFAULT_TRY_TIMES; + uint64_t delta = tick / tries; + + if (!delta) { + delta = us; + tries = 1; + } + + while ((io_reg_read(reg) & mask) != val) { + if (!tries--) { + trace_error(TRACE_CLASS_WAIT, "ewt"); + return -EIO; + } + wait_delay(delta); + } + return 0; +} + #endif