[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