[alsa-devel] [PATCH] ASoC: ti: davinci-mcasp: Improve serializer handling in multi AXR setups
When multiple serializers are used we need to track the number of serializers used by the other stream direction to avoid killing data lines when the first stream used more serializers than the second would need. We are still protected against the case when the second stream uses more serializers which had affected the running stream as well.
To take advantage of the improved serializer logic we need to modify the channel constraints rule as well to allow the use of multiple serializers for the second stream as additional ones will not affect the FS/BCLK on the bus.
Signed-off-by: Peter Ujfalusi peter.ujfalusi@ti.com --- sound/soc/ti/davinci-mcasp.c | 92 +++++++++++++++++++++--------------- 1 file changed, 53 insertions(+), 39 deletions(-)
diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c index 6a87455d7c42..7c2081b63a60 100644 --- a/sound/soc/ti/davinci-mcasp.c +++ b/sound/soc/ti/davinci-mcasp.c @@ -109,6 +109,7 @@ struct davinci_mcasp {
/* Used for comstraint setting on the second stream */ u32 channels; + u8 active_serializers[2];
#ifdef CONFIG_GPIOLIB struct gpio_chip gpio_chip; @@ -814,6 +815,7 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream, u8 rx_ser = 0; u8 slots = mcasp->tdm_slots; u8 max_active_serializers = (channels + slots - 1) / slots; + u8 max_rx_serializers, max_tx_serializers; int active_serializers, numevt; u32 reg; /* Default configuration */ @@ -823,22 +825,28 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream, if (stream == SNDRV_PCM_STREAM_PLAYBACK) { mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF); mcasp_clr_bits(mcasp, DAVINCI_MCASP_XEVTCTL_REG, TXDATADMADIS); + max_tx_serializers = max_active_serializers; + max_rx_serializers = + mcasp->active_serializers[SNDRV_PCM_STREAM_CAPTURE]; } else { mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF); mcasp_clr_bits(mcasp, DAVINCI_MCASP_REVTCTL_REG, RXDATADMADIS); + max_tx_serializers = + mcasp->active_serializers[SNDRV_PCM_STREAM_PLAYBACK]; + max_rx_serializers = max_active_serializers; }
for (i = 0; i < mcasp->num_serializer; i++) { mcasp_set_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i), mcasp->serial_dir[i]); if (mcasp->serial_dir[i] == TX_MODE && - tx_ser < max_active_serializers) { + tx_ser < max_tx_serializers) { mcasp_mod_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i), mcasp->dismod, DISMOD_MASK); set_bit(PIN_BIT_AXR(i), &mcasp->pdir); tx_ser++; } else if (mcasp->serial_dir[i] == RX_MODE && - rx_ser < max_active_serializers) { + rx_ser < max_rx_serializers) { clear_bit(PIN_BIT_AXR(i), &mcasp->pdir); rx_ser++; } else { @@ -885,7 +893,8 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream, } else { dma_data->maxburst = 0; } - return 0; + + goto out; }
if (period_words % active_serializers) { @@ -915,6 +924,9 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream, numevt = 0; dma_data->maxburst = numevt;
+out: + mcasp->active_serializers[stream] = active_serializers; + return 0; }
@@ -1154,6 +1166,37 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, int period_size = params_period_size(params); int ret;
+ switch (params_format(params)) { + case SNDRV_PCM_FORMAT_U8: + case SNDRV_PCM_FORMAT_S8: + word_length = 8; + break; + + case SNDRV_PCM_FORMAT_U16_LE: + case SNDRV_PCM_FORMAT_S16_LE: + word_length = 16; + break; + + case SNDRV_PCM_FORMAT_U24_3LE: + case SNDRV_PCM_FORMAT_S24_3LE: + word_length = 24; + break; + + case SNDRV_PCM_FORMAT_U24_LE: + case SNDRV_PCM_FORMAT_S24_LE: + word_length = 24; + break; + + case SNDRV_PCM_FORMAT_U32_LE: + case SNDRV_PCM_FORMAT_S32_LE: + word_length = 32; + break; + + default: + printk(KERN_WARNING "davinci-mcasp: unsupported PCM format"); + return -EINVAL; + } + ret = davinci_mcasp_set_dai_fmt(cpu_dai, mcasp->dai_fmt); if (ret) return ret; @@ -1188,37 +1231,6 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, if (ret) return ret;
- switch (params_format(params)) { - case SNDRV_PCM_FORMAT_U8: - case SNDRV_PCM_FORMAT_S8: - word_length = 8; - break; - - case SNDRV_PCM_FORMAT_U16_LE: - case SNDRV_PCM_FORMAT_S16_LE: - word_length = 16; - break; - - case SNDRV_PCM_FORMAT_U24_3LE: - case SNDRV_PCM_FORMAT_S24_3LE: - word_length = 24; - break; - - case SNDRV_PCM_FORMAT_U24_LE: - case SNDRV_PCM_FORMAT_S24_LE: - word_length = 24; - break; - - case SNDRV_PCM_FORMAT_U32_LE: - case SNDRV_PCM_FORMAT_S32_LE: - word_length = 32; - break; - - default: - printk(KERN_WARNING "davinci-mcasp: unsupported PCM format"); - return -EINVAL; - } - davinci_config_channel_size(mcasp, word_length);
if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE) @@ -1405,12 +1417,13 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream, max_channels *= tdm_slots; /* * If the already active stream has less channels than the calculated - * limnit based on the seirializers * tdm_slots, we need to use that as - * a constraint for the second stream. - * Otherwise (first stream or less allowed channels) we use the - * calculated constraint. + * limit based on the seirializers * tdm_slots, and only one serializer + * is in use we need to use that as a constraint for the second stream. + * Otherwise (first stream or less allowed channels or more than one + * serializer in use) we use the calculated constraint. */ - if (mcasp->channels && mcasp->channels < max_channels) + if (mcasp->channels && mcasp->channels < max_channels && + ruledata->serializers == 1) max_channels = mcasp->channels; /* * But we can always allow channels upto the amount of @@ -1471,6 +1484,7 @@ static void davinci_mcasp_shutdown(struct snd_pcm_substream *substream, struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
mcasp->substreams[substream->stream] = NULL; + mcasp->active_serializers[substream->stream] = 0;
if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) return;
The patch
ASoC: ti: davinci-mcasp: Improve serializer handling in multi AXR setups
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.4
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From b7989e271e9f7fd4edb4166cd2a79b980c4b6136 Mon Sep 17 00:00:00 2001
From: Peter Ujfalusi peter.ujfalusi@ti.com Date: Thu, 25 Jul 2019 11:34:32 +0300 Subject: [PATCH] ASoC: ti: davinci-mcasp: Improve serializer handling in multi AXR setups
When multiple serializers are used we need to track the number of serializers used by the other stream direction to avoid killing data lines when the first stream used more serializers than the second would need. We are still protected against the case when the second stream uses more serializers which had affected the running stream as well.
To take advantage of the improved serializer logic we need to modify the channel constraints rule as well to allow the use of multiple serializers for the second stream as additional ones will not affect the FS/BCLK on the bus.
Signed-off-by: Peter Ujfalusi peter.ujfalusi@ti.com Link: https://lore.kernel.org/r/20190725083432.7419-1-peter.ujfalusi@ti.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/ti/davinci-mcasp.c | 92 +++++++++++++++++++++--------------- 1 file changed, 53 insertions(+), 39 deletions(-)
diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c index 09ba3d3c70a0..c3a2c53fdb3a 100644 --- a/sound/soc/ti/davinci-mcasp.c +++ b/sound/soc/ti/davinci-mcasp.c @@ -109,6 +109,7 @@ struct davinci_mcasp {
/* Used for comstraint setting on the second stream */ u32 channels; + u8 active_serializers[2];
#ifdef CONFIG_GPIOLIB struct gpio_chip gpio_chip; @@ -813,6 +814,7 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream, u8 rx_ser = 0; u8 slots = mcasp->tdm_slots; u8 max_active_serializers = (channels + slots - 1) / slots; + u8 max_rx_serializers, max_tx_serializers; int active_serializers, numevt; u32 reg; /* Default configuration */ @@ -822,22 +824,28 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream, if (stream == SNDRV_PCM_STREAM_PLAYBACK) { mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF); mcasp_clr_bits(mcasp, DAVINCI_MCASP_XEVTCTL_REG, TXDATADMADIS); + max_tx_serializers = max_active_serializers; + max_rx_serializers = + mcasp->active_serializers[SNDRV_PCM_STREAM_CAPTURE]; } else { mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF); mcasp_clr_bits(mcasp, DAVINCI_MCASP_REVTCTL_REG, RXDATADMADIS); + max_tx_serializers = + mcasp->active_serializers[SNDRV_PCM_STREAM_PLAYBACK]; + max_rx_serializers = max_active_serializers; }
for (i = 0; i < mcasp->num_serializer; i++) { mcasp_set_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i), mcasp->serial_dir[i]); if (mcasp->serial_dir[i] == TX_MODE && - tx_ser < max_active_serializers) { + tx_ser < max_tx_serializers) { mcasp_mod_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i), mcasp->dismod, DISMOD_MASK); set_bit(PIN_BIT_AXR(i), &mcasp->pdir); tx_ser++; } else if (mcasp->serial_dir[i] == RX_MODE && - rx_ser < max_active_serializers) { + rx_ser < max_rx_serializers) { clear_bit(PIN_BIT_AXR(i), &mcasp->pdir); rx_ser++; } else { @@ -884,7 +892,8 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream, } else { dma_data->maxburst = 0; } - return 0; + + goto out; }
if (period_words % active_serializers) { @@ -914,6 +923,9 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream, numevt = 0; dma_data->maxburst = numevt;
+out: + mcasp->active_serializers[stream] = active_serializers; + return 0; }
@@ -1153,6 +1165,37 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, int period_size = params_period_size(params); int ret;
+ switch (params_format(params)) { + case SNDRV_PCM_FORMAT_U8: + case SNDRV_PCM_FORMAT_S8: + word_length = 8; + break; + + case SNDRV_PCM_FORMAT_U16_LE: + case SNDRV_PCM_FORMAT_S16_LE: + word_length = 16; + break; + + case SNDRV_PCM_FORMAT_U24_3LE: + case SNDRV_PCM_FORMAT_S24_3LE: + word_length = 24; + break; + + case SNDRV_PCM_FORMAT_U24_LE: + case SNDRV_PCM_FORMAT_S24_LE: + word_length = 24; + break; + + case SNDRV_PCM_FORMAT_U32_LE: + case SNDRV_PCM_FORMAT_S32_LE: + word_length = 32; + break; + + default: + printk(KERN_WARNING "davinci-mcasp: unsupported PCM format"); + return -EINVAL; + } + ret = davinci_mcasp_set_dai_fmt(cpu_dai, mcasp->dai_fmt); if (ret) return ret; @@ -1187,37 +1230,6 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, if (ret) return ret;
- switch (params_format(params)) { - case SNDRV_PCM_FORMAT_U8: - case SNDRV_PCM_FORMAT_S8: - word_length = 8; - break; - - case SNDRV_PCM_FORMAT_U16_LE: - case SNDRV_PCM_FORMAT_S16_LE: - word_length = 16; - break; - - case SNDRV_PCM_FORMAT_U24_3LE: - case SNDRV_PCM_FORMAT_S24_3LE: - word_length = 24; - break; - - case SNDRV_PCM_FORMAT_U24_LE: - case SNDRV_PCM_FORMAT_S24_LE: - word_length = 24; - break; - - case SNDRV_PCM_FORMAT_U32_LE: - case SNDRV_PCM_FORMAT_S32_LE: - word_length = 32; - break; - - default: - printk(KERN_WARNING "davinci-mcasp: unsupported PCM format"); - return -EINVAL; - } - davinci_config_channel_size(mcasp, word_length);
if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE) @@ -1404,12 +1416,13 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream, max_channels *= tdm_slots; /* * If the already active stream has less channels than the calculated - * limnit based on the seirializers * tdm_slots, we need to use that as - * a constraint for the second stream. - * Otherwise (first stream or less allowed channels) we use the - * calculated constraint. + * limit based on the seirializers * tdm_slots, and only one serializer + * is in use we need to use that as a constraint for the second stream. + * Otherwise (first stream or less allowed channels or more than one + * serializer in use) we use the calculated constraint. */ - if (mcasp->channels && mcasp->channels < max_channels) + if (mcasp->channels && mcasp->channels < max_channels && + ruledata->serializers == 1) max_channels = mcasp->channels; /* * But we can always allow channels upto the amount of @@ -1470,6 +1483,7 @@ static void davinci_mcasp_shutdown(struct snd_pcm_substream *substream, struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
mcasp->substreams[substream->stream] = NULL; + mcasp->active_serializers[substream->stream] = 0;
if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) return;
participants (2)
-
Mark Brown
-
Peter Ujfalusi