[Intel-gfx] [PATCH] drm/i915: Fix DSI panels with v1 MIPI sequences without a DEASSERT sequence

Hans de Goede j.w.r.degoede at gmail.com
Thu Jan 25 13:37:26 UTC 2018


So far models of the Dell Venue 8 Pro, with a panel with MIPI panel
index = 3, one of which has been kindly provided to me by Jan Brummer,
where not working with the i915 driver, giving a black screen on the
first modeset.

The problem with at least these Dells is that their VBT defines a MIPI
ASSERT sequence, but not a DEASSERT sequence. Instead they DEASSERT the
reset in their INIT_OTP sequence, but the deassert must be done before
calling intel_dsi_device_ready(), so that is too late.

Simply doing the INIT_OTP sequence earlier is not enough to fix this,
because the INIT_OTP sequence also sends various MIPI packets to the
panel, which can only happen after calling intel_dsi_device_ready().

This commit fixes this by making mipi_exec_send_packet() call
intel_dsi_device_ready() if not done already, so that we can call the
INIT_OTP sequence earlier on affected devices.

Note that this only changes the init-sequence on devices for which
intel_dsi_use_init_otp_as_deassert() returns true, on other devices
intel_dsi->device_ready will be set to true before calling any
MIPI sequences which may send packets, so the check added to
mipi_exec_send_packet() is a nop there.

BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=82880
Related: https://bugs.freedesktop.org/show_bug.cgi?id=101205
Reported-by: Jan-Michael Brummer <jan.brummer at tabos.org>
Tested-by: Hans de Goede <hdegoede at redhat.com>
Signed-off-by: Hans de Goede <hdegoede at redhat.com>
---
 drivers/gpu/drm/i915/intel_dsi.c     | 53 ++++++++++++++++++++++++++++++++++--
 drivers/gpu/drm/i915/intel_dsi.h     |  4 +++
 drivers/gpu/drm/i915/intel_dsi_vbt.c |  6 ++++
 3 files changed, 60 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c
index f67d321376e4..3d82811a38f3 100644
--- a/drivers/gpu/drm/i915/intel_dsi.c
+++ b/drivers/gpu/drm/i915/intel_dsi.c
@@ -539,9 +539,14 @@ static void vlv_dsi_device_ready(struct intel_encoder *encoder)
 	}
 }
 
-static void intel_dsi_device_ready(struct intel_encoder *encoder)
+void intel_dsi_device_ready(struct intel_encoder *encoder)
 {
 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+	struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+
+	/* Already done? */
+	if (intel_dsi->device_ready)
+		return;
 
 	if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
 		vlv_dsi_device_ready(encoder);
@@ -549,6 +554,8 @@ static void intel_dsi_device_ready(struct intel_encoder *encoder)
 		bxt_dsi_device_ready(encoder);
 	else if (IS_GEMINILAKE(dev_priv))
 		glk_dsi_device_ready(encoder);
+
+	intel_dsi->device_ready = true;
 }
 
 static void glk_dsi_enter_low_power_mode(struct intel_encoder *encoder)
@@ -786,6 +793,36 @@ static void intel_dsi_msleep(struct intel_dsi *intel_dsi, int msec)
  * - wait t4                                           - wait t4
  */
 
+/*
+ * Some v1 VBT MIPI sequences do the deassert in the init OTP sequence.
+ * The deassert must be done before calling intel_dsi_device_ready, while
+ * intel_dsi_device_ready() must be called before any send packet ops inside
+ * the init OTP sequence. mipi_exec_send_packet() deals with calling
+ * intel_dsi_device_ready() if necessary. This function checks if we need
+ * to call init OTP at deassert time.
+ */
+static bool intel_dsi_use_init_otp_as_deassert(struct intel_dsi *intel_dsi)
+{
+	struct drm_i915_private *dev_priv = to_i915(intel_dsi->base.base.dev);
+
+	/* Limit this to VLV for now. */
+	if (!IS_VALLEYVIEW(dev_priv))
+		return false;
+
+	/* Limit this to v1 vid-mode sequences */
+	if (!is_vid_mode(intel_dsi) || dev_priv->vbt.dsi.seq_version != 1)
+		return false;
+
+	/* If there is an assert-reset seq and no deassert one, use init OTP */
+	if (dev_priv->vbt.dsi.sequence[MIPI_SEQ_ASSERT_RESET] != 0 &&
+	    dev_priv->vbt.dsi.sequence[MIPI_SEQ_DEASSERT_RESET] == 0) {
+		DRM_DEBUG_KMS("Using init OTP to deassert reset\n");
+		return true;
+	}
+
+	return false;
+}
+
 static void intel_dsi_pre_enable(struct intel_encoder *encoder,
 				 const struct intel_crtc_state *pipe_config,
 				 const struct drm_connector_state *conn_state)
@@ -840,7 +877,10 @@ static void intel_dsi_pre_enable(struct intel_encoder *encoder,
 	intel_dsi_msleep(intel_dsi, intel_dsi->panel_on_delay);
 
 	/* Deassert reset */
-	intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DEASSERT_RESET);
+	if (intel_dsi_use_init_otp_as_deassert(intel_dsi))
+		intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_INIT_OTP);
+	else
+		intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DEASSERT_RESET);
 
 	if (IS_GEMINILAKE(dev_priv)) {
 		glk_cold_boot = glk_dsi_enable_io(encoder);
@@ -858,7 +898,8 @@ static void intel_dsi_pre_enable(struct intel_encoder *encoder,
 		intel_dsi_prepare(encoder, pipe_config);
 
 	/* Send initialization commands in LP mode */
-	intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_INIT_OTP);
+	if (!intel_dsi_use_init_otp_as_deassert(intel_dsi))
+		intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_INIT_OTP);
 
 	/* Enable port in pre-enable phase itself because as per hw team
 	 * recommendation, port should be enabled befor plane & pipe */
@@ -925,12 +966,15 @@ static void intel_dsi_disable(struct intel_encoder *encoder,
 static void intel_dsi_clear_device_ready(struct intel_encoder *encoder)
 {
 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+	struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
 
 	if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv) ||
 	    IS_BROXTON(dev_priv))
 		vlv_dsi_clear_device_ready(encoder);
 	else if (IS_GEMINILAKE(dev_priv))
 		glk_dsi_clear_device_ready(encoder);
+
+	intel_dsi->device_ready = false;
 }
 
 static void intel_dsi_post_disable(struct intel_encoder *encoder,
@@ -944,6 +988,9 @@ static void intel_dsi_post_disable(struct intel_encoder *encoder,
 
 	DRM_DEBUG_KMS("\n");
 
+	/* in case the dsi panel is on when the i915 driver gets loaded */
+	intel_dsi->device_ready = true;
+
 	if (is_vid_mode(intel_dsi)) {
 		for_each_dsi_port(port, intel_dsi->ports)
 			wait_for_dsi_fifo_empty(intel_dsi, port);
diff --git a/drivers/gpu/drm/i915/intel_dsi.h b/drivers/gpu/drm/i915/intel_dsi.h
index 7afeb9580f41..d501cbcc97d0 100644
--- a/drivers/gpu/drm/i915/intel_dsi.h
+++ b/drivers/gpu/drm/i915/intel_dsi.h
@@ -46,6 +46,9 @@ struct intel_dsi {
 
 	struct intel_connector *attached_connector;
 
+	/* Have we put the device in ready state (LP-11) ? */
+	bool device_ready;
+
 	/* bit mask of ports being driven */
 	u16 ports;
 
@@ -132,6 +135,7 @@ static inline struct intel_dsi *enc_to_intel_dsi(struct drm_encoder *encoder)
 /* intel_dsi.c */
 void wait_for_dsi_fifo_empty(struct intel_dsi *intel_dsi, enum port port);
 enum mipi_dsi_pixel_format pixel_format_from_register_bits(u32 fmt);
+void intel_dsi_device_ready(struct intel_encoder *encoder);
 
 /* intel_dsi_pll.c */
 bool intel_dsi_pll_is_enabled(struct drm_i915_private *dev_priv);
diff --git a/drivers/gpu/drm/i915/intel_dsi_vbt.c b/drivers/gpu/drm/i915/intel_dsi_vbt.c
index 91c07b0c8db9..cf4e9e2a8df1 100644
--- a/drivers/gpu/drm/i915/intel_dsi_vbt.c
+++ b/drivers/gpu/drm/i915/intel_dsi_vbt.c
@@ -118,6 +118,12 @@ static const u8 *mipi_exec_send_packet(struct intel_dsi *intel_dsi,
 
 	DRM_DEBUG_KMS("\n");
 
+	/* Make sure the device is in ready state (LP-11) */
+	if (!intel_dsi->device_ready) {
+		intel_dsi_device_ready(&intel_dsi->base);
+		usleep_range(10000, 20000);
+	}
+
 	flags = *data++;
 	type = *data++;
 
-- 
2.14.3



More information about the Intel-gfx mailing list