linux/drivers/gpu/drm/i915/intel_sprite.c
<<
>>
Prefs
   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 <drm/drmP.h>
  33#include <drm/drm_crtc.h>
  34#include <drm/drm_fourcc.h>
  35#include "intel_drv.h"
  36#include <drm/i915_drm.h>
  37#include "i915_drv.h"
  38
  39static void
  40ivb_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        unsigned long sprsurf_offset, linear_offset;
  52        int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
  53        bool scaling_was_enabled = dev_priv->sprite_scaling_enabled;
  54
  55        sprctl = I915_READ(SPRCTL(pipe));
  56
  57        /* Mask out pixel format bits in case we change it */
  58        sprctl &= ~SPRITE_PIXFORMAT_MASK;
  59        sprctl &= ~SPRITE_RGB_ORDER_RGBX;
  60        sprctl &= ~SPRITE_YUV_BYTE_ORDER_MASK;
  61        sprctl &= ~SPRITE_TILED;
  62
  63        switch (fb->pixel_format) {
  64        case DRM_FORMAT_XBGR8888:
  65                sprctl |= SPRITE_FORMAT_RGBX888 | SPRITE_RGB_ORDER_RGBX;
  66                break;
  67        case DRM_FORMAT_XRGB8888:
  68                sprctl |= SPRITE_FORMAT_RGBX888;
  69                break;
  70        case DRM_FORMAT_YUYV:
  71                sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YUYV;
  72                break;
  73        case DRM_FORMAT_YVYU:
  74                sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YVYU;
  75                break;
  76        case DRM_FORMAT_UYVY:
  77                sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_UYVY;
  78                break;
  79        case DRM_FORMAT_VYUY:
  80                sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_VYUY;
  81                break;
  82        default:
  83                BUG();
  84        }
  85
  86        if (obj->tiling_mode != I915_TILING_NONE)
  87                sprctl |= SPRITE_TILED;
  88
  89        /* must disable */
  90        sprctl |= SPRITE_TRICKLE_FEED_DISABLE;
  91        sprctl |= SPRITE_ENABLE;
  92
  93        if (IS_HASWELL(dev))
  94                sprctl |= SPRITE_PIPE_CSC_ENABLE;
  95
  96        /* Sizes are 0 based */
  97        src_w--;
  98        src_h--;
  99        crtc_w--;
 100        crtc_h--;
 101
 102        intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size);
 103
 104        /*
 105         * IVB workaround: must disable low power watermarks for at least
 106         * one frame before enabling scaling.  LP watermarks can be re-enabled
 107         * when scaling is disabled.
 108         */
 109        if (crtc_w != src_w || crtc_h != src_h) {
 110                dev_priv->sprite_scaling_enabled |= 1 << pipe;
 111
 112                if (!scaling_was_enabled) {
 113                        intel_update_watermarks(dev);
 114                        intel_wait_for_vblank(dev, pipe);
 115                }
 116                sprscale = SPRITE_SCALE_ENABLE | (src_w << 16) | src_h;
 117        } else
 118                dev_priv->sprite_scaling_enabled &= ~(1 << pipe);
 119
 120        I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]);
 121        I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x);
 122
 123        linear_offset = y * fb->pitches[0] + x * pixel_size;
 124        sprsurf_offset =
 125                intel_gen4_compute_page_offset(&x, &y, obj->tiling_mode,
 126                                               pixel_size, fb->pitches[0]);
 127        linear_offset -= sprsurf_offset;
 128
 129        /* HSW consolidates SPRTILEOFF and SPRLINOFF into a single SPROFFSET
 130         * register */
 131        if (IS_HASWELL(dev))
 132                I915_WRITE(SPROFFSET(pipe), (y << 16) | x);
 133        else if (obj->tiling_mode != I915_TILING_NONE)
 134                I915_WRITE(SPRTILEOFF(pipe), (y << 16) | x);
 135        else
 136                I915_WRITE(SPRLINOFF(pipe), linear_offset);
 137
 138        I915_WRITE(SPRSIZE(pipe), (crtc_h << 16) | crtc_w);
 139        if (intel_plane->can_scale)
 140                I915_WRITE(SPRSCALE(pipe), sprscale);
 141        I915_WRITE(SPRCTL(pipe), sprctl);
 142        I915_MODIFY_DISPBASE(SPRSURF(pipe), obj->gtt_offset + sprsurf_offset);
 143        POSTING_READ(SPRSURF(pipe));
 144
 145        /* potentially re-enable LP watermarks */
 146        if (scaling_was_enabled && !dev_priv->sprite_scaling_enabled)
 147                intel_update_watermarks(dev);
 148}
 149
 150static void
 151ivb_disable_plane(struct drm_plane *plane)
 152{
 153        struct drm_device *dev = plane->dev;
 154        struct drm_i915_private *dev_priv = dev->dev_private;
 155        struct intel_plane *intel_plane = to_intel_plane(plane);
 156        int pipe = intel_plane->pipe;
 157        bool scaling_was_enabled = dev_priv->sprite_scaling_enabled;
 158
 159        I915_WRITE(SPRCTL(pipe), I915_READ(SPRCTL(pipe)) & ~SPRITE_ENABLE);
 160        /* Can't leave the scaler enabled... */
 161        if (intel_plane->can_scale)
 162                I915_WRITE(SPRSCALE(pipe), 0);
 163        /* Activate double buffered register update */
 164        I915_MODIFY_DISPBASE(SPRSURF(pipe), 0);
 165        POSTING_READ(SPRSURF(pipe));
 166
 167        dev_priv->sprite_scaling_enabled &= ~(1 << pipe);
 168
 169        /* potentially re-enable LP watermarks */
 170        if (scaling_was_enabled && !dev_priv->sprite_scaling_enabled)
 171                intel_update_watermarks(dev);
 172}
 173
 174static int
 175ivb_update_colorkey(struct drm_plane *plane,
 176                    struct drm_intel_sprite_colorkey *key)
 177{
 178        struct drm_device *dev = plane->dev;
 179        struct drm_i915_private *dev_priv = dev->dev_private;
 180        struct intel_plane *intel_plane;
 181        u32 sprctl;
 182        int ret = 0;
 183
 184        intel_plane = to_intel_plane(plane);
 185
 186        I915_WRITE(SPRKEYVAL(intel_plane->pipe), key->min_value);
 187        I915_WRITE(SPRKEYMAX(intel_plane->pipe), key->max_value);
 188        I915_WRITE(SPRKEYMSK(intel_plane->pipe), key->channel_mask);
 189
 190        sprctl = I915_READ(SPRCTL(intel_plane->pipe));
 191        sprctl &= ~(SPRITE_SOURCE_KEY | SPRITE_DEST_KEY);
 192        if (key->flags & I915_SET_COLORKEY_DESTINATION)
 193                sprctl |= SPRITE_DEST_KEY;
 194        else if (key->flags & I915_SET_COLORKEY_SOURCE)
 195                sprctl |= SPRITE_SOURCE_KEY;
 196        I915_WRITE(SPRCTL(intel_plane->pipe), sprctl);
 197
 198        POSTING_READ(SPRKEYMSK(intel_plane->pipe));
 199
 200        return ret;
 201}
 202
 203static void
 204ivb_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key)
 205{
 206        struct drm_device *dev = plane->dev;
 207        struct drm_i915_private *dev_priv = dev->dev_private;
 208        struct intel_plane *intel_plane;
 209        u32 sprctl;
 210
 211        intel_plane = to_intel_plane(plane);
 212
 213        key->min_value = I915_READ(SPRKEYVAL(intel_plane->pipe));
 214        key->max_value = I915_READ(SPRKEYMAX(intel_plane->pipe));
 215        key->channel_mask = I915_READ(SPRKEYMSK(intel_plane->pipe));
 216        key->flags = 0;
 217
 218        sprctl = I915_READ(SPRCTL(intel_plane->pipe));
 219
 220        if (sprctl & SPRITE_DEST_KEY)
 221                key->flags = I915_SET_COLORKEY_DESTINATION;
 222        else if (sprctl & SPRITE_SOURCE_KEY)
 223                key->flags = I915_SET_COLORKEY_SOURCE;
 224        else
 225                key->flags = I915_SET_COLORKEY_NONE;
 226}
 227
 228static void
 229ilk_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
 230                 struct drm_i915_gem_object *obj, int crtc_x, int crtc_y,
 231                 unsigned int crtc_w, unsigned int crtc_h,
 232                 uint32_t x, uint32_t y,
 233                 uint32_t src_w, uint32_t src_h)
 234{
 235        struct drm_device *dev = plane->dev;
 236        struct drm_i915_private *dev_priv = dev->dev_private;
 237        struct intel_plane *intel_plane = to_intel_plane(plane);
 238        int pipe = intel_plane->pipe;
 239        unsigned long dvssurf_offset, linear_offset;
 240        u32 dvscntr, dvsscale;
 241        int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
 242
 243        dvscntr = I915_READ(DVSCNTR(pipe));
 244
 245        /* Mask out pixel format bits in case we change it */
 246        dvscntr &= ~DVS_PIXFORMAT_MASK;
 247        dvscntr &= ~DVS_RGB_ORDER_XBGR;
 248        dvscntr &= ~DVS_YUV_BYTE_ORDER_MASK;
 249        dvscntr &= ~DVS_TILED;
 250
 251        switch (fb->pixel_format) {
 252        case DRM_FORMAT_XBGR8888:
 253                dvscntr |= DVS_FORMAT_RGBX888 | DVS_RGB_ORDER_XBGR;
 254                break;
 255        case DRM_FORMAT_XRGB8888:
 256                dvscntr |= DVS_FORMAT_RGBX888;
 257                break;
 258        case DRM_FORMAT_YUYV:
 259                dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YUYV;
 260                break;
 261        case DRM_FORMAT_YVYU:
 262                dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YVYU;
 263                break;
 264        case DRM_FORMAT_UYVY:
 265                dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_UYVY;
 266                break;
 267        case DRM_FORMAT_VYUY:
 268                dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_VYUY;
 269                break;
 270        default:
 271                BUG();
 272        }
 273
 274        if (obj->tiling_mode != I915_TILING_NONE)
 275                dvscntr |= DVS_TILED;
 276
 277        if (IS_GEN6(dev))
 278                dvscntr |= DVS_TRICKLE_FEED_DISABLE; /* must disable */
 279        dvscntr |= DVS_ENABLE;
 280
 281        /* Sizes are 0 based */
 282        src_w--;
 283        src_h--;
 284        crtc_w--;
 285        crtc_h--;
 286
 287        intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size);
 288
 289        dvsscale = 0;
 290        if (IS_GEN5(dev) || crtc_w != src_w || crtc_h != src_h)
 291                dvsscale = DVS_SCALE_ENABLE | (src_w << 16) | src_h;
 292
 293        I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]);
 294        I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x);
 295
 296        linear_offset = y * fb->pitches[0] + x * pixel_size;
 297        dvssurf_offset =
 298                intel_gen4_compute_page_offset(&x, &y, obj->tiling_mode,
 299                                               pixel_size, fb->pitches[0]);
 300        linear_offset -= dvssurf_offset;
 301
 302        if (obj->tiling_mode != I915_TILING_NONE)
 303                I915_WRITE(DVSTILEOFF(pipe), (y << 16) | x);
 304        else
 305                I915_WRITE(DVSLINOFF(pipe), linear_offset);
 306
 307        I915_WRITE(DVSSIZE(pipe), (crtc_h << 16) | crtc_w);
 308        I915_WRITE(DVSSCALE(pipe), dvsscale);
 309        I915_WRITE(DVSCNTR(pipe), dvscntr);
 310        I915_MODIFY_DISPBASE(DVSSURF(pipe), obj->gtt_offset + dvssurf_offset);
 311        POSTING_READ(DVSSURF(pipe));
 312}
 313
 314static void
 315ilk_disable_plane(struct drm_plane *plane)
 316{
 317        struct drm_device *dev = plane->dev;
 318        struct drm_i915_private *dev_priv = dev->dev_private;
 319        struct intel_plane *intel_plane = to_intel_plane(plane);
 320        int pipe = intel_plane->pipe;
 321
 322        I915_WRITE(DVSCNTR(pipe), I915_READ(DVSCNTR(pipe)) & ~DVS_ENABLE);
 323        /* Disable the scaler */
 324        I915_WRITE(DVSSCALE(pipe), 0);
 325        /* Flush double buffered register updates */
 326        I915_MODIFY_DISPBASE(DVSSURF(pipe), 0);
 327        POSTING_READ(DVSSURF(pipe));
 328}
 329
 330static void
 331intel_enable_primary(struct drm_crtc *crtc)
 332{
 333        struct drm_device *dev = crtc->dev;
 334        struct drm_i915_private *dev_priv = dev->dev_private;
 335        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 336        int reg = DSPCNTR(intel_crtc->plane);
 337
 338        if (!intel_crtc->primary_disabled)
 339                return;
 340
 341        intel_crtc->primary_disabled = false;
 342        intel_update_fbc(dev);
 343
 344        I915_WRITE(reg, I915_READ(reg) | DISPLAY_PLANE_ENABLE);
 345}
 346
 347static void
 348intel_disable_primary(struct drm_crtc *crtc)
 349{
 350        struct drm_device *dev = crtc->dev;
 351        struct drm_i915_private *dev_priv = dev->dev_private;
 352        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 353        int reg = DSPCNTR(intel_crtc->plane);
 354
 355        if (intel_crtc->primary_disabled)
 356                return;
 357
 358        I915_WRITE(reg, I915_READ(reg) & ~DISPLAY_PLANE_ENABLE);
 359
 360        intel_crtc->primary_disabled = true;
 361        intel_update_fbc(dev);
 362}
 363
 364static int
 365ilk_update_colorkey(struct drm_plane *plane,
 366                    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        int ret = 0;
 373
 374        intel_plane = to_intel_plane(plane);
 375
 376        I915_WRITE(DVSKEYVAL(intel_plane->pipe), key->min_value);
 377        I915_WRITE(DVSKEYMAX(intel_plane->pipe), key->max_value);
 378        I915_WRITE(DVSKEYMSK(intel_plane->pipe), key->channel_mask);
 379
 380        dvscntr = I915_READ(DVSCNTR(intel_plane->pipe));
 381        dvscntr &= ~(DVS_SOURCE_KEY | DVS_DEST_KEY);
 382        if (key->flags & I915_SET_COLORKEY_DESTINATION)
 383                dvscntr |= DVS_DEST_KEY;
 384        else if (key->flags & I915_SET_COLORKEY_SOURCE)
 385                dvscntr |= DVS_SOURCE_KEY;
 386        I915_WRITE(DVSCNTR(intel_plane->pipe), dvscntr);
 387
 388        POSTING_READ(DVSKEYMSK(intel_plane->pipe));
 389
 390        return ret;
 391}
 392
 393static void
 394ilk_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key)
 395{
 396        struct drm_device *dev = plane->dev;
 397        struct drm_i915_private *dev_priv = dev->dev_private;
 398        struct intel_plane *intel_plane;
 399        u32 dvscntr;
 400
 401        intel_plane = to_intel_plane(plane);
 402
 403        key->min_value = I915_READ(DVSKEYVAL(intel_plane->pipe));
 404        key->max_value = I915_READ(DVSKEYMAX(intel_plane->pipe));
 405        key->channel_mask = I915_READ(DVSKEYMSK(intel_plane->pipe));
 406        key->flags = 0;
 407
 408        dvscntr = I915_READ(DVSCNTR(intel_plane->pipe));
 409
 410        if (dvscntr & DVS_DEST_KEY)
 411                key->flags = I915_SET_COLORKEY_DESTINATION;
 412        else if (dvscntr & DVS_SOURCE_KEY)
 413                key->flags = I915_SET_COLORKEY_SOURCE;
 414        else
 415                key->flags = I915_SET_COLORKEY_NONE;
 416}
 417
 418static int
 419intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
 420                   struct drm_framebuffer *fb, int crtc_x, int crtc_y,
 421                   unsigned int crtc_w, unsigned int crtc_h,
 422                   uint32_t src_x, uint32_t src_y,
 423                   uint32_t src_w, uint32_t src_h)
 424{
 425        struct drm_device *dev = plane->dev;
 426        struct drm_i915_private *dev_priv = dev->dev_private;
 427        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 428        struct intel_plane *intel_plane = to_intel_plane(plane);
 429        struct intel_framebuffer *intel_fb;
 430        struct drm_i915_gem_object *obj, *old_obj;
 431        int pipe = intel_plane->pipe;
 432        enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv,
 433                                                                      pipe);
 434        int ret = 0;
 435        int x = src_x >> 16, y = src_y >> 16;
 436        int primary_w = crtc->mode.hdisplay, primary_h = crtc->mode.vdisplay;
 437        bool disable_primary = false;
 438
 439        intel_fb = to_intel_framebuffer(fb);
 440        obj = intel_fb->obj;
 441
 442        old_obj = intel_plane->obj;
 443
 444        src_w = src_w >> 16;
 445        src_h = src_h >> 16;
 446
 447        /* Pipe must be running... */
 448        if (!(I915_READ(PIPECONF(cpu_transcoder)) & PIPECONF_ENABLE))
 449                return -EINVAL;
 450
 451        if (crtc_x >= primary_w || crtc_y >= primary_h)
 452                return -EINVAL;
 453
 454        /* Don't modify another pipe's plane */
 455        if (intel_plane->pipe != intel_crtc->pipe)
 456                return -EINVAL;
 457
 458        /* Sprite planes can be linear or x-tiled surfaces */
 459        switch (obj->tiling_mode) {
 460                case I915_TILING_NONE:
 461                case I915_TILING_X:
 462                        break;
 463                default:
 464                        return -EINVAL;
 465        }
 466
 467        /*
 468         * Clamp the width & height into the visible area.  Note we don't
 469         * try to scale the source if part of the visible region is offscreen.
 470         * The caller must handle that by adjusting source offset and size.
 471         */
 472        if ((crtc_x < 0) && ((crtc_x + crtc_w) > 0)) {
 473                crtc_w += crtc_x;
 474                crtc_x = 0;
 475        }
 476        if ((crtc_x + crtc_w) <= 0) /* Nothing to display */
 477                goto out;
 478        if ((crtc_x + crtc_w) > primary_w)
 479                crtc_w = primary_w - crtc_x;
 480
 481        if ((crtc_y < 0) && ((crtc_y + crtc_h) > 0)) {
 482                crtc_h += crtc_y;
 483                crtc_y = 0;
 484        }
 485        if ((crtc_y + crtc_h) <= 0) /* Nothing to display */
 486                goto out;
 487        if (crtc_y + crtc_h > primary_h)
 488                crtc_h = primary_h - crtc_y;
 489
 490        if (!crtc_w || !crtc_h) /* Again, nothing to display */
 491                goto out;
 492
 493        /*
 494         * We may not have a scaler, eg. HSW does not have it any more
 495         */
 496        if (!intel_plane->can_scale && (crtc_w != src_w || crtc_h != src_h))
 497                return -EINVAL;
 498
 499        /*
 500         * We can take a larger source and scale it down, but
 501         * only so much...  16x is the max on SNB.
 502         */
 503        if (((src_w * src_h) / (crtc_w * crtc_h)) > intel_plane->max_downscale)
 504                return -EINVAL;
 505
 506        /*
 507         * If the sprite is completely covering the primary plane,
 508         * we can disable the primary and save power.
 509         */
 510        if ((crtc_x == 0) && (crtc_y == 0) &&
 511            (crtc_w == primary_w) && (crtc_h == primary_h))
 512                disable_primary = true;
 513
 514        mutex_lock(&dev->struct_mutex);
 515
 516        ret = intel_pin_and_fence_fb_obj(dev, obj, NULL);
 517        if (ret)
 518                goto out_unlock;
 519
 520        intel_plane->obj = obj;
 521
 522        /*
 523         * Be sure to re-enable the primary before the sprite is no longer
 524         * covering it fully.
 525         */
 526        if (!disable_primary)
 527                intel_enable_primary(crtc);
 528
 529        intel_plane->update_plane(plane, fb, obj, crtc_x, crtc_y,
 530                                  crtc_w, crtc_h, x, y, src_w, src_h);
 531
 532        if (disable_primary)
 533                intel_disable_primary(crtc);
 534
 535        /* Unpin old obj after new one is active to avoid ugliness */
 536        if (old_obj) {
 537                /*
 538                 * It's fairly common to simply update the position of
 539                 * an existing object.  In that case, we don't need to
 540                 * wait for vblank to avoid ugliness, we only need to
 541                 * do the pin & ref bookkeeping.
 542                 */
 543                if (old_obj != obj) {
 544                        mutex_unlock(&dev->struct_mutex);
 545                        intel_wait_for_vblank(dev, to_intel_crtc(crtc)->pipe);
 546                        mutex_lock(&dev->struct_mutex);
 547                }
 548                intel_unpin_fb_obj(old_obj);
 549        }
 550
 551out_unlock:
 552        mutex_unlock(&dev->struct_mutex);
 553out:
 554        return ret;
 555}
 556
 557static int
 558intel_disable_plane(struct drm_plane *plane)
 559{
 560        struct drm_device *dev = plane->dev;
 561        struct intel_plane *intel_plane = to_intel_plane(plane);
 562        int ret = 0;
 563
 564        if (plane->crtc)
 565                intel_enable_primary(plane->crtc);
 566        intel_plane->disable_plane(plane);
 567
 568        if (!intel_plane->obj)
 569                goto out;
 570
 571        mutex_lock(&dev->struct_mutex);
 572        intel_unpin_fb_obj(intel_plane->obj);
 573        intel_plane->obj = NULL;
 574        mutex_unlock(&dev->struct_mutex);
 575out:
 576
 577        return ret;
 578}
 579
 580static void intel_destroy_plane(struct drm_plane *plane)
 581{
 582        struct intel_plane *intel_plane = to_intel_plane(plane);
 583        intel_disable_plane(plane);
 584        drm_plane_cleanup(plane);
 585        kfree(intel_plane);
 586}
 587
 588int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
 589                              struct drm_file *file_priv)
 590{
 591        struct drm_intel_sprite_colorkey *set = data;
 592        struct drm_mode_object *obj;
 593        struct drm_plane *plane;
 594        struct intel_plane *intel_plane;
 595        int ret = 0;
 596
 597        if (!drm_core_check_feature(dev, DRIVER_MODESET))
 598                return -ENODEV;
 599
 600        /* Make sure we don't try to enable both src & dest simultaneously */
 601        if ((set->flags & (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) == (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE))
 602                return -EINVAL;
 603
 604        drm_modeset_lock_all(dev);
 605
 606        obj = drm_mode_object_find(dev, set->plane_id, DRM_MODE_OBJECT_PLANE);
 607        if (!obj) {
 608                ret = -EINVAL;
 609                goto out_unlock;
 610        }
 611
 612        plane = obj_to_plane(obj);
 613        intel_plane = to_intel_plane(plane);
 614        ret = intel_plane->update_colorkey(plane, set);
 615
 616out_unlock:
 617        drm_modeset_unlock_all(dev);
 618        return ret;
 619}
 620
 621int intel_sprite_get_colorkey(struct drm_device *dev, void *data,
 622                              struct drm_file *file_priv)
 623{
 624        struct drm_intel_sprite_colorkey *get = data;
 625        struct drm_mode_object *obj;
 626        struct drm_plane *plane;
 627        struct intel_plane *intel_plane;
 628        int ret = 0;
 629
 630        if (!drm_core_check_feature(dev, DRIVER_MODESET))
 631                return -ENODEV;
 632
 633        drm_modeset_lock_all(dev);
 634
 635        obj = drm_mode_object_find(dev, get->plane_id, DRM_MODE_OBJECT_PLANE);
 636        if (!obj) {
 637                ret = -EINVAL;
 638                goto out_unlock;
 639        }
 640
 641        plane = obj_to_plane(obj);
 642        intel_plane = to_intel_plane(plane);
 643        intel_plane->get_colorkey(plane, get);
 644
 645out_unlock:
 646        drm_modeset_unlock_all(dev);
 647        return ret;
 648}
 649
 650static const struct drm_plane_funcs intel_plane_funcs = {
 651        .update_plane = intel_update_plane,
 652        .disable_plane = intel_disable_plane,
 653        .destroy = intel_destroy_plane,
 654};
 655
 656static uint32_t ilk_plane_formats[] = {
 657        DRM_FORMAT_XRGB8888,
 658        DRM_FORMAT_YUYV,
 659        DRM_FORMAT_YVYU,
 660        DRM_FORMAT_UYVY,
 661        DRM_FORMAT_VYUY,
 662};
 663
 664static uint32_t snb_plane_formats[] = {
 665        DRM_FORMAT_XBGR8888,
 666        DRM_FORMAT_XRGB8888,
 667        DRM_FORMAT_YUYV,
 668        DRM_FORMAT_YVYU,
 669        DRM_FORMAT_UYVY,
 670        DRM_FORMAT_VYUY,
 671};
 672
 673int
 674intel_plane_init(struct drm_device *dev, enum pipe pipe)
 675{
 676        struct intel_plane *intel_plane;
 677        unsigned long possible_crtcs;
 678        const uint32_t *plane_formats;
 679        int num_plane_formats;
 680        int ret;
 681
 682        if (INTEL_INFO(dev)->gen < 5)
 683                return -ENODEV;
 684
 685        intel_plane = kzalloc(sizeof(struct intel_plane), GFP_KERNEL);
 686        if (!intel_plane)
 687                return -ENOMEM;
 688
 689        switch (INTEL_INFO(dev)->gen) {
 690        case 5:
 691        case 6:
 692                intel_plane->can_scale = true;
 693                intel_plane->max_downscale = 16;
 694                intel_plane->update_plane = ilk_update_plane;
 695                intel_plane->disable_plane = ilk_disable_plane;
 696                intel_plane->update_colorkey = ilk_update_colorkey;
 697                intel_plane->get_colorkey = ilk_get_colorkey;
 698
 699                if (IS_GEN6(dev)) {
 700                        plane_formats = snb_plane_formats;
 701                        num_plane_formats = ARRAY_SIZE(snb_plane_formats);
 702                } else {
 703                        plane_formats = ilk_plane_formats;
 704                        num_plane_formats = ARRAY_SIZE(ilk_plane_formats);
 705                }
 706                break;
 707
 708        case 7:
 709                if (IS_HASWELL(dev) || IS_VALLEYVIEW(dev))
 710                        intel_plane->can_scale = false;
 711                else
 712                        intel_plane->can_scale = true;
 713                intel_plane->max_downscale = 2;
 714                intel_plane->update_plane = ivb_update_plane;
 715                intel_plane->disable_plane = ivb_disable_plane;
 716                intel_plane->update_colorkey = ivb_update_colorkey;
 717                intel_plane->get_colorkey = ivb_get_colorkey;
 718
 719                plane_formats = snb_plane_formats;
 720                num_plane_formats = ARRAY_SIZE(snb_plane_formats);
 721                break;
 722
 723        default:
 724                kfree(intel_plane);
 725                return -ENODEV;
 726        }
 727
 728        intel_plane->pipe = pipe;
 729        possible_crtcs = (1 << pipe);
 730        ret = drm_plane_init(dev, &intel_plane->base, possible_crtcs,
 731                             &intel_plane_funcs,
 732                             plane_formats, num_plane_formats,
 733                             false);
 734        if (ret)
 735                kfree(intel_plane);
 736
 737        return ret;
 738}
 739