summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/msm/disp/dpu1
diff options
context:
space:
mode:
authorRob Clark <robdclark@chromium.org>2022-02-23 11:11:08 -0800
committerRob Clark <robdclark@chromium.org>2022-02-25 07:59:58 -0800
commit9e4dde28e9cd34ee13a6b7247f0857fb49fd3f19 (patch)
tree17fee6c9091477bc662c43c372e91dfa203539f9 /drivers/gpu/drm/msm/disp/dpu1
parentdb22583d6c7da2b20965514a123705cf753c931a (diff)
downloadlinux-9e4dde28e9cd34ee13a6b7247f0857fb49fd3f19.tar.bz2
drm/msm: Avoid dirtyfb stalls on video mode displays (v2)
Someone on IRC once asked an innocent enough sounding question: Why with xf86-video-modesetting is es2gears limited at 120fps. So I broke out the perfetto tracing mesa MR and took a look. It turns out the problem was drm_atomic_helper_dirtyfb(), which would end up waiting for vblank.. es2gears would rapidly push two frames to Xorg, which would blit them to screen and in idle hook (I assume) call the DIRTYFB ioctl. Which in turn would do an atomic update to flush the dirty rects, which would stall until the next vblank. And then the whole process would repeat. But this is a bit silly, we only need dirtyfb for command mode DSI panels. So track in plane state whether dirtyfb is required, and track in the fb how many attached planes require dirtyfb so that we can skip it when not required. (Note, mdp4 does not actually have cmd mode support.) Signed-off-by: Rob Clark <robdclark@chromium.org> Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org> Link: https://lore.kernel.org/r/20220223191118.881321-1-robdclark@gmail.com Signed-off-by: Rob Clark <robdclark@chromium.org>
Diffstat (limited to 'drivers/gpu/drm/msm/disp/dpu1')
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c20
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c5
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h3
3 files changed, 25 insertions, 3 deletions
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
index 662b7bc9c219..7763558ef566 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
@@ -1046,6 +1046,20 @@ struct plane_state {
u32 pipe_id;
};
+static bool dpu_crtc_needs_dirtyfb(struct drm_crtc_state *cstate)
+{
+ struct drm_crtc *crtc = cstate->crtc;
+ struct drm_encoder *encoder;
+
+ drm_for_each_encoder_mask (encoder, crtc->dev, cstate->encoder_mask) {
+ if (dpu_encoder_get_intf_mode(encoder) == INTF_MODE_CMD) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
static int dpu_crtc_atomic_check(struct drm_crtc *crtc,
struct drm_atomic_state *state)
{
@@ -1066,6 +1080,7 @@ static int dpu_crtc_atomic_check(struct drm_crtc *crtc,
const struct drm_plane_state *pipe_staged[SSPP_MAX];
int left_zpos_cnt = 0, right_zpos_cnt = 0;
struct drm_rect crtc_rect = { 0 };
+ bool needs_dirtyfb = dpu_crtc_needs_dirtyfb(crtc_state);
pstates = kzalloc(sizeof(*pstates) * DPU_STAGE_MAX * 4, GFP_KERNEL);
@@ -1097,6 +1112,7 @@ static int dpu_crtc_atomic_check(struct drm_crtc *crtc,
/* get plane state for all drm planes associated with crtc state */
drm_atomic_crtc_state_for_each_plane_state(plane, pstate, crtc_state) {
+ struct dpu_plane_state *dpu_pstate = to_dpu_plane_state(pstate);
struct drm_rect dst, clip = crtc_rect;
if (IS_ERR_OR_NULL(pstate)) {
@@ -1108,11 +1124,13 @@ static int dpu_crtc_atomic_check(struct drm_crtc *crtc,
if (cnt >= DPU_STAGE_MAX * 4)
continue;
- pstates[cnt].dpu_pstate = to_dpu_plane_state(pstate);
+ pstates[cnt].dpu_pstate = dpu_pstate;
pstates[cnt].drm_pstate = pstate;
pstates[cnt].stage = pstate->normalized_zpos;
pstates[cnt].pipe_id = dpu_plane_pipe(plane);
+ dpu_pstate->needs_dirtyfb = needs_dirtyfb;
+
if (pipe_staged[pstates[cnt].pipe_id]) {
multirect_plane[multirect_count].r0 =
pipe_staged[pstates[cnt].pipe_id];
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
index ca75089c9d61..6565682fe227 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
@@ -902,7 +902,7 @@ static int dpu_plane_prepare_fb(struct drm_plane *plane,
if (pstate->aspace) {
ret = msm_framebuffer_prepare(new_state->fb,
- pstate->aspace);
+ pstate->aspace, pstate->needs_dirtyfb);
if (ret) {
DPU_ERROR("failed to prepare framebuffer\n");
return ret;
@@ -933,7 +933,8 @@ static void dpu_plane_cleanup_fb(struct drm_plane *plane,
DPU_DEBUG_PLANE(pdpu, "FB[%u]\n", old_state->fb->base.id);
- msm_framebuffer_cleanup(old_state->fb, old_pstate->aspace);
+ msm_framebuffer_cleanup(old_state->fb, old_pstate->aspace,
+ old_pstate->needs_dirtyfb);
}
static bool dpu_plane_validate_src(struct drm_rect *src,
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
index 9d51dad5c6a5..50781e2d3577 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
@@ -25,6 +25,7 @@
* @pending: whether the current update is still pending
* @plane_fetch_bw: calculated BW per plane
* @plane_clk: calculated clk per plane
+ * @needs_dirtyfb: whether attached CRTC needs pixel data explicitly flushed
*/
struct dpu_plane_state {
struct drm_plane_state base;
@@ -37,6 +38,8 @@ struct dpu_plane_state {
u64 plane_fetch_bw;
u64 plane_clk;
+
+ bool needs_dirtyfb;
};
/**