--- zzzz-none-000/linux-3.10.107/drivers/gpu/drm/i915/intel_sprite.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/gpu/drm/i915/intel_sprite.c 2021-02-04 17:41:59.000000000 +0000 @@ -32,32 +32,335 @@ #include #include #include +#include +#include +#include #include "intel_drv.h" #include #include "i915_drv.h" +static bool +format_is_yuv(uint32_t format) +{ + switch (format) { + case DRM_FORMAT_YUYV: + case DRM_FORMAT_UYVY: + case DRM_FORMAT_VYUY: + case DRM_FORMAT_YVYU: + return true; + default: + return false; + } +} + +static int usecs_to_scanlines(const struct drm_display_mode *adjusted_mode, + int usecs) +{ + /* paranoia */ + if (!adjusted_mode->crtc_htotal) + return 1; + + return DIV_ROUND_UP(usecs * adjusted_mode->crtc_clock, + 1000 * adjusted_mode->crtc_htotal); +} + +/** + * intel_pipe_update_start() - start update of a set of display registers + * @crtc: the crtc of which the registers are going to be updated + * @start_vbl_count: vblank counter return pointer used for error checking + * + * Mark the start of an update to pipe registers that should be updated + * atomically regarding vblank. If the next vblank will happens within + * the next 100 us, this function waits until the vblank passes. + * + * After a successful call to this function, interrupts will be disabled + * until a subsequent call to intel_pipe_update_end(). That is done to + * avoid random delays. The value written to @start_vbl_count should be + * supplied to intel_pipe_update_end() for error checking. + */ +void intel_pipe_update_start(struct intel_crtc *crtc) +{ + struct drm_device *dev = crtc->base.dev; + const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode; + enum pipe pipe = crtc->pipe; + long timeout = msecs_to_jiffies_timeout(1); + int scanline, min, max, vblank_start; + wait_queue_head_t *wq = drm_crtc_vblank_waitqueue(&crtc->base); + DEFINE_WAIT(wait); + + vblank_start = adjusted_mode->crtc_vblank_start; + if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) + vblank_start = DIV_ROUND_UP(vblank_start, 2); + + /* FIXME needs to be calibrated sensibly */ + min = vblank_start - usecs_to_scanlines(adjusted_mode, 100); + max = vblank_start - 1; + + local_irq_disable(); + + if (min <= 0 || max <= 0) + return; + + if (WARN_ON(drm_crtc_vblank_get(&crtc->base))) + return; + + crtc->debug.min_vbl = min; + crtc->debug.max_vbl = max; + trace_i915_pipe_update_start(crtc); + + for (;;) { + /* + * prepare_to_wait() has a memory barrier, which guarantees + * other CPUs can see the task state update by the time we + * read the scanline. + */ + prepare_to_wait(wq, &wait, TASK_UNINTERRUPTIBLE); + + scanline = intel_get_crtc_scanline(crtc); + if (scanline < min || scanline > max) + break; + + if (timeout <= 0) { + DRM_ERROR("Potential atomic update failure on pipe %c\n", + pipe_name(crtc->pipe)); + break; + } + + local_irq_enable(); + + timeout = schedule_timeout(timeout); + + local_irq_disable(); + } + + finish_wait(wq, &wait); + + drm_crtc_vblank_put(&crtc->base); + + crtc->debug.scanline_start = scanline; + crtc->debug.start_vbl_time = ktime_get(); + crtc->debug.start_vbl_count = + dev->driver->get_vblank_counter(dev, pipe); + + trace_i915_pipe_update_vblank_evaded(crtc); +} + +/** + * intel_pipe_update_end() - end update of a set of display registers + * @crtc: the crtc of which the registers were updated + * @start_vbl_count: start vblank counter (used for error checking) + * + * Mark the end of an update started with intel_pipe_update_start(). This + * re-enables interrupts and verifies the update was actually completed + * before a vblank using the value of @start_vbl_count. + */ +void intel_pipe_update_end(struct intel_crtc *crtc) +{ + struct drm_device *dev = crtc->base.dev; + enum pipe pipe = crtc->pipe; + int scanline_end = intel_get_crtc_scanline(crtc); + u32 end_vbl_count = dev->driver->get_vblank_counter(dev, pipe); + ktime_t end_vbl_time = ktime_get(); + + trace_i915_pipe_update_end(crtc, end_vbl_count, scanline_end); + + local_irq_enable(); + + if (crtc->debug.start_vbl_count && + crtc->debug.start_vbl_count != end_vbl_count) { + DRM_ERROR("Atomic update failure on pipe %c (start=%u end=%u) time %lld us, min %d, max %d, scanline start %d, end %d\n", + pipe_name(pipe), crtc->debug.start_vbl_count, + end_vbl_count, + ktime_us_delta(end_vbl_time, crtc->debug.start_vbl_time), + crtc->debug.min_vbl, crtc->debug.max_vbl, + crtc->debug.scanline_start, scanline_end); + } +} + static void -vlv_update_plane(struct drm_plane *dplane, struct drm_framebuffer *fb, - struct drm_i915_gem_object *obj, int crtc_x, int crtc_y, +skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc, + struct drm_framebuffer *fb, + int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, uint32_t x, uint32_t y, uint32_t src_w, uint32_t src_h) { + struct drm_device *dev = drm_plane->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_plane *intel_plane = to_intel_plane(drm_plane); + struct drm_i915_gem_object *obj = intel_fb_obj(fb); + const int pipe = intel_plane->pipe; + const int plane = intel_plane->plane + 1; + u32 plane_ctl, stride_div, stride; + int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); + const struct drm_intel_sprite_colorkey *key = + &to_intel_plane_state(drm_plane->state)->ckey; + u32 surf_addr; + u32 tile_height, plane_offset, plane_size; + unsigned int rotation; + int x_offset, y_offset; + struct intel_crtc_state *crtc_state = to_intel_crtc(crtc)->config; + int scaler_id; + + plane_ctl = PLANE_CTL_ENABLE | + PLANE_CTL_PIPE_GAMMA_ENABLE | + PLANE_CTL_PIPE_CSC_ENABLE; + + plane_ctl |= skl_plane_ctl_format(fb->pixel_format); + plane_ctl |= skl_plane_ctl_tiling(fb->modifier[0]); + + rotation = drm_plane->state->rotation; + plane_ctl |= skl_plane_ctl_rotation(rotation); + + intel_update_sprite_watermarks(drm_plane, crtc, src_w, src_h, + pixel_size, true, + src_w != crtc_w || src_h != crtc_h); + + stride_div = intel_fb_stride_alignment(dev, fb->modifier[0], + fb->pixel_format); + + scaler_id = to_intel_plane_state(drm_plane->state)->scaler_id; + + /* Sizes are 0 based */ + src_w--; + src_h--; + crtc_w--; + crtc_h--; + + if (key->flags) { + I915_WRITE(PLANE_KEYVAL(pipe, plane), key->min_value); + I915_WRITE(PLANE_KEYMAX(pipe, plane), key->max_value); + I915_WRITE(PLANE_KEYMSK(pipe, plane), key->channel_mask); + } + + if (key->flags & I915_SET_COLORKEY_DESTINATION) + plane_ctl |= PLANE_CTL_KEY_ENABLE_DESTINATION; + else if (key->flags & I915_SET_COLORKEY_SOURCE) + plane_ctl |= PLANE_CTL_KEY_ENABLE_SOURCE; + + surf_addr = intel_plane_obj_offset(intel_plane, obj, 0); + + if (intel_rotation_90_or_270(rotation)) { + /* stride: Surface height in tiles */ + tile_height = intel_tile_height(dev, fb->pixel_format, + fb->modifier[0], 0); + stride = DIV_ROUND_UP(fb->height, tile_height); + plane_size = (src_w << 16) | src_h; + x_offset = stride * tile_height - y - (src_h + 1); + y_offset = x; + } else { + stride = fb->pitches[0] / stride_div; + plane_size = (src_h << 16) | src_w; + x_offset = x; + y_offset = y; + } + plane_offset = y_offset << 16 | x_offset; + + I915_WRITE(PLANE_OFFSET(pipe, plane), plane_offset); + I915_WRITE(PLANE_STRIDE(pipe, plane), stride); + I915_WRITE(PLANE_SIZE(pipe, plane), plane_size); + + /* program plane scaler */ + if (scaler_id >= 0) { + uint32_t ps_ctrl = 0; + + DRM_DEBUG_KMS("plane = %d PS_PLANE_SEL(plane) = 0x%x\n", plane, + PS_PLANE_SEL(plane)); + ps_ctrl = PS_SCALER_EN | PS_PLANE_SEL(plane) | + crtc_state->scaler_state.scalers[scaler_id].mode; + I915_WRITE(SKL_PS_CTRL(pipe, scaler_id), ps_ctrl); + I915_WRITE(SKL_PS_PWR_GATE(pipe, scaler_id), 0); + I915_WRITE(SKL_PS_WIN_POS(pipe, scaler_id), (crtc_x << 16) | crtc_y); + I915_WRITE(SKL_PS_WIN_SZ(pipe, scaler_id), + ((crtc_w + 1) << 16)|(crtc_h + 1)); + + I915_WRITE(PLANE_POS(pipe, plane), 0); + } else { + I915_WRITE(PLANE_POS(pipe, plane), (crtc_y << 16) | crtc_x); + } + + I915_WRITE(PLANE_CTL(pipe, plane), plane_ctl); + I915_WRITE(PLANE_SURF(pipe, plane), surf_addr); + POSTING_READ(PLANE_SURF(pipe, plane)); +} + +static void +skl_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc) +{ struct drm_device *dev = dplane->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_plane *intel_plane = to_intel_plane(dplane); + const int pipe = intel_plane->pipe; + const int plane = intel_plane->plane + 1; + + I915_WRITE(PLANE_CTL(pipe, plane), 0); + + I915_WRITE(PLANE_SURF(pipe, plane), 0); + POSTING_READ(PLANE_SURF(pipe, plane)); + + intel_update_sprite_watermarks(dplane, crtc, 0, 0, 0, false, false); +} + +static void +chv_update_csc(struct intel_plane *intel_plane, uint32_t format) +{ + struct drm_i915_private *dev_priv = intel_plane->base.dev->dev_private; + int plane = intel_plane->plane; + + /* Seems RGB data bypasses the CSC always */ + if (!format_is_yuv(format)) + return; + + /* + * BT.601 limited range YCbCr -> full range RGB + * + * |r| | 6537 4769 0| |cr | + * |g| = |-3330 4769 -1605| x |y-64| + * |b| | 0 4769 8263| |cb | + * + * Cb and Cr apparently come in as signed already, so no + * need for any offset. For Y we need to remove the offset. + */ + I915_WRITE(SPCSCYGOFF(plane), SPCSC_OOFF(0) | SPCSC_IOFF(-64)); + I915_WRITE(SPCSCCBOFF(plane), SPCSC_OOFF(0) | SPCSC_IOFF(0)); + I915_WRITE(SPCSCCROFF(plane), SPCSC_OOFF(0) | SPCSC_IOFF(0)); + + I915_WRITE(SPCSCC01(plane), SPCSC_C1(4769) | SPCSC_C0(6537)); + I915_WRITE(SPCSCC23(plane), SPCSC_C1(-3330) | SPCSC_C0(0)); + I915_WRITE(SPCSCC45(plane), SPCSC_C1(-1605) | SPCSC_C0(4769)); + I915_WRITE(SPCSCC67(plane), SPCSC_C1(4769) | SPCSC_C0(0)); + I915_WRITE(SPCSCC8(plane), SPCSC_C0(8263)); + + I915_WRITE(SPCSCYGICLAMP(plane), SPCSC_IMAX(940) | SPCSC_IMIN(64)); + I915_WRITE(SPCSCCBICLAMP(plane), SPCSC_IMAX(448) | SPCSC_IMIN(-448)); + I915_WRITE(SPCSCCRICLAMP(plane), SPCSC_IMAX(448) | SPCSC_IMIN(-448)); + + I915_WRITE(SPCSCYGOCLAMP(plane), SPCSC_OMAX(1023) | SPCSC_OMIN(0)); + I915_WRITE(SPCSCCBOCLAMP(plane), SPCSC_OMAX(1023) | SPCSC_OMIN(0)); + I915_WRITE(SPCSCCROCLAMP(plane), SPCSC_OMAX(1023) | SPCSC_OMIN(0)); +} + +static void +vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, + struct drm_framebuffer *fb, + int crtc_x, int crtc_y, + unsigned int crtc_w, unsigned int crtc_h, + uint32_t x, uint32_t y, + uint32_t src_w, uint32_t src_h) +{ + struct drm_device *dev = dplane->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_plane *intel_plane = to_intel_plane(dplane); + struct drm_i915_gem_object *obj = intel_fb_obj(fb); int pipe = intel_plane->pipe; int plane = intel_plane->plane; u32 sprctl; unsigned long sprsurf_offset, linear_offset; int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); + const struct drm_intel_sprite_colorkey *key = + &to_intel_plane_state(dplane->state)->ckey; - sprctl = I915_READ(SPCNTR(pipe, plane)); - - /* Mask out pixel format bits in case we change it */ - sprctl &= ~SP_PIXFORMAT_MASK; - sprctl &= ~SP_YUV_BYTE_ORDER_MASK; - sprctl &= ~SP_TILED; + sprctl = SP_ENABLE; switch (fb->pixel_format) { case DRM_FORMAT_YUYV: @@ -102,43 +405,68 @@ break; } + /* + * Enable gamma to match primary/cursor plane behaviour. + * FIXME should be user controllable via propertiesa. + */ + sprctl |= SP_GAMMA_ENABLE; + if (obj->tiling_mode != I915_TILING_NONE) sprctl |= SP_TILED; - sprctl |= SP_ENABLE; - /* Sizes are 0 based */ src_w--; src_h--; crtc_w--; crtc_h--; - intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size); - - I915_WRITE(SPSTRIDE(pipe, plane), fb->pitches[0]); - I915_WRITE(SPPOS(pipe, plane), (crtc_y << 16) | crtc_x); - linear_offset = y * fb->pitches[0] + x * pixel_size; - sprsurf_offset = intel_gen4_compute_page_offset(&x, &y, + sprsurf_offset = intel_gen4_compute_page_offset(dev_priv, + &x, &y, obj->tiling_mode, pixel_size, fb->pitches[0]); linear_offset -= sprsurf_offset; + if (dplane->state->rotation == BIT(DRM_ROTATE_180)) { + sprctl |= SP_ROTATE_180; + + x += src_w; + y += src_h; + linear_offset += src_h * fb->pitches[0] + src_w * pixel_size; + } + + if (key->flags) { + I915_WRITE(SPKEYMINVAL(pipe, plane), key->min_value); + I915_WRITE(SPKEYMAXVAL(pipe, plane), key->max_value); + I915_WRITE(SPKEYMSK(pipe, plane), key->channel_mask); + } + + if (key->flags & I915_SET_COLORKEY_SOURCE) + sprctl |= SP_SOURCE_KEY; + + if (IS_CHERRYVIEW(dev) && pipe == PIPE_B) + chv_update_csc(intel_plane, fb->pixel_format); + + I915_WRITE(SPSTRIDE(pipe, plane), fb->pitches[0]); + I915_WRITE(SPPOS(pipe, plane), (crtc_y << 16) | crtc_x); + if (obj->tiling_mode != I915_TILING_NONE) I915_WRITE(SPTILEOFF(pipe, plane), (y << 16) | x); else I915_WRITE(SPLINOFF(pipe, plane), linear_offset); + I915_WRITE(SPCONSTALPHA(pipe, plane), 0); + I915_WRITE(SPSIZE(pipe, plane), (crtc_h << 16) | crtc_w); I915_WRITE(SPCNTR(pipe, plane), sprctl); - I915_MODIFY_DISPBASE(SPSURF(pipe, plane), obj->gtt_offset + - sprsurf_offset); + I915_WRITE(SPSURF(pipe, plane), i915_gem_obj_ggtt_offset(obj) + + sprsurf_offset); POSTING_READ(SPSURF(pipe, plane)); } static void -vlv_disable_plane(struct drm_plane *dplane) +vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc) { struct drm_device *dev = dplane->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -146,67 +474,16 @@ int pipe = intel_plane->pipe; int plane = intel_plane->plane; - I915_WRITE(SPCNTR(pipe, plane), I915_READ(SPCNTR(pipe, plane)) & - ~SP_ENABLE); - /* Activate double buffered register update */ - I915_MODIFY_DISPBASE(SPSURF(pipe, plane), 0); - POSTING_READ(SPSURF(pipe, plane)); -} - -static int -vlv_update_colorkey(struct drm_plane *dplane, - struct drm_intel_sprite_colorkey *key) -{ - struct drm_device *dev = dplane->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_plane *intel_plane = to_intel_plane(dplane); - int pipe = intel_plane->pipe; - int plane = intel_plane->plane; - u32 sprctl; - - if (key->flags & I915_SET_COLORKEY_DESTINATION) - return -EINVAL; - - I915_WRITE(SPKEYMINVAL(pipe, plane), key->min_value); - I915_WRITE(SPKEYMAXVAL(pipe, plane), key->max_value); - I915_WRITE(SPKEYMSK(pipe, plane), key->channel_mask); - - sprctl = I915_READ(SPCNTR(pipe, plane)); - sprctl &= ~SP_SOURCE_KEY; - if (key->flags & I915_SET_COLORKEY_SOURCE) - sprctl |= SP_SOURCE_KEY; - I915_WRITE(SPCNTR(pipe, plane), sprctl); - - POSTING_READ(SPKEYMSK(pipe, plane)); + I915_WRITE(SPCNTR(pipe, plane), 0); - return 0; -} - -static void -vlv_get_colorkey(struct drm_plane *dplane, - struct drm_intel_sprite_colorkey *key) -{ - struct drm_device *dev = dplane->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_plane *intel_plane = to_intel_plane(dplane); - int pipe = intel_plane->pipe; - int plane = intel_plane->plane; - u32 sprctl; - - key->min_value = I915_READ(SPKEYMINVAL(pipe, plane)); - key->max_value = I915_READ(SPKEYMAXVAL(pipe, plane)); - key->channel_mask = I915_READ(SPKEYMSK(pipe, plane)); - - sprctl = I915_READ(SPCNTR(pipe, plane)); - if (sprctl & SP_SOURCE_KEY) - key->flags = I915_SET_COLORKEY_SOURCE; - else - key->flags = I915_SET_COLORKEY_NONE; + I915_WRITE(SPSURF(pipe, plane), 0); + POSTING_READ(SPSURF(pipe, plane)); } static void -ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, - struct drm_i915_gem_object *obj, int crtc_x, int crtc_y, +ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, + struct drm_framebuffer *fb, + int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, uint32_t x, uint32_t y, uint32_t src_w, uint32_t src_h) @@ -214,19 +491,15 @@ struct drm_device *dev = plane->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_plane *intel_plane = to_intel_plane(plane); - int pipe = intel_plane->pipe; + struct drm_i915_gem_object *obj = intel_fb_obj(fb); + enum pipe pipe = intel_plane->pipe; u32 sprctl, sprscale = 0; unsigned long sprsurf_offset, linear_offset; int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); - bool scaling_was_enabled = dev_priv->sprite_scaling_enabled; + const struct drm_intel_sprite_colorkey *key = + &to_intel_plane_state(plane->state)->ckey; - sprctl = I915_READ(SPRCTL(pipe)); - - /* Mask out pixel format bits in case we change it */ - sprctl &= ~SPRITE_PIXFORMAT_MASK; - sprctl &= ~SPRITE_RGB_ORDER_RGBX; - sprctl &= ~SPRITE_YUV_BYTE_ORDER_MASK; - sprctl &= ~SPRITE_TILED; + sprctl = SPRITE_ENABLE; switch (fb->pixel_format) { case DRM_FORMAT_XBGR8888: @@ -251,52 +524,72 @@ BUG(); } + /* + * Enable gamma to match primary/cursor plane behaviour. + * FIXME should be user controllable via propertiesa. + */ + sprctl |= SPRITE_GAMMA_ENABLE; + if (obj->tiling_mode != I915_TILING_NONE) sprctl |= SPRITE_TILED; - /* must disable */ - sprctl |= SPRITE_TRICKLE_FEED_DISABLE; - sprctl |= SPRITE_ENABLE; + if (IS_HASWELL(dev) || IS_BROADWELL(dev)) + sprctl &= ~SPRITE_TRICKLE_FEED_DISABLE; + else + sprctl |= SPRITE_TRICKLE_FEED_DISABLE; - if (IS_HASWELL(dev)) + if (IS_HASWELL(dev) || IS_BROADWELL(dev)) sprctl |= SPRITE_PIPE_CSC_ENABLE; + intel_update_sprite_watermarks(plane, crtc, src_w, src_h, pixel_size, + true, + src_w != crtc_w || src_h != crtc_h); + /* Sizes are 0 based */ src_w--; src_h--; crtc_w--; crtc_h--; - intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size); - - /* - * IVB workaround: must disable low power watermarks for at least - * one frame before enabling scaling. LP watermarks can be re-enabled - * when scaling is disabled. - */ - if (crtc_w != src_w || crtc_h != src_h) { - dev_priv->sprite_scaling_enabled |= 1 << pipe; - - if (!scaling_was_enabled) { - intel_update_watermarks(dev); - intel_wait_for_vblank(dev, pipe); - } + if (crtc_w != src_w || crtc_h != src_h) sprscale = SPRITE_SCALE_ENABLE | (src_w << 16) | src_h; - } else - dev_priv->sprite_scaling_enabled &= ~(1 << pipe); - - I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]); - I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x); linear_offset = y * fb->pitches[0] + x * pixel_size; sprsurf_offset = - intel_gen4_compute_page_offset(&x, &y, obj->tiling_mode, + intel_gen4_compute_page_offset(dev_priv, + &x, &y, obj->tiling_mode, pixel_size, fb->pitches[0]); linear_offset -= sprsurf_offset; + if (plane->state->rotation == BIT(DRM_ROTATE_180)) { + sprctl |= SPRITE_ROTATE_180; + + /* HSW and BDW does this automagically in hardware */ + if (!IS_HASWELL(dev) && !IS_BROADWELL(dev)) { + x += src_w; + y += src_h; + linear_offset += src_h * fb->pitches[0] + + src_w * pixel_size; + } + } + + if (key->flags) { + I915_WRITE(SPRKEYVAL(pipe), key->min_value); + I915_WRITE(SPRKEYMAX(pipe), key->max_value); + I915_WRITE(SPRKEYMSK(pipe), key->channel_mask); + } + + if (key->flags & I915_SET_COLORKEY_DESTINATION) + sprctl |= SPRITE_DEST_KEY; + else if (key->flags & I915_SET_COLORKEY_SOURCE) + sprctl |= SPRITE_SOURCE_KEY; + + I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]); + I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x); + /* HSW consolidates SPRTILEOFF and SPRLINOFF into a single SPROFFSET * register */ - if (IS_HASWELL(dev)) + if (IS_HASWELL(dev) || IS_BROADWELL(dev)) I915_WRITE(SPROFFSET(pipe), (y << 16) | x); else if (obj->tiling_mode != I915_TILING_NONE) I915_WRITE(SPRTILEOFF(pipe), (y << 16) | x); @@ -307,95 +600,32 @@ if (intel_plane->can_scale) I915_WRITE(SPRSCALE(pipe), sprscale); I915_WRITE(SPRCTL(pipe), sprctl); - I915_MODIFY_DISPBASE(SPRSURF(pipe), obj->gtt_offset + sprsurf_offset); + I915_WRITE(SPRSURF(pipe), + i915_gem_obj_ggtt_offset(obj) + sprsurf_offset); POSTING_READ(SPRSURF(pipe)); - - /* potentially re-enable LP watermarks */ - if (scaling_was_enabled && !dev_priv->sprite_scaling_enabled) - intel_update_watermarks(dev); } static void -ivb_disable_plane(struct drm_plane *plane) +ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc) { struct drm_device *dev = plane->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_plane *intel_plane = to_intel_plane(plane); int pipe = intel_plane->pipe; - bool scaling_was_enabled = dev_priv->sprite_scaling_enabled; - I915_WRITE(SPRCTL(pipe), I915_READ(SPRCTL(pipe)) & ~SPRITE_ENABLE); + I915_WRITE(SPRCTL(pipe), 0); /* Can't leave the scaler enabled... */ if (intel_plane->can_scale) I915_WRITE(SPRSCALE(pipe), 0); - /* Activate double buffered register update */ - I915_MODIFY_DISPBASE(SPRSURF(pipe), 0); - POSTING_READ(SPRSURF(pipe)); - - dev_priv->sprite_scaling_enabled &= ~(1 << pipe); - - /* potentially re-enable LP watermarks */ - if (scaling_was_enabled && !dev_priv->sprite_scaling_enabled) - intel_update_watermarks(dev); -} - -static int -ivb_update_colorkey(struct drm_plane *plane, - struct drm_intel_sprite_colorkey *key) -{ - struct drm_device *dev = plane->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_plane *intel_plane; - u32 sprctl; - int ret = 0; - - intel_plane = to_intel_plane(plane); - - I915_WRITE(SPRKEYVAL(intel_plane->pipe), key->min_value); - I915_WRITE(SPRKEYMAX(intel_plane->pipe), key->max_value); - I915_WRITE(SPRKEYMSK(intel_plane->pipe), key->channel_mask); - - sprctl = I915_READ(SPRCTL(intel_plane->pipe)); - sprctl &= ~(SPRITE_SOURCE_KEY | SPRITE_DEST_KEY); - if (key->flags & I915_SET_COLORKEY_DESTINATION) - sprctl |= SPRITE_DEST_KEY; - else if (key->flags & I915_SET_COLORKEY_SOURCE) - sprctl |= SPRITE_SOURCE_KEY; - I915_WRITE(SPRCTL(intel_plane->pipe), sprctl); - - POSTING_READ(SPRKEYMSK(intel_plane->pipe)); - - return ret; -} - -static void -ivb_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key) -{ - struct drm_device *dev = plane->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_plane *intel_plane; - u32 sprctl; - - intel_plane = to_intel_plane(plane); - key->min_value = I915_READ(SPRKEYVAL(intel_plane->pipe)); - key->max_value = I915_READ(SPRKEYMAX(intel_plane->pipe)); - key->channel_mask = I915_READ(SPRKEYMSK(intel_plane->pipe)); - key->flags = 0; - - sprctl = I915_READ(SPRCTL(intel_plane->pipe)); - - if (sprctl & SPRITE_DEST_KEY) - key->flags = I915_SET_COLORKEY_DESTINATION; - else if (sprctl & SPRITE_SOURCE_KEY) - key->flags = I915_SET_COLORKEY_SOURCE; - else - key->flags = I915_SET_COLORKEY_NONE; + I915_WRITE(SPRSURF(pipe), 0); + POSTING_READ(SPRSURF(pipe)); } static void -ilk_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, - struct drm_i915_gem_object *obj, int crtc_x, int crtc_y, +ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, + struct drm_framebuffer *fb, + int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, uint32_t x, uint32_t y, uint32_t src_w, uint32_t src_h) @@ -403,18 +633,15 @@ struct drm_device *dev = plane->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_plane *intel_plane = to_intel_plane(plane); + struct drm_i915_gem_object *obj = intel_fb_obj(fb); int pipe = intel_plane->pipe; unsigned long dvssurf_offset, linear_offset; u32 dvscntr, dvsscale; int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); + const struct drm_intel_sprite_colorkey *key = + &to_intel_plane_state(plane->state)->ckey; - dvscntr = I915_READ(DVSCNTR(pipe)); - - /* Mask out pixel format bits in case we change it */ - dvscntr &= ~DVS_PIXFORMAT_MASK; - dvscntr &= ~DVS_RGB_ORDER_XBGR; - dvscntr &= ~DVS_YUV_BYTE_ORDER_MASK; - dvscntr &= ~DVS_TILED; + dvscntr = DVS_ENABLE; switch (fb->pixel_format) { case DRM_FORMAT_XBGR8888: @@ -439,12 +666,21 @@ BUG(); } + /* + * Enable gamma to match primary/cursor plane behaviour. + * FIXME should be user controllable via propertiesa. + */ + dvscntr |= DVS_GAMMA_ENABLE; + if (obj->tiling_mode != I915_TILING_NONE) dvscntr |= DVS_TILED; if (IS_GEN6(dev)) dvscntr |= DVS_TRICKLE_FEED_DISABLE; /* must disable */ - dvscntr |= DVS_ENABLE; + + intel_update_sprite_watermarks(plane, crtc, src_w, src_h, + pixel_size, true, + src_w != crtc_w || src_h != crtc_h); /* Sizes are 0 based */ src_w--; @@ -452,21 +688,39 @@ crtc_w--; crtc_h--; - intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size); - dvsscale = 0; - if (IS_GEN5(dev) || crtc_w != src_w || crtc_h != src_h) + if (crtc_w != src_w || crtc_h != src_h) dvsscale = DVS_SCALE_ENABLE | (src_w << 16) | src_h; - I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]); - I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x); - linear_offset = y * fb->pitches[0] + x * pixel_size; dvssurf_offset = - intel_gen4_compute_page_offset(&x, &y, obj->tiling_mode, + intel_gen4_compute_page_offset(dev_priv, + &x, &y, obj->tiling_mode, pixel_size, fb->pitches[0]); linear_offset -= dvssurf_offset; + if (plane->state->rotation == BIT(DRM_ROTATE_180)) { + dvscntr |= DVS_ROTATE_180; + + x += src_w; + y += src_h; + linear_offset += src_h * fb->pitches[0] + src_w * pixel_size; + } + + if (key->flags) { + I915_WRITE(DVSKEYVAL(pipe), key->min_value); + I915_WRITE(DVSKEYMAX(pipe), key->max_value); + I915_WRITE(DVSKEYMSK(pipe), key->channel_mask); + } + + if (key->flags & I915_SET_COLORKEY_DESTINATION) + dvscntr |= DVS_DEST_KEY; + else if (key->flags & I915_SET_COLORKEY_SOURCE) + dvscntr |= DVS_SOURCE_KEY; + + I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]); + I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x); + if (obj->tiling_mode != I915_TILING_NONE) I915_WRITE(DVSTILEOFF(pipe), (y << 16) | x); else @@ -475,383 +729,288 @@ I915_WRITE(DVSSIZE(pipe), (crtc_h << 16) | crtc_w); I915_WRITE(DVSSCALE(pipe), dvsscale); I915_WRITE(DVSCNTR(pipe), dvscntr); - I915_MODIFY_DISPBASE(DVSSURF(pipe), obj->gtt_offset + dvssurf_offset); + I915_WRITE(DVSSURF(pipe), + i915_gem_obj_ggtt_offset(obj) + dvssurf_offset); POSTING_READ(DVSSURF(pipe)); } static void -ilk_disable_plane(struct drm_plane *plane) +ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc) { struct drm_device *dev = plane->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_plane *intel_plane = to_intel_plane(plane); int pipe = intel_plane->pipe; - I915_WRITE(DVSCNTR(pipe), I915_READ(DVSCNTR(pipe)) & ~DVS_ENABLE); + I915_WRITE(DVSCNTR(pipe), 0); /* Disable the scaler */ I915_WRITE(DVSSCALE(pipe), 0); - /* Flush double buffered register updates */ - I915_MODIFY_DISPBASE(DVSSURF(pipe), 0); - POSTING_READ(DVSSURF(pipe)); -} - -static void -intel_enable_primary(struct drm_crtc *crtc) -{ - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int reg = DSPCNTR(intel_crtc->plane); - - if (!intel_crtc->primary_disabled) - return; - - intel_crtc->primary_disabled = false; - intel_update_fbc(dev); - - I915_WRITE(reg, I915_READ(reg) | DISPLAY_PLANE_ENABLE); -} -static void -intel_disable_primary(struct drm_crtc *crtc) -{ - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int reg = DSPCNTR(intel_crtc->plane); - - if (intel_crtc->primary_disabled) - return; - - I915_WRITE(reg, I915_READ(reg) & ~DISPLAY_PLANE_ENABLE); - - intel_crtc->primary_disabled = true; - intel_update_fbc(dev); -} - -static int -ilk_update_colorkey(struct drm_plane *plane, - struct drm_intel_sprite_colorkey *key) -{ - struct drm_device *dev = plane->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_plane *intel_plane; - u32 dvscntr; - int ret = 0; - - intel_plane = to_intel_plane(plane); - - I915_WRITE(DVSKEYVAL(intel_plane->pipe), key->min_value); - I915_WRITE(DVSKEYMAX(intel_plane->pipe), key->max_value); - I915_WRITE(DVSKEYMSK(intel_plane->pipe), key->channel_mask); - - dvscntr = I915_READ(DVSCNTR(intel_plane->pipe)); - dvscntr &= ~(DVS_SOURCE_KEY | DVS_DEST_KEY); - if (key->flags & I915_SET_COLORKEY_DESTINATION) - dvscntr |= DVS_DEST_KEY; - else if (key->flags & I915_SET_COLORKEY_SOURCE) - dvscntr |= DVS_SOURCE_KEY; - I915_WRITE(DVSCNTR(intel_plane->pipe), dvscntr); - - POSTING_READ(DVSKEYMSK(intel_plane->pipe)); - - return ret; -} - -static void -ilk_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key) -{ - struct drm_device *dev = plane->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_plane *intel_plane; - u32 dvscntr; - - intel_plane = to_intel_plane(plane); - - key->min_value = I915_READ(DVSKEYVAL(intel_plane->pipe)); - key->max_value = I915_READ(DVSKEYMAX(intel_plane->pipe)); - key->channel_mask = I915_READ(DVSKEYMSK(intel_plane->pipe)); - key->flags = 0; - - dvscntr = I915_READ(DVSCNTR(intel_plane->pipe)); - - if (dvscntr & DVS_DEST_KEY) - key->flags = I915_SET_COLORKEY_DESTINATION; - else if (dvscntr & DVS_SOURCE_KEY) - key->flags = I915_SET_COLORKEY_SOURCE; - else - key->flags = I915_SET_COLORKEY_NONE; + I915_WRITE(DVSSURF(pipe), 0); + POSTING_READ(DVSSURF(pipe)); } static int -intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, - struct drm_framebuffer *fb, int crtc_x, int crtc_y, - unsigned int crtc_w, unsigned int crtc_h, - uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h) +intel_check_sprite_plane(struct drm_plane *plane, + struct intel_crtc_state *crtc_state, + struct intel_plane_state *state) { struct drm_device *dev = plane->dev; - struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_crtc *crtc = state->base.crtc; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_plane *intel_plane = to_intel_plane(plane); - struct intel_framebuffer *intel_fb; - struct drm_i915_gem_object *obj, *old_obj; - int pipe = intel_plane->pipe; - enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, - pipe); - int ret = 0; - int x = src_x >> 16, y = src_y >> 16; - int primary_w = crtc->mode.hdisplay, primary_h = crtc->mode.vdisplay; - bool disable_primary = false; - - intel_fb = to_intel_framebuffer(fb); - obj = intel_fb->obj; - - old_obj = intel_plane->obj; - - intel_plane->crtc_x = crtc_x; - intel_plane->crtc_y = crtc_y; - intel_plane->crtc_w = crtc_w; - intel_plane->crtc_h = crtc_h; - intel_plane->src_x = src_x; - intel_plane->src_y = src_y; - intel_plane->src_w = src_w; - intel_plane->src_h = src_h; - - src_w = src_w >> 16; - src_h = src_h >> 16; - - /* Pipe must be running... */ - if (!(I915_READ(PIPECONF(cpu_transcoder)) & PIPECONF_ENABLE)) - return -EINVAL; - - if (crtc_x >= primary_w || crtc_y >= primary_h) - return -EINVAL; + struct drm_framebuffer *fb = state->base.fb; + int crtc_x, crtc_y; + unsigned int crtc_w, crtc_h; + uint32_t src_x, src_y, src_w, src_h; + struct drm_rect *src = &state->src; + struct drm_rect *dst = &state->dst; + const struct drm_rect *clip = &state->clip; + int hscale, vscale; + int max_scale, min_scale; + bool can_scale; + int pixel_size; + + if (!fb) { + state->visible = false; + return 0; + } /* Don't modify another pipe's plane */ - if (intel_plane->pipe != intel_crtc->pipe) + if (intel_plane->pipe != intel_crtc->pipe) { + DRM_DEBUG_KMS("Wrong plane <-> crtc mapping\n"); return -EINVAL; - - /* Sprite planes can be linear or x-tiled surfaces */ - switch (obj->tiling_mode) { - case I915_TILING_NONE: - case I915_TILING_X: - break; - default: - return -EINVAL; } - /* - * Clamp the width & height into the visible area. Note we don't - * try to scale the source if part of the visible region is offscreen. - * The caller must handle that by adjusting source offset and size. - */ - if ((crtc_x < 0) && ((crtc_x + crtc_w) > 0)) { - crtc_w += crtc_x; - crtc_x = 0; + /* FIXME check all gen limits */ + if (fb->width < 3 || fb->height < 3 || fb->pitches[0] > 16384) { + DRM_DEBUG_KMS("Unsuitable framebuffer for plane\n"); + return -EINVAL; } - if ((crtc_x + crtc_w) <= 0) /* Nothing to display */ - goto out; - if ((crtc_x + crtc_w) > primary_w) - crtc_w = primary_w - crtc_x; - if ((crtc_y < 0) && ((crtc_y + crtc_h) > 0)) { - crtc_h += crtc_y; - crtc_y = 0; + /* setup can_scale, min_scale, max_scale */ + if (INTEL_INFO(dev)->gen >= 9) { + /* use scaler when colorkey is not required */ + if (state->ckey.flags == I915_SET_COLORKEY_NONE) { + can_scale = 1; + min_scale = 1; + max_scale = skl_max_scale(intel_crtc, crtc_state); + } else { + can_scale = 0; + min_scale = DRM_PLANE_HELPER_NO_SCALING; + max_scale = DRM_PLANE_HELPER_NO_SCALING; + } + } else { + can_scale = intel_plane->can_scale; + max_scale = intel_plane->max_downscale << 16; + min_scale = intel_plane->can_scale ? 1 : (1 << 16); } - if ((crtc_y + crtc_h) <= 0) /* Nothing to display */ - goto out; - if (crtc_y + crtc_h > primary_h) - crtc_h = primary_h - crtc_y; - - if (!crtc_w || !crtc_h) /* Again, nothing to display */ - goto out; /* - * We may not have a scaler, eg. HSW does not have it any more + * FIXME the following code does a bunch of fuzzy adjustments to the + * coordinates and sizes. We probably need some way to decide whether + * more strict checking should be done instead. */ - if (!intel_plane->can_scale && (crtc_w != src_w || crtc_h != src_h)) - return -EINVAL; + drm_rect_rotate(src, fb->width << 16, fb->height << 16, + state->base.rotation); - /* - * We can take a larger source and scale it down, but - * only so much... 16x is the max on SNB. - */ - if (((src_w * src_h) / (crtc_w * crtc_h)) > intel_plane->max_downscale) - return -EINVAL; + hscale = drm_rect_calc_hscale_relaxed(src, dst, min_scale, max_scale); + BUG_ON(hscale < 0); - /* - * If the sprite is completely covering the primary plane, - * we can disable the primary and save power. - */ - if ((crtc_x == 0) && (crtc_y == 0) && - (crtc_w == primary_w) && (crtc_h == primary_h)) - disable_primary = true; - - mutex_lock(&dev->struct_mutex); - - /* Note that this will apply the VT-d workaround for scanouts, - * which is more restrictive than required for sprites. (The - * primary plane requires 256KiB alignment with 64 PTE padding, - * the sprite planes only require 128KiB alignment and 32 PTE padding. - */ - ret = intel_pin_and_fence_fb_obj(dev, obj, NULL); - if (ret) - goto out_unlock; + vscale = drm_rect_calc_vscale_relaxed(src, dst, min_scale, max_scale); + BUG_ON(vscale < 0); - intel_plane->obj = obj; + state->visible = drm_rect_clip_scaled(src, dst, clip, hscale, vscale); + + crtc_x = dst->x1; + crtc_y = dst->y1; + crtc_w = drm_rect_width(dst); + crtc_h = drm_rect_height(dst); + + if (state->visible) { + /* check again in case clipping clamped the results */ + hscale = drm_rect_calc_hscale(src, dst, min_scale, max_scale); + if (hscale < 0) { + DRM_DEBUG_KMS("Horizontal scaling factor out of limits\n"); + drm_rect_debug_print(src, true); + drm_rect_debug_print(dst, false); - /* - * Be sure to re-enable the primary before the sprite is no longer - * covering it fully. - */ - if (!disable_primary) - intel_enable_primary(crtc); + return hscale; + } - intel_plane->update_plane(plane, fb, obj, crtc_x, crtc_y, - crtc_w, crtc_h, x, y, src_w, src_h); + vscale = drm_rect_calc_vscale(src, dst, min_scale, max_scale); + if (vscale < 0) { + DRM_DEBUG_KMS("Vertical scaling factor out of limits\n"); + drm_rect_debug_print(src, true); + drm_rect_debug_print(dst, false); - if (disable_primary) - intel_disable_primary(crtc); + return vscale; + } + + /* Make the source viewport size an exact multiple of the scaling factors. */ + drm_rect_adjust_size(src, + drm_rect_width(dst) * hscale - drm_rect_width(src), + drm_rect_height(dst) * vscale - drm_rect_height(src)); + + drm_rect_rotate_inv(src, fb->width << 16, fb->height << 16, + state->base.rotation); + + /* sanity check to make sure the src viewport wasn't enlarged */ + WARN_ON(src->x1 < (int) state->base.src_x || + src->y1 < (int) state->base.src_y || + src->x2 > (int) state->base.src_x + state->base.src_w || + src->y2 > (int) state->base.src_y + state->base.src_h); - /* Unpin old obj after new one is active to avoid ugliness */ - if (old_obj) { /* - * It's fairly common to simply update the position of - * an existing object. In that case, we don't need to - * wait for vblank to avoid ugliness, we only need to - * do the pin & ref bookkeeping. + * Hardware doesn't handle subpixel coordinates. + * Adjust to (macro)pixel boundary, but be careful not to + * increase the source viewport size, because that could + * push the downscaling factor out of bounds. */ - if (old_obj != obj) { - mutex_unlock(&dev->struct_mutex); - intel_wait_for_vblank(dev, to_intel_crtc(crtc)->pipe); - mutex_lock(&dev->struct_mutex); + src_x = src->x1 >> 16; + src_w = drm_rect_width(src) >> 16; + src_y = src->y1 >> 16; + src_h = drm_rect_height(src) >> 16; + + if (format_is_yuv(fb->pixel_format)) { + src_x &= ~1; + src_w &= ~1; + + /* + * Must keep src and dst the + * same if we can't scale. + */ + if (!can_scale) + crtc_w &= ~1; + + if (crtc_w == 0) + state->visible = false; } - intel_unpin_fb_obj(old_obj); } -out_unlock: - mutex_unlock(&dev->struct_mutex); -out: - return ret; -} + /* Check size restrictions when scaling */ + if (state->visible && (src_w != crtc_w || src_h != crtc_h)) { + unsigned int width_bytes; -static int -intel_disable_plane(struct drm_plane *plane) -{ - struct drm_device *dev = plane->dev; - struct intel_plane *intel_plane = to_intel_plane(plane); - int ret = 0; + WARN_ON(!can_scale); - if (plane->crtc) - intel_enable_primary(plane->crtc); - intel_plane->disable_plane(plane); + /* FIXME interlacing min height is 6 */ - if (!intel_plane->obj) - goto out; + if (crtc_w < 3 || crtc_h < 3) + state->visible = false; - intel_wait_for_vblank(dev, intel_plane->pipe); + if (src_w < 3 || src_h < 3) + state->visible = false; - mutex_lock(&dev->struct_mutex); - intel_unpin_fb_obj(intel_plane->obj); - intel_plane->obj = NULL; - mutex_unlock(&dev->struct_mutex); -out: + pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); + width_bytes = ((src_x * pixel_size) & 63) + + src_w * pixel_size; - return ret; + if (INTEL_INFO(dev)->gen < 9 && (src_w > 2048 || src_h > 2048 || + width_bytes > 4096 || fb->pitches[0] > 4096)) { + DRM_DEBUG_KMS("Source dimensions exceed hardware limits\n"); + return -EINVAL; + } + } + + if (state->visible) { + src->x1 = src_x << 16; + src->x2 = (src_x + src_w) << 16; + src->y1 = src_y << 16; + src->y2 = (src_y + src_h) << 16; + } + + dst->x1 = crtc_x; + dst->x2 = crtc_x + crtc_w; + dst->y1 = crtc_y; + dst->y2 = crtc_y + crtc_h; + + return 0; } -static void intel_destroy_plane(struct drm_plane *plane) +static void +intel_commit_sprite_plane(struct drm_plane *plane, + struct intel_plane_state *state) { + struct drm_crtc *crtc = state->base.crtc; struct intel_plane *intel_plane = to_intel_plane(plane); - intel_disable_plane(plane); - drm_plane_cleanup(plane); - kfree(intel_plane); + struct drm_framebuffer *fb = state->base.fb; + + crtc = crtc ? crtc : plane->crtc; + + if (!crtc->state->active) + return; + + if (state->visible) { + intel_plane->update_plane(plane, crtc, fb, + state->dst.x1, state->dst.y1, + drm_rect_width(&state->dst), + drm_rect_height(&state->dst), + state->src.x1 >> 16, + state->src.y1 >> 16, + drm_rect_width(&state->src) >> 16, + drm_rect_height(&state->src) >> 16); + } else { + intel_plane->disable_plane(plane, crtc); + } } int intel_sprite_set_colorkey(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_intel_sprite_colorkey *set = data; - struct drm_mode_object *obj; struct drm_plane *plane; - struct intel_plane *intel_plane; + struct drm_plane_state *plane_state; + struct drm_atomic_state *state; + struct drm_modeset_acquire_ctx ctx; int ret = 0; - if (!drm_core_check_feature(dev, DRIVER_MODESET)) - return -ENODEV; - /* Make sure we don't try to enable both src & dest simultaneously */ if ((set->flags & (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) == (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) return -EINVAL; - drm_modeset_lock_all(dev); + if (IS_VALLEYVIEW(dev) && + set->flags & I915_SET_COLORKEY_DESTINATION) + return -EINVAL; - obj = drm_mode_object_find(dev, set->plane_id, DRM_MODE_OBJECT_PLANE); - if (!obj) { - ret = -EINVAL; - goto out_unlock; + plane = drm_plane_find(dev, set->plane_id); + if (!plane || plane->type != DRM_PLANE_TYPE_OVERLAY) + return -ENOENT; + + drm_modeset_acquire_init(&ctx, 0); + + state = drm_atomic_state_alloc(plane->dev); + if (!state) { + ret = -ENOMEM; + goto out; } + state->acquire_ctx = &ctx; - plane = obj_to_plane(obj); - intel_plane = to_intel_plane(plane); - ret = intel_plane->update_colorkey(plane, set); - -out_unlock: - drm_modeset_unlock_all(dev); - return ret; -} - -int intel_sprite_get_colorkey(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_intel_sprite_colorkey *get = data; - struct drm_mode_object *obj; - struct drm_plane *plane; - struct intel_plane *intel_plane; - int ret = 0; - - if (!drm_core_check_feature(dev, DRIVER_MODESET)) - return -ENODEV; + while (1) { + plane_state = drm_atomic_get_plane_state(state, plane); + ret = PTR_ERR_OR_ZERO(plane_state); + if (!ret) { + to_intel_plane_state(plane_state)->ckey = *set; + ret = drm_atomic_commit(state); + } - drm_modeset_lock_all(dev); + if (ret != -EDEADLK) + break; - obj = drm_mode_object_find(dev, get->plane_id, DRM_MODE_OBJECT_PLANE); - if (!obj) { - ret = -EINVAL; - goto out_unlock; + drm_atomic_state_clear(state); + drm_modeset_backoff(&ctx); } - plane = obj_to_plane(obj); - intel_plane = to_intel_plane(plane); - intel_plane->get_colorkey(plane, get); + if (ret) + drm_atomic_state_free(state); -out_unlock: - drm_modeset_unlock_all(dev); +out: + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); return ret; } -void intel_plane_restore(struct drm_plane *plane) -{ - struct intel_plane *intel_plane = to_intel_plane(plane); - - if (!plane->crtc || !plane->fb) - return; - - intel_update_plane(plane, plane->crtc, plane->fb, - intel_plane->crtc_x, intel_plane->crtc_y, - intel_plane->crtc_w, intel_plane->crtc_h, - intel_plane->src_x, intel_plane->src_y, - intel_plane->src_w, intel_plane->src_h); -} - -static const struct drm_plane_funcs intel_plane_funcs = { - .update_plane = intel_update_plane, - .disable_plane = intel_disable_plane, - .destroy = intel_destroy_plane, -}; - -static uint32_t ilk_plane_formats[] = { +static const uint32_t ilk_plane_formats[] = { DRM_FORMAT_XRGB8888, DRM_FORMAT_YUYV, DRM_FORMAT_YVYU, @@ -859,7 +1018,7 @@ DRM_FORMAT_VYUY, }; -static uint32_t snb_plane_formats[] = { +static const uint32_t snb_plane_formats[] = { DRM_FORMAT_XBGR8888, DRM_FORMAT_XRGB8888, DRM_FORMAT_YUYV, @@ -868,7 +1027,7 @@ DRM_FORMAT_VYUY, }; -static uint32_t vlv_plane_formats[] = { +static const uint32_t vlv_plane_formats[] = { DRM_FORMAT_RGB565, DRM_FORMAT_ABGR8888, DRM_FORMAT_ARGB8888, @@ -882,10 +1041,23 @@ DRM_FORMAT_VYUY, }; +static uint32_t skl_plane_formats[] = { + DRM_FORMAT_RGB565, + DRM_FORMAT_ABGR8888, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_XBGR8888, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_YUYV, + DRM_FORMAT_YVYU, + DRM_FORMAT_UYVY, + DRM_FORMAT_VYUY, +}; + int intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane) { struct intel_plane *intel_plane; + struct intel_plane_state *state; unsigned long possible_crtcs; const uint32_t *plane_formats; int num_plane_formats; @@ -894,10 +1066,17 @@ if (INTEL_INFO(dev)->gen < 5) return -ENODEV; - intel_plane = kzalloc(sizeof(struct intel_plane), GFP_KERNEL); + intel_plane = kzalloc(sizeof(*intel_plane), GFP_KERNEL); if (!intel_plane) return -ENOMEM; + state = intel_create_plane_state(&intel_plane->base); + if (!state) { + kfree(intel_plane); + return -ENOMEM; + } + intel_plane->base.state = &state->base; + switch (INTEL_INFO(dev)->gen) { case 5: case 6: @@ -905,8 +1084,6 @@ intel_plane->max_downscale = 16; intel_plane->update_plane = ilk_update_plane; intel_plane->disable_plane = ilk_disable_plane; - intel_plane->update_colorkey = ilk_update_colorkey; - intel_plane->get_colorkey = ilk_get_colorkey; if (IS_GEN6(dev)) { plane_formats = snb_plane_formats; @@ -918,32 +1095,38 @@ break; case 7: - if (IS_HASWELL(dev) || IS_VALLEYVIEW(dev)) - intel_plane->can_scale = false; - else + case 8: + if (IS_IVYBRIDGE(dev)) { intel_plane->can_scale = true; + intel_plane->max_downscale = 2; + } else { + intel_plane->can_scale = false; + intel_plane->max_downscale = 1; + } if (IS_VALLEYVIEW(dev)) { - intel_plane->max_downscale = 1; intel_plane->update_plane = vlv_update_plane; intel_plane->disable_plane = vlv_disable_plane; - intel_plane->update_colorkey = vlv_update_colorkey; - intel_plane->get_colorkey = vlv_get_colorkey; plane_formats = vlv_plane_formats; num_plane_formats = ARRAY_SIZE(vlv_plane_formats); } else { - intel_plane->max_downscale = 2; intel_plane->update_plane = ivb_update_plane; intel_plane->disable_plane = ivb_disable_plane; - intel_plane->update_colorkey = ivb_update_colorkey; - intel_plane->get_colorkey = ivb_get_colorkey; plane_formats = snb_plane_formats; num_plane_formats = ARRAY_SIZE(snb_plane_formats); } break; + case 9: + intel_plane->can_scale = true; + intel_plane->update_plane = skl_update_plane; + intel_plane->disable_plane = skl_disable_plane; + state->scaler_id = -1; + plane_formats = skl_plane_formats; + num_plane_formats = ARRAY_SIZE(skl_plane_formats); + break; default: kfree(intel_plane); return -ENODEV; @@ -951,13 +1134,23 @@ intel_plane->pipe = pipe; intel_plane->plane = plane; + intel_plane->frontbuffer_bit = INTEL_FRONTBUFFER_SPRITE(pipe, plane); + intel_plane->check_plane = intel_check_sprite_plane; + intel_plane->commit_plane = intel_commit_sprite_plane; possible_crtcs = (1 << pipe); - ret = drm_plane_init(dev, &intel_plane->base, possible_crtcs, - &intel_plane_funcs, - plane_formats, num_plane_formats, - false); - if (ret) + ret = drm_universal_plane_init(dev, &intel_plane->base, possible_crtcs, + &intel_plane_funcs, + plane_formats, num_plane_formats, + DRM_PLANE_TYPE_OVERLAY); + if (ret) { kfree(intel_plane); + goto out; + } + intel_create_rotation_property(dev, intel_plane); + + drm_plane_helper_add(&intel_plane->base, &intel_plane_helper_funcs); + +out: return ret; }