mirror of https://github.com/thesofproject/sof.git
dw_dma: Split DMA pause and stop command
Data after pause command should be kept compatible to omit pop noise on output. The solution may be waiting for FIFO empty but it takes to long - up to 1 processing period time. Another - introduced - solution is to stop draining new data from buffer after pause, but keeping dma connection with dai up to release command. In this place waiting for FIFO empty shouldn't take so much time, so system agent won't panic and data will be consistent. Signed-off-by: Karol Trzcinski <karolx.trzcinski@linux.intel.com>
This commit is contained in:
parent
ed3919a1b1
commit
6713d90c21
|
@ -620,12 +620,15 @@ static int dai_comp_trigger(struct comp_dev *dev, int cmd)
|
|||
dd->xrun = 1;
|
||||
|
||||
/* fallthrough */
|
||||
case COMP_TRIGGER_PAUSE:
|
||||
case COMP_TRIGGER_STOP:
|
||||
comp_dbg(dev, "dai_comp_trigger(), PAUSE/STOP");
|
||||
comp_dbg(dev, "dai_comp_trigger(), STOP");
|
||||
ret = dma_stop(dd->chan);
|
||||
dai_trigger(dd->dai, cmd, dev->direction);
|
||||
break;
|
||||
case COMP_TRIGGER_PAUSE:
|
||||
comp_dbg(dev, "dai_comp_trigger(), PAUSE");
|
||||
ret = dma_pause(dd->chan);
|
||||
dai_trigger(dd->dai, cmd, dev->direction);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -72,6 +72,8 @@ static const uint32_t burst_elems[] = {1, 2, 4, 8};
|
|||
#define DW_DMA_BUFFER_PERIOD_COUNT 2
|
||||
#endif
|
||||
|
||||
static int dw_dma_stop(struct dma_chan_data *channel);
|
||||
|
||||
static void dw_dma_interrupt_mask(struct dma_chan_data *channel)
|
||||
{
|
||||
/* mask block, transfer and error interrupts for channel */
|
||||
|
@ -266,7 +268,8 @@ static int dw_dma_start(struct dma_chan_data *channel)
|
|||
irq_local_disable(flags);
|
||||
|
||||
/* check if channel idle, disabled and ready */
|
||||
if (channel->status != COMP_STATE_PREPARE ||
|
||||
if ((channel->status != COMP_STATE_PREPARE &&
|
||||
channel->status != COMP_STATE_PAUSED) ||
|
||||
(dma_reg_read(dma, DW_DMA_CHAN_EN) & DW_CHAN(channel->index))) {
|
||||
trace_dwdma_error("dw_dma_start() error: dma %d channel %d "
|
||||
"not ready ena 0x%x status 0x%x",
|
||||
|
@ -334,16 +337,32 @@ out:
|
|||
static int dw_dma_release(struct dma_chan_data *channel)
|
||||
{
|
||||
struct dw_dma_chan_data *dw_chan = dma_chan_get_data(channel);
|
||||
struct dma *dma = channel->dma;
|
||||
uint32_t flags;
|
||||
int ret;
|
||||
|
||||
trace_dwdma("dw_dma_release(): dma %d channel %d release",
|
||||
channel->dma->plat_data.id, channel->index);
|
||||
|
||||
irq_local_disable(flags);
|
||||
|
||||
/* now we wait for FIFO to be empty */
|
||||
ret = poll_for_register_delay(dma_base(dma) +
|
||||
DW_CFG_LOW(channel->index),
|
||||
DW_CFGL_FIFO_EMPTY,
|
||||
DW_CFGL_FIFO_EMPTY,
|
||||
DW_DMA_TIMEOUT);
|
||||
|
||||
/* get next lli for proper release */
|
||||
dw_chan->lli_current = (struct dw_lli *)dw_chan->lli_current->llp;
|
||||
|
||||
/* prepare to start */
|
||||
dw_dma_stop(channel);
|
||||
|
||||
if (ret < 0)
|
||||
trace_dwdma_error("dw_dma_release() error: dma %d channel %d timeout",
|
||||
dma->plat_data.id, channel->index);
|
||||
|
||||
irq_local_enable(flags);
|
||||
|
||||
return 0;
|
||||
|
@ -351,6 +370,8 @@ static int dw_dma_release(struct dma_chan_data *channel)
|
|||
|
||||
static int dw_dma_pause(struct dma_chan_data *channel)
|
||||
{
|
||||
struct dw_dma_chan_data *dw_chan = dma_chan_get_data(channel);
|
||||
struct dma *dma = channel->dma;
|
||||
uint32_t flags;
|
||||
|
||||
trace_dwdma("dw_dma_pause(): dma %d channel %d pause",
|
||||
|
@ -361,6 +382,9 @@ static int dw_dma_pause(struct dma_chan_data *channel)
|
|||
if (channel->status != COMP_STATE_ACTIVE)
|
||||
goto out;
|
||||
|
||||
dma_reg_write(dma, DW_CFG_LOW(channel->index),
|
||||
dw_chan->cfg_lo | DW_CFGL_SUSPEND);
|
||||
|
||||
/* pause the channel */
|
||||
channel->status = COMP_STATE_PAUSED;
|
||||
|
||||
|
@ -392,7 +416,8 @@ static int dw_dma_stop(struct dma_chan_data *channel)
|
|||
|
||||
irq_local_disable(flags);
|
||||
|
||||
if (channel->status != COMP_STATE_ACTIVE)
|
||||
if (channel->status != COMP_STATE_ACTIVE &&
|
||||
channel->status != COMP_STATE_PAUSED)
|
||||
goto out;
|
||||
|
||||
#if CONFIG_DMA_SUSPEND_DRAIN
|
||||
|
|
|
@ -517,8 +517,8 @@ static int hda_dma_pause(struct dma_chan_data *channel)
|
|||
if (channel->status != COMP_STATE_ACTIVE)
|
||||
goto out;
|
||||
|
||||
/* pause the channel */
|
||||
channel->status = COMP_STATE_PAUSED;
|
||||
/* stop the channel */
|
||||
hda_dma_stop(channel);
|
||||
|
||||
out:
|
||||
irq_local_enable(flags);
|
||||
|
|
Loading…
Reference in New Issue