* [PATCH] clk: rockchip: rk3588: let MCLK_SPDIF* rate requests reach the divider
@ 2026-08-20 7:54 Karl Asseily
2026-08-20 8:39 ` Karl Asseily
0 siblings, 1 reply; 2+ messages in thread
From: Karl Asseily @ 2026-08-20 7:54 UTC (permalink / raw)
To: mturquette, sboyd, heiko
Cc: bmasney, linux-clk, linux-rockchip, linux-arm-kernel,
linux-kernel, Karl Asseily
Every MCLK_SPDIFn gate is declared with flags 0, while the CLK_SPDIFn mux
immediately above it already carries CLK_SET_RATE_PARENT. The rockchip
S/PDIF driver calls clk_set_rate() on the gate, which has no .set_rate of
its own and, without CLK_SET_RATE_PARENT, no way to pass the request up.
The clock core therefore computes "new rate == current rate", returns 0,
and changes nothing.
The visible effect is that S/PDIF is stuck on whatever divider the
bootloader left behind. On a board whose audio PLL is parked on the
48 kHz family, every 44.1 kHz source goes out at 48 kHz, silently, with
nothing reporting an error. Measured on an RK3588 board playing 44.1 kHz
material, before and after:
mclk_spdif0 12287999 Hz 48000 x 256
mclk_spdif0 11289598 Hz 44100 x 256
Add CLK_SET_RATE_PARENT to all eight MCLK_SPDIF gates so the request
propagates to the fractional divider that can satisfy it.
Propagation stops there. Each chain terminates at CLK_SPDIFn_SRC, which
is declared with flags 0, so a rate request cannot reach a shared PLL and
pull unrelated consumers off frequency.
Two pairs of gates share a divider - mclk_spdif2 and mclk_spdif2_dp0 both
sit on clk_spdif2_dp0, and mclk_spdif5 and mclk_spdif5_dp1 on
clk_spdif5_dp1 - so a rate set on one moves the other. That sharing is in
the hardware and is not introduced here; before this change neither of
them could set a rate at all.
Signed-off-by: Karl Asseily <karl@asseily.com>
---
Notes:
Generated against broonie/sound.git for-next. clk-rk3588.c
carries no ASoC changes, so this should apply to any current tree.
Tested on RK3588 hardware running 7.1.3: without this a 44.1 kHz stream leaves
the S/PDIF transmitter at 48 kHz; with it mclk_spdif0 retunes and the receiver
locks at 44.1 kHz.
checkpatch --strict reports "Alignment should match open parenthesis" on the
touched lines. That continuation indentation is unchanged by this patch and
matches every other clock entry in the file; realigning only these eight would
make them the inconsistent ones.
drivers/clk/rockchip/clk-rk3588.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/drivers/clk/rockchip/clk-rk3588.c b/drivers/clk/rockchip/clk-rk3588.c
index 2ba9976654c..b3d577dccfc 100644
--- a/drivers/clk/rockchip/clk-rk3588.c
+++ b/drivers/clk/rockchip/clk-rk3588.c
@@ -960,7 +960,7 @@ static struct rockchip_clk_branch rk3588_early_clk_branches[] __initdata = {
RK3588_CLKSEL_CON(33), 0,
RK3588_CLKGATE_CON(9), 0, GFLAGS,
&rk3588_spdif0_fracmux),
- GATE(MCLK_SPDIF0, "mclk_spdif0", "clk_spdif0", 0,
+ GATE(MCLK_SPDIF0, "mclk_spdif0", "clk_spdif0", CLK_SET_RATE_PARENT,
RK3588_CLKGATE_CON(9), 1, GFLAGS),
GATE(HCLK_SPDIF1, "hclk_spdif1", "hclk_audio_root", 0,
@@ -973,7 +973,7 @@ static struct rockchip_clk_branch rk3588_early_clk_branches[] __initdata = {
RK3588_CLKSEL_CON(35), 0,
RK3588_CLKGATE_CON(9), 4, GFLAGS,
&rk3588_spdif1_fracmux),
- GATE(MCLK_SPDIF1, "mclk_spdif1", "clk_spdif1", 0,
+ GATE(MCLK_SPDIF1, "mclk_spdif1", "clk_spdif1", CLK_SET_RATE_PARENT,
RK3588_CLKGATE_CON(9), 5, GFLAGS),
COMPOSITE(ACLK_AV1_ROOT, "aclk_av1_root", gpll_cpll_aupll_p, 0,
@@ -1868,9 +1868,9 @@ static struct rockchip_clk_branch rk3588_early_clk_branches[] __initdata = {
RK3588_CLKSEL_CON(123), 0,
RK3588_CLKGATE_CON(57), 4, GFLAGS,
&rk3588_spdif2_dp0_fracmux),
- GATE(MCLK_SPDIF2_DP0, "mclk_spdif2_dp0", "clk_spdif2_dp0", 0,
+ GATE(MCLK_SPDIF2_DP0, "mclk_spdif2_dp0", "clk_spdif2_dp0", CLK_SET_RATE_PARENT,
RK3588_CLKGATE_CON(57), 5, GFLAGS),
- GATE(MCLK_SPDIF2, "mclk_spdif2", "clk_spdif2_dp0", 0,
+ GATE(MCLK_SPDIF2, "mclk_spdif2", "clk_spdif2_dp0", CLK_SET_RATE_PARENT,
RK3588_CLKGATE_CON(57), 6, GFLAGS),
COMPOSITE(CLK_SPDIF5_DP1_SRC, "clk_spdif5_dp1_src", gpll_aupll_p, 0,
RK3588_CLKSEL_CON(124), 7, 1, MFLAGS, 2, 5, DFLAGS,
@@ -1880,9 +1880,9 @@ static struct rockchip_clk_branch rk3588_early_clk_branches[] __initdata = {
RK3588_CLKSEL_CON(125), 0,
RK3588_CLKGATE_CON(57), 9, GFLAGS,
&rk3588_spdif5_dp1_fracmux),
- GATE(MCLK_SPDIF5_DP1, "mclk_spdif5_dp1", "clk_spdif5_dp1", 0,
+ GATE(MCLK_SPDIF5_DP1, "mclk_spdif5_dp1", "clk_spdif5_dp1", CLK_SET_RATE_PARENT,
RK3588_CLKGATE_CON(57), 10, GFLAGS),
- GATE(MCLK_SPDIF5, "mclk_spdif5", "clk_spdif5_dp1", 0,
+ GATE(MCLK_SPDIF5, "mclk_spdif5", "clk_spdif5_dp1", CLK_SET_RATE_PARENT,
RK3588_CLKGATE_CON(57), 11, GFLAGS),
COMPOSITE_NOMUX(CLK_AUX16M_0, "clk_aux16m_0", "gpll", 0,
RK3588_CLKSEL_CON(117), 0, 8, DFLAGS,
@@ -2059,7 +2059,7 @@ static struct rockchip_clk_branch rk3588_early_clk_branches[] __initdata = {
RK3588_CLKSEL_CON(149), 0,
RK3588_CLKGATE_CON(63), 6, GFLAGS,
&rk3588_spdif3_fracmux),
- GATE(MCLK_SPDIF3, "mclk_spdif3", "clk_spdif3", 0,
+ GATE(MCLK_SPDIF3, "mclk_spdif3", "clk_spdif3", CLK_SET_RATE_PARENT,
RK3588_CLKGATE_CON(63), 7, GFLAGS),
COMPOSITE(CLK_SPDIF4_SRC, "clk_spdif4_src", gpll_aupll_p, 0,
RK3588_CLKSEL_CON(150), 7, 1, MFLAGS, 2, 5, DFLAGS,
@@ -2069,7 +2069,7 @@ static struct rockchip_clk_branch rk3588_early_clk_branches[] __initdata = {
RK3588_CLKSEL_CON(151), 0,
RK3588_CLKGATE_CON(63), 10, GFLAGS,
&rk3588_spdif4_fracmux),
- GATE(MCLK_SPDIF4, "mclk_spdif4", "clk_spdif4", 0,
+ GATE(MCLK_SPDIF4, "mclk_spdif4", "clk_spdif4", CLK_SET_RATE_PARENT,
RK3588_CLKGATE_CON(63), 11, GFLAGS),
COMPOSITE(MCLK_SPDIFRX0, "mclk_spdifrx0", gpll_cpll_aupll_p, 0,
RK3588_CLKSEL_CON(152), 7, 2, MFLAGS, 2, 5, DFLAGS,
--
2.34.1
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH] clk: rockchip: rk3588: let MCLK_SPDIF* rate requests reach the divider
2026-08-20 7:54 [PATCH] clk: rockchip: rk3588: let MCLK_SPDIF* rate requests reach the divider Karl Asseily
@ 2026-08-20 8:39 ` Karl Asseily
0 siblings, 0 replies; 2+ messages in thread
From: Karl Asseily @ 2026-08-20 8:39 UTC (permalink / raw)
To: mturquette, sboyd, heiko
Cc: bmasney, linux-clk, linux-rockchip, linux-arm-kernel,
linux-kernel
Please drop this patch. It is a no-op and my analysis was wrong.
rockchip_clk_register_branch() adds CLK_SET_RATE_PARENT to every
branch_gate at registration:
case branch_gate:
flags |= CLK_SET_RATE_PARENT;
so the MCLK_SPDIF* gates already propagate and the flags column in the
branch table makes no difference.
The behaviour I was chasing was real, but the cause is elsewhere:
simple-audio-card only calls the CPU DAI's set_sysclk() when the card
node has an mclk-fs property, and rk_spdif_set_sysclk() is the only
caller of clk_set_rate() in the S/PDIF path. Without mclk-fs no rate
request is ever made, MCLK stays at whatever the bootloader left, and
44.1 kHz material goes out at 48 kHz. Adding mclk-fs to my card node
fixed it. The before/after rates I quoted belong to that change, not
to this one.
Sorry for the noise.
Karl
On Thu, Aug 20, 2026 at 10:54 AM Karl Asseily <karl@asseily.com> wrote:
>
> Every MCLK_SPDIFn gate is declared with flags 0, while the CLK_SPDIFn mux
> immediately above it already carries CLK_SET_RATE_PARENT. The rockchip
> S/PDIF driver calls clk_set_rate() on the gate, which has no .set_rate of
> its own and, without CLK_SET_RATE_PARENT, no way to pass the request up.
> The clock core therefore computes "new rate == current rate", returns 0,
> and changes nothing.
>
> The visible effect is that S/PDIF is stuck on whatever divider the
> bootloader left behind. On a board whose audio PLL is parked on the
> 48 kHz family, every 44.1 kHz source goes out at 48 kHz, silently, with
> nothing reporting an error. Measured on an RK3588 board playing 44.1 kHz
> material, before and after:
>
> mclk_spdif0 12287999 Hz 48000 x 256
> mclk_spdif0 11289598 Hz 44100 x 256
>
> Add CLK_SET_RATE_PARENT to all eight MCLK_SPDIF gates so the request
> propagates to the fractional divider that can satisfy it.
>
> Propagation stops there. Each chain terminates at CLK_SPDIFn_SRC, which
> is declared with flags 0, so a rate request cannot reach a shared PLL and
> pull unrelated consumers off frequency.
>
> Two pairs of gates share a divider - mclk_spdif2 and mclk_spdif2_dp0 both
> sit on clk_spdif2_dp0, and mclk_spdif5 and mclk_spdif5_dp1 on
> clk_spdif5_dp1 - so a rate set on one moves the other. That sharing is in
> the hardware and is not introduced here; before this change neither of
> them could set a rate at all.
>
> Signed-off-by: Karl Asseily <karl@asseily.com>
> ---
>
> Notes:
> Generated against broonie/sound.git for-next. clk-rk3588.c
> carries no ASoC changes, so this should apply to any current tree.
>
> Tested on RK3588 hardware running 7.1.3: without this a 44.1 kHz stream leaves
> the S/PDIF transmitter at 48 kHz; with it mclk_spdif0 retunes and the receiver
> locks at 44.1 kHz.
>
> checkpatch --strict reports "Alignment should match open parenthesis" on the
> touched lines. That continuation indentation is unchanged by this patch and
> matches every other clock entry in the file; realigning only these eight would
> make them the inconsistent ones.
>
> drivers/clk/rockchip/clk-rk3588.c | 16 ++++++++--------
> 1 file changed, 8 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/clk/rockchip/clk-rk3588.c b/drivers/clk/rockchip/clk-rk3588.c
> index 2ba9976654c..b3d577dccfc 100644
> --- a/drivers/clk/rockchip/clk-rk3588.c
> +++ b/drivers/clk/rockchip/clk-rk3588.c
> @@ -960,7 +960,7 @@ static struct rockchip_clk_branch rk3588_early_clk_branches[] __initdata = {
> RK3588_CLKSEL_CON(33), 0,
> RK3588_CLKGATE_CON(9), 0, GFLAGS,
> &rk3588_spdif0_fracmux),
> - GATE(MCLK_SPDIF0, "mclk_spdif0", "clk_spdif0", 0,
> + GATE(MCLK_SPDIF0, "mclk_spdif0", "clk_spdif0", CLK_SET_RATE_PARENT,
> RK3588_CLKGATE_CON(9), 1, GFLAGS),
>
> GATE(HCLK_SPDIF1, "hclk_spdif1", "hclk_audio_root", 0,
> @@ -973,7 +973,7 @@ static struct rockchip_clk_branch rk3588_early_clk_branches[] __initdata = {
> RK3588_CLKSEL_CON(35), 0,
> RK3588_CLKGATE_CON(9), 4, GFLAGS,
> &rk3588_spdif1_fracmux),
> - GATE(MCLK_SPDIF1, "mclk_spdif1", "clk_spdif1", 0,
> + GATE(MCLK_SPDIF1, "mclk_spdif1", "clk_spdif1", CLK_SET_RATE_PARENT,
> RK3588_CLKGATE_CON(9), 5, GFLAGS),
>
> COMPOSITE(ACLK_AV1_ROOT, "aclk_av1_root", gpll_cpll_aupll_p, 0,
> @@ -1868,9 +1868,9 @@ static struct rockchip_clk_branch rk3588_early_clk_branches[] __initdata = {
> RK3588_CLKSEL_CON(123), 0,
> RK3588_CLKGATE_CON(57), 4, GFLAGS,
> &rk3588_spdif2_dp0_fracmux),
> - GATE(MCLK_SPDIF2_DP0, "mclk_spdif2_dp0", "clk_spdif2_dp0", 0,
> + GATE(MCLK_SPDIF2_DP0, "mclk_spdif2_dp0", "clk_spdif2_dp0", CLK_SET_RATE_PARENT,
> RK3588_CLKGATE_CON(57), 5, GFLAGS),
> - GATE(MCLK_SPDIF2, "mclk_spdif2", "clk_spdif2_dp0", 0,
> + GATE(MCLK_SPDIF2, "mclk_spdif2", "clk_spdif2_dp0", CLK_SET_RATE_PARENT,
> RK3588_CLKGATE_CON(57), 6, GFLAGS),
> COMPOSITE(CLK_SPDIF5_DP1_SRC, "clk_spdif5_dp1_src", gpll_aupll_p, 0,
> RK3588_CLKSEL_CON(124), 7, 1, MFLAGS, 2, 5, DFLAGS,
> @@ -1880,9 +1880,9 @@ static struct rockchip_clk_branch rk3588_early_clk_branches[] __initdata = {
> RK3588_CLKSEL_CON(125), 0,
> RK3588_CLKGATE_CON(57), 9, GFLAGS,
> &rk3588_spdif5_dp1_fracmux),
> - GATE(MCLK_SPDIF5_DP1, "mclk_spdif5_dp1", "clk_spdif5_dp1", 0,
> + GATE(MCLK_SPDIF5_DP1, "mclk_spdif5_dp1", "clk_spdif5_dp1", CLK_SET_RATE_PARENT,
> RK3588_CLKGATE_CON(57), 10, GFLAGS),
> - GATE(MCLK_SPDIF5, "mclk_spdif5", "clk_spdif5_dp1", 0,
> + GATE(MCLK_SPDIF5, "mclk_spdif5", "clk_spdif5_dp1", CLK_SET_RATE_PARENT,
> RK3588_CLKGATE_CON(57), 11, GFLAGS),
> COMPOSITE_NOMUX(CLK_AUX16M_0, "clk_aux16m_0", "gpll", 0,
> RK3588_CLKSEL_CON(117), 0, 8, DFLAGS,
> @@ -2059,7 +2059,7 @@ static struct rockchip_clk_branch rk3588_early_clk_branches[] __initdata = {
> RK3588_CLKSEL_CON(149), 0,
> RK3588_CLKGATE_CON(63), 6, GFLAGS,
> &rk3588_spdif3_fracmux),
> - GATE(MCLK_SPDIF3, "mclk_spdif3", "clk_spdif3", 0,
> + GATE(MCLK_SPDIF3, "mclk_spdif3", "clk_spdif3", CLK_SET_RATE_PARENT,
> RK3588_CLKGATE_CON(63), 7, GFLAGS),
> COMPOSITE(CLK_SPDIF4_SRC, "clk_spdif4_src", gpll_aupll_p, 0,
> RK3588_CLKSEL_CON(150), 7, 1, MFLAGS, 2, 5, DFLAGS,
> @@ -2069,7 +2069,7 @@ static struct rockchip_clk_branch rk3588_early_clk_branches[] __initdata = {
> RK3588_CLKSEL_CON(151), 0,
> RK3588_CLKGATE_CON(63), 10, GFLAGS,
> &rk3588_spdif4_fracmux),
> - GATE(MCLK_SPDIF4, "mclk_spdif4", "clk_spdif4", 0,
> + GATE(MCLK_SPDIF4, "mclk_spdif4", "clk_spdif4", CLK_SET_RATE_PARENT,
> RK3588_CLKGATE_CON(63), 11, GFLAGS),
> COMPOSITE(MCLK_SPDIFRX0, "mclk_spdifrx0", gpll_cpll_aupll_p, 0,
> RK3588_CLKSEL_CON(152), 7, 2, MFLAGS, 2, 5, DFLAGS,
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-08-20 8:40 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-20 7:54 [PATCH] clk: rockchip: rk3588: let MCLK_SPDIF* rate requests reach the divider Karl Asseily
2026-08-20 8:39 ` Karl Asseily
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox