diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_sprite.c')
-rw-r--r-- | drivers/gpu/drm/i915/intel_sprite.c | 1087 |
1 files changed, 506 insertions, 581 deletions
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 07a74ef589bd..e3d41c096dc6 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -33,10 +33,25 @@ #include <drm/drm_crtc.h> #include <drm/drm_fourcc.h> #include <drm/drm_rect.h> +#include <drm/drm_plane_helper.h> #include "intel_drv.h" #include <drm/i915_drm.h> #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 *mode, int usecs) { /* paranoia */ @@ -46,18 +61,32 @@ static int usecs_to_scanlines(const struct drm_display_mode *mode, int usecs) return DIV_ROUND_UP(usecs * mode->crtc_clock, 1000 * mode->crtc_htotal); } -static bool intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl_count) +/** + * 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. + * + * Return: true if the call was successful + */ +bool intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl_count) { struct drm_device *dev = crtc->base.dev; - const struct drm_display_mode *mode = &crtc->config.adjusted_mode; + const struct drm_display_mode *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); - WARN_ON(!drm_modeset_is_locked(&crtc->base.mutex)); - vblank_start = mode->crtc_vblank_start; if (mode->flags & DRM_MODE_FLAG_INTERLACE) vblank_start = DIV_ROUND_UP(vblank_start, 2); @@ -69,7 +98,7 @@ static bool intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl if (min <= 0 || max <= 0) return false; - if (WARN_ON(drm_vblank_get(dev, pipe))) + if (WARN_ON(drm_crtc_vblank_get(&crtc->base))) return false; local_irq_disable(); @@ -103,7 +132,7 @@ static bool intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl finish_wait(wq, &wait); - drm_vblank_put(dev, pipe); + drm_crtc_vblank_put(&crtc->base); *start_vbl_count = dev->driver->get_vblank_counter(dev, pipe); @@ -112,7 +141,16 @@ static bool intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl return true; } -static void intel_pipe_update_end(struct intel_crtc *crtc, u32 start_vbl_count) +/** + * 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, u32 start_vbl_count) { struct drm_device *dev = crtc->base.dev; enum pipe pipe = crtc->pipe; @@ -139,9 +177,213 @@ static void intel_update_primary_plane(struct intel_crtc *crtc) } static void +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 = &intel_plane->ckey; + unsigned long surf_addr; + u32 tile_height, plane_offset, plane_size; + unsigned int rotation; + int x_offset, y_offset; + + plane_ctl = PLANE_CTL_ENABLE | + PLANE_CTL_PIPE_CSC_ENABLE; + + switch (fb->pixel_format) { + case DRM_FORMAT_RGB565: + plane_ctl |= PLANE_CTL_FORMAT_RGB_565; + break; + case DRM_FORMAT_XBGR8888: + plane_ctl |= PLANE_CTL_FORMAT_XRGB_8888 | PLANE_CTL_ORDER_RGBX; + break; + case DRM_FORMAT_XRGB8888: + plane_ctl |= PLANE_CTL_FORMAT_XRGB_8888; + break; + /* + * XXX: For ARBG/ABGR formats we default to expecting scanout buffers + * to be already pre-multiplied. We need to add a knob (or a different + * DRM_FORMAT) for user-space to configure that. + */ + case DRM_FORMAT_ABGR8888: + plane_ctl |= PLANE_CTL_FORMAT_XRGB_8888 | + PLANE_CTL_ORDER_RGBX | + PLANE_CTL_ALPHA_SW_PREMULTIPLY; + break; + case DRM_FORMAT_ARGB8888: + plane_ctl |= PLANE_CTL_FORMAT_XRGB_8888 | + PLANE_CTL_ALPHA_SW_PREMULTIPLY; + break; + case DRM_FORMAT_YUYV: + plane_ctl |= PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_YUYV; + break; + case DRM_FORMAT_YVYU: + plane_ctl |= PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_YVYU; + break; + case DRM_FORMAT_UYVY: + plane_ctl |= PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_UYVY; + break; + case DRM_FORMAT_VYUY: + plane_ctl |= PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_VYUY; + break; + default: + BUG(); + } + + switch (fb->modifier[0]) { + case DRM_FORMAT_MOD_NONE: + break; + case I915_FORMAT_MOD_X_TILED: + plane_ctl |= PLANE_CTL_TILED_X; + break; + case I915_FORMAT_MOD_Y_TILED: + plane_ctl |= PLANE_CTL_TILED_Y; + break; + case I915_FORMAT_MOD_Yf_TILED: + plane_ctl |= PLANE_CTL_TILED_YF; + break; + default: + MISSING_CASE(fb->modifier[0]); + } + + rotation = drm_plane->state->rotation; + switch (rotation) { + case BIT(DRM_ROTATE_90): + plane_ctl |= PLANE_CTL_ROTATE_90; + break; + + case BIT(DRM_ROTATE_180): + plane_ctl |= PLANE_CTL_ROTATE_180; + break; + + case BIT(DRM_ROTATE_270): + plane_ctl |= PLANE_CTL_ROTATE_270; + break; + } + + 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); + + /* 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); + + if (intel_rotation_90_or_270(rotation)) { + /* stride: Surface height in tiles */ + tile_height = intel_tile_height(dev, fb->bits_per_pixel, + fb->modifier[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_POS(pipe, plane), (crtc_y << 16) | crtc_x); + I915_WRITE(PLANE_SIZE(pipe, plane), plane_size); + 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 *drm_plane, struct drm_crtc *crtc) +{ + 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); + const int pipe = intel_plane->pipe; + const int plane = intel_plane->plane + 1; + + I915_WRITE(PLANE_CTL(pipe, plane), 0); + + /* Activate double buffered register update */ + I915_WRITE(PLANE_SURF(pipe, plane), 0); + POSTING_READ(PLANE_SURF(pipe, plane)); + + intel_update_sprite_watermarks(drm_plane, 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, - struct drm_i915_gem_object *obj, int crtc_x, int crtc_y, + 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) @@ -150,21 +392,15 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, struct drm_i915_private *dev_priv = dev->dev_private; struct intel_plane *intel_plane = to_intel_plane(dplane); struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + 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); - u32 start_vbl_count; - bool atomic_update; - - sprctl = I915_READ(SPCNTR(pipe, plane)); + const struct drm_intel_sprite_colorkey *key = &intel_plane->ckey; - /* 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_ROTATE_180; + sprctl = SP_ENABLE; switch (fb->pixel_format) { case DRM_FORMAT_YUYV: @@ -218,8 +454,6 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, if (obj->tiling_mode != I915_TILING_NONE) sprctl |= SP_TILED; - sprctl |= SP_ENABLE; - intel_update_sprite_watermarks(dplane, crtc, src_w, src_h, pixel_size, true, src_w != crtc_w || src_h != crtc_h); @@ -237,7 +471,7 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, fb->pitches[0]); linear_offset -= sprsurf_offset; - if (intel_plane->rotation == BIT(DRM_ROTATE_180)) { + if (dplane->state->rotation == BIT(DRM_ROTATE_180)) { sprctl |= SP_ROTATE_180; x += src_w; @@ -245,10 +479,20 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, linear_offset += src_h * fb->pitches[0] + src_w * pixel_size; } - atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count); - intel_update_primary_plane(intel_crtc); + 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); @@ -257,15 +501,14 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, 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_WRITE(SPSURF(pipe, plane), i915_gem_obj_ggtt_offset(obj) + sprsurf_offset); intel_flush_primary_plane(dev_priv, intel_crtc->plane); - - if (atomic_update) - intel_pipe_update_end(intel_crtc, start_vbl_count); } static void @@ -277,81 +520,24 @@ vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc) struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_plane->pipe; int plane = intel_plane->plane; - u32 start_vbl_count; - bool atomic_update; - - atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count); intel_update_primary_plane(intel_crtc); - I915_WRITE(SPCNTR(pipe, plane), I915_READ(SPCNTR(pipe, plane)) & - ~SP_ENABLE); + I915_WRITE(SPCNTR(pipe, plane), 0); + /* Activate double buffered register update */ I915_WRITE(SPSURF(pipe, plane), 0); intel_flush_primary_plane(dev_priv, intel_crtc->plane); - if (atomic_update) - intel_pipe_update_end(intel_crtc, start_vbl_count); - intel_update_sprite_watermarks(dplane, crtc, 0, 0, 0, false, false); } -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)); - - 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; -} static void ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_framebuffer *fb, - struct drm_i915_gem_object *obj, int crtc_x, int crtc_y, + 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) @@ -360,21 +546,14 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_i915_private *dev_priv = dev->dev_private; struct intel_plane *intel_plane = to_intel_plane(plane); struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - 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); - u32 start_vbl_count; - bool atomic_update; - - sprctl = I915_READ(SPRCTL(pipe)); + const struct drm_intel_sprite_colorkey *key = &intel_plane->ckey; - /* 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_ROTATE_180; + sprctl = SPRITE_ENABLE; switch (fb->pixel_format) { case DRM_FORMAT_XBGR8888: @@ -413,8 +592,6 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, else sprctl |= SPRITE_TRICKLE_FEED_DISABLE; - sprctl |= SPRITE_ENABLE; - if (IS_HASWELL(dev) || IS_BROADWELL(dev)) sprctl |= SPRITE_PIPE_CSC_ENABLE; @@ -437,7 +614,7 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, pixel_size, fb->pitches[0]); linear_offset -= sprsurf_offset; - if (intel_plane->rotation == BIT(DRM_ROTATE_180)) { + if (plane->state->rotation == BIT(DRM_ROTATE_180)) { sprctl |= SPRITE_ROTATE_180; /* HSW and BDW does this automagically in hardware */ @@ -449,10 +626,19 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, } } - atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count); - intel_update_primary_plane(intel_crtc); + 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); @@ -473,9 +659,6 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, i915_gem_obj_ggtt_offset(obj) + sprsurf_offset); intel_flush_primary_plane(dev_priv, intel_crtc->plane); - - if (atomic_update) - intel_pipe_update_end(intel_crtc, start_vbl_count); } static void @@ -486,10 +669,6 @@ ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc) struct intel_plane *intel_plane = to_intel_plane(plane); struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_plane->pipe; - u32 start_vbl_count; - bool atomic_update; - - atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count); intel_update_primary_plane(intel_crtc); @@ -501,77 +680,12 @@ ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc) I915_WRITE(SPRSURF(pipe), 0); intel_flush_primary_plane(dev_priv, intel_crtc->plane); - - if (atomic_update) - intel_pipe_update_end(intel_crtc, start_vbl_count); - - /* - * Avoid underruns when disabling the sprite. - * FIXME remove once watermark updates are done properly. - */ - intel_wait_for_vblank(dev, pipe); - - intel_update_sprite_watermarks(plane, crtc, 0, 0, 0, false, false); -} - -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; } static void ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_framebuffer *fb, - struct drm_i915_gem_object *obj, int crtc_x, int crtc_y, + 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) @@ -580,21 +694,14 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_i915_private *dev_priv = dev->dev_private; struct intel_plane *intel_plane = to_intel_plane(plane); struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + 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); - u32 start_vbl_count; - bool atomic_update; + const struct drm_intel_sprite_colorkey *key = &intel_plane->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_ROTATE_180; + dvscntr = DVS_ENABLE; switch (fb->pixel_format) { case DRM_FORMAT_XBGR8888: @@ -630,7 +737,6 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, 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, @@ -652,7 +758,7 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, pixel_size, fb->pitches[0]); linear_offset -= dvssurf_offset; - if (intel_plane->rotation == BIT(DRM_ROTATE_180)) { + if (plane->state->rotation == BIT(DRM_ROTATE_180)) { dvscntr |= DVS_ROTATE_180; x += src_w; @@ -660,10 +766,19 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, linear_offset += src_h * fb->pitches[0] + src_w * pixel_size; } - atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count); - intel_update_primary_plane(intel_crtc); + 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); @@ -679,9 +794,6 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, i915_gem_obj_ggtt_offset(obj) + dvssurf_offset); intel_flush_primary_plane(dev_priv, intel_crtc->plane); - - if (atomic_update) - intel_pipe_update_end(intel_crtc, start_vbl_count); } static void @@ -692,34 +804,30 @@ ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc) struct intel_plane *intel_plane = to_intel_plane(plane); struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_plane->pipe; - u32 start_vbl_count; - bool atomic_update; - - atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count); intel_update_primary_plane(intel_crtc); - 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_WRITE(DVSSURF(pipe), 0); intel_flush_primary_plane(dev_priv, intel_crtc->plane); - - if (atomic_update) - intel_pipe_update_end(intel_crtc, start_vbl_count); - - /* - * Avoid underruns when disabling the sprite. - * FIXME remove once watermark updates are done properly. - */ - intel_wait_for_vblank(dev, pipe); - - intel_update_sprite_watermarks(plane, crtc, 0, 0, 0, false, false); } -static void +/** + * intel_post_enable_primary - Perform operations after enabling primary plane + * @crtc: the CRTC whose primary plane was just enabled + * + * Performs potentially sleeping operations that must be done after the primary + * plane is enabled, such as updating FBC and IPS. Note that this may be + * called due to an explicit primary plane update, or due to an implicit + * re-enable that is caused when a sprite plane is updated to no longer + * completely hide the primary plane. + */ +void intel_post_enable_primary(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -742,11 +850,21 @@ intel_post_enable_primary(struct drm_crtc *crtc) hsw_enable_ips(intel_crtc); mutex_lock(&dev->struct_mutex); - intel_update_fbc(dev); + intel_fbc_update(dev); mutex_unlock(&dev->struct_mutex); } -static void +/** + * intel_pre_disable_primary - Perform operations before disabling primary plane + * @crtc: the CRTC whose primary plane is to be disabled + * + * Performs potentially sleeping operations that must be done before the + * primary plane is enabled, such as updating FBC and IPS. Note that this may + * be called due to an explicit primary plane update, or due to an implicit + * disable that is caused when a sprite plane completely hides the primary + * plane. + */ +void intel_pre_disable_primary(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -754,8 +872,8 @@ intel_pre_disable_primary(struct drm_crtc *crtc) struct intel_crtc *intel_crtc = to_intel_crtc(crtc); mutex_lock(&dev->struct_mutex); - if (dev_priv->fbc.plane == intel_crtc->plane) - intel_disable_fbc(dev); + if (dev_priv->fbc.crtc == intel_crtc) + intel_fbc_disable(dev); mutex_unlock(&dev->struct_mutex); /* @@ -767,135 +885,34 @@ intel_pre_disable_primary(struct drm_crtc *crtc) hsw_disable_ips(intel_crtc); } -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; -} - -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 bool colorkey_enabled(struct intel_plane *intel_plane) { - struct drm_intel_sprite_colorkey key; - - intel_plane->get_colorkey(&intel_plane->base, &key); - - return key.flags != I915_SET_COLORKEY_NONE; + return intel_plane->ckey.flags != I915_SET_COLORKEY_NONE; } 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_plane_state *state) { - struct drm_device *dev = plane->dev; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_crtc *intel_crtc = to_intel_crtc(state->base.crtc); struct intel_plane *intel_plane = to_intel_plane(plane); - enum pipe pipe = intel_crtc->pipe; - struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); - struct drm_i915_gem_object *obj = intel_fb->obj; - struct drm_i915_gem_object *old_obj = intel_plane->obj; - int ret; - bool primary_enabled; - bool visible; + 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; - int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); - struct drm_rect src = { - /* sample coordinates in 16.16 fixed point */ - .x1 = src_x, - .x2 = src_x + src_w, - .y1 = src_y, - .y2 = src_y + src_h, - }; - struct drm_rect dst = { - /* integer pixels */ - .x1 = crtc_x, - .x2 = crtc_x + crtc_w, - .y1 = crtc_y, - .y2 = crtc_y + crtc_h, - }; - const struct drm_rect clip = { - .x2 = intel_crtc->active ? intel_crtc->config.pipe_src_w : 0, - .y2 = intel_crtc->active ? intel_crtc->config.pipe_src_h : 0, - }; - const struct { - int crtc_x, crtc_y; - unsigned int crtc_w, crtc_h; - uint32_t src_x, src_y, src_w, src_h; - } orig = { - .crtc_x = crtc_x, - .crtc_y = crtc_y, - .crtc_w = crtc_w, - .crtc_h = crtc_h, - .src_x = src_x, - .src_y = src_y, - .src_w = src_w, - .src_h = src_h, - }; + int pixel_size; + + intel_crtc = intel_crtc ? intel_crtc : to_intel_crtc(plane->crtc); + + if (!fb) { + state->visible = false; + goto finish; + } /* Don't modify another pipe's plane */ if (intel_plane->pipe != intel_crtc->pipe) { @@ -909,16 +926,6 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, 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: - DRM_DEBUG_KMS("Unsupported tiling mode\n"); - return -EINVAL; - } - /* * FIXME the following code does a bunch of fuzzy adjustments to the * coordinates and sizes. We probably need some way to decide whether @@ -927,55 +934,55 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, max_scale = intel_plane->max_downscale << 16; min_scale = intel_plane->can_scale ? 1 : (1 << 16); - drm_rect_rotate(&src, fb->width << 16, fb->height << 16, - intel_plane->rotation); + drm_rect_rotate(src, fb->width << 16, fb->height << 16, + state->base.rotation); - hscale = drm_rect_calc_hscale_relaxed(&src, &dst, min_scale, max_scale); + hscale = drm_rect_calc_hscale_relaxed(src, dst, min_scale, max_scale); BUG_ON(hscale < 0); - vscale = drm_rect_calc_vscale_relaxed(&src, &dst, min_scale, max_scale); + vscale = drm_rect_calc_vscale_relaxed(src, dst, min_scale, max_scale); BUG_ON(vscale < 0); - visible = drm_rect_clip_scaled(&src, &dst, &clip, hscale, vscale); + 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); + crtc_x = dst->x1; + crtc_y = dst->y1; + crtc_w = drm_rect_width(dst); + crtc_h = drm_rect_height(dst); - if (visible) { + if (state->visible) { /* check again in case clipping clamped the results */ - hscale = drm_rect_calc_hscale(&src, &dst, min_scale, max_scale); + 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); + drm_rect_debug_print(src, true); + drm_rect_debug_print(dst, false); return hscale; } - vscale = drm_rect_calc_vscale(&src, &dst, min_scale, max_scale); + 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); + drm_rect_debug_print(src, true); + drm_rect_debug_print(dst, false); 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_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, - intel_plane->rotation); + 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) src_x || - src.y1 < (int) src_y || - src.x2 > (int) (src_x + src_w) || - src.y2 > (int) (src_y + src_h)); + 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); /* * Hardware doesn't handle subpixel coordinates. @@ -983,10 +990,10 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, * increase the source viewport size, because that could * push the downscaling factor out of bounds. */ - src_x = src.x1 >> 16; - src_w = drm_rect_width(&src) >> 16; - src_y = src.y1 >> 16; - src_h = drm_rect_height(&src) >> 16; + 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; @@ -1000,12 +1007,12 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, crtc_w &= ~1; if (crtc_w == 0) - visible = false; + state->visible = false; } } /* Check size restrictions when scaling */ - if (visible && (src_w != crtc_w || src_h != crtc_h)) { + if (state->visible && (src_w != crtc_w || src_h != crtc_h)) { unsigned int width_bytes; WARN_ON(!intel_plane->can_scale); @@ -1013,12 +1020,14 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, /* FIXME interlacing min height is 6 */ if (crtc_w < 3 || crtc_h < 3) - visible = false; + state->visible = false; if (src_w < 3 || src_h < 3) - visible = false; + state->visible = false; - width_bytes = ((src_x * pixel_size) & 63) + src_w * pixel_size; + pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); + width_bytes = ((src_x * pixel_size) & 63) + + src_w * pixel_size; if (src_w > 2048 || src_h > 2048 || width_bytes > 4096 || fb->pitches[0] > 4096) { @@ -1027,137 +1036,93 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, } } - dst.x1 = crtc_x; - dst.x2 = crtc_x + crtc_w; - dst.y1 = crtc_y; - dst.y2 = crtc_y + crtc_h; + 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; +finish: /* * If the sprite is completely covering the primary plane, * we can disable the primary and save power. */ - primary_enabled = !drm_rect_equals(&dst, &clip) || colorkey_enabled(intel_plane); - WARN_ON(!primary_enabled && !visible && intel_crtc->active); - - 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); - - i915_gem_track_fb(old_obj, obj, - INTEL_FRONTBUFFER_SPRITE(pipe)); - mutex_unlock(&dev->struct_mutex); - - if (ret) - return ret; - - intel_plane->crtc_x = orig.crtc_x; - intel_plane->crtc_y = orig.crtc_y; - intel_plane->crtc_w = orig.crtc_w; - intel_plane->crtc_h = orig.crtc_h; - intel_plane->src_x = orig.src_x; - intel_plane->src_y = orig.src_y; - intel_plane->src_w = orig.src_w; - intel_plane->src_h = orig.src_h; - intel_plane->obj = obj; + state->hides_primary = fb != NULL && drm_rect_equals(dst, clip) && + !colorkey_enabled(intel_plane); + WARN_ON(state->hides_primary && !state->visible && intel_crtc->active); if (intel_crtc->active) { - bool primary_was_enabled = intel_crtc->primary_enabled; - - intel_crtc->primary_enabled = primary_enabled; + if (intel_crtc->primary_enabled == state->hides_primary) + intel_crtc->atomic.wait_for_flips = true; - if (primary_was_enabled != primary_enabled) - intel_crtc_wait_for_pending_flips(crtc); - - if (primary_was_enabled && !primary_enabled) - intel_pre_disable_primary(crtc); - - if (visible) - intel_plane->update_plane(plane, crtc, fb, obj, - crtc_x, crtc_y, crtc_w, crtc_h, - src_x, src_y, src_w, src_h); - else - intel_plane->disable_plane(plane, crtc); + if (intel_crtc->primary_enabled && state->hides_primary) + intel_crtc->atomic.pre_disable_primary = true; - intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_SPRITE(pipe)); + intel_crtc->atomic.fb_bits |= + INTEL_FRONTBUFFER_SPRITE(intel_crtc->pipe); - if (!primary_was_enabled && primary_enabled) - intel_post_enable_primary(crtc); - } + if (!intel_crtc->primary_enabled && !state->hides_primary) + intel_crtc->atomic.post_enable_primary = true; - /* 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. - */ - if (old_obj != obj && intel_crtc->active) - intel_wait_for_vblank(dev, intel_crtc->pipe); + if (intel_wm_need_update(plane, &state->base)) + intel_crtc->atomic.update_wm = true; - mutex_lock(&dev->struct_mutex); - intel_unpin_fb_obj(old_obj); - mutex_unlock(&dev->struct_mutex); + if (!state->visible) { + /* + * Avoid underruns when disabling the sprite. + * FIXME remove once watermark updates are done properly. + */ + intel_crtc->atomic.wait_vblank = true; + intel_crtc->atomic.update_sprite_watermarks |= + (1 << drm_plane_index(plane)); + } } return 0; } -static int -intel_disable_plane(struct drm_plane *plane) +static void +intel_commit_sprite_plane(struct drm_plane *plane, + struct intel_plane_state *state) { - struct drm_device *dev = plane->dev; - struct intel_plane *intel_plane = to_intel_plane(plane); + struct drm_crtc *crtc = state->base.crtc; struct intel_crtc *intel_crtc; - enum pipe pipe; - - if (!plane->fb) - return 0; + struct intel_plane *intel_plane = to_intel_plane(plane); + 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; - if (WARN_ON(!plane->crtc)) - return -EINVAL; + crtc = crtc ? crtc : plane->crtc; + intel_crtc = to_intel_crtc(crtc); - intel_crtc = to_intel_crtc(plane->crtc); - pipe = intel_crtc->pipe; + plane->fb = fb; if (intel_crtc->active) { - bool primary_was_enabled = intel_crtc->primary_enabled; - - intel_crtc->primary_enabled = true; - - intel_plane->disable_plane(plane, plane->crtc); - - if (!primary_was_enabled && intel_crtc->primary_enabled) - intel_post_enable_primary(plane->crtc); - } - - if (intel_plane->obj) { - if (intel_crtc->active) - intel_wait_for_vblank(dev, intel_plane->pipe); - - mutex_lock(&dev->struct_mutex); - intel_unpin_fb_obj(intel_plane->obj); - i915_gem_track_fb(intel_plane->obj, NULL, - INTEL_FRONTBUFFER_SPRITE(pipe)); - mutex_unlock(&dev->struct_mutex); - - intel_plane->obj = NULL; + intel_crtc->primary_enabled = !state->hides_primary; + + if (state->visible) { + crtc_x = state->dst.x1; + crtc_y = state->dst.y1; + crtc_w = drm_rect_width(&state->dst); + crtc_h = drm_rect_height(&state->dst); + src_x = state->src.x1 >> 16; + src_y = state->src.y1 >> 16; + src_w = drm_rect_width(&state->src) >> 16; + src_h = drm_rect_height(&state->src) >> 16; + intel_plane->update_plane(plane, crtc, fb, + crtc_x, crtc_y, crtc_w, crtc_h, + src_x, src_y, src_w, src_h); + } else { + intel_plane->disable_plane(plane, crtc); + } } - - return 0; -} - -static void intel_destroy_plane(struct drm_plane *plane) -{ - struct intel_plane *intel_plane = to_intel_plane(plane); - intel_disable_plane(plane); - drm_plane_cleanup(plane); - kfree(intel_plane); } int intel_sprite_set_colorkey(struct drm_device *dev, void *data, @@ -1168,112 +1133,50 @@ int intel_sprite_set_colorkey(struct drm_device *dev, void *data, struct intel_plane *intel_plane; 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; + if (IS_VALLEYVIEW(dev) && + set->flags & I915_SET_COLORKEY_DESTINATION) + return -EINVAL; + drm_modeset_lock_all(dev); plane = drm_plane_find(dev, set->plane_id); - if (!plane) { + if (!plane || plane->type != DRM_PLANE_TYPE_OVERLAY) { ret = -ENOENT; goto out_unlock; } 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_plane *plane; - struct intel_plane *intel_plane; - int ret = 0; - - if (!drm_core_check_feature(dev, DRIVER_MODESET)) - return -ENODEV; - - drm_modeset_lock_all(dev); - - plane = drm_plane_find(dev, get->plane_id); - if (!plane) { - ret = -ENOENT; - goto out_unlock; - } + intel_plane->ckey = *set; - intel_plane = to_intel_plane(plane); - intel_plane->get_colorkey(plane, get); + /* + * The only way this could fail would be due to + * the current plane state being unsupportable already, + * and we dont't consider that an error for the + * colorkey ioctl. So just ignore any error. + */ + intel_plane_restore(plane); out_unlock: drm_modeset_unlock_all(dev); return ret; } -int intel_plane_set_property(struct drm_plane *plane, - struct drm_property *prop, - uint64_t val) -{ - struct drm_device *dev = plane->dev; - struct intel_plane *intel_plane = to_intel_plane(plane); - uint64_t old_val; - int ret = -ENOENT; - - if (prop == dev->mode_config.rotation_property) { - /* exactly one rotation angle please */ - if (hweight32(val & 0xf) != 1) - return -EINVAL; - - if (intel_plane->rotation == val) - return 0; - - old_val = intel_plane->rotation; - intel_plane->rotation = val; - ret = intel_plane_restore(plane); - if (ret) - intel_plane->rotation = old_val; - } - - return ret; -} - int intel_plane_restore(struct drm_plane *plane) { - struct intel_plane *intel_plane = to_intel_plane(plane); - - if (!plane->crtc || !plane->fb) + if (!plane->crtc || !plane->state->fb) return 0; - return plane->funcs->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); -} - -void intel_plane_disable(struct drm_plane *plane) -{ - if (!plane->crtc || !plane->fb) - return; - - intel_disable_plane(plane); + return drm_plane_helper_update(plane, plane->crtc, plane->state->fb, + plane->state->crtc_x, plane->state->crtc_y, + plane->state->crtc_w, plane->state->crtc_h, + plane->state->src_x, plane->state->src_y, + plane->state->src_w, plane->state->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, - .set_property = intel_plane_set_property, -}; - static uint32_t ilk_plane_formats[] = { DRM_FORMAT_XRGB8888, DRM_FORMAT_YUYV, @@ -1305,10 +1208,23 @@ static uint32_t vlv_plane_formats[] = { 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; @@ -1321,6 +1237,13 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane) 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: @@ -1328,8 +1251,6 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane) 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; @@ -1353,22 +1274,31 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane) if (IS_VALLEYVIEW(dev)) { 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->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: + /* + * FIXME: Skylake planes can be scaled (with some restrictions), + * but this is for another time. + */ + intel_plane->can_scale = false; + intel_plane->max_downscale = 1; + 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; @@ -1376,7 +1306,9 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane) intel_plane->pipe = pipe; intel_plane->plane = plane; - intel_plane->rotation = BIT(DRM_ROTATE_0); + intel_plane->check_plane = intel_check_sprite_plane; + intel_plane->commit_plane = intel_commit_sprite_plane; + intel_plane->ckey.flags = I915_SET_COLORKEY_NONE; possible_crtcs = (1 << pipe); ret = drm_universal_plane_init(dev, &intel_plane->base, possible_crtcs, &intel_plane_funcs, @@ -1387,16 +1319,9 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane) goto out; } - if (!dev->mode_config.rotation_property) - dev->mode_config.rotation_property = - drm_mode_create_rotation_property(dev, - BIT(DRM_ROTATE_0) | - BIT(DRM_ROTATE_180)); + intel_create_rotation_property(dev, intel_plane); - if (dev->mode_config.rotation_property) - drm_object_attach_property(&intel_plane->base.base, - dev->mode_config.rotation_property, - intel_plane->rotation); + drm_plane_helper_add(&intel_plane->base, &intel_plane_helper_funcs); out: return ret; |