On 03/15/2018 07:01 AM, Keyon Jie wrote:
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 yang.jie@linux.intel.com
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 1ee107c..a863b44 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);
Looks good enough to me, we may want to come back and revisit watermark levels later. Some implementations use half of the FIFO, some fill/empty it as soon as possible, not sure what makes sense and if it needs to be configured differently for specific applications, e.g. if you want ultra low latency.
- trace_ssp("coe"); ssp_write(dai, SSCR0, sscr0); ssp_write(dai, SSCR1, sscr1);