From cc54f1313dd47881e80dc3de58855ffd2297a1e7 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Thu, 15 Mar 2018 20:01:09 +0800 Subject: [PATCH] apl-ssp: fix capture double speed issue Previously TFT and RFT are set to 0s which means we are using threshold level 1, where interrupt asserts for every valid bits of each slot(e.g. for s16_le capture, interrupts assert for each 16 bits), but DMAC will treat it as notification of one full sample(e.g. 32 bits for s16_le stereo) and read those all bits, this will lead to capture with double speed at format s16_le stereo. Here add handle for FIFO trigger Threshold level, set them to bytes for each full sample(active_slots * valid_bits / 8), and the issue is fixed. Signed-off-by: Keyon Jie --- src/drivers/apl-ssp.c | 45 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/drivers/apl-ssp.c b/src/drivers/apl-ssp.c index 1ee107ca8..a863b448a 100644 --- a/src/drivers/apl-ssp.c +++ b/src/drivers/apl-ssp.c @@ -43,6 +43,19 @@ #define trace_ssp_error(__e) trace_error(TRACE_CLASS_SSP, __e) #define tracev_ssp(__e) tracev_event(TRACE_CLASS_SSP, __e) +/* FIXME: move this to a helper and optimize */ +static int hweight_32(uint32_t mask) +{ + int i; + int count = 0; + + for (i = 0; i < 32; i++) { + count += mask & 1; + mask >>= 1; + } + return count; +} + /* save SSP context prior to entering D3 */ static int ssp_context_store(struct dai *dai) { @@ -96,6 +109,11 @@ static inline int ssp_set_config(struct dai *dai, uint32_t dummy_stop; uint32_t frame_len = 0; uint32_t bdiv_min; + uint32_t tft; + uint32_t rft; + uint32_t active_tx_slots = 2; + uint32_t active_rx_slots = 2; + bool inverted_frame = false; int ret = 0; @@ -353,6 +371,9 @@ static inline int ssp_set_config(struct dai *dai, sspsp |= SSPSP_SFRMP(!inverted_frame); sspsp |= SSPSP_FSRT; + active_tx_slots = hweight_32(config->tx_slot_mask); + active_rx_slots = hweight_32(config->rx_slot_mask); + break; case SOF_DAI_FMT_DSP_B: @@ -371,6 +392,9 @@ static inline int ssp_set_config(struct dai *dai, */ sspsp |= SSPSP_SFRMP(!inverted_frame); + active_tx_slots = hweight_32(config->tx_slot_mask); + active_rx_slots = hweight_32(config->rx_slot_mask); + break; default: trace_ssp_error("eca"); @@ -408,6 +432,27 @@ static inline int ssp_set_config(struct dai *dai, /* bypass divider for MCLK */ mdivr = 0x00000fff; + /* setting TFT and RFT */ + switch (config->sample_valid_bits) { + case 16: + /* use 2 bytes for each slot */ + tft = active_tx_slots * 2; + rft = active_rx_slots * 2; + break; + case 24: + case 32: + /* use 4 bytes for each slot */ + tft = active_tx_slots * 4; + rft = active_rx_slots * 4; + break; + default: + trace_ssp_error("ecd"); + ret = -EINVAL; + goto out; + } + + sscr3 |= SSCR3_TX(tft) | SSCR3_RX(rft); + trace_ssp("coe"); ssp_write(dai, SSCR0, sscr0); ssp_write(dai, SSCR1, sscr1);