From 236c48e692458fb55ec96ac1823a176f2bce09f1 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 2 Mar 2017 19:14:58 +0200 Subject: [PATCH] drm/i915: Skip useless watermark/FIFO related work on VLV/CHV when not needed MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Check whether anything relevant has actually change when we compute new watermarks for each plane in the state. If the watermarks for no primary/sprite planes changed we don't have to recompute the FIFO split or reprogram the DSBARB registers. And even the cursor watermarks didn't change we can skip the merge+invert step between all the planes on the pipe as well. v2: s/noninverted/raw/ for consistency with other platforms v3: Drop duplicated vlv_get_fifo_size() call during init Signed-off-by: Ville Syrjälä Reviewed-by: Maarten Lankhorst Link: http://patchwork.freedesktop.org/patch/msgid/20170302171508.1666-9-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/intel_atomic.c | 1 + drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_pm.c | 71 +++++++++++++++++++++++------ 3 files changed, 58 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index e65818e5d2ab..50fb1f76cc5f 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -99,6 +99,7 @@ intel_crtc_duplicate_state(struct drm_crtc *crtc) crtc_state->update_wm_pre = false; crtc_state->update_wm_post = false; crtc_state->fb_changed = false; + crtc_state->fifo_changed = false; crtc_state->wm.need_postvbl_update = false; crtc_state->fb_bits = 0; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 2f23521f0e00..1e05da992aa0 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -573,6 +573,7 @@ struct intel_crtc_state { bool disable_cxsr; bool update_wm_pre, update_wm_post; /* watermarks are updated */ bool fb_changed; /* fb on any of the planes is changed */ + bool fifo_changed; /* FIFO split is changed */ /* Pipe source size (ie. panel fitter input size) * All planes will be positioned inside this space, diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index df76c4fd4cf3..39bc4206be7a 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1128,30 +1128,35 @@ static u16 vlv_invert_wm_value(u16 wm, u16 fifo_size) * Starting from 'level' set all higher * levels to 'value' in the "raw" watermarks. */ -static void vlv_raw_plane_wm_set(struct intel_crtc_state *crtc_state, +static bool vlv_raw_plane_wm_set(struct intel_crtc_state *crtc_state, int level, enum plane_id plane_id, u16 value) { struct drm_i915_private *dev_priv = to_i915(crtc_state->base.crtc->dev); int num_levels = vlv_num_wm_levels(dev_priv); + bool dirty = false; for (; level < num_levels; level++) { struct vlv_pipe_wm *raw = &crtc_state->wm.vlv.raw[level]; + dirty |= raw->plane[plane_id] != value; raw->plane[plane_id] = value; } + + return dirty; } -static void vlv_plane_wm_compute(struct intel_crtc_state *crtc_state, +static bool vlv_plane_wm_compute(struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state) { struct intel_plane *plane = to_intel_plane(plane_state->base.plane); enum plane_id plane_id = plane->id; int num_levels = vlv_num_wm_levels(to_i915(plane->base.dev)); int level; + bool dirty = false; if (!plane_state->base.visible) { - vlv_raw_plane_wm_set(crtc_state, 0, plane_id, 0); - return; + dirty |= vlv_raw_plane_wm_set(crtc_state, 0, plane_id, 0); + goto out; } for (level = 0; level < num_levels; level++) { @@ -1166,17 +1171,22 @@ static void vlv_plane_wm_compute(struct intel_crtc_state *crtc_state, if (wm > max_wm) break; + dirty |= raw->plane[plane_id] != wm; raw->plane[plane_id] = wm; } /* mark all higher levels as invalid */ - vlv_raw_plane_wm_set(crtc_state, level, plane_id, USHRT_MAX); + dirty |= vlv_raw_plane_wm_set(crtc_state, level, plane_id, USHRT_MAX); - DRM_DEBUG_KMS("%s wms: [0]=%d,[1]=%d,[2]=%d\n", - plane->base.name, - crtc_state->wm.vlv.raw[VLV_WM_LEVEL_PM2].plane[plane_id], - crtc_state->wm.vlv.raw[VLV_WM_LEVEL_PM5].plane[plane_id], - crtc_state->wm.vlv.raw[VLV_WM_LEVEL_DDR_DVFS].plane[plane_id]); +out: + if (dirty) + DRM_DEBUG_KMS("%s wms: [0]=%d,[1]=%d,[2]=%d\n", + plane->base.name, + crtc_state->wm.vlv.raw[VLV_WM_LEVEL_PM2].plane[plane_id], + crtc_state->wm.vlv.raw[VLV_WM_LEVEL_PM5].plane[plane_id], + crtc_state->wm.vlv.raw[VLV_WM_LEVEL_DDR_DVFS].plane[plane_id]); + + return dirty; } static bool vlv_plane_wm_is_valid(const struct intel_crtc_state *crtc_state, @@ -1209,10 +1219,12 @@ static int vlv_compute_pipe_wm(struct intel_crtc_state *crtc_state) &crtc_state->wm.vlv.fifo_state; int num_active_planes = hweight32(crtc_state->active_planes & ~BIT(PLANE_CURSOR)); + bool needs_modeset = drm_atomic_crtc_needs_modeset(&crtc_state->base); struct intel_plane_state *plane_state; struct intel_plane *plane; enum plane_id plane_id; int level, ret, i; + unsigned int dirty = 0; for_each_intel_plane_in_state(state, plane, plane_state, i) { const struct intel_plane_state *old_plane_state = @@ -1222,7 +1234,37 @@ static int vlv_compute_pipe_wm(struct intel_crtc_state *crtc_state) old_plane_state->base.crtc != &crtc->base) continue; - vlv_plane_wm_compute(crtc_state, plane_state); + if (vlv_plane_wm_compute(crtc_state, plane_state)) + dirty |= BIT(plane->id); + } + + /* + * DSPARB registers may have been reset due to the + * power well being turned off. Make sure we restore + * them to a consistent state even if no primary/sprite + * planes are initially active. + */ + if (needs_modeset) + crtc_state->fifo_changed = true; + + if (!dirty) + return 0; + + /* cursor changes don't warrant a FIFO recompute */ + if (dirty & ~BIT(PLANE_CURSOR)) { + const struct intel_crtc_state *old_crtc_state = + to_intel_crtc_state(crtc->base.state); + const struct vlv_fifo_state *old_fifo_state = + &old_crtc_state->wm.vlv.fifo_state; + + ret = vlv_compute_fifo(crtc_state); + if (ret) + return ret; + + if (needs_modeset || + memcmp(old_fifo_state, fifo_state, + sizeof(*fifo_state)) != 0) + crtc_state->fifo_changed = true; } /* initially allow all levels */ @@ -1235,10 +1277,6 @@ static int vlv_compute_pipe_wm(struct intel_crtc_state *crtc_state) wm_state->cxsr = crtc->pipe != PIPE_C && crtc->wm.cxsr_allowed && num_active_planes == 1; - ret = vlv_compute_fifo(crtc_state); - if (ret) - return ret; - for (level = 0; level < wm_state->num_levels; level++) { const struct vlv_pipe_wm *raw = &crtc_state->wm.vlv.raw[level]; const int sr_fifo_size = INTEL_INFO(dev_priv)->num_pipes * 512 - 1; @@ -1287,6 +1325,9 @@ static void vlv_atomic_update_fifo(struct intel_atomic_state *state, &crtc_state->wm.vlv.fifo_state; int sprite0_start, sprite1_start, fifo_size; + if (!crtc_state->fifo_changed) + return; + sprite0_start = fifo_state->plane[PLANE_PRIMARY]; sprite1_start = fifo_state->plane[PLANE_SPRITE0] + sprite0_start; fifo_size = fifo_state->plane[PLANE_SPRITE1] + sprite1_start; -- 2.30.2