[Sound-open-firmware] [PATCH] ssp: clean-up register setup
Clean-up register configurations for SSCR0..5, SSPSP, SFIFOTT
The results are ok in I2S and LEFT_J 24 bits Tested with RT5645 and DA7212
TODO: 1. fix 16 bit issue (right channel lost) 2. test DSP modes 3. connect SSP and DMA watermarks
Signed-off-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com --- src/drivers/ssp.c | 264 ++++++++++++++++++++++++++++++++++++++++++------- src/include/reef/ssp.h | 40 ++++++-- 2 files changed, 259 insertions(+), 45 deletions(-)
diff --git a/src/drivers/ssp.c b/src/drivers/ssp.c index 9eb4934..0ed570c 100644 --- a/src/drivers/ssp.c +++ b/src/drivers/ssp.c @@ -30,6 +30,7 @@ */
#include <errno.h> +#include <stdbool.h> #include <reef/stream.h> #include <reef/ssp.h> #include <reef/alloc.h> @@ -40,6 +41,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) { @@ -47,6 +61,8 @@ static int ssp_context_store(struct dai *dai)
ssp->sscr0 = ssp_read(dai, SSCR0); ssp->sscr1 = ssp_read(dai, SSCR1); + + /* FIXME: need to store sscr2,3,4,5 */ ssp->psp = ssp_read(dai, SSPSP);
return 0; @@ -59,6 +75,7 @@ static int ssp_context_restore(struct dai *dai)
ssp_write(dai, SSCR0, ssp->sscr0); ssp_write(dai, SSCR1, ssp->sscr1); + /* FIXME: need to restore sscr2,3,4,5 */ ssp_write(dai, SSPSP, ssp->psp);
return 0; @@ -73,12 +90,20 @@ static inline int ssp_set_config(struct dai *dai, uint32_t sscr1; uint32_t sscr2; uint32_t sscr3; + uint32_t sscr4; + uint32_t sscr5; uint32_t sspsp; uint32_t sfifott; uint32_t mdiv; uint32_t bdiv; uint32_t data_size; + uint32_t start_delay; + uint32_t active_tx_slots = 2; + uint32_t active_rx_slots = 2; uint32_t frame_len = 0; + bool inverted_frame = false; + bool cfs = false; + bool cbs = false; int ret = 0;
spin_lock(&ssp->lock); @@ -94,34 +119,98 @@ static inline int ssp_set_config(struct dai *dai, trace_ssp("cos");
/* reset SSP settings */ - sscr0 = SSCR0_RIM | SSCR0_TIM; - sscr1 = SSCR1_PINTE | SSCR1_RWOT; - sscr2 = 0x1c1; - sscr3 = 0x2c018; - sspsp = 0; + /* sscr0 dynamic settings are DSS, EDSS, SCR, FRDC, ECS */ + /* + * FIXME: MOD, ACS, NCS are not set, + * no support for network mode for now + */ + sscr0 = SSCR0_PSP | SSCR0_RIM | SSCR0_TIM; + + /* + * FIXME: PINTE and RWOT are not set in sscr1 + * sscr1 = SSCR1_PINTE | SSCR1_RWOT; + */ + + /* sscr1 dynamic settings are TFT, RFT, SFRMDIR, SCLKDIR, SCFR */ + sscr1 = SSCR1_TTE; +#ifdef ENABLE_TIE_RIE /* FIXME: not enabled, difference with SST driver */ + sscr1 |= SSCR1_TIE | SSCR1_RIE; +#endif + + /* sscr2 dynamic setting is SLV_EXT_CLK_RUN_EN */ + sscr2 = SSCR2_URUN_FIX0; + sscr2 |= SSCR2_ASRC_INTR_MASK; +#ifdef ENABLE_SSCR2_FIXES /* FIXME: is this needed ? */ + sscr2 |= SSCR2_UNDRN_FIX_EN | SSCR2_FIFO_EMPTY_FIX_EN; +#endif + + + /* + * sscr3 dynamic settings are FRM_MS_EN, I2S_MODE_EN, I2S_FRM_POL, + * I2S_TX_EN, I2S_RX_EN, I2S_CLK_MST + */ + sscr3 = SSCR3_I2S_TX_SS_FIX_EN | SSCR3_I2S_RX_SS_FIX_EN | + SSCR3_STRETCH_TX | SSCR3_STRETCH_RX | + SSCR3_SYN_FIX_EN; +#ifdef ENABLE_CLK_EDGE_SEL /* FIXME: is this needed ? */ + sscr3 |= SSCR3_CLK_EDGE_SEL; +#endif + + /* sscr4 dynamic settings is TOT_FRAME_PRD */ + sscr4 = 0x0; + + /* sscr4 dynamic settings are FRM_ASRT_CLOCKS and FRM_POLARITY */ + sscr5 = 0x0; + + /* sspsp dynamic settings are SCMODE, SFRMP, DMYSTRT, SFRMWDTH */ + sspsp = SSPSP_ETDS; /* make sure SDO line is tri-stated when inactive */
ssp->config = *config; ssp->params = config->ssp[0];
- /* TODO: allow topology to define SSP clock type */ - config->ssp[0].clk_id = SSP_CLK_EXT; - /* clock masters */ + /* + * On TNG/BYT/CHT, the SSP wrapper generates the fs even in master mode, + * the master/slave choice depends on the clock type + */ + sscr1 |= SSCR1_SFRMDIR; + switch (config->format & SOF_DAI_FMT_MASTER_MASK) { case SOF_DAI_FMT_CBM_CFM: - sscr1 |= SSCR1_SCLKDIR | SSCR1_SFRMDIR; + sscr0 |= SSCR0_ECS; /* external clock used */ + sscr1 |= SSCR1_SCLKDIR; + /* + * FIXME: does SSRC1.SCFR need to be set + * when codec is master ? + */ + sscr2 |= SSCR2_SLV_EXT_CLK_RUN_EN; break; case SOF_DAI_FMT_CBS_CFS: +#ifdef ENABLE_SSRCR1_SCFR /* FIXME: is this needed ? */ sscr1 |= SSCR1_SCFR; - sscr3 |= SSCR3_I2S_FRM_MST | SSCR3_I2S_CLK_MST; +#endif + sscr3 |= SSCR3_FRM_MST_EN; + cfs = true; + cbs = true; break; case SOF_DAI_FMT_CBM_CFS: - sscr1 |= SSCR1_SFRMDIR; + sscr0 |= SSCR0_ECS; /* external clock used */ + sscr1 |= SSCR1_SCLKDIR; + /* + * FIXME: does SSRC1.SCFR need to be set + * when codec is master ? + */ + sscr2 |= SSCR2_SLV_EXT_CLK_RUN_EN; + sscr3 |= SSCR3_FRM_MST_EN; + cfs = true; + /* FIXME: this mode has not been tested */ break; case SOF_DAI_FMT_CBS_CFM: - sscr1 |= SSCR1_SCLKDIR | SSCR1_SFRMDIR | SSCR1_SCFR; - break; - case SSP_CLK_DEFAULT: +#ifdef ENABLE_SSRCR1_SCFR /* FIXME: is this needed ? */ + sscr1 |= SSCR1_SCFR; +#endif + /* FIXME: this mode has not been tested */ + cbs = true; break; default: trace_ssp_error("ec2"); @@ -137,9 +226,11 @@ static inline int ssp_set_config(struct dai *dai, break; case SOF_DAI_FMT_IB_IF: sspsp |= SSPSP_SCMODE(2); + inverted_frame = true; /* handled later with format */ break; case SOF_DAI_FMT_IB_NF: - sspsp |= SSPSP_SCMODE(2) | SSPSP_SFRMP; + sspsp |= SSPSP_SCMODE(2); + inverted_frame = true; /* handled later with format */ break; default: trace_ssp_error("ec3"); @@ -147,6 +238,10 @@ static inline int ssp_set_config(struct dai *dai, goto out; }
+#ifdef CLK_TYPE /* not enabled, keep the code for reference */ + /* TODO: allow topology to define SSP clock type */ + config->ssp[0].clk_id = SSP_CLK_EXT; + /* clock source */ switch (config->ssp[0].clk_id) { case SSP_CLK_AUDIO: @@ -166,6 +261,7 @@ static inline int ssp_set_config(struct dai *dai, ret = -EINVAL; goto out; } +#endif
/* BCLK is generated from MCLK - must be divisable */ if (config->mclk % config->bclk) { @@ -211,20 +307,118 @@ static inline int ssp_set_config(struct dai *dai, switch (config->format & SOF_DAI_FMT_FORMAT_MASK) { case SOF_DAI_FMT_I2S:
+ start_delay = 1; + /* enable I2S mode */ - sscr3 |= SSCR3_I2S_ENA | SSCR3_I2S_TX_ENA | SSCR3_I2S_RX_ENA; - sscr0 |= SSCR0_PSP; + sscr3 |= SSCR3_I2S_MODE_EN | SSCR3_I2S_TX_EN | SSCR3_I2S_RX_EN; + + /* set asserted frame length */ + frame_len = config->sample_container_bits; + + /* handle frame polarity, I2S default is falling/active low */ + sspsp |= SSPSP_SFRMP(!inverted_frame); + sscr3 |= SSCR3_I2S_FRM_POL(!inverted_frame); + + if (cbs) { + /* + * keep RX functioning on a TX underflow + * (I2S/LEFT_J master only) + */ + sscr3 |= SSCR3_MST_CLK_EN; + + /* + * total frame period (both asserted and + * deasserted time of frame + */ + sscr4 |= SSCR4_TOT_FRM_PRD(frame_len << 1); + } + + break; + + case SOF_DAI_FMT_LEFT_J: + + start_delay = 0; + + /* apparently we need the same initialization as for I2S */ + sscr3 |= SSCR3_I2S_MODE_EN | SSCR3_I2S_TX_EN | SSCR3_I2S_RX_EN;
/* set asserted frame length */ frame_len = config->sample_container_bits; + + /* LEFT_J default is rising/active high, opposite of I2S */ + sspsp |= SSPSP_SFRMP(inverted_frame); + sscr3 |= SSCR3_I2S_FRM_POL(inverted_frame); + + if (cbs) { + /* + * keep RX functioning on a TX underflow + * (I2S/LEFT_J master only) + */ + sscr3 |= SSCR3_MST_CLK_EN; + + /* + * total frame period (both asserted and + * deasserted time of frame + */ + sscr4 |= SSCR4_TOT_FRM_PRD(frame_len << 1); + } + break; case SOF_DAI_FMT_DSP_A: - sscr0 |= SSCR0_PSP | SSCR0_MOD | SSCR0_FRDC(config->num_slots); - sspsp |= SSPSP_SFRMWDTH(1) | SSPSP_SFRMDLY(2); + + start_delay = 1; + + sscr0 |= SSCR0_MOD | SSCR0_FRDC(config->num_slots); + + /* set asserted frame length */ + frame_len = 1; + + /* handle frame polarity, DSP_A default is rising/active high */ + sspsp |= SSPSP_SFRMP(inverted_frame); + if (cfs) { + /* set sscr frame polarity in DSP/master mode only */ + sscr5 |= SSCR5_FRM_POLARITY(inverted_frame); + } + + /* + * total frame period (both asserted and + * deasserted time of frame) + */ + if (cbs) + sscr4 |= SSCR4_TOT_FRM_PRD(config->num_slots * + config->sample_container_bits); + + 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: - sscr0 |= SSCR0_PSP | SSCR0_MOD | SSCR0_FRDC(config->num_slots); - sspsp |= SSPSP_SFRMWDTH(1); + + start_delay = 0; + + sscr0 |= SSCR0_MOD | SSCR0_FRDC(config->num_slots); + + /* set asserted frame length */ + frame_len = 1; + + /* handle frame polarity, DSP_A default is rising/active high */ + sspsp |= SSPSP_SFRMP(inverted_frame); + if (cfs) { + /* set sscr frame polarity in DSP/master mode only */ + sscr5 |= SSCR5_FRM_POLARITY(inverted_frame); + } + + /* + * total frame period (both asserted and + * deasserted time of frame + */ + if (cbs) + sscr4 |= SSCR4_TOT_FRM_PRD(config->num_slots * + config->sample_container_bits); + + active_tx_slots = hweight_32(config->tx_slot_mask); + active_rx_slots = hweight_32(config->rx_slot_mask); + break; default: trace_ssp_error("eca"); @@ -232,35 +426,35 @@ static inline int ssp_set_config(struct dai *dai, 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); + sspsp |= SSPSP_DMYSTRT(start_delay); + sspsp |= SSPSP_SFRMWDTH(frame_len); + sscr5 |= SSCR5_FRM_ASRT_CLOCKS(frame_len);
- /* sample data size on SSP FIFO */ - if (config->sample_valid_bits == 16) - /* 2 * 16bit packed into 32bit FIFO */ - data_size = 32; - else - data_size = config->sample_container_bits; + data_size = config->sample_valid_bits;
if (data_size > 16) sscr0 |= (SSCR0_EDSS | SSCR0_DSIZE(data_size - 16)); else sscr0 |= SSCR0_DSIZE(data_size);
- /* watermarks - (RFT + 1) should equal DMA SRC_MSIZE */ - sfifott = (SFIFOTT_TX(4) | SFIFOTT_RX(12)); + /* FIXME: + * watermarks - (RFT + 1) should equal DMA SRC_MSIZE + */ + sfifott = (SFIFOTT_TX(2*active_tx_slots) | + SFIFOTT_RX(2*active_rx_slots));
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, SSCR4, sscr4); + ssp_write(dai, SSCR5, sscr5); ssp_write(dai, SSPSP, sspsp); ssp_write(dai, SFIFOTT, sfifott); + ssp_write(dai, SSTSA, config->tx_slot_mask); + ssp_write(dai, SSRSA, config->rx_slot_mask);
ssp->state[DAI_DIR_PLAYBACK] = COMP_STATE_PREPARE; ssp->state[DAI_DIR_CAPTURE] = COMP_STATE_PREPARE; diff --git a/src/include/reef/ssp.h b/src/include/reef/ssp.h index e3da690..c00d14c 100644 --- a/src/include/reef/ssp.h +++ b/src/include/reef/ssp.h @@ -91,9 +91,9 @@ extern const struct dai_ops ssp_ops; #define SSCR1_SPH (1 << 4) #define SSCR1_MWDS (1 << 5) #define SSCR1_TFT_MASK (0x000003c0) -#define SSCR1_TX(x) (((x) - 1) << 6) +#define SSCR1_TFT(x) (((x) - 1) << 6) #define SSCR1_RFT_MASK (0x00003c00) -#define SSCR1_RX(x) (((x) - 1) << 10) +#define SSCR1_RFT(x) (((x) - 1) << 10) #define SSCR1_EFWR (1 << 14) #define SSCR1_STRF (1 << 15) #define SSCR1_IFS (1 << 16) @@ -112,6 +112,18 @@ extern const struct dai_ops ssp_ops; #define SSCR1_TTE (1 << 30) #define SSCR1_TTELP (1 << 31)
+/* SSCR2 bits */ +#define SSCR2_URUN_FIX0 (1 << 0) +#define SSCR2_URUN_FIX1 (1 << 1) +#define SSCR2_SLV_EXT_CLK_RUN_EN (1 << 2) +#define SSCR2_CLK_DEL_EN (1 << 3) +#define SSCR2_UNDRN_FIX_EN (1 << 6) +#define SSCR2_FIFO_EMPTY_FIX_EN (1 << 7) +#define SSCR2_ASRC_CNTR_EN (1 << 8) +#define SSCR2_ASRC_CNTR_CLR (1 << 9) +#define SSCR2_ASRC_FRM_CNRT_EN (1 << 10) +#define SSCR2_ASRC_INTR_MASK (1 << 11) + /* SSR bits */ #define SSSR_TNF (1 << 2) #define SSSR_RNE (1 << 3) @@ -122,7 +134,7 @@ extern const struct dai_ops ssp_ops;
/* SSPSP bits */ #define SSPSP_SCMODE(x) ((x) << 0) -#define SSPSP_SFRMP (1 << 2) +#define SSPSP_SFRMP(x) ((x) << 2) #define SSPSP_ETDS (1 << 3) #define SSPSP_STRTDLY(x) ((x) << 4) #define SSPSP_DMYSTRT(x) ((x) << 7) @@ -132,18 +144,26 @@ extern const struct dai_ops ssp_ops; #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) +#define SSCR3_FRM_MST_EN (1 << 0) +#define SSCR3_I2S_MODE_EN (1 << 1) +#define SSCR3_I2S_FRM_POL(x) ((x) << 2) +#define SSCR3_I2S_TX_SS_FIX_EN (1 << 3) +#define SSCR3_I2S_RX_SS_FIX_EN (1 << 4) +#define SSCR3_I2S_TX_EN (1 << 9) +#define SSCR3_I2S_RX_EN (1 << 10) +#define SSCR3_CLK_EDGE_SEL (1 << 12) +#define SSCR3_STRETCH_TX (1 << 14) +#define SSCR3_STRETCH_RX (1 << 15) +#define SSCR3_MST_CLK_EN (1 << 16) +#define SSCR3_SYN_FIX_EN (1 << 17) +
/* SSCR4 bits */ -#define SSCR4_FRM_CLOCKS(x) ((x) << 7) +#define SSCR4_TOT_FRM_PRD(x) ((x) << 7)
/* SSCR5 bits */ #define SSCR5_FRM_ASRT_CLOCKS(x) (((x) - 1) << 1) +#define SSCR5_FRM_POLARITY(x) ((x) << 0)
/* SFIFOTT bits */ #define SFIFOTT_TX(x) ((x) - 1)
On Tue, 2017-11-14 at 17:29 -0600, Pierre-Louis Bossart wrote:
Clean-up register configurations for SSCR0..5, SSPSP, SFIFOTT
The results are ok in I2S and LEFT_J 24 bits Tested with RT5645 and DA7212
Thanks, Applied.
Btw, can you add a file rename ssp.c -> byt-ssp.c to your TODO list :)
Liam
participants (2)
-
Liam Girdwood
-
Pierre-Louis Bossart