xref: /dflybsd-src/sys/dev/drm/i915/intel_sprite.c (revision af4b81b9fa0b40a0b482311a55a909d593a54aee)
1e3adcf8fSFrançois Tigeot /*
2e3adcf8fSFrançois Tigeot  * Copyright © 2011 Intel Corporation
3e3adcf8fSFrançois Tigeot  *
4e3adcf8fSFrançois Tigeot  * Permission is hereby granted, free of charge, to any person obtaining a
5e3adcf8fSFrançois Tigeot  * copy of this software and associated documentation files (the "Software"),
6e3adcf8fSFrançois Tigeot  * to deal in the Software without restriction, including without limitation
7e3adcf8fSFrançois Tigeot  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8e3adcf8fSFrançois Tigeot  * and/or sell copies of the Software, and to permit persons to whom the
9e3adcf8fSFrançois Tigeot  * Software is furnished to do so, subject to the following conditions:
10e3adcf8fSFrançois Tigeot  *
11e3adcf8fSFrançois Tigeot  * The above copyright notice and this permission notice (including the next
12e3adcf8fSFrançois Tigeot  * paragraph) shall be included in all copies or substantial portions of the
13e3adcf8fSFrançois Tigeot  * Software.
14e3adcf8fSFrançois Tigeot  *
15e3adcf8fSFrançois Tigeot  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16e3adcf8fSFrançois Tigeot  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17e3adcf8fSFrançois Tigeot  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18e3adcf8fSFrançois Tigeot  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19e3adcf8fSFrançois Tigeot  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20e3adcf8fSFrançois Tigeot  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21e3adcf8fSFrançois Tigeot  * SOFTWARE.
22e3adcf8fSFrançois Tigeot  *
23e3adcf8fSFrançois Tigeot  * Authors:
24e3adcf8fSFrançois Tigeot  *   Jesse Barnes <jbarnes@virtuousgeek.org>
25e3adcf8fSFrançois Tigeot  *
26e3adcf8fSFrançois Tigeot  * New plane/sprite handling.
27e3adcf8fSFrançois Tigeot  *
28e3adcf8fSFrançois Tigeot  * The older chips had a separate interface for programming plane related
29e3adcf8fSFrançois Tigeot  * registers; newer ones are much simpler and we can use the new DRM plane
30e3adcf8fSFrançois Tigeot  * support.
31e3adcf8fSFrançois Tigeot  *
32e3adcf8fSFrançois Tigeot  * $FreeBSD: src/sys/dev/drm2/i915/intel_sprite.c,v 1.1 2012/05/22 11:07:44 kib Exp $
33e3adcf8fSFrançois Tigeot  */
34e3adcf8fSFrançois Tigeot 
3518e26a6dSFrançois Tigeot #include <drm/drmP.h>
3618e26a6dSFrançois Tigeot #include <drm/drm_crtc.h>
3718e26a6dSFrançois Tigeot #include <uapi_drm/drm_fourcc.h>
3818e26a6dSFrançois Tigeot #include "intel_drv.h"
395c6c6f23SFrançois Tigeot #include <drm/i915_drm.h>
40e3adcf8fSFrançois Tigeot #include "i915_drv.h"
41e3adcf8fSFrançois Tigeot 
42e3adcf8fSFrançois Tigeot static void
43e3adcf8fSFrançois Tigeot ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
44e3adcf8fSFrançois Tigeot 		 struct drm_i915_gem_object *obj, int crtc_x, int crtc_y,
45e3adcf8fSFrançois Tigeot 		 unsigned int crtc_w, unsigned int crtc_h,
46e3adcf8fSFrançois Tigeot 		 uint32_t x, uint32_t y,
47e3adcf8fSFrançois Tigeot 		 uint32_t src_w, uint32_t src_h)
48e3adcf8fSFrançois Tigeot {
49e3adcf8fSFrançois Tigeot 	struct drm_device *dev = plane->dev;
50e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
51e3adcf8fSFrançois Tigeot 	struct intel_plane *intel_plane = to_intel_plane(plane);
52e3adcf8fSFrançois Tigeot 	int pipe = intel_plane->pipe;
53e3adcf8fSFrançois Tigeot 	u32 sprctl, sprscale = 0;
54e3adcf8fSFrançois Tigeot 	int pixel_size;
55e3adcf8fSFrançois Tigeot 
56e3adcf8fSFrançois Tigeot 	sprctl = I915_READ(SPRCTL(pipe));
57e3adcf8fSFrançois Tigeot 
58e3adcf8fSFrançois Tigeot 	/* Mask out pixel format bits in case we change it */
59e3adcf8fSFrançois Tigeot 	sprctl &= ~SPRITE_PIXFORMAT_MASK;
60e3adcf8fSFrançois Tigeot 	sprctl &= ~SPRITE_RGB_ORDER_RGBX;
61e3adcf8fSFrançois Tigeot 	sprctl &= ~SPRITE_YUV_BYTE_ORDER_MASK;
62e3adcf8fSFrançois Tigeot 
63e3adcf8fSFrançois Tigeot 	switch (fb->pixel_format) {
64e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_XBGR8888:
65e3adcf8fSFrançois Tigeot 		sprctl |= SPRITE_FORMAT_RGBX888;
66e3adcf8fSFrançois Tigeot 		pixel_size = 4;
67e3adcf8fSFrançois Tigeot 		break;
68e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_XRGB8888:
69e3adcf8fSFrançois Tigeot 		sprctl |= SPRITE_FORMAT_RGBX888 | SPRITE_RGB_ORDER_RGBX;
70e3adcf8fSFrançois Tigeot 		pixel_size = 4;
71e3adcf8fSFrançois Tigeot 		break;
72e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_YUYV:
73e3adcf8fSFrançois Tigeot 		sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YUYV;
74e3adcf8fSFrançois Tigeot 		pixel_size = 2;
75e3adcf8fSFrançois Tigeot 		break;
76e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_YVYU:
77e3adcf8fSFrançois Tigeot 		sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YVYU;
78e3adcf8fSFrançois Tigeot 		pixel_size = 2;
79e3adcf8fSFrançois Tigeot 		break;
80e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_UYVY:
81e3adcf8fSFrançois Tigeot 		sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_UYVY;
82e3adcf8fSFrançois Tigeot 		pixel_size = 2;
83e3adcf8fSFrançois Tigeot 		break;
84e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_VYUY:
85e3adcf8fSFrançois Tigeot 		sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_VYUY;
86e3adcf8fSFrançois Tigeot 		pixel_size = 2;
87e3adcf8fSFrançois Tigeot 		break;
88e3adcf8fSFrançois Tigeot 	default:
89e3adcf8fSFrançois Tigeot 		DRM_DEBUG_DRIVER("bad pixel format, assuming RGBX888\n");
90e3adcf8fSFrançois Tigeot 		sprctl |= DVS_FORMAT_RGBX888;
91e3adcf8fSFrançois Tigeot 		pixel_size = 4;
92e3adcf8fSFrançois Tigeot 		break;
93e3adcf8fSFrançois Tigeot 	}
94e3adcf8fSFrançois Tigeot 
95e3adcf8fSFrançois Tigeot 	if (obj->tiling_mode != I915_TILING_NONE)
96e3adcf8fSFrançois Tigeot 		sprctl |= SPRITE_TILED;
97e3adcf8fSFrançois Tigeot 
98e3adcf8fSFrançois Tigeot 	/* must disable */
99e3adcf8fSFrançois Tigeot 	sprctl |= SPRITE_TRICKLE_FEED_DISABLE;
100e3adcf8fSFrançois Tigeot 	sprctl |= SPRITE_ENABLE;
101e3adcf8fSFrançois Tigeot 
102e3adcf8fSFrançois Tigeot 	/* Sizes are 0 based */
103e3adcf8fSFrançois Tigeot 	src_w--;
104e3adcf8fSFrançois Tigeot 	src_h--;
105e3adcf8fSFrançois Tigeot 	crtc_w--;
106e3adcf8fSFrançois Tigeot 	crtc_h--;
107e3adcf8fSFrançois Tigeot 
108e3adcf8fSFrançois Tigeot 	intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size);
109e3adcf8fSFrançois Tigeot 
110e3adcf8fSFrançois Tigeot 	/*
111e3adcf8fSFrançois Tigeot 	 * IVB workaround: must disable low power watermarks for at least
112e3adcf8fSFrançois Tigeot 	 * one frame before enabling scaling.  LP watermarks can be re-enabled
113e3adcf8fSFrançois Tigeot 	 * when scaling is disabled.
114e3adcf8fSFrançois Tigeot 	 */
115e3adcf8fSFrançois Tigeot 	if (crtc_w != src_w || crtc_h != src_h) {
116e3adcf8fSFrançois Tigeot 		dev_priv->sprite_scaling_enabled = true;
117e3adcf8fSFrançois Tigeot 		sandybridge_update_wm(dev);
118e3adcf8fSFrançois Tigeot 		intel_wait_for_vblank(dev, pipe);
119e3adcf8fSFrançois Tigeot 		sprscale = SPRITE_SCALE_ENABLE | (src_w << 16) | src_h;
120e3adcf8fSFrançois Tigeot 	} else {
121e3adcf8fSFrançois Tigeot 		dev_priv->sprite_scaling_enabled = false;
122e3adcf8fSFrançois Tigeot 		/* potentially re-enable LP watermarks */
123e3adcf8fSFrançois Tigeot 		sandybridge_update_wm(dev);
124e3adcf8fSFrançois Tigeot 	}
125e3adcf8fSFrançois Tigeot 
126e3adcf8fSFrançois Tigeot 	I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]);
127e3adcf8fSFrançois Tigeot 	I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x);
128e3adcf8fSFrançois Tigeot 	if (obj->tiling_mode != I915_TILING_NONE) {
129e3adcf8fSFrançois Tigeot 		I915_WRITE(SPRTILEOFF(pipe), (y << 16) | x);
130e3adcf8fSFrançois Tigeot 	} else {
131e3adcf8fSFrançois Tigeot 		unsigned long offset;
132e3adcf8fSFrançois Tigeot 
133e3adcf8fSFrançois Tigeot 		offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8);
134e3adcf8fSFrançois Tigeot 		I915_WRITE(SPRLINOFF(pipe), offset);
135e3adcf8fSFrançois Tigeot 	}
136e3adcf8fSFrançois Tigeot 	I915_WRITE(SPRSIZE(pipe), (crtc_h << 16) | crtc_w);
137e3adcf8fSFrançois Tigeot 	I915_WRITE(SPRSCALE(pipe), sprscale);
138e3adcf8fSFrançois Tigeot 	I915_WRITE(SPRCTL(pipe), sprctl);
139e3adcf8fSFrançois Tigeot 	I915_WRITE(SPRSURF(pipe), obj->gtt_offset);
140e3adcf8fSFrançois Tigeot 	POSTING_READ(SPRSURF(pipe));
141e3adcf8fSFrançois Tigeot }
142e3adcf8fSFrançois Tigeot 
143e3adcf8fSFrançois Tigeot static void
144e3adcf8fSFrançois Tigeot ivb_disable_plane(struct drm_plane *plane)
145e3adcf8fSFrançois Tigeot {
146e3adcf8fSFrançois Tigeot 	struct drm_device *dev = plane->dev;
147e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
148e3adcf8fSFrançois Tigeot 	struct intel_plane *intel_plane = to_intel_plane(plane);
149e3adcf8fSFrançois Tigeot 	int pipe = intel_plane->pipe;
150e3adcf8fSFrançois Tigeot 
151e3adcf8fSFrançois Tigeot 	I915_WRITE(SPRCTL(pipe), I915_READ(SPRCTL(pipe)) & ~SPRITE_ENABLE);
152e3adcf8fSFrançois Tigeot 	/* Can't leave the scaler enabled... */
153e3adcf8fSFrançois Tigeot 	I915_WRITE(SPRSCALE(pipe), 0);
154e3adcf8fSFrançois Tigeot 	/* Activate double buffered register update */
155e3adcf8fSFrançois Tigeot 	I915_WRITE(SPRSURF(pipe), 0);
156e3adcf8fSFrançois Tigeot 	POSTING_READ(SPRSURF(pipe));
157e3adcf8fSFrançois Tigeot }
158e3adcf8fSFrançois Tigeot 
159e3adcf8fSFrançois Tigeot static int
160e3adcf8fSFrançois Tigeot ivb_update_colorkey(struct drm_plane *plane,
161e3adcf8fSFrançois Tigeot 		    struct drm_intel_sprite_colorkey *key)
162e3adcf8fSFrançois Tigeot {
163e3adcf8fSFrançois Tigeot 	struct drm_device *dev = plane->dev;
164e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
165e3adcf8fSFrançois Tigeot 	struct intel_plane *intel_plane;
166e3adcf8fSFrançois Tigeot 	u32 sprctl;
167e3adcf8fSFrançois Tigeot 	int ret = 0;
168e3adcf8fSFrançois Tigeot 
169e3adcf8fSFrançois Tigeot 	intel_plane = to_intel_plane(plane);
170e3adcf8fSFrançois Tigeot 
171e3adcf8fSFrançois Tigeot 	I915_WRITE(SPRKEYVAL(intel_plane->pipe), key->min_value);
172e3adcf8fSFrançois Tigeot 	I915_WRITE(SPRKEYMAX(intel_plane->pipe), key->max_value);
173e3adcf8fSFrançois Tigeot 	I915_WRITE(SPRKEYMSK(intel_plane->pipe), key->channel_mask);
174e3adcf8fSFrançois Tigeot 
175e3adcf8fSFrançois Tigeot 	sprctl = I915_READ(SPRCTL(intel_plane->pipe));
176e3adcf8fSFrançois Tigeot 	sprctl &= ~(SPRITE_SOURCE_KEY | SPRITE_DEST_KEY);
177e3adcf8fSFrançois Tigeot 	if (key->flags & I915_SET_COLORKEY_DESTINATION)
178e3adcf8fSFrançois Tigeot 		sprctl |= SPRITE_DEST_KEY;
179e3adcf8fSFrançois Tigeot 	else if (key->flags & I915_SET_COLORKEY_SOURCE)
180e3adcf8fSFrançois Tigeot 		sprctl |= SPRITE_SOURCE_KEY;
181e3adcf8fSFrançois Tigeot 	I915_WRITE(SPRCTL(intel_plane->pipe), sprctl);
182e3adcf8fSFrançois Tigeot 
183e3adcf8fSFrançois Tigeot 	POSTING_READ(SPRKEYMSK(intel_plane->pipe));
184e3adcf8fSFrançois Tigeot 
185e3adcf8fSFrançois Tigeot 	return ret;
186e3adcf8fSFrançois Tigeot }
187e3adcf8fSFrançois Tigeot 
188e3adcf8fSFrançois Tigeot static void
189e3adcf8fSFrançois Tigeot ivb_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key)
190e3adcf8fSFrançois Tigeot {
191e3adcf8fSFrançois Tigeot 	struct drm_device *dev = plane->dev;
192e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
193e3adcf8fSFrançois Tigeot 	struct intel_plane *intel_plane;
194e3adcf8fSFrançois Tigeot 	u32 sprctl;
195e3adcf8fSFrançois Tigeot 
196e3adcf8fSFrançois Tigeot 	intel_plane = to_intel_plane(plane);
197e3adcf8fSFrançois Tigeot 
198e3adcf8fSFrançois Tigeot 	key->min_value = I915_READ(SPRKEYVAL(intel_plane->pipe));
199e3adcf8fSFrançois Tigeot 	key->max_value = I915_READ(SPRKEYMAX(intel_plane->pipe));
200e3adcf8fSFrançois Tigeot 	key->channel_mask = I915_READ(SPRKEYMSK(intel_plane->pipe));
201e3adcf8fSFrançois Tigeot 	key->flags = 0;
202e3adcf8fSFrançois Tigeot 
203e3adcf8fSFrançois Tigeot 	sprctl = I915_READ(SPRCTL(intel_plane->pipe));
204e3adcf8fSFrançois Tigeot 
205e3adcf8fSFrançois Tigeot 	if (sprctl & SPRITE_DEST_KEY)
206e3adcf8fSFrançois Tigeot 		key->flags = I915_SET_COLORKEY_DESTINATION;
207e3adcf8fSFrançois Tigeot 	else if (sprctl & SPRITE_SOURCE_KEY)
208e3adcf8fSFrançois Tigeot 		key->flags = I915_SET_COLORKEY_SOURCE;
209e3adcf8fSFrançois Tigeot 	else
210e3adcf8fSFrançois Tigeot 		key->flags = I915_SET_COLORKEY_NONE;
211e3adcf8fSFrançois Tigeot }
212e3adcf8fSFrançois Tigeot 
213e3adcf8fSFrançois Tigeot static void
214e3adcf8fSFrançois Tigeot snb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
215e3adcf8fSFrançois Tigeot 		 struct drm_i915_gem_object *obj, int crtc_x, int crtc_y,
216e3adcf8fSFrançois Tigeot 		 unsigned int crtc_w, unsigned int crtc_h,
217e3adcf8fSFrançois Tigeot 		 uint32_t x, uint32_t y,
218e3adcf8fSFrançois Tigeot 		 uint32_t src_w, uint32_t src_h)
219e3adcf8fSFrançois Tigeot {
220e3adcf8fSFrançois Tigeot 	struct drm_device *dev = plane->dev;
221e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
222e3adcf8fSFrançois Tigeot 	struct intel_plane *intel_plane = to_intel_plane(plane);
223e3adcf8fSFrançois Tigeot 	int pipe = intel_plane->pipe, pixel_size;
224e3adcf8fSFrançois Tigeot 	u32 dvscntr, dvsscale = 0;
225e3adcf8fSFrançois Tigeot 
226e3adcf8fSFrançois Tigeot 	dvscntr = I915_READ(DVSCNTR(pipe));
227e3adcf8fSFrançois Tigeot 
228e3adcf8fSFrançois Tigeot 	/* Mask out pixel format bits in case we change it */
229e3adcf8fSFrançois Tigeot 	dvscntr &= ~DVS_PIXFORMAT_MASK;
230e3adcf8fSFrançois Tigeot 	dvscntr &= ~DVS_RGB_ORDER_XBGR;
231e3adcf8fSFrançois Tigeot 	dvscntr &= ~DVS_YUV_BYTE_ORDER_MASK;
232e3adcf8fSFrançois Tigeot 
233e3adcf8fSFrançois Tigeot 	switch (fb->pixel_format) {
234e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_XBGR8888:
235e3adcf8fSFrançois Tigeot 		dvscntr |= DVS_FORMAT_RGBX888 | DVS_RGB_ORDER_XBGR;
236e3adcf8fSFrançois Tigeot 		pixel_size = 4;
237e3adcf8fSFrançois Tigeot 		break;
238e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_XRGB8888:
239e3adcf8fSFrançois Tigeot 		dvscntr |= DVS_FORMAT_RGBX888;
240e3adcf8fSFrançois Tigeot 		pixel_size = 4;
241e3adcf8fSFrançois Tigeot 		break;
242e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_YUYV:
243e3adcf8fSFrançois Tigeot 		dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YUYV;
244e3adcf8fSFrançois Tigeot 		pixel_size = 2;
245e3adcf8fSFrançois Tigeot 		break;
246e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_YVYU:
247e3adcf8fSFrançois Tigeot 		dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YVYU;
248e3adcf8fSFrançois Tigeot 		pixel_size = 2;
249e3adcf8fSFrançois Tigeot 		break;
250e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_UYVY:
251e3adcf8fSFrançois Tigeot 		dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_UYVY;
252e3adcf8fSFrançois Tigeot 		pixel_size = 2;
253e3adcf8fSFrançois Tigeot 		break;
254e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_VYUY:
255e3adcf8fSFrançois Tigeot 		dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_VYUY;
256e3adcf8fSFrançois Tigeot 		pixel_size = 2;
257e3adcf8fSFrançois Tigeot 		break;
258e3adcf8fSFrançois Tigeot 	default:
259e3adcf8fSFrançois Tigeot 		DRM_DEBUG_DRIVER("bad pixel format, assuming RGBX888\n");
260e3adcf8fSFrançois Tigeot 		dvscntr |= DVS_FORMAT_RGBX888;
261e3adcf8fSFrançois Tigeot 		pixel_size = 4;
262e3adcf8fSFrançois Tigeot 		break;
263e3adcf8fSFrançois Tigeot 	}
264e3adcf8fSFrançois Tigeot 
265e3adcf8fSFrançois Tigeot 	if (obj->tiling_mode != I915_TILING_NONE)
266e3adcf8fSFrançois Tigeot 		dvscntr |= DVS_TILED;
267e3adcf8fSFrançois Tigeot 
268e3adcf8fSFrançois Tigeot 	/* must disable */
269e3adcf8fSFrançois Tigeot 	dvscntr |= DVS_TRICKLE_FEED_DISABLE;
270e3adcf8fSFrançois Tigeot 	dvscntr |= DVS_ENABLE;
271e3adcf8fSFrançois Tigeot 
272e3adcf8fSFrançois Tigeot 	/* Sizes are 0 based */
273e3adcf8fSFrançois Tigeot 	src_w--;
274e3adcf8fSFrançois Tigeot 	src_h--;
275e3adcf8fSFrançois Tigeot 	crtc_w--;
276e3adcf8fSFrançois Tigeot 	crtc_h--;
277e3adcf8fSFrançois Tigeot 
278e3adcf8fSFrançois Tigeot 	intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size);
279e3adcf8fSFrançois Tigeot 
280e3adcf8fSFrançois Tigeot 	if (crtc_w != src_w || crtc_h != src_h)
281e3adcf8fSFrançois Tigeot 		dvsscale = DVS_SCALE_ENABLE | (src_w << 16) | src_h;
282e3adcf8fSFrançois Tigeot 
283e3adcf8fSFrançois Tigeot 	I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]);
284e3adcf8fSFrançois Tigeot 	I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x);
285e3adcf8fSFrançois Tigeot 	if (obj->tiling_mode != I915_TILING_NONE) {
286e3adcf8fSFrançois Tigeot 		I915_WRITE(DVSTILEOFF(pipe), (y << 16) | x);
287e3adcf8fSFrançois Tigeot 	} else {
288e3adcf8fSFrançois Tigeot 		unsigned long offset;
289e3adcf8fSFrançois Tigeot 
290e3adcf8fSFrançois Tigeot 		offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8);
291e3adcf8fSFrançois Tigeot 		I915_WRITE(DVSLINOFF(pipe), offset);
292e3adcf8fSFrançois Tigeot 	}
293e3adcf8fSFrançois Tigeot 	I915_WRITE(DVSSIZE(pipe), (crtc_h << 16) | crtc_w);
294e3adcf8fSFrançois Tigeot 	I915_WRITE(DVSSCALE(pipe), dvsscale);
295e3adcf8fSFrançois Tigeot 	I915_WRITE(DVSCNTR(pipe), dvscntr);
296e3adcf8fSFrançois Tigeot 	I915_WRITE(DVSSURF(pipe), obj->gtt_offset);
297e3adcf8fSFrançois Tigeot 	POSTING_READ(DVSSURF(pipe));
298e3adcf8fSFrançois Tigeot }
299e3adcf8fSFrançois Tigeot 
300e3adcf8fSFrançois Tigeot static void
301e3adcf8fSFrançois Tigeot snb_disable_plane(struct drm_plane *plane)
302e3adcf8fSFrançois Tigeot {
303e3adcf8fSFrançois Tigeot 	struct drm_device *dev = plane->dev;
304e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
305e3adcf8fSFrançois Tigeot 	struct intel_plane *intel_plane = to_intel_plane(plane);
306e3adcf8fSFrançois Tigeot 	int pipe = intel_plane->pipe;
307e3adcf8fSFrançois Tigeot 
308e3adcf8fSFrançois Tigeot 	I915_WRITE(DVSCNTR(pipe), I915_READ(DVSCNTR(pipe)) & ~DVS_ENABLE);
309e3adcf8fSFrançois Tigeot 	/* Disable the scaler */
310e3adcf8fSFrançois Tigeot 	I915_WRITE(DVSSCALE(pipe), 0);
311e3adcf8fSFrançois Tigeot 	/* Flush double buffered register updates */
312e3adcf8fSFrançois Tigeot 	I915_WRITE(DVSSURF(pipe), 0);
313e3adcf8fSFrançois Tigeot 	POSTING_READ(DVSSURF(pipe));
314e3adcf8fSFrançois Tigeot }
315e3adcf8fSFrançois Tigeot 
316e3adcf8fSFrançois Tigeot static void
317e3adcf8fSFrançois Tigeot intel_enable_primary(struct drm_crtc *crtc)
318e3adcf8fSFrançois Tigeot {
319e3adcf8fSFrançois Tigeot 	struct drm_device *dev = crtc->dev;
320e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
321e3adcf8fSFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
322e3adcf8fSFrançois Tigeot 	int reg = DSPCNTR(intel_crtc->plane);
323e3adcf8fSFrançois Tigeot 
324e3adcf8fSFrançois Tigeot 	I915_WRITE(reg, I915_READ(reg) | DISPLAY_PLANE_ENABLE);
325e3adcf8fSFrançois Tigeot }
326e3adcf8fSFrançois Tigeot 
327e3adcf8fSFrançois Tigeot static void
328e3adcf8fSFrançois Tigeot intel_disable_primary(struct drm_crtc *crtc)
329e3adcf8fSFrançois Tigeot {
330e3adcf8fSFrançois Tigeot 	struct drm_device *dev = crtc->dev;
331e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
332e3adcf8fSFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
333e3adcf8fSFrançois Tigeot 	int reg = DSPCNTR(intel_crtc->plane);
334e3adcf8fSFrançois Tigeot 
335e3adcf8fSFrançois Tigeot 	I915_WRITE(reg, I915_READ(reg) & ~DISPLAY_PLANE_ENABLE);
336e3adcf8fSFrançois Tigeot }
337e3adcf8fSFrançois Tigeot 
338e3adcf8fSFrançois Tigeot static int
339e3adcf8fSFrançois Tigeot snb_update_colorkey(struct drm_plane *plane,
340e3adcf8fSFrançois Tigeot 		    struct drm_intel_sprite_colorkey *key)
341e3adcf8fSFrançois Tigeot {
342e3adcf8fSFrançois Tigeot 	struct drm_device *dev = plane->dev;
343e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
344e3adcf8fSFrançois Tigeot 	struct intel_plane *intel_plane;
345e3adcf8fSFrançois Tigeot 	u32 dvscntr;
346e3adcf8fSFrançois Tigeot 	int ret = 0;
347e3adcf8fSFrançois Tigeot 
348e3adcf8fSFrançois Tigeot 	intel_plane = to_intel_plane(plane);
349e3adcf8fSFrançois Tigeot 
350e3adcf8fSFrançois Tigeot 	I915_WRITE(DVSKEYVAL(intel_plane->pipe), key->min_value);
351e3adcf8fSFrançois Tigeot 	I915_WRITE(DVSKEYMAX(intel_plane->pipe), key->max_value);
352e3adcf8fSFrançois Tigeot 	I915_WRITE(DVSKEYMSK(intel_plane->pipe), key->channel_mask);
353e3adcf8fSFrançois Tigeot 
354e3adcf8fSFrançois Tigeot 	dvscntr = I915_READ(DVSCNTR(intel_plane->pipe));
355e3adcf8fSFrançois Tigeot 	dvscntr &= ~(DVS_SOURCE_KEY | DVS_DEST_KEY);
356e3adcf8fSFrançois Tigeot 	if (key->flags & I915_SET_COLORKEY_DESTINATION)
357e3adcf8fSFrançois Tigeot 		dvscntr |= DVS_DEST_KEY;
358e3adcf8fSFrançois Tigeot 	else if (key->flags & I915_SET_COLORKEY_SOURCE)
359e3adcf8fSFrançois Tigeot 		dvscntr |= DVS_SOURCE_KEY;
360e3adcf8fSFrançois Tigeot 	I915_WRITE(DVSCNTR(intel_plane->pipe), dvscntr);
361e3adcf8fSFrançois Tigeot 
362e3adcf8fSFrançois Tigeot 	POSTING_READ(DVSKEYMSK(intel_plane->pipe));
363e3adcf8fSFrançois Tigeot 
364e3adcf8fSFrançois Tigeot 	return ret;
365e3adcf8fSFrançois Tigeot }
366e3adcf8fSFrançois Tigeot 
367e3adcf8fSFrançois Tigeot static void
368e3adcf8fSFrançois Tigeot snb_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key)
369e3adcf8fSFrançois Tigeot {
370e3adcf8fSFrançois Tigeot 	struct drm_device *dev = plane->dev;
371e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
372e3adcf8fSFrançois Tigeot 	struct intel_plane *intel_plane;
373e3adcf8fSFrançois Tigeot 	u32 dvscntr;
374e3adcf8fSFrançois Tigeot 
375e3adcf8fSFrançois Tigeot 	intel_plane = to_intel_plane(plane);
376e3adcf8fSFrançois Tigeot 
377e3adcf8fSFrançois Tigeot 	key->min_value = I915_READ(DVSKEYVAL(intel_plane->pipe));
378e3adcf8fSFrançois Tigeot 	key->max_value = I915_READ(DVSKEYMAX(intel_plane->pipe));
379e3adcf8fSFrançois Tigeot 	key->channel_mask = I915_READ(DVSKEYMSK(intel_plane->pipe));
380e3adcf8fSFrançois Tigeot 	key->flags = 0;
381e3adcf8fSFrançois Tigeot 
382e3adcf8fSFrançois Tigeot 	dvscntr = I915_READ(DVSCNTR(intel_plane->pipe));
383e3adcf8fSFrançois Tigeot 
384e3adcf8fSFrançois Tigeot 	if (dvscntr & DVS_DEST_KEY)
385e3adcf8fSFrançois Tigeot 		key->flags = I915_SET_COLORKEY_DESTINATION;
386e3adcf8fSFrançois Tigeot 	else if (dvscntr & DVS_SOURCE_KEY)
387e3adcf8fSFrançois Tigeot 		key->flags = I915_SET_COLORKEY_SOURCE;
388e3adcf8fSFrançois Tigeot 	else
389e3adcf8fSFrançois Tigeot 		key->flags = I915_SET_COLORKEY_NONE;
390e3adcf8fSFrançois Tigeot }
391e3adcf8fSFrançois Tigeot 
392e3adcf8fSFrançois Tigeot static int
393e3adcf8fSFrançois Tigeot intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
394e3adcf8fSFrançois Tigeot 		   struct drm_framebuffer *fb, int crtc_x, int crtc_y,
395e3adcf8fSFrançois Tigeot 		   unsigned int crtc_w, unsigned int crtc_h,
396e3adcf8fSFrançois Tigeot 		   uint32_t src_x, uint32_t src_y,
397e3adcf8fSFrançois Tigeot 		   uint32_t src_w, uint32_t src_h)
398e3adcf8fSFrançois Tigeot {
399e3adcf8fSFrançois Tigeot 	struct drm_device *dev = plane->dev;
400e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
401e3adcf8fSFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
402e3adcf8fSFrançois Tigeot 	struct intel_plane *intel_plane = to_intel_plane(plane);
403e3adcf8fSFrançois Tigeot 	struct intel_framebuffer *intel_fb;
404e3adcf8fSFrançois Tigeot 	struct drm_i915_gem_object *obj, *old_obj;
405e3adcf8fSFrançois Tigeot 	int pipe = intel_plane->pipe;
406e3adcf8fSFrançois Tigeot 	int ret = 0;
407e3adcf8fSFrançois Tigeot 	int x = src_x >> 16, y = src_y >> 16;
408e3adcf8fSFrançois Tigeot 	int primary_w = crtc->mode.hdisplay, primary_h = crtc->mode.vdisplay;
409e3adcf8fSFrançois Tigeot 	bool disable_primary = false;
410e3adcf8fSFrançois Tigeot 
411e3adcf8fSFrançois Tigeot 	intel_fb = to_intel_framebuffer(fb);
412e3adcf8fSFrançois Tigeot 	obj = intel_fb->obj;
413e3adcf8fSFrançois Tigeot 
414e3adcf8fSFrançois Tigeot 	old_obj = intel_plane->obj;
415e3adcf8fSFrançois Tigeot 
416e3adcf8fSFrançois Tigeot 	src_w = src_w >> 16;
417e3adcf8fSFrançois Tigeot 	src_h = src_h >> 16;
418e3adcf8fSFrançois Tigeot 
419e3adcf8fSFrançois Tigeot 	/* Pipe must be running... */
420e3adcf8fSFrançois Tigeot 	if (!(I915_READ(PIPECONF(pipe)) & PIPECONF_ENABLE))
421e3adcf8fSFrançois Tigeot 		return -EINVAL;
422e3adcf8fSFrançois Tigeot 
423e3adcf8fSFrançois Tigeot 	if (crtc_x >= primary_w || crtc_y >= primary_h)
424e3adcf8fSFrançois Tigeot 		return -EINVAL;
425e3adcf8fSFrançois Tigeot 
426e3adcf8fSFrançois Tigeot 	/* Don't modify another pipe's plane */
427e3adcf8fSFrançois Tigeot 	if (intel_plane->pipe != intel_crtc->pipe)
428e3adcf8fSFrançois Tigeot 		return -EINVAL;
429e3adcf8fSFrançois Tigeot 
430e3adcf8fSFrançois Tigeot 	/*
431e3adcf8fSFrançois Tigeot 	 * Clamp the width & height into the visible area.  Note we don't
432e3adcf8fSFrançois Tigeot 	 * try to scale the source if part of the visible region is offscreen.
433e3adcf8fSFrançois Tigeot 	 * The caller must handle that by adjusting source offset and size.
434e3adcf8fSFrançois Tigeot 	 */
435e3adcf8fSFrançois Tigeot 	if ((crtc_x < 0) && ((crtc_x + crtc_w) > 0)) {
436e3adcf8fSFrançois Tigeot 		crtc_w += crtc_x;
437e3adcf8fSFrançois Tigeot 		crtc_x = 0;
438e3adcf8fSFrançois Tigeot 	}
439e3adcf8fSFrançois Tigeot 	if ((crtc_x + crtc_w) <= 0) /* Nothing to display */
440e3adcf8fSFrançois Tigeot 		goto out;
441e3adcf8fSFrançois Tigeot 	if ((crtc_x + crtc_w) > primary_w)
442e3adcf8fSFrançois Tigeot 		crtc_w = primary_w - crtc_x;
443e3adcf8fSFrançois Tigeot 
444e3adcf8fSFrançois Tigeot 	if ((crtc_y < 0) && ((crtc_y + crtc_h) > 0)) {
445e3adcf8fSFrançois Tigeot 		crtc_h += crtc_y;
446e3adcf8fSFrançois Tigeot 		crtc_y = 0;
447e3adcf8fSFrançois Tigeot 	}
448e3adcf8fSFrançois Tigeot 	if ((crtc_y + crtc_h) <= 0) /* Nothing to display */
449e3adcf8fSFrançois Tigeot 		goto out;
450e3adcf8fSFrançois Tigeot 	if (crtc_y + crtc_h > primary_h)
451e3adcf8fSFrançois Tigeot 		crtc_h = primary_h - crtc_y;
452e3adcf8fSFrançois Tigeot 
453e3adcf8fSFrançois Tigeot 	if (!crtc_w || !crtc_h) /* Again, nothing to display */
454e3adcf8fSFrançois Tigeot 		goto out;
455e3adcf8fSFrançois Tigeot 
456e3adcf8fSFrançois Tigeot 	/*
457e3adcf8fSFrançois Tigeot 	 * We can take a larger source and scale it down, but
458e3adcf8fSFrançois Tigeot 	 * only so much...  16x is the max on SNB.
459e3adcf8fSFrançois Tigeot 	 */
460e3adcf8fSFrançois Tigeot 	if (((src_w * src_h) / (crtc_w * crtc_h)) > intel_plane->max_downscale)
461e3adcf8fSFrançois Tigeot 		return -EINVAL;
462e3adcf8fSFrançois Tigeot 
463e3adcf8fSFrançois Tigeot 	/*
464e3adcf8fSFrançois Tigeot 	 * If the sprite is completely covering the primary plane,
465e3adcf8fSFrançois Tigeot 	 * we can disable the primary and save power.
466e3adcf8fSFrançois Tigeot 	 */
467e3adcf8fSFrançois Tigeot 	if ((crtc_x == 0) && (crtc_y == 0) &&
468e3adcf8fSFrançois Tigeot 	    (crtc_w == primary_w) && (crtc_h == primary_h))
469e3adcf8fSFrançois Tigeot 		disable_primary = true;
470e3adcf8fSFrançois Tigeot 
471e3adcf8fSFrançois Tigeot 	DRM_LOCK(dev);
472e3adcf8fSFrançois Tigeot 
473e3adcf8fSFrançois Tigeot 	ret = intel_pin_and_fence_fb_obj(dev, obj, NULL);
474e3adcf8fSFrançois Tigeot 	if (ret)
475e3adcf8fSFrançois Tigeot 		goto out_unlock;
476e3adcf8fSFrançois Tigeot 
477e3adcf8fSFrançois Tigeot 	intel_plane->obj = obj;
478e3adcf8fSFrançois Tigeot 
479e3adcf8fSFrançois Tigeot 	/*
480e3adcf8fSFrançois Tigeot 	 * Be sure to re-enable the primary before the sprite is no longer
481e3adcf8fSFrançois Tigeot 	 * covering it fully.
482e3adcf8fSFrançois Tigeot 	 */
483e3adcf8fSFrançois Tigeot 	if (!disable_primary && intel_plane->primary_disabled) {
484e3adcf8fSFrançois Tigeot 		intel_enable_primary(crtc);
485e3adcf8fSFrançois Tigeot 		intel_plane->primary_disabled = false;
486e3adcf8fSFrançois Tigeot 	}
487e3adcf8fSFrançois Tigeot 
488e3adcf8fSFrançois Tigeot 	intel_plane->update_plane(plane, fb, obj, crtc_x, crtc_y,
489e3adcf8fSFrançois Tigeot 				  crtc_w, crtc_h, x, y, src_w, src_h);
490e3adcf8fSFrançois Tigeot 
491e3adcf8fSFrançois Tigeot 	if (disable_primary) {
492e3adcf8fSFrançois Tigeot 		intel_disable_primary(crtc);
493e3adcf8fSFrançois Tigeot 		intel_plane->primary_disabled = true;
494e3adcf8fSFrançois Tigeot 	}
495e3adcf8fSFrançois Tigeot 
496e3adcf8fSFrançois Tigeot 	/* Unpin old obj after new one is active to avoid ugliness */
497e3adcf8fSFrançois Tigeot 	if (old_obj) {
498e3adcf8fSFrançois Tigeot 		/*
499e3adcf8fSFrançois Tigeot 		 * It's fairly common to simply update the position of
500e3adcf8fSFrançois Tigeot 		 * an existing object.  In that case, we don't need to
501e3adcf8fSFrançois Tigeot 		 * wait for vblank to avoid ugliness, we only need to
502e3adcf8fSFrançois Tigeot 		 * do the pin & ref bookkeeping.
503e3adcf8fSFrançois Tigeot 		 */
504e3adcf8fSFrançois Tigeot 		if (old_obj != obj) {
505e3adcf8fSFrançois Tigeot 			DRM_UNLOCK(dev);
506e3adcf8fSFrançois Tigeot 			intel_wait_for_vblank(dev, to_intel_crtc(crtc)->pipe);
507e3adcf8fSFrançois Tigeot 			DRM_LOCK(dev);
508e3adcf8fSFrançois Tigeot 		}
509e3adcf8fSFrançois Tigeot 		intel_unpin_fb_obj(old_obj);
510e3adcf8fSFrançois Tigeot 	}
511e3adcf8fSFrançois Tigeot 
512e3adcf8fSFrançois Tigeot out_unlock:
513e3adcf8fSFrançois Tigeot 	DRM_UNLOCK(dev);
514e3adcf8fSFrançois Tigeot out:
515e3adcf8fSFrançois Tigeot 	return ret;
516e3adcf8fSFrançois Tigeot }
517e3adcf8fSFrançois Tigeot 
518e3adcf8fSFrançois Tigeot static int
519e3adcf8fSFrançois Tigeot intel_disable_plane(struct drm_plane *plane)
520e3adcf8fSFrançois Tigeot {
521e3adcf8fSFrançois Tigeot 	struct drm_device *dev = plane->dev;
522e3adcf8fSFrançois Tigeot 	struct intel_plane *intel_plane = to_intel_plane(plane);
523e3adcf8fSFrançois Tigeot 	int ret = 0;
524e3adcf8fSFrançois Tigeot 
525e3adcf8fSFrançois Tigeot 	if (intel_plane->primary_disabled) {
526e3adcf8fSFrançois Tigeot 		intel_enable_primary(plane->crtc);
527e3adcf8fSFrançois Tigeot 		intel_plane->primary_disabled = false;
528e3adcf8fSFrançois Tigeot 	}
529e3adcf8fSFrançois Tigeot 
530e3adcf8fSFrançois Tigeot 	intel_plane->disable_plane(plane);
531e3adcf8fSFrançois Tigeot 
532e3adcf8fSFrançois Tigeot 	if (!intel_plane->obj)
533e3adcf8fSFrançois Tigeot 		goto out;
534e3adcf8fSFrançois Tigeot 
535e3adcf8fSFrançois Tigeot 	DRM_LOCK(dev);
536e3adcf8fSFrançois Tigeot 	intel_unpin_fb_obj(intel_plane->obj);
537e3adcf8fSFrançois Tigeot 	intel_plane->obj = NULL;
538e3adcf8fSFrançois Tigeot 	DRM_UNLOCK(dev);
539e3adcf8fSFrançois Tigeot out:
540e3adcf8fSFrançois Tigeot 
541e3adcf8fSFrançois Tigeot 	return ret;
542e3adcf8fSFrançois Tigeot }
543e3adcf8fSFrançois Tigeot 
544e3adcf8fSFrançois Tigeot static void intel_destroy_plane(struct drm_plane *plane)
545e3adcf8fSFrançois Tigeot {
546e3adcf8fSFrançois Tigeot 	struct intel_plane *intel_plane = to_intel_plane(plane);
547e3adcf8fSFrançois Tigeot 	intel_disable_plane(plane);
548e3adcf8fSFrançois Tigeot 	drm_plane_cleanup(plane);
549e3adcf8fSFrançois Tigeot 	drm_free(intel_plane, DRM_MEM_KMS);
550e3adcf8fSFrançois Tigeot }
551e3adcf8fSFrançois Tigeot 
552e3adcf8fSFrançois Tigeot int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
553e3adcf8fSFrançois Tigeot 			      struct drm_file *file_priv)
554e3adcf8fSFrançois Tigeot {
555e3adcf8fSFrançois Tigeot 	struct drm_intel_sprite_colorkey *set = data;
556e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
557e3adcf8fSFrançois Tigeot 	struct drm_mode_object *obj;
558e3adcf8fSFrançois Tigeot 	struct drm_plane *plane;
559e3adcf8fSFrançois Tigeot 	struct intel_plane *intel_plane;
560e3adcf8fSFrançois Tigeot 	int ret = 0;
561e3adcf8fSFrançois Tigeot 
562e3adcf8fSFrançois Tigeot 	if (!dev_priv)
563e3adcf8fSFrançois Tigeot 		return -EINVAL;
564e3adcf8fSFrançois Tigeot 
565e3adcf8fSFrançois Tigeot 	/* Make sure we don't try to enable both src & dest simultaneously */
566e3adcf8fSFrançois Tigeot 	if ((set->flags & (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) == (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE))
567e3adcf8fSFrançois Tigeot 		return -EINVAL;
568e3adcf8fSFrançois Tigeot 
569*af4b81b9SFrançois Tigeot 	lockmgr(&dev->mode_config.mutex, LK_EXCLUSIVE);
570e3adcf8fSFrançois Tigeot 
571e3adcf8fSFrançois Tigeot 	obj = drm_mode_object_find(dev, set->plane_id, DRM_MODE_OBJECT_PLANE);
572e3adcf8fSFrançois Tigeot 	if (!obj) {
573e3adcf8fSFrançois Tigeot 		ret = -EINVAL;
574e3adcf8fSFrançois Tigeot 		goto out_unlock;
575e3adcf8fSFrançois Tigeot 	}
576e3adcf8fSFrançois Tigeot 
577e3adcf8fSFrançois Tigeot 	plane = obj_to_plane(obj);
578e3adcf8fSFrançois Tigeot 	intel_plane = to_intel_plane(plane);
579e3adcf8fSFrançois Tigeot 	ret = intel_plane->update_colorkey(plane, set);
580e3adcf8fSFrançois Tigeot 
581e3adcf8fSFrançois Tigeot out_unlock:
582*af4b81b9SFrançois Tigeot 	lockmgr(&dev->mode_config.mutex, LK_RELEASE);
583e3adcf8fSFrançois Tigeot 	return ret;
584e3adcf8fSFrançois Tigeot }
585e3adcf8fSFrançois Tigeot 
586e3adcf8fSFrançois Tigeot int intel_sprite_get_colorkey(struct drm_device *dev, void *data,
587e3adcf8fSFrançois Tigeot 			      struct drm_file *file_priv)
588e3adcf8fSFrançois Tigeot {
589e3adcf8fSFrançois Tigeot 	struct drm_intel_sprite_colorkey *get = data;
590e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
591e3adcf8fSFrançois Tigeot 	struct drm_mode_object *obj;
592e3adcf8fSFrançois Tigeot 	struct drm_plane *plane;
593e3adcf8fSFrançois Tigeot 	struct intel_plane *intel_plane;
594e3adcf8fSFrançois Tigeot 	int ret = 0;
595e3adcf8fSFrançois Tigeot 
596e3adcf8fSFrançois Tigeot 	if (!dev_priv)
597e3adcf8fSFrançois Tigeot 		return -EINVAL;
598e3adcf8fSFrançois Tigeot 
599*af4b81b9SFrançois Tigeot 	lockmgr(&dev->mode_config.mutex, LK_EXCLUSIVE);
600e3adcf8fSFrançois Tigeot 
601e3adcf8fSFrançois Tigeot 	obj = drm_mode_object_find(dev, get->plane_id, DRM_MODE_OBJECT_PLANE);
602e3adcf8fSFrançois Tigeot 	if (!obj) {
603e3adcf8fSFrançois Tigeot 		ret = -EINVAL;
604e3adcf8fSFrançois Tigeot 		goto out_unlock;
605e3adcf8fSFrançois Tigeot 	}
606e3adcf8fSFrançois Tigeot 
607e3adcf8fSFrançois Tigeot 	plane = obj_to_plane(obj);
608e3adcf8fSFrançois Tigeot 	intel_plane = to_intel_plane(plane);
609e3adcf8fSFrançois Tigeot 	intel_plane->get_colorkey(plane, get);
610e3adcf8fSFrançois Tigeot 
611e3adcf8fSFrançois Tigeot out_unlock:
612*af4b81b9SFrançois Tigeot 	lockmgr(&dev->mode_config.mutex, LK_RELEASE);
613e3adcf8fSFrançois Tigeot 	return ret;
614e3adcf8fSFrançois Tigeot }
615e3adcf8fSFrançois Tigeot 
616e3adcf8fSFrançois Tigeot static const struct drm_plane_funcs intel_plane_funcs = {
617e3adcf8fSFrançois Tigeot 	.update_plane = intel_update_plane,
618e3adcf8fSFrançois Tigeot 	.disable_plane = intel_disable_plane,
619e3adcf8fSFrançois Tigeot 	.destroy = intel_destroy_plane,
620e3adcf8fSFrançois Tigeot };
621e3adcf8fSFrançois Tigeot 
622e3adcf8fSFrançois Tigeot static uint32_t snb_plane_formats[] = {
623e3adcf8fSFrançois Tigeot 	DRM_FORMAT_XBGR8888,
624e3adcf8fSFrançois Tigeot 	DRM_FORMAT_XRGB8888,
625e3adcf8fSFrançois Tigeot 	DRM_FORMAT_YUYV,
626e3adcf8fSFrançois Tigeot 	DRM_FORMAT_YVYU,
627e3adcf8fSFrançois Tigeot 	DRM_FORMAT_UYVY,
628e3adcf8fSFrançois Tigeot 	DRM_FORMAT_VYUY,
629e3adcf8fSFrançois Tigeot };
630e3adcf8fSFrançois Tigeot 
631e3adcf8fSFrançois Tigeot int
632e3adcf8fSFrançois Tigeot intel_plane_init(struct drm_device *dev, enum i915_pipe pipe)
633e3adcf8fSFrançois Tigeot {
634e3adcf8fSFrançois Tigeot 	struct intel_plane *intel_plane;
635e3adcf8fSFrançois Tigeot 	unsigned long possible_crtcs;
636e3adcf8fSFrançois Tigeot 	int ret;
637e3adcf8fSFrançois Tigeot 
638e3adcf8fSFrançois Tigeot 	if (!(IS_GEN6(dev) || IS_GEN7(dev)))
639e3adcf8fSFrançois Tigeot 		return -ENODEV;
640e3adcf8fSFrançois Tigeot 
641e3adcf8fSFrançois Tigeot 	intel_plane = kmalloc(sizeof(struct intel_plane), DRM_MEM_KMS,
642e3adcf8fSFrançois Tigeot 	    M_WAITOK | M_ZERO);
643e3adcf8fSFrançois Tigeot 
644e3adcf8fSFrançois Tigeot 	if (IS_GEN6(dev)) {
645e3adcf8fSFrançois Tigeot 		intel_plane->max_downscale = 16;
646e3adcf8fSFrançois Tigeot 		intel_plane->update_plane = snb_update_plane;
647e3adcf8fSFrançois Tigeot 		intel_plane->disable_plane = snb_disable_plane;
648e3adcf8fSFrançois Tigeot 		intel_plane->update_colorkey = snb_update_colorkey;
649e3adcf8fSFrançois Tigeot 		intel_plane->get_colorkey = snb_get_colorkey;
650e3adcf8fSFrançois Tigeot 	} else if (IS_GEN7(dev)) {
651e3adcf8fSFrançois Tigeot 		intel_plane->max_downscale = 2;
652e3adcf8fSFrançois Tigeot 		intel_plane->update_plane = ivb_update_plane;
653e3adcf8fSFrançois Tigeot 		intel_plane->disable_plane = ivb_disable_plane;
654e3adcf8fSFrançois Tigeot 		intel_plane->update_colorkey = ivb_update_colorkey;
655e3adcf8fSFrançois Tigeot 		intel_plane->get_colorkey = ivb_get_colorkey;
656e3adcf8fSFrançois Tigeot 	}
657e3adcf8fSFrançois Tigeot 
658e3adcf8fSFrançois Tigeot 	intel_plane->pipe = pipe;
659e3adcf8fSFrançois Tigeot 	possible_crtcs = (1 << pipe);
660e3adcf8fSFrançois Tigeot 	ret = drm_plane_init(dev, &intel_plane->base, possible_crtcs,
661e3adcf8fSFrançois Tigeot 			     &intel_plane_funcs, snb_plane_formats,
662e3adcf8fSFrançois Tigeot 			     DRM_ARRAY_SIZE(snb_plane_formats), false);
663e3adcf8fSFrançois Tigeot 	if (ret)
664e3adcf8fSFrançois Tigeot 		drm_free(intel_plane, DRM_MEM_KMS);
665e3adcf8fSFrançois Tigeot 
666e3adcf8fSFrançois Tigeot 	return ret;
667e3adcf8fSFrançois Tigeot }
668e3adcf8fSFrançois Tigeot 
669