From 1ec4384285a44fcc7c967d5193b10fe291dd3fb0 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Tue, 20 Oct 2020 14:28:37 +0800 Subject: [PATCH 1/2] ssp: disable SSP port during ssp_start() We should make sure the SSP port is disabled when trying to start new transmission or reception, to avoid any potential race between transmission and the reception on the same SSP port. Fixes #3520 #3525 Signed-off-by: Keyon Jie --- src/drivers/intel/ssp/ssp.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/drivers/intel/ssp/ssp.c b/src/drivers/intel/ssp/ssp.c index cf103da73328..967b4b361702 100644 --- a/src/drivers/intel/ssp/ssp.c +++ b/src/drivers/intel/ssp/ssp.c @@ -688,13 +688,12 @@ static int ssp_get_hw_params(struct dai *dai, static void ssp_start(struct dai *dai, int direction) { struct ssp_pdata *ssp = dai_get_drvdata(dai); + uint32_t sscr0 = ssp_read(dai, SSCR0); + uint32_t sspsp = ssp_read(dai, SSPSP); + uint32_t sssr = ssp_read(dai, SSSR); 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) { @@ -705,6 +704,10 @@ static void ssp_start(struct dai *dai, int direction) ssp->params.bclk_delay)); } + if (sscr0 & SSCR0_SSE) + /* disable SSP to load new configuration */ + ssp_update_bits(dai, SSCR0, SSCR0_SSE, 0); + /* enable DMA */ if (direction == DAI_DIR_PLAYBACK) { ssp_update_bits(dai, SSCR1, SSCR1_TSRE, SSCR1_TSRE); @@ -714,6 +717,14 @@ static void ssp_start(struct dai *dai, int direction) ssp_update_bits(dai, SSRSA, SSRSA_RXEN, SSRSA_RXEN); } + /* restore ssp status */ + ssp_write(dai, SSSR, sssr); + ssp_write(dai, SSPSP, sspsp); + + /* enable port */ + ssp_write(dai, SSCR0, sscr0 | SSCR0_SSE); + ssp->state[direction] = COMP_STATE_ACTIVE; + /* wait to get valid fifo status */ wait_delay(PLATFORM_SSP_DELAY); From 32c70c468e2bcb3c3c2ca1a8474749681e986254 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Tue, 20 Oct 2020 14:59:22 +0800 Subject: [PATCH 2/2] baytrail: ssp: disable SSP port during ssp_start() Add the similar fix to baytrail ssp which disabling the SSP port during ssp_start(), to avoid any potential race between transmission and the reception on the same SSP port. Fixes #3520 Signed-off-by: Keyon Jie --- src/drivers/intel/baytrail/ssp.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/drivers/intel/baytrail/ssp.c b/src/drivers/intel/baytrail/ssp.c index ea553ce0564e..e93c49c8d82c 100644 --- a/src/drivers/intel/baytrail/ssp.c +++ b/src/drivers/intel/baytrail/ssp.c @@ -516,21 +516,32 @@ static int ssp_get_hw_params(struct dai *dai, static void ssp_start(struct dai *dai, int direction) { struct ssp_pdata *ssp = dai_get_drvdata(dai); + uint32_t sscr0 = ssp_read(dai, SSCR0); + uint32_t sspsp = ssp_read(dai, SSPSP); + uint32_t sssr = ssp_read(dai, SSSR); 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 (sscr0 & SSCR0_SSE) + /* disable SSP to load new configuration */ + ssp_update_bits(dai, SSCR0, SSCR0_SSE, 0); + /* enable DMA */ if (direction == DAI_DIR_PLAYBACK) ssp_update_bits(dai, SSCR1, SSCR1_TSRE, SSCR1_TSRE); else ssp_update_bits(dai, SSCR1, SSCR1_RSRE, SSCR1_RSRE); + /* restore ssp status */ + ssp_write(dai, SSSR, sssr); + ssp_write(dai, SSPSP, sspsp); + + /* enable port */ + ssp_write(dai, SSCR0, sscr0 | SSCR0_SSE); + ssp->state[direction] = COMP_STATE_ACTIVE; + spin_unlock(&dai->lock); }