All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/51] Atomic mode setting and page flip
@ 2012-10-25 18:05 ville.syrjala
  2012-10-25 18:05 ` [PATCH 01/51] drm: Be more paranoid with integer overflows ville.syrjala
                   ` (50 more replies)
  0 siblings, 51 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

Here's the latest atomic stuff. It's finally starting to look somewhat
reasonable.

I rebased the work on top of drm-fixes as of today.

There are quite a few preparatory patches in the series. Some of those are just
fixes/cleanups that could be pushed independently.

What's still unfinished:
- some integration w/ legacy code paths is missing
  (eg. for the MODE and CONNECTOR_IDS props)
- ioctl blocks until the GPU rendering has caught up. Need to make it fully async.
- I took a shortcut w/ danvet's modeset rework new vs. old state logic
- some other ugly bits are probably still left in the code, but I'm starting to get
  tunnel vision and some extra eyes on the code wouldn't hurt
- other stuff I might be forgetting...

git repos can be found on gitorious, as usual:
https://gitorious.org/vsyrjala/linux/commits/drm_atomic_15
https://gitorious.org/vsyrjala/drm/commits/drm_atomic_7

A test app of sorts can be found here:
https://gitorious.org/vsyrjala/plane/commits/buffer_tracking

I also made a modifed version of the test app that renders via GL, but I need to
clean that up a bit before I push it. Will do so tomorrow.

^ permalink raw reply	[flat|nested] 61+ messages in thread

* [PATCH 01/51] drm: Be more paranoid with integer overflows
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 02/51] drm: Constify some function arguments ville.syrjala
                   ` (49 subsequent siblings)
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Make sure 'width * cpp' and 'height * pitch + offset' don't exceed
UINT_MAX.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/drm_crtc.c |   10 +++++++++-
 1 files changed, 9 insertions(+), 1 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index ef1b221..d9a639c 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -2280,13 +2280,21 @@ static int framebuffer_check(const struct drm_mode_fb_cmd2 *r)
 
 	for (i = 0; i < num_planes; i++) {
 		unsigned int width = r->width / (i != 0 ? hsub : 1);
+		unsigned int height = r->height / (i != 0 ? vsub : 1);
+		unsigned int cpp = drm_format_plane_cpp(r->pixel_format, i);
 
 		if (!r->handles[i]) {
 			DRM_DEBUG_KMS("no buffer object handle for plane %d\n", i);
 			return -EINVAL;
 		}
 
-		if (r->pitches[i] < drm_format_plane_cpp(r->pixel_format, i) * width) {
+		if ((uint64_t) width * cpp > UINT_MAX)
+			return -ERANGE;
+
+		if ((uint64_t) height * r->pitches[i] + r->offsets[i] > UINT_MAX)
+			return -ERANGE;
+
+		if (r->pitches[i] < width * cpp) {
 			DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i);
 			return -EINVAL;
 		}
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 02/51] drm: Constify some function arguments
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
  2012-10-25 18:05 ` [PATCH 01/51] drm: Be more paranoid with integer overflows ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 03/51] drm: Ignore blob propertys in drm_property_change_is_valid() ville.syrjala
                   ` (48 subsequent siblings)
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

None of drm_mode_debug_printmodeline(), drm_mode_equal(), drm_mode_width()
or drm_mode_height() change the mode passed in, so make the arguments
const.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/drm_modes.c |    8 ++++----
 include/drm/drm_crtc.h      |    8 ++++----
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index 59450f3..d8da30e 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -46,7 +46,7 @@
  *
  * Describe @mode using DRM_DEBUG.
  */
-void drm_mode_debug_printmodeline(struct drm_display_mode *mode)
+void drm_mode_debug_printmodeline(const struct drm_display_mode *mode)
 {
 	DRM_DEBUG_KMS("Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d "
 			"0x%x 0x%x\n",
@@ -558,7 +558,7 @@ EXPORT_SYMBOL(drm_mode_list_concat);
  * RETURNS:
  * @mode->hdisplay
  */
-int drm_mode_width(struct drm_display_mode *mode)
+int drm_mode_width(const struct drm_display_mode *mode)
 {
 	return mode->hdisplay;
 
@@ -579,7 +579,7 @@ EXPORT_SYMBOL(drm_mode_width);
  * RETURNS:
  * @mode->vdisplay
  */
-int drm_mode_height(struct drm_display_mode *mode)
+int drm_mode_height(const struct drm_display_mode *mode)
 {
 	return mode->vdisplay;
 }
@@ -768,7 +768,7 @@ EXPORT_SYMBOL(drm_mode_duplicate);
  * RETURNS:
  * True if the modes are equal, false otherwise.
  */
-bool drm_mode_equal(struct drm_display_mode *mode1, struct drm_display_mode *mode2)
+bool drm_mode_equal(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2)
 {
 	/* do clock check convert to PICOS so fb modes get matched
 	 * the same */
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 3fa18b7..49dd8c2 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -887,14 +887,14 @@ extern void drm_mode_remove(struct drm_connector *connector, struct drm_display_
 extern void drm_mode_copy(struct drm_display_mode *dst, const struct drm_display_mode *src);
 extern struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev,
 						   const struct drm_display_mode *mode);
-extern void drm_mode_debug_printmodeline(struct drm_display_mode *mode);
+extern void drm_mode_debug_printmodeline(const struct drm_display_mode *mode);
 extern void drm_mode_config_init(struct drm_device *dev);
 extern void drm_mode_config_reset(struct drm_device *dev);
 extern void drm_mode_config_cleanup(struct drm_device *dev);
 extern void drm_mode_set_name(struct drm_display_mode *mode);
-extern bool drm_mode_equal(struct drm_display_mode *mode1, struct drm_display_mode *mode2);
-extern int drm_mode_width(struct drm_display_mode *mode);
-extern int drm_mode_height(struct drm_display_mode *mode);
+extern bool drm_mode_equal(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2);
+extern int drm_mode_width(const struct drm_display_mode *mode);
+extern int drm_mode_height(const struct drm_display_mode *mode);
 
 /* for us by fb module */
 extern int drm_mode_attachmode_crtc(struct drm_device *dev,
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 03/51] drm: Ignore blob propertys in drm_property_change_is_valid()
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
  2012-10-25 18:05 ` [PATCH 01/51] drm: Be more paranoid with integer overflows ville.syrjala
  2012-10-25 18:05 ` [PATCH 02/51] drm: Constify some function arguments ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 04/51] drm: Add struct drm_region and assorted utility functions ville.syrjala
                   ` (47 subsequent siblings)
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

In case of a blob property drm_property_change_is_valid() can't
tell whether the change is valid or not. So just return true
for all blob properties, and leave it up to someone else to
check it.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/drm_crtc.c |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index d9a639c..3533609 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -3212,6 +3212,9 @@ static bool drm_property_change_is_valid(struct drm_property *property,
 		for (i = 0; i < property->num_values; i++)
 			valid_mask |= (1ULL << property->values[i]);
 		return !(value & ~valid_mask);
+	} else if (property->flags & DRM_MODE_PROP_BLOB) {
+		/* Only the driver knows */
+		return true;
 	} else {
 		int i;
 		for (i = 0; i < property->num_values; i++)
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 04/51] drm: Add struct drm_region and assorted utility functions
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (2 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 03/51] drm: Ignore blob propertys in drm_property_change_is_valid() ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 05/51] drm: Add drm_calc_{hscale, vscale}() " ville.syrjala
                   ` (46 subsequent siblings)
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

struct drm_region represents a two dimensional region. The utility
functions are there to help driver writers.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/drm_crtc.c |  155 ++++++++++++++++++++++++++++++++++++++++++++
 include/drm/drm_crtc.h     |   24 +++++++
 2 files changed, 179 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 3533609..e60beda 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -3914,3 +3914,158 @@ int drm_format_vert_chroma_subsampling(uint32_t format)
 	}
 }
 EXPORT_SYMBOL(drm_format_vert_chroma_subsampling);
+
+/**
+ * drm_region_adjust_size - adjust the size of the region
+ * @r: region to be adjusted
+ * @x: horizontal adjustment
+ * @y: vertical adjustment
+ *
+ * Change the size of region @r by @x in the horizontal direction,
+ * and by @y in the vertical direction, while keeping the center
+ * of @r stationary.
+ *
+ * Positive @x and @y increase the size, negative values decrease it.
+ */
+void drm_region_adjust_size(struct drm_region *r, int x, int y)
+{
+	r->x1 -= x >> 1;
+	r->y1 -= y >> 1;
+	r->x2 += (x + 1) >> 1;
+	r->y2 += (y + 1) >> 1;
+}
+EXPORT_SYMBOL(drm_region_adjust_size);
+
+/**
+ * drm_region_translate - translate the region
+ * @r: region to be tranlated
+ * @x: horizontal translation
+ * @y: vertical translation
+ *
+ * Move region @r by @x in the horizontal direction,
+ * and by @y in the vertical direction.
+ */
+void drm_region_translate(struct drm_region *r, int x, int y)
+{
+	r->x1 += x;
+	r->y1 += y;
+	r->x2 += x;
+	r->y2 += y;
+}
+EXPORT_SYMBOL(drm_region_translate);
+
+/**
+ * drm_region_subsample - subsample a region
+ * @r: region to be subsampled
+ * @hsub: horizontal subsampling factor
+ * @vsub: vertical subsampling factor
+ *
+ * Divide the coordinates of region @r by @hsub and @vsub.
+ */
+void drm_region_subsample(struct drm_region *r, int hsub, int vsub)
+{
+	r->x1 /= hsub;
+	r->y1 /= vsub;
+	r->x2 /= hsub;
+	r->y2 /= vsub;
+}
+EXPORT_SYMBOL(drm_region_subsample);
+
+/**
+ * drm_region_width - determine the region width
+ * @r: region whose width is returned
+ *
+ * RETURNS:
+ * The width of the region.
+ */
+int drm_region_width(const struct drm_region *r)
+{
+	return r->x2 - r->x1;
+}
+EXPORT_SYMBOL(drm_region_width);
+
+/**
+ * drm_region_height - determine the region height
+ * @r: region whose height is returned
+ *
+ * RETURNS:
+ * The height of the region.
+ */
+int drm_region_height(const struct drm_region *r)
+{
+	return r->y2 - r->y1;
+}
+EXPORT_SYMBOL(drm_region_height);
+
+/**
+ * drm_region_visible - determine if the the region is visible
+ * @r: region whose visibility is returned
+ *
+ * RETURNS:
+ * @true if the region is visible, @false otherwise.
+ */
+bool drm_region_visible(const struct drm_region *r)
+{
+	return drm_region_width(r) > 0 && drm_region_height(r) > 0;
+}
+EXPORT_SYMBOL(drm_region_visible);
+
+/**
+ * drm_region_clip - clip one region by another region
+ * @r: region to be clipped
+ * @clip: clip region
+ *
+ * Clip region @r by region @clip.
+ *
+ * RETURNS:
+ * @true if the region is still visible after being clipped,
+ * @false otherwise.
+ */
+bool drm_region_clip(struct drm_region *r, const struct drm_region *clip)
+{
+	r->x1 = max(r->x1, clip->x1);
+	r->y1 = max(r->y1, clip->y1);
+	r->x2 = min(r->x2, clip->x2);
+	r->y2 = min(r->y2, clip->y2);
+
+	return drm_region_visible(r);
+}
+EXPORT_SYMBOL(drm_region_clip);
+
+/**
+ * drm_region_clip_scaled - perform a scaled clip operation
+ * @src: source window region
+ * @dst: destination window region
+ * @clip: clip region
+ * @hscale: horizontal scaling factor
+ * @vscale: vertical scaling factor
+ *
+ * Clip region @dst by region @clip. Clip region @src by the same
+ * amounts multiplied by @hscale and @vscale.
+ *
+ * RETUTRNS:
+ * @true if region @dst is still visible after being clipped,
+ * @false otherwise
+ */
+bool drm_region_clip_scaled(struct drm_region *src, struct drm_region *dst,
+			    const struct drm_region *clip,
+			    int hscale, int vscale)
+{
+	int diff;
+
+	diff = clip->x1 - dst->x1;
+	if (diff > 0)
+		src->x1 += diff * hscale;
+	diff = clip->y1 - dst->y1;
+	if (diff > 0)
+		src->y1 += diff * vscale;
+	diff = dst->x2 - clip->x2;
+	if (diff > 0)
+		src->x2 -= diff * hscale;
+	diff = dst->y2 - clip->y2;
+	if (diff > 0)
+		src->y2 -= diff * vscale;
+
+	return drm_region_clip(dst, clip);
+}
+EXPORT_SYMBOL(drm_region_clip_scaled);
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 49dd8c2..5252c11 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -1079,4 +1079,28 @@ extern int drm_format_plane_cpp(uint32_t format, int plane);
 extern int drm_format_horz_chroma_subsampling(uint32_t format);
 extern int drm_format_vert_chroma_subsampling(uint32_t format);
 
+/**
+ * drm_region - two dimensional region
+ * @x1: horizontal starting coordinate (inclusive)
+ * @x2: horizontal ending coordinate (exclusive)
+ * @y1: vertical starting coordinate (inclusive)
+ * @y2: vertical ending coordinate (exclusive)
+ */
+struct drm_region {
+	int x1, y1, x2, y2;
+};
+
+extern void drm_region_adjust_size(struct drm_region *r, int x, int y);
+extern void drm_region_translate(struct drm_region *r, int x, int y);
+extern void drm_region_subsample(struct drm_region *r, int hsub, int vsub);
+extern int drm_region_width(const struct drm_region *r);
+extern int drm_region_height(const struct drm_region *r);
+extern bool drm_region_visible(const struct drm_region *r);
+extern bool drm_region_clip(struct drm_region *r,
+			    const struct drm_region *clip);
+extern bool drm_region_clip_scaled(struct drm_region *src,
+				   struct drm_region *dst,
+				   const struct drm_region *clip,
+				   int hscale, int vscale);
+
 #endif /* __DRM_CRTC_H__ */
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 05/51] drm: Add drm_calc_{hscale, vscale}() utility functions
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (3 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 04/51] drm: Add struct drm_region and assorted utility functions ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 06/51] drm: Keep a copy of last plane coordinates ville.syrjala
                   ` (45 subsequent siblings)
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/drm_crtc.c |  102 ++++++++++++++++++++++++++++++++++++++++++++
 include/drm/drm_crtc.h     |    4 ++
 2 files changed, 106 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index e60beda..c0b064e 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -4069,3 +4069,105 @@ bool drm_region_clip_scaled(struct drm_region *src, struct drm_region *dst,
 	return drm_region_clip(dst, clip);
 }
 EXPORT_SYMBOL(drm_region_clip_scaled);
+
+/**
+ * drm_calc_hscale - calculate the horizontal scaling factor
+ * @src: source window region
+ * @dst: destination window region
+ * @min_hscale: minimum allowed horizontal scaling factor
+ * @max_hscale: maximum allowed horizontal scaling factor
+ *
+ * Calculate the horizontal scaling factor as
+ * (@src width) / (@dst width).
+ *
+ * If the calculated scaling factor is below @min_hscale,
+ * decrease the width of region @dst to compensate.
+ *
+ * If the calculcated scaling factor is above @max_hscale,
+ * decrease the width of region @src to compensate.
+ *
+ * RETURNS:
+ * The horizontal scaling factor.
+ */
+int drm_calc_hscale(struct drm_region *src, struct drm_region *dst,
+		    int min_hscale, int max_hscale)
+{
+	int src_w = drm_region_width(src);
+	int dst_w = drm_region_width(dst);
+	int hscale;
+
+	if (dst_w <= 0)
+		return 0;
+
+	hscale = src_w / dst_w;
+
+	if (hscale < min_hscale) {
+		int max_dst_w = src_w / min_hscale;
+
+		drm_region_adjust_size(dst, max_dst_w - dst_w, 0);
+
+		return min_hscale;
+	}
+
+	if (hscale > max_hscale) {
+		int max_src_w = dst_w * max_hscale;
+
+		drm_region_adjust_size(src, max_src_w - src_w, 0);
+
+		return max_hscale;
+	}
+
+	return hscale;
+}
+EXPORT_SYMBOL(drm_calc_hscale);
+
+/**
+ * drm_calc_vscale - calculate the vertical scaling factor
+ * @src: source window region
+ * @dst: destination window region
+ * @min_vscale: minimum allowed vertical scaling factor
+ * @max_vscale: maximum allowed vertical scaling factor
+ *
+ * Calculate the vertical scaling factor as
+ * (@src height) / (@dst height).
+ *
+ * If the calculated scaling factor is below @min_vscale,
+ * decrease the height of region @dst to compensate.
+ *
+ * If the calculcated scaling factor is above @max_vscale,
+ * decrease the height of region @src to compensate.
+ *
+ * RETURNS:
+ * The vertical scaling factor.
+ */
+int drm_calc_vscale(struct drm_region *src, struct drm_region *dst,
+		    int min_vscale, int max_vscale)
+{
+	int src_h = drm_region_height(src);
+	int dst_h = drm_region_height(dst);
+	int vscale;
+
+	if (dst_h <= 0)
+		return 0;
+
+	vscale = src_h / dst_h;
+
+	if (vscale < min_vscale) {
+		int max_dst_h = src_h / min_vscale;
+
+		drm_region_adjust_size(dst, 0, max_dst_h - dst_h);
+
+		return min_vscale;
+	}
+
+	if (vscale > max_vscale) {
+		int max_src_h = dst_h * max_vscale;
+
+		drm_region_adjust_size(src, 0, max_src_h - src_h);
+
+		return max_vscale;
+	}
+
+	return vscale;
+}
+EXPORT_SYMBOL(drm_calc_vscale);
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 5252c11..bc89654 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -1102,5 +1102,9 @@ extern bool drm_region_clip_scaled(struct drm_region *src,
 				   struct drm_region *dst,
 				   const struct drm_region *clip,
 				   int hscale, int vscale);
+extern int drm_calc_hscale(struct drm_region *src, struct drm_region *dst,
+			   int min_hscale, int max_hscale);
+extern int drm_calc_vscale(struct drm_region *src, struct drm_region *dst,
+			   int min_vscale, int max_vscale);
 
 #endif /* __DRM_CRTC_H__ */
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 06/51] drm: Keep a copy of last plane coordinates
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (4 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 05/51] drm: Add drm_calc_{hscale, vscale}() " ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 07/51] drm: Add restore_fbdev_mode() hook to drm_fb_helper ville.syrjala
                   ` (44 subsequent siblings)
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

If the update_plane() operation succeeds, make a copy of the requested
src and crtc coordinates, so that the the plane may be reclipped if the
display mode changed later.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/drm_crtc.c |    8 ++++++++
 include/drm/drm_crtc.h     |    4 ++++
 2 files changed, 12 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index c0b064e..d5ceff0 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -1853,6 +1853,14 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
 	if (!ret) {
 		plane->crtc = crtc;
 		plane->fb = fb;
+		plane->crtc_x = plane_req->crtc_x;
+		plane->crtc_y = plane_req->crtc_y;
+		plane->crtc_w = plane_req->crtc_w;
+		plane->crtc_h = plane_req->crtc_h;
+		plane->src_x = plane_req->src_x;
+		plane->src_y = plane_req->src_y;
+		plane->src_w = plane_req->src_w;
+		plane->src_h = plane_req->src_h;
 	}
 
 out:
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index bc89654..6a66704 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -672,6 +672,10 @@ struct drm_plane {
 	void *helper_private;
 
 	struct drm_object_properties properties;
+
+	uint32_t src_x, src_y, src_w, src_h;
+	int32_t crtc_x, crtc_y;
+	uint32_t crtc_w, crtc_h;
 };
 
 /**
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 07/51] drm: Add restore_fbdev_mode() hook to drm_fb_helper
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (5 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 06/51] drm: Keep a copy of last plane coordinates ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 08/51] drm: Export drm_property_create_blob() and drm_property_destroy_blob() ville.syrjala
                   ` (43 subsequent siblings)
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Add an optional driver specific restore_fbdev_mode() hook to
drm_fb_helper. If the driver doesn't provide the hook,
drm_fb_helper_restore_fbdev_mode() is called directly as before.

In this hook the driver can disable additional planes, cursors etc.
that shouldn't be visible while fbdev is in control.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/drm_fb_helper.c |    5 ++++-
 include/drm/drm_fb_helper.h     |    1 +
 2 files changed, 5 insertions(+), 1 deletions(-)

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 4d58d7e..082a837 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -248,7 +248,10 @@ static bool drm_fb_helper_force_kernel_mode(void)
 		if (helper->dev->switch_power_state == DRM_SWITCH_POWER_OFF)
 			continue;
 
-		ret = drm_fb_helper_restore_fbdev_mode(helper);
+		if (helper->funcs->restore_fbdev_mode)
+			ret = helper->funcs->restore_fbdev_mode(helper);
+		else
+			ret = drm_fb_helper_restore_fbdev_mode(helper);
 		if (ret)
 			error = true;
 	}
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index 5120b01..7f76e9c 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -56,6 +56,7 @@ struct drm_fb_helper_funcs {
 
 	int (*fb_probe)(struct drm_fb_helper *helper,
 			struct drm_fb_helper_surface_size *sizes);
+	int (*restore_fbdev_mode)(struct drm_fb_helper *helper);
 };
 
 struct drm_fb_helper_connector {
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 08/51] drm: Export drm_property_create_blob() and drm_property_destroy_blob()
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (6 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 07/51] drm: Add restore_fbdev_mode() hook to drm_fb_helper ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 09/51] drm: Allow signed values for range properties ville.syrjala
                   ` (42 subsequent siblings)
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/drm_crtc.c |    8 +++++---
 include/drm/drm_crtc.h     |    4 ++++
 2 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index d5ceff0..ddd7252 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -3108,8 +3108,8 @@ done:
 	return ret;
 }
 
-static struct drm_property_blob *drm_property_create_blob(struct drm_device *dev, int length,
-							  void *data)
+struct drm_property_blob *drm_property_create_blob(struct drm_device *dev, int length,
+						   void *data)
 {
 	struct drm_property_blob *blob;
 	int ret;
@@ -3134,14 +3134,16 @@ static struct drm_property_blob *drm_property_create_blob(struct drm_device *dev
 	list_add_tail(&blob->head, &dev->mode_config.property_blob_list);
 	return blob;
 }
+EXPORT_SYMBOL(drm_property_create_blob);
 
-static void drm_property_destroy_blob(struct drm_device *dev,
+void drm_property_destroy_blob(struct drm_device *dev,
 			       struct drm_property_blob *blob)
 {
 	drm_mode_object_put(dev, &blob->base);
 	list_del(&blob->head);
 	kfree(blob);
 }
+EXPORT_SYMBOL(drm_property_destroy_blob);
 
 int drm_mode_getblob_ioctl(struct drm_device *dev,
 			   void *data, struct drm_file *file_priv)
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 6a66704..8eb04c9 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -969,6 +969,10 @@ struct drm_property *drm_property_create_range(struct drm_device *dev, int flags
 					 const char *name,
 					 uint64_t min, uint64_t max);
 extern void drm_property_destroy(struct drm_device *dev, struct drm_property *property);
+extern struct drm_property_blob *drm_property_create_blob(struct drm_device *dev,
+							  int length, void *data);
+extern void drm_property_destroy_blob(struct drm_device *dev,
+				      struct drm_property_blob *blob);
 extern int drm_property_add_enum(struct drm_property *property, int index,
 				 uint64_t value, const char *name);
 extern int drm_mode_create_dvi_i_properties(struct drm_device *dev);
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 09/51] drm: Allow signed values for range properties
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (7 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 08/51] drm: Export drm_property_create_blob() and drm_property_destroy_blob() ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 10/51] drm: Allow drm_mode_object_find() to look up an object of any type ville.syrjala
                   ` (41 subsequent siblings)
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Treat a range property as signed when the unsigned minimum value is
larger than the unsigned maximum value.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/drm_crtc.c |   17 ++++++++++++++---
 1 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index ddd7252..8ee7e45 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -3207,14 +3207,25 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector,
 }
 EXPORT_SYMBOL(drm_mode_connector_update_edid_property);
 
-static bool drm_property_change_is_valid(struct drm_property *property,
+static bool range_property_is_signed(const struct drm_property *property)
+{
+	return property->values[0] > property->values[1];
+}
+
+static bool drm_property_change_is_valid(const struct drm_property *property,
 					 uint64_t value)
 {
 	if (property->flags & DRM_MODE_PROP_IMMUTABLE)
 		return false;
 	if (property->flags & DRM_MODE_PROP_RANGE) {
-		if (value < property->values[0] || value > property->values[1])
-			return false;
+		if (range_property_is_signed(property)) {
+			if ((int64_t)value < (int64_t)property->values[0] ||
+			    (int64_t)value > (int64_t)property->values[1])
+				return false;
+		} else {
+			if (value < property->values[0] || value > property->values[1])
+				return false;
+		}
 		return true;
 	} else if (property->flags & DRM_MODE_PROP_BITMASK) {
 		int i;
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 10/51] drm: Allow drm_mode_object_find() to look up an object of any type
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (8 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 09/51] drm: Allow signed values for range properties ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 11/51] drm: Export drm_encoder_crtc_ok ville.syrjala
                   ` (40 subsequent siblings)
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

To avoid having to pass object types from userspace for atomic mode
setting ioctl, allow drm_mode_object_find() to look up an object of any
type. This will only work as long as the all object types share the ID
space.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/drm_crtc.c |    3 ++-
 include/drm/drm_crtc.h     |    1 +
 2 files changed, 3 insertions(+), 1 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 8ee7e45..1a7a6aa 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -267,7 +267,8 @@ struct drm_mode_object *drm_mode_object_find(struct drm_device *dev,
 
 	mutex_lock(&dev->mode_config.idr_mutex);
 	obj = idr_find(&dev->mode_config.crtc_idr, id);
-	if (!obj || (obj->type != type) || (obj->id != id))
+	if (!obj || (type != DRM_MODE_OBJECT_ANY && obj->type != type) ||
+	    (obj->id != id))
 		obj = NULL;
 	mutex_unlock(&dev->mode_config.idr_mutex);
 
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 8eb04c9..45f56ce 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -48,6 +48,7 @@ struct drm_object_properties;
 #define DRM_MODE_OBJECT_FB 0xfbfbfbfb
 #define DRM_MODE_OBJECT_BLOB 0xbbbbbbbb
 #define DRM_MODE_OBJECT_PLANE 0xeeeeeeee
+#define DRM_MODE_OBJECT_ANY 0
 
 struct drm_mode_object {
 	uint32_t id;
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 11/51] drm: Export drm_encoder_crtc_ok
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (9 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 10/51] drm: Allow drm_mode_object_find() to look up an object of any type ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 12/51] drm: Export drm_crtc_prepare_encoders() ville.syrjala
                   ` (39 subsequent siblings)
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

---
 drivers/gpu/drm/drm_crtc_helper.c |    5 +++--
 include/drm/drm_crtc_helper.h     |    3 +++
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index 1227adf..d30e0dd 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -279,8 +279,8 @@ EXPORT_SYMBOL(drm_helper_disable_unused_functions);
  *
  * Return false if @encoder can't be driven by @crtc, true otherwise.
  */
-static bool drm_encoder_crtc_ok(struct drm_encoder *encoder,
-				struct drm_crtc *crtc)
+bool drm_encoder_crtc_ok(struct drm_encoder *encoder,
+			 struct drm_crtc *crtc)
 {
 	struct drm_device *dev;
 	struct drm_crtc *tmp;
@@ -300,6 +300,7 @@ static bool drm_encoder_crtc_ok(struct drm_encoder *encoder,
 		return true;
 	return false;
 }
+EXPORT_SYMBOL(drm_encoder_crtc_ok);
 
 /*
  * Check the CRTC we're going to map each output to vs. its current
diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h
index e01cc80..a17285c 100644
--- a/include/drm/drm_crtc_helper.h
+++ b/include/drm/drm_crtc_helper.h
@@ -166,4 +166,7 @@ extern void drm_helper_hpd_irq_event(struct drm_device *dev);
 extern void drm_kms_helper_poll_disable(struct drm_device *dev);
 extern void drm_kms_helper_poll_enable(struct drm_device *dev);
 
+extern bool drm_encoder_crtc_ok(struct drm_encoder *encoder,
+				struct drm_crtc *crtc);
+
 #endif
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 12/51] drm: Export drm_crtc_prepare_encoders()
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (10 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 11/51] drm: Export drm_encoder_crtc_ok ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 13/51] drm: Refactor object property check code ville.syrjala
                   ` (38 subsequent siblings)
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

---
 drivers/gpu/drm/drm_crtc_helper.c |    3 ++-
 include/drm/drm_crtc_helper.h     |    1 +
 2 files changed, 3 insertions(+), 1 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index d30e0dd..80bbbda 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -307,7 +307,7 @@ EXPORT_SYMBOL(drm_encoder_crtc_ok);
  * CRTC.  If they don't match, we have to disable the output and the CRTC
  * since the driver will have to re-route things.
  */
-static void
+void
 drm_crtc_prepare_encoders(struct drm_device *dev)
 {
 	struct drm_encoder_helper_funcs *encoder_funcs;
@@ -324,6 +324,7 @@ drm_crtc_prepare_encoders(struct drm_device *dev)
 			drm_encoder_disable(encoder);
 	}
 }
+EXPORT_SYMBOL(drm_crtc_prepare_encoders);
 
 /**
  * drm_crtc_set_mode - set a mode
diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h
index a17285c..d3be5ae 100644
--- a/include/drm/drm_crtc_helper.h
+++ b/include/drm/drm_crtc_helper.h
@@ -168,5 +168,6 @@ extern void drm_kms_helper_poll_enable(struct drm_device *dev);
 
 extern bool drm_encoder_crtc_ok(struct drm_encoder *encoder,
 				struct drm_crtc *crtc);
+extern void drm_crtc_prepare_encoders(struct drm_device *dev);
 
 #endif
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 13/51] drm: Refactor object property check code
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (11 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 12/51] drm: Export drm_crtc_prepare_encoders() ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 14/51] drm: Export mode<->umode conversion functions ville.syrjala
                   ` (37 subsequent siblings)
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Refactor the code to check whether an object has a specific property
to a new function.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/drm_crtc.c |   20 ++++++++++++++------
 1 files changed, 14 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 1a7a6aa..ad18e23 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -3368,6 +3368,19 @@ out:
 	return ret;
 }
 
+static bool object_has_prop(const struct drm_mode_object *obj, u32 prop_id)
+{
+	int i;
+
+	if (!obj->properties)
+		return false;
+
+	for (i = 0; i < obj->properties->count; i++)
+		if (obj->properties->ids[i] == prop_id)
+			return true;
+	return false;
+}
+
 int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
 				    struct drm_file *file_priv)
 {
@@ -3376,7 +3389,6 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
 	struct drm_mode_object *prop_obj;
 	struct drm_property *property;
 	int ret = -EINVAL;
-	int i;
 
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
@@ -3389,11 +3401,7 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
 	if (!arg_obj->properties)
 		goto out;
 
-	for (i = 0; i < arg_obj->properties->count; i++)
-		if (arg_obj->properties->ids[i] == arg->prop_id)
-			break;
-
-	if (i == arg_obj->properties->count)
+	if (!object_has_prop(arg_obj, arg->prop_id))
 		goto out;
 
 	prop_obj = drm_mode_object_find(dev, arg->prop_id,
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 14/51] drm: Export mode<->umode conversion functions
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (12 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 13/51] drm: Refactor object property check code ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 15/51] drm: Make blobs resizeable ville.syrjala
                   ` (36 subsequent siblings)
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Export drm_crtc_convert_to_umode() and drm_crtc_convert_umode().

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/drm_crtc.c |   10 ++++++----
 include/drm/drm_crtc.h     |    4 ++++
 2 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index ad18e23..177bc73 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -1120,8 +1120,8 @@ EXPORT_SYMBOL(drm_mode_config_cleanup);
  * Convert a drm_display_mode into a drm_mode_modeinfo structure to return to
  * the user.
  */
-static void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out,
-				      const struct drm_display_mode *in)
+void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out,
+			       const struct drm_display_mode *in)
 {
 	WARN(in->hdisplay > USHRT_MAX || in->hsync_start > USHRT_MAX ||
 	     in->hsync_end > USHRT_MAX || in->htotal > USHRT_MAX ||
@@ -1147,6 +1147,7 @@ static void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out,
 	strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN);
 	out->name[DRM_DISPLAY_MODE_LEN-1] = 0;
 }
+EXPORT_SYMBOL(drm_crtc_convert_to_umode);
 
 /**
  * drm_crtc_convert_to_umode - convert a modeinfo into a drm_display_mode
@@ -1162,8 +1163,8 @@ static void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out,
  * RETURNS:
  * Zero on success, errno on failure.
  */
-static int drm_crtc_convert_umode(struct drm_display_mode *out,
-				  const struct drm_mode_modeinfo *in)
+int drm_crtc_convert_umode(struct drm_display_mode *out,
+			   const struct drm_mode_modeinfo *in)
 {
 	if (in->clock > INT_MAX || in->vrefresh > INT_MAX)
 		return -ERANGE;
@@ -1187,6 +1188,7 @@ static int drm_crtc_convert_umode(struct drm_display_mode *out,
 
 	return 0;
 }
+EXPORT_SYMBOL(drm_crtc_convert_umode);
 
 /**
  * drm_mode_getresources - get graphics configuration
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 45f56ce..4830b47 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -1087,6 +1087,10 @@ extern int drm_format_num_planes(uint32_t format);
 extern int drm_format_plane_cpp(uint32_t format, int plane);
 extern int drm_format_horz_chroma_subsampling(uint32_t format);
 extern int drm_format_vert_chroma_subsampling(uint32_t format);
+extern void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out,
+				      const struct drm_display_mode *in);
+extern int drm_crtc_convert_umode(struct drm_display_mode *out,
+				  const struct drm_mode_modeinfo *in);
 
 /**
  * drm_region - two dimensional region
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 15/51] drm: Make blobs resizeable
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (13 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 14/51] drm: Export mode<->umode conversion functions ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 16/51] drm: Add drm_flip helper ville.syrjala
                   ` (35 subsequent siblings)
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

When first allocated blobs can be given a maximum size for which memory
is allocated. Later the data inside the blob can be replaced, assuming
that the maximum size is not exceeded.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/drm_crtc.c |   45 ++++++++++++++++++++++++++++++++++++++-----
 include/drm/drm_crtc.h     |    8 ++++++-
 2 files changed, 46 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 177bc73..7a6ed7d 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -2922,6 +2922,9 @@ void drm_property_destroy(struct drm_device *dev, struct drm_property *property)
 {
 	struct drm_property_enum *prop_enum, *pt;
 
+	if (!property)
+		return;
+
 	list_for_each_entry_safe(prop_enum, pt, &property->enum_blob_list, head) {
 		list_del(&prop_enum->head);
 		kfree(prop_enum);
@@ -3111,16 +3114,24 @@ done:
 	return ret;
 }
 
-struct drm_property_blob *drm_property_create_blob(struct drm_device *dev, int length,
-						   void *data)
+struct drm_property_blob *drm_property_create_blob(struct drm_device *dev,
+						   unsigned int length,
+						   unsigned int max_length,
+						   const void *data)
 {
 	struct drm_property_blob *blob;
 	int ret;
 
-	if (!length || !data)
+	if (!!length != !!data)
 		return NULL;
 
-	blob = kzalloc(sizeof(struct drm_property_blob)+length, GFP_KERNEL);
+	if (max_length < length)
+		max_length = length;
+
+	if (max_length == 0)
+		return NULL;
+
+	blob = kzalloc(sizeof(struct drm_property_blob)+max_length, GFP_KERNEL);
 	if (!blob)
 		return NULL;
 
@@ -3130,18 +3141,40 @@ struct drm_property_blob *drm_property_create_blob(struct drm_device *dev, int l
 		return NULL;
 	}
 
+	blob->max_length = max_length;
 	blob->length = length;
 
-	memcpy(blob->data, data, length);
+	if (length)
+		memcpy(blob->data, data, length);
 
 	list_add_tail(&blob->head, &dev->mode_config.property_blob_list);
 	return blob;
 }
 EXPORT_SYMBOL(drm_property_create_blob);
 
+int drm_property_blob_replace_data(struct drm_property_blob *blob,
+				   unsigned int length, const void *data)
+{
+	if (!!length != !!data)
+		return -EINVAL;
+
+	if (length > blob->max_length)
+		return -ENOSPC;
+
+	blob->length = length;
+	if (length)
+		memcpy(blob->data, data, length);
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_property_blob_replace_data);
+
 void drm_property_destroy_blob(struct drm_device *dev,
 			       struct drm_property_blob *blob)
 {
+	if (!blob)
+		return;
+
 	drm_mode_object_put(dev, &blob->base);
 	list_del(&blob->head);
 	kfree(blob);
@@ -3200,7 +3233,7 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector,
 
 	size = EDID_LENGTH * (1 + edid->extensions);
 	connector->edid_blob_ptr = drm_property_create_blob(connector->dev,
-							    size, edid);
+							    size, 0, edid);
 
 	ret = drm_connector_property_set_value(connector,
 					       dev->mode_config.edid_property,
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 4830b47..710f490 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -276,6 +276,7 @@ struct drm_property_blob {
 	struct drm_mode_object base;
 	struct list_head head;
 	unsigned int length;
+	unsigned int max_length;
 	unsigned char data[];
 };
 
@@ -971,7 +972,12 @@ struct drm_property *drm_property_create_range(struct drm_device *dev, int flags
 					 uint64_t min, uint64_t max);
 extern void drm_property_destroy(struct drm_device *dev, struct drm_property *property);
 extern struct drm_property_blob *drm_property_create_blob(struct drm_device *dev,
-							  int length, void *data);
+							  unsigned int level,
+							  unsigned int max_length,
+							  const void *data);
+extern int drm_property_blob_replace_data(struct drm_property_blob *blob,
+					  unsigned int length,
+					  const void *data);
 extern void drm_property_destroy_blob(struct drm_device *dev,
 				      struct drm_property_blob *blob);
 extern int drm_property_add_enum(struct drm_property *property, int index,
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 16/51] drm: Add drm_flip helper
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (14 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 15/51] drm: Make blobs resizeable ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 17/51] drm: Add mode_blob and connector_ids_blob to drm_crtc ville.syrjala
                   ` (34 subsequent siblings)
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

The drm_flip mechanism can be used to implement robust page flipping
support, and also to synchronize the flips on multiple hardware
scanout engines (eg. CRTCs and overlays).

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/Makefile   |    2 +-
 drivers/gpu/drm/drm_flip.c |  376 ++++++++++++++++++++++++++++++++++++++++++++
 include/drm/drm_flip.h     |  244 ++++++++++++++++++++++++++++
 3 files changed, 621 insertions(+), 1 deletions(-)
 create mode 100644 drivers/gpu/drm/drm_flip.c
 create mode 100644 include/drm/drm_flip.h

diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 2ff5cef..f98afd8 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -12,7 +12,7 @@ drm-y       :=	drm_auth.o drm_buffer.o drm_bufs.o drm_cache.o \
 		drm_platform.o drm_sysfs.o drm_hashtab.o drm_mm.o \
 		drm_crtc.o drm_modes.o drm_edid.o \
 		drm_info.o drm_debugfs.o drm_encoder_slave.o \
-		drm_trace_points.o drm_global.o drm_prime.o
+		drm_trace_points.o drm_global.o drm_prime.o drm_flip.o
 
 drm-$(CONFIG_COMPAT) += drm_ioc32.o
 drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
diff --git a/drivers/gpu/drm/drm_flip.c b/drivers/gpu/drm/drm_flip.c
new file mode 100644
index 0000000..6ccc3f8
--- /dev/null
+++ b/drivers/gpu/drm/drm_flip.c
@@ -0,0 +1,376 @@
+/*
+ * Copyright (C) 2012 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ * Ville Syrjälä <ville.syrjala@linux.intel.com>
+ */
+
+#include <drm/drm_flip.h>
+
+static void drm_flip_driver_cleanup(struct work_struct *work)
+{
+	struct drm_flip *flip, *next;
+	struct drm_flip_driver *driver =
+		container_of(work, struct drm_flip_driver, cleanup_work);
+	LIST_HEAD(list);
+
+	spin_lock_irq(&driver->lock);
+
+	list_cut_position(&list,
+			  &driver->cleanup_list,
+			  driver->cleanup_list.prev);
+
+	spin_unlock_irq(&driver->lock);
+
+	if (list_empty(&list))
+		return;
+
+	list_for_each_entry_safe(flip, next, &list, list) {
+		struct drm_flip_helper *helper = flip->helper;
+
+		WARN_ON(!flip->finished);
+
+		helper->funcs->cleanup(flip);
+	}
+}
+
+static void drm_flip_driver_finish(struct work_struct *work)
+{
+	struct drm_flip *flip, *next;
+	struct drm_flip_driver *driver =
+		container_of(work, struct drm_flip_driver, finish_work);
+	LIST_HEAD(list);
+	bool need_cleanup = false;
+
+	spin_lock_irq(&driver->lock);
+
+	list_cut_position(&list,
+			  &driver->finish_list,
+			  driver->finish_list.prev);
+
+	spin_unlock_irq(&driver->lock);
+
+	if (list_empty(&list))
+		return;
+
+	list_for_each_entry_safe(flip, next, &list, list) {
+		struct drm_flip_helper *helper = flip->helper;
+
+		helper->funcs->finish(flip);
+
+		spin_lock_irq(&driver->lock);
+
+		flip->finished = true;
+
+		/*
+		 * It's possible that drm_flip_set_scanout() was called after we
+		 * pulled this flip from finish_list, in which case the flip
+		 * could be in need of cleanup, but not on cleanup_list.
+		 */
+		if (flip == helper->scanout_flip) {
+			list_del_init(&flip->list);
+		} else {
+			need_cleanup = true;
+			list_move_tail(&flip->list, &driver->cleanup_list);
+		}
+
+		spin_unlock_irq(&driver->lock);
+	}
+
+	if (need_cleanup)
+		queue_work(driver->wq, &driver->cleanup_work);
+}
+
+static bool drm_flip_set_scanout(struct drm_flip_helper *helper,
+				 struct drm_flip *flip)
+{
+	struct drm_flip_driver *driver = helper->driver;
+	struct drm_flip *old = helper->scanout_flip;
+
+	helper->scanout_flip = flip;
+
+	if (old && old->finished)
+		list_move_tail(&old->list, &driver->cleanup_list);
+
+	return old != NULL;
+}
+
+static bool drm_flip_complete(struct drm_flip *flip)
+{
+	struct drm_flip_helper *helper = flip->helper;
+	struct drm_flip_driver *driver = helper->driver;
+	bool need_cleanup = false;
+
+	helper->funcs->complete(flip);
+
+	if (flip->flipped) {
+		if (drm_flip_set_scanout(helper, flip))
+			need_cleanup = true;
+	}
+
+	list_add_tail(&flip->list, &driver->finish_list);
+
+	return need_cleanup;
+}
+
+void drm_flip_helper_init(struct drm_flip_helper *helper,
+			  struct drm_flip_driver *driver,
+			  const struct drm_flip_helper_funcs *funcs)
+{
+	helper->pending_flip = NULL;
+	helper->scanout_flip = NULL;
+	helper->driver = driver;
+	helper->funcs = funcs;
+}
+
+void drm_flip_helper_clear(struct drm_flip_helper *helper)
+{
+	unsigned long flags;
+	struct drm_flip_driver *driver = helper->driver;
+	struct drm_flip *pending_flip;
+	bool need_finish = false;
+	bool need_cleanup = false;
+
+	spin_lock_irqsave(&driver->lock, flags);
+
+	pending_flip = helper->pending_flip;
+
+	if (pending_flip) {
+		BUG_ON(pending_flip->helper != helper);
+
+		need_finish = true;
+
+		if (drm_flip_complete(pending_flip))
+			need_cleanup = true;
+
+		helper->pending_flip = NULL;
+	}
+
+	if (drm_flip_set_scanout(helper, NULL))
+		need_cleanup = true;
+
+	spin_unlock_irqrestore(&driver->lock, flags);
+
+	if (need_finish)
+		queue_work(driver->wq, &driver->finish_work);
+
+	if (need_cleanup)
+		queue_work(driver->wq, &driver->cleanup_work);
+}
+
+void drm_flip_helper_fini(struct drm_flip_helper *helper)
+{
+	struct drm_flip_driver *driver = helper->driver;
+
+	drm_flip_helper_clear(helper);
+
+	flush_work_sync(&driver->finish_work);
+	flush_work_sync(&driver->cleanup_work);
+}
+
+void drm_flip_helper_vblank(struct drm_flip_helper *helper)
+{
+	struct drm_flip_driver *driver = helper->driver;
+	struct drm_flip *pending_flip;
+	unsigned long flags;
+	bool need_finish = false;
+	bool need_cleanup = false;
+
+	spin_lock_irqsave(&driver->lock, flags);
+
+	pending_flip = helper->pending_flip;
+
+	if (pending_flip) {
+		BUG_ON(pending_flip->helper != helper);
+
+		if (helper->funcs->vblank(pending_flip))
+			pending_flip->flipped = true;
+
+		if (pending_flip->flipped) {
+			need_finish = true;
+
+			if (drm_flip_complete(pending_flip))
+				need_cleanup = true;
+
+			helper->pending_flip = NULL;
+		}
+	}
+
+	spin_unlock_irqrestore(&driver->lock, flags);
+
+	if (need_finish)
+		queue_work(driver->wq, &driver->finish_work);
+
+	if (need_cleanup)
+		queue_work(driver->wq, &driver->cleanup_work);
+}
+
+void drm_flip_driver_init(struct drm_flip_driver *driver,
+			  const struct drm_flip_driver_funcs *funcs)
+{
+	spin_lock_init(&driver->lock);
+
+	INIT_LIST_HEAD(&driver->finish_list);
+	INIT_LIST_HEAD(&driver->cleanup_list);
+
+	INIT_WORK(&driver->finish_work, drm_flip_driver_finish);
+	INIT_WORK(&driver->cleanup_work, drm_flip_driver_cleanup);
+
+	driver->funcs = funcs;
+
+	driver->wq = create_singlethread_workqueue("drm_flip");
+}
+
+void drm_flip_driver_fini(struct drm_flip_driver *driver)
+{
+	destroy_workqueue(driver->wq);
+
+	/* All the scheduled flips should be cleaned up by now. */
+	WARN_ON(!list_empty(&driver->finish_list));
+	WARN_ON(!list_empty(&driver->cleanup_list));
+}
+
+void drm_flip_driver_schedule_flips(struct drm_flip_driver *driver,
+				    struct list_head *flips)
+{
+	unsigned long flags;
+	struct drm_flip *flip, *next;
+	bool need_finish = false;
+	bool need_cleanup = false;
+
+	spin_lock_irqsave(&driver->lock, flags);
+
+	list_for_each_entry(flip, flips, list) {
+		struct drm_flip_helper *helper = flip->helper;
+		struct drm_flip *pending_flip = helper->pending_flip;
+
+		if (helper->funcs->flip(flip, pending_flip))
+			pending_flip->flipped = true;
+	}
+
+	if (driver->funcs->flush)
+		driver->funcs->flush(driver);
+
+	/* Complete all flips that got overridden */
+	list_for_each_entry_safe(flip, next, flips, list) {
+		struct drm_flip_helper *helper = flip->helper;
+		struct drm_flip *pending_flip = helper->pending_flip;
+
+		BUG_ON(helper->driver != driver);
+
+		if (pending_flip) {
+			BUG_ON(pending_flip->helper != helper);
+
+			need_finish = true;
+
+			if (drm_flip_complete(pending_flip))
+				need_cleanup = true;
+		}
+
+		list_del_init(&flip->list);
+		helper->pending_flip = flip;
+	}
+
+	spin_unlock_irqrestore(&driver->lock, flags);
+
+	if (need_finish)
+		queue_work(driver->wq, &driver->finish_work);
+
+	if (need_cleanup)
+		queue_work(driver->wq, &driver->cleanup_work);
+}
+
+void drm_flip_driver_prepare_flips(struct drm_flip_driver *driver,
+				   struct list_head *flips)
+{
+	struct drm_flip *flip;
+
+	list_for_each_entry(flip, flips, list) {
+		struct drm_flip_helper *helper = flip->helper;
+
+		if (helper->funcs->prepare)
+			helper->funcs->prepare(flip);
+	}
+}
+
+void drm_flip_driver_complete_flips(struct drm_flip_driver *driver,
+				    struct list_head *flips)
+{
+	unsigned long flags;
+	struct drm_flip *flip, *next;
+	bool need_finish = false;
+	bool need_cleanup = false;
+
+	spin_lock_irqsave(&driver->lock, flags);
+
+	/* first complete all pending flips */
+	list_for_each_entry(flip, flips, list) {
+		struct drm_flip_helper *helper = flip->helper;
+		struct drm_flip *pending_flip = helper->pending_flip;
+
+		BUG_ON(helper->driver != driver);
+
+		if (pending_flip) {
+			BUG_ON(pending_flip->helper != helper);
+
+			need_finish = true;
+
+			if (drm_flip_complete(pending_flip))
+				need_cleanup = true;
+
+			helper->pending_flip = NULL;
+		}
+	}
+
+	/* then complete all new flips as well */
+	list_for_each_entry_safe(flip, next, flips, list) {
+		list_del_init(&flip->list);
+
+		/*
+		 * This is the flip that gets scanned out
+		 * next time the hardware is fired up.
+		 */
+		flip->flipped = true;
+
+		need_finish = true;
+
+		if (drm_flip_complete(flip))
+			need_cleanup = true;
+	}
+
+	spin_unlock_irqrestore(&driver->lock, flags);
+
+	if (need_finish)
+		queue_work(driver->wq, &driver->finish_work);
+
+	if (need_cleanup)
+		queue_work(driver->wq, &driver->cleanup_work);
+}
+
+void drm_flip_init(struct drm_flip *flip,
+		   struct drm_flip_helper *helper)
+{
+	flip->helper = helper;
+	flip->flipped = false;
+	flip->finished = false;
+	INIT_LIST_HEAD(&flip->list);
+}
diff --git a/include/drm/drm_flip.h b/include/drm/drm_flip.h
new file mode 100644
index 0000000..4172d6e
--- /dev/null
+++ b/include/drm/drm_flip.h
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2012 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and iated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ * Ville Syrjälä <ville.syrjala@linux.intel.com>
+ */
+
+#ifndef DRM_FLIP_H
+#define DRM_FLIP_H
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+
+struct drm_flip;
+struct drm_flip_helper;
+struct drm_flip_driver;
+
+/* Driver callbacks for drm_flip_driver */
+struct drm_flip_driver_funcs {
+	/*
+	 * Optional callback, called after drm_flip_driver_schedule_flips()
+	 * has called drm_flip_helper::flip() for all the provided flips.
+	 * Can be used to:
+	 * - commit the flips atomically to the hardware, if the
+	 *   hardware provides some mechanism to do that.
+	 * - flush posted writes to make sure all the flips have reached
+	 *   the hardware
+	 * Called with drm_flip_driver::lock held.
+	 */
+	void (*flush)(struct drm_flip_driver *driver);
+};
+
+/*
+ * The driver needs one drm_flip_driver to
+ * coordinates the drm_flip mechanism.
+ */
+struct drm_flip_driver {
+	/* protects drm_flip_driver, drm_flip_helper, and drm_flip internals. */
+	spinlock_t lock;
+
+	/* list of drm_flips waiting to be finished, protected by 'lock' */
+	struct list_head finish_list;
+
+	/* list of drm_flips waiting to be cleaned up, protected by 'lock' */
+	struct list_head cleanup_list;
+
+	/* work used to finish the drm_flips */
+	struct work_struct finish_work;
+
+	/* work used to clean up the drm_flips */
+	struct work_struct cleanup_work;
+
+	/* driver provided callback functions */
+	const struct drm_flip_driver_funcs *funcs;
+
+	/* work queue for finish_work and cleanup_work */
+	struct workqueue_struct *wq;
+};
+
+/* Driver callbacks for drm_flip_helper */
+struct drm_flip_helper_funcs {
+	/*
+	 * Optional function to perform heavy but non-timing
+	 * critial preparations for the flip.
+	 * Called from drm_flip_driver_prepare_flips() with
+	 * no extra locks being held.
+	 */
+	void (*prepare)(struct drm_flip *flip);
+	/*
+	 * Instruct the hardware to flip on the next vblank.
+	 * Must return true, iff pending_flip exists, and has
+	 * actually flipped (ie. now being scanned out).
+	 * Otherwise must return false.
+	 * Called with drm_flip_driver::lock held.
+	 */
+	bool (*flip)(struct drm_flip *flip,
+		     struct drm_flip *pending_flip);
+	/*
+	 * Called from drm_flip_helper_vblank() if
+	 * pending_flip exists. Must return true, iff
+	 * pending_flip has actually flipped (ie. now
+	 * being scanned out). Otherwise must return false.
+	 * Called with drm_flip_driver::lock held.
+	 */
+	bool (*vblank)(struct drm_flip *pending_flip);
+
+	/*
+	 * The flip has just occured, or it got overwritten
+	 * by a more recent flip. If the flip occured, it is
+	 * now being scanned out, otherwise it is scheduled
+	 * for cleanup.
+	 * Can be called from drm_flip_driver_schedule_flips(),
+	 * drm_flip_driver_complete_flips(), or from
+	 * drm_flip_helper_vblank().
+	 * Called with drm_flip_driver::lock held.
+	 */
+	void (*complete)(struct drm_flip *flip);
+
+	/*
+	 * Perform finishing steps on the flip. Called from a workqueue
+	 * soon after the flip has completed. The flip's buffer may be
+	 * actively scanned out.
+	 * Called with no locks being held.
+	 */
+	void (*finish)(struct drm_flip *flip);
+
+	/*
+	 * Perform final cleanup on the flip. Called from a workqueue
+	 * after the flip's buffer is no longer being scanned out.
+	 * Called with no locks being held.
+	 */
+	void (*cleanup)(struct drm_flip *flip);
+
+};
+
+/*
+ * The driver needs one drm_flip_helper for each scanout engine it
+ * wants to operate through the drm_flip mechanism.
+ */
+struct drm_flip_helper {
+	/* drm_flip from the previous drm_flip_schedule() call */
+	struct drm_flip *pending_flip;
+	/* drm_flip whose buffer is being scanned out */
+	struct drm_flip *scanout_flip;
+	/* associated drm_flip_driver */
+	struct drm_flip_driver *driver;
+	/* driver provided callback functions */
+	const struct drm_flip_helper_funcs *funcs;
+};
+
+/*
+ * This structure represents a single page flip operation.
+ */
+struct drm_flip {
+	/* associated drm_flip_helper */
+	struct drm_flip_helper *helper;
+	/* has this flip occured? */
+	bool flipped;
+	/* has the finish work been executed for this flip? */
+	bool finished;
+	/* used to keep this flip on various lists */
+	struct list_head list;
+};
+
+/*
+ * Initialize the flip driver.
+ */
+void drm_flip_driver_init(struct drm_flip_driver *driver,
+			  const struct drm_flip_driver_funcs *funcs);
+
+/*
+ * Finalize the flip driver. This will block until all the
+ * pending finish and cleanup work has been completed.
+ */
+void drm_flip_driver_fini(struct drm_flip_driver *driver);
+
+/*
+ * Initialize flip helper.
+ */
+void drm_flip_helper_init(struct drm_flip_helper *helper,
+			  struct drm_flip_driver *driver,
+			  const struct drm_flip_helper_funcs *funcs);
+
+/*
+ * Clear flip helper state. This will forcefully complete the
+ * helper's pending flip (if any).
+ */
+void drm_flip_helper_clear(struct drm_flip_helper *helper);
+
+/*
+ * Finalize the flip helper. This will forcefully complete the
+ * helper's pending flip (if any), and wait for the finish and
+ * cleanup works to finish.
+ */
+void drm_flip_helper_fini(struct drm_flip_helper *helper);
+
+/*
+ * Call this from the driver's vblank handler for the scanout engine
+ * associated with this helper.
+ */
+void drm_flip_helper_vblank(struct drm_flip_helper *helper);
+
+/*
+ * This will call drm_flip_helper::prepare() (if provided) for all the
+ * drm_flips on the list. The purpose is to perform any non-timing critical
+ * preparation steps for the flips before taking locks or disabling interrupts.
+ */
+void drm_flip_driver_prepare_flips(struct drm_flip_driver *driver,
+				   struct list_head *flips);
+
+/*
+ * Schedule the flips on the list to occur on the next vblank.
+ *
+ * This will call drm_flip_helper::flip() for all the drm_flips on the list.
+ * It will then call drm_flip_driver::flush(), after which it will complete
+ * any pending_flip that got overridden by the new flips.
+ *
+ * Unless the hardware provides some mechanism to synchronize the flips, the
+ * time spent until drm_flip_driver::flush() is timing critical and the driver
+ * must somehow make sure it can complete the operation in a seemingly atomic
+ * fashion.
+ */
+void drm_flip_driver_schedule_flips(struct drm_flip_driver *driver,
+				    struct list_head *flips);
+
+/*
+ * This will complete any pending_flip and also all the flips
+ * on the provided list (in that order).
+ *
+ * Call this instead of drm_flip_driver_schedule_flips()
+ * eg. if the hardware powered down, and you just want to keep
+ * the drm_flip mechanim's state consistent w/o waking up the
+ * hardware.
+ */
+void drm_flip_driver_complete_flips(struct drm_flip_driver *driver,
+				    struct list_head *flips);
+
+/*
+ * Initialize the flip structure members.
+ */
+void drm_flip_init(struct drm_flip *flip,
+		   struct drm_flip_helper *helper);
+
+#endif
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 17/51] drm: Add mode_blob and connector_ids_blob to drm_crtc
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (15 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 16/51] drm: Add drm_flip helper ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 18/51] drm: Add the atomic modeset ioctl ville.syrjala
                   ` (33 subsequent siblings)
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

These will be ued by standard properties MODE and CONNECTOR_IDS.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 include/drm/drm_crtc.h |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 710f490..011f51b 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -423,6 +423,9 @@ struct drm_crtc {
 	void *helper_private;
 
 	struct drm_object_properties properties;
+
+	struct drm_property_blob *mode_blob;
+	struct drm_property_blob *connector_ids_blob;
 };
 
 
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 18/51] drm: Add the atomic modeset ioctl
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (16 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 17/51] drm: Add mode_blob and connector_ids_blob to drm_crtc ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 19/51] drm/i915: Fix display pixel format handling ville.syrjala
                   ` (32 subsequent siblings)
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

This new ioctl can be used to update an arbitrary set of object
properties in one operation.

The ioctl simply takes a list of object IDs and property IDs and their
values. For setting values of blob properties, the property value
indicates the length of the data, and the actual data is passed via
another blob pointer.

Three flags are currently supported to alter the behaviour of the ioctl:
- DRM_MODE_ATOMIC_TEST_ONLY indicates that the new state chould only be
  checked for validity, but not hardware state is to be modified.
- DRM_MODE_ATOMIC_EVENT requests that asynchronous completion events be
  sent back to user space. A new event type is added for this purpose.
- DRM_MODE_ATOMIC_NONBLOCK indicates that the operation must be
  completed asynchronously without blocking the the caller for
  significant amounts of time.

Internally the driver must implement the functions pointers in struct
drm_atomic_funcs to support the new ioctl.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/drm_crtc.c  |  146 +++++++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/drm_drv.c   |    1 +
 include/drm/drmP.h          |    8 +++
 include/drm/drm_crtc.h      |   13 ++++
 include/uapi/drm/drm.h      |   12 ++++
 include/uapi/drm/drm_mode.h |   17 +++++
 6 files changed, 197 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 7a6ed7d..4736cfe 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -4236,3 +4236,149 @@ int drm_calc_vscale(struct drm_region *src, struct drm_region *dst,
 	return vscale;
 }
 EXPORT_SYMBOL(drm_calc_vscale);
+
+int drm_mode_atomic_ioctl(struct drm_device *dev,
+			  void *data, struct drm_file *file_priv)
+{
+	struct drm_mode_atomic *arg = data;
+	uint32_t __user *objs_ptr = (uint32_t __user *)(unsigned long)(arg->objs_ptr);
+	uint32_t __user *count_props_ptr = (uint32_t __user *)(unsigned long)(arg->count_props_ptr);
+	uint32_t __user *props_ptr = (uint32_t __user *)(unsigned long)(arg->props_ptr);
+	uint64_t __user *prop_values_ptr = (uint64_t __user *)(unsigned long)(arg->prop_values_ptr);
+	uint64_t __user *blob_values_ptr = (uint64_t __user *)(unsigned long)(arg->blob_values_ptr);
+	unsigned int copied_objs = 0;
+	unsigned int copied_props = 0;
+	unsigned int copied_blobs = 0;
+	void *state;
+	int ret = 0;
+	unsigned int i, j;
+
+	if (!dev->driver->atomic_funcs ||
+	    !dev->driver->atomic_funcs->begin ||
+	    !dev->driver->atomic_funcs->set ||
+	    !dev->driver->atomic_funcs->check ||
+	    !dev->driver->atomic_funcs->commit ||
+	    !dev->driver->atomic_funcs->end)
+		return -ENOSYS;
+
+	if (arg->flags & ~(DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_EVENT | DRM_MODE_ATOMIC_NONBLOCK))
+		return -EINVAL;
+
+	/* can't test and expect an event at the same time. */
+	if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY && arg->flags & DRM_MODE_ATOMIC_EVENT)
+		return -EINVAL;
+
+	mutex_lock(&dev->mode_config.mutex);
+
+	state = dev->driver->atomic_funcs->begin(dev, file_priv, arg->flags, arg->user_data);
+	if (IS_ERR(state)) {
+		ret = PTR_ERR(state);
+		goto unlock;
+	}
+
+	for (i = 0; i < arg->count_objs; i++) {
+		uint32_t obj_id, count_props;
+		struct drm_mode_object *obj;
+
+		if (get_user(obj_id, objs_ptr + copied_objs)) {
+			ret = -EFAULT;
+			goto out;
+		}
+
+		obj = drm_mode_object_find(dev, obj_id, DRM_MODE_OBJECT_ANY);
+		if (!obj || !obj->properties) {
+			ret = -ENOENT;
+			goto out;
+		}
+
+		if (get_user(count_props, count_props_ptr + copied_objs)) {
+			ret = -EFAULT;
+			goto out;
+		}
+
+		copied_objs++;
+
+		for (j = 0; j < count_props; j++) {
+			uint32_t prop_id;
+			uint64_t prop_value;
+			struct drm_mode_object *prop_obj;
+			struct drm_property *prop;
+			void *blob_data = NULL;
+
+			if (get_user(prop_id, props_ptr + copied_props)) {
+				ret = -EFAULT;
+				goto out;
+			}
+
+			if (!object_has_prop(obj, prop_id)) {
+				ret = -EINVAL;
+				goto out;
+			}
+
+			prop_obj = drm_mode_object_find(dev, prop_id, DRM_MODE_OBJECT_PROPERTY);
+			if (!prop_obj) {
+				ret = -ENOENT;
+				goto out;
+			}
+			prop = obj_to_property(prop_obj);
+
+			if (get_user(prop_value, prop_values_ptr + copied_props)) {
+				ret = -EFAULT;
+				goto out;
+			}
+
+			if (!drm_property_change_is_valid(prop, prop_value)) {
+				ret = -EINVAL;
+				goto out;
+			}
+
+			if (prop->flags & DRM_MODE_PROP_BLOB && prop_value) {
+				uint64_t blob_ptr;
+
+				if (get_user(blob_ptr, blob_values_ptr + copied_blobs)) {
+					ret = -EFAULT;
+					goto out;
+				}
+
+				blob_data = kmalloc(prop_value, GFP_KERNEL);
+				if (!blob_data) {
+					ret = -ENOMEM;
+					goto out;
+				}
+
+				if (copy_from_user(blob_data, (void __user *)(unsigned long)blob_ptr, prop_value)) {
+					kfree(blob_data);
+					ret = -EFAULT;
+					goto out;
+				}
+			}
+
+			/* User space sends the blob pointer even if we don't use it (length==0). */
+			if (prop->flags & DRM_MODE_PROP_BLOB)
+				copied_blobs++;
+
+			/* The driver will be in charge of blob_data from now on. */
+			ret = dev->driver->atomic_funcs->set(dev, state, obj, prop, prop_value, blob_data);
+			if (ret)
+				goto out;
+
+			copied_props++;
+		}
+	}
+
+	ret = dev->driver->atomic_funcs->check(dev, state);
+	if (ret)
+		goto out;
+
+	if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY)
+		goto out;
+
+	ret = dev->driver->atomic_funcs->commit(dev, state);
+
+ out:
+	dev->driver->atomic_funcs->end(dev, state);
+ unlock:
+	mutex_unlock(&dev->mode_config.mutex);
+
+	return ret;
+}
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index be174ca..dbef305 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -166,6 +166,7 @@ static struct drm_ioctl_desc drm_ioctls[] = {
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_DESTROY_DUMB, drm_mode_destroy_dumb_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_SETPROPERTY, drm_mode_obj_set_property_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+	DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATOMIC, drm_mode_atomic_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
 };
 
 #define DRM_CORE_IOCTL_COUNT	ARRAY_SIZE( drm_ioctls )
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index 3fd8280..f50f63e 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -958,6 +958,8 @@ struct drm_driver {
 
 	/* List of devices hanging off this driver */
 	struct list_head device_list;
+
+	const struct drm_atomic_funcs *atomic_funcs;
 };
 
 #define DRM_MINOR_UNASSIGNED 0
@@ -1051,6 +1053,12 @@ struct drm_pending_vblank_event {
 	struct drm_event_vblank event;
 };
 
+struct drm_pending_atomic_event {
+	struct drm_pending_event base;
+	int pipe;
+	struct drm_event_atomic event;
+};
+
 /**
  * DRM device structure. This structure represent a complete card that
  * may contain multiple heads.
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 011f51b..69420e7 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -1089,6 +1089,8 @@ extern int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
 					     struct drm_file *file_priv);
 extern int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
 					   struct drm_file *file_priv);
+extern int drm_mode_atomic_ioctl(struct drm_device *dev,
+				 void *data, struct drm_file *file_priv);
 
 extern void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth,
 				 int *bpp);
@@ -1129,4 +1131,15 @@ extern int drm_calc_hscale(struct drm_region *src, struct drm_region *dst,
 extern int drm_calc_vscale(struct drm_region *src, struct drm_region *dst,
 			   int min_vscale, int max_vscale);
 
+struct drm_atomic_funcs {
+	void *(*begin)(struct drm_device *dev, struct drm_file *file,
+		       uint32_t flags, uint64_t user_data);
+	int (*set)(struct drm_device *dev, void *state,
+		   struct drm_mode_object *obj, struct drm_property *prop,
+		   uint64_t value, void *blob_data);
+	int (*check)(struct drm_device *dev, void *state);
+	int (*commit)(struct drm_device *dev, void *state);
+	void (*end)(struct drm_device *dev, void *state);
+};
+
 #endif /* __DRM_CRTC_H__ */
diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h
index 1e3481e..f8d3e8f 100644
--- a/include/uapi/drm/drm.h
+++ b/include/uapi/drm/drm.h
@@ -732,6 +732,7 @@ struct drm_prime_handle {
 #define DRM_IOCTL_MODE_ADDFB2		DRM_IOWR(0xB8, struct drm_mode_fb_cmd2)
 #define DRM_IOCTL_MODE_OBJ_GETPROPERTIES	DRM_IOWR(0xB9, struct drm_mode_obj_get_properties)
 #define DRM_IOCTL_MODE_OBJ_SETPROPERTY	DRM_IOWR(0xBA, struct drm_mode_obj_set_property)
+#define DRM_IOCTL_MODE_ATOMIC	DRM_IOWR(0xBB, struct drm_mode_atomic)
 
 /**
  * Device specific ioctls should only be in their respective headers
@@ -763,6 +764,7 @@ struct drm_event {
 
 #define DRM_EVENT_VBLANK 0x01
 #define DRM_EVENT_FLIP_COMPLETE 0x02
+#define DRM_EVENT_ATOMIC_COMPLETE 0x03
 
 struct drm_event_vblank {
 	struct drm_event base;
@@ -773,6 +775,16 @@ struct drm_event_vblank {
 	__u32 reserved;
 };
 
+struct drm_event_atomic {
+	struct drm_event base;
+	__u64 user_data;
+	__u32 tv_sec;
+	__u32 tv_usec;
+	__u32 sequence;
+	__u32 obj_id;
+	__u32 old_fb_id;
+};
+
 #define DRM_CAP_DUMB_BUFFER 0x1
 #define DRM_CAP_VBLANK_HIGH_CRTC 0x2
 #define DRM_CAP_DUMB_PREFERRED_DEPTH 0x3
diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
index 3d6301b..71f5e0d 100644
--- a/include/uapi/drm/drm_mode.h
+++ b/include/uapi/drm/drm_mode.h
@@ -460,4 +460,21 @@ struct drm_mode_destroy_dumb {
 	uint32_t handle;
 };
 
+
+#define DRM_MODE_ATOMIC_TEST_ONLY (1<<0)
+#define DRM_MODE_ATOMIC_EVENT (1<<1)
+#define DRM_MODE_ATOMIC_NONBLOCK (1<<2)
+
+/* FIXME come up with some sane error reporting mechanism? */
+struct drm_mode_atomic {
+	__u32 flags;
+	__u32 count_objs;
+	__u64 objs_ptr;
+	__u64 count_props_ptr;
+	__u64 props_ptr;
+	__u64 prop_values_ptr;
+	__u64 blob_values_ptr;
+	__u64 user_data;
+};
+
 #endif
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 19/51] drm/i915: Fix display pixel format handling
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (17 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 18/51] drm: Add the atomic modeset ioctl ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 20/51] drm/i915: Add SURFLIVE register definitions ville.syrjala
                   ` (31 subsequent siblings)
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Fix support for all RGB/BGR pixel formats (except the 16:16:16:16 float
format).

Fix intel_init_framebuffer() to match hardware and driver limitations:
* RGB332 is not supported at all
* CI8 is supported
* XRGB1555 & co. are supported on Gen3 and earlier
* XRGB210101010 & co. are supported from Gen4 onwards
* BGR formats are supported from Gen4 onwards
* YUV formats are supported from Gen5 onwards (driver limitation)

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/i915_reg.h      |   17 ++++--
 drivers/gpu/drm/i915/intel_display.c |   94 ++++++++++++++++++++++------------
 2 files changed, 74 insertions(+), 37 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index a4162dd..c2e82cc 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -2998,12 +2998,19 @@
 #define   DISPPLANE_GAMMA_ENABLE		(1<<30)
 #define   DISPPLANE_GAMMA_DISABLE		0
 #define   DISPPLANE_PIXFORMAT_MASK		(0xf<<26)
+#define   DISPPLANE_YUV422			(0x0<<26)
 #define   DISPPLANE_8BPP			(0x2<<26)
-#define   DISPPLANE_15_16BPP			(0x4<<26)
-#define   DISPPLANE_16BPP			(0x5<<26)
-#define   DISPPLANE_32BPP_NO_ALPHA		(0x6<<26)
-#define   DISPPLANE_32BPP			(0x7<<26)
-#define   DISPPLANE_32BPP_30BIT_NO_ALPHA	(0xa<<26)
+#define   DISPPLANE_BGRA555			(0x3<<26)
+#define   DISPPLANE_BGRX555			(0x4<<26)
+#define   DISPPLANE_BGRX565			(0x5<<26)
+#define   DISPPLANE_BGRX888			(0x6<<26)
+#define   DISPPLANE_BGRA888			(0x7<<26)
+#define   DISPPLANE_RGBX101010			(0x8<<26)
+#define   DISPPLANE_RGBA101010			(0x9<<26)
+#define   DISPPLANE_BGRX101010			(0xa<<26)
+#define   DISPPLANE_RGBX161616			(0xc<<26)
+#define   DISPPLANE_RGBX888			(0xe<<26)
+#define   DISPPLANE_RGBA888			(0xf<<26)
 #define   DISPPLANE_STEREO_ENABLE		(1<<25)
 #define   DISPPLANE_STEREO_DISABLE		0
 #define   DISPPLANE_SEL_PIPE_SHIFT		24
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 461a637..2dd19f3 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -1969,24 +1969,38 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb,
 	dspcntr = I915_READ(reg);
 	/* Mask out pixel format bits in case we change it */
 	dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
-	switch (fb->bits_per_pixel) {
-	case 8:
+	switch (fb->pixel_format) {
+	case DRM_FORMAT_C8:
 		dspcntr |= DISPPLANE_8BPP;
 		break;
-	case 16:
-		if (fb->depth == 15)
-			dspcntr |= DISPPLANE_15_16BPP;
-		else
-			dspcntr |= DISPPLANE_16BPP;
+	case DRM_FORMAT_XRGB1555:
+	case DRM_FORMAT_ARGB1555:
+		dspcntr |= DISPPLANE_BGRX555;
 		break;
-	case 24:
-	case 32:
-		dspcntr |= DISPPLANE_32BPP_NO_ALPHA;
+	case DRM_FORMAT_RGB565:
+		dspcntr |= DISPPLANE_BGRX565;
+		break;
+	case DRM_FORMAT_XRGB8888:
+	case DRM_FORMAT_ARGB8888:
+		dspcntr |= DISPPLANE_BGRX888;
+		break;
+	case DRM_FORMAT_XBGR8888:
+	case DRM_FORMAT_ABGR8888:
+		dspcntr |= DISPPLANE_RGBX888;
+		break;
+	case DRM_FORMAT_XRGB2101010:
+	case DRM_FORMAT_ARGB2101010:
+		dspcntr |= DISPPLANE_BGRX101010;
+		break;
+	case DRM_FORMAT_XBGR2101010:
+	case DRM_FORMAT_ABGR2101010:
+		dspcntr |= DISPPLANE_RGBX101010;
 		break;
 	default:
-		DRM_ERROR("Unknown color depth %d\n", fb->bits_per_pixel);
+		DRM_ERROR("Unknown pixel format 0x%08x\n", fb->pixel_format);
 		return -EINVAL;
 	}
+
 	if (INTEL_INFO(dev)->gen >= 4) {
 		if (obj->tiling_mode != I915_TILING_NONE)
 			dspcntr |= DISPPLANE_TILED;
@@ -2053,27 +2067,31 @@ static int ironlake_update_plane(struct drm_crtc *crtc,
 	dspcntr = I915_READ(reg);
 	/* Mask out pixel format bits in case we change it */
 	dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
-	switch (fb->bits_per_pixel) {
-	case 8:
+	switch (fb->pixel_format) {
+	case DRM_FORMAT_C8:
 		dspcntr |= DISPPLANE_8BPP;
 		break;
-	case 16:
-		if (fb->depth != 16)
-			return -EINVAL;
-
-		dspcntr |= DISPPLANE_16BPP;
+	case DRM_FORMAT_RGB565:
+		dspcntr |= DISPPLANE_BGRX565;
 		break;
-	case 24:
-	case 32:
-		if (fb->depth == 24)
-			dspcntr |= DISPPLANE_32BPP_NO_ALPHA;
-		else if (fb->depth == 30)
-			dspcntr |= DISPPLANE_32BPP_30BIT_NO_ALPHA;
-		else
-			return -EINVAL;
+	case DRM_FORMAT_XRGB8888:
+	case DRM_FORMAT_ARGB8888:
+		dspcntr |= DISPPLANE_BGRX888;
+		break;
+	case DRM_FORMAT_XBGR8888:
+	case DRM_FORMAT_ABGR8888:
+		dspcntr |= DISPPLANE_RGBX888;
+		break;
+	case DRM_FORMAT_XRGB2101010:
+	case DRM_FORMAT_ARGB2101010:
+		dspcntr |= DISPPLANE_BGRX101010;
+		break;
+	case DRM_FORMAT_XBGR2101010:
+	case DRM_FORMAT_ABGR2101010:
+		dspcntr |= DISPPLANE_RGBX101010;
 		break;
 	default:
-		DRM_ERROR("Unknown color depth %d\n", fb->bits_per_pixel);
+		DRM_ERROR("Unknown pixel format 0x%08x\n", fb->pixel_format);
 		return -EINVAL;
 	}
 
@@ -7707,24 +7725,36 @@ int intel_framebuffer_init(struct drm_device *dev,
 	if (mode_cmd->pitches[0] & 63)
 		return -EINVAL;
 
+	/* Reject formats not supported by any plane early. */
 	switch (mode_cmd->pixel_format) {
-	case DRM_FORMAT_RGB332:
+	case DRM_FORMAT_C8:
 	case DRM_FORMAT_RGB565:
 	case DRM_FORMAT_XRGB8888:
-	case DRM_FORMAT_XBGR8888:
 	case DRM_FORMAT_ARGB8888:
+		break;
+	case DRM_FORMAT_XRGB1555:
+	case DRM_FORMAT_ARGB1555:
+		if (INTEL_INFO(dev)->gen > 3)
+			return -EINVAL;
+		break;
+	case DRM_FORMAT_XBGR8888:
+	case DRM_FORMAT_ABGR8888:
 	case DRM_FORMAT_XRGB2101010:
 	case DRM_FORMAT_ARGB2101010:
-		/* RGB formats are common across chipsets */
+	case DRM_FORMAT_XBGR2101010:
+	case DRM_FORMAT_ABGR2101010:
+		if (INTEL_INFO(dev)->gen < 4)
+			return -EINVAL;
 		break;
 	case DRM_FORMAT_YUYV:
 	case DRM_FORMAT_UYVY:
 	case DRM_FORMAT_YVYU:
 	case DRM_FORMAT_VYUY:
+		if (INTEL_INFO(dev)->gen < 6)
+			return -EINVAL;
 		break;
 	default:
-		DRM_DEBUG_KMS("unsupported pixel format %u\n",
-				mode_cmd->pixel_format);
+		DRM_DEBUG_KMS("unsupported pixel format 0x%08x\n", mode_cmd->pixel_format);
 		return -EINVAL;
 	}
 
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 20/51] drm/i915: Add SURFLIVE register definitions
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (18 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 19/51] drm/i915: Fix display pixel format handling ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 21/51] drm/i915: Implement execbuffer wait for all planes ville.syrjala
                   ` (30 subsequent siblings)
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/i915_reg.h |    7 +++++++
 1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index c2e82cc..5ea4570 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -3031,6 +3031,7 @@
 #define _DSPASIZE		0x70190
 #define _DSPASURF		0x7019C /* 965+ only */
 #define _DSPATILEOFF		0x701A4 /* 965+ only */
+#define _DSPASURFLIVE		0x701AC
 
 #define DSPCNTR(plane) _PIPE(plane, _DSPACNTR, _DSPBCNTR)
 #define DSPADDR(plane) _PIPE(plane, _DSPAADDR, _DSPBADDR)
@@ -3040,6 +3041,7 @@
 #define DSPSURF(plane) _PIPE(plane, _DSPASURF, _DSPBSURF)
 #define DSPTILEOFF(plane) _PIPE(plane, _DSPATILEOFF, _DSPBTILEOFF)
 #define DSPLINOFF(plane) DSPADDR(plane)
+#define DSPSURFLIVE(plane) _PIPE(plane, _DSPASURFLIVE, _DSPBSURFLIVE)
 
 /* Display/Sprite base address macros */
 #define DISP_BASEADDR_MASK	(0xfffff000)
@@ -3085,6 +3087,7 @@
 #define _DSPBSIZE		0x71190
 #define _DSPBSURF		0x7119C
 #define _DSPBTILEOFF		0x711A4
+#define _DSPBSURFLIVE		0x711AC
 
 /* Sprite A control */
 #define _DVSACNTR		0x72180
@@ -3150,6 +3153,7 @@
 #define DVSTILEOFF(pipe) _PIPE(pipe, _DVSATILEOFF, _DVSBTILEOFF)
 #define DVSKEYVAL(pipe) _PIPE(pipe, _DVSAKEYVAL, _DVSBKEYVAL)
 #define DVSKEYMSK(pipe) _PIPE(pipe, _DVSAKEYMSK, _DVSBKEYMSK)
+#define DVSSURFLIVE(pipe) _PIPE(pipe, _DVSASURFLIVE, _DVSBSURFLIVE)
 
 #define _SPRA_CTL		0x70280
 #define   SPRITE_ENABLE			(1<<31)
@@ -3184,6 +3188,7 @@
 #define _SPRA_SURF		0x7029c
 #define _SPRA_KEYMAX		0x702a0
 #define _SPRA_TILEOFF		0x702a4
+#define _SPRA_SURFLIVE		0x702ac
 #define _SPRA_SCALE		0x70304
 #define   SPRITE_SCALE_ENABLE	(1<<31)
 #define   SPRITE_FILTER_MASK	(3<<29)
@@ -3204,6 +3209,7 @@
 #define _SPRB_SURF		0x7129c
 #define _SPRB_KEYMAX		0x712a0
 #define _SPRB_TILEOFF		0x712a4
+#define _SPRB_SURFLIVE		0x712ac
 #define _SPRB_SCALE		0x71304
 #define _SPRB_GAMC		0x71400
 
@@ -3219,6 +3225,7 @@
 #define SPRTILEOFF(pipe) _PIPE(pipe, _SPRA_TILEOFF, _SPRB_TILEOFF)
 #define SPRSCALE(pipe) _PIPE(pipe, _SPRA_SCALE, _SPRB_SCALE)
 #define SPRGAMC(pipe) _PIPE(pipe, _SPRA_GAMC, _SPRB_GAMC)
+#define SPRSURFLIVE(pipe) _PIPE(pipe, _SPRA_SURFLIVE, _SPRB_SURFLIVE)
 
 /* VBIOS regs */
 #define VGACNTRL		0x71400
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 21/51] drm/i915: Implement execbuffer wait for all planes
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (19 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 20/51] drm/i915: Add SURFLIVE register definitions ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 22/51] drm/i915: Check framebuffer stride more thoroughly ville.syrjala
                   ` (29 subsequent siblings)
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Add the MI_WAIT_FOR_EVENT bits for sprites, and fix up the whole thing
for IVB which moved most of the bits around.

Not tested at all!

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/i915_gem_execbuffer.c |   44 +++++++++++++++++++++++++--
 drivers/gpu/drm/i915/i915_reg.h            |    9 ++++++
 2 files changed, 49 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
index 3eea143..cb4d9f7 100644
--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
@@ -625,10 +625,46 @@ i915_gem_execbuffer_wait_for_flips(struct intel_ring_buffer *ring, u32 flips)
 		if (((flips >> plane) & 1) == 0)
 			continue;
 
-		if (plane)
-			flip_mask = MI_WAIT_FOR_PLANE_B_FLIP;
-		else
-			flip_mask = MI_WAIT_FOR_PLANE_A_FLIP;
+		if (IS_GEN7(ring->dev)) {
+			switch (plane) {
+			case 0:
+				flip_mask = MI_WAIT_FOR_PLANE_A_FLIP_IVB;
+				break;
+			case 1:
+				flip_mask = MI_WAIT_FOR_PLANE_B_FLIP_IVB;
+				break;
+			case 2:
+				flip_mask = MI_WAIT_FOR_PLANE_C_FLIP_IVB;
+				break;
+			case 16:
+				flip_mask = MI_WAIT_FOR_SPRITE_A_FLIP_IVB;
+				break;
+			case 17:
+				flip_mask = MI_WAIT_FOR_SPRITE_B_FLIP_IVB;
+				break;
+			case 18:
+				flip_mask = MI_WAIT_FOR_SPRITE_C_FLIP_IVB;
+				break;
+			}
+		} else {
+			switch (plane) {
+			case 0:
+				flip_mask = MI_WAIT_FOR_PLANE_A_FLIP;
+				break;
+			case 1:
+				flip_mask = MI_WAIT_FOR_PLANE_B_FLIP;
+				break;
+			case 2:
+				flip_mask = MI_WAIT_FOR_PLANE_C_FLIP;
+				break;
+			case 16:
+				flip_mask = MI_WAIT_FOR_SPRITE_A_FLIP;
+				break;
+			case 17:
+				flip_mask = MI_WAIT_FOR_SPRITE_B_FLIP;
+				break;
+			}
+		}
 
 		ret = intel_ring_begin(ring, 2);
 		if (ret)
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 5ea4570..6d09411 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -188,7 +188,16 @@
 #define MI_NOOP			MI_INSTR(0, 0)
 #define MI_USER_INTERRUPT	MI_INSTR(0x02, 0)
 #define MI_WAIT_FOR_EVENT       MI_INSTR(0x03, 0)
+#define   MI_WAIT_FOR_SPRITE_C_FLIP_IVB	(1<<20)
+#define   MI_WAIT_FOR_PLANE_C_FLIP_IVB	(1<<15)
+#define   MI_WAIT_FOR_SPRITE_B_FLIP_IVB	(1<<10)
+#define   MI_WAIT_FOR_PLANE_B_FLIP_IVB	(1<<9)
+#define   MI_WAIT_FOR_SPRITE_A_FLIP_IVB	(1<<2)
+#define   MI_WAIT_FOR_PLANE_A_FLIP_IVB	(1<<1)
 #define   MI_WAIT_FOR_OVERLAY_FLIP	(1<<16)
+#define   MI_WAIT_FOR_SPRITE_B_FLIP	(1<<16)
+#define   MI_WAIT_FOR_SPRITE_A_FLIP	(1<<8)
+#define   MI_WAIT_FOR_PLANE_C_FLIP	(1<<8)
 #define   MI_WAIT_FOR_PLANE_B_FLIP      (1<<6)
 #define   MI_WAIT_FOR_PLANE_A_FLIP      (1<<2)
 #define   MI_WAIT_FOR_PLANE_A_SCANLINES (1<<1)
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 22/51] drm/i915: Check framebuffer stride more thoroughly
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (20 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 21/51] drm/i915: Implement execbuffer wait for all planes ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 23/51] drm/i915: Check the framebuffer offset ville.syrjala
                   ` (28 subsequent siblings)
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Make sure the the framebuffer stride is smaller than the maximum
accepted by any plane.

Also when using a tiled memory make sure the object stride matches
the framebuffer stride.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_display.c |   18 ++++++++++++++++++
 1 files changed, 18 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 2dd19f3..581772c 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -7712,6 +7712,17 @@ static const struct drm_framebuffer_funcs intel_fb_funcs = {
 	.create_handle = intel_user_framebuffer_create_handle,
 };
 
+static unsigned int intel_max_fb_stride(const struct drm_device *dev)
+{
+	/* FIXME: BSpec for pre-Gen5 is a bit unclear on stride limits */
+	if (INTEL_INFO(dev)->gen <= 3)
+		return 8192;
+	else if (INTEL_INFO(dev)->gen <= 4)
+		return 16384;
+	else
+		return 32768;
+}
+
 int intel_framebuffer_init(struct drm_device *dev,
 			   struct intel_framebuffer *intel_fb,
 			   struct drm_mode_fb_cmd2 *mode_cmd,
@@ -7725,6 +7736,13 @@ int intel_framebuffer_init(struct drm_device *dev,
 	if (mode_cmd->pitches[0] & 63)
 		return -EINVAL;
 
+	if (mode_cmd->pitches[0] > intel_max_fb_stride(dev))
+		return -EINVAL;
+
+	if (obj->tiling_mode != I915_TILING_NONE &&
+	    mode_cmd->pitches[0] != obj->stride)
+		return -EINVAL;
+
 	/* Reject formats not supported by any plane early. */
 	switch (mode_cmd->pixel_format) {
 	case DRM_FORMAT_C8:
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 23/51] drm/i915: Check the framebuffer offset
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (21 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 22/51] drm/i915: Check framebuffer stride more thoroughly ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 24/51] drm/i915: Handle framebuffer offsets[] ville.syrjala
                   ` (27 subsequent siblings)
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

The framebuffer offset must be aligned to (macro)pixel size.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_display.c |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 581772c..f3fea88 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -7729,6 +7729,7 @@ int intel_framebuffer_init(struct drm_device *dev,
 			   struct drm_i915_gem_object *obj)
 {
 	int ret;
+	unsigned int align = drm_format_plane_cpp(mode_cmd->pixel_format, 0);
 
 	if (obj->tiling_mode == I915_TILING_Y)
 		return -EINVAL;
@@ -7768,6 +7769,7 @@ int intel_framebuffer_init(struct drm_device *dev,
 	case DRM_FORMAT_UYVY:
 	case DRM_FORMAT_YVYU:
 	case DRM_FORMAT_VYUY:
+		align <<= 1;
 		if (INTEL_INFO(dev)->gen < 6)
 			return -EINVAL;
 		break;
@@ -7776,6 +7778,9 @@ int intel_framebuffer_init(struct drm_device *dev,
 		return -EINVAL;
 	}
 
+	if (mode_cmd->offsets[0] % align)
+		return -EINVAL;
+
 	ret = drm_framebuffer_init(dev, &intel_fb->base, &intel_fb_funcs);
 	if (ret) {
 		DRM_ERROR("framebuffer init failed %d\n", ret);
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 24/51] drm/i915: Handle framebuffer offsets[]
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (22 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 23/51] drm/i915: Check the framebuffer offset ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 25/51] drm/i915: Implement proper clipping for video sprites ville.syrjala
                   ` (26 subsequent siblings)
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Take fb->offset[0] into account when calculating the linear and tile x/y
offsets.

For non-tiled surfaces fb->offset[0] is simply added to the linear
byte offset.

For tiled surfaces treat fb->offsets[0] as a byte offset into the
linearized view of the surface. So we end up converting fb->offsets[0]
into additional x and y offsets.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_display.c |   12 ++++++------
 1 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index f3fea88..a4eb64f 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -1952,6 +1952,7 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb,
 	unsigned long linear_offset;
 	u32 dspcntr;
 	u32 reg;
+	unsigned int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
 
 	switch (plane) {
 	case 0:
@@ -2010,13 +2011,12 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb,
 
 	I915_WRITE(reg, dspcntr);
 
-	linear_offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8);
+	linear_offset = fb->offsets[0] + y * fb->pitches[0] + x * cpp;
 
 	if (INTEL_INFO(dev)->gen >= 4) {
 		intel_crtc->dspaddr_offset =
 			gen4_compute_dspaddr_offset_xtiled(&x, &y,
-							   fb->bits_per_pixel / 8,
-							   fb->pitches[0]);
+							   cpp, fb->pitches[0]);
 		linear_offset -= intel_crtc->dspaddr_offset;
 	} else {
 		intel_crtc->dspaddr_offset = linear_offset;
@@ -2049,6 +2049,7 @@ static int ironlake_update_plane(struct drm_crtc *crtc,
 	unsigned long linear_offset;
 	u32 dspcntr;
 	u32 reg;
+	unsigned int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
 
 	switch (plane) {
 	case 0:
@@ -2105,11 +2106,10 @@ static int ironlake_update_plane(struct drm_crtc *crtc,
 
 	I915_WRITE(reg, dspcntr);
 
-	linear_offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8);
+	linear_offset = fb->offsets[0] + y * fb->pitches[0] + x * (fb->bits_per_pixel / 8);
 	intel_crtc->dspaddr_offset =
 		gen4_compute_dspaddr_offset_xtiled(&x, &y,
-						   fb->bits_per_pixel / 8,
-						   fb->pitches[0]);
+						   cpp, fb->pitches[0]);
 	linear_offset -= intel_crtc->dspaddr_offset;
 
 	DRM_DEBUG_KMS("Writing base %08X %08lX %d %d %d\n",
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 25/51] drm/i915: Implement proper clipping for video sprites
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (23 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 24/51] drm/i915: Handle framebuffer offsets[] ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 26/51] drm/i915: pixel_size == cpp ville.syrjala
                   ` (25 subsequent siblings)
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Properly clip the source when the destination gets clipped
by the pipe dimensions.

Sadly the video sprite hardware is rather limited so it can't do proper
sub-pixel postitioning. Resort to a best effort approach, where the
source coordinates are rounded to the nearest (macro)pixel boundary.

Also do some additional checking against various hardware limits.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_sprite.c |  150 ++++++++++++++++++++++++-----------
 1 files changed, 102 insertions(+), 48 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index 82f5e5c..7d1da04 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -128,11 +128,14 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
 	I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]);
 	I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x);
 	if (obj->tiling_mode != I915_TILING_NONE) {
+		y += fb->offsets[0] / fb->pitches[0];
+		x += fb->offsets[0] % fb->pitches[0] / pixel_size;
+
 		I915_WRITE(SPRTILEOFF(pipe), (y << 16) | x);
 	} else {
 		unsigned long offset;
 
-		offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8);
+		offset = fb->offsets[0] + y * fb->pitches[0] + x * pixel_size;
 		I915_WRITE(SPRLINOFF(pipe), offset);
 	}
 	I915_WRITE(SPRSIZE(pipe), (crtc_h << 16) | crtc_w);
@@ -290,11 +293,14 @@ ilk_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
 	I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]);
 	I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x);
 	if (obj->tiling_mode != I915_TILING_NONE) {
+		y += fb->offsets[0] / fb->pitches[0];
+		x += fb->offsets[0] % fb->pitches[0] / pixel_size;
+
 		I915_WRITE(DVSTILEOFF(pipe), (y << 16) | x);
 	} else {
 		unsigned long offset;
 
-		offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8);
+		offset = fb->offsets[0] + y * fb->pitches[0] + x * pixel_size;
 		I915_WRITE(DVSLINOFF(pipe), offset);
 	}
 	I915_WRITE(DVSSIZE(pipe), (crtc_h << 16) | crtc_w);
@@ -408,6 +414,20 @@ ilk_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key)
 		key->flags = I915_SET_COLORKEY_NONE;
 }
 
+static bool
+format_is_yuv(uint32_t format)
+{
+	switch (format) {
+	case DRM_FORMAT_YUYV:
+	case DRM_FORMAT_UYVY:
+	case DRM_FORMAT_VYUY:
+	case DRM_FORMAT_YVYU:
+		return true;
+	default:
+		return false;
+	}
+}
+
 static int
 intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
 		   struct drm_framebuffer *fb, int crtc_x, int crtc_y,
@@ -419,65 +439,97 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	struct intel_plane *intel_plane = to_intel_plane(plane);
-	struct intel_framebuffer *intel_fb;
-	struct drm_i915_gem_object *obj, *old_obj;
+	struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
+	struct drm_i915_gem_object *obj = intel_fb->obj;
+	struct drm_i915_gem_object *old_obj = intel_plane->obj;
 	int pipe = intel_plane->pipe;
 	int ret = 0;
-	int x = src_x >> 16, y = src_y >> 16;
 	int primary_w = crtc->mode.hdisplay, primary_h = crtc->mode.vdisplay;
 	bool disable_primary = false;
+	bool visible;
+	int hscale, vscale;
+	int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
+	struct drm_region src = {
+		.x1 = src_x,
+		.x2 = src_x + src_w,
+		.y1 = src_y,
+		.y2 = src_y + src_h,
+	};
+	struct drm_region dst = {
+		.x1 = crtc_x,
+		.x2 = crtc_x + crtc_w,
+		.y1 = crtc_y,
+		.y2 = crtc_y + crtc_h,
+	};
+	const struct drm_region clip = {
+		.x2 = crtc->mode.hdisplay,
+		.y2 = crtc->mode.vdisplay,
+	};
 
-	intel_fb = to_intel_framebuffer(fb);
-	obj = intel_fb->obj;
+	/* Don't modify another pipe's plane */
+	if (intel_plane->pipe != intel_crtc->pipe)
+		return -EINVAL;
 
-	old_obj = intel_plane->obj;
+	if (fb->width < 3 || fb->height < 3 || fb->pitches[0] > 16384)
+		return -EINVAL;
 
-	src_w = src_w >> 16;
-	src_h = src_h >> 16;
+	hscale = drm_calc_hscale(&src, &dst, 1, intel_plane->max_downscale << 16);
+	vscale = drm_calc_vscale(&src, &dst, 1, intel_plane->max_downscale << 16);
 
-	/* Pipe must be running... */
-	if (!(I915_READ(PIPECONF(pipe)) & PIPECONF_ENABLE))
-		return -EINVAL;
+	visible = drm_region_clip_scaled(&src, &dst, &clip, hscale, vscale);
 
-	if (crtc_x >= primary_w || crtc_y >= primary_h)
-		return -EINVAL;
+	crtc_x = dst.x1;
+	crtc_y = dst.y1;
+	crtc_w = drm_region_width(&dst);
+	crtc_h = drm_region_height(&dst);
 
-	/* Don't modify another pipe's plane */
-	if (intel_plane->pipe != intel_crtc->pipe)
-		return -EINVAL;
+	/* HW doesn't seem to like smaller sprite, even when scaling */
+	/* FIXME return an error instead? */
+	if (crtc_w < 3 || crtc_h < 3)
+		visible = false;
 
 	/*
-	 * Clamp the width & height into the visible area.  Note we don't
-	 * try to scale the source if part of the visible region is offscreen.
-	 * The caller must handle that by adjusting source offset and size.
+	 * Hardware doesn't handle subpixel coordinates.
+	 * Round to nearest (macro)pixel boundary.
 	 */
-	if ((crtc_x < 0) && ((crtc_x + crtc_w) > 0)) {
-		crtc_w += crtc_x;
-		crtc_x = 0;
+	if (format_is_yuv(fb->pixel_format)) {
+		src_x = ((src.x1 + 0x10000) >> 17) << 1;
+		src_w = (((src.x2 + 0x10000) >> 17) << 1) - src_x;
+	} else {
+		src_x = (src.x1 + 0x8000) >> 16;
+		src_w = ((src.x2 + 0x8000) >> 16) - src_x;
 	}
-	if ((crtc_x + crtc_w) <= 0) /* Nothing to display */
-		goto out;
-	if ((crtc_x + crtc_w) > primary_w)
-		crtc_w = primary_w - crtc_x;
+	src_y = (src.y1 + 0x8000) >> 16;
+	src_h = ((src.y2 + 0x8000) >> 16) - src_y;
 
-	if ((crtc_y < 0) && ((crtc_y + crtc_h) > 0)) {
-		crtc_h += crtc_y;
-		crtc_y = 0;
+	/* Account for minimum source size when scaling */
+	if (visible && (src_w != crtc_w || src_h != crtc_h)) {
+		unsigned int min_w = format_is_yuv(fb->pixel_format) ? 4 : 3;
+
+		if (src_w < min_w) {
+			src_w = min_w;
+			if (src_x > fb->width - src_w)
+				src_x = fb->width - src_w;
+		}
+
+		/* FIXME interlacing */
+		if (src_h < 3) {
+			src_h = 3;
+			if (src_y > fb->height - src_h)
+				src_y = fb->height - src_h;
+		}
 	}
-	if ((crtc_y + crtc_h) <= 0) /* Nothing to display */
-		goto out;
-	if (crtc_y + crtc_h > primary_h)
-		crtc_h = primary_h - crtc_y;
 
-	if (!crtc_w || !crtc_h) /* Again, nothing to display */
-		goto out;
+	/* Check size restrictions when scaling */
+	if (visible && (src_w != crtc_w || src_h != crtc_h)) {
+		if (src_w > 2048 || src_h > 2048 ||
+		    src_w * cpp > 4096 - 64 || fb->pitches[0] > 4096)
+			return -EINVAL;
+	}
 
-	/*
-	 * We can take a larger source and scale it down, but
-	 * only so much...  16x is the max on SNB.
-	 */
-	if (((src_w * src_h) / (crtc_w * crtc_h)) > intel_plane->max_downscale)
-		return -EINVAL;
+	/* Pipe must be running... */
+	if (!(I915_READ(PIPECONF(pipe)) & PIPECONF_ENABLE))
+		return 0;
 
 	/*
 	 * If the sprite is completely covering the primary plane,
@@ -502,11 +554,14 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
 	if (!disable_primary)
 		intel_enable_primary(crtc);
 
-	intel_plane->update_plane(plane, fb, obj, crtc_x, crtc_y,
-				  crtc_w, crtc_h, x, y, src_w, src_h);
+	if (visible) {
+		intel_plane->update_plane(plane, fb, obj, crtc_x, crtc_y,
+					  crtc_w, crtc_h, src_x, src_y, src_w, src_h);
 
-	if (disable_primary)
-		intel_disable_primary(crtc);
+		if (disable_primary)
+			intel_disable_primary(crtc);
+	} else
+		intel_plane->disable_plane(plane);
 
 	/* Unpin old obj after new one is active to avoid ugliness */
 	if (old_obj) {
@@ -526,7 +581,6 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
 
 out_unlock:
 	mutex_unlock(&dev->struct_mutex);
-out:
 	return ret;
 }
 
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 26/51] drm/i915: pixel_size == cpp
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (24 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 25/51] drm/i915: Implement proper clipping for video sprites ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 27/51] drm/i915: Bad pixel formats can't reach the sprite code ville.syrjala
                   ` (24 subsequent siblings)
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Use drm_format_plane_cpp() to get 'pixel_size' in the sprite code.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_sprite.c |   19 +++----------------
 1 files changed, 3 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index 7d1da04..709b978 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -48,7 +48,7 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
 	struct intel_plane *intel_plane = to_intel_plane(plane);
 	int pipe = intel_plane->pipe;
 	u32 sprctl, sprscale = 0;
-	int pixel_size;
+	int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
 
 	sprctl = I915_READ(SPRCTL(pipe));
 
@@ -61,32 +61,25 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
 	switch (fb->pixel_format) {
 	case DRM_FORMAT_XBGR8888:
 		sprctl |= SPRITE_FORMAT_RGBX888 | SPRITE_RGB_ORDER_RGBX;
-		pixel_size = 4;
 		break;
 	case DRM_FORMAT_XRGB8888:
 		sprctl |= SPRITE_FORMAT_RGBX888;
-		pixel_size = 4;
 		break;
 	case DRM_FORMAT_YUYV:
 		sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YUYV;
-		pixel_size = 2;
 		break;
 	case DRM_FORMAT_YVYU:
 		sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YVYU;
-		pixel_size = 2;
 		break;
 	case DRM_FORMAT_UYVY:
 		sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_UYVY;
-		pixel_size = 2;
 		break;
 	case DRM_FORMAT_VYUY:
 		sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_VYUY;
-		pixel_size = 2;
 		break;
 	default:
 		DRM_DEBUG_DRIVER("bad pixel format, assuming RGBX888\n");
 		sprctl |= SPRITE_FORMAT_RGBX888;
-		pixel_size = 4;
 		break;
 	}
 
@@ -228,8 +221,9 @@ ilk_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
 	struct drm_device *dev = plane->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_plane *intel_plane = to_intel_plane(plane);
-	int pipe = intel_plane->pipe, pixel_size;
+	int pipe = intel_plane->pipe;
 	u32 dvscntr, dvsscale;
+	int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
 
 	dvscntr = I915_READ(DVSCNTR(pipe));
 
@@ -242,32 +236,25 @@ ilk_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
 	switch (fb->pixel_format) {
 	case DRM_FORMAT_XBGR8888:
 		dvscntr |= DVS_FORMAT_RGBX888 | DVS_RGB_ORDER_XBGR;
-		pixel_size = 4;
 		break;
 	case DRM_FORMAT_XRGB8888:
 		dvscntr |= DVS_FORMAT_RGBX888;
-		pixel_size = 4;
 		break;
 	case DRM_FORMAT_YUYV:
 		dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YUYV;
-		pixel_size = 2;
 		break;
 	case DRM_FORMAT_YVYU:
 		dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YVYU;
-		pixel_size = 2;
 		break;
 	case DRM_FORMAT_UYVY:
 		dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_UYVY;
-		pixel_size = 2;
 		break;
 	case DRM_FORMAT_VYUY:
 		dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_VYUY;
-		pixel_size = 2;
 		break;
 	default:
 		DRM_DEBUG_DRIVER("bad pixel format, assuming RGBX888\n");
 		dvscntr |= DVS_FORMAT_RGBX888;
-		pixel_size = 4;
 		break;
 	}
 
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 27/51] drm/i915: Bad pixel formats can't reach the sprite code
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (25 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 26/51] drm/i915: pixel_size == cpp ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 28/51] drm/i915: Implement restore_fbdev_mode hook ville.syrjala
                   ` (23 subsequent siblings)
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

The framebuffer pixel format is already checked by the common code.
So there's no way an invalid format could reach the driver. So instead
of falling back to a default format, call BUG().

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_sprite.c |    8 ++------
 1 files changed, 2 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index 709b978..cd6777f 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -78,9 +78,7 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
 		sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_VYUY;
 		break;
 	default:
-		DRM_DEBUG_DRIVER("bad pixel format, assuming RGBX888\n");
-		sprctl |= SPRITE_FORMAT_RGBX888;
-		break;
+		BUG();
 	}
 
 	if (obj->tiling_mode != I915_TILING_NONE)
@@ -253,9 +251,7 @@ ilk_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
 		dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_VYUY;
 		break;
 	default:
-		DRM_DEBUG_DRIVER("bad pixel format, assuming RGBX888\n");
-		dvscntr |= DVS_FORMAT_RGBX888;
-		break;
+		BUG();
 	}
 
 	if (obj->tiling_mode != I915_TILING_NONE)
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 28/51] drm/i915: Implement restore_fbdev_mode hook
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (26 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 27/51] drm/i915: Bad pixel formats can't reach the sprite code ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 29/51] drm/i915: Split clipping and checking from update_plane hook ville.syrjala
                   ` (22 subsequent siblings)
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Convert intel_fb_restore_mode to be useable as the
drm_fb_helper.restore_fbdev_mode hook. This will cause all planes to be
disabled when swithing back to fbcon.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/i915_dma.c  |    2 +-
 drivers/gpu/drm/i915/intel_drv.h |    2 +-
 drivers/gpu/drm/i915/intel_fb.c  |   14 ++++++++++----
 3 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index c9bfd83..acc4317 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1820,7 +1820,7 @@ void i915_driver_lastclose(struct drm_device * dev)
 		return;
 
 	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
-		intel_fb_restore_mode(dev);
+		intel_fb_restore_mode(&dev_priv->fbdev->helper);
 		vga_switcheroo_process_delayed_switch();
 		return;
 	}
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index fe71425..64d87c2 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -527,7 +527,7 @@ extern int intel_overlay_attrs(struct drm_device *dev, void *data,
 			       struct drm_file *file_priv);
 
 extern void intel_fb_output_poll_changed(struct drm_device *dev);
-extern void intel_fb_restore_mode(struct drm_device *dev);
+extern int intel_fb_restore_mode(struct drm_fb_helper *helper);
 
 extern void assert_pipe(struct drm_i915_private *dev_priv, enum pipe pipe,
 			bool state);
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c
index 7b30b5c..f087041 100644
--- a/drivers/gpu/drm/i915/intel_fb.c
+++ b/drivers/gpu/drm/i915/intel_fb.c
@@ -193,6 +193,7 @@ static struct drm_fb_helper_funcs intel_fb_helper_funcs = {
 	.gamma_set = intel_crtc_fb_gamma_set,
 	.gamma_get = intel_crtc_fb_gamma_get,
 	.fb_probe = intel_fb_find_or_create_single,
+	.restore_fbdev_mode = intel_fb_restore_mode,
 };
 
 static void intel_fbdev_destroy(struct drm_device *dev,
@@ -273,22 +274,27 @@ void intel_fb_output_poll_changed(struct drm_device *dev)
 	drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper);
 }
 
-void intel_fb_restore_mode(struct drm_device *dev)
+int intel_fb_restore_mode(struct drm_fb_helper *helper)
 {
+	struct drm_device *dev = helper->dev;
 	int ret;
-	drm_i915_private_t *dev_priv = dev->dev_private;
 	struct drm_mode_config *config = &dev->mode_config;
 	struct drm_plane *plane;
 
 	mutex_lock(&dev->mode_config.mutex);
 
-	ret = drm_fb_helper_restore_fbdev_mode(&dev_priv->fbdev->helper);
-	if (ret)
+	ret = drm_fb_helper_restore_fbdev_mode(helper);
+	if (ret) {
 		DRM_DEBUG("failed to restore crtc mode\n");
+		goto out;
+	}
 
 	/* Be sure to shut off any planes that may be active */
 	list_for_each_entry(plane, &config->plane_list, head)
 		plane->funcs->disable_plane(plane);
 
+out:
 	mutex_unlock(&dev->mode_config.mutex);
+
+	return ret;
 }
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 29/51] drm/i915: Split clipping and checking from update_plane hook
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (27 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 28/51] drm/i915: Implement restore_fbdev_mode hook ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 30/51] drm/i915: Factor out i9xx_compute_clocks() like ironlake_compute_clocks() ville.syrjala
                   ` (21 subsequent siblings)
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Split the update_plane() codepath into two separate steps. The first
step checkis and clips the plane, and the second step actually commits
the changes to the hardware. This allows the atomic modesetting code
to perform all checks before clobering hardware state.

The update_plane() hook is reduced to a thin wrapper calling both check
and commit functions.

Buffer (un)pinning is still being performed in the commit step. This
needs to be changed as well, so that the atomic modesetting code can
try to pin all new buffers before touching the hardware.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_drv.h    |   15 +-
 drivers/gpu/drm/i915/intel_sprite.c |  367 ++++++++++++++++++++++------------
 2 files changed, 247 insertions(+), 135 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 64d87c2..0660d38 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -214,6 +214,15 @@ struct intel_crtc {
 	struct intel_pch_pll *pch_pll;
 };
 
+struct intel_plane_coords {
+	/* disabled or fully clipped? */
+	bool visible;
+	/* coordinates clipped against pipe dimensions */
+	int32_t crtc_x, crtc_y;
+	uint32_t crtc_w, crtc_h;
+	uint32_t src_x, src_y, src_w, src_h;
+};
+
 struct intel_plane {
 	struct drm_plane base;
 	enum pipe pipe;
@@ -222,11 +231,7 @@ struct intel_plane {
 	u32 lut_r[1024], lut_g[1024], lut_b[1024];
 	void (*update_plane)(struct drm_plane *plane,
 			     struct drm_framebuffer *fb,
-			     struct drm_i915_gem_object *obj,
-			     int crtc_x, int crtc_y,
-			     unsigned int crtc_w, unsigned int crtc_h,
-			     uint32_t x, uint32_t y,
-			     uint32_t src_w, uint32_t src_h);
+			     const struct intel_plane_coords *clip);
 	void (*disable_plane)(struct drm_plane *plane);
 	int (*update_colorkey)(struct drm_plane *plane,
 			       struct drm_intel_sprite_colorkey *key);
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index cd6777f..fee6f17 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -36,16 +36,173 @@
 #include <drm/i915_drm.h>
 #include "i915_drv.h"
 
+static bool
+format_is_yuv(uint32_t format)
+{
+	switch (format) {
+	case DRM_FORMAT_YUYV:
+	case DRM_FORMAT_UYVY:
+	case DRM_FORMAT_VYUY:
+	case DRM_FORMAT_YVYU:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static void intel_clip_plane(const struct drm_plane *plane,
+			     const struct drm_crtc *crtc,
+			     const struct drm_framebuffer *fb,
+			     struct intel_plane_coords *coords)
+{
+	const struct intel_plane *intel_plane = to_intel_plane(plane);
+	const struct drm_display_mode *mode = &crtc->mode;
+	int hscale, vscale;
+	struct drm_region src = {
+		.x1 = coords->src_x,
+		.x2 = coords->src_x + coords->src_w,
+		.y1 = coords->src_y,
+		.y2 = coords->src_y + coords->src_h,
+	};
+	struct drm_region dst = {
+		.x1 = coords->crtc_x,
+		.x2 = coords->crtc_x + coords->crtc_w,
+		.y1 = coords->crtc_y,
+		.y2 = coords->crtc_y + coords->crtc_h,
+	};
+	const struct drm_region clip = {
+		.x2 = mode->hdisplay,
+		.y2 = mode->vdisplay,
+	};
+
+	hscale = drm_calc_hscale(&src, &dst, 1, intel_plane->max_downscale << 16);
+	vscale = drm_calc_vscale(&src, &dst, 1, intel_plane->max_downscale << 16);
+
+	coords->visible = drm_region_clip_scaled(&src, &dst, &clip, hscale, vscale);
+
+	coords->crtc_x = dst.x1;
+	coords->crtc_y = dst.y1;
+	coords->crtc_w = drm_region_width(&dst);
+	coords->crtc_h = drm_region_height(&dst);
+
+	/* HW doesn't seem to like smaller sprite, even when scaling */
+	/* FIXME return an error instead? */
+	if (coords->crtc_w < 3 || coords->crtc_h < 3)
+		coords->visible = false;
+
+	/*
+	 * Hardware doesn't handle subpixel coordinates.
+	 * Round to nearest (macro)pixel boundary.
+	 */
+	if (format_is_yuv(fb->pixel_format)) {
+		coords->src_x = ((src.x1 + 0x10000) >> 17) << 1;
+		coords->src_w = (((src.x2 + 0x10000) >> 17) << 1) - coords->src_x;
+	} else {
+		coords->src_x = (src.x1 + 0x8000) >> 16;
+		coords->src_w = ((src.x2 + 0x8000) >> 16) - coords->src_x;
+	}
+	coords->src_y = (src.y1 + 0x8000) >> 16;
+	coords->src_h = ((src.y2 + 0x8000) >> 16) - coords->src_y;
+
+	/* Account for minimum source size when scaling */
+	if (coords->visible && (coords->src_w != coords->crtc_w || coords->src_h != coords->crtc_h)) {
+		unsigned int min_w = format_is_yuv(fb->pixel_format) ? 4 : 3;
+
+		if (coords->src_w < min_w) {
+			coords->src_w = min_w;
+			if (coords->src_x > fb->width - coords->src_w)
+				coords->src_x = fb->width - coords->src_w;
+		}
+
+		/* FIXME interlacing */
+		if (coords->src_h < 3) {
+			coords->src_h = 3;
+			if (coords->src_y > fb->height - coords->src_h)
+				coords->src_y = fb->height - coords->src_h;
+		}
+	}
+}
+
+int intel_check_plane(const struct drm_plane *plane,
+		      const struct drm_crtc *crtc,
+		      const struct drm_framebuffer *fb,
+		      struct intel_plane_coords *coords)
+{
+	const struct intel_plane *intel_plane = to_intel_plane(plane);
+
+	if (fb) {
+		/* FIXME copy-pasted. refactor common code in drm_crtc.c */
+		uint32_t fb_width = fb->width << 16;
+		uint32_t fb_height = fb->height << 16;
+		int i;
+
+		for (i = 0; i < plane->format_count; i++) {
+			if (plane->format_types[i] == fb->pixel_format)
+				break;
+		}
+		if (i == plane->format_count)
+			return -EINVAL;
+
+		if (coords->src_w > fb_width ||
+		    coords->src_x > fb_width - coords->src_w ||
+		    coords->src_h > fb_height ||
+		    coords->src_y > fb_height - coords->src_h)
+			return -ENOSPC;
+
+		if (coords->crtc_w > INT_MAX ||
+		    coords->crtc_x > INT_MAX - (int32_t) coords->crtc_w ||
+		    coords->crtc_h > INT_MAX ||
+		    coords->crtc_y > INT_MAX - (int32_t) coords->crtc_h)
+			return -ERANGE;
+
+		if (fb->width < 3 || fb->height < 3 || fb->pitches[0] > 16384)
+			return -EINVAL;
+	}
+
+	if (crtc) {
+		const struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+		/* Don't modify another pipe's plane */
+		if (intel_plane->pipe != intel_crtc->pipe)
+			return -EINVAL;
+	}
+
+	if (!fb || !crtc || !crtc->enabled) {
+		coords->visible = false;
+		return 0;
+	}
+
+	intel_clip_plane(plane, crtc, fb, coords);
+
+	/* Check size restrictions when scaling */
+	if (coords->visible && (coords->src_w != coords->crtc_w || coords->src_h != coords->crtc_h)) {
+		unsigned int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
+
+		if (coords->src_w > 2048 || coords->src_h > 2048 ||
+		    coords->src_w * cpp > 4096 - 64 || fb->pitches[0] > 4096)
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
 static void
-ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
-		 struct drm_i915_gem_object *obj, int crtc_x, int crtc_y,
-		 unsigned int crtc_w, unsigned int crtc_h,
-		 uint32_t x, uint32_t y,
-		 uint32_t src_w, uint32_t src_h)
+ivb_update_plane(struct drm_plane *plane,
+		 struct drm_framebuffer *fb,
+		 const struct intel_plane_coords *coords)
 {
 	struct drm_device *dev = plane->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_plane *intel_plane = to_intel_plane(plane);
+	const struct drm_i915_gem_object *obj = to_intel_framebuffer(fb)->obj;
+	int crtc_x = coords->crtc_x;
+	int crtc_y = coords->crtc_y;
+	unsigned int crtc_w = coords->crtc_w;
+	unsigned int crtc_h = coords->crtc_h;
+	uint32_t x = coords->src_x;
+	uint32_t y = coords->src_y;
+	uint32_t src_w = coords->src_w;
+	uint32_t src_h = coords->src_h;
 	int pipe = intel_plane->pipe;
 	u32 sprctl, sprscale = 0;
 	int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
@@ -210,15 +367,22 @@ ivb_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key)
 }
 
 static void
-ilk_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
-		 struct drm_i915_gem_object *obj, int crtc_x, int crtc_y,
-		 unsigned int crtc_w, unsigned int crtc_h,
-		 uint32_t x, uint32_t y,
-		 uint32_t src_w, uint32_t src_h)
+ilk_update_plane(struct drm_plane *plane,
+		 struct drm_framebuffer *fb,
+		 const struct intel_plane_coords *coords)
 {
 	struct drm_device *dev = plane->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_plane *intel_plane = to_intel_plane(plane);
+	const struct drm_i915_gem_object *obj = to_intel_framebuffer(fb)->obj;
+	int crtc_x = coords->crtc_x;
+	int crtc_y = coords->crtc_y;
+	unsigned int crtc_w = coords->crtc_w;
+	unsigned int crtc_h = coords->crtc_h;
+	uint32_t x = coords->src_x;
+	uint32_t y = coords->src_y;
+	uint32_t src_w = coords->src_w;
+	uint32_t src_h = coords->src_h;
 	int pipe = intel_plane->pipe;
 	u32 dvscntr, dvsscale;
 	int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
@@ -397,129 +561,68 @@ ilk_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key)
 		key->flags = I915_SET_COLORKEY_NONE;
 }
 
-static bool
-format_is_yuv(uint32_t format)
-{
-	switch (format) {
-	case DRM_FORMAT_YUYV:
-	case DRM_FORMAT_UYVY:
-	case DRM_FORMAT_VYUY:
-	case DRM_FORMAT_YVYU:
-		return true;
-	default:
-		return false;
-	}
-}
-
 static int
-intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
-		   struct drm_framebuffer *fb, int crtc_x, int crtc_y,
-		   unsigned int crtc_w, unsigned int crtc_h,
-		   uint32_t src_x, uint32_t src_y,
-		   uint32_t src_w, uint32_t src_h)
+intel_disable_plane(struct drm_plane *plane)
 {
 	struct drm_device *dev = plane->dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	struct intel_plane *intel_plane = to_intel_plane(plane);
-	struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
-	struct drm_i915_gem_object *obj = intel_fb->obj;
-	struct drm_i915_gem_object *old_obj = intel_plane->obj;
-	int pipe = intel_plane->pipe;
 	int ret = 0;
-	int primary_w = crtc->mode.hdisplay, primary_h = crtc->mode.vdisplay;
-	bool disable_primary = false;
-	bool visible;
-	int hscale, vscale;
-	int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
-	struct drm_region src = {
-		.x1 = src_x,
-		.x2 = src_x + src_w,
-		.y1 = src_y,
-		.y2 = src_y + src_h,
-	};
-	struct drm_region dst = {
-		.x1 = crtc_x,
-		.x2 = crtc_x + crtc_w,
-		.y1 = crtc_y,
-		.y2 = crtc_y + crtc_h,
-	};
-	const struct drm_region clip = {
-		.x2 = crtc->mode.hdisplay,
-		.y2 = crtc->mode.vdisplay,
-	};
 
-	/* Don't modify another pipe's plane */
-	if (intel_plane->pipe != intel_crtc->pipe)
-		return -EINVAL;
-
-	if (fb->width < 3 || fb->height < 3 || fb->pitches[0] > 16384)
-		return -EINVAL;
-
-	hscale = drm_calc_hscale(&src, &dst, 1, intel_plane->max_downscale << 16);
-	vscale = drm_calc_vscale(&src, &dst, 1, intel_plane->max_downscale << 16);
-
-	visible = drm_region_clip_scaled(&src, &dst, &clip, hscale, vscale);
-
-	crtc_x = dst.x1;
-	crtc_y = dst.y1;
-	crtc_w = drm_region_width(&dst);
-	crtc_h = drm_region_height(&dst);
+	if (plane->crtc)
+		intel_enable_primary(plane->crtc);
 
-	/* HW doesn't seem to like smaller sprite, even when scaling */
-	/* FIXME return an error instead? */
-	if (crtc_w < 3 || crtc_h < 3)
-		visible = false;
+	intel_plane->disable_plane(plane);
 
-	/*
-	 * Hardware doesn't handle subpixel coordinates.
-	 * Round to nearest (macro)pixel boundary.
-	 */
-	if (format_is_yuv(fb->pixel_format)) {
-		src_x = ((src.x1 + 0x10000) >> 17) << 1;
-		src_w = (((src.x2 + 0x10000) >> 17) << 1) - src_x;
-	} else {
-		src_x = (src.x1 + 0x8000) >> 16;
-		src_w = ((src.x2 + 0x8000) >> 16) - src_x;
-	}
-	src_y = (src.y1 + 0x8000) >> 16;
-	src_h = ((src.y2 + 0x8000) >> 16) - src_y;
+	if (!intel_plane->obj)
+		goto out;
 
-	/* Account for minimum source size when scaling */
-	if (visible && (src_w != crtc_w || src_h != crtc_h)) {
-		unsigned int min_w = format_is_yuv(fb->pixel_format) ? 4 : 3;
+	mutex_lock(&dev->struct_mutex);
+	intel_unpin_fb_obj(intel_plane->obj);
+	intel_plane->obj = NULL;
+	mutex_unlock(&dev->struct_mutex);
+out:
 
-		if (src_w < min_w) {
-			src_w = min_w;
-			if (src_x > fb->width - src_w)
-				src_x = fb->width - src_w;
-		}
+	return ret;
+}
 
-		/* FIXME interlacing */
-		if (src_h < 3) {
-			src_h = 3;
-			if (src_y > fb->height - src_h)
-				src_y = fb->height - src_h;
-		}
-	}
+int
+intel_commit_plane(struct drm_plane *plane,
+		   struct drm_crtc *crtc,
+		   struct drm_framebuffer *fb,
+		   const struct intel_plane_coords *coords)
+{
+	struct drm_device *dev = plane->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_plane *intel_plane = to_intel_plane(plane);
+	struct intel_framebuffer *intel_fb;
+	struct drm_i915_gem_object *obj;
+	struct drm_i915_gem_object *old_obj = intel_plane->obj;
+	int pipe = intel_plane->pipe;
+	int ret;
+	int primary_w, primary_h;
+	bool disable_primary = false;
 
-	/* Check size restrictions when scaling */
-	if (visible && (src_w != crtc_w || src_h != crtc_h)) {
-		if (src_w > 2048 || src_h > 2048 ||
-		    src_w * cpp > 4096 - 64 || fb->pitches[0] > 4096)
-			return -EINVAL;
+	if (!coords->visible) {
+		intel_disable_plane(plane);
+		return 0;
 	}
 
+	/* FIXME this should happen anymore I suppose */
 	/* Pipe must be running... */
 	if (!(I915_READ(PIPECONF(pipe)) & PIPECONF_ENABLE))
 		return 0;
 
+	intel_fb = to_intel_framebuffer(fb);
+	obj = intel_fb->obj;
+	primary_w = crtc->mode.hdisplay;
+	primary_h = crtc->mode.vdisplay;
+
 	/*
 	 * If the sprite is completely covering the primary plane,
 	 * we can disable the primary and save power.
 	 */
-	if ((crtc_x == 0) && (crtc_y == 0) &&
-	    (crtc_w == primary_w) && (crtc_h == primary_h))
+	if ((coords->crtc_x == 0) && (coords->crtc_y == 0) &&
+	    (coords->crtc_w == primary_w) && (coords->crtc_h == primary_h))
 		disable_primary = true;
 
 	mutex_lock(&dev->struct_mutex);
@@ -537,9 +640,8 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
 	if (!disable_primary)
 		intel_enable_primary(crtc);
 
-	if (visible) {
-		intel_plane->update_plane(plane, fb, obj, crtc_x, crtc_y,
-					  crtc_w, crtc_h, src_x, src_y, src_w, src_h);
+	if (coords->visible) {
+		intel_plane->update_plane(plane, fb, coords);
 
 		if (disable_primary)
 			intel_disable_primary(crtc);
@@ -568,26 +670,31 @@ out_unlock:
 }
 
 static int
-intel_disable_plane(struct drm_plane *plane)
+intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
+		   struct drm_framebuffer *fb, int crtc_x, int crtc_y,
+		   unsigned int crtc_w, unsigned int crtc_h,
+		   uint32_t src_x, uint32_t src_y,
+		   uint32_t src_w, uint32_t src_h)
 {
-	struct drm_device *dev = plane->dev;
-	struct intel_plane *intel_plane = to_intel_plane(plane);
-	int ret = 0;
-
-	if (plane->crtc)
-		intel_enable_primary(plane->crtc);
-	intel_plane->disable_plane(plane);
+	int ret;
+	struct intel_plane_coords coords = {
+		.crtc_x = crtc_x,
+		.crtc_y = crtc_y,
+		.crtc_w = crtc_w,
+		.crtc_h = crtc_h,
+		.src_x = src_x,
+		.src_y = src_y,
+		.src_w = src_w,
+		.src_h = src_h,
+	};
 
-	if (!intel_plane->obj)
-		goto out;
+	ret = intel_check_plane(plane, crtc, fb, &coords);
+	if (ret)
+		return ret;
 
-	mutex_lock(&dev->struct_mutex);
-	intel_unpin_fb_obj(intel_plane->obj);
-	intel_plane->obj = NULL;
-	mutex_unlock(&dev->struct_mutex);
-out:
+	intel_commit_plane(plane, crtc, fb, &coords);
 
-	return ret;
+	return 0;
 }
 
 static void intel_destroy_plane(struct drm_plane *plane)
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 30/51] drm/i915: Factor out i9xx_compute_clocks() like ironlake_compute_clocks()
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (28 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 29/51] drm/i915: Split clipping and checking from update_plane hook ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 31/51] drm/i915: Consitify adjusted_mode parameter ville.syrjala
                   ` (20 subsequent siblings)
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Split the clock stuff out.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_display.c |   88 +++++++++++++++++++++-------------
 1 files changed, 55 insertions(+), 33 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index a4eb64f..2a0748c 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -4301,25 +4301,20 @@ static void i8xx_update_pll(struct drm_crtc *crtc,
 	I915_WRITE(DPLL(pipe), dpll);
 }
 
-static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
-			      struct drm_display_mode *mode,
-			      struct drm_display_mode *adjusted_mode,
-			      int x, int y,
-			      struct drm_framebuffer *fb)
+static bool i9xx_compute_clocks(struct drm_crtc *crtc,
+				struct drm_display_mode *adjusted_mode,
+				intel_clock_t *clock,
+				bool *has_reduced_clock,
+				intel_clock_t *reduced_clock,
+				int *refclk, int *num_connectors, bool *is_dp)
 {
 	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 pipe = intel_crtc->pipe;
-	int plane = intel_crtc->plane;
-	int refclk, num_connectors = 0;
-	intel_clock_t clock, reduced_clock;
-	u32 dspcntr, pipeconf, vsyncshift;
-	bool ok, has_reduced_clock = false, is_sdvo = false;
-	bool is_lvds = false, is_tv = false, is_dp = false;
 	struct intel_encoder *encoder;
 	const intel_limit_t *limit;
-	int ret;
+	bool ret, is_sdvo = false, is_tv = false, is_lvds = false;
+
+	*num_connectors = 0;
 
 	for_each_encoder_on_crtc(dev, crtc, encoder) {
 		switch (encoder->type) {
@@ -4336,30 +4331,25 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
 			is_tv = true;
 			break;
 		case INTEL_OUTPUT_DISPLAYPORT:
-			is_dp = true;
+			*is_dp = true;
 			break;
 		}
 
-		num_connectors++;
+		(*num_connectors)++;
 	}
 
-	refclk = i9xx_get_refclk(crtc, num_connectors);
+	*refclk = i9xx_get_refclk(crtc, *num_connectors);
 
 	/*
 	 * Returns a set of divisors for the desired target clock with the given
 	 * refclk, or FALSE.  The returned values represent the clock equation:
 	 * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
 	 */
-	limit = intel_limit(crtc, refclk);
-	ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, NULL,
-			     &clock);
-	if (!ok) {
-		DRM_ERROR("Couldn't find PLL settings for mode!\n");
-		return -EINVAL;
-	}
-
-	/* Ensure that the cursor is valid for the new mode before changing... */
-	intel_crtc_update_cursor(crtc, true);
+	limit = intel_limit(crtc, *refclk);
+	ret = limit->find_pll(limit, crtc, adjusted_mode->clock, *refclk, NULL,
+			      clock);
+	if (!ret)
+		return false;
 
 	if (is_lvds && dev_priv->lvds_downclock_avail) {
 		/*
@@ -4368,15 +4358,47 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
 		 * by using the FP0/FP1. In such case we will disable the LVDS
 		 * downclock feature.
 		*/
-		has_reduced_clock = limit->find_pll(limit, crtc,
-						    dev_priv->lvds_downclock,
-						    refclk,
-						    &clock,
-						    &reduced_clock);
+		*has_reduced_clock = limit->find_pll(limit, crtc,
+						     dev_priv->lvds_downclock,
+						     *refclk,
+						     clock,
+						     reduced_clock);
 	}
 
 	if (is_sdvo && is_tv)
-		i9xx_adjust_sdvo_tv_clock(adjusted_mode, &clock);
+		i9xx_adjust_sdvo_tv_clock(adjusted_mode, clock);
+
+	return true;
+}
+
+static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
+			      struct drm_display_mode *mode,
+			      struct drm_display_mode *adjusted_mode,
+			      int x, int y,
+			      struct drm_framebuffer *fb)
+{
+	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 pipe = intel_crtc->pipe;
+	int plane = intel_crtc->plane;
+	int refclk, num_connectors = 0;
+	intel_clock_t clock, reduced_clock;
+	u32 dspcntr, pipeconf, vsyncshift;
+	bool ok, has_reduced_clock = false;
+	bool is_dp = false;
+	int ret;
+
+	ok = i9xx_compute_clocks(crtc, adjusted_mode, &clock,
+				 &has_reduced_clock, &reduced_clock,
+				 &refclk, &num_connectors, &is_dp);
+	if (!ok) {
+		DRM_ERROR("Couldn't find PLL settings for mode!\n");
+		return -EINVAL;
+	}
+
+	/* Ensure that the cursor is valid for the new mode before changing... */
+	intel_crtc_update_cursor(crtc, true);
 
 	i9xx_update_pll_dividers(crtc, &clock, has_reduced_clock ?
 				 &reduced_clock : NULL);
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 31/51] drm/i915: Consitify adjusted_mode parameter
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (29 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 30/51] drm/i915: Factor out i9xx_compute_clocks() like ironlake_compute_clocks() ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 32/51] drm/i915: Add intel_check_clock() ville.syrjala
                   ` (19 subsequent siblings)
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

i9xx_adjust_sdvo_tv_clock(), i9xx_compute_clocks() and
ironlake_compute_clocks() do not modify the adjusted_mode passed in, so
pass it as const.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_display.c |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 2a0748c..d6b4bfe 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -3963,7 +3963,7 @@ static int i9xx_get_refclk(struct drm_crtc *crtc, int num_connectors)
 	return refclk;
 }
 
-static void i9xx_adjust_sdvo_tv_clock(struct drm_display_mode *adjusted_mode,
+static void i9xx_adjust_sdvo_tv_clock(const struct drm_display_mode *adjusted_mode,
 				      intel_clock_t *clock)
 {
 	/* SDVO TV has fixed PLL values depend on its clock range,
@@ -4302,7 +4302,7 @@ static void i8xx_update_pll(struct drm_crtc *crtc,
 }
 
 static bool i9xx_compute_clocks(struct drm_crtc *crtc,
-				struct drm_display_mode *adjusted_mode,
+				const struct drm_display_mode *adjusted_mode,
 				intel_clock_t *clock,
 				bool *has_reduced_clock,
 				intel_clock_t *reduced_clock,
@@ -4716,7 +4716,7 @@ static void ironlake_set_pipeconf(struct drm_crtc *crtc,
 }
 
 static bool ironlake_compute_clocks(struct drm_crtc *crtc,
-				    struct drm_display_mode *adjusted_mode,
+				    const struct drm_display_mode *adjusted_mode,
 				    intel_clock_t *clock,
 				    bool *has_reduced_clock,
 				    intel_clock_t *reduced_clock)
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 32/51] drm/i915: Add intel_check_clock()
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (30 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 31/51] drm/i915: Consitify adjusted_mode parameter ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 33/51] drm/i915: store cursor_handle in struct intel_crtc ville.syrjala
                   ` (18 subsequent siblings)
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

intel_check_clock() can be used to check clock validity w/o modifying
hardware state.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/i915_drv.h      |    2 ++
 drivers/gpu/drm/i915/intel_display.c |   24 ++++++++++++++++++++++++
 2 files changed, 26 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index f511fa2..53a35fd 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1600,6 +1600,8 @@ extern bool intel_fbc_enabled(struct drm_device *dev);
 extern void intel_disable_fbc(struct drm_device *dev);
 extern bool ironlake_set_drps(struct drm_device *dev, u8 val);
 extern void ironlake_init_pch_refclk(struct drm_device *dev);
+extern int intel_check_clock(struct drm_crtc *crtc,
+			     const struct drm_display_mode *adjusted_mode);
 extern void gen6_set_rps(struct drm_device *dev, u8 val);
 extern void intel_detect_pch(struct drm_device *dev);
 extern int intel_trans_dp_port_sel(struct drm_crtc *crtc);
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index d6b4bfe..d4d7454 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -5124,6 +5124,30 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
 	return ret;
 }
 
+int intel_check_clock(struct drm_crtc *crtc,
+		      const struct drm_display_mode *adjusted_mode)
+{
+	struct drm_device *dev = crtc->dev;
+	intel_clock_t clock, reduced_clock;
+	bool has_reduced_clock = false;
+	bool ok;
+
+	if (HAS_PCH_SPLIT(dev)) {
+		ok = ironlake_compute_clocks(crtc, adjusted_mode, &clock,
+					     &has_reduced_clock, &reduced_clock);
+	} else {
+		int num_connectors = 0;
+		bool is_dp = false;
+		int refclk;
+
+		ok = i9xx_compute_clocks(crtc, adjusted_mode, &clock,
+					 &has_reduced_clock, &reduced_clock,
+					 &refclk, &num_connectors, &is_dp);
+	}
+
+	return ok ? 0 : -EINVAL;
+}
+
 static int intel_crtc_mode_set(struct drm_crtc *crtc,
 			       struct drm_display_mode *mode,
 			       struct drm_display_mode *adjusted_mode,
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 33/51] drm/i915: store cursor_handle in struct intel_crtc
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (31 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 32/51] drm/i915: Add intel_check_clock() ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 34/51] drm/i915: split cursor setting code into prepare/commit/unref parts ville.syrjala
                   ` (17 subsequent siblings)
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ander Conselvan de Oliveira <conselvan2@gmail.com>

This way it is possible to check if the cursor changed without doing
any setup. Will be useful for the atomic modesetting api.
---
 drivers/gpu/drm/i915/intel_display.c |    1 +
 drivers/gpu/drm/i915/intel_drv.h     |    2 +-
 2 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index d4d7454..c59985d 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -5674,6 +5674,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
 	mutex_unlock(&dev->struct_mutex);
 
 	intel_crtc->cursor_addr = addr;
+	intel_crtc->cursor_handle = handle;
 	intel_crtc->cursor_bo = obj;
 	intel_crtc->cursor_width = width;
 	intel_crtc->cursor_height = height;
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 0660d38..abe646d 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -204,7 +204,7 @@ struct intel_crtc {
 	unsigned long dspaddr_offset;
 
 	struct drm_i915_gem_object *cursor_bo;
-	uint32_t cursor_addr;
+	uint32_t cursor_addr, cursor_handle;
 	int16_t cursor_x, cursor_y;
 	int16_t cursor_width, cursor_height;
 	bool cursor_visible;
-- 
1.7.8.6

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 34/51] drm/i915: split cursor setting code into prepare/commit/unref parts
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (32 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 33/51] drm/i915: store cursor_handle in struct intel_crtc ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 35/51] drm/i915: unstatic cursor functions for use with atomic modesetting ville.syrjala
                   ` (16 subsequent siblings)
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ander Conselvan de Oliveira <conselvan2@gmail.com>

The atomic mode setting API will need to pin the cursor bo without
making changes to the current setup. Only on a later stage the cursor
registers can be written and the previous bo released.

This patch splits intel_crtc_cursor_set() into three parts: prepare,
commit and unref. intel_crtc_cursor_prepare() will pin the cursor bo
and return a gem object and the address to be written to the cursor
registers. intel_crtc_cursor_commit() takes that object and address
and actually changes the cursor. intel_crtc_cursor_unref() is used to
release the previous cursor bo.
---
 drivers/gpu/drm/i915/intel_display.c |   90 +++++++++++++++++++++++++--------
 1 files changed, 68 insertions(+), 22 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index c59985d..20539c4 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -5587,10 +5587,12 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
 	}
 }
 
-static int intel_crtc_cursor_set(struct drm_crtc *crtc,
+static int intel_crtc_cursor_prepare(struct drm_crtc *crtc,
 				 struct drm_file *file,
 				 uint32_t handle,
-				 uint32_t width, uint32_t height)
+				 uint32_t width, uint32_t height,
+				 struct drm_i915_gem_object **obj_ret,
+				 uint32_t *addr_ret)
 {
 	struct drm_device *dev = crtc->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -5602,10 +5604,9 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
 	/* if we want to turn off the cursor ignore width and height */
 	if (!handle) {
 		DRM_DEBUG_KMS("cursor off\n");
-		addr = 0;
-		obj = NULL;
-		mutex_lock(&dev->struct_mutex);
-		goto finish;
+		*addr_ret = 0;
+		*obj_ret = NULL;
+		return 0;
 	}
 
 	/* Currently we only support 64x64 cursors */
@@ -5661,17 +5662,46 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
 	if (IS_GEN2(dev))
 		I915_WRITE(CURSIZE, (height << 12) | width);
 
- finish:
-	if (intel_crtc->cursor_bo) {
-		if (dev_priv->info->cursor_needs_physical) {
-			if (intel_crtc->cursor_bo != obj)
-				i915_gem_detach_phys_object(dev, intel_crtc->cursor_bo);
-		} else
-			i915_gem_object_unpin(intel_crtc->cursor_bo);
-		drm_gem_object_unreference(&intel_crtc->cursor_bo->base);
-	}
+	mutex_unlock(&dev->struct_mutex);
 
+	*obj_ret = obj;
+	*addr_ret = addr;
+
+	return 0;
+fail_unpin:
+	i915_gem_object_unpin(obj);
+fail_locked:
 	mutex_unlock(&dev->struct_mutex);
+fail:
+	drm_gem_object_unreference_unlocked(&obj->base);
+	return ret;
+}
+
+static void intel_crtc_cursor_bo_unref(struct drm_crtc *crtc,
+				       struct drm_i915_gem_object *obj)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+	mutex_lock(&dev->struct_mutex);
+
+	if (dev_priv->info->cursor_needs_physical) {
+		if (obj != intel_crtc->cursor_bo)
+			i915_gem_detach_phys_object(dev, obj);
+	} else
+		i915_gem_object_unpin(obj);
+	drm_gem_object_unreference(&obj->base);
+
+	mutex_unlock(&dev->struct_mutex);
+}
+
+static void intel_crtc_cursor_commit(struct drm_crtc *crtc, uint32_t handle,
+				     uint32_t width, uint32_t height,
+				     struct drm_i915_gem_object *obj,
+				     uint32_t addr)
+{
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
 	intel_crtc->cursor_addr = addr;
 	intel_crtc->cursor_handle = handle;
@@ -5680,15 +5710,31 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
 	intel_crtc->cursor_height = height;
 
 	intel_crtc_update_cursor(crtc, true);
+}
+
+static int intel_crtc_cursor_set(struct drm_crtc *crtc,
+				 struct drm_file *file,
+				 uint32_t handle,
+				 uint32_t width, uint32_t height)
+{
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	int ret;
+	struct drm_i915_gem_object *obj, *old_obj;
+	uint32_t addr;
+
+	ret = intel_crtc_cursor_prepare(crtc, file, handle, width, height,
+					&obj, &addr);
+	if (ret)
+		return ret;
+
+	old_obj = intel_crtc->cursor_bo;
+
+	intel_crtc_cursor_commit(crtc, handle, width, height, obj, addr);
+
+	if (old_obj)
+		intel_crtc_cursor_bo_unref(crtc, old_obj);
 
 	return 0;
-fail_unpin:
-	i915_gem_object_unpin(obj);
-fail_locked:
-	mutex_unlock(&dev->struct_mutex);
-fail:
-	drm_gem_object_unreference_unlocked(&obj->base);
-	return ret;
 }
 
 static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
-- 
1.7.8.6

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 35/51] drm/i915: unstatic cursor functions for use with atomic modesetting
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (33 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 34/51] drm/i915: split cursor setting code into prepare/commit/unref parts ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 36/51] drm/i915: Unstatic intel_finish_fb() ville.syrjala
                   ` (15 subsequent siblings)
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ander Conselvan de Oliveira <conselvan2@gmail.com>

---
 drivers/gpu/drm/i915/intel_display.c |   24 ++++++++++++------------
 drivers/gpu/drm/i915/intel_drv.h     |   13 +++++++++++++
 2 files changed, 25 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 20539c4..da59490 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -5587,12 +5587,12 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
 	}
 }
 
-static int intel_crtc_cursor_prepare(struct drm_crtc *crtc,
-				 struct drm_file *file,
-				 uint32_t handle,
-				 uint32_t width, uint32_t height,
-				 struct drm_i915_gem_object **obj_ret,
-				 uint32_t *addr_ret)
+int intel_crtc_cursor_prepare(struct drm_crtc *crtc,
+			      struct drm_file *file,
+			      uint32_t handle,
+			      uint32_t width, uint32_t height,
+			      struct drm_i915_gem_object **obj_ret,
+			      uint32_t *addr_ret)
 {
 	struct drm_device *dev = crtc->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -5677,8 +5677,8 @@ fail:
 	return ret;
 }
 
-static void intel_crtc_cursor_bo_unref(struct drm_crtc *crtc,
-				       struct drm_i915_gem_object *obj)
+void intel_crtc_cursor_bo_unref(struct drm_crtc *crtc,
+				struct drm_i915_gem_object *obj)
 {
 	struct drm_device *dev = crtc->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -5696,10 +5696,10 @@ static void intel_crtc_cursor_bo_unref(struct drm_crtc *crtc,
 	mutex_unlock(&dev->struct_mutex);
 }
 
-static void intel_crtc_cursor_commit(struct drm_crtc *crtc, uint32_t handle,
-				     uint32_t width, uint32_t height,
-				     struct drm_i915_gem_object *obj,
-				     uint32_t addr)
+void intel_crtc_cursor_commit(struct drm_crtc *crtc, uint32_t handle,
+			      uint32_t width, uint32_t height,
+			      struct drm_i915_gem_object *obj,
+			      uint32_t addr)
 {
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index abe646d..19bef3e 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -586,4 +586,17 @@ extern void intel_ddi_mode_set(struct drm_encoder *encoder,
 				struct drm_display_mode *mode,
 				struct drm_display_mode *adjusted_mode);
 
+extern int intel_crtc_cursor_prepare(struct drm_crtc *crtc,
+				     struct drm_file *file,
+				     uint32_t handle,
+				     uint32_t width, uint32_t height,
+				     struct drm_i915_gem_object **obj_ret,
+				     uint32_t *addr_ret);
+extern void intel_crtc_cursor_bo_unref(struct drm_crtc *crtc,
+				       struct drm_i915_gem_object *obj);
+extern void intel_crtc_cursor_commit(struct drm_crtc *crtc, uint32_t handle,
+				     uint32_t width, uint32_t height,
+				     struct drm_i915_gem_object *obj,
+				     uint32_t addr);
+
 #endif /* __INTEL_DRV_H__ */
-- 
1.7.8.6

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 36/51] drm/i915: Unstatic intel_finish_fb()
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (34 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 35/51] drm/i915: unstatic cursor functions for use with atomic modesetting ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 37/51] drm/i915: Pull intel_pipe_set_base() out of the crtc_mode_set() functions ville.syrjala
                   ` (14 subsequent siblings)
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

intel_finish_fb() will be used by the atomic modeset code, so make it
non-static.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_display.c |    2 +-
 drivers/gpu/drm/i915/intel_drv.h     |    1 +
 2 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index da59490..f27ac4d 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -2139,7 +2139,7 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
 	return dev_priv->display.update_plane(crtc, fb, x, y);
 }
 
-static int
+int
 intel_finish_fb(struct drm_framebuffer *old_fb)
 {
 	struct drm_i915_gem_object *obj = to_intel_framebuffer(old_fb)->obj;
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 19bef3e..9dea410 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -511,6 +511,7 @@ extern int intel_pin_and_fence_fb_obj(struct drm_device *dev,
 				      struct drm_i915_gem_object *obj,
 				      struct intel_ring_buffer *pipelined);
 extern void intel_unpin_fb_obj(struct drm_i915_gem_object *obj);
+extern int intel_finish_fb(struct drm_framebuffer *old_fb);
 
 extern int intel_framebuffer_init(struct drm_device *dev,
 				  struct intel_framebuffer *ifb,
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 37/51] drm/i915: Pull intel_pipe_set_base() out of the crtc_mode_set() functions
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (35 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 36/51] drm/i915: Unstatic intel_finish_fb() ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 38/51] drm/i915: Unstatic intel_crtc_update_sarea() ville.syrjala
                   ` (13 subsequent siblings)
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

intel_pipe_set_base() (un)pins the buffers, so it can't be called from
the atomic modeset paths. Pull the intel_pipe_set_base() and watermark
modifications out of i9xx_crtc_mode_set() and ironlake_crtc_mode_set()
into intel_crtc_mode_set(), so that the former two can be used from the
atomic modeset paths.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_display.c |   26 ++++++++++++--------------
 1 files changed, 12 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index f27ac4d..79b6de7 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -4387,7 +4387,6 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
 	u32 dspcntr, pipeconf, vsyncshift;
 	bool ok, has_reduced_clock = false;
 	bool is_dp = false;
-	int ret;
 
 	ok = i9xx_compute_clocks(crtc, adjusted_mode, &clock,
 				 &has_reduced_clock, &reduced_clock,
@@ -4517,11 +4516,7 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
 	I915_WRITE(DSPCNTR(plane), dspcntr);
 	POSTING_READ(DSPCNTR(plane));
 
-	ret = intel_pipe_set_base(crtc, x, y, fb);
-
-	intel_update_watermarks(dev);
-
-	return ret;
+	return 0;
 }
 
 /*
@@ -4795,7 +4790,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
 	bool ok, has_reduced_clock = false, is_sdvo = false;
 	bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false;
 	struct intel_encoder *encoder, *edp_encoder = NULL;
-	int ret;
 	struct fdi_m_n m_n = {0};
 	u32 temp;
 	int target_clock, pixel_multiplier, lane, link_bw, factor;
@@ -5115,13 +5109,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
 	I915_WRITE(DSPCNTR(plane), DISPPLANE_GAMMA_ENABLE);
 	POSTING_READ(DSPCNTR(plane));
 
-	ret = intel_pipe_set_base(crtc, x, y, fb);
-
-	intel_update_watermarks(dev);
-
-	intel_update_linetime_watermarks(dev, pipe, adjusted_mode);
-
-	return ret;
+	return 0;
 }
 
 int intel_check_clock(struct drm_crtc *crtc,
@@ -5164,6 +5152,16 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
 
 	ret = dev_priv->display.crtc_mode_set(crtc, mode, adjusted_mode,
 					      x, y, fb);
+
+	if (!ret) {
+		ret = intel_pipe_set_base(crtc, x, y, fb);
+
+		intel_update_watermarks(dev);
+
+		if (HAS_PCH_SPLIT(dev))
+			intel_update_linetime_watermarks(dev, pipe, adjusted_mode);
+	}
+
 	drm_vblank_post_modeset(dev, pipe);
 
 	return ret;
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 38/51] drm/i915: Unstatic intel_crtc_update_sarea()
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (36 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 37/51] drm/i915: Pull intel_pipe_set_base() out of the crtc_mode_set() functions ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 39/51] drm/i915: Introduce intel_crtc_update_sarea_pos() ville.syrjala
                   ` (12 subsequent siblings)
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Make intel_crtc_update_sarea() available for the atomic mode setting
code.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_display.c |    4 ++--
 drivers/gpu/drm/i915/intel_drv.h     |    2 ++
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 79b6de7..6a5a82b 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -3457,8 +3457,8 @@ static void i9xx_crtc_off(struct drm_crtc *crtc)
 {
 }
 
-static void intel_crtc_update_sarea(struct drm_crtc *crtc,
-				    bool enabled)
+void intel_crtc_update_sarea(struct drm_crtc *crtc,
+			     bool enabled)
 {
 	struct drm_device *dev = crtc->dev;
 	struct drm_i915_master_private *master_priv;
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 9dea410..cd6ea3b 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -600,4 +600,6 @@ extern void intel_crtc_cursor_commit(struct drm_crtc *crtc, uint32_t handle,
 				     struct drm_i915_gem_object *obj,
 				     uint32_t addr);
 
+extern void intel_crtc_update_sarea(struct drm_crtc *crtc, bool enabled);
+
 #endif /* __INTEL_DRV_H__ */
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 39/51] drm/i915: Introduce intel_crtc_update_sarea_pos()
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (37 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 38/51] drm/i915: Unstatic intel_crtc_update_sarea() ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 40/51] drm/i915: Constify mode argument to intel_modeset_adjusted_mode() ville.syrjala
                   ` (11 subsequent siblings)
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Refactor the code that stores the panning x/y position into the sarea.
Make the new function intel_crtc_update_sarea_pos() available to the
atomic mode setting code.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_display.c |   43 ++++++++++++++++++++++------------
 drivers/gpu/drm/i915/intel_drv.h     |    1 +
 2 files changed, 29 insertions(+), 15 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 6a5a82b..ff51171 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -2166,13 +2166,39 @@ intel_finish_fb(struct drm_framebuffer *old_fb)
 	return ret;
 }
 
+void intel_crtc_update_sarea_pos(struct drm_crtc *crtc, int x, int y)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_i915_master_private *master_priv;
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+	if (!dev->primary->master)
+		return;
+
+	master_priv = dev->primary->master->driver_priv;
+	if (!master_priv->sarea_priv)
+		return;
+
+	switch (intel_crtc->pipe) {
+	case 0:
+		master_priv->sarea_priv->pipeA_x = x;
+		master_priv->sarea_priv->pipeA_y = y;
+		break;
+	case 1:
+		master_priv->sarea_priv->pipeB_x = x;
+		master_priv->sarea_priv->pipeB_y = y;
+		break;
+	default:
+		break;
+	}
+}
+
 static int
 intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
 		    struct drm_framebuffer *fb)
 {
 	struct drm_device *dev = crtc->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct drm_i915_master_private *master_priv;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	struct drm_framebuffer *old_fb;
 	int ret;
@@ -2224,20 +2250,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
 	intel_update_fbc(dev);
 	mutex_unlock(&dev->struct_mutex);
 
-	if (!dev->primary->master)
-		return 0;
-
-	master_priv = dev->primary->master->driver_priv;
-	if (!master_priv->sarea_priv)
-		return 0;
-
-	if (intel_crtc->pipe) {
-		master_priv->sarea_priv->pipeB_x = x;
-		master_priv->sarea_priv->pipeB_y = y;
-	} else {
-		master_priv->sarea_priv->pipeA_x = x;
-		master_priv->sarea_priv->pipeA_y = y;
-	}
+	intel_crtc_update_sarea_pos(crtc, x, y);
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index cd6ea3b..c65c97fc 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -601,5 +601,6 @@ extern void intel_crtc_cursor_commit(struct drm_crtc *crtc, uint32_t handle,
 				     uint32_t addr);
 
 extern void intel_crtc_update_sarea(struct drm_crtc *crtc, bool enabled);
+extern void intel_crtc_update_sarea_pos(struct drm_crtc *crtc, int x, int y);
 
 #endif /* __INTEL_DRV_H__ */
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 40/51] drm/i915: Constify mode argument to intel_modeset_adjusted_mode()
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (38 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 39/51] drm/i915: Introduce intel_crtc_update_sarea_pos() ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 41/51] drm/i915: Unstatic intel_crtc_mode_fixup() ville.syrjala
                   ` (10 subsequent siblings)
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

intel_modeset_adjusted_mode() doesn't modify the passed display mode. So
pass it as const.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_display.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index ff51171..683d434 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -6823,7 +6823,7 @@ static void intel_modeset_commit_output_state(struct drm_device *dev)
 
 static struct drm_display_mode *
 intel_modeset_adjusted_mode(struct drm_crtc *crtc,
-			    struct drm_display_mode *mode)
+			    const struct drm_display_mode *mode)
 {
 	struct drm_device *dev = crtc->dev;
 	struct drm_display_mode *adjusted_mode;
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 41/51] drm/i915: Unstatic intel_crtc_mode_fixup()
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (39 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 40/51] drm/i915: Constify mode argument to intel_modeset_adjusted_mode() ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 42/51] drm/i915: Introduce intel_plane_regs ville.syrjala
                   ` (9 subsequent siblings)
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Make intel_crtc_mode_fixup() available for the upcoming atomic
modesetting code.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_display.c |    6 +++---
 drivers/gpu/drm/i915/intel_drv.h     |    4 ++++
 2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 683d434..ba737b8 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -3669,9 +3669,9 @@ bool intel_connector_get_hw_state(struct intel_connector *connector)
 	return encoder->get_hw_state(encoder, &pipe);
 }
 
-static bool intel_crtc_mode_fixup(struct drm_crtc *crtc,
-				  const struct drm_display_mode *mode,
-				  struct drm_display_mode *adjusted_mode)
+bool intel_crtc_mode_fixup(struct drm_crtc *crtc,
+			   const struct drm_display_mode *mode,
+			   struct drm_display_mode *adjusted_mode)
 {
 	struct drm_device *dev = crtc->dev;
 
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index c65c97fc..2b9acba 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -603,4 +603,8 @@ extern void intel_crtc_cursor_commit(struct drm_crtc *crtc, uint32_t handle,
 extern void intel_crtc_update_sarea(struct drm_crtc *crtc, bool enabled);
 extern void intel_crtc_update_sarea_pos(struct drm_crtc *crtc, int x, int y);
 
+extern bool intel_crtc_mode_fixup(struct drm_crtc *crtc,
+				  const struct drm_display_mode *mode,
+				  struct drm_display_mode *adjusted_mode);
+
 #endif /* __INTEL_DRV_H__ */
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 42/51] drm/i915: Introduce intel_plane_regs
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (40 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 41/51] drm/i915: Unstatic intel_crtc_mode_fixup() ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 43/51] drm/i915: Split primary plane update_plane() into calc+commit phases ville.syrjala
                   ` (8 subsequent siblings)
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

intel_plane_regs can be used to shadow all the typical plane registers.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_drv.h |   14 ++++++++++++++
 1 files changed, 14 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 2b9acba..5dab482 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -181,6 +181,20 @@ struct intel_connector {
 	bool (*get_hw_state)(struct intel_connector *);
 };
 
+struct intel_plane_regs {
+	u32 cntr;
+	u32 linoff;
+	u32 stride;
+	u32 pos;
+	u32 size;
+	u32 keyval;
+	u32 keymsk;
+	u32 surf;
+	u32 keymaxval;
+	u32 tileoff;
+	u32 scale;
+};
+
 struct intel_crtc {
 	struct drm_crtc base;
 	enum pipe pipe;
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 43/51] drm/i915: Split primary plane update_plane() into calc+commit phases
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (41 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 42/51] drm/i915: Introduce intel_plane_regs ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 44/51] drm/i915: Split sprite " ville.syrjala
                   ` (7 subsequent siblings)
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Separate the part that calculates the register values from the part that
writes the registers. This will be useful in the atomic page flip code.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/i915_drv.h      |    3 +
 drivers/gpu/drm/i915/intel_display.c |  145 ++++++++++++++++++++++------------
 drivers/gpu/drm/i915/intel_drv.h     |    1 +
 3 files changed, 100 insertions(+), 49 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 53a35fd..302b6e6 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -269,6 +269,9 @@ struct drm_i915_display_funcs {
 			  struct drm_i915_gem_object *obj);
 	int (*update_plane)(struct drm_crtc *crtc, struct drm_framebuffer *fb,
 			    int x, int y);
+	int (*calc_plane)(struct drm_crtc *crtc, struct drm_framebuffer *fb,
+			  int x, int y);
+	void (*commit_plane)(struct drm_crtc *crtc);
 	/* clock updates for mode set */
 	/* cursor updates */
 	/* render clock increase/decrease */
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index ba737b8..0fb1e09 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -1940,8 +1940,27 @@ static unsigned long gen4_compute_dspaddr_offset_xtiled(int *x, int *y,
 	return tile_rows * pitch * 8 + tiles * 4096;
 }
 
-static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb,
-			     int x, int y)
+static void intel_commit_plane(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 plane = intel_crtc->plane;
+	const struct intel_plane_regs *regs = &intel_crtc->primary_regs;
+
+	I915_WRITE(DSPCNTR(plane), regs->cntr);
+	I915_WRITE(DSPSTRIDE(plane), regs->stride);
+
+	if (INTEL_INFO(dev)->gen >= 4) {
+		I915_WRITE(DSPTILEOFF(plane), regs->tileoff);
+		I915_WRITE(DSPLINOFF(plane), regs->linoff);
+		I915_WRITE(DSPSURF(plane), regs->surf);
+	} else
+		I915_WRITE(DSPADDR(plane), regs->linoff);
+}
+
+static int i9xx_calc_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb,
+			   int x, int y)
 {
 	struct drm_device *dev = crtc->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1950,9 +1969,8 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb,
 	struct drm_i915_gem_object *obj;
 	int plane = intel_crtc->plane;
 	unsigned long linear_offset;
-	u32 dspcntr;
-	u32 reg;
 	unsigned int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
+	struct intel_plane_regs *regs = &intel_crtc->primary_regs;
 
 	switch (plane) {
 	case 0:
@@ -1966,36 +1984,35 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb,
 	intel_fb = to_intel_framebuffer(fb);
 	obj = intel_fb->obj;
 
-	reg = DSPCNTR(plane);
-	dspcntr = I915_READ(reg);
+	regs->cntr = I915_READ(DSPCNTR(plane));
 	/* Mask out pixel format bits in case we change it */
-	dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
+	regs->cntr &= ~DISPPLANE_PIXFORMAT_MASK;
 	switch (fb->pixel_format) {
 	case DRM_FORMAT_C8:
-		dspcntr |= DISPPLANE_8BPP;
+		regs->cntr |= DISPPLANE_8BPP;
 		break;
 	case DRM_FORMAT_XRGB1555:
 	case DRM_FORMAT_ARGB1555:
-		dspcntr |= DISPPLANE_BGRX555;
+		regs->cntr |= DISPPLANE_BGRX555;
 		break;
 	case DRM_FORMAT_RGB565:
-		dspcntr |= DISPPLANE_BGRX565;
+		regs->cntr |= DISPPLANE_BGRX565;
 		break;
 	case DRM_FORMAT_XRGB8888:
 	case DRM_FORMAT_ARGB8888:
-		dspcntr |= DISPPLANE_BGRX888;
+		regs->cntr |= DISPPLANE_BGRX888;
 		break;
 	case DRM_FORMAT_XBGR8888:
 	case DRM_FORMAT_ABGR8888:
-		dspcntr |= DISPPLANE_RGBX888;
+		regs->cntr |= DISPPLANE_RGBX888;
 		break;
 	case DRM_FORMAT_XRGB2101010:
 	case DRM_FORMAT_ARGB2101010:
-		dspcntr |= DISPPLANE_BGRX101010;
+		regs->cntr |= DISPPLANE_BGRX101010;
 		break;
 	case DRM_FORMAT_XBGR2101010:
 	case DRM_FORMAT_ABGR2101010:
-		dspcntr |= DISPPLANE_RGBX101010;
+		regs->cntr |= DISPPLANE_RGBX101010;
 		break;
 	default:
 		DRM_ERROR("Unknown pixel format 0x%08x\n", fb->pixel_format);
@@ -2004,13 +2021,11 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb,
 
 	if (INTEL_INFO(dev)->gen >= 4) {
 		if (obj->tiling_mode != I915_TILING_NONE)
-			dspcntr |= DISPPLANE_TILED;
+			regs->cntr |= DISPPLANE_TILED;
 		else
-			dspcntr &= ~DISPPLANE_TILED;
+			regs->cntr &= ~DISPPLANE_TILED;
 	}
 
-	I915_WRITE(reg, dspcntr);
-
 	linear_offset = fb->offsets[0] + y * fb->pitches[0] + x * cpp;
 
 	if (INTEL_INFO(dev)->gen >= 4) {
@@ -2024,21 +2039,37 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb,
 
 	DRM_DEBUG_KMS("Writing base %08X %08lX %d %d %d\n",
 		      obj->gtt_offset, linear_offset, x, y, fb->pitches[0]);
-	I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]);
+	regs->stride = fb->pitches[0];
 	if (INTEL_INFO(dev)->gen >= 4) {
-		I915_MODIFY_DISPBASE(DSPSURF(plane),
-				     obj->gtt_offset + intel_crtc->dspaddr_offset);
-		I915_WRITE(DSPTILEOFF(plane), (y << 16) | x);
-		I915_WRITE(DSPLINOFF(plane), linear_offset);
+		regs->surf = I915_LO_DISPBASE(I915_READ(DSPSURF(plane))) |
+			(obj->gtt_offset + intel_crtc->dspaddr_offset);
+		regs->tileoff = (y << 16) | x;
+		regs->linoff = linear_offset;
 	} else
-		I915_WRITE(DSPADDR(plane), obj->gtt_offset + linear_offset);
-	POSTING_READ(reg);
+		regs->linoff = obj->gtt_offset + linear_offset;
 
 	return 0;
 }
 
-static int ironlake_update_plane(struct drm_crtc *crtc,
-				 struct drm_framebuffer *fb, int x, int y)
+static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb,
+			     int x, int y)
+{
+	struct drm_i915_private *dev_priv = crtc->dev->dev_private;
+	int ret;
+
+	ret = i9xx_calc_plane(crtc, fb, x, y);
+	if (ret)
+		return ret;
+
+	intel_commit_plane(crtc);
+
+	POSTING_READ(DSPCNTR(to_intel_crtc(crtc)->plane));
+
+	return 0;
+}
+
+static int ironlake_calc_plane(struct drm_crtc *crtc,
+			       struct drm_framebuffer *fb, int x, int y)
 {
 	struct drm_device *dev = crtc->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -2047,9 +2078,8 @@ static int ironlake_update_plane(struct drm_crtc *crtc,
 	struct drm_i915_gem_object *obj;
 	int plane = intel_crtc->plane;
 	unsigned long linear_offset;
-	u32 dspcntr;
-	u32 reg;
 	unsigned int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
+	struct intel_plane_regs *regs = &intel_crtc->primary_regs;
 
 	switch (plane) {
 	case 0:
@@ -2064,32 +2094,31 @@ static int ironlake_update_plane(struct drm_crtc *crtc,
 	intel_fb = to_intel_framebuffer(fb);
 	obj = intel_fb->obj;
 
-	reg = DSPCNTR(plane);
-	dspcntr = I915_READ(reg);
+	regs->cntr = I915_READ(DSPCNTR(plane));
 	/* Mask out pixel format bits in case we change it */
-	dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
+	regs->cntr &= ~DISPPLANE_PIXFORMAT_MASK;
 	switch (fb->pixel_format) {
 	case DRM_FORMAT_C8:
-		dspcntr |= DISPPLANE_8BPP;
+		regs->cntr |= DISPPLANE_8BPP;
 		break;
 	case DRM_FORMAT_RGB565:
-		dspcntr |= DISPPLANE_BGRX565;
+		regs->cntr |= DISPPLANE_BGRX565;
 		break;
 	case DRM_FORMAT_XRGB8888:
 	case DRM_FORMAT_ARGB8888:
-		dspcntr |= DISPPLANE_BGRX888;
+		regs->cntr |= DISPPLANE_BGRX888;
 		break;
 	case DRM_FORMAT_XBGR8888:
 	case DRM_FORMAT_ABGR8888:
-		dspcntr |= DISPPLANE_RGBX888;
+		regs->cntr |= DISPPLANE_RGBX888;
 		break;
 	case DRM_FORMAT_XRGB2101010:
 	case DRM_FORMAT_ARGB2101010:
-		dspcntr |= DISPPLANE_BGRX101010;
+		regs->cntr |= DISPPLANE_BGRX101010;
 		break;
 	case DRM_FORMAT_XBGR2101010:
 	case DRM_FORMAT_ABGR2101010:
-		dspcntr |= DISPPLANE_RGBX101010;
+		regs->cntr |= DISPPLANE_RGBX101010;
 		break;
 	default:
 		DRM_ERROR("Unknown pixel format 0x%08x\n", fb->pixel_format);
@@ -2097,14 +2126,12 @@ static int ironlake_update_plane(struct drm_crtc *crtc,
 	}
 
 	if (obj->tiling_mode != I915_TILING_NONE)
-		dspcntr |= DISPPLANE_TILED;
+		regs->cntr |= DISPPLANE_TILED;
 	else
-		dspcntr &= ~DISPPLANE_TILED;
+		regs->cntr &= ~DISPPLANE_TILED;
 
 	/* must disable */
-	dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
-
-	I915_WRITE(reg, dspcntr);
+	regs->cntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
 
 	linear_offset = fb->offsets[0] + y * fb->pitches[0] + x * (fb->bits_per_pixel / 8);
 	intel_crtc->dspaddr_offset =
@@ -2114,12 +2141,28 @@ static int ironlake_update_plane(struct drm_crtc *crtc,
 
 	DRM_DEBUG_KMS("Writing base %08X %08lX %d %d %d\n",
 		      obj->gtt_offset, linear_offset, x, y, fb->pitches[0]);
-	I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]);
-	I915_MODIFY_DISPBASE(DSPSURF(plane),
-			     obj->gtt_offset + intel_crtc->dspaddr_offset);
-	I915_WRITE(DSPTILEOFF(plane), (y << 16) | x);
-	I915_WRITE(DSPLINOFF(plane), linear_offset);
-	POSTING_READ(reg);
+	regs->stride = fb->pitches[0];
+	regs->surf = I915_LO_DISPBASE(I915_READ(DSPSURF(plane))) |
+		(obj->gtt_offset + intel_crtc->dspaddr_offset);
+	regs->tileoff = (y << 16) | x;
+	regs->linoff = linear_offset;
+
+	return 0;
+}
+
+static int ironlake_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb,
+				 int x, int y)
+{
+	struct drm_i915_private *dev_priv = crtc->dev->dev_private;
+	int ret;
+
+	ret = ironlake_calc_plane(crtc, fb, x, y);
+	if (ret)
+		return ret;
+
+	intel_commit_plane(crtc);
+
+	POSTING_READ(DSPCNTR(to_intel_crtc(crtc)->plane));
 
 	return 0;
 }
@@ -7928,12 +7971,16 @@ static void intel_init_display(struct drm_device *dev)
 		dev_priv->display.crtc_disable = ironlake_crtc_disable;
 		dev_priv->display.off = ironlake_crtc_off;
 		dev_priv->display.update_plane = ironlake_update_plane;
+		dev_priv->display.calc_plane = ironlake_calc_plane;
+		dev_priv->display.commit_plane = intel_commit_plane;
 	} else {
 		dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set;
 		dev_priv->display.crtc_enable = i9xx_crtc_enable;
 		dev_priv->display.crtc_disable = i9xx_crtc_disable;
 		dev_priv->display.off = i9xx_crtc_off;
 		dev_priv->display.update_plane = i9xx_update_plane;
+		dev_priv->display.calc_plane = i9xx_calc_plane;
+		dev_priv->display.commit_plane = intel_commit_plane;
 	}
 
 	/* Returns the core display clock speed */
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 5dab482..1389eeb 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -226,6 +226,7 @@ struct intel_crtc {
 
 	/* We can share PLLs across outputs if the timings match */
 	struct intel_pch_pll *pch_pll;
+	struct intel_plane_regs primary_regs;
 };
 
 struct intel_plane_coords {
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 44/51] drm/i915: Split sprite update_plane() into calc+commit phases
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (42 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 43/51] drm/i915: Split primary plane update_plane() into calc+commit phases ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 45/51] drm/i915: Implement atomic modesetting ville.syrjala
                   ` (6 subsequent siblings)
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Separate the part that calculates the register values from the part that
writes the registers. This will be useful in the atomic page flip code.
Also move the watermark magic into a prepare function that can be
performed outside the critical parts of the atomic page flip code.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_drv.h    |    5 +
 drivers/gpu/drm/i915/intel_sprite.c |  398 ++++++++++++++++++++++-------------
 2 files changed, 259 insertions(+), 144 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 1389eeb..6ab8f65 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -252,6 +252,11 @@ struct intel_plane {
 			       struct drm_intel_sprite_colorkey *key);
 	void (*get_colorkey)(struct drm_plane *plane,
 			     struct drm_intel_sprite_colorkey *key);
+	void (*calc)(struct drm_plane *plane, struct drm_framebuffer *fb,
+		     const struct intel_plane_coords *clip);
+	void (*prepare)(struct drm_plane *plane);
+	void (*commit)(struct drm_plane *plane);
+	struct intel_plane_regs regs;
 };
 
 struct intel_watermark_params {
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index fee6f17..06d62e70 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -187,14 +187,12 @@ int intel_check_plane(const struct drm_plane *plane,
 }
 
 static void
-ivb_update_plane(struct drm_plane *plane,
-		 struct drm_framebuffer *fb,
-		 const struct intel_plane_coords *coords)
+ivb_calc_plane(struct drm_plane *plane,
+	       struct drm_framebuffer *fb,
+	       const struct intel_plane_coords *coords)
 {
-	struct drm_device *dev = plane->dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_plane *intel_plane = to_intel_plane(plane);
-	const struct drm_i915_gem_object *obj = to_intel_framebuffer(fb)->obj;
+	const struct drm_i915_gem_object *obj;
 	int crtc_x = coords->crtc_x;
 	int crtc_y = coords->crtc_y;
 	unsigned int crtc_w = coords->crtc_w;
@@ -203,47 +201,55 @@ ivb_update_plane(struct drm_plane *plane,
 	uint32_t y = coords->src_y;
 	uint32_t src_w = coords->src_w;
 	uint32_t src_h = coords->src_h;
-	int pipe = intel_plane->pipe;
-	u32 sprctl, sprscale = 0;
-	int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
+	int pixel_size;
+	struct intel_plane_regs *regs = &intel_plane->regs;
+
+	if (!coords->visible) {
+		regs->cntr &= ~SPRITE_ENABLE;
+		/* Disable the scaler */
+		regs->scale = 0;
+		return;
+	}
 
-	sprctl = I915_READ(SPRCTL(pipe));
+	obj = to_intel_framebuffer(fb)->obj;
+	pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
 
 	/* Mask out pixel format bits in case we change it */
-	sprctl &= ~SPRITE_PIXFORMAT_MASK;
-	sprctl &= ~SPRITE_RGB_ORDER_RGBX;
-	sprctl &= ~SPRITE_YUV_BYTE_ORDER_MASK;
-	sprctl &= ~SPRITE_TILED;
+	regs->cntr &= ~(SPRITE_PIXFORMAT_MASK |
+			SPRITE_RGB_ORDER_RGBX |
+			SPRITE_YUV_BYTE_ORDER_MASK |
+			SPRITE_TILED |
+			SPRITE_ENABLE);
 
 	switch (fb->pixel_format) {
 	case DRM_FORMAT_XBGR8888:
-		sprctl |= SPRITE_FORMAT_RGBX888 | SPRITE_RGB_ORDER_RGBX;
+		regs->cntr |= SPRITE_FORMAT_RGBX888 | SPRITE_RGB_ORDER_RGBX;
 		break;
 	case DRM_FORMAT_XRGB8888:
-		sprctl |= SPRITE_FORMAT_RGBX888;
+		regs->cntr |= SPRITE_FORMAT_RGBX888;
 		break;
 	case DRM_FORMAT_YUYV:
-		sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YUYV;
+		regs->cntr |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YUYV;
 		break;
 	case DRM_FORMAT_YVYU:
-		sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YVYU;
+		regs->cntr |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YVYU;
 		break;
 	case DRM_FORMAT_UYVY:
-		sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_UYVY;
+		regs->cntr |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_UYVY;
 		break;
 	case DRM_FORMAT_VYUY:
-		sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_VYUY;
+		regs->cntr |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_VYUY;
 		break;
 	default:
 		BUG();
 	}
 
 	if (obj->tiling_mode != I915_TILING_NONE)
-		sprctl |= SPRITE_TILED;
+		regs->cntr |= SPRITE_TILED;
 
 	/* must disable */
-	sprctl |= SPRITE_TRICKLE_FEED_DISABLE;
-	sprctl |= SPRITE_ENABLE;
+	regs->cntr |= SPRITE_TRICKLE_FEED_DISABLE;
+	regs->cntr |= SPRITE_ENABLE;
 
 	/* Sizes are 0 based */
 	src_w--;
@@ -251,20 +257,68 @@ ivb_update_plane(struct drm_plane *plane,
 	crtc_w--;
 	crtc_h--;
 
-	intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size);
+	regs->scale = 0;
+	if (crtc_w != src_w || crtc_h != src_h)
+		regs->scale = SPRITE_SCALE_ENABLE | (src_w << 16) | src_h;
+
+	regs->stride = fb->pitches[0];
+	regs->pos = (crtc_y << 16) | crtc_x;
+	if (obj->tiling_mode != I915_TILING_NONE) {
+		y += fb->offsets[0] / fb->pitches[0];
+		x += fb->offsets[0] % fb->pitches[0] / pixel_size;
+
+		regs->tileoff = (y << 16) | x;
+	} else
+		regs->linoff = fb->offsets[0] + y * fb->pitches[0] + x * pixel_size;
+	regs->size = (crtc_h << 16) | crtc_w;
+	regs->surf = I915_LO_DISPBASE(regs->surf) | obj->gtt_offset;
+}
+
+static void
+ivb_commit_plane(struct drm_plane *plane)
+{
+	struct drm_device *dev = plane->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_plane *intel_plane = to_intel_plane(plane);
+	int pipe = intel_plane->pipe;
+	const struct intel_plane_regs *regs = &intel_plane->regs;
+
+	I915_WRITE(SPRKEYVAL(pipe), regs->keyval);
+	I915_WRITE(SPRKEYMAX(pipe), regs->keymaxval);
+	I915_WRITE(SPRKEYMSK(pipe), regs->keymsk);
+	I915_WRITE(SPRSTRIDE(pipe), regs->stride);
+	I915_WRITE(SPRPOS(pipe), regs->pos);
+	I915_WRITE(SPRTILEOFF(pipe), regs->tileoff);
+	I915_WRITE(SPRLINOFF(pipe), regs->linoff);
+	I915_WRITE(SPRSIZE(pipe), regs->size);
+	I915_WRITE(SPRSCALE(pipe), regs->scale);
+	I915_WRITE(SPRCTL(pipe), regs->cntr);
+	I915_WRITE(SPRSURF(pipe), regs->surf);
+}
+
+static void
+ivb_prepare_plane(struct drm_plane *plane)
+{
+	struct drm_device *dev = plane->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_plane *intel_plane = to_intel_plane(plane);
+	int pipe = intel_plane->pipe;
+	int pixel_size = plane->fb ? drm_format_plane_cpp(plane->fb->pixel_format, 0) : 0;
+	const struct intel_plane_regs *regs = &intel_plane->regs;
+
+	intel_update_sprite_watermarks(dev, pipe, regs->size & 0xffff, pixel_size);
 
 	/*
 	 * IVB workaround: must disable low power watermarks for at least
 	 * one frame before enabling scaling.  LP watermarks can be re-enabled
 	 * when scaling is disabled.
 	 */
-	if (crtc_w != src_w || crtc_h != src_h) {
+	if (regs->scale & SPRITE_SCALE_ENABLE) {
 		if (!dev_priv->sprite_scaling_enabled) {
 			dev_priv->sprite_scaling_enabled = true;
 			intel_update_watermarks(dev);
 			intel_wait_for_vblank(dev, pipe);
 		}
-		sprscale = SPRITE_SCALE_ENABLE | (src_w << 16) | src_h;
 	} else {
 		if (dev_priv->sprite_scaling_enabled) {
 			dev_priv->sprite_scaling_enabled = false;
@@ -272,24 +326,21 @@ ivb_update_plane(struct drm_plane *plane,
 			intel_update_watermarks(dev);
 		}
 	}
+}
 
-	I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]);
-	I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x);
-	if (obj->tiling_mode != I915_TILING_NONE) {
-		y += fb->offsets[0] / fb->pitches[0];
-		x += fb->offsets[0] % fb->pitches[0] / pixel_size;
-
-		I915_WRITE(SPRTILEOFF(pipe), (y << 16) | x);
-	} else {
-		unsigned long offset;
+static void
+ivb_update_plane(struct drm_plane *plane,
+		 struct drm_framebuffer *fb,
+		 const struct intel_plane_coords *coords)
+{
+	struct drm_device *dev = plane->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_plane *intel_plane = to_intel_plane(plane);
+	int pipe = intel_plane->pipe;
 
-		offset = fb->offsets[0] + y * fb->pitches[0] + x * pixel_size;
-		I915_WRITE(SPRLINOFF(pipe), offset);
-	}
-	I915_WRITE(SPRSIZE(pipe), (crtc_h << 16) | crtc_w);
-	I915_WRITE(SPRSCALE(pipe), sprscale);
-	I915_WRITE(SPRCTL(pipe), sprctl);
-	I915_MODIFY_DISPBASE(SPRSURF(pipe), obj->gtt_offset);
+	ivb_calc_plane(plane, fb, coords);
+	ivb_prepare_plane(plane);
+	ivb_commit_plane(plane);
 	POSTING_READ(SPRSURF(pipe));
 }
 
@@ -300,12 +351,12 @@ ivb_disable_plane(struct drm_plane *plane)
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_plane *intel_plane = to_intel_plane(plane);
 	int pipe = intel_plane->pipe;
+	struct intel_plane_regs *regs = &intel_plane->regs;
 
-	I915_WRITE(SPRCTL(pipe), I915_READ(SPRCTL(pipe)) & ~SPRITE_ENABLE);
+	regs->cntr &= ~SPRITE_ENABLE;
 	/* Can't leave the scaler enabled... */
-	I915_WRITE(SPRSCALE(pipe), 0);
-	/* Activate double buffered register update */
-	I915_MODIFY_DISPBASE(SPRSURF(pipe), 0);
+	regs->scale = 0;
+	ivb_commit_plane(plane);
 	POSTING_READ(SPRSURF(pipe));
 
 	dev_priv->sprite_scaling_enabled = false;
@@ -318,63 +369,52 @@ ivb_update_colorkey(struct drm_plane *plane,
 {
 	struct drm_device *dev = plane->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_plane *intel_plane;
-	u32 sprctl;
-	int ret = 0;
-
-	intel_plane = to_intel_plane(plane);
+	struct intel_plane *intel_plane = to_intel_plane(plane);
+	struct intel_plane_regs *regs = &intel_plane->regs;
 
-	I915_WRITE(SPRKEYVAL(intel_plane->pipe), key->min_value);
-	I915_WRITE(SPRKEYMAX(intel_plane->pipe), key->max_value);
-	I915_WRITE(SPRKEYMSK(intel_plane->pipe), key->channel_mask);
+	regs->keyval = key->min_value;
+	regs->keymaxval = key->max_value;
+	regs->keymsk = key->channel_mask;
 
-	sprctl = I915_READ(SPRCTL(intel_plane->pipe));
-	sprctl &= ~(SPRITE_SOURCE_KEY | SPRITE_DEST_KEY);
+	regs->cntr &= ~(SPRITE_SOURCE_KEY | SPRITE_DEST_KEY);
 	if (key->flags & I915_SET_COLORKEY_DESTINATION)
-		sprctl |= SPRITE_DEST_KEY;
+		regs->cntr |= SPRITE_DEST_KEY;
 	else if (key->flags & I915_SET_COLORKEY_SOURCE)
-		sprctl |= SPRITE_SOURCE_KEY;
-	I915_WRITE(SPRCTL(intel_plane->pipe), sprctl);
+		regs->cntr |= SPRITE_SOURCE_KEY;
 
+	ivb_commit_plane(plane);
 	POSTING_READ(SPRKEYMSK(intel_plane->pipe));
 
-	return ret;
+	return 0;
 }
 
 static void
 ivb_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key)
 {
-	struct drm_device *dev = plane->dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_plane *intel_plane;
-	u32 sprctl;
-
-	intel_plane = to_intel_plane(plane);
+	struct intel_plane *intel_plane = to_intel_plane(plane);
+	const struct intel_plane_regs *regs = &intel_plane->regs;
 
-	key->min_value = I915_READ(SPRKEYVAL(intel_plane->pipe));
-	key->max_value = I915_READ(SPRKEYMAX(intel_plane->pipe));
-	key->channel_mask = I915_READ(SPRKEYMSK(intel_plane->pipe));
+	key->min_value = regs->keyval;
+	key->max_value = regs->keymaxval;
+	key->channel_mask = regs->keymsk;
 	key->flags = 0;
 
-	sprctl = I915_READ(SPRCTL(intel_plane->pipe));
-
-	if (sprctl & SPRITE_DEST_KEY)
+	if (regs->cntr & SPRITE_DEST_KEY)
 		key->flags = I915_SET_COLORKEY_DESTINATION;
-	else if (sprctl & SPRITE_SOURCE_KEY)
+	else if (regs->cntr & SPRITE_SOURCE_KEY)
 		key->flags = I915_SET_COLORKEY_SOURCE;
 	else
 		key->flags = I915_SET_COLORKEY_NONE;
 }
 
 static void
-ilk_update_plane(struct drm_plane *plane,
-		 struct drm_framebuffer *fb,
-		 const struct intel_plane_coords *coords)
+ilk_calc_plane(struct drm_plane *plane,
+	       struct drm_framebuffer *fb,
+	       const struct intel_plane_coords *coords)
 {
 	struct drm_device *dev = plane->dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_plane *intel_plane = to_intel_plane(plane);
-	const struct drm_i915_gem_object *obj = to_intel_framebuffer(fb)->obj;
+	const struct drm_i915_gem_object *obj;
 	int crtc_x = coords->crtc_x;
 	int crtc_y = coords->crtc_y;
 	unsigned int crtc_w = coords->crtc_w;
@@ -383,47 +423,55 @@ ilk_update_plane(struct drm_plane *plane,
 	uint32_t y = coords->src_y;
 	uint32_t src_w = coords->src_w;
 	uint32_t src_h = coords->src_h;
-	int pipe = intel_plane->pipe;
-	u32 dvscntr, dvsscale;
-	int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
+	int pixel_size;
+	struct intel_plane_regs *regs = &intel_plane->regs;
+
+	if (!coords->visible) {
+		regs->cntr &= ~DVS_ENABLE;
+		/* Disable the scaler */
+		regs->scale = 0;
+		return;
+	}
 
-	dvscntr = I915_READ(DVSCNTR(pipe));
+	obj = to_intel_framebuffer(fb)->obj;
+	pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
 
 	/* Mask out pixel format bits in case we change it */
-	dvscntr &= ~DVS_PIXFORMAT_MASK;
-	dvscntr &= ~DVS_RGB_ORDER_XBGR;
-	dvscntr &= ~DVS_YUV_BYTE_ORDER_MASK;
-	dvscntr &= ~DVS_TILED;
+	regs->cntr &= ~(DVS_PIXFORMAT_MASK |
+			DVS_RGB_ORDER_XBGR |
+			DVS_YUV_BYTE_ORDER_MASK |
+			DVS_TILED |
+			DVS_ENABLE);
 
 	switch (fb->pixel_format) {
 	case DRM_FORMAT_XBGR8888:
-		dvscntr |= DVS_FORMAT_RGBX888 | DVS_RGB_ORDER_XBGR;
+		regs->cntr |= DVS_FORMAT_RGBX888 | DVS_RGB_ORDER_XBGR;
 		break;
 	case DRM_FORMAT_XRGB8888:
-		dvscntr |= DVS_FORMAT_RGBX888;
+		regs->cntr |= DVS_FORMAT_RGBX888;
 		break;
 	case DRM_FORMAT_YUYV:
-		dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YUYV;
+		regs->cntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YUYV;
 		break;
 	case DRM_FORMAT_YVYU:
-		dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YVYU;
+		regs->cntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YVYU;
 		break;
 	case DRM_FORMAT_UYVY:
-		dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_UYVY;
+		regs->cntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_UYVY;
 		break;
 	case DRM_FORMAT_VYUY:
-		dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_VYUY;
+		regs->cntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_VYUY;
 		break;
 	default:
 		BUG();
 	}
 
 	if (obj->tiling_mode != I915_TILING_NONE)
-		dvscntr |= DVS_TILED;
+		regs->cntr |= DVS_TILED;
 
 	if (IS_GEN6(dev))
-		dvscntr |= DVS_TRICKLE_FEED_DISABLE; /* must disable */
-	dvscntr |= DVS_ENABLE;
+		regs->cntr |= DVS_TRICKLE_FEED_DISABLE; /* must disable */
+	regs->cntr |= DVS_ENABLE;
 
 	/* Sizes are 0 based */
 	src_w--;
@@ -431,29 +479,70 @@ ilk_update_plane(struct drm_plane *plane,
 	crtc_w--;
 	crtc_h--;
 
-	intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size);
-
-	dvsscale = 0;
+	regs->scale = 0;
 	if (IS_GEN5(dev) || crtc_w != src_w || crtc_h != src_h)
-		dvsscale = DVS_SCALE_ENABLE | (src_w << 16) | src_h;
+		regs->scale = DVS_SCALE_ENABLE | (src_w << 16) | src_h;
 
-	I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]);
-	I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x);
+	regs->stride = fb->pitches[0];
+	regs->pos = (crtc_y << 16) | crtc_x;
 	if (obj->tiling_mode != I915_TILING_NONE) {
 		y += fb->offsets[0] / fb->pitches[0];
 		x += fb->offsets[0] % fb->pitches[0] / pixel_size;
 
-		I915_WRITE(DVSTILEOFF(pipe), (y << 16) | x);
-	} else {
-		unsigned long offset;
+		regs->tileoff = (y << 16) | x;
+	} else
+		regs->linoff = fb->offsets[0] + y * fb->pitches[0] + x * pixel_size;
+	regs->size = (crtc_h << 16) | crtc_w;
+	regs->surf = I915_LO_DISPBASE(regs->surf) | obj->gtt_offset;
+}
 
-		offset = fb->offsets[0] + y * fb->pitches[0] + x * pixel_size;
-		I915_WRITE(DVSLINOFF(pipe), offset);
-	}
-	I915_WRITE(DVSSIZE(pipe), (crtc_h << 16) | crtc_w);
-	I915_WRITE(DVSSCALE(pipe), dvsscale);
-	I915_WRITE(DVSCNTR(pipe), dvscntr);
-	I915_MODIFY_DISPBASE(DVSSURF(pipe), obj->gtt_offset);
+static void
+ilk_prepare_plane(struct drm_plane *plane)
+{
+	struct drm_device *dev = plane->dev;
+	struct intel_plane *intel_plane = to_intel_plane(plane);
+	int pipe = intel_plane->pipe;
+	int pixel_size = plane->fb ? drm_format_plane_cpp(plane->fb->pixel_format, 0) : 0;
+	const struct intel_plane_regs *regs = &intel_plane->regs;
+
+	intel_update_sprite_watermarks(dev, pipe, regs->size & 0xffff, pixel_size);
+}
+
+static void
+ilk_commit_plane(struct drm_plane *plane)
+{
+	struct drm_device *dev = plane->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_plane *intel_plane = to_intel_plane(plane);
+	int pipe = intel_plane->pipe;
+	const struct intel_plane_regs *regs = &intel_plane->regs;
+
+	I915_WRITE(DVSKEYVAL(pipe), regs->keyval);
+	I915_WRITE(DVSKEYMAX(pipe), regs->keymaxval);
+	I915_WRITE(DVSKEYMSK(pipe), regs->keymsk);
+	I915_WRITE(DVSSTRIDE(pipe), regs->stride);
+	I915_WRITE(DVSPOS(pipe), regs->pos);
+	I915_WRITE(DVSTILEOFF(pipe), regs->tileoff);
+	I915_WRITE(DVSLINOFF(pipe), regs->linoff);
+	I915_WRITE(DVSSIZE(pipe), regs->size);
+	I915_WRITE(DVSSCALE(pipe), regs->scale);
+	I915_WRITE(DVSCNTR(pipe), regs->cntr);
+	I915_WRITE(DVSSURF(pipe), regs->surf);
+}
+
+static void
+ilk_update_plane(struct drm_plane *plane,
+		 struct drm_framebuffer *fb,
+		 const struct intel_plane_coords *coords)
+{
+	struct drm_device *dev = plane->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_plane *intel_plane = to_intel_plane(plane);
+	int pipe = intel_plane->pipe;
+
+	ilk_calc_plane(plane, fb, coords);
+	ilk_prepare_plane(plane);
+	ilk_commit_plane(plane);
 	POSTING_READ(DVSSURF(pipe));
 }
 
@@ -464,21 +553,34 @@ ilk_disable_plane(struct drm_plane *plane)
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_plane *intel_plane = to_intel_plane(plane);
 	int pipe = intel_plane->pipe;
+	struct intel_plane_regs *regs = &intel_plane->regs;
 
-	I915_WRITE(DVSCNTR(pipe), I915_READ(DVSCNTR(pipe)) & ~DVS_ENABLE);
+	regs->cntr &= ~DVS_ENABLE;
 	/* Disable the scaler */
-	I915_WRITE(DVSSCALE(pipe), 0);
-	/* Flush double buffered register updates */
-	I915_MODIFY_DISPBASE(DVSSURF(pipe), 0);
+	regs->scale = 0;
+	ilk_commit_plane(plane);
 	POSTING_READ(DVSSURF(pipe));
 }
 
+void intel_calc_sprite(struct drm_plane *plane,
+		       struct drm_framebuffer *fb,
+		       const struct intel_plane_coords *coords)
+{
+	struct drm_device *dev = plane->dev;
+
+	if (INTEL_INFO(dev)->gen >= 7)
+		ivb_calc_plane(plane, fb, coords);
+	else
+		ilk_calc_plane(plane, fb, coords);
+}
+
 static void
 intel_enable_primary(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);
+	struct intel_plane_regs *regs = &intel_crtc->primary_regs;
 	int reg = DSPCNTR(intel_crtc->plane);
 
 	if (!intel_crtc->primary_disabled)
@@ -487,7 +589,8 @@ intel_enable_primary(struct drm_crtc *crtc)
 	intel_crtc->primary_disabled = false;
 	intel_update_fbc(dev);
 
-	I915_WRITE(reg, I915_READ(reg) | DISPLAY_PLANE_ENABLE);
+	regs->cntr = I915_READ(reg) | DISPLAY_PLANE_ENABLE;
+	dev_priv->display.commit_plane(crtc);
 }
 
 static void
@@ -496,12 +599,14 @@ intel_disable_primary(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);
+	struct intel_plane_regs *regs = &intel_crtc->primary_regs;
 	int reg = DSPCNTR(intel_crtc->plane);
 
 	if (intel_crtc->primary_disabled)
 		return;
 
-	I915_WRITE(reg, I915_READ(reg) & ~DISPLAY_PLANE_ENABLE);
+	regs->cntr = I915_READ(reg) & ~DISPLAY_PLANE_ENABLE;
+	dev_priv->display.commit_plane(crtc);
 
 	intel_crtc->primary_disabled = true;
 	intel_update_fbc(dev);
@@ -513,49 +618,39 @@ ilk_update_colorkey(struct drm_plane *plane,
 {
 	struct drm_device *dev = plane->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_plane *intel_plane;
-	u32 dvscntr;
-	int ret = 0;
-
-	intel_plane = to_intel_plane(plane);
+	struct intel_plane *intel_plane = to_intel_plane(plane);
+	struct intel_plane_regs *regs = &intel_plane->regs;
 
-	I915_WRITE(DVSKEYVAL(intel_plane->pipe), key->min_value);
-	I915_WRITE(DVSKEYMAX(intel_plane->pipe), key->max_value);
-	I915_WRITE(DVSKEYMSK(intel_plane->pipe), key->channel_mask);
+	regs->keyval = key->min_value;
+	regs->keymaxval = key->max_value;
+	regs->keymsk = key->channel_mask;
 
-	dvscntr = I915_READ(DVSCNTR(intel_plane->pipe));
-	dvscntr &= ~(DVS_SOURCE_KEY | DVS_DEST_KEY);
+	regs->cntr &= ~(DVS_SOURCE_KEY | DVS_DEST_KEY);
 	if (key->flags & I915_SET_COLORKEY_DESTINATION)
-		dvscntr |= DVS_DEST_KEY;
+		regs->cntr |= DVS_DEST_KEY;
 	else if (key->flags & I915_SET_COLORKEY_SOURCE)
-		dvscntr |= DVS_SOURCE_KEY;
-	I915_WRITE(DVSCNTR(intel_plane->pipe), dvscntr);
+		regs->cntr |= DVS_SOURCE_KEY;
 
+	ilk_commit_plane(plane);
 	POSTING_READ(DVSKEYMSK(intel_plane->pipe));
 
-	return ret;
+	return 0;
 }
 
 static void
 ilk_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key)
 {
-	struct drm_device *dev = plane->dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_plane *intel_plane;
-	u32 dvscntr;
-
-	intel_plane = to_intel_plane(plane);
+	struct intel_plane *intel_plane = to_intel_plane(plane);
+	const struct intel_plane_regs *regs = &intel_plane->regs;
 
-	key->min_value = I915_READ(DVSKEYVAL(intel_plane->pipe));
-	key->max_value = I915_READ(DVSKEYMAX(intel_plane->pipe));
-	key->channel_mask = I915_READ(DVSKEYMSK(intel_plane->pipe));
+	key->min_value = regs->keyval;
+	key->max_value = regs->keymaxval;
+	key->channel_mask = regs->keymsk;
 	key->flags = 0;
 
-	dvscntr = I915_READ(DVSCNTR(intel_plane->pipe));
-
-	if (dvscntr & DVS_DEST_KEY)
+	if (regs->cntr & DVS_DEST_KEY)
 		key->flags = I915_SET_COLORKEY_DESTINATION;
-	else if (dvscntr & DVS_SOURCE_KEY)
+	else if (regs->cntr & DVS_SOURCE_KEY)
 		key->flags = I915_SET_COLORKEY_SOURCE;
 	else
 		key->flags = I915_SET_COLORKEY_NONE;
@@ -793,6 +888,7 @@ static uint32_t snb_plane_formats[] = {
 int
 intel_plane_init(struct drm_device *dev, enum pipe pipe)
 {
+	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_plane *intel_plane;
 	unsigned long possible_crtcs;
 	const uint32_t *plane_formats;
@@ -815,6 +911,13 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe)
 		intel_plane->update_colorkey = ilk_update_colorkey;
 		intel_plane->get_colorkey = ilk_get_colorkey;
 
+		intel_plane->calc = ilk_calc_plane;
+		intel_plane->prepare = ilk_prepare_plane;
+		intel_plane->commit = ilk_commit_plane;
+
+		intel_plane->regs.cntr = I915_READ(DVSCNTR(pipe));
+		intel_plane->regs.surf = I915_READ(DVSSURF(pipe));
+
 		if (IS_GEN6(dev)) {
 			plane_formats = snb_plane_formats;
 			num_plane_formats = ARRAY_SIZE(snb_plane_formats);
@@ -831,6 +934,13 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe)
 		intel_plane->update_colorkey = ivb_update_colorkey;
 		intel_plane->get_colorkey = ivb_get_colorkey;
 
+		intel_plane->calc = ivb_calc_plane;
+		intel_plane->prepare = ivb_prepare_plane;
+		intel_plane->commit = ivb_commit_plane;
+
+		intel_plane->regs.cntr = I915_READ(SPRCTL(pipe));
+		intel_plane->regs.surf = I915_READ(SPRSURF(pipe));
+
 		plane_formats = snb_plane_formats;
 		num_plane_formats = ARRAY_SIZE(snb_plane_formats);
 		break;
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 45/51] drm/i915: Implement atomic modesetting
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (43 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 44/51] drm/i915: Split sprite " ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 46/51] drm/i915: Add support for atomic modesetting completion events ville.syrjala
                   ` (5 subsequent siblings)
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Implement the mandatory hooks for the atomic modeset ioctl.

The code first makes a backup of the current state, then proceeds to
modify the state as properties are modified. After all the properties
have been handled the new state is checked, and if everything checks
out, the new state is commited to hardware. Finally we clean up any
temporary storage.

In theory everything is checked before the hardware state is clobbered,
so there should be no need for rollback. But as the current modesetting
code can still return errors from some of of the operation, the rollback
code is included.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/Makefile        |    1 +
 drivers/gpu/drm/i915/intel_atomic.c  | 1625 ++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_display.c |    5 +
 drivers/gpu/drm/i915/intel_drv.h     |    3 +
 include/drm/drm_crtc.h               |    2 +
 5 files changed, 1636 insertions(+), 0 deletions(-)
 create mode 100644 drivers/gpu/drm/i915/intel_atomic.c

diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 0f2c549..cca14e4 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -16,6 +16,7 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o \
 	  i915_gem_tiling.o \
 	  i915_sysfs.o \
 	  i915_trace_points.o \
+	  intel_atomic.o \
 	  intel_display.o \
 	  intel_crt.o \
 	  intel_lvds.o \
diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c
new file mode 100644
index 0000000..4899f8c
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_atomic.c
@@ -0,0 +1,1625 @@
+/*
+ * Copyright (C) 2011-2012 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ * Ville Syrjälä <ville.syrjala@linux.intel.com>
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+
+#include "intel_drv.h"
+
+static struct drm_property *prop_src_x;
+static struct drm_property *prop_src_y;
+static struct drm_property *prop_src_w;
+static struct drm_property *prop_src_h;
+static struct drm_property *prop_crtc_x;
+static struct drm_property *prop_crtc_y;
+static struct drm_property *prop_crtc_w;
+static struct drm_property *prop_crtc_h;
+static struct drm_property *prop_fb_id;
+static struct drm_property *prop_crtc_id;
+static struct drm_property *prop_mode;
+static struct drm_property *prop_connector_ids;
+static struct drm_property *prop_cursor_id;
+static struct drm_property *prop_cursor_x;
+static struct drm_property *prop_cursor_y;
+static struct drm_property *prop_cursor_w;
+static struct drm_property *prop_cursor_h;
+
+struct intel_plane_state {
+	struct drm_plane *plane;
+	struct intel_plane_coords coords;
+	bool dirty;
+	bool pinned;
+	bool changed;
+
+	struct {
+		struct drm_crtc *crtc;
+		struct drm_framebuffer *fb;
+		uint32_t src_x, src_y, src_w, src_h;
+		int32_t crtc_x, crtc_y;
+		uint32_t crtc_w, crtc_h;
+	} old;
+};
+
+struct intel_crtc_state {
+	struct drm_crtc *crtc;
+	bool mode_dirty;
+	bool fb_dirty;
+	bool cursor_dirty;
+	bool active_dirty;
+	bool pinned;
+	bool cursor_pinned;
+	unsigned long connectors_bitmask;
+	unsigned long encoders_bitmask;
+	bool changed;
+
+	struct {
+		bool enabled;
+		struct drm_display_mode mode;
+		struct drm_framebuffer *fb;
+		int x, y;
+		unsigned long connectors_bitmask;
+		unsigned long encoders_bitmask;
+
+		struct drm_i915_gem_object *cursor_bo;
+		uint32_t cursor_handle;
+		int16_t cursor_x, cursor_y;
+		int16_t cursor_width, cursor_height;
+		bool cursor_visible;
+	} old;
+};
+
+struct intel_atomic_state {
+	struct drm_file *file;
+	struct intel_plane_state *plane;
+	struct intel_crtc_state *crtc;
+	bool dirty;
+	bool restore_state;
+	bool restore_hw;
+	unsigned int flags;
+	uint64_t user_data;
+	struct drm_plane *saved_planes;
+	struct intel_crtc *saved_crtcs;
+	struct drm_connector *saved_connectors;
+	struct drm_encoder *saved_encoders;
+};
+
+static void update_connectors_bitmask(struct drm_crtc *crtc,
+				      unsigned long *connectors_bitmask)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_connector *connector;
+	unsigned int i = 0;
+
+	*connectors_bitmask = 0;
+
+	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+		if (connector->encoder && connector->encoder->crtc == crtc)
+			__set_bit(i, connectors_bitmask);
+
+		i++;
+	}
+}
+
+static void update_encoders_bitmask(struct drm_crtc *crtc,
+				    unsigned long *encoders_bitmask)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_encoder *encoder;
+	unsigned int i = 0;
+
+	*encoders_bitmask = 0;
+
+	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+		if (encoder->crtc == crtc)
+			__set_bit(i, encoders_bitmask);
+
+		i++;
+	}
+}
+
+static int process_connectors(struct intel_crtc_state *s, const uint32_t *ids, int count_ids)
+{
+	struct drm_crtc *crtc = s->crtc;
+	struct drm_device *dev = crtc->dev;
+	struct drm_connector *connectors[count_ids];
+	struct drm_connector *connector;
+	struct drm_encoder *encoder;
+	int i;
+
+	for (i = 0; i < count_ids; i++) {
+		struct drm_encoder *encoder;
+		const struct drm_connector_helper_funcs *connector_funcs;
+		struct drm_mode_object *obj;
+		int j;
+
+		/* don't accept duplicates */
+		for (j = i + 1; j < count_ids; j++)
+			if (ids[i] == ids[j])
+				return -EINVAL;
+
+		obj = drm_mode_object_find(dev, ids[i], DRM_MODE_OBJECT_CONNECTOR);
+		if (!obj) {
+			DRM_DEBUG_KMS("Unknown connector ID %u\n", ids[i]);
+			return -ENOENT;
+		}
+
+		connector = obj_to_connector(obj);
+		connector_funcs = connector->helper_private;
+
+		encoder = connector_funcs->best_encoder(connector);
+
+		if (!drm_encoder_crtc_ok(encoder, crtc))
+			return -EINVAL;
+
+		connectors[i] = connector;
+	}
+
+	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+		const struct drm_connector_helper_funcs *connector_funcs =
+			connector->helper_private;
+
+		for (i = 0; i < count_ids; i++) {
+			if (connector == connectors[i])
+				break;
+		}
+
+		/* this connector isn't in the set */
+		if (i == count_ids) {
+			/* remove the link to the encoder if this crtc was set to drive it */
+			if (connector->encoder && connector->encoder->crtc == crtc)
+				connector->encoder = NULL;
+			continue;
+		}
+
+		encoder = connector_funcs->best_encoder(connector);
+
+		connector->encoder = encoder;
+		encoder->crtc = crtc;
+	}
+
+	/* prune dangling encoder->crtc links pointing to this crtc  */
+	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+		if (encoder->crtc == crtc && !drm_helper_encoder_in_use(encoder))
+			encoder->crtc = NULL;
+	}
+
+	update_connectors_bitmask(s->crtc, &s->connectors_bitmask);
+	update_encoders_bitmask(s->crtc, &s->encoders_bitmask);
+
+	return 0;
+}
+
+static size_t intel_atomic_state_size(const struct drm_device *dev)
+{
+	struct intel_atomic_state *state;
+	unsigned int num_connector = dev->mode_config.num_connector;
+	unsigned int num_encoder = dev->mode_config.num_encoder;
+	unsigned int num_crtc = dev->mode_config.num_crtc;
+	unsigned int num_plane = dev->mode_config.num_plane;
+
+	return sizeof *state +
+		num_crtc * sizeof state->crtc[0] +
+		num_plane * sizeof state->plane[0] +
+		num_connector * sizeof state->saved_connectors[0] +
+		num_encoder * sizeof state->saved_encoders[0] +
+		num_crtc * sizeof state->saved_crtcs[0] +
+		num_plane * sizeof state->saved_planes[0];
+}
+
+
+static void populate_old(struct drm_device *dev)
+{
+	struct drm_encoder *encoder;
+	struct drm_connector *connector;
+
+	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
+		encoder->old_crtc = encoder->crtc;
+
+	list_for_each_entry(connector, &dev->mode_config.connector_list, head)
+		connector->old_encoder = connector->encoder;
+}
+
+static void *intel_atomic_begin(struct drm_device *dev, struct drm_file *file,
+				uint32_t flags, uint64_t user_data)
+{
+	struct intel_atomic_state *state;
+	struct drm_plane *plane;
+	struct drm_crtc *crtc;
+	struct drm_connector *connector;
+	struct drm_encoder *encoder;
+	unsigned int num_connector = dev->mode_config.num_connector;
+	unsigned int num_encoder = dev->mode_config.num_encoder;
+	unsigned int num_crtc = dev->mode_config.num_crtc;
+	unsigned int num_plane = dev->mode_config.num_plane;
+	int i;
+
+	state = kzalloc(intel_atomic_state_size(dev), GFP_KERNEL);
+	if (!state)
+		return ERR_PTR(-ENOMEM);
+
+	state->flags = flags;
+	state->file = file;
+	state->user_data = user_data;
+
+	state->crtc = (struct intel_crtc_state *)(state + 1);
+	state->plane = (struct intel_plane_state  *)(state->crtc + num_crtc);
+
+	state->saved_connectors = (struct drm_connector *)(state->plane + num_plane);
+	state->saved_encoders = (struct drm_encoder *)(state->saved_connectors + num_connector);
+	state->saved_crtcs = (struct intel_crtc *)(state->saved_encoders + num_encoder);
+	state->saved_planes = (struct drm_plane *)(state->saved_crtcs + num_crtc);
+
+	populate_old(dev);
+
+	i = 0;
+	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+		struct intel_crtc_state *s = &state->crtc[i++];
+		struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+		s->crtc = crtc;
+		s->old.cursor_bo = intel_crtc->cursor_bo;
+		s->old.cursor_x = intel_crtc->cursor_x;
+		s->old.cursor_y = intel_crtc->cursor_y;
+		s->old.cursor_width = intel_crtc->cursor_width;
+		s->old.cursor_height = intel_crtc->cursor_height;
+		s->old.cursor_visible = intel_crtc->cursor_visible;
+
+		/* save current config */
+		s->old.enabled = crtc->enabled;
+		s->old.mode = crtc->mode;
+		s->old.fb = crtc->fb;
+		s->old.x = crtc->x;
+		s->old.y = crtc->y;
+
+		update_connectors_bitmask(crtc, &s->connectors_bitmask);
+		update_encoders_bitmask(crtc, &s->encoders_bitmask);
+
+		s->old.connectors_bitmask = s->connectors_bitmask;
+		s->old.encoders_bitmask = s->encoders_bitmask;
+	}
+
+	i = 0;
+	list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
+		struct intel_plane_state *s = &state->plane[i++];
+
+		s->plane = plane;
+
+		/* save current config */
+		s->old.crtc = plane->crtc;
+		s->old.fb = plane->fb;
+		s->old.src_x = plane->src_x;
+		s->old.src_y = plane->src_y;
+		s->old.src_w = plane->src_w;
+		s->old.src_h = plane->src_h;
+		s->old.crtc_x = plane->crtc_x;
+		s->old.crtc_y = plane->crtc_y;
+		s->old.crtc_w = plane->crtc_w;
+		s->old.crtc_h = plane->crtc_h;
+	}
+
+	i = 0;
+	list_for_each_entry(connector, &dev->mode_config.connector_list, head)
+		state->saved_connectors[i++] = *connector;
+	i = 0;
+	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
+		state->saved_encoders[i++] = *encoder;
+	i = 0;
+	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+		struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+		state->saved_crtcs[i++] = *intel_crtc;
+	}
+	i = 0;
+	list_for_each_entry(plane, &dev->mode_config.plane_list, head)
+		state->saved_planes[i++] = *plane;
+
+	state->file = file;
+
+	return state;
+}
+
+static int plane_set(struct intel_atomic_state *s,
+		     struct intel_plane_state *state,
+		     struct drm_property *prop,
+		     uint64_t value)
+{
+	struct drm_plane *plane = state->plane;
+	struct drm_mode_object *obj;
+
+	state->changed = true;
+
+	if (prop == prop_src_x) {
+		plane->src_x = value;
+	} else if (prop == prop_src_y) {
+		plane->src_y = value;
+	} else if (prop == prop_src_w) {
+		plane->src_w = value;
+	} else if (prop == prop_src_h) {
+		plane->src_h = value;
+	} else if (prop == prop_crtc_x) {
+		plane->crtc_x = value;
+	} else if (prop == prop_crtc_y) {
+		plane->crtc_y = value;
+	} else if (prop == prop_crtc_w) {
+		plane->crtc_w = value;
+	} else if (prop == prop_crtc_h) {
+		plane->crtc_h = value;
+	} else if (prop == prop_crtc_id) {
+		if (value) {
+			obj = drm_mode_object_find(plane->dev, value, DRM_MODE_OBJECT_CRTC);
+			if (!obj) {
+				DRM_DEBUG_KMS("Unknown CRTC ID %llu\n", value);
+				return -ENOENT;
+			}
+			plane->crtc = obj_to_crtc(obj);
+		} else
+			plane->crtc = NULL;
+	} else if (prop == prop_fb_id) {
+		if (value) {
+			obj = drm_mode_object_find(plane->dev, value, DRM_MODE_OBJECT_FB);
+			if (!obj) {
+				DRM_DEBUG_KMS("Unknown framebuffer ID %llu\n", value);
+				return -ENOENT;
+			}
+			plane->fb = obj_to_fb(obj);
+		} else
+			plane->fb = NULL;
+	} else
+		return -ENOENT;
+
+	s->restore_state = true;
+
+	return 0;
+}
+
+static int crtc_set(struct intel_atomic_state *s,
+		    struct intel_crtc_state *state,
+		    struct drm_property *prop,
+		    uint64_t value, const void *blob_data)
+{
+	struct drm_crtc *crtc = state->crtc;
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	struct drm_mode_object *obj;
+
+	state->changed = true;
+
+	if (prop == prop_src_x) {
+		crtc->x = value;
+	} else if (prop == prop_src_y) {
+		crtc->y = value;
+	} else if (prop == prop_mode) {
+		const struct drm_mode_modeinfo *umode = blob_data;
+
+		if (value != 0 && value != sizeof *umode) {
+			DRM_DEBUG_KMS("Invalid mode length\n");
+			return -EINVAL;
+		}
+
+		if (value) {
+			struct drm_display_mode *mode;
+			int ret;
+
+			mode = drm_mode_create(crtc->dev);
+			if (!mode)
+				return -ENOMEM;
+
+			ret = drm_crtc_convert_umode(mode, umode);
+			if (ret) {
+				DRM_DEBUG_KMS("Invalid mode\n");
+				drm_mode_debug_printmodeline(mode);
+				drm_mode_destroy(crtc->dev, mode);
+				return ret;
+			}
+
+			drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
+
+			crtc->mode = *mode;
+			crtc->enabled = true;
+			drm_mode_destroy(crtc->dev, mode);
+		} else
+			crtc->enabled = false;
+	} else if (prop == prop_fb_id) {
+		if (value) {
+			obj = drm_mode_object_find(crtc->dev, value, DRM_MODE_OBJECT_FB);
+			if (!obj) {
+				DRM_DEBUG_KMS("Unknown framebuffer ID %llu\n", value);
+				return -ENOENT;
+			}
+			crtc->fb = obj_to_fb(obj);
+		} else
+			crtc->fb = NULL;
+	} else if (prop == prop_connector_ids) {
+		const uint32_t *ids = blob_data;
+		uint64_t count_ids = value / sizeof(uint32_t);
+		int ret;
+
+		if (value & 3) {
+			DRM_DEBUG_KMS("Invalid connectors length\n");
+			return -EINVAL;
+		}
+
+		if (count_ids > crtc->dev->mode_config.num_connector) {
+			DRM_DEBUG_KMS("Too many connectors specified\n");
+			return -ERANGE;
+		}
+
+		ret = process_connectors(state, ids, count_ids);
+		if (ret)
+			return ret;
+	} else if (prop == prop_cursor_id) {
+		intel_crtc->cursor_handle = value;
+	} else if (prop == prop_cursor_x) {
+		intel_crtc->cursor_x = value;
+	} else if (prop == prop_cursor_y) {
+		intel_crtc->cursor_y = value;
+	} else if (prop == prop_cursor_w) {
+		if (value != 0 && value != 64) {
+			DRM_DEBUG_KMS("only 64x64 cursor sprites are supported\n");
+			return -EINVAL;
+		}
+		intel_crtc->cursor_width = value;
+	} else if (prop == prop_cursor_h) {
+		if (value != 0 && value != 64) {
+			DRM_DEBUG_KMS("only 64x64 cursor sprites are supported\n");
+			return -EINVAL;
+		}
+		intel_crtc->cursor_height = value;
+	} else
+		return -ENOENT;
+
+	s->restore_state = true;
+
+	return 0;
+}
+
+static void crtc_compute_dirty(struct intel_atomic_state *s,
+			       struct intel_crtc_state *state)
+{
+	struct drm_crtc *crtc = state->crtc;
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+	/* if no properties were specified nothing is dirty */
+	if (!state->changed)
+		return;
+
+	/* fb/pan changed? */
+	if (crtc->x != state->old.x ||
+	    crtc->y != state->old.y ||
+	    crtc->fb != state->old.fb) {
+		/* FIXME do we need a full modeset sometimes? */
+		state->fb_dirty = true;
+	}
+
+	/* enabled <-> disabled? */
+	if (crtc->enabled != state->old.enabled) {
+		state->mode_dirty = true;
+		state->active_dirty = true;
+	}
+
+	/* mode changed? */
+	if (crtc->enabled && state->old.enabled &&
+	    !drm_mode_equal(&crtc->mode, &state->old.mode)) {
+		state->mode_dirty = true;
+
+		if (crtc->mode.hdisplay != state->old.mode.hdisplay ||
+		    crtc->mode.vdisplay != state->old.mode.vdisplay)
+			state->active_dirty = true;
+	}
+
+	/* connectors changed? */
+	if (state->connectors_bitmask != state->old.connectors_bitmask ||
+	    state->encoders_bitmask != state->old.encoders_bitmask)
+		state->mode_dirty = true;
+
+	/* cursor changed? */
+	if (intel_crtc->cursor_handle != state->old.cursor_handle ||
+	    intel_crtc->cursor_x != state->old.cursor_x ||
+	    intel_crtc->cursor_y != state->old.cursor_y ||
+	    intel_crtc->cursor_width != state->old.cursor_width ||
+	    intel_crtc->cursor_height != state->old.cursor_height)
+		state->cursor_dirty = true;
+
+	if (state->fb_dirty || state->mode_dirty || state->cursor_dirty)
+		s->dirty = true;
+}
+
+static void plane_compute_dirty(struct intel_atomic_state *s,
+				struct intel_plane_state *state)
+{
+	struct drm_plane *plane = state->plane;
+
+	/* if no properties were specified nothing is dirty */
+	if (!state->changed)
+		return;
+
+	if (plane->src_x != state->old.src_x ||
+	    plane->src_y != state->old.src_x ||
+	    plane->src_w != state->old.src_x ||
+	    plane->src_h != state->old.src_x ||
+	    plane->crtc_x != state->old.crtc_x ||
+	    plane->crtc_y != state->old.crtc_y ||
+	    plane->crtc_w != state->old.crtc_w ||
+	    plane->crtc_h != state->old.crtc_h ||
+	    plane->crtc != state->old.crtc ||
+	    plane->fb != state->old.fb)
+		state->dirty = true;
+
+	if (state->dirty)
+		s->dirty = true;
+}
+
+static struct intel_plane_state *get_plane_state(const struct drm_device *dev,
+						 struct intel_atomic_state *state,
+						 const struct drm_plane *plane)
+{
+	int i;
+
+	for (i = 0; i < dev->mode_config.num_plane; i++)
+		if (plane == state->plane[i].plane)
+			return &state->plane[i];
+
+	return NULL;
+}
+
+static struct intel_crtc_state *get_crtc_state(const struct drm_device *dev,
+					       struct intel_atomic_state *state,
+					       const struct drm_crtc *crtc)
+{
+	int i;
+
+	for (i = 0; i < dev->mode_config.num_crtc; i++)
+		if (crtc == state->crtc[i].crtc)
+			return &state->crtc[i];
+
+	return NULL;
+}
+
+static void crtc_prepare(struct intel_crtc_state *st,
+			 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);
+	struct intel_encoder *intel_encoder;
+
+	dev_priv->display.crtc_disable(&intel_crtc->base);
+
+	/* FIXME need to check where this stuff is used really */
+	list_for_each_entry(intel_encoder, &dev->mode_config.encoder_list, base.head) {
+		if (intel_encoder->base.crtc == crtc)
+			intel_encoder->connectors_active = false;
+	}
+}
+
+static int crtc_set_base(struct drm_crtc *crtc)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	return dev_priv->display.update_plane(crtc, crtc->fb, crtc->x, crtc->y);
+}
+
+static int crtc_mode_set(struct drm_crtc *crtc)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct drm_encoder *encoder;
+	int pipe = to_intel_crtc(crtc)->pipe;
+	int ret;
+
+	if (!crtc->enabled) {
+		dev_priv->display.off(crtc);
+		return 0;
+	}
+
+	drm_vblank_pre_modeset(dev, pipe);
+
+	ret = dev_priv->display.crtc_mode_set(crtc, &crtc->mode, &crtc->hwmode,
+					      crtc->x, crtc->y, crtc->fb);
+	if (!ret)
+		ret = dev_priv->display.update_plane(crtc, crtc->fb, crtc->x, crtc->y);
+
+	if (!ret) {
+		intel_update_watermarks(dev);
+
+		if (HAS_PCH_SPLIT(dev))
+			intel_update_linetime_watermarks(dev, pipe, &crtc->hwmode);
+	}
+
+	drm_vblank_post_modeset(dev, pipe);
+
+	if (ret)
+		return ret;
+
+	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+		const struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
+
+		if (encoder->crtc != crtc)
+			continue;
+
+		encoder_funcs->mode_set(encoder, &crtc->mode, &crtc->hwmode);
+	}
+
+	return 0;
+}
+
+static void crtc_commit(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);
+	struct intel_encoder *intel_encoder;
+
+	if (!crtc->enabled)
+		return;
+
+	dev_priv->display.crtc_enable(&intel_crtc->base);
+
+	/* FIXME need to check where this stuff is used really */
+	/* FIXME need to update DPMS state somewhere */
+	list_for_each_entry(intel_encoder, &dev->mode_config.encoder_list, base.head) {
+		if (intel_encoder->base.crtc == crtc)
+			intel_encoder->connectors_active = true;
+	}
+}
+
+static void unpin_cursors(struct drm_device *dev,
+			  struct intel_atomic_state *s)
+{
+	int i;
+
+	for (i = 0; i < dev->mode_config.num_crtc; i++) {
+		struct intel_crtc_state *st = &s->crtc[i];
+		struct drm_crtc *crtc = st->crtc;
+		struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+		if (!st->cursor_pinned)
+			continue;
+
+		intel_crtc_cursor_bo_unref(crtc, intel_crtc->cursor_bo);
+
+		st->cursor_pinned = false;
+	}
+}
+
+static int pin_cursors(struct drm_device *dev,
+			struct intel_atomic_state *s)
+{
+	int i, ret;
+
+	for (i = 0; i < dev->mode_config.num_crtc; i++) {
+		struct intel_crtc_state *st = &s->crtc[i];
+		struct drm_crtc *crtc = st->crtc;
+		struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+		if (!st->cursor_dirty)
+			continue;
+
+		ret = intel_crtc_cursor_prepare(crtc, s->file,
+						intel_crtc->cursor_handle,
+						intel_crtc->cursor_width,
+						intel_crtc->cursor_height,
+						&intel_crtc->cursor_bo,
+						&intel_crtc->cursor_addr);
+		if (ret)
+			goto unpin;
+
+		st->cursor_pinned = true;
+	}
+
+	return 0;
+
+unpin:
+	unpin_cursors(dev, s);
+
+	return ret;
+}
+
+static void unpin_old_cursors(struct drm_device *dev,
+			      struct intel_atomic_state *s)
+{
+	int i;
+
+	for (i = 0; i < dev->mode_config.num_crtc; i++) {
+		struct intel_crtc_state *st = &s->crtc[i];
+		struct drm_crtc *crtc = st->crtc;
+
+		if (!st->cursor_dirty)
+			continue;
+
+		if (!st->old.cursor_bo)
+			continue;
+
+		intel_crtc_cursor_bo_unref(crtc, st->old.cursor_bo);
+	}
+}
+
+static void unpin_fbs(struct drm_device *dev,
+		      struct intel_atomic_state *s)
+{
+	int i;
+
+	for (i = dev->mode_config.num_plane - 1; i >= 0; i--) {
+		struct intel_plane_state *st = &s->plane[i];
+		struct drm_plane *plane = st->plane;
+		struct drm_i915_gem_object *obj;
+
+		if (!st->pinned)
+			continue;
+
+		obj = to_intel_framebuffer(plane->fb)->obj;
+
+		mutex_lock(&dev->struct_mutex);
+		intel_unpin_fb_obj(obj);
+		mutex_unlock(&dev->struct_mutex);
+
+		st->pinned = false;
+	}
+
+	for (i = dev->mode_config.num_crtc - 1; i >= 0; i--) {
+		struct intel_crtc_state *st = &s->crtc[i];
+		struct drm_crtc *crtc = st->crtc;
+		struct drm_i915_gem_object *obj;
+
+		if (!st->pinned)
+			continue;
+
+		obj = to_intel_framebuffer(crtc->fb)->obj;
+
+		mutex_lock(&dev->struct_mutex);
+		intel_unpin_fb_obj(obj);
+		mutex_unlock(&dev->struct_mutex);
+
+		st->pinned = false;
+	}
+}
+
+static int pin_fbs(struct drm_device *dev,
+		   struct intel_atomic_state *s)
+{
+	int i, ret;
+
+	for (i = 0; i < dev->mode_config.num_crtc; i++) {
+		struct intel_crtc_state *st = &s->crtc[i];
+		struct drm_crtc *crtc = st->crtc;
+		struct drm_i915_gem_object *obj;
+
+		if (!st->fb_dirty)
+			continue;
+
+		if (!crtc->fb)
+			continue;
+
+		obj = to_intel_framebuffer(crtc->fb)->obj;
+
+		mutex_lock(&dev->struct_mutex);
+		ret = intel_pin_and_fence_fb_obj(dev, obj, NULL);
+		mutex_unlock(&dev->struct_mutex);
+
+		if (ret)
+			goto unpin;
+
+		st->pinned = true;
+	}
+
+	for (i = 0; i < dev->mode_config.num_plane; i++) {
+		struct intel_plane_state *st = &s->plane[i];
+		struct drm_plane *plane = st->plane;
+		struct drm_i915_gem_object *obj;
+
+		if (!st->dirty)
+			continue;
+
+		if (!plane->fb)
+			continue;
+
+		obj = to_intel_framebuffer(plane->fb)->obj;
+
+		mutex_lock(&dev->struct_mutex);
+		ret = intel_pin_and_fence_fb_obj(dev, obj, NULL);
+		mutex_unlock(&dev->struct_mutex);
+
+		if (ret)
+			goto unpin;
+
+		st->pinned = true;
+	}
+
+	return 0;
+
+ unpin:
+	unpin_fbs(dev, s);
+
+	return ret;
+}
+
+static void unpin_old_fbs(struct drm_device *dev,
+			  struct intel_atomic_state *s)
+{
+	int i;
+
+	for (i = 0; i < dev->mode_config.num_crtc; i++) {
+		struct intel_crtc_state *st = &s->crtc[i];
+		struct drm_i915_gem_object *obj;
+
+		if (!st->fb_dirty)
+			continue;
+
+		if (!st->old.fb)
+			continue;
+
+		obj = to_intel_framebuffer(st->old.fb)->obj;
+
+		mutex_lock(&dev->struct_mutex);
+		intel_unpin_fb_obj(obj);
+		mutex_unlock(&dev->struct_mutex);
+	}
+
+	for (i = 0; i < dev->mode_config.num_plane; i++) {
+		struct intel_plane_state *st = &s->plane[i];
+		struct drm_i915_gem_object *obj;
+
+		if (!st->dirty)
+			continue;
+
+		if (!st->old.fb)
+			continue;
+
+		obj = to_intel_framebuffer(st->old.fb)->obj;
+
+		mutex_lock(&dev->struct_mutex);
+		intel_unpin_fb_obj(obj);
+		mutex_unlock(&dev->struct_mutex);
+	}
+}
+
+static void update_plane_obj(struct drm_device *dev,
+			     struct intel_atomic_state *s)
+{
+	int i;
+
+	for (i = 0; i < dev->mode_config.num_plane; i++) {
+		struct intel_plane_state *st = &s->plane[i];
+		struct drm_plane *plane = st->plane;
+		struct intel_plane *intel_plane = to_intel_plane(plane);
+
+		if (!st->dirty)
+			continue;
+
+		if (plane->fb)
+			intel_plane->obj = to_intel_framebuffer(plane->fb)->obj;
+		else
+			intel_plane->obj = NULL;
+	}
+}
+
+/* FIXME need to refactor the sprite code some more */
+int intel_disable_plane_nopin(struct drm_plane *plane);
+int intel_commit_plane_nopin(struct drm_plane *plane,
+			     struct drm_crtc *crtc,
+			     struct drm_framebuffer *fb,
+			     const struct intel_plane_coords *coords);
+
+static void swap_old_new(struct drm_device *dev,
+			 struct intel_atomic_state *s)
+{
+	struct drm_encoder *encoder;
+	struct drm_connector *connector;
+	int i;
+
+	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
+		swap(encoder->crtc, encoder->old_crtc);
+
+	list_for_each_entry(connector, &dev->mode_config.connector_list, head)
+		swap(connector->encoder, connector->old_encoder);
+
+	for (i = 0; i < dev->mode_config.num_crtc; i++) {
+		struct intel_crtc_state *st = &s->crtc[i];
+		struct drm_crtc *crtc = st->crtc;
+
+		swap(crtc->enabled, st->old.enabled);
+	}
+}
+
+static int apply_config(struct drm_device *dev,
+			struct intel_atomic_state *s)
+{
+	int i, ret;
+
+	/*
+	 * FIXME
+`	 * Hackish way to make crtc_disable() see the current
+	 * state (actually just some select pieces of it).
+	 */
+	swap_old_new(dev, s);
+
+	for (i = 0; i < dev->mode_config.num_crtc; i++) {
+		struct intel_crtc_state *st = &s->crtc[i];
+
+		mutex_lock(&dev->struct_mutex);
+
+		if (st->mode_dirty) {
+			/* wait for pending MI_WAIT_FOR_EVENTs */
+			if (st->old.fb)
+				intel_finish_fb(st->old.fb);
+		}
+
+		mutex_unlock(&dev->struct_mutex);
+
+		if (!st->mode_dirty)
+			continue;
+
+		crtc_prepare(st, st->crtc);
+	}
+
+	/* Undo the hack above. */
+	swap_old_new(dev, s);
+
+	for (i = 0; i < dev->mode_config.num_crtc; i++) {
+		struct intel_crtc_state *st = &s->crtc[i];
+
+		if (!st->mode_dirty)
+			continue;
+
+		ret = crtc_mode_set(st->crtc);
+		if (ret)
+			return ret;
+	}
+
+	for (i = 0; i < dev->mode_config.num_crtc; i++) {
+		struct intel_crtc_state *st = &s->crtc[i];
+		struct drm_crtc *crtc = st->crtc;
+		int j;
+
+		if (st->mode_dirty)
+			crtc_commit(crtc);
+		else if (st->fb_dirty) {
+			ret = crtc_set_base(st->crtc);
+			if (ret)
+				return ret;
+		}
+
+		/*
+		 * FIXME these should happen alongside the primary plane setup
+		 * which occurs inside the crtc_enable() hook.
+		 */
+
+		if (st->cursor_dirty) {
+			struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+			intel_crtc_cursor_commit(crtc,
+						 intel_crtc->cursor_handle,
+						 intel_crtc->cursor_width,
+						 intel_crtc->cursor_height,
+						 intel_crtc->cursor_bo,
+						 intel_crtc->cursor_addr);
+		}
+
+		for (j = 0; j < dev->mode_config.num_plane; j++) {
+			struct intel_plane_state *pst = &s->plane[j];
+			struct drm_plane *plane = pst->plane;
+			struct intel_plane *intel_plane = to_intel_plane(plane);
+
+			if (!pst->dirty)
+				continue;
+
+			if (pst->coords.visible && plane->crtc == crtc)
+				intel_plane->update_plane(plane, plane->fb, &pst->coords);
+			else if (!pst->coords.visible && pst->old.crtc == crtc)
+				intel_plane->disable_plane(plane);
+		}
+	}
+
+	/* don't restore the old state in end() */
+	s->dirty = false;
+	s->restore_state = false;
+
+	return 0;
+}
+
+static void restore_state(struct drm_device *dev,
+			  struct intel_atomic_state *s)
+{
+	int i;
+	struct drm_connector *connector;
+	struct drm_encoder *encoder;
+	struct drm_crtc *crtc;
+	struct drm_plane *plane;
+
+	i = 0;
+	list_for_each_entry(connector, &dev->mode_config.connector_list, head)
+		*connector = s->saved_connectors[i++];
+	i = 0;
+	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
+		*encoder = s->saved_encoders[i++];
+	i = 0;
+	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+		struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+		intel_crtc->base = s->saved_crtcs[i].base;
+		intel_crtc->cursor_bo = s->saved_crtcs[i].cursor_bo;
+		intel_crtc->cursor_addr = s->saved_crtcs[i].cursor_addr;
+		intel_crtc->cursor_handle = s->saved_crtcs[i].cursor_handle;
+		intel_crtc->cursor_x = s->saved_crtcs[i].cursor_x;
+		intel_crtc->cursor_y = s->saved_crtcs[i].cursor_y;
+		intel_crtc->cursor_width = s->saved_crtcs[i].cursor_width;
+		intel_crtc->cursor_height = s->saved_crtcs[i].cursor_height;
+		intel_crtc->cursor_visible = s->saved_crtcs[i].cursor_visible;
+
+		i++;
+	}
+	i = 0;
+	list_for_each_entry(plane, &dev->mode_config.plane_list, head)
+		*plane = s->saved_planes[i++];
+
+	/* FIXME props etc. */
+
+	/* was the hardware state clobbered? */
+	if (s->restore_hw)
+		apply_config(dev, s);
+}
+
+static int intel_atomic_set(struct drm_device *dev, void *state,
+			    struct drm_mode_object *obj,
+			    struct drm_property *prop,
+			    uint64_t value, void *blob_data)
+{
+	struct intel_atomic_state *s = state;
+	int ret = -EINVAL;
+
+	switch (obj->type) {
+	case DRM_MODE_OBJECT_PLANE:
+		ret = plane_set(s, get_plane_state(dev, s, obj_to_plane(obj)), prop, value);
+		break;
+	case DRM_MODE_OBJECT_CRTC:
+		ret = crtc_set(s, get_crtc_state(dev, s, obj_to_crtc(obj)), prop, value, blob_data);
+		break;
+	default:
+		break;
+	}
+
+	kfree(blob_data);
+
+	return ret;
+}
+
+int intel_check_plane(const struct drm_plane *plane,
+		      const struct drm_crtc *crtc,
+		      const struct drm_framebuffer *fb,
+		      struct intel_plane_coords *st);
+
+static void dirty_planes(const struct drm_device *dev,
+			 struct intel_atomic_state *state,
+			 const struct drm_crtc *crtc)
+{
+	int i;
+
+	for (i = 0; i < dev->mode_config.num_plane; i++) {
+		struct intel_plane_state *s = &state->plane[i];
+
+		if (s->plane->crtc == crtc)
+			s->dirty = true;
+	}
+}
+
+static int check_crtc(struct intel_crtc_state *s)
+{
+	struct drm_crtc *crtc = s->crtc;
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	struct drm_device *dev = crtc->dev;
+	struct drm_encoder *encoder;
+	struct drm_framebuffer *fb = crtc->fb;
+	int ret;
+
+	/* must have a fb and connectors if we have a mode, and vice versa */
+	if (crtc->enabled) {
+		if (!fb)
+			return -EINVAL;
+		if (!drm_helper_crtc_in_use(crtc))
+			return -EINVAL;
+	} else {
+		if (fb)
+			return -EINVAL;
+		if (drm_helper_crtc_in_use(crtc))
+			return -EINVAL;
+	}
+
+	if (crtc->enabled) {
+		if (crtc->mode.hdisplay > fb->width ||
+		    crtc->mode.vdisplay > fb->height ||
+		    crtc->x > fb->width - crtc->mode.hdisplay ||
+		    crtc->y > fb->height - crtc->mode.vdisplay)
+			return -ENOSPC;
+	}
+
+	if (fb) {
+		/* FIXME refactor and check */
+		switch (fb->pixel_format) {
+		case DRM_FORMAT_C8:
+		case DRM_FORMAT_RGB565:
+		case DRM_FORMAT_XRGB8888:
+		case DRM_FORMAT_ARGB8888:
+		case DRM_FORMAT_XBGR8888:
+		case DRM_FORMAT_ABGR8888:
+		case DRM_FORMAT_XRGB2101010:
+		case DRM_FORMAT_ARGB2101010:
+		case DRM_FORMAT_XBGR2101010:
+		case DRM_FORMAT_ABGR2101010:
+		case DRM_FORMAT_XRGB1555:
+		case DRM_FORMAT_ARGB1555:
+			break;
+		default:
+			return -EINVAL;
+		}
+	}
+
+	if (intel_crtc->cursor_visible &&
+	    (intel_crtc->cursor_width != 64 ||
+	     intel_crtc->cursor_height != 64)) {
+		return -EINVAL;
+	}
+
+	if (!crtc->enabled || !s->mode_dirty)
+		return 0;
+
+	crtc->hwmode = crtc->mode;
+
+	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+		const struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
+
+		if (encoder->crtc != crtc)
+			continue;
+
+		if (!encoder_funcs->mode_fixup(encoder, &crtc->mode, &crtc->hwmode))
+			return -EINVAL;
+	}
+
+	if (!intel_crtc_mode_fixup(crtc, &crtc->mode, &crtc->hwmode))
+		return -EINVAL;
+
+	ret = intel_check_clock(crtc, &crtc->hwmode);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int intel_atomic_check(struct drm_device *dev, void *state)
+{
+	struct intel_atomic_state *s = state;
+	int ret;
+	int i;
+
+	for (i = 0; i < dev->mode_config.num_crtc; i++) {
+		struct intel_crtc_state *st = &s->crtc[i];
+
+		crtc_compute_dirty(s, st);
+	}
+
+	for (i = 0; i < dev->mode_config.num_crtc; i++) {
+		struct intel_plane_state *st = &s->plane[i];
+
+		plane_compute_dirty(s, st);
+	}
+
+	if (!s->dirty)
+		return 0;
+
+	for (i = 0; i < dev->mode_config.num_crtc; i++) {
+		struct intel_crtc_state *st = &s->crtc[i];
+
+		if (!st->fb_dirty && !st->mode_dirty && !st->cursor_dirty)
+			continue;
+
+		if (st->mode_dirty && s->flags & DRM_MODE_ATOMIC_NONBLOCK)
+			return -EAGAIN;
+
+		ret = check_crtc(st);
+		if (ret)
+			return ret;
+
+		/*
+		 * Mark all planes on this CRTC as dirty if the active video
+		 * area changed so that the planes will get reclipped correctly.
+		 *
+		 * Also any modesetting will disable+enable the pipe, so the
+		 * plane needs to be re-enabled afterwards too.
+		 * TODO: there's no need to redo the clipping in such cases
+		 * if the computed values were cached, the could be commited
+		 * directly.
+		 */
+		if (st->active_dirty || st->mode_dirty)
+			dirty_planes(dev, s, st->crtc);
+	}
+
+	/* check for conflicts in encoder/connector assignment */
+	for (i = 0; i < dev->mode_config.num_crtc; i++) {
+		struct intel_crtc_state *st = &s->crtc[i];
+		int j;
+
+		for (j = i + 1; j < dev->mode_config.num_crtc; j++) {
+			struct intel_crtc_state *st2 = &s->crtc[j];
+
+			if (st->connectors_bitmask & st2->connectors_bitmask)
+				return -EINVAL;
+
+			if (st->encoders_bitmask & st2->encoders_bitmask)
+				return -EINVAL;
+		}
+	}
+
+	for (i = 0; i < dev->mode_config.num_plane; i++) {
+		struct intel_plane_state *st = &s->plane[i];
+		const struct drm_plane *plane = st->plane;
+
+		if (!st->dirty)
+			continue;
+
+		st->coords.crtc_x = plane->crtc_x;
+		st->coords.crtc_y = plane->crtc_y;
+		st->coords.crtc_w = plane->crtc_w;
+		st->coords.crtc_h = plane->crtc_h;
+
+		st->coords.src_x = plane->src_x;
+		st->coords.src_y = plane->src_y;
+		st->coords.src_w = plane->src_w;
+		st->coords.src_h = plane->src_h;
+
+		ret = intel_check_plane(plane, plane->crtc, plane->fb, &st->coords);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static void update_plane_props(struct drm_plane *plane)
+{
+	struct drm_mode_object *obj = &plane->base;
+
+	drm_object_property_set_value(obj, prop_src_x, plane->src_x);
+	drm_object_property_set_value(obj, prop_src_y, plane->src_y);
+	drm_object_property_set_value(obj, prop_src_w, plane->src_w);
+	drm_object_property_set_value(obj, prop_src_h, plane->src_h);
+
+	drm_object_property_set_value(obj, prop_crtc_x, plane->crtc_x);
+	drm_object_property_set_value(obj, prop_crtc_y, plane->crtc_y);
+	drm_object_property_set_value(obj, prop_crtc_w, plane->crtc_w);
+	drm_object_property_set_value(obj, prop_crtc_h, plane->crtc_h);
+
+	drm_object_property_set_value(obj, prop_fb_id, plane->fb ? plane->fb->base.id : 0);
+	drm_object_property_set_value(obj, prop_crtc_id, plane->crtc ? plane->crtc->base.id : 0);
+}
+
+static int update_prop_connector_ids(struct drm_crtc *crtc)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_connector *connector;
+	uint64_t value = 0;
+	int i = 0;
+	uint32_t connector_ids[dev->mode_config.num_connector];
+
+	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+		if (connector->encoder && connector->encoder->crtc == crtc)
+			connector_ids[i++] = connector->base.id;
+	}
+
+	if (i) {
+		drm_property_blob_replace_data(crtc->connector_ids_blob,
+					       i * sizeof connector_ids[0], connector_ids);
+		value = crtc->connector_ids_blob->base.id;
+	} else
+		drm_property_blob_replace_data(crtc->connector_ids_blob, 0, NULL);
+
+	drm_object_property_set_value(&crtc->base, prop_connector_ids, value);
+
+	return 0;
+}
+
+static int update_prop_mode(struct drm_crtc *crtc)
+{
+	uint64_t value = 0;
+
+	if (crtc->enabled) {
+		struct drm_mode_modeinfo umode;
+
+		drm_crtc_convert_to_umode(&umode, &crtc->mode);
+		drm_property_blob_replace_data(crtc->mode_blob, sizeof umode, &umode);
+		value = crtc->mode_blob->base.id;
+	} else
+		drm_property_blob_replace_data(crtc->mode_blob, 0, NULL);
+
+	drm_object_property_set_value(&crtc->base, prop_mode, value);
+
+	return 0;
+}
+
+static void update_crtc_props(struct drm_crtc *crtc)
+{
+	struct drm_mode_object *obj = &crtc->base;
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+	drm_object_property_set_value(obj, prop_src_x, crtc->x);
+	drm_object_property_set_value(obj, prop_src_y, crtc->y);
+
+	drm_object_property_set_value(obj, prop_fb_id, crtc->fb ? crtc->fb->base.id : 0);
+
+	drm_object_property_set_value(obj, prop_cursor_id, intel_crtc->cursor_handle);
+	drm_object_property_set_value(obj, prop_cursor_x, intel_crtc->cursor_x);
+	drm_object_property_set_value(obj, prop_cursor_y, intel_crtc->cursor_y);
+	drm_object_property_set_value(obj, prop_cursor_w, intel_crtc->cursor_width);
+	drm_object_property_set_value(obj, prop_cursor_h, intel_crtc->cursor_height);
+
+	update_prop_mode(crtc);
+	update_prop_connector_ids(crtc);
+}
+
+static void update_props(struct drm_device *dev,
+			 struct intel_atomic_state *s)
+{
+	int i;
+
+	for (i = 0; i < dev->mode_config.num_crtc; i++) {
+		struct intel_crtc_state *st = &s->crtc[i];
+
+		if (!st->fb_dirty && !st->mode_dirty)
+			continue;
+
+		update_crtc_props(st->crtc);
+	}
+
+	for (i = 0; i < dev->mode_config.num_plane; i++) {
+		struct intel_plane_state *st = &s->plane[i];
+
+		if (!st->dirty)
+			continue;
+
+		update_plane_props(st->plane);
+	}
+}
+
+static void update_crtc(struct drm_device *dev,
+			struct intel_atomic_state *s)
+{
+	int i;
+
+	for (i = 0; i < dev->mode_config.num_crtc; i++) {
+		struct intel_crtc_state *st = &s->crtc[i];
+		struct drm_crtc *crtc = st->crtc;
+
+		/* FIXME is this OK? */
+		if (st->fb_dirty && !st->mode_dirty) {
+			mutex_lock(&dev->struct_mutex);
+			intel_update_fbc(dev);
+			mutex_unlock(&dev->struct_mutex);
+		}
+
+		if (st->mode_dirty) {
+			drm_calc_timestamping_constants(crtc);
+			intel_crtc_update_sarea(crtc, crtc->enabled);
+		}
+
+		if (st->fb_dirty)
+			intel_crtc_update_sarea_pos(crtc, crtc->x, crtc->y);
+	}
+}
+
+static int intel_atomic_commit(struct drm_device *dev, void *state)
+{
+	struct intel_atomic_state *s = state;
+	int ret;
+
+	if (s->flags & DRM_MODE_ATOMIC_NONBLOCK)
+		return -ENOSYS;
+
+	if (s->flags & DRM_MODE_ATOMIC_EVENT)
+		return -ENOSYS;
+
+	if (!s->dirty)
+		return 0;
+
+	ret = pin_fbs(dev, s);
+	if (ret)
+		return ret;
+
+	ret = pin_cursors(dev, s);
+	if (ret)
+		return ret;
+
+	/* apply in a blocking manner */
+	ret = apply_config(dev, s);
+	if (ret) {
+		unpin_cursors(dev, s);
+		unpin_fbs(dev, s);
+		s->restore_hw = true;
+		return ret;
+	}
+
+	unpin_old_cursors(dev, s);
+	unpin_old_fbs(dev, s);
+
+	update_plane_obj(dev, s);
+
+	update_crtc(dev, s);
+
+	update_props(dev, s);
+
+	return 0;
+}
+
+static void intel_atomic_end(struct drm_device *dev, void *state)
+{
+	struct intel_atomic_state *s = state;
+
+	/* restore the state of all objects */
+	if (s->restore_state)
+		restore_state(dev, state);
+
+	kfree(state);
+}
+
+static const struct drm_atomic_funcs intel_atomic_funcs = {
+	.begin = intel_atomic_begin,
+	.set = intel_atomic_set,
+	.check = intel_atomic_check,
+	.commit = intel_atomic_commit,
+	.end = intel_atomic_end,
+};
+
+static struct {
+	struct drm_property **prop;
+	const char *name;
+	uint64_t min;
+	uint64_t max;
+} props[] = {
+	{ &prop_src_x, "SRC_X", 0, UINT_MAX },
+	{ &prop_src_y, "SRC_Y", 0, UINT_MAX },
+	{ &prop_src_w, "SRC_W", 0, UINT_MAX },
+	{ &prop_src_h, "SRC_H", 0, UINT_MAX },
+
+	{ &prop_crtc_x, "CRTC_X", INT_MIN, INT_MAX },
+	{ &prop_crtc_y, "CRTC_Y", INT_MIN, INT_MAX },
+	{ &prop_crtc_w, "CRTC_W", 0, INT_MAX },
+	{ &prop_crtc_h, "CRTC_H", 0, INT_MAX },
+
+	{ &prop_fb_id, "FB_ID", 0, UINT_MAX },
+	{ &prop_crtc_id, "CRTC_ID", 0, UINT_MAX },
+
+	{ &prop_cursor_id, "CURSOR_ID", 0, UINT_MAX },
+	{ &prop_cursor_w, "CURSOR_W", 0, UINT_MAX },
+	{ &prop_cursor_h, "CURSOR_H", 0, UINT_MAX },
+	{ &prop_cursor_x, "CURSOR_X", INT_MIN, INT_MAX },
+	{ &prop_cursor_y, "CURSOR_Y", INT_MIN, INT_MAX },
+};
+
+int intel_atomic_init(struct drm_device *dev)
+{
+	struct drm_crtc *crtc;
+	struct drm_plane *plane;
+	int ret = -ENOMEM;
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(props); i++) {
+		*props[i].prop =
+			drm_property_create_range(dev, 0, props[i].name,
+						  props[i].min, props[i].max);
+		if (!*props[i].prop)
+			goto out;
+	}
+
+	/* FIXME create special object ID list property type? */
+	prop_connector_ids = drm_property_create(dev, DRM_MODE_PROP_BLOB, "CONNECTOR_IDS", 0);
+	if (!prop_connector_ids)
+		goto out;
+
+	prop_mode = drm_property_create(dev, DRM_MODE_PROP_BLOB, "MODE", 0);
+	if (!prop_mode)
+		goto out;
+
+	list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
+		struct drm_mode_object *obj = &plane->base;
+
+		drm_object_attach_property(obj, prop_src_x, 0);
+		drm_object_attach_property(obj, prop_src_y, 0);
+		drm_object_attach_property(obj, prop_src_w, 0);
+		drm_object_attach_property(obj, prop_src_h, 0);
+
+		drm_object_attach_property(obj, prop_crtc_x, 0);
+		drm_object_attach_property(obj, prop_crtc_y, 0);
+		drm_object_attach_property(obj, prop_crtc_w, 0);
+		drm_object_attach_property(obj, prop_crtc_h, 0);
+
+		drm_object_attach_property(obj, prop_fb_id, 0);
+		drm_object_attach_property(obj, prop_crtc_id, 0);
+
+		update_plane_props(plane);
+	}
+
+	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+		struct drm_mode_object *obj = &crtc->base;
+
+		drm_object_attach_property(obj, prop_src_x, 0);
+		drm_object_attach_property(obj, prop_src_y, 0);
+
+		drm_object_attach_property(obj, prop_fb_id, 0);
+		drm_object_attach_property(obj, prop_mode, 0);
+		drm_object_attach_property(obj, prop_connector_ids, 0);
+
+		drm_object_attach_property(obj, prop_cursor_id, 0);
+		drm_object_attach_property(obj, prop_cursor_x, 0);
+		drm_object_attach_property(obj, prop_cursor_y, 0);
+		drm_object_attach_property(obj, prop_cursor_w, 0);
+		drm_object_attach_property(obj, prop_cursor_h, 0);
+
+		crtc->mode_blob = drm_property_create_blob(dev, 0, sizeof(struct drm_mode_modeinfo), NULL);
+		if (!crtc->mode_blob)
+			goto out;
+
+		crtc->connector_ids_blob = drm_property_create_blob(dev, 0,
+								    dev->mode_config.num_connector * sizeof(uint32_t), NULL);
+		if (!crtc->connector_ids_blob)
+			goto out;
+
+		update_crtc_props(crtc);
+	}
+
+	dev->driver->atomic_funcs = &intel_atomic_funcs;
+
+	return 0;
+
+ out:
+	drm_property_destroy(dev, prop_mode);
+	drm_property_destroy(dev, prop_connector_ids);
+
+	while (i--)
+		drm_property_destroy(dev, *props[i].prop);
+
+	return ret;
+}
+
+void intel_atomic_fini(struct drm_device *dev)
+{
+	struct drm_crtc *crtc;
+
+	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+		drm_property_destroy_blob(dev, crtc->mode_blob);
+		drm_property_destroy_blob(dev, crtc->connector_ids_blob);
+	}
+
+	drm_property_destroy(dev, prop_connector_ids);
+	drm_property_destroy(dev, prop_mode);
+	drm_property_destroy(dev, prop_crtc_id);
+	drm_property_destroy(dev, prop_fb_id);
+
+	drm_property_destroy(dev, prop_crtc_h);
+	drm_property_destroy(dev, prop_crtc_w);
+	drm_property_destroy(dev, prop_crtc_y);
+	drm_property_destroy(dev, prop_crtc_x);
+
+	drm_property_destroy(dev, prop_src_h);
+	drm_property_destroy(dev, prop_src_w);
+	drm_property_destroy(dev, prop_src_y);
+	drm_property_destroy(dev, prop_src_x);
+}
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 0fb1e09..ac46281 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -7830,6 +7830,9 @@ static void intel_setup_outputs(struct drm_device *dev)
 			intel_encoder_clones(encoder);
 	}
 
+	/* FIXME error handling */
+	intel_atomic_init(dev);
+
 	if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev))
 		ironlake_init_pch_refclk(dev);
 }
@@ -8565,6 +8568,8 @@ void intel_modeset_cleanup(struct drm_device *dev)
 	/* flush any delayed tasks or pending work */
 	flush_scheduled_work();
 
+	intel_atomic_fini(dev);
+
 	drm_mode_config_cleanup(dev);
 }
 
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 6ab8f65..616d5d3 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -627,4 +627,7 @@ extern bool intel_crtc_mode_fixup(struct drm_crtc *crtc,
 				  const struct drm_display_mode *mode,
 				  struct drm_display_mode *adjusted_mode);
 
+extern int intel_atomic_init(struct drm_device *dev);
+extern void intel_atomic_fini(struct drm_device *dev);
+
 #endif /* __INTEL_DRV_H__ */
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 69420e7..f37e8a7 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -509,6 +509,7 @@ struct drm_encoder {
 	struct drm_crtc *crtc;
 	const struct drm_encoder_funcs *funcs;
 	void *helper_private;
+	struct drm_crtc *old_crtc;
 };
 
 enum drm_connector_force {
@@ -614,6 +615,7 @@ struct drm_connector {
 	int audio_latency[2];
 	int null_edid_counter; /* needed to workaround some HW bugs where we get all 0s */
 	unsigned bad_edid_counter;
+	struct drm_encoder *old_encoder;
 };
 
 /**
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 46/51] drm/i915: Add support for atomic modesetting completion events
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (44 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 45/51] drm/i915: Implement atomic modesetting ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-11-01 11:12   ` Daniel Vetter
  2012-10-25 18:05 ` [PATCH 47/51] drm/i915: Add atomic page flip support ville.syrjala
                   ` (4 subsequent siblings)
  50 siblings, 1 reply; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Send completion events when the atomic modesetting operations has
finished succesfully.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_atomic.c |  195 ++++++++++++++++++++++++++++++++++-
 1 files changed, 192 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c
index 4899f8c..3adb140 100644
--- a/drivers/gpu/drm/i915/intel_atomic.c
+++ b/drivers/gpu/drm/i915/intel_atomic.c
@@ -53,6 +53,7 @@ struct intel_plane_state {
 	bool dirty;
 	bool pinned;
 	bool changed;
+	struct drm_pending_atomic_event *event;
 
 	struct {
 		struct drm_crtc *crtc;
@@ -74,6 +75,7 @@ struct intel_crtc_state {
 	unsigned long connectors_bitmask;
 	unsigned long encoders_bitmask;
 	bool changed;
+	struct drm_pending_atomic_event *event;
 
 	struct {
 		bool enabled;
@@ -922,6 +924,111 @@ int intel_commit_plane_nopin(struct drm_plane *plane,
 			     struct drm_framebuffer *fb,
 			     const struct intel_plane_coords *coords);
 
+static struct drm_pending_atomic_event *alloc_event(struct drm_device *dev,
+						    struct drm_file *file_priv,
+						    uint64_t user_data)
+{
+	struct drm_pending_atomic_event *e;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->event_lock, flags);
+
+	if (file_priv->event_space < sizeof e->event) {
+		spin_unlock_irqrestore(&dev->event_lock, flags);
+		return ERR_PTR(-ENOSPC);
+	}
+
+	file_priv->event_space -= sizeof e->event;
+	spin_unlock_irqrestore(&dev->event_lock, flags);
+
+	e = kzalloc(sizeof *e, GFP_KERNEL);
+	if (!e) {
+		spin_lock_irqsave(&dev->event_lock, flags);
+		file_priv->event_space += sizeof e->event;
+		spin_unlock_irqrestore(&dev->event_lock, flags);
+
+		return ERR_PTR(-ENOMEM);
+	}
+
+	e->event.base.type = DRM_EVENT_ATOMIC_COMPLETE;
+	e->event.base.length = sizeof e->event;
+	e->event.user_data = user_data;
+	e->base.event = &e->event.base;
+	e->base.file_priv = file_priv;
+	e->base.destroy = (void (*) (struct drm_pending_event *)) kfree;
+
+	return e;
+}
+
+static void free_event(struct drm_pending_atomic_event *e)
+{
+	e->base.file_priv->event_space += sizeof e->event;
+	kfree(e);
+}
+
+static void queue_event(struct drm_device *dev, struct drm_crtc *crtc,
+			struct drm_pending_atomic_event *e)
+{
+	struct timeval tvbl;
+
+	if (crtc) {
+		int pipe = to_intel_crtc(crtc)->pipe;
+
+		/* FIXME this is wrong for flips that are completed not at vblank */
+		e->event.sequence = drm_vblank_count_and_time(dev, pipe, &tvbl);
+		e->event.tv_sec = tvbl.tv_sec;
+		e->event.tv_usec = tvbl.tv_usec;
+	} else {
+		e->event.sequence = 0;
+		e->event.tv_sec = 0;
+		e->event.tv_usec = 0;
+	}
+
+	list_add_tail(&e->base.link, &e->base.file_priv->event_list);
+	wake_up_interruptible(&e->base.file_priv->event_wait);
+}
+
+static void queue_remaining_events(struct drm_device *dev, struct intel_atomic_state *s)
+{
+	int i;
+
+	for (i = 0; i < dev->mode_config.num_crtc; i++) {
+		struct intel_crtc_state *st = &s->crtc[i];
+
+		if (st->event) {
+			if (st->old.fb)
+				st->event->event.old_fb_id = st->old.fb->base.id;
+
+			spin_lock_irq(&dev->event_lock);
+			queue_event(dev, st->crtc, st->event);
+			spin_unlock_irq(&dev->event_lock);
+
+			st->event = NULL;
+		}
+	}
+
+	for (i = 0; i < dev->mode_config.num_plane; i++) {
+		struct intel_plane_state *st = &s->plane[i];
+		struct drm_crtc *crtc;
+
+		if (!st->event)
+			continue;
+
+		crtc = st->plane->crtc;
+		if (!crtc)
+			crtc = st->old.crtc;
+
+		if (st->old.fb)
+			st->event->event.old_fb_id = st->old.fb->base.id;
+
+		spin_lock_irq(&dev->event_lock);
+		queue_event(dev, crtc, st->event);
+		spin_unlock_irq(&dev->event_lock);
+
+		st->event = NULL;
+	}
+}
+
 static void swap_old_new(struct drm_device *dev,
 			 struct intel_atomic_state *s)
 {
@@ -1426,6 +1533,73 @@ static void update_crtc(struct drm_device *dev,
 	}
 }
 
+static int alloc_flip_data(struct drm_device *dev, struct intel_atomic_state *s)
+{
+	int i;
+
+	for (i = 0; i < dev->mode_config.num_crtc; i++) {
+		struct intel_crtc_state *st = &s->crtc[i];
+
+		if (st->changed && s->flags & DRM_MODE_ATOMIC_EVENT) {
+			struct drm_pending_atomic_event *e;
+
+			e = alloc_event(dev, s->file, s->user_data);
+			if (IS_ERR(e))
+				return PTR_ERR(e);
+
+			e->event.obj_id = st->crtc->base.id;
+
+			st->event = e;
+		}
+	}
+
+
+	for (i = 0; i < dev->mode_config.num_plane; i++) {
+		struct intel_plane_state *st = &s->plane[i];
+
+		if (st->changed && s->flags & DRM_MODE_ATOMIC_EVENT) {
+			struct drm_pending_atomic_event *e;
+
+			e = alloc_event(dev, s->file, s->user_data);
+			if (IS_ERR(e))
+				return PTR_ERR(e);
+
+			e->event.obj_id = st->plane->base.id;
+
+			st->event = e;
+		}
+	}
+
+	return 0;
+}
+
+static void free_flip_data(struct drm_device *dev, struct intel_atomic_state *s)
+{
+	int i;
+
+	for (i = 0; i < dev->mode_config.num_crtc; i++) {
+		struct intel_crtc_state *st = &s->crtc[i];
+
+		if (st->event) {
+			spin_lock_irq(&dev->event_lock);
+			free_event(st->event);
+			spin_unlock_irq(&dev->event_lock);
+			st->event = NULL;
+		}
+	}
+
+	for (i = 0; i < dev->mode_config.num_plane; i++) {
+		struct intel_plane_state *st = &s->plane[i];
+
+		if (st->event) {
+			spin_lock_irq(&dev->event_lock);
+			free_event(st->event);
+			spin_unlock_irq(&dev->event_lock);
+			st->event = NULL;
+		}
+	}
+}
+
 static int intel_atomic_commit(struct drm_device *dev, void *state)
 {
 	struct intel_atomic_state *s = state;
@@ -1434,12 +1608,13 @@ static int intel_atomic_commit(struct drm_device *dev, void *state)
 	if (s->flags & DRM_MODE_ATOMIC_NONBLOCK)
 		return -ENOSYS;
 
-	if (s->flags & DRM_MODE_ATOMIC_EVENT)
-		return -ENOSYS;
-
 	if (!s->dirty)
 		return 0;
 
+	ret = alloc_flip_data(dev, s);
+	if (ret)
+		return ret;
+
 	ret = pin_fbs(dev, s);
 	if (ret)
 		return ret;
@@ -1460,6 +1635,17 @@ static int intel_atomic_commit(struct drm_device *dev, void *state)
 	unpin_old_cursors(dev, s);
 	unpin_old_fbs(dev, s);
 
+	/*
+	 * Either we took the blocking code path, or perhaps the state of
+	 * some objects didn't actually change? Nonetheless the user wanted
+	 * events for all objects he touched, so queue up any events that
+	 * are still pending.
+	 *
+	 * FIXME this needs more work. If the previous flip is still pending
+	 * we shouldn't send this event until that flip completes.
+	 */
+	queue_remaining_events(dev, s);
+
 	update_plane_obj(dev, s);
 
 	update_crtc(dev, s);
@@ -1473,6 +1659,9 @@ static void intel_atomic_end(struct drm_device *dev, void *state)
 {
 	struct intel_atomic_state *s = state;
 
+	/* don't send events when restoring old state */
+	free_flip_data(dev, state);
+
 	/* restore the state of all objects */
 	if (s->restore_state)
 		restore_state(dev, state);
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 47/51] drm/i915: Add atomic page flip support
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (45 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 46/51] drm/i915: Add support for atomic modesetting completion events ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 48/51] drm/i915: Unstatic intel_enable_primary() and intel_disable_primary() ville.syrjala
                   ` (3 subsequent siblings)
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Add support for the DRM_MODE_ATOMIC_NONBLOCK flag.

The drm_flip helper provides the necessary logic to track the
progress of the flips. drm_flip is driven by a few extra calls
from the interrupt handling and crtc_disable code paths.

Since the hardware doesn't provide inter-plane synchronization, some
extra software magic is required to avoid flips for multiple planes
ending up on the wrong sides of the vblank leading edge.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/i915_dma.c      |    3 +
 drivers/gpu/drm/i915/i915_drv.h      |    4 +
 drivers/gpu/drm/i915/i915_irq.c      |   16 +-
 drivers/gpu/drm/i915/intel_atomic.c  |  622 +++++++++++++++++++++++++++++++++-
 drivers/gpu/drm/i915/intel_display.c |    2 +
 drivers/gpu/drm/i915/intel_drv.h     |    7 +
 6 files changed, 637 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index acc4317..33999f1 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1794,6 +1794,8 @@ int i915_driver_open(struct drm_device *dev, struct drm_file *file)
 
 	idr_init(&file_priv->context_idr);
 
+	INIT_LIST_HEAD(&file_priv->pending_flips);
+
 	return 0;
 }
 
@@ -1834,6 +1836,7 @@ void i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv)
 {
 	i915_gem_context_close(dev, file_priv);
 	i915_gem_release(dev, file_priv);
+	intel_atomic_free_events(dev, file_priv);
 }
 
 void i915_driver_postclose(struct drm_device *dev, struct drm_file *file)
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 302b6e6..51b36c1 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -36,6 +36,7 @@
 #include <linux/io-mapping.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
+#include <drm/drm_flip.h>
 #include <drm/intel-gtt.h>
 #include <linux/backlight.h>
 #include <linux/intel-iommu.h>
@@ -882,6 +883,8 @@ typedef struct drm_i915_private {
 	struct work_struct parity_error_work;
 	bool hw_contexts_disabled;
 	uint32_t hw_context_size;
+
+	struct drm_flip_driver flip_driver;
 } drm_i915_private_t;
 
 /* Iterate over initialised rings */
@@ -1100,6 +1103,7 @@ struct drm_i915_file_private {
 		struct list_head request_list;
 	} mm;
 	struct idr context_idr;
+	struct list_head pending_flips;
 };
 
 #define INTEL_INFO(dev)	(((struct drm_i915_private *) (dev)->dev_private)->info)
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 32e1bda..ee22e97 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -563,8 +563,10 @@ static irqreturn_t valleyview_irq_handler(DRM_IRQ_ARGS)
 		spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
 		for_each_pipe(pipe) {
-			if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS)
+			if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS) {
 				drm_handle_vblank(dev, pipe);
+				intel_atomic_handle_vblank(dev, pipe);
+			}
 
 			if (pipe_stats[pipe] & PLANE_FLIPDONE_INT_STATUS_VLV) {
 				intel_prepare_page_flip(dev, pipe);
@@ -697,8 +699,10 @@ static irqreturn_t ivybridge_irq_handler(DRM_IRQ_ARGS)
 			intel_opregion_gse_intr(dev);
 
 		for (i = 0; i < 3; i++) {
-			if (de_iir & (DE_PIPEA_VBLANK_IVB << (5 * i)))
+			if (de_iir & (DE_PIPEA_VBLANK_IVB << (5 * i))) {
 				drm_handle_vblank(dev, i);
+				intel_atomic_handle_vblank(dev, i);
+			}
 			if (de_iir & (DE_PLANEA_FLIP_DONE_IVB << (5 * i))) {
 				intel_prepare_page_flip(dev, i);
 				intel_finish_page_flip_plane(dev, i);
@@ -784,11 +788,15 @@ static irqreturn_t ironlake_irq_handler(DRM_IRQ_ARGS)
 	if (de_iir & DE_GSE)
 		intel_opregion_gse_intr(dev);
 
-	if (de_iir & DE_PIPEA_VBLANK)
+	if (de_iir & DE_PIPEA_VBLANK) {
 		drm_handle_vblank(dev, 0);
+		intel_atomic_handle_vblank(dev, 0);
+	}
 
-	if (de_iir & DE_PIPEB_VBLANK)
+	if (de_iir & DE_PIPEB_VBLANK) {
 		drm_handle_vblank(dev, 1);
+		intel_atomic_handle_vblank(dev, 1);
+	}
 
 	if (de_iir & DE_PLANEA_FLIP_DONE) {
 		intel_prepare_page_flip(dev, 0);
diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c
index 3adb140..238a843 100644
--- a/drivers/gpu/drm/i915/intel_atomic.c
+++ b/drivers/gpu/drm/i915/intel_atomic.c
@@ -26,6 +26,7 @@
 
 #include <drm/drmP.h>
 #include <drm/drm_crtc.h>
+#include <drm/drm_flip.h>
 
 #include "intel_drv.h"
 
@@ -47,6 +48,20 @@ static struct drm_property *prop_cursor_y;
 static struct drm_property *prop_cursor_w;
 static struct drm_property *prop_cursor_h;
 
+struct intel_flip {
+	struct drm_flip base;
+	u32 vbl_count;
+	bool vblank_ref;
+	bool has_cursor;
+	struct drm_crtc *crtc;
+	struct drm_plane *plane;
+	struct drm_i915_gem_object *old_bo;
+	struct drm_i915_gem_object *old_cursor_bo;
+	struct drm_pending_atomic_event *event;
+	uint32_t old_fb_id;
+	struct list_head pending_head;
+};
+
 struct intel_plane_state {
 	struct drm_plane *plane;
 	struct intel_plane_coords coords;
@@ -54,6 +69,7 @@ struct intel_plane_state {
 	bool pinned;
 	bool changed;
 	struct drm_pending_atomic_event *event;
+	struct intel_flip *flip;
 
 	struct {
 		struct drm_crtc *crtc;
@@ -76,6 +92,7 @@ struct intel_crtc_state {
 	unsigned long encoders_bitmask;
 	bool changed;
 	struct drm_pending_atomic_event *event;
+	struct intel_flip *flip;
 
 	struct {
 		bool enabled;
@@ -966,6 +983,22 @@ static void free_event(struct drm_pending_atomic_event *e)
 	kfree(e);
 }
 
+void intel_atomic_free_events(struct drm_device *dev, struct drm_file *file)
+{
+	struct drm_i915_file_private *file_priv = file->driver_priv;
+	struct intel_flip *intel_flip, *next;
+
+	spin_lock_irq(&dev->event_lock);
+
+	list_for_each_entry_safe(intel_flip, next, &file_priv->pending_flips, pending_head) {
+		free_event(intel_flip->event);
+		intel_flip->event = NULL;
+		list_del_init(&intel_flip->pending_head);
+	}
+
+	spin_unlock_irq(&dev->event_lock);
+}
+
 static void queue_event(struct drm_device *dev, struct drm_crtc *crtc,
 			struct drm_pending_atomic_event *e)
 {
@@ -1533,6 +1566,60 @@ static void update_crtc(struct drm_device *dev,
 	}
 }
 
+static void atomic_pipe_commit(struct drm_device *dev,
+			       struct intel_atomic_state *state,
+			       int pipe);
+
+static int apply_nonblocking(struct drm_device *dev, struct intel_atomic_state *s)
+{
+	struct intel_crtc *intel_crtc;
+	int i;
+
+	for (i = 0; i < dev->mode_config.num_crtc; i++) {
+		struct intel_crtc_state *st = &s->crtc[i];
+		struct intel_crtc *intel_crtc = to_intel_crtc(st->crtc);
+		struct drm_i915_gem_object *obj;
+
+		if (!st->old.fb)
+			continue;
+
+		obj = to_intel_framebuffer(st->old.fb)->obj;
+
+		/* Only one bit per plane in pending_flips */
+		if (atomic_read(&obj->pending_flip) & (1 << intel_crtc->plane))
+			return -EBUSY;
+	}
+
+	for (i = 0; i < dev->mode_config.num_plane; i++) {
+		struct intel_plane_state *st = &s->plane[i];
+		struct intel_plane *intel_plane = to_intel_plane(st->plane);
+		struct drm_i915_gem_object *obj;
+
+		if (!st->old.fb)
+			continue;
+
+		obj = to_intel_framebuffer(st->old.fb)->obj;
+
+		if (!st->old.fb)
+			continue;
+
+		obj = to_intel_framebuffer(st->old.fb)->obj;
+
+		/* Only one bit per plane in pending_flips */
+		if (atomic_read(&obj->pending_flip) & (1 << (16 + intel_plane->pipe)))
+			return -EBUSY;
+	}
+
+	list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, base.head)
+		atomic_pipe_commit(dev, s, intel_crtc->pipe);
+
+	/* don't restore the old state in end() */
+	s->dirty = false;
+	s->restore_state = false;
+
+	return 0;
+}
+
 static int alloc_flip_data(struct drm_device *dev, struct intel_atomic_state *s)
 {
 	int i;
@@ -1551,6 +1638,13 @@ static int alloc_flip_data(struct drm_device *dev, struct intel_atomic_state *s)
 
 			st->event = e;
 		}
+
+		if (!st->fb_dirty && !st->mode_dirty && !st->cursor_dirty)
+			continue;
+
+		st->flip = kzalloc(sizeof *st->flip, GFP_KERNEL);
+		if (!st->flip)
+			return -ENOMEM;
 	}
 
 
@@ -1568,6 +1662,13 @@ static int alloc_flip_data(struct drm_device *dev, struct intel_atomic_state *s)
 
 			st->event = e;
 		}
+
+		if (!st->dirty)
+			continue;
+
+		st->flip = kzalloc(sizeof *st->flip, GFP_KERNEL);
+		if (!st->flip)
+			return -ENOMEM;
 	}
 
 	return 0;
@@ -1586,6 +1687,9 @@ static void free_flip_data(struct drm_device *dev, struct intel_atomic_state *s)
 			spin_unlock_irq(&dev->event_lock);
 			st->event = NULL;
 		}
+
+		kfree(st->flip);
+		st->flip = NULL;
 	}
 
 	for (i = 0; i < dev->mode_config.num_plane; i++) {
@@ -1597,6 +1701,9 @@ static void free_flip_data(struct drm_device *dev, struct intel_atomic_state *s)
 			spin_unlock_irq(&dev->event_lock);
 			st->event = NULL;
 		}
+
+		kfree(st->flip);
+		st->flip = NULL;
 	}
 }
 
@@ -1605,9 +1712,6 @@ static int intel_atomic_commit(struct drm_device *dev, void *state)
 	struct intel_atomic_state *s = state;
 	int ret;
 
-	if (s->flags & DRM_MODE_ATOMIC_NONBLOCK)
-		return -ENOSYS;
-
 	if (!s->dirty)
 		return 0;
 
@@ -1623,17 +1727,27 @@ static int intel_atomic_commit(struct drm_device *dev, void *state)
 	if (ret)
 		return ret;
 
-	/* apply in a blocking manner */
-	ret = apply_config(dev, s);
-	if (ret) {
-		unpin_cursors(dev, s);
-		unpin_fbs(dev, s);
-		s->restore_hw = true;
-		return ret;
-	}
+	/* try to apply in a non blocking manner */
+	if (s->flags & DRM_MODE_ATOMIC_NONBLOCK) {
+		ret = apply_nonblocking(dev, s);
+		if (ret) {
+			unpin_cursors(dev, s);
+			unpin_fbs(dev, s);
+			return ret;
+		}
+	} else {
+		/* apply in a blocking manner */
+		ret = apply_config(dev, s);
+		if (ret) {
+			unpin_cursors(dev, s);
+			unpin_fbs(dev, s);
+			s->restore_hw = true;
+			return ret;
+		}
 
-	unpin_old_cursors(dev, s);
-	unpin_old_fbs(dev, s);
+		unpin_old_cursors(dev, s);
+		unpin_old_fbs(dev, s);
+	}
 
 	/*
 	 * Either we took the blocking code path, or perhaps the state of
@@ -1703,6 +1817,9 @@ static struct {
 	{ &prop_cursor_y, "CURSOR_Y", INT_MIN, INT_MAX },
 };
 
+static void intel_flip_init(struct drm_device *dev);
+static void intel_flip_fini(struct drm_device *dev);
+
 int intel_atomic_init(struct drm_device *dev)
 {
 	struct drm_crtc *crtc;
@@ -1776,6 +1893,8 @@ int intel_atomic_init(struct drm_device *dev)
 
 	dev->driver->atomic_funcs = &intel_atomic_funcs;
 
+	intel_flip_init(dev);
+
 	return 0;
 
  out:
@@ -1792,6 +1911,8 @@ void intel_atomic_fini(struct drm_device *dev)
 {
 	struct drm_crtc *crtc;
 
+	intel_flip_fini(dev);
+
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 		drm_property_destroy_blob(dev, crtc->mode_blob);
 		drm_property_destroy_blob(dev, crtc->connector_ids_blob);
@@ -1812,3 +1933,478 @@ void intel_atomic_fini(struct drm_device *dev)
 	drm_property_destroy(dev, prop_src_y);
 	drm_property_destroy(dev, prop_src_x);
 }
+
+enum {
+	/* somwehat arbitrary value */
+	INTEL_VBL_CNT_TIMEOUT = 5,
+};
+
+static void intel_flip_complete(struct drm_flip *flip)
+{
+	struct intel_flip *intel_flip =
+		container_of(flip, struct intel_flip, base);
+	struct drm_device *dev = intel_flip->crtc->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct drm_crtc *crtc = intel_flip->crtc;
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	int pipe = intel_crtc->pipe;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->event_lock, flags);
+
+	if (intel_flip->event) {
+		list_del_init(&intel_flip->pending_head);
+		intel_flip->event->event.old_fb_id = intel_flip->old_fb_id;
+		queue_event(dev, crtc, intel_flip->event);
+	}
+
+	spin_unlock_irqrestore(&dev->event_lock, flags);
+
+	if (intel_flip->vblank_ref)
+		drm_vblank_put(dev, pipe);
+
+	/* Possibly allow rendering to old_bo again */
+	if (intel_flip->old_bo) {
+		if (intel_flip->plane) {
+			struct intel_plane *intel_plane = to_intel_plane(intel_flip->plane);
+			atomic_clear_mask(1 << (16 + intel_plane->pipe), &intel_flip->old_bo->pending_flip.counter);
+		} else
+			atomic_clear_mask(1 << intel_crtc->plane, &intel_flip->old_bo->pending_flip.counter);
+
+		if (atomic_read(&intel_flip->old_bo->pending_flip) == 0)
+			wake_up(&dev_priv->pending_flip_queue);
+	}
+}
+
+static void intel_flip_finish(struct drm_flip *flip)
+{
+	struct intel_flip *intel_flip =
+		container_of(flip, struct intel_flip, base);
+	struct drm_device *dev = intel_flip->crtc->dev;
+
+	if (intel_flip->old_bo) {
+		mutex_lock(&dev->struct_mutex);
+
+		intel_unpin_fb_obj(intel_flip->old_bo);
+
+		drm_gem_object_unreference(&intel_flip->old_bo->base);
+
+		mutex_unlock(&dev->struct_mutex);
+	}
+
+	if (intel_flip->old_cursor_bo)
+		intel_crtc_cursor_bo_unref(intel_flip->crtc, intel_flip->old_cursor_bo);
+}
+
+static void intel_flip_cleanup(struct drm_flip *flip)
+{
+	struct intel_flip *intel_flip =
+		container_of(flip, struct intel_flip, base);
+
+	kfree(intel_flip);
+}
+
+static void intel_flip_driver_flush(struct drm_flip_driver *driver)
+{
+	struct drm_i915_private *dev_priv =
+		container_of(driver, struct drm_i915_private, flip_driver);
+
+	/* Flush posted writes */
+	I915_READ(PIPEDSL(PIPE_A));
+}
+
+static bool intel_have_new_frmcount(struct drm_device *dev)
+{
+	return IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5;
+}
+
+static u32 get_vbl_count(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 pipe = intel_crtc->pipe;
+
+	if (intel_have_new_frmcount(dev)) {
+		return I915_READ(PIPE_FRMCOUNT_GM45(pipe));
+	} else  {
+		u32 high, low1, low2, dsl;
+		unsigned int timeout = 0;
+
+		/*
+		 * FIXME check where the frame counter increments, and if
+		 * it happens in the middle of some line, take appropriate
+		 * measures to get a sensible reading.
+		 */
+
+		/* All reads must be satisfied during the same frame */
+		do {
+			low1 = I915_READ(PIPEFRAMEPIXEL(pipe)) >> PIPE_FRAME_LOW_SHIFT;
+			high = I915_READ(PIPEFRAME(pipe)) << 8;
+			dsl = I915_READ(PIPEDSL(pipe));
+			low2 = I915_READ(PIPEFRAMEPIXEL(pipe)) >> PIPE_FRAME_LOW_SHIFT;
+		} while (low1 != low2 && timeout++ < INTEL_VBL_CNT_TIMEOUT);
+
+		if (timeout >= INTEL_VBL_CNT_TIMEOUT)
+			dev_warn(dev->dev,
+				 "Timed out while determining VBL count for pipe %d\n", pipe);
+
+		return ((high | low2) +
+			((dsl >= crtc->hwmode.crtc_vdisplay) &&
+			 (dsl < crtc->hwmode.crtc_vtotal - 1))) & 0xffffff;
+	}
+}
+
+static unsigned int usecs_to_scanlines(struct drm_crtc *crtc,
+				       unsigned int usecs)
+{
+	/* paranoia */
+	if (!crtc->hwmode.crtc_htotal)
+		return 1;
+
+	return DIV_ROUND_UP(usecs * crtc->hwmode.clock,
+			    1000 * crtc->hwmode.crtc_htotal);
+}
+
+static void intel_pipe_vblank_evade(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 pipe = intel_crtc->pipe;
+	/* FIXME needs to be calibrated sensibly */
+	u32 min = crtc->hwmode.crtc_vdisplay - usecs_to_scanlines(crtc, 50);
+	u32 max = crtc->hwmode.crtc_vdisplay - 1;
+	long timeout = msecs_to_jiffies(3);
+	u32 val;
+
+	bool vblank_ref = drm_vblank_get(dev, pipe) == 0;
+
+	intel_crtc->vbl_received = false;
+
+	val = I915_READ(PIPEDSL(pipe));
+
+	while (val >= min && val <= max && timeout > 0) {
+		local_irq_enable();
+
+		timeout = wait_event_timeout(intel_crtc->vbl_wait,
+					     intel_crtc->vbl_received,
+					     timeout);
+
+		local_irq_disable();
+
+		intel_crtc->vbl_received = false;
+
+		val = I915_READ(PIPEDSL(pipe));
+	}
+
+	if (vblank_ref)
+		drm_vblank_put(dev, pipe);
+
+	if (val >= min && val <= max)
+		dev_warn(dev->dev,
+			 "Page flipping close to vblank start (DSL=%u, VBL=%u)\n",
+			 val, crtc->hwmode.crtc_vdisplay);
+}
+
+static bool vbl_count_after_eq_new(u32 a, u32 b)
+{
+	return !((a - b) & 0x80000000);
+}
+
+static bool vbl_count_after_eq(u32 a, u32 b)
+{
+	return !((a - b) & 0x800000);
+}
+
+static bool intel_vbl_check(struct drm_flip *pending_flip, u32 vbl_count)
+{
+	struct intel_flip *old_intel_flip =
+		container_of(pending_flip, struct intel_flip, base);
+	struct drm_device *dev = old_intel_flip->crtc->dev;
+
+	if (intel_have_new_frmcount(dev))
+		return vbl_count_after_eq_new(vbl_count, old_intel_flip->vbl_count);
+	else
+		return vbl_count_after_eq(vbl_count, old_intel_flip->vbl_count);
+}
+
+static void intel_flip_prepare(struct drm_flip *flip)
+{
+	struct intel_flip *intel_flip =
+		container_of(flip, struct intel_flip, base);
+
+	if (intel_flip->plane) {
+		struct drm_plane *plane = intel_flip->plane;
+		struct intel_plane *intel_plane = to_intel_plane(plane);
+
+		intel_plane->prepare(plane);
+	}
+}
+
+static bool intel_flip_flip(struct drm_flip *flip,
+			    struct drm_flip *pending_flip)
+{
+	struct intel_flip *intel_flip = container_of(flip, struct intel_flip, base);
+	struct drm_crtc *crtc = intel_flip->crtc;
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	struct drm_device *dev = crtc->dev;
+	int pipe = intel_crtc->pipe;
+	u32 vbl_count;
+
+	intel_flip->vblank_ref = drm_vblank_get(dev, pipe) == 0;
+
+	vbl_count = get_vbl_count(crtc);
+
+	/* arm all the double buffer registers */
+	if (intel_flip->plane) {
+		struct drm_plane *plane = intel_flip->plane;
+		struct intel_plane *intel_plane = to_intel_plane(plane);
+
+		intel_plane->commit(plane);
+	} else {
+		struct drm_i915_private *dev_priv = dev->dev_private;
+
+		dev_priv->display.commit_plane(crtc);
+	}
+
+	if (intel_flip->has_cursor)
+		intel_crtc_cursor_commit(crtc,
+					 intel_crtc->cursor_handle,
+					 intel_crtc->cursor_width,
+					 intel_crtc->cursor_height,
+					 intel_crtc->cursor_bo,
+					 intel_crtc->cursor_addr);
+
+	/* This flip will happen on the next vblank */
+	if (intel_have_new_frmcount(dev))
+		intel_flip->vbl_count = vbl_count + 1;
+	else
+		intel_flip->vbl_count = (vbl_count + 1) & 0xffffff;
+
+	if (pending_flip) {
+		struct intel_flip *old_intel_flip =
+			container_of(pending_flip, struct intel_flip, base);
+		bool flipped = intel_vbl_check(pending_flip, vbl_count);
+
+		if (!flipped) {
+			swap(intel_flip->old_fb_id, old_intel_flip->old_fb_id);
+			swap(intel_flip->old_bo, old_intel_flip->old_bo);
+			swap(intel_flip->old_cursor_bo, old_intel_flip->old_cursor_bo);
+		}
+
+		return flipped;
+	}
+
+	return false;
+}
+
+static bool intel_flip_vblank(struct drm_flip *pending_flip)
+{
+	struct intel_flip *old_intel_flip =
+		container_of(pending_flip, struct intel_flip, base);
+	u32 vbl_count = get_vbl_count(old_intel_flip->crtc);
+
+	return intel_vbl_check(pending_flip, vbl_count);
+}
+
+static const struct drm_flip_helper_funcs intel_flip_funcs = {
+	.prepare = intel_flip_prepare,
+	.flip = intel_flip_flip,
+	.vblank = intel_flip_vblank,
+	.complete = intel_flip_complete,
+	.finish = intel_flip_finish,
+	.cleanup = intel_flip_cleanup,
+};
+
+static const struct drm_flip_driver_funcs intel_flip_driver_funcs = {
+	.flush = intel_flip_driver_flush,
+};
+
+static void intel_flip_init(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_crtc *intel_crtc;
+	struct intel_plane *intel_plane;
+
+	drm_flip_driver_init(&dev_priv->flip_driver, &intel_flip_driver_funcs);
+
+	list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, base.head) {
+		init_waitqueue_head(&intel_crtc->vbl_wait);
+
+		drm_flip_helper_init(&intel_crtc->flip_helper,
+				     &dev_priv->flip_driver, &intel_flip_funcs);
+	}
+
+	list_for_each_entry(intel_plane, &dev->mode_config.plane_list, base.head)
+		drm_flip_helper_init(&intel_plane->flip_helper,
+				     &dev_priv->flip_driver, &intel_flip_funcs);
+}
+
+static void intel_flip_fini(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_crtc *intel_crtc;
+	struct intel_plane *intel_plane;
+
+	list_for_each_entry(intel_plane, &dev->mode_config.plane_list, base.head)
+		drm_flip_helper_fini(&intel_plane->flip_helper);
+
+	list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, base.head)
+		drm_flip_helper_fini(&intel_crtc->flip_helper);
+
+	drm_flip_driver_fini(&dev_priv->flip_driver);
+}
+
+static void atomic_pipe_commit(struct drm_device *dev,
+			       struct intel_atomic_state *state,
+			       int pipe)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct drm_i915_file_private *file_priv = state->file->driver_priv;
+	LIST_HEAD(flips);
+	int i;
+	bool pipe_enabled = to_intel_crtc(intel_get_crtc_for_pipe(dev, pipe))->active;
+
+	for (i = 0; i < dev->mode_config.num_crtc; i++) {
+		struct intel_crtc_state *st = &state->crtc[i];
+		struct drm_crtc *crtc = st->crtc;
+		struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+		struct intel_flip *intel_flip;
+
+		if (!st->fb_dirty && !st->cursor_dirty)
+			continue;
+
+		if (intel_crtc->pipe != pipe)
+			continue;
+
+		intel_flip = st->flip;
+		st->flip = NULL;
+
+		drm_flip_init(&intel_flip->base, &intel_crtc->flip_helper);
+
+		if (st->event) {
+			intel_flip->event = st->event;
+			st->event = NULL;
+			/* need to keep track of it in case process exits */
+			spin_lock_irq(&dev->event_lock);
+			list_add_tail(&intel_flip->pending_head,
+				      &file_priv->pending_flips);
+			spin_unlock_irq(&dev->event_lock);
+		}
+
+		intel_flip->crtc = crtc;
+
+		/* should already be checked so can't fail */
+		/* FIXME refactor the failing parts? */
+		dev_priv->display.calc_plane(crtc, crtc->fb, crtc->x, crtc->y);
+
+		if (st->cursor_dirty) {
+			intel_flip->has_cursor = true;
+			intel_flip->old_cursor_bo = st->old.cursor_bo;
+		}
+
+		if (st->old.fb) {
+			intel_flip->old_fb_id = st->old.fb->base.id;
+			intel_flip->old_bo = to_intel_framebuffer(st->old.fb)->obj;
+
+			mutex_lock(&dev->struct_mutex);
+			drm_gem_object_reference(&intel_flip->old_bo->base);
+			mutex_unlock(&dev->struct_mutex);
+
+			/*
+			 * Block clients from rendering to the new back buffer until
+			 * the flip occurs and the object is no longer visible.
+			 */
+			atomic_set_mask(1 << intel_crtc->plane,
+					&intel_flip->old_bo->pending_flip.counter);
+		}
+
+		list_add_tail(&intel_flip->base.list, &flips);
+	}
+
+	for (i = 0; i < dev->mode_config.num_plane; i++) {
+		struct intel_plane_state *st = &state->plane[i];
+		struct drm_plane *plane = st->plane;
+		struct intel_plane *intel_plane = to_intel_plane(plane);
+		struct intel_flip *intel_flip;
+
+		if (!st->dirty)
+			continue;
+
+		if (intel_plane->pipe != pipe)
+			continue;
+
+		intel_flip = st->flip;
+		st->flip = NULL;
+
+		drm_flip_init(&intel_flip->base, &intel_plane->flip_helper);
+
+		if (st->event) {
+			intel_flip->event = st->event;
+			st->event = NULL;
+			/* need to keep track of it in case process exits */
+			spin_lock_irq(&dev->event_lock);
+			list_add_tail(&intel_flip->pending_head,
+				      &file_priv->pending_flips);
+			spin_unlock_irq(&dev->event_lock);
+		}
+
+		intel_flip->crtc = intel_get_crtc_for_pipe(dev, pipe);
+		intel_flip->plane = plane;
+
+		intel_plane->calc(plane, plane->fb, &st->coords);
+
+		if (st->old.fb) {
+			intel_flip->old_fb_id = st->old.fb->base.id;
+			intel_flip->old_bo = to_intel_framebuffer(st->old.fb)->obj;
+
+			mutex_lock(&dev->struct_mutex);
+			drm_gem_object_reference(&intel_flip->old_bo->base);
+			mutex_unlock(&dev->struct_mutex);
+
+			/*
+			 * Block clients from rendering to the new back buffer until
+			 * the flip occurs and the object is no longer visible.
+			 */
+			atomic_set_mask(1 << (16 + intel_plane->pipe),
+					&intel_flip->old_bo->pending_flip.counter);
+		}
+
+		list_add_tail(&intel_flip->base.list, &flips);
+	}
+
+	if (list_empty(&flips))
+		return;
+
+	if (!pipe_enabled) {
+		drm_flip_driver_complete_flips(&dev_priv->flip_driver, &flips);
+		return;
+	}
+
+	drm_flip_driver_prepare_flips(&dev_priv->flip_driver, &flips);
+
+	local_irq_disable();
+
+	intel_pipe_vblank_evade(intel_get_crtc_for_pipe(dev, pipe));
+
+	drm_flip_driver_schedule_flips(&dev_priv->flip_driver, &flips);
+
+	local_irq_enable();
+}
+
+void intel_atomic_handle_vblank(struct drm_device *dev, int pipe)
+{
+	struct intel_crtc *intel_crtc = to_intel_crtc(intel_get_crtc_for_pipe(dev, pipe));
+	struct intel_plane *intel_plane;
+
+	intel_crtc->vbl_received = true;
+	wake_up(&intel_crtc->vbl_wait);
+
+	drm_flip_helper_vblank(&intel_crtc->flip_helper);
+
+	list_for_each_entry(intel_plane, &dev->mode_config.plane_list, base.head) {
+		if (intel_plane->pipe == pipe)
+			drm_flip_helper_vblank(&intel_plane->flip_helper);
+	}
+}
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index ac46281..756cf94 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -3357,6 +3357,7 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
 		encoder->disable(encoder);
 
 	intel_crtc_wait_for_pending_flips(crtc);
+	drm_flip_helper_clear(&intel_crtc->flip_helper);
 	drm_vblank_off(dev, pipe);
 	intel_crtc_update_cursor(crtc, false);
 
@@ -3493,6 +3494,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
 
 	/* Give the overlay scaler a chance to disable if it's on this pipe */
 	intel_crtc_wait_for_pending_flips(crtc);
+	drm_flip_helper_clear(&intel_crtc->flip_helper);
 	drm_vblank_off(dev, pipe);
 	intel_crtc_dpms_overlay(intel_crtc, false);
 	intel_crtc_update_cursor(crtc, false);
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 616d5d3..4784c44 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -32,6 +32,7 @@
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_dp_helper.h>
+#include <drm/drm_flip.h>
 
 #define _wait_for(COND, MS, W) ({ \
 	unsigned long timeout__ = jiffies + msecs_to_jiffies(MS);	\
@@ -227,6 +228,9 @@ struct intel_crtc {
 	/* We can share PLLs across outputs if the timings match */
 	struct intel_pch_pll *pch_pll;
 	struct intel_plane_regs primary_regs;
+	struct drm_flip_helper flip_helper;
+	wait_queue_head_t vbl_wait;
+	bool vbl_received;
 };
 
 struct intel_plane_coords {
@@ -257,6 +261,7 @@ struct intel_plane {
 	void (*prepare)(struct drm_plane *plane);
 	void (*commit)(struct drm_plane *plane);
 	struct intel_plane_regs regs;
+	struct drm_flip_helper flip_helper;
 };
 
 struct intel_watermark_params {
@@ -629,5 +634,7 @@ extern bool intel_crtc_mode_fixup(struct drm_crtc *crtc,
 
 extern int intel_atomic_init(struct drm_device *dev);
 extern void intel_atomic_fini(struct drm_device *dev);
+extern void intel_atomic_free_events(struct drm_device *dev, struct drm_file *file);
+extern void intel_atomic_handle_vblank(struct drm_device *dev, int pipe);
 
 #endif /* __INTEL_DRV_H__ */
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 48/51] drm/i915: Unstatic intel_enable_primary() and intel_disable_primary()
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (46 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 47/51] drm/i915: Add atomic page flip support ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 49/51] drm/i915: Respect primary_disabled in crtc_enable() ville.syrjala
                   ` (2 subsequent siblings)
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

intel_enable_primary() and intel_disable_primary() are needed in the
atomic mode setting code.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_drv.h    |    3 +++
 drivers/gpu/drm/i915/intel_sprite.c |    4 ++--
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 4784c44..b9b96d3 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -637,4 +637,7 @@ extern void intel_atomic_fini(struct drm_device *dev);
 extern void intel_atomic_free_events(struct drm_device *dev, struct drm_file *file);
 extern void intel_atomic_handle_vblank(struct drm_device *dev, int pipe);
 
+extern void intel_enable_primary(struct drm_crtc *crtc);
+extern void intel_disable_primary(struct drm_crtc *crtc);
+
 #endif /* __INTEL_DRV_H__ */
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index 06d62e70..88fdd0d 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -574,7 +574,7 @@ void intel_calc_sprite(struct drm_plane *plane,
 		ilk_calc_plane(plane, fb, coords);
 }
 
-static void
+void
 intel_enable_primary(struct drm_crtc *crtc)
 {
 	struct drm_device *dev = crtc->dev;
@@ -593,7 +593,7 @@ intel_enable_primary(struct drm_crtc *crtc)
 	dev_priv->display.commit_plane(crtc);
 }
 
-static void
+void
 intel_disable_primary(struct drm_crtc *crtc)
 {
 	struct drm_device *dev = crtc->dev;
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 49/51] drm/i915: Respect primary_disabled in crtc_enable()
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (47 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 48/51] drm/i915: Unstatic intel_enable_primary() and intel_disable_primary() ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 50/51] drm/i915: Enable/disable primary plane in calc_plane() ville.syrjala
  2012-10-25 18:05 ` [PATCH 51/51] drm/i915: Add primary plane disable logic to atomic mode setting code ville.syrjala
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Check primary_disabled state before enabling the primary plane in
crtc_enable() hooks.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_display.c |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 756cf94..6a1ed7e 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -3311,7 +3311,8 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
 	intel_crtc_load_lut(crtc);
 
 	intel_enable_pipe(dev_priv, pipe, is_pch_port);
-	intel_enable_plane(dev_priv, plane, pipe);
+	if (!intel_crtc->primary_disabled)
+		intel_enable_plane(dev_priv, plane, pipe);
 
 	if (is_pch_port)
 		ironlake_pch_enable(crtc);
@@ -3463,7 +3464,8 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc)
 
 	intel_enable_pll(dev_priv, pipe);
 	intel_enable_pipe(dev_priv, pipe, false);
-	intel_enable_plane(dev_priv, plane, pipe);
+	if (!intel_crtc->primary_disabled)
+		intel_enable_plane(dev_priv, plane, pipe);
 
 	intel_crtc_load_lut(crtc);
 	intel_update_fbc(dev);
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 50/51] drm/i915: Enable/disable primary plane in calc_plane()
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (48 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 49/51] drm/i915: Respect primary_disabled in crtc_enable() ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  2012-10-25 18:05 ` [PATCH 51/51] drm/i915: Add primary plane disable logic to atomic mode setting code ville.syrjala
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Check the active and primary_disabled flags and set the
DISPLAY_PLANE_ENABLE bit accordingly in calc_plane() hook for the
primary plane.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_display.c |   10 ++++++++++
 1 files changed, 10 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 6a1ed7e..43cff11 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -2026,6 +2026,11 @@ static int i9xx_calc_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb,
 			regs->cntr &= ~DISPPLANE_TILED;
 	}
 
+	if (intel_crtc->active && !intel_crtc->primary_disabled)
+		regs->cntr |= DISPLAY_PLANE_ENABLE;
+	else
+		regs->cntr &= ~DISPLAY_PLANE_ENABLE;
+
 	linear_offset = fb->offsets[0] + y * fb->pitches[0] + x * cpp;
 
 	if (INTEL_INFO(dev)->gen >= 4) {
@@ -2133,6 +2138,11 @@ static int ironlake_calc_plane(struct drm_crtc *crtc,
 	/* must disable */
 	regs->cntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
 
+	if (intel_crtc->active && !intel_crtc->primary_disabled)
+		regs->cntr |= DISPLAY_PLANE_ENABLE;
+	else
+		regs->cntr &= ~DISPLAY_PLANE_ENABLE;
+
 	linear_offset = fb->offsets[0] + y * fb->pitches[0] + x * (fb->bits_per_pixel / 8);
 	intel_crtc->dspaddr_offset =
 		gen4_compute_dspaddr_offset_xtiled(&x, &y,
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 51/51] drm/i915: Add primary plane disable logic to atomic mode setting code
  2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
                   ` (49 preceding siblings ...)
  2012-10-25 18:05 ` [PATCH 50/51] drm/i915: Enable/disable primary plane in calc_plane() ville.syrjala
@ 2012-10-25 18:05 ` ville.syrjala
  50 siblings, 0 replies; 61+ messages in thread
From: ville.syrjala @ 2012-10-25 18:05 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Enable/disable the primary plane accordingly when the sprite plane
coverage changes.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_atomic.c |   41 +++++++++++++++++++++++++++++++++++
 1 files changed, 41 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c
index 238a843..41885fa 100644
--- a/drivers/gpu/drm/i915/intel_atomic.c
+++ b/drivers/gpu/drm/i915/intel_atomic.c
@@ -93,6 +93,7 @@ struct intel_crtc_state {
 	bool changed;
 	struct drm_pending_atomic_event *event;
 	struct intel_flip *flip;
+	bool primary_disabled;
 
 	struct {
 		bool enabled;
@@ -318,6 +319,8 @@ static void *intel_atomic_begin(struct drm_device *dev, struct drm_file *file,
 
 		s->old.connectors_bitmask = s->connectors_bitmask;
 		s->old.encoders_bitmask = s->encoders_bitmask;
+
+		s->primary_disabled = intel_crtc->primary_disabled;
 	}
 
 	i = 0;
@@ -1157,6 +1160,9 @@ static int apply_config(struct drm_device *dev,
 						 intel_crtc->cursor_addr);
 		}
 
+		if (!st->primary_disabled)
+			intel_enable_primary(crtc);
+
 		for (j = 0; j < dev->mode_config.num_plane; j++) {
 			struct intel_plane_state *pst = &s->plane[j];
 			struct drm_plane *plane = pst->plane;
@@ -1170,6 +1176,9 @@ static int apply_config(struct drm_device *dev,
 			else if (!pst->coords.visible && pst->old.crtc == crtc)
 				intel_plane->disable_plane(plane);
 		}
+
+		if (st->primary_disabled)
+			intel_disable_primary(crtc);
 	}
 
 	/* don't restore the old state in end() */
@@ -1207,6 +1216,7 @@ static void restore_state(struct drm_device *dev,
 		intel_crtc->cursor_width = s->saved_crtcs[i].cursor_width;
 		intel_crtc->cursor_height = s->saved_crtcs[i].cursor_height;
 		intel_crtc->cursor_visible = s->saved_crtcs[i].cursor_visible;
+		intel_crtc->primary_disabled = s->saved_crtcs[i].primary_disabled;
 
 		i++;
 	}
@@ -1346,6 +1356,28 @@ static int check_crtc(struct intel_crtc_state *s)
 	return 0;
 }
 
+static void update_primary_visibility(struct drm_device *dev,
+				      struct intel_atomic_state *s,
+				      const struct drm_crtc *crtc,
+				      const struct drm_plane *plane,
+				      const struct intel_plane_coords *coords)
+{
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	bool primary_disabled =
+		coords->visible &&
+		coords->crtc_x == 0 &&
+		coords->crtc_y == 0 &&
+		coords->crtc_w == crtc->mode.hdisplay &&
+		coords->crtc_h == crtc->mode.vdisplay;
+
+	if (primary_disabled != intel_crtc->primary_disabled) {
+		struct intel_crtc_state *st = get_crtc_state(dev, s, crtc);
+		st->fb_dirty = true;
+		st->primary_disabled = primary_disabled;
+		s->dirty = true;
+	}
+}
+
 static int intel_atomic_check(struct drm_device *dev, void *state)
 {
 	struct intel_atomic_state *s = state;
@@ -1430,6 +1462,12 @@ static int intel_atomic_check(struct drm_device *dev, void *state)
 		ret = intel_check_plane(plane, plane->crtc, plane->fb, &st->coords);
 		if (ret)
 			return ret;
+
+		/* FIXME doesn't correctly handle cases where plane moves between crtcs */
+		if (plane->crtc)
+			update_primary_visibility(dev, s, plane->crtc, plane, &st->coords);
+		else if (st->old.crtc)
+			update_primary_visibility(dev, s, st->old.crtc, plane, &st->coords);
 	}
 
 	return 0;
@@ -2295,6 +2333,9 @@ static void atomic_pipe_commit(struct drm_device *dev,
 
 		intel_flip->crtc = crtc;
 
+		/* update primary_disabled befoer calc_plane() */
+		intel_crtc->primary_disabled = st->primary_disabled;
+
 		/* should already be checked so can't fail */
 		/* FIXME refactor the failing parts? */
 		dev_priv->display.calc_plane(crtc, crtc->fb, crtc->x, crtc->y);
-- 
1.7.8.6

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 61+ messages in thread

* Re: [PATCH 46/51] drm/i915: Add support for atomic modesetting completion events
  2012-10-25 18:05 ` [PATCH 46/51] drm/i915: Add support for atomic modesetting completion events ville.syrjala
@ 2012-11-01 11:12   ` Daniel Vetter
  2012-11-01 14:39     ` Jesse Barnes
  0 siblings, 1 reply; 61+ messages in thread
From: Daniel Vetter @ 2012-11-01 11:12 UTC (permalink / raw)
  To: ville.syrjala; +Cc: dri-devel

On Thu, Oct 25, 2012 at 8:05 PM,  <ville.syrjala@linux.intel.com> wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>
> Send completion events when the atomic modesetting operations has
> finished succesfully.
>
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>

I have to admit I'm not on top of the latest ioctl/interface
discussion, but one new requirement for the modeset (not the pageflip
part) of the all this atomic stuff I've discovered is that the kernel
needs to be able to select the crtcs for each output completely
unrestricted. I think userspace should simply pass in abstract crtc
ids (e.g. 0, 1, 2, ...) and the kernel then passes back the actual
crtcs it has selected.

We can't do that remapping internally because the crtc abstraction is leaky:
- wait_for_vblank requires the pipe id, which could then change on every modeset
- similarly userspace doing MI_WAIT for scanlines needs to know the
actual hw pipe in use by a crtc.
And current userspace presumes that the mapping between crtc->pipe
doesn't change.

An example why the kernel needs to pick the crtc for userspace:
- on ivb only pipe A has a 7x5 panel fitter, so usually you want to
put the panel on the first crtc
- but if you run in a 3 pipe configuration and have an eDP panel, it's
better to put the eDP output on pipe C, since then pipes A&B will have
full 4-lane fdi links to the pch ports (instead of otherwise only 2
lanes each on links B&C)
- similarly when we have a 3 pipe configuration with all encoders on
the pch, we need to move the mode with the highest dotclock to pipe A
(since that's the only one which will have 4 lanes, pipe B&C will only
have 2 each).
- afaik these kind of asymmetric constraints won't disappear anytime
soon, haswell definitely still has some.

Cheers, Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH 46/51] drm/i915: Add support for atomic modesetting completion events
  2012-11-01 11:12   ` Daniel Vetter
@ 2012-11-01 14:39     ` Jesse Barnes
  2012-11-01 17:07       ` Ville Syrjälä
  0 siblings, 1 reply; 61+ messages in thread
From: Jesse Barnes @ 2012-11-01 14:39 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: dri-devel

On Thu, 1 Nov 2012 12:12:35 +0100
Daniel Vetter <daniel@ffwll.ch> wrote:

> On Thu, Oct 25, 2012 at 8:05 PM,  <ville.syrjala@linux.intel.com> wrote:
> > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> >
> > Send completion events when the atomic modesetting operations has
> > finished succesfully.
> >
> > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> I have to admit I'm not on top of the latest ioctl/interface
> discussion, but one new requirement for the modeset (not the pageflip
> part) of the all this atomic stuff I've discovered is that the kernel
> needs to be able to select the crtcs for each output completely
> unrestricted. I think userspace should simply pass in abstract crtc
> ids (e.g. 0, 1, 2, ...) and the kernel then passes back the actual
> crtcs it has selected.
> 
> We can't do that remapping internally because the crtc abstraction is leaky:
> - wait_for_vblank requires the pipe id, which could then change on every modeset
> - similarly userspace doing MI_WAIT for scanlines needs to know the
> actual hw pipe in use by a crtc.
> And current userspace presumes that the mapping between crtc->pipe
> doesn't change.
> 
> An example why the kernel needs to pick the crtc for userspace:
> - on ivb only pipe A has a 7x5 panel fitter, so usually you want to
> put the panel on the first crtc
> - but if you run in a 3 pipe configuration and have an eDP panel, it's
> better to put the eDP output on pipe C, since then pipes A&B will have
> full 4-lane fdi links to the pch ports (instead of otherwise only 2
> lanes each on links B&C)
> - similarly when we have a 3 pipe configuration with all encoders on
> the pch, we need to move the mode with the highest dotclock to pipe A
> (since that's the only one which will have 4 lanes, pipe B&C will only
> have 2 each).
> - afaik these kind of asymmetric constraints won't disappear anytime
> soon, haswell definitely still has some.

Yeah that's a good point... adding a virtual crtc layer would solve
this and let us preserve the existing ABI.

-- 
Jesse Barnes, Intel Open Source Technology Center
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH 46/51] drm/i915: Add support for atomic modesetting completion events
  2012-11-01 14:39     ` Jesse Barnes
@ 2012-11-01 17:07       ` Ville Syrjälä
  2012-11-01 17:12         ` Jesse Barnes
  0 siblings, 1 reply; 61+ messages in thread
From: Ville Syrjälä @ 2012-11-01 17:07 UTC (permalink / raw)
  To: Jesse Barnes; +Cc: dri-devel

On Thu, Nov 01, 2012 at 07:39:12AM -0700, Jesse Barnes wrote:
> On Thu, 1 Nov 2012 12:12:35 +0100
> Daniel Vetter <daniel@ffwll.ch> wrote:
> 
> > On Thu, Oct 25, 2012 at 8:05 PM,  <ville.syrjala@linux.intel.com> wrote:
> > > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > >
> > > Send completion events when the atomic modesetting operations has
> > > finished succesfully.
> > >
> > > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > 
> > I have to admit I'm not on top of the latest ioctl/interface
> > discussion, but one new requirement for the modeset (not the pageflip
> > part) of the all this atomic stuff I've discovered is that the kernel
> > needs to be able to select the crtcs for each output completely
> > unrestricted. I think userspace should simply pass in abstract crtc
> > ids (e.g. 0, 1, 2, ...) and the kernel then passes back the actual
> > crtcs it has selected.
> > 
> > We can't do that remapping internally because the crtc abstraction is leaky:
> > - wait_for_vblank requires the pipe id, which could then change on every modeset
> > - similarly userspace doing MI_WAIT for scanlines needs to know the
> > actual hw pipe in use by a crtc.
> > And current userspace presumes that the mapping between crtc->pipe
> > doesn't change.
> > 
> > An example why the kernel needs to pick the crtc for userspace:
> > - on ivb only pipe A has a 7x5 panel fitter, so usually you want to
> > put the panel on the first crtc
> > - but if you run in a 3 pipe configuration and have an eDP panel, it's
> > better to put the eDP output on pipe C, since then pipes A&B will have
> > full 4-lane fdi links to the pch ports (instead of otherwise only 2
> > lanes each on links B&C)
> > - similarly when we have a 3 pipe configuration with all encoders on
> > the pch, we need to move the mode with the highest dotclock to pipe A
> > (since that's the only one which will have 4 lanes, pipe B&C will only
> > have 2 each).
> > - afaik these kind of asymmetric constraints won't disappear anytime
> > soon, haswell definitely still has some.
> 
> Yeah that's a good point... adding a virtual crtc layer would solve
> this and let us preserve the existing ABI.

How would the state handling work? I mean if drm_crtc X currently has
some state, drm_crtc Y has some other state, and then we do a modeset
which would require swapping the roles of the crtcs, what would happen
to the bits of state that we didn't specify?

If we'd do the remapping below the drm crtc layer, the state would
always be tied to the drm crtc. But that would definitely require
mostly uniform hardware "crtcs" so that the capabilities of the
drm_crtcs wouldn't keep changing whenever the remap happens.

Well, I suppose we could tie the state to the virtual crtc instead,
and doing an operation on a real drm_crtc would also change the
state of the currently bound virtual crtc. And then changing the
virtual<->real mapping would just copy the state over from the virtual
crtc to the real drm_crtc.

And if we do it for crtcs, then we'd need to do it for planes as well,
because the plane<->crtc mapping can be fixed or otherwise limited
in some fashion.

Either way it sounds rather messy to me.

Another option would be just leave it up to userspace to make the
correct choice between crtcs and planes. But then user space needs
to be equipped with more hardware specific knowledge, so it's not
a very appealing idea either.

-- 
Ville Syrjälä
Intel OTC

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH 46/51] drm/i915: Add support for atomic modesetting completion events
  2012-11-01 17:07       ` Ville Syrjälä
@ 2012-11-01 17:12         ` Jesse Barnes
  2012-11-01 22:39           ` Daniel Vetter
  0 siblings, 1 reply; 61+ messages in thread
From: Jesse Barnes @ 2012-11-01 17:12 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: dri-devel

On Thu, 1 Nov 2012 19:07:02 +0200
Ville Syrjälä <ville.syrjala@linux.intel.com> wrote:

> On Thu, Nov 01, 2012 at 07:39:12AM -0700, Jesse Barnes wrote:
> > On Thu, 1 Nov 2012 12:12:35 +0100
> > Daniel Vetter <daniel@ffwll.ch> wrote:
> > 
> > > On Thu, Oct 25, 2012 at 8:05 PM,  <ville.syrjala@linux.intel.com> wrote:
> > > > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > >
> > > > Send completion events when the atomic modesetting operations has
> > > > finished succesfully.
> > > >
> > > > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > 
> > > I have to admit I'm not on top of the latest ioctl/interface
> > > discussion, but one new requirement for the modeset (not the pageflip
> > > part) of the all this atomic stuff I've discovered is that the kernel
> > > needs to be able to select the crtcs for each output completely
> > > unrestricted. I think userspace should simply pass in abstract crtc
> > > ids (e.g. 0, 1, 2, ...) and the kernel then passes back the actual
> > > crtcs it has selected.
> > > 
> > > We can't do that remapping internally because the crtc abstraction is leaky:
> > > - wait_for_vblank requires the pipe id, which could then change on every modeset
> > > - similarly userspace doing MI_WAIT for scanlines needs to know the
> > > actual hw pipe in use by a crtc.
> > > And current userspace presumes that the mapping between crtc->pipe
> > > doesn't change.
> > > 
> > > An example why the kernel needs to pick the crtc for userspace:
> > > - on ivb only pipe A has a 7x5 panel fitter, so usually you want to
> > > put the panel on the first crtc
> > > - but if you run in a 3 pipe configuration and have an eDP panel, it's
> > > better to put the eDP output on pipe C, since then pipes A&B will have
> > > full 4-lane fdi links to the pch ports (instead of otherwise only 2
> > > lanes each on links B&C)
> > > - similarly when we have a 3 pipe configuration with all encoders on
> > > the pch, we need to move the mode with the highest dotclock to pipe A
> > > (since that's the only one which will have 4 lanes, pipe B&C will only
> > > have 2 each).
> > > - afaik these kind of asymmetric constraints won't disappear anytime
> > > soon, haswell definitely still has some.
> > 
> > Yeah that's a good point... adding a virtual crtc layer would solve
> > this and let us preserve the existing ABI.
> 
> How would the state handling work? I mean if drm_crtc X currently has
> some state, drm_crtc Y has some other state, and then we do a modeset
> which would require swapping the roles of the crtcs, what would happen
> to the bits of state that we didn't specify?
> 
> If we'd do the remapping below the drm crtc layer, the state would
> always be tied to the drm crtc. But that would definitely require
> mostly uniform hardware "crtcs" so that the capabilities of the
> drm_crtcs wouldn't keep changing whenever the remap happens.
> 
> Well, I suppose we could tie the state to the virtual crtc instead,
> and doing an operation on a real drm_crtc would also change the
> state of the currently bound virtual crtc. And then changing the
> virtual<->real mapping would just copy the state over from the virtual
> crtc to the real drm_crtc.
> 
> And if we do it for crtcs, then we'd need to do it for planes as well,
> because the plane<->crtc mapping can be fixed or otherwise limited
> in some fashion.
> 
> Either way it sounds rather messy to me.
> 
> Another option would be just leave it up to userspace to make the
> correct choice between crtcs and planes. But then user space needs
> to be equipped with more hardware specific knowledge, so it's not
> a very appealing idea either.

Yeah it gets ugly one way or another.  From a userspace perspective,
keeping the ugliness in the kernel is nice, and if we have to do it
somewhere I guess I'd prefer that.

However, we can't always hide hw details like that in the kernel
through generic interfaces (e.g. for sprites and all their
restrictions) so userspace will have to have some knowledge one way or
another, and maybe it's not that bad to push some of the other
limitation knowledge into our userspace code.

Ambivalent.

-- 
Jesse Barnes, Intel Open Source Technology Center
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH 46/51] drm/i915: Add support for atomic modesetting completion events
  2012-11-01 17:12         ` Jesse Barnes
@ 2012-11-01 22:39           ` Daniel Vetter
  2012-11-02  9:10             ` Ville Syrjälä
  2012-11-07 20:29             ` Rob Clark
  0 siblings, 2 replies; 61+ messages in thread
From: Daniel Vetter @ 2012-11-01 22:39 UTC (permalink / raw)
  To: Jesse Barnes; +Cc: dri-devel

On Thu, Nov 01, 2012 at 10:12:21AM -0700, Jesse Barnes wrote:
> On Thu, 1 Nov 2012 19:07:02 +0200
> Ville Syrjälä <ville.syrjala@linux.intel.com> wrote:
> 
> > On Thu, Nov 01, 2012 at 07:39:12AM -0700, Jesse Barnes wrote:
> > > On Thu, 1 Nov 2012 12:12:35 +0100
> > > Daniel Vetter <daniel@ffwll.ch> wrote:
> > > 
> > > > On Thu, Oct 25, 2012 at 8:05 PM,  <ville.syrjala@linux.intel.com> wrote:
> > > > > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > > >
> > > > > Send completion events when the atomic modesetting operations has
> > > > > finished succesfully.
> > > > >
> > > > > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > > 
> > > > I have to admit I'm not on top of the latest ioctl/interface
> > > > discussion, but one new requirement for the modeset (not the pageflip
> > > > part) of the all this atomic stuff I've discovered is that the kernel
> > > > needs to be able to select the crtcs for each output completely
> > > > unrestricted. I think userspace should simply pass in abstract crtc
> > > > ids (e.g. 0, 1, 2, ...) and the kernel then passes back the actual
> > > > crtcs it has selected.
> > > > 
> > > > We can't do that remapping internally because the crtc abstraction is leaky:
> > > > - wait_for_vblank requires the pipe id, which could then change on every modeset
> > > > - similarly userspace doing MI_WAIT for scanlines needs to know the
> > > > actual hw pipe in use by a crtc.
> > > > And current userspace presumes that the mapping between crtc->pipe
> > > > doesn't change.
> > > > 
> > > > An example why the kernel needs to pick the crtc for userspace:
> > > > - on ivb only pipe A has a 7x5 panel fitter, so usually you want to
> > > > put the panel on the first crtc
> > > > - but if you run in a 3 pipe configuration and have an eDP panel, it's
> > > > better to put the eDP output on pipe C, since then pipes A&B will have
> > > > full 4-lane fdi links to the pch ports (instead of otherwise only 2
> > > > lanes each on links B&C)
> > > > - similarly when we have a 3 pipe configuration with all encoders on
> > > > the pch, we need to move the mode with the highest dotclock to pipe A
> > > > (since that's the only one which will have 4 lanes, pipe B&C will only
> > > > have 2 each).
> > > > - afaik these kind of asymmetric constraints won't disappear anytime
> > > > soon, haswell definitely still has some.
> > > 
> > > Yeah that's a good point... adding a virtual crtc layer would solve
> > > this and let us preserve the existing ABI.
> > 
> > How would the state handling work? I mean if drm_crtc X currently has
> > some state, drm_crtc Y has some other state, and then we do a modeset
> > which would require swapping the roles of the crtcs, what would happen
> > to the bits of state that we didn't specify?
> > 
> > If we'd do the remapping below the drm crtc layer, the state would
> > always be tied to the drm crtc. But that would definitely require
> > mostly uniform hardware "crtcs" so that the capabilities of the
> > drm_crtcs wouldn't keep changing whenever the remap happens.
> > 
> > Well, I suppose we could tie the state to the virtual crtc instead,
> > and doing an operation on a real drm_crtc would also change the
> > state of the currently bound virtual crtc. And then changing the
> > virtual<->real mapping would just copy the state over from the virtual
> > crtc to the real drm_crtc.
> > 
> > And if we do it for crtcs, then we'd need to do it for planes as well,
> > because the plane<->crtc mapping can be fixed or otherwise limited
> > in some fashion.
> > 
> > Either way it sounds rather messy to me.
> > 
> > Another option would be just leave it up to userspace to make the
> > correct choice between crtcs and planes. But then user space needs
> > to be equipped with more hardware specific knowledge, so it's not
> > a very appealing idea either.
> 
> Yeah it gets ugly one way or another.  From a userspace perspective,
> keeping the ugliness in the kernel is nice, and if we have to do it
> somewhere I guess I'd prefer that.

My tentative Grand Plan (tm) for the atomic modeset implementation of such
things is to pimp the new struct intel_crtc_config to contain all the
configuration state (so with Rob's atomic modeset proposal that would also
embed the drm_crtc_state struct). It would also contain all the derived
state like pll settings, fdi lanes, ...

Now the improve >mode_adjust stage, now called ->compute_config allocates
such a struct for each crtc, does some prep, calls down into
encoder->compute_config callbacks, then applies any fixups and screaming
required to come up with a working global config. All rather hazy, I know
;-)

But e.g. for the above case of trying to squeeze the fdi links into the
available sets of fdi lanes I guess we could first compute the upper bound
for the fdi link requirements (the current wip stuff already pre-computes
the pipe_bpp from the fb->depth). Then check whether that fits, do any
readjustments (I already have a has_pch_encoder attribute, maybe at the
wrong spot still, but we should be able to know which outputs need fdi
links). If there's no way to fit it, reassign pipes a bit or try
dithering. Once that works, call into encoders ...

Or maybe we could do a loop, since the encoders also limit the pipe_bpp.
So first pipe_bpp from the fb->depth, then check for output properties
(6bpc dithering on lvds, or a puny dp link), then check whether it fits
into fdi. If not, dither more or reassign, then re-run the encoder config
computations. If it still has too high bw requirementsmuch, give up.

In any case, and disregarding the above ramblings, I plan to make the
intel_crtc_config thing free-standing for the ->compute_config stage, so
we could easily add a preferred_crtc pointer to it since it's not tied to
a specific crtc at that point. The problem now is that the
connector->encoder->crtc links are embedded into the connectors and
encoders, so they are not free-standing. But if we want to support atomic
modeset on all properties (which I think we should), we need to fix that
anyway ...

> However, we can't always hide hw details like that in the kernel
> through generic interfaces (e.g. for sprites and all their
> restrictions) so userspace will have to have some knowledge one way or
> another, and maybe it's not that bad to push some of the other
> limitation knowledge into our userspace code.

I disagree, there's no sane way that userspace can figure out that the 3
pipe config it wants would work, but only if it moves the eDP output to
some other pipe. So if our aim is to support that (I know, we have more
pressing and less lofty things on the table), the interface should allow
it.

Cheers, Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH 46/51] drm/i915: Add support for atomic modesetting completion events
  2012-11-01 22:39           ` Daniel Vetter
@ 2012-11-02  9:10             ` Ville Syrjälä
  2012-11-07 20:29             ` Rob Clark
  1 sibling, 0 replies; 61+ messages in thread
From: Ville Syrjälä @ 2012-11-02  9:10 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: dri-devel

On Thu, Nov 01, 2012 at 11:39:58PM +0100, Daniel Vetter wrote:
> On Thu, Nov 01, 2012 at 10:12:21AM -0700, Jesse Barnes wrote:
> > On Thu, 1 Nov 2012 19:07:02 +0200
> > Ville Syrjälä <ville.syrjala@linux.intel.com> wrote:
> > 
> > > On Thu, Nov 01, 2012 at 07:39:12AM -0700, Jesse Barnes wrote:
> > > > On Thu, 1 Nov 2012 12:12:35 +0100
> > > > Daniel Vetter <daniel@ffwll.ch> wrote:
> > > > 
> > > > > On Thu, Oct 25, 2012 at 8:05 PM,  <ville.syrjala@linux.intel.com> wrote:
> > > > > > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > > > >
> > > > > > Send completion events when the atomic modesetting operations has
> > > > > > finished succesfully.
> > > > > >
> > > > > > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > > > 
> > > > > I have to admit I'm not on top of the latest ioctl/interface
> > > > > discussion, but one new requirement for the modeset (not the pageflip
> > > > > part) of the all this atomic stuff I've discovered is that the kernel
> > > > > needs to be able to select the crtcs for each output completely
> > > > > unrestricted. I think userspace should simply pass in abstract crtc
> > > > > ids (e.g. 0, 1, 2, ...) and the kernel then passes back the actual
> > > > > crtcs it has selected.
> > > > > 
> > > > > We can't do that remapping internally because the crtc abstraction is leaky:
> > > > > - wait_for_vblank requires the pipe id, which could then change on every modeset
> > > > > - similarly userspace doing MI_WAIT for scanlines needs to know the
> > > > > actual hw pipe in use by a crtc.
> > > > > And current userspace presumes that the mapping between crtc->pipe
> > > > > doesn't change.
> > > > > 
> > > > > An example why the kernel needs to pick the crtc for userspace:
> > > > > - on ivb only pipe A has a 7x5 panel fitter, so usually you want to
> > > > > put the panel on the first crtc
> > > > > - but if you run in a 3 pipe configuration and have an eDP panel, it's
> > > > > better to put the eDP output on pipe C, since then pipes A&B will have
> > > > > full 4-lane fdi links to the pch ports (instead of otherwise only 2
> > > > > lanes each on links B&C)
> > > > > - similarly when we have a 3 pipe configuration with all encoders on
> > > > > the pch, we need to move the mode with the highest dotclock to pipe A
> > > > > (since that's the only one which will have 4 lanes, pipe B&C will only
> > > > > have 2 each).
> > > > > - afaik these kind of asymmetric constraints won't disappear anytime
> > > > > soon, haswell definitely still has some.
> > > > 
> > > > Yeah that's a good point... adding a virtual crtc layer would solve
> > > > this and let us preserve the existing ABI.
> > > 
> > > How would the state handling work? I mean if drm_crtc X currently has
> > > some state, drm_crtc Y has some other state, and then we do a modeset
> > > which would require swapping the roles of the crtcs, what would happen
> > > to the bits of state that we didn't specify?
> > > 
> > > If we'd do the remapping below the drm crtc layer, the state would
> > > always be tied to the drm crtc. But that would definitely require
> > > mostly uniform hardware "crtcs" so that the capabilities of the
> > > drm_crtcs wouldn't keep changing whenever the remap happens.
> > > 
> > > Well, I suppose we could tie the state to the virtual crtc instead,
> > > and doing an operation on a real drm_crtc would also change the
> > > state of the currently bound virtual crtc. And then changing the
> > > virtual<->real mapping would just copy the state over from the virtual
> > > crtc to the real drm_crtc.
> > > 
> > > And if we do it for crtcs, then we'd need to do it for planes as well,
> > > because the plane<->crtc mapping can be fixed or otherwise limited
> > > in some fashion.
> > > 
> > > Either way it sounds rather messy to me.
> > > 
> > > Another option would be just leave it up to userspace to make the
> > > correct choice between crtcs and planes. But then user space needs
> > > to be equipped with more hardware specific knowledge, so it's not
> > > a very appealing idea either.
> > 
> > Yeah it gets ugly one way or another.  From a userspace perspective,
> > keeping the ugliness in the kernel is nice, and if we have to do it
> > somewhere I guess I'd prefer that.
> 
> My tentative Grand Plan (tm) for the atomic modeset implementation of such
> things is to pimp the new struct intel_crtc_config to contain all the
> configuration state (so with Rob's atomic modeset proposal that would also
> embed the drm_crtc_state struct). It would also contain all the derived
> state like pll settings, fdi lanes, ...
> 
> Now the improve >mode_adjust stage, now called ->compute_config allocates
> such a struct for each crtc, does some prep, calls down into
> encoder->compute_config callbacks, then applies any fixups and screaming
> required to come up with a working global config. All rather hazy, I know
> ;-)
> 
> But e.g. for the above case of trying to squeeze the fdi links into the
> available sets of fdi lanes I guess we could first compute the upper bound
> for the fdi link requirements (the current wip stuff already pre-computes
> the pipe_bpp from the fb->depth). Then check whether that fits, do any
> readjustments (I already have a has_pch_encoder attribute, maybe at the
> wrong spot still, but we should be able to know which outputs need fdi
> links). If there's no way to fit it, reassign pipes a bit or try
> dithering. Once that works, call into encoders ...
> 
> Or maybe we could do a loop, since the encoders also limit the pipe_bpp.
> So first pipe_bpp from the fb->depth, then check for output properties
> (6bpc dithering on lvds, or a puny dp link), then check whether it fits
> into fdi. If not, dither more or reassign, then re-run the encoder config
> computations. If it still has too high bw requirementsmuch, give up.
> 
> In any case, and disregarding the above ramblings, I plan to make the
> intel_crtc_config thing free-standing for the ->compute_config stage, so
> we could easily add a preferred_crtc pointer to it since it's not tied to
> a specific crtc at that point. The problem now is that the
> connector->encoder->crtc links are embedded into the connectors and
> encoders, so they are not free-standing. But if we want to support atomic
> modeset on all properties (which I think we should), we need to fix that
> anyway ...

I'm not sure what the placement of the encoder and crtc pointers
has to do with atomic modeset.

Now, all of what you describe above is about the internals, and
seems perfectly reasonable. It sounds like the same idea had
when I started plaing around with atomic modeset. That is pulling
the state out of the various structures into some kind of state
object that can be manipulated w/o disturbing the rest of the
system. But I gave up on the idea due to the sheer scope of the
work, and I wanted to make something that works sooner rather
than later. My current code just goes around and shovels the
new state into the object structs themselves, relying mostly
on the save/restore code to reset the various bits of state to
the original values when things fail.

But anyway, the user visible state handling is still going to
be a problem with them virtual crtcs. We need to come up with
a plan for that if that's really the route we want to take.

-- 
Ville Syrjälä
Intel OTC

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH 46/51] drm/i915: Add support for atomic modesetting completion events
  2012-11-01 22:39           ` Daniel Vetter
  2012-11-02  9:10             ` Ville Syrjälä
@ 2012-11-07 20:29             ` Rob Clark
  2012-11-09 21:20               ` Daniel Vetter
  1 sibling, 1 reply; 61+ messages in thread
From: Rob Clark @ 2012-11-07 20:29 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: dri-devel

On Thu, Nov 1, 2012 at 5:39 PM, Daniel Vetter <daniel@ffwll.ch> wrote:
> On Thu, Nov 01, 2012 at 10:12:21AM -0700, Jesse Barnes wrote:
>> On Thu, 1 Nov 2012 19:07:02 +0200
>> Ville Syrjälä <ville.syrjala@linux.intel.com> wrote:
>>
>> > On Thu, Nov 01, 2012 at 07:39:12AM -0700, Jesse Barnes wrote:
>> > > On Thu, 1 Nov 2012 12:12:35 +0100
>> > > Daniel Vetter <daniel@ffwll.ch> wrote:
>> > >
>> > > > On Thu, Oct 25, 2012 at 8:05 PM,  <ville.syrjala@linux.intel.com> wrote:
>> > > > > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>> > > > >
>> > > > > Send completion events when the atomic modesetting operations has
>> > > > > finished succesfully.
>> > > > >
>> > > > > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
>> > > >
>> > > > I have to admit I'm not on top of the latest ioctl/interface
>> > > > discussion, but one new requirement for the modeset (not the pageflip
>> > > > part) of the all this atomic stuff I've discovered is that the kernel
>> > > > needs to be able to select the crtcs for each output completely
>> > > > unrestricted. I think userspace should simply pass in abstract crtc
>> > > > ids (e.g. 0, 1, 2, ...) and the kernel then passes back the actual
>> > > > crtcs it has selected.
>> > > >
>> > > > We can't do that remapping internally because the crtc abstraction is leaky:
>> > > > - wait_for_vblank requires the pipe id, which could then change on every modeset
>> > > > - similarly userspace doing MI_WAIT for scanlines needs to know the
>> > > > actual hw pipe in use by a crtc.
>> > > > And current userspace presumes that the mapping between crtc->pipe
>> > > > doesn't change.

I don't know if it is possible, but it would be nice to try to clean
up crtc<->pipe stuff..  userspace, at least modetest, assumes crtc ==
crtc_list[pipe].  But I haven't noticed yet anywhere that this
relationship is documented.  And if you are thinking about doing what
I think you are thinking about doing, then this assumption would no
longer hold for i915.

How frequently do you emit waits for scanline?  Places where the pipe
# ends up in cmdstream, would it be too crazy to handle that like a
reloc where the kernel goes and fixes up the actual value in the
cmdstream as it does it's GEM reloc pass?  If you did this then you
could virtualize pipe as well as crtc.

>> > > > An example why the kernel needs to pick the crtc for userspace:
>> > > > - on ivb only pipe A has a 7x5 panel fitter, so usually you want to
>> > > > put the panel on the first crtc
>> > > > - but if you run in a 3 pipe configuration and have an eDP panel, it's
>> > > > better to put the eDP output on pipe C, since then pipes A&B will have
>> > > > full 4-lane fdi links to the pch ports (instead of otherwise only 2
>> > > > lanes each on links B&C)
>> > > > - similarly when we have a 3 pipe configuration with all encoders on
>> > > > the pch, we need to move the mode with the highest dotclock to pipe A
>> > > > (since that's the only one which will have 4 lanes, pipe B&C will only
>> > > > have 2 each).
>> > > > - afaik these kind of asymmetric constraints won't disappear anytime
>> > > > soon, haswell definitely still has some.
>> > >
>> > > Yeah that's a good point... adding a virtual crtc layer would solve
>> > > this and let us preserve the existing ABI.
>> >
>> > How would the state handling work? I mean if drm_crtc X currently has
>> > some state, drm_crtc Y has some other state, and then we do a modeset
>> > which would require swapping the roles of the crtcs, what would happen
>> > to the bits of state that we didn't specify?
>> >
>> > If we'd do the remapping below the drm crtc layer, the state would
>> > always be tied to the drm crtc. But that would definitely require
>> > mostly uniform hardware "crtcs" so that the capabilities of the
>> > drm_crtcs wouldn't keep changing whenever the remap happens.
>> >
>> > Well, I suppose we could tie the state to the virtual crtc instead,
>> > and doing an operation on a real drm_crtc would also change the
>> > state of the currently bound virtual crtc. And then changing the
>> > virtual<->real mapping would just copy the state over from the virtual
>> > crtc to the real drm_crtc.
>> >
>> > And if we do it for crtcs, then we'd need to do it for planes as well,
>> > because the plane<->crtc mapping can be fixed or otherwise limited
>> > in some fashion.
>> >
>> > Either way it sounds rather messy to me.
>> >
>> > Another option would be just leave it up to userspace to make the
>> > correct choice between crtcs and planes. But then user space needs
>> > to be equipped with more hardware specific knowledge, so it's not
>> > a very appealing idea either.
>>
>> Yeah it gets ugly one way or another.  From a userspace perspective,
>> keeping the ugliness in the kernel is nice, and if we have to do it
>> somewhere I guess I'd prefer that.
>
> My tentative Grand Plan (tm) for the atomic modeset implementation of such
> things is to pimp the new struct intel_crtc_config to contain all the
> configuration state (so with Rob's atomic modeset proposal that would also
> embed the drm_crtc_state struct). It would also contain all the derived
> state like pll settings, fdi lanes, ...
>
> Now the improve >mode_adjust stage, now called ->compute_config allocates
> such a struct for each crtc, does some prep, calls down into
> encoder->compute_config callbacks, then applies any fixups and screaming
> required to come up with a working global config. All rather hazy, I know
> ;-)
>
> But e.g. for the above case of trying to squeeze the fdi links into the
> available sets of fdi lanes I guess we could first compute the upper bound
> for the fdi link requirements (the current wip stuff already pre-computes
> the pipe_bpp from the fb->depth). Then check whether that fits, do any
> readjustments (I already have a has_pch_encoder attribute, maybe at the
> wrong spot still, but we should be able to know which outputs need fdi
> links). If there's no way to fit it, reassign pipes a bit or try
> dithering. Once that works, call into encoders ...
>
> Or maybe we could do a loop, since the encoders also limit the pipe_bpp.
> So first pipe_bpp from the fb->depth, then check for output properties
> (6bpc dithering on lvds, or a puny dp link), then check whether it fits
> into fdi. If not, dither more or reassign, then re-run the encoder config
> computations. If it still has too high bw requirementsmuch, give up.
>
> In any case, and disregarding the above ramblings, I plan to make the
> intel_crtc_config thing free-standing for the ->compute_config stage, so
> we could easily add a preferred_crtc pointer to it since it's not tied to
> a specific crtc at that point. The problem now is that the
> connector->encoder->crtc links are embedded into the connectors and
> encoders, so they are not free-standing. But if we want to support atomic
> modeset on all properties (which I think we should), we need to fix that
> anyway ...

I think for full atomic modeset, then the drm_*_state structs end up
having the link pointers, ie 'struct drm_connector_state' has the ptr
to 'struct drm_encoder', and so on..

BR,
-R

>
>> However, we can't always hide hw details like that in the kernel
>> through generic interfaces (e.g. for sprites and all their
>> restrictions) so userspace will have to have some knowledge one way or
>> another, and maybe it's not that bad to push some of the other
>> limitation knowledge into our userspace code.
>
> I disagree, there's no sane way that userspace can figure out that the 3
> pipe config it wants would work, but only if it moves the eDP output to
> some other pipe. So if our aim is to support that (I know, we have more
> pressing and less lofty things on the table), the interface should allow
> it.
>
> Cheers, Daniel
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> +41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH 46/51] drm/i915: Add support for atomic modesetting completion events
  2012-11-07 20:29             ` Rob Clark
@ 2012-11-09 21:20               ` Daniel Vetter
  2012-11-09 21:25                 ` Rob Clark
  0 siblings, 1 reply; 61+ messages in thread
From: Daniel Vetter @ 2012-11-09 21:20 UTC (permalink / raw)
  To: Rob Clark; +Cc: dri-devel

On Wed, Nov 07, 2012 at 02:29:45PM -0600, Rob Clark wrote:
> On Thu, Nov 1, 2012 at 5:39 PM, Daniel Vetter <daniel@ffwll.ch> wrote:
> > On Thu, Nov 01, 2012 at 10:12:21AM -0700, Jesse Barnes wrote:
> >> On Thu, 1 Nov 2012 19:07:02 +0200
> >> Ville Syrjälä <ville.syrjala@linux.intel.com> wrote:
> >>
> >> > On Thu, Nov 01, 2012 at 07:39:12AM -0700, Jesse Barnes wrote:
> >> > > On Thu, 1 Nov 2012 12:12:35 +0100
> >> > > Daniel Vetter <daniel@ffwll.ch> wrote:
> >> > >
> >> > > > On Thu, Oct 25, 2012 at 8:05 PM,  <ville.syrjala@linux.intel.com> wrote:
> >> > > > > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> >> > > > >
> >> > > > > Send completion events when the atomic modesetting operations has
> >> > > > > finished succesfully.
> >> > > > >
> >> > > > > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> >> > > >
> >> > > > I have to admit I'm not on top of the latest ioctl/interface
> >> > > > discussion, but one new requirement for the modeset (not the pageflip
> >> > > > part) of the all this atomic stuff I've discovered is that the kernel
> >> > > > needs to be able to select the crtcs for each output completely
> >> > > > unrestricted. I think userspace should simply pass in abstract crtc
> >> > > > ids (e.g. 0, 1, 2, ...) and the kernel then passes back the actual
> >> > > > crtcs it has selected.
> >> > > >
> >> > > > We can't do that remapping internally because the crtc abstraction is leaky:
> >> > > > - wait_for_vblank requires the pipe id, which could then change on every modeset
> >> > > > - similarly userspace doing MI_WAIT for scanlines needs to know the
> >> > > > actual hw pipe in use by a crtc.
> >> > > > And current userspace presumes that the mapping between crtc->pipe
> >> > > > doesn't change.
> 
> I don't know if it is possible, but it would be nice to try to clean
> up crtc<->pipe stuff..  userspace, at least modetest, assumes crtc ==
> crtc_list[pipe].  But I haven't noticed yet anywhere that this
> relationship is documented.  And if you are thinking about doing what
> I think you are thinking about doing, then this assumption would no
> longer hold for i915.

This relationship does already no longer hold on i915 - on gen3 at least
we sometimes switch the crtc->pipe assignement (to make fbc more useful),
which means even with todays code userspace cannot assume (when running on
i915), that the vblank pipe satisfies crtc == crtc_list[pipe].

> How frequently do you emit waits for scanline?  Places where the pipe
> # ends up in cmdstream, would it be too crazy to handle that like a
> reloc where the kernel goes and fixes up the actual value in the
> cmdstream as it does it's GEM reloc pass?  If you did this then you
> could virtualize pipe as well as crtc.

Every dri2 copyregion or Xv upload to the frontbuffer on pre-gen6 will use
it. And we need old userspace to keep on working - presumably the fb layer
will switch to using the new atomic modeset stuff (if available) to figure
out an optimal config, so this is relevant.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH 46/51] drm/i915: Add support for atomic modesetting completion events
  2012-11-09 21:20               ` Daniel Vetter
@ 2012-11-09 21:25                 ` Rob Clark
  0 siblings, 0 replies; 61+ messages in thread
From: Rob Clark @ 2012-11-09 21:25 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: dri-devel

On Fri, Nov 9, 2012 at 3:20 PM, Daniel Vetter <daniel@ffwll.ch> wrote:
> On Wed, Nov 07, 2012 at 02:29:45PM -0600, Rob Clark wrote:
>> On Thu, Nov 1, 2012 at 5:39 PM, Daniel Vetter <daniel@ffwll.ch> wrote:
>> > On Thu, Nov 01, 2012 at 10:12:21AM -0700, Jesse Barnes wrote:
>> >> On Thu, 1 Nov 2012 19:07:02 +0200
>> >> Ville Syrjälä <ville.syrjala@linux.intel.com> wrote:
>> >>
>> >> > On Thu, Nov 01, 2012 at 07:39:12AM -0700, Jesse Barnes wrote:
>> >> > > On Thu, 1 Nov 2012 12:12:35 +0100
>> >> > > Daniel Vetter <daniel@ffwll.ch> wrote:
>> >> > >
>> >> > > > On Thu, Oct 25, 2012 at 8:05 PM,  <ville.syrjala@linux.intel.com> wrote:
>> >> > > > > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>> >> > > > >
>> >> > > > > Send completion events when the atomic modesetting operations has
>> >> > > > > finished succesfully.
>> >> > > > >
>> >> > > > > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
>> >> > > >
>> >> > > > I have to admit I'm not on top of the latest ioctl/interface
>> >> > > > discussion, but one new requirement for the modeset (not the pageflip
>> >> > > > part) of the all this atomic stuff I've discovered is that the kernel
>> >> > > > needs to be able to select the crtcs for each output completely
>> >> > > > unrestricted. I think userspace should simply pass in abstract crtc
>> >> > > > ids (e.g. 0, 1, 2, ...) and the kernel then passes back the actual
>> >> > > > crtcs it has selected.
>> >> > > >
>> >> > > > We can't do that remapping internally because the crtc abstraction is leaky:
>> >> > > > - wait_for_vblank requires the pipe id, which could then change on every modeset
>> >> > > > - similarly userspace doing MI_WAIT for scanlines needs to know the
>> >> > > > actual hw pipe in use by a crtc.
>> >> > > > And current userspace presumes that the mapping between crtc->pipe
>> >> > > > doesn't change.
>>
>> I don't know if it is possible, but it would be nice to try to clean
>> up crtc<->pipe stuff..  userspace, at least modetest, assumes crtc ==
>> crtc_list[pipe].  But I haven't noticed yet anywhere that this
>> relationship is documented.  And if you are thinking about doing what
>> I think you are thinking about doing, then this assumption would no
>> longer hold for i915.
>
> This relationship does already no longer hold on i915 - on gen3 at least
> we sometimes switch the crtc->pipe assignement (to make fbc more useful),
> which means even with todays code userspace cannot assume (when running on
> i915), that the vblank pipe satisfies crtc == crtc_list[pipe].

hmm, how does this not break weston compositor-drm (and modetest w/
vsync'd flipping.. although I suppose that is a less important
use-case)

>> How frequently do you emit waits for scanline?  Places where the pipe
>> # ends up in cmdstream, would it be too crazy to handle that like a
>> reloc where the kernel goes and fixes up the actual value in the
>> cmdstream as it does it's GEM reloc pass?  If you did this then you
>> could virtualize pipe as well as crtc.
>
> Every dri2 copyregion or Xv upload to the frontbuffer on pre-gen6 will use
> it. And we need old userspace to keep on working - presumably the fb layer
> will switch to using the new atomic modeset stuff (if available) to figure
> out an optimal config, so this is relevant.

yeah, not quite sure how the backwards-compat should work.. you'd have
to somehow only dynamically reassign crtcs if you could tell that
userspace is new enough to cope..

BR,
-R

> -Daniel
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> +41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 61+ messages in thread

end of thread, other threads:[~2012-11-09 21:25 UTC | newest]

Thread overview: 61+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-10-25 18:05 [PATCH 00/51] Atomic mode setting and page flip ville.syrjala
2012-10-25 18:05 ` [PATCH 01/51] drm: Be more paranoid with integer overflows ville.syrjala
2012-10-25 18:05 ` [PATCH 02/51] drm: Constify some function arguments ville.syrjala
2012-10-25 18:05 ` [PATCH 03/51] drm: Ignore blob propertys in drm_property_change_is_valid() ville.syrjala
2012-10-25 18:05 ` [PATCH 04/51] drm: Add struct drm_region and assorted utility functions ville.syrjala
2012-10-25 18:05 ` [PATCH 05/51] drm: Add drm_calc_{hscale, vscale}() " ville.syrjala
2012-10-25 18:05 ` [PATCH 06/51] drm: Keep a copy of last plane coordinates ville.syrjala
2012-10-25 18:05 ` [PATCH 07/51] drm: Add restore_fbdev_mode() hook to drm_fb_helper ville.syrjala
2012-10-25 18:05 ` [PATCH 08/51] drm: Export drm_property_create_blob() and drm_property_destroy_blob() ville.syrjala
2012-10-25 18:05 ` [PATCH 09/51] drm: Allow signed values for range properties ville.syrjala
2012-10-25 18:05 ` [PATCH 10/51] drm: Allow drm_mode_object_find() to look up an object of any type ville.syrjala
2012-10-25 18:05 ` [PATCH 11/51] drm: Export drm_encoder_crtc_ok ville.syrjala
2012-10-25 18:05 ` [PATCH 12/51] drm: Export drm_crtc_prepare_encoders() ville.syrjala
2012-10-25 18:05 ` [PATCH 13/51] drm: Refactor object property check code ville.syrjala
2012-10-25 18:05 ` [PATCH 14/51] drm: Export mode<->umode conversion functions ville.syrjala
2012-10-25 18:05 ` [PATCH 15/51] drm: Make blobs resizeable ville.syrjala
2012-10-25 18:05 ` [PATCH 16/51] drm: Add drm_flip helper ville.syrjala
2012-10-25 18:05 ` [PATCH 17/51] drm: Add mode_blob and connector_ids_blob to drm_crtc ville.syrjala
2012-10-25 18:05 ` [PATCH 18/51] drm: Add the atomic modeset ioctl ville.syrjala
2012-10-25 18:05 ` [PATCH 19/51] drm/i915: Fix display pixel format handling ville.syrjala
2012-10-25 18:05 ` [PATCH 20/51] drm/i915: Add SURFLIVE register definitions ville.syrjala
2012-10-25 18:05 ` [PATCH 21/51] drm/i915: Implement execbuffer wait for all planes ville.syrjala
2012-10-25 18:05 ` [PATCH 22/51] drm/i915: Check framebuffer stride more thoroughly ville.syrjala
2012-10-25 18:05 ` [PATCH 23/51] drm/i915: Check the framebuffer offset ville.syrjala
2012-10-25 18:05 ` [PATCH 24/51] drm/i915: Handle framebuffer offsets[] ville.syrjala
2012-10-25 18:05 ` [PATCH 25/51] drm/i915: Implement proper clipping for video sprites ville.syrjala
2012-10-25 18:05 ` [PATCH 26/51] drm/i915: pixel_size == cpp ville.syrjala
2012-10-25 18:05 ` [PATCH 27/51] drm/i915: Bad pixel formats can't reach the sprite code ville.syrjala
2012-10-25 18:05 ` [PATCH 28/51] drm/i915: Implement restore_fbdev_mode hook ville.syrjala
2012-10-25 18:05 ` [PATCH 29/51] drm/i915: Split clipping and checking from update_plane hook ville.syrjala
2012-10-25 18:05 ` [PATCH 30/51] drm/i915: Factor out i9xx_compute_clocks() like ironlake_compute_clocks() ville.syrjala
2012-10-25 18:05 ` [PATCH 31/51] drm/i915: Consitify adjusted_mode parameter ville.syrjala
2012-10-25 18:05 ` [PATCH 32/51] drm/i915: Add intel_check_clock() ville.syrjala
2012-10-25 18:05 ` [PATCH 33/51] drm/i915: store cursor_handle in struct intel_crtc ville.syrjala
2012-10-25 18:05 ` [PATCH 34/51] drm/i915: split cursor setting code into prepare/commit/unref parts ville.syrjala
2012-10-25 18:05 ` [PATCH 35/51] drm/i915: unstatic cursor functions for use with atomic modesetting ville.syrjala
2012-10-25 18:05 ` [PATCH 36/51] drm/i915: Unstatic intel_finish_fb() ville.syrjala
2012-10-25 18:05 ` [PATCH 37/51] drm/i915: Pull intel_pipe_set_base() out of the crtc_mode_set() functions ville.syrjala
2012-10-25 18:05 ` [PATCH 38/51] drm/i915: Unstatic intel_crtc_update_sarea() ville.syrjala
2012-10-25 18:05 ` [PATCH 39/51] drm/i915: Introduce intel_crtc_update_sarea_pos() ville.syrjala
2012-10-25 18:05 ` [PATCH 40/51] drm/i915: Constify mode argument to intel_modeset_adjusted_mode() ville.syrjala
2012-10-25 18:05 ` [PATCH 41/51] drm/i915: Unstatic intel_crtc_mode_fixup() ville.syrjala
2012-10-25 18:05 ` [PATCH 42/51] drm/i915: Introduce intel_plane_regs ville.syrjala
2012-10-25 18:05 ` [PATCH 43/51] drm/i915: Split primary plane update_plane() into calc+commit phases ville.syrjala
2012-10-25 18:05 ` [PATCH 44/51] drm/i915: Split sprite " ville.syrjala
2012-10-25 18:05 ` [PATCH 45/51] drm/i915: Implement atomic modesetting ville.syrjala
2012-10-25 18:05 ` [PATCH 46/51] drm/i915: Add support for atomic modesetting completion events ville.syrjala
2012-11-01 11:12   ` Daniel Vetter
2012-11-01 14:39     ` Jesse Barnes
2012-11-01 17:07       ` Ville Syrjälä
2012-11-01 17:12         ` Jesse Barnes
2012-11-01 22:39           ` Daniel Vetter
2012-11-02  9:10             ` Ville Syrjälä
2012-11-07 20:29             ` Rob Clark
2012-11-09 21:20               ` Daniel Vetter
2012-11-09 21:25                 ` Rob Clark
2012-10-25 18:05 ` [PATCH 47/51] drm/i915: Add atomic page flip support ville.syrjala
2012-10-25 18:05 ` [PATCH 48/51] drm/i915: Unstatic intel_enable_primary() and intel_disable_primary() ville.syrjala
2012-10-25 18:05 ` [PATCH 49/51] drm/i915: Respect primary_disabled in crtc_enable() ville.syrjala
2012-10-25 18:05 ` [PATCH 50/51] drm/i915: Enable/disable primary plane in calc_plane() ville.syrjala
2012-10-25 18:05 ` [PATCH 51/51] drm/i915: Add primary plane disable logic to atomic mode setting code ville.syrjala

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.