diff mbox series

[4/5,SRU,U/OEM-5.10] drm/i915: Add an encoder hook to sanitize its state during init/resume

Message ID 20201221101437.28606-5-koba.ko@canonical.com
State New
Headers show
Series Fix drm_WARN_ON(common_len <= 0) | expand

Commit Message

Koba Ko Dec. 21, 2020, 10:14 a.m. UTC
From: Imre Deak <imre.deak@intel.com>

https://bugs.launchpad.net/bugs/1908885 

Atm, if a full modeset is performed during the initial modeset the link
training will happen with uninitialized max DP rate and lane count. Make
sure the corresponding encoder state is initialized by adding an encoder
hook called during driver init and system resume.

A better alternative would be to store all states in the CRTC state and
make this state available for the link re-training code. Also instead of
the DPCD read in the hook there should be really a proper sink HW
readout in place. Both of these require a bigger rework, so for now opting
for this minimal fix to make at least full initial modesets work.

The patch is based on
https://patchwork.freedesktop.org/patch/101473/?series=10354&rev=3

v2: (Ville)
- s/sanitize_state/sync_state/
- No point in calling the hook when CRTC is disabled, remove the call.
- No point in calling the hook for MST, remove it.

v3: Check only DPCD_REV to avoid clobbering intel_dp->dpcd. (Ville)

Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Imre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20201005230154.1477653-1-imre.deak@intel.com
(cherry picked from commit f9e76a6e68d39a13c269999cfb2df23054c5146b)
Signed-off-by: Koba Ko <koba.ko@canonical.com>
---
 drivers/gpu/drm/i915/display/intel_ddi.c      |  8 ++++++
 drivers/gpu/drm/i915/display/intel_display.c  |  2 ++
 .../drm/i915/display/intel_display_types.h    |  7 +++++
 drivers/gpu/drm/i915/display/intel_dp.c       | 28 +++++++++++++++++++
 drivers/gpu/drm/i915/display/intel_dp.h       |  2 ++
 5 files changed, 47 insertions(+)
diff mbox series

Patch

diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
index 48f0c62f0f02..e19cbb43e028 100644
--- a/drivers/gpu/drm/i915/display/intel_ddi.c
+++ b/drivers/gpu/drm/i915/display/intel_ddi.c
@@ -4551,6 +4551,13 @@  void intel_ddi_get_config(struct intel_encoder *encoder,
 	intel_read_dp_sdp(encoder, pipe_config, DP_SDP_VSC);
 }
 
+static void intel_ddi_sync_state(struct intel_encoder *encoder,
+				 const struct intel_crtc_state *crtc_state)
+{
+	if (intel_crtc_has_dp_encoder(crtc_state))
+		intel_dp_sync_state(encoder, crtc_state);
+}
+
 static bool intel_ddi_initial_fastset_check(struct intel_encoder *encoder,
 					    struct intel_crtc_state *crtc_state)
 {
@@ -5175,6 +5182,7 @@  void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
 	encoder->update_pipe = intel_ddi_update_pipe;
 	encoder->get_hw_state = intel_ddi_get_hw_state;
 	encoder->get_config = intel_ddi_get_config;
+	encoder->sync_state = intel_ddi_sync_state;
 	encoder->initial_fastset_check = intel_ddi_initial_fastset_check;
 	encoder->suspend = intel_dp_encoder_suspend;
 	encoder->get_power_domains = intel_ddi_get_power_domains;
diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
index 6c454ca87da0..320aa000de14 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -18511,6 +18511,8 @@  static void intel_modeset_readout_hw_state(struct drm_device *dev)
 
 			encoder->base.crtc = &crtc->base;
 			encoder->get_config(encoder, crtc_state);
+			if (encoder->sync_state)
+				encoder->sync_state(encoder, crtc_state);
 		} else {
 			encoder->base.crtc = NULL;
 		}
diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
index 56b953052e9a..cb32688f0434 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -188,6 +188,13 @@  struct intel_encoder {
 	void (*get_config)(struct intel_encoder *,
 			   struct intel_crtc_state *pipe_config);
 
+	/*
+	 * Optional hook called during init/resume to sync any state
+	 * stored in the encoder (eg. DP link parameters) wrt. the HW state.
+	 */
+	void (*sync_state)(struct intel_encoder *encoder,
+			   const struct intel_crtc_state *crtc_state);
+
 	/*
 	 * Optional hook, returning true if this encoder allows a fastset
 	 * during the initial commit, false otherwise.
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 6f525fdd9eb1..aa4a03aa623a 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -3691,6 +3691,33 @@  static void intel_dp_get_config(struct intel_encoder *encoder,
 	}
 }
 
+static bool
+intel_dp_get_dpcd(struct intel_dp *intel_dp);
+
+/**
+ * intel_dp_sync_state - sync the encoder state during init/resume
+ * @encoder: intel encoder to sync
+ * @crtc_state: state for the CRTC connected to the encoder
+ *
+ * Sync any state stored in the encoder wrt. HW state during driver init
+ * and system resume.
+ */
+void intel_dp_sync_state(struct intel_encoder *encoder,
+			 const struct intel_crtc_state *crtc_state)
+{
+	struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+
+	/*
+	 * Don't clobber DPCD if it's been already read out during output
+	 * setup (eDP) or detect.
+	 */
+	if (intel_dp->dpcd[DP_DPCD_REV] == 0)
+		intel_dp_get_dpcd(intel_dp);
+
+	intel_dp->max_link_lane_count = intel_dp_max_common_lane_count(intel_dp);
+	intel_dp->max_link_rate = intel_dp_max_common_rate(intel_dp);
+}
+
 bool intel_dp_initial_fastset_check(struct intel_encoder *encoder,
 				    struct intel_crtc_state *crtc_state)
 {
@@ -8067,6 +8094,7 @@  bool intel_dp_init(struct drm_i915_private *dev_priv,
 	intel_encoder->compute_config = intel_dp_compute_config;
 	intel_encoder->get_hw_state = intel_dp_get_hw_state;
 	intel_encoder->get_config = intel_dp_get_config;
+	intel_encoder->sync_state = intel_dp_sync_state;
 	intel_encoder->initial_fastset_check = intel_dp_initial_fastset_check;
 	intel_encoder->update_pipe = intel_panel_update_backlight;
 	intel_encoder->suspend = intel_dp_encoder_suspend;
diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h
index 9d560ccfef02..3c916cdaf2f5 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.h
+++ b/drivers/gpu/drm/i915/display/intel_dp.h
@@ -138,5 +138,7 @@  int intel_dp_init_hdcp(struct intel_digital_port *dig_port,
 
 bool intel_dp_initial_fastset_check(struct intel_encoder *encoder,
 				    struct intel_crtc_state *crtc_state);
+void intel_dp_sync_state(struct intel_encoder *encoder,
+			 const struct intel_crtc_state *crtc_state);
 
 #endif /* __INTEL_DP_H__ */