* [PATCH v7 00/30] Add HDMI 2.0 support to DW HDMI QP TX
@ 2026-06-01 22:44 ` Cristian Ciocaltea
0 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip,
Dmitry Baryshkov, Diederik de Haas, Maud Spierings
Enable HDMI 2.0 display modes (e.g. 4K@60Hz) on the Synopsys DW HDMI QP
TX controller, as found in Rockchip RK3576 & RK3588 SoCs, by adding SCDC
management for high TMDS clock ratio and scrambling.
Since SCDC state is lost on sink disconnects, the bridge driver needs to
trigger a CRTC reset during connector detection. To support this, the
series introduces the connector and bridge scrambling infrastructure
(patches 1-8), wires it up through the bridge connector layer with an
atomic-aware detect_ctx hook (patches 9-11), then implements the SCDC
scrambling feature in the DW HDMI QP bridge driver (patches 12-15).
Patches 16-18 are minor cleanups in the Rockchip platform driver.
Patches 19-23 improve HPD handling by deferring IRQ registration until
the connector is fully initialized, adding .enable_hpd()/.disable_hpd()
PHY ops, and restricting HPD events to the affected connector.
Patches 24-25 convert vc4 HDMI to the common SCDC scrambling helpers as
a proof of reuse, replacing the driver-local scrambling implementation.
Patches 26-30 add KUnit tests: connector scrambler validation, a new
4K@60Hz 600MHz EDID, hdmi_state_helper scrambling tests, and EDID
conformity fixes for some of the existing test blobs.
This has been tested on the following boards:
* Radxa ROCK 5B (RK3588)
* Radxa ROCK 4D (RK3576)
* Raspberry Pi 5 Model B Rev 1.1 (BCM2712 D0)
Regards,
Cristian
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
Changes in v7:
- Split the scrambler_needed flag computation from the SCDC scrambling
helpers into a standalone hdmi_state_helper patch for clarity (new
patch 6)
- Added vc4 HDMI conversion to common TMDS char rate constants and SCDC
scrambling helpers as a proof of reuse (new patches 24-25)
- Added KUnit tests for connector scrambler_supported/callback
consistency validation (new patch 26)
- Added 4K@60Hz 600MHz TMDS test EDID for high-rate scrambling coverage
(new patch 27)
- Added KUnit tests for hdmi_state_helper scrambler_needed flag:
low-rate, high-rate, and source-no-support cases (new patch 28)
- Fixed EDID conformity issues (edid-decode v1.33.0 failures) in the
existing 1080p+4K YUV420 200MHz and 4K RGB/YUV 340MHz test EDIDs
without changing the capabilities used by existing tests (new patches
29-30)
- Rebased onto latest drm-misc-next
- Link to v6: https://patch.msgid.link/20260520-dw-hdmi-qp-scramb-v6-0-24b74603b782@collabora.com
Changes in v6:
- Collected R-b & A-b tags from Dmitry and Heiko
- Restructured the series from 10 into 22 patches, splitting the SCDC
scrambling helpers, connector infrastructure, bridge operations,
bridge_connector plumbing, dw-hdmi-qp implementation, and Rockchip
platform changes into distinct commits
- Added drm_scdc_dbg() macro to simplify debug messages (new patch)
- Added drm_scdc_start/stop/sync_status() helpers for full scrambling
lifecycle management (reworked from v5 patch 5)
- Added drm_atomic_helper_connector_hdmi_hotplug_ctx() to propagate
modeset acquire context for SCDC sync on hotplug (new patch)
- Added connector scrambler callbacks and SCDC work/flag infrastructure
as a separate patch (split from v5 patch 5)
- Added DRM_BRIDGE_OP_HDMI_SCRAMBLER bridge operation with
hdmi_scrambler_enable/disable callbacks (new patch)
- Implemented bridge_connector scrambler interface wiring (new patch)
- Added .enable_hpd()/.disable_hpd() PHY ops for dw-hdmi-qp bridge and
Rockchip platform drivers, replacing the obsolete .setup_hpd() op
- Added dw_hdmi_qp_hpd_notify() helper for targeted connector-only HPD
notification (split from v5 patch 10)
- Dropped drm_fb_helper_hotplug_event() unused variable (new cleanup)
- Dropped unused drm_simple_kms_helper.h include (new cleanup)
- Masked RK3576 HPD IRQ in io_init() for consistency with RK3588
- Rebased onto latest drm-misc-next
- Link to v5: https://patch.msgid.link/20260426-dw-hdmi-qp-scramb-v5-0-d778e70c317b@collabora.com
Changes in v5:
- Added new patches: 1/10, 3/10, 6/10, 7/10, 8/10
- Removed redundant no-op error check in drm_bridge_helper_reset_crtc()
(patch 1)
- Removed the EDEADLK retry loop from the bridge .detect_ctx() callback,
as that's already handled in the drm_bridge_detect_ctx() helper or by
the caller when ctx is provided (patch 2)
- Refactored drm_bridge_detect() to delegate to drm_bridge_detect_ctx()
and added a WARN_ON for unexpected negative return values (patch 2)
- Split the bridge-connector .detect_ctx() switch into a preparatory
patch to use cached connector status in .get_modes() (patch 3)
- Improved error handling in SCDC scrambling setup: roll back high TMDS
clock ratio on scrambling failure, reset scramb_enabled flag on
set_scramb failure, and add SCDC version read/write error checks
(patch 5)
- Annotated scramb_enabled with READ_ONCE/WRITE_ONCE for cross-context
access between modeset paths and the scrambling work item (patch 5)
- Renamed SCDC_MIN_SOURCE_VERSION to SCDC_MAX_SOURCE_VERSION (patch 5)
- Rate limited i2c error messages (patch 6)
- Added missing newlines in dev_err_probe() messages (patch 7)
- Replaced indirect device pointer accesses with local dev variable in
bind() (patch 8)
- Split the HPD connector restriction (formerly patch 4/4): register HPD
IRQ after connector setup first (patch 9), then restrict HPD event to
the affected connector (patch 10); also collected R-b from Heiko
- Rebased onto latest drm-misc-next
- Link to v4: https://lore.kernel.org/r/20260303-dw-hdmi-qp-scramb-v4-0-317d3b8bd219@collabora.com
Changes in v4:
- Fixed conflicts while rebasing onto latest drm-misc-next
- Link to v3: https://lore.kernel.org/r/20260119-dw-hdmi-qp-scramb-v3-0-bd8611730fc1@collabora.com
Changes in v3:
- Used drm_bridge_helper_reset_crtc() helper to reset the display
pipeline and got rid of some boilerplate code (Maxime)
- Rebased onto latest drm-misc-next
- Link to v2: https://lore.kernel.org/r/20260113-dw-hdmi-qp-scramb-v2-0-ae7b2c58d24d@collabora.com
Changes in v2:
- Collected Tested-by tags from Diederik and Maud
- Rebased onto latest drm-misc-next
- Ensured the recently introduced 'no-hpd' support for dealing with
unconnected/repurposed/broken HPD pin is limited to HDMI 1.4 rates
- Link to v1: https://lore.kernel.org/r/20251203-dw-hdmi-qp-scramb-v1-0-836fe7401a69@collabora.com
---
Cristian Ciocaltea (30):
drm/fb-helper: Remove unused local variable in hotplug_event()
drm/connector: Add HDMI 2.0 scrambler infrastructure
drm/display: scdc_helper: Add macro for connector-prefixed debug messages
drm/display: scdc_helper: Add HDMI 2.0 scrambling management helpers
drm/display: hdmi_state_helper: Add ctx-aware hotplug helper for SCDC sync
drm/display: hdmi_state_helper: Plumb HDMI 2.0 source scrambling capability
drm/bridge: Remove redundant error check in drm_bridge_helper_reset_crtc()
drm/bridge: Add HDMI 2.0 scrambler bridge operation and callbacks
drm/display: bridge_connector: Use cached connector status in .get_modes()
drm/display: bridge_connector: Switch to .detect_ctx() connector helper
drm/display: bridge_connector: Wire up HDMI 2.0 scrambler callbacks
drm/bridge: dw-hdmi-qp: Rate limit i2c read error messages
drm/bridge: dw-hdmi-qp: Provide .{enable|disable}_hpd() PHY ops
drm/bridge: dw-hdmi-qp: Add HDMI 2.0 SCDC scrambling support
drm/bridge: dw-hdmi-qp: Provide dw_hdmi_qp_hpd_notify() helper
drm/rockchip: dw_hdmi_qp: Add missing newlines in dev_err_probe() messages
drm/rockchip: dw_hdmi_qp: Use local dev variable consistently in bind()
drm/rockchip: dw_hdmi_qp: Drop unnecessary #include
drm/rockchip: dw_hdmi_qp: Defer HPD IRQ enable until after connector setup
drm/rockchip: dw_hdmi_qp: Mask HPD IRQ in rk3576_io_init()
drm/rockchip: dw_hdmi_qp: Implement .{enable|disable}_hpd() PHY ops
drm/rockchip: dw_hdmi_qp: Switch to dw_hdmi_qp_hpd_notify()
drm/bridge: dw-hdmi-qp: Remove obsolete .setup_hpd() phy op
drm/vc4: hdmi: Use common TMDS char rate constants
drm/vc4: hdmi: Convert to common HDMI 2.0 SCDC scrambling helpers
drm/tests: connector: Add HDMI source-side scrambler capability tests
drm/tests: edid: Add 4K@60Hz EDID with 600MHz TMDS
drm/tests: hdmi_state_helper: Add HDMI 2.0 scrambling tests
drm/tests: edid: Fix conformity for 1080p+4K YUV420 200MHz EDID
drm/tests: edid: Fix conformity for 4K RGB/YUV 340MHz EDID
drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 132 ++++++++--
drivers/gpu/drm/display/drm_bridge_connector.c | 119 ++++++---
drivers/gpu/drm/display/drm_hdmi_state_helper.c | 55 +++-
drivers/gpu/drm/display/drm_scdc_helper.c | 269 ++++++++++++++++++--
drivers/gpu/drm/drm_bridge_helper.c | 2 -
drivers/gpu/drm/drm_connector.c | 18 ++
drivers/gpu/drm/drm_fb_helper.c | 11 +-
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 130 +++++-----
drivers/gpu/drm/tests/drm_connector_test.c | 132 ++++++++++
drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 219 ++++++++++++++++
drivers/gpu/drm/tests/drm_kunit_edid.h | 250 ++++++++++++++----
drivers/gpu/drm/vc4/vc4_hdmi.c | 278 +++------------------
drivers/gpu/drm/vc4/vc4_hdmi.h | 8 -
include/drm/bridge/dw_hdmi_qp.h | 4 +-
include/drm/display/drm_hdmi_state_helper.h | 4 +
include/drm/display/drm_scdc_helper.h | 6 +-
include/drm/drm_bridge.h | 26 ++
include/drm/drm_connector.h | 81 ++++++
18 files changed, 1285 insertions(+), 459 deletions(-)
---
base-commit: e84b07e0a30b371117f9a1120a4645c213f39cd9
change-id: 20251203-dw-hdmi-qp-scramb-cdbd8b57ccf9
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply [flat|nested] 72+ messages in thread* [PATCH v7 01/30] drm/fb-helper: Remove unused local variable in hotplug_event()
2026-06-01 22:44 ` Cristian Ciocaltea
@ 2026-06-01 22:44 ` Cristian Ciocaltea
-1 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
Remove the 'err' local variable in drm_fb_helper_hotplug_event() which
only stores a return value that is never used beyond the immediate
return statement. This simplifies the code without behavior changes.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/drm_fb_helper.c | 11 +++--------
1 file changed, 3 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 7b11a582f8ec..3316bb00a662 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -1744,21 +1744,17 @@ EXPORT_SYMBOL(drm_fb_helper_initial_config);
*/
int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
{
- int err = 0;
-
if (!drm_fbdev_emulation || !fb_helper)
return 0;
mutex_lock(&fb_helper->lock);
- if (fb_helper->deferred_setup) {
- err = __drm_fb_helper_initial_config_and_unlock(fb_helper);
- return err;
- }
+ if (fb_helper->deferred_setup)
+ return __drm_fb_helper_initial_config_and_unlock(fb_helper);
if (!fb_helper->fb || !drm_master_internal_acquire(fb_helper->dev)) {
fb_helper->delayed_hotplug = true;
mutex_unlock(&fb_helper->lock);
- return err;
+ return 0;
}
drm_master_internal_release(fb_helper->dev);
@@ -1802,4 +1798,3 @@ bool drm_fb_helper_gem_is_fb(const struct drm_fb_helper *fb_helper,
return gem == obj;
}
EXPORT_SYMBOL_GPL(drm_fb_helper_gem_is_fb);
-
--
2.54.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH v7 01/30] drm/fb-helper: Remove unused local variable in hotplug_event()
@ 2026-06-01 22:44 ` Cristian Ciocaltea
0 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
Remove the 'err' local variable in drm_fb_helper_hotplug_event() which
only stores a return value that is never used beyond the immediate
return statement. This simplifies the code without behavior changes.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/drm_fb_helper.c | 11 +++--------
1 file changed, 3 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 7b11a582f8ec..3316bb00a662 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -1744,21 +1744,17 @@ EXPORT_SYMBOL(drm_fb_helper_initial_config);
*/
int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
{
- int err = 0;
-
if (!drm_fbdev_emulation || !fb_helper)
return 0;
mutex_lock(&fb_helper->lock);
- if (fb_helper->deferred_setup) {
- err = __drm_fb_helper_initial_config_and_unlock(fb_helper);
- return err;
- }
+ if (fb_helper->deferred_setup)
+ return __drm_fb_helper_initial_config_and_unlock(fb_helper);
if (!fb_helper->fb || !drm_master_internal_acquire(fb_helper->dev)) {
fb_helper->delayed_hotplug = true;
mutex_unlock(&fb_helper->lock);
- return err;
+ return 0;
}
drm_master_internal_release(fb_helper->dev);
@@ -1802,4 +1798,3 @@ bool drm_fb_helper_gem_is_fb(const struct drm_fb_helper *fb_helper,
return gem == obj;
}
EXPORT_SYMBOL_GPL(drm_fb_helper_gem_is_fb);
-
--
2.54.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 72+ messages in thread* Re: [PATCH v7 01/30] drm/fb-helper: Remove unused local variable in hotplug_event()
2026-06-01 22:44 ` Cristian Ciocaltea
@ 2026-06-11 9:49 ` Maxime Ripard
-1 siblings, 0 replies; 72+ messages in thread
From: Maxime Ripard @ 2026-06-11 9:49 UTC (permalink / raw)
To: Cristian Ciocaltea
Cc: dri-devel, kernel, linux-arm-kernel, linux-kernel, linux-rockchip,
Andrzej Hajda, Andy Yan, Daniel Stone, Dave Stevenson,
David Airlie, Heiko Stübner, Jernej Skrabec, Jonas Karlman,
Laurent Pinchart, Luca Ceresoli, Maarten Lankhorst, Maxime Ripard,
Maíra Canal, Neil Armstrong, Raspberry Pi Kernel Maintenance,
Robert Foss, Sandy Huang, Simona Vetter, Thomas Zimmermann
On Tue, 2 Jun 2026 01:44:01 +0300, Cristian Ciocaltea wrote:
> Remove the 'err' local variable in drm_fb_helper_hotplug_event() which
> only stores a return value that is never used beyond the immediate
> return statement. This simplifies the code without behavior changes.
>
> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
>
> [ ... ]
Acked-by: Maxime Ripard <mripard@kernel.org>
Thanks!
Maxime
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH v7 01/30] drm/fb-helper: Remove unused local variable in hotplug_event()
@ 2026-06-11 9:49 ` Maxime Ripard
0 siblings, 0 replies; 72+ messages in thread
From: Maxime Ripard @ 2026-06-11 9:49 UTC (permalink / raw)
To: Cristian Ciocaltea
Cc: dri-devel, kernel, linux-arm-kernel, linux-kernel, linux-rockchip,
Andrzej Hajda, Andy Yan, Daniel Stone, Dave Stevenson,
David Airlie, Heiko Stübner, Jernej Skrabec, Jonas Karlman,
Laurent Pinchart, Luca Ceresoli, Maarten Lankhorst, Maxime Ripard,
Maíra Canal, Neil Armstrong, Raspberry Pi Kernel Maintenance,
Robert Foss, Sandy Huang, Simona Vetter, Thomas Zimmermann
On Tue, 2 Jun 2026 01:44:01 +0300, Cristian Ciocaltea wrote:
> Remove the 'err' local variable in drm_fb_helper_hotplug_event() which
> only stores a return value that is never used beyond the immediate
> return statement. This simplifies the code without behavior changes.
>
> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
>
> [ ... ]
Acked-by: Maxime Ripard <mripard@kernel.org>
Thanks!
Maxime
^ permalink raw reply [flat|nested] 72+ messages in thread
* [PATCH v7 02/30] drm/connector: Add HDMI 2.0 scrambler infrastructure
2026-06-01 22:44 ` Cristian Ciocaltea
@ 2026-06-01 22:44 ` Cristian Ciocaltea
-1 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
Add the connector-level infrastructure to support HDMI 2.0 scrambling:
- A scrambler_supported flag to indicate whether the source supports the
scrambling capability, in which case the newly introduced
.scrambler_{enable|disable}() callbacks in drm_connector_hdmi_funcs
are mandatory
- A scrambler_needed flag to be managed by the hdmi state helpers based
on the negotiated TMDS character rate and the source/sink scrambling
capabilities
- A scrambler_enabled flag to track whether scrambling is currently
active
- A delayed work item (scdc_work) with an associated callback (scdc_cb)
to monitor sink-side scrambling status and retry the setup if the sink
resets it
These are intended to be used by SCDC scrambling helpers to coordinate
scrambling setup and teardown between the source driver and the DRM
core.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/drm_connector.c | 18 +++++++++
include/drm/drm_connector.h | 81 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 99 insertions(+)
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index a5d13b92b665..526dc2931b8a 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -220,6 +220,19 @@ void drm_connector_free_work_fn(struct work_struct *work)
}
}
+static void drm_connector_hdmi_scdc_work(struct work_struct *work)
+{
+ struct drm_connector *connector;
+ struct drm_connector_hdmi *hdmi;
+
+ hdmi = container_of(to_delayed_work(work), struct drm_connector_hdmi,
+ scdc_work);
+ connector = container_of(hdmi, struct drm_connector, hdmi);
+
+ if (hdmi->scdc_cb)
+ hdmi->scdc_cb(connector);
+}
+
static int drm_connector_init_only(struct drm_device *dev,
struct drm_connector *connector,
const struct drm_connector_funcs *funcs,
@@ -285,6 +298,7 @@ static int drm_connector_init_only(struct drm_device *dev,
mutex_init(&connector->edid_override_mutex);
mutex_init(&connector->hdmi.infoframes.lock);
mutex_init(&connector->hdmi_audio.lock);
+ INIT_DELAYED_WORK(&connector->hdmi.scdc_work, drm_connector_hdmi_scdc_work);
connector->edid_blob_ptr = NULL;
connector->epoch_counter = 0;
connector->tile_blob_ptr = NULL;
@@ -606,6 +620,10 @@ int drmm_connector_hdmi_init(struct drm_device *dev,
!hdmi_funcs->hdmi.write_infoframe)
return -EINVAL;
+ if (connector->hdmi.scrambler_supported &&
+ (!hdmi_funcs->scrambler_enable || !hdmi_funcs->scrambler_disable))
+ return -EINVAL;
+
ret = drmm_connector_init(dev, connector, funcs, connector_type, ddc);
if (ret)
return ret;
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 529755c2e862..f1c5c15a6cce 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -28,6 +28,7 @@
#include <linux/ctype.h>
#include <linux/hdmi.h>
#include <linux/notifier.h>
+#include <linux/workqueue.h>
#include <drm/drm_mode_object.h>
#include <drm/drm_util.h>
#include <drm/drm_property.h>
@@ -1057,6 +1058,19 @@ struct drm_connector_hdmi_state {
* @tmds_char_rate: TMDS Character Rate, in Hz.
*/
unsigned long long tmds_char_rate;
+
+ /**
+ * @scrambler_needed: Whether HDMI 2.0 SCDC scrambling is required
+ * for the negotiated mode/bpc/format.
+ *
+ * Computed by drm_atomic_helper_connector_hdmi_check() from
+ * @tmds_char_rate and the source/sink scrambling capabilities.
+ *
+ * Per HDMI 2.0, scrambling is mandatory above 340 MHz TMDS
+ * character rate. Optional scrambling at lower rates is
+ * deliberately not requested by the helper.
+ */
+ bool scrambler_needed;
};
/**
@@ -1358,6 +1372,36 @@ struct drm_connector_hdmi_funcs {
*/
const struct drm_edid *(*read_edid)(struct drm_connector *connector);
+ /**
+ * @scrambler_enable:
+ *
+ * This callback is invoked through @drm_scdc_start_scrambling during
+ * a commit to setup SCDC scrambling and high TMDS clock ratio on
+ * source side.
+ *
+ * The @scrambler_enable callback is mandatory if HDMI 2.0 is to be
+ * supported.
+ *
+ * Returns:
+ * 0 on success, a negative error code otherwise
+ */
+ int (*scrambler_enable)(struct drm_connector *connector);
+
+ /**
+ * @scrambler_disable:
+ *
+ * This callback is invoked through @drm_scdc_stop_scrambling during
+ * a commit to disable SCDC scrambling and high TMDS clock ratio on
+ * source side.
+ *
+ * The @scrambler_disable callback is mandatory if HDMI 2.0 is to be
+ * supported.
+ *
+ * Returns:
+ * 0 on success, a negative error code otherwise
+ */
+ int (*scrambler_disable)(struct drm_connector *connector);
+
/**
* @avi:
*
@@ -1960,6 +2004,43 @@ struct drm_connector_hdmi {
*/
unsigned long supported_formats;
+ /**
+ * @scrambler_supported: Indicates whether the HDMI controller
+ * (source) supports HDMI 2.0 SCDC scrambling.
+ *
+ * When true, @drm_connector_hdmi_funcs.scrambler_enable and
+ * @drm_connector_hdmi_funcs.scrambler_disable are mandatory.
+ * This is enforced by drmm_connector_hdmi_init().
+ *
+ * For HDMI bridge based drivers using drm_bridge_connector_init(),
+ * this is propagated automatically from bridges that set the
+ * DRM_BRIDGE_OP_HDMI_SCRAMBLER flag in their &drm_bridge->ops.
+ * Other drivers must set this field on @connector->hdmi before calling
+ * drmm_connector_hdmi_init().
+ */
+ bool scrambler_supported;
+
+ /**
+ * @scrambler_enabled: Tracks whether HDMI 2.0 scrambler is currently enabled.
+ */
+ bool scrambler_enabled;
+
+ /**
+ * @scdc_work: Work item currently used to monitor sink-side scrambling
+ * status and retry setup if the sink resets it.
+ */
+ struct delayed_work scdc_work;
+
+ /** @scdc_cb: Callback to be invoked as part of @scdc_work.
+ *
+ * Currently used to monitor sink-side scrambling status and retry
+ * setup if the sink resets it.
+ *
+ * This is assigned by the framework when making use of
+ * drm_scdc_start_scrambling() helper.
+ */
+ void (*scdc_cb)(struct drm_connector *connector);
+
/**
* @funcs: HDMI connector Control Functions
*/
--
2.54.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH v7 02/30] drm/connector: Add HDMI 2.0 scrambler infrastructure
@ 2026-06-01 22:44 ` Cristian Ciocaltea
0 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
Add the connector-level infrastructure to support HDMI 2.0 scrambling:
- A scrambler_supported flag to indicate whether the source supports the
scrambling capability, in which case the newly introduced
.scrambler_{enable|disable}() callbacks in drm_connector_hdmi_funcs
are mandatory
- A scrambler_needed flag to be managed by the hdmi state helpers based
on the negotiated TMDS character rate and the source/sink scrambling
capabilities
- A scrambler_enabled flag to track whether scrambling is currently
active
- A delayed work item (scdc_work) with an associated callback (scdc_cb)
to monitor sink-side scrambling status and retry the setup if the sink
resets it
These are intended to be used by SCDC scrambling helpers to coordinate
scrambling setup and teardown between the source driver and the DRM
core.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/drm_connector.c | 18 +++++++++
include/drm/drm_connector.h | 81 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 99 insertions(+)
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index a5d13b92b665..526dc2931b8a 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -220,6 +220,19 @@ void drm_connector_free_work_fn(struct work_struct *work)
}
}
+static void drm_connector_hdmi_scdc_work(struct work_struct *work)
+{
+ struct drm_connector *connector;
+ struct drm_connector_hdmi *hdmi;
+
+ hdmi = container_of(to_delayed_work(work), struct drm_connector_hdmi,
+ scdc_work);
+ connector = container_of(hdmi, struct drm_connector, hdmi);
+
+ if (hdmi->scdc_cb)
+ hdmi->scdc_cb(connector);
+}
+
static int drm_connector_init_only(struct drm_device *dev,
struct drm_connector *connector,
const struct drm_connector_funcs *funcs,
@@ -285,6 +298,7 @@ static int drm_connector_init_only(struct drm_device *dev,
mutex_init(&connector->edid_override_mutex);
mutex_init(&connector->hdmi.infoframes.lock);
mutex_init(&connector->hdmi_audio.lock);
+ INIT_DELAYED_WORK(&connector->hdmi.scdc_work, drm_connector_hdmi_scdc_work);
connector->edid_blob_ptr = NULL;
connector->epoch_counter = 0;
connector->tile_blob_ptr = NULL;
@@ -606,6 +620,10 @@ int drmm_connector_hdmi_init(struct drm_device *dev,
!hdmi_funcs->hdmi.write_infoframe)
return -EINVAL;
+ if (connector->hdmi.scrambler_supported &&
+ (!hdmi_funcs->scrambler_enable || !hdmi_funcs->scrambler_disable))
+ return -EINVAL;
+
ret = drmm_connector_init(dev, connector, funcs, connector_type, ddc);
if (ret)
return ret;
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 529755c2e862..f1c5c15a6cce 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -28,6 +28,7 @@
#include <linux/ctype.h>
#include <linux/hdmi.h>
#include <linux/notifier.h>
+#include <linux/workqueue.h>
#include <drm/drm_mode_object.h>
#include <drm/drm_util.h>
#include <drm/drm_property.h>
@@ -1057,6 +1058,19 @@ struct drm_connector_hdmi_state {
* @tmds_char_rate: TMDS Character Rate, in Hz.
*/
unsigned long long tmds_char_rate;
+
+ /**
+ * @scrambler_needed: Whether HDMI 2.0 SCDC scrambling is required
+ * for the negotiated mode/bpc/format.
+ *
+ * Computed by drm_atomic_helper_connector_hdmi_check() from
+ * @tmds_char_rate and the source/sink scrambling capabilities.
+ *
+ * Per HDMI 2.0, scrambling is mandatory above 340 MHz TMDS
+ * character rate. Optional scrambling at lower rates is
+ * deliberately not requested by the helper.
+ */
+ bool scrambler_needed;
};
/**
@@ -1358,6 +1372,36 @@ struct drm_connector_hdmi_funcs {
*/
const struct drm_edid *(*read_edid)(struct drm_connector *connector);
+ /**
+ * @scrambler_enable:
+ *
+ * This callback is invoked through @drm_scdc_start_scrambling during
+ * a commit to setup SCDC scrambling and high TMDS clock ratio on
+ * source side.
+ *
+ * The @scrambler_enable callback is mandatory if HDMI 2.0 is to be
+ * supported.
+ *
+ * Returns:
+ * 0 on success, a negative error code otherwise
+ */
+ int (*scrambler_enable)(struct drm_connector *connector);
+
+ /**
+ * @scrambler_disable:
+ *
+ * This callback is invoked through @drm_scdc_stop_scrambling during
+ * a commit to disable SCDC scrambling and high TMDS clock ratio on
+ * source side.
+ *
+ * The @scrambler_disable callback is mandatory if HDMI 2.0 is to be
+ * supported.
+ *
+ * Returns:
+ * 0 on success, a negative error code otherwise
+ */
+ int (*scrambler_disable)(struct drm_connector *connector);
+
/**
* @avi:
*
@@ -1960,6 +2004,43 @@ struct drm_connector_hdmi {
*/
unsigned long supported_formats;
+ /**
+ * @scrambler_supported: Indicates whether the HDMI controller
+ * (source) supports HDMI 2.0 SCDC scrambling.
+ *
+ * When true, @drm_connector_hdmi_funcs.scrambler_enable and
+ * @drm_connector_hdmi_funcs.scrambler_disable are mandatory.
+ * This is enforced by drmm_connector_hdmi_init().
+ *
+ * For HDMI bridge based drivers using drm_bridge_connector_init(),
+ * this is propagated automatically from bridges that set the
+ * DRM_BRIDGE_OP_HDMI_SCRAMBLER flag in their &drm_bridge->ops.
+ * Other drivers must set this field on @connector->hdmi before calling
+ * drmm_connector_hdmi_init().
+ */
+ bool scrambler_supported;
+
+ /**
+ * @scrambler_enabled: Tracks whether HDMI 2.0 scrambler is currently enabled.
+ */
+ bool scrambler_enabled;
+
+ /**
+ * @scdc_work: Work item currently used to monitor sink-side scrambling
+ * status and retry setup if the sink resets it.
+ */
+ struct delayed_work scdc_work;
+
+ /** @scdc_cb: Callback to be invoked as part of @scdc_work.
+ *
+ * Currently used to monitor sink-side scrambling status and retry
+ * setup if the sink resets it.
+ *
+ * This is assigned by the framework when making use of
+ * drm_scdc_start_scrambling() helper.
+ */
+ void (*scdc_cb)(struct drm_connector *connector);
+
/**
* @funcs: HDMI connector Control Functions
*/
--
2.54.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH v7 03/30] drm/display: scdc_helper: Add macro for connector-prefixed debug messages
2026-06-01 22:44 ` Cristian Ciocaltea
@ 2026-06-01 22:44 ` Cristian Ciocaltea
-1 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
Introduce the drm_scdc_dbg() wrapper over drm_dbg_kms() to help getting
rid of the boilerplate around prefixing the debug messages with the
connector information.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_scdc_helper.c | 24 +++++++++---------------
1 file changed, 9 insertions(+), 15 deletions(-)
diff --git a/drivers/gpu/drm/display/drm_scdc_helper.c b/drivers/gpu/drm/display/drm_scdc_helper.c
index df878aad4a36..cb6632346aad 100644
--- a/drivers/gpu/drm/display/drm_scdc_helper.c
+++ b/drivers/gpu/drm/display/drm_scdc_helper.c
@@ -55,6 +55,10 @@
#define SCDC_I2C_SLAVE_ADDRESS 0x54
+#define drm_scdc_dbg(connector, fmt, ...) \
+ drm_dbg_kms((connector)->dev, "[CONNECTOR:%d:%s] " fmt, \
+ (connector)->base.id, (connector)->name, ##__VA_ARGS__)
+
/**
* drm_scdc_read - read a block of data from SCDC
* @adapter: I2C controller
@@ -158,9 +162,7 @@ bool drm_scdc_get_scrambling_status(struct drm_connector *connector)
ret = drm_scdc_readb(connector->ddc, SCDC_SCRAMBLER_STATUS, &status);
if (ret < 0) {
- drm_dbg_kms(connector->dev,
- "[CONNECTOR:%d:%s] Failed to read scrambling status: %d\n",
- connector->base.id, connector->name, ret);
+ drm_scdc_dbg(connector, "Failed to read scrambling status: %d\n", ret);
return false;
}
@@ -188,9 +190,7 @@ bool drm_scdc_set_scrambling(struct drm_connector *connector,
ret = drm_scdc_readb(connector->ddc, SCDC_TMDS_CONFIG, &config);
if (ret < 0) {
- drm_dbg_kms(connector->dev,
- "[CONNECTOR:%d:%s] Failed to read TMDS config: %d\n",
- connector->base.id, connector->name, ret);
+ drm_scdc_dbg(connector, "Failed to read TMDS config: %d\n", ret);
return false;
}
@@ -201,9 +201,7 @@ bool drm_scdc_set_scrambling(struct drm_connector *connector,
ret = drm_scdc_writeb(connector->ddc, SCDC_TMDS_CONFIG, config);
if (ret < 0) {
- drm_dbg_kms(connector->dev,
- "[CONNECTOR:%d:%s] Failed to enable scrambling: %d\n",
- connector->base.id, connector->name, ret);
+ drm_scdc_dbg(connector, "Failed to enable scrambling: %d\n", ret);
return false;
}
@@ -248,9 +246,7 @@ bool drm_scdc_set_high_tmds_clock_ratio(struct drm_connector *connector,
ret = drm_scdc_readb(connector->ddc, SCDC_TMDS_CONFIG, &config);
if (ret < 0) {
- drm_dbg_kms(connector->dev,
- "[CONNECTOR:%d:%s] Failed to read TMDS config: %d\n",
- connector->base.id, connector->name, ret);
+ drm_scdc_dbg(connector, "Failed to read TMDS config: %d\n", ret);
return false;
}
@@ -261,9 +257,7 @@ bool drm_scdc_set_high_tmds_clock_ratio(struct drm_connector *connector,
ret = drm_scdc_writeb(connector->ddc, SCDC_TMDS_CONFIG, config);
if (ret < 0) {
- drm_dbg_kms(connector->dev,
- "[CONNECTOR:%d:%s] Failed to set TMDS clock ratio: %d\n",
- connector->base.id, connector->name, ret);
+ drm_scdc_dbg(connector, "Failed to set TMDS clock ratio: %d\n", ret);
return false;
}
--
2.54.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH v7 03/30] drm/display: scdc_helper: Add macro for connector-prefixed debug messages
@ 2026-06-01 22:44 ` Cristian Ciocaltea
0 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
Introduce the drm_scdc_dbg() wrapper over drm_dbg_kms() to help getting
rid of the boilerplate around prefixing the debug messages with the
connector information.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_scdc_helper.c | 24 +++++++++---------------
1 file changed, 9 insertions(+), 15 deletions(-)
diff --git a/drivers/gpu/drm/display/drm_scdc_helper.c b/drivers/gpu/drm/display/drm_scdc_helper.c
index df878aad4a36..cb6632346aad 100644
--- a/drivers/gpu/drm/display/drm_scdc_helper.c
+++ b/drivers/gpu/drm/display/drm_scdc_helper.c
@@ -55,6 +55,10 @@
#define SCDC_I2C_SLAVE_ADDRESS 0x54
+#define drm_scdc_dbg(connector, fmt, ...) \
+ drm_dbg_kms((connector)->dev, "[CONNECTOR:%d:%s] " fmt, \
+ (connector)->base.id, (connector)->name, ##__VA_ARGS__)
+
/**
* drm_scdc_read - read a block of data from SCDC
* @adapter: I2C controller
@@ -158,9 +162,7 @@ bool drm_scdc_get_scrambling_status(struct drm_connector *connector)
ret = drm_scdc_readb(connector->ddc, SCDC_SCRAMBLER_STATUS, &status);
if (ret < 0) {
- drm_dbg_kms(connector->dev,
- "[CONNECTOR:%d:%s] Failed to read scrambling status: %d\n",
- connector->base.id, connector->name, ret);
+ drm_scdc_dbg(connector, "Failed to read scrambling status: %d\n", ret);
return false;
}
@@ -188,9 +190,7 @@ bool drm_scdc_set_scrambling(struct drm_connector *connector,
ret = drm_scdc_readb(connector->ddc, SCDC_TMDS_CONFIG, &config);
if (ret < 0) {
- drm_dbg_kms(connector->dev,
- "[CONNECTOR:%d:%s] Failed to read TMDS config: %d\n",
- connector->base.id, connector->name, ret);
+ drm_scdc_dbg(connector, "Failed to read TMDS config: %d\n", ret);
return false;
}
@@ -201,9 +201,7 @@ bool drm_scdc_set_scrambling(struct drm_connector *connector,
ret = drm_scdc_writeb(connector->ddc, SCDC_TMDS_CONFIG, config);
if (ret < 0) {
- drm_dbg_kms(connector->dev,
- "[CONNECTOR:%d:%s] Failed to enable scrambling: %d\n",
- connector->base.id, connector->name, ret);
+ drm_scdc_dbg(connector, "Failed to enable scrambling: %d\n", ret);
return false;
}
@@ -248,9 +246,7 @@ bool drm_scdc_set_high_tmds_clock_ratio(struct drm_connector *connector,
ret = drm_scdc_readb(connector->ddc, SCDC_TMDS_CONFIG, &config);
if (ret < 0) {
- drm_dbg_kms(connector->dev,
- "[CONNECTOR:%d:%s] Failed to read TMDS config: %d\n",
- connector->base.id, connector->name, ret);
+ drm_scdc_dbg(connector, "Failed to read TMDS config: %d\n", ret);
return false;
}
@@ -261,9 +257,7 @@ bool drm_scdc_set_high_tmds_clock_ratio(struct drm_connector *connector,
ret = drm_scdc_writeb(connector->ddc, SCDC_TMDS_CONFIG, config);
if (ret < 0) {
- drm_dbg_kms(connector->dev,
- "[CONNECTOR:%d:%s] Failed to set TMDS clock ratio: %d\n",
- connector->base.id, connector->name, ret);
+ drm_scdc_dbg(connector, "Failed to set TMDS clock ratio: %d\n", ret);
return false;
}
--
2.54.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 72+ messages in thread* Re: [PATCH v7 03/30] drm/display: scdc_helper: Add macro for connector-prefixed debug messages
2026-06-01 22:44 ` Cristian Ciocaltea
@ 2026-06-11 15:19 ` Maxime Ripard
-1 siblings, 0 replies; 72+ messages in thread
From: Maxime Ripard @ 2026-06-11 15:19 UTC (permalink / raw)
To: Cristian Ciocaltea
Cc: dri-devel, kernel, linux-arm-kernel, linux-kernel, linux-rockchip,
Andrzej Hajda, Andy Yan, Daniel Stone, Dave Stevenson,
David Airlie, Heiko Stübner, Jernej Skrabec, Jonas Karlman,
Laurent Pinchart, Luca Ceresoli, Maarten Lankhorst, Maxime Ripard,
Maíra Canal, Neil Armstrong, Raspberry Pi Kernel Maintenance,
Robert Foss, Sandy Huang, Simona Vetter, Thomas Zimmermann
On Tue, 2 Jun 2026 01:44:03 +0300, Cristian Ciocaltea wrote:
> Introduce the drm_scdc_dbg() wrapper over drm_dbg_kms() to help getting
> rid of the boilerplate around prefixing the debug messages with the
> connector information.
>
> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
>
> [ ... ]
Acked-by: Maxime Ripard <mripard@kernel.org>
Thanks!
Maxime
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH v7 03/30] drm/display: scdc_helper: Add macro for connector-prefixed debug messages
@ 2026-06-11 15:19 ` Maxime Ripard
0 siblings, 0 replies; 72+ messages in thread
From: Maxime Ripard @ 2026-06-11 15:19 UTC (permalink / raw)
To: Cristian Ciocaltea
Cc: dri-devel, kernel, linux-arm-kernel, linux-kernel, linux-rockchip,
Andrzej Hajda, Andy Yan, Daniel Stone, Dave Stevenson,
David Airlie, Heiko Stübner, Jernej Skrabec, Jonas Karlman,
Laurent Pinchart, Luca Ceresoli, Maarten Lankhorst, Maxime Ripard,
Maíra Canal, Neil Armstrong, Raspberry Pi Kernel Maintenance,
Robert Foss, Sandy Huang, Simona Vetter, Thomas Zimmermann
On Tue, 2 Jun 2026 01:44:03 +0300, Cristian Ciocaltea wrote:
> Introduce the drm_scdc_dbg() wrapper over drm_dbg_kms() to help getting
> rid of the boilerplate around prefixing the debug messages with the
> connector information.
>
> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
>
> [ ... ]
Acked-by: Maxime Ripard <mripard@kernel.org>
Thanks!
Maxime
^ permalink raw reply [flat|nested] 72+ messages in thread
* [PATCH v7 04/30] drm/display: scdc_helper: Add HDMI 2.0 scrambling management helpers
2026-06-01 22:44 ` Cristian Ciocaltea
@ 2026-06-01 22:44 ` Cristian Ciocaltea
-1 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
Add helpers to manage the full lifecycle of HDMI 2.0 SCDC scrambling on
both source and sink sides:
- drm_scdc_start_scrambling(): configures SCDC scrambling and high TMDS
clock ratio and starts a periodic work item that monitors the sink's
SCDC scrambling status, retrying setup when the sink loses state
- drm_scdc_stop_scrambling(): tears down scrambling on both sides and
cancels the monitoring work
- drm_scdc_sync_status(): triggers a CRTC reset on reconnection to
restore SCDC state lost during sink disconnects within an active
display pipeline
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_scdc_helper.c | 245 +++++++++++++++++++++++++++++-
include/drm/display/drm_scdc_helper.h | 6 +-
2 files changed, 244 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/display/drm_scdc_helper.c b/drivers/gpu/drm/display/drm_scdc_helper.c
index cb6632346aad..f71728e5ca81 100644
--- a/drivers/gpu/drm/display/drm_scdc_helper.c
+++ b/drivers/gpu/drm/display/drm_scdc_helper.c
@@ -21,15 +21,22 @@
* DEALINGS IN THE SOFTWARE.
*/
+#include <linux/delay.h>
#include <linux/export.h>
#include <linux/i2c.h>
+#include <linux/minmax.h>
#include <linux/slab.h>
-#include <linux/delay.h>
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge_helper.h>
+#include <drm/drm_connector.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_device.h>
+#include <drm/drm_modeset_lock.h>
+#include <drm/drm_print.h>
#include <drm/display/drm_scdc_helper.h>
-#include <drm/drm_connector.h>
-#include <drm/drm_device.h>
-#include <drm/drm_print.h>
/**
* DOC: scdc helpers
@@ -50,10 +57,14 @@
* has to track the connector status changes using interrupts and
* restore the SCDC status. The typical solution for this is to trigger an
* empty modeset in drm_connector_helper_funcs.detect_ctx(), like what vc4 does
- * in vc4_hdmi_reset_link().
+ * in vc4_hdmi_reset_link(). Alternatively, use the HDMI connector framework
+ * which ensures drm_scdc_sync_status() is called in the context of
+ * drm_atomic_helper_connector_hdmi_hotplug_ctx().
*/
-#define SCDC_I2C_SLAVE_ADDRESS 0x54
+#define SCDC_I2C_SLAVE_ADDRESS 0x54
+#define SCDC_MAX_SOURCE_VERSION 0x1
+#define SCDC_STATUS_POLL_DELAY_MS 1000
#define drm_scdc_dbg(connector, fmt, ...) \
drm_dbg_kms((connector)->dev, "[CONNECTOR:%d:%s] " fmt, \
@@ -270,3 +281,225 @@ bool drm_scdc_set_high_tmds_clock_ratio(struct drm_connector *connector,
return true;
}
EXPORT_SYMBOL(drm_scdc_set_high_tmds_clock_ratio);
+
+static int drm_scdc_try_scrambling_setup(struct drm_connector *connector)
+{
+ bool done;
+
+ done = drm_scdc_set_high_tmds_clock_ratio(connector, true);
+ if (!done)
+ return -EIO;
+
+ done = drm_scdc_set_scrambling(connector, true);
+ if (!done)
+ return -EIO;
+
+ if (READ_ONCE(connector->hdmi.scrambler_enabled))
+ schedule_delayed_work(&connector->hdmi.scdc_work,
+ msecs_to_jiffies(SCDC_STATUS_POLL_DELAY_MS));
+
+ return 0;
+}
+
+static void drm_scdc_monitor_scrambler(struct drm_connector *connector)
+{
+ if (READ_ONCE(connector->hdmi.scrambler_enabled) &&
+ !drm_scdc_get_scrambling_status(connector))
+ drm_scdc_try_scrambling_setup(connector);
+}
+
+static int drm_scdc_reset_crtc(struct drm_connector *connector,
+ struct drm_modeset_acquire_ctx *ctx)
+{
+ struct drm_device *dev = connector->dev;
+ struct drm_crtc *crtc;
+ u8 config;
+ int ret;
+
+ if (!ctx)
+ return 0;
+
+ /*
+ * This is normally part of .detect_ctx() call path, which already holds
+ * connection_mutex through @ctx. However, re-acquiring it with the
+ * same context is a no-op and makes the helper safe under any caller.
+ */
+ ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
+ if (ret)
+ return ret;
+
+ if (!connector->state)
+ return 0;
+
+ crtc = connector->state->crtc;
+ if (!crtc)
+ return 0;
+
+ ret = drm_scdc_readb(connector->ddc, SCDC_TMDS_CONFIG, &config);
+ if (ret) {
+ drm_scdc_dbg(connector, "Failed to read TMDS config: %d\n", ret);
+ return ret;
+ }
+
+ if ((config & SCDC_SCRAMBLING_ENABLE) &&
+ (config & SCDC_TMDS_BIT_CLOCK_RATIO_BY_40))
+ return 0;
+
+ /*
+ * Reset the CRTC to suspend TMDS transmission, conforming to HDMI 2.0
+ * spec which requires scrambled data not to be sent before the sink is
+ * configured, and TMDS clock to be suspended while changing the clock
+ * ratio. The disable/re-enable cycle triggered by the reset should
+ * call drm_scdc_start_scrambling() during re-enable, properly
+ * configuring the sink before data transmission resumes.
+ */
+
+ drm_scdc_dbg(connector, "Resetting CRTC to restore SCDC status\n");
+
+ ret = drm_atomic_helper_reset_crtc(crtc, ctx);
+ if (ret && ret != -EDEADLK)
+ drm_scdc_dbg(connector, "Failed to reset CRTC: %d\n", ret);
+
+ return ret;
+}
+
+/**
+ * drm_scdc_start_scrambling - activate scrambling and monitor SCDC status
+ * @connector: connector
+ *
+ * Enables scrambling and high TMDS clock ratio on both source and sink sides.
+ * Additionally, use a delayed work item to monitor the scrambling status on
+ * the sink side and retry the operation, as some displays refuse to set the
+ * scrambling bit right away.
+ *
+ * Returns:
+ * Zero if scrambling is set successfully, an error code otherwise.
+ */
+int drm_scdc_start_scrambling(struct drm_connector *connector)
+{
+ struct drm_display_info *info = &connector->display_info;
+ struct drm_connector_hdmi *hdmi = &connector->hdmi;
+ int ret;
+ u8 ver;
+
+ if (!hdmi->scrambler_supported) {
+ drm_scdc_dbg(connector, "Scrambler not supported, bailing.\n");
+ return -EINVAL;
+ }
+
+ if (!info->is_hdmi ||
+ !info->hdmi.scdc.supported ||
+ !info->hdmi.scdc.scrambling.supported) {
+ drm_scdc_dbg(connector, "Sink doesn't support scrambling.\n");
+ return -EINVAL;
+ }
+
+ drm_scdc_dbg(connector, "Enabling scrambling\n");
+
+ ret = drm_scdc_readb(connector->ddc, SCDC_SINK_VERSION, &ver);
+ if (ret) {
+ drm_scdc_dbg(connector, "Failed to read SCDC_SINK_VERSION: %d\n", ret);
+ return ret;
+ }
+
+ ret = drm_scdc_writeb(connector->ddc, SCDC_SOURCE_VERSION,
+ min_t(u8, ver, SCDC_MAX_SOURCE_VERSION));
+ if (ret) {
+ drm_scdc_dbg(connector, "Failed to write SCDC_SOURCE_VERSION: %d\n", ret);
+ return ret;
+ }
+
+ hdmi->scdc_cb = drm_scdc_monitor_scrambler;
+ WRITE_ONCE(hdmi->scrambler_enabled, true);
+
+ ret = drm_scdc_try_scrambling_setup(connector);
+ if (!ret)
+ ret = hdmi->funcs->scrambler_enable(connector);
+
+ if (ret) {
+ WRITE_ONCE(hdmi->scrambler_enabled, false);
+ cancel_delayed_work_sync(&hdmi->scdc_work);
+ hdmi->scdc_cb = NULL;
+
+ drm_scdc_set_scrambling(connector, false);
+ drm_scdc_set_high_tmds_clock_ratio(connector, false);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(drm_scdc_start_scrambling);
+
+/**
+ * drm_scdc_stop_scrambling - deactivate scrambling and SCDC status monitor
+ * @connector: connector
+ *
+ * Disables scrambling and high TMDS clock ratio on both source and sink sides.
+ * Also cancels the SCDC status monitoring work item, if it is still pending.
+ *
+ * Returns:
+ * Zero if scrambling is reset successfully, an error code otherwise.
+ */
+int drm_scdc_stop_scrambling(struct drm_connector *connector)
+{
+ struct drm_display_info *info = &connector->display_info;
+ struct drm_connector_hdmi *hdmi = &connector->hdmi;
+
+ if (!hdmi->scrambler_supported) {
+ drm_scdc_dbg(connector, "Scrambler not supported, bailing.\n");
+ return -EINVAL;
+ }
+
+ if (!READ_ONCE(hdmi->scrambler_enabled))
+ return 0;
+
+ drm_scdc_dbg(connector, "Disabling scrambling\n");
+
+ WRITE_ONCE(hdmi->scrambler_enabled, false);
+ cancel_delayed_work_sync(&hdmi->scdc_work);
+ hdmi->scdc_cb = NULL;
+
+ if (connector->status == connector_status_connected &&
+ info->is_hdmi && info->hdmi.scdc.supported &&
+ info->hdmi.scdc.scrambling.supported) {
+ drm_scdc_set_scrambling(connector, false);
+ drm_scdc_set_high_tmds_clock_ratio(connector, false);
+ }
+
+ return hdmi->funcs->scrambler_disable(connector);
+}
+EXPORT_SYMBOL(drm_scdc_stop_scrambling);
+
+/**
+ * drm_scdc_sync_status - resync the sink-side SCDC upon reconnect
+ * @connector: connector
+ * @plugged: connector plugged status event
+ * @ctx: initialized lock acquisition context
+ *
+ * When receiving hotplug disconnect/reconnect event, while the display is
+ * still active (CRTC enabled), the SCDC status on the sink side is reset
+ * and must be explicitly restored.
+ *
+ * The typical solution for this is to trigger an empty modeset in
+ * drm_connector_helper_funcs.detect_ctx(), which is what this helper does
+ * by triggering a CRTC reset on reconnection.
+ *
+ * When making use of the HDMI connector framework, this is automatically
+ * triggered via drm_atomic_helper_connector_hdmi_hotplug_ctx().
+ *
+ * Returns:
+ * Zero on success, an error code otherwise, including -EDEADLK.
+ */
+int drm_scdc_sync_status(struct drm_connector *connector, bool plugged,
+ struct drm_modeset_acquire_ctx *ctx)
+{
+ struct drm_connector_hdmi *hdmi = &connector->hdmi;
+
+ if (hdmi->scrambler_supported && plugged &&
+ READ_ONCE(hdmi->scrambler_enabled))
+ return drm_scdc_reset_crtc(connector, ctx);
+
+ /* TODO: Also handle HDMI 2.1 FRL link training */
+
+ return 0;
+}
+EXPORT_SYMBOL(drm_scdc_sync_status);
diff --git a/include/drm/display/drm_scdc_helper.h b/include/drm/display/drm_scdc_helper.h
index 34600476a1b9..5d9a37bbb362 100644
--- a/include/drm/display/drm_scdc_helper.h
+++ b/include/drm/display/drm_scdc_helper.h
@@ -29,6 +29,7 @@
#include <drm/display/drm_scdc.h>
struct drm_connector;
+struct drm_modeset_acquire_ctx;
struct i2c_adapter;
ssize_t drm_scdc_read(struct i2c_adapter *adapter, u8 offset, void *buffer,
@@ -76,5 +77,8 @@ bool drm_scdc_get_scrambling_status(struct drm_connector *connector);
bool drm_scdc_set_scrambling(struct drm_connector *connector, bool enable);
bool drm_scdc_set_high_tmds_clock_ratio(struct drm_connector *connector, bool set);
-
+int drm_scdc_start_scrambling(struct drm_connector *connector);
+int drm_scdc_stop_scrambling(struct drm_connector *connector);
+int drm_scdc_sync_status(struct drm_connector *connector, bool plugged,
+ struct drm_modeset_acquire_ctx *ctx);
#endif
--
2.54.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH v7 04/30] drm/display: scdc_helper: Add HDMI 2.0 scrambling management helpers
@ 2026-06-01 22:44 ` Cristian Ciocaltea
0 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
Add helpers to manage the full lifecycle of HDMI 2.0 SCDC scrambling on
both source and sink sides:
- drm_scdc_start_scrambling(): configures SCDC scrambling and high TMDS
clock ratio and starts a periodic work item that monitors the sink's
SCDC scrambling status, retrying setup when the sink loses state
- drm_scdc_stop_scrambling(): tears down scrambling on both sides and
cancels the monitoring work
- drm_scdc_sync_status(): triggers a CRTC reset on reconnection to
restore SCDC state lost during sink disconnects within an active
display pipeline
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_scdc_helper.c | 245 +++++++++++++++++++++++++++++-
include/drm/display/drm_scdc_helper.h | 6 +-
2 files changed, 244 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/display/drm_scdc_helper.c b/drivers/gpu/drm/display/drm_scdc_helper.c
index cb6632346aad..f71728e5ca81 100644
--- a/drivers/gpu/drm/display/drm_scdc_helper.c
+++ b/drivers/gpu/drm/display/drm_scdc_helper.c
@@ -21,15 +21,22 @@
* DEALINGS IN THE SOFTWARE.
*/
+#include <linux/delay.h>
#include <linux/export.h>
#include <linux/i2c.h>
+#include <linux/minmax.h>
#include <linux/slab.h>
-#include <linux/delay.h>
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge_helper.h>
+#include <drm/drm_connector.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_device.h>
+#include <drm/drm_modeset_lock.h>
+#include <drm/drm_print.h>
#include <drm/display/drm_scdc_helper.h>
-#include <drm/drm_connector.h>
-#include <drm/drm_device.h>
-#include <drm/drm_print.h>
/**
* DOC: scdc helpers
@@ -50,10 +57,14 @@
* has to track the connector status changes using interrupts and
* restore the SCDC status. The typical solution for this is to trigger an
* empty modeset in drm_connector_helper_funcs.detect_ctx(), like what vc4 does
- * in vc4_hdmi_reset_link().
+ * in vc4_hdmi_reset_link(). Alternatively, use the HDMI connector framework
+ * which ensures drm_scdc_sync_status() is called in the context of
+ * drm_atomic_helper_connector_hdmi_hotplug_ctx().
*/
-#define SCDC_I2C_SLAVE_ADDRESS 0x54
+#define SCDC_I2C_SLAVE_ADDRESS 0x54
+#define SCDC_MAX_SOURCE_VERSION 0x1
+#define SCDC_STATUS_POLL_DELAY_MS 1000
#define drm_scdc_dbg(connector, fmt, ...) \
drm_dbg_kms((connector)->dev, "[CONNECTOR:%d:%s] " fmt, \
@@ -270,3 +281,225 @@ bool drm_scdc_set_high_tmds_clock_ratio(struct drm_connector *connector,
return true;
}
EXPORT_SYMBOL(drm_scdc_set_high_tmds_clock_ratio);
+
+static int drm_scdc_try_scrambling_setup(struct drm_connector *connector)
+{
+ bool done;
+
+ done = drm_scdc_set_high_tmds_clock_ratio(connector, true);
+ if (!done)
+ return -EIO;
+
+ done = drm_scdc_set_scrambling(connector, true);
+ if (!done)
+ return -EIO;
+
+ if (READ_ONCE(connector->hdmi.scrambler_enabled))
+ schedule_delayed_work(&connector->hdmi.scdc_work,
+ msecs_to_jiffies(SCDC_STATUS_POLL_DELAY_MS));
+
+ return 0;
+}
+
+static void drm_scdc_monitor_scrambler(struct drm_connector *connector)
+{
+ if (READ_ONCE(connector->hdmi.scrambler_enabled) &&
+ !drm_scdc_get_scrambling_status(connector))
+ drm_scdc_try_scrambling_setup(connector);
+}
+
+static int drm_scdc_reset_crtc(struct drm_connector *connector,
+ struct drm_modeset_acquire_ctx *ctx)
+{
+ struct drm_device *dev = connector->dev;
+ struct drm_crtc *crtc;
+ u8 config;
+ int ret;
+
+ if (!ctx)
+ return 0;
+
+ /*
+ * This is normally part of .detect_ctx() call path, which already holds
+ * connection_mutex through @ctx. However, re-acquiring it with the
+ * same context is a no-op and makes the helper safe under any caller.
+ */
+ ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
+ if (ret)
+ return ret;
+
+ if (!connector->state)
+ return 0;
+
+ crtc = connector->state->crtc;
+ if (!crtc)
+ return 0;
+
+ ret = drm_scdc_readb(connector->ddc, SCDC_TMDS_CONFIG, &config);
+ if (ret) {
+ drm_scdc_dbg(connector, "Failed to read TMDS config: %d\n", ret);
+ return ret;
+ }
+
+ if ((config & SCDC_SCRAMBLING_ENABLE) &&
+ (config & SCDC_TMDS_BIT_CLOCK_RATIO_BY_40))
+ return 0;
+
+ /*
+ * Reset the CRTC to suspend TMDS transmission, conforming to HDMI 2.0
+ * spec which requires scrambled data not to be sent before the sink is
+ * configured, and TMDS clock to be suspended while changing the clock
+ * ratio. The disable/re-enable cycle triggered by the reset should
+ * call drm_scdc_start_scrambling() during re-enable, properly
+ * configuring the sink before data transmission resumes.
+ */
+
+ drm_scdc_dbg(connector, "Resetting CRTC to restore SCDC status\n");
+
+ ret = drm_atomic_helper_reset_crtc(crtc, ctx);
+ if (ret && ret != -EDEADLK)
+ drm_scdc_dbg(connector, "Failed to reset CRTC: %d\n", ret);
+
+ return ret;
+}
+
+/**
+ * drm_scdc_start_scrambling - activate scrambling and monitor SCDC status
+ * @connector: connector
+ *
+ * Enables scrambling and high TMDS clock ratio on both source and sink sides.
+ * Additionally, use a delayed work item to monitor the scrambling status on
+ * the sink side and retry the operation, as some displays refuse to set the
+ * scrambling bit right away.
+ *
+ * Returns:
+ * Zero if scrambling is set successfully, an error code otherwise.
+ */
+int drm_scdc_start_scrambling(struct drm_connector *connector)
+{
+ struct drm_display_info *info = &connector->display_info;
+ struct drm_connector_hdmi *hdmi = &connector->hdmi;
+ int ret;
+ u8 ver;
+
+ if (!hdmi->scrambler_supported) {
+ drm_scdc_dbg(connector, "Scrambler not supported, bailing.\n");
+ return -EINVAL;
+ }
+
+ if (!info->is_hdmi ||
+ !info->hdmi.scdc.supported ||
+ !info->hdmi.scdc.scrambling.supported) {
+ drm_scdc_dbg(connector, "Sink doesn't support scrambling.\n");
+ return -EINVAL;
+ }
+
+ drm_scdc_dbg(connector, "Enabling scrambling\n");
+
+ ret = drm_scdc_readb(connector->ddc, SCDC_SINK_VERSION, &ver);
+ if (ret) {
+ drm_scdc_dbg(connector, "Failed to read SCDC_SINK_VERSION: %d\n", ret);
+ return ret;
+ }
+
+ ret = drm_scdc_writeb(connector->ddc, SCDC_SOURCE_VERSION,
+ min_t(u8, ver, SCDC_MAX_SOURCE_VERSION));
+ if (ret) {
+ drm_scdc_dbg(connector, "Failed to write SCDC_SOURCE_VERSION: %d\n", ret);
+ return ret;
+ }
+
+ hdmi->scdc_cb = drm_scdc_monitor_scrambler;
+ WRITE_ONCE(hdmi->scrambler_enabled, true);
+
+ ret = drm_scdc_try_scrambling_setup(connector);
+ if (!ret)
+ ret = hdmi->funcs->scrambler_enable(connector);
+
+ if (ret) {
+ WRITE_ONCE(hdmi->scrambler_enabled, false);
+ cancel_delayed_work_sync(&hdmi->scdc_work);
+ hdmi->scdc_cb = NULL;
+
+ drm_scdc_set_scrambling(connector, false);
+ drm_scdc_set_high_tmds_clock_ratio(connector, false);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(drm_scdc_start_scrambling);
+
+/**
+ * drm_scdc_stop_scrambling - deactivate scrambling and SCDC status monitor
+ * @connector: connector
+ *
+ * Disables scrambling and high TMDS clock ratio on both source and sink sides.
+ * Also cancels the SCDC status monitoring work item, if it is still pending.
+ *
+ * Returns:
+ * Zero if scrambling is reset successfully, an error code otherwise.
+ */
+int drm_scdc_stop_scrambling(struct drm_connector *connector)
+{
+ struct drm_display_info *info = &connector->display_info;
+ struct drm_connector_hdmi *hdmi = &connector->hdmi;
+
+ if (!hdmi->scrambler_supported) {
+ drm_scdc_dbg(connector, "Scrambler not supported, bailing.\n");
+ return -EINVAL;
+ }
+
+ if (!READ_ONCE(hdmi->scrambler_enabled))
+ return 0;
+
+ drm_scdc_dbg(connector, "Disabling scrambling\n");
+
+ WRITE_ONCE(hdmi->scrambler_enabled, false);
+ cancel_delayed_work_sync(&hdmi->scdc_work);
+ hdmi->scdc_cb = NULL;
+
+ if (connector->status == connector_status_connected &&
+ info->is_hdmi && info->hdmi.scdc.supported &&
+ info->hdmi.scdc.scrambling.supported) {
+ drm_scdc_set_scrambling(connector, false);
+ drm_scdc_set_high_tmds_clock_ratio(connector, false);
+ }
+
+ return hdmi->funcs->scrambler_disable(connector);
+}
+EXPORT_SYMBOL(drm_scdc_stop_scrambling);
+
+/**
+ * drm_scdc_sync_status - resync the sink-side SCDC upon reconnect
+ * @connector: connector
+ * @plugged: connector plugged status event
+ * @ctx: initialized lock acquisition context
+ *
+ * When receiving hotplug disconnect/reconnect event, while the display is
+ * still active (CRTC enabled), the SCDC status on the sink side is reset
+ * and must be explicitly restored.
+ *
+ * The typical solution for this is to trigger an empty modeset in
+ * drm_connector_helper_funcs.detect_ctx(), which is what this helper does
+ * by triggering a CRTC reset on reconnection.
+ *
+ * When making use of the HDMI connector framework, this is automatically
+ * triggered via drm_atomic_helper_connector_hdmi_hotplug_ctx().
+ *
+ * Returns:
+ * Zero on success, an error code otherwise, including -EDEADLK.
+ */
+int drm_scdc_sync_status(struct drm_connector *connector, bool plugged,
+ struct drm_modeset_acquire_ctx *ctx)
+{
+ struct drm_connector_hdmi *hdmi = &connector->hdmi;
+
+ if (hdmi->scrambler_supported && plugged &&
+ READ_ONCE(hdmi->scrambler_enabled))
+ return drm_scdc_reset_crtc(connector, ctx);
+
+ /* TODO: Also handle HDMI 2.1 FRL link training */
+
+ return 0;
+}
+EXPORT_SYMBOL(drm_scdc_sync_status);
diff --git a/include/drm/display/drm_scdc_helper.h b/include/drm/display/drm_scdc_helper.h
index 34600476a1b9..5d9a37bbb362 100644
--- a/include/drm/display/drm_scdc_helper.h
+++ b/include/drm/display/drm_scdc_helper.h
@@ -29,6 +29,7 @@
#include <drm/display/drm_scdc.h>
struct drm_connector;
+struct drm_modeset_acquire_ctx;
struct i2c_adapter;
ssize_t drm_scdc_read(struct i2c_adapter *adapter, u8 offset, void *buffer,
@@ -76,5 +77,8 @@ bool drm_scdc_get_scrambling_status(struct drm_connector *connector);
bool drm_scdc_set_scrambling(struct drm_connector *connector, bool enable);
bool drm_scdc_set_high_tmds_clock_ratio(struct drm_connector *connector, bool set);
-
+int drm_scdc_start_scrambling(struct drm_connector *connector);
+int drm_scdc_stop_scrambling(struct drm_connector *connector);
+int drm_scdc_sync_status(struct drm_connector *connector, bool plugged,
+ struct drm_modeset_acquire_ctx *ctx);
#endif
--
2.54.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH v7 05/30] drm/display: hdmi_state_helper: Add ctx-aware hotplug helper for SCDC sync
2026-06-01 22:44 ` Cristian Ciocaltea
@ 2026-06-01 22:44 ` Cristian Ciocaltea
-1 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
Introduce drm_atomic_helper_connector_hdmi_hotplug_ctx(), a variant of
drm_atomic_helper_connector_hdmi_hotplug() that accepts a
drm_modeset_acquire_ctx.
This enables SCDC status synchronization on hotplug events, which
requires lock acquisition context for performing the CRTC reset
triggered by drm_scdc_sync_status().
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_hdmi_state_helper.c | 40 ++++++++++++++++++++-----
include/drm/display/drm_hdmi_state_helper.h | 4 +++
2 files changed, 37 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
index a331ebdd65af..a96d81cbf94f 100644
--- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
@@ -12,6 +12,7 @@
#include <drm/display/drm_hdmi_cec_helper.h>
#include <drm/display/drm_hdmi_helper.h>
#include <drm/display/drm_hdmi_state_helper.h>
+#include <drm/display/drm_scdc_helper.h>
/**
* DOC: hdmi helpers
@@ -1150,18 +1151,20 @@ drm_atomic_helper_connector_hdmi_clear_audio_infoframe(struct drm_connector *con
}
EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_clear_audio_infoframe);
-static void
+static int
drm_atomic_helper_connector_hdmi_update(struct drm_connector *connector,
- enum drm_connector_status status)
+ enum drm_connector_status status,
+ struct drm_modeset_acquire_ctx *ctx)
{
const struct drm_edid *drm_edid;
+ int ret = 0;
if (status == connector_status_disconnected) {
- // TODO: also handle scramber, HDMI sink disconnected.
+ ret = drm_scdc_sync_status(connector, false, ctx);
drm_connector_hdmi_audio_plugged_notify(connector, false);
drm_edid_connector_update(connector, NULL);
drm_connector_cec_phys_addr_invalidate(connector);
- return;
+ return ret;
}
if (connector->hdmi.funcs->read_edid)
@@ -1174,10 +1177,12 @@ drm_atomic_helper_connector_hdmi_update(struct drm_connector *connector,
drm_edid_free(drm_edid);
if (status == connector_status_connected) {
- // TODO: also handle scramber, HDMI sink is now connected.
+ ret = drm_scdc_sync_status(connector, true, ctx);
drm_connector_hdmi_audio_plugged_notify(connector, true);
drm_connector_cec_phys_addr_set(connector);
}
+
+ return ret;
}
/**
@@ -1191,10 +1196,31 @@ drm_atomic_helper_connector_hdmi_update(struct drm_connector *connector,
void drm_atomic_helper_connector_hdmi_hotplug(struct drm_connector *connector,
enum drm_connector_status status)
{
- drm_atomic_helper_connector_hdmi_update(connector, status);
+ drm_atomic_helper_connector_hdmi_update(connector, status, NULL);
}
EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_hotplug);
+/**
+ * drm_atomic_helper_connector_hdmi_hotplug_ctx - Handle the hotplug event for the HDMI connector
+ * @connector: A pointer to the HDMI connector
+ * @status: Connection status
+ * @ctx: Lock acquisition context to be used for resetting CRTC
+ *
+ * This function should be called as a part of the .detect() / .detect_ctx()
+ * callbacks for all status changes.
+ *
+ * Returns:
+ * Zero on success, error code on failure.
+ * If @ctx is set, it might also return -EDEADLK.
+ */
+int drm_atomic_helper_connector_hdmi_hotplug_ctx(struct drm_connector *connector,
+ enum drm_connector_status status,
+ struct drm_modeset_acquire_ctx *ctx)
+{
+ return drm_atomic_helper_connector_hdmi_update(connector, status, ctx);
+}
+EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_hotplug_ctx);
+
/**
* drm_atomic_helper_connector_hdmi_force - HDMI Connector implementation of the force callback
* @connector: A pointer to the HDMI connector
@@ -1206,6 +1232,6 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_hotplug);
*/
void drm_atomic_helper_connector_hdmi_force(struct drm_connector *connector)
{
- drm_atomic_helper_connector_hdmi_update(connector, connector->status);
+ drm_atomic_helper_connector_hdmi_update(connector, connector->status, NULL);
}
EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_force);
diff --git a/include/drm/display/drm_hdmi_state_helper.h b/include/drm/display/drm_hdmi_state_helper.h
index 13375bd0f4ae..75fedd4a3ba8 100644
--- a/include/drm/display/drm_hdmi_state_helper.h
+++ b/include/drm/display/drm_hdmi_state_helper.h
@@ -7,6 +7,7 @@ struct drm_atomic_commit;
struct drm_connector;
struct drm_connector_state;
struct drm_display_mode;
+struct drm_modeset_acquire_ctx;
struct hdmi_audio_infoframe;
enum drm_connector_status;
@@ -24,6 +25,9 @@ int drm_atomic_helper_connector_hdmi_update_infoframes(struct drm_connector *con
struct drm_atomic_commit *state);
void drm_atomic_helper_connector_hdmi_hotplug(struct drm_connector *connector,
enum drm_connector_status status);
+int drm_atomic_helper_connector_hdmi_hotplug_ctx(struct drm_connector *connector,
+ enum drm_connector_status status,
+ struct drm_modeset_acquire_ctx *ctx);
void drm_atomic_helper_connector_hdmi_force(struct drm_connector *connector);
enum drm_mode_status
--
2.54.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH v7 05/30] drm/display: hdmi_state_helper: Add ctx-aware hotplug helper for SCDC sync
@ 2026-06-01 22:44 ` Cristian Ciocaltea
0 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
Introduce drm_atomic_helper_connector_hdmi_hotplug_ctx(), a variant of
drm_atomic_helper_connector_hdmi_hotplug() that accepts a
drm_modeset_acquire_ctx.
This enables SCDC status synchronization on hotplug events, which
requires lock acquisition context for performing the CRTC reset
triggered by drm_scdc_sync_status().
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_hdmi_state_helper.c | 40 ++++++++++++++++++++-----
include/drm/display/drm_hdmi_state_helper.h | 4 +++
2 files changed, 37 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
index a331ebdd65af..a96d81cbf94f 100644
--- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
@@ -12,6 +12,7 @@
#include <drm/display/drm_hdmi_cec_helper.h>
#include <drm/display/drm_hdmi_helper.h>
#include <drm/display/drm_hdmi_state_helper.h>
+#include <drm/display/drm_scdc_helper.h>
/**
* DOC: hdmi helpers
@@ -1150,18 +1151,20 @@ drm_atomic_helper_connector_hdmi_clear_audio_infoframe(struct drm_connector *con
}
EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_clear_audio_infoframe);
-static void
+static int
drm_atomic_helper_connector_hdmi_update(struct drm_connector *connector,
- enum drm_connector_status status)
+ enum drm_connector_status status,
+ struct drm_modeset_acquire_ctx *ctx)
{
const struct drm_edid *drm_edid;
+ int ret = 0;
if (status == connector_status_disconnected) {
- // TODO: also handle scramber, HDMI sink disconnected.
+ ret = drm_scdc_sync_status(connector, false, ctx);
drm_connector_hdmi_audio_plugged_notify(connector, false);
drm_edid_connector_update(connector, NULL);
drm_connector_cec_phys_addr_invalidate(connector);
- return;
+ return ret;
}
if (connector->hdmi.funcs->read_edid)
@@ -1174,10 +1177,12 @@ drm_atomic_helper_connector_hdmi_update(struct drm_connector *connector,
drm_edid_free(drm_edid);
if (status == connector_status_connected) {
- // TODO: also handle scramber, HDMI sink is now connected.
+ ret = drm_scdc_sync_status(connector, true, ctx);
drm_connector_hdmi_audio_plugged_notify(connector, true);
drm_connector_cec_phys_addr_set(connector);
}
+
+ return ret;
}
/**
@@ -1191,10 +1196,31 @@ drm_atomic_helper_connector_hdmi_update(struct drm_connector *connector,
void drm_atomic_helper_connector_hdmi_hotplug(struct drm_connector *connector,
enum drm_connector_status status)
{
- drm_atomic_helper_connector_hdmi_update(connector, status);
+ drm_atomic_helper_connector_hdmi_update(connector, status, NULL);
}
EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_hotplug);
+/**
+ * drm_atomic_helper_connector_hdmi_hotplug_ctx - Handle the hotplug event for the HDMI connector
+ * @connector: A pointer to the HDMI connector
+ * @status: Connection status
+ * @ctx: Lock acquisition context to be used for resetting CRTC
+ *
+ * This function should be called as a part of the .detect() / .detect_ctx()
+ * callbacks for all status changes.
+ *
+ * Returns:
+ * Zero on success, error code on failure.
+ * If @ctx is set, it might also return -EDEADLK.
+ */
+int drm_atomic_helper_connector_hdmi_hotplug_ctx(struct drm_connector *connector,
+ enum drm_connector_status status,
+ struct drm_modeset_acquire_ctx *ctx)
+{
+ return drm_atomic_helper_connector_hdmi_update(connector, status, ctx);
+}
+EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_hotplug_ctx);
+
/**
* drm_atomic_helper_connector_hdmi_force - HDMI Connector implementation of the force callback
* @connector: A pointer to the HDMI connector
@@ -1206,6 +1232,6 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_hotplug);
*/
void drm_atomic_helper_connector_hdmi_force(struct drm_connector *connector)
{
- drm_atomic_helper_connector_hdmi_update(connector, connector->status);
+ drm_atomic_helper_connector_hdmi_update(connector, connector->status, NULL);
}
EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_force);
diff --git a/include/drm/display/drm_hdmi_state_helper.h b/include/drm/display/drm_hdmi_state_helper.h
index 13375bd0f4ae..75fedd4a3ba8 100644
--- a/include/drm/display/drm_hdmi_state_helper.h
+++ b/include/drm/display/drm_hdmi_state_helper.h
@@ -7,6 +7,7 @@ struct drm_atomic_commit;
struct drm_connector;
struct drm_connector_state;
struct drm_display_mode;
+struct drm_modeset_acquire_ctx;
struct hdmi_audio_infoframe;
enum drm_connector_status;
@@ -24,6 +25,9 @@ int drm_atomic_helper_connector_hdmi_update_infoframes(struct drm_connector *con
struct drm_atomic_commit *state);
void drm_atomic_helper_connector_hdmi_hotplug(struct drm_connector *connector,
enum drm_connector_status status);
+int drm_atomic_helper_connector_hdmi_hotplug_ctx(struct drm_connector *connector,
+ enum drm_connector_status status,
+ struct drm_modeset_acquire_ctx *ctx);
void drm_atomic_helper_connector_hdmi_force(struct drm_connector *connector);
enum drm_mode_status
--
2.54.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 72+ messages in thread* Re: [PATCH v7 05/30] drm/display: hdmi_state_helper: Add ctx-aware hotplug helper for SCDC sync
2026-06-01 22:44 ` Cristian Ciocaltea
@ 2026-06-11 15:25 ` Maxime Ripard
-1 siblings, 0 replies; 72+ messages in thread
From: Maxime Ripard @ 2026-06-11 15:25 UTC (permalink / raw)
To: Cristian Ciocaltea
Cc: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Sandy Huang,
Heiko Stübner, Andy Yan, Daniel Stone, Dave Stevenson,
Maíra Canal, Raspberry Pi Kernel Maintenance, kernel,
dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
[-- Attachment #1: Type: text/plain, Size: 5580 bytes --]
On Tue, Jun 02, 2026 at 01:44:05AM +0300, Cristian Ciocaltea wrote:
> Introduce drm_atomic_helper_connector_hdmi_hotplug_ctx(), a variant of
> drm_atomic_helper_connector_hdmi_hotplug() that accepts a
> drm_modeset_acquire_ctx.
>
> This enables SCDC status synchronization on hotplug events, which
> requires lock acquisition context for performing the CRTC reset
> triggered by drm_scdc_sync_status().
>
> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
> ---
> drivers/gpu/drm/display/drm_hdmi_state_helper.c | 40 ++++++++++++++++++++-----
> include/drm/display/drm_hdmi_state_helper.h | 4 +++
> 2 files changed, 37 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
> index a331ebdd65af..a96d81cbf94f 100644
> --- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
> +++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
> @@ -12,6 +12,7 @@
> #include <drm/display/drm_hdmi_cec_helper.h>
> #include <drm/display/drm_hdmi_helper.h>
> #include <drm/display/drm_hdmi_state_helper.h>
> +#include <drm/display/drm_scdc_helper.h>
>
> /**
> * DOC: hdmi helpers
> @@ -1150,18 +1151,20 @@ drm_atomic_helper_connector_hdmi_clear_audio_infoframe(struct drm_connector *con
> }
> EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_clear_audio_infoframe);
>
> -static void
> +static int
> drm_atomic_helper_connector_hdmi_update(struct drm_connector *connector,
> - enum drm_connector_status status)
> + enum drm_connector_status status,
> + struct drm_modeset_acquire_ctx *ctx)
> {
> const struct drm_edid *drm_edid;
> + int ret = 0;
>
> if (status == connector_status_disconnected) {
> - // TODO: also handle scramber, HDMI sink disconnected.
> + ret = drm_scdc_sync_status(connector, false, ctx);
> drm_connector_hdmi_audio_plugged_notify(connector, false);
> drm_edid_connector_update(connector, NULL);
> drm_connector_cec_phys_addr_invalidate(connector);
> - return;
> + return ret;
> }
>
> if (connector->hdmi.funcs->read_edid)
> @@ -1174,10 +1177,12 @@ drm_atomic_helper_connector_hdmi_update(struct drm_connector *connector,
> drm_edid_free(drm_edid);
>
> if (status == connector_status_connected) {
> - // TODO: also handle scramber, HDMI sink is now connected.
> + ret = drm_scdc_sync_status(connector, true, ctx);
> drm_connector_hdmi_audio_plugged_notify(connector, true);
> drm_connector_cec_phys_addr_set(connector);
> }
> +
> + return ret;
> }
>
> /**
> @@ -1191,10 +1196,31 @@ drm_atomic_helper_connector_hdmi_update(struct drm_connector *connector,
> void drm_atomic_helper_connector_hdmi_hotplug(struct drm_connector *connector,
> enum drm_connector_status status)
> {
> - drm_atomic_helper_connector_hdmi_update(connector, status);
> + drm_atomic_helper_connector_hdmi_update(connector, status, NULL);
> }
> EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_hotplug);
>
> +/**
> + * drm_atomic_helper_connector_hdmi_hotplug_ctx - Handle the hotplug event for the HDMI connector
> + * @connector: A pointer to the HDMI connector
> + * @status: Connection status
> + * @ctx: Lock acquisition context to be used for resetting CRTC
> + *
> + * This function should be called as a part of the .detect() / .detect_ctx()
> + * callbacks for all status changes.
> + *
> + * Returns:
> + * Zero on success, error code on failure.
> + * If @ctx is set, it might also return -EDEADLK.
> + */
> +int drm_atomic_helper_connector_hdmi_hotplug_ctx(struct drm_connector *connector,
> + enum drm_connector_status status,
> + struct drm_modeset_acquire_ctx *ctx)
> +{
> + return drm_atomic_helper_connector_hdmi_update(connector, status, ctx);
> +}
> +EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_hotplug_ctx);
> +
> /**
> * drm_atomic_helper_connector_hdmi_force - HDMI Connector implementation of the force callback
> * @connector: A pointer to the HDMI connector
> @@ -1206,6 +1232,6 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_hotplug);
> */
> void drm_atomic_helper_connector_hdmi_force(struct drm_connector *connector)
> {
> - drm_atomic_helper_connector_hdmi_update(connector, connector->status);
> + drm_atomic_helper_connector_hdmi_update(connector, connector->status, NULL);
> }
> EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_force);
> diff --git a/include/drm/display/drm_hdmi_state_helper.h b/include/drm/display/drm_hdmi_state_helper.h
> index 13375bd0f4ae..75fedd4a3ba8 100644
> --- a/include/drm/display/drm_hdmi_state_helper.h
> +++ b/include/drm/display/drm_hdmi_state_helper.h
> @@ -7,6 +7,7 @@ struct drm_atomic_commit;
> struct drm_connector;
> struct drm_connector_state;
> struct drm_display_mode;
> +struct drm_modeset_acquire_ctx;
> struct hdmi_audio_infoframe;
>
> enum drm_connector_status;
> @@ -24,6 +25,9 @@ int drm_atomic_helper_connector_hdmi_update_infoframes(struct drm_connector *con
> struct drm_atomic_commit *state);
> void drm_atomic_helper_connector_hdmi_hotplug(struct drm_connector *connector,
> enum drm_connector_status status);
> +int drm_atomic_helper_connector_hdmi_hotplug_ctx(struct drm_connector *connector,
> + enum drm_connector_status status,
> + struct drm_modeset_acquire_ctx *ctx);
There's not a lot of users, so I'd prefer if we were just changing the
prototype of drm_atomic_helper_connector_hdmi_hotplug()
Maxime
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 273 bytes --]
^ permalink raw reply [flat|nested] 72+ messages in thread* Re: [PATCH v7 05/30] drm/display: hdmi_state_helper: Add ctx-aware hotplug helper for SCDC sync
@ 2026-06-11 15:25 ` Maxime Ripard
0 siblings, 0 replies; 72+ messages in thread
From: Maxime Ripard @ 2026-06-11 15:25 UTC (permalink / raw)
To: Cristian Ciocaltea
Cc: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Sandy Huang,
Heiko Stübner, Andy Yan, Daniel Stone, Dave Stevenson,
Maíra Canal, Raspberry Pi Kernel Maintenance, kernel,
dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
[-- Attachment #1.1: Type: text/plain, Size: 5580 bytes --]
On Tue, Jun 02, 2026 at 01:44:05AM +0300, Cristian Ciocaltea wrote:
> Introduce drm_atomic_helper_connector_hdmi_hotplug_ctx(), a variant of
> drm_atomic_helper_connector_hdmi_hotplug() that accepts a
> drm_modeset_acquire_ctx.
>
> This enables SCDC status synchronization on hotplug events, which
> requires lock acquisition context for performing the CRTC reset
> triggered by drm_scdc_sync_status().
>
> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
> ---
> drivers/gpu/drm/display/drm_hdmi_state_helper.c | 40 ++++++++++++++++++++-----
> include/drm/display/drm_hdmi_state_helper.h | 4 +++
> 2 files changed, 37 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
> index a331ebdd65af..a96d81cbf94f 100644
> --- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
> +++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
> @@ -12,6 +12,7 @@
> #include <drm/display/drm_hdmi_cec_helper.h>
> #include <drm/display/drm_hdmi_helper.h>
> #include <drm/display/drm_hdmi_state_helper.h>
> +#include <drm/display/drm_scdc_helper.h>
>
> /**
> * DOC: hdmi helpers
> @@ -1150,18 +1151,20 @@ drm_atomic_helper_connector_hdmi_clear_audio_infoframe(struct drm_connector *con
> }
> EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_clear_audio_infoframe);
>
> -static void
> +static int
> drm_atomic_helper_connector_hdmi_update(struct drm_connector *connector,
> - enum drm_connector_status status)
> + enum drm_connector_status status,
> + struct drm_modeset_acquire_ctx *ctx)
> {
> const struct drm_edid *drm_edid;
> + int ret = 0;
>
> if (status == connector_status_disconnected) {
> - // TODO: also handle scramber, HDMI sink disconnected.
> + ret = drm_scdc_sync_status(connector, false, ctx);
> drm_connector_hdmi_audio_plugged_notify(connector, false);
> drm_edid_connector_update(connector, NULL);
> drm_connector_cec_phys_addr_invalidate(connector);
> - return;
> + return ret;
> }
>
> if (connector->hdmi.funcs->read_edid)
> @@ -1174,10 +1177,12 @@ drm_atomic_helper_connector_hdmi_update(struct drm_connector *connector,
> drm_edid_free(drm_edid);
>
> if (status == connector_status_connected) {
> - // TODO: also handle scramber, HDMI sink is now connected.
> + ret = drm_scdc_sync_status(connector, true, ctx);
> drm_connector_hdmi_audio_plugged_notify(connector, true);
> drm_connector_cec_phys_addr_set(connector);
> }
> +
> + return ret;
> }
>
> /**
> @@ -1191,10 +1196,31 @@ drm_atomic_helper_connector_hdmi_update(struct drm_connector *connector,
> void drm_atomic_helper_connector_hdmi_hotplug(struct drm_connector *connector,
> enum drm_connector_status status)
> {
> - drm_atomic_helper_connector_hdmi_update(connector, status);
> + drm_atomic_helper_connector_hdmi_update(connector, status, NULL);
> }
> EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_hotplug);
>
> +/**
> + * drm_atomic_helper_connector_hdmi_hotplug_ctx - Handle the hotplug event for the HDMI connector
> + * @connector: A pointer to the HDMI connector
> + * @status: Connection status
> + * @ctx: Lock acquisition context to be used for resetting CRTC
> + *
> + * This function should be called as a part of the .detect() / .detect_ctx()
> + * callbacks for all status changes.
> + *
> + * Returns:
> + * Zero on success, error code on failure.
> + * If @ctx is set, it might also return -EDEADLK.
> + */
> +int drm_atomic_helper_connector_hdmi_hotplug_ctx(struct drm_connector *connector,
> + enum drm_connector_status status,
> + struct drm_modeset_acquire_ctx *ctx)
> +{
> + return drm_atomic_helper_connector_hdmi_update(connector, status, ctx);
> +}
> +EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_hotplug_ctx);
> +
> /**
> * drm_atomic_helper_connector_hdmi_force - HDMI Connector implementation of the force callback
> * @connector: A pointer to the HDMI connector
> @@ -1206,6 +1232,6 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_hotplug);
> */
> void drm_atomic_helper_connector_hdmi_force(struct drm_connector *connector)
> {
> - drm_atomic_helper_connector_hdmi_update(connector, connector->status);
> + drm_atomic_helper_connector_hdmi_update(connector, connector->status, NULL);
> }
> EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_force);
> diff --git a/include/drm/display/drm_hdmi_state_helper.h b/include/drm/display/drm_hdmi_state_helper.h
> index 13375bd0f4ae..75fedd4a3ba8 100644
> --- a/include/drm/display/drm_hdmi_state_helper.h
> +++ b/include/drm/display/drm_hdmi_state_helper.h
> @@ -7,6 +7,7 @@ struct drm_atomic_commit;
> struct drm_connector;
> struct drm_connector_state;
> struct drm_display_mode;
> +struct drm_modeset_acquire_ctx;
> struct hdmi_audio_infoframe;
>
> enum drm_connector_status;
> @@ -24,6 +25,9 @@ int drm_atomic_helper_connector_hdmi_update_infoframes(struct drm_connector *con
> struct drm_atomic_commit *state);
> void drm_atomic_helper_connector_hdmi_hotplug(struct drm_connector *connector,
> enum drm_connector_status status);
> +int drm_atomic_helper_connector_hdmi_hotplug_ctx(struct drm_connector *connector,
> + enum drm_connector_status status,
> + struct drm_modeset_acquire_ctx *ctx);
There's not a lot of users, so I'd prefer if we were just changing the
prototype of drm_atomic_helper_connector_hdmi_hotplug()
Maxime
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 273 bytes --]
[-- Attachment #2: Type: text/plain, Size: 170 bytes --]
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply [flat|nested] 72+ messages in thread
* [PATCH v7 06/30] drm/display: hdmi_state_helper: Plumb HDMI 2.0 source scrambling capability
2026-06-01 22:44 ` Cristian Ciocaltea
@ 2026-06-01 22:44 ` Cristian Ciocaltea
-1 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
Toggle drm_connector_hdmi_state.scrambler_needed flag when the TMDS
character rate exceeds 340 MHz and both the source and the sink advertise
SCDC scrambling capability. Drivers no longer need to open-code this
check.
According to HDMI 2.0 spec, scrambling is only mandatory above 340 MHz;
the optional sub-340 MHz scrambling path is intentionally not requested.
Once all drivers are converted to advertise the scrambler support, the
unsupported HDMI 2.0 modes could be simply rejected.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_hdmi_state_helper.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
index a96d81cbf94f..7cb880dcedfe 100644
--- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
@@ -588,6 +588,21 @@ hdmi_compute_clock(const struct drm_connector *connector,
if (status != MODE_OK)
return -EINVAL;
+ if (clock > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ) {
+ const struct drm_display_info *info = &connector->display_info;
+
+ /*
+ * TODO: Reject unsupported HDMI 2.0 modes once all drivers
+ * advertise their scrambler capability.
+ */
+ conn_state->hdmi.scrambler_needed = connector->hdmi.scrambler_supported &&
+ info->is_hdmi &&
+ info->hdmi.scdc.supported &&
+ info->hdmi.scdc.scrambling.supported;
+ } else {
+ conn_state->hdmi.scrambler_needed = false;
+ }
+
conn_state->hdmi.tmds_char_rate = clock;
return 0;
--
2.54.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH v7 06/30] drm/display: hdmi_state_helper: Plumb HDMI 2.0 source scrambling capability
@ 2026-06-01 22:44 ` Cristian Ciocaltea
0 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
Toggle drm_connector_hdmi_state.scrambler_needed flag when the TMDS
character rate exceeds 340 MHz and both the source and the sink advertise
SCDC scrambling capability. Drivers no longer need to open-code this
check.
According to HDMI 2.0 spec, scrambling is only mandatory above 340 MHz;
the optional sub-340 MHz scrambling path is intentionally not requested.
Once all drivers are converted to advertise the scrambler support, the
unsupported HDMI 2.0 modes could be simply rejected.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_hdmi_state_helper.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
index a96d81cbf94f..7cb880dcedfe 100644
--- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
@@ -588,6 +588,21 @@ hdmi_compute_clock(const struct drm_connector *connector,
if (status != MODE_OK)
return -EINVAL;
+ if (clock > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ) {
+ const struct drm_display_info *info = &connector->display_info;
+
+ /*
+ * TODO: Reject unsupported HDMI 2.0 modes once all drivers
+ * advertise their scrambler capability.
+ */
+ conn_state->hdmi.scrambler_needed = connector->hdmi.scrambler_supported &&
+ info->is_hdmi &&
+ info->hdmi.scdc.supported &&
+ info->hdmi.scdc.scrambling.supported;
+ } else {
+ conn_state->hdmi.scrambler_needed = false;
+ }
+
conn_state->hdmi.tmds_char_rate = clock;
return 0;
--
2.54.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH v7 07/30] drm/bridge: Remove redundant error check in drm_bridge_helper_reset_crtc()
2026-06-01 22:44 ` Cristian Ciocaltea
@ 2026-06-01 22:44 ` Cristian Ciocaltea
-1 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip,
Dmitry Baryshkov
Remove the no-op error check after drm_atomic_helper_reset_crtc() since
the goto target is the immediately following label and the return value
is already propagated correctly without it.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/drm_bridge_helper.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/drivers/gpu/drm/drm_bridge_helper.c b/drivers/gpu/drm/drm_bridge_helper.c
index 420f29cf3e54..0a3c8fee66b3 100644
--- a/drivers/gpu/drm/drm_bridge_helper.c
+++ b/drivers/gpu/drm/drm_bridge_helper.c
@@ -50,8 +50,6 @@ int drm_bridge_helper_reset_crtc(struct drm_bridge *bridge,
crtc = connector->state->crtc;
ret = drm_atomic_helper_reset_crtc(crtc, ctx);
- if (ret)
- goto out;
out:
drm_modeset_unlock(&dev->mode_config.connection_mutex);
--
2.54.0
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH v7 07/30] drm/bridge: Remove redundant error check in drm_bridge_helper_reset_crtc()
@ 2026-06-01 22:44 ` Cristian Ciocaltea
0 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip,
Dmitry Baryshkov
Remove the no-op error check after drm_atomic_helper_reset_crtc() since
the goto target is the immediately following label and the return value
is already propagated correctly without it.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/drm_bridge_helper.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/drivers/gpu/drm/drm_bridge_helper.c b/drivers/gpu/drm/drm_bridge_helper.c
index 420f29cf3e54..0a3c8fee66b3 100644
--- a/drivers/gpu/drm/drm_bridge_helper.c
+++ b/drivers/gpu/drm/drm_bridge_helper.c
@@ -50,8 +50,6 @@ int drm_bridge_helper_reset_crtc(struct drm_bridge *bridge,
crtc = connector->state->crtc;
ret = drm_atomic_helper_reset_crtc(crtc, ctx);
- if (ret)
- goto out;
out:
drm_modeset_unlock(&dev->mode_config.connection_mutex);
--
2.54.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH v7 08/30] drm/bridge: Add HDMI 2.0 scrambler bridge operation and callbacks
2026-06-01 22:44 ` Cristian Ciocaltea
@ 2026-06-01 22:44 ` Cristian Ciocaltea
-1 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
Add DRM_BRIDGE_OP_HDMI_SCRAMBLER bridge operation flag and the
corresponding .hdmi_scrambler_{enable|disable}() bridge funcs callbacks.
Bridge drivers are expected to set DRM_BRIDGE_OP_HDMI_SCRAMBLER to
advertise that they implement source-side scrambling control, which the
bridge connector layer uses to wire up the connector's scrambler
callbacks.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
include/drm/drm_bridge.h | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index 4ba3a5deef9a..f36e1e71aa86 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -667,6 +667,26 @@ struct drm_bridge_funcs {
const struct drm_display_mode *mode,
unsigned long long tmds_rate);
+ /**
+ * @hdmi_scrambler_enable:
+ *
+ * Enable source-side HDMI 2.0 scrambling and high TMDS clock ratio.
+ *
+ * This callback is optional but it must be implemented by bridges that
+ * set the DRM_BRIDGE_OP_HDMI_SCRAMBLER flag in their &drm_bridge->ops.
+ */
+ int (*hdmi_scrambler_enable)(struct drm_bridge *bridge);
+
+ /**
+ * @hdmi_scrambler_disable:
+ *
+ * Disable source-side HDMI 2.0 scrambling and high TMDS clock ratio.
+ *
+ * This callback is optional but it must be implemented by bridges that
+ * set the DRM_BRIDGE_OP_HDMI_SCRAMBLER flag in their &drm_bridge->ops.
+ */
+ int (*hdmi_scrambler_disable)(struct drm_bridge *bridge);
+
/**
* @hdmi_clear_avi_infoframe:
*
@@ -1092,6 +1112,12 @@ enum drm_bridge_ops {
* &drm_bridge_funcs->hdmi_clear_spd_infoframe callbacks.
*/
DRM_BRIDGE_OP_HDMI_SPD_INFOFRAME = BIT(10),
+ /**
+ * @DRM_BRIDGE_OP_HDMI_SCRAMBLER: The bridge supports
+ * &drm_bridge_funcs->hdmi_scrambler_enable and
+ * &drm_bridge_funcs->hdmi_scrambler_disable callbacks.
+ */
+ DRM_BRIDGE_OP_HDMI_SCRAMBLER = BIT(11),
};
/**
--
2.54.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH v7 08/30] drm/bridge: Add HDMI 2.0 scrambler bridge operation and callbacks
@ 2026-06-01 22:44 ` Cristian Ciocaltea
0 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
Add DRM_BRIDGE_OP_HDMI_SCRAMBLER bridge operation flag and the
corresponding .hdmi_scrambler_{enable|disable}() bridge funcs callbacks.
Bridge drivers are expected to set DRM_BRIDGE_OP_HDMI_SCRAMBLER to
advertise that they implement source-side scrambling control, which the
bridge connector layer uses to wire up the connector's scrambler
callbacks.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
include/drm/drm_bridge.h | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index 4ba3a5deef9a..f36e1e71aa86 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -667,6 +667,26 @@ struct drm_bridge_funcs {
const struct drm_display_mode *mode,
unsigned long long tmds_rate);
+ /**
+ * @hdmi_scrambler_enable:
+ *
+ * Enable source-side HDMI 2.0 scrambling and high TMDS clock ratio.
+ *
+ * This callback is optional but it must be implemented by bridges that
+ * set the DRM_BRIDGE_OP_HDMI_SCRAMBLER flag in their &drm_bridge->ops.
+ */
+ int (*hdmi_scrambler_enable)(struct drm_bridge *bridge);
+
+ /**
+ * @hdmi_scrambler_disable:
+ *
+ * Disable source-side HDMI 2.0 scrambling and high TMDS clock ratio.
+ *
+ * This callback is optional but it must be implemented by bridges that
+ * set the DRM_BRIDGE_OP_HDMI_SCRAMBLER flag in their &drm_bridge->ops.
+ */
+ int (*hdmi_scrambler_disable)(struct drm_bridge *bridge);
+
/**
* @hdmi_clear_avi_infoframe:
*
@@ -1092,6 +1112,12 @@ enum drm_bridge_ops {
* &drm_bridge_funcs->hdmi_clear_spd_infoframe callbacks.
*/
DRM_BRIDGE_OP_HDMI_SPD_INFOFRAME = BIT(10),
+ /**
+ * @DRM_BRIDGE_OP_HDMI_SCRAMBLER: The bridge supports
+ * &drm_bridge_funcs->hdmi_scrambler_enable and
+ * &drm_bridge_funcs->hdmi_scrambler_disable callbacks.
+ */
+ DRM_BRIDGE_OP_HDMI_SCRAMBLER = BIT(11),
};
/**
--
2.54.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH v7 09/30] drm/display: bridge_connector: Use cached connector status in .get_modes()
2026-06-01 22:44 ` Cristian Ciocaltea
@ 2026-06-01 22:44 ` Cristian Ciocaltea
-1 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip,
Dmitry Baryshkov
Replace the active drm_bridge_connector_detect() call in get_modes()
with a read of the already-cached connector->status.
The .get_modes() callback is only invoked from
drm_helper_probe_single_connector_modes(), which has already retrieved
the connector status. Calling detect again is redundant and triggers a
duplicate hotplug event. This is also a prerequisite for switching to
the .detect_ctx() hook, which requires a drm_modeset_acquire_ctx not
available in the .get_modes() path.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_bridge_connector.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
index cafa498c3848..61c2a46edaf3 100644
--- a/drivers/gpu/drm/display/drm_bridge_connector.c
+++ b/drivers/gpu/drm/display/drm_bridge_connector.c
@@ -301,12 +301,10 @@ static const struct drm_connector_funcs drm_bridge_connector_funcs = {
static int drm_bridge_connector_get_modes_edid(struct drm_connector *connector,
struct drm_bridge *bridge)
{
- enum drm_connector_status status;
const struct drm_edid *drm_edid;
int n;
- status = drm_bridge_connector_detect(connector, false);
- if (status != connector_status_connected)
+ if (connector->status != connector_status_connected)
goto no_edid;
drm_edid = drm_bridge_edid_read(bridge, connector);
--
2.54.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH v7 09/30] drm/display: bridge_connector: Use cached connector status in .get_modes()
@ 2026-06-01 22:44 ` Cristian Ciocaltea
0 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip,
Dmitry Baryshkov
Replace the active drm_bridge_connector_detect() call in get_modes()
with a read of the already-cached connector->status.
The .get_modes() callback is only invoked from
drm_helper_probe_single_connector_modes(), which has already retrieved
the connector status. Calling detect again is redundant and triggers a
duplicate hotplug event. This is also a prerequisite for switching to
the .detect_ctx() hook, which requires a drm_modeset_acquire_ctx not
available in the .get_modes() path.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_bridge_connector.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
index cafa498c3848..61c2a46edaf3 100644
--- a/drivers/gpu/drm/display/drm_bridge_connector.c
+++ b/drivers/gpu/drm/display/drm_bridge_connector.c
@@ -301,12 +301,10 @@ static const struct drm_connector_funcs drm_bridge_connector_funcs = {
static int drm_bridge_connector_get_modes_edid(struct drm_connector *connector,
struct drm_bridge *bridge)
{
- enum drm_connector_status status;
const struct drm_edid *drm_edid;
int n;
- status = drm_bridge_connector_detect(connector, false);
- if (status != connector_status_connected)
+ if (connector->status != connector_status_connected)
goto no_edid;
drm_edid = drm_bridge_edid_read(bridge, connector);
--
2.54.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH v7 10/30] drm/display: bridge_connector: Switch to .detect_ctx() connector helper
2026-06-01 22:44 ` Cristian Ciocaltea
@ 2026-06-01 22:44 ` Cristian Ciocaltea
-1 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip,
Diederik de Haas, Maud Spierings, Dmitry Baryshkov
Replace the .detect() connector_funcs callback with the atomic-aware
.detect_ctx() connector_helper_funcs hook.
This propagates the modeset acquire context through
drm_atomic_helper_connector_hdmi_hotplug_ctx() to the HDMI connector
framework, enabling SCDC state recovery via CRTC reset when the sink
reconnects during an active display pipeline.
Tested-by: Diederik de Haas <diederik@cknow-tech.com>
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_bridge_connector.c | 74 ++++++++++++++------------
1 file changed, 40 insertions(+), 34 deletions(-)
diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
index 61c2a46edaf3..9d21b1b57b0d 100644
--- a/drivers/gpu/drm/display/drm_bridge_connector.c
+++ b/drivers/gpu/drm/display/drm_bridge_connector.c
@@ -208,39 +208,6 @@ static void drm_bridge_connector_disable_hpd(struct drm_connector *connector)
* Bridge Connector Functions
*/
-static enum drm_connector_status
-drm_bridge_connector_detect(struct drm_connector *connector, bool force)
-{
- struct drm_bridge_connector *bridge_connector =
- to_drm_bridge_connector(connector);
- struct drm_bridge *detect = bridge_connector->bridge_detect;
- struct drm_bridge *hdmi = bridge_connector->bridge_hdmi;
- enum drm_connector_status status;
-
- if (detect) {
- status = detect->funcs->detect(detect, connector);
-
- if (hdmi)
- drm_atomic_helper_connector_hdmi_hotplug(connector, status);
-
- drm_bridge_connector_hpd_notify(connector, status);
- } else {
- switch (connector->connector_type) {
- case DRM_MODE_CONNECTOR_DPI:
- case DRM_MODE_CONNECTOR_LVDS:
- case DRM_MODE_CONNECTOR_DSI:
- case DRM_MODE_CONNECTOR_eDP:
- status = connector_status_connected;
- break;
- default:
- status = connector_status_unknown;
- break;
- }
- }
-
- return status;
-}
-
static void drm_bridge_connector_force(struct drm_connector *connector)
{
struct drm_bridge_connector *bridge_connector =
@@ -284,7 +251,6 @@ drm_bridge_connector_create_state(struct drm_connector *connector)
}
static const struct drm_connector_funcs drm_bridge_connector_funcs = {
- .detect = drm_bridge_connector_detect,
.force = drm_bridge_connector_force,
.fill_modes = drm_helper_probe_single_connector_modes,
.atomic_create_state = drm_bridge_connector_create_state,
@@ -298,6 +264,45 @@ static const struct drm_connector_funcs drm_bridge_connector_funcs = {
* Bridge Connector Helper Functions
*/
+static int drm_bridge_connector_detect_ctx(struct drm_connector *connector,
+ struct drm_modeset_acquire_ctx *ctx,
+ bool force)
+{
+ struct drm_bridge_connector *bridge_connector =
+ to_drm_bridge_connector(connector);
+ struct drm_bridge *detect = bridge_connector->bridge_detect;
+ struct drm_bridge *hdmi = bridge_connector->bridge_hdmi;
+ enum drm_connector_status status;
+ int ret;
+
+ if (detect) {
+ status = detect->funcs->detect(detect, connector);
+
+ if (hdmi) {
+ ret = drm_atomic_helper_connector_hdmi_hotplug_ctx(connector,
+ status, ctx);
+ if (ret == -EDEADLK)
+ return ret;
+ }
+
+ drm_bridge_connector_hpd_notify(connector, status);
+ } else {
+ switch (connector->connector_type) {
+ case DRM_MODE_CONNECTOR_DPI:
+ case DRM_MODE_CONNECTOR_LVDS:
+ case DRM_MODE_CONNECTOR_DSI:
+ case DRM_MODE_CONNECTOR_eDP:
+ status = connector_status_connected;
+ break;
+ default:
+ status = connector_status_unknown;
+ break;
+ }
+ }
+
+ return status;
+}
+
static int drm_bridge_connector_get_modes_edid(struct drm_connector *connector,
struct drm_bridge *bridge)
{
@@ -389,6 +394,7 @@ static int drm_bridge_connector_atomic_check(struct drm_connector *connector,
static const struct drm_connector_helper_funcs drm_bridge_connector_helper_funcs = {
.get_modes = drm_bridge_connector_get_modes,
+ .detect_ctx = drm_bridge_connector_detect_ctx,
.mode_valid = drm_bridge_connector_mode_valid,
.enable_hpd = drm_bridge_connector_enable_hpd,
.disable_hpd = drm_bridge_connector_disable_hpd,
--
2.54.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH v7 10/30] drm/display: bridge_connector: Switch to .detect_ctx() connector helper
@ 2026-06-01 22:44 ` Cristian Ciocaltea
0 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip,
Diederik de Haas, Maud Spierings, Dmitry Baryshkov
Replace the .detect() connector_funcs callback with the atomic-aware
.detect_ctx() connector_helper_funcs hook.
This propagates the modeset acquire context through
drm_atomic_helper_connector_hdmi_hotplug_ctx() to the HDMI connector
framework, enabling SCDC state recovery via CRTC reset when the sink
reconnects during an active display pipeline.
Tested-by: Diederik de Haas <diederik@cknow-tech.com>
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_bridge_connector.c | 74 ++++++++++++++------------
1 file changed, 40 insertions(+), 34 deletions(-)
diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
index 61c2a46edaf3..9d21b1b57b0d 100644
--- a/drivers/gpu/drm/display/drm_bridge_connector.c
+++ b/drivers/gpu/drm/display/drm_bridge_connector.c
@@ -208,39 +208,6 @@ static void drm_bridge_connector_disable_hpd(struct drm_connector *connector)
* Bridge Connector Functions
*/
-static enum drm_connector_status
-drm_bridge_connector_detect(struct drm_connector *connector, bool force)
-{
- struct drm_bridge_connector *bridge_connector =
- to_drm_bridge_connector(connector);
- struct drm_bridge *detect = bridge_connector->bridge_detect;
- struct drm_bridge *hdmi = bridge_connector->bridge_hdmi;
- enum drm_connector_status status;
-
- if (detect) {
- status = detect->funcs->detect(detect, connector);
-
- if (hdmi)
- drm_atomic_helper_connector_hdmi_hotplug(connector, status);
-
- drm_bridge_connector_hpd_notify(connector, status);
- } else {
- switch (connector->connector_type) {
- case DRM_MODE_CONNECTOR_DPI:
- case DRM_MODE_CONNECTOR_LVDS:
- case DRM_MODE_CONNECTOR_DSI:
- case DRM_MODE_CONNECTOR_eDP:
- status = connector_status_connected;
- break;
- default:
- status = connector_status_unknown;
- break;
- }
- }
-
- return status;
-}
-
static void drm_bridge_connector_force(struct drm_connector *connector)
{
struct drm_bridge_connector *bridge_connector =
@@ -284,7 +251,6 @@ drm_bridge_connector_create_state(struct drm_connector *connector)
}
static const struct drm_connector_funcs drm_bridge_connector_funcs = {
- .detect = drm_bridge_connector_detect,
.force = drm_bridge_connector_force,
.fill_modes = drm_helper_probe_single_connector_modes,
.atomic_create_state = drm_bridge_connector_create_state,
@@ -298,6 +264,45 @@ static const struct drm_connector_funcs drm_bridge_connector_funcs = {
* Bridge Connector Helper Functions
*/
+static int drm_bridge_connector_detect_ctx(struct drm_connector *connector,
+ struct drm_modeset_acquire_ctx *ctx,
+ bool force)
+{
+ struct drm_bridge_connector *bridge_connector =
+ to_drm_bridge_connector(connector);
+ struct drm_bridge *detect = bridge_connector->bridge_detect;
+ struct drm_bridge *hdmi = bridge_connector->bridge_hdmi;
+ enum drm_connector_status status;
+ int ret;
+
+ if (detect) {
+ status = detect->funcs->detect(detect, connector);
+
+ if (hdmi) {
+ ret = drm_atomic_helper_connector_hdmi_hotplug_ctx(connector,
+ status, ctx);
+ if (ret == -EDEADLK)
+ return ret;
+ }
+
+ drm_bridge_connector_hpd_notify(connector, status);
+ } else {
+ switch (connector->connector_type) {
+ case DRM_MODE_CONNECTOR_DPI:
+ case DRM_MODE_CONNECTOR_LVDS:
+ case DRM_MODE_CONNECTOR_DSI:
+ case DRM_MODE_CONNECTOR_eDP:
+ status = connector_status_connected;
+ break;
+ default:
+ status = connector_status_unknown;
+ break;
+ }
+ }
+
+ return status;
+}
+
static int drm_bridge_connector_get_modes_edid(struct drm_connector *connector,
struct drm_bridge *bridge)
{
@@ -389,6 +394,7 @@ static int drm_bridge_connector_atomic_check(struct drm_connector *connector,
static const struct drm_connector_helper_funcs drm_bridge_connector_helper_funcs = {
.get_modes = drm_bridge_connector_get_modes,
+ .detect_ctx = drm_bridge_connector_detect_ctx,
.mode_valid = drm_bridge_connector_mode_valid,
.enable_hpd = drm_bridge_connector_enable_hpd,
.disable_hpd = drm_bridge_connector_disable_hpd,
--
2.54.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH v7 11/30] drm/display: bridge_connector: Wire up HDMI 2.0 scrambler callbacks
2026-06-01 22:44 ` Cristian Ciocaltea
@ 2026-06-01 22:44 ` Cristian Ciocaltea
-1 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
Connect the bridge connector's .scrambler_{enable|disable} callbacks to
the underlying bridge's .hdmi_scrambler_{enable|disable} funcs when
DRM_BRIDGE_OP_HDMI_SCRAMBLER is advertised.
This completes the bridge connector plumbing so that the SCDC
scrambling helpers can control source-side scrambling through the
bridge chain.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_bridge_connector.c | 41 +++++++++++++++++++++++++-
1 file changed, 40 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
index 9d21b1b57b0d..d048ab49eade 100644
--- a/drivers/gpu/drm/display/drm_bridge_connector.c
+++ b/drivers/gpu/drm/display/drm_bridge_connector.c
@@ -555,6 +555,32 @@ static int drm_bridge_connector_write_spd_infoframe(struct drm_connector *connec
return bridge->funcs->hdmi_write_spd_infoframe(bridge, buffer, len);
}
+static int drm_bridge_connector_scrambler_enable(struct drm_connector *connector)
+{
+ struct drm_bridge_connector *bridge_connector =
+ to_drm_bridge_connector(connector);
+ struct drm_bridge *bridge;
+
+ bridge = bridge_connector->bridge_hdmi;
+ if (!bridge)
+ return -EINVAL;
+
+ return bridge->funcs->hdmi_scrambler_enable(bridge);
+}
+
+static int drm_bridge_connector_scrambler_disable(struct drm_connector *connector)
+{
+ struct drm_bridge_connector *bridge_connector =
+ to_drm_bridge_connector(connector);
+ struct drm_bridge *bridge;
+
+ bridge = bridge_connector->bridge_hdmi;
+ if (!bridge)
+ return -EINVAL;
+
+ return bridge->funcs->hdmi_scrambler_disable(bridge);
+}
+
static const struct drm_edid *
drm_bridge_connector_read_edid(struct drm_connector *connector)
{
@@ -580,7 +606,7 @@ static const struct drm_connector_hdmi_funcs drm_bridge_connector_hdmi_funcs = {
.clear_infoframe = drm_bridge_connector_clear_hdmi_infoframe,
.write_infoframe = drm_bridge_connector_write_hdmi_infoframe,
},
- /* audio, hdr_drm and spd are set dynamically during init */
+ /* scrambler, audio, hdr_drm and spd are set dynamically during init */
};
static const struct drm_connector_infoframe_funcs drm_bridge_connector_hdmi_audio_infoframe = {
@@ -886,6 +912,11 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
!bridge->funcs->hdmi_clear_spd_infoframe))
return ERR_PTR(-EINVAL);
+ if (bridge->ops & DRM_BRIDGE_OP_HDMI_SCRAMBLER &&
+ (!bridge->funcs->hdmi_scrambler_enable ||
+ !bridge->funcs->hdmi_scrambler_disable))
+ return ERR_PTR(-EINVAL);
+
bridge_connector->bridge_hdmi = drm_bridge_get(bridge);
if (bridge->supported_formats)
@@ -990,6 +1021,14 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
bridge_connector->hdmi_funcs.spd =
drm_bridge_connector_hdmi_spd_infoframe;
+ if (bridge_connector->bridge_hdmi->ops & DRM_BRIDGE_OP_HDMI_SCRAMBLER) {
+ bridge_connector->hdmi_funcs.scrambler_enable =
+ drm_bridge_connector_scrambler_enable;
+ bridge_connector->hdmi_funcs.scrambler_disable =
+ drm_bridge_connector_scrambler_disable;
+ connector->hdmi.scrambler_supported = true;
+ }
+
ret = drmm_connector_hdmi_init(drm, connector,
bridge_connector->bridge_hdmi->vendor,
bridge_connector->bridge_hdmi->product,
--
2.54.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH v7 11/30] drm/display: bridge_connector: Wire up HDMI 2.0 scrambler callbacks
@ 2026-06-01 22:44 ` Cristian Ciocaltea
0 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
Connect the bridge connector's .scrambler_{enable|disable} callbacks to
the underlying bridge's .hdmi_scrambler_{enable|disable} funcs when
DRM_BRIDGE_OP_HDMI_SCRAMBLER is advertised.
This completes the bridge connector plumbing so that the SCDC
scrambling helpers can control source-side scrambling through the
bridge chain.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_bridge_connector.c | 41 +++++++++++++++++++++++++-
1 file changed, 40 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
index 9d21b1b57b0d..d048ab49eade 100644
--- a/drivers/gpu/drm/display/drm_bridge_connector.c
+++ b/drivers/gpu/drm/display/drm_bridge_connector.c
@@ -555,6 +555,32 @@ static int drm_bridge_connector_write_spd_infoframe(struct drm_connector *connec
return bridge->funcs->hdmi_write_spd_infoframe(bridge, buffer, len);
}
+static int drm_bridge_connector_scrambler_enable(struct drm_connector *connector)
+{
+ struct drm_bridge_connector *bridge_connector =
+ to_drm_bridge_connector(connector);
+ struct drm_bridge *bridge;
+
+ bridge = bridge_connector->bridge_hdmi;
+ if (!bridge)
+ return -EINVAL;
+
+ return bridge->funcs->hdmi_scrambler_enable(bridge);
+}
+
+static int drm_bridge_connector_scrambler_disable(struct drm_connector *connector)
+{
+ struct drm_bridge_connector *bridge_connector =
+ to_drm_bridge_connector(connector);
+ struct drm_bridge *bridge;
+
+ bridge = bridge_connector->bridge_hdmi;
+ if (!bridge)
+ return -EINVAL;
+
+ return bridge->funcs->hdmi_scrambler_disable(bridge);
+}
+
static const struct drm_edid *
drm_bridge_connector_read_edid(struct drm_connector *connector)
{
@@ -580,7 +606,7 @@ static const struct drm_connector_hdmi_funcs drm_bridge_connector_hdmi_funcs = {
.clear_infoframe = drm_bridge_connector_clear_hdmi_infoframe,
.write_infoframe = drm_bridge_connector_write_hdmi_infoframe,
},
- /* audio, hdr_drm and spd are set dynamically during init */
+ /* scrambler, audio, hdr_drm and spd are set dynamically during init */
};
static const struct drm_connector_infoframe_funcs drm_bridge_connector_hdmi_audio_infoframe = {
@@ -886,6 +912,11 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
!bridge->funcs->hdmi_clear_spd_infoframe))
return ERR_PTR(-EINVAL);
+ if (bridge->ops & DRM_BRIDGE_OP_HDMI_SCRAMBLER &&
+ (!bridge->funcs->hdmi_scrambler_enable ||
+ !bridge->funcs->hdmi_scrambler_disable))
+ return ERR_PTR(-EINVAL);
+
bridge_connector->bridge_hdmi = drm_bridge_get(bridge);
if (bridge->supported_formats)
@@ -990,6 +1021,14 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
bridge_connector->hdmi_funcs.spd =
drm_bridge_connector_hdmi_spd_infoframe;
+ if (bridge_connector->bridge_hdmi->ops & DRM_BRIDGE_OP_HDMI_SCRAMBLER) {
+ bridge_connector->hdmi_funcs.scrambler_enable =
+ drm_bridge_connector_scrambler_enable;
+ bridge_connector->hdmi_funcs.scrambler_disable =
+ drm_bridge_connector_scrambler_disable;
+ connector->hdmi.scrambler_supported = true;
+ }
+
ret = drmm_connector_hdmi_init(drm, connector,
bridge_connector->bridge_hdmi->vendor,
bridge_connector->bridge_hdmi->product,
--
2.54.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH v7 12/30] drm/bridge: dw-hdmi-qp: Rate limit i2c read error messages
2026-06-01 22:44 ` Cristian Ciocaltea
@ 2026-06-01 22:44 ` Cristian Ciocaltea
-1 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
During EDID reads, repeated i2c errors can flood the kernel log:
[ 25.361716] dwhdmiqp-rockchip fde80000.hdmi: i2c read error
[ 25.363376] dwhdmiqp-rockchip fde80000.hdmi: i2c read error
...
[ 25.368671] dwhdmiqp-rockchip fde80000.hdmi: i2c read error
[ 25.369440] dwhdmiqp-rockchip fde80000.hdmi: failed to get edid
Switch to dev_err_ratelimited() in dw_hdmi_qp_i2c_read() to reduce log
spam while still reporting the condition.
Reviewed-by: Heiko Stuebner <heiko@sntech.de>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
index 1c214a8e6dc2..b3318655ceab 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
@@ -561,7 +561,7 @@ static int dw_hdmi_qp_i2c_read(struct dw_hdmi_qp *hdmi,
dev_dbg_ratelimited(hdmi->dev,
"i2c read timed out\n");
else
- dev_err(hdmi->dev, "i2c read timed out\n");
+ dev_err_ratelimited(hdmi->dev, "i2c read timed out\n");
dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0);
return -EAGAIN;
}
@@ -572,7 +572,7 @@ static int dw_hdmi_qp_i2c_read(struct dw_hdmi_qp *hdmi,
dev_dbg_ratelimited(hdmi->dev,
"i2c read error\n");
else
- dev_err(hdmi->dev, "i2c read error\n");
+ dev_err_ratelimited(hdmi->dev, "i2c read error\n");
dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0);
return -EIO;
}
--
2.54.0
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH v7 12/30] drm/bridge: dw-hdmi-qp: Rate limit i2c read error messages
@ 2026-06-01 22:44 ` Cristian Ciocaltea
0 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
During EDID reads, repeated i2c errors can flood the kernel log:
[ 25.361716] dwhdmiqp-rockchip fde80000.hdmi: i2c read error
[ 25.363376] dwhdmiqp-rockchip fde80000.hdmi: i2c read error
...
[ 25.368671] dwhdmiqp-rockchip fde80000.hdmi: i2c read error
[ 25.369440] dwhdmiqp-rockchip fde80000.hdmi: failed to get edid
Switch to dev_err_ratelimited() in dw_hdmi_qp_i2c_read() to reduce log
spam while still reporting the condition.
Reviewed-by: Heiko Stuebner <heiko@sntech.de>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
index 1c214a8e6dc2..b3318655ceab 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
@@ -561,7 +561,7 @@ static int dw_hdmi_qp_i2c_read(struct dw_hdmi_qp *hdmi,
dev_dbg_ratelimited(hdmi->dev,
"i2c read timed out\n");
else
- dev_err(hdmi->dev, "i2c read timed out\n");
+ dev_err_ratelimited(hdmi->dev, "i2c read timed out\n");
dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0);
return -EAGAIN;
}
@@ -572,7 +572,7 @@ static int dw_hdmi_qp_i2c_read(struct dw_hdmi_qp *hdmi,
dev_dbg_ratelimited(hdmi->dev,
"i2c read error\n");
else
- dev_err(hdmi->dev, "i2c read error\n");
+ dev_err_ratelimited(hdmi->dev, "i2c read error\n");
dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0);
return -EIO;
}
--
2.54.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH v7 13/30] drm/bridge: dw-hdmi-qp: Provide .{enable|disable}_hpd() PHY ops
2026-06-01 22:44 ` Cristian Ciocaltea
@ 2026-06-01 22:44 ` Cristian Ciocaltea
-1 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
Implement the .hpd_enable() and .hpd_disable() bridge callbacks and
extend dw_hdmi_qp_phy_ops with corresponding hooks.
This enables the DRM core to control when HPD interrupts are armed,
which is needed to prevent premature interrupt delivery before the
connector is fully initialized, and to properly quiesce HPD during
suspend.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 18 ++++++++++++++++++
include/drm/bridge/dw_hdmi_qp.h | 2 ++
2 files changed, 20 insertions(+)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
index b3318655ceab..3f72bea20ba4 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
@@ -1189,6 +1189,22 @@ static int dw_hdmi_qp_cec_transmit(struct drm_bridge *bridge, u8 attempts,
#define dw_hdmi_qp_cec_transmit NULL
#endif /* CONFIG_DRM_DW_HDMI_QP_CEC */
+static void dw_hdmi_qp_bridge_hpd_enable(struct drm_bridge *bridge)
+{
+ struct dw_hdmi_qp *hdmi = bridge->driver_private;
+
+ if (hdmi->phy.ops->enable_hpd)
+ hdmi->phy.ops->enable_hpd(hdmi, hdmi->phy.data);
+}
+
+static void dw_hdmi_qp_bridge_hpd_disable(struct drm_bridge *bridge)
+{
+ struct dw_hdmi_qp *hdmi = bridge->driver_private;
+
+ if (hdmi->phy.ops->disable_hpd)
+ hdmi->phy.ops->disable_hpd(hdmi, hdmi->phy.data);
+}
+
static const struct drm_bridge_funcs dw_hdmi_qp_bridge_funcs = {
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
@@ -1196,6 +1212,8 @@ static const struct drm_bridge_funcs dw_hdmi_qp_bridge_funcs = {
.atomic_enable = dw_hdmi_qp_bridge_atomic_enable,
.atomic_disable = dw_hdmi_qp_bridge_atomic_disable,
.detect = dw_hdmi_qp_bridge_detect,
+ .hpd_enable = dw_hdmi_qp_bridge_hpd_enable,
+ .hpd_disable = dw_hdmi_qp_bridge_hpd_disable,
.edid_read = dw_hdmi_qp_bridge_edid_read,
.hdmi_tmds_char_rate_valid = dw_hdmi_qp_bridge_tmds_char_rate_valid,
.hdmi_clear_avi_infoframe = dw_hdmi_qp_bridge_clear_avi_infoframe,
diff --git a/include/drm/bridge/dw_hdmi_qp.h b/include/drm/bridge/dw_hdmi_qp.h
index 6ea9c561cfef..b80fceffc315 100644
--- a/include/drm/bridge/dw_hdmi_qp.h
+++ b/include/drm/bridge/dw_hdmi_qp.h
@@ -17,6 +17,8 @@ struct dw_hdmi_qp_phy_ops {
void (*disable)(struct dw_hdmi_qp *hdmi, void *data);
enum drm_connector_status (*read_hpd)(struct dw_hdmi_qp *hdmi, void *data);
void (*setup_hpd)(struct dw_hdmi_qp *hdmi, void *data);
+ void (*enable_hpd)(struct dw_hdmi_qp *hdmi, void *data);
+ void (*disable_hpd)(struct dw_hdmi_qp *hdmi, void *data);
};
struct dw_hdmi_qp_plat_data {
--
2.54.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH v7 13/30] drm/bridge: dw-hdmi-qp: Provide .{enable|disable}_hpd() PHY ops
@ 2026-06-01 22:44 ` Cristian Ciocaltea
0 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
Implement the .hpd_enable() and .hpd_disable() bridge callbacks and
extend dw_hdmi_qp_phy_ops with corresponding hooks.
This enables the DRM core to control when HPD interrupts are armed,
which is needed to prevent premature interrupt delivery before the
connector is fully initialized, and to properly quiesce HPD during
suspend.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 18 ++++++++++++++++++
include/drm/bridge/dw_hdmi_qp.h | 2 ++
2 files changed, 20 insertions(+)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
index b3318655ceab..3f72bea20ba4 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
@@ -1189,6 +1189,22 @@ static int dw_hdmi_qp_cec_transmit(struct drm_bridge *bridge, u8 attempts,
#define dw_hdmi_qp_cec_transmit NULL
#endif /* CONFIG_DRM_DW_HDMI_QP_CEC */
+static void dw_hdmi_qp_bridge_hpd_enable(struct drm_bridge *bridge)
+{
+ struct dw_hdmi_qp *hdmi = bridge->driver_private;
+
+ if (hdmi->phy.ops->enable_hpd)
+ hdmi->phy.ops->enable_hpd(hdmi, hdmi->phy.data);
+}
+
+static void dw_hdmi_qp_bridge_hpd_disable(struct drm_bridge *bridge)
+{
+ struct dw_hdmi_qp *hdmi = bridge->driver_private;
+
+ if (hdmi->phy.ops->disable_hpd)
+ hdmi->phy.ops->disable_hpd(hdmi, hdmi->phy.data);
+}
+
static const struct drm_bridge_funcs dw_hdmi_qp_bridge_funcs = {
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
@@ -1196,6 +1212,8 @@ static const struct drm_bridge_funcs dw_hdmi_qp_bridge_funcs = {
.atomic_enable = dw_hdmi_qp_bridge_atomic_enable,
.atomic_disable = dw_hdmi_qp_bridge_atomic_disable,
.detect = dw_hdmi_qp_bridge_detect,
+ .hpd_enable = dw_hdmi_qp_bridge_hpd_enable,
+ .hpd_disable = dw_hdmi_qp_bridge_hpd_disable,
.edid_read = dw_hdmi_qp_bridge_edid_read,
.hdmi_tmds_char_rate_valid = dw_hdmi_qp_bridge_tmds_char_rate_valid,
.hdmi_clear_avi_infoframe = dw_hdmi_qp_bridge_clear_avi_infoframe,
diff --git a/include/drm/bridge/dw_hdmi_qp.h b/include/drm/bridge/dw_hdmi_qp.h
index 6ea9c561cfef..b80fceffc315 100644
--- a/include/drm/bridge/dw_hdmi_qp.h
+++ b/include/drm/bridge/dw_hdmi_qp.h
@@ -17,6 +17,8 @@ struct dw_hdmi_qp_phy_ops {
void (*disable)(struct dw_hdmi_qp *hdmi, void *data);
enum drm_connector_status (*read_hpd)(struct dw_hdmi_qp *hdmi, void *data);
void (*setup_hpd)(struct dw_hdmi_qp *hdmi, void *data);
+ void (*enable_hpd)(struct dw_hdmi_qp *hdmi, void *data);
+ void (*disable_hpd)(struct dw_hdmi_qp *hdmi, void *data);
};
struct dw_hdmi_qp_plat_data {
--
2.54.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH v7 14/30] drm/bridge: dw-hdmi-qp: Add HDMI 2.0 SCDC scrambling support
2026-06-01 22:44 ` Cristian Ciocaltea
@ 2026-06-01 22:44 ` Cristian Ciocaltea
-1 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip,
Diederik de Haas, Maud Spierings
Enable HDMI 2.0 display modes (e.g. 4K@60Hz) by implementing SCDC
scrambling and high TMDS clock ratio management for TMDS character
rates exceeding the 340 MHz HDMI 1.4b limit.
Reject modes requiring TMDS rates above 600 MHz since those require
HDMI 2.1 FRL which is not yet supported. In no_hpd configurations,
further restrict to 340 MHz because SCDC requires a connected sink.
Tested-by: Diederik de Haas <diederik@cknow-tech.com>
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Acked-by: Heiko Stuebner <heiko@sntech.de>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 76 +++++++++++++++++++++-------
1 file changed, 58 insertions(+), 18 deletions(-)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
index 3f72bea20ba4..0250ddd8f91a 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
@@ -2,6 +2,7 @@
/*
* Copyright (c) 2021-2022 Rockchip Electronics Co., Ltd.
* Copyright (c) 2024 Collabora Ltd.
+ * Copyright (c) 2025 Amazon.com, Inc. or its affiliates.
*
* Author: Algea Cao <algea.cao@rock-chips.com>
* Author: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
@@ -15,12 +16,12 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
-#include <linux/workqueue.h>
#include <drm/bridge/dw_hdmi_qp.h>
#include <drm/display/drm_hdmi_helper.h>
#include <drm/display/drm_hdmi_cec_helper.h>
#include <drm/display/drm_hdmi_state_helper.h>
+#include <drm/display/drm_scdc_helper.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
@@ -162,6 +163,7 @@ struct dw_hdmi_qp {
} phy;
unsigned long ref_clk_rate;
+ struct drm_connector *curr_conn;
struct regmap *regm;
int main_irq;
@@ -752,26 +754,35 @@ static void dw_hdmi_qp_bridge_atomic_enable(struct drm_bridge *bridge,
{
struct dw_hdmi_qp *hdmi = bridge->driver_private;
struct drm_connector_state *conn_state;
- struct drm_connector *connector;
unsigned int op_mode;
+ int ret;
- connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder);
- if (WARN_ON(!connector))
+ hdmi->curr_conn = drm_atomic_get_new_connector_for_encoder(state,
+ bridge->encoder);
+ if (WARN_ON(!hdmi->curr_conn))
return;
- conn_state = drm_atomic_get_new_connector_state(state, connector);
+ conn_state = drm_atomic_get_new_connector_state(state, hdmi->curr_conn);
if (WARN_ON(!conn_state))
return;
- if (connector->display_info.is_hdmi) {
- dev_dbg(hdmi->dev, "%s mode=HDMI %s rate=%llu bpc=%u\n", __func__,
- drm_hdmi_connector_get_output_format_name(conn_state->hdmi.output_format),
- conn_state->hdmi.tmds_char_rate, conn_state->hdmi.output_bpc);
+ if (hdmi->curr_conn->display_info.is_hdmi) {
op_mode = 0;
hdmi->tmds_char_rate = conn_state->hdmi.tmds_char_rate;
+
+ if (conn_state->hdmi.scrambler_needed) {
+ ret = drm_scdc_start_scrambling(hdmi->curr_conn);
+ if (ret)
+ dev_warn(hdmi->dev, "Failed to setup SCDC: %d\n", ret);
+ }
+
+ dev_dbg(hdmi->dev, "%s mode=HDMI %s rate=%llu bpc=%u scramb=%d\n", __func__,
+ drm_hdmi_connector_get_output_format_name(conn_state->hdmi.output_format),
+ conn_state->hdmi.tmds_char_rate, conn_state->hdmi.output_bpc,
+ hdmi->curr_conn->hdmi.scrambler_enabled);
} else {
- dev_dbg(hdmi->dev, "%s mode=DVI\n", __func__);
op_mode = OPMODE_DVI;
+ dev_dbg(hdmi->dev, "%s mode=DVI\n", __func__);
}
hdmi->phy.ops->init(hdmi, hdmi->phy.data);
@@ -779,7 +790,7 @@ static void dw_hdmi_qp_bridge_atomic_enable(struct drm_bridge *bridge,
dw_hdmi_qp_mod(hdmi, HDCP2_BYPASS, HDCP2_BYPASS, HDCP2LOGIC_CONFIG0);
dw_hdmi_qp_mod(hdmi, op_mode, OPMODE_DVI, LINK_CONFIG0);
- drm_atomic_helper_connector_hdmi_update_infoframes(connector, state);
+ drm_atomic_helper_connector_hdmi_update_infoframes(hdmi->curr_conn, state);
}
static void dw_hdmi_qp_bridge_atomic_disable(struct drm_bridge *bridge,
@@ -787,8 +798,14 @@ static void dw_hdmi_qp_bridge_atomic_disable(struct drm_bridge *bridge,
{
struct dw_hdmi_qp *hdmi = bridge->driver_private;
+ if (!hdmi->curr_conn)
+ return;
+
hdmi->tmds_char_rate = 0;
+ drm_scdc_stop_scrambling(hdmi->curr_conn);
+
+ hdmi->curr_conn = NULL;
hdmi->phy.ops->disable(hdmi, hdmi->phy.data);
}
@@ -830,12 +847,12 @@ dw_hdmi_qp_bridge_tmds_char_rate_valid(const struct drm_bridge *bridge,
{
struct dw_hdmi_qp *hdmi = bridge->driver_private;
- /*
- * TODO: when hdmi->no_hpd is 1 we must not support modes that
- * require scrambling, including every mode with a clock above
- * HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ.
- */
- if (rate > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ) {
+ if (hdmi->no_hpd && rate > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ) {
+ dev_dbg(hdmi->dev, "Unsupported TMDS char rate in no_hpd mode: %lld\n", rate);
+ return MODE_CLOCK_HIGH;
+ }
+
+ if (rate > HDMI_2_0_TMDS_CHAR_RATE_MAX_HZ) {
dev_dbg(hdmi->dev, "Unsupported TMDS char rate: %lld\n", rate);
return MODE_CLOCK_HIGH;
}
@@ -843,6 +860,26 @@ dw_hdmi_qp_bridge_tmds_char_rate_valid(const struct drm_bridge *bridge,
return MODE_OK;
}
+static int dw_hdmi_qp_bridge_scrambler_enable(struct drm_bridge *bridge)
+{
+ struct dw_hdmi_qp *hdmi = bridge->driver_private;
+
+ dw_hdmi_qp_write(hdmi, 1, SCRAMB_CONFIG0);
+ dev_dbg(hdmi->dev, "scrambler enabled\n");
+
+ return 0;
+}
+
+static int dw_hdmi_qp_bridge_scrambler_disable(struct drm_bridge *bridge)
+{
+ struct dw_hdmi_qp *hdmi = bridge->driver_private;
+
+ dw_hdmi_qp_write(hdmi, 0, SCRAMB_CONFIG0);
+ dev_dbg(hdmi->dev, "scrambler disabled\n");
+
+ return 0;
+}
+
static int dw_hdmi_qp_bridge_clear_avi_infoframe(struct drm_bridge *bridge)
{
struct dw_hdmi_qp *hdmi = bridge->driver_private;
@@ -1216,6 +1253,8 @@ static const struct drm_bridge_funcs dw_hdmi_qp_bridge_funcs = {
.hpd_disable = dw_hdmi_qp_bridge_hpd_disable,
.edid_read = dw_hdmi_qp_bridge_edid_read,
.hdmi_tmds_char_rate_valid = dw_hdmi_qp_bridge_tmds_char_rate_valid,
+ .hdmi_scrambler_enable = dw_hdmi_qp_bridge_scrambler_enable,
+ .hdmi_scrambler_disable = dw_hdmi_qp_bridge_scrambler_disable,
.hdmi_clear_avi_infoframe = dw_hdmi_qp_bridge_clear_avi_infoframe,
.hdmi_write_avi_infoframe = dw_hdmi_qp_bridge_write_avi_infoframe,
.hdmi_clear_hdmi_infoframe = dw_hdmi_qp_bridge_clear_hdmi_infoframe,
@@ -1342,7 +1381,8 @@ struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev,
DRM_BRIDGE_OP_HDMI |
DRM_BRIDGE_OP_HDMI_AUDIO |
DRM_BRIDGE_OP_HDMI_HDR_DRM_INFOFRAME |
- DRM_BRIDGE_OP_HDMI_SPD_INFOFRAME;
+ DRM_BRIDGE_OP_HDMI_SPD_INFOFRAME |
+ DRM_BRIDGE_OP_HDMI_SCRAMBLER;
if (!hdmi->no_hpd)
hdmi->bridge.ops |= DRM_BRIDGE_OP_HPD;
hdmi->bridge.of_node = pdev->dev.of_node;
--
2.54.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH v7 14/30] drm/bridge: dw-hdmi-qp: Add HDMI 2.0 SCDC scrambling support
@ 2026-06-01 22:44 ` Cristian Ciocaltea
0 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip,
Diederik de Haas, Maud Spierings
Enable HDMI 2.0 display modes (e.g. 4K@60Hz) by implementing SCDC
scrambling and high TMDS clock ratio management for TMDS character
rates exceeding the 340 MHz HDMI 1.4b limit.
Reject modes requiring TMDS rates above 600 MHz since those require
HDMI 2.1 FRL which is not yet supported. In no_hpd configurations,
further restrict to 340 MHz because SCDC requires a connected sink.
Tested-by: Diederik de Haas <diederik@cknow-tech.com>
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Acked-by: Heiko Stuebner <heiko@sntech.de>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 76 +++++++++++++++++++++-------
1 file changed, 58 insertions(+), 18 deletions(-)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
index 3f72bea20ba4..0250ddd8f91a 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
@@ -2,6 +2,7 @@
/*
* Copyright (c) 2021-2022 Rockchip Electronics Co., Ltd.
* Copyright (c) 2024 Collabora Ltd.
+ * Copyright (c) 2025 Amazon.com, Inc. or its affiliates.
*
* Author: Algea Cao <algea.cao@rock-chips.com>
* Author: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
@@ -15,12 +16,12 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
-#include <linux/workqueue.h>
#include <drm/bridge/dw_hdmi_qp.h>
#include <drm/display/drm_hdmi_helper.h>
#include <drm/display/drm_hdmi_cec_helper.h>
#include <drm/display/drm_hdmi_state_helper.h>
+#include <drm/display/drm_scdc_helper.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
@@ -162,6 +163,7 @@ struct dw_hdmi_qp {
} phy;
unsigned long ref_clk_rate;
+ struct drm_connector *curr_conn;
struct regmap *regm;
int main_irq;
@@ -752,26 +754,35 @@ static void dw_hdmi_qp_bridge_atomic_enable(struct drm_bridge *bridge,
{
struct dw_hdmi_qp *hdmi = bridge->driver_private;
struct drm_connector_state *conn_state;
- struct drm_connector *connector;
unsigned int op_mode;
+ int ret;
- connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder);
- if (WARN_ON(!connector))
+ hdmi->curr_conn = drm_atomic_get_new_connector_for_encoder(state,
+ bridge->encoder);
+ if (WARN_ON(!hdmi->curr_conn))
return;
- conn_state = drm_atomic_get_new_connector_state(state, connector);
+ conn_state = drm_atomic_get_new_connector_state(state, hdmi->curr_conn);
if (WARN_ON(!conn_state))
return;
- if (connector->display_info.is_hdmi) {
- dev_dbg(hdmi->dev, "%s mode=HDMI %s rate=%llu bpc=%u\n", __func__,
- drm_hdmi_connector_get_output_format_name(conn_state->hdmi.output_format),
- conn_state->hdmi.tmds_char_rate, conn_state->hdmi.output_bpc);
+ if (hdmi->curr_conn->display_info.is_hdmi) {
op_mode = 0;
hdmi->tmds_char_rate = conn_state->hdmi.tmds_char_rate;
+
+ if (conn_state->hdmi.scrambler_needed) {
+ ret = drm_scdc_start_scrambling(hdmi->curr_conn);
+ if (ret)
+ dev_warn(hdmi->dev, "Failed to setup SCDC: %d\n", ret);
+ }
+
+ dev_dbg(hdmi->dev, "%s mode=HDMI %s rate=%llu bpc=%u scramb=%d\n", __func__,
+ drm_hdmi_connector_get_output_format_name(conn_state->hdmi.output_format),
+ conn_state->hdmi.tmds_char_rate, conn_state->hdmi.output_bpc,
+ hdmi->curr_conn->hdmi.scrambler_enabled);
} else {
- dev_dbg(hdmi->dev, "%s mode=DVI\n", __func__);
op_mode = OPMODE_DVI;
+ dev_dbg(hdmi->dev, "%s mode=DVI\n", __func__);
}
hdmi->phy.ops->init(hdmi, hdmi->phy.data);
@@ -779,7 +790,7 @@ static void dw_hdmi_qp_bridge_atomic_enable(struct drm_bridge *bridge,
dw_hdmi_qp_mod(hdmi, HDCP2_BYPASS, HDCP2_BYPASS, HDCP2LOGIC_CONFIG0);
dw_hdmi_qp_mod(hdmi, op_mode, OPMODE_DVI, LINK_CONFIG0);
- drm_atomic_helper_connector_hdmi_update_infoframes(connector, state);
+ drm_atomic_helper_connector_hdmi_update_infoframes(hdmi->curr_conn, state);
}
static void dw_hdmi_qp_bridge_atomic_disable(struct drm_bridge *bridge,
@@ -787,8 +798,14 @@ static void dw_hdmi_qp_bridge_atomic_disable(struct drm_bridge *bridge,
{
struct dw_hdmi_qp *hdmi = bridge->driver_private;
+ if (!hdmi->curr_conn)
+ return;
+
hdmi->tmds_char_rate = 0;
+ drm_scdc_stop_scrambling(hdmi->curr_conn);
+
+ hdmi->curr_conn = NULL;
hdmi->phy.ops->disable(hdmi, hdmi->phy.data);
}
@@ -830,12 +847,12 @@ dw_hdmi_qp_bridge_tmds_char_rate_valid(const struct drm_bridge *bridge,
{
struct dw_hdmi_qp *hdmi = bridge->driver_private;
- /*
- * TODO: when hdmi->no_hpd is 1 we must not support modes that
- * require scrambling, including every mode with a clock above
- * HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ.
- */
- if (rate > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ) {
+ if (hdmi->no_hpd && rate > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ) {
+ dev_dbg(hdmi->dev, "Unsupported TMDS char rate in no_hpd mode: %lld\n", rate);
+ return MODE_CLOCK_HIGH;
+ }
+
+ if (rate > HDMI_2_0_TMDS_CHAR_RATE_MAX_HZ) {
dev_dbg(hdmi->dev, "Unsupported TMDS char rate: %lld\n", rate);
return MODE_CLOCK_HIGH;
}
@@ -843,6 +860,26 @@ dw_hdmi_qp_bridge_tmds_char_rate_valid(const struct drm_bridge *bridge,
return MODE_OK;
}
+static int dw_hdmi_qp_bridge_scrambler_enable(struct drm_bridge *bridge)
+{
+ struct dw_hdmi_qp *hdmi = bridge->driver_private;
+
+ dw_hdmi_qp_write(hdmi, 1, SCRAMB_CONFIG0);
+ dev_dbg(hdmi->dev, "scrambler enabled\n");
+
+ return 0;
+}
+
+static int dw_hdmi_qp_bridge_scrambler_disable(struct drm_bridge *bridge)
+{
+ struct dw_hdmi_qp *hdmi = bridge->driver_private;
+
+ dw_hdmi_qp_write(hdmi, 0, SCRAMB_CONFIG0);
+ dev_dbg(hdmi->dev, "scrambler disabled\n");
+
+ return 0;
+}
+
static int dw_hdmi_qp_bridge_clear_avi_infoframe(struct drm_bridge *bridge)
{
struct dw_hdmi_qp *hdmi = bridge->driver_private;
@@ -1216,6 +1253,8 @@ static const struct drm_bridge_funcs dw_hdmi_qp_bridge_funcs = {
.hpd_disable = dw_hdmi_qp_bridge_hpd_disable,
.edid_read = dw_hdmi_qp_bridge_edid_read,
.hdmi_tmds_char_rate_valid = dw_hdmi_qp_bridge_tmds_char_rate_valid,
+ .hdmi_scrambler_enable = dw_hdmi_qp_bridge_scrambler_enable,
+ .hdmi_scrambler_disable = dw_hdmi_qp_bridge_scrambler_disable,
.hdmi_clear_avi_infoframe = dw_hdmi_qp_bridge_clear_avi_infoframe,
.hdmi_write_avi_infoframe = dw_hdmi_qp_bridge_write_avi_infoframe,
.hdmi_clear_hdmi_infoframe = dw_hdmi_qp_bridge_clear_hdmi_infoframe,
@@ -1342,7 +1381,8 @@ struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev,
DRM_BRIDGE_OP_HDMI |
DRM_BRIDGE_OP_HDMI_AUDIO |
DRM_BRIDGE_OP_HDMI_HDR_DRM_INFOFRAME |
- DRM_BRIDGE_OP_HDMI_SPD_INFOFRAME;
+ DRM_BRIDGE_OP_HDMI_SPD_INFOFRAME |
+ DRM_BRIDGE_OP_HDMI_SCRAMBLER;
if (!hdmi->no_hpd)
hdmi->bridge.ops |= DRM_BRIDGE_OP_HPD;
hdmi->bridge.of_node = pdev->dev.of_node;
--
2.54.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH v7 15/30] drm/bridge: dw-hdmi-qp: Provide dw_hdmi_qp_hpd_notify() helper
2026-06-01 22:44 ` Cristian Ciocaltea
@ 2026-06-01 22:44 ` Cristian Ciocaltea
-1 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
Export dw_hdmi_qp_hpd_notify() for platform drivers to report hot-plug
detection events. Unlike drm_helper_hpd_irq_event() which polls all
connectors, this helper targets only the affected connector and ensures
.detect_ctx() is invoked on reconnection events to trigger SCDC state
recovery.
Note that this helper may sleep, so it must only be called from a
threaded HPD interrupt handler or a work function.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 31 ++++++++++++++++++++++++++++
include/drm/bridge/dw_hdmi_qp.h | 1 +
2 files changed, 32 insertions(+)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
index 0250ddd8f91a..999229705ffb 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
@@ -29,6 +29,7 @@
#include <drm/drm_edid.h>
#include <drm/drm_modes.h>
#include <drm/drm_print.h>
+#include <drm/drm_probe_helper.h>
#include <media/cec.h>
@@ -1433,6 +1434,36 @@ struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev,
}
EXPORT_SYMBOL_GPL(dw_hdmi_qp_bind);
+/**
+ * dw_hdmi_qp_hpd_notify() - Notify a hot-plug detection event
+ * @hdmi: pointer to the DW HDMI QP controller
+ *
+ * Platform drivers should call this from their threaded IRQ handler or work
+ * function to notify the bridge of a connection status change.
+ * The bridge's .read_hpd() phy_ops callback is used to read the current
+ * connection status.
+ */
+void dw_hdmi_qp_hpd_notify(struct dw_hdmi_qp *hdmi)
+{
+ enum drm_connector_status status;
+
+ status = hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data);
+ dev_dbg(hdmi->dev, "%s status=%d\n", __func__, status);
+
+ /*
+ * When the display pipeline has been already active, switch to
+ * drm_connector_helper_hpd_irq_event() to ensure .detect_ctx()
+ * gets invoked, i.e. via drm_helper_probe_detect(), because
+ * drm_bridge_hpd_notify() defers to a delayed hotplug path in
+ * this case.
+ */
+ if (hdmi->curr_conn && status == connector_status_connected)
+ drm_connector_helper_hpd_irq_event(hdmi->curr_conn);
+ else
+ drm_bridge_hpd_notify(&hdmi->bridge, status);
+}
+EXPORT_SYMBOL_GPL(dw_hdmi_qp_hpd_notify);
+
void dw_hdmi_qp_suspend(struct device *dev, struct dw_hdmi_qp *hdmi)
{
disable_irq(hdmi->main_irq);
diff --git a/include/drm/bridge/dw_hdmi_qp.h b/include/drm/bridge/dw_hdmi_qp.h
index b80fceffc315..b4fb1c578a5b 100644
--- a/include/drm/bridge/dw_hdmi_qp.h
+++ b/include/drm/bridge/dw_hdmi_qp.h
@@ -36,6 +36,7 @@ struct dw_hdmi_qp_plat_data {
struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev,
struct drm_encoder *encoder,
const struct dw_hdmi_qp_plat_data *plat_data);
+void dw_hdmi_qp_hpd_notify(struct dw_hdmi_qp *hdmi);
void dw_hdmi_qp_suspend(struct device *dev, struct dw_hdmi_qp *hdmi);
void dw_hdmi_qp_resume(struct device *dev, struct dw_hdmi_qp *hdmi);
#endif /* __DW_HDMI_QP__ */
--
2.54.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH v7 15/30] drm/bridge: dw-hdmi-qp: Provide dw_hdmi_qp_hpd_notify() helper
@ 2026-06-01 22:44 ` Cristian Ciocaltea
0 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
Export dw_hdmi_qp_hpd_notify() for platform drivers to report hot-plug
detection events. Unlike drm_helper_hpd_irq_event() which polls all
connectors, this helper targets only the affected connector and ensures
.detect_ctx() is invoked on reconnection events to trigger SCDC state
recovery.
Note that this helper may sleep, so it must only be called from a
threaded HPD interrupt handler or a work function.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 31 ++++++++++++++++++++++++++++
include/drm/bridge/dw_hdmi_qp.h | 1 +
2 files changed, 32 insertions(+)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
index 0250ddd8f91a..999229705ffb 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
@@ -29,6 +29,7 @@
#include <drm/drm_edid.h>
#include <drm/drm_modes.h>
#include <drm/drm_print.h>
+#include <drm/drm_probe_helper.h>
#include <media/cec.h>
@@ -1433,6 +1434,36 @@ struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev,
}
EXPORT_SYMBOL_GPL(dw_hdmi_qp_bind);
+/**
+ * dw_hdmi_qp_hpd_notify() - Notify a hot-plug detection event
+ * @hdmi: pointer to the DW HDMI QP controller
+ *
+ * Platform drivers should call this from their threaded IRQ handler or work
+ * function to notify the bridge of a connection status change.
+ * The bridge's .read_hpd() phy_ops callback is used to read the current
+ * connection status.
+ */
+void dw_hdmi_qp_hpd_notify(struct dw_hdmi_qp *hdmi)
+{
+ enum drm_connector_status status;
+
+ status = hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data);
+ dev_dbg(hdmi->dev, "%s status=%d\n", __func__, status);
+
+ /*
+ * When the display pipeline has been already active, switch to
+ * drm_connector_helper_hpd_irq_event() to ensure .detect_ctx()
+ * gets invoked, i.e. via drm_helper_probe_detect(), because
+ * drm_bridge_hpd_notify() defers to a delayed hotplug path in
+ * this case.
+ */
+ if (hdmi->curr_conn && status == connector_status_connected)
+ drm_connector_helper_hpd_irq_event(hdmi->curr_conn);
+ else
+ drm_bridge_hpd_notify(&hdmi->bridge, status);
+}
+EXPORT_SYMBOL_GPL(dw_hdmi_qp_hpd_notify);
+
void dw_hdmi_qp_suspend(struct device *dev, struct dw_hdmi_qp *hdmi)
{
disable_irq(hdmi->main_irq);
diff --git a/include/drm/bridge/dw_hdmi_qp.h b/include/drm/bridge/dw_hdmi_qp.h
index b80fceffc315..b4fb1c578a5b 100644
--- a/include/drm/bridge/dw_hdmi_qp.h
+++ b/include/drm/bridge/dw_hdmi_qp.h
@@ -36,6 +36,7 @@ struct dw_hdmi_qp_plat_data {
struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev,
struct drm_encoder *encoder,
const struct dw_hdmi_qp_plat_data *plat_data);
+void dw_hdmi_qp_hpd_notify(struct dw_hdmi_qp *hdmi);
void dw_hdmi_qp_suspend(struct device *dev, struct dw_hdmi_qp *hdmi);
void dw_hdmi_qp_resume(struct device *dev, struct dw_hdmi_qp *hdmi);
#endif /* __DW_HDMI_QP__ */
--
2.54.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH v7 16/30] drm/rockchip: dw_hdmi_qp: Add missing newlines in dev_err_probe() messages
2026-06-01 22:44 ` Cristian Ciocaltea
@ 2026-06-01 22:44 ` Cristian Ciocaltea
-1 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
Add the missing trailing newlines to a couple of dev_err_probe() calls
in dw_hdmi_qp_rockchip_bind().
Fixes: b6736a4ea3fa ("drm/rockchip: dw_hdmi_qp: Improve error handling with dev_err_probe()")
Fixes: e1f7b7cbd74c ("drm/rockchip: dw_hdmi_qp: Switch to drmm_encoder_init()")
Reviewed-by: Heiko Stuebner <heiko@sntech.de>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index f35484715c2d..296f9a3ba66a 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -589,14 +589,14 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
drm_encoder_helper_add(encoder, &dw_hdmi_qp_rockchip_encoder_helper_funcs);
ret = drmm_encoder_init(drm, encoder, NULL, DRM_MODE_ENCODER_TMDS, NULL);
if (ret)
- return dev_err_probe(hdmi->dev, ret, "Failed to init encoder");
+ return dev_err_probe(hdmi->dev, ret, "Failed to init encoder\n");
platform_set_drvdata(pdev, hdmi);
hdmi->hdmi = dw_hdmi_qp_bind(pdev, encoder, &plat_data);
if (IS_ERR(hdmi->hdmi))
return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->hdmi),
- "Failed to bind dw-hdmi-qp");
+ "Failed to bind dw-hdmi-qp\n");
connector = drm_bridge_connector_init(drm, encoder);
if (IS_ERR(connector))
--
2.54.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH v7 16/30] drm/rockchip: dw_hdmi_qp: Add missing newlines in dev_err_probe() messages
@ 2026-06-01 22:44 ` Cristian Ciocaltea
0 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
Add the missing trailing newlines to a couple of dev_err_probe() calls
in dw_hdmi_qp_rockchip_bind().
Fixes: b6736a4ea3fa ("drm/rockchip: dw_hdmi_qp: Improve error handling with dev_err_probe()")
Fixes: e1f7b7cbd74c ("drm/rockchip: dw_hdmi_qp: Switch to drmm_encoder_init()")
Reviewed-by: Heiko Stuebner <heiko@sntech.de>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index f35484715c2d..296f9a3ba66a 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -589,14 +589,14 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
drm_encoder_helper_add(encoder, &dw_hdmi_qp_rockchip_encoder_helper_funcs);
ret = drmm_encoder_init(drm, encoder, NULL, DRM_MODE_ENCODER_TMDS, NULL);
if (ret)
- return dev_err_probe(hdmi->dev, ret, "Failed to init encoder");
+ return dev_err_probe(hdmi->dev, ret, "Failed to init encoder\n");
platform_set_drvdata(pdev, hdmi);
hdmi->hdmi = dw_hdmi_qp_bind(pdev, encoder, &plat_data);
if (IS_ERR(hdmi->hdmi))
return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->hdmi),
- "Failed to bind dw-hdmi-qp");
+ "Failed to bind dw-hdmi-qp\n");
connector = drm_bridge_connector_init(drm, encoder);
if (IS_ERR(connector))
--
2.54.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH v7 17/30] drm/rockchip: dw_hdmi_qp: Use local dev variable consistently in bind()
2026-06-01 22:44 ` Cristian Ciocaltea
@ 2026-06-01 22:44 ` Cristian Ciocaltea
-1 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
Replace indirect struct device accesses via hdmi->dev and pdev->dev with
the local dev parameter already available in dw_hdmi_qp_rockchip_bind(),
for consistency and readability.
Reviewed-by: Heiko Stuebner <heiko@sntech.de>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 33 +++++++++++++-------------
1 file changed, 16 insertions(+), 17 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index 296f9a3ba66a..46df5abe31a4 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -475,7 +475,7 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
struct clk *ref_clk;
int ret, irq, i;
- if (!pdev->dev.of_node)
+ if (!dev->of_node)
return -ENODEV;
hdmi = drmm_kzalloc(drm, sizeof(*hdmi), GFP_KERNEL);
@@ -495,7 +495,7 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
return dev_err_probe(dev, -ENODEV, "Missing platform ctrl ops\n");
hdmi->ctrl_ops = cfg->ctrl_ops;
- hdmi->dev = &pdev->dev;
+ hdmi->dev = dev;
hdmi->port_id = -ENODEV;
/* Identify port ID by matching base IO address */
@@ -506,7 +506,7 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
}
}
if (hdmi->port_id < 0)
- return dev_err_probe(hdmi->dev, hdmi->port_id,
+ return dev_err_probe(dev, hdmi->port_id,
"Failed to match HDMI port ID\n");
plat_data.phy_ops = cfg->phy_ops;
@@ -530,37 +530,36 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
hdmi->regmap = syscon_regmap_lookup_by_phandle(dev->of_node,
"rockchip,grf");
if (IS_ERR(hdmi->regmap))
- return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->regmap),
+ return dev_err_probe(dev, PTR_ERR(hdmi->regmap),
"Unable to get rockchip,grf\n");
hdmi->vo_regmap = syscon_regmap_lookup_by_phandle(dev->of_node,
"rockchip,vo-grf");
if (IS_ERR(hdmi->vo_regmap))
- return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->vo_regmap),
+ return dev_err_probe(dev, PTR_ERR(hdmi->vo_regmap),
"Unable to get rockchip,vo-grf\n");
- ret = devm_clk_bulk_get_all_enabled(hdmi->dev, &clks);
+ ret = devm_clk_bulk_get_all_enabled(dev, &clks);
if (ret < 0)
- return dev_err_probe(hdmi->dev, ret, "Failed to get clocks\n");
+ return dev_err_probe(dev, ret, "Failed to get clocks\n");
- ref_clk = clk_get(hdmi->dev, "ref");
+ ref_clk = clk_get(dev, "ref");
if (IS_ERR(ref_clk))
- return dev_err_probe(hdmi->dev, PTR_ERR(ref_clk),
+ return dev_err_probe(dev, PTR_ERR(ref_clk),
"Failed to get ref clock\n");
plat_data.ref_clk_rate = clk_get_rate(ref_clk);
clk_put(ref_clk);
- hdmi->frl_enable_gpio = devm_gpiod_get_optional(hdmi->dev, "frl-enable",
+ hdmi->frl_enable_gpio = devm_gpiod_get_optional(dev, "frl-enable",
GPIOD_OUT_LOW);
if (IS_ERR(hdmi->frl_enable_gpio))
- return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->frl_enable_gpio),
+ return dev_err_probe(dev, PTR_ERR(hdmi->frl_enable_gpio),
"Failed to request FRL enable GPIO\n");
hdmi->phy = devm_of_phy_get_by_index(dev, dev->of_node, 0);
if (IS_ERR(hdmi->phy))
- return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->phy),
- "Failed to get phy\n");
+ return dev_err_probe(dev, PTR_ERR(hdmi->phy), "Failed to get phy\n");
cfg->ctrl_ops->io_init(hdmi);
@@ -578,7 +577,7 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
if (irq < 0)
return irq;
- ret = devm_request_threaded_irq(hdmi->dev, irq,
+ ret = devm_request_threaded_irq(dev, irq,
cfg->ctrl_ops->hardirq_callback,
cfg->ctrl_ops->irq_callback,
IRQF_SHARED, "dw-hdmi-qp-hpd",
@@ -589,18 +588,18 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
drm_encoder_helper_add(encoder, &dw_hdmi_qp_rockchip_encoder_helper_funcs);
ret = drmm_encoder_init(drm, encoder, NULL, DRM_MODE_ENCODER_TMDS, NULL);
if (ret)
- return dev_err_probe(hdmi->dev, ret, "Failed to init encoder\n");
+ return dev_err_probe(dev, ret, "Failed to init encoder\n");
platform_set_drvdata(pdev, hdmi);
hdmi->hdmi = dw_hdmi_qp_bind(pdev, encoder, &plat_data);
if (IS_ERR(hdmi->hdmi))
- return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->hdmi),
+ return dev_err_probe(dev, PTR_ERR(hdmi->hdmi),
"Failed to bind dw-hdmi-qp\n");
connector = drm_bridge_connector_init(drm, encoder);
if (IS_ERR(connector))
- return dev_err_probe(hdmi->dev, PTR_ERR(connector),
+ return dev_err_probe(dev, PTR_ERR(connector),
"Failed to init bridge connector\n");
return 0;
--
2.54.0
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH v7 17/30] drm/rockchip: dw_hdmi_qp: Use local dev variable consistently in bind()
@ 2026-06-01 22:44 ` Cristian Ciocaltea
0 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
Replace indirect struct device accesses via hdmi->dev and pdev->dev with
the local dev parameter already available in dw_hdmi_qp_rockchip_bind(),
for consistency and readability.
Reviewed-by: Heiko Stuebner <heiko@sntech.de>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 33 +++++++++++++-------------
1 file changed, 16 insertions(+), 17 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index 296f9a3ba66a..46df5abe31a4 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -475,7 +475,7 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
struct clk *ref_clk;
int ret, irq, i;
- if (!pdev->dev.of_node)
+ if (!dev->of_node)
return -ENODEV;
hdmi = drmm_kzalloc(drm, sizeof(*hdmi), GFP_KERNEL);
@@ -495,7 +495,7 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
return dev_err_probe(dev, -ENODEV, "Missing platform ctrl ops\n");
hdmi->ctrl_ops = cfg->ctrl_ops;
- hdmi->dev = &pdev->dev;
+ hdmi->dev = dev;
hdmi->port_id = -ENODEV;
/* Identify port ID by matching base IO address */
@@ -506,7 +506,7 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
}
}
if (hdmi->port_id < 0)
- return dev_err_probe(hdmi->dev, hdmi->port_id,
+ return dev_err_probe(dev, hdmi->port_id,
"Failed to match HDMI port ID\n");
plat_data.phy_ops = cfg->phy_ops;
@@ -530,37 +530,36 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
hdmi->regmap = syscon_regmap_lookup_by_phandle(dev->of_node,
"rockchip,grf");
if (IS_ERR(hdmi->regmap))
- return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->regmap),
+ return dev_err_probe(dev, PTR_ERR(hdmi->regmap),
"Unable to get rockchip,grf\n");
hdmi->vo_regmap = syscon_regmap_lookup_by_phandle(dev->of_node,
"rockchip,vo-grf");
if (IS_ERR(hdmi->vo_regmap))
- return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->vo_regmap),
+ return dev_err_probe(dev, PTR_ERR(hdmi->vo_regmap),
"Unable to get rockchip,vo-grf\n");
- ret = devm_clk_bulk_get_all_enabled(hdmi->dev, &clks);
+ ret = devm_clk_bulk_get_all_enabled(dev, &clks);
if (ret < 0)
- return dev_err_probe(hdmi->dev, ret, "Failed to get clocks\n");
+ return dev_err_probe(dev, ret, "Failed to get clocks\n");
- ref_clk = clk_get(hdmi->dev, "ref");
+ ref_clk = clk_get(dev, "ref");
if (IS_ERR(ref_clk))
- return dev_err_probe(hdmi->dev, PTR_ERR(ref_clk),
+ return dev_err_probe(dev, PTR_ERR(ref_clk),
"Failed to get ref clock\n");
plat_data.ref_clk_rate = clk_get_rate(ref_clk);
clk_put(ref_clk);
- hdmi->frl_enable_gpio = devm_gpiod_get_optional(hdmi->dev, "frl-enable",
+ hdmi->frl_enable_gpio = devm_gpiod_get_optional(dev, "frl-enable",
GPIOD_OUT_LOW);
if (IS_ERR(hdmi->frl_enable_gpio))
- return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->frl_enable_gpio),
+ return dev_err_probe(dev, PTR_ERR(hdmi->frl_enable_gpio),
"Failed to request FRL enable GPIO\n");
hdmi->phy = devm_of_phy_get_by_index(dev, dev->of_node, 0);
if (IS_ERR(hdmi->phy))
- return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->phy),
- "Failed to get phy\n");
+ return dev_err_probe(dev, PTR_ERR(hdmi->phy), "Failed to get phy\n");
cfg->ctrl_ops->io_init(hdmi);
@@ -578,7 +577,7 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
if (irq < 0)
return irq;
- ret = devm_request_threaded_irq(hdmi->dev, irq,
+ ret = devm_request_threaded_irq(dev, irq,
cfg->ctrl_ops->hardirq_callback,
cfg->ctrl_ops->irq_callback,
IRQF_SHARED, "dw-hdmi-qp-hpd",
@@ -589,18 +588,18 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
drm_encoder_helper_add(encoder, &dw_hdmi_qp_rockchip_encoder_helper_funcs);
ret = drmm_encoder_init(drm, encoder, NULL, DRM_MODE_ENCODER_TMDS, NULL);
if (ret)
- return dev_err_probe(hdmi->dev, ret, "Failed to init encoder\n");
+ return dev_err_probe(dev, ret, "Failed to init encoder\n");
platform_set_drvdata(pdev, hdmi);
hdmi->hdmi = dw_hdmi_qp_bind(pdev, encoder, &plat_data);
if (IS_ERR(hdmi->hdmi))
- return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->hdmi),
+ return dev_err_probe(dev, PTR_ERR(hdmi->hdmi),
"Failed to bind dw-hdmi-qp\n");
connector = drm_bridge_connector_init(drm, encoder);
if (IS_ERR(connector))
- return dev_err_probe(hdmi->dev, PTR_ERR(connector),
+ return dev_err_probe(dev, PTR_ERR(connector),
"Failed to init bridge connector\n");
return 0;
--
2.54.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH v7 18/30] drm/rockchip: dw_hdmi_qp: Drop unnecessary #include
2026-06-01 22:44 ` Cristian Ciocaltea
@ 2026-06-01 22:44 ` Cristian Ciocaltea
-1 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
Remove superfluous drm_simple_kms_helper.h include, which has no users
in this file since commit e1f7b7cbd74c ("drm/rockchip: dw_hdmi_qp:
Switch to drmm_encoder_init()").
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index 46df5abe31a4..8d64b76a1aa5 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -24,7 +24,6 @@
#include <drm/drm_managed.h>
#include <drm/drm_of.h>
#include <drm/drm_probe_helper.h>
-#include <drm/drm_simple_kms_helper.h>
#include "rockchip_drm_drv.h"
--
2.54.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH v7 18/30] drm/rockchip: dw_hdmi_qp: Drop unnecessary #include
@ 2026-06-01 22:44 ` Cristian Ciocaltea
0 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
Remove superfluous drm_simple_kms_helper.h include, which has no users
in this file since commit e1f7b7cbd74c ("drm/rockchip: dw_hdmi_qp:
Switch to drmm_encoder_init()").
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index 46df5abe31a4..8d64b76a1aa5 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -24,7 +24,6 @@
#include <drm/drm_managed.h>
#include <drm/drm_of.h>
#include <drm/drm_probe_helper.h>
-#include <drm/drm_simple_kms_helper.h>
#include "rockchip_drm_drv.h"
--
2.54.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH v7 19/30] drm/rockchip: dw_hdmi_qp: Defer HPD IRQ enable until after connector setup
2026-06-01 22:44 ` Cristian Ciocaltea
@ 2026-06-01 22:44 ` Cristian Ciocaltea
-1 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip,
Dmitry Baryshkov
Request the HPD IRQ early in bind() with IRQF_NO_AUTOEN, keeping it
disabled until all DRM resources are fully initialized, at which point
enable_irq() arms it. This prevents premature interrupt delivery
without forcing devm_request_threaded_irq() to the very end of the
initialization sequence, which would complicate error unwinding.
Note that IRQF_NO_AUTOEN is incompatible with IRQF_SHARED; the latter is
dropped as this IRQ has no other users.
Suggested-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index 8d64b76a1aa5..27342094958c 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -579,7 +579,7 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
ret = devm_request_threaded_irq(dev, irq,
cfg->ctrl_ops->hardirq_callback,
cfg->ctrl_ops->irq_callback,
- IRQF_SHARED, "dw-hdmi-qp-hpd",
+ IRQF_NO_AUTOEN, "dw-hdmi-qp-hpd",
hdmi);
if (ret)
return ret;
@@ -601,6 +601,8 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
return dev_err_probe(dev, PTR_ERR(connector),
"Failed to init bridge connector\n");
+ enable_irq(irq);
+
return 0;
}
--
2.54.0
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH v7 19/30] drm/rockchip: dw_hdmi_qp: Defer HPD IRQ enable until after connector setup
@ 2026-06-01 22:44 ` Cristian Ciocaltea
0 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip,
Dmitry Baryshkov
Request the HPD IRQ early in bind() with IRQF_NO_AUTOEN, keeping it
disabled until all DRM resources are fully initialized, at which point
enable_irq() arms it. This prevents premature interrupt delivery
without forcing devm_request_threaded_irq() to the very end of the
initialization sequence, which would complicate error unwinding.
Note that IRQF_NO_AUTOEN is incompatible with IRQF_SHARED; the latter is
dropped as this IRQ has no other users.
Suggested-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index 8d64b76a1aa5..27342094958c 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -579,7 +579,7 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
ret = devm_request_threaded_irq(dev, irq,
cfg->ctrl_ops->hardirq_callback,
cfg->ctrl_ops->irq_callback,
- IRQF_SHARED, "dw-hdmi-qp-hpd",
+ IRQF_NO_AUTOEN, "dw-hdmi-qp-hpd",
hdmi);
if (ret)
return ret;
@@ -601,6 +601,8 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
return dev_err_probe(dev, PTR_ERR(connector),
"Failed to init bridge connector\n");
+ enable_irq(irq);
+
return 0;
}
--
2.54.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH v7 20/30] drm/rockchip: dw_hdmi_qp: Mask HPD IRQ in rk3576_io_init()
2026-06-01 22:44 ` Cristian Ciocaltea
@ 2026-06-01 22:44 ` Cristian Ciocaltea
-1 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
Mask the RK3576 HPD interrupt in io_init() so it starts disabled,
matching the RK3588 behavior. This prevents spurious interrupts before
the bridge framework enables HPD via the .hpd_enable() callback.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index 27342094958c..62ea5c7cbbe6 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -346,7 +346,7 @@ static void dw_hdmi_qp_rk3576_io_init(struct rockchip_hdmi_qp *hdmi)
regmap_write(hdmi->vo_regmap, RK3576_VO0_GRF_SOC_CON14, val);
- val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 0);
+ val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 1);
regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
}
--
2.54.0
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH v7 20/30] drm/rockchip: dw_hdmi_qp: Mask HPD IRQ in rk3576_io_init()
@ 2026-06-01 22:44 ` Cristian Ciocaltea
0 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
Mask the RK3576 HPD interrupt in io_init() so it starts disabled,
matching the RK3588 behavior. This prevents spurious interrupts before
the bridge framework enables HPD via the .hpd_enable() callback.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index 27342094958c..62ea5c7cbbe6 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -346,7 +346,7 @@ static void dw_hdmi_qp_rk3576_io_init(struct rockchip_hdmi_qp *hdmi)
regmap_write(hdmi->vo_regmap, RK3576_VO0_GRF_SOC_CON14, val);
- val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 0);
+ val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 1);
regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
}
--
2.54.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH v7 21/30] drm/rockchip: dw_hdmi_qp: Implement .{enable|disable}_hpd() PHY ops
2026-06-01 22:44 ` Cristian Ciocaltea
@ 2026-06-01 22:44 ` Cristian Ciocaltea
-1 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
Implement .enable_hpd() and .disable_hpd() phy ops for RK3576 and RK3588
SoCs, used by the corresponding bridge callbacks for HPD activation
control.
Consolidate the interrupt clear-and-unmask sequence into enable_hpd()
and the mask-only operation into disable_hpd(), replacing the open-coded
register writes in the interrupt handlers and io_init().
The .setup_hpd() phy op, which was previously called from
dw_hdmi_qp_init_hw(), is no longer needed and its users are removed.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 78 +++++++++++++-------------
1 file changed, 38 insertions(+), 40 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index 62ea5c7cbbe6..b9e0ea56efd8 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -193,7 +193,7 @@ dw_hdmi_qp_rk3588_read_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
return val ? connector_status_connected : connector_status_disconnected;
}
-static void dw_hdmi_qp_rk3588_setup_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
+static void dw_hdmi_qp_rk3588_enable_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
{
struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
u32 val;
@@ -208,11 +208,25 @@ static void dw_hdmi_qp_rk3588_setup_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
}
+static void dw_hdmi_qp_rk3588_disable_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
+{
+ struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
+ u32 val;
+
+ if (hdmi->port_id)
+ val = FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_MSK, 1);
+ else
+ val = FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_MSK, 1);
+
+ regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
+}
+
static const struct dw_hdmi_qp_phy_ops rk3588_hdmi_phy_ops = {
.init = dw_hdmi_qp_rk3588_phy_init,
.disable = dw_hdmi_qp_rk3588_phy_disable,
.read_hpd = dw_hdmi_qp_rk3588_read_hpd,
- .setup_hpd = dw_hdmi_qp_rk3588_setup_hpd,
+ .enable_hpd = dw_hdmi_qp_rk3588_enable_hpd,
+ .disable_hpd = dw_hdmi_qp_rk3588_disable_hpd,
};
static enum drm_connector_status
@@ -227,7 +241,7 @@ dw_hdmi_qp_rk3576_read_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
connector_status_connected : connector_status_disconnected;
}
-static void dw_hdmi_qp_rk3576_setup_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
+static void dw_hdmi_qp_rk3576_enable_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
{
struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
u32 val;
@@ -236,14 +250,22 @@ static void dw_hdmi_qp_rk3576_setup_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 0));
regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
- regmap_write(hdmi->regmap, 0xa404, 0xffff0102);
+}
+
+static void dw_hdmi_qp_rk3576_disable_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
+{
+ struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
+
+ regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0,
+ FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 1));
}
static const struct dw_hdmi_qp_phy_ops rk3576_hdmi_phy_ops = {
.init = dw_hdmi_qp_rk3588_phy_init,
.disable = dw_hdmi_qp_rk3588_phy_disable,
.read_hpd = dw_hdmi_qp_rk3576_read_hpd,
- .setup_hpd = dw_hdmi_qp_rk3576_setup_hpd,
+ .enable_hpd = dw_hdmi_qp_rk3576_enable_hpd,
+ .disable_hpd = dw_hdmi_qp_rk3576_disable_hpd,
};
static void dw_hdmi_qp_rk3588_hpd_work(struct work_struct *work)
@@ -264,13 +286,12 @@ static void dw_hdmi_qp_rk3588_hpd_work(struct work_struct *work)
static irqreturn_t dw_hdmi_qp_rk3576_hardirq(int irq, void *dev_id)
{
struct rockchip_hdmi_qp *hdmi = dev_id;
- u32 intr_stat, val;
+ u32 intr_stat;
regmap_read(hdmi->regmap, RK3576_IOC_HDMI_HPD_STATUS, &intr_stat);
- if (intr_stat) {
- val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 1);
- regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
+ if (intr_stat) {
+ dw_hdmi_qp_rk3576_disable_hpd(NULL, hdmi);
return IRQ_WAKE_THREAD;
}
@@ -280,15 +301,11 @@ static irqreturn_t dw_hdmi_qp_rk3576_hardirq(int irq, void *dev_id)
static irqreturn_t dw_hdmi_qp_rk3576_irq(int irq, void *dev_id)
{
struct rockchip_hdmi_qp *hdmi = dev_id;
- u32 val;
- val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_CLR, 1);
- regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
mod_delayed_work(system_percpu_wq, &hdmi->hpd_work,
msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
- val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 0);
- regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
+ dw_hdmi_qp_rk3576_enable_hpd(NULL, hdmi);
return IRQ_HANDLED;
}
@@ -296,16 +313,12 @@ static irqreturn_t dw_hdmi_qp_rk3576_irq(int irq, void *dev_id)
static irqreturn_t dw_hdmi_qp_rk3588_hardirq(int irq, void *dev_id)
{
struct rockchip_hdmi_qp *hdmi = dev_id;
- u32 intr_stat, val;
+ u32 intr_stat;
regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &intr_stat);
if (intr_stat) {
- if (hdmi->port_id)
- val = FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_MSK, 1);
- else
- val = FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_MSK, 1);
- regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
+ dw_hdmi_qp_rk3588_disable_hpd(NULL, hdmi);
return IRQ_WAKE_THREAD;
}
@@ -315,22 +328,11 @@ static irqreturn_t dw_hdmi_qp_rk3588_hardirq(int irq, void *dev_id)
static irqreturn_t dw_hdmi_qp_rk3588_irq(int irq, void *dev_id)
{
struct rockchip_hdmi_qp *hdmi = dev_id;
- u32 val;
-
- if (hdmi->port_id)
- val = FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_CLR, 1);
- else
- val = FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_CLR, 1);
- regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
mod_delayed_work(system_percpu_wq, &hdmi->hpd_work,
msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
- if (hdmi->port_id)
- val |= FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_MSK, 0);
- else
- val |= FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_MSK, 0);
- regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
+ dw_hdmi_qp_rk3588_enable_hpd(NULL, hdmi);
return IRQ_HANDLED;
}
@@ -343,11 +345,11 @@ static void dw_hdmi_qp_rk3576_io_init(struct rockchip_hdmi_qp *hdmi)
FIELD_PREP_WM16(RK3576_SDAIN_MASK, 1) |
FIELD_PREP_WM16(RK3576_HDMI_GRANT_SEL, 1) |
FIELD_PREP_WM16(RK3576_I2S_SEL_MASK, 1);
-
regmap_write(hdmi->vo_regmap, RK3576_VO0_GRF_SOC_CON14, val);
- val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 1);
- regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
+ regmap_write(hdmi->regmap, 0xa404, 0xffff0102);
+
+ dw_hdmi_qp_rk3576_disable_hpd(NULL, hdmi);
}
static void dw_hdmi_qp_rk3588_io_init(struct rockchip_hdmi_qp *hdmi)
@@ -372,11 +374,7 @@ static void dw_hdmi_qp_rk3588_io_init(struct rockchip_hdmi_qp *hdmi)
val = FIELD_PREP_WM16(RK3588_HDMI0_GRANT_SEL, 1);
regmap_write(hdmi->vo_regmap, RK3588_GRF_VO1_CON9, val);
- if (hdmi->port_id)
- val = FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_MSK, 1);
- else
- val = FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_MSK, 1);
- regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
+ dw_hdmi_qp_rk3588_disable_hpd(NULL, hdmi);
}
static void dw_hdmi_qp_rk3576_enc_init(struct rockchip_hdmi_qp *hdmi,
--
2.54.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH v7 21/30] drm/rockchip: dw_hdmi_qp: Implement .{enable|disable}_hpd() PHY ops
@ 2026-06-01 22:44 ` Cristian Ciocaltea
0 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
Implement .enable_hpd() and .disable_hpd() phy ops for RK3576 and RK3588
SoCs, used by the corresponding bridge callbacks for HPD activation
control.
Consolidate the interrupt clear-and-unmask sequence into enable_hpd()
and the mask-only operation into disable_hpd(), replacing the open-coded
register writes in the interrupt handlers and io_init().
The .setup_hpd() phy op, which was previously called from
dw_hdmi_qp_init_hw(), is no longer needed and its users are removed.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 78 +++++++++++++-------------
1 file changed, 38 insertions(+), 40 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index 62ea5c7cbbe6..b9e0ea56efd8 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -193,7 +193,7 @@ dw_hdmi_qp_rk3588_read_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
return val ? connector_status_connected : connector_status_disconnected;
}
-static void dw_hdmi_qp_rk3588_setup_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
+static void dw_hdmi_qp_rk3588_enable_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
{
struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
u32 val;
@@ -208,11 +208,25 @@ static void dw_hdmi_qp_rk3588_setup_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
}
+static void dw_hdmi_qp_rk3588_disable_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
+{
+ struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
+ u32 val;
+
+ if (hdmi->port_id)
+ val = FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_MSK, 1);
+ else
+ val = FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_MSK, 1);
+
+ regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
+}
+
static const struct dw_hdmi_qp_phy_ops rk3588_hdmi_phy_ops = {
.init = dw_hdmi_qp_rk3588_phy_init,
.disable = dw_hdmi_qp_rk3588_phy_disable,
.read_hpd = dw_hdmi_qp_rk3588_read_hpd,
- .setup_hpd = dw_hdmi_qp_rk3588_setup_hpd,
+ .enable_hpd = dw_hdmi_qp_rk3588_enable_hpd,
+ .disable_hpd = dw_hdmi_qp_rk3588_disable_hpd,
};
static enum drm_connector_status
@@ -227,7 +241,7 @@ dw_hdmi_qp_rk3576_read_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
connector_status_connected : connector_status_disconnected;
}
-static void dw_hdmi_qp_rk3576_setup_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
+static void dw_hdmi_qp_rk3576_enable_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
{
struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
u32 val;
@@ -236,14 +250,22 @@ static void dw_hdmi_qp_rk3576_setup_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 0));
regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
- regmap_write(hdmi->regmap, 0xa404, 0xffff0102);
+}
+
+static void dw_hdmi_qp_rk3576_disable_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
+{
+ struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
+
+ regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0,
+ FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 1));
}
static const struct dw_hdmi_qp_phy_ops rk3576_hdmi_phy_ops = {
.init = dw_hdmi_qp_rk3588_phy_init,
.disable = dw_hdmi_qp_rk3588_phy_disable,
.read_hpd = dw_hdmi_qp_rk3576_read_hpd,
- .setup_hpd = dw_hdmi_qp_rk3576_setup_hpd,
+ .enable_hpd = dw_hdmi_qp_rk3576_enable_hpd,
+ .disable_hpd = dw_hdmi_qp_rk3576_disable_hpd,
};
static void dw_hdmi_qp_rk3588_hpd_work(struct work_struct *work)
@@ -264,13 +286,12 @@ static void dw_hdmi_qp_rk3588_hpd_work(struct work_struct *work)
static irqreturn_t dw_hdmi_qp_rk3576_hardirq(int irq, void *dev_id)
{
struct rockchip_hdmi_qp *hdmi = dev_id;
- u32 intr_stat, val;
+ u32 intr_stat;
regmap_read(hdmi->regmap, RK3576_IOC_HDMI_HPD_STATUS, &intr_stat);
- if (intr_stat) {
- val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 1);
- regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
+ if (intr_stat) {
+ dw_hdmi_qp_rk3576_disable_hpd(NULL, hdmi);
return IRQ_WAKE_THREAD;
}
@@ -280,15 +301,11 @@ static irqreturn_t dw_hdmi_qp_rk3576_hardirq(int irq, void *dev_id)
static irqreturn_t dw_hdmi_qp_rk3576_irq(int irq, void *dev_id)
{
struct rockchip_hdmi_qp *hdmi = dev_id;
- u32 val;
- val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_CLR, 1);
- regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
mod_delayed_work(system_percpu_wq, &hdmi->hpd_work,
msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
- val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 0);
- regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
+ dw_hdmi_qp_rk3576_enable_hpd(NULL, hdmi);
return IRQ_HANDLED;
}
@@ -296,16 +313,12 @@ static irqreturn_t dw_hdmi_qp_rk3576_irq(int irq, void *dev_id)
static irqreturn_t dw_hdmi_qp_rk3588_hardirq(int irq, void *dev_id)
{
struct rockchip_hdmi_qp *hdmi = dev_id;
- u32 intr_stat, val;
+ u32 intr_stat;
regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &intr_stat);
if (intr_stat) {
- if (hdmi->port_id)
- val = FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_MSK, 1);
- else
- val = FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_MSK, 1);
- regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
+ dw_hdmi_qp_rk3588_disable_hpd(NULL, hdmi);
return IRQ_WAKE_THREAD;
}
@@ -315,22 +328,11 @@ static irqreturn_t dw_hdmi_qp_rk3588_hardirq(int irq, void *dev_id)
static irqreturn_t dw_hdmi_qp_rk3588_irq(int irq, void *dev_id)
{
struct rockchip_hdmi_qp *hdmi = dev_id;
- u32 val;
-
- if (hdmi->port_id)
- val = FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_CLR, 1);
- else
- val = FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_CLR, 1);
- regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
mod_delayed_work(system_percpu_wq, &hdmi->hpd_work,
msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
- if (hdmi->port_id)
- val |= FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_MSK, 0);
- else
- val |= FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_MSK, 0);
- regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
+ dw_hdmi_qp_rk3588_enable_hpd(NULL, hdmi);
return IRQ_HANDLED;
}
@@ -343,11 +345,11 @@ static void dw_hdmi_qp_rk3576_io_init(struct rockchip_hdmi_qp *hdmi)
FIELD_PREP_WM16(RK3576_SDAIN_MASK, 1) |
FIELD_PREP_WM16(RK3576_HDMI_GRANT_SEL, 1) |
FIELD_PREP_WM16(RK3576_I2S_SEL_MASK, 1);
-
regmap_write(hdmi->vo_regmap, RK3576_VO0_GRF_SOC_CON14, val);
- val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 1);
- regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
+ regmap_write(hdmi->regmap, 0xa404, 0xffff0102);
+
+ dw_hdmi_qp_rk3576_disable_hpd(NULL, hdmi);
}
static void dw_hdmi_qp_rk3588_io_init(struct rockchip_hdmi_qp *hdmi)
@@ -372,11 +374,7 @@ static void dw_hdmi_qp_rk3588_io_init(struct rockchip_hdmi_qp *hdmi)
val = FIELD_PREP_WM16(RK3588_HDMI0_GRANT_SEL, 1);
regmap_write(hdmi->vo_regmap, RK3588_GRF_VO1_CON9, val);
- if (hdmi->port_id)
- val = FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_MSK, 1);
- else
- val = FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_MSK, 1);
- regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
+ dw_hdmi_qp_rk3588_disable_hpd(NULL, hdmi);
}
static void dw_hdmi_qp_rk3576_enc_init(struct rockchip_hdmi_qp *hdmi,
--
2.54.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH v7 22/30] drm/rockchip: dw_hdmi_qp: Switch to dw_hdmi_qp_hpd_notify()
2026-06-01 22:44 ` Cristian Ciocaltea
@ 2026-06-01 22:44 ` Cristian Ciocaltea
-1 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
Switch from drm_helper_hpd_irq_event(), which polls all connectors, to
the recently introduced dw_hdmi_qp_hpd_notify() helper, which runs the
detect cycle only on the affected connector.
This avoids unnecessary work and redundant detect calls on unrelated
connectors.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 12 ++----------
1 file changed, 2 insertions(+), 10 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index b9e0ea56efd8..666631fc9162 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -23,7 +23,6 @@
#include <drm/drm_bridge_connector.h>
#include <drm/drm_managed.h>
#include <drm/drm_of.h>
-#include <drm/drm_probe_helper.h>
#include "rockchip_drm_drv.h"
@@ -273,14 +272,8 @@ static void dw_hdmi_qp_rk3588_hpd_work(struct work_struct *work)
struct rockchip_hdmi_qp *hdmi = container_of(work,
struct rockchip_hdmi_qp,
hpd_work.work);
- struct drm_device *drm = hdmi->encoder.encoder.dev;
- bool changed;
- if (drm) {
- changed = drm_helper_hpd_irq_event(drm);
- if (changed)
- dev_dbg(hdmi->dev, "connector status changed\n");
- }
+ dw_hdmi_qp_hpd_notify(hdmi->hdmi);
}
static irqreturn_t dw_hdmi_qp_rk3576_hardirq(int irq, void *dev_id)
@@ -645,8 +638,7 @@ static int __maybe_unused dw_hdmi_qp_rockchip_resume(struct device *dev)
dw_hdmi_qp_resume(dev, hdmi->hdmi);
- if (hdmi->encoder.encoder.dev)
- drm_helper_hpd_irq_event(hdmi->encoder.encoder.dev);
+ dw_hdmi_qp_hpd_notify(hdmi->hdmi);
return 0;
}
--
2.54.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH v7 22/30] drm/rockchip: dw_hdmi_qp: Switch to dw_hdmi_qp_hpd_notify()
@ 2026-06-01 22:44 ` Cristian Ciocaltea
0 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
Switch from drm_helper_hpd_irq_event(), which polls all connectors, to
the recently introduced dw_hdmi_qp_hpd_notify() helper, which runs the
detect cycle only on the affected connector.
This avoids unnecessary work and redundant detect calls on unrelated
connectors.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 12 ++----------
1 file changed, 2 insertions(+), 10 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index b9e0ea56efd8..666631fc9162 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -23,7 +23,6 @@
#include <drm/drm_bridge_connector.h>
#include <drm/drm_managed.h>
#include <drm/drm_of.h>
-#include <drm/drm_probe_helper.h>
#include "rockchip_drm_drv.h"
@@ -273,14 +272,8 @@ static void dw_hdmi_qp_rk3588_hpd_work(struct work_struct *work)
struct rockchip_hdmi_qp *hdmi = container_of(work,
struct rockchip_hdmi_qp,
hpd_work.work);
- struct drm_device *drm = hdmi->encoder.encoder.dev;
- bool changed;
- if (drm) {
- changed = drm_helper_hpd_irq_event(drm);
- if (changed)
- dev_dbg(hdmi->dev, "connector status changed\n");
- }
+ dw_hdmi_qp_hpd_notify(hdmi->hdmi);
}
static irqreturn_t dw_hdmi_qp_rk3576_hardirq(int irq, void *dev_id)
@@ -645,8 +638,7 @@ static int __maybe_unused dw_hdmi_qp_rockchip_resume(struct device *dev)
dw_hdmi_qp_resume(dev, hdmi->hdmi);
- if (hdmi->encoder.encoder.dev)
- drm_helper_hpd_irq_event(hdmi->encoder.encoder.dev);
+ dw_hdmi_qp_hpd_notify(hdmi->hdmi);
return 0;
}
--
2.54.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH v7 23/30] drm/bridge: dw-hdmi-qp: Remove obsolete .setup_hpd() phy op
2026-06-01 22:44 ` Cristian Ciocaltea
@ 2026-06-01 22:44 ` Cristian Ciocaltea
-1 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
With the transition to .{enable|disable}_hpd() phy ops complete in both
the bridge and platform drivers, .setup_hpd() has no remaining callers.
Drop it.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 3 ---
include/drm/bridge/dw_hdmi_qp.h | 1 -
2 files changed, 4 deletions(-)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
index 999229705ffb..3cb06fe43087 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
@@ -1318,9 +1318,6 @@ static void dw_hdmi_qp_init_hw(struct dw_hdmi_qp *hdmi)
/* Clear DONE and ERROR interrupts */
dw_hdmi_qp_write(hdmi, I2CM_OP_DONE_CLEAR | I2CM_NACK_RCVD_CLEAR,
MAINUNIT_1_INT_CLEAR);
-
- if (hdmi->phy.ops->setup_hpd)
- hdmi->phy.ops->setup_hpd(hdmi, hdmi->phy.data);
}
struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev,
diff --git a/include/drm/bridge/dw_hdmi_qp.h b/include/drm/bridge/dw_hdmi_qp.h
index b4fb1c578a5b..ad33f9cafdeb 100644
--- a/include/drm/bridge/dw_hdmi_qp.h
+++ b/include/drm/bridge/dw_hdmi_qp.h
@@ -16,7 +16,6 @@ struct dw_hdmi_qp_phy_ops {
int (*init)(struct dw_hdmi_qp *hdmi, void *data);
void (*disable)(struct dw_hdmi_qp *hdmi, void *data);
enum drm_connector_status (*read_hpd)(struct dw_hdmi_qp *hdmi, void *data);
- void (*setup_hpd)(struct dw_hdmi_qp *hdmi, void *data);
void (*enable_hpd)(struct dw_hdmi_qp *hdmi, void *data);
void (*disable_hpd)(struct dw_hdmi_qp *hdmi, void *data);
};
--
2.54.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH v7 23/30] drm/bridge: dw-hdmi-qp: Remove obsolete .setup_hpd() phy op
@ 2026-06-01 22:44 ` Cristian Ciocaltea
0 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
With the transition to .{enable|disable}_hpd() phy ops complete in both
the bridge and platform drivers, .setup_hpd() has no remaining callers.
Drop it.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 3 ---
include/drm/bridge/dw_hdmi_qp.h | 1 -
2 files changed, 4 deletions(-)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
index 999229705ffb..3cb06fe43087 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
@@ -1318,9 +1318,6 @@ static void dw_hdmi_qp_init_hw(struct dw_hdmi_qp *hdmi)
/* Clear DONE and ERROR interrupts */
dw_hdmi_qp_write(hdmi, I2CM_OP_DONE_CLEAR | I2CM_NACK_RCVD_CLEAR,
MAINUNIT_1_INT_CLEAR);
-
- if (hdmi->phy.ops->setup_hpd)
- hdmi->phy.ops->setup_hpd(hdmi, hdmi->phy.data);
}
struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev,
diff --git a/include/drm/bridge/dw_hdmi_qp.h b/include/drm/bridge/dw_hdmi_qp.h
index b4fb1c578a5b..ad33f9cafdeb 100644
--- a/include/drm/bridge/dw_hdmi_qp.h
+++ b/include/drm/bridge/dw_hdmi_qp.h
@@ -16,7 +16,6 @@ struct dw_hdmi_qp_phy_ops {
int (*init)(struct dw_hdmi_qp *hdmi, void *data);
void (*disable)(struct dw_hdmi_qp *hdmi, void *data);
enum drm_connector_status (*read_hpd)(struct dw_hdmi_qp *hdmi, void *data);
- void (*setup_hpd)(struct dw_hdmi_qp *hdmi, void *data);
void (*enable_hpd)(struct dw_hdmi_qp *hdmi, void *data);
void (*disable_hpd)(struct dw_hdmi_qp *hdmi, void *data);
};
--
2.54.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH v7 24/30] drm/vc4: hdmi: Use common TMDS char rate constants
2026-06-01 22:44 ` Cristian Ciocaltea
@ 2026-06-01 22:44 ` Cristian Ciocaltea
-1 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
Replace HDMI_14_MAX_TMDS_CLK defined locally with
HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ provided by linux/hdmi.h. Note this
incorrectly referenced HDMI 1.4, as the 340 MHz maximum TMDS character
rate was actually introduced in HDMI 1.3.
Similarly, use HDMI_2_0_TMDS_CHAR_RATE_MAX_HZ instead of the 600000000
magic number.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/vc4/vc4_hdmi.c | 17 ++++++++---------
1 file changed, 8 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index 74dce4be0c00..046ac4f43ba8 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -45,6 +45,7 @@
#include <linux/clk.h>
#include <linux/component.h>
#include <linux/gpio/consumer.h>
+#include <linux/hdmi.h>
#include <linux/i2c.h>
#include <linux/of.h>
#include <linux/of_address.h>
@@ -113,8 +114,6 @@
#define HSM_MIN_CLOCK_FREQ 120000000
#define CEC_CLOCK_FREQ 40000
-#define HDMI_14_MAX_TMDS_CLK (340 * 1000 * 1000)
-
static bool vc4_hdmi_supports_scrambling(struct vc4_hdmi *vc4_hdmi)
{
struct drm_display_info *display = &vc4_hdmi->connector.display_info;
@@ -137,7 +136,7 @@ static bool vc4_hdmi_mode_needs_scrambling(const struct drm_display_mode *mode,
{
unsigned long long clock = drm_hdmi_compute_mode_clock(mode, bpc, fmt);
- return clock > HDMI_14_MAX_TMDS_CLK;
+ return clock > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ;
}
static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused)
@@ -1727,7 +1726,7 @@ vc4_hdmi_connector_clock_valid(const struct drm_connector *connector,
if (clock > vc4_hdmi->variant->max_pixel_clock)
return MODE_CLOCK_HIGH;
- if (!vc4->hvs->vc5_hdmi_enable_hdmi_20 && clock > HDMI_14_MAX_TMDS_CLK)
+ if (!vc4->hvs->vc5_hdmi_enable_hdmi_20 && clock > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ)
return MODE_CLOCK_HIGH;
/* 4096x2160@60 is not reliable without overclocking core */
@@ -3253,7 +3252,7 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
* vc4_hdmi_disable_scrambling() will thus run at boot, make
* sure it's disabled, and avoid any inconsistency.
*/
- if (variant->max_pixel_clock > HDMI_14_MAX_TMDS_CLK)
+ if (variant->max_pixel_clock > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ)
vc4_hdmi->scdc_enabled = true;
ret = variant->init_resources(drm, vc4_hdmi);
@@ -3383,7 +3382,7 @@ static const struct vc4_hdmi_variant bcm2711_hdmi0_variant = {
.encoder_type = VC4_ENCODER_TYPE_HDMI0,
.debugfs_name = "hdmi0_regs",
.card_name = "vc4-hdmi-0",
- .max_pixel_clock = 600000000,
+ .max_pixel_clock = HDMI_2_0_TMDS_CHAR_RATE_MAX_HZ,
.registers = vc5_hdmi_hdmi0_fields,
.num_registers = ARRAY_SIZE(vc5_hdmi_hdmi0_fields),
.phy_lane_mapping = {
@@ -3412,7 +3411,7 @@ static const struct vc4_hdmi_variant bcm2711_hdmi1_variant = {
.encoder_type = VC4_ENCODER_TYPE_HDMI1,
.debugfs_name = "hdmi1_regs",
.card_name = "vc4-hdmi-1",
- .max_pixel_clock = HDMI_14_MAX_TMDS_CLK,
+ .max_pixel_clock = HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ,
.registers = vc5_hdmi_hdmi1_fields,
.num_registers = ARRAY_SIZE(vc5_hdmi_hdmi1_fields),
.phy_lane_mapping = {
@@ -3441,7 +3440,7 @@ static const struct vc4_hdmi_variant bcm2712_hdmi0_variant = {
.encoder_type = VC4_ENCODER_TYPE_HDMI0,
.debugfs_name = "hdmi0_regs",
.card_name = "vc4-hdmi-0",
- .max_pixel_clock = 600000000,
+ .max_pixel_clock = HDMI_2_0_TMDS_CHAR_RATE_MAX_HZ,
.registers = vc6_hdmi_hdmi0_fields,
.num_registers = ARRAY_SIZE(vc6_hdmi_hdmi0_fields),
.phy_lane_mapping = {
@@ -3468,7 +3467,7 @@ static const struct vc4_hdmi_variant bcm2712_hdmi1_variant = {
.encoder_type = VC4_ENCODER_TYPE_HDMI1,
.debugfs_name = "hdmi1_regs",
.card_name = "vc4-hdmi-1",
- .max_pixel_clock = 600000000,
+ .max_pixel_clock = HDMI_2_0_TMDS_CHAR_RATE_MAX_HZ,
.registers = vc6_hdmi_hdmi1_fields,
.num_registers = ARRAY_SIZE(vc6_hdmi_hdmi1_fields),
.phy_lane_mapping = {
--
2.54.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH v7 24/30] drm/vc4: hdmi: Use common TMDS char rate constants
@ 2026-06-01 22:44 ` Cristian Ciocaltea
0 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
Replace HDMI_14_MAX_TMDS_CLK defined locally with
HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ provided by linux/hdmi.h. Note this
incorrectly referenced HDMI 1.4, as the 340 MHz maximum TMDS character
rate was actually introduced in HDMI 1.3.
Similarly, use HDMI_2_0_TMDS_CHAR_RATE_MAX_HZ instead of the 600000000
magic number.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/vc4/vc4_hdmi.c | 17 ++++++++---------
1 file changed, 8 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index 74dce4be0c00..046ac4f43ba8 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -45,6 +45,7 @@
#include <linux/clk.h>
#include <linux/component.h>
#include <linux/gpio/consumer.h>
+#include <linux/hdmi.h>
#include <linux/i2c.h>
#include <linux/of.h>
#include <linux/of_address.h>
@@ -113,8 +114,6 @@
#define HSM_MIN_CLOCK_FREQ 120000000
#define CEC_CLOCK_FREQ 40000
-#define HDMI_14_MAX_TMDS_CLK (340 * 1000 * 1000)
-
static bool vc4_hdmi_supports_scrambling(struct vc4_hdmi *vc4_hdmi)
{
struct drm_display_info *display = &vc4_hdmi->connector.display_info;
@@ -137,7 +136,7 @@ static bool vc4_hdmi_mode_needs_scrambling(const struct drm_display_mode *mode,
{
unsigned long long clock = drm_hdmi_compute_mode_clock(mode, bpc, fmt);
- return clock > HDMI_14_MAX_TMDS_CLK;
+ return clock > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ;
}
static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused)
@@ -1727,7 +1726,7 @@ vc4_hdmi_connector_clock_valid(const struct drm_connector *connector,
if (clock > vc4_hdmi->variant->max_pixel_clock)
return MODE_CLOCK_HIGH;
- if (!vc4->hvs->vc5_hdmi_enable_hdmi_20 && clock > HDMI_14_MAX_TMDS_CLK)
+ if (!vc4->hvs->vc5_hdmi_enable_hdmi_20 && clock > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ)
return MODE_CLOCK_HIGH;
/* 4096x2160@60 is not reliable without overclocking core */
@@ -3253,7 +3252,7 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
* vc4_hdmi_disable_scrambling() will thus run at boot, make
* sure it's disabled, and avoid any inconsistency.
*/
- if (variant->max_pixel_clock > HDMI_14_MAX_TMDS_CLK)
+ if (variant->max_pixel_clock > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ)
vc4_hdmi->scdc_enabled = true;
ret = variant->init_resources(drm, vc4_hdmi);
@@ -3383,7 +3382,7 @@ static const struct vc4_hdmi_variant bcm2711_hdmi0_variant = {
.encoder_type = VC4_ENCODER_TYPE_HDMI0,
.debugfs_name = "hdmi0_regs",
.card_name = "vc4-hdmi-0",
- .max_pixel_clock = 600000000,
+ .max_pixel_clock = HDMI_2_0_TMDS_CHAR_RATE_MAX_HZ,
.registers = vc5_hdmi_hdmi0_fields,
.num_registers = ARRAY_SIZE(vc5_hdmi_hdmi0_fields),
.phy_lane_mapping = {
@@ -3412,7 +3411,7 @@ static const struct vc4_hdmi_variant bcm2711_hdmi1_variant = {
.encoder_type = VC4_ENCODER_TYPE_HDMI1,
.debugfs_name = "hdmi1_regs",
.card_name = "vc4-hdmi-1",
- .max_pixel_clock = HDMI_14_MAX_TMDS_CLK,
+ .max_pixel_clock = HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ,
.registers = vc5_hdmi_hdmi1_fields,
.num_registers = ARRAY_SIZE(vc5_hdmi_hdmi1_fields),
.phy_lane_mapping = {
@@ -3441,7 +3440,7 @@ static const struct vc4_hdmi_variant bcm2712_hdmi0_variant = {
.encoder_type = VC4_ENCODER_TYPE_HDMI0,
.debugfs_name = "hdmi0_regs",
.card_name = "vc4-hdmi-0",
- .max_pixel_clock = 600000000,
+ .max_pixel_clock = HDMI_2_0_TMDS_CHAR_RATE_MAX_HZ,
.registers = vc6_hdmi_hdmi0_fields,
.num_registers = ARRAY_SIZE(vc6_hdmi_hdmi0_fields),
.phy_lane_mapping = {
@@ -3468,7 +3467,7 @@ static const struct vc4_hdmi_variant bcm2712_hdmi1_variant = {
.encoder_type = VC4_ENCODER_TYPE_HDMI1,
.debugfs_name = "hdmi1_regs",
.card_name = "vc4-hdmi-1",
- .max_pixel_clock = 600000000,
+ .max_pixel_clock = HDMI_2_0_TMDS_CHAR_RATE_MAX_HZ,
.registers = vc6_hdmi_hdmi1_fields,
.num_registers = ARRAY_SIZE(vc6_hdmi_hdmi1_fields),
.phy_lane_mapping = {
--
2.54.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 72+ messages in thread* Re: [PATCH v7 24/30] drm/vc4: hdmi: Use common TMDS char rate constants
2026-06-01 22:44 ` Cristian Ciocaltea
@ 2026-06-11 15:32 ` Maxime Ripard
-1 siblings, 0 replies; 72+ messages in thread
From: Maxime Ripard @ 2026-06-11 15:32 UTC (permalink / raw)
To: Cristian Ciocaltea
Cc: dri-devel, kernel, linux-arm-kernel, linux-kernel, linux-rockchip,
Andrzej Hajda, Andy Yan, Daniel Stone, Dave Stevenson,
David Airlie, Heiko Stübner, Jernej Skrabec, Jonas Karlman,
Laurent Pinchart, Luca Ceresoli, Maarten Lankhorst, Maxime Ripard,
Maíra Canal, Neil Armstrong, Raspberry Pi Kernel Maintenance,
Robert Foss, Sandy Huang, Simona Vetter, Thomas Zimmermann
On Tue, 2 Jun 2026 01:44:24 +0300, Cristian Ciocaltea wrote:
> Replace HDMI_14_MAX_TMDS_CLK defined locally with
> HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ provided by linux/hdmi.h. Note this
> incorrectly referenced HDMI 1.4, as the 340 MHz maximum TMDS character
> rate was actually introduced in HDMI 1.3.
>
>
> [ ... ]
Acked-by: Maxime Ripard <mripard@kernel.org>
Thanks!
Maxime
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH v7 24/30] drm/vc4: hdmi: Use common TMDS char rate constants
@ 2026-06-11 15:32 ` Maxime Ripard
0 siblings, 0 replies; 72+ messages in thread
From: Maxime Ripard @ 2026-06-11 15:32 UTC (permalink / raw)
To: Cristian Ciocaltea
Cc: dri-devel, kernel, linux-arm-kernel, linux-kernel, linux-rockchip,
Andrzej Hajda, Andy Yan, Daniel Stone, Dave Stevenson,
David Airlie, Heiko Stübner, Jernej Skrabec, Jonas Karlman,
Laurent Pinchart, Luca Ceresoli, Maarten Lankhorst, Maxime Ripard,
Maíra Canal, Neil Armstrong, Raspberry Pi Kernel Maintenance,
Robert Foss, Sandy Huang, Simona Vetter, Thomas Zimmermann
On Tue, 2 Jun 2026 01:44:24 +0300, Cristian Ciocaltea wrote:
> Replace HDMI_14_MAX_TMDS_CLK defined locally with
> HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ provided by linux/hdmi.h. Note this
> incorrectly referenced HDMI 1.4, as the 340 MHz maximum TMDS character
> rate was actually introduced in HDMI 1.3.
>
>
> [ ... ]
Acked-by: Maxime Ripard <mripard@kernel.org>
Thanks!
Maxime
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH v7 24/30] drm/vc4: hdmi: Use common TMDS char rate constants
2026-06-01 22:44 ` Cristian Ciocaltea
@ 2026-06-11 17:14 ` Dave Stevenson
-1 siblings, 0 replies; 72+ messages in thread
From: Dave Stevenson @ 2026-06-11 17:14 UTC (permalink / raw)
To: Cristian Ciocaltea
Cc: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Maíra Canal, Raspberry Pi Kernel Maintenance, kernel,
dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
On Mon, 1 Jun 2026 at 23:45, Cristian Ciocaltea
<cristian.ciocaltea@collabora.com> wrote:
>
> Replace HDMI_14_MAX_TMDS_CLK defined locally with
> HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ provided by linux/hdmi.h. Note this
> incorrectly referenced HDMI 1.4, as the 340 MHz maximum TMDS character
> rate was actually introduced in HDMI 1.3.
>
> Similarly, use HDMI_2_0_TMDS_CHAR_RATE_MAX_HZ instead of the 600000000
> magic number.
>
> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
Reviewed-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
> ---
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH v7 24/30] drm/vc4: hdmi: Use common TMDS char rate constants
@ 2026-06-11 17:14 ` Dave Stevenson
0 siblings, 0 replies; 72+ messages in thread
From: Dave Stevenson @ 2026-06-11 17:14 UTC (permalink / raw)
To: Cristian Ciocaltea
Cc: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Maíra Canal, Raspberry Pi Kernel Maintenance, kernel,
dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
On Mon, 1 Jun 2026 at 23:45, Cristian Ciocaltea
<cristian.ciocaltea@collabora.com> wrote:
>
> Replace HDMI_14_MAX_TMDS_CLK defined locally with
> HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ provided by linux/hdmi.h. Note this
> incorrectly referenced HDMI 1.4, as the 340 MHz maximum TMDS character
> rate was actually introduced in HDMI 1.3.
>
> Similarly, use HDMI_2_0_TMDS_CHAR_RATE_MAX_HZ instead of the 600000000
> magic number.
>
> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
Reviewed-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
> ---
^ permalink raw reply [flat|nested] 72+ messages in thread
* [PATCH v7 25/30] drm/vc4: hdmi: Convert to common HDMI 2.0 SCDC scrambling helpers
2026-06-01 22:44 ` Cristian Ciocaltea
@ 2026-06-01 22:44 ` Cristian Ciocaltea
-1 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
Replace the vc4-local scrambling implementation with the newly
introduced DRM common SCDC scrambling infrastructure:
- Advertise source-side scrambling support by setting
connector->hdmi.scrambling_supported based on the variant's
max_pixel_clock before drmm_connector_hdmi_init().
- Provide minimal .scrambler_{enable|disable} connector callbacks that
only toggle the VC5 HDMI_SCRAMBLER_CTL register. Sink-side SCDC
programming and periodic status monitoring are now delegated to
drm_scdc_{start|stop}_scrambling().
- Replace vc4_hdmi_enable_scrambling() with a conditional call to
drm_scdc_start_scrambling() in post_crtc_enable, gated on
conn_state->hdmi.scrambler_needed (computed by the HDMI state helper).
- Replace vc4_hdmi_disable_scrambling() with drm_scdc_stop_scrambling()
in post_crtc_disable.
- Drop vc4_hdmi_reset_link() and vc4_hdmi_handle_hotplug(), switching
the .detect_ctx() path to
drm_atomic_helper_connector_hdmi_hotplug_ctx() which internally calls
drm_scdc_sync_status() to trigger a CRTC reset on reconnection.
- Drop the local scrambling_work delayed workqueue and scdc_enabled
flag, now tracked by the common drm_connector_hdmi layer.
- Drop vc4_hdmi_supports_scrambling() and
vc4_hdmi_mode_needs_scrambling() helpers, inlining the remaining 4KP60
warning with an explicit drm_hdmi_compute_mode_clock() check.
- Seed connector->hdmi.scrambler_enabled = true in connector_init() to
ensure drm_scdc_stop_scrambling() runs at boot and disables any stale
scrambling state left by the bootloader.
No functional change is expected for the supported modes.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/vc4/vc4_hdmi.c | 265 ++++++-----------------------------------
drivers/gpu/drm/vc4/vc4_hdmi.h | 8 --
2 files changed, 35 insertions(+), 238 deletions(-)
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index 046ac4f43ba8..02f6ca6ab52b 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -114,31 +114,6 @@
#define HSM_MIN_CLOCK_FREQ 120000000
#define CEC_CLOCK_FREQ 40000
-static bool vc4_hdmi_supports_scrambling(struct vc4_hdmi *vc4_hdmi)
-{
- struct drm_display_info *display = &vc4_hdmi->connector.display_info;
-
- lockdep_assert_held(&vc4_hdmi->mutex);
-
- if (!display->is_hdmi)
- return false;
-
- if (!display->hdmi.scdc.supported ||
- !display->hdmi.scdc.scrambling.supported)
- return false;
-
- return true;
-}
-
-static bool vc4_hdmi_mode_needs_scrambling(const struct drm_display_mode *mode,
- unsigned int bpc,
- enum drm_output_color_format fmt)
-{
- unsigned long long clock = drm_hdmi_compute_mode_clock(mode, bpc, fmt);
-
- return clock > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ;
-}
-
static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused)
{
struct drm_debugfs_entry *entry = m->private;
@@ -272,124 +247,6 @@ static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi)
static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi) {}
#endif
-static int vc4_hdmi_reset_link(struct drm_connector *connector,
- struct drm_modeset_acquire_ctx *ctx)
-{
- struct drm_device *drm;
- struct vc4_hdmi *vc4_hdmi;
- struct drm_connector_state *conn_state;
- struct drm_crtc_state *crtc_state;
- struct drm_crtc *crtc;
- bool scrambling_needed;
- u8 config;
- int ret;
-
- if (!connector)
- return 0;
-
- drm = connector->dev;
- ret = drm_modeset_lock(&drm->mode_config.connection_mutex, ctx);
- if (ret)
- return ret;
-
- conn_state = connector->state;
- crtc = conn_state->crtc;
- if (!crtc)
- return 0;
-
- ret = drm_modeset_lock(&crtc->mutex, ctx);
- if (ret)
- return ret;
-
- crtc_state = crtc->state;
- if (!crtc_state->active)
- return 0;
-
- vc4_hdmi = connector_to_vc4_hdmi(connector);
- mutex_lock(&vc4_hdmi->mutex);
-
- if (!vc4_hdmi_supports_scrambling(vc4_hdmi)) {
- mutex_unlock(&vc4_hdmi->mutex);
- return 0;
- }
-
- scrambling_needed = vc4_hdmi_mode_needs_scrambling(&vc4_hdmi->saved_adjusted_mode,
- vc4_hdmi->output_bpc,
- vc4_hdmi->output_format);
- if (!scrambling_needed) {
- mutex_unlock(&vc4_hdmi->mutex);
- return 0;
- }
-
- if (conn_state->commit &&
- !try_wait_for_completion(&conn_state->commit->hw_done)) {
- mutex_unlock(&vc4_hdmi->mutex);
- return 0;
- }
-
- ret = drm_scdc_readb(connector->ddc, SCDC_TMDS_CONFIG, &config);
- if (ret < 0) {
- drm_err(drm, "Failed to read TMDS config: %d\n", ret);
- mutex_unlock(&vc4_hdmi->mutex);
- return 0;
- }
-
- if (!!(config & SCDC_SCRAMBLING_ENABLE) == scrambling_needed) {
- mutex_unlock(&vc4_hdmi->mutex);
- return 0;
- }
-
- mutex_unlock(&vc4_hdmi->mutex);
-
- /*
- * HDMI 2.0 says that one should not send scrambled data
- * prior to configuring the sink scrambling, and that
- * TMDS clock/data transmission should be suspended when
- * changing the TMDS clock rate in the sink. So let's
- * just do a full modeset here, even though some sinks
- * would be perfectly happy if were to just reconfigure
- * the SCDC settings on the fly.
- */
- return drm_atomic_helper_reset_crtc(crtc, ctx);
-}
-
-static void vc4_hdmi_handle_hotplug(struct vc4_hdmi *vc4_hdmi,
- struct drm_modeset_acquire_ctx *ctx,
- enum drm_connector_status status)
-{
- struct drm_connector *connector = &vc4_hdmi->connector;
- int ret;
-
- /*
- * NOTE: This function should really be called with vc4_hdmi->mutex
- * held, but doing so results in reentrancy issues since
- * cec_s_phys_addr() might call .adap_enable, which leads to that
- * funtion being called with our mutex held.
- *
- * A similar situation occurs with vc4_hdmi_reset_link() that
- * will call into our KMS hooks if the scrambling was enabled.
- *
- * Concurrency isn't an issue at the moment since we don't share
- * any state with any of the other frameworks so we can ignore
- * the lock for now.
- */
-
- drm_atomic_helper_connector_hdmi_hotplug(connector, status);
-
- if (status != connector_status_connected)
- return;
-
- for (;;) {
- ret = vc4_hdmi_reset_link(connector, ctx);
- if (ret == -EDEADLK) {
- drm_modeset_backoff(ctx);
- continue;
- }
-
- break;
- }
-}
-
static int vc4_hdmi_connector_detect_ctx(struct drm_connector *connector,
struct drm_modeset_acquire_ctx *ctx,
bool force)
@@ -401,8 +258,8 @@ static int vc4_hdmi_connector_detect_ctx(struct drm_connector *connector,
/*
* NOTE: This function should really take vc4_hdmi->mutex, but
* doing so results in reentrancy issues since
- * vc4_hdmi_handle_hotplug() can call into other functions that
- * would take the mutex while it's held here.
+ * drm_atomic_helper_connector_hdmi_hotplug_ctx() can call into other
+ * functions that would take the mutex while it's held here.
*
* Concurrency isn't an issue at the moment since we don't share
* any state with any of the other frameworks so we can ignore
@@ -425,10 +282,11 @@ static int vc4_hdmi_connector_detect_ctx(struct drm_connector *connector,
status = connector_status_connected;
}
- vc4_hdmi_handle_hotplug(vc4_hdmi, ctx, status);
+ ret = drm_atomic_helper_connector_hdmi_hotplug_ctx(connector, status, ctx);
+
pm_runtime_put(&vc4_hdmi->pdev->dev);
- return status;
+ return ret == -EDEADLK ? ret : status;
}
static int vc4_hdmi_connector_get_modes(struct drm_connector *connector)
@@ -441,9 +299,12 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector)
if (!vc4->hvs->vc5_hdmi_enable_hdmi_20) {
struct drm_device *drm = connector->dev;
const struct drm_display_mode *mode;
+ unsigned long long clock;
list_for_each_entry(mode, &connector->probed_modes, head) {
- if (vc4_hdmi_mode_needs_scrambling(mode, 8, DRM_OUTPUT_COLOR_FORMAT_RGB444)) {
+ clock = drm_hdmi_compute_mode_clock(mode, 8,
+ DRM_OUTPUT_COLOR_FORMAT_RGB444);
+ if (clock > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ) {
drm_warn_once(drm, "The core clock cannot reach frequencies high enough to support 4k @ 60Hz.");
drm_warn_once(drm, "Please change your config.txt file to add hdmi_enable_4kp60.");
}
@@ -540,6 +401,9 @@ static int vc4_hdmi_connector_init(struct drm_device *dev,
if (vc4_hdmi->variant->supports_hdr)
max_bpc = 12;
+ connector->hdmi.scrambler_supported =
+ vc4_hdmi->variant->max_pixel_clock > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ;
+
ret = drmm_connector_hdmi_init(dev, connector,
"Broadcom", "Videocore",
&vc4_hdmi_connector_funcs,
@@ -561,6 +425,14 @@ static int vc4_hdmi_connector_init(struct drm_device *dev,
drm_connector_helper_add(connector, &vc4_hdmi_connector_helper_funcs);
+ /*
+ * Since we don't know the state of the controller and its
+ * display (if any), let's assume it's always enabled.
+ * drm_scdc_stop_scrambling() will thus run at boot, make
+ * sure it's disabled, and avoid any inconsistency.
+ */
+ connector->hdmi.scrambler_enabled = connector->hdmi.scrambler_supported;
+
/*
* Some of the properties below require access to state, like bpc.
* Allocate some default initial connector state with our reset helper.
@@ -786,93 +658,30 @@ static int vc4_hdmi_write_spd_infoframe(struct drm_connector *connector,
buffer, len);
}
-#define SCRAMBLING_POLLING_DELAY_MS 1000
-
-static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder)
+static int vc4_hdmi_scrambler_enable(struct drm_connector *connector)
{
- struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
- struct drm_connector *connector = &vc4_hdmi->connector;
- struct drm_device *drm = connector->dev;
- const struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode;
+ struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
unsigned long flags;
- int idx;
-
- lockdep_assert_held(&vc4_hdmi->mutex);
-
- if (!vc4_hdmi_supports_scrambling(vc4_hdmi))
- return;
-
- if (!vc4_hdmi_mode_needs_scrambling(mode,
- vc4_hdmi->output_bpc,
- vc4_hdmi->output_format))
- return;
-
- 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);
spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
- drm_dev_exit(idx);
-
- vc4_hdmi->scdc_enabled = true;
-
- queue_delayed_work(system_percpu_wq, &vc4_hdmi->scrambling_work,
- msecs_to_jiffies(SCRAMBLING_POLLING_DELAY_MS));
+ return 0;
}
-static void vc4_hdmi_disable_scrambling(struct drm_encoder *encoder)
+static int vc4_hdmi_scrambler_disable(struct drm_connector *connector)
{
- struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
- struct drm_connector *connector = &vc4_hdmi->connector;
- struct drm_device *drm = connector->dev;
+ struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
unsigned long flags;
- int idx;
-
- lockdep_assert_held(&vc4_hdmi->mutex);
-
- if (!vc4_hdmi->scdc_enabled)
- return;
-
- vc4_hdmi->scdc_enabled = false;
-
- if (delayed_work_pending(&vc4_hdmi->scrambling_work))
- cancel_delayed_work_sync(&vc4_hdmi->scrambling_work);
-
- if (!drm_dev_enter(drm, &idx))
- return;
spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
HDMI_WRITE(HDMI_SCRAMBLER_CTL, HDMI_READ(HDMI_SCRAMBLER_CTL) &
~VC5_HDMI_SCRAMBLER_CTL_ENABLE);
spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
- drm_scdc_set_scrambling(connector, false);
- drm_scdc_set_high_tmds_clock_ratio(connector, false);
-
- drm_dev_exit(idx);
-}
-
-static void vc4_hdmi_scrambling_wq(struct work_struct *work)
-{
- struct vc4_hdmi *vc4_hdmi = container_of(to_delayed_work(work),
- struct vc4_hdmi,
- scrambling_work);
- struct drm_connector *connector = &vc4_hdmi->connector;
-
- 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));
+ return 0;
}
static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder,
@@ -917,7 +726,7 @@ 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_scdc_stop_scrambling(&vc4_hdmi->connector);
drm_dev_exit(idx);
@@ -1625,6 +1434,7 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder,
struct drm_display_info *display = &vc4_hdmi->connector.display_info;
bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC;
bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC;
+ struct drm_connector_state *conn_state;
unsigned long flags;
int ret;
int idx;
@@ -1693,7 +1503,10 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder,
}
vc4_hdmi_recenter_fifo(vc4_hdmi);
- vc4_hdmi_enable_scrambling(encoder);
+
+ conn_state = drm_atomic_get_new_connector_state(state, connector);
+ if (conn_state && conn_state->hdmi.scrambler_needed)
+ drm_scdc_start_scrambling(connector);
drm_dev_exit(idx);
@@ -1739,7 +1552,9 @@ vc4_hdmi_connector_clock_valid(const struct drm_connector *connector,
}
static const struct drm_connector_hdmi_funcs vc4_hdmi_hdmi_connector_funcs = {
- .tmds_char_rate_valid = vc4_hdmi_connector_clock_valid,
+ .tmds_char_rate_valid = vc4_hdmi_connector_clock_valid,
+ .scrambler_enable = vc4_hdmi_scrambler_enable,
+ .scrambler_disable = vc4_hdmi_scrambler_disable,
.avi = {
.clear_infoframe = vc4_hdmi_clear_avi_infoframe,
.write_infoframe = vc4_hdmi_write_avi_infoframe,
@@ -3233,7 +3048,6 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
return ret;
spin_lock_init(&vc4_hdmi->hw_lock);
- INIT_DELAYED_WORK(&vc4_hdmi->scrambling_work, vc4_hdmi_scrambling_wq);
dev_set_drvdata(dev, vc4_hdmi);
encoder = &vc4_hdmi->encoder.base;
@@ -3246,15 +3060,6 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
vc4_hdmi->pdev = pdev;
vc4_hdmi->variant = variant;
- /*
- * Since we don't know the state of the controller and its
- * display (if any), let's assume it's always enabled.
- * vc4_hdmi_disable_scrambling() will thus run at boot, make
- * sure it's disabled, and avoid any inconsistency.
- */
- if (variant->max_pixel_clock > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ)
- vc4_hdmi->scdc_enabled = true;
-
ret = variant->init_resources(drm, vc4_hdmi);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h
index 29d461d4ee49..58c92ebc2677 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.h
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.h
@@ -118,8 +118,6 @@ struct vc4_hdmi {
struct vc4_encoder encoder;
struct drm_connector connector;
- struct delayed_work scrambling_work;
-
struct i2c_adapter *ddc;
void __iomem *hdmicore_regs;
void __iomem *hd_regs;
@@ -193,12 +191,6 @@ struct vc4_hdmi {
*/
bool packet_ram_enabled;
- /**
- * @scdc_enabled: Is the HDMI controller currently running with
- * the scrambler on? Protected by @mutex.
- */
- bool scdc_enabled;
-
/**
* @output_bpc: Copy of @drm_connector_state.hdmi.output_bpc for
* use outside of KMS hooks. Protected by @mutex.
--
2.54.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH v7 25/30] drm/vc4: hdmi: Convert to common HDMI 2.0 SCDC scrambling helpers
@ 2026-06-01 22:44 ` Cristian Ciocaltea
0 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
Replace the vc4-local scrambling implementation with the newly
introduced DRM common SCDC scrambling infrastructure:
- Advertise source-side scrambling support by setting
connector->hdmi.scrambling_supported based on the variant's
max_pixel_clock before drmm_connector_hdmi_init().
- Provide minimal .scrambler_{enable|disable} connector callbacks that
only toggle the VC5 HDMI_SCRAMBLER_CTL register. Sink-side SCDC
programming and periodic status monitoring are now delegated to
drm_scdc_{start|stop}_scrambling().
- Replace vc4_hdmi_enable_scrambling() with a conditional call to
drm_scdc_start_scrambling() in post_crtc_enable, gated on
conn_state->hdmi.scrambler_needed (computed by the HDMI state helper).
- Replace vc4_hdmi_disable_scrambling() with drm_scdc_stop_scrambling()
in post_crtc_disable.
- Drop vc4_hdmi_reset_link() and vc4_hdmi_handle_hotplug(), switching
the .detect_ctx() path to
drm_atomic_helper_connector_hdmi_hotplug_ctx() which internally calls
drm_scdc_sync_status() to trigger a CRTC reset on reconnection.
- Drop the local scrambling_work delayed workqueue and scdc_enabled
flag, now tracked by the common drm_connector_hdmi layer.
- Drop vc4_hdmi_supports_scrambling() and
vc4_hdmi_mode_needs_scrambling() helpers, inlining the remaining 4KP60
warning with an explicit drm_hdmi_compute_mode_clock() check.
- Seed connector->hdmi.scrambler_enabled = true in connector_init() to
ensure drm_scdc_stop_scrambling() runs at boot and disables any stale
scrambling state left by the bootloader.
No functional change is expected for the supported modes.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/vc4/vc4_hdmi.c | 265 ++++++-----------------------------------
drivers/gpu/drm/vc4/vc4_hdmi.h | 8 --
2 files changed, 35 insertions(+), 238 deletions(-)
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index 046ac4f43ba8..02f6ca6ab52b 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -114,31 +114,6 @@
#define HSM_MIN_CLOCK_FREQ 120000000
#define CEC_CLOCK_FREQ 40000
-static bool vc4_hdmi_supports_scrambling(struct vc4_hdmi *vc4_hdmi)
-{
- struct drm_display_info *display = &vc4_hdmi->connector.display_info;
-
- lockdep_assert_held(&vc4_hdmi->mutex);
-
- if (!display->is_hdmi)
- return false;
-
- if (!display->hdmi.scdc.supported ||
- !display->hdmi.scdc.scrambling.supported)
- return false;
-
- return true;
-}
-
-static bool vc4_hdmi_mode_needs_scrambling(const struct drm_display_mode *mode,
- unsigned int bpc,
- enum drm_output_color_format fmt)
-{
- unsigned long long clock = drm_hdmi_compute_mode_clock(mode, bpc, fmt);
-
- return clock > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ;
-}
-
static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused)
{
struct drm_debugfs_entry *entry = m->private;
@@ -272,124 +247,6 @@ static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi)
static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi) {}
#endif
-static int vc4_hdmi_reset_link(struct drm_connector *connector,
- struct drm_modeset_acquire_ctx *ctx)
-{
- struct drm_device *drm;
- struct vc4_hdmi *vc4_hdmi;
- struct drm_connector_state *conn_state;
- struct drm_crtc_state *crtc_state;
- struct drm_crtc *crtc;
- bool scrambling_needed;
- u8 config;
- int ret;
-
- if (!connector)
- return 0;
-
- drm = connector->dev;
- ret = drm_modeset_lock(&drm->mode_config.connection_mutex, ctx);
- if (ret)
- return ret;
-
- conn_state = connector->state;
- crtc = conn_state->crtc;
- if (!crtc)
- return 0;
-
- ret = drm_modeset_lock(&crtc->mutex, ctx);
- if (ret)
- return ret;
-
- crtc_state = crtc->state;
- if (!crtc_state->active)
- return 0;
-
- vc4_hdmi = connector_to_vc4_hdmi(connector);
- mutex_lock(&vc4_hdmi->mutex);
-
- if (!vc4_hdmi_supports_scrambling(vc4_hdmi)) {
- mutex_unlock(&vc4_hdmi->mutex);
- return 0;
- }
-
- scrambling_needed = vc4_hdmi_mode_needs_scrambling(&vc4_hdmi->saved_adjusted_mode,
- vc4_hdmi->output_bpc,
- vc4_hdmi->output_format);
- if (!scrambling_needed) {
- mutex_unlock(&vc4_hdmi->mutex);
- return 0;
- }
-
- if (conn_state->commit &&
- !try_wait_for_completion(&conn_state->commit->hw_done)) {
- mutex_unlock(&vc4_hdmi->mutex);
- return 0;
- }
-
- ret = drm_scdc_readb(connector->ddc, SCDC_TMDS_CONFIG, &config);
- if (ret < 0) {
- drm_err(drm, "Failed to read TMDS config: %d\n", ret);
- mutex_unlock(&vc4_hdmi->mutex);
- return 0;
- }
-
- if (!!(config & SCDC_SCRAMBLING_ENABLE) == scrambling_needed) {
- mutex_unlock(&vc4_hdmi->mutex);
- return 0;
- }
-
- mutex_unlock(&vc4_hdmi->mutex);
-
- /*
- * HDMI 2.0 says that one should not send scrambled data
- * prior to configuring the sink scrambling, and that
- * TMDS clock/data transmission should be suspended when
- * changing the TMDS clock rate in the sink. So let's
- * just do a full modeset here, even though some sinks
- * would be perfectly happy if were to just reconfigure
- * the SCDC settings on the fly.
- */
- return drm_atomic_helper_reset_crtc(crtc, ctx);
-}
-
-static void vc4_hdmi_handle_hotplug(struct vc4_hdmi *vc4_hdmi,
- struct drm_modeset_acquire_ctx *ctx,
- enum drm_connector_status status)
-{
- struct drm_connector *connector = &vc4_hdmi->connector;
- int ret;
-
- /*
- * NOTE: This function should really be called with vc4_hdmi->mutex
- * held, but doing so results in reentrancy issues since
- * cec_s_phys_addr() might call .adap_enable, which leads to that
- * funtion being called with our mutex held.
- *
- * A similar situation occurs with vc4_hdmi_reset_link() that
- * will call into our KMS hooks if the scrambling was enabled.
- *
- * Concurrency isn't an issue at the moment since we don't share
- * any state with any of the other frameworks so we can ignore
- * the lock for now.
- */
-
- drm_atomic_helper_connector_hdmi_hotplug(connector, status);
-
- if (status != connector_status_connected)
- return;
-
- for (;;) {
- ret = vc4_hdmi_reset_link(connector, ctx);
- if (ret == -EDEADLK) {
- drm_modeset_backoff(ctx);
- continue;
- }
-
- break;
- }
-}
-
static int vc4_hdmi_connector_detect_ctx(struct drm_connector *connector,
struct drm_modeset_acquire_ctx *ctx,
bool force)
@@ -401,8 +258,8 @@ static int vc4_hdmi_connector_detect_ctx(struct drm_connector *connector,
/*
* NOTE: This function should really take vc4_hdmi->mutex, but
* doing so results in reentrancy issues since
- * vc4_hdmi_handle_hotplug() can call into other functions that
- * would take the mutex while it's held here.
+ * drm_atomic_helper_connector_hdmi_hotplug_ctx() can call into other
+ * functions that would take the mutex while it's held here.
*
* Concurrency isn't an issue at the moment since we don't share
* any state with any of the other frameworks so we can ignore
@@ -425,10 +282,11 @@ static int vc4_hdmi_connector_detect_ctx(struct drm_connector *connector,
status = connector_status_connected;
}
- vc4_hdmi_handle_hotplug(vc4_hdmi, ctx, status);
+ ret = drm_atomic_helper_connector_hdmi_hotplug_ctx(connector, status, ctx);
+
pm_runtime_put(&vc4_hdmi->pdev->dev);
- return status;
+ return ret == -EDEADLK ? ret : status;
}
static int vc4_hdmi_connector_get_modes(struct drm_connector *connector)
@@ -441,9 +299,12 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector)
if (!vc4->hvs->vc5_hdmi_enable_hdmi_20) {
struct drm_device *drm = connector->dev;
const struct drm_display_mode *mode;
+ unsigned long long clock;
list_for_each_entry(mode, &connector->probed_modes, head) {
- if (vc4_hdmi_mode_needs_scrambling(mode, 8, DRM_OUTPUT_COLOR_FORMAT_RGB444)) {
+ clock = drm_hdmi_compute_mode_clock(mode, 8,
+ DRM_OUTPUT_COLOR_FORMAT_RGB444);
+ if (clock > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ) {
drm_warn_once(drm, "The core clock cannot reach frequencies high enough to support 4k @ 60Hz.");
drm_warn_once(drm, "Please change your config.txt file to add hdmi_enable_4kp60.");
}
@@ -540,6 +401,9 @@ static int vc4_hdmi_connector_init(struct drm_device *dev,
if (vc4_hdmi->variant->supports_hdr)
max_bpc = 12;
+ connector->hdmi.scrambler_supported =
+ vc4_hdmi->variant->max_pixel_clock > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ;
+
ret = drmm_connector_hdmi_init(dev, connector,
"Broadcom", "Videocore",
&vc4_hdmi_connector_funcs,
@@ -561,6 +425,14 @@ static int vc4_hdmi_connector_init(struct drm_device *dev,
drm_connector_helper_add(connector, &vc4_hdmi_connector_helper_funcs);
+ /*
+ * Since we don't know the state of the controller and its
+ * display (if any), let's assume it's always enabled.
+ * drm_scdc_stop_scrambling() will thus run at boot, make
+ * sure it's disabled, and avoid any inconsistency.
+ */
+ connector->hdmi.scrambler_enabled = connector->hdmi.scrambler_supported;
+
/*
* Some of the properties below require access to state, like bpc.
* Allocate some default initial connector state with our reset helper.
@@ -786,93 +658,30 @@ static int vc4_hdmi_write_spd_infoframe(struct drm_connector *connector,
buffer, len);
}
-#define SCRAMBLING_POLLING_DELAY_MS 1000
-
-static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder)
+static int vc4_hdmi_scrambler_enable(struct drm_connector *connector)
{
- struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
- struct drm_connector *connector = &vc4_hdmi->connector;
- struct drm_device *drm = connector->dev;
- const struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode;
+ struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
unsigned long flags;
- int idx;
-
- lockdep_assert_held(&vc4_hdmi->mutex);
-
- if (!vc4_hdmi_supports_scrambling(vc4_hdmi))
- return;
-
- if (!vc4_hdmi_mode_needs_scrambling(mode,
- vc4_hdmi->output_bpc,
- vc4_hdmi->output_format))
- return;
-
- 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);
spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
- drm_dev_exit(idx);
-
- vc4_hdmi->scdc_enabled = true;
-
- queue_delayed_work(system_percpu_wq, &vc4_hdmi->scrambling_work,
- msecs_to_jiffies(SCRAMBLING_POLLING_DELAY_MS));
+ return 0;
}
-static void vc4_hdmi_disable_scrambling(struct drm_encoder *encoder)
+static int vc4_hdmi_scrambler_disable(struct drm_connector *connector)
{
- struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
- struct drm_connector *connector = &vc4_hdmi->connector;
- struct drm_device *drm = connector->dev;
+ struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
unsigned long flags;
- int idx;
-
- lockdep_assert_held(&vc4_hdmi->mutex);
-
- if (!vc4_hdmi->scdc_enabled)
- return;
-
- vc4_hdmi->scdc_enabled = false;
-
- if (delayed_work_pending(&vc4_hdmi->scrambling_work))
- cancel_delayed_work_sync(&vc4_hdmi->scrambling_work);
-
- if (!drm_dev_enter(drm, &idx))
- return;
spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
HDMI_WRITE(HDMI_SCRAMBLER_CTL, HDMI_READ(HDMI_SCRAMBLER_CTL) &
~VC5_HDMI_SCRAMBLER_CTL_ENABLE);
spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
- drm_scdc_set_scrambling(connector, false);
- drm_scdc_set_high_tmds_clock_ratio(connector, false);
-
- drm_dev_exit(idx);
-}
-
-static void vc4_hdmi_scrambling_wq(struct work_struct *work)
-{
- struct vc4_hdmi *vc4_hdmi = container_of(to_delayed_work(work),
- struct vc4_hdmi,
- scrambling_work);
- struct drm_connector *connector = &vc4_hdmi->connector;
-
- 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));
+ return 0;
}
static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder,
@@ -917,7 +726,7 @@ 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_scdc_stop_scrambling(&vc4_hdmi->connector);
drm_dev_exit(idx);
@@ -1625,6 +1434,7 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder,
struct drm_display_info *display = &vc4_hdmi->connector.display_info;
bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC;
bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC;
+ struct drm_connector_state *conn_state;
unsigned long flags;
int ret;
int idx;
@@ -1693,7 +1503,10 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder,
}
vc4_hdmi_recenter_fifo(vc4_hdmi);
- vc4_hdmi_enable_scrambling(encoder);
+
+ conn_state = drm_atomic_get_new_connector_state(state, connector);
+ if (conn_state && conn_state->hdmi.scrambler_needed)
+ drm_scdc_start_scrambling(connector);
drm_dev_exit(idx);
@@ -1739,7 +1552,9 @@ vc4_hdmi_connector_clock_valid(const struct drm_connector *connector,
}
static const struct drm_connector_hdmi_funcs vc4_hdmi_hdmi_connector_funcs = {
- .tmds_char_rate_valid = vc4_hdmi_connector_clock_valid,
+ .tmds_char_rate_valid = vc4_hdmi_connector_clock_valid,
+ .scrambler_enable = vc4_hdmi_scrambler_enable,
+ .scrambler_disable = vc4_hdmi_scrambler_disable,
.avi = {
.clear_infoframe = vc4_hdmi_clear_avi_infoframe,
.write_infoframe = vc4_hdmi_write_avi_infoframe,
@@ -3233,7 +3048,6 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
return ret;
spin_lock_init(&vc4_hdmi->hw_lock);
- INIT_DELAYED_WORK(&vc4_hdmi->scrambling_work, vc4_hdmi_scrambling_wq);
dev_set_drvdata(dev, vc4_hdmi);
encoder = &vc4_hdmi->encoder.base;
@@ -3246,15 +3060,6 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
vc4_hdmi->pdev = pdev;
vc4_hdmi->variant = variant;
- /*
- * Since we don't know the state of the controller and its
- * display (if any), let's assume it's always enabled.
- * vc4_hdmi_disable_scrambling() will thus run at boot, make
- * sure it's disabled, and avoid any inconsistency.
- */
- if (variant->max_pixel_clock > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ)
- vc4_hdmi->scdc_enabled = true;
-
ret = variant->init_resources(drm, vc4_hdmi);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h
index 29d461d4ee49..58c92ebc2677 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.h
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.h
@@ -118,8 +118,6 @@ struct vc4_hdmi {
struct vc4_encoder encoder;
struct drm_connector connector;
- struct delayed_work scrambling_work;
-
struct i2c_adapter *ddc;
void __iomem *hdmicore_regs;
void __iomem *hd_regs;
@@ -193,12 +191,6 @@ struct vc4_hdmi {
*/
bool packet_ram_enabled;
- /**
- * @scdc_enabled: Is the HDMI controller currently running with
- * the scrambler on? Protected by @mutex.
- */
- bool scdc_enabled;
-
/**
* @output_bpc: Copy of @drm_connector_state.hdmi.output_bpc for
* use outside of KMS hooks. Protected by @mutex.
--
2.54.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH v7 26/30] drm/tests: connector: Add HDMI source-side scrambler capability tests
2026-06-01 22:44 ` Cristian Ciocaltea
@ 2026-06-01 22:44 ` Cristian Ciocaltea
-1 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
Add KUnit tests covering the consistency validation between HDMI
connector's scrambler_supported flag and the .scrambler_{enable,disable}
HDMI connector callbacks that drmm_connector_hdmi_init() performs.
The four added cases cover the validation matrix:
- scrambler_supported = true with both callbacks set: success
- scrambler_supported = true with no callbacks: failure
- scrambler_supported = true with only one callback: failure
- scrambler_supported = false with both callbacks: success (callbacks
ignored)
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/tests/drm_connector_test.c | 132 +++++++++++++++++++++++++++++
1 file changed, 132 insertions(+)
diff --git a/drivers/gpu/drm/tests/drm_connector_test.c b/drivers/gpu/drm/tests/drm_connector_test.c
index beb1d50a6646..b79b75be18c4 100644
--- a/drivers/gpu/drm/tests/drm_connector_test.c
+++ b/drivers/gpu/drm/tests/drm_connector_test.c
@@ -47,6 +47,41 @@ static const struct drm_connector_hdmi_funcs dummy_hdmi_funcs = {
},
};
+static int accept_scrambler_enable(struct drm_connector *connector)
+{
+ return 0;
+}
+
+static int accept_scrambler_disable(struct drm_connector *connector)
+{
+ return 0;
+}
+
+static const struct drm_connector_hdmi_funcs dummy_hdmi_funcs_scrambler = {
+ .scrambler_enable = accept_scrambler_enable,
+ .scrambler_disable = accept_scrambler_disable,
+ .avi = {
+ .clear_infoframe = accept_infoframe_clear_infoframe,
+ .write_infoframe = accept_infoframe_write_infoframe,
+ },
+ .hdmi = {
+ .clear_infoframe = accept_infoframe_clear_infoframe,
+ .write_infoframe = accept_infoframe_write_infoframe,
+ },
+};
+
+static const struct drm_connector_hdmi_funcs dummy_hdmi_funcs_scrambler_partial = {
+ .scrambler_enable = accept_scrambler_enable,
+ .avi = {
+ .clear_infoframe = accept_infoframe_clear_infoframe,
+ .write_infoframe = accept_infoframe_write_infoframe,
+ },
+ .hdmi = {
+ .clear_infoframe = accept_infoframe_clear_infoframe,
+ .write_infoframe = accept_infoframe_write_infoframe,
+ },
+};
+
static const struct drm_connector_funcs dummy_funcs = {
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
@@ -1254,6 +1289,99 @@ KUNIT_ARRAY_PARAM(drm_connector_hdmi_init_type_invalid,
drm_connector_hdmi_init_type_invalid_tests,
drm_connector_hdmi_init_type_desc);
+/*
+ * Test that the registration of an HDMI connector advertising source-side
+ * scrambling support succeeds when the .scrambler_{enable|disable} callbacks
+ * are provided.
+ */
+static void drm_test_connector_hdmi_init_scrambler_valid(struct kunit *test)
+{
+ struct drm_connector_init_priv *priv = test->priv;
+ int ret;
+
+ priv->connector.hdmi.scrambler_supported = true;
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ "Vendor", "Product",
+ &dummy_funcs,
+ &dummy_hdmi_funcs_scrambler,
+ DRM_MODE_CONNECTOR_HDMIA,
+ &priv->ddc,
+ BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ 8);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+}
+
+/*
+ * Test that the registration of an HDMI connector advertising source-side
+ * scrambling support fails when the .scrambler_{enable|disable} callbacks
+ * are not provided.
+ */
+static void drm_test_connector_hdmi_init_scrambler_no_callbacks(struct kunit *test)
+{
+ struct drm_connector_init_priv *priv = test->priv;
+ int ret;
+
+ priv->connector.hdmi.scrambler_supported = true;
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ "Vendor", "Product",
+ &dummy_funcs,
+ &dummy_hdmi_funcs,
+ DRM_MODE_CONNECTOR_HDMIA,
+ &priv->ddc,
+ BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ 8);
+ KUNIT_EXPECT_LT(test, ret, 0);
+}
+
+/*
+ * Test that the registration of an HDMI connector advertising source-side
+ * scrambling support fails when only one of the .scrambler_{enable|disable}
+ * callbacks are provided.
+ */
+static void drm_test_connector_hdmi_init_scrambler_partial_callbacks(struct kunit *test)
+{
+ struct drm_connector_init_priv *priv = test->priv;
+ int ret;
+
+ priv->connector.hdmi.scrambler_supported = true;
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ "Vendor", "Product",
+ &dummy_funcs,
+ &dummy_hdmi_funcs_scrambler_partial,
+ DRM_MODE_CONNECTOR_HDMIA,
+ &priv->ddc,
+ BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ 8);
+ KUNIT_EXPECT_LT(test, ret, 0);
+}
+
+/*
+ * Test that the registration of an HDMI connector not advertising source-side
+ * scrambling support succeeds, even when the .scrambler_{enable|disable}
+ * callbacks are provided, i.e. they are ignored.
+ */
+static void drm_test_connector_hdmi_init_scrambler_ignored_callbacks(struct kunit *test)
+{
+ struct drm_connector_init_priv *priv = test->priv;
+ int ret;
+
+ priv->connector.hdmi.scrambler_supported = false;
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ "Vendor", "Product",
+ &dummy_funcs,
+ &dummy_hdmi_funcs_scrambler,
+ DRM_MODE_CONNECTOR_HDMIA,
+ &priv->ddc,
+ BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ 8);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+ KUNIT_EXPECT_EQ(test, priv->connector.hdmi.scrambler_supported, false);
+}
+
static struct kunit_case drmm_connector_hdmi_init_tests[] = {
KUNIT_CASE(drm_test_connector_hdmi_init_valid),
KUNIT_CASE(drm_test_connector_hdmi_init_bpc_8),
@@ -1278,6 +1406,10 @@ static struct kunit_case drmm_connector_hdmi_init_tests[] = {
drm_connector_hdmi_init_type_valid_gen_params),
KUNIT_CASE_PARAM(drm_test_connector_hdmi_init_type_invalid,
drm_connector_hdmi_init_type_invalid_gen_params),
+ KUNIT_CASE(drm_test_connector_hdmi_init_scrambler_valid),
+ KUNIT_CASE(drm_test_connector_hdmi_init_scrambler_no_callbacks),
+ KUNIT_CASE(drm_test_connector_hdmi_init_scrambler_partial_callbacks),
+ KUNIT_CASE(drm_test_connector_hdmi_init_scrambler_ignored_callbacks),
{ }
};
--
2.54.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH v7 26/30] drm/tests: connector: Add HDMI source-side scrambler capability tests
@ 2026-06-01 22:44 ` Cristian Ciocaltea
0 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
Add KUnit tests covering the consistency validation between HDMI
connector's scrambler_supported flag and the .scrambler_{enable,disable}
HDMI connector callbacks that drmm_connector_hdmi_init() performs.
The four added cases cover the validation matrix:
- scrambler_supported = true with both callbacks set: success
- scrambler_supported = true with no callbacks: failure
- scrambler_supported = true with only one callback: failure
- scrambler_supported = false with both callbacks: success (callbacks
ignored)
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/tests/drm_connector_test.c | 132 +++++++++++++++++++++++++++++
1 file changed, 132 insertions(+)
diff --git a/drivers/gpu/drm/tests/drm_connector_test.c b/drivers/gpu/drm/tests/drm_connector_test.c
index beb1d50a6646..b79b75be18c4 100644
--- a/drivers/gpu/drm/tests/drm_connector_test.c
+++ b/drivers/gpu/drm/tests/drm_connector_test.c
@@ -47,6 +47,41 @@ static const struct drm_connector_hdmi_funcs dummy_hdmi_funcs = {
},
};
+static int accept_scrambler_enable(struct drm_connector *connector)
+{
+ return 0;
+}
+
+static int accept_scrambler_disable(struct drm_connector *connector)
+{
+ return 0;
+}
+
+static const struct drm_connector_hdmi_funcs dummy_hdmi_funcs_scrambler = {
+ .scrambler_enable = accept_scrambler_enable,
+ .scrambler_disable = accept_scrambler_disable,
+ .avi = {
+ .clear_infoframe = accept_infoframe_clear_infoframe,
+ .write_infoframe = accept_infoframe_write_infoframe,
+ },
+ .hdmi = {
+ .clear_infoframe = accept_infoframe_clear_infoframe,
+ .write_infoframe = accept_infoframe_write_infoframe,
+ },
+};
+
+static const struct drm_connector_hdmi_funcs dummy_hdmi_funcs_scrambler_partial = {
+ .scrambler_enable = accept_scrambler_enable,
+ .avi = {
+ .clear_infoframe = accept_infoframe_clear_infoframe,
+ .write_infoframe = accept_infoframe_write_infoframe,
+ },
+ .hdmi = {
+ .clear_infoframe = accept_infoframe_clear_infoframe,
+ .write_infoframe = accept_infoframe_write_infoframe,
+ },
+};
+
static const struct drm_connector_funcs dummy_funcs = {
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
@@ -1254,6 +1289,99 @@ KUNIT_ARRAY_PARAM(drm_connector_hdmi_init_type_invalid,
drm_connector_hdmi_init_type_invalid_tests,
drm_connector_hdmi_init_type_desc);
+/*
+ * Test that the registration of an HDMI connector advertising source-side
+ * scrambling support succeeds when the .scrambler_{enable|disable} callbacks
+ * are provided.
+ */
+static void drm_test_connector_hdmi_init_scrambler_valid(struct kunit *test)
+{
+ struct drm_connector_init_priv *priv = test->priv;
+ int ret;
+
+ priv->connector.hdmi.scrambler_supported = true;
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ "Vendor", "Product",
+ &dummy_funcs,
+ &dummy_hdmi_funcs_scrambler,
+ DRM_MODE_CONNECTOR_HDMIA,
+ &priv->ddc,
+ BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ 8);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+}
+
+/*
+ * Test that the registration of an HDMI connector advertising source-side
+ * scrambling support fails when the .scrambler_{enable|disable} callbacks
+ * are not provided.
+ */
+static void drm_test_connector_hdmi_init_scrambler_no_callbacks(struct kunit *test)
+{
+ struct drm_connector_init_priv *priv = test->priv;
+ int ret;
+
+ priv->connector.hdmi.scrambler_supported = true;
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ "Vendor", "Product",
+ &dummy_funcs,
+ &dummy_hdmi_funcs,
+ DRM_MODE_CONNECTOR_HDMIA,
+ &priv->ddc,
+ BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ 8);
+ KUNIT_EXPECT_LT(test, ret, 0);
+}
+
+/*
+ * Test that the registration of an HDMI connector advertising source-side
+ * scrambling support fails when only one of the .scrambler_{enable|disable}
+ * callbacks are provided.
+ */
+static void drm_test_connector_hdmi_init_scrambler_partial_callbacks(struct kunit *test)
+{
+ struct drm_connector_init_priv *priv = test->priv;
+ int ret;
+
+ priv->connector.hdmi.scrambler_supported = true;
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ "Vendor", "Product",
+ &dummy_funcs,
+ &dummy_hdmi_funcs_scrambler_partial,
+ DRM_MODE_CONNECTOR_HDMIA,
+ &priv->ddc,
+ BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ 8);
+ KUNIT_EXPECT_LT(test, ret, 0);
+}
+
+/*
+ * Test that the registration of an HDMI connector not advertising source-side
+ * scrambling support succeeds, even when the .scrambler_{enable|disable}
+ * callbacks are provided, i.e. they are ignored.
+ */
+static void drm_test_connector_hdmi_init_scrambler_ignored_callbacks(struct kunit *test)
+{
+ struct drm_connector_init_priv *priv = test->priv;
+ int ret;
+
+ priv->connector.hdmi.scrambler_supported = false;
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ "Vendor", "Product",
+ &dummy_funcs,
+ &dummy_hdmi_funcs_scrambler,
+ DRM_MODE_CONNECTOR_HDMIA,
+ &priv->ddc,
+ BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ 8);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+ KUNIT_EXPECT_EQ(test, priv->connector.hdmi.scrambler_supported, false);
+}
+
static struct kunit_case drmm_connector_hdmi_init_tests[] = {
KUNIT_CASE(drm_test_connector_hdmi_init_valid),
KUNIT_CASE(drm_test_connector_hdmi_init_bpc_8),
@@ -1278,6 +1406,10 @@ static struct kunit_case drmm_connector_hdmi_init_tests[] = {
drm_connector_hdmi_init_type_valid_gen_params),
KUNIT_CASE_PARAM(drm_test_connector_hdmi_init_type_invalid,
drm_connector_hdmi_init_type_invalid_gen_params),
+ KUNIT_CASE(drm_test_connector_hdmi_init_scrambler_valid),
+ KUNIT_CASE(drm_test_connector_hdmi_init_scrambler_no_callbacks),
+ KUNIT_CASE(drm_test_connector_hdmi_init_scrambler_partial_callbacks),
+ KUNIT_CASE(drm_test_connector_hdmi_init_scrambler_ignored_callbacks),
{ }
};
--
2.54.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH v7 27/30] drm/tests: edid: Add 4K@60Hz EDID with 600MHz TMDS
2026-06-01 22:44 ` Cristian Ciocaltea
@ 2026-06-01 22:44 ` Cristian Ciocaltea
-1 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
Add a new test EDID advertising the following capabilities:
Max resolution: 3840x2160@60Hz with RGB, YUV444, YUV422, YUV420
Max BPC: 16
Max TMDS clock: 600 MHz
This is needed to exercise the new HDMI infrastructure that decides
whether scrambling needs to be enabled for a given display mode and
to validate that high-rate modes are properly rejected/accepted
depending on the source/sink scrambling capability.
The EDID is derived from test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz
with the following changes:
- Upgraded the first DTD from 3840x2160@30 (297 MHz) to 3840x2160@60
(594 MHz). The H/V totals (4400x2250) and porches already match the
HDMI 2.0 4K@60Hz standard timing, so only the pixel clock had to be
bumped.
- Widened Display Range Limits descriptor to cover the new timing, i.e.
24-140 kHz H, max dotclock 600 MHz.
- Updated CTA-861 Video Data Block to advertise VIC 97 (4K@60Hz) instead
of VIC 95 (4k30).
- Bumped HF-VSDB Max TMDS Character Rate to 600 MHz, keeping
SCDC_Present set so that the sink advertises scrambling support.
- Cleared HDMI VSDB Max TMDS clock byte, as required by HDMI 2.0 when
the HF-VSDB declares a Max TMDS Character Rate above 340 MHz.
- Provided a Video Capability Data Block advertising selectable RGB and
YCC quantization range plus underscan for IT/CE formats; also set the
'IT Video Formats Underscanned' bit in the CTA-861 extension header to
match.
- Aligned base block image size with the DTD (160x90 cm) and replaced
the bogus 'Week of Manufacture = 0xff' with the Model Year code, both
fixing inherited EDID conformity warnings.
- Dropped the empty YCbCr 4:2:0 Video Data Block inherited from the
parent EDID, which is flagged as a failure by edid-decode v1.33.0
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/tests/drm_kunit_edid.h | 128 +++++++++++++++++++++++++++++++++
1 file changed, 128 insertions(+)
diff --git a/drivers/gpu/drm/tests/drm_kunit_edid.h b/drivers/gpu/drm/tests/drm_kunit_edid.h
index f4923157f5bf..9b318f7d364e 100644
--- a/drivers/gpu/drm/tests/drm_kunit_edid.h
+++ b/drivers/gpu/drm/tests/drm_kunit_edid.h
@@ -980,4 +980,132 @@ static const unsigned char test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz[] = {
0x00, 0x00, 0x00, 0x84
};
+/*
+ * Max resolution: 3840x2160@60Hz with RGB, YUV444, YUV422, YUV420
+ * Max BPC: 16 for all modes
+ * Max TMDS clock: 600 MHz
+ *
+ * edid-decode (hex):
+ *
+ * 00 ff ff ff ff ff ff 00 31 d8 34 00 00 00 00 00
+ * 00 23 01 03 80 a0 5a 78 0f ee 91 a3 54 4c 99 26
+ * 0f 50 54 20 00 00 01 01 01 01 01 01 01 01 01 01
+ * 01 01 01 01 01 01 08 e8 00 30 f2 70 5a 80 b0 58
+ * 8a 00 40 84 63 00 00 1e 00 00 00 fc 00 54 65 73
+ * 74 20 45 44 49 44 0a 20 20 20 00 00 00 fd 00 18
+ * 55 18 8c 3c 00 0a 20 20 20 20 20 20 00 00 00 10
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 a9
+ *
+ * 02 03 28 b1 41 61 6c 03 0c 00 10 00 78 00 20 00
+ * 00 01 03 6d d8 5d c4 01 78 80 07 00 00 00 00 00
+ * 00 e2 00 ca e3 0f 01 00 00 00 00 00 00 00 00 00
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 54
+ *
+ * ----------------
+ *
+ * Block 0, Base EDID:
+ * EDID Structure Version & Revision: 1.3
+ * Vendor & Product Identification:
+ * Manufacturer: LNX
+ * Model: 52
+ * Made in: 2025
+ * Basic Display Parameters & Features:
+ * Digital display
+ * Maximum image size: 160 cm x 90 cm
+ * Gamma: 2.20
+ * RGB color display
+ * Default (sRGB) color space is primary color space
+ * First detailed timing is the preferred timing
+ * Supports GTF timings within operating range
+ * Color Characteristics:
+ * Red : 0.6396, 0.3300
+ * Green: 0.2998, 0.5996
+ * Blue : 0.1503, 0.0595
+ * White: 0.3125, 0.3291
+ * Established Timings I & II:
+ * DMT 0x04: 640x480 59.940476 Hz 4:3 31.469 kHz 25.175000 MHz
+ * Standard Timings: none
+ * Detailed Timing Descriptors:
+ * DTD 1: 3840x2160 60.000000 Hz 16:9 135.000 kHz 594.000000 MHz (1600 mm x 900 mm)
+ * Hfront 176 Hsync 88 Hback 296 Hpol P
+ * Vfront 8 Vsync 10 Vback 72 Vpol P
+ * Display Product Name: 'Test EDID'
+ * Display Range Limits:
+ * Monitor ranges (GTF): 24-85 Hz V, 24-140 kHz H, max dotclock 600 MHz
+ * Dummy Descriptor:
+ * Extension blocks: 1
+ * Checksum: 0xa9
+ *
+ * ----------------
+ *
+ * Block 1, CTA-861 Extension Block:
+ * Revision: 3
+ * Underscans IT Video Formats by default
+ * Supports YCbCr 4:4:4
+ * Supports YCbCr 4:2:2
+ * Native detailed modes: 1
+ * Video Data Block:
+ * VIC 97: 3840x2160 60.000000 Hz 16:9 135.000 kHz 594.000000 MHz
+ * Vendor-Specific Data Block (HDMI), OUI 00-0C-03:
+ * Source physical address: 1.0.0.0
+ * DC_48bit
+ * DC_36bit
+ * DC_30bit
+ * DC_Y444
+ * Maximum TMDS clock: 0 MHz
+ * Extended HDMI video details:
+ * Vendor-Specific Data Block (HDMI Forum), OUI C4-5D-D8:
+ * Version: 1
+ * Maximum TMDS Character Rate: 600 MHz
+ * SCDC Present
+ * Supports 16-bits/component Deep Color 4:2:0 Pixel Encoding
+ * Supports 12-bits/component Deep Color 4:2:0 Pixel Encoding
+ * Supports 10-bits/component Deep Color 4:2:0 Pixel Encoding
+ * VRRmin: 0 Hz
+ * VRRmax: 0 Hz
+ * Video Capability Data Block:
+ * YCbCr quantization: Selectable (via AVI YQ)
+ * RGB quantization: Selectable (via AVI Q)
+ * PT scan behavior: No Data
+ * IT scan behavior: Always Underscanned
+ * CE scan behavior: Always Underscanned
+ * YCbCr 4:2:0 Capability Map Data Block:
+ * VIC 97: 3840x2160 60.000000 Hz 16:9 135.000 kHz 594.000000 MHz
+ * Checksum: 0x54 Unused space in Extension Block: 87 bytes
+ *
+ * ----------------
+ *
+ * edid-decode 1.33.0
+ *
+ * EDID conformity: PASS
+ */
+static const unsigned char test_edid_hdmi_4k_rgb_yuv420_dc_max_600mhz[] = {
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x31, 0xd8, 0x34, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x01, 0x03, 0x80, 0xa0, 0x5a, 0x78,
+ 0x0f, 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26, 0x0f, 0x50, 0x54, 0x20,
+ 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x08, 0xe8, 0x00, 0x30, 0xf2, 0x70,
+ 0x5a, 0x80, 0xb0, 0x58, 0x8a, 0x00, 0x40, 0x84, 0x63, 0x00, 0x00, 0x1e,
+ 0x00, 0x00, 0x00, 0xfc, 0x00, 0x54, 0x65, 0x73, 0x74, 0x20, 0x45, 0x44,
+ 0x49, 0x44, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x18,
+ 0x55, 0x18, 0x8c, 0x3c, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xa9, 0x02, 0x03, 0x28, 0xb1,
+ 0x41, 0x61, 0x6c, 0x03, 0x0c, 0x00, 0x10, 0x00, 0x78, 0x00, 0x20, 0x00,
+ 0x00, 0x01, 0x03, 0x6d, 0xd8, 0x5d, 0xc4, 0x01, 0x78, 0x80, 0x07, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xe2, 0x00, 0xca, 0xe3, 0x0f, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x54,
+};
+
#endif // DRM_KUNIT_EDID_H_
--
2.54.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH v7 27/30] drm/tests: edid: Add 4K@60Hz EDID with 600MHz TMDS
@ 2026-06-01 22:44 ` Cristian Ciocaltea
0 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
Add a new test EDID advertising the following capabilities:
Max resolution: 3840x2160@60Hz with RGB, YUV444, YUV422, YUV420
Max BPC: 16
Max TMDS clock: 600 MHz
This is needed to exercise the new HDMI infrastructure that decides
whether scrambling needs to be enabled for a given display mode and
to validate that high-rate modes are properly rejected/accepted
depending on the source/sink scrambling capability.
The EDID is derived from test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz
with the following changes:
- Upgraded the first DTD from 3840x2160@30 (297 MHz) to 3840x2160@60
(594 MHz). The H/V totals (4400x2250) and porches already match the
HDMI 2.0 4K@60Hz standard timing, so only the pixel clock had to be
bumped.
- Widened Display Range Limits descriptor to cover the new timing, i.e.
24-140 kHz H, max dotclock 600 MHz.
- Updated CTA-861 Video Data Block to advertise VIC 97 (4K@60Hz) instead
of VIC 95 (4k30).
- Bumped HF-VSDB Max TMDS Character Rate to 600 MHz, keeping
SCDC_Present set so that the sink advertises scrambling support.
- Cleared HDMI VSDB Max TMDS clock byte, as required by HDMI 2.0 when
the HF-VSDB declares a Max TMDS Character Rate above 340 MHz.
- Provided a Video Capability Data Block advertising selectable RGB and
YCC quantization range plus underscan for IT/CE formats; also set the
'IT Video Formats Underscanned' bit in the CTA-861 extension header to
match.
- Aligned base block image size with the DTD (160x90 cm) and replaced
the bogus 'Week of Manufacture = 0xff' with the Model Year code, both
fixing inherited EDID conformity warnings.
- Dropped the empty YCbCr 4:2:0 Video Data Block inherited from the
parent EDID, which is flagged as a failure by edid-decode v1.33.0
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/tests/drm_kunit_edid.h | 128 +++++++++++++++++++++++++++++++++
1 file changed, 128 insertions(+)
diff --git a/drivers/gpu/drm/tests/drm_kunit_edid.h b/drivers/gpu/drm/tests/drm_kunit_edid.h
index f4923157f5bf..9b318f7d364e 100644
--- a/drivers/gpu/drm/tests/drm_kunit_edid.h
+++ b/drivers/gpu/drm/tests/drm_kunit_edid.h
@@ -980,4 +980,132 @@ static const unsigned char test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz[] = {
0x00, 0x00, 0x00, 0x84
};
+/*
+ * Max resolution: 3840x2160@60Hz with RGB, YUV444, YUV422, YUV420
+ * Max BPC: 16 for all modes
+ * Max TMDS clock: 600 MHz
+ *
+ * edid-decode (hex):
+ *
+ * 00 ff ff ff ff ff ff 00 31 d8 34 00 00 00 00 00
+ * 00 23 01 03 80 a0 5a 78 0f ee 91 a3 54 4c 99 26
+ * 0f 50 54 20 00 00 01 01 01 01 01 01 01 01 01 01
+ * 01 01 01 01 01 01 08 e8 00 30 f2 70 5a 80 b0 58
+ * 8a 00 40 84 63 00 00 1e 00 00 00 fc 00 54 65 73
+ * 74 20 45 44 49 44 0a 20 20 20 00 00 00 fd 00 18
+ * 55 18 8c 3c 00 0a 20 20 20 20 20 20 00 00 00 10
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 a9
+ *
+ * 02 03 28 b1 41 61 6c 03 0c 00 10 00 78 00 20 00
+ * 00 01 03 6d d8 5d c4 01 78 80 07 00 00 00 00 00
+ * 00 e2 00 ca e3 0f 01 00 00 00 00 00 00 00 00 00
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 54
+ *
+ * ----------------
+ *
+ * Block 0, Base EDID:
+ * EDID Structure Version & Revision: 1.3
+ * Vendor & Product Identification:
+ * Manufacturer: LNX
+ * Model: 52
+ * Made in: 2025
+ * Basic Display Parameters & Features:
+ * Digital display
+ * Maximum image size: 160 cm x 90 cm
+ * Gamma: 2.20
+ * RGB color display
+ * Default (sRGB) color space is primary color space
+ * First detailed timing is the preferred timing
+ * Supports GTF timings within operating range
+ * Color Characteristics:
+ * Red : 0.6396, 0.3300
+ * Green: 0.2998, 0.5996
+ * Blue : 0.1503, 0.0595
+ * White: 0.3125, 0.3291
+ * Established Timings I & II:
+ * DMT 0x04: 640x480 59.940476 Hz 4:3 31.469 kHz 25.175000 MHz
+ * Standard Timings: none
+ * Detailed Timing Descriptors:
+ * DTD 1: 3840x2160 60.000000 Hz 16:9 135.000 kHz 594.000000 MHz (1600 mm x 900 mm)
+ * Hfront 176 Hsync 88 Hback 296 Hpol P
+ * Vfront 8 Vsync 10 Vback 72 Vpol P
+ * Display Product Name: 'Test EDID'
+ * Display Range Limits:
+ * Monitor ranges (GTF): 24-85 Hz V, 24-140 kHz H, max dotclock 600 MHz
+ * Dummy Descriptor:
+ * Extension blocks: 1
+ * Checksum: 0xa9
+ *
+ * ----------------
+ *
+ * Block 1, CTA-861 Extension Block:
+ * Revision: 3
+ * Underscans IT Video Formats by default
+ * Supports YCbCr 4:4:4
+ * Supports YCbCr 4:2:2
+ * Native detailed modes: 1
+ * Video Data Block:
+ * VIC 97: 3840x2160 60.000000 Hz 16:9 135.000 kHz 594.000000 MHz
+ * Vendor-Specific Data Block (HDMI), OUI 00-0C-03:
+ * Source physical address: 1.0.0.0
+ * DC_48bit
+ * DC_36bit
+ * DC_30bit
+ * DC_Y444
+ * Maximum TMDS clock: 0 MHz
+ * Extended HDMI video details:
+ * Vendor-Specific Data Block (HDMI Forum), OUI C4-5D-D8:
+ * Version: 1
+ * Maximum TMDS Character Rate: 600 MHz
+ * SCDC Present
+ * Supports 16-bits/component Deep Color 4:2:0 Pixel Encoding
+ * Supports 12-bits/component Deep Color 4:2:0 Pixel Encoding
+ * Supports 10-bits/component Deep Color 4:2:0 Pixel Encoding
+ * VRRmin: 0 Hz
+ * VRRmax: 0 Hz
+ * Video Capability Data Block:
+ * YCbCr quantization: Selectable (via AVI YQ)
+ * RGB quantization: Selectable (via AVI Q)
+ * PT scan behavior: No Data
+ * IT scan behavior: Always Underscanned
+ * CE scan behavior: Always Underscanned
+ * YCbCr 4:2:0 Capability Map Data Block:
+ * VIC 97: 3840x2160 60.000000 Hz 16:9 135.000 kHz 594.000000 MHz
+ * Checksum: 0x54 Unused space in Extension Block: 87 bytes
+ *
+ * ----------------
+ *
+ * edid-decode 1.33.0
+ *
+ * EDID conformity: PASS
+ */
+static const unsigned char test_edid_hdmi_4k_rgb_yuv420_dc_max_600mhz[] = {
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x31, 0xd8, 0x34, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x01, 0x03, 0x80, 0xa0, 0x5a, 0x78,
+ 0x0f, 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26, 0x0f, 0x50, 0x54, 0x20,
+ 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x08, 0xe8, 0x00, 0x30, 0xf2, 0x70,
+ 0x5a, 0x80, 0xb0, 0x58, 0x8a, 0x00, 0x40, 0x84, 0x63, 0x00, 0x00, 0x1e,
+ 0x00, 0x00, 0x00, 0xfc, 0x00, 0x54, 0x65, 0x73, 0x74, 0x20, 0x45, 0x44,
+ 0x49, 0x44, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x18,
+ 0x55, 0x18, 0x8c, 0x3c, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xa9, 0x02, 0x03, 0x28, 0xb1,
+ 0x41, 0x61, 0x6c, 0x03, 0x0c, 0x00, 0x10, 0x00, 0x78, 0x00, 0x20, 0x00,
+ 0x00, 0x01, 0x03, 0x6d, 0xd8, 0x5d, 0xc4, 0x01, 0x78, 0x80, 0x07, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xe2, 0x00, 0xca, 0xe3, 0x0f, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x54,
+};
+
#endif // DRM_KUNIT_EDID_H_
--
2.54.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH v7 28/30] drm/tests: hdmi_state_helper: Add HDMI 2.0 scrambling tests
2026-06-01 22:44 ` Cristian Ciocaltea
@ 2026-06-01 22:44 ` Cristian Ciocaltea
-1 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
Cover the newly introduced HDMI 2.0 source-scrambler plumbing in the
drm_hdmi_state_helper code with the following KUnit tests:
- drm_test_check_scrambler_needed_low_rate verifies that a mode with
TMDS rate <= 340 MHz never sets conn_state->hdmi.scrambler_needed,
even when both endpoints advertise scrambling support.
- drm_test_check_scrambler_needed_high_rate verifies that a mode with
TMDS rate > 340 MHz makes the helper set scrambler_needed.
- drm_test_check_scrambler_needed_high_rate_no_adv verifies that a mode
with TMDS rate > 340 MHz never sets scrambler_needed when source does
not advertise scrambling support, regardless of sink scrambling
advertisement.
To match the behaviour drm_bridge_connector_init() applies to bridges
that implement source-scrambling callbacks, the __connector_hdmi_init()
helper now infers connector->hdmi.scrambling_supported from the presence
of .scrambler_enable and .scrambler_disable in the supplied
drm_connector_hdmi_funcs, mirroring how connector capability should be
wired up in real drivers.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 219 +++++++++++++++++++++
1 file changed, 219 insertions(+)
diff --git a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
index e89e1af7a811..98cd42f429cb 100644
--- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
+++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
@@ -20,6 +20,8 @@
#include <drm/display/drm_hdmi_helper.h>
#include <drm/display/drm_hdmi_state_helper.h>
+#include <linux/hdmi.h>
+
#include "../drm_crtc_internal.h"
#include <kunit/test.h>
@@ -140,6 +142,29 @@ static const struct drm_connector_hdmi_funcs reject_100mhz_connector_hdmi_funcs
},
};
+static int accept_scrambler_enable(struct drm_connector *connector)
+{
+ return 0;
+}
+
+static int accept_scrambler_disable(struct drm_connector *connector)
+{
+ return 0;
+}
+
+static const struct drm_connector_hdmi_funcs scrambler_connector_hdmi_funcs = {
+ .scrambler_enable = accept_scrambler_enable,
+ .scrambler_disable = accept_scrambler_disable,
+ .avi = {
+ .clear_infoframe = accept_infoframe_clear_infoframe,
+ .write_infoframe = accept_infoframe_write_infoframe,
+ },
+ .hdmi = {
+ .clear_infoframe = accept_infoframe_clear_infoframe,
+ .write_infoframe = accept_infoframe_write_infoframe,
+ },
+};
+
static int dummy_connector_get_modes(struct drm_connector *connector)
{
struct drm_atomic_helper_connector_hdmi_priv *priv =
@@ -240,6 +265,8 @@ __connector_hdmi_init(struct kunit *test,
conn = &priv->connector;
conn->ycbcr_420_allowed = !!(formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420));
+ conn->hdmi.scrambler_supported = hdmi_funcs->scrambler_enable &&
+ hdmi_funcs->scrambler_disable;
ret = drmm_connector_hdmi_init(drm, conn,
"Vendor", "Product",
@@ -2198,6 +2225,195 @@ static void drm_test_check_disable_connector(struct kunit *test)
drm_modeset_acquire_fini(&ctx);
}
+/*
+ * Test that a sub-340 MHz TMDS character rate does not set
+ * conn_state->hdmi.scrambler_needed, even when the source
+ * and the sink both support scrambling.
+ */
+static void drm_test_check_scrambler_needed_low_rate(struct kunit *test)
+{
+ struct drm_atomic_helper_connector_hdmi_priv *priv;
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_connector_state *conn_state;
+ struct drm_display_info *info;
+ struct drm_display_mode *low_rate_mode;
+ struct drm_connector *conn;
+ struct drm_device *drm;
+ struct drm_crtc *crtc;
+ unsigned long long rate;
+ int ret;
+
+ priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
+ BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ 8,
+ &scrambler_connector_hdmi_funcs,
+ test_edid_hdmi_4k_rgb_yuv420_dc_max_600mhz);
+ KUNIT_ASSERT_NOT_NULL(test, priv);
+
+ drm = &priv->drm;
+ crtc = priv->crtc;
+ conn = &priv->connector;
+ info = &conn->display_info;
+ KUNIT_ASSERT_TRUE(test, conn->hdmi.scrambler_supported);
+ KUNIT_ASSERT_TRUE(test, info->is_hdmi);
+ KUNIT_ASSERT_TRUE(test, info->hdmi.scdc.supported);
+ KUNIT_ASSERT_TRUE(test, info->hdmi.scdc.scrambling.supported);
+
+ low_rate_mode = drm_kunit_display_mode_from_cea_vic(test, drm, 16);
+ KUNIT_ASSERT_NOT_NULL(test, low_rate_mode);
+
+ rate = drm_hdmi_compute_mode_clock(low_rate_mode, 8, DRM_OUTPUT_COLOR_FORMAT_RGB444);
+ KUNIT_ASSERT_LT(test, rate, HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ);
+
+ drm_modeset_acquire_init(&ctx, 0);
+
+retry_conn_enable:
+ ret = drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn,
+ low_rate_mode, &ctx);
+ if (ret == -EDEADLK) {
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_conn_enable;
+ }
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ conn_state = conn->state;
+ KUNIT_ASSERT_NOT_NULL(test, conn_state);
+
+ KUNIT_EXPECT_LE(test, conn_state->hdmi.tmds_char_rate,
+ HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ);
+ KUNIT_EXPECT_FALSE(test, conn_state->hdmi.scrambler_needed);
+
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+}
+
+/*
+ * Test that an over-340 MHz TMDS character rate sets
+ * conn_state->hdmi.scrambler_needed when both source
+ * and sink advertise scrambling support.
+ */
+static void drm_test_check_scrambler_needed_high_rate(struct kunit *test)
+{
+ struct drm_atomic_helper_connector_hdmi_priv *priv;
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_connector_state *conn_state;
+ struct drm_display_info *info;
+ struct drm_display_mode *preferred;
+ struct drm_connector *conn;
+ struct drm_device *drm;
+ struct drm_crtc *crtc;
+ unsigned long long rate;
+ int ret;
+
+ priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
+ BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ 8,
+ &scrambler_connector_hdmi_funcs,
+ test_edid_hdmi_4k_rgb_yuv420_dc_max_600mhz);
+ KUNIT_ASSERT_NOT_NULL(test, priv);
+
+ drm = &priv->drm;
+ crtc = priv->crtc;
+ conn = &priv->connector;
+ info = &conn->display_info;
+ KUNIT_ASSERT_TRUE(test, conn->hdmi.scrambler_supported);
+ KUNIT_ASSERT_TRUE(test, info->is_hdmi);
+ KUNIT_ASSERT_TRUE(test, info->hdmi.scdc.supported);
+ KUNIT_ASSERT_TRUE(test, info->hdmi.scdc.scrambling.supported);
+
+ preferred = find_preferred_mode(conn);
+ KUNIT_ASSERT_NOT_NULL(test, preferred);
+
+ rate = drm_hdmi_compute_mode_clock(preferred, 8, DRM_OUTPUT_COLOR_FORMAT_RGB444);
+ KUNIT_ASSERT_GT(test, rate, HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ);
+
+ drm_modeset_acquire_init(&ctx, 0);
+
+retry_conn_enable:
+ ret = drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn,
+ preferred, &ctx);
+ if (ret == -EDEADLK) {
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_conn_enable;
+ }
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ conn_state = conn->state;
+ KUNIT_ASSERT_NOT_NULL(test, conn_state);
+
+ KUNIT_EXPECT_GT(test, conn_state->hdmi.tmds_char_rate,
+ HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ);
+ KUNIT_EXPECT_TRUE(test, conn_state->hdmi.scrambler_needed);
+
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+}
+
+/*
+ * Test that an over-340 MHz TMDS character rate does not set
+ * conn_state->hdmi.scrambler_needed when the source does not
+ * advertise scrambling support, even if the sink does.
+ */
+static void drm_test_check_scrambler_needed_high_rate_no_adv(struct kunit *test)
+{
+ struct drm_atomic_helper_connector_hdmi_priv *priv;
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_connector_state *conn_state;
+ struct drm_display_info *info;
+ struct drm_display_mode *preferred;
+ struct drm_connector *conn;
+ struct drm_device *drm;
+ struct drm_crtc *crtc;
+ unsigned long long rate;
+ int ret;
+
+ priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
+ BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ 8,
+ &dummy_connector_hdmi_funcs,
+ test_edid_hdmi_4k_rgb_yuv420_dc_max_600mhz);
+ KUNIT_ASSERT_NOT_NULL(test, priv);
+
+ drm = &priv->drm;
+ crtc = priv->crtc;
+ conn = &priv->connector;
+ info = &conn->display_info;
+ KUNIT_ASSERT_FALSE(test, conn->hdmi.scrambler_supported);
+ KUNIT_ASSERT_TRUE(test, info->is_hdmi);
+ KUNIT_ASSERT_TRUE(test, info->hdmi.scdc.supported);
+ KUNIT_ASSERT_TRUE(test, info->hdmi.scdc.scrambling.supported);
+
+ preferred = find_preferred_mode(conn);
+ KUNIT_ASSERT_NOT_NULL(test, preferred);
+
+ rate = drm_hdmi_compute_mode_clock(preferred, 8, DRM_OUTPUT_COLOR_FORMAT_RGB444);
+ KUNIT_ASSERT_GT(test, rate, HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ);
+
+ drm_modeset_acquire_init(&ctx, 0);
+
+retry_conn_enable:
+ ret = drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn,
+ preferred, &ctx);
+ if (ret == -EDEADLK) {
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_conn_enable;
+ }
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ conn_state = conn->state;
+ KUNIT_ASSERT_NOT_NULL(test, conn_state);
+
+ KUNIT_EXPECT_GT(test, conn_state->hdmi.tmds_char_rate,
+ HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ);
+ KUNIT_EXPECT_FALSE(test, conn_state->hdmi.scrambler_needed);
+
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+}
+
static struct kunit_case drm_atomic_helper_connector_hdmi_check_tests[] = {
KUNIT_CASE(drm_test_check_broadcast_rgb_auto_cea_mode),
KUNIT_CASE(drm_test_check_broadcast_rgb_auto_cea_mode_vic_1),
@@ -2227,6 +2443,9 @@ static struct kunit_case drm_atomic_helper_connector_hdmi_check_tests[] = {
KUNIT_CASE(drm_test_check_tmds_char_rate_rgb_8bpc),
KUNIT_CASE(drm_test_check_tmds_char_rate_rgb_10bpc),
KUNIT_CASE(drm_test_check_tmds_char_rate_rgb_12bpc),
+ KUNIT_CASE(drm_test_check_scrambler_needed_low_rate),
+ KUNIT_CASE(drm_test_check_scrambler_needed_high_rate),
+ KUNIT_CASE(drm_test_check_scrambler_needed_high_rate_no_adv),
/*
* TODO: We should have tests to check that a change in the
* format triggers a CRTC mode change just like we do for the
--
2.54.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH v7 28/30] drm/tests: hdmi_state_helper: Add HDMI 2.0 scrambling tests
@ 2026-06-01 22:44 ` Cristian Ciocaltea
0 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
Cover the newly introduced HDMI 2.0 source-scrambler plumbing in the
drm_hdmi_state_helper code with the following KUnit tests:
- drm_test_check_scrambler_needed_low_rate verifies that a mode with
TMDS rate <= 340 MHz never sets conn_state->hdmi.scrambler_needed,
even when both endpoints advertise scrambling support.
- drm_test_check_scrambler_needed_high_rate verifies that a mode with
TMDS rate > 340 MHz makes the helper set scrambler_needed.
- drm_test_check_scrambler_needed_high_rate_no_adv verifies that a mode
with TMDS rate > 340 MHz never sets scrambler_needed when source does
not advertise scrambling support, regardless of sink scrambling
advertisement.
To match the behaviour drm_bridge_connector_init() applies to bridges
that implement source-scrambling callbacks, the __connector_hdmi_init()
helper now infers connector->hdmi.scrambling_supported from the presence
of .scrambler_enable and .scrambler_disable in the supplied
drm_connector_hdmi_funcs, mirroring how connector capability should be
wired up in real drivers.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 219 +++++++++++++++++++++
1 file changed, 219 insertions(+)
diff --git a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
index e89e1af7a811..98cd42f429cb 100644
--- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
+++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
@@ -20,6 +20,8 @@
#include <drm/display/drm_hdmi_helper.h>
#include <drm/display/drm_hdmi_state_helper.h>
+#include <linux/hdmi.h>
+
#include "../drm_crtc_internal.h"
#include <kunit/test.h>
@@ -140,6 +142,29 @@ static const struct drm_connector_hdmi_funcs reject_100mhz_connector_hdmi_funcs
},
};
+static int accept_scrambler_enable(struct drm_connector *connector)
+{
+ return 0;
+}
+
+static int accept_scrambler_disable(struct drm_connector *connector)
+{
+ return 0;
+}
+
+static const struct drm_connector_hdmi_funcs scrambler_connector_hdmi_funcs = {
+ .scrambler_enable = accept_scrambler_enable,
+ .scrambler_disable = accept_scrambler_disable,
+ .avi = {
+ .clear_infoframe = accept_infoframe_clear_infoframe,
+ .write_infoframe = accept_infoframe_write_infoframe,
+ },
+ .hdmi = {
+ .clear_infoframe = accept_infoframe_clear_infoframe,
+ .write_infoframe = accept_infoframe_write_infoframe,
+ },
+};
+
static int dummy_connector_get_modes(struct drm_connector *connector)
{
struct drm_atomic_helper_connector_hdmi_priv *priv =
@@ -240,6 +265,8 @@ __connector_hdmi_init(struct kunit *test,
conn = &priv->connector;
conn->ycbcr_420_allowed = !!(formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420));
+ conn->hdmi.scrambler_supported = hdmi_funcs->scrambler_enable &&
+ hdmi_funcs->scrambler_disable;
ret = drmm_connector_hdmi_init(drm, conn,
"Vendor", "Product",
@@ -2198,6 +2225,195 @@ static void drm_test_check_disable_connector(struct kunit *test)
drm_modeset_acquire_fini(&ctx);
}
+/*
+ * Test that a sub-340 MHz TMDS character rate does not set
+ * conn_state->hdmi.scrambler_needed, even when the source
+ * and the sink both support scrambling.
+ */
+static void drm_test_check_scrambler_needed_low_rate(struct kunit *test)
+{
+ struct drm_atomic_helper_connector_hdmi_priv *priv;
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_connector_state *conn_state;
+ struct drm_display_info *info;
+ struct drm_display_mode *low_rate_mode;
+ struct drm_connector *conn;
+ struct drm_device *drm;
+ struct drm_crtc *crtc;
+ unsigned long long rate;
+ int ret;
+
+ priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
+ BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ 8,
+ &scrambler_connector_hdmi_funcs,
+ test_edid_hdmi_4k_rgb_yuv420_dc_max_600mhz);
+ KUNIT_ASSERT_NOT_NULL(test, priv);
+
+ drm = &priv->drm;
+ crtc = priv->crtc;
+ conn = &priv->connector;
+ info = &conn->display_info;
+ KUNIT_ASSERT_TRUE(test, conn->hdmi.scrambler_supported);
+ KUNIT_ASSERT_TRUE(test, info->is_hdmi);
+ KUNIT_ASSERT_TRUE(test, info->hdmi.scdc.supported);
+ KUNIT_ASSERT_TRUE(test, info->hdmi.scdc.scrambling.supported);
+
+ low_rate_mode = drm_kunit_display_mode_from_cea_vic(test, drm, 16);
+ KUNIT_ASSERT_NOT_NULL(test, low_rate_mode);
+
+ rate = drm_hdmi_compute_mode_clock(low_rate_mode, 8, DRM_OUTPUT_COLOR_FORMAT_RGB444);
+ KUNIT_ASSERT_LT(test, rate, HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ);
+
+ drm_modeset_acquire_init(&ctx, 0);
+
+retry_conn_enable:
+ ret = drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn,
+ low_rate_mode, &ctx);
+ if (ret == -EDEADLK) {
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_conn_enable;
+ }
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ conn_state = conn->state;
+ KUNIT_ASSERT_NOT_NULL(test, conn_state);
+
+ KUNIT_EXPECT_LE(test, conn_state->hdmi.tmds_char_rate,
+ HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ);
+ KUNIT_EXPECT_FALSE(test, conn_state->hdmi.scrambler_needed);
+
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+}
+
+/*
+ * Test that an over-340 MHz TMDS character rate sets
+ * conn_state->hdmi.scrambler_needed when both source
+ * and sink advertise scrambling support.
+ */
+static void drm_test_check_scrambler_needed_high_rate(struct kunit *test)
+{
+ struct drm_atomic_helper_connector_hdmi_priv *priv;
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_connector_state *conn_state;
+ struct drm_display_info *info;
+ struct drm_display_mode *preferred;
+ struct drm_connector *conn;
+ struct drm_device *drm;
+ struct drm_crtc *crtc;
+ unsigned long long rate;
+ int ret;
+
+ priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
+ BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ 8,
+ &scrambler_connector_hdmi_funcs,
+ test_edid_hdmi_4k_rgb_yuv420_dc_max_600mhz);
+ KUNIT_ASSERT_NOT_NULL(test, priv);
+
+ drm = &priv->drm;
+ crtc = priv->crtc;
+ conn = &priv->connector;
+ info = &conn->display_info;
+ KUNIT_ASSERT_TRUE(test, conn->hdmi.scrambler_supported);
+ KUNIT_ASSERT_TRUE(test, info->is_hdmi);
+ KUNIT_ASSERT_TRUE(test, info->hdmi.scdc.supported);
+ KUNIT_ASSERT_TRUE(test, info->hdmi.scdc.scrambling.supported);
+
+ preferred = find_preferred_mode(conn);
+ KUNIT_ASSERT_NOT_NULL(test, preferred);
+
+ rate = drm_hdmi_compute_mode_clock(preferred, 8, DRM_OUTPUT_COLOR_FORMAT_RGB444);
+ KUNIT_ASSERT_GT(test, rate, HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ);
+
+ drm_modeset_acquire_init(&ctx, 0);
+
+retry_conn_enable:
+ ret = drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn,
+ preferred, &ctx);
+ if (ret == -EDEADLK) {
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_conn_enable;
+ }
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ conn_state = conn->state;
+ KUNIT_ASSERT_NOT_NULL(test, conn_state);
+
+ KUNIT_EXPECT_GT(test, conn_state->hdmi.tmds_char_rate,
+ HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ);
+ KUNIT_EXPECT_TRUE(test, conn_state->hdmi.scrambler_needed);
+
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+}
+
+/*
+ * Test that an over-340 MHz TMDS character rate does not set
+ * conn_state->hdmi.scrambler_needed when the source does not
+ * advertise scrambling support, even if the sink does.
+ */
+static void drm_test_check_scrambler_needed_high_rate_no_adv(struct kunit *test)
+{
+ struct drm_atomic_helper_connector_hdmi_priv *priv;
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_connector_state *conn_state;
+ struct drm_display_info *info;
+ struct drm_display_mode *preferred;
+ struct drm_connector *conn;
+ struct drm_device *drm;
+ struct drm_crtc *crtc;
+ unsigned long long rate;
+ int ret;
+
+ priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
+ BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ 8,
+ &dummy_connector_hdmi_funcs,
+ test_edid_hdmi_4k_rgb_yuv420_dc_max_600mhz);
+ KUNIT_ASSERT_NOT_NULL(test, priv);
+
+ drm = &priv->drm;
+ crtc = priv->crtc;
+ conn = &priv->connector;
+ info = &conn->display_info;
+ KUNIT_ASSERT_FALSE(test, conn->hdmi.scrambler_supported);
+ KUNIT_ASSERT_TRUE(test, info->is_hdmi);
+ KUNIT_ASSERT_TRUE(test, info->hdmi.scdc.supported);
+ KUNIT_ASSERT_TRUE(test, info->hdmi.scdc.scrambling.supported);
+
+ preferred = find_preferred_mode(conn);
+ KUNIT_ASSERT_NOT_NULL(test, preferred);
+
+ rate = drm_hdmi_compute_mode_clock(preferred, 8, DRM_OUTPUT_COLOR_FORMAT_RGB444);
+ KUNIT_ASSERT_GT(test, rate, HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ);
+
+ drm_modeset_acquire_init(&ctx, 0);
+
+retry_conn_enable:
+ ret = drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn,
+ preferred, &ctx);
+ if (ret == -EDEADLK) {
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_conn_enable;
+ }
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ conn_state = conn->state;
+ KUNIT_ASSERT_NOT_NULL(test, conn_state);
+
+ KUNIT_EXPECT_GT(test, conn_state->hdmi.tmds_char_rate,
+ HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ);
+ KUNIT_EXPECT_FALSE(test, conn_state->hdmi.scrambler_needed);
+
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+}
+
static struct kunit_case drm_atomic_helper_connector_hdmi_check_tests[] = {
KUNIT_CASE(drm_test_check_broadcast_rgb_auto_cea_mode),
KUNIT_CASE(drm_test_check_broadcast_rgb_auto_cea_mode_vic_1),
@@ -2227,6 +2443,9 @@ static struct kunit_case drm_atomic_helper_connector_hdmi_check_tests[] = {
KUNIT_CASE(drm_test_check_tmds_char_rate_rgb_8bpc),
KUNIT_CASE(drm_test_check_tmds_char_rate_rgb_10bpc),
KUNIT_CASE(drm_test_check_tmds_char_rate_rgb_12bpc),
+ KUNIT_CASE(drm_test_check_scrambler_needed_low_rate),
+ KUNIT_CASE(drm_test_check_scrambler_needed_high_rate),
+ KUNIT_CASE(drm_test_check_scrambler_needed_high_rate_no_adv),
/*
* TODO: We should have tests to check that a change in the
* format triggers a CRTC mode change just like we do for the
--
2.54.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH v7 29/30] drm/tests: edid: Fix conformity for 1080p+4K YUV420 200MHz EDID
2026-06-01 22:44 ` Cristian Ciocaltea
@ 2026-06-01 22:44 ` Cristian Ciocaltea
-1 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
The test EDID added by commit 58fe1d78605e ("drm/tests: hdmi: Provide
EDID supporting 4K@30Hz with YUV420 only") fails 'edid-decode --check'
(v1.33.0) with the following issues:
Warnings:
Block 1, CTA-861 Extension Block:
IT Video Formats are overscanned by default, but normally this should be underscanned.
YCbCr 4:2:0 Video Data Block: Some YCbCr 4:2:0 timings are invalid for HDMI 2.1
(which requires an RGB timings pixel rate >= 590 MHz).
EDID:
Base EDID: Some timings are out of range of the Monitor Ranges:
Maximum Clock: 297.000 MHz (Monitor: 170.000 MHz)
CTA-861: Multiple native progressive timings are defined.
Failures:
Block 0, Base EDID:
Vendor & Product Identification: EDID 1.3 does not support week 0xff.
Block 1, CTA-861 Extension Block:
Vendor-Specific Data Block (HDMI Forum), OUI C4-5D-D8: Max TMDS rate is > 0 and <= 340 or > 600.
YCbCr 4:2:0 Capability Map Data Block: Empty Capability Map.
YCbCr 4:2:0 Video Data Block: YCbCr 4:2:0-only VIC 95 is also a regular VIC.
Missing VCDB, needed for Set Selectable RGB Quantization to avoid interop issues.
EDID:
CTA-861: The maximum HDMI TMDS clock is 200000 kHz, but one or more video timings go up to 297000 kHz.
Address them while preserving the advertised maximum resolutions, BPC
and TMDS clock used by the existing KUnit tests:
- Week 0xff is not valid for EDID 1.3; set it to 0x00 so that the Model
year field becomes a regular Year of Manufacture.
- The HDMI Forum VSDB Max TMDS Character Rate must be 0 when no rate
above 340 MHz is supported. The HDMI VSDB still advertises 200 MHz as
Max TMDS Clock.
- VIC 95 (3840x2160@30Hz) was reported as YUV420-only but was listed in
both the regular Video Data Block and the YCbCr 4:2:0 Video Data
Block. Drop it from the regular VDB (so it stays advertised in the
4:2:0 VDB only) and remove the now unnecessary empty YCbCr 4:2:0
Capability Map Data Block.
- Add a Video Capability Data Block advertising selectable RGB and YCC
quantization range plus underscan for IT/CE formats; also set the 'IT
Video Formats Underscanned' bit in the CTA-861 extension header to
match.
- Bump the Display Range Limits max pixel clock from 170 MHz to 300 MHz
so it covers the 297 MHz pixel rate of VIC 95.
- Drop the 'native' flag from VIC 16 in the Video Data Block so it is no
longer flagged as a second native progressive timing alongside the
preferred DTD.
The only remaining warning is HDMI 2.1 related and can be ignored, as it
requires that any mode listed in the YCbCr 4:2:0 Video Data Block must
have a corresponding RGB pixel clock >= 590 MHz.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/tests/drm_kunit_edid.h | 65 +++++++++++++++++++++-------------
1 file changed, 41 insertions(+), 24 deletions(-)
diff --git a/drivers/gpu/drm/tests/drm_kunit_edid.h b/drivers/gpu/drm/tests/drm_kunit_edid.h
index 9b318f7d364e..618b42d2fd8e 100644
--- a/drivers/gpu/drm/tests/drm_kunit_edid.h
+++ b/drivers/gpu/drm/tests/drm_kunit_edid.h
@@ -758,22 +758,22 @@ static const unsigned char test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz[] = {
* edid-decode (hex):
*
* 00 ff ff ff ff ff ff 00 31 d8 34 00 00 00 00 00
- * ff 23 01 03 80 60 36 78 0f ee 91 a3 54 4c 99 26
+ * 00 23 01 03 80 60 36 78 0f ee 91 a3 54 4c 99 26
* 0f 50 54 20 00 00 01 01 01 01 01 01 01 01 01 01
* 01 01 01 01 01 01 02 3a 80 18 71 38 2d 40 58 2c
* 45 00 c0 1c 32 00 00 1e 00 00 00 fc 00 54 65 73
* 74 20 45 44 49 44 0a 20 20 20 00 00 00 fd 00 18
- * 55 18 5e 11 00 0a 20 20 20 20 20 20 00 00 00 10
- * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 bb
+ * 55 18 5e 1e 00 0a 20 20 20 20 20 20 00 00 00 10
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 ad
*
- * 02 03 29 31 42 90 5f 6c 03 0c 00 10 00 78 28 20
- * 00 00 01 03 6d d8 5d c4 01 28 80 07 00 00 00 00
- * 00 00 e3 0f 00 00 e2 0e 5f 00 00 00 00 00 00 00
+ * 02 03 27 b1 41 10 6c 03 0c 00 10 00 78 28 20 00
+ * 00 01 03 6d d8 5d c4 01 00 80 07 00 00 00 00 00
+ * 00 e2 00 ca e2 0e 5f 00 00 00 00 00 00 00 00 00
* 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
* 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
* 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
* 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ca
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 9a
*
* ----------------
*
@@ -782,7 +782,7 @@ static const unsigned char test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz[] = {
* Vendor & Product Identification:
* Manufacturer: LNX
* Model: 52
- * Model year: 2025
+ * Made in: 2025
* Basic Display Parameters & Features:
* Digital display
* Maximum image size: 96 cm x 54 cm
@@ -805,21 +805,21 @@ static const unsigned char test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz[] = {
* Vfront 4 Vsync 5 Vback 36 Vpol P
* Display Product Name: 'Test EDID'
* Display Range Limits:
- * Monitor ranges (GTF): 24-85 Hz V, 24-94 kHz H, max dotclock 170 MHz
+ * Monitor ranges (GTF): 24-85 Hz V, 24-94 kHz H, max dotclock 300 MHz
* Dummy Descriptor:
* Extension blocks: 1
- * Checksum: 0xbb
+ * Checksum: 0xad
*
* ----------------
*
* Block 1, CTA-861 Extension Block:
* Revision: 3
+ * Underscans IT Video Formats by default
* Supports YCbCr 4:4:4
* Supports YCbCr 4:2:2
* Native detailed modes: 1
* Video Data Block:
- * VIC 16: 1920x1080 60.000000 Hz 16:9 67.500 kHz 148.500000 MHz (native)
- * VIC 95: 3840x2160 30.000000 Hz 16:9 67.500 kHz 297.000000 MHz
+ * VIC 16: 1920x1080 60.000000 Hz 16:9 67.500 kHz 148.500000 MHz
* Vendor-Specific Data Block (HDMI), OUI 00-0C-03:
* Source physical address: 1.0.0.0
* DC_48bit
@@ -830,40 +830,57 @@ static const unsigned char test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz[] = {
* Extended HDMI video details:
* Vendor-Specific Data Block (HDMI Forum), OUI C4-5D-D8:
* Version: 1
- * Maximum TMDS Character Rate: 200 MHz
* SCDC Present
* Supports 16-bits/component Deep Color 4:2:0 Pixel Encoding
* Supports 12-bits/component Deep Color 4:2:0 Pixel Encoding
* Supports 10-bits/component Deep Color 4:2:0 Pixel Encoding
- * YCbCr 4:2:0 Capability Map Data Block:
- * Empty Capability Map
+ * VRRmin: 0 Hz
+ * VRRmax: 0 Hz
+ * Video Capability Data Block:
+ * YCbCr quantization: Selectable (via AVI YQ)
+ * RGB quantization: Selectable (via AVI Q)
+ * PT scan behavior: No Data
+ * IT scan behavior: Always Underscanned
+ * CE scan behavior: Always Underscanned
* YCbCr 4:2:0 Video Data Block:
* VIC 95: 3840x2160 30.000000 Hz 16:9 67.500 kHz 297.000000 MHz
- * Checksum: 0xca
+ * Checksum: 0x9a Unused space in Extension Block: 88 bytes
+ *
+ * ----------------
+ *
+ * edid-decode 1.33.0
+ *
+ * Warnings:
+ *
+ * Block 1, CTA-861 Extension Block:
+ * YCbCr 4:2:0 Video Data Block: Some YCbCr 4:2:0 timings are invalid for HDMI 2.1
+ * (which requires an RGB timings pixel rate >= 590 MHz).
+ *
+ * EDID conformity: PASS
*/
static const unsigned char test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz[] = {
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x31, 0xd8, 0x34, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xff, 0x23, 0x01, 0x03, 0x80, 0x60, 0x36, 0x78,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x01, 0x03, 0x80, 0x60, 0x36, 0x78,
0x0f, 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26, 0x0f, 0x50, 0x54, 0x20,
0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3a, 0x80, 0x18, 0x71, 0x38,
0x2d, 0x40, 0x58, 0x2c, 0x45, 0x00, 0xc0, 0x1c, 0x32, 0x00, 0x00, 0x1e,
0x00, 0x00, 0x00, 0xfc, 0x00, 0x54, 0x65, 0x73, 0x74, 0x20, 0x45, 0x44,
0x49, 0x44, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x18,
- 0x55, 0x18, 0x5e, 0x11, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x55, 0x18, 0x5e, 0x1e, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xbb, 0x02, 0x03, 0x29, 0x31,
- 0x42, 0x90, 0x5f, 0x6c, 0x03, 0x0c, 0x00, 0x10, 0x00, 0x78, 0x28, 0x20,
- 0x00, 0x00, 0x01, 0x03, 0x6d, 0xd8, 0x5d, 0xc4, 0x01, 0x28, 0x80, 0x07,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0x0f, 0x00, 0x00, 0xe2, 0x0e,
- 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xad, 0x02, 0x03, 0x27, 0xb1,
+ 0x41, 0x10, 0x6c, 0x03, 0x0c, 0x00, 0x10, 0x00, 0x78, 0x28, 0x20, 0x00,
+ 0x00, 0x01, 0x03, 0x6d, 0xd8, 0x5d, 0xc4, 0x01, 0x00, 0x80, 0x07, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xe2, 0x00, 0xca, 0xe2, 0x0e, 0x5f, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0xca
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x9a,
};
/*
--
2.54.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH v7 29/30] drm/tests: edid: Fix conformity for 1080p+4K YUV420 200MHz EDID
@ 2026-06-01 22:44 ` Cristian Ciocaltea
0 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
The test EDID added by commit 58fe1d78605e ("drm/tests: hdmi: Provide
EDID supporting 4K@30Hz with YUV420 only") fails 'edid-decode --check'
(v1.33.0) with the following issues:
Warnings:
Block 1, CTA-861 Extension Block:
IT Video Formats are overscanned by default, but normally this should be underscanned.
YCbCr 4:2:0 Video Data Block: Some YCbCr 4:2:0 timings are invalid for HDMI 2.1
(which requires an RGB timings pixel rate >= 590 MHz).
EDID:
Base EDID: Some timings are out of range of the Monitor Ranges:
Maximum Clock: 297.000 MHz (Monitor: 170.000 MHz)
CTA-861: Multiple native progressive timings are defined.
Failures:
Block 0, Base EDID:
Vendor & Product Identification: EDID 1.3 does not support week 0xff.
Block 1, CTA-861 Extension Block:
Vendor-Specific Data Block (HDMI Forum), OUI C4-5D-D8: Max TMDS rate is > 0 and <= 340 or > 600.
YCbCr 4:2:0 Capability Map Data Block: Empty Capability Map.
YCbCr 4:2:0 Video Data Block: YCbCr 4:2:0-only VIC 95 is also a regular VIC.
Missing VCDB, needed for Set Selectable RGB Quantization to avoid interop issues.
EDID:
CTA-861: The maximum HDMI TMDS clock is 200000 kHz, but one or more video timings go up to 297000 kHz.
Address them while preserving the advertised maximum resolutions, BPC
and TMDS clock used by the existing KUnit tests:
- Week 0xff is not valid for EDID 1.3; set it to 0x00 so that the Model
year field becomes a regular Year of Manufacture.
- The HDMI Forum VSDB Max TMDS Character Rate must be 0 when no rate
above 340 MHz is supported. The HDMI VSDB still advertises 200 MHz as
Max TMDS Clock.
- VIC 95 (3840x2160@30Hz) was reported as YUV420-only but was listed in
both the regular Video Data Block and the YCbCr 4:2:0 Video Data
Block. Drop it from the regular VDB (so it stays advertised in the
4:2:0 VDB only) and remove the now unnecessary empty YCbCr 4:2:0
Capability Map Data Block.
- Add a Video Capability Data Block advertising selectable RGB and YCC
quantization range plus underscan for IT/CE formats; also set the 'IT
Video Formats Underscanned' bit in the CTA-861 extension header to
match.
- Bump the Display Range Limits max pixel clock from 170 MHz to 300 MHz
so it covers the 297 MHz pixel rate of VIC 95.
- Drop the 'native' flag from VIC 16 in the Video Data Block so it is no
longer flagged as a second native progressive timing alongside the
preferred DTD.
The only remaining warning is HDMI 2.1 related and can be ignored, as it
requires that any mode listed in the YCbCr 4:2:0 Video Data Block must
have a corresponding RGB pixel clock >= 590 MHz.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/tests/drm_kunit_edid.h | 65 +++++++++++++++++++++-------------
1 file changed, 41 insertions(+), 24 deletions(-)
diff --git a/drivers/gpu/drm/tests/drm_kunit_edid.h b/drivers/gpu/drm/tests/drm_kunit_edid.h
index 9b318f7d364e..618b42d2fd8e 100644
--- a/drivers/gpu/drm/tests/drm_kunit_edid.h
+++ b/drivers/gpu/drm/tests/drm_kunit_edid.h
@@ -758,22 +758,22 @@ static const unsigned char test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz[] = {
* edid-decode (hex):
*
* 00 ff ff ff ff ff ff 00 31 d8 34 00 00 00 00 00
- * ff 23 01 03 80 60 36 78 0f ee 91 a3 54 4c 99 26
+ * 00 23 01 03 80 60 36 78 0f ee 91 a3 54 4c 99 26
* 0f 50 54 20 00 00 01 01 01 01 01 01 01 01 01 01
* 01 01 01 01 01 01 02 3a 80 18 71 38 2d 40 58 2c
* 45 00 c0 1c 32 00 00 1e 00 00 00 fc 00 54 65 73
* 74 20 45 44 49 44 0a 20 20 20 00 00 00 fd 00 18
- * 55 18 5e 11 00 0a 20 20 20 20 20 20 00 00 00 10
- * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 bb
+ * 55 18 5e 1e 00 0a 20 20 20 20 20 20 00 00 00 10
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 ad
*
- * 02 03 29 31 42 90 5f 6c 03 0c 00 10 00 78 28 20
- * 00 00 01 03 6d d8 5d c4 01 28 80 07 00 00 00 00
- * 00 00 e3 0f 00 00 e2 0e 5f 00 00 00 00 00 00 00
+ * 02 03 27 b1 41 10 6c 03 0c 00 10 00 78 28 20 00
+ * 00 01 03 6d d8 5d c4 01 00 80 07 00 00 00 00 00
+ * 00 e2 00 ca e2 0e 5f 00 00 00 00 00 00 00 00 00
* 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
* 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
* 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
* 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ca
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 9a
*
* ----------------
*
@@ -782,7 +782,7 @@ static const unsigned char test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz[] = {
* Vendor & Product Identification:
* Manufacturer: LNX
* Model: 52
- * Model year: 2025
+ * Made in: 2025
* Basic Display Parameters & Features:
* Digital display
* Maximum image size: 96 cm x 54 cm
@@ -805,21 +805,21 @@ static const unsigned char test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz[] = {
* Vfront 4 Vsync 5 Vback 36 Vpol P
* Display Product Name: 'Test EDID'
* Display Range Limits:
- * Monitor ranges (GTF): 24-85 Hz V, 24-94 kHz H, max dotclock 170 MHz
+ * Monitor ranges (GTF): 24-85 Hz V, 24-94 kHz H, max dotclock 300 MHz
* Dummy Descriptor:
* Extension blocks: 1
- * Checksum: 0xbb
+ * Checksum: 0xad
*
* ----------------
*
* Block 1, CTA-861 Extension Block:
* Revision: 3
+ * Underscans IT Video Formats by default
* Supports YCbCr 4:4:4
* Supports YCbCr 4:2:2
* Native detailed modes: 1
* Video Data Block:
- * VIC 16: 1920x1080 60.000000 Hz 16:9 67.500 kHz 148.500000 MHz (native)
- * VIC 95: 3840x2160 30.000000 Hz 16:9 67.500 kHz 297.000000 MHz
+ * VIC 16: 1920x1080 60.000000 Hz 16:9 67.500 kHz 148.500000 MHz
* Vendor-Specific Data Block (HDMI), OUI 00-0C-03:
* Source physical address: 1.0.0.0
* DC_48bit
@@ -830,40 +830,57 @@ static const unsigned char test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz[] = {
* Extended HDMI video details:
* Vendor-Specific Data Block (HDMI Forum), OUI C4-5D-D8:
* Version: 1
- * Maximum TMDS Character Rate: 200 MHz
* SCDC Present
* Supports 16-bits/component Deep Color 4:2:0 Pixel Encoding
* Supports 12-bits/component Deep Color 4:2:0 Pixel Encoding
* Supports 10-bits/component Deep Color 4:2:0 Pixel Encoding
- * YCbCr 4:2:0 Capability Map Data Block:
- * Empty Capability Map
+ * VRRmin: 0 Hz
+ * VRRmax: 0 Hz
+ * Video Capability Data Block:
+ * YCbCr quantization: Selectable (via AVI YQ)
+ * RGB quantization: Selectable (via AVI Q)
+ * PT scan behavior: No Data
+ * IT scan behavior: Always Underscanned
+ * CE scan behavior: Always Underscanned
* YCbCr 4:2:0 Video Data Block:
* VIC 95: 3840x2160 30.000000 Hz 16:9 67.500 kHz 297.000000 MHz
- * Checksum: 0xca
+ * Checksum: 0x9a Unused space in Extension Block: 88 bytes
+ *
+ * ----------------
+ *
+ * edid-decode 1.33.0
+ *
+ * Warnings:
+ *
+ * Block 1, CTA-861 Extension Block:
+ * YCbCr 4:2:0 Video Data Block: Some YCbCr 4:2:0 timings are invalid for HDMI 2.1
+ * (which requires an RGB timings pixel rate >= 590 MHz).
+ *
+ * EDID conformity: PASS
*/
static const unsigned char test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz[] = {
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x31, 0xd8, 0x34, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xff, 0x23, 0x01, 0x03, 0x80, 0x60, 0x36, 0x78,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x01, 0x03, 0x80, 0x60, 0x36, 0x78,
0x0f, 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26, 0x0f, 0x50, 0x54, 0x20,
0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3a, 0x80, 0x18, 0x71, 0x38,
0x2d, 0x40, 0x58, 0x2c, 0x45, 0x00, 0xc0, 0x1c, 0x32, 0x00, 0x00, 0x1e,
0x00, 0x00, 0x00, 0xfc, 0x00, 0x54, 0x65, 0x73, 0x74, 0x20, 0x45, 0x44,
0x49, 0x44, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x18,
- 0x55, 0x18, 0x5e, 0x11, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x55, 0x18, 0x5e, 0x1e, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xbb, 0x02, 0x03, 0x29, 0x31,
- 0x42, 0x90, 0x5f, 0x6c, 0x03, 0x0c, 0x00, 0x10, 0x00, 0x78, 0x28, 0x20,
- 0x00, 0x00, 0x01, 0x03, 0x6d, 0xd8, 0x5d, 0xc4, 0x01, 0x28, 0x80, 0x07,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0x0f, 0x00, 0x00, 0xe2, 0x0e,
- 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xad, 0x02, 0x03, 0x27, 0xb1,
+ 0x41, 0x10, 0x6c, 0x03, 0x0c, 0x00, 0x10, 0x00, 0x78, 0x28, 0x20, 0x00,
+ 0x00, 0x01, 0x03, 0x6d, 0xd8, 0x5d, 0xc4, 0x01, 0x00, 0x80, 0x07, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xe2, 0x00, 0xca, 0xe2, 0x0e, 0x5f, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0xca
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x9a,
};
/*
--
2.54.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH v7 30/30] drm/tests: edid: Fix conformity for 4K RGB/YUV 340MHz EDID
2026-06-01 22:44 ` Cristian Ciocaltea
@ 2026-06-01 22:44 ` Cristian Ciocaltea
-1 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
The test EDID added by commit 54a5f1c4d5f8 ("drm/tests: hdmi: Provide
EDID supporting 4K@30Hz with RGB/YUV") fails 'edid-decode --check'
(v1.33.0) with the following issues:
Warnings:
Block 1, CTA-861 Extension Block:
IT Video Formats are overscanned by default, but normally this should be underscanned.
YCbCr 4:2:0 Capability Map Data Block: Some YCbCr 4:2:0 timings are invalid for HDMI 2.1
(which requires an RGB timings pixel rate >= 590 MHz).
Failures:
Block 0, Base EDID:
Vendor & Product Identification: EDID 1.3 does not support week 0xff.
Detailed Timing Descriptor #1: Mismatch of image size 1600x900 mm vs display size 960x540 mm.
Block 1, CTA-861 Extension Block:
Vendor-Specific Data Block (HDMI Forum), OUI C4-5D-D8: Max TMDS rate is > 0 and <= 340 or > 600.
YCbCr 4:2:0 Video Data Block: This Data Block is empty.
Missing VCDB, needed for Set Selectable RGB Quantization to avoid interop issues.
EDID:
Base EDID: The DTD max image size is 1600x900mm, which is larger than the display size 960.0x540.0mm.
Address them while preserving the advertised maximum resolution, BPC and
TMDS clock used by the existing KUnit tests:
- Week 0xff is not valid for EDID 1.3; set it to 0x00 so that the Model
year field becomes a regular Year of Manufacture.
- Align the DTD image size with the Basic Display Parameters maximum
image size (96 cm x 54 cm).
- The HDMI Forum VSDB Max TMDS Character Rate must be 0 when no rate
above 340 MHz is supported. The HDMI VSDB still advertises 340 MHz as
Max TMDS Clock.
- Drop the empty YCbCr 4:2:0 Video Data Block. VIC 95 (3840x2160@30Hz)
remains advertised as YUV420-capable via the YCbCr 4:2:0 Capability
Map Data Block, which references the corresponding entry in the
regular Video Data Block.
- Add a Video Capability Data Block advertising selectable RGB and YCC
quantization range plus underscan for IT/CE formats; also set the 'IT
Video Formats Underscanned' bit in the CTA-861 extension header to
match.
The only remaining warning is HDMI 2.1 related and can be ignored, as it
requires that any mode listed in the YCbCr 4:2:0 Video Data Block must
have a corresponding RGB pixel clock >= 590 MHz.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/tests/drm_kunit_edid.h | 57 ++++++++++++++++++++++------------
1 file changed, 38 insertions(+), 19 deletions(-)
diff --git a/drivers/gpu/drm/tests/drm_kunit_edid.h b/drivers/gpu/drm/tests/drm_kunit_edid.h
index 618b42d2fd8e..9a326c9e3f7b 100644
--- a/drivers/gpu/drm/tests/drm_kunit_edid.h
+++ b/drivers/gpu/drm/tests/drm_kunit_edid.h
@@ -891,22 +891,22 @@ static const unsigned char test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz[
* edid-decode (hex):
*
* 00 ff ff ff ff ff ff 00 31 d8 34 00 00 00 00 00
- * ff 23 01 03 80 60 36 78 0f ee 91 a3 54 4c 99 26
+ * 00 23 01 03 80 60 36 78 0f ee 91 a3 54 4c 99 26
* 0f 50 54 20 00 00 01 01 01 01 01 01 01 01 01 01
* 01 01 01 01 01 01 04 74 00 30 f2 70 5a 80 b0 58
- * 8a 00 40 84 63 00 00 1e 00 00 00 fc 00 54 65 73
+ * 8a 00 c0 1c 32 00 00 1e 00 00 00 fc 00 54 65 73
* 74 20 45 44 49 44 0a 20 20 20 00 00 00 fd 00 18
* 55 18 5e 22 00 0a 20 20 20 20 20 20 00 00 00 10
- * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 ce
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 e6
*
- * 02 03 27 31 41 5f 6c 03 0c 00 10 00 78 44 20 00
- * 00 01 03 6d d8 5d c4 01 44 80 07 00 00 00 00 00
- * 00 e3 0f 01 00 e1 0e 00 00 00 00 00 00 00 00 00
+ * 02 03 28 b1 41 5f 6c 03 0c 00 10 00 78 44 20 00
+ * 00 01 03 6d d8 5d c4 01 00 80 07 00 00 00 00 00
+ * 00 e2 00 ca e3 0f 01 00 00 00 00 00 00 00 00 00
* 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
* 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
* 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
* 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 84
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 8a
*
* ----------------
*
@@ -915,7 +915,7 @@ static const unsigned char test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz[
* Vendor & Product Identification:
* Manufacturer: LNX
* Model: 52
- * Model year: 2025
+ * Made in: 2025
* Basic Display Parameters & Features:
* Digital display
* Maximum image size: 96 cm x 54 cm
@@ -933,7 +933,7 @@ static const unsigned char test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz[
* DMT 0x04: 640x480 59.940476 Hz 4:3 31.469 kHz 25.175000 MHz
* Standard Timings: none
* Detailed Timing Descriptors:
- * DTD 1: 3840x2160 30.000000 Hz 16:9 67.500 kHz 297.000000 MHz (1600 mm x 900 mm)
+ * DTD 1: 3840x2160 30.000000 Hz 16:9 67.500 kHz 297.000000 MHz (960 mm x 540 mm)
* Hfront 176 Hsync 88 Hback 296 Hpol P
* Vfront 8 Vsync 10 Vback 72 Vpol P
* Display Product Name: 'Test EDID'
@@ -941,12 +941,13 @@ static const unsigned char test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz[
* Monitor ranges (GTF): 24-85 Hz V, 24-94 kHz H, max dotclock 340 MHz
* Dummy Descriptor:
* Extension blocks: 1
- * Checksum: 0xce
+ * Checksum: 0xe6
*
* ----------------
*
* Block 1, CTA-861 Extension Block:
* Revision: 3
+ * Underscans IT Video Formats by default
* Supports YCbCr 4:4:4
* Supports YCbCr 4:2:2
* Native detailed modes: 1
@@ -962,31 +963,49 @@ static const unsigned char test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz[
* Extended HDMI video details:
* Vendor-Specific Data Block (HDMI Forum), OUI C4-5D-D8:
* Version: 1
- * Maximum TMDS Character Rate: 340 MHz
* SCDC Present
* Supports 16-bits/component Deep Color 4:2:0 Pixel Encoding
* Supports 12-bits/component Deep Color 4:2:0 Pixel Encoding
* Supports 10-bits/component Deep Color 4:2:0 Pixel Encoding
+ * VRRmin: 0 Hz
+ * VRRmax: 0 Hz
+ * Video Capability Data Block:
+ * YCbCr quantization: Selectable (via AVI YQ)
+ * RGB quantization: Selectable (via AVI Q)
+ * PT scan behavior: No Data
+ * IT scan behavior: Always Underscanned
+ * CE scan behavior: Always Underscanned
* YCbCr 4:2:0 Capability Map Data Block:
* VIC 95: 3840x2160 30.000000 Hz 16:9 67.500 kHz 297.000000 MHz
- * YCbCr 4:2:0 Video Data Block:
- * Checksum: 0x84
+ * Checksum: 0x8a Unused space in Extension Block: 87 bytes
+ *
+ * ----------------
+ *
+ * edid-decode 1.33.0
+ *
+ * Warnings:
+ *
+ * Block 1, CTA-861 Extension Block:
+ * YCbCr 4:2:0 Capability Map Data Block: Some YCbCr 4:2:0 timings are invalid for HDMI 2.1
+ * (which requires an RGB timings pixel rate >= 590 MHz).
+ *
+ * EDID conformity: PASS
*/
static const unsigned char test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz[] = {
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x31, 0xd8, 0x34, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xff, 0x23, 0x01, 0x03, 0x80, 0x60, 0x36, 0x78,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x01, 0x03, 0x80, 0x60, 0x36, 0x78,
0x0f, 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26, 0x0f, 0x50, 0x54, 0x20,
0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x74, 0x00, 0x30, 0xf2, 0x70,
- 0x5a, 0x80, 0xb0, 0x58, 0x8a, 0x00, 0x40, 0x84, 0x63, 0x00, 0x00, 0x1e,
+ 0x5a, 0x80, 0xb0, 0x58, 0x8a, 0x00, 0xc0, 0x1c, 0x32, 0x00, 0x00, 0x1e,
0x00, 0x00, 0x00, 0xfc, 0x00, 0x54, 0x65, 0x73, 0x74, 0x20, 0x45, 0x44,
0x49, 0x44, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x18,
0x55, 0x18, 0x5e, 0x22, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xce, 0x02, 0x03, 0x27, 0x31,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xe6, 0x02, 0x03, 0x28, 0xb1,
0x41, 0x5f, 0x6c, 0x03, 0x0c, 0x00, 0x10, 0x00, 0x78, 0x44, 0x20, 0x00,
- 0x00, 0x01, 0x03, 0x6d, 0xd8, 0x5d, 0xc4, 0x01, 0x44, 0x80, 0x07, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0x0f, 0x01, 0x00, 0xe1, 0x0e, 0x00,
+ 0x00, 0x01, 0x03, 0x6d, 0xd8, 0x5d, 0xc4, 0x01, 0x00, 0x80, 0x07, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xe2, 0x00, 0xca, 0xe3, 0x0f, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -994,7 +1013,7 @@ static const unsigned char test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x84
+ 0x00, 0x00, 0x00, 0x8a,
};
/*
--
2.54.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH v7 30/30] drm/tests: edid: Fix conformity for 4K RGB/YUV 340MHz EDID
@ 2026-06-01 22:44 ` Cristian Ciocaltea
0 siblings, 0 replies; 72+ messages in thread
From: Cristian Ciocaltea @ 2026-06-01 22:44 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
The test EDID added by commit 54a5f1c4d5f8 ("drm/tests: hdmi: Provide
EDID supporting 4K@30Hz with RGB/YUV") fails 'edid-decode --check'
(v1.33.0) with the following issues:
Warnings:
Block 1, CTA-861 Extension Block:
IT Video Formats are overscanned by default, but normally this should be underscanned.
YCbCr 4:2:0 Capability Map Data Block: Some YCbCr 4:2:0 timings are invalid for HDMI 2.1
(which requires an RGB timings pixel rate >= 590 MHz).
Failures:
Block 0, Base EDID:
Vendor & Product Identification: EDID 1.3 does not support week 0xff.
Detailed Timing Descriptor #1: Mismatch of image size 1600x900 mm vs display size 960x540 mm.
Block 1, CTA-861 Extension Block:
Vendor-Specific Data Block (HDMI Forum), OUI C4-5D-D8: Max TMDS rate is > 0 and <= 340 or > 600.
YCbCr 4:2:0 Video Data Block: This Data Block is empty.
Missing VCDB, needed for Set Selectable RGB Quantization to avoid interop issues.
EDID:
Base EDID: The DTD max image size is 1600x900mm, which is larger than the display size 960.0x540.0mm.
Address them while preserving the advertised maximum resolution, BPC and
TMDS clock used by the existing KUnit tests:
- Week 0xff is not valid for EDID 1.3; set it to 0x00 so that the Model
year field becomes a regular Year of Manufacture.
- Align the DTD image size with the Basic Display Parameters maximum
image size (96 cm x 54 cm).
- The HDMI Forum VSDB Max TMDS Character Rate must be 0 when no rate
above 340 MHz is supported. The HDMI VSDB still advertises 340 MHz as
Max TMDS Clock.
- Drop the empty YCbCr 4:2:0 Video Data Block. VIC 95 (3840x2160@30Hz)
remains advertised as YUV420-capable via the YCbCr 4:2:0 Capability
Map Data Block, which references the corresponding entry in the
regular Video Data Block.
- Add a Video Capability Data Block advertising selectable RGB and YCC
quantization range plus underscan for IT/CE formats; also set the 'IT
Video Formats Underscanned' bit in the CTA-861 extension header to
match.
The only remaining warning is HDMI 2.1 related and can be ignored, as it
requires that any mode listed in the YCbCr 4:2:0 Video Data Block must
have a corresponding RGB pixel clock >= 590 MHz.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/tests/drm_kunit_edid.h | 57 ++++++++++++++++++++++------------
1 file changed, 38 insertions(+), 19 deletions(-)
diff --git a/drivers/gpu/drm/tests/drm_kunit_edid.h b/drivers/gpu/drm/tests/drm_kunit_edid.h
index 618b42d2fd8e..9a326c9e3f7b 100644
--- a/drivers/gpu/drm/tests/drm_kunit_edid.h
+++ b/drivers/gpu/drm/tests/drm_kunit_edid.h
@@ -891,22 +891,22 @@ static const unsigned char test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz[
* edid-decode (hex):
*
* 00 ff ff ff ff ff ff 00 31 d8 34 00 00 00 00 00
- * ff 23 01 03 80 60 36 78 0f ee 91 a3 54 4c 99 26
+ * 00 23 01 03 80 60 36 78 0f ee 91 a3 54 4c 99 26
* 0f 50 54 20 00 00 01 01 01 01 01 01 01 01 01 01
* 01 01 01 01 01 01 04 74 00 30 f2 70 5a 80 b0 58
- * 8a 00 40 84 63 00 00 1e 00 00 00 fc 00 54 65 73
+ * 8a 00 c0 1c 32 00 00 1e 00 00 00 fc 00 54 65 73
* 74 20 45 44 49 44 0a 20 20 20 00 00 00 fd 00 18
* 55 18 5e 22 00 0a 20 20 20 20 20 20 00 00 00 10
- * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 ce
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 e6
*
- * 02 03 27 31 41 5f 6c 03 0c 00 10 00 78 44 20 00
- * 00 01 03 6d d8 5d c4 01 44 80 07 00 00 00 00 00
- * 00 e3 0f 01 00 e1 0e 00 00 00 00 00 00 00 00 00
+ * 02 03 28 b1 41 5f 6c 03 0c 00 10 00 78 44 20 00
+ * 00 01 03 6d d8 5d c4 01 00 80 07 00 00 00 00 00
+ * 00 e2 00 ca e3 0f 01 00 00 00 00 00 00 00 00 00
* 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
* 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
* 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
* 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 84
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 8a
*
* ----------------
*
@@ -915,7 +915,7 @@ static const unsigned char test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz[
* Vendor & Product Identification:
* Manufacturer: LNX
* Model: 52
- * Model year: 2025
+ * Made in: 2025
* Basic Display Parameters & Features:
* Digital display
* Maximum image size: 96 cm x 54 cm
@@ -933,7 +933,7 @@ static const unsigned char test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz[
* DMT 0x04: 640x480 59.940476 Hz 4:3 31.469 kHz 25.175000 MHz
* Standard Timings: none
* Detailed Timing Descriptors:
- * DTD 1: 3840x2160 30.000000 Hz 16:9 67.500 kHz 297.000000 MHz (1600 mm x 900 mm)
+ * DTD 1: 3840x2160 30.000000 Hz 16:9 67.500 kHz 297.000000 MHz (960 mm x 540 mm)
* Hfront 176 Hsync 88 Hback 296 Hpol P
* Vfront 8 Vsync 10 Vback 72 Vpol P
* Display Product Name: 'Test EDID'
@@ -941,12 +941,13 @@ static const unsigned char test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz[
* Monitor ranges (GTF): 24-85 Hz V, 24-94 kHz H, max dotclock 340 MHz
* Dummy Descriptor:
* Extension blocks: 1
- * Checksum: 0xce
+ * Checksum: 0xe6
*
* ----------------
*
* Block 1, CTA-861 Extension Block:
* Revision: 3
+ * Underscans IT Video Formats by default
* Supports YCbCr 4:4:4
* Supports YCbCr 4:2:2
* Native detailed modes: 1
@@ -962,31 +963,49 @@ static const unsigned char test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz[
* Extended HDMI video details:
* Vendor-Specific Data Block (HDMI Forum), OUI C4-5D-D8:
* Version: 1
- * Maximum TMDS Character Rate: 340 MHz
* SCDC Present
* Supports 16-bits/component Deep Color 4:2:0 Pixel Encoding
* Supports 12-bits/component Deep Color 4:2:0 Pixel Encoding
* Supports 10-bits/component Deep Color 4:2:0 Pixel Encoding
+ * VRRmin: 0 Hz
+ * VRRmax: 0 Hz
+ * Video Capability Data Block:
+ * YCbCr quantization: Selectable (via AVI YQ)
+ * RGB quantization: Selectable (via AVI Q)
+ * PT scan behavior: No Data
+ * IT scan behavior: Always Underscanned
+ * CE scan behavior: Always Underscanned
* YCbCr 4:2:0 Capability Map Data Block:
* VIC 95: 3840x2160 30.000000 Hz 16:9 67.500 kHz 297.000000 MHz
- * YCbCr 4:2:0 Video Data Block:
- * Checksum: 0x84
+ * Checksum: 0x8a Unused space in Extension Block: 87 bytes
+ *
+ * ----------------
+ *
+ * edid-decode 1.33.0
+ *
+ * Warnings:
+ *
+ * Block 1, CTA-861 Extension Block:
+ * YCbCr 4:2:0 Capability Map Data Block: Some YCbCr 4:2:0 timings are invalid for HDMI 2.1
+ * (which requires an RGB timings pixel rate >= 590 MHz).
+ *
+ * EDID conformity: PASS
*/
static const unsigned char test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz[] = {
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x31, 0xd8, 0x34, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xff, 0x23, 0x01, 0x03, 0x80, 0x60, 0x36, 0x78,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x01, 0x03, 0x80, 0x60, 0x36, 0x78,
0x0f, 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26, 0x0f, 0x50, 0x54, 0x20,
0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x74, 0x00, 0x30, 0xf2, 0x70,
- 0x5a, 0x80, 0xb0, 0x58, 0x8a, 0x00, 0x40, 0x84, 0x63, 0x00, 0x00, 0x1e,
+ 0x5a, 0x80, 0xb0, 0x58, 0x8a, 0x00, 0xc0, 0x1c, 0x32, 0x00, 0x00, 0x1e,
0x00, 0x00, 0x00, 0xfc, 0x00, 0x54, 0x65, 0x73, 0x74, 0x20, 0x45, 0x44,
0x49, 0x44, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x18,
0x55, 0x18, 0x5e, 0x22, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xce, 0x02, 0x03, 0x27, 0x31,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xe6, 0x02, 0x03, 0x28, 0xb1,
0x41, 0x5f, 0x6c, 0x03, 0x0c, 0x00, 0x10, 0x00, 0x78, 0x44, 0x20, 0x00,
- 0x00, 0x01, 0x03, 0x6d, 0xd8, 0x5d, 0xc4, 0x01, 0x44, 0x80, 0x07, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0x0f, 0x01, 0x00, 0xe1, 0x0e, 0x00,
+ 0x00, 0x01, 0x03, 0x6d, 0xd8, 0x5d, 0xc4, 0x01, 0x00, 0x80, 0x07, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xe2, 0x00, 0xca, 0xe3, 0x0f, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -994,7 +1013,7 @@ static const unsigned char test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x84
+ 0x00, 0x00, 0x00, 0x8a,
};
/*
--
2.54.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 72+ messages in thread