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