intel_sprite.c revision 235783
1235783Skib/* 2235783Skib * Copyright �� 2011 Intel Corporation 3235783Skib * 4235783Skib * Permission is hereby granted, free of charge, to any person obtaining a 5235783Skib * copy of this software and associated documentation files (the "Software"), 6235783Skib * to deal in the Software without restriction, including without limitation 7235783Skib * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8235783Skib * and/or sell copies of the Software, and to permit persons to whom the 9235783Skib * Software is furnished to do so, subject to the following conditions: 10235783Skib * 11235783Skib * The above copyright notice and this permission notice (including the next 12235783Skib * paragraph) shall be included in all copies or substantial portions of the 13235783Skib * Software. 14235783Skib * 15235783Skib * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16235783Skib * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17235783Skib * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18235783Skib * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19235783Skib * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20235783Skib * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21235783Skib * SOFTWARE. 22235783Skib * 23235783Skib * Authors: 24235783Skib * Jesse Barnes <jbarnes@virtuousgeek.org> 25235783Skib * 26235783Skib * New plane/sprite handling. 27235783Skib * 28235783Skib * The older chips had a separate interface for programming plane related 29235783Skib * registers; newer ones are much simpler and we can use the new DRM plane 30235783Skib * support. 31235783Skib */ 32235783Skib 33235783Skib#include <sys/cdefs.h> 34235783Skib__FBSDID("$FreeBSD: head/sys/dev/drm2/i915/intel_sprite.c 235783 2012-05-22 11:07:44Z kib $"); 35235783Skib 36235783Skib#include <dev/drm2/drmP.h> 37235783Skib#include <dev/drm2/drm.h> 38235783Skib#include <dev/drm2/i915/i915_drm.h> 39235783Skib#include <dev/drm2/i915/i915_drv.h> 40235783Skib#include <dev/drm2/i915/intel_drv.h> 41235783Skib#include <dev/drm2/drm_fourcc.h> 42235783Skib 43235783Skibstatic void 44235783Skibivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, 45235783Skib struct drm_i915_gem_object *obj, int crtc_x, int crtc_y, 46235783Skib unsigned int crtc_w, unsigned int crtc_h, 47235783Skib uint32_t x, uint32_t y, 48235783Skib uint32_t src_w, uint32_t src_h) 49235783Skib{ 50235783Skib struct drm_device *dev = plane->dev; 51235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 52235783Skib struct intel_plane *intel_plane = to_intel_plane(plane); 53235783Skib int pipe = intel_plane->pipe; 54235783Skib u32 sprctl, sprscale = 0; 55235783Skib int pixel_size; 56235783Skib 57235783Skib sprctl = I915_READ(SPRCTL(pipe)); 58235783Skib 59235783Skib /* Mask out pixel format bits in case we change it */ 60235783Skib sprctl &= ~SPRITE_PIXFORMAT_MASK; 61235783Skib sprctl &= ~SPRITE_RGB_ORDER_RGBX; 62235783Skib sprctl &= ~SPRITE_YUV_BYTE_ORDER_MASK; 63235783Skib 64235783Skib switch (fb->pixel_format) { 65235783Skib case DRM_FORMAT_XBGR8888: 66235783Skib sprctl |= SPRITE_FORMAT_RGBX888; 67235783Skib pixel_size = 4; 68235783Skib break; 69235783Skib case DRM_FORMAT_XRGB8888: 70235783Skib sprctl |= SPRITE_FORMAT_RGBX888 | SPRITE_RGB_ORDER_RGBX; 71235783Skib pixel_size = 4; 72235783Skib break; 73235783Skib case DRM_FORMAT_YUYV: 74235783Skib sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YUYV; 75235783Skib pixel_size = 2; 76235783Skib break; 77235783Skib case DRM_FORMAT_YVYU: 78235783Skib sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YVYU; 79235783Skib pixel_size = 2; 80235783Skib break; 81235783Skib case DRM_FORMAT_UYVY: 82235783Skib sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_UYVY; 83235783Skib pixel_size = 2; 84235783Skib break; 85235783Skib case DRM_FORMAT_VYUY: 86235783Skib sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_VYUY; 87235783Skib pixel_size = 2; 88235783Skib break; 89235783Skib default: 90235783Skib DRM_DEBUG_DRIVER("bad pixel format, assuming RGBX888\n"); 91235783Skib sprctl |= DVS_FORMAT_RGBX888; 92235783Skib pixel_size = 4; 93235783Skib break; 94235783Skib } 95235783Skib 96235783Skib if (obj->tiling_mode != I915_TILING_NONE) 97235783Skib sprctl |= SPRITE_TILED; 98235783Skib 99235783Skib /* must disable */ 100235783Skib sprctl |= SPRITE_TRICKLE_FEED_DISABLE; 101235783Skib sprctl |= SPRITE_ENABLE; 102235783Skib 103235783Skib /* Sizes are 0 based */ 104235783Skib src_w--; 105235783Skib src_h--; 106235783Skib crtc_w--; 107235783Skib crtc_h--; 108235783Skib 109235783Skib intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size); 110235783Skib 111235783Skib /* 112235783Skib * IVB workaround: must disable low power watermarks for at least 113235783Skib * one frame before enabling scaling. LP watermarks can be re-enabled 114235783Skib * when scaling is disabled. 115235783Skib */ 116235783Skib if (crtc_w != src_w || crtc_h != src_h) { 117235783Skib dev_priv->sprite_scaling_enabled = true; 118235783Skib sandybridge_update_wm(dev); 119235783Skib intel_wait_for_vblank(dev, pipe); 120235783Skib sprscale = SPRITE_SCALE_ENABLE | (src_w << 16) | src_h; 121235783Skib } else { 122235783Skib dev_priv->sprite_scaling_enabled = false; 123235783Skib /* potentially re-enable LP watermarks */ 124235783Skib sandybridge_update_wm(dev); 125235783Skib } 126235783Skib 127235783Skib I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]); 128235783Skib I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x); 129235783Skib if (obj->tiling_mode != I915_TILING_NONE) { 130235783Skib I915_WRITE(SPRTILEOFF(pipe), (y << 16) | x); 131235783Skib } else { 132235783Skib unsigned long offset; 133235783Skib 134235783Skib offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8); 135235783Skib I915_WRITE(SPRLINOFF(pipe), offset); 136235783Skib } 137235783Skib I915_WRITE(SPRSIZE(pipe), (crtc_h << 16) | crtc_w); 138235783Skib I915_WRITE(SPRSCALE(pipe), sprscale); 139235783Skib I915_WRITE(SPRCTL(pipe), sprctl); 140235783Skib I915_WRITE(SPRSURF(pipe), obj->gtt_offset); 141235783Skib POSTING_READ(SPRSURF(pipe)); 142235783Skib} 143235783Skib 144235783Skibstatic void 145235783Skibivb_disable_plane(struct drm_plane *plane) 146235783Skib{ 147235783Skib struct drm_device *dev = plane->dev; 148235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 149235783Skib struct intel_plane *intel_plane = to_intel_plane(plane); 150235783Skib int pipe = intel_plane->pipe; 151235783Skib 152235783Skib I915_WRITE(SPRCTL(pipe), I915_READ(SPRCTL(pipe)) & ~SPRITE_ENABLE); 153235783Skib /* Can't leave the scaler enabled... */ 154235783Skib I915_WRITE(SPRSCALE(pipe), 0); 155235783Skib /* Activate double buffered register update */ 156235783Skib I915_WRITE(SPRSURF(pipe), 0); 157235783Skib POSTING_READ(SPRSURF(pipe)); 158235783Skib} 159235783Skib 160235783Skibstatic int 161235783Skibivb_update_colorkey(struct drm_plane *plane, 162235783Skib struct drm_intel_sprite_colorkey *key) 163235783Skib{ 164235783Skib struct drm_device *dev = plane->dev; 165235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 166235783Skib struct intel_plane *intel_plane; 167235783Skib u32 sprctl; 168235783Skib int ret = 0; 169235783Skib 170235783Skib intel_plane = to_intel_plane(plane); 171235783Skib 172235783Skib I915_WRITE(SPRKEYVAL(intel_plane->pipe), key->min_value); 173235783Skib I915_WRITE(SPRKEYMAX(intel_plane->pipe), key->max_value); 174235783Skib I915_WRITE(SPRKEYMSK(intel_plane->pipe), key->channel_mask); 175235783Skib 176235783Skib sprctl = I915_READ(SPRCTL(intel_plane->pipe)); 177235783Skib sprctl &= ~(SPRITE_SOURCE_KEY | SPRITE_DEST_KEY); 178235783Skib if (key->flags & I915_SET_COLORKEY_DESTINATION) 179235783Skib sprctl |= SPRITE_DEST_KEY; 180235783Skib else if (key->flags & I915_SET_COLORKEY_SOURCE) 181235783Skib sprctl |= SPRITE_SOURCE_KEY; 182235783Skib I915_WRITE(SPRCTL(intel_plane->pipe), sprctl); 183235783Skib 184235783Skib POSTING_READ(SPRKEYMSK(intel_plane->pipe)); 185235783Skib 186235783Skib return ret; 187235783Skib} 188235783Skib 189235783Skibstatic void 190235783Skibivb_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key) 191235783Skib{ 192235783Skib struct drm_device *dev = plane->dev; 193235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 194235783Skib struct intel_plane *intel_plane; 195235783Skib u32 sprctl; 196235783Skib 197235783Skib intel_plane = to_intel_plane(plane); 198235783Skib 199235783Skib key->min_value = I915_READ(SPRKEYVAL(intel_plane->pipe)); 200235783Skib key->max_value = I915_READ(SPRKEYMAX(intel_plane->pipe)); 201235783Skib key->channel_mask = I915_READ(SPRKEYMSK(intel_plane->pipe)); 202235783Skib key->flags = 0; 203235783Skib 204235783Skib sprctl = I915_READ(SPRCTL(intel_plane->pipe)); 205235783Skib 206235783Skib if (sprctl & SPRITE_DEST_KEY) 207235783Skib key->flags = I915_SET_COLORKEY_DESTINATION; 208235783Skib else if (sprctl & SPRITE_SOURCE_KEY) 209235783Skib key->flags = I915_SET_COLORKEY_SOURCE; 210235783Skib else 211235783Skib key->flags = I915_SET_COLORKEY_NONE; 212235783Skib} 213235783Skib 214235783Skibstatic void 215235783Skibsnb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, 216235783Skib struct drm_i915_gem_object *obj, int crtc_x, int crtc_y, 217235783Skib unsigned int crtc_w, unsigned int crtc_h, 218235783Skib uint32_t x, uint32_t y, 219235783Skib uint32_t src_w, uint32_t src_h) 220235783Skib{ 221235783Skib struct drm_device *dev = plane->dev; 222235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 223235783Skib struct intel_plane *intel_plane = to_intel_plane(plane); 224235783Skib int pipe = intel_plane->pipe, pixel_size; 225235783Skib u32 dvscntr, dvsscale = 0; 226235783Skib 227235783Skib dvscntr = I915_READ(DVSCNTR(pipe)); 228235783Skib 229235783Skib /* Mask out pixel format bits in case we change it */ 230235783Skib dvscntr &= ~DVS_PIXFORMAT_MASK; 231235783Skib dvscntr &= ~DVS_RGB_ORDER_XBGR; 232235783Skib dvscntr &= ~DVS_YUV_BYTE_ORDER_MASK; 233235783Skib 234235783Skib switch (fb->pixel_format) { 235235783Skib case DRM_FORMAT_XBGR8888: 236235783Skib dvscntr |= DVS_FORMAT_RGBX888 | DVS_RGB_ORDER_XBGR; 237235783Skib pixel_size = 4; 238235783Skib break; 239235783Skib case DRM_FORMAT_XRGB8888: 240235783Skib dvscntr |= DVS_FORMAT_RGBX888; 241235783Skib pixel_size = 4; 242235783Skib break; 243235783Skib case DRM_FORMAT_YUYV: 244235783Skib dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YUYV; 245235783Skib pixel_size = 2; 246235783Skib break; 247235783Skib case DRM_FORMAT_YVYU: 248235783Skib dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YVYU; 249235783Skib pixel_size = 2; 250235783Skib break; 251235783Skib case DRM_FORMAT_UYVY: 252235783Skib dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_UYVY; 253235783Skib pixel_size = 2; 254235783Skib break; 255235783Skib case DRM_FORMAT_VYUY: 256235783Skib dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_VYUY; 257235783Skib pixel_size = 2; 258235783Skib break; 259235783Skib default: 260235783Skib DRM_DEBUG_DRIVER("bad pixel format, assuming RGBX888\n"); 261235783Skib dvscntr |= DVS_FORMAT_RGBX888; 262235783Skib pixel_size = 4; 263235783Skib break; 264235783Skib } 265235783Skib 266235783Skib if (obj->tiling_mode != I915_TILING_NONE) 267235783Skib dvscntr |= DVS_TILED; 268235783Skib 269235783Skib /* must disable */ 270235783Skib dvscntr |= DVS_TRICKLE_FEED_DISABLE; 271235783Skib dvscntr |= DVS_ENABLE; 272235783Skib 273235783Skib /* Sizes are 0 based */ 274235783Skib src_w--; 275235783Skib src_h--; 276235783Skib crtc_w--; 277235783Skib crtc_h--; 278235783Skib 279235783Skib intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size); 280235783Skib 281235783Skib if (crtc_w != src_w || crtc_h != src_h) 282235783Skib dvsscale = DVS_SCALE_ENABLE | (src_w << 16) | src_h; 283235783Skib 284235783Skib I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]); 285235783Skib I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x); 286235783Skib if (obj->tiling_mode != I915_TILING_NONE) { 287235783Skib I915_WRITE(DVSTILEOFF(pipe), (y << 16) | x); 288235783Skib } else { 289235783Skib unsigned long offset; 290235783Skib 291235783Skib offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8); 292235783Skib I915_WRITE(DVSLINOFF(pipe), offset); 293235783Skib } 294235783Skib I915_WRITE(DVSSIZE(pipe), (crtc_h << 16) | crtc_w); 295235783Skib I915_WRITE(DVSSCALE(pipe), dvsscale); 296235783Skib I915_WRITE(DVSCNTR(pipe), dvscntr); 297235783Skib I915_WRITE(DVSSURF(pipe), obj->gtt_offset); 298235783Skib POSTING_READ(DVSSURF(pipe)); 299235783Skib} 300235783Skib 301235783Skibstatic void 302235783Skibsnb_disable_plane(struct drm_plane *plane) 303235783Skib{ 304235783Skib struct drm_device *dev = plane->dev; 305235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 306235783Skib struct intel_plane *intel_plane = to_intel_plane(plane); 307235783Skib int pipe = intel_plane->pipe; 308235783Skib 309235783Skib I915_WRITE(DVSCNTR(pipe), I915_READ(DVSCNTR(pipe)) & ~DVS_ENABLE); 310235783Skib /* Disable the scaler */ 311235783Skib I915_WRITE(DVSSCALE(pipe), 0); 312235783Skib /* Flush double buffered register updates */ 313235783Skib I915_WRITE(DVSSURF(pipe), 0); 314235783Skib POSTING_READ(DVSSURF(pipe)); 315235783Skib} 316235783Skib 317235783Skibstatic void 318235783Skibintel_enable_primary(struct drm_crtc *crtc) 319235783Skib{ 320235783Skib struct drm_device *dev = crtc->dev; 321235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 322235783Skib struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 323235783Skib int reg = DSPCNTR(intel_crtc->plane); 324235783Skib 325235783Skib I915_WRITE(reg, I915_READ(reg) | DISPLAY_PLANE_ENABLE); 326235783Skib} 327235783Skib 328235783Skibstatic void 329235783Skibintel_disable_primary(struct drm_crtc *crtc) 330235783Skib{ 331235783Skib struct drm_device *dev = crtc->dev; 332235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 333235783Skib struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 334235783Skib int reg = DSPCNTR(intel_crtc->plane); 335235783Skib 336235783Skib I915_WRITE(reg, I915_READ(reg) & ~DISPLAY_PLANE_ENABLE); 337235783Skib} 338235783Skib 339235783Skibstatic int 340235783Skibsnb_update_colorkey(struct drm_plane *plane, 341235783Skib struct drm_intel_sprite_colorkey *key) 342235783Skib{ 343235783Skib struct drm_device *dev = plane->dev; 344235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 345235783Skib struct intel_plane *intel_plane; 346235783Skib u32 dvscntr; 347235783Skib int ret = 0; 348235783Skib 349235783Skib intel_plane = to_intel_plane(plane); 350235783Skib 351235783Skib I915_WRITE(DVSKEYVAL(intel_plane->pipe), key->min_value); 352235783Skib I915_WRITE(DVSKEYMAX(intel_plane->pipe), key->max_value); 353235783Skib I915_WRITE(DVSKEYMSK(intel_plane->pipe), key->channel_mask); 354235783Skib 355235783Skib dvscntr = I915_READ(DVSCNTR(intel_plane->pipe)); 356235783Skib dvscntr &= ~(DVS_SOURCE_KEY | DVS_DEST_KEY); 357235783Skib if (key->flags & I915_SET_COLORKEY_DESTINATION) 358235783Skib dvscntr |= DVS_DEST_KEY; 359235783Skib else if (key->flags & I915_SET_COLORKEY_SOURCE) 360235783Skib dvscntr |= DVS_SOURCE_KEY; 361235783Skib I915_WRITE(DVSCNTR(intel_plane->pipe), dvscntr); 362235783Skib 363235783Skib POSTING_READ(DVSKEYMSK(intel_plane->pipe)); 364235783Skib 365235783Skib return ret; 366235783Skib} 367235783Skib 368235783Skibstatic void 369235783Skibsnb_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key) 370235783Skib{ 371235783Skib struct drm_device *dev = plane->dev; 372235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 373235783Skib struct intel_plane *intel_plane; 374235783Skib u32 dvscntr; 375235783Skib 376235783Skib intel_plane = to_intel_plane(plane); 377235783Skib 378235783Skib key->min_value = I915_READ(DVSKEYVAL(intel_plane->pipe)); 379235783Skib key->max_value = I915_READ(DVSKEYMAX(intel_plane->pipe)); 380235783Skib key->channel_mask = I915_READ(DVSKEYMSK(intel_plane->pipe)); 381235783Skib key->flags = 0; 382235783Skib 383235783Skib dvscntr = I915_READ(DVSCNTR(intel_plane->pipe)); 384235783Skib 385235783Skib if (dvscntr & DVS_DEST_KEY) 386235783Skib key->flags = I915_SET_COLORKEY_DESTINATION; 387235783Skib else if (dvscntr & DVS_SOURCE_KEY) 388235783Skib key->flags = I915_SET_COLORKEY_SOURCE; 389235783Skib else 390235783Skib key->flags = I915_SET_COLORKEY_NONE; 391235783Skib} 392235783Skib 393235783Skibstatic int 394235783Skibintel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, 395235783Skib struct drm_framebuffer *fb, int crtc_x, int crtc_y, 396235783Skib unsigned int crtc_w, unsigned int crtc_h, 397235783Skib uint32_t src_x, uint32_t src_y, 398235783Skib uint32_t src_w, uint32_t src_h) 399235783Skib{ 400235783Skib struct drm_device *dev = plane->dev; 401235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 402235783Skib struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 403235783Skib struct intel_plane *intel_plane = to_intel_plane(plane); 404235783Skib struct intel_framebuffer *intel_fb; 405235783Skib struct drm_i915_gem_object *obj, *old_obj; 406235783Skib int pipe = intel_plane->pipe; 407235783Skib int ret = 0; 408235783Skib int x = src_x >> 16, y = src_y >> 16; 409235783Skib int primary_w = crtc->mode.hdisplay, primary_h = crtc->mode.vdisplay; 410235783Skib bool disable_primary = false; 411235783Skib 412235783Skib intel_fb = to_intel_framebuffer(fb); 413235783Skib obj = intel_fb->obj; 414235783Skib 415235783Skib old_obj = intel_plane->obj; 416235783Skib 417235783Skib src_w = src_w >> 16; 418235783Skib src_h = src_h >> 16; 419235783Skib 420235783Skib /* Pipe must be running... */ 421235783Skib if (!(I915_READ(PIPECONF(pipe)) & PIPECONF_ENABLE)) 422235783Skib return -EINVAL; 423235783Skib 424235783Skib if (crtc_x >= primary_w || crtc_y >= primary_h) 425235783Skib return -EINVAL; 426235783Skib 427235783Skib /* Don't modify another pipe's plane */ 428235783Skib if (intel_plane->pipe != intel_crtc->pipe) 429235783Skib return -EINVAL; 430235783Skib 431235783Skib /* 432235783Skib * Clamp the width & height into the visible area. Note we don't 433235783Skib * try to scale the source if part of the visible region is offscreen. 434235783Skib * The caller must handle that by adjusting source offset and size. 435235783Skib */ 436235783Skib if ((crtc_x < 0) && ((crtc_x + crtc_w) > 0)) { 437235783Skib crtc_w += crtc_x; 438235783Skib crtc_x = 0; 439235783Skib } 440235783Skib if ((crtc_x + crtc_w) <= 0) /* Nothing to display */ 441235783Skib goto out; 442235783Skib if ((crtc_x + crtc_w) > primary_w) 443235783Skib crtc_w = primary_w - crtc_x; 444235783Skib 445235783Skib if ((crtc_y < 0) && ((crtc_y + crtc_h) > 0)) { 446235783Skib crtc_h += crtc_y; 447235783Skib crtc_y = 0; 448235783Skib } 449235783Skib if ((crtc_y + crtc_h) <= 0) /* Nothing to display */ 450235783Skib goto out; 451235783Skib if (crtc_y + crtc_h > primary_h) 452235783Skib crtc_h = primary_h - crtc_y; 453235783Skib 454235783Skib if (!crtc_w || !crtc_h) /* Again, nothing to display */ 455235783Skib goto out; 456235783Skib 457235783Skib /* 458235783Skib * We can take a larger source and scale it down, but 459235783Skib * only so much... 16x is the max on SNB. 460235783Skib */ 461235783Skib if (((src_w * src_h) / (crtc_w * crtc_h)) > intel_plane->max_downscale) 462235783Skib return -EINVAL; 463235783Skib 464235783Skib /* 465235783Skib * If the sprite is completely covering the primary plane, 466235783Skib * we can disable the primary and save power. 467235783Skib */ 468235783Skib if ((crtc_x == 0) && (crtc_y == 0) && 469235783Skib (crtc_w == primary_w) && (crtc_h == primary_h)) 470235783Skib disable_primary = true; 471235783Skib 472235783Skib DRM_LOCK(dev); 473235783Skib 474235783Skib ret = intel_pin_and_fence_fb_obj(dev, obj, NULL); 475235783Skib if (ret) 476235783Skib goto out_unlock; 477235783Skib 478235783Skib intel_plane->obj = obj; 479235783Skib 480235783Skib /* 481235783Skib * Be sure to re-enable the primary before the sprite is no longer 482235783Skib * covering it fully. 483235783Skib */ 484235783Skib if (!disable_primary && intel_plane->primary_disabled) { 485235783Skib intel_enable_primary(crtc); 486235783Skib intel_plane->primary_disabled = false; 487235783Skib } 488235783Skib 489235783Skib intel_plane->update_plane(plane, fb, obj, crtc_x, crtc_y, 490235783Skib crtc_w, crtc_h, x, y, src_w, src_h); 491235783Skib 492235783Skib if (disable_primary) { 493235783Skib intel_disable_primary(crtc); 494235783Skib intel_plane->primary_disabled = true; 495235783Skib } 496235783Skib 497235783Skib /* Unpin old obj after new one is active to avoid ugliness */ 498235783Skib if (old_obj) { 499235783Skib /* 500235783Skib * It's fairly common to simply update the position of 501235783Skib * an existing object. In that case, we don't need to 502235783Skib * wait for vblank to avoid ugliness, we only need to 503235783Skib * do the pin & ref bookkeeping. 504235783Skib */ 505235783Skib if (old_obj != obj) { 506235783Skib DRM_UNLOCK(dev); 507235783Skib intel_wait_for_vblank(dev, to_intel_crtc(crtc)->pipe); 508235783Skib DRM_LOCK(dev); 509235783Skib } 510235783Skib intel_unpin_fb_obj(old_obj); 511235783Skib } 512235783Skib 513235783Skibout_unlock: 514235783Skib DRM_UNLOCK(dev); 515235783Skibout: 516235783Skib return ret; 517235783Skib} 518235783Skib 519235783Skibstatic int 520235783Skibintel_disable_plane(struct drm_plane *plane) 521235783Skib{ 522235783Skib struct drm_device *dev = plane->dev; 523235783Skib struct intel_plane *intel_plane = to_intel_plane(plane); 524235783Skib int ret = 0; 525235783Skib 526235783Skib if (intel_plane->primary_disabled) { 527235783Skib intel_enable_primary(plane->crtc); 528235783Skib intel_plane->primary_disabled = false; 529235783Skib } 530235783Skib 531235783Skib intel_plane->disable_plane(plane); 532235783Skib 533235783Skib if (!intel_plane->obj) 534235783Skib goto out; 535235783Skib 536235783Skib DRM_LOCK(dev); 537235783Skib intel_unpin_fb_obj(intel_plane->obj); 538235783Skib intel_plane->obj = NULL; 539235783Skib DRM_UNLOCK(dev); 540235783Skibout: 541235783Skib 542235783Skib return ret; 543235783Skib} 544235783Skib 545235783Skibstatic void intel_destroy_plane(struct drm_plane *plane) 546235783Skib{ 547235783Skib struct intel_plane *intel_plane = to_intel_plane(plane); 548235783Skib intel_disable_plane(plane); 549235783Skib drm_plane_cleanup(plane); 550235783Skib free(intel_plane, DRM_MEM_KMS); 551235783Skib} 552235783Skib 553235783Skibint intel_sprite_set_colorkey(struct drm_device *dev, void *data, 554235783Skib struct drm_file *file_priv) 555235783Skib{ 556235783Skib struct drm_intel_sprite_colorkey *set = data; 557235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 558235783Skib struct drm_mode_object *obj; 559235783Skib struct drm_plane *plane; 560235783Skib struct intel_plane *intel_plane; 561235783Skib int ret = 0; 562235783Skib 563235783Skib if (!dev_priv) 564235783Skib return -EINVAL; 565235783Skib 566235783Skib /* Make sure we don't try to enable both src & dest simultaneously */ 567235783Skib if ((set->flags & (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) == (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) 568235783Skib return -EINVAL; 569235783Skib 570235783Skib sx_xlock(&dev->mode_config.mutex); 571235783Skib 572235783Skib obj = drm_mode_object_find(dev, set->plane_id, DRM_MODE_OBJECT_PLANE); 573235783Skib if (!obj) { 574235783Skib ret = -EINVAL; 575235783Skib goto out_unlock; 576235783Skib } 577235783Skib 578235783Skib plane = obj_to_plane(obj); 579235783Skib intel_plane = to_intel_plane(plane); 580235783Skib ret = intel_plane->update_colorkey(plane, set); 581235783Skib 582235783Skibout_unlock: 583235783Skib sx_xunlock(&dev->mode_config.mutex); 584235783Skib return ret; 585235783Skib} 586235783Skib 587235783Skibint intel_sprite_get_colorkey(struct drm_device *dev, void *data, 588235783Skib struct drm_file *file_priv) 589235783Skib{ 590235783Skib struct drm_intel_sprite_colorkey *get = data; 591235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 592235783Skib struct drm_mode_object *obj; 593235783Skib struct drm_plane *plane; 594235783Skib struct intel_plane *intel_plane; 595235783Skib int ret = 0; 596235783Skib 597235783Skib if (!dev_priv) 598235783Skib return -EINVAL; 599235783Skib 600235783Skib sx_xlock(&dev->mode_config.mutex); 601235783Skib 602235783Skib obj = drm_mode_object_find(dev, get->plane_id, DRM_MODE_OBJECT_PLANE); 603235783Skib if (!obj) { 604235783Skib ret = -EINVAL; 605235783Skib goto out_unlock; 606235783Skib } 607235783Skib 608235783Skib plane = obj_to_plane(obj); 609235783Skib intel_plane = to_intel_plane(plane); 610235783Skib intel_plane->get_colorkey(plane, get); 611235783Skib 612235783Skibout_unlock: 613235783Skib sx_xunlock(&dev->mode_config.mutex); 614235783Skib return ret; 615235783Skib} 616235783Skib 617235783Skibstatic const struct drm_plane_funcs intel_plane_funcs = { 618235783Skib .update_plane = intel_update_plane, 619235783Skib .disable_plane = intel_disable_plane, 620235783Skib .destroy = intel_destroy_plane, 621235783Skib}; 622235783Skib 623235783Skibstatic uint32_t snb_plane_formats[] = { 624235783Skib DRM_FORMAT_XBGR8888, 625235783Skib DRM_FORMAT_XRGB8888, 626235783Skib DRM_FORMAT_YUYV, 627235783Skib DRM_FORMAT_YVYU, 628235783Skib DRM_FORMAT_UYVY, 629235783Skib DRM_FORMAT_VYUY, 630235783Skib}; 631235783Skib 632235783Skibint 633235783Skibintel_plane_init(struct drm_device *dev, enum pipe pipe) 634235783Skib{ 635235783Skib struct intel_plane *intel_plane; 636235783Skib unsigned long possible_crtcs; 637235783Skib int ret; 638235783Skib 639235783Skib if (!(IS_GEN6(dev) || IS_GEN7(dev))) 640235783Skib return -ENODEV; 641235783Skib 642235783Skib intel_plane = malloc(sizeof(struct intel_plane), DRM_MEM_KMS, 643235783Skib M_WAITOK | M_ZERO); 644235783Skib 645235783Skib if (IS_GEN6(dev)) { 646235783Skib intel_plane->max_downscale = 16; 647235783Skib intel_plane->update_plane = snb_update_plane; 648235783Skib intel_plane->disable_plane = snb_disable_plane; 649235783Skib intel_plane->update_colorkey = snb_update_colorkey; 650235783Skib intel_plane->get_colorkey = snb_get_colorkey; 651235783Skib } else if (IS_GEN7(dev)) { 652235783Skib intel_plane->max_downscale = 2; 653235783Skib intel_plane->update_plane = ivb_update_plane; 654235783Skib intel_plane->disable_plane = ivb_disable_plane; 655235783Skib intel_plane->update_colorkey = ivb_update_colorkey; 656235783Skib intel_plane->get_colorkey = ivb_get_colorkey; 657235783Skib } 658235783Skib 659235783Skib intel_plane->pipe = pipe; 660235783Skib possible_crtcs = (1 << pipe); 661235783Skib ret = drm_plane_init(dev, &intel_plane->base, possible_crtcs, 662235783Skib &intel_plane_funcs, snb_plane_formats, 663235783Skib DRM_ARRAY_SIZE(snb_plane_formats), false); 664235783Skib if (ret) 665235783Skib free(intel_plane, DRM_MEM_KMS); 666235783Skib 667235783Skib return ret; 668235783Skib} 669235783Skib 670