diff mbox series

[v2,10/13] drm/i915: Move ddb/wm programming into plane update/disable hooks on skl+

Message ID 20181114210729.16185-11-ville.syrjala@linux.intel.com (mailing list archive)
State New, archived
Headers show
Series drm/i915: Program SKL+ watermarks/ddb more carefully | expand

Commit Message

Ville Syrjälä Nov. 14, 2018, 9:07 p.m. UTC
From: Ville Syrjälä <ville.syrjala@linux.intel.com>

On SKL+ the plane WM/BUF_CFG registers are a proper part of each
plane's register set. That means accessing them will cancel any
pending plane update, and we would need a PLANE_SURF register write
to arm the wm/ddb change as well.

To avoid all the problems with that let's just move the wm/ddb
programming into the plane update/disable hooks. Now all plane
registers get written in one (hopefully atomic) operation.

To make that feasible we'll move the plane ddb tracking into
the crtc state. Watermarks were already tracked there.

v2: Rebase due to input CSC
v3: Split out a bunch of junk (Matt)

Cc: Matt Roper <matthew.d.roper@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/i915_debugfs.c  |  21 +-
 drivers/gpu/drm/i915/i915_drv.h      |   3 -
 drivers/gpu/drm/i915/intel_display.c |  16 +-
 drivers/gpu/drm/i915/intel_display.h |  11 +-
 drivers/gpu/drm/i915/intel_drv.h     |   9 +
 drivers/gpu/drm/i915/intel_pm.c      | 317 ++++++++++++---------------
 drivers/gpu/drm/i915/intel_sprite.c  |   4 +
 7 files changed, 181 insertions(+), 200 deletions(-)

Comments

Matt Roper Nov. 21, 2018, 12:48 a.m. UTC | #1
On Wed, Nov 14, 2018 at 11:07:26PM +0200, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> On SKL+ the plane WM/BUF_CFG registers are a proper part of each
> plane's register set. That means accessing them will cancel any
> pending plane update, and we would need a PLANE_SURF register write
> to arm the wm/ddb change as well.
> 
> To avoid all the problems with that let's just move the wm/ddb
> programming into the plane update/disable hooks. Now all plane
> registers get written in one (hopefully atomic) operation.
> 
> To make that feasible we'll move the plane ddb tracking into
> the crtc state. Watermarks were already tracked there.
> 
> v2: Rebase due to input CSC
> v3: Split out a bunch of junk (Matt)
> 
> Cc: Matt Roper <matthew.d.roper@intel.com>
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/i915_debugfs.c  |  21 +-
>  drivers/gpu/drm/i915/i915_drv.h      |   3 -
>  drivers/gpu/drm/i915/intel_display.c |  16 +-
>  drivers/gpu/drm/i915/intel_display.h |  11 +-
>  drivers/gpu/drm/i915/intel_drv.h     |   9 +
>  drivers/gpu/drm/i915/intel_pm.c      | 317 ++++++++++++---------------
>  drivers/gpu/drm/i915/intel_sprite.c  |   4 +
>  7 files changed, 181 insertions(+), 200 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
> index 670db5073d70..f8b2200947cf 100644
> --- a/drivers/gpu/drm/i915/i915_debugfs.c
> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
> @@ -3437,31 +3437,32 @@ static int i915_ddb_info(struct seq_file *m, void *unused)
>  {
>  	struct drm_i915_private *dev_priv = node_to_i915(m->private);
>  	struct drm_device *dev = &dev_priv->drm;
> -	struct skl_ddb_allocation *ddb;
>  	struct skl_ddb_entry *entry;
> -	enum pipe pipe;
> -	int plane;
> +	struct intel_crtc *crtc;
>  
>  	if (INTEL_GEN(dev_priv) < 9)
>  		return -ENODEV;
>  
>  	drm_modeset_lock_all(dev);
>  
> -	ddb = &dev_priv->wm.skl_hw.ddb;
> -
>  	seq_printf(m, "%-15s%8s%8s%8s\n", "", "Start", "End", "Size");
>  
> -	for_each_pipe(dev_priv, pipe) {
> +	for_each_intel_crtc(&dev_priv->drm, crtc) {
> +		struct intel_crtc_state *crtc_state =
> +			to_intel_crtc_state(crtc->base.state);
> +		enum pipe pipe = crtc->pipe;
> +		enum plane_id plane_id;
> +
>  		seq_printf(m, "Pipe %c\n", pipe_name(pipe));
>  
> -		for_each_universal_plane(dev_priv, pipe, plane) {
> -			entry = &ddb->plane[pipe][plane];
> -			seq_printf(m, "  Plane%-8d%8u%8u%8u\n", plane + 1,
> +		for_each_plane_id_on_crtc(crtc, plane_id) {
> +			entry = &crtc_state->wm.skl.plane_ddb_y[plane_id];
> +			seq_printf(m, "  Plane%-8d%8u%8u%8u\n", plane_id + 1,
>  				   entry->start, entry->end,
>  				   skl_ddb_entry_size(entry));
>  		}
>  
> -		entry = &ddb->plane[pipe][PLANE_CURSOR];
> +		entry = &crtc_state->wm.skl.plane_ddb_y[PLANE_CURSOR];
>  		seq_printf(m, "  %-13s%8u%8u%8u\n", "Cursor", entry->start,
>  			   entry->end, skl_ddb_entry_size(entry));
>  	}
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 5d686b585a95..89af64fe90a5 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -1241,9 +1241,6 @@ static inline bool skl_ddb_entry_equal(const struct skl_ddb_entry *e1,
>  }
>  
>  struct skl_ddb_allocation {
> -	/* packed/y */
> -	struct skl_ddb_entry plane[I915_MAX_PIPES][I915_MAX_PLANES];
> -	struct skl_ddb_entry uv_plane[I915_MAX_PIPES][I915_MAX_PLANES];
>  	u8 enabled_slices; /* GEN11 has configurable 2 slices */
>  };
>  
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 0caba7258fee..2981cea3704a 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -10083,6 +10083,10 @@ static void i9xx_update_cursor(struct intel_plane *plane,
>  	 * except when the plane is getting enabled at which time
>  	 * the CURCNTR write arms the update.
>  	 */
> +
> +	if (INTEL_GEN(dev_priv) >= 9)
> +		skl_write_cursor_wm(plane, crtc_state);
> +
>  	if (plane->cursor.base != base ||
>  	    plane->cursor.size != fbc_ctl ||
>  	    plane->cursor.cntl != cntl) {
> @@ -11872,6 +11876,8 @@ static void verify_wm_state(struct drm_crtc *crtc,
>  	struct skl_pipe_wm hw_wm, *sw_wm;
>  	struct skl_plane_wm *hw_plane_wm, *sw_plane_wm;
>  	struct skl_ddb_entry *hw_ddb_entry, *sw_ddb_entry;
> +	struct skl_ddb_entry hw_ddb_y[I915_MAX_PLANES];
> +	struct skl_ddb_entry hw_ddb_uv[I915_MAX_PLANES];
>  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
>  	const enum pipe pipe = intel_crtc->pipe;
>  	int plane, level, max_level = ilk_wm_max_level(dev_priv);
> @@ -11882,6 +11888,8 @@ static void verify_wm_state(struct drm_crtc *crtc,
>  	skl_pipe_wm_get_hw_state(crtc, &hw_wm);
>  	sw_wm = &to_intel_crtc_state(new_state)->wm.skl.optimal;
>  
> +	skl_pipe_ddb_get_hw_state(intel_crtc, hw_ddb_y, hw_ddb_uv);
> +
>  	skl_ddb_get_hw_state(dev_priv, &hw_ddb);
>  	sw_ddb = &dev_priv->wm.skl_hw.ddb;
>  
> @@ -11924,8 +11932,8 @@ static void verify_wm_state(struct drm_crtc *crtc,
>  		}
>  
>  		/* DDB */
> -		hw_ddb_entry = &hw_ddb.plane[pipe][plane];
> -		sw_ddb_entry = &sw_ddb->plane[pipe][plane];
> +		hw_ddb_entry = &hw_ddb_y[plane];
> +		sw_ddb_entry = &to_intel_crtc_state(new_state)->wm.skl.plane_ddb_y[plane];
>  
>  		if (!skl_ddb_entry_equal(hw_ddb_entry, sw_ddb_entry)) {
>  			DRM_ERROR("mismatch in DDB state pipe %c plane %d (expected (%u,%u), found (%u,%u))\n",
> @@ -11974,8 +11982,8 @@ static void verify_wm_state(struct drm_crtc *crtc,
>  		}
>  
>  		/* DDB */
> -		hw_ddb_entry = &hw_ddb.plane[pipe][PLANE_CURSOR];
> -		sw_ddb_entry = &sw_ddb->plane[pipe][PLANE_CURSOR];
> +		hw_ddb_entry = &hw_ddb_y[PLANE_CURSOR];
> +		sw_ddb_entry = &to_intel_crtc_state(new_state)->wm.skl.plane_ddb_y[PLANE_CURSOR];
>  
>  		if (!skl_ddb_entry_equal(hw_ddb_entry, sw_ddb_entry)) {
>  			DRM_ERROR("mismatch in DDB state pipe %c cursor (expected (%u,%u), found (%u,%u))\n",
> diff --git a/drivers/gpu/drm/i915/intel_display.h b/drivers/gpu/drm/i915/intel_display.h
> index df9e6ebb27de..078406dc65e5 100644
> --- a/drivers/gpu/drm/i915/intel_display.h
> +++ b/drivers/gpu/drm/i915/intel_display.h
> @@ -319,7 +319,7 @@ struct intel_link_m_n {
>  			    &(dev)->mode_config.plane_list,		\
>  			    base.head)					\
>  		for_each_if((plane_mask) &				\
> -			    drm_plane_mask(&intel_plane->base)))
> +			    drm_plane_mask(&intel_plane->base))
>  
>  #define for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane)	\
>  	list_for_each_entry(intel_plane,				\
> @@ -415,6 +415,15 @@ struct intel_link_m_n {
>  	     (__i)++) \
>  		for_each_if(plane)
>  
> +#define for_each_oldnew_intel_crtc_in_state(__state, crtc, old_crtc_state, new_crtc_state, __i) \
> +	for ((__i) = 0; \
> +	     (__i) < (__state)->base.dev->mode_config.num_crtc && \
> +		     ((crtc) = to_intel_crtc((__state)->base.crtcs[__i].ptr), \
> +		      (old_crtc_state) = to_intel_crtc_state((__state)->base.crtcs[__i].old_state), \
> +		      (new_crtc_state) = to_intel_crtc_state((__state)->base.crtcs[__i].new_state), 1); \
> +	     (__i)++) \
> +		for_each_if(crtc)
> +
>  void intel_link_compute_m_n(int bpp, int nlanes,
>  			    int pixel_clock, int link_clock,
>  			    struct intel_link_m_n *m_n,
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index 23b33970db17..4a9af09c483a 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -705,6 +705,8 @@ struct intel_crtc_wm_state {
>  			/* gen9+ only needs 1-step wm programming */
>  			struct skl_pipe_wm optimal;
>  			struct skl_ddb_entry ddb;
> +			struct skl_ddb_entry plane_ddb_y[I915_MAX_PLANES];
> +			struct skl_ddb_entry plane_ddb_uv[I915_MAX_PLANES];

I feel like naming these _y and _uv is going to cause confusion.  The Y
and UV are backwards half the time (based on the swap we have to do
farther down), and doesn't have meaning at all for RGB.  Maybe name
these something like "plane_ddb_main" and "plane_ddb_extra" to somewhat
disassociate it with the actual type of data it's supposed to represent?

If you want to keep the _y and _uv (which are nice and short), I think
we at least need some warning comments here explaining the behavior.

>  		} skl;
>  
>  		struct {
> @@ -2183,6 +2185,9 @@ void g4x_wm_get_hw_state(struct drm_device *dev);
>  void vlv_wm_get_hw_state(struct drm_device *dev);
>  void ilk_wm_get_hw_state(struct drm_device *dev);
>  void skl_wm_get_hw_state(struct drm_device *dev);
> +void skl_pipe_ddb_get_hw_state(struct intel_crtc *crtc,
> +			       struct skl_ddb_entry *ddb_y,
> +			       struct skl_ddb_entry *ddb_uv);
>  void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv,
>  			  struct skl_ddb_allocation *ddb /* out */);
>  void skl_pipe_wm_get_hw_state(struct drm_crtc *crtc,
> @@ -2197,6 +2202,10 @@ bool skl_wm_level_equals(const struct skl_wm_level *l1,
>  bool skl_ddb_allocation_overlaps(const struct skl_ddb_entry *ddb,
>  				 const struct skl_ddb_entry entries[],
>  				 int num_entries, int ignore_idx);
> +void skl_write_plane_wm(struct intel_plane *plane,
> +			const struct intel_crtc_state *crtc_state);
> +void skl_write_cursor_wm(struct intel_plane *plane,
> +			 const struct intel_crtc_state *crtc_state);
>  bool ilk_disable_lp_wm(struct drm_device *dev);
>  int skl_check_pipe_max_pixel_rate(struct intel_crtc *intel_crtc,
>  				  struct intel_crtc_state *cstate);
> diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> index a21654c974ba..1b337004054a 100644
> --- a/drivers/gpu/drm/i915/intel_pm.c
> +++ b/drivers/gpu/drm/i915/intel_pm.c
> @@ -3912,68 +3912,70 @@ static void
>  skl_ddb_get_hw_plane_state(struct drm_i915_private *dev_priv,
>  			   const enum pipe pipe,
>  			   const enum plane_id plane_id,
> -			   struct skl_ddb_allocation *ddb /* out */)
> +			   struct skl_ddb_entry *ddb_y,
> +			   struct skl_ddb_entry *ddb_uv)
>  {
> -	u32 val, val2 = 0;
> -	int fourcc, pixel_format;
> +	u32 val, val2;
> +	u32 fourcc = 0;
>  
>  	/* Cursor doesn't support NV12/planar, so no extra calculation needed */
>  	if (plane_id == PLANE_CURSOR) {
>  		val = I915_READ(CUR_BUF_CFG(pipe));
> -		skl_ddb_entry_init_from_hw(dev_priv,
> -					   &ddb->plane[pipe][plane_id], val);
> +		skl_ddb_entry_init_from_hw(dev_priv, ddb_y, val);
>  		return;
>  	}
>  
>  	val = I915_READ(PLANE_CTL(pipe, plane_id));
>  
>  	/* No DDB allocated for disabled planes */
> -	if (!(val & PLANE_CTL_ENABLE))
> -		return;

I think we should mention the readout behavior change in the commit
message (i.e., we now read out DDB even if we think the plane is
disabled).  Either that or move the behavior change to a separate patch.

We should also drop the comment line since I don't think it really makes
sense anymore.

> +	if (val & PLANE_CTL_ENABLE)
> +		fourcc = skl_format_to_fourcc(val & PLANE_CTL_FORMAT_MASK,
> +					      val & PLANE_CTL_ORDER_RGBX,
> +					      val & PLANE_CTL_ALPHA_MASK);
>  
> -	pixel_format = val & PLANE_CTL_FORMAT_MASK;
> -	fourcc = skl_format_to_fourcc(pixel_format,
> -				      val & PLANE_CTL_ORDER_RGBX,
> -				      val & PLANE_CTL_ALPHA_MASK);
> -
> -	val = I915_READ(PLANE_BUF_CFG(pipe, plane_id));
> -	if (fourcc == DRM_FORMAT_NV12 && INTEL_GEN(dev_priv) < 11) {
> +	if (INTEL_GEN(dev_priv) >= 11) {
> +		val = I915_READ(PLANE_BUF_CFG(pipe, plane_id));
> +		skl_ddb_entry_init_from_hw(dev_priv, ddb_y, val);
> +	} else {
> +		val = I915_READ(PLANE_BUF_CFG(pipe, plane_id));
>  		val2 = I915_READ(PLANE_NV12_BUF_CFG(pipe, plane_id));
>  
> -		skl_ddb_entry_init_from_hw(dev_priv,
> -					   &ddb->plane[pipe][plane_id], val2);
> -		skl_ddb_entry_init_from_hw(dev_priv,
> -					   &ddb->uv_plane[pipe][plane_id], val);
> -	} else {
> -		skl_ddb_entry_init_from_hw(dev_priv,
> -					   &ddb->plane[pipe][plane_id], val);
> +		if (fourcc == DRM_FORMAT_NV12)
> +			swap(val, val2);
> +
> +		skl_ddb_entry_init_from_hw(dev_priv, ddb_y, val);
> +		skl_ddb_entry_init_from_hw(dev_priv, ddb_uv, val2);
>  	}
>  }
>  
> +void skl_pipe_ddb_get_hw_state(struct intel_crtc *crtc,
> +			       struct skl_ddb_entry *ddb_y,
> +			       struct skl_ddb_entry *ddb_uv)
> +{
> +	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
> +	enum intel_display_power_domain power_domain;
> +	enum pipe pipe = crtc->pipe;
> +	enum plane_id plane_id;
> +
> +	power_domain = POWER_DOMAIN_PIPE(pipe);
> +	if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
> +		return;
> +
> +	for_each_plane_id_on_crtc(crtc, plane_id)
> +		skl_ddb_get_hw_plane_state(dev_priv, pipe,
> +					   plane_id,
> +					   &ddb_y[plane_id],
> +					   &ddb_uv[plane_id]);
> +
> +	intel_display_power_put(dev_priv, power_domain);
> +}
> +
>  void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv,
>  			  struct skl_ddb_allocation *ddb /* out */)
>  {
> -	struct intel_crtc *crtc;
> -
>  	memset(ddb, 0, sizeof(*ddb));

We can drop the memset.  The entire structure is only 1 byte now, and we
set its only remaining field on the next line.

>  
>  	ddb->enabled_slices = intel_enabled_dbuf_slices_num(dev_priv);
> -
> -	for_each_intel_crtc(&dev_priv->drm, crtc) {
> -		enum intel_display_power_domain power_domain;
> -		enum plane_id plane_id;
> -		enum pipe pipe = crtc->pipe;
> -
> -		power_domain = POWER_DOMAIN_PIPE(pipe);
> -		if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
> -			continue;
> -
> -		for_each_plane_id_on_crtc(crtc, plane_id)
> -			skl_ddb_get_hw_plane_state(dev_priv, pipe,
> -						   plane_id, ddb);
> -
> -		intel_display_power_put(dev_priv, power_domain);
> -	}
>  }
>  
>  /*
> @@ -4371,7 +4373,6 @@ skl_allocate_pipe_ddb(struct intel_crtc_state *cstate,
>  	struct drm_crtc *crtc = cstate->base.crtc;
>  	struct drm_i915_private *dev_priv = to_i915(crtc->dev);
>  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> -	enum pipe pipe = intel_crtc->pipe;
>  	struct skl_ddb_entry *alloc = &cstate->wm.skl.ddb;
>  	uint16_t alloc_size, start;
>  	uint16_t minimum[I915_MAX_PLANES] = {};
> @@ -4384,8 +4385,8 @@ skl_allocate_pipe_ddb(struct intel_crtc_state *cstate,
>  	uint16_t total_min_blocks = 0;
>  
>  	/* Clear the partitioning for disabled planes. */
> -	memset(ddb->plane[pipe], 0, sizeof(ddb->plane[pipe]));
> -	memset(ddb->uv_plane[pipe], 0, sizeof(ddb->uv_plane[pipe]));
> +	memset(cstate->wm.skl.plane_ddb_y, 0, sizeof(cstate->wm.skl.plane_ddb_y));
> +	memset(cstate->wm.skl.plane_ddb_uv, 0, sizeof(cstate->wm.skl.plane_ddb_uv));
>  
>  	if (WARN_ON(!state))
>  		return 0;
> @@ -4432,8 +4433,8 @@ skl_allocate_pipe_ddb(struct intel_crtc_state *cstate,
>  	}
>  
>  	alloc_size -= total_min_blocks;
> -	ddb->plane[pipe][PLANE_CURSOR].start = alloc->end - minimum[PLANE_CURSOR];
> -	ddb->plane[pipe][PLANE_CURSOR].end = alloc->end;
> +	cstate->wm.skl.plane_ddb_y[PLANE_CURSOR].start = alloc->end - minimum[PLANE_CURSOR];
> +	cstate->wm.skl.plane_ddb_y[PLANE_CURSOR].end = alloc->end;
>  
>  	/*
>  	 * 2. Distribute the remaining space in proportion to the amount of
> @@ -4464,8 +4465,8 @@ skl_allocate_pipe_ddb(struct intel_crtc_state *cstate,
>  
>  		/* Leave disabled planes at (0,0) */
>  		if (data_rate) {
> -			ddb->plane[pipe][plane_id].start = start;
> -			ddb->plane[pipe][plane_id].end = start + plane_blocks;
> +			cstate->wm.skl.plane_ddb_y[plane_id].start = start;
> +			cstate->wm.skl.plane_ddb_y[plane_id].end = start + plane_blocks;
>  		}
>  
>  		start += plane_blocks;
> @@ -4480,8 +4481,8 @@ skl_allocate_pipe_ddb(struct intel_crtc_state *cstate,
>  		WARN_ON(INTEL_GEN(dev_priv) >= 11 && uv_plane_blocks);
>  
>  		if (uv_data_rate) {
> -			ddb->uv_plane[pipe][plane_id].start = start;
> -			ddb->uv_plane[pipe][plane_id].end =
> +			cstate->wm.skl.plane_ddb_uv[plane_id].start = start;
> +			cstate->wm.skl.plane_ddb_uv[plane_id].end =
>  				start + uv_plane_blocks;
>  		}
>  
> @@ -4939,16 +4940,13 @@ static void skl_compute_transition_wm(const struct intel_crtc_state *cstate,
>  	}
>  }
>  
> -static int skl_build_plane_wm_single(struct skl_ddb_allocation *ddb,
> -				     struct intel_crtc_state *crtc_state,
> +static int skl_build_plane_wm_single(struct intel_crtc_state *crtc_state,
>  				     const struct intel_plane_state *plane_state,
>  				     enum plane_id plane_id, int color_plane)
>  {
> -	struct intel_plane *plane = to_intel_plane(plane_state->base.plane);
>  	struct skl_plane_wm *wm = &crtc_state->wm.skl.optimal.planes[plane_id];
> +	u16 ddb_blocks = skl_ddb_entry_size(&crtc_state->wm.skl.plane_ddb_y[plane_id]);
>  	struct skl_wm_params wm_params;
> -	enum pipe pipe = plane->pipe;
> -	uint16_t ddb_blocks = skl_ddb_entry_size(&ddb->plane[pipe][plane_id]);
>  	int ret;
>  
>  	ret = skl_compute_plane_wm_params(crtc_state, plane_state,
> @@ -4966,16 +4964,13 @@ static int skl_build_plane_wm_single(struct skl_ddb_allocation *ddb,
>  	return 0;
>  }
>  
> -static int skl_build_plane_wm_uv(struct skl_ddb_allocation *ddb,
> -				 struct intel_crtc_state *crtc_state,
> +static int skl_build_plane_wm_uv(struct intel_crtc_state *crtc_state,
>  				 const struct intel_plane_state *plane_state,
>  				 enum plane_id plane_id)
>  {
> -	struct intel_plane *plane = to_intel_plane(plane_state->base.plane);
>  	struct skl_plane_wm *wm = &crtc_state->wm.skl.optimal.planes[plane_id];
> +	u16 ddb_blocks = skl_ddb_entry_size(&crtc_state->wm.skl.plane_ddb_uv[plane_id]);
>  	struct skl_wm_params wm_params;
> -	enum pipe pipe = plane->pipe;
> -	uint16_t ddb_blocks = skl_ddb_entry_size(&ddb->uv_plane[pipe][plane_id]);
>  	int ret;
>  
>  	wm->is_planar = true;
> @@ -4994,8 +4989,7 @@ static int skl_build_plane_wm_uv(struct skl_ddb_allocation *ddb,
>  	return 0;
>  }
>  
> -static int skl_build_plane_wm(struct skl_ddb_allocation *ddb,
> -			      struct skl_pipe_wm *pipe_wm,
> +static int skl_build_plane_wm(struct skl_pipe_wm *pipe_wm,
>  			      struct intel_crtc_state *crtc_state,
>  			      const struct intel_plane_state *plane_state)
>  {
> @@ -5007,13 +5001,13 @@ static int skl_build_plane_wm(struct skl_ddb_allocation *ddb,
>  	if (!intel_wm_plane_visible(crtc_state, plane_state))
>  		return 0;
>  
> -	ret = skl_build_plane_wm_single(ddb, crtc_state, plane_state,
> +	ret = skl_build_plane_wm_single(crtc_state, plane_state,
>  					plane_id, 0);
>  	if (ret)
>  		return ret;
>  
>  	if (fb->format->is_yuv && fb->format->num_planes > 1) {
> -		ret = skl_build_plane_wm_uv(ddb, crtc_state, plane_state,
> +		ret = skl_build_plane_wm_uv(crtc_state, plane_state,
>  					    plane_id);
>  		if (ret)
>  			return ret;
> @@ -5022,8 +5016,7 @@ static int skl_build_plane_wm(struct skl_ddb_allocation *ddb,
>  	return 0;
>  }
>  
> -static int icl_build_plane_wm(struct skl_ddb_allocation *ddb,
> -			      struct skl_pipe_wm *pipe_wm,
> +static int icl_build_plane_wm(struct skl_pipe_wm *pipe_wm,
>  			      struct intel_crtc_state *crtc_state,
>  			      const struct intel_plane_state *plane_state)
>  {
> @@ -5041,17 +5034,17 @@ static int icl_build_plane_wm(struct skl_ddb_allocation *ddb,
>  		WARN_ON(!fb->format->is_yuv ||
>  			fb->format->num_planes == 1);
>  
> -		ret = skl_build_plane_wm_single(ddb, crtc_state, plane_state,
> +		ret = skl_build_plane_wm_single(crtc_state, plane_state,
>  						y_plane_id, 0);
>  		if (ret)
>  			return ret;
>  
> -		ret = skl_build_plane_wm_single(ddb, crtc_state, plane_state,
> +		ret = skl_build_plane_wm_single(crtc_state, plane_state,
>  						plane_id, 1);
>  		if (ret)
>  			return ret;
>  	} else if (intel_wm_plane_visible(crtc_state, plane_state)) {
> -		ret = skl_build_plane_wm_single(ddb, crtc_state, plane_state,
> +		ret = skl_build_plane_wm_single(crtc_state, plane_state,
>  						plane_id, 0);
>  		if (ret)
>  			return ret;
> @@ -5061,7 +5054,6 @@ static int icl_build_plane_wm(struct skl_ddb_allocation *ddb,
>  }
>  
>  static int skl_build_pipe_wm(struct intel_crtc_state *cstate,
> -			     struct skl_ddb_allocation *ddb,
>  			     struct skl_pipe_wm *pipe_wm)
>  {
>  	struct drm_i915_private *dev_priv = to_i915(cstate->base.crtc->dev);
> @@ -5081,10 +5073,10 @@ static int skl_build_pipe_wm(struct intel_crtc_state *cstate,
>  						to_intel_plane_state(pstate);
>  
>  		if (INTEL_GEN(dev_priv) >= 11)
> -			ret = icl_build_plane_wm(ddb, pipe_wm,
> +			ret = icl_build_plane_wm(pipe_wm,
>  						 cstate, intel_pstate);
>  		else
> -			ret = skl_build_plane_wm(ddb, pipe_wm,
> +			ret = skl_build_plane_wm(pipe_wm,
>  						 cstate, intel_pstate);
>  		if (ret)
>  			return ret;
> @@ -5100,9 +5092,9 @@ static void skl_ddb_entry_write(struct drm_i915_private *dev_priv,
>  				const struct skl_ddb_entry *entry)
>  {
>  	if (entry->end)
> -		I915_WRITE(reg, (entry->end - 1) << 16 | entry->start);
> +		I915_WRITE_FW(reg, (entry->end - 1) << 16 | entry->start);
>  	else
> -		I915_WRITE(reg, 0);
> +		I915_WRITE_FW(reg, 0);
>  }
>  
>  static void skl_write_wm_level(struct drm_i915_private *dev_priv,
> @@ -5117,19 +5109,22 @@ static void skl_write_wm_level(struct drm_i915_private *dev_priv,
>  		val |= level->plane_res_l << PLANE_WM_LINES_SHIFT;
>  	}
>  
> -	I915_WRITE(reg, val);
> +	I915_WRITE_FW(reg, val);
>  }
>  
> -static void skl_write_plane_wm(struct intel_crtc *intel_crtc,
> -			       const struct skl_plane_wm *wm,
> -			       const struct skl_ddb_allocation *ddb,
> -			       enum plane_id plane_id)
> +void skl_write_plane_wm(struct intel_plane *plane,
> +			const struct intel_crtc_state *crtc_state)
>  {
> -	struct drm_crtc *crtc = &intel_crtc->base;
> -	struct drm_device *dev = crtc->dev;
> -	struct drm_i915_private *dev_priv = to_i915(dev);
> +	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
>  	int level, max_level = ilk_wm_max_level(dev_priv);
> -	enum pipe pipe = intel_crtc->pipe;
> +	enum plane_id plane_id = plane->id;
> +	enum pipe pipe = plane->pipe;
> +	const struct skl_plane_wm *wm =
> +		&crtc_state->wm.skl.optimal.planes[plane_id];
> +	const struct skl_ddb_entry *ddb_y =
> +		&crtc_state->wm.skl.plane_ddb_y[plane_id];
> +	const struct skl_ddb_entry *ddb_uv =
> +		&crtc_state->wm.skl.plane_ddb_uv[plane_id];
>  
>  	for (level = 0; level <= max_level; level++) {
>  		skl_write_wm_level(dev_priv, PLANE_WM(pipe, plane_id, level),
> @@ -5138,29 +5133,32 @@ static void skl_write_plane_wm(struct intel_crtc *intel_crtc,
>  	skl_write_wm_level(dev_priv, PLANE_WM_TRANS(pipe, plane_id),
>  			   &wm->trans_wm);
>  
> -	if (wm->is_planar && INTEL_GEN(dev_priv) < 11) {
> -		skl_ddb_entry_write(dev_priv, PLANE_BUF_CFG(pipe, plane_id),
> -				    &ddb->uv_plane[pipe][plane_id]);
> +	if (INTEL_GEN(dev_priv) >= 11) {
>  		skl_ddb_entry_write(dev_priv,
> -				    PLANE_NV12_BUF_CFG(pipe, plane_id),
> -				    &ddb->plane[pipe][plane_id]);
> -	} else {
> -		skl_ddb_entry_write(dev_priv, PLANE_BUF_CFG(pipe, plane_id),
> -				    &ddb->plane[pipe][plane_id]);
> -		if (INTEL_GEN(dev_priv) < 11)
> -			I915_WRITE(PLANE_NV12_BUF_CFG(pipe, plane_id), 0x0);
> +				    PLANE_BUF_CFG(pipe, plane_id), ddb_y);
> +		return;
>  	}
> +
> +	if (wm->is_planar)
> +		swap(ddb_y, ddb_uv);

As noted above, I understand why this is, but it sure looks confusing at
a casual glance...


Matt

> +
> +	skl_ddb_entry_write(dev_priv,
> +			    PLANE_BUF_CFG(pipe, plane_id), ddb_y);
> +	skl_ddb_entry_write(dev_priv,
> +			    PLANE_NV12_BUF_CFG(pipe, plane_id), ddb_uv);
>  }
>  
> -static void skl_write_cursor_wm(struct intel_crtc *intel_crtc,
> -				const struct skl_plane_wm *wm,
> -				const struct skl_ddb_allocation *ddb)
> +void skl_write_cursor_wm(struct intel_plane *plane,
> +			 const struct intel_crtc_state *crtc_state)
>  {
> -	struct drm_crtc *crtc = &intel_crtc->base;
> -	struct drm_device *dev = crtc->dev;
> -	struct drm_i915_private *dev_priv = to_i915(dev);
> +	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
>  	int level, max_level = ilk_wm_max_level(dev_priv);
> -	enum pipe pipe = intel_crtc->pipe;
> +	enum plane_id plane_id = plane->id;
> +	enum pipe pipe = plane->pipe;
> +	const struct skl_plane_wm *wm =
> +		&crtc_state->wm.skl.optimal.planes[plane_id];
> +	const struct skl_ddb_entry *ddb =
> +		&crtc_state->wm.skl.plane_ddb_y[plane_id];
>  
>  	for (level = 0; level <= max_level; level++) {
>  		skl_write_wm_level(dev_priv, CUR_WM(pipe, level),
> @@ -5168,8 +5166,7 @@ static void skl_write_cursor_wm(struct intel_crtc *intel_crtc,
>  	}
>  	skl_write_wm_level(dev_priv, CUR_WM_TRANS(pipe), &wm->trans_wm);
>  
> -	skl_ddb_entry_write(dev_priv, CUR_BUF_CFG(pipe),
> -			    &ddb->plane[pipe][PLANE_CURSOR]);
> +	skl_ddb_entry_write(dev_priv, CUR_BUF_CFG(pipe), ddb);
>  }
>  
>  bool skl_wm_level_equals(const struct skl_wm_level *l1,
> @@ -5210,13 +5207,12 @@ bool skl_ddb_allocation_overlaps(const struct skl_ddb_entry *ddb,
>  static int skl_update_pipe_wm(struct drm_crtc_state *cstate,
>  			      const struct skl_pipe_wm *old_pipe_wm,
>  			      struct skl_pipe_wm *pipe_wm, /* out */
> -			      struct skl_ddb_allocation *ddb, /* out */
>  			      bool *changed /* out */)
>  {
>  	struct intel_crtc_state *intel_cstate = to_intel_crtc_state(cstate);
>  	int ret;
>  
> -	ret = skl_build_pipe_wm(intel_cstate, ddb, pipe_wm);
> +	ret = skl_build_pipe_wm(intel_cstate, pipe_wm);
>  	if (ret)
>  		return ret;
>  
> @@ -5242,42 +5238,29 @@ pipes_modified(struct drm_atomic_state *state)
>  }
>  
>  static int
> -skl_ddb_add_affected_planes(struct intel_crtc_state *cstate)
> +skl_ddb_add_affected_planes(const struct intel_crtc_state *old_crtc_state,
> +			    struct intel_crtc_state *new_crtc_state)
>  {
> -	struct drm_atomic_state *state = cstate->base.state;
> -	struct drm_device *dev = state->dev;
> -	struct drm_crtc *crtc = cstate->base.crtc;
> -	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> -	struct drm_i915_private *dev_priv = to_i915(dev);
> -	struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
> -	struct skl_ddb_allocation *new_ddb = &intel_state->wm_results.ddb;
> -	struct skl_ddb_allocation *cur_ddb = &dev_priv->wm.skl_hw.ddb;
> -	struct drm_plane *plane;
> -	enum pipe pipe = intel_crtc->pipe;
> +	struct intel_atomic_state *state = to_intel_atomic_state(new_crtc_state->base.state);
> +	struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->base.crtc);
> +	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
> +	struct intel_plane *plane;
>  
> -	drm_for_each_plane_mask(plane, dev, cstate->base.plane_mask) {
> -		struct drm_plane_state *plane_state;
> -		struct intel_plane *linked;
> -		enum plane_id plane_id = to_intel_plane(plane)->id;
> +	for_each_intel_plane_on_crtc(&dev_priv->drm, crtc, plane) {
> +		struct intel_plane_state *plane_state;
> +		enum plane_id plane_id = plane->id;
>  
> -		if (skl_ddb_entry_equal(&cur_ddb->plane[pipe][plane_id],
> -					&new_ddb->plane[pipe][plane_id]) &&
> -		    skl_ddb_entry_equal(&cur_ddb->uv_plane[pipe][plane_id],
> -					&new_ddb->uv_plane[pipe][plane_id]))
> +		if (skl_ddb_entry_equal(&old_crtc_state->wm.skl.plane_ddb_y[plane_id],
> +					&new_crtc_state->wm.skl.plane_ddb_y[plane_id]) &&
> +		    skl_ddb_entry_equal(&old_crtc_state->wm.skl.plane_ddb_uv[plane_id],
> +					&new_crtc_state->wm.skl.plane_ddb_uv[plane_id]))
>  			continue;
>  
> -		plane_state = drm_atomic_get_plane_state(state, plane);
> +		plane_state = intel_atomic_get_plane_state(state, plane);
>  		if (IS_ERR(plane_state))
>  			return PTR_ERR(plane_state);
>  
> -		/* Make sure linked plane is updated too */
> -		linked = to_intel_plane_state(plane_state)->linked_plane;
> -		if (!linked)
> -			continue;
> -
> -		plane_state = drm_atomic_get_plane_state(state, &linked->base);
> -		if (IS_ERR(plane_state))
> -			return PTR_ERR(plane_state);
> +		new_crtc_state->update_planes |= BIT(plane_id);
>  	}
>  
>  	return 0;
> @@ -5289,18 +5272,21 @@ skl_compute_ddb(struct drm_atomic_state *state)
>  	const struct drm_i915_private *dev_priv = to_i915(state->dev);
>  	struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
>  	struct skl_ddb_allocation *ddb = &intel_state->wm_results.ddb;
> +	struct intel_crtc_state *old_crtc_state;
> +	struct intel_crtc_state *new_crtc_state;
>  	struct intel_crtc *crtc;
> -	struct intel_crtc_state *cstate;
>  	int ret, i;
>  
>  	memcpy(ddb, &dev_priv->wm.skl_hw.ddb, sizeof(*ddb));
>  
> -	for_each_new_intel_crtc_in_state(intel_state, crtc, cstate, i) {
> -		ret = skl_allocate_pipe_ddb(cstate, ddb);
> +	for_each_oldnew_intel_crtc_in_state(intel_state, crtc, old_crtc_state,
> +					    new_crtc_state, i) {
> +		ret = skl_allocate_pipe_ddb(new_crtc_state, ddb);
>  		if (ret)
>  			return ret;
>  
> -		ret = skl_ddb_add_affected_planes(cstate);
> +		ret = skl_ddb_add_affected_planes(old_crtc_state,
> +						  new_crtc_state);
>  		if (ret)
>  			return ret;
>  	}
> @@ -5309,36 +5295,29 @@ skl_compute_ddb(struct drm_atomic_state *state)
>  }
>  
>  static void
> -skl_print_wm_changes(const struct drm_atomic_state *state)
> +skl_print_wm_changes(struct intel_atomic_state *state)
>  {
> -	const struct drm_device *dev = state->dev;
> -	const struct drm_i915_private *dev_priv = to_i915(dev);
> -	const struct intel_atomic_state *intel_state =
> -		to_intel_atomic_state(state);
> -	const struct drm_crtc *crtc;
> -	const struct drm_crtc_state *cstate;
> -	const struct intel_plane *intel_plane;
> -	const struct skl_ddb_allocation *old_ddb = &dev_priv->wm.skl_hw.ddb;
> -	const struct skl_ddb_allocation *new_ddb = &intel_state->wm_results.ddb;
> +	struct drm_i915_private *dev_priv = to_i915(state->base.dev);
> +	const struct intel_crtc_state *old_crtc_state;
> +	const struct intel_crtc_state *new_crtc_state;
> +	struct intel_plane *plane;
> +	struct intel_crtc *crtc;
>  	int i;
>  
> -	for_each_new_crtc_in_state(state, crtc, cstate, i) {
> -		const struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> -		enum pipe pipe = intel_crtc->pipe;
> -
> -		for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) {
> -			enum plane_id plane_id = intel_plane->id;
> +	for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
> +					    new_crtc_state, i) {
> +		for_each_intel_plane_on_crtc(&dev_priv->drm, crtc, plane) {
> +			enum plane_id plane_id = plane->id;
>  			const struct skl_ddb_entry *old, *new;
>  
> -			old = &old_ddb->plane[pipe][plane_id];
> -			new = &new_ddb->plane[pipe][plane_id];
> +			old = &old_crtc_state->wm.skl.plane_ddb_y[plane_id];
> +			new = &new_crtc_state->wm.skl.plane_ddb_y[plane_id];
>  
>  			if (skl_ddb_entry_equal(old, new))
>  				continue;
>  
>  			DRM_DEBUG_KMS("[PLANE:%d:%s] ddb (%d - %d) -> (%d - %d)\n",
> -				      intel_plane->base.base.id,
> -				      intel_plane->base.name,
> +				      plane->base.base.id, plane->base.name,
>  				      old->start, old->end,
>  				      new->start, new->end);
>  		}
> @@ -5474,8 +5453,7 @@ skl_compute_wm(struct drm_atomic_state *state)
>  			&to_intel_crtc_state(crtc->state)->wm.skl.optimal;
>  
>  		pipe_wm = &intel_cstate->wm.skl.optimal;
> -		ret = skl_update_pipe_wm(cstate, old_pipe_wm, pipe_wm,
> -					 &results->ddb, &changed);
> +		ret = skl_update_pipe_wm(cstate, old_pipe_wm, pipe_wm, &changed);
>  		if (ret)
>  			return ret;
>  
> @@ -5489,7 +5467,7 @@ skl_compute_wm(struct drm_atomic_state *state)
>  		intel_cstate->update_wm_pre = true;
>  	}
>  
> -	skl_print_wm_changes(state);
> +	skl_print_wm_changes(intel_state);
>  
>  	return 0;
>  }
> @@ -5500,23 +5478,12 @@ static void skl_atomic_update_crtc_wm(struct intel_atomic_state *state,
>  	struct intel_crtc *crtc = to_intel_crtc(cstate->base.crtc);
>  	struct drm_i915_private *dev_priv = to_i915(state->base.dev);
>  	struct skl_pipe_wm *pipe_wm = &cstate->wm.skl.optimal;
> -	const struct skl_ddb_allocation *ddb = &state->wm_results.ddb;
>  	enum pipe pipe = crtc->pipe;
> -	enum plane_id plane_id;
>  
>  	if (!(state->wm_results.dirty_pipes & drm_crtc_mask(&crtc->base)))
>  		return;
>  
>  	I915_WRITE(PIPE_WM_LINETIME(pipe), pipe_wm->linetime);
> -
> -	for_each_plane_id_on_crtc(crtc, plane_id) {
> -		if (plane_id != PLANE_CURSOR)
> -			skl_write_plane_wm(crtc, &pipe_wm->planes[plane_id],
> -					   ddb, plane_id);
> -		else
> -			skl_write_cursor_wm(crtc, &pipe_wm->planes[plane_id],
> -					    ddb);
> -	}
>  }
>  
>  static void skl_initial_wm(struct intel_atomic_state *state,
> @@ -5526,8 +5493,6 @@ static void skl_initial_wm(struct intel_atomic_state *state,
>  	struct drm_device *dev = intel_crtc->base.dev;
>  	struct drm_i915_private *dev_priv = to_i915(dev);
>  	struct skl_ddb_values *results = &state->wm_results;
> -	struct skl_ddb_values *hw_vals = &dev_priv->wm.skl_hw;
> -	enum pipe pipe = intel_crtc->pipe;
>  
>  	if ((results->dirty_pipes & drm_crtc_mask(&intel_crtc->base)) == 0)
>  		return;
> @@ -5537,11 +5502,6 @@ static void skl_initial_wm(struct intel_atomic_state *state,
>  	if (cstate->base.active_changed)
>  		skl_atomic_update_crtc_wm(state, cstate);
>  
> -	memcpy(hw_vals->ddb.uv_plane[pipe], results->ddb.uv_plane[pipe],
> -	       sizeof(hw_vals->ddb.uv_plane[pipe]));
> -	memcpy(hw_vals->ddb.plane[pipe], results->ddb.plane[pipe],
> -	       sizeof(hw_vals->ddb.plane[pipe]));
> -
>  	mutex_unlock(&dev_priv->wm.wm_mutex);
>  }
>  
> @@ -5692,13 +5652,6 @@ void skl_wm_get_hw_state(struct drm_device *dev)
>  	if (dev_priv->active_crtcs) {
>  		/* Fully recompute DDB on first atomic commit */
>  		dev_priv->wm.distrust_bios_wm = true;
> -	} else {
> -		/*
> -		 * Easy/common case; just sanitize DDB now if everything off
> -		 * Keep dbuf slice info intact
> -		 */
> -		memset(ddb->plane, 0, sizeof(ddb->plane));
> -		memset(ddb->uv_plane, 0, sizeof(ddb->uv_plane));
>  	}
>  }
>  
> diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
> index 74d904a49bf9..0262159e7084 100644
> --- a/drivers/gpu/drm/i915/intel_sprite.c
> +++ b/drivers/gpu/drm/i915/intel_sprite.c
> @@ -542,6 +542,8 @@ skl_program_plane(struct intel_plane *plane,
>  	if (fb->format->is_yuv && icl_is_hdr_plane(plane))
>  		icl_program_input_csc_coeff(crtc_state, plane_state);
>  
> +	skl_write_plane_wm(plane, crtc_state);
> +
>  	I915_WRITE_FW(PLANE_KEYVAL(pipe, plane_id), key->min_value);
>  	I915_WRITE_FW(PLANE_KEYMSK(pipe, plane_id), keymsk);
>  	I915_WRITE_FW(PLANE_KEYMAX(pipe, plane_id), keymax);
> @@ -604,6 +606,8 @@ skl_disable_plane(struct intel_plane *plane,
>  
>  	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
>  
> +	skl_write_plane_wm(plane, crtc_state);
> +
>  	I915_WRITE_FW(PLANE_CTL(pipe, plane_id), 0);
>  	I915_WRITE_FW(PLANE_SURF(pipe, plane_id), 0);
>  
> -- 
> 2.18.1
>
Ville Syrjälä Nov. 21, 2018, 7:01 p.m. UTC | #2
On Tue, Nov 20, 2018 at 04:48:39PM -0800, Matt Roper wrote:
> On Wed, Nov 14, 2018 at 11:07:26PM +0200, Ville Syrjala wrote:
> > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > 
> > On SKL+ the plane WM/BUF_CFG registers are a proper part of each
> > plane's register set. That means accessing them will cancel any
> > pending plane update, and we would need a PLANE_SURF register write
> > to arm the wm/ddb change as well.
> > 
> > To avoid all the problems with that let's just move the wm/ddb
> > programming into the plane update/disable hooks. Now all plane
> > registers get written in one (hopefully atomic) operation.
> > 
> > To make that feasible we'll move the plane ddb tracking into
> > the crtc state. Watermarks were already tracked there.
> > 
> > v2: Rebase due to input CSC
> > v3: Split out a bunch of junk (Matt)
> > 
> > Cc: Matt Roper <matthew.d.roper@intel.com>
> > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > ---
> >  drivers/gpu/drm/i915/i915_debugfs.c  |  21 +-
> >  drivers/gpu/drm/i915/i915_drv.h      |   3 -
> >  drivers/gpu/drm/i915/intel_display.c |  16 +-
> >  drivers/gpu/drm/i915/intel_display.h |  11 +-
> >  drivers/gpu/drm/i915/intel_drv.h     |   9 +
> >  drivers/gpu/drm/i915/intel_pm.c      | 317 ++++++++++++---------------
> >  drivers/gpu/drm/i915/intel_sprite.c  |   4 +
> >  7 files changed, 181 insertions(+), 200 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
> > index 670db5073d70..f8b2200947cf 100644
> > --- a/drivers/gpu/drm/i915/i915_debugfs.c
> > +++ b/drivers/gpu/drm/i915/i915_debugfs.c
> > @@ -3437,31 +3437,32 @@ static int i915_ddb_info(struct seq_file *m, void *unused)
> >  {
> >  	struct drm_i915_private *dev_priv = node_to_i915(m->private);
> >  	struct drm_device *dev = &dev_priv->drm;
> > -	struct skl_ddb_allocation *ddb;
> >  	struct skl_ddb_entry *entry;
> > -	enum pipe pipe;
> > -	int plane;
> > +	struct intel_crtc *crtc;
> >  
> >  	if (INTEL_GEN(dev_priv) < 9)
> >  		return -ENODEV;
> >  
> >  	drm_modeset_lock_all(dev);
> >  
> > -	ddb = &dev_priv->wm.skl_hw.ddb;
> > -
> >  	seq_printf(m, "%-15s%8s%8s%8s\n", "", "Start", "End", "Size");
> >  
> > -	for_each_pipe(dev_priv, pipe) {
> > +	for_each_intel_crtc(&dev_priv->drm, crtc) {
> > +		struct intel_crtc_state *crtc_state =
> > +			to_intel_crtc_state(crtc->base.state);
> > +		enum pipe pipe = crtc->pipe;
> > +		enum plane_id plane_id;
> > +
> >  		seq_printf(m, "Pipe %c\n", pipe_name(pipe));
> >  
> > -		for_each_universal_plane(dev_priv, pipe, plane) {
> > -			entry = &ddb->plane[pipe][plane];
> > -			seq_printf(m, "  Plane%-8d%8u%8u%8u\n", plane + 1,
> > +		for_each_plane_id_on_crtc(crtc, plane_id) {
> > +			entry = &crtc_state->wm.skl.plane_ddb_y[plane_id];
> > +			seq_printf(m, "  Plane%-8d%8u%8u%8u\n", plane_id + 1,
> >  				   entry->start, entry->end,
> >  				   skl_ddb_entry_size(entry));
> >  		}
> >  
> > -		entry = &ddb->plane[pipe][PLANE_CURSOR];
> > +		entry = &crtc_state->wm.skl.plane_ddb_y[PLANE_CURSOR];
> >  		seq_printf(m, "  %-13s%8u%8u%8u\n", "Cursor", entry->start,
> >  			   entry->end, skl_ddb_entry_size(entry));
> >  	}
> > diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> > index 5d686b585a95..89af64fe90a5 100644
> > --- a/drivers/gpu/drm/i915/i915_drv.h
> > +++ b/drivers/gpu/drm/i915/i915_drv.h
> > @@ -1241,9 +1241,6 @@ static inline bool skl_ddb_entry_equal(const struct skl_ddb_entry *e1,
> >  }
> >  
> >  struct skl_ddb_allocation {
> > -	/* packed/y */
> > -	struct skl_ddb_entry plane[I915_MAX_PIPES][I915_MAX_PLANES];
> > -	struct skl_ddb_entry uv_plane[I915_MAX_PIPES][I915_MAX_PLANES];
> >  	u8 enabled_slices; /* GEN11 has configurable 2 slices */
> >  };
> >  
> > diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> > index 0caba7258fee..2981cea3704a 100644
> > --- a/drivers/gpu/drm/i915/intel_display.c
> > +++ b/drivers/gpu/drm/i915/intel_display.c
> > @@ -10083,6 +10083,10 @@ static void i9xx_update_cursor(struct intel_plane *plane,
> >  	 * except when the plane is getting enabled at which time
> >  	 * the CURCNTR write arms the update.
> >  	 */
> > +
> > +	if (INTEL_GEN(dev_priv) >= 9)
> > +		skl_write_cursor_wm(plane, crtc_state);
> > +
> >  	if (plane->cursor.base != base ||
> >  	    plane->cursor.size != fbc_ctl ||
> >  	    plane->cursor.cntl != cntl) {
> > @@ -11872,6 +11876,8 @@ static void verify_wm_state(struct drm_crtc *crtc,
> >  	struct skl_pipe_wm hw_wm, *sw_wm;
> >  	struct skl_plane_wm *hw_plane_wm, *sw_plane_wm;
> >  	struct skl_ddb_entry *hw_ddb_entry, *sw_ddb_entry;
> > +	struct skl_ddb_entry hw_ddb_y[I915_MAX_PLANES];
> > +	struct skl_ddb_entry hw_ddb_uv[I915_MAX_PLANES];
> >  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> >  	const enum pipe pipe = intel_crtc->pipe;
> >  	int plane, level, max_level = ilk_wm_max_level(dev_priv);
> > @@ -11882,6 +11888,8 @@ static void verify_wm_state(struct drm_crtc *crtc,
> >  	skl_pipe_wm_get_hw_state(crtc, &hw_wm);
> >  	sw_wm = &to_intel_crtc_state(new_state)->wm.skl.optimal;
> >  
> > +	skl_pipe_ddb_get_hw_state(intel_crtc, hw_ddb_y, hw_ddb_uv);
> > +
> >  	skl_ddb_get_hw_state(dev_priv, &hw_ddb);
> >  	sw_ddb = &dev_priv->wm.skl_hw.ddb;
> >  
> > @@ -11924,8 +11932,8 @@ static void verify_wm_state(struct drm_crtc *crtc,
> >  		}
> >  
> >  		/* DDB */
> > -		hw_ddb_entry = &hw_ddb.plane[pipe][plane];
> > -		sw_ddb_entry = &sw_ddb->plane[pipe][plane];
> > +		hw_ddb_entry = &hw_ddb_y[plane];
> > +		sw_ddb_entry = &to_intel_crtc_state(new_state)->wm.skl.plane_ddb_y[plane];
> >  
> >  		if (!skl_ddb_entry_equal(hw_ddb_entry, sw_ddb_entry)) {
> >  			DRM_ERROR("mismatch in DDB state pipe %c plane %d (expected (%u,%u), found (%u,%u))\n",
> > @@ -11974,8 +11982,8 @@ static void verify_wm_state(struct drm_crtc *crtc,
> >  		}
> >  
> >  		/* DDB */
> > -		hw_ddb_entry = &hw_ddb.plane[pipe][PLANE_CURSOR];
> > -		sw_ddb_entry = &sw_ddb->plane[pipe][PLANE_CURSOR];
> > +		hw_ddb_entry = &hw_ddb_y[PLANE_CURSOR];
> > +		sw_ddb_entry = &to_intel_crtc_state(new_state)->wm.skl.plane_ddb_y[PLANE_CURSOR];
> >  
> >  		if (!skl_ddb_entry_equal(hw_ddb_entry, sw_ddb_entry)) {
> >  			DRM_ERROR("mismatch in DDB state pipe %c cursor (expected (%u,%u), found (%u,%u))\n",
> > diff --git a/drivers/gpu/drm/i915/intel_display.h b/drivers/gpu/drm/i915/intel_display.h
> > index df9e6ebb27de..078406dc65e5 100644
> > --- a/drivers/gpu/drm/i915/intel_display.h
> > +++ b/drivers/gpu/drm/i915/intel_display.h
> > @@ -319,7 +319,7 @@ struct intel_link_m_n {
> >  			    &(dev)->mode_config.plane_list,		\
> >  			    base.head)					\
> >  		for_each_if((plane_mask) &				\
> > -			    drm_plane_mask(&intel_plane->base)))
> > +			    drm_plane_mask(&intel_plane->base))
> >  
> >  #define for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane)	\
> >  	list_for_each_entry(intel_plane,				\
> > @@ -415,6 +415,15 @@ struct intel_link_m_n {
> >  	     (__i)++) \
> >  		for_each_if(plane)
> >  
> > +#define for_each_oldnew_intel_crtc_in_state(__state, crtc, old_crtc_state, new_crtc_state, __i) \
> > +	for ((__i) = 0; \
> > +	     (__i) < (__state)->base.dev->mode_config.num_crtc && \
> > +		     ((crtc) = to_intel_crtc((__state)->base.crtcs[__i].ptr), \
> > +		      (old_crtc_state) = to_intel_crtc_state((__state)->base.crtcs[__i].old_state), \
> > +		      (new_crtc_state) = to_intel_crtc_state((__state)->base.crtcs[__i].new_state), 1); \
> > +	     (__i)++) \
> > +		for_each_if(crtc)
> > +
> >  void intel_link_compute_m_n(int bpp, int nlanes,
> >  			    int pixel_clock, int link_clock,
> >  			    struct intel_link_m_n *m_n,
> > diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> > index 23b33970db17..4a9af09c483a 100644
> > --- a/drivers/gpu/drm/i915/intel_drv.h
> > +++ b/drivers/gpu/drm/i915/intel_drv.h
> > @@ -705,6 +705,8 @@ struct intel_crtc_wm_state {
> >  			/* gen9+ only needs 1-step wm programming */
> >  			struct skl_pipe_wm optimal;
> >  			struct skl_ddb_entry ddb;
> > +			struct skl_ddb_entry plane_ddb_y[I915_MAX_PLANES];
> > +			struct skl_ddb_entry plane_ddb_uv[I915_MAX_PLANES];
> 
> I feel like naming these _y and _uv is going to cause confusion.  The Y
> and UV are backwards half the time (based on the swap we have to do
> farther down), and doesn't have meaning at all for RGB.  Maybe name
> these something like "plane_ddb_main" and "plane_ddb_extra" to somewhat
> disassociate it with the actual type of data it's supposed to represent?
> 
> If you want to keep the _y and _uv (which are nice and short), I think
> we at least need some warning comments here explaining the behavior.

Yeah, I was also thinking we might want to just start following the
hardware convention with these and get rid of the swap()s. My initial
idea was just something like ddb[] and ddb_nv12[] to match the
register names.

But let's do that as a followup maybe?

> 
> >  		} skl;
> >  
> >  		struct {
> > @@ -2183,6 +2185,9 @@ void g4x_wm_get_hw_state(struct drm_device *dev);
> >  void vlv_wm_get_hw_state(struct drm_device *dev);
> >  void ilk_wm_get_hw_state(struct drm_device *dev);
> >  void skl_wm_get_hw_state(struct drm_device *dev);
> > +void skl_pipe_ddb_get_hw_state(struct intel_crtc *crtc,
> > +			       struct skl_ddb_entry *ddb_y,
> > +			       struct skl_ddb_entry *ddb_uv);
> >  void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv,
> >  			  struct skl_ddb_allocation *ddb /* out */);
> >  void skl_pipe_wm_get_hw_state(struct drm_crtc *crtc,
> > @@ -2197,6 +2202,10 @@ bool skl_wm_level_equals(const struct skl_wm_level *l1,
> >  bool skl_ddb_allocation_overlaps(const struct skl_ddb_entry *ddb,
> >  				 const struct skl_ddb_entry entries[],
> >  				 int num_entries, int ignore_idx);
> > +void skl_write_plane_wm(struct intel_plane *plane,
> > +			const struct intel_crtc_state *crtc_state);
> > +void skl_write_cursor_wm(struct intel_plane *plane,
> > +			 const struct intel_crtc_state *crtc_state);
> >  bool ilk_disable_lp_wm(struct drm_device *dev);
> >  int skl_check_pipe_max_pixel_rate(struct intel_crtc *intel_crtc,
> >  				  struct intel_crtc_state *cstate);
> > diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> > index a21654c974ba..1b337004054a 100644
> > --- a/drivers/gpu/drm/i915/intel_pm.c
> > +++ b/drivers/gpu/drm/i915/intel_pm.c
> > @@ -3912,68 +3912,70 @@ static void
> >  skl_ddb_get_hw_plane_state(struct drm_i915_private *dev_priv,
> >  			   const enum pipe pipe,
> >  			   const enum plane_id plane_id,
> > -			   struct skl_ddb_allocation *ddb /* out */)
> > +			   struct skl_ddb_entry *ddb_y,
> > +			   struct skl_ddb_entry *ddb_uv)
> >  {
> > -	u32 val, val2 = 0;
> > -	int fourcc, pixel_format;
> > +	u32 val, val2;
> > +	u32 fourcc = 0;
> >  
> >  	/* Cursor doesn't support NV12/planar, so no extra calculation needed */
> >  	if (plane_id == PLANE_CURSOR) {
> >  		val = I915_READ(CUR_BUF_CFG(pipe));
> > -		skl_ddb_entry_init_from_hw(dev_priv,
> > -					   &ddb->plane[pipe][plane_id], val);
> > +		skl_ddb_entry_init_from_hw(dev_priv, ddb_y, val);
> >  		return;
> >  	}
> >  
> >  	val = I915_READ(PLANE_CTL(pipe, plane_id));
> >  
> >  	/* No DDB allocated for disabled planes */
> > -	if (!(val & PLANE_CTL_ENABLE))
> > -		return;
> 
> I think we should mention the readout behavior change in the commit
> message (i.e., we now read out DDB even if we think the plane is
> disabled).  Either that or move the behavior change to a separate patch.
> 
> We should also drop the comment line since I don't think it really makes
> sense anymore.

Sure.

> 
> > +	if (val & PLANE_CTL_ENABLE)
> > +		fourcc = skl_format_to_fourcc(val & PLANE_CTL_FORMAT_MASK,
> > +					      val & PLANE_CTL_ORDER_RGBX,
> > +					      val & PLANE_CTL_ALPHA_MASK);
> >  
> > -	pixel_format = val & PLANE_CTL_FORMAT_MASK;
> > -	fourcc = skl_format_to_fourcc(pixel_format,
> > -				      val & PLANE_CTL_ORDER_RGBX,
> > -				      val & PLANE_CTL_ALPHA_MASK);
> > -
> > -	val = I915_READ(PLANE_BUF_CFG(pipe, plane_id));
> > -	if (fourcc == DRM_FORMAT_NV12 && INTEL_GEN(dev_priv) < 11) {
> > +	if (INTEL_GEN(dev_priv) >= 11) {
> > +		val = I915_READ(PLANE_BUF_CFG(pipe, plane_id));
> > +		skl_ddb_entry_init_from_hw(dev_priv, ddb_y, val);
> > +	} else {
> > +		val = I915_READ(PLANE_BUF_CFG(pipe, plane_id));
> >  		val2 = I915_READ(PLANE_NV12_BUF_CFG(pipe, plane_id));
> >  
> > -		skl_ddb_entry_init_from_hw(dev_priv,
> > -					   &ddb->plane[pipe][plane_id], val2);
> > -		skl_ddb_entry_init_from_hw(dev_priv,
> > -					   &ddb->uv_plane[pipe][plane_id], val);
> > -	} else {
> > -		skl_ddb_entry_init_from_hw(dev_priv,
> > -					   &ddb->plane[pipe][plane_id], val);
> > +		if (fourcc == DRM_FORMAT_NV12)
> > +			swap(val, val2);
> > +
> > +		skl_ddb_entry_init_from_hw(dev_priv, ddb_y, val);
> > +		skl_ddb_entry_init_from_hw(dev_priv, ddb_uv, val2);
> >  	}
> >  }
> >  
> > +void skl_pipe_ddb_get_hw_state(struct intel_crtc *crtc,
> > +			       struct skl_ddb_entry *ddb_y,
> > +			       struct skl_ddb_entry *ddb_uv)
> > +{
> > +	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
> > +	enum intel_display_power_domain power_domain;
> > +	enum pipe pipe = crtc->pipe;
> > +	enum plane_id plane_id;
> > +
> > +	power_domain = POWER_DOMAIN_PIPE(pipe);
> > +	if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
> > +		return;
> > +
> > +	for_each_plane_id_on_crtc(crtc, plane_id)
> > +		skl_ddb_get_hw_plane_state(dev_priv, pipe,
> > +					   plane_id,
> > +					   &ddb_y[plane_id],
> > +					   &ddb_uv[plane_id]);
> > +
> > +	intel_display_power_put(dev_priv, power_domain);
> > +}
> > +
> >  void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv,
> >  			  struct skl_ddb_allocation *ddb /* out */)
> >  {
> > -	struct intel_crtc *crtc;
> > -
> >  	memset(ddb, 0, sizeof(*ddb));
> 
> We can drop the memset.  The entire structure is only 1 byte now, and we
> set its only remaining field on the next line.

Ack.

> 
> >  
> >  	ddb->enabled_slices = intel_enabled_dbuf_slices_num(dev_priv);
> > -
> > -	for_each_intel_crtc(&dev_priv->drm, crtc) {
> > -		enum intel_display_power_domain power_domain;
> > -		enum plane_id plane_id;
> > -		enum pipe pipe = crtc->pipe;
> > -
> > -		power_domain = POWER_DOMAIN_PIPE(pipe);
> > -		if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
> > -			continue;
> > -
> > -		for_each_plane_id_on_crtc(crtc, plane_id)
> > -			skl_ddb_get_hw_plane_state(dev_priv, pipe,
> > -						   plane_id, ddb);
> > -
> > -		intel_display_power_put(dev_priv, power_domain);
> > -	}
> >  }
> >  
> >  /*
> > @@ -4371,7 +4373,6 @@ skl_allocate_pipe_ddb(struct intel_crtc_state *cstate,
> >  	struct drm_crtc *crtc = cstate->base.crtc;
> >  	struct drm_i915_private *dev_priv = to_i915(crtc->dev);
> >  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> > -	enum pipe pipe = intel_crtc->pipe;
> >  	struct skl_ddb_entry *alloc = &cstate->wm.skl.ddb;
> >  	uint16_t alloc_size, start;
> >  	uint16_t minimum[I915_MAX_PLANES] = {};
> > @@ -4384,8 +4385,8 @@ skl_allocate_pipe_ddb(struct intel_crtc_state *cstate,
> >  	uint16_t total_min_blocks = 0;
> >  
> >  	/* Clear the partitioning for disabled planes. */
> > -	memset(ddb->plane[pipe], 0, sizeof(ddb->plane[pipe]));
> > -	memset(ddb->uv_plane[pipe], 0, sizeof(ddb->uv_plane[pipe]));
> > +	memset(cstate->wm.skl.plane_ddb_y, 0, sizeof(cstate->wm.skl.plane_ddb_y));
> > +	memset(cstate->wm.skl.plane_ddb_uv, 0, sizeof(cstate->wm.skl.plane_ddb_uv));
> >  
> >  	if (WARN_ON(!state))
> >  		return 0;
> > @@ -4432,8 +4433,8 @@ skl_allocate_pipe_ddb(struct intel_crtc_state *cstate,
> >  	}
> >  
> >  	alloc_size -= total_min_blocks;
> > -	ddb->plane[pipe][PLANE_CURSOR].start = alloc->end - minimum[PLANE_CURSOR];
> > -	ddb->plane[pipe][PLANE_CURSOR].end = alloc->end;
> > +	cstate->wm.skl.plane_ddb_y[PLANE_CURSOR].start = alloc->end - minimum[PLANE_CURSOR];
> > +	cstate->wm.skl.plane_ddb_y[PLANE_CURSOR].end = alloc->end;
> >  
> >  	/*
> >  	 * 2. Distribute the remaining space in proportion to the amount of
> > @@ -4464,8 +4465,8 @@ skl_allocate_pipe_ddb(struct intel_crtc_state *cstate,
> >  
> >  		/* Leave disabled planes at (0,0) */
> >  		if (data_rate) {
> > -			ddb->plane[pipe][plane_id].start = start;
> > -			ddb->plane[pipe][plane_id].end = start + plane_blocks;
> > +			cstate->wm.skl.plane_ddb_y[plane_id].start = start;
> > +			cstate->wm.skl.plane_ddb_y[plane_id].end = start + plane_blocks;
> >  		}
> >  
> >  		start += plane_blocks;
> > @@ -4480,8 +4481,8 @@ skl_allocate_pipe_ddb(struct intel_crtc_state *cstate,
> >  		WARN_ON(INTEL_GEN(dev_priv) >= 11 && uv_plane_blocks);
> >  
> >  		if (uv_data_rate) {
> > -			ddb->uv_plane[pipe][plane_id].start = start;
> > -			ddb->uv_plane[pipe][plane_id].end =
> > +			cstate->wm.skl.plane_ddb_uv[plane_id].start = start;
> > +			cstate->wm.skl.plane_ddb_uv[plane_id].end =
> >  				start + uv_plane_blocks;
> >  		}
> >  
> > @@ -4939,16 +4940,13 @@ static void skl_compute_transition_wm(const struct intel_crtc_state *cstate,
> >  	}
> >  }
> >  
> > -static int skl_build_plane_wm_single(struct skl_ddb_allocation *ddb,
> > -				     struct intel_crtc_state *crtc_state,
> > +static int skl_build_plane_wm_single(struct intel_crtc_state *crtc_state,
> >  				     const struct intel_plane_state *plane_state,
> >  				     enum plane_id plane_id, int color_plane)
> >  {
> > -	struct intel_plane *plane = to_intel_plane(plane_state->base.plane);
> >  	struct skl_plane_wm *wm = &crtc_state->wm.skl.optimal.planes[plane_id];
> > +	u16 ddb_blocks = skl_ddb_entry_size(&crtc_state->wm.skl.plane_ddb_y[plane_id]);
> >  	struct skl_wm_params wm_params;
> > -	enum pipe pipe = plane->pipe;
> > -	uint16_t ddb_blocks = skl_ddb_entry_size(&ddb->plane[pipe][plane_id]);
> >  	int ret;
> >  
> >  	ret = skl_compute_plane_wm_params(crtc_state, plane_state,
> > @@ -4966,16 +4964,13 @@ static int skl_build_plane_wm_single(struct skl_ddb_allocation *ddb,
> >  	return 0;
> >  }
> >  
> > -static int skl_build_plane_wm_uv(struct skl_ddb_allocation *ddb,
> > -				 struct intel_crtc_state *crtc_state,
> > +static int skl_build_plane_wm_uv(struct intel_crtc_state *crtc_state,
> >  				 const struct intel_plane_state *plane_state,
> >  				 enum plane_id plane_id)
> >  {
> > -	struct intel_plane *plane = to_intel_plane(plane_state->base.plane);
> >  	struct skl_plane_wm *wm = &crtc_state->wm.skl.optimal.planes[plane_id];
> > +	u16 ddb_blocks = skl_ddb_entry_size(&crtc_state->wm.skl.plane_ddb_uv[plane_id]);
> >  	struct skl_wm_params wm_params;
> > -	enum pipe pipe = plane->pipe;
> > -	uint16_t ddb_blocks = skl_ddb_entry_size(&ddb->uv_plane[pipe][plane_id]);
> >  	int ret;
> >  
> >  	wm->is_planar = true;
> > @@ -4994,8 +4989,7 @@ static int skl_build_plane_wm_uv(struct skl_ddb_allocation *ddb,
> >  	return 0;
> >  }
> >  
> > -static int skl_build_plane_wm(struct skl_ddb_allocation *ddb,
> > -			      struct skl_pipe_wm *pipe_wm,
> > +static int skl_build_plane_wm(struct skl_pipe_wm *pipe_wm,
> >  			      struct intel_crtc_state *crtc_state,
> >  			      const struct intel_plane_state *plane_state)
> >  {
> > @@ -5007,13 +5001,13 @@ static int skl_build_plane_wm(struct skl_ddb_allocation *ddb,
> >  	if (!intel_wm_plane_visible(crtc_state, plane_state))
> >  		return 0;
> >  
> > -	ret = skl_build_plane_wm_single(ddb, crtc_state, plane_state,
> > +	ret = skl_build_plane_wm_single(crtc_state, plane_state,
> >  					plane_id, 0);
> >  	if (ret)
> >  		return ret;
> >  
> >  	if (fb->format->is_yuv && fb->format->num_planes > 1) {
> > -		ret = skl_build_plane_wm_uv(ddb, crtc_state, plane_state,
> > +		ret = skl_build_plane_wm_uv(crtc_state, plane_state,
> >  					    plane_id);
> >  		if (ret)
> >  			return ret;
> > @@ -5022,8 +5016,7 @@ static int skl_build_plane_wm(struct skl_ddb_allocation *ddb,
> >  	return 0;
> >  }
> >  
> > -static int icl_build_plane_wm(struct skl_ddb_allocation *ddb,
> > -			      struct skl_pipe_wm *pipe_wm,
> > +static int icl_build_plane_wm(struct skl_pipe_wm *pipe_wm,
> >  			      struct intel_crtc_state *crtc_state,
> >  			      const struct intel_plane_state *plane_state)
> >  {
> > @@ -5041,17 +5034,17 @@ static int icl_build_plane_wm(struct skl_ddb_allocation *ddb,
> >  		WARN_ON(!fb->format->is_yuv ||
> >  			fb->format->num_planes == 1);
> >  
> > -		ret = skl_build_plane_wm_single(ddb, crtc_state, plane_state,
> > +		ret = skl_build_plane_wm_single(crtc_state, plane_state,
> >  						y_plane_id, 0);
> >  		if (ret)
> >  			return ret;
> >  
> > -		ret = skl_build_plane_wm_single(ddb, crtc_state, plane_state,
> > +		ret = skl_build_plane_wm_single(crtc_state, plane_state,
> >  						plane_id, 1);
> >  		if (ret)
> >  			return ret;
> >  	} else if (intel_wm_plane_visible(crtc_state, plane_state)) {
> > -		ret = skl_build_plane_wm_single(ddb, crtc_state, plane_state,
> > +		ret = skl_build_plane_wm_single(crtc_state, plane_state,
> >  						plane_id, 0);
> >  		if (ret)
> >  			return ret;
> > @@ -5061,7 +5054,6 @@ static int icl_build_plane_wm(struct skl_ddb_allocation *ddb,
> >  }
> >  
> >  static int skl_build_pipe_wm(struct intel_crtc_state *cstate,
> > -			     struct skl_ddb_allocation *ddb,
> >  			     struct skl_pipe_wm *pipe_wm)
> >  {
> >  	struct drm_i915_private *dev_priv = to_i915(cstate->base.crtc->dev);
> > @@ -5081,10 +5073,10 @@ static int skl_build_pipe_wm(struct intel_crtc_state *cstate,
> >  						to_intel_plane_state(pstate);
> >  
> >  		if (INTEL_GEN(dev_priv) >= 11)
> > -			ret = icl_build_plane_wm(ddb, pipe_wm,
> > +			ret = icl_build_plane_wm(pipe_wm,
> >  						 cstate, intel_pstate);
> >  		else
> > -			ret = skl_build_plane_wm(ddb, pipe_wm,
> > +			ret = skl_build_plane_wm(pipe_wm,
> >  						 cstate, intel_pstate);
> >  		if (ret)
> >  			return ret;
> > @@ -5100,9 +5092,9 @@ static void skl_ddb_entry_write(struct drm_i915_private *dev_priv,
> >  				const struct skl_ddb_entry *entry)
> >  {
> >  	if (entry->end)
> > -		I915_WRITE(reg, (entry->end - 1) << 16 | entry->start);
> > +		I915_WRITE_FW(reg, (entry->end - 1) << 16 | entry->start);
> >  	else
> > -		I915_WRITE(reg, 0);
> > +		I915_WRITE_FW(reg, 0);
> >  }
> >  
> >  static void skl_write_wm_level(struct drm_i915_private *dev_priv,
> > @@ -5117,19 +5109,22 @@ static void skl_write_wm_level(struct drm_i915_private *dev_priv,
> >  		val |= level->plane_res_l << PLANE_WM_LINES_SHIFT;
> >  	}
> >  
> > -	I915_WRITE(reg, val);
> > +	I915_WRITE_FW(reg, val);
> >  }
> >  
> > -static void skl_write_plane_wm(struct intel_crtc *intel_crtc,
> > -			       const struct skl_plane_wm *wm,
> > -			       const struct skl_ddb_allocation *ddb,
> > -			       enum plane_id plane_id)
> > +void skl_write_plane_wm(struct intel_plane *plane,
> > +			const struct intel_crtc_state *crtc_state)
> >  {
> > -	struct drm_crtc *crtc = &intel_crtc->base;
> > -	struct drm_device *dev = crtc->dev;
> > -	struct drm_i915_private *dev_priv = to_i915(dev);
> > +	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
> >  	int level, max_level = ilk_wm_max_level(dev_priv);
> > -	enum pipe pipe = intel_crtc->pipe;
> > +	enum plane_id plane_id = plane->id;
> > +	enum pipe pipe = plane->pipe;
> > +	const struct skl_plane_wm *wm =
> > +		&crtc_state->wm.skl.optimal.planes[plane_id];
> > +	const struct skl_ddb_entry *ddb_y =
> > +		&crtc_state->wm.skl.plane_ddb_y[plane_id];
> > +	const struct skl_ddb_entry *ddb_uv =
> > +		&crtc_state->wm.skl.plane_ddb_uv[plane_id];
> >  
> >  	for (level = 0; level <= max_level; level++) {
> >  		skl_write_wm_level(dev_priv, PLANE_WM(pipe, plane_id, level),
> > @@ -5138,29 +5133,32 @@ static void skl_write_plane_wm(struct intel_crtc *intel_crtc,
> >  	skl_write_wm_level(dev_priv, PLANE_WM_TRANS(pipe, plane_id),
> >  			   &wm->trans_wm);
> >  
> > -	if (wm->is_planar && INTEL_GEN(dev_priv) < 11) {
> > -		skl_ddb_entry_write(dev_priv, PLANE_BUF_CFG(pipe, plane_id),
> > -				    &ddb->uv_plane[pipe][plane_id]);
> > +	if (INTEL_GEN(dev_priv) >= 11) {
> >  		skl_ddb_entry_write(dev_priv,
> > -				    PLANE_NV12_BUF_CFG(pipe, plane_id),
> > -				    &ddb->plane[pipe][plane_id]);
> > -	} else {
> > -		skl_ddb_entry_write(dev_priv, PLANE_BUF_CFG(pipe, plane_id),
> > -				    &ddb->plane[pipe][plane_id]);
> > -		if (INTEL_GEN(dev_priv) < 11)
> > -			I915_WRITE(PLANE_NV12_BUF_CFG(pipe, plane_id), 0x0);
> > +				    PLANE_BUF_CFG(pipe, plane_id), ddb_y);
> > +		return;
> >  	}
> > +
> > +	if (wm->is_planar)
> > +		swap(ddb_y, ddb_uv);
> 
> As noted above, I understand why this is, but it sure looks confusing at
> a casual glance...
> 
> 
> Matt
> 
> > +
> > +	skl_ddb_entry_write(dev_priv,
> > +			    PLANE_BUF_CFG(pipe, plane_id), ddb_y);
> > +	skl_ddb_entry_write(dev_priv,
> > +			    PLANE_NV12_BUF_CFG(pipe, plane_id), ddb_uv);
> >  }
> >  
> > -static void skl_write_cursor_wm(struct intel_crtc *intel_crtc,
> > -				const struct skl_plane_wm *wm,
> > -				const struct skl_ddb_allocation *ddb)
> > +void skl_write_cursor_wm(struct intel_plane *plane,
> > +			 const struct intel_crtc_state *crtc_state)
> >  {
> > -	struct drm_crtc *crtc = &intel_crtc->base;
> > -	struct drm_device *dev = crtc->dev;
> > -	struct drm_i915_private *dev_priv = to_i915(dev);
> > +	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
> >  	int level, max_level = ilk_wm_max_level(dev_priv);
> > -	enum pipe pipe = intel_crtc->pipe;
> > +	enum plane_id plane_id = plane->id;
> > +	enum pipe pipe = plane->pipe;
> > +	const struct skl_plane_wm *wm =
> > +		&crtc_state->wm.skl.optimal.planes[plane_id];
> > +	const struct skl_ddb_entry *ddb =
> > +		&crtc_state->wm.skl.plane_ddb_y[plane_id];
> >  
> >  	for (level = 0; level <= max_level; level++) {
> >  		skl_write_wm_level(dev_priv, CUR_WM(pipe, level),
> > @@ -5168,8 +5166,7 @@ static void skl_write_cursor_wm(struct intel_crtc *intel_crtc,
> >  	}
> >  	skl_write_wm_level(dev_priv, CUR_WM_TRANS(pipe), &wm->trans_wm);
> >  
> > -	skl_ddb_entry_write(dev_priv, CUR_BUF_CFG(pipe),
> > -			    &ddb->plane[pipe][PLANE_CURSOR]);
> > +	skl_ddb_entry_write(dev_priv, CUR_BUF_CFG(pipe), ddb);
> >  }
> >  
> >  bool skl_wm_level_equals(const struct skl_wm_level *l1,
> > @@ -5210,13 +5207,12 @@ bool skl_ddb_allocation_overlaps(const struct skl_ddb_entry *ddb,
> >  static int skl_update_pipe_wm(struct drm_crtc_state *cstate,
> >  			      const struct skl_pipe_wm *old_pipe_wm,
> >  			      struct skl_pipe_wm *pipe_wm, /* out */
> > -			      struct skl_ddb_allocation *ddb, /* out */
> >  			      bool *changed /* out */)
> >  {
> >  	struct intel_crtc_state *intel_cstate = to_intel_crtc_state(cstate);
> >  	int ret;
> >  
> > -	ret = skl_build_pipe_wm(intel_cstate, ddb, pipe_wm);
> > +	ret = skl_build_pipe_wm(intel_cstate, pipe_wm);
> >  	if (ret)
> >  		return ret;
> >  
> > @@ -5242,42 +5238,29 @@ pipes_modified(struct drm_atomic_state *state)
> >  }
> >  
> >  static int
> > -skl_ddb_add_affected_planes(struct intel_crtc_state *cstate)
> > +skl_ddb_add_affected_planes(const struct intel_crtc_state *old_crtc_state,
> > +			    struct intel_crtc_state *new_crtc_state)
> >  {
> > -	struct drm_atomic_state *state = cstate->base.state;
> > -	struct drm_device *dev = state->dev;
> > -	struct drm_crtc *crtc = cstate->base.crtc;
> > -	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> > -	struct drm_i915_private *dev_priv = to_i915(dev);
> > -	struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
> > -	struct skl_ddb_allocation *new_ddb = &intel_state->wm_results.ddb;
> > -	struct skl_ddb_allocation *cur_ddb = &dev_priv->wm.skl_hw.ddb;
> > -	struct drm_plane *plane;
> > -	enum pipe pipe = intel_crtc->pipe;
> > +	struct intel_atomic_state *state = to_intel_atomic_state(new_crtc_state->base.state);
> > +	struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->base.crtc);
> > +	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
> > +	struct intel_plane *plane;
> >  
> > -	drm_for_each_plane_mask(plane, dev, cstate->base.plane_mask) {
> > -		struct drm_plane_state *plane_state;
> > -		struct intel_plane *linked;
> > -		enum plane_id plane_id = to_intel_plane(plane)->id;
> > +	for_each_intel_plane_on_crtc(&dev_priv->drm, crtc, plane) {
> > +		struct intel_plane_state *plane_state;
> > +		enum plane_id plane_id = plane->id;
> >  
> > -		if (skl_ddb_entry_equal(&cur_ddb->plane[pipe][plane_id],
> > -					&new_ddb->plane[pipe][plane_id]) &&
> > -		    skl_ddb_entry_equal(&cur_ddb->uv_plane[pipe][plane_id],
> > -					&new_ddb->uv_plane[pipe][plane_id]))
> > +		if (skl_ddb_entry_equal(&old_crtc_state->wm.skl.plane_ddb_y[plane_id],
> > +					&new_crtc_state->wm.skl.plane_ddb_y[plane_id]) &&
> > +		    skl_ddb_entry_equal(&old_crtc_state->wm.skl.plane_ddb_uv[plane_id],
> > +					&new_crtc_state->wm.skl.plane_ddb_uv[plane_id]))
> >  			continue;
> >  
> > -		plane_state = drm_atomic_get_plane_state(state, plane);
> > +		plane_state = intel_atomic_get_plane_state(state, plane);
> >  		if (IS_ERR(plane_state))
> >  			return PTR_ERR(plane_state);
> >  
> > -		/* Make sure linked plane is updated too */
> > -		linked = to_intel_plane_state(plane_state)->linked_plane;
> > -		if (!linked)
> > -			continue;
> > -
> > -		plane_state = drm_atomic_get_plane_state(state, &linked->base);
> > -		if (IS_ERR(plane_state))
> > -			return PTR_ERR(plane_state);
> > +		new_crtc_state->update_planes |= BIT(plane_id);
> >  	}
> >  
> >  	return 0;
> > @@ -5289,18 +5272,21 @@ skl_compute_ddb(struct drm_atomic_state *state)
> >  	const struct drm_i915_private *dev_priv = to_i915(state->dev);
> >  	struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
> >  	struct skl_ddb_allocation *ddb = &intel_state->wm_results.ddb;
> > +	struct intel_crtc_state *old_crtc_state;
> > +	struct intel_crtc_state *new_crtc_state;
> >  	struct intel_crtc *crtc;
> > -	struct intel_crtc_state *cstate;
> >  	int ret, i;
> >  
> >  	memcpy(ddb, &dev_priv->wm.skl_hw.ddb, sizeof(*ddb));
> >  
> > -	for_each_new_intel_crtc_in_state(intel_state, crtc, cstate, i) {
> > -		ret = skl_allocate_pipe_ddb(cstate, ddb);
> > +	for_each_oldnew_intel_crtc_in_state(intel_state, crtc, old_crtc_state,
> > +					    new_crtc_state, i) {
> > +		ret = skl_allocate_pipe_ddb(new_crtc_state, ddb);
> >  		if (ret)
> >  			return ret;
> >  
> > -		ret = skl_ddb_add_affected_planes(cstate);
> > +		ret = skl_ddb_add_affected_planes(old_crtc_state,
> > +						  new_crtc_state);
> >  		if (ret)
> >  			return ret;
> >  	}
> > @@ -5309,36 +5295,29 @@ skl_compute_ddb(struct drm_atomic_state *state)
> >  }
> >  
> >  static void
> > -skl_print_wm_changes(const struct drm_atomic_state *state)
> > +skl_print_wm_changes(struct intel_atomic_state *state)
> >  {
> > -	const struct drm_device *dev = state->dev;
> > -	const struct drm_i915_private *dev_priv = to_i915(dev);
> > -	const struct intel_atomic_state *intel_state =
> > -		to_intel_atomic_state(state);
> > -	const struct drm_crtc *crtc;
> > -	const struct drm_crtc_state *cstate;
> > -	const struct intel_plane *intel_plane;
> > -	const struct skl_ddb_allocation *old_ddb = &dev_priv->wm.skl_hw.ddb;
> > -	const struct skl_ddb_allocation *new_ddb = &intel_state->wm_results.ddb;
> > +	struct drm_i915_private *dev_priv = to_i915(state->base.dev);
> > +	const struct intel_crtc_state *old_crtc_state;
> > +	const struct intel_crtc_state *new_crtc_state;
> > +	struct intel_plane *plane;
> > +	struct intel_crtc *crtc;
> >  	int i;
> >  
> > -	for_each_new_crtc_in_state(state, crtc, cstate, i) {
> > -		const struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> > -		enum pipe pipe = intel_crtc->pipe;
> > -
> > -		for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) {
> > -			enum plane_id plane_id = intel_plane->id;
> > +	for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
> > +					    new_crtc_state, i) {
> > +		for_each_intel_plane_on_crtc(&dev_priv->drm, crtc, plane) {
> > +			enum plane_id plane_id = plane->id;
> >  			const struct skl_ddb_entry *old, *new;
> >  
> > -			old = &old_ddb->plane[pipe][plane_id];
> > -			new = &new_ddb->plane[pipe][plane_id];
> > +			old = &old_crtc_state->wm.skl.plane_ddb_y[plane_id];
> > +			new = &new_crtc_state->wm.skl.plane_ddb_y[plane_id];
> >  
> >  			if (skl_ddb_entry_equal(old, new))
> >  				continue;
> >  
> >  			DRM_DEBUG_KMS("[PLANE:%d:%s] ddb (%d - %d) -> (%d - %d)\n",
> > -				      intel_plane->base.base.id,
> > -				      intel_plane->base.name,
> > +				      plane->base.base.id, plane->base.name,
> >  				      old->start, old->end,
> >  				      new->start, new->end);
> >  		}
> > @@ -5474,8 +5453,7 @@ skl_compute_wm(struct drm_atomic_state *state)
> >  			&to_intel_crtc_state(crtc->state)->wm.skl.optimal;
> >  
> >  		pipe_wm = &intel_cstate->wm.skl.optimal;
> > -		ret = skl_update_pipe_wm(cstate, old_pipe_wm, pipe_wm,
> > -					 &results->ddb, &changed);
> > +		ret = skl_update_pipe_wm(cstate, old_pipe_wm, pipe_wm, &changed);
> >  		if (ret)
> >  			return ret;
> >  
> > @@ -5489,7 +5467,7 @@ skl_compute_wm(struct drm_atomic_state *state)
> >  		intel_cstate->update_wm_pre = true;
> >  	}
> >  
> > -	skl_print_wm_changes(state);
> > +	skl_print_wm_changes(intel_state);
> >  
> >  	return 0;
> >  }
> > @@ -5500,23 +5478,12 @@ static void skl_atomic_update_crtc_wm(struct intel_atomic_state *state,
> >  	struct intel_crtc *crtc = to_intel_crtc(cstate->base.crtc);
> >  	struct drm_i915_private *dev_priv = to_i915(state->base.dev);
> >  	struct skl_pipe_wm *pipe_wm = &cstate->wm.skl.optimal;
> > -	const struct skl_ddb_allocation *ddb = &state->wm_results.ddb;
> >  	enum pipe pipe = crtc->pipe;
> > -	enum plane_id plane_id;
> >  
> >  	if (!(state->wm_results.dirty_pipes & drm_crtc_mask(&crtc->base)))
> >  		return;
> >  
> >  	I915_WRITE(PIPE_WM_LINETIME(pipe), pipe_wm->linetime);
> > -
> > -	for_each_plane_id_on_crtc(crtc, plane_id) {
> > -		if (plane_id != PLANE_CURSOR)
> > -			skl_write_plane_wm(crtc, &pipe_wm->planes[plane_id],
> > -					   ddb, plane_id);
> > -		else
> > -			skl_write_cursor_wm(crtc, &pipe_wm->planes[plane_id],
> > -					    ddb);
> > -	}
> >  }
> >  
> >  static void skl_initial_wm(struct intel_atomic_state *state,
> > @@ -5526,8 +5493,6 @@ static void skl_initial_wm(struct intel_atomic_state *state,
> >  	struct drm_device *dev = intel_crtc->base.dev;
> >  	struct drm_i915_private *dev_priv = to_i915(dev);
> >  	struct skl_ddb_values *results = &state->wm_results;
> > -	struct skl_ddb_values *hw_vals = &dev_priv->wm.skl_hw;
> > -	enum pipe pipe = intel_crtc->pipe;
> >  
> >  	if ((results->dirty_pipes & drm_crtc_mask(&intel_crtc->base)) == 0)
> >  		return;
> > @@ -5537,11 +5502,6 @@ static void skl_initial_wm(struct intel_atomic_state *state,
> >  	if (cstate->base.active_changed)
> >  		skl_atomic_update_crtc_wm(state, cstate);
> >  
> > -	memcpy(hw_vals->ddb.uv_plane[pipe], results->ddb.uv_plane[pipe],
> > -	       sizeof(hw_vals->ddb.uv_plane[pipe]));
> > -	memcpy(hw_vals->ddb.plane[pipe], results->ddb.plane[pipe],
> > -	       sizeof(hw_vals->ddb.plane[pipe]));
> > -
> >  	mutex_unlock(&dev_priv->wm.wm_mutex);
> >  }
> >  
> > @@ -5692,13 +5652,6 @@ void skl_wm_get_hw_state(struct drm_device *dev)
> >  	if (dev_priv->active_crtcs) {
> >  		/* Fully recompute DDB on first atomic commit */
> >  		dev_priv->wm.distrust_bios_wm = true;
> > -	} else {
> > -		/*
> > -		 * Easy/common case; just sanitize DDB now if everything off
> > -		 * Keep dbuf slice info intact
> > -		 */
> > -		memset(ddb->plane, 0, sizeof(ddb->plane));
> > -		memset(ddb->uv_plane, 0, sizeof(ddb->uv_plane));
> >  	}
> >  }
> >  
> > diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
> > index 74d904a49bf9..0262159e7084 100644
> > --- a/drivers/gpu/drm/i915/intel_sprite.c
> > +++ b/drivers/gpu/drm/i915/intel_sprite.c
> > @@ -542,6 +542,8 @@ skl_program_plane(struct intel_plane *plane,
> >  	if (fb->format->is_yuv && icl_is_hdr_plane(plane))
> >  		icl_program_input_csc_coeff(crtc_state, plane_state);
> >  
> > +	skl_write_plane_wm(plane, crtc_state);
> > +
> >  	I915_WRITE_FW(PLANE_KEYVAL(pipe, plane_id), key->min_value);
> >  	I915_WRITE_FW(PLANE_KEYMSK(pipe, plane_id), keymsk);
> >  	I915_WRITE_FW(PLANE_KEYMAX(pipe, plane_id), keymax);
> > @@ -604,6 +606,8 @@ skl_disable_plane(struct intel_plane *plane,
> >  
> >  	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
> >  
> > +	skl_write_plane_wm(plane, crtc_state);
> > +
> >  	I915_WRITE_FW(PLANE_CTL(pipe, plane_id), 0);
> >  	I915_WRITE_FW(PLANE_SURF(pipe, plane_id), 0);
> >  
> > -- 
> > 2.18.1
> > 
> 
> -- 
> Matt Roper
> Graphics Software Engineer
> IoTG Platform Enabling & Development
> Intel Corporation
> (916) 356-2795
diff mbox series

Patch

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 670db5073d70..f8b2200947cf 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -3437,31 +3437,32 @@  static int i915_ddb_info(struct seq_file *m, void *unused)
 {
 	struct drm_i915_private *dev_priv = node_to_i915(m->private);
 	struct drm_device *dev = &dev_priv->drm;
-	struct skl_ddb_allocation *ddb;
 	struct skl_ddb_entry *entry;
-	enum pipe pipe;
-	int plane;
+	struct intel_crtc *crtc;
 
 	if (INTEL_GEN(dev_priv) < 9)
 		return -ENODEV;
 
 	drm_modeset_lock_all(dev);
 
-	ddb = &dev_priv->wm.skl_hw.ddb;
-
 	seq_printf(m, "%-15s%8s%8s%8s\n", "", "Start", "End", "Size");
 
-	for_each_pipe(dev_priv, pipe) {
+	for_each_intel_crtc(&dev_priv->drm, crtc) {
+		struct intel_crtc_state *crtc_state =
+			to_intel_crtc_state(crtc->base.state);
+		enum pipe pipe = crtc->pipe;
+		enum plane_id plane_id;
+
 		seq_printf(m, "Pipe %c\n", pipe_name(pipe));
 
-		for_each_universal_plane(dev_priv, pipe, plane) {
-			entry = &ddb->plane[pipe][plane];
-			seq_printf(m, "  Plane%-8d%8u%8u%8u\n", plane + 1,
+		for_each_plane_id_on_crtc(crtc, plane_id) {
+			entry = &crtc_state->wm.skl.plane_ddb_y[plane_id];
+			seq_printf(m, "  Plane%-8d%8u%8u%8u\n", plane_id + 1,
 				   entry->start, entry->end,
 				   skl_ddb_entry_size(entry));
 		}
 
-		entry = &ddb->plane[pipe][PLANE_CURSOR];
+		entry = &crtc_state->wm.skl.plane_ddb_y[PLANE_CURSOR];
 		seq_printf(m, "  %-13s%8u%8u%8u\n", "Cursor", entry->start,
 			   entry->end, skl_ddb_entry_size(entry));
 	}
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 5d686b585a95..89af64fe90a5 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1241,9 +1241,6 @@  static inline bool skl_ddb_entry_equal(const struct skl_ddb_entry *e1,
 }
 
 struct skl_ddb_allocation {
-	/* packed/y */
-	struct skl_ddb_entry plane[I915_MAX_PIPES][I915_MAX_PLANES];
-	struct skl_ddb_entry uv_plane[I915_MAX_PIPES][I915_MAX_PLANES];
 	u8 enabled_slices; /* GEN11 has configurable 2 slices */
 };
 
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 0caba7258fee..2981cea3704a 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -10083,6 +10083,10 @@  static void i9xx_update_cursor(struct intel_plane *plane,
 	 * except when the plane is getting enabled at which time
 	 * the CURCNTR write arms the update.
 	 */
+
+	if (INTEL_GEN(dev_priv) >= 9)
+		skl_write_cursor_wm(plane, crtc_state);
+
 	if (plane->cursor.base != base ||
 	    plane->cursor.size != fbc_ctl ||
 	    plane->cursor.cntl != cntl) {
@@ -11872,6 +11876,8 @@  static void verify_wm_state(struct drm_crtc *crtc,
 	struct skl_pipe_wm hw_wm, *sw_wm;
 	struct skl_plane_wm *hw_plane_wm, *sw_plane_wm;
 	struct skl_ddb_entry *hw_ddb_entry, *sw_ddb_entry;
+	struct skl_ddb_entry hw_ddb_y[I915_MAX_PLANES];
+	struct skl_ddb_entry hw_ddb_uv[I915_MAX_PLANES];
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	const enum pipe pipe = intel_crtc->pipe;
 	int plane, level, max_level = ilk_wm_max_level(dev_priv);
@@ -11882,6 +11888,8 @@  static void verify_wm_state(struct drm_crtc *crtc,
 	skl_pipe_wm_get_hw_state(crtc, &hw_wm);
 	sw_wm = &to_intel_crtc_state(new_state)->wm.skl.optimal;
 
+	skl_pipe_ddb_get_hw_state(intel_crtc, hw_ddb_y, hw_ddb_uv);
+
 	skl_ddb_get_hw_state(dev_priv, &hw_ddb);
 	sw_ddb = &dev_priv->wm.skl_hw.ddb;
 
@@ -11924,8 +11932,8 @@  static void verify_wm_state(struct drm_crtc *crtc,
 		}
 
 		/* DDB */
-		hw_ddb_entry = &hw_ddb.plane[pipe][plane];
-		sw_ddb_entry = &sw_ddb->plane[pipe][plane];
+		hw_ddb_entry = &hw_ddb_y[plane];
+		sw_ddb_entry = &to_intel_crtc_state(new_state)->wm.skl.plane_ddb_y[plane];
 
 		if (!skl_ddb_entry_equal(hw_ddb_entry, sw_ddb_entry)) {
 			DRM_ERROR("mismatch in DDB state pipe %c plane %d (expected (%u,%u), found (%u,%u))\n",
@@ -11974,8 +11982,8 @@  static void verify_wm_state(struct drm_crtc *crtc,
 		}
 
 		/* DDB */
-		hw_ddb_entry = &hw_ddb.plane[pipe][PLANE_CURSOR];
-		sw_ddb_entry = &sw_ddb->plane[pipe][PLANE_CURSOR];
+		hw_ddb_entry = &hw_ddb_y[PLANE_CURSOR];
+		sw_ddb_entry = &to_intel_crtc_state(new_state)->wm.skl.plane_ddb_y[PLANE_CURSOR];
 
 		if (!skl_ddb_entry_equal(hw_ddb_entry, sw_ddb_entry)) {
 			DRM_ERROR("mismatch in DDB state pipe %c cursor (expected (%u,%u), found (%u,%u))\n",
diff --git a/drivers/gpu/drm/i915/intel_display.h b/drivers/gpu/drm/i915/intel_display.h
index df9e6ebb27de..078406dc65e5 100644
--- a/drivers/gpu/drm/i915/intel_display.h
+++ b/drivers/gpu/drm/i915/intel_display.h
@@ -319,7 +319,7 @@  struct intel_link_m_n {
 			    &(dev)->mode_config.plane_list,		\
 			    base.head)					\
 		for_each_if((plane_mask) &				\
-			    drm_plane_mask(&intel_plane->base)))
+			    drm_plane_mask(&intel_plane->base))
 
 #define for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane)	\
 	list_for_each_entry(intel_plane,				\
@@ -415,6 +415,15 @@  struct intel_link_m_n {
 	     (__i)++) \
 		for_each_if(plane)
 
+#define for_each_oldnew_intel_crtc_in_state(__state, crtc, old_crtc_state, new_crtc_state, __i) \
+	for ((__i) = 0; \
+	     (__i) < (__state)->base.dev->mode_config.num_crtc && \
+		     ((crtc) = to_intel_crtc((__state)->base.crtcs[__i].ptr), \
+		      (old_crtc_state) = to_intel_crtc_state((__state)->base.crtcs[__i].old_state), \
+		      (new_crtc_state) = to_intel_crtc_state((__state)->base.crtcs[__i].new_state), 1); \
+	     (__i)++) \
+		for_each_if(crtc)
+
 void intel_link_compute_m_n(int bpp, int nlanes,
 			    int pixel_clock, int link_clock,
 			    struct intel_link_m_n *m_n,
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 23b33970db17..4a9af09c483a 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -705,6 +705,8 @@  struct intel_crtc_wm_state {
 			/* gen9+ only needs 1-step wm programming */
 			struct skl_pipe_wm optimal;
 			struct skl_ddb_entry ddb;
+			struct skl_ddb_entry plane_ddb_y[I915_MAX_PLANES];
+			struct skl_ddb_entry plane_ddb_uv[I915_MAX_PLANES];
 		} skl;
 
 		struct {
@@ -2183,6 +2185,9 @@  void g4x_wm_get_hw_state(struct drm_device *dev);
 void vlv_wm_get_hw_state(struct drm_device *dev);
 void ilk_wm_get_hw_state(struct drm_device *dev);
 void skl_wm_get_hw_state(struct drm_device *dev);
+void skl_pipe_ddb_get_hw_state(struct intel_crtc *crtc,
+			       struct skl_ddb_entry *ddb_y,
+			       struct skl_ddb_entry *ddb_uv);
 void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv,
 			  struct skl_ddb_allocation *ddb /* out */);
 void skl_pipe_wm_get_hw_state(struct drm_crtc *crtc,
@@ -2197,6 +2202,10 @@  bool skl_wm_level_equals(const struct skl_wm_level *l1,
 bool skl_ddb_allocation_overlaps(const struct skl_ddb_entry *ddb,
 				 const struct skl_ddb_entry entries[],
 				 int num_entries, int ignore_idx);
+void skl_write_plane_wm(struct intel_plane *plane,
+			const struct intel_crtc_state *crtc_state);
+void skl_write_cursor_wm(struct intel_plane *plane,
+			 const struct intel_crtc_state *crtc_state);
 bool ilk_disable_lp_wm(struct drm_device *dev);
 int skl_check_pipe_max_pixel_rate(struct intel_crtc *intel_crtc,
 				  struct intel_crtc_state *cstate);
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index a21654c974ba..1b337004054a 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -3912,68 +3912,70 @@  static void
 skl_ddb_get_hw_plane_state(struct drm_i915_private *dev_priv,
 			   const enum pipe pipe,
 			   const enum plane_id plane_id,
-			   struct skl_ddb_allocation *ddb /* out */)
+			   struct skl_ddb_entry *ddb_y,
+			   struct skl_ddb_entry *ddb_uv)
 {
-	u32 val, val2 = 0;
-	int fourcc, pixel_format;
+	u32 val, val2;
+	u32 fourcc = 0;
 
 	/* Cursor doesn't support NV12/planar, so no extra calculation needed */
 	if (plane_id == PLANE_CURSOR) {
 		val = I915_READ(CUR_BUF_CFG(pipe));
-		skl_ddb_entry_init_from_hw(dev_priv,
-					   &ddb->plane[pipe][plane_id], val);
+		skl_ddb_entry_init_from_hw(dev_priv, ddb_y, val);
 		return;
 	}
 
 	val = I915_READ(PLANE_CTL(pipe, plane_id));
 
 	/* No DDB allocated for disabled planes */
-	if (!(val & PLANE_CTL_ENABLE))
-		return;
+	if (val & PLANE_CTL_ENABLE)
+		fourcc = skl_format_to_fourcc(val & PLANE_CTL_FORMAT_MASK,
+					      val & PLANE_CTL_ORDER_RGBX,
+					      val & PLANE_CTL_ALPHA_MASK);
 
-	pixel_format = val & PLANE_CTL_FORMAT_MASK;
-	fourcc = skl_format_to_fourcc(pixel_format,
-				      val & PLANE_CTL_ORDER_RGBX,
-				      val & PLANE_CTL_ALPHA_MASK);
-
-	val = I915_READ(PLANE_BUF_CFG(pipe, plane_id));
-	if (fourcc == DRM_FORMAT_NV12 && INTEL_GEN(dev_priv) < 11) {
+	if (INTEL_GEN(dev_priv) >= 11) {
+		val = I915_READ(PLANE_BUF_CFG(pipe, plane_id));
+		skl_ddb_entry_init_from_hw(dev_priv, ddb_y, val);
+	} else {
+		val = I915_READ(PLANE_BUF_CFG(pipe, plane_id));
 		val2 = I915_READ(PLANE_NV12_BUF_CFG(pipe, plane_id));
 
-		skl_ddb_entry_init_from_hw(dev_priv,
-					   &ddb->plane[pipe][plane_id], val2);
-		skl_ddb_entry_init_from_hw(dev_priv,
-					   &ddb->uv_plane[pipe][plane_id], val);
-	} else {
-		skl_ddb_entry_init_from_hw(dev_priv,
-					   &ddb->plane[pipe][plane_id], val);
+		if (fourcc == DRM_FORMAT_NV12)
+			swap(val, val2);
+
+		skl_ddb_entry_init_from_hw(dev_priv, ddb_y, val);
+		skl_ddb_entry_init_from_hw(dev_priv, ddb_uv, val2);
 	}
 }
 
+void skl_pipe_ddb_get_hw_state(struct intel_crtc *crtc,
+			       struct skl_ddb_entry *ddb_y,
+			       struct skl_ddb_entry *ddb_uv)
+{
+	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+	enum intel_display_power_domain power_domain;
+	enum pipe pipe = crtc->pipe;
+	enum plane_id plane_id;
+
+	power_domain = POWER_DOMAIN_PIPE(pipe);
+	if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
+		return;
+
+	for_each_plane_id_on_crtc(crtc, plane_id)
+		skl_ddb_get_hw_plane_state(dev_priv, pipe,
+					   plane_id,
+					   &ddb_y[plane_id],
+					   &ddb_uv[plane_id]);
+
+	intel_display_power_put(dev_priv, power_domain);
+}
+
 void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv,
 			  struct skl_ddb_allocation *ddb /* out */)
 {
-	struct intel_crtc *crtc;
-
 	memset(ddb, 0, sizeof(*ddb));
 
 	ddb->enabled_slices = intel_enabled_dbuf_slices_num(dev_priv);
-
-	for_each_intel_crtc(&dev_priv->drm, crtc) {
-		enum intel_display_power_domain power_domain;
-		enum plane_id plane_id;
-		enum pipe pipe = crtc->pipe;
-
-		power_domain = POWER_DOMAIN_PIPE(pipe);
-		if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
-			continue;
-
-		for_each_plane_id_on_crtc(crtc, plane_id)
-			skl_ddb_get_hw_plane_state(dev_priv, pipe,
-						   plane_id, ddb);
-
-		intel_display_power_put(dev_priv, power_domain);
-	}
 }
 
 /*
@@ -4371,7 +4373,6 @@  skl_allocate_pipe_ddb(struct intel_crtc_state *cstate,
 	struct drm_crtc *crtc = cstate->base.crtc;
 	struct drm_i915_private *dev_priv = to_i915(crtc->dev);
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	enum pipe pipe = intel_crtc->pipe;
 	struct skl_ddb_entry *alloc = &cstate->wm.skl.ddb;
 	uint16_t alloc_size, start;
 	uint16_t minimum[I915_MAX_PLANES] = {};
@@ -4384,8 +4385,8 @@  skl_allocate_pipe_ddb(struct intel_crtc_state *cstate,
 	uint16_t total_min_blocks = 0;
 
 	/* Clear the partitioning for disabled planes. */
-	memset(ddb->plane[pipe], 0, sizeof(ddb->plane[pipe]));
-	memset(ddb->uv_plane[pipe], 0, sizeof(ddb->uv_plane[pipe]));
+	memset(cstate->wm.skl.plane_ddb_y, 0, sizeof(cstate->wm.skl.plane_ddb_y));
+	memset(cstate->wm.skl.plane_ddb_uv, 0, sizeof(cstate->wm.skl.plane_ddb_uv));
 
 	if (WARN_ON(!state))
 		return 0;
@@ -4432,8 +4433,8 @@  skl_allocate_pipe_ddb(struct intel_crtc_state *cstate,
 	}
 
 	alloc_size -= total_min_blocks;
-	ddb->plane[pipe][PLANE_CURSOR].start = alloc->end - minimum[PLANE_CURSOR];
-	ddb->plane[pipe][PLANE_CURSOR].end = alloc->end;
+	cstate->wm.skl.plane_ddb_y[PLANE_CURSOR].start = alloc->end - minimum[PLANE_CURSOR];
+	cstate->wm.skl.plane_ddb_y[PLANE_CURSOR].end = alloc->end;
 
 	/*
 	 * 2. Distribute the remaining space in proportion to the amount of
@@ -4464,8 +4465,8 @@  skl_allocate_pipe_ddb(struct intel_crtc_state *cstate,
 
 		/* Leave disabled planes at (0,0) */
 		if (data_rate) {
-			ddb->plane[pipe][plane_id].start = start;
-			ddb->plane[pipe][plane_id].end = start + plane_blocks;
+			cstate->wm.skl.plane_ddb_y[plane_id].start = start;
+			cstate->wm.skl.plane_ddb_y[plane_id].end = start + plane_blocks;
 		}
 
 		start += plane_blocks;
@@ -4480,8 +4481,8 @@  skl_allocate_pipe_ddb(struct intel_crtc_state *cstate,
 		WARN_ON(INTEL_GEN(dev_priv) >= 11 && uv_plane_blocks);
 
 		if (uv_data_rate) {
-			ddb->uv_plane[pipe][plane_id].start = start;
-			ddb->uv_plane[pipe][plane_id].end =
+			cstate->wm.skl.plane_ddb_uv[plane_id].start = start;
+			cstate->wm.skl.plane_ddb_uv[plane_id].end =
 				start + uv_plane_blocks;
 		}
 
@@ -4939,16 +4940,13 @@  static void skl_compute_transition_wm(const struct intel_crtc_state *cstate,
 	}
 }
 
-static int skl_build_plane_wm_single(struct skl_ddb_allocation *ddb,
-				     struct intel_crtc_state *crtc_state,
+static int skl_build_plane_wm_single(struct intel_crtc_state *crtc_state,
 				     const struct intel_plane_state *plane_state,
 				     enum plane_id plane_id, int color_plane)
 {
-	struct intel_plane *plane = to_intel_plane(plane_state->base.plane);
 	struct skl_plane_wm *wm = &crtc_state->wm.skl.optimal.planes[plane_id];
+	u16 ddb_blocks = skl_ddb_entry_size(&crtc_state->wm.skl.plane_ddb_y[plane_id]);
 	struct skl_wm_params wm_params;
-	enum pipe pipe = plane->pipe;
-	uint16_t ddb_blocks = skl_ddb_entry_size(&ddb->plane[pipe][plane_id]);
 	int ret;
 
 	ret = skl_compute_plane_wm_params(crtc_state, plane_state,
@@ -4966,16 +4964,13 @@  static int skl_build_plane_wm_single(struct skl_ddb_allocation *ddb,
 	return 0;
 }
 
-static int skl_build_plane_wm_uv(struct skl_ddb_allocation *ddb,
-				 struct intel_crtc_state *crtc_state,
+static int skl_build_plane_wm_uv(struct intel_crtc_state *crtc_state,
 				 const struct intel_plane_state *plane_state,
 				 enum plane_id plane_id)
 {
-	struct intel_plane *plane = to_intel_plane(plane_state->base.plane);
 	struct skl_plane_wm *wm = &crtc_state->wm.skl.optimal.planes[plane_id];
+	u16 ddb_blocks = skl_ddb_entry_size(&crtc_state->wm.skl.plane_ddb_uv[plane_id]);
 	struct skl_wm_params wm_params;
-	enum pipe pipe = plane->pipe;
-	uint16_t ddb_blocks = skl_ddb_entry_size(&ddb->uv_plane[pipe][plane_id]);
 	int ret;
 
 	wm->is_planar = true;
@@ -4994,8 +4989,7 @@  static int skl_build_plane_wm_uv(struct skl_ddb_allocation *ddb,
 	return 0;
 }
 
-static int skl_build_plane_wm(struct skl_ddb_allocation *ddb,
-			      struct skl_pipe_wm *pipe_wm,
+static int skl_build_plane_wm(struct skl_pipe_wm *pipe_wm,
 			      struct intel_crtc_state *crtc_state,
 			      const struct intel_plane_state *plane_state)
 {
@@ -5007,13 +5001,13 @@  static int skl_build_plane_wm(struct skl_ddb_allocation *ddb,
 	if (!intel_wm_plane_visible(crtc_state, plane_state))
 		return 0;
 
-	ret = skl_build_plane_wm_single(ddb, crtc_state, plane_state,
+	ret = skl_build_plane_wm_single(crtc_state, plane_state,
 					plane_id, 0);
 	if (ret)
 		return ret;
 
 	if (fb->format->is_yuv && fb->format->num_planes > 1) {
-		ret = skl_build_plane_wm_uv(ddb, crtc_state, plane_state,
+		ret = skl_build_plane_wm_uv(crtc_state, plane_state,
 					    plane_id);
 		if (ret)
 			return ret;
@@ -5022,8 +5016,7 @@  static int skl_build_plane_wm(struct skl_ddb_allocation *ddb,
 	return 0;
 }
 
-static int icl_build_plane_wm(struct skl_ddb_allocation *ddb,
-			      struct skl_pipe_wm *pipe_wm,
+static int icl_build_plane_wm(struct skl_pipe_wm *pipe_wm,
 			      struct intel_crtc_state *crtc_state,
 			      const struct intel_plane_state *plane_state)
 {
@@ -5041,17 +5034,17 @@  static int icl_build_plane_wm(struct skl_ddb_allocation *ddb,
 		WARN_ON(!fb->format->is_yuv ||
 			fb->format->num_planes == 1);
 
-		ret = skl_build_plane_wm_single(ddb, crtc_state, plane_state,
+		ret = skl_build_plane_wm_single(crtc_state, plane_state,
 						y_plane_id, 0);
 		if (ret)
 			return ret;
 
-		ret = skl_build_plane_wm_single(ddb, crtc_state, plane_state,
+		ret = skl_build_plane_wm_single(crtc_state, plane_state,
 						plane_id, 1);
 		if (ret)
 			return ret;
 	} else if (intel_wm_plane_visible(crtc_state, plane_state)) {
-		ret = skl_build_plane_wm_single(ddb, crtc_state, plane_state,
+		ret = skl_build_plane_wm_single(crtc_state, plane_state,
 						plane_id, 0);
 		if (ret)
 			return ret;
@@ -5061,7 +5054,6 @@  static int icl_build_plane_wm(struct skl_ddb_allocation *ddb,
 }
 
 static int skl_build_pipe_wm(struct intel_crtc_state *cstate,
-			     struct skl_ddb_allocation *ddb,
 			     struct skl_pipe_wm *pipe_wm)
 {
 	struct drm_i915_private *dev_priv = to_i915(cstate->base.crtc->dev);
@@ -5081,10 +5073,10 @@  static int skl_build_pipe_wm(struct intel_crtc_state *cstate,
 						to_intel_plane_state(pstate);
 
 		if (INTEL_GEN(dev_priv) >= 11)
-			ret = icl_build_plane_wm(ddb, pipe_wm,
+			ret = icl_build_plane_wm(pipe_wm,
 						 cstate, intel_pstate);
 		else
-			ret = skl_build_plane_wm(ddb, pipe_wm,
+			ret = skl_build_plane_wm(pipe_wm,
 						 cstate, intel_pstate);
 		if (ret)
 			return ret;
@@ -5100,9 +5092,9 @@  static void skl_ddb_entry_write(struct drm_i915_private *dev_priv,
 				const struct skl_ddb_entry *entry)
 {
 	if (entry->end)
-		I915_WRITE(reg, (entry->end - 1) << 16 | entry->start);
+		I915_WRITE_FW(reg, (entry->end - 1) << 16 | entry->start);
 	else
-		I915_WRITE(reg, 0);
+		I915_WRITE_FW(reg, 0);
 }
 
 static void skl_write_wm_level(struct drm_i915_private *dev_priv,
@@ -5117,19 +5109,22 @@  static void skl_write_wm_level(struct drm_i915_private *dev_priv,
 		val |= level->plane_res_l << PLANE_WM_LINES_SHIFT;
 	}
 
-	I915_WRITE(reg, val);
+	I915_WRITE_FW(reg, val);
 }
 
-static void skl_write_plane_wm(struct intel_crtc *intel_crtc,
-			       const struct skl_plane_wm *wm,
-			       const struct skl_ddb_allocation *ddb,
-			       enum plane_id plane_id)
+void skl_write_plane_wm(struct intel_plane *plane,
+			const struct intel_crtc_state *crtc_state)
 {
-	struct drm_crtc *crtc = &intel_crtc->base;
-	struct drm_device *dev = crtc->dev;
-	struct drm_i915_private *dev_priv = to_i915(dev);
+	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
 	int level, max_level = ilk_wm_max_level(dev_priv);
-	enum pipe pipe = intel_crtc->pipe;
+	enum plane_id plane_id = plane->id;
+	enum pipe pipe = plane->pipe;
+	const struct skl_plane_wm *wm =
+		&crtc_state->wm.skl.optimal.planes[plane_id];
+	const struct skl_ddb_entry *ddb_y =
+		&crtc_state->wm.skl.plane_ddb_y[plane_id];
+	const struct skl_ddb_entry *ddb_uv =
+		&crtc_state->wm.skl.plane_ddb_uv[plane_id];
 
 	for (level = 0; level <= max_level; level++) {
 		skl_write_wm_level(dev_priv, PLANE_WM(pipe, plane_id, level),
@@ -5138,29 +5133,32 @@  static void skl_write_plane_wm(struct intel_crtc *intel_crtc,
 	skl_write_wm_level(dev_priv, PLANE_WM_TRANS(pipe, plane_id),
 			   &wm->trans_wm);
 
-	if (wm->is_planar && INTEL_GEN(dev_priv) < 11) {
-		skl_ddb_entry_write(dev_priv, PLANE_BUF_CFG(pipe, plane_id),
-				    &ddb->uv_plane[pipe][plane_id]);
+	if (INTEL_GEN(dev_priv) >= 11) {
 		skl_ddb_entry_write(dev_priv,
-				    PLANE_NV12_BUF_CFG(pipe, plane_id),
-				    &ddb->plane[pipe][plane_id]);
-	} else {
-		skl_ddb_entry_write(dev_priv, PLANE_BUF_CFG(pipe, plane_id),
-				    &ddb->plane[pipe][plane_id]);
-		if (INTEL_GEN(dev_priv) < 11)
-			I915_WRITE(PLANE_NV12_BUF_CFG(pipe, plane_id), 0x0);
+				    PLANE_BUF_CFG(pipe, plane_id), ddb_y);
+		return;
 	}
+
+	if (wm->is_planar)
+		swap(ddb_y, ddb_uv);
+
+	skl_ddb_entry_write(dev_priv,
+			    PLANE_BUF_CFG(pipe, plane_id), ddb_y);
+	skl_ddb_entry_write(dev_priv,
+			    PLANE_NV12_BUF_CFG(pipe, plane_id), ddb_uv);
 }
 
-static void skl_write_cursor_wm(struct intel_crtc *intel_crtc,
-				const struct skl_plane_wm *wm,
-				const struct skl_ddb_allocation *ddb)
+void skl_write_cursor_wm(struct intel_plane *plane,
+			 const struct intel_crtc_state *crtc_state)
 {
-	struct drm_crtc *crtc = &intel_crtc->base;
-	struct drm_device *dev = crtc->dev;
-	struct drm_i915_private *dev_priv = to_i915(dev);
+	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
 	int level, max_level = ilk_wm_max_level(dev_priv);
-	enum pipe pipe = intel_crtc->pipe;
+	enum plane_id plane_id = plane->id;
+	enum pipe pipe = plane->pipe;
+	const struct skl_plane_wm *wm =
+		&crtc_state->wm.skl.optimal.planes[plane_id];
+	const struct skl_ddb_entry *ddb =
+		&crtc_state->wm.skl.plane_ddb_y[plane_id];
 
 	for (level = 0; level <= max_level; level++) {
 		skl_write_wm_level(dev_priv, CUR_WM(pipe, level),
@@ -5168,8 +5166,7 @@  static void skl_write_cursor_wm(struct intel_crtc *intel_crtc,
 	}
 	skl_write_wm_level(dev_priv, CUR_WM_TRANS(pipe), &wm->trans_wm);
 
-	skl_ddb_entry_write(dev_priv, CUR_BUF_CFG(pipe),
-			    &ddb->plane[pipe][PLANE_CURSOR]);
+	skl_ddb_entry_write(dev_priv, CUR_BUF_CFG(pipe), ddb);
 }
 
 bool skl_wm_level_equals(const struct skl_wm_level *l1,
@@ -5210,13 +5207,12 @@  bool skl_ddb_allocation_overlaps(const struct skl_ddb_entry *ddb,
 static int skl_update_pipe_wm(struct drm_crtc_state *cstate,
 			      const struct skl_pipe_wm *old_pipe_wm,
 			      struct skl_pipe_wm *pipe_wm, /* out */
-			      struct skl_ddb_allocation *ddb, /* out */
 			      bool *changed /* out */)
 {
 	struct intel_crtc_state *intel_cstate = to_intel_crtc_state(cstate);
 	int ret;
 
-	ret = skl_build_pipe_wm(intel_cstate, ddb, pipe_wm);
+	ret = skl_build_pipe_wm(intel_cstate, pipe_wm);
 	if (ret)
 		return ret;
 
@@ -5242,42 +5238,29 @@  pipes_modified(struct drm_atomic_state *state)
 }
 
 static int
-skl_ddb_add_affected_planes(struct intel_crtc_state *cstate)
+skl_ddb_add_affected_planes(const struct intel_crtc_state *old_crtc_state,
+			    struct intel_crtc_state *new_crtc_state)
 {
-	struct drm_atomic_state *state = cstate->base.state;
-	struct drm_device *dev = state->dev;
-	struct drm_crtc *crtc = cstate->base.crtc;
-	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	struct drm_i915_private *dev_priv = to_i915(dev);
-	struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
-	struct skl_ddb_allocation *new_ddb = &intel_state->wm_results.ddb;
-	struct skl_ddb_allocation *cur_ddb = &dev_priv->wm.skl_hw.ddb;
-	struct drm_plane *plane;
-	enum pipe pipe = intel_crtc->pipe;
+	struct intel_atomic_state *state = to_intel_atomic_state(new_crtc_state->base.state);
+	struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->base.crtc);
+	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+	struct intel_plane *plane;
 
-	drm_for_each_plane_mask(plane, dev, cstate->base.plane_mask) {
-		struct drm_plane_state *plane_state;
-		struct intel_plane *linked;
-		enum plane_id plane_id = to_intel_plane(plane)->id;
+	for_each_intel_plane_on_crtc(&dev_priv->drm, crtc, plane) {
+		struct intel_plane_state *plane_state;
+		enum plane_id plane_id = plane->id;
 
-		if (skl_ddb_entry_equal(&cur_ddb->plane[pipe][plane_id],
-					&new_ddb->plane[pipe][plane_id]) &&
-		    skl_ddb_entry_equal(&cur_ddb->uv_plane[pipe][plane_id],
-					&new_ddb->uv_plane[pipe][plane_id]))
+		if (skl_ddb_entry_equal(&old_crtc_state->wm.skl.plane_ddb_y[plane_id],
+					&new_crtc_state->wm.skl.plane_ddb_y[plane_id]) &&
+		    skl_ddb_entry_equal(&old_crtc_state->wm.skl.plane_ddb_uv[plane_id],
+					&new_crtc_state->wm.skl.plane_ddb_uv[plane_id]))
 			continue;
 
-		plane_state = drm_atomic_get_plane_state(state, plane);
+		plane_state = intel_atomic_get_plane_state(state, plane);
 		if (IS_ERR(plane_state))
 			return PTR_ERR(plane_state);
 
-		/* Make sure linked plane is updated too */
-		linked = to_intel_plane_state(plane_state)->linked_plane;
-		if (!linked)
-			continue;
-
-		plane_state = drm_atomic_get_plane_state(state, &linked->base);
-		if (IS_ERR(plane_state))
-			return PTR_ERR(plane_state);
+		new_crtc_state->update_planes |= BIT(plane_id);
 	}
 
 	return 0;
@@ -5289,18 +5272,21 @@  skl_compute_ddb(struct drm_atomic_state *state)
 	const struct drm_i915_private *dev_priv = to_i915(state->dev);
 	struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
 	struct skl_ddb_allocation *ddb = &intel_state->wm_results.ddb;
+	struct intel_crtc_state *old_crtc_state;
+	struct intel_crtc_state *new_crtc_state;
 	struct intel_crtc *crtc;
-	struct intel_crtc_state *cstate;
 	int ret, i;
 
 	memcpy(ddb, &dev_priv->wm.skl_hw.ddb, sizeof(*ddb));
 
-	for_each_new_intel_crtc_in_state(intel_state, crtc, cstate, i) {
-		ret = skl_allocate_pipe_ddb(cstate, ddb);
+	for_each_oldnew_intel_crtc_in_state(intel_state, crtc, old_crtc_state,
+					    new_crtc_state, i) {
+		ret = skl_allocate_pipe_ddb(new_crtc_state, ddb);
 		if (ret)
 			return ret;
 
-		ret = skl_ddb_add_affected_planes(cstate);
+		ret = skl_ddb_add_affected_planes(old_crtc_state,
+						  new_crtc_state);
 		if (ret)
 			return ret;
 	}
@@ -5309,36 +5295,29 @@  skl_compute_ddb(struct drm_atomic_state *state)
 }
 
 static void
-skl_print_wm_changes(const struct drm_atomic_state *state)
+skl_print_wm_changes(struct intel_atomic_state *state)
 {
-	const struct drm_device *dev = state->dev;
-	const struct drm_i915_private *dev_priv = to_i915(dev);
-	const struct intel_atomic_state *intel_state =
-		to_intel_atomic_state(state);
-	const struct drm_crtc *crtc;
-	const struct drm_crtc_state *cstate;
-	const struct intel_plane *intel_plane;
-	const struct skl_ddb_allocation *old_ddb = &dev_priv->wm.skl_hw.ddb;
-	const struct skl_ddb_allocation *new_ddb = &intel_state->wm_results.ddb;
+	struct drm_i915_private *dev_priv = to_i915(state->base.dev);
+	const struct intel_crtc_state *old_crtc_state;
+	const struct intel_crtc_state *new_crtc_state;
+	struct intel_plane *plane;
+	struct intel_crtc *crtc;
 	int i;
 
-	for_each_new_crtc_in_state(state, crtc, cstate, i) {
-		const struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-		enum pipe pipe = intel_crtc->pipe;
-
-		for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) {
-			enum plane_id plane_id = intel_plane->id;
+	for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
+					    new_crtc_state, i) {
+		for_each_intel_plane_on_crtc(&dev_priv->drm, crtc, plane) {
+			enum plane_id plane_id = plane->id;
 			const struct skl_ddb_entry *old, *new;
 
-			old = &old_ddb->plane[pipe][plane_id];
-			new = &new_ddb->plane[pipe][plane_id];
+			old = &old_crtc_state->wm.skl.plane_ddb_y[plane_id];
+			new = &new_crtc_state->wm.skl.plane_ddb_y[plane_id];
 
 			if (skl_ddb_entry_equal(old, new))
 				continue;
 
 			DRM_DEBUG_KMS("[PLANE:%d:%s] ddb (%d - %d) -> (%d - %d)\n",
-				      intel_plane->base.base.id,
-				      intel_plane->base.name,
+				      plane->base.base.id, plane->base.name,
 				      old->start, old->end,
 				      new->start, new->end);
 		}
@@ -5474,8 +5453,7 @@  skl_compute_wm(struct drm_atomic_state *state)
 			&to_intel_crtc_state(crtc->state)->wm.skl.optimal;
 
 		pipe_wm = &intel_cstate->wm.skl.optimal;
-		ret = skl_update_pipe_wm(cstate, old_pipe_wm, pipe_wm,
-					 &results->ddb, &changed);
+		ret = skl_update_pipe_wm(cstate, old_pipe_wm, pipe_wm, &changed);
 		if (ret)
 			return ret;
 
@@ -5489,7 +5467,7 @@  skl_compute_wm(struct drm_atomic_state *state)
 		intel_cstate->update_wm_pre = true;
 	}
 
-	skl_print_wm_changes(state);
+	skl_print_wm_changes(intel_state);
 
 	return 0;
 }
@@ -5500,23 +5478,12 @@  static void skl_atomic_update_crtc_wm(struct intel_atomic_state *state,
 	struct intel_crtc *crtc = to_intel_crtc(cstate->base.crtc);
 	struct drm_i915_private *dev_priv = to_i915(state->base.dev);
 	struct skl_pipe_wm *pipe_wm = &cstate->wm.skl.optimal;
-	const struct skl_ddb_allocation *ddb = &state->wm_results.ddb;
 	enum pipe pipe = crtc->pipe;
-	enum plane_id plane_id;
 
 	if (!(state->wm_results.dirty_pipes & drm_crtc_mask(&crtc->base)))
 		return;
 
 	I915_WRITE(PIPE_WM_LINETIME(pipe), pipe_wm->linetime);
-
-	for_each_plane_id_on_crtc(crtc, plane_id) {
-		if (plane_id != PLANE_CURSOR)
-			skl_write_plane_wm(crtc, &pipe_wm->planes[plane_id],
-					   ddb, plane_id);
-		else
-			skl_write_cursor_wm(crtc, &pipe_wm->planes[plane_id],
-					    ddb);
-	}
 }
 
 static void skl_initial_wm(struct intel_atomic_state *state,
@@ -5526,8 +5493,6 @@  static void skl_initial_wm(struct intel_atomic_state *state,
 	struct drm_device *dev = intel_crtc->base.dev;
 	struct drm_i915_private *dev_priv = to_i915(dev);
 	struct skl_ddb_values *results = &state->wm_results;
-	struct skl_ddb_values *hw_vals = &dev_priv->wm.skl_hw;
-	enum pipe pipe = intel_crtc->pipe;
 
 	if ((results->dirty_pipes & drm_crtc_mask(&intel_crtc->base)) == 0)
 		return;
@@ -5537,11 +5502,6 @@  static void skl_initial_wm(struct intel_atomic_state *state,
 	if (cstate->base.active_changed)
 		skl_atomic_update_crtc_wm(state, cstate);
 
-	memcpy(hw_vals->ddb.uv_plane[pipe], results->ddb.uv_plane[pipe],
-	       sizeof(hw_vals->ddb.uv_plane[pipe]));
-	memcpy(hw_vals->ddb.plane[pipe], results->ddb.plane[pipe],
-	       sizeof(hw_vals->ddb.plane[pipe]));
-
 	mutex_unlock(&dev_priv->wm.wm_mutex);
 }
 
@@ -5692,13 +5652,6 @@  void skl_wm_get_hw_state(struct drm_device *dev)
 	if (dev_priv->active_crtcs) {
 		/* Fully recompute DDB on first atomic commit */
 		dev_priv->wm.distrust_bios_wm = true;
-	} else {
-		/*
-		 * Easy/common case; just sanitize DDB now if everything off
-		 * Keep dbuf slice info intact
-		 */
-		memset(ddb->plane, 0, sizeof(ddb->plane));
-		memset(ddb->uv_plane, 0, sizeof(ddb->uv_plane));
 	}
 }
 
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index 74d904a49bf9..0262159e7084 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -542,6 +542,8 @@  skl_program_plane(struct intel_plane *plane,
 	if (fb->format->is_yuv && icl_is_hdr_plane(plane))
 		icl_program_input_csc_coeff(crtc_state, plane_state);
 
+	skl_write_plane_wm(plane, crtc_state);
+
 	I915_WRITE_FW(PLANE_KEYVAL(pipe, plane_id), key->min_value);
 	I915_WRITE_FW(PLANE_KEYMSK(pipe, plane_id), keymsk);
 	I915_WRITE_FW(PLANE_KEYMAX(pipe, plane_id), keymax);
@@ -604,6 +606,8 @@  skl_disable_plane(struct intel_plane *plane,
 
 	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
 
+	skl_write_plane_wm(plane, crtc_state);
+
 	I915_WRITE_FW(PLANE_CTL(pipe, plane_id), 0);
 	I915_WRITE_FW(PLANE_SURF(pipe, plane_id), 0);