From f5d66b0064d8a49a52538135e7459a05862830cf Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 13 May 2021 19:23:59 -0500 Subject: [PATCH] ssp: move SSP blck enablement to ssp_set_config The SSP clocks are currently started in the trigger phase. This is problematic for multiple reasons: a) we should *NEVER* change clock sources in a trigger phase. Switching clocks in and out based on start/stop is asking for trouble. b) we should enable the clocks in the prepare phase c) we are missing a hw_free (dual of prepare) for DAIs. We should stop the SSP and switch clocks in a hw_free This patch moves some of the configuration to the prepare phase (which internally calls ssp_set_config). Initial results show that we can start the bclk 6+ms before starting the transfers. FIXME: 1. the bclk signal is zeroed out at some point. that's not normal 2. the fsync signal should start at the same time as the bclk according to the hardware documentation. It's not clear what causes the fsync to remain high for ~6ms. 3. there is a ~4.2ms delay between the fsync activation and the actual data transfers. This may be due to buffering in the DSP, but that's clearly not good at all. Signed-off-by: Pierre-Louis Bossart --- src/drivers/intel/ssp/ssp.c | 42 +++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/src/drivers/intel/ssp/ssp.c b/src/drivers/intel/ssp/ssp.c index d03efb4e0c93..4a1c50365c4e 100644 --- a/src/drivers/intel/ssp/ssp.c +++ b/src/drivers/intel/ssp/ssp.c @@ -125,6 +125,8 @@ static int ssp_context_restore(struct dai *dai) return 0; } +static int ssp_pre_start(struct dai *dai); + /* Digital Audio interface formatting */ static int ssp_set_config(struct dai *dai, struct sof_ipc_dai_config *config) @@ -602,6 +604,18 @@ static int ssp_set_config(struct dai *dai, dai_info(dai, "ssp_set_config(), ssrsa = 0x%08x, sstsa = 0x%08x", ssrsa, sstsa); + /* request mclk/bclk */ + ssp_pre_start(dai); + + /* enable DMA transfers */ + ssp_update_bits(dai, SSCR1, SSCR1_TSRE, SSCR1_TSRE); + ssp_update_bits(dai, SSCR1, SSCR1_RSRE, SSCR1_RSRE); + + /* enable port */ + ssp_update_bits(dai, SSCR0, SSCR0_SSE, SSCR0_SSE); + + dai_info(dai, "ssp_set_config() SSE enabled"); + ssp->state[DAI_DIR_PLAYBACK] = COMP_STATE_PREPARE; ssp->state[DAI_DIR_CAPTURE] = COMP_STATE_PREPARE; @@ -629,11 +643,6 @@ static int ssp_pre_start(struct dai *dai) dai_info(dai, "ssp_pre_start()"); - /* SSP active means bclk already configured. */ - if (ssp->state[SOF_IPC_STREAM_PLAYBACK] == COMP_STATE_ACTIVE || - ssp->state[SOF_IPC_STREAM_CAPTURE] == COMP_STATE_ACTIVE) - return 0; - /* MCLK config */ ret = mn_set_mclk(config->ssp.mclk_id, config->ssp.mclk_rate); if (ret < 0) { @@ -698,6 +707,8 @@ static void ssp_post_stop(struct dai *dai) { struct ssp_pdata *ssp = dai_get_drvdata(dai); + return; + /* release clocks if SSP is inactive */ if (ssp->state[SOF_IPC_STREAM_PLAYBACK] != COMP_STATE_ACTIVE && ssp->state[SOF_IPC_STREAM_CAPTURE] != COMP_STATE_ACTIVE) { @@ -746,17 +757,12 @@ static void ssp_start(struct dai *dai, int direction) { struct ssp_pdata *ssp = dai_get_drvdata(dai); - spin_lock(&dai->lock); + dai_info(dai, "ssp_start()"); - /* request mclk/bclk */ - ssp_pre_start(dai); + spin_lock(&dai->lock); - /* enable port */ - ssp_update_bits(dai, SSCR0, SSCR0_SSE, SSCR0_SSE); ssp->state[direction] = COMP_STATE_ACTIVE; - dai_info(dai, "ssp_start()"); - if (ssp->params.bclk_delay) { /* drive BCLK early for guaranteed time, * before first FSYNC, it is required by some codecs @@ -767,12 +773,11 @@ static void ssp_start(struct dai *dai, int direction) /* enable DMA */ if (direction == DAI_DIR_PLAYBACK) { - ssp_update_bits(dai, SSCR1, SSCR1_TSRE, SSCR1_TSRE); ssp_update_bits(dai, SSTSA, SSTSA_TXEN, SSTSA_TXEN); } else { - ssp_update_bits(dai, SSCR1, SSCR1_RSRE, SSCR1_RSRE); ssp_update_bits(dai, SSRSA, SSRSA_RXEN, SSRSA_RXEN); } + dai_info(dai, "ssp_start() DMA started"); /* wait to get valid fifo status */ wait_delay(PLATFORM_SSP_DELAY); @@ -793,7 +798,6 @@ static void ssp_stop(struct dai *dai, int direction) /* stop Rx if neeed */ if (direction == DAI_DIR_CAPTURE && ssp->state[SOF_IPC_STREAM_CAPTURE] != COMP_STATE_PREPARE) { - ssp_update_bits(dai, SSCR1, SSCR1_RSRE, 0); ssp_update_bits(dai, SSRSA, SSRSA_RXEN, 0); ssp_empty_rx_fifo(dai); ssp->state[SOF_IPC_STREAM_CAPTURE] = COMP_STATE_PREPARE; @@ -804,19 +808,11 @@ static void ssp_stop(struct dai *dai, int direction) if (direction == DAI_DIR_PLAYBACK && ssp->state[SOF_IPC_STREAM_PLAYBACK] != COMP_STATE_PREPARE) { ssp_empty_tx_fifo(dai); - ssp_update_bits(dai, SSCR1, SSCR1_TSRE, 0); ssp_update_bits(dai, SSTSA, SSTSA_TXEN, 0); ssp->state[SOF_IPC_STREAM_PLAYBACK] = COMP_STATE_PREPARE; dai_info(dai, "ssp_stop(), TX stop"); } - /* disable SSP port if no users */ - if (ssp->state[SOF_IPC_STREAM_CAPTURE] == COMP_STATE_PREPARE && - ssp->state[SOF_IPC_STREAM_PLAYBACK] == COMP_STATE_PREPARE) { - ssp_update_bits(dai, SSCR0, SSCR0_SSE, 0); - dai_info(dai, "ssp_stop(), SSP port disabled"); - } - ssp_post_stop(dai); spin_unlock(&dai->lock);