[PATCH 0/2] ASoC: meson: axg: fix TDM channel order sync
On the Amlogic AXG series, the TODDR FIFO may get out of sync with the TDM decoder if the decoder is started before the FIFO. The channel appears shifted in memory in an unpredictable way.
To fix this, the trick is to start the FIFO before the TDM decoder. This way the FIFO is already waiting when the 1st channel is produced and it is correctly placed in memory.
Jerome Brunet (2): ASoC: meson: axg-card: make links nonatomic ASoC: meson: axg-tdm-interface: manage formatters in trigger
sound/soc/meson/axg-card.c | 1 + sound/soc/meson/axg-tdm-interface.c | 26 +++++++++++++++++++++----- 2 files changed, 22 insertions(+), 5 deletions(-)
Non atomic operations need to be performed in the trigger callback of the TDM interfaces. Those are BEs but what matters is the nonatomic flag of the FE in the DPCM context. Just set nonatomic for everything so, at least, it is clear.
Signed-off-by: Jerome Brunet jbrunet@baylibre.com --- sound/soc/meson/axg-card.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/sound/soc/meson/axg-card.c b/sound/soc/meson/axg-card.c index 2b77010c2c5c..cbbaa55d92a6 100644 --- a/sound/soc/meson/axg-card.c +++ b/sound/soc/meson/axg-card.c @@ -320,6 +320,7 @@ static int axg_card_add_link(struct snd_soc_card *card, struct device_node *np,
dai_link->cpus = cpu; dai_link->num_cpus = 1; + dai_link->nonatomic = true;
ret = meson_card_parse_dai(card, np, &dai_link->cpus->of_node, &dai_link->cpus->dai_name);
So far, the formatters have been reset/enabled using the .prepare() callback. This was done in this callback because walking the formatters use a mutex so it could not be done in .trigger(), which is atomic by default.
It turns out there is a problem on capture path of the AXG series. The FIFO may get out of sync with the TDM decoder if the IP are not enabled in a specific order. The FIFO must be enabled before the formatter starts producing data. IOW, we must deal with FE before the BE. The .prepare() callback is called on the BEs before the FE so it is not OK for the AXG.
The .trigger() callback order can be configured, and it deals with the FE before the BEs by default. To solve our problem, we just need to start and stop the formatters from the .trigger() callback. It is OK do so now that the links have been made 'nonatomic' in the card driver.
Signed-off-by: Jerome Brunet jbrunet@baylibre.com --- sound/soc/meson/axg-tdm-interface.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-)
diff --git a/sound/soc/meson/axg-tdm-interface.c b/sound/soc/meson/axg-tdm-interface.c index 87cac440b369..db077773af7a 100644 --- a/sound/soc/meson/axg-tdm-interface.c +++ b/sound/soc/meson/axg-tdm-interface.c @@ -351,13 +351,29 @@ static int axg_tdm_iface_hw_free(struct snd_pcm_substream *substream, return 0; }
-static int axg_tdm_iface_prepare(struct snd_pcm_substream *substream, +static int axg_tdm_iface_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) { - struct axg_tdm_stream *ts = snd_soc_dai_get_dma_data(dai, substream); + struct axg_tdm_stream *ts = + snd_soc_dai_get_dma_data(dai, substream); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + axg_tdm_stream_start(ts); + break; + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_STOP: + axg_tdm_stream_stop(ts); + break; + default: + return -EINVAL; + }
- /* Force all attached formatters to update */ - return axg_tdm_stream_reset(ts); + return 0; }
static int axg_tdm_iface_remove_dai(struct snd_soc_dai *dai) @@ -397,8 +413,8 @@ static const struct snd_soc_dai_ops axg_tdm_iface_ops = { .set_fmt = axg_tdm_iface_set_fmt, .startup = axg_tdm_iface_startup, .hw_params = axg_tdm_iface_hw_params, - .prepare = axg_tdm_iface_prepare, .hw_free = axg_tdm_iface_hw_free, + .trigger = axg_tdm_iface_trigger, };
/* TDM Backend DAIs */
On Wed, 20 Oct 2021 13:42:15 +0200, Jerome Brunet wrote:
On the Amlogic AXG series, the TODDR FIFO may get out of sync with the TDM decoder if the decoder is started before the FIFO. The channel appears shifted in memory in an unpredictable way.
To fix this, the trick is to start the FIFO before the TDM decoder. This way the FIFO is already waiting when the 1st channel is produced and it is correctly placed in memory.
[...]
Applied to
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next
Thanks!
[1/2] ASoC: meson: axg-card: make links nonatomic commit: e138233e56e9829e65b6293887063a1a3ccb2d68 [2/2] ASoC: meson: axg-tdm-interface: manage formatters in trigger commit: bf5e4887eeddb48480568466536aa08ec7f179a5
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
participants (2)
-
Jerome Brunet
-
Mark Brown