mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
To: "Maarten Lankhorst" <maarten.lankhorst@linux.intel.com>,
	"Maxime Ripard" <mripard@kernel.org>,
	"Thomas Zimmermann" <tzimmermann@suse.de>,
	"David Airlie" <airlied@gmail.com>,
	"Simona Vetter" <simona@ffwll.ch>,
	"Maíra Canal" <mcanal@igalia.com>
Cc: kernel@collabora.com, dri-devel@lists.freedesktop.org,
	 linux-kernel@vger.kernel.org
Subject: [PATCH 3/3] drm/display: hdmi: Reset sink scrambling on non-scrambled modesets
Date: Wed, 04 Nov 2026 15:26:22 +0200	[thread overview]
Message-ID: <20261104-hdmi-scdc-scramb-fixes-v1-3-16a9bb3d64a6@collabora.com> (raw)
In-Reply-To: <20261104-hdmi-scdc-scramb-fixes-v1-0-16a9bb3d64a6@collabora.com>

drm_connector_hdmi_disable_scrambling() only clears the sink SCDC status
when the connector is known to be connected.  That is never true when a
source driver disables scrambling at boot to clean up after the
firmware, as vc4 does from vc4_crtc_disable_at_boot(), where
connector->status is still unknown and no EDID has been read.

A sink left scrambling by the firmware thus keeps both Scrambling_Enable
and the 1/40 TMDS bit clock ratio set.  If the first modeset picks a
mode below 340 MHz, no disable happens in between, since the CRTC was
never active in atomic state, and drm_connector_hdmi_enable_scrambling()
returns early, leaving the sink trying to descramble an unscrambled
stream.

Instead of blind SCDC writes at boot towards a possibly absent sink,
reset the sink status from drm_connector_hdmi_enable_scrambling() when
no scrambling is required.  By then the sink has been probed, and HDMI
2.0 expects a scrambling capable sink to have Scrambling_Enable cleared
below 340 MHz anyway.  The reset runs regardless of source scrambler
support, since the firmware may have left the sink scrambling.

Factor the reset out into a helper also used by the disable and error
paths, gated only on drm_scdc_sink_supports_scrambling(), which suffices
because drm_display_info is zeroed until the first EDID read and reset
on disconnect, making the connector->status check redundant.  As the
helper now runs on every non-scrambled modeset, read SCDC_TMDS_CONFIG
first and only clear the bits actually set, so the common case costs a
single DDC read.

Fixes: d653818324ed ("drm/display: hdmi: Add HDMI 2.0 scrambling management helpers")
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
 drivers/gpu/drm/display/drm_hdmi_helper.c | 45 ++++++++++++++++++++++++-------
 1 file changed, 36 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/display/drm_hdmi_helper.c b/drivers/gpu/drm/display/drm_hdmi_helper.c
index 974d5de6d380..278cfda38e18 100644
--- a/drivers/gpu/drm/display/drm_hdmi_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_helper.c
@@ -470,6 +470,28 @@ static bool drm_scdc_sink_supports_scrambling(struct drm_connector *connector)
 	       info->hdmi.scdc.scrambling.supported;
 }
 
+static void drm_connector_hdmi_reset_sink_scrambling(struct drm_connector *connector)
+{
+	struct drm_device *dev = connector->dev;
+	u8 config;
+	int ret;
+
+	if (!connector->ddc || !drm_scdc_sink_supports_scrambling(connector))
+		return;
+
+	ret = drm_scdc_readb(connector->ddc, SCDC_TMDS_CONFIG, &config);
+	if (ret) {
+		drm_dbg_kms(dev, "Failed to read TMDS config: %d\n", ret);
+		return;
+	}
+
+	if (config & SCDC_SCRAMBLING_ENABLE)
+		drm_scdc_set_scrambling(connector, false);
+
+	if (config & SCDC_TMDS_BIT_CLOCK_RATIO_BY_40)
+		drm_scdc_set_high_tmds_clock_ratio(connector, false);
+}
+
 static int drm_connector_hdmi_try_scrambling_setup(struct drm_connector *connector)
 {
 	bool done;
@@ -522,6 +544,11 @@ static void drm_connector_hdmi_scdc_work(struct work_struct *work)
  * the sink side and retry the operation, as some displays refuse to set the
  * scrambling bit right away.
  *
+ * When @conn_state doesn't require scrambling, the sink-side SCDC status is
+ * reset instead, so that a sink left scrambling by a state the driver did not
+ * control, e.g. set up by the firmware before boot, doesn't end up out of sync
+ * with the source.
+ *
  * The work item is cancelled by drm_connector_hdmi_disable_scrambling(), hence
  * source drivers must ensure the display pipeline is shut down on unbind, e.g.
  * via drm_atomic_helper_shutdown(). Otherwise the work may outlive the driver's
@@ -541,8 +568,14 @@ int drm_connector_hdmi_enable_scrambling(struct drm_connector *connector,
 	if (!conn_state)
 		return -EINVAL;
 
-	if (!conn_state->hdmi.scrambler_needed)
+	if (!conn_state->hdmi.scrambler_needed) {
+		/*
+		 * Resync the sink here, where it is known to be connected
+		 * and its capabilities have been parsed.
+		 */
+		drm_connector_hdmi_reset_sink_scrambling(connector);
 		return 0;
+	}
 
 	if (!drm_connector_hdmi_scrambler_supported(connector)) {
 		drm_dbg_kms(dev, "Source doesn't support scrambling.\n");
@@ -581,8 +614,7 @@ int drm_connector_hdmi_enable_scrambling(struct drm_connector *connector,
 		WRITE_ONCE(hdmi->scrambler_enabled, false);
 		cancel_delayed_work_sync(&hdmi->scdc_work);
 
-		drm_scdc_set_scrambling(connector, false);
-		drm_scdc_set_high_tmds_clock_ratio(connector, false);
+		drm_connector_hdmi_reset_sink_scrambling(connector);
 	}
 
 	return ret;
@@ -619,12 +651,7 @@ int drm_connector_hdmi_disable_scrambling(struct drm_connector *connector)
 	if (hdmi->scdc_work_initialized)
 		cancel_delayed_work_sync(&hdmi->scdc_work);
 
-	if (connector->ddc &&
-	    connector->status == connector_status_connected &&
-	    drm_scdc_sink_supports_scrambling(connector)) {
-		drm_scdc_set_scrambling(connector, false);
-		drm_scdc_set_high_tmds_clock_ratio(connector, false);
-	}
+	drm_connector_hdmi_reset_sink_scrambling(connector);
 
 	return hdmi->funcs->scrambler_disable(connector);
 }

-- 
2.55.0


  parent reply	other threads:[~2026-11-04 13:26 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-04 13:26 [PATCH 0/3] drm/display: hdmi: Fix SCDC scrambling corner cases Cristian Ciocaltea
2026-11-04 13:26 ` [PATCH 1/3] drm/display: hdmi: Prevent NULL pointer dereference in sync_scdc() Cristian Ciocaltea
2026-11-09 12:00   ` Maíra Canal
2026-11-09 12:39     ` Cristian Ciocaltea
2026-11-09 12:40       ` Maíra Canal
2026-11-04 13:26 ` [PATCH 2/3] drm/display: hdmi: Use committed state to decide on SCDC resync Cristian Ciocaltea
2026-11-09 12:04   ` Maíra Canal
2026-11-04 13:26 ` Cristian Ciocaltea [this message]
2026-11-09 12:15   ` [PATCH 3/3] drm/display: hdmi: Reset sink scrambling on non-scrambled modesets Maíra Canal

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261104-hdmi-scdc-scramb-fixes-v1-3-16a9bb3d64a6@collabora.com \
    --to=cristian.ciocaltea@collabora.com \
    --cc=airlied@gmail.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=kernel@collabora.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=maarten.lankhorst@linux.intel.com \
    --cc=mcanal@igalia.com \
    --cc=mripard@kernel.org \
    --cc=simona@ffwll.ch \
    --cc=tzimmermann@suse.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®