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> 36*2c9916cdSFrançois Tigeot #include <drm/drm_plane_helper.h> 3718e26a6dSFrançois Tigeot #include "intel_drv.h" 385c6c6f23SFrançois Tigeot #include <drm/i915_drm.h> 39e3adcf8fSFrançois Tigeot #include "i915_drv.h" 40e3adcf8fSFrançois Tigeot 41*2c9916cdSFrançois Tigeot static bool 42*2c9916cdSFrançois Tigeot format_is_yuv(uint32_t format) 43*2c9916cdSFrançois Tigeot { 44*2c9916cdSFrançois Tigeot switch (format) { 45*2c9916cdSFrançois Tigeot case DRM_FORMAT_YUYV: 46*2c9916cdSFrançois Tigeot case DRM_FORMAT_UYVY: 47*2c9916cdSFrançois Tigeot case DRM_FORMAT_VYUY: 48*2c9916cdSFrançois Tigeot case DRM_FORMAT_YVYU: 49*2c9916cdSFrançois Tigeot return true; 50*2c9916cdSFrançois Tigeot default: 51*2c9916cdSFrançois Tigeot return false; 52*2c9916cdSFrançois Tigeot } 53*2c9916cdSFrançois Tigeot } 54*2c9916cdSFrançois Tigeot 55ba55f2f5SFrançois Tigeot static int usecs_to_scanlines(const struct drm_display_mode *mode, int usecs) 56ba55f2f5SFrançois Tigeot { 57ba55f2f5SFrançois Tigeot /* paranoia */ 58ba55f2f5SFrançois Tigeot if (!mode->crtc_htotal) 59ba55f2f5SFrançois Tigeot return 1; 60ba55f2f5SFrançois Tigeot 61ba55f2f5SFrançois Tigeot return DIV_ROUND_UP(usecs * mode->crtc_clock, 1000 * mode->crtc_htotal); 62ba55f2f5SFrançois Tigeot } 63ba55f2f5SFrançois Tigeot 64*2c9916cdSFrançois Tigeot /** 65*2c9916cdSFrançois Tigeot * intel_pipe_update_start() - start update of a set of display registers 66*2c9916cdSFrançois Tigeot * @crtc: the crtc of which the registers are going to be updated 67*2c9916cdSFrançois Tigeot * @start_vbl_count: vblank counter return pointer used for error checking 68*2c9916cdSFrançois Tigeot * 69*2c9916cdSFrançois Tigeot * Mark the start of an update to pipe registers that should be updated 70*2c9916cdSFrançois Tigeot * atomically regarding vblank. If the next vblank will happens within 71*2c9916cdSFrançois Tigeot * the next 100 us, this function waits until the vblank passes. 72*2c9916cdSFrançois Tigeot * 73*2c9916cdSFrançois Tigeot * After a successful call to this function, interrupts will be disabled 74*2c9916cdSFrançois Tigeot * until a subsequent call to intel_pipe_update_end(). That is done to 75*2c9916cdSFrançois Tigeot * avoid random delays. The value written to @start_vbl_count should be 76*2c9916cdSFrançois Tigeot * supplied to intel_pipe_update_end() for error checking. 77*2c9916cdSFrançois Tigeot * 78*2c9916cdSFrançois Tigeot * Return: true if the call was successful 79*2c9916cdSFrançois Tigeot */ 80*2c9916cdSFrançois Tigeot bool intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl_count) 81ba55f2f5SFrançois Tigeot { 82ba55f2f5SFrançois Tigeot struct drm_device *dev = crtc->base.dev; 83*2c9916cdSFrançois Tigeot const struct drm_display_mode *mode = &crtc->config->base.adjusted_mode; 84ba55f2f5SFrançois Tigeot enum i915_pipe pipe = crtc->pipe; 85ba55f2f5SFrançois Tigeot long timeout = msecs_to_jiffies_timeout(1); 86ba55f2f5SFrançois Tigeot int scanline, min, max, vblank_start; 871b13d190SFrançois Tigeot wait_queue_head_t *wq = drm_crtc_vblank_waitqueue(&crtc->base); 88ba55f2f5SFrançois Tigeot DEFINE_WAIT(wait); 89ba55f2f5SFrançois Tigeot 90ba55f2f5SFrançois Tigeot vblank_start = mode->crtc_vblank_start; 91ba55f2f5SFrançois Tigeot if (mode->flags & DRM_MODE_FLAG_INTERLACE) 92ba55f2f5SFrançois Tigeot vblank_start = DIV_ROUND_UP(vblank_start, 2); 93ba55f2f5SFrançois Tigeot 94ba55f2f5SFrançois Tigeot /* FIXME needs to be calibrated sensibly */ 95ba55f2f5SFrançois Tigeot min = vblank_start - usecs_to_scanlines(mode, 100); 96ba55f2f5SFrançois Tigeot max = vblank_start - 1; 97ba55f2f5SFrançois Tigeot 98ba55f2f5SFrançois Tigeot if (min <= 0 || max <= 0) 99ba55f2f5SFrançois Tigeot return false; 100ba55f2f5SFrançois Tigeot 101ba55f2f5SFrançois Tigeot if (WARN_ON(drm_vblank_get(dev, pipe))) 102ba55f2f5SFrançois Tigeot return false; 103ba55f2f5SFrançois Tigeot 104ba55f2f5SFrançois Tigeot local_irq_disable(); 105ba55f2f5SFrançois Tigeot 106ba55f2f5SFrançois Tigeot trace_i915_pipe_update_start(crtc, min, max); 107ba55f2f5SFrançois Tigeot 108ba55f2f5SFrançois Tigeot for (;;) { 109ba55f2f5SFrançois Tigeot /* 110ba55f2f5SFrançois Tigeot * prepare_to_wait() has a memory barrier, which guarantees 111ba55f2f5SFrançois Tigeot * other CPUs can see the task state update by the time we 112ba55f2f5SFrançois Tigeot * read the scanline. 113ba55f2f5SFrançois Tigeot */ 1141b13d190SFrançois Tigeot prepare_to_wait(wq, &wait, TASK_UNINTERRUPTIBLE); 115ba55f2f5SFrançois Tigeot 116ba55f2f5SFrançois Tigeot scanline = intel_get_crtc_scanline(crtc); 117ba55f2f5SFrançois Tigeot if (scanline < min || scanline > max) 118ba55f2f5SFrançois Tigeot break; 119ba55f2f5SFrançois Tigeot 120ba55f2f5SFrançois Tigeot if (timeout <= 0) { 121ba55f2f5SFrançois Tigeot DRM_ERROR("Potential atomic update failure on pipe %c\n", 122ba55f2f5SFrançois Tigeot pipe_name(crtc->pipe)); 123ba55f2f5SFrançois Tigeot break; 124ba55f2f5SFrançois Tigeot } 125ba55f2f5SFrançois Tigeot 126ba55f2f5SFrançois Tigeot local_irq_enable(); 127ba55f2f5SFrançois Tigeot 128ba55f2f5SFrançois Tigeot timeout = schedule_timeout(timeout); 129ba55f2f5SFrançois Tigeot 130ba55f2f5SFrançois Tigeot local_irq_disable(); 131ba55f2f5SFrançois Tigeot } 132ba55f2f5SFrançois Tigeot 1331b13d190SFrançois Tigeot finish_wait(wq, &wait); 134ba55f2f5SFrançois Tigeot 135ba55f2f5SFrançois Tigeot drm_vblank_put(dev, pipe); 136ba55f2f5SFrançois Tigeot 137ba55f2f5SFrançois Tigeot *start_vbl_count = dev->driver->get_vblank_counter(dev, pipe); 138ba55f2f5SFrançois Tigeot 139ba55f2f5SFrançois Tigeot trace_i915_pipe_update_vblank_evaded(crtc, min, max, *start_vbl_count); 140ba55f2f5SFrançois Tigeot 141ba55f2f5SFrançois Tigeot return true; 142ba55f2f5SFrançois Tigeot } 143ba55f2f5SFrançois Tigeot 144*2c9916cdSFrançois Tigeot /** 145*2c9916cdSFrançois Tigeot * intel_pipe_update_end() - end update of a set of display registers 146*2c9916cdSFrançois Tigeot * @crtc: the crtc of which the registers were updated 147*2c9916cdSFrançois Tigeot * @start_vbl_count: start vblank counter (used for error checking) 148*2c9916cdSFrançois Tigeot * 149*2c9916cdSFrançois Tigeot * Mark the end of an update started with intel_pipe_update_start(). This 150*2c9916cdSFrançois Tigeot * re-enables interrupts and verifies the update was actually completed 151*2c9916cdSFrançois Tigeot * before a vblank using the value of @start_vbl_count. 152*2c9916cdSFrançois Tigeot */ 153*2c9916cdSFrançois Tigeot void intel_pipe_update_end(struct intel_crtc *crtc, u32 start_vbl_count) 154ba55f2f5SFrançois Tigeot { 155ba55f2f5SFrançois Tigeot struct drm_device *dev = crtc->base.dev; 156ba55f2f5SFrançois Tigeot enum i915_pipe pipe = crtc->pipe; 157ba55f2f5SFrançois Tigeot u32 end_vbl_count = dev->driver->get_vblank_counter(dev, pipe); 158ba55f2f5SFrançois Tigeot 159ba55f2f5SFrançois Tigeot trace_i915_pipe_update_end(crtc, end_vbl_count); 160ba55f2f5SFrançois Tigeot 161ba55f2f5SFrançois Tigeot local_irq_enable(); 162ba55f2f5SFrançois Tigeot 163ba55f2f5SFrançois Tigeot if (start_vbl_count != end_vbl_count) 164ba55f2f5SFrançois Tigeot DRM_ERROR("Atomic update failure on pipe %c (start=%u end=%u)\n", 165ba55f2f5SFrançois Tigeot pipe_name(pipe), start_vbl_count, end_vbl_count); 166ba55f2f5SFrançois Tigeot } 167ba55f2f5SFrançois Tigeot 168ba55f2f5SFrançois Tigeot static void intel_update_primary_plane(struct intel_crtc *crtc) 169ba55f2f5SFrançois Tigeot { 170ba55f2f5SFrançois Tigeot struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; 171ba55f2f5SFrançois Tigeot int reg = DSPCNTR(crtc->plane); 172ba55f2f5SFrançois Tigeot 173ba55f2f5SFrançois Tigeot if (crtc->primary_enabled) 174ba55f2f5SFrançois Tigeot I915_WRITE(reg, I915_READ(reg) | DISPLAY_PLANE_ENABLE); 175ba55f2f5SFrançois Tigeot else 176ba55f2f5SFrançois Tigeot I915_WRITE(reg, I915_READ(reg) & ~DISPLAY_PLANE_ENABLE); 177ba55f2f5SFrançois Tigeot } 178ba55f2f5SFrançois Tigeot 179e3adcf8fSFrançois Tigeot static void 180*2c9916cdSFrançois Tigeot skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc, 181*2c9916cdSFrançois Tigeot struct drm_framebuffer *fb, 182*2c9916cdSFrançois Tigeot struct drm_i915_gem_object *obj, int crtc_x, int crtc_y, 183*2c9916cdSFrançois Tigeot unsigned int crtc_w, unsigned int crtc_h, 184*2c9916cdSFrançois Tigeot uint32_t x, uint32_t y, 185*2c9916cdSFrançois Tigeot uint32_t src_w, uint32_t src_h) 186*2c9916cdSFrançois Tigeot { 187*2c9916cdSFrançois Tigeot struct drm_device *dev = drm_plane->dev; 188*2c9916cdSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 189*2c9916cdSFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(drm_plane); 190*2c9916cdSFrançois Tigeot const int pipe = intel_plane->pipe; 191*2c9916cdSFrançois Tigeot const int plane = intel_plane->plane + 1; 192*2c9916cdSFrançois Tigeot u32 plane_ctl, stride; 193*2c9916cdSFrançois Tigeot int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); 194*2c9916cdSFrançois Tigeot 195*2c9916cdSFrançois Tigeot plane_ctl = I915_READ(PLANE_CTL(pipe, plane)); 196*2c9916cdSFrançois Tigeot 197*2c9916cdSFrançois Tigeot /* Mask out pixel format bits in case we change it */ 198*2c9916cdSFrançois Tigeot plane_ctl &= ~PLANE_CTL_FORMAT_MASK; 199*2c9916cdSFrançois Tigeot plane_ctl &= ~PLANE_CTL_ORDER_RGBX; 200*2c9916cdSFrançois Tigeot plane_ctl &= ~PLANE_CTL_YUV422_ORDER_MASK; 201*2c9916cdSFrançois Tigeot plane_ctl &= ~PLANE_CTL_TILED_MASK; 202*2c9916cdSFrançois Tigeot plane_ctl &= ~PLANE_CTL_ALPHA_MASK; 203*2c9916cdSFrançois Tigeot plane_ctl &= ~PLANE_CTL_ROTATE_MASK; 204*2c9916cdSFrançois Tigeot 205*2c9916cdSFrançois Tigeot /* Trickle feed has to be enabled */ 206*2c9916cdSFrançois Tigeot plane_ctl &= ~PLANE_CTL_TRICKLE_FEED_DISABLE; 207*2c9916cdSFrançois Tigeot 208*2c9916cdSFrançois Tigeot switch (fb->pixel_format) { 209*2c9916cdSFrançois Tigeot case DRM_FORMAT_RGB565: 210*2c9916cdSFrançois Tigeot plane_ctl |= PLANE_CTL_FORMAT_RGB_565; 211*2c9916cdSFrançois Tigeot break; 212*2c9916cdSFrançois Tigeot case DRM_FORMAT_XBGR8888: 213*2c9916cdSFrançois Tigeot plane_ctl |= PLANE_CTL_FORMAT_XRGB_8888 | PLANE_CTL_ORDER_RGBX; 214*2c9916cdSFrançois Tigeot break; 215*2c9916cdSFrançois Tigeot case DRM_FORMAT_XRGB8888: 216*2c9916cdSFrançois Tigeot plane_ctl |= PLANE_CTL_FORMAT_XRGB_8888; 217*2c9916cdSFrançois Tigeot break; 218*2c9916cdSFrançois Tigeot /* 219*2c9916cdSFrançois Tigeot * XXX: For ARBG/ABGR formats we default to expecting scanout buffers 220*2c9916cdSFrançois Tigeot * to be already pre-multiplied. We need to add a knob (or a different 221*2c9916cdSFrançois Tigeot * DRM_FORMAT) for user-space to configure that. 222*2c9916cdSFrançois Tigeot */ 223*2c9916cdSFrançois Tigeot case DRM_FORMAT_ABGR8888: 224*2c9916cdSFrançois Tigeot plane_ctl |= PLANE_CTL_FORMAT_XRGB_8888 | 225*2c9916cdSFrançois Tigeot PLANE_CTL_ORDER_RGBX | 226*2c9916cdSFrançois Tigeot PLANE_CTL_ALPHA_SW_PREMULTIPLY; 227*2c9916cdSFrançois Tigeot break; 228*2c9916cdSFrançois Tigeot case DRM_FORMAT_ARGB8888: 229*2c9916cdSFrançois Tigeot plane_ctl |= PLANE_CTL_FORMAT_XRGB_8888 | 230*2c9916cdSFrançois Tigeot PLANE_CTL_ALPHA_SW_PREMULTIPLY; 231*2c9916cdSFrançois Tigeot break; 232*2c9916cdSFrançois Tigeot case DRM_FORMAT_YUYV: 233*2c9916cdSFrançois Tigeot plane_ctl |= PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_YUYV; 234*2c9916cdSFrançois Tigeot break; 235*2c9916cdSFrançois Tigeot case DRM_FORMAT_YVYU: 236*2c9916cdSFrançois Tigeot plane_ctl |= PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_YVYU; 237*2c9916cdSFrançois Tigeot break; 238*2c9916cdSFrançois Tigeot case DRM_FORMAT_UYVY: 239*2c9916cdSFrançois Tigeot plane_ctl |= PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_UYVY; 240*2c9916cdSFrançois Tigeot break; 241*2c9916cdSFrançois Tigeot case DRM_FORMAT_VYUY: 242*2c9916cdSFrançois Tigeot plane_ctl |= PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_VYUY; 243*2c9916cdSFrançois Tigeot break; 244*2c9916cdSFrançois Tigeot default: 245*2c9916cdSFrançois Tigeot BUG(); 246*2c9916cdSFrançois Tigeot } 247*2c9916cdSFrançois Tigeot 248*2c9916cdSFrançois Tigeot switch (obj->tiling_mode) { 249*2c9916cdSFrançois Tigeot case I915_TILING_NONE: 250*2c9916cdSFrançois Tigeot stride = fb->pitches[0] >> 6; 251*2c9916cdSFrançois Tigeot break; 252*2c9916cdSFrançois Tigeot case I915_TILING_X: 253*2c9916cdSFrançois Tigeot plane_ctl |= PLANE_CTL_TILED_X; 254*2c9916cdSFrançois Tigeot stride = fb->pitches[0] >> 9; 255*2c9916cdSFrançois Tigeot break; 256*2c9916cdSFrançois Tigeot default: 257*2c9916cdSFrançois Tigeot BUG(); 258*2c9916cdSFrançois Tigeot } 259*2c9916cdSFrançois Tigeot if (drm_plane->state->rotation == BIT(DRM_ROTATE_180)) 260*2c9916cdSFrançois Tigeot plane_ctl |= PLANE_CTL_ROTATE_180; 261*2c9916cdSFrançois Tigeot 262*2c9916cdSFrançois Tigeot plane_ctl |= PLANE_CTL_ENABLE; 263*2c9916cdSFrançois Tigeot plane_ctl |= PLANE_CTL_PIPE_CSC_ENABLE; 264*2c9916cdSFrançois Tigeot 265*2c9916cdSFrançois Tigeot intel_update_sprite_watermarks(drm_plane, crtc, src_w, src_h, 266*2c9916cdSFrançois Tigeot pixel_size, true, 267*2c9916cdSFrançois Tigeot src_w != crtc_w || src_h != crtc_h); 268*2c9916cdSFrançois Tigeot 269*2c9916cdSFrançois Tigeot /* Sizes are 0 based */ 270*2c9916cdSFrançois Tigeot src_w--; 271*2c9916cdSFrançois Tigeot src_h--; 272*2c9916cdSFrançois Tigeot crtc_w--; 273*2c9916cdSFrançois Tigeot crtc_h--; 274*2c9916cdSFrançois Tigeot 275*2c9916cdSFrançois Tigeot I915_WRITE(PLANE_OFFSET(pipe, plane), (y << 16) | x); 276*2c9916cdSFrançois Tigeot I915_WRITE(PLANE_STRIDE(pipe, plane), stride); 277*2c9916cdSFrançois Tigeot I915_WRITE(PLANE_POS(pipe, plane), (crtc_y << 16) | crtc_x); 278*2c9916cdSFrançois Tigeot I915_WRITE(PLANE_SIZE(pipe, plane), (crtc_h << 16) | crtc_w); 279*2c9916cdSFrançois Tigeot I915_WRITE(PLANE_CTL(pipe, plane), plane_ctl); 280*2c9916cdSFrançois Tigeot I915_WRITE(PLANE_SURF(pipe, plane), i915_gem_obj_ggtt_offset(obj)); 281*2c9916cdSFrançois Tigeot POSTING_READ(PLANE_SURF(pipe, plane)); 282*2c9916cdSFrançois Tigeot } 283*2c9916cdSFrançois Tigeot 284*2c9916cdSFrançois Tigeot static void 285*2c9916cdSFrançois Tigeot skl_disable_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc) 286*2c9916cdSFrançois Tigeot { 287*2c9916cdSFrançois Tigeot struct drm_device *dev = drm_plane->dev; 288*2c9916cdSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 289*2c9916cdSFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(drm_plane); 290*2c9916cdSFrançois Tigeot const int pipe = intel_plane->pipe; 291*2c9916cdSFrançois Tigeot const int plane = intel_plane->plane + 1; 292*2c9916cdSFrançois Tigeot 293*2c9916cdSFrançois Tigeot I915_WRITE(PLANE_CTL(pipe, plane), 294*2c9916cdSFrançois Tigeot I915_READ(PLANE_CTL(pipe, plane)) & ~PLANE_CTL_ENABLE); 295*2c9916cdSFrançois Tigeot 296*2c9916cdSFrançois Tigeot /* Activate double buffered register update */ 297*2c9916cdSFrançois Tigeot I915_WRITE(PLANE_CTL(pipe, plane), 0); 298*2c9916cdSFrançois Tigeot POSTING_READ(PLANE_CTL(pipe, plane)); 299*2c9916cdSFrançois Tigeot 300*2c9916cdSFrançois Tigeot intel_update_sprite_watermarks(drm_plane, crtc, 0, 0, 0, false, false); 301*2c9916cdSFrançois Tigeot } 302*2c9916cdSFrançois Tigeot 303*2c9916cdSFrançois Tigeot static int 304*2c9916cdSFrançois Tigeot skl_update_colorkey(struct drm_plane *drm_plane, 305*2c9916cdSFrançois Tigeot struct drm_intel_sprite_colorkey *key) 306*2c9916cdSFrançois Tigeot { 307*2c9916cdSFrançois Tigeot struct drm_device *dev = drm_plane->dev; 308*2c9916cdSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 309*2c9916cdSFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(drm_plane); 310*2c9916cdSFrançois Tigeot const int pipe = intel_plane->pipe; 311*2c9916cdSFrançois Tigeot const int plane = intel_plane->plane; 312*2c9916cdSFrançois Tigeot u32 plane_ctl; 313*2c9916cdSFrançois Tigeot 314*2c9916cdSFrançois Tigeot I915_WRITE(PLANE_KEYVAL(pipe, plane), key->min_value); 315*2c9916cdSFrançois Tigeot I915_WRITE(PLANE_KEYMAX(pipe, plane), key->max_value); 316*2c9916cdSFrançois Tigeot I915_WRITE(PLANE_KEYMSK(pipe, plane), key->channel_mask); 317*2c9916cdSFrançois Tigeot 318*2c9916cdSFrançois Tigeot plane_ctl = I915_READ(PLANE_CTL(pipe, plane)); 319*2c9916cdSFrançois Tigeot plane_ctl &= ~PLANE_CTL_KEY_ENABLE_MASK; 320*2c9916cdSFrançois Tigeot if (key->flags & I915_SET_COLORKEY_DESTINATION) 321*2c9916cdSFrançois Tigeot plane_ctl |= PLANE_CTL_KEY_ENABLE_DESTINATION; 322*2c9916cdSFrançois Tigeot else if (key->flags & I915_SET_COLORKEY_SOURCE) 323*2c9916cdSFrançois Tigeot plane_ctl |= PLANE_CTL_KEY_ENABLE_SOURCE; 324*2c9916cdSFrançois Tigeot I915_WRITE(PLANE_CTL(pipe, plane), plane_ctl); 325*2c9916cdSFrançois Tigeot 326*2c9916cdSFrançois Tigeot POSTING_READ(PLANE_CTL(pipe, plane)); 327*2c9916cdSFrançois Tigeot 328*2c9916cdSFrançois Tigeot return 0; 329*2c9916cdSFrançois Tigeot } 330*2c9916cdSFrançois Tigeot 331*2c9916cdSFrançois Tigeot static void 332*2c9916cdSFrançois Tigeot skl_get_colorkey(struct drm_plane *drm_plane, 333*2c9916cdSFrançois Tigeot struct drm_intel_sprite_colorkey *key) 334*2c9916cdSFrançois Tigeot { 335*2c9916cdSFrançois Tigeot struct drm_device *dev = drm_plane->dev; 336*2c9916cdSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 337*2c9916cdSFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(drm_plane); 338*2c9916cdSFrançois Tigeot const int pipe = intel_plane->pipe; 339*2c9916cdSFrançois Tigeot const int plane = intel_plane->plane; 340*2c9916cdSFrançois Tigeot u32 plane_ctl; 341*2c9916cdSFrançois Tigeot 342*2c9916cdSFrançois Tigeot key->min_value = I915_READ(PLANE_KEYVAL(pipe, plane)); 343*2c9916cdSFrançois Tigeot key->max_value = I915_READ(PLANE_KEYMAX(pipe, plane)); 344*2c9916cdSFrançois Tigeot key->channel_mask = I915_READ(PLANE_KEYMSK(pipe, plane)); 345*2c9916cdSFrançois Tigeot 346*2c9916cdSFrançois Tigeot plane_ctl = I915_READ(PLANE_CTL(pipe, plane)); 347*2c9916cdSFrançois Tigeot 348*2c9916cdSFrançois Tigeot switch (plane_ctl & PLANE_CTL_KEY_ENABLE_MASK) { 349*2c9916cdSFrançois Tigeot case PLANE_CTL_KEY_ENABLE_DESTINATION: 350*2c9916cdSFrançois Tigeot key->flags = I915_SET_COLORKEY_DESTINATION; 351*2c9916cdSFrançois Tigeot break; 352*2c9916cdSFrançois Tigeot case PLANE_CTL_KEY_ENABLE_SOURCE: 353*2c9916cdSFrançois Tigeot key->flags = I915_SET_COLORKEY_SOURCE; 354*2c9916cdSFrançois Tigeot break; 355*2c9916cdSFrançois Tigeot default: 356*2c9916cdSFrançois Tigeot key->flags = I915_SET_COLORKEY_NONE; 357*2c9916cdSFrançois Tigeot } 358*2c9916cdSFrançois Tigeot } 359*2c9916cdSFrançois Tigeot 360*2c9916cdSFrançois Tigeot static void 361*2c9916cdSFrançois Tigeot chv_update_csc(struct intel_plane *intel_plane, uint32_t format) 362*2c9916cdSFrançois Tigeot { 363*2c9916cdSFrançois Tigeot struct drm_i915_private *dev_priv = intel_plane->base.dev->dev_private; 364*2c9916cdSFrançois Tigeot int plane = intel_plane->plane; 365*2c9916cdSFrançois Tigeot 366*2c9916cdSFrançois Tigeot /* Seems RGB data bypasses the CSC always */ 367*2c9916cdSFrançois Tigeot if (!format_is_yuv(format)) 368*2c9916cdSFrançois Tigeot return; 369*2c9916cdSFrançois Tigeot 370*2c9916cdSFrançois Tigeot /* 371*2c9916cdSFrançois Tigeot * BT.601 limited range YCbCr -> full range RGB 372*2c9916cdSFrançois Tigeot * 373*2c9916cdSFrançois Tigeot * |r| | 6537 4769 0| |cr | 374*2c9916cdSFrançois Tigeot * |g| = |-3330 4769 -1605| x |y-64| 375*2c9916cdSFrançois Tigeot * |b| | 0 4769 8263| |cb | 376*2c9916cdSFrançois Tigeot * 377*2c9916cdSFrançois Tigeot * Cb and Cr apparently come in as signed already, so no 378*2c9916cdSFrançois Tigeot * need for any offset. For Y we need to remove the offset. 379*2c9916cdSFrançois Tigeot */ 380*2c9916cdSFrançois Tigeot I915_WRITE(SPCSCYGOFF(plane), SPCSC_OOFF(0) | SPCSC_IOFF(-64)); 381*2c9916cdSFrançois Tigeot I915_WRITE(SPCSCCBOFF(plane), SPCSC_OOFF(0) | SPCSC_IOFF(0)); 382*2c9916cdSFrançois Tigeot I915_WRITE(SPCSCCROFF(plane), SPCSC_OOFF(0) | SPCSC_IOFF(0)); 383*2c9916cdSFrançois Tigeot 384*2c9916cdSFrançois Tigeot I915_WRITE(SPCSCC01(plane), SPCSC_C1(4769) | SPCSC_C0(6537)); 385*2c9916cdSFrançois Tigeot I915_WRITE(SPCSCC23(plane), SPCSC_C1(-3330) | SPCSC_C0(0)); 386*2c9916cdSFrançois Tigeot I915_WRITE(SPCSCC45(plane), SPCSC_C1(-1605) | SPCSC_C0(4769)); 387*2c9916cdSFrançois Tigeot I915_WRITE(SPCSCC67(plane), SPCSC_C1(4769) | SPCSC_C0(0)); 388*2c9916cdSFrançois Tigeot I915_WRITE(SPCSCC8(plane), SPCSC_C0(8263)); 389*2c9916cdSFrançois Tigeot 390*2c9916cdSFrançois Tigeot I915_WRITE(SPCSCYGICLAMP(plane), SPCSC_IMAX(940) | SPCSC_IMIN(64)); 391*2c9916cdSFrançois Tigeot I915_WRITE(SPCSCCBICLAMP(plane), SPCSC_IMAX(448) | SPCSC_IMIN(-448)); 392*2c9916cdSFrançois Tigeot I915_WRITE(SPCSCCRICLAMP(plane), SPCSC_IMAX(448) | SPCSC_IMIN(-448)); 393*2c9916cdSFrançois Tigeot 394*2c9916cdSFrançois Tigeot I915_WRITE(SPCSCYGOCLAMP(plane), SPCSC_OMAX(1023) | SPCSC_OMIN(0)); 395*2c9916cdSFrançois Tigeot I915_WRITE(SPCSCCBOCLAMP(plane), SPCSC_OMAX(1023) | SPCSC_OMIN(0)); 396*2c9916cdSFrançois Tigeot I915_WRITE(SPCSCCROCLAMP(plane), SPCSC_OMAX(1023) | SPCSC_OMIN(0)); 397*2c9916cdSFrançois Tigeot } 398*2c9916cdSFrançois Tigeot 399*2c9916cdSFrançois Tigeot static void 4009edbd4a0SFrançois Tigeot vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, 4019edbd4a0SFrançois Tigeot struct drm_framebuffer *fb, 4028e26cdf6SFrançois Tigeot struct drm_i915_gem_object *obj, int crtc_x, int crtc_y, 4038e26cdf6SFrançois Tigeot unsigned int crtc_w, unsigned int crtc_h, 4048e26cdf6SFrançois Tigeot uint32_t x, uint32_t y, 4058e26cdf6SFrançois Tigeot uint32_t src_w, uint32_t src_h) 4068e26cdf6SFrançois Tigeot { 4078e26cdf6SFrançois Tigeot struct drm_device *dev = dplane->dev; 4088e26cdf6SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 4098e26cdf6SFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(dplane); 410ba55f2f5SFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 4118e26cdf6SFrançois Tigeot int pipe = intel_plane->pipe; 4128e26cdf6SFrançois Tigeot int plane = intel_plane->plane; 4138e26cdf6SFrançois Tigeot u32 sprctl; 4148e26cdf6SFrançois Tigeot unsigned long sprsurf_offset, linear_offset; 4158e26cdf6SFrançois Tigeot int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); 4168e26cdf6SFrançois Tigeot 4178e26cdf6SFrançois Tigeot sprctl = I915_READ(SPCNTR(pipe, plane)); 4188e26cdf6SFrançois Tigeot 4198e26cdf6SFrançois Tigeot /* Mask out pixel format bits in case we change it */ 4208e26cdf6SFrançois Tigeot sprctl &= ~SP_PIXFORMAT_MASK; 4218e26cdf6SFrançois Tigeot sprctl &= ~SP_YUV_BYTE_ORDER_MASK; 4228e26cdf6SFrançois Tigeot sprctl &= ~SP_TILED; 4231b13d190SFrançois Tigeot sprctl &= ~SP_ROTATE_180; 4248e26cdf6SFrançois Tigeot 4258e26cdf6SFrançois Tigeot switch (fb->pixel_format) { 4268e26cdf6SFrançois Tigeot case DRM_FORMAT_YUYV: 4278e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_YUYV; 4288e26cdf6SFrançois Tigeot break; 4298e26cdf6SFrançois Tigeot case DRM_FORMAT_YVYU: 4308e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_YVYU; 4318e26cdf6SFrançois Tigeot break; 4328e26cdf6SFrançois Tigeot case DRM_FORMAT_UYVY: 4338e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_UYVY; 4348e26cdf6SFrançois Tigeot break; 4358e26cdf6SFrançois Tigeot case DRM_FORMAT_VYUY: 4368e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_VYUY; 4378e26cdf6SFrançois Tigeot break; 4388e26cdf6SFrançois Tigeot case DRM_FORMAT_RGB565: 4398e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_BGR565; 4408e26cdf6SFrançois Tigeot break; 4418e26cdf6SFrançois Tigeot case DRM_FORMAT_XRGB8888: 4428e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_BGRX8888; 4438e26cdf6SFrançois Tigeot break; 4448e26cdf6SFrançois Tigeot case DRM_FORMAT_ARGB8888: 4458e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_BGRA8888; 4468e26cdf6SFrançois Tigeot break; 4478e26cdf6SFrançois Tigeot case DRM_FORMAT_XBGR2101010: 4488e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_RGBX1010102; 4498e26cdf6SFrançois Tigeot break; 4508e26cdf6SFrançois Tigeot case DRM_FORMAT_ABGR2101010: 4518e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_RGBA1010102; 4528e26cdf6SFrançois Tigeot break; 4538e26cdf6SFrançois Tigeot case DRM_FORMAT_XBGR8888: 4548e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_RGBX8888; 4558e26cdf6SFrançois Tigeot break; 4568e26cdf6SFrançois Tigeot case DRM_FORMAT_ABGR8888: 4578e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_RGBA8888; 4588e26cdf6SFrançois Tigeot break; 4598e26cdf6SFrançois Tigeot default: 4608e26cdf6SFrançois Tigeot /* 4618e26cdf6SFrançois Tigeot * If we get here one of the upper layers failed to filter 4628e26cdf6SFrançois Tigeot * out the unsupported plane formats 4638e26cdf6SFrançois Tigeot */ 4648e26cdf6SFrançois Tigeot BUG(); 4658e26cdf6SFrançois Tigeot break; 4668e26cdf6SFrançois Tigeot } 4678e26cdf6SFrançois Tigeot 4689edbd4a0SFrançois Tigeot /* 4699edbd4a0SFrançois Tigeot * Enable gamma to match primary/cursor plane behaviour. 4709edbd4a0SFrançois Tigeot * FIXME should be user controllable via propertiesa. 4719edbd4a0SFrançois Tigeot */ 4729edbd4a0SFrançois Tigeot sprctl |= SP_GAMMA_ENABLE; 4739edbd4a0SFrançois Tigeot 4748e26cdf6SFrançois Tigeot if (obj->tiling_mode != I915_TILING_NONE) 4758e26cdf6SFrançois Tigeot sprctl |= SP_TILED; 4768e26cdf6SFrançois Tigeot 4778e26cdf6SFrançois Tigeot sprctl |= SP_ENABLE; 4788e26cdf6SFrançois Tigeot 47924edb884SFrançois Tigeot intel_update_sprite_watermarks(dplane, crtc, src_w, src_h, 48024edb884SFrançois Tigeot pixel_size, true, 4819edbd4a0SFrançois Tigeot src_w != crtc_w || src_h != crtc_h); 4829edbd4a0SFrançois Tigeot 4838e26cdf6SFrançois Tigeot /* Sizes are 0 based */ 4848e26cdf6SFrançois Tigeot src_w--; 4858e26cdf6SFrançois Tigeot src_h--; 4868e26cdf6SFrançois Tigeot crtc_w--; 4878e26cdf6SFrançois Tigeot crtc_h--; 4888e26cdf6SFrançois Tigeot 4898e26cdf6SFrançois Tigeot linear_offset = y * fb->pitches[0] + x * pixel_size; 4908e26cdf6SFrançois Tigeot sprsurf_offset = intel_gen4_compute_page_offset(&x, &y, 4918e26cdf6SFrançois Tigeot obj->tiling_mode, 4928e26cdf6SFrançois Tigeot pixel_size, 4938e26cdf6SFrançois Tigeot fb->pitches[0]); 4948e26cdf6SFrançois Tigeot linear_offset -= sprsurf_offset; 4958e26cdf6SFrançois Tigeot 496*2c9916cdSFrançois Tigeot if (dplane->state->rotation == BIT(DRM_ROTATE_180)) { 4971b13d190SFrançois Tigeot sprctl |= SP_ROTATE_180; 4981b13d190SFrançois Tigeot 4991b13d190SFrançois Tigeot x += src_w; 5001b13d190SFrançois Tigeot y += src_h; 5011b13d190SFrançois Tigeot linear_offset += src_h * fb->pitches[0] + src_w * pixel_size; 5021b13d190SFrançois Tigeot } 5031b13d190SFrançois Tigeot 504ba55f2f5SFrançois Tigeot intel_update_primary_plane(intel_crtc); 505ba55f2f5SFrançois Tigeot 506*2c9916cdSFrançois Tigeot if (IS_CHERRYVIEW(dev) && pipe == PIPE_B) 507*2c9916cdSFrançois Tigeot chv_update_csc(intel_plane, fb->pixel_format); 508*2c9916cdSFrançois Tigeot 509ba55f2f5SFrançois Tigeot I915_WRITE(SPSTRIDE(pipe, plane), fb->pitches[0]); 510ba55f2f5SFrançois Tigeot I915_WRITE(SPPOS(pipe, plane), (crtc_y << 16) | crtc_x); 511ba55f2f5SFrançois Tigeot 5128e26cdf6SFrançois Tigeot if (obj->tiling_mode != I915_TILING_NONE) 5138e26cdf6SFrançois Tigeot I915_WRITE(SPTILEOFF(pipe, plane), (y << 16) | x); 5148e26cdf6SFrançois Tigeot else 5158e26cdf6SFrançois Tigeot I915_WRITE(SPLINOFF(pipe, plane), linear_offset); 5168e26cdf6SFrançois Tigeot 517*2c9916cdSFrançois Tigeot I915_WRITE(SPCONSTALPHA(pipe, plane), 0); 518*2c9916cdSFrançois Tigeot 5198e26cdf6SFrançois Tigeot I915_WRITE(SPSIZE(pipe, plane), (crtc_h << 16) | crtc_w); 5208e26cdf6SFrançois Tigeot I915_WRITE(SPCNTR(pipe, plane), sprctl); 5219edbd4a0SFrançois Tigeot I915_WRITE(SPSURF(pipe, plane), i915_gem_obj_ggtt_offset(obj) + 5228e26cdf6SFrançois Tigeot sprsurf_offset); 523ba55f2f5SFrançois Tigeot 524ba55f2f5SFrançois Tigeot intel_flush_primary_plane(dev_priv, intel_crtc->plane); 5258e26cdf6SFrançois Tigeot } 5268e26cdf6SFrançois Tigeot 5278e26cdf6SFrançois Tigeot static void 5289edbd4a0SFrançois Tigeot vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc) 5298e26cdf6SFrançois Tigeot { 5308e26cdf6SFrançois Tigeot struct drm_device *dev = dplane->dev; 5318e26cdf6SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 5328e26cdf6SFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(dplane); 533ba55f2f5SFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 5348e26cdf6SFrançois Tigeot int pipe = intel_plane->pipe; 5358e26cdf6SFrançois Tigeot int plane = intel_plane->plane; 536ba55f2f5SFrançois Tigeot 537ba55f2f5SFrançois Tigeot intel_update_primary_plane(intel_crtc); 5388e26cdf6SFrançois Tigeot 5398e26cdf6SFrançois Tigeot I915_WRITE(SPCNTR(pipe, plane), I915_READ(SPCNTR(pipe, plane)) & 5408e26cdf6SFrançois Tigeot ~SP_ENABLE); 5418e26cdf6SFrançois Tigeot /* Activate double buffered register update */ 5429edbd4a0SFrançois Tigeot I915_WRITE(SPSURF(pipe, plane), 0); 543ba55f2f5SFrançois Tigeot 544ba55f2f5SFrançois Tigeot intel_flush_primary_plane(dev_priv, intel_crtc->plane); 545ba55f2f5SFrançois Tigeot 54624edb884SFrançois Tigeot intel_update_sprite_watermarks(dplane, crtc, 0, 0, 0, false, false); 5478e26cdf6SFrançois Tigeot } 5488e26cdf6SFrançois Tigeot 5498e26cdf6SFrançois Tigeot static int 5508e26cdf6SFrançois Tigeot vlv_update_colorkey(struct drm_plane *dplane, 5518e26cdf6SFrançois Tigeot struct drm_intel_sprite_colorkey *key) 5528e26cdf6SFrançois Tigeot { 5538e26cdf6SFrançois Tigeot struct drm_device *dev = dplane->dev; 5548e26cdf6SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 5558e26cdf6SFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(dplane); 5568e26cdf6SFrançois Tigeot int pipe = intel_plane->pipe; 5578e26cdf6SFrançois Tigeot int plane = intel_plane->plane; 5588e26cdf6SFrançois Tigeot u32 sprctl; 5598e26cdf6SFrançois Tigeot 5608e26cdf6SFrançois Tigeot if (key->flags & I915_SET_COLORKEY_DESTINATION) 5618e26cdf6SFrançois Tigeot return -EINVAL; 5628e26cdf6SFrançois Tigeot 5638e26cdf6SFrançois Tigeot I915_WRITE(SPKEYMINVAL(pipe, plane), key->min_value); 5648e26cdf6SFrançois Tigeot I915_WRITE(SPKEYMAXVAL(pipe, plane), key->max_value); 5658e26cdf6SFrançois Tigeot I915_WRITE(SPKEYMSK(pipe, plane), key->channel_mask); 5668e26cdf6SFrançois Tigeot 5678e26cdf6SFrançois Tigeot sprctl = I915_READ(SPCNTR(pipe, plane)); 5688e26cdf6SFrançois Tigeot sprctl &= ~SP_SOURCE_KEY; 5698e26cdf6SFrançois Tigeot if (key->flags & I915_SET_COLORKEY_SOURCE) 5708e26cdf6SFrançois Tigeot sprctl |= SP_SOURCE_KEY; 5718e26cdf6SFrançois Tigeot I915_WRITE(SPCNTR(pipe, plane), sprctl); 5728e26cdf6SFrançois Tigeot 5738e26cdf6SFrançois Tigeot POSTING_READ(SPKEYMSK(pipe, plane)); 5748e26cdf6SFrançois Tigeot 5758e26cdf6SFrançois Tigeot return 0; 5768e26cdf6SFrançois Tigeot } 5778e26cdf6SFrançois Tigeot 5788e26cdf6SFrançois Tigeot static void 5798e26cdf6SFrançois Tigeot vlv_get_colorkey(struct drm_plane *dplane, 5808e26cdf6SFrançois Tigeot struct drm_intel_sprite_colorkey *key) 5818e26cdf6SFrançois Tigeot { 5828e26cdf6SFrançois Tigeot struct drm_device *dev = dplane->dev; 5838e26cdf6SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 5848e26cdf6SFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(dplane); 5858e26cdf6SFrançois Tigeot int pipe = intel_plane->pipe; 5868e26cdf6SFrançois Tigeot int plane = intel_plane->plane; 5878e26cdf6SFrançois Tigeot u32 sprctl; 5888e26cdf6SFrançois Tigeot 5898e26cdf6SFrançois Tigeot key->min_value = I915_READ(SPKEYMINVAL(pipe, plane)); 5908e26cdf6SFrançois Tigeot key->max_value = I915_READ(SPKEYMAXVAL(pipe, plane)); 5918e26cdf6SFrançois Tigeot key->channel_mask = I915_READ(SPKEYMSK(pipe, plane)); 5928e26cdf6SFrançois Tigeot 5938e26cdf6SFrançois Tigeot sprctl = I915_READ(SPCNTR(pipe, plane)); 5948e26cdf6SFrançois Tigeot if (sprctl & SP_SOURCE_KEY) 5958e26cdf6SFrançois Tigeot key->flags = I915_SET_COLORKEY_SOURCE; 5968e26cdf6SFrançois Tigeot else 5978e26cdf6SFrançois Tigeot key->flags = I915_SET_COLORKEY_NONE; 5988e26cdf6SFrançois Tigeot } 5998e26cdf6SFrançois Tigeot 6008e26cdf6SFrançois Tigeot static void 6019edbd4a0SFrançois Tigeot ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, 6029edbd4a0SFrançois Tigeot struct drm_framebuffer *fb, 603e3adcf8fSFrançois Tigeot struct drm_i915_gem_object *obj, int crtc_x, int crtc_y, 604e3adcf8fSFrançois Tigeot unsigned int crtc_w, unsigned int crtc_h, 605e3adcf8fSFrançois Tigeot uint32_t x, uint32_t y, 606e3adcf8fSFrançois Tigeot uint32_t src_w, uint32_t src_h) 607e3adcf8fSFrançois Tigeot { 608e3adcf8fSFrançois Tigeot struct drm_device *dev = plane->dev; 609e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 610e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(plane); 611ba55f2f5SFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 612e3adcf8fSFrançois Tigeot int pipe = intel_plane->pipe; 613e3adcf8fSFrançois Tigeot u32 sprctl, sprscale = 0; 6142c84b0b6SFrançois Tigeot unsigned long sprsurf_offset, linear_offset; 6152c84b0b6SFrançois Tigeot int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); 616e3adcf8fSFrançois Tigeot 617e3adcf8fSFrançois Tigeot sprctl = I915_READ(SPRCTL(pipe)); 618e3adcf8fSFrançois Tigeot 619e3adcf8fSFrançois Tigeot /* Mask out pixel format bits in case we change it */ 620e3adcf8fSFrançois Tigeot sprctl &= ~SPRITE_PIXFORMAT_MASK; 621e3adcf8fSFrançois Tigeot sprctl &= ~SPRITE_RGB_ORDER_RGBX; 622e3adcf8fSFrançois Tigeot sprctl &= ~SPRITE_YUV_BYTE_ORDER_MASK; 6232c84b0b6SFrançois Tigeot sprctl &= ~SPRITE_TILED; 6241b13d190SFrançois Tigeot sprctl &= ~SPRITE_ROTATE_180; 625e3adcf8fSFrançois Tigeot 626e3adcf8fSFrançois Tigeot switch (fb->pixel_format) { 627e3adcf8fSFrançois Tigeot case DRM_FORMAT_XBGR8888: 6282c84b0b6SFrançois Tigeot sprctl |= SPRITE_FORMAT_RGBX888 | SPRITE_RGB_ORDER_RGBX; 629e3adcf8fSFrançois Tigeot break; 630e3adcf8fSFrançois Tigeot case DRM_FORMAT_XRGB8888: 6312c84b0b6SFrançois Tigeot sprctl |= SPRITE_FORMAT_RGBX888; 632e3adcf8fSFrançois Tigeot break; 633e3adcf8fSFrançois Tigeot case DRM_FORMAT_YUYV: 634e3adcf8fSFrançois Tigeot sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YUYV; 635e3adcf8fSFrançois Tigeot break; 636e3adcf8fSFrançois Tigeot case DRM_FORMAT_YVYU: 637e3adcf8fSFrançois Tigeot sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YVYU; 638e3adcf8fSFrançois Tigeot break; 639e3adcf8fSFrançois Tigeot case DRM_FORMAT_UYVY: 640e3adcf8fSFrançois Tigeot sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_UYVY; 641e3adcf8fSFrançois Tigeot break; 642e3adcf8fSFrançois Tigeot case DRM_FORMAT_VYUY: 643e3adcf8fSFrançois Tigeot sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_VYUY; 644e3adcf8fSFrançois Tigeot break; 645e3adcf8fSFrançois Tigeot default: 6462c84b0b6SFrançois Tigeot BUG(); 647e3adcf8fSFrançois Tigeot } 648e3adcf8fSFrançois Tigeot 6499edbd4a0SFrançois Tigeot /* 6509edbd4a0SFrançois Tigeot * Enable gamma to match primary/cursor plane behaviour. 6519edbd4a0SFrançois Tigeot * FIXME should be user controllable via propertiesa. 6529edbd4a0SFrançois Tigeot */ 6539edbd4a0SFrançois Tigeot sprctl |= SPRITE_GAMMA_ENABLE; 6549edbd4a0SFrançois Tigeot 655e3adcf8fSFrançois Tigeot if (obj->tiling_mode != I915_TILING_NONE) 656e3adcf8fSFrançois Tigeot sprctl |= SPRITE_TILED; 657e3adcf8fSFrançois Tigeot 6589edbd4a0SFrançois Tigeot if (IS_HASWELL(dev) || IS_BROADWELL(dev)) 6599edbd4a0SFrançois Tigeot sprctl &= ~SPRITE_TRICKLE_FEED_DISABLE; 6609edbd4a0SFrançois Tigeot else 661e3adcf8fSFrançois Tigeot sprctl |= SPRITE_TRICKLE_FEED_DISABLE; 6629edbd4a0SFrançois Tigeot 663e3adcf8fSFrançois Tigeot sprctl |= SPRITE_ENABLE; 664e3adcf8fSFrançois Tigeot 6659edbd4a0SFrançois Tigeot if (IS_HASWELL(dev) || IS_BROADWELL(dev)) 666a2fdbec6SFrançois Tigeot sprctl |= SPRITE_PIPE_CSC_ENABLE; 667a2fdbec6SFrançois Tigeot 66824edb884SFrançois Tigeot intel_update_sprite_watermarks(plane, crtc, src_w, src_h, pixel_size, 66924edb884SFrançois Tigeot true, 6709edbd4a0SFrançois Tigeot src_w != crtc_w || src_h != crtc_h); 6719edbd4a0SFrançois Tigeot 672e3adcf8fSFrançois Tigeot /* Sizes are 0 based */ 673e3adcf8fSFrançois Tigeot src_w--; 674e3adcf8fSFrançois Tigeot src_h--; 675e3adcf8fSFrançois Tigeot crtc_w--; 676e3adcf8fSFrançois Tigeot crtc_h--; 677e3adcf8fSFrançois Tigeot 6789edbd4a0SFrançois Tigeot if (crtc_w != src_w || crtc_h != src_h) 679e3adcf8fSFrançois Tigeot sprscale = SPRITE_SCALE_ENABLE | (src_w << 16) | src_h; 680e3adcf8fSFrançois Tigeot 6812c84b0b6SFrançois Tigeot linear_offset = y * fb->pitches[0] + x * pixel_size; 6822c84b0b6SFrançois Tigeot sprsurf_offset = 683df188185SFrançois Tigeot intel_gen4_compute_page_offset(&x, &y, obj->tiling_mode, 6842c84b0b6SFrançois Tigeot pixel_size, fb->pitches[0]); 6852c84b0b6SFrançois Tigeot linear_offset -= sprsurf_offset; 6862c84b0b6SFrançois Tigeot 687*2c9916cdSFrançois Tigeot if (plane->state->rotation == BIT(DRM_ROTATE_180)) { 6881b13d190SFrançois Tigeot sprctl |= SPRITE_ROTATE_180; 6891b13d190SFrançois Tigeot 6901b13d190SFrançois Tigeot /* HSW and BDW does this automagically in hardware */ 6911b13d190SFrançois Tigeot if (!IS_HASWELL(dev) && !IS_BROADWELL(dev)) { 6921b13d190SFrançois Tigeot x += src_w; 6931b13d190SFrançois Tigeot y += src_h; 6941b13d190SFrançois Tigeot linear_offset += src_h * fb->pitches[0] + 6951b13d190SFrançois Tigeot src_w * pixel_size; 6961b13d190SFrançois Tigeot } 6971b13d190SFrançois Tigeot } 6981b13d190SFrançois Tigeot 699ba55f2f5SFrançois Tigeot intel_update_primary_plane(intel_crtc); 700ba55f2f5SFrançois Tigeot 701ba55f2f5SFrançois Tigeot I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]); 702ba55f2f5SFrançois Tigeot I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x); 703ba55f2f5SFrançois Tigeot 7042c84b0b6SFrançois Tigeot /* HSW consolidates SPRTILEOFF and SPRLINOFF into a single SPROFFSET 7052c84b0b6SFrançois Tigeot * register */ 7069edbd4a0SFrançois Tigeot if (IS_HASWELL(dev) || IS_BROADWELL(dev)) 7072c84b0b6SFrançois Tigeot I915_WRITE(SPROFFSET(pipe), (y << 16) | x); 7082c84b0b6SFrançois Tigeot else if (obj->tiling_mode != I915_TILING_NONE) 7092c84b0b6SFrançois Tigeot I915_WRITE(SPRTILEOFF(pipe), (y << 16) | x); 7102c84b0b6SFrançois Tigeot else 7112c84b0b6SFrançois Tigeot I915_WRITE(SPRLINOFF(pipe), linear_offset); 7122c84b0b6SFrançois Tigeot 713e3adcf8fSFrançois Tigeot I915_WRITE(SPRSIZE(pipe), (crtc_h << 16) | crtc_w); 7142c84b0b6SFrançois Tigeot if (intel_plane->can_scale) 715e3adcf8fSFrançois Tigeot I915_WRITE(SPRSCALE(pipe), sprscale); 716e3adcf8fSFrançois Tigeot I915_WRITE(SPRCTL(pipe), sprctl); 7179edbd4a0SFrançois Tigeot I915_WRITE(SPRSURF(pipe), 7189edbd4a0SFrançois Tigeot i915_gem_obj_ggtt_offset(obj) + sprsurf_offset); 719ba55f2f5SFrançois Tigeot 720ba55f2f5SFrançois Tigeot intel_flush_primary_plane(dev_priv, intel_crtc->plane); 721e3adcf8fSFrançois Tigeot } 722e3adcf8fSFrançois Tigeot 723e3adcf8fSFrançois Tigeot static void 7249edbd4a0SFrançois Tigeot ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc) 725e3adcf8fSFrançois Tigeot { 726e3adcf8fSFrançois Tigeot struct drm_device *dev = plane->dev; 727e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 728e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(plane); 729ba55f2f5SFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 730e3adcf8fSFrançois Tigeot int pipe = intel_plane->pipe; 731ba55f2f5SFrançois Tigeot 732ba55f2f5SFrançois Tigeot intel_update_primary_plane(intel_crtc); 733e3adcf8fSFrançois Tigeot 734e3adcf8fSFrançois Tigeot I915_WRITE(SPRCTL(pipe), I915_READ(SPRCTL(pipe)) & ~SPRITE_ENABLE); 735e3adcf8fSFrançois Tigeot /* Can't leave the scaler enabled... */ 7362c84b0b6SFrançois Tigeot if (intel_plane->can_scale) 737e3adcf8fSFrançois Tigeot I915_WRITE(SPRSCALE(pipe), 0); 738e3adcf8fSFrançois Tigeot /* Activate double buffered register update */ 7399edbd4a0SFrançois Tigeot I915_WRITE(SPRSURF(pipe), 0); 740ba55f2f5SFrançois Tigeot 741ba55f2f5SFrançois Tigeot intel_flush_primary_plane(dev_priv, intel_crtc->plane); 742ba55f2f5SFrançois Tigeot 7439edbd4a0SFrançois Tigeot /* 7449edbd4a0SFrançois Tigeot * Avoid underruns when disabling the sprite. 7459edbd4a0SFrançois Tigeot * FIXME remove once watermark updates are done properly. 7469edbd4a0SFrançois Tigeot */ 747*2c9916cdSFrançois Tigeot intel_crtc->atomic.wait_vblank = true; 748*2c9916cdSFrançois Tigeot intel_crtc->atomic.update_sprite_watermarks |= (1 << drm_plane_index(plane)); 749e3adcf8fSFrançois Tigeot } 750e3adcf8fSFrançois Tigeot 751e3adcf8fSFrançois Tigeot static int 752e3adcf8fSFrançois Tigeot ivb_update_colorkey(struct drm_plane *plane, 753e3adcf8fSFrançois Tigeot struct drm_intel_sprite_colorkey *key) 754e3adcf8fSFrançois Tigeot { 755e3adcf8fSFrançois Tigeot struct drm_device *dev = plane->dev; 756e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 757e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane; 758e3adcf8fSFrançois Tigeot u32 sprctl; 759e3adcf8fSFrançois Tigeot int ret = 0; 760e3adcf8fSFrançois Tigeot 761e3adcf8fSFrançois Tigeot intel_plane = to_intel_plane(plane); 762e3adcf8fSFrançois Tigeot 763e3adcf8fSFrançois Tigeot I915_WRITE(SPRKEYVAL(intel_plane->pipe), key->min_value); 764e3adcf8fSFrançois Tigeot I915_WRITE(SPRKEYMAX(intel_plane->pipe), key->max_value); 765e3adcf8fSFrançois Tigeot I915_WRITE(SPRKEYMSK(intel_plane->pipe), key->channel_mask); 766e3adcf8fSFrançois Tigeot 767e3adcf8fSFrançois Tigeot sprctl = I915_READ(SPRCTL(intel_plane->pipe)); 768e3adcf8fSFrançois Tigeot sprctl &= ~(SPRITE_SOURCE_KEY | SPRITE_DEST_KEY); 769e3adcf8fSFrançois Tigeot if (key->flags & I915_SET_COLORKEY_DESTINATION) 770e3adcf8fSFrançois Tigeot sprctl |= SPRITE_DEST_KEY; 771e3adcf8fSFrançois Tigeot else if (key->flags & I915_SET_COLORKEY_SOURCE) 772e3adcf8fSFrançois Tigeot sprctl |= SPRITE_SOURCE_KEY; 773e3adcf8fSFrançois Tigeot I915_WRITE(SPRCTL(intel_plane->pipe), sprctl); 774e3adcf8fSFrançois Tigeot 775e3adcf8fSFrançois Tigeot POSTING_READ(SPRKEYMSK(intel_plane->pipe)); 776e3adcf8fSFrançois Tigeot 777e3adcf8fSFrançois Tigeot return ret; 778e3adcf8fSFrançois Tigeot } 779e3adcf8fSFrançois Tigeot 780e3adcf8fSFrançois Tigeot static void 781e3adcf8fSFrançois Tigeot ivb_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key) 782e3adcf8fSFrançois Tigeot { 783e3adcf8fSFrançois Tigeot struct drm_device *dev = plane->dev; 784e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 785e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane; 786e3adcf8fSFrançois Tigeot u32 sprctl; 787e3adcf8fSFrançois Tigeot 788e3adcf8fSFrançois Tigeot intel_plane = to_intel_plane(plane); 789e3adcf8fSFrançois Tigeot 790e3adcf8fSFrançois Tigeot key->min_value = I915_READ(SPRKEYVAL(intel_plane->pipe)); 791e3adcf8fSFrançois Tigeot key->max_value = I915_READ(SPRKEYMAX(intel_plane->pipe)); 792e3adcf8fSFrançois Tigeot key->channel_mask = I915_READ(SPRKEYMSK(intel_plane->pipe)); 793e3adcf8fSFrançois Tigeot key->flags = 0; 794e3adcf8fSFrançois Tigeot 795e3adcf8fSFrançois Tigeot sprctl = I915_READ(SPRCTL(intel_plane->pipe)); 796e3adcf8fSFrançois Tigeot 797e3adcf8fSFrançois Tigeot if (sprctl & SPRITE_DEST_KEY) 798e3adcf8fSFrançois Tigeot key->flags = I915_SET_COLORKEY_DESTINATION; 799e3adcf8fSFrançois Tigeot else if (sprctl & SPRITE_SOURCE_KEY) 800e3adcf8fSFrançois Tigeot key->flags = I915_SET_COLORKEY_SOURCE; 801e3adcf8fSFrançois Tigeot else 802e3adcf8fSFrançois Tigeot key->flags = I915_SET_COLORKEY_NONE; 803e3adcf8fSFrançois Tigeot } 804e3adcf8fSFrançois Tigeot 805e3adcf8fSFrançois Tigeot static void 8069edbd4a0SFrançois Tigeot ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, 8079edbd4a0SFrançois Tigeot struct drm_framebuffer *fb, 808e3adcf8fSFrançois Tigeot struct drm_i915_gem_object *obj, int crtc_x, int crtc_y, 809e3adcf8fSFrançois Tigeot unsigned int crtc_w, unsigned int crtc_h, 810e3adcf8fSFrançois Tigeot uint32_t x, uint32_t y, 811e3adcf8fSFrançois Tigeot uint32_t src_w, uint32_t src_h) 812e3adcf8fSFrançois Tigeot { 813e3adcf8fSFrançois Tigeot struct drm_device *dev = plane->dev; 814e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 815e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(plane); 816ba55f2f5SFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 8172c84b0b6SFrançois Tigeot int pipe = intel_plane->pipe; 8182c84b0b6SFrançois Tigeot unsigned long dvssurf_offset, linear_offset; 8192c84b0b6SFrançois Tigeot u32 dvscntr, dvsscale; 8202c84b0b6SFrançois Tigeot int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); 821e3adcf8fSFrançois Tigeot 822e3adcf8fSFrançois Tigeot dvscntr = I915_READ(DVSCNTR(pipe)); 823e3adcf8fSFrançois Tigeot 824e3adcf8fSFrançois Tigeot /* Mask out pixel format bits in case we change it */ 825e3adcf8fSFrançois Tigeot dvscntr &= ~DVS_PIXFORMAT_MASK; 826e3adcf8fSFrançois Tigeot dvscntr &= ~DVS_RGB_ORDER_XBGR; 827e3adcf8fSFrançois Tigeot dvscntr &= ~DVS_YUV_BYTE_ORDER_MASK; 8282c84b0b6SFrançois Tigeot dvscntr &= ~DVS_TILED; 8291b13d190SFrançois Tigeot dvscntr &= ~DVS_ROTATE_180; 830e3adcf8fSFrançois Tigeot 831e3adcf8fSFrançois Tigeot switch (fb->pixel_format) { 832e3adcf8fSFrançois Tigeot case DRM_FORMAT_XBGR8888: 833e3adcf8fSFrançois Tigeot dvscntr |= DVS_FORMAT_RGBX888 | DVS_RGB_ORDER_XBGR; 834e3adcf8fSFrançois Tigeot break; 835e3adcf8fSFrançois Tigeot case DRM_FORMAT_XRGB8888: 836e3adcf8fSFrançois Tigeot dvscntr |= DVS_FORMAT_RGBX888; 837e3adcf8fSFrançois Tigeot break; 838e3adcf8fSFrançois Tigeot case DRM_FORMAT_YUYV: 839e3adcf8fSFrançois Tigeot dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YUYV; 840e3adcf8fSFrançois Tigeot break; 841e3adcf8fSFrançois Tigeot case DRM_FORMAT_YVYU: 842e3adcf8fSFrançois Tigeot dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YVYU; 843e3adcf8fSFrançois Tigeot break; 844e3adcf8fSFrançois Tigeot case DRM_FORMAT_UYVY: 845e3adcf8fSFrançois Tigeot dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_UYVY; 846e3adcf8fSFrançois Tigeot break; 847e3adcf8fSFrançois Tigeot case DRM_FORMAT_VYUY: 848e3adcf8fSFrançois Tigeot dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_VYUY; 849e3adcf8fSFrançois Tigeot break; 850e3adcf8fSFrançois Tigeot default: 8512c84b0b6SFrançois Tigeot BUG(); 852e3adcf8fSFrançois Tigeot } 853e3adcf8fSFrançois Tigeot 8549edbd4a0SFrançois Tigeot /* 8559edbd4a0SFrançois Tigeot * Enable gamma to match primary/cursor plane behaviour. 8569edbd4a0SFrançois Tigeot * FIXME should be user controllable via propertiesa. 8579edbd4a0SFrançois Tigeot */ 8589edbd4a0SFrançois Tigeot dvscntr |= DVS_GAMMA_ENABLE; 8599edbd4a0SFrançois Tigeot 860e3adcf8fSFrançois Tigeot if (obj->tiling_mode != I915_TILING_NONE) 861e3adcf8fSFrançois Tigeot dvscntr |= DVS_TILED; 862e3adcf8fSFrançois Tigeot 8632c84b0b6SFrançois Tigeot if (IS_GEN6(dev)) 8642c84b0b6SFrançois Tigeot dvscntr |= DVS_TRICKLE_FEED_DISABLE; /* must disable */ 865e3adcf8fSFrançois Tigeot dvscntr |= DVS_ENABLE; 866e3adcf8fSFrançois Tigeot 86724edb884SFrançois Tigeot intel_update_sprite_watermarks(plane, crtc, src_w, src_h, 86824edb884SFrançois Tigeot pixel_size, true, 8699edbd4a0SFrançois Tigeot src_w != crtc_w || src_h != crtc_h); 8709edbd4a0SFrançois Tigeot 871e3adcf8fSFrançois Tigeot /* Sizes are 0 based */ 872e3adcf8fSFrançois Tigeot src_w--; 873e3adcf8fSFrançois Tigeot src_h--; 874e3adcf8fSFrançois Tigeot crtc_w--; 875e3adcf8fSFrançois Tigeot crtc_h--; 876e3adcf8fSFrançois Tigeot 8772c84b0b6SFrançois Tigeot dvsscale = 0; 8789edbd4a0SFrançois Tigeot if (crtc_w != src_w || crtc_h != src_h) 879e3adcf8fSFrançois Tigeot dvsscale = DVS_SCALE_ENABLE | (src_w << 16) | src_h; 880e3adcf8fSFrançois Tigeot 8812c84b0b6SFrançois Tigeot linear_offset = y * fb->pitches[0] + x * pixel_size; 8822c84b0b6SFrançois Tigeot dvssurf_offset = 883df188185SFrançois Tigeot intel_gen4_compute_page_offset(&x, &y, obj->tiling_mode, 8842c84b0b6SFrançois Tigeot pixel_size, fb->pitches[0]); 8852c84b0b6SFrançois Tigeot linear_offset -= dvssurf_offset; 8862c84b0b6SFrançois Tigeot 887*2c9916cdSFrançois Tigeot if (plane->state->rotation == BIT(DRM_ROTATE_180)) { 8881b13d190SFrançois Tigeot dvscntr |= DVS_ROTATE_180; 8891b13d190SFrançois Tigeot 8901b13d190SFrançois Tigeot x += src_w; 8911b13d190SFrançois Tigeot y += src_h; 8921b13d190SFrançois Tigeot linear_offset += src_h * fb->pitches[0] + src_w * pixel_size; 8931b13d190SFrançois Tigeot } 8941b13d190SFrançois Tigeot 895ba55f2f5SFrançois Tigeot intel_update_primary_plane(intel_crtc); 896ba55f2f5SFrançois Tigeot 897ba55f2f5SFrançois Tigeot I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]); 898ba55f2f5SFrançois Tigeot I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x); 899ba55f2f5SFrançois Tigeot 9002c84b0b6SFrançois Tigeot if (obj->tiling_mode != I915_TILING_NONE) 9012c84b0b6SFrançois Tigeot I915_WRITE(DVSTILEOFF(pipe), (y << 16) | x); 9022c84b0b6SFrançois Tigeot else 9032c84b0b6SFrançois Tigeot I915_WRITE(DVSLINOFF(pipe), linear_offset); 9042c84b0b6SFrançois Tigeot 905e3adcf8fSFrançois Tigeot I915_WRITE(DVSSIZE(pipe), (crtc_h << 16) | crtc_w); 906e3adcf8fSFrançois Tigeot I915_WRITE(DVSSCALE(pipe), dvsscale); 907e3adcf8fSFrançois Tigeot I915_WRITE(DVSCNTR(pipe), dvscntr); 9089edbd4a0SFrançois Tigeot I915_WRITE(DVSSURF(pipe), 9099edbd4a0SFrançois Tigeot i915_gem_obj_ggtt_offset(obj) + dvssurf_offset); 910ba55f2f5SFrançois Tigeot 911ba55f2f5SFrançois Tigeot intel_flush_primary_plane(dev_priv, intel_crtc->plane); 912e3adcf8fSFrançois Tigeot } 913e3adcf8fSFrançois Tigeot 914e3adcf8fSFrançois Tigeot static void 9159edbd4a0SFrançois Tigeot ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc) 916e3adcf8fSFrançois Tigeot { 917e3adcf8fSFrançois Tigeot struct drm_device *dev = plane->dev; 918e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 919e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(plane); 920ba55f2f5SFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 921e3adcf8fSFrançois Tigeot int pipe = intel_plane->pipe; 922ba55f2f5SFrançois Tigeot 923ba55f2f5SFrançois Tigeot intel_update_primary_plane(intel_crtc); 924e3adcf8fSFrançois Tigeot 925e3adcf8fSFrançois Tigeot I915_WRITE(DVSCNTR(pipe), I915_READ(DVSCNTR(pipe)) & ~DVS_ENABLE); 926e3adcf8fSFrançois Tigeot /* Disable the scaler */ 927e3adcf8fSFrançois Tigeot I915_WRITE(DVSSCALE(pipe), 0); 928e3adcf8fSFrançois Tigeot /* Flush double buffered register updates */ 9299edbd4a0SFrançois Tigeot I915_WRITE(DVSSURF(pipe), 0); 930ba55f2f5SFrançois Tigeot 931ba55f2f5SFrançois Tigeot intel_flush_primary_plane(dev_priv, intel_crtc->plane); 932ba55f2f5SFrançois Tigeot 9339edbd4a0SFrançois Tigeot /* 9349edbd4a0SFrançois Tigeot * Avoid underruns when disabling the sprite. 9359edbd4a0SFrançois Tigeot * FIXME remove once watermark updates are done properly. 9369edbd4a0SFrançois Tigeot */ 937*2c9916cdSFrançois Tigeot intel_crtc->atomic.wait_vblank = true; 938*2c9916cdSFrançois Tigeot intel_crtc->atomic.update_sprite_watermarks |= (1 << drm_plane_index(plane)); 939e3adcf8fSFrançois Tigeot } 940e3adcf8fSFrançois Tigeot 941*2c9916cdSFrançois Tigeot /** 942*2c9916cdSFrançois Tigeot * intel_post_enable_primary - Perform operations after enabling primary plane 943*2c9916cdSFrançois Tigeot * @crtc: the CRTC whose primary plane was just enabled 944*2c9916cdSFrançois Tigeot * 945*2c9916cdSFrançois Tigeot * Performs potentially sleeping operations that must be done after the primary 946*2c9916cdSFrançois Tigeot * plane is enabled, such as updating FBC and IPS. Note that this may be 947*2c9916cdSFrançois Tigeot * called due to an explicit primary plane update, or due to an implicit 948*2c9916cdSFrançois Tigeot * re-enable that is caused when a sprite plane is updated to no longer 949*2c9916cdSFrançois Tigeot * completely hide the primary plane. 950*2c9916cdSFrançois Tigeot */ 951*2c9916cdSFrançois Tigeot void 952ba55f2f5SFrançois Tigeot intel_post_enable_primary(struct drm_crtc *crtc) 953e3adcf8fSFrançois Tigeot { 954e3adcf8fSFrançois Tigeot struct drm_device *dev = crtc->dev; 955e3adcf8fSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 956e3adcf8fSFrançois Tigeot 957ba55f2f5SFrançois Tigeot /* 958ba55f2f5SFrançois Tigeot * BDW signals flip done immediately if the plane 959ba55f2f5SFrançois Tigeot * is disabled, even if the plane enable is already 960ba55f2f5SFrançois Tigeot * armed to occur at the next vblank :( 961ba55f2f5SFrançois Tigeot */ 962ba55f2f5SFrançois Tigeot if (IS_BROADWELL(dev)) 963ba55f2f5SFrançois Tigeot intel_wait_for_vblank(dev, intel_crtc->pipe); 9649edbd4a0SFrançois Tigeot 9659edbd4a0SFrançois Tigeot /* 9669edbd4a0SFrançois Tigeot * FIXME IPS should be fine as long as one plane is 9679edbd4a0SFrançois Tigeot * enabled, but in practice it seems to have problems 9689edbd4a0SFrançois Tigeot * when going from primary only to sprite only and vice 9699edbd4a0SFrançois Tigeot * versa. 9709edbd4a0SFrançois Tigeot */ 9719edbd4a0SFrançois Tigeot hsw_enable_ips(intel_crtc); 9729edbd4a0SFrançois Tigeot 9739edbd4a0SFrançois Tigeot mutex_lock(&dev->struct_mutex); 974*2c9916cdSFrançois Tigeot intel_fbc_update(dev); 9759edbd4a0SFrançois Tigeot mutex_unlock(&dev->struct_mutex); 976e3adcf8fSFrançois Tigeot } 977e3adcf8fSFrançois Tigeot 978*2c9916cdSFrançois Tigeot /** 979*2c9916cdSFrançois Tigeot * intel_pre_disable_primary - Perform operations before disabling primary plane 980*2c9916cdSFrançois Tigeot * @crtc: the CRTC whose primary plane is to be disabled 981*2c9916cdSFrançois Tigeot * 982*2c9916cdSFrançois Tigeot * Performs potentially sleeping operations that must be done before the 983*2c9916cdSFrançois Tigeot * primary plane is enabled, such as updating FBC and IPS. Note that this may 984*2c9916cdSFrançois Tigeot * be called due to an explicit primary plane update, or due to an implicit 985*2c9916cdSFrançois Tigeot * disable that is caused when a sprite plane completely hides the primary 986*2c9916cdSFrançois Tigeot * plane. 987*2c9916cdSFrançois Tigeot */ 988*2c9916cdSFrançois Tigeot void 989ba55f2f5SFrançois Tigeot intel_pre_disable_primary(struct drm_crtc *crtc) 990e3adcf8fSFrançois Tigeot { 991e3adcf8fSFrançois Tigeot struct drm_device *dev = crtc->dev; 992e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 993e3adcf8fSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 9942c84b0b6SFrançois Tigeot 9959edbd4a0SFrançois Tigeot mutex_lock(&dev->struct_mutex); 9969edbd4a0SFrançois Tigeot if (dev_priv->fbc.plane == intel_crtc->plane) 997*2c9916cdSFrançois Tigeot intel_fbc_disable(dev); 9989edbd4a0SFrançois Tigeot mutex_unlock(&dev->struct_mutex); 9999edbd4a0SFrançois Tigeot 10009edbd4a0SFrançois Tigeot /* 10019edbd4a0SFrançois Tigeot * FIXME IPS should be fine as long as one plane is 10029edbd4a0SFrançois Tigeot * enabled, but in practice it seems to have problems 10039edbd4a0SFrançois Tigeot * when going from primary only to sprite only and vice 10049edbd4a0SFrançois Tigeot * versa. 10059edbd4a0SFrançois Tigeot */ 10069edbd4a0SFrançois Tigeot hsw_disable_ips(intel_crtc); 1007e3adcf8fSFrançois Tigeot } 1008e3adcf8fSFrançois Tigeot 1009e3adcf8fSFrançois Tigeot static int 10102c84b0b6SFrançois Tigeot ilk_update_colorkey(struct drm_plane *plane, 1011e3adcf8fSFrançois Tigeot struct drm_intel_sprite_colorkey *key) 1012e3adcf8fSFrançois Tigeot { 1013e3adcf8fSFrançois Tigeot struct drm_device *dev = plane->dev; 1014e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 1015e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane; 1016e3adcf8fSFrançois Tigeot u32 dvscntr; 1017e3adcf8fSFrançois Tigeot int ret = 0; 1018e3adcf8fSFrançois Tigeot 1019e3adcf8fSFrançois Tigeot intel_plane = to_intel_plane(plane); 1020e3adcf8fSFrançois Tigeot 1021e3adcf8fSFrançois Tigeot I915_WRITE(DVSKEYVAL(intel_plane->pipe), key->min_value); 1022e3adcf8fSFrançois Tigeot I915_WRITE(DVSKEYMAX(intel_plane->pipe), key->max_value); 1023e3adcf8fSFrançois Tigeot I915_WRITE(DVSKEYMSK(intel_plane->pipe), key->channel_mask); 1024e3adcf8fSFrançois Tigeot 1025e3adcf8fSFrançois Tigeot dvscntr = I915_READ(DVSCNTR(intel_plane->pipe)); 1026e3adcf8fSFrançois Tigeot dvscntr &= ~(DVS_SOURCE_KEY | DVS_DEST_KEY); 1027e3adcf8fSFrançois Tigeot if (key->flags & I915_SET_COLORKEY_DESTINATION) 1028e3adcf8fSFrançois Tigeot dvscntr |= DVS_DEST_KEY; 1029e3adcf8fSFrançois Tigeot else if (key->flags & I915_SET_COLORKEY_SOURCE) 1030e3adcf8fSFrançois Tigeot dvscntr |= DVS_SOURCE_KEY; 1031e3adcf8fSFrançois Tigeot I915_WRITE(DVSCNTR(intel_plane->pipe), dvscntr); 1032e3adcf8fSFrançois Tigeot 1033e3adcf8fSFrançois Tigeot POSTING_READ(DVSKEYMSK(intel_plane->pipe)); 1034e3adcf8fSFrançois Tigeot 1035e3adcf8fSFrançois Tigeot return ret; 1036e3adcf8fSFrançois Tigeot } 1037e3adcf8fSFrançois Tigeot 1038e3adcf8fSFrançois Tigeot static void 10392c84b0b6SFrançois Tigeot ilk_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key) 1040e3adcf8fSFrançois Tigeot { 1041e3adcf8fSFrançois Tigeot struct drm_device *dev = plane->dev; 1042e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 1043e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane; 1044e3adcf8fSFrançois Tigeot u32 dvscntr; 1045e3adcf8fSFrançois Tigeot 1046e3adcf8fSFrançois Tigeot intel_plane = to_intel_plane(plane); 1047e3adcf8fSFrançois Tigeot 1048e3adcf8fSFrançois Tigeot key->min_value = I915_READ(DVSKEYVAL(intel_plane->pipe)); 1049e3adcf8fSFrançois Tigeot key->max_value = I915_READ(DVSKEYMAX(intel_plane->pipe)); 1050e3adcf8fSFrançois Tigeot key->channel_mask = I915_READ(DVSKEYMSK(intel_plane->pipe)); 1051e3adcf8fSFrançois Tigeot key->flags = 0; 1052e3adcf8fSFrançois Tigeot 1053e3adcf8fSFrançois Tigeot dvscntr = I915_READ(DVSCNTR(intel_plane->pipe)); 1054e3adcf8fSFrançois Tigeot 1055e3adcf8fSFrançois Tigeot if (dvscntr & DVS_DEST_KEY) 1056e3adcf8fSFrançois Tigeot key->flags = I915_SET_COLORKEY_DESTINATION; 1057e3adcf8fSFrançois Tigeot else if (dvscntr & DVS_SOURCE_KEY) 1058e3adcf8fSFrançois Tigeot key->flags = I915_SET_COLORKEY_SOURCE; 1059e3adcf8fSFrançois Tigeot else 1060e3adcf8fSFrançois Tigeot key->flags = I915_SET_COLORKEY_NONE; 1061e3adcf8fSFrançois Tigeot } 1062e3adcf8fSFrançois Tigeot 10639edbd4a0SFrançois Tigeot static bool colorkey_enabled(struct intel_plane *intel_plane) 10649edbd4a0SFrançois Tigeot { 10659edbd4a0SFrançois Tigeot struct drm_intel_sprite_colorkey key; 10669edbd4a0SFrançois Tigeot 10679edbd4a0SFrançois Tigeot intel_plane->get_colorkey(&intel_plane->base, &key); 10689edbd4a0SFrançois Tigeot 10699edbd4a0SFrançois Tigeot return key.flags != I915_SET_COLORKEY_NONE; 10709edbd4a0SFrançois Tigeot } 10719edbd4a0SFrançois Tigeot 1072e3adcf8fSFrançois Tigeot static int 1073*2c9916cdSFrançois Tigeot intel_check_sprite_plane(struct drm_plane *plane, 1074*2c9916cdSFrançois Tigeot struct intel_plane_state *state) 1075e3adcf8fSFrançois Tigeot { 1076*2c9916cdSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(state->base.crtc); 1077e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(plane); 1078*2c9916cdSFrançois Tigeot struct drm_framebuffer *fb = state->base.fb; 1079*2c9916cdSFrançois Tigeot struct drm_i915_gem_object *obj = intel_fb_obj(fb); 10809edbd4a0SFrançois Tigeot int crtc_x, crtc_y; 10819edbd4a0SFrançois Tigeot unsigned int crtc_w, crtc_h; 10829edbd4a0SFrançois Tigeot uint32_t src_x, src_y, src_w, src_h; 1083*2c9916cdSFrançois Tigeot struct drm_rect *src = &state->src; 1084*2c9916cdSFrançois Tigeot struct drm_rect *dst = &state->dst; 1085*2c9916cdSFrançois Tigeot const struct drm_rect *clip = &state->clip; 1086*2c9916cdSFrançois Tigeot int hscale, vscale; 1087*2c9916cdSFrançois Tigeot int max_scale, min_scale; 1088*2c9916cdSFrançois Tigeot int pixel_size; 1089*2c9916cdSFrançois Tigeot 1090*2c9916cdSFrançois Tigeot intel_crtc = intel_crtc ? intel_crtc : to_intel_crtc(plane->crtc); 1091*2c9916cdSFrançois Tigeot 1092*2c9916cdSFrançois Tigeot if (!fb) { 1093*2c9916cdSFrançois Tigeot state->visible = false; 1094*2c9916cdSFrançois Tigeot goto finish; 1095*2c9916cdSFrançois Tigeot } 1096e3adcf8fSFrançois Tigeot 1097e3adcf8fSFrançois Tigeot /* Don't modify another pipe's plane */ 10985d0b1887SFrançois Tigeot if (intel_plane->pipe != intel_crtc->pipe) { 10995d0b1887SFrançois Tigeot DRM_DEBUG_KMS("Wrong plane <-> crtc mapping\n"); 1100e3adcf8fSFrançois Tigeot return -EINVAL; 11015d0b1887SFrançois Tigeot } 11025d0b1887SFrançois Tigeot 11035d0b1887SFrançois Tigeot /* FIXME check all gen limits */ 11045d0b1887SFrançois Tigeot if (fb->width < 3 || fb->height < 3 || fb->pitches[0] > 16384) { 11055d0b1887SFrançois Tigeot DRM_DEBUG_KMS("Unsuitable framebuffer for plane\n"); 11065d0b1887SFrançois Tigeot return -EINVAL; 11075d0b1887SFrançois Tigeot } 1108e3adcf8fSFrançois Tigeot 11092c84b0b6SFrançois Tigeot /* Sprite planes can be linear or x-tiled surfaces */ 11102c84b0b6SFrançois Tigeot switch (obj->tiling_mode) { 11112c84b0b6SFrançois Tigeot case I915_TILING_NONE: 11122c84b0b6SFrançois Tigeot case I915_TILING_X: 11132c84b0b6SFrançois Tigeot break; 11142c84b0b6SFrançois Tigeot default: 11155d0b1887SFrançois Tigeot DRM_DEBUG_KMS("Unsupported tiling mode\n"); 11162c84b0b6SFrançois Tigeot return -EINVAL; 11172c84b0b6SFrançois Tigeot } 11182c84b0b6SFrançois Tigeot 1119e3adcf8fSFrançois Tigeot /* 11205d0b1887SFrançois Tigeot * FIXME the following code does a bunch of fuzzy adjustments to the 11215d0b1887SFrançois Tigeot * coordinates and sizes. We probably need some way to decide whether 11225d0b1887SFrançois Tigeot * more strict checking should be done instead. 1123e3adcf8fSFrançois Tigeot */ 11245d0b1887SFrançois Tigeot max_scale = intel_plane->max_downscale << 16; 11255d0b1887SFrançois Tigeot min_scale = intel_plane->can_scale ? 1 : (1 << 16); 1126e3adcf8fSFrançois Tigeot 1127*2c9916cdSFrançois Tigeot drm_rect_rotate(src, fb->width << 16, fb->height << 16, 1128*2c9916cdSFrançois Tigeot state->base.rotation); 11291b13d190SFrançois Tigeot 1130*2c9916cdSFrançois Tigeot hscale = drm_rect_calc_hscale_relaxed(src, dst, min_scale, max_scale); 11315d0b1887SFrançois Tigeot BUG_ON(hscale < 0); 1132e3adcf8fSFrançois Tigeot 1133*2c9916cdSFrançois Tigeot vscale = drm_rect_calc_vscale_relaxed(src, dst, min_scale, max_scale); 11345d0b1887SFrançois Tigeot BUG_ON(vscale < 0); 11355d0b1887SFrançois Tigeot 1136*2c9916cdSFrançois Tigeot state->visible = drm_rect_clip_scaled(src, dst, clip, hscale, vscale); 11375d0b1887SFrançois Tigeot 1138*2c9916cdSFrançois Tigeot crtc_x = dst->x1; 1139*2c9916cdSFrançois Tigeot crtc_y = dst->y1; 1140*2c9916cdSFrançois Tigeot crtc_w = drm_rect_width(dst); 1141*2c9916cdSFrançois Tigeot crtc_h = drm_rect_height(dst); 11425d0b1887SFrançois Tigeot 1143*2c9916cdSFrançois Tigeot if (state->visible) { 11445d0b1887SFrançois Tigeot /* check again in case clipping clamped the results */ 1145*2c9916cdSFrançois Tigeot hscale = drm_rect_calc_hscale(src, dst, min_scale, max_scale); 11465d0b1887SFrançois Tigeot if (hscale < 0) { 11475d0b1887SFrançois Tigeot DRM_DEBUG_KMS("Horizontal scaling factor out of limits\n"); 1148*2c9916cdSFrançois Tigeot drm_rect_debug_print(src, true); 1149*2c9916cdSFrançois Tigeot drm_rect_debug_print(dst, false); 11505d0b1887SFrançois Tigeot 11515d0b1887SFrançois Tigeot return hscale; 11525d0b1887SFrançois Tigeot } 11535d0b1887SFrançois Tigeot 1154*2c9916cdSFrançois Tigeot vscale = drm_rect_calc_vscale(src, dst, min_scale, max_scale); 11555d0b1887SFrançois Tigeot if (vscale < 0) { 11565d0b1887SFrançois Tigeot DRM_DEBUG_KMS("Vertical scaling factor out of limits\n"); 1157*2c9916cdSFrançois Tigeot drm_rect_debug_print(src, true); 1158*2c9916cdSFrançois Tigeot drm_rect_debug_print(dst, false); 11595d0b1887SFrançois Tigeot 11605d0b1887SFrançois Tigeot return vscale; 11615d0b1887SFrançois Tigeot } 11625d0b1887SFrançois Tigeot 11635d0b1887SFrançois Tigeot /* Make the source viewport size an exact multiple of the scaling factors. */ 1164*2c9916cdSFrançois Tigeot drm_rect_adjust_size(src, 1165*2c9916cdSFrançois Tigeot drm_rect_width(dst) * hscale - drm_rect_width(src), 1166*2c9916cdSFrançois Tigeot drm_rect_height(dst) * vscale - drm_rect_height(src)); 11675d0b1887SFrançois Tigeot 1168*2c9916cdSFrançois Tigeot drm_rect_rotate_inv(src, fb->width << 16, fb->height << 16, 1169*2c9916cdSFrançois Tigeot state->base.rotation); 11701b13d190SFrançois Tigeot 11715d0b1887SFrançois Tigeot /* sanity check to make sure the src viewport wasn't enlarged */ 1172*2c9916cdSFrançois Tigeot WARN_ON(src->x1 < (int) state->base.src_x || 1173*2c9916cdSFrançois Tigeot src->y1 < (int) state->base.src_y || 1174*2c9916cdSFrançois Tigeot src->x2 > (int) state->base.src_x + state->base.src_w || 1175*2c9916cdSFrançois Tigeot src->y2 > (int) state->base.src_y + state->base.src_h); 1176e3adcf8fSFrançois Tigeot 1177e3adcf8fSFrançois Tigeot /* 11785d0b1887SFrançois Tigeot * Hardware doesn't handle subpixel coordinates. 11795d0b1887SFrançois Tigeot * Adjust to (macro)pixel boundary, but be careful not to 11805d0b1887SFrançois Tigeot * increase the source viewport size, because that could 11815d0b1887SFrançois Tigeot * push the downscaling factor out of bounds. 11822c84b0b6SFrançois Tigeot */ 1183*2c9916cdSFrançois Tigeot src_x = src->x1 >> 16; 1184*2c9916cdSFrançois Tigeot src_w = drm_rect_width(src) >> 16; 1185*2c9916cdSFrançois Tigeot src_y = src->y1 >> 16; 1186*2c9916cdSFrançois Tigeot src_h = drm_rect_height(src) >> 16; 11875d0b1887SFrançois Tigeot 11885d0b1887SFrançois Tigeot if (format_is_yuv(fb->pixel_format)) { 11895d0b1887SFrançois Tigeot src_x &= ~1; 11905d0b1887SFrançois Tigeot src_w &= ~1; 11912c84b0b6SFrançois Tigeot 11922c84b0b6SFrançois Tigeot /* 11935d0b1887SFrançois Tigeot * Must keep src and dst the 11945d0b1887SFrançois Tigeot * same if we can't scale. 1195e3adcf8fSFrançois Tigeot */ 11965d0b1887SFrançois Tigeot if (!intel_plane->can_scale) 11975d0b1887SFrançois Tigeot crtc_w &= ~1; 11985d0b1887SFrançois Tigeot 11995d0b1887SFrançois Tigeot if (crtc_w == 0) 1200*2c9916cdSFrançois Tigeot state->visible = false; 12015d0b1887SFrançois Tigeot } 12025d0b1887SFrançois Tigeot } 12035d0b1887SFrançois Tigeot 12045d0b1887SFrançois Tigeot /* Check size restrictions when scaling */ 1205*2c9916cdSFrançois Tigeot if (state->visible && (src_w != crtc_w || src_h != crtc_h)) { 12065d0b1887SFrançois Tigeot unsigned int width_bytes; 12075d0b1887SFrançois Tigeot 12085d0b1887SFrançois Tigeot WARN_ON(!intel_plane->can_scale); 12095d0b1887SFrançois Tigeot 12105d0b1887SFrançois Tigeot /* FIXME interlacing min height is 6 */ 12115d0b1887SFrançois Tigeot 12125d0b1887SFrançois Tigeot if (crtc_w < 3 || crtc_h < 3) 1213*2c9916cdSFrançois Tigeot state->visible = false; 12145d0b1887SFrançois Tigeot 12155d0b1887SFrançois Tigeot if (src_w < 3 || src_h < 3) 1216*2c9916cdSFrançois Tigeot state->visible = false; 12175d0b1887SFrançois Tigeot 1218*2c9916cdSFrançois Tigeot pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); 1219*2c9916cdSFrançois Tigeot width_bytes = ((src_x * pixel_size) & 63) + 1220*2c9916cdSFrançois Tigeot src_w * pixel_size; 12215d0b1887SFrançois Tigeot 12225d0b1887SFrançois Tigeot if (src_w > 2048 || src_h > 2048 || 12235d0b1887SFrançois Tigeot width_bytes > 4096 || fb->pitches[0] > 4096) { 12245d0b1887SFrançois Tigeot DRM_DEBUG_KMS("Source dimensions exceed hardware limits\n"); 1225e3adcf8fSFrançois Tigeot return -EINVAL; 12265d0b1887SFrançois Tigeot } 12275d0b1887SFrançois Tigeot } 12285d0b1887SFrançois Tigeot 1229*2c9916cdSFrançois Tigeot if (state->visible) { 1230*2c9916cdSFrançois Tigeot src->x1 = src_x; 1231*2c9916cdSFrançois Tigeot src->x2 = src_x + src_w; 1232*2c9916cdSFrançois Tigeot src->y1 = src_y; 1233*2c9916cdSFrançois Tigeot src->y2 = src_y + src_h; 1234*2c9916cdSFrançois Tigeot } 1235e3adcf8fSFrançois Tigeot 1236*2c9916cdSFrançois Tigeot dst->x1 = crtc_x; 1237*2c9916cdSFrançois Tigeot dst->x2 = crtc_x + crtc_w; 1238*2c9916cdSFrançois Tigeot dst->y1 = crtc_y; 1239*2c9916cdSFrançois Tigeot dst->y2 = crtc_y + crtc_h; 1240*2c9916cdSFrançois Tigeot 1241*2c9916cdSFrançois Tigeot finish: 1242e3adcf8fSFrançois Tigeot /* 1243e3adcf8fSFrançois Tigeot * If the sprite is completely covering the primary plane, 1244e3adcf8fSFrançois Tigeot * we can disable the primary and save power. 1245e3adcf8fSFrançois Tigeot */ 1246*2c9916cdSFrançois Tigeot state->hides_primary = fb != NULL && drm_rect_equals(dst, clip) && 1247*2c9916cdSFrançois Tigeot !colorkey_enabled(intel_plane); 1248*2c9916cdSFrançois Tigeot WARN_ON(state->hides_primary && !state->visible && intel_crtc->active); 1249e3adcf8fSFrançois Tigeot 1250*2c9916cdSFrançois Tigeot if (intel_crtc->active) { 1251*2c9916cdSFrançois Tigeot if (intel_crtc->primary_enabled == state->hides_primary) 1252*2c9916cdSFrançois Tigeot intel_crtc->atomic.wait_for_flips = true; 1253e3adcf8fSFrançois Tigeot 1254*2c9916cdSFrançois Tigeot if (intel_crtc->primary_enabled && state->hides_primary) 1255*2c9916cdSFrançois Tigeot intel_crtc->atomic.pre_disable_primary = true; 1256e3adcf8fSFrançois Tigeot 1257*2c9916cdSFrançois Tigeot intel_crtc->atomic.fb_bits |= 1258*2c9916cdSFrançois Tigeot INTEL_FRONTBUFFER_SPRITE(intel_crtc->pipe); 12599edbd4a0SFrançois Tigeot 1260*2c9916cdSFrançois Tigeot if (!intel_crtc->primary_enabled && !state->hides_primary) 1261*2c9916cdSFrançois Tigeot intel_crtc->atomic.post_enable_primary = true; 1262*2c9916cdSFrançois Tigeot } 12639edbd4a0SFrançois Tigeot 1264*2c9916cdSFrançois Tigeot return 0; 1265*2c9916cdSFrançois Tigeot } 1266*2c9916cdSFrançois Tigeot 1267*2c9916cdSFrançois Tigeot static void 1268*2c9916cdSFrançois Tigeot intel_commit_sprite_plane(struct drm_plane *plane, 1269*2c9916cdSFrançois Tigeot struct intel_plane_state *state) 1270*2c9916cdSFrançois Tigeot { 1271*2c9916cdSFrançois Tigeot struct drm_crtc *crtc = state->base.crtc; 1272*2c9916cdSFrançois Tigeot struct intel_crtc *intel_crtc; 1273*2c9916cdSFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(plane); 1274*2c9916cdSFrançois Tigeot struct drm_framebuffer *fb = state->base.fb; 1275*2c9916cdSFrançois Tigeot struct drm_i915_gem_object *obj = intel_fb_obj(fb); 1276*2c9916cdSFrançois Tigeot int crtc_x, crtc_y; 1277*2c9916cdSFrançois Tigeot unsigned int crtc_w, crtc_h; 1278*2c9916cdSFrançois Tigeot uint32_t src_x, src_y, src_w, src_h; 1279*2c9916cdSFrançois Tigeot 1280*2c9916cdSFrançois Tigeot crtc = crtc ? crtc : plane->crtc; 1281*2c9916cdSFrançois Tigeot intel_crtc = to_intel_crtc(crtc); 1282*2c9916cdSFrançois Tigeot 1283*2c9916cdSFrançois Tigeot plane->fb = state->base.fb; 1284e3adcf8fSFrançois Tigeot intel_plane->obj = obj; 1285e3adcf8fSFrançois Tigeot 12869edbd4a0SFrançois Tigeot if (intel_crtc->active) { 1287*2c9916cdSFrançois Tigeot intel_crtc->primary_enabled = !state->hides_primary; 1288ba55f2f5SFrançois Tigeot 1289*2c9916cdSFrançois Tigeot if (state->visible) { 1290*2c9916cdSFrançois Tigeot crtc_x = state->dst.x1; 1291*2c9916cdSFrançois Tigeot crtc_y = state->dst.y1; 1292*2c9916cdSFrançois Tigeot crtc_w = drm_rect_width(&state->dst); 1293*2c9916cdSFrançois Tigeot crtc_h = drm_rect_height(&state->dst); 1294*2c9916cdSFrançois Tigeot src_x = state->src.x1; 1295*2c9916cdSFrançois Tigeot src_y = state->src.y1; 1296*2c9916cdSFrançois Tigeot src_w = drm_rect_width(&state->src); 1297*2c9916cdSFrançois Tigeot src_h = drm_rect_height(&state->src); 12989edbd4a0SFrançois Tigeot intel_plane->update_plane(plane, crtc, fb, obj, 12995d0b1887SFrançois Tigeot crtc_x, crtc_y, crtc_w, crtc_h, 13005d0b1887SFrançois Tigeot src_x, src_y, src_w, src_h); 1301*2c9916cdSFrançois Tigeot } else { 13029edbd4a0SFrançois Tigeot intel_plane->disable_plane(plane, crtc); 13039edbd4a0SFrançois Tigeot } 1304e3adcf8fSFrançois Tigeot } 1305e3adcf8fSFrançois Tigeot } 1306e3adcf8fSFrançois Tigeot 1307e3adcf8fSFrançois Tigeot int intel_sprite_set_colorkey(struct drm_device *dev, void *data, 1308e3adcf8fSFrançois Tigeot struct drm_file *file_priv) 1309e3adcf8fSFrançois Tigeot { 1310e3adcf8fSFrançois Tigeot struct drm_intel_sprite_colorkey *set = data; 1311e3adcf8fSFrançois Tigeot struct drm_plane *plane; 1312e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane; 1313e3adcf8fSFrançois Tigeot int ret = 0; 1314e3adcf8fSFrançois Tigeot 13152c84b0b6SFrançois Tigeot if (!drm_core_check_feature(dev, DRIVER_MODESET)) 13162c84b0b6SFrançois Tigeot return -ENODEV; 1317e3adcf8fSFrançois Tigeot 1318e3adcf8fSFrançois Tigeot /* Make sure we don't try to enable both src & dest simultaneously */ 1319e3adcf8fSFrançois Tigeot if ((set->flags & (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) == (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) 1320e3adcf8fSFrançois Tigeot return -EINVAL; 1321e3adcf8fSFrançois Tigeot 1322a2fdbec6SFrançois Tigeot drm_modeset_lock_all(dev); 1323e3adcf8fSFrançois Tigeot 132424edb884SFrançois Tigeot plane = drm_plane_find(dev, set->plane_id); 1325*2c9916cdSFrançois Tigeot if (!plane || plane->type != DRM_PLANE_TYPE_OVERLAY) { 13269edbd4a0SFrançois Tigeot ret = -ENOENT; 1327e3adcf8fSFrançois Tigeot goto out_unlock; 1328e3adcf8fSFrançois Tigeot } 1329e3adcf8fSFrançois Tigeot 1330e3adcf8fSFrançois Tigeot intel_plane = to_intel_plane(plane); 1331e3adcf8fSFrançois Tigeot ret = intel_plane->update_colorkey(plane, set); 1332e3adcf8fSFrançois Tigeot 1333e3adcf8fSFrançois Tigeot out_unlock: 1334a2fdbec6SFrançois Tigeot drm_modeset_unlock_all(dev); 1335e3adcf8fSFrançois Tigeot return ret; 1336e3adcf8fSFrançois Tigeot } 1337e3adcf8fSFrançois Tigeot 1338e3adcf8fSFrançois Tigeot int intel_sprite_get_colorkey(struct drm_device *dev, void *data, 1339e3adcf8fSFrançois Tigeot struct drm_file *file_priv) 1340e3adcf8fSFrançois Tigeot { 1341e3adcf8fSFrançois Tigeot struct drm_intel_sprite_colorkey *get = data; 1342e3adcf8fSFrançois Tigeot struct drm_plane *plane; 1343e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane; 1344e3adcf8fSFrançois Tigeot int ret = 0; 1345e3adcf8fSFrançois Tigeot 13462c84b0b6SFrançois Tigeot if (!drm_core_check_feature(dev, DRIVER_MODESET)) 13472c84b0b6SFrançois Tigeot return -ENODEV; 1348e3adcf8fSFrançois Tigeot 1349a2fdbec6SFrançois Tigeot drm_modeset_lock_all(dev); 1350e3adcf8fSFrançois Tigeot 135124edb884SFrançois Tigeot plane = drm_plane_find(dev, get->plane_id); 1352*2c9916cdSFrançois Tigeot if (!plane || plane->type != DRM_PLANE_TYPE_OVERLAY) { 13539edbd4a0SFrançois Tigeot ret = -ENOENT; 1354e3adcf8fSFrançois Tigeot goto out_unlock; 1355e3adcf8fSFrançois Tigeot } 1356e3adcf8fSFrançois Tigeot 1357e3adcf8fSFrançois Tigeot intel_plane = to_intel_plane(plane); 1358e3adcf8fSFrançois Tigeot intel_plane->get_colorkey(plane, get); 1359e3adcf8fSFrançois Tigeot 1360e3adcf8fSFrançois Tigeot out_unlock: 1361a2fdbec6SFrançois Tigeot drm_modeset_unlock_all(dev); 1362e3adcf8fSFrançois Tigeot return ret; 1363e3adcf8fSFrançois Tigeot } 1364e3adcf8fSFrançois Tigeot 13651b13d190SFrançois Tigeot int intel_plane_set_property(struct drm_plane *plane, 13661b13d190SFrançois Tigeot struct drm_property *prop, 13671b13d190SFrançois Tigeot uint64_t val) 13681b13d190SFrançois Tigeot { 13691b13d190SFrançois Tigeot struct drm_device *dev = plane->dev; 13701b13d190SFrançois Tigeot uint64_t old_val; 13711b13d190SFrançois Tigeot int ret = -ENOENT; 13721b13d190SFrançois Tigeot 13731b13d190SFrançois Tigeot if (prop == dev->mode_config.rotation_property) { 13741b13d190SFrançois Tigeot /* exactly one rotation angle please */ 13751b13d190SFrançois Tigeot if (hweight32(val & 0xf) != 1) 13761b13d190SFrançois Tigeot return -EINVAL; 13771b13d190SFrançois Tigeot 1378*2c9916cdSFrançois Tigeot if (plane->state->rotation == val) 13791b13d190SFrançois Tigeot return 0; 13801b13d190SFrançois Tigeot 1381*2c9916cdSFrançois Tigeot old_val = plane->state->rotation; 1382*2c9916cdSFrançois Tigeot plane->state->rotation = val; 13831b13d190SFrançois Tigeot ret = intel_plane_restore(plane); 13841b13d190SFrançois Tigeot if (ret) 1385*2c9916cdSFrançois Tigeot plane->state->rotation = old_val; 13861b13d190SFrançois Tigeot } 13871b13d190SFrançois Tigeot 13881b13d190SFrançois Tigeot return ret; 13891b13d190SFrançois Tigeot } 13901b13d190SFrançois Tigeot 13911b13d190SFrançois Tigeot int intel_plane_restore(struct drm_plane *plane) 13928e26cdf6SFrançois Tigeot { 13938e26cdf6SFrançois Tigeot if (!plane->crtc || !plane->fb) 13941b13d190SFrançois Tigeot return 0; 13958e26cdf6SFrançois Tigeot 13961b13d190SFrançois Tigeot return plane->funcs->update_plane(plane, plane->crtc, plane->fb, 1397*2c9916cdSFrançois Tigeot plane->state->crtc_x, plane->state->crtc_y, 1398*2c9916cdSFrançois Tigeot plane->state->crtc_w, plane->state->crtc_h, 1399*2c9916cdSFrançois Tigeot plane->state->src_x, plane->state->src_y, 1400*2c9916cdSFrançois Tigeot plane->state->src_w, plane->state->src_h); 14018e26cdf6SFrançois Tigeot } 14028e26cdf6SFrançois Tigeot 14032c84b0b6SFrançois Tigeot static uint32_t ilk_plane_formats[] = { 14042c84b0b6SFrançois Tigeot DRM_FORMAT_XRGB8888, 14052c84b0b6SFrançois Tigeot DRM_FORMAT_YUYV, 14062c84b0b6SFrançois Tigeot DRM_FORMAT_YVYU, 14072c84b0b6SFrançois Tigeot DRM_FORMAT_UYVY, 14082c84b0b6SFrançois Tigeot DRM_FORMAT_VYUY, 14092c84b0b6SFrançois Tigeot }; 14102c84b0b6SFrançois Tigeot 1411e3adcf8fSFrançois Tigeot static uint32_t snb_plane_formats[] = { 1412e3adcf8fSFrançois Tigeot DRM_FORMAT_XBGR8888, 1413e3adcf8fSFrançois Tigeot DRM_FORMAT_XRGB8888, 1414e3adcf8fSFrançois Tigeot DRM_FORMAT_YUYV, 1415e3adcf8fSFrançois Tigeot DRM_FORMAT_YVYU, 1416e3adcf8fSFrançois Tigeot DRM_FORMAT_UYVY, 1417e3adcf8fSFrançois Tigeot DRM_FORMAT_VYUY, 1418e3adcf8fSFrançois Tigeot }; 1419e3adcf8fSFrançois Tigeot 14208e26cdf6SFrançois Tigeot static uint32_t vlv_plane_formats[] = { 14218e26cdf6SFrançois Tigeot DRM_FORMAT_RGB565, 14228e26cdf6SFrançois Tigeot DRM_FORMAT_ABGR8888, 14238e26cdf6SFrançois Tigeot DRM_FORMAT_ARGB8888, 14248e26cdf6SFrançois Tigeot DRM_FORMAT_XBGR8888, 14258e26cdf6SFrançois Tigeot DRM_FORMAT_XRGB8888, 14268e26cdf6SFrançois Tigeot DRM_FORMAT_XBGR2101010, 14278e26cdf6SFrançois Tigeot DRM_FORMAT_ABGR2101010, 14288e26cdf6SFrançois Tigeot DRM_FORMAT_YUYV, 14298e26cdf6SFrançois Tigeot DRM_FORMAT_YVYU, 14308e26cdf6SFrançois Tigeot DRM_FORMAT_UYVY, 14318e26cdf6SFrançois Tigeot DRM_FORMAT_VYUY, 14328e26cdf6SFrançois Tigeot }; 14338e26cdf6SFrançois Tigeot 1434*2c9916cdSFrançois Tigeot static uint32_t skl_plane_formats[] = { 1435*2c9916cdSFrançois Tigeot DRM_FORMAT_RGB565, 1436*2c9916cdSFrançois Tigeot DRM_FORMAT_ABGR8888, 1437*2c9916cdSFrançois Tigeot DRM_FORMAT_ARGB8888, 1438*2c9916cdSFrançois Tigeot DRM_FORMAT_XBGR8888, 1439*2c9916cdSFrançois Tigeot DRM_FORMAT_XRGB8888, 1440*2c9916cdSFrançois Tigeot DRM_FORMAT_YUYV, 1441*2c9916cdSFrançois Tigeot DRM_FORMAT_YVYU, 1442*2c9916cdSFrançois Tigeot DRM_FORMAT_UYVY, 1443*2c9916cdSFrançois Tigeot DRM_FORMAT_VYUY, 1444*2c9916cdSFrançois Tigeot }; 1445*2c9916cdSFrançois Tigeot 1446e3adcf8fSFrançois Tigeot int 14478e26cdf6SFrançois Tigeot intel_plane_init(struct drm_device *dev, enum i915_pipe pipe, int plane) 1448e3adcf8fSFrançois Tigeot { 1449e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane; 1450*2c9916cdSFrançois Tigeot struct intel_plane_state *state; 1451e3adcf8fSFrançois Tigeot unsigned long possible_crtcs; 14522c84b0b6SFrançois Tigeot const uint32_t *plane_formats; 14532c84b0b6SFrançois Tigeot int num_plane_formats; 1454e3adcf8fSFrançois Tigeot int ret; 1455e3adcf8fSFrançois Tigeot 14562c84b0b6SFrançois Tigeot if (INTEL_INFO(dev)->gen < 5) 1457e3adcf8fSFrançois Tigeot return -ENODEV; 1458e3adcf8fSFrançois Tigeot 14599edbd4a0SFrançois Tigeot intel_plane = kzalloc(sizeof(*intel_plane), GFP_KERNEL); 14602c84b0b6SFrançois Tigeot if (!intel_plane) 14612c84b0b6SFrançois Tigeot return -ENOMEM; 14622c84b0b6SFrançois Tigeot 1463*2c9916cdSFrançois Tigeot state = intel_create_plane_state(&intel_plane->base); 1464*2c9916cdSFrançois Tigeot if (!state) { 1465*2c9916cdSFrançois Tigeot kfree(intel_plane); 1466*2c9916cdSFrançois Tigeot return -ENOMEM; 1467*2c9916cdSFrançois Tigeot } 1468*2c9916cdSFrançois Tigeot intel_plane->base.state = &state->base; 1469*2c9916cdSFrançois Tigeot 14702c84b0b6SFrançois Tigeot switch (INTEL_INFO(dev)->gen) { 14712c84b0b6SFrançois Tigeot case 5: 14722c84b0b6SFrançois Tigeot case 6: 14732c84b0b6SFrançois Tigeot intel_plane->can_scale = true; 14742c84b0b6SFrançois Tigeot intel_plane->max_downscale = 16; 14752c84b0b6SFrançois Tigeot intel_plane->update_plane = ilk_update_plane; 14762c84b0b6SFrançois Tigeot intel_plane->disable_plane = ilk_disable_plane; 14772c84b0b6SFrançois Tigeot intel_plane->update_colorkey = ilk_update_colorkey; 14782c84b0b6SFrançois Tigeot intel_plane->get_colorkey = ilk_get_colorkey; 1479e3adcf8fSFrançois Tigeot 1480e3adcf8fSFrançois Tigeot if (IS_GEN6(dev)) { 14812c84b0b6SFrançois Tigeot plane_formats = snb_plane_formats; 14822c84b0b6SFrançois Tigeot num_plane_formats = ARRAY_SIZE(snb_plane_formats); 14832c84b0b6SFrançois Tigeot } else { 14842c84b0b6SFrançois Tigeot plane_formats = ilk_plane_formats; 14852c84b0b6SFrançois Tigeot num_plane_formats = ARRAY_SIZE(ilk_plane_formats); 14862c84b0b6SFrançois Tigeot } 14872c84b0b6SFrançois Tigeot break; 14882c84b0b6SFrançois Tigeot 14892c84b0b6SFrançois Tigeot case 7: 14909edbd4a0SFrançois Tigeot case 8: 14915d0b1887SFrançois Tigeot if (IS_IVYBRIDGE(dev)) { 14922c84b0b6SFrançois Tigeot intel_plane->can_scale = true; 14935d0b1887SFrançois Tigeot intel_plane->max_downscale = 2; 14945d0b1887SFrançois Tigeot } else { 14955d0b1887SFrançois Tigeot intel_plane->can_scale = false; 14965d0b1887SFrançois Tigeot intel_plane->max_downscale = 1; 14975d0b1887SFrançois Tigeot } 14988e26cdf6SFrançois Tigeot 14998e26cdf6SFrançois Tigeot if (IS_VALLEYVIEW(dev)) { 15008e26cdf6SFrançois Tigeot intel_plane->update_plane = vlv_update_plane; 15018e26cdf6SFrançois Tigeot intel_plane->disable_plane = vlv_disable_plane; 15028e26cdf6SFrançois Tigeot intel_plane->update_colorkey = vlv_update_colorkey; 15038e26cdf6SFrançois Tigeot intel_plane->get_colorkey = vlv_get_colorkey; 15048e26cdf6SFrançois Tigeot 15058e26cdf6SFrançois Tigeot plane_formats = vlv_plane_formats; 15068e26cdf6SFrançois Tigeot num_plane_formats = ARRAY_SIZE(vlv_plane_formats); 15078e26cdf6SFrançois Tigeot } else { 1508e3adcf8fSFrançois Tigeot intel_plane->update_plane = ivb_update_plane; 1509e3adcf8fSFrançois Tigeot intel_plane->disable_plane = ivb_disable_plane; 1510e3adcf8fSFrançois Tigeot intel_plane->update_colorkey = ivb_update_colorkey; 1511e3adcf8fSFrançois Tigeot intel_plane->get_colorkey = ivb_get_colorkey; 15122c84b0b6SFrançois Tigeot 15132c84b0b6SFrançois Tigeot plane_formats = snb_plane_formats; 15142c84b0b6SFrançois Tigeot num_plane_formats = ARRAY_SIZE(snb_plane_formats); 15158e26cdf6SFrançois Tigeot } 15162c84b0b6SFrançois Tigeot break; 1517*2c9916cdSFrançois Tigeot case 9: 1518*2c9916cdSFrançois Tigeot /* 1519*2c9916cdSFrançois Tigeot * FIXME: Skylake planes can be scaled (with some restrictions), 1520*2c9916cdSFrançois Tigeot * but this is for another time. 1521*2c9916cdSFrançois Tigeot */ 1522*2c9916cdSFrançois Tigeot intel_plane->can_scale = false; 1523*2c9916cdSFrançois Tigeot intel_plane->max_downscale = 1; 1524*2c9916cdSFrançois Tigeot intel_plane->update_plane = skl_update_plane; 1525*2c9916cdSFrançois Tigeot intel_plane->disable_plane = skl_disable_plane; 1526*2c9916cdSFrançois Tigeot intel_plane->update_colorkey = skl_update_colorkey; 1527*2c9916cdSFrançois Tigeot intel_plane->get_colorkey = skl_get_colorkey; 15282c84b0b6SFrançois Tigeot 1529*2c9916cdSFrançois Tigeot plane_formats = skl_plane_formats; 1530*2c9916cdSFrançois Tigeot num_plane_formats = ARRAY_SIZE(skl_plane_formats); 1531*2c9916cdSFrançois Tigeot break; 15322c84b0b6SFrançois Tigeot default: 1533158486a6SFrançois Tigeot kfree(intel_plane); 15342c84b0b6SFrançois Tigeot return -ENODEV; 1535e3adcf8fSFrançois Tigeot } 1536e3adcf8fSFrançois Tigeot 1537e3adcf8fSFrançois Tigeot intel_plane->pipe = pipe; 15388e26cdf6SFrançois Tigeot intel_plane->plane = plane; 1539*2c9916cdSFrançois Tigeot intel_plane->check_plane = intel_check_sprite_plane; 1540*2c9916cdSFrançois Tigeot intel_plane->commit_plane = intel_commit_sprite_plane; 1541e3adcf8fSFrançois Tigeot possible_crtcs = (1 << pipe); 15421b13d190SFrançois Tigeot ret = drm_universal_plane_init(dev, &intel_plane->base, possible_crtcs, 15432c84b0b6SFrançois Tigeot &intel_plane_funcs, 15442c84b0b6SFrançois Tigeot plane_formats, num_plane_formats, 15451b13d190SFrançois Tigeot DRM_PLANE_TYPE_OVERLAY); 15461b13d190SFrançois Tigeot if (ret) { 1547158486a6SFrançois Tigeot kfree(intel_plane); 15481b13d190SFrançois Tigeot goto out; 15491b13d190SFrançois Tigeot } 1550e3adcf8fSFrançois Tigeot 15511b13d190SFrançois Tigeot if (!dev->mode_config.rotation_property) 15521b13d190SFrançois Tigeot dev->mode_config.rotation_property = 15531b13d190SFrançois Tigeot drm_mode_create_rotation_property(dev, 15541b13d190SFrançois Tigeot BIT(DRM_ROTATE_0) | 15551b13d190SFrançois Tigeot BIT(DRM_ROTATE_180)); 15561b13d190SFrançois Tigeot 15571b13d190SFrançois Tigeot if (dev->mode_config.rotation_property) 15581b13d190SFrançois Tigeot drm_object_attach_property(&intel_plane->base.base, 15591b13d190SFrançois Tigeot dev->mode_config.rotation_property, 1560*2c9916cdSFrançois Tigeot state->base.rotation); 1561*2c9916cdSFrançois Tigeot 1562*2c9916cdSFrançois Tigeot drm_plane_helper_add(&intel_plane->base, &intel_plane_helper_funcs); 15631b13d190SFrançois Tigeot 15641b13d190SFrançois Tigeot out: 1565e3adcf8fSFrançois Tigeot return ret; 1566e3adcf8fSFrançois Tigeot } 1567