From: james qian wang (Arm Technology China) Date: Tue, 22 Jan 2019 11:11:16 +0000 (+0000) Subject: drm/komeda: Add komeda_crtc_atomic_enable/disable X-Git-Tag: v5.4-rc1~971^2~6^2~7 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=b7925b61bd311015e48fdfc8983572d0009e3909;p=platform%2Fkernel%2Flinux-rpi.git drm/komeda: Add komeda_crtc_atomic_enable/disable 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) Signed-off-by: Liviu Dudau --- diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c index ef902bf..6c85d36 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c @@ -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, }; diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.h b/drivers/gpu/drm/arm/display/komeda/komeda_kms.h index beb94ff..7ec571d 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_kms.h +++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.h @@ -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 */ diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h index 3d7a9ee..233e512 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h +++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h @@ -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, diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c index a051651..ae1c377 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c @@ -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) {