All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Ville Syrjälä" <ville.syrjala@linux.intel.com>
To: Jani Nikula <jani.nikula@intel.com>
Cc: Dave Airlie <airlied@redhat.com>, intel-gfx@lists.freedesktop.org
Subject: Re: [Intel-gfx] [PATCH v12 7/8] drm/i915: refactor skylake scaler code into new file.
Date: Fri, 5 Feb 2021 17:04:47 +0200	[thread overview]
Message-ID: <YB1ej+Wg3wFnq1IU@intel.com> (raw)
In-Reply-To: <2fa703ffc7b96a41c392fd5ebbd2e6e4ffb6fb05.1612536383.git.jani.nikula@intel.com>

On Fri, Feb 05, 2021 at 04:48:42PM +0200, Jani Nikula wrote:
> From: Dave Airlie <airlied@redhat.com>
> 
> This moves the code from various places and consolidates it
> into one new file.
> 
> v2:
> - rename skl_program_plane -> skl_program_plane_scaler (Ville)
> - also move skl_pfit_enable, and consequently make some skl_scaler_*
>   functions static to skl_scaler.c (Ville)
> 
> Signed-off-by: Dave Airlie <airlied@redhat.com>
> Signed-off-by: Jani Nikula <jani.nikula@intel.com>

Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>

> ---
>  drivers/gpu/drm/i915/Makefile                 |   1 +
>  drivers/gpu/drm/i915/display/icl_dsi.c        |   1 +
>  drivers/gpu/drm/i915/display/intel_atomic.c   |   2 +-
>  drivers/gpu/drm/i915/display/intel_ddi.c      |   1 +
>  drivers/gpu/drm/i915/display/intel_display.c  | 488 +--------------
>  drivers/gpu/drm/i915/display/intel_display.h  |   6 -
>  drivers/gpu/drm/i915/display/intel_dp_mst.c   |   1 +
>  drivers/gpu/drm/i915/display/intel_sprite.c   |  62 --
>  drivers/gpu/drm/i915/display/intel_sprite.h   |   7 -
>  drivers/gpu/drm/i915/display/skl_scaler.c     | 556 ++++++++++++++++++
>  drivers/gpu/drm/i915/display/skl_scaler.h     |  29 +
>  .../drm/i915/display/skl_universal_plane.c    |   3 +-
>  .../drm/i915/display/skl_universal_plane.h    |   4 +
>  drivers/gpu/drm/i915/display/vlv_dsi.c        |   1 +
>  14 files changed, 598 insertions(+), 564 deletions(-)
>  create mode 100644 drivers/gpu/drm/i915/display/skl_scaler.c
>  create mode 100644 drivers/gpu/drm/i915/display/skl_scaler.h
> 
> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
> index 9388e09184fe..235679637d1c 100644
> --- a/drivers/gpu/drm/i915/Makefile
> +++ b/drivers/gpu/drm/i915/Makefile
> @@ -226,6 +226,7 @@ i915-y += \
>  	display/intel_tc.o \
>  	display/intel_vga.o \
>  	display/i9xx_plane.o \
> +	display/skl_scaler.o \
>  	display/skl_universal_plane.o
>  i915-$(CONFIG_ACPI) += \
>  	display/intel_acpi.o \
> diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c
> index 9eeec6fadec7..7ef6b89c79d9 100644
> --- a/drivers/gpu/drm/i915/display/icl_dsi.c
> +++ b/drivers/gpu/drm/i915/display/icl_dsi.c
> @@ -35,6 +35,7 @@
>  #include "intel_dsi.h"
>  #include "intel_panel.h"
>  #include "intel_vdsc.h"
> +#include "skl_scaler.h"
>  #include "skl_universal_plane.h"
>  
>  static int header_credits_available(struct drm_i915_private *dev_priv,
> diff --git a/drivers/gpu/drm/i915/display/intel_atomic.c b/drivers/gpu/drm/i915/display/intel_atomic.c
> index e00fdc47c0eb..27f7d7109ca3 100644
> --- a/drivers/gpu/drm/i915/display/intel_atomic.c
> +++ b/drivers/gpu/drm/i915/display/intel_atomic.c
> @@ -40,7 +40,7 @@
>  #include "intel_global_state.h"
>  #include "intel_hdcp.h"
>  #include "intel_psr.h"
> -#include "intel_sprite.h"
> +#include "skl_universal_plane.h"
>  
>  /**
>   * intel_digital_connector_atomic_get_property - hook for connector->atomic_get_property.
> diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
> index f4746c1edabe..3c4003605f93 100644
> --- a/drivers/gpu/drm/i915/display/intel_ddi.c
> +++ b/drivers/gpu/drm/i915/display/intel_ddi.c
> @@ -54,6 +54,7 @@
>  #include "intel_tc.h"
>  #include "intel_vdsc.h"
>  #include "intel_vrr.h"
> +#include "skl_scaler.h"
>  #include "skl_universal_plane.h"
>  
>  static const u8 index_to_dp_signal_levels[] = {
> diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
> index 1826b4fc6cec..beed08c00b6c 100644
> --- a/drivers/gpu/drm/i915/display/intel_display.c
> +++ b/drivers/gpu/drm/i915/display/intel_display.c
> @@ -94,6 +94,7 @@
>  #include "intel_tc.h"
>  #include "intel_vga.h"
>  #include "i9xx_plane.h"
> +#include "skl_scaler.h"
>  #include "skl_universal_plane.h"
>  
>  static void i9xx_crtc_clock_get(struct intel_crtc *crtc,
> @@ -2521,38 +2522,6 @@ intel_plane_fence_y_offset(const struct intel_plane_state *plane_state)
>  	return y;
>  }
>  
> -static void skl_detach_scaler(struct intel_crtc *intel_crtc, int id)
> -{
> -	struct drm_device *dev = intel_crtc->base.dev;
> -	struct drm_i915_private *dev_priv = to_i915(dev);
> -	unsigned long irqflags;
> -
> -	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
> -
> -	intel_de_write_fw(dev_priv, SKL_PS_CTRL(intel_crtc->pipe, id), 0);
> -	intel_de_write_fw(dev_priv, SKL_PS_WIN_POS(intel_crtc->pipe, id), 0);
> -	intel_de_write_fw(dev_priv, SKL_PS_WIN_SZ(intel_crtc->pipe, id), 0);
> -
> -	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
> -}
> -
> -/*
> - * This function detaches (aka. unbinds) unused scalers in hardware
> - */
> -static void skl_detach_scalers(const struct intel_crtc_state *crtc_state)
> -{
> -	struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->uapi.crtc);
> -	const struct intel_crtc_scaler_state *scaler_state =
> -		&crtc_state->scaler_state;
> -	int i;
> -
> -	/* loop through and disable scalers that aren't in use */
> -	for (i = 0; i < intel_crtc->num_scalers; i++) {
> -		if (!scaler_state->scalers[i].in_use)
> -			skl_detach_scaler(intel_crtc, i);
> -	}
> -}
> -
>  static int
>  __intel_display_resume(struct drm_device *dev,
>  		       struct drm_atomic_state *state,
> @@ -3117,461 +3086,6 @@ static void cpt_verify_modeset(struct drm_i915_private *dev_priv,
>  	}
>  }
>  
> -/*
> - * The hardware phase 0.0 refers to the center of the pixel.
> - * We want to start from the top/left edge which is phase
> - * -0.5. That matches how the hardware calculates the scaling
> - * factors (from top-left of the first pixel to bottom-right
> - * of the last pixel, as opposed to the pixel centers).
> - *
> - * For 4:2:0 subsampled chroma planes we obviously have to
> - * adjust that so that the chroma sample position lands in
> - * the right spot.
> - *
> - * Note that for packed YCbCr 4:2:2 formats there is no way to
> - * control chroma siting. The hardware simply replicates the
> - * chroma samples for both of the luma samples, and thus we don't
> - * actually get the expected MPEG2 chroma siting convention :(
> - * The same behaviour is observed on pre-SKL platforms as well.
> - *
> - * Theory behind the formula (note that we ignore sub-pixel
> - * source coordinates):
> - * s = source sample position
> - * d = destination sample position
> - *
> - * Downscaling 4:1:
> - * -0.5
> - * | 0.0
> - * | |     1.5 (initial phase)
> - * | |     |
> - * v v     v
> - * | s | s | s | s |
> - * |       d       |
> - *
> - * Upscaling 1:4:
> - * -0.5
> - * | -0.375 (initial phase)
> - * | |     0.0
> - * | |     |
> - * v v     v
> - * |       s       |
> - * | d | d | d | d |
> - */
> -u16 skl_scaler_calc_phase(int sub, int scale, bool chroma_cosited)
> -{
> -	int phase = -0x8000;
> -	u16 trip = 0;
> -
> -	if (chroma_cosited)
> -		phase += (sub - 1) * 0x8000 / sub;
> -
> -	phase += scale / (2 * sub);
> -
> -	/*
> -	 * Hardware initial phase limited to [-0.5:1.5].
> -	 * Since the max hardware scale factor is 3.0, we
> -	 * should never actually excdeed 1.0 here.
> -	 */
> -	WARN_ON(phase < -0x8000 || phase > 0x18000);
> -
> -	if (phase < 0)
> -		phase = 0x10000 + phase;
> -	else
> -		trip = PS_PHASE_TRIP;
> -
> -	return ((phase >> 2) & PS_PHASE_MASK) | trip;
> -}
> -
> -#define SKL_MIN_SRC_W 8
> -#define SKL_MAX_SRC_W 4096
> -#define SKL_MIN_SRC_H 8
> -#define SKL_MAX_SRC_H 4096
> -#define SKL_MIN_DST_W 8
> -#define SKL_MAX_DST_W 4096
> -#define SKL_MIN_DST_H 8
> -#define SKL_MAX_DST_H 4096
> -#define ICL_MAX_SRC_W 5120
> -#define ICL_MAX_SRC_H 4096
> -#define ICL_MAX_DST_W 5120
> -#define ICL_MAX_DST_H 4096
> -#define SKL_MIN_YUV_420_SRC_W 16
> -#define SKL_MIN_YUV_420_SRC_H 16
> -
> -static int
> -skl_update_scaler(struct intel_crtc_state *crtc_state, bool force_detach,
> -		  unsigned int scaler_user, int *scaler_id,
> -		  int src_w, int src_h, int dst_w, int dst_h,
> -		  const struct drm_format_info *format,
> -		  u64 modifier, bool need_scaler)
> -{
> -	struct intel_crtc_scaler_state *scaler_state =
> -		&crtc_state->scaler_state;
> -	struct intel_crtc *intel_crtc =
> -		to_intel_crtc(crtc_state->uapi.crtc);
> -	struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
> -	const struct drm_display_mode *adjusted_mode =
> -		&crtc_state->hw.adjusted_mode;
> -
> -	/*
> -	 * Src coordinates are already rotated by 270 degrees for
> -	 * the 90/270 degree plane rotation cases (to match the
> -	 * GTT mapping), hence no need to account for rotation here.
> -	 */
> -	if (src_w != dst_w || src_h != dst_h)
> -		need_scaler = true;
> -
> -	/*
> -	 * Scaling/fitting not supported in IF-ID mode in GEN9+
> -	 * TODO: Interlace fetch mode doesn't support YUV420 planar formats.
> -	 * Once NV12 is enabled, handle it here while allocating scaler
> -	 * for NV12.
> -	 */
> -	if (INTEL_GEN(dev_priv) >= 9 && crtc_state->hw.enable &&
> -	    need_scaler && adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
> -		drm_dbg_kms(&dev_priv->drm,
> -			    "Pipe/Plane scaling not supported with IF-ID mode\n");
> -		return -EINVAL;
> -	}
> -
> -	/*
> -	 * if plane is being disabled or scaler is no more required or force detach
> -	 *  - free scaler binded to this plane/crtc
> -	 *  - in order to do this, update crtc->scaler_usage
> -	 *
> -	 * Here scaler state in crtc_state is set free so that
> -	 * scaler can be assigned to other user. Actual register
> -	 * update to free the scaler is done in plane/panel-fit programming.
> -	 * For this purpose crtc/plane_state->scaler_id isn't reset here.
> -	 */
> -	if (force_detach || !need_scaler) {
> -		if (*scaler_id >= 0) {
> -			scaler_state->scaler_users &= ~(1 << scaler_user);
> -			scaler_state->scalers[*scaler_id].in_use = 0;
> -
> -			drm_dbg_kms(&dev_priv->drm,
> -				    "scaler_user index %u.%u: "
> -				    "Staged freeing scaler id %d scaler_users = 0x%x\n",
> -				    intel_crtc->pipe, scaler_user, *scaler_id,
> -				    scaler_state->scaler_users);
> -			*scaler_id = -1;
> -		}
> -		return 0;
> -	}
> -
> -	if (format && intel_format_info_is_yuv_semiplanar(format, modifier) &&
> -	    (src_h < SKL_MIN_YUV_420_SRC_H || src_w < SKL_MIN_YUV_420_SRC_W)) {
> -		drm_dbg_kms(&dev_priv->drm,
> -			    "Planar YUV: src dimensions not met\n");
> -		return -EINVAL;
> -	}
> -
> -	/* range checks */
> -	if (src_w < SKL_MIN_SRC_W || src_h < SKL_MIN_SRC_H ||
> -	    dst_w < SKL_MIN_DST_W || dst_h < SKL_MIN_DST_H ||
> -	    (INTEL_GEN(dev_priv) >= 11 &&
> -	     (src_w > ICL_MAX_SRC_W || src_h > ICL_MAX_SRC_H ||
> -	      dst_w > ICL_MAX_DST_W || dst_h > ICL_MAX_DST_H)) ||
> -	    (INTEL_GEN(dev_priv) < 11 &&
> -	     (src_w > SKL_MAX_SRC_W || src_h > SKL_MAX_SRC_H ||
> -	      dst_w > SKL_MAX_DST_W || dst_h > SKL_MAX_DST_H)))	{
> -		drm_dbg_kms(&dev_priv->drm,
> -			    "scaler_user index %u.%u: src %ux%u dst %ux%u "
> -			    "size is out of scaler range\n",
> -			    intel_crtc->pipe, scaler_user, src_w, src_h,
> -			    dst_w, dst_h);
> -		return -EINVAL;
> -	}
> -
> -	/* mark this plane as a scaler user in crtc_state */
> -	scaler_state->scaler_users |= (1 << scaler_user);
> -	drm_dbg_kms(&dev_priv->drm, "scaler_user index %u.%u: "
> -		    "staged scaling request for %ux%u->%ux%u scaler_users = 0x%x\n",
> -		    intel_crtc->pipe, scaler_user, src_w, src_h, dst_w, dst_h,
> -		    scaler_state->scaler_users);
> -
> -	return 0;
> -}
> -
> -static int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state)
> -{
> -	const struct drm_display_mode *pipe_mode = &crtc_state->hw.pipe_mode;
> -	int width, height;
> -
> -	if (crtc_state->pch_pfit.enabled) {
> -		width = drm_rect_width(&crtc_state->pch_pfit.dst);
> -		height = drm_rect_height(&crtc_state->pch_pfit.dst);
> -	} else {
> -		width = pipe_mode->crtc_hdisplay;
> -		height = pipe_mode->crtc_vdisplay;
> -	}
> -	return skl_update_scaler(crtc_state, !crtc_state->hw.active,
> -				 SKL_CRTC_INDEX,
> -				 &crtc_state->scaler_state.scaler_id,
> -				 crtc_state->pipe_src_w, crtc_state->pipe_src_h,
> -				 width, height, NULL, 0,
> -				 crtc_state->pch_pfit.enabled);
> -}
> -
> -/**
> - * skl_update_scaler_plane - Stages update to scaler state for a given plane.
> - * @crtc_state: crtc's scaler state
> - * @plane_state: atomic plane state to update
> - *
> - * Return
> - *     0 - scaler_usage updated successfully
> - *    error - requested scaling cannot be supported or other error condition
> - */
> -static int skl_update_scaler_plane(struct intel_crtc_state *crtc_state,
> -				   struct intel_plane_state *plane_state)
> -{
> -	struct intel_plane *intel_plane =
> -		to_intel_plane(plane_state->uapi.plane);
> -	struct drm_i915_private *dev_priv = to_i915(intel_plane->base.dev);
> -	struct drm_framebuffer *fb = plane_state->hw.fb;
> -	int ret;
> -	bool force_detach = !fb || !plane_state->uapi.visible;
> -	bool need_scaler = false;
> -
> -	/* Pre-gen11 and SDR planes always need a scaler for planar formats. */
> -	if (!icl_is_hdr_plane(dev_priv, intel_plane->id) &&
> -	    fb && intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier))
> -		need_scaler = true;
> -
> -	ret = skl_update_scaler(crtc_state, force_detach,
> -				drm_plane_index(&intel_plane->base),
> -				&plane_state->scaler_id,
> -				drm_rect_width(&plane_state->uapi.src) >> 16,
> -				drm_rect_height(&plane_state->uapi.src) >> 16,
> -				drm_rect_width(&plane_state->uapi.dst),
> -				drm_rect_height(&plane_state->uapi.dst),
> -				fb ? fb->format : NULL,
> -				fb ? fb->modifier : 0,
> -				need_scaler);
> -
> -	if (ret || plane_state->scaler_id < 0)
> -		return ret;
> -
> -	/* check colorkey */
> -	if (plane_state->ckey.flags) {
> -		drm_dbg_kms(&dev_priv->drm,
> -			    "[PLANE:%d:%s] scaling with color key not allowed",
> -			    intel_plane->base.base.id,
> -			    intel_plane->base.name);
> -		return -EINVAL;
> -	}
> -
> -	/* Check src format */
> -	switch (fb->format->format) {
> -	case DRM_FORMAT_RGB565:
> -	case DRM_FORMAT_XBGR8888:
> -	case DRM_FORMAT_XRGB8888:
> -	case DRM_FORMAT_ABGR8888:
> -	case DRM_FORMAT_ARGB8888:
> -	case DRM_FORMAT_XRGB2101010:
> -	case DRM_FORMAT_XBGR2101010:
> -	case DRM_FORMAT_ARGB2101010:
> -	case DRM_FORMAT_ABGR2101010:
> -	case DRM_FORMAT_YUYV:
> -	case DRM_FORMAT_YVYU:
> -	case DRM_FORMAT_UYVY:
> -	case DRM_FORMAT_VYUY:
> -	case DRM_FORMAT_NV12:
> -	case DRM_FORMAT_XYUV8888:
> -	case DRM_FORMAT_P010:
> -	case DRM_FORMAT_P012:
> -	case DRM_FORMAT_P016:
> -	case DRM_FORMAT_Y210:
> -	case DRM_FORMAT_Y212:
> -	case DRM_FORMAT_Y216:
> -	case DRM_FORMAT_XVYU2101010:
> -	case DRM_FORMAT_XVYU12_16161616:
> -	case DRM_FORMAT_XVYU16161616:
> -		break;
> -	case DRM_FORMAT_XBGR16161616F:
> -	case DRM_FORMAT_ABGR16161616F:
> -	case DRM_FORMAT_XRGB16161616F:
> -	case DRM_FORMAT_ARGB16161616F:
> -		if (INTEL_GEN(dev_priv) >= 11)
> -			break;
> -		fallthrough;
> -	default:
> -		drm_dbg_kms(&dev_priv->drm,
> -			    "[PLANE:%d:%s] FB:%d unsupported scaling format 0x%x\n",
> -			    intel_plane->base.base.id, intel_plane->base.name,
> -			    fb->base.id, fb->format->format);
> -		return -EINVAL;
> -	}
> -
> -	return 0;
> -}
> -
> -void skl_scaler_disable(const struct intel_crtc_state *old_crtc_state)
> -{
> -	struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc);
> -	int i;
> -
> -	for (i = 0; i < crtc->num_scalers; i++)
> -		skl_detach_scaler(crtc, i);
> -}
> -
> -static int cnl_coef_tap(int i)
> -{
> -	return i % 7;
> -}
> -
> -static u16 cnl_nearest_filter_coef(int t)
> -{
> -	return t == 3 ? 0x0800 : 0x3000;
> -}
> -
> -/*
> - *  Theory behind setting nearest-neighbor integer scaling:
> - *
> - *  17 phase of 7 taps requires 119 coefficients in 60 dwords per set.
> - *  The letter represents the filter tap (D is the center tap) and the number
> - *  represents the coefficient set for a phase (0-16).
> - *
> - *         +------------+------------------------+------------------------+
> - *         |Index value | Data value coeffient 1 | Data value coeffient 2 |
> - *         +------------+------------------------+------------------------+
> - *         |   00h      |          B0            |          A0            |
> - *         +------------+------------------------+------------------------+
> - *         |   01h      |          D0            |          C0            |
> - *         +------------+------------------------+------------------------+
> - *         |   02h      |          F0            |          E0            |
> - *         +------------+------------------------+------------------------+
> - *         |   03h      |          A1            |          G0            |
> - *         +------------+------------------------+------------------------+
> - *         |   04h      |          C1            |          B1            |
> - *         +------------+------------------------+------------------------+
> - *         |   ...      |          ...           |          ...           |
> - *         +------------+------------------------+------------------------+
> - *         |   38h      |          B16           |          A16           |
> - *         +------------+------------------------+------------------------+
> - *         |   39h      |          D16           |          C16           |
> - *         +------------+------------------------+------------------------+
> - *         |   3Ah      |          F16           |          C16           |
> - *         +------------+------------------------+------------------------+
> - *         |   3Bh      |        Reserved        |          G16           |
> - *         +------------+------------------------+------------------------+
> - *
> - *  To enable nearest-neighbor scaling:  program scaler coefficents with
> - *  the center tap (Dxx) values set to 1 and all other values set to 0 as per
> - *  SCALER_COEFFICIENT_FORMAT
> - *
> - */
> -
> -static void cnl_program_nearest_filter_coefs(struct drm_i915_private *dev_priv,
> -					     enum pipe pipe, int id, int set)
> -{
> -	int i;
> -
> -	intel_de_write_fw(dev_priv, CNL_PS_COEF_INDEX_SET(pipe, id, set),
> -			  PS_COEE_INDEX_AUTO_INC);
> -
> -	for (i = 0; i < 17 * 7; i += 2) {
> -		u32 tmp;
> -		int t;
> -
> -		t = cnl_coef_tap(i);
> -		tmp = cnl_nearest_filter_coef(t);
> -
> -		t = cnl_coef_tap(i + 1);
> -		tmp |= cnl_nearest_filter_coef(t) << 16;
> -
> -		intel_de_write_fw(dev_priv, CNL_PS_COEF_DATA_SET(pipe, id, set),
> -				  tmp);
> -	}
> -
> -	intel_de_write_fw(dev_priv, CNL_PS_COEF_INDEX_SET(pipe, id, set), 0);
> -}
> -
> -u32 skl_scaler_get_filter_select(enum drm_scaling_filter filter, int set)
> -{
> -	if (filter == DRM_SCALING_FILTER_NEAREST_NEIGHBOR) {
> -		return (PS_FILTER_PROGRAMMED |
> -			PS_Y_VERT_FILTER_SELECT(set) |
> -			PS_Y_HORZ_FILTER_SELECT(set) |
> -			PS_UV_VERT_FILTER_SELECT(set) |
> -			PS_UV_HORZ_FILTER_SELECT(set));
> -	}
> -
> -	return PS_FILTER_MEDIUM;
> -}
> -
> -void skl_scaler_setup_filter(struct drm_i915_private *dev_priv, enum pipe pipe,
> -			     int id, int set, enum drm_scaling_filter filter)
> -{
> -	switch (filter) {
> -	case DRM_SCALING_FILTER_DEFAULT:
> -		break;
> -	case DRM_SCALING_FILTER_NEAREST_NEIGHBOR:
> -		cnl_program_nearest_filter_coefs(dev_priv, pipe, id, set);
> -		break;
> -	default:
> -		MISSING_CASE(filter);
> -	}
> -}
> -
> -static void skl_pfit_enable(const struct intel_crtc_state *crtc_state)
> -{
> -	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
> -	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
> -	const struct intel_crtc_scaler_state *scaler_state =
> -		&crtc_state->scaler_state;
> -	struct drm_rect src = {
> -		.x2 = crtc_state->pipe_src_w << 16,
> -		.y2 = crtc_state->pipe_src_h << 16,
> -	};
> -	const struct drm_rect *dst = &crtc_state->pch_pfit.dst;
> -	u16 uv_rgb_hphase, uv_rgb_vphase;
> -	enum pipe pipe = crtc->pipe;
> -	int width = drm_rect_width(dst);
> -	int height = drm_rect_height(dst);
> -	int x = dst->x1;
> -	int y = dst->y1;
> -	int hscale, vscale;
> -	unsigned long irqflags;
> -	int id;
> -	u32 ps_ctrl;
> -
> -	if (!crtc_state->pch_pfit.enabled)
> -		return;
> -
> -	if (drm_WARN_ON(&dev_priv->drm,
> -			crtc_state->scaler_state.scaler_id < 0))
> -		return;
> -
> -	hscale = drm_rect_calc_hscale(&src, dst, 0, INT_MAX);
> -	vscale = drm_rect_calc_vscale(&src, dst, 0, INT_MAX);
> -
> -	uv_rgb_hphase = skl_scaler_calc_phase(1, hscale, false);
> -	uv_rgb_vphase = skl_scaler_calc_phase(1, vscale, false);
> -
> -	id = scaler_state->scaler_id;
> -
> -	ps_ctrl = skl_scaler_get_filter_select(crtc_state->hw.scaling_filter, 0);
> -	ps_ctrl |=  PS_SCALER_EN | scaler_state->scalers[id].mode;
> -
> -	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
> -
> -	skl_scaler_setup_filter(dev_priv, pipe, id, 0,
> -				crtc_state->hw.scaling_filter);
> -
> -	intel_de_write_fw(dev_priv, SKL_PS_CTRL(pipe, id), ps_ctrl);
> -
> -	intel_de_write_fw(dev_priv, SKL_PS_VPHASE(pipe, id),
> -			  PS_Y_PHASE(0) | PS_UV_RGB_PHASE(uv_rgb_vphase));
> -	intel_de_write_fw(dev_priv, SKL_PS_HPHASE(pipe, id),
> -			  PS_Y_PHASE(0) | PS_UV_RGB_PHASE(uv_rgb_hphase));
> -	intel_de_write_fw(dev_priv, SKL_PS_WIN_POS(pipe, id),
> -			  x << 16 | y);
> -	intel_de_write_fw(dev_priv, SKL_PS_WIN_SZ(pipe, id),
> -			  width << 16 | height);
> -
> -	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
> -}
> -
>  static void ilk_pfit_enable(const struct intel_crtc_state *crtc_state)
>  {
>  	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
> diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h
> index c80e5a3356ef..e3757ecabbf7 100644
> --- a/drivers/gpu/drm/i915/display/intel_display.h
> +++ b/drivers/gpu/drm/i915/display/intel_display.h
> @@ -618,12 +618,6 @@ enum intel_display_power_domain
>  intel_legacy_aux_to_power_domain(enum aux_ch aux_ch);
>  void intel_crtc_arm_fifo_underrun(struct intel_crtc *crtc,
>  				  struct intel_crtc_state *crtc_state);
> -
> -u16 skl_scaler_calc_phase(int sub, int scale, bool chroma_center);
> -void skl_scaler_disable(const struct intel_crtc_state *old_crtc_state);
> -u32 skl_scaler_get_filter_select(enum drm_scaling_filter filter, int set);
> -void skl_scaler_setup_filter(struct drm_i915_private *dev_priv, enum pipe pipe,
> -			     int id, int set, enum drm_scaling_filter filter);
>  void ilk_pfit_disable(const struct intel_crtc_state *old_crtc_state);
>  
>  int bdw_get_pipemisc_bpp(struct intel_crtc *crtc);
> diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c
> index b4621ed0127e..8e316146b6d1 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c
> +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c
> @@ -39,6 +39,7 @@
>  #include "intel_dp_mst.h"
>  #include "intel_dpio_phy.h"
>  #include "intel_hdcp.h"
> +#include "skl_scaler.h"
>  
>  static int intel_dp_mst_compute_link_config(struct intel_encoder *encoder,
>  					    struct intel_crtc_state *crtc_state,
> diff --git a/drivers/gpu/drm/i915/display/intel_sprite.c b/drivers/gpu/drm/i915/display/intel_sprite.c
> index 46fcb5b9983f..4cbdb8fd4bb1 100644
> --- a/drivers/gpu/drm/i915/display/intel_sprite.c
> +++ b/drivers/gpu/drm/i915/display/intel_sprite.c
> @@ -138,68 +138,6 @@ int intel_plane_check_src_coordinates(struct intel_plane_state *plane_state)
>  	return 0;
>  }
>  
> -void
> -skl_program_scaler(struct intel_plane *plane,
> -		   const struct intel_crtc_state *crtc_state,
> -		   const struct intel_plane_state *plane_state)
> -{
> -	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
> -	const struct drm_framebuffer *fb = plane_state->hw.fb;
> -	enum pipe pipe = plane->pipe;
> -	int scaler_id = plane_state->scaler_id;
> -	const struct intel_scaler *scaler =
> -		&crtc_state->scaler_state.scalers[scaler_id];
> -	int crtc_x = plane_state->uapi.dst.x1;
> -	int crtc_y = plane_state->uapi.dst.y1;
> -	u32 crtc_w = drm_rect_width(&plane_state->uapi.dst);
> -	u32 crtc_h = drm_rect_height(&plane_state->uapi.dst);
> -	u16 y_hphase, uv_rgb_hphase;
> -	u16 y_vphase, uv_rgb_vphase;
> -	int hscale, vscale;
> -	u32 ps_ctrl;
> -
> -	hscale = drm_rect_calc_hscale(&plane_state->uapi.src,
> -				      &plane_state->uapi.dst,
> -				      0, INT_MAX);
> -	vscale = drm_rect_calc_vscale(&plane_state->uapi.src,
> -				      &plane_state->uapi.dst,
> -				      0, INT_MAX);
> -
> -	/* TODO: handle sub-pixel coordinates */
> -	if (intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier) &&
> -	    !icl_is_hdr_plane(dev_priv, plane->id)) {
> -		y_hphase = skl_scaler_calc_phase(1, hscale, false);
> -		y_vphase = skl_scaler_calc_phase(1, vscale, false);
> -
> -		/* MPEG2 chroma siting convention */
> -		uv_rgb_hphase = skl_scaler_calc_phase(2, hscale, true);
> -		uv_rgb_vphase = skl_scaler_calc_phase(2, vscale, false);
> -	} else {
> -		/* not used */
> -		y_hphase = 0;
> -		y_vphase = 0;
> -
> -		uv_rgb_hphase = skl_scaler_calc_phase(1, hscale, false);
> -		uv_rgb_vphase = skl_scaler_calc_phase(1, vscale, false);
> -	}
> -
> -	ps_ctrl = skl_scaler_get_filter_select(plane_state->hw.scaling_filter, 0);
> -	ps_ctrl |= PS_SCALER_EN | PS_PLANE_SEL(plane->id) | scaler->mode;
> -
> -	skl_scaler_setup_filter(dev_priv, pipe, scaler_id, 0,
> -				plane_state->hw.scaling_filter);
> -
> -	intel_de_write_fw(dev_priv, SKL_PS_CTRL(pipe, scaler_id), ps_ctrl);
> -	intel_de_write_fw(dev_priv, SKL_PS_VPHASE(pipe, scaler_id),
> -			  PS_Y_PHASE(y_vphase) | PS_UV_RGB_PHASE(uv_rgb_vphase));
> -	intel_de_write_fw(dev_priv, SKL_PS_HPHASE(pipe, scaler_id),
> -			  PS_Y_PHASE(y_hphase) | PS_UV_RGB_PHASE(uv_rgb_hphase));
> -	intel_de_write_fw(dev_priv, SKL_PS_WIN_POS(pipe, scaler_id),
> -			  (crtc_x << 16) | crtc_y);
> -	intel_de_write_fw(dev_priv, SKL_PS_WIN_SZ(pipe, scaler_id),
> -			  (crtc_w << 16) | crtc_h);
> -}
> -
>  static void i9xx_plane_linear_gamma(u16 gamma[8])
>  {
>  	/* The points are not evenly spaced. */
> diff --git a/drivers/gpu/drm/i915/display/intel_sprite.h b/drivers/gpu/drm/i915/display/intel_sprite.h
> index 418897f953fc..f6989da2dc4b 100644
> --- a/drivers/gpu/drm/i915/display/intel_sprite.h
> +++ b/drivers/gpu/drm/i915/display/intel_sprite.h
> @@ -45,10 +45,6 @@ static inline u8 icl_hdr_plane_mask(void)
>  		BIT(PLANE_SPRITE0) | BIT(PLANE_SPRITE1);
>  }
>  
> -bool icl_is_nv12_y_plane(struct drm_i915_private *dev_priv,
> -			 enum plane_id plane_id);
> -bool icl_is_hdr_plane(struct drm_i915_private *dev_priv, enum plane_id plane_id);
> -
>  int ivb_plane_min_cdclk(const struct intel_crtc_state *crtc_state,
>  			const struct intel_plane_state *plane_state);
>  int hsw_plane_min_cdclk(const struct intel_crtc_state *crtc_state,
> @@ -56,7 +52,4 @@ int hsw_plane_min_cdclk(const struct intel_crtc_state *crtc_state,
>  int vlv_plane_min_cdclk(const struct intel_crtc_state *crtc_state,
>  			const struct intel_plane_state *plane_state);
>  
> -void skl_program_scaler(struct intel_plane *plane,
> -			const struct intel_crtc_state *crtc_state,
> -			const struct intel_plane_state *plane_state);
>  #endif /* __INTEL_SPRITE_H__ */
> diff --git a/drivers/gpu/drm/i915/display/skl_scaler.c b/drivers/gpu/drm/i915/display/skl_scaler.c
> new file mode 100644
> index 000000000000..b37a87bb190f
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/display/skl_scaler.c
> @@ -0,0 +1,556 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright © 2020 Intel Corporation
> + */
> +#include "intel_display_types.h"
> +#include "skl_scaler.h"
> +#include "skl_universal_plane.h"
> +
> +/*
> + * The hardware phase 0.0 refers to the center of the pixel.
> + * We want to start from the top/left edge which is phase
> + * -0.5. That matches how the hardware calculates the scaling
> + * factors (from top-left of the first pixel to bottom-right
> + * of the last pixel, as opposed to the pixel centers).
> + *
> + * For 4:2:0 subsampled chroma planes we obviously have to
> + * adjust that so that the chroma sample position lands in
> + * the right spot.
> + *
> + * Note that for packed YCbCr 4:2:2 formats there is no way to
> + * control chroma siting. The hardware simply replicates the
> + * chroma samples for both of the luma samples, and thus we don't
> + * actually get the expected MPEG2 chroma siting convention :(
> + * The same behaviour is observed on pre-SKL platforms as well.
> + *
> + * Theory behind the formula (note that we ignore sub-pixel
> + * source coordinates):
> + * s = source sample position
> + * d = destination sample position
> + *
> + * Downscaling 4:1:
> + * -0.5
> + * | 0.0
> + * | |     1.5 (initial phase)
> + * | |     |
> + * v v     v
> + * | s | s | s | s |
> + * |       d       |
> + *
> + * Upscaling 1:4:
> + * -0.5
> + * | -0.375 (initial phase)
> + * | |     0.0
> + * | |     |
> + * v v     v
> + * |       s       |
> + * | d | d | d | d |
> + */
> +static u16 skl_scaler_calc_phase(int sub, int scale, bool chroma_cosited)
> +{
> +	int phase = -0x8000;
> +	u16 trip = 0;
> +
> +	if (chroma_cosited)
> +		phase += (sub - 1) * 0x8000 / sub;
> +
> +	phase += scale / (2 * sub);
> +
> +	/*
> +	 * Hardware initial phase limited to [-0.5:1.5].
> +	 * Since the max hardware scale factor is 3.0, we
> +	 * should never actually excdeed 1.0 here.
> +	 */
> +	WARN_ON(phase < -0x8000 || phase > 0x18000);
> +
> +	if (phase < 0)
> +		phase = 0x10000 + phase;
> +	else
> +		trip = PS_PHASE_TRIP;
> +
> +	return ((phase >> 2) & PS_PHASE_MASK) | trip;
> +}
> +
> +#define SKL_MIN_SRC_W 8
> +#define SKL_MAX_SRC_W 4096
> +#define SKL_MIN_SRC_H 8
> +#define SKL_MAX_SRC_H 4096
> +#define SKL_MIN_DST_W 8
> +#define SKL_MAX_DST_W 4096
> +#define SKL_MIN_DST_H 8
> +#define SKL_MAX_DST_H 4096
> +#define ICL_MAX_SRC_W 5120
> +#define ICL_MAX_SRC_H 4096
> +#define ICL_MAX_DST_W 5120
> +#define ICL_MAX_DST_H 4096
> +#define SKL_MIN_YUV_420_SRC_W 16
> +#define SKL_MIN_YUV_420_SRC_H 16
> +
> +static int
> +skl_update_scaler(struct intel_crtc_state *crtc_state, bool force_detach,
> +		  unsigned int scaler_user, int *scaler_id,
> +		  int src_w, int src_h, int dst_w, int dst_h,
> +		  const struct drm_format_info *format,
> +		  u64 modifier, bool need_scaler)
> +{
> +	struct intel_crtc_scaler_state *scaler_state =
> +		&crtc_state->scaler_state;
> +	struct intel_crtc *intel_crtc =
> +		to_intel_crtc(crtc_state->uapi.crtc);
> +	struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
> +	const struct drm_display_mode *adjusted_mode =
> +		&crtc_state->hw.adjusted_mode;
> +
> +	/*
> +	 * Src coordinates are already rotated by 270 degrees for
> +	 * the 90/270 degree plane rotation cases (to match the
> +	 * GTT mapping), hence no need to account for rotation here.
> +	 */
> +	if (src_w != dst_w || src_h != dst_h)
> +		need_scaler = true;
> +
> +	/*
> +	 * Scaling/fitting not supported in IF-ID mode in GEN9+
> +	 * TODO: Interlace fetch mode doesn't support YUV420 planar formats.
> +	 * Once NV12 is enabled, handle it here while allocating scaler
> +	 * for NV12.
> +	 */
> +	if (INTEL_GEN(dev_priv) >= 9 && crtc_state->hw.enable &&
> +	    need_scaler && adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
> +		drm_dbg_kms(&dev_priv->drm,
> +			    "Pipe/Plane scaling not supported with IF-ID mode\n");
> +		return -EINVAL;
> +	}
> +
> +	/*
> +	 * if plane is being disabled or scaler is no more required or force detach
> +	 *  - free scaler binded to this plane/crtc
> +	 *  - in order to do this, update crtc->scaler_usage
> +	 *
> +	 * Here scaler state in crtc_state is set free so that
> +	 * scaler can be assigned to other user. Actual register
> +	 * update to free the scaler is done in plane/panel-fit programming.
> +	 * For this purpose crtc/plane_state->scaler_id isn't reset here.
> +	 */
> +	if (force_detach || !need_scaler) {
> +		if (*scaler_id >= 0) {
> +			scaler_state->scaler_users &= ~(1 << scaler_user);
> +			scaler_state->scalers[*scaler_id].in_use = 0;
> +
> +			drm_dbg_kms(&dev_priv->drm,
> +				    "scaler_user index %u.%u: "
> +				    "Staged freeing scaler id %d scaler_users = 0x%x\n",
> +				    intel_crtc->pipe, scaler_user, *scaler_id,
> +				    scaler_state->scaler_users);
> +			*scaler_id = -1;
> +		}
> +		return 0;
> +	}
> +
> +	if (format && intel_format_info_is_yuv_semiplanar(format, modifier) &&
> +	    (src_h < SKL_MIN_YUV_420_SRC_H || src_w < SKL_MIN_YUV_420_SRC_W)) {
> +		drm_dbg_kms(&dev_priv->drm,
> +			    "Planar YUV: src dimensions not met\n");
> +		return -EINVAL;
> +	}
> +
> +	/* range checks */
> +	if (src_w < SKL_MIN_SRC_W || src_h < SKL_MIN_SRC_H ||
> +	    dst_w < SKL_MIN_DST_W || dst_h < SKL_MIN_DST_H ||
> +	    (INTEL_GEN(dev_priv) >= 11 &&
> +	     (src_w > ICL_MAX_SRC_W || src_h > ICL_MAX_SRC_H ||
> +	      dst_w > ICL_MAX_DST_W || dst_h > ICL_MAX_DST_H)) ||
> +	    (INTEL_GEN(dev_priv) < 11 &&
> +	     (src_w > SKL_MAX_SRC_W || src_h > SKL_MAX_SRC_H ||
> +	      dst_w > SKL_MAX_DST_W || dst_h > SKL_MAX_DST_H)))	{
> +		drm_dbg_kms(&dev_priv->drm,
> +			    "scaler_user index %u.%u: src %ux%u dst %ux%u "
> +			    "size is out of scaler range\n",
> +			    intel_crtc->pipe, scaler_user, src_w, src_h,
> +			    dst_w, dst_h);
> +		return -EINVAL;
> +	}
> +
> +	/* mark this plane as a scaler user in crtc_state */
> +	scaler_state->scaler_users |= (1 << scaler_user);
> +	drm_dbg_kms(&dev_priv->drm, "scaler_user index %u.%u: "
> +		    "staged scaling request for %ux%u->%ux%u scaler_users = 0x%x\n",
> +		    intel_crtc->pipe, scaler_user, src_w, src_h, dst_w, dst_h,
> +		    scaler_state->scaler_users);
> +
> +	return 0;
> +}
> +
> +int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state)
> +{
> +	const struct drm_display_mode *pipe_mode = &crtc_state->hw.pipe_mode;
> +	int width, height;
> +
> +	if (crtc_state->pch_pfit.enabled) {
> +		width = drm_rect_width(&crtc_state->pch_pfit.dst);
> +		height = drm_rect_height(&crtc_state->pch_pfit.dst);
> +	} else {
> +		width = pipe_mode->crtc_hdisplay;
> +		height = pipe_mode->crtc_vdisplay;
> +	}
> +	return skl_update_scaler(crtc_state, !crtc_state->hw.active,
> +				 SKL_CRTC_INDEX,
> +				 &crtc_state->scaler_state.scaler_id,
> +				 crtc_state->pipe_src_w, crtc_state->pipe_src_h,
> +				 width, height, NULL, 0,
> +				 crtc_state->pch_pfit.enabled);
> +}
> +
> +/**
> + * skl_update_scaler_plane - Stages update to scaler state for a given plane.
> + * @crtc_state: crtc's scaler state
> + * @plane_state: atomic plane state to update
> + *
> + * Return
> + *     0 - scaler_usage updated successfully
> + *    error - requested scaling cannot be supported or other error condition
> + */
> +int skl_update_scaler_plane(struct intel_crtc_state *crtc_state,
> +			    struct intel_plane_state *plane_state)
> +{
> +	struct intel_plane *intel_plane =
> +		to_intel_plane(plane_state->uapi.plane);
> +	struct drm_i915_private *dev_priv = to_i915(intel_plane->base.dev);
> +	struct drm_framebuffer *fb = plane_state->hw.fb;
> +	int ret;
> +	bool force_detach = !fb || !plane_state->uapi.visible;
> +	bool need_scaler = false;
> +
> +	/* Pre-gen11 and SDR planes always need a scaler for planar formats. */
> +	if (!icl_is_hdr_plane(dev_priv, intel_plane->id) &&
> +	    fb && intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier))
> +		need_scaler = true;
> +
> +	ret = skl_update_scaler(crtc_state, force_detach,
> +				drm_plane_index(&intel_plane->base),
> +				&plane_state->scaler_id,
> +				drm_rect_width(&plane_state->uapi.src) >> 16,
> +				drm_rect_height(&plane_state->uapi.src) >> 16,
> +				drm_rect_width(&plane_state->uapi.dst),
> +				drm_rect_height(&plane_state->uapi.dst),
> +				fb ? fb->format : NULL,
> +				fb ? fb->modifier : 0,
> +				need_scaler);
> +
> +	if (ret || plane_state->scaler_id < 0)
> +		return ret;
> +
> +	/* check colorkey */
> +	if (plane_state->ckey.flags) {
> +		drm_dbg_kms(&dev_priv->drm,
> +			    "[PLANE:%d:%s] scaling with color key not allowed",
> +			    intel_plane->base.base.id,
> +			    intel_plane->base.name);
> +		return -EINVAL;
> +	}
> +
> +	/* Check src format */
> +	switch (fb->format->format) {
> +	case DRM_FORMAT_RGB565:
> +	case DRM_FORMAT_XBGR8888:
> +	case DRM_FORMAT_XRGB8888:
> +	case DRM_FORMAT_ABGR8888:
> +	case DRM_FORMAT_ARGB8888:
> +	case DRM_FORMAT_XRGB2101010:
> +	case DRM_FORMAT_XBGR2101010:
> +	case DRM_FORMAT_ARGB2101010:
> +	case DRM_FORMAT_ABGR2101010:
> +	case DRM_FORMAT_YUYV:
> +	case DRM_FORMAT_YVYU:
> +	case DRM_FORMAT_UYVY:
> +	case DRM_FORMAT_VYUY:
> +	case DRM_FORMAT_NV12:
> +	case DRM_FORMAT_XYUV8888:
> +	case DRM_FORMAT_P010:
> +	case DRM_FORMAT_P012:
> +	case DRM_FORMAT_P016:
> +	case DRM_FORMAT_Y210:
> +	case DRM_FORMAT_Y212:
> +	case DRM_FORMAT_Y216:
> +	case DRM_FORMAT_XVYU2101010:
> +	case DRM_FORMAT_XVYU12_16161616:
> +	case DRM_FORMAT_XVYU16161616:
> +		break;
> +	case DRM_FORMAT_XBGR16161616F:
> +	case DRM_FORMAT_ABGR16161616F:
> +	case DRM_FORMAT_XRGB16161616F:
> +	case DRM_FORMAT_ARGB16161616F:
> +		if (INTEL_GEN(dev_priv) >= 11)
> +			break;
> +		fallthrough;
> +	default:
> +		drm_dbg_kms(&dev_priv->drm,
> +			    "[PLANE:%d:%s] FB:%d unsupported scaling format 0x%x\n",
> +			    intel_plane->base.base.id, intel_plane->base.name,
> +			    fb->base.id, fb->format->format);
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static int cnl_coef_tap(int i)
> +{
> +	return i % 7;
> +}
> +
> +static u16 cnl_nearest_filter_coef(int t)
> +{
> +	return t == 3 ? 0x0800 : 0x3000;
> +}
> +
> +/*
> + *  Theory behind setting nearest-neighbor integer scaling:
> + *
> + *  17 phase of 7 taps requires 119 coefficients in 60 dwords per set.
> + *  The letter represents the filter tap (D is the center tap) and the number
> + *  represents the coefficient set for a phase (0-16).
> + *
> + *         +------------+------------------------+------------------------+
> + *         |Index value | Data value coeffient 1 | Data value coeffient 2 |
> + *         +------------+------------------------+------------------------+
> + *         |   00h      |          B0            |          A0            |
> + *         +------------+------------------------+------------------------+
> + *         |   01h      |          D0            |          C0            |
> + *         +------------+------------------------+------------------------+
> + *         |   02h      |          F0            |          E0            |
> + *         +------------+------------------------+------------------------+
> + *         |   03h      |          A1            |          G0            |
> + *         +------------+------------------------+------------------------+
> + *         |   04h      |          C1            |          B1            |
> + *         +------------+------------------------+------------------------+
> + *         |   ...      |          ...           |          ...           |
> + *         +------------+------------------------+------------------------+
> + *         |   38h      |          B16           |          A16           |
> + *         +------------+------------------------+------------------------+
> + *         |   39h      |          D16           |          C16           |
> + *         +------------+------------------------+------------------------+
> + *         |   3Ah      |          F16           |          C16           |
> + *         +------------+------------------------+------------------------+
> + *         |   3Bh      |        Reserved        |          G16           |
> + *         +------------+------------------------+------------------------+
> + *
> + *  To enable nearest-neighbor scaling:  program scaler coefficents with
> + *  the center tap (Dxx) values set to 1 and all other values set to 0 as per
> + *  SCALER_COEFFICIENT_FORMAT
> + *
> + */
> +
> +static void cnl_program_nearest_filter_coefs(struct drm_i915_private *dev_priv,
> +					     enum pipe pipe, int id, int set)
> +{
> +	int i;
> +
> +	intel_de_write_fw(dev_priv, CNL_PS_COEF_INDEX_SET(pipe, id, set),
> +			  PS_COEE_INDEX_AUTO_INC);
> +
> +	for (i = 0; i < 17 * 7; i += 2) {
> +		u32 tmp;
> +		int t;
> +
> +		t = cnl_coef_tap(i);
> +		tmp = cnl_nearest_filter_coef(t);
> +
> +		t = cnl_coef_tap(i + 1);
> +		tmp |= cnl_nearest_filter_coef(t) << 16;
> +
> +		intel_de_write_fw(dev_priv, CNL_PS_COEF_DATA_SET(pipe, id, set),
> +				  tmp);
> +	}
> +
> +	intel_de_write_fw(dev_priv, CNL_PS_COEF_INDEX_SET(pipe, id, set), 0);
> +}
> +
> +static u32 skl_scaler_get_filter_select(enum drm_scaling_filter filter, int set)
> +{
> +	if (filter == DRM_SCALING_FILTER_NEAREST_NEIGHBOR) {
> +		return (PS_FILTER_PROGRAMMED |
> +			PS_Y_VERT_FILTER_SELECT(set) |
> +			PS_Y_HORZ_FILTER_SELECT(set) |
> +			PS_UV_VERT_FILTER_SELECT(set) |
> +			PS_UV_HORZ_FILTER_SELECT(set));
> +	}
> +
> +	return PS_FILTER_MEDIUM;
> +}
> +
> +static void skl_scaler_setup_filter(struct drm_i915_private *dev_priv, enum pipe pipe,
> +				    int id, int set, enum drm_scaling_filter filter)
> +{
> +	switch (filter) {
> +	case DRM_SCALING_FILTER_DEFAULT:
> +		break;
> +	case DRM_SCALING_FILTER_NEAREST_NEIGHBOR:
> +		cnl_program_nearest_filter_coefs(dev_priv, pipe, id, set);
> +		break;
> +	default:
> +		MISSING_CASE(filter);
> +	}
> +}
> +
> +void skl_pfit_enable(const struct intel_crtc_state *crtc_state)
> +{
> +	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
> +	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
> +	const struct intel_crtc_scaler_state *scaler_state =
> +		&crtc_state->scaler_state;
> +	struct drm_rect src = {
> +		.x2 = crtc_state->pipe_src_w << 16,
> +		.y2 = crtc_state->pipe_src_h << 16,
> +	};
> +	const struct drm_rect *dst = &crtc_state->pch_pfit.dst;
> +	u16 uv_rgb_hphase, uv_rgb_vphase;
> +	enum pipe pipe = crtc->pipe;
> +	int width = drm_rect_width(dst);
> +	int height = drm_rect_height(dst);
> +	int x = dst->x1;
> +	int y = dst->y1;
> +	int hscale, vscale;
> +	unsigned long irqflags;
> +	int id;
> +	u32 ps_ctrl;
> +
> +	if (!crtc_state->pch_pfit.enabled)
> +		return;
> +
> +	if (drm_WARN_ON(&dev_priv->drm,
> +			crtc_state->scaler_state.scaler_id < 0))
> +		return;
> +
> +	hscale = drm_rect_calc_hscale(&src, dst, 0, INT_MAX);
> +	vscale = drm_rect_calc_vscale(&src, dst, 0, INT_MAX);
> +
> +	uv_rgb_hphase = skl_scaler_calc_phase(1, hscale, false);
> +	uv_rgb_vphase = skl_scaler_calc_phase(1, vscale, false);
> +
> +	id = scaler_state->scaler_id;
> +
> +	ps_ctrl = skl_scaler_get_filter_select(crtc_state->hw.scaling_filter, 0);
> +	ps_ctrl |=  PS_SCALER_EN | scaler_state->scalers[id].mode;
> +
> +	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
> +
> +	skl_scaler_setup_filter(dev_priv, pipe, id, 0,
> +				crtc_state->hw.scaling_filter);
> +
> +	intel_de_write_fw(dev_priv, SKL_PS_CTRL(pipe, id), ps_ctrl);
> +
> +	intel_de_write_fw(dev_priv, SKL_PS_VPHASE(pipe, id),
> +			  PS_Y_PHASE(0) | PS_UV_RGB_PHASE(uv_rgb_vphase));
> +	intel_de_write_fw(dev_priv, SKL_PS_HPHASE(pipe, id),
> +			  PS_Y_PHASE(0) | PS_UV_RGB_PHASE(uv_rgb_hphase));
> +	intel_de_write_fw(dev_priv, SKL_PS_WIN_POS(pipe, id),
> +			  x << 16 | y);
> +	intel_de_write_fw(dev_priv, SKL_PS_WIN_SZ(pipe, id),
> +			  width << 16 | height);
> +
> +	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
> +}
> +
> +void
> +skl_program_plane_scaler(struct intel_plane *plane,
> +			 const struct intel_crtc_state *crtc_state,
> +			 const struct intel_plane_state *plane_state)
> +{
> +	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
> +	const struct drm_framebuffer *fb = plane_state->hw.fb;
> +	enum pipe pipe = plane->pipe;
> +	int scaler_id = plane_state->scaler_id;
> +	const struct intel_scaler *scaler =
> +		&crtc_state->scaler_state.scalers[scaler_id];
> +	int crtc_x = plane_state->uapi.dst.x1;
> +	int crtc_y = plane_state->uapi.dst.y1;
> +	u32 crtc_w = drm_rect_width(&plane_state->uapi.dst);
> +	u32 crtc_h = drm_rect_height(&plane_state->uapi.dst);
> +	u16 y_hphase, uv_rgb_hphase;
> +	u16 y_vphase, uv_rgb_vphase;
> +	int hscale, vscale;
> +	u32 ps_ctrl;
> +
> +	hscale = drm_rect_calc_hscale(&plane_state->uapi.src,
> +				      &plane_state->uapi.dst,
> +				      0, INT_MAX);
> +	vscale = drm_rect_calc_vscale(&plane_state->uapi.src,
> +				      &plane_state->uapi.dst,
> +				      0, INT_MAX);
> +
> +	/* TODO: handle sub-pixel coordinates */
> +	if (intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier) &&
> +	    !icl_is_hdr_plane(dev_priv, plane->id)) {
> +		y_hphase = skl_scaler_calc_phase(1, hscale, false);
> +		y_vphase = skl_scaler_calc_phase(1, vscale, false);
> +
> +		/* MPEG2 chroma siting convention */
> +		uv_rgb_hphase = skl_scaler_calc_phase(2, hscale, true);
> +		uv_rgb_vphase = skl_scaler_calc_phase(2, vscale, false);
> +	} else {
> +		/* not used */
> +		y_hphase = 0;
> +		y_vphase = 0;
> +
> +		uv_rgb_hphase = skl_scaler_calc_phase(1, hscale, false);
> +		uv_rgb_vphase = skl_scaler_calc_phase(1, vscale, false);
> +	}
> +
> +	ps_ctrl = skl_scaler_get_filter_select(plane_state->hw.scaling_filter, 0);
> +	ps_ctrl |= PS_SCALER_EN | PS_PLANE_SEL(plane->id) | scaler->mode;
> +
> +	skl_scaler_setup_filter(dev_priv, pipe, scaler_id, 0,
> +				plane_state->hw.scaling_filter);
> +
> +	intel_de_write_fw(dev_priv, SKL_PS_CTRL(pipe, scaler_id), ps_ctrl);
> +	intel_de_write_fw(dev_priv, SKL_PS_VPHASE(pipe, scaler_id),
> +			  PS_Y_PHASE(y_vphase) | PS_UV_RGB_PHASE(uv_rgb_vphase));
> +	intel_de_write_fw(dev_priv, SKL_PS_HPHASE(pipe, scaler_id),
> +			  PS_Y_PHASE(y_hphase) | PS_UV_RGB_PHASE(uv_rgb_hphase));
> +	intel_de_write_fw(dev_priv, SKL_PS_WIN_POS(pipe, scaler_id),
> +			  (crtc_x << 16) | crtc_y);
> +	intel_de_write_fw(dev_priv, SKL_PS_WIN_SZ(pipe, scaler_id),
> +			  (crtc_w << 16) | crtc_h);
> +}
> +
> +static void skl_detach_scaler(struct intel_crtc *intel_crtc, int id)
> +{
> +	struct drm_device *dev = intel_crtc->base.dev;
> +	struct drm_i915_private *dev_priv = to_i915(dev);
> +	unsigned long irqflags;
> +
> +	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
> +
> +	intel_de_write_fw(dev_priv, SKL_PS_CTRL(intel_crtc->pipe, id), 0);
> +	intel_de_write_fw(dev_priv, SKL_PS_WIN_POS(intel_crtc->pipe, id), 0);
> +	intel_de_write_fw(dev_priv, SKL_PS_WIN_SZ(intel_crtc->pipe, id), 0);
> +
> +	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
> +}
> +
> +/*
> + * This function detaches (aka. unbinds) unused scalers in hardware
> + */
> +void skl_detach_scalers(const struct intel_crtc_state *crtc_state)
> +{
> +	struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->uapi.crtc);
> +	const struct intel_crtc_scaler_state *scaler_state =
> +		&crtc_state->scaler_state;
> +	int i;
> +
> +	/* loop through and disable scalers that aren't in use */
> +	for (i = 0; i < intel_crtc->num_scalers; i++) {
> +		if (!scaler_state->scalers[i].in_use)
> +			skl_detach_scaler(intel_crtc, i);
> +	}
> +}
> +
> +void skl_scaler_disable(const struct intel_crtc_state *old_crtc_state)
> +{
> +	struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc);
> +	int i;
> +
> +	for (i = 0; i < crtc->num_scalers; i++)
> +		skl_detach_scaler(crtc, i);
> +}
> diff --git a/drivers/gpu/drm/i915/display/skl_scaler.h b/drivers/gpu/drm/i915/display/skl_scaler.h
> new file mode 100644
> index 000000000000..0097d5d08e10
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/display/skl_scaler.h
> @@ -0,0 +1,29 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * Copyright © 2020 Intel Corporation
> + */
> +#ifndef INTEL_SCALER_H
> +#define INTEL_SCALER_H
> +
> +#include <linux/types.h>
> +
> +enum drm_scaling_filter;
> +struct drm_i915_private;
> +struct intel_crtc_state;
> +struct intel_plane_state;
> +struct intel_plane;
> +enum pipe;
> +
> +int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state);
> +
> +int skl_update_scaler_plane(struct intel_crtc_state *crtc_state,
> +			    struct intel_plane_state *plane_state);
> +
> +void skl_pfit_enable(const struct intel_crtc_state *crtc_state);
> +
> +void skl_program_plane_scaler(struct intel_plane *plane,
> +			      const struct intel_crtc_state *crtc_state,
> +			      const struct intel_plane_state *plane_state);
> +void skl_detach_scalers(const struct intel_crtc_state *crtc_state);
> +void skl_scaler_disable(const struct intel_crtc_state *old_crtc_state);
> +#endif
> diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c
> index 4ae1a2ef29ec..1f335cb09149 100644
> --- a/drivers/gpu/drm/i915/display/skl_universal_plane.c
> +++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c
> @@ -14,6 +14,7 @@
>  #include "intel_pm.h"
>  #include "intel_psr.h"
>  #include "intel_sprite.h"
> +#include "skl_scaler.h"
>  #include "skl_universal_plane.h"
>  
>  static const u32 skl_plane_formats[] = {
> @@ -1054,7 +1055,7 @@ skl_program_plane(struct intel_plane *plane,
>  			  intel_plane_ggtt_offset(plane_state) + surf_addr);
>  
>  	if (plane_state->scaler_id >= 0)
> -		skl_program_scaler(plane, crtc_state, plane_state);
> +		skl_program_plane_scaler(plane, crtc_state, plane_state);
>  
>  	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
>  }
> diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.h b/drivers/gpu/drm/i915/display/skl_universal_plane.h
> index 70eb5010cd28..818266653630 100644
> --- a/drivers/gpu/drm/i915/display/skl_universal_plane.h
> +++ b/drivers/gpu/drm/i915/display/skl_universal_plane.h
> @@ -30,4 +30,8 @@ int skl_ccs_to_main_plane(const struct drm_framebuffer *fb, int ccs_plane);
>  int skl_calc_main_surface_offset(const struct intel_plane_state *plane_state,
>  				 int *x, int *y, u32 *offset);
>  
> +bool icl_is_nv12_y_plane(struct drm_i915_private *dev_priv,
> +			 enum plane_id plane_id);
> +bool icl_is_hdr_plane(struct drm_i915_private *dev_priv, enum plane_id plane_id);
> +
>  #endif
> diff --git a/drivers/gpu/drm/i915/display/vlv_dsi.c b/drivers/gpu/drm/i915/display/vlv_dsi.c
> index f94025ec603a..1059a26c1f58 100644
> --- a/drivers/gpu/drm/i915/display/vlv_dsi.c
> +++ b/drivers/gpu/drm/i915/display/vlv_dsi.c
> @@ -38,6 +38,7 @@
>  #include "intel_fifo_underrun.h"
>  #include "intel_panel.h"
>  #include "intel_sideband.h"
> +#include "skl_scaler.h"
>  
>  /* return pixels in terms of txbyteclkhs */
>  static u16 txbyteclkhs(u16 pixels, int bpp, int lane_count,
> -- 
> 2.20.1

-- 
Ville Syrjälä
Intel
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

  reply	other threads:[~2021-02-05 15:04 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-02-05 14:48 [Intel-gfx] [PATCH v12 0/8] drm/i915: refactor intel_display.c + a bit more Jani Nikula
2021-02-05 14:48 ` [Intel-gfx] [PATCH v12 1/8] drm/i915: migrate skl planes code new file (v5) Jani Nikula
2021-02-05 15:01   ` Ville Syrjälä
2021-02-05 14:48 ` [Intel-gfx] [PATCH v12 2/8] drm/i915: move pipe update code into crtc. (v2) Jani Nikula
2021-02-05 14:48 ` [Intel-gfx] [PATCH v12 3/8] drm/i915: split fb scalable checks into g4x and skl versions Jani Nikula
2021-02-05 14:48 ` [Intel-gfx] [PATCH v12 4/8] drm/i915: move is_ccs_modifier to an inline Jani Nikula
2021-02-05 14:48 ` [Intel-gfx] [PATCH v12 5/8] drm/i915: migrate pll enable/disable code to intel_dpll.[ch] Jani Nikula
2021-02-05 14:48 ` [Intel-gfx] [PATCH v12 6/8] drm/i915: migrate i9xx plane get config Jani Nikula
2021-02-05 14:48 ` [Intel-gfx] [PATCH v12 7/8] drm/i915: refactor skylake scaler code into new file Jani Nikula
2021-02-05 15:04   ` Ville Syrjälä [this message]
2021-02-05 14:48 ` [Intel-gfx] [PATCH v12 8/8] drm/i915: move ddi pll state get to dpll mgr Jani Nikula
2021-02-05 15:09   ` Ville Syrjälä
2021-02-05 20:36     ` Ville Syrjälä
2021-02-08 10:18       ` Jani Nikula
2021-02-05 20:27 ` [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for drm/i915: refactor intel_display.c + a bit more (rev2) Patchwork
2021-02-05 20:29 ` [Intel-gfx] ✗ Fi.CI.SPARSE: " Patchwork
2021-02-05 20:58 ` [Intel-gfx] ✓ Fi.CI.BAT: success " Patchwork
2021-02-06  7:41 ` [Intel-gfx] ✓ Fi.CI.IGT: " Patchwork

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=YB1ej+Wg3wFnq1IU@intel.com \
    --to=ville.syrjala@linux.intel.com \
    --cc=airlied@redhat.com \
    --cc=intel-gfx@lists.freedesktop.org \
    --cc=jani.nikula@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.