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 */
|
||||
if (dd->xrun == 0) {
|
||||
/* start the DAI */
|
||||
dai_trigger(dd->dai, cmd, dev->direction);
|
||||
ret = dma_start(dd->chan);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
/* start the DAI */
|
||||
dai_trigger(dd->dai, cmd, dev->direction);
|
||||
} else {
|
||||
dd->xrun = 0;
|
||||
}
|
||||
|
@ -695,8 +695,21 @@ static int dai_comp_trigger_internal(struct comp_dev *dev, int cmd)
|
|||
COMPILER_FALLTHROUGH;
|
||||
case COMP_TRIGGER_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);
|
||||
dai_trigger(dd->dai, cmd, dev->direction);
|
||||
#else
|
||||
dai_trigger(dd->dai, cmd, dev->direction);
|
||||
ret = dma_stop(dd->chan);
|
||||
#endif
|
||||
break;
|
||||
case COMP_TRIGGER_PAUSE:
|
||||
comp_dbg(dev, "dai_comp_trigger_internal(), PAUSE");
|
||||
|
|
Loading…
Reference in New Issue