[Sound-open-firmware] [PATCH] drivers: ssp: Improve SSP I2S and DSP mode generation from topology.

Liam Girdwood liam.r.girdwood at linux.intel.com
Wed Aug 30 23:32:08 CEST 2017


Improve support for I2S and DSP modes alongside using topology data to
define the mode configuration. Add trace errors to reject any unsupported
configurations.

Signed-off-by: Liam Girdwood <liam.r.girdwood at linux.intel.com>
---
 src/drivers/ssp.c      | 75 +++++++++++++++++++++++++-------------------------
 src/include/reef/ssp.h | 20 +++++++++++++-
 2 files changed, 56 insertions(+), 39 deletions(-)

diff --git a/src/drivers/ssp.c b/src/drivers/ssp.c
index 1a1000a..0b7589a 100644
--- a/src/drivers/ssp.c
+++ b/src/drivers/ssp.c
@@ -69,8 +69,8 @@ static inline int ssp_set_config(struct dai *dai,
 	struct sof_ipc_dai_config *config)
 {
 	struct ssp_pdata *ssp = dai_get_drvdata(dai);
-	uint32_t sscr0, sscr1, sspsp, sfifott, mdiv, bdiv;
-	uint32_t stop_size, data_size;
+	uint32_t sscr0, sscr1, sscr2, sscr3, sspsp, sfifott, mdiv, bdiv;
+	uint32_t data_size, frame_len = 0;
 	int ret = 0;
 
 	spin_lock(&ssp->lock);
@@ -78,7 +78,7 @@ static inline int ssp_set_config(struct dai *dai,
 	/* is playback/capture already running */
 	if (ssp->state[DAI_DIR_PLAYBACK] > SSP_STATE_IDLE ||
 		ssp->state[DAI_DIR_CAPTURE] > SSP_STATE_IDLE) {
-		trace_ssp_error("wsS");
+		trace_ssp_error("ec1");
 		goto out;
 	}
 
@@ -87,6 +87,8 @@ static inline int ssp_set_config(struct dai *dai,
 	/* reset SSP settings */
 	sscr0 = 0;
 	sscr1 = 0;
+	sscr2 = 0xc1;
+	sscr3 = 0x2c018;
 	sspsp = 0;
 
 	ssp->config = *config;
@@ -102,6 +104,7 @@ static inline int ssp_set_config(struct dai *dai,
 		break;
 	case SOF_DAI_FMT_CBS_CFS:
 		sscr1 |= SSCR1_SCFR | SSCR1_RWOT;
+		sscr3 |= SSCR3_I2S_FRM_MST | SSCR3_I2S_CLK_MST;
 		break;
 	case SOF_DAI_FMT_CBM_CFS:
 		sscr1 |= SSCR1_SFRMDIR;
@@ -112,6 +115,7 @@ static inline int ssp_set_config(struct dai *dai,
 	case SSP_CLK_DEFAULT:
 		break;
 	default:
+		trace_ssp_error("ec2");
 		ret = -EINVAL;
 		goto out;
 	}
@@ -129,6 +133,7 @@ static inline int ssp_set_config(struct dai *dai,
 		sspsp |= SSPSP_SCMODE(2) | SSPSP_SFRMP;
 		break;
 	default:
+		trace_ssp_error("ec3");
 		ret = -EINVAL;
 		goto out;
 	}
@@ -148,13 +153,14 @@ static inline int ssp_set_config(struct dai *dai,
 		sscr0 |= SSCR0_NCS | SSCR0_MOD;
 		break;
 	default:
+		trace_ssp_error("ec4");
 		ret = -EINVAL;
 		goto out;
 	}
 
 	/* BCLK is generated from MCLK - must be divisable */
 	if (config->mclk % config->bclk) {
-		trace_ssp_error("ec1");
+		trace_ssp_error("ec5");
 		ret = -EINVAL;
 		goto out;
 	}
@@ -162,17 +168,17 @@ static inline int ssp_set_config(struct dai *dai,
 	/* divisor must be within SCR range */
 	mdiv = (config->mclk / config->bclk)- 1;
 	if (mdiv > (SSCR0_SCR_MASK >> 8)) {
-		trace_ssp_error("ec2");
+		trace_ssp_error("ec6");
 		ret = -EINVAL;
 		goto out;
 	}
 
-	/* set the divisor */
+	/* set the SCR divisor */
 	sscr0 |= SSCR0_SCR(mdiv);
 
 	/* calc frame width based on BCLK and rate - must be divisable */
 	if (config->bclk % config->fclk) {
-		trace_ssp_error("ec3");
+		trace_ssp_error("ec7");
 		ret = -EINVAL;
 		goto out;
 	}
@@ -180,61 +186,60 @@ static inline int ssp_set_config(struct dai *dai,
 	/* must be enouch BCLKs for data */
 	bdiv = config->bclk / config->fclk;
 	if (bdiv < config->sample_container_bits * config->num_slots) {
-		trace_ssp_error("ec4");
+		trace_ssp_error("ec8");
 		ret = -EINVAL;
 		goto out;
 	}
 
 	/* sample_container_bits must be <= 38 for SSP */
 	if (config->sample_container_bits > 38) {
-		trace_ssp_error("ec5");
+		trace_ssp_error("ec9");
 		ret = -EINVAL;
 		goto out;
 	}
 
-	trace_value(mdiv);
-	trace_value(bdiv);
-
 	/* format */
 	switch (config->format & SOF_DAI_FMT_FORMAT_MASK) {
 	case SOF_DAI_FMT_I2S:
 
-		/* calculate dummy stop size and include dummy start */
-		stop_size = config->sample_container_bits -
-			(config->sample_valid_bits) - 1;
-		trace_value(stop_size);
-		if (stop_size > 3) {
-			trace_ssp_error("ec6");
-			ret = -EINVAL;
-			goto out;
-		}
+		/* enable I2S mode */
+		sscr3 |= SSCR3_I2S_ENA | SSCR3_I2S_TX_ENA | SSCR3_I2S_RX_ENA;
 
 		sscr0 |= SSCR0_PSP;
 		sscr1 |= SSCR1_TRAIL;
-		sspsp |= SSPSP_SFRMWDTH(config->sample_container_bits);
-		/* subtract 1 for I2S start delay */
-		sspsp |= SSPSP_SFRMDLY((config->sample_container_bits - 1) * 2);
-		sspsp |= SSPSP_DMYSTRT(1);
-		sspsp |= SSPSP_DMYSTOP(stop_size);
+
+		/* set asserted frame length */
+		frame_len = config->sample_container_bits;
 		break;
 	case SOF_DAI_FMT_DSP_A:
-		sspsp |= SSPSP_FSRT;
+		sscr0 |= SSCR0_PSP | SSCR0_MOD | SSCR0_FRDC(config->num_slots);
+		sscr1 |= SSCR1_TRAIL;
+		sspsp |= SSPSP_SFRMWDTH(1) | SSPSP_SFRMDLY(2);
 	case SOF_DAI_FMT_DSP_B:
-		sscr0 |= SSCR0_PSP;
+		sscr0 |= SSCR0_PSP | SSCR0_MOD | SSCR0_FRDC(config->num_slots);
 		sscr1 |= SSCR1_TRAIL;
+		sspsp |= SSPSP_SFRMWDTH(1);
 		break;
 	default:
+		trace_ssp_error("eca");
 		ret = -EINVAL;
 		goto out;
 	}
 
+	/* set frame length and slot mask in I2s & PCM modes */
+	ssp_write(dai, SSCR4,
+		SSCR4_FRM_CLOCKS(config->sample_container_bits << 1));
+	ssp_write(dai, SSCR5, SSCR5_FRM_ASRT_CLOCKS(frame_len));
+	ssp_write(dai, SSTSA, config->tx_slot_mask);
+	ssp_write(dai, SSRSA, config->rx_slot_mask);
+
 	/* sample data size on SSP FIFO */
 	switch (config->sample_valid_bits) {
 	case 16:	/* 2 * 16bit packed into 32bit FIFO */
 		data_size = 32;
 		break;
 	default:
-		data_size = config->sample_valid_bits;
+		data_size = config->sample_container_bits;
 	}
 
 	if (data_size > 16)
@@ -242,20 +247,14 @@ static inline int ssp_set_config(struct dai *dai,
 	else
 		sscr0 |= SSCR0_DSIZE(data_size);
 
-	/* watermarks - TODO: do we still need old sscr1 method ?? */
-	sscr1 |= (SSCR1_TX(4) | SSCR1_RX(4));
-
 	/* watermarks - (RFT + 1) should equal DMA SRC_MSIZE */
 	sfifott = (SFIFOTT_TX(8) | SFIFOTT_RX(8));
-#if 0
-	if (dai->config.lbm)
-		sscr1 |= SSCR1_LBM;
-	else
-		sscr1 &= ~SSCR1_LBM;
-#endif
+
 	trace_ssp("coe");
 	ssp_write(dai, SSCR0, sscr0);
 	ssp_write(dai, SSCR1, sscr1);
+	ssp_write(dai, SSCR2, sscr2);
+	ssp_write(dai, SSCR3, sscr3);
 	ssp_write(dai, SSPSP, sspsp);
 	ssp_write(dai, SFIFOTT, sfifott);
 
diff --git a/src/include/reef/ssp.h b/src/include/reef/ssp.h
index 7e557ed..42efb14 100644
--- a/src/include/reef/ssp.h
+++ b/src/include/reef/ssp.h
@@ -55,7 +55,11 @@
 #define SSTSA		0x30
 #define SSRSA		0x34
 #define SSTSS		0x38
+#define SSCR2		0x40
 #define SFIFOTT		0x6C
+#define SSCR3		0x70
+#define SSCR4		0x74
+#define SSCR5		0x78
 
 extern const struct dai_ops ssp_ops;
 
@@ -75,7 +79,7 @@ extern const struct dai_ops ssp_ops;
 #define SSCR0_NCS	(1 << 21)
 #define SSCR0_RIM	(1 << 22)
 #define SSCR0_TUM	(1 << 23)
-#define SSCR0_FRDC	(0x07000000)
+#define SSCR0_FRDC(x)	((x - 1) << 24)
 #define SSCR0_ACS	(1 << 30)
 #define SSCR0_MOD	(1 << 31)
 
@@ -127,6 +131,20 @@ extern const struct dai_ops ssp_ops;
 #define SSPSP_DMYSTOP(x)	((x) << 23)
 #define SSPSP_FSRT		(1 << 25)
 
+/* SSCR3 bits */
+#define SSCR3_I2S_FRM_MST	(1 << 0)
+#define SSCR3_I2S_ENA		(1 << 1)
+#define SSCR3_I2S_FRM_POL	(1 << 2)
+#define SSCR3_I2S_TX_ENA	(1 << 9)
+#define SSCR3_I2S_RX_ENA	(1 << 10)
+#define SSCR3_I2S_CLK_MST	(1 << 16)
+
+/* SSCR4 bits */
+#define SSCR4_FRM_CLOCKS(x)	(x << 7)
+
+/* SSCR5 bits */
+#define SSCR5_FRM_ASRT_CLOCKS(x)	((x - 1) << 1)
+
 /* SFIFOTT bits */
 #define SFIFOTT_TX(x)		(x - 1)
 #define SFIFOTT_RX(x)		((x - 1) << 16)
-- 
2.11.0



More information about the Sound-open-firmware mailing list