From 1e0fe65ab0ac754153c83a3ddc256eb27b8cabe3 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 2 Jun 2023 16:33:10 +0300 Subject: [PATCH] intel: ssp: On playback stop only wait for the DMA to stop It does not make much sense to wait for the TX FIFO to drain as we either going to power off SSP or the clocks will remain running due to active capture. It just introduces extra delay on stop, which can be significant in case of low sampling rates. However we should make sure that the DMA is not filling the TX FIFO to make sure that the SSP is not disabled during DMA burst. Signed-off-by: Peter Ujfalusi --- src/drivers/intel/ssp/ssp.c | 48 +++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/src/drivers/intel/ssp/ssp.c b/src/drivers/intel/ssp/ssp.c index 0ec5d2ab88c0..57292727e110 100644 --- a/src/drivers/intel/ssp/ssp.c +++ b/src/drivers/intel/ssp/ssp.c @@ -41,30 +41,37 @@ DECLARE_SOF_UUID("ssp-dai", ssp_uuid, 0x31458125, 0x95c4, 0x4085, DECLARE_TR_CTX(ssp_tr, SOF_UUID(ssp_uuid), LOG_LEVEL_INFO); -/* empty SSP transmit FIFO */ -static void ssp_empty_tx_fifo(struct dai *dai) +static void ssp_wait_tx_dma_idle(struct dai *dai) { - int ret; - uint32_t sssr; + struct ssp_pdata *ssp = dai_get_drvdata(dai); + uint64_t sample_ticks = clock_ticks_per_sample(PLATFORM_DEFAULT_CLOCK, + ssp->params.fsync_rate); + uint32_t retry = SSP_RX_FLUSH_RETRY_MAX; + uint32_t entries[2]; - /* - * SSSR_TNF is cleared when TX FIFO is empty or full, - * so wait for set TNF then for TFL zero - order matter. - */ - ret = poll_for_register_delay(dai_base(dai) + SSSR, SSSR_TNF, SSSR_TNF, - SSP_MAX_SEND_TIME_PER_SAMPLE); - ret |= poll_for_register_delay(dai_base(dai) + SSCR3, SSCR3_TFL_MASK, 0, - SSP_MAX_SEND_TIME_PER_SAMPLE * - (SSP_FIFO_DEPTH - 1) / 2); + entries[0] = SSCR3_TFL_VAL(ssp_read(dai, SSCR3)); - if (ret) - dai_warn(dai, "ssp_empty_tx_fifo() warning: timeout"); + /* Unlikely: the TX FIFO is empty */ + if (!entries[0] && (ssp_read(dai, SSSR) & SSSR_TNF)) + return; - sssr = ssp_read(dai, SSSR); + while (retry--) { + /* Wait one sample time */ + wait_delay(sample_ticks); + + entries[1] = SSCR3_TFL_VAL(ssp_read(dai, SSCR3)); + + /* + * If the TX FIFO has less entries or equal entries after one + * sample time then DMA is not running to fill the FIFO and we + * can break out from the loop + */ + if (entries[0] >= entries[1]) + break; + } - /* clear interrupt */ - if (sssr & SSSR_TUR) - ssp_write(dai, SSSR, sssr); + /* Just in case clear the underflow status */ + ssp_update_bits(dai, SSSR, SSSR_TUR, SSSR_TUR); } static void ssp_empty_rx_fifo_on_start(struct dai *dai) @@ -1032,6 +1039,7 @@ static void ssp_start(struct dai *dai, int direction) /* enable DMA */ if (direction == DAI_DIR_PLAYBACK) { + ssp_update_bits(dai, SSSR, SSSR_TUR, SSSR_TUR); ssp_update_bits(dai, SSCR1, SSCR1_TSRE, SSCR1_TSRE); ssp_update_bits(dai, SSTSA, SSTSA_TXEN, SSTSA_TXEN); } else { @@ -1094,7 +1102,7 @@ static void ssp_stop(struct dai *dai, int direction) if (direction == DAI_DIR_PLAYBACK && ssp->state[SOF_IPC_STREAM_PLAYBACK] != COMP_STATE_PREPARE) { ssp_update_bits(dai, SSCR1, SSCR1_TSRE, 0); - ssp_empty_tx_fifo(dai); + ssp_wait_tx_dma_idle(dai); ssp_update_bits(dai, SSTSA, SSTSA_TXEN, 0); ssp->state[SOF_IPC_STREAM_PLAYBACK] = COMP_STATE_PREPARE; dai_info(dai, "ssp_stop(), TX stop");