summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/i915/Makefile1
-rw-r--r--drivers/gpu/drm/i915/display/g4x_dp.c13
-rw-r--r--drivers/gpu/drm/i915/display/intel_ddi.c19
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_types.h5
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp.c21
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp.h1
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp_link_training.c13
-rw-r--r--drivers/gpu/drm/i915/display/intel_encoder.c39
-rw-r--r--drivers/gpu/drm/i915/display/intel_encoder.h16
-rw-r--r--drivers/gpu/drm/xe/Makefile1
10 files changed, 124 insertions, 5 deletions
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 06e6486c07b5..23840e53acba 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -329,6 +329,7 @@ i915-y += \
display/intel_dsi_dcs_backlight.o \
display/intel_dsi_vbt.o \
display/intel_dvo.o \
+ display/intel_encoder.o \
display/intel_gmbus.o \
display/intel_hdmi.o \
display/intel_lspcon.o \
diff --git a/drivers/gpu/drm/i915/display/g4x_dp.c b/drivers/gpu/drm/i915/display/g4x_dp.c
index 40fee8380a81..4d279cadf7e2 100644
--- a/drivers/gpu/drm/i915/display/g4x_dp.c
+++ b/drivers/gpu/drm/i915/display/g4x_dp.c
@@ -20,6 +20,7 @@
#include "intel_dp_aux.h"
#include "intel_dp_link_training.h"
#include "intel_dpio_phy.h"
+#include "intel_encoder.h"
#include "intel_fifo_underrun.h"
#include "intel_hdmi.h"
#include "intel_hotplug.h"
@@ -1239,6 +1240,15 @@ static bool ilk_digital_port_connected(struct intel_encoder *encoder)
return intel_de_read(dev_priv, DEISR) & bit;
}
+static void g4x_dp_suspend_complete(struct intel_encoder *encoder)
+{
+ /*
+ * TODO: Move this to intel_dp_encoder_suspend(),
+ * once modeset locking around that is removed.
+ */
+ intel_encoder_link_check_flush_work(encoder);
+}
+
static void intel_dp_encoder_destroy(struct drm_encoder *encoder)
{
intel_dp_encoder_flush_work(encoder);
@@ -1325,6 +1335,8 @@ bool g4x_dp_init(struct drm_i915_private *dev_priv,
"DP %c", port_name(port)))
goto err_encoder_init;
+ intel_encoder_link_check_init(intel_encoder, intel_dp_link_check);
+
intel_encoder->hotplug = intel_dp_hotplug;
intel_encoder->compute_config = intel_dp_compute_config;
intel_encoder->get_hw_state = intel_dp_get_hw_state;
@@ -1333,6 +1345,7 @@ bool g4x_dp_init(struct drm_i915_private *dev_priv,
intel_encoder->initial_fastset_check = intel_dp_initial_fastset_check;
intel_encoder->update_pipe = intel_backlight_update;
intel_encoder->suspend = intel_dp_encoder_suspend;
+ intel_encoder->suspend_complete = g4x_dp_suspend_complete;
intel_encoder->shutdown = intel_dp_encoder_shutdown;
if (IS_CHERRYVIEW(dev_priv)) {
intel_encoder->pre_pll_enable = chv_dp_pre_pll_enable;
diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
index 4e033e4066b1..823c66ad8988 100644
--- a/drivers/gpu/drm/i915/display/intel_ddi.c
+++ b/drivers/gpu/drm/i915/display/intel_ddi.c
@@ -57,6 +57,7 @@
#include "intel_dp_tunnel.h"
#include "intel_dpio_phy.h"
#include "intel_dsi.h"
+#include "intel_encoder.h"
#include "intel_fdi.h"
#include "intel_fifo_underrun.h"
#include "intel_gmbus.h"
@@ -4525,6 +4526,17 @@ static int intel_hdmi_reset_link(struct intel_encoder *encoder,
return intel_modeset_commit_pipes(dev_priv, BIT(crtc->pipe), ctx);
}
+static void intel_ddi_link_check(struct intel_encoder *encoder)
+{
+ struct drm_i915_private *i915 = to_i915(encoder->base.dev);
+ struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
+
+ /* TODO: Move checking the HDMI link state here as well. */
+ drm_WARN_ON(&i915->drm, !dig_port->dp.attached_connector);
+
+ intel_dp_link_check(encoder);
+}
+
static enum intel_hotplug_state
intel_ddi_hotplug(struct intel_encoder *encoder,
struct intel_connector *connector)
@@ -4768,6 +4780,11 @@ static void intel_ddi_tc_encoder_suspend_complete(struct intel_encoder *encoder)
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+ /*
+ * TODO: Move this to intel_dp_encoder_suspend(),
+ * once modeset locking around that is removed.
+ */
+ intel_encoder_link_check_flush_work(encoder);
intel_tc_port_suspend(dig_port);
}
@@ -4958,6 +4975,8 @@ void intel_ddi_init(struct drm_i915_private *dev_priv,
"DDI %c/PHY %c", port_name(port), phy_name(phy));
}
+ intel_encoder_link_check_init(encoder, intel_ddi_link_check);
+
mutex_init(&dig_port->hdcp_mutex);
dig_port->num_hdcp_streams = 0;
diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
index 3e493472cf06..1af3d48a7b86 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -161,6 +161,11 @@ struct intel_encoder {
enum port port;
u16 cloneable;
u8 pipe_mask;
+
+ /* Check and recover a bad link state. */
+ struct delayed_work link_check_work;
+ void (*link_check)(struct intel_encoder *encoder);
+
enum intel_hotplug_state (*hotplug)(struct intel_encoder *encoder,
struct intel_connector *connector);
enum intel_output_type (*compute_output_type)(struct intel_encoder *,
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index edd3e0e7085f..0833302baabc 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -69,6 +69,7 @@
#include "intel_dpio_phy.h"
#include "intel_dpll.h"
#include "intel_drrs.h"
+#include "intel_encoder.h"
#include "intel_fifo_underrun.h"
#include "intel_hdcp.h"
#include "intel_hdmi.h"
@@ -76,6 +77,7 @@
#include "intel_hotplug_irq.h"
#include "intel_lspcon.h"
#include "intel_lvds.h"
+#include "intel_modeset_lock.h"
#include "intel_panel.h"
#include "intel_pch_display.h"
#include "intel_pps.h"
@@ -5248,6 +5250,18 @@ int intel_dp_retrain_link(struct intel_encoder *encoder,
return 0;
}
+void intel_dp_link_check(struct intel_encoder *encoder)
+{
+ struct drm_i915_private *i915 = to_i915(encoder->base.dev);
+ struct drm_modeset_acquire_ctx ctx;
+ int ret;
+
+ intel_modeset_lock_ctx_retry(&ctx, NULL, 0, ret)
+ ret = intel_dp_retrain_link(encoder, &ctx);
+
+ drm_WARN_ON(&i915->drm, ret);
+}
+
static int intel_dp_prep_phy_test(struct intel_dp *intel_dp,
struct drm_modeset_acquire_ctx *ctx,
u8 *pipe_mask)
@@ -6014,11 +6028,14 @@ void intel_dp_connector_sync_state(struct intel_connector *connector,
}
}
-void intel_dp_encoder_flush_work(struct drm_encoder *encoder)
+void intel_dp_encoder_flush_work(struct drm_encoder *_encoder)
{
- struct intel_digital_port *dig_port = enc_to_dig_port(to_intel_encoder(encoder));
+ struct intel_encoder *encoder = to_intel_encoder(_encoder);
+ struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
struct intel_dp *intel_dp = &dig_port->dp;
+ intel_encoder_link_check_flush_work(encoder);
+
intel_dp_mst_encoder_cleanup(dig_port);
intel_dp_tunnel_destroy(intel_dp);
diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h
index 0d169027067f..79193af55518 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.h
+++ b/drivers/gpu/drm/i915/display/intel_dp.h
@@ -60,6 +60,7 @@ int intel_dp_get_active_pipes(struct intel_dp *intel_dp,
u8 *pipe_mask);
int intel_dp_retrain_link(struct intel_encoder *encoder,
struct drm_modeset_acquire_ctx *ctx);
+void intel_dp_link_check(struct intel_encoder *encoder);
void intel_dp_set_power(struct intel_dp *intel_dp, u8 mode);
void intel_dp_configure_protocol_converter(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state);
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 190372cf76e5..1164255cf5f2 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 "intel_display_types.h"
#include "intel_dp.h"
#include "intel_dp_link_training.h"
+#include "intel_encoder.h"
#include "intel_panel.h"
#define LT_MSG_PREFIX "[CONNECTOR:%d:%s][ENCODER:%d:%s][%s] "
@@ -1464,6 +1465,8 @@ void intel_dp_start_link_train(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
+ struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+ struct intel_encoder *encoder = &dig_port->base;
bool passed;
/*
@@ -1483,6 +1486,11 @@ void intel_dp_start_link_train(struct intel_dp *intel_dp,
else
passed = intel_dp_link_train_all_phys(intel_dp, crtc_state, lttpr_count);
+ if (passed) {
+ intel_encoder_link_check_queue_work(encoder, 2000);
+ return;
+ }
+
/*
* Ignore the link failure in CI
*
@@ -1495,13 +1503,12 @@ void intel_dp_start_link_train(struct intel_dp *intel_dp,
* For test cases which rely on the link training or processing of HPDs
* ignore_long_hpd flag can unset from the testcase.
*/
- if (!passed && i915->display.hotplug.ignore_long_hpd) {
+ if (i915->display.hotplug.ignore_long_hpd) {
lt_dbg(intel_dp, DP_PHY_DPRX, "Ignore the link failure\n");
return;
}
- if (!passed)
- intel_dp_schedule_fallback_link_training(intel_dp, crtc_state);
+ intel_dp_schedule_fallback_link_training(intel_dp, crtc_state);
}
void intel_dp_128b132b_sdp_crc16(struct intel_dp *intel_dp,
diff --git a/drivers/gpu/drm/i915/display/intel_encoder.c b/drivers/gpu/drm/i915/display/intel_encoder.c
new file mode 100644
index 000000000000..dee55f56960f
--- /dev/null
+++ b/drivers/gpu/drm/i915/display/intel_encoder.c
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2024 Intel Corporation
+ */
+
+#include <linux/workqueue.h>
+
+#include "i915_drv.h"
+
+#include "intel_display_types.h"
+#include "intel_encoder.h"
+
+static void intel_encoder_link_check_work_fn(struct work_struct *work)
+{
+ struct intel_encoder *encoder =
+ container_of(work, typeof(*encoder), link_check_work.work);
+
+ encoder->link_check(encoder);
+}
+
+void intel_encoder_link_check_init(struct intel_encoder *encoder,
+ void (*callback)(struct intel_encoder *encoder))
+{
+ INIT_DELAYED_WORK(&encoder->link_check_work, intel_encoder_link_check_work_fn);
+ encoder->link_check = callback;
+}
+
+void intel_encoder_link_check_flush_work(struct intel_encoder *encoder)
+{
+ cancel_delayed_work_sync(&encoder->link_check_work);
+}
+
+void intel_encoder_link_check_queue_work(struct intel_encoder *encoder, int delay_ms)
+{
+ struct drm_i915_private *i915 = to_i915(encoder->base.dev);
+
+ mod_delayed_work(i915->unordered_wq,
+ &encoder->link_check_work, msecs_to_jiffies(delay_ms));
+}
diff --git a/drivers/gpu/drm/i915/display/intel_encoder.h b/drivers/gpu/drm/i915/display/intel_encoder.h
new file mode 100644
index 000000000000..2cda054e2b15
--- /dev/null
+++ b/drivers/gpu/drm/i915/display/intel_encoder.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2024 Intel Corporation
+ */
+
+#ifndef __INTEL_ENCODER_H__
+#define __INTEL_ENCODER_H__
+
+struct intel_encoder;
+
+void intel_encoder_link_check_init(struct intel_encoder *encoder,
+ void (*callback)(struct intel_encoder *encoder));
+void intel_encoder_link_check_queue_work(struct intel_encoder *encoder, int delay_ms);
+void intel_encoder_link_check_flush_work(struct intel_encoder *encoder);
+
+#endif /* __INTEL_ENCODER_H__ */
diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile
index 0132397a1a31..1e5d88d6a152 100644
--- a/drivers/gpu/drm/xe/Makefile
+++ b/drivers/gpu/drm/xe/Makefile
@@ -258,6 +258,7 @@ xe-$(CONFIG_DRM_XE_DISPLAY) += \
i915-display/intel_dsi.o \
i915-display/intel_dsi_dcs_backlight.o \
i915-display/intel_dsi_vbt.o \
+ i915-display/intel_encoder.o \
i915-display/intel_fb.o \
i915-display/intel_fbc.o \
i915-display/intel_fdi.o \