* [PATCH v10 00/69] Add HDMI 2.0 support to DW HDMI QP TX
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Dmitry Baryshkov, Sashiko, 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 at the DRM infrastructure level, the series first
introduces the HDMI version enum, then prepares for changing the
signature of drmm_connector_hdmi_init(), i.e. dropping the vendor,
product, supported_formats and max_bpc arguments, which are being moved
into struct drm_connector_hdmi_funcs, by temporarily renaming the helper
to drmm_connector_hdmi_ini2(). This lets the new signature be
introduced under the original name while callers are converted
incrementally. Note the transitional name matches the original's length
so continuation-line arguments stay aligned to the opening parenthesis,
keeping the diff to the identifier itself and avoiding re-alignment
churn.
Appending more HDMI-specific arguments to the init function would not
scale well, hence the hdmi_funcs struct is extended with new fields:
supported_hdmi_ver, supported_tmds_char_rate. These are used to
infer and/or limit the maximum TMDS character rate permitted for the
connector.
Patches 6-11 build the connector and bridge scrambling infrastructure on
top: the connector scrambler callbacks/flags, the scdc-helper
additions (connector-prefixed debug macro and SCDC version helper), and
the HDMI scrambling management helpers including SCDC source-version
advertisement.
Patches 12-23 wires this up through the hdmi-state-helper and bridge
connector layers: source TMDS rate validation, hotplug SCDC state sync
and the scrambling requirement, new source-side scrambling bridge ops,
the switch to a cached-status, atomic-aware .detect_ctx() connector
helper, and finally hooking up the HDMI 2.0 scrambler callbacks.
The SCDC scrambling feature itself is implemented in the DW HDMI QP
bridge driver, alongside i2c error-message rate limiting,
.enable_hpd()/.disable_hpd() PHY ops and a dw_hdmi_qp_hpd_notify()
helper (patches 24-28).
Patches 29-38 cover the Rockchip platform driver and HPD handling: bug
fixes, minor cleanups, avoiding spurious HDP IRQ wakeups, masking the
RK3576 HPD IRQ in io_init, implementing the .{enable|disable}_hpd() PHY
ops, switching HPD reports to dw_hdmi_qp_hpd_notify() to restrict events
to the affected connector, dropping the now-unused .setup_hpd() PHY op.
Patches 39-46 convert VC4 HDMI to the common infrastructure as a proof
of reuse: adopting the shared TMDS char rate constants, switching to
drm_hdmi_mode_needs_scrambling() and force_ctx(), proper -EDEADLK
handling, and replacing the driver-local scrambling implementation with
the common SCDC scrambling helpers.
Patches 47-55 advertise supported version for all HDMI
connectors/bridges, except the MediaTek HDMI driver (for now), as it
requires non-trivial changes: there's a core library shared between two
drivers, one being HDMI 2.0 compliant.
Patches 56-65 add KUnit tests: HDMI caps-based init coverage and
source-side scrambler validation for the connector, conversion of
hdmi_state_helper to the new drmm_connector_hdmi_init() with
max_tmds_char_rate validation, a new 4K@60Hz 600MHz TMDS EDID,
source-side scrambling decision coverage, and conformity fixes for the
existing 1080p+4K YUV420 200MHz and 4K RGB/YUV 340MHz test EDID blobs.
Eventually patches 66-69 remove the now unused
drmm_connector_hdmi_ini2() helper and drop redundant hdmi fields from
connector structs: vendor, product, supported_formats and max_bpc.
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)
Note that commit d87773de9efe1 ("clocksource/drivers/arm_arch_timer:
Default to EL2 virtual timer when running VHE"), introduced in v7.2-rc1,
causes Raspberry Pi 5 to hang during boot. Reverting the commit
restores normal boot. This issue has already been reported in [1];
alternatively, the workaround proposed in [2] can be applied.
Regards,
Cristian
[1] https://lore.kernel.org/all/ea15cce1-b393-43f6-8d58-3d6f90f0c0cd@samsung.com/
[2] https://lore.kernel.org/all/20260619204832.586079-1-dan@reactivated.net/
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
Changes in v10:
- Collected T-b from Diederik on relevant patches
- Collected R-b from Dmitry on patch renaming drmm_connector_hdmi_init()
- Added new patches to address Sashiko findings:
* drm/connector: hdmi: Handle reset() state allocation failure
* drm/bridge: Fix unlocked list_del in drm_bridge_add()
* drm/bridge: Fix unlocked list access in drm_bridge_attach()
* drm/rockchip: dw_hdmi_qp: Cancel pending HPD work on suspend
* drm/probe-helper: Introduce .force_ctx() connector callback
* drm/display: bridge_connector: Switch to .force_ctx() connector
helper
* drm/vc4: hdmi: Switch to .force_ctx() connector helper
* drm/display: hdmi-state-helper: Drop
drm_atomic_helper_connector_hdmi_force()
- Updated "drm/connector: Add drmm_connector_hdmi_init() with new
signature" to check if the reset callback failed to allocate memory
- Updated "drm/display: hdmi-state-helper: Pass acquire ctx to hotplug
helpers" to introduce drm_atomic_helper_connector_hdmi_force_ctx()
implementation and drop the conflicting local ctx from
drm_atomic_helper_connector_hdmi_force()
- Updated "drm/display: hdmi: Add HDMI 2.0 scrambling management
helpers" to bail early in the work handler on
drm_connector_is_unregistered()
- Updated "drm/bridge: dw-hdmi-qp: Provide dw_hdmi_qp_hpd_notify()
helper" to use READ_ONCE/WRITE_ONCE on hdmi->curr_conn
- Reworked "drm/rockchip: dw_hdmi_qp: Fix NULL deref in PM ops on
incomplete bind" into "drm/rockchip: dw_hdmi_qp: Fix invalid drvdata
access in PM ops"
- Fixed "drm/rockchip: rk3066_hdmi: Advertise HDMI 1.4 capabilities" to
set the expected HDMI_VERSION_1_4 instead of HDMI_VERSION_1_3
- Fixed all KUnit tests that created a dangling pointer by storing the
address of a stack-allocated drm_connector_hdmi_funcs structure into a
persistent device-managed object
- Fixed flawed logic in "drm/tests: connector: Add HDMI
max_tmds_char_rate init coverage" causing a couple of rate limit
rejection tests to pass for the wrong reason
- Rebased series onto latest drm-misc-next
- Link to v9: https://patch.msgid.link/20260723-dw-hdmi-qp-scramb-v9-0-4fb12ea22ac9@collabora.com
Changes in v9:
- Collected A-b, R-b, T-b tags from Dmitry, Maxime, Maud
- Dropped misleading "HDMI_VERSION_UNKNOWN means legacy/default
behaviour" from drm_connector_hdmi_caps.supported_hdmi_ver
documentation
- Warned in drm_bridge_add() if an HDMI bridge leaves supported_hdmi_ver
unset
- Added max_tmds_char_rate to drm_bridge struct and wire it through
drm_bridge_connector_init() along with supported_hdmi_ver
- Got rid of connector's scrambler_supported flag and, instead, relied
on checking the presence of scrambler callbacks via a new
drm_connector_hdmi_scrambler_supported() helper (Dmitry)
- Dropped HDMI connector scdc_cb callback and introduced
scdc_work_initialized flag to perform lazy initialization and guard
the teardown paths against touching an uninitialized work item
- Unconditionally checked connector->hdmi.max_tmds_char_rate in
"drm/display: hdmi-state-helper: Add fallback TMDS rate validation"
and performed s/fallback/source/ in commit subject & description
(Maxime)
- Added a TODO comment for checking
drm_display_info.hdmi.scdc.scrambling.low_rates in "drm/display:
hdmi-state-helper: Set HDMI scrambling requirement" patch (Maxime)
- Moved the prototype changes from "drm/display: hdmi-state-helper: Sync
SCDC state on hotplug" into a dedicated "drm/display:
hdmi-state-helper: Pass acquire ctx to hotplug helpers" patch; also
switched ctx and status args ordering, for consistency with
detect_ctx() signature (Maxime)
- Ensured HDMI connector's SCDC delayed work is explicitly canceled
during connector cleanup (Sashiko)
- Fixed a potential NULL pointer dereference in
drm_connector_hdmi_enable_scrambling() and
drm_connector_hdmi_sync_scdc() helpers caused by forcing an EDID
advertising SCDC on a connector that physically lacks an I2C DDC bus
(Sashiko)
- dw-hdmi-qp
* Fixed a potential NULL pointer dereference in
dw_hdmi_qp_hpd_notify() helper by using a local variable to cache
the connector pointer (Sashiko)
* Ensured hdmi->phy.ops->disable() is not skipped in
dw_hdmi_qp_bridge_atomic_disable() by accessing the connector via
drm_atomic_get_old_connector_for_encoder() instead of
hdmi->curr_conn (Sashiko)
* Mitigated a potential use-after-free reported by Sashiko caused when
HPD interrupt fires after the DRM device is torn down; reworked
"Defer HPD IRQ enable until after connector setup" into:
* Factor out HPD interrupt mask/unmask helpers
* Control the HPD IRQ line via the bridge HPD ops
* Added new patch addressing another Sashiko finding: drm/rockchip:
dw_hdmi_qp: Avoid spurious HPD IRQ thread wakeups
* Added new patch: drm/bridge: dw-hdmi-qp: Remove unused workqueue
include and define
* Dropped .hdmi_tmds_char_rate_valid() usage from the
bridge/synopsys/dw-hdmi-qp.c scrambling support patch, while
advertising HDMI 1.4 capability for no-hpd configurations
- VC4
* Passed ctx instead of NULL when calling
drm_atomic_helper_connector_hdmi_hotplug() from
vc4_hdmi_handle_hotplug() in the helper preparatory patch
* Aligned with the expected detect_ctx() semantics in a dedicated
"drm/vc4: hdmi: Propagate -EDEADLK to the top level" rather than
bundled in the conversion patch
* Optimized diff around drm_dev_enter() in the conversion patch
(Maxime)
* Simplified vc4_hdmi_connector_clock_valid() logic by deferring max
clock validation to HDMI helpers (new patch)
- Migrated to a funcs-based HDMI connector init API - new patches:
* drm/display: hdmi: Rename drmm_connector_hdmi_init() to *_ini2()
* drm/display: bridge_connector: Convert to drmm_connector_hdmi_init()
* drm/vc4: hdmi: Convert to drmm_connector_hdmi_init()
* drm/vc4: hdmi: Convert to common HDMI 2.0 scrambling infrastructure
* drm/sun4i: hdmi: Convert to drmm_connector_hdmi_init()
* drm/tests: connector: Convert to drmm_connector_hdmi_init()
* drm/tests: hdmi_state_helper: Convert to drmm_connector_hdmi_init()
* drm/bridge: adv7511: Advertise HDMI 1.2 capabilities
* drm/bridge: inno-hdmi: Advertise HDMI 1.2 capabilities
* drm/bridge: ite-it6263: Drop redundant .mode_valid hook
* drm/bridge: ite-it6263: Advertise HDMI 1.3 capabilities
* drm/bridge: ite-it66121: Advertise HDMI 1.2 capabilities
* drm/bridge: lontium-lt9611: Advertise HDMI 1.4 capabilities
* drm/rockchip: rk3066_hdmi: Advertise HDMI 1.4 capabilities
* drm/sun4i: hdmi: Convert to drmm_connector_hdmi_init()
* drm/connector: Remove drmm_connector_hdmi_ini2()
* drm/connector: Drop redundant hdmi vendor/product fields
* drm/connector: Drop redundant hdmi supported_formats field
* drm/connector: Drop redundant max_bpc field
- KUnit
* Adapted hdmi_state_helper scrambler tests and reworked a couple of
max_tmds_char_rate tests according to the latest DRM core changes
* Fixed a regression in the HDMI caps-based init coverage
* Fix a couple of bisectability issues, also implied partial commit
reorder
* Set supported HDMI version for the test bridges (new patch)
- Rebased series onto latest drm-misc-next and removed "drm/rockchip:
dw_hdmi_qp: Drop unnecessary #include" patch, since a similar change
as been already applied
- Link to v8: https://patch.msgid.link/20260702-dw-hdmi-qp-scramb-v8-0-d79890d00b6a@collabora.com
Changes in v8:
- Added an enum hdmi_version under video/hdmi to describe the HDMI
specification version a source/sink supports (new patch 1)
- Introduced HDMI connector capabilities API and reworked the
infrastructure patches on top of it: drmm_connector_hdmi_init() now
takes a drm_connector_hdmi_caps struct that carries supported_formats,
max_bpc, supported_hdmi_ver and max_tmds_char_rate (new patches 2-3)
- Moved all the new SCDC helpers covering both source and sink to
display/drm_hdmi_helper.c
- Renamed drm_scdc_{start,stop}_scrambling() to
drm_connector_hdmi_{enable,disable}_scrambling() and added a
connector-state argument so the scrambler_needed flag is checked
centrally instead of in every driver
- Renamed drm_scdc_sync_status() to drm_connector_hdmi_sync_scdc(),
aligned its lifecycle with vc4_hdmi_reset_link(), and removed the
internal drm_scdc_reset_crtc() helper; it now also gates on CRTC state
and an in-flight commit (Maxime)
- Changed the prototype of drm_atomic_helper_connector_hdmi_hotplug() to
take an acquire context and an int return, instead of adding a new
_ctx variant (Maxime)
- Added drm_hdmi_mode_needs_scrambling() to centralise the above-340 MHz
decision (new patch 7)
- Made SCDC source version negotiation optional and moved it to a
dedicated patch "drm/display: hdmi: Advertise SCDC source version when
scrambling" (new patch 8), backed by a new
drm_scdc_set_source_version() helper in "drm/display: scdc-helper: Add
helper to set SCDC version information" (new patch 6)
- Added a fallback TMDS rate validation patch using the connector-level
max_tmds_char_rate when the driver provides no .tmds_char_rate_valid()
hook (new patch 9)
- Split scrambler_needed flag handling into its own hdmi-state-helper
dedicate change (new patch 11)
- VC4:
* Replaced vc4_hdmi_mode_needs_scrambling() with
drm_hdmi_mode_needs_scrambling() (new patch 30)
* Restored drm_dev_{enter,exit}() pairing around the converted
scrambling paths
* Removed now unused output_{bpc,color_format} fields from vc4_hdmi as
part of the SCDC conversion
- KUnit:
* Covered the caps-based connector init path: NULL caps, inferred
max_tmds_char_rate per supported_hdmi_ver, and override validation
(new patch 32)
* Switched drm_hdmi_state_helper_test to the caps-based init helper
and exposed it through
drm_kunit_helper_connector_hdmi_init_with_caps_edid_funcs() (new
patch 34)
* Added max_tmds_char_rate fallback coverage in
drm_hdmi_state_helper_test (new patch 35)
- Rebased onto latest drm-misc-next and dropped the already applied
"drm/fb-helper: Remove unused local variable in hotplug_event()" patch
- Link to v7: https://patch.msgid.link/20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@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 (69):
video/hdmi: Introduce HDMI version enum
drm/connector: hdmi: Handle reset() state allocation failure
drm/display: hdmi: Rename drmm_connector_hdmi_init() to *_ini2()
drm/connector: Add drmm_connector_hdmi_init() with new signature
drm/display: bridge_connector: Convert to drmm_connector_hdmi_init()
drm/probe-helper: Introduce .force_ctx() connector callback
drm/connector: Add HDMI 2.0 scrambler infrastructure
drm/display: scdc-helper: Add macro for connector-prefixed debug messages
drm/display: scdc-helper: Add helper to set SCDC version information
drm/display: hdmi: Add HDMI 2.0 scrambling management helpers
drm/display: hdmi: Advertise SCDC source version when scrambling
drm/bridge: Fix unlocked list_del in drm_bridge_add()
drm/bridge: Fix unlocked list access in drm_bridge_attach()
drm/bridge: Remove redundant error check in drm_bridge_helper_reset_crtc()
drm/bridge: Add bridge ops for source-side HDMI 2.0 scrambling
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: Switch to .force_ctx() connector helper
drm/display: bridge_connector: Wire up HDMI 2.0 scrambler callbacks
drm/display: hdmi-state-helper: Add source TMDS rate validation
drm/display: hdmi-state-helper: Pass acquire ctx to hotplug helpers
drm/display: hdmi-state-helper: Sync SCDC state on hotplug
drm/display: hdmi-state-helper: Set HDMI scrambling requirement
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: Remove unused workqueue include and define
drm/bridge: dw-hdmi-qp: Add HDMI 2.0 scrambling support
drm/bridge: dw-hdmi-qp: Provide dw_hdmi_qp_hpd_notify() helper
drm/rockchip: dw_hdmi_qp: Fix invalid drvdata access in PM ops
drm/rockchip: dw_hdmi_qp: Cancel pending HPD work on suspend
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: Avoid spurious HPD IRQ thread wakeups
drm/rockchip: dw_hdmi_qp: Mask RK3576 HPD IRQ in io_init
drm/rockchip: dw_hdmi_qp: Implement .{enable,disable}_hpd() PHY ops
drm/rockchip: dw_hdmi_qp: Factor out HPD interrupt (un)mask helpers
drm/rockchip: dw_hdmi_qp: Control the HPD IRQ line via the bridge HPD ops
drm/rockchip: dw_hdmi_qp: Use dw_hdmi_qp_hpd_notify() for HPD reports
drm/bridge: dw-hdmi-qp: Drop unused .setup_hpd() phy op
drm/vc4: hdmi: Use common TMDS char rate constants
drm/vc4: hdmi: Switch to drm_hdmi_mode_needs_scrambling()
drm/vc4: hdmi: Switch to .force_ctx() connector helper
drm/vc4: hdmi: Propagate -EDEADLK to the top level
drm/vc4: hdmi: Convert to drmm_connector_hdmi_init()
drm/vc4: hdmi: Convert to common HDMI 2.0 scrambling infrastructure
drm/vc4: hdmi: Defer pixel clock validation to HDMI helpers
drm/display: hdmi-state-helper: Drop drm_atomic_helper_connector_hdmi_force()
drm/bridge: adv7511: Advertise HDMI 1.2 capabilities
drm/bridge: inno-hdmi: Advertise HDMI 1.2 capabilities
drm/bridge: ite-it6263: Drop redundant .mode_valid hook
drm/bridge: ite-it6263: Advertise HDMI 1.3 capabilities
drm/bridge: ite-it66121: Advertise HDMI 1.2 capabilities
drm/bridge: lontium-lt9611: Advertise HDMI 1.4 capabilities
drm/rockchip: rk3066_hdmi: Advertise HDMI 1.4 capabilities
drm/sun4i: hdmi: Convert to drmm_connector_hdmi_init()
drm/tests: edid: Add 4K@60Hz EDID with 600MHz TMDS
drm/tests: edid: Fix conformity for 1080p+4K YUV420 200MHz EDID
drm/tests: edid: Fix conformity for 4K RGB/YUV 340MHz EDID
drm/tests: bridge: Set supported HDMI version
drm/tests: connector: Convert to drmm_connector_hdmi_init()
drm/tests: connector: Add HDMI max_tmds_char_rate init coverage
drm/tests: connector: Add HDMI source-side scrambler coverage
drm/tests: hdmi_state_helper: Convert to drmm_connector_hdmi_init()
drm/tests: hdmi_state_helper: Add connector-provided max_tmds_char_rate coverage
drm/tests: hdmi_state_helper: Cover source-side scrambling decision
drm/connector: Remove drmm_connector_hdmi_ini2()
drm/connector: Drop redundant hdmi vendor/product fields
drm/connector: Drop redundant hdmi supported_formats field
drm/connector: Drop redundant max_bpc field
drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 22 +-
drivers/gpu/drm/bridge/inno-hdmi.c | 1 +
drivers/gpu/drm/bridge/ite-it6263.c | 33 +-
drivers/gpu/drm/bridge/ite-it66121.c | 13 +-
drivers/gpu/drm/bridge/lontium-lt9611.c | 16 +-
drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 125 ++++-
drivers/gpu/drm/display/drm_bridge_connector.c | 183 ++++---
drivers/gpu/drm/display/drm_hdmi_helper.c | 303 +++++++++++
drivers/gpu/drm/display/drm_hdmi_state_helper.c | 78 ++-
drivers/gpu/drm/display/drm_scdc_helper.c | 70 ++-
drivers/gpu/drm/drm_bridge.c | 19 +-
drivers/gpu/drm/drm_bridge_helper.c | 2 -
drivers/gpu/drm/drm_connector.c | 92 +++-
drivers/gpu/drm/drm_probe_helper.c | 14 +-
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 189 ++++---
drivers/gpu/drm/rockchip/rk3066_hdmi.c | 2 +
drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c | 14 +-
drivers/gpu/drm/tests/drm_bridge_test.c | 2 +
drivers/gpu/drm/tests/drm_connector_test.c | 522 ++++++++++++------
drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 599 +++++++++++++++------
drivers/gpu/drm/tests/drm_kunit_edid.c | 251 +++++++--
drivers/gpu/drm/tests/drm_kunit_edid.h | 1 +
drivers/gpu/drm/vc4/vc4_hdmi.c | 357 +++---------
drivers/gpu/drm/vc4/vc4_hdmi.h | 30 +-
include/drm/bridge/dw_hdmi_qp.h | 4 +-
include/drm/display/drm_hdmi_helper.h | 15 +
include/drm/display/drm_hdmi_state_helper.h | 9 +-
include/drm/display/drm_scdc_helper.h | 2 +
include/drm/drm_bridge.h | 49 ++
include/drm/drm_connector.h | 167 +++++-
include/drm/drm_modeset_helper_vtables.h | 28 +
include/linux/hdmi.h | 12 +
32 files changed, 2208 insertions(+), 1016 deletions(-)
---
base-commit: bc47d5937f21c5fc94504f03e18f1adb56d97634
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] 155+ messages in thread* [PATCH v10 01/69] video/hdmi: Introduce HDMI version enum
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Dmitry Baryshkov
Add an enum to represent HDMI specification versions. This will be used
by upcoming changes to associate HDMI connectors and bridges with a
maximum supported version and to simplify handling of version-dependent
features.
Reviewed-by: Maxime Ripard <mripard@kernel.org>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
include/linux/hdmi.h | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
index 8dab78e1f61b..b80a5ee63bb2 100644
--- a/include/linux/hdmi.h
+++ b/include/linux/hdmi.h
@@ -27,6 +27,18 @@
#include <linux/types.h>
#include <linux/device.h>
+enum hdmi_version {
+ HDMI_VERSION_UNKNOWN,
+ HDMI_VERSION_1_0,
+ HDMI_VERSION_1_1,
+ HDMI_VERSION_1_2,
+ HDMI_VERSION_1_3,
+ HDMI_VERSION_1_4,
+ HDMI_VERSION_2_0,
+ HDMI_VERSION_2_1,
+ HDMI_VERSION_2_2,
+};
+
enum hdmi_packet_type {
HDMI_PACKET_TYPE_NULL = 0x00,
HDMI_PACKET_TYPE_AUDIO_CLOCK_REGEN = 0x01,
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 01/69] video/hdmi: Introduce HDMI version enum
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Dmitry Baryshkov
Add an enum to represent HDMI specification versions. This will be used
by upcoming changes to associate HDMI connectors and bridges with a
maximum supported version and to simplify handling of version-dependent
features.
Reviewed-by: Maxime Ripard <mripard@kernel.org>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
include/linux/hdmi.h | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
index 8dab78e1f61b..b80a5ee63bb2 100644
--- a/include/linux/hdmi.h
+++ b/include/linux/hdmi.h
@@ -27,6 +27,18 @@
#include <linux/types.h>
#include <linux/device.h>
+enum hdmi_version {
+ HDMI_VERSION_UNKNOWN,
+ HDMI_VERSION_1_0,
+ HDMI_VERSION_1_1,
+ HDMI_VERSION_1_2,
+ HDMI_VERSION_1_3,
+ HDMI_VERSION_1_4,
+ HDMI_VERSION_2_0,
+ HDMI_VERSION_2_1,
+ HDMI_VERSION_2_2,
+};
+
enum hdmi_packet_type {
HDMI_PACKET_TYPE_NULL = 0x00,
HDMI_PACKET_TYPE_AUDIO_CLOCK_REGEN = 0x01,
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread* Re: [PATCH v10 01/69] video/hdmi: Introduce HDMI version enum
2026-07-31 16:19 ` Cristian Ciocaltea
(?)
@ 2026-07-31 16:25 ` sashiko-bot
-1 siblings, 0 replies; 155+ messages in thread
From: sashiko-bot @ 2026-07-31 16:25 UTC (permalink / raw)
To: Cristian Ciocaltea; +Cc: linux-sunxi, dri-devel
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] The `hdmi_version` enum includes `HDMI_VERSION_2_2`, but there is no HDMI 2.2 specification.
--
--- Patch [1]: [PATCH v10 01/69] video/hdmi: Introduce HDMI version enum ---
commit 15fb027a48288332d9771472bd4b270e1f7f2d4b
Author: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
video/hdmi: Introduce HDMI version enum
This commit introduces an enum to represent various HDMI specification
versions. It is intended to be used by upcoming changes to associate
HDMI connectors and bridges with a maximum supported version.
> diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
> index 8dab78e1f61bd..b80a5ee63bb23 100644
> --- a/include/linux/hdmi.h
> +++ b/include/linux/hdmi.h
[ ... ]
> @@ -27,6 +27,18 @@
> #include <linux/types.h>
> #include <linux/device.h>
>
> +enum hdmi_version {
> + HDMI_VERSION_UNKNOWN,
> + HDMI_VERSION_1_0,
> + HDMI_VERSION_1_1,
> + HDMI_VERSION_1_2,
> + HDMI_VERSION_1_3,
> + HDMI_VERSION_1_4,
> + HDMI_VERSION_2_0,
> + HDMI_VERSION_2_1,
> + HDMI_VERSION_2_2,
[Severity: Low]
This isn't a bug, but is HDMI_VERSION_2_2 intended to be here?
The latest major specification family released by the HDMI Forum is 2.1, and
there is no HDMI 2.2 specification.
Could this have been conflated with HDCP 2.2, which is frequently used
alongside HDMI 2.0/2.1? Including a non-existent version could lead to
incorrect capability reporting if drivers attempt to set it as a maximum
supported version.
> +};
> +
> enum hdmi_packet_type {
> HDMI_PACKET_TYPE_NULL = 0x00,
> HDMI_PACKET_TYPE_AUDIO_CLOCK_REGEN = 0x01,
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260731-dw-hdmi-qp-scramb-v10-0-294364b2cf15@collabora.com?part=1
^ permalink raw reply [flat|nested] 155+ messages in thread
* [PATCH v10 02/69] drm/connector: hdmi: Handle reset() state allocation failure
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Sashiko
In drmm_connector_hdmi_init(), if the reset callback fails to allocate
memory, e.g. inside drm_atomic_helper_connector_reset(),
connector->state will remain NULL. This is unconditionally passed to
drm_connector_attach_max_bpc_property(), leading to a NULL pointer
dereference.
Bail out with -ENOMEM if the reset callback leaves connector->state
unset.
Fixes: aadb3e16b8f3 ("drm/connector: hdmi: Add output BPC to the connector state")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://lore.kernel.org/all/20260723015306.C94241F000E9@smtp.kernel.org/
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/drm_connector.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 8b4baed060f3..0e39431e85b2 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -628,6 +628,8 @@ int drmm_connector_hdmi_init(struct drm_device *dev,
connector->state = state;
} else if (connector->funcs->reset) {
connector->funcs->reset(connector);
+ if (!connector->state)
+ return -ENOMEM;
}
drm_connector_attach_max_bpc_property(connector, 8, max_bpc);
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 02/69] drm/connector: hdmi: Handle reset() state allocation failure
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Sashiko
In drmm_connector_hdmi_init(), if the reset callback fails to allocate
memory, e.g. inside drm_atomic_helper_connector_reset(),
connector->state will remain NULL. This is unconditionally passed to
drm_connector_attach_max_bpc_property(), leading to a NULL pointer
dereference.
Bail out with -ENOMEM if the reset callback leaves connector->state
unset.
Fixes: aadb3e16b8f3 ("drm/connector: hdmi: Add output BPC to the connector state")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://lore.kernel.org/all/20260723015306.C94241F000E9@smtp.kernel.org/
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/drm_connector.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 8b4baed060f3..0e39431e85b2 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -628,6 +628,8 @@ int drmm_connector_hdmi_init(struct drm_device *dev,
connector->state = state;
} else if (connector->funcs->reset) {
connector->funcs->reset(connector);
+ if (!connector->state)
+ return -ENOMEM;
}
drm_connector_attach_max_bpc_property(connector, 8, max_bpc);
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread* Re: [PATCH v10 02/69] drm/connector: hdmi: Handle reset() state allocation failure
2026-07-31 16:19 ` Cristian Ciocaltea
(?)
@ 2026-07-31 16:37 ` sashiko-bot
-1 siblings, 0 replies; 155+ messages in thread
From: sashiko-bot @ 2026-07-31 16:37 UTC (permalink / raw)
To: Cristian Ciocaltea; +Cc: linux-sunxi, dri-devel
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Custom connector reset callbacks and helpers crash on allocation failure before the newly added NULL check can execute.
--
--- Patch [2]: [PATCH v10 02/69] drm/connector: hdmi: Handle reset() state allocation failure ---
commit 4612d8e6373873b0631394a087aa684911dafc2f
Author: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
drm/connector: hdmi: Handle reset() state allocation failure
This commit adds a check for memory allocation failure during the connector
reset callback in drmm_connector_hdmi_init(). If connector->state remains
NULL after reset(), it bails out with -ENOMEM to avoid a subsequent NULL
pointer dereference.
Link: https://lore.kernel.org/all/20260723015306.C94241F000E9@smtp.kernel.org/
> diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
> index 8b4baed060f3a..0e39431e85b20 100644
> --- a/drivers/gpu/drm/drm_connector.c
> +++ b/drivers/gpu/drm/drm_connector.c
> @@ -628,6 +628,8 @@ int drmm_connector_hdmi_init(struct drm_device *dev,
> connector->state = state;
> } else if (connector->funcs->reset) {
> connector->funcs->reset(connector);
[Severity: High]
This is a pre-existing issue, but does this patch fully prevent the NULL
pointer dereference?
If memory allocation fails inside the reset callback, connector->state
becomes NULL. However, custom reset callbacks like vc4_hdmi_connector_reset()
and sun4i_hdmi_connector_reset() pass this state directly to
__drm_atomic_helper_connector_hdmi_state_init():
drivers/gpu/drm/vc4/vc4_hdmi.c:vc4_hdmi_connector_reset() {
...
__drm_atomic_helper_connector_hdmi_state_init(connector, connector->state);
...
}
That helper unconditionally dereferences new_conn_state:
drivers/gpu/drm/display/drm_hdmi_state_helper.c:__drm_atomic_helper_connector_hdmi_state_init() {
...
new_conn_state->max_bpc = max_bpc;
...
}
Could this trigger a kernel panic inside the custom reset callback before
it even returns here to be caught by the new check?
> + if (!connector->state)
> + return -ENOMEM;
> }
>
> drm_connector_attach_max_bpc_property(connector, 8, max_bpc);
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260731-dw-hdmi-qp-scramb-v10-0-294364b2cf15@collabora.com?part=2
^ permalink raw reply [flat|nested] 155+ messages in thread
* [PATCH v10 03/69] drm/display: hdmi: Rename drmm_connector_hdmi_init() to *_ini2()
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Dmitry Baryshkov, Diederik de Haas
In preparation for changing the signature of drmm_connector_hdmi_init(),
i.e. dropping the vendor, product, supported_formats and max_bpc
arguments, which are being moved into struct drm_connector_hdmi_funcs,
temporarily rename the helper to drmm_connector_hdmi_ini2().
This lets the new signature be introduced under the original name while
callers are converted incrementally. The final patch removes *_ini2()
once no callers remain.
This is a mechanical, same-length rename performed with sed:
$ git grep -l 'drmm_connector_hdmi_init' -- '*.[ch]' \
| xargs sed -i 's/drmm_connector_hdmi_init/drmm_connector_hdmi_ini2/g'
The transitional name matches the original's length so continuation-line
arguments stay aligned to the opening parenthesis, keeping the diff to
the identifier itself and avoiding re-alignment churn here and in the
later conversions.
No functional change intended.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_bridge_connector.c | 2 +-
drivers/gpu/drm/drm_connector.c | 6 ++--
drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c | 2 +-
drivers/gpu/drm/tests/drm_connector_test.c | 42 +++++++++++-----------
drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 2 +-
drivers/gpu/drm/vc4/vc4_hdmi.c | 2 +-
include/drm/drm_connector.h | 2 +-
7 files changed, 29 insertions(+), 29 deletions(-)
diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
index 8b54069fa53a..f75ce47a6350 100644
--- a/drivers/gpu/drm/display/drm_bridge_connector.c
+++ b/drivers/gpu/drm/display/drm_bridge_connector.c
@@ -1010,7 +1010,7 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
bridge_connector->hdmi_funcs.spd =
drm_bridge_connector_hdmi_spd_infoframe;
- ret = drmm_connector_hdmi_init(drm, connector,
+ ret = drmm_connector_hdmi_ini2(drm, connector,
bridge_connector->bridge_hdmi->vendor,
bridge_connector->bridge_hdmi->product,
&drm_bridge_connector_funcs,
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 0e39431e85b2..5e520cff6094 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -543,7 +543,7 @@ int drmm_connector_init(struct drm_device *dev,
EXPORT_SYMBOL(drmm_connector_init);
/**
- * drmm_connector_hdmi_init - Init a preallocated HDMI connector
+ * drmm_connector_hdmi_ini2 - Init a preallocated HDMI connector
* @dev: DRM device
* @connector: A pointer to the HDMI connector to init
* @vendor: HDMI Controller Vendor name
@@ -568,7 +568,7 @@ EXPORT_SYMBOL(drmm_connector_init);
* Returns:
* Zero on success, error code on failure.
*/
-int drmm_connector_hdmi_init(struct drm_device *dev,
+int drmm_connector_hdmi_ini2(struct drm_device *dev,
struct drm_connector *connector,
const char *vendor, const char *product,
const struct drm_connector_funcs *funcs,
@@ -646,7 +646,7 @@ int drmm_connector_hdmi_init(struct drm_device *dev,
return 0;
}
-EXPORT_SYMBOL(drmm_connector_hdmi_init);
+EXPORT_SYMBOL(drmm_connector_hdmi_ini2);
/**
* drm_connector_attach_edid_property - attach edid property.
diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
index e99f52ebb26f..96b2b597caa6 100644
--- a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
+++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
@@ -653,7 +653,7 @@ static int sun4i_hdmi_bind(struct device *dev, struct device *master,
drm_connector_helper_add(&hdmi->connector,
&sun4i_hdmi_connector_helper_funcs);
- ret = drmm_connector_hdmi_init(drm, &hdmi->connector,
+ ret = drmm_connector_hdmi_ini2(drm, &hdmi->connector,
/*
* NOTE: Those are likely to be
* wrong, but I couldn't find the
diff --git a/drivers/gpu/drm/tests/drm_connector_test.c b/drivers/gpu/drm/tests/drm_connector_test.c
index beb1d50a6646..3368aedd4e66 100644
--- a/drivers/gpu/drm/tests/drm_connector_test.c
+++ b/drivers/gpu/drm/tests/drm_connector_test.c
@@ -669,7 +669,7 @@ static void drm_test_connector_hdmi_init_valid(struct kunit *test)
struct drm_connector_init_priv *priv = test->priv;
int ret;
- ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
"Vendor", "Product",
&dummy_funcs,
&dummy_hdmi_funcs,
@@ -689,7 +689,7 @@ static void drm_test_connector_hdmi_init_null_ddc(struct kunit *test)
struct drm_connector_init_priv *priv = test->priv;
int ret;
- ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
"Vendor", "Product",
&dummy_funcs,
&dummy_hdmi_funcs,
@@ -709,7 +709,7 @@ static void drm_test_connector_hdmi_init_null_vendor(struct kunit *test)
struct drm_connector_init_priv *priv = test->priv;
int ret;
- ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
NULL, "Product",
&dummy_funcs,
&dummy_hdmi_funcs,
@@ -729,7 +729,7 @@ static void drm_test_connector_hdmi_init_null_product(struct kunit *test)
struct drm_connector_init_priv *priv = test->priv;
int ret;
- ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
"Vendor", NULL,
&dummy_funcs,
&dummy_hdmi_funcs,
@@ -755,7 +755,7 @@ static void drm_test_connector_hdmi_init_product_valid(struct kunit *test)
KUNIT_ASSERT_LT(test, strlen(product_name), DRM_CONNECTOR_HDMI_PRODUCT_LEN);
- ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
"Vendor", product_name,
&dummy_funcs,
&dummy_hdmi_funcs,
@@ -788,7 +788,7 @@ static void drm_test_connector_hdmi_init_product_length_exact(struct kunit *test
KUNIT_ASSERT_EQ(test, strlen(product_name), DRM_CONNECTOR_HDMI_PRODUCT_LEN);
- ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
"Vendor", product_name,
&dummy_funcs,
&dummy_hdmi_funcs,
@@ -815,7 +815,7 @@ static void drm_test_connector_hdmi_init_product_length_too_long(struct kunit *t
KUNIT_ASSERT_GT(test, strlen(product_name), DRM_CONNECTOR_HDMI_PRODUCT_LEN);
- ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
"Vendor", product_name,
&dummy_funcs,
&dummy_hdmi_funcs,
@@ -841,7 +841,7 @@ static void drm_test_connector_hdmi_init_vendor_valid(struct kunit *test)
KUNIT_ASSERT_LT(test, strlen(vendor_name), DRM_CONNECTOR_HDMI_VENDOR_LEN);
- ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
vendor_name, "Product",
&dummy_funcs,
&dummy_hdmi_funcs,
@@ -873,7 +873,7 @@ static void drm_test_connector_hdmi_init_vendor_length_exact(struct kunit *test)
KUNIT_ASSERT_EQ(test, strlen(vendor_name), DRM_CONNECTOR_HDMI_VENDOR_LEN);
- ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
vendor_name, "Product",
&dummy_funcs,
&dummy_hdmi_funcs,
@@ -900,7 +900,7 @@ static void drm_test_connector_hdmi_init_vendor_length_too_long(struct kunit *te
KUNIT_ASSERT_GT(test, strlen(vendor_name), DRM_CONNECTOR_HDMI_VENDOR_LEN);
- ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
vendor_name, "Product",
&dummy_funcs,
&dummy_hdmi_funcs,
@@ -920,7 +920,7 @@ static void drm_test_connector_hdmi_init_bpc_invalid(struct kunit *test)
struct drm_connector_init_priv *priv = test->priv;
int ret;
- ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
"Vendor", "Product",
&dummy_funcs,
&dummy_hdmi_funcs,
@@ -940,7 +940,7 @@ static void drm_test_connector_hdmi_init_bpc_null(struct kunit *test)
struct drm_connector_init_priv *priv = test->priv;
int ret;
- ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
"Vendor", "Product",
&dummy_funcs,
&dummy_hdmi_funcs,
@@ -965,7 +965,7 @@ static void drm_test_connector_hdmi_init_bpc_8(struct kunit *test)
uint64_t val;
int ret;
- ret = drmm_connector_hdmi_init(&priv->drm, connector,
+ ret = drmm_connector_hdmi_ini2(&priv->drm, connector,
"Vendor", "Product",
&dummy_funcs,
&dummy_hdmi_funcs,
@@ -1006,7 +1006,7 @@ static void drm_test_connector_hdmi_init_bpc_10(struct kunit *test)
uint64_t val;
int ret;
- ret = drmm_connector_hdmi_init(&priv->drm, connector,
+ ret = drmm_connector_hdmi_ini2(&priv->drm, connector,
"Vendor", "Product",
&dummy_funcs,
&dummy_hdmi_funcs,
@@ -1047,7 +1047,7 @@ static void drm_test_connector_hdmi_init_bpc_12(struct kunit *test)
uint64_t val;
int ret;
- ret = drmm_connector_hdmi_init(&priv->drm, connector,
+ ret = drmm_connector_hdmi_ini2(&priv->drm, connector,
"Vendor", "Product",
&dummy_funcs,
&dummy_hdmi_funcs,
@@ -1083,7 +1083,7 @@ static void drm_test_connector_hdmi_init_formats_empty(struct kunit *test)
struct drm_connector_init_priv *priv = test->priv;
int ret;
- ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
"Vendor", "Product",
&dummy_funcs,
&dummy_hdmi_funcs,
@@ -1103,7 +1103,7 @@ static void drm_test_connector_hdmi_init_formats_no_rgb(struct kunit *test)
struct drm_connector_init_priv *priv = test->priv;
int ret;
- ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
"Vendor", "Product",
&dummy_funcs,
&dummy_hdmi_funcs,
@@ -1161,7 +1161,7 @@ static void drm_test_connector_hdmi_init_formats_yuv420_allowed(struct kunit *te
params = test->param_value;
priv->connector.ycbcr_420_allowed = params->yuv420_allowed;
- ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
"Vendor", "Product",
&dummy_funcs,
&dummy_hdmi_funcs,
@@ -1182,7 +1182,7 @@ static void drm_test_connector_hdmi_init_type_valid(struct kunit *test)
unsigned int connector_type = *(unsigned int *)test->param_value;
int ret;
- ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
"Vendor", "Product",
&dummy_funcs,
&dummy_hdmi_funcs,
@@ -1217,7 +1217,7 @@ static void drm_test_connector_hdmi_init_type_invalid(struct kunit *test)
unsigned int connector_type = *(unsigned int *)test->param_value;
int ret;
- ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
"Vendor", "Product",
&dummy_funcs,
&dummy_hdmi_funcs,
@@ -1494,7 +1494,7 @@ static void drm_test_drm_connector_attach_broadcast_rgb_property_hdmi_connector(
struct drm_property *prop;
int ret;
- ret = drmm_connector_hdmi_init(&priv->drm, connector,
+ ret = drmm_connector_hdmi_ini2(&priv->drm, connector,
"Vendor", "Product",
&dummy_funcs,
&dummy_hdmi_funcs,
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 353a261d42da..4c2a400bc15a 100644
--- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
+++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
@@ -275,7 +275,7 @@ __connector_hdmi_init(struct kunit *test,
conn = &priv->connector;
conn->ycbcr_420_allowed = !!(formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420));
- ret = drmm_connector_hdmi_init(drm, conn,
+ ret = drmm_connector_hdmi_ini2(drm, conn,
"Vendor", "Product",
&dummy_connector_funcs,
hdmi_funcs,
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index 17c8635c5afa..72ff95ca97de 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -541,7 +541,7 @@ static int vc4_hdmi_connector_init(struct drm_device *dev,
if (vc4_hdmi->variant->supports_hdr)
max_bpc = 12;
- ret = drmm_connector_hdmi_init(dev, connector,
+ ret = drmm_connector_hdmi_ini2(dev, connector,
"Broadcom", "Videocore",
&vc4_hdmi_connector_funcs,
&vc4_hdmi_hdmi_connector_funcs,
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index a0cf0268de48..2e7d75cb0adf 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -2549,7 +2549,7 @@ int drmm_connector_init(struct drm_device *dev,
const struct drm_connector_funcs *funcs,
int connector_type,
struct i2c_adapter *ddc);
-int drmm_connector_hdmi_init(struct drm_device *dev,
+int drmm_connector_hdmi_ini2(struct drm_device *dev,
struct drm_connector *connector,
const char *vendor, const char *product,
const struct drm_connector_funcs *funcs,
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 03/69] drm/display: hdmi: Rename drmm_connector_hdmi_init() to *_ini2()
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Dmitry Baryshkov, Diederik de Haas
In preparation for changing the signature of drmm_connector_hdmi_init(),
i.e. dropping the vendor, product, supported_formats and max_bpc
arguments, which are being moved into struct drm_connector_hdmi_funcs,
temporarily rename the helper to drmm_connector_hdmi_ini2().
This lets the new signature be introduced under the original name while
callers are converted incrementally. The final patch removes *_ini2()
once no callers remain.
This is a mechanical, same-length rename performed with sed:
$ git grep -l 'drmm_connector_hdmi_init' -- '*.[ch]' \
| xargs sed -i 's/drmm_connector_hdmi_init/drmm_connector_hdmi_ini2/g'
The transitional name matches the original's length so continuation-line
arguments stay aligned to the opening parenthesis, keeping the diff to
the identifier itself and avoiding re-alignment churn here and in the
later conversions.
No functional change intended.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_bridge_connector.c | 2 +-
drivers/gpu/drm/drm_connector.c | 6 ++--
drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c | 2 +-
drivers/gpu/drm/tests/drm_connector_test.c | 42 +++++++++++-----------
drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 2 +-
drivers/gpu/drm/vc4/vc4_hdmi.c | 2 +-
include/drm/drm_connector.h | 2 +-
7 files changed, 29 insertions(+), 29 deletions(-)
diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
index 8b54069fa53a..f75ce47a6350 100644
--- a/drivers/gpu/drm/display/drm_bridge_connector.c
+++ b/drivers/gpu/drm/display/drm_bridge_connector.c
@@ -1010,7 +1010,7 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
bridge_connector->hdmi_funcs.spd =
drm_bridge_connector_hdmi_spd_infoframe;
- ret = drmm_connector_hdmi_init(drm, connector,
+ ret = drmm_connector_hdmi_ini2(drm, connector,
bridge_connector->bridge_hdmi->vendor,
bridge_connector->bridge_hdmi->product,
&drm_bridge_connector_funcs,
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 0e39431e85b2..5e520cff6094 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -543,7 +543,7 @@ int drmm_connector_init(struct drm_device *dev,
EXPORT_SYMBOL(drmm_connector_init);
/**
- * drmm_connector_hdmi_init - Init a preallocated HDMI connector
+ * drmm_connector_hdmi_ini2 - Init a preallocated HDMI connector
* @dev: DRM device
* @connector: A pointer to the HDMI connector to init
* @vendor: HDMI Controller Vendor name
@@ -568,7 +568,7 @@ EXPORT_SYMBOL(drmm_connector_init);
* Returns:
* Zero on success, error code on failure.
*/
-int drmm_connector_hdmi_init(struct drm_device *dev,
+int drmm_connector_hdmi_ini2(struct drm_device *dev,
struct drm_connector *connector,
const char *vendor, const char *product,
const struct drm_connector_funcs *funcs,
@@ -646,7 +646,7 @@ int drmm_connector_hdmi_init(struct drm_device *dev,
return 0;
}
-EXPORT_SYMBOL(drmm_connector_hdmi_init);
+EXPORT_SYMBOL(drmm_connector_hdmi_ini2);
/**
* drm_connector_attach_edid_property - attach edid property.
diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
index e99f52ebb26f..96b2b597caa6 100644
--- a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
+++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
@@ -653,7 +653,7 @@ static int sun4i_hdmi_bind(struct device *dev, struct device *master,
drm_connector_helper_add(&hdmi->connector,
&sun4i_hdmi_connector_helper_funcs);
- ret = drmm_connector_hdmi_init(drm, &hdmi->connector,
+ ret = drmm_connector_hdmi_ini2(drm, &hdmi->connector,
/*
* NOTE: Those are likely to be
* wrong, but I couldn't find the
diff --git a/drivers/gpu/drm/tests/drm_connector_test.c b/drivers/gpu/drm/tests/drm_connector_test.c
index beb1d50a6646..3368aedd4e66 100644
--- a/drivers/gpu/drm/tests/drm_connector_test.c
+++ b/drivers/gpu/drm/tests/drm_connector_test.c
@@ -669,7 +669,7 @@ static void drm_test_connector_hdmi_init_valid(struct kunit *test)
struct drm_connector_init_priv *priv = test->priv;
int ret;
- ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
"Vendor", "Product",
&dummy_funcs,
&dummy_hdmi_funcs,
@@ -689,7 +689,7 @@ static void drm_test_connector_hdmi_init_null_ddc(struct kunit *test)
struct drm_connector_init_priv *priv = test->priv;
int ret;
- ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
"Vendor", "Product",
&dummy_funcs,
&dummy_hdmi_funcs,
@@ -709,7 +709,7 @@ static void drm_test_connector_hdmi_init_null_vendor(struct kunit *test)
struct drm_connector_init_priv *priv = test->priv;
int ret;
- ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
NULL, "Product",
&dummy_funcs,
&dummy_hdmi_funcs,
@@ -729,7 +729,7 @@ static void drm_test_connector_hdmi_init_null_product(struct kunit *test)
struct drm_connector_init_priv *priv = test->priv;
int ret;
- ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
"Vendor", NULL,
&dummy_funcs,
&dummy_hdmi_funcs,
@@ -755,7 +755,7 @@ static void drm_test_connector_hdmi_init_product_valid(struct kunit *test)
KUNIT_ASSERT_LT(test, strlen(product_name), DRM_CONNECTOR_HDMI_PRODUCT_LEN);
- ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
"Vendor", product_name,
&dummy_funcs,
&dummy_hdmi_funcs,
@@ -788,7 +788,7 @@ static void drm_test_connector_hdmi_init_product_length_exact(struct kunit *test
KUNIT_ASSERT_EQ(test, strlen(product_name), DRM_CONNECTOR_HDMI_PRODUCT_LEN);
- ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
"Vendor", product_name,
&dummy_funcs,
&dummy_hdmi_funcs,
@@ -815,7 +815,7 @@ static void drm_test_connector_hdmi_init_product_length_too_long(struct kunit *t
KUNIT_ASSERT_GT(test, strlen(product_name), DRM_CONNECTOR_HDMI_PRODUCT_LEN);
- ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
"Vendor", product_name,
&dummy_funcs,
&dummy_hdmi_funcs,
@@ -841,7 +841,7 @@ static void drm_test_connector_hdmi_init_vendor_valid(struct kunit *test)
KUNIT_ASSERT_LT(test, strlen(vendor_name), DRM_CONNECTOR_HDMI_VENDOR_LEN);
- ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
vendor_name, "Product",
&dummy_funcs,
&dummy_hdmi_funcs,
@@ -873,7 +873,7 @@ static void drm_test_connector_hdmi_init_vendor_length_exact(struct kunit *test)
KUNIT_ASSERT_EQ(test, strlen(vendor_name), DRM_CONNECTOR_HDMI_VENDOR_LEN);
- ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
vendor_name, "Product",
&dummy_funcs,
&dummy_hdmi_funcs,
@@ -900,7 +900,7 @@ static void drm_test_connector_hdmi_init_vendor_length_too_long(struct kunit *te
KUNIT_ASSERT_GT(test, strlen(vendor_name), DRM_CONNECTOR_HDMI_VENDOR_LEN);
- ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
vendor_name, "Product",
&dummy_funcs,
&dummy_hdmi_funcs,
@@ -920,7 +920,7 @@ static void drm_test_connector_hdmi_init_bpc_invalid(struct kunit *test)
struct drm_connector_init_priv *priv = test->priv;
int ret;
- ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
"Vendor", "Product",
&dummy_funcs,
&dummy_hdmi_funcs,
@@ -940,7 +940,7 @@ static void drm_test_connector_hdmi_init_bpc_null(struct kunit *test)
struct drm_connector_init_priv *priv = test->priv;
int ret;
- ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
"Vendor", "Product",
&dummy_funcs,
&dummy_hdmi_funcs,
@@ -965,7 +965,7 @@ static void drm_test_connector_hdmi_init_bpc_8(struct kunit *test)
uint64_t val;
int ret;
- ret = drmm_connector_hdmi_init(&priv->drm, connector,
+ ret = drmm_connector_hdmi_ini2(&priv->drm, connector,
"Vendor", "Product",
&dummy_funcs,
&dummy_hdmi_funcs,
@@ -1006,7 +1006,7 @@ static void drm_test_connector_hdmi_init_bpc_10(struct kunit *test)
uint64_t val;
int ret;
- ret = drmm_connector_hdmi_init(&priv->drm, connector,
+ ret = drmm_connector_hdmi_ini2(&priv->drm, connector,
"Vendor", "Product",
&dummy_funcs,
&dummy_hdmi_funcs,
@@ -1047,7 +1047,7 @@ static void drm_test_connector_hdmi_init_bpc_12(struct kunit *test)
uint64_t val;
int ret;
- ret = drmm_connector_hdmi_init(&priv->drm, connector,
+ ret = drmm_connector_hdmi_ini2(&priv->drm, connector,
"Vendor", "Product",
&dummy_funcs,
&dummy_hdmi_funcs,
@@ -1083,7 +1083,7 @@ static void drm_test_connector_hdmi_init_formats_empty(struct kunit *test)
struct drm_connector_init_priv *priv = test->priv;
int ret;
- ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
"Vendor", "Product",
&dummy_funcs,
&dummy_hdmi_funcs,
@@ -1103,7 +1103,7 @@ static void drm_test_connector_hdmi_init_formats_no_rgb(struct kunit *test)
struct drm_connector_init_priv *priv = test->priv;
int ret;
- ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
"Vendor", "Product",
&dummy_funcs,
&dummy_hdmi_funcs,
@@ -1161,7 +1161,7 @@ static void drm_test_connector_hdmi_init_formats_yuv420_allowed(struct kunit *te
params = test->param_value;
priv->connector.ycbcr_420_allowed = params->yuv420_allowed;
- ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
"Vendor", "Product",
&dummy_funcs,
&dummy_hdmi_funcs,
@@ -1182,7 +1182,7 @@ static void drm_test_connector_hdmi_init_type_valid(struct kunit *test)
unsigned int connector_type = *(unsigned int *)test->param_value;
int ret;
- ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
"Vendor", "Product",
&dummy_funcs,
&dummy_hdmi_funcs,
@@ -1217,7 +1217,7 @@ static void drm_test_connector_hdmi_init_type_invalid(struct kunit *test)
unsigned int connector_type = *(unsigned int *)test->param_value;
int ret;
- ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
"Vendor", "Product",
&dummy_funcs,
&dummy_hdmi_funcs,
@@ -1494,7 +1494,7 @@ static void drm_test_drm_connector_attach_broadcast_rgb_property_hdmi_connector(
struct drm_property *prop;
int ret;
- ret = drmm_connector_hdmi_init(&priv->drm, connector,
+ ret = drmm_connector_hdmi_ini2(&priv->drm, connector,
"Vendor", "Product",
&dummy_funcs,
&dummy_hdmi_funcs,
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 353a261d42da..4c2a400bc15a 100644
--- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
+++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
@@ -275,7 +275,7 @@ __connector_hdmi_init(struct kunit *test,
conn = &priv->connector;
conn->ycbcr_420_allowed = !!(formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420));
- ret = drmm_connector_hdmi_init(drm, conn,
+ ret = drmm_connector_hdmi_ini2(drm, conn,
"Vendor", "Product",
&dummy_connector_funcs,
hdmi_funcs,
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index 17c8635c5afa..72ff95ca97de 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -541,7 +541,7 @@ static int vc4_hdmi_connector_init(struct drm_device *dev,
if (vc4_hdmi->variant->supports_hdr)
max_bpc = 12;
- ret = drmm_connector_hdmi_init(dev, connector,
+ ret = drmm_connector_hdmi_ini2(dev, connector,
"Broadcom", "Videocore",
&vc4_hdmi_connector_funcs,
&vc4_hdmi_hdmi_connector_funcs,
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index a0cf0268de48..2e7d75cb0adf 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -2549,7 +2549,7 @@ int drmm_connector_init(struct drm_device *dev,
const struct drm_connector_funcs *funcs,
int connector_type,
struct i2c_adapter *ddc);
-int drmm_connector_hdmi_init(struct drm_device *dev,
+int drmm_connector_hdmi_ini2(struct drm_device *dev,
struct drm_connector *connector,
const char *vendor, const char *product,
const struct drm_connector_funcs *funcs,
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 04/69] drm/connector: Add drmm_connector_hdmi_init() with new signature
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Diederik de Haas
In preparation for providing HDMI 2.x source capabilities, move the
vendor, product, supported_formats and max_bpc parameters out of the
init function into struct drm_connector_hdmi_funcs, and add new
supported_hdmi_ver and supported_tmds_char_rate fields there as well.
Appending more HDMI-specific arguments to that function would not scale
well, hence introduce drmm_connector_hdmi_init() with the reduced
signature.
Additionally, add the max_tmds_char_rate field to struct
drm_connector_hdmi and use the supported HDMI version to determinate the
maximum TMDS character rate allowed by the specification. Some
controllers, however, may support a lower rate than that version would
imply. A non-zero supported_tmds_char_rate lets drivers override this
default with the actual controller capability. A value of zero keeps
the limit inferred from supported_hdmi_ver.
Callers are converted in the following patches, while the old and now
renamed *_ini2() helper is removed at the end of the series.
No functional changes expected for existing callers.
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/drm_connector.c | 136 ++++++++++++++++++++++++++++++++++++++++
include/drm/drm_connector.h | 62 +++++++++++++++++-
2 files changed, 197 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 5e520cff6094..4721cdeafc84 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -542,6 +542,142 @@ int drmm_connector_init(struct drm_device *dev,
}
EXPORT_SYMBOL(drmm_connector_init);
+/**
+ * drmm_connector_hdmi_init - Init a preallocated HDMI connector
+ * @dev: DRM device
+ * @connector: A pointer to the HDMI connector to init
+ * @funcs: callbacks for this connector
+ * @hdmi_funcs: HDMI-related callbacks and capabilities for this connector
+ * @connector_type: user visible type of the connector
+ * @ddc: optional pointer to the associated ddc adapter
+ *
+ * Initialises a preallocated HDMI connector. Connectors can be
+ * subclassed as part of driver connector objects.
+ *
+ * Cleanup is automatically handled with a call to
+ * drm_connector_cleanup() in a DRM-managed action.
+ *
+ * The connector structure should be allocated with drmm_kzalloc().
+ *
+ * The @drm_connector_funcs.destroy hook must be NULL.
+ *
+ * Returns:
+ * Zero on success, error code on failure.
+ */
+int drmm_connector_hdmi_init(struct drm_device *dev,
+ struct drm_connector *connector,
+ const struct drm_connector_funcs *funcs,
+ const struct drm_connector_hdmi_funcs *hdmi_funcs,
+ int connector_type,
+ struct i2c_adapter *ddc)
+{
+ int ret;
+
+ if (!hdmi_funcs)
+ return -EINVAL;
+
+ if (!hdmi_funcs->vendor || !hdmi_funcs->product)
+ return -EINVAL;
+
+ if ((strlen(hdmi_funcs->vendor) > DRM_CONNECTOR_HDMI_VENDOR_LEN) ||
+ (strlen(hdmi_funcs->product) > DRM_CONNECTOR_HDMI_PRODUCT_LEN))
+ return -EINVAL;
+
+ if (!hdmi_funcs->supported_formats ||
+ !(hdmi_funcs->supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444)))
+ return -EINVAL;
+
+ if (connector->ycbcr_420_allowed !=
+ !!(hdmi_funcs->supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420)))
+ return -EINVAL;
+
+ if (!(hdmi_funcs->max_bpc == 8 ||
+ hdmi_funcs->max_bpc == 10 ||
+ hdmi_funcs->max_bpc == 12))
+ return -EINVAL;
+
+ if (!hdmi_funcs->avi.clear_infoframe ||
+ !hdmi_funcs->avi.write_infoframe ||
+ !hdmi_funcs->hdmi.clear_infoframe ||
+ !hdmi_funcs->hdmi.write_infoframe)
+ return -EINVAL;
+
+ if (!(connector_type == DRM_MODE_CONNECTOR_HDMIA ||
+ connector_type == DRM_MODE_CONNECTOR_HDMIB))
+ return -EINVAL;
+
+ ret = drmm_connector_init(dev, connector, funcs, connector_type, ddc);
+ if (ret)
+ return ret;
+
+ /* TODO: remove after conversion to new drmm_connector_hdmi_init() */
+ connector->hdmi.supported_formats = hdmi_funcs->supported_formats;
+
+ /*
+ * The supported HDMI version can be used to determinate the maximum
+ * TMDS character rate allowed by the specification. Some controllers,
+ * however, may support a lower rate than that version would imply.
+ *
+ * A non-zero caps->max_tmds_char_rate lets drivers override this
+ * default with the actual controller capability. A value of zero keeps
+ * the limit inferred from supported_hdmi_ver.
+ */
+ if (hdmi_funcs->supported_hdmi_ver >= HDMI_VERSION_2_0)
+ connector->hdmi.max_tmds_char_rate = HDMI_2_0_TMDS_CHAR_RATE_MAX_HZ;
+ else if (hdmi_funcs->supported_hdmi_ver >= HDMI_VERSION_1_3)
+ connector->hdmi.max_tmds_char_rate = HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ;
+ else if (hdmi_funcs->supported_hdmi_ver >= HDMI_VERSION_1_0)
+ connector->hdmi.max_tmds_char_rate = HDMI_1_0_TMDS_CHAR_RATE_MAX_HZ;
+
+ if (hdmi_funcs->supported_tmds_char_rate) {
+ if (hdmi_funcs->supported_tmds_char_rate > connector->hdmi.max_tmds_char_rate) {
+ drm_err(dev, "Enforced max_tmds_char_rate exceeds %llu spec limit\n",
+ connector->hdmi.max_tmds_char_rate);
+ return -EINVAL;
+ }
+ connector->hdmi.max_tmds_char_rate = hdmi_funcs->supported_tmds_char_rate;
+ }
+
+ /* TODO: remove after conversion to new drmm_connector_hdmi_init() */
+ strtomem_pad(connector->hdmi.vendor, hdmi_funcs->vendor, 0);
+ strtomem_pad(connector->hdmi.product, hdmi_funcs->product, 0);
+
+ /*
+ * drm_connector_attach_max_bpc_property() requires the
+ * connector to have a state.
+ */
+ if (connector->funcs->atomic_create_state) {
+ struct drm_connector_state *state;
+
+ state = connector->funcs->atomic_create_state(connector);
+ if (IS_ERR(state))
+ return PTR_ERR(state);
+
+ connector->state = state;
+ } else if (connector->funcs->reset) {
+ connector->funcs->reset(connector);
+ if (!connector->state)
+ return -ENOMEM;
+ }
+
+ drm_connector_attach_max_bpc_property(connector, 8, hdmi_funcs->max_bpc);
+ /* TODO: remove after conversion to new drmm_connector_hdmi_init() */
+ connector->max_bpc = hdmi_funcs->max_bpc;
+
+ if (hdmi_funcs->max_bpc > 8)
+ drm_connector_attach_hdr_output_metadata_property(connector);
+
+ ret = drm_connector_attach_color_format_property(connector,
+ hdmi_funcs->supported_formats);
+ if (ret)
+ return ret;
+
+ connector->hdmi.funcs = hdmi_funcs;
+
+ return 0;
+}
+EXPORT_SYMBOL(drmm_connector_hdmi_init);
+
/**
* drmm_connector_hdmi_ini2 - Init a preallocated HDMI connector
* @dev: DRM device
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 2e7d75cb0adf..2a49c4d55f77 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -1403,8 +1403,50 @@ struct drm_connector_infoframe_funcs {
/**
* struct drm_connector_hdmi_funcs - drm_hdmi_connector control functions
+ * and controller capabilities
*/
struct drm_connector_hdmi_funcs {
+ /**
+ * @vendor: HDMI Controller Vendor name.
+ */
+ const char *vendor;
+
+ /**
+ * @product: HDMI Controller Product name
+ */
+ const char *product;
+
+ /**
+ * @supported_hdmi_ver:
+ *
+ * Maximum HDMI specification version supported by the controller side
+ * of this connector. This describes the controller capability only;
+ * the effective link capabilities may be further restricted by the
+ * sink, bridge, or mode validation.
+ */
+ enum hdmi_version supported_hdmi_ver;
+
+ /**
+ * @supported_tmds_char_rate:
+ *
+ * Maximum TMDS character rate supported by the controller, in Hz.
+ * A value of 0 means the core should use the default limit implied by
+ * @supported_hdmi_ver.
+ */
+ unsigned long long supported_tmds_char_rate;
+
+ /**
+ * @supported_formats:
+ *
+ * Bitmask of @drm_output_color_format listing supported output formats.
+ */
+ unsigned long supported_formats;
+
+ /**
+ * @max_bpc: Maximum bits per char the HDMI connector supports.
+ */
+ unsigned int max_bpc;
+
/**
* @tmds_char_rate_valid:
*
@@ -2052,7 +2094,19 @@ struct drm_connector_hdmi {
unsigned long supported_formats;
/**
- * @funcs: HDMI connector Control Functions
+ * @max_tmds_char_rate: Maximum TMDS character rate, in Hz,
+ * supported by the controller.
+ *
+ * This is inferred from &drm_connector_hdmi_funcs.supported_hdmi_ver,
+ * by default. However, controllers may support a lower rate than that
+ * specification version would imply. If that is the case, drivers are
+ * expected to set &drm_connector_hdmi_funcs.supported_tmds_char_rate
+ * to a non-zero value indicating the actual limit.
+ */
+ unsigned long long max_tmds_char_rate;
+
+ /**
+ * @funcs: HDMI connector Control Functions and controller capabilities
*/
const struct drm_connector_hdmi_funcs *funcs;
@@ -2549,6 +2603,12 @@ int drmm_connector_init(struct drm_device *dev,
const struct drm_connector_funcs *funcs,
int connector_type,
struct i2c_adapter *ddc);
+int drmm_connector_hdmi_init(struct drm_device *dev,
+ struct drm_connector *connector,
+ const struct drm_connector_funcs *funcs,
+ const struct drm_connector_hdmi_funcs *hdmi_funcs,
+ int connector_type,
+ struct i2c_adapter *ddc);
int drmm_connector_hdmi_ini2(struct drm_device *dev,
struct drm_connector *connector,
const char *vendor, const char *product,
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 04/69] drm/connector: Add drmm_connector_hdmi_init() with new signature
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Diederik de Haas
In preparation for providing HDMI 2.x source capabilities, move the
vendor, product, supported_formats and max_bpc parameters out of the
init function into struct drm_connector_hdmi_funcs, and add new
supported_hdmi_ver and supported_tmds_char_rate fields there as well.
Appending more HDMI-specific arguments to that function would not scale
well, hence introduce drmm_connector_hdmi_init() with the reduced
signature.
Additionally, add the max_tmds_char_rate field to struct
drm_connector_hdmi and use the supported HDMI version to determinate the
maximum TMDS character rate allowed by the specification. Some
controllers, however, may support a lower rate than that version would
imply. A non-zero supported_tmds_char_rate lets drivers override this
default with the actual controller capability. A value of zero keeps
the limit inferred from supported_hdmi_ver.
Callers are converted in the following patches, while the old and now
renamed *_ini2() helper is removed at the end of the series.
No functional changes expected for existing callers.
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/drm_connector.c | 136 ++++++++++++++++++++++++++++++++++++++++
include/drm/drm_connector.h | 62 +++++++++++++++++-
2 files changed, 197 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 5e520cff6094..4721cdeafc84 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -542,6 +542,142 @@ int drmm_connector_init(struct drm_device *dev,
}
EXPORT_SYMBOL(drmm_connector_init);
+/**
+ * drmm_connector_hdmi_init - Init a preallocated HDMI connector
+ * @dev: DRM device
+ * @connector: A pointer to the HDMI connector to init
+ * @funcs: callbacks for this connector
+ * @hdmi_funcs: HDMI-related callbacks and capabilities for this connector
+ * @connector_type: user visible type of the connector
+ * @ddc: optional pointer to the associated ddc adapter
+ *
+ * Initialises a preallocated HDMI connector. Connectors can be
+ * subclassed as part of driver connector objects.
+ *
+ * Cleanup is automatically handled with a call to
+ * drm_connector_cleanup() in a DRM-managed action.
+ *
+ * The connector structure should be allocated with drmm_kzalloc().
+ *
+ * The @drm_connector_funcs.destroy hook must be NULL.
+ *
+ * Returns:
+ * Zero on success, error code on failure.
+ */
+int drmm_connector_hdmi_init(struct drm_device *dev,
+ struct drm_connector *connector,
+ const struct drm_connector_funcs *funcs,
+ const struct drm_connector_hdmi_funcs *hdmi_funcs,
+ int connector_type,
+ struct i2c_adapter *ddc)
+{
+ int ret;
+
+ if (!hdmi_funcs)
+ return -EINVAL;
+
+ if (!hdmi_funcs->vendor || !hdmi_funcs->product)
+ return -EINVAL;
+
+ if ((strlen(hdmi_funcs->vendor) > DRM_CONNECTOR_HDMI_VENDOR_LEN) ||
+ (strlen(hdmi_funcs->product) > DRM_CONNECTOR_HDMI_PRODUCT_LEN))
+ return -EINVAL;
+
+ if (!hdmi_funcs->supported_formats ||
+ !(hdmi_funcs->supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444)))
+ return -EINVAL;
+
+ if (connector->ycbcr_420_allowed !=
+ !!(hdmi_funcs->supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420)))
+ return -EINVAL;
+
+ if (!(hdmi_funcs->max_bpc == 8 ||
+ hdmi_funcs->max_bpc == 10 ||
+ hdmi_funcs->max_bpc == 12))
+ return -EINVAL;
+
+ if (!hdmi_funcs->avi.clear_infoframe ||
+ !hdmi_funcs->avi.write_infoframe ||
+ !hdmi_funcs->hdmi.clear_infoframe ||
+ !hdmi_funcs->hdmi.write_infoframe)
+ return -EINVAL;
+
+ if (!(connector_type == DRM_MODE_CONNECTOR_HDMIA ||
+ connector_type == DRM_MODE_CONNECTOR_HDMIB))
+ return -EINVAL;
+
+ ret = drmm_connector_init(dev, connector, funcs, connector_type, ddc);
+ if (ret)
+ return ret;
+
+ /* TODO: remove after conversion to new drmm_connector_hdmi_init() */
+ connector->hdmi.supported_formats = hdmi_funcs->supported_formats;
+
+ /*
+ * The supported HDMI version can be used to determinate the maximum
+ * TMDS character rate allowed by the specification. Some controllers,
+ * however, may support a lower rate than that version would imply.
+ *
+ * A non-zero caps->max_tmds_char_rate lets drivers override this
+ * default with the actual controller capability. A value of zero keeps
+ * the limit inferred from supported_hdmi_ver.
+ */
+ if (hdmi_funcs->supported_hdmi_ver >= HDMI_VERSION_2_0)
+ connector->hdmi.max_tmds_char_rate = HDMI_2_0_TMDS_CHAR_RATE_MAX_HZ;
+ else if (hdmi_funcs->supported_hdmi_ver >= HDMI_VERSION_1_3)
+ connector->hdmi.max_tmds_char_rate = HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ;
+ else if (hdmi_funcs->supported_hdmi_ver >= HDMI_VERSION_1_0)
+ connector->hdmi.max_tmds_char_rate = HDMI_1_0_TMDS_CHAR_RATE_MAX_HZ;
+
+ if (hdmi_funcs->supported_tmds_char_rate) {
+ if (hdmi_funcs->supported_tmds_char_rate > connector->hdmi.max_tmds_char_rate) {
+ drm_err(dev, "Enforced max_tmds_char_rate exceeds %llu spec limit\n",
+ connector->hdmi.max_tmds_char_rate);
+ return -EINVAL;
+ }
+ connector->hdmi.max_tmds_char_rate = hdmi_funcs->supported_tmds_char_rate;
+ }
+
+ /* TODO: remove after conversion to new drmm_connector_hdmi_init() */
+ strtomem_pad(connector->hdmi.vendor, hdmi_funcs->vendor, 0);
+ strtomem_pad(connector->hdmi.product, hdmi_funcs->product, 0);
+
+ /*
+ * drm_connector_attach_max_bpc_property() requires the
+ * connector to have a state.
+ */
+ if (connector->funcs->atomic_create_state) {
+ struct drm_connector_state *state;
+
+ state = connector->funcs->atomic_create_state(connector);
+ if (IS_ERR(state))
+ return PTR_ERR(state);
+
+ connector->state = state;
+ } else if (connector->funcs->reset) {
+ connector->funcs->reset(connector);
+ if (!connector->state)
+ return -ENOMEM;
+ }
+
+ drm_connector_attach_max_bpc_property(connector, 8, hdmi_funcs->max_bpc);
+ /* TODO: remove after conversion to new drmm_connector_hdmi_init() */
+ connector->max_bpc = hdmi_funcs->max_bpc;
+
+ if (hdmi_funcs->max_bpc > 8)
+ drm_connector_attach_hdr_output_metadata_property(connector);
+
+ ret = drm_connector_attach_color_format_property(connector,
+ hdmi_funcs->supported_formats);
+ if (ret)
+ return ret;
+
+ connector->hdmi.funcs = hdmi_funcs;
+
+ return 0;
+}
+EXPORT_SYMBOL(drmm_connector_hdmi_init);
+
/**
* drmm_connector_hdmi_ini2 - Init a preallocated HDMI connector
* @dev: DRM device
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 2e7d75cb0adf..2a49c4d55f77 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -1403,8 +1403,50 @@ struct drm_connector_infoframe_funcs {
/**
* struct drm_connector_hdmi_funcs - drm_hdmi_connector control functions
+ * and controller capabilities
*/
struct drm_connector_hdmi_funcs {
+ /**
+ * @vendor: HDMI Controller Vendor name.
+ */
+ const char *vendor;
+
+ /**
+ * @product: HDMI Controller Product name
+ */
+ const char *product;
+
+ /**
+ * @supported_hdmi_ver:
+ *
+ * Maximum HDMI specification version supported by the controller side
+ * of this connector. This describes the controller capability only;
+ * the effective link capabilities may be further restricted by the
+ * sink, bridge, or mode validation.
+ */
+ enum hdmi_version supported_hdmi_ver;
+
+ /**
+ * @supported_tmds_char_rate:
+ *
+ * Maximum TMDS character rate supported by the controller, in Hz.
+ * A value of 0 means the core should use the default limit implied by
+ * @supported_hdmi_ver.
+ */
+ unsigned long long supported_tmds_char_rate;
+
+ /**
+ * @supported_formats:
+ *
+ * Bitmask of @drm_output_color_format listing supported output formats.
+ */
+ unsigned long supported_formats;
+
+ /**
+ * @max_bpc: Maximum bits per char the HDMI connector supports.
+ */
+ unsigned int max_bpc;
+
/**
* @tmds_char_rate_valid:
*
@@ -2052,7 +2094,19 @@ struct drm_connector_hdmi {
unsigned long supported_formats;
/**
- * @funcs: HDMI connector Control Functions
+ * @max_tmds_char_rate: Maximum TMDS character rate, in Hz,
+ * supported by the controller.
+ *
+ * This is inferred from &drm_connector_hdmi_funcs.supported_hdmi_ver,
+ * by default. However, controllers may support a lower rate than that
+ * specification version would imply. If that is the case, drivers are
+ * expected to set &drm_connector_hdmi_funcs.supported_tmds_char_rate
+ * to a non-zero value indicating the actual limit.
+ */
+ unsigned long long max_tmds_char_rate;
+
+ /**
+ * @funcs: HDMI connector Control Functions and controller capabilities
*/
const struct drm_connector_hdmi_funcs *funcs;
@@ -2549,6 +2603,12 @@ int drmm_connector_init(struct drm_device *dev,
const struct drm_connector_funcs *funcs,
int connector_type,
struct i2c_adapter *ddc);
+int drmm_connector_hdmi_init(struct drm_device *dev,
+ struct drm_connector *connector,
+ const struct drm_connector_funcs *funcs,
+ const struct drm_connector_hdmi_funcs *hdmi_funcs,
+ int connector_type,
+ struct i2c_adapter *ddc);
int drmm_connector_hdmi_ini2(struct drm_device *dev,
struct drm_connector *connector,
const char *vendor, const char *product,
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 05/69] drm/display: bridge_connector: Convert to drmm_connector_hdmi_init()
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Maud Spierings, Diederik de Haas
Switch drm_bridge_connector to the new drmm_connector_hdmi_init()
signature. The vendor, product, supported_formats and max_bpc values
now live in struct drm_connector_hdmi_funcs instead of being passed as
separate arguments. This allows future HDMI 2.x capabilities to be
plumbed without growing the function's argument list.
Introduce the supported_hdmi_ver field in struct drm_bridge to let
bridges declare the HDMI specification version they comply with,
as well as max_tmds_char_rate to allow them to override the limit
inferred from that version. This is particularly useful when handling
chip variants with different capabilities.
Additionally, add a warning in drm_bridge_add() if an HDMI bridge leaves
supported_hdmi_ver unset. This alerts bridge drivers setting the
DRM_BRIDGE_OP_HDMI flag that they must also declare their supported HDMI
version.
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_bridge_connector.c | 43 ++++++++++++++++----------
drivers/gpu/drm/drm_bridge.c | 6 +++-
include/drm/drm_bridge.h | 14 +++++++++
3 files changed, 46 insertions(+), 17 deletions(-)
diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
index f75ce47a6350..9ad31e9df0ab 100644
--- a/drivers/gpu/drm/display/drm_bridge_connector.c
+++ b/drivers/gpu/drm/display/drm_bridge_connector.c
@@ -590,6 +590,8 @@ drm_bridge_connector_read_edid(struct drm_connector *connector)
}
static const struct drm_connector_hdmi_funcs drm_bridge_connector_hdmi_funcs = {
+ .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ .max_bpc = 8,
.tmds_char_rate_valid = drm_bridge_connector_tmds_char_rate_valid,
.read_edid = drm_bridge_connector_read_edid,
.avi = {
@@ -823,8 +825,6 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
struct drm_connector *connector;
struct i2c_adapter *ddc = NULL;
struct drm_bridge *panel_bridge __free(drm_bridge_put) = NULL;
- unsigned int supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444);
- unsigned int max_bpc = 8;
bool support_hdcp = false;
int connector_type;
int ret;
@@ -907,11 +907,6 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
return ERR_PTR(-EINVAL);
bridge_connector->bridge_hdmi = drm_bridge_get(bridge);
-
- if (bridge->supported_formats)
- supported_formats = bridge->supported_formats;
- if (bridge->max_bpc)
- max_bpc = bridge->max_bpc;
}
if (bridge->ops & DRM_BRIDGE_OP_HDMI_AUDIO) {
@@ -993,11 +988,31 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
return ERR_PTR(-EINVAL);
if (bridge_connector->bridge_hdmi) {
- if (!connector->ycbcr_420_allowed)
- supported_formats &= ~BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420);
-
bridge_connector->hdmi_funcs = drm_bridge_connector_hdmi_funcs;
+ bridge_connector->hdmi_funcs.vendor = bridge_connector->bridge_hdmi->vendor;
+ bridge_connector->hdmi_funcs.product = bridge_connector->bridge_hdmi->product;
+
+ if (bridge_connector->bridge_hdmi->supported_hdmi_ver)
+ bridge_connector->hdmi_funcs.supported_hdmi_ver =
+ bridge_connector->bridge_hdmi->supported_hdmi_ver;
+
+ if (bridge_connector->bridge_hdmi->supported_formats)
+ bridge_connector->hdmi_funcs.supported_formats =
+ bridge_connector->bridge_hdmi->supported_formats;
+
+ if (!connector->ycbcr_420_allowed)
+ bridge_connector->hdmi_funcs.supported_formats &=
+ ~BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420);
+
+ if (bridge_connector->bridge_hdmi->max_tmds_char_rate)
+ bridge_connector->hdmi_funcs.supported_tmds_char_rate =
+ bridge_connector->bridge_hdmi->max_tmds_char_rate;
+
+ if (bridge_connector->bridge_hdmi->max_bpc)
+ bridge_connector->hdmi_funcs.max_bpc =
+ bridge_connector->bridge_hdmi->max_bpc;
+
if (bridge_connector->bridge_hdmi->ops & DRM_BRIDGE_OP_HDMI_AUDIO)
bridge_connector->hdmi_funcs.audio =
drm_bridge_connector_hdmi_audio_infoframe;
@@ -1010,14 +1025,10 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
bridge_connector->hdmi_funcs.spd =
drm_bridge_connector_hdmi_spd_infoframe;
- ret = drmm_connector_hdmi_ini2(drm, connector,
- bridge_connector->bridge_hdmi->vendor,
- bridge_connector->bridge_hdmi->product,
+ ret = drmm_connector_hdmi_init(drm, connector,
&drm_bridge_connector_funcs,
&bridge_connector->hdmi_funcs,
- connector_type, ddc,
- supported_formats,
- max_bpc);
+ connector_type, ddc);
if (ret)
return ERR_PTR(ret);
} else {
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 83f1809a5d37..afaae272347c 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -460,9 +460,13 @@ void drm_bridge_add(struct drm_bridge *bridge)
mutex_init(&bridge->hpd_state_mutex);
mutex_init(&bridge->hpd_mutex);
- if (bridge->ops & DRM_BRIDGE_OP_HDMI)
+ if (bridge->ops & DRM_BRIDGE_OP_HDMI) {
+ if (bridge->supported_hdmi_ver == HDMI_VERSION_UNKNOWN)
+ DRM_WARN("HDMI bridge misses supported HDMI version\n");
+
bridge->ycbcr_420_allowed = !!(bridge->supported_formats &
BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420));
+ }
mutex_lock(&bridge_lock);
list_add_tail(&bridge->list, &bridge_list);
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index 58fff047f43b..5a5a25995471 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -1081,6 +1081,12 @@ struct drm_bridge {
*/
const char *product;
+ /**
+ * @supported_hdmi_ver: HDMI version the bridge is conformant with.
+ * This is only relevant if @DRM_BRIDGE_OP_HDMI is set.
+ */
+ enum hdmi_version supported_hdmi_ver;
+
/**
* @supported_formats: Bitmask of @drm_output_color_format listing
* supported output formats. This is only relevant if
@@ -1088,6 +1094,14 @@ struct drm_bridge {
*/
unsigned int supported_formats;
+ /**
+ * @max_tmds_char_rate: Maximum TMDS character rate, in Hz, the HDMI
+ * bridge supports. A value of 0 means the core should use the default
+ * limit implied by @supported_hdmi_ver. This is only relevant if
+ * @DRM_BRIDGE_OP_HDMI is set.
+ */
+ unsigned long long max_tmds_char_rate;
+
/**
* @max_bpc: Maximum bits per char the HDMI bridge supports. Allowed
* values are 8, 10 and 12. This is only relevant if
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 05/69] drm/display: bridge_connector: Convert to drmm_connector_hdmi_init()
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Maud Spierings, Diederik de Haas
Switch drm_bridge_connector to the new drmm_connector_hdmi_init()
signature. The vendor, product, supported_formats and max_bpc values
now live in struct drm_connector_hdmi_funcs instead of being passed as
separate arguments. This allows future HDMI 2.x capabilities to be
plumbed without growing the function's argument list.
Introduce the supported_hdmi_ver field in struct drm_bridge to let
bridges declare the HDMI specification version they comply with,
as well as max_tmds_char_rate to allow them to override the limit
inferred from that version. This is particularly useful when handling
chip variants with different capabilities.
Additionally, add a warning in drm_bridge_add() if an HDMI bridge leaves
supported_hdmi_ver unset. This alerts bridge drivers setting the
DRM_BRIDGE_OP_HDMI flag that they must also declare their supported HDMI
version.
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_bridge_connector.c | 43 ++++++++++++++++----------
drivers/gpu/drm/drm_bridge.c | 6 +++-
include/drm/drm_bridge.h | 14 +++++++++
3 files changed, 46 insertions(+), 17 deletions(-)
diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
index f75ce47a6350..9ad31e9df0ab 100644
--- a/drivers/gpu/drm/display/drm_bridge_connector.c
+++ b/drivers/gpu/drm/display/drm_bridge_connector.c
@@ -590,6 +590,8 @@ drm_bridge_connector_read_edid(struct drm_connector *connector)
}
static const struct drm_connector_hdmi_funcs drm_bridge_connector_hdmi_funcs = {
+ .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ .max_bpc = 8,
.tmds_char_rate_valid = drm_bridge_connector_tmds_char_rate_valid,
.read_edid = drm_bridge_connector_read_edid,
.avi = {
@@ -823,8 +825,6 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
struct drm_connector *connector;
struct i2c_adapter *ddc = NULL;
struct drm_bridge *panel_bridge __free(drm_bridge_put) = NULL;
- unsigned int supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444);
- unsigned int max_bpc = 8;
bool support_hdcp = false;
int connector_type;
int ret;
@@ -907,11 +907,6 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
return ERR_PTR(-EINVAL);
bridge_connector->bridge_hdmi = drm_bridge_get(bridge);
-
- if (bridge->supported_formats)
- supported_formats = bridge->supported_formats;
- if (bridge->max_bpc)
- max_bpc = bridge->max_bpc;
}
if (bridge->ops & DRM_BRIDGE_OP_HDMI_AUDIO) {
@@ -993,11 +988,31 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
return ERR_PTR(-EINVAL);
if (bridge_connector->bridge_hdmi) {
- if (!connector->ycbcr_420_allowed)
- supported_formats &= ~BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420);
-
bridge_connector->hdmi_funcs = drm_bridge_connector_hdmi_funcs;
+ bridge_connector->hdmi_funcs.vendor = bridge_connector->bridge_hdmi->vendor;
+ bridge_connector->hdmi_funcs.product = bridge_connector->bridge_hdmi->product;
+
+ if (bridge_connector->bridge_hdmi->supported_hdmi_ver)
+ bridge_connector->hdmi_funcs.supported_hdmi_ver =
+ bridge_connector->bridge_hdmi->supported_hdmi_ver;
+
+ if (bridge_connector->bridge_hdmi->supported_formats)
+ bridge_connector->hdmi_funcs.supported_formats =
+ bridge_connector->bridge_hdmi->supported_formats;
+
+ if (!connector->ycbcr_420_allowed)
+ bridge_connector->hdmi_funcs.supported_formats &=
+ ~BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420);
+
+ if (bridge_connector->bridge_hdmi->max_tmds_char_rate)
+ bridge_connector->hdmi_funcs.supported_tmds_char_rate =
+ bridge_connector->bridge_hdmi->max_tmds_char_rate;
+
+ if (bridge_connector->bridge_hdmi->max_bpc)
+ bridge_connector->hdmi_funcs.max_bpc =
+ bridge_connector->bridge_hdmi->max_bpc;
+
if (bridge_connector->bridge_hdmi->ops & DRM_BRIDGE_OP_HDMI_AUDIO)
bridge_connector->hdmi_funcs.audio =
drm_bridge_connector_hdmi_audio_infoframe;
@@ -1010,14 +1025,10 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
bridge_connector->hdmi_funcs.spd =
drm_bridge_connector_hdmi_spd_infoframe;
- ret = drmm_connector_hdmi_ini2(drm, connector,
- bridge_connector->bridge_hdmi->vendor,
- bridge_connector->bridge_hdmi->product,
+ ret = drmm_connector_hdmi_init(drm, connector,
&drm_bridge_connector_funcs,
&bridge_connector->hdmi_funcs,
- connector_type, ddc,
- supported_formats,
- max_bpc);
+ connector_type, ddc);
if (ret)
return ERR_PTR(ret);
} else {
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 83f1809a5d37..afaae272347c 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -460,9 +460,13 @@ void drm_bridge_add(struct drm_bridge *bridge)
mutex_init(&bridge->hpd_state_mutex);
mutex_init(&bridge->hpd_mutex);
- if (bridge->ops & DRM_BRIDGE_OP_HDMI)
+ if (bridge->ops & DRM_BRIDGE_OP_HDMI) {
+ if (bridge->supported_hdmi_ver == HDMI_VERSION_UNKNOWN)
+ DRM_WARN("HDMI bridge misses supported HDMI version\n");
+
bridge->ycbcr_420_allowed = !!(bridge->supported_formats &
BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420));
+ }
mutex_lock(&bridge_lock);
list_add_tail(&bridge->list, &bridge_list);
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index 58fff047f43b..5a5a25995471 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -1081,6 +1081,12 @@ struct drm_bridge {
*/
const char *product;
+ /**
+ * @supported_hdmi_ver: HDMI version the bridge is conformant with.
+ * This is only relevant if @DRM_BRIDGE_OP_HDMI is set.
+ */
+ enum hdmi_version supported_hdmi_ver;
+
/**
* @supported_formats: Bitmask of @drm_output_color_format listing
* supported output formats. This is only relevant if
@@ -1088,6 +1094,14 @@ struct drm_bridge {
*/
unsigned int supported_formats;
+ /**
+ * @max_tmds_char_rate: Maximum TMDS character rate, in Hz, the HDMI
+ * bridge supports. A value of 0 means the core should use the default
+ * limit implied by @supported_hdmi_ver. This is only relevant if
+ * @DRM_BRIDGE_OP_HDMI is set.
+ */
+ unsigned long long max_tmds_char_rate;
+
/**
* @max_bpc: Maximum bits per char the HDMI bridge supports. Allowed
* values are 8, 10 and 12. This is only relevant if
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 06/69] drm/probe-helper: Introduce .force_ctx() connector callback
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
The .force() connector callback is invoked by
drm_helper_probe_single_connector_modes() while the modeset acquire
context it created is live, but the hook signature provides no way to
pass it down, e.g. to support implementations needing to lock further
objects.
Add a .force_ctx() variant to drm_connector_helper_funcs, taking the
acquire context and returning an error code, so that -EDEADLK propagates
into the existing retry path. When provided, it takes precedence over
drm_connector_funcs' .force(), which is kept for existing users.
This is a prerequisite for SCDC status synchronization in the HDMI
connector framework.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/drm_probe_helper.c | 14 +++++++++++++-
include/drm/drm_connector.h | 6 ++++++
include/drm/drm_modeset_helper_vtables.h | 28 ++++++++++++++++++++++++++++
3 files changed, 47 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c
index e26ead5b5e58..918255bcfa09 100644
--- a/drivers/gpu/drm/drm_probe_helper.c
+++ b/drivers/gpu/drm/drm_probe_helper.c
@@ -559,6 +559,7 @@ static int __drm_helper_update_and_validate(struct drm_connector *connector,
int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
uint32_t maxX, uint32_t maxY)
{
+ const struct drm_connector_helper_funcs *funcs = connector->helper_private;
struct drm_device *dev = connector->dev;
struct drm_display_mode *mode;
int count = 0, ret;
@@ -592,8 +593,19 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
connector->status = connector_status_connected;
else
connector->status = connector_status_disconnected;
- if (connector->funcs->force)
+
+ if (funcs && funcs->force_ctx) {
+ ret = funcs->force_ctx(connector, &ctx);
+ if (ret == -EDEADLK) {
+ drm_modeset_backoff(&ctx);
+ goto retry;
+ } else if (ret < 0) {
+ drm_dbg_kms(dev, "[CONNECTOR:%d:%s] force_ctx failed: %d\n",
+ connector->base.id, connector->name, ret);
+ }
+ } else if (connector->funcs->force) {
connector->funcs->force(connector);
+ }
} else {
ret = drm_helper_probe_detect(connector, &ctx, true);
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 2a49c4d55f77..a6de3e63b462 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -1603,6 +1603,12 @@ struct drm_connector_funcs {
* the sysfs interfaces or on the kernel cmdline. In that case the
* @detect callback isn't called.
*
+ * New drivers should implement
+ * &drm_connector_helper_funcs.force_ctx instead, which gets passed
+ * the modeset acquire context and thus allows taking additional
+ * locks. It takes precedence over this callback when both are
+ * implemented.
+ *
* FIXME:
*
* Note that this hook is only called by the probe helper. It's not in
diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h
index ca6268945c28..cf5fe5ba2b18 100644
--- a/include/drm/drm_modeset_helper_vtables.h
+++ b/include/drm/drm_modeset_helper_vtables.h
@@ -921,6 +921,34 @@ struct drm_connector_helper_funcs {
struct drm_modeset_acquire_ctx *ctx,
bool force);
+ /**
+ * @force_ctx:
+ *
+ * This function is called to update internal encoder state when the
+ * connector is forced to a certain state by userspace, either through
+ * the sysfs interfaces or on the kernel cmdline. In that case the
+ * @detect_ctx callback isn't called.
+ *
+ * This is the atomic version of &drm_connector_funcs.force. When
+ * both are implemented, this one takes precedence and
+ * &drm_connector_funcs.force is not called.
+ *
+ * To avoid races against concurrent connector state updates, the
+ * helper libraries always call this with ctx set to a valid context,
+ * and &drm_mode_config.connection_mutex will always be locked with
+ * the ctx parameter set to this ctx. This allows taking additional
+ * locks as required.
+ *
+ * RETURNS:
+ *
+ * Zero on success, or a negative error code otherwise. This includes
+ * -EDEADLK when a lock acquisition needs to be restarted, in which
+ * case the helpers take care of backing off and calling this function
+ * again.
+ */
+ int (*force_ctx)(struct drm_connector *connector,
+ struct drm_modeset_acquire_ctx *ctx);
+
/**
* @mode_valid:
*
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 06/69] drm/probe-helper: Introduce .force_ctx() connector callback
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
The .force() connector callback is invoked by
drm_helper_probe_single_connector_modes() while the modeset acquire
context it created is live, but the hook signature provides no way to
pass it down, e.g. to support implementations needing to lock further
objects.
Add a .force_ctx() variant to drm_connector_helper_funcs, taking the
acquire context and returning an error code, so that -EDEADLK propagates
into the existing retry path. When provided, it takes precedence over
drm_connector_funcs' .force(), which is kept for existing users.
This is a prerequisite for SCDC status synchronization in the HDMI
connector framework.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/drm_probe_helper.c | 14 +++++++++++++-
include/drm/drm_connector.h | 6 ++++++
include/drm/drm_modeset_helper_vtables.h | 28 ++++++++++++++++++++++++++++
3 files changed, 47 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c
index e26ead5b5e58..918255bcfa09 100644
--- a/drivers/gpu/drm/drm_probe_helper.c
+++ b/drivers/gpu/drm/drm_probe_helper.c
@@ -559,6 +559,7 @@ static int __drm_helper_update_and_validate(struct drm_connector *connector,
int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
uint32_t maxX, uint32_t maxY)
{
+ const struct drm_connector_helper_funcs *funcs = connector->helper_private;
struct drm_device *dev = connector->dev;
struct drm_display_mode *mode;
int count = 0, ret;
@@ -592,8 +593,19 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
connector->status = connector_status_connected;
else
connector->status = connector_status_disconnected;
- if (connector->funcs->force)
+
+ if (funcs && funcs->force_ctx) {
+ ret = funcs->force_ctx(connector, &ctx);
+ if (ret == -EDEADLK) {
+ drm_modeset_backoff(&ctx);
+ goto retry;
+ } else if (ret < 0) {
+ drm_dbg_kms(dev, "[CONNECTOR:%d:%s] force_ctx failed: %d\n",
+ connector->base.id, connector->name, ret);
+ }
+ } else if (connector->funcs->force) {
connector->funcs->force(connector);
+ }
} else {
ret = drm_helper_probe_detect(connector, &ctx, true);
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 2a49c4d55f77..a6de3e63b462 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -1603,6 +1603,12 @@ struct drm_connector_funcs {
* the sysfs interfaces or on the kernel cmdline. In that case the
* @detect callback isn't called.
*
+ * New drivers should implement
+ * &drm_connector_helper_funcs.force_ctx instead, which gets passed
+ * the modeset acquire context and thus allows taking additional
+ * locks. It takes precedence over this callback when both are
+ * implemented.
+ *
* FIXME:
*
* Note that this hook is only called by the probe helper. It's not in
diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h
index ca6268945c28..cf5fe5ba2b18 100644
--- a/include/drm/drm_modeset_helper_vtables.h
+++ b/include/drm/drm_modeset_helper_vtables.h
@@ -921,6 +921,34 @@ struct drm_connector_helper_funcs {
struct drm_modeset_acquire_ctx *ctx,
bool force);
+ /**
+ * @force_ctx:
+ *
+ * This function is called to update internal encoder state when the
+ * connector is forced to a certain state by userspace, either through
+ * the sysfs interfaces or on the kernel cmdline. In that case the
+ * @detect_ctx callback isn't called.
+ *
+ * This is the atomic version of &drm_connector_funcs.force. When
+ * both are implemented, this one takes precedence and
+ * &drm_connector_funcs.force is not called.
+ *
+ * To avoid races against concurrent connector state updates, the
+ * helper libraries always call this with ctx set to a valid context,
+ * and &drm_mode_config.connection_mutex will always be locked with
+ * the ctx parameter set to this ctx. This allows taking additional
+ * locks as required.
+ *
+ * RETURNS:
+ *
+ * Zero on success, or a negative error code otherwise. This includes
+ * -EDEADLK when a lock acquisition needs to be restarted, in which
+ * case the helpers take care of backing off and calling this function
+ * again.
+ */
+ int (*force_ctx)(struct drm_connector *connector,
+ struct drm_modeset_acquire_ctx *ctx);
+
/**
* @mode_valid:
*
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* Re: [PATCH v10 06/69] drm/probe-helper: Introduce .force_ctx() connector callback
2026-07-31 16:19 ` Cristian Ciocaltea
(?)
@ 2026-07-31 17:06 ` sashiko-bot
-1 siblings, 0 replies; 155+ messages in thread
From: sashiko-bot @ 2026-07-31 17:06 UTC (permalink / raw)
To: Cristian Ciocaltea; +Cc: dri-devel, linux-sunxi
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Modifying `connector->status` before `force_ctx()` can return `-EDEADLK` causes subsequent retries to incorrectly evaluate `old_status == connector->status`, silently skipping the hotplug event.
--
--- Patch [6]: [PATCH v10 06/69] drm/probe-helper: Introduce .force_ctx() connector callback ---
commit b08054d3073ea6707b0fe9e517dde416f7e5c8b6
Author: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
drm/probe-helper: Introduce .force_ctx() connector callback
This commit introduces a force_ctx() variant to the connector helper
functions, taking a modeset acquire context and returning an error code
so that -EDEADLK can propagate. It takes precedence over the existing
force() callback when both are implemented.
> diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c
> index e26ead5b5e589..918255bcfa096 100644
> --- a/drivers/gpu/drm/drm_probe_helper.c
> +++ b/drivers/gpu/drm/drm_probe_helper.c
[ ... ]
> @@ -592,8 +593,19 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
> connector->status = connector_status_connected;
> else
> connector->status = connector_status_disconnected;
> - if (connector->funcs->force)
> +
> + if (funcs && funcs->force_ctx) {
> + ret = funcs->force_ctx(connector, &ctx);
> + if (ret == -EDEADLK) {
> + drm_modeset_backoff(&ctx);
> + goto retry;
[Severity: Medium]
Does modifying connector->status before force_ctx() cause hotplug events
to be dropped on lock contention?
If funcs->force_ctx() returns -EDEADLK, the code branches to the retry
label. During the retry loop, old_status is assigned the current
connector->status:
drm_helper_probe_single_connector_modes() {
retry:
...
old_status = connector->status;
Since connector->status was already updated prior to the failed attempt,
old_status will equal the new status. When the lock is finally acquired
after the retry, the old_status != connector->status check later in the
function evaluates to false, causing the hotplug event detection logic
to be silently skipped.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260731-dw-hdmi-qp-scramb-v10-0-294364b2cf15@collabora.com?part=6
^ permalink raw reply [flat|nested] 155+ messages in thread
* [PATCH v10 07/69] drm/connector: Add HDMI 2.0 scrambler infrastructure
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Maud Spierings, Diederik de Haas
Add the connector-level infrastructure to support HDMI 2.0 scrambling:
- A drm_connector_hdmi_scrambler_supported() helper to report whether
the source supports the scrambling capability, based on the presence
of 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) to monitor sink-side scrambling status
and retry the setup if the sink resets it
- A scdc_work_initialized flag to support lazy initialization of the
work item on the first scrambling enable and guard the teardown paths
These are intended to be used by SCDC scrambling helpers to coordinate
scrambling setup and teardown between the source driver and the DRM
core.
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/drm_connector.c | 31 ++++++++++++---
include/drm/drm_connector.h | 83 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 109 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 4721cdeafc84..a18410faf040 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -622,12 +622,29 @@ int drmm_connector_hdmi_init(struct drm_device *dev,
* default with the actual controller capability. A value of zero keeps
* the limit inferred from supported_hdmi_ver.
*/
- if (hdmi_funcs->supported_hdmi_ver >= HDMI_VERSION_2_0)
+ if (hdmi_funcs->supported_hdmi_ver >= HDMI_VERSION_2_0) {
+ if (!hdmi_funcs->scrambler_enable || !hdmi_funcs->scrambler_disable) {
+ drm_err(dev, "Scrambler callbacks missing for HDMI 2.x\n");
+ return -EINVAL;
+ }
+
connector->hdmi.max_tmds_char_rate = HDMI_2_0_TMDS_CHAR_RATE_MAX_HZ;
- else if (hdmi_funcs->supported_hdmi_ver >= HDMI_VERSION_1_3)
- connector->hdmi.max_tmds_char_rate = HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ;
- else if (hdmi_funcs->supported_hdmi_ver >= HDMI_VERSION_1_0)
- connector->hdmi.max_tmds_char_rate = HDMI_1_0_TMDS_CHAR_RATE_MAX_HZ;
+ } else {
+ /*
+ * Scrambler callbacks are only valid for connectors advertising
+ * HDMI 2.0 capability. drm_connector_hdmi_scrambler_supported()
+ * relies on their presence to report scrambling support.
+ */
+ if (hdmi_funcs->scrambler_enable || hdmi_funcs->scrambler_disable) {
+ drm_err(dev, "Scrambler callbacks unexpected for HDMI 1.x\n");
+ return -EINVAL;
+ }
+
+ if (hdmi_funcs->supported_hdmi_ver >= HDMI_VERSION_1_3)
+ connector->hdmi.max_tmds_char_rate = HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ;
+ else if (hdmi_funcs->supported_hdmi_ver >= HDMI_VERSION_1_0)
+ connector->hdmi.max_tmds_char_rate = HDMI_1_0_TMDS_CHAR_RATE_MAX_HZ;
+ }
if (hdmi_funcs->supported_tmds_char_rate) {
if (hdmi_funcs->supported_tmds_char_rate > connector->hdmi.max_tmds_char_rate) {
@@ -635,6 +652,7 @@ int drmm_connector_hdmi_init(struct drm_device *dev,
connector->hdmi.max_tmds_char_rate);
return -EINVAL;
}
+
connector->hdmi.max_tmds_char_rate = hdmi_funcs->supported_tmds_char_rate;
}
@@ -918,6 +936,9 @@ void drm_connector_cleanup(struct drm_connector *connector)
DRM_CONNECTOR_REGISTERED))
drm_connector_unregister(connector);
+ if (connector->hdmi.scdc_work_initialized)
+ cancel_delayed_work_sync(&connector->hdmi.scdc_work);
+
platform_device_unregister(connector->hdmi_audio.codec_pdev);
if (connector->privacy_screen) {
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index a6de3e63b462..89a140d6f064 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>
@@ -1131,6 +1132,17 @@ 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() according to
+ * the HDMI 2.0 specification: scrambling is mandatory above a 340 MHz
+ * TMDS character rate. Optional scrambling at lower rates is
+ * deliberately not requested by the helper.
+ */
+ bool scrambler_needed;
};
/**
@@ -1481,6 +1493,36 @@ struct drm_connector_hdmi_funcs {
*/
const struct drm_edid *(*read_edid)(struct drm_connector *connector);
+ /**
+ * @scrambler_enable:
+ *
+ * The callback is invoked via @drm_connector_hdmi_enable_scrambling
+ * during commit to setup SCDC scrambling and high TMDS clock ratio on
+ * the 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:
+ *
+ * The callback is invoked via @drm_connector_hdmi_disable_scrambling
+ * during commit to tear down SCDC scrambling and high TMDS clock ratio
+ * on the 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:
*
@@ -2111,6 +2153,25 @@ struct drm_connector_hdmi {
*/
unsigned long long max_tmds_char_rate;
+ /**
+ * @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_work_initialized: Tracks whether @scdc_work has been set up via
+ * INIT_DELAYED_WORK(). The work item is initialized lazily on the first
+ * scrambling enable, so this guards the teardown paths against touching
+ * an uninitialized work item.
+ */
+ bool scdc_work_initialized;
+
/**
* @funcs: HDMI connector Control Functions and controller capabilities
*/
@@ -2702,6 +2763,28 @@ drm_connector_is_unregistered(struct drm_connector *connector)
DRM_CONNECTOR_UNREGISTERED;
}
+/**
+ * drm_connector_hdmi_scrambler_supported - does connector support HDMI
+ * scrambling?
+ * @connector: DRM connector
+ *
+ * Checks whether or not @connector driver supports HDMI scrambling. When
+ * controller advertises HDMI_VERSION_2_0 support, the
+ * @drm_connector_hdmi_funcs.scrambler_enable and
+ * @drm_connector_hdmi_funcs.scrambler_disable callbacks are mandatory and
+ * enforced during drmm_connector_hdmi_init().
+ *
+ * Returns:
+ * True if the connector supports scrambling, false otherwise.
+ */
+static inline bool
+drm_connector_hdmi_scrambler_supported(struct drm_connector *connector)
+{
+ return connector->hdmi.funcs &&
+ connector->hdmi.funcs->scrambler_enable &&
+ connector->hdmi.funcs->scrambler_disable;
+}
+
void drm_connector_oob_hotplug_event(struct fwnode_handle *connector_fwnode,
enum drm_connector_status status);
enum drm_connector_color_format
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 07/69] drm/connector: Add HDMI 2.0 scrambler infrastructure
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Maud Spierings, Diederik de Haas
Add the connector-level infrastructure to support HDMI 2.0 scrambling:
- A drm_connector_hdmi_scrambler_supported() helper to report whether
the source supports the scrambling capability, based on the presence
of 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) to monitor sink-side scrambling status
and retry the setup if the sink resets it
- A scdc_work_initialized flag to support lazy initialization of the
work item on the first scrambling enable and guard the teardown paths
These are intended to be used by SCDC scrambling helpers to coordinate
scrambling setup and teardown between the source driver and the DRM
core.
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/drm_connector.c | 31 ++++++++++++---
include/drm/drm_connector.h | 83 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 109 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 4721cdeafc84..a18410faf040 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -622,12 +622,29 @@ int drmm_connector_hdmi_init(struct drm_device *dev,
* default with the actual controller capability. A value of zero keeps
* the limit inferred from supported_hdmi_ver.
*/
- if (hdmi_funcs->supported_hdmi_ver >= HDMI_VERSION_2_0)
+ if (hdmi_funcs->supported_hdmi_ver >= HDMI_VERSION_2_0) {
+ if (!hdmi_funcs->scrambler_enable || !hdmi_funcs->scrambler_disable) {
+ drm_err(dev, "Scrambler callbacks missing for HDMI 2.x\n");
+ return -EINVAL;
+ }
+
connector->hdmi.max_tmds_char_rate = HDMI_2_0_TMDS_CHAR_RATE_MAX_HZ;
- else if (hdmi_funcs->supported_hdmi_ver >= HDMI_VERSION_1_3)
- connector->hdmi.max_tmds_char_rate = HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ;
- else if (hdmi_funcs->supported_hdmi_ver >= HDMI_VERSION_1_0)
- connector->hdmi.max_tmds_char_rate = HDMI_1_0_TMDS_CHAR_RATE_MAX_HZ;
+ } else {
+ /*
+ * Scrambler callbacks are only valid for connectors advertising
+ * HDMI 2.0 capability. drm_connector_hdmi_scrambler_supported()
+ * relies on their presence to report scrambling support.
+ */
+ if (hdmi_funcs->scrambler_enable || hdmi_funcs->scrambler_disable) {
+ drm_err(dev, "Scrambler callbacks unexpected for HDMI 1.x\n");
+ return -EINVAL;
+ }
+
+ if (hdmi_funcs->supported_hdmi_ver >= HDMI_VERSION_1_3)
+ connector->hdmi.max_tmds_char_rate = HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ;
+ else if (hdmi_funcs->supported_hdmi_ver >= HDMI_VERSION_1_0)
+ connector->hdmi.max_tmds_char_rate = HDMI_1_0_TMDS_CHAR_RATE_MAX_HZ;
+ }
if (hdmi_funcs->supported_tmds_char_rate) {
if (hdmi_funcs->supported_tmds_char_rate > connector->hdmi.max_tmds_char_rate) {
@@ -635,6 +652,7 @@ int drmm_connector_hdmi_init(struct drm_device *dev,
connector->hdmi.max_tmds_char_rate);
return -EINVAL;
}
+
connector->hdmi.max_tmds_char_rate = hdmi_funcs->supported_tmds_char_rate;
}
@@ -918,6 +936,9 @@ void drm_connector_cleanup(struct drm_connector *connector)
DRM_CONNECTOR_REGISTERED))
drm_connector_unregister(connector);
+ if (connector->hdmi.scdc_work_initialized)
+ cancel_delayed_work_sync(&connector->hdmi.scdc_work);
+
platform_device_unregister(connector->hdmi_audio.codec_pdev);
if (connector->privacy_screen) {
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index a6de3e63b462..89a140d6f064 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>
@@ -1131,6 +1132,17 @@ 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() according to
+ * the HDMI 2.0 specification: scrambling is mandatory above a 340 MHz
+ * TMDS character rate. Optional scrambling at lower rates is
+ * deliberately not requested by the helper.
+ */
+ bool scrambler_needed;
};
/**
@@ -1481,6 +1493,36 @@ struct drm_connector_hdmi_funcs {
*/
const struct drm_edid *(*read_edid)(struct drm_connector *connector);
+ /**
+ * @scrambler_enable:
+ *
+ * The callback is invoked via @drm_connector_hdmi_enable_scrambling
+ * during commit to setup SCDC scrambling and high TMDS clock ratio on
+ * the 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:
+ *
+ * The callback is invoked via @drm_connector_hdmi_disable_scrambling
+ * during commit to tear down SCDC scrambling and high TMDS clock ratio
+ * on the 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:
*
@@ -2111,6 +2153,25 @@ struct drm_connector_hdmi {
*/
unsigned long long max_tmds_char_rate;
+ /**
+ * @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_work_initialized: Tracks whether @scdc_work has been set up via
+ * INIT_DELAYED_WORK(). The work item is initialized lazily on the first
+ * scrambling enable, so this guards the teardown paths against touching
+ * an uninitialized work item.
+ */
+ bool scdc_work_initialized;
+
/**
* @funcs: HDMI connector Control Functions and controller capabilities
*/
@@ -2702,6 +2763,28 @@ drm_connector_is_unregistered(struct drm_connector *connector)
DRM_CONNECTOR_UNREGISTERED;
}
+/**
+ * drm_connector_hdmi_scrambler_supported - does connector support HDMI
+ * scrambling?
+ * @connector: DRM connector
+ *
+ * Checks whether or not @connector driver supports HDMI scrambling. When
+ * controller advertises HDMI_VERSION_2_0 support, the
+ * @drm_connector_hdmi_funcs.scrambler_enable and
+ * @drm_connector_hdmi_funcs.scrambler_disable callbacks are mandatory and
+ * enforced during drmm_connector_hdmi_init().
+ *
+ * Returns:
+ * True if the connector supports scrambling, false otherwise.
+ */
+static inline bool
+drm_connector_hdmi_scrambler_supported(struct drm_connector *connector)
+{
+ return connector->hdmi.funcs &&
+ connector->hdmi.funcs->scrambler_enable &&
+ connector->hdmi.funcs->scrambler_disable;
+}
+
void drm_connector_oob_hotplug_event(struct fwnode_handle *connector_fwnode,
enum drm_connector_status status);
enum drm_connector_color_format
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 08/69] drm/display: scdc-helper: Add macro for connector-prefixed debug messages
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Maud Spierings, Diederik de Haas
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.
Acked-by: Maxime Ripard <mripard@kernel.org>
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
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.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 08/69] drm/display: scdc-helper: Add macro for connector-prefixed debug messages
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Maud Spierings, Diederik de Haas
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.
Acked-by: Maxime Ripard <mripard@kernel.org>
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
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.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 09/69] drm/display: scdc-helper: Add helper to set SCDC version information
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Dmitry Baryshkov, Maud Spierings,
Diederik de Haas
The HDMI 2.x specs mandate that compliant Sink devices report their SCDC
version in the Sink Version register, which reads as 1 on any
SCDC-capable sink.
There is also a dedicated Source Version register. Writing it is not
compulsory, but the spec advises that compliant Source devices do so, in
which case the value must be 1.
Add drm_scdc_set_source_version() to follow this recommendation. The
Sink Version register is read first, both to log the advertised SCDC
version and to guard against non-conformant devices: a sink reporting
version 0 is either not SCDC-version-aware or broken, so writing the
source version gains nothing and risks upsetting such hardware. In that
case the write is skipped.
The source version is passed as a parameter rather than hardcoded, as
future spec revisions may define additional rules for the allowable
version values. The written value is additionally clamped to the sink's
reported version so the source never advertises a version the sink does
not understand.
Acked-by: Maxime Ripard <mripard@kernel.org>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_scdc_helper.c | 46 ++++++++++++++++++++++++++++++-
include/drm/display/drm_scdc_helper.h | 2 ++
2 files changed, 47 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/display/drm_scdc_helper.c b/drivers/gpu/drm/display/drm_scdc_helper.c
index cb6632346aad..6d804ee19420 100644
--- a/drivers/gpu/drm/display/drm_scdc_helper.c
+++ b/drivers/gpu/drm/display/drm_scdc_helper.c
@@ -21,10 +21,11 @@
* 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/display/drm_scdc_helper.h>
#include <drm/drm_connector.h>
@@ -270,3 +271,46 @@ bool drm_scdc_set_high_tmds_clock_ratio(struct drm_connector *connector,
return true;
}
EXPORT_SYMBOL(drm_scdc_set_high_tmds_clock_ratio);
+
+/**
+ * drm_scdc_set_source_version - set SCDC source version on the sink
+ * @connector: connector
+ * @ver: source version to advertise (per spec, 1)
+ *
+ * Reads the sink version for diagnostics and as a guard, then writes
+ * the source version unless the sink reports version 0.
+ *
+ * Returns:
+ * 0 on success or when skipped; a negative error code when either
+ * the read or the write failed.
+ */
+int drm_scdc_set_source_version(struct drm_connector *connector, u8 ver)
+{
+ u8 sink_ver;
+ int ret;
+
+ ret = drm_scdc_readb(connector->ddc, SCDC_SINK_VERSION, &sink_ver);
+ if (ret) {
+ drm_scdc_dbg(connector, "Failed to read SCDC_SINK_VERSION: %d\n", ret);
+ return ret;
+ }
+
+ drm_scdc_dbg(connector, "Sink reported SCDC ver. %u\n", sink_ver);
+
+ /*
+ * Only advertise our source version to sinks that report a
+ * non-zero sink version. A sink reporting version 0 is either
+ * not SCDC-version-aware or non-conformant; writing the source
+ * version gains nothing and may upset broken hardware.
+ */
+ if (sink_ver) {
+ ret = drm_scdc_writeb(connector->ddc, SCDC_SOURCE_VERSION,
+ min_t(u8, sink_ver, ver));
+ if (ret)
+ drm_scdc_dbg(connector,
+ "Failed to write SCDC_SOURCE_VERSION: %d\n", ret);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(drm_scdc_set_source_version);
diff --git a/include/drm/display/drm_scdc_helper.h b/include/drm/display/drm_scdc_helper.h
index 34600476a1b9..90b0828364c2 100644
--- a/include/drm/display/drm_scdc_helper.h
+++ b/include/drm/display/drm_scdc_helper.h
@@ -77,4 +77,6 @@ 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_set_source_version(struct drm_connector *connector, u8 ver);
+
#endif
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 09/69] drm/display: scdc-helper: Add helper to set SCDC version information
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Dmitry Baryshkov, Maud Spierings,
Diederik de Haas
The HDMI 2.x specs mandate that compliant Sink devices report their SCDC
version in the Sink Version register, which reads as 1 on any
SCDC-capable sink.
There is also a dedicated Source Version register. Writing it is not
compulsory, but the spec advises that compliant Source devices do so, in
which case the value must be 1.
Add drm_scdc_set_source_version() to follow this recommendation. The
Sink Version register is read first, both to log the advertised SCDC
version and to guard against non-conformant devices: a sink reporting
version 0 is either not SCDC-version-aware or broken, so writing the
source version gains nothing and risks upsetting such hardware. In that
case the write is skipped.
The source version is passed as a parameter rather than hardcoded, as
future spec revisions may define additional rules for the allowable
version values. The written value is additionally clamped to the sink's
reported version so the source never advertises a version the sink does
not understand.
Acked-by: Maxime Ripard <mripard@kernel.org>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_scdc_helper.c | 46 ++++++++++++++++++++++++++++++-
include/drm/display/drm_scdc_helper.h | 2 ++
2 files changed, 47 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/display/drm_scdc_helper.c b/drivers/gpu/drm/display/drm_scdc_helper.c
index cb6632346aad..6d804ee19420 100644
--- a/drivers/gpu/drm/display/drm_scdc_helper.c
+++ b/drivers/gpu/drm/display/drm_scdc_helper.c
@@ -21,10 +21,11 @@
* 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/display/drm_scdc_helper.h>
#include <drm/drm_connector.h>
@@ -270,3 +271,46 @@ bool drm_scdc_set_high_tmds_clock_ratio(struct drm_connector *connector,
return true;
}
EXPORT_SYMBOL(drm_scdc_set_high_tmds_clock_ratio);
+
+/**
+ * drm_scdc_set_source_version - set SCDC source version on the sink
+ * @connector: connector
+ * @ver: source version to advertise (per spec, 1)
+ *
+ * Reads the sink version for diagnostics and as a guard, then writes
+ * the source version unless the sink reports version 0.
+ *
+ * Returns:
+ * 0 on success or when skipped; a negative error code when either
+ * the read or the write failed.
+ */
+int drm_scdc_set_source_version(struct drm_connector *connector, u8 ver)
+{
+ u8 sink_ver;
+ int ret;
+
+ ret = drm_scdc_readb(connector->ddc, SCDC_SINK_VERSION, &sink_ver);
+ if (ret) {
+ drm_scdc_dbg(connector, "Failed to read SCDC_SINK_VERSION: %d\n", ret);
+ return ret;
+ }
+
+ drm_scdc_dbg(connector, "Sink reported SCDC ver. %u\n", sink_ver);
+
+ /*
+ * Only advertise our source version to sinks that report a
+ * non-zero sink version. A sink reporting version 0 is either
+ * not SCDC-version-aware or non-conformant; writing the source
+ * version gains nothing and may upset broken hardware.
+ */
+ if (sink_ver) {
+ ret = drm_scdc_writeb(connector->ddc, SCDC_SOURCE_VERSION,
+ min_t(u8, sink_ver, ver));
+ if (ret)
+ drm_scdc_dbg(connector,
+ "Failed to write SCDC_SOURCE_VERSION: %d\n", ret);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(drm_scdc_set_source_version);
diff --git a/include/drm/display/drm_scdc_helper.h b/include/drm/display/drm_scdc_helper.h
index 34600476a1b9..90b0828364c2 100644
--- a/include/drm/display/drm_scdc_helper.h
+++ b/include/drm/display/drm_scdc_helper.h
@@ -77,4 +77,6 @@ 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_set_source_version(struct drm_connector *connector, u8 ver);
+
#endif
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 10/69] drm/display: hdmi: Add HDMI 2.0 scrambling management helpers
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Maud Spierings, Diederik de Haas
Add helpers to manage the full lifecycle of HDMI 2.0 SCDC scrambling on
both source and sink sides:
- drm_hdmi_mode_needs_scrambling(): checks whether a mode, bits per
component and output format combination requires scrambling, which is
needed when the resulting TMDS character rate exceeds the HDMI 1.3
maximum of 340 MHz
- drm_connector_hdmi_enable_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_connector_hdmi_disable_scrambling(): tears down scrambling on both
sides and cancels the monitoring work
- drm_connector_hdmi_sync_scdc(): triggers a CRTC reset on reconnection
to restore SCDC state lost during sink disconnects within an active
display pipeline
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_hdmi_helper.c | 296 ++++++++++++++++++++++++++++++
include/drm/display/drm_hdmi_helper.h | 15 ++
2 files changed, 311 insertions(+)
diff --git a/drivers/gpu/drm/display/drm_hdmi_helper.c b/drivers/gpu/drm/display/drm_hdmi_helper.c
index 5cb0b033b171..cfecfef639ad 100644
--- a/drivers/gpu/drm/display/drm_hdmi_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_helper.c
@@ -4,12 +4,20 @@
#include <linux/module.h>
#include <drm/display/drm_hdmi_helper.h>
+#include <drm/display/drm_scdc_helper.h>
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_connector.h>
+#include <drm/drm_crtc.h>
#include <drm/drm_edid.h>
#include <drm/drm_modes.h>
+#include <drm/drm_modeset_lock.h>
#include <drm/drm_print.h>
#include <drm/drm_property.h>
+#define DRM_HDMI_SCDC_POLL_DELAY_MS 1000
+
static inline bool is_eotf_supported(u8 output_eotf, u8 sink_eotf)
{
return sink_eotf & BIT(output_eotf);
@@ -426,3 +434,291 @@ drm_hdmi_acr_get_n_cts(unsigned long long tmds_char_rate,
*out_cts = cts;
}
EXPORT_SYMBOL(drm_hdmi_acr_get_n_cts);
+
+/**
+ * drm_hdmi_mode_needs_scrambling() - Check if an HDMI mode requires scrambling
+ * @mode: Display mode to check
+ * @bpc: Bits per color component
+ * @fmt: Output pixel format
+ *
+ * Computes the TMDS character rate for the given mode, bits per component and
+ * output format, and checks whether it exceeds the HDMI 1.3 maximum TMDS
+ * character rate of 340 MHz.
+ *
+ * Returns:
+ * true if the mode requires scrambling, false otherwise.
+ */
+bool drm_hdmi_mode_needs_scrambling(const struct drm_display_mode *mode,
+ unsigned int bpc,
+ enum drm_output_color_format fmt)
+{
+ unsigned long long tmds_char_rate;
+
+ tmds_char_rate = drm_hdmi_compute_mode_clock(mode, bpc, fmt);
+
+ return tmds_char_rate > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ;
+}
+EXPORT_SYMBOL(drm_hdmi_mode_needs_scrambling);
+
+static bool drm_scdc_sink_supports_scrambling(struct drm_connector *connector)
+{
+ const struct drm_display_info *info = &connector->display_info;
+
+ return info->is_hdmi &&
+ info->hdmi.scdc.supported &&
+ info->hdmi.scdc.scrambling.supported;
+}
+
+static int drm_connector_hdmi_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(DRM_HDMI_SCDC_POLL_DELAY_MS));
+
+ return 0;
+}
+
+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);
+
+ /*
+ * The connector, and hence this work item, may outlive the source
+ * driver, e.g. when userspace keeps a DRM file descriptor open past
+ * unbind. Never poke the DDC bus after the connector got unregistered,
+ * as the underlying I2C adapter may already be gone.
+ */
+ if (drm_connector_is_unregistered(connector))
+ return;
+
+ if (READ_ONCE(connector->hdmi.scrambler_enabled) &&
+ !drm_scdc_get_scrambling_status(connector))
+ drm_connector_hdmi_try_scrambling_setup(connector);
+}
+
+/**
+ * drm_connector_hdmi_enable_scrambling() - enable scrambling and monitor SCDC status
+ * @connector: connector
+ * @conn_state: connector state
+ *
+ * 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.
+ *
+ * The work item is cancelled by drm_connector_hdmi_disable_scrambling(), hence
+ * source drivers must ensure the display pipeline is shut down on unbind, e.g.
+ * via drm_atomic_helper_shutdown(). Otherwise the work may outlive the driver's
+ * devres-managed resources, since the connector itself is only cleaned up when
+ * the last reference to the DRM device is dropped.
+ *
+ * Returns:
+ * Zero if scrambling is set successfully, an error code otherwise.
+ */
+int drm_connector_hdmi_enable_scrambling(struct drm_connector *connector,
+ const struct drm_connector_state *conn_state)
+{
+ struct drm_connector_hdmi *hdmi = &connector->hdmi;
+ struct drm_device *dev = connector->dev;
+ int ret;
+
+ if (!conn_state)
+ return -EINVAL;
+
+ if (!conn_state->hdmi.scrambler_needed)
+ return 0;
+
+ if (!drm_connector_hdmi_scrambler_supported(connector)) {
+ drm_dbg_kms(dev, "Source doesn't support scrambling.\n");
+ return -EINVAL;
+ }
+
+ if (!drm_scdc_sink_supports_scrambling(connector)) {
+ drm_dbg_kms(dev, "Sink doesn't support scrambling.\n");
+ return -EINVAL;
+ }
+
+ if (!connector->ddc)
+ return -EINVAL;
+
+ drm_dbg_kms(dev, "Enabling scrambling\n");
+
+ if (!hdmi->scdc_work_initialized) {
+ INIT_DELAYED_WORK(&hdmi->scdc_work,
+ drm_connector_hdmi_scdc_work);
+ hdmi->scdc_work_initialized = true;
+ }
+
+ WRITE_ONCE(hdmi->scrambler_enabled, true);
+
+ ret = drm_connector_hdmi_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);
+
+ drm_scdc_set_scrambling(connector, false);
+ drm_scdc_set_high_tmds_clock_ratio(connector, false);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(drm_connector_hdmi_enable_scrambling);
+
+/**
+ * drm_connector_hdmi_disable_scrambling() - disable scrambling and SCDC monitoring
+ * @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_connector_hdmi_disable_scrambling(struct drm_connector *connector)
+{
+ struct drm_connector_hdmi *hdmi = &connector->hdmi;
+ struct drm_device *dev = connector->dev;
+
+ if (!READ_ONCE(hdmi->scrambler_enabled))
+ return 0;
+
+ drm_dbg_kms(dev, "Disabling scrambling\n");
+
+ WRITE_ONCE(hdmi->scrambler_enabled, false);
+
+ /*
+ * A driver may force scrambler_enabled at init to trigger a disable
+ * at boot (e.g. vc4), bypassing the enable path that sets up the work
+ * item. Only cancel it once it has actually been initialized.
+ */
+ if (hdmi->scdc_work_initialized)
+ cancel_delayed_work_sync(&hdmi->scdc_work);
+
+ if (connector->status == connector_status_connected &&
+ drm_scdc_sink_supports_scrambling(connector)) {
+ drm_scdc_set_scrambling(connector, false);
+ drm_scdc_set_high_tmds_clock_ratio(connector, false);
+ }
+
+ return hdmi->funcs->scrambler_disable(connector);
+}
+EXPORT_SYMBOL(drm_connector_hdmi_disable_scrambling);
+
+/**
+ * drm_connector_hdmi_sync_scdc() - 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().
+ *
+ * Returns:
+ * Zero on success, an error code otherwise, including -EDEADLK.
+ */
+int drm_connector_hdmi_sync_scdc(struct drm_connector *connector, bool plugged,
+ struct drm_modeset_acquire_ctx *ctx)
+{
+ struct drm_connector_hdmi *hdmi = &connector->hdmi;
+ struct drm_device *dev = connector->dev;
+ struct drm_connector_state *conn_state;
+ struct drm_crtc *crtc;
+ u8 config;
+ int ret;
+
+ if (!connector || !plugged || !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(&connector->dev->mode_config.connection_mutex, ctx);
+ if (ret)
+ return ret;
+
+ /* TODO: Also handle HDMI 2.1 FRL link training */
+
+ if (!drm_connector_hdmi_scrambler_supported(connector) ||
+ !READ_ONCE(hdmi->scrambler_enabled))
+ return 0;
+
+ conn_state = connector->state;
+ if (!conn_state)
+ return 0;
+
+ crtc = conn_state->crtc;
+ if (!crtc)
+ return 0;
+
+ ret = drm_modeset_lock(&crtc->mutex, ctx);
+ if (ret)
+ return ret;
+
+ if (!crtc->state || !crtc->state->active)
+ return 0;
+
+ if (!connector->ddc || !drm_scdc_sink_supports_scrambling(connector))
+ return 0;
+
+ if (conn_state->commit &&
+ !try_wait_for_completion(&conn_state->commit->hw_done))
+ return 0;
+
+ ret = drm_scdc_readb(connector->ddc, SCDC_TMDS_CONFIG, &config);
+ if (ret) {
+ drm_dbg_kms(dev, "Failed to read TMDS config: %d\n", ret);
+ return ret;
+ }
+
+ if (config & SCDC_SCRAMBLING_ENABLE)
+ return 0;
+
+ /*
+ * HDMI 2.0 requires 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.
+ *
+ * The disable/re-enable cycle triggered by the reset should call
+ * drm_connector_hdmi_enable_scrambling() during re-enable, thus
+ * properly configuring the sink before data transmission resumes.
+ */
+ drm_dbg_kms(dev, "Resetting CRTC to restore SCDC status\n");
+
+ ret = drm_atomic_helper_reset_crtc(crtc, ctx);
+ if (ret && ret != -EDEADLK)
+ drm_dbg_kms(dev, "Failed to reset CRTC: %d\n", ret);
+
+ return ret;
+}
+EXPORT_SYMBOL(drm_connector_hdmi_sync_scdc);
diff --git a/include/drm/display/drm_hdmi_helper.h b/include/drm/display/drm_hdmi_helper.h
index 9c31ed90516b..2cdd6e3bc090 100644
--- a/include/drm/display/drm_hdmi_helper.h
+++ b/include/drm/display/drm_hdmi_helper.h
@@ -8,6 +8,7 @@
struct drm_connector;
struct drm_connector_state;
struct drm_display_mode;
+struct drm_modeset_acquire_ctx;
enum drm_output_color_format;
void
@@ -35,4 +36,18 @@ drm_hdmi_acr_get_n_cts(unsigned long long tmds_char_rate,
unsigned int *out_n,
unsigned int *out_cts);
+bool
+drm_hdmi_mode_needs_scrambling(const struct drm_display_mode *mode,
+ unsigned int bpc, enum drm_output_color_format fmt);
+
+int
+drm_connector_hdmi_enable_scrambling(struct drm_connector *connector,
+ const struct drm_connector_state *conn_state);
+int
+drm_connector_hdmi_disable_scrambling(struct drm_connector *connector);
+
+int
+drm_connector_hdmi_sync_scdc(struct drm_connector *connector, bool plugged,
+ struct drm_modeset_acquire_ctx *ctx);
+
#endif
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 10/69] drm/display: hdmi: Add HDMI 2.0 scrambling management helpers
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Maud Spierings, Diederik de Haas
Add helpers to manage the full lifecycle of HDMI 2.0 SCDC scrambling on
both source and sink sides:
- drm_hdmi_mode_needs_scrambling(): checks whether a mode, bits per
component and output format combination requires scrambling, which is
needed when the resulting TMDS character rate exceeds the HDMI 1.3
maximum of 340 MHz
- drm_connector_hdmi_enable_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_connector_hdmi_disable_scrambling(): tears down scrambling on both
sides and cancels the monitoring work
- drm_connector_hdmi_sync_scdc(): triggers a CRTC reset on reconnection
to restore SCDC state lost during sink disconnects within an active
display pipeline
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_hdmi_helper.c | 296 ++++++++++++++++++++++++++++++
include/drm/display/drm_hdmi_helper.h | 15 ++
2 files changed, 311 insertions(+)
diff --git a/drivers/gpu/drm/display/drm_hdmi_helper.c b/drivers/gpu/drm/display/drm_hdmi_helper.c
index 5cb0b033b171..cfecfef639ad 100644
--- a/drivers/gpu/drm/display/drm_hdmi_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_helper.c
@@ -4,12 +4,20 @@
#include <linux/module.h>
#include <drm/display/drm_hdmi_helper.h>
+#include <drm/display/drm_scdc_helper.h>
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_connector.h>
+#include <drm/drm_crtc.h>
#include <drm/drm_edid.h>
#include <drm/drm_modes.h>
+#include <drm/drm_modeset_lock.h>
#include <drm/drm_print.h>
#include <drm/drm_property.h>
+#define DRM_HDMI_SCDC_POLL_DELAY_MS 1000
+
static inline bool is_eotf_supported(u8 output_eotf, u8 sink_eotf)
{
return sink_eotf & BIT(output_eotf);
@@ -426,3 +434,291 @@ drm_hdmi_acr_get_n_cts(unsigned long long tmds_char_rate,
*out_cts = cts;
}
EXPORT_SYMBOL(drm_hdmi_acr_get_n_cts);
+
+/**
+ * drm_hdmi_mode_needs_scrambling() - Check if an HDMI mode requires scrambling
+ * @mode: Display mode to check
+ * @bpc: Bits per color component
+ * @fmt: Output pixel format
+ *
+ * Computes the TMDS character rate for the given mode, bits per component and
+ * output format, and checks whether it exceeds the HDMI 1.3 maximum TMDS
+ * character rate of 340 MHz.
+ *
+ * Returns:
+ * true if the mode requires scrambling, false otherwise.
+ */
+bool drm_hdmi_mode_needs_scrambling(const struct drm_display_mode *mode,
+ unsigned int bpc,
+ enum drm_output_color_format fmt)
+{
+ unsigned long long tmds_char_rate;
+
+ tmds_char_rate = drm_hdmi_compute_mode_clock(mode, bpc, fmt);
+
+ return tmds_char_rate > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ;
+}
+EXPORT_SYMBOL(drm_hdmi_mode_needs_scrambling);
+
+static bool drm_scdc_sink_supports_scrambling(struct drm_connector *connector)
+{
+ const struct drm_display_info *info = &connector->display_info;
+
+ return info->is_hdmi &&
+ info->hdmi.scdc.supported &&
+ info->hdmi.scdc.scrambling.supported;
+}
+
+static int drm_connector_hdmi_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(DRM_HDMI_SCDC_POLL_DELAY_MS));
+
+ return 0;
+}
+
+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);
+
+ /*
+ * The connector, and hence this work item, may outlive the source
+ * driver, e.g. when userspace keeps a DRM file descriptor open past
+ * unbind. Never poke the DDC bus after the connector got unregistered,
+ * as the underlying I2C adapter may already be gone.
+ */
+ if (drm_connector_is_unregistered(connector))
+ return;
+
+ if (READ_ONCE(connector->hdmi.scrambler_enabled) &&
+ !drm_scdc_get_scrambling_status(connector))
+ drm_connector_hdmi_try_scrambling_setup(connector);
+}
+
+/**
+ * drm_connector_hdmi_enable_scrambling() - enable scrambling and monitor SCDC status
+ * @connector: connector
+ * @conn_state: connector state
+ *
+ * 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.
+ *
+ * The work item is cancelled by drm_connector_hdmi_disable_scrambling(), hence
+ * source drivers must ensure the display pipeline is shut down on unbind, e.g.
+ * via drm_atomic_helper_shutdown(). Otherwise the work may outlive the driver's
+ * devres-managed resources, since the connector itself is only cleaned up when
+ * the last reference to the DRM device is dropped.
+ *
+ * Returns:
+ * Zero if scrambling is set successfully, an error code otherwise.
+ */
+int drm_connector_hdmi_enable_scrambling(struct drm_connector *connector,
+ const struct drm_connector_state *conn_state)
+{
+ struct drm_connector_hdmi *hdmi = &connector->hdmi;
+ struct drm_device *dev = connector->dev;
+ int ret;
+
+ if (!conn_state)
+ return -EINVAL;
+
+ if (!conn_state->hdmi.scrambler_needed)
+ return 0;
+
+ if (!drm_connector_hdmi_scrambler_supported(connector)) {
+ drm_dbg_kms(dev, "Source doesn't support scrambling.\n");
+ return -EINVAL;
+ }
+
+ if (!drm_scdc_sink_supports_scrambling(connector)) {
+ drm_dbg_kms(dev, "Sink doesn't support scrambling.\n");
+ return -EINVAL;
+ }
+
+ if (!connector->ddc)
+ return -EINVAL;
+
+ drm_dbg_kms(dev, "Enabling scrambling\n");
+
+ if (!hdmi->scdc_work_initialized) {
+ INIT_DELAYED_WORK(&hdmi->scdc_work,
+ drm_connector_hdmi_scdc_work);
+ hdmi->scdc_work_initialized = true;
+ }
+
+ WRITE_ONCE(hdmi->scrambler_enabled, true);
+
+ ret = drm_connector_hdmi_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);
+
+ drm_scdc_set_scrambling(connector, false);
+ drm_scdc_set_high_tmds_clock_ratio(connector, false);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(drm_connector_hdmi_enable_scrambling);
+
+/**
+ * drm_connector_hdmi_disable_scrambling() - disable scrambling and SCDC monitoring
+ * @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_connector_hdmi_disable_scrambling(struct drm_connector *connector)
+{
+ struct drm_connector_hdmi *hdmi = &connector->hdmi;
+ struct drm_device *dev = connector->dev;
+
+ if (!READ_ONCE(hdmi->scrambler_enabled))
+ return 0;
+
+ drm_dbg_kms(dev, "Disabling scrambling\n");
+
+ WRITE_ONCE(hdmi->scrambler_enabled, false);
+
+ /*
+ * A driver may force scrambler_enabled at init to trigger a disable
+ * at boot (e.g. vc4), bypassing the enable path that sets up the work
+ * item. Only cancel it once it has actually been initialized.
+ */
+ if (hdmi->scdc_work_initialized)
+ cancel_delayed_work_sync(&hdmi->scdc_work);
+
+ if (connector->status == connector_status_connected &&
+ drm_scdc_sink_supports_scrambling(connector)) {
+ drm_scdc_set_scrambling(connector, false);
+ drm_scdc_set_high_tmds_clock_ratio(connector, false);
+ }
+
+ return hdmi->funcs->scrambler_disable(connector);
+}
+EXPORT_SYMBOL(drm_connector_hdmi_disable_scrambling);
+
+/**
+ * drm_connector_hdmi_sync_scdc() - 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().
+ *
+ * Returns:
+ * Zero on success, an error code otherwise, including -EDEADLK.
+ */
+int drm_connector_hdmi_sync_scdc(struct drm_connector *connector, bool plugged,
+ struct drm_modeset_acquire_ctx *ctx)
+{
+ struct drm_connector_hdmi *hdmi = &connector->hdmi;
+ struct drm_device *dev = connector->dev;
+ struct drm_connector_state *conn_state;
+ struct drm_crtc *crtc;
+ u8 config;
+ int ret;
+
+ if (!connector || !plugged || !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(&connector->dev->mode_config.connection_mutex, ctx);
+ if (ret)
+ return ret;
+
+ /* TODO: Also handle HDMI 2.1 FRL link training */
+
+ if (!drm_connector_hdmi_scrambler_supported(connector) ||
+ !READ_ONCE(hdmi->scrambler_enabled))
+ return 0;
+
+ conn_state = connector->state;
+ if (!conn_state)
+ return 0;
+
+ crtc = conn_state->crtc;
+ if (!crtc)
+ return 0;
+
+ ret = drm_modeset_lock(&crtc->mutex, ctx);
+ if (ret)
+ return ret;
+
+ if (!crtc->state || !crtc->state->active)
+ return 0;
+
+ if (!connector->ddc || !drm_scdc_sink_supports_scrambling(connector))
+ return 0;
+
+ if (conn_state->commit &&
+ !try_wait_for_completion(&conn_state->commit->hw_done))
+ return 0;
+
+ ret = drm_scdc_readb(connector->ddc, SCDC_TMDS_CONFIG, &config);
+ if (ret) {
+ drm_dbg_kms(dev, "Failed to read TMDS config: %d\n", ret);
+ return ret;
+ }
+
+ if (config & SCDC_SCRAMBLING_ENABLE)
+ return 0;
+
+ /*
+ * HDMI 2.0 requires 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.
+ *
+ * The disable/re-enable cycle triggered by the reset should call
+ * drm_connector_hdmi_enable_scrambling() during re-enable, thus
+ * properly configuring the sink before data transmission resumes.
+ */
+ drm_dbg_kms(dev, "Resetting CRTC to restore SCDC status\n");
+
+ ret = drm_atomic_helper_reset_crtc(crtc, ctx);
+ if (ret && ret != -EDEADLK)
+ drm_dbg_kms(dev, "Failed to reset CRTC: %d\n", ret);
+
+ return ret;
+}
+EXPORT_SYMBOL(drm_connector_hdmi_sync_scdc);
diff --git a/include/drm/display/drm_hdmi_helper.h b/include/drm/display/drm_hdmi_helper.h
index 9c31ed90516b..2cdd6e3bc090 100644
--- a/include/drm/display/drm_hdmi_helper.h
+++ b/include/drm/display/drm_hdmi_helper.h
@@ -8,6 +8,7 @@
struct drm_connector;
struct drm_connector_state;
struct drm_display_mode;
+struct drm_modeset_acquire_ctx;
enum drm_output_color_format;
void
@@ -35,4 +36,18 @@ drm_hdmi_acr_get_n_cts(unsigned long long tmds_char_rate,
unsigned int *out_n,
unsigned int *out_cts);
+bool
+drm_hdmi_mode_needs_scrambling(const struct drm_display_mode *mode,
+ unsigned int bpc, enum drm_output_color_format fmt);
+
+int
+drm_connector_hdmi_enable_scrambling(struct drm_connector *connector,
+ const struct drm_connector_state *conn_state);
+int
+drm_connector_hdmi_disable_scrambling(struct drm_connector *connector);
+
+int
+drm_connector_hdmi_sync_scdc(struct drm_connector *connector, bool plugged,
+ struct drm_modeset_acquire_ctx *ctx);
+
#endif
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread* Re: [PATCH v10 10/69] drm/display: hdmi: Add HDMI 2.0 scrambling management helpers
2026-07-31 16:19 ` Cristian Ciocaltea
(?)
@ 2026-07-31 17:33 ` sashiko-bot
-1 siblings, 0 replies; 155+ messages in thread
From: sashiko-bot @ 2026-07-31 17:33 UTC (permalink / raw)
To: Cristian Ciocaltea; +Cc: dri-devel, linux-sunxi
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [High] The SCDC scrambling monitor work item fails to reschedule itself, terminating the periodic polling after a single successful check or transient error.
- [High] Missing NULL check for connector->ddc in drm_connector_hdmi_disable_scrambling() causes a crash when scrambling is disabled for a connector without a DDC bus.
- [High] TOCTOU race condition in drm_connector_hdmi_scdc_work leading to a potential Use-After-Free of the I2C adapter.
- [High] Dead code in drm_connector_hdmi_sync_scdc fails to synchronize with hardware programming due to an impossible condition.
--
--- Patch [10]: [PATCH v10 10/69] drm/display: hdmi: Add HDMI 2.0 scrambling management helpers ---
commit 3991d28f3f40213e274370d230b6145165dadbee
Author: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
drm/display: hdmi: Add HDMI 2.0 scrambling management helpers
This commit adds helpers to manage the full lifecycle of HDMI 2.0 SCDC
scrambling on both source and sink sides. It introduces checking if a mode
needs scrambling, enabling/disabling with monitoring, and restoring the
SCDC state on reconnection.
> diff --git a/drivers/gpu/drm/display/drm_hdmi_helper.c b/drivers/gpu/drm/display/drm_hdmi_helper.c
> index 5cb0b033b1713..cfecfef639ad0 100644
> --- a/drivers/gpu/drm/display/drm_hdmi_helper.c
> +++ b/drivers/gpu/drm/display/drm_hdmi_helper.c
[ ... ]
> @@ -426,3 +434,291 @@ drm_hdmi_acr_get_n_cts(unsigned long long tmds_char_rate,
> *out_cts = cts;
> }
> EXPORT_SYMBOL(drm_hdmi_acr_get_n_cts);
[ ... ]
> +static int drm_connector_hdmi_try_scrambling_setup(struct drm_connector *connector)
> +{
> + bool done;
> +
> + done = drm_scdc_set_high_tmds_clock_ratio(connector, true);
> + if (!done)
> + return -EIO;
[Severity: High]
Does this prevent the SCDC worker from retrying on transient errors?
If drm_scdc_set_high_tmds_clock_ratio() fails, the function returns -EIO
early and skips the schedule_delayed_work() call, preventing any further
monitoring of the scrambling state.
[ ... ]
> +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);
> +
> + /*
> + * The connector, and hence this work item, may outlive the source
> + * driver, e.g. when userspace keeps a DRM file descriptor open past
> + * unbind. Never poke the DDC bus after the connector got unregistered,
> + * as the underlying I2C adapter may already be gone.
> + */
> + if (drm_connector_is_unregistered(connector))
> + return;
[Severity: High]
Could this lockless check lead to a Use-After-Free of the I2C adapter?
If the worker thread is preempted immediately after this check returns false,
the driver unbind process could complete and free the I2C adapter. When the
worker resumes, it calls drm_scdc_get_scrambling_status() which accesses the
now-freed connector->ddc.
> +
> + if (READ_ONCE(connector->hdmi.scrambler_enabled) &&
> + !drm_scdc_get_scrambling_status(connector))
> + drm_connector_hdmi_try_scrambling_setup(connector);
[Severity: High]
Will this work item fail to reschedule itself if the SCDC status is correct?
If drm_scdc_get_scrambling_status() returns true (meaning scrambling is
working), this function simply returns without rescheduling the worker. The
rescheduling only happens inside drm_connector_hdmi_try_scrambling_setup()
on a successful setup, so the periodic monitoring stops after the first
successful check.
> +}
[ ... ]
> +int drm_connector_hdmi_disable_scrambling(struct drm_connector *connector)
> +{
> + struct drm_connector_hdmi *hdmi = &connector->hdmi;
> + struct drm_device *dev = connector->dev;
> +
> + if (!READ_ONCE(hdmi->scrambler_enabled))
> + return 0;
> +
> + drm_dbg_kms(dev, "Disabling scrambling\n");
> +
> + WRITE_ONCE(hdmi->scrambler_enabled, false);
> +
> + /*
> + * A driver may force scrambler_enabled at init to trigger a disable
> + * at boot (e.g. vc4), bypassing the enable path that sets up the work
> + * item. Only cancel it once it has actually been initialized.
> + */
> + if (hdmi->scdc_work_initialized)
> + cancel_delayed_work_sync(&hdmi->scdc_work);
> +
> + if (connector->status == connector_status_connected &&
> + drm_scdc_sink_supports_scrambling(connector)) {
> + drm_scdc_set_scrambling(connector, false);
> + drm_scdc_set_high_tmds_clock_ratio(connector, false);
[Severity: High]
Can this cause a NULL pointer dereference if connector->ddc is missing?
If a driver forces hdmi->scrambler_enabled to true at init to trigger a
disable at boot, and the connector has no DDC bus (connector->ddc is NULL),
drm_scdc_set_scrambling() will unconditionally dereference the NULL DDC
adapter. The enable path correctly checks for connector->ddc, but the disable
path does not.
> + }
> +
> + return hdmi->funcs->scrambler_disable(connector);
> +}
[ ... ]
> +int drm_connector_hdmi_sync_scdc(struct drm_connector *connector, bool plugged,
> + struct drm_modeset_acquire_ctx *ctx)
> +{
> + struct drm_connector_hdmi *hdmi = &connector->hdmi;
> + struct drm_device *dev = connector->dev;
> + struct drm_connector_state *conn_state;
> + struct drm_crtc *crtc;
> + u8 config;
> + int ret;
> +
> + if (!connector || !plugged || !ctx)
> + return 0;
[ ... ]
> + crtc = conn_state->crtc;
> + if (!crtc)
> + return 0;
> +
> + ret = drm_modeset_lock(&crtc->mutex, ctx);
> + if (ret)
> + return ret;
> +
> + if (!crtc->state || !crtc->state->active)
> + return 0;
> +
> + if (!connector->ddc || !drm_scdc_sink_supports_scrambling(connector))
> + return 0;
> +
> + if (conn_state->commit &&
> + !try_wait_for_completion(&conn_state->commit->hw_done))
[Severity: High]
Is this wait condition dead code?
Earlier in the function, it verifies that crtc is not NULL (if (!crtc)
return 0;). According to the struct drm_connector_state documentation, the
commit field is only set when crtc is NULL. Since crtc is guaranteed to be
non-NULL here, conn_state->commit will always be NULL, making this check
impossible to hit. Consequently, the function proceeds to perform SCDC I2C
reads concurrently with active hardware programming.
> + return 0;
> +
> + ret = drm_scdc_readb(connector->ddc, SCDC_TMDS_CONFIG, &config);
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260731-dw-hdmi-qp-scramb-v10-0-294364b2cf15@collabora.com?part=10
^ permalink raw reply [flat|nested] 155+ messages in thread
* [PATCH v10 11/69] drm/display: hdmi: Advertise SCDC source version when scrambling
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Maud Spierings, Diederik de Haas
The HDMI 2.0 spec advises that compliant Source devices report their
SCDC version in the Source Version register. Do so when enabling
scrambling by calling drm_scdc_set_source_version().
Failures are non-fatal: SCDC version negotiation is purely informational
and does not gate scrambling or any high-bitrate functionality, so a
flaky DDC bus should not block scrambling setup.
Acked-by: Maxime Ripard <mripard@kernel.org>
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_hdmi_helper.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/drivers/gpu/drm/display/drm_hdmi_helper.c b/drivers/gpu/drm/display/drm_hdmi_helper.c
index cfecfef639ad..493f2728ab86 100644
--- a/drivers/gpu/drm/display/drm_hdmi_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_helper.c
@@ -16,6 +16,7 @@
#include <drm/drm_print.h>
#include <drm/drm_property.h>
+#define DRM_HDMI_SCDC_SOURCE_VERSION 1
#define DRM_HDMI_SCDC_POLL_DELAY_MS 1000
static inline bool is_eotf_supported(u8 output_eotf, u8 sink_eotf)
@@ -556,6 +557,12 @@ int drm_connector_hdmi_enable_scrambling(struct drm_connector *connector,
if (!connector->ddc)
return -EINVAL;
+ /*
+ * Advertise our SCDC source version. This is purely informational and
+ * does not gate scrambling, so failures are non-fatal.
+ */
+ drm_scdc_set_source_version(connector, DRM_HDMI_SCDC_SOURCE_VERSION);
+
drm_dbg_kms(dev, "Enabling scrambling\n");
if (!hdmi->scdc_work_initialized) {
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 11/69] drm/display: hdmi: Advertise SCDC source version when scrambling
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Maud Spierings, Diederik de Haas
The HDMI 2.0 spec advises that compliant Source devices report their
SCDC version in the Source Version register. Do so when enabling
scrambling by calling drm_scdc_set_source_version().
Failures are non-fatal: SCDC version negotiation is purely informational
and does not gate scrambling or any high-bitrate functionality, so a
flaky DDC bus should not block scrambling setup.
Acked-by: Maxime Ripard <mripard@kernel.org>
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_hdmi_helper.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/drivers/gpu/drm/display/drm_hdmi_helper.c b/drivers/gpu/drm/display/drm_hdmi_helper.c
index cfecfef639ad..493f2728ab86 100644
--- a/drivers/gpu/drm/display/drm_hdmi_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_helper.c
@@ -16,6 +16,7 @@
#include <drm/drm_print.h>
#include <drm/drm_property.h>
+#define DRM_HDMI_SCDC_SOURCE_VERSION 1
#define DRM_HDMI_SCDC_POLL_DELAY_MS 1000
static inline bool is_eotf_supported(u8 output_eotf, u8 sink_eotf)
@@ -556,6 +557,12 @@ int drm_connector_hdmi_enable_scrambling(struct drm_connector *connector,
if (!connector->ddc)
return -EINVAL;
+ /*
+ * Advertise our SCDC source version. This is purely informational and
+ * does not gate scrambling, so failures are non-fatal.
+ */
+ drm_scdc_set_source_version(connector, DRM_HDMI_SCDC_SOURCE_VERSION);
+
drm_dbg_kms(dev, "Enabling scrambling\n");
if (!hdmi->scdc_work_initialized) {
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 12/69] drm/bridge: Fix unlocked list_del in drm_bridge_add()
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Sashiko
When re-adding a bridge that was previously removed, drm_bridge_add()
drops it from bridge_lingering_list without holding bridge_lock.
Both bridge_list and bridge_lingering_list are protected by bridge_lock,
as they are concurrently modified by drm_bridge_remove() and
__drm_bridge_free(), and walked by the debugfs 'bridges' file. Running
the list_empty() test and the list_del_init() outside of the lock may
therefore corrupt either list.
Perform both under bridge_lock.
Fixes: 17805a15d175 ("drm/bridge: add list of removed refcounted bridges")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://lore.kernel.org/all/20260723015004.1F5711F000E9@smtp.kernel.org/
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/drm_bridge.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index afaae272347c..8b8f71c3ccff 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -21,6 +21,7 @@
* DEALINGS IN THE SOFTWARE.
*/
+#include <linux/cleanup.h>
#include <linux/debugfs.h>
#include <linux/err.h>
#include <linux/export.h>
@@ -454,8 +455,10 @@ void drm_bridge_add(struct drm_bridge *bridge)
* in bridge_lingering_list. Remove it or bridge_lingering_list will be
* corrupted when adding this bridge to bridge_list below.
*/
- if (!list_empty(&bridge->list))
- list_del_init(&bridge->list);
+ scoped_guard(mutex, &bridge_lock) {
+ if (!list_empty(&bridge->list))
+ list_del_init(&bridge->list);
+ }
mutex_init(&bridge->hpd_state_mutex);
mutex_init(&bridge->hpd_mutex);
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 12/69] drm/bridge: Fix unlocked list_del in drm_bridge_add()
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Sashiko
When re-adding a bridge that was previously removed, drm_bridge_add()
drops it from bridge_lingering_list without holding bridge_lock.
Both bridge_list and bridge_lingering_list are protected by bridge_lock,
as they are concurrently modified by drm_bridge_remove() and
__drm_bridge_free(), and walked by the debugfs 'bridges' file. Running
the list_empty() test and the list_del_init() outside of the lock may
therefore corrupt either list.
Perform both under bridge_lock.
Fixes: 17805a15d175 ("drm/bridge: add list of removed refcounted bridges")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://lore.kernel.org/all/20260723015004.1F5711F000E9@smtp.kernel.org/
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/drm_bridge.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index afaae272347c..8b8f71c3ccff 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -21,6 +21,7 @@
* DEALINGS IN THE SOFTWARE.
*/
+#include <linux/cleanup.h>
#include <linux/debugfs.h>
#include <linux/err.h>
#include <linux/export.h>
@@ -454,8 +455,10 @@ void drm_bridge_add(struct drm_bridge *bridge)
* in bridge_lingering_list. Remove it or bridge_lingering_list will be
* corrupted when adding this bridge to bridge_list below.
*/
- if (!list_empty(&bridge->list))
- list_del_init(&bridge->list);
+ scoped_guard(mutex, &bridge_lock) {
+ if (!list_empty(&bridge->list))
+ list_del_init(&bridge->list);
+ }
mutex_init(&bridge->hpd_state_mutex);
mutex_init(&bridge->hpd_mutex);
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread* Re: [PATCH v10 12/69] drm/bridge: Fix unlocked list_del in drm_bridge_add()
2026-07-31 16:19 ` Cristian Ciocaltea
(?)
@ 2026-07-31 17:50 ` sashiko-bot
-1 siblings, 0 replies; 155+ messages in thread
From: sashiko-bot @ 2026-07-31 17:50 UTC (permalink / raw)
To: Cristian Ciocaltea; +Cc: dri-devel, linux-sunxi
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Legacy zero-initialized bridges not allocated via devm_drm_bridge_alloc() will cause a kernel panic due to an uninitialized list_head and trigger refcount warnings.
--
--- Patch [12]: [PATCH v10 12/69] drm/bridge: Fix unlocked list_del in drm_bridge_add() ---
commit e0f10da4c05d8a75c537ce94edb147bda1eb2e78
Author: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
drm/bridge: Fix unlocked list_del in drm_bridge_add()
This commit addresses a list corruption issue in drm_bridge_add() by wrapping
the bridge_lingering_list removal sequence with the bridge_lock mutex. It
prevents concurrent modifications from drm_bridge_remove() and debugfs walks.
Closes: https://lore.kernel.org/all/20260723015004.1F5711F000E9@smtp.kernel.org/
> diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
> index afaae272347c0..8b8f71c3ccff9 100644
> --- a/drivers/gpu/drm/drm_bridge.c
> +++ b/drivers/gpu/drm/drm_bridge.c
[ ... ]
> @@ -454,8 +455,10 @@ void drm_bridge_add(struct drm_bridge *bridge)
> * in bridge_lingering_list. Remove it or bridge_lingering_list will be
> * corrupted when adding this bridge to bridge_list below.
> */
> - if (!list_empty(&bridge->list))
> - list_del_init(&bridge->list);
> + scoped_guard(mutex, &bridge_lock) {
> + if (!list_empty(&bridge->list))
> + list_del_init(&bridge->list);
> + }
[Severity: High]
This is a pre-existing issue, but will this cause a kernel panic for legacy
bridge drivers that allocate struct drm_bridge using kzalloc() instead of
devm_drm_bridge_alloc()?
For a zero-initialized bridge struct, the list_empty() check evaluates to
false because the uninitialized list_head pointers are NULL, and NULL is not
equal to &bridge->list.
This means list_del_init() will execute and unconditionally dereference the
NULL prev and next pointers, crashing the kernel during device probe.
Is it possible to check if the list_head is actually initialized before
testing if it is empty, or handle legacy zero-initialized bridges safely
to avoid breaking the probe path on affected platforms?
>
> mutex_init(&bridge->hpd_state_mutex);
> mutex_init(&bridge->hpd_mutex);
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260731-dw-hdmi-qp-scramb-v10-0-294364b2cf15@collabora.com?part=12
^ permalink raw reply [flat|nested] 155+ messages in thread
* [PATCH v10 13/69] drm/bridge: Fix unlocked list access in drm_bridge_attach()
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
drm_bridge_attach() inspects bridge->list to warn about bridges being
attached without a previous drm_bridge_add() call, but it does so
without holding bridge_lock.
The list head can be concurrently written by drm_bridge_add(),
drm_bridge_remove() and __drm_bridge_free() while they operate on
neighbouring entries of bridge_list or bridge_lingering_list, all of
them under bridge_lock. Hence the unlocked read is a data race, even
though it is unlikely to change the outcome of list_empty() in practice.
Perform the check with bridge_lock held.
Fixes: 76f1a9711b83 ("drm/bridge: add warning for bridges attached without being added")
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/drm_bridge.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 8b8f71c3ccff..9a658decad2a 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -600,8 +600,10 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
if (!bridge->container)
DRM_WARN("DRM bridge corrupted or not allocated by devm_drm_bridge_alloc()\n");
- if (list_empty(&bridge->list))
- DRM_WARN("Missing drm_bridge_add() before attach\n");
+ scoped_guard(mutex, &bridge_lock) {
+ if (list_empty(&bridge->list))
+ DRM_WARN("Missing drm_bridge_add() before attach\n");
+ }
drm_bridge_get(bridge);
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 13/69] drm/bridge: Fix unlocked list access in drm_bridge_attach()
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
drm_bridge_attach() inspects bridge->list to warn about bridges being
attached without a previous drm_bridge_add() call, but it does so
without holding bridge_lock.
The list head can be concurrently written by drm_bridge_add(),
drm_bridge_remove() and __drm_bridge_free() while they operate on
neighbouring entries of bridge_list or bridge_lingering_list, all of
them under bridge_lock. Hence the unlocked read is a data race, even
though it is unlikely to change the outcome of list_empty() in practice.
Perform the check with bridge_lock held.
Fixes: 76f1a9711b83 ("drm/bridge: add warning for bridges attached without being added")
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/drm_bridge.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 8b8f71c3ccff..9a658decad2a 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -600,8 +600,10 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
if (!bridge->container)
DRM_WARN("DRM bridge corrupted or not allocated by devm_drm_bridge_alloc()\n");
- if (list_empty(&bridge->list))
- DRM_WARN("Missing drm_bridge_add() before attach\n");
+ scoped_guard(mutex, &bridge_lock) {
+ if (list_empty(&bridge->list))
+ DRM_WARN("Missing drm_bridge_add() before attach\n");
+ }
drm_bridge_get(bridge);
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 14/69] drm/bridge: Remove redundant error check in drm_bridge_helper_reset_crtc()
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Dmitry Baryshkov, Maud Spierings,
Diederik de Haas
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>
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
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.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 14/69] drm/bridge: Remove redundant error check in drm_bridge_helper_reset_crtc()
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Dmitry Baryshkov, Maud Spierings,
Diederik de Haas
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>
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
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.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* Re: [PATCH v10 14/69] drm/bridge: Remove redundant error check in drm_bridge_helper_reset_crtc()
2026-07-31 16:19 ` Cristian Ciocaltea
(?)
@ 2026-07-31 18:01 ` sashiko-bot
-1 siblings, 0 replies; 155+ messages in thread
From: sashiko-bot @ 2026-07-31 18:01 UTC (permalink / raw)
To: Cristian Ciocaltea; +Cc: dri-devel, linux-sunxi
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Double unlock of connection_mutex and unprotected state access due to nested lock handling flaw in drm_atomic_get_connector_for_encoder.
--
--- Patch [14]: [PATCH v10 14/69] drm/bridge: Remove redundant error check in drm_bridge_helper_reset_crtc() ---
commit 3469d1c48eb06940af7b278f9266400f3b5ea3dc
Author: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
drm/bridge: Remove redundant error check in drm_bridge_helper_reset_crtc()
This commit removes a no-op error check after drm_atomic_helper_reset_crtc(),
as the return value is already propagated correctly by the fall-through to
the out label.
> diff --git a/drivers/gpu/drm/drm_bridge_helper.c b/drivers/gpu/drm/drm_bridge_helper.c
> index 420f29cf3e543..0a3c8fee66b32 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);
[Severity: High]
This is a pre-existing issue, but does this result in a double-unlock of
connection_mutex?
Earlier in this function, the lock is acquired before calling
drm_atomic_get_connector_for_encoder():
drm_bridge_helper_reset_crtc() {
...
ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
if (ret)
return ret;
connector = drm_atomic_get_connector_for_encoder(encoder, ctx);
...
}
However, drm_atomic_get_connector_for_encoder() unconditionally unlocks
the mutex on exit. Because drm_modeset_unlock() lacks a nesting counter, it
fully drops the ww_mutex.
Consequently, connector->state is accessed locklessly, and reaching this out
label calls drm_modeset_unlock() a second time, which could corrupt the
kernel lock state.
> return ret;
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260731-dw-hdmi-qp-scramb-v10-0-294364b2cf15@collabora.com?part=14
^ permalink raw reply [flat|nested] 155+ messages in thread
* [PATCH v10 15/69] drm/bridge: Add bridge ops for source-side HDMI 2.0 scrambling
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Dmitry Baryshkov
Bridges advertising HDMI 2.0 must be able to enable and disable
source-side scrambling and the high TMDS clock ratio when the configured
mode exceeds 340 MHz.
Add .hdmi_scrambler_{enable|disable}() callbacks covering the
source-side programming only; sink-side SCDC negotiation remains the job
of the HDMI connector helpers.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
include/drm/drm_bridge.h | 35 +++++++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index 5a5a25995471..77b3ffe69230 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -561,6 +561,41 @@ struct drm_bridge_funcs {
const struct drm_display_mode *mode,
unsigned long long tmds_rate);
+ /**
+ * @hdmi_scrambler_enable:
+ *
+ * Enable source-side scrambling and the high TMDS clock ratio for the
+ * mode currently being applied.
+ *
+ * This only programs the source side. Sink-side SCDC configuration is
+ * handled by the HDMI connector helpers.
+ *
+ * Mandatory for bridges that set the DRM_BRIDGE_OP_HDMI flag in their
+ * &drm_bridge->ops and advertise HDMI_VERSION_2_0 or later via
+ * &drm_bridge->supported_hdmi_ver; unused otherwise.
+ *
+ * Returns:
+ * 0 on success, a negative error code otherwise.
+ */
+ int (*hdmi_scrambler_enable)(struct drm_bridge *bridge);
+
+ /**
+ * @hdmi_scrambler_disable:
+ *
+ * Disable source-side scrambling and the high TMDS clock ratio.
+ *
+ * This only programs the source side. Sink-side SCDC configuration is
+ * handled by the HDMI connector helpers.
+ *
+ * Mandatory for bridges that set the DRM_BRIDGE_OP_HDMI flag in their
+ * &drm_bridge->ops and advertise HDMI_VERSION_2_0 or later via
+ * &drm_bridge->supported_hdmi_ver; unused otherwise.
+ *
+ * Returns:
+ * 0 on success, a negative error code otherwise.
+ */
+ int (*hdmi_scrambler_disable)(struct drm_bridge *bridge);
+
/**
* @hdmi_clear_avi_infoframe:
*
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 15/69] drm/bridge: Add bridge ops for source-side HDMI 2.0 scrambling
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Dmitry Baryshkov
Bridges advertising HDMI 2.0 must be able to enable and disable
source-side scrambling and the high TMDS clock ratio when the configured
mode exceeds 340 MHz.
Add .hdmi_scrambler_{enable|disable}() callbacks covering the
source-side programming only; sink-side SCDC negotiation remains the job
of the HDMI connector helpers.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
include/drm/drm_bridge.h | 35 +++++++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index 5a5a25995471..77b3ffe69230 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -561,6 +561,41 @@ struct drm_bridge_funcs {
const struct drm_display_mode *mode,
unsigned long long tmds_rate);
+ /**
+ * @hdmi_scrambler_enable:
+ *
+ * Enable source-side scrambling and the high TMDS clock ratio for the
+ * mode currently being applied.
+ *
+ * This only programs the source side. Sink-side SCDC configuration is
+ * handled by the HDMI connector helpers.
+ *
+ * Mandatory for bridges that set the DRM_BRIDGE_OP_HDMI flag in their
+ * &drm_bridge->ops and advertise HDMI_VERSION_2_0 or later via
+ * &drm_bridge->supported_hdmi_ver; unused otherwise.
+ *
+ * Returns:
+ * 0 on success, a negative error code otherwise.
+ */
+ int (*hdmi_scrambler_enable)(struct drm_bridge *bridge);
+
+ /**
+ * @hdmi_scrambler_disable:
+ *
+ * Disable source-side scrambling and the high TMDS clock ratio.
+ *
+ * This only programs the source side. Sink-side SCDC configuration is
+ * handled by the HDMI connector helpers.
+ *
+ * Mandatory for bridges that set the DRM_BRIDGE_OP_HDMI flag in their
+ * &drm_bridge->ops and advertise HDMI_VERSION_2_0 or later via
+ * &drm_bridge->supported_hdmi_ver; unused otherwise.
+ *
+ * Returns:
+ * 0 on success, a negative error code otherwise.
+ */
+ int (*hdmi_scrambler_disable)(struct drm_bridge *bridge);
+
/**
* @hdmi_clear_avi_infoframe:
*
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread* Re: [PATCH v10 15/69] drm/bridge: Add bridge ops for source-side HDMI 2.0 scrambling
2026-07-31 16:19 ` Cristian Ciocaltea
(?)
@ 2026-07-31 18:09 ` sashiko-bot
-1 siblings, 0 replies; 155+ messages in thread
From: sashiko-bot @ 2026-07-31 18:09 UTC (permalink / raw)
To: Cristian Ciocaltea; +Cc: linux-sunxi, dri-devel
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Missing API implementation for bridge HDMI 2.0 scrambler callbacks causes unconditional probe failure.
--
--- Patch [15]: [PATCH v10 15/69] drm/bridge: Add bridge ops for source-side HDMI 2.0 scrambling ---
commit 5577332c0f45e627e54f1e2997be97e38fdecf40
Author: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
drm/bridge: Add bridge ops for source-side HDMI 2.0 scrambling
This commit adds hdmi_scrambler_enable() and hdmi_scrambler_disable()
callbacks to struct drm_bridge_funcs. These allow bridges to enable or
disable source-side scrambling and high TMDS clock ratios for modes
exceeding 340 MHz.
> diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
> index 5a5a25995471c..77b3ffe692304 100644
> --- a/include/drm/drm_bridge.h
> +++ b/include/drm/drm_bridge.h
[ ... ]
> + /**
> + * @hdmi_scrambler_enable:
> + *
> + * Enable source-side scrambling and the high TMDS clock ratio for the
> + * mode currently being applied.
[ ... ]
> + * Returns:
> + * 0 on success, a negative error code otherwise.
> + */
> + int (*hdmi_scrambler_enable)(struct drm_bridge *bridge);
> +
> + /**
> + * @hdmi_scrambler_disable:
> + *
> + * Disable source-side scrambling and the high TMDS clock ratio.
[ ... ]
> + * Returns:
> + * 0 on success, a negative error code otherwise.
> + */
> + int (*hdmi_scrambler_disable)(struct drm_bridge *bridge);
[Severity: Medium]
Are these newly added callbacks being hooked up to the DRM connector
infrastructure?
Looking at drm_bridge_connector_init() in drm_bridge_connector.c, it
initializes hdmi_funcs but doesn't seem to map these new bridge callbacks:
bridge_connector->hdmi_funcs = drm_bridge_connector_hdmi_funcs;
bridge_connector->hdmi_funcs.vendor = bridge_connector->bridge_hdmi->vendor;
bridge_connector->hdmi_funcs.product = bridge_connector->bridge_hdmi->product;
If a bridge advertises HDMI_VERSION_2_0, will drmm_connector_hdmi_init()
fail with -EINVAL during probe because the connector's hdmi_funcs are
missing these required scrambler callbacks?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260731-dw-hdmi-qp-scramb-v10-0-294364b2cf15@collabora.com?part=15
^ permalink raw reply [flat|nested] 155+ messages in thread
* [PATCH v10 16/69] drm/display: bridge_connector: Use cached connector status in .get_modes()
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Dmitry Baryshkov, Maud Spierings,
Diederik de Haas
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>
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
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 9ad31e9df0ab..8a833c813101 100644
--- a/drivers/gpu/drm/display/drm_bridge_connector.c
+++ b/drivers/gpu/drm/display/drm_bridge_connector.c
@@ -325,12 +325,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.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 16/69] drm/display: bridge_connector: Use cached connector status in .get_modes()
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Dmitry Baryshkov, Maud Spierings,
Diederik de Haas
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>
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
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 9ad31e9df0ab..8a833c813101 100644
--- a/drivers/gpu/drm/display/drm_bridge_connector.c
+++ b/drivers/gpu/drm/display/drm_bridge_connector.c
@@ -325,12 +325,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.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 17/69] drm/display: bridge_connector: Switch to .detect_ctx() connector helper
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Dmitry Baryshkov, Maud Spierings,
Diederik de Haas
Replace the .detect() connector_funcs callback with the atomic-aware
.detect_ctx() connector_helper_funcs hook.
This is preparatory work to allow propagating the modeset acquire
context through drm_atomic_helper_connector_hdmi_hotplug() to the HDMI
connector framework, enabling SCDC state recovery via CRTC reset when
the sink reconnects during an active display pipeline.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_bridge_connector.c | 69 +++++++++++++-------------
1 file changed, 35 insertions(+), 34 deletions(-)
diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
index 8a833c813101..0d44a270b636 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 =
@@ -307,7 +274,6 @@ drm_bridge_connector_color_format(const struct drm_connector_state *conn_state)
}
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,
@@ -322,6 +288,40 @@ 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;
+
+ 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 int drm_bridge_connector_get_modes_edid(struct drm_connector *connector,
struct drm_bridge *bridge)
{
@@ -413,6 +413,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.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 17/69] drm/display: bridge_connector: Switch to .detect_ctx() connector helper
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Dmitry Baryshkov, Maud Spierings,
Diederik de Haas
Replace the .detect() connector_funcs callback with the atomic-aware
.detect_ctx() connector_helper_funcs hook.
This is preparatory work to allow propagating the modeset acquire
context through drm_atomic_helper_connector_hdmi_hotplug() to the HDMI
connector framework, enabling SCDC state recovery via CRTC reset when
the sink reconnects during an active display pipeline.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_bridge_connector.c | 69 +++++++++++++-------------
1 file changed, 35 insertions(+), 34 deletions(-)
diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
index 8a833c813101..0d44a270b636 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 =
@@ -307,7 +274,6 @@ drm_bridge_connector_color_format(const struct drm_connector_state *conn_state)
}
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,
@@ -322,6 +288,40 @@ 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;
+
+ 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 int drm_bridge_connector_get_modes_edid(struct drm_connector *connector,
struct drm_bridge *bridge)
{
@@ -413,6 +413,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.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 18/69] drm/display: bridge_connector: Switch to .force_ctx() connector helper
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
Turn drm_bridge_connector_force() into a .force_ctx() implementation and
hand the acquire context over to
drm_atomic_helper_connector_hdmi_force_ctx(), so that the HDMI connector
framework can reset the CRTC to recover the SCDC state when the sink
reconnects while the display pipeline is active.
No functional change for non-HDMI bridge connectors, which keep behaving
as a no-op.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_bridge_connector.c | 25 ++++++++++++++-----------
1 file changed, 14 insertions(+), 11 deletions(-)
diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
index 0d44a270b636..86353a0b9758 100644
--- a/drivers/gpu/drm/display/drm_bridge_connector.c
+++ b/drivers/gpu/drm/display/drm_bridge_connector.c
@@ -208,16 +208,6 @@ static void drm_bridge_connector_disable_hpd(struct drm_connector *connector)
* Bridge Connector Functions
*/
-static void drm_bridge_connector_force(struct drm_connector *connector)
-{
- struct drm_bridge_connector *bridge_connector =
- to_drm_bridge_connector(connector);
- struct drm_bridge *hdmi = bridge_connector->bridge_hdmi;
-
- if (hdmi)
- drm_atomic_helper_connector_hdmi_force(connector);
-}
-
static void drm_bridge_connector_debugfs_init(struct drm_connector *connector,
struct dentry *root)
{
@@ -274,7 +264,6 @@ drm_bridge_connector_color_format(const struct drm_connector_state *conn_state)
}
static const struct drm_connector_funcs drm_bridge_connector_funcs = {
- .force = drm_bridge_connector_force,
.fill_modes = drm_helper_probe_single_connector_modes,
.atomic_create_state = drm_bridge_connector_create_state,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
@@ -322,6 +311,19 @@ static int drm_bridge_connector_detect_ctx(struct drm_connector *connector,
return status;
}
+static int drm_bridge_connector_force_ctx(struct drm_connector *connector,
+ struct drm_modeset_acquire_ctx *ctx)
+{
+ struct drm_bridge_connector *bridge_connector =
+ to_drm_bridge_connector(connector);
+ struct drm_bridge *hdmi = bridge_connector->bridge_hdmi;
+
+ if (hdmi)
+ return drm_atomic_helper_connector_hdmi_force_ctx(connector, ctx);
+
+ return 0;
+}
+
static int drm_bridge_connector_get_modes_edid(struct drm_connector *connector,
struct drm_bridge *bridge)
{
@@ -414,6 +416,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,
+ .force_ctx = drm_bridge_connector_force_ctx,
.mode_valid = drm_bridge_connector_mode_valid,
.enable_hpd = drm_bridge_connector_enable_hpd,
.disable_hpd = drm_bridge_connector_disable_hpd,
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 18/69] drm/display: bridge_connector: Switch to .force_ctx() connector helper
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
Turn drm_bridge_connector_force() into a .force_ctx() implementation and
hand the acquire context over to
drm_atomic_helper_connector_hdmi_force_ctx(), so that the HDMI connector
framework can reset the CRTC to recover the SCDC state when the sink
reconnects while the display pipeline is active.
No functional change for non-HDMI bridge connectors, which keep behaving
as a no-op.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_bridge_connector.c | 25 ++++++++++++++-----------
1 file changed, 14 insertions(+), 11 deletions(-)
diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
index 0d44a270b636..86353a0b9758 100644
--- a/drivers/gpu/drm/display/drm_bridge_connector.c
+++ b/drivers/gpu/drm/display/drm_bridge_connector.c
@@ -208,16 +208,6 @@ static void drm_bridge_connector_disable_hpd(struct drm_connector *connector)
* Bridge Connector Functions
*/
-static void drm_bridge_connector_force(struct drm_connector *connector)
-{
- struct drm_bridge_connector *bridge_connector =
- to_drm_bridge_connector(connector);
- struct drm_bridge *hdmi = bridge_connector->bridge_hdmi;
-
- if (hdmi)
- drm_atomic_helper_connector_hdmi_force(connector);
-}
-
static void drm_bridge_connector_debugfs_init(struct drm_connector *connector,
struct dentry *root)
{
@@ -274,7 +264,6 @@ drm_bridge_connector_color_format(const struct drm_connector_state *conn_state)
}
static const struct drm_connector_funcs drm_bridge_connector_funcs = {
- .force = drm_bridge_connector_force,
.fill_modes = drm_helper_probe_single_connector_modes,
.atomic_create_state = drm_bridge_connector_create_state,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
@@ -322,6 +311,19 @@ static int drm_bridge_connector_detect_ctx(struct drm_connector *connector,
return status;
}
+static int drm_bridge_connector_force_ctx(struct drm_connector *connector,
+ struct drm_modeset_acquire_ctx *ctx)
+{
+ struct drm_bridge_connector *bridge_connector =
+ to_drm_bridge_connector(connector);
+ struct drm_bridge *hdmi = bridge_connector->bridge_hdmi;
+
+ if (hdmi)
+ return drm_atomic_helper_connector_hdmi_force_ctx(connector, ctx);
+
+ return 0;
+}
+
static int drm_bridge_connector_get_modes_edid(struct drm_connector *connector,
struct drm_bridge *bridge)
{
@@ -414,6 +416,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,
+ .force_ctx = drm_bridge_connector_force_ctx,
.mode_valid = drm_bridge_connector_mode_valid,
.enable_hpd = drm_bridge_connector_enable_hpd,
.disable_hpd = drm_bridge_connector_disable_hpd,
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread* Re: [PATCH v10 18/69] drm/display: bridge_connector: Switch to .force_ctx() connector helper
2026-07-31 16:19 ` Cristian Ciocaltea
(?)
@ 2026-07-31 18:31 ` sashiko-bot
-1 siblings, 0 replies; 155+ messages in thread
From: sashiko-bot @ 2026-07-31 18:31 UTC (permalink / raw)
To: Cristian Ciocaltea; +Cc: dri-devel, linux-sunxi
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] The patch replaces `drm_bridge_connector_force()` with `drm_bridge_connector_force_ctx()` and calls `drm_atomic_helper_connector_hdmi_force_ctx()`. However, `drm_atomic_helper_connector_hdmi_force_ctx()` is neither defined nor declared anywhere in the kernel tree. This results in an implicit function declaration error and undefined reference during linking.
--
--- Patch [18]: [PATCH v10 18/69] drm/display: bridge_connector: Switch to .force_ctx() connector helper ---
commit 01a7e2cca1b495d499fd78712842111769ad4146
Author: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
drm/display: bridge_connector: Switch to .force_ctx() connector helper
This commit replaces the drm_bridge_connector_force() function with a
.force_ctx() implementation. It hands the acquire context over to
drm_atomic_helper_connector_hdmi_force_ctx() for HDMI connectors.
> diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
> --- a/drivers/gpu/drm/display/drm_bridge_connector.c
> +++ b/drivers/gpu/drm/display/drm_bridge_connector.c
[ ... ]
> @@ -322,6 +311,19 @@ static int drm_bridge_connector_detect_ctx(struct drm_connector *connector,
> return status;
> }
>
> +static int drm_bridge_connector_force_ctx(struct drm_connector *connector,
> + struct drm_modeset_acquire_ctx *ctx)
> +{
> + struct drm_bridge_connector *bridge_connector =
> + to_drm_bridge_connector(connector);
> + struct drm_bridge *hdmi = bridge_connector->bridge_hdmi;
> +
> + if (hdmi)
> + return drm_atomic_helper_connector_hdmi_force_ctx(connector, ctx);
[Severity: Low]
It appears drm_atomic_helper_connector_hdmi_force_ctx() is not declared
anywhere in the kernel tree prior to being used here.
Could this result in an implicit function declaration error and an undefined
reference during linking when building with DRM display bridge connector
support enabled? Is it possible a prerequisite patch introducing this
helper was omitted from the series?
> +
> + return 0;
> +}
> +
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260731-dw-hdmi-qp-scramb-v10-0-294364b2cf15@collabora.com?part=18
^ permalink raw reply [flat|nested] 155+ messages in thread
* [PATCH v10 19/69] drm/display: bridge_connector: Wire up HDMI 2.0 scrambler callbacks
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Maud Spierings, Diederik de Haas
Connect the bridge connector's .scrambler_{enable|disable} callbacks to
the underlying bridge's .hdmi_scrambler_{enable|disable} funcs when
HDMI 2.0 conformance is advertised.
This completes the bridge connector plumbing so that the SCDC
scrambling helpers can control source-side scrambling through the
bridge chain.
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_bridge_connector.c | 40 +++++++++++++++++++++++++-
1 file changed, 39 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
index 86353a0b9758..80b33d4f6b38 100644
--- a/drivers/gpu/drm/display/drm_bridge_connector.c
+++ b/drivers/gpu/drm/display/drm_bridge_connector.c
@@ -577,6 +577,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)
{
@@ -604,7 +630,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 = {
@@ -908,6 +934,11 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
!bridge->funcs->hdmi_clear_spd_infoframe))
return ERR_PTR(-EINVAL);
+ if (bridge->supported_hdmi_ver >= HDMI_VERSION_2_0 &&
+ (!bridge->funcs->hdmi_scrambler_enable ||
+ !bridge->funcs->hdmi_scrambler_disable))
+ return ERR_PTR(-EINVAL);
+
bridge_connector->bridge_hdmi = drm_bridge_get(bridge);
}
@@ -1027,6 +1058,13 @@ 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->supported_hdmi_ver >= HDMI_VERSION_2_0) {
+ bridge_connector->hdmi_funcs.scrambler_enable =
+ drm_bridge_connector_scrambler_enable;
+ bridge_connector->hdmi_funcs.scrambler_disable =
+ drm_bridge_connector_scrambler_disable;
+ }
+
ret = drmm_connector_hdmi_init(drm, connector,
&drm_bridge_connector_funcs,
&bridge_connector->hdmi_funcs,
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 19/69] drm/display: bridge_connector: Wire up HDMI 2.0 scrambler callbacks
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Maud Spierings, Diederik de Haas
Connect the bridge connector's .scrambler_{enable|disable} callbacks to
the underlying bridge's .hdmi_scrambler_{enable|disable} funcs when
HDMI 2.0 conformance is advertised.
This completes the bridge connector plumbing so that the SCDC
scrambling helpers can control source-side scrambling through the
bridge chain.
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_bridge_connector.c | 40 +++++++++++++++++++++++++-
1 file changed, 39 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
index 86353a0b9758..80b33d4f6b38 100644
--- a/drivers/gpu/drm/display/drm_bridge_connector.c
+++ b/drivers/gpu/drm/display/drm_bridge_connector.c
@@ -577,6 +577,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)
{
@@ -604,7 +630,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 = {
@@ -908,6 +934,11 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
!bridge->funcs->hdmi_clear_spd_infoframe))
return ERR_PTR(-EINVAL);
+ if (bridge->supported_hdmi_ver >= HDMI_VERSION_2_0 &&
+ (!bridge->funcs->hdmi_scrambler_enable ||
+ !bridge->funcs->hdmi_scrambler_disable))
+ return ERR_PTR(-EINVAL);
+
bridge_connector->bridge_hdmi = drm_bridge_get(bridge);
}
@@ -1027,6 +1058,13 @@ 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->supported_hdmi_ver >= HDMI_VERSION_2_0) {
+ bridge_connector->hdmi_funcs.scrambler_enable =
+ drm_bridge_connector_scrambler_enable;
+ bridge_connector->hdmi_funcs.scrambler_disable =
+ drm_bridge_connector_scrambler_disable;
+ }
+
ret = drmm_connector_hdmi_init(drm, connector,
&drm_bridge_connector_funcs,
&bridge_connector->hdmi_funcs,
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 20/69] drm/display: hdmi-state-helper: Add source TMDS rate validation
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Maud Spierings, Diederik de Haas
Validate the computed TMDS character rate against
connector->hdmi.max_tmds_char_rate, when provided by the driver/source.
This gives HDMI connectors common support for rejecting modes whose TMDS
character rate exceeds the source supported limit, while still allowing
drivers with custom validation requirements to implement their own
tmds_char_rate_valid() callback.
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_hdmi_state_helper.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
index ce17eeefc2da..92be6278ea44 100644
--- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
@@ -560,6 +560,10 @@ hdmi_clock_valid(const struct drm_connector *connector,
if (info->max_tmds_clock && clock > info->max_tmds_clock * 1000)
return MODE_CLOCK_HIGH;
+ if (connector->hdmi.max_tmds_char_rate &&
+ clock > connector->hdmi.max_tmds_char_rate)
+ return MODE_CLOCK_HIGH;
+
if (funcs && funcs->tmds_char_rate_valid) {
enum drm_mode_status status;
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 20/69] drm/display: hdmi-state-helper: Add source TMDS rate validation
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Maud Spierings, Diederik de Haas
Validate the computed TMDS character rate against
connector->hdmi.max_tmds_char_rate, when provided by the driver/source.
This gives HDMI connectors common support for rejecting modes whose TMDS
character rate exceeds the source supported limit, while still allowing
drivers with custom validation requirements to implement their own
tmds_char_rate_valid() callback.
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_hdmi_state_helper.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
index ce17eeefc2da..92be6278ea44 100644
--- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
@@ -560,6 +560,10 @@ hdmi_clock_valid(const struct drm_connector *connector,
if (info->max_tmds_clock && clock > info->max_tmds_clock * 1000)
return MODE_CLOCK_HIGH;
+ if (connector->hdmi.max_tmds_char_rate &&
+ clock > connector->hdmi.max_tmds_char_rate)
+ return MODE_CLOCK_HIGH;
+
if (funcs && funcs->tmds_char_rate_valid) {
enum drm_mode_status status;
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 21/69] drm/display: hdmi-state-helper: Pass acquire ctx to hotplug helpers
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Diederik de Haas
In preparation for supporting SCDC status synchronization on hotplug
events, extend drm_atomic_helper_connector_hdmi_hotplug() and
drm_atomic_helper_connector_hdmi_update() to take a struct
drm_modeset_acquire_ctx argument. This will be used when a CRTC reset
is required.
Additionally, change their return type from void to int to allow
propagation of errors such as -EDEADLK caused by lock contention.
Update existing callers accordingly. Note that in the VC4 case, the
return code is ignored, as it cannot fail: being in the .detect_ctx()
call path, the connection mutex is already held through ctx, and it
bails out early because the driver relies on a local SCDC
state-management implementation, and therefore does not yet expose the
scrambler capability through the common helpers.
Similarly, introduce drm_atomic_helper_connector_hdmi_force_ctx() as the
HDMI connector implementation of the .force_ctx() callback. Since
migrating from the .force() callback is somewhat more involved, its
users will be migrated incrementally, after which
drm_atomic_helper_connector_hdmi_force() will be removed.
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_bridge_connector.c | 8 +++--
drivers/gpu/drm/display/drm_hdmi_state_helper.c | 42 +++++++++++++++++++++----
drivers/gpu/drm/vc4/vc4_hdmi.c | 2 +-
include/drm/display/drm_hdmi_state_helper.h | 8 +++--
4 files changed, 49 insertions(+), 11 deletions(-)
diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
index 80b33d4f6b38..e78efccb7757 100644
--- a/drivers/gpu/drm/display/drm_bridge_connector.c
+++ b/drivers/gpu/drm/display/drm_bridge_connector.c
@@ -286,12 +286,16 @@ static int drm_bridge_connector_detect_ctx(struct drm_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)
- drm_atomic_helper_connector_hdmi_hotplug(connector, status);
+ if (hdmi) {
+ ret = drm_atomic_helper_connector_hdmi_hotplug(connector, ctx, status);
+ if (ret == -EDEADLK)
+ return ret;
+ }
drm_bridge_connector_hpd_notify(connector, status);
} else {
diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
index 92be6278ea44..4a93c279c9a7 100644
--- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
@@ -1199,8 +1199,9 @@ 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,
+ struct drm_modeset_acquire_ctx *ctx,
enum drm_connector_status status)
{
const struct drm_edid *drm_edid;
@@ -1210,7 +1211,7 @@ drm_atomic_helper_connector_hdmi_update(struct drm_connector *connector,
drm_connector_hdmi_audio_plugged_notify(connector, false);
drm_edid_connector_update(connector, NULL);
drm_connector_cec_phys_addr_invalidate(connector);
- return;
+ return 0;
}
if (connector->hdmi.funcs->read_edid)
@@ -1227,20 +1228,28 @@ drm_atomic_helper_connector_hdmi_update(struct drm_connector *connector,
drm_connector_hdmi_audio_plugged_notify(connector, true);
drm_connector_cec_phys_addr_set(connector);
}
+
+ return 0;
}
/**
* drm_atomic_helper_connector_hdmi_hotplug - Handle the hotplug event for the HDMI connector
* @connector: A pointer to the HDMI connector
+ * @ctx: Lock acquisition context to be used for resetting CRTC
* @status: Connection status
*
* 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.
*/
-void drm_atomic_helper_connector_hdmi_hotplug(struct drm_connector *connector,
- enum drm_connector_status status)
+int drm_atomic_helper_connector_hdmi_hotplug(struct drm_connector *connector,
+ struct drm_modeset_acquire_ctx *ctx,
+ enum drm_connector_status status)
{
- drm_atomic_helper_connector_hdmi_update(connector, status);
+ return drm_atomic_helper_connector_hdmi_update(connector, ctx, status);
}
EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_hotplug);
@@ -1255,6 +1264,27 @@ 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, NULL, connector->status);
}
EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_force);
+
+/**
+ * drm_atomic_helper_connector_hdmi_force_ctx - HDMI Connector implementation
+ * of the force_ctx callback
+ * @connector: A pointer to the HDMI connector
+ * @ctx: Lock acquisition context to be used for resetting CRTC
+ *
+ * This function implements the .force_ctx() callback for the HDMI connectors.
+ * It can either be used directly as the callback or should be called from
+ * within the .force_ctx() callback implementation to maintain the HDMI-specific
+ * connector's data.
+ *
+ * Returns:
+ * Zero on success, error code on failure, including -EDEADLK.
+ */
+int drm_atomic_helper_connector_hdmi_force_ctx(struct drm_connector *connector,
+ struct drm_modeset_acquire_ctx *ctx)
+{
+ return drm_atomic_helper_connector_hdmi_update(connector, ctx, connector->status);
+}
+EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_force_ctx);
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index 72ff95ca97de..7f613f912368 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -375,7 +375,7 @@ static void vc4_hdmi_handle_hotplug(struct vc4_hdmi *vc4_hdmi,
* the lock for now.
*/
- drm_atomic_helper_connector_hdmi_hotplug(connector, status);
+ drm_atomic_helper_connector_hdmi_hotplug(connector, ctx, status);
if (status != connector_status_connected)
return;
diff --git a/include/drm/display/drm_hdmi_state_helper.h b/include/drm/display/drm_hdmi_state_helper.h
index 13375bd0f4ae..ae4fff82c3fb 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;
@@ -22,9 +23,12 @@ int drm_atomic_helper_connector_hdmi_update_audio_infoframe(struct drm_connector
int drm_atomic_helper_connector_hdmi_clear_audio_infoframe(struct drm_connector *connector);
int drm_atomic_helper_connector_hdmi_update_infoframes(struct drm_connector *connector,
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(struct drm_connector *connector,
+ struct drm_modeset_acquire_ctx *ctx,
+ enum drm_connector_status status);
void drm_atomic_helper_connector_hdmi_force(struct drm_connector *connector);
+int drm_atomic_helper_connector_hdmi_force_ctx(struct drm_connector *connector,
+ struct drm_modeset_acquire_ctx *ctx);
enum drm_mode_status
drm_hdmi_connector_mode_valid(struct drm_connector *connector,
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 21/69] drm/display: hdmi-state-helper: Pass acquire ctx to hotplug helpers
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Diederik de Haas
In preparation for supporting SCDC status synchronization on hotplug
events, extend drm_atomic_helper_connector_hdmi_hotplug() and
drm_atomic_helper_connector_hdmi_update() to take a struct
drm_modeset_acquire_ctx argument. This will be used when a CRTC reset
is required.
Additionally, change their return type from void to int to allow
propagation of errors such as -EDEADLK caused by lock contention.
Update existing callers accordingly. Note that in the VC4 case, the
return code is ignored, as it cannot fail: being in the .detect_ctx()
call path, the connection mutex is already held through ctx, and it
bails out early because the driver relies on a local SCDC
state-management implementation, and therefore does not yet expose the
scrambler capability through the common helpers.
Similarly, introduce drm_atomic_helper_connector_hdmi_force_ctx() as the
HDMI connector implementation of the .force_ctx() callback. Since
migrating from the .force() callback is somewhat more involved, its
users will be migrated incrementally, after which
drm_atomic_helper_connector_hdmi_force() will be removed.
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_bridge_connector.c | 8 +++--
drivers/gpu/drm/display/drm_hdmi_state_helper.c | 42 +++++++++++++++++++++----
drivers/gpu/drm/vc4/vc4_hdmi.c | 2 +-
include/drm/display/drm_hdmi_state_helper.h | 8 +++--
4 files changed, 49 insertions(+), 11 deletions(-)
diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
index 80b33d4f6b38..e78efccb7757 100644
--- a/drivers/gpu/drm/display/drm_bridge_connector.c
+++ b/drivers/gpu/drm/display/drm_bridge_connector.c
@@ -286,12 +286,16 @@ static int drm_bridge_connector_detect_ctx(struct drm_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)
- drm_atomic_helper_connector_hdmi_hotplug(connector, status);
+ if (hdmi) {
+ ret = drm_atomic_helper_connector_hdmi_hotplug(connector, ctx, status);
+ if (ret == -EDEADLK)
+ return ret;
+ }
drm_bridge_connector_hpd_notify(connector, status);
} else {
diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
index 92be6278ea44..4a93c279c9a7 100644
--- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
@@ -1199,8 +1199,9 @@ 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,
+ struct drm_modeset_acquire_ctx *ctx,
enum drm_connector_status status)
{
const struct drm_edid *drm_edid;
@@ -1210,7 +1211,7 @@ drm_atomic_helper_connector_hdmi_update(struct drm_connector *connector,
drm_connector_hdmi_audio_plugged_notify(connector, false);
drm_edid_connector_update(connector, NULL);
drm_connector_cec_phys_addr_invalidate(connector);
- return;
+ return 0;
}
if (connector->hdmi.funcs->read_edid)
@@ -1227,20 +1228,28 @@ drm_atomic_helper_connector_hdmi_update(struct drm_connector *connector,
drm_connector_hdmi_audio_plugged_notify(connector, true);
drm_connector_cec_phys_addr_set(connector);
}
+
+ return 0;
}
/**
* drm_atomic_helper_connector_hdmi_hotplug - Handle the hotplug event for the HDMI connector
* @connector: A pointer to the HDMI connector
+ * @ctx: Lock acquisition context to be used for resetting CRTC
* @status: Connection status
*
* 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.
*/
-void drm_atomic_helper_connector_hdmi_hotplug(struct drm_connector *connector,
- enum drm_connector_status status)
+int drm_atomic_helper_connector_hdmi_hotplug(struct drm_connector *connector,
+ struct drm_modeset_acquire_ctx *ctx,
+ enum drm_connector_status status)
{
- drm_atomic_helper_connector_hdmi_update(connector, status);
+ return drm_atomic_helper_connector_hdmi_update(connector, ctx, status);
}
EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_hotplug);
@@ -1255,6 +1264,27 @@ 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, NULL, connector->status);
}
EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_force);
+
+/**
+ * drm_atomic_helper_connector_hdmi_force_ctx - HDMI Connector implementation
+ * of the force_ctx callback
+ * @connector: A pointer to the HDMI connector
+ * @ctx: Lock acquisition context to be used for resetting CRTC
+ *
+ * This function implements the .force_ctx() callback for the HDMI connectors.
+ * It can either be used directly as the callback or should be called from
+ * within the .force_ctx() callback implementation to maintain the HDMI-specific
+ * connector's data.
+ *
+ * Returns:
+ * Zero on success, error code on failure, including -EDEADLK.
+ */
+int drm_atomic_helper_connector_hdmi_force_ctx(struct drm_connector *connector,
+ struct drm_modeset_acquire_ctx *ctx)
+{
+ return drm_atomic_helper_connector_hdmi_update(connector, ctx, connector->status);
+}
+EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_force_ctx);
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index 72ff95ca97de..7f613f912368 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -375,7 +375,7 @@ static void vc4_hdmi_handle_hotplug(struct vc4_hdmi *vc4_hdmi,
* the lock for now.
*/
- drm_atomic_helper_connector_hdmi_hotplug(connector, status);
+ drm_atomic_helper_connector_hdmi_hotplug(connector, ctx, status);
if (status != connector_status_connected)
return;
diff --git a/include/drm/display/drm_hdmi_state_helper.h b/include/drm/display/drm_hdmi_state_helper.h
index 13375bd0f4ae..ae4fff82c3fb 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;
@@ -22,9 +23,12 @@ int drm_atomic_helper_connector_hdmi_update_audio_infoframe(struct drm_connector
int drm_atomic_helper_connector_hdmi_clear_audio_infoframe(struct drm_connector *connector);
int drm_atomic_helper_connector_hdmi_update_infoframes(struct drm_connector *connector,
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(struct drm_connector *connector,
+ struct drm_modeset_acquire_ctx *ctx,
+ enum drm_connector_status status);
void drm_atomic_helper_connector_hdmi_force(struct drm_connector *connector);
+int drm_atomic_helper_connector_hdmi_force_ctx(struct drm_connector *connector,
+ struct drm_modeset_acquire_ctx *ctx);
enum drm_mode_status
drm_hdmi_connector_mode_valid(struct drm_connector *connector,
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 22/69] drm/display: hdmi-state-helper: Sync SCDC state on hotplug
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Maud Spierings, Diederik de Haas
drm_atomic_helper_connector_hdmi_hotplug() does not currently
synchronize SCDC status on hotplug events, leaving the scrambler state
potentially inconsistent after (re)connect.
Hook drm_connector_hdmi_sync_scdc() into both the connect and disconnect
paths, replacing the existing TODOs around missing scrambler handling.
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_hdmi_state_helper.c | 23 ++++++++++++++---------
1 file changed, 14 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
index 4a93c279c9a7..3377ea936120 100644
--- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
@@ -1205,13 +1205,16 @@ drm_atomic_helper_connector_hdmi_update(struct drm_connector *connector,
enum drm_connector_status status)
{
const struct drm_edid *drm_edid;
+ int ret = 0;
if (status == connector_status_disconnected) {
- // TODO: also handle scramber, HDMI sink disconnected.
- drm_connector_hdmi_audio_plugged_notify(connector, false);
- drm_edid_connector_update(connector, NULL);
- drm_connector_cec_phys_addr_invalidate(connector);
- return 0;
+ ret = drm_connector_hdmi_sync_scdc(connector, false, ctx);
+ if (ret != -EDEADLK) {
+ drm_connector_hdmi_audio_plugged_notify(connector, false);
+ drm_edid_connector_update(connector, NULL);
+ drm_connector_cec_phys_addr_invalidate(connector);
+ }
+ return ret;
}
if (connector->hdmi.funcs->read_edid)
@@ -1224,12 +1227,14 @@ 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.
- drm_connector_hdmi_audio_plugged_notify(connector, true);
- drm_connector_cec_phys_addr_set(connector);
+ ret = drm_connector_hdmi_sync_scdc(connector, true, ctx);
+ if (ret != -EDEADLK) {
+ drm_connector_hdmi_audio_plugged_notify(connector, true);
+ drm_connector_cec_phys_addr_set(connector);
+ }
}
- return 0;
+ return ret;
}
/**
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 22/69] drm/display: hdmi-state-helper: Sync SCDC state on hotplug
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Maud Spierings, Diederik de Haas
drm_atomic_helper_connector_hdmi_hotplug() does not currently
synchronize SCDC status on hotplug events, leaving the scrambler state
potentially inconsistent after (re)connect.
Hook drm_connector_hdmi_sync_scdc() into both the connect and disconnect
paths, replacing the existing TODOs around missing scrambler handling.
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_hdmi_state_helper.c | 23 ++++++++++++++---------
1 file changed, 14 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
index 4a93c279c9a7..3377ea936120 100644
--- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
@@ -1205,13 +1205,16 @@ drm_atomic_helper_connector_hdmi_update(struct drm_connector *connector,
enum drm_connector_status status)
{
const struct drm_edid *drm_edid;
+ int ret = 0;
if (status == connector_status_disconnected) {
- // TODO: also handle scramber, HDMI sink disconnected.
- drm_connector_hdmi_audio_plugged_notify(connector, false);
- drm_edid_connector_update(connector, NULL);
- drm_connector_cec_phys_addr_invalidate(connector);
- return 0;
+ ret = drm_connector_hdmi_sync_scdc(connector, false, ctx);
+ if (ret != -EDEADLK) {
+ drm_connector_hdmi_audio_plugged_notify(connector, false);
+ drm_edid_connector_update(connector, NULL);
+ drm_connector_cec_phys_addr_invalidate(connector);
+ }
+ return ret;
}
if (connector->hdmi.funcs->read_edid)
@@ -1224,12 +1227,14 @@ 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.
- drm_connector_hdmi_audio_plugged_notify(connector, true);
- drm_connector_cec_phys_addr_set(connector);
+ ret = drm_connector_hdmi_sync_scdc(connector, true, ctx);
+ if (ret != -EDEADLK) {
+ drm_connector_hdmi_audio_plugged_notify(connector, true);
+ drm_connector_cec_phys_addr_set(connector);
+ }
}
- return 0;
+ return ret;
}
/**
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread* Re: [PATCH v10 22/69] drm/display: hdmi-state-helper: Sync SCDC state on hotplug
2026-07-31 16:19 ` Cristian Ciocaltea
(?)
@ 2026-07-31 19:02 ` sashiko-bot
-1 siblings, 0 replies; 155+ messages in thread
From: sashiko-bot @ 2026-07-31 19:02 UTC (permalink / raw)
To: Cristian Ciocaltea; +Cc: linux-sunxi, dri-devel
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] SCDC sync fails to handle scrambler teardown on disconnect, leaving the source scrambler active when swapping to a non-scrambling sink.
--
--- Patch [22]: [PATCH v10 22/69] drm/display: hdmi-state-helper: Sync SCDC state on hotplug ---
commit 7cc2ce705b4793d8696717d86562fbd6c0bde231
Author: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
drm/display: hdmi-state-helper: Sync SCDC state on hotplug
This commit hooks drm_connector_hdmi_sync_scdc() into the connect and
disconnect paths in drm_atomic_helper_connector_hdmi_update() to synchronize
the SCDC status on hotplug events.
> diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
> index 4a93c279c9a76..3377ea9361209 100644
> --- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
> +++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
> @@ -1205,13 +1205,16 @@ drm_atomic_helper_connector_hdmi_update(struct drm_connector *connector,
> enum drm_connector_status status)
> {
> const struct drm_edid *drm_edid;
> + int ret = 0;
>
> if (status == connector_status_disconnected) {
> - // TODO: also handle scramber, HDMI sink disconnected.
> - drm_connector_hdmi_audio_plugged_notify(connector, false);
> - drm_edid_connector_update(connector, NULL);
> - drm_connector_cec_phys_addr_invalidate(connector);
> - return 0;
> + ret = drm_connector_hdmi_sync_scdc(connector, false, ctx);
[Severity: High]
Does this call successfully tear down the scrambler on disconnect?
Looking at drm_connector_hdmi_sync_scdc() in drm_hdmi_helper.c, it seems
to return immediately if the plugged parameter is false:
int drm_connector_hdmi_sync_scdc(struct drm_connector *connector, bool plugged,
struct drm_modeset_acquire_ctx *ctx)
{
...
if (!connector || !plugged || !ctx)
return 0;
This would make the disconnect call a no-op, failing to disable the source
scrambler.
Additionally, if a non-scrambling sink is subsequently plugged in, the
connect path will call drm_connector_hdmi_sync_scdc() with plugged set to
true, which also bails out early:
if (!connector->ddc || !drm_scdc_sink_supports_scrambling(connector))
return 0;
Could this leave the source scrambler incorrectly enabled if a user swaps from
an HDMI 2.0 monitor to an older HDMI 1.4 monitor, resulting in broken display
output due to mismatched hardware state?
> + if (ret != -EDEADLK) {
> + drm_connector_hdmi_audio_plugged_notify(connector, false);
> + drm_edid_connector_update(connector, NULL);
> + drm_connector_cec_phys_addr_invalidate(connector);
> + }
> + return ret;
> }
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260731-dw-hdmi-qp-scramb-v10-0-294364b2cf15@collabora.com?part=22
^ permalink raw reply [flat|nested] 155+ messages in thread
* [PATCH v10 23/69] drm/display: hdmi-state-helper: Set HDMI scrambling requirement
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Maud Spierings, Diederik de Haas
Set drm_connector_hdmi_state.scrambler_needed when the computed TMDS
character rate exceeds the HDMI 1.3 maximum TMDS character rate.
HDMI 2.0 requires scrambling above 340 MHz. Centralize that clock-based
requirement in the HDMI state helper so drivers do not need to open-code
the threshold check.
Acked-by: Maxime Ripard <mripard@kernel.org>
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_hdmi_state_helper.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
index 3377ea936120..9544eb8659aa 100644
--- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
@@ -594,6 +594,9 @@ hdmi_compute_clock(const struct drm_connector *connector,
conn_state->hdmi.tmds_char_rate = clock;
+ /* TODO: also check drm_display_info.hdmi.scdc.scrambling.low_rates */
+ conn_state->hdmi.scrambler_needed = (clock > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ);
+
return 0;
}
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 23/69] drm/display: hdmi-state-helper: Set HDMI scrambling requirement
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Maud Spierings, Diederik de Haas
Set drm_connector_hdmi_state.scrambler_needed when the computed TMDS
character rate exceeds the HDMI 1.3 maximum TMDS character rate.
HDMI 2.0 requires scrambling above 340 MHz. Centralize that clock-based
requirement in the HDMI state helper so drivers do not need to open-code
the threshold check.
Acked-by: Maxime Ripard <mripard@kernel.org>
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_hdmi_state_helper.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
index 3377ea936120..9544eb8659aa 100644
--- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
@@ -594,6 +594,9 @@ hdmi_compute_clock(const struct drm_connector *connector,
conn_state->hdmi.tmds_char_rate = clock;
+ /* TODO: also check drm_display_info.hdmi.scdc.scrambling.low_rates */
+ conn_state->hdmi.scrambler_needed = (clock > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ);
+
return 0;
}
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* Re: [PATCH v10 23/69] drm/display: hdmi-state-helper: Set HDMI scrambling requirement
2026-07-31 16:19 ` Cristian Ciocaltea
(?)
@ 2026-07-31 19:20 ` sashiko-bot
-1 siblings, 0 replies; 155+ messages in thread
From: sashiko-bot @ 2026-07-31 19:20 UTC (permalink / raw)
To: Cristian Ciocaltea; +Cc: linux-sunxi, dri-devel
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] The HDMI atomic check phase unconditionally sets `scrambler_needed` for TMDS character rates > 340 MHz without verifying if the source and sink actually support scrambling, which can cause an ungraceful failure during the atomic commit phase.
--
--- Patch [23]: [PATCH v10 23/69] drm/display: hdmi-state-helper: Set HDMI scrambling requirement ---
commit e6622cfc80adce83ef4209e099003b9cb90bec11
Author: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
drm/display: hdmi-state-helper: Set HDMI scrambling requirement
This commit centralizes the HDMI scrambling requirement check in the HDMI state
helper. It sets drm_connector_hdmi_state.scrambler_needed to true when the
computed TMDS character rate exceeds the HDMI 1.3 maximum limit.
> diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
> index 3377ea9361209..9544eb8659aa8 100644
> --- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
> +++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
> @@ -594,6 +594,9 @@ hdmi_compute_clock(const struct drm_connector *connector,
>
> conn_state->hdmi.tmds_char_rate = clock;
>
> + /* TODO: also check drm_display_info.hdmi.scdc.scrambling.low_rates */
> + conn_state->hdmi.scrambler_needed = (clock > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ);
> +
[Severity: High]
Does this code allow an atomic_check to succeed even when the source or sink
does not actually support scrambling?
In the KMS atomic framework, hardware capabilities must be validated during the
atomic_check phase to prevent failures during atomic_commit. Here, we set
scrambler_needed to true for clocks > 340 MHz, but we don't seem to verify if
the sink or the source hardware actually supports scrambling.
If a malformed EDID advertises a high TMDS clock but lacks SCDC scrambling
support, or if a driver supports high clocks but fails to implement the
scrambler hooks, the atomic check phase will pass. Later, when
drm_connector_hdmi_enable_scrambling() is called during the commit phase, it
will evaluate scrambler_needed and return -EINVAL.
Failing during the atomic commit phase violates KMS rules and results in a
broken display pipeline. Should hdmi_compute_clock() or hdmi_clock_valid()
also verify drm_scdc_sink_supports_scrambling() and
drm_connector_hdmi_scrambler_supported() before succeeding?
> return 0;
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260731-dw-hdmi-qp-scramb-v10-0-294364b2cf15@collabora.com?part=23
^ permalink raw reply [flat|nested] 155+ messages in thread
* [PATCH v10 24/69] drm/bridge: dw-hdmi-qp: Rate limit i2c read error messages
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Maud Spierings, Diederik de Haas
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>
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
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 cfd1b18c06e6..7475b6b71836 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.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 24/69] drm/bridge: dw-hdmi-qp: Rate limit i2c read error messages
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Maud Spierings, Diederik de Haas
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>
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
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 cfd1b18c06e6..7475b6b71836 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.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 25/69] drm/bridge: dw-hdmi-qp: Provide .{enable,disable}_hpd() PHY ops
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Maud Spierings, Diederik de Haas
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.
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
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 7475b6b71836..a0613f0d2ebc 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_get_output_bus_fmts = drm_atomic_helper_bridge_get_hdmi_output_bus_fmts,
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
@@ -1197,6 +1213,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.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 25/69] drm/bridge: dw-hdmi-qp: Provide .{enable,disable}_hpd() PHY ops
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Maud Spierings, Diederik de Haas
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.
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
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 7475b6b71836..a0613f0d2ebc 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_get_output_bus_fmts = drm_atomic_helper_bridge_get_hdmi_output_bus_fmts,
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
@@ -1197,6 +1213,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.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 26/69] drm/bridge: dw-hdmi-qp: Remove unused workqueue include and define
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
linux/workqueue.h is no longer needed, and SCRAMB_POLL_DELAY_MS is
unused.
Remove them.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 3 ---
1 file changed, 3 deletions(-)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
index a0613f0d2ebc..246c4161e627 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
@@ -15,7 +15,6 @@
#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>
@@ -38,8 +37,6 @@
#define DDC_CI_ADDR 0x37
#define DDC_SEGMENT_ADDR 0x30
-#define SCRAMB_POLL_DELAY_MS 3000
-
/*
* Unless otherwise noted, entries in this table are 100% optimization.
* Values can be obtained from dw_hdmi_qp_compute_n() but that function is
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 26/69] drm/bridge: dw-hdmi-qp: Remove unused workqueue include and define
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
linux/workqueue.h is no longer needed, and SCRAMB_POLL_DELAY_MS is
unused.
Remove them.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 3 ---
1 file changed, 3 deletions(-)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
index a0613f0d2ebc..246c4161e627 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
@@ -15,7 +15,6 @@
#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>
@@ -38,8 +37,6 @@
#define DDC_CI_ADDR 0x37
#define DDC_SEGMENT_ADDR 0x30
-#define SCRAMB_POLL_DELAY_MS 3000
-
/*
* Unless otherwise noted, entries in this table are 100% optimization.
* Values can be obtained from dw_hdmi_qp_compute_n() but that function is
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 27/69] drm/bridge: dw-hdmi-qp: Add HDMI 2.0 scrambling support
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Maud Spierings, Diederik de Haas
Add support for SCDC scrambling and the high TMDS clock ratio required
by HDMI 2.0 modes with TMDS character rates above 340 MHz, such as
4K@60Hz.
Hook the bridge into the DRM HDMI connector scrambling helpers so the
sink-side SCDC state and the controller scrambler are updated together
as part of the atomic enable and disable paths. This allows the driver
to advertise HDMI 2.0 support when HPD is available.
Keep no-HPD configurations limited to HDMI 1.4, since SCDC access
requires a connected HDMI sink.
Modes above the HDMI 2.0 600 MHz TMDS character-rate limit are now
implicitly rejected by the DRM HDMI connector/bridge infrastructure,
making the dw_hdmi_qp_bridge_tmds_char_rate_valid() callback redundant.
Drop it.
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
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 | 60 ++++++++++++++++++----------
1 file changed, 39 insertions(+), 21 deletions(-)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
index 246c4161e627..ee74266b7aa9 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>
@@ -751,6 +752,7 @@ static void dw_hdmi_qp_bridge_atomic_enable(struct drm_bridge *bridge,
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))
@@ -761,14 +763,20 @@ static void dw_hdmi_qp_bridge_atomic_enable(struct drm_bridge *bridge,
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);
op_mode = 0;
hdmi->tmds_char_rate = conn_state->hdmi.tmds_char_rate;
+
+ ret = drm_connector_hdmi_enable_scrambling(connector, conn_state);
+ if (ret)
+ dev_warn(hdmi->dev, "Failed to enable scrambling: %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,
+ connector->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);
@@ -783,9 +791,13 @@ static void dw_hdmi_qp_bridge_atomic_disable(struct drm_bridge *bridge,
struct drm_atomic_commit *state)
{
struct dw_hdmi_qp *hdmi = bridge->driver_private;
+ struct drm_connector *connector;
hdmi->tmds_char_rate = 0;
+ connector = drm_atomic_get_old_connector_for_encoder(state, bridge->encoder);
+ drm_connector_hdmi_disable_scrambling(connector);
+
hdmi->phy.ops->disable(hdmi, hdmi->phy.data);
}
@@ -820,24 +832,24 @@ dw_hdmi_qp_bridge_edid_read(struct drm_bridge *bridge,
return drm_edid;
}
-static enum drm_mode_status
-dw_hdmi_qp_bridge_tmds_char_rate_valid(const struct drm_bridge *bridge,
- const struct drm_display_mode *mode,
- unsigned long long rate)
+static int dw_hdmi_qp_bridge_scrambler_enable(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) {
- dev_dbg(hdmi->dev, "Unsupported TMDS char rate: %lld\n", rate);
- return MODE_CLOCK_HIGH;
- }
+ dw_hdmi_qp_write(hdmi, 1, SCRAMB_CONFIG0);
+ dev_dbg(hdmi->dev, "scrambler enabled\n");
- return MODE_OK;
+ 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)
@@ -1213,7 +1225,8 @@ static const struct drm_bridge_funcs dw_hdmi_qp_bridge_funcs = {
.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_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,
@@ -1341,13 +1354,18 @@ struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev,
DRM_BRIDGE_OP_HDMI_AUDIO |
DRM_BRIDGE_OP_HDMI_HDR_DRM_INFOFRAME |
DRM_BRIDGE_OP_HDMI_SPD_INFOFRAME;
- if (!hdmi->no_hpd)
- hdmi->bridge.ops |= DRM_BRIDGE_OP_HPD;
hdmi->bridge.of_node = pdev->dev.of_node;
hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
hdmi->bridge.vendor = "Synopsys";
hdmi->bridge.product = "DW HDMI QP TX";
+ if (hdmi->no_hpd) {
+ hdmi->bridge.supported_hdmi_ver = HDMI_VERSION_1_4;
+ } else {
+ hdmi->bridge.supported_hdmi_ver = HDMI_VERSION_2_0;
+ hdmi->bridge.ops |= DRM_BRIDGE_OP_HPD;
+ }
+
if (plat_data->supported_formats)
hdmi->bridge.supported_formats = plat_data->supported_formats;
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 27/69] drm/bridge: dw-hdmi-qp: Add HDMI 2.0 scrambling support
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Maud Spierings, Diederik de Haas
Add support for SCDC scrambling and the high TMDS clock ratio required
by HDMI 2.0 modes with TMDS character rates above 340 MHz, such as
4K@60Hz.
Hook the bridge into the DRM HDMI connector scrambling helpers so the
sink-side SCDC state and the controller scrambler are updated together
as part of the atomic enable and disable paths. This allows the driver
to advertise HDMI 2.0 support when HPD is available.
Keep no-HPD configurations limited to HDMI 1.4, since SCDC access
requires a connected HDMI sink.
Modes above the HDMI 2.0 600 MHz TMDS character-rate limit are now
implicitly rejected by the DRM HDMI connector/bridge infrastructure,
making the dw_hdmi_qp_bridge_tmds_char_rate_valid() callback redundant.
Drop it.
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
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 | 60 ++++++++++++++++++----------
1 file changed, 39 insertions(+), 21 deletions(-)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
index 246c4161e627..ee74266b7aa9 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>
@@ -751,6 +752,7 @@ static void dw_hdmi_qp_bridge_atomic_enable(struct drm_bridge *bridge,
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))
@@ -761,14 +763,20 @@ static void dw_hdmi_qp_bridge_atomic_enable(struct drm_bridge *bridge,
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);
op_mode = 0;
hdmi->tmds_char_rate = conn_state->hdmi.tmds_char_rate;
+
+ ret = drm_connector_hdmi_enable_scrambling(connector, conn_state);
+ if (ret)
+ dev_warn(hdmi->dev, "Failed to enable scrambling: %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,
+ connector->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);
@@ -783,9 +791,13 @@ static void dw_hdmi_qp_bridge_atomic_disable(struct drm_bridge *bridge,
struct drm_atomic_commit *state)
{
struct dw_hdmi_qp *hdmi = bridge->driver_private;
+ struct drm_connector *connector;
hdmi->tmds_char_rate = 0;
+ connector = drm_atomic_get_old_connector_for_encoder(state, bridge->encoder);
+ drm_connector_hdmi_disable_scrambling(connector);
+
hdmi->phy.ops->disable(hdmi, hdmi->phy.data);
}
@@ -820,24 +832,24 @@ dw_hdmi_qp_bridge_edid_read(struct drm_bridge *bridge,
return drm_edid;
}
-static enum drm_mode_status
-dw_hdmi_qp_bridge_tmds_char_rate_valid(const struct drm_bridge *bridge,
- const struct drm_display_mode *mode,
- unsigned long long rate)
+static int dw_hdmi_qp_bridge_scrambler_enable(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) {
- dev_dbg(hdmi->dev, "Unsupported TMDS char rate: %lld\n", rate);
- return MODE_CLOCK_HIGH;
- }
+ dw_hdmi_qp_write(hdmi, 1, SCRAMB_CONFIG0);
+ dev_dbg(hdmi->dev, "scrambler enabled\n");
- return MODE_OK;
+ 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)
@@ -1213,7 +1225,8 @@ static const struct drm_bridge_funcs dw_hdmi_qp_bridge_funcs = {
.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_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,
@@ -1341,13 +1354,18 @@ struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev,
DRM_BRIDGE_OP_HDMI_AUDIO |
DRM_BRIDGE_OP_HDMI_HDR_DRM_INFOFRAME |
DRM_BRIDGE_OP_HDMI_SPD_INFOFRAME;
- if (!hdmi->no_hpd)
- hdmi->bridge.ops |= DRM_BRIDGE_OP_HPD;
hdmi->bridge.of_node = pdev->dev.of_node;
hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
hdmi->bridge.vendor = "Synopsys";
hdmi->bridge.product = "DW HDMI QP TX";
+ if (hdmi->no_hpd) {
+ hdmi->bridge.supported_hdmi_ver = HDMI_VERSION_1_4;
+ } else {
+ hdmi->bridge.supported_hdmi_ver = HDMI_VERSION_2_0;
+ hdmi->bridge.ops |= DRM_BRIDGE_OP_HPD;
+ }
+
if (plat_data->supported_formats)
hdmi->bridge.supported_formats = plat_data->supported_formats;
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 28/69] drm/bridge: dw-hdmi-qp: Provide dw_hdmi_qp_hpd_notify() helper
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Maud Spierings, Diederik de Haas
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.
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 37 ++++++++++++++++++++++++++++
include/drm/bridge/dw_hdmi_qp.h | 1 +
2 files changed, 38 insertions(+)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
index ee74266b7aa9..a2277531182c 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
@@ -28,6 +28,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>
@@ -163,6 +164,8 @@ struct dw_hdmi_qp {
struct regmap *regm;
int main_irq;
+ /* Written by the atomic enable/disable hooks, read locklessly by HPD */
+ struct drm_connector *curr_conn;
unsigned long tmds_char_rate;
bool no_hpd;
};
@@ -785,6 +788,8 @@ static void dw_hdmi_qp_bridge_atomic_enable(struct drm_bridge *bridge,
dw_hdmi_qp_mod(hdmi, op_mode, OPMODE_DVI, LINK_CONFIG0);
drm_atomic_helper_connector_hdmi_update_infoframes(connector, state);
+
+ WRITE_ONCE(hdmi->curr_conn, connector);
}
static void dw_hdmi_qp_bridge_atomic_disable(struct drm_bridge *bridge,
@@ -793,6 +798,7 @@ static void dw_hdmi_qp_bridge_atomic_disable(struct drm_bridge *bridge,
struct dw_hdmi_qp *hdmi = bridge->driver_private;
struct drm_connector *connector;
+ WRITE_ONCE(hdmi->curr_conn, NULL);
hdmi->tmds_char_rate = 0;
connector = drm_atomic_get_old_connector_for_encoder(state, bridge->encoder);
@@ -1409,6 +1415,37 @@ 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)
+{
+ struct drm_connector *conn = READ_ONCE(hdmi->curr_conn);
+ 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 (conn && status == connector_status_connected)
+ drm_connector_helper_hpd_irq_event(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.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 28/69] drm/bridge: dw-hdmi-qp: Provide dw_hdmi_qp_hpd_notify() helper
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Maud Spierings, Diederik de Haas
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.
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 37 ++++++++++++++++++++++++++++
include/drm/bridge/dw_hdmi_qp.h | 1 +
2 files changed, 38 insertions(+)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
index ee74266b7aa9..a2277531182c 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
@@ -28,6 +28,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>
@@ -163,6 +164,8 @@ struct dw_hdmi_qp {
struct regmap *regm;
int main_irq;
+ /* Written by the atomic enable/disable hooks, read locklessly by HPD */
+ struct drm_connector *curr_conn;
unsigned long tmds_char_rate;
bool no_hpd;
};
@@ -785,6 +788,8 @@ static void dw_hdmi_qp_bridge_atomic_enable(struct drm_bridge *bridge,
dw_hdmi_qp_mod(hdmi, op_mode, OPMODE_DVI, LINK_CONFIG0);
drm_atomic_helper_connector_hdmi_update_infoframes(connector, state);
+
+ WRITE_ONCE(hdmi->curr_conn, connector);
}
static void dw_hdmi_qp_bridge_atomic_disable(struct drm_bridge *bridge,
@@ -793,6 +798,7 @@ static void dw_hdmi_qp_bridge_atomic_disable(struct drm_bridge *bridge,
struct dw_hdmi_qp *hdmi = bridge->driver_private;
struct drm_connector *connector;
+ WRITE_ONCE(hdmi->curr_conn, NULL);
hdmi->tmds_char_rate = 0;
connector = drm_atomic_get_old_connector_for_encoder(state, bridge->encoder);
@@ -1409,6 +1415,37 @@ 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)
+{
+ struct drm_connector *conn = READ_ONCE(hdmi->curr_conn);
+ 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 (conn && status == connector_status_connected)
+ drm_connector_helper_hpd_irq_event(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.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 29/69] drm/rockchip: dw_hdmi_qp: Fix invalid drvdata access in PM ops
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Sashiko
The system-sleep PM callbacks fetch the driver state via
dev_get_drvdata() and dereference it unconditionally. However, the
platform device is bound by ->probe(), which merely registers a
component, hence the callbacks may well run when no valid state is
available:
- Before the aggregate driver calls ->bind(), e.g. when the system
suspends while probing is still deferred waiting for the VOP,
dev_get_drvdata() returns NULL.
- After ->unbind(), or when ->bind() fails past platform_set_drvdata(),
drvdata is left pointing to memory obtained via drmm_kzalloc(), which
is released together with the DRM device, while this platform device
remains bound and PM-capable.
Publish the driver data only after ->bind() completes successfully, and
clear it in ->unbind(). This ensures that a non-NULL drvdata always
represents live state, allowing each PM callback to rely on a single
NULL check.
Fixes: 128a9bf8ace2 ("drm/rockchip: Add basic RK3588 HDMI output support")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://lore.kernel.org/all/20260702151550.8E14D1F000E9@smtp.kernel.org/
Closes: https://lore.kernel.org/all/20260723014811.1F9F01F000E9@smtp.kernel.org/
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index 9c4cf68d79d5..646a4cb96830 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -683,8 +683,6 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
if (ret)
return dev_err_probe(hdmi->dev, ret, "Failed to init encoder");
- 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),
@@ -695,6 +693,8 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
return dev_err_probe(hdmi->dev, PTR_ERR(connector),
"Failed to init bridge connector\n");
+ platform_set_drvdata(pdev, hdmi);
+
return 0;
}
@@ -704,6 +704,8 @@ static void dw_hdmi_qp_rockchip_unbind(struct device *dev,
{
struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev);
+ dev_set_drvdata(dev, NULL);
+
cancel_delayed_work_sync(&hdmi->hpd_work);
}
@@ -726,7 +728,8 @@ static int __maybe_unused dw_hdmi_qp_rockchip_suspend(struct device *dev)
{
struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev);
- dw_hdmi_qp_suspend(dev, hdmi->hdmi);
+ if (hdmi)
+ dw_hdmi_qp_suspend(dev, hdmi->hdmi);
return 0;
}
@@ -735,6 +738,9 @@ static int __maybe_unused dw_hdmi_qp_rockchip_resume(struct device *dev)
{
struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev);
+ if (!hdmi)
+ return 0;
+
hdmi->ctrl_ops->io_init(hdmi);
dw_hdmi_qp_resume(dev, hdmi->hdmi);
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 29/69] drm/rockchip: dw_hdmi_qp: Fix invalid drvdata access in PM ops
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Sashiko
The system-sleep PM callbacks fetch the driver state via
dev_get_drvdata() and dereference it unconditionally. However, the
platform device is bound by ->probe(), which merely registers a
component, hence the callbacks may well run when no valid state is
available:
- Before the aggregate driver calls ->bind(), e.g. when the system
suspends while probing is still deferred waiting for the VOP,
dev_get_drvdata() returns NULL.
- After ->unbind(), or when ->bind() fails past platform_set_drvdata(),
drvdata is left pointing to memory obtained via drmm_kzalloc(), which
is released together with the DRM device, while this platform device
remains bound and PM-capable.
Publish the driver data only after ->bind() completes successfully, and
clear it in ->unbind(). This ensures that a non-NULL drvdata always
represents live state, allowing each PM callback to rely on a single
NULL check.
Fixes: 128a9bf8ace2 ("drm/rockchip: Add basic RK3588 HDMI output support")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://lore.kernel.org/all/20260702151550.8E14D1F000E9@smtp.kernel.org/
Closes: https://lore.kernel.org/all/20260723014811.1F9F01F000E9@smtp.kernel.org/
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index 9c4cf68d79d5..646a4cb96830 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -683,8 +683,6 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
if (ret)
return dev_err_probe(hdmi->dev, ret, "Failed to init encoder");
- 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),
@@ -695,6 +693,8 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
return dev_err_probe(hdmi->dev, PTR_ERR(connector),
"Failed to init bridge connector\n");
+ platform_set_drvdata(pdev, hdmi);
+
return 0;
}
@@ -704,6 +704,8 @@ static void dw_hdmi_qp_rockchip_unbind(struct device *dev,
{
struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev);
+ dev_set_drvdata(dev, NULL);
+
cancel_delayed_work_sync(&hdmi->hpd_work);
}
@@ -726,7 +728,8 @@ static int __maybe_unused dw_hdmi_qp_rockchip_suspend(struct device *dev)
{
struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev);
- dw_hdmi_qp_suspend(dev, hdmi->hdmi);
+ if (hdmi)
+ dw_hdmi_qp_suspend(dev, hdmi->hdmi);
return 0;
}
@@ -735,6 +738,9 @@ static int __maybe_unused dw_hdmi_qp_rockchip_resume(struct device *dev)
{
struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev);
+ if (!hdmi)
+ return 0;
+
hdmi->ctrl_ops->io_init(hdmi);
dw_hdmi_qp_resume(dev, hdmi->hdmi);
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread* Re: [PATCH v10 29/69] drm/rockchip: dw_hdmi_qp: Fix invalid drvdata access in PM ops
2026-07-31 16:19 ` Cristian Ciocaltea
(?)
@ 2026-07-31 20:19 ` sashiko-bot
-1 siblings, 0 replies; 155+ messages in thread
From: sashiko-bot @ 2026-07-31 20:19 UTC (permalink / raw)
To: Cristian Ciocaltea; +Cc: linux-sunxi, dri-devel
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Pre-existing issues:
- [High] Use-After-Free of `hdmi` struct due to `devm_request_threaded_irq` being used in component bind, leaking the IRQ on unbind.
- [High] The HPD hardirq handler checks the raw SOC status register instead of the interrupt pending status, breaking unplug detection and stealing shared IRQs.
--
--- Patch [29]: [PATCH v10 29/69] drm/rockchip: dw_hdmi_qp: Fix invalid drvdata access in PM ops ---
commit fc12a8c8d5e7177cf76cf4554fb62df0ebde5bbd
Author: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
drm/rockchip: dw_hdmi_qp: Fix invalid drvdata access in PM ops
The system-sleep PM callbacks fetch the driver state via dev_get_drvdata()
and dereference it unconditionally. This patch ensures non-NULL drvdata
always represents live state, allowing each PM callback to rely on a single
NULL check.
Closes: https://lore.kernel.org/all/20260702151550.8E14D1F000E9@smtp.kernel.org/
Closes: https://lore.kernel.org/all/20260723014811.1F9F01F000E9@smtp.kernel.org/
> diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
> index 9c4cf68d79d50..646a4cb968309 100644
> --- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
> +++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
[ ... ]
> @@ -704,6 +704,8 @@ static void dw_hdmi_qp_rockchip_unbind(struct device *dev,
> {
> struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev);
>
> + dev_set_drvdata(dev, NULL);
> +
> cancel_delayed_work_sync(&hdmi->hpd_work);
[Severity: High]
This isn't a bug introduced by this patch, but is it safe to rely on
devm_request_threaded_irq() for the HPD interrupt when lifecycle is managed
via component bind and unbind?
Looking at dw_hdmi_qp_rockchip_bind(), the IRQ is requested with devm on the
component device:
ret = devm_request_threaded_irq(dev, hdmi->hpd_irq, ...);
Because devm resources are tied to the device's probe and remove lifecycle,
the IRQ is not freed when the component is unbound. When the aggregate DRM
device is torn down, hdmi (allocated via drmm_kzalloc) is freed.
If the HPD interrupt fires afterwards, the still-active IRQ handler will
dereference the freed hdmi pointer.
Also, calling cancel_delayed_work_sync() here doesn't prevent the active IRQ
handler from immediately re-arming the workqueue.
Should this use a non-devm request_threaded_irq() in dw_hdmi_qp_rockchip_bind()
and call free_irq() here in dw_hdmi_qp_rockchip_unbind()?
[Severity: High]
This is also a pre-existing issue, but does the hardirq handler properly handle
interrupts on unplug events?
Looking at dw_hdmi_qp_rk3588_hardirq() and dw_hdmi_qp_rk3576_hardirq(), they
read the raw level register without masking:
regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &intr_stat);
if (intr_stat) {
...
When the HDMI cable is unplugged, the HPD level goes to 0, which triggers the
interrupt. If no other unrelated bits in this 32-bit register are set,
intr_stat evaluates to 0 and the handler returns IRQ_NONE without clearing the
interrupt.
Could this cause the kernel to see an unhandled interrupt and disable it
permanently?
Conversely, if any unrelated bit is 1, it will always return IRQ_WAKE_THREAD,
falsely claiming interrupts for other devices on this shared IRQ line.
Should this check the interrupt pending status instead of the raw SOC status
register?
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260731-dw-hdmi-qp-scramb-v10-0-294364b2cf15@collabora.com?part=29
^ permalink raw reply [flat|nested] 155+ messages in thread
* [PATCH v10 30/69] drm/rockchip: dw_hdmi_qp: Cancel pending HPD work on suspend
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Sashiko
The HPD threaded handler debounces hotplug events by delaying
hdmi->hpd_work for 150 ms. Nothing discards that work when the system
goes to sleep: drm_kms_helper_poll_disable() only disables the HPD IRQ
line via the bridge .hpd_disable() op, and disable_irq() merely waits
for the threaded handler, which has already returned after arming the
timer.
If the debounce expires during suspend, its non-freezable work may probe
the connector and read the EDID over DDC. Since genpd powers off the
HDMI controller's power domain in ->suspend_noirq(), this access may
hit unpowered hardware and hang the system.
Cancel the work in the suspend callback. The DRM device is registered
as a consumer of the HDMI device, so it always suspends first and the
HPD IRQ is already disabled by that point, meaning nothing can re-arm
the work behind our back. No counterpart is needed on resume, as the
work gets scheduled again on the next hotplug interrupt.
Fixes: 128a9bf8ace2 ("drm/rockchip: Add basic RK3588 HDMI output support")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://lore.kernel.org/all/20260723015909.7F79A1F000E9@smtp.kernel.org/
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 8 ++++++--
1 file changed, 6 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 646a4cb96830..e9fda67b8ca9 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -728,8 +728,12 @@ static int __maybe_unused dw_hdmi_qp_rockchip_suspend(struct device *dev)
{
struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev);
- if (hdmi)
- dw_hdmi_qp_suspend(dev, hdmi->hdmi);
+ if (!hdmi)
+ return 0;
+
+ dw_hdmi_qp_suspend(dev, hdmi->hdmi);
+
+ cancel_delayed_work_sync(&hdmi->hpd_work);
return 0;
}
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 30/69] drm/rockchip: dw_hdmi_qp: Cancel pending HPD work on suspend
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Sashiko
The HPD threaded handler debounces hotplug events by delaying
hdmi->hpd_work for 150 ms. Nothing discards that work when the system
goes to sleep: drm_kms_helper_poll_disable() only disables the HPD IRQ
line via the bridge .hpd_disable() op, and disable_irq() merely waits
for the threaded handler, which has already returned after arming the
timer.
If the debounce expires during suspend, its non-freezable work may probe
the connector and read the EDID over DDC. Since genpd powers off the
HDMI controller's power domain in ->suspend_noirq(), this access may
hit unpowered hardware and hang the system.
Cancel the work in the suspend callback. The DRM device is registered
as a consumer of the HDMI device, so it always suspends first and the
HPD IRQ is already disabled by that point, meaning nothing can re-arm
the work behind our back. No counterpart is needed on resume, as the
work gets scheduled again on the next hotplug interrupt.
Fixes: 128a9bf8ace2 ("drm/rockchip: Add basic RK3588 HDMI output support")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://lore.kernel.org/all/20260723015909.7F79A1F000E9@smtp.kernel.org/
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 8 ++++++--
1 file changed, 6 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 646a4cb96830..e9fda67b8ca9 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -728,8 +728,12 @@ static int __maybe_unused dw_hdmi_qp_rockchip_suspend(struct device *dev)
{
struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev);
- if (hdmi)
- dw_hdmi_qp_suspend(dev, hdmi->hdmi);
+ if (!hdmi)
+ return 0;
+
+ dw_hdmi_qp_suspend(dev, hdmi->hdmi);
+
+ cancel_delayed_work_sync(&hdmi->hpd_work);
return 0;
}
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread* Re: [PATCH v10 30/69] drm/rockchip: dw_hdmi_qp: Cancel pending HPD work on suspend
2026-07-31 16:19 ` Cristian Ciocaltea
(?)
@ 2026-07-31 20:30 ` sashiko-bot
-1 siblings, 0 replies; 155+ messages in thread
From: sashiko-bot @ 2026-07-31 20:30 UTC (permalink / raw)
To: Cristian Ciocaltea; +Cc: dri-devel, linux-sunxi
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
New issues:
- [High] Deadlock during suspend: disabling the main IRQ before cancelling the HPD work causes I2C timeouts.
Pre-existing issues:
- [High] Incomplete fix: HPD IRQ is not actually disabled, allowing delayed work to be re-armed during suspend.
- [High] Use-After-Free of `hdmi` due to devres/drmm mismatch on component unbind.
--
--- Patch [30]: [PATCH v10 30/69] drm/rockchip: dw_hdmi_qp: Cancel pending HPD work on suspend ---
commit 9b084d07cd142a4d5581877b274f1d064cd6ebd9
Author: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
drm/rockchip: dw_hdmi_qp: Cancel pending HPD work on suspend
This commit cancels the pending HPD work during the suspend callback.
The intent is to prevent the work from probing the connector and reading
the EDID after the HDMI controller's power domain has been powered off.
Closes: https://lore.kernel.org/all/20260723015909.7F79A1F000E9@smtp.kernel.org/
> diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
> index 646a4cb968309..e9fda67b8ca94 100644
> --- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
> +++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
> @@ -728,8 +728,12 @@ static int __maybe_unused dw_hdmi_qp_rockchip_suspend(struct device *dev)
> {
> struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev);
>
> - if (hdmi)
> - dw_hdmi_qp_suspend(dev, hdmi->hdmi);
> + if (!hdmi)
> + return 0;
> +
> + dw_hdmi_qp_suspend(dev, hdmi->hdmi);
> +
> + cancel_delayed_work_sync(&hdmi->hpd_work);
[Severity: High]
Does this code cause a deadlock during suspend if the HPD work is actively
running?
Because dw_hdmi_qp_suspend() is called first, it explicitly disables the
main IRQ.
If the HPD work is running and reads the EDID over DDC, the read relies on
dw_hdmi_qp_i2c_read(), which waits for a completion signaled by the main IRQ
handler.
Since the main IRQ is already disabled, will the I2C transfers time out
repeatedly, stalling cancel_delayed_work_sync() and completely hanging the
suspend process?
[Severity: High]
This isn't a bug introduced by this patch, but does this actually prevent the
work from running on unpowered hardware?
The commit message assumes drm_kms_helper_poll_disable() disables the HPD IRQ
via the bridge .hpd_disable() op.
However, rk3588_hdmi_phy_ops does not implement .disable_hpd:
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,
};
This makes the DRM core's attempt to mask the IRQ a no-op, and the separate
HPD IRQ requested in dw_hdmi_qp_rockchip_bind() remains unmasked.
If a hotplug event occurs after cancel_delayed_work_sync() returns, but
before suspend_noirq disables all IRQs, will the handler fire and re-arm the
work on system_percpu_wq?
Since this workqueue is not freezable, could the work still execute after the
power domain is off?
[Severity: High]
This is a pre-existing issue, but does the component unbind path have a
use-after-free issue?
In dw_hdmi_qp_rockchip_bind(), the hdmi context is tied to the DRM device's
lifetime:
hdmi = drmm_kzalloc(drm, sizeof(*hdmi), GFP_KERNEL);
However, the HPD IRQ is tied to the platform device's lifetime:
ret = devm_request_threaded_irq(hdmi->dev, irq,
cfg->ctrl_ops->hardirq_callback,
cfg->ctrl_ops->irq_callback,
IRQF_SHARED, "dw-hdmi-qp-hpd",
hdmi);
When the component is unbound (e.g., driver removal or DRM teardown), the
DRM device frees all drmm memory, including the hdmi structure.
Because the platform device itself isn't removed, its devm resources are not
released, leaving the IRQ active.
If an HPD interrupt fires subsequently, will the handler dereference the
freed hdmi pointer?
>
> return 0;
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260731-dw-hdmi-qp-scramb-v10-0-294364b2cf15@collabora.com?part=30
^ permalink raw reply [flat|nested] 155+ messages in thread
* [PATCH v10 31/69] drm/rockchip: dw_hdmi_qp: Add missing newlines in dev_err_probe() messages
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Maud Spierings, Diederik de Haas
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>
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
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 e9fda67b8ca9..8b48558deb3e 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -681,12 +681,12 @@ 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");
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.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 31/69] drm/rockchip: dw_hdmi_qp: Add missing newlines in dev_err_probe() messages
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Maud Spierings, Diederik de Haas
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>
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
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 e9fda67b8ca9..8b48558deb3e 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -681,12 +681,12 @@ 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");
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.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread* Re: [PATCH v10 31/69] drm/rockchip: dw_hdmi_qp: Add missing newlines in dev_err_probe() messages
2026-07-31 16:19 ` Cristian Ciocaltea
(?)
@ 2026-07-31 20:38 ` sashiko-bot
-1 siblings, 0 replies; 155+ messages in thread
From: sashiko-bot @ 2026-07-31 20:38 UTC (permalink / raw)
To: Cristian Ciocaltea; +Cc: linux-sunxi, dri-devel
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Pre-existing issues:
- [High] Using devm_ APIs on the component device in the bind callback causes resource leaks and a use-after-free on unbind/rebind.
- [High] The dw_hdmi_qp library lacks an unbind function, causing permanent resource leaks when componentized drivers unbind.
--
--- Patch [31]: [PATCH v10 31/69] drm/rockchip: dw_hdmi_qp: Add missing newlines in dev_err_probe() messages ---
commit 5dd7ce4a56ed7d72cce118d1d9700cdba6b578d8
Author: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
drm/rockchip: dw_hdmi_qp: Add missing newlines in dev_err_probe() messages
This commit adds missing trailing newlines to a couple of dev_err_probe()
calls in dw_hdmi_qp_rockchip_bind().
> diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
> index e9fda67b8ca94..8b48558deb3e7 100644
> --- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
> +++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
> @@ -681,12 +681,12 @@ 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");
>
> hdmi->hdmi = dw_hdmi_qp_bind(pdev, encoder, &plat_data);
[Severity: High]
This isn't a bug introduced by this patch, but does dw_hdmi_qp_bind() leak
resources on component unbind?
dw_hdmi_qp_bind() allocates multiple devm_ resources on the component device
such as memory, regmaps, shared IRQs, and bridges. Since the dw_hdmi_qp
library lacks an unbind function, these resources are never freed when the
DRM device unbinds.
On rebind, new duplicate resources will be appended to the component device's
devres list, leading to unbounded memory growth and multiple shared IRQ
handlers firing concurrently.
[Severity: High]
This is a pre-existing issue, but does mixing drmm_ and devm_ allocations in
this component bind callback create a lifecycle mismatch?
Earlier in this function, the hdmi structure is allocated with
drmm_kzalloc(), but devm_request_threaded_irq() is called on the component
dev (which hasn't unbound).
When the user unbinds the main DRM device via sysfs, component unbind
destroys the DRM device and frees the hdmi structure. However, the IRQ
remains registered on the component device. If an interrupt fires, the
handler will access the freed hdmi pointer.
Additionally, dw_hdmi_qp_rockchip_unbind() only calls
cancel_delayed_work_sync(), leaving devm_ resources accumulated on rebind.
> 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))
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260731-dw-hdmi-qp-scramb-v10-0-294364b2cf15@collabora.com?part=31
^ permalink raw reply [flat|nested] 155+ messages in thread
* [PATCH v10 32/69] drm/rockchip: dw_hdmi_qp: Use local dev variable consistently in bind()
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Maud Spierings, Diederik de Haas
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>
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
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 8b48558deb3e..36043bf82273 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -563,7 +563,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);
@@ -583,7 +583,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 */
@@ -594,7 +594,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;
@@ -622,37 +622,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);
@@ -670,7 +669,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",
@@ -681,16 +680,16 @@ 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");
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");
platform_set_drvdata(pdev, hdmi);
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 32/69] drm/rockchip: dw_hdmi_qp: Use local dev variable consistently in bind()
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Maud Spierings, Diederik de Haas
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>
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
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 8b48558deb3e..36043bf82273 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -563,7 +563,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);
@@ -583,7 +583,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 */
@@ -594,7 +594,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;
@@ -622,37 +622,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);
@@ -670,7 +669,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",
@@ -681,16 +680,16 @@ 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");
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");
platform_set_drvdata(pdev, hdmi);
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* Re: [PATCH v10 32/69] drm/rockchip: dw_hdmi_qp: Use local dev variable consistently in bind()
2026-07-31 16:19 ` Cristian Ciocaltea
(?)
@ 2026-07-31 20:47 ` sashiko-bot
-1 siblings, 0 replies; 155+ messages in thread
From: sashiko-bot @ 2026-07-31 20:47 UTC (permalink / raw)
To: Cristian Ciocaltea; +Cc: dri-devel, linux-sunxi
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
Pre-existing issues:
- [High] Use-After-Free and resource leaks due to devm_ allocations in component bind callback.
- [High] Pending delayed work is not canceled on error paths, leading to Use-After-Free.
- [High] Missing cleanup for dw_hdmi_qp_bind() on the error path leads to resource and bridge leaks.
--
--- Patch [32]: [PATCH v10 32/69] drm/rockchip: dw_hdmi_qp: Use local dev variable consistently in bind() ---
commit 43fdb5eca012528d707389ce53b62eb4132b9532
Author: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
drm/rockchip: dw_hdmi_qp: Use local dev variable consistently in bind()
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.
> diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
> index 8b48558deb3e7..36043bf82273c 100644
> --- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
> +++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
[ ... ]
> @@ -670,7 +669,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",
> hdmi);
[Severity: High]
This isn't a bug introduced by this patch, but does the use of devm_ here
cause a use-after-free and resource leak on component unbind?
The hdmi context is allocated via drmm_kzalloc, tying its lifetime to the
DRM master device. However, devm_request_threaded_irq ties the HPD IRQ
handler to the platform device's lifecycle, not the component bind/unbind
lifecycle.
If the component is unbound (e.g. the DRM master is removed), drmm will free
the hdmi context, but the IRQ remains active. A subsequent HPD interrupt
will trigger the handler, which dereferences the freed hdmi pointer. Also,
every bind retry leaks devm resources like clocks and GPIOs since they
aren't tied to the bind lifecycle.
> if (ret)
> return ret;
>
> 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");
[Severity: High]
This is a pre-existing issue, but does this error path lead to a
use-after-free?
The HPD IRQ is requested earlier and can fire immediately, scheduling
hdmi->hpd_work. If drmm_encoder_init() fails here, we return directly
without calling cancel_delayed_work_sync().
The DRM core handles the component bind failure by tearing down the DRM
device, causing drmm to free the hdmi structure. The pending delayed work
will then execute and dereference the freed hdmi pointer.
>
> 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");
[Severity: High]
This isn't a bug introduced by this patch, but does this error path
permanently leak devm-managed bridges?
dw_hdmi_qp_bind() allocates state and registers a DRM bridge using devm_
functions tied to the platform device. If drm_bridge_connector_init() fails,
we return directly without calling dw_hdmi_qp_unbind() or cleaning up the
bridge.
Because the resources are managed by devm_ tied to the platform device, they
won't be freed when the component bind fails. Every retry of the component
bind will allocate new memory and register duplicate DRM bridges in the
global list.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260731-dw-hdmi-qp-scramb-v10-0-294364b2cf15@collabora.com?part=32
^ permalink raw reply [flat|nested] 155+ messages in thread
* [PATCH v10 33/69] drm/rockchip: dw_hdmi_qp: Avoid spurious HPD IRQ thread wakeups
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Sashiko, Diederik de Haas
The RK3576 and RK3588 HPD hardirq handlers read shared status registers
and currently wake the threaded handler whenever any bit in those
registers is set. This can wake the HDMI IRQ thread for unrelated
status bits, and on RK3588 can also wake the thread for the other HDMI
port.
Mask the status value with the SoC-specific HPD interrupt bit before
deciding whether to wake the threaded handler. On RK3588, select the
HDMI0 or HDMI1 HPD bit according to the instance port id.
No stable backport is needed. The issue may only cause spurious IRQ
thread wakeups and does not cause functional breakage.
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://lore.kernel.org/all/20260702151346.5A4EC1F000E9@smtp.kernel.org/
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 7 ++++++-
1 file changed, 6 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 36043bf82273..f5342c5f457b 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -34,6 +34,7 @@
#define RK3576_IOC_HDMI_HPD_STATUS 0xa440
#define RK3576_HDMI_LEVEL_INT BIT(3)
+#define RK3576_HDMI_OHPD_INT BIT(4)
#define RK3576_VO0_GRF_SOC_CON1 0x0004
#define RK3576_HDMI_FRL_MOD BIT(0)
@@ -64,7 +65,9 @@
#define RK3588_HPD_HDMI1_IO_EN_MASK BIT(13)
#define RK3588_GRF_SOC_STATUS1 0x0384
#define RK3588_HDMI0_LEVEL_INT BIT(16)
+#define RK3588_HDMI0_OHPD_INT BIT(17)
#define RK3588_HDMI1_LEVEL_INT BIT(24)
+#define RK3588_HDMI1_OHPD_INT BIT(25)
#define RK3588_GRF_VO1_CON3 0x000c
#define RK3588_GRF_VO1_CON6 0x0018
#define RK3588_COLOR_DEPTH_MASK GENMASK(7, 4)
@@ -348,7 +351,7 @@ static irqreturn_t dw_hdmi_qp_rk3576_hardirq(int irq, void *dev_id)
u32 intr_stat, val;
regmap_read(hdmi->regmap, RK3576_IOC_HDMI_HPD_STATUS, &intr_stat);
- if (intr_stat) {
+ if (intr_stat & RK3576_HDMI_OHPD_INT) {
val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 1);
regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
@@ -381,6 +384,8 @@ static irqreturn_t dw_hdmi_qp_rk3588_hardirq(int irq, void *dev_id)
regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &intr_stat);
+ intr_stat &= hdmi->port_id ? RK3588_HDMI1_OHPD_INT : RK3588_HDMI0_OHPD_INT;
+
if (intr_stat) {
if (hdmi->port_id)
val = FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_MSK, 1);
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 33/69] drm/rockchip: dw_hdmi_qp: Avoid spurious HPD IRQ thread wakeups
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Sashiko, Diederik de Haas
The RK3576 and RK3588 HPD hardirq handlers read shared status registers
and currently wake the threaded handler whenever any bit in those
registers is set. This can wake the HDMI IRQ thread for unrelated
status bits, and on RK3588 can also wake the thread for the other HDMI
port.
Mask the status value with the SoC-specific HPD interrupt bit before
deciding whether to wake the threaded handler. On RK3588, select the
HDMI0 or HDMI1 HPD bit according to the instance port id.
No stable backport is needed. The issue may only cause spurious IRQ
thread wakeups and does not cause functional breakage.
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://lore.kernel.org/all/20260702151346.5A4EC1F000E9@smtp.kernel.org/
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 7 ++++++-
1 file changed, 6 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 36043bf82273..f5342c5f457b 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -34,6 +34,7 @@
#define RK3576_IOC_HDMI_HPD_STATUS 0xa440
#define RK3576_HDMI_LEVEL_INT BIT(3)
+#define RK3576_HDMI_OHPD_INT BIT(4)
#define RK3576_VO0_GRF_SOC_CON1 0x0004
#define RK3576_HDMI_FRL_MOD BIT(0)
@@ -64,7 +65,9 @@
#define RK3588_HPD_HDMI1_IO_EN_MASK BIT(13)
#define RK3588_GRF_SOC_STATUS1 0x0384
#define RK3588_HDMI0_LEVEL_INT BIT(16)
+#define RK3588_HDMI0_OHPD_INT BIT(17)
#define RK3588_HDMI1_LEVEL_INT BIT(24)
+#define RK3588_HDMI1_OHPD_INT BIT(25)
#define RK3588_GRF_VO1_CON3 0x000c
#define RK3588_GRF_VO1_CON6 0x0018
#define RK3588_COLOR_DEPTH_MASK GENMASK(7, 4)
@@ -348,7 +351,7 @@ static irqreturn_t dw_hdmi_qp_rk3576_hardirq(int irq, void *dev_id)
u32 intr_stat, val;
regmap_read(hdmi->regmap, RK3576_IOC_HDMI_HPD_STATUS, &intr_stat);
- if (intr_stat) {
+ if (intr_stat & RK3576_HDMI_OHPD_INT) {
val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 1);
regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
@@ -381,6 +384,8 @@ static irqreturn_t dw_hdmi_qp_rk3588_hardirq(int irq, void *dev_id)
regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &intr_stat);
+ intr_stat &= hdmi->port_id ? RK3588_HDMI1_OHPD_INT : RK3588_HDMI0_OHPD_INT;
+
if (intr_stat) {
if (hdmi->port_id)
val = FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_MSK, 1);
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 34/69] drm/rockchip: dw_hdmi_qp: Mask RK3576 HPD IRQ in io_init
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
Start with HPD masked, matching RK3588, so the bridge framework controls
when interrupts are armed via hpd_enable().
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 f5342c5f457b..64e8e4c12cbd 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -432,7 +432,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.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 34/69] drm/rockchip: dw_hdmi_qp: Mask RK3576 HPD IRQ in io_init
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
Start with HPD masked, matching RK3588, so the bridge framework controls
when interrupts are armed via hpd_enable().
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 f5342c5f457b..64e8e4c12cbd 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -432,7 +432,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.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* Re: [PATCH v10 34/69] drm/rockchip: dw_hdmi_qp: Mask RK3576 HPD IRQ in io_init
2026-07-31 16:19 ` Cristian Ciocaltea
(?)
@ 2026-07-31 21:14 ` sashiko-bot
-1 siblings, 0 replies; 155+ messages in thread
From: sashiko-bot @ 2026-07-31 21:14 UTC (permalink / raw)
To: Cristian Ciocaltea; +Cc: linux-sunxi, dri-devel
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
New issues:
- [Medium] Logic error: HPD interrupt is unconditionally unmasked during `setup_hpd`, defeating the patch's intent to defer arming to the bridge framework.
Pre-existing issues:
- [High] High-severity Use-After-Free and resource leaks due to improper use of `devm_*` APIs in the component `bind` callback.
- [High] RK3588 HPD IRQ handler clears the interrupt status a second time when unmasking, causing potential loss of hotplug events.
--
--- Patch [34]: [PATCH v10 34/69] drm/rockchip: dw_hdmi_qp: Mask RK3576 HPD IRQ in io_init ---
commit 1e56140d6c0038883d14ac31b8ac46f871e3f59e
Author: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
drm/rockchip: dw_hdmi_qp: Mask RK3576 HPD IRQ in io_init
This commit masks the HPD interrupt during I/O initialization for RK3576,
intending to defer interrupt arming to the bridge framework.
> diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
> --- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
> +++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
> @@ -432,7 +432,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);
> }
[Severity: Medium]
Does this change actually defer the interrupt arming?
Looking at dw_hdmi_qp_rk3576_setup_hpd() in the same file, the interrupt
appears to be unconditionally unmasked later during hardware initialization:
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c:dw_hdmi_qp_rk3576_setup_hpd() {
...
val = (FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_CLR, 1) | FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 0));
...
}
Additionally, it appears that rk3576_hdmi_phy_ops lacks the .enable_hpd and
.disable_hpd callbacks. Can the bridge framework actually control the
interrupt without these callbacks implemented?
[Severity: High]
This is a pre-existing issue, but I noticed a potential use-after-free
in the component bind/unbind lifecycle.
In dw_hdmi_qp_rockchip_bind(), devm_request_threaded_irq() is used to
allocate the IRQ handler on the platform device:
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c:dw_hdmi_qp_rockchip_bind() {
...
ret = devm_request_threaded_irq(dev, irq, ...);
...
}
However, the dev_id passed is hdmi, which is allocated via
drmm_kzalloc(). Since devm_ resources are tied to the device probe/remove
lifecycle rather than the component bind/unbind lifecycle, the IRQ is not
freed in dw_hdmi_qp_rockchip_unbind().
If the master unbinds, the drmm memory is freed, but the IRQ handler remains
active. Could an interrupt firing after unbind cause a use-after-free when
it accesses the freed hdmi pointer?
[Severity: High]
This is a pre-existing issue, but does dw_hdmi_qp_rk3588_irq() accidentally
clear the interrupt a second time when unmasking?
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c:dw_hdmi_qp_rk3588_irq() {
...
val |= FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_MSK, 0);
regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
...
}
Because this uses a bitwise OR, val retains the RK3588_HDMI0_HPD_INT_CLR
write-enable mask and data bit from earlier in the function. Does this
second regmap_write() clear the interrupt again, potentially losing hotplug
events that occurred between the two writes?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260731-dw-hdmi-qp-scramb-v10-0-294364b2cf15@collabora.com?part=34
^ permalink raw reply [flat|nested] 155+ messages in thread
* [PATCH v10 35/69] drm/rockchip: dw_hdmi_qp: Implement .{enable,disable}_hpd() PHY ops
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Maud Spierings, Diederik de Haas
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.
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
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 64e8e4c12cbd..1965641fbadf 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -277,7 +277,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;
@@ -292,11 +292,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
@@ -311,7 +325,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;
@@ -320,14 +334,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)
@@ -348,13 +370,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 & RK3576_HDMI_OHPD_INT) {
- val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 1);
- regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
+ if (intr_stat & RK3576_HDMI_OHPD_INT) {
+ dw_hdmi_qp_rk3576_disable_hpd(NULL, hdmi);
return IRQ_WAKE_THREAD;
}
@@ -364,15 +385,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;
}
@@ -380,18 +397,14 @@ 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);
intr_stat &= hdmi->port_id ? RK3588_HDMI1_OHPD_INT : RK3588_HDMI0_OHPD_INT;
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;
}
@@ -401,22 +414,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;
}
@@ -429,11 +431,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)
@@ -458,11 +460,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.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 35/69] drm/rockchip: dw_hdmi_qp: Implement .{enable,disable}_hpd() PHY ops
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Maud Spierings, Diederik de Haas
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.
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
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 64e8e4c12cbd..1965641fbadf 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -277,7 +277,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;
@@ -292,11 +292,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
@@ -311,7 +325,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;
@@ -320,14 +334,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)
@@ -348,13 +370,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 & RK3576_HDMI_OHPD_INT) {
- val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 1);
- regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
+ if (intr_stat & RK3576_HDMI_OHPD_INT) {
+ dw_hdmi_qp_rk3576_disable_hpd(NULL, hdmi);
return IRQ_WAKE_THREAD;
}
@@ -364,15 +385,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;
}
@@ -380,18 +397,14 @@ 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);
intr_stat &= hdmi->port_id ? RK3588_HDMI1_OHPD_INT : RK3588_HDMI0_OHPD_INT;
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;
}
@@ -401,22 +414,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;
}
@@ -429,11 +431,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)
@@ -458,11 +460,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.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 36/69] drm/rockchip: dw_hdmi_qp: Factor out HPD interrupt (un)mask helpers
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Diederik de Haas
Extract the GRF-level HPD interrupt mask/unmask register writes into
dedicated dw_hdmi_qp_rk35{88,76}_{mask,unmask}_hpd() helpers, and use
them from the .enable_hpd()/.disable_hpd() phy ops as well as the
hardirq, threaded re-arm and io_init() paths.
This is a preparatory refactor that separates the SoC-level HPD mask
from the phy op entry points, so a subsequent change can gate the
platform HPD IRQ line without affecting the debounce paths.
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 54 ++++++++++++++++++--------
1 file changed, 37 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 1965641fbadf..46a61112c14f 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -277,9 +277,8 @@ 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_enable_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
+static void dw_hdmi_qp_rk3588_unmask_hpd(struct rockchip_hdmi_qp *hdmi)
{
- struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
u32 val;
if (hdmi->port_id)
@@ -292,9 +291,8 @@ static void dw_hdmi_qp_rk3588_enable_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)
+static void dw_hdmi_qp_rk3588_mask_hpd(struct rockchip_hdmi_qp *hdmi)
{
- struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
u32 val;
if (hdmi->port_id)
@@ -305,6 +303,20 @@ static void dw_hdmi_qp_rk3588_disable_hpd(struct dw_hdmi_qp *dw_hdmi, void *data
regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
}
+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;
+
+ dw_hdmi_qp_rk3588_unmask_hpd(hdmi);
+}
+
+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;
+
+ dw_hdmi_qp_rk3588_mask_hpd(hdmi);
+}
+
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,
@@ -325,23 +337,31 @@ 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_unmask_hpd(struct rockchip_hdmi_qp *hdmi)
+{
+ regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0,
+ FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_CLR, 1) |
+ FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 0));
+}
+
+static void dw_hdmi_qp_rk3576_mask_hpd(struct rockchip_hdmi_qp *hdmi)
+{
+ regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0,
+ FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 1));
+}
+
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;
- val = (FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_CLR, 1) |
- FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 0));
-
- regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
+ dw_hdmi_qp_rk3576_unmask_hpd(hdmi);
}
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));
+ dw_hdmi_qp_rk3576_mask_hpd(hdmi);
}
static const struct dw_hdmi_qp_phy_ops rk3576_hdmi_phy_ops = {
@@ -375,7 +395,7 @@ static irqreturn_t dw_hdmi_qp_rk3576_hardirq(int irq, void *dev_id)
regmap_read(hdmi->regmap, RK3576_IOC_HDMI_HPD_STATUS, &intr_stat);
if (intr_stat & RK3576_HDMI_OHPD_INT) {
- dw_hdmi_qp_rk3576_disable_hpd(NULL, hdmi);
+ dw_hdmi_qp_rk3576_mask_hpd(hdmi);
return IRQ_WAKE_THREAD;
}
@@ -389,7 +409,7 @@ static irqreturn_t dw_hdmi_qp_rk3576_irq(int irq, void *dev_id)
mod_delayed_work(system_percpu_wq, &hdmi->hpd_work,
msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
- dw_hdmi_qp_rk3576_enable_hpd(NULL, hdmi);
+ dw_hdmi_qp_rk3576_unmask_hpd(hdmi);
return IRQ_HANDLED;
}
@@ -404,7 +424,7 @@ static irqreturn_t dw_hdmi_qp_rk3588_hardirq(int irq, void *dev_id)
intr_stat &= hdmi->port_id ? RK3588_HDMI1_OHPD_INT : RK3588_HDMI0_OHPD_INT;
if (intr_stat) {
- dw_hdmi_qp_rk3588_disable_hpd(NULL, hdmi);
+ dw_hdmi_qp_rk3588_mask_hpd(hdmi);
return IRQ_WAKE_THREAD;
}
@@ -418,7 +438,7 @@ static irqreturn_t dw_hdmi_qp_rk3588_irq(int irq, void *dev_id)
mod_delayed_work(system_percpu_wq, &hdmi->hpd_work,
msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
- dw_hdmi_qp_rk3588_enable_hpd(NULL, hdmi);
+ dw_hdmi_qp_rk3588_unmask_hpd(hdmi);
return IRQ_HANDLED;
}
@@ -435,7 +455,7 @@ static void dw_hdmi_qp_rk3576_io_init(struct rockchip_hdmi_qp *hdmi)
regmap_write(hdmi->regmap, 0xa404, 0xffff0102);
- dw_hdmi_qp_rk3576_disable_hpd(NULL, hdmi);
+ dw_hdmi_qp_rk3576_mask_hpd(hdmi);
}
static void dw_hdmi_qp_rk3588_io_init(struct rockchip_hdmi_qp *hdmi)
@@ -460,7 +480,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);
- dw_hdmi_qp_rk3588_disable_hpd(NULL, hdmi);
+ dw_hdmi_qp_rk3588_mask_hpd(hdmi);
}
static void dw_hdmi_qp_rk3576_enc_init(struct rockchip_hdmi_qp *hdmi,
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 36/69] drm/rockchip: dw_hdmi_qp: Factor out HPD interrupt (un)mask helpers
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Diederik de Haas
Extract the GRF-level HPD interrupt mask/unmask register writes into
dedicated dw_hdmi_qp_rk35{88,76}_{mask,unmask}_hpd() helpers, and use
them from the .enable_hpd()/.disable_hpd() phy ops as well as the
hardirq, threaded re-arm and io_init() paths.
This is a preparatory refactor that separates the SoC-level HPD mask
from the phy op entry points, so a subsequent change can gate the
platform HPD IRQ line without affecting the debounce paths.
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 54 ++++++++++++++++++--------
1 file changed, 37 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 1965641fbadf..46a61112c14f 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -277,9 +277,8 @@ 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_enable_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
+static void dw_hdmi_qp_rk3588_unmask_hpd(struct rockchip_hdmi_qp *hdmi)
{
- struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
u32 val;
if (hdmi->port_id)
@@ -292,9 +291,8 @@ static void dw_hdmi_qp_rk3588_enable_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)
+static void dw_hdmi_qp_rk3588_mask_hpd(struct rockchip_hdmi_qp *hdmi)
{
- struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
u32 val;
if (hdmi->port_id)
@@ -305,6 +303,20 @@ static void dw_hdmi_qp_rk3588_disable_hpd(struct dw_hdmi_qp *dw_hdmi, void *data
regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
}
+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;
+
+ dw_hdmi_qp_rk3588_unmask_hpd(hdmi);
+}
+
+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;
+
+ dw_hdmi_qp_rk3588_mask_hpd(hdmi);
+}
+
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,
@@ -325,23 +337,31 @@ 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_unmask_hpd(struct rockchip_hdmi_qp *hdmi)
+{
+ regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0,
+ FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_CLR, 1) |
+ FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 0));
+}
+
+static void dw_hdmi_qp_rk3576_mask_hpd(struct rockchip_hdmi_qp *hdmi)
+{
+ regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0,
+ FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 1));
+}
+
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;
- val = (FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_CLR, 1) |
- FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 0));
-
- regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
+ dw_hdmi_qp_rk3576_unmask_hpd(hdmi);
}
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));
+ dw_hdmi_qp_rk3576_mask_hpd(hdmi);
}
static const struct dw_hdmi_qp_phy_ops rk3576_hdmi_phy_ops = {
@@ -375,7 +395,7 @@ static irqreturn_t dw_hdmi_qp_rk3576_hardirq(int irq, void *dev_id)
regmap_read(hdmi->regmap, RK3576_IOC_HDMI_HPD_STATUS, &intr_stat);
if (intr_stat & RK3576_HDMI_OHPD_INT) {
- dw_hdmi_qp_rk3576_disable_hpd(NULL, hdmi);
+ dw_hdmi_qp_rk3576_mask_hpd(hdmi);
return IRQ_WAKE_THREAD;
}
@@ -389,7 +409,7 @@ static irqreturn_t dw_hdmi_qp_rk3576_irq(int irq, void *dev_id)
mod_delayed_work(system_percpu_wq, &hdmi->hpd_work,
msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
- dw_hdmi_qp_rk3576_enable_hpd(NULL, hdmi);
+ dw_hdmi_qp_rk3576_unmask_hpd(hdmi);
return IRQ_HANDLED;
}
@@ -404,7 +424,7 @@ static irqreturn_t dw_hdmi_qp_rk3588_hardirq(int irq, void *dev_id)
intr_stat &= hdmi->port_id ? RK3588_HDMI1_OHPD_INT : RK3588_HDMI0_OHPD_INT;
if (intr_stat) {
- dw_hdmi_qp_rk3588_disable_hpd(NULL, hdmi);
+ dw_hdmi_qp_rk3588_mask_hpd(hdmi);
return IRQ_WAKE_THREAD;
}
@@ -418,7 +438,7 @@ static irqreturn_t dw_hdmi_qp_rk3588_irq(int irq, void *dev_id)
mod_delayed_work(system_percpu_wq, &hdmi->hpd_work,
msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
- dw_hdmi_qp_rk3588_enable_hpd(NULL, hdmi);
+ dw_hdmi_qp_rk3588_unmask_hpd(hdmi);
return IRQ_HANDLED;
}
@@ -435,7 +455,7 @@ static void dw_hdmi_qp_rk3576_io_init(struct rockchip_hdmi_qp *hdmi)
regmap_write(hdmi->regmap, 0xa404, 0xffff0102);
- dw_hdmi_qp_rk3576_disable_hpd(NULL, hdmi);
+ dw_hdmi_qp_rk3576_mask_hpd(hdmi);
}
static void dw_hdmi_qp_rk3588_io_init(struct rockchip_hdmi_qp *hdmi)
@@ -460,7 +480,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);
- dw_hdmi_qp_rk3588_disable_hpd(NULL, hdmi);
+ dw_hdmi_qp_rk3588_mask_hpd(hdmi);
}
static void dw_hdmi_qp_rk3576_enc_init(struct rockchip_hdmi_qp *hdmi,
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 37/69] drm/rockchip: dw_hdmi_qp: Control the HPD IRQ line via the bridge HPD ops
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Diederik de Haas
The HPD interrupt must not be delivered before the DRM connector is fully
set up, and it should be quiesced while the display pipeline is suspended.
On top of that, the threaded handler re-arms HPD unconditionally after the
hotplug debounce, which must not override an explicit disable requested by
the DRM core.
Request the HPD IRQ in bind() with IRQF_NO_AUTOEN so it stays disabled
until the core arms it, and drive enable_irq()/disable_irq() from the
phy ops invoked by the bridge through its hpd_{enable,disable}()
callbacks. This ensures the line is only armed after the connector is
ready. disable_irq() additionally waits for the threaded handler to
finish, so its GRF re-arm can no longer race with and override a
core-requested disable.
Note that IRQF_NO_AUTOEN is incompatible with IRQF_SHARED; the latter is
dropped as this IRQ has no other users.
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index 46a61112c14f..253da2162ce6 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -99,6 +99,7 @@ struct rockchip_hdmi_qp {
struct phy *phy;
struct gpio_desc *frl_enable_gpio;
struct delayed_work hpd_work;
+ int hpd_irq;
int port_id;
const struct rockchip_hdmi_qp_ctrl_ops *ctrl_ops;
unsigned long long tmds_char_rate;
@@ -308,12 +309,14 @@ 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;
dw_hdmi_qp_rk3588_unmask_hpd(hdmi);
+ enable_irq(hdmi->hpd_irq);
}
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;
+ disable_irq(hdmi->hpd_irq);
dw_hdmi_qp_rk3588_mask_hpd(hdmi);
}
@@ -355,12 +358,14 @@ 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;
dw_hdmi_qp_rk3576_unmask_hpd(hdmi);
+ enable_irq(hdmi->hpd_irq);
}
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;
+ disable_irq(hdmi->hpd_irq);
dw_hdmi_qp_rk3576_mask_hpd(hdmi);
}
@@ -584,7 +589,7 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
struct resource *res;
struct clk_bulk_data *clks;
struct clk *ref_clk;
- int ret, irq, i;
+ int ret, i;
if (!dev->of_node)
return -ENODEV;
@@ -688,14 +693,14 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
if (plat_data.cec_irq < 0)
return plat_data.cec_irq;
- irq = platform_get_irq_byname(pdev, "hpd");
- if (irq < 0)
- return irq;
+ hdmi->hpd_irq = platform_get_irq_byname(pdev, "hpd");
+ if (hdmi->hpd_irq < 0)
+ return hdmi->hpd_irq;
- ret = devm_request_threaded_irq(dev, irq,
+ ret = devm_request_threaded_irq(dev, hdmi->hpd_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;
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 37/69] drm/rockchip: dw_hdmi_qp: Control the HPD IRQ line via the bridge HPD ops
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Diederik de Haas
The HPD interrupt must not be delivered before the DRM connector is fully
set up, and it should be quiesced while the display pipeline is suspended.
On top of that, the threaded handler re-arms HPD unconditionally after the
hotplug debounce, which must not override an explicit disable requested by
the DRM core.
Request the HPD IRQ in bind() with IRQF_NO_AUTOEN so it stays disabled
until the core arms it, and drive enable_irq()/disable_irq() from the
phy ops invoked by the bridge through its hpd_{enable,disable}()
callbacks. This ensures the line is only armed after the connector is
ready. disable_irq() additionally waits for the threaded handler to
finish, so its GRF re-arm can no longer race with and override a
core-requested disable.
Note that IRQF_NO_AUTOEN is incompatible with IRQF_SHARED; the latter is
dropped as this IRQ has no other users.
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index 46a61112c14f..253da2162ce6 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -99,6 +99,7 @@ struct rockchip_hdmi_qp {
struct phy *phy;
struct gpio_desc *frl_enable_gpio;
struct delayed_work hpd_work;
+ int hpd_irq;
int port_id;
const struct rockchip_hdmi_qp_ctrl_ops *ctrl_ops;
unsigned long long tmds_char_rate;
@@ -308,12 +309,14 @@ 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;
dw_hdmi_qp_rk3588_unmask_hpd(hdmi);
+ enable_irq(hdmi->hpd_irq);
}
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;
+ disable_irq(hdmi->hpd_irq);
dw_hdmi_qp_rk3588_mask_hpd(hdmi);
}
@@ -355,12 +358,14 @@ 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;
dw_hdmi_qp_rk3576_unmask_hpd(hdmi);
+ enable_irq(hdmi->hpd_irq);
}
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;
+ disable_irq(hdmi->hpd_irq);
dw_hdmi_qp_rk3576_mask_hpd(hdmi);
}
@@ -584,7 +589,7 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
struct resource *res;
struct clk_bulk_data *clks;
struct clk *ref_clk;
- int ret, irq, i;
+ int ret, i;
if (!dev->of_node)
return -ENODEV;
@@ -688,14 +693,14 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
if (plat_data.cec_irq < 0)
return plat_data.cec_irq;
- irq = platform_get_irq_byname(pdev, "hpd");
- if (irq < 0)
- return irq;
+ hdmi->hpd_irq = platform_get_irq_byname(pdev, "hpd");
+ if (hdmi->hpd_irq < 0)
+ return hdmi->hpd_irq;
- ret = devm_request_threaded_irq(dev, irq,
+ ret = devm_request_threaded_irq(dev, hdmi->hpd_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;
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 38/69] drm/rockchip: dw_hdmi_qp: Use dw_hdmi_qp_hpd_notify() for HPD reports
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Maud Spierings, Diederik de Haas
Notify only the affected connector instead of polling all of them, and
ensure .detect_ctx() runs on reconnect to recover SCDC state.
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
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 253da2162ce6..bbdd47d4f381 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_bridge_connector.h>
#include <drm/drm_managed.h>
#include <drm/drm_of.h>
-#include <drm/drm_probe_helper.h>
#include "rockchip_drm_drv.h"
@@ -382,14 +381,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)
@@ -776,8 +769,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.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 38/69] drm/rockchip: dw_hdmi_qp: Use dw_hdmi_qp_hpd_notify() for HPD reports
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Maud Spierings, Diederik de Haas
Notify only the affected connector instead of polling all of them, and
ensure .detect_ctx() runs on reconnect to recover SCDC state.
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
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 253da2162ce6..bbdd47d4f381 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_bridge_connector.h>
#include <drm/drm_managed.h>
#include <drm/drm_of.h>
-#include <drm/drm_probe_helper.h>
#include "rockchip_drm_drv.h"
@@ -382,14 +381,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)
@@ -776,8 +769,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.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 39/69] drm/bridge: dw-hdmi-qp: Drop unused .setup_hpd() phy op
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Maud Spierings, Diederik de Haas
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.
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
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 a2277531182c..fcbc518cd90a 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
@@ -1295,9 +1295,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.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 39/69] drm/bridge: dw-hdmi-qp: Drop unused .setup_hpd() phy op
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Maud Spierings, Diederik de Haas
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.
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
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 a2277531182c..fcbc518cd90a 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
@@ -1295,9 +1295,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.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 40/69] drm/vc4: hdmi: Use common TMDS char rate constants
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
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.
Reviewed-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
Acked-by: Maxime Ripard <mripard@kernel.org>
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 7f613f912368..9ce56eca775c 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.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 40/69] drm/vc4: hdmi: Use common TMDS char rate constants
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
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.
Reviewed-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
Acked-by: Maxime Ripard <mripard@kernel.org>
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 7f613f912368..9ce56eca775c 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.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 41/69] drm/vc4: hdmi: Switch to drm_hdmi_mode_needs_scrambling()
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
The VC4 HDMI driver has a local helper to check whether a mode requires
scrambling. It is equivalent to drm_hdmi_mode_needs_scrambling(), so
use the common helper instead.
No functional change intended.
Acked-by: Maxime Ripard <mripard@kernel.org>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/vc4/vc4_hdmi.c | 16 ++++------------
1 file changed, 4 insertions(+), 12 deletions(-)
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index 9ce56eca775c..4f7fc6689869 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -130,15 +130,6 @@ static bool vc4_hdmi_supports_scrambling(struct vc4_hdmi *vc4_hdmi)
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;
@@ -313,7 +304,7 @@ static int vc4_hdmi_reset_link(struct drm_connector *connector,
return 0;
}
- scrambling_needed = vc4_hdmi_mode_needs_scrambling(&vc4_hdmi->saved_adjusted_mode,
+ scrambling_needed = drm_hdmi_mode_needs_scrambling(&vc4_hdmi->saved_adjusted_mode,
vc4_hdmi->output_bpc,
vc4_hdmi->output_format);
if (!scrambling_needed) {
@@ -443,7 +434,8 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector)
const struct drm_display_mode *mode;
list_for_each_entry(mode, &connector->probed_modes, head) {
- if (vc4_hdmi_mode_needs_scrambling(mode, 8, DRM_OUTPUT_COLOR_FORMAT_RGB444)) {
+ if (drm_hdmi_mode_needs_scrambling(mode, 8,
+ DRM_OUTPUT_COLOR_FORMAT_RGB444)) {
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.");
}
@@ -802,7 +794,7 @@ static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder)
if (!vc4_hdmi_supports_scrambling(vc4_hdmi))
return;
- if (!vc4_hdmi_mode_needs_scrambling(mode,
+ if (!drm_hdmi_mode_needs_scrambling(mode,
vc4_hdmi->output_bpc,
vc4_hdmi->output_format))
return;
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 41/69] drm/vc4: hdmi: Switch to drm_hdmi_mode_needs_scrambling()
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
The VC4 HDMI driver has a local helper to check whether a mode requires
scrambling. It is equivalent to drm_hdmi_mode_needs_scrambling(), so
use the common helper instead.
No functional change intended.
Acked-by: Maxime Ripard <mripard@kernel.org>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/vc4/vc4_hdmi.c | 16 ++++------------
1 file changed, 4 insertions(+), 12 deletions(-)
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index 9ce56eca775c..4f7fc6689869 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -130,15 +130,6 @@ static bool vc4_hdmi_supports_scrambling(struct vc4_hdmi *vc4_hdmi)
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;
@@ -313,7 +304,7 @@ static int vc4_hdmi_reset_link(struct drm_connector *connector,
return 0;
}
- scrambling_needed = vc4_hdmi_mode_needs_scrambling(&vc4_hdmi->saved_adjusted_mode,
+ scrambling_needed = drm_hdmi_mode_needs_scrambling(&vc4_hdmi->saved_adjusted_mode,
vc4_hdmi->output_bpc,
vc4_hdmi->output_format);
if (!scrambling_needed) {
@@ -443,7 +434,8 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector)
const struct drm_display_mode *mode;
list_for_each_entry(mode, &connector->probed_modes, head) {
- if (vc4_hdmi_mode_needs_scrambling(mode, 8, DRM_OUTPUT_COLOR_FORMAT_RGB444)) {
+ if (drm_hdmi_mode_needs_scrambling(mode, 8,
+ DRM_OUTPUT_COLOR_FORMAT_RGB444)) {
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.");
}
@@ -802,7 +794,7 @@ static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder)
if (!vc4_hdmi_supports_scrambling(vc4_hdmi))
return;
- if (!vc4_hdmi_mode_needs_scrambling(mode,
+ if (!drm_hdmi_mode_needs_scrambling(mode,
vc4_hdmi->output_bpc,
vc4_hdmi->output_format))
return;
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 42/69] drm/vc4: hdmi: Switch to .force_ctx() connector helper
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
Use drm_atomic_helper_connector_hdmi_force_ctx() as the .force_ctx()
implementation, so that the acquire context created by the probe helper
reaches the HDMI connector framework.
This is a prerequisite for converting the driver to the common HDMI 2.0
scrambling infrastructure, which implicitly handles SCDC state recovery
through a CRTC reset when the sink reconnects while the display pipeline
is active. Note that this does not interfere with the local SCDC
state-management implementation, since the driver's scrambler capability
has not yet been exposed through the common helpers.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/vc4/vc4_hdmi.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index 4f7fc6689869..ba16e7944cf3 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -504,7 +504,6 @@ static void vc4_hdmi_connector_reset(struct drm_connector *connector)
}
static const struct drm_connector_funcs vc4_hdmi_connector_funcs = {
- .force = drm_atomic_helper_connector_hdmi_force,
.fill_modes = drm_helper_probe_single_connector_modes,
.reset = vc4_hdmi_connector_reset,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
@@ -513,6 +512,7 @@ static const struct drm_connector_funcs vc4_hdmi_connector_funcs = {
static const struct drm_connector_helper_funcs vc4_hdmi_connector_helper_funcs = {
.detect_ctx = vc4_hdmi_connector_detect_ctx,
+ .force_ctx = drm_atomic_helper_connector_hdmi_force_ctx,
.get_modes = vc4_hdmi_connector_get_modes,
.atomic_check = vc4_hdmi_connector_atomic_check,
.mode_valid = drm_hdmi_connector_mode_valid,
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 42/69] drm/vc4: hdmi: Switch to .force_ctx() connector helper
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
Use drm_atomic_helper_connector_hdmi_force_ctx() as the .force_ctx()
implementation, so that the acquire context created by the probe helper
reaches the HDMI connector framework.
This is a prerequisite for converting the driver to the common HDMI 2.0
scrambling infrastructure, which implicitly handles SCDC state recovery
through a CRTC reset when the sink reconnects while the display pipeline
is active. Note that this does not interfere with the local SCDC
state-management implementation, since the driver's scrambler capability
has not yet been exposed through the common helpers.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/vc4/vc4_hdmi.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index 4f7fc6689869..ba16e7944cf3 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -504,7 +504,6 @@ static void vc4_hdmi_connector_reset(struct drm_connector *connector)
}
static const struct drm_connector_funcs vc4_hdmi_connector_funcs = {
- .force = drm_atomic_helper_connector_hdmi_force,
.fill_modes = drm_helper_probe_single_connector_modes,
.reset = vc4_hdmi_connector_reset,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
@@ -513,6 +512,7 @@ static const struct drm_connector_funcs vc4_hdmi_connector_funcs = {
static const struct drm_connector_helper_funcs vc4_hdmi_connector_helper_funcs = {
.detect_ctx = vc4_hdmi_connector_detect_ctx,
+ .force_ctx = drm_atomic_helper_connector_hdmi_force_ctx,
.get_modes = vc4_hdmi_connector_get_modes,
.atomic_check = vc4_hdmi_connector_atomic_check,
.mode_valid = drm_hdmi_connector_mode_valid,
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 43/69] drm/vc4: hdmi: Propagate -EDEADLK to the top level
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
drm_connector_helper_funcs.detect_ctx() is expected to propagate
-EDEADLK so that context owners, e.g. drm_helper_probe_detect_ctx(), can
perform the required backoff and retry.
vc4_hdmi_handle_hotplug() instead runs its own retry loop and calls
drm_modeset_backoff() on an acquire context it does not own. This drops
all locks in the context, including connection_mutex held by the core.
Drop the local retry logic and propagate -EDEADLK to the caller instead.
This aligns VC4 with the expected detect_ctx() semantics.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/vc4/vc4_hdmi.c | 23 +++++++----------------
1 file changed, 7 insertions(+), 16 deletions(-)
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index ba16e7944cf3..72042fad04c5 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -344,12 +344,11 @@ static int vc4_hdmi_reset_link(struct drm_connector *connector,
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)
+static int 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
@@ -368,17 +367,9 @@ static void vc4_hdmi_handle_hotplug(struct vc4_hdmi *vc4_hdmi,
drm_atomic_helper_connector_hdmi_hotplug(connector, ctx, status);
if (status != connector_status_connected)
- return;
+ return 0;
- for (;;) {
- ret = vc4_hdmi_reset_link(connector, ctx);
- if (ret == -EDEADLK) {
- drm_modeset_backoff(ctx);
- continue;
- }
-
- break;
- }
+ return vc4_hdmi_reset_link(connector, ctx);
}
static int vc4_hdmi_connector_detect_ctx(struct drm_connector *connector,
@@ -416,10 +407,10 @@ static int vc4_hdmi_connector_detect_ctx(struct drm_connector *connector,
status = connector_status_connected;
}
- vc4_hdmi_handle_hotplug(vc4_hdmi, ctx, status);
+ ret = vc4_hdmi_handle_hotplug(vc4_hdmi, ctx, status);
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)
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 43/69] drm/vc4: hdmi: Propagate -EDEADLK to the top level
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
drm_connector_helper_funcs.detect_ctx() is expected to propagate
-EDEADLK so that context owners, e.g. drm_helper_probe_detect_ctx(), can
perform the required backoff and retry.
vc4_hdmi_handle_hotplug() instead runs its own retry loop and calls
drm_modeset_backoff() on an acquire context it does not own. This drops
all locks in the context, including connection_mutex held by the core.
Drop the local retry logic and propagate -EDEADLK to the caller instead.
This aligns VC4 with the expected detect_ctx() semantics.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/vc4/vc4_hdmi.c | 23 +++++++----------------
1 file changed, 7 insertions(+), 16 deletions(-)
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index ba16e7944cf3..72042fad04c5 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -344,12 +344,11 @@ static int vc4_hdmi_reset_link(struct drm_connector *connector,
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)
+static int 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
@@ -368,17 +367,9 @@ static void vc4_hdmi_handle_hotplug(struct vc4_hdmi *vc4_hdmi,
drm_atomic_helper_connector_hdmi_hotplug(connector, ctx, status);
if (status != connector_status_connected)
- return;
+ return 0;
- for (;;) {
- ret = vc4_hdmi_reset_link(connector, ctx);
- if (ret == -EDEADLK) {
- drm_modeset_backoff(ctx);
- continue;
- }
-
- break;
- }
+ return vc4_hdmi_reset_link(connector, ctx);
}
static int vc4_hdmi_connector_detect_ctx(struct drm_connector *connector,
@@ -416,10 +407,10 @@ static int vc4_hdmi_connector_detect_ctx(struct drm_connector *connector,
status = connector_status_connected;
}
- vc4_hdmi_handle_hotplug(vc4_hdmi, ctx, status);
+ ret = vc4_hdmi_handle_hotplug(vc4_hdmi, ctx, status);
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)
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 44/69] drm/vc4: hdmi: Convert to drmm_connector_hdmi_init()
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
Switch driver over to the new drmm_connector_hdmi_init() signature. The
vendor, product, supported_formats and max_bpc values previously passed
as arguments are now provided through struct drm_connector_hdmi_funcs,
together with the new supported_hdmi_ver field.
VC4 needs three distinct capability sets, based on the maximum TMDS
character rate and color depth supported by each controller variant:
RPi 0-3: 162 MHz (HDMI 1.2), 8-bit
RPi 4 (HDMI1): 340 MHz (HDMI 1.4), 12-bit
RPi 4 (HDMI0), RPi 5: 600 MHz (HDMI 2.0), 12-bit
Introduce three drm_connector_hdmi_funcs instances for these tiers and
assign them to the corresponding vc4_hdmi_variant entries. Additionally,
drop the now redundant .supports_hdr field of struct vc4_hdmi_variant.
As the callback members are identical across all three, factor the
shared initializers into a VC4_HDMI_CONNECTOR_FUNCS_COMMON macro to
avoid duplication, with each variant adding only its distinguishing
max_bpc/supported_hdmi_ver fields.
Note that HDMI 2.0 cannot be advertised at this point, since it requires
converting the driver to common scrambling infrastructure. This will be
handled separately, hence temporarily use HDMI_VERSION_UNKNOWN for the
related hdmi_funcs instance to skip generic scrambler and TMDS rate
validation, and continue to rely on current driver-local implementation.
No functional change intended.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/vc4/vc4_hdmi.c | 93 ++++++++++++++++++++++++------------------
drivers/gpu/drm/vc4/vc4_hdmi.h | 6 +--
2 files changed, 56 insertions(+), 43 deletions(-)
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index 72042fad04c5..d599957fee3a 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -509,7 +509,6 @@ static const struct drm_connector_helper_funcs vc4_hdmi_connector_helper_funcs =
.mode_valid = drm_hdmi_connector_mode_valid,
};
-static const struct drm_connector_hdmi_funcs vc4_hdmi_hdmi_connector_funcs;
static const struct drm_connector_hdmi_audio_funcs vc4_hdmi_audio_funcs;
static int vc4_hdmi_connector_init(struct drm_device *dev,
@@ -517,22 +516,13 @@ static int vc4_hdmi_connector_init(struct drm_device *dev,
{
struct drm_connector *connector = &vc4_hdmi->connector;
struct drm_encoder *encoder = &vc4_hdmi->encoder.base;
- unsigned int max_bpc = 8;
int ret;
- if (vc4_hdmi->variant->supports_hdr)
- max_bpc = 12;
-
- ret = drmm_connector_hdmi_ini2(dev, connector,
- "Broadcom", "Videocore",
+ ret = drmm_connector_hdmi_init(dev, connector,
&vc4_hdmi_connector_funcs,
- &vc4_hdmi_hdmi_connector_funcs,
+ vc4_hdmi->variant->hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
- vc4_hdmi->ddc,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444),
- max_bpc);
+ vc4_hdmi->ddc);
if (ret)
return ret;
@@ -1721,28 +1711,51 @@ vc4_hdmi_connector_clock_valid(const struct drm_connector *connector,
return MODE_OK;
}
-static const struct drm_connector_hdmi_funcs vc4_hdmi_hdmi_connector_funcs = {
- .tmds_char_rate_valid = vc4_hdmi_connector_clock_valid,
- .avi = {
- .clear_infoframe = vc4_hdmi_clear_avi_infoframe,
- .write_infoframe = vc4_hdmi_write_avi_infoframe,
- },
- .hdmi = {
- .clear_infoframe = vc4_hdmi_clear_hdmi_infoframe,
- .write_infoframe = vc4_hdmi_write_hdmi_infoframe,
- },
- .audio = {
- .clear_infoframe = vc4_hdmi_clear_audio_infoframe,
- .write_infoframe = vc4_hdmi_write_audio_infoframe,
- },
- .hdr_drm = {
- .clear_infoframe = vc4_hdmi_clear_hdr_drm_infoframe,
- .write_infoframe = vc4_hdmi_write_hdr_drm_infoframe,
- },
- .spd = {
- .clear_infoframe = vc4_hdmi_clear_spd_infoframe,
- .write_infoframe = vc4_hdmi_write_spd_infoframe,
- },
+#define VC4_HDMI_CONNECTOR_FUNCS_COMMON \
+ .vendor = "Broadcom", \
+ .product = "Videocore", \
+ .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) | \
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) | \
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444), \
+ .tmds_char_rate_valid = vc4_hdmi_connector_clock_valid, \
+ .avi = { \
+ .clear_infoframe = vc4_hdmi_clear_avi_infoframe, \
+ .write_infoframe = vc4_hdmi_write_avi_infoframe, \
+ }, \
+ .hdmi = { \
+ .clear_infoframe = vc4_hdmi_clear_hdmi_infoframe, \
+ .write_infoframe = vc4_hdmi_write_hdmi_infoframe, \
+ }, \
+ .audio = { \
+ .clear_infoframe = vc4_hdmi_clear_audio_infoframe, \
+ .write_infoframe = vc4_hdmi_write_audio_infoframe, \
+ }, \
+ .hdr_drm = { \
+ .clear_infoframe = vc4_hdmi_clear_hdr_drm_infoframe, \
+ .write_infoframe = vc4_hdmi_write_hdr_drm_infoframe, \
+ }, \
+ .spd = { \
+ .clear_infoframe = vc4_hdmi_clear_spd_infoframe, \
+ .write_infoframe = vc4_hdmi_write_spd_infoframe, \
+ }
+
+static const struct drm_connector_hdmi_funcs vc4_hdmi_connector_funcs_hdmi12 = {
+ VC4_HDMI_CONNECTOR_FUNCS_COMMON,
+ .max_bpc = 8,
+ .supported_hdmi_ver = HDMI_VERSION_1_2,
+};
+
+static const struct drm_connector_hdmi_funcs vc4_hdmi_connector_funcs_hdmi14 = {
+ VC4_HDMI_CONNECTOR_FUNCS_COMMON,
+ .max_bpc = 12,
+ .supported_hdmi_ver = HDMI_VERSION_1_4,
+};
+
+static const struct drm_connector_hdmi_funcs vc4_hdmi_connector_funcs_hdmi20 = {
+ VC4_HDMI_CONNECTOR_FUNCS_COMMON,
+ .max_bpc = 12,
+ /* TODO: set HDMI_VERSION_2_0 and convert to common scrambler infra */
+ .supported_hdmi_ver = HDMI_VERSION_UNKNOWN,
};
#define WIFI_2_4GHz_CH1_MIN_FREQ 2400000000ULL
@@ -3358,7 +3371,7 @@ static const struct vc4_hdmi_variant bcm2835_variant = {
.phy_rng_enable = vc4_hdmi_phy_rng_enable,
.phy_rng_disable = vc4_hdmi_phy_rng_disable,
.channel_map = vc4_hdmi_channel_map,
- .supports_hdr = false,
+ .hdmi_funcs = &vc4_hdmi_connector_funcs_hdmi12,
};
static const struct vc4_hdmi_variant bcm2711_hdmi0_variant = {
@@ -3386,8 +3399,8 @@ static const struct vc4_hdmi_variant bcm2711_hdmi0_variant = {
.phy_rng_enable = vc5_hdmi_phy_rng_enable,
.phy_rng_disable = vc5_hdmi_phy_rng_disable,
.channel_map = vc5_hdmi_channel_map,
- .supports_hdr = true,
.hp_detect = vc5_hdmi_hp_detect,
+ .hdmi_funcs = &vc4_hdmi_connector_funcs_hdmi20,
};
static const struct vc4_hdmi_variant bcm2711_hdmi1_variant = {
@@ -3415,8 +3428,8 @@ static const struct vc4_hdmi_variant bcm2711_hdmi1_variant = {
.phy_rng_enable = vc5_hdmi_phy_rng_enable,
.phy_rng_disable = vc5_hdmi_phy_rng_disable,
.channel_map = vc5_hdmi_channel_map,
- .supports_hdr = true,
.hp_detect = vc5_hdmi_hp_detect,
+ .hdmi_funcs = &vc4_hdmi_connector_funcs_hdmi14,
};
static const struct vc4_hdmi_variant bcm2712_hdmi0_variant = {
@@ -3442,8 +3455,8 @@ static const struct vc4_hdmi_variant bcm2712_hdmi0_variant = {
.phy_init = vc6_hdmi_phy_init,
.phy_disable = vc6_hdmi_phy_disable,
.channel_map = vc5_hdmi_channel_map,
- .supports_hdr = true,
.hp_detect = vc5_hdmi_hp_detect,
+ .hdmi_funcs = &vc4_hdmi_connector_funcs_hdmi20,
};
static const struct vc4_hdmi_variant bcm2712_hdmi1_variant = {
@@ -3469,8 +3482,8 @@ static const struct vc4_hdmi_variant bcm2712_hdmi1_variant = {
.phy_init = vc6_hdmi_phy_init,
.phy_disable = vc6_hdmi_phy_disable,
.channel_map = vc5_hdmi_channel_map,
- .supports_hdr = true,
.hp_detect = vc5_hdmi_hp_detect,
+ .hdmi_funcs = &vc4_hdmi_connector_funcs_hdmi20,
};
static const struct of_device_id vc4_hdmi_dt_match[] = {
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h
index 29d461d4ee49..d5ffcc17de32 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.h
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.h
@@ -90,11 +90,11 @@ struct vc4_hdmi_variant {
/* Callback to get channel map */
u32 (*channel_map)(struct vc4_hdmi *vc4_hdmi, u32 channel_mask);
- /* Enables HDR metadata */
- bool supports_hdr;
-
/* Callback for hardware specific hotplug detect */
bool (*hp_detect)(struct vc4_hdmi *vc4_hdmi);
+
+ /* HDMI-related connector callbacks and controller capabilities */
+ const struct drm_connector_hdmi_funcs *hdmi_funcs;
};
/* HDMI audio information */
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 44/69] drm/vc4: hdmi: Convert to drmm_connector_hdmi_init()
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
Switch driver over to the new drmm_connector_hdmi_init() signature. The
vendor, product, supported_formats and max_bpc values previously passed
as arguments are now provided through struct drm_connector_hdmi_funcs,
together with the new supported_hdmi_ver field.
VC4 needs three distinct capability sets, based on the maximum TMDS
character rate and color depth supported by each controller variant:
RPi 0-3: 162 MHz (HDMI 1.2), 8-bit
RPi 4 (HDMI1): 340 MHz (HDMI 1.4), 12-bit
RPi 4 (HDMI0), RPi 5: 600 MHz (HDMI 2.0), 12-bit
Introduce three drm_connector_hdmi_funcs instances for these tiers and
assign them to the corresponding vc4_hdmi_variant entries. Additionally,
drop the now redundant .supports_hdr field of struct vc4_hdmi_variant.
As the callback members are identical across all three, factor the
shared initializers into a VC4_HDMI_CONNECTOR_FUNCS_COMMON macro to
avoid duplication, with each variant adding only its distinguishing
max_bpc/supported_hdmi_ver fields.
Note that HDMI 2.0 cannot be advertised at this point, since it requires
converting the driver to common scrambling infrastructure. This will be
handled separately, hence temporarily use HDMI_VERSION_UNKNOWN for the
related hdmi_funcs instance to skip generic scrambler and TMDS rate
validation, and continue to rely on current driver-local implementation.
No functional change intended.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/vc4/vc4_hdmi.c | 93 ++++++++++++++++++++++++------------------
drivers/gpu/drm/vc4/vc4_hdmi.h | 6 +--
2 files changed, 56 insertions(+), 43 deletions(-)
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index 72042fad04c5..d599957fee3a 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -509,7 +509,6 @@ static const struct drm_connector_helper_funcs vc4_hdmi_connector_helper_funcs =
.mode_valid = drm_hdmi_connector_mode_valid,
};
-static const struct drm_connector_hdmi_funcs vc4_hdmi_hdmi_connector_funcs;
static const struct drm_connector_hdmi_audio_funcs vc4_hdmi_audio_funcs;
static int vc4_hdmi_connector_init(struct drm_device *dev,
@@ -517,22 +516,13 @@ static int vc4_hdmi_connector_init(struct drm_device *dev,
{
struct drm_connector *connector = &vc4_hdmi->connector;
struct drm_encoder *encoder = &vc4_hdmi->encoder.base;
- unsigned int max_bpc = 8;
int ret;
- if (vc4_hdmi->variant->supports_hdr)
- max_bpc = 12;
-
- ret = drmm_connector_hdmi_ini2(dev, connector,
- "Broadcom", "Videocore",
+ ret = drmm_connector_hdmi_init(dev, connector,
&vc4_hdmi_connector_funcs,
- &vc4_hdmi_hdmi_connector_funcs,
+ vc4_hdmi->variant->hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
- vc4_hdmi->ddc,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444),
- max_bpc);
+ vc4_hdmi->ddc);
if (ret)
return ret;
@@ -1721,28 +1711,51 @@ vc4_hdmi_connector_clock_valid(const struct drm_connector *connector,
return MODE_OK;
}
-static const struct drm_connector_hdmi_funcs vc4_hdmi_hdmi_connector_funcs = {
- .tmds_char_rate_valid = vc4_hdmi_connector_clock_valid,
- .avi = {
- .clear_infoframe = vc4_hdmi_clear_avi_infoframe,
- .write_infoframe = vc4_hdmi_write_avi_infoframe,
- },
- .hdmi = {
- .clear_infoframe = vc4_hdmi_clear_hdmi_infoframe,
- .write_infoframe = vc4_hdmi_write_hdmi_infoframe,
- },
- .audio = {
- .clear_infoframe = vc4_hdmi_clear_audio_infoframe,
- .write_infoframe = vc4_hdmi_write_audio_infoframe,
- },
- .hdr_drm = {
- .clear_infoframe = vc4_hdmi_clear_hdr_drm_infoframe,
- .write_infoframe = vc4_hdmi_write_hdr_drm_infoframe,
- },
- .spd = {
- .clear_infoframe = vc4_hdmi_clear_spd_infoframe,
- .write_infoframe = vc4_hdmi_write_spd_infoframe,
- },
+#define VC4_HDMI_CONNECTOR_FUNCS_COMMON \
+ .vendor = "Broadcom", \
+ .product = "Videocore", \
+ .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) | \
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) | \
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444), \
+ .tmds_char_rate_valid = vc4_hdmi_connector_clock_valid, \
+ .avi = { \
+ .clear_infoframe = vc4_hdmi_clear_avi_infoframe, \
+ .write_infoframe = vc4_hdmi_write_avi_infoframe, \
+ }, \
+ .hdmi = { \
+ .clear_infoframe = vc4_hdmi_clear_hdmi_infoframe, \
+ .write_infoframe = vc4_hdmi_write_hdmi_infoframe, \
+ }, \
+ .audio = { \
+ .clear_infoframe = vc4_hdmi_clear_audio_infoframe, \
+ .write_infoframe = vc4_hdmi_write_audio_infoframe, \
+ }, \
+ .hdr_drm = { \
+ .clear_infoframe = vc4_hdmi_clear_hdr_drm_infoframe, \
+ .write_infoframe = vc4_hdmi_write_hdr_drm_infoframe, \
+ }, \
+ .spd = { \
+ .clear_infoframe = vc4_hdmi_clear_spd_infoframe, \
+ .write_infoframe = vc4_hdmi_write_spd_infoframe, \
+ }
+
+static const struct drm_connector_hdmi_funcs vc4_hdmi_connector_funcs_hdmi12 = {
+ VC4_HDMI_CONNECTOR_FUNCS_COMMON,
+ .max_bpc = 8,
+ .supported_hdmi_ver = HDMI_VERSION_1_2,
+};
+
+static const struct drm_connector_hdmi_funcs vc4_hdmi_connector_funcs_hdmi14 = {
+ VC4_HDMI_CONNECTOR_FUNCS_COMMON,
+ .max_bpc = 12,
+ .supported_hdmi_ver = HDMI_VERSION_1_4,
+};
+
+static const struct drm_connector_hdmi_funcs vc4_hdmi_connector_funcs_hdmi20 = {
+ VC4_HDMI_CONNECTOR_FUNCS_COMMON,
+ .max_bpc = 12,
+ /* TODO: set HDMI_VERSION_2_0 and convert to common scrambler infra */
+ .supported_hdmi_ver = HDMI_VERSION_UNKNOWN,
};
#define WIFI_2_4GHz_CH1_MIN_FREQ 2400000000ULL
@@ -3358,7 +3371,7 @@ static const struct vc4_hdmi_variant bcm2835_variant = {
.phy_rng_enable = vc4_hdmi_phy_rng_enable,
.phy_rng_disable = vc4_hdmi_phy_rng_disable,
.channel_map = vc4_hdmi_channel_map,
- .supports_hdr = false,
+ .hdmi_funcs = &vc4_hdmi_connector_funcs_hdmi12,
};
static const struct vc4_hdmi_variant bcm2711_hdmi0_variant = {
@@ -3386,8 +3399,8 @@ static const struct vc4_hdmi_variant bcm2711_hdmi0_variant = {
.phy_rng_enable = vc5_hdmi_phy_rng_enable,
.phy_rng_disable = vc5_hdmi_phy_rng_disable,
.channel_map = vc5_hdmi_channel_map,
- .supports_hdr = true,
.hp_detect = vc5_hdmi_hp_detect,
+ .hdmi_funcs = &vc4_hdmi_connector_funcs_hdmi20,
};
static const struct vc4_hdmi_variant bcm2711_hdmi1_variant = {
@@ -3415,8 +3428,8 @@ static const struct vc4_hdmi_variant bcm2711_hdmi1_variant = {
.phy_rng_enable = vc5_hdmi_phy_rng_enable,
.phy_rng_disable = vc5_hdmi_phy_rng_disable,
.channel_map = vc5_hdmi_channel_map,
- .supports_hdr = true,
.hp_detect = vc5_hdmi_hp_detect,
+ .hdmi_funcs = &vc4_hdmi_connector_funcs_hdmi14,
};
static const struct vc4_hdmi_variant bcm2712_hdmi0_variant = {
@@ -3442,8 +3455,8 @@ static const struct vc4_hdmi_variant bcm2712_hdmi0_variant = {
.phy_init = vc6_hdmi_phy_init,
.phy_disable = vc6_hdmi_phy_disable,
.channel_map = vc5_hdmi_channel_map,
- .supports_hdr = true,
.hp_detect = vc5_hdmi_hp_detect,
+ .hdmi_funcs = &vc4_hdmi_connector_funcs_hdmi20,
};
static const struct vc4_hdmi_variant bcm2712_hdmi1_variant = {
@@ -3469,8 +3482,8 @@ static const struct vc4_hdmi_variant bcm2712_hdmi1_variant = {
.phy_init = vc6_hdmi_phy_init,
.phy_disable = vc6_hdmi_phy_disable,
.channel_map = vc5_hdmi_channel_map,
- .supports_hdr = true,
.hp_detect = vc5_hdmi_hp_detect,
+ .hdmi_funcs = &vc4_hdmi_connector_funcs_hdmi20,
};
static const struct of_device_id vc4_hdmi_dt_match[] = {
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h
index 29d461d4ee49..d5ffcc17de32 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.h
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.h
@@ -90,11 +90,11 @@ struct vc4_hdmi_variant {
/* Callback to get channel map */
u32 (*channel_map)(struct vc4_hdmi *vc4_hdmi, u32 channel_mask);
- /* Enables HDR metadata */
- bool supports_hdr;
-
/* Callback for hardware specific hotplug detect */
bool (*hp_detect)(struct vc4_hdmi *vc4_hdmi);
+
+ /* HDMI-related connector callbacks and controller capabilities */
+ const struct drm_connector_hdmi_funcs *hdmi_funcs;
};
/* HDMI audio information */
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 45/69] drm/vc4: hdmi: Convert to common HDMI 2.0 scrambling infrastructure
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
Replace driver local scrambling logic with the newly introduced common
HDMI 2.0 scrambling support:
- Advertise source-side scrambling capability by setting supported HDMI
version based on the variant's max_pixel_clock.
- Provide minimal .scrambler_{enable,disable} connector callbacks that
only toggle the VC5 HDMI_SCRAMBLER_CTL register, while delegating
sink-side SCDC programming and periodic status monitoring to
drm_connector_hdmi_{enable,disable}_scrambling().
- Drop vc4_hdmi_reset_link() and vc4_hdmi_handle_hotplug(), switching
the .detect_ctx() path to drm_atomic_helper_connector_hdmi_hotplug()
which internally calls drm_connector_hdmi_sync_scdc() 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, as well as
the now unused output_{bpc,color_format} driver data members.
No functional change intended.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/vc4/vc4_hdmi.c | 230 +++++------------------------------------
drivers/gpu/drm/vc4/vc4_hdmi.h | 21 ----
2 files changed, 28 insertions(+), 223 deletions(-)
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index d599957fee3a..ec0c1f4224d7 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -35,7 +35,6 @@
#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>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_edid.h>
@@ -114,22 +113,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 int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused)
{
struct drm_debugfs_entry *entry = m->private;
@@ -263,115 +246,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 = drm_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 int 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;
-
- /*
- * 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, ctx, status);
-
- if (status != connector_status_connected)
- return 0;
-
- return vc4_hdmi_reset_link(connector, ctx);
-}
-
static int vc4_hdmi_connector_detect_ctx(struct drm_connector *connector,
struct drm_modeset_acquire_ctx *ctx,
bool force)
@@ -383,8 +257,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() 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
@@ -407,7 +281,8 @@ static int vc4_hdmi_connector_detect_ctx(struct drm_connector *connector,
status = connector_status_connected;
}
- ret = vc4_hdmi_handle_hotplug(vc4_hdmi, ctx, status);
+ ret = drm_atomic_helper_connector_hdmi_hotplug(connector, ctx, status);
+
pm_runtime_put(&vc4_hdmi->pdev->dev);
return ret == -EDEADLK ? ret : status;
@@ -534,6 +409,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_connector_hdmi_disable_scrambling() will thus run at boot,
+ * make sure it's disabled, and avoid any inconsistency.
+ */
+ connector->hdmi.scrambler_enabled = drm_connector_hdmi_scrambler_supported(connector);
+
/*
* Some of the properties below require access to state, like bpc.
* Allocate some default initial connector state with our reset helper.
@@ -759,32 +642,15 @@ 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 vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
struct drm_device *drm = connector->dev;
- const struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode;
unsigned long flags;
int idx;
- lockdep_assert_held(&vc4_hdmi->mutex);
-
- if (!vc4_hdmi_supports_scrambling(vc4_hdmi))
- return;
-
- if (!drm_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);
+ return -ENODEV;
spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
HDMI_WRITE(HDMI_SCRAMBLER_CTL, HDMI_READ(HDMI_SCRAMBLER_CTL) |
@@ -793,59 +659,27 @@ static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder)
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 vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
struct drm_device *drm = connector->dev;
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;
+ return -ENODEV;
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,
@@ -890,7 +724,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_connector_hdmi_disable_scrambling(&vc4_hdmi->connector);
drm_dev_exit(idx);
@@ -1598,6 +1432,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;
@@ -1666,7 +1501,9 @@ 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);
+ drm_connector_hdmi_enable_scrambling(connector, conn_state);
drm_dev_exit(idx);
@@ -1683,8 +1520,6 @@ static void vc4_hdmi_encoder_atomic_mode_set(struct drm_encoder *encoder,
mutex_lock(&vc4_hdmi->mutex);
drm_mode_copy(&vc4_hdmi->saved_adjusted_mode,
&crtc_state->adjusted_mode);
- vc4_hdmi->output_bpc = conn_state->hdmi.output_bpc;
- vc4_hdmi->output_format = conn_state->hdmi.output_format;
mutex_unlock(&vc4_hdmi->mutex);
}
@@ -1754,8 +1589,9 @@ static const struct drm_connector_hdmi_funcs vc4_hdmi_connector_funcs_hdmi14 = {
static const struct drm_connector_hdmi_funcs vc4_hdmi_connector_funcs_hdmi20 = {
VC4_HDMI_CONNECTOR_FUNCS_COMMON,
.max_bpc = 12,
- /* TODO: set HDMI_VERSION_2_0 and convert to common scrambler infra */
- .supported_hdmi_ver = HDMI_VERSION_UNKNOWN,
+ .supported_hdmi_ver = HDMI_VERSION_2_0,
+ .scrambler_enable = vc4_hdmi_scrambler_enable,
+ .scrambler_disable = vc4_hdmi_scrambler_disable,
};
#define WIFI_2_4GHz_CH1_MIN_FREQ 2400000000ULL
@@ -3229,7 +3065,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;
@@ -3242,15 +3077,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 d5ffcc17de32..f6159c9e6144 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,25 +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.
- */
- unsigned int output_bpc;
-
- /**
- * @output_format: Copy of
- * @drm_connector_state.hdmi.output_format for use outside of
- * KMS hooks. Protected by @mutex.
- */
- enum drm_output_color_format output_format;
-
/**
* @hdmi_jack: Represents the connection state of the HDMI plug, for
* ALSA jack detection.
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 45/69] drm/vc4: hdmi: Convert to common HDMI 2.0 scrambling infrastructure
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
Replace driver local scrambling logic with the newly introduced common
HDMI 2.0 scrambling support:
- Advertise source-side scrambling capability by setting supported HDMI
version based on the variant's max_pixel_clock.
- Provide minimal .scrambler_{enable,disable} connector callbacks that
only toggle the VC5 HDMI_SCRAMBLER_CTL register, while delegating
sink-side SCDC programming and periodic status monitoring to
drm_connector_hdmi_{enable,disable}_scrambling().
- Drop vc4_hdmi_reset_link() and vc4_hdmi_handle_hotplug(), switching
the .detect_ctx() path to drm_atomic_helper_connector_hdmi_hotplug()
which internally calls drm_connector_hdmi_sync_scdc() 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, as well as
the now unused output_{bpc,color_format} driver data members.
No functional change intended.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/vc4/vc4_hdmi.c | 230 +++++------------------------------------
drivers/gpu/drm/vc4/vc4_hdmi.h | 21 ----
2 files changed, 28 insertions(+), 223 deletions(-)
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index d599957fee3a..ec0c1f4224d7 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -35,7 +35,6 @@
#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>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_edid.h>
@@ -114,22 +113,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 int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused)
{
struct drm_debugfs_entry *entry = m->private;
@@ -263,115 +246,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 = drm_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 int 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;
-
- /*
- * 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, ctx, status);
-
- if (status != connector_status_connected)
- return 0;
-
- return vc4_hdmi_reset_link(connector, ctx);
-}
-
static int vc4_hdmi_connector_detect_ctx(struct drm_connector *connector,
struct drm_modeset_acquire_ctx *ctx,
bool force)
@@ -383,8 +257,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() 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
@@ -407,7 +281,8 @@ static int vc4_hdmi_connector_detect_ctx(struct drm_connector *connector,
status = connector_status_connected;
}
- ret = vc4_hdmi_handle_hotplug(vc4_hdmi, ctx, status);
+ ret = drm_atomic_helper_connector_hdmi_hotplug(connector, ctx, status);
+
pm_runtime_put(&vc4_hdmi->pdev->dev);
return ret == -EDEADLK ? ret : status;
@@ -534,6 +409,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_connector_hdmi_disable_scrambling() will thus run at boot,
+ * make sure it's disabled, and avoid any inconsistency.
+ */
+ connector->hdmi.scrambler_enabled = drm_connector_hdmi_scrambler_supported(connector);
+
/*
* Some of the properties below require access to state, like bpc.
* Allocate some default initial connector state with our reset helper.
@@ -759,32 +642,15 @@ 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 vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
struct drm_device *drm = connector->dev;
- const struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode;
unsigned long flags;
int idx;
- lockdep_assert_held(&vc4_hdmi->mutex);
-
- if (!vc4_hdmi_supports_scrambling(vc4_hdmi))
- return;
-
- if (!drm_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);
+ return -ENODEV;
spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
HDMI_WRITE(HDMI_SCRAMBLER_CTL, HDMI_READ(HDMI_SCRAMBLER_CTL) |
@@ -793,59 +659,27 @@ static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder)
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 vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
struct drm_device *drm = connector->dev;
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;
+ return -ENODEV;
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,
@@ -890,7 +724,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_connector_hdmi_disable_scrambling(&vc4_hdmi->connector);
drm_dev_exit(idx);
@@ -1598,6 +1432,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;
@@ -1666,7 +1501,9 @@ 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);
+ drm_connector_hdmi_enable_scrambling(connector, conn_state);
drm_dev_exit(idx);
@@ -1683,8 +1520,6 @@ static void vc4_hdmi_encoder_atomic_mode_set(struct drm_encoder *encoder,
mutex_lock(&vc4_hdmi->mutex);
drm_mode_copy(&vc4_hdmi->saved_adjusted_mode,
&crtc_state->adjusted_mode);
- vc4_hdmi->output_bpc = conn_state->hdmi.output_bpc;
- vc4_hdmi->output_format = conn_state->hdmi.output_format;
mutex_unlock(&vc4_hdmi->mutex);
}
@@ -1754,8 +1589,9 @@ static const struct drm_connector_hdmi_funcs vc4_hdmi_connector_funcs_hdmi14 = {
static const struct drm_connector_hdmi_funcs vc4_hdmi_connector_funcs_hdmi20 = {
VC4_HDMI_CONNECTOR_FUNCS_COMMON,
.max_bpc = 12,
- /* TODO: set HDMI_VERSION_2_0 and convert to common scrambler infra */
- .supported_hdmi_ver = HDMI_VERSION_UNKNOWN,
+ .supported_hdmi_ver = HDMI_VERSION_2_0,
+ .scrambler_enable = vc4_hdmi_scrambler_enable,
+ .scrambler_disable = vc4_hdmi_scrambler_disable,
};
#define WIFI_2_4GHz_CH1_MIN_FREQ 2400000000ULL
@@ -3229,7 +3065,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;
@@ -3242,15 +3077,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 d5ffcc17de32..f6159c9e6144 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,25 +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.
- */
- unsigned int output_bpc;
-
- /**
- * @output_format: Copy of
- * @drm_connector_state.hdmi.output_format for use outside of
- * KMS hooks. Protected by @mutex.
- */
- enum drm_output_color_format output_format;
-
/**
* @hdmi_jack: Represents the connection state of the HDMI plug, for
* ALSA jack detection.
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 46/69] drm/vc4: hdmi: Defer pixel clock validation to HDMI helpers
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
drm_atomic_helper_connector_hdmi_check() rejects modes whose computed
TMDS character rate exceeds the connector limit before invoking the
driver's .tmds_char_rate_valid() hook.
BCM2835 is capped at 162 MHz, slightly below the 165 MHz limit of HDMI
1.2. Set supported_tmds_char_rate in vc4_hdmi_connector_funcs_hdmi10 so
that the limit inferred from supported_hdmi_ver is overridden by the
lower hardware constraint. All other chip variants rely on the standard
HDMI 1.4/2.0 limits, so the default validation suffices.
This allows vc4_hdmi_connector_clock_valid() to be simplified by
dropping the now-redundant max_pixel_clock field from struct
vc4_hdmi_variant.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/vc4/vc4_hdmi.c | 10 +---------
drivers/gpu/drm/vc4/vc4_hdmi.h | 3 ---
2 files changed, 1 insertion(+), 12 deletions(-)
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index ec0c1f4224d7..12d0adc3cb1f 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -1528,12 +1528,8 @@ vc4_hdmi_connector_clock_valid(const struct drm_connector *connector,
const struct drm_display_mode *mode,
unsigned long long clock)
{
- const struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
struct vc4_dev *vc4 = to_vc4_dev(connector->dev);
- if (clock > vc4_hdmi->variant->max_pixel_clock)
- return MODE_CLOCK_HIGH;
-
if (!vc4->hvs->vc5_hdmi_enable_hdmi_20 && clock > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ)
return MODE_CLOCK_HIGH;
@@ -1578,6 +1574,7 @@ static const struct drm_connector_hdmi_funcs vc4_hdmi_connector_funcs_hdmi12 = {
VC4_HDMI_CONNECTOR_FUNCS_COMMON,
.max_bpc = 8,
.supported_hdmi_ver = HDMI_VERSION_1_2,
+ .supported_tmds_char_rate = 162000000,
};
static const struct drm_connector_hdmi_funcs vc4_hdmi_connector_funcs_hdmi14 = {
@@ -3184,7 +3181,6 @@ static const struct vc4_hdmi_variant bcm2835_variant = {
.encoder_type = VC4_ENCODER_TYPE_HDMI0,
.debugfs_name = "hdmi_regs",
.card_name = "vc4-hdmi",
- .max_pixel_clock = 162000000,
.registers = vc4_hdmi_fields,
.num_registers = ARRAY_SIZE(vc4_hdmi_fields),
@@ -3204,7 +3200,6 @@ 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 = HDMI_2_0_TMDS_CHAR_RATE_MAX_HZ,
.registers = vc5_hdmi_hdmi0_fields,
.num_registers = ARRAY_SIZE(vc5_hdmi_hdmi0_fields),
.phy_lane_mapping = {
@@ -3233,7 +3228,6 @@ 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_1_3_TMDS_CHAR_RATE_MAX_HZ,
.registers = vc5_hdmi_hdmi1_fields,
.num_registers = ARRAY_SIZE(vc5_hdmi_hdmi1_fields),
.phy_lane_mapping = {
@@ -3262,7 +3256,6 @@ 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 = HDMI_2_0_TMDS_CHAR_RATE_MAX_HZ,
.registers = vc6_hdmi_hdmi0_fields,
.num_registers = ARRAY_SIZE(vc6_hdmi_hdmi0_fields),
.phy_lane_mapping = {
@@ -3289,7 +3282,6 @@ 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 = HDMI_2_0_TMDS_CHAR_RATE_MAX_HZ,
.registers = vc6_hdmi_hdmi1_fields,
.num_registers = ARRAY_SIZE(vc6_hdmi_hdmi1_fields),
.phy_lane_mapping = {
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h
index f6159c9e6144..61486e7b4ba2 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.h
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.h
@@ -29,9 +29,6 @@ struct vc4_hdmi_variant {
/* Filename to expose the registers in debugfs */
const char *debugfs_name;
- /* Maximum pixel clock supported by the controller (in Hz) */
- unsigned long long max_pixel_clock;
-
/* List of the registers available on that variant */
const struct vc4_hdmi_register *registers;
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 46/69] drm/vc4: hdmi: Defer pixel clock validation to HDMI helpers
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
drm_atomic_helper_connector_hdmi_check() rejects modes whose computed
TMDS character rate exceeds the connector limit before invoking the
driver's .tmds_char_rate_valid() hook.
BCM2835 is capped at 162 MHz, slightly below the 165 MHz limit of HDMI
1.2. Set supported_tmds_char_rate in vc4_hdmi_connector_funcs_hdmi10 so
that the limit inferred from supported_hdmi_ver is overridden by the
lower hardware constraint. All other chip variants rely on the standard
HDMI 1.4/2.0 limits, so the default validation suffices.
This allows vc4_hdmi_connector_clock_valid() to be simplified by
dropping the now-redundant max_pixel_clock field from struct
vc4_hdmi_variant.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/vc4/vc4_hdmi.c | 10 +---------
drivers/gpu/drm/vc4/vc4_hdmi.h | 3 ---
2 files changed, 1 insertion(+), 12 deletions(-)
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index ec0c1f4224d7..12d0adc3cb1f 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -1528,12 +1528,8 @@ vc4_hdmi_connector_clock_valid(const struct drm_connector *connector,
const struct drm_display_mode *mode,
unsigned long long clock)
{
- const struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
struct vc4_dev *vc4 = to_vc4_dev(connector->dev);
- if (clock > vc4_hdmi->variant->max_pixel_clock)
- return MODE_CLOCK_HIGH;
-
if (!vc4->hvs->vc5_hdmi_enable_hdmi_20 && clock > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ)
return MODE_CLOCK_HIGH;
@@ -1578,6 +1574,7 @@ static const struct drm_connector_hdmi_funcs vc4_hdmi_connector_funcs_hdmi12 = {
VC4_HDMI_CONNECTOR_FUNCS_COMMON,
.max_bpc = 8,
.supported_hdmi_ver = HDMI_VERSION_1_2,
+ .supported_tmds_char_rate = 162000000,
};
static const struct drm_connector_hdmi_funcs vc4_hdmi_connector_funcs_hdmi14 = {
@@ -3184,7 +3181,6 @@ static const struct vc4_hdmi_variant bcm2835_variant = {
.encoder_type = VC4_ENCODER_TYPE_HDMI0,
.debugfs_name = "hdmi_regs",
.card_name = "vc4-hdmi",
- .max_pixel_clock = 162000000,
.registers = vc4_hdmi_fields,
.num_registers = ARRAY_SIZE(vc4_hdmi_fields),
@@ -3204,7 +3200,6 @@ 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 = HDMI_2_0_TMDS_CHAR_RATE_MAX_HZ,
.registers = vc5_hdmi_hdmi0_fields,
.num_registers = ARRAY_SIZE(vc5_hdmi_hdmi0_fields),
.phy_lane_mapping = {
@@ -3233,7 +3228,6 @@ 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_1_3_TMDS_CHAR_RATE_MAX_HZ,
.registers = vc5_hdmi_hdmi1_fields,
.num_registers = ARRAY_SIZE(vc5_hdmi_hdmi1_fields),
.phy_lane_mapping = {
@@ -3262,7 +3256,6 @@ 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 = HDMI_2_0_TMDS_CHAR_RATE_MAX_HZ,
.registers = vc6_hdmi_hdmi0_fields,
.num_registers = ARRAY_SIZE(vc6_hdmi_hdmi0_fields),
.phy_lane_mapping = {
@@ -3289,7 +3282,6 @@ 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 = HDMI_2_0_TMDS_CHAR_RATE_MAX_HZ,
.registers = vc6_hdmi_hdmi1_fields,
.num_registers = ARRAY_SIZE(vc6_hdmi_hdmi1_fields),
.phy_lane_mapping = {
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h
index f6159c9e6144..61486e7b4ba2 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.h
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.h
@@ -29,9 +29,6 @@ struct vc4_hdmi_variant {
/* Filename to expose the registers in debugfs */
const char *debugfs_name;
- /* Maximum pixel clock supported by the controller (in Hz) */
- unsigned long long max_pixel_clock;
-
/* List of the registers available on that variant */
const struct vc4_hdmi_register *registers;
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 47/69] drm/display: hdmi-state-helper: Drop drm_atomic_helper_connector_hdmi_force()
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
With all callers converted to the .force_ctx() connector helper, this
function has no users left. Remove it.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_hdmi_state_helper.c | 15 ---------------
include/drm/display/drm_hdmi_state_helper.h | 1 -
2 files changed, 16 deletions(-)
diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
index 9544eb8659aa..04c9e06b9dc1 100644
--- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
@@ -1261,21 +1261,6 @@ int drm_atomic_helper_connector_hdmi_hotplug(struct drm_connector *connector,
}
EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_hotplug);
-/**
- * drm_atomic_helper_connector_hdmi_force - HDMI Connector implementation of the force callback
- * @connector: A pointer to the HDMI connector
- *
- * This function implements the .force() callback for the HDMI connectors. It
- * can either be used directly as the callback or should be called from within
- * the .force() callback implementation to maintain the HDMI-specific
- * connector's data.
- */
-void drm_atomic_helper_connector_hdmi_force(struct drm_connector *connector)
-{
- drm_atomic_helper_connector_hdmi_update(connector, NULL, connector->status);
-}
-EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_force);
-
/**
* drm_atomic_helper_connector_hdmi_force_ctx - HDMI Connector implementation
* of the force_ctx callback
diff --git a/include/drm/display/drm_hdmi_state_helper.h b/include/drm/display/drm_hdmi_state_helper.h
index ae4fff82c3fb..81c85b4dce56 100644
--- a/include/drm/display/drm_hdmi_state_helper.h
+++ b/include/drm/display/drm_hdmi_state_helper.h
@@ -26,7 +26,6 @@ int drm_atomic_helper_connector_hdmi_update_infoframes(struct drm_connector *con
int drm_atomic_helper_connector_hdmi_hotplug(struct drm_connector *connector,
struct drm_modeset_acquire_ctx *ctx,
enum drm_connector_status status);
-void drm_atomic_helper_connector_hdmi_force(struct drm_connector *connector);
int drm_atomic_helper_connector_hdmi_force_ctx(struct drm_connector *connector,
struct drm_modeset_acquire_ctx *ctx);
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 47/69] drm/display: hdmi-state-helper: Drop drm_atomic_helper_connector_hdmi_force()
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
With all callers converted to the .force_ctx() connector helper, this
function has no users left. Remove it.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_hdmi_state_helper.c | 15 ---------------
include/drm/display/drm_hdmi_state_helper.h | 1 -
2 files changed, 16 deletions(-)
diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
index 9544eb8659aa..04c9e06b9dc1 100644
--- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
@@ -1261,21 +1261,6 @@ int drm_atomic_helper_connector_hdmi_hotplug(struct drm_connector *connector,
}
EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_hotplug);
-/**
- * drm_atomic_helper_connector_hdmi_force - HDMI Connector implementation of the force callback
- * @connector: A pointer to the HDMI connector
- *
- * This function implements the .force() callback for the HDMI connectors. It
- * can either be used directly as the callback or should be called from within
- * the .force() callback implementation to maintain the HDMI-specific
- * connector's data.
- */
-void drm_atomic_helper_connector_hdmi_force(struct drm_connector *connector)
-{
- drm_atomic_helper_connector_hdmi_update(connector, NULL, connector->status);
-}
-EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_force);
-
/**
* drm_atomic_helper_connector_hdmi_force_ctx - HDMI Connector implementation
* of the force_ctx callback
diff --git a/include/drm/display/drm_hdmi_state_helper.h b/include/drm/display/drm_hdmi_state_helper.h
index ae4fff82c3fb..81c85b4dce56 100644
--- a/include/drm/display/drm_hdmi_state_helper.h
+++ b/include/drm/display/drm_hdmi_state_helper.h
@@ -26,7 +26,6 @@ int drm_atomic_helper_connector_hdmi_update_infoframes(struct drm_connector *con
int drm_atomic_helper_connector_hdmi_hotplug(struct drm_connector *connector,
struct drm_modeset_acquire_ctx *ctx,
enum drm_connector_status status);
-void drm_atomic_helper_connector_hdmi_force(struct drm_connector *connector);
int drm_atomic_helper_connector_hdmi_force_ctx(struct drm_connector *connector,
struct drm_modeset_acquire_ctx *ctx);
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 48/69] drm/bridge: adv7511: Advertise HDMI 1.2 capabilities
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
Bridges using DRM_BRIDGE_OP_HDMI are now expected to also provide a
supported HDMI version. This is not yet enforced, but will become
mandatory once the migration to the new caps-based HDMI connector
initialization API is completed.
Since max_mode_clock_khz does not exceed 165 MHz for any of the chip
variants handled by the driver, advertise HDMI 1.2 as the supported
version and set the bridge's max_tmds_char_rate so the connector limit
inferred from supported_hdmi_ver is overridden by the chip-specific
hardware constraints.
drm_bridge_connector_atomic_check() runs
drm_atomic_helper_connector_hdmi_check(), which rejects modes whose
computed TMDS character rate exceeds the connector limit before invoking
the driver's .tmds_char_rate_valid() hook, making
adv7511_bridge_hdmi_tmds_char_rate_valid() redundant. Drop it.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 22 +++-------------------
1 file changed, 3 insertions(+), 19 deletions(-)
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
index 038b852405b5..c3ef44074477 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
@@ -8,6 +8,7 @@
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/gpio/consumer.h>
+#include <linux/hdmi.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/slab.h>
@@ -775,11 +776,6 @@ static int adv7511_connector_init(struct adv7511 *adv)
* DRM Bridge Operations
*/
-static const struct adv7511 *bridge_to_adv7511_const(const struct drm_bridge *bridge)
-{
- return container_of(bridge, struct adv7511, bridge);
-}
-
static void adv7511_bridge_atomic_enable(struct drm_bridge *bridge,
struct drm_atomic_commit *state)
{
@@ -817,19 +813,6 @@ static void adv7511_bridge_atomic_disable(struct drm_bridge *bridge,
adv7511_power_off(adv);
}
-static enum drm_mode_status
-adv7511_bridge_hdmi_tmds_char_rate_valid(const struct drm_bridge *bridge,
- const struct drm_display_mode *mode,
- unsigned long long tmds_rate)
-{
- const struct adv7511 *adv = bridge_to_adv7511_const(bridge);
-
- if (tmds_rate > 1000ULL * adv->info->max_mode_clock_khz)
- return MODE_CLOCK_HIGH;
-
- return MODE_OK;
-}
-
static enum drm_mode_status adv7511_bridge_mode_valid(struct drm_bridge *bridge,
const struct drm_display_info *info,
const struct drm_display_mode *mode)
@@ -1006,7 +989,6 @@ static const struct drm_bridge_funcs adv7511_bridge_funcs = {
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
.atomic_create_state = drm_atomic_helper_bridge_create_state,
- .hdmi_tmds_char_rate_valid = adv7511_bridge_hdmi_tmds_char_rate_valid,
.hdmi_clear_audio_infoframe = adv7511_bridge_hdmi_clear_audio_infoframe,
.hdmi_write_audio_infoframe = adv7511_bridge_hdmi_write_audio_infoframe,
.hdmi_clear_avi_infoframe = adv7511_bridge_hdmi_clear_avi_infoframe,
@@ -1359,6 +1341,8 @@ static int adv7511_probe(struct i2c_client *i2c)
adv7511->bridge.vendor = "Analog";
adv7511->bridge.product = adv7511->info->name;
+ adv7511->bridge.supported_hdmi_ver = HDMI_VERSION_1_2;
+ adv7511->bridge.max_tmds_char_rate = 1000ULL * adv7511->info->max_mode_clock_khz;
#ifdef CONFIG_DRM_I2C_ADV7511_AUDIO
adv7511->bridge.ops |= DRM_BRIDGE_OP_HDMI_AUDIO;
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 48/69] drm/bridge: adv7511: Advertise HDMI 1.2 capabilities
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
Bridges using DRM_BRIDGE_OP_HDMI are now expected to also provide a
supported HDMI version. This is not yet enforced, but will become
mandatory once the migration to the new caps-based HDMI connector
initialization API is completed.
Since max_mode_clock_khz does not exceed 165 MHz for any of the chip
variants handled by the driver, advertise HDMI 1.2 as the supported
version and set the bridge's max_tmds_char_rate so the connector limit
inferred from supported_hdmi_ver is overridden by the chip-specific
hardware constraints.
drm_bridge_connector_atomic_check() runs
drm_atomic_helper_connector_hdmi_check(), which rejects modes whose
computed TMDS character rate exceeds the connector limit before invoking
the driver's .tmds_char_rate_valid() hook, making
adv7511_bridge_hdmi_tmds_char_rate_valid() redundant. Drop it.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 22 +++-------------------
1 file changed, 3 insertions(+), 19 deletions(-)
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
index 038b852405b5..c3ef44074477 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
@@ -8,6 +8,7 @@
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/gpio/consumer.h>
+#include <linux/hdmi.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/slab.h>
@@ -775,11 +776,6 @@ static int adv7511_connector_init(struct adv7511 *adv)
* DRM Bridge Operations
*/
-static const struct adv7511 *bridge_to_adv7511_const(const struct drm_bridge *bridge)
-{
- return container_of(bridge, struct adv7511, bridge);
-}
-
static void adv7511_bridge_atomic_enable(struct drm_bridge *bridge,
struct drm_atomic_commit *state)
{
@@ -817,19 +813,6 @@ static void adv7511_bridge_atomic_disable(struct drm_bridge *bridge,
adv7511_power_off(adv);
}
-static enum drm_mode_status
-adv7511_bridge_hdmi_tmds_char_rate_valid(const struct drm_bridge *bridge,
- const struct drm_display_mode *mode,
- unsigned long long tmds_rate)
-{
- const struct adv7511 *adv = bridge_to_adv7511_const(bridge);
-
- if (tmds_rate > 1000ULL * adv->info->max_mode_clock_khz)
- return MODE_CLOCK_HIGH;
-
- return MODE_OK;
-}
-
static enum drm_mode_status adv7511_bridge_mode_valid(struct drm_bridge *bridge,
const struct drm_display_info *info,
const struct drm_display_mode *mode)
@@ -1006,7 +989,6 @@ static const struct drm_bridge_funcs adv7511_bridge_funcs = {
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
.atomic_create_state = drm_atomic_helper_bridge_create_state,
- .hdmi_tmds_char_rate_valid = adv7511_bridge_hdmi_tmds_char_rate_valid,
.hdmi_clear_audio_infoframe = adv7511_bridge_hdmi_clear_audio_infoframe,
.hdmi_write_audio_infoframe = adv7511_bridge_hdmi_write_audio_infoframe,
.hdmi_clear_avi_infoframe = adv7511_bridge_hdmi_clear_avi_infoframe,
@@ -1359,6 +1341,8 @@ static int adv7511_probe(struct i2c_client *i2c)
adv7511->bridge.vendor = "Analog";
adv7511->bridge.product = adv7511->info->name;
+ adv7511->bridge.supported_hdmi_ver = HDMI_VERSION_1_2;
+ adv7511->bridge.max_tmds_char_rate = 1000ULL * adv7511->info->max_mode_clock_khz;
#ifdef CONFIG_DRM_I2C_ADV7511_AUDIO
adv7511->bridge.ops |= DRM_BRIDGE_OP_HDMI_AUDIO;
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 49/69] drm/bridge: inno-hdmi: Advertise HDMI 1.2 capabilities
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
Bridges using DRM_BRIDGE_OP_HDMI are now expected to also provide a
supported HDMI version. This is not yet enforced, but will become
mandatory once the migration to the new caps-based HDMI connector
initialization API is completed.
Since inno_hdmi_phy_config.pixelclock does not exceed 165 MHz for any of
the chip variants handled by the driver, advertise HDMI 1.2 as the
supported version.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/bridge/inno-hdmi.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/gpu/drm/bridge/inno-hdmi.c b/drivers/gpu/drm/bridge/inno-hdmi.c
index dd35f5a875d3..ea3447d4f285 100644
--- a/drivers/gpu/drm/bridge/inno-hdmi.c
+++ b/drivers/gpu/drm/bridge/inno-hdmi.c
@@ -1119,6 +1119,7 @@ struct inno_hdmi *inno_hdmi_bind(struct device *dev,
hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
hdmi->bridge.vendor = "Inno";
hdmi->bridge.product = "Inno HDMI";
+ hdmi->bridge.supported_hdmi_ver = HDMI_VERSION_1_2;
hdmi->bridge.ddc = inno_hdmi_i2c_adapter(hdmi);
if (IS_ERR(hdmi->bridge.ddc))
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 49/69] drm/bridge: inno-hdmi: Advertise HDMI 1.2 capabilities
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
Bridges using DRM_BRIDGE_OP_HDMI are now expected to also provide a
supported HDMI version. This is not yet enforced, but will become
mandatory once the migration to the new caps-based HDMI connector
initialization API is completed.
Since inno_hdmi_phy_config.pixelclock does not exceed 165 MHz for any of
the chip variants handled by the driver, advertise HDMI 1.2 as the
supported version.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/bridge/inno-hdmi.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/gpu/drm/bridge/inno-hdmi.c b/drivers/gpu/drm/bridge/inno-hdmi.c
index dd35f5a875d3..ea3447d4f285 100644
--- a/drivers/gpu/drm/bridge/inno-hdmi.c
+++ b/drivers/gpu/drm/bridge/inno-hdmi.c
@@ -1119,6 +1119,7 @@ struct inno_hdmi *inno_hdmi_bind(struct device *dev,
hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
hdmi->bridge.vendor = "Inno";
hdmi->bridge.product = "Inno HDMI";
+ hdmi->bridge.supported_hdmi_ver = HDMI_VERSION_1_2;
hdmi->bridge.ddc = inno_hdmi_i2c_adapter(hdmi);
if (IS_ERR(hdmi->bridge.ddc))
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 50/69] drm/bridge: ite-it6263: Drop redundant .mode_valid hook
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
Bridges using DRM_BRIDGE_OP_HDMI expect connectors to be created through
drm_bridge_connector_init(), thereby relying on the bridge connector's
.mode_valid hook to invoke drm_hdmi_connector_mode_valid().
The generic helper computes the mode's TMDS character rate and forwards
it to the bridge's .hdmi_tmds_char_rate_valid callback through the
connector HDMI funcs. This covers exactly what
it6263_bridge_mode_valid() does for 8 bpc RGB444, but due to being
output-format aware, it also handles the validation more thoroughly.
Both the connector and bridge .mode_valid hooks are invoked during
mode validation through drm_mode_validate_pipeline(), so the custom
bridge hook is redundant. Drop it.
While at it, remove the now-unused drm_hdmi_helper.h include.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/bridge/ite-it6263.c | 16 ----------------
1 file changed, 16 deletions(-)
diff --git a/drivers/gpu/drm/bridge/ite-it6263.c b/drivers/gpu/drm/bridge/ite-it6263.c
index 21ac8e58b9d2..550999491086 100644
--- a/drivers/gpu/drm/bridge/ite-it6263.c
+++ b/drivers/gpu/drm/bridge/ite-it6263.c
@@ -15,7 +15,6 @@
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
-#include <drm/display/drm_hdmi_helper.h>
#include <drm/display/drm_hdmi_state_helper.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
@@ -669,20 +668,6 @@ static void it6263_bridge_atomic_enable(struct drm_bridge *bridge,
regmap_write(regmap, HDMI_REG_PKT_GENERAL_CTRL, ENABLE_PKT | REPEAT_PKT);
}
-static enum drm_mode_status
-it6263_bridge_mode_valid(struct drm_bridge *bridge,
- const struct drm_display_info *info,
- const struct drm_display_mode *mode)
-{
- unsigned long long rate;
-
- rate = drm_hdmi_compute_mode_clock(mode, 8, DRM_OUTPUT_COLOR_FORMAT_RGB444);
- if (rate == 0)
- return MODE_NOCLOCK;
-
- return bridge->funcs->hdmi_tmds_char_rate_valid(bridge, mode, rate);
-}
-
static int it6263_bridge_attach(struct drm_bridge *bridge,
struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
@@ -831,7 +816,6 @@ static const struct drm_bridge_funcs it6263_bridge_funcs = {
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
.atomic_create_state = drm_atomic_helper_bridge_create_state,
.attach = it6263_bridge_attach,
- .mode_valid = it6263_bridge_mode_valid,
.atomic_disable = it6263_bridge_atomic_disable,
.atomic_enable = it6263_bridge_atomic_enable,
.detect = it6263_bridge_detect,
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 50/69] drm/bridge: ite-it6263: Drop redundant .mode_valid hook
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
Bridges using DRM_BRIDGE_OP_HDMI expect connectors to be created through
drm_bridge_connector_init(), thereby relying on the bridge connector's
.mode_valid hook to invoke drm_hdmi_connector_mode_valid().
The generic helper computes the mode's TMDS character rate and forwards
it to the bridge's .hdmi_tmds_char_rate_valid callback through the
connector HDMI funcs. This covers exactly what
it6263_bridge_mode_valid() does for 8 bpc RGB444, but due to being
output-format aware, it also handles the validation more thoroughly.
Both the connector and bridge .mode_valid hooks are invoked during
mode validation through drm_mode_validate_pipeline(), so the custom
bridge hook is redundant. Drop it.
While at it, remove the now-unused drm_hdmi_helper.h include.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/bridge/ite-it6263.c | 16 ----------------
1 file changed, 16 deletions(-)
diff --git a/drivers/gpu/drm/bridge/ite-it6263.c b/drivers/gpu/drm/bridge/ite-it6263.c
index 21ac8e58b9d2..550999491086 100644
--- a/drivers/gpu/drm/bridge/ite-it6263.c
+++ b/drivers/gpu/drm/bridge/ite-it6263.c
@@ -15,7 +15,6 @@
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
-#include <drm/display/drm_hdmi_helper.h>
#include <drm/display/drm_hdmi_state_helper.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
@@ -669,20 +668,6 @@ static void it6263_bridge_atomic_enable(struct drm_bridge *bridge,
regmap_write(regmap, HDMI_REG_PKT_GENERAL_CTRL, ENABLE_PKT | REPEAT_PKT);
}
-static enum drm_mode_status
-it6263_bridge_mode_valid(struct drm_bridge *bridge,
- const struct drm_display_info *info,
- const struct drm_display_mode *mode)
-{
- unsigned long long rate;
-
- rate = drm_hdmi_compute_mode_clock(mode, 8, DRM_OUTPUT_COLOR_FORMAT_RGB444);
- if (rate == 0)
- return MODE_NOCLOCK;
-
- return bridge->funcs->hdmi_tmds_char_rate_valid(bridge, mode, rate);
-}
-
static int it6263_bridge_attach(struct drm_bridge *bridge,
struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
@@ -831,7 +816,6 @@ static const struct drm_bridge_funcs it6263_bridge_funcs = {
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
.atomic_create_state = drm_atomic_helper_bridge_create_state,
.attach = it6263_bridge_attach,
- .mode_valid = it6263_bridge_mode_valid,
.atomic_disable = it6263_bridge_atomic_disable,
.atomic_enable = it6263_bridge_atomic_enable,
.detect = it6263_bridge_detect,
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 51/69] drm/bridge: ite-it6263: Advertise HDMI 1.3 capabilities
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
Bridges using DRM_BRIDGE_OP_HDMI are expected to provide the supported
HDMI version. This is not enforced yet, but will become mandatory once
the migration to the caps-based HDMI connector initialization API is
complete.
Advertise HDMI 1.3 support for IT6263, covering the 225 MHz TMDS
character rate currently documented by the driver, which is within the
HDMI 1.3 limit of 340 MHz. Additionally, keep the stricter 150 MHz
effective mode limit by setting max_tmds_char_rate from
MAX_PIXEL_CLOCK_KHZ.
The existing .hdmi_tmds_char_rate_valid() hook checks both the pixel
clock and TMDS character rate. Since the bridge only supports 8 bpc
RGB444, these are equivalent for supported modes, making the 225 MHz
TMDS rate check unreachable once the 150 MHz pixel-clock limit is
applied.
drm_bridge_connector_atomic_check() invokes
drm_atomic_helper_connector_hdmi_check(), which rejects modes whose
computed TMDS character rate exceeds the connector's max_tmds_char_rate
before invoking the driver's .tmds_char_rate_valid hook. Since
max_tmds_char_rate now carries the existing effective limit,
it6263_hdmi_tmds_char_rate_valid() is redundant. Drop it.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/bridge/ite-it6263.c | 17 ++---------------
1 file changed, 2 insertions(+), 15 deletions(-)
diff --git a/drivers/gpu/drm/bridge/ite-it6263.c b/drivers/gpu/drm/bridge/ite-it6263.c
index 550999491086..e8e0197171e1 100644
--- a/drivers/gpu/drm/bridge/ite-it6263.c
+++ b/drivers/gpu/drm/bridge/ite-it6263.c
@@ -738,20 +738,6 @@ it6263_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
return input_fmts;
}
-static enum drm_mode_status
-it6263_hdmi_tmds_char_rate_valid(const struct drm_bridge *bridge,
- const struct drm_display_mode *mode,
- unsigned long long tmds_rate)
-{
- if (mode->clock > MAX_PIXEL_CLOCK_KHZ)
- return MODE_CLOCK_HIGH;
-
- if (tmds_rate > MAX_HDMI_TMDS_CHAR_RATE_HZ)
- return MODE_CLOCK_HIGH;
-
- return MODE_OK;
-}
-
static int it6263_hdmi_clear_avi_infoframe(struct drm_bridge *bridge)
{
struct it6263 *it = bridge_to_it6263(bridge);
@@ -821,7 +807,6 @@ static const struct drm_bridge_funcs it6263_bridge_funcs = {
.detect = it6263_bridge_detect,
.edid_read = it6263_bridge_edid_read,
.atomic_get_input_bus_fmts = it6263_bridge_atomic_get_input_bus_fmts,
- .hdmi_tmds_char_rate_valid = it6263_hdmi_tmds_char_rate_valid,
.hdmi_clear_avi_infoframe = it6263_hdmi_clear_avi_infoframe,
.hdmi_write_avi_infoframe = it6263_hdmi_write_avi_infoframe,
.hdmi_clear_hdmi_infoframe = it6263_hdmi_clear_hdmi_infoframe,
@@ -883,6 +868,8 @@ static int it6263_probe(struct i2c_client *client)
it->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
it->bridge.vendor = "ITE";
it->bridge.product = "IT6263";
+ it->bridge.supported_hdmi_ver = HDMI_VERSION_1_3;
+ it->bridge.max_tmds_char_rate = 1000ULL * MAX_PIXEL_CLOCK_KHZ;
return devm_drm_bridge_add(dev, &it->bridge);
}
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 51/69] drm/bridge: ite-it6263: Advertise HDMI 1.3 capabilities
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
Bridges using DRM_BRIDGE_OP_HDMI are expected to provide the supported
HDMI version. This is not enforced yet, but will become mandatory once
the migration to the caps-based HDMI connector initialization API is
complete.
Advertise HDMI 1.3 support for IT6263, covering the 225 MHz TMDS
character rate currently documented by the driver, which is within the
HDMI 1.3 limit of 340 MHz. Additionally, keep the stricter 150 MHz
effective mode limit by setting max_tmds_char_rate from
MAX_PIXEL_CLOCK_KHZ.
The existing .hdmi_tmds_char_rate_valid() hook checks both the pixel
clock and TMDS character rate. Since the bridge only supports 8 bpc
RGB444, these are equivalent for supported modes, making the 225 MHz
TMDS rate check unreachable once the 150 MHz pixel-clock limit is
applied.
drm_bridge_connector_atomic_check() invokes
drm_atomic_helper_connector_hdmi_check(), which rejects modes whose
computed TMDS character rate exceeds the connector's max_tmds_char_rate
before invoking the driver's .tmds_char_rate_valid hook. Since
max_tmds_char_rate now carries the existing effective limit,
it6263_hdmi_tmds_char_rate_valid() is redundant. Drop it.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/bridge/ite-it6263.c | 17 ++---------------
1 file changed, 2 insertions(+), 15 deletions(-)
diff --git a/drivers/gpu/drm/bridge/ite-it6263.c b/drivers/gpu/drm/bridge/ite-it6263.c
index 550999491086..e8e0197171e1 100644
--- a/drivers/gpu/drm/bridge/ite-it6263.c
+++ b/drivers/gpu/drm/bridge/ite-it6263.c
@@ -738,20 +738,6 @@ it6263_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
return input_fmts;
}
-static enum drm_mode_status
-it6263_hdmi_tmds_char_rate_valid(const struct drm_bridge *bridge,
- const struct drm_display_mode *mode,
- unsigned long long tmds_rate)
-{
- if (mode->clock > MAX_PIXEL_CLOCK_KHZ)
- return MODE_CLOCK_HIGH;
-
- if (tmds_rate > MAX_HDMI_TMDS_CHAR_RATE_HZ)
- return MODE_CLOCK_HIGH;
-
- return MODE_OK;
-}
-
static int it6263_hdmi_clear_avi_infoframe(struct drm_bridge *bridge)
{
struct it6263 *it = bridge_to_it6263(bridge);
@@ -821,7 +807,6 @@ static const struct drm_bridge_funcs it6263_bridge_funcs = {
.detect = it6263_bridge_detect,
.edid_read = it6263_bridge_edid_read,
.atomic_get_input_bus_fmts = it6263_bridge_atomic_get_input_bus_fmts,
- .hdmi_tmds_char_rate_valid = it6263_hdmi_tmds_char_rate_valid,
.hdmi_clear_avi_infoframe = it6263_hdmi_clear_avi_infoframe,
.hdmi_write_avi_infoframe = it6263_hdmi_write_avi_infoframe,
.hdmi_clear_hdmi_infoframe = it6263_hdmi_clear_hdmi_infoframe,
@@ -883,6 +868,8 @@ static int it6263_probe(struct i2c_client *client)
it->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
it->bridge.vendor = "ITE";
it->bridge.product = "IT6263";
+ it->bridge.supported_hdmi_ver = HDMI_VERSION_1_3;
+ it->bridge.max_tmds_char_rate = 1000ULL * MAX_PIXEL_CLOCK_KHZ;
return devm_drm_bridge_add(dev, &it->bridge);
}
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 52/69] drm/bridge: ite-it66121: Advertise HDMI 1.2 capabilities
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:19 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
Bridges using DRM_BRIDGE_OP_HDMI are now expected to also provide a
supported HDMI version. This is not yet enforced, but will become
mandatory once the migration to the new caps-based HDMI connector
initialization API is completed.
Since none of the chip variants handled by the driver can drive a TMDS
character rate exceeding 148.5 MHz, advertise HDMI 1.2 as the supported
version. HDMI 1.2 allows up to 165 MHz, so set the bridge's
max_tmds_char_rate to ensure the connector limit derived from
supported_hdmi_ver remains within the hardware capabilities.
drm_bridge_connector_atomic_check() runs
drm_atomic_helper_connector_hdmi_check(), which rejects modes whose
computed TMDS character rate exceeds the connector limit before invoking
the driver's .tmds_char_rate_valid() hook, making the max_rate check in
it66121_bridge_hdmi_tmds_char_rate_valid() redundant. Drop it.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/bridge/ite-it66121.c | 13 ++++---------
1 file changed, 4 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/bridge/ite-it66121.c b/drivers/gpu/drm/bridge/ite-it66121.c
index 51fc68ffdf8f..c8d0a26e8e90 100644
--- a/drivers/gpu/drm/bridge/ite-it66121.c
+++ b/drivers/gpu/drm/bridge/ite-it66121.c
@@ -10,6 +10,7 @@
#include <linux/media-bus-format.h>
#include <linux/module.h>
#include <linux/device.h>
+#include <linux/hdmi.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/bitfield.h>
@@ -867,15 +868,6 @@ it66121_bridge_hdmi_tmds_char_rate_valid(const struct drm_bridge *bridge,
const struct drm_display_mode *mode,
unsigned long long tmds_rate)
{
- const struct it66121_ctx *ctx =
- container_of(bridge, const struct it66121_ctx, bridge);
- unsigned long long max_rate;
-
- max_rate = (ctx->bus_width == 12) ? 74250000ULL : 148500000ULL;
-
- if (tmds_rate > max_rate)
- return MODE_CLOCK_HIGH;
-
if (tmds_rate < HDMI_TMDS_CHAR_RATE_MIN_HZ)
return MODE_CLOCK_LOW;
@@ -1670,6 +1662,9 @@ static int it66121_probe(struct i2c_client *client)
DRM_BRIDGE_OP_HDMI;
ctx->bridge.vendor = "ITE";
ctx->bridge.product = "IT66121";
+ ctx->bridge.supported_hdmi_ver = HDMI_VERSION_1_2;
+ ctx->bridge.max_tmds_char_rate = ctx->bus_width == 12 ? 74250000ULL : 148500000ULL;
+
if (client->irq > 0) {
ctx->bridge.ops |= DRM_BRIDGE_OP_HPD;
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 52/69] drm/bridge: ite-it66121: Advertise HDMI 1.2 capabilities
@ 2026-07-31 16:19 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:19 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
Bridges using DRM_BRIDGE_OP_HDMI are now expected to also provide a
supported HDMI version. This is not yet enforced, but will become
mandatory once the migration to the new caps-based HDMI connector
initialization API is completed.
Since none of the chip variants handled by the driver can drive a TMDS
character rate exceeding 148.5 MHz, advertise HDMI 1.2 as the supported
version. HDMI 1.2 allows up to 165 MHz, so set the bridge's
max_tmds_char_rate to ensure the connector limit derived from
supported_hdmi_ver remains within the hardware capabilities.
drm_bridge_connector_atomic_check() runs
drm_atomic_helper_connector_hdmi_check(), which rejects modes whose
computed TMDS character rate exceeds the connector limit before invoking
the driver's .tmds_char_rate_valid() hook, making the max_rate check in
it66121_bridge_hdmi_tmds_char_rate_valid() redundant. Drop it.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/bridge/ite-it66121.c | 13 ++++---------
1 file changed, 4 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/bridge/ite-it66121.c b/drivers/gpu/drm/bridge/ite-it66121.c
index 51fc68ffdf8f..c8d0a26e8e90 100644
--- a/drivers/gpu/drm/bridge/ite-it66121.c
+++ b/drivers/gpu/drm/bridge/ite-it66121.c
@@ -10,6 +10,7 @@
#include <linux/media-bus-format.h>
#include <linux/module.h>
#include <linux/device.h>
+#include <linux/hdmi.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/bitfield.h>
@@ -867,15 +868,6 @@ it66121_bridge_hdmi_tmds_char_rate_valid(const struct drm_bridge *bridge,
const struct drm_display_mode *mode,
unsigned long long tmds_rate)
{
- const struct it66121_ctx *ctx =
- container_of(bridge, const struct it66121_ctx, bridge);
- unsigned long long max_rate;
-
- max_rate = (ctx->bus_width == 12) ? 74250000ULL : 148500000ULL;
-
- if (tmds_rate > max_rate)
- return MODE_CLOCK_HIGH;
-
if (tmds_rate < HDMI_TMDS_CHAR_RATE_MIN_HZ)
return MODE_CLOCK_LOW;
@@ -1670,6 +1662,9 @@ static int it66121_probe(struct i2c_client *client)
DRM_BRIDGE_OP_HDMI;
ctx->bridge.vendor = "ITE";
ctx->bridge.product = "IT66121";
+ ctx->bridge.supported_hdmi_ver = HDMI_VERSION_1_2;
+ ctx->bridge.max_tmds_char_rate = ctx->bus_width == 12 ? 74250000ULL : 148500000ULL;
+
if (client->irq > 0) {
ctx->bridge.ops |= DRM_BRIDGE_OP_HPD;
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 53/69] drm/bridge: lontium-lt9611: Advertise HDMI 1.4 capabilities
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:20 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:20 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
Bridges using DRM_BRIDGE_OP_HDMI are expected to provide the supported
HDMI version. This is not enforced yet, but will become mandatory once
the migration to the caps-based HDMI connector initialization API is
complete.
As LT9611 supposedly cannot drive a TMDS character rate exceeding 297
MHz, advertise HDMI 1.4 as the supported version. HDMI 1.4 allows up to
340 MHz, so set the bridge's max_tmds_char_rate to ensure the connector
limit derived from supported_hdmi_ver remains within the hardware
capabilities.
drm_bridge_connector_atomic_check() calls
drm_atomic_helper_connector_hdmi_check(), which rejects modes whose
computed TMDS character rate exceeds the connector's max_tmds_char_rate
before invoking the driver's .tmds_char_rate_valid hook. Since
max_tmds_char_rate now carries the existing effective limit,
lt9611_hdmi_tmds_char_rate_valid() is redundant. Drop it.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/bridge/lontium-lt9611.c | 16 +++-------------
1 file changed, 3 insertions(+), 13 deletions(-)
diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c b/drivers/gpu/drm/bridge/lontium-lt9611.c
index fb34f661ee0a..f66e3d1b1b57 100644
--- a/drivers/gpu/drm/bridge/lontium-lt9611.c
+++ b/drivers/gpu/drm/bridge/lontium-lt9611.c
@@ -5,6 +5,7 @@
*/
#include <linux/gpio/consumer.h>
+#include <linux/hdmi.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/media-bus-format.h>
@@ -952,18 +953,6 @@ static int lt9611_hdmi_write_hdmi_infoframe(struct drm_bridge *bridge,
return 0;
}
-static enum drm_mode_status
-lt9611_hdmi_tmds_char_rate_valid(const struct drm_bridge *bridge,
- const struct drm_display_mode *mode,
- unsigned long long tmds_rate)
-{
- /* 297 MHz for 4k@30 mode */
- if (tmds_rate > 297000000)
- return MODE_CLOCK_HIGH;
-
- return MODE_OK;
-}
-
static int lt9611_hdmi_audio_startup(struct drm_bridge *bridge,
struct drm_connector *connector)
{
@@ -1029,7 +1018,6 @@ static const struct drm_bridge_funcs lt9611_bridge_funcs = {
.atomic_create_state = drm_atomic_helper_bridge_create_state,
.atomic_get_input_bus_fmts = lt9611_atomic_get_input_bus_fmts,
- .hdmi_tmds_char_rate_valid = lt9611_hdmi_tmds_char_rate_valid,
.hdmi_write_audio_infoframe = lt9611_hdmi_write_audio_infoframe,
.hdmi_clear_audio_infoframe = lt9611_hdmi_clear_audio_infoframe,
.hdmi_write_avi_infoframe = lt9611_hdmi_write_avi_infoframe,
@@ -1177,6 +1165,8 @@ static int lt9611_probe(struct i2c_client *client)
lt9611->bridge.hdmi_audio_dev = dev;
lt9611->bridge.hdmi_audio_max_i2s_playback_channels = 8;
lt9611->bridge.hdmi_audio_dai_port = 2;
+ lt9611->bridge.supported_hdmi_ver = HDMI_VERSION_1_4;
+ lt9611->bridge.max_tmds_char_rate = 297000000; /* 297 MHz for 4k@30 mode */
drm_bridge_add(<9611->bridge);
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 53/69] drm/bridge: lontium-lt9611: Advertise HDMI 1.4 capabilities
@ 2026-07-31 16:20 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:20 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
Bridges using DRM_BRIDGE_OP_HDMI are expected to provide the supported
HDMI version. This is not enforced yet, but will become mandatory once
the migration to the caps-based HDMI connector initialization API is
complete.
As LT9611 supposedly cannot drive a TMDS character rate exceeding 297
MHz, advertise HDMI 1.4 as the supported version. HDMI 1.4 allows up to
340 MHz, so set the bridge's max_tmds_char_rate to ensure the connector
limit derived from supported_hdmi_ver remains within the hardware
capabilities.
drm_bridge_connector_atomic_check() calls
drm_atomic_helper_connector_hdmi_check(), which rejects modes whose
computed TMDS character rate exceeds the connector's max_tmds_char_rate
before invoking the driver's .tmds_char_rate_valid hook. Since
max_tmds_char_rate now carries the existing effective limit,
lt9611_hdmi_tmds_char_rate_valid() is redundant. Drop it.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/bridge/lontium-lt9611.c | 16 +++-------------
1 file changed, 3 insertions(+), 13 deletions(-)
diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c b/drivers/gpu/drm/bridge/lontium-lt9611.c
index fb34f661ee0a..f66e3d1b1b57 100644
--- a/drivers/gpu/drm/bridge/lontium-lt9611.c
+++ b/drivers/gpu/drm/bridge/lontium-lt9611.c
@@ -5,6 +5,7 @@
*/
#include <linux/gpio/consumer.h>
+#include <linux/hdmi.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/media-bus-format.h>
@@ -952,18 +953,6 @@ static int lt9611_hdmi_write_hdmi_infoframe(struct drm_bridge *bridge,
return 0;
}
-static enum drm_mode_status
-lt9611_hdmi_tmds_char_rate_valid(const struct drm_bridge *bridge,
- const struct drm_display_mode *mode,
- unsigned long long tmds_rate)
-{
- /* 297 MHz for 4k@30 mode */
- if (tmds_rate > 297000000)
- return MODE_CLOCK_HIGH;
-
- return MODE_OK;
-}
-
static int lt9611_hdmi_audio_startup(struct drm_bridge *bridge,
struct drm_connector *connector)
{
@@ -1029,7 +1018,6 @@ static const struct drm_bridge_funcs lt9611_bridge_funcs = {
.atomic_create_state = drm_atomic_helper_bridge_create_state,
.atomic_get_input_bus_fmts = lt9611_atomic_get_input_bus_fmts,
- .hdmi_tmds_char_rate_valid = lt9611_hdmi_tmds_char_rate_valid,
.hdmi_write_audio_infoframe = lt9611_hdmi_write_audio_infoframe,
.hdmi_clear_audio_infoframe = lt9611_hdmi_clear_audio_infoframe,
.hdmi_write_avi_infoframe = lt9611_hdmi_write_avi_infoframe,
@@ -1177,6 +1165,8 @@ static int lt9611_probe(struct i2c_client *client)
lt9611->bridge.hdmi_audio_dev = dev;
lt9611->bridge.hdmi_audio_max_i2s_playback_channels = 8;
lt9611->bridge.hdmi_audio_dai_port = 2;
+ lt9611->bridge.supported_hdmi_ver = HDMI_VERSION_1_4;
+ lt9611->bridge.max_tmds_char_rate = 297000000; /* 297 MHz for 4k@30 mode */
drm_bridge_add(<9611->bridge);
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 54/69] drm/rockchip: rk3066_hdmi: Advertise HDMI 1.4 capabilities
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:20 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:20 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
Bridges using DRM_BRIDGE_OP_HDMI are now expected to also provide a
supported HDMI version. This is not yet enforced, but will become
mandatory once the migration to the new caps-based HDMI connector
initialization API is completed.
The RK3066 HDMI TX supports HDMI 1.4a, as described in commit
f84d3d37b7fb ("drm: rockchip: introduce rk3066 hdmi"). However, the
driver does not currently enforce a maximum TMDS character rate, it only
filters non-CEA modes and excludes VIC 1 (640x480) via the .mode_valid
callback.
Advertise HDMI 1.4 support for now so that modes exceeding the 340 MHz
TMDS limit are rejected by the core.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/rockchip/rk3066_hdmi.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/gpu/drm/rockchip/rk3066_hdmi.c b/drivers/gpu/drm/rockchip/rk3066_hdmi.c
index f28d6a883e09..f748700b0ba6 100644
--- a/drivers/gpu/drm/rockchip/rk3066_hdmi.c
+++ b/drivers/gpu/drm/rockchip/rk3066_hdmi.c
@@ -14,6 +14,7 @@
#include <drm/drm_probe_helper.h>
#include <linux/clk.h>
+#include <linux/hdmi.h>
#include <linux/mfd/syscon.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
@@ -712,6 +713,7 @@ rk3066_hdmi_register(struct drm_device *drm, struct rk3066_hdmi *hdmi)
hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
hdmi->bridge.vendor = "Rockchip";
hdmi->bridge.product = "RK3066 HDMI";
+ hdmi->bridge.supported_hdmi_ver = HDMI_VERSION_1_4;
hdmi->bridge.ddc = rk3066_hdmi_i2c_adapter(hdmi);
if (IS_ERR(hdmi->bridge.ddc))
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 54/69] drm/rockchip: rk3066_hdmi: Advertise HDMI 1.4 capabilities
@ 2026-07-31 16:20 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:20 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
Bridges using DRM_BRIDGE_OP_HDMI are now expected to also provide a
supported HDMI version. This is not yet enforced, but will become
mandatory once the migration to the new caps-based HDMI connector
initialization API is completed.
The RK3066 HDMI TX supports HDMI 1.4a, as described in commit
f84d3d37b7fb ("drm: rockchip: introduce rk3066 hdmi"). However, the
driver does not currently enforce a maximum TMDS character rate, it only
filters non-CEA modes and excludes VIC 1 (640x480) via the .mode_valid
callback.
Advertise HDMI 1.4 support for now so that modes exceeding the 340 MHz
TMDS limit are rejected by the core.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/rockchip/rk3066_hdmi.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/gpu/drm/rockchip/rk3066_hdmi.c b/drivers/gpu/drm/rockchip/rk3066_hdmi.c
index f28d6a883e09..f748700b0ba6 100644
--- a/drivers/gpu/drm/rockchip/rk3066_hdmi.c
+++ b/drivers/gpu/drm/rockchip/rk3066_hdmi.c
@@ -14,6 +14,7 @@
#include <drm/drm_probe_helper.h>
#include <linux/clk.h>
+#include <linux/hdmi.h>
#include <linux/mfd/syscon.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
@@ -712,6 +713,7 @@ rk3066_hdmi_register(struct drm_device *drm, struct rk3066_hdmi *hdmi)
hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
hdmi->bridge.vendor = "Rockchip";
hdmi->bridge.product = "RK3066 HDMI";
+ hdmi->bridge.supported_hdmi_ver = HDMI_VERSION_1_4;
hdmi->bridge.ddc = rk3066_hdmi_i2c_adapter(hdmi);
if (IS_ERR(hdmi->bridge.ddc))
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 55/69] drm/sun4i: hdmi: Convert to drmm_connector_hdmi_init()
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:20 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:20 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
Switch driver over to the new drmm_connector_hdmi_init() signature and
advertise HDMI 1.2 support. The vendor, product, supported_formats and
max_bpc values previously passed as arguments are now provided through
struct drm_connector_hdmi_funcs, together with the new
supported_hdmi_ver field.
The HDMI connector helpers infer the 165 MHz TMDS character rate ceiling
from supported_hdmi_ver and reject modes exceeding it before invoking
the driver's .tmds_char_rate_valid() hook. This makes the explicit mode
clock check in sun4i_hdmi_connector_clock_valid() redundant, so drop it.
No functional change intended.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c | 16 +++++++---------
1 file changed, 7 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
index 96b2b597caa6..850a8fecf0b5 100644
--- a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
+++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
@@ -192,10 +192,6 @@ sun4i_hdmi_connector_clock_valid(const struct drm_connector *connector,
if (mode->flags & DRM_MODE_FLAG_DBLCLK)
return MODE_BAD;
- /* HDMI 1.0 max TMDS character rate */
- if (clock > HDMI_1_0_TMDS_CHAR_RATE_MAX_HZ)
- return MODE_CLOCK_HIGH;
-
rounded_rate = clk_round_rate(hdmi->tmds_clk, clock);
if (rounded_rate > 0 &&
max_t(unsigned long, rounded_rate, clock) -
@@ -253,6 +249,11 @@ static struct i2c_adapter *sun4i_hdmi_get_ddc(struct device *dev)
}
static const struct drm_connector_hdmi_funcs sun4i_hdmi_hdmi_connector_funcs = {
+ .vendor = "AW",
+ .product = "HDMI",
+ .supported_hdmi_ver = HDMI_VERSION_1_2,
+ .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ .max_bpc = 8,
.tmds_char_rate_valid = sun4i_hdmi_connector_clock_valid,
.avi = {
.clear_infoframe = sun4i_hdmi_clear_avi_infoframe,
@@ -653,19 +654,16 @@ static int sun4i_hdmi_bind(struct device *dev, struct device *master,
drm_connector_helper_add(&hdmi->connector,
&sun4i_hdmi_connector_helper_funcs);
- ret = drmm_connector_hdmi_ini2(drm, &hdmi->connector,
+ ret = drmm_connector_hdmi_init(drm, &hdmi->connector,
/*
* NOTE: Those are likely to be
* wrong, but I couldn't find the
* actual ones in the BSP.
*/
- "AW", "HDMI",
&sun4i_hdmi_connector_funcs,
&sun4i_hdmi_hdmi_connector_funcs,
DRM_MODE_CONNECTOR_HDMIA,
- hdmi->ddc_i2c,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ hdmi->ddc_i2c);
if (ret) {
dev_err(dev,
"Couldn't initialise the HDMI connector\n");
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 55/69] drm/sun4i: hdmi: Convert to drmm_connector_hdmi_init()
@ 2026-07-31 16:20 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:20 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
Switch driver over to the new drmm_connector_hdmi_init() signature and
advertise HDMI 1.2 support. The vendor, product, supported_formats and
max_bpc values previously passed as arguments are now provided through
struct drm_connector_hdmi_funcs, together with the new
supported_hdmi_ver field.
The HDMI connector helpers infer the 165 MHz TMDS character rate ceiling
from supported_hdmi_ver and reject modes exceeding it before invoking
the driver's .tmds_char_rate_valid() hook. This makes the explicit mode
clock check in sun4i_hdmi_connector_clock_valid() redundant, so drop it.
No functional change intended.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c | 16 +++++++---------
1 file changed, 7 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
index 96b2b597caa6..850a8fecf0b5 100644
--- a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
+++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
@@ -192,10 +192,6 @@ sun4i_hdmi_connector_clock_valid(const struct drm_connector *connector,
if (mode->flags & DRM_MODE_FLAG_DBLCLK)
return MODE_BAD;
- /* HDMI 1.0 max TMDS character rate */
- if (clock > HDMI_1_0_TMDS_CHAR_RATE_MAX_HZ)
- return MODE_CLOCK_HIGH;
-
rounded_rate = clk_round_rate(hdmi->tmds_clk, clock);
if (rounded_rate > 0 &&
max_t(unsigned long, rounded_rate, clock) -
@@ -253,6 +249,11 @@ static struct i2c_adapter *sun4i_hdmi_get_ddc(struct device *dev)
}
static const struct drm_connector_hdmi_funcs sun4i_hdmi_hdmi_connector_funcs = {
+ .vendor = "AW",
+ .product = "HDMI",
+ .supported_hdmi_ver = HDMI_VERSION_1_2,
+ .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ .max_bpc = 8,
.tmds_char_rate_valid = sun4i_hdmi_connector_clock_valid,
.avi = {
.clear_infoframe = sun4i_hdmi_clear_avi_infoframe,
@@ -653,19 +654,16 @@ static int sun4i_hdmi_bind(struct device *dev, struct device *master,
drm_connector_helper_add(&hdmi->connector,
&sun4i_hdmi_connector_helper_funcs);
- ret = drmm_connector_hdmi_ini2(drm, &hdmi->connector,
+ ret = drmm_connector_hdmi_init(drm, &hdmi->connector,
/*
* NOTE: Those are likely to be
* wrong, but I couldn't find the
* actual ones in the BSP.
*/
- "AW", "HDMI",
&sun4i_hdmi_connector_funcs,
&sun4i_hdmi_hdmi_connector_funcs,
DRM_MODE_CONNECTOR_HDMIA,
- hdmi->ddc_i2c,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ hdmi->ddc_i2c);
if (ret) {
dev_err(dev,
"Couldn't initialise the HDMI connector\n");
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 56/69] drm/tests: edid: Add 4K@60Hz EDID with 600MHz TMDS
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:20 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:20 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
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.c | 129 +++++++++++++++++++++++++++++++++
drivers/gpu/drm/tests/drm_kunit_edid.h | 1 +
2 files changed, 130 insertions(+)
diff --git a/drivers/gpu/drm/tests/drm_kunit_edid.c b/drivers/gpu/drm/tests/drm_kunit_edid.c
index c807ae0d9faa..673a0ea8c2ae 100644
--- a/drivers/gpu/drm/tests/drm_kunit_edid.c
+++ b/drivers/gpu/drm/tests/drm_kunit_edid.c
@@ -990,6 +990,135 @@ const unsigned char test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz[] = {
};
EXPORT_SYMBOL(test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz);
+/*
+ * 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
+ */
+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,
+};
+EXPORT_SYMBOL(test_edid_hdmi_4k_rgb_yuv420_dc_max_600mhz);
+
MODULE_AUTHOR("Maxime Ripard <mripard@kernel.org>");
MODULE_DESCRIPTION("EDID Definitions for KUnit tests");
MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/tests/drm_kunit_edid.h b/drivers/gpu/drm/tests/drm_kunit_edid.h
index 28b4df93a555..fb5b0295e35e 100644
--- a/drivers/gpu/drm/tests/drm_kunit_edid.h
+++ b/drivers/gpu/drm/tests/drm_kunit_edid.h
@@ -12,5 +12,6 @@ extern const unsigned char test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz[256];
extern const unsigned char test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz[256];
extern const unsigned char test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz[256];
extern const unsigned char test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz[256];
+extern const unsigned char test_edid_hdmi_4k_rgb_yuv420_dc_max_600mhz[256];
#endif // DRM_KUNIT_EDID_H_
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 56/69] drm/tests: edid: Add 4K@60Hz EDID with 600MHz TMDS
@ 2026-07-31 16:20 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:20 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
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.c | 129 +++++++++++++++++++++++++++++++++
drivers/gpu/drm/tests/drm_kunit_edid.h | 1 +
2 files changed, 130 insertions(+)
diff --git a/drivers/gpu/drm/tests/drm_kunit_edid.c b/drivers/gpu/drm/tests/drm_kunit_edid.c
index c807ae0d9faa..673a0ea8c2ae 100644
--- a/drivers/gpu/drm/tests/drm_kunit_edid.c
+++ b/drivers/gpu/drm/tests/drm_kunit_edid.c
@@ -990,6 +990,135 @@ const unsigned char test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz[] = {
};
EXPORT_SYMBOL(test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz);
+/*
+ * 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
+ */
+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,
+};
+EXPORT_SYMBOL(test_edid_hdmi_4k_rgb_yuv420_dc_max_600mhz);
+
MODULE_AUTHOR("Maxime Ripard <mripard@kernel.org>");
MODULE_DESCRIPTION("EDID Definitions for KUnit tests");
MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/tests/drm_kunit_edid.h b/drivers/gpu/drm/tests/drm_kunit_edid.h
index 28b4df93a555..fb5b0295e35e 100644
--- a/drivers/gpu/drm/tests/drm_kunit_edid.h
+++ b/drivers/gpu/drm/tests/drm_kunit_edid.h
@@ -12,5 +12,6 @@ extern const unsigned char test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz[256];
extern const unsigned char test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz[256];
extern const unsigned char test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz[256];
extern const unsigned char test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz[256];
+extern const unsigned char test_edid_hdmi_4k_rgb_yuv420_dc_max_600mhz[256];
#endif // DRM_KUNIT_EDID_H_
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 57/69] drm/tests: edid: Fix conformity for 1080p+4K YUV420 200MHz EDID
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:20 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:20 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
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.c | 65 +++++++++++++++++++++-------------
1 file changed, 41 insertions(+), 24 deletions(-)
diff --git a/drivers/gpu/drm/tests/drm_kunit_edid.c b/drivers/gpu/drm/tests/drm_kunit_edid.c
index 673a0ea8c2ae..4dff28fff796 100644
--- a/drivers/gpu/drm/tests/drm_kunit_edid.c
+++ b/drivers/gpu/drm/tests/drm_kunit_edid.c
@@ -766,22 +766,22 @@ EXPORT_SYMBOL(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
*
* ----------------
*
@@ -790,7 +790,7 @@ EXPORT_SYMBOL(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
@@ -813,21 +813,21 @@ EXPORT_SYMBOL(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
@@ -838,40 +838,57 @@ EXPORT_SYMBOL(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
*/
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,
};
EXPORT_SYMBOL(test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz);
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 57/69] drm/tests: edid: Fix conformity for 1080p+4K YUV420 200MHz EDID
@ 2026-07-31 16:20 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:20 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
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.c | 65 +++++++++++++++++++++-------------
1 file changed, 41 insertions(+), 24 deletions(-)
diff --git a/drivers/gpu/drm/tests/drm_kunit_edid.c b/drivers/gpu/drm/tests/drm_kunit_edid.c
index 673a0ea8c2ae..4dff28fff796 100644
--- a/drivers/gpu/drm/tests/drm_kunit_edid.c
+++ b/drivers/gpu/drm/tests/drm_kunit_edid.c
@@ -766,22 +766,22 @@ EXPORT_SYMBOL(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
*
* ----------------
*
@@ -790,7 +790,7 @@ EXPORT_SYMBOL(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
@@ -813,21 +813,21 @@ EXPORT_SYMBOL(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
@@ -838,40 +838,57 @@ EXPORT_SYMBOL(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
*/
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,
};
EXPORT_SYMBOL(test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz);
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 58/69] drm/tests: edid: Fix conformity for 4K RGB/YUV 340MHz EDID
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:20 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:20 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
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.c | 57 ++++++++++++++++++++++------------
1 file changed, 38 insertions(+), 19 deletions(-)
diff --git a/drivers/gpu/drm/tests/drm_kunit_edid.c b/drivers/gpu/drm/tests/drm_kunit_edid.c
index 4dff28fff796..a6c5e8d6077a 100644
--- a/drivers/gpu/drm/tests/drm_kunit_edid.c
+++ b/drivers/gpu/drm/tests/drm_kunit_edid.c
@@ -900,22 +900,22 @@ EXPORT_SYMBOL(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
*
* ----------------
*
@@ -924,7 +924,7 @@ EXPORT_SYMBOL(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
@@ -942,7 +942,7 @@ EXPORT_SYMBOL(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'
@@ -950,12 +950,13 @@ EXPORT_SYMBOL(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
@@ -971,31 +972,49 @@ EXPORT_SYMBOL(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
*/
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,
@@ -1003,7 +1022,7 @@ 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,
};
EXPORT_SYMBOL(test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz);
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 58/69] drm/tests: edid: Fix conformity for 4K RGB/YUV 340MHz EDID
@ 2026-07-31 16:20 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:20 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
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.c | 57 ++++++++++++++++++++++------------
1 file changed, 38 insertions(+), 19 deletions(-)
diff --git a/drivers/gpu/drm/tests/drm_kunit_edid.c b/drivers/gpu/drm/tests/drm_kunit_edid.c
index 4dff28fff796..a6c5e8d6077a 100644
--- a/drivers/gpu/drm/tests/drm_kunit_edid.c
+++ b/drivers/gpu/drm/tests/drm_kunit_edid.c
@@ -900,22 +900,22 @@ EXPORT_SYMBOL(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
*
* ----------------
*
@@ -924,7 +924,7 @@ EXPORT_SYMBOL(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
@@ -942,7 +942,7 @@ EXPORT_SYMBOL(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'
@@ -950,12 +950,13 @@ EXPORT_SYMBOL(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
@@ -971,31 +972,49 @@ EXPORT_SYMBOL(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
*/
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,
@@ -1003,7 +1022,7 @@ 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,
};
EXPORT_SYMBOL(test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz);
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 59/69] drm/tests: bridge: Set supported HDMI version
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:20 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:20 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
Bridges using DRM_BRIDGE_OP_HDMI are now expected to also provide a
supported HDMI version. This is not yet enforced, but will become
mandatory once the migration to the new HDMI connector initialization API
is completed.
Advertise HDMI 1.4 as the default for the test bridges, since that is
the highest version that does not require additional initialization
data. This also avoids implying support for HDMI capabilities they do
not currently model.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/tests/drm_bridge_test.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/gpu/drm/tests/drm_bridge_test.c b/drivers/gpu/drm/tests/drm_bridge_test.c
index 15583ade8494..a445f71c31b8 100644
--- a/drivers/gpu/drm/tests/drm_bridge_test.c
+++ b/drivers/gpu/drm/tests/drm_bridge_test.c
@@ -497,6 +497,7 @@ drm_test_bridge_chain_init(struct kunit *test, unsigned int num_bridges,
bridge->type = DRM_MODE_CONNECTOR_HDMIA;
bridge->vendor = "LNX";
bridge->product = "KUnit";
+ bridge->supported_hdmi_ver = HDMI_VERSION_1_4;
bridge->supported_formats = (BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444) |
BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
@@ -597,6 +598,7 @@ drm_test_bridge_hdmi_init(struct kunit *test, const struct drm_bridge_funcs *fun
bridge->ops |= DRM_BRIDGE_OP_HDMI;
bridge->vendor = "LNX";
bridge->product = "KUnit";
+ bridge->supported_hdmi_ver = HDMI_VERSION_1_4;
ret = drm_kunit_bridge_add(test, bridge);
if (ret)
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 59/69] drm/tests: bridge: Set supported HDMI version
@ 2026-07-31 16:20 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:20 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
Bridges using DRM_BRIDGE_OP_HDMI are now expected to also provide a
supported HDMI version. This is not yet enforced, but will become
mandatory once the migration to the new HDMI connector initialization API
is completed.
Advertise HDMI 1.4 as the default for the test bridges, since that is
the highest version that does not require additional initialization
data. This also avoids implying support for HDMI capabilities they do
not currently model.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/tests/drm_bridge_test.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/gpu/drm/tests/drm_bridge_test.c b/drivers/gpu/drm/tests/drm_bridge_test.c
index 15583ade8494..a445f71c31b8 100644
--- a/drivers/gpu/drm/tests/drm_bridge_test.c
+++ b/drivers/gpu/drm/tests/drm_bridge_test.c
@@ -497,6 +497,7 @@ drm_test_bridge_chain_init(struct kunit *test, unsigned int num_bridges,
bridge->type = DRM_MODE_CONNECTOR_HDMIA;
bridge->vendor = "LNX";
bridge->product = "KUnit";
+ bridge->supported_hdmi_ver = HDMI_VERSION_1_4;
bridge->supported_formats = (BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444) |
BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
@@ -597,6 +598,7 @@ drm_test_bridge_hdmi_init(struct kunit *test, const struct drm_bridge_funcs *fun
bridge->ops |= DRM_BRIDGE_OP_HDMI;
bridge->vendor = "LNX";
bridge->product = "KUnit";
+ bridge->supported_hdmi_ver = HDMI_VERSION_1_4;
ret = drm_kunit_bridge_add(test, bridge);
if (ret)
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 60/69] drm/tests: connector: Convert to drmm_connector_hdmi_init()
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:20 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:20 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
Switch tests over to the new drmm_connector_hdmi_init() signature, where
the vendor, product, supported_formats and max_bpc values previously
passed as arguments are now provided through struct
drm_connector_hdmi_funcs.
As a consequence, the tests exercising those values can no longer share
the static dummy_hdmi_funcs and need a modified copy of their own.
Since the connector retains a pointer to it, such a copy must not be
placed on the stack, which is gone by the time the DRM-managed actions
release the connector. Keep it in struct drm_connector_init_priv
instead: it embeds the DRM device and is only freed via
managed.final_kfree, i.e. once drm_dev_release() has run all DRM-managed
actions, so its lifetime strictly outlives the connector.
Note that a kunit_kzalloc() buffer would not be suitable, as KUnit
releases its resources in reverse order, hence one allocated by a test
would be freed before the DRM device allocated by the suite .init().
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/tests/drm_connector_test.c | 251 ++++++++++++++---------------
1 file changed, 119 insertions(+), 132 deletions(-)
diff --git a/drivers/gpu/drm/tests/drm_connector_test.c b/drivers/gpu/drm/tests/drm_connector_test.c
index 3368aedd4e66..c53ccce21a42 100644
--- a/drivers/gpu/drm/tests/drm_connector_test.c
+++ b/drivers/gpu/drm/tests/drm_connector_test.c
@@ -23,6 +23,8 @@ struct drm_connector_init_priv {
struct drm_device drm;
struct drm_connector connector;
struct i2c_adapter ddc;
+ /* Mutable copy of a static instance for test-specific overrides */
+ struct drm_connector_hdmi_funcs hdmi_funcs;
};
static int accept_infoframe_clear_infoframe(struct drm_connector *connector)
@@ -37,6 +39,11 @@ static int accept_infoframe_write_infoframe(struct drm_connector *connector,
}
static const struct drm_connector_hdmi_funcs dummy_hdmi_funcs = {
+ .vendor = "Vendor",
+ .product = "Product",
+ .supported_hdmi_ver = HDMI_VERSION_1_4,
+ .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ .max_bpc = 8,
.avi = {
.clear_infoframe = accept_infoframe_clear_infoframe,
.write_infoframe = accept_infoframe_write_infoframe,
@@ -669,14 +676,11 @@ static void drm_test_connector_hdmi_init_valid(struct kunit *test)
struct drm_connector_init_priv *priv = test->priv;
int ret;
- ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
- "Vendor", "Product",
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
&dummy_hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
- &priv->ddc,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ &priv->ddc);
KUNIT_EXPECT_EQ(test, ret, 0);
}
@@ -689,14 +693,11 @@ static void drm_test_connector_hdmi_init_null_ddc(struct kunit *test)
struct drm_connector_init_priv *priv = test->priv;
int ret;
- ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
- "Vendor", "Product",
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
&dummy_hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
- NULL,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ NULL);
KUNIT_EXPECT_EQ(test, ret, 0);
}
@@ -709,14 +710,14 @@ static void drm_test_connector_hdmi_init_null_vendor(struct kunit *test)
struct drm_connector_init_priv *priv = test->priv;
int ret;
- ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
- NULL, "Product",
+ priv->hdmi_funcs = dummy_hdmi_funcs;
+ priv->hdmi_funcs.vendor = NULL;
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
- &dummy_hdmi_funcs,
+ &priv->hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
- &priv->ddc,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ &priv->ddc);
KUNIT_EXPECT_LT(test, ret, 0);
}
@@ -729,14 +730,14 @@ static void drm_test_connector_hdmi_init_null_product(struct kunit *test)
struct drm_connector_init_priv *priv = test->priv;
int ret;
- ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
- "Vendor", NULL,
+ priv->hdmi_funcs = dummy_hdmi_funcs;
+ priv->hdmi_funcs.product = NULL;
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
- &dummy_hdmi_funcs,
+ &priv->hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
- &priv->ddc,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ &priv->ddc);
KUNIT_EXPECT_LT(test, ret, 0);
}
@@ -750,19 +751,19 @@ static void drm_test_connector_hdmi_init_product_valid(struct kunit *test)
const unsigned char expected_product[DRM_CONNECTOR_HDMI_PRODUCT_LEN] = {
'P', 'r', 'o', 'd',
};
- const char *product_name = "Prod";
int ret;
- KUNIT_ASSERT_LT(test, strlen(product_name), DRM_CONNECTOR_HDMI_PRODUCT_LEN);
+ priv->hdmi_funcs = dummy_hdmi_funcs;
+ priv->hdmi_funcs.product = "Prod";
- ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
- "Vendor", product_name,
+ KUNIT_ASSERT_LT(test, strlen(priv->hdmi_funcs.product),
+ DRM_CONNECTOR_HDMI_PRODUCT_LEN);
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
- &dummy_hdmi_funcs,
+ &priv->hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
- &priv->ddc,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ &priv->ddc);
KUNIT_EXPECT_EQ(test, ret, 0);
KUNIT_EXPECT_MEMEQ(test,
priv->connector.hdmi.product,
@@ -783,19 +784,19 @@ static void drm_test_connector_hdmi_init_product_length_exact(struct kunit *test
'P', 'r', 'o', 'd', 'u', 'c', 't',
'P', 'r',
};
- const char *product_name = "ProductProductPr";
int ret;
- KUNIT_ASSERT_EQ(test, strlen(product_name), DRM_CONNECTOR_HDMI_PRODUCT_LEN);
+ priv->hdmi_funcs = dummy_hdmi_funcs;
+ priv->hdmi_funcs.product = "ProductProductPr";
- ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
- "Vendor", product_name,
+ KUNIT_ASSERT_EQ(test, strlen(priv->hdmi_funcs.product),
+ DRM_CONNECTOR_HDMI_PRODUCT_LEN);
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
- &dummy_hdmi_funcs,
+ &priv->hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
- &priv->ddc,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ &priv->ddc);
KUNIT_EXPECT_EQ(test, ret, 0);
KUNIT_EXPECT_MEMEQ(test,
priv->connector.hdmi.product,
@@ -810,19 +811,19 @@ static void drm_test_connector_hdmi_init_product_length_exact(struct kunit *test
static void drm_test_connector_hdmi_init_product_length_too_long(struct kunit *test)
{
struct drm_connector_init_priv *priv = test->priv;
- const char *product_name = "ProductProductProduct";
int ret;
- KUNIT_ASSERT_GT(test, strlen(product_name), DRM_CONNECTOR_HDMI_PRODUCT_LEN);
+ priv->hdmi_funcs = dummy_hdmi_funcs;
+ priv->hdmi_funcs.product = "ProductProductProduct";
- ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
- "Vendor", product_name,
+ KUNIT_ASSERT_GT(test, strlen(priv->hdmi_funcs.product),
+ DRM_CONNECTOR_HDMI_PRODUCT_LEN);
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
- &dummy_hdmi_funcs,
+ &priv->hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
- &priv->ddc,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ &priv->ddc);
KUNIT_EXPECT_LT(test, ret, 0);
}
@@ -836,19 +837,19 @@ static void drm_test_connector_hdmi_init_vendor_valid(struct kunit *test)
const char expected_vendor[DRM_CONNECTOR_HDMI_VENDOR_LEN] = {
'V', 'e', 'n', 'd',
};
- const char *vendor_name = "Vend";
int ret;
- KUNIT_ASSERT_LT(test, strlen(vendor_name), DRM_CONNECTOR_HDMI_VENDOR_LEN);
+ priv->hdmi_funcs = dummy_hdmi_funcs;
+ priv->hdmi_funcs.vendor = "Vend";
- ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
- vendor_name, "Product",
+ KUNIT_ASSERT_LT(test, strlen(priv->hdmi_funcs.vendor),
+ DRM_CONNECTOR_HDMI_VENDOR_LEN);
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
- &dummy_hdmi_funcs,
+ &priv->hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
- &priv->ddc,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ &priv->ddc);
KUNIT_EXPECT_EQ(test, ret, 0);
KUNIT_EXPECT_MEMEQ(test,
priv->connector.hdmi.vendor,
@@ -868,19 +869,19 @@ static void drm_test_connector_hdmi_init_vendor_length_exact(struct kunit *test)
'V', 'e', 'n', 'd', 'o', 'r',
'V', 'e',
};
- const char *vendor_name = "VendorVe";
int ret;
- KUNIT_ASSERT_EQ(test, strlen(vendor_name), DRM_CONNECTOR_HDMI_VENDOR_LEN);
+ priv->hdmi_funcs = dummy_hdmi_funcs;
+ priv->hdmi_funcs.vendor = "VendorVe";
- ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
- vendor_name, "Product",
+ KUNIT_ASSERT_EQ(test, strlen(priv->hdmi_funcs.vendor),
+ DRM_CONNECTOR_HDMI_VENDOR_LEN);
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
- &dummy_hdmi_funcs,
+ &priv->hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
- &priv->ddc,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ &priv->ddc);
KUNIT_EXPECT_EQ(test, ret, 0);
KUNIT_EXPECT_MEMEQ(test,
priv->connector.hdmi.vendor,
@@ -895,19 +896,17 @@ static void drm_test_connector_hdmi_init_vendor_length_exact(struct kunit *test)
static void drm_test_connector_hdmi_init_vendor_length_too_long(struct kunit *test)
{
struct drm_connector_init_priv *priv = test->priv;
- const char *vendor_name = "VendorVendor";
int ret;
- KUNIT_ASSERT_GT(test, strlen(vendor_name), DRM_CONNECTOR_HDMI_VENDOR_LEN);
+ priv->hdmi_funcs = dummy_hdmi_funcs;
+ priv->hdmi_funcs.vendor = "VendorVendor";
+ KUNIT_ASSERT_GT(test, strlen(priv->hdmi_funcs.vendor), DRM_CONNECTOR_HDMI_VENDOR_LEN);
- ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
- vendor_name, "Product",
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
- &dummy_hdmi_funcs,
+ &priv->hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
- &priv->ddc,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ &priv->ddc);
KUNIT_EXPECT_LT(test, ret, 0);
}
@@ -920,14 +919,14 @@ static void drm_test_connector_hdmi_init_bpc_invalid(struct kunit *test)
struct drm_connector_init_priv *priv = test->priv;
int ret;
- ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
- "Vendor", "Product",
+ priv->hdmi_funcs = dummy_hdmi_funcs;
+ priv->hdmi_funcs.max_bpc = 9;
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
- &dummy_hdmi_funcs,
+ &priv->hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
- &priv->ddc,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 9);
+ &priv->ddc);
KUNIT_EXPECT_LT(test, ret, 0);
}
@@ -940,14 +939,14 @@ static void drm_test_connector_hdmi_init_bpc_null(struct kunit *test)
struct drm_connector_init_priv *priv = test->priv;
int ret;
- ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
- "Vendor", "Product",
+ priv->hdmi_funcs = dummy_hdmi_funcs;
+ priv->hdmi_funcs.max_bpc = 0;
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
- &dummy_hdmi_funcs,
+ &priv->hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
- &priv->ddc,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 0);
+ &priv->ddc);
KUNIT_EXPECT_LT(test, ret, 0);
}
@@ -965,14 +964,11 @@ static void drm_test_connector_hdmi_init_bpc_8(struct kunit *test)
uint64_t val;
int ret;
- ret = drmm_connector_hdmi_ini2(&priv->drm, connector,
- "Vendor", "Product",
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
&dummy_hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
- &priv->ddc,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ &priv->ddc);
KUNIT_EXPECT_EQ(test, ret, 0);
prop = connector->max_bpc_property;
@@ -1006,14 +1002,14 @@ static void drm_test_connector_hdmi_init_bpc_10(struct kunit *test)
uint64_t val;
int ret;
- ret = drmm_connector_hdmi_ini2(&priv->drm, connector,
- "Vendor", "Product",
+ priv->hdmi_funcs = dummy_hdmi_funcs;
+ priv->hdmi_funcs.max_bpc = 10;
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
- &dummy_hdmi_funcs,
+ &priv->hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
- &priv->ddc,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 10);
+ &priv->ddc);
KUNIT_EXPECT_EQ(test, ret, 0);
prop = connector->max_bpc_property;
@@ -1047,14 +1043,14 @@ static void drm_test_connector_hdmi_init_bpc_12(struct kunit *test)
uint64_t val;
int ret;
- ret = drmm_connector_hdmi_ini2(&priv->drm, connector,
- "Vendor", "Product",
+ priv->hdmi_funcs = dummy_hdmi_funcs;
+ priv->hdmi_funcs.max_bpc = 12;
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
- &dummy_hdmi_funcs,
+ &priv->hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
- &priv->ddc,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 12);
+ &priv->ddc);
KUNIT_EXPECT_EQ(test, ret, 0);
prop = connector->max_bpc_property;
@@ -1083,14 +1079,14 @@ static void drm_test_connector_hdmi_init_formats_empty(struct kunit *test)
struct drm_connector_init_priv *priv = test->priv;
int ret;
- ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
- "Vendor", "Product",
+ priv->hdmi_funcs = dummy_hdmi_funcs;
+ priv->hdmi_funcs.supported_formats = 0;
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
- &dummy_hdmi_funcs,
+ &priv->hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
- &priv->ddc,
- 0,
- 8);
+ &priv->ddc);
KUNIT_EXPECT_LT(test, ret, 0);
}
@@ -1103,14 +1099,14 @@ static void drm_test_connector_hdmi_init_formats_no_rgb(struct kunit *test)
struct drm_connector_init_priv *priv = test->priv;
int ret;
- ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
- "Vendor", "Product",
+ priv->hdmi_funcs = dummy_hdmi_funcs;
+ priv->hdmi_funcs.supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422);
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
- &dummy_hdmi_funcs,
+ &priv->hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
- &priv->ddc,
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422),
- 8);
+ &priv->ddc);
KUNIT_EXPECT_LT(test, ret, 0);
}
@@ -1161,14 +1157,14 @@ static void drm_test_connector_hdmi_init_formats_yuv420_allowed(struct kunit *te
params = test->param_value;
priv->connector.ycbcr_420_allowed = params->yuv420_allowed;
- ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
- "Vendor", "Product",
+ priv->hdmi_funcs = dummy_hdmi_funcs;
+ priv->hdmi_funcs.supported_formats = params->supported_formats;
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
- &dummy_hdmi_funcs,
+ &priv->hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
- &priv->ddc,
- params->supported_formats,
- 8);
+ &priv->ddc);
KUNIT_EXPECT_EQ(test, ret, params->expected_result);
}
@@ -1182,14 +1178,11 @@ static void drm_test_connector_hdmi_init_type_valid(struct kunit *test)
unsigned int connector_type = *(unsigned int *)test->param_value;
int ret;
- ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
- "Vendor", "Product",
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
&dummy_hdmi_funcs,
connector_type,
- &priv->ddc,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ &priv->ddc);
KUNIT_EXPECT_EQ(test, ret, 0);
}
@@ -1217,14 +1210,11 @@ static void drm_test_connector_hdmi_init_type_invalid(struct kunit *test)
unsigned int connector_type = *(unsigned int *)test->param_value;
int ret;
- ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
- "Vendor", "Product",
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
&dummy_hdmi_funcs,
connector_type,
- &priv->ddc,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ &priv->ddc);
KUNIT_EXPECT_LT(test, ret, 0);
}
@@ -1494,14 +1484,11 @@ static void drm_test_drm_connector_attach_broadcast_rgb_property_hdmi_connector(
struct drm_property *prop;
int ret;
- ret = drmm_connector_hdmi_ini2(&priv->drm, connector,
- "Vendor", "Product",
+ ret = drmm_connector_hdmi_init(&priv->drm, connector,
&dummy_funcs,
&dummy_hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
- &priv->ddc,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ &priv->ddc);
KUNIT_EXPECT_EQ(test, ret, 0);
ret = drm_connector_attach_broadcast_rgb_property(connector);
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 60/69] drm/tests: connector: Convert to drmm_connector_hdmi_init()
@ 2026-07-31 16:20 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:20 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
Switch tests over to the new drmm_connector_hdmi_init() signature, where
the vendor, product, supported_formats and max_bpc values previously
passed as arguments are now provided through struct
drm_connector_hdmi_funcs.
As a consequence, the tests exercising those values can no longer share
the static dummy_hdmi_funcs and need a modified copy of their own.
Since the connector retains a pointer to it, such a copy must not be
placed on the stack, which is gone by the time the DRM-managed actions
release the connector. Keep it in struct drm_connector_init_priv
instead: it embeds the DRM device and is only freed via
managed.final_kfree, i.e. once drm_dev_release() has run all DRM-managed
actions, so its lifetime strictly outlives the connector.
Note that a kunit_kzalloc() buffer would not be suitable, as KUnit
releases its resources in reverse order, hence one allocated by a test
would be freed before the DRM device allocated by the suite .init().
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/tests/drm_connector_test.c | 251 ++++++++++++++---------------
1 file changed, 119 insertions(+), 132 deletions(-)
diff --git a/drivers/gpu/drm/tests/drm_connector_test.c b/drivers/gpu/drm/tests/drm_connector_test.c
index 3368aedd4e66..c53ccce21a42 100644
--- a/drivers/gpu/drm/tests/drm_connector_test.c
+++ b/drivers/gpu/drm/tests/drm_connector_test.c
@@ -23,6 +23,8 @@ struct drm_connector_init_priv {
struct drm_device drm;
struct drm_connector connector;
struct i2c_adapter ddc;
+ /* Mutable copy of a static instance for test-specific overrides */
+ struct drm_connector_hdmi_funcs hdmi_funcs;
};
static int accept_infoframe_clear_infoframe(struct drm_connector *connector)
@@ -37,6 +39,11 @@ static int accept_infoframe_write_infoframe(struct drm_connector *connector,
}
static const struct drm_connector_hdmi_funcs dummy_hdmi_funcs = {
+ .vendor = "Vendor",
+ .product = "Product",
+ .supported_hdmi_ver = HDMI_VERSION_1_4,
+ .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ .max_bpc = 8,
.avi = {
.clear_infoframe = accept_infoframe_clear_infoframe,
.write_infoframe = accept_infoframe_write_infoframe,
@@ -669,14 +676,11 @@ static void drm_test_connector_hdmi_init_valid(struct kunit *test)
struct drm_connector_init_priv *priv = test->priv;
int ret;
- ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
- "Vendor", "Product",
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
&dummy_hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
- &priv->ddc,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ &priv->ddc);
KUNIT_EXPECT_EQ(test, ret, 0);
}
@@ -689,14 +693,11 @@ static void drm_test_connector_hdmi_init_null_ddc(struct kunit *test)
struct drm_connector_init_priv *priv = test->priv;
int ret;
- ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
- "Vendor", "Product",
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
&dummy_hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
- NULL,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ NULL);
KUNIT_EXPECT_EQ(test, ret, 0);
}
@@ -709,14 +710,14 @@ static void drm_test_connector_hdmi_init_null_vendor(struct kunit *test)
struct drm_connector_init_priv *priv = test->priv;
int ret;
- ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
- NULL, "Product",
+ priv->hdmi_funcs = dummy_hdmi_funcs;
+ priv->hdmi_funcs.vendor = NULL;
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
- &dummy_hdmi_funcs,
+ &priv->hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
- &priv->ddc,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ &priv->ddc);
KUNIT_EXPECT_LT(test, ret, 0);
}
@@ -729,14 +730,14 @@ static void drm_test_connector_hdmi_init_null_product(struct kunit *test)
struct drm_connector_init_priv *priv = test->priv;
int ret;
- ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
- "Vendor", NULL,
+ priv->hdmi_funcs = dummy_hdmi_funcs;
+ priv->hdmi_funcs.product = NULL;
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
- &dummy_hdmi_funcs,
+ &priv->hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
- &priv->ddc,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ &priv->ddc);
KUNIT_EXPECT_LT(test, ret, 0);
}
@@ -750,19 +751,19 @@ static void drm_test_connector_hdmi_init_product_valid(struct kunit *test)
const unsigned char expected_product[DRM_CONNECTOR_HDMI_PRODUCT_LEN] = {
'P', 'r', 'o', 'd',
};
- const char *product_name = "Prod";
int ret;
- KUNIT_ASSERT_LT(test, strlen(product_name), DRM_CONNECTOR_HDMI_PRODUCT_LEN);
+ priv->hdmi_funcs = dummy_hdmi_funcs;
+ priv->hdmi_funcs.product = "Prod";
- ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
- "Vendor", product_name,
+ KUNIT_ASSERT_LT(test, strlen(priv->hdmi_funcs.product),
+ DRM_CONNECTOR_HDMI_PRODUCT_LEN);
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
- &dummy_hdmi_funcs,
+ &priv->hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
- &priv->ddc,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ &priv->ddc);
KUNIT_EXPECT_EQ(test, ret, 0);
KUNIT_EXPECT_MEMEQ(test,
priv->connector.hdmi.product,
@@ -783,19 +784,19 @@ static void drm_test_connector_hdmi_init_product_length_exact(struct kunit *test
'P', 'r', 'o', 'd', 'u', 'c', 't',
'P', 'r',
};
- const char *product_name = "ProductProductPr";
int ret;
- KUNIT_ASSERT_EQ(test, strlen(product_name), DRM_CONNECTOR_HDMI_PRODUCT_LEN);
+ priv->hdmi_funcs = dummy_hdmi_funcs;
+ priv->hdmi_funcs.product = "ProductProductPr";
- ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
- "Vendor", product_name,
+ KUNIT_ASSERT_EQ(test, strlen(priv->hdmi_funcs.product),
+ DRM_CONNECTOR_HDMI_PRODUCT_LEN);
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
- &dummy_hdmi_funcs,
+ &priv->hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
- &priv->ddc,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ &priv->ddc);
KUNIT_EXPECT_EQ(test, ret, 0);
KUNIT_EXPECT_MEMEQ(test,
priv->connector.hdmi.product,
@@ -810,19 +811,19 @@ static void drm_test_connector_hdmi_init_product_length_exact(struct kunit *test
static void drm_test_connector_hdmi_init_product_length_too_long(struct kunit *test)
{
struct drm_connector_init_priv *priv = test->priv;
- const char *product_name = "ProductProductProduct";
int ret;
- KUNIT_ASSERT_GT(test, strlen(product_name), DRM_CONNECTOR_HDMI_PRODUCT_LEN);
+ priv->hdmi_funcs = dummy_hdmi_funcs;
+ priv->hdmi_funcs.product = "ProductProductProduct";
- ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
- "Vendor", product_name,
+ KUNIT_ASSERT_GT(test, strlen(priv->hdmi_funcs.product),
+ DRM_CONNECTOR_HDMI_PRODUCT_LEN);
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
- &dummy_hdmi_funcs,
+ &priv->hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
- &priv->ddc,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ &priv->ddc);
KUNIT_EXPECT_LT(test, ret, 0);
}
@@ -836,19 +837,19 @@ static void drm_test_connector_hdmi_init_vendor_valid(struct kunit *test)
const char expected_vendor[DRM_CONNECTOR_HDMI_VENDOR_LEN] = {
'V', 'e', 'n', 'd',
};
- const char *vendor_name = "Vend";
int ret;
- KUNIT_ASSERT_LT(test, strlen(vendor_name), DRM_CONNECTOR_HDMI_VENDOR_LEN);
+ priv->hdmi_funcs = dummy_hdmi_funcs;
+ priv->hdmi_funcs.vendor = "Vend";
- ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
- vendor_name, "Product",
+ KUNIT_ASSERT_LT(test, strlen(priv->hdmi_funcs.vendor),
+ DRM_CONNECTOR_HDMI_VENDOR_LEN);
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
- &dummy_hdmi_funcs,
+ &priv->hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
- &priv->ddc,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ &priv->ddc);
KUNIT_EXPECT_EQ(test, ret, 0);
KUNIT_EXPECT_MEMEQ(test,
priv->connector.hdmi.vendor,
@@ -868,19 +869,19 @@ static void drm_test_connector_hdmi_init_vendor_length_exact(struct kunit *test)
'V', 'e', 'n', 'd', 'o', 'r',
'V', 'e',
};
- const char *vendor_name = "VendorVe";
int ret;
- KUNIT_ASSERT_EQ(test, strlen(vendor_name), DRM_CONNECTOR_HDMI_VENDOR_LEN);
+ priv->hdmi_funcs = dummy_hdmi_funcs;
+ priv->hdmi_funcs.vendor = "VendorVe";
- ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
- vendor_name, "Product",
+ KUNIT_ASSERT_EQ(test, strlen(priv->hdmi_funcs.vendor),
+ DRM_CONNECTOR_HDMI_VENDOR_LEN);
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
- &dummy_hdmi_funcs,
+ &priv->hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
- &priv->ddc,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ &priv->ddc);
KUNIT_EXPECT_EQ(test, ret, 0);
KUNIT_EXPECT_MEMEQ(test,
priv->connector.hdmi.vendor,
@@ -895,19 +896,17 @@ static void drm_test_connector_hdmi_init_vendor_length_exact(struct kunit *test)
static void drm_test_connector_hdmi_init_vendor_length_too_long(struct kunit *test)
{
struct drm_connector_init_priv *priv = test->priv;
- const char *vendor_name = "VendorVendor";
int ret;
- KUNIT_ASSERT_GT(test, strlen(vendor_name), DRM_CONNECTOR_HDMI_VENDOR_LEN);
+ priv->hdmi_funcs = dummy_hdmi_funcs;
+ priv->hdmi_funcs.vendor = "VendorVendor";
+ KUNIT_ASSERT_GT(test, strlen(priv->hdmi_funcs.vendor), DRM_CONNECTOR_HDMI_VENDOR_LEN);
- ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
- vendor_name, "Product",
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
- &dummy_hdmi_funcs,
+ &priv->hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
- &priv->ddc,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ &priv->ddc);
KUNIT_EXPECT_LT(test, ret, 0);
}
@@ -920,14 +919,14 @@ static void drm_test_connector_hdmi_init_bpc_invalid(struct kunit *test)
struct drm_connector_init_priv *priv = test->priv;
int ret;
- ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
- "Vendor", "Product",
+ priv->hdmi_funcs = dummy_hdmi_funcs;
+ priv->hdmi_funcs.max_bpc = 9;
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
- &dummy_hdmi_funcs,
+ &priv->hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
- &priv->ddc,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 9);
+ &priv->ddc);
KUNIT_EXPECT_LT(test, ret, 0);
}
@@ -940,14 +939,14 @@ static void drm_test_connector_hdmi_init_bpc_null(struct kunit *test)
struct drm_connector_init_priv *priv = test->priv;
int ret;
- ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
- "Vendor", "Product",
+ priv->hdmi_funcs = dummy_hdmi_funcs;
+ priv->hdmi_funcs.max_bpc = 0;
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
- &dummy_hdmi_funcs,
+ &priv->hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
- &priv->ddc,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 0);
+ &priv->ddc);
KUNIT_EXPECT_LT(test, ret, 0);
}
@@ -965,14 +964,11 @@ static void drm_test_connector_hdmi_init_bpc_8(struct kunit *test)
uint64_t val;
int ret;
- ret = drmm_connector_hdmi_ini2(&priv->drm, connector,
- "Vendor", "Product",
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
&dummy_hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
- &priv->ddc,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ &priv->ddc);
KUNIT_EXPECT_EQ(test, ret, 0);
prop = connector->max_bpc_property;
@@ -1006,14 +1002,14 @@ static void drm_test_connector_hdmi_init_bpc_10(struct kunit *test)
uint64_t val;
int ret;
- ret = drmm_connector_hdmi_ini2(&priv->drm, connector,
- "Vendor", "Product",
+ priv->hdmi_funcs = dummy_hdmi_funcs;
+ priv->hdmi_funcs.max_bpc = 10;
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
- &dummy_hdmi_funcs,
+ &priv->hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
- &priv->ddc,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 10);
+ &priv->ddc);
KUNIT_EXPECT_EQ(test, ret, 0);
prop = connector->max_bpc_property;
@@ -1047,14 +1043,14 @@ static void drm_test_connector_hdmi_init_bpc_12(struct kunit *test)
uint64_t val;
int ret;
- ret = drmm_connector_hdmi_ini2(&priv->drm, connector,
- "Vendor", "Product",
+ priv->hdmi_funcs = dummy_hdmi_funcs;
+ priv->hdmi_funcs.max_bpc = 12;
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
- &dummy_hdmi_funcs,
+ &priv->hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
- &priv->ddc,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 12);
+ &priv->ddc);
KUNIT_EXPECT_EQ(test, ret, 0);
prop = connector->max_bpc_property;
@@ -1083,14 +1079,14 @@ static void drm_test_connector_hdmi_init_formats_empty(struct kunit *test)
struct drm_connector_init_priv *priv = test->priv;
int ret;
- ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
- "Vendor", "Product",
+ priv->hdmi_funcs = dummy_hdmi_funcs;
+ priv->hdmi_funcs.supported_formats = 0;
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
- &dummy_hdmi_funcs,
+ &priv->hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
- &priv->ddc,
- 0,
- 8);
+ &priv->ddc);
KUNIT_EXPECT_LT(test, ret, 0);
}
@@ -1103,14 +1099,14 @@ static void drm_test_connector_hdmi_init_formats_no_rgb(struct kunit *test)
struct drm_connector_init_priv *priv = test->priv;
int ret;
- ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
- "Vendor", "Product",
+ priv->hdmi_funcs = dummy_hdmi_funcs;
+ priv->hdmi_funcs.supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422);
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
- &dummy_hdmi_funcs,
+ &priv->hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
- &priv->ddc,
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422),
- 8);
+ &priv->ddc);
KUNIT_EXPECT_LT(test, ret, 0);
}
@@ -1161,14 +1157,14 @@ static void drm_test_connector_hdmi_init_formats_yuv420_allowed(struct kunit *te
params = test->param_value;
priv->connector.ycbcr_420_allowed = params->yuv420_allowed;
- ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
- "Vendor", "Product",
+ priv->hdmi_funcs = dummy_hdmi_funcs;
+ priv->hdmi_funcs.supported_formats = params->supported_formats;
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
- &dummy_hdmi_funcs,
+ &priv->hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
- &priv->ddc,
- params->supported_formats,
- 8);
+ &priv->ddc);
KUNIT_EXPECT_EQ(test, ret, params->expected_result);
}
@@ -1182,14 +1178,11 @@ static void drm_test_connector_hdmi_init_type_valid(struct kunit *test)
unsigned int connector_type = *(unsigned int *)test->param_value;
int ret;
- ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
- "Vendor", "Product",
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
&dummy_hdmi_funcs,
connector_type,
- &priv->ddc,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ &priv->ddc);
KUNIT_EXPECT_EQ(test, ret, 0);
}
@@ -1217,14 +1210,11 @@ static void drm_test_connector_hdmi_init_type_invalid(struct kunit *test)
unsigned int connector_type = *(unsigned int *)test->param_value;
int ret;
- ret = drmm_connector_hdmi_ini2(&priv->drm, &priv->connector,
- "Vendor", "Product",
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
&dummy_hdmi_funcs,
connector_type,
- &priv->ddc,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ &priv->ddc);
KUNIT_EXPECT_LT(test, ret, 0);
}
@@ -1494,14 +1484,11 @@ static void drm_test_drm_connector_attach_broadcast_rgb_property_hdmi_connector(
struct drm_property *prop;
int ret;
- ret = drmm_connector_hdmi_ini2(&priv->drm, connector,
- "Vendor", "Product",
+ ret = drmm_connector_hdmi_init(&priv->drm, connector,
&dummy_funcs,
&dummy_hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
- &priv->ddc,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ &priv->ddc);
KUNIT_EXPECT_EQ(test, ret, 0);
ret = drm_connector_attach_broadcast_rgb_property(connector);
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 61/69] drm/tests: connector: Add HDMI max_tmds_char_rate init coverage
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:20 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:20 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
Add KUnit tests for the new drmm_connector_hdmi_init() extension, which
infers the connector's max_tmds_char_rate from the HDMI specification
version advertised by the driver. Also validate a driver-capped
max_tmds_char_rate against the version-inferred limit: override below,
accept at, reject above, reject when no version is advertised.
Since HDMI_VERSION_2_0 requires scrambler callbacks to be provided, add
a dummy_hdmi_funcs_scrambler instance for tests that initialize HDMI 2.0
connectors.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/tests/drm_connector_test.c | 179 +++++++++++++++++++++++++++++
1 file changed, 179 insertions(+)
diff --git a/drivers/gpu/drm/tests/drm_connector_test.c b/drivers/gpu/drm/tests/drm_connector_test.c
index c53ccce21a42..17242d1c1b16 100644
--- a/drivers/gpu/drm/tests/drm_connector_test.c
+++ b/drivers/gpu/drm/tests/drm_connector_test.c
@@ -54,6 +54,34 @@ 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 = {
+ .vendor = "Vendor",
+ .product = "Product",
+ .supported_hdmi_ver = HDMI_VERSION_2_0,
+ .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ .max_bpc = 8,
+ .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_funcs dummy_funcs = {
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
@@ -1244,6 +1272,151 @@ 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 without an explicit max TMDS
+ * character rate being provided succeeds, and the connector limit is inferred
+ * from the advertised HDMI specification version.
+ */
+struct drm_connector_hdmi_init_max_tmds_rate_inferred_case {
+ const char *desc;
+ enum hdmi_version ver;
+ unsigned long long expected;
+};
+
+static void drm_test_connector_hdmi_init_max_tmds_rate_inferred(struct kunit *test)
+{
+ struct drm_connector_init_priv *priv = test->priv;
+ const struct drm_connector_hdmi_init_max_tmds_rate_inferred_case *params =
+ test->param_value;
+ int ret;
+
+ priv->hdmi_funcs = params->ver < HDMI_VERSION_2_0 ?
+ dummy_hdmi_funcs : dummy_hdmi_funcs_scrambler;
+ priv->hdmi_funcs.supported_hdmi_ver = params->ver;
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ &dummy_funcs,
+ &priv->hdmi_funcs,
+ DRM_MODE_CONNECTOR_HDMIA,
+ &priv->ddc);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+ KUNIT_EXPECT_EQ(test, priv->connector.hdmi.max_tmds_char_rate,
+ params->expected);
+}
+
+static const struct drm_connector_hdmi_init_max_tmds_rate_inferred_case
+drm_connector_hdmi_init_max_tmds_rate_inferred_tests[] = {
+ { "unknown", HDMI_VERSION_UNKNOWN, 0 },
+ { "1.0", HDMI_VERSION_1_0, HDMI_1_0_TMDS_CHAR_RATE_MAX_HZ },
+ { "1.2", HDMI_VERSION_1_2, HDMI_1_0_TMDS_CHAR_RATE_MAX_HZ },
+ { "1.3", HDMI_VERSION_1_3, HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ },
+ { "1.4", HDMI_VERSION_1_4, HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ },
+ { "2.0", HDMI_VERSION_2_0, HDMI_2_0_TMDS_CHAR_RATE_MAX_HZ },
+};
+
+static void drm_connector_hdmi_init_max_tmds_rate_inferred_desc(
+ const struct drm_connector_hdmi_init_max_tmds_rate_inferred_case *t,
+ char *desc)
+{
+ strscpy(desc, t->desc, KUNIT_PARAM_DESC_SIZE);
+}
+
+KUNIT_ARRAY_PARAM(drm_connector_hdmi_init_max_tmds_rate_inferred,
+ drm_connector_hdmi_init_max_tmds_rate_inferred_tests,
+ drm_connector_hdmi_init_max_tmds_rate_inferred_desc);
+
+/*
+ * Test that the registration of an HDMI connector providing a max TMDS
+ * character rate strictly below the version-inferred limit succeeds, and
+ * the connector limit is overridden.
+ */
+static void drm_test_connector_hdmi_init_max_tmds_rate_override(struct kunit *test)
+{
+ struct drm_connector_init_priv *priv = test->priv;
+ int ret;
+
+ priv->hdmi_funcs = dummy_hdmi_funcs;
+ priv->hdmi_funcs.supported_hdmi_ver = HDMI_VERSION_1_4;
+ priv->hdmi_funcs.supported_tmds_char_rate = HDMI_1_0_TMDS_CHAR_RATE_MAX_HZ;
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ &dummy_funcs,
+ &priv->hdmi_funcs,
+ DRM_MODE_CONNECTOR_HDMIA,
+ &priv->ddc);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+ KUNIT_EXPECT_EQ(test, priv->connector.hdmi.max_tmds_char_rate,
+ HDMI_1_0_TMDS_CHAR_RATE_MAX_HZ);
+}
+
+/*
+ * Test that the registration of an HDMI connector providing a max TMDS
+ * character rate equal to the version-inferred limit succeeds.
+ */
+static void drm_test_connector_hdmi_init_max_tmds_rate_at_limit(struct kunit *test)
+{
+ struct drm_connector_init_priv *priv = test->priv;
+ int ret;
+
+ priv->hdmi_funcs = dummy_hdmi_funcs;
+ priv->hdmi_funcs.supported_hdmi_ver = HDMI_VERSION_1_2;
+ priv->hdmi_funcs.supported_tmds_char_rate = HDMI_1_0_TMDS_CHAR_RATE_MAX_HZ;
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ &dummy_funcs,
+ &priv->hdmi_funcs,
+ DRM_MODE_CONNECTOR_HDMIA,
+ &priv->ddc);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+ KUNIT_EXPECT_EQ(test, priv->connector.hdmi.max_tmds_char_rate,
+ HDMI_1_0_TMDS_CHAR_RATE_MAX_HZ);
+}
+
+/*
+ * Test that the registration of an HDMI connector providing a max TMDS
+ * character rate that exceeds the limit inferred from the advertised HDMI
+ * specification version fails.
+ */
+static void drm_test_connector_hdmi_init_max_tmds_rate_off_limit(struct kunit *test)
+{
+ struct drm_connector_init_priv *priv = test->priv;
+ int ret;
+
+ priv->hdmi_funcs = dummy_hdmi_funcs;
+ priv->hdmi_funcs.supported_hdmi_ver = HDMI_VERSION_1_2;
+ priv->hdmi_funcs.supported_tmds_char_rate = HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ;
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ &dummy_funcs,
+ &priv->hdmi_funcs,
+ DRM_MODE_CONNECTOR_HDMIA,
+ &priv->ddc);
+ KUNIT_EXPECT_LT(test, ret, 0);
+}
+
+/*
+ * Test that the registration of an HDMI connector providing a non-zero max
+ * TMDS character rate without an HDMI specification version fails, as the
+ * version-inferred limit defaults to zero and any positive override would
+ * exceed it.
+ */
+static void drm_test_connector_hdmi_init_max_tmds_rate_no_version(struct kunit *test)
+{
+ struct drm_connector_init_priv *priv = test->priv;
+ int ret;
+
+ priv->hdmi_funcs = dummy_hdmi_funcs;
+ priv->hdmi_funcs.supported_hdmi_ver = HDMI_VERSION_UNKNOWN;
+ priv->hdmi_funcs.supported_tmds_char_rate = HDMI_1_0_TMDS_CHAR_RATE_MAX_HZ;
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ &dummy_funcs,
+ &priv->hdmi_funcs,
+ DRM_MODE_CONNECTOR_HDMIA,
+ &priv->ddc);
+ KUNIT_EXPECT_LT(test, ret, 0);
+}
+
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),
@@ -1268,6 +1441,12 @@ 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_PARAM(drm_test_connector_hdmi_init_max_tmds_rate_inferred,
+ drm_connector_hdmi_init_max_tmds_rate_inferred_gen_params),
+ KUNIT_CASE(drm_test_connector_hdmi_init_max_tmds_rate_override),
+ KUNIT_CASE(drm_test_connector_hdmi_init_max_tmds_rate_at_limit),
+ KUNIT_CASE(drm_test_connector_hdmi_init_max_tmds_rate_off_limit),
+ KUNIT_CASE(drm_test_connector_hdmi_init_max_tmds_rate_no_version),
{ }
};
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 61/69] drm/tests: connector: Add HDMI max_tmds_char_rate init coverage
@ 2026-07-31 16:20 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:20 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
Add KUnit tests for the new drmm_connector_hdmi_init() extension, which
infers the connector's max_tmds_char_rate from the HDMI specification
version advertised by the driver. Also validate a driver-capped
max_tmds_char_rate against the version-inferred limit: override below,
accept at, reject above, reject when no version is advertised.
Since HDMI_VERSION_2_0 requires scrambler callbacks to be provided, add
a dummy_hdmi_funcs_scrambler instance for tests that initialize HDMI 2.0
connectors.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/tests/drm_connector_test.c | 179 +++++++++++++++++++++++++++++
1 file changed, 179 insertions(+)
diff --git a/drivers/gpu/drm/tests/drm_connector_test.c b/drivers/gpu/drm/tests/drm_connector_test.c
index c53ccce21a42..17242d1c1b16 100644
--- a/drivers/gpu/drm/tests/drm_connector_test.c
+++ b/drivers/gpu/drm/tests/drm_connector_test.c
@@ -54,6 +54,34 @@ 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 = {
+ .vendor = "Vendor",
+ .product = "Product",
+ .supported_hdmi_ver = HDMI_VERSION_2_0,
+ .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ .max_bpc = 8,
+ .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_funcs dummy_funcs = {
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
@@ -1244,6 +1272,151 @@ 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 without an explicit max TMDS
+ * character rate being provided succeeds, and the connector limit is inferred
+ * from the advertised HDMI specification version.
+ */
+struct drm_connector_hdmi_init_max_tmds_rate_inferred_case {
+ const char *desc;
+ enum hdmi_version ver;
+ unsigned long long expected;
+};
+
+static void drm_test_connector_hdmi_init_max_tmds_rate_inferred(struct kunit *test)
+{
+ struct drm_connector_init_priv *priv = test->priv;
+ const struct drm_connector_hdmi_init_max_tmds_rate_inferred_case *params =
+ test->param_value;
+ int ret;
+
+ priv->hdmi_funcs = params->ver < HDMI_VERSION_2_0 ?
+ dummy_hdmi_funcs : dummy_hdmi_funcs_scrambler;
+ priv->hdmi_funcs.supported_hdmi_ver = params->ver;
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ &dummy_funcs,
+ &priv->hdmi_funcs,
+ DRM_MODE_CONNECTOR_HDMIA,
+ &priv->ddc);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+ KUNIT_EXPECT_EQ(test, priv->connector.hdmi.max_tmds_char_rate,
+ params->expected);
+}
+
+static const struct drm_connector_hdmi_init_max_tmds_rate_inferred_case
+drm_connector_hdmi_init_max_tmds_rate_inferred_tests[] = {
+ { "unknown", HDMI_VERSION_UNKNOWN, 0 },
+ { "1.0", HDMI_VERSION_1_0, HDMI_1_0_TMDS_CHAR_RATE_MAX_HZ },
+ { "1.2", HDMI_VERSION_1_2, HDMI_1_0_TMDS_CHAR_RATE_MAX_HZ },
+ { "1.3", HDMI_VERSION_1_3, HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ },
+ { "1.4", HDMI_VERSION_1_4, HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ },
+ { "2.0", HDMI_VERSION_2_0, HDMI_2_0_TMDS_CHAR_RATE_MAX_HZ },
+};
+
+static void drm_connector_hdmi_init_max_tmds_rate_inferred_desc(
+ const struct drm_connector_hdmi_init_max_tmds_rate_inferred_case *t,
+ char *desc)
+{
+ strscpy(desc, t->desc, KUNIT_PARAM_DESC_SIZE);
+}
+
+KUNIT_ARRAY_PARAM(drm_connector_hdmi_init_max_tmds_rate_inferred,
+ drm_connector_hdmi_init_max_tmds_rate_inferred_tests,
+ drm_connector_hdmi_init_max_tmds_rate_inferred_desc);
+
+/*
+ * Test that the registration of an HDMI connector providing a max TMDS
+ * character rate strictly below the version-inferred limit succeeds, and
+ * the connector limit is overridden.
+ */
+static void drm_test_connector_hdmi_init_max_tmds_rate_override(struct kunit *test)
+{
+ struct drm_connector_init_priv *priv = test->priv;
+ int ret;
+
+ priv->hdmi_funcs = dummy_hdmi_funcs;
+ priv->hdmi_funcs.supported_hdmi_ver = HDMI_VERSION_1_4;
+ priv->hdmi_funcs.supported_tmds_char_rate = HDMI_1_0_TMDS_CHAR_RATE_MAX_HZ;
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ &dummy_funcs,
+ &priv->hdmi_funcs,
+ DRM_MODE_CONNECTOR_HDMIA,
+ &priv->ddc);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+ KUNIT_EXPECT_EQ(test, priv->connector.hdmi.max_tmds_char_rate,
+ HDMI_1_0_TMDS_CHAR_RATE_MAX_HZ);
+}
+
+/*
+ * Test that the registration of an HDMI connector providing a max TMDS
+ * character rate equal to the version-inferred limit succeeds.
+ */
+static void drm_test_connector_hdmi_init_max_tmds_rate_at_limit(struct kunit *test)
+{
+ struct drm_connector_init_priv *priv = test->priv;
+ int ret;
+
+ priv->hdmi_funcs = dummy_hdmi_funcs;
+ priv->hdmi_funcs.supported_hdmi_ver = HDMI_VERSION_1_2;
+ priv->hdmi_funcs.supported_tmds_char_rate = HDMI_1_0_TMDS_CHAR_RATE_MAX_HZ;
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ &dummy_funcs,
+ &priv->hdmi_funcs,
+ DRM_MODE_CONNECTOR_HDMIA,
+ &priv->ddc);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+ KUNIT_EXPECT_EQ(test, priv->connector.hdmi.max_tmds_char_rate,
+ HDMI_1_0_TMDS_CHAR_RATE_MAX_HZ);
+}
+
+/*
+ * Test that the registration of an HDMI connector providing a max TMDS
+ * character rate that exceeds the limit inferred from the advertised HDMI
+ * specification version fails.
+ */
+static void drm_test_connector_hdmi_init_max_tmds_rate_off_limit(struct kunit *test)
+{
+ struct drm_connector_init_priv *priv = test->priv;
+ int ret;
+
+ priv->hdmi_funcs = dummy_hdmi_funcs;
+ priv->hdmi_funcs.supported_hdmi_ver = HDMI_VERSION_1_2;
+ priv->hdmi_funcs.supported_tmds_char_rate = HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ;
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ &dummy_funcs,
+ &priv->hdmi_funcs,
+ DRM_MODE_CONNECTOR_HDMIA,
+ &priv->ddc);
+ KUNIT_EXPECT_LT(test, ret, 0);
+}
+
+/*
+ * Test that the registration of an HDMI connector providing a non-zero max
+ * TMDS character rate without an HDMI specification version fails, as the
+ * version-inferred limit defaults to zero and any positive override would
+ * exceed it.
+ */
+static void drm_test_connector_hdmi_init_max_tmds_rate_no_version(struct kunit *test)
+{
+ struct drm_connector_init_priv *priv = test->priv;
+ int ret;
+
+ priv->hdmi_funcs = dummy_hdmi_funcs;
+ priv->hdmi_funcs.supported_hdmi_ver = HDMI_VERSION_UNKNOWN;
+ priv->hdmi_funcs.supported_tmds_char_rate = HDMI_1_0_TMDS_CHAR_RATE_MAX_HZ;
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ &dummy_funcs,
+ &priv->hdmi_funcs,
+ DRM_MODE_CONNECTOR_HDMIA,
+ &priv->ddc);
+ KUNIT_EXPECT_LT(test, ret, 0);
+}
+
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),
@@ -1268,6 +1441,12 @@ 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_PARAM(drm_test_connector_hdmi_init_max_tmds_rate_inferred,
+ drm_connector_hdmi_init_max_tmds_rate_inferred_gen_params),
+ KUNIT_CASE(drm_test_connector_hdmi_init_max_tmds_rate_override),
+ KUNIT_CASE(drm_test_connector_hdmi_init_max_tmds_rate_at_limit),
+ KUNIT_CASE(drm_test_connector_hdmi_init_max_tmds_rate_off_limit),
+ KUNIT_CASE(drm_test_connector_hdmi_init_max_tmds_rate_no_version),
{ }
};
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 62/69] drm/tests: connector: Add HDMI source-side scrambler coverage
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:20 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:20 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
Add KUnit tests for the HDMI source-side scrambling validation done by
the new drmm_connector_hdmi_init() helper.
Connector initialization derives scrambler support from the
driver-provided supported_hdmi_ver capability. The scrambler callbacks
are only valid for connectors advertising HDMI 2.0 or later, as
drm_connector_hdmi_scrambler_supported() uses their presence to report
source-side scrambling support.
Therefore, connectors that advertise source-side scrambling support must
provide both .scrambler_enable and .scrambler_disable. Registration is
rejected if either callback is missing. Conversely, connectors that do
not advertise source-side scrambling support must not provide these
callbacks, and registration is rejected if they are present.
Test the valid and invalid callback combinations for both supported and
unsupported scrambling configurations.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/tests/drm_connector_test.c | 87 ++++++++++++++++++++++++++++++
1 file changed, 87 insertions(+)
diff --git a/drivers/gpu/drm/tests/drm_connector_test.c b/drivers/gpu/drm/tests/drm_connector_test.c
index 17242d1c1b16..3d8500ad8be9 100644
--- a/drivers/gpu/drm/tests/drm_connector_test.c
+++ b/drivers/gpu/drm/tests/drm_connector_test.c
@@ -1417,6 +1417,89 @@ static void drm_test_connector_hdmi_init_max_tmds_rate_no_version(struct kunit *
KUNIT_EXPECT_LT(test, ret, 0);
}
+/*
+ * 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;
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ &dummy_funcs,
+ &dummy_hdmi_funcs_scrambler,
+ DRM_MODE_CONNECTOR_HDMIA,
+ &priv->ddc);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+ KUNIT_EXPECT_TRUE(test, drm_connector_hdmi_scrambler_supported(&priv->connector));
+}
+
+/*
+ * 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->hdmi_funcs = dummy_hdmi_funcs_scrambler;
+ priv->hdmi_funcs.scrambler_enable = NULL;
+ priv->hdmi_funcs.scrambler_disable = NULL;
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ &dummy_funcs,
+ &priv->hdmi_funcs,
+ DRM_MODE_CONNECTOR_HDMIA,
+ &priv->ddc);
+ 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->hdmi_funcs = dummy_hdmi_funcs_scrambler;
+ priv->hdmi_funcs.scrambler_disable = NULL;
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ &dummy_funcs,
+ &priv->hdmi_funcs,
+ DRM_MODE_CONNECTOR_HDMIA,
+ &priv->ddc);
+ KUNIT_EXPECT_LT(test, ret, 0);
+}
+
+/*
+ * Test that the registration of an HDMI connector not advertising source-side
+ * scrambling support fails when .scrambler_{enable,disable} callbacks are
+ * provided.
+ */
+static void drm_test_connector_hdmi_init_scrambler_unexpected_callbacks(struct kunit *test)
+{
+ struct drm_connector_init_priv *priv = test->priv;
+ int ret;
+
+ priv->hdmi_funcs = dummy_hdmi_funcs_scrambler;
+ priv->hdmi_funcs.supported_hdmi_ver = HDMI_VERSION_1_4;
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ &dummy_funcs,
+ &priv->hdmi_funcs,
+ DRM_MODE_CONNECTOR_HDMIA,
+ &priv->ddc);
+ KUNIT_EXPECT_LT(test, ret, 0);
+}
+
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),
@@ -1447,6 +1530,10 @@ static struct kunit_case drmm_connector_hdmi_init_tests[] = {
KUNIT_CASE(drm_test_connector_hdmi_init_max_tmds_rate_at_limit),
KUNIT_CASE(drm_test_connector_hdmi_init_max_tmds_rate_off_limit),
KUNIT_CASE(drm_test_connector_hdmi_init_max_tmds_rate_no_version),
+ 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_unexpected_callbacks),
{ }
};
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 62/69] drm/tests: connector: Add HDMI source-side scrambler coverage
@ 2026-07-31 16:20 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:20 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
Add KUnit tests for the HDMI source-side scrambling validation done by
the new drmm_connector_hdmi_init() helper.
Connector initialization derives scrambler support from the
driver-provided supported_hdmi_ver capability. The scrambler callbacks
are only valid for connectors advertising HDMI 2.0 or later, as
drm_connector_hdmi_scrambler_supported() uses their presence to report
source-side scrambling support.
Therefore, connectors that advertise source-side scrambling support must
provide both .scrambler_enable and .scrambler_disable. Registration is
rejected if either callback is missing. Conversely, connectors that do
not advertise source-side scrambling support must not provide these
callbacks, and registration is rejected if they are present.
Test the valid and invalid callback combinations for both supported and
unsupported scrambling configurations.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/tests/drm_connector_test.c | 87 ++++++++++++++++++++++++++++++
1 file changed, 87 insertions(+)
diff --git a/drivers/gpu/drm/tests/drm_connector_test.c b/drivers/gpu/drm/tests/drm_connector_test.c
index 17242d1c1b16..3d8500ad8be9 100644
--- a/drivers/gpu/drm/tests/drm_connector_test.c
+++ b/drivers/gpu/drm/tests/drm_connector_test.c
@@ -1417,6 +1417,89 @@ static void drm_test_connector_hdmi_init_max_tmds_rate_no_version(struct kunit *
KUNIT_EXPECT_LT(test, ret, 0);
}
+/*
+ * 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;
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ &dummy_funcs,
+ &dummy_hdmi_funcs_scrambler,
+ DRM_MODE_CONNECTOR_HDMIA,
+ &priv->ddc);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+ KUNIT_EXPECT_TRUE(test, drm_connector_hdmi_scrambler_supported(&priv->connector));
+}
+
+/*
+ * 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->hdmi_funcs = dummy_hdmi_funcs_scrambler;
+ priv->hdmi_funcs.scrambler_enable = NULL;
+ priv->hdmi_funcs.scrambler_disable = NULL;
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ &dummy_funcs,
+ &priv->hdmi_funcs,
+ DRM_MODE_CONNECTOR_HDMIA,
+ &priv->ddc);
+ 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->hdmi_funcs = dummy_hdmi_funcs_scrambler;
+ priv->hdmi_funcs.scrambler_disable = NULL;
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ &dummy_funcs,
+ &priv->hdmi_funcs,
+ DRM_MODE_CONNECTOR_HDMIA,
+ &priv->ddc);
+ KUNIT_EXPECT_LT(test, ret, 0);
+}
+
+/*
+ * Test that the registration of an HDMI connector not advertising source-side
+ * scrambling support fails when .scrambler_{enable,disable} callbacks are
+ * provided.
+ */
+static void drm_test_connector_hdmi_init_scrambler_unexpected_callbacks(struct kunit *test)
+{
+ struct drm_connector_init_priv *priv = test->priv;
+ int ret;
+
+ priv->hdmi_funcs = dummy_hdmi_funcs_scrambler;
+ priv->hdmi_funcs.supported_hdmi_ver = HDMI_VERSION_1_4;
+
+ ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+ &dummy_funcs,
+ &priv->hdmi_funcs,
+ DRM_MODE_CONNECTOR_HDMIA,
+ &priv->ddc);
+ KUNIT_EXPECT_LT(test, ret, 0);
+}
+
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),
@@ -1447,6 +1530,10 @@ static struct kunit_case drmm_connector_hdmi_init_tests[] = {
KUNIT_CASE(drm_test_connector_hdmi_init_max_tmds_rate_at_limit),
KUNIT_CASE(drm_test_connector_hdmi_init_max_tmds_rate_off_limit),
KUNIT_CASE(drm_test_connector_hdmi_init_max_tmds_rate_no_version),
+ 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_unexpected_callbacks),
{ }
};
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 63/69] drm/tests: hdmi_state_helper: Convert to drmm_connector_hdmi_init()
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:20 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:20 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
Switch tests over to the new drmm_connector_hdmi_init() signature, where
the vendor, product, supported_formats and max_bpc values previously
passed as arguments are now provided through struct
drm_connector_hdmi_funcs.
As a consequence, the tests exercising those values can no longer share
the static hdmi_funcs and need a modified copy of their own. Since the
connector retains a pointer to it, such a copy must not live on the
caller's stack, which is gone by the time the DRM-managed actions
release the connector.
Let __connector_hdmi_init() store it in struct
drm_atomic_helper_connector_hdmi_priv instead. This structure embeds
the DRM device and is freed through managed.final_kfree only after
drm_dev_release() has run all DRM-managed actions, so it strictly
outlives the connector.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 334 ++++++++++-----------
1 file changed, 164 insertions(+), 170 deletions(-)
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 4c2a400bc15a..f35dc31326bc 100644
--- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
+++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
@@ -32,6 +32,7 @@ struct drm_atomic_helper_connector_hdmi_priv {
struct drm_crtc *crtc;
struct drm_encoder encoder;
struct drm_connector connector;
+ struct drm_connector_hdmi_funcs hdmi_funcs;
const void *current_edid;
size_t current_edid_len;
@@ -124,6 +125,11 @@ static int accept_infoframe_write_infoframe(struct drm_connector *connector,
}
static const struct drm_connector_hdmi_funcs dummy_connector_hdmi_funcs = {
+ .vendor = "Vendor",
+ .product = "Product",
+ .supported_hdmi_ver = HDMI_VERSION_1_4,
+ .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ .max_bpc = 8,
.avi = {
.clear_infoframe = accept_infoframe_clear_infoframe,
.write_infoframe = accept_infoframe_write_infoframe,
@@ -143,6 +149,11 @@ reject_connector_tmds_char_rate_valid(const struct drm_connector *connector,
}
static const struct drm_connector_hdmi_funcs reject_connector_hdmi_funcs = {
+ .vendor = "Vendor",
+ .product = "Product",
+ .supported_hdmi_ver = HDMI_VERSION_1_4,
+ .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ .max_bpc = 8,
.tmds_char_rate_valid = reject_connector_tmds_char_rate_valid,
.avi = {
.clear_infoframe = accept_infoframe_clear_infoframe,
@@ -163,6 +174,11 @@ reject_100mhz_connector_tmds_char_rate_valid(const struct drm_connector *connect
}
static const struct drm_connector_hdmi_funcs reject_100mhz_connector_hdmi_funcs = {
+ .vendor = "Vendor",
+ .product = "Product",
+ .supported_hdmi_ver = HDMI_VERSION_1_4,
+ .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ .max_bpc = 8,
.tmds_char_rate_valid = reject_100mhz_connector_tmds_char_rate_valid,
.avi = {
.clear_infoframe = accept_infoframe_clear_infoframe,
@@ -231,8 +247,6 @@ static const struct drm_encoder_helper_funcs test_encoder_helper_funcs = {
static
struct drm_atomic_helper_connector_hdmi_priv *
__connector_hdmi_init(struct kunit *test,
- unsigned int formats,
- unsigned int max_bpc,
const struct drm_connector_hdmi_funcs *hdmi_funcs,
const void *edid_data, size_t edid_len)
{
@@ -273,16 +287,15 @@ __connector_hdmi_init(struct kunit *test,
enc->possible_crtcs = drm_crtc_mask(priv->crtc);
conn = &priv->connector;
- conn->ycbcr_420_allowed = !!(formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420));
+ conn->ycbcr_420_allowed = !!(hdmi_funcs->supported_formats &
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420));
- ret = drmm_connector_hdmi_ini2(drm, conn,
- "Vendor", "Product",
+ priv->hdmi_funcs = *hdmi_funcs;
+ ret = drmm_connector_hdmi_init(drm, conn,
&dummy_connector_funcs,
- hdmi_funcs,
+ &priv->hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
- NULL,
- formats,
- max_bpc);
+ NULL);
KUNIT_ASSERT_EQ(test, ret, 0);
drm_connector_helper_add(conn, &dummy_connector_helper_funcs);
@@ -298,18 +311,14 @@ __connector_hdmi_init(struct kunit *test,
return priv;
}
-#define drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, formats, max_bpc, funcs, edid) \
- __connector_hdmi_init(test, formats, max_bpc, funcs, edid, ARRAY_SIZE(edid))
+#define drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, funcs, edid) \
+ __connector_hdmi_init(test, funcs, edid, ARRAY_SIZE(edid))
static
struct drm_atomic_helper_connector_hdmi_priv *
-drm_kunit_helper_connector_hdmi_init(struct kunit *test,
- unsigned int formats,
- unsigned int max_bpc)
+drm_kunit_helper_connector_hdmi_init(struct kunit *test)
{
return drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- formats,
- max_bpc,
&dummy_connector_hdmi_funcs,
test_edid_hdmi_1080p_rgb_max_200mhz);
}
@@ -333,9 +342,7 @@ static void drm_test_check_broadcast_rgb_crtc_mode_changed(struct kunit *test)
struct drm_crtc *crtc;
int ret;
- priv = drm_kunit_helper_connector_hdmi_init(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ priv = drm_kunit_helper_connector_hdmi_init(test);
KUNIT_ASSERT_NOT_NULL(test, priv);
drm = &priv->drm;
@@ -408,9 +415,7 @@ static void drm_test_check_broadcast_rgb_crtc_mode_not_changed(struct kunit *tes
struct drm_crtc *crtc;
int ret;
- priv = drm_kunit_helper_connector_hdmi_init(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ priv = drm_kunit_helper_connector_hdmi_init(test);
KUNIT_ASSERT_NOT_NULL(test, priv);
drm = &priv->drm;
@@ -483,9 +488,7 @@ static void drm_test_check_broadcast_rgb_auto_cea_mode(struct kunit *test)
struct drm_crtc *crtc;
int ret;
- priv = drm_kunit_helper_connector_hdmi_init(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ priv = drm_kunit_helper_connector_hdmi_init(test);
KUNIT_ASSERT_NOT_NULL(test, priv);
drm = &priv->drm;
@@ -550,9 +553,7 @@ static void drm_test_check_broadcast_rgb_auto_cea_mode_vic_1(struct kunit *test)
struct drm_crtc *crtc;
int ret;
- priv = drm_kunit_helper_connector_hdmi_init(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ priv = drm_kunit_helper_connector_hdmi_init(test);
KUNIT_ASSERT_NOT_NULL(test, priv);
drm = &priv->drm;
@@ -617,9 +618,7 @@ static void drm_test_check_broadcast_rgb_full_cea_mode(struct kunit *test)
struct drm_crtc *crtc;
int ret;
- priv = drm_kunit_helper_connector_hdmi_init(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ priv = drm_kunit_helper_connector_hdmi_init(test);
KUNIT_ASSERT_NOT_NULL(test, priv);
drm = &priv->drm;
@@ -686,9 +685,7 @@ static void drm_test_check_broadcast_rgb_full_cea_mode_vic_1(struct kunit *test)
struct drm_crtc *crtc;
int ret;
- priv = drm_kunit_helper_connector_hdmi_init(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ priv = drm_kunit_helper_connector_hdmi_init(test);
KUNIT_ASSERT_NOT_NULL(test, priv);
drm = &priv->drm;
@@ -755,9 +752,7 @@ static void drm_test_check_broadcast_rgb_limited_cea_mode(struct kunit *test)
struct drm_crtc *crtc;
int ret;
- priv = drm_kunit_helper_connector_hdmi_init(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ priv = drm_kunit_helper_connector_hdmi_init(test);
KUNIT_ASSERT_NOT_NULL(test, priv);
drm = &priv->drm;
@@ -824,9 +819,7 @@ static void drm_test_check_broadcast_rgb_limited_cea_mode_vic_1(struct kunit *te
struct drm_crtc *crtc;
int ret;
- priv = drm_kunit_helper_connector_hdmi_init(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ priv = drm_kunit_helper_connector_hdmi_init(test);
KUNIT_ASSERT_NOT_NULL(test, priv);
drm = &priv->drm;
@@ -883,6 +876,7 @@ static void drm_test_check_broadcast_rgb_limited_cea_mode_vic_1(struct kunit *te
*/
static void drm_test_check_broadcast_rgb_cea_mode_yuv420(struct kunit *test)
{
+ struct drm_connector_hdmi_funcs hdmi_funcs = dummy_connector_hdmi_funcs;
struct drm_atomic_helper_connector_hdmi_priv *priv;
enum drm_hdmi_broadcast_rgb broadcast_rgb;
struct drm_modeset_acquire_ctx ctx;
@@ -895,12 +889,11 @@ static void drm_test_check_broadcast_rgb_cea_mode_yuv420(struct kunit *test)
int ret;
broadcast_rgb = *(enum drm_hdmi_broadcast_rgb *)test->param_value;
+ hdmi_funcs.supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420);
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420),
- 8,
- &dummy_connector_hdmi_funcs,
+ &hdmi_funcs,
test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -984,6 +977,7 @@ KUNIT_ARRAY_PARAM(check_broadcast_rgb_cea_mode_yuv420,
*/
static void drm_test_check_output_bpc_crtc_mode_changed(struct kunit *test)
{
+ struct drm_connector_hdmi_funcs hdmi_funcs = dummy_connector_hdmi_funcs;
struct drm_atomic_helper_connector_hdmi_priv *priv;
struct drm_modeset_acquire_ctx ctx;
struct drm_connector_state *old_conn_state;
@@ -996,10 +990,9 @@ static void drm_test_check_output_bpc_crtc_mode_changed(struct kunit *test)
struct drm_crtc *crtc;
int ret;
+ hdmi_funcs.max_bpc = 10;
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 10,
- &dummy_connector_hdmi_funcs,
+ &hdmi_funcs,
test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -1066,6 +1059,7 @@ static void drm_test_check_output_bpc_crtc_mode_changed(struct kunit *test)
*/
static void drm_test_check_output_bpc_crtc_mode_not_changed(struct kunit *test)
{
+ struct drm_connector_hdmi_funcs hdmi_funcs = dummy_connector_hdmi_funcs;
struct drm_atomic_helper_connector_hdmi_priv *priv;
struct drm_modeset_acquire_ctx ctx;
struct drm_connector_state *old_conn_state;
@@ -1078,10 +1072,9 @@ static void drm_test_check_output_bpc_crtc_mode_not_changed(struct kunit *test)
struct drm_crtc *crtc;
int ret;
+ hdmi_funcs.max_bpc = 10;
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 10,
- &dummy_connector_hdmi_funcs,
+ &hdmi_funcs,
test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -1145,6 +1138,7 @@ static void drm_test_check_output_bpc_crtc_mode_not_changed(struct kunit *test)
*/
static void drm_test_check_output_bpc_dvi(struct kunit *test)
{
+ struct drm_connector_hdmi_funcs hdmi_funcs = dummy_connector_hdmi_funcs;
struct drm_atomic_helper_connector_hdmi_priv *priv;
struct drm_modeset_acquire_ctx ctx;
struct drm_connector_state *conn_state;
@@ -1155,12 +1149,12 @@ static void drm_test_check_output_bpc_dvi(struct kunit *test)
struct drm_crtc *crtc;
int ret;
+ hdmi_funcs.max_bpc = 12;
+ hdmi_funcs.supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444);
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444),
- 12,
- &dummy_connector_hdmi_funcs,
+ &hdmi_funcs,
test_edid_dvi_1080p);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -1213,8 +1207,6 @@ static void drm_test_check_tmds_char_rate_rgb_8bpc(struct kunit *test)
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_1080p_rgb_max_200mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -1258,6 +1250,7 @@ static void drm_test_check_tmds_char_rate_rgb_8bpc(struct kunit *test)
*/
static void drm_test_check_tmds_char_rate_rgb_10bpc(struct kunit *test)
{
+ struct drm_connector_hdmi_funcs hdmi_funcs = dummy_connector_hdmi_funcs;
struct drm_atomic_helper_connector_hdmi_priv *priv;
struct drm_modeset_acquire_ctx ctx;
struct drm_connector_state *conn_state;
@@ -1267,10 +1260,9 @@ static void drm_test_check_tmds_char_rate_rgb_10bpc(struct kunit *test)
struct drm_crtc *crtc;
int ret;
+ hdmi_funcs.max_bpc = 10;
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 10,
- &dummy_connector_hdmi_funcs,
+ &hdmi_funcs,
test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -1313,6 +1305,7 @@ static void drm_test_check_tmds_char_rate_rgb_10bpc(struct kunit *test)
*/
static void drm_test_check_tmds_char_rate_rgb_12bpc(struct kunit *test)
{
+ struct drm_connector_hdmi_funcs hdmi_funcs = dummy_connector_hdmi_funcs;
struct drm_atomic_helper_connector_hdmi_priv *priv;
struct drm_modeset_acquire_ctx ctx;
struct drm_connector_state *conn_state;
@@ -1322,10 +1315,9 @@ static void drm_test_check_tmds_char_rate_rgb_12bpc(struct kunit *test)
struct drm_crtc *crtc;
int ret;
+ hdmi_funcs.max_bpc = 12;
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 12,
- &dummy_connector_hdmi_funcs,
+ &hdmi_funcs,
test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -1381,9 +1373,7 @@ static void drm_test_check_hdmi_funcs_reject_rate(struct kunit *test)
struct drm_crtc *crtc;
int ret;
- priv = drm_kunit_helper_connector_hdmi_init(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ priv = drm_kunit_helper_connector_hdmi_init(test);
KUNIT_ASSERT_NOT_NULL(test, priv);
drm = &priv->drm;
@@ -1438,6 +1428,7 @@ static void drm_test_check_hdmi_funcs_reject_rate(struct kunit *test)
*/
static void drm_test_check_max_tmds_rate_bpc_fallback_rgb(struct kunit *test)
{
+ struct drm_connector_hdmi_funcs hdmi_funcs = dummy_connector_hdmi_funcs;
struct drm_atomic_helper_connector_hdmi_priv *priv;
struct drm_modeset_acquire_ctx ctx;
struct drm_connector_state *conn_state;
@@ -1449,10 +1440,9 @@ static void drm_test_check_max_tmds_rate_bpc_fallback_rgb(struct kunit *test)
struct drm_crtc *crtc;
int ret;
+ hdmi_funcs.max_bpc = 12;
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 12,
- &dummy_connector_hdmi_funcs,
+ &hdmi_funcs,
test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -1512,6 +1502,7 @@ static void drm_test_check_max_tmds_rate_bpc_fallback_rgb(struct kunit *test)
*/
static void drm_test_check_max_tmds_rate_bpc_fallback_yuv420(struct kunit *test)
{
+ struct drm_connector_hdmi_funcs hdmi_funcs = dummy_connector_hdmi_funcs;
struct drm_atomic_helper_connector_hdmi_priv *priv;
struct drm_modeset_acquire_ctx ctx;
struct drm_connector_state *conn_state;
@@ -1523,11 +1514,11 @@ static void drm_test_check_max_tmds_rate_bpc_fallback_yuv420(struct kunit *test)
struct drm_crtc *crtc;
int ret;
+ hdmi_funcs.max_bpc = 12;
+ hdmi_funcs.supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420);
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420),
- 12,
- &dummy_connector_hdmi_funcs,
+ &hdmi_funcs,
test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -1588,6 +1579,7 @@ static void drm_test_check_max_tmds_rate_bpc_fallback_yuv420(struct kunit *test)
*/
static void drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv422(struct kunit *test)
{
+ struct drm_connector_hdmi_funcs hdmi_funcs = dummy_connector_hdmi_funcs;
struct drm_atomic_helper_connector_hdmi_priv *priv;
struct drm_modeset_acquire_ctx ctx;
struct drm_connector_state *conn_state;
@@ -1599,12 +1591,12 @@ static void drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv422(struct kunit
struct drm_crtc *crtc;
int ret;
+ hdmi_funcs.max_bpc = 12;
+ hdmi_funcs.supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444);
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444),
- 12,
- &dummy_connector_hdmi_funcs,
+ &hdmi_funcs,
test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -1669,6 +1661,7 @@ static void drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv422(struct kunit
*/
static void drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv420(struct kunit *test)
{
+ struct drm_connector_hdmi_funcs hdmi_funcs = dummy_connector_hdmi_funcs;
struct drm_atomic_helper_connector_hdmi_priv *priv;
struct drm_modeset_acquire_ctx ctx;
struct drm_connector_state *conn_state;
@@ -1680,11 +1673,11 @@ static void drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv420(struct kunit
struct drm_crtc *crtc;
int ret;
+ hdmi_funcs.max_bpc = 12;
+ hdmi_funcs.supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420);
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420),
- 12,
- &dummy_connector_hdmi_funcs,
+ &hdmi_funcs,
test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -1740,6 +1733,7 @@ static void drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv420(struct kunit
*/
static void drm_test_check_driver_unsupported_fallback_yuv420(struct kunit *test)
{
+ struct drm_connector_hdmi_funcs hdmi_funcs = dummy_connector_hdmi_funcs;
struct drm_atomic_helper_connector_hdmi_priv *priv;
struct drm_modeset_acquire_ctx ctx;
struct drm_connector_state *conn_state;
@@ -1752,10 +1746,9 @@ static void drm_test_check_driver_unsupported_fallback_yuv420(struct kunit *test
struct drm_crtc *crtc;
int ret;
+ hdmi_funcs.max_bpc = 12;
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 12,
- &dummy_connector_hdmi_funcs,
+ &hdmi_funcs,
test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -1826,6 +1819,7 @@ static void drm_test_check_driver_unsupported_fallback_yuv420(struct kunit *test
*/
static void drm_test_check_output_bpc_format_vic_1(struct kunit *test)
{
+ struct drm_connector_hdmi_funcs hdmi_funcs = dummy_connector_hdmi_funcs;
struct drm_atomic_helper_connector_hdmi_priv *priv;
struct drm_modeset_acquire_ctx ctx;
struct drm_connector_state *conn_state;
@@ -1837,12 +1831,12 @@ static void drm_test_check_output_bpc_format_vic_1(struct kunit *test)
struct drm_crtc *crtc;
int ret;
+ hdmi_funcs.max_bpc = 12;
+ hdmi_funcs.supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444);
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444),
- 12,
- &dummy_connector_hdmi_funcs,
+ &hdmi_funcs,
test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -1897,6 +1891,7 @@ static void drm_test_check_output_bpc_format_vic_1(struct kunit *test)
*/
static void drm_test_check_output_bpc_format_driver_rgb_only(struct kunit *test)
{
+ struct drm_connector_hdmi_funcs hdmi_funcs = dummy_connector_hdmi_funcs;
struct drm_atomic_helper_connector_hdmi_priv *priv;
struct drm_modeset_acquire_ctx ctx;
struct drm_connector_state *conn_state;
@@ -1908,10 +1903,9 @@ static void drm_test_check_output_bpc_format_driver_rgb_only(struct kunit *test)
struct drm_crtc *crtc;
int ret;
+ hdmi_funcs.max_bpc = 12;
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 12,
- &dummy_connector_hdmi_funcs,
+ &hdmi_funcs,
test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -1970,6 +1964,7 @@ static void drm_test_check_output_bpc_format_driver_rgb_only(struct kunit *test)
*/
static void drm_test_check_output_bpc_format_display_rgb_only(struct kunit *test)
{
+ struct drm_connector_hdmi_funcs hdmi_funcs = dummy_connector_hdmi_funcs;
struct drm_atomic_helper_connector_hdmi_priv *priv;
struct drm_modeset_acquire_ctx ctx;
struct drm_connector_state *conn_state;
@@ -1981,12 +1976,12 @@ static void drm_test_check_output_bpc_format_display_rgb_only(struct kunit *test
struct drm_crtc *crtc;
int ret;
+ hdmi_funcs.max_bpc = 12;
+ hdmi_funcs.supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444);
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444),
- 12,
- &dummy_connector_hdmi_funcs,
+ &hdmi_funcs,
test_edid_hdmi_1080p_rgb_max_200mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -2058,8 +2053,6 @@ static void drm_test_check_output_bpc_format_driver_8bpc_only(struct kunit *test
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_1080p_rgb_yuv_dc_max_340mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -2112,6 +2105,7 @@ static void drm_test_check_output_bpc_format_driver_8bpc_only(struct kunit *test
*/
static void drm_test_check_output_bpc_format_display_8bpc_only(struct kunit *test)
{
+ struct drm_connector_hdmi_funcs hdmi_funcs = dummy_connector_hdmi_funcs;
struct drm_atomic_helper_connector_hdmi_priv *priv;
struct drm_modeset_acquire_ctx ctx;
struct drm_connector_state *conn_state;
@@ -2123,12 +2117,12 @@ static void drm_test_check_output_bpc_format_display_8bpc_only(struct kunit *tes
struct drm_crtc *crtc;
int ret;
+ hdmi_funcs.max_bpc = 12;
+ hdmi_funcs.supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444);
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444),
- 12,
- &dummy_connector_hdmi_funcs,
+ &hdmi_funcs,
test_edid_hdmi_1080p_rgb_max_340mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -2187,9 +2181,7 @@ static void drm_test_check_disable_connector(struct kunit *test)
struct drm_crtc *crtc;
int ret;
- priv = drm_kunit_helper_connector_hdmi_init(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ priv = drm_kunit_helper_connector_hdmi_init(test);
KUNIT_ASSERT_NOT_NULL(test, priv);
drm_modeset_acquire_init(&ctx, 0);
@@ -2256,6 +2248,7 @@ struct color_format_test_param {
*/
static void drm_test_check_hdmi_color_format(struct kunit *test)
{
+ struct drm_connector_hdmi_funcs hdmi_funcs = dummy_connector_hdmi_funcs;
const struct color_format_test_param *param = test->param_value;
struct drm_atomic_helper_connector_hdmi_priv *priv;
struct drm_connector_state *conn_state;
@@ -2266,13 +2259,13 @@ static void drm_test_check_hdmi_color_format(struct kunit *test)
struct drm_display_mode *preferred;
int ret;
+ hdmi_funcs.max_bpc = 12;
+ hdmi_funcs.supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444);
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444),
- 12,
- &dummy_connector_hdmi_funcs,
+ &hdmi_funcs,
test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -2364,6 +2357,7 @@ KUNIT_ARRAY_PARAM_DESC(check_hdmi_color_format, hdmi_color_format_params, desc);
*/
static void drm_test_check_hdmi_color_format_420_only(struct kunit *test)
{
+ struct drm_connector_hdmi_funcs hdmi_funcs = dummy_connector_hdmi_funcs;
const struct color_format_test_param *param = test->param_value;
struct drm_atomic_helper_connector_hdmi_priv *priv;
struct drm_connector_state *conn_state;
@@ -2373,13 +2367,13 @@ static void drm_test_check_hdmi_color_format_420_only(struct kunit *test)
struct drm_display_mode *dank;
int ret;
+ hdmi_funcs.max_bpc = 12;
+ hdmi_funcs.supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444);
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444),
- 12,
- &dummy_connector_hdmi_funcs,
+ &hdmi_funcs,
test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -2507,9 +2501,7 @@ static void drm_test_check_broadcast_rgb_value(struct kunit *test)
struct drm_connector_state *conn_state;
struct drm_connector *conn;
- priv = drm_kunit_helper_connector_hdmi_init(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ priv = drm_kunit_helper_connector_hdmi_init(test);
KUNIT_ASSERT_NOT_NULL(test, priv);
conn = &priv->connector;
@@ -2529,9 +2521,7 @@ static void drm_test_check_bpc_8_value(struct kunit *test)
struct drm_connector_state *conn_state;
struct drm_connector *conn;
- priv = drm_kunit_helper_connector_hdmi_init(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ priv = drm_kunit_helper_connector_hdmi_init(test);
KUNIT_ASSERT_NOT_NULL(test, priv);
conn = &priv->connector;
@@ -2549,13 +2539,15 @@ static void drm_test_check_bpc_8_value(struct kunit *test)
*/
static void drm_test_check_bpc_10_value(struct kunit *test)
{
+ struct drm_connector_hdmi_funcs hdmi_funcs = dummy_connector_hdmi_funcs;
struct drm_atomic_helper_connector_hdmi_priv *priv;
struct drm_connector_state *conn_state;
struct drm_connector *conn;
- priv = drm_kunit_helper_connector_hdmi_init(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 10);
+ hdmi_funcs.max_bpc = 10;
+ priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
+ &hdmi_funcs,
+ test_edid_hdmi_1080p_rgb_max_200mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
conn = &priv->connector;
@@ -2573,13 +2565,15 @@ static void drm_test_check_bpc_10_value(struct kunit *test)
*/
static void drm_test_check_bpc_12_value(struct kunit *test)
{
+ struct drm_connector_hdmi_funcs hdmi_funcs = dummy_connector_hdmi_funcs;
struct drm_atomic_helper_connector_hdmi_priv *priv;
struct drm_connector_state *conn_state;
struct drm_connector *conn;
- priv = drm_kunit_helper_connector_hdmi_init(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 12);
+ hdmi_funcs.max_bpc = 12;
+ priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
+ &hdmi_funcs,
+ test_edid_hdmi_1080p_rgb_max_200mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
conn = &priv->connector;
@@ -2595,15 +2589,17 @@ static void drm_test_check_bpc_12_value(struct kunit *test)
*/
static void drm_test_check_format_value(struct kunit *test)
{
+ struct drm_connector_hdmi_funcs hdmi_funcs = dummy_connector_hdmi_funcs;
struct drm_atomic_helper_connector_hdmi_priv *priv;
struct drm_connector_state *conn_state;
struct drm_connector *conn;
- priv = drm_kunit_helper_connector_hdmi_init(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444),
- 8);
+ hdmi_funcs.supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444);
+ priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
+ &hdmi_funcs,
+ test_edid_hdmi_1080p_rgb_max_200mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
conn = &priv->connector;
@@ -2617,15 +2613,18 @@ static void drm_test_check_format_value(struct kunit *test)
*/
static void drm_test_check_tmds_char_value(struct kunit *test)
{
+ struct drm_connector_hdmi_funcs hdmi_funcs = dummy_connector_hdmi_funcs;
struct drm_atomic_helper_connector_hdmi_priv *priv;
struct drm_connector_state *conn_state;
struct drm_connector *conn;
- priv = drm_kunit_helper_connector_hdmi_init(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444),
- 12);
+ hdmi_funcs.max_bpc = 12;
+ hdmi_funcs.supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444);
+ priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
+ &hdmi_funcs,
+ test_edid_hdmi_1080p_rgb_max_200mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
conn = &priv->connector;
@@ -2659,9 +2658,7 @@ static void drm_test_check_mode_valid(struct kunit *test)
struct drm_connector *conn;
struct drm_display_mode *preferred;
- priv = drm_kunit_helper_connector_hdmi_init(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ priv = drm_kunit_helper_connector_hdmi_init(test);
KUNIT_ASSERT_NOT_NULL(test, priv);
conn = &priv->connector;
@@ -2684,8 +2681,6 @@ static void drm_test_check_mode_valid_reject_rate(struct kunit *test)
struct drm_display_mode *preferred;
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8,
&reject_100mhz_connector_hdmi_funcs,
test_edid_hdmi_1080p_rgb_max_200mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -2716,8 +2711,6 @@ static void drm_test_check_mode_valid_reject(struct kunit *test)
int ret;
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8,
&reject_connector_hdmi_funcs,
no_edid);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -2746,8 +2739,6 @@ static void drm_test_check_mode_valid_reject_max_clock(struct kunit *test)
struct drm_display_mode *preferred;
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_1080p_rgb_max_100mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -2769,15 +2760,15 @@ static void drm_test_check_mode_valid_reject_max_clock(struct kunit *test)
*/
static void drm_test_check_mode_valid_yuv420_only_max_clock(struct kunit *test)
{
+ struct drm_connector_hdmi_funcs hdmi_funcs = dummy_connector_hdmi_funcs;
struct drm_atomic_helper_connector_hdmi_priv *priv;
struct drm_display_mode *dank;
struct drm_connector *conn;
+ hdmi_funcs.supported_formats = BIT(HDMI_COLORSPACE_RGB) |
+ BIT(HDMI_COLORSPACE_YUV420);
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(HDMI_COLORSPACE_RGB) |
- BIT(HDMI_COLORSPACE_YUV420),
- 8,
- &dummy_connector_hdmi_funcs,
+ &hdmi_funcs,
test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -2809,8 +2800,6 @@ drm_test_check_mode_valid_reject_yuv420_only_connector(struct kunit *test)
struct drm_connector *conn;
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(HDMI_COLORSPACE_RGB),
- 8,
&dummy_connector_hdmi_funcs,
test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -2835,8 +2824,6 @@ drm_test_check_mode_valid_accept_yuv420_also_connector_rgb(struct kunit *test)
struct drm_connector *conn;
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(HDMI_COLORSPACE_RGB),
- 8,
&dummy_connector_hdmi_funcs,
test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -2885,8 +2872,6 @@ static void drm_test_check_infoframes(struct kunit *test)
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_1080p_rgb_max_200mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -2960,6 +2945,11 @@ static int reject_infoframe_write_infoframe(struct drm_connector *connector,
}
static const struct drm_connector_hdmi_funcs reject_avi_infoframe_hdmi_funcs = {
+ .vendor = "Vendor",
+ .product = "Product",
+ .supported_hdmi_ver = HDMI_VERSION_1_4,
+ .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ .max_bpc = 8,
.avi = {
.clear_infoframe = accept_infoframe_clear_infoframe,
.write_infoframe = reject_infoframe_write_infoframe,
@@ -2988,8 +2978,6 @@ static void drm_test_check_reject_avi_infoframe(struct kunit *test)
int ret;
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8,
&reject_avi_infoframe_hdmi_funcs,
test_edid_hdmi_1080p_rgb_max_200mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -3059,6 +3047,11 @@ static void drm_test_check_reject_avi_infoframe(struct kunit *test)
}
static const struct drm_connector_hdmi_funcs reject_hdr_infoframe_hdmi_funcs = {
+ .vendor = "Vendor",
+ .product = "Product",
+ .supported_hdmi_ver = HDMI_VERSION_1_4,
+ .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ .max_bpc = 8,
.avi = {
.clear_infoframe = accept_infoframe_clear_infoframe,
.write_infoframe = accept_infoframe_write_infoframe,
@@ -3092,8 +3085,6 @@ static void drm_test_check_reject_hdr_infoframe_bpc_8(struct kunit *test)
int ret;
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8,
&reject_hdr_infoframe_hdmi_funcs,
test_edid_hdmi_1080p_rgb_max_200mhz_hdr);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -3190,6 +3181,7 @@ static void drm_test_check_reject_hdr_infoframe_bpc_8(struct kunit *test)
*/
static void drm_test_check_reject_hdr_infoframe_bpc_10(struct kunit *test)
{
+ struct drm_connector_hdmi_funcs hdmi_funcs = reject_hdr_infoframe_hdmi_funcs;
struct drm_atomic_helper_connector_hdmi_priv *priv;
struct drm_modeset_acquire_ctx ctx;
struct drm_atomic_commit *state;
@@ -3205,10 +3197,9 @@ static void drm_test_check_reject_hdr_infoframe_bpc_10(struct kunit *test)
bool replaced;
int ret;
+ hdmi_funcs.max_bpc = 10;
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 10,
- &reject_hdr_infoframe_hdmi_funcs,
+ &hdmi_funcs,
test_edid_hdmi_1080p_rgb_max_200mhz_hdr);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -3307,6 +3298,11 @@ static void drm_test_check_reject_hdr_infoframe_bpc_10(struct kunit *test)
}
static const struct drm_connector_hdmi_funcs reject_audio_infoframe_hdmi_funcs = {
+ .vendor = "Vendor",
+ .product = "Product",
+ .supported_hdmi_ver = HDMI_VERSION_1_4,
+ .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ .max_bpc = 8,
.avi = {
.clear_infoframe = accept_infoframe_clear_infoframe,
.write_infoframe = accept_infoframe_write_infoframe,
@@ -3341,8 +3337,6 @@ static void drm_test_check_reject_audio_infoframe(struct kunit *test)
int ret;
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8,
&reject_audio_infoframe_hdmi_funcs,
test_edid_hdmi_1080p_rgb_max_200mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 63/69] drm/tests: hdmi_state_helper: Convert to drmm_connector_hdmi_init()
@ 2026-07-31 16:20 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:20 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
Switch tests over to the new drmm_connector_hdmi_init() signature, where
the vendor, product, supported_formats and max_bpc values previously
passed as arguments are now provided through struct
drm_connector_hdmi_funcs.
As a consequence, the tests exercising those values can no longer share
the static hdmi_funcs and need a modified copy of their own. Since the
connector retains a pointer to it, such a copy must not live on the
caller's stack, which is gone by the time the DRM-managed actions
release the connector.
Let __connector_hdmi_init() store it in struct
drm_atomic_helper_connector_hdmi_priv instead. This structure embeds
the DRM device and is freed through managed.final_kfree only after
drm_dev_release() has run all DRM-managed actions, so it strictly
outlives the connector.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 334 ++++++++++-----------
1 file changed, 164 insertions(+), 170 deletions(-)
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 4c2a400bc15a..f35dc31326bc 100644
--- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
+++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
@@ -32,6 +32,7 @@ struct drm_atomic_helper_connector_hdmi_priv {
struct drm_crtc *crtc;
struct drm_encoder encoder;
struct drm_connector connector;
+ struct drm_connector_hdmi_funcs hdmi_funcs;
const void *current_edid;
size_t current_edid_len;
@@ -124,6 +125,11 @@ static int accept_infoframe_write_infoframe(struct drm_connector *connector,
}
static const struct drm_connector_hdmi_funcs dummy_connector_hdmi_funcs = {
+ .vendor = "Vendor",
+ .product = "Product",
+ .supported_hdmi_ver = HDMI_VERSION_1_4,
+ .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ .max_bpc = 8,
.avi = {
.clear_infoframe = accept_infoframe_clear_infoframe,
.write_infoframe = accept_infoframe_write_infoframe,
@@ -143,6 +149,11 @@ reject_connector_tmds_char_rate_valid(const struct drm_connector *connector,
}
static const struct drm_connector_hdmi_funcs reject_connector_hdmi_funcs = {
+ .vendor = "Vendor",
+ .product = "Product",
+ .supported_hdmi_ver = HDMI_VERSION_1_4,
+ .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ .max_bpc = 8,
.tmds_char_rate_valid = reject_connector_tmds_char_rate_valid,
.avi = {
.clear_infoframe = accept_infoframe_clear_infoframe,
@@ -163,6 +174,11 @@ reject_100mhz_connector_tmds_char_rate_valid(const struct drm_connector *connect
}
static const struct drm_connector_hdmi_funcs reject_100mhz_connector_hdmi_funcs = {
+ .vendor = "Vendor",
+ .product = "Product",
+ .supported_hdmi_ver = HDMI_VERSION_1_4,
+ .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ .max_bpc = 8,
.tmds_char_rate_valid = reject_100mhz_connector_tmds_char_rate_valid,
.avi = {
.clear_infoframe = accept_infoframe_clear_infoframe,
@@ -231,8 +247,6 @@ static const struct drm_encoder_helper_funcs test_encoder_helper_funcs = {
static
struct drm_atomic_helper_connector_hdmi_priv *
__connector_hdmi_init(struct kunit *test,
- unsigned int formats,
- unsigned int max_bpc,
const struct drm_connector_hdmi_funcs *hdmi_funcs,
const void *edid_data, size_t edid_len)
{
@@ -273,16 +287,15 @@ __connector_hdmi_init(struct kunit *test,
enc->possible_crtcs = drm_crtc_mask(priv->crtc);
conn = &priv->connector;
- conn->ycbcr_420_allowed = !!(formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420));
+ conn->ycbcr_420_allowed = !!(hdmi_funcs->supported_formats &
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420));
- ret = drmm_connector_hdmi_ini2(drm, conn,
- "Vendor", "Product",
+ priv->hdmi_funcs = *hdmi_funcs;
+ ret = drmm_connector_hdmi_init(drm, conn,
&dummy_connector_funcs,
- hdmi_funcs,
+ &priv->hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
- NULL,
- formats,
- max_bpc);
+ NULL);
KUNIT_ASSERT_EQ(test, ret, 0);
drm_connector_helper_add(conn, &dummy_connector_helper_funcs);
@@ -298,18 +311,14 @@ __connector_hdmi_init(struct kunit *test,
return priv;
}
-#define drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, formats, max_bpc, funcs, edid) \
- __connector_hdmi_init(test, formats, max_bpc, funcs, edid, ARRAY_SIZE(edid))
+#define drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, funcs, edid) \
+ __connector_hdmi_init(test, funcs, edid, ARRAY_SIZE(edid))
static
struct drm_atomic_helper_connector_hdmi_priv *
-drm_kunit_helper_connector_hdmi_init(struct kunit *test,
- unsigned int formats,
- unsigned int max_bpc)
+drm_kunit_helper_connector_hdmi_init(struct kunit *test)
{
return drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- formats,
- max_bpc,
&dummy_connector_hdmi_funcs,
test_edid_hdmi_1080p_rgb_max_200mhz);
}
@@ -333,9 +342,7 @@ static void drm_test_check_broadcast_rgb_crtc_mode_changed(struct kunit *test)
struct drm_crtc *crtc;
int ret;
- priv = drm_kunit_helper_connector_hdmi_init(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ priv = drm_kunit_helper_connector_hdmi_init(test);
KUNIT_ASSERT_NOT_NULL(test, priv);
drm = &priv->drm;
@@ -408,9 +415,7 @@ static void drm_test_check_broadcast_rgb_crtc_mode_not_changed(struct kunit *tes
struct drm_crtc *crtc;
int ret;
- priv = drm_kunit_helper_connector_hdmi_init(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ priv = drm_kunit_helper_connector_hdmi_init(test);
KUNIT_ASSERT_NOT_NULL(test, priv);
drm = &priv->drm;
@@ -483,9 +488,7 @@ static void drm_test_check_broadcast_rgb_auto_cea_mode(struct kunit *test)
struct drm_crtc *crtc;
int ret;
- priv = drm_kunit_helper_connector_hdmi_init(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ priv = drm_kunit_helper_connector_hdmi_init(test);
KUNIT_ASSERT_NOT_NULL(test, priv);
drm = &priv->drm;
@@ -550,9 +553,7 @@ static void drm_test_check_broadcast_rgb_auto_cea_mode_vic_1(struct kunit *test)
struct drm_crtc *crtc;
int ret;
- priv = drm_kunit_helper_connector_hdmi_init(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ priv = drm_kunit_helper_connector_hdmi_init(test);
KUNIT_ASSERT_NOT_NULL(test, priv);
drm = &priv->drm;
@@ -617,9 +618,7 @@ static void drm_test_check_broadcast_rgb_full_cea_mode(struct kunit *test)
struct drm_crtc *crtc;
int ret;
- priv = drm_kunit_helper_connector_hdmi_init(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ priv = drm_kunit_helper_connector_hdmi_init(test);
KUNIT_ASSERT_NOT_NULL(test, priv);
drm = &priv->drm;
@@ -686,9 +685,7 @@ static void drm_test_check_broadcast_rgb_full_cea_mode_vic_1(struct kunit *test)
struct drm_crtc *crtc;
int ret;
- priv = drm_kunit_helper_connector_hdmi_init(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ priv = drm_kunit_helper_connector_hdmi_init(test);
KUNIT_ASSERT_NOT_NULL(test, priv);
drm = &priv->drm;
@@ -755,9 +752,7 @@ static void drm_test_check_broadcast_rgb_limited_cea_mode(struct kunit *test)
struct drm_crtc *crtc;
int ret;
- priv = drm_kunit_helper_connector_hdmi_init(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ priv = drm_kunit_helper_connector_hdmi_init(test);
KUNIT_ASSERT_NOT_NULL(test, priv);
drm = &priv->drm;
@@ -824,9 +819,7 @@ static void drm_test_check_broadcast_rgb_limited_cea_mode_vic_1(struct kunit *te
struct drm_crtc *crtc;
int ret;
- priv = drm_kunit_helper_connector_hdmi_init(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ priv = drm_kunit_helper_connector_hdmi_init(test);
KUNIT_ASSERT_NOT_NULL(test, priv);
drm = &priv->drm;
@@ -883,6 +876,7 @@ static void drm_test_check_broadcast_rgb_limited_cea_mode_vic_1(struct kunit *te
*/
static void drm_test_check_broadcast_rgb_cea_mode_yuv420(struct kunit *test)
{
+ struct drm_connector_hdmi_funcs hdmi_funcs = dummy_connector_hdmi_funcs;
struct drm_atomic_helper_connector_hdmi_priv *priv;
enum drm_hdmi_broadcast_rgb broadcast_rgb;
struct drm_modeset_acquire_ctx ctx;
@@ -895,12 +889,11 @@ static void drm_test_check_broadcast_rgb_cea_mode_yuv420(struct kunit *test)
int ret;
broadcast_rgb = *(enum drm_hdmi_broadcast_rgb *)test->param_value;
+ hdmi_funcs.supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420);
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420),
- 8,
- &dummy_connector_hdmi_funcs,
+ &hdmi_funcs,
test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -984,6 +977,7 @@ KUNIT_ARRAY_PARAM(check_broadcast_rgb_cea_mode_yuv420,
*/
static void drm_test_check_output_bpc_crtc_mode_changed(struct kunit *test)
{
+ struct drm_connector_hdmi_funcs hdmi_funcs = dummy_connector_hdmi_funcs;
struct drm_atomic_helper_connector_hdmi_priv *priv;
struct drm_modeset_acquire_ctx ctx;
struct drm_connector_state *old_conn_state;
@@ -996,10 +990,9 @@ static void drm_test_check_output_bpc_crtc_mode_changed(struct kunit *test)
struct drm_crtc *crtc;
int ret;
+ hdmi_funcs.max_bpc = 10;
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 10,
- &dummy_connector_hdmi_funcs,
+ &hdmi_funcs,
test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -1066,6 +1059,7 @@ static void drm_test_check_output_bpc_crtc_mode_changed(struct kunit *test)
*/
static void drm_test_check_output_bpc_crtc_mode_not_changed(struct kunit *test)
{
+ struct drm_connector_hdmi_funcs hdmi_funcs = dummy_connector_hdmi_funcs;
struct drm_atomic_helper_connector_hdmi_priv *priv;
struct drm_modeset_acquire_ctx ctx;
struct drm_connector_state *old_conn_state;
@@ -1078,10 +1072,9 @@ static void drm_test_check_output_bpc_crtc_mode_not_changed(struct kunit *test)
struct drm_crtc *crtc;
int ret;
+ hdmi_funcs.max_bpc = 10;
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 10,
- &dummy_connector_hdmi_funcs,
+ &hdmi_funcs,
test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -1145,6 +1138,7 @@ static void drm_test_check_output_bpc_crtc_mode_not_changed(struct kunit *test)
*/
static void drm_test_check_output_bpc_dvi(struct kunit *test)
{
+ struct drm_connector_hdmi_funcs hdmi_funcs = dummy_connector_hdmi_funcs;
struct drm_atomic_helper_connector_hdmi_priv *priv;
struct drm_modeset_acquire_ctx ctx;
struct drm_connector_state *conn_state;
@@ -1155,12 +1149,12 @@ static void drm_test_check_output_bpc_dvi(struct kunit *test)
struct drm_crtc *crtc;
int ret;
+ hdmi_funcs.max_bpc = 12;
+ hdmi_funcs.supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444);
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444),
- 12,
- &dummy_connector_hdmi_funcs,
+ &hdmi_funcs,
test_edid_dvi_1080p);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -1213,8 +1207,6 @@ static void drm_test_check_tmds_char_rate_rgb_8bpc(struct kunit *test)
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_1080p_rgb_max_200mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -1258,6 +1250,7 @@ static void drm_test_check_tmds_char_rate_rgb_8bpc(struct kunit *test)
*/
static void drm_test_check_tmds_char_rate_rgb_10bpc(struct kunit *test)
{
+ struct drm_connector_hdmi_funcs hdmi_funcs = dummy_connector_hdmi_funcs;
struct drm_atomic_helper_connector_hdmi_priv *priv;
struct drm_modeset_acquire_ctx ctx;
struct drm_connector_state *conn_state;
@@ -1267,10 +1260,9 @@ static void drm_test_check_tmds_char_rate_rgb_10bpc(struct kunit *test)
struct drm_crtc *crtc;
int ret;
+ hdmi_funcs.max_bpc = 10;
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 10,
- &dummy_connector_hdmi_funcs,
+ &hdmi_funcs,
test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -1313,6 +1305,7 @@ static void drm_test_check_tmds_char_rate_rgb_10bpc(struct kunit *test)
*/
static void drm_test_check_tmds_char_rate_rgb_12bpc(struct kunit *test)
{
+ struct drm_connector_hdmi_funcs hdmi_funcs = dummy_connector_hdmi_funcs;
struct drm_atomic_helper_connector_hdmi_priv *priv;
struct drm_modeset_acquire_ctx ctx;
struct drm_connector_state *conn_state;
@@ -1322,10 +1315,9 @@ static void drm_test_check_tmds_char_rate_rgb_12bpc(struct kunit *test)
struct drm_crtc *crtc;
int ret;
+ hdmi_funcs.max_bpc = 12;
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 12,
- &dummy_connector_hdmi_funcs,
+ &hdmi_funcs,
test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -1381,9 +1373,7 @@ static void drm_test_check_hdmi_funcs_reject_rate(struct kunit *test)
struct drm_crtc *crtc;
int ret;
- priv = drm_kunit_helper_connector_hdmi_init(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ priv = drm_kunit_helper_connector_hdmi_init(test);
KUNIT_ASSERT_NOT_NULL(test, priv);
drm = &priv->drm;
@@ -1438,6 +1428,7 @@ static void drm_test_check_hdmi_funcs_reject_rate(struct kunit *test)
*/
static void drm_test_check_max_tmds_rate_bpc_fallback_rgb(struct kunit *test)
{
+ struct drm_connector_hdmi_funcs hdmi_funcs = dummy_connector_hdmi_funcs;
struct drm_atomic_helper_connector_hdmi_priv *priv;
struct drm_modeset_acquire_ctx ctx;
struct drm_connector_state *conn_state;
@@ -1449,10 +1440,9 @@ static void drm_test_check_max_tmds_rate_bpc_fallback_rgb(struct kunit *test)
struct drm_crtc *crtc;
int ret;
+ hdmi_funcs.max_bpc = 12;
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 12,
- &dummy_connector_hdmi_funcs,
+ &hdmi_funcs,
test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -1512,6 +1502,7 @@ static void drm_test_check_max_tmds_rate_bpc_fallback_rgb(struct kunit *test)
*/
static void drm_test_check_max_tmds_rate_bpc_fallback_yuv420(struct kunit *test)
{
+ struct drm_connector_hdmi_funcs hdmi_funcs = dummy_connector_hdmi_funcs;
struct drm_atomic_helper_connector_hdmi_priv *priv;
struct drm_modeset_acquire_ctx ctx;
struct drm_connector_state *conn_state;
@@ -1523,11 +1514,11 @@ static void drm_test_check_max_tmds_rate_bpc_fallback_yuv420(struct kunit *test)
struct drm_crtc *crtc;
int ret;
+ hdmi_funcs.max_bpc = 12;
+ hdmi_funcs.supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420);
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420),
- 12,
- &dummy_connector_hdmi_funcs,
+ &hdmi_funcs,
test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -1588,6 +1579,7 @@ static void drm_test_check_max_tmds_rate_bpc_fallback_yuv420(struct kunit *test)
*/
static void drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv422(struct kunit *test)
{
+ struct drm_connector_hdmi_funcs hdmi_funcs = dummy_connector_hdmi_funcs;
struct drm_atomic_helper_connector_hdmi_priv *priv;
struct drm_modeset_acquire_ctx ctx;
struct drm_connector_state *conn_state;
@@ -1599,12 +1591,12 @@ static void drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv422(struct kunit
struct drm_crtc *crtc;
int ret;
+ hdmi_funcs.max_bpc = 12;
+ hdmi_funcs.supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444);
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444),
- 12,
- &dummy_connector_hdmi_funcs,
+ &hdmi_funcs,
test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -1669,6 +1661,7 @@ static void drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv422(struct kunit
*/
static void drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv420(struct kunit *test)
{
+ struct drm_connector_hdmi_funcs hdmi_funcs = dummy_connector_hdmi_funcs;
struct drm_atomic_helper_connector_hdmi_priv *priv;
struct drm_modeset_acquire_ctx ctx;
struct drm_connector_state *conn_state;
@@ -1680,11 +1673,11 @@ static void drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv420(struct kunit
struct drm_crtc *crtc;
int ret;
+ hdmi_funcs.max_bpc = 12;
+ hdmi_funcs.supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420);
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420),
- 12,
- &dummy_connector_hdmi_funcs,
+ &hdmi_funcs,
test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -1740,6 +1733,7 @@ static void drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv420(struct kunit
*/
static void drm_test_check_driver_unsupported_fallback_yuv420(struct kunit *test)
{
+ struct drm_connector_hdmi_funcs hdmi_funcs = dummy_connector_hdmi_funcs;
struct drm_atomic_helper_connector_hdmi_priv *priv;
struct drm_modeset_acquire_ctx ctx;
struct drm_connector_state *conn_state;
@@ -1752,10 +1746,9 @@ static void drm_test_check_driver_unsupported_fallback_yuv420(struct kunit *test
struct drm_crtc *crtc;
int ret;
+ hdmi_funcs.max_bpc = 12;
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 12,
- &dummy_connector_hdmi_funcs,
+ &hdmi_funcs,
test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -1826,6 +1819,7 @@ static void drm_test_check_driver_unsupported_fallback_yuv420(struct kunit *test
*/
static void drm_test_check_output_bpc_format_vic_1(struct kunit *test)
{
+ struct drm_connector_hdmi_funcs hdmi_funcs = dummy_connector_hdmi_funcs;
struct drm_atomic_helper_connector_hdmi_priv *priv;
struct drm_modeset_acquire_ctx ctx;
struct drm_connector_state *conn_state;
@@ -1837,12 +1831,12 @@ static void drm_test_check_output_bpc_format_vic_1(struct kunit *test)
struct drm_crtc *crtc;
int ret;
+ hdmi_funcs.max_bpc = 12;
+ hdmi_funcs.supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444);
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444),
- 12,
- &dummy_connector_hdmi_funcs,
+ &hdmi_funcs,
test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -1897,6 +1891,7 @@ static void drm_test_check_output_bpc_format_vic_1(struct kunit *test)
*/
static void drm_test_check_output_bpc_format_driver_rgb_only(struct kunit *test)
{
+ struct drm_connector_hdmi_funcs hdmi_funcs = dummy_connector_hdmi_funcs;
struct drm_atomic_helper_connector_hdmi_priv *priv;
struct drm_modeset_acquire_ctx ctx;
struct drm_connector_state *conn_state;
@@ -1908,10 +1903,9 @@ static void drm_test_check_output_bpc_format_driver_rgb_only(struct kunit *test)
struct drm_crtc *crtc;
int ret;
+ hdmi_funcs.max_bpc = 12;
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 12,
- &dummy_connector_hdmi_funcs,
+ &hdmi_funcs,
test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -1970,6 +1964,7 @@ static void drm_test_check_output_bpc_format_driver_rgb_only(struct kunit *test)
*/
static void drm_test_check_output_bpc_format_display_rgb_only(struct kunit *test)
{
+ struct drm_connector_hdmi_funcs hdmi_funcs = dummy_connector_hdmi_funcs;
struct drm_atomic_helper_connector_hdmi_priv *priv;
struct drm_modeset_acquire_ctx ctx;
struct drm_connector_state *conn_state;
@@ -1981,12 +1976,12 @@ static void drm_test_check_output_bpc_format_display_rgb_only(struct kunit *test
struct drm_crtc *crtc;
int ret;
+ hdmi_funcs.max_bpc = 12;
+ hdmi_funcs.supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444);
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444),
- 12,
- &dummy_connector_hdmi_funcs,
+ &hdmi_funcs,
test_edid_hdmi_1080p_rgb_max_200mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -2058,8 +2053,6 @@ static void drm_test_check_output_bpc_format_driver_8bpc_only(struct kunit *test
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_1080p_rgb_yuv_dc_max_340mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -2112,6 +2105,7 @@ static void drm_test_check_output_bpc_format_driver_8bpc_only(struct kunit *test
*/
static void drm_test_check_output_bpc_format_display_8bpc_only(struct kunit *test)
{
+ struct drm_connector_hdmi_funcs hdmi_funcs = dummy_connector_hdmi_funcs;
struct drm_atomic_helper_connector_hdmi_priv *priv;
struct drm_modeset_acquire_ctx ctx;
struct drm_connector_state *conn_state;
@@ -2123,12 +2117,12 @@ static void drm_test_check_output_bpc_format_display_8bpc_only(struct kunit *tes
struct drm_crtc *crtc;
int ret;
+ hdmi_funcs.max_bpc = 12;
+ hdmi_funcs.supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444);
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444),
- 12,
- &dummy_connector_hdmi_funcs,
+ &hdmi_funcs,
test_edid_hdmi_1080p_rgb_max_340mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -2187,9 +2181,7 @@ static void drm_test_check_disable_connector(struct kunit *test)
struct drm_crtc *crtc;
int ret;
- priv = drm_kunit_helper_connector_hdmi_init(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ priv = drm_kunit_helper_connector_hdmi_init(test);
KUNIT_ASSERT_NOT_NULL(test, priv);
drm_modeset_acquire_init(&ctx, 0);
@@ -2256,6 +2248,7 @@ struct color_format_test_param {
*/
static void drm_test_check_hdmi_color_format(struct kunit *test)
{
+ struct drm_connector_hdmi_funcs hdmi_funcs = dummy_connector_hdmi_funcs;
const struct color_format_test_param *param = test->param_value;
struct drm_atomic_helper_connector_hdmi_priv *priv;
struct drm_connector_state *conn_state;
@@ -2266,13 +2259,13 @@ static void drm_test_check_hdmi_color_format(struct kunit *test)
struct drm_display_mode *preferred;
int ret;
+ hdmi_funcs.max_bpc = 12;
+ hdmi_funcs.supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444);
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444),
- 12,
- &dummy_connector_hdmi_funcs,
+ &hdmi_funcs,
test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -2364,6 +2357,7 @@ KUNIT_ARRAY_PARAM_DESC(check_hdmi_color_format, hdmi_color_format_params, desc);
*/
static void drm_test_check_hdmi_color_format_420_only(struct kunit *test)
{
+ struct drm_connector_hdmi_funcs hdmi_funcs = dummy_connector_hdmi_funcs;
const struct color_format_test_param *param = test->param_value;
struct drm_atomic_helper_connector_hdmi_priv *priv;
struct drm_connector_state *conn_state;
@@ -2373,13 +2367,13 @@ static void drm_test_check_hdmi_color_format_420_only(struct kunit *test)
struct drm_display_mode *dank;
int ret;
+ hdmi_funcs.max_bpc = 12;
+ hdmi_funcs.supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444);
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444),
- 12,
- &dummy_connector_hdmi_funcs,
+ &hdmi_funcs,
test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -2507,9 +2501,7 @@ static void drm_test_check_broadcast_rgb_value(struct kunit *test)
struct drm_connector_state *conn_state;
struct drm_connector *conn;
- priv = drm_kunit_helper_connector_hdmi_init(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ priv = drm_kunit_helper_connector_hdmi_init(test);
KUNIT_ASSERT_NOT_NULL(test, priv);
conn = &priv->connector;
@@ -2529,9 +2521,7 @@ static void drm_test_check_bpc_8_value(struct kunit *test)
struct drm_connector_state *conn_state;
struct drm_connector *conn;
- priv = drm_kunit_helper_connector_hdmi_init(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ priv = drm_kunit_helper_connector_hdmi_init(test);
KUNIT_ASSERT_NOT_NULL(test, priv);
conn = &priv->connector;
@@ -2549,13 +2539,15 @@ static void drm_test_check_bpc_8_value(struct kunit *test)
*/
static void drm_test_check_bpc_10_value(struct kunit *test)
{
+ struct drm_connector_hdmi_funcs hdmi_funcs = dummy_connector_hdmi_funcs;
struct drm_atomic_helper_connector_hdmi_priv *priv;
struct drm_connector_state *conn_state;
struct drm_connector *conn;
- priv = drm_kunit_helper_connector_hdmi_init(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 10);
+ hdmi_funcs.max_bpc = 10;
+ priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
+ &hdmi_funcs,
+ test_edid_hdmi_1080p_rgb_max_200mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
conn = &priv->connector;
@@ -2573,13 +2565,15 @@ static void drm_test_check_bpc_10_value(struct kunit *test)
*/
static void drm_test_check_bpc_12_value(struct kunit *test)
{
+ struct drm_connector_hdmi_funcs hdmi_funcs = dummy_connector_hdmi_funcs;
struct drm_atomic_helper_connector_hdmi_priv *priv;
struct drm_connector_state *conn_state;
struct drm_connector *conn;
- priv = drm_kunit_helper_connector_hdmi_init(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 12);
+ hdmi_funcs.max_bpc = 12;
+ priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
+ &hdmi_funcs,
+ test_edid_hdmi_1080p_rgb_max_200mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
conn = &priv->connector;
@@ -2595,15 +2589,17 @@ static void drm_test_check_bpc_12_value(struct kunit *test)
*/
static void drm_test_check_format_value(struct kunit *test)
{
+ struct drm_connector_hdmi_funcs hdmi_funcs = dummy_connector_hdmi_funcs;
struct drm_atomic_helper_connector_hdmi_priv *priv;
struct drm_connector_state *conn_state;
struct drm_connector *conn;
- priv = drm_kunit_helper_connector_hdmi_init(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444),
- 8);
+ hdmi_funcs.supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444);
+ priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
+ &hdmi_funcs,
+ test_edid_hdmi_1080p_rgb_max_200mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
conn = &priv->connector;
@@ -2617,15 +2613,18 @@ static void drm_test_check_format_value(struct kunit *test)
*/
static void drm_test_check_tmds_char_value(struct kunit *test)
{
+ struct drm_connector_hdmi_funcs hdmi_funcs = dummy_connector_hdmi_funcs;
struct drm_atomic_helper_connector_hdmi_priv *priv;
struct drm_connector_state *conn_state;
struct drm_connector *conn;
- priv = drm_kunit_helper_connector_hdmi_init(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444),
- 12);
+ hdmi_funcs.max_bpc = 12;
+ hdmi_funcs.supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444);
+ priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
+ &hdmi_funcs,
+ test_edid_hdmi_1080p_rgb_max_200mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
conn = &priv->connector;
@@ -2659,9 +2658,7 @@ static void drm_test_check_mode_valid(struct kunit *test)
struct drm_connector *conn;
struct drm_display_mode *preferred;
- priv = drm_kunit_helper_connector_hdmi_init(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ priv = drm_kunit_helper_connector_hdmi_init(test);
KUNIT_ASSERT_NOT_NULL(test, priv);
conn = &priv->connector;
@@ -2684,8 +2681,6 @@ static void drm_test_check_mode_valid_reject_rate(struct kunit *test)
struct drm_display_mode *preferred;
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8,
&reject_100mhz_connector_hdmi_funcs,
test_edid_hdmi_1080p_rgb_max_200mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -2716,8 +2711,6 @@ static void drm_test_check_mode_valid_reject(struct kunit *test)
int ret;
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8,
&reject_connector_hdmi_funcs,
no_edid);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -2746,8 +2739,6 @@ static void drm_test_check_mode_valid_reject_max_clock(struct kunit *test)
struct drm_display_mode *preferred;
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_1080p_rgb_max_100mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -2769,15 +2760,15 @@ static void drm_test_check_mode_valid_reject_max_clock(struct kunit *test)
*/
static void drm_test_check_mode_valid_yuv420_only_max_clock(struct kunit *test)
{
+ struct drm_connector_hdmi_funcs hdmi_funcs = dummy_connector_hdmi_funcs;
struct drm_atomic_helper_connector_hdmi_priv *priv;
struct drm_display_mode *dank;
struct drm_connector *conn;
+ hdmi_funcs.supported_formats = BIT(HDMI_COLORSPACE_RGB) |
+ BIT(HDMI_COLORSPACE_YUV420);
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(HDMI_COLORSPACE_RGB) |
- BIT(HDMI_COLORSPACE_YUV420),
- 8,
- &dummy_connector_hdmi_funcs,
+ &hdmi_funcs,
test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -2809,8 +2800,6 @@ drm_test_check_mode_valid_reject_yuv420_only_connector(struct kunit *test)
struct drm_connector *conn;
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(HDMI_COLORSPACE_RGB),
- 8,
&dummy_connector_hdmi_funcs,
test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -2835,8 +2824,6 @@ drm_test_check_mode_valid_accept_yuv420_also_connector_rgb(struct kunit *test)
struct drm_connector *conn;
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(HDMI_COLORSPACE_RGB),
- 8,
&dummy_connector_hdmi_funcs,
test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -2885,8 +2872,6 @@ static void drm_test_check_infoframes(struct kunit *test)
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_1080p_rgb_max_200mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -2960,6 +2945,11 @@ static int reject_infoframe_write_infoframe(struct drm_connector *connector,
}
static const struct drm_connector_hdmi_funcs reject_avi_infoframe_hdmi_funcs = {
+ .vendor = "Vendor",
+ .product = "Product",
+ .supported_hdmi_ver = HDMI_VERSION_1_4,
+ .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ .max_bpc = 8,
.avi = {
.clear_infoframe = accept_infoframe_clear_infoframe,
.write_infoframe = reject_infoframe_write_infoframe,
@@ -2988,8 +2978,6 @@ static void drm_test_check_reject_avi_infoframe(struct kunit *test)
int ret;
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8,
&reject_avi_infoframe_hdmi_funcs,
test_edid_hdmi_1080p_rgb_max_200mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -3059,6 +3047,11 @@ static void drm_test_check_reject_avi_infoframe(struct kunit *test)
}
static const struct drm_connector_hdmi_funcs reject_hdr_infoframe_hdmi_funcs = {
+ .vendor = "Vendor",
+ .product = "Product",
+ .supported_hdmi_ver = HDMI_VERSION_1_4,
+ .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ .max_bpc = 8,
.avi = {
.clear_infoframe = accept_infoframe_clear_infoframe,
.write_infoframe = accept_infoframe_write_infoframe,
@@ -3092,8 +3085,6 @@ static void drm_test_check_reject_hdr_infoframe_bpc_8(struct kunit *test)
int ret;
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8,
&reject_hdr_infoframe_hdmi_funcs,
test_edid_hdmi_1080p_rgb_max_200mhz_hdr);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -3190,6 +3181,7 @@ static void drm_test_check_reject_hdr_infoframe_bpc_8(struct kunit *test)
*/
static void drm_test_check_reject_hdr_infoframe_bpc_10(struct kunit *test)
{
+ struct drm_connector_hdmi_funcs hdmi_funcs = reject_hdr_infoframe_hdmi_funcs;
struct drm_atomic_helper_connector_hdmi_priv *priv;
struct drm_modeset_acquire_ctx ctx;
struct drm_atomic_commit *state;
@@ -3205,10 +3197,9 @@ static void drm_test_check_reject_hdr_infoframe_bpc_10(struct kunit *test)
bool replaced;
int ret;
+ hdmi_funcs.max_bpc = 10;
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 10,
- &reject_hdr_infoframe_hdmi_funcs,
+ &hdmi_funcs,
test_edid_hdmi_1080p_rgb_max_200mhz_hdr);
KUNIT_ASSERT_NOT_NULL(test, priv);
@@ -3307,6 +3298,11 @@ static void drm_test_check_reject_hdr_infoframe_bpc_10(struct kunit *test)
}
static const struct drm_connector_hdmi_funcs reject_audio_infoframe_hdmi_funcs = {
+ .vendor = "Vendor",
+ .product = "Product",
+ .supported_hdmi_ver = HDMI_VERSION_1_4,
+ .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ .max_bpc = 8,
.avi = {
.clear_infoframe = accept_infoframe_clear_infoframe,
.write_infoframe = accept_infoframe_write_infoframe,
@@ -3341,8 +3337,6 @@ static void drm_test_check_reject_audio_infoframe(struct kunit *test)
int ret;
priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8,
&reject_audio_infoframe_hdmi_funcs,
test_edid_hdmi_1080p_rgb_max_200mhz);
KUNIT_ASSERT_NOT_NULL(test, priv);
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 64/69] drm/tests: hdmi_state_helper: Add connector-provided max_tmds_char_rate coverage
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:20 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:20 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
Test the hdmi_clock_valid() logic that rejects modes whose TMDS
character rate exceeds connector->hdmi.max_tmds_char_rate.
Exercise both an explicit limit set through drm_connector_hdmi_funcs'
supported_tmds_char_rate and the limit inferred from supported_hdmi_ver.
Also verify that a driver hook can further restrict the connector limit.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 116 +++++++++++++++++++++
1 file changed, 116 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 f35dc31326bc..6d648332aa15 100644
--- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
+++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
@@ -190,6 +190,32 @@ static const struct drm_connector_hdmi_funcs reject_100mhz_connector_hdmi_funcs
},
};
+static enum drm_mode_status
+accept_any_connector_tmds_char_rate_valid(const struct drm_connector *connector,
+ const struct drm_display_mode *mode,
+ unsigned long long tmds_rate)
+{
+ return MODE_OK;
+}
+
+static const struct drm_connector_hdmi_funcs reject_over_165mhz_connector_hdmi_funcs = {
+ .vendor = "Vendor",
+ .product = "Product",
+ .supported_hdmi_ver = HDMI_VERSION_1_3,
+ .supported_tmds_char_rate = HDMI_1_0_TMDS_CHAR_RATE_MAX_HZ,
+ .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ .max_bpc = 8,
+ .tmds_char_rate_valid = accept_any_connector_tmds_char_rate_valid,
+ .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 =
@@ -2753,6 +2779,93 @@ static void drm_test_check_mode_valid_reject_max_clock(struct kunit *test)
KUNIT_EXPECT_EQ(test, preferred->clock, 25200);
}
+/*
+ * Test that the max_tmds_char_rate inferred from caps.supported_hdmi_ver
+ * is applied as a mode-filtering limit: with an HDMI 1.3 connector and no
+ * driver hook, drm_hdmi_connector_mode_valid() will reject modes whose TMDS
+ * character rate exceeds 340 MHz, even though the sink itself advertises
+ * a higher limit (600 MHz).
+ */
+static void
+drm_test_check_mode_valid_reject_inferred_max_tmds_char_rate(struct kunit *test)
+{
+ struct drm_connector_hdmi_funcs hdmi_funcs = dummy_connector_hdmi_funcs;
+ struct drm_atomic_helper_connector_hdmi_priv *priv;
+ struct drm_display_mode *preferred;
+
+ hdmi_funcs.supported_hdmi_ver = HDMI_VERSION_1_3;
+
+ priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, &hdmi_funcs,
+ test_edid_hdmi_4k_rgb_yuv420_dc_max_600mhz);
+ KUNIT_ASSERT_NOT_NULL(test, priv);
+
+ KUNIT_ASSERT_EQ(test, priv->connector.hdmi.max_tmds_char_rate,
+ HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ);
+
+ preferred = find_preferred_mode(&priv->connector);
+ KUNIT_ASSERT_NOT_NULL(test, preferred);
+ KUNIT_EXPECT_EQ(test, preferred->hdisplay, 2560);
+ KUNIT_EXPECT_EQ(test, preferred->vdisplay, 1600);
+ KUNIT_EXPECT_EQ(test, preferred->clock, 268500);
+}
+
+/*
+ * Test that a connector-provided max_tmds_char_rate limit (165 MHz) takes
+ * precedence over a permissive .tmds_char_rate_valid() driver hook and
+ * drm_hdmi_connector_mode_valid() will reject modes whose computed TMDS
+ * character exceeds the connector limit.
+ */
+static void
+drm_test_check_mode_valid_connector_max_tmds_char_rate_precedes_driver_hook(struct kunit *test)
+{
+ struct drm_atomic_helper_connector_hdmi_priv *priv;
+ struct drm_display_mode *preferred;
+
+ priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
+ &reject_over_165mhz_connector_hdmi_funcs,
+ test_edid_hdmi_4k_rgb_yuv420_dc_max_600mhz);
+ KUNIT_ASSERT_NOT_NULL(test, priv);
+
+ KUNIT_ASSERT_EQ(test, priv->connector.hdmi.max_tmds_char_rate,
+ HDMI_1_0_TMDS_CHAR_RATE_MAX_HZ);
+
+ preferred = find_preferred_mode(&priv->connector);
+ KUNIT_ASSERT_NOT_NULL(test, preferred);
+ KUNIT_EXPECT_EQ(test, preferred->hdisplay, 2048);
+ KUNIT_EXPECT_EQ(test, preferred->vdisplay, 1152);
+ KUNIT_EXPECT_EQ(test, preferred->clock, 162000);
+}
+
+/*
+ * Test that a connector-provided max_tmds_char_rate (165 MHz) can be further
+ * limited by a more restrictive (100 MHz) .tmds_char_rate_valid() driver hook
+ * and drm_hdmi_connector_mode_valid() will reject modes whose computed TMDS
+ * character exceeds the hook limit.
+ */
+static void
+drm_test_check_mode_valid_driver_hook_limits_connector_max_tmds_char_rate(struct kunit *test)
+{
+ struct drm_connector_hdmi_funcs hdmi_funcs = reject_100mhz_connector_hdmi_funcs;
+ struct drm_atomic_helper_connector_hdmi_priv *priv;
+ struct drm_display_mode *preferred;
+
+ hdmi_funcs.supported_hdmi_ver = HDMI_VERSION_1_3;
+ hdmi_funcs.supported_tmds_char_rate = HDMI_1_0_TMDS_CHAR_RATE_MAX_HZ;
+
+ priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, &hdmi_funcs,
+ test_edid_hdmi_4k_rgb_yuv420_dc_max_600mhz);
+ KUNIT_ASSERT_NOT_NULL(test, priv);
+
+ KUNIT_ASSERT_EQ(test, priv->connector.hdmi.max_tmds_char_rate,
+ HDMI_1_0_TMDS_CHAR_RATE_MAX_HZ);
+
+ preferred = find_preferred_mode(&priv->connector);
+ KUNIT_ASSERT_NOT_NULL(test, preferred);
+ KUNIT_EXPECT_EQ(test, preferred->hdisplay, 1440);
+ KUNIT_EXPECT_EQ(test, preferred->vdisplay, 900);
+ KUNIT_EXPECT_EQ(test, preferred->clock, 88750);
+}
+
/*
* Test that drm_hdmi_connector_mode_valid() will accept modes that require a
* 4:2:0 chroma subsampling, even if said mode would violate maximum clock
@@ -2843,6 +2956,9 @@ static struct kunit_case drm_atomic_helper_connector_hdmi_mode_valid_tests[] = {
KUNIT_CASE(drm_test_check_mode_valid_reject),
KUNIT_CASE(drm_test_check_mode_valid_reject_rate),
KUNIT_CASE(drm_test_check_mode_valid_reject_max_clock),
+ KUNIT_CASE(drm_test_check_mode_valid_reject_inferred_max_tmds_char_rate),
+ KUNIT_CASE(drm_test_check_mode_valid_connector_max_tmds_char_rate_precedes_driver_hook),
+ KUNIT_CASE(drm_test_check_mode_valid_driver_hook_limits_connector_max_tmds_char_rate),
KUNIT_CASE(drm_test_check_mode_valid_yuv420_only_max_clock),
KUNIT_CASE(drm_test_check_mode_valid_reject_yuv420_only_connector),
KUNIT_CASE(drm_test_check_mode_valid_accept_yuv420_also_connector_rgb),
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 64/69] drm/tests: hdmi_state_helper: Add connector-provided max_tmds_char_rate coverage
@ 2026-07-31 16:20 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:20 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
Test the hdmi_clock_valid() logic that rejects modes whose TMDS
character rate exceeds connector->hdmi.max_tmds_char_rate.
Exercise both an explicit limit set through drm_connector_hdmi_funcs'
supported_tmds_char_rate and the limit inferred from supported_hdmi_ver.
Also verify that a driver hook can further restrict the connector limit.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 116 +++++++++++++++++++++
1 file changed, 116 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 f35dc31326bc..6d648332aa15 100644
--- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
+++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
@@ -190,6 +190,32 @@ static const struct drm_connector_hdmi_funcs reject_100mhz_connector_hdmi_funcs
},
};
+static enum drm_mode_status
+accept_any_connector_tmds_char_rate_valid(const struct drm_connector *connector,
+ const struct drm_display_mode *mode,
+ unsigned long long tmds_rate)
+{
+ return MODE_OK;
+}
+
+static const struct drm_connector_hdmi_funcs reject_over_165mhz_connector_hdmi_funcs = {
+ .vendor = "Vendor",
+ .product = "Product",
+ .supported_hdmi_ver = HDMI_VERSION_1_3,
+ .supported_tmds_char_rate = HDMI_1_0_TMDS_CHAR_RATE_MAX_HZ,
+ .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ .max_bpc = 8,
+ .tmds_char_rate_valid = accept_any_connector_tmds_char_rate_valid,
+ .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 =
@@ -2753,6 +2779,93 @@ static void drm_test_check_mode_valid_reject_max_clock(struct kunit *test)
KUNIT_EXPECT_EQ(test, preferred->clock, 25200);
}
+/*
+ * Test that the max_tmds_char_rate inferred from caps.supported_hdmi_ver
+ * is applied as a mode-filtering limit: with an HDMI 1.3 connector and no
+ * driver hook, drm_hdmi_connector_mode_valid() will reject modes whose TMDS
+ * character rate exceeds 340 MHz, even though the sink itself advertises
+ * a higher limit (600 MHz).
+ */
+static void
+drm_test_check_mode_valid_reject_inferred_max_tmds_char_rate(struct kunit *test)
+{
+ struct drm_connector_hdmi_funcs hdmi_funcs = dummy_connector_hdmi_funcs;
+ struct drm_atomic_helper_connector_hdmi_priv *priv;
+ struct drm_display_mode *preferred;
+
+ hdmi_funcs.supported_hdmi_ver = HDMI_VERSION_1_3;
+
+ priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, &hdmi_funcs,
+ test_edid_hdmi_4k_rgb_yuv420_dc_max_600mhz);
+ KUNIT_ASSERT_NOT_NULL(test, priv);
+
+ KUNIT_ASSERT_EQ(test, priv->connector.hdmi.max_tmds_char_rate,
+ HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ);
+
+ preferred = find_preferred_mode(&priv->connector);
+ KUNIT_ASSERT_NOT_NULL(test, preferred);
+ KUNIT_EXPECT_EQ(test, preferred->hdisplay, 2560);
+ KUNIT_EXPECT_EQ(test, preferred->vdisplay, 1600);
+ KUNIT_EXPECT_EQ(test, preferred->clock, 268500);
+}
+
+/*
+ * Test that a connector-provided max_tmds_char_rate limit (165 MHz) takes
+ * precedence over a permissive .tmds_char_rate_valid() driver hook and
+ * drm_hdmi_connector_mode_valid() will reject modes whose computed TMDS
+ * character exceeds the connector limit.
+ */
+static void
+drm_test_check_mode_valid_connector_max_tmds_char_rate_precedes_driver_hook(struct kunit *test)
+{
+ struct drm_atomic_helper_connector_hdmi_priv *priv;
+ struct drm_display_mode *preferred;
+
+ priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
+ &reject_over_165mhz_connector_hdmi_funcs,
+ test_edid_hdmi_4k_rgb_yuv420_dc_max_600mhz);
+ KUNIT_ASSERT_NOT_NULL(test, priv);
+
+ KUNIT_ASSERT_EQ(test, priv->connector.hdmi.max_tmds_char_rate,
+ HDMI_1_0_TMDS_CHAR_RATE_MAX_HZ);
+
+ preferred = find_preferred_mode(&priv->connector);
+ KUNIT_ASSERT_NOT_NULL(test, preferred);
+ KUNIT_EXPECT_EQ(test, preferred->hdisplay, 2048);
+ KUNIT_EXPECT_EQ(test, preferred->vdisplay, 1152);
+ KUNIT_EXPECT_EQ(test, preferred->clock, 162000);
+}
+
+/*
+ * Test that a connector-provided max_tmds_char_rate (165 MHz) can be further
+ * limited by a more restrictive (100 MHz) .tmds_char_rate_valid() driver hook
+ * and drm_hdmi_connector_mode_valid() will reject modes whose computed TMDS
+ * character exceeds the hook limit.
+ */
+static void
+drm_test_check_mode_valid_driver_hook_limits_connector_max_tmds_char_rate(struct kunit *test)
+{
+ struct drm_connector_hdmi_funcs hdmi_funcs = reject_100mhz_connector_hdmi_funcs;
+ struct drm_atomic_helper_connector_hdmi_priv *priv;
+ struct drm_display_mode *preferred;
+
+ hdmi_funcs.supported_hdmi_ver = HDMI_VERSION_1_3;
+ hdmi_funcs.supported_tmds_char_rate = HDMI_1_0_TMDS_CHAR_RATE_MAX_HZ;
+
+ priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, &hdmi_funcs,
+ test_edid_hdmi_4k_rgb_yuv420_dc_max_600mhz);
+ KUNIT_ASSERT_NOT_NULL(test, priv);
+
+ KUNIT_ASSERT_EQ(test, priv->connector.hdmi.max_tmds_char_rate,
+ HDMI_1_0_TMDS_CHAR_RATE_MAX_HZ);
+
+ preferred = find_preferred_mode(&priv->connector);
+ KUNIT_ASSERT_NOT_NULL(test, preferred);
+ KUNIT_EXPECT_EQ(test, preferred->hdisplay, 1440);
+ KUNIT_EXPECT_EQ(test, preferred->vdisplay, 900);
+ KUNIT_EXPECT_EQ(test, preferred->clock, 88750);
+}
+
/*
* Test that drm_hdmi_connector_mode_valid() will accept modes that require a
* 4:2:0 chroma subsampling, even if said mode would violate maximum clock
@@ -2843,6 +2956,9 @@ static struct kunit_case drm_atomic_helper_connector_hdmi_mode_valid_tests[] = {
KUNIT_CASE(drm_test_check_mode_valid_reject),
KUNIT_CASE(drm_test_check_mode_valid_reject_rate),
KUNIT_CASE(drm_test_check_mode_valid_reject_max_clock),
+ KUNIT_CASE(drm_test_check_mode_valid_reject_inferred_max_tmds_char_rate),
+ KUNIT_CASE(drm_test_check_mode_valid_connector_max_tmds_char_rate_precedes_driver_hook),
+ KUNIT_CASE(drm_test_check_mode_valid_driver_hook_limits_connector_max_tmds_char_rate),
KUNIT_CASE(drm_test_check_mode_valid_yuv420_only_max_clock),
KUNIT_CASE(drm_test_check_mode_valid_reject_yuv420_only_connector),
KUNIT_CASE(drm_test_check_mode_valid_accept_yuv420_also_connector_rgb),
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 65/69] drm/tests: hdmi_state_helper: Cover source-side scrambling decision
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:20 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:20 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
Add a couple of atomic-check cases that initialise an HDMI 2.0
connector, so the core infers the scrambler support and the 600 MHz TMDS
limit, and assert that conn_state->hdmi.scrambler_needed stays clear for
a 1080p@60 CEA mode (~148.5 MHz TMDS) and is set for the 4K@60 RGB
preferred mode (~594 MHz TMDS), straddling the 340 MHz threshold.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 151 +++++++++++++++++++++
1 file changed, 151 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 6d648332aa15..68b442c32a2a 100644
--- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
+++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
@@ -216,6 +216,34 @@ static const struct drm_connector_hdmi_funcs reject_over_165mhz_connector_hdmi_f
},
};
+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 = {
+ .vendor = "Vendor",
+ .product = "Product",
+ .supported_hdmi_ver = HDMI_VERSION_2_0,
+ .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ .max_bpc = 8,
+ .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 =
@@ -2254,6 +2282,127 @@ static void drm_test_check_disable_connector(struct kunit *test)
drm_modeset_acquire_fini(&ctx);
}
+/*
+ * Test that on an HDMI connector with source+sink scrambling support, driving
+ * a sub-340 MHz CEA mode, we end up with scrambler_needed cleared.
+ */
+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,
+ &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, drm_connector_hdmi_scrambler_supported(conn));
+ 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 on an HDMI connector with source+sink scrambling support, driving
+ * the 4K@60 RGB preferred mode (~594 MHz TMDS, above the 340 MHz threshold),
+ * we end up with scrambler_needed set.
+ */
+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,
+ &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, drm_connector_hdmi_scrambler_supported(conn));
+ 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);
+}
+
struct color_format_test_param {
enum drm_connector_color_format fmt;
enum drm_output_color_format expected;
@@ -2496,6 +2645,8 @@ 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_PARAM(drm_test_check_hdmi_color_format,
check_hdmi_color_format_gen_params),
KUNIT_CASE_PARAM(drm_test_check_hdmi_color_format_420_only,
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 65/69] drm/tests: hdmi_state_helper: Cover source-side scrambling decision
@ 2026-07-31 16:20 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:20 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip
Add a couple of atomic-check cases that initialise an HDMI 2.0
connector, so the core infers the scrambler support and the 600 MHz TMDS
limit, and assert that conn_state->hdmi.scrambler_needed stays clear for
a 1080p@60 CEA mode (~148.5 MHz TMDS) and is set for the 4K@60 RGB
preferred mode (~594 MHz TMDS), straddling the 340 MHz threshold.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 151 +++++++++++++++++++++
1 file changed, 151 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 6d648332aa15..68b442c32a2a 100644
--- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
+++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
@@ -216,6 +216,34 @@ static const struct drm_connector_hdmi_funcs reject_over_165mhz_connector_hdmi_f
},
};
+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 = {
+ .vendor = "Vendor",
+ .product = "Product",
+ .supported_hdmi_ver = HDMI_VERSION_2_0,
+ .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ .max_bpc = 8,
+ .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 =
@@ -2254,6 +2282,127 @@ static void drm_test_check_disable_connector(struct kunit *test)
drm_modeset_acquire_fini(&ctx);
}
+/*
+ * Test that on an HDMI connector with source+sink scrambling support, driving
+ * a sub-340 MHz CEA mode, we end up with scrambler_needed cleared.
+ */
+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,
+ &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, drm_connector_hdmi_scrambler_supported(conn));
+ 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 on an HDMI connector with source+sink scrambling support, driving
+ * the 4K@60 RGB preferred mode (~594 MHz TMDS, above the 340 MHz threshold),
+ * we end up with scrambler_needed set.
+ */
+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,
+ &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, drm_connector_hdmi_scrambler_supported(conn));
+ 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);
+}
+
struct color_format_test_param {
enum drm_connector_color_format fmt;
enum drm_output_color_format expected;
@@ -2496,6 +2645,8 @@ 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_PARAM(drm_test_check_hdmi_color_format,
check_hdmi_color_format_gen_params),
KUNIT_CASE_PARAM(drm_test_check_hdmi_color_format_420_only,
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 66/69] drm/connector: Remove drmm_connector_hdmi_ini2()
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:20 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:20 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Diederik de Haas
All callers have been converted to the new drmm_connector_hdmi_init()
signature. Remove the transitional drmm_connector_hdmi_ini2() function,
its declaration, its EXPORT_SYMBOL() and its kernel-doc.
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/drm_connector.c | 106 ----------------------------------------
include/drm/drm_connector.h | 9 ----
2 files changed, 115 deletions(-)
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index a18410faf040..b2e8d99c0e9a 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -696,112 +696,6 @@ int drmm_connector_hdmi_init(struct drm_device *dev,
}
EXPORT_SYMBOL(drmm_connector_hdmi_init);
-/**
- * drmm_connector_hdmi_ini2 - Init a preallocated HDMI connector
- * @dev: DRM device
- * @connector: A pointer to the HDMI connector to init
- * @vendor: HDMI Controller Vendor name
- * @product: HDMI Controller Product name
- * @funcs: callbacks for this connector
- * @hdmi_funcs: HDMI-related callbacks for this connector
- * @connector_type: user visible type of the connector
- * @ddc: optional pointer to the associated ddc adapter
- * @supported_formats: Bitmask of @drm_output_color_format listing supported output formats
- * @max_bpc: Maximum bits per char the HDMI connector supports
- *
- * Initialises a preallocated HDMI connector. Connectors can be
- * subclassed as part of driver connector objects.
- *
- * Cleanup is automatically handled with a call to
- * drm_connector_cleanup() in a DRM-managed action.
- *
- * The connector structure should be allocated with drmm_kzalloc().
- *
- * The @drm_connector_funcs.destroy hook must be NULL.
- *
- * Returns:
- * Zero on success, error code on failure.
- */
-int drmm_connector_hdmi_ini2(struct drm_device *dev,
- struct drm_connector *connector,
- const char *vendor, const char *product,
- const struct drm_connector_funcs *funcs,
- const struct drm_connector_hdmi_funcs *hdmi_funcs,
- int connector_type,
- struct i2c_adapter *ddc,
- unsigned long supported_formats,
- unsigned int max_bpc)
-{
- int ret;
-
- if (!vendor || !product)
- return -EINVAL;
-
- if ((strlen(vendor) > DRM_CONNECTOR_HDMI_VENDOR_LEN) ||
- (strlen(product) > DRM_CONNECTOR_HDMI_PRODUCT_LEN))
- return -EINVAL;
-
- if (!(connector_type == DRM_MODE_CONNECTOR_HDMIA ||
- connector_type == DRM_MODE_CONNECTOR_HDMIB))
- return -EINVAL;
-
- if (!supported_formats || !(supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444)))
- return -EINVAL;
-
- if (connector->ycbcr_420_allowed != !!(supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420)))
- return -EINVAL;
-
- if (!(max_bpc == 8 || max_bpc == 10 || max_bpc == 12))
- return -EINVAL;
-
- if (!hdmi_funcs->avi.clear_infoframe ||
- !hdmi_funcs->avi.write_infoframe ||
- !hdmi_funcs->hdmi.clear_infoframe ||
- !hdmi_funcs->hdmi.write_infoframe)
- return -EINVAL;
-
- ret = drmm_connector_init(dev, connector, funcs, connector_type, ddc);
- if (ret)
- return ret;
-
- connector->hdmi.supported_formats = supported_formats;
- strtomem_pad(connector->hdmi.vendor, vendor, 0);
- strtomem_pad(connector->hdmi.product, product, 0);
-
- /*
- * drm_connector_attach_max_bpc_property() requires the
- * connector to have a state.
- */
- if (connector->funcs->atomic_create_state) {
- struct drm_connector_state *state;
-
- state = connector->funcs->atomic_create_state(connector);
- if (IS_ERR(state))
- return PTR_ERR(state);
-
- connector->state = state;
- } else if (connector->funcs->reset) {
- connector->funcs->reset(connector);
- if (!connector->state)
- return -ENOMEM;
- }
-
- drm_connector_attach_max_bpc_property(connector, 8, max_bpc);
- connector->max_bpc = max_bpc;
-
- if (max_bpc > 8)
- drm_connector_attach_hdr_output_metadata_property(connector);
-
- ret = drm_connector_attach_color_format_property(connector, supported_formats);
- if (ret)
- return ret;
-
- connector->hdmi.funcs = hdmi_funcs;
-
- return 0;
-}
-EXPORT_SYMBOL(drmm_connector_hdmi_ini2);
-
/**
* drm_connector_attach_edid_property - attach edid property.
* @connector: the connector
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 89a140d6f064..2ad8d1611e84 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -2676,15 +2676,6 @@ int drmm_connector_hdmi_init(struct drm_device *dev,
const struct drm_connector_hdmi_funcs *hdmi_funcs,
int connector_type,
struct i2c_adapter *ddc);
-int drmm_connector_hdmi_ini2(struct drm_device *dev,
- struct drm_connector *connector,
- const char *vendor, const char *product,
- const struct drm_connector_funcs *funcs,
- const struct drm_connector_hdmi_funcs *hdmi_funcs,
- int connector_type,
- struct i2c_adapter *ddc,
- unsigned long supported_formats,
- unsigned int max_bpc);
void drm_connector_attach_edid_property(struct drm_connector *connector);
int drm_connector_register(struct drm_connector *connector);
int drm_connector_dynamic_register(struct drm_connector *connector);
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 66/69] drm/connector: Remove drmm_connector_hdmi_ini2()
@ 2026-07-31 16:20 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:20 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Diederik de Haas
All callers have been converted to the new drmm_connector_hdmi_init()
signature. Remove the transitional drmm_connector_hdmi_ini2() function,
its declaration, its EXPORT_SYMBOL() and its kernel-doc.
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/drm_connector.c | 106 ----------------------------------------
include/drm/drm_connector.h | 9 ----
2 files changed, 115 deletions(-)
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index a18410faf040..b2e8d99c0e9a 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -696,112 +696,6 @@ int drmm_connector_hdmi_init(struct drm_device *dev,
}
EXPORT_SYMBOL(drmm_connector_hdmi_init);
-/**
- * drmm_connector_hdmi_ini2 - Init a preallocated HDMI connector
- * @dev: DRM device
- * @connector: A pointer to the HDMI connector to init
- * @vendor: HDMI Controller Vendor name
- * @product: HDMI Controller Product name
- * @funcs: callbacks for this connector
- * @hdmi_funcs: HDMI-related callbacks for this connector
- * @connector_type: user visible type of the connector
- * @ddc: optional pointer to the associated ddc adapter
- * @supported_formats: Bitmask of @drm_output_color_format listing supported output formats
- * @max_bpc: Maximum bits per char the HDMI connector supports
- *
- * Initialises a preallocated HDMI connector. Connectors can be
- * subclassed as part of driver connector objects.
- *
- * Cleanup is automatically handled with a call to
- * drm_connector_cleanup() in a DRM-managed action.
- *
- * The connector structure should be allocated with drmm_kzalloc().
- *
- * The @drm_connector_funcs.destroy hook must be NULL.
- *
- * Returns:
- * Zero on success, error code on failure.
- */
-int drmm_connector_hdmi_ini2(struct drm_device *dev,
- struct drm_connector *connector,
- const char *vendor, const char *product,
- const struct drm_connector_funcs *funcs,
- const struct drm_connector_hdmi_funcs *hdmi_funcs,
- int connector_type,
- struct i2c_adapter *ddc,
- unsigned long supported_formats,
- unsigned int max_bpc)
-{
- int ret;
-
- if (!vendor || !product)
- return -EINVAL;
-
- if ((strlen(vendor) > DRM_CONNECTOR_HDMI_VENDOR_LEN) ||
- (strlen(product) > DRM_CONNECTOR_HDMI_PRODUCT_LEN))
- return -EINVAL;
-
- if (!(connector_type == DRM_MODE_CONNECTOR_HDMIA ||
- connector_type == DRM_MODE_CONNECTOR_HDMIB))
- return -EINVAL;
-
- if (!supported_formats || !(supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444)))
- return -EINVAL;
-
- if (connector->ycbcr_420_allowed != !!(supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420)))
- return -EINVAL;
-
- if (!(max_bpc == 8 || max_bpc == 10 || max_bpc == 12))
- return -EINVAL;
-
- if (!hdmi_funcs->avi.clear_infoframe ||
- !hdmi_funcs->avi.write_infoframe ||
- !hdmi_funcs->hdmi.clear_infoframe ||
- !hdmi_funcs->hdmi.write_infoframe)
- return -EINVAL;
-
- ret = drmm_connector_init(dev, connector, funcs, connector_type, ddc);
- if (ret)
- return ret;
-
- connector->hdmi.supported_formats = supported_formats;
- strtomem_pad(connector->hdmi.vendor, vendor, 0);
- strtomem_pad(connector->hdmi.product, product, 0);
-
- /*
- * drm_connector_attach_max_bpc_property() requires the
- * connector to have a state.
- */
- if (connector->funcs->atomic_create_state) {
- struct drm_connector_state *state;
-
- state = connector->funcs->atomic_create_state(connector);
- if (IS_ERR(state))
- return PTR_ERR(state);
-
- connector->state = state;
- } else if (connector->funcs->reset) {
- connector->funcs->reset(connector);
- if (!connector->state)
- return -ENOMEM;
- }
-
- drm_connector_attach_max_bpc_property(connector, 8, max_bpc);
- connector->max_bpc = max_bpc;
-
- if (max_bpc > 8)
- drm_connector_attach_hdr_output_metadata_property(connector);
-
- ret = drm_connector_attach_color_format_property(connector, supported_formats);
- if (ret)
- return ret;
-
- connector->hdmi.funcs = hdmi_funcs;
-
- return 0;
-}
-EXPORT_SYMBOL(drmm_connector_hdmi_ini2);
-
/**
* drm_connector_attach_edid_property - attach edid property.
* @connector: the connector
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 89a140d6f064..2ad8d1611e84 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -2676,15 +2676,6 @@ int drmm_connector_hdmi_init(struct drm_device *dev,
const struct drm_connector_hdmi_funcs *hdmi_funcs,
int connector_type,
struct i2c_adapter *ddc);
-int drmm_connector_hdmi_ini2(struct drm_device *dev,
- struct drm_connector *connector,
- const char *vendor, const char *product,
- const struct drm_connector_funcs *funcs,
- const struct drm_connector_hdmi_funcs *hdmi_funcs,
- int connector_type,
- struct i2c_adapter *ddc,
- unsigned long supported_formats,
- unsigned int max_bpc);
void drm_connector_attach_edid_property(struct drm_connector *connector);
int drm_connector_register(struct drm_connector *connector);
int drm_connector_dynamic_register(struct drm_connector *connector);
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 67/69] drm/connector: Drop redundant hdmi vendor/product fields
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:20 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:20 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Diederik de Haas
Now that all users migrated to the new drmm_connector_hdmi_init()
signature, vendor and product are provided through struct
drm_connector_hdmi_funcs, a reference to which is already stored in
drm_connector_hdmi.
Drop the redundant fields from drm_connector_hdmi and point its users to
hdmi.funcs->vendor and hdmi.funcs->product instead.
This allows simplifying the related connector registration tests by
getting rid of the now unnecessary KUNIT_EXPECT_MEMEQ() checks.
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_hdmi_state_helper.c | 4 +--
drivers/gpu/drm/drm_connector.c | 4 ---
drivers/gpu/drm/tests/drm_connector_test.c | 41 +++----------------------
include/drm/drm_connector.h | 14 ++-------
4 files changed, 8 insertions(+), 55 deletions(-)
diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
index 04c9e06b9dc1..83a8fcb41343 100644
--- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
@@ -784,8 +784,8 @@ static int hdmi_generate_spd_infoframe(const struct drm_connector *connector,
return 0;
ret = hdmi_spd_infoframe_init(frame,
- connector->hdmi.vendor,
- connector->hdmi.product);
+ connector->hdmi.funcs->vendor,
+ connector->hdmi.funcs->product);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index b2e8d99c0e9a..f5f38dc4bfa6 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -656,10 +656,6 @@ int drmm_connector_hdmi_init(struct drm_device *dev,
connector->hdmi.max_tmds_char_rate = hdmi_funcs->supported_tmds_char_rate;
}
- /* TODO: remove after conversion to new drmm_connector_hdmi_init() */
- strtomem_pad(connector->hdmi.vendor, hdmi_funcs->vendor, 0);
- strtomem_pad(connector->hdmi.product, hdmi_funcs->product, 0);
-
/*
* drm_connector_attach_max_bpc_property() requires the
* connector to have a state.
diff --git a/drivers/gpu/drm/tests/drm_connector_test.c b/drivers/gpu/drm/tests/drm_connector_test.c
index 3d8500ad8be9..42f804500de6 100644
--- a/drivers/gpu/drm/tests/drm_connector_test.c
+++ b/drivers/gpu/drm/tests/drm_connector_test.c
@@ -771,14 +771,11 @@ static void drm_test_connector_hdmi_init_null_product(struct kunit *test)
/*
* Test that the registration of a connector with a valid, shorter than
- * the max length, product name succeeds, and is stored padded with 0.
+ * the max length, product name succeeds.
*/
static void drm_test_connector_hdmi_init_product_valid(struct kunit *test)
{
struct drm_connector_init_priv *priv = test->priv;
- const unsigned char expected_product[DRM_CONNECTOR_HDMI_PRODUCT_LEN] = {
- 'P', 'r', 'o', 'd',
- };
int ret;
priv->hdmi_funcs = dummy_hdmi_funcs;
@@ -793,25 +790,15 @@ static void drm_test_connector_hdmi_init_product_valid(struct kunit *test)
DRM_MODE_CONNECTOR_HDMIA,
&priv->ddc);
KUNIT_EXPECT_EQ(test, ret, 0);
- KUNIT_EXPECT_MEMEQ(test,
- priv->connector.hdmi.product,
- expected_product,
- sizeof(priv->connector.hdmi.product));
}
/*
* Test that the registration of a connector with a valid, at max
- * length, product name succeeds, and is stored padded without any
- * trailing \0.
+ * length, product name succeeds.
*/
static void drm_test_connector_hdmi_init_product_length_exact(struct kunit *test)
{
struct drm_connector_init_priv *priv = test->priv;
- const unsigned char expected_product[DRM_CONNECTOR_HDMI_PRODUCT_LEN] = {
- 'P', 'r', 'o', 'd', 'u', 'c', 't',
- 'P', 'r', 'o', 'd', 'u', 'c', 't',
- 'P', 'r',
- };
int ret;
priv->hdmi_funcs = dummy_hdmi_funcs;
@@ -826,10 +813,6 @@ static void drm_test_connector_hdmi_init_product_length_exact(struct kunit *test
DRM_MODE_CONNECTOR_HDMIA,
&priv->ddc);
KUNIT_EXPECT_EQ(test, ret, 0);
- KUNIT_EXPECT_MEMEQ(test,
- priv->connector.hdmi.product,
- expected_product,
- sizeof(priv->connector.hdmi.product));
}
/*
@@ -857,14 +840,11 @@ static void drm_test_connector_hdmi_init_product_length_too_long(struct kunit *t
/*
* Test that the registration of a connector with a vendor name smaller
- * than the maximum length succeeds, and is stored padded with zeros.
+ * than the maximum length succeeds.
*/
static void drm_test_connector_hdmi_init_vendor_valid(struct kunit *test)
{
struct drm_connector_init_priv *priv = test->priv;
- const char expected_vendor[DRM_CONNECTOR_HDMI_VENDOR_LEN] = {
- 'V', 'e', 'n', 'd',
- };
int ret;
priv->hdmi_funcs = dummy_hdmi_funcs;
@@ -879,24 +859,15 @@ static void drm_test_connector_hdmi_init_vendor_valid(struct kunit *test)
DRM_MODE_CONNECTOR_HDMIA,
&priv->ddc);
KUNIT_EXPECT_EQ(test, ret, 0);
- KUNIT_EXPECT_MEMEQ(test,
- priv->connector.hdmi.vendor,
- expected_vendor,
- sizeof(priv->connector.hdmi.vendor));
}
/*
* Test that the registration of a connector with a vendor name at the
- * maximum length succeeds, and is stored padded without the trailing
- * zero.
+ * maximum length succeeds.
*/
static void drm_test_connector_hdmi_init_vendor_length_exact(struct kunit *test)
{
struct drm_connector_init_priv *priv = test->priv;
- const char expected_vendor[DRM_CONNECTOR_HDMI_VENDOR_LEN] = {
- 'V', 'e', 'n', 'd', 'o', 'r',
- 'V', 'e',
- };
int ret;
priv->hdmi_funcs = dummy_hdmi_funcs;
@@ -911,10 +882,6 @@ static void drm_test_connector_hdmi_init_vendor_length_exact(struct kunit *test)
DRM_MODE_CONNECTOR_HDMIA,
&priv->ddc);
KUNIT_EXPECT_EQ(test, ret, 0);
- KUNIT_EXPECT_MEMEQ(test,
- priv->connector.hdmi.vendor,
- expected_vendor,
- sizeof(priv->connector.hdmi.vendor));
}
/*
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 2ad8d1611e84..f7627de624de 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -1418,11 +1418,13 @@ struct drm_connector_infoframe_funcs {
* and controller capabilities
*/
struct drm_connector_hdmi_funcs {
+#define DRM_CONNECTOR_HDMI_VENDOR_LEN 8
/**
* @vendor: HDMI Controller Vendor name.
*/
const char *vendor;
+#define DRM_CONNECTOR_HDMI_PRODUCT_LEN 16
/**
* @product: HDMI Controller Product name
*/
@@ -2123,18 +2125,6 @@ struct drm_connector_hdmi_audio {
* struct drm_connector_hdmi - DRM Connector HDMI-related structure
*/
struct drm_connector_hdmi {
-#define DRM_CONNECTOR_HDMI_VENDOR_LEN 8
- /**
- * @vendor: HDMI Controller Vendor Name
- */
- unsigned char vendor[DRM_CONNECTOR_HDMI_VENDOR_LEN] __nonstring;
-
-#define DRM_CONNECTOR_HDMI_PRODUCT_LEN 16
- /**
- * @product: HDMI Controller Product Name
- */
- unsigned char product[DRM_CONNECTOR_HDMI_PRODUCT_LEN] __nonstring;
-
/**
* @supported_formats: Bitmask of @drm_output_color_format
* supported by the controller.
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 67/69] drm/connector: Drop redundant hdmi vendor/product fields
@ 2026-07-31 16:20 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:20 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Diederik de Haas
Now that all users migrated to the new drmm_connector_hdmi_init()
signature, vendor and product are provided through struct
drm_connector_hdmi_funcs, a reference to which is already stored in
drm_connector_hdmi.
Drop the redundant fields from drm_connector_hdmi and point its users to
hdmi.funcs->vendor and hdmi.funcs->product instead.
This allows simplifying the related connector registration tests by
getting rid of the now unnecessary KUNIT_EXPECT_MEMEQ() checks.
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_hdmi_state_helper.c | 4 +--
drivers/gpu/drm/drm_connector.c | 4 ---
drivers/gpu/drm/tests/drm_connector_test.c | 41 +++----------------------
include/drm/drm_connector.h | 14 ++-------
4 files changed, 8 insertions(+), 55 deletions(-)
diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
index 04c9e06b9dc1..83a8fcb41343 100644
--- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
@@ -784,8 +784,8 @@ static int hdmi_generate_spd_infoframe(const struct drm_connector *connector,
return 0;
ret = hdmi_spd_infoframe_init(frame,
- connector->hdmi.vendor,
- connector->hdmi.product);
+ connector->hdmi.funcs->vendor,
+ connector->hdmi.funcs->product);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index b2e8d99c0e9a..f5f38dc4bfa6 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -656,10 +656,6 @@ int drmm_connector_hdmi_init(struct drm_device *dev,
connector->hdmi.max_tmds_char_rate = hdmi_funcs->supported_tmds_char_rate;
}
- /* TODO: remove after conversion to new drmm_connector_hdmi_init() */
- strtomem_pad(connector->hdmi.vendor, hdmi_funcs->vendor, 0);
- strtomem_pad(connector->hdmi.product, hdmi_funcs->product, 0);
-
/*
* drm_connector_attach_max_bpc_property() requires the
* connector to have a state.
diff --git a/drivers/gpu/drm/tests/drm_connector_test.c b/drivers/gpu/drm/tests/drm_connector_test.c
index 3d8500ad8be9..42f804500de6 100644
--- a/drivers/gpu/drm/tests/drm_connector_test.c
+++ b/drivers/gpu/drm/tests/drm_connector_test.c
@@ -771,14 +771,11 @@ static void drm_test_connector_hdmi_init_null_product(struct kunit *test)
/*
* Test that the registration of a connector with a valid, shorter than
- * the max length, product name succeeds, and is stored padded with 0.
+ * the max length, product name succeeds.
*/
static void drm_test_connector_hdmi_init_product_valid(struct kunit *test)
{
struct drm_connector_init_priv *priv = test->priv;
- const unsigned char expected_product[DRM_CONNECTOR_HDMI_PRODUCT_LEN] = {
- 'P', 'r', 'o', 'd',
- };
int ret;
priv->hdmi_funcs = dummy_hdmi_funcs;
@@ -793,25 +790,15 @@ static void drm_test_connector_hdmi_init_product_valid(struct kunit *test)
DRM_MODE_CONNECTOR_HDMIA,
&priv->ddc);
KUNIT_EXPECT_EQ(test, ret, 0);
- KUNIT_EXPECT_MEMEQ(test,
- priv->connector.hdmi.product,
- expected_product,
- sizeof(priv->connector.hdmi.product));
}
/*
* Test that the registration of a connector with a valid, at max
- * length, product name succeeds, and is stored padded without any
- * trailing \0.
+ * length, product name succeeds.
*/
static void drm_test_connector_hdmi_init_product_length_exact(struct kunit *test)
{
struct drm_connector_init_priv *priv = test->priv;
- const unsigned char expected_product[DRM_CONNECTOR_HDMI_PRODUCT_LEN] = {
- 'P', 'r', 'o', 'd', 'u', 'c', 't',
- 'P', 'r', 'o', 'd', 'u', 'c', 't',
- 'P', 'r',
- };
int ret;
priv->hdmi_funcs = dummy_hdmi_funcs;
@@ -826,10 +813,6 @@ static void drm_test_connector_hdmi_init_product_length_exact(struct kunit *test
DRM_MODE_CONNECTOR_HDMIA,
&priv->ddc);
KUNIT_EXPECT_EQ(test, ret, 0);
- KUNIT_EXPECT_MEMEQ(test,
- priv->connector.hdmi.product,
- expected_product,
- sizeof(priv->connector.hdmi.product));
}
/*
@@ -857,14 +840,11 @@ static void drm_test_connector_hdmi_init_product_length_too_long(struct kunit *t
/*
* Test that the registration of a connector with a vendor name smaller
- * than the maximum length succeeds, and is stored padded with zeros.
+ * than the maximum length succeeds.
*/
static void drm_test_connector_hdmi_init_vendor_valid(struct kunit *test)
{
struct drm_connector_init_priv *priv = test->priv;
- const char expected_vendor[DRM_CONNECTOR_HDMI_VENDOR_LEN] = {
- 'V', 'e', 'n', 'd',
- };
int ret;
priv->hdmi_funcs = dummy_hdmi_funcs;
@@ -879,24 +859,15 @@ static void drm_test_connector_hdmi_init_vendor_valid(struct kunit *test)
DRM_MODE_CONNECTOR_HDMIA,
&priv->ddc);
KUNIT_EXPECT_EQ(test, ret, 0);
- KUNIT_EXPECT_MEMEQ(test,
- priv->connector.hdmi.vendor,
- expected_vendor,
- sizeof(priv->connector.hdmi.vendor));
}
/*
* Test that the registration of a connector with a vendor name at the
- * maximum length succeeds, and is stored padded without the trailing
- * zero.
+ * maximum length succeeds.
*/
static void drm_test_connector_hdmi_init_vendor_length_exact(struct kunit *test)
{
struct drm_connector_init_priv *priv = test->priv;
- const char expected_vendor[DRM_CONNECTOR_HDMI_VENDOR_LEN] = {
- 'V', 'e', 'n', 'd', 'o', 'r',
- 'V', 'e',
- };
int ret;
priv->hdmi_funcs = dummy_hdmi_funcs;
@@ -911,10 +882,6 @@ static void drm_test_connector_hdmi_init_vendor_length_exact(struct kunit *test)
DRM_MODE_CONNECTOR_HDMIA,
&priv->ddc);
KUNIT_EXPECT_EQ(test, ret, 0);
- KUNIT_EXPECT_MEMEQ(test,
- priv->connector.hdmi.vendor,
- expected_vendor,
- sizeof(priv->connector.hdmi.vendor));
}
/*
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 2ad8d1611e84..f7627de624de 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -1418,11 +1418,13 @@ struct drm_connector_infoframe_funcs {
* and controller capabilities
*/
struct drm_connector_hdmi_funcs {
+#define DRM_CONNECTOR_HDMI_VENDOR_LEN 8
/**
* @vendor: HDMI Controller Vendor name.
*/
const char *vendor;
+#define DRM_CONNECTOR_HDMI_PRODUCT_LEN 16
/**
* @product: HDMI Controller Product name
*/
@@ -2123,18 +2125,6 @@ struct drm_connector_hdmi_audio {
* struct drm_connector_hdmi - DRM Connector HDMI-related structure
*/
struct drm_connector_hdmi {
-#define DRM_CONNECTOR_HDMI_VENDOR_LEN 8
- /**
- * @vendor: HDMI Controller Vendor Name
- */
- unsigned char vendor[DRM_CONNECTOR_HDMI_VENDOR_LEN] __nonstring;
-
-#define DRM_CONNECTOR_HDMI_PRODUCT_LEN 16
- /**
- * @product: HDMI Controller Product Name
- */
- unsigned char product[DRM_CONNECTOR_HDMI_PRODUCT_LEN] __nonstring;
-
/**
* @supported_formats: Bitmask of @drm_output_color_format
* supported by the controller.
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 68/69] drm/connector: Drop redundant hdmi supported_formats field
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:20 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:20 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Diederik de Haas
Now that all users migrated to the new drmm_connector_hdmi_init()
signature, supported_formats is provided through struct
drm_connector_hdmi_funcs, a reference to which is already stored in
drm_connector_hdmi.
Drop the redundant field from drm_connector_hdmi and point its users to
hdmi.funcs->supported_formats instead.
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_hdmi_state_helper.c | 3 ++-
drivers/gpu/drm/drm_connector.c | 3 ---
include/drm/drm_connector.h | 6 ------
3 files changed, 2 insertions(+), 10 deletions(-)
diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
index 83a8fcb41343..c5496641a2f3 100644
--- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
@@ -426,7 +426,8 @@ sink_supports_format_bpc(const struct drm_connector *connector,
return false;
}
- if (!(connector->hdmi.supported_formats & BIT(format))) {
+ if (!connector->hdmi.funcs ||
+ !(connector->hdmi.funcs->supported_formats & BIT(format))) {
drm_dbg_kms(dev, "%s format unsupported by the connector.\n",
drm_hdmi_connector_get_output_format_name(format));
return false;
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index f5f38dc4bfa6..293b2823475d 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -610,9 +610,6 @@ int drmm_connector_hdmi_init(struct drm_device *dev,
if (ret)
return ret;
- /* TODO: remove after conversion to new drmm_connector_hdmi_init() */
- connector->hdmi.supported_formats = hdmi_funcs->supported_formats;
-
/*
* The supported HDMI version can be used to determinate the maximum
* TMDS character rate allowed by the specification. Some controllers,
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index f7627de624de..75bd9ac03571 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -2125,12 +2125,6 @@ struct drm_connector_hdmi_audio {
* struct drm_connector_hdmi - DRM Connector HDMI-related structure
*/
struct drm_connector_hdmi {
- /**
- * @supported_formats: Bitmask of @drm_output_color_format
- * supported by the controller.
- */
- unsigned long supported_formats;
-
/**
* @max_tmds_char_rate: Maximum TMDS character rate, in Hz,
* supported by the controller.
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 68/69] drm/connector: Drop redundant hdmi supported_formats field
@ 2026-07-31 16:20 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:20 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Diederik de Haas
Now that all users migrated to the new drmm_connector_hdmi_init()
signature, supported_formats is provided through struct
drm_connector_hdmi_funcs, a reference to which is already stored in
drm_connector_hdmi.
Drop the redundant field from drm_connector_hdmi and point its users to
hdmi.funcs->supported_formats instead.
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_hdmi_state_helper.c | 3 ++-
drivers/gpu/drm/drm_connector.c | 3 ---
include/drm/drm_connector.h | 6 ------
3 files changed, 2 insertions(+), 10 deletions(-)
diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
index 83a8fcb41343..c5496641a2f3 100644
--- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
@@ -426,7 +426,8 @@ sink_supports_format_bpc(const struct drm_connector *connector,
return false;
}
- if (!(connector->hdmi.supported_formats & BIT(format))) {
+ if (!connector->hdmi.funcs ||
+ !(connector->hdmi.funcs->supported_formats & BIT(format))) {
drm_dbg_kms(dev, "%s format unsupported by the connector.\n",
drm_hdmi_connector_get_output_format_name(format));
return false;
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index f5f38dc4bfa6..293b2823475d 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -610,9 +610,6 @@ int drmm_connector_hdmi_init(struct drm_device *dev,
if (ret)
return ret;
- /* TODO: remove after conversion to new drmm_connector_hdmi_init() */
- connector->hdmi.supported_formats = hdmi_funcs->supported_formats;
-
/*
* The supported HDMI version can be used to determinate the maximum
* TMDS character rate allowed by the specification. Some controllers,
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index f7627de624de..75bd9ac03571 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -2125,12 +2125,6 @@ struct drm_connector_hdmi_audio {
* struct drm_connector_hdmi - DRM Connector HDMI-related structure
*/
struct drm_connector_hdmi {
- /**
- * @supported_formats: Bitmask of @drm_output_color_format
- * supported by the controller.
- */
- unsigned long supported_formats;
-
/**
* @max_tmds_char_rate: Maximum TMDS character rate, in Hz,
* supported by the controller.
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread
* [PATCH v10 69/69] drm/connector: Drop redundant max_bpc field
2026-07-31 16:19 ` Cristian Ciocaltea
@ 2026-07-31 16:20 ` Cristian Ciocaltea
-1 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:20 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Diederik de Haas
Now that all users migrated to the new drmm_connector_hdmi_init()
signature, max_bpc is provided through struct drm_connector_hdmi_funcs,
a reference to which is already stored in drm_connector_hdmi.
Drop the redundant connector->max_bpc field and point its users to
hdmi.funcs->max_bpc instead.
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_hdmi_state_helper.c | 6 +++---
drivers/gpu/drm/drm_connector.c | 2 --
include/drm/drm_connector.h | 5 -----
3 files changed, 3 insertions(+), 10 deletions(-)
diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
index c5496641a2f3..53057ef80e45 100644
--- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
@@ -319,7 +319,7 @@
void __drm_atomic_helper_connector_hdmi_state_init(struct drm_connector *connector,
struct drm_connector_state *new_conn_state)
{
- unsigned int max_bpc = connector->max_bpc;
+ unsigned int max_bpc = connector->hdmi.funcs ? connector->hdmi.funcs->max_bpc : 0;
new_conn_state->max_bpc = max_bpc;
new_conn_state->max_requested_bpc = max_bpc;
@@ -678,7 +678,7 @@ hdmi_compute_config(const struct drm_connector *connector,
{
unsigned int max_bpc = clamp_t(unsigned int,
conn_state->max_bpc,
- 8, connector->max_bpc);
+ 8, connector->hdmi.funcs->max_bpc);
enum drm_output_color_format fmt;
int ret;
@@ -811,7 +811,7 @@ static int hdmi_generate_hdr_infoframe(const struct drm_connector *connector,
if (!connector->hdmi.funcs->hdr_drm.write_infoframe)
return 0;
- if (connector->max_bpc < 10)
+ if (connector->hdmi.funcs->max_bpc < 10)
return 0;
if (!conn_state->hdr_output_metadata)
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 293b2823475d..38d9f977338c 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -672,8 +672,6 @@ int drmm_connector_hdmi_init(struct drm_device *dev,
}
drm_connector_attach_max_bpc_property(connector, 8, hdmi_funcs->max_bpc);
- /* TODO: remove after conversion to new drmm_connector_hdmi_init() */
- connector->max_bpc = hdmi_funcs->max_bpc;
if (hdmi_funcs->max_bpc > 8)
drm_connector_attach_hdr_output_metadata_property(connector);
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 75bd9ac03571..5e0d65adb244 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -2391,11 +2391,6 @@ struct drm_connector {
*/
struct drm_property_blob *path_blob_ptr;
- /**
- * @max_bpc: Maximum bits per color channel the connector supports.
- */
- unsigned int max_bpc;
-
/**
* @max_bpc_property: Default connector property for the max bpc to be
* driven out of the connector.
--
2.55.0
^ permalink raw reply related [flat|nested] 155+ messages in thread* [PATCH v10 69/69] drm/connector: Drop redundant max_bpc field
@ 2026-07-31 16:20 ` Cristian Ciocaltea
0 siblings, 0 replies; 155+ messages in thread
From: Cristian Ciocaltea @ 2026-07-31 16:20 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Sandy Huang, Heiko Stübner,
Andy Yan, Algea Cao, Daniel Stone, Liu Ying, Phong LE
Cc: kernel, linux-kernel, dri-devel, linux-arm-kernel, linux-sunxi,
linux-rockchip, Diederik de Haas
Now that all users migrated to the new drmm_connector_hdmi_init()
signature, max_bpc is provided through struct drm_connector_hdmi_funcs,
a reference to which is already stored in drm_connector_hdmi.
Drop the redundant connector->max_bpc field and point its users to
hdmi.funcs->max_bpc instead.
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_hdmi_state_helper.c | 6 +++---
drivers/gpu/drm/drm_connector.c | 2 --
include/drm/drm_connector.h | 5 -----
3 files changed, 3 insertions(+), 10 deletions(-)
diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
index c5496641a2f3..53057ef80e45 100644
--- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
@@ -319,7 +319,7 @@
void __drm_atomic_helper_connector_hdmi_state_init(struct drm_connector *connector,
struct drm_connector_state *new_conn_state)
{
- unsigned int max_bpc = connector->max_bpc;
+ unsigned int max_bpc = connector->hdmi.funcs ? connector->hdmi.funcs->max_bpc : 0;
new_conn_state->max_bpc = max_bpc;
new_conn_state->max_requested_bpc = max_bpc;
@@ -678,7 +678,7 @@ hdmi_compute_config(const struct drm_connector *connector,
{
unsigned int max_bpc = clamp_t(unsigned int,
conn_state->max_bpc,
- 8, connector->max_bpc);
+ 8, connector->hdmi.funcs->max_bpc);
enum drm_output_color_format fmt;
int ret;
@@ -811,7 +811,7 @@ static int hdmi_generate_hdr_infoframe(const struct drm_connector *connector,
if (!connector->hdmi.funcs->hdr_drm.write_infoframe)
return 0;
- if (connector->max_bpc < 10)
+ if (connector->hdmi.funcs->max_bpc < 10)
return 0;
if (!conn_state->hdr_output_metadata)
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 293b2823475d..38d9f977338c 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -672,8 +672,6 @@ int drmm_connector_hdmi_init(struct drm_device *dev,
}
drm_connector_attach_max_bpc_property(connector, 8, hdmi_funcs->max_bpc);
- /* TODO: remove after conversion to new drmm_connector_hdmi_init() */
- connector->max_bpc = hdmi_funcs->max_bpc;
if (hdmi_funcs->max_bpc > 8)
drm_connector_attach_hdr_output_metadata_property(connector);
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 75bd9ac03571..5e0d65adb244 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -2391,11 +2391,6 @@ struct drm_connector {
*/
struct drm_property_blob *path_blob_ptr;
- /**
- * @max_bpc: Maximum bits per color channel the connector supports.
- */
- unsigned int max_bpc;
-
/**
* @max_bpc_property: Default connector property for the max bpc to be
* driven out of the connector.
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 155+ messages in thread