[PATCH 004/108] drm/i915/dp_link_training: Introduce link training state struct

Imre Deak
2026-04-28T12:52:55Z

Start isolating the link training state from the generic DP code by
introducing a separate intel_dp_link_training state struct.

Allocate the state so it can remain opaque within its own module.

Follow-up changes will move link training fields from the DP struct to
the link training state.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
drivers/gpu/drm/i915/display/g4x_dp.c | 10 ++++-
drivers/gpu/drm/i915/display/intel_ddi.c | 18 ++++++++-
.../drm/i915/display/intel_display_types.h | 2 +
drivers/gpu/drm/i915/display/intel_dp.c | 31 +++++++++++++++
drivers/gpu/drm/i915/display/intel_dp.h | 3 ++
.../drm/i915/display/intel_dp_link_training.c | 39 +++++++++++++++++++
.../drm/i915/display/intel_dp_link_training.h | 4 ++
7 files changed, 104 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/g4x_dp.c b/drivers/gpu/drm/i915/display/g4x_dp.c
index 5e74d8a3ba5c8..e1698172a8163 100644
--- a/drivers/gpu/drm/i915/display/g4x_dp.c
+++ b/drivers/gpu/drm/i915/display/g4x_dp.c
@@ -1252,10 +1252,13 @@ static void g4x_dp_suspend_complete(struct intel_encoder *encoder)

static void intel_dp_encoder_destroy(struct drm_encoder *encoder)
{
+ struct intel_digital_port *dig_port = enc_to_dig_port(to_intel_encoder(encoder));
+
intel_dp_encoder_flush_work(encoder);

drm_encoder_cleanup(encoder);
- kfree(enc_to_dig_port(to_intel_encoder(encoder)));
+ intel_dp_link_cleanup(&dig_port->dp);
+ kfree(dig_port);
}

static void intel_dp_encoder_reset(struct drm_encoder *encoder)
@@ -1350,6 +1353,9 @@ bool g4x_dp_init(struct intel_display *display,
intel_encoder->audio_enable = g4x_dp_audio_enable;
intel_encoder->audio_disable = g4x_dp_audio_disable;

+ if (intel_dp_link_init(&dig_port->dp) != 0)
+ goto err_dp_init;
+
if ((display->platform.ivybridge && port == PORT_A) ||
(HAS_PCH_CPT(display) && port != PORT_A)) {
dig_port->dp.set_link_train = cpt_set_link_train;
@@ -1419,6 +1425,8 @@ bool g4x_dp_init(struct intel_display *display,
return true;

err_init_connector:
+ intel_dp_link_cleanup(&dig_port->dp);
+err_dp_init:
drm_encoder_cleanup(encoder);
err_encoder_init:
kfree(intel_connector);
diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
index 2681940a5cfe3..f094830d34b92 100644
--- a/drivers/gpu/drm/i915/display/intel_ddi.c
+++ b/drivers/gpu/drm/i915/display/intel_ddi.c
@@ -4656,6 +4656,7 @@ static void intel_ddi_encoder_destroy(struct drm_encoder *encoder)

drm_encoder_cleanup(encoder);
kfree(dig_port->hdcp.port_data.streams);
+ intel_dp_link_cleanup(&dig_port->dp);
kfree(dig_port);
}

@@ -4693,11 +4694,16 @@ static int intel_ddi_init_dp_connector(struct intel_digital_port *dig_port)
struct intel_display *display = to_intel_display(dig_port);
struct intel_connector *connector;
enum port port = dig_port->base.port;
+ int err;

connector = intel_connector_alloc();
if (!connector)
return -ENOMEM;

+ err = intel_dp_link_init(&dig_port->dp);
+ if (err)
+ goto err_dp_init;
+
dig_port->dp.output_reg = DDI_BUF_CTL(port);
if (DISPLAY_VER(display) >= 14)
dig_port->dp.prepare_link_retrain = mtl_ddi_prepare_link_retrain;
@@ -4710,8 +4716,9 @@ static int intel_ddi_init_dp_connector(struct intel_digital_port *dig_port)
dig_port->dp.preemph_max = intel_ddi_dp_preemph_max;

if (!intel_dp_init_connector(dig_port, connector)) {
- kfree(connector);
- return -EINVAL;
+ err = -EINVAL;
+
+ goto err_init_connector;
}

if (dig_port->base.type == INTEL_OUTPUT_EDP) {
@@ -4727,6 +4734,13 @@ static int intel_ddi_init_dp_connector(struct intel_digital_port *dig_port)
}

return 0;
+
+err_init_connector:
+ intel_dp_link_cleanup(&dig_port->dp);
+err_dp_init:
+ kfree(connector);
+
+ return err;
}

static int intel_hdmi_reset_link(struct intel_encoder *encoder,
diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
index c819167618502..27714e4cffcdf 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -58,6 +58,7 @@ struct cec_notifier;
struct drm_printer;
struct intel_connector;
struct intel_ddi_buf_trans;
+struct intel_dp_link_training;
struct intel_fbc;
struct intel_global_objs_state;
struct intel_hdcp_shim;
@@ -1853,6 +1854,7 @@ struct intel_dp {
int seq_train_failures;
int force_train_failure;
bool force_retrain;
+ struct intel_dp_link_training *training;
} link;
bool reset_link_params;
int mso_link_count;
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index df34df6610ac2..442610054d7f7 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -7526,3 +7526,34 @@ bool intel_dp_joiner_candidate_valid(struct intel_connector *connector,

return true;
}
+
+/**
+ * intel_dp_link_init - initialize link state
+ * @intel_dp: DP encoder state
+ *
+ * Initialize the link state for @intel_dp and the connectors attached
+ * to it.
+ *
+ * Return:
+ * - %0 in case of successful initialization.
+ * - negative error code in case of failure.
+ */
+int intel_dp_link_init(struct intel_dp *intel_dp)
+{
+ intel_dp->link.training = intel_dp_link_training_init(intel_dp);
+ if (!intel_dp->link.training)
+ return -ENOMEM;
+
+ return 0;
+}
+
+/**
+ * intel_dp_link_cleanup - clean up link state
+ * @intel_dp: DP encoder state
+ *
+ * Clean up the link state for @intel_dp.
+ */
+void intel_dp_link_cleanup(struct intel_dp *intel_dp)
+{
+ intel_dp_link_training_cleanup(intel_dp->link.training);
+}
diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h
index 2849b9ecdc71a..f2abd6059a22a 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.h
+++ b/drivers/gpu/drm/i915/display/intel_dp.h
@@ -238,4 +238,7 @@ bool intel_dp_joiner_candidate_valid(struct intel_connector *connector,
for ((__num_joined_pipes) = 1; (__num_joined_pipes) <= (I915_MAX_PIPES); (__num_joined_pipes)++) \
for_each_if(intel_dp_joiner_candidate_valid(__connector, (__mode)->hdisplay, __num_joined_pipes))

+int intel_dp_link_init(struct intel_dp *intel_dp);
+void intel_dp_link_cleanup(struct intel_dp *intel_dp);
+
#endif /* __INTEL_DP_H__ */
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 a26094223f780..c4e461d24e2ed 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -60,6 +60,10 @@

#define MAX_SEQ_TRAIN_FAILURES 2

+struct intel_dp_link_training {
+ struct intel_dp *dp;
+};
+
static void intel_dp_reset_lttpr_common_caps(struct intel_dp *intel_dp)
{
memset(intel_dp->lttpr_common_caps, 0, sizeof(intel_dp->lttpr_common_caps));
@@ -2217,3 +2221,38 @@ void intel_dp_link_training_debugfs_add(struct intel_connector *connector)
debugfs_create_file("i915_dp_link_retrain_disabled", 0444, root,
connector, &i915_dp_link_retrain_disabled_fops);
}
+
+/**
+ * intel_dp_link_training_init - allocate and initialize link training state
+ * @intel_dp: DP encoder state
+ *
+ * Allocate and initialize the link training state for @intel_dp and the
+ * connectors attached to it.
+ *
+ * Return:
+ * - Pointer to the newly allocated link training state.
+ * - %NULL if allocation fails.
+ */
+struct intel_dp_link_training *intel_dp_link_training_init(struct intel_dp *intel_dp)
+{
+ struct intel_dp_link_training *link_training;
+
+ link_training = kzalloc_obj(*link_training);
+ if (!link_training)
+ return NULL;
+
+ link_training->dp = intel_dp;
+
+ return link_training;
+}
+
+/**
+ * intel_dp_link_training_cleanup - free link training state
+ * @link_training: link training state to free
+ *
+ * Free @link_training.
+ */
+void intel_dp_link_training_cleanup(struct intel_dp_link_training *link_training)
+{
+ kfree(link_training);
+}
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.h b/drivers/gpu/drm/i915/display/intel_dp_link_training.h
index 33dcbde6a4089..e68d51bcb42e1 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.h
@@ -12,6 +12,7 @@ struct intel_atomic_state;
struct intel_connector;
struct intel_crtc_state;
struct intel_dp;
+struct intel_dp_link_training;

int intel_dp_read_dprx_caps(struct intel_dp *intel_dp, u8 dpcd[DP_RECEIVER_CAP_SIZE]);
int intel_dp_init_lttpr_and_dprx_caps(struct intel_dp *intel_dp);
@@ -55,4 +56,7 @@ void intel_dp_128b132b_sdp_crc16(struct intel_dp *intel_dp,

void intel_dp_link_training_debugfs_add(struct intel_connector *connector);

+struct intel_dp_link_training *intel_dp_link_training_init(struct intel_dp *intel_dp);
+void intel_dp_link_training_cleanup(struct intel_dp_link_training *link_training);
+
#endif /* __INTEL_DP_LINK_TRAINING_H__ */
--
2.49.1