Skip to content

Commit

Permalink
drm/rockchip: Disallow PSR for the whole atomic commit
Browse files Browse the repository at this point in the history
Currently PSR flush is triggered from CRTC's .atomic_begin() callback,
which is executed after modeset disables and enables and before plane
updates are committed. Since PSR flush and re-enable can be triggered
asynchronously by external sources (input event, delayed work), it can
race with hardware programming done in the aforementioned stages.

This patch blocks the PSR completely before hardware programming part
begins and unblock after it ends. This relies on reference counted PSR
disable introduced with previous patch.

Cc: Kristian H. Kristensen <[email protected]>
Signed-off-by: Tomasz Figa <[email protected]>
Signed-off-by: Sean Paul <[email protected]>
Signed-off-by: Thierry Escande <[email protected]>
Signed-off-by: Enric Balletbo i Serra <[email protected]>
Tested-by: Marek Szyprowski <[email protected]>
Reviewed-by: Andrzej Hajda <[email protected]>
Signed-off-by: Andrzej Hajda <[email protected]>
Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
  • Loading branch information
tom3q authored and Andrzej Hajda committed Apr 24, 2018
1 parent 6e6cf3e commit d2d4f51
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 8 deletions.
61 changes: 60 additions & 1 deletion drivers/gpu/drm/rockchip/rockchip_drm_fb.c
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,67 @@ rockchip_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
return ERR_PTR(ret);
}

static void
rockchip_drm_psr_inhibit_get_state(struct drm_atomic_state *state)
{
struct drm_crtc *crtc;
struct drm_crtc_state *crtc_state;
struct drm_encoder *encoder;
u32 encoder_mask = 0;
int i;

for_each_old_crtc_in_state(state, crtc, crtc_state, i) {
encoder_mask |= crtc_state->encoder_mask;
encoder_mask |= crtc->state->encoder_mask;
}

drm_for_each_encoder_mask(encoder, state->dev, encoder_mask)
rockchip_drm_psr_inhibit_get(encoder);
}

static void
rockchip_drm_psr_inhibit_put_state(struct drm_atomic_state *state)
{
struct drm_crtc *crtc;
struct drm_crtc_state *crtc_state;
struct drm_encoder *encoder;
u32 encoder_mask = 0;
int i;

for_each_old_crtc_in_state(state, crtc, crtc_state, i) {
encoder_mask |= crtc_state->encoder_mask;
encoder_mask |= crtc->state->encoder_mask;
}

drm_for_each_encoder_mask(encoder, state->dev, encoder_mask)
rockchip_drm_psr_inhibit_put(encoder);
}

static void
rockchip_atomic_helper_commit_tail_rpm(struct drm_atomic_state *old_state)
{
struct drm_device *dev = old_state->dev;

rockchip_drm_psr_inhibit_get_state(old_state);

drm_atomic_helper_commit_modeset_disables(dev, old_state);

drm_atomic_helper_commit_modeset_enables(dev, old_state);

drm_atomic_helper_commit_planes(dev, old_state,
DRM_PLANE_COMMIT_ACTIVE_ONLY);

rockchip_drm_psr_inhibit_put_state(old_state);

drm_atomic_helper_commit_hw_done(old_state);

drm_atomic_helper_wait_for_vblanks(dev, old_state);

drm_atomic_helper_cleanup_planes(dev, old_state);
}

static const struct drm_mode_config_helper_funcs rockchip_mode_config_helpers = {
.atomic_commit_tail = drm_atomic_helper_commit_tail_rpm,
.atomic_commit_tail = rockchip_atomic_helper_commit_tail_rpm,
};

static const struct drm_mode_config_funcs rockchip_drm_mode_config_funcs = {
Expand Down
7 changes: 0 additions & 7 deletions drivers/gpu/drm/rockchip/rockchip_drm_vop.c
Original file line number Diff line number Diff line change
Expand Up @@ -1029,16 +1029,9 @@ static void vop_crtc_atomic_flush(struct drm_crtc *crtc,
}
}

static void vop_crtc_atomic_begin(struct drm_crtc *crtc,
struct drm_crtc_state *old_crtc_state)
{
rockchip_drm_psr_flush(crtc);
}

static const struct drm_crtc_helper_funcs vop_crtc_helper_funcs = {
.mode_fixup = vop_crtc_mode_fixup,
.atomic_flush = vop_crtc_atomic_flush,
.atomic_begin = vop_crtc_atomic_begin,
.atomic_enable = vop_crtc_atomic_enable,
.atomic_disable = vop_crtc_atomic_disable,
};
Expand Down

0 comments on commit d2d4f51

Please sign in to comment.