[Sound-open-firmware] [PATCH] SSP: refine padding bit setting on Broadwell
Rander Wang
rander.wang at linux.intel.com
Fri Jun 1 10:50:35 CEST 2018
merge commit 36f23c6cc3ed ("apl-ssp: fix padding bit issues in
I2S/LEFT_J mode") and refine it on Broadwell.
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart at linux.intel.com>
Signed-off-by: Rander Wang <rander.wang at linux.intel.com>
---
test it on Broadwell
---
src/drivers/hsw-ssp.c | 99 ++++++++++++++++++++++++++++++++++++++++++---------
src/include/sof/ssp.h | 11 +++---
2 files changed, 87 insertions(+), 23 deletions(-)
diff --git a/src/drivers/hsw-ssp.c b/src/drivers/hsw-ssp.c
index 7e5ae3d..b2fa99e 100644
--- a/src/drivers/hsw-ssp.c
+++ b/src/drivers/hsw-ssp.c
@@ -77,11 +77,16 @@ static inline int ssp_set_config(struct dai *dai,
uint32_t sscr1;
uint32_t sscr2;
uint32_t sspsp;
+ uint32_t sspsp2;
uint32_t mdiv;
uint32_t bdiv;
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 format;
bool inverted_frame = false;
int ret = 0;
@@ -130,6 +135,9 @@ static inline int ssp_set_config(struct dai *dai,
/* sspsp dynamic settings are SCMODE, SFRMP, DMYSTRT, SFRMWDTH */
sspsp = SSPSP_ETDS; /* make sure SDO line is tri-stated when inactive */
+ /* sspsp2 no dynamic setting */
+ sspsp2 = 0x0;
+
ssp->config = *config;
ssp->params = config->ssp;
@@ -252,29 +260,83 @@ static inline int ssp_set_config(struct dai *dai,
goto out;
}
- /* format */
- switch (config->format & SOF_DAI_FMT_FORMAT_MASK) {
- case SOF_DAI_FMT_I2S:
-
- start_delay = 1;
-
- /* set asserted frame length */
- frame_len = config->ssp.tdm_slot_width;
-
- /* handle frame polarity, I2S default is falling/active low */
- sspsp |= SSPSP_SFRMP(!inverted_frame);
+ bdiv_min = config->ssp.tdm_slots * config->ssp.sample_valid_bits;
+ if (bdiv < bdiv_min) {
+ trace_ssp_error("ecc");
+ ret = -EINVAL;
+ goto out;
+ }
- break;
+ frame_end_padding = bdiv - bdiv_min;
+ if (frame_end_padding > SSPSP2_FEP_MASK) {
+ trace_ssp_error("ecd");
+ ret = -EINVAL;
+ goto out;
+ }
+ /* format */
+ format = config->format & SOF_DAI_FMT_FORMAT_MASK;
+ switch (format) {
+ case SOF_DAI_FMT_I2S:
case SOF_DAI_FMT_LEFT_J:
- start_delay = 0;
+ if (format == SOF_DAI_FMT_I2S) {
+ start_delay = 1;
+
+ /*
+ * handle frame polarity, I2S default is falling/active low,
+ * non-inverted(inverted_frame=0) -- active low(SFRMP=0),
+ * inverted(inverted_frame=1) -- rising/active high(SFRMP=1),
+ * so, we should set SFRMP to inverted_frame.
+ */
+ sspsp |= SSPSP_SFRMP(inverted_frame);
+ sspsp |= SSPSP_FSRT;
+
+ } else {
+ start_delay = 0;
+
+ /*
+ * handle frame polarity, LEFT_J default is rising/active high,
+ * non-inverted(inverted_frame=0) -- active high(SFRMP=1),
+ * inverted(inverted_frame=1) -- falling/active low(SFRMP=0),
+ * so, we should set SFRMP to !inverted_frame.
+ */
+ sspsp |= SSPSP_SFRMP(!inverted_frame);
+ }
- /* set asserted frame length */
- frame_len = config->ssp.tdm_slot_width;
+ sscr0 |= SSCR0_FRDC(config->ssp.tdm_slots);
- /* LEFT_J default is rising/active high, opposite of I2S */
- sspsp |= SSPSP_SFRMP(inverted_frame);
+ if (bdiv % 2) {
+ trace_ssp_error("eca");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* set asserted frame length to half frame length */
+ frame_len = bdiv / 2;
+
+ /*
+ * 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_DMYSTOP(slot_end_padding & SSPSP_DMYSTOP_MASK);
+ slot_end_padding >>= SSPSP_DMYSTOP_BITS;
+ sspsp |= SSPSP_EDMYSTOP(slot_end_padding & SSPSP_EDMYSTOP_MASK);
break;
case SOF_DAI_FMT_DSP_A:
@@ -288,6 +350,7 @@ static inline int ssp_set_config(struct dai *dai,
/* handle frame polarity, DSP_A default is rising/active high */
sspsp |= SSPSP_SFRMP(inverted_frame);
+ sspsp2 |= (frame_end_padding & SSPSP2_FEP_MASK);
break;
case SOF_DAI_FMT_DSP_B:
@@ -301,6 +364,7 @@ static inline int ssp_set_config(struct dai *dai,
/* handle frame polarity, DSP_A default is rising/active high */
sspsp |= SSPSP_SFRMP(inverted_frame);
+ sspsp2 |= (frame_end_padding & SSPSP2_FEP_MASK);
break;
default:
@@ -329,6 +393,7 @@ static inline int ssp_set_config(struct dai *dai,
ssp_write(dai, SSPSP, sspsp);
ssp_write(dai, SSTSA, config->ssp.tx_slots);
ssp_write(dai, SSRSA, config->ssp.rx_slots);
+ ssp_write(dai, SSPSP2, sspsp2);
ssp->state[DAI_DIR_PLAYBACK] = COMP_STATE_PREPARE;
ssp->state[DAI_DIR_CAPTURE] = COMP_STATE_PREPARE;
diff --git a/src/include/sof/ssp.h b/src/include/sof/ssp.h
index d34b011..3a1f6ed 100644
--- a/src/include/sof/ssp.h
+++ b/src/include/sof/ssp.h
@@ -55,12 +55,12 @@
#define SSTSA 0x30
#define SSRSA 0x34
#define SSTSS 0x38
+#define SSCR2 0x40
#if defined CONFIG_BAYTRAIL ||\
defined CONFIG_CHERRYTRAIL ||\
defined CONFIG_BROADWELL ||\
defined CONFIG_HASWELL
-#define SSCR2 0x40
#define SFIFOTT 0x6C
#define SSCR3 0x70
#define SSCR4 0x74
@@ -159,14 +159,13 @@ extern const struct dai_ops ssp_ops;
#define SSPSP_DMYSTOP_BITS 2
#define SSPSP_DMYSTOP_MASK ((0x1 << SSPSP_DMYSTOP_BITS) - 1)
#define SSPSP_FSRT (1 << 25)
-
-#if defined CONFIG_APOLLOLAKE || defined CONFIG_CANNONLAKE
#define SSPSP_EDMYSTOP(x) ((x) << 26)
#define SSPSP_EDMYSTOP_MASK 0x7
+
+#define SSPSP2 0x44
#define SSPSP2_FEP_MASK 0xff
-#define SSTSS 0x38
-#define SSCR2 0x40
-#define SSPSP2 0x44
+
+#if defined CONFIG_APOLLOLAKE || defined CONFIG_CANNONLAKE
#define SSCR3 0x48
#define SSIOC 0x4C
--
2.14.1
More information about the Sound-open-firmware
mailing list