[Sound-open-firmware] [PATCH] apl-ssp: fix padding bit issues in I2S/LEFT_J mode
The current code doesn't work for I2S/LEFT_J when the slot width and number of valid bits don't match (e.g. 24 bit data in 32-bit slot).
In I2S/LEFT_J mode, the padding is not at the end of the frame but at the end of each slot, and is evenly distributed between the two left and right phases.
Fix by using DMYSTOP for I2S/LEFT_J, and only program SSPSP2 for DSP_A and DSP_B modes
Signed-off-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com --- src/drivers/apl-ssp.c | 79 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 63 insertions(+), 16 deletions(-)
diff --git a/src/drivers/apl-ssp.c b/src/drivers/apl-ssp.c index a02d934..3a97cb8 100644 --- a/src/drivers/apl-ssp.c +++ b/src/drivers/apl-ssp.c @@ -107,6 +107,7 @@ static inline int ssp_set_config(struct dai *dai, uint32_t data_size; uint32_t start_delay; uint32_t frame_end_padding; + uint32_t slot_end_padding; uint32_t frame_len = 0; uint32_t bdiv_min; uint32_t tft; @@ -299,6 +300,20 @@ static inline int ssp_set_config(struct dai *dai, goto out; }
+ bdiv_min = config->ssp.tdm_slots * config->ssp.sample_valid_bits; + if (bdiv < bdiv_min) { + trace_ssp_error("ecc"); + ret = -EINVAL; + goto out; + } + + frame_end_padding = bdiv - bdiv_min; + if (frame_end_padding > SSPSP2_FEP_MASK) { + trace_ssp_error("ecd"); + ret = -EINVAL; + goto out; + } + /* format */ switch (config->format & SOF_DAI_FMT_FORMAT_MASK) { case SOF_DAI_FMT_I2S: @@ -325,6 +340,28 @@ static inline int ssp_set_config(struct dai *dai, sspsp |= SSPSP_SFRMP(inverted_frame); sspsp |= SSPSP_FSRT;
+ /* + * for I2S/LEFT_J, the padding has to happen at the end + * of each slot + */ + if (frame_end_padding % 2) { + trace_ssp_error("ece"); + ret = -EINVAL; + goto out; + } + + slot_end_padding = frame_end_padding / 2; + + if (slot_end_padding > 15) { + /* can't handle padding over 15 bits */ + trace_ssp_error("ecf"); + ret = -EINVAL; + goto out; + } + + sspsp |= SSPSP_EDMYSTOP((slot_end_padding >> 2) & 0x3); + sspsp |= SSPSP_DMYSTOP(slot_end_padding & 0x3); + break;
case SOF_DAI_FMT_LEFT_J: @@ -353,6 +390,28 @@ static inline int ssp_set_config(struct dai *dai, */ sspsp |= SSPSP_SFRMP(!inverted_frame);
+ /* + * for I2S/LEFT_J, the padding has to happen at the end + * of each slot + */ + if (frame_end_padding % 2) { + trace_ssp_error("ecg"); + ret = -EINVAL; + goto out; + } + + slot_end_padding = frame_end_padding / 2; + + if (slot_end_padding > 15) { + /* can't handle padding over 15 bits */ + trace_ssp_error("ech"); + ret = -EINVAL; + goto out; + } + + sspsp |= SSPSP_EDMYSTOP((slot_end_padding >> 2) & 0x3); + sspsp |= SSPSP_DMYSTOP(slot_end_padding & 0x3); + break; case SOF_DAI_FMT_DSP_A:
@@ -375,6 +434,8 @@ static inline int ssp_set_config(struct dai *dai, active_tx_slots = hweight_32(config->ssp.tx_slots); active_rx_slots = hweight_32(config->ssp.rx_slots);
+ sspsp2 |= (frame_end_padding & SSPSP2_FEP_MASK); + break; case SOF_DAI_FMT_DSP_B:
@@ -396,6 +457,8 @@ static inline int ssp_set_config(struct dai *dai, active_tx_slots = hweight_32(config->ssp.tx_slots); active_rx_slots = hweight_32(config->ssp.rx_slots);
+ sspsp2 |= (frame_end_padding & SSPSP2_FEP_MASK); + break; default: trace_ssp_error("eca"); @@ -406,22 +469,6 @@ static inline int ssp_set_config(struct dai *dai, sspsp |= SSPSP_STRTDLY(start_delay); sspsp |= SSPSP_SFRMWDTH(frame_len);
- bdiv_min = config->ssp.tdm_slots * config->ssp.sample_valid_bits; - if (bdiv < bdiv_min) { - trace_ssp_error("ecc"); - ret = -EINVAL; - goto out; - } - - frame_end_padding = bdiv - bdiv_min; - if (frame_end_padding > SSPSP2_FEP_MASK) { - trace_ssp_error("ecd"); - ret = -EINVAL; - goto out; - } - - sspsp2 |= (frame_end_padding & SSPSP2_FEP_MASK); - data_size = config->ssp.sample_valid_bits;
if (data_size > 16)
-----Original Message----- From: sound-open-firmware-bounces@alsa-project.org [mailto:sound-open- firmware-bounces@alsa-project.org] On Behalf Of Pierre-Louis Bossart Sent: Friday, April 13, 2018 6:27 AM To: sound-open-firmware@alsa-project.org Cc: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Subject: [Sound-open-firmware] [PATCH] apl-ssp: fix padding bit issues in I2S/LEFT_J mode
The current code doesn't work for I2S/LEFT_J when the slot width and number of valid bits don't match (e.g. 24 bit data in 32-bit slot).
In I2S/LEFT_J mode, the padding is not at the end of the frame but at the end of each slot, and is evenly distributed between the two left and right phases.
Fix by using DMYSTOP for I2S/LEFT_J, and only program SSPSP2 for DSP_A and DSP_B modes
Signed-off-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com
src/drivers/apl-ssp.c | 79 ++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 63 insertions(+), 16 deletions(-)
diff --git a/src/drivers/apl-ssp.c b/src/drivers/apl-ssp.c index a02d934..3a97cb8 100644 --- a/src/drivers/apl-ssp.c +++ b/src/drivers/apl-ssp.c @@ -107,6 +107,7 @@ static inline int ssp_set_config(struct dai *dai, uint32_t data_size; uint32_t start_delay; uint32_t frame_end_padding;
- uint32_t slot_end_padding; uint32_t frame_len = 0; uint32_t bdiv_min; uint32_t tft;
@@ -299,6 +300,20 @@ static inline int ssp_set_config(struct dai *dai, goto out; }
- bdiv_min = config->ssp.tdm_slots * config->ssp.sample_valid_bits;
- if (bdiv < bdiv_min) {
trace_ssp_error("ecc");
ret = -EINVAL;
goto out;
- }
- frame_end_padding = bdiv - bdiv_min;
- if (frame_end_padding > SSPSP2_FEP_MASK) {
trace_ssp_error("ecd");
ret = -EINVAL;
goto out;
- }
- /* format */ switch (config->format & SOF_DAI_FMT_FORMAT_MASK) { case SOF_DAI_FMT_I2S:
@@ -325,6 +340,28 @@ static inline int ssp_set_config(struct dai *dai, sspsp |= SSPSP_SFRMP(inverted_frame); sspsp |= SSPSP_FSRT;
/*
* for I2S/LEFT_J, the padding has to happen at the end
* of each slot
*/
if (frame_end_padding % 2) {
trace_ssp_error("ece");
ret = -EINVAL;
goto out;
}
slot_end_padding = frame_end_padding / 2;
if (slot_end_padding > 15) {
/* can't handle padding over 15 bits */
trace_ssp_error("ecf");
ret = -EINVAL;
goto out;
}
sspsp |= SSPSP_EDMYSTOP((slot_end_padding >> 2) & 0x3);
sspsp |= SSPSP_DMYSTOP(slot_end_padding & 0x3);
break;
case SOF_DAI_FMT_LEFT_J:
@@ -353,6 +390,28 @@ static inline int ssp_set_config(struct dai *dai, */ sspsp |= SSPSP_SFRMP(!inverted_frame);
/*
* for I2S/LEFT_J, the padding has to happen at the end
* of each slot
*/
if (frame_end_padding % 2) {
trace_ssp_error("ecg");
ret = -EINVAL;
goto out;
}
slot_end_padding = frame_end_padding / 2;
if (slot_end_padding > 15) {
/* can't handle padding over 15 bits */
trace_ssp_error("ech");
ret = -EINVAL;
goto out;
}
sspsp |= SSPSP_EDMYSTOP((slot_end_padding >> 2) & 0x3);
sspsp |= SSPSP_DMYSTOP(slot_end_padding & 0x3);
We have already macros for those masks, just sent you a patch which you can combine with.
Thanks, ~Keyon
- break; case SOF_DAI_FMT_DSP_A:
@@ -375,6 +434,8 @@ static inline int ssp_set_config(struct dai *dai, active_tx_slots = hweight_32(config->ssp.tx_slots); active_rx_slots = hweight_32(config->ssp.rx_slots);
sspsp2 |= (frame_end_padding & SSPSP2_FEP_MASK);
- break; case SOF_DAI_FMT_DSP_B:
@@ -396,6 +457,8 @@ static inline int ssp_set_config(struct dai *dai, active_tx_slots = hweight_32(config->ssp.tx_slots); active_rx_slots = hweight_32(config->ssp.rx_slots);
sspsp2 |= (frame_end_padding & SSPSP2_FEP_MASK);
- break; default: trace_ssp_error("eca");
@@ -406,22 +469,6 @@ static inline int ssp_set_config(struct dai *dai, sspsp |= SSPSP_STRTDLY(start_delay); sspsp |= SSPSP_SFRMWDTH(frame_len);
bdiv_min = config->ssp.tdm_slots * config->ssp.sample_valid_bits;
if (bdiv < bdiv_min) {
trace_ssp_error("ecc");
ret = -EINVAL;
goto out;
}
frame_end_padding = bdiv - bdiv_min;
if (frame_end_padding > SSPSP2_FEP_MASK) {
trace_ssp_error("ecd");
ret = -EINVAL;
goto out;
}
sspsp2 |= (frame_end_padding & SSPSP2_FEP_MASK);
data_size = config->ssp.sample_valid_bits;
if (data_size > 16)
-- 2.14.1
Sound-open-firmware mailing list Sound-open-firmware@alsa-project.org http://mailman.alsa-project.org/mailman/listinfo/sound-open-firmware
sspsp |= SSPSP_EDMYSTOP((slot_end_padding >> 2) & 0x3);
sspsp |= SSPSP_DMYSTOP(slot_end_padding & 0x3);
We have already macros for those masks, just sent you a patch which you can combine with.
Did you mean this?
+ sspsp |= SSPSP_DMYSTOP(SSPSP_DMYSTOP_MASK & dummy_stop); + sspsp |= SSPSP_EDMYSTOP(SSPSP_EDMYSTOP_MASK & + (dummy_stop >> SSPSP_DMYSTOP_BITS));
-----Original Message----- From: Pierre-Louis Bossart [mailto:pierre-louis.bossart@linux.intel.com] Sent: Friday, April 13, 2018 10:19 PM To: Jie, Yang yang.jie@intel.com; sound-open-firmware@alsa-project.org Subject: Re: [Sound-open-firmware] [PATCH] apl-ssp: fix padding bit issues in I2S/LEFT_J mode
sspsp |= SSPSP_EDMYSTOP((slot_end_padding >> 2) & 0x3);
sspsp |= SSPSP_DMYSTOP(slot_end_padding & 0x3);
We have already macros for those masks, just sent you a patch which you can
combine with.
Did you mean this?
Yep.
Thanks, ~Keyon
- sspsp |= SSPSP_DMYSTOP(SSPSP_DMYSTOP_MASK & dummy_stop);
- sspsp |= SSPSP_EDMYSTOP(SSPSP_EDMYSTOP_MASK &
(dummy_stop >> SSPSP_DMYSTOP_BITS));
On Thu, 2018-04-12 at 17:27 -0500, Pierre-Louis Bossart wrote:
The current code doesn't work for I2S/LEFT_J when the slot width and number of valid bits don't match (e.g. 24 bit data in 32-bit slot).
In I2S/LEFT_J mode, the padding is not at the end of the frame but at the end of each slot, and is evenly distributed between the two left and right phases.
Fix by using DMYSTOP for I2S/LEFT_J, and only program SSPSP2 for DSP_A and DSP_B modes
Signed-off-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com
all applied.
Thanks
Liam
participants (3)
-
Jie, Yang
-
Liam Girdwood
-
Pierre-Louis Bossart