From: Carsten Haitzler <carsten.haitz...@arm.com>

Sometimes there is an extra dcm crtc state in the pipeline whose
penting vblank event has not been handled yet. We would previously
throw this out and the vblank event never triggers leading to hard
lockups higher up the stack where an expected vlank event never comes
back (screen freezes).

This fixes that by tracking a pending crtc state that needs handling
and handle it producing a vlank event next vblank if it had not
laready been handled before. This fixes the hangs and ensures our
display keeps updating seamlessly and is certainly a much better state
to be in than after some time ending up with a mysteriously frozen
screen and a lot of kernle messages complaining about this too.

Signed-off-by: Carsten Haitzler <carsten.haitz...@arm.com>
---
 .../gpu/drm/arm/display/komeda/komeda_crtc.c  | 10 ++++++++++
 .../gpu/drm/arm/display/komeda/komeda_kms.c   | 19 ++++++++++++++++++-
 .../gpu/drm/arm/display/komeda/komeda_kms.h   |  3 +++
 3 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c 
b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
index 59172acb9738..b7f0a5f97222 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
@@ -227,6 +227,16 @@ void komeda_crtc_handle_event(struct komeda_crtc   *kcrtc,
                        complete_all(kcrtc->disable_done);
                        kcrtc->disable_done = NULL;
                } else if (crtc->state->event) {
+                       if (kcrtc->state_needs_handling) {
+                               event = kcrtc->state_needs_handling->event;
+                               if (event) {
+                                       kcrtc->state_needs_handling->event = 
NULL;
+                                       kcrtc->state_needs_handling = NULL;
+                                       drm_crtc_send_vblank_event(crtc, event);
+                               } else {
+                                       kcrtc->state_needs_handling = NULL;
+                               }
+                       }
                        event = crtc->state->event;
                        /*
                         * Consume event before notifying drm core that flip
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c 
b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c
index 93b7f09b96ca..bbc051a1896a 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c
@@ -226,10 +226,27 @@ static int komeda_kms_check(struct drm_device *dev,
        return 0;
 }
 
+static int komeda_kms_commit(struct drm_device *drm,
+                             struct drm_atomic_state *state,
+                             bool nonblock)
+{
+       int i;
+       struct drm_crtc *crtc;
+       struct drm_crtc_state *old_crtc_state, *new_crtc_state;
+       struct komeda_crtc *kcrtc;
+
+       for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state,
+                                     new_crtc_state, i) {
+               kcrtc = to_kcrtc(crtc);
+               kcrtc->state_needs_handling = crtc->state;
+       }
+       return drm_atomic_helper_commit(drm, state, nonblock);
+}
+
 static const struct drm_mode_config_funcs komeda_mode_config_funcs = {
        .fb_create              = komeda_fb_create,
        .atomic_check           = komeda_kms_check,
-       .atomic_commit          = drm_atomic_helper_commit,
+       .atomic_commit          = komeda_kms_commit,
 };
 
 static void komeda_kms_mode_config_init(struct komeda_kms_dev *kms,
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.h 
b/drivers/gpu/drm/arm/display/komeda/komeda_kms.h
index 456f3c435719..8ff3ad04dfe4 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_kms.h
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.h
@@ -84,6 +84,9 @@ struct komeda_crtc {
 
        /** @disable_done: this flip_done is for tracing the disable */
        struct completion *disable_done;
+
+       /** @state_needs_handling: Has not had it's vblank event handled yet */
+       struct drm_crtc_state *state_needs_handling;
 };
 
 /**
-- 
2.32.0

Reply via email to