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@xxxxxxxxx> Tested-by: Hans de Goede <hdegoede@xxxxxxxxxx> Signed-off-by: Hans de Goede <hdegoede@xxxxxxxxxx> --- 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 _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel