[PATCH] drm/i915: add SNB video sprite support

Jesse Barnes jbarnes at virtuousgeek.org
Tue Oct 25 04:22:06 PDT 2011


The video sprites support various video surface formats natively and can
handle scaling as well.  So add support for them using the new DRM core
overlay support functions.

v2: collapse patches and fix plane disable vs unpin ordering bug

Signed-off-by: Jesse Barnes <jbarnes at virtuousgeek.org>
---
 drivers/gpu/drm/i915/Makefile         |    1 +
 drivers/gpu/drm/i915/i915_reg.h       |  116 ++++++++++
 drivers/gpu/drm/i915/intel_display.c  |   26 ++-
 drivers/gpu/drm/i915/intel_drv.h      |   14 ++
 drivers/gpu/drm/i915/intel_fb.c       |    6 +
 drivers/gpu/drm/i915/intel_overlay2.c |  393 +++++++++++++++++++++++++++++++++
 6 files changed, 547 insertions(+), 9 deletions(-)
 create mode 100644 drivers/gpu/drm/i915/intel_overlay2.c

diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 0ae6a7c..6193471 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -28,6 +28,7 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \
 	  intel_dvo.o \
 	  intel_ringbuffer.o \
 	  intel_overlay.o \
+	  intel_overlay2.o \
 	  intel_opregion.o \
 	  dvo_ch7xxx.o \
 	  dvo_ch7017.o \
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 5a09416..8cbda0b 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -2666,6 +2666,122 @@
 #define _DSPBSURF		0x7119C
 #define _DSPBTILEOFF		0x711A4
 
+/* Sprite A control */
+#define _DVSACNTR		0x72180
+#define   DVS_ENABLE		(1<<31)
+#define   DVS_GAMMA_ENABLE	(1<<30)
+#define   DVS_PIXFORMAT_MASK	(3<<25)
+#define   DVS_FORMAT_YUV422	(0<<25)
+#define   DVS_FORMAT_RGBX101010	(1<<25)
+#define   DVS_FORMAT_RGBX888	(2<<25)
+#define   DVS_FORMAT_RGBX161616	(3<<25)
+#define   DVS_SOURCE_KEY	(1<<22)
+#define   DVS_RGB_ORDER_RGBX	(1<<20)
+#define   DVS_YUV_BYTE_ORDER_MASK (3<<16)
+#define   DVS_YUV_ORDER_YUYV	(0<<16)
+#define   DVS_YUV_ORDER_UYVY	(1<<16)
+#define   DVS_YUV_ORDER_YVYU	(2<<16)
+#define   DVS_YUV_ORDER_VYUY	(3<<16)
+#define   DVS_DEST_KEY		(1<<2)
+#define   DVS_TRICKLE_FEED_DISABLE (1<<14)
+#define   DVS_TILED		(1<<10)
+#define _DVSASTRIDE		0x72188
+#define _DVSAPOS		0x7218c
+#define _DVSASIZE		0x72190
+#define _DVSAKEYVAL		0x72194
+#define _DVSAKEYMSK		0x72198
+#define _DVSASURF		0x7219c
+#define _DVSAKEYMAXVAL		0x721a0
+#define _DVSATILEOFF		0x721a4
+#define _DVSASURFLIVE		0x721ac
+#define _DVSASCALE		0x72204
+#define   DVS_SCALE_ENABLE	(1<<31)
+#define   DVS_FILTER_MASK	(3<<29)
+#define   DVS_FILTER_MEDIUM	(0<<29)
+#define   DVS_FILTER_ENHANCING	(1<<29)
+#define   DVS_FILTER_SOFTENING	(2<<29)
+#define _DVSAGAMC		0x72300
+
+#define _DVSBCNTR		0x73180
+#define _DVSBSTRIDE		0x73188
+#define _DVSBPOS		0x7318c
+#define _DVSBSIZE		0x73190
+#define _DVSBKEYVAL		0x73194
+#define _DVSBKEYMSK		0x73198
+#define _DVSBSURF		0x7319c
+#define _DVSBKEYMAXVAL		0x731a0
+#define _DVSBTILEOFF		0x731a4
+#define _DVSBSURFLIVE		0x731ac
+#define _DVSBSCALE		0x73204
+#define _DVSBGAMC		0x73300
+
+#define DVSCNTR(pipe) _PIPE(pipe, _DVSACNTR, _DVSBCNTR)
+#define DVSSTRIDE(pipe) _PIPE(pipe, _DVSASTRIDE, _DVSBSTRIDE)
+#define DVSPOS(pipe) _PIPE(pipe, _DVSAPOS, _DVSBPOS)
+#define DVSSURF(pipe) _PIPE(pipe, _DVSASURF, _DVSBSURF)
+#define DVSSIZE(pipe) _PIPE(pipe, _DVSASIZE, _DVSBSIZE)
+#define DVSSCALE(pipe) _PIPE(pipe, _DVSASCALE, _DVSBSCALE)
+#define DVSTILEOFF(pipe) _PIPE(pipe, _DVSATILEOFF, _DVSBTILEOFF)
+
+#define _SPRA_CTL		0x70280
+#define   SPRITE_ENABLE			(1<<31)
+#define   SPRITE_GAMMA_ENABLE		(1<<30)
+#define   SPRITE_PIXFORMAT_MASK		(7<<25)
+#define   SPRITE_FORMAT_YUV422		(0<<25)
+#define   SPRITE_FORMAT_RGBX101010	(1<<25)
+#define   SPRITE_FORMAT_RGBX888		(2<<25)
+#define   SPRITE_FORMAT_RGBX161616	(3<<25)
+#define   SPRITE_FORMAT_YUV444		(4<<25)
+#define   SPRITE_FORMAT_XBGR101010	(5<<25)
+#define   SPRITE_CSC_ENABLE		(1<<24)
+#define   SPRITE_SOURCE_KEY		(1<<22)
+#define   SPRITE_RGB_ORDER_RGBX		(1<<20) /* only for 888 and 161616 */
+#define   SPRITE_YUV_TO_RGB_CSC_DISABLE	(1<<19)
+#define   SPRITE_YUV_CSC_FORMAT_BT709	(1<<18) /* 0 is BT601 */
+#define   SPRITE_YUV_BYTE_ORDER_MASK	(3<<16)
+#define   SPRITE_YUV_ORDER_YUYV		(0<<16)
+#define   SPRITE_YUV_ORDER_UYVY		(1<<16)
+#define   SPRITE_YUV_ORDER_YVYU		(2<<16)
+#define   SPRITE_YUV_ORDER_VYUY		(3<<16)
+#define   SPRITE_TRICKLE_FEED_DISABLE	(1<<14)
+#define   SPRITE_INT_GAMMA_ENABLE	(1<<13)
+#define   SPRITE_TILED			(1<<10)
+#define   SPRITE_DEST_KEY		(1<<2)
+#define _SPRA_STRIDE		0x70288
+#define _SPRA_POS		0x7028c
+#define _SPRA_SIZE		0x70290
+#define _SPRA_KEYVAL		0x70294
+#define _SPRA_KEYMSK		0x70298
+#define _SPRA_SURF		0x7029c
+#define _SPRA_KEYMAX		0x702a0
+#define _SPRA_TILEOFF		0x702a4
+#define _SPRA_SCALE		0x70304
+#define _SPRA_GAMC		0x70400
+
+#define _SPRB_CTL		0x70280
+#define _SPRB_STRIDE		0x70288
+#define _SPRB_POS		0x7028c
+#define _SPRB_SIZE		0x70290
+#define _SPRB_KEYVAL		0x70294
+#define _SPRB_KEYMSK		0x70298
+#define _SPRB_SURF		0x7029c
+#define _SPRB_KEYMAX		0x702a0
+#define _SPRB_TILEOFF		0x702a4
+#define _SPRB_SCALE		0x70304
+#define _SPRB_GAMC		0x70400
+
+#define SPRCTL(pipe) _PIPE(pipe, _SPRA_CTL, _SPRB_CTL)
+#define SPRSTRIDE(pipe) _PIPE(pipe, _SPRA_STRIDE, _SPRB_STRIDE)
+#define SPRPOS(pipe) _PIPE(pipe, _SPRA_POS, _SPRB_POS)
+#define SPRSIZE(pipe) _PIPE(pipe, _SPRA_SIZE, _SPRB_SIZE)
+#define SPRKEYVAL(pipe) _PIPE(pipe, _SPRA_KEYVAL, _SPRB_KEYVAL)
+#define SPRKEYMSK(pipe) _PIPE(pipe, _SPRA_KEYMSK, _SPRB_KEYMSK)
+#define SPRSURF(pipe) _PIPE(pipe, _SPRA_SURF, _SPRB_SURF)
+#define SPRKEYMAX(pipe) _PIPE(pipe, _SPRA_KEYMAX, _SPRB_KEYMAX)
+#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)
+
 /* VBIOS regs */
 #define VGACNTRL		0x71400
 # define VGA_DISP_DISABLE			(1 << 31)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index e748338..cd7e04d 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -915,8 +915,8 @@ static void assert_panel_unlocked(struct drm_i915_private *dev_priv,
 	     pipe_name(pipe));
 }
 
-static void assert_pipe(struct drm_i915_private *dev_priv,
-			enum pipe pipe, bool state)
+void assert_pipe(struct drm_i915_private *dev_priv,
+		 enum pipe pipe, bool state)
 {
 	int reg;
 	u32 val;
@@ -929,8 +929,6 @@ static void assert_pipe(struct drm_i915_private *dev_priv,
 	     "pipe %c assertion failure (expected %s, current %s)\n",
 	     pipe_name(pipe), state_string(state), state_string(cur_state));
 }
-#define assert_pipe_enabled(d, p) assert_pipe(d, p, true)
-#define assert_pipe_disabled(d, p) assert_pipe(d, p, false)
 
 static void assert_plane_enabled(struct drm_i915_private *dev_priv,
 				 enum plane plane)
@@ -4439,7 +4437,8 @@ static void ironlake_update_wm(struct drm_device *dev)
 			    ILK_LP0_CURSOR_LATENCY,
 			    &plane_wm, &cursor_wm)) {
 		I915_WRITE(WM0_PIPEA_ILK,
-			   (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
+			   (plane_wm << WM0_PIPE_PLANE_SHIFT) |
+			   (plane_wm << WM0_PIPE_SPRITE_SHIFT) | cursor_wm);
 		DRM_DEBUG_KMS("FIFO watermarks For pipe A -"
 			      " plane %d, " "cursor: %d\n",
 			      plane_wm, cursor_wm);
@@ -4453,7 +4452,8 @@ static void ironlake_update_wm(struct drm_device *dev)
 			    ILK_LP0_CURSOR_LATENCY,
 			    &plane_wm, &cursor_wm)) {
 		I915_WRITE(WM0_PIPEB_ILK,
-			   (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
+			   (plane_wm << WM0_PIPE_PLANE_SHIFT) |
+			   (plane_wm << WM0_PIPE_SPRITE_SHIFT) | cursor_wm);
 		DRM_DEBUG_KMS("FIFO watermarks For pipe B -"
 			      " plane %d, cursor: %d\n",
 			      plane_wm, cursor_wm);
@@ -4521,7 +4521,8 @@ static void sandybridge_update_wm(struct drm_device *dev)
 			    &sandybridge_cursor_wm_info, latency,
 			    &plane_wm, &cursor_wm)) {
 		I915_WRITE(WM0_PIPEA_ILK,
-			   (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
+			   (plane_wm << WM0_PIPE_PLANE_SHIFT) |
+			   (plane_wm << WM0_PIPE_SPRITE_SHIFT) | cursor_wm);
 		DRM_DEBUG_KMS("FIFO watermarks For pipe A -"
 			      " plane %d, " "cursor: %d\n",
 			      plane_wm, cursor_wm);
@@ -4533,7 +4534,8 @@ static void sandybridge_update_wm(struct drm_device *dev)
 			    &sandybridge_cursor_wm_info, latency,
 			    &plane_wm, &cursor_wm)) {
 		I915_WRITE(WM0_PIPEB_ILK,
-			   (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
+			   (plane_wm << WM0_PIPE_PLANE_SHIFT) |
+			   (plane_wm << WM0_PIPE_SPRITE_SHIFT) | cursor_wm);
 		DRM_DEBUG_KMS("FIFO watermarks For pipe B -"
 			      " plane %d, cursor: %d\n",
 			      plane_wm, cursor_wm);
@@ -8692,7 +8694,7 @@ static void i915_disable_vga(struct drm_device *dev)
 void intel_modeset_init(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	int i;
+	int i, ret;
 
 	drm_mode_config_init(dev);
 
@@ -8722,6 +8724,12 @@ void intel_modeset_init(struct drm_device *dev)
 
 	for (i = 0; i < dev_priv->num_pipe; i++) {
 		intel_crtc_init(dev, i);
+		if (HAS_PCH_SPLIT(dev)) {
+			ret = intel_plane_init(dev, i);
+			if (ret)
+				DRM_ERROR("plane %d init failed: %d\n",
+					  i, ret);
+		}
 	}
 
 	/* Just disable it once at startup */
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 467fb4a..50b633b 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -176,10 +176,18 @@ struct intel_crtc {
 	bool use_pll_a;
 };
 
+struct intel_plane {
+	struct drm_plane base;
+	enum pipe pipe;
+	struct drm_i915_gem_object *obj;
+	u32 lut_r[1024], lut_g[1024], lut_b[1024];
+};
+
 #define to_intel_crtc(x) container_of(x, struct intel_crtc, base)
 #define to_intel_connector(x) container_of(x, struct intel_connector, base)
 #define to_intel_encoder(x) container_of(x, struct intel_encoder, base)
 #define to_intel_framebuffer(x) container_of(x, struct intel_framebuffer, base)
+#define to_intel_plane(x) container_of(x, struct intel_plane, base)
 
 #define DIP_HEADER_SIZE	5
 
@@ -289,6 +297,7 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
 extern bool intel_dpd_is_edp(struct drm_device *dev);
 extern void intel_edp_link_config(struct intel_encoder *, int *, int *);
 extern bool intel_encoder_is_pch_edp(struct drm_encoder *encoder);
+extern int intel_plane_init(struct drm_device *dev, enum pipe pipe);
 
 /* intel_panel.c */
 extern void intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
@@ -379,6 +388,11 @@ extern int intel_overlay_attrs(struct drm_device *dev, void *data,
 extern void intel_fb_output_poll_changed(struct drm_device *dev);
 extern void intel_fb_restore_mode(struct drm_device *dev);
 
+extern void assert_pipe(struct drm_i915_private *dev_priv, enum pipe pipe,
+			bool state);
+#define assert_pipe_enabled(d, p) assert_pipe(d, p, true)
+#define assert_pipe_disabled(d, p) assert_pipe(d, p, false)
+
 extern void intel_init_clock_gating(struct drm_device *dev);
 extern void intel_write_eld(struct drm_encoder *encoder,
 			    struct drm_display_mode *mode);
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c
index 11baa99..513a40c 100644
--- a/drivers/gpu/drm/i915/intel_fb.c
+++ b/drivers/gpu/drm/i915/intel_fb.c
@@ -270,8 +270,14 @@ void intel_fb_restore_mode(struct drm_device *dev)
 {
 	int ret;
 	drm_i915_private_t *dev_priv = dev->dev_private;
+	struct drm_mode_config *config = &dev->mode_config;
+	struct drm_plane *plane;
 
 	ret = drm_fb_helper_restore_fbdev_mode(&dev_priv->fbdev->helper);
 	if (ret)
 		DRM_DEBUG("failed to restore crtc mode\n");
+
+	/* 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);
 }
diff --git a/drivers/gpu/drm/i915/intel_overlay2.c b/drivers/gpu/drm/i915/intel_overlay2.c
new file mode 100644
index 0000000..61594b6
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_overlay2.c
@@ -0,0 +1,393 @@
+/*
+ * Copyright © 2011 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:
+ *   Jesse Barnes <jbarnes at virtuousgeek.org>
+ *
+ * New plane/sprite handling.
+ *
+ * The older chips had a separate interface for programming plane related
+ * registers; newer ones are much simpler and we can use the new DRM plane
+ * support.
+ */
+#include "drmP.h"
+#include "drm_crtc.h"
+#include "intel_drv.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+
+/*
+ * Note on refcounting:
+ * When the user creates an fb for the GEM object to be used for the plane,
+ * a ref is taken on the object.  However, if the application exits before
+ * disabling the plane, the DRM close handling will free all the fbs and
+ * unless we take a ref on the object, it will be destroyed before the
+ * plane disable hook is called, causing obvious trouble with our efforts
+ * to look up and unpin the object.  So we take a ref after we move the
+ * object to the display plane so it won't be destroyed until our disable
+ * hook is called and we drop our private reference.
+ */
+
+static int
+ivb_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 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, *old_obj;
+	int pipe = intel_plane->pipe;
+	unsigned long start, offset;
+	u32 sprctl;
+	u32 reg = SPRCTL(pipe);
+	int ret = 0;
+	int x = src_x >> 16, y = src_y >> 16;
+
+	assert_pipe_enabled(dev_priv, pipe);
+
+	intel_fb = to_intel_framebuffer(fb);
+	obj = intel_fb->obj;
+
+	old_obj = intel_plane->obj;
+
+	mutex_lock(&dev->struct_mutex);
+
+	sprctl = I915_READ(reg);
+
+	/* Mask out pixel format bits in case we change it */
+	sprctl &= ~(SPRITE_DEST_KEY | SPRITE_SOURCE_KEY);
+	sprctl &= ~SPRITE_PIXFORMAT_MASK;
+	sprctl &= ~SPRITE_RGB_ORDER_RGBX;
+	sprctl &= ~SPRITE_YUV_BYTE_ORDER_MASK;
+
+	switch (fb->pixel_format) {
+	case V4L2_PIX_FMT_BGR32:
+		sprctl |= SPRITE_FORMAT_RGBX888;
+		break;
+	case V4L2_PIX_FMT_RGB32:
+		sprctl |= SPRITE_FORMAT_RGBX888 | SPRITE_RGB_ORDER_RGBX;
+		break;
+	case V4L2_PIX_FMT_YUYV:
+		sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YUYV;
+		break;
+	case V4L2_PIX_FMT_YVYU:
+		sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YVYU;
+		break;
+	case V4L2_PIX_FMT_UYVY:
+		sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_UYVY;
+		break;
+	case V4L2_PIX_FMT_VYUY:
+		sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_VYUY;
+		break;
+	default:
+		ret = -EINVAL;
+		DRM_ERROR("bad pixel format\n");
+		goto out_unlock;
+	}
+
+	if (obj->tiling_mode != I915_TILING_X) {
+		DRM_ERROR("plane surfaces must be X tiled\n");
+		ret = -EINVAL;
+		goto out_unlock;
+	}
+
+	ret = intel_pin_and_fence_fb_obj(dev, obj, NULL);
+	if (ret)
+		goto out_unlock;
+
+	drm_gem_object_reference(&obj->base);
+
+	intel_plane->obj = obj;
+
+	sprctl |= SPRITE_TILED;
+
+	/* must disable */
+	sprctl |= SPRITE_TRICKLE_FEED_DISABLE;
+	sprctl |= SPRITE_ENABLE;
+
+	start = obj->gtt_offset;
+	offset = y * fb->pitch + x * (fb->bits_per_pixel / 8);
+
+	I915_WRITE(SPRSTRIDE(pipe), fb->pitch);
+	I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x);
+	I915_WRITE(SPRTILEOFF(pipe), (y << 16) | x);
+	I915_WRITE(SPRSIZE(pipe), (fb->height << 16) | fb->width);
+	I915_WRITE(SPRSCALE(pipe), 0);
+	I915_WRITE(reg, sprctl);
+	I915_WRITE(SPRSURF(pipe), start);
+	POSTING_READ(SPRSURF(pipe));
+
+	/* Adjust watermarks as needed */
+	I915_WRITE(WM1S_LP_ILK, 0x100);
+
+	/* Unpin old obj after new one is active to avoid ugliness */
+	if (old_obj) {
+		intel_wait_for_vblank(dev, to_intel_crtc(crtc)->pipe);
+		i915_gem_object_unpin(old_obj);
+	}
+
+out_unlock:
+	mutex_unlock(&dev->struct_mutex);
+
+	return ret;
+}
+
+static int
+snb_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 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, *old_obj;
+	int pipe = intel_plane->pipe;
+	unsigned long start, offset;
+	u32 dvscntr, dvsscale = 0;
+	u32 reg = DVSCNTR(pipe);
+	int ret = 0;
+	int x = src_x >> 16, y = src_y >> 16;
+	int active_w = crtc->mode.hdisplay, active_h = crtc->mode.vdisplay;
+
+	assert_pipe_enabled(dev_priv, pipe);
+
+	intel_fb = to_intel_framebuffer(fb);
+	obj = intel_fb->obj;
+
+	old_obj = intel_plane->obj;
+
+	if (crtc_x >= active_w || crtc_y >= active_h)
+		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)) > 16)
+		return -EINVAL;
+
+	/* Clamp the width & height into the visible area */
+	if (crtc_x + crtc_w > active_w)
+		crtc_w = active_w - crtc_x - 1;
+	if (crtc_y + crtc_h > active_h)
+		crtc_h = active_h - crtc_y - 1;
+
+	mutex_lock(&dev->struct_mutex);
+
+	dvscntr = I915_READ(reg);
+
+	/* Mask out pixel format bits in case we change it */
+	dvscntr &= ~(DVS_DEST_KEY | DVS_SOURCE_KEY);
+	dvscntr &= ~DVS_PIXFORMAT_MASK;
+	dvscntr &= ~DVS_RGB_ORDER_RGBX;
+	dvscntr &= ~DVS_YUV_BYTE_ORDER_MASK;
+
+	switch (fb->pixel_format) {
+	case V4L2_PIX_FMT_BGR32:
+		dvscntr |= DVS_FORMAT_RGBX888;
+		break;
+	case V4L2_PIX_FMT_RGB32:
+		dvscntr |= DVS_FORMAT_RGBX888 | DVS_RGB_ORDER_RGBX;
+		break;
+	case V4L2_PIX_FMT_YUYV:
+		dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YUYV;
+		break;
+	case V4L2_PIX_FMT_YVYU:
+		dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YVYU;
+		break;
+	case V4L2_PIX_FMT_UYVY:
+		dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_UYVY;
+		break;
+	case V4L2_PIX_FMT_VYUY:
+		dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_VYUY;
+		break;
+	default:
+		ret = -EINVAL;
+		DRM_ERROR("bad pixel format\n");
+		goto out_unlock;
+	}
+
+	if (obj->tiling_mode != I915_TILING_X) {
+		DRM_ERROR("plane surfaces must be X tiled\n");
+		ret = -EINVAL;
+		goto out_unlock;
+	}
+
+	ret = intel_pin_and_fence_fb_obj(dev, obj, NULL);
+	if (ret)
+		goto out_unlock;
+
+	drm_gem_object_reference(&obj->base);
+
+	intel_plane->obj = obj;
+
+	dvscntr |= DVS_TILED;
+
+	/* must disable */
+	dvscntr |= DVS_TRICKLE_FEED_DISABLE;
+	dvscntr |= DVS_ENABLE;
+
+	start = obj->gtt_offset;
+	offset = y * fb->pitch + x * (fb->bits_per_pixel / 8);
+
+	if (crtc_w != src_w || crtc_h != src_h)
+		dvsscale = DVS_SCALE_ENABLE | (src_h << 16) | src_w;
+
+	I915_WRITE(DVSSTRIDE(pipe), fb->pitch);
+	I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x);
+	I915_WRITE(DVSTILEOFF(pipe), (y << 16) | x);
+	I915_WRITE(DVSSIZE(pipe), (crtc_h << 16) | crtc_w);
+	I915_WRITE(DVSSCALE(pipe), dvsscale);
+	I915_WRITE(reg, dvscntr);
+	I915_WRITE(DVSSURF(pipe), start);
+	POSTING_READ(DVSSURF(pipe));
+
+	/* Unpin old obj after new one is active to avoid ugliness */
+	if (old_obj) {
+		intel_wait_for_vblank(dev, to_intel_crtc(crtc)->pipe);
+		i915_gem_object_unpin(old_obj);
+	}
+
+out_unlock:
+	mutex_unlock(&dev->struct_mutex);
+
+	return ret;
+}
+
+static int
+ivb_disable_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 ret = 0;
+
+	mutex_lock(&dev->struct_mutex);
+
+	if (!intel_plane->obj)
+		goto out_unlock;
+
+	ret = i915_gem_object_finish_gpu(intel_plane->obj);
+	if (ret)
+		goto out_unlock;
+
+	i915_gem_object_unpin(intel_plane->obj);
+
+	drm_gem_object_reference(&intel_plane->obj->base);
+
+out_unlock:
+	intel_plane->obj = NULL;
+
+	I915_WRITE(SPRCTL(pipe), I915_READ(SPRCTL(pipe)) & ~SPRITE_ENABLE);
+	I915_WRITE(SPRSURF(pipe), 0);
+	POSTING_READ(SPRSURF(pipe));
+
+	mutex_unlock(&dev->struct_mutex);
+
+	return ret;
+}
+
+static int
+snb_disable_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 ret = 0;
+
+	mutex_lock(&dev->struct_mutex);
+
+	if (!intel_plane->obj)
+		goto out_unlock;
+
+	ret = i915_gem_object_finish_gpu(intel_plane->obj);
+	if (ret)
+		goto out_unlock;
+
+	i915_gem_object_unpin(intel_plane->obj);
+
+	drm_gem_object_reference(&intel_plane->obj->base);
+
+out_unlock:
+	intel_plane->obj = NULL;
+
+	I915_WRITE(DVSCNTR(pipe), I915_READ(DVSCNTR(pipe)) & ~DVS_ENABLE);
+	I915_WRITE(DVSSURF(pipe), 0);
+	POSTING_READ(DVSSURF(pipe));
+
+	mutex_unlock(&dev->struct_mutex);
+
+	return ret;
+}
+
+static struct drm_plane_funcs intel_plane_funcs;
+
+static uint32_t snb_plane_formats[] = {
+	V4L2_PIX_FMT_BGR32,
+	V4L2_PIX_FMT_RGB32,
+	V4L2_PIX_FMT_YUYV,
+	V4L2_PIX_FMT_YVYU,
+	V4L2_PIX_FMT_UYVY,
+	V4L2_PIX_FMT_VYUY,
+};
+
+int
+intel_plane_init(struct drm_device *dev, enum pipe pipe)
+{
+	struct intel_plane *intel_plane;
+	unsigned long possible_crtcs;
+
+	if (!(IS_GEN6(dev) || IS_GEN7(dev))) {
+		DRM_ERROR("new plane code only for SNB+\n");
+		return -ENODEV;
+	}
+
+	intel_plane = kzalloc(sizeof(struct intel_plane), GFP_KERNEL);
+	if (!intel_plane)
+		return -ENOMEM;
+
+	if (IS_GEN6(dev)) {
+		intel_plane_funcs.update_plane = snb_update_plane;
+		intel_plane_funcs.disable_plane = snb_disable_plane;
+	} else if (IS_GEN7(dev)) {
+		intel_plane_funcs.update_plane = ivb_update_plane;
+		intel_plane_funcs.disable_plane = ivb_disable_plane;
+	}
+
+	intel_plane->pipe = pipe;
+	possible_crtcs = (1 << pipe);
+	drm_plane_init(dev, &intel_plane->base, possible_crtcs,
+		       &intel_plane_funcs, snb_plane_formats,
+		       ARRAY_SIZE(snb_plane_formats));
+
+	return 0;
+}
+
-- 
1.7.4.1




More information about the dri-devel mailing list