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;  |