drm/komeda: Add komeda_crtc_atomic_enable/disable
authorjames qian wang (Arm Technology China) <james.qian.wang@arm.com>
Tue, 22 Jan 2019 11:11:16 +0000 (11:11 +0000)
committerLiviu Dudau <Liviu.Dudau@arm.com>
Mon, 29 Apr 2019 11:35:57 +0000 (12:35 +0100)
Pass enable/disable command to komeda and adjust komeda hardware for
enable/disable a display instance.

v2: Rebase

Signed-off-by: James Qian Wang (Arm Technology China) <james.qian.wang@arm.com>
Signed-off-by: Liviu Dudau <liviu.dudau@arm.com>
drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
drivers/gpu/drm/arm/display/komeda/komeda_kms.h
drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c

index ef902bf..6c85d36 100644 (file)
@@ -55,7 +55,7 @@ u32 komeda_calc_mclk(struct komeda_crtc_state *kcrtc_st)
  * 1. adjust display operation mode.
  * 2. enable needed clk
  */
-int
+static int
 komeda_crtc_prepare(struct komeda_crtc *kcrtc)
 {
        struct komeda_dev *mdev = kcrtc->base.dev->dev_private;
@@ -111,7 +111,7 @@ unlock:
        return err;
 }
 
-int
+static int
 komeda_crtc_unprepare(struct komeda_crtc *kcrtc)
 {
        struct komeda_dev *mdev = kcrtc->base.dev->dev_private;
@@ -161,9 +161,28 @@ void komeda_crtc_handle_event(struct komeda_crtc   *kcrtc,
        if (events & KOMEDA_EVENT_EOW)
                DRM_DEBUG("EOW.\n");
 
-       /* will handle it with crtc->flush */
-       if (events & KOMEDA_EVENT_FLIP)
-               DRM_DEBUG("FLIP Done.\n");
+       if (events & KOMEDA_EVENT_FLIP) {
+               unsigned long flags;
+               struct drm_pending_vblank_event *event;
+
+               spin_lock_irqsave(&crtc->dev->event_lock, flags);
+               if (kcrtc->disable_done) {
+                       complete_all(kcrtc->disable_done);
+                       kcrtc->disable_done = NULL;
+               } else if (crtc->state->event) {
+                       event = crtc->state->event;
+                       /*
+                        * Consume event before notifying drm core that flip
+                        * happened.
+                        */
+                       crtc->state->event = NULL;
+                       drm_crtc_send_vblank_event(crtc, event);
+               } else {
+                       DRM_WARN("CRTC[%d]: FLIP happen but no pending commit.\n",
+                                drm_crtc_index(&kcrtc->base));
+               }
+               spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
+       }
 }
 
 static void
@@ -188,6 +207,81 @@ komeda_crtc_do_flush(struct drm_crtc *crtc,
 }
 
 static void
+komeda_crtc_atomic_enable(struct drm_crtc *crtc,
+                         struct drm_crtc_state *old)
+{
+       komeda_crtc_prepare(to_kcrtc(crtc));
+       drm_crtc_vblank_on(crtc);
+       komeda_crtc_do_flush(crtc, old);
+}
+
+static void
+komeda_crtc_atomic_disable(struct drm_crtc *crtc,
+                          struct drm_crtc_state *old)
+{
+       struct komeda_crtc *kcrtc = to_kcrtc(crtc);
+       struct komeda_crtc_state *old_st = to_kcrtc_st(old);
+       struct komeda_dev *mdev = crtc->dev->dev_private;
+       struct komeda_pipeline *master = kcrtc->master;
+       struct completion *disable_done = &crtc->state->commit->flip_done;
+       struct completion temp;
+       int timeout;
+
+       DRM_DEBUG_ATOMIC("CRTC%d_DISABLE: active_pipes: 0x%x, affected: 0x%x.\n",
+                        drm_crtc_index(crtc),
+                        old_st->active_pipes, old_st->affected_pipes);
+
+       if (has_bit(master->id, old_st->active_pipes))
+               komeda_pipeline_disable(master, old->state);
+
+       /* crtc_disable has two scenarios according to the state->active switch.
+        * 1. active -> inactive
+        *    this commit is a disable commit. and the commit will be finished
+        *    or done after the disable operation. on this case we can directly
+        *    use the crtc->state->event to tracking the HW disable operation.
+        * 2. active -> active
+        *    the crtc->commit is not for disable, but a modeset operation when
+        *    crtc is active, such commit actually has been completed by 3
+        *    DRM operations:
+        *    crtc_disable, update_planes(crtc_flush), crtc_enable
+        *    so on this case the crtc->commit is for the whole process.
+        *    we can not use it for tracing the disable, we need a temporary
+        *    flip_done for tracing the disable. and crtc->state->event for
+        *    the crtc_enable operation.
+        *    That's also the reason why skip modeset commit in
+        *    komeda_crtc_atomic_flush()
+        */
+       if (crtc->state->active) {
+               struct komeda_pipeline_state *pipe_st;
+               /* clear the old active_comps to zero */
+               pipe_st = komeda_pipeline_get_old_state(master, old->state);
+               pipe_st->active_comps = 0;
+
+               init_completion(&temp);
+               kcrtc->disable_done = &temp;
+               disable_done = &temp;
+       }
+
+       mdev->funcs->flush(mdev, master->id, 0);
+
+       /* wait the disable take affect.*/
+       timeout = wait_for_completion_timeout(disable_done, HZ);
+       if (timeout == 0) {
+               DRM_ERROR("disable pipeline%d timeout.\n", kcrtc->master->id);
+               if (crtc->state->active) {
+                       unsigned long flags;
+
+                       spin_lock_irqsave(&crtc->dev->event_lock, flags);
+                       kcrtc->disable_done = NULL;
+                       spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
+               }
+       }
+
+       drm_crtc_vblank_off(crtc);
+       komeda_crtc_unprepare(kcrtc);
+}
+
+static void
 komeda_crtc_atomic_flush(struct drm_crtc *crtc,
                         struct drm_crtc_state *old)
 {
@@ -251,6 +345,8 @@ static bool komeda_crtc_mode_fixup(struct drm_crtc *crtc,
 struct drm_crtc_helper_funcs komeda_crtc_helper_funcs = {
        .atomic_check   = komeda_crtc_atomic_check,
        .atomic_flush   = komeda_crtc_atomic_flush,
+       .atomic_enable  = komeda_crtc_atomic_enable,
+       .atomic_disable = komeda_crtc_atomic_disable,
        .mode_valid     = komeda_crtc_mode_valid,
        .mode_fixup     = komeda_crtc_mode_fixup,
 };
index beb94ff..7ec571d 100644 (file)
@@ -70,6 +70,9 @@ struct komeda_crtc {
         * merge into the master.
         */
        struct komeda_pipeline *slave;
+
+       /* this flip_done is for tracing the disable */
+       struct completion *disable_done;
 };
 
 /** struct komeda_crtc_state */
index 3d7a9ee..233e512 100644 (file)
@@ -412,6 +412,9 @@ int komeda_build_display_data_flow(struct komeda_crtc *kcrtc,
 int komeda_release_unclaimed_resources(struct komeda_pipeline *pipe,
                                       struct komeda_crtc_state *kcrtc_st);
 
+struct komeda_pipeline_state *
+komeda_pipeline_get_old_state(struct komeda_pipeline *pipe,
+                             struct drm_atomic_state *state);
 void komeda_pipeline_disable(struct komeda_pipeline *pipe,
                             struct drm_atomic_state *old_state);
 void komeda_pipeline_update(struct komeda_pipeline *pipe,
index a051651..ae1c377 100644 (file)
@@ -551,6 +551,38 @@ int komeda_release_unclaimed_resources(struct komeda_pipeline *pipe,
        return 0;
 }
 
+void komeda_pipeline_disable(struct komeda_pipeline *pipe,
+                            struct drm_atomic_state *old_state)
+{
+       struct komeda_pipeline_state *old;
+       struct komeda_component *c;
+       struct komeda_component_state *c_st;
+       u32 id, disabling_comps = 0;
+
+       old = komeda_pipeline_get_old_state(pipe, old_state);
+
+       disabling_comps = old->active_comps;
+       DRM_DEBUG_ATOMIC("PIPE%d: disabling_comps: 0x%x.\n",
+                        pipe->id, disabling_comps);
+
+       dp_for_each_set_bit(id, disabling_comps) {
+               c = komeda_pipeline_get_component(pipe, id);
+               c_st = priv_to_comp_st(c->obj.state);
+
+               /*
+                * If we disabled a component then all active_inputs should be
+                * put in the list of changed_active_inputs, so they get
+                * re-enabled.
+                * This usually happens during a modeset when the pipeline is
+                * first disabled and then the actual state gets committed
+                * again.
+                */
+               c_st->changed_active_inputs |= c_st->active_inputs;
+
+               c->funcs->disable(c);
+       }
+}
+
 void komeda_pipeline_update(struct komeda_pipeline *pipe,
                            struct drm_atomic_state *old_state)
 {