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