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 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;