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