diff mbox series

[RFC,2/2] drm/i915: Pick nearest-neighbor mode for integer scaling ratios

Message ID 20190903165227.6056-3-shashank.sharma@intel.com (mailing list archive)
State New, archived
Headers show
Series Enable Nearest-neighbor for Integer mode scaling | expand

Commit Message

Sharma, Shashank Sept. 3, 2019, 4:52 p.m. UTC
Nearest-neighbor, is a new scaling mode, introduced in GEN11 display HW.
Nearest-neighbor results in blurless outputs, when upscaling ratio is a
complete integer ratio like:

- upscaling from 1280x720(HD) to 3840x2160(UHD/4K)
  horizontal upscaling factor = 3840/1280 = 3
  vertical upscaling factor = 2160/720 = 3

This is an example of a scenario with integer scaling ratios, and if we
can pick nearest-neighbor mode scaling in display, it can produce sharp
and non-blurry output, compared to the default scaling mode selected by
I915 ("medium").

PS: NN has been introduced from GEN11 display HW only.

Cc: Jani Nikula <jani.nikula@intel.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Daniel Vetter <daniel.vetter@intel.com>
Cc: Vivi, Rodrigo <rodrigo.vivi@intel.com>
Signed-off-by: Shashank Sharma <shashank.sharma@intel.com>
---
 drivers/gpu/drm/i915/display/intel_display.c | 81 +++++++++++++++++++-
 drivers/gpu/drm/i915/i915_reg.h              | 31 ++++++++
 2 files changed, 111 insertions(+), 1 deletion(-)

Comments

Ramalingam C Sept. 4, 2019, 7:54 a.m. UTC | #1
On 2019-09-03 at 22:22:27 +0530, Shashank Sharma wrote:
> Nearest-neighbor, is a new scaling mode, introduced in GEN11 display HW.
> Nearest-neighbor results in blurless outputs, when upscaling ratio is a
> complete integer ratio like:
> 
> - upscaling from 1280x720(HD) to 3840x2160(UHD/4K)
>   horizontal upscaling factor = 3840/1280 = 3
>   vertical upscaling factor = 2160/720 = 3
> 
> This is an example of a scenario with integer scaling ratios, and if we
> can pick nearest-neighbor mode scaling in display, it can produce sharp
> and non-blurry output, compared to the default scaling mode selected by
> I915 ("medium").
> 
> PS: NN has been introduced from GEN11 display HW only.
> 
> Cc: Jani Nikula <jani.nikula@intel.com>
> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> Cc: Daniel Vetter <daniel.vetter@intel.com>
> Cc: Vivi, Rodrigo <rodrigo.vivi@intel.com>
> Signed-off-by: Shashank Sharma <shashank.sharma@intel.com>
> ---
>  drivers/gpu/drm/i915/display/intel_display.c | 81 +++++++++++++++++++-
>  drivers/gpu/drm/i915/i915_reg.h              | 31 ++++++++
>  2 files changed, 111 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
> index 613130db3c05..9808797a92d9 100644
> --- a/drivers/gpu/drm/i915/display/intel_display.c
> +++ b/drivers/gpu/drm/i915/display/intel_display.c
> @@ -5613,6 +5613,74 @@ static void skylake_scaler_disable(struct intel_crtc *crtc)
>  		skl_detach_scaler(crtc, i);
>  }
>  
> +static void
> +icl_setup_nearest_neighbor_mode(const struct intel_crtc_state *crtc_state)
> +{
> +	int count;
> +	int phase;
> +	struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
> +	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
> +	int scaler_id = crtc_state->scaler_state.scaler_id;
> +	enum pipe pipe = crtc->pipe;
> +
> +	/*
> +	 * To setup nearest-neighbor integer scaling mode:
> +	 * Write 60 dwords: represnting 119 coefficients.
> +	 *
> +	 * Seven basic Coefficients are named from An......Gn.
> +	 * Value of every D'th coefficent must be 1, all others to be 0.
> +	 *
> +	 * 17 such phases of 7 such coefficients = 119 coefficients.
> +	 * Arrange these 119 coefficients in 60 dwords, 2 coefficient
> +	 * per dword, in the sequence shown below:
> +	 *
> +	 *+------------+--------------+
> +	 *|     B0     |      A0      |
> +	 *+---------------------------+
> +	 *|    D0 = 1  |      C0      |
> +	 *+---------------------------+
> +	 *|     F0     |      E0      |
> +	 *+---------------------------+
> +	 *|     A1     |      G0      |
> +	 *+---------------------------+
> +	 *|     C1     |      B1      |
> +	 *+---------------------------+
> +	 *|     E1     |      D1 = 1  |
> +	 *+---------------------------+
> +	 *|    .....   |     .....    |
> +	 *+---------------------------+
> +	 *|    ......  |     ......   |
> +	 *+---------------------------+
> +	 *|    Res     |      G16     |
> +	 *+------------+--------------+
> +	 *
> +	 */
> +
> +	for (phase = 0; phase < 17; phase++) {
> +		for (count = 0; count < 7; count++) {
> +			u32 val = 0;
> +
> +			/* Every D'th entry needs to be 1 */
> +			if (count == 3) {
> +				if (phase % 2)
> +					val = 1;
> +				else
> +					val = (1 << 16);
> +			}
> +
> +			I915_WRITE_FW(SKL_PS_COEF_INDEX_SET0(pipe, scaler_id),
> +				      phase * 17 + count);
> +			I915_WRITE_FW(SKL_PS_COEF_DATA_SET0(pipe, scaler_id),
> +				      val);
> +
> +			I915_WRITE_FW(SKL_PS_COEF_INDEX_SET1(pipe, scaler_id),
> +				      phase * 17 + count);
> +			I915_WRITE_FW(SKL_PS_COEF_DATA_SET1(pipe, scaler_id),
> +				      val);
Shouldn't we take the 16 MSBites of val here? Am I missing something in
macro! 

-Ram
> +		}
> +	}
> +}
> +
>  static void skylake_pfit_enable(const struct intel_crtc_state *crtc_state)
>  {
>  	struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
> @@ -5623,6 +5691,7 @@ static void skylake_pfit_enable(const struct intel_crtc_state *crtc_state)
>  
>  	if (crtc_state->pch_pfit.enabled) {
>  		u16 uv_rgb_hphase, uv_rgb_vphase;
> +		u32 scaler_mode = PS_FILTER_MEDIUM;
>  		int pfit_w, pfit_h, hscale, vscale;
>  		int id;
>  
> @@ -5638,9 +5707,19 @@ static void skylake_pfit_enable(const struct intel_crtc_state *crtc_state)
>  		uv_rgb_hphase = skl_scaler_calc_phase(1, hscale, false);
>  		uv_rgb_vphase = skl_scaler_calc_phase(1, vscale, false);
>  
> +		/*
> +		 * Pick nearest-neighbor scaler mode over medium, if scaling
> +		 * is happening at integer ratios.
> +		 */
> +		if (INTEL_GEN(dev_priv) >= 11 &&
> +		    scaler_state->integer_scaling) {
> +			scaler_mode = PS_FILTER_PROGRAMMED;
> +			icl_setup_nearest_neighbor_mode(crtc_state);
> +		}
> +
>  		id = scaler_state->scaler_id;
>  		I915_WRITE(SKL_PS_CTRL(pipe, id), PS_SCALER_EN |
> -			PS_FILTER_MEDIUM | scaler_state->scalers[id].mode);
> +			scaler_mode | scaler_state->scalers[id].mode);
>  		I915_WRITE_FW(SKL_PS_VPHASE(pipe, id),
>  			      PS_Y_PHASE(0) | PS_UV_RGB_PHASE(uv_rgb_vphase));
>  		I915_WRITE_FW(SKL_PS_HPHASE(pipe, id),
> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> index ea2f0fa2402d..42fdff3bbf29 100644
> --- a/drivers/gpu/drm/i915/i915_reg.h
> +++ b/drivers/gpu/drm/i915/i915_reg.h
> @@ -7062,6 +7062,7 @@ enum {
>  #define PS_PLANE_SEL(plane) (((plane) + 1) << 25)
>  #define PS_FILTER_MASK         (3 << 23)
>  #define PS_FILTER_MEDIUM       (0 << 23)
> +#define PS_FILTER_PROGRAMMED   (1 << 23)
>  #define PS_FILTER_EDGE_ENHANCE (2 << 23)
>  #define PS_FILTER_BILINEAR     (3 << 23)
>  #define PS_VERT3TAP            (1 << 21)
> @@ -7138,6 +7139,24 @@ enum {
>  #define _PS_ECC_STAT_2B     0x68AD0
>  #define _PS_ECC_STAT_1C     0x691D0
>  
> +#define _PS_COEF_SET0_INDEX_1A     0x68198
> +#define _PS_COEF_SET0_INDEX_2A     0x68298
> +#define _PS_COEF_SET0_INDEX_1B     0x68998
> +#define _PS_COEF_SET0_INDEX_2B     0x68A98
> +#define _PS_COEF_SET1_INDEX_1A     0x681A0
> +#define _PS_COEF_SET1_INDEX_2A     0x682A0
> +#define _PS_COEF_SET1_INDEX_1B     0x689A0
> +#define _PS_COEF_SET1_INDEX_2B     0x68AA0
> +
> +#define _PS_COEF_SET0_DATA_1A     0x6819C
> +#define _PS_COEF_SET0_DATA_2A     0x6829C
> +#define _PS_COEF_SET0_DATA_1B     0x6899C
> +#define _PS_COEF_SET0_DATA_2B     0x68A9C
> +#define _PS_COEF_SET1_DATA_1A     0x681A4
> +#define _PS_COEF_SET1_DATA_2A     0x682A4
> +#define _PS_COEF_SET1_DATA_1B     0x689A4
> +#define _PS_COEF_SET1_DATA_2B     0x68AA4
> +
>  #define _ID(id, a, b) _PICK_EVEN(id, a, b)
>  #define SKL_PS_CTRL(pipe, id) _MMIO_PIPE(pipe,        \
>  			_ID(id, _PS_1A_CTRL, _PS_2A_CTRL),       \
> @@ -7166,6 +7185,18 @@ enum {
>  #define SKL_PS_ECC_STAT(pipe, id)  _MMIO_PIPE(pipe,     \
>  			_ID(id, _PS_ECC_STAT_1A, _PS_ECC_STAT_2A),   \
>  			_ID(id, _PS_ECC_STAT_1B, _PS_ECC_STAT_2B))
> +#define SKL_PS_COEF_DATA_SET0(pipe, id)  _MMIO_PIPE(pipe,     \
> +			_ID(id, _PS_COEF_SET0_DATA_1A, _PS_COEF_SET0_DATA_2A), \
> +			_ID(id, _PS_COEF_SET0_DATA_1B, _PS_COEF_SET0_DATA_1B))
> +#define SKL_PS_COEF_DATA_SET1(pipe, id)  _MMIO_PIPE(pipe,     \
> +			_ID(id, _PS_COEF_SET1_DATA_1A, _PS_COEF_SET1_DATA_2A), \
> +			_ID(id, _PS_COEF_SET1_DATA_1B, _PS_COEF_SET1_DATA_1B))
> +#define SKL_PS_COEF_INDEX_SET0(pipe, id)  _MMIO_PIPE(pipe,     \
> +			_ID(id, _PS_COEF_SET0_INDEX_1A, _PS_COEF_SET0_INDEX_2A), \
> +			_ID(id, _PS_COEF_SET0_INDEX_1B, _PS_COEF_SET0_INDEX_1B))
> +#define SKL_PS_COEF_INDEX_SET1(pipe, id)  _MMIO_PIPE(pipe,     \
> +			_ID(id, _PS_COEF_SET1_INDEX_1A, _PS_COEF_SET1_INDEX_2A), \
> +			_ID(id, _PS_COEF_SET1_INDEX_1B, _PS_COEF_SET1_INDEX_1B))
>  
>  /* legacy palette */
>  #define _LGC_PALETTE_A           0x4a000
> -- 
> 2.17.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
diff mbox series

Patch

diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
index 613130db3c05..9808797a92d9 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -5613,6 +5613,74 @@  static void skylake_scaler_disable(struct intel_crtc *crtc)
 		skl_detach_scaler(crtc, i);
 }
 
+static void
+icl_setup_nearest_neighbor_mode(const struct intel_crtc_state *crtc_state)
+{
+	int count;
+	int phase;
+	struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+	int scaler_id = crtc_state->scaler_state.scaler_id;
+	enum pipe pipe = crtc->pipe;
+
+	/*
+	 * To setup nearest-neighbor integer scaling mode:
+	 * Write 60 dwords: represnting 119 coefficients.
+	 *
+	 * Seven basic Coefficients are named from An......Gn.
+	 * Value of every D'th coefficent must be 1, all others to be 0.
+	 *
+	 * 17 such phases of 7 such coefficients = 119 coefficients.
+	 * Arrange these 119 coefficients in 60 dwords, 2 coefficient
+	 * per dword, in the sequence shown below:
+	 *
+	 *+------------+--------------+
+	 *|     B0     |      A0      |
+	 *+---------------------------+
+	 *|    D0 = 1  |      C0      |
+	 *+---------------------------+
+	 *|     F0     |      E0      |
+	 *+---------------------------+
+	 *|     A1     |      G0      |
+	 *+---------------------------+
+	 *|     C1     |      B1      |
+	 *+---------------------------+
+	 *|     E1     |      D1 = 1  |
+	 *+---------------------------+
+	 *|    .....   |     .....    |
+	 *+---------------------------+
+	 *|    ......  |     ......   |
+	 *+---------------------------+
+	 *|    Res     |      G16     |
+	 *+------------+--------------+
+	 *
+	 */
+
+	for (phase = 0; phase < 17; phase++) {
+		for (count = 0; count < 7; count++) {
+			u32 val = 0;
+
+			/* Every D'th entry needs to be 1 */
+			if (count == 3) {
+				if (phase % 2)
+					val = 1;
+				else
+					val = (1 << 16);
+			}
+
+			I915_WRITE_FW(SKL_PS_COEF_INDEX_SET0(pipe, scaler_id),
+				      phase * 17 + count);
+			I915_WRITE_FW(SKL_PS_COEF_DATA_SET0(pipe, scaler_id),
+				      val);
+
+			I915_WRITE_FW(SKL_PS_COEF_INDEX_SET1(pipe, scaler_id),
+				      phase * 17 + count);
+			I915_WRITE_FW(SKL_PS_COEF_DATA_SET1(pipe, scaler_id),
+				      val);
+		}
+	}
+}
+
 static void skylake_pfit_enable(const struct intel_crtc_state *crtc_state)
 {
 	struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
@@ -5623,6 +5691,7 @@  static void skylake_pfit_enable(const struct intel_crtc_state *crtc_state)
 
 	if (crtc_state->pch_pfit.enabled) {
 		u16 uv_rgb_hphase, uv_rgb_vphase;
+		u32 scaler_mode = PS_FILTER_MEDIUM;
 		int pfit_w, pfit_h, hscale, vscale;
 		int id;
 
@@ -5638,9 +5707,19 @@  static void skylake_pfit_enable(const struct intel_crtc_state *crtc_state)
 		uv_rgb_hphase = skl_scaler_calc_phase(1, hscale, false);
 		uv_rgb_vphase = skl_scaler_calc_phase(1, vscale, false);
 
+		/*
+		 * Pick nearest-neighbor scaler mode over medium, if scaling
+		 * is happening at integer ratios.
+		 */
+		if (INTEL_GEN(dev_priv) >= 11 &&
+		    scaler_state->integer_scaling) {
+			scaler_mode = PS_FILTER_PROGRAMMED;
+			icl_setup_nearest_neighbor_mode(crtc_state);
+		}
+
 		id = scaler_state->scaler_id;
 		I915_WRITE(SKL_PS_CTRL(pipe, id), PS_SCALER_EN |
-			PS_FILTER_MEDIUM | scaler_state->scalers[id].mode);
+			scaler_mode | scaler_state->scalers[id].mode);
 		I915_WRITE_FW(SKL_PS_VPHASE(pipe, id),
 			      PS_Y_PHASE(0) | PS_UV_RGB_PHASE(uv_rgb_vphase));
 		I915_WRITE_FW(SKL_PS_HPHASE(pipe, id),
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index ea2f0fa2402d..42fdff3bbf29 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -7062,6 +7062,7 @@  enum {
 #define PS_PLANE_SEL(plane) (((plane) + 1) << 25)
 #define PS_FILTER_MASK         (3 << 23)
 #define PS_FILTER_MEDIUM       (0 << 23)
+#define PS_FILTER_PROGRAMMED   (1 << 23)
 #define PS_FILTER_EDGE_ENHANCE (2 << 23)
 #define PS_FILTER_BILINEAR     (3 << 23)
 #define PS_VERT3TAP            (1 << 21)
@@ -7138,6 +7139,24 @@  enum {
 #define _PS_ECC_STAT_2B     0x68AD0
 #define _PS_ECC_STAT_1C     0x691D0
 
+#define _PS_COEF_SET0_INDEX_1A     0x68198
+#define _PS_COEF_SET0_INDEX_2A     0x68298
+#define _PS_COEF_SET0_INDEX_1B     0x68998
+#define _PS_COEF_SET0_INDEX_2B     0x68A98
+#define _PS_COEF_SET1_INDEX_1A     0x681A0
+#define _PS_COEF_SET1_INDEX_2A     0x682A0
+#define _PS_COEF_SET1_INDEX_1B     0x689A0
+#define _PS_COEF_SET1_INDEX_2B     0x68AA0
+
+#define _PS_COEF_SET0_DATA_1A     0x6819C
+#define _PS_COEF_SET0_DATA_2A     0x6829C
+#define _PS_COEF_SET0_DATA_1B     0x6899C
+#define _PS_COEF_SET0_DATA_2B     0x68A9C
+#define _PS_COEF_SET1_DATA_1A     0x681A4
+#define _PS_COEF_SET1_DATA_2A     0x682A4
+#define _PS_COEF_SET1_DATA_1B     0x689A4
+#define _PS_COEF_SET1_DATA_2B     0x68AA4
+
 #define _ID(id, a, b) _PICK_EVEN(id, a, b)
 #define SKL_PS_CTRL(pipe, id) _MMIO_PIPE(pipe,        \
 			_ID(id, _PS_1A_CTRL, _PS_2A_CTRL),       \
@@ -7166,6 +7185,18 @@  enum {
 #define SKL_PS_ECC_STAT(pipe, id)  _MMIO_PIPE(pipe,     \
 			_ID(id, _PS_ECC_STAT_1A, _PS_ECC_STAT_2A),   \
 			_ID(id, _PS_ECC_STAT_1B, _PS_ECC_STAT_2B))
+#define SKL_PS_COEF_DATA_SET0(pipe, id)  _MMIO_PIPE(pipe,     \
+			_ID(id, _PS_COEF_SET0_DATA_1A, _PS_COEF_SET0_DATA_2A), \
+			_ID(id, _PS_COEF_SET0_DATA_1B, _PS_COEF_SET0_DATA_1B))
+#define SKL_PS_COEF_DATA_SET1(pipe, id)  _MMIO_PIPE(pipe,     \
+			_ID(id, _PS_COEF_SET1_DATA_1A, _PS_COEF_SET1_DATA_2A), \
+			_ID(id, _PS_COEF_SET1_DATA_1B, _PS_COEF_SET1_DATA_1B))
+#define SKL_PS_COEF_INDEX_SET0(pipe, id)  _MMIO_PIPE(pipe,     \
+			_ID(id, _PS_COEF_SET0_INDEX_1A, _PS_COEF_SET0_INDEX_2A), \
+			_ID(id, _PS_COEF_SET0_INDEX_1B, _PS_COEF_SET0_INDEX_1B))
+#define SKL_PS_COEF_INDEX_SET1(pipe, id)  _MMIO_PIPE(pipe,     \
+			_ID(id, _PS_COEF_SET1_INDEX_1A, _PS_COEF_SET1_INDEX_2A), \
+			_ID(id, _PS_COEF_SET1_INDEX_1B, _PS_COEF_SET1_INDEX_1B))
 
 /* legacy palette */
 #define _LGC_PALETTE_A           0x4a000