Request for feedback : [RFC] Added a new 'window size' property for connector

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Ville,

Please review this patch. This is just a provisional patch. 
Here we have tried to extend the 'scaling mode' property by adding a new 'manual' mode and User will have to specify the display window (Panel fitter's output) through another property. But this may not be enough.

To support the arbitrary use of Panel fitter, as per your & Chris's suggestions, we can use the following 2 approaches. 

1. Introduce a new property (of blob type) through which a structure would be passed, which will have the Panel fitter input (PIPESRC) & output info. Using this Driver can then do a modeset internally.
     'fb_id' info will also be required to passed here, conforming to the PIPESRC. 
Or 
2. Add the border info to the display mode structure which will control the Panel fitter output. The panel fitter input (i.e. PIPESRC) will be provided through the regular 'hdisplay',  'vdisplay' fields.
     This way the PIPESRC programing & Panel fitter mode update could be done in a single modeset call.

In both the cases, we can have an additional check that if only the Panel fitter input (fb size) is getting changed & Panel fitter reprogramming is not required, then a full modeset can be avoided except the PIPESRC programming.  
This could allow to dynamically flip the frame buffers of different resolution without a modeset.

Best regards
Akash

-----Original Message-----
From: Goel, Akash 
Sent: Tuesday, March 04, 2014 3:42 PM
To: intel-gfx@xxxxxxxxxxxxxxxxxxxxx
Cc: Goel, Akash; G, Pallavi
Subject: [RFC] drm/i915 : Added a new 'window size' property for connector

From: Akash Goel <akash.goel@xxxxxxxxx>

Added a new 'window size' property for connectors.
This can be used to control the output window size of Panel fitter.
Also addd a new mode 'Manual' to existing 'scaling mode'
property.

Signed-off-by: G Pallavi <pallavi.g@xxxxxxxxx>
Signed-off-by: Akash Goel <akash.goel@xxxxxxxxx>
---
 drivers/gpu/drm/drm_crtc.c         |   1 +
 drivers/gpu/drm/i915/intel_dp.c    |  58 ++++++++++++++++++---
 drivers/gpu/drm/i915/intel_drv.h   |   8 +++
 drivers/gpu/drm/i915/intel_panel.c | 104 +++++++++++++++++++++++++++++++++++++
 include/drm/drm_crtc.h             |   3 ++
 include/uapi/drm/drm_mode.h        |   1 +
 6 files changed, 167 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 35ea15d..1d237b5 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -123,6 +123,7 @@ static const struct drm_prop_enum_list drm_scaling_mode_enum_list[] =
 	{ DRM_MODE_SCALE_FULLSCREEN, "Full" },
 	{ DRM_MODE_SCALE_CENTER, "Center" },
 	{ DRM_MODE_SCALE_ASPECT, "Full aspect" },
+	{ DRM_MODE_SCALE_MANUAL, "Manual" },
 };
 
 /*
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index c512d78..c697b7a 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -886,12 +886,22 @@ intel_dp_compute_config(struct intel_encoder *encoder,
 	if (is_edp(intel_dp) && intel_connector->panel.fixed_mode) {
 		intel_fixed_panel_mode(intel_connector->panel.fixed_mode,
 				       adjusted_mode);
-		if (!HAS_PCH_SPLIT(dev))
-			intel_gmch_panel_fitting(intel_crtc, pipe_config,
-						 intel_connector->panel.fitting_mode);
-		else
-			intel_pch_panel_fitting(intel_crtc, pipe_config,
-						intel_connector->panel.fitting_mode);
+		if (!HAS_PCH_SPLIT(dev)) {
+			if (intel_connector->panel.fitting_mode == DRM_MODE_SCALE_MANUAL)
+				intel_gmch_manual_panel_fitting(intel_crtc, pipe_config,
+							intel_connector->panel.display_window_size);
+			else
+				intel_gmch_panel_fitting(intel_crtc, pipe_config,
+							 intel_connector->panel.fitting_mode);
+		}
+		else {
+			if (intel_connector->panel.fitting_mode == DRM_MODE_SCALE_MANUAL)
+				intel_pch_manual_panel_fitting(intel_crtc, pipe_config,
+							intel_connector->panel.display_window_size);
+			else
+				intel_pch_panel_fitting(intel_crtc, pipe_config,
+						        intel_connector->panel.fitting_mode);
+		}
 	}
 
 	if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK) @@ -3376,14 +3386,36 @@ intel_dp_set_property(struct drm_connector *connector,
 		}
 
 		if (intel_connector->panel.fitting_mode == val) {
-			/* the eDP scaling property is not changed */
-			return 0;
+			/* Check if display window size has changed */
+			if ((val == DRM_MODE_SCALE_MANUAL) &&
+			     intel_connector->panel.display_window_size_changed)
+				intel_connector->panel.display_window_size_changed = 0;
+			else {
+				/* the eDP scaling property is not changed */
+				return 0;
+			}
 		}
 		intel_connector->panel.fitting_mode = val;
 
+		if (val != DRM_MODE_SCALE_MANUAL)
+			intel_connector->panel.display_window_size = 0;
+
 		goto done;
 	}
 
+	if (is_edp(intel_dp) &&
+	    property == connector->dev->mode_config.window_size_property) {
+		if (intel_connector->panel.display_window_size == val) {
+			/* the eDP panel window size property is not changed */
+			intel_connector->panel.display_window_size_changed = 0;
+			return 0;
+		}
+		intel_connector->panel.display_window_size = val;
+		intel_connector->panel.display_window_size_changed = 1;
+
+		return 0;
+	}
+
 	return -EINVAL;
 
 done:
@@ -3517,6 +3549,16 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connect
 			connector->dev->mode_config.scaling_mode_property,
 			DRM_MODE_SCALE_ASPECT);
 		intel_connector->panel.fitting_mode = DRM_MODE_SCALE_ASPECT;
+
+		connector->dev->mode_config.window_size_property =
+			drm_property_create_range(connector->dev, 0,
+						"window size", 0, 0xFFFFFFFF);
+		drm_object_attach_property(
+			&connector->base,
+			connector->dev->mode_config.window_size_property,
+			0);
+		intel_connector->panel.display_window_size = 0;
+		intel_connector->panel.display_window_size_changed = 0;
 	}
 }
 
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index a4ffc02..5247b6b 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -157,6 +157,8 @@ struct intel_panel {
 	struct drm_display_mode *fixed_mode;
 	struct drm_display_mode *downclock_mode;
 	int fitting_mode;
+	u32 display_window_size;
+	bool display_window_size_changed;
 
 	/* backlight */
 	struct {
@@ -841,9 +843,15 @@ void intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode,  void intel_pch_panel_fitting(struct intel_crtc *crtc,
 			     struct intel_crtc_config *pipe_config,
 			     int fitting_mode);
+void intel_pch_manual_panel_fitting(struct intel_crtc *intel_crtc,
+				    struct intel_crtc_config *pipe_config,
+				    u32 display_window_size);
 void intel_gmch_panel_fitting(struct intel_crtc *crtc,
 			      struct intel_crtc_config *pipe_config,
 			      int fitting_mode);
+void intel_gmch_manual_panel_fitting(struct intel_crtc *crtc,
+			      struct intel_crtc_config *pipe_config,
+			      u32 display_window_size);
 void intel_panel_set_backlight(struct intel_connector *connector, u32 level,
 			       u32 max);
 int intel_panel_setup_backlight(struct drm_connector *connector); diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
index cb05840..2965975 100644
--- a/drivers/gpu/drm/i915/intel_panel.c
+++ b/drivers/gpu/drm/i915/intel_panel.c
@@ -114,6 +114,48 @@ done:
 	pipe_config->pch_pfit.enabled = pipe_config->pch_pfit.size != 0;  }
 
+void
+intel_pch_manual_panel_fitting(struct intel_crtc *intel_crtc,
+			struct intel_crtc_config *pipe_config,
+			u32 display_window_size)
+{
+	struct drm_display_mode *adjusted_mode;
+	int x, y;
+	u32 tot_width, tot_height;
+	u32 dst_width, dst_height;
+
+	adjusted_mode = &pipe_config->adjusted_mode;
+
+	tot_width  = adjusted_mode->crtc_hdisplay;
+	tot_height = adjusted_mode->crtc_vdisplay;
+
+	dst_width  = ((display_window_size >> 16) & 0xffff);
+	dst_height = (display_window_size & 0xffff);
+
+	x = y = 0;
+
+	if (tot_width < dst_width) {
+		DRM_ERROR("width is too big\n");
+		return;
+	} else if (dst_width & 1) {
+		DRM_ERROR("width must be even\n");
+		return;
+	} else if (tot_height < dst_height) {
+		DRM_ERROR("height is too big\n");
+		return;
+	} else if (dst_height & 1) {
+		DRM_ERROR("height must be even\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; }
+
 static void
 centre_horizontally(struct drm_display_mode *mode,
 		    int width)
@@ -323,6 +365,68 @@ out:
 	pipe_config->gmch_pfit.lvds_border_bits = border;  }
 
+void intel_gmch_manual_panel_fitting(struct intel_crtc *intel_crtc,
+				     struct intel_crtc_config *pipe_config,
+				     u32 display_window_size)
+{
+	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->crtc_hdisplay;
+	tot_height = adjusted_mode->crtc_vdisplay;
+
+	dst_width  = ((display_window_size >> 16) & 0xffff);
+	dst_height = (display_window_size & 0xffff);
+
+	pf_horizontal_ratio = panel_fitter_scaling(src_width, dst_width);
+	pf_vertical_ratio   = panel_fitter_scaling(src_height, dst_height);
+
+/* Max Downscale ratio of 1.125, expressed in 1.12 fixed point format 
+*/ #define MAX_DOWNSCALE_RATIO  (0x9 << 9)
+
+	if (pf_horizontal_ratio > MAX_DOWNSCALE_RATIO) {
+			DRM_ERROR("width is too small\n");
+			return;
+	} else if (tot_width < dst_width) {
+			DRM_ERROR("width is too big\n");
+			return;
+	} else if (dst_width & 1) {
+			DRM_ERROR("width must be even\n");
+			return;
+	} else if (pf_vertical_ratio > MAX_DOWNSCALE_RATIO) {
+			DRM_ERROR("height is too small\n");
+			return;
+	} else if (tot_height < dst_height) {
+			DRM_ERROR("height is too big\n");
+			return;
+	} else if (dst_height & 1) {
+			DRM_ERROR("height must be even\n");
+			return;
+	}
+
+	centre_horizontally(adjusted_mode, dst_width);
+	centre_vertically(adjusted_mode, dst_height);
+	border = LVDS_BORDER_ENABLE;
+
+	/* 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);
+
+	pipe_config->gmch_pfit.control = pfit_control;
+	pipe_config->gmch_pfit.lvds_border_bits = border;
+
+	return;
+}
+
 static u32 intel_panel_compute_brightness(struct intel_connector *connector,
 					  u32 val)
 {
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index f764654..625d7fd 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -902,6 +902,9 @@ struct drm_mode_config {
 	struct drm_property *scaling_mode_property;
 	struct drm_property *dirty_info_property;
 
+	/* Panel fitter output property */
+	struct drm_property *window_size_property;
+
 	/* dumb ioctl parameters */
 	uint32_t preferred_depth, prefer_shadow;
 
diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h index f104c26..a187dac 100644
--- a/include/uapi/drm/drm_mode.h
+++ b/include/uapi/drm/drm_mode.h
@@ -87,6 +87,7 @@
 #define DRM_MODE_SCALE_FULLSCREEN	1 /* Full screen, ignore aspect */
 #define DRM_MODE_SCALE_CENTER		2 /* Centered, no scaling */
 #define DRM_MODE_SCALE_ASPECT		3 /* Full screen, preserve aspect */
+#define DRM_MODE_SCALE_MANUAL		4 /* User can control display window size */
 
 /* Dithering mode options */
 #define DRM_MODE_DITHERING_OFF	0
--
1.8.5.2

_______________________________________________
Intel-gfx mailing list
Intel-gfx@xxxxxxxxxxxxxxxxxxxxx
http://lists.freedesktop.org/mailman/listinfo/intel-gfx




[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]
  Powered by Linux