Re: ASoC: amd: acp-pdm: full-scale burst on every DMIC capture start
From: Mukunda,Vijendar
Date: Thu Aug 27 2026 - 02:45:43 EST
On 8/24/26 19:17, Robin Everaars wrote:
Please try with attached patches.Could you please re-test with the updated patches, particularly theI tested the three exact attachments against v7.1.8 on the ASUS ProArt PX13
active-capture s2idle resume scenario that originally triggered the BUG?
The expected result is a clean resume with no scheduling-while-atomic
warning and successful capture continuation after resume without
requiring a fresh stream restart.
HN7306EAC. Their SHA-256 values were:
patch 1 87c2462d4528f13ee14e28df805a7a220b463cf05f59825bdfe4fd70be7cd8a7
patch 2 6ad1a74b4e276126a2d6d7518b27651aa2d38996e77cffba6f07034d29fc4661
patch 3 d1af42b8ee371af99cc7056c59cc3feae17cfd69f2f83a89a8ebee47be63e199
The loaded snd_ps_pdm_dma module matched the rebuilt artifact. Its SHA-256
was c2e1a7390584918bab6893943f5231b156e3e9d5db89c307cb9bf7c1e150c63c.
The ordinary paths behaved as follows:
- The first runtime-suspended capture after boot returned -EIO before
delivering data and had no matching kernel diagnostic.
The next five
runtime-suspended starts each delivered all 48000 frames with no clipped
or >=99% full-scale samples.
- 5/5 active warm starts delivered all 48000 frames with no clipped or
>=99% full-scale samples.
- PAUSE_PUSH/PAUSE_RELEASE passed 3/3 with a 0.5 s pause and 3/3 with a
2 s pause. All six recordings delivered 144000 frames with no clipped
or >=99% full-scale samples.
Active-capture s2idle still fails. I repeated the cycle twice. Both runs
reached ALSA SUSPENDED at the same frame boundary and produced this result:
SUSPENDED boundary=97284
RESUME rc=0 (ok) state=XRUN
XRUN boundary=97284
error: Broken pipe
No post-resume sample was delivered in either run. There was no
scheduling-while-atomic warning, BUG, Oops or PDM kernel error, so moving the
sleep out of the trigger callback removed the atomic-context failure. It did
not provide successful capture continuation.
The expected 300 ms settle was also not visible in t
he PM resume interval.
In both kernel traces, the interval from "Suspending console(s)" through the
ACP resume message to "PM: suspend exit" was only about 10 to 12 ms. By
comparison, the same userspace test measured prepare() at 304 ms. This makes
me suspect that acp63_pdm_settle() is not reached from acp63_pdm_resume() for
this active stream, although I have not instrumented the callback to prove
that.
The first fresh open after each resume returned -EIO with no frames, as did
the first cold open after boot. Subsequent fresh captures worked and had no
clipped or >=99% full-scale samples. I am keeping this first-open behavior
separate from the reproducible in-place resume XRUN.
There is also a hardware-coverage gap for patch 3. The patched
snd_soc_ps_mach module was built and installed, but this machine binds
snd_acp_sdw_legacy_mach for its SoundWire card. snd_soc_ps_mach was never
loaded, so I did not exercise the nonatomic link change.
I have withheld Tested-by
because the active capture fails 2/2 and patch 3
is untested on this machine. I can test another revision or an instrumented
resume callback on the same hardware.
-
Vijendar
From 75a9017a1e3f8bf224524842afeaf9e203993737 Mon Sep 17 00:00:00 2001
Thanks,
Robin
From: Vijendar Mukunda <Vijendar.Mukunda@xxxxxxx>
Date: Thu, 27 Aug 2026 12:02:10 +0530
Subject: [PATCH V3 0/3] ASoC: amd: ps: pdm: fix CIC decimator transients and resume XRUN
The ACP PDM DMIC on Pink Sardine (ACP6.3/7.0/7.1) emits a full-scale
Nyquist-rate burst at the start of every capture stream and after a
system suspend/resume cycle with an active capture. This series fixes
both cases and extends the nonatomic machine-driver coverage to
acp-sdw-legacy-mach.
Patch 1 adds a prepare() DAI callback that enables the PDM decimator
and waits 300 ms for the CIC filter chain to stabilise before the DMA
is armed. A new acp63_pause_pdm_dma() helper keeps the decimator
running across PAUSE_PUSH/PAUSE_RELEASE so no settling delay is needed
on pause resume.
Patch 2 extends the fix to the system resume path. After
TRIGGER_SUSPEND the decimator is disabled; because prepare() is not
called before TRIGGER_RESUME, the settle sequence must run elsewhere.
It is placed in acp63_pdm_component_resume(), the snd_soc_component_driver
resume callback, which runs inside the ASoC deferred resume workqueue
after the parent ACP hardware has been fully restored and before the
card reaches SNDRV_CTL_POWER_D0. This guarantees the 300 ms CIC settling
completes before TRIGGER_RESUME fires. A shared acp63_pdm_settle()
helper is factored out so prepare() and acp63_pdm_component_resume() use
identical logic.
Patch 3 marks the PDM DAI link nonatomic = 1 in all machine drivers
that register the acp_ps_pdm_dma link: ps-mach.c and
acp-sdw-legacy-mach.c.
Changes in v3:
- Patch 1: no code changes.
- Patch 2: fix active-capture s2idle XRUN reported by tester on ASUS
ProArt PX13 HN7306EAC (snd_acp_sdw_legacy_mach). v2 placed the
settle in acp63_pdm_resume() (SYSTEM_SLEEP_PM_OPS .resume hook),
which is a platform device PM callback. This runs during dpm_resume()
before snd_soc_resume() is called, so the parent ACP hardware may not
yet be restored when acp63_pdm_settle() tries to write ACP_PDM_ENABLE.
Result: the 300 ms settle completes on stale hardware, the ACP parent
later re-initialises the block, and TRIGGER_RESUME fires without any
valid settle. Every s2idle resume produced:
SUSPENDED boundary=97284
RESUME rc=0 (ok) state=XRUN
error: Broken pipe
Fix: move acp63_pdm_settle() to acp63_pdm_component_resume(), the
snd_soc_component_driver .resume callback. This runs inside the ASoC
deferred workqueue (soc_resume_deferred), which is scheduled by
snd_soc_resume() only after all platform device PM resumes complete.
The workqueue holds the card at SNDRV_CTL_POWER_D2 while it runs,
so userspace cannot issue TRIGGER_RESUME until the settle finishes.
The platform device acp63_pdm_resume() retains only DMA ring buffer
reconfiguration and interrupt enable.
- Patch 3: extend nonatomic flag to acp-sdw-legacy-mach.c. The ASUS
PX13 binds snd_acp_sdw_legacy_mach for its SoundWire card and also
registers a PDM DMIC DAI link using acp_ps_pdm_dma. v2 only marked
ps-mach.c; acp-sdw-legacy-mach.c was missing, leaving the trigger
path atomic on all sdw-legacy machines.
Vijendar Mukunda (3):
ASoC: amd: ps: pdm: fix decimator transient on stream start
ASoC: amd: ps: pdm: fix decimator transient on system resume
ASoC: amd: ps: pdm: set PDM DAI link as non-atomic
sound/soc/amd/acp/acp-sdw-legacy-mach.c | 7 ++
sound/soc/amd/ps/ps-mach.c | 1 +
sound/soc/amd/ps/ps-pdm-dma.c | 149 +++++++++++++++++++++++-
3 files changed, 151 insertions(+), 6 deletions(-)
--
2.48.1
From 86e71798fd56934cb73aad3c78838b94c69b55e0 Mon Sep 17 00:00:00 2001
From: Vijendar Mukunda <Vijendar.Mukunda@xxxxxxx>
Date: Wed, 12 Aug 2026 14:41:42 +0530
Subject: [PATCH V3 1/3] ASoC: amd: ps: pdm: fix decimator transient on stream
start
The ACP PDM DMIC emits a full-scale Nyquist-rate burst at the beginning
of every capture stream. The burst lasts ~4 ms on a warm start (ACP
already running) and ~250 ms on a cold start (ACP runtime-suspended),
and is audible to remote call participants as a click on join.
Root cause: acp63_start_pdm_dma() enables the PDM decimator and the DMA
in the same call, so the CIC filter chain's unflushed initial state goes
directly to userspace. An exponentially growing alternating pattern
collapses into full-scale saturation on both channels in antiphase --
the classic signature of a CIC integrator/comb chain running from a
non-zero initial condition.
Fix: add a prepare() DAI callback that enables PDM_ENABLE and waits
300 ms before the DMA starts. 300 ms is chosen to cover the cold-start
case; the warm-start transient clears in under 5 ms. After the
settling delay, flush ACP_WOV_PDM_FIFO_FLUSH so the DMA sees a clean
buffer. acp63_start_pdm_dma() then only arms the DMA, skipping the
PDM_ENABLE write when prepare() has already set it.
For the RESUME path where prepare() is not called, PDM_ENABLE is set
conditionally in acp63_start_pdm_dma() if not already active.
PAUSE handling: PAUSE_PUSH previously disabled both the DMA and the PDM
decimator via acp63_stop_pdm_dma(). After moving PDM_ENABLE to
prepare(), ALSA does not call prepare() between PAUSE_PUSH and
PAUSE_RELEASE, so PAUSE_RELEASE would have re-enabled PDM without the
300 ms settling delay, reproducing the transient on every resume from
pause.
Fix the pause path by adding acp63_pause_pdm_dma(), which stops the DMA
only and leaves the PDM decimator running. PAUSE_RELEASE flushes the
FIFO to discard samples accumulated while the DMA was stopped, then
restarts the DMA. Since the CIC filter never stopped, no settling delay
is needed. STOP and SUSPEND continue to use acp63_stop_pdm_dma(), which
disables both DMA and PDM.
Signed-off-by: Vijendar Mukunda <Vijendar.Mukunda@xxxxxxx>
---
sound/soc/amd/ps/ps-pdm-dma.c | 103 ++++++++++++++++++++++++++++++++--
1 file changed, 97 insertions(+), 6 deletions(-)
diff --git a/sound/soc/amd/ps/ps-pdm-dma.c b/sound/soc/amd/ps/ps-pdm-dma.c
index 04c014349347..e8f84d83a886 100644
--- a/sound/soc/amd/ps/ps-pdm-dma.c
+++ b/sound/soc/amd/ps/ps-pdm-dma.c
@@ -5,6 +5,7 @@
* Copyright 2022, 2025 Advanced Micro Devices, Inc.
*/
+#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/bitfield.h>
@@ -19,6 +20,17 @@
#define DRV_NAME "acp_ps_pdm_dma"
+/*
+ * Time in milliseconds to wait after enabling the PDM clock before
+ * starting the DMA. The PDM microphone and the CIC/decimation filter
+ * chain need this time to reach a stable state; without it the first
+ * frames delivered to userspace contain a saturated Nyquist-rate
+ * transient (unflushed decimator initial state). 300 ms covers both
+ * the warm-start case (~4 ms) and the cold-start case (~250 ms, when
+ * the ACP has been runtime-suspended).
+ */
+#define PDM_SETTLING_DELAY_MS 300
+
static int pdm_gain = 3;
module_param(pdm_gain, int, 0644);
MODULE_PARM_DESC(pdm_gain, "Gain control (0-3)");
@@ -107,12 +119,19 @@ static int acp63_start_pdm_dma(void __iomem *acp_base)
u32 pdm_dma_enable;
int timeout;
- pdm_enable = 0x01;
- pdm_dma_enable = 0x01;
-
acp63_enable_pdm_clock(acp_base);
- writel(pdm_enable, acp_base + ACP_WOV_PDM_ENABLE);
- writel(pdm_dma_enable, acp_base + ACP_WOV_PDM_DMA_ENABLE);
+
+ /*
+ * PDM_ENABLE and the clock were already set in prepare() for the
+ * initial stream start to allow the CIC filter to settle. Only
+ * write PDM_ENABLE if it is not already set, to cover the
+ * RESUME and PAUSE_RELEASE paths where prepare() was not called.
+ */
+ pdm_enable = readl(acp_base + ACP_WOV_PDM_ENABLE);
+ if (!(pdm_enable & ACP_PDM_ENABLE))
+ writel(ACP_PDM_ENABLE, acp_base + ACP_WOV_PDM_ENABLE);
+
+ writel(0x01, acp_base + ACP_WOV_PDM_DMA_ENABLE);
timeout = 0;
while (++timeout < ACP_COUNTER) {
pdm_dma_enable = readl(acp_base + ACP_WOV_PDM_DMA_ENABLE);
@@ -154,6 +173,32 @@ static int acp63_stop_pdm_dma(void __iomem *acp_base)
return 0;
}
+static int acp63_pause_pdm_dma(void __iomem *acp_base)
+{
+ u32 pdm_dma_enable;
+ int timeout;
+
+ /*
+ * Stop only the DMA; leave the PDM decimator running so that
+ * PAUSE_RELEASE does not need to wait for the CIC filter to
+ * settle again. The caller is responsible for flushing the FIFO
+ * before restarting the DMA on PAUSE_RELEASE.
+ */
+ pdm_dma_enable = readl(acp_base + ACP_WOV_PDM_DMA_ENABLE);
+ if (!(pdm_dma_enable & 0x01))
+ return 0;
+
+ writel(0x02, acp_base + ACP_WOV_PDM_DMA_ENABLE);
+ timeout = 0;
+ while (++timeout < ACP_COUNTER) {
+ pdm_dma_enable = readl(acp_base + ACP_WOV_PDM_DMA_ENABLE);
+ if ((pdm_dma_enable & 0x02) == 0x00)
+ return 0;
+ udelay(DELAY_US);
+ }
+ return -ETIMEDOUT;
+}
+
static void acp63_config_dma(struct pdm_stream_instance *rtd, int direction)
{
u16 page_idx;
@@ -286,6 +331,29 @@ static int acp63_pdm_dma_close(struct snd_soc_component *component,
return 0;
}
+static int acp63_pdm_dma_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct pdm_stream_instance *rtd = substream->runtime->private_data;
+
+ if (!rtd || substream->stream != SNDRV_PCM_STREAM_CAPTURE)
+ return 0;
+
+ /*
+ * Enable the PDM decimator now, before the DMA starts. The
+ * CIC filter chain and the microphone itself need time to reach
+ * a stable state after the clock is applied. Without this
+ * settling period the first frames captured by the DMA contain
+ * a saturated Nyquist-rate transient. Wait for the decimator
+ * to flush, then clear the FIFO so the DMA sees a clean buffer.
+ */
+ acp63_enable_pdm_clock(rtd->acp63_base);
+ writel(ACP_PDM_ENABLE, rtd->acp63_base + ACP_WOV_PDM_ENABLE);
+ msleep(PDM_SETTLING_DELAY_MS);
+ writel(0x01, rtd->acp63_base + ACP_WOV_PDM_FIFO_FLUSH);
+ return 0;
+}
+
static int acp63_pdm_dai_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
{
@@ -306,21 +374,43 @@ static int acp63_pdm_dai_trigger(struct snd_pcm_substream *substream,
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
+ writel(ch_mask, rtd->acp63_base + ACP_WOV_PDM_NO_OF_CHANNELS);
+ writel(PDM_DECIMATION_FACTOR, rtd->acp63_base + ACP_WOV_PDM_DECIMATION_FACTOR);
+ rtd->bytescount = acp63_pdm_get_byte_count(rtd, substream->stream);
+ pdm_status = acp63_check_pdm_dma_status(rtd->acp63_base);
+ if (!pdm_status)
+ ret = acp63_start_pdm_dma(rtd->acp63_base);
+ break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
writel(ch_mask, rtd->acp63_base + ACP_WOV_PDM_NO_OF_CHANNELS);
writel(PDM_DECIMATION_FACTOR, rtd->acp63_base + ACP_WOV_PDM_DECIMATION_FACTOR);
rtd->bytescount = acp63_pdm_get_byte_count(rtd, substream->stream);
+ /*
+ * The PDM decimator was left running during PAUSE_PUSH so no
+ * 300 ms settling delay is needed. Flush the FIFO to discard
+ * samples accumulated while the DMA was stopped, then restart
+ * the DMA.
+ */
+ writel(0x01, rtd->acp63_base + ACP_WOV_PDM_FIFO_FLUSH);
pdm_status = acp63_check_pdm_dma_status(rtd->acp63_base);
if (!pdm_status)
ret = acp63_start_pdm_dma(rtd->acp63_base);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
pdm_status = acp63_check_pdm_dma_status(rtd->acp63_base);
if (pdm_status)
ret = acp63_stop_pdm_dma(rtd->acp63_base);
break;
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ /*
+ * Leave the PDM decimator running so that PAUSE_RELEASE does
+ * not need the 300 ms CIC settling delay. Only stop the DMA.
+ */
+ pdm_status = acp63_check_pdm_dma_status(rtd->acp63_base);
+ if (pdm_status)
+ ret = acp63_pause_pdm_dma(rtd->acp63_base);
+ break;
default:
ret = -EINVAL;
break;
@@ -329,6 +419,7 @@ static int acp63_pdm_dai_trigger(struct snd_pcm_substream *substream,
}
static const struct snd_soc_dai_ops acp63_pdm_dai_ops = {
+ .prepare = acp63_pdm_dma_prepare,
.trigger = acp63_pdm_dai_trigger,
};
--
2.48.1
From 09c042b2e6a0c3df914f0dd2053d46a6899d504e Mon Sep 17 00:00:00 2001
From: Vijendar Mukunda <Vijendar.Mukunda@xxxxxxx>
Date: Fri, 14 Aug 2026 11:38:45 +0530
Subject: [PATCH V3 2/3] ASoC: amd: ps: pdm: fix decimator transient on system
resume
After a system suspend/resume cycle with an active ALSA capture,
TRIGGER_RESUME fires after TRIGGER_SUSPEND without an intervening
prepare() call. TRIGGER_SUSPEND calls acp63_stop_pdm_dma() which
disables both the DMA and the PDM decimator. TRIGGER_RESUME then
called acp63_start_pdm_dma() which re-enables PDM and DMA together
without the 300 ms CIC settling delay or the FIFO flush, producing the
same Nyquist-rate transient that the prepare() fix was designed to
prevent. On hardware the transient caused an immediate XRUN and
broken-pipe error after wake.
Fix by adding the new acp63_pdm_settle() helper that encapsulates the
enable-clock / enable-PDM / msleep / flush-FIFO sequence, and calling
it from acp63_pdm_component_resume(), the snd_soc_component_driver
resume callback. prepare() is also updated to call through this helper.
The settle is placed in the component resume rather than the platform
device PM resume (acp63_pdm_resume) because the component resume runs
inside the ASoC deferred resume workqueue, which is guaranteed to
execute after the parent ACP hardware has been fully restored and while
the card power state is still D2. This ensures the 300 ms CIC settling
completes before the card reaches D0, at which point the PCM layer can
issue TRIGGER_RESUME.
TRIGGER_RESUME runs under the PCM stream spinlock (IRQs disabled via
snd_pcm_action_lock_irq()), so msleep() is not permitted inside the
trigger callback. Placing the settle in acp63_pdm_component_resume()
ensures the CIC filter is stable before TRIGGER_RESUME fires, without
sleeping in atomic context.
Signed-off-by: Vijendar Mukunda <Vijendar.Mukunda@xxxxxxx>
---
sound/soc/amd/ps/ps-pdm-dma.c | 54 ++++++++++++++++++++++++++++++++---
1 file changed, 50 insertions(+), 4 deletions(-)
diff --git a/sound/soc/amd/ps/ps-pdm-dma.c b/sound/soc/amd/ps/ps-pdm-dma.c
index e8f84d83a886..f2d179308d79 100644
--- a/sound/soc/amd/ps/ps-pdm-dma.c
+++ b/sound/soc/amd/ps/ps-pdm-dma.c
@@ -331,6 +331,20 @@ static int acp63_pdm_dma_close(struct snd_soc_component *component,
return 0;
}
+/*
+ * acp63_pdm_settle - enable the PDM decimator and wait for it to stabilise.
+ *
+ * Called from prepare() and from TRIGGER_RESUME (where prepare() is not
+ * invoked by the ALSA core). Must not be called from atomic context.
+ */
+static void acp63_pdm_settle(void __iomem *acp_base)
+{
+ acp63_enable_pdm_clock(acp_base);
+ writel(ACP_PDM_ENABLE, acp_base + ACP_WOV_PDM_ENABLE);
+ msleep(PDM_SETTLING_DELAY_MS);
+ writel(0x01, acp_base + ACP_WOV_PDM_FIFO_FLUSH);
+}
+
static int acp63_pdm_dma_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
@@ -347,10 +361,7 @@ static int acp63_pdm_dma_prepare(struct snd_pcm_substream *substream,
* a saturated Nyquist-rate transient. Wait for the decimator
* to flush, then clear the FIFO so the DMA sees a clean buffer.
*/
- acp63_enable_pdm_clock(rtd->acp63_base);
- writel(ACP_PDM_ENABLE, rtd->acp63_base + ACP_WOV_PDM_ENABLE);
- msleep(PDM_SETTLING_DELAY_MS);
- writel(0x01, rtd->acp63_base + ACP_WOV_PDM_FIFO_FLUSH);
+ acp63_pdm_settle(rtd->acp63_base);
return 0;
}
@@ -373,10 +384,24 @@ static int acp63_pdm_dai_trigger(struct snd_pcm_substream *substream,
}
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
+ writel(ch_mask, rtd->acp63_base + ACP_WOV_PDM_NO_OF_CHANNELS);
+ writel(PDM_DECIMATION_FACTOR, rtd->acp63_base + ACP_WOV_PDM_DECIMATION_FACTOR);
+ rtd->bytescount = acp63_pdm_get_byte_count(rtd, substream->stream);
+ pdm_status = acp63_check_pdm_dma_status(rtd->acp63_base);
+ if (!pdm_status)
+ ret = acp63_start_pdm_dma(rtd->acp63_base);
+ break;
case SNDRV_PCM_TRIGGER_RESUME:
writel(ch_mask, rtd->acp63_base + ACP_WOV_PDM_NO_OF_CHANNELS);
writel(PDM_DECIMATION_FACTOR, rtd->acp63_base + ACP_WOV_PDM_DECIMATION_FACTOR);
rtd->bytescount = acp63_pdm_get_byte_count(rtd, substream->stream);
+ /*
+ * acp63_pdm_component_resume() already called acp63_pdm_settle()
+ * in sleepable component resume context before the PCM layer
+ * issued TRIGGER_RESUME. The trigger callback runs under the PCM
+ * stream spinlock (irqs disabled), so no msleep() is allowed
+ * here. Just arm the DMA.
+ */
pdm_status = acp63_check_pdm_dma_status(rtd->acp63_base);
if (!pdm_status)
ret = acp63_start_pdm_dma(rtd->acp63_base);
@@ -436,6 +461,26 @@ static struct snd_soc_dai_driver acp63_pdm_dai_driver = {
.ops = &acp63_pdm_dai_ops,
};
+static int acp63_pdm_component_resume(struct snd_soc_component *component)
+{
+ struct pdm_dev_data *adata = dev_get_drvdata(component->dev);
+ struct pdm_stream_instance *rtd;
+
+ if (!adata->capture_stream || !adata->capture_stream->runtime)
+ return 0;
+
+ rtd = adata->capture_stream->runtime->private_data;
+ /*
+ * TRIGGER_SUSPEND disabled the PDM decimator. Run the CIC settling
+ * sequence here, in sleepable component resume context, after the
+ * parent ACP hardware has been fully restored but before the PCM
+ * layer issues TRIGGER_RESUME (which runs under the stream spinlock
+ * with IRQs disabled and cannot call msleep).
+ */
+ acp63_pdm_settle(rtd->acp63_base);
+ return 0;
+}
+
static const struct snd_soc_component_driver acp63_pdm_component = {
.name = DRV_NAME,
.open = acp63_pdm_dma_open,
@@ -443,6 +488,7 @@ static const struct snd_soc_component_driver acp63_pdm_component = {
.hw_params = acp63_pdm_dma_hw_params,
.pointer = acp63_pdm_dma_pointer,
.pcm_new = acp63_pdm_dma_new,
+ .resume = acp63_pdm_component_resume,
.use_dai_pcm_id = true,
};
--
2.48.1
From a9caa873c0afd16646278d920afda614ef853b58 Mon Sep 17 00:00:00 2001
From: Vijendar Mukunda <Vijendar.Mukunda@xxxxxxx>
Date: Fri, 14 Aug 2026 11:39:10 +0530
Subject: [PATCH V3 3/3] ASoC: amd: ps: pdm: set PDM DAI link as non-atomic
The prepare() DAI callback calls msleep() via acp63_pdm_settle() to
allow the CIC filter to settle before DMA starts. Mark the PDM DAI
link nonatomic = 1 so the trigger path is also nonatomic, matching the
sleep requirements of the ops registered on this link and preventing
any future msleep() inside the trigger from hitting a scheduling-while-
atomic BUG.
This applies to both machine drivers that register the PDM DMIC DAI
link using acp_ps_pdm_dma: ps-mach.c (direct PDM link) and
acp-sdw-legacy-mach.c (SoundWire legacy machine driver). Both share
the same acp63_pdm_dma_prepare() -> acp63_pdm_settle() path.
Signed-off-by: Vijendar Mukunda <Vijendar.Mukunda@xxxxxxx>
---
sound/soc/amd/acp/acp-sdw-legacy-mach.c | 7 +++++++
sound/soc/amd/ps/ps-mach.c | 1 +
2 files changed, 8 insertions(+)
diff --git a/sound/soc/amd/acp/acp-sdw-legacy-mach.c b/sound/soc/amd/acp/acp-sdw-legacy-mach.c
index 6eac42bac855..072ce18abbcf 100644
--- a/sound/soc/amd/acp/acp-sdw-legacy-mach.c
+++ b/sound/soc/amd/acp/acp-sdw-legacy-mach.c
@@ -387,6 +387,13 @@ static int create_dmic_dailinks(struct snd_soc_card *card,
if (ret)
return ret;
+ /*
+ * The PDM prepare() callback calls msleep() via acp63_pdm_settle()
+ * to allow the CIC filter to settle. Mark the DAI link nonatomic so
+ * the trigger path is also nonatomic, matching the sleep requirements
+ * of the ops registered on this link.
+ */
+ (*dai_links)->nonatomic = true;
(*dai_links)++;
return 0;
diff --git a/sound/soc/amd/ps/ps-mach.c b/sound/soc/amd/ps/ps-mach.c
index 3e49c255c025..a040b5fcb0b7 100644
--- a/sound/soc/amd/ps/ps-mach.c
+++ b/sound/soc/amd/ps/ps-mach.c
@@ -32,6 +32,7 @@ static struct snd_soc_dai_link acp63_dai_pdm[] = {
.name = "acp63-dmic-capture",
.stream_name = "DMIC capture",
.capture_only = 1,
+ .nonatomic = 1,
SND_SOC_DAILINK_REG(acp63_pdm, dmic_codec, pdm_platform),
},
};
--
2.48.1