[PATCH v2 0/2] refine and clean code for synchronous mode
refine and clean code for synchronous mode
Shengjiu Wang (2): ASoC: fsl_sai: Clean code for synchronous mode ASoC: fsl_sai: Refine enable and disable sequence for synchronous mode
changes in v2: - Split the commit - refine the sequence in trigger stop
sound/soc/fsl/fsl_sai.c | 133 ++++++++++++++++++++++++++-------------- 1 file changed, 86 insertions(+), 47 deletions(-)
Tx synchronous with Rx: The RMR is the word mask register, it is used to mask any word in the frame, it is not relating to clock generation, So it is no need to be changed when Tx is going to be enabled.
Rx synchronous with Tx: The TMR is the word mask register, it is used to mask any word in the frame, it is not relating to clock generation, So it is no need to be changed when Rx is going to be enabled.
Signed-off-by: Shengjiu Wang shengjiu.wang@nxp.com --- sound/soc/fsl/fsl_sai.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-)
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index cdff739924e2..84714fe7144c 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -470,8 +470,7 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, /* * For SAI master mode, when Tx(Rx) sync with Rx(Tx) clock, Rx(Tx) will * generate bclk and frame clock for Tx(Rx), we should set RCR4(TCR4), - * RCR5(TCR5) and RMR(TMR) for playback(capture), or there will be sync - * error. + * RCR5(TCR5) for playback(capture), or there will be sync error. */
if (!sai->is_slave_mode) { @@ -482,8 +481,6 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, regmap_update_bits(sai->regmap, FSL_SAI_TCR5(ofs), FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK | FSL_SAI_CR5_FBT_MASK, val_cr5); - regmap_write(sai->regmap, FSL_SAI_TMR, - ~0UL - ((1 << channels) - 1)); } else if (!sai->synchronous[RX] && sai->synchronous[TX] && tx) { regmap_update_bits(sai->regmap, FSL_SAI_RCR4(ofs), FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK, @@ -491,8 +488,6 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, regmap_update_bits(sai->regmap, FSL_SAI_RCR5(ofs), FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK | FSL_SAI_CR5_FBT_MASK, val_cr5); - regmap_write(sai->regmap, FSL_SAI_RMR, - ~0UL - ((1 << channels) - 1)); } }
On Wed, Aug 05, 2020 at 10:23:52AM +0800, Shengjiu Wang wrote:
Tx synchronous with Rx: The RMR is the word mask register, it is used to mask any word in the frame, it is not relating to clock generation, So it is no need to be changed when Tx is going to be enabled.
Rx synchronous with Tx: The TMR is the word mask register, it is used to mask any word in the frame, it is not relating to clock generation, So it is no need to be changed when Rx is going to be enabled.
Signed-off-by: Shengjiu Wang shengjiu.wang@nxp.com
Can you rename the PATCH subject to something more specific? For example, "Drop TMR/RMR settings for synchronous mode".
Please add this once it's addressed: Reviewed-by: Nicolin Chen nicoleotsuka@gmail.com
Tx synchronous with Rx: The TCSR.TE is no need to enabled when only Rx is going to be enabled. Check if need to disable RSCR.RE before disabling TCSR.TE.
Rx synchronous with Tx: The RCSR.RE is no need to enabled when only Tx is going to be enabled. Check if need to disable TSCR.RE before disabling RCSR.TE.
Signed-off-by: Shengjiu Wang shengjiu.wang@nxp.com --- sound/soc/fsl/fsl_sai.c | 126 +++++++++++++++++++++++++++------------- 1 file changed, 85 insertions(+), 41 deletions(-)
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 84714fe7144c..f30c4e7b5221 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -517,6 +517,56 @@ static int fsl_sai_hw_free(struct snd_pcm_substream *substream, return 0; }
+/** + * fsl_sai_dir_is_synced - Check if stream is synced by the opposite stream + * + * SAI supports synchronous mode using bit/frame clocks of either Transmitter's + * or Receiver's for both streams. This function is used to check if clocks of + * the stream's are synced by the opposite stream. + * + * @sai: SAI context + * @dir: stream direction + */ +static inline bool fsl_sai_dir_is_synced(struct fsl_sai *sai, int dir) +{ + int adir = (dir == TX) ? RX : TX; + + /* current dir in async mode while opposite dir in sync mode */ + return !sai->synchronous[dir] && sai->synchronous[adir]; +} + +static void fsl_sai_config_disable(struct fsl_sai *sai, int dir) +{ + unsigned int ofs = sai->soc_data->reg_offset; + bool tx = dir == TX; + u32 xcsr, count = 100; + + regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs), + FSL_SAI_CSR_TERE, 0); + + /* TERE will remain set till the end of current frame */ + do { + udelay(10); + regmap_read(sai->regmap, FSL_SAI_xCSR(tx, ofs), &xcsr); + } while (--count && xcsr & FSL_SAI_CSR_TERE); + + regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs), + FSL_SAI_CSR_FR, FSL_SAI_CSR_FR); + + /* + * For sai master mode, after several open/close sai, + * there will be no frame clock, and can't recover + * anymore. Add software reset to fix this issue. + * This is a hardware bug, and will be fix in the + * next sai version. + */ + if (!sai->is_slave_mode) { + /* Software Reset */ + regmap_write(sai->regmap, FSL_SAI_xCSR(tx, ofs), FSL_SAI_CSR_SR); + /* Clear SR bit to finish the reset */ + regmap_write(sai->regmap, FSL_SAI_xCSR(tx, ofs), 0); + } +}
static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *cpu_dai) @@ -525,7 +575,9 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, unsigned int ofs = sai->soc_data->reg_offset;
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; - u32 xcsr, count = 100; + int adir = tx ? RX : TX; + int dir = tx ? TX : RX; + u32 xcsr;
/* * Asynchronous mode: Clear SYNC for both Tx and Rx. @@ -548,10 +600,22 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs), FSL_SAI_CSR_FRDE, FSL_SAI_CSR_FRDE);
- regmap_update_bits(sai->regmap, FSL_SAI_RCSR(ofs), - FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE); - regmap_update_bits(sai->regmap, FSL_SAI_TCSR(ofs), + regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs), FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE); + /* + * Enable the opposite direction for synchronous mode + * 1. Tx sync with Rx: only set RE for Rx; set TE & RE for Tx + * 2. Rx sync with Tx: only set TE for Tx; set RE & TE for Rx + * + * RM recommends to enable RE after TE for case 1 and to enable + * TE after RE for case 2, but we here may not always guarantee + * that happens: "arecord 1.wav; aplay 2.wav" in case 1 enables + * TE after RE, which is against what RM recommends but should + * be safe to do, judging by years of testing results. + */ + if (fsl_sai_dir_is_synced(sai, adir)) + regmap_update_bits(sai->regmap, FSL_SAI_xCSR((!tx), ofs), + FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE);
regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs), FSL_SAI_CSR_xIE_MASK, FSL_SAI_FLAGS); @@ -566,43 +630,23 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
/* Check if the opposite FRDE is also disabled */ regmap_read(sai->regmap, FSL_SAI_xCSR(!tx, ofs), &xcsr); - if (!(xcsr & FSL_SAI_CSR_FRDE)) { - /* Disable both directions and reset their FIFOs */ - regmap_update_bits(sai->regmap, FSL_SAI_TCSR(ofs), - FSL_SAI_CSR_TERE, 0); - regmap_update_bits(sai->regmap, FSL_SAI_RCSR(ofs), - FSL_SAI_CSR_TERE, 0); - - /* TERE will remain set till the end of current frame */ - do { - udelay(10); - regmap_read(sai->regmap, - FSL_SAI_xCSR(tx, ofs), &xcsr); - } while (--count && xcsr & FSL_SAI_CSR_TERE); - - regmap_update_bits(sai->regmap, FSL_SAI_TCSR(ofs), - FSL_SAI_CSR_FR, FSL_SAI_CSR_FR); - regmap_update_bits(sai->regmap, FSL_SAI_RCSR(ofs), - FSL_SAI_CSR_FR, FSL_SAI_CSR_FR); - - /* - * For sai master mode, after several open/close sai, - * there will be no frame clock, and can't recover - * anymore. Add software reset to fix this issue. - * This is a hardware bug, and will be fix in the - * next sai version. - */ - if (!sai->is_slave_mode) { - /* Software Reset for both Tx and Rx */ - regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), - FSL_SAI_CSR_SR); - regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), - FSL_SAI_CSR_SR); - /* Clear SR bit to finish the reset */ - regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), 0); - regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), 0); - } - } + + /* + * If opposite stream provides clocks for synchronous mode and + * it is inactive, disable it before disabling the current one + */ + if (fsl_sai_dir_is_synced(sai, adir) && !(xcsr & FSL_SAI_CSR_FRDE)) + fsl_sai_config_disable(sai, adir); + + /* + * Disable current stream if either of: + * 1. current stream doesn't provide clocks for synchronous mode + * 2. current stream provides clocks for synchronous mode but no + * more stream is active. + */ + if (!fsl_sai_dir_is_synced(sai, dir) || !(xcsr & FSL_SAI_CSR_FRDE)) + fsl_sai_config_disable(sai, dir); + break; default: return -EINVAL;
On Wed, Aug 05, 2020 at 10:23:53AM +0800, Shengjiu Wang wrote:
Tx synchronous with Rx: The TCSR.TE is no need to enabled when only Rx is going to be enabled. Check if need to disable RSCR.RE before disabling TCSR.TE.
Rx synchronous with Tx: The RCSR.RE is no need to enabled when only Tx is going to be enabled. Check if need to disable TSCR.RE before disabling RCSR.TE.
Please add to the commit log more context such as what we have discussed: what's the problem of the current driver, and why we _have_to_ apply this change though it's sightly against what RM recommends.
(If thing is straightforward, it's okay to make the text short. Yet I believe that this change deserves more than these lines.)
One info that you should mention -- also the main reason why I'm convinced to add this change: trigger() is still in the shape of the early version where we only supported one operation mode -- Tx synchronous with Rx. So we need an update for other modes.
Signed-off-by: Shengjiu Wang shengjiu.wang@nxp.com
The git-diff part looks good, please add this in next ver.:
Reviewed-by: Nicolin Chen nicoleotsuka@gmail.com
Btw, the new fsl_sai_dir_is_synced() can be probably applied to other places with a followup patch.
On Wed, Aug 5, 2020 at 12:13 PM Nicolin Chen nicoleotsuka@gmail.com wrote:
On Wed, Aug 05, 2020 at 10:23:53AM +0800, Shengjiu Wang wrote:
Tx synchronous with Rx: The TCSR.TE is no need to enabled when only Rx is going to be enabled. Check if need to disable RSCR.RE before disabling TCSR.TE.
Rx synchronous with Tx: The RCSR.RE is no need to enabled when only Tx is going to be enabled. Check if need to disable TSCR.RE before disabling RCSR.TE.
Please add to the commit log more context such as what we have discussed: what's the problem of the current driver, and why we _have_to_ apply this change though it's sightly against what RM recommends.
(If thing is straightforward, it's okay to make the text short. Yet I believe that this change deserves more than these lines.)
One info that you should mention -- also the main reason why I'm convinced to add this change: trigger() is still in the shape of the early version where we only supported one operation mode -- Tx synchronous with Rx. So we need an update for other modes.
Signed-off-by: Shengjiu Wang shengjiu.wang@nxp.com
The git-diff part looks good, please add this in next ver.:
Reviewed-by: Nicolin Chen nicoleotsuka@gmail.com
Btw, the new fsl_sai_dir_is_synced() can be probably applied to other places with a followup patch.
Do you mean move it to the beginning of this file?
best regards wang shengjiu
On Wed, Aug 05, 2020 at 01:03:37PM +0800, Shengjiu Wang wrote:
Btw, the new fsl_sai_dir_is_synced() can be probably applied to other places with a followup patch.
Do you mean move it to the beginning of this file?
There are other existing places testing "sync[tx] && !sync[!tx]" so you may submit another change to replace them. But, yea, will be a good idea to move that helper function to the top.
participants (3)
-
Nicolin Chen
-
Shengjiu Wang
-
Shengjiu Wang