[PATCH 6/6] drm/i915: New drm crtc property for varying the Crtc size

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

 



From: Akash Goel <akash.goel@xxxxxxxxx>

This patch adds a new drm crtc property for varying the Pipe Src size
or the Panel fitter input size. Pipe Src controls the size that is
scaled from.
This will allow to dynamically flip the frame buffers
of different resolutions.
For this Driver internally enables the Panel fitter or Hw scaler
if its a Fixed mode panel & new Pipe Src values differ from the
Pipe timings

Signed-off-by: Akash Goel <akash.goel@xxxxxxxxx>
Signed-off-by: Pallavi G<pallavi.g@xxxxxxxxx>
---
 drivers/gpu/drm/drm_crtc.c           |  7 ++++
 drivers/gpu/drm/drm_fb_helper.c      |  7 ++++
 drivers/gpu/drm/i915/intel_display.c | 72 ++++++++++++++++++++++++++++++++++++
 include/drm/drm_crtc.h               |  7 ++++
 4 files changed, 93 insertions(+)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index f09b752..328efac 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -5169,3 +5169,10 @@ struct drm_property *drm_mode_create_rotation_property(struct drm_device *dev,
 					   supported_rotations);
 }
 EXPORT_SYMBOL(drm_mode_create_rotation_property);
+
+struct drm_property *drm_mode_create_crtc_size_property(struct drm_device *dev)
+{
+	return drm_property_create_range(dev, 0, "crtc size",
+					   0, UINT_MAX);
+}
+EXPORT_SYMBOL(drm_mode_create_crtc_size_property);
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 63d7b8e..6eb1949 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -307,6 +307,13 @@ static bool restore_fbdev_mode(struct drm_fb_helper *fb_helper)
 		struct drm_crtc *crtc = mode_set->crtc;
 		int ret;
 
+		if (dev->mode_config.crtc_size_property) {
+			crtc->crtc_w = crtc->crtc_h = 0;
+			drm_object_property_set_value(&crtc->base,
+				dev->mode_config.crtc_size_property,
+				0);
+		}
+
 		if (crtc->funcs->cursor_set) {
 			ret = crtc->funcs->cursor_set(crtc, NULL, 0, 0, 0);
 			if (ret)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index a75d1a0..7c417fc 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -10183,6 +10183,12 @@ intel_modeset_pipe_config(struct drm_crtc *crtc,
 	pipe_config->pipe_src_w = pipe_config->requested_mode.crtc_hdisplay;
 	pipe_config->pipe_src_h = pipe_config->requested_mode.crtc_vdisplay;
 
+	/* Set the Pipe Src values as per the crtc size property values */
+	if (crtc->crtc_w && crtc->crtc_h) {
+		pipe_config->pipe_src_w = crtc->crtc_w;
+		pipe_config->pipe_src_h = crtc->crtc_h;
+	}
+
 encoder_retry:
 	/* Ensure the port clock defaults are reset when retrying. */
 	pipe_config->port_clock = 0;
@@ -11438,11 +11444,67 @@ out_config:
 	return ret;
 }
 
+static int intel_crtc_set_property(struct drm_crtc *crtc,
+				    struct drm_property *prop,
+				    uint64_t val)
+{
+	struct drm_device *dev = crtc->dev;
+	int ret = -ENOENT;
+
+	if (prop == dev->mode_config.crtc_size_property) {
+		int old_width, old_height;
+		int new_width = (int)((val >> 16) & 0xffff);
+		int new_height = (int)(val & 0xffff);
+		const struct drm_framebuffer *fb = crtc->primary->fb;
+
+		if ((new_width == crtc->crtc_w) &&
+		    (new_height == crtc->crtc_h))
+			return 0;
+
+		/* Check if property is resetted, so just return */
+		if ((new_width == 0) && (new_height) == 0) {
+			crtc->crtc_w = crtc->crtc_h = 0;
+			/* FIXME, Is modeset required here ?. Actually the
+			   current FB may not be compatible with the mode */
+			return 0;
+		} else if ((new_width == 0) || (new_height == 0))
+			return -EINVAL;
+
+		/* Check if the current FB is compatible with new requested
+		   Pipesrc values by the User */
+		if (new_width > fb->width ||
+			new_height > fb->height ||
+			crtc->x > fb->width - new_width ||
+			crtc->y > fb->height - new_height) {
+			DRM_DEBUG_KMS("New Pipe Src values %dx%d is incompatible with current fb size & viewport %ux%u+%d+%d\n",
+			      new_width, new_height, fb->width, fb->height, crtc->x, crtc->y);
+			return -EINVAL;
+		}
+
+		old_width = crtc->crtc_w;
+		old_height = crtc->crtc_h;
+
+		crtc->crtc_w = new_width;
+		crtc->crtc_h = new_height;
+
+		/* Currently do a modeset always, this will also
+		 * enable & configure the Panel fitter accordingly */
+		ret = intel_crtc_restore_mode(crtc);
+		if (ret) {
+			crtc->crtc_w = old_width;
+			crtc->crtc_h = old_height;
+		}
+	}
+
+	return ret;
+}
+
 static const struct drm_crtc_funcs intel_crtc_funcs = {
 	.gamma_set = intel_crtc_gamma_set,
 	.set_config = intel_crtc_set_config,
 	.destroy = intel_crtc_destroy,
 	.page_flip = intel_crtc_page_flip,
+	.set_property = intel_crtc_set_property,
 };
 
 static bool ibx_pch_dpll_get_hw_state(struct drm_i915_private *dev_priv,
@@ -11963,6 +12025,16 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
 	drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs);
 
 	WARN_ON(drm_crtc_index(&intel_crtc->base) != intel_crtc->pipe);
+
+	if (!dev->mode_config.crtc_size_property)
+			dev->mode_config.crtc_size_property =
+				drm_mode_create_crtc_size_property(dev);
+
+	if (dev->mode_config.crtc_size_property)
+			drm_object_attach_property(&intel_crtc->base.base,
+				dev->mode_config.crtc_size_property,
+				0);
+
 	return;
 
 fail:
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 0375d75..b409003 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -354,6 +354,11 @@ struct drm_crtc {
 	bool invert_dimensions;
 
 	int x, y;
+
+	/* Gets set only through the crtc_size property */
+	int crtc_w;
+	int crtc_h;
+
 	const struct drm_crtc_funcs *funcs;
 
 	/* CRTC gamma size for reporting to userspace */
@@ -826,6 +831,7 @@ struct drm_mode_config {
 	struct drm_property *path_property;
 	struct drm_property *plane_type_property;
 	struct drm_property *rotation_property;
+	struct drm_property *crtc_size_property;
 
 	/* DVI-I properties */
 	struct drm_property *dvi_i_subconnector_property;
@@ -1137,6 +1143,7 @@ extern int drm_format_vert_chroma_subsampling(uint32_t format);
 extern const char *drm_get_format_name(uint32_t format);
 extern struct drm_property *drm_mode_create_rotation_property(struct drm_device *dev,
 							      unsigned int supported_rotations);
+extern struct drm_property *drm_mode_create_crtc_size_property(struct drm_device *dev);
 extern unsigned int drm_rotation_simplify(unsigned int rotation,
 					  unsigned int supported_rotations);
 
-- 
1.9.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