diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_sprite.c')
-rw-r--r-- | drivers/gpu/drm/i915/intel_sprite.c | 261 |
1 files changed, 196 insertions, 65 deletions
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index dd485f59eb1d..dbdcf85032df 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -41,8 +41,7 @@ #include <drm/i915_drm.h> #include "i915_drv.h" -static bool -format_is_yuv(uint32_t format) +bool intel_format_is_yuv(u32 format) { switch (format) { case DRM_FORMAT_YUYV: @@ -266,6 +265,7 @@ skl_update_plane(struct intel_plane *plane, if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) I915_WRITE_FW(PLANE_COLOR_CTL(pipe, plane_id), plane_state->color_ctl); + if (key->flags) { I915_WRITE_FW(PLANE_KEYVAL(pipe, plane_id), key->min_value); I915_WRITE_FW(PLANE_KEYMAX(pipe, plane_id), key->max_value); @@ -346,44 +346,103 @@ skl_plane_get_hw_state(struct intel_plane *plane) } static void -chv_update_csc(struct intel_plane *plane, uint32_t format) +chv_update_csc(const struct intel_plane_state *plane_state) { + struct intel_plane *plane = to_intel_plane(plane_state->base.plane); struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + const struct drm_framebuffer *fb = plane_state->base.fb; enum plane_id plane_id = plane->id; - - /* Seems RGB data bypasses the CSC always */ - if (!format_is_yuv(format)) - return; - /* - * BT.601 limited range YCbCr -> full range RGB + * |r| | c0 c1 c2 | |cr| + * |g| = | c3 c4 c5 | x |y | + * |b| | c6 c7 c8 | |cb| * - * |r| | 6537 4769 0| |cr | - * |g| = |-3330 4769 -1605| x |y-64| - * |b| | 0 4769 8263| |cb | + * Coefficients are s3.12. * - * Cb and Cr apparently come in as signed already, so no - * need for any offset. For Y we need to remove the offset. + * Cb and Cr apparently come in as signed already, and + * we always get full range data in on account of CLRC0/1. */ - I915_WRITE_FW(SPCSCYGOFF(plane_id), SPCSC_OOFF(0) | SPCSC_IOFF(-64)); + static const s16 csc_matrix[][9] = { + /* BT.601 full range YCbCr -> full range RGB */ + [DRM_COLOR_YCBCR_BT601] = { + 5743, 4096, 0, + -2925, 4096, -1410, + 0, 4096, 7258, + }, + /* BT.709 full range YCbCr -> full range RGB */ + [DRM_COLOR_YCBCR_BT709] = { + 6450, 4096, 0, + -1917, 4096, -767, + 0, 4096, 7601, + }, + }; + const s16 *csc = csc_matrix[plane_state->base.color_encoding]; + + /* Seems RGB data bypasses the CSC always */ + if (!intel_format_is_yuv(fb->format->format)) + return; + + I915_WRITE_FW(SPCSCYGOFF(plane_id), SPCSC_OOFF(0) | SPCSC_IOFF(0)); I915_WRITE_FW(SPCSCCBOFF(plane_id), SPCSC_OOFF(0) | SPCSC_IOFF(0)); I915_WRITE_FW(SPCSCCROFF(plane_id), SPCSC_OOFF(0) | SPCSC_IOFF(0)); - I915_WRITE_FW(SPCSCC01(plane_id), SPCSC_C1(4769) | SPCSC_C0(6537)); - I915_WRITE_FW(SPCSCC23(plane_id), SPCSC_C1(-3330) | SPCSC_C0(0)); - I915_WRITE_FW(SPCSCC45(plane_id), SPCSC_C1(-1605) | SPCSC_C0(4769)); - I915_WRITE_FW(SPCSCC67(plane_id), SPCSC_C1(4769) | SPCSC_C0(0)); - I915_WRITE_FW(SPCSCC8(plane_id), SPCSC_C0(8263)); + I915_WRITE_FW(SPCSCC01(plane_id), SPCSC_C1(csc[1]) | SPCSC_C0(csc[0])); + I915_WRITE_FW(SPCSCC23(plane_id), SPCSC_C1(csc[3]) | SPCSC_C0(csc[2])); + I915_WRITE_FW(SPCSCC45(plane_id), SPCSC_C1(csc[5]) | SPCSC_C0(csc[4])); + I915_WRITE_FW(SPCSCC67(plane_id), SPCSC_C1(csc[7]) | SPCSC_C0(csc[6])); + I915_WRITE_FW(SPCSCC8(plane_id), SPCSC_C0(csc[8])); - I915_WRITE_FW(SPCSCYGICLAMP(plane_id), SPCSC_IMAX(940) | SPCSC_IMIN(64)); - I915_WRITE_FW(SPCSCCBICLAMP(plane_id), SPCSC_IMAX(448) | SPCSC_IMIN(-448)); - I915_WRITE_FW(SPCSCCRICLAMP(plane_id), SPCSC_IMAX(448) | SPCSC_IMIN(-448)); + I915_WRITE_FW(SPCSCYGICLAMP(plane_id), SPCSC_IMAX(1023) | SPCSC_IMIN(0)); + I915_WRITE_FW(SPCSCCBICLAMP(plane_id), SPCSC_IMAX(512) | SPCSC_IMIN(-512)); + I915_WRITE_FW(SPCSCCRICLAMP(plane_id), SPCSC_IMAX(512) | SPCSC_IMIN(-512)); I915_WRITE_FW(SPCSCYGOCLAMP(plane_id), SPCSC_OMAX(1023) | SPCSC_OMIN(0)); I915_WRITE_FW(SPCSCCBOCLAMP(plane_id), SPCSC_OMAX(1023) | SPCSC_OMIN(0)); I915_WRITE_FW(SPCSCCROCLAMP(plane_id), SPCSC_OMAX(1023) | SPCSC_OMIN(0)); } +#define SIN_0 0 +#define COS_0 1 + +static void +vlv_update_clrc(const struct intel_plane_state *plane_state) +{ + struct intel_plane *plane = to_intel_plane(plane_state->base.plane); + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + const struct drm_framebuffer *fb = plane_state->base.fb; + enum pipe pipe = plane->pipe; + enum plane_id plane_id = plane->id; + int contrast, brightness, sh_scale, sh_sin, sh_cos; + + if (intel_format_is_yuv(fb->format->format) && + plane_state->base.color_range == DRM_COLOR_YCBCR_LIMITED_RANGE) { + /* + * Expand limited range to full range: + * Contrast is applied first and is used to expand Y range. + * Brightness is applied second and is used to remove the + * offset from Y. Saturation/hue is used to expand CbCr range. + */ + contrast = DIV_ROUND_CLOSEST(255 << 6, 235 - 16); + brightness = -DIV_ROUND_CLOSEST(16 * 255, 235 - 16); + sh_scale = DIV_ROUND_CLOSEST(128 << 7, 240 - 128); + sh_sin = SIN_0 * sh_scale; + sh_cos = COS_0 * sh_scale; + } else { + /* Pass-through everything. */ + contrast = 1 << 6; + brightness = 0; + sh_scale = 1 << 7; + sh_sin = SIN_0 * sh_scale; + sh_cos = COS_0 * sh_scale; + } + + /* FIXME these register are single buffered :( */ + I915_WRITE_FW(SPCLRC0(pipe, plane_id), + SP_CONTRAST(contrast) | SP_BRIGHTNESS(brightness)); + I915_WRITE_FW(SPCLRC1(pipe, plane_id), + SP_SH_SIN(sh_sin) | SP_SH_COS(sh_cos)); +} + static u32 vlv_sprite_ctl(const struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state) { @@ -433,6 +492,9 @@ static u32 vlv_sprite_ctl(const struct intel_crtc_state *crtc_state, return 0; } + if (plane_state->base.color_encoding == DRM_COLOR_YCBCR_BT709) + sprctl |= SP_YUV_FORMAT_BT709; + if (fb->modifier == I915_FORMAT_MOD_X_TILED) sprctl |= SP_TILED; @@ -477,8 +539,10 @@ vlv_update_plane(struct intel_plane *plane, spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); + vlv_update_clrc(plane_state); + if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B) - chv_update_csc(plane, fb->format->format); + chv_update_csc(plane_state); if (key->flags) { I915_WRITE_FW(SPKEYMINVAL(pipe, plane_id), key->min_value); @@ -584,6 +648,12 @@ static u32 ivb_sprite_ctl(const struct intel_crtc_state *crtc_state, return 0; } + if (plane_state->base.color_encoding == DRM_COLOR_YCBCR_BT709) + sprctl |= SPRITE_YUV_TO_RGB_CSC_FORMAT_BT709; + + if (plane_state->base.color_range == DRM_COLOR_YCBCR_FULL_RANGE) + sprctl |= SPRITE_YUV_RANGE_CORRECTION_DISABLE; + if (fb->modifier == I915_FORMAT_MOD_X_TILED) sprctl |= SPRITE_TILED; @@ -740,6 +810,12 @@ static u32 g4x_sprite_ctl(const struct intel_crtc_state *crtc_state, return 0; } + if (plane_state->base.color_encoding == DRM_COLOR_YCBCR_BT709) + dvscntr |= DVS_YUV_FORMAT_BT709; + + if (plane_state->base.color_range == DRM_COLOR_YCBCR_FULL_RANGE) + dvscntr |= DVS_YUV_RANGE_CORRECTION_DISABLE; + if (fb->modifier == I915_FORMAT_MOD_X_TILED) dvscntr |= DVS_TILED; @@ -864,7 +940,8 @@ intel_check_sprite_plane(struct intel_plane *plane, uint32_t src_x, src_y, src_w, src_h; struct drm_rect *src = &state->base.src; struct drm_rect *dst = &state->base.dst; - const struct drm_rect *clip = &state->clip; + struct drm_rect clip = {}; + int max_stride = INTEL_GEN(dev_priv) >= 9 ? 32768 : 16384; int hscale, vscale; int max_scale, min_scale; bool can_scale; @@ -885,7 +962,7 @@ intel_check_sprite_plane(struct intel_plane *plane, } /* FIXME check all gen limits */ - if (fb->width < 3 || fb->height < 3 || fb->pitches[0] > 16384) { + if (fb->width < 3 || fb->height < 3 || fb->pitches[0] > max_stride) { DRM_DEBUG_KMS("Unsuitable framebuffer for plane\n"); return -EINVAL; } @@ -893,7 +970,7 @@ intel_check_sprite_plane(struct intel_plane *plane, /* setup can_scale, min_scale, max_scale */ if (INTEL_GEN(dev_priv) >= 9) { /* use scaler when colorkey is not required */ - if (state->ckey.flags == I915_SET_COLORKEY_NONE) { + if (!state->ckey.flags) { can_scale = 1; min_scale = 1; max_scale = skl_max_scale(crtc, crtc_state); @@ -922,7 +999,11 @@ intel_check_sprite_plane(struct intel_plane *plane, vscale = drm_rect_calc_vscale_relaxed(src, dst, min_scale, max_scale); BUG_ON(vscale < 0); - state->base.visible = drm_rect_clip_scaled(src, dst, clip, hscale, vscale); + if (crtc_state->base.enable) + drm_mode_get_hv_timing(&crtc_state->base.mode, + &clip.x2, &clip.y2); + + state->base.visible = drm_rect_clip_scaled(src, dst, &clip, hscale, vscale); crtc_x = dst->x1; crtc_y = dst->y1; @@ -974,7 +1055,7 @@ intel_check_sprite_plane(struct intel_plane *plane, src_y = src->y1 >> 16; src_h = drm_rect_height(src) >> 16; - if (format_is_yuv(fb->format->format)) { + if (intel_format_is_yuv(fb->format->format)) { src_x &= ~1; src_w &= ~1; @@ -1027,7 +1108,7 @@ intel_check_sprite_plane(struct intel_plane *plane, dst->y2 = crtc_y + crtc_h; if (INTEL_GEN(dev_priv) >= 9) { - ret = skl_check_plane_surface(state); + ret = skl_check_plane_surface(crtc_state, state); if (ret) return ret; @@ -1058,8 +1139,8 @@ intel_check_sprite_plane(struct intel_plane *plane, return 0; } -int intel_sprite_set_colorkey(struct drm_device *dev, void *data, - struct drm_file *file_priv) +int intel_sprite_set_colorkey_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) { struct drm_i915_private *dev_priv = to_i915(dev); struct drm_intel_sprite_colorkey *set = data; @@ -1069,6 +1150,12 @@ int intel_sprite_set_colorkey(struct drm_device *dev, void *data, struct drm_modeset_acquire_ctx ctx; int ret = 0; + /* ignore the pointless "none" flag */ + set->flags &= ~I915_SET_COLORKEY_NONE; + + if (set->flags & ~(I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) + return -EINVAL; + /* 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; @@ -1161,18 +1248,27 @@ static uint32_t skl_plane_formats[] = { DRM_FORMAT_VYUY, }; -static const uint64_t skl_plane_format_modifiers[] = { +static const uint64_t skl_plane_format_modifiers_noccs[] = { + I915_FORMAT_MOD_Yf_TILED, + I915_FORMAT_MOD_Y_TILED, + I915_FORMAT_MOD_X_TILED, + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_INVALID +}; + +static const uint64_t skl_plane_format_modifiers_ccs[] = { + I915_FORMAT_MOD_Yf_TILED_CCS, + I915_FORMAT_MOD_Y_TILED_CCS, + I915_FORMAT_MOD_Yf_TILED, + I915_FORMAT_MOD_Y_TILED, I915_FORMAT_MOD_X_TILED, DRM_FORMAT_MOD_LINEAR, DRM_FORMAT_MOD_INVALID }; -static bool g4x_sprite_plane_format_mod_supported(struct drm_plane *plane, - uint32_t format, - uint64_t modifier) +static bool g4x_mod_supported(uint32_t format, uint64_t modifier) { switch (format) { - case DRM_FORMAT_XBGR8888: case DRM_FORMAT_XRGB8888: case DRM_FORMAT_YUYV: case DRM_FORMAT_YVYU: @@ -1187,22 +1283,38 @@ static bool g4x_sprite_plane_format_mod_supported(struct drm_plane *plane, } } -static bool vlv_sprite_plane_format_mod_supported(struct drm_plane *plane, - uint32_t format, - uint64_t modifier) +static bool snb_mod_supported(uint32_t format, uint64_t modifier) { switch (format) { + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_XBGR8888: case DRM_FORMAT_YUYV: case DRM_FORMAT_YVYU: case DRM_FORMAT_UYVY: case DRM_FORMAT_VYUY: + if (modifier == DRM_FORMAT_MOD_LINEAR || + modifier == I915_FORMAT_MOD_X_TILED) + return true; + /* fall through */ + default: + return false; + } +} + +static bool vlv_mod_supported(uint32_t format, uint64_t modifier) +{ + switch (format) { case DRM_FORMAT_RGB565: - case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_ABGR8888: case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_XRGB8888: case DRM_FORMAT_XBGR2101010: case DRM_FORMAT_ABGR2101010: - case DRM_FORMAT_XBGR8888: - case DRM_FORMAT_ABGR8888: + case DRM_FORMAT_YUYV: + case DRM_FORMAT_YVYU: + case DRM_FORMAT_UYVY: + case DRM_FORMAT_VYUY: if (modifier == DRM_FORMAT_MOD_LINEAR || modifier == I915_FORMAT_MOD_X_TILED) return true; @@ -1212,16 +1324,17 @@ static bool vlv_sprite_plane_format_mod_supported(struct drm_plane *plane, } } -static bool skl_sprite_plane_format_mod_supported(struct drm_plane *plane, - uint32_t format, - uint64_t modifier) +static bool skl_mod_supported(uint32_t format, uint64_t modifier) { - /* This is the same as primary plane since SKL has universal planes */ switch (format) { case DRM_FORMAT_XRGB8888: case DRM_FORMAT_XBGR8888: case DRM_FORMAT_ARGB8888: case DRM_FORMAT_ABGR8888: + if (modifier == I915_FORMAT_MOD_Yf_TILED_CCS || + modifier == I915_FORMAT_MOD_Y_TILED_CCS) + return true; + /* fall through */ case DRM_FORMAT_RGB565: case DRM_FORMAT_XRGB2101010: case DRM_FORMAT_XBGR2101010: @@ -1257,13 +1370,13 @@ static bool intel_sprite_plane_format_mod_supported(struct drm_plane *plane, return false; if (INTEL_GEN(dev_priv) >= 9) - return skl_sprite_plane_format_mod_supported(plane, format, modifier); + return skl_mod_supported(format, modifier); else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) - return vlv_sprite_plane_format_mod_supported(plane, format, modifier); + return vlv_mod_supported(format, modifier); + else if (INTEL_GEN(dev_priv) >= 6) + return snb_mod_supported(format, modifier); else - return g4x_sprite_plane_format_mod_supported(plane, format, modifier); - - unreachable(); + return g4x_mod_supported(format, modifier); } static const struct drm_plane_funcs intel_sprite_plane_funcs = { @@ -1277,6 +1390,23 @@ static const struct drm_plane_funcs intel_sprite_plane_funcs = { .format_mod_supported = intel_sprite_plane_format_mod_supported, }; +bool skl_plane_has_ccs(struct drm_i915_private *dev_priv, + enum pipe pipe, enum plane_id plane_id) +{ + if (plane_id == PLANE_CURSOR) + return false; + + if (INTEL_GEN(dev_priv) >= 10) + return true; + + if (IS_GEMINILAKE(dev_priv)) + return pipe != PIPE_C; + + return pipe != PIPE_C && + (plane_id == PLANE_PRIMARY || + plane_id == PLANE_SPRITE0); +} + struct intel_plane * intel_sprite_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe, int plane) @@ -1303,7 +1433,7 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv, } intel_plane->base.state = &state->base; - if (INTEL_GEN(dev_priv) >= 10) { + if (INTEL_GEN(dev_priv) >= 9) { intel_plane->can_scale = true; state->scaler_id = -1; @@ -1313,18 +1443,11 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv, plane_formats = skl_plane_formats; num_plane_formats = ARRAY_SIZE(skl_plane_formats); - modifiers = skl_plane_format_modifiers; - } else if (INTEL_GEN(dev_priv) >= 9) { - intel_plane->can_scale = true; - state->scaler_id = -1; - - intel_plane->update_plane = skl_update_plane; - intel_plane->disable_plane = skl_disable_plane; - intel_plane->get_hw_state = skl_plane_get_hw_state; - plane_formats = skl_plane_formats; - num_plane_formats = ARRAY_SIZE(skl_plane_formats); - modifiers = skl_plane_format_modifiers; + if (skl_plane_has_ccs(dev_priv, pipe, PLANE_SPRITE0 + plane)) + modifiers = skl_plane_format_modifiers_ccs; + else + modifiers = skl_plane_format_modifiers_noccs; } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { intel_plane->can_scale = false; intel_plane->max_downscale = 1; @@ -1386,7 +1509,7 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv, intel_plane->pipe = pipe; intel_plane->i9xx_plane = plane; intel_plane->id = PLANE_SPRITE0 + plane; - intel_plane->frontbuffer_bit = INTEL_FRONTBUFFER_SPRITE(pipe, plane); + intel_plane->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, intel_plane->id); intel_plane->check_plane = intel_check_sprite_plane; possible_crtcs = (1 << pipe); @@ -1412,6 +1535,14 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv, DRM_MODE_ROTATE_0, supported_rotations); + drm_plane_create_color_properties(&intel_plane->base, + BIT(DRM_COLOR_YCBCR_BT601) | + BIT(DRM_COLOR_YCBCR_BT709), + BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) | + BIT(DRM_COLOR_YCBCR_FULL_RANGE), + DRM_COLOR_YCBCR_BT709, + DRM_COLOR_YCBCR_LIMITED_RANGE); + drm_plane_helper_add(&intel_plane->base, &intel_plane_helper_funcs); return intel_plane; |