| From e958b5884725dac86d36c1e7afe5a55f31feb0b2 Mon Sep 17 00:00:00 2001 |
| From: Robert Hancock <robert.hancock@calian.com> |
| Date: Fri, 7 Jan 2022 15:47:06 -0600 |
| Subject: ASoC: xilinx: xlnx_formatter_pcm: Make buffer bytes multiple of period bytes |
| |
| From: Robert Hancock <robert.hancock@calian.com> |
| |
| commit e958b5884725dac86d36c1e7afe5a55f31feb0b2 upstream. |
| |
| This patch is based on one in the Xilinx kernel tree, "ASoc: xlnx: Make |
| buffer bytes multiple of period bytes" by Devarsh Thakkar. The same |
| issue exists in the mainline version of the driver. The original |
| patch description is as follows: |
| |
| "The Xilinx Audio Formatter IP has a constraint on period |
| bytes to be multiple of 64. This leads to driver changing |
| the period size to suitable frames such that period bytes |
| are multiple of 64. |
| |
| Now since period bytes and period size are updated but not |
| the buffer bytes, this may make the buffer bytes unaligned |
| and not multiple of period bytes. |
| |
| When this happens we hear popping noise as while DMA is being |
| done the buffer bytes are not enough to complete DMA access |
| for last period of frame within the application buffer boundary. |
| |
| To avoid this, align buffer bytes too as multiple of 64, and |
| set another constraint to always enforce number of periods as |
| integer. Now since, there is already a rule in alsa core |
| to enforce Buffer size = Number of Periods * Period Size |
| this automatically aligns buffer bytes as multiple of period |
| bytes." |
| |
| Fixes: 6f6c3c36f091 ("ASoC: xlnx: add pcm formatter platform driver") |
| Cc: Devarsh Thakkar <devarsh.thakkar@xilinx.com> |
| Signed-off-by: Robert Hancock <robert.hancock@calian.com> |
| Link: https://lore.kernel.org/r/20220107214711.1100162-2-robert.hancock@calian.com |
| Signed-off-by: Mark Brown <broonie@kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| sound/soc/xilinx/xlnx_formatter_pcm.c | 27 ++++++++++++++++++++++++--- |
| 1 file changed, 24 insertions(+), 3 deletions(-) |
| |
| --- a/sound/soc/xilinx/xlnx_formatter_pcm.c |
| +++ b/sound/soc/xilinx/xlnx_formatter_pcm.c |
| @@ -37,6 +37,7 @@ |
| #define XLNX_AUD_XFER_COUNT 0x28 |
| #define XLNX_AUD_CH_STS_START 0x2C |
| #define XLNX_BYTES_PER_CH 0x44 |
| +#define XLNX_AUD_ALIGN_BYTES 64 |
| |
| #define AUD_STS_IOC_IRQ_MASK BIT(31) |
| #define AUD_STS_CH_STS_MASK BIT(29) |
| @@ -368,12 +369,32 @@ static int xlnx_formatter_pcm_open(struc |
| snd_soc_set_runtime_hwparams(substream, &xlnx_pcm_hardware); |
| runtime->private_data = stream_data; |
| |
| - /* Resize the period size divisible by 64 */ |
| + /* Resize the period bytes as divisible by 64 */ |
| err = snd_pcm_hw_constraint_step(runtime, 0, |
| - SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64); |
| + SNDRV_PCM_HW_PARAM_PERIOD_BYTES, |
| + XLNX_AUD_ALIGN_BYTES); |
| if (err) { |
| dev_err(component->dev, |
| - "unable to set constraint on period bytes\n"); |
| + "Unable to set constraint on period bytes\n"); |
| + return err; |
| + } |
| + |
| + /* Resize the buffer bytes as divisible by 64 */ |
| + err = snd_pcm_hw_constraint_step(runtime, 0, |
| + SNDRV_PCM_HW_PARAM_BUFFER_BYTES, |
| + XLNX_AUD_ALIGN_BYTES); |
| + if (err) { |
| + dev_err(component->dev, |
| + "Unable to set constraint on buffer bytes\n"); |
| + return err; |
| + } |
| + |
| + /* Set periods as integer multiple */ |
| + err = snd_pcm_hw_constraint_integer(runtime, |
| + SNDRV_PCM_HW_PARAM_PERIODS); |
| + if (err < 0) { |
| + dev_err(component->dev, |
| + "Unable to set constraint on periods to be integer\n"); |
| return err; |
| } |
| |