All of lore.kernel.org
 help / color / mirror / Atom feed
From: akash.goel@intel.com
To: intel-gfx@lists.freedesktop.org
Cc: Akash Goel <akash.goel@intel.com>
Subject: [PATCH v4 3/3] drm/i915: New drm crtc property for varying the size of borders
Date: Wed, 26 Mar 2014 09:25:12 +0530	[thread overview]
Message-ID: <1395806112-21713-1-git-send-email-akash.goel@intel.com> (raw)
In-Reply-To: <1395564976-19870-1-git-send-email-akash.goel@intel.com>

From: Akash Goel <akash.goel@intel.com>

This patch adds a new drm crtc property for varying the size of
the horizontal & vertical borers of the output/display window.
This will control the output of Panel fitter.

v2: Added a new check for the invalid border size input

v3: Fixed bugs in output window calculation
Removed superfluous checks

v4: Added the capability to forecfully enable the Panel fitter.
The property value is of 64 bits, first 32 bits are used for
border dimensions. The 33rd bit can be used to forcefully
enable the panel fitter. This is useful for Panels which
do not override the User specified Pipe timings.

Testcase: igt/kms_panel_fitter_test

Signed-off-by: Akash Goel <akash.goel@intel.com>
---
 drivers/gpu/drm/i915/i915_drv.h      |   7 ++
 drivers/gpu/drm/i915/intel_display.c |  39 +++++++-
 drivers/gpu/drm/i915/intel_drv.h     |   5 +
 drivers/gpu/drm/i915/intel_panel.c   | 176 ++++++++++++++++++++++++++++++++---
 4 files changed, 211 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 6f3af15..eec32ed 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1614,6 +1614,13 @@ typedef struct drm_i915_private {
 	 */
 	struct drm_property *input_size_property;
 
+	/*
+	 * Property to dynamically vary the size of the
+	 * borders. This will indirectly control the size
+	 * of the display window i.e Panel fitter output
+	 */
+	struct drm_property *output_border_property;
+
 	uint32_t hw_context_size;
 	struct list_head context_list;
 
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 7149123..a217f25 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -10447,7 +10447,23 @@ static int intel_crtc_set_property(struct drm_crtc *crtc,
 	struct drm_device *dev = crtc->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	int ret = -ENOENT;
+
+	if (property == dev_priv->output_border_property) {
+		if ((val == (uint64_t)intel_crtc->border_size) &&
+		    (((val >> 32) & 0x1) == intel_crtc->pfit_enabled))
+			return 0;
+
+		intel_crtc->border_size = (uint32_t)val;
+		intel_crtc->pfit_enabled = (val >> 32) & 0x1;
+		if ((intel_crtc->border_size != 0) &&
+		    (!intel_crtc->pfit_enabled)) {
+			DRM_ERROR("Wrong setting, expect Pfit to be enabled when "
+				  "applying borders\n");
+			return -EINVAL;
+		}
+
+		goto done;
+	}
 
 	if (property == dev_priv->input_size_property) {
 		int new_width = (int)((val >> 16) & 0xffff);
@@ -10488,7 +10504,13 @@ static int intel_crtc_set_property(struct drm_crtc *crtc,
 		return 0;
 	}
 
-	return ret;
+	return -EINVAL;
+
+done:
+	if (crtc)
+		intel_crtc_restore_mode(crtc);
+
+	return 0;
 }
 
 static const struct drm_crtc_funcs intel_crtc_funcs = {
@@ -10641,12 +10663,23 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
 
 	if (!dev_priv->input_size_property)
 		dev_priv->input_size_property =
-			drm_property_create_range(dev, 0, "input size", 0, 0xFFFFFFFF);
+			drm_property_create_range(dev, 0, "input size",
+						0, 0xFFFFFFFF);
 
 	if (dev_priv->input_size_property)
 		drm_object_attach_property(&intel_crtc->base.base,
 					   dev_priv->input_size_property,
 					   0);
+
+	if (!dev_priv->output_border_property)
+		dev_priv->output_border_property =
+			drm_property_create_range(dev, 0, "border size",
+						0, (uint64_t)0x1FFFFFFFF);
+
+	if (dev_priv->output_border_property)
+		drm_object_attach_property(&intel_crtc->base.base,
+					   dev_priv->output_border_property,
+					   0);
 }
 
 enum pipe intel_get_pipe_from_connector(struct intel_connector *connector)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 5360d16..3cfc9da 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -387,6 +387,11 @@ struct intel_crtc {
 	bool cpu_fifo_underrun_disabled;
 	bool pch_fifo_underrun_disabled;
 
+	/* for forceful enabling of panel fitter */
+	bool pfit_enabled;
+	/* border info for the output/display window */
+	uint32_t border_size;
+
 	/* per-pipe watermark state */
 	struct {
 		/* watermarks currently being used  */
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
index cb05840..86a486e 100644
--- a/drivers/gpu/drm/i915/intel_panel.c
+++ b/drivers/gpu/drm/i915/intel_panel.c
@@ -29,10 +29,25 @@
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+/* Max Downscale ratio of 1.125, expressed in 1.12 fixed point format */
+#define MAX_DOWNSCALE_RATIO  (0x9 << 9)
 
 #include <linux/moduleparam.h>
 #include "intel_drv.h"
 
+static inline u32 panel_fitter_scaling(u32 source, u32 target)
+{
+	/*
+	 * Floating point operation is not supported. So the FACTOR
+	 * is defined, which can avoid the floating point computation
+	 * when calculating the panel ratio.
+	 */
+#define ACCURACY 12
+#define FACTOR (1 << ACCURACY)
+	u32 ratio = source * FACTOR / target;
+	return (FACTOR * ratio + FACTOR/2) / FACTOR;
+}
+
 void
 intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode,
 		       struct drm_display_mode *adjusted_mode)
@@ -42,6 +57,60 @@ intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode,
 	drm_mode_set_crtcinfo(adjusted_mode, 0);
 }
 
+void
+intel_pch_manual_panel_fitting(struct intel_crtc *intel_crtc,
+			struct intel_crtc_config *pipe_config)
+{
+	struct drm_display_mode *adjusted_mode;
+	int x, y;
+	u32 pf_horizontal_ratio, pf_vertical_ratio;
+	u32 tot_width, tot_height;
+	u32 src_width, src_height; /* pipesrc.x, pipesrc.y */
+	u32 dst_width, dst_height;
+
+	adjusted_mode = &pipe_config->adjusted_mode;
+
+	src_width = pipe_config->pipe_src_w;
+	src_height = pipe_config->pipe_src_h;
+
+	tot_width  = adjusted_mode->hdisplay;
+	tot_height = adjusted_mode->vdisplay;
+
+	/*
+	 * Having non zero borders will reduce the size of 'HACTIVE/VACTIVE'
+	 * region. So (HACTIVE - Left border - Right Border) *
+	 * (VACTIVE  - Top Border  - Bottom border) will effectively be the
+	 * output rectangle on screen
+	 */
+	dst_width = tot_width -
+			(((intel_crtc->border_size >> 16) & 0xffff) * 2);
+	dst_height = tot_height -
+			((intel_crtc->border_size & 0xffff) * 2);
+
+	if ((dst_width == 0) || (dst_height == 0)) {
+		DRM_ERROR("Invalid border size input\n");
+		return;
+	}
+
+	pf_horizontal_ratio = panel_fitter_scaling(src_width, dst_width);
+	pf_vertical_ratio   = panel_fitter_scaling(src_height, dst_height);
+
+	if (pf_horizontal_ratio > MAX_DOWNSCALE_RATIO) {
+		DRM_ERROR("width is too small\n");
+		return;
+	} else if (pf_vertical_ratio > MAX_DOWNSCALE_RATIO) {
+		DRM_ERROR("height is too small\n");
+		return;
+	}
+
+	x = (adjusted_mode->hdisplay - dst_width + 1)/2;
+	y = (adjusted_mode->vdisplay - dst_height + 1)/2;
+
+	pipe_config->pch_pfit.pos = (x << 16) | y;
+	pipe_config->pch_pfit.size = (dst_width << 16) | dst_height;
+	pipe_config->pch_pfit.enabled = pipe_config->pch_pfit.size != 0;
+}
+
 /* adjusted_mode has been preset to be the panel's fixed mode */
 void
 intel_pch_panel_fitting(struct intel_crtc *intel_crtc,
@@ -55,6 +124,13 @@ intel_pch_panel_fitting(struct intel_crtc *intel_crtc,
 
 	x = y = width = height = 0;
 
+	/* check if User wants to apply the borders, or wants to forcefully
+	   enable the panel fitter, otherwise fall through the regular path */
+	if (intel_crtc->pfit_enabled ||
+			intel_crtc->border_size)
+		return intel_pch_manual_panel_fitting(intel_crtc,
+						      pipe_config);
+
 	/* Native modes don't need fitting */
 	if (adjusted_mode->hdisplay == pipe_config->pipe_src_w &&
 	    adjusted_mode->vdisplay == pipe_config->pipe_src_h)
@@ -157,19 +233,6 @@ centre_vertically(struct drm_display_mode *mode,
 	mode->crtc_vsync_end = mode->crtc_vsync_start + sync_width;
 }
 
-static inline u32 panel_fitter_scaling(u32 source, u32 target)
-{
-	/*
-	 * Floating point operation is not supported. So the FACTOR
-	 * is defined, which can avoid the floating point computation
-	 * when calculating the panel ratio.
-	 */
-#define ACCURACY 12
-#define FACTOR (1 << ACCURACY)
-	u32 ratio = source * FACTOR / target;
-	return (FACTOR * ratio + FACTOR/2) / FACTOR;
-}
-
 static void i965_scale_aspect(struct intel_crtc_config *pipe_config,
 			      u32 *pfit_control)
 {
@@ -247,6 +310,86 @@ static void i9xx_scale_aspect(struct intel_crtc_config *pipe_config,
 	}
 }
 
+void intel_gmch_manual_panel_fitting(struct intel_crtc *intel_crtc,
+				     struct intel_crtc_config *pipe_config)
+{
+	struct drm_device *dev = intel_crtc->base.dev;
+	u32 pfit_control = 0, border = 0;
+	u32 pf_horizontal_ratio, pf_vertical_ratio;
+	struct drm_display_mode *adjusted_mode;
+	u32 tot_width, tot_height;
+	u32 src_width, src_height; /* pipesrc.x, pipesrc.y */
+	u32 dst_width, dst_height;
+
+	adjusted_mode = &pipe_config->adjusted_mode;
+
+	src_width = pipe_config->pipe_src_w;
+	src_height = pipe_config->pipe_src_h;
+
+	tot_width = adjusted_mode->hdisplay;
+	tot_height = adjusted_mode->vdisplay;
+
+	/*
+	 * Having non zero borders will reduce the size of 'HACTIVE/VACTIVE'
+	 * region. So (HACTIVE - Left border - Right Border) *
+	 * (VACTIVE  - Top Border  - Bottom border) will effectively be the
+	 * output rectangle on screen
+	 */
+	dst_width = tot_width -
+			(((intel_crtc->border_size >> 16) & 0xffff) * 2);
+	dst_height = tot_height -
+			((intel_crtc->border_size & 0xffff) * 2);
+
+	if ((dst_width == 0) || (dst_height == 0)) {
+		DRM_ERROR("Invalid border size input\n");
+		return;
+	}
+
+	pf_horizontal_ratio = panel_fitter_scaling(src_width, dst_width);
+	pf_vertical_ratio   = panel_fitter_scaling(src_height, dst_height);
+
+	if (pf_horizontal_ratio > MAX_DOWNSCALE_RATIO) {
+		DRM_ERROR("width is too small\n");
+		return;
+	} else if (pf_vertical_ratio > MAX_DOWNSCALE_RATIO) {
+		DRM_ERROR("height is too small\n");
+		return;
+	}
+
+	if (dst_width != tot_width)
+		centre_horizontally(adjusted_mode, dst_width);
+	if (dst_height != tot_height)
+		centre_vertically(adjusted_mode, dst_height);
+
+	/* No scaling needed now, but still enable the panel fitter,
+	   as that will allow the User to subequently do the dynamic
+	   flipping of fbs of different resolutions */
+	if (adjusted_mode->crtc_hdisplay == pipe_config->pipe_src_w &&
+	    adjusted_mode->crtc_vdisplay == pipe_config->pipe_src_h) {
+		BUG_ON(!intel_crtc->pfit_enabled);
+		DRM_DEBUG_KMS("Forcefully enabling the Panel fitter\n");
+	}
+
+	border = LVDS_BORDER_ENABLE;
+
+	if (INTEL_INFO(dev)->gen >= 4) {
+		/* PFIT_SCALING_PROGRAMMED is de-featured on BYT */
+		pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO;
+		pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) | PFIT_FILTER_FUZZY);
+	} else {
+		pfit_control |= (PFIT_ENABLE |
+				 VERT_AUTO_SCALE | HORIZ_AUTO_SCALE |
+				 VERT_INTERP_BILINEAR | HORIZ_INTERP_BILINEAR);
+	}
+
+	/* Make sure pre-965 set dither correctly for 18bpp panels. */
+	if (INTEL_INFO(dev)->gen < 4 && pipe_config->pipe_bpp == 18)
+		pfit_control |= PANEL_8TO6_DITHER_ENABLE;
+
+	pipe_config->gmch_pfit.control = pfit_control;
+	pipe_config->gmch_pfit.lvds_border_bits = border;
+}
+
 void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc,
 			      struct intel_crtc_config *pipe_config,
 			      int fitting_mode)
@@ -257,6 +400,13 @@ void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc,
 
 	adjusted_mode = &pipe_config->adjusted_mode;
 
+	/* check if User wants to apply the borders, or wants to forcefully
+	   enable the panel fitter, otherwise fall through the regular path */
+	if (intel_crtc->pfit_enabled ||
+			intel_crtc->border_size)
+		return intel_gmch_manual_panel_fitting(intel_crtc,
+						       pipe_config);
+
 	/* Native modes don't need fitting */
 	if (adjusted_mode->hdisplay == pipe_config->pipe_src_w &&
 	    adjusted_mode->vdisplay == pipe_config->pipe_src_h)
-- 
1.8.5.2

  reply	other threads:[~2014-03-26  3:52 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-03-10  5:10 [PATCH 0/3] Two new drm crtc properties akash.goel
2014-03-10  5:10 ` [PATCH 1/3] drm/i915: Initialized 'set_property' fn pointer field of intel_crtc_funcs structure akash.goel
2014-03-10  5:10 ` [PATCH 2/3] drm/i915: New drm crtc property for varying the Pipe Src size akash.goel
2014-03-10  5:10 ` [PATCH 3/3] drm/i915: New drm crtc property for varying the size of borders akash.goel
2014-03-10  5:14 ` [PATCH 0/3] Two new drm crtc properties Daniel Vetter
2014-03-10  5:17   ` Goel, Akash
2014-03-11 12:54   ` [PATCH 1/3] drm/i915: Initialized 'set_property' fn pointer field of intel_crtc_funcs structure akash.goel
2014-03-11 12:54     ` [PATCH v2 0/3] Two new drm crtc properties akash.goel
2014-03-21 19:15       ` Goel, Akash
2014-03-11 12:54     ` [PATCH v2 2/3] drm/i915: New drm crtc property for varying the Pipe Src size akash.goel
2014-03-11 12:54     ` [PATCH v2 3/3] drm/i915: New drm crtc property for varying the size of borders akash.goel
2014-03-23  8:56       ` [PATCH v3] " akash.goel
2014-03-26  3:55         ` akash.goel [this message]
2014-04-07  4:06           ` [PATCH v4 3/3] " Goel, Akash
2014-04-08 16:31             ` Damien Lespiau
2014-04-08 16:32               ` Damien Lespiau
2014-04-08 16:28           ` Ville Syrjälä
2014-04-10  7:43             ` Akash Goel
2014-04-10 11:34               ` Ville Syrjälä
2014-04-11  3:04                 ` Akash Goel
2014-04-11 11:42                   ` Ville Syrjälä
2014-04-13 12:28                     ` Akash Goel
2014-04-13 17:12                       ` Daniel Vetter
2014-04-20 10:49                     ` [PATCH v5 3/4] " akash.goel
2014-03-21 19:53   ` [PATCH 0/3] Two new drm crtc properties Daniel Vetter
2014-03-22  4:29     ` Goel, Akash

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=1395806112-21713-1-git-send-email-akash.goel@intel.com \
    --to=akash.goel@intel.com \
    --cc=intel-gfx@lists.freedesktop.org \
    /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.