[Sound-open-firmware] [PATCH v2] 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 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); + trace_ssp("coe"); ssp_write(dai, SSCR0, sscr0); ssp_write(dai, SSCR1, sscr1);
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);
On Thu, 2018-03-15 at 20:01 +0800, 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
Applied.
Thanks
Liam
participants (3)
-
Keyon Jie
-
Liam Girdwood
-
Pierre-Louis Bossart