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) <james.qian.wang@arm.com> Signed-off-by: Liviu Dudau <liviu.dudau@arm.com>
This commit is contained in:
parent
20d84aa841
commit
b7925b61bd
|
@ -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
|
||||
|
@ -187,6 +206,81 @@ komeda_crtc_do_flush(struct drm_crtc *crtc,
|
|||
mdev->funcs->flush(mdev, master->id, kcrtc_st->active_pipes);
|
||||
}
|
||||
|
||||
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,
|
||||
};
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue