drm/i915: Implement commit w/o pinning for sprites
[vsyrjala:linux.git] / drivers / gpu / drm / i915 / intel_sprite.c
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 bool
40 format_is_yuv(uint32_t format)
41 {
42         switch (format) {
43         case DRM_FORMAT_YUYV:
44         case DRM_FORMAT_UYVY:
45         case DRM_FORMAT_VYUY:
46         case DRM_FORMAT_YVYU:
47                 return true;
48         default:
49                 return false;
50         }
51 }
52
53 static void intel_clip_plane(const struct drm_plane *plane,
54                              const struct drm_crtc *crtc,
55                              const struct drm_framebuffer *fb,
56                              struct intel_plane_coords *coords)
57 {
58         const struct intel_plane *intel_plane = to_intel_plane(plane);
59         const struct drm_display_mode *mode = &crtc->mode;
60         int hscale, vscale;
61         struct drm_region src = {
62                 .x1 = coords->src_x,
63                 .x2 = coords->src_x + coords->src_w,
64                 .y1 = coords->src_y,
65                 .y2 = coords->src_y + coords->src_h,
66         };
67         struct drm_region dst = {
68                 .x1 = coords->crtc_x,
69                 .x2 = coords->crtc_x + coords->crtc_w,
70                 .y1 = coords->crtc_y,
71                 .y2 = coords->crtc_y + coords->crtc_h,
72         };
73         const struct drm_region clip = {
74                 .x2 = mode->hdisplay,
75                 .y2 = mode->vdisplay,
76         };
77
78         hscale = drm_calc_hscale(&src, &dst, 1, intel_plane->max_downscale << 16);
79         vscale = drm_calc_vscale(&src, &dst, 1, intel_plane->max_downscale << 16);
80
81         coords->visible = drm_region_clip_scaled(&src, &dst, &clip, hscale, vscale);
82
83         coords->crtc_x = dst.x1;
84         coords->crtc_y = dst.y1;
85         coords->crtc_w = drm_region_width(&dst);
86         coords->crtc_h = drm_region_height(&dst);
87
88         /* HW doesn't seem to like smaller sprite, even when scaling */
89         /* FIXME return an error instead? */
90         if (coords->crtc_w < 3 || coords->crtc_h < 3)
91                 coords->visible = false;
92
93         /*
94          * Hardware doesn't handle subpixel coordinates.
95          * Round to nearest (macro)pixel boundary.
96          */
97         if (format_is_yuv(fb->pixel_format)) {
98                 coords->src_x = ((src.x1 + 0x10000) >> 17) << 1;
99                 coords->src_w = (((src.x2 + 0x10000) >> 17) << 1) - coords->src_x;
100         } else {
101                 coords->src_x = (src.x1 + 0x8000) >> 16;
102                 coords->src_w = ((src.x2 + 0x8000) >> 16) - coords->src_x;
103         }
104         coords->src_y = (src.y1 + 0x8000) >> 16;
105         coords->src_h = ((src.y2 + 0x8000) >> 16) - coords->src_y;
106
107         /* Account for minimum source size when scaling */
108         if (coords->visible && (coords->src_w != coords->crtc_w || coords->src_h != coords->crtc_h)) {
109                 unsigned int min_w = format_is_yuv(fb->pixel_format) ? 4 : 3;
110
111                 if (coords->src_w < min_w) {
112                         coords->src_w = min_w;
113                         if (coords->src_x > fb->width - coords->src_w)
114                                 coords->src_x = fb->width - coords->src_w;
115                 }
116
117                 /* FIXME interlacing */
118                 if (coords->src_h < 3) {
119                         coords->src_h = 3;
120                         if (coords->src_y > fb->height - coords->src_h)
121                                 coords->src_y = fb->height - coords->src_h;
122                 }
123         }
124 }
125
126 int intel_check_plane(const struct drm_plane *plane,
127                       const struct drm_crtc *crtc,
128                       const struct drm_framebuffer *fb,
129                       struct intel_plane_coords *coords)
130 {
131         const struct intel_plane *intel_plane = to_intel_plane(plane);
132
133         if (fb) {
134                 /* FIXME copy-pasted. refactor common code in drm_crtc.c */
135                 uint32_t fb_width = fb->width << 16;
136                 uint32_t fb_height = fb->height << 16;
137                 int i;
138
139                 for (i = 0; i < plane->format_count; i++) {
140                         if (plane->format_types[i] == fb->pixel_format)
141                                 break;
142                 }
143                 if (i == plane->format_count)
144                         return -EINVAL;
145
146                 if (coords->src_w > fb_width ||
147                     coords->src_x > fb_width - coords->src_w ||
148                     coords->src_h > fb_height ||
149                     coords->src_y > fb_height - coords->src_h)
150                         return -ENOSPC;
151
152                 if (coords->crtc_w > INT_MAX ||
153                     coords->crtc_x > INT_MAX - (int32_t) coords->crtc_w ||
154                     coords->crtc_h > INT_MAX ||
155                     coords->crtc_y > INT_MAX - (int32_t) coords->crtc_h)
156                         return -ERANGE;
157
158                 if (fb->width < 3 || fb->height < 3 || fb->pitches[0] > 16384)
159                         return -EINVAL;
160         }
161
162         if (crtc) {
163                 const struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
164
165                 /* Don't modify another pipe's plane */
166                 if (intel_plane->pipe != intel_crtc->pipe)
167                         return -EINVAL;
168         }
169
170         if (!fb || !crtc || !crtc->enabled) {
171                 coords->visible = false;
172                 return 0;
173         }
174
175         intel_clip_plane(plane, crtc, fb, coords);
176
177         /* Check size restrictions when scaling */
178         if (coords->visible && (coords->src_w != coords->crtc_w || coords->src_h != coords->crtc_h)) {
179                 unsigned int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
180
181                 if (coords->src_w > 2048 || coords->src_h > 2048 ||
182                     coords->src_w * cpp > 4096 - 64 || fb->pitches[0] > 4096)
183                         return -EINVAL;
184         }
185
186         return 0;
187 }
188
189 static void
190 ivb_update_plane(struct drm_plane *plane,
191                  struct drm_framebuffer *fb,
192                  const struct intel_plane_coords *coords)
193 {
194         struct drm_device *dev = plane->dev;
195         struct drm_i915_private *dev_priv = dev->dev_private;
196         struct intel_plane *intel_plane = to_intel_plane(plane);
197         const struct drm_i915_gem_object *obj = to_intel_framebuffer(fb)->obj;
198         int crtc_x = coords->crtc_x;
199         int crtc_y = coords->crtc_y;
200         unsigned int crtc_w = coords->crtc_w;
201         unsigned int crtc_h = coords->crtc_h;
202         uint32_t x = coords->src_x;
203         uint32_t y = coords->src_y;
204         uint32_t src_w = coords->src_w;
205         uint32_t src_h = coords->src_h;
206         int pipe = intel_plane->pipe;
207         u32 sprctl, sprscale = 0;
208         int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
209
210         sprctl = I915_READ(SPRCTL(pipe));
211
212         /* Mask out pixel format bits in case we change it */
213         sprctl &= ~SPRITE_PIXFORMAT_MASK;
214         sprctl &= ~SPRITE_RGB_ORDER_RGBX;
215         sprctl &= ~SPRITE_YUV_BYTE_ORDER_MASK;
216         sprctl &= ~SPRITE_TILED;
217
218         switch (fb->pixel_format) {
219         case DRM_FORMAT_XBGR8888:
220                 sprctl |= SPRITE_FORMAT_RGBX888;
221                 break;
222         case DRM_FORMAT_XRGB8888:
223                 sprctl |= SPRITE_FORMAT_RGBX888 | SPRITE_RGB_ORDER_RGBX;
224                 break;
225         case DRM_FORMAT_YUYV:
226                 sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YUYV;
227                 break;
228         case DRM_FORMAT_YVYU:
229                 sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YVYU;
230                 break;
231         case DRM_FORMAT_UYVY:
232                 sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_UYVY;
233                 break;
234         case DRM_FORMAT_VYUY:
235                 sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_VYUY;
236                 break;
237         default:
238                 BUG();
239         }
240
241         if (obj->tiling_mode != I915_TILING_NONE)
242                 sprctl |= SPRITE_TILED;
243
244         /* must disable */
245         sprctl |= SPRITE_TRICKLE_FEED_DISABLE;
246         sprctl |= SPRITE_ENABLE;
247
248         /* Sizes are 0 based */
249         src_w--;
250         src_h--;
251         crtc_w--;
252         crtc_h--;
253
254         intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size);
255
256         /*
257          * IVB workaround: must disable low power watermarks for at least
258          * one frame before enabling scaling.  LP watermarks can be re-enabled
259          * when scaling is disabled.
260          */
261         if (crtc_w != src_w || crtc_h != src_h) {
262                 if (!dev_priv->sprite_scaling_enabled) {
263                         dev_priv->sprite_scaling_enabled = true;
264                         intel_update_watermarks(dev);
265                         intel_wait_for_vblank(dev, pipe);
266                 }
267                 sprscale = SPRITE_SCALE_ENABLE | (src_w << 16) | src_h;
268         } else {
269                 if (dev_priv->sprite_scaling_enabled) {
270                         dev_priv->sprite_scaling_enabled = false;
271                         /* potentially re-enable LP watermarks */
272                         intel_update_watermarks(dev);
273                 }
274         }
275
276         I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]);
277         I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x);
278         if (obj->tiling_mode != I915_TILING_NONE) {
279                 y += fb->offsets[0] / fb->pitches[0];
280                 x += fb->offsets[0] % fb->pitches[0] / pixel_size;
281
282                 I915_WRITE(SPRTILEOFF(pipe), (y << 16) | x);
283         } else {
284                 unsigned long offset;
285
286                 offset = fb->offsets[0] + y * fb->pitches[0] + x * pixel_size;
287                 I915_WRITE(SPRLINOFF(pipe), offset);
288         }
289         I915_WRITE(SPRSIZE(pipe), (crtc_h << 16) | crtc_w);
290         I915_WRITE(SPRSCALE(pipe), sprscale);
291         I915_WRITE(SPRCTL(pipe), sprctl);
292         I915_MODIFY_DISPBASE(SPRSURF(pipe), obj->gtt_offset);
293         POSTING_READ(SPRSURF(pipe));
294 }
295
296 static void
297 ivb_disable_plane(struct drm_plane *plane)
298 {
299         struct drm_device *dev = plane->dev;
300         struct drm_i915_private *dev_priv = dev->dev_private;
301         struct intel_plane *intel_plane = to_intel_plane(plane);
302         int pipe = intel_plane->pipe;
303
304         I915_WRITE(SPRCTL(pipe), I915_READ(SPRCTL(pipe)) & ~SPRITE_ENABLE);
305         /* Can't leave the scaler enabled... */
306         I915_WRITE(SPRSCALE(pipe), 0);
307         /* Activate double buffered register update */
308         I915_MODIFY_DISPBASE(SPRSURF(pipe), 0);
309         POSTING_READ(SPRSURF(pipe));
310
311         dev_priv->sprite_scaling_enabled = false;
312         intel_update_watermarks(dev);
313 }
314
315 static int
316 ivb_update_colorkey(struct drm_plane *plane,
317                     struct drm_intel_sprite_colorkey *key)
318 {
319         struct drm_device *dev = plane->dev;
320         struct drm_i915_private *dev_priv = dev->dev_private;
321         struct intel_plane *intel_plane;
322         u32 sprctl;
323         int ret = 0;
324
325         intel_plane = to_intel_plane(plane);
326
327         I915_WRITE(SPRKEYVAL(intel_plane->pipe), key->min_value);
328         I915_WRITE(SPRKEYMAX(intel_plane->pipe), key->max_value);
329         I915_WRITE(SPRKEYMSK(intel_plane->pipe), key->channel_mask);
330
331         sprctl = I915_READ(SPRCTL(intel_plane->pipe));
332         sprctl &= ~(SPRITE_SOURCE_KEY | SPRITE_DEST_KEY);
333         if (key->flags & I915_SET_COLORKEY_DESTINATION)
334                 sprctl |= SPRITE_DEST_KEY;
335         else if (key->flags & I915_SET_COLORKEY_SOURCE)
336                 sprctl |= SPRITE_SOURCE_KEY;
337         I915_WRITE(SPRCTL(intel_plane->pipe), sprctl);
338
339         POSTING_READ(SPRKEYMSK(intel_plane->pipe));
340
341         return ret;
342 }
343
344 static void
345 ivb_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key)
346 {
347         struct drm_device *dev = plane->dev;
348         struct drm_i915_private *dev_priv = dev->dev_private;
349         struct intel_plane *intel_plane;
350         u32 sprctl;
351
352         intel_plane = to_intel_plane(plane);
353
354         key->min_value = I915_READ(SPRKEYVAL(intel_plane->pipe));
355         key->max_value = I915_READ(SPRKEYMAX(intel_plane->pipe));
356         key->channel_mask = I915_READ(SPRKEYMSK(intel_plane->pipe));
357         key->flags = 0;
358
359         sprctl = I915_READ(SPRCTL(intel_plane->pipe));
360
361         if (sprctl & SPRITE_DEST_KEY)
362                 key->flags = I915_SET_COLORKEY_DESTINATION;
363         else if (sprctl & SPRITE_SOURCE_KEY)
364                 key->flags = I915_SET_COLORKEY_SOURCE;
365         else
366                 key->flags = I915_SET_COLORKEY_NONE;
367 }
368
369 static void
370 ilk_update_plane(struct drm_plane *plane,
371                  struct drm_framebuffer *fb,
372                  const struct intel_plane_coords *coords)
373 {
374         struct drm_device *dev = plane->dev;
375         struct drm_i915_private *dev_priv = dev->dev_private;
376         struct intel_plane *intel_plane = to_intel_plane(plane);
377         const struct drm_i915_gem_object *obj = to_intel_framebuffer(fb)->obj;
378         int crtc_x = coords->crtc_x;
379         int crtc_y = coords->crtc_y;
380         unsigned int crtc_w = coords->crtc_w;
381         unsigned int crtc_h = coords->crtc_h;
382         uint32_t x = coords->src_x;
383         uint32_t y = coords->src_y;
384         uint32_t src_w = coords->src_w;
385         uint32_t src_h = coords->src_h;
386         int pipe = intel_plane->pipe;
387         u32 dvscntr, dvsscale;
388         int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
389
390         dvscntr = I915_READ(DVSCNTR(pipe));
391
392         /* Mask out pixel format bits in case we change it */
393         dvscntr &= ~DVS_PIXFORMAT_MASK;
394         dvscntr &= ~DVS_RGB_ORDER_XBGR;
395         dvscntr &= ~DVS_YUV_BYTE_ORDER_MASK;
396
397         switch (fb->pixel_format) {
398         case DRM_FORMAT_XBGR8888:
399                 dvscntr |= DVS_FORMAT_RGBX888 | DVS_RGB_ORDER_XBGR;
400                 break;
401         case DRM_FORMAT_XRGB8888:
402                 dvscntr |= DVS_FORMAT_RGBX888;
403                 break;
404         case DRM_FORMAT_YUYV:
405                 dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YUYV;
406                 break;
407         case DRM_FORMAT_YVYU:
408                 dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YVYU;
409                 break;
410         case DRM_FORMAT_UYVY:
411                 dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_UYVY;
412                 break;
413         case DRM_FORMAT_VYUY:
414                 dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_VYUY;
415                 break;
416         default:
417                 BUG();
418         }
419
420         if (obj->tiling_mode != I915_TILING_NONE)
421                 dvscntr |= DVS_TILED;
422
423         if (IS_GEN6(dev))
424                 dvscntr |= DVS_TRICKLE_FEED_DISABLE; /* must disable */
425         dvscntr |= DVS_ENABLE;
426
427         /* Sizes are 0 based */
428         src_w--;
429         src_h--;
430         crtc_w--;
431         crtc_h--;
432
433         intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size);
434
435         dvsscale = 0;
436         if (IS_GEN5(dev) || crtc_w != src_w || crtc_h != src_h)
437                 dvsscale = DVS_SCALE_ENABLE | (src_w << 16) | src_h;
438
439         I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]);
440         I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x);
441         if (obj->tiling_mode != I915_TILING_NONE) {
442                 y += fb->offsets[0] / fb->pitches[0];
443                 x += fb->offsets[0] % fb->pitches[0] / pixel_size;
444
445                 I915_WRITE(DVSTILEOFF(pipe), (y << 16) | x);
446         } else {
447                 unsigned long offset;
448
449                 offset = fb->offsets[0] + y * fb->pitches[0] + x * pixel_size;
450                 I915_WRITE(DVSLINOFF(pipe), offset);
451         }
452         I915_WRITE(DVSSIZE(pipe), (crtc_h << 16) | crtc_w);
453         I915_WRITE(DVSSCALE(pipe), dvsscale);
454         I915_WRITE(DVSCNTR(pipe), dvscntr);
455         I915_MODIFY_DISPBASE(DVSSURF(pipe), obj->gtt_offset);
456         POSTING_READ(DVSSURF(pipe));
457 }
458
459 static void
460 ilk_disable_plane(struct drm_plane *plane)
461 {
462         struct drm_device *dev = plane->dev;
463         struct drm_i915_private *dev_priv = dev->dev_private;
464         struct intel_plane *intel_plane = to_intel_plane(plane);
465         int pipe = intel_plane->pipe;
466
467         I915_WRITE(DVSCNTR(pipe), I915_READ(DVSCNTR(pipe)) & ~DVS_ENABLE);
468         /* Disable the scaler */
469         I915_WRITE(DVSSCALE(pipe), 0);
470         /* Flush double buffered register updates */
471         I915_MODIFY_DISPBASE(DVSSURF(pipe), 0);
472         POSTING_READ(DVSSURF(pipe));
473 }
474
475 static void
476 intel_enable_primary(struct drm_crtc *crtc)
477 {
478         struct drm_device *dev = crtc->dev;
479         struct drm_i915_private *dev_priv = dev->dev_private;
480         struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
481         int reg = DSPCNTR(intel_crtc->plane);
482
483         if (!intel_crtc->primary_disabled)
484                 return;
485
486         intel_crtc->primary_disabled = false;
487         intel_update_fbc(dev);
488
489         I915_WRITE(reg, I915_READ(reg) | DISPLAY_PLANE_ENABLE);
490 }
491
492 static void
493 intel_disable_primary(struct drm_crtc *crtc)
494 {
495         struct drm_device *dev = crtc->dev;
496         struct drm_i915_private *dev_priv = dev->dev_private;
497         struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
498         int reg = DSPCNTR(intel_crtc->plane);
499
500         if (intel_crtc->primary_disabled)
501                 return;
502
503         I915_WRITE(reg, I915_READ(reg) & ~DISPLAY_PLANE_ENABLE);
504
505         intel_crtc->primary_disabled = true;
506         intel_update_fbc(dev);
507 }
508
509 static int
510 ilk_update_colorkey(struct drm_plane *plane,
511                     struct drm_intel_sprite_colorkey *key)
512 {
513         struct drm_device *dev = plane->dev;
514         struct drm_i915_private *dev_priv = dev->dev_private;
515         struct intel_plane *intel_plane;
516         u32 dvscntr;
517         int ret = 0;
518
519         intel_plane = to_intel_plane(plane);
520
521         I915_WRITE(DVSKEYVAL(intel_plane->pipe), key->min_value);
522         I915_WRITE(DVSKEYMAX(intel_plane->pipe), key->max_value);
523         I915_WRITE(DVSKEYMSK(intel_plane->pipe), key->channel_mask);
524
525         dvscntr = I915_READ(DVSCNTR(intel_plane->pipe));
526         dvscntr &= ~(DVS_SOURCE_KEY | DVS_DEST_KEY);
527         if (key->flags & I915_SET_COLORKEY_DESTINATION)
528                 dvscntr |= DVS_DEST_KEY;
529         else if (key->flags & I915_SET_COLORKEY_SOURCE)
530                 dvscntr |= DVS_SOURCE_KEY;
531         I915_WRITE(DVSCNTR(intel_plane->pipe), dvscntr);
532
533         POSTING_READ(DVSKEYMSK(intel_plane->pipe));
534
535         return ret;
536 }
537
538 static void
539 ilk_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key)
540 {
541         struct drm_device *dev = plane->dev;
542         struct drm_i915_private *dev_priv = dev->dev_private;
543         struct intel_plane *intel_plane;
544         u32 dvscntr;
545
546         intel_plane = to_intel_plane(plane);
547
548         key->min_value = I915_READ(DVSKEYVAL(intel_plane->pipe));
549         key->max_value = I915_READ(DVSKEYMAX(intel_plane->pipe));
550         key->channel_mask = I915_READ(DVSKEYMSK(intel_plane->pipe));
551         key->flags = 0;
552
553         dvscntr = I915_READ(DVSCNTR(intel_plane->pipe));
554
555         if (dvscntr & DVS_DEST_KEY)
556                 key->flags = I915_SET_COLORKEY_DESTINATION;
557         else if (dvscntr & DVS_SOURCE_KEY)
558                 key->flags = I915_SET_COLORKEY_SOURCE;
559         else
560                 key->flags = I915_SET_COLORKEY_NONE;
561 }
562
563 void
564 _intel_disable_plane(struct drm_plane *plane, bool unpin)
565 {
566         struct drm_device *dev = plane->dev;
567         struct intel_plane *intel_plane = to_intel_plane(plane);
568         int ret = 0;
569
570         if (plane->crtc)
571                 intel_enable_primary(plane->crtc);
572
573         intel_plane->disable_plane(plane);
574
575         if (!unpin || !intel_plane->obj)
576                 goto out;
577
578         mutex_lock(&dev->struct_mutex);
579         intel_unpin_fb_obj(intel_plane->obj);
580         intel_plane->obj = NULL;
581         mutex_unlock(&dev->struct_mutex);
582 out:
583
584         return ret;
585 }
586
587 static int
588 intel_disable_plane(struct drm_plane *plane)
589 {
590         _intel_disable_plane(plane, true);
591
592         return 0;
593 }
594
595 int
596 intel_commit_plane(struct drm_plane *plane,
597                    struct drm_crtc *crtc,
598                    struct drm_framebuffer *fb,
599                    const struct intel_plane_coords *coords,
600                    bool pin)
601 {
602         struct drm_device *dev = plane->dev;
603         struct drm_i915_private *dev_priv = dev->dev_private;
604         struct intel_plane *intel_plane = to_intel_plane(plane);
605         struct intel_framebuffer *intel_fb;
606         struct drm_i915_gem_object *obj;
607         struct drm_i915_gem_object *old_obj = intel_plane->obj;
608         int pipe = intel_plane->pipe;
609         int ret;
610         int primary_w, primary_h;
611         bool disable_primary = false;
612
613         if (!coords->visible) {
614                 intel_disable_plane(plane);
615                 return 0;
616         }
617
618         /* FIXME this should happen anymore I suppose */
619         /* Pipe must be running... */
620         if (!(I915_READ(PIPECONF(pipe)) & PIPECONF_ENABLE))
621                 return 0;
622
623         intel_fb = to_intel_framebuffer(fb);
624         obj = intel_fb->obj;
625         primary_w = crtc->mode.hdisplay;
626         primary_h = crtc->mode.vdisplay;
627
628         /*
629          * If the sprite is completely covering the primary plane,
630          * we can disable the primary and save power.
631          */
632         if ((coords->crtc_x == 0) && (coords->crtc_y == 0) &&
633             (coords->crtc_w == primary_w) && (coords->crtc_h == primary_h))
634                 disable_primary = true;
635
636         mutex_lock(&dev->struct_mutex);
637
638         if (pin) {
639                 ret = intel_pin_and_fence_fb_obj(dev, obj, NULL);
640                 if (ret)
641                         goto out_unlock;
642
643                 intel_plane->obj = obj;
644         }
645
646         /*
647          * Be sure to re-enable the primary before the sprite is no longer
648          * covering it fully.
649          */
650         if (!disable_primary)
651                 intel_enable_primary(crtc);
652
653         if (coords->visible) {
654                 intel_plane->update_plane(plane, fb, coords);
655
656                 if (disable_primary)
657                         intel_disable_primary(crtc);
658         } else
659                 intel_plane->disable_plane(plane);
660
661         /* Unpin old obj after new one is active to avoid ugliness */
662         if (pin && old_obj) {
663                 /*
664                  * It's fairly common to simply update the position of
665                  * an existing object.  In that case, we don't need to
666                  * wait for vblank to avoid ugliness, we only need to
667                  * do the pin & ref bookkeeping.
668                  */
669                 if (old_obj != obj) {
670                         mutex_unlock(&dev->struct_mutex);
671                         intel_wait_for_vblank(dev, to_intel_crtc(crtc)->pipe);
672                         mutex_lock(&dev->struct_mutex);
673                 }
674                 intel_unpin_fb_obj(old_obj);
675         }
676
677 out_unlock:
678         mutex_unlock(&dev->struct_mutex);
679         return ret;
680 }
681
682 static int
683 intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
684                    struct drm_framebuffer *fb, int crtc_x, int crtc_y,
685                    unsigned int crtc_w, unsigned int crtc_h,
686                    uint32_t src_x, uint32_t src_y,
687                    uint32_t src_w, uint32_t src_h)
688 {
689         int ret;
690         struct intel_plane_coords coords = {
691                 .crtc_x = crtc_x,
692                 .crtc_y = crtc_y,
693                 .crtc_w = crtc_w,
694                 .crtc_h = crtc_h,
695                 .src_x = src_x,
696                 .src_y = src_y,
697                 .src_w = src_w,
698                 .src_h = src_h,
699         };
700
701         ret = intel_check_plane(plane, crtc, fb, &coords);
702         if (ret)
703                 return ret;
704
705         intel_commit_plane(plane, crtc, fb, &coords, true);
706
707         return 0;
708 }
709
710 static void intel_destroy_plane(struct drm_plane *plane)
711 {
712         struct intel_plane *intel_plane = to_intel_plane(plane);
713         intel_disable_plane(plane);
714         drm_plane_cleanup(plane);
715         kfree(intel_plane);
716 }
717
718 int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
719                               struct drm_file *file_priv)
720 {
721         struct drm_intel_sprite_colorkey *set = data;
722         struct drm_mode_object *obj;
723         struct drm_plane *plane;
724         struct intel_plane *intel_plane;
725         int ret = 0;
726
727         if (!drm_core_check_feature(dev, DRIVER_MODESET))
728                 return -ENODEV;
729
730         /* Make sure we don't try to enable both src & dest simultaneously */
731         if ((set->flags & (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) == (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE))
732                 return -EINVAL;
733
734         mutex_lock(&dev->mode_config.mutex);
735
736         obj = drm_mode_object_find(dev, set->plane_id, DRM_MODE_OBJECT_PLANE);
737         if (!obj) {
738                 ret = -EINVAL;
739                 goto out_unlock;
740         }
741
742         plane = obj_to_plane(obj);
743         intel_plane = to_intel_plane(plane);
744         ret = intel_plane->update_colorkey(plane, set);
745
746 out_unlock:
747         mutex_unlock(&dev->mode_config.mutex);
748         return ret;
749 }
750
751 int intel_sprite_get_colorkey(struct drm_device *dev, void *data,
752                               struct drm_file *file_priv)
753 {
754         struct drm_intel_sprite_colorkey *get = data;
755         struct drm_mode_object *obj;
756         struct drm_plane *plane;
757         struct intel_plane *intel_plane;
758         int ret = 0;
759
760         if (!drm_core_check_feature(dev, DRIVER_MODESET))
761                 return -ENODEV;
762
763         mutex_lock(&dev->mode_config.mutex);
764
765         obj = drm_mode_object_find(dev, get->plane_id, DRM_MODE_OBJECT_PLANE);
766         if (!obj) {
767                 ret = -EINVAL;
768                 goto out_unlock;
769         }
770
771         plane = obj_to_plane(obj);
772         intel_plane = to_intel_plane(plane);
773         intel_plane->get_colorkey(plane, get);
774
775 out_unlock:
776         mutex_unlock(&dev->mode_config.mutex);
777         return ret;
778 }
779
780 static const struct drm_plane_funcs intel_plane_funcs = {
781         .update_plane = intel_update_plane,
782         .disable_plane = intel_disable_plane,
783         .destroy = intel_destroy_plane,
784 };
785
786 static uint32_t ilk_plane_formats[] = {
787         DRM_FORMAT_XRGB8888,
788         DRM_FORMAT_YUYV,
789         DRM_FORMAT_YVYU,
790         DRM_FORMAT_UYVY,
791         DRM_FORMAT_VYUY,
792 };
793
794 static uint32_t snb_plane_formats[] = {
795         DRM_FORMAT_XBGR8888,
796         DRM_FORMAT_XRGB8888,
797         DRM_FORMAT_YUYV,
798         DRM_FORMAT_YVYU,
799         DRM_FORMAT_UYVY,
800         DRM_FORMAT_VYUY,
801 };
802
803 int
804 intel_plane_init(struct drm_device *dev, enum pipe pipe)
805 {
806         struct intel_plane *intel_plane;
807         unsigned long possible_crtcs;
808         const uint32_t *plane_formats;
809         int num_plane_formats;
810         int ret;
811
812         if (INTEL_INFO(dev)->gen < 5)
813                 return -ENODEV;
814
815         intel_plane = kzalloc(sizeof(struct intel_plane), GFP_KERNEL);
816         if (!intel_plane)
817                 return -ENOMEM;
818
819         switch (INTEL_INFO(dev)->gen) {
820         case 5:
821         case 6:
822                 intel_plane->max_downscale = 16;
823                 intel_plane->update_plane = ilk_update_plane;
824                 intel_plane->disable_plane = ilk_disable_plane;
825                 intel_plane->update_colorkey = ilk_update_colorkey;
826                 intel_plane->get_colorkey = ilk_get_colorkey;
827
828                 if (IS_GEN6(dev)) {
829                         plane_formats = snb_plane_formats;
830                         num_plane_formats = ARRAY_SIZE(snb_plane_formats);
831                 } else {
832                         plane_formats = ilk_plane_formats;
833                         num_plane_formats = ARRAY_SIZE(ilk_plane_formats);
834                 }
835                 break;
836
837         case 7:
838                 intel_plane->max_downscale = 2;
839                 intel_plane->update_plane = ivb_update_plane;
840                 intel_plane->disable_plane = ivb_disable_plane;
841                 intel_plane->update_colorkey = ivb_update_colorkey;
842                 intel_plane->get_colorkey = ivb_get_colorkey;
843
844                 plane_formats = snb_plane_formats;
845                 num_plane_formats = ARRAY_SIZE(snb_plane_formats);
846                 break;
847
848         default:
849                 kfree(intel_plane);
850                 return -ENODEV;
851         }
852
853         intel_plane->pipe = pipe;
854         possible_crtcs = (1 << pipe);
855         ret = drm_plane_init(dev, &intel_plane->base, possible_crtcs,
856                              &intel_plane_funcs,
857                              plane_formats, num_plane_formats,
858                              false);
859         if (ret)
860                 kfree(intel_plane);
861
862         return ret;
863 }