[RFC 14/14] drm/i915: send one frame after enabling mipi cmd mode

Gaurav K Singh
2015-05-29T10:40:14Z

If MIPI is operated in command mode, and after display reset. if
not even one frame is sent after enabling the pipe and then if it
is disabled, pipe is getting stuck. This patch will fix this issue
by sending one frame after enabling the pipe.

Ideally,there should not be a case where there is mode set and no frames
are sent.

Signed-off-by: Gaurav K Singh <gaurav.k.singh@intel.com>
Signed-off-by: Yogesh Mohan Marimuthu <yogesh.mohan.marimuthu@intel.com>
---
drivers/gpu/drm/i915/intel_display.c | 46 ++++++++++++++++++++++++++++++++++
drivers/gpu/drm/i915/intel_drv.h | 6 +++++
2 files changed, 52 insertions(+)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 8dd0066..46e7f0b 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -5905,6 +5905,7 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc)
struct drm_i915_private *dev_priv = to_i915(dev);
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
struct intel_encoder *encoder;
+ struct intel_dsi *intel_dsi;
int pipe = intel_crtc->pipe;
bool is_dsi;

@@ -5967,6 +5968,25 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc)

for_each_encoder_on_crtc(dev, crtc, encoder)
encoder->enable(encoder);
+
+ for_each_encoder_on_crtc(dev, crtc, encoder) {
+ if (encoder->type != INTEL_OUTPUT_DSI)
+ continue;
+
+ intel_dsi = enc_to_intel_dsi(&encoder->base);
+ if (intel_dsi->operation_mode == INTEL_DSI_COMMAND_MODE) {
+ /*
+ * save the current pipe counter. During disable use
+ * this variable to check if at least one frame has
+ * been sent. If no frame is sent and MIPI is disabled
+ * in command mode, then pipe gets stuck.
+ */
+ intel_crtc->hw_frm_cnt_at_enable =
+ I915_READ(PIPEFRAME(pipe));
+ }
+ break;
+ }
+
}

static void i9xx_set_pll_dividers(struct intel_crtc *crtc)
@@ -6065,6 +6085,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
struct intel_encoder *encoder;
+ struct intel_dsi *intel_dsi;
int pipe = intel_crtc->pipe;
bool all_pipe_disabled;
u32 val;
@@ -6072,6 +6093,31 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
if (!intel_crtc->active)
return;

+ for_each_encoder_on_crtc(dev, crtc, encoder) {
+ if (encoder->type != INTEL_OUTPUT_DSI)
+ continue;
+
+ intel_dsi = enc_to_intel_dsi(&encoder->base);
+ if ((intel_dsi->operation_mode == INTEL_DSI_COMMAND_MODE) &&
+ (intel_crtc->hw_frm_cnt_at_enable ==
+ I915_READ(PIPEFRAME(pipe)))) {
+
+ intel_dsi_update_panel_fb(encoder);
+
+ /*
+ * wait for ~2 frames for TE interrupt and sending one
+ * frame.
+ */
+ msleep(40);
+
+ if (intel_crtc->hw_frm_cnt_at_enable ==
+ I915_READ(PIPEFRAME(pipe)))
+ DRM_ERROR("Pipe is stuck for DSI cmd mode.");
+ }
+
+ break;
+ }
+
/*
* On gen2 planes are double buffered but the pipe isn't, so we must
* wait for planes to fully turn off before disabling the pipe.
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 7c59862..e453934 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -550,6 +550,12 @@ struct intel_crtc {

/* scalers available on this crtc */
int num_scalers;
+
+ /*
+ * save the frame counter at enable sequence to make sure one frame has
+ * been sent before disable sequence.
+ */
+ u32 hw_frm_cnt_at_enable;
};

struct intel_plane_wm_parameters {
--
1.7.9.5