From b9fb774c1806878509adc726d5b275c684821fd9 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Mon, 17 Sep 2018 17:22:45 +0800 Subject: [PATCH 1/2] wait: add a function to wait for a register ready by pulling method The register status is checked by polling its value in request time Signed-off-by: Rander Wang --- src/include/sof/wait.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) 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 From fbb001b90350a2af54104ae5c430518787cc4af5 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Mon, 10 Sep 2018 14:34:37 +0800 Subject: [PATCH 2/2] dma: fix dma issue on BYT It is caused by the change of removing dai waiting after stop. dma should not be stopped in dai_comp_trigger if HW LLI is not enable. At this time DMA is still working and it can't be stopped DMA engine would stop the channel automatically after each transfer. So just query channel status to stop dma on BYT Signed-off-by: Pan Xiuli Signed-off-by: Rander Wang --- src/drivers/dw-dma.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) 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,