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> 355d0b1887SFrançois Tigeot #include <drm/drm_rect.h> 3618e26a6dSFrançois Tigeot #include "intel_drv.h" 375c6c6f23SFrançois Tigeot #include <drm/i915_drm.h> 38e3adcf8fSFrançois Tigeot #include "i915_drv.h" 39e3adcf8fSFrançois Tigeot 40e3adcf8fSFrançois Tigeot static void 41*9edbd4a0SFrançois Tigeot vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, 42*9edbd4a0SFrançois Tigeot struct drm_framebuffer *fb, 438e26cdf6SFrançois Tigeot struct drm_i915_gem_object *obj, int crtc_x, int crtc_y, 448e26cdf6SFrançois Tigeot unsigned int crtc_w, unsigned int crtc_h, 458e26cdf6SFrançois Tigeot uint32_t x, uint32_t y, 468e26cdf6SFrançois Tigeot uint32_t src_w, uint32_t src_h) 478e26cdf6SFrançois Tigeot { 488e26cdf6SFrançois Tigeot struct drm_device *dev = dplane->dev; 498e26cdf6SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 508e26cdf6SFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(dplane); 518e26cdf6SFrançois Tigeot int pipe = intel_plane->pipe; 528e26cdf6SFrançois Tigeot int plane = intel_plane->plane; 538e26cdf6SFrançois Tigeot u32 sprctl; 548e26cdf6SFrançois Tigeot unsigned long sprsurf_offset, linear_offset; 558e26cdf6SFrançois Tigeot int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); 568e26cdf6SFrançois Tigeot 578e26cdf6SFrançois Tigeot sprctl = I915_READ(SPCNTR(pipe, plane)); 588e26cdf6SFrançois Tigeot 598e26cdf6SFrançois Tigeot /* Mask out pixel format bits in case we change it */ 608e26cdf6SFrançois Tigeot sprctl &= ~SP_PIXFORMAT_MASK; 618e26cdf6SFrançois Tigeot sprctl &= ~SP_YUV_BYTE_ORDER_MASK; 628e26cdf6SFrançois Tigeot sprctl &= ~SP_TILED; 638e26cdf6SFrançois Tigeot 648e26cdf6SFrançois Tigeot switch (fb->pixel_format) { 658e26cdf6SFrançois Tigeot case DRM_FORMAT_YUYV: 668e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_YUYV; 678e26cdf6SFrançois Tigeot break; 688e26cdf6SFrançois Tigeot case DRM_FORMAT_YVYU: 698e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_YVYU; 708e26cdf6SFrançois Tigeot break; 718e26cdf6SFrançois Tigeot case DRM_FORMAT_UYVY: 728e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_UYVY; 738e26cdf6SFrançois Tigeot break; 748e26cdf6SFrançois Tigeot case DRM_FORMAT_VYUY: 758e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_VYUY; 768e26cdf6SFrançois Tigeot break; 778e26cdf6SFrançois Tigeot case DRM_FORMAT_RGB565: 788e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_BGR565; 798e26cdf6SFrançois Tigeot break; 808e26cdf6SFrançois Tigeot case DRM_FORMAT_XRGB8888: 818e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_BGRX8888; 828e26cdf6SFrançois Tigeot break; 838e26cdf6SFrançois Tigeot case DRM_FORMAT_ARGB8888: 848e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_BGRA8888; 858e26cdf6SFrançois Tigeot break; 868e26cdf6SFrançois Tigeot case DRM_FORMAT_XBGR2101010: 878e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_RGBX1010102; 888e26cdf6SFrançois Tigeot break; 898e26cdf6SFrançois Tigeot case DRM_FORMAT_ABGR2101010: 908e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_RGBA1010102; 918e26cdf6SFrançois Tigeot break; 928e26cdf6SFrançois Tigeot case DRM_FORMAT_XBGR8888: 938e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_RGBX8888; 948e26cdf6SFrançois Tigeot break; 958e26cdf6SFrançois Tigeot case DRM_FORMAT_ABGR8888: 968e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_RGBA8888; 978e26cdf6SFrançois Tigeot break; 988e26cdf6SFrançois Tigeot default: 998e26cdf6SFrançois Tigeot /* 1008e26cdf6SFrançois Tigeot * If we get here one of the upper layers failed to filter 1018e26cdf6SFrançois Tigeot * out the unsupported plane formats 1028e26cdf6SFrançois Tigeot */ 1038e26cdf6SFrançois Tigeot BUG(); 1048e26cdf6SFrançois Tigeot break; 1058e26cdf6SFrançois Tigeot } 1068e26cdf6SFrançois Tigeot 107*9edbd4a0SFrançois Tigeot /* 108*9edbd4a0SFrançois Tigeot * Enable gamma to match primary/cursor plane behaviour. 109*9edbd4a0SFrançois Tigeot * FIXME should be user controllable via propertiesa. 110*9edbd4a0SFrançois Tigeot */ 111*9edbd4a0SFrançois Tigeot sprctl |= SP_GAMMA_ENABLE; 112*9edbd4a0SFrançois Tigeot 1138e26cdf6SFrançois Tigeot if (obj->tiling_mode != I915_TILING_NONE) 1148e26cdf6SFrançois Tigeot sprctl |= SP_TILED; 1158e26cdf6SFrançois Tigeot 1168e26cdf6SFrançois Tigeot sprctl |= SP_ENABLE; 1178e26cdf6SFrançois Tigeot 118*9edbd4a0SFrançois Tigeot intel_update_sprite_watermarks(dplane, crtc, src_w, pixel_size, true, 119*9edbd4a0SFrançois Tigeot src_w != crtc_w || src_h != crtc_h); 120*9edbd4a0SFrançois Tigeot 1218e26cdf6SFrançois Tigeot /* Sizes are 0 based */ 1228e26cdf6SFrançois Tigeot src_w--; 1238e26cdf6SFrançois Tigeot src_h--; 1248e26cdf6SFrançois Tigeot crtc_w--; 1258e26cdf6SFrançois Tigeot crtc_h--; 1268e26cdf6SFrançois Tigeot 1278e26cdf6SFrançois Tigeot I915_WRITE(SPSTRIDE(pipe, plane), fb->pitches[0]); 1288e26cdf6SFrançois Tigeot I915_WRITE(SPPOS(pipe, plane), (crtc_y << 16) | crtc_x); 1298e26cdf6SFrançois Tigeot 1308e26cdf6SFrançois Tigeot linear_offset = y * fb->pitches[0] + x * pixel_size; 1318e26cdf6SFrançois Tigeot sprsurf_offset = intel_gen4_compute_page_offset(&x, &y, 1328e26cdf6SFrançois Tigeot obj->tiling_mode, 1338e26cdf6SFrançois Tigeot pixel_size, 1348e26cdf6SFrançois Tigeot fb->pitches[0]); 1358e26cdf6SFrançois Tigeot linear_offset -= sprsurf_offset; 1368e26cdf6SFrançois Tigeot 1378e26cdf6SFrançois Tigeot if (obj->tiling_mode != I915_TILING_NONE) 1388e26cdf6SFrançois Tigeot I915_WRITE(SPTILEOFF(pipe, plane), (y << 16) | x); 1398e26cdf6SFrançois Tigeot else 1408e26cdf6SFrançois Tigeot I915_WRITE(SPLINOFF(pipe, plane), linear_offset); 1418e26cdf6SFrançois Tigeot 1428e26cdf6SFrançois Tigeot I915_WRITE(SPSIZE(pipe, plane), (crtc_h << 16) | crtc_w); 1438e26cdf6SFrançois Tigeot I915_WRITE(SPCNTR(pipe, plane), sprctl); 144*9edbd4a0SFrançois Tigeot I915_WRITE(SPSURF(pipe, plane), i915_gem_obj_ggtt_offset(obj) + 1458e26cdf6SFrançois Tigeot sprsurf_offset); 1468e26cdf6SFrançois Tigeot POSTING_READ(SPSURF(pipe, plane)); 1478e26cdf6SFrançois Tigeot } 1488e26cdf6SFrançois Tigeot 1498e26cdf6SFrançois Tigeot static void 150*9edbd4a0SFrançois Tigeot vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc) 1518e26cdf6SFrançois Tigeot { 1528e26cdf6SFrançois Tigeot struct drm_device *dev = dplane->dev; 1538e26cdf6SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 1548e26cdf6SFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(dplane); 1558e26cdf6SFrançois Tigeot int pipe = intel_plane->pipe; 1568e26cdf6SFrançois Tigeot int plane = intel_plane->plane; 1578e26cdf6SFrançois Tigeot 1588e26cdf6SFrançois Tigeot I915_WRITE(SPCNTR(pipe, plane), I915_READ(SPCNTR(pipe, plane)) & 1598e26cdf6SFrançois Tigeot ~SP_ENABLE); 1608e26cdf6SFrançois Tigeot /* Activate double buffered register update */ 161*9edbd4a0SFrançois Tigeot I915_WRITE(SPSURF(pipe, plane), 0); 1628e26cdf6SFrançois Tigeot POSTING_READ(SPSURF(pipe, plane)); 163*9edbd4a0SFrançois Tigeot 164*9edbd4a0SFrançois Tigeot intel_update_sprite_watermarks(dplane, crtc, 0, 0, false, false); 1658e26cdf6SFrançois Tigeot } 1668e26cdf6SFrançois Tigeot 1678e26cdf6SFrançois Tigeot static int 1688e26cdf6SFrançois Tigeot vlv_update_colorkey(struct drm_plane *dplane, 1698e26cdf6SFrançois Tigeot struct drm_intel_sprite_colorkey *key) 1708e26cdf6SFrançois Tigeot { 1718e26cdf6SFrançois Tigeot struct drm_device *dev = dplane->dev; 1728e26cdf6SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 1738e26cdf6SFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(dplane); 1748e26cdf6SFrançois Tigeot int pipe = intel_plane->pipe; 1758e26cdf6SFrançois Tigeot int plane = intel_plane->plane; 1768e26cdf6SFrançois Tigeot u32 sprctl; 1778e26cdf6SFrançois Tigeot 1788e26cdf6SFrançois Tigeot if (key->flags & I915_SET_COLORKEY_DESTINATION) 1798e26cdf6SFrançois Tigeot return -EINVAL; 1808e26cdf6SFrançois Tigeot 1818e26cdf6SFrançois Tigeot I915_WRITE(SPKEYMINVAL(pipe, plane), key->min_value); 1828e26cdf6SFrançois Tigeot I915_WRITE(SPKEYMAXVAL(pipe, plane), key->max_value); 1838e26cdf6SFrançois Tigeot I915_WRITE(SPKEYMSK(pipe, plane), key->channel_mask); 1848e26cdf6SFrançois Tigeot 1858e26cdf6SFrançois Tigeot sprctl = I915_READ(SPCNTR(pipe, plane)); 1868e26cdf6SFrançois Tigeot sprctl &= ~SP_SOURCE_KEY; 1878e26cdf6SFrançois Tigeot if (key->flags & I915_SET_COLORKEY_SOURCE) 1888e26cdf6SFrançois Tigeot sprctl |= SP_SOURCE_KEY; 1898e26cdf6SFrançois Tigeot I915_WRITE(SPCNTR(pipe, plane), sprctl); 1908e26cdf6SFrançois Tigeot 1918e26cdf6SFrançois Tigeot POSTING_READ(SPKEYMSK(pipe, plane)); 1928e26cdf6SFrançois Tigeot 1938e26cdf6SFrançois Tigeot return 0; 1948e26cdf6SFrançois Tigeot } 1958e26cdf6SFrançois Tigeot 1968e26cdf6SFrançois Tigeot static void 1978e26cdf6SFrançois Tigeot vlv_get_colorkey(struct drm_plane *dplane, 1988e26cdf6SFrançois Tigeot struct drm_intel_sprite_colorkey *key) 1998e26cdf6SFrançois Tigeot { 2008e26cdf6SFrançois Tigeot struct drm_device *dev = dplane->dev; 2018e26cdf6SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 2028e26cdf6SFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(dplane); 2038e26cdf6SFrançois Tigeot int pipe = intel_plane->pipe; 2048e26cdf6SFrançois Tigeot int plane = intel_plane->plane; 2058e26cdf6SFrançois Tigeot u32 sprctl; 2068e26cdf6SFrançois Tigeot 2078e26cdf6SFrançois Tigeot key->min_value = I915_READ(SPKEYMINVAL(pipe, plane)); 2088e26cdf6SFrançois Tigeot key->max_value = I915_READ(SPKEYMAXVAL(pipe, plane)); 2098e26cdf6SFrançois Tigeot key->channel_mask = I915_READ(SPKEYMSK(pipe, plane)); 2108e26cdf6SFrançois Tigeot 2118e26cdf6SFrançois Tigeot sprctl = I915_READ(SPCNTR(pipe, plane)); 2128e26cdf6SFrançois Tigeot if (sprctl & SP_SOURCE_KEY) 2138e26cdf6SFrançois Tigeot key->flags = I915_SET_COLORKEY_SOURCE; 2148e26cdf6SFrançois Tigeot else 2158e26cdf6SFrançois Tigeot key->flags = I915_SET_COLORKEY_NONE; 2168e26cdf6SFrançois Tigeot } 2178e26cdf6SFrançois Tigeot 2188e26cdf6SFrançois Tigeot static void 219*9edbd4a0SFrançois Tigeot ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, 220*9edbd4a0SFrançois Tigeot struct drm_framebuffer *fb, 221e3adcf8fSFrançois Tigeot struct drm_i915_gem_object *obj, int crtc_x, int crtc_y, 222e3adcf8fSFrançois Tigeot unsigned int crtc_w, unsigned int crtc_h, 223e3adcf8fSFrançois Tigeot uint32_t x, uint32_t y, 224e3adcf8fSFrançois Tigeot uint32_t src_w, uint32_t src_h) 225e3adcf8fSFrançois Tigeot { 226e3adcf8fSFrançois Tigeot struct drm_device *dev = plane->dev; 227e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 228e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(plane); 229e3adcf8fSFrançois Tigeot int pipe = intel_plane->pipe; 230e3adcf8fSFrançois Tigeot u32 sprctl, sprscale = 0; 2312c84b0b6SFrançois Tigeot unsigned long sprsurf_offset, linear_offset; 2322c84b0b6SFrançois Tigeot int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); 233e3adcf8fSFrançois Tigeot 234e3adcf8fSFrançois Tigeot sprctl = I915_READ(SPRCTL(pipe)); 235e3adcf8fSFrançois Tigeot 236e3adcf8fSFrançois Tigeot /* Mask out pixel format bits in case we change it */ 237e3adcf8fSFrançois Tigeot sprctl &= ~SPRITE_PIXFORMAT_MASK; 238e3adcf8fSFrançois Tigeot sprctl &= ~SPRITE_RGB_ORDER_RGBX; 239e3adcf8fSFrançois Tigeot sprctl &= ~SPRITE_YUV_BYTE_ORDER_MASK; 2402c84b0b6SFrançois Tigeot sprctl &= ~SPRITE_TILED; 241e3adcf8fSFrançois Tigeot 242e3adcf8fSFrançois Tigeot switch (fb->pixel_format) { 243e3adcf8fSFrançois Tigeot case DRM_FORMAT_XBGR8888: 2442c84b0b6SFrançois Tigeot sprctl |= SPRITE_FORMAT_RGBX888 | SPRITE_RGB_ORDER_RGBX; 245e3adcf8fSFrançois Tigeot break; 246e3adcf8fSFrançois Tigeot case DRM_FORMAT_XRGB8888: 2472c84b0b6SFrançois Tigeot sprctl |= SPRITE_FORMAT_RGBX888; 248e3adcf8fSFrançois Tigeot break; 249e3adcf8fSFrançois Tigeot case DRM_FORMAT_YUYV: 250e3adcf8fSFrançois Tigeot sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YUYV; 251e3adcf8fSFrançois Tigeot break; 252e3adcf8fSFrançois Tigeot case DRM_FORMAT_YVYU: 253e3adcf8fSFrançois Tigeot sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YVYU; 254e3adcf8fSFrançois Tigeot break; 255e3adcf8fSFrançois Tigeot case DRM_FORMAT_UYVY: 256e3adcf8fSFrançois Tigeot sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_UYVY; 257e3adcf8fSFrançois Tigeot break; 258e3adcf8fSFrançois Tigeot case DRM_FORMAT_VYUY: 259e3adcf8fSFrançois Tigeot sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_VYUY; 260e3adcf8fSFrançois Tigeot break; 261e3adcf8fSFrançois Tigeot default: 2622c84b0b6SFrançois Tigeot BUG(); 263e3adcf8fSFrançois Tigeot } 264e3adcf8fSFrançois Tigeot 265*9edbd4a0SFrançois Tigeot /* 266*9edbd4a0SFrançois Tigeot * Enable gamma to match primary/cursor plane behaviour. 267*9edbd4a0SFrançois Tigeot * FIXME should be user controllable via propertiesa. 268*9edbd4a0SFrançois Tigeot */ 269*9edbd4a0SFrançois Tigeot sprctl |= SPRITE_GAMMA_ENABLE; 270*9edbd4a0SFrançois Tigeot 271e3adcf8fSFrançois Tigeot if (obj->tiling_mode != I915_TILING_NONE) 272e3adcf8fSFrançois Tigeot sprctl |= SPRITE_TILED; 273e3adcf8fSFrançois Tigeot 274*9edbd4a0SFrançois Tigeot if (IS_HASWELL(dev) || IS_BROADWELL(dev)) 275*9edbd4a0SFrançois Tigeot sprctl &= ~SPRITE_TRICKLE_FEED_DISABLE; 276*9edbd4a0SFrançois Tigeot else 277e3adcf8fSFrançois Tigeot sprctl |= SPRITE_TRICKLE_FEED_DISABLE; 278*9edbd4a0SFrançois Tigeot 279e3adcf8fSFrançois Tigeot sprctl |= SPRITE_ENABLE; 280e3adcf8fSFrançois Tigeot 281*9edbd4a0SFrançois Tigeot if (IS_HASWELL(dev) || IS_BROADWELL(dev)) 282a2fdbec6SFrançois Tigeot sprctl |= SPRITE_PIPE_CSC_ENABLE; 283a2fdbec6SFrançois Tigeot 284*9edbd4a0SFrançois Tigeot intel_update_sprite_watermarks(plane, crtc, src_w, pixel_size, true, 285*9edbd4a0SFrançois Tigeot src_w != crtc_w || src_h != crtc_h); 286*9edbd4a0SFrançois Tigeot 287e3adcf8fSFrançois Tigeot /* Sizes are 0 based */ 288e3adcf8fSFrançois Tigeot src_w--; 289e3adcf8fSFrançois Tigeot src_h--; 290e3adcf8fSFrançois Tigeot crtc_w--; 291e3adcf8fSFrançois Tigeot crtc_h--; 292e3adcf8fSFrançois Tigeot 293*9edbd4a0SFrançois Tigeot if (crtc_w != src_w || crtc_h != src_h) 294e3adcf8fSFrançois Tigeot sprscale = SPRITE_SCALE_ENABLE | (src_w << 16) | src_h; 295e3adcf8fSFrançois Tigeot 296e3adcf8fSFrançois Tigeot I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]); 297e3adcf8fSFrançois Tigeot I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x); 298e3adcf8fSFrançois Tigeot 2992c84b0b6SFrançois Tigeot linear_offset = y * fb->pitches[0] + x * pixel_size; 3002c84b0b6SFrançois Tigeot sprsurf_offset = 301df188185SFrançois Tigeot intel_gen4_compute_page_offset(&x, &y, obj->tiling_mode, 3022c84b0b6SFrançois Tigeot pixel_size, fb->pitches[0]); 3032c84b0b6SFrançois Tigeot linear_offset -= sprsurf_offset; 3042c84b0b6SFrançois Tigeot 3052c84b0b6SFrançois Tigeot /* HSW consolidates SPRTILEOFF and SPRLINOFF into a single SPROFFSET 3062c84b0b6SFrançois Tigeot * register */ 307*9edbd4a0SFrançois Tigeot if (IS_HASWELL(dev) || IS_BROADWELL(dev)) 3082c84b0b6SFrançois Tigeot I915_WRITE(SPROFFSET(pipe), (y << 16) | x); 3092c84b0b6SFrançois Tigeot else if (obj->tiling_mode != I915_TILING_NONE) 3102c84b0b6SFrançois Tigeot I915_WRITE(SPRTILEOFF(pipe), (y << 16) | x); 3112c84b0b6SFrançois Tigeot else 3122c84b0b6SFrançois Tigeot I915_WRITE(SPRLINOFF(pipe), linear_offset); 3132c84b0b6SFrançois Tigeot 314e3adcf8fSFrançois Tigeot I915_WRITE(SPRSIZE(pipe), (crtc_h << 16) | crtc_w); 3152c84b0b6SFrançois Tigeot if (intel_plane->can_scale) 316e3adcf8fSFrançois Tigeot I915_WRITE(SPRSCALE(pipe), sprscale); 317e3adcf8fSFrançois Tigeot I915_WRITE(SPRCTL(pipe), sprctl); 318*9edbd4a0SFrançois Tigeot I915_WRITE(SPRSURF(pipe), 319*9edbd4a0SFrançois Tigeot i915_gem_obj_ggtt_offset(obj) + sprsurf_offset); 320e3adcf8fSFrançois Tigeot POSTING_READ(SPRSURF(pipe)); 321e3adcf8fSFrançois Tigeot } 322e3adcf8fSFrançois Tigeot 323e3adcf8fSFrançois Tigeot static void 324*9edbd4a0SFrançois Tigeot ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc) 325e3adcf8fSFrançois Tigeot { 326e3adcf8fSFrançois Tigeot struct drm_device *dev = plane->dev; 327e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 328e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(plane); 329e3adcf8fSFrançois Tigeot int pipe = intel_plane->pipe; 330e3adcf8fSFrançois Tigeot 331e3adcf8fSFrançois Tigeot I915_WRITE(SPRCTL(pipe), I915_READ(SPRCTL(pipe)) & ~SPRITE_ENABLE); 332e3adcf8fSFrançois Tigeot /* Can't leave the scaler enabled... */ 3332c84b0b6SFrançois Tigeot if (intel_plane->can_scale) 334e3adcf8fSFrançois Tigeot I915_WRITE(SPRSCALE(pipe), 0); 335e3adcf8fSFrançois Tigeot /* Activate double buffered register update */ 336*9edbd4a0SFrançois Tigeot I915_WRITE(SPRSURF(pipe), 0); 337e3adcf8fSFrançois Tigeot POSTING_READ(SPRSURF(pipe)); 3382c84b0b6SFrançois Tigeot 339*9edbd4a0SFrançois Tigeot /* 340*9edbd4a0SFrançois Tigeot * Avoid underruns when disabling the sprite. 341*9edbd4a0SFrançois Tigeot * FIXME remove once watermark updates are done properly. 342*9edbd4a0SFrançois Tigeot */ 343*9edbd4a0SFrançois Tigeot intel_wait_for_vblank(dev, pipe); 344a2fdbec6SFrançois Tigeot 345*9edbd4a0SFrançois Tigeot intel_update_sprite_watermarks(plane, crtc, 0, 0, false, false); 346e3adcf8fSFrançois Tigeot } 347e3adcf8fSFrançois Tigeot 348e3adcf8fSFrançois Tigeot static int 349e3adcf8fSFrançois Tigeot ivb_update_colorkey(struct drm_plane *plane, 350e3adcf8fSFrançois Tigeot struct drm_intel_sprite_colorkey *key) 351e3adcf8fSFrançois Tigeot { 352e3adcf8fSFrançois Tigeot struct drm_device *dev = plane->dev; 353e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 354e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane; 355e3adcf8fSFrançois Tigeot u32 sprctl; 356e3adcf8fSFrançois Tigeot int ret = 0; 357e3adcf8fSFrançois Tigeot 358e3adcf8fSFrançois Tigeot intel_plane = to_intel_plane(plane); 359e3adcf8fSFrançois Tigeot 360e3adcf8fSFrançois Tigeot I915_WRITE(SPRKEYVAL(intel_plane->pipe), key->min_value); 361e3adcf8fSFrançois Tigeot I915_WRITE(SPRKEYMAX(intel_plane->pipe), key->max_value); 362e3adcf8fSFrançois Tigeot I915_WRITE(SPRKEYMSK(intel_plane->pipe), key->channel_mask); 363e3adcf8fSFrançois Tigeot 364e3adcf8fSFrançois Tigeot sprctl = I915_READ(SPRCTL(intel_plane->pipe)); 365e3adcf8fSFrançois Tigeot sprctl &= ~(SPRITE_SOURCE_KEY | SPRITE_DEST_KEY); 366e3adcf8fSFrançois Tigeot if (key->flags & I915_SET_COLORKEY_DESTINATION) 367e3adcf8fSFrançois Tigeot sprctl |= SPRITE_DEST_KEY; 368e3adcf8fSFrançois Tigeot else if (key->flags & I915_SET_COLORKEY_SOURCE) 369e3adcf8fSFrançois Tigeot sprctl |= SPRITE_SOURCE_KEY; 370e3adcf8fSFrançois Tigeot I915_WRITE(SPRCTL(intel_plane->pipe), sprctl); 371e3adcf8fSFrançois Tigeot 372e3adcf8fSFrançois Tigeot POSTING_READ(SPRKEYMSK(intel_plane->pipe)); 373e3adcf8fSFrançois Tigeot 374e3adcf8fSFrançois Tigeot return ret; 375e3adcf8fSFrançois Tigeot } 376e3adcf8fSFrançois Tigeot 377e3adcf8fSFrançois Tigeot static void 378e3adcf8fSFrançois Tigeot ivb_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key) 379e3adcf8fSFrançois Tigeot { 380e3adcf8fSFrançois Tigeot struct drm_device *dev = plane->dev; 381e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 382e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane; 383e3adcf8fSFrançois Tigeot u32 sprctl; 384e3adcf8fSFrançois Tigeot 385e3adcf8fSFrançois Tigeot intel_plane = to_intel_plane(plane); 386e3adcf8fSFrançois Tigeot 387e3adcf8fSFrançois Tigeot key->min_value = I915_READ(SPRKEYVAL(intel_plane->pipe)); 388e3adcf8fSFrançois Tigeot key->max_value = I915_READ(SPRKEYMAX(intel_plane->pipe)); 389e3adcf8fSFrançois Tigeot key->channel_mask = I915_READ(SPRKEYMSK(intel_plane->pipe)); 390e3adcf8fSFrançois Tigeot key->flags = 0; 391e3adcf8fSFrançois Tigeot 392e3adcf8fSFrançois Tigeot sprctl = I915_READ(SPRCTL(intel_plane->pipe)); 393e3adcf8fSFrançois Tigeot 394e3adcf8fSFrançois Tigeot if (sprctl & SPRITE_DEST_KEY) 395e3adcf8fSFrançois Tigeot key->flags = I915_SET_COLORKEY_DESTINATION; 396e3adcf8fSFrançois Tigeot else if (sprctl & SPRITE_SOURCE_KEY) 397e3adcf8fSFrançois Tigeot key->flags = I915_SET_COLORKEY_SOURCE; 398e3adcf8fSFrançois Tigeot else 399e3adcf8fSFrançois Tigeot key->flags = I915_SET_COLORKEY_NONE; 400e3adcf8fSFrançois Tigeot } 401e3adcf8fSFrançois Tigeot 402e3adcf8fSFrançois Tigeot static void 403*9edbd4a0SFrançois Tigeot ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, 404*9edbd4a0SFrançois Tigeot struct drm_framebuffer *fb, 405e3adcf8fSFrançois Tigeot struct drm_i915_gem_object *obj, int crtc_x, int crtc_y, 406e3adcf8fSFrançois Tigeot unsigned int crtc_w, unsigned int crtc_h, 407e3adcf8fSFrançois Tigeot uint32_t x, uint32_t y, 408e3adcf8fSFrançois Tigeot uint32_t src_w, uint32_t src_h) 409e3adcf8fSFrançois Tigeot { 410e3adcf8fSFrançois Tigeot struct drm_device *dev = plane->dev; 411e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 412e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(plane); 4132c84b0b6SFrançois Tigeot int pipe = intel_plane->pipe; 4142c84b0b6SFrançois Tigeot unsigned long dvssurf_offset, linear_offset; 4152c84b0b6SFrançois Tigeot u32 dvscntr, dvsscale; 4162c84b0b6SFrançois Tigeot int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); 417e3adcf8fSFrançois Tigeot 418e3adcf8fSFrançois Tigeot dvscntr = I915_READ(DVSCNTR(pipe)); 419e3adcf8fSFrançois Tigeot 420e3adcf8fSFrançois Tigeot /* Mask out pixel format bits in case we change it */ 421e3adcf8fSFrançois Tigeot dvscntr &= ~DVS_PIXFORMAT_MASK; 422e3adcf8fSFrançois Tigeot dvscntr &= ~DVS_RGB_ORDER_XBGR; 423e3adcf8fSFrançois Tigeot dvscntr &= ~DVS_YUV_BYTE_ORDER_MASK; 4242c84b0b6SFrançois Tigeot dvscntr &= ~DVS_TILED; 425e3adcf8fSFrançois Tigeot 426e3adcf8fSFrançois Tigeot switch (fb->pixel_format) { 427e3adcf8fSFrançois Tigeot case DRM_FORMAT_XBGR8888: 428e3adcf8fSFrançois Tigeot dvscntr |= DVS_FORMAT_RGBX888 | DVS_RGB_ORDER_XBGR; 429e3adcf8fSFrançois Tigeot break; 430e3adcf8fSFrançois Tigeot case DRM_FORMAT_XRGB8888: 431e3adcf8fSFrançois Tigeot dvscntr |= DVS_FORMAT_RGBX888; 432e3adcf8fSFrançois Tigeot break; 433e3adcf8fSFrançois Tigeot case DRM_FORMAT_YUYV: 434e3adcf8fSFrançois Tigeot dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YUYV; 435e3adcf8fSFrançois Tigeot break; 436e3adcf8fSFrançois Tigeot case DRM_FORMAT_YVYU: 437e3adcf8fSFrançois Tigeot dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YVYU; 438e3adcf8fSFrançois Tigeot break; 439e3adcf8fSFrançois Tigeot case DRM_FORMAT_UYVY: 440e3adcf8fSFrançois Tigeot dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_UYVY; 441e3adcf8fSFrançois Tigeot break; 442e3adcf8fSFrançois Tigeot case DRM_FORMAT_VYUY: 443e3adcf8fSFrançois Tigeot dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_VYUY; 444e3adcf8fSFrançois Tigeot break; 445e3adcf8fSFrançois Tigeot default: 4462c84b0b6SFrançois Tigeot BUG(); 447e3adcf8fSFrançois Tigeot } 448e3adcf8fSFrançois Tigeot 449*9edbd4a0SFrançois Tigeot /* 450*9edbd4a0SFrançois Tigeot * Enable gamma to match primary/cursor plane behaviour. 451*9edbd4a0SFrançois Tigeot * FIXME should be user controllable via propertiesa. 452*9edbd4a0SFrançois Tigeot */ 453*9edbd4a0SFrançois Tigeot dvscntr |= DVS_GAMMA_ENABLE; 454*9edbd4a0SFrançois Tigeot 455e3adcf8fSFrançois Tigeot if (obj->tiling_mode != I915_TILING_NONE) 456e3adcf8fSFrançois Tigeot dvscntr |= DVS_TILED; 457e3adcf8fSFrançois Tigeot 4582c84b0b6SFrançois Tigeot if (IS_GEN6(dev)) 4592c84b0b6SFrançois Tigeot dvscntr |= DVS_TRICKLE_FEED_DISABLE; /* must disable */ 460e3adcf8fSFrançois Tigeot dvscntr |= DVS_ENABLE; 461e3adcf8fSFrançois Tigeot 462*9edbd4a0SFrançois Tigeot intel_update_sprite_watermarks(plane, crtc, src_w, pixel_size, true, 463*9edbd4a0SFrançois Tigeot src_w != crtc_w || src_h != crtc_h); 464*9edbd4a0SFrançois Tigeot 465e3adcf8fSFrançois Tigeot /* Sizes are 0 based */ 466e3adcf8fSFrançois Tigeot src_w--; 467e3adcf8fSFrançois Tigeot src_h--; 468e3adcf8fSFrançois Tigeot crtc_w--; 469e3adcf8fSFrançois Tigeot crtc_h--; 470e3adcf8fSFrançois Tigeot 4712c84b0b6SFrançois Tigeot dvsscale = 0; 472*9edbd4a0SFrançois Tigeot if (crtc_w != src_w || crtc_h != src_h) 473e3adcf8fSFrançois Tigeot dvsscale = DVS_SCALE_ENABLE | (src_w << 16) | src_h; 474e3adcf8fSFrançois Tigeot 475e3adcf8fSFrançois Tigeot I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]); 476e3adcf8fSFrançois Tigeot I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x); 477e3adcf8fSFrançois Tigeot 4782c84b0b6SFrançois Tigeot linear_offset = y * fb->pitches[0] + x * pixel_size; 4792c84b0b6SFrançois Tigeot dvssurf_offset = 480df188185SFrançois Tigeot intel_gen4_compute_page_offset(&x, &y, obj->tiling_mode, 4812c84b0b6SFrançois Tigeot pixel_size, fb->pitches[0]); 4822c84b0b6SFrançois Tigeot linear_offset -= dvssurf_offset; 4832c84b0b6SFrançois Tigeot 4842c84b0b6SFrançois Tigeot if (obj->tiling_mode != I915_TILING_NONE) 4852c84b0b6SFrançois Tigeot I915_WRITE(DVSTILEOFF(pipe), (y << 16) | x); 4862c84b0b6SFrançois Tigeot else 4872c84b0b6SFrançois Tigeot I915_WRITE(DVSLINOFF(pipe), linear_offset); 4882c84b0b6SFrançois Tigeot 489e3adcf8fSFrançois Tigeot I915_WRITE(DVSSIZE(pipe), (crtc_h << 16) | crtc_w); 490e3adcf8fSFrançois Tigeot I915_WRITE(DVSSCALE(pipe), dvsscale); 491e3adcf8fSFrançois Tigeot I915_WRITE(DVSCNTR(pipe), dvscntr); 492*9edbd4a0SFrançois Tigeot I915_WRITE(DVSSURF(pipe), 493*9edbd4a0SFrançois Tigeot i915_gem_obj_ggtt_offset(obj) + dvssurf_offset); 494e3adcf8fSFrançois Tigeot POSTING_READ(DVSSURF(pipe)); 495e3adcf8fSFrançois Tigeot } 496e3adcf8fSFrançois Tigeot 497e3adcf8fSFrançois Tigeot static void 498*9edbd4a0SFrançois Tigeot ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc) 499e3adcf8fSFrançois Tigeot { 500e3adcf8fSFrançois Tigeot struct drm_device *dev = plane->dev; 501e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 502e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(plane); 503e3adcf8fSFrançois Tigeot int pipe = intel_plane->pipe; 504e3adcf8fSFrançois Tigeot 505e3adcf8fSFrançois Tigeot I915_WRITE(DVSCNTR(pipe), I915_READ(DVSCNTR(pipe)) & ~DVS_ENABLE); 506e3adcf8fSFrançois Tigeot /* Disable the scaler */ 507e3adcf8fSFrançois Tigeot I915_WRITE(DVSSCALE(pipe), 0); 508e3adcf8fSFrançois Tigeot /* Flush double buffered register updates */ 509*9edbd4a0SFrançois Tigeot I915_WRITE(DVSSURF(pipe), 0); 510e3adcf8fSFrançois Tigeot POSTING_READ(DVSSURF(pipe)); 511*9edbd4a0SFrançois Tigeot 512*9edbd4a0SFrançois Tigeot /* 513*9edbd4a0SFrançois Tigeot * Avoid underruns when disabling the sprite. 514*9edbd4a0SFrançois Tigeot * FIXME remove once watermark updates are done properly. 515*9edbd4a0SFrançois Tigeot */ 516*9edbd4a0SFrançois Tigeot intel_wait_for_vblank(dev, pipe); 517*9edbd4a0SFrançois Tigeot 518*9edbd4a0SFrançois Tigeot intel_update_sprite_watermarks(plane, crtc, 0, 0, false, false); 519e3adcf8fSFrançois Tigeot } 520e3adcf8fSFrançois Tigeot 521e3adcf8fSFrançois Tigeot static void 522e3adcf8fSFrançois Tigeot intel_enable_primary(struct drm_crtc *crtc) 523e3adcf8fSFrançois Tigeot { 524e3adcf8fSFrançois Tigeot struct drm_device *dev = crtc->dev; 525e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 526e3adcf8fSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 527e3adcf8fSFrançois Tigeot int reg = DSPCNTR(intel_crtc->plane); 528e3adcf8fSFrançois Tigeot 529*9edbd4a0SFrançois Tigeot if (intel_crtc->primary_enabled) 5302c84b0b6SFrançois Tigeot return; 5312c84b0b6SFrançois Tigeot 532*9edbd4a0SFrançois Tigeot intel_crtc->primary_enabled = true; 5332c84b0b6SFrançois Tigeot 534e3adcf8fSFrançois Tigeot I915_WRITE(reg, I915_READ(reg) | DISPLAY_PLANE_ENABLE); 535*9edbd4a0SFrançois Tigeot intel_flush_primary_plane(dev_priv, intel_crtc->plane); 536*9edbd4a0SFrançois Tigeot 537*9edbd4a0SFrançois Tigeot /* 538*9edbd4a0SFrançois Tigeot * FIXME IPS should be fine as long as one plane is 539*9edbd4a0SFrançois Tigeot * enabled, but in practice it seems to have problems 540*9edbd4a0SFrançois Tigeot * when going from primary only to sprite only and vice 541*9edbd4a0SFrançois Tigeot * versa. 542*9edbd4a0SFrançois Tigeot */ 543*9edbd4a0SFrançois Tigeot if (intel_crtc->config.ips_enabled) { 544*9edbd4a0SFrançois Tigeot intel_wait_for_vblank(dev, intel_crtc->pipe); 545*9edbd4a0SFrançois Tigeot hsw_enable_ips(intel_crtc); 546*9edbd4a0SFrançois Tigeot } 547*9edbd4a0SFrançois Tigeot 548*9edbd4a0SFrançois Tigeot mutex_lock(&dev->struct_mutex); 549*9edbd4a0SFrançois Tigeot intel_update_fbc(dev); 550*9edbd4a0SFrançois Tigeot mutex_unlock(&dev->struct_mutex); 551e3adcf8fSFrançois Tigeot } 552e3adcf8fSFrançois Tigeot 553e3adcf8fSFrançois Tigeot static void 554e3adcf8fSFrançois Tigeot intel_disable_primary(struct drm_crtc *crtc) 555e3adcf8fSFrançois Tigeot { 556e3adcf8fSFrançois Tigeot struct drm_device *dev = crtc->dev; 557e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 558e3adcf8fSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 559e3adcf8fSFrançois Tigeot int reg = DSPCNTR(intel_crtc->plane); 560e3adcf8fSFrançois Tigeot 561*9edbd4a0SFrançois Tigeot if (!intel_crtc->primary_enabled) 5622c84b0b6SFrançois Tigeot return; 5632c84b0b6SFrançois Tigeot 564*9edbd4a0SFrançois Tigeot intel_crtc->primary_enabled = false; 5652c84b0b6SFrançois Tigeot 566*9edbd4a0SFrançois Tigeot mutex_lock(&dev->struct_mutex); 567*9edbd4a0SFrançois Tigeot if (dev_priv->fbc.plane == intel_crtc->plane) 568*9edbd4a0SFrançois Tigeot intel_disable_fbc(dev); 569*9edbd4a0SFrançois Tigeot mutex_unlock(&dev->struct_mutex); 570*9edbd4a0SFrançois Tigeot 571*9edbd4a0SFrançois Tigeot /* 572*9edbd4a0SFrançois Tigeot * FIXME IPS should be fine as long as one plane is 573*9edbd4a0SFrançois Tigeot * enabled, but in practice it seems to have problems 574*9edbd4a0SFrançois Tigeot * when going from primary only to sprite only and vice 575*9edbd4a0SFrançois Tigeot * versa. 576*9edbd4a0SFrançois Tigeot */ 577*9edbd4a0SFrançois Tigeot hsw_disable_ips(intel_crtc); 578*9edbd4a0SFrançois Tigeot 579*9edbd4a0SFrançois Tigeot I915_WRITE(reg, I915_READ(reg) & ~DISPLAY_PLANE_ENABLE); 580*9edbd4a0SFrançois Tigeot intel_flush_primary_plane(dev_priv, intel_crtc->plane); 581e3adcf8fSFrançois Tigeot } 582e3adcf8fSFrançois Tigeot 583e3adcf8fSFrançois Tigeot static int 5842c84b0b6SFrançois Tigeot ilk_update_colorkey(struct drm_plane *plane, 585e3adcf8fSFrançois Tigeot struct drm_intel_sprite_colorkey *key) 586e3adcf8fSFrançois Tigeot { 587e3adcf8fSFrançois Tigeot struct drm_device *dev = plane->dev; 588e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 589e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane; 590e3adcf8fSFrançois Tigeot u32 dvscntr; 591e3adcf8fSFrançois Tigeot int ret = 0; 592e3adcf8fSFrançois Tigeot 593e3adcf8fSFrançois Tigeot intel_plane = to_intel_plane(plane); 594e3adcf8fSFrançois Tigeot 595e3adcf8fSFrançois Tigeot I915_WRITE(DVSKEYVAL(intel_plane->pipe), key->min_value); 596e3adcf8fSFrançois Tigeot I915_WRITE(DVSKEYMAX(intel_plane->pipe), key->max_value); 597e3adcf8fSFrançois Tigeot I915_WRITE(DVSKEYMSK(intel_plane->pipe), key->channel_mask); 598e3adcf8fSFrançois Tigeot 599e3adcf8fSFrançois Tigeot dvscntr = I915_READ(DVSCNTR(intel_plane->pipe)); 600e3adcf8fSFrançois Tigeot dvscntr &= ~(DVS_SOURCE_KEY | DVS_DEST_KEY); 601e3adcf8fSFrançois Tigeot if (key->flags & I915_SET_COLORKEY_DESTINATION) 602e3adcf8fSFrançois Tigeot dvscntr |= DVS_DEST_KEY; 603e3adcf8fSFrançois Tigeot else if (key->flags & I915_SET_COLORKEY_SOURCE) 604e3adcf8fSFrançois Tigeot dvscntr |= DVS_SOURCE_KEY; 605e3adcf8fSFrançois Tigeot I915_WRITE(DVSCNTR(intel_plane->pipe), dvscntr); 606e3adcf8fSFrançois Tigeot 607e3adcf8fSFrançois Tigeot POSTING_READ(DVSKEYMSK(intel_plane->pipe)); 608e3adcf8fSFrançois Tigeot 609e3adcf8fSFrançois Tigeot return ret; 610e3adcf8fSFrançois Tigeot } 611e3adcf8fSFrançois Tigeot 612e3adcf8fSFrançois Tigeot static void 6132c84b0b6SFrançois Tigeot ilk_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key) 614e3adcf8fSFrançois Tigeot { 615e3adcf8fSFrançois Tigeot struct drm_device *dev = plane->dev; 616e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 617e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane; 618e3adcf8fSFrançois Tigeot u32 dvscntr; 619e3adcf8fSFrançois Tigeot 620e3adcf8fSFrançois Tigeot intel_plane = to_intel_plane(plane); 621e3adcf8fSFrançois Tigeot 622e3adcf8fSFrançois Tigeot key->min_value = I915_READ(DVSKEYVAL(intel_plane->pipe)); 623e3adcf8fSFrançois Tigeot key->max_value = I915_READ(DVSKEYMAX(intel_plane->pipe)); 624e3adcf8fSFrançois Tigeot key->channel_mask = I915_READ(DVSKEYMSK(intel_plane->pipe)); 625e3adcf8fSFrançois Tigeot key->flags = 0; 626e3adcf8fSFrançois Tigeot 627e3adcf8fSFrançois Tigeot dvscntr = I915_READ(DVSCNTR(intel_plane->pipe)); 628e3adcf8fSFrançois Tigeot 629e3adcf8fSFrançois Tigeot if (dvscntr & DVS_DEST_KEY) 630e3adcf8fSFrançois Tigeot key->flags = I915_SET_COLORKEY_DESTINATION; 631e3adcf8fSFrançois Tigeot else if (dvscntr & DVS_SOURCE_KEY) 632e3adcf8fSFrançois Tigeot key->flags = I915_SET_COLORKEY_SOURCE; 633e3adcf8fSFrançois Tigeot else 634e3adcf8fSFrançois Tigeot key->flags = I915_SET_COLORKEY_NONE; 635e3adcf8fSFrançois Tigeot } 636e3adcf8fSFrançois Tigeot 6375d0b1887SFrançois Tigeot static bool 6385d0b1887SFrançois Tigeot format_is_yuv(uint32_t format) 6395d0b1887SFrançois Tigeot { 6405d0b1887SFrançois Tigeot switch (format) { 6415d0b1887SFrançois Tigeot case DRM_FORMAT_YUYV: 6425d0b1887SFrançois Tigeot case DRM_FORMAT_UYVY: 6435d0b1887SFrançois Tigeot case DRM_FORMAT_VYUY: 6445d0b1887SFrançois Tigeot case DRM_FORMAT_YVYU: 6455d0b1887SFrançois Tigeot return true; 6465d0b1887SFrançois Tigeot default: 6475d0b1887SFrançois Tigeot return false; 6485d0b1887SFrançois Tigeot } 6495d0b1887SFrançois Tigeot } 6505d0b1887SFrançois Tigeot 651*9edbd4a0SFrançois Tigeot static bool colorkey_enabled(struct intel_plane *intel_plane) 652*9edbd4a0SFrançois Tigeot { 653*9edbd4a0SFrançois Tigeot struct drm_intel_sprite_colorkey key; 654*9edbd4a0SFrançois Tigeot 655*9edbd4a0SFrançois Tigeot intel_plane->get_colorkey(&intel_plane->base, &key); 656*9edbd4a0SFrançois Tigeot 657*9edbd4a0SFrançois Tigeot return key.flags != I915_SET_COLORKEY_NONE; 658*9edbd4a0SFrançois Tigeot } 659*9edbd4a0SFrançois Tigeot 660e3adcf8fSFrançois Tigeot static int 661e3adcf8fSFrançois Tigeot intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, 662e3adcf8fSFrançois Tigeot struct drm_framebuffer *fb, int crtc_x, int crtc_y, 663e3adcf8fSFrançois Tigeot unsigned int crtc_w, unsigned int crtc_h, 664e3adcf8fSFrançois Tigeot uint32_t src_x, uint32_t src_y, 665e3adcf8fSFrançois Tigeot uint32_t src_w, uint32_t src_h) 666e3adcf8fSFrançois Tigeot { 667e3adcf8fSFrançois Tigeot struct drm_device *dev = plane->dev; 668e3adcf8fSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 669e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(plane); 670*9edbd4a0SFrançois Tigeot struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); 671*9edbd4a0SFrançois Tigeot struct drm_i915_gem_object *obj = intel_fb->obj; 672*9edbd4a0SFrançois Tigeot struct drm_i915_gem_object *old_obj = intel_plane->obj; 673*9edbd4a0SFrançois Tigeot int ret; 674e3adcf8fSFrançois Tigeot bool disable_primary = false; 6755d0b1887SFrançois Tigeot bool visible; 6765d0b1887SFrançois Tigeot int hscale, vscale; 6775d0b1887SFrançois Tigeot int max_scale, min_scale; 6785d0b1887SFrançois Tigeot int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); 6795d0b1887SFrançois Tigeot struct drm_rect src = { 6805d0b1887SFrançois Tigeot /* sample coordinates in 16.16 fixed point */ 6815d0b1887SFrançois Tigeot .x1 = src_x, 6825d0b1887SFrançois Tigeot .x2 = src_x + src_w, 6835d0b1887SFrançois Tigeot .y1 = src_y, 6845d0b1887SFrançois Tigeot .y2 = src_y + src_h, 6855d0b1887SFrançois Tigeot }; 6865d0b1887SFrançois Tigeot struct drm_rect dst = { 6875d0b1887SFrançois Tigeot /* integer pixels */ 6885d0b1887SFrançois Tigeot .x1 = crtc_x, 6895d0b1887SFrançois Tigeot .x2 = crtc_x + crtc_w, 6905d0b1887SFrançois Tigeot .y1 = crtc_y, 6915d0b1887SFrançois Tigeot .y2 = crtc_y + crtc_h, 6925d0b1887SFrançois Tigeot }; 6935d0b1887SFrançois Tigeot const struct drm_rect clip = { 694*9edbd4a0SFrançois Tigeot .x2 = intel_crtc->active ? intel_crtc->config.pipe_src_w : 0, 695*9edbd4a0SFrançois Tigeot .y2 = intel_crtc->active ? intel_crtc->config.pipe_src_h : 0, 6965d0b1887SFrançois Tigeot }; 697*9edbd4a0SFrançois Tigeot const struct { 698*9edbd4a0SFrançois Tigeot int crtc_x, crtc_y; 699*9edbd4a0SFrançois Tigeot unsigned int crtc_w, crtc_h; 700*9edbd4a0SFrançois Tigeot uint32_t src_x, src_y, src_w, src_h; 701*9edbd4a0SFrançois Tigeot } orig = { 702*9edbd4a0SFrançois Tigeot .crtc_x = crtc_x, 703*9edbd4a0SFrançois Tigeot .crtc_y = crtc_y, 704*9edbd4a0SFrançois Tigeot .crtc_w = crtc_w, 705*9edbd4a0SFrançois Tigeot .crtc_h = crtc_h, 706*9edbd4a0SFrançois Tigeot .src_x = src_x, 707*9edbd4a0SFrançois Tigeot .src_y = src_y, 708*9edbd4a0SFrançois Tigeot .src_w = src_w, 709*9edbd4a0SFrançois Tigeot .src_h = src_h, 710*9edbd4a0SFrançois Tigeot }; 711e3adcf8fSFrançois Tigeot 712e3adcf8fSFrançois Tigeot /* Don't modify another pipe's plane */ 7135d0b1887SFrançois Tigeot if (intel_plane->pipe != intel_crtc->pipe) { 7145d0b1887SFrançois Tigeot DRM_DEBUG_KMS("Wrong plane <-> crtc mapping\n"); 715e3adcf8fSFrançois Tigeot return -EINVAL; 7165d0b1887SFrançois Tigeot } 7175d0b1887SFrançois Tigeot 7185d0b1887SFrançois Tigeot /* FIXME check all gen limits */ 7195d0b1887SFrançois Tigeot if (fb->width < 3 || fb->height < 3 || fb->pitches[0] > 16384) { 7205d0b1887SFrançois Tigeot DRM_DEBUG_KMS("Unsuitable framebuffer for plane\n"); 7215d0b1887SFrançois Tigeot return -EINVAL; 7225d0b1887SFrançois Tigeot } 723e3adcf8fSFrançois Tigeot 7242c84b0b6SFrançois Tigeot /* Sprite planes can be linear or x-tiled surfaces */ 7252c84b0b6SFrançois Tigeot switch (obj->tiling_mode) { 7262c84b0b6SFrançois Tigeot case I915_TILING_NONE: 7272c84b0b6SFrançois Tigeot case I915_TILING_X: 7282c84b0b6SFrançois Tigeot break; 7292c84b0b6SFrançois Tigeot default: 7305d0b1887SFrançois Tigeot DRM_DEBUG_KMS("Unsupported tiling mode\n"); 7312c84b0b6SFrançois Tigeot return -EINVAL; 7322c84b0b6SFrançois Tigeot } 7332c84b0b6SFrançois Tigeot 734e3adcf8fSFrançois Tigeot /* 7355d0b1887SFrançois Tigeot * FIXME the following code does a bunch of fuzzy adjustments to the 7365d0b1887SFrançois Tigeot * coordinates and sizes. We probably need some way to decide whether 7375d0b1887SFrançois Tigeot * more strict checking should be done instead. 738e3adcf8fSFrançois Tigeot */ 7395d0b1887SFrançois Tigeot max_scale = intel_plane->max_downscale << 16; 7405d0b1887SFrançois Tigeot min_scale = intel_plane->can_scale ? 1 : (1 << 16); 741e3adcf8fSFrançois Tigeot 7425d0b1887SFrançois Tigeot hscale = drm_rect_calc_hscale_relaxed(&src, &dst, min_scale, max_scale); 7435d0b1887SFrançois Tigeot BUG_ON(hscale < 0); 744e3adcf8fSFrançois Tigeot 7455d0b1887SFrançois Tigeot vscale = drm_rect_calc_vscale_relaxed(&src, &dst, min_scale, max_scale); 7465d0b1887SFrançois Tigeot BUG_ON(vscale < 0); 7475d0b1887SFrançois Tigeot 7485d0b1887SFrançois Tigeot visible = drm_rect_clip_scaled(&src, &dst, &clip, hscale, vscale); 7495d0b1887SFrançois Tigeot 7505d0b1887SFrançois Tigeot crtc_x = dst.x1; 7515d0b1887SFrançois Tigeot crtc_y = dst.y1; 7525d0b1887SFrançois Tigeot crtc_w = drm_rect_width(&dst); 7535d0b1887SFrançois Tigeot crtc_h = drm_rect_height(&dst); 7545d0b1887SFrançois Tigeot 7555d0b1887SFrançois Tigeot if (visible) { 7565d0b1887SFrançois Tigeot /* check again in case clipping clamped the results */ 7575d0b1887SFrançois Tigeot hscale = drm_rect_calc_hscale(&src, &dst, min_scale, max_scale); 7585d0b1887SFrançois Tigeot if (hscale < 0) { 7595d0b1887SFrançois Tigeot DRM_DEBUG_KMS("Horizontal scaling factor out of limits\n"); 7605d0b1887SFrançois Tigeot drm_rect_debug_print(&src, true); 7615d0b1887SFrançois Tigeot drm_rect_debug_print(&dst, false); 7625d0b1887SFrançois Tigeot 7635d0b1887SFrançois Tigeot return hscale; 7645d0b1887SFrançois Tigeot } 7655d0b1887SFrançois Tigeot 7665d0b1887SFrançois Tigeot vscale = drm_rect_calc_vscale(&src, &dst, min_scale, max_scale); 7675d0b1887SFrançois Tigeot if (vscale < 0) { 7685d0b1887SFrançois Tigeot DRM_DEBUG_KMS("Vertical scaling factor out of limits\n"); 7695d0b1887SFrançois Tigeot drm_rect_debug_print(&src, true); 7705d0b1887SFrançois Tigeot drm_rect_debug_print(&dst, false); 7715d0b1887SFrançois Tigeot 7725d0b1887SFrançois Tigeot return vscale; 7735d0b1887SFrançois Tigeot } 7745d0b1887SFrançois Tigeot 7755d0b1887SFrançois Tigeot /* Make the source viewport size an exact multiple of the scaling factors. */ 7765d0b1887SFrançois Tigeot drm_rect_adjust_size(&src, 7775d0b1887SFrançois Tigeot drm_rect_width(&dst) * hscale - drm_rect_width(&src), 7785d0b1887SFrançois Tigeot drm_rect_height(&dst) * vscale - drm_rect_height(&src)); 7795d0b1887SFrançois Tigeot 7805d0b1887SFrançois Tigeot /* sanity check to make sure the src viewport wasn't enlarged */ 7815d0b1887SFrançois Tigeot WARN_ON(src.x1 < (int) src_x || 7825d0b1887SFrançois Tigeot src.y1 < (int) src_y || 7835d0b1887SFrançois Tigeot src.x2 > (int) (src_x + src_w) || 7845d0b1887SFrançois Tigeot src.y2 > (int) (src_y + src_h)); 785e3adcf8fSFrançois Tigeot 786e3adcf8fSFrançois Tigeot /* 7875d0b1887SFrançois Tigeot * Hardware doesn't handle subpixel coordinates. 7885d0b1887SFrançois Tigeot * Adjust to (macro)pixel boundary, but be careful not to 7895d0b1887SFrançois Tigeot * increase the source viewport size, because that could 7905d0b1887SFrançois Tigeot * push the downscaling factor out of bounds. 7912c84b0b6SFrançois Tigeot */ 7925d0b1887SFrançois Tigeot src_x = src.x1 >> 16; 7935d0b1887SFrançois Tigeot src_w = drm_rect_width(&src) >> 16; 7945d0b1887SFrançois Tigeot src_y = src.y1 >> 16; 7955d0b1887SFrançois Tigeot src_h = drm_rect_height(&src) >> 16; 7965d0b1887SFrançois Tigeot 7975d0b1887SFrançois Tigeot if (format_is_yuv(fb->pixel_format)) { 7985d0b1887SFrançois Tigeot src_x &= ~1; 7995d0b1887SFrançois Tigeot src_w &= ~1; 8002c84b0b6SFrançois Tigeot 8012c84b0b6SFrançois Tigeot /* 8025d0b1887SFrançois Tigeot * Must keep src and dst the 8035d0b1887SFrançois Tigeot * same if we can't scale. 804e3adcf8fSFrançois Tigeot */ 8055d0b1887SFrançois Tigeot if (!intel_plane->can_scale) 8065d0b1887SFrançois Tigeot crtc_w &= ~1; 8075d0b1887SFrançois Tigeot 8085d0b1887SFrançois Tigeot if (crtc_w == 0) 8095d0b1887SFrançois Tigeot visible = false; 8105d0b1887SFrançois Tigeot } 8115d0b1887SFrançois Tigeot } 8125d0b1887SFrançois Tigeot 8135d0b1887SFrançois Tigeot /* Check size restrictions when scaling */ 8145d0b1887SFrançois Tigeot if (visible && (src_w != crtc_w || src_h != crtc_h)) { 8155d0b1887SFrançois Tigeot unsigned int width_bytes; 8165d0b1887SFrançois Tigeot 8175d0b1887SFrançois Tigeot WARN_ON(!intel_plane->can_scale); 8185d0b1887SFrançois Tigeot 8195d0b1887SFrançois Tigeot /* FIXME interlacing min height is 6 */ 8205d0b1887SFrançois Tigeot 8215d0b1887SFrançois Tigeot if (crtc_w < 3 || crtc_h < 3) 8225d0b1887SFrançois Tigeot visible = false; 8235d0b1887SFrançois Tigeot 8245d0b1887SFrançois Tigeot if (src_w < 3 || src_h < 3) 8255d0b1887SFrançois Tigeot visible = false; 8265d0b1887SFrançois Tigeot 8275d0b1887SFrançois Tigeot width_bytes = ((src_x * pixel_size) & 63) + src_w * pixel_size; 8285d0b1887SFrançois Tigeot 8295d0b1887SFrançois Tigeot if (src_w > 2048 || src_h > 2048 || 8305d0b1887SFrançois Tigeot width_bytes > 4096 || fb->pitches[0] > 4096) { 8315d0b1887SFrançois Tigeot DRM_DEBUG_KMS("Source dimensions exceed hardware limits\n"); 832e3adcf8fSFrançois Tigeot return -EINVAL; 8335d0b1887SFrançois Tigeot } 8345d0b1887SFrançois Tigeot } 8355d0b1887SFrançois Tigeot 8365d0b1887SFrançois Tigeot dst.x1 = crtc_x; 8375d0b1887SFrançois Tigeot dst.x2 = crtc_x + crtc_w; 8385d0b1887SFrançois Tigeot dst.y1 = crtc_y; 8395d0b1887SFrançois Tigeot dst.y2 = crtc_y + crtc_h; 840e3adcf8fSFrançois Tigeot 841e3adcf8fSFrançois Tigeot /* 842e3adcf8fSFrançois Tigeot * If the sprite is completely covering the primary plane, 843e3adcf8fSFrançois Tigeot * we can disable the primary and save power. 844e3adcf8fSFrançois Tigeot */ 845*9edbd4a0SFrançois Tigeot disable_primary = drm_rect_equals(&dst, &clip) && !colorkey_enabled(intel_plane); 846*9edbd4a0SFrançois Tigeot WARN_ON(disable_primary && !visible && intel_crtc->active); 847e3adcf8fSFrançois Tigeot 848a2fdbec6SFrançois Tigeot mutex_lock(&dev->struct_mutex); 849e3adcf8fSFrançois Tigeot 8508e26cdf6SFrançois Tigeot /* Note that this will apply the VT-d workaround for scanouts, 8518e26cdf6SFrançois Tigeot * which is more restrictive than required for sprites. (The 8528e26cdf6SFrançois Tigeot * primary plane requires 256KiB alignment with 64 PTE padding, 8538e26cdf6SFrançois Tigeot * the sprite planes only require 128KiB alignment and 32 PTE padding. 8548e26cdf6SFrançois Tigeot */ 855e3adcf8fSFrançois Tigeot ret = intel_pin_and_fence_fb_obj(dev, obj, NULL); 856e3adcf8fSFrançois Tigeot 857*9edbd4a0SFrançois Tigeot mutex_unlock(&dev->struct_mutex); 858*9edbd4a0SFrançois Tigeot 859*9edbd4a0SFrançois Tigeot if (ret) 860*9edbd4a0SFrançois Tigeot return ret; 861*9edbd4a0SFrançois Tigeot 862*9edbd4a0SFrançois Tigeot intel_plane->crtc_x = orig.crtc_x; 863*9edbd4a0SFrançois Tigeot intel_plane->crtc_y = orig.crtc_y; 864*9edbd4a0SFrançois Tigeot intel_plane->crtc_w = orig.crtc_w; 865*9edbd4a0SFrançois Tigeot intel_plane->crtc_h = orig.crtc_h; 866*9edbd4a0SFrançois Tigeot intel_plane->src_x = orig.src_x; 867*9edbd4a0SFrançois Tigeot intel_plane->src_y = orig.src_y; 868*9edbd4a0SFrançois Tigeot intel_plane->src_w = orig.src_w; 869*9edbd4a0SFrançois Tigeot intel_plane->src_h = orig.src_h; 870e3adcf8fSFrançois Tigeot intel_plane->obj = obj; 871e3adcf8fSFrançois Tigeot 872*9edbd4a0SFrançois Tigeot if (intel_crtc->active) { 873e3adcf8fSFrançois Tigeot /* 874e3adcf8fSFrançois Tigeot * Be sure to re-enable the primary before the sprite is no longer 875e3adcf8fSFrançois Tigeot * covering it fully. 876e3adcf8fSFrançois Tigeot */ 8772c84b0b6SFrançois Tigeot if (!disable_primary) 878e3adcf8fSFrançois Tigeot intel_enable_primary(crtc); 879e3adcf8fSFrançois Tigeot 8805d0b1887SFrançois Tigeot if (visible) 881*9edbd4a0SFrançois Tigeot intel_plane->update_plane(plane, crtc, fb, obj, 8825d0b1887SFrançois Tigeot crtc_x, crtc_y, crtc_w, crtc_h, 8835d0b1887SFrançois Tigeot src_x, src_y, src_w, src_h); 8845d0b1887SFrançois Tigeot else 885*9edbd4a0SFrançois Tigeot intel_plane->disable_plane(plane, crtc); 886e3adcf8fSFrançois Tigeot 8872c84b0b6SFrançois Tigeot if (disable_primary) 888e3adcf8fSFrançois Tigeot intel_disable_primary(crtc); 889*9edbd4a0SFrançois Tigeot } 890e3adcf8fSFrançois Tigeot 891e3adcf8fSFrançois Tigeot /* Unpin old obj after new one is active to avoid ugliness */ 892e3adcf8fSFrançois Tigeot if (old_obj) { 893e3adcf8fSFrançois Tigeot /* 894e3adcf8fSFrançois Tigeot * It's fairly common to simply update the position of 895e3adcf8fSFrançois Tigeot * an existing object. In that case, we don't need to 896e3adcf8fSFrançois Tigeot * wait for vblank to avoid ugliness, we only need to 897e3adcf8fSFrançois Tigeot * do the pin & ref bookkeeping. 898e3adcf8fSFrançois Tigeot */ 899*9edbd4a0SFrançois Tigeot if (old_obj != obj && intel_crtc->active) 900*9edbd4a0SFrançois Tigeot intel_wait_for_vblank(dev, intel_crtc->pipe); 901*9edbd4a0SFrançois Tigeot 902a2fdbec6SFrançois Tigeot mutex_lock(&dev->struct_mutex); 903e3adcf8fSFrançois Tigeot intel_unpin_fb_obj(old_obj); 904*9edbd4a0SFrançois Tigeot mutex_unlock(&dev->struct_mutex); 905e3adcf8fSFrançois Tigeot } 906e3adcf8fSFrançois Tigeot 907*9edbd4a0SFrançois Tigeot return 0; 908e3adcf8fSFrançois Tigeot } 909e3adcf8fSFrançois Tigeot 910e3adcf8fSFrançois Tigeot static int 911e3adcf8fSFrançois Tigeot intel_disable_plane(struct drm_plane *plane) 912e3adcf8fSFrançois Tigeot { 913e3adcf8fSFrançois Tigeot struct drm_device *dev = plane->dev; 914e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(plane); 915*9edbd4a0SFrançois Tigeot struct intel_crtc *intel_crtc; 916e3adcf8fSFrançois Tigeot 917*9edbd4a0SFrançois Tigeot if (!plane->fb) 918*9edbd4a0SFrançois Tigeot return 0; 919*9edbd4a0SFrançois Tigeot 920*9edbd4a0SFrançois Tigeot if (WARN_ON(!plane->crtc)) 921*9edbd4a0SFrançois Tigeot return -EINVAL; 922*9edbd4a0SFrançois Tigeot 923*9edbd4a0SFrançois Tigeot intel_crtc = to_intel_crtc(plane->crtc); 924*9edbd4a0SFrançois Tigeot 925*9edbd4a0SFrançois Tigeot if (intel_crtc->active) { 926e3adcf8fSFrançois Tigeot intel_enable_primary(plane->crtc); 927*9edbd4a0SFrançois Tigeot intel_plane->disable_plane(plane, plane->crtc); 928*9edbd4a0SFrançois Tigeot } 929e3adcf8fSFrançois Tigeot 930*9edbd4a0SFrançois Tigeot if (intel_plane->obj) { 931*9edbd4a0SFrançois Tigeot if (intel_crtc->active) 9328e26cdf6SFrançois Tigeot intel_wait_for_vblank(dev, intel_plane->pipe); 9338e26cdf6SFrançois Tigeot 934a2fdbec6SFrançois Tigeot mutex_lock(&dev->struct_mutex); 935e3adcf8fSFrançois Tigeot intel_unpin_fb_obj(intel_plane->obj); 936a2fdbec6SFrançois Tigeot mutex_unlock(&dev->struct_mutex); 937e3adcf8fSFrançois Tigeot 938*9edbd4a0SFrançois Tigeot intel_plane->obj = NULL; 939*9edbd4a0SFrançois Tigeot } 940*9edbd4a0SFrançois Tigeot 941*9edbd4a0SFrançois Tigeot return 0; 942e3adcf8fSFrançois Tigeot } 943e3adcf8fSFrançois Tigeot 944e3adcf8fSFrançois Tigeot static void intel_destroy_plane(struct drm_plane *plane) 945e3adcf8fSFrançois Tigeot { 946e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(plane); 947e3adcf8fSFrançois Tigeot intel_disable_plane(plane); 948e3adcf8fSFrançois Tigeot drm_plane_cleanup(plane); 949158486a6SFrançois Tigeot kfree(intel_plane); 950e3adcf8fSFrançois Tigeot } 951e3adcf8fSFrançois Tigeot 952e3adcf8fSFrançois Tigeot int intel_sprite_set_colorkey(struct drm_device *dev, void *data, 953e3adcf8fSFrançois Tigeot struct drm_file *file_priv) 954e3adcf8fSFrançois Tigeot { 955e3adcf8fSFrançois Tigeot struct drm_intel_sprite_colorkey *set = data; 956e3adcf8fSFrançois Tigeot struct drm_mode_object *obj; 957e3adcf8fSFrançois Tigeot struct drm_plane *plane; 958e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane; 959e3adcf8fSFrançois Tigeot int ret = 0; 960e3adcf8fSFrançois Tigeot 9612c84b0b6SFrançois Tigeot if (!drm_core_check_feature(dev, DRIVER_MODESET)) 9622c84b0b6SFrançois Tigeot return -ENODEV; 963e3adcf8fSFrançois Tigeot 964e3adcf8fSFrançois Tigeot /* Make sure we don't try to enable both src & dest simultaneously */ 965e3adcf8fSFrançois Tigeot if ((set->flags & (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) == (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) 966e3adcf8fSFrançois Tigeot return -EINVAL; 967e3adcf8fSFrançois Tigeot 968a2fdbec6SFrançois Tigeot drm_modeset_lock_all(dev); 969e3adcf8fSFrançois Tigeot 970e3adcf8fSFrançois Tigeot obj = drm_mode_object_find(dev, set->plane_id, DRM_MODE_OBJECT_PLANE); 971e3adcf8fSFrançois Tigeot if (!obj) { 972*9edbd4a0SFrançois Tigeot ret = -ENOENT; 973e3adcf8fSFrançois Tigeot goto out_unlock; 974e3adcf8fSFrançois Tigeot } 975e3adcf8fSFrançois Tigeot 976e3adcf8fSFrançois Tigeot plane = obj_to_plane(obj); 977e3adcf8fSFrançois Tigeot intel_plane = to_intel_plane(plane); 978e3adcf8fSFrançois Tigeot ret = intel_plane->update_colorkey(plane, set); 979e3adcf8fSFrançois Tigeot 980e3adcf8fSFrançois Tigeot out_unlock: 981a2fdbec6SFrançois Tigeot drm_modeset_unlock_all(dev); 982e3adcf8fSFrançois Tigeot return ret; 983e3adcf8fSFrançois Tigeot } 984e3adcf8fSFrançois Tigeot 985e3adcf8fSFrançois Tigeot int intel_sprite_get_colorkey(struct drm_device *dev, void *data, 986e3adcf8fSFrançois Tigeot struct drm_file *file_priv) 987e3adcf8fSFrançois Tigeot { 988e3adcf8fSFrançois Tigeot struct drm_intel_sprite_colorkey *get = data; 989e3adcf8fSFrançois Tigeot struct drm_mode_object *obj; 990e3adcf8fSFrançois Tigeot struct drm_plane *plane; 991e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane; 992e3adcf8fSFrançois Tigeot int ret = 0; 993e3adcf8fSFrançois Tigeot 9942c84b0b6SFrançois Tigeot if (!drm_core_check_feature(dev, DRIVER_MODESET)) 9952c84b0b6SFrançois Tigeot return -ENODEV; 996e3adcf8fSFrançois Tigeot 997a2fdbec6SFrançois Tigeot drm_modeset_lock_all(dev); 998e3adcf8fSFrançois Tigeot 999e3adcf8fSFrançois Tigeot obj = drm_mode_object_find(dev, get->plane_id, DRM_MODE_OBJECT_PLANE); 1000e3adcf8fSFrançois Tigeot if (!obj) { 1001*9edbd4a0SFrançois Tigeot ret = -ENOENT; 1002e3adcf8fSFrançois Tigeot goto out_unlock; 1003e3adcf8fSFrançois Tigeot } 1004e3adcf8fSFrançois Tigeot 1005e3adcf8fSFrançois Tigeot plane = obj_to_plane(obj); 1006e3adcf8fSFrançois Tigeot intel_plane = to_intel_plane(plane); 1007e3adcf8fSFrançois Tigeot intel_plane->get_colorkey(plane, get); 1008e3adcf8fSFrançois Tigeot 1009e3adcf8fSFrançois Tigeot out_unlock: 1010a2fdbec6SFrançois Tigeot drm_modeset_unlock_all(dev); 1011e3adcf8fSFrançois Tigeot return ret; 1012e3adcf8fSFrançois Tigeot } 1013e3adcf8fSFrançois Tigeot 10148e26cdf6SFrançois Tigeot void intel_plane_restore(struct drm_plane *plane) 10158e26cdf6SFrançois Tigeot { 10168e26cdf6SFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(plane); 10178e26cdf6SFrançois Tigeot 10188e26cdf6SFrançois Tigeot if (!plane->crtc || !plane->fb) 10198e26cdf6SFrançois Tigeot return; 10208e26cdf6SFrançois Tigeot 10218e26cdf6SFrançois Tigeot intel_update_plane(plane, plane->crtc, plane->fb, 10228e26cdf6SFrançois Tigeot intel_plane->crtc_x, intel_plane->crtc_y, 10238e26cdf6SFrançois Tigeot intel_plane->crtc_w, intel_plane->crtc_h, 10248e26cdf6SFrançois Tigeot intel_plane->src_x, intel_plane->src_y, 10258e26cdf6SFrançois Tigeot intel_plane->src_w, intel_plane->src_h); 10268e26cdf6SFrançois Tigeot } 10278e26cdf6SFrançois Tigeot 10285d0b1887SFrançois Tigeot void intel_plane_disable(struct drm_plane *plane) 10295d0b1887SFrançois Tigeot { 10305d0b1887SFrançois Tigeot if (!plane->crtc || !plane->fb) 10315d0b1887SFrançois Tigeot return; 10325d0b1887SFrançois Tigeot 10335d0b1887SFrançois Tigeot intel_disable_plane(plane); 10345d0b1887SFrançois Tigeot } 10355d0b1887SFrançois Tigeot 1036e3adcf8fSFrançois Tigeot static const struct drm_plane_funcs intel_plane_funcs = { 1037e3adcf8fSFrançois Tigeot .update_plane = intel_update_plane, 1038e3adcf8fSFrançois Tigeot .disable_plane = intel_disable_plane, 1039e3adcf8fSFrançois Tigeot .destroy = intel_destroy_plane, 1040e3adcf8fSFrançois Tigeot }; 1041e3adcf8fSFrançois Tigeot 10422c84b0b6SFrançois Tigeot static uint32_t ilk_plane_formats[] = { 10432c84b0b6SFrançois Tigeot DRM_FORMAT_XRGB8888, 10442c84b0b6SFrançois Tigeot DRM_FORMAT_YUYV, 10452c84b0b6SFrançois Tigeot DRM_FORMAT_YVYU, 10462c84b0b6SFrançois Tigeot DRM_FORMAT_UYVY, 10472c84b0b6SFrançois Tigeot DRM_FORMAT_VYUY, 10482c84b0b6SFrançois Tigeot }; 10492c84b0b6SFrançois Tigeot 1050e3adcf8fSFrançois Tigeot static uint32_t snb_plane_formats[] = { 1051e3adcf8fSFrançois Tigeot DRM_FORMAT_XBGR8888, 1052e3adcf8fSFrançois Tigeot DRM_FORMAT_XRGB8888, 1053e3adcf8fSFrançois Tigeot DRM_FORMAT_YUYV, 1054e3adcf8fSFrançois Tigeot DRM_FORMAT_YVYU, 1055e3adcf8fSFrançois Tigeot DRM_FORMAT_UYVY, 1056e3adcf8fSFrançois Tigeot DRM_FORMAT_VYUY, 1057e3adcf8fSFrançois Tigeot }; 1058e3adcf8fSFrançois Tigeot 10598e26cdf6SFrançois Tigeot static uint32_t vlv_plane_formats[] = { 10608e26cdf6SFrançois Tigeot DRM_FORMAT_RGB565, 10618e26cdf6SFrançois Tigeot DRM_FORMAT_ABGR8888, 10628e26cdf6SFrançois Tigeot DRM_FORMAT_ARGB8888, 10638e26cdf6SFrançois Tigeot DRM_FORMAT_XBGR8888, 10648e26cdf6SFrançois Tigeot DRM_FORMAT_XRGB8888, 10658e26cdf6SFrançois Tigeot DRM_FORMAT_XBGR2101010, 10668e26cdf6SFrançois Tigeot DRM_FORMAT_ABGR2101010, 10678e26cdf6SFrançois Tigeot DRM_FORMAT_YUYV, 10688e26cdf6SFrançois Tigeot DRM_FORMAT_YVYU, 10698e26cdf6SFrançois Tigeot DRM_FORMAT_UYVY, 10708e26cdf6SFrançois Tigeot DRM_FORMAT_VYUY, 10718e26cdf6SFrançois Tigeot }; 10728e26cdf6SFrançois Tigeot 1073e3adcf8fSFrançois Tigeot int 10748e26cdf6SFrançois Tigeot intel_plane_init(struct drm_device *dev, enum i915_pipe pipe, int plane) 1075e3adcf8fSFrançois Tigeot { 1076e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane; 1077e3adcf8fSFrançois Tigeot unsigned long possible_crtcs; 10782c84b0b6SFrançois Tigeot const uint32_t *plane_formats; 10792c84b0b6SFrançois Tigeot int num_plane_formats; 1080e3adcf8fSFrançois Tigeot int ret; 1081e3adcf8fSFrançois Tigeot 10822c84b0b6SFrançois Tigeot if (INTEL_INFO(dev)->gen < 5) 1083e3adcf8fSFrançois Tigeot return -ENODEV; 1084e3adcf8fSFrançois Tigeot 1085*9edbd4a0SFrançois Tigeot intel_plane = kzalloc(sizeof(*intel_plane), GFP_KERNEL); 10862c84b0b6SFrançois Tigeot if (!intel_plane) 10872c84b0b6SFrançois Tigeot return -ENOMEM; 10882c84b0b6SFrançois Tigeot 10892c84b0b6SFrançois Tigeot switch (INTEL_INFO(dev)->gen) { 10902c84b0b6SFrançois Tigeot case 5: 10912c84b0b6SFrançois Tigeot case 6: 10922c84b0b6SFrançois Tigeot intel_plane->can_scale = true; 10932c84b0b6SFrançois Tigeot intel_plane->max_downscale = 16; 10942c84b0b6SFrançois Tigeot intel_plane->update_plane = ilk_update_plane; 10952c84b0b6SFrançois Tigeot intel_plane->disable_plane = ilk_disable_plane; 10962c84b0b6SFrançois Tigeot intel_plane->update_colorkey = ilk_update_colorkey; 10972c84b0b6SFrançois Tigeot intel_plane->get_colorkey = ilk_get_colorkey; 1098e3adcf8fSFrançois Tigeot 1099e3adcf8fSFrançois Tigeot if (IS_GEN6(dev)) { 11002c84b0b6SFrançois Tigeot plane_formats = snb_plane_formats; 11012c84b0b6SFrançois Tigeot num_plane_formats = ARRAY_SIZE(snb_plane_formats); 11022c84b0b6SFrançois Tigeot } else { 11032c84b0b6SFrançois Tigeot plane_formats = ilk_plane_formats; 11042c84b0b6SFrançois Tigeot num_plane_formats = ARRAY_SIZE(ilk_plane_formats); 11052c84b0b6SFrançois Tigeot } 11062c84b0b6SFrançois Tigeot break; 11072c84b0b6SFrançois Tigeot 11082c84b0b6SFrançois Tigeot case 7: 1109*9edbd4a0SFrançois Tigeot case 8: 11105d0b1887SFrançois Tigeot if (IS_IVYBRIDGE(dev)) { 11112c84b0b6SFrançois Tigeot intel_plane->can_scale = true; 11125d0b1887SFrançois Tigeot intel_plane->max_downscale = 2; 11135d0b1887SFrançois Tigeot } else { 11145d0b1887SFrançois Tigeot intel_plane->can_scale = false; 11155d0b1887SFrançois Tigeot intel_plane->max_downscale = 1; 11165d0b1887SFrançois Tigeot } 11178e26cdf6SFrançois Tigeot 11188e26cdf6SFrançois Tigeot if (IS_VALLEYVIEW(dev)) { 11198e26cdf6SFrançois Tigeot intel_plane->update_plane = vlv_update_plane; 11208e26cdf6SFrançois Tigeot intel_plane->disable_plane = vlv_disable_plane; 11218e26cdf6SFrançois Tigeot intel_plane->update_colorkey = vlv_update_colorkey; 11228e26cdf6SFrançois Tigeot intel_plane->get_colorkey = vlv_get_colorkey; 11238e26cdf6SFrançois Tigeot 11248e26cdf6SFrançois Tigeot plane_formats = vlv_plane_formats; 11258e26cdf6SFrançois Tigeot num_plane_formats = ARRAY_SIZE(vlv_plane_formats); 11268e26cdf6SFrançois Tigeot } else { 1127e3adcf8fSFrançois Tigeot intel_plane->update_plane = ivb_update_plane; 1128e3adcf8fSFrançois Tigeot intel_plane->disable_plane = ivb_disable_plane; 1129e3adcf8fSFrançois Tigeot intel_plane->update_colorkey = ivb_update_colorkey; 1130e3adcf8fSFrançois Tigeot intel_plane->get_colorkey = ivb_get_colorkey; 11312c84b0b6SFrançois Tigeot 11322c84b0b6SFrançois Tigeot plane_formats = snb_plane_formats; 11332c84b0b6SFrançois Tigeot num_plane_formats = ARRAY_SIZE(snb_plane_formats); 11348e26cdf6SFrançois Tigeot } 11352c84b0b6SFrançois Tigeot break; 11362c84b0b6SFrançois Tigeot 11372c84b0b6SFrançois Tigeot default: 1138158486a6SFrançois Tigeot kfree(intel_plane); 11392c84b0b6SFrançois Tigeot return -ENODEV; 1140e3adcf8fSFrançois Tigeot } 1141e3adcf8fSFrançois Tigeot 1142e3adcf8fSFrançois Tigeot intel_plane->pipe = pipe; 11438e26cdf6SFrançois Tigeot intel_plane->plane = plane; 1144e3adcf8fSFrançois Tigeot possible_crtcs = (1 << pipe); 1145e3adcf8fSFrançois Tigeot ret = drm_plane_init(dev, &intel_plane->base, possible_crtcs, 11462c84b0b6SFrançois Tigeot &intel_plane_funcs, 11472c84b0b6SFrançois Tigeot plane_formats, num_plane_formats, 11482c84b0b6SFrançois Tigeot false); 1149e3adcf8fSFrançois Tigeot if (ret) 1150158486a6SFrançois Tigeot kfree(intel_plane); 1151e3adcf8fSFrançois Tigeot 1152e3adcf8fSFrançois Tigeot return ret; 1153e3adcf8fSFrançois Tigeot } 1154