diff options
| -rw-r--r-- | drivers/gpu/drm/i915/display/intel_atomic_plane.c | 180 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/display/intel_atomic_plane.h | 4 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/display/intel_display.c | 188 | 
3 files changed, 180 insertions, 192 deletions
| diff --git a/drivers/gpu/drm/i915/display/intel_atomic_plane.c b/drivers/gpu/drm/i915/display/intel_atomic_plane.c index 0e15fe908855..687fc2e3a0d8 100644 --- a/drivers/gpu/drm/i915/display/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/display/intel_atomic_plane.c @@ -45,6 +45,7 @@  #include "intel_fb_pin.h"  #include "intel_pm.h"  #include "intel_sprite.h" +#include "skl_scaler.h"  static void intel_plane_state_reset(struct intel_plane_state *plane_state,  				    struct intel_plane *plane) @@ -330,6 +331,185 @@ void intel_plane_set_invisible(struct intel_crtc_state *crtc_state,  	plane_state->uapi.visible = false;  } +/* FIXME nuke when all wm code is atomic */ +static bool intel_wm_need_update(const struct intel_plane_state *cur, +				 struct intel_plane_state *new) +{ +	/* Update watermarks on tiling or size changes. */ +	if (new->uapi.visible != cur->uapi.visible) +		return true; + +	if (!cur->hw.fb || !new->hw.fb) +		return false; + +	if (cur->hw.fb->modifier != new->hw.fb->modifier || +	    cur->hw.rotation != new->hw.rotation || +	    drm_rect_width(&new->uapi.src) != drm_rect_width(&cur->uapi.src) || +	    drm_rect_height(&new->uapi.src) != drm_rect_height(&cur->uapi.src) || +	    drm_rect_width(&new->uapi.dst) != drm_rect_width(&cur->uapi.dst) || +	    drm_rect_height(&new->uapi.dst) != drm_rect_height(&cur->uapi.dst)) +		return true; + +	return false; +} + +static bool intel_plane_is_scaled(const struct intel_plane_state *plane_state) +{ +	int src_w = drm_rect_width(&plane_state->uapi.src) >> 16; +	int src_h = drm_rect_height(&plane_state->uapi.src) >> 16; +	int dst_w = drm_rect_width(&plane_state->uapi.dst); +	int dst_h = drm_rect_height(&plane_state->uapi.dst); + +	return src_w != dst_w || src_h != dst_h; +} + +static bool intel_plane_do_async_flip(struct intel_plane *plane, +				      const struct intel_crtc_state *old_crtc_state, +				      const struct intel_crtc_state *new_crtc_state) +{ +	struct drm_i915_private *i915 = to_i915(plane->base.dev); + +	if (!plane->async_flip) +		return false; + +	if (!new_crtc_state->uapi.async_flip) +		return false; + +	/* +	 * In platforms after DISPLAY13, we might need to override +	 * first async flip in order to change watermark levels +	 * as part of optimization. +	 * So for those, we are checking if this is a first async flip. +	 * For platforms earlier than DISPLAY13 we always do async flip. +	 */ +	return DISPLAY_VER(i915) < 13 || old_crtc_state->uapi.async_flip; +} + +static int intel_plane_atomic_calc_changes(const struct intel_crtc_state *old_crtc_state, +					   struct intel_crtc_state *new_crtc_state, +					   const struct intel_plane_state *old_plane_state, +					   struct intel_plane_state *new_plane_state) +{ +	struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc); +	struct intel_plane *plane = to_intel_plane(new_plane_state->uapi.plane); +	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); +	bool mode_changed = intel_crtc_needs_modeset(new_crtc_state); +	bool was_crtc_enabled = old_crtc_state->hw.active; +	bool is_crtc_enabled = new_crtc_state->hw.active; +	bool turn_off, turn_on, visible, was_visible; +	int ret; + +	if (DISPLAY_VER(dev_priv) >= 9 && plane->id != PLANE_CURSOR) { +		ret = skl_update_scaler_plane(new_crtc_state, new_plane_state); +		if (ret) +			return ret; +	} + +	was_visible = old_plane_state->uapi.visible; +	visible = new_plane_state->uapi.visible; + +	if (!was_crtc_enabled && drm_WARN_ON(&dev_priv->drm, was_visible)) +		was_visible = false; + +	/* +	 * Visibility is calculated as if the crtc was on, but +	 * after scaler setup everything depends on it being off +	 * when the crtc isn't active. +	 * +	 * FIXME this is wrong for watermarks. Watermarks should also +	 * be computed as if the pipe would be active. Perhaps move +	 * per-plane wm computation to the .check_plane() hook, and +	 * only combine the results from all planes in the current place? +	 */ +	if (!is_crtc_enabled) { +		intel_plane_set_invisible(new_crtc_state, new_plane_state); +		visible = false; +	} + +	if (!was_visible && !visible) +		return 0; + +	turn_off = was_visible && (!visible || mode_changed); +	turn_on = visible && (!was_visible || mode_changed); + +	drm_dbg_atomic(&dev_priv->drm, +		       "[CRTC:%d:%s] with [PLANE:%d:%s] visible %i -> %i, off %i, on %i, ms %i\n", +		       crtc->base.base.id, crtc->base.name, +		       plane->base.base.id, plane->base.name, +		       was_visible, visible, +		       turn_off, turn_on, mode_changed); + +	if (turn_on) { +		if (DISPLAY_VER(dev_priv) < 5 && !IS_G4X(dev_priv)) +			new_crtc_state->update_wm_pre = true; + +		/* must disable cxsr around plane enable/disable */ +		if (plane->id != PLANE_CURSOR) +			new_crtc_state->disable_cxsr = true; +	} else if (turn_off) { +		if (DISPLAY_VER(dev_priv) < 5 && !IS_G4X(dev_priv)) +			new_crtc_state->update_wm_post = true; + +		/* must disable cxsr around plane enable/disable */ +		if (plane->id != PLANE_CURSOR) +			new_crtc_state->disable_cxsr = true; +	} else if (intel_wm_need_update(old_plane_state, new_plane_state)) { +		if (DISPLAY_VER(dev_priv) < 5 && !IS_G4X(dev_priv)) { +			/* FIXME bollocks */ +			new_crtc_state->update_wm_pre = true; +			new_crtc_state->update_wm_post = true; +		} +	} + +	if (visible || was_visible) +		new_crtc_state->fb_bits |= plane->frontbuffer_bit; + +	/* +	 * ILK/SNB DVSACNTR/Sprite Enable +	 * IVB SPR_CTL/Sprite Enable +	 * "When in Self Refresh Big FIFO mode, a write to enable the +	 *  plane will be internally buffered and delayed while Big FIFO +	 *  mode is exiting." +	 * +	 * Which means that enabling the sprite can take an extra frame +	 * when we start in big FIFO mode (LP1+). Thus we need to drop +	 * down to LP0 and wait for vblank in order to make sure the +	 * sprite gets enabled on the next vblank after the register write. +	 * Doing otherwise would risk enabling the sprite one frame after +	 * we've already signalled flip completion. We can resume LP1+ +	 * once the sprite has been enabled. +	 * +	 * +	 * WaCxSRDisabledForSpriteScaling:ivb +	 * IVB SPR_SCALE/Scaling Enable +	 * "Low Power watermarks must be disabled for at least one +	 *  frame before enabling sprite scaling, and kept disabled +	 *  until sprite scaling is disabled." +	 * +	 * ILK/SNB DVSASCALE/Scaling Enable +	 * "When in Self Refresh Big FIFO mode, scaling enable will be +	 *  masked off while Big FIFO mode is exiting." +	 * +	 * Despite the w/a only being listed for IVB we assume that +	 * the ILK/SNB note has similar ramifications, hence we apply +	 * the w/a on all three platforms. +	 * +	 * With experimental results seems this is needed also for primary +	 * plane, not only sprite plane. +	 */ +	if (plane->id != PLANE_CURSOR && +	    (IS_IRONLAKE(dev_priv) || IS_SANDYBRIDGE(dev_priv) || +	     IS_IVYBRIDGE(dev_priv)) && +	    (turn_on || (!intel_plane_is_scaled(old_plane_state) && +			 intel_plane_is_scaled(new_plane_state)))) +		new_crtc_state->disable_lp_wm = true; + +	if (intel_plane_do_async_flip(plane, old_crtc_state, new_crtc_state)) +		new_plane_state->do_async_flip = true; + +	return 0; +} +  int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_state,  					struct intel_crtc_state *new_crtc_state,  					const struct intel_plane_state *old_plane_state, diff --git a/drivers/gpu/drm/i915/display/intel_atomic_plane.h b/drivers/gpu/drm/i915/display/intel_atomic_plane.h index ead789709477..9822b921279c 100644 --- a/drivers/gpu/drm/i915/display/intel_atomic_plane.h +++ b/drivers/gpu/drm/i915/display/intel_atomic_plane.h @@ -56,10 +56,6 @@ int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_  					struct intel_plane_state *intel_state);  int intel_plane_atomic_check(struct intel_atomic_state *state,  			     struct intel_plane *plane); -int intel_plane_atomic_calc_changes(const struct intel_crtc_state *old_crtc_state, -				    struct intel_crtc_state *crtc_state, -				    const struct intel_plane_state *old_plane_state, -				    struct intel_plane_state *plane_state);  int intel_plane_calc_min_cdclk(struct intel_atomic_state *state,  			       struct intel_plane *plane,  			       bool *need_cdclk_calc); diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index ae278d5e4fe9..a6ebca9c7f76 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -4668,194 +4668,6 @@ intel_encoder_current_mode(struct intel_encoder *encoder)  	return mode;  } -/** - * intel_wm_need_update - Check whether watermarks need updating - * @cur: current plane state - * @new: new plane state - * - * Check current plane state versus the new one to determine whether - * watermarks need to be recalculated. - * - * Returns true or false. - */ -static bool intel_wm_need_update(const struct intel_plane_state *cur, -				 struct intel_plane_state *new) -{ -	/* Update watermarks on tiling or size changes. */ -	if (new->uapi.visible != cur->uapi.visible) -		return true; - -	if (!cur->hw.fb || !new->hw.fb) -		return false; - -	if (cur->hw.fb->modifier != new->hw.fb->modifier || -	    cur->hw.rotation != new->hw.rotation || -	    drm_rect_width(&new->uapi.src) != drm_rect_width(&cur->uapi.src) || -	    drm_rect_height(&new->uapi.src) != drm_rect_height(&cur->uapi.src) || -	    drm_rect_width(&new->uapi.dst) != drm_rect_width(&cur->uapi.dst) || -	    drm_rect_height(&new->uapi.dst) != drm_rect_height(&cur->uapi.dst)) -		return true; - -	return false; -} - -static bool needs_scaling(const struct intel_plane_state *state) -{ -	int src_w = drm_rect_width(&state->uapi.src) >> 16; -	int src_h = drm_rect_height(&state->uapi.src) >> 16; -	int dst_w = drm_rect_width(&state->uapi.dst); -	int dst_h = drm_rect_height(&state->uapi.dst); - -	return (src_w != dst_w || src_h != dst_h); -} - -static bool intel_plane_do_async_flip(struct intel_plane *plane, -				      const struct intel_crtc_state *old_crtc_state, -				      const struct intel_crtc_state *new_crtc_state) -{ -	struct drm_i915_private *i915 = to_i915(plane->base.dev); - -	if (!plane->async_flip) -		return false; - -	if (!new_crtc_state->uapi.async_flip) -		return false; - -	/* -	 * In platforms after DISPLAY13, we might need to override -	 * first async flip in order to change watermark levels -	 * as part of optimization. -	 * So for those, we are checking if this is a first async flip. -	 * For platforms earlier than DISPLAY13 we always do async flip. -	 */ -	return DISPLAY_VER(i915) < 13 || old_crtc_state->uapi.async_flip; -} - -int intel_plane_atomic_calc_changes(const struct intel_crtc_state *old_crtc_state, -				    struct intel_crtc_state *new_crtc_state, -				    const struct intel_plane_state *old_plane_state, -				    struct intel_plane_state *new_plane_state) -{ -	struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc); -	struct intel_plane *plane = to_intel_plane(new_plane_state->uapi.plane); -	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); -	bool mode_changed = intel_crtc_needs_modeset(new_crtc_state); -	bool was_crtc_enabled = old_crtc_state->hw.active; -	bool is_crtc_enabled = new_crtc_state->hw.active; -	bool turn_off, turn_on, visible, was_visible; -	int ret; - -	if (DISPLAY_VER(dev_priv) >= 9 && plane->id != PLANE_CURSOR) { -		ret = skl_update_scaler_plane(new_crtc_state, new_plane_state); -		if (ret) -			return ret; -	} - -	was_visible = old_plane_state->uapi.visible; -	visible = new_plane_state->uapi.visible; - -	if (!was_crtc_enabled && drm_WARN_ON(&dev_priv->drm, was_visible)) -		was_visible = false; - -	/* -	 * Visibility is calculated as if the crtc was on, but -	 * after scaler setup everything depends on it being off -	 * when the crtc isn't active. -	 * -	 * FIXME this is wrong for watermarks. Watermarks should also -	 * be computed as if the pipe would be active. Perhaps move -	 * per-plane wm computation to the .check_plane() hook, and -	 * only combine the results from all planes in the current place? -	 */ -	if (!is_crtc_enabled) { -		intel_plane_set_invisible(new_crtc_state, new_plane_state); -		visible = false; -	} - -	if (!was_visible && !visible) -		return 0; - -	turn_off = was_visible && (!visible || mode_changed); -	turn_on = visible && (!was_visible || mode_changed); - -	drm_dbg_atomic(&dev_priv->drm, -		       "[CRTC:%d:%s] with [PLANE:%d:%s] visible %i -> %i, off %i, on %i, ms %i\n", -		       crtc->base.base.id, crtc->base.name, -		       plane->base.base.id, plane->base.name, -		       was_visible, visible, -		       turn_off, turn_on, mode_changed); - -	if (turn_on) { -		if (DISPLAY_VER(dev_priv) < 5 && !IS_G4X(dev_priv)) -			new_crtc_state->update_wm_pre = true; - -		/* must disable cxsr around plane enable/disable */ -		if (plane->id != PLANE_CURSOR) -			new_crtc_state->disable_cxsr = true; -	} else if (turn_off) { -		if (DISPLAY_VER(dev_priv) < 5 && !IS_G4X(dev_priv)) -			new_crtc_state->update_wm_post = true; - -		/* must disable cxsr around plane enable/disable */ -		if (plane->id != PLANE_CURSOR) -			new_crtc_state->disable_cxsr = true; -	} else if (intel_wm_need_update(old_plane_state, new_plane_state)) { -		if (DISPLAY_VER(dev_priv) < 5 && !IS_G4X(dev_priv)) { -			/* FIXME bollocks */ -			new_crtc_state->update_wm_pre = true; -			new_crtc_state->update_wm_post = true; -		} -	} - -	if (visible || was_visible) -		new_crtc_state->fb_bits |= plane->frontbuffer_bit; - -	/* -	 * ILK/SNB DVSACNTR/Sprite Enable -	 * IVB SPR_CTL/Sprite Enable -	 * "When in Self Refresh Big FIFO mode, a write to enable the -	 *  plane will be internally buffered and delayed while Big FIFO -	 *  mode is exiting." -	 * -	 * Which means that enabling the sprite can take an extra frame -	 * when we start in big FIFO mode (LP1+). Thus we need to drop -	 * down to LP0 and wait for vblank in order to make sure the -	 * sprite gets enabled on the next vblank after the register write. -	 * Doing otherwise would risk enabling the sprite one frame after -	 * we've already signalled flip completion. We can resume LP1+ -	 * once the sprite has been enabled. -	 * -	 * -	 * WaCxSRDisabledForSpriteScaling:ivb -	 * IVB SPR_SCALE/Scaling Enable -	 * "Low Power watermarks must be disabled for at least one -	 *  frame before enabling sprite scaling, and kept disabled -	 *  until sprite scaling is disabled." -	 * -	 * ILK/SNB DVSASCALE/Scaling Enable -	 * "When in Self Refresh Big FIFO mode, scaling enable will be -	 *  masked off while Big FIFO mode is exiting." -	 * -	 * Despite the w/a only being listed for IVB we assume that -	 * the ILK/SNB note has similar ramifications, hence we apply -	 * the w/a on all three platforms. -	 * -	 * With experimental results seems this is needed also for primary -	 * plane, not only sprite plane. -	 */ -	if (plane->id != PLANE_CURSOR && -	    (IS_IRONLAKE(dev_priv) || IS_SANDYBRIDGE(dev_priv) || -	     IS_IVYBRIDGE(dev_priv)) && -	    (turn_on || (!needs_scaling(old_plane_state) && -			 needs_scaling(new_plane_state)))) -		new_crtc_state->disable_lp_wm = true; - -	if (intel_plane_do_async_flip(plane, old_crtc_state, new_crtc_state)) -		new_plane_state->do_async_flip = true; - -	return 0; -} -  static bool encoders_cloneable(const struct intel_encoder *a,  			       const struct intel_encoder *b)  { | 
