* Re: [PATCH] drm/vc4: hdmi: write SCDC TMDS_Bit_Clock_Ratio before the TMDS clock starts
[not found] <20261020134941.631907-1-lucas.tanure@neat.no>
@ 2026-10-20 14:22 ` sashiko-bot
0 siblings, 0 replies; only message in thread
From: sashiko-bot @ 2026-10-20 14:22 UTC (permalink / raw)
To: Lucas Tanure; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] drm/vc4: hdmi: SCDC bits updated while TMDS clock runs on BCM2712
- [Medium] drm/vc4: hdmi: split SCDC and scrambler enable across crtc callbacks
- [Medium] drm/vc4: hdmi: race with scrambling_work when disabling scrambling in powerdown
--
commit 5be38e4d64847031b3ada407365354ff41c9b9d0
Author: Lucas Tanure <lucas.tanure@neat.no>
drm/vc4: hdmi: write SCDC TMDS_Bit_Clock_Ratio before the TMDS clock starts
This commit moves the SCDC high TMDS clock ratio and scrambling configuration
into vc4_hdmi_encoder_pre_crtc_configure() before PHY initialization, and
moves vc4_hdmi_disable_scrambling() into
vc4_hdmi_encoder_post_crtc_powerdown() after phy_disable().
Link: https://github.com/raspberrypi/linux/issues/7693
> diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
> index 3a90dbb61f4ea..11b9811bb97cf 100644
> --- a/drivers/gpu/drm/vc4/vc4_hdmi.c
> +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
> @@ -812,9 +812,6 @@ static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder)
> if (!drm_dev_enter(drm, &idx))
> return;
>
> - drm_scdc_set_high_tmds_clock_ratio(connector, true);
> - drm_scdc_set_scrambling(connector, true);
> -
> spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
> HDMI_WRITE(HDMI_SCRAMBLER_CTL, HDMI_READ(HDMI_SCRAMBLER_CTL) |
> VC5_HDMI_SCRAMBLER_CTL_ENABLE);
> @@ -919,8 +916,6 @@ static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder,
> spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
> }
>
> - vc4_hdmi_disable_scrambling(encoder);
> -
> drm_dev_exit(idx);
>
> out:
> @@ -948,6 +943,8 @@ static void vc4_hdmi_encoder_post_crtc_powerdown(struct drm_encoder *encoder,
> if (vc4_hdmi->variant->phy_disable)
> vc4_hdmi->variant->phy_disable(vc4_hdmi);
>
> + vc4_hdmi_disable_scrambling(encoder);
> +
[Severity: High]
Does moving vc4_hdmi_disable_scrambling() after variant->phy_disable()
actually stop the TMDS clock before clearing the SCDC bits on BCM2712?
While bcm2711_hdmi0_variant sets .phy_disable to vc5_hdmi_phy_disable() (which
calls vc5_hdmi_reset_phy()), bcm2712_hdmi0_variant and bcm2712_hdmi1_variant
set .phy_disable to vc6_hdmi_phy_disable(), which is an empty stub:
drivers/gpu/drm/vc4/vc4_hdmi_phy.c:
void vc6_hdmi_phy_disable(struct vc4_hdmi *vc4_hdmi)
{
}
Because clk_disable_unprepare() and pm_runtime_put() have not executed yet in
vc4_hdmi_encoder_post_crtc_powerdown(), vc4_hdmi_disable_scrambling() still
clears SCDC_SCRAMBLING_ENABLE and SCDC_TMDS_BIT_CLOCK_RATIO_BY_40 while the
BCM2712 PHY PLL and TX clock lane (VC6_HDMI_TX_PHY_HDMI_POWERUP_CTL_TX_CK_PWRUP)
are powered up and outputting the TMDS clock.
Furthermore, during a mode switch (for example from 1080p60 to 3840x2160@60)
or a hotplug link reset via vc4_hdmi_connector_detect_ctx() ->
vc4_hdmi_handle_hotplug() -> vc4_hdmi_reset_link() ->
drm_atomic_helper_reset_crtc(), runtime PM may not synchronously suspend and
reset the hardware between drm_atomic_helper_commit_modeset_disables() and
drm_atomic_helper_commit_modeset_enables() (for instance when pm_runtime_put()
is asynchronous, when CEC holds a runtime PM reference via
vc4_hdmi_cec_enable(), or when vc4_hdmi_connector_detect_ctx() holds a runtime
PM reference across vc4_hdmi_handle_hotplug()). Since vc6_hdmi_phy_disable()
did not call vc6_hdmi_reset_phy(), won't the previous mode's TMDS clock still
be running when vc4_hdmi_encoder_pre_crtc_configure() writes the SCDC
registers and waits 1-2 ms before vc6_hdmi_phy_init() finally calls
vc6_hdmi_reset_phy()?
[Severity: Medium]
Can deferring vc4_hdmi_disable_scrambling() to
vc4_hdmi_encoder_post_crtc_powerdown() race with vc4_hdmi->scrambling_work and
leave SCDC scrambling enabled after teardown?
During vc4_crtc_atomic_disable() -> vc4_crtc_disable(),
vc4_hdmi_encoder_post_crtc_disable() stops HDMI output and drops
vc4_hdmi->mutex, followed by vc4_crtc_pixelvalve_reset(),
vc4_hvs_stop_channel(), and variant->phy_disable(). Throughout this teardown
sequence, vc4_hdmi->scrambling_work remains armed while the link and PHY are
shut down, causing the sink to drop SCDC_SCRAMBLING_STATUS to 0.
If scrambling_work fires during this window and vc4_hdmi_scrambling_wq()
starts executing on system_percpu_wq before vc4_hdmi_disable_scrambling() is
called, delayed_work_pending(&vc4_hdmi->scrambling_work) will return false in
vc4_hdmi_disable_scrambling():
drivers/gpu/drm/vc4/vc4_hdmi.c:vc4_hdmi_disable_scrambling() {
...
if (delayed_work_pending(&vc4_hdmi->scrambling_work))
cancel_delayed_work_sync(&vc4_hdmi->scrambling_work);
...
}
Because vc4_hdmi_scrambling_wq() neither acquires vc4_hdmi->mutex nor checks
vc4_hdmi->scdc_enabled:
drivers/gpu/drm/vc4/vc4_hdmi.c:vc4_hdmi_scrambling_wq() {
...
if (drm_scdc_get_scrambling_status(connector))
return;
drm_scdc_set_high_tmds_clock_ratio(connector, true);
drm_scdc_set_scrambling(connector, true);
queue_delayed_work(system_percpu_wq, &vc4_hdmi->scrambling_work,
msecs_to_jiffies(SCRAMBLING_POLLING_DELAY_MS));
}
won't the in-flight worker observe drm_scdc_get_scrambling_status(connector)
returning false, write SCDC_TMDS_BIT_CLOCK_RATIO_BY_40 and
SCDC_SCRAMBLING_ENABLE back to true on the sink, and re-queue scrambling_work
every second after vc4_hdmi_disable_scrambling() has finished?
> clk_disable_unprepare(vc4_hdmi->pixel_bvb_clock);
> clk_disable_unprepare(vc4_hdmi->pixel_clock);
>
> @@ -1555,6 +1552,13 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
> goto err_disable_pixel_clock;
> }
>
> + if (vc4_hdmi_supports_scrambling(vc4_hdmi) &&
> + vc4_hdmi_mode_needs_scrambling(mode, vc4_hdmi->output_bpc, vc4_hdmi->output_format)) {
> + drm_scdc_set_high_tmds_clock_ratio(connector, true);
> + drm_scdc_set_scrambling(connector, true);
> + usleep_range(1000, 2000);
> + }
> +
[Severity: Medium]
Is it intentional to enable SCDC scrambling in the sink here in
vc4_hdmi_encoder_pre_crtc_configure(), while leaving the source scrambler
enable (VC5_HDMI_SCRAMBLER_CTL_ENABLE) and vc4_hdmi->scdc_enabled = true at
the end of vc4_hdmi_encoder_post_crtc_enable()?
During vc4_atomic_commit_tail() -> drm_atomic_helper_commit_modeset_enables()
-> vc4_crtc_atomic_enable() for a mode above 340 MHz, after
vc4_hdmi_encoder_pre_crtc_configure() sets SCDC_SCRAMBLING_ENABLE in the sink,
the driver runs phy_init(), set_timings(), enables the PixelValve, and then in
vc4_hdmi_encoder_post_crtc_enable() enables video output, waits for
VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE, enables packet RAM, transmits
InfoFrames via drm_atomic_helper_connector_hdmi_update_infoframes(), and calls
vc4_hdmi_recenter_fifo() before finally calling vc4_hdmi_enable_scrambling():
drivers/gpu/drm/vc4/vc4_hdmi.c:vc4_hdmi_encoder_post_crtc_enable() {
...
if (display->is_hdmi) {
...
HDMI_WRITE(HDMI_RAM_PACKET_CONFIG,
VC4_HDMI_RAM_PACKET_ENABLE);
spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
vc4_hdmi->packet_ram_enabled = true;
drm_atomic_helper_connector_hdmi_update_infoframes(connector, state);
}
vc4_hdmi_recenter_fifo(vc4_hdmi);
vc4_hdmi_enable_scrambling(encoder);
}
During that window, the sink's descrambler is enabled while the source is
transmitting unscrambled TMDS control periods, video data, and initial
InfoFrames.
In addition, because vc4_hdmi->mutex is dropped between
vc4_hdmi_encoder_pre_crtc_configure() and vc4_hdmi_encoder_post_crtc_enable(),
if vc4_hdmi_enable_scrambling() returns early (for example if a concurrent
vc4_hdmi_connector_detect_ctx() -> vc4_hdmi_handle_hotplug() ->
drm_atomic_helper_connector_hdmi_hotplug() updates connector->display_info so
vc4_hdmi_supports_scrambling() returns false, or if drm_dev_enter() fails),
vc4_hdmi->scdc_enabled will remain false while the sink's SCDC bits are left
enabled, causing vc4_hdmi_disable_scrambling() to skip clearing them on
disable.
Also, drm_scdc_set_high_tmds_clock_ratio() in
drivers/gpu/drm/display/drm_scdc_helper.c already calls usleep_range(1000,
2000) before returning, so is the additional usleep_range(1000, 2000) here
needed?
> if (vc4_hdmi->variant->phy_init)
> vc4_hdmi->variant->phy_init(vc4_hdmi, conn_state);
>
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261020134941.631907-1-lucas.tanure@neat.no?part=1
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2026-10-20 14:22 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20261020134941.631907-1-lucas.tanure@neat.no>
2026-10-20 14:22 ` [PATCH] drm/vc4: hdmi: write SCDC TMDS_Bit_Clock_Ratio before the TMDS clock starts sashiko-bot
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.