[PATCH] drm/bridge: dw-hdmi-qp: compute audio CTS from N when not in TMDS table
Luca Ceresoli
luca.ceresoli at bootlin.com
Mon May 18 03:50:18 PDT 2026
Hello Simon,
On Sat May 9, 2026 at 9:09 AM CEST, Simon Wright wrote:
> dw_hdmi_qp_find_cts() returns 0 for any TMDS character rate not
> present in common_tmds_cts_table[] (which terminates at 148.5 MHz).
> In that case dw_hdmi_qp_set_sample_rate() calls dw_hdmi_qp_set_cts_n()
> with cts == 0, which leaves AUDPKT_ACR_CTS_OVR_EN clear and falls
> back to the controller's internal CTS auto-measurement.
> On at least the RK3576 hdptx integration, strict HDMI sinks mute
> audio in this configuration. The behaviour reproduces at any rate
> not present in the table -- it is not specific to HDMI 2.x:
> 1920x1080 at 60 with 10-bit deep colour (185.625 MHz, HDMI 1.4) is
> affected, as is 3840x2160 at 60 8-bit (594 MHz, HDMI 2.0). Supplying
> explicit CTS via the standard set_cts_n() override path resolves
> the mute.
> The driver already has the symmetric machinery for the N-table-miss
> case: dw_hdmi_qp_compute_n() falls back to a dynamic search using
> dw_hdmi_qp_audio_math_diff() ((pixel_clk * n) / (128 * freq)) when
> no table entry matches. The CTS path lacks the equivalent fallback.
> Compute CTS inline in dw_hdmi_qp_set_sample_rate() from N per the
> HDMI spec (CTS = TMDS * N / (128 * Fs)) when find_cts() returns 0.
> The same formula appears in the legacy DesignWare HDMI driver
> (drivers/gpu/drm/bridge/synopsys/dw-hdmi.c, hdmi_set_clk_regenerator())
> under its AHB / GP audio paths.
> Tested on R76S (RK3576) on Armbian-edge mainline 7.0.1 with Cristian
> Ciocaltea's hdptx-clk-fixes v1 series applied:
> TMDS Mode In table? Audio with fix
> 148.5 MHz 1080p60 8-bit yes plays (regression check)
> 185.625 MHz 1080p60 10-bit no plays
> 297 MHz 3840p30 8-bit no plays
> 594 MHz 3840p60 8-bit no plays
> Sinks tested: LG G3 OLED, LG C4 OLED, TCL 75P7K QLED, Kogan
> KALED43XU9210STA (Changhong-OEM 4K LED). Without the fix, the LG
> G3 mutes audio -- this is the originally reported bug
> (linux-rockchip 070633). The LG C4 was verified during this cycle
> to mute at 185.625 MHz (1080p60 10-bit) with the unpatched module.
> The Kogan TV plays audio with or without the fix; it is a
> permissive HDMI 2.0 implementation that does not strictly cross-
> check ACR timing. The TCL 75P7K was tested with the fix loaded
> only.
> Audio plays at every supported sample rate (32 / 44.1 / 48 / 96 /
> 192 kHz) verified on the TCL at the 185.625 MHz out-of-table TMDS
> rate -- the fallback's CTS = (TMDS * N) / (128 * Fs) computation is
> independent of sample rate, as expected.
> The LG C4's CTA-861 SVDs do not advertise 3840x2160 at 60 over TMDS
> (it is signalled FRL-only on that model), so that one row is N/A
> on the C4. The same audio-path code is exercised at 297 MHz on
> that sink and behaves identically to the G3.
> Reported-by: Simon Wright <simon at symple.nz>
> Closes:
> https://lists.infradead.org/pipermail/linux-rockchip/2026-May/070633.html
> Suggested-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
> Tested-by: Simon Wright <simon at symple.nz>
> Signed-off-by: Simon Wright <simon at symple.nz>
> ---
> drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 15 +++++++++++++++
> 1 file changed, 15 insertions(+)
> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
> b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
> index 0dbb1274360..25ac8d3cfc8 100644
> ---a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
> +++b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
> @@-461,6 +461,21 @@static void dw_hdmi_qp_set_sample_rate(struct
> dw_hdmi_qp *hdmi, unsigned long lo
> n = dw_hdmi_qp_find_n(hdmi, tmds_char_rate, sample_rate);
> cts = dw_hdmi_qp_find_cts(hdmi, tmds_char_rate, sample_rate);
> + /*
> + * dw_hdmi_qp_find_cts() returns 0 for any TMDS rate not in
> + * common_tmds_cts_table[]. Falling through to the controller's
> + * auto-measure path mutes audio on strict HDMI sinks at out-of-
> + * table rates (e.g. 185.625 MHz, 297 MHz, 594 MHz). Compute CTS
> + * from N per HDMI spec instead, so the standard override path
> + * supplies it on the wire.
> + */
> + if (!cts && n) {
> + u64 computed = (u64)tmds_char_rate * n;
> +
> + do_div(computed, 128ULL * sample_rate);
> + cts = (unsigned int)computed;
> + }
> +
> dw_hdmi_qp_set_cts_n(hdmi, cts, n);
> }
Thanks for your patch. I cannot comment on the content but I can point for
formal issues with your submission.
Your patch got mangled by your mailer and cannot be applied. Please don't
try to convince your mailer to send patches the right way: save your time
and use "git-format patch + git send-email", or even better use b4.
Also your commit message is very detailed, and think it would be more
readable if split in paragraphs. You can have a look at various commits in
the kernel log for inspiration.
There's plenty of suggestions on how to send patches in [0], ensure you
read them all.
[0] https://docs.kernel.org/process/submitting-patches.html
Thanks!
Luca
--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
More information about the Linux-rockchip
mailing list