From 850afb66beba413c16c9a48173cd29be14d90eed Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 23 Oct 2020 10:53:53 +0800 Subject: [PATCH 1/2] clk: add helper to get sample ticks for a specific sample rate Add helper clock_ticks_per_sample() to calculate and return the clock ticks for a specific sample rate. Signed-off-by: Keyon Jie --- src/include/sof/lib/clk.h | 2 ++ src/lib/clk.c | 13 +++++++++++++ 2 files changed, 15 insertions(+) diff --git a/src/include/sof/lib/clk.h b/src/include/sof/lib/clk.h index 04febf6f2b04..af6ff0c712c9 100644 --- a/src/include/sof/lib/clk.h +++ b/src/include/sof/lib/clk.h @@ -57,6 +57,8 @@ void clock_low_power_mode(int clock, bool enable); uint64_t clock_ms_to_ticks(int clock, uint64_t ms); +uint64_t clock_ticks_per_sample(int clock, uint32_t sample_rate); + void platform_timer_set_delta(struct timer *timer, uint64_t ns); static inline struct clock_info *clocks_get(void) diff --git a/src/lib/clk.c b/src/lib/clk.c index 6253cd416629..3650c5c1ab3b 100644 --- a/src/lib/clk.c +++ b/src/lib/clk.c @@ -115,6 +115,19 @@ uint64_t clock_ms_to_ticks(int clock, uint64_t ms) return ticks; } +uint64_t clock_ticks_per_sample(int clock, uint32_t sample_rate) +{ + struct clock_info *clk_info = clocks_get() + clock; + uint32_t ticks_per_msec; + uint64_t ticks_per_sample; + + platform_shared_get(clk_info, sizeof(*clk_info)); + ticks_per_msec = clk_info->freqs[clk_info->current_freq_idx].ticks_per_msec; + ticks_per_sample = sample_rate ? ticks_per_msec * 1000 / sample_rate : 0; + + return ticks_per_sample; +} + void platform_timer_set_delta(struct timer *timer, uint64_t ns) { struct clock_info *clk_info = clocks_get() + PLATFORM_DEFAULT_CLOCK; From ec405b1fd308a0981cfb4be1aeb6789015a879a3 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Thu, 22 Oct 2020 14:24:31 +0800 Subject: [PATCH 2/2] ssp: refine the RX FIFO flushing logic The SSSR_BSY is not necessary for flushing, we need to read out entries every time the FIFO is not empty. This flushing may need take place several rounds, and we need to wait 1 sample time between 2 flushing rounds. Fixes #3525 Signed-off-by: Keyon Jie --- src/drivers/intel/ssp/ssp.c | 34 +++++++++++++++++++++------------- src/include/sof/drivers/ssp.h | 4 ++-- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/src/drivers/intel/ssp/ssp.c b/src/drivers/intel/ssp/ssp.c index 0cda5888bb0e..9b8e4e9127e8 100644 --- a/src/drivers/intel/ssp/ssp.c +++ b/src/drivers/intel/ssp/ssp.c @@ -67,24 +67,32 @@ static void ssp_empty_tx_fifo(struct dai *dai) /* empty SSP receive FIFO */ static void ssp_empty_rx_fifo(struct dai *dai) { - struct timer *timer = timer_get(); - uint64_t deadline = platform_timer_get(timer) + - clock_ms_to_ticks(PLATFORM_DEFAULT_CLOCK, 1) * - SSP_RX_FLUSH_TIMEOUT / 1000; + 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; + uint32_t i; /* * To make sure all the RX FIFO entries are read out for the flushing, - * we need to wait until the SSSR_RNE is cleared after the SSP link is - * stopped (the SSSR_BSY is cleared), otherwise, there might be - * obsoleted entries remained in the FIFO, which will impact the next - * run with the SSP RX and lead to samples mismatched issue. + * we need to wait a minimal SSP port delay after entries are all read, + * and then re-check to see if there is any subsequent entries written + * to the FIFO. This will help to make sure there is no sample mismatched + * issue for the next run with the SSP RX. */ - do { - while (ssp_read(dai, SSSR) & SSSR_RNE) - /* read to empty the fifo */ + while ((ssp_read(dai, SSSR) & SSSR_RNE) && retry--) { + entries = SSCR3_RFL_VAL(ssp_read(dai, SSCR3)); + dai_dbg(dai, "ssp_empty_rx_fifo(), before flushing, entries %d", entries); + for (i = 0; i < entries + 1; i++) + /* read to try empty fifo */ ssp_read(dai, SSDR); - } while ((ssp_read(dai, SSSR) & SSSR_BSY) && - platform_timer_get(timer) < deadline); + + /* wait to get valid fifo status and re-check */ + wait_delay(sample_ticks); + entries = SSCR3_RFL_VAL(ssp_read(dai, SSCR3)); + dai_dbg(dai, "ssp_empty_rx_fifo(), after flushing, entries %d", entries); + } /* clear interrupt */ ssp_update_bits(dai, SSSR, SSSR_ROR, SSSR_ROR); diff --git a/src/include/sof/drivers/ssp.h b/src/include/sof/drivers/ssp.h index 9e2a2f0d36a5..46aadb26ec39 100644 --- a/src/include/sof/drivers/ssp.h +++ b/src/include/sof/drivers/ssp.h @@ -220,8 +220,8 @@ extern const struct dai_driver ssp_driver; /* For 8000 Hz rate one sample is transmitted within 125us */ #define SSP_MAX_SEND_TIME_PER_SAMPLE 125 -/* SSP flush timeout in microseconds */ -#define SSP_RX_FLUSH_TIMEOUT 200 +/* SSP flush retry counts maximum */ +#define SSP_RX_FLUSH_RETRY_MAX 16 #define ssp_irq(ssp) \ ssp->plat_data.irq