* [PATCH RFC 00/12] Add support for DisplayPort link training information report
@ 2026-04-09 17:08 Kory Maincent
2026-04-09 17:08 ` [PATCH RFC 01/12] drm/i915/display/intel_sdvo: Fix double connector destroy in error paths Kory Maincent
` (11 more replies)
0 siblings, 12 replies; 13+ messages in thread
From: Kory Maincent @ 2026-04-09 17:08 UTC (permalink / raw)
To: Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
David Airlie, Simona Vetter, Dave Airlie, Jesse Barnes,
Eric Anholt, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Chun-Kuang Hu, Philipp Zabel,
Matthias Brugger, AngeloGioacchino Del Regno, Chris Wilson
Cc: Thomas Petazzoni, Mark Yacoub, Sean Paul, Louis Chauvet,
intel-gfx, intel-xe, dri-devel, linux-kernel, linux-mediatek,
linux-arm-kernel, Simona Vetter, Kory Maincent
DisplayPort link training negotiates the physical-layer parameters needed
for a reliable connection: lane count, link rate, voltage swing,
pre-emphasis, and optionally Display Stream Compression (DSC). Currently,
each driver exposes this state in its own way, often through
driver-specific debugfs entries, with no standard interface for userspace
diagnostic and monitoring tools.
This series introduces a generic, DRM-managed framework for exposing DP
link training state as standard connector properties, modeled after the
existing HDMI helper drmm_connector_hdmi_init().
The new drmm_connector_dp_init() helper initializes a DP connector and
registers the following connector properties to expose the negotiated link
state to userspace:
- num_lanes: negotiated lane count (1, 2 or 4)
- link_rate: negotiated link rate
- dsc_en: whether Display Stream Compression is active
- voltage_swingN: per-lane voltage swing level (lanes 0-3)
- pre_emphasisN: per-lane pre-emphasis level (lanes 0-3)
Two runtime helpers update and clear these properties when link training
completes or the link goes down:
- drm_connector_dp_set_link_train_properties()
- drm_connector_dp_reset_link_train_properties()
Two drivers are updated as reference implementations: i915 (direct
connector path) and MediaTek (via the bridge connector framework using a
new DRM_BRIDGE_OP_DP flag). The i915 patches are preceded by a series of
conversions to DRM managed resources, which are required before adopting
drmm_connector_dp_init().
The MST case in i915 driver is not supported yet.
Patches 1-3: Fix two error-path cleanup bugs in i915 sdvo and lvds
[Will probably be sent standalone]
Patches 4-8: Convert i915 display resources to DRM managed lifetime
Patch 9: Introduce the core drmm_connector_dp_init() framework
Patch 10: Wire the i915 DP connector to use the new helpers
Patch 11: Introduce DRM_BRIDGE_OP_DP and wire bridge connectors
Patch 12: Wire the MediaTek DP bridge to the new helpers [untested]
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
Kory Maincent (12):
drm/i915/display/intel_sdvo: Fix double connector destroy in error paths
drm/i915/display/intel_lvds: Drop redundant manual cleanup on init failure
drm/i915/display/intel_dp: Drop redundant intel_dp_aux_fini() on init failure
drm/i915/display: Switch to drmm_mode_config_init() and drop manual cleanup
drm/i915/display: Switch to managed for crtc
drm/i915/display: Switch to managed for plane
drm/i915/display: Switch to managed for encoder
drm/i915/display: Switch to managed for connector
drm: Introduce drmm_connector_dp_init() with link training state properties
drm/i915/display/dp: Adopt dp_connector helpers to expose link training state
drm/bridge: Wire drmm_connector_dp_init() via new DRM_BRIDGE_OP_DP flag
drm/mediatek: Use dp_connector helpers to report link training state
drivers/gpu/drm/Makefile | 1 +
drivers/gpu/drm/display/drm_bridge_connector.c | 26 +-
drivers/gpu/drm/drm_dp_connector.c | 344 +++++++++++++++++++++
drivers/gpu/drm/i915/display/g4x_dp.c | 39 +--
drivers/gpu/drm/i915/display/g4x_hdmi.c | 27 +-
drivers/gpu/drm/i915/display/i9xx_plane.c | 97 +++---
drivers/gpu/drm/i915/display/icl_dsi.c | 50 ++-
drivers/gpu/drm/i915/display/intel_connector.c | 26 +-
drivers/gpu/drm/i915/display/intel_connector.h | 5 +-
drivers/gpu/drm/i915/display/intel_crt.c | 28 +-
drivers/gpu/drm/i915/display/intel_crtc.c | 102 +++---
drivers/gpu/drm/i915/display/intel_cursor.c | 41 ++-
drivers/gpu/drm/i915/display/intel_ddi.c | 64 ++--
drivers/gpu/drm/i915/display/intel_display.c | 8 -
drivers/gpu/drm/i915/display/intel_display.h | 1 -
.../gpu/drm/i915/display/intel_display_driver.c | 37 ++-
drivers/gpu/drm/i915/display/intel_dp.c | 43 ++-
.../gpu/drm/i915/display/intel_dp_link_training.c | 25 ++
drivers/gpu/drm/i915/display/intel_dp_mst.c | 33 +-
drivers/gpu/drm/i915/display/intel_dvo.c | 43 +--
drivers/gpu/drm/i915/display/intel_encoder.c | 6 +-
drivers/gpu/drm/i915/display/intel_encoder.h | 3 +-
drivers/gpu/drm/i915/display/intel_hdmi.c | 15 +-
drivers/gpu/drm/i915/display/intel_lvds.c | 45 ++-
drivers/gpu/drm/i915/display/intel_plane.c | 45 +--
drivers/gpu/drm/i915/display/intel_plane.h | 5 +-
drivers/gpu/drm/i915/display/intel_sdvo.c | 134 +++-----
drivers/gpu/drm/i915/display/intel_sprite.c | 119 ++++---
drivers/gpu/drm/i915/display/intel_tv.c | 26 +-
drivers/gpu/drm/i915/display/skl_universal_plane.c | 102 +++---
drivers/gpu/drm/i915/display/vlv_dsi.c | 42 +--
drivers/gpu/drm/mediatek/mtk_dp.c | 34 +-
include/drm/drm_bridge.h | 13 +
include/drm/drm_connector.h | 38 +++
include/drm/drm_dp_connector.h | 109 +++++++
35 files changed, 1125 insertions(+), 651 deletions(-)
---
base-commit: db5a75cfd29766536be62aece9f19c6e7a858fa6
change-id: 20260226-feat_link_cap-20cbb6f31d40
Best regards,
--
Köry Maincent, Bootlin
Embedded Linux and kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH RFC 01/12] drm/i915/display/intel_sdvo: Fix double connector destroy in error paths
2026-04-09 17:08 [PATCH RFC 00/12] Add support for DisplayPort link training information report Kory Maincent
@ 2026-04-09 17:08 ` Kory Maincent
2026-04-09 17:08 ` [PATCH RFC 02/12] drm/i915/display/intel_lvds: Drop redundant manual cleanup on init failure Kory Maincent
` (10 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Kory Maincent @ 2026-04-09 17:08 UTC (permalink / raw)
To: Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
David Airlie, Simona Vetter, Dave Airlie, Jesse Barnes,
Eric Anholt, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Chun-Kuang Hu, Philipp Zabel,
Matthias Brugger, AngeloGioacchino Del Regno, Chris Wilson
Cc: Thomas Petazzoni, Mark Yacoub, Sean Paul, Louis Chauvet,
intel-gfx, intel-xe, dri-devel, linux-kernel, linux-mediatek,
linux-arm-kernel, Simona Vetter, Kory Maincent
intel_sdvo_connector_funcs registers intel_connector_destroy() as the
.destroy callback. Once drm_connector_init_with_ddc() succeeds inside
intel_sdvo_connector_init(), the DRM core takes ownership of the
connector object and will call .destroy on teardown.
The error labels in intel_sdvo_tv_init() and intel_sdvo_lvds_init()
call intel_connector_destroy() explicitly before returning false,
causing it to be invoked twice: once in the error path and again by
the DRM core through the registered .destroy callback.
Remove the manual intel_connector_destroy() calls from the error labels
and return false directly instead.
Fixes: 32aad86fe88e7 ("drm/i915/sdvo: Propagate errors from reading/writing control bus.")
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
Not tested as I don't have such hardware.
---
drivers/gpu/drm/i915/display/intel_sdvo.c | 16 ++++------------
1 file changed, 4 insertions(+), 12 deletions(-)
diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c
index 2e1af9e869ded..6eb2b4b45a9b4 100644
--- a/drivers/gpu/drm/i915/display/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/display/intel_sdvo.c
@@ -2873,16 +2873,12 @@ intel_sdvo_tv_init(struct intel_sdvo *intel_sdvo, u16 type)
}
if (!intel_sdvo_tv_create_property(intel_sdvo, intel_sdvo_connector, type))
- goto err;
+ return false;
if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector))
- goto err;
+ return false;
return true;
-
-err:
- intel_connector_destroy(connector);
- return false;
}
static bool
@@ -2945,7 +2941,7 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, u16 type)
}
if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector))
- goto err;
+ return false;
intel_bios_init_panel_late(display, &intel_connector->panel, NULL, NULL);
@@ -2967,13 +2963,9 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, u16 type)
intel_panel_init(intel_connector, NULL);
if (!intel_panel_preferred_fixed_mode(intel_connector))
- goto err;
+ return false;
return true;
-
-err:
- intel_connector_destroy(connector);
- return false;
}
static u16 intel_sdvo_filter_output_flags(u16 flags)
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH RFC 02/12] drm/i915/display/intel_lvds: Drop redundant manual cleanup on init failure
2026-04-09 17:08 [PATCH RFC 00/12] Add support for DisplayPort link training information report Kory Maincent
2026-04-09 17:08 ` [PATCH RFC 01/12] drm/i915/display/intel_sdvo: Fix double connector destroy in error paths Kory Maincent
@ 2026-04-09 17:08 ` Kory Maincent
2026-04-09 17:08 ` [PATCH RFC 03/12] drm/i915/display/intel_dp: Drop redundant intel_dp_aux_fini() " Kory Maincent
` (9 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Kory Maincent @ 2026-04-09 17:08 UTC (permalink / raw)
To: Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
David Airlie, Simona Vetter, Dave Airlie, Jesse Barnes,
Eric Anholt, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Chun-Kuang Hu, Philipp Zabel,
Matthias Brugger, AngeloGioacchino Del Regno, Chris Wilson
Cc: Thomas Petazzoni, Mark Yacoub, Sean Paul, Louis Chauvet,
intel-gfx, intel-xe, dri-devel, linux-kernel, linux-mediatek,
linux-arm-kernel, Simona Vetter, Kory Maincent
intel_lvds_init() had a goto-based error path that manually called
drm_connector_cleanup(), drm_encoder_cleanup(), kfree() and
intel_connector_free() when no LVDS panel mode could be found.
Once drm_connector_init_with_ddc() and drm_encoder_init() have been
called, the DRM core takes ownership of these objects and will invoke
their .destroy callbacks (intel_connector_destroy and
intel_encoder_destroy) during device teardown. The manual cleanup in
the failed: label is therefore redundant.
Remove it and replace the goto with a simple early return.
Fixes: 79e539453b34e ("DRM: i915: add mode setting support")
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
Not tested as I don't have such hardware.
---
drivers/gpu/drm/i915/display/intel_lvds.c | 14 ++++----------
1 file changed, 4 insertions(+), 10 deletions(-)
diff --git a/drivers/gpu/drm/i915/display/intel_lvds.c b/drivers/gpu/drm/i915/display/intel_lvds.c
index cc6d4bfcff102..e78a41e2b268c 100644
--- a/drivers/gpu/drm/i915/display/intel_lvds.c
+++ b/drivers/gpu/drm/i915/display/intel_lvds.c
@@ -991,8 +991,10 @@ void intel_lvds_init(struct intel_display *display)
mutex_unlock(&display->drm->mode_config.mutex);
/* If we still don't have a mode after all that, give up. */
- if (!intel_panel_preferred_fixed_mode(connector))
- goto failed;
+ if (!intel_panel_preferred_fixed_mode(connector)) {
+ drm_dbg_kms(display->drm, "No LVDS modes found, disabling.\n");
+ return;
+ }
intel_panel_init(connector, drm_edid);
@@ -1005,12 +1007,4 @@ void intel_lvds_init(struct intel_display *display)
lvds_encoder->a3_power = lvds & LVDS_A3_POWER_MASK;
return;
-
-failed:
- drm_dbg_kms(display->drm, "No LVDS modes found, disabling.\n");
- drm_connector_cleanup(&connector->base);
- drm_encoder_cleanup(&encoder->base);
- kfree(lvds_encoder);
- intel_connector_free(connector);
- return;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH RFC 03/12] drm/i915/display/intel_dp: Drop redundant intel_dp_aux_fini() on init failure
2026-04-09 17:08 [PATCH RFC 00/12] Add support for DisplayPort link training information report Kory Maincent
2026-04-09 17:08 ` [PATCH RFC 01/12] drm/i915/display/intel_sdvo: Fix double connector destroy in error paths Kory Maincent
2026-04-09 17:08 ` [PATCH RFC 02/12] drm/i915/display/intel_lvds: Drop redundant manual cleanup on init failure Kory Maincent
@ 2026-04-09 17:08 ` Kory Maincent
2026-04-09 17:08 ` [PATCH RFC 04/12] drm/i915/display: Switch to drmm_mode_config_init() and drop manual cleanup Kory Maincent
` (8 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Kory Maincent @ 2026-04-09 17:08 UTC (permalink / raw)
To: Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
David Airlie, Simona Vetter, Dave Airlie, Jesse Barnes,
Eric Anholt, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Chun-Kuang Hu, Philipp Zabel,
Matthias Brugger, AngeloGioacchino Del Regno, Chris Wilson
Cc: Thomas Petazzoni, Mark Yacoub, Sean Paul, Louis Chauvet,
intel-gfx, intel-xe, dri-devel, linux-kernel, linux-mediatek,
linux-arm-kernel, Simona Vetter, Kory Maincent
intel_dp_aux_fini() is already invoked via intel_dp_encoder_flush_work()
in the encoder destroy path (intel_dp_encoder_destroy() and
intel_ddi_encoder_destroy()). Calling it explicitly when
intel_edp_init_connector() fails before jumping to the fail label
therefore results in a double invocation. Drop the redundant call.
Fixes: c191eca110a37 ("drm/i915: Move intel_connector->unregister to connector->early_unregister")
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
drivers/gpu/drm/i915/display/intel_dp.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 4955bd8b11d7a..71f206adbebd3 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -7232,10 +7232,8 @@ intel_dp_init_connector(struct intel_digital_port *dig_port,
connector->get_hw_state = intel_connector_get_hw_state;
connector->sync_state = intel_dp_connector_sync_state;
- if (!intel_edp_init_connector(intel_dp, connector)) {
- intel_dp_aux_fini(intel_dp);
+ if (!intel_edp_init_connector(intel_dp, connector))
goto fail;
- }
intel_dp_set_source_rates(intel_dp);
intel_dp_set_common_rates(intel_dp);
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH RFC 04/12] drm/i915/display: Switch to drmm_mode_config_init() and drop manual cleanup
2026-04-09 17:08 [PATCH RFC 00/12] Add support for DisplayPort link training information report Kory Maincent
` (2 preceding siblings ...)
2026-04-09 17:08 ` [PATCH RFC 03/12] drm/i915/display/intel_dp: Drop redundant intel_dp_aux_fini() " Kory Maincent
@ 2026-04-09 17:08 ` Kory Maincent
2026-04-09 17:08 ` [PATCH RFC 05/12] drm/i915/display: Switch to managed for crtc Kory Maincent
` (7 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Kory Maincent @ 2026-04-09 17:08 UTC (permalink / raw)
To: Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
David Airlie, Simona Vetter, Dave Airlie, Jesse Barnes,
Eric Anholt, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Chun-Kuang Hu, Philipp Zabel,
Matthias Brugger, AngeloGioacchino Del Regno, Chris Wilson
Cc: Thomas Petazzoni, Mark Yacoub, Sean Paul, Louis Chauvet,
intel-gfx, intel-xe, dri-devel, linux-kernel, linux-mediatek,
linux-arm-kernel, Simona Vetter, Kory Maincent
Replace drm_mode_config_init() with drmm_mode_config_init() in
intel_mode_config_init(). The managed variant automatically registers
drm_mode_config_cleanup() with devres, so drivers must no longer call it
directly.
Since intel_mode_config_cleanup() was solely a wrapper combining
intel_atomic_global_obj_cleanup() and drm_mode_config_cleanup(), and the
latter is now handled by DRM core, remove it entirely. Instead, register
intel_atomic_global_obj_cleanup() as a devres action so it still runs just
before drm_mode_config_cleanup() during teardown, preserving the correct
cleanup ordering.
Change intel_mode_config_init() to return int to propagate any error from
drmm_mode_config_init().
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
.../gpu/drm/i915/display/intel_display_driver.c | 37 ++++++++++++++--------
1 file changed, 24 insertions(+), 13 deletions(-)
diff --git a/drivers/gpu/drm/i915/display/intel_display_driver.c b/drivers/gpu/drm/i915/display/intel_display_driver.c
index 23bfecc983e8d..d02393053cef4 100644
--- a/drivers/gpu/drm/i915/display/intel_display_driver.c
+++ b/drivers/gpu/drm/i915/display/intel_display_driver.c
@@ -12,6 +12,7 @@
#include <drm/display/drm_dp_mst_helper.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_client_event.h>
+#include <drm/drm_managed.h>
#include <drm/drm_mode_config.h>
#include <drm/drm_privacy_screen_consumer.h>
#include <drm/drm_print.h>
@@ -48,6 +49,7 @@
#include "intel_fbdev.h"
#include "intel_fdi.h"
#include "intel_flipq.h"
+#include "intel_global_state.h"
#include "intel_gmbus.h"
#include "intel_hdcp.h"
#include "intel_hotplug.h"
@@ -111,13 +113,28 @@ static const struct drm_mode_config_helper_funcs intel_mode_config_funcs = {
.atomic_commit_setup = drm_dp_mst_atomic_setup_commit,
};
-static void intel_mode_config_init(struct intel_display *display)
+static void intel_atomic_global_obj_cleanup_action(struct drm_device *drm, void *data)
+{
+ intel_atomic_global_obj_cleanup((struct intel_display *)data);
+}
+
+static int intel_mode_config_init(struct intel_display *display)
{
struct drm_mode_config *mode_config = &display->drm->mode_config;
+ int ret;
+
+ ret = drmm_mode_config_init(display->drm);
+ if (ret)
+ return ret;
- drm_mode_config_init(display->drm);
INIT_LIST_HEAD(&display->global.obj_list);
+ ret = drmm_add_action_or_reset(display->drm,
+ intel_atomic_global_obj_cleanup_action,
+ display);
+ if (ret)
+ return ret;
+
mode_config->min_width = 0;
mode_config->min_height = 0;
@@ -148,12 +165,8 @@ static void intel_mode_config_init(struct intel_display *display)
}
intel_cursor_mode_config_init(display);
-}
-static void intel_mode_config_cleanup(struct intel_display *display)
-{
- intel_atomic_global_obj_cleanup(display);
- drm_mode_config_cleanup(display->drm);
+ return 0;
}
static void intel_plane_possible_crtcs_init(struct intel_display *display)
@@ -255,7 +268,9 @@ int intel_display_driver_probe_noirq(struct intel_display *display)
intel_dmc_init(display);
- intel_mode_config_init(display);
+ ret = intel_mode_config_init(display);
+ if (ret)
+ goto cleanup_wq_unordered;
ret = intel_cdclk_init(display);
if (ret)
@@ -456,7 +471,7 @@ int intel_display_driver_probe_nogem(struct intel_display *display)
ret = intel_crtc_init(display);
if (ret)
- goto err_mode_config;
+ return ret;
intel_plane_possible_crtcs_init(display);
intel_dpll_init(display);
@@ -497,8 +512,6 @@ int intel_display_driver_probe_nogem(struct intel_display *display)
err_hdcp:
intel_hdcp_component_fini(display);
-err_mode_config:
- intel_mode_config_cleanup(display);
return ret;
}
@@ -618,8 +631,6 @@ void intel_display_driver_remove_noirq(struct intel_display *display)
intel_hdcp_component_fini(display);
- intel_mode_config_cleanup(display);
-
intel_dp_tunnel_mgr_cleanup(display);
intel_overlay_cleanup(display);
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH RFC 05/12] drm/i915/display: Switch to managed for crtc
2026-04-09 17:08 [PATCH RFC 00/12] Add support for DisplayPort link training information report Kory Maincent
` (3 preceding siblings ...)
2026-04-09 17:08 ` [PATCH RFC 04/12] drm/i915/display: Switch to drmm_mode_config_init() and drop manual cleanup Kory Maincent
@ 2026-04-09 17:08 ` Kory Maincent
2026-04-09 17:08 ` [PATCH RFC 06/12] drm/i915/display: Switch to managed for plane Kory Maincent
` (6 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Kory Maincent @ 2026-04-09 17:08 UTC (permalink / raw)
To: Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
David Airlie, Simona Vetter, Dave Airlie, Jesse Barnes,
Eric Anholt, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Chun-Kuang Hu, Philipp Zabel,
Matthias Brugger, AngeloGioacchino Del Regno, Chris Wilson
Cc: Thomas Petazzoni, Mark Yacoub, Sean Paul, Louis Chauvet,
intel-gfx, intel-xe, dri-devel, linux-kernel, linux-mediatek,
linux-arm-kernel, Simona Vetter, Kory Maincent
The current i915 driver uses non-managed function to create crtc. It
is not an issue yet, but in order to comply with the latest DRM
requirement, convert this code to use drm and device managed helpers.
Assisted-by: Claude Code:2.1.90
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
drivers/gpu/drm/i915/display/intel_crtc.c | 102 ++++++++++--------------------
1 file changed, 35 insertions(+), 67 deletions(-)
diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c b/drivers/gpu/drm/i915/display/intel_crtc.c
index b8189cd5d864a..e2f995313acf2 100644
--- a/drivers/gpu/drm/i915/display/intel_crtc.c
+++ b/drivers/gpu/drm/i915/display/intel_crtc.c
@@ -8,6 +8,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_fourcc.h>
+#include <drm/drm_managed.h>
#include <drm/drm_plane.h>
#include <drm/drm_print.h>
#include <drm/drm_vblank.h>
@@ -191,41 +192,11 @@ void intel_crtc_state_reset(struct intel_crtc_state *crtc_state,
crtc_state->max_link_bpp_x16 = INT_MAX;
}
-static struct intel_crtc *intel_crtc_alloc(void)
+static void intel_crtc_vblank_pm_qos_cleanup(struct drm_device *drm, void *data)
{
- struct intel_crtc_state *crtc_state;
- struct intel_crtc *crtc;
-
- crtc = kzalloc_obj(*crtc);
- if (!crtc)
- return ERR_PTR(-ENOMEM);
-
- crtc_state = intel_crtc_state_alloc(crtc);
- if (!crtc_state) {
- kfree(crtc);
- return ERR_PTR(-ENOMEM);
- }
-
- crtc->base.state = &crtc_state->uapi;
- crtc->config = crtc_state;
-
- return crtc;
-}
-
-static void intel_crtc_free(struct intel_crtc *crtc)
-{
- intel_crtc_destroy_state(&crtc->base, crtc->base.state);
- kfree(crtc);
-}
-
-static void intel_crtc_destroy(struct drm_crtc *_crtc)
-{
- struct intel_crtc *crtc = to_intel_crtc(_crtc);
+ struct intel_crtc *crtc = data;
cpu_latency_qos_remove_request(&crtc->vblank_pm_qos);
-
- drm_crtc_cleanup(&crtc->base);
- kfree(crtc);
}
static int intel_crtc_late_register(struct drm_crtc *crtc)
@@ -236,7 +207,6 @@ static int intel_crtc_late_register(struct drm_crtc *crtc)
#define INTEL_CRTC_FUNCS \
.set_config = drm_atomic_helper_set_config, \
- .destroy = intel_crtc_destroy, \
.page_flip = drm_atomic_helper_page_flip, \
.atomic_duplicate_state = intel_crtc_duplicate_state, \
.atomic_destroy_state = intel_crtc_destroy_state, \
@@ -311,28 +281,19 @@ static const struct drm_crtc_funcs i8xx_crtc_funcs = {
static int __intel_crtc_init(struct intel_display *display, enum pipe pipe)
{
struct intel_plane *primary, *cursor;
+ struct intel_crtc_state *crtc_state;
const struct drm_crtc_funcs *funcs;
struct intel_crtc *crtc;
+ u32 plane_ids_mask = 0;
int sprite, ret;
- crtc = intel_crtc_alloc();
- if (IS_ERR(crtc))
- return PTR_ERR(crtc);
-
- crtc->pipe = pipe;
- crtc->num_scalers = DISPLAY_RUNTIME_INFO(display)->num_scalers[pipe];
-
if (DISPLAY_VER(display) >= 9)
primary = skl_universal_plane_create(display, pipe, PLANE_1);
else
primary = intel_primary_plane_create(display, pipe);
- if (IS_ERR(primary)) {
- ret = PTR_ERR(primary);
- goto fail;
- }
- crtc->plane_ids_mask |= BIT(primary->id);
-
- intel_init_fifo_underrun_reporting(display, crtc, false);
+ if (IS_ERR(primary))
+ return PTR_ERR(primary);
+ plane_ids_mask |= BIT(primary->id);
for_each_sprite(display, pipe, sprite) {
struct intel_plane *plane;
@@ -341,19 +302,15 @@ static int __intel_crtc_init(struct intel_display *display, enum pipe pipe)
plane = skl_universal_plane_create(display, pipe, PLANE_2 + sprite);
else
plane = intel_sprite_plane_create(display, pipe, sprite);
- if (IS_ERR(plane)) {
- ret = PTR_ERR(plane);
- goto fail;
- }
- crtc->plane_ids_mask |= BIT(plane->id);
+ if (IS_ERR(plane))
+ return PTR_ERR(plane);
+ plane_ids_mask |= BIT(plane->id);
}
cursor = intel_cursor_plane_create(display, pipe);
- if (IS_ERR(cursor)) {
- ret = PTR_ERR(cursor);
- goto fail;
- }
- crtc->plane_ids_mask |= BIT(cursor->id);
+ if (IS_ERR(cursor))
+ return PTR_ERR(cursor);
+ plane_ids_mask |= BIT(cursor->id);
if (HAS_GMCH(display)) {
if (display->platform.cherryview ||
@@ -376,11 +333,23 @@ static int __intel_crtc_init(struct intel_display *display, enum pipe pipe)
funcs = &ilk_crtc_funcs;
}
- ret = drm_crtc_init_with_planes(display->drm, &crtc->base,
- &primary->base, &cursor->base,
- funcs, "pipe %c", pipe_name(pipe));
- if (ret)
- goto fail;
+ crtc = drmm_crtc_alloc_with_planes(display->drm, struct intel_crtc, base,
+ &primary->base, &cursor->base,
+ funcs, "pipe %c", pipe_name(pipe));
+ if (IS_ERR(crtc))
+ return PTR_ERR(crtc);
+
+ crtc->pipe = pipe;
+ crtc->num_scalers = DISPLAY_RUNTIME_INFO(display)->num_scalers[pipe];
+ crtc->plane_ids_mask = plane_ids_mask;
+
+ crtc_state = intel_crtc_state_alloc(crtc);
+ if (!crtc_state)
+ return -ENOMEM;
+ crtc->base.state = &crtc_state->uapi;
+ crtc->config = crtc_state;
+
+ intel_init_fifo_underrun_reporting(display, crtc, false);
if (DISPLAY_VER(display) >= 11)
drm_crtc_create_scaling_filter_property(&crtc->base,
@@ -393,17 +362,16 @@ static int __intel_crtc_init(struct intel_display *display, enum pipe pipe)
cpu_latency_qos_add_request(&crtc->vblank_pm_qos, PM_QOS_DEFAULT_VALUE);
+ ret = drmm_add_action_or_reset(display->drm, intel_crtc_vblank_pm_qos_cleanup, crtc);
+ if (ret)
+ return ret;
+
drm_WARN_ON(display->drm, drm_crtc_index(&crtc->base) != crtc->pipe);
if (HAS_CASF(display) && crtc->num_scalers >= 2)
drm_crtc_create_sharpness_strength_property(&crtc->base);
return 0;
-
-fail:
- intel_crtc_free(crtc);
-
- return ret;
}
int intel_crtc_init(struct intel_display *display)
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH RFC 06/12] drm/i915/display: Switch to managed for plane
2026-04-09 17:08 [PATCH RFC 00/12] Add support for DisplayPort link training information report Kory Maincent
` (4 preceding siblings ...)
2026-04-09 17:08 ` [PATCH RFC 05/12] drm/i915/display: Switch to managed for crtc Kory Maincent
@ 2026-04-09 17:08 ` Kory Maincent
2026-04-09 17:08 ` [PATCH RFC 07/12] drm/i915/display: Switch to managed for encoder Kory Maincent
` (5 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Kory Maincent @ 2026-04-09 17:08 UTC (permalink / raw)
To: Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
David Airlie, Simona Vetter, Dave Airlie, Jesse Barnes,
Eric Anholt, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Chun-Kuang Hu, Philipp Zabel,
Matthias Brugger, AngeloGioacchino Del Regno, Chris Wilson
Cc: Thomas Petazzoni, Mark Yacoub, Sean Paul, Louis Chauvet,
intel-gfx, intel-xe, dri-devel, linux-kernel, linux-mediatek,
linux-arm-kernel, Simona Vetter, Kory Maincent
The current i915 driver uses non-managed function to create plane. It
is not an issue yet, but in order to comply with the latest DRM
requirement, convert this code to use drm and device managed helpers.
Assisted-by: Claude Code:2.1.90
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
drivers/gpu/drm/i915/display/i9xx_plane.c | 97 ++++++++---------
drivers/gpu/drm/i915/display/intel_cursor.c | 41 ++++---
drivers/gpu/drm/i915/display/intel_plane.c | 45 +-------
drivers/gpu/drm/i915/display/intel_plane.h | 5 +-
drivers/gpu/drm/i915/display/intel_sprite.c | 119 ++++++++++-----------
drivers/gpu/drm/i915/display/skl_universal_plane.c | 102 +++++++++---------
6 files changed, 181 insertions(+), 228 deletions(-)
diff --git a/drivers/gpu/drm/i915/display/i9xx_plane.c b/drivers/gpu/drm/i915/display/i9xx_plane.c
index 9c16753a1f3ba..032c56b478dfc 100644
--- a/drivers/gpu/drm/i915/display/i9xx_plane.c
+++ b/drivers/gpu/drm/i915/display/i9xx_plane.c
@@ -8,6 +8,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_blend.h>
#include <drm/drm_fourcc.h>
+#include <drm/drm_managed.h>
#include <drm/drm_print.h>
#include "i9xx_plane.h"
@@ -882,7 +883,6 @@ static unsigned int i9xx_plane_min_alignment(struct intel_plane *plane,
static const struct drm_plane_funcs i965_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
- .destroy = intel_plane_destroy,
.atomic_duplicate_state = intel_plane_duplicate_state,
.atomic_destroy_state = intel_plane_destroy_state,
.format_mod_supported = i965_plane_format_mod_supported,
@@ -892,7 +892,6 @@ static const struct drm_plane_funcs i965_plane_funcs = {
static const struct drm_plane_funcs i8xx_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
- .destroy = intel_plane_destroy,
.atomic_duplicate_state = intel_plane_duplicate_state,
.atomic_destroy_state = intel_plane_destroy_state,
.format_mod_supported = i8xx_plane_format_mod_supported,
@@ -923,32 +922,15 @@ static void i9xx_disable_tiling(struct intel_plane *plane)
struct intel_plane *
intel_primary_plane_create(struct intel_display *display, enum pipe pipe)
{
+ struct intel_plane_state *plane_state;
struct intel_plane *plane;
const struct drm_plane_funcs *plane_funcs;
unsigned int supported_rotations;
const u64 *modifiers;
const u32 *formats;
int num_formats;
- int ret, zpos;
-
- plane = intel_plane_alloc();
- if (IS_ERR(plane))
- return plane;
-
- plane->pipe = pipe;
- /*
- * On gen2/3 only plane A can do FBC, but the panel fitter and LVDS
- * port is hooked to pipe B. Hence we want plane A feeding pipe B.
- */
- if (HAS_FBC(display) && DISPLAY_VER(display) < 4 &&
- INTEL_NUM_PIPES(display) == 2)
- plane->i9xx_plane = (enum i9xx_plane_id) !pipe;
- else
- plane->i9xx_plane = (enum i9xx_plane_id) pipe;
- plane->id = PLANE_PRIMARY;
- plane->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, plane->id);
-
- intel_fbc_add_plane(i9xx_plane_fbc(display, plane->i9xx_plane), plane);
+ enum i9xx_plane_id i9xx_plane;
+ int zpos;
if (display->platform.valleyview || display->platform.cherryview) {
formats = vlv_primary_formats;
@@ -984,6 +966,46 @@ intel_primary_plane_create(struct intel_display *display, enum pipe pipe)
else
plane_funcs = &i8xx_plane_funcs;
+ /*
+ * On gen2/3 only plane A can do FBC, but the panel fitter and LVDS
+ * port is hooked to pipe B. Hence we want plane A feeding pipe B.
+ */
+ if (HAS_FBC(display) && DISPLAY_VER(display) < 4 &&
+ INTEL_NUM_PIPES(display) == 2)
+ i9xx_plane = (enum i9xx_plane_id)!pipe;
+ else
+ i9xx_plane = (enum i9xx_plane_id)pipe;
+
+ modifiers = intel_fb_plane_get_modifiers(display, INTEL_PLANE_CAP_TILING_X);
+
+ if (DISPLAY_VER(display) >= 5 || display->platform.g4x)
+ plane = drmm_universal_plane_alloc(display->drm, struct intel_plane, base,
+ 0, plane_funcs,
+ formats, num_formats,
+ modifiers,
+ DRM_PLANE_TYPE_PRIMARY,
+ "primary %c", pipe_name(pipe));
+ else
+ plane = drmm_universal_plane_alloc(display->drm, struct intel_plane, base,
+ 0, plane_funcs,
+ formats, num_formats,
+ modifiers,
+ DRM_PLANE_TYPE_PRIMARY,
+ "plane %c",
+ plane_name(i9xx_plane));
+
+ kfree(modifiers);
+
+ if (IS_ERR(plane))
+ return plane;
+
+ plane->pipe = pipe;
+ plane->i9xx_plane = i9xx_plane;
+ plane->id = PLANE_PRIMARY;
+ plane->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, plane->id);
+
+ intel_fbc_add_plane(i9xx_plane_fbc(display, plane->i9xx_plane), plane);
+
if (display->platform.valleyview || display->platform.cherryview)
plane->min_cdclk = vlv_plane_min_cdclk;
else if (display->platform.broadwell || display->platform.haswell)
@@ -1069,28 +1091,12 @@ intel_primary_plane_create(struct intel_display *display, enum pipe pipe)
plane->disable_tiling = i9xx_disable_tiling;
- modifiers = intel_fb_plane_get_modifiers(display, INTEL_PLANE_CAP_TILING_X);
-
- if (DISPLAY_VER(display) >= 5 || display->platform.g4x)
- ret = drm_universal_plane_init(display->drm, &plane->base,
- 0, plane_funcs,
- formats, num_formats,
- modifiers,
- DRM_PLANE_TYPE_PRIMARY,
- "primary %c", pipe_name(pipe));
- else
- ret = drm_universal_plane_init(display->drm, &plane->base,
- 0, plane_funcs,
- formats, num_formats,
- modifiers,
- DRM_PLANE_TYPE_PRIMARY,
- "plane %c",
- plane_name(plane->i9xx_plane));
-
- kfree(modifiers);
+ plane_state = kzalloc_obj(*plane_state);
+ if (!plane_state)
+ return ERR_PTR(-ENOMEM);
- if (ret)
- goto fail;
+ intel_plane_state_reset(plane_state, plane);
+ plane->base.state = &plane_state->uapi;
if (display->platform.cherryview && pipe == PIPE_B) {
supported_rotations =
@@ -1114,11 +1120,6 @@ intel_primary_plane_create(struct intel_display *display, enum pipe pipe)
intel_plane_helper_add(plane);
return plane;
-
-fail:
- intel_plane_free(plane);
-
- return ERR_PTR(ret);
}
static int i9xx_format_to_fourcc(int format)
diff --git a/drivers/gpu/drm/i915/display/intel_cursor.c b/drivers/gpu/drm/i915/display/intel_cursor.c
index 18d1014de3613..2493baf25fbe2 100644
--- a/drivers/gpu/drm/i915/display/intel_cursor.c
+++ b/drivers/gpu/drm/i915/display/intel_cursor.c
@@ -9,6 +9,7 @@
#include <drm/drm_blend.h>
#include <drm/drm_damage_helper.h>
#include <drm/drm_fourcc.h>
+#include <drm/drm_managed.h>
#include <drm/drm_print.h>
#include <drm/drm_vblank.h>
@@ -971,7 +972,6 @@ intel_legacy_cursor_update(struct drm_plane *_plane,
static const struct drm_plane_funcs intel_cursor_plane_funcs = {
.update_plane = intel_legacy_cursor_update,
.disable_plane = drm_atomic_helper_disable_plane,
- .destroy = intel_plane_destroy,
.atomic_duplicate_state = intel_plane_duplicate_state,
.atomic_destroy_state = intel_plane_destroy_state,
.format_mod_supported = intel_cursor_format_mod_supported,
@@ -1004,11 +1004,23 @@ struct intel_plane *
intel_cursor_plane_create(struct intel_display *display,
enum pipe pipe)
{
+ struct intel_plane_state *plane_state;
struct intel_plane *cursor;
- int ret, zpos;
+ int zpos;
u64 *modifiers;
- cursor = intel_plane_alloc();
+ modifiers = intel_fb_plane_get_modifiers(display, INTEL_PLANE_CAP_NONE);
+
+ cursor = drmm_universal_plane_alloc(display->drm, struct intel_plane, base,
+ 0, &intel_cursor_plane_funcs,
+ intel_cursor_formats,
+ ARRAY_SIZE(intel_cursor_formats),
+ modifiers,
+ DRM_PLANE_TYPE_CURSOR,
+ "cursor %c", pipe_name(pipe));
+
+ kfree(modifiers);
+
if (IS_ERR(cursor))
return cursor;
@@ -1056,20 +1068,12 @@ intel_cursor_plane_create(struct intel_display *display,
if (display->platform.i845g || display->platform.i865g || HAS_CUR_FBC(display))
cursor->cursor.size = ~0;
- modifiers = intel_fb_plane_get_modifiers(display, INTEL_PLANE_CAP_NONE);
-
- ret = drm_universal_plane_init(display->drm, &cursor->base,
- 0, &intel_cursor_plane_funcs,
- intel_cursor_formats,
- ARRAY_SIZE(intel_cursor_formats),
- modifiers,
- DRM_PLANE_TYPE_CURSOR,
- "cursor %c", pipe_name(pipe));
-
- kfree(modifiers);
+ plane_state = kzalloc_obj(*plane_state);
+ if (!plane_state)
+ return ERR_PTR(-ENOMEM);
- if (ret)
- goto fail;
+ intel_plane_state_reset(plane_state, cursor);
+ cursor->base.state = &plane_state->uapi;
if (DISPLAY_VER(display) >= 4)
drm_plane_create_rotation_property(&cursor->base,
@@ -1088,11 +1092,6 @@ intel_cursor_plane_create(struct intel_display *display,
intel_plane_helper_add(cursor);
return cursor;
-
-fail:
- intel_plane_free(cursor);
-
- return ERR_PTR(ret);
}
void intel_cursor_mode_config_init(struct intel_display *display)
diff --git a/drivers/gpu/drm/i915/display/intel_plane.c b/drivers/gpu/drm/i915/display/intel_plane.c
index 5390ceb21ca42..05c2dc0902f5c 100644
--- a/drivers/gpu/drm/i915/display/intel_plane.c
+++ b/drivers/gpu/drm/i915/display/intel_plane.c
@@ -62,8 +62,8 @@
#include "skl_universal_plane.h"
#include "skl_watermark.h"
-static void intel_plane_state_reset(struct intel_plane_state *plane_state,
- struct intel_plane *plane)
+void intel_plane_state_reset(struct intel_plane_state *plane_state,
+ struct intel_plane *plane)
{
memset(plane_state, 0, sizeof(*plane_state));
@@ -72,47 +72,6 @@ static void intel_plane_state_reset(struct intel_plane_state *plane_state,
plane_state->scaler_id = -1;
}
-struct intel_plane *intel_plane_alloc(void)
-{
- struct intel_plane_state *plane_state;
- struct intel_plane *plane;
-
- plane = kzalloc_obj(*plane);
- if (!plane)
- return ERR_PTR(-ENOMEM);
-
- plane_state = kzalloc_obj(*plane_state);
- if (!plane_state) {
- kfree(plane);
- return ERR_PTR(-ENOMEM);
- }
-
- intel_plane_state_reset(plane_state, plane);
-
- plane->base.state = &plane_state->uapi;
-
- return plane;
-}
-
-void intel_plane_free(struct intel_plane *plane)
-{
- intel_plane_destroy_state(&plane->base, plane->base.state);
- kfree(plane);
-}
-
-/**
- * intel_plane_destroy - destroy a plane
- * @plane: plane to destroy
- *
- * Common destruction function for all types of planes (primary, cursor,
- * sprite).
- */
-void intel_plane_destroy(struct drm_plane *plane)
-{
- drm_plane_cleanup(plane);
- kfree(to_intel_plane(plane));
-}
-
/**
* intel_plane_duplicate_state - duplicate plane state
* @plane: drm plane
diff --git a/drivers/gpu/drm/i915/display/intel_plane.h b/drivers/gpu/drm/i915/display/intel_plane.h
index 5a8f2f3baab5f..56221619a2b29 100644
--- a/drivers/gpu/drm/i915/display/intel_plane.h
+++ b/drivers/gpu/drm/i915/display/intel_plane.h
@@ -55,9 +55,8 @@ void intel_plane_update_arm(struct intel_dsb *dsb,
void intel_plane_disable_arm(struct intel_dsb *dsb,
struct intel_plane *plane,
const struct intel_crtc_state *crtc_state);
-struct intel_plane *intel_plane_alloc(void);
-void intel_plane_free(struct intel_plane *plane);
-void intel_plane_destroy(struct drm_plane *plane);
+void intel_plane_state_reset(struct intel_plane_state *plane_state,
+ struct intel_plane *plane);
struct drm_plane_state *intel_plane_duplicate_state(struct drm_plane *plane);
void intel_plane_destroy_state(struct drm_plane *plane,
struct drm_plane_state *state);
diff --git a/drivers/gpu/drm/i915/display/intel_sprite.c b/drivers/gpu/drm/i915/display/intel_sprite.c
index 6a65f92e8a031..f285d15734ee5 100644
--- a/drivers/gpu/drm/i915/display/intel_sprite.c
+++ b/drivers/gpu/drm/i915/display/intel_sprite.c
@@ -36,6 +36,7 @@
#include <drm/drm_blend.h>
#include <drm/drm_color_mgmt.h>
#include <drm/drm_fourcc.h>
+#include <drm/drm_managed.h>
#include <drm/drm_print.h>
#include <drm/drm_rect.h>
@@ -1563,7 +1564,6 @@ static bool vlv_sprite_format_mod_supported(struct drm_plane *_plane,
static const struct drm_plane_funcs g4x_sprite_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
- .destroy = intel_plane_destroy,
.atomic_duplicate_state = intel_plane_duplicate_state,
.atomic_destroy_state = intel_plane_destroy_state,
.format_mod_supported = g4x_sprite_format_mod_supported,
@@ -1573,7 +1573,6 @@ static const struct drm_plane_funcs g4x_sprite_funcs = {
static const struct drm_plane_funcs snb_sprite_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
- .destroy = intel_plane_destroy,
.atomic_duplicate_state = intel_plane_duplicate_state,
.atomic_destroy_state = intel_plane_destroy_state,
.format_mod_supported = snb_sprite_format_mod_supported,
@@ -1583,7 +1582,6 @@ static const struct drm_plane_funcs snb_sprite_funcs = {
static const struct drm_plane_funcs vlv_sprite_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
- .destroy = intel_plane_destroy,
.atomic_duplicate_state = intel_plane_duplicate_state,
.atomic_destroy_state = intel_plane_destroy_state,
.format_mod_supported = vlv_sprite_format_mod_supported,
@@ -1594,18 +1592,69 @@ struct intel_plane *
intel_sprite_plane_create(struct intel_display *display,
enum pipe pipe, int sprite)
{
+ struct intel_plane_state *plane_state;
struct intel_plane *plane;
const struct drm_plane_funcs *plane_funcs;
unsigned int supported_rotations;
const u64 *modifiers;
const u32 *formats;
int num_formats;
- int ret, zpos;
+ int zpos;
+
+ if (display->platform.valleyview || display->platform.cherryview) {
+ if (display->platform.cherryview && pipe == PIPE_B) {
+ formats = chv_pipe_b_sprite_formats;
+ num_formats = ARRAY_SIZE(chv_pipe_b_sprite_formats);
+ } else {
+ formats = vlv_sprite_formats;
+ num_formats = ARRAY_SIZE(vlv_sprite_formats);
+ }
+
+ plane_funcs = &vlv_sprite_funcs;
+ } else if (DISPLAY_VER(display) >= 7) {
+ formats = snb_sprite_formats;
+ num_formats = ARRAY_SIZE(snb_sprite_formats);
+
+ plane_funcs = &snb_sprite_funcs;
+ } else {
+ if (display->platform.sandybridge) {
+ formats = snb_sprite_formats;
+ num_formats = ARRAY_SIZE(snb_sprite_formats);
+
+ plane_funcs = &snb_sprite_funcs;
+ } else {
+ formats = g4x_sprite_formats;
+ num_formats = ARRAY_SIZE(g4x_sprite_formats);
+
+ plane_funcs = &g4x_sprite_funcs;
+ }
+ }
+
+ if (display->platform.cherryview && pipe == PIPE_B) {
+ supported_rotations =
+ DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 |
+ DRM_MODE_REFLECT_X;
+ } else {
+ supported_rotations =
+ DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180;
+ }
+
+ modifiers = intel_fb_plane_get_modifiers(display, INTEL_PLANE_CAP_TILING_X);
+
+ plane = drmm_universal_plane_alloc(display->drm, struct intel_plane, base,
+ 0, plane_funcs,
+ formats, num_formats, modifiers,
+ DRM_PLANE_TYPE_OVERLAY,
+ "sprite %c", sprite_name(display, pipe, sprite));
+ kfree(modifiers);
- plane = intel_plane_alloc();
if (IS_ERR(plane))
return plane;
+ plane->pipe = pipe;
+ plane->id = PLANE_SPRITE0 + sprite;
+ plane->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, plane->id);
+
if (display->platform.valleyview || display->platform.cherryview) {
plane->update_noarm = vlv_sprite_update_noarm;
plane->update_arm = vlv_sprite_update_arm;
@@ -1621,16 +1670,6 @@ intel_sprite_plane_create(struct intel_display *display,
/* FIXME undocumented for VLV/CHV so not sure what's actually needed */
if (intel_scanout_needs_vtd_wa(display))
plane->vtd_guard = 128;
-
- if (display->platform.cherryview && pipe == PIPE_B) {
- formats = chv_pipe_b_sprite_formats;
- num_formats = ARRAY_SIZE(chv_pipe_b_sprite_formats);
- } else {
- formats = vlv_sprite_formats;
- num_formats = ARRAY_SIZE(vlv_sprite_formats);
- }
-
- plane_funcs = &vlv_sprite_funcs;
} else if (DISPLAY_VER(display) >= 7) {
plane->update_noarm = ivb_sprite_update_noarm;
plane->update_arm = ivb_sprite_update_arm;
@@ -1652,11 +1691,6 @@ intel_sprite_plane_create(struct intel_display *display,
if (intel_scanout_needs_vtd_wa(display))
plane->vtd_guard = 64;
-
- formats = snb_sprite_formats;
- num_formats = ARRAY_SIZE(snb_sprite_formats);
-
- plane_funcs = &snb_sprite_funcs;
} else {
plane->update_noarm = g4x_sprite_update_noarm;
plane->update_arm = g4x_sprite_update_arm;
@@ -1671,44 +1705,14 @@ intel_sprite_plane_create(struct intel_display *display,
if (intel_scanout_needs_vtd_wa(display))
plane->vtd_guard = 64;
-
- if (display->platform.sandybridge) {
- formats = snb_sprite_formats;
- num_formats = ARRAY_SIZE(snb_sprite_formats);
-
- plane_funcs = &snb_sprite_funcs;
- } else {
- formats = g4x_sprite_formats;
- num_formats = ARRAY_SIZE(g4x_sprite_formats);
-
- plane_funcs = &g4x_sprite_funcs;
- }
}
- if (display->platform.cherryview && pipe == PIPE_B) {
- supported_rotations =
- DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 |
- DRM_MODE_REFLECT_X;
- } else {
- supported_rotations =
- DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180;
- }
+ plane_state = kzalloc_obj(*plane_state);
+ if (!plane_state)
+ return ERR_PTR(-ENOMEM);
- plane->pipe = pipe;
- plane->id = PLANE_SPRITE0 + sprite;
- plane->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, plane->id);
-
- modifiers = intel_fb_plane_get_modifiers(display, INTEL_PLANE_CAP_TILING_X);
-
- ret = drm_universal_plane_init(display->drm, &plane->base,
- 0, plane_funcs,
- formats, num_formats, modifiers,
- DRM_PLANE_TYPE_OVERLAY,
- "sprite %c", sprite_name(display, pipe, sprite));
- kfree(modifiers);
-
- if (ret)
- goto fail;
+ intel_plane_state_reset(plane_state, plane);
+ plane->base.state = &plane_state->uapi;
drm_plane_create_rotation_property(&plane->base,
DRM_MODE_ROTATE_0,
@@ -1728,9 +1732,4 @@ intel_sprite_plane_create(struct intel_display *display,
intel_plane_helper_add(plane);
return plane;
-
-fail:
- intel_plane_free(plane);
-
- return ERR_PTR(ret);
}
diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c
index 11ba42c67e3ed..6d6b108bf7e46 100644
--- a/drivers/gpu/drm/i915/display/skl_universal_plane.c
+++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c
@@ -7,6 +7,7 @@
#include <drm/drm_blend.h>
#include <drm/drm_damage_helper.h>
#include <drm/drm_fourcc.h>
+#include <drm/drm_managed.h>
#include <drm/drm_print.h>
#include "intel_bo.h"
@@ -2690,7 +2691,6 @@ static bool tgl_plane_format_mod_supported(struct drm_plane *_plane,
static const struct drm_plane_funcs skl_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
- .destroy = intel_plane_destroy,
.atomic_duplicate_state = intel_plane_duplicate_state,
.atomic_destroy_state = intel_plane_destroy_state,
.format_mod_supported = skl_plane_format_mod_supported,
@@ -2700,7 +2700,6 @@ static const struct drm_plane_funcs skl_plane_funcs = {
static const struct drm_plane_funcs icl_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
- .destroy = intel_plane_destroy,
.atomic_duplicate_state = intel_plane_duplicate_state,
.atomic_destroy_state = intel_plane_destroy_state,
.format_mod_supported = icl_plane_format_mod_supported,
@@ -2710,7 +2709,6 @@ static const struct drm_plane_funcs icl_plane_funcs = {
static const struct drm_plane_funcs tgl_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
- .destroy = intel_plane_destroy,
.atomic_duplicate_state = intel_plane_duplicate_state,
.atomic_destroy_state = intel_plane_destroy_state,
.format_mod_supported = tgl_plane_format_mod_supported,
@@ -2850,6 +2848,7 @@ struct intel_plane *
skl_universal_plane_create(struct intel_display *display,
enum pipe pipe, enum plane_id plane_id)
{
+ struct intel_plane_state *plane_state;
const struct drm_plane_funcs *plane_funcs;
struct intel_plane *plane;
enum drm_plane_type plane_type;
@@ -2858,10 +2857,50 @@ skl_universal_plane_create(struct intel_display *display,
const u64 *modifiers;
const u32 *formats;
int num_formats;
- int ret;
u8 caps;
- plane = intel_plane_alloc();
+ if (DISPLAY_VER(display) >= 11)
+ formats = icl_get_plane_formats(display, pipe,
+ plane_id, &num_formats);
+ else if (DISPLAY_VER(display) >= 10)
+ formats = glk_get_plane_formats(display, pipe,
+ plane_id, &num_formats);
+ else
+ formats = skl_get_plane_formats(display, pipe,
+ plane_id, &num_formats);
+
+ if (DISPLAY_VER(display) >= 12)
+ plane_funcs = &tgl_plane_funcs;
+ else if (DISPLAY_VER(display) == 11)
+ plane_funcs = &icl_plane_funcs;
+ else
+ plane_funcs = &skl_plane_funcs;
+
+ if (plane_id == PLANE_1)
+ plane_type = DRM_PLANE_TYPE_PRIMARY;
+ else
+ plane_type = DRM_PLANE_TYPE_OVERLAY;
+
+ if (DISPLAY_VER(display) >= 12)
+ caps = tgl_plane_caps(display, pipe, plane_id);
+ else if (DISPLAY_VER(display) == 11)
+ caps = icl_plane_caps(display, pipe, plane_id);
+ else if (DISPLAY_VER(display) == 10)
+ caps = glk_plane_caps(display, pipe, plane_id);
+ else
+ caps = skl_plane_caps(display, pipe, plane_id);
+
+ modifiers = intel_fb_plane_get_modifiers(display, caps);
+
+ plane = drmm_universal_plane_alloc(display->drm, struct intel_plane, base,
+ 0, plane_funcs,
+ formats, num_formats, modifiers,
+ plane_type,
+ "plane %d%c", plane_id + 1,
+ pipe_name(pipe));
+
+ kfree(modifiers);
+
if (IS_ERR(plane))
return plane;
@@ -2940,50 +2979,12 @@ skl_universal_plane_create(struct intel_display *display,
plane->can_async_flip = skl_plane_can_async_flip;
}
- if (DISPLAY_VER(display) >= 11)
- formats = icl_get_plane_formats(display, pipe,
- plane_id, &num_formats);
- else if (DISPLAY_VER(display) >= 10)
- formats = glk_get_plane_formats(display, pipe,
- plane_id, &num_formats);
- else
- formats = skl_get_plane_formats(display, pipe,
- plane_id, &num_formats);
+ plane_state = kzalloc_obj(*plane_state);
+ if (!plane_state)
+ return ERR_PTR(-ENOMEM);
- if (DISPLAY_VER(display) >= 12)
- plane_funcs = &tgl_plane_funcs;
- else if (DISPLAY_VER(display) == 11)
- plane_funcs = &icl_plane_funcs;
- else
- plane_funcs = &skl_plane_funcs;
-
- if (plane_id == PLANE_1)
- plane_type = DRM_PLANE_TYPE_PRIMARY;
- else
- plane_type = DRM_PLANE_TYPE_OVERLAY;
-
- if (DISPLAY_VER(display) >= 12)
- caps = tgl_plane_caps(display, pipe, plane_id);
- else if (DISPLAY_VER(display) == 11)
- caps = icl_plane_caps(display, pipe, plane_id);
- else if (DISPLAY_VER(display) == 10)
- caps = glk_plane_caps(display, pipe, plane_id);
- else
- caps = skl_plane_caps(display, pipe, plane_id);
-
- modifiers = intel_fb_plane_get_modifiers(display, caps);
-
- ret = drm_universal_plane_init(display->drm, &plane->base,
- 0, plane_funcs,
- formats, num_formats, modifiers,
- plane_type,
- "plane %d%c", plane_id + 1,
- pipe_name(pipe));
-
- kfree(modifiers);
-
- if (ret)
- goto fail;
+ intel_plane_state_reset(plane_state, plane);
+ plane->base.state = &plane_state->uapi;
if (DISPLAY_VER(display) >= 13)
supported_rotations = DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180;
@@ -3033,11 +3034,6 @@ skl_universal_plane_create(struct intel_display *display,
intel_plane_helper_add(plane);
return plane;
-
-fail:
- intel_plane_free(plane);
-
- return ERR_PTR(ret);
}
void
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH RFC 07/12] drm/i915/display: Switch to managed for encoder
2026-04-09 17:08 [PATCH RFC 00/12] Add support for DisplayPort link training information report Kory Maincent
` (5 preceding siblings ...)
2026-04-09 17:08 ` [PATCH RFC 06/12] drm/i915/display: Switch to managed for plane Kory Maincent
@ 2026-04-09 17:08 ` Kory Maincent
2026-04-09 17:08 ` [PATCH RFC 08/12] drm/i915/display: Switch to managed for connector Kory Maincent
` (4 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Kory Maincent @ 2026-04-09 17:08 UTC (permalink / raw)
To: Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
David Airlie, Simona Vetter, Dave Airlie, Jesse Barnes,
Eric Anholt, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Chun-Kuang Hu, Philipp Zabel,
Matthias Brugger, AngeloGioacchino Del Regno, Chris Wilson
Cc: Thomas Petazzoni, Mark Yacoub, Sean Paul, Louis Chauvet,
intel-gfx, intel-xe, dri-devel, linux-kernel, linux-mediatek,
linux-arm-kernel, Simona Vetter, Kory Maincent
The current i915 driver uses non-managed function to create encoder. It
is not an issue yet, but in order to comply with the latest DRM
requirement, convert this code to use drm and device managed helpers.
Assisted-by: Claude Code:2.1.90
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
drivers/gpu/drm/i915/display/g4x_dp.c | 31 ++++++++---------
drivers/gpu/drm/i915/display/g4x_hdmi.c | 19 ++++-------
drivers/gpu/drm/i915/display/icl_dsi.c | 20 +++--------
drivers/gpu/drm/i915/display/intel_crt.c | 9 +++--
drivers/gpu/drm/i915/display/intel_ddi.c | 50 +++++++++++++++-------------
drivers/gpu/drm/i915/display/intel_display.c | 8 -----
drivers/gpu/drm/i915/display/intel_display.h | 1 -
drivers/gpu/drm/i915/display/intel_dp_mst.c | 20 +++--------
drivers/gpu/drm/i915/display/intel_dvo.c | 22 ++++++------
drivers/gpu/drm/i915/display/intel_encoder.c | 6 ++--
drivers/gpu/drm/i915/display/intel_encoder.h | 3 +-
drivers/gpu/drm/i915/display/intel_lvds.c | 13 +++-----
drivers/gpu/drm/i915/display/intel_sdvo.c | 45 +++++++++++--------------
drivers/gpu/drm/i915/display/intel_tv.c | 11 +++---
drivers/gpu/drm/i915/display/vlv_dsi.c | 22 +++++-------
15 files changed, 114 insertions(+), 166 deletions(-)
diff --git a/drivers/gpu/drm/i915/display/g4x_dp.c b/drivers/gpu/drm/i915/display/g4x_dp.c
index 5e74d8a3ba5c8..99b6c5ce39b2a 100644
--- a/drivers/gpu/drm/i915/display/g4x_dp.c
+++ b/drivers/gpu/drm/i915/display/g4x_dp.c
@@ -7,6 +7,7 @@
#include <linux/string_helpers.h>
+#include <drm/drm_managed.h>
#include <drm/drm_print.h>
#include "g4x_dp.h"
@@ -1250,12 +1251,9 @@ static void g4x_dp_suspend_complete(struct intel_encoder *encoder)
intel_encoder_link_check_flush_work(encoder);
}
-static void intel_dp_encoder_destroy(struct drm_encoder *encoder)
+static void intel_dp_encoder_flush_work_cleanup(struct drm_device *drm, void *data)
{
- intel_dp_encoder_flush_work(encoder);
-
- drm_encoder_cleanup(encoder);
- kfree(enc_to_dig_port(to_intel_encoder(encoder)));
+ intel_dp_encoder_flush_work(data);
}
static void intel_dp_encoder_reset(struct drm_encoder *encoder)
@@ -1276,7 +1274,6 @@ static void intel_dp_encoder_reset(struct drm_encoder *encoder)
static const struct drm_encoder_funcs intel_dp_enc_funcs = {
.reset = intel_dp_encoder_reset,
- .destroy = intel_dp_encoder_destroy,
};
bool g4x_dp_init(struct intel_display *display,
@@ -1298,22 +1295,26 @@ bool g4x_dp_init(struct intel_display *display,
drm_dbg_kms(display->drm, "No VBT child device for DP-%c\n",
port_name(port));
- dig_port = intel_dig_port_alloc();
+ dig_port = intel_dig_port_alloc(display->drm);
if (!dig_port)
return false;
intel_connector = intel_connector_alloc();
if (!intel_connector)
- goto err_connector_alloc;
+ return false;
intel_encoder = &dig_port->base;
encoder = &intel_encoder->base;
intel_encoder->devdata = devdata;
- if (drm_encoder_init(display->drm, &intel_encoder->base,
- &intel_dp_enc_funcs, DRM_MODE_ENCODER_TMDS,
- "DP %c", port_name(port)))
+ if (drmm_encoder_init(display->drm, &intel_encoder->base,
+ &intel_dp_enc_funcs, DRM_MODE_ENCODER_TMDS,
+ "DP %c", port_name(port)))
+ goto err_encoder_init;
+
+ if (drmm_add_action_or_reset(display->drm,
+ intel_dp_encoder_flush_work_cleanup, encoder))
goto err_encoder_init;
intel_encoder_link_check_init(intel_encoder, intel_dp_link_check);
@@ -1411,18 +1412,14 @@ bool g4x_dp_init(struct intel_display *display,
dig_port->aux_ch = intel_dp_aux_ch(intel_encoder);
if (dig_port->aux_ch == AUX_CH_NONE)
- goto err_init_connector;
+ goto err_encoder_init;
if (!intel_dp_init_connector(dig_port, intel_connector))
- goto err_init_connector;
+ goto err_encoder_init;
return true;
-err_init_connector:
- drm_encoder_cleanup(encoder);
err_encoder_init:
kfree(intel_connector);
-err_connector_alloc:
- kfree(dig_port);
return false;
}
diff --git a/drivers/gpu/drm/i915/display/g4x_hdmi.c b/drivers/gpu/drm/i915/display/g4x_hdmi.c
index 5fe5067c4237c..45ee1ad504bc1 100644
--- a/drivers/gpu/drm/i915/display/g4x_hdmi.c
+++ b/drivers/gpu/drm/i915/display/g4x_hdmi.c
@@ -5,6 +5,7 @@
* HDMI support for G4x,ILK,SNB,IVB,VLV,CHV (HSW+ handled by the DDI code).
*/
+#include <drm/drm_managed.h>
#include <drm/drm_print.h>
#include "g4x_hdmi.h"
@@ -562,7 +563,6 @@ static void chv_hdmi_pre_enable(struct intel_atomic_state *state,
}
static const struct drm_encoder_funcs intel_hdmi_enc_funcs = {
- .destroy = intel_encoder_destroy,
};
static enum intel_hotplug_state
@@ -686,21 +686,21 @@ bool g4x_hdmi_init(struct intel_display *display,
drm_dbg_kms(display->drm, "No VBT child device for HDMI-%c\n",
port_name(port));
- dig_port = intel_dig_port_alloc();
+ dig_port = intel_dig_port_alloc(display->drm);
if (!dig_port)
return false;
intel_connector = intel_connector_alloc();
if (!intel_connector)
- goto err_connector_alloc;
+ return false;
intel_encoder = &dig_port->base;
intel_encoder->devdata = devdata;
- if (drm_encoder_init(display->drm, &intel_encoder->base,
- &intel_hdmi_enc_funcs, DRM_MODE_ENCODER_TMDS,
- "HDMI %c", port_name(port)))
+ if (drmm_encoder_init(display->drm, &intel_encoder->base,
+ &intel_hdmi_enc_funcs, DRM_MODE_ENCODER_TMDS,
+ "HDMI %c", port_name(port)))
goto err_encoder_init;
intel_encoder->hotplug = intel_hdmi_hotplug;
@@ -763,16 +763,11 @@ bool g4x_hdmi_init(struct intel_display *display,
intel_infoframe_init(dig_port);
if (!intel_hdmi_init_connector(dig_port, intel_connector))
- goto err_init_connector;
+ goto err_encoder_init;
return true;
-
-err_init_connector:
- drm_encoder_cleanup(&intel_encoder->base);
err_encoder_init:
kfree(intel_connector);
-err_connector_alloc:
- kfree(dig_port);
return false;
}
diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c
index afbaa0465842a..cfee173a2367a 100644
--- a/drivers/gpu/drm/i915/display/icl_dsi.c
+++ b/drivers/gpu/drm/i915/display/icl_dsi.c
@@ -30,6 +30,7 @@
#include <drm/display/drm_dsc_helper.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_fixed.h>
+#include <drm/drm_managed.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
@@ -1775,13 +1776,7 @@ static bool gen11_dsi_initial_fastset_check(struct intel_encoder *encoder,
return true;
}
-static void gen11_dsi_encoder_destroy(struct drm_encoder *encoder)
-{
- intel_encoder_destroy(encoder);
-}
-
static const struct drm_encoder_funcs gen11_dsi_encoder_funcs = {
- .destroy = gen11_dsi_encoder_destroy,
};
static const struct drm_connector_funcs gen11_dsi_connector_funcs = {
@@ -1934,8 +1929,10 @@ void icl_dsi_init(struct intel_display *display,
if (port == PORT_NONE)
return;
- intel_dsi = kzalloc_obj(*intel_dsi);
- if (!intel_dsi)
+ intel_dsi = drmm_encoder_alloc(display->drm, struct intel_dsi, base.base,
+ &gen11_dsi_encoder_funcs,
+ DRM_MODE_ENCODER_DSI, "DSI %c", port_name(port));
+ if (IS_ERR(intel_dsi))
return;
intel_connector = intel_connector_alloc();
@@ -1950,11 +1947,6 @@ void icl_dsi_init(struct intel_display *display,
encoder->devdata = devdata;
- /* register DSI encoder with DRM subsystem */
- drm_encoder_init(display->drm, &encoder->base,
- &gen11_dsi_encoder_funcs,
- DRM_MODE_ENCODER_DSI, "DSI %c", port_name(port));
-
encoder->pre_pll_enable = gen11_dsi_pre_pll_enable;
encoder->pre_enable = gen11_dsi_pre_enable;
encoder->enable = gen11_dsi_enable;
@@ -2037,7 +2029,5 @@ void icl_dsi_init(struct intel_display *display,
err:
drm_connector_cleanup(connector);
- drm_encoder_cleanup(&encoder->base);
- kfree(intel_dsi);
kfree(intel_connector);
}
diff --git a/drivers/gpu/drm/i915/display/intel_crt.c b/drivers/gpu/drm/i915/display/intel_crt.c
index 6aa6a1dd6e1b0..39bb115955f5a 100644
--- a/drivers/gpu/drm/i915/display/intel_crt.c
+++ b/drivers/gpu/drm/i915/display/intel_crt.c
@@ -31,6 +31,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
#include <drm/drm_edid.h>
+#include <drm/drm_managed.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <video/vga.h>
@@ -1004,7 +1005,6 @@ static const struct drm_connector_helper_funcs intel_crt_connector_helper_funcs
static const struct drm_encoder_funcs intel_crt_enc_funcs = {
.reset = intel_crt_reset,
- .destroy = intel_encoder_destroy,
};
void intel_crt_init(struct intel_display *display)
@@ -1041,8 +1041,9 @@ void intel_crt_init(struct intel_display *display)
intel_de_write(display, adpa_reg, adpa);
}
- crt = kzalloc_obj(struct intel_crt);
- if (!crt)
+ crt = drmm_encoder_alloc(display->drm, struct intel_crt, base.base,
+ &intel_crt_enc_funcs, DRM_MODE_ENCODER_DAC, "CRT");
+ if (IS_ERR(crt))
return;
connector = intel_connector_alloc();
@@ -1058,8 +1059,6 @@ void intel_crt_init(struct intel_display *display)
DRM_MODE_CONNECTOR_VGA,
intel_gmbus_get_adapter(display, ddc_pin));
- drm_encoder_init(display->drm, &crt->base.base, &intel_crt_enc_funcs,
- DRM_MODE_ENCODER_DAC, "CRT");
intel_connector_attach_encoder(connector, &crt->base);
diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
index ebefa889bc8c5..003287ad5bc59 100644
--- a/drivers/gpu/drm/i915/display/intel_ddi.c
+++ b/drivers/gpu/drm/i915/display/intel_ddi.c
@@ -31,6 +31,7 @@
#include <drm/display/drm_dp_helper.h>
#include <drm/display/drm_scdc_helper.h>
+#include <drm/drm_managed.h>
#include <drm/drm_print.h>
#include <drm/drm_privacy_screen_consumer.h>
@@ -4644,19 +4645,19 @@ static int intel_ddi_compute_config_late(struct intel_encoder *encoder,
return 0;
}
-static void intel_ddi_encoder_destroy(struct drm_encoder *encoder)
+static void intel_ddi_encoder_cleanup(struct drm_device *drm, void *data)
{
- struct intel_display *display = to_intel_display(encoder->dev);
- struct intel_digital_port *dig_port = enc_to_dig_port(to_intel_encoder(encoder));
+ struct intel_digital_port *dig_port = data;
+ struct intel_display *display = to_intel_display(&dig_port->base);
- intel_dp_encoder_flush_work(encoder);
- if (intel_encoder_is_tc(&dig_port->base))
- intel_tc_port_cleanup(dig_port);
+ intel_dp_encoder_flush_work(&dig_port->base.base);
intel_display_power_flush_work(display);
-
- drm_encoder_cleanup(encoder);
kfree(dig_port->hdcp.port_data.streams);
- kfree(dig_port);
+}
+
+static void intel_tc_port_cleanup_action(struct drm_device *drm, void *data)
+{
+ intel_tc_port_cleanup(data);
}
static void intel_ddi_encoder_reset(struct drm_encoder *encoder)
@@ -4684,7 +4685,6 @@ static int intel_ddi_encoder_late_register(struct drm_encoder *_encoder)
static const struct drm_encoder_funcs intel_ddi_funcs = {
.reset = intel_ddi_encoder_reset,
- .destroy = intel_ddi_encoder_destroy,
.late_register = intel_ddi_encoder_late_register,
};
@@ -5243,16 +5243,20 @@ void intel_ddi_init(struct intel_display *display,
phy_name(phy));
}
- dig_port = intel_dig_port_alloc();
+ dig_port = intel_dig_port_alloc(display->drm);
if (!dig_port)
return;
encoder = &dig_port->base;
encoder->devdata = devdata;
- drm_encoder_init(display->drm, &encoder->base, &intel_ddi_funcs,
- DRM_MODE_ENCODER_TMDS, "%s",
- intel_ddi_encoder_name(display, port, phy, &encoder_name));
+ if (drmm_encoder_init(display->drm, &encoder->base, &intel_ddi_funcs,
+ DRM_MODE_ENCODER_TMDS, "%s",
+ intel_ddi_encoder_name(display, port, phy, &encoder_name)))
+ return;
+
+ if (drmm_add_action_or_reset(display->drm, intel_ddi_encoder_cleanup, dig_port))
+ return;
intel_encoder_link_check_init(encoder, intel_ddi_link_check);
@@ -5411,7 +5415,7 @@ void intel_ddi_init(struct intel_display *display,
if (need_aux_ch(encoder, init_dp)) {
dig_port->aux_ch = intel_dp_aux_ch(encoder);
if (dig_port->aux_ch == AUX_CH_NONE)
- goto err;
+ return;
}
/*
@@ -5447,7 +5451,11 @@ void intel_ddi_init(struct intel_display *display,
dig_port->unlock = intel_tc_port_unlock;
if (intel_tc_port_init(dig_port, is_legacy) < 0)
- goto err;
+ return;
+
+ if (drmm_add_action_or_reset(display->drm,
+ intel_tc_port_cleanup_action, dig_port))
+ return;
}
drm_WARN_ON(display->drm, port > PORT_I);
@@ -5478,7 +5486,7 @@ void intel_ddi_init(struct intel_display *display,
if (init_dp) {
if (intel_ddi_init_dp_connector(dig_port))
- goto err;
+ return;
dig_port->hpd_pulse = intel_dp_hpd_pulse;
@@ -5492,12 +5500,6 @@ void intel_ddi_init(struct intel_display *display,
*/
if (encoder->type != INTEL_OUTPUT_EDP && init_hdmi) {
if (intel_ddi_init_hdmi_connector(dig_port))
- goto err;
+ return;
}
-
- return;
-
-err:
- drm_encoder_cleanup(&encoder->base);
- kfree(dig_port);
}
diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
index 10b6c6fcb03f6..049a796da4c38 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -2192,14 +2192,6 @@ static void i9xx_crtc_disable(struct intel_atomic_state *state,
i830_enable_pipe(display, pipe);
}
-void intel_encoder_destroy(struct drm_encoder *encoder)
-{
- struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
-
- drm_encoder_cleanup(encoder);
- kfree(intel_encoder);
-}
-
static bool intel_crtc_supports_double_wide(const struct intel_crtc *crtc)
{
struct intel_display *display = to_intel_display(crtc);
diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h
index 552a59d19e0f6..6c2681738e6b2 100644
--- a/drivers/gpu/drm/i915/display/intel_display.h
+++ b/drivers/gpu/drm/i915/display/intel_display.h
@@ -416,7 +416,6 @@ void intel_disable_transcoder(const struct intel_crtc_state *old_crtc_state);
void i830_enable_pipe(struct intel_display *display, enum pipe pipe);
void i830_disable_pipe(struct intel_display *display, enum pipe pipe);
bool intel_has_pending_fb_unpin(struct intel_display *display);
-void intel_encoder_destroy(struct drm_encoder *encoder);
struct drm_display_mode *
intel_encoder_current_mode(struct intel_encoder *encoder);
void intel_encoder_get_config(struct intel_encoder *encoder,
diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c
index 887b6de14e467..5fe6fbcaf9371 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_mst.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c
@@ -30,6 +30,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_fixed.h>
+#include <drm/drm_managed.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
@@ -1645,16 +1646,7 @@ static const struct drm_connector_helper_funcs mst_connector_helper_funcs = {
.detect_ctx = mst_connector_detect_ctx,
};
-static void mst_stream_encoder_destroy(struct drm_encoder *encoder)
-{
- struct intel_dp_mst_encoder *intel_mst = enc_to_mst(to_intel_encoder(encoder));
-
- drm_encoder_cleanup(encoder);
- kfree(intel_mst);
-}
-
static const struct drm_encoder_funcs mst_stream_encoder_funcs = {
- .destroy = mst_stream_encoder_destroy,
};
static bool mst_connector_get_hw_state(struct intel_connector *connector)
@@ -1850,18 +1842,16 @@ mst_stream_encoder_create(struct intel_digital_port *dig_port, enum pipe pipe)
struct intel_dp_mst_encoder *intel_mst;
struct intel_encoder *encoder;
- intel_mst = kzalloc_obj(*intel_mst);
-
- if (!intel_mst)
+ intel_mst = drmm_encoder_alloc(display->drm, struct intel_dp_mst_encoder,
+ base.base, &mst_stream_encoder_funcs,
+ DRM_MODE_ENCODER_DPMST, "DP-MST %c", pipe_name(pipe));
+ if (IS_ERR(intel_mst))
return NULL;
intel_mst->pipe = pipe;
encoder = &intel_mst->base;
intel_mst->primary = dig_port;
- drm_encoder_init(display->drm, &encoder->base, &mst_stream_encoder_funcs,
- DRM_MODE_ENCODER_DPMST, "DP-MST %c", pipe_name(pipe));
-
encoder->type = INTEL_OUTPUT_DP_MST;
encoder->power_domain = primary_encoder->power_domain;
encoder->port = primary_encoder->port;
diff --git a/drivers/gpu/drm/i915/display/intel_dvo.c b/drivers/gpu/drm/i915/display/intel_dvo.c
index 405b33aca9dde..ea2f6426fd77d 100644
--- a/drivers/gpu/drm/i915/display/intel_dvo.c
+++ b/drivers/gpu/drm/i915/display/intel_dvo.c
@@ -31,6 +31,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
#include <drm/drm_edid.h>
+#include <drm/drm_managed.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
@@ -372,18 +373,15 @@ static const struct drm_connector_helper_funcs intel_dvo_connector_helper_funcs
.get_modes = intel_dvo_get_modes,
};
-static void intel_dvo_enc_destroy(struct drm_encoder *encoder)
+static void intel_dvo_dev_destroy(struct drm_device *drm, void *data)
{
- struct intel_dvo *intel_dvo = enc_to_dvo(to_intel_encoder(encoder));
+ struct intel_dvo *intel_dvo = data;
if (intel_dvo->dev.dev_ops->destroy)
intel_dvo->dev.dev_ops->destroy(&intel_dvo->dev);
-
- intel_encoder_destroy(encoder);
}
static const struct drm_encoder_funcs intel_dvo_enc_funcs = {
- .destroy = intel_dvo_enc_destroy,
};
static int intel_dvo_encoder_type(const struct intel_dvo_device *dvo)
@@ -494,7 +492,7 @@ void intel_dvo_init(struct intel_display *display)
struct intel_encoder *encoder;
struct intel_dvo *intel_dvo;
- intel_dvo = kzalloc_obj(*intel_dvo);
+ intel_dvo = drmm_kzalloc(display->drm, sizeof(*intel_dvo), GFP_KERNEL);
if (!intel_dvo)
return;
@@ -517,13 +515,15 @@ void intel_dvo_init(struct intel_display *display)
connector->get_hw_state = intel_dvo_connector_get_hw_state;
if (!intel_dvo_probe(display, intel_dvo)) {
- kfree(intel_dvo);
intel_connector_free(connector);
return;
}
assert_port_valid(display, intel_dvo->dev.port);
+ if (drmm_add_action_or_reset(display->drm, intel_dvo_dev_destroy, intel_dvo))
+ return;
+
encoder->type = INTEL_OUTPUT_DVO;
encoder->power_domain = POWER_DOMAIN_PORT_OTHER;
encoder->port = intel_dvo->dev.port;
@@ -533,10 +533,10 @@ void intel_dvo_init(struct intel_display *display)
encoder->cloneable = BIT(INTEL_OUTPUT_ANALOG) |
BIT(INTEL_OUTPUT_DVO);
- drm_encoder_init(display->drm, &encoder->base,
- &intel_dvo_enc_funcs,
- intel_dvo_encoder_type(&intel_dvo->dev),
- "DVO %c", port_name(encoder->port));
+ drmm_encoder_init(display->drm, &encoder->base,
+ &intel_dvo_enc_funcs,
+ intel_dvo_encoder_type(&intel_dvo->dev),
+ "DVO %c", port_name(encoder->port));
drm_dbg_kms(display->drm, "[ENCODER:%d:%s] detected %s\n",
encoder->base.base.id, encoder->base.name,
diff --git a/drivers/gpu/drm/i915/display/intel_encoder.c b/drivers/gpu/drm/i915/display/intel_encoder.c
index d01b081a60740..2ebd1e4457482 100644
--- a/drivers/gpu/drm/i915/display/intel_encoder.c
+++ b/drivers/gpu/drm/i915/display/intel_encoder.c
@@ -5,6 +5,8 @@
#include <linux/workqueue.h>
+#include <drm/drm_managed.h>
+
#include "intel_display_core.h"
#include "intel_display_types.h"
#include "intel_encoder.h"
@@ -104,11 +106,11 @@ void intel_encoder_shutdown_all(struct intel_display *display)
encoder->shutdown_complete(encoder);
}
-struct intel_digital_port *intel_dig_port_alloc(void)
+struct intel_digital_port *intel_dig_port_alloc(struct drm_device *drm)
{
struct intel_digital_port *dig_port;
- dig_port = kzalloc_obj(*dig_port);
+ dig_port = drmm_kzalloc(drm, sizeof(*dig_port), GFP_KERNEL);
if (!dig_port)
return NULL;
diff --git a/drivers/gpu/drm/i915/display/intel_encoder.h b/drivers/gpu/drm/i915/display/intel_encoder.h
index ace0fe1a8f27a..42f3982970065 100644
--- a/drivers/gpu/drm/i915/display/intel_encoder.h
+++ b/drivers/gpu/drm/i915/display/intel_encoder.h
@@ -6,6 +6,7 @@
#ifndef __INTEL_ENCODER_H__
#define __INTEL_ENCODER_H__
+struct drm_device;
struct intel_digital_port;
struct intel_display;
struct intel_encoder;
@@ -21,6 +22,6 @@ void intel_encoder_shutdown_all(struct intel_display *display);
void intel_encoder_block_all_hpds(struct intel_display *display);
void intel_encoder_unblock_all_hpds(struct intel_display *display);
-struct intel_digital_port *intel_dig_port_alloc(void);
+struct intel_digital_port *intel_dig_port_alloc(struct drm_device *drm);
#endif /* __INTEL_ENCODER_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_lvds.c b/drivers/gpu/drm/i915/display/intel_lvds.c
index e78a41e2b268c..7bb99eb44a5a4 100644
--- a/drivers/gpu/drm/i915/display/intel_lvds.c
+++ b/drivers/gpu/drm/i915/display/intel_lvds.c
@@ -37,6 +37,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
#include <drm/drm_edid.h>
+#include <drm/drm_managed.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
@@ -517,7 +518,6 @@ static const struct drm_connector_funcs intel_lvds_connector_funcs = {
};
static const struct drm_encoder_funcs intel_lvds_enc_funcs = {
- .destroy = intel_encoder_destroy,
};
static int intel_no_lvds_dmi_callback(const struct dmi_system_id *id)
@@ -886,15 +886,14 @@ void intel_lvds_init(struct intel_display *display)
"LVDS is not present in VBT, but enabled anyway\n");
}
- lvds_encoder = kzalloc_obj(*lvds_encoder);
- if (!lvds_encoder)
+ lvds_encoder = drmm_encoder_alloc(display->drm, struct intel_lvds_encoder, base.base,
+ &intel_lvds_enc_funcs, DRM_MODE_ENCODER_LVDS, "LVDS");
+ if (IS_ERR(lvds_encoder))
return;
connector = intel_connector_alloc();
- if (!connector) {
- kfree(lvds_encoder);
+ if (!connector)
return;
- }
lvds_encoder->attached_connector = connector;
encoder = &lvds_encoder->base;
@@ -904,8 +903,6 @@ void intel_lvds_init(struct intel_display *display)
DRM_MODE_CONNECTOR_LVDS,
intel_gmbus_get_adapter(display, ddc_pin));
- drm_encoder_init(display->drm, &encoder->base, &intel_lvds_enc_funcs,
- DRM_MODE_ENCODER_LVDS, "LVDS");
encoder->enable = intel_enable_lvds;
encoder->pre_enable = intel_pre_enable_lvds;
diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c
index 6eb2b4b45a9b4..f5aaa38002674 100644
--- a/drivers/gpu/drm/i915/display/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/display/intel_sdvo.c
@@ -36,6 +36,7 @@
#include <drm/drm_crtc.h>
#include <drm/drm_edid.h>
#include <drm/drm_eld.h>
+#include <drm/drm_managed.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
@@ -2542,24 +2543,19 @@ static const struct drm_connector_helper_funcs intel_sdvo_connector_helper_funcs
.atomic_check = intel_sdvo_atomic_check,
};
-static void intel_sdvo_encoder_destroy(struct drm_encoder *_encoder)
+static void intel_sdvo_unselect_i2c_bus(struct intel_sdvo *sdvo);
+
+static void intel_sdvo_cleanup(struct drm_device *drm, void *data)
{
- struct intel_encoder *encoder = to_intel_encoder(_encoder);
- struct intel_sdvo *sdvo = to_sdvo(encoder);
+ struct intel_sdvo *intel_sdvo = data;
int i;
- for (i = 0; i < ARRAY_SIZE(sdvo->ddc); i++) {
- if (sdvo->ddc[i].ddc_bus)
- i2c_del_adapter(&sdvo->ddc[i].ddc);
+ for (i = 0; i < ARRAY_SIZE(intel_sdvo->ddc); i++) {
+ if (intel_sdvo->ddc[i].ddc_bus)
+ i2c_del_adapter(&intel_sdvo->ddc[i].ddc);
}
-
- drm_encoder_cleanup(&encoder->base);
- kfree(sdvo);
-};
-
-static const struct drm_encoder_funcs intel_sdvo_enc_funcs = {
- .destroy = intel_sdvo_encoder_destroy,
-};
+ intel_sdvo_unselect_i2c_bus(intel_sdvo);
+}
static int
intel_sdvo_guess_ddc_bus(struct intel_sdvo *sdvo,
@@ -3381,8 +3377,9 @@ bool intel_sdvo_init(struct intel_display *display,
if (!assert_sdvo_port_valid(display, port))
return false;
- intel_sdvo = kzalloc_obj(*intel_sdvo);
- if (!intel_sdvo)
+ intel_sdvo = drmm_encoder_alloc(display->drm, struct intel_sdvo, base.base,
+ NULL, 0, "SDVO %c", port_name(port));
+ if (IS_ERR(intel_sdvo))
return false;
/* encoder type will be decided later */
@@ -3391,15 +3388,14 @@ bool intel_sdvo_init(struct intel_display *display,
intel_encoder->power_domain = POWER_DOMAIN_PORT_OTHER;
intel_encoder->port = port;
- drm_encoder_init(display->drm, &intel_encoder->base,
- &intel_sdvo_enc_funcs, 0,
- "SDVO %c", port_name(port));
-
intel_sdvo->sdvo_reg = sdvo_reg;
intel_sdvo->target_addr = intel_sdvo_get_target_addr(intel_sdvo) >> 1;
intel_sdvo_select_i2c_bus(intel_sdvo);
+ if (drmm_add_action_or_reset(display->drm, intel_sdvo_cleanup, intel_sdvo))
+ return false;
+
/* Read the regs to test if we can talk to the device */
for (i = 0; i < 0x40; i++) {
u8 byte;
@@ -3408,7 +3404,7 @@ bool intel_sdvo_init(struct intel_display *display,
drm_dbg_kms(display->drm,
"No SDVO device found on %s\n",
SDVO_NAME(intel_sdvo));
- goto err;
+ return false;
}
}
@@ -3428,7 +3424,7 @@ bool intel_sdvo_init(struct intel_display *display,
/* In default case sdvo lvds is false */
if (!intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps))
- goto err;
+ return false;
intel_sdvo->colorimetry_cap =
intel_sdvo_get_colorimetry_cap(intel_sdvo);
@@ -3439,7 +3435,7 @@ bool intel_sdvo_init(struct intel_display *display,
ret = intel_sdvo_init_ddc_proxy(&intel_sdvo->ddc[i],
intel_sdvo, i + 1);
if (ret)
- goto err;
+ return false;
}
if (!intel_sdvo_output_setup(intel_sdvo)) {
@@ -3502,9 +3498,6 @@ bool intel_sdvo_init(struct intel_display *display,
err_output:
intel_sdvo_output_cleanup(intel_sdvo);
-err:
- intel_sdvo_unselect_i2c_bus(intel_sdvo);
- intel_sdvo_encoder_destroy(&intel_encoder->base);
return false;
}
diff --git a/drivers/gpu/drm/i915/display/intel_tv.c b/drivers/gpu/drm/i915/display/intel_tv.c
index 8fbf0adb56992..05df0acc6dc3e 100644
--- a/drivers/gpu/drm/i915/display/intel_tv.c
+++ b/drivers/gpu/drm/i915/display/intel_tv.c
@@ -33,6 +33,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
#include <drm/drm_edid.h>
+#include <drm/drm_managed.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
@@ -1881,7 +1882,6 @@ static const struct drm_connector_helper_funcs intel_tv_connector_helper_funcs =
};
static const struct drm_encoder_funcs intel_tv_enc_funcs = {
- .destroy = intel_encoder_destroy,
};
static void intel_tv_add_properties(struct drm_connector *connector)
@@ -1966,10 +1966,10 @@ intel_tv_init(struct intel_display *display)
(tv_dac_off & TVDAC_STATE_CHG_EN) != 0)
return;
- intel_tv = kzalloc_obj(*intel_tv);
- if (!intel_tv) {
+ intel_tv = drmm_encoder_alloc(display->drm, struct intel_tv, base.base,
+ &intel_tv_enc_funcs, DRM_MODE_ENCODER_TVDAC, "TV");
+ if (IS_ERR(intel_tv))
return;
- }
intel_connector = intel_connector_alloc();
if (!intel_connector) {
@@ -1996,9 +1996,6 @@ intel_tv_init(struct intel_display *display)
drm_connector_init(display->drm, connector, &intel_tv_connector_funcs,
DRM_MODE_CONNECTOR_SVIDEO);
- drm_encoder_init(display->drm, &intel_encoder->base,
- &intel_tv_enc_funcs,
- DRM_MODE_ENCODER_TVDAC, "TV");
intel_encoder->compute_config = intel_tv_compute_config;
intel_encoder->get_config = intel_tv_get_config;
diff --git a/drivers/gpu/drm/i915/display/vlv_dsi.c b/drivers/gpu/drm/i915/display/vlv_dsi.c
index d4db73c184e5c..e84edb6242716 100644
--- a/drivers/gpu/drm/i915/display/vlv_dsi.c
+++ b/drivers/gpu/drm/i915/display/vlv_dsi.c
@@ -30,6 +30,7 @@
#include <drm/drm_crtc.h>
#include <drm/drm_edid.h>
#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_managed.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
@@ -1531,7 +1532,6 @@ static void intel_dsi_unprepare(struct intel_encoder *encoder)
}
static const struct drm_encoder_funcs intel_dsi_funcs = {
- .destroy = intel_encoder_destroy,
};
static enum drm_mode_status vlv_dsi_mode_valid(struct drm_connector *connector,
@@ -1918,22 +1918,19 @@ void vlv_dsi_init(struct intel_display *display)
else
display->dsi.mmio_base = VLV_MIPI_BASE;
- intel_dsi = kzalloc_obj(*intel_dsi);
- if (!intel_dsi)
+ intel_dsi = drmm_encoder_alloc(display->drm, struct intel_dsi, base.base,
+ &intel_dsi_funcs, DRM_MODE_ENCODER_DSI,
+ "DSI %c", port_name(port));
+ if (IS_ERR(intel_dsi))
return;
connector = intel_connector_alloc();
- if (!connector) {
- kfree(intel_dsi);
+ if (!connector)
return;
- }
encoder = &intel_dsi->base;
intel_dsi->attached_connector = connector;
- drm_encoder_init(display->drm, &encoder->base, &intel_dsi_funcs,
- DRM_MODE_ENCODER_DSI, "DSI %c", port_name(port));
-
encoder->compute_config = intel_dsi_compute_config;
encoder->pre_enable = intel_dsi_pre_enable;
if (display->platform.geminilake || display->platform.broxton)
@@ -1985,14 +1982,14 @@ void vlv_dsi_init(struct intel_display *display)
host = intel_dsi_host_init(intel_dsi, &intel_dsi_host_ops,
port);
if (!host)
- goto err;
+ return;
intel_dsi->dsi_hosts[port] = host;
}
if (!intel_dsi_vbt_init(intel_dsi, MIPI_DSI_GENERIC_PANEL_ID)) {
drm_dbg_kms(display->drm, "no device found\n");
- goto err;
+ return;
}
/* Use clock read-back from current hw-state for fastboot */
@@ -2050,8 +2047,5 @@ void vlv_dsi_init(struct intel_display *display)
err_cleanup_connector:
drm_connector_cleanup(&connector->base);
-err:
- drm_encoder_cleanup(&encoder->base);
- kfree(intel_dsi);
kfree(connector);
}
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH RFC 08/12] drm/i915/display: Switch to managed for connector
2026-04-09 17:08 [PATCH RFC 00/12] Add support for DisplayPort link training information report Kory Maincent
` (6 preceding siblings ...)
2026-04-09 17:08 ` [PATCH RFC 07/12] drm/i915/display: Switch to managed for encoder Kory Maincent
@ 2026-04-09 17:08 ` Kory Maincent
2026-04-09 17:08 ` [PATCH RFC 09/12] drm: Introduce drmm_connector_dp_init() with link training state properties Kory Maincent
` (3 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Kory Maincent @ 2026-04-09 17:08 UTC (permalink / raw)
To: Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
David Airlie, Simona Vetter, Dave Airlie, Jesse Barnes,
Eric Anholt, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Chun-Kuang Hu, Philipp Zabel,
Matthias Brugger, AngeloGioacchino Del Regno, Chris Wilson
Cc: Thomas Petazzoni, Mark Yacoub, Sean Paul, Louis Chauvet,
intel-gfx, intel-xe, dri-devel, linux-kernel, linux-mediatek,
linux-arm-kernel, Simona Vetter, Kory Maincent
The current i915 driver uses non-managed function to create connector. It
is not an issue yet, but in order to comply with the latest DRM
requirement, convert this code to use drm and device managed helpers.
Assisted-by: Claude Code:2.1.90
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
drivers/gpu/drm/i915/display/g4x_dp.c | 14 ++---
drivers/gpu/drm/i915/display/g4x_hdmi.c | 10 ++--
drivers/gpu/drm/i915/display/icl_dsi.c | 30 +++++------
drivers/gpu/drm/i915/display/intel_connector.c | 26 ++++++---
drivers/gpu/drm/i915/display/intel_connector.h | 5 +-
drivers/gpu/drm/i915/display/intel_crt.c | 19 +++----
drivers/gpu/drm/i915/display/intel_ddi.c | 14 +++--
drivers/gpu/drm/i915/display/intel_dp.c | 12 +++--
drivers/gpu/drm/i915/display/intel_dp_mst.c | 13 ++++-
drivers/gpu/drm/i915/display/intel_dvo.c | 21 ++++----
drivers/gpu/drm/i915/display/intel_hdmi.c | 15 ++++--
drivers/gpu/drm/i915/display/intel_lvds.c | 18 ++++---
drivers/gpu/drm/i915/display/intel_sdvo.c | 73 +++++++++-----------------
drivers/gpu/drm/i915/display/intel_tv.c | 15 +++---
drivers/gpu/drm/i915/display/vlv_dsi.c | 20 ++++---
15 files changed, 153 insertions(+), 152 deletions(-)
diff --git a/drivers/gpu/drm/i915/display/g4x_dp.c b/drivers/gpu/drm/i915/display/g4x_dp.c
index 99b6c5ce39b2a..e7c3d72d223ee 100644
--- a/drivers/gpu/drm/i915/display/g4x_dp.c
+++ b/drivers/gpu/drm/i915/display/g4x_dp.c
@@ -1299,7 +1299,7 @@ bool g4x_dp_init(struct intel_display *display,
if (!dig_port)
return false;
- intel_connector = intel_connector_alloc();
+ intel_connector = intel_connector_alloc(display->drm);
if (!intel_connector)
return false;
@@ -1311,11 +1311,11 @@ bool g4x_dp_init(struct intel_display *display,
if (drmm_encoder_init(display->drm, &intel_encoder->base,
&intel_dp_enc_funcs, DRM_MODE_ENCODER_TMDS,
"DP %c", port_name(port)))
- goto err_encoder_init;
+ return false;
if (drmm_add_action_or_reset(display->drm,
intel_dp_encoder_flush_work_cleanup, encoder))
- goto err_encoder_init;
+ return false;
intel_encoder_link_check_init(intel_encoder, intel_dp_link_check);
@@ -1412,14 +1412,10 @@ bool g4x_dp_init(struct intel_display *display,
dig_port->aux_ch = intel_dp_aux_ch(intel_encoder);
if (dig_port->aux_ch == AUX_CH_NONE)
- goto err_encoder_init;
+ return false;
if (!intel_dp_init_connector(dig_port, intel_connector))
- goto err_encoder_init;
+ return false;
return true;
-
-err_encoder_init:
- kfree(intel_connector);
- return false;
}
diff --git a/drivers/gpu/drm/i915/display/g4x_hdmi.c b/drivers/gpu/drm/i915/display/g4x_hdmi.c
index 45ee1ad504bc1..ab964194e63d0 100644
--- a/drivers/gpu/drm/i915/display/g4x_hdmi.c
+++ b/drivers/gpu/drm/i915/display/g4x_hdmi.c
@@ -690,7 +690,7 @@ bool g4x_hdmi_init(struct intel_display *display,
if (!dig_port)
return false;
- intel_connector = intel_connector_alloc();
+ intel_connector = intel_connector_alloc(display->drm);
if (!intel_connector)
return false;
@@ -701,7 +701,7 @@ bool g4x_hdmi_init(struct intel_display *display,
if (drmm_encoder_init(display->drm, &intel_encoder->base,
&intel_hdmi_enc_funcs, DRM_MODE_ENCODER_TMDS,
"HDMI %c", port_name(port)))
- goto err_encoder_init;
+ return false;
intel_encoder->hotplug = intel_hdmi_hotplug;
intel_encoder->compute_config = g4x_hdmi_compute_config;
@@ -763,11 +763,7 @@ bool g4x_hdmi_init(struct intel_display *display,
intel_infoframe_init(dig_port);
if (!intel_hdmi_init_connector(dig_port, intel_connector))
- goto err_encoder_init;
+ return false;
return true;
-err_encoder_init:
- kfree(intel_connector);
-
- return false;
}
diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c
index cfee173a2367a..3d7372f473d95 100644
--- a/drivers/gpu/drm/i915/display/icl_dsi.c
+++ b/drivers/gpu/drm/i915/display/icl_dsi.c
@@ -1783,7 +1783,6 @@ static const struct drm_connector_funcs gen11_dsi_connector_funcs = {
.detect = intel_panel_detect,
.late_register = intel_connector_register,
.early_unregister = intel_connector_unregister,
- .destroy = intel_connector_destroy,
.fill_modes = drm_helper_probe_single_connector_modes,
.atomic_get_property = intel_digital_connector_atomic_get_property,
.atomic_set_property = intel_digital_connector_atomic_set_property,
@@ -1935,11 +1934,9 @@ void icl_dsi_init(struct intel_display *display,
if (IS_ERR(intel_dsi))
return;
- intel_connector = intel_connector_alloc();
- if (!intel_connector) {
- kfree(intel_dsi);
+ intel_connector = intel_connector_alloc(display->drm);
+ if (!intel_connector)
return;
- }
encoder = &intel_dsi->base;
intel_dsi->attached_connector = intel_connector;
@@ -1969,10 +1966,16 @@ void icl_dsi_init(struct intel_display *display,
encoder->shutdown = intel_dsi_shutdown;
/* register DSI connector with DRM subsystem */
- drm_connector_init(display->drm, connector,
- &gen11_dsi_connector_funcs,
- DRM_MODE_CONNECTOR_DSI);
+ drmm_connector_init(display->drm, connector,
+ &gen11_dsi_connector_funcs,
+ DRM_MODE_CONNECTOR_DSI, NULL);
drm_connector_helper_add(connector, &gen11_dsi_connector_helper_funcs);
+
+ if (drmm_add_action_or_reset(display->drm, intel_connector_destroy, intel_connector)) {
+ drm_err(display->drm, "Failed to register intel_connector_destroy clean-up.\n");
+ return;
+ }
+
connector->display_info.subpixel_order = SubPixelHorizontalRGB;
intel_connector->get_hw_state = intel_connector_get_hw_state;
@@ -1989,7 +1992,7 @@ void icl_dsi_init(struct intel_display *display,
if (!intel_panel_preferred_fixed_mode(intel_connector)) {
drm_err(display->drm, "DSI fixed mode info missing\n");
- goto err;
+ return;
}
intel_panel_init(intel_connector, NULL);
@@ -2012,22 +2015,17 @@ void icl_dsi_init(struct intel_display *display,
host = intel_dsi_host_init(intel_dsi, &gen11_dsi_host_ops, port);
if (!host)
- goto err;
+ return;
intel_dsi->dsi_hosts[port] = host;
}
if (!intel_dsi_vbt_init(intel_dsi, MIPI_DSI_GENERIC_PANEL_ID)) {
drm_dbg_kms(display->drm, "no device found\n");
- goto err;
+ return;
}
icl_dphy_param_init(intel_dsi);
icl_dsi_add_properties(intel_connector);
- return;
-
-err:
- drm_connector_cleanup(connector);
- kfree(intel_connector);
}
diff --git a/drivers/gpu/drm/i915/display/intel_connector.c b/drivers/gpu/drm/i915/display/intel_connector.c
index 7ef9338d67abf..6fb64c6f4c9e4 100644
--- a/drivers/gpu/drm/i915/display/intel_connector.c
+++ b/drivers/gpu/drm/i915/display/intel_connector.c
@@ -28,6 +28,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_edid.h>
+#include <drm/drm_managed.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
@@ -101,7 +102,21 @@ static int intel_connector_init(struct intel_connector *connector)
return 0;
}
-struct intel_connector *intel_connector_alloc(void)
+struct intel_connector *intel_connector_alloc(struct drm_device *dev)
+{
+ struct intel_connector *connector;
+
+ connector = drmm_kzalloc(dev, sizeof(*connector), GFP_KERNEL);
+ if (!connector)
+ return NULL;
+
+ if (intel_connector_init(connector) < 0)
+ return NULL;
+
+ return connector;
+}
+
+struct intel_connector *intel_subconnector_alloc(void)
{
struct intel_connector *connector;
@@ -127,15 +142,14 @@ struct intel_connector *intel_connector_alloc(void)
void intel_connector_free(struct intel_connector *connector)
{
kfree(to_intel_digital_connector_state(connector->base.state));
- kfree(connector);
}
/*
* Connector type independent destroy hook for drm_connector_funcs.
*/
-void intel_connector_destroy(struct drm_connector *connector)
+void intel_connector_destroy(struct drm_device *dev, void *data)
{
- struct intel_connector *intel_connector = to_intel_connector(connector);
+ struct intel_connector *intel_connector = (struct intel_connector *)data;
drm_edid_free(intel_connector->detect_edid);
@@ -143,12 +157,8 @@ void intel_connector_destroy(struct drm_connector *connector)
intel_panel_fini(intel_connector);
- drm_connector_cleanup(connector);
-
if (intel_connector->mst.port)
drm_dp_mst_put_port_malloc(intel_connector->mst.port);
-
- kfree(connector);
}
int intel_connector_register(struct drm_connector *_connector)
diff --git a/drivers/gpu/drm/i915/display/intel_connector.h b/drivers/gpu/drm/i915/display/intel_connector.h
index 0aa86626e6463..6c47ca46c1d18 100644
--- a/drivers/gpu/drm/i915/display/intel_connector.h
+++ b/drivers/gpu/drm/i915/display/intel_connector.h
@@ -14,9 +14,10 @@ struct i2c_adapter;
struct intel_connector;
struct intel_encoder;
-struct intel_connector *intel_connector_alloc(void);
+struct intel_connector *intel_connector_alloc(struct drm_device *dev);
+struct intel_connector *intel_subconnector_alloc(void);
void intel_connector_free(struct intel_connector *connector);
-void intel_connector_destroy(struct drm_connector *connector);
+void intel_connector_destroy(struct drm_device *dev, void *data);
int intel_connector_register(struct drm_connector *connector);
void intel_connector_unregister(struct drm_connector *connector);
void intel_connector_attach_encoder(struct intel_connector *connector,
diff --git a/drivers/gpu/drm/i915/display/intel_crt.c b/drivers/gpu/drm/i915/display/intel_crt.c
index 39bb115955f5a..8af76d141888b 100644
--- a/drivers/gpu/drm/i915/display/intel_crt.c
+++ b/drivers/gpu/drm/i915/display/intel_crt.c
@@ -992,7 +992,6 @@ static const struct drm_connector_funcs intel_crt_connector_funcs = {
.fill_modes = drm_helper_probe_single_connector_modes,
.late_register = intel_connector_register,
.early_unregister = intel_connector_unregister,
- .destroy = intel_connector_destroy,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
};
@@ -1046,19 +1045,21 @@ void intel_crt_init(struct intel_display *display)
if (IS_ERR(crt))
return;
- connector = intel_connector_alloc();
- if (!connector) {
- kfree(crt);
+ connector = intel_connector_alloc(display->drm);
+ if (!connector)
return;
- }
ddc_pin = display->vbt.crt_ddc_pin;
- drm_connector_init_with_ddc(display->drm, &connector->base,
- &intel_crt_connector_funcs,
- DRM_MODE_CONNECTOR_VGA,
- intel_gmbus_get_adapter(display, ddc_pin));
+ drmm_connector_init(display->drm, &connector->base,
+ &intel_crt_connector_funcs,
+ DRM_MODE_CONNECTOR_VGA,
+ intel_gmbus_get_adapter(display, ddc_pin));
+ if (drmm_add_action_or_reset(display->drm, intel_connector_destroy, connector)) {
+ drm_err(display->drm, "Failed to register intel_connector_destroy clean-up.\n");
+ return;
+ }
intel_connector_attach_encoder(connector, &crt->base);
diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
index 003287ad5bc59..bb87a7361aa92 100644
--- a/drivers/gpu/drm/i915/display/intel_ddi.c
+++ b/drivers/gpu/drm/i915/display/intel_ddi.c
@@ -4694,7 +4694,7 @@ static int intel_ddi_init_dp_connector(struct intel_digital_port *dig_port)
struct intel_connector *connector;
enum port port = dig_port->base.port;
- connector = intel_connector_alloc();
+ connector = intel_connector_alloc(display->drm);
if (!connector)
return -ENOMEM;
@@ -4709,10 +4709,8 @@ static int intel_ddi_init_dp_connector(struct intel_digital_port *dig_port)
dig_port->dp.voltage_max = intel_ddi_dp_voltage_max;
dig_port->dp.preemph_max = intel_ddi_dp_preemph_max;
- if (!intel_dp_init_connector(dig_port, connector)) {
- kfree(connector);
+ if (!intel_dp_init_connector(dig_port, connector))
return -EINVAL;
- }
if (dig_port->base.type == INTEL_OUTPUT_EDP) {
struct drm_privacy_screen *privacy_screen;
@@ -4892,12 +4890,13 @@ static bool bdw_digital_port_connected(struct intel_encoder *encoder)
return intel_de_read(display, GEN8_DE_PORT_ISR) & bit;
}
-static int intel_ddi_init_hdmi_connector(struct intel_digital_port *dig_port)
+static int intel_ddi_init_hdmi_connector(struct drm_device *dev,
+ struct intel_digital_port *dig_port)
{
struct intel_connector *connector;
enum port port = dig_port->base.port;
- connector = intel_connector_alloc();
+ connector = intel_connector_alloc(dev);
if (!connector)
return -ENOMEM;
@@ -4910,7 +4909,6 @@ static int intel_ddi_init_hdmi_connector(struct intel_digital_port *dig_port)
* don't fail the entire DDI init.
*/
dig_port->hdmi.hdmi_reg = INVALID_MMIO_REG;
- kfree(connector);
}
return 0;
@@ -5499,7 +5497,7 @@ void intel_ddi_init(struct intel_display *display,
* but leave it just in case we have some really bad VBTs...
*/
if (encoder->type != INTEL_OUTPUT_EDP && init_hdmi) {
- if (intel_ddi_init_hdmi_connector(dig_port))
+ if (intel_ddi_init_hdmi_connector(display->drm, dig_port))
return;
}
}
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 71f206adbebd3..2af64de9c81de 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -47,6 +47,7 @@
#include <drm/drm_crtc.h>
#include <drm/drm_edid.h>
#include <drm/drm_fixed.h>
+#include <drm/drm_managed.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
@@ -6810,7 +6811,6 @@ static const struct drm_connector_funcs intel_dp_connector_funcs = {
.atomic_set_property = intel_digital_connector_atomic_set_property,
.late_register = intel_dp_connector_register,
.early_unregister = intel_dp_connector_unregister,
- .destroy = intel_connector_destroy,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
.atomic_duplicate_state = intel_digital_connector_duplicate_state,
.oob_hotplug_event = intel_dp_oob_hotplug_event,
@@ -7213,10 +7213,15 @@ intel_dp_init_connector(struct intel_digital_port *dig_port,
type == DRM_MODE_CONNECTOR_eDP ? "eDP" : "DP",
encoder->base.base.id, encoder->base.name);
- drm_connector_init_with_ddc(dev, &connector->base, &intel_dp_connector_funcs,
- type, &intel_dp->aux.ddc);
+ drmm_connector_init(dev, &connector->base, &intel_dp_connector_funcs,
+ type, &intel_dp->aux.ddc);
drm_connector_helper_add(&connector->base, &intel_dp_connector_helper_funcs);
+ if (drmm_add_action_or_reset(dev, intel_connector_destroy, connector)) {
+ drm_err(dev, "Failed to register intel_connector_destroy clean-up.\n");
+ goto fail;
+ }
+
if (!HAS_GMCH(display) && DISPLAY_VER(display) < 12)
connector->base.interlace_allowed = true;
@@ -7260,7 +7265,6 @@ intel_dp_init_connector(struct intel_digital_port *dig_port,
fail:
intel_display_power_flush_work(display);
- drm_connector_cleanup(&connector->base);
return false;
}
diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c
index 5fe6fbcaf9371..4b0cdb61c33d6 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_mst.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c
@@ -1438,13 +1438,22 @@ mst_connector_early_unregister(struct drm_connector *_connector)
drm_dp_mst_connector_early_unregister(&connector->base, connector->mst.port);
}
+static void mst_connector_destroy(struct drm_connector *connector)
+{
+ struct intel_connector *intel_connector = to_intel_connector(connector);
+
+ intel_connector_destroy(connector->dev, intel_connector);
+ drm_connector_cleanup(connector);
+ kfree(connector);
+}
+
static const struct drm_connector_funcs mst_connector_funcs = {
.fill_modes = drm_helper_probe_single_connector_modes,
.atomic_get_property = intel_digital_connector_atomic_get_property,
.atomic_set_property = intel_digital_connector_atomic_set_property,
.late_register = mst_connector_late_register,
.early_unregister = mst_connector_early_unregister,
- .destroy = intel_connector_destroy,
+ .destroy = mst_connector_destroy,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
.atomic_duplicate_state = intel_digital_connector_duplicate_state,
};
@@ -1769,7 +1778,7 @@ mst_topology_add_connector(struct drm_dp_mst_topology_mgr *mgr,
enum pipe pipe;
int ret;
- connector = intel_connector_alloc();
+ connector = intel_subconnector_alloc();
if (!connector)
return NULL;
diff --git a/drivers/gpu/drm/i915/display/intel_dvo.c b/drivers/gpu/drm/i915/display/intel_dvo.c
index ea2f6426fd77d..1f84cc44598bf 100644
--- a/drivers/gpu/drm/i915/display/intel_dvo.c
+++ b/drivers/gpu/drm/i915/display/intel_dvo.c
@@ -362,7 +362,6 @@ static const struct drm_connector_funcs intel_dvo_connector_funcs = {
.detect = intel_dvo_detect,
.late_register = intel_connector_register,
.early_unregister = intel_connector_unregister,
- .destroy = intel_connector_destroy,
.fill_modes = drm_helper_probe_single_connector_modes,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
@@ -496,11 +495,9 @@ void intel_dvo_init(struct intel_display *display)
if (!intel_dvo)
return;
- connector = intel_connector_alloc();
- if (!connector) {
- kfree(intel_dvo);
+ connector = intel_connector_alloc(display->drm);
+ if (!connector)
return;
- }
intel_dvo->attached_connector = connector;
@@ -547,13 +544,19 @@ void intel_dvo_init(struct intel_display *display)
DRM_CONNECTOR_POLL_DISCONNECT;
connector->base.polled = connector->polled;
- drm_connector_init_with_ddc(display->drm, &connector->base,
- &intel_dvo_connector_funcs,
- intel_dvo_connector_type(&intel_dvo->dev),
- intel_gmbus_get_adapter(display, GMBUS_PIN_DPC));
+ drmm_connector_init(display->drm, &connector->base,
+ &intel_dvo_connector_funcs,
+ intel_dvo_connector_type(&intel_dvo->dev),
+ intel_gmbus_get_adapter(display, GMBUS_PIN_DPC));
drm_connector_helper_add(&connector->base,
&intel_dvo_connector_helper_funcs);
+
+ if (drmm_add_action_or_reset(display->drm, intel_connector_destroy, connector)) {
+ drm_err(display->drm, "Failed to register intel_connector_destroy clean-up.\n");
+ return;
+ }
+
connector->base.display_info.subpixel_order = SubPixelHorizontalRGB;
intel_connector_attach_encoder(connector, encoder);
diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c
index 05e898d10a2be..f744bae14eaf2 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
@@ -39,6 +39,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
#include <drm/drm_edid.h>
+#include <drm/drm_managed.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <drm/intel/intel_lpe_audio.h>
@@ -2650,7 +2651,6 @@ static const struct drm_connector_funcs intel_hdmi_connector_funcs = {
.atomic_set_property = intel_digital_connector_atomic_set_property,
.late_register = intel_hdmi_connector_register,
.early_unregister = intel_hdmi_connector_unregister,
- .destroy = intel_connector_destroy,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
.atomic_duplicate_state = intel_digital_connector_duplicate_state,
};
@@ -3083,13 +3083,18 @@ bool intel_hdmi_init_connector(struct intel_digital_port *dig_port,
if (!ddc_pin)
return false;
- drm_connector_init_with_ddc(dev, connector,
- &intel_hdmi_connector_funcs,
- DRM_MODE_CONNECTOR_HDMIA,
- intel_gmbus_get_adapter(display, ddc_pin));
+ drmm_connector_init(dev, connector,
+ &intel_hdmi_connector_funcs,
+ DRM_MODE_CONNECTOR_HDMIA,
+ intel_gmbus_get_adapter(display, ddc_pin));
drm_connector_helper_add(connector, &intel_hdmi_connector_helper_funcs);
+ if (drmm_add_action_or_reset(display->drm, intel_connector_destroy, intel_connector)) {
+ drm_err(dev, "Failed to register intel_connector_destroy clean-up.\n");
+ return false;
+ }
+
if (DISPLAY_VER(display) < 12)
connector->interlace_allowed = true;
diff --git a/drivers/gpu/drm/i915/display/intel_lvds.c b/drivers/gpu/drm/i915/display/intel_lvds.c
index 7bb99eb44a5a4..567eda1720261 100644
--- a/drivers/gpu/drm/i915/display/intel_lvds.c
+++ b/drivers/gpu/drm/i915/display/intel_lvds.c
@@ -512,7 +512,6 @@ static const struct drm_connector_funcs intel_lvds_connector_funcs = {
.atomic_set_property = intel_digital_connector_atomic_set_property,
.late_register = intel_connector_register,
.early_unregister = intel_connector_unregister,
- .destroy = intel_connector_destroy,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
.atomic_duplicate_state = intel_digital_connector_duplicate_state,
};
@@ -891,18 +890,23 @@ void intel_lvds_init(struct intel_display *display)
if (IS_ERR(lvds_encoder))
return;
- connector = intel_connector_alloc();
+ encoder = &lvds_encoder->base;
+
+ connector = intel_connector_alloc(display->drm);
if (!connector)
return;
lvds_encoder->attached_connector = connector;
- encoder = &lvds_encoder->base;
- drm_connector_init_with_ddc(display->drm, &connector->base,
- &intel_lvds_connector_funcs,
- DRM_MODE_CONNECTOR_LVDS,
- intel_gmbus_get_adapter(display, ddc_pin));
+ drmm_connector_init(display->drm, &connector->base,
+ &intel_lvds_connector_funcs,
+ DRM_MODE_CONNECTOR_LVDS,
+ intel_gmbus_get_adapter(display, ddc_pin));
+ if (drmm_add_action_or_reset(display->drm, intel_connector_destroy, connector)) {
+ drm_err(display->drm, "Failed to register intel_connector_destroy clean-up.\n");
+ return;
+ }
encoder->enable = intel_enable_lvds;
encoder->pre_enable = intel_pre_enable_lvds;
diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c
index f5aaa38002674..af3a250f637e1 100644
--- a/drivers/gpu/drm/i915/display/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/display/intel_sdvo.c
@@ -2507,7 +2507,6 @@ static const struct drm_connector_funcs intel_sdvo_connector_funcs = {
.atomic_set_property = intel_sdvo_connector_atomic_set_property,
.late_register = intel_connector_register,
.early_unregister = intel_connector_unregister,
- .destroy = intel_connector_destroy,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
.atomic_duplicate_state = intel_sdvo_connector_duplicate_state,
};
@@ -2730,17 +2729,23 @@ intel_sdvo_connector_init(struct intel_sdvo_connector *connector,
if (HAS_DDC(connector))
ddc = intel_sdvo_select_ddc_bus(encoder, connector);
- ret = drm_connector_init_with_ddc(encoder->base.base.dev,
- &connector->base.base,
- &intel_sdvo_connector_funcs,
- connector->base.base.connector_type,
- ddc ? &ddc->ddc : NULL);
+ ret = drmm_connector_init(encoder->base.base.dev,
+ &connector->base.base,
+ &intel_sdvo_connector_funcs,
+ connector->base.base.connector_type,
+ ddc ? &ddc->ddc : NULL);
if (ret < 0)
return ret;
drm_connector_helper_add(&connector->base.base,
&intel_sdvo_connector_helper_funcs);
+ ret = drmm_add_action_or_reset(display->drm, intel_connector_destroy, &connector->base);
+ if (ret) {
+ drm_err(display->drm, "Failed to register intel_connector_destroy clean-up.\n");
+ return ret;
+ }
+
connector->base.base.display_info.subpixel_order = SubPixelHorizontalRGB;
connector->base.base.interlace_allowed = true;
connector->base.get_hw_state = intel_sdvo_connector_get_hw_state;
@@ -2765,20 +2770,18 @@ intel_sdvo_add_hdmi_properties(struct intel_sdvo *intel_sdvo,
intel_attach_aspect_ratio_property(&connector->base.base);
}
-static struct intel_sdvo_connector *intel_sdvo_connector_alloc(void)
+static struct intel_sdvo_connector *intel_sdvo_connector_alloc(struct drm_device *dev)
{
struct intel_sdvo_connector *sdvo_connector;
struct intel_sdvo_connector_state *conn_state;
- sdvo_connector = kzalloc_obj(*sdvo_connector);
+ sdvo_connector = drmm_kzalloc(dev, sizeof(*sdvo_connector), GFP_KERNEL);
if (!sdvo_connector)
return NULL;
conn_state = kzalloc_obj(*conn_state);
- if (!conn_state) {
- kfree(sdvo_connector);
+ if (!conn_state)
return NULL;
- }
__drm_atomic_helper_connector_reset(&sdvo_connector->base.base,
&conn_state->base.base);
@@ -2800,7 +2803,7 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, u16 type)
drm_dbg_kms(display->drm, "initialising DVI type 0x%x\n", type);
- intel_sdvo_connector = intel_sdvo_connector_alloc();
+ intel_sdvo_connector = intel_sdvo_connector_alloc(display->drm);
if (!intel_sdvo_connector)
return false;
@@ -2830,10 +2833,8 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, u16 type)
intel_sdvo_connector->is_hdmi = true;
}
- if (intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo) < 0) {
- kfree(intel_sdvo_connector);
+ if (intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo) < 0)
return false;
- }
if (intel_sdvo_connector->is_hdmi)
intel_sdvo_add_hdmi_properties(intel_sdvo, intel_sdvo_connector);
@@ -2852,7 +2853,7 @@ intel_sdvo_tv_init(struct intel_sdvo *intel_sdvo, u16 type)
drm_dbg_kms(display->drm, "initialising TV type 0x%x\n", type);
- intel_sdvo_connector = intel_sdvo_connector_alloc();
+ intel_sdvo_connector = intel_sdvo_connector_alloc(display->drm);
if (!intel_sdvo_connector)
return false;
@@ -2863,10 +2864,8 @@ intel_sdvo_tv_init(struct intel_sdvo *intel_sdvo, u16 type)
intel_sdvo_connector->output_flag = type;
- if (intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo) < 0) {
- kfree(intel_sdvo_connector);
+ if (intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo) < 0)
return false;
- }
if (!intel_sdvo_tv_create_property(intel_sdvo, intel_sdvo_connector, type))
return false;
@@ -2888,7 +2887,7 @@ intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, u16 type)
drm_dbg_kms(display->drm, "initialising analog type 0x%x\n", type);
- intel_sdvo_connector = intel_sdvo_connector_alloc();
+ intel_sdvo_connector = intel_sdvo_connector_alloc(display->drm);
if (!intel_sdvo_connector)
return false;
@@ -2901,10 +2900,8 @@ intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, u16 type)
intel_sdvo_connector->output_flag = type;
- if (intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo) < 0) {
- kfree(intel_sdvo_connector);
+ if (intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo) < 0)
return false;
- }
return true;
}
@@ -2920,7 +2917,7 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, u16 type)
drm_dbg_kms(display->drm, "initialising LVDS type 0x%x\n", type);
- intel_sdvo_connector = intel_sdvo_connector_alloc();
+ intel_sdvo_connector = intel_sdvo_connector_alloc(display->drm);
if (!intel_sdvo_connector)
return false;
@@ -2931,10 +2928,8 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, u16 type)
intel_sdvo_connector->output_flag = type;
- if (intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo) < 0) {
- kfree(intel_sdvo_connector);
+ if (intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo) < 0)
return false;
- }
if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector))
return false;
@@ -3038,19 +3033,6 @@ intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo)
return true;
}
-static void intel_sdvo_output_cleanup(struct intel_sdvo *intel_sdvo)
-{
- struct intel_display *display = to_intel_display(&intel_sdvo->base);
- struct drm_connector *connector, *tmp;
-
- list_for_each_entry_safe(connector, tmp,
- &display->drm->mode_config.connector_list, head) {
- if (intel_attached_encoder(to_intel_connector(connector)) == &intel_sdvo->base) {
- drm_connector_unregister(connector);
- intel_connector_destroy(connector);
- }
- }
-}
static bool intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo,
struct intel_sdvo_connector *intel_sdvo_connector,
@@ -3443,7 +3425,7 @@ bool intel_sdvo_init(struct intel_display *display,
"SDVO output failed to setup on %s\n",
SDVO_NAME(intel_sdvo));
/* Output_setup can leave behind connectors! */
- goto err_output;
+ return false;
}
/*
@@ -3469,12 +3451,12 @@ bool intel_sdvo_init(struct intel_display *display,
/* Set the input timing to the screen. Assume always input 0. */
if (!intel_sdvo_set_target_input(intel_sdvo))
- goto err_output;
+ return false;
if (!intel_sdvo_get_input_pixel_clock_range(intel_sdvo,
&intel_sdvo->pixel_clock_min,
&intel_sdvo->pixel_clock_max))
- goto err_output;
+ return false;
drm_dbg_kms(display->drm, "%s device VID/DID: %02X:%02X.%02X, "
"clock range %dMHz - %dMHz, "
@@ -3495,9 +3477,4 @@ bool intel_sdvo_init(struct intel_display *display,
(SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1 |
SDVO_OUTPUT_LVDS1) ? 'Y' : 'N');
return true;
-
-err_output:
- intel_sdvo_output_cleanup(intel_sdvo);
-
- return false;
}
diff --git a/drivers/gpu/drm/i915/display/intel_tv.c b/drivers/gpu/drm/i915/display/intel_tv.c
index 05df0acc6dc3e..d473d915909e0 100644
--- a/drivers/gpu/drm/i915/display/intel_tv.c
+++ b/drivers/gpu/drm/i915/display/intel_tv.c
@@ -1841,7 +1841,6 @@ intel_tv_get_modes(struct drm_connector *connector)
static const struct drm_connector_funcs intel_tv_connector_funcs = {
.late_register = intel_connector_register,
.early_unregister = intel_connector_unregister,
- .destroy = intel_connector_destroy,
.fill_modes = drm_helper_probe_single_connector_modes,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
.atomic_duplicate_state = intel_tv_connector_duplicate_state,
@@ -1971,11 +1970,9 @@ intel_tv_init(struct intel_display *display)
if (IS_ERR(intel_tv))
return;
- intel_connector = intel_connector_alloc();
- if (!intel_connector) {
- kfree(intel_tv);
+ intel_connector = intel_connector_alloc(display->drm);
+ if (!intel_connector)
return;
- }
intel_encoder = &intel_tv->base;
connector = &intel_connector->base;
@@ -1993,9 +1990,13 @@ intel_tv_init(struct intel_display *display)
intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT;
intel_connector->base.polled = intel_connector->polled;
- drm_connector_init(display->drm, connector, &intel_tv_connector_funcs,
- DRM_MODE_CONNECTOR_SVIDEO);
+ drmm_connector_init(display->drm, connector, &intel_tv_connector_funcs,
+ DRM_MODE_CONNECTOR_SVIDEO, NULL);
+ if (drmm_add_action_or_reset(display->drm, intel_connector_destroy, intel_connector)) {
+ drm_err(display->drm, "Failed to register intel_connector_destroy clean-up.\n");
+ return;
+ }
intel_encoder->compute_config = intel_tv_compute_config;
intel_encoder->get_config = intel_tv_get_config;
diff --git a/drivers/gpu/drm/i915/display/vlv_dsi.c b/drivers/gpu/drm/i915/display/vlv_dsi.c
index e84edb6242716..726f4190a8398 100644
--- a/drivers/gpu/drm/i915/display/vlv_dsi.c
+++ b/drivers/gpu/drm/i915/display/vlv_dsi.c
@@ -1560,7 +1560,6 @@ static const struct drm_connector_funcs intel_dsi_connector_funcs = {
.detect = intel_panel_detect,
.late_register = intel_connector_register,
.early_unregister = intel_connector_unregister,
- .destroy = intel_connector_destroy,
.fill_modes = drm_helper_probe_single_connector_modes,
.atomic_get_property = intel_digital_connector_atomic_get_property,
.atomic_set_property = intel_digital_connector_atomic_set_property,
@@ -1924,7 +1923,7 @@ void vlv_dsi_init(struct intel_display *display)
if (IS_ERR(intel_dsi))
return;
- connector = intel_connector_alloc();
+ connector = intel_connector_alloc(display->drm);
if (!connector)
return;
@@ -2011,11 +2010,16 @@ void vlv_dsi_init(struct intel_display *display)
intel_dsi_vbt_gpio_init(intel_dsi,
intel_dsi_get_hw_state(encoder, &pipe));
- drm_connector_init(display->drm, &connector->base, &intel_dsi_connector_funcs,
- DRM_MODE_CONNECTOR_DSI);
+ drmm_connector_init(display->drm, &connector->base, &intel_dsi_connector_funcs,
+ DRM_MODE_CONNECTOR_DSI, NULL);
drm_connector_helper_add(&connector->base, &intel_dsi_connector_helper_funcs);
+ if (drmm_add_action_or_reset(display->drm, intel_connector_destroy, connector)) {
+ drm_err(display->drm, "Failed to register intel_connector_destroy clean-up.\n");
+ return;
+ }
+
connector->base.display_info.subpixel_order = SubPixelHorizontalRGB; /*XXX*/
intel_connector_attach_encoder(connector, encoder);
@@ -2026,7 +2030,7 @@ void vlv_dsi_init(struct intel_display *display)
if (!intel_panel_preferred_fixed_mode(connector)) {
drm_dbg_kms(display->drm, "no fixed mode\n");
- goto err_cleanup_connector;
+ return;
}
dmi_id = dmi_first_match(vlv_dsi_dmi_quirk_table);
@@ -2042,10 +2046,4 @@ void vlv_dsi_init(struct intel_display *display)
intel_backlight_setup(connector, INVALID_PIPE);
vlv_dsi_add_properties(connector);
-
- return;
-
-err_cleanup_connector:
- drm_connector_cleanup(&connector->base);
- kfree(connector);
}
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH RFC 09/12] drm: Introduce drmm_connector_dp_init() with link training state properties
2026-04-09 17:08 [PATCH RFC 00/12] Add support for DisplayPort link training information report Kory Maincent
` (7 preceding siblings ...)
2026-04-09 17:08 ` [PATCH RFC 08/12] drm/i915/display: Switch to managed for connector Kory Maincent
@ 2026-04-09 17:08 ` Kory Maincent
2026-04-09 17:08 ` [PATCH RFC 10/12] drm/i915/display/dp: Adopt dp_connector helpers to expose link training state Kory Maincent
` (2 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Kory Maincent @ 2026-04-09 17:08 UTC (permalink / raw)
To: Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
David Airlie, Simona Vetter, Dave Airlie, Jesse Barnes,
Eric Anholt, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Chun-Kuang Hu, Philipp Zabel,
Matthias Brugger, AngeloGioacchino Del Regno, Chris Wilson
Cc: Thomas Petazzoni, Mark Yacoub, Sean Paul, Louis Chauvet,
intel-gfx, intel-xe, dri-devel, linux-kernel, linux-mediatek,
linux-arm-kernel, Simona Vetter, Kory Maincent
Add a managed DisplayPort connector initialization helper,
drmm_connector_dp_init(), modeled after the existing HDMI counterpart
drmm_connector_hdmi_init(). Cleanup is handled automatically via a
DRM-managed action.
The helper creates the following immutable connector properties to expose
DP link training capabilities and state to userspace:
- num_lanes: bitmask of supported lane counts (1, 2, 4)
- link_rate: Array of supported link rates.
- dsc_en: Display Stream Compression supported
- voltage_swingN: per-lane voltage swing level bitmask
- pre-emphasisN: per-lane pre-emphasis level bitmask
Link rates are passed by the driver in deca-kbps, following the DRM
convention, but exposed to userspace in kbps for clarity.
Two additional helpers are provided to update and reset those properties
at runtime:
- drm_connector_dp_set_link_train_properties()
- drm_connector_dp_reset_link_train_properties()
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
drivers/gpu/drm/Makefile | 1 +
drivers/gpu/drm/drm_dp_connector.c | 344 +++++++++++++++++++++++++++++++++++++
include/drm/drm_connector.h | 38 ++++
include/drm/drm_dp_connector.h | 109 ++++++++++++
4 files changed, 492 insertions(+)
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index e97faabcd7830..8ff08c2fb863e 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -42,6 +42,7 @@ drm-y := \
drm_color_mgmt.o \
drm_colorop.o \
drm_connector.o \
+ drm_dp_connector.o \
drm_crtc.o \
drm_displayid.o \
drm_drv.o \
diff --git a/drivers/gpu/drm/drm_dp_connector.c b/drivers/gpu/drm/drm_dp_connector.c
new file mode 100644
index 0000000000000..b25637a4378d5
--- /dev/null
+++ b/drivers/gpu/drm/drm_dp_connector.c
@@ -0,0 +1,344 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2026 Google
+ * Author: Kory Maincent <kory.maincent@bootlin.com>
+ */
+#include <drm/drm_dp_connector.h>
+#include <drm/drm_print.h>
+#include <linux/list.h>
+
+/**
+ * drm_connector_dp_link_reset_properties() - Reset DisplayPort link configuration
+ * @connector: DRM connector
+ * @dp_link: Link training informations
+ *
+ * Returns: Zero on success, or an errno code otherwise.
+ */
+int
+drm_connector_dp_set_link_train_properties(struct drm_connector *connector,
+ const struct drm_connector_dp_link_train *dp_link_train)
+{
+ u32 lrate = 0;
+ int ret;
+
+ if (!connector)
+ return -ENODEV;
+
+ if (dp_link_train->nlanes && !is_power_of_2(dp_link_train->nlanes & DRM_NLANES_MASK)) {
+ drm_err(connector->dev, "Wrong lane number");
+ return -EINVAL;
+ }
+
+ if (dp_link_train->rate) {
+ struct drm_property_enum *prop_enum;
+ bool found = false;
+
+ list_for_each_entry(prop_enum, &connector->dp.link_rate_property->enum_list, head) {
+ u32 parsed_rate;
+
+ /* Convert dp_link_train->rate from deca-kbps to kbps */
+ if (!kstrtou32(prop_enum->name, 10, &parsed_rate) &&
+ dp_link_train->rate * 10 == parsed_rate) {
+ lrate = 1 << prop_enum->value;
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ drm_err(connector->dev, "Wrong rate value");
+ return -EINVAL;
+ }
+ }
+
+ ret = drm_object_property_set_value(&connector->base, connector->dp.nlanes_property,
+ dp_link_train->nlanes);
+ if (ret)
+ return ret;
+
+ ret = drm_object_property_set_value(&connector->base, connector->dp.link_rate_property,
+ lrate);
+ if (ret)
+ return ret;
+
+ if (connector->dp.dsc_en_property) {
+ ret = drm_object_property_set_value(&connector->base, connector->dp.dsc_en_property,
+ dp_link_train->dsc_en);
+ if (ret)
+ return ret;
+ }
+
+ for (int i = 0; i < 4; i++) {
+ if (connector->dp.v_swing_property[i]) {
+ ret = drm_object_property_set_value(&connector->base,
+ connector->dp.v_swing_property[i],
+ dp_link_train->v_swing[i]);
+ if (ret)
+ return ret;
+ }
+
+ if (connector->dp.pre_emph_property[i]) {
+ ret = drm_object_property_set_value(&connector->base,
+ connector->dp.pre_emph_property[i],
+ dp_link_train->pre_emph[i]);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(drm_connector_dp_set_link_train_properties);
+
+/**
+ * drm_connector_dp_link_reset_properties() - Reset DisplayPort link configuration
+ * @connector: DRM connector
+ */
+void drm_connector_dp_reset_link_train_properties(struct drm_connector *connector)
+{
+ struct drm_connector_dp_link_train dp_link_train = {0};
+
+ drm_connector_dp_set_link_train_properties(connector, &dp_link_train);
+}
+EXPORT_SYMBOL(drm_connector_dp_reset_link_train_properties);
+
+static int drm_connector_create_nlanes_prop(struct drm_connector *connector,
+ u8 sup_nlanes)
+{
+ static const struct drm_prop_enum_list props[] = {
+ {__builtin_ffs(DRM_DP_1LANE) - 1, "1" },
+ {__builtin_ffs(DRM_DP_2LANE) - 1, "2" },
+ {__builtin_ffs(DRM_DP_4LANE) - 1, "4" },
+ };
+ struct drm_property *prop;
+
+ if (drm_WARN_ON(connector->dev, sup_nlanes != (sup_nlanes & DRM_NLANES_MASK)))
+ return -EINVAL;
+
+ prop = drm_property_create_bitmask(connector->dev, DRM_MODE_PROP_IMMUTABLE,
+ "num_lanes", props, ARRAY_SIZE(props),
+ sup_nlanes);
+ if (!prop)
+ return -ENOMEM;
+
+ drm_object_attach_property(&connector->base, prop, 0);
+
+ connector->dp.nlanes_property = prop;
+
+ return 0;
+}
+
+static int drm_connector_create_lrate_prop(struct drm_connector *connector,
+ u32 sup_nlrates,
+ const u32 *sup_lrates)
+{
+ struct drm_prop_enum_list *props;
+ u32 supp_nlrates_bitmask = 0;
+ struct drm_property *prop;
+ int ret = 0;
+
+ if (!sup_nlrates || !sup_lrates)
+ return 0;
+
+ props = kcalloc(sup_nlrates, sizeof(*props), GFP_KERNEL);
+ if (!props)
+ return -ENOMEM;
+
+ for (int i = 0; i < sup_nlrates; i++) {
+ props[i].type = i;
+ /* Convert deca-kbps to kbps */
+ props[i].name = kasprintf(GFP_KERNEL, "%d", sup_lrates[i] * 10);
+ if (!props[i].name) {
+ while (i--)
+ kfree(props[i].name);
+ kfree(props);
+ return -ENOMEM;
+ }
+ supp_nlrates_bitmask |= 1 << i;
+ }
+
+ prop = drm_property_create_bitmask(connector->dev, DRM_MODE_PROP_IMMUTABLE,
+ "link_rate", props, sup_nlrates,
+ supp_nlrates_bitmask);
+ if (!prop) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ drm_object_attach_property(&connector->base, prop, 0);
+
+ connector->dp.link_rate_property = prop;
+
+out:
+ for (int i = 0; i < sup_nlrates; i++)
+ kfree(props[i].name);
+
+ kfree(props);
+ return ret;
+}
+
+static int drm_connector_create_dsc_prop(struct drm_connector *connector)
+{
+ struct drm_property *prop;
+
+ prop = drm_property_create_bool(connector->dev, DRM_MODE_PROP_IMMUTABLE, "dsc_en");
+ if (!prop)
+ return -ENOMEM;
+
+ drm_object_attach_property(&connector->base, prop, 0);
+
+ connector->dp.dsc_en_property = prop;
+
+ return 0;
+}
+
+static int drm_connector_create_vswing_prop(struct drm_connector *connector,
+ u8 sup_v_swings, int id)
+{
+ static const struct drm_prop_enum_list props[] = {
+ {__builtin_ffs(DRM_DP_VOLTAGE_SWING_LEVEL_0) - 1, "level_0" },
+ {__builtin_ffs(DRM_DP_VOLTAGE_SWING_LEVEL_1) - 1, "level_1" },
+ {__builtin_ffs(DRM_DP_VOLTAGE_SWING_LEVEL_2) - 1, "level_2" },
+ {__builtin_ffs(DRM_DP_VOLTAGE_SWING_LEVEL_3) - 1, "level_3" },
+ };
+ struct drm_property *prop;
+ char str[16];
+
+ if (!sup_v_swings)
+ return 0;
+
+ if (drm_WARN_ON(connector->dev, sup_v_swings != (sup_v_swings &
+ DRM_DP_VOLTAGE_SWING_LEVEL_MASK)))
+ return -EINVAL;
+
+ snprintf(str, sizeof(str), "voltage_swing%d", id);
+ prop = drm_property_create_bitmask(connector->dev, DRM_MODE_PROP_IMMUTABLE,
+ str, props, ARRAY_SIZE(props),
+ sup_v_swings);
+ if (!prop)
+ return -ENOMEM;
+
+ drm_object_attach_property(&connector->base, prop, 0);
+
+ connector->dp.v_swing_property[id] = prop;
+
+ return 0;
+}
+
+static int drm_connector_create_pre_emph_prop(struct drm_connector *connector,
+ u8 sup_pre_emph, int id)
+{
+ static const struct drm_prop_enum_list props[] = {
+ {__builtin_ffs(DRM_DP_PRE_EMPH_LEVEL_0) - 1, "level_0" },
+ {__builtin_ffs(DRM_DP_PRE_EMPH_LEVEL_1) - 1, "level_1" },
+ {__builtin_ffs(DRM_DP_PRE_EMPH_LEVEL_2) - 1, "level_2" },
+ {__builtin_ffs(DRM_DP_PRE_EMPH_LEVEL_3) - 1, "level_3" },
+ };
+ struct drm_property *prop;
+ char str[16];
+
+ if (!sup_pre_emph)
+ return 0;
+
+ if (drm_WARN_ON(connector->dev, sup_pre_emph != (sup_pre_emph &
+ DRM_DP_PRE_EMPH_LEVEL_MASK)))
+ return -EINVAL;
+
+ snprintf(str, sizeof(str), "pre_emphasis%d", id);
+ prop = drm_property_create_bitmask(connector->dev, DRM_MODE_PROP_IMMUTABLE,
+ str, props, ARRAY_SIZE(props),
+ sup_pre_emph);
+ if (!prop)
+ return -ENOMEM;
+
+ drm_object_attach_property(&connector->base, prop, 0);
+
+ connector->dp.pre_emph_property[id] = prop;
+
+ return 0;
+}
+
+static int
+drm_connector_dp_create_props(struct drm_connector *connector,
+ const struct drm_connector_dp_link_train_caps *dp_link_train_caps)
+{
+ u8 nlanes;
+ int ret;
+
+ ret = drm_connector_create_nlanes_prop(connector, dp_link_train_caps->nlanes);
+ if (ret)
+ return ret;
+
+ ret = drm_connector_create_lrate_prop(connector, dp_link_train_caps->nrates,
+ dp_link_train_caps->rates);
+ if (ret)
+ return ret;
+
+ if (dp_link_train_caps->dsc) {
+ ret = drm_connector_create_dsc_prop(connector);
+ if (ret)
+ return ret;
+ }
+
+ nlanes = 1 << (fls(dp_link_train_caps->nlanes) - 1);
+ for (int i = 0; i < nlanes; i++) {
+ ret = drm_connector_create_vswing_prop(connector,
+ dp_link_train_caps->v_swings, i);
+ if (ret)
+ return ret;
+
+ ret = drm_connector_create_pre_emph_prop(connector,
+ dp_link_train_caps->pre_emphs, i);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * drmm_connector_dp_init - Init a preallocated DisplayPort connector
+ * @dev: DRM device
+ * @connector: A pointer to the DisplayPort connector to init
+ * @funcs: callbacks for this connector
+ * @dp_link_train_caps: DisplayPort link training capabilities. The pointer
+ * is not kept by the DRM core
+ * @connector_type: user visible type of the connector
+ * @ddc: optional pointer to the associated ddc adapter
+ *
+ * Initialises a preallocated DisplayPort 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_dp_init(struct drm_device *dev,
+ struct drm_connector *connector,
+ const struct drm_connector_funcs *funcs,
+ const struct drm_connector_dp_link_train_caps *dp_link_train_caps,
+ int connector_type,
+ struct i2c_adapter *ddc)
+{
+ int ret;
+
+ if (!(connector_type == DRM_MODE_CONNECTOR_DisplayPort ||
+ connector_type == DRM_MODE_CONNECTOR_eDP))
+ return -EINVAL;
+
+ if (!dp_link_train_caps)
+ return -EINVAL;
+
+ ret = drmm_connector_init(dev, connector, funcs, connector_type, ddc);
+ if (ret)
+ return ret;
+
+ return drm_connector_dp_create_props(connector, dp_link_train_caps);
+}
+EXPORT_SYMBOL(drmm_connector_dp_init);
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index f83f28cae2075..df3a71fed35b1 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -1987,6 +1987,39 @@ struct drm_connector_cec {
void *data;
};
+/**
+ * struct drm_connector_dp - DRM Connector DisplayPort-related structure
+ */
+struct drm_connector_dp {
+ /**
+ * @nlanes_property: Connector property to report the number of lanes
+ */
+ struct drm_property *nlanes_property;
+
+ /**
+ * @link_rate_property: Connector property to report the link rate
+ */
+ struct drm_property *link_rate_property;
+
+ /**
+ * @dsc_en_property: Connector property to report the Display Stream
+ * Compression supporrt
+ */
+ struct drm_property *dsc_en_property;
+
+ /**
+ * @v_swing_property: Connector property to report the voltage
+ * swing per lane
+ */
+ struct drm_property *v_swing_property[4];
+
+ /**
+ * @pre_emph_property: Connector property to report the
+ * pre-emphasis per lane
+ */
+ struct drm_property *pre_emph_property[4];
+};
+
/**
* struct drm_connector - central DRM connector control structure
*
@@ -2410,6 +2443,11 @@ struct drm_connector {
* @cec: CEC-related data.
*/
struct drm_connector_cec cec;
+
+ /**
+ * @dp: DisplayPort-related variable and properties.
+ */
+ struct drm_connector_dp dp;
};
#define obj_to_connector(x) container_of(x, struct drm_connector, base)
diff --git a/include/drm/drm_dp_connector.h b/include/drm/drm_dp_connector.h
new file mode 100644
index 0000000000000..77d2f4bb6df68
--- /dev/null
+++ b/include/drm/drm_dp_connector.h
@@ -0,0 +1,109 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef DRM_DP_CONNECTOR_H_
+#define DRM_DP_CONNECTOR_H_
+
+#include <drm/drm_connector.h>
+
+#define DRM_DP_1LANE BIT(0)
+#define DRM_DP_2LANE BIT(1)
+#define DRM_DP_4LANE BIT(2)
+#define DRM_NLANES_MASK (DRM_DP_1LANE | DRM_DP_2LANE | DRM_DP_4LANE)
+#define DRM_DP_VOLTAGE_SWING_LEVEL_0 BIT(0)
+#define DRM_DP_VOLTAGE_SWING_LEVEL_1 BIT(1)
+#define DRM_DP_VOLTAGE_SWING_LEVEL_2 BIT(2)
+#define DRM_DP_VOLTAGE_SWING_LEVEL_3 BIT(3)
+#define DRM_DP_VOLTAGE_SWING_LEVEL_MASK (DRM_DP_VOLTAGE_SWING_LEVEL_0 | \
+ DRM_DP_VOLTAGE_SWING_LEVEL_1 | \
+ DRM_DP_VOLTAGE_SWING_LEVEL_2 | \
+ DRM_DP_VOLTAGE_SWING_LEVEL_3)
+#define DRM_DP_PRE_EMPH_LEVEL_0 BIT(0)
+#define DRM_DP_PRE_EMPH_LEVEL_1 BIT(1)
+#define DRM_DP_PRE_EMPH_LEVEL_2 BIT(2)
+#define DRM_DP_PRE_EMPH_LEVEL_3 BIT(3)
+#define DRM_DP_PRE_EMPH_LEVEL_MASK (DRM_DP_PRE_EMPH_LEVEL_0 | \
+ DRM_DP_PRE_EMPH_LEVEL_1 | \
+ DRM_DP_PRE_EMPH_LEVEL_2 | \
+ DRM_DP_PRE_EMPH_LEVEL_3)
+
+/**
+ * struct drm_connector_dp_link_train_caps - DRM DisplayPort link training
+ * capabilities
+ */
+struct drm_connector_dp_link_train_caps {
+ /**
+ * @nlanes: Bitmask of lanes number supported
+ */
+ u8 nlanes;
+
+ /**
+ * @nrates: Number of link rates supported
+ */
+ u32 nrates;
+
+ /**
+ * @rates: Array listing the supported link rates in deca-kbps
+ */
+ const u32 *rates;
+
+ /**
+ * @dsc: Display Stream Compression supported
+ */
+ bool dsc;
+
+ /**
+ * @v_swings: Bitmask of voltage swing level supported
+ */
+ u8 v_swings;
+
+ /**
+ * @pre_emphs: Bitmask of pre-emphasis level supported
+ */
+ u8 pre_emphs;
+};
+
+/**
+ * struct drm_connector_dp_link_train - DRM DisplayPort link training
+ * information report
+ */
+struct drm_connector_dp_link_train {
+ /**
+ * @nlanes: The number of lanes used
+ */
+ u8 nlanes;
+
+ /**
+ * @rates: Link rate value selected in deca-kbps
+ */
+ u32 rate;
+
+ /**
+ * @dsc: Display Stream Compression enabled
+ */
+ bool dsc_en;
+
+ /**
+ * @v_swings: Array listing the bitmask voltage swing level per lanes
+ */
+ u8 v_swing[4];
+
+ /**
+ * @pre_emph: Array listing the bitmask pre-emphasis level per lanes
+ */
+ u8 pre_emph[4];
+};
+
+int drmm_connector_dp_init(struct drm_device *dev,
+ struct drm_connector *connector,
+ const struct drm_connector_funcs *funcs,
+ const struct drm_connector_dp_link_train_caps *dp_link_train_caps,
+ int connector_type,
+ struct i2c_adapter *ddc);
+
+int
+drm_connector_dp_set_link_train_properties(struct drm_connector *con,
+ const struct drm_connector_dp_link_train *dp_link_train);
+
+void drm_connector_dp_reset_link_train_properties(struct drm_connector *connector);
+
+#endif // DRM_DP_CONNECTOR_H_
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH RFC 10/12] drm/i915/display/dp: Adopt dp_connector helpers to expose link training state
2026-04-09 17:08 [PATCH RFC 00/12] Add support for DisplayPort link training information report Kory Maincent
` (8 preceding siblings ...)
2026-04-09 17:08 ` [PATCH RFC 09/12] drm: Introduce drmm_connector_dp_init() with link training state properties Kory Maincent
@ 2026-04-09 17:08 ` Kory Maincent
2026-04-09 17:08 ` [PATCH RFC 11/12] drm/bridge: Wire drmm_connector_dp_init() via new DRM_BRIDGE_OP_DP flag Kory Maincent
2026-04-09 17:08 ` [PATCH RFC 12/12] drm/mediatek: Use dp_connector helpers to report link training state Kory Maincent
11 siblings, 0 replies; 13+ messages in thread
From: Kory Maincent @ 2026-04-09 17:08 UTC (permalink / raw)
To: Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
David Airlie, Simona Vetter, Dave Airlie, Jesse Barnes,
Eric Anholt, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Chun-Kuang Hu, Philipp Zabel,
Matthias Brugger, AngeloGioacchino Del Regno, Chris Wilson
Cc: Thomas Petazzoni, Mark Yacoub, Sean Paul, Louis Chauvet,
intel-gfx, intel-xe, dri-devel, linux-kernel, linux-mediatek,
linux-arm-kernel, Simona Vetter, Kory Maincent
Switch the i915 DP connector initialization from drmm_connector_init()
to drmm_connector_dp_init(), providing the source link capabilities
(supported lane counts, link rates, DSC support, voltage swing and
pre-emphasis levels).
Add intel_dp_report_link_train() to collect the negotiated link
parameters (rate, lane count, DSC enable, per-lane voltage swing and
pre-emphasis) and report them via drm_connector_dp_set_link_train_properties()
once link training completes successfully.
Reset the link training properties via
drm_connector_dp_reset_link_train_properties() when the connector is
reported as disconnected or when the display device is disabled, so
the exposed state always reflects the current link status.
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
drivers/gpu/drm/i915/display/intel_dp.c | 31 +++++++++++++++++++---
.../gpu/drm/i915/display/intel_dp_link_training.c | 25 +++++++++++++++++
2 files changed, 52 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 2af64de9c81de..641406bdc0cc9 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -45,6 +45,7 @@
#include <drm/display/drm_hdmi_helper.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
+#include <drm/drm_dp_connector.h>
#include <drm/drm_edid.h>
#include <drm/drm_fixed.h>
#include <drm/drm_managed.h>
@@ -6337,8 +6338,10 @@ intel_dp_detect(struct drm_connector *_connector,
drm_WARN_ON(display->drm,
!drm_modeset_is_locked(&display->drm->mode_config.connection_mutex));
- if (!intel_display_device_enabled(display))
+ if (!intel_display_device_enabled(display)) {
+ drm_connector_dp_reset_link_train_properties(_connector);
return connector_status_disconnected;
+ }
if (!intel_display_driver_check_access(display))
return connector->base.status;
@@ -6388,6 +6391,8 @@ intel_dp_detect(struct drm_connector *_connector,
intel_dp_tunnel_disconnect(intel_dp);
+ drm_connector_dp_reset_link_train_properties(_connector);
+
goto out_unset_edid;
}
@@ -7162,10 +7167,12 @@ intel_dp_init_connector(struct intel_digital_port *dig_port,
struct intel_connector *connector)
{
struct intel_display *display = to_intel_display(dig_port);
+ struct drm_connector_dp_link_train_caps link_caps;
struct intel_dp *intel_dp = &dig_port->dp;
struct intel_encoder *encoder = &dig_port->base;
struct drm_device *dev = encoder->base.dev;
enum port port = encoder->port;
+ u32 *rates;
int type;
if (drm_WARN(dev, dig_port->max_lanes < 1,
@@ -7213,8 +7220,25 @@ intel_dp_init_connector(struct intel_digital_port *dig_port,
type == DRM_MODE_CONNECTOR_eDP ? "eDP" : "DP",
encoder->base.base.id, encoder->base.name);
- drmm_connector_init(dev, &connector->base, &intel_dp_connector_funcs,
- type, &intel_dp->aux.ddc);
+ intel_dp_set_source_rates(intel_dp);
+ link_caps.nlanes = DRM_DP_1LANE | DRM_DP_2LANE | DRM_DP_4LANE;
+ link_caps.nrates = intel_dp->num_source_rates;
+ rates = kzalloc_objs(*rates, intel_dp->num_source_rates);
+ if (!rates)
+ goto fail;
+
+ for (int i = 0; i < intel_dp->num_source_rates; i++)
+ rates[i] = intel_dp->source_rates[i];
+
+ link_caps.rates = rates;
+ link_caps.dsc = true;
+ link_caps.v_swings = DRM_DP_VOLTAGE_SWING_LEVEL_MASK;
+ link_caps.pre_emphs = DRM_DP_PRE_EMPH_LEVEL_MASK;
+
+ drmm_connector_dp_init(dev, &connector->base, &intel_dp_connector_funcs,
+ &link_caps, type, &intel_dp->aux.ddc);
+ kfree(rates);
+
drm_connector_helper_add(&connector->base, &intel_dp_connector_helper_funcs);
if (drmm_add_action_or_reset(dev, intel_connector_destroy, connector)) {
@@ -7240,7 +7264,6 @@ intel_dp_init_connector(struct intel_digital_port *dig_port,
if (!intel_edp_init_connector(intel_dp, connector))
goto fail;
- intel_dp_set_source_rates(intel_dp);
intel_dp_set_common_rates(intel_dp);
intel_dp_reset_link_params(intel_dp);
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
index 54c585c59b900..c2fd46a323650 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -25,6 +25,7 @@
#include <linux/iopoll.h>
#include <drm/display/drm_dp_helper.h>
+#include <drm/drm_dp_connector.h>
#include <drm/drm_print.h>
#include "intel_display_core.h"
@@ -1116,6 +1117,27 @@ intel_dp_128b132b_intra_hop(struct intel_dp *intel_dp,
return sink_status & DP_INTRA_HOP_AUX_REPLY_INDICATION ? 1 : 0;
}
+static void intel_dp_report_link_train(struct intel_dp *intel_dp)
+{
+ struct intel_connector *connector = intel_dp->attached_connector;
+ struct drm_connector_dp_link_train dp_link_train;
+
+ dp_link_train.rate = intel_dp->link_rate;
+ dp_link_train.nlanes = intel_dp->lane_count;
+ dp_link_train.dsc_en = connector->dp.dsc_decompression_enabled;
+
+ for (int i = 0; i < intel_dp->lane_count; i++) {
+ int v_swing_level = (intel_dp->train_set[i] &
+ DP_TRAIN_VOLTAGE_SWING_MASK) >> DP_TRAIN_VOLTAGE_SWING_SHIFT;
+ int pre_emph_level = (intel_dp->train_set[i] &
+ DP_TRAIN_PRE_EMPHASIS_MASK) >> DP_TRAIN_PRE_EMPHASIS_SHIFT;
+ dp_link_train.v_swing[i] = 1 << v_swing_level;
+ dp_link_train.pre_emph[i] = 1 << pre_emph_level;
+ }
+
+ drm_connector_dp_set_link_train_properties(&connector->base, &dp_link_train);
+}
+
/**
* intel_dp_stop_link_train - stop link training
* @intel_dp: DP struct
@@ -1144,6 +1166,9 @@ void intel_dp_stop_link_train(struct intel_dp *intel_dp,
intel_dp_program_link_training_pattern(intel_dp, crtc_state, DP_PHY_DPRX,
DP_TRAINING_PATTERN_DISABLE);
+ if (!intel_dp->is_mst)
+ intel_dp_report_link_train(intel_dp);
+
if (intel_dp_is_uhbr(crtc_state)) {
ret = poll_timeout_us(ret = intel_dp_128b132b_intra_hop(intel_dp, crtc_state),
ret == 0,
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH RFC 11/12] drm/bridge: Wire drmm_connector_dp_init() via new DRM_BRIDGE_OP_DP flag
2026-04-09 17:08 [PATCH RFC 00/12] Add support for DisplayPort link training information report Kory Maincent
` (9 preceding siblings ...)
2026-04-09 17:08 ` [PATCH RFC 10/12] drm/i915/display/dp: Adopt dp_connector helpers to expose link training state Kory Maincent
@ 2026-04-09 17:08 ` Kory Maincent
2026-04-09 17:08 ` [PATCH RFC 12/12] drm/mediatek: Use dp_connector helpers to report link training state Kory Maincent
11 siblings, 0 replies; 13+ messages in thread
From: Kory Maincent @ 2026-04-09 17:08 UTC (permalink / raw)
To: Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
David Airlie, Simona Vetter, Dave Airlie, Jesse Barnes,
Eric Anholt, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Chun-Kuang Hu, Philipp Zabel,
Matthias Brugger, AngeloGioacchino Del Regno, Chris Wilson
Cc: Thomas Petazzoni, Mark Yacoub, Sean Paul, Louis Chauvet,
intel-gfx, intel-xe, dri-devel, linux-kernel, linux-mediatek,
linux-arm-kernel, Simona Vetter, Kory Maincent
Introduce DRM_BRIDGE_OP_DP, a new bridge operation flag for bridges
that provide DisplayPort connector operations with link training support.
Bridges advertising this flag must fill the dp_link_train_caps field in
struct drm_bridge with their link training capabilities.
In drm_bridge_connector_init(), when a bridge sets DRM_BRIDGE_OP_DP,
use drmm_connector_dp_init() instead of the generic drmm_connector_init()
so the connector exposes link training state properties to userspace.
This mirrors the existing pattern used for HDMI bridges.
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
drivers/gpu/drm/display/drm_bridge_connector.c | 26 +++++++++++++++++++++++++-
include/drm/drm_bridge.h | 13 +++++++++++++
2 files changed, 38 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
index 39cc18f78eda1..e20b61bb03f12 100644
--- a/drivers/gpu/drm/display/drm_bridge_connector.c
+++ b/drivers/gpu/drm/display/drm_bridge_connector.c
@@ -13,7 +13,7 @@
#include <drm/drm_atomic_state_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_bridge_connector.h>
-#include <drm/drm_connector.h>
+#include <drm/drm_dp_connector.h>
#include <drm/drm_device.h>
#include <drm/drm_edid.h>
#include <drm/drm_managed.h>
@@ -108,6 +108,13 @@ struct drm_bridge_connector {
* HDMI Audio infrastructure, if any (see &DRM_BRIDGE_OP_HDMI_AUDIO).
*/
struct drm_bridge *bridge_hdmi_audio;
+ /**
+ * @bridge_dp:
+ *
+ * The bridge in the chain that implements necessary support for the
+ * DisplayPort connector infrastructure, if any (see &DRM_BRIDGE_OP_DP).
+ */
+ struct drm_bridge *bridge_dp;
/**
* @bridge_dp_audio:
*
@@ -766,6 +773,7 @@ static void drm_bridge_connector_put_bridges(struct drm_device *dev, void *data)
drm_bridge_put(bridge_connector->bridge_hdmi_audio);
drm_bridge_put(bridge_connector->bridge_dp_audio);
drm_bridge_put(bridge_connector->bridge_hdmi_cec);
+ drm_bridge_put(bridge_connector->bridge_dp);
}
/**
@@ -898,6 +906,15 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
bridge_connector->bridge_hdmi_audio = drm_bridge_get(bridge);
}
+ if (bridge->ops & DRM_BRIDGE_OP_DP) {
+ if (bridge_connector->bridge_dp)
+ return ERR_PTR(-EBUSY);
+ if (!bridge->dp_link_train_caps)
+ return ERR_PTR(-EINVAL);
+
+ bridge_connector->bridge_dp = drm_bridge_get(bridge);
+ }
+
if (bridge->ops & DRM_BRIDGE_OP_DP_AUDIO) {
if (bridge_connector->bridge_dp_audio)
return ERR_PTR(-EBUSY);
@@ -986,6 +1003,13 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
max_bpc);
if (ret)
return ERR_PTR(ret);
+ } else if (bridge_connector->bridge_dp) {
+ ret = drmm_connector_dp_init(drm, connector,
+ &drm_bridge_connector_funcs,
+ bridge_connector->bridge_dp->dp_link_train_caps,
+ connector_type, ddc);
+ if (ret)
+ return ERR_PTR(ret);
} else {
ret = drmm_connector_init(drm, connector,
&drm_bridge_connector_funcs,
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index a8d67bd9ee505..b3df9dffd5bcc 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -1092,6 +1092,14 @@ enum drm_bridge_ops {
* &drm_bridge_funcs->hdmi_clear_spd_infoframe callbacks.
*/
DRM_BRIDGE_OP_HDMI_SPD_INFOFRAME = BIT(10),
+ /**
+ * @DRM_BRIDGE_OP_DP: The bridge provides DisplayPort connector
+ * operations, including link training support. Bridges that set
+ * this flag must provide DisplayPort-related information and
+ * fill the &drm_bridge->dp_link_train_caps link training
+ * capabilities.
+ */
+ DRM_BRIDGE_OP_DP = BIT(11),
};
/**
@@ -1267,6 +1275,11 @@ struct drm_bridge {
*/
void *hpd_data;
+ /**
+ * @dp_link_train_caps: DisplayPort link training capabilities
+ */
+ const struct drm_connector_dp_link_train_caps *dp_link_train_caps;
+
/**
* @next_bridge: Pointer to the following bridge, automatically put
* when this bridge is freed (i.e. at destroy time). This is for
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH RFC 12/12] drm/mediatek: Use dp_connector helpers to report link training state
2026-04-09 17:08 [PATCH RFC 00/12] Add support for DisplayPort link training information report Kory Maincent
` (10 preceding siblings ...)
2026-04-09 17:08 ` [PATCH RFC 11/12] drm/bridge: Wire drmm_connector_dp_init() via new DRM_BRIDGE_OP_DP flag Kory Maincent
@ 2026-04-09 17:08 ` Kory Maincent
11 siblings, 0 replies; 13+ messages in thread
From: Kory Maincent @ 2026-04-09 17:08 UTC (permalink / raw)
To: Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
David Airlie, Simona Vetter, Dave Airlie, Jesse Barnes,
Eric Anholt, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Chun-Kuang Hu, Philipp Zabel,
Matthias Brugger, AngeloGioacchino Del Regno, Chris Wilson
Cc: Thomas Petazzoni, Mark Yacoub, Sean Paul, Louis Chauvet,
intel-gfx, intel-xe, dri-devel, linux-kernel, linux-mediatek,
linux-arm-kernel, Simona Vetter, Kory Maincent
Set DRM_BRIDGE_OP_DP and populate dp_link_train_caps with the supported
link rates, lane counts, voltage swing and pre-emphasis levels so the
bridge connector uses drmm_connector_dp_init() and exposes the link
training state properties to userspace.
Store per-lane voltage swing and pre-emphasis values in
mtk_dp_train_info and report the negotiated link parameters via
drm_connector_dp_set_link_train_properties() on training completion.
Clear them via drm_connector_dp_reset_link_train_properties() when a
disconnect is detected in the HPD event thread.
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
This patch has still not been tested. I am in the process of finding the
hardware for that.
---
drivers/gpu/drm/mediatek/mtk_dp.c | 34 +++++++++++++++++++++++++++++++++-
1 file changed, 33 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
index c52cc7c2e2006..119718c1374c5 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -10,6 +10,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_crtc.h>
+#include <drm/drm_dp_connector.h>
#include <drm/drm_edid.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
@@ -72,6 +73,8 @@ struct mtk_dp_train_info {
/* link_rate is in multiple of 0.27Gbps */
int link_rate;
int lane_count;
+ u8 vswing[4];
+ u8 preemphasis[4];
unsigned int channel_eq_pattern;
};
@@ -1561,6 +1564,9 @@ static void mtk_dp_train_update_swing_pre(struct mtk_dp *mtk_dp, int lanes,
mtk_dp_set_swing_pre_emphasis(mtk_dp, lane, swing, preemphasis);
drm_dp_dpcd_writeb(&mtk_dp->aux, DP_TRAINING_LANE0_SET + lane,
val);
+
+ mtk_dp->train_info.vswing[lane] = swing;
+ mtk_dp->train_info.preemphasis[lane] = preemphasis;
}
}
@@ -1812,6 +1818,21 @@ static void mtk_dp_train_change_mode(struct mtk_dp *mtk_dp)
mtk_dp_reset_swing_pre_emphasis(mtk_dp);
}
+static int mtk_dp_report_link_train(struct mtk_dp *mtk_dp)
+{
+ struct drm_connector_dp_link_train dp_link_train;
+
+ dp_link_train.rate = drm_dp_bw_code_to_link_rate(mtk_dp->train_info.link_rate);
+ dp_link_train.nlanes = mtk_dp->train_info.lane_count;
+
+ for (int i = 0; i < mtk_dp->train_info.lane_count; i++) {
+ dp_link_train.v_swing[i] = 1 << mtk_dp->train_info.vswing[i];
+ dp_link_train.pre_emph[i] = 1 << mtk_dp->train_info.preemphasis[i];
+ }
+
+ return drm_connector_dp_set_link_train_properties(mtk_dp->conn, &dp_link_train);
+}
+
static int mtk_dp_training(struct mtk_dp *mtk_dp)
{
int ret;
@@ -1892,7 +1913,7 @@ static int mtk_dp_training(struct mtk_dp *mtk_dp)
mtk_dp_training_set_scramble(mtk_dp, true);
mtk_dp_set_enhanced_frame_mode(mtk_dp);
- return 0;
+ return mtk_dp_report_link_train(mtk_dp);
}
static void mtk_dp_video_enable(struct mtk_dp *mtk_dp, bool enable)
@@ -2004,6 +2025,7 @@ static irqreturn_t mtk_dp_hpd_event_thread(int hpd, void *dev)
mtk_dp->need_debounce = false;
mod_timer(&mtk_dp->debounce_timer,
jiffies + msecs_to_jiffies(100) - 1);
+ drm_connector_dp_reset_link_train_properties(mtk_dp->conn);
} else {
mtk_dp_aux_panel_poweron(mtk_dp, true);
@@ -2742,6 +2764,14 @@ static int mtk_dp_edp_link_panel(struct drm_dp_aux *mtk_aux)
static int mtk_dp_probe(struct platform_device *pdev)
{
+ static const u32 dp_rates[] = {162000, 270000, 540000, 810000};
+ static const struct drm_connector_dp_link_train_caps dp_link_train_caps = {
+ .nlanes = DRM_DP_1LANE | DRM_DP_2LANE | DRM_DP_4LANE,
+ .nrates = ARRAY_SIZE(dp_rates),
+ .rates = dp_rates,
+ .v_swings = DRM_DP_VOLTAGE_SWING_LEVEL_MASK,
+ .pre_emphs = DRM_DP_PRE_EMPH_LEVEL_MASK,
+ };
struct mtk_dp *mtk_dp;
struct device *dev = &pdev->dev;
int ret;
@@ -2809,6 +2839,8 @@ static int mtk_dp_probe(struct platform_device *pdev)
mtk_dp->bridge.of_node = dev->of_node;
mtk_dp->bridge.type = mtk_dp->data->bridge_type;
+ mtk_dp->bridge.dp_link_train_caps = &dp_link_train_caps;
+ mtk_dp->bridge.ops = DRM_BRIDGE_OP_DP;
if (mtk_dp->bridge.type == DRM_MODE_CONNECTOR_eDP) {
/*
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
end of thread, other threads:[~2026-04-09 17:09 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-09 17:08 [PATCH RFC 00/12] Add support for DisplayPort link training information report Kory Maincent
2026-04-09 17:08 ` [PATCH RFC 01/12] drm/i915/display/intel_sdvo: Fix double connector destroy in error paths Kory Maincent
2026-04-09 17:08 ` [PATCH RFC 02/12] drm/i915/display/intel_lvds: Drop redundant manual cleanup on init failure Kory Maincent
2026-04-09 17:08 ` [PATCH RFC 03/12] drm/i915/display/intel_dp: Drop redundant intel_dp_aux_fini() " Kory Maincent
2026-04-09 17:08 ` [PATCH RFC 04/12] drm/i915/display: Switch to drmm_mode_config_init() and drop manual cleanup Kory Maincent
2026-04-09 17:08 ` [PATCH RFC 05/12] drm/i915/display: Switch to managed for crtc Kory Maincent
2026-04-09 17:08 ` [PATCH RFC 06/12] drm/i915/display: Switch to managed for plane Kory Maincent
2026-04-09 17:08 ` [PATCH RFC 07/12] drm/i915/display: Switch to managed for encoder Kory Maincent
2026-04-09 17:08 ` [PATCH RFC 08/12] drm/i915/display: Switch to managed for connector Kory Maincent
2026-04-09 17:08 ` [PATCH RFC 09/12] drm: Introduce drmm_connector_dp_init() with link training state properties Kory Maincent
2026-04-09 17:08 ` [PATCH RFC 10/12] drm/i915/display/dp: Adopt dp_connector helpers to expose link training state Kory Maincent
2026-04-09 17:08 ` [PATCH RFC 11/12] drm/bridge: Wire drmm_connector_dp_init() via new DRM_BRIDGE_OP_DP flag Kory Maincent
2026-04-09 17:08 ` [PATCH RFC 12/12] drm/mediatek: Use dp_connector helpers to report link training state Kory Maincent
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox