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: releng/10.3/sys/dev/drm2/i915/intel_sprite.c 280369 2015-03-23 13:38:33Z 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) { 117280369Skib if (!dev_priv->sprite_scaling_enabled) { 118280369Skib dev_priv->sprite_scaling_enabled = true; 119280369Skib intel_update_watermarks(dev); 120280369Skib intel_wait_for_vblank(dev, pipe); 121280369Skib } 122235783Skib sprscale = SPRITE_SCALE_ENABLE | (src_w << 16) | src_h; 123235783Skib } else { 124280369Skib if (dev_priv->sprite_scaling_enabled) { 125280369Skib dev_priv->sprite_scaling_enabled = false; 126280369Skib /* potentially re-enable LP watermarks */ 127280369Skib intel_update_watermarks(dev); 128280369Skib } 129235783Skib } 130235783Skib 131235783Skib I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]); 132235783Skib I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x); 133235783Skib if (obj->tiling_mode != I915_TILING_NONE) { 134235783Skib I915_WRITE(SPRTILEOFF(pipe), (y << 16) | x); 135235783Skib } else { 136235783Skib unsigned long offset; 137235783Skib 138235783Skib offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8); 139235783Skib I915_WRITE(SPRLINOFF(pipe), offset); 140235783Skib } 141235783Skib I915_WRITE(SPRSIZE(pipe), (crtc_h << 16) | crtc_w); 142235783Skib I915_WRITE(SPRSCALE(pipe), sprscale); 143235783Skib I915_WRITE(SPRCTL(pipe), sprctl); 144280369Skib I915_MODIFY_DISPBASE(SPRSURF(pipe), obj->gtt_offset); 145235783Skib POSTING_READ(SPRSURF(pipe)); 146235783Skib} 147235783Skib 148235783Skibstatic void 149235783Skibivb_disable_plane(struct drm_plane *plane) 150235783Skib{ 151235783Skib struct drm_device *dev = plane->dev; 152235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 153235783Skib struct intel_plane *intel_plane = to_intel_plane(plane); 154235783Skib int pipe = intel_plane->pipe; 155235783Skib 156235783Skib I915_WRITE(SPRCTL(pipe), I915_READ(SPRCTL(pipe)) & ~SPRITE_ENABLE); 157235783Skib /* Can't leave the scaler enabled... */ 158235783Skib I915_WRITE(SPRSCALE(pipe), 0); 159235783Skib /* Activate double buffered register update */ 160280369Skib I915_MODIFY_DISPBASE(SPRSURF(pipe), 0); 161235783Skib POSTING_READ(SPRSURF(pipe)); 162280369Skib 163280369Skib dev_priv->sprite_scaling_enabled = false; 164280369Skib intel_update_watermarks(dev); 165235783Skib} 166235783Skib 167235783Skibstatic int 168235783Skibivb_update_colorkey(struct drm_plane *plane, 169235783Skib struct drm_intel_sprite_colorkey *key) 170235783Skib{ 171235783Skib struct drm_device *dev = plane->dev; 172235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 173235783Skib struct intel_plane *intel_plane; 174235783Skib u32 sprctl; 175235783Skib int ret = 0; 176235783Skib 177235783Skib intel_plane = to_intel_plane(plane); 178235783Skib 179235783Skib I915_WRITE(SPRKEYVAL(intel_plane->pipe), key->min_value); 180235783Skib I915_WRITE(SPRKEYMAX(intel_plane->pipe), key->max_value); 181235783Skib I915_WRITE(SPRKEYMSK(intel_plane->pipe), key->channel_mask); 182235783Skib 183235783Skib sprctl = I915_READ(SPRCTL(intel_plane->pipe)); 184235783Skib sprctl &= ~(SPRITE_SOURCE_KEY | SPRITE_DEST_KEY); 185235783Skib if (key->flags & I915_SET_COLORKEY_DESTINATION) 186235783Skib sprctl |= SPRITE_DEST_KEY; 187235783Skib else if (key->flags & I915_SET_COLORKEY_SOURCE) 188235783Skib sprctl |= SPRITE_SOURCE_KEY; 189235783Skib I915_WRITE(SPRCTL(intel_plane->pipe), sprctl); 190235783Skib 191235783Skib POSTING_READ(SPRKEYMSK(intel_plane->pipe)); 192235783Skib 193235783Skib return ret; 194235783Skib} 195235783Skib 196235783Skibstatic void 197235783Skibivb_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key) 198235783Skib{ 199235783Skib struct drm_device *dev = plane->dev; 200235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 201235783Skib struct intel_plane *intel_plane; 202235783Skib u32 sprctl; 203235783Skib 204235783Skib intel_plane = to_intel_plane(plane); 205235783Skib 206235783Skib key->min_value = I915_READ(SPRKEYVAL(intel_plane->pipe)); 207235783Skib key->max_value = I915_READ(SPRKEYMAX(intel_plane->pipe)); 208235783Skib key->channel_mask = I915_READ(SPRKEYMSK(intel_plane->pipe)); 209235783Skib key->flags = 0; 210235783Skib 211235783Skib sprctl = I915_READ(SPRCTL(intel_plane->pipe)); 212235783Skib 213235783Skib if (sprctl & SPRITE_DEST_KEY) 214235783Skib key->flags = I915_SET_COLORKEY_DESTINATION; 215235783Skib else if (sprctl & SPRITE_SOURCE_KEY) 216235783Skib key->flags = I915_SET_COLORKEY_SOURCE; 217235783Skib else 218235783Skib key->flags = I915_SET_COLORKEY_NONE; 219235783Skib} 220235783Skib 221235783Skibstatic void 222280369Skibilk_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, 223235783Skib struct drm_i915_gem_object *obj, int crtc_x, int crtc_y, 224235783Skib unsigned int crtc_w, unsigned int crtc_h, 225235783Skib uint32_t x, uint32_t y, 226235783Skib uint32_t src_w, uint32_t src_h) 227235783Skib{ 228235783Skib struct drm_device *dev = plane->dev; 229235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 230235783Skib struct intel_plane *intel_plane = to_intel_plane(plane); 231235783Skib int pipe = intel_plane->pipe, pixel_size; 232280369Skib u32 dvscntr, dvsscale; 233235783Skib 234235783Skib dvscntr = I915_READ(DVSCNTR(pipe)); 235235783Skib 236235783Skib /* Mask out pixel format bits in case we change it */ 237235783Skib dvscntr &= ~DVS_PIXFORMAT_MASK; 238235783Skib dvscntr &= ~DVS_RGB_ORDER_XBGR; 239235783Skib dvscntr &= ~DVS_YUV_BYTE_ORDER_MASK; 240235783Skib 241235783Skib switch (fb->pixel_format) { 242235783Skib case DRM_FORMAT_XBGR8888: 243235783Skib dvscntr |= DVS_FORMAT_RGBX888 | DVS_RGB_ORDER_XBGR; 244235783Skib pixel_size = 4; 245235783Skib break; 246235783Skib case DRM_FORMAT_XRGB8888: 247235783Skib dvscntr |= DVS_FORMAT_RGBX888; 248235783Skib pixel_size = 4; 249235783Skib break; 250235783Skib case DRM_FORMAT_YUYV: 251235783Skib dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YUYV; 252235783Skib pixel_size = 2; 253235783Skib break; 254235783Skib case DRM_FORMAT_YVYU: 255235783Skib dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YVYU; 256235783Skib pixel_size = 2; 257235783Skib break; 258235783Skib case DRM_FORMAT_UYVY: 259235783Skib dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_UYVY; 260235783Skib pixel_size = 2; 261235783Skib break; 262235783Skib case DRM_FORMAT_VYUY: 263235783Skib dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_VYUY; 264235783Skib pixel_size = 2; 265235783Skib break; 266235783Skib default: 267235783Skib DRM_DEBUG_DRIVER("bad pixel format, assuming RGBX888\n"); 268235783Skib dvscntr |= DVS_FORMAT_RGBX888; 269235783Skib pixel_size = 4; 270235783Skib break; 271235783Skib } 272235783Skib 273235783Skib if (obj->tiling_mode != I915_TILING_NONE) 274235783Skib dvscntr |= DVS_TILED; 275235783Skib 276280369Skib if (IS_GEN6(dev)) 277280369Skib dvscntr |= DVS_TRICKLE_FEED_DISABLE; /* must disable */ 278235783Skib dvscntr |= DVS_ENABLE; 279235783Skib 280235783Skib /* Sizes are 0 based */ 281235783Skib src_w--; 282235783Skib src_h--; 283235783Skib crtc_w--; 284235783Skib crtc_h--; 285235783Skib 286235783Skib intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size); 287235783Skib 288280369Skib dvsscale = 0; 289280369Skib if (IS_GEN5(dev) || crtc_w != src_w || crtc_h != src_h) 290235783Skib dvsscale = DVS_SCALE_ENABLE | (src_w << 16) | src_h; 291235783Skib 292235783Skib I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]); 293235783Skib I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x); 294235783Skib if (obj->tiling_mode != I915_TILING_NONE) { 295235783Skib I915_WRITE(DVSTILEOFF(pipe), (y << 16) | x); 296235783Skib } else { 297235783Skib unsigned long offset; 298235783Skib 299235783Skib offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8); 300235783Skib I915_WRITE(DVSLINOFF(pipe), offset); 301235783Skib } 302235783Skib I915_WRITE(DVSSIZE(pipe), (crtc_h << 16) | crtc_w); 303235783Skib I915_WRITE(DVSSCALE(pipe), dvsscale); 304235783Skib I915_WRITE(DVSCNTR(pipe), dvscntr); 305280369Skib I915_MODIFY_DISPBASE(DVSSURF(pipe), obj->gtt_offset); 306235783Skib POSTING_READ(DVSSURF(pipe)); 307235783Skib} 308235783Skib 309235783Skibstatic void 310280369Skibilk_disable_plane(struct drm_plane *plane) 311235783Skib{ 312235783Skib struct drm_device *dev = plane->dev; 313235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 314235783Skib struct intel_plane *intel_plane = to_intel_plane(plane); 315235783Skib int pipe = intel_plane->pipe; 316235783Skib 317235783Skib I915_WRITE(DVSCNTR(pipe), I915_READ(DVSCNTR(pipe)) & ~DVS_ENABLE); 318235783Skib /* Disable the scaler */ 319235783Skib I915_WRITE(DVSSCALE(pipe), 0); 320235783Skib /* Flush double buffered register updates */ 321280369Skib I915_MODIFY_DISPBASE(DVSSURF(pipe), 0); 322235783Skib POSTING_READ(DVSSURF(pipe)); 323235783Skib} 324235783Skib 325235783Skibstatic void 326235783Skibintel_enable_primary(struct drm_crtc *crtc) 327235783Skib{ 328235783Skib struct drm_device *dev = crtc->dev; 329235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 330235783Skib struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 331235783Skib int reg = DSPCNTR(intel_crtc->plane); 332235783Skib 333235783Skib I915_WRITE(reg, I915_READ(reg) | DISPLAY_PLANE_ENABLE); 334235783Skib} 335235783Skib 336235783Skibstatic void 337235783Skibintel_disable_primary(struct drm_crtc *crtc) 338235783Skib{ 339235783Skib struct drm_device *dev = crtc->dev; 340235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 341235783Skib struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 342235783Skib int reg = DSPCNTR(intel_crtc->plane); 343235783Skib 344235783Skib I915_WRITE(reg, I915_READ(reg) & ~DISPLAY_PLANE_ENABLE); 345235783Skib} 346235783Skib 347235783Skibstatic int 348280369Skibilk_update_colorkey(struct drm_plane *plane, 349235783Skib struct drm_intel_sprite_colorkey *key) 350235783Skib{ 351235783Skib struct drm_device *dev = plane->dev; 352235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 353235783Skib struct intel_plane *intel_plane; 354235783Skib u32 dvscntr; 355235783Skib int ret = 0; 356235783Skib 357235783Skib intel_plane = to_intel_plane(plane); 358235783Skib 359235783Skib I915_WRITE(DVSKEYVAL(intel_plane->pipe), key->min_value); 360235783Skib I915_WRITE(DVSKEYMAX(intel_plane->pipe), key->max_value); 361235783Skib I915_WRITE(DVSKEYMSK(intel_plane->pipe), key->channel_mask); 362235783Skib 363235783Skib dvscntr = I915_READ(DVSCNTR(intel_plane->pipe)); 364235783Skib dvscntr &= ~(DVS_SOURCE_KEY | DVS_DEST_KEY); 365235783Skib if (key->flags & I915_SET_COLORKEY_DESTINATION) 366235783Skib dvscntr |= DVS_DEST_KEY; 367235783Skib else if (key->flags & I915_SET_COLORKEY_SOURCE) 368235783Skib dvscntr |= DVS_SOURCE_KEY; 369235783Skib I915_WRITE(DVSCNTR(intel_plane->pipe), dvscntr); 370235783Skib 371235783Skib POSTING_READ(DVSKEYMSK(intel_plane->pipe)); 372235783Skib 373235783Skib return ret; 374235783Skib} 375235783Skib 376235783Skibstatic void 377280369Skibilk_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key) 378235783Skib{ 379235783Skib struct drm_device *dev = plane->dev; 380235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 381235783Skib struct intel_plane *intel_plane; 382235783Skib u32 dvscntr; 383235783Skib 384235783Skib intel_plane = to_intel_plane(plane); 385235783Skib 386235783Skib key->min_value = I915_READ(DVSKEYVAL(intel_plane->pipe)); 387235783Skib key->max_value = I915_READ(DVSKEYMAX(intel_plane->pipe)); 388235783Skib key->channel_mask = I915_READ(DVSKEYMSK(intel_plane->pipe)); 389235783Skib key->flags = 0; 390235783Skib 391235783Skib dvscntr = I915_READ(DVSCNTR(intel_plane->pipe)); 392235783Skib 393235783Skib if (dvscntr & DVS_DEST_KEY) 394235783Skib key->flags = I915_SET_COLORKEY_DESTINATION; 395235783Skib else if (dvscntr & DVS_SOURCE_KEY) 396235783Skib key->flags = I915_SET_COLORKEY_SOURCE; 397235783Skib else 398235783Skib key->flags = I915_SET_COLORKEY_NONE; 399235783Skib} 400235783Skib 401235783Skibstatic int 402235783Skibintel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, 403235783Skib struct drm_framebuffer *fb, int crtc_x, int crtc_y, 404235783Skib unsigned int crtc_w, unsigned int crtc_h, 405235783Skib uint32_t src_x, uint32_t src_y, 406235783Skib uint32_t src_w, uint32_t src_h) 407235783Skib{ 408235783Skib struct drm_device *dev = plane->dev; 409235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 410235783Skib struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 411235783Skib struct intel_plane *intel_plane = to_intel_plane(plane); 412235783Skib struct intel_framebuffer *intel_fb; 413235783Skib struct drm_i915_gem_object *obj, *old_obj; 414235783Skib int pipe = intel_plane->pipe; 415235783Skib int ret = 0; 416235783Skib int x = src_x >> 16, y = src_y >> 16; 417235783Skib int primary_w = crtc->mode.hdisplay, primary_h = crtc->mode.vdisplay; 418235783Skib bool disable_primary = false; 419235783Skib 420235783Skib intel_fb = to_intel_framebuffer(fb); 421235783Skib obj = intel_fb->obj; 422235783Skib 423235783Skib old_obj = intel_plane->obj; 424235783Skib 425235783Skib src_w = src_w >> 16; 426235783Skib src_h = src_h >> 16; 427235783Skib 428235783Skib /* Pipe must be running... */ 429235783Skib if (!(I915_READ(PIPECONF(pipe)) & PIPECONF_ENABLE)) 430235783Skib return -EINVAL; 431235783Skib 432235783Skib if (crtc_x >= primary_w || crtc_y >= primary_h) 433235783Skib return -EINVAL; 434235783Skib 435235783Skib /* Don't modify another pipe's plane */ 436235783Skib if (intel_plane->pipe != intel_crtc->pipe) 437235783Skib return -EINVAL; 438235783Skib 439235783Skib /* 440235783Skib * Clamp the width & height into the visible area. Note we don't 441235783Skib * try to scale the source if part of the visible region is offscreen. 442235783Skib * The caller must handle that by adjusting source offset and size. 443235783Skib */ 444235783Skib if ((crtc_x < 0) && ((crtc_x + crtc_w) > 0)) { 445235783Skib crtc_w += crtc_x; 446235783Skib crtc_x = 0; 447235783Skib } 448235783Skib if ((crtc_x + crtc_w) <= 0) /* Nothing to display */ 449235783Skib goto out; 450235783Skib if ((crtc_x + crtc_w) > primary_w) 451235783Skib crtc_w = primary_w - crtc_x; 452235783Skib 453235783Skib if ((crtc_y < 0) && ((crtc_y + crtc_h) > 0)) { 454235783Skib crtc_h += crtc_y; 455235783Skib crtc_y = 0; 456235783Skib } 457235783Skib if ((crtc_y + crtc_h) <= 0) /* Nothing to display */ 458235783Skib goto out; 459235783Skib if (crtc_y + crtc_h > primary_h) 460235783Skib crtc_h = primary_h - crtc_y; 461235783Skib 462235783Skib if (!crtc_w || !crtc_h) /* Again, nothing to display */ 463235783Skib goto out; 464235783Skib 465235783Skib /* 466235783Skib * We can take a larger source and scale it down, but 467235783Skib * only so much... 16x is the max on SNB. 468235783Skib */ 469235783Skib if (((src_w * src_h) / (crtc_w * crtc_h)) > intel_plane->max_downscale) 470235783Skib return -EINVAL; 471235783Skib 472235783Skib /* 473235783Skib * If the sprite is completely covering the primary plane, 474235783Skib * we can disable the primary and save power. 475235783Skib */ 476235783Skib if ((crtc_x == 0) && (crtc_y == 0) && 477235783Skib (crtc_w == primary_w) && (crtc_h == primary_h)) 478235783Skib disable_primary = true; 479235783Skib 480235783Skib DRM_LOCK(dev); 481235783Skib 482235783Skib ret = intel_pin_and_fence_fb_obj(dev, obj, NULL); 483235783Skib if (ret) 484235783Skib goto out_unlock; 485235783Skib 486235783Skib intel_plane->obj = obj; 487235783Skib 488235783Skib /* 489235783Skib * Be sure to re-enable the primary before the sprite is no longer 490235783Skib * covering it fully. 491235783Skib */ 492235783Skib if (!disable_primary && intel_plane->primary_disabled) { 493235783Skib intel_enable_primary(crtc); 494235783Skib intel_plane->primary_disabled = false; 495235783Skib } 496235783Skib 497235783Skib intel_plane->update_plane(plane, fb, obj, crtc_x, crtc_y, 498235783Skib crtc_w, crtc_h, x, y, src_w, src_h); 499235783Skib 500235783Skib if (disable_primary) { 501235783Skib intel_disable_primary(crtc); 502235783Skib intel_plane->primary_disabled = true; 503235783Skib } 504235783Skib 505235783Skib /* Unpin old obj after new one is active to avoid ugliness */ 506235783Skib if (old_obj) { 507235783Skib /* 508235783Skib * It's fairly common to simply update the position of 509235783Skib * an existing object. In that case, we don't need to 510235783Skib * wait for vblank to avoid ugliness, we only need to 511235783Skib * do the pin & ref bookkeeping. 512235783Skib */ 513235783Skib if (old_obj != obj) { 514235783Skib DRM_UNLOCK(dev); 515235783Skib intel_wait_for_vblank(dev, to_intel_crtc(crtc)->pipe); 516235783Skib DRM_LOCK(dev); 517235783Skib } 518235783Skib intel_unpin_fb_obj(old_obj); 519235783Skib } 520235783Skib 521235783Skibout_unlock: 522235783Skib DRM_UNLOCK(dev); 523235783Skibout: 524235783Skib return ret; 525235783Skib} 526235783Skib 527235783Skibstatic int 528235783Skibintel_disable_plane(struct drm_plane *plane) 529235783Skib{ 530235783Skib struct drm_device *dev = plane->dev; 531235783Skib struct intel_plane *intel_plane = to_intel_plane(plane); 532235783Skib int ret = 0; 533235783Skib 534235783Skib if (intel_plane->primary_disabled) { 535235783Skib intel_enable_primary(plane->crtc); 536235783Skib intel_plane->primary_disabled = false; 537235783Skib } 538235783Skib 539235783Skib intel_plane->disable_plane(plane); 540235783Skib 541235783Skib if (!intel_plane->obj) 542235783Skib goto out; 543235783Skib 544235783Skib DRM_LOCK(dev); 545235783Skib intel_unpin_fb_obj(intel_plane->obj); 546235783Skib intel_plane->obj = NULL; 547235783Skib DRM_UNLOCK(dev); 548235783Skibout: 549235783Skib 550235783Skib return ret; 551235783Skib} 552235783Skib 553235783Skibstatic void intel_destroy_plane(struct drm_plane *plane) 554235783Skib{ 555235783Skib struct intel_plane *intel_plane = to_intel_plane(plane); 556235783Skib intel_disable_plane(plane); 557235783Skib drm_plane_cleanup(plane); 558235783Skib free(intel_plane, DRM_MEM_KMS); 559235783Skib} 560235783Skib 561235783Skibint intel_sprite_set_colorkey(struct drm_device *dev, void *data, 562235783Skib struct drm_file *file_priv) 563235783Skib{ 564235783Skib struct drm_intel_sprite_colorkey *set = data; 565235783Skib struct drm_mode_object *obj; 566235783Skib struct drm_plane *plane; 567235783Skib struct intel_plane *intel_plane; 568235783Skib int ret = 0; 569235783Skib 570280369Skib if (!drm_core_check_feature(dev, DRIVER_MODESET)) 571280369Skib return -ENODEV; 572235783Skib 573235783Skib /* Make sure we don't try to enable both src & dest simultaneously */ 574235783Skib if ((set->flags & (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) == (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) 575235783Skib return -EINVAL; 576235783Skib 577235783Skib sx_xlock(&dev->mode_config.mutex); 578235783Skib 579235783Skib obj = drm_mode_object_find(dev, set->plane_id, DRM_MODE_OBJECT_PLANE); 580235783Skib if (!obj) { 581235783Skib ret = -EINVAL; 582235783Skib goto out_unlock; 583235783Skib } 584235783Skib 585235783Skib plane = obj_to_plane(obj); 586235783Skib intel_plane = to_intel_plane(plane); 587235783Skib ret = intel_plane->update_colorkey(plane, set); 588235783Skib 589235783Skibout_unlock: 590235783Skib sx_xunlock(&dev->mode_config.mutex); 591235783Skib return ret; 592235783Skib} 593235783Skib 594235783Skibint intel_sprite_get_colorkey(struct drm_device *dev, void *data, 595235783Skib struct drm_file *file_priv) 596235783Skib{ 597235783Skib struct drm_intel_sprite_colorkey *get = data; 598235783Skib struct drm_mode_object *obj; 599235783Skib struct drm_plane *plane; 600235783Skib struct intel_plane *intel_plane; 601235783Skib int ret = 0; 602235783Skib 603280369Skib if (!drm_core_check_feature(dev, DRIVER_MODESET)) 604280369Skib return -ENODEV; 605235783Skib 606235783Skib sx_xlock(&dev->mode_config.mutex); 607235783Skib 608235783Skib obj = drm_mode_object_find(dev, get->plane_id, DRM_MODE_OBJECT_PLANE); 609235783Skib if (!obj) { 610235783Skib ret = -EINVAL; 611235783Skib goto out_unlock; 612235783Skib } 613235783Skib 614235783Skib plane = obj_to_plane(obj); 615235783Skib intel_plane = to_intel_plane(plane); 616235783Skib intel_plane->get_colorkey(plane, get); 617235783Skib 618235783Skibout_unlock: 619235783Skib sx_xunlock(&dev->mode_config.mutex); 620235783Skib return ret; 621235783Skib} 622235783Skib 623235783Skibstatic const struct drm_plane_funcs intel_plane_funcs = { 624235783Skib .update_plane = intel_update_plane, 625235783Skib .disable_plane = intel_disable_plane, 626235783Skib .destroy = intel_destroy_plane, 627235783Skib}; 628235783Skib 629280369Skibstatic uint32_t ilk_plane_formats[] = { 630280369Skib DRM_FORMAT_XRGB8888, 631280369Skib DRM_FORMAT_YUYV, 632280369Skib DRM_FORMAT_YVYU, 633280369Skib DRM_FORMAT_UYVY, 634280369Skib DRM_FORMAT_VYUY, 635280369Skib}; 636280369Skib 637235783Skibstatic uint32_t snb_plane_formats[] = { 638235783Skib DRM_FORMAT_XBGR8888, 639235783Skib DRM_FORMAT_XRGB8888, 640235783Skib DRM_FORMAT_YUYV, 641235783Skib DRM_FORMAT_YVYU, 642235783Skib DRM_FORMAT_UYVY, 643235783Skib DRM_FORMAT_VYUY, 644235783Skib}; 645235783Skib 646235783Skibint 647235783Skibintel_plane_init(struct drm_device *dev, enum pipe pipe) 648235783Skib{ 649235783Skib struct intel_plane *intel_plane; 650235783Skib unsigned long possible_crtcs; 651280369Skib const uint32_t *plane_formats; 652280369Skib int num_plane_formats; 653235783Skib int ret; 654235783Skib 655280369Skib if (INTEL_INFO(dev)->gen < 5) 656235783Skib return -ENODEV; 657235783Skib 658235783Skib intel_plane = malloc(sizeof(struct intel_plane), DRM_MEM_KMS, 659235783Skib M_WAITOK | M_ZERO); 660235783Skib 661280369Skib switch (INTEL_INFO(dev)->gen) { 662280369Skib case 5: 663280369Skib case 6: 664235783Skib intel_plane->max_downscale = 16; 665280369Skib intel_plane->update_plane = ilk_update_plane; 666280369Skib intel_plane->disable_plane = ilk_disable_plane; 667280369Skib intel_plane->update_colorkey = ilk_update_colorkey; 668280369Skib intel_plane->get_colorkey = ilk_get_colorkey; 669280369Skib 670280369Skib if (IS_GEN6(dev)) { 671280369Skib plane_formats = snb_plane_formats; 672280369Skib num_plane_formats = DRM_ARRAY_SIZE(snb_plane_formats); 673280369Skib } else { 674280369Skib plane_formats = ilk_plane_formats; 675280369Skib num_plane_formats = DRM_ARRAY_SIZE(ilk_plane_formats); 676280369Skib } 677280369Skib break; 678280369Skib 679280369Skib case 7: 680235783Skib intel_plane->max_downscale = 2; 681235783Skib intel_plane->update_plane = ivb_update_plane; 682235783Skib intel_plane->disable_plane = ivb_disable_plane; 683235783Skib intel_plane->update_colorkey = ivb_update_colorkey; 684235783Skib intel_plane->get_colorkey = ivb_get_colorkey; 685280369Skib 686280369Skib plane_formats = snb_plane_formats; 687280369Skib num_plane_formats = DRM_ARRAY_SIZE(snb_plane_formats); 688280369Skib break; 689280369Skib 690280369Skib default: 691280369Skib return -ENODEV; 692235783Skib } 693235783Skib 694235783Skib intel_plane->pipe = pipe; 695235783Skib possible_crtcs = (1 << pipe); 696235783Skib ret = drm_plane_init(dev, &intel_plane->base, possible_crtcs, 697280369Skib &intel_plane_funcs, 698280369Skib plane_formats, num_plane_formats, 699280369Skib false); 700235783Skib if (ret) 701235783Skib free(intel_plane, DRM_MEM_KMS); 702235783Skib 703235783Skib return ret; 704235783Skib} 705235783Skib 706