Skip to content

Commit

Permalink
intel: ssp: On playback stop only wait for the DMA to stop
Browse files Browse the repository at this point in the history
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 <peter.ujfalusi@linux.intel.com>
  • Loading branch information
ujfalusi authored and kv2019i committed Nov 2, 2023
1 parent 755a512 commit 1e0fe65
Showing 1 changed file with 28 additions and 20 deletions.
48 changes: 28 additions & 20 deletions src/drivers/intel/ssp/ssp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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");
Expand Down

0 comments on commit 1e0fe65

Please sign in to comment.