mirror of https://github.com/thesofproject/sof.git
dai: correct the order for DAI and DMA start/stop
To stop/suspend an active DMA channel: 1. Stop the DMA service request at the peripheral first (stop the DAI); 2. Disable the hardware service request on the appropriate DMA channel. For start/resume: 1. Enable the DMA service request on the appropriate channel; 2. Enable the DMA service request at the peripheral (enable DAI). When the start/stop order for DMA and DAI is different, on multiple start/stop runs for playback or record or combined, we get an underrun/overflow. That's because the DAI makes a DMA request, before the DMA channel is enabled. Some platforms cannot just simple disable DMA channel during the transfer, because it will hang the whole DMA controller. Therefore, for DMA_SUSPEND_DRAIN, stop the DMA first and let the DAI drain the FIFO in order to stop the channel as soon as possible. Fixes: #3809 Signed-off-by: Iuliana Prodan <iuliana.prodan@nxp.com>
This commit is contained in:
parent
fa35ee00f2
commit
1fa1001e24
|
@ -651,11 +651,11 @@ static int dai_comp_trigger_internal(struct comp_dev *dev, int cmd)
|
||||||
|
|
||||||
/* only start the DAI if we are not XRUN handling */
|
/* only start the DAI if we are not XRUN handling */
|
||||||
if (dd->xrun == 0) {
|
if (dd->xrun == 0) {
|
||||||
/* start the DAI */
|
|
||||||
dai_trigger(dd->dai, cmd, dev->direction);
|
|
||||||
ret = dma_start(dd->chan);
|
ret = dma_start(dd->chan);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
/* start the DAI */
|
||||||
|
dai_trigger(dd->dai, cmd, dev->direction);
|
||||||
} else {
|
} else {
|
||||||
dd->xrun = 0;
|
dd->xrun = 0;
|
||||||
}
|
}
|
||||||
|
@ -695,8 +695,21 @@ static int dai_comp_trigger_internal(struct comp_dev *dev, int cmd)
|
||||||
COMPILER_FALLTHROUGH;
|
COMPILER_FALLTHROUGH;
|
||||||
case COMP_TRIGGER_STOP:
|
case COMP_TRIGGER_STOP:
|
||||||
comp_dbg(dev, "dai_comp_trigger_internal(), STOP");
|
comp_dbg(dev, "dai_comp_trigger_internal(), STOP");
|
||||||
|
/*
|
||||||
|
* Some platforms cannot just simple disable
|
||||||
|
* DMA channel during the transfer,
|
||||||
|
* because it will hang the whole DMA controller.
|
||||||
|
* Therefore, stop the DMA first and let the DAI
|
||||||
|
* drain the FIFO in order to stop the channel
|
||||||
|
* as soon as possible.
|
||||||
|
*/
|
||||||
|
#if CONFIG_DMA_SUSPEND_DRAIN
|
||||||
ret = dma_stop(dd->chan);
|
ret = dma_stop(dd->chan);
|
||||||
dai_trigger(dd->dai, cmd, dev->direction);
|
dai_trigger(dd->dai, cmd, dev->direction);
|
||||||
|
#else
|
||||||
|
dai_trigger(dd->dai, cmd, dev->direction);
|
||||||
|
ret = dma_stop(dd->chan);
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
case COMP_TRIGGER_PAUSE:
|
case COMP_TRIGGER_PAUSE:
|
||||||
comp_dbg(dev, "dai_comp_trigger_internal(), PAUSE");
|
comp_dbg(dev, "dai_comp_trigger_internal(), PAUSE");
|
||||||
|
|
Loading…
Reference in New Issue