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 40*ba55f2f5SFrançois Tigeot static int usecs_to_scanlines(const struct drm_display_mode *mode, int usecs) 41*ba55f2f5SFrançois Tigeot { 42*ba55f2f5SFrançois Tigeot /* paranoia */ 43*ba55f2f5SFrançois Tigeot if (!mode->crtc_htotal) 44*ba55f2f5SFrançois Tigeot return 1; 45*ba55f2f5SFrançois Tigeot 46*ba55f2f5SFrançois Tigeot return DIV_ROUND_UP(usecs * mode->crtc_clock, 1000 * mode->crtc_htotal); 47*ba55f2f5SFrançois Tigeot } 48*ba55f2f5SFrançois Tigeot 49*ba55f2f5SFrançois Tigeot static bool intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl_count) 50*ba55f2f5SFrançois Tigeot { 51*ba55f2f5SFrançois Tigeot struct drm_device *dev = crtc->base.dev; 52*ba55f2f5SFrançois Tigeot const struct drm_display_mode *mode = &crtc->config.adjusted_mode; 53*ba55f2f5SFrançois Tigeot enum i915_pipe pipe = crtc->pipe; 54*ba55f2f5SFrançois Tigeot long timeout = msecs_to_jiffies_timeout(1); 55*ba55f2f5SFrançois Tigeot int scanline, min, max, vblank_start; 56*ba55f2f5SFrançois Tigeot DEFINE_WAIT(wait); 57*ba55f2f5SFrançois Tigeot 58*ba55f2f5SFrançois Tigeot WARN_ON(!drm_modeset_is_locked(&crtc->base.mutex)); 59*ba55f2f5SFrançois Tigeot 60*ba55f2f5SFrançois Tigeot vblank_start = mode->crtc_vblank_start; 61*ba55f2f5SFrançois Tigeot if (mode->flags & DRM_MODE_FLAG_INTERLACE) 62*ba55f2f5SFrançois Tigeot vblank_start = DIV_ROUND_UP(vblank_start, 2); 63*ba55f2f5SFrançois Tigeot 64*ba55f2f5SFrançois Tigeot /* FIXME needs to be calibrated sensibly */ 65*ba55f2f5SFrançois Tigeot min = vblank_start - usecs_to_scanlines(mode, 100); 66*ba55f2f5SFrançois Tigeot max = vblank_start - 1; 67*ba55f2f5SFrançois Tigeot 68*ba55f2f5SFrançois Tigeot if (min <= 0 || max <= 0) 69*ba55f2f5SFrançois Tigeot return false; 70*ba55f2f5SFrançois Tigeot 71*ba55f2f5SFrançois Tigeot if (WARN_ON(drm_vblank_get(dev, pipe))) 72*ba55f2f5SFrançois Tigeot return false; 73*ba55f2f5SFrançois Tigeot 74*ba55f2f5SFrançois Tigeot local_irq_disable(); 75*ba55f2f5SFrançois Tigeot 76*ba55f2f5SFrançois Tigeot trace_i915_pipe_update_start(crtc, min, max); 77*ba55f2f5SFrançois Tigeot 78*ba55f2f5SFrançois Tigeot for (;;) { 79*ba55f2f5SFrançois Tigeot /* 80*ba55f2f5SFrançois Tigeot * prepare_to_wait() has a memory barrier, which guarantees 81*ba55f2f5SFrançois Tigeot * other CPUs can see the task state update by the time we 82*ba55f2f5SFrançois Tigeot * read the scanline. 83*ba55f2f5SFrançois Tigeot */ 84*ba55f2f5SFrançois Tigeot prepare_to_wait(&crtc->vbl_wait, &wait, TASK_UNINTERRUPTIBLE); 85*ba55f2f5SFrançois Tigeot 86*ba55f2f5SFrançois Tigeot scanline = intel_get_crtc_scanline(crtc); 87*ba55f2f5SFrançois Tigeot if (scanline < min || scanline > max) 88*ba55f2f5SFrançois Tigeot break; 89*ba55f2f5SFrançois Tigeot 90*ba55f2f5SFrançois Tigeot if (timeout <= 0) { 91*ba55f2f5SFrançois Tigeot DRM_ERROR("Potential atomic update failure on pipe %c\n", 92*ba55f2f5SFrançois Tigeot pipe_name(crtc->pipe)); 93*ba55f2f5SFrançois Tigeot break; 94*ba55f2f5SFrançois Tigeot } 95*ba55f2f5SFrançois Tigeot 96*ba55f2f5SFrançois Tigeot local_irq_enable(); 97*ba55f2f5SFrançois Tigeot 98*ba55f2f5SFrançois Tigeot timeout = schedule_timeout(timeout); 99*ba55f2f5SFrançois Tigeot 100*ba55f2f5SFrançois Tigeot local_irq_disable(); 101*ba55f2f5SFrançois Tigeot } 102*ba55f2f5SFrançois Tigeot 103*ba55f2f5SFrançois Tigeot finish_wait(&crtc->vbl_wait, &wait); 104*ba55f2f5SFrançois Tigeot 105*ba55f2f5SFrançois Tigeot drm_vblank_put(dev, pipe); 106*ba55f2f5SFrançois Tigeot 107*ba55f2f5SFrançois Tigeot *start_vbl_count = dev->driver->get_vblank_counter(dev, pipe); 108*ba55f2f5SFrançois Tigeot 109*ba55f2f5SFrançois Tigeot trace_i915_pipe_update_vblank_evaded(crtc, min, max, *start_vbl_count); 110*ba55f2f5SFrançois Tigeot 111*ba55f2f5SFrançois Tigeot return true; 112*ba55f2f5SFrançois Tigeot } 113*ba55f2f5SFrançois Tigeot 114*ba55f2f5SFrançois Tigeot static void intel_pipe_update_end(struct intel_crtc *crtc, u32 start_vbl_count) 115*ba55f2f5SFrançois Tigeot { 116*ba55f2f5SFrançois Tigeot struct drm_device *dev = crtc->base.dev; 117*ba55f2f5SFrançois Tigeot enum i915_pipe pipe = crtc->pipe; 118*ba55f2f5SFrançois Tigeot u32 end_vbl_count = dev->driver->get_vblank_counter(dev, pipe); 119*ba55f2f5SFrançois Tigeot 120*ba55f2f5SFrançois Tigeot trace_i915_pipe_update_end(crtc, end_vbl_count); 121*ba55f2f5SFrançois Tigeot 122*ba55f2f5SFrançois Tigeot local_irq_enable(); 123*ba55f2f5SFrançois Tigeot 124*ba55f2f5SFrançois Tigeot if (start_vbl_count != end_vbl_count) 125*ba55f2f5SFrançois Tigeot DRM_ERROR("Atomic update failure on pipe %c (start=%u end=%u)\n", 126*ba55f2f5SFrançois Tigeot pipe_name(pipe), start_vbl_count, end_vbl_count); 127*ba55f2f5SFrançois Tigeot } 128*ba55f2f5SFrançois Tigeot 129*ba55f2f5SFrançois Tigeot static void intel_update_primary_plane(struct intel_crtc *crtc) 130*ba55f2f5SFrançois Tigeot { 131*ba55f2f5SFrançois Tigeot struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; 132*ba55f2f5SFrançois Tigeot int reg = DSPCNTR(crtc->plane); 133*ba55f2f5SFrançois Tigeot 134*ba55f2f5SFrançois Tigeot if (crtc->primary_enabled) 135*ba55f2f5SFrançois Tigeot I915_WRITE(reg, I915_READ(reg) | DISPLAY_PLANE_ENABLE); 136*ba55f2f5SFrançois Tigeot else 137*ba55f2f5SFrançois Tigeot I915_WRITE(reg, I915_READ(reg) & ~DISPLAY_PLANE_ENABLE); 138*ba55f2f5SFrançois Tigeot } 139*ba55f2f5SFrançois Tigeot 140e3adcf8fSFrançois Tigeot static void 1419edbd4a0SFrançois Tigeot vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, 1429edbd4a0SFrançois Tigeot struct drm_framebuffer *fb, 1438e26cdf6SFrançois Tigeot struct drm_i915_gem_object *obj, int crtc_x, int crtc_y, 1448e26cdf6SFrançois Tigeot unsigned int crtc_w, unsigned int crtc_h, 1458e26cdf6SFrançois Tigeot uint32_t x, uint32_t y, 1468e26cdf6SFrançois Tigeot uint32_t src_w, uint32_t src_h) 1478e26cdf6SFrançois Tigeot { 1488e26cdf6SFrançois Tigeot struct drm_device *dev = dplane->dev; 1498e26cdf6SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 1508e26cdf6SFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(dplane); 151*ba55f2f5SFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 1528e26cdf6SFrançois Tigeot int pipe = intel_plane->pipe; 1538e26cdf6SFrançois Tigeot int plane = intel_plane->plane; 1548e26cdf6SFrançois Tigeot u32 sprctl; 1558e26cdf6SFrançois Tigeot unsigned long sprsurf_offset, linear_offset; 1568e26cdf6SFrançois Tigeot int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); 157*ba55f2f5SFrançois Tigeot u32 start_vbl_count; 158*ba55f2f5SFrançois Tigeot bool atomic_update; 1598e26cdf6SFrançois Tigeot 1608e26cdf6SFrançois Tigeot sprctl = I915_READ(SPCNTR(pipe, plane)); 1618e26cdf6SFrançois Tigeot 1628e26cdf6SFrançois Tigeot /* Mask out pixel format bits in case we change it */ 1638e26cdf6SFrançois Tigeot sprctl &= ~SP_PIXFORMAT_MASK; 1648e26cdf6SFrançois Tigeot sprctl &= ~SP_YUV_BYTE_ORDER_MASK; 1658e26cdf6SFrançois Tigeot sprctl &= ~SP_TILED; 1668e26cdf6SFrançois Tigeot 1678e26cdf6SFrançois Tigeot switch (fb->pixel_format) { 1688e26cdf6SFrançois Tigeot case DRM_FORMAT_YUYV: 1698e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_YUYV; 1708e26cdf6SFrançois Tigeot break; 1718e26cdf6SFrançois Tigeot case DRM_FORMAT_YVYU: 1728e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_YVYU; 1738e26cdf6SFrançois Tigeot break; 1748e26cdf6SFrançois Tigeot case DRM_FORMAT_UYVY: 1758e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_UYVY; 1768e26cdf6SFrançois Tigeot break; 1778e26cdf6SFrançois Tigeot case DRM_FORMAT_VYUY: 1788e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_VYUY; 1798e26cdf6SFrançois Tigeot break; 1808e26cdf6SFrançois Tigeot case DRM_FORMAT_RGB565: 1818e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_BGR565; 1828e26cdf6SFrançois Tigeot break; 1838e26cdf6SFrançois Tigeot case DRM_FORMAT_XRGB8888: 1848e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_BGRX8888; 1858e26cdf6SFrançois Tigeot break; 1868e26cdf6SFrançois Tigeot case DRM_FORMAT_ARGB8888: 1878e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_BGRA8888; 1888e26cdf6SFrançois Tigeot break; 1898e26cdf6SFrançois Tigeot case DRM_FORMAT_XBGR2101010: 1908e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_RGBX1010102; 1918e26cdf6SFrançois Tigeot break; 1928e26cdf6SFrançois Tigeot case DRM_FORMAT_ABGR2101010: 1938e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_RGBA1010102; 1948e26cdf6SFrançois Tigeot break; 1958e26cdf6SFrançois Tigeot case DRM_FORMAT_XBGR8888: 1968e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_RGBX8888; 1978e26cdf6SFrançois Tigeot break; 1988e26cdf6SFrançois Tigeot case DRM_FORMAT_ABGR8888: 1998e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_RGBA8888; 2008e26cdf6SFrançois Tigeot break; 2018e26cdf6SFrançois Tigeot default: 2028e26cdf6SFrançois Tigeot /* 2038e26cdf6SFrançois Tigeot * If we get here one of the upper layers failed to filter 2048e26cdf6SFrançois Tigeot * out the unsupported plane formats 2058e26cdf6SFrançois Tigeot */ 2068e26cdf6SFrançois Tigeot BUG(); 2078e26cdf6SFrançois Tigeot break; 2088e26cdf6SFrançois Tigeot } 2098e26cdf6SFrançois Tigeot 2109edbd4a0SFrançois Tigeot /* 2119edbd4a0SFrançois Tigeot * Enable gamma to match primary/cursor plane behaviour. 2129edbd4a0SFrançois Tigeot * FIXME should be user controllable via propertiesa. 2139edbd4a0SFrançois Tigeot */ 2149edbd4a0SFrançois Tigeot sprctl |= SP_GAMMA_ENABLE; 2159edbd4a0SFrançois Tigeot 2168e26cdf6SFrançois Tigeot if (obj->tiling_mode != I915_TILING_NONE) 2178e26cdf6SFrançois Tigeot sprctl |= SP_TILED; 2188e26cdf6SFrançois Tigeot 2198e26cdf6SFrançois Tigeot sprctl |= SP_ENABLE; 2208e26cdf6SFrançois Tigeot 2219edbd4a0SFrançois Tigeot intel_update_sprite_watermarks(dplane, crtc, src_w, pixel_size, true, 2229edbd4a0SFrançois Tigeot src_w != crtc_w || src_h != crtc_h); 2239edbd4a0SFrançois Tigeot 2248e26cdf6SFrançois Tigeot /* Sizes are 0 based */ 2258e26cdf6SFrançois Tigeot src_w--; 2268e26cdf6SFrançois Tigeot src_h--; 2278e26cdf6SFrançois Tigeot crtc_w--; 2288e26cdf6SFrançois Tigeot crtc_h--; 2298e26cdf6SFrançois Tigeot 2308e26cdf6SFrançois Tigeot linear_offset = y * fb->pitches[0] + x * pixel_size; 2318e26cdf6SFrançois Tigeot sprsurf_offset = intel_gen4_compute_page_offset(&x, &y, 2328e26cdf6SFrançois Tigeot obj->tiling_mode, 2338e26cdf6SFrançois Tigeot pixel_size, 2348e26cdf6SFrançois Tigeot fb->pitches[0]); 2358e26cdf6SFrançois Tigeot linear_offset -= sprsurf_offset; 2368e26cdf6SFrançois Tigeot 237*ba55f2f5SFrançois Tigeot atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count); 238*ba55f2f5SFrançois Tigeot 239*ba55f2f5SFrançois Tigeot intel_update_primary_plane(intel_crtc); 240*ba55f2f5SFrançois Tigeot 241*ba55f2f5SFrançois Tigeot I915_WRITE(SPSTRIDE(pipe, plane), fb->pitches[0]); 242*ba55f2f5SFrançois Tigeot I915_WRITE(SPPOS(pipe, plane), (crtc_y << 16) | crtc_x); 243*ba55f2f5SFrançois Tigeot 2448e26cdf6SFrançois Tigeot if (obj->tiling_mode != I915_TILING_NONE) 2458e26cdf6SFrançois Tigeot I915_WRITE(SPTILEOFF(pipe, plane), (y << 16) | x); 2468e26cdf6SFrançois Tigeot else 2478e26cdf6SFrançois Tigeot I915_WRITE(SPLINOFF(pipe, plane), linear_offset); 2488e26cdf6SFrançois Tigeot 2498e26cdf6SFrançois Tigeot I915_WRITE(SPSIZE(pipe, plane), (crtc_h << 16) | crtc_w); 2508e26cdf6SFrançois Tigeot I915_WRITE(SPCNTR(pipe, plane), sprctl); 2519edbd4a0SFrançois Tigeot I915_WRITE(SPSURF(pipe, plane), i915_gem_obj_ggtt_offset(obj) + 2528e26cdf6SFrançois Tigeot sprsurf_offset); 253*ba55f2f5SFrançois Tigeot 254*ba55f2f5SFrançois Tigeot intel_flush_primary_plane(dev_priv, intel_crtc->plane); 255*ba55f2f5SFrançois Tigeot 256*ba55f2f5SFrançois Tigeot if (atomic_update) 257*ba55f2f5SFrançois Tigeot intel_pipe_update_end(intel_crtc, start_vbl_count); 2588e26cdf6SFrançois Tigeot } 2598e26cdf6SFrançois Tigeot 2608e26cdf6SFrançois Tigeot static void 2619edbd4a0SFrançois Tigeot vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc) 2628e26cdf6SFrançois Tigeot { 2638e26cdf6SFrançois Tigeot struct drm_device *dev = dplane->dev; 2648e26cdf6SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 2658e26cdf6SFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(dplane); 266*ba55f2f5SFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 2678e26cdf6SFrançois Tigeot int pipe = intel_plane->pipe; 2688e26cdf6SFrançois Tigeot int plane = intel_plane->plane; 269*ba55f2f5SFrançois Tigeot u32 start_vbl_count; 270*ba55f2f5SFrançois Tigeot bool atomic_update; 271*ba55f2f5SFrançois Tigeot 272*ba55f2f5SFrançois Tigeot atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count); 273*ba55f2f5SFrançois Tigeot 274*ba55f2f5SFrançois Tigeot intel_update_primary_plane(intel_crtc); 2758e26cdf6SFrançois Tigeot 2768e26cdf6SFrançois Tigeot I915_WRITE(SPCNTR(pipe, plane), I915_READ(SPCNTR(pipe, plane)) & 2778e26cdf6SFrançois Tigeot ~SP_ENABLE); 2788e26cdf6SFrançois Tigeot /* Activate double buffered register update */ 2799edbd4a0SFrançois Tigeot I915_WRITE(SPSURF(pipe, plane), 0); 280*ba55f2f5SFrançois Tigeot 281*ba55f2f5SFrançois Tigeot intel_flush_primary_plane(dev_priv, intel_crtc->plane); 282*ba55f2f5SFrançois Tigeot 283*ba55f2f5SFrançois Tigeot if (atomic_update) 284*ba55f2f5SFrançois Tigeot intel_pipe_update_end(intel_crtc, start_vbl_count); 2859edbd4a0SFrançois Tigeot 2869edbd4a0SFrançois Tigeot intel_update_sprite_watermarks(dplane, crtc, 0, 0, false, false); 2878e26cdf6SFrançois Tigeot } 2888e26cdf6SFrançois Tigeot 2898e26cdf6SFrançois Tigeot static int 2908e26cdf6SFrançois Tigeot vlv_update_colorkey(struct drm_plane *dplane, 2918e26cdf6SFrançois Tigeot struct drm_intel_sprite_colorkey *key) 2928e26cdf6SFrançois Tigeot { 2938e26cdf6SFrançois Tigeot struct drm_device *dev = dplane->dev; 2948e26cdf6SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 2958e26cdf6SFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(dplane); 2968e26cdf6SFrançois Tigeot int pipe = intel_plane->pipe; 2978e26cdf6SFrançois Tigeot int plane = intel_plane->plane; 2988e26cdf6SFrançois Tigeot u32 sprctl; 2998e26cdf6SFrançois Tigeot 3008e26cdf6SFrançois Tigeot if (key->flags & I915_SET_COLORKEY_DESTINATION) 3018e26cdf6SFrançois Tigeot return -EINVAL; 3028e26cdf6SFrançois Tigeot 3038e26cdf6SFrançois Tigeot I915_WRITE(SPKEYMINVAL(pipe, plane), key->min_value); 3048e26cdf6SFrançois Tigeot I915_WRITE(SPKEYMAXVAL(pipe, plane), key->max_value); 3058e26cdf6SFrançois Tigeot I915_WRITE(SPKEYMSK(pipe, plane), key->channel_mask); 3068e26cdf6SFrançois Tigeot 3078e26cdf6SFrançois Tigeot sprctl = I915_READ(SPCNTR(pipe, plane)); 3088e26cdf6SFrançois Tigeot sprctl &= ~SP_SOURCE_KEY; 3098e26cdf6SFrançois Tigeot if (key->flags & I915_SET_COLORKEY_SOURCE) 3108e26cdf6SFrançois Tigeot sprctl |= SP_SOURCE_KEY; 3118e26cdf6SFrançois Tigeot I915_WRITE(SPCNTR(pipe, plane), sprctl); 3128e26cdf6SFrançois Tigeot 3138e26cdf6SFrançois Tigeot POSTING_READ(SPKEYMSK(pipe, plane)); 3148e26cdf6SFrançois Tigeot 3158e26cdf6SFrançois Tigeot return 0; 3168e26cdf6SFrançois Tigeot } 3178e26cdf6SFrançois Tigeot 3188e26cdf6SFrançois Tigeot static void 3198e26cdf6SFrançois Tigeot vlv_get_colorkey(struct drm_plane *dplane, 3208e26cdf6SFrançois Tigeot struct drm_intel_sprite_colorkey *key) 3218e26cdf6SFrançois Tigeot { 3228e26cdf6SFrançois Tigeot struct drm_device *dev = dplane->dev; 3238e26cdf6SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 3248e26cdf6SFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(dplane); 3258e26cdf6SFrançois Tigeot int pipe = intel_plane->pipe; 3268e26cdf6SFrançois Tigeot int plane = intel_plane->plane; 3278e26cdf6SFrançois Tigeot u32 sprctl; 3288e26cdf6SFrançois Tigeot 3298e26cdf6SFrançois Tigeot key->min_value = I915_READ(SPKEYMINVAL(pipe, plane)); 3308e26cdf6SFrançois Tigeot key->max_value = I915_READ(SPKEYMAXVAL(pipe, plane)); 3318e26cdf6SFrançois Tigeot key->channel_mask = I915_READ(SPKEYMSK(pipe, plane)); 3328e26cdf6SFrançois Tigeot 3338e26cdf6SFrançois Tigeot sprctl = I915_READ(SPCNTR(pipe, plane)); 3348e26cdf6SFrançois Tigeot if (sprctl & SP_SOURCE_KEY) 3358e26cdf6SFrançois Tigeot key->flags = I915_SET_COLORKEY_SOURCE; 3368e26cdf6SFrançois Tigeot else 3378e26cdf6SFrançois Tigeot key->flags = I915_SET_COLORKEY_NONE; 3388e26cdf6SFrançois Tigeot } 3398e26cdf6SFrançois Tigeot 3408e26cdf6SFrançois Tigeot static void 3419edbd4a0SFrançois Tigeot ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, 3429edbd4a0SFrançois Tigeot struct drm_framebuffer *fb, 343e3adcf8fSFrançois Tigeot struct drm_i915_gem_object *obj, int crtc_x, int crtc_y, 344e3adcf8fSFrançois Tigeot unsigned int crtc_w, unsigned int crtc_h, 345e3adcf8fSFrançois Tigeot uint32_t x, uint32_t y, 346e3adcf8fSFrançois Tigeot uint32_t src_w, uint32_t src_h) 347e3adcf8fSFrançois Tigeot { 348e3adcf8fSFrançois Tigeot struct drm_device *dev = plane->dev; 349e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 350e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(plane); 351*ba55f2f5SFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 352e3adcf8fSFrançois Tigeot int pipe = intel_plane->pipe; 353e3adcf8fSFrançois Tigeot u32 sprctl, sprscale = 0; 3542c84b0b6SFrançois Tigeot unsigned long sprsurf_offset, linear_offset; 3552c84b0b6SFrançois Tigeot int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); 356*ba55f2f5SFrançois Tigeot u32 start_vbl_count; 357*ba55f2f5SFrançois Tigeot bool atomic_update; 358e3adcf8fSFrançois Tigeot 359e3adcf8fSFrançois Tigeot sprctl = I915_READ(SPRCTL(pipe)); 360e3adcf8fSFrançois Tigeot 361e3adcf8fSFrançois Tigeot /* Mask out pixel format bits in case we change it */ 362e3adcf8fSFrançois Tigeot sprctl &= ~SPRITE_PIXFORMAT_MASK; 363e3adcf8fSFrançois Tigeot sprctl &= ~SPRITE_RGB_ORDER_RGBX; 364e3adcf8fSFrançois Tigeot sprctl &= ~SPRITE_YUV_BYTE_ORDER_MASK; 3652c84b0b6SFrançois Tigeot sprctl &= ~SPRITE_TILED; 366e3adcf8fSFrançois Tigeot 367e3adcf8fSFrançois Tigeot switch (fb->pixel_format) { 368e3adcf8fSFrançois Tigeot case DRM_FORMAT_XBGR8888: 3692c84b0b6SFrançois Tigeot sprctl |= SPRITE_FORMAT_RGBX888 | SPRITE_RGB_ORDER_RGBX; 370e3adcf8fSFrançois Tigeot break; 371e3adcf8fSFrançois Tigeot case DRM_FORMAT_XRGB8888: 3722c84b0b6SFrançois Tigeot sprctl |= SPRITE_FORMAT_RGBX888; 373e3adcf8fSFrançois Tigeot break; 374e3adcf8fSFrançois Tigeot case DRM_FORMAT_YUYV: 375e3adcf8fSFrançois Tigeot sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YUYV; 376e3adcf8fSFrançois Tigeot break; 377e3adcf8fSFrançois Tigeot case DRM_FORMAT_YVYU: 378e3adcf8fSFrançois Tigeot sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YVYU; 379e3adcf8fSFrançois Tigeot break; 380e3adcf8fSFrançois Tigeot case DRM_FORMAT_UYVY: 381e3adcf8fSFrançois Tigeot sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_UYVY; 382e3adcf8fSFrançois Tigeot break; 383e3adcf8fSFrançois Tigeot case DRM_FORMAT_VYUY: 384e3adcf8fSFrançois Tigeot sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_VYUY; 385e3adcf8fSFrançois Tigeot break; 386e3adcf8fSFrançois Tigeot default: 3872c84b0b6SFrançois Tigeot BUG(); 388e3adcf8fSFrançois Tigeot } 389e3adcf8fSFrançois Tigeot 3909edbd4a0SFrançois Tigeot /* 3919edbd4a0SFrançois Tigeot * Enable gamma to match primary/cursor plane behaviour. 3929edbd4a0SFrançois Tigeot * FIXME should be user controllable via propertiesa. 3939edbd4a0SFrançois Tigeot */ 3949edbd4a0SFrançois Tigeot sprctl |= SPRITE_GAMMA_ENABLE; 3959edbd4a0SFrançois Tigeot 396e3adcf8fSFrançois Tigeot if (obj->tiling_mode != I915_TILING_NONE) 397e3adcf8fSFrançois Tigeot sprctl |= SPRITE_TILED; 398e3adcf8fSFrançois Tigeot 3999edbd4a0SFrançois Tigeot if (IS_HASWELL(dev) || IS_BROADWELL(dev)) 4009edbd4a0SFrançois Tigeot sprctl &= ~SPRITE_TRICKLE_FEED_DISABLE; 4019edbd4a0SFrançois Tigeot else 402e3adcf8fSFrançois Tigeot sprctl |= SPRITE_TRICKLE_FEED_DISABLE; 4039edbd4a0SFrançois Tigeot 404e3adcf8fSFrançois Tigeot sprctl |= SPRITE_ENABLE; 405e3adcf8fSFrançois Tigeot 4069edbd4a0SFrançois Tigeot if (IS_HASWELL(dev) || IS_BROADWELL(dev)) 407a2fdbec6SFrançois Tigeot sprctl |= SPRITE_PIPE_CSC_ENABLE; 408a2fdbec6SFrançois Tigeot 4099edbd4a0SFrançois Tigeot intel_update_sprite_watermarks(plane, crtc, src_w, pixel_size, true, 4109edbd4a0SFrançois Tigeot src_w != crtc_w || src_h != crtc_h); 4119edbd4a0SFrançois Tigeot 412e3adcf8fSFrançois Tigeot /* Sizes are 0 based */ 413e3adcf8fSFrançois Tigeot src_w--; 414e3adcf8fSFrançois Tigeot src_h--; 415e3adcf8fSFrançois Tigeot crtc_w--; 416e3adcf8fSFrançois Tigeot crtc_h--; 417e3adcf8fSFrançois Tigeot 4189edbd4a0SFrançois Tigeot if (crtc_w != src_w || crtc_h != src_h) 419e3adcf8fSFrançois Tigeot sprscale = SPRITE_SCALE_ENABLE | (src_w << 16) | src_h; 420e3adcf8fSFrançois Tigeot 4212c84b0b6SFrançois Tigeot linear_offset = y * fb->pitches[0] + x * pixel_size; 4222c84b0b6SFrançois Tigeot sprsurf_offset = 423df188185SFrançois Tigeot intel_gen4_compute_page_offset(&x, &y, obj->tiling_mode, 4242c84b0b6SFrançois Tigeot pixel_size, fb->pitches[0]); 4252c84b0b6SFrançois Tigeot linear_offset -= sprsurf_offset; 4262c84b0b6SFrançois Tigeot 427*ba55f2f5SFrançois Tigeot atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count); 428*ba55f2f5SFrançois Tigeot 429*ba55f2f5SFrançois Tigeot intel_update_primary_plane(intel_crtc); 430*ba55f2f5SFrançois Tigeot 431*ba55f2f5SFrançois Tigeot I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]); 432*ba55f2f5SFrançois Tigeot I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x); 433*ba55f2f5SFrançois Tigeot 4342c84b0b6SFrançois Tigeot /* HSW consolidates SPRTILEOFF and SPRLINOFF into a single SPROFFSET 4352c84b0b6SFrançois Tigeot * register */ 4369edbd4a0SFrançois Tigeot if (IS_HASWELL(dev) || IS_BROADWELL(dev)) 4372c84b0b6SFrançois Tigeot I915_WRITE(SPROFFSET(pipe), (y << 16) | x); 4382c84b0b6SFrançois Tigeot else if (obj->tiling_mode != I915_TILING_NONE) 4392c84b0b6SFrançois Tigeot I915_WRITE(SPRTILEOFF(pipe), (y << 16) | x); 4402c84b0b6SFrançois Tigeot else 4412c84b0b6SFrançois Tigeot I915_WRITE(SPRLINOFF(pipe), linear_offset); 4422c84b0b6SFrançois Tigeot 443e3adcf8fSFrançois Tigeot I915_WRITE(SPRSIZE(pipe), (crtc_h << 16) | crtc_w); 4442c84b0b6SFrançois Tigeot if (intel_plane->can_scale) 445e3adcf8fSFrançois Tigeot I915_WRITE(SPRSCALE(pipe), sprscale); 446e3adcf8fSFrançois Tigeot I915_WRITE(SPRCTL(pipe), sprctl); 4479edbd4a0SFrançois Tigeot I915_WRITE(SPRSURF(pipe), 4489edbd4a0SFrançois Tigeot i915_gem_obj_ggtt_offset(obj) + sprsurf_offset); 449*ba55f2f5SFrançois Tigeot 450*ba55f2f5SFrançois Tigeot intel_flush_primary_plane(dev_priv, intel_crtc->plane); 451*ba55f2f5SFrançois Tigeot 452*ba55f2f5SFrançois Tigeot if (atomic_update) 453*ba55f2f5SFrançois Tigeot intel_pipe_update_end(intel_crtc, start_vbl_count); 454e3adcf8fSFrançois Tigeot } 455e3adcf8fSFrançois Tigeot 456e3adcf8fSFrançois Tigeot static void 4579edbd4a0SFrançois Tigeot ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc) 458e3adcf8fSFrançois Tigeot { 459e3adcf8fSFrançois Tigeot struct drm_device *dev = plane->dev; 460e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 461e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(plane); 462*ba55f2f5SFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 463e3adcf8fSFrançois Tigeot int pipe = intel_plane->pipe; 464*ba55f2f5SFrançois Tigeot u32 start_vbl_count; 465*ba55f2f5SFrançois Tigeot bool atomic_update; 466*ba55f2f5SFrançois Tigeot 467*ba55f2f5SFrançois Tigeot atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count); 468*ba55f2f5SFrançois Tigeot 469*ba55f2f5SFrançois Tigeot intel_update_primary_plane(intel_crtc); 470e3adcf8fSFrançois Tigeot 471e3adcf8fSFrançois Tigeot I915_WRITE(SPRCTL(pipe), I915_READ(SPRCTL(pipe)) & ~SPRITE_ENABLE); 472e3adcf8fSFrançois Tigeot /* Can't leave the scaler enabled... */ 4732c84b0b6SFrançois Tigeot if (intel_plane->can_scale) 474e3adcf8fSFrançois Tigeot I915_WRITE(SPRSCALE(pipe), 0); 475e3adcf8fSFrançois Tigeot /* Activate double buffered register update */ 4769edbd4a0SFrançois Tigeot I915_WRITE(SPRSURF(pipe), 0); 477*ba55f2f5SFrançois Tigeot 478*ba55f2f5SFrançois Tigeot intel_flush_primary_plane(dev_priv, intel_crtc->plane); 479*ba55f2f5SFrançois Tigeot 480*ba55f2f5SFrançois Tigeot if (atomic_update) 481*ba55f2f5SFrançois Tigeot intel_pipe_update_end(intel_crtc, start_vbl_count); 4822c84b0b6SFrançois Tigeot 4839edbd4a0SFrançois Tigeot /* 4849edbd4a0SFrançois Tigeot * Avoid underruns when disabling the sprite. 4859edbd4a0SFrançois Tigeot * FIXME remove once watermark updates are done properly. 4869edbd4a0SFrançois Tigeot */ 4879edbd4a0SFrançois Tigeot intel_wait_for_vblank(dev, pipe); 488a2fdbec6SFrançois Tigeot 4899edbd4a0SFrançois Tigeot intel_update_sprite_watermarks(plane, crtc, 0, 0, false, false); 490e3adcf8fSFrançois Tigeot } 491e3adcf8fSFrançois Tigeot 492e3adcf8fSFrançois Tigeot static int 493e3adcf8fSFrançois Tigeot ivb_update_colorkey(struct drm_plane *plane, 494e3adcf8fSFrançois Tigeot struct drm_intel_sprite_colorkey *key) 495e3adcf8fSFrançois Tigeot { 496e3adcf8fSFrançois Tigeot struct drm_device *dev = plane->dev; 497e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 498e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane; 499e3adcf8fSFrançois Tigeot u32 sprctl; 500e3adcf8fSFrançois Tigeot int ret = 0; 501e3adcf8fSFrançois Tigeot 502e3adcf8fSFrançois Tigeot intel_plane = to_intel_plane(plane); 503e3adcf8fSFrançois Tigeot 504e3adcf8fSFrançois Tigeot I915_WRITE(SPRKEYVAL(intel_plane->pipe), key->min_value); 505e3adcf8fSFrançois Tigeot I915_WRITE(SPRKEYMAX(intel_plane->pipe), key->max_value); 506e3adcf8fSFrançois Tigeot I915_WRITE(SPRKEYMSK(intel_plane->pipe), key->channel_mask); 507e3adcf8fSFrançois Tigeot 508e3adcf8fSFrançois Tigeot sprctl = I915_READ(SPRCTL(intel_plane->pipe)); 509e3adcf8fSFrançois Tigeot sprctl &= ~(SPRITE_SOURCE_KEY | SPRITE_DEST_KEY); 510e3adcf8fSFrançois Tigeot if (key->flags & I915_SET_COLORKEY_DESTINATION) 511e3adcf8fSFrançois Tigeot sprctl |= SPRITE_DEST_KEY; 512e3adcf8fSFrançois Tigeot else if (key->flags & I915_SET_COLORKEY_SOURCE) 513e3adcf8fSFrançois Tigeot sprctl |= SPRITE_SOURCE_KEY; 514e3adcf8fSFrançois Tigeot I915_WRITE(SPRCTL(intel_plane->pipe), sprctl); 515e3adcf8fSFrançois Tigeot 516e3adcf8fSFrançois Tigeot POSTING_READ(SPRKEYMSK(intel_plane->pipe)); 517e3adcf8fSFrançois Tigeot 518e3adcf8fSFrançois Tigeot return ret; 519e3adcf8fSFrançois Tigeot } 520e3adcf8fSFrançois Tigeot 521e3adcf8fSFrançois Tigeot static void 522e3adcf8fSFrançois Tigeot ivb_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key) 523e3adcf8fSFrançois Tigeot { 524e3adcf8fSFrançois Tigeot struct drm_device *dev = plane->dev; 525e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 526e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane; 527e3adcf8fSFrançois Tigeot u32 sprctl; 528e3adcf8fSFrançois Tigeot 529e3adcf8fSFrançois Tigeot intel_plane = to_intel_plane(plane); 530e3adcf8fSFrançois Tigeot 531e3adcf8fSFrançois Tigeot key->min_value = I915_READ(SPRKEYVAL(intel_plane->pipe)); 532e3adcf8fSFrançois Tigeot key->max_value = I915_READ(SPRKEYMAX(intel_plane->pipe)); 533e3adcf8fSFrançois Tigeot key->channel_mask = I915_READ(SPRKEYMSK(intel_plane->pipe)); 534e3adcf8fSFrançois Tigeot key->flags = 0; 535e3adcf8fSFrançois Tigeot 536e3adcf8fSFrançois Tigeot sprctl = I915_READ(SPRCTL(intel_plane->pipe)); 537e3adcf8fSFrançois Tigeot 538e3adcf8fSFrançois Tigeot if (sprctl & SPRITE_DEST_KEY) 539e3adcf8fSFrançois Tigeot key->flags = I915_SET_COLORKEY_DESTINATION; 540e3adcf8fSFrançois Tigeot else if (sprctl & SPRITE_SOURCE_KEY) 541e3adcf8fSFrançois Tigeot key->flags = I915_SET_COLORKEY_SOURCE; 542e3adcf8fSFrançois Tigeot else 543e3adcf8fSFrançois Tigeot key->flags = I915_SET_COLORKEY_NONE; 544e3adcf8fSFrançois Tigeot } 545e3adcf8fSFrançois Tigeot 546e3adcf8fSFrançois Tigeot static void 5479edbd4a0SFrançois Tigeot ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, 5489edbd4a0SFrançois Tigeot struct drm_framebuffer *fb, 549e3adcf8fSFrançois Tigeot struct drm_i915_gem_object *obj, int crtc_x, int crtc_y, 550e3adcf8fSFrançois Tigeot unsigned int crtc_w, unsigned int crtc_h, 551e3adcf8fSFrançois Tigeot uint32_t x, uint32_t y, 552e3adcf8fSFrançois Tigeot uint32_t src_w, uint32_t src_h) 553e3adcf8fSFrançois Tigeot { 554e3adcf8fSFrançois Tigeot struct drm_device *dev = plane->dev; 555e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 556e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(plane); 557*ba55f2f5SFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 5582c84b0b6SFrançois Tigeot int pipe = intel_plane->pipe; 5592c84b0b6SFrançois Tigeot unsigned long dvssurf_offset, linear_offset; 5602c84b0b6SFrançois Tigeot u32 dvscntr, dvsscale; 5612c84b0b6SFrançois Tigeot int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); 562*ba55f2f5SFrançois Tigeot u32 start_vbl_count; 563*ba55f2f5SFrançois Tigeot bool atomic_update; 564e3adcf8fSFrançois Tigeot 565e3adcf8fSFrançois Tigeot dvscntr = I915_READ(DVSCNTR(pipe)); 566e3adcf8fSFrançois Tigeot 567e3adcf8fSFrançois Tigeot /* Mask out pixel format bits in case we change it */ 568e3adcf8fSFrançois Tigeot dvscntr &= ~DVS_PIXFORMAT_MASK; 569e3adcf8fSFrançois Tigeot dvscntr &= ~DVS_RGB_ORDER_XBGR; 570e3adcf8fSFrançois Tigeot dvscntr &= ~DVS_YUV_BYTE_ORDER_MASK; 5712c84b0b6SFrançois Tigeot dvscntr &= ~DVS_TILED; 572e3adcf8fSFrançois Tigeot 573e3adcf8fSFrançois Tigeot switch (fb->pixel_format) { 574e3adcf8fSFrançois Tigeot case DRM_FORMAT_XBGR8888: 575e3adcf8fSFrançois Tigeot dvscntr |= DVS_FORMAT_RGBX888 | DVS_RGB_ORDER_XBGR; 576e3adcf8fSFrançois Tigeot break; 577e3adcf8fSFrançois Tigeot case DRM_FORMAT_XRGB8888: 578e3adcf8fSFrançois Tigeot dvscntr |= DVS_FORMAT_RGBX888; 579e3adcf8fSFrançois Tigeot break; 580e3adcf8fSFrançois Tigeot case DRM_FORMAT_YUYV: 581e3adcf8fSFrançois Tigeot dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YUYV; 582e3adcf8fSFrançois Tigeot break; 583e3adcf8fSFrançois Tigeot case DRM_FORMAT_YVYU: 584e3adcf8fSFrançois Tigeot dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YVYU; 585e3adcf8fSFrançois Tigeot break; 586e3adcf8fSFrançois Tigeot case DRM_FORMAT_UYVY: 587e3adcf8fSFrançois Tigeot dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_UYVY; 588e3adcf8fSFrançois Tigeot break; 589e3adcf8fSFrançois Tigeot case DRM_FORMAT_VYUY: 590e3adcf8fSFrançois Tigeot dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_VYUY; 591e3adcf8fSFrançois Tigeot break; 592e3adcf8fSFrançois Tigeot default: 5932c84b0b6SFrançois Tigeot BUG(); 594e3adcf8fSFrançois Tigeot } 595e3adcf8fSFrançois Tigeot 5969edbd4a0SFrançois Tigeot /* 5979edbd4a0SFrançois Tigeot * Enable gamma to match primary/cursor plane behaviour. 5989edbd4a0SFrançois Tigeot * FIXME should be user controllable via propertiesa. 5999edbd4a0SFrançois Tigeot */ 6009edbd4a0SFrançois Tigeot dvscntr |= DVS_GAMMA_ENABLE; 6019edbd4a0SFrançois Tigeot 602e3adcf8fSFrançois Tigeot if (obj->tiling_mode != I915_TILING_NONE) 603e3adcf8fSFrançois Tigeot dvscntr |= DVS_TILED; 604e3adcf8fSFrançois Tigeot 6052c84b0b6SFrançois Tigeot if (IS_GEN6(dev)) 6062c84b0b6SFrançois Tigeot dvscntr |= DVS_TRICKLE_FEED_DISABLE; /* must disable */ 607e3adcf8fSFrançois Tigeot dvscntr |= DVS_ENABLE; 608e3adcf8fSFrançois Tigeot 6099edbd4a0SFrançois Tigeot intel_update_sprite_watermarks(plane, crtc, src_w, pixel_size, true, 6109edbd4a0SFrançois Tigeot src_w != crtc_w || src_h != crtc_h); 6119edbd4a0SFrançois Tigeot 612e3adcf8fSFrançois Tigeot /* Sizes are 0 based */ 613e3adcf8fSFrançois Tigeot src_w--; 614e3adcf8fSFrançois Tigeot src_h--; 615e3adcf8fSFrançois Tigeot crtc_w--; 616e3adcf8fSFrançois Tigeot crtc_h--; 617e3adcf8fSFrançois Tigeot 6182c84b0b6SFrançois Tigeot dvsscale = 0; 6199edbd4a0SFrançois Tigeot if (crtc_w != src_w || crtc_h != src_h) 620e3adcf8fSFrançois Tigeot dvsscale = DVS_SCALE_ENABLE | (src_w << 16) | src_h; 621e3adcf8fSFrançois Tigeot 6222c84b0b6SFrançois Tigeot linear_offset = y * fb->pitches[0] + x * pixel_size; 6232c84b0b6SFrançois Tigeot dvssurf_offset = 624df188185SFrançois Tigeot intel_gen4_compute_page_offset(&x, &y, obj->tiling_mode, 6252c84b0b6SFrançois Tigeot pixel_size, fb->pitches[0]); 6262c84b0b6SFrançois Tigeot linear_offset -= dvssurf_offset; 6272c84b0b6SFrançois Tigeot 628*ba55f2f5SFrançois Tigeot atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count); 629*ba55f2f5SFrançois Tigeot 630*ba55f2f5SFrançois Tigeot intel_update_primary_plane(intel_crtc); 631*ba55f2f5SFrançois Tigeot 632*ba55f2f5SFrançois Tigeot I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]); 633*ba55f2f5SFrançois Tigeot I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x); 634*ba55f2f5SFrançois Tigeot 6352c84b0b6SFrançois Tigeot if (obj->tiling_mode != I915_TILING_NONE) 6362c84b0b6SFrançois Tigeot I915_WRITE(DVSTILEOFF(pipe), (y << 16) | x); 6372c84b0b6SFrançois Tigeot else 6382c84b0b6SFrançois Tigeot I915_WRITE(DVSLINOFF(pipe), linear_offset); 6392c84b0b6SFrançois Tigeot 640e3adcf8fSFrançois Tigeot I915_WRITE(DVSSIZE(pipe), (crtc_h << 16) | crtc_w); 641e3adcf8fSFrançois Tigeot I915_WRITE(DVSSCALE(pipe), dvsscale); 642e3adcf8fSFrançois Tigeot I915_WRITE(DVSCNTR(pipe), dvscntr); 6439edbd4a0SFrançois Tigeot I915_WRITE(DVSSURF(pipe), 6449edbd4a0SFrançois Tigeot i915_gem_obj_ggtt_offset(obj) + dvssurf_offset); 645*ba55f2f5SFrançois Tigeot 646*ba55f2f5SFrançois Tigeot intel_flush_primary_plane(dev_priv, intel_crtc->plane); 647*ba55f2f5SFrançois Tigeot 648*ba55f2f5SFrançois Tigeot if (atomic_update) 649*ba55f2f5SFrançois Tigeot intel_pipe_update_end(intel_crtc, start_vbl_count); 650e3adcf8fSFrançois Tigeot } 651e3adcf8fSFrançois Tigeot 652e3adcf8fSFrançois Tigeot static void 6539edbd4a0SFrançois Tigeot ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc) 654e3adcf8fSFrançois Tigeot { 655e3adcf8fSFrançois Tigeot struct drm_device *dev = plane->dev; 656e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 657e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(plane); 658*ba55f2f5SFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 659e3adcf8fSFrançois Tigeot int pipe = intel_plane->pipe; 660*ba55f2f5SFrançois Tigeot u32 start_vbl_count; 661*ba55f2f5SFrançois Tigeot bool atomic_update; 662*ba55f2f5SFrançois Tigeot 663*ba55f2f5SFrançois Tigeot atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count); 664*ba55f2f5SFrançois Tigeot 665*ba55f2f5SFrançois Tigeot intel_update_primary_plane(intel_crtc); 666e3adcf8fSFrançois Tigeot 667e3adcf8fSFrançois Tigeot I915_WRITE(DVSCNTR(pipe), I915_READ(DVSCNTR(pipe)) & ~DVS_ENABLE); 668e3adcf8fSFrançois Tigeot /* Disable the scaler */ 669e3adcf8fSFrançois Tigeot I915_WRITE(DVSSCALE(pipe), 0); 670e3adcf8fSFrançois Tigeot /* Flush double buffered register updates */ 6719edbd4a0SFrançois Tigeot I915_WRITE(DVSSURF(pipe), 0); 672*ba55f2f5SFrançois Tigeot 673*ba55f2f5SFrançois Tigeot intel_flush_primary_plane(dev_priv, intel_crtc->plane); 674*ba55f2f5SFrançois Tigeot 675*ba55f2f5SFrançois Tigeot if (atomic_update) 676*ba55f2f5SFrançois Tigeot intel_pipe_update_end(intel_crtc, start_vbl_count); 6779edbd4a0SFrançois Tigeot 6789edbd4a0SFrançois Tigeot /* 6799edbd4a0SFrançois Tigeot * Avoid underruns when disabling the sprite. 6809edbd4a0SFrançois Tigeot * FIXME remove once watermark updates are done properly. 6819edbd4a0SFrançois Tigeot */ 6829edbd4a0SFrançois Tigeot intel_wait_for_vblank(dev, pipe); 6839edbd4a0SFrançois Tigeot 6849edbd4a0SFrançois Tigeot intel_update_sprite_watermarks(plane, crtc, 0, 0, false, false); 685e3adcf8fSFrançois Tigeot } 686e3adcf8fSFrançois Tigeot 687e3adcf8fSFrançois Tigeot static void 688*ba55f2f5SFrançois Tigeot intel_post_enable_primary(struct drm_crtc *crtc) 689e3adcf8fSFrançois Tigeot { 690e3adcf8fSFrançois Tigeot struct drm_device *dev = crtc->dev; 691e3adcf8fSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 692e3adcf8fSFrançois Tigeot 693*ba55f2f5SFrançois Tigeot /* 694*ba55f2f5SFrançois Tigeot * BDW signals flip done immediately if the plane 695*ba55f2f5SFrançois Tigeot * is disabled, even if the plane enable is already 696*ba55f2f5SFrançois Tigeot * armed to occur at the next vblank :( 697*ba55f2f5SFrançois Tigeot */ 698*ba55f2f5SFrançois Tigeot if (IS_BROADWELL(dev)) 699*ba55f2f5SFrançois Tigeot intel_wait_for_vblank(dev, intel_crtc->pipe); 7009edbd4a0SFrançois Tigeot 7019edbd4a0SFrançois Tigeot /* 7029edbd4a0SFrançois Tigeot * FIXME IPS should be fine as long as one plane is 7039edbd4a0SFrançois Tigeot * enabled, but in practice it seems to have problems 7049edbd4a0SFrançois Tigeot * when going from primary only to sprite only and vice 7059edbd4a0SFrançois Tigeot * versa. 7069edbd4a0SFrançois Tigeot */ 7079edbd4a0SFrançois Tigeot hsw_enable_ips(intel_crtc); 7089edbd4a0SFrançois Tigeot 7099edbd4a0SFrançois Tigeot mutex_lock(&dev->struct_mutex); 7109edbd4a0SFrançois Tigeot intel_update_fbc(dev); 7119edbd4a0SFrançois Tigeot mutex_unlock(&dev->struct_mutex); 712e3adcf8fSFrançois Tigeot } 713e3adcf8fSFrançois Tigeot 714e3adcf8fSFrançois Tigeot static void 715*ba55f2f5SFrançois Tigeot intel_pre_disable_primary(struct drm_crtc *crtc) 716e3adcf8fSFrançois Tigeot { 717e3adcf8fSFrançois Tigeot struct drm_device *dev = crtc->dev; 718e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 719e3adcf8fSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 7202c84b0b6SFrançois Tigeot 7219edbd4a0SFrançois Tigeot mutex_lock(&dev->struct_mutex); 7229edbd4a0SFrançois Tigeot if (dev_priv->fbc.plane == intel_crtc->plane) 7239edbd4a0SFrançois Tigeot intel_disable_fbc(dev); 7249edbd4a0SFrançois Tigeot mutex_unlock(&dev->struct_mutex); 7259edbd4a0SFrançois Tigeot 7269edbd4a0SFrançois Tigeot /* 7279edbd4a0SFrançois Tigeot * FIXME IPS should be fine as long as one plane is 7289edbd4a0SFrançois Tigeot * enabled, but in practice it seems to have problems 7299edbd4a0SFrançois Tigeot * when going from primary only to sprite only and vice 7309edbd4a0SFrançois Tigeot * versa. 7319edbd4a0SFrançois Tigeot */ 7329edbd4a0SFrançois Tigeot hsw_disable_ips(intel_crtc); 733e3adcf8fSFrançois Tigeot } 734e3adcf8fSFrançois Tigeot 735e3adcf8fSFrançois Tigeot static int 7362c84b0b6SFrançois Tigeot ilk_update_colorkey(struct drm_plane *plane, 737e3adcf8fSFrançois Tigeot struct drm_intel_sprite_colorkey *key) 738e3adcf8fSFrançois Tigeot { 739e3adcf8fSFrançois Tigeot struct drm_device *dev = plane->dev; 740e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 741e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane; 742e3adcf8fSFrançois Tigeot u32 dvscntr; 743e3adcf8fSFrançois Tigeot int ret = 0; 744e3adcf8fSFrançois Tigeot 745e3adcf8fSFrançois Tigeot intel_plane = to_intel_plane(plane); 746e3adcf8fSFrançois Tigeot 747e3adcf8fSFrançois Tigeot I915_WRITE(DVSKEYVAL(intel_plane->pipe), key->min_value); 748e3adcf8fSFrançois Tigeot I915_WRITE(DVSKEYMAX(intel_plane->pipe), key->max_value); 749e3adcf8fSFrançois Tigeot I915_WRITE(DVSKEYMSK(intel_plane->pipe), key->channel_mask); 750e3adcf8fSFrançois Tigeot 751e3adcf8fSFrançois Tigeot dvscntr = I915_READ(DVSCNTR(intel_plane->pipe)); 752e3adcf8fSFrançois Tigeot dvscntr &= ~(DVS_SOURCE_KEY | DVS_DEST_KEY); 753e3adcf8fSFrançois Tigeot if (key->flags & I915_SET_COLORKEY_DESTINATION) 754e3adcf8fSFrançois Tigeot dvscntr |= DVS_DEST_KEY; 755e3adcf8fSFrançois Tigeot else if (key->flags & I915_SET_COLORKEY_SOURCE) 756e3adcf8fSFrançois Tigeot dvscntr |= DVS_SOURCE_KEY; 757e3adcf8fSFrançois Tigeot I915_WRITE(DVSCNTR(intel_plane->pipe), dvscntr); 758e3adcf8fSFrançois Tigeot 759e3adcf8fSFrançois Tigeot POSTING_READ(DVSKEYMSK(intel_plane->pipe)); 760e3adcf8fSFrançois Tigeot 761e3adcf8fSFrançois Tigeot return ret; 762e3adcf8fSFrançois Tigeot } 763e3adcf8fSFrançois Tigeot 764e3adcf8fSFrançois Tigeot static void 7652c84b0b6SFrançois Tigeot ilk_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key) 766e3adcf8fSFrançois Tigeot { 767e3adcf8fSFrançois Tigeot struct drm_device *dev = plane->dev; 768e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 769e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane; 770e3adcf8fSFrançois Tigeot u32 dvscntr; 771e3adcf8fSFrançois Tigeot 772e3adcf8fSFrançois Tigeot intel_plane = to_intel_plane(plane); 773e3adcf8fSFrançois Tigeot 774e3adcf8fSFrançois Tigeot key->min_value = I915_READ(DVSKEYVAL(intel_plane->pipe)); 775e3adcf8fSFrançois Tigeot key->max_value = I915_READ(DVSKEYMAX(intel_plane->pipe)); 776e3adcf8fSFrançois Tigeot key->channel_mask = I915_READ(DVSKEYMSK(intel_plane->pipe)); 777e3adcf8fSFrançois Tigeot key->flags = 0; 778e3adcf8fSFrançois Tigeot 779e3adcf8fSFrançois Tigeot dvscntr = I915_READ(DVSCNTR(intel_plane->pipe)); 780e3adcf8fSFrançois Tigeot 781e3adcf8fSFrançois Tigeot if (dvscntr & DVS_DEST_KEY) 782e3adcf8fSFrançois Tigeot key->flags = I915_SET_COLORKEY_DESTINATION; 783e3adcf8fSFrançois Tigeot else if (dvscntr & DVS_SOURCE_KEY) 784e3adcf8fSFrançois Tigeot key->flags = I915_SET_COLORKEY_SOURCE; 785e3adcf8fSFrançois Tigeot else 786e3adcf8fSFrançois Tigeot key->flags = I915_SET_COLORKEY_NONE; 787e3adcf8fSFrançois Tigeot } 788e3adcf8fSFrançois Tigeot 7895d0b1887SFrançois Tigeot static bool 7905d0b1887SFrançois Tigeot format_is_yuv(uint32_t format) 7915d0b1887SFrançois Tigeot { 7925d0b1887SFrançois Tigeot switch (format) { 7935d0b1887SFrançois Tigeot case DRM_FORMAT_YUYV: 7945d0b1887SFrançois Tigeot case DRM_FORMAT_UYVY: 7955d0b1887SFrançois Tigeot case DRM_FORMAT_VYUY: 7965d0b1887SFrançois Tigeot case DRM_FORMAT_YVYU: 7975d0b1887SFrançois Tigeot return true; 7985d0b1887SFrançois Tigeot default: 7995d0b1887SFrançois Tigeot return false; 8005d0b1887SFrançois Tigeot } 8015d0b1887SFrançois Tigeot } 8025d0b1887SFrançois Tigeot 8039edbd4a0SFrançois Tigeot static bool colorkey_enabled(struct intel_plane *intel_plane) 8049edbd4a0SFrançois Tigeot { 8059edbd4a0SFrançois Tigeot struct drm_intel_sprite_colorkey key; 8069edbd4a0SFrançois Tigeot 8079edbd4a0SFrançois Tigeot intel_plane->get_colorkey(&intel_plane->base, &key); 8089edbd4a0SFrançois Tigeot 8099edbd4a0SFrançois Tigeot return key.flags != I915_SET_COLORKEY_NONE; 8109edbd4a0SFrançois Tigeot } 8119edbd4a0SFrançois Tigeot 812e3adcf8fSFrançois Tigeot static int 813e3adcf8fSFrançois Tigeot intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, 814e3adcf8fSFrançois Tigeot struct drm_framebuffer *fb, int crtc_x, int crtc_y, 815e3adcf8fSFrançois Tigeot unsigned int crtc_w, unsigned int crtc_h, 816e3adcf8fSFrançois Tigeot uint32_t src_x, uint32_t src_y, 817e3adcf8fSFrançois Tigeot uint32_t src_w, uint32_t src_h) 818e3adcf8fSFrançois Tigeot { 819e3adcf8fSFrançois Tigeot struct drm_device *dev = plane->dev; 820e3adcf8fSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 821e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(plane); 8229edbd4a0SFrançois Tigeot struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); 8239edbd4a0SFrançois Tigeot struct drm_i915_gem_object *obj = intel_fb->obj; 8249edbd4a0SFrançois Tigeot struct drm_i915_gem_object *old_obj = intel_plane->obj; 8259edbd4a0SFrançois Tigeot int ret; 826*ba55f2f5SFrançois Tigeot bool primary_enabled; 8275d0b1887SFrançois Tigeot bool visible; 8285d0b1887SFrançois Tigeot int hscale, vscale; 8295d0b1887SFrançois Tigeot int max_scale, min_scale; 8305d0b1887SFrançois Tigeot int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); 8315d0b1887SFrançois Tigeot struct drm_rect src = { 8325d0b1887SFrançois Tigeot /* sample coordinates in 16.16 fixed point */ 8335d0b1887SFrançois Tigeot .x1 = src_x, 8345d0b1887SFrançois Tigeot .x2 = src_x + src_w, 8355d0b1887SFrançois Tigeot .y1 = src_y, 8365d0b1887SFrançois Tigeot .y2 = src_y + src_h, 8375d0b1887SFrançois Tigeot }; 8385d0b1887SFrançois Tigeot struct drm_rect dst = { 8395d0b1887SFrançois Tigeot /* integer pixels */ 8405d0b1887SFrançois Tigeot .x1 = crtc_x, 8415d0b1887SFrançois Tigeot .x2 = crtc_x + crtc_w, 8425d0b1887SFrançois Tigeot .y1 = crtc_y, 8435d0b1887SFrançois Tigeot .y2 = crtc_y + crtc_h, 8445d0b1887SFrançois Tigeot }; 8455d0b1887SFrançois Tigeot const struct drm_rect clip = { 8469edbd4a0SFrançois Tigeot .x2 = intel_crtc->active ? intel_crtc->config.pipe_src_w : 0, 8479edbd4a0SFrançois Tigeot .y2 = intel_crtc->active ? intel_crtc->config.pipe_src_h : 0, 8485d0b1887SFrançois Tigeot }; 8499edbd4a0SFrançois Tigeot const struct { 8509edbd4a0SFrançois Tigeot int crtc_x, crtc_y; 8519edbd4a0SFrançois Tigeot unsigned int crtc_w, crtc_h; 8529edbd4a0SFrançois Tigeot uint32_t src_x, src_y, src_w, src_h; 8539edbd4a0SFrançois Tigeot } orig = { 8549edbd4a0SFrançois Tigeot .crtc_x = crtc_x, 8559edbd4a0SFrançois Tigeot .crtc_y = crtc_y, 8569edbd4a0SFrançois Tigeot .crtc_w = crtc_w, 8579edbd4a0SFrançois Tigeot .crtc_h = crtc_h, 8589edbd4a0SFrançois Tigeot .src_x = src_x, 8599edbd4a0SFrançois Tigeot .src_y = src_y, 8609edbd4a0SFrançois Tigeot .src_w = src_w, 8619edbd4a0SFrançois Tigeot .src_h = src_h, 8629edbd4a0SFrançois Tigeot }; 863e3adcf8fSFrançois Tigeot 864e3adcf8fSFrançois Tigeot /* Don't modify another pipe's plane */ 8655d0b1887SFrançois Tigeot if (intel_plane->pipe != intel_crtc->pipe) { 8665d0b1887SFrançois Tigeot DRM_DEBUG_KMS("Wrong plane <-> crtc mapping\n"); 867e3adcf8fSFrançois Tigeot return -EINVAL; 8685d0b1887SFrançois Tigeot } 8695d0b1887SFrançois Tigeot 8705d0b1887SFrançois Tigeot /* FIXME check all gen limits */ 8715d0b1887SFrançois Tigeot if (fb->width < 3 || fb->height < 3 || fb->pitches[0] > 16384) { 8725d0b1887SFrançois Tigeot DRM_DEBUG_KMS("Unsuitable framebuffer for plane\n"); 8735d0b1887SFrançois Tigeot return -EINVAL; 8745d0b1887SFrançois Tigeot } 875e3adcf8fSFrançois Tigeot 8762c84b0b6SFrançois Tigeot /* Sprite planes can be linear or x-tiled surfaces */ 8772c84b0b6SFrançois Tigeot switch (obj->tiling_mode) { 8782c84b0b6SFrançois Tigeot case I915_TILING_NONE: 8792c84b0b6SFrançois Tigeot case I915_TILING_X: 8802c84b0b6SFrançois Tigeot break; 8812c84b0b6SFrançois Tigeot default: 8825d0b1887SFrançois Tigeot DRM_DEBUG_KMS("Unsupported tiling mode\n"); 8832c84b0b6SFrançois Tigeot return -EINVAL; 8842c84b0b6SFrançois Tigeot } 8852c84b0b6SFrançois Tigeot 886e3adcf8fSFrançois Tigeot /* 8875d0b1887SFrançois Tigeot * FIXME the following code does a bunch of fuzzy adjustments to the 8885d0b1887SFrançois Tigeot * coordinates and sizes. We probably need some way to decide whether 8895d0b1887SFrançois Tigeot * more strict checking should be done instead. 890e3adcf8fSFrançois Tigeot */ 8915d0b1887SFrançois Tigeot max_scale = intel_plane->max_downscale << 16; 8925d0b1887SFrançois Tigeot min_scale = intel_plane->can_scale ? 1 : (1 << 16); 893e3adcf8fSFrançois Tigeot 8945d0b1887SFrançois Tigeot hscale = drm_rect_calc_hscale_relaxed(&src, &dst, min_scale, max_scale); 8955d0b1887SFrançois Tigeot BUG_ON(hscale < 0); 896e3adcf8fSFrançois Tigeot 8975d0b1887SFrançois Tigeot vscale = drm_rect_calc_vscale_relaxed(&src, &dst, min_scale, max_scale); 8985d0b1887SFrançois Tigeot BUG_ON(vscale < 0); 8995d0b1887SFrançois Tigeot 9005d0b1887SFrançois Tigeot visible = drm_rect_clip_scaled(&src, &dst, &clip, hscale, vscale); 9015d0b1887SFrançois Tigeot 9025d0b1887SFrançois Tigeot crtc_x = dst.x1; 9035d0b1887SFrançois Tigeot crtc_y = dst.y1; 9045d0b1887SFrançois Tigeot crtc_w = drm_rect_width(&dst); 9055d0b1887SFrançois Tigeot crtc_h = drm_rect_height(&dst); 9065d0b1887SFrançois Tigeot 9075d0b1887SFrançois Tigeot if (visible) { 9085d0b1887SFrançois Tigeot /* check again in case clipping clamped the results */ 9095d0b1887SFrançois Tigeot hscale = drm_rect_calc_hscale(&src, &dst, min_scale, max_scale); 9105d0b1887SFrançois Tigeot if (hscale < 0) { 9115d0b1887SFrançois Tigeot DRM_DEBUG_KMS("Horizontal scaling factor out of limits\n"); 9125d0b1887SFrançois Tigeot drm_rect_debug_print(&src, true); 9135d0b1887SFrançois Tigeot drm_rect_debug_print(&dst, false); 9145d0b1887SFrançois Tigeot 9155d0b1887SFrançois Tigeot return hscale; 9165d0b1887SFrançois Tigeot } 9175d0b1887SFrançois Tigeot 9185d0b1887SFrançois Tigeot vscale = drm_rect_calc_vscale(&src, &dst, min_scale, max_scale); 9195d0b1887SFrançois Tigeot if (vscale < 0) { 9205d0b1887SFrançois Tigeot DRM_DEBUG_KMS("Vertical scaling factor out of limits\n"); 9215d0b1887SFrançois Tigeot drm_rect_debug_print(&src, true); 9225d0b1887SFrançois Tigeot drm_rect_debug_print(&dst, false); 9235d0b1887SFrançois Tigeot 9245d0b1887SFrançois Tigeot return vscale; 9255d0b1887SFrançois Tigeot } 9265d0b1887SFrançois Tigeot 9275d0b1887SFrançois Tigeot /* Make the source viewport size an exact multiple of the scaling factors. */ 9285d0b1887SFrançois Tigeot drm_rect_adjust_size(&src, 9295d0b1887SFrançois Tigeot drm_rect_width(&dst) * hscale - drm_rect_width(&src), 9305d0b1887SFrançois Tigeot drm_rect_height(&dst) * vscale - drm_rect_height(&src)); 9315d0b1887SFrançois Tigeot 9325d0b1887SFrançois Tigeot /* sanity check to make sure the src viewport wasn't enlarged */ 9335d0b1887SFrançois Tigeot WARN_ON(src.x1 < (int) src_x || 9345d0b1887SFrançois Tigeot src.y1 < (int) src_y || 9355d0b1887SFrançois Tigeot src.x2 > (int) (src_x + src_w) || 9365d0b1887SFrançois Tigeot src.y2 > (int) (src_y + src_h)); 937e3adcf8fSFrançois Tigeot 938e3adcf8fSFrançois Tigeot /* 9395d0b1887SFrançois Tigeot * Hardware doesn't handle subpixel coordinates. 9405d0b1887SFrançois Tigeot * Adjust to (macro)pixel boundary, but be careful not to 9415d0b1887SFrançois Tigeot * increase the source viewport size, because that could 9425d0b1887SFrançois Tigeot * push the downscaling factor out of bounds. 9432c84b0b6SFrançois Tigeot */ 9445d0b1887SFrançois Tigeot src_x = src.x1 >> 16; 9455d0b1887SFrançois Tigeot src_w = drm_rect_width(&src) >> 16; 9465d0b1887SFrançois Tigeot src_y = src.y1 >> 16; 9475d0b1887SFrançois Tigeot src_h = drm_rect_height(&src) >> 16; 9485d0b1887SFrançois Tigeot 9495d0b1887SFrançois Tigeot if (format_is_yuv(fb->pixel_format)) { 9505d0b1887SFrançois Tigeot src_x &= ~1; 9515d0b1887SFrançois Tigeot src_w &= ~1; 9522c84b0b6SFrançois Tigeot 9532c84b0b6SFrançois Tigeot /* 9545d0b1887SFrançois Tigeot * Must keep src and dst the 9555d0b1887SFrançois Tigeot * same if we can't scale. 956e3adcf8fSFrançois Tigeot */ 9575d0b1887SFrançois Tigeot if (!intel_plane->can_scale) 9585d0b1887SFrançois Tigeot crtc_w &= ~1; 9595d0b1887SFrançois Tigeot 9605d0b1887SFrançois Tigeot if (crtc_w == 0) 9615d0b1887SFrançois Tigeot visible = false; 9625d0b1887SFrançois Tigeot } 9635d0b1887SFrançois Tigeot } 9645d0b1887SFrançois Tigeot 9655d0b1887SFrançois Tigeot /* Check size restrictions when scaling */ 9665d0b1887SFrançois Tigeot if (visible && (src_w != crtc_w || src_h != crtc_h)) { 9675d0b1887SFrançois Tigeot unsigned int width_bytes; 9685d0b1887SFrançois Tigeot 9695d0b1887SFrançois Tigeot WARN_ON(!intel_plane->can_scale); 9705d0b1887SFrançois Tigeot 9715d0b1887SFrançois Tigeot /* FIXME interlacing min height is 6 */ 9725d0b1887SFrançois Tigeot 9735d0b1887SFrançois Tigeot if (crtc_w < 3 || crtc_h < 3) 9745d0b1887SFrançois Tigeot visible = false; 9755d0b1887SFrançois Tigeot 9765d0b1887SFrançois Tigeot if (src_w < 3 || src_h < 3) 9775d0b1887SFrançois Tigeot visible = false; 9785d0b1887SFrançois Tigeot 9795d0b1887SFrançois Tigeot width_bytes = ((src_x * pixel_size) & 63) + src_w * pixel_size; 9805d0b1887SFrançois Tigeot 9815d0b1887SFrançois Tigeot if (src_w > 2048 || src_h > 2048 || 9825d0b1887SFrançois Tigeot width_bytes > 4096 || fb->pitches[0] > 4096) { 9835d0b1887SFrançois Tigeot DRM_DEBUG_KMS("Source dimensions exceed hardware limits\n"); 984e3adcf8fSFrançois Tigeot return -EINVAL; 9855d0b1887SFrançois Tigeot } 9865d0b1887SFrançois Tigeot } 9875d0b1887SFrançois Tigeot 9885d0b1887SFrançois Tigeot dst.x1 = crtc_x; 9895d0b1887SFrançois Tigeot dst.x2 = crtc_x + crtc_w; 9905d0b1887SFrançois Tigeot dst.y1 = crtc_y; 9915d0b1887SFrançois Tigeot dst.y2 = crtc_y + crtc_h; 992e3adcf8fSFrançois Tigeot 993e3adcf8fSFrançois Tigeot /* 994e3adcf8fSFrançois Tigeot * If the sprite is completely covering the primary plane, 995e3adcf8fSFrançois Tigeot * we can disable the primary and save power. 996e3adcf8fSFrançois Tigeot */ 997*ba55f2f5SFrançois Tigeot primary_enabled = !drm_rect_equals(&dst, &clip) || colorkey_enabled(intel_plane); 998*ba55f2f5SFrançois Tigeot WARN_ON(!primary_enabled && !visible && intel_crtc->active); 999e3adcf8fSFrançois Tigeot 1000a2fdbec6SFrançois Tigeot mutex_lock(&dev->struct_mutex); 1001e3adcf8fSFrançois Tigeot 10028e26cdf6SFrançois Tigeot /* Note that this will apply the VT-d workaround for scanouts, 10038e26cdf6SFrançois Tigeot * which is more restrictive than required for sprites. (The 10048e26cdf6SFrançois Tigeot * primary plane requires 256KiB alignment with 64 PTE padding, 10058e26cdf6SFrançois Tigeot * the sprite planes only require 128KiB alignment and 32 PTE padding. 10068e26cdf6SFrançois Tigeot */ 1007e3adcf8fSFrançois Tigeot ret = intel_pin_and_fence_fb_obj(dev, obj, NULL); 1008e3adcf8fSFrançois Tigeot 10099edbd4a0SFrançois Tigeot mutex_unlock(&dev->struct_mutex); 10109edbd4a0SFrançois Tigeot 10119edbd4a0SFrançois Tigeot if (ret) 10129edbd4a0SFrançois Tigeot return ret; 10139edbd4a0SFrançois Tigeot 10149edbd4a0SFrançois Tigeot intel_plane->crtc_x = orig.crtc_x; 10159edbd4a0SFrançois Tigeot intel_plane->crtc_y = orig.crtc_y; 10169edbd4a0SFrançois Tigeot intel_plane->crtc_w = orig.crtc_w; 10179edbd4a0SFrançois Tigeot intel_plane->crtc_h = orig.crtc_h; 10189edbd4a0SFrançois Tigeot intel_plane->src_x = orig.src_x; 10199edbd4a0SFrançois Tigeot intel_plane->src_y = orig.src_y; 10209edbd4a0SFrançois Tigeot intel_plane->src_w = orig.src_w; 10219edbd4a0SFrançois Tigeot intel_plane->src_h = orig.src_h; 1022e3adcf8fSFrançois Tigeot intel_plane->obj = obj; 1023e3adcf8fSFrançois Tigeot 10249edbd4a0SFrançois Tigeot if (intel_crtc->active) { 1025*ba55f2f5SFrançois Tigeot bool primary_was_enabled = intel_crtc->primary_enabled; 1026*ba55f2f5SFrançois Tigeot 1027*ba55f2f5SFrançois Tigeot intel_crtc->primary_enabled = primary_enabled; 1028*ba55f2f5SFrançois Tigeot 1029*ba55f2f5SFrançois Tigeot if (primary_was_enabled != primary_enabled) 1030*ba55f2f5SFrançois Tigeot intel_crtc_wait_for_pending_flips(crtc); 1031*ba55f2f5SFrançois Tigeot 1032*ba55f2f5SFrançois Tigeot if (primary_was_enabled && !primary_enabled) 1033*ba55f2f5SFrançois Tigeot intel_pre_disable_primary(crtc); 1034e3adcf8fSFrançois Tigeot 10355d0b1887SFrançois Tigeot if (visible) 10369edbd4a0SFrançois Tigeot intel_plane->update_plane(plane, crtc, fb, obj, 10375d0b1887SFrançois Tigeot crtc_x, crtc_y, crtc_w, crtc_h, 10385d0b1887SFrançois Tigeot src_x, src_y, src_w, src_h); 10395d0b1887SFrançois Tigeot else 10409edbd4a0SFrançois Tigeot intel_plane->disable_plane(plane, crtc); 1041e3adcf8fSFrançois Tigeot 1042*ba55f2f5SFrançois Tigeot if (!primary_was_enabled && primary_enabled) 1043*ba55f2f5SFrançois Tigeot intel_post_enable_primary(crtc); 10449edbd4a0SFrançois Tigeot } 1045e3adcf8fSFrançois Tigeot 1046e3adcf8fSFrançois Tigeot /* Unpin old obj after new one is active to avoid ugliness */ 1047e3adcf8fSFrançois Tigeot if (old_obj) { 1048e3adcf8fSFrançois Tigeot /* 1049e3adcf8fSFrançois Tigeot * It's fairly common to simply update the position of 1050e3adcf8fSFrançois Tigeot * an existing object. In that case, we don't need to 1051e3adcf8fSFrançois Tigeot * wait for vblank to avoid ugliness, we only need to 1052e3adcf8fSFrançois Tigeot * do the pin & ref bookkeeping. 1053e3adcf8fSFrançois Tigeot */ 10549edbd4a0SFrançois Tigeot if (old_obj != obj && intel_crtc->active) 10559edbd4a0SFrançois Tigeot intel_wait_for_vblank(dev, intel_crtc->pipe); 10569edbd4a0SFrançois Tigeot 1057a2fdbec6SFrançois Tigeot mutex_lock(&dev->struct_mutex); 1058e3adcf8fSFrançois Tigeot intel_unpin_fb_obj(old_obj); 10599edbd4a0SFrançois Tigeot mutex_unlock(&dev->struct_mutex); 1060e3adcf8fSFrançois Tigeot } 1061e3adcf8fSFrançois Tigeot 10629edbd4a0SFrançois Tigeot return 0; 1063e3adcf8fSFrançois Tigeot } 1064e3adcf8fSFrançois Tigeot 1065e3adcf8fSFrançois Tigeot static int 1066e3adcf8fSFrançois Tigeot intel_disable_plane(struct drm_plane *plane) 1067e3adcf8fSFrançois Tigeot { 1068e3adcf8fSFrançois Tigeot struct drm_device *dev = plane->dev; 1069e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(plane); 10709edbd4a0SFrançois Tigeot struct intel_crtc *intel_crtc; 1071e3adcf8fSFrançois Tigeot 10729edbd4a0SFrançois Tigeot if (!plane->fb) 10739edbd4a0SFrançois Tigeot return 0; 10749edbd4a0SFrançois Tigeot 10759edbd4a0SFrançois Tigeot if (WARN_ON(!plane->crtc)) 10769edbd4a0SFrançois Tigeot return -EINVAL; 10779edbd4a0SFrançois Tigeot 10789edbd4a0SFrançois Tigeot intel_crtc = to_intel_crtc(plane->crtc); 10799edbd4a0SFrançois Tigeot 10809edbd4a0SFrançois Tigeot if (intel_crtc->active) { 1081*ba55f2f5SFrançois Tigeot bool primary_was_enabled = intel_crtc->primary_enabled; 1082*ba55f2f5SFrançois Tigeot 1083*ba55f2f5SFrançois Tigeot intel_crtc->primary_enabled = true; 1084*ba55f2f5SFrançois Tigeot 10859edbd4a0SFrançois Tigeot intel_plane->disable_plane(plane, plane->crtc); 1086*ba55f2f5SFrançois Tigeot 1087*ba55f2f5SFrançois Tigeot if (!primary_was_enabled && intel_crtc->primary_enabled) 1088*ba55f2f5SFrançois Tigeot intel_post_enable_primary(plane->crtc); 10899edbd4a0SFrançois Tigeot } 1090e3adcf8fSFrançois Tigeot 10919edbd4a0SFrançois Tigeot if (intel_plane->obj) { 10929edbd4a0SFrançois Tigeot if (intel_crtc->active) 10938e26cdf6SFrançois Tigeot intel_wait_for_vblank(dev, intel_plane->pipe); 10948e26cdf6SFrançois Tigeot 1095a2fdbec6SFrançois Tigeot mutex_lock(&dev->struct_mutex); 1096e3adcf8fSFrançois Tigeot intel_unpin_fb_obj(intel_plane->obj); 1097a2fdbec6SFrançois Tigeot mutex_unlock(&dev->struct_mutex); 1098e3adcf8fSFrançois Tigeot 10999edbd4a0SFrançois Tigeot intel_plane->obj = NULL; 11009edbd4a0SFrançois Tigeot } 11019edbd4a0SFrançois Tigeot 11029edbd4a0SFrançois Tigeot return 0; 1103e3adcf8fSFrançois Tigeot } 1104e3adcf8fSFrançois Tigeot 1105e3adcf8fSFrançois Tigeot static void intel_destroy_plane(struct drm_plane *plane) 1106e3adcf8fSFrançois Tigeot { 1107e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(plane); 1108e3adcf8fSFrançois Tigeot intel_disable_plane(plane); 1109e3adcf8fSFrançois Tigeot drm_plane_cleanup(plane); 1110158486a6SFrançois Tigeot kfree(intel_plane); 1111e3adcf8fSFrançois Tigeot } 1112e3adcf8fSFrançois Tigeot 1113e3adcf8fSFrançois Tigeot int intel_sprite_set_colorkey(struct drm_device *dev, void *data, 1114e3adcf8fSFrançois Tigeot struct drm_file *file_priv) 1115e3adcf8fSFrançois Tigeot { 1116e3adcf8fSFrançois Tigeot struct drm_intel_sprite_colorkey *set = data; 1117e3adcf8fSFrançois Tigeot struct drm_mode_object *obj; 1118e3adcf8fSFrançois Tigeot struct drm_plane *plane; 1119e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane; 1120e3adcf8fSFrançois Tigeot int ret = 0; 1121e3adcf8fSFrançois Tigeot 11222c84b0b6SFrançois Tigeot if (!drm_core_check_feature(dev, DRIVER_MODESET)) 11232c84b0b6SFrançois Tigeot return -ENODEV; 1124e3adcf8fSFrançois Tigeot 1125e3adcf8fSFrançois Tigeot /* Make sure we don't try to enable both src & dest simultaneously */ 1126e3adcf8fSFrançois Tigeot if ((set->flags & (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) == (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) 1127e3adcf8fSFrançois Tigeot return -EINVAL; 1128e3adcf8fSFrançois Tigeot 1129a2fdbec6SFrançois Tigeot drm_modeset_lock_all(dev); 1130e3adcf8fSFrançois Tigeot 1131e3adcf8fSFrançois Tigeot obj = drm_mode_object_find(dev, set->plane_id, DRM_MODE_OBJECT_PLANE); 1132e3adcf8fSFrançois Tigeot if (!obj) { 11339edbd4a0SFrançois Tigeot ret = -ENOENT; 1134e3adcf8fSFrançois Tigeot goto out_unlock; 1135e3adcf8fSFrançois Tigeot } 1136e3adcf8fSFrançois Tigeot 1137e3adcf8fSFrançois Tigeot plane = obj_to_plane(obj); 1138e3adcf8fSFrançois Tigeot intel_plane = to_intel_plane(plane); 1139e3adcf8fSFrançois Tigeot ret = intel_plane->update_colorkey(plane, set); 1140e3adcf8fSFrançois Tigeot 1141e3adcf8fSFrançois Tigeot out_unlock: 1142a2fdbec6SFrançois Tigeot drm_modeset_unlock_all(dev); 1143e3adcf8fSFrançois Tigeot return ret; 1144e3adcf8fSFrançois Tigeot } 1145e3adcf8fSFrançois Tigeot 1146e3adcf8fSFrançois Tigeot int intel_sprite_get_colorkey(struct drm_device *dev, void *data, 1147e3adcf8fSFrançois Tigeot struct drm_file *file_priv) 1148e3adcf8fSFrançois Tigeot { 1149e3adcf8fSFrançois Tigeot struct drm_intel_sprite_colorkey *get = data; 1150e3adcf8fSFrançois Tigeot struct drm_mode_object *obj; 1151e3adcf8fSFrançois Tigeot struct drm_plane *plane; 1152e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane; 1153e3adcf8fSFrançois Tigeot int ret = 0; 1154e3adcf8fSFrançois Tigeot 11552c84b0b6SFrançois Tigeot if (!drm_core_check_feature(dev, DRIVER_MODESET)) 11562c84b0b6SFrançois Tigeot return -ENODEV; 1157e3adcf8fSFrançois Tigeot 1158a2fdbec6SFrançois Tigeot drm_modeset_lock_all(dev); 1159e3adcf8fSFrançois Tigeot 1160e3adcf8fSFrançois Tigeot obj = drm_mode_object_find(dev, get->plane_id, DRM_MODE_OBJECT_PLANE); 1161e3adcf8fSFrançois Tigeot if (!obj) { 11629edbd4a0SFrançois Tigeot ret = -ENOENT; 1163e3adcf8fSFrançois Tigeot goto out_unlock; 1164e3adcf8fSFrançois Tigeot } 1165e3adcf8fSFrançois Tigeot 1166e3adcf8fSFrançois Tigeot plane = obj_to_plane(obj); 1167e3adcf8fSFrançois Tigeot intel_plane = to_intel_plane(plane); 1168e3adcf8fSFrançois Tigeot intel_plane->get_colorkey(plane, get); 1169e3adcf8fSFrançois Tigeot 1170e3adcf8fSFrançois Tigeot out_unlock: 1171a2fdbec6SFrançois Tigeot drm_modeset_unlock_all(dev); 1172e3adcf8fSFrançois Tigeot return ret; 1173e3adcf8fSFrançois Tigeot } 1174e3adcf8fSFrançois Tigeot 11758e26cdf6SFrançois Tigeot void intel_plane_restore(struct drm_plane *plane) 11768e26cdf6SFrançois Tigeot { 11778e26cdf6SFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(plane); 11788e26cdf6SFrançois Tigeot 11798e26cdf6SFrançois Tigeot if (!plane->crtc || !plane->fb) 11808e26cdf6SFrançois Tigeot return; 11818e26cdf6SFrançois Tigeot 11828e26cdf6SFrançois Tigeot intel_update_plane(plane, plane->crtc, plane->fb, 11838e26cdf6SFrançois Tigeot intel_plane->crtc_x, intel_plane->crtc_y, 11848e26cdf6SFrançois Tigeot intel_plane->crtc_w, intel_plane->crtc_h, 11858e26cdf6SFrançois Tigeot intel_plane->src_x, intel_plane->src_y, 11868e26cdf6SFrançois Tigeot intel_plane->src_w, intel_plane->src_h); 11878e26cdf6SFrançois Tigeot } 11888e26cdf6SFrançois Tigeot 11895d0b1887SFrançois Tigeot void intel_plane_disable(struct drm_plane *plane) 11905d0b1887SFrançois Tigeot { 11915d0b1887SFrançois Tigeot if (!plane->crtc || !plane->fb) 11925d0b1887SFrançois Tigeot return; 11935d0b1887SFrançois Tigeot 11945d0b1887SFrançois Tigeot intel_disable_plane(plane); 11955d0b1887SFrançois Tigeot } 11965d0b1887SFrançois Tigeot 1197e3adcf8fSFrançois Tigeot static const struct drm_plane_funcs intel_plane_funcs = { 1198e3adcf8fSFrançois Tigeot .update_plane = intel_update_plane, 1199e3adcf8fSFrançois Tigeot .disable_plane = intel_disable_plane, 1200e3adcf8fSFrançois Tigeot .destroy = intel_destroy_plane, 1201e3adcf8fSFrançois Tigeot }; 1202e3adcf8fSFrançois Tigeot 12032c84b0b6SFrançois Tigeot static uint32_t ilk_plane_formats[] = { 12042c84b0b6SFrançois Tigeot DRM_FORMAT_XRGB8888, 12052c84b0b6SFrançois Tigeot DRM_FORMAT_YUYV, 12062c84b0b6SFrançois Tigeot DRM_FORMAT_YVYU, 12072c84b0b6SFrançois Tigeot DRM_FORMAT_UYVY, 12082c84b0b6SFrançois Tigeot DRM_FORMAT_VYUY, 12092c84b0b6SFrançois Tigeot }; 12102c84b0b6SFrançois Tigeot 1211e3adcf8fSFrançois Tigeot static uint32_t snb_plane_formats[] = { 1212e3adcf8fSFrançois Tigeot DRM_FORMAT_XBGR8888, 1213e3adcf8fSFrançois Tigeot DRM_FORMAT_XRGB8888, 1214e3adcf8fSFrançois Tigeot DRM_FORMAT_YUYV, 1215e3adcf8fSFrançois Tigeot DRM_FORMAT_YVYU, 1216e3adcf8fSFrançois Tigeot DRM_FORMAT_UYVY, 1217e3adcf8fSFrançois Tigeot DRM_FORMAT_VYUY, 1218e3adcf8fSFrançois Tigeot }; 1219e3adcf8fSFrançois Tigeot 12208e26cdf6SFrançois Tigeot static uint32_t vlv_plane_formats[] = { 12218e26cdf6SFrançois Tigeot DRM_FORMAT_RGB565, 12228e26cdf6SFrançois Tigeot DRM_FORMAT_ABGR8888, 12238e26cdf6SFrançois Tigeot DRM_FORMAT_ARGB8888, 12248e26cdf6SFrançois Tigeot DRM_FORMAT_XBGR8888, 12258e26cdf6SFrançois Tigeot DRM_FORMAT_XRGB8888, 12268e26cdf6SFrançois Tigeot DRM_FORMAT_XBGR2101010, 12278e26cdf6SFrançois Tigeot DRM_FORMAT_ABGR2101010, 12288e26cdf6SFrançois Tigeot DRM_FORMAT_YUYV, 12298e26cdf6SFrançois Tigeot DRM_FORMAT_YVYU, 12308e26cdf6SFrançois Tigeot DRM_FORMAT_UYVY, 12318e26cdf6SFrançois Tigeot DRM_FORMAT_VYUY, 12328e26cdf6SFrançois Tigeot }; 12338e26cdf6SFrançois Tigeot 1234e3adcf8fSFrançois Tigeot int 12358e26cdf6SFrançois Tigeot intel_plane_init(struct drm_device *dev, enum i915_pipe pipe, int plane) 1236e3adcf8fSFrançois Tigeot { 1237e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane; 1238e3adcf8fSFrançois Tigeot unsigned long possible_crtcs; 12392c84b0b6SFrançois Tigeot const uint32_t *plane_formats; 12402c84b0b6SFrançois Tigeot int num_plane_formats; 1241e3adcf8fSFrançois Tigeot int ret; 1242e3adcf8fSFrançois Tigeot 12432c84b0b6SFrançois Tigeot if (INTEL_INFO(dev)->gen < 5) 1244e3adcf8fSFrançois Tigeot return -ENODEV; 1245e3adcf8fSFrançois Tigeot 12469edbd4a0SFrançois Tigeot intel_plane = kzalloc(sizeof(*intel_plane), GFP_KERNEL); 12472c84b0b6SFrançois Tigeot if (!intel_plane) 12482c84b0b6SFrançois Tigeot return -ENOMEM; 12492c84b0b6SFrançois Tigeot 12502c84b0b6SFrançois Tigeot switch (INTEL_INFO(dev)->gen) { 12512c84b0b6SFrançois Tigeot case 5: 12522c84b0b6SFrançois Tigeot case 6: 12532c84b0b6SFrançois Tigeot intel_plane->can_scale = true; 12542c84b0b6SFrançois Tigeot intel_plane->max_downscale = 16; 12552c84b0b6SFrançois Tigeot intel_plane->update_plane = ilk_update_plane; 12562c84b0b6SFrançois Tigeot intel_plane->disable_plane = ilk_disable_plane; 12572c84b0b6SFrançois Tigeot intel_plane->update_colorkey = ilk_update_colorkey; 12582c84b0b6SFrançois Tigeot intel_plane->get_colorkey = ilk_get_colorkey; 1259e3adcf8fSFrançois Tigeot 1260e3adcf8fSFrançois Tigeot if (IS_GEN6(dev)) { 12612c84b0b6SFrançois Tigeot plane_formats = snb_plane_formats; 12622c84b0b6SFrançois Tigeot num_plane_formats = ARRAY_SIZE(snb_plane_formats); 12632c84b0b6SFrançois Tigeot } else { 12642c84b0b6SFrançois Tigeot plane_formats = ilk_plane_formats; 12652c84b0b6SFrançois Tigeot num_plane_formats = ARRAY_SIZE(ilk_plane_formats); 12662c84b0b6SFrançois Tigeot } 12672c84b0b6SFrançois Tigeot break; 12682c84b0b6SFrançois Tigeot 12692c84b0b6SFrançois Tigeot case 7: 12709edbd4a0SFrançois Tigeot case 8: 12715d0b1887SFrançois Tigeot if (IS_IVYBRIDGE(dev)) { 12722c84b0b6SFrançois Tigeot intel_plane->can_scale = true; 12735d0b1887SFrançois Tigeot intel_plane->max_downscale = 2; 12745d0b1887SFrançois Tigeot } else { 12755d0b1887SFrançois Tigeot intel_plane->can_scale = false; 12765d0b1887SFrançois Tigeot intel_plane->max_downscale = 1; 12775d0b1887SFrançois Tigeot } 12788e26cdf6SFrançois Tigeot 12798e26cdf6SFrançois Tigeot if (IS_VALLEYVIEW(dev)) { 12808e26cdf6SFrançois Tigeot intel_plane->update_plane = vlv_update_plane; 12818e26cdf6SFrançois Tigeot intel_plane->disable_plane = vlv_disable_plane; 12828e26cdf6SFrançois Tigeot intel_plane->update_colorkey = vlv_update_colorkey; 12838e26cdf6SFrançois Tigeot intel_plane->get_colorkey = vlv_get_colorkey; 12848e26cdf6SFrançois Tigeot 12858e26cdf6SFrançois Tigeot plane_formats = vlv_plane_formats; 12868e26cdf6SFrançois Tigeot num_plane_formats = ARRAY_SIZE(vlv_plane_formats); 12878e26cdf6SFrançois Tigeot } else { 1288e3adcf8fSFrançois Tigeot intel_plane->update_plane = ivb_update_plane; 1289e3adcf8fSFrançois Tigeot intel_plane->disable_plane = ivb_disable_plane; 1290e3adcf8fSFrançois Tigeot intel_plane->update_colorkey = ivb_update_colorkey; 1291e3adcf8fSFrançois Tigeot intel_plane->get_colorkey = ivb_get_colorkey; 12922c84b0b6SFrançois Tigeot 12932c84b0b6SFrançois Tigeot plane_formats = snb_plane_formats; 12942c84b0b6SFrançois Tigeot num_plane_formats = ARRAY_SIZE(snb_plane_formats); 12958e26cdf6SFrançois Tigeot } 12962c84b0b6SFrançois Tigeot break; 12972c84b0b6SFrançois Tigeot 12982c84b0b6SFrançois Tigeot default: 1299158486a6SFrançois Tigeot kfree(intel_plane); 13002c84b0b6SFrançois Tigeot return -ENODEV; 1301e3adcf8fSFrançois Tigeot } 1302e3adcf8fSFrançois Tigeot 1303e3adcf8fSFrançois Tigeot intel_plane->pipe = pipe; 13048e26cdf6SFrançois Tigeot intel_plane->plane = plane; 1305e3adcf8fSFrançois Tigeot possible_crtcs = (1 << pipe); 1306e3adcf8fSFrançois Tigeot ret = drm_plane_init(dev, &intel_plane->base, possible_crtcs, 13072c84b0b6SFrançois Tigeot &intel_plane_funcs, 13082c84b0b6SFrançois Tigeot plane_formats, num_plane_formats, 13092c84b0b6SFrançois Tigeot false); 1310e3adcf8fSFrançois Tigeot if (ret) 1311158486a6SFrançois Tigeot kfree(intel_plane); 1312e3adcf8fSFrançois Tigeot 1313e3adcf8fSFrançois Tigeot return ret; 1314e3adcf8fSFrançois Tigeot } 1315