diff options
Diffstat (limited to 'drivers/gpu/drm/i915/display/intel_sprite.c')
| -rw-r--r-- | drivers/gpu/drm/i915/display/intel_sprite.c | 344 | 
1 files changed, 260 insertions, 84 deletions
diff --git a/drivers/gpu/drm/i915/display/intel_sprite.c b/drivers/gpu/drm/i915/display/intel_sprite.c index 004b52027ae8..dea63be1964f 100644 --- a/drivers/gpu/drm/i915/display/intel_sprite.c +++ b/drivers/gpu/drm/i915/display/intel_sprite.c @@ -40,8 +40,9 @@  #include <drm/i915_drm.h>  #include "i915_drv.h" +#include "i915_trace.h"  #include "intel_atomic_plane.h" -#include "intel_drv.h" +#include "intel_display_types.h"  #include "intel_frontbuffer.h"  #include "intel_pm.h"  #include "intel_psr.h" @@ -330,6 +331,12 @@ int intel_plane_check_src_coordinates(struct intel_plane_state *plane_state)  	return 0;  } +bool icl_is_hdr_plane(struct drm_i915_private *dev_priv, enum plane_id plane_id) +{ +	return INTEL_GEN(dev_priv) >= 11 && +		icl_hdr_plane_mask() & BIT(plane_id); +} +  static unsigned int  skl_plane_max_stride(struct intel_plane *plane,  		     u32 pixel_format, u64 modifier, @@ -441,9 +448,21 @@ icl_program_input_csc(struct intel_plane *plane,  		 */  		[DRM_COLOR_YCBCR_BT709] = {  			0x7C98, 0x7800, 0x0, -			0x9EF8, 0x7800, 0xABF8, +			0x9EF8, 0x7800, 0xAC00,  			0x0, 0x7800,  0x7ED8,  		}, +		/* +		 * BT.2020 full range YCbCr -> full range RGB +		 * The matrix required is : +		 * [1.000, 0.000, 1.474, +		 *  1.000, -0.1645, -0.5713, +		 *  1.000, 1.8814, 0.0000] +		 */ +		[DRM_COLOR_YCBCR_BT2020] = { +			0x7BC8, 0x7800, 0x0, +			0x8928, 0x7800, 0xAA88, +			0x0, 0x7800, 0x7F10, +		},  	};  	/* Matrix for Limited Range to Full Range Conversion */ @@ -451,26 +470,38 @@ icl_program_input_csc(struct intel_plane *plane,  		/*  		 * BT.601 Limted range YCbCr -> full range RGB  		 * The matrix required is : -		 * [1.164384, 0.000, 1.596370, -		 *  1.138393, -0.382500, -0.794598, -		 *  1.138393, 1.971696, 0.0000] +		 * [1.164384, 0.000, 1.596027, +		 *  1.164384, -0.39175, -0.812813, +		 *  1.164384, 2.017232, 0.0000]  		 */  		[DRM_COLOR_YCBCR_BT601] = {  			0x7CC8, 0x7950, 0x0, -			0x8CB8, 0x7918, 0x9C40, -			0x0, 0x7918, 0x7FC8, +			0x8D00, 0x7950, 0x9C88, +			0x0, 0x7950, 0x6810,  		},  		/*  		 * BT.709 Limited range YCbCr -> full range RGB  		 * The matrix required is : -		 * [1.164, 0.000, 1.833671, -		 *  1.138393, -0.213249, -0.532909, -		 *  1.138393, 2.112402, 0.0000] +		 * [1.164384, 0.000, 1.792741, +		 *  1.164384, -0.213249, -0.532909, +		 *  1.164384, 2.112402, 0.0000]  		 */  		[DRM_COLOR_YCBCR_BT709] = { -			0x7EA8, 0x7950, 0x0, -			0x8888, 0x7918, 0xADA8, -			0x0, 0x7918,  0x6870, +			0x7E58, 0x7950, 0x0, +			0x8888, 0x7950, 0xADA8, +			0x0, 0x7950,  0x6870, +		}, +		/* +		 * BT.2020 Limited range YCbCr -> full range RGB +		 * The matrix required is : +		 * [1.164, 0.000, 1.678, +		 *  1.164, -0.1873, -0.6504, +		 *  1.164, 2.1417, 0.0000] +		 */ +		[DRM_COLOR_YCBCR_BT2020] = { +			0x7D70, 0x7950, 0x0, +			0x8A68, 0x7950, 0xAC00, +			0x0, 0x7950, 0x6890,  		},  	};  	const u16 *csc; @@ -492,8 +523,11 @@ icl_program_input_csc(struct intel_plane *plane,  	I915_WRITE_FW(PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 0),  		      PREOFF_YUV_TO_RGB_HI); -	I915_WRITE_FW(PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 1), -		      PREOFF_YUV_TO_RGB_ME); +	if (plane_state->base.color_range == DRM_COLOR_YCBCR_FULL_RANGE) +		I915_WRITE_FW(PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 1), 0); +	else +		I915_WRITE_FW(PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 1), +			      PREOFF_YUV_TO_RGB_ME);  	I915_WRITE_FW(PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 2),  		      PREOFF_YUV_TO_RGB_LO);  	I915_WRITE_FW(PLANE_INPUT_CSC_POSTOFF(pipe, plane_id, 0), 0x0); @@ -683,6 +717,16 @@ skl_plane_get_hw_state(struct intel_plane *plane,  	return ret;  } +static void i9xx_plane_linear_gamma(u16 gamma[8]) +{ +	/* The points are not evenly spaced. */ +	static const u8 in[8] = { 0, 1, 2, 4, 8, 16, 24, 32 }; +	int i; + +	for (i = 0; i < 8; i++) +		gamma[i] = (in[i] << 8) / 32; +} +  static void  chv_update_csc(const struct intel_plane_state *plane_state)  { @@ -858,6 +902,31 @@ static u32 vlv_sprite_ctl(const struct intel_crtc_state *crtc_state,  	return sprctl;  } +static void vlv_update_gamma(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; +	u16 gamma[8]; +	int i; + +	/* Seems RGB data bypasses the gamma always */ +	if (!fb->format->is_yuv) +		return; + +	i9xx_plane_linear_gamma(gamma); + +	/* FIXME these register are single buffered :( */ +	/* The two end points are implicit (0.0 and 1.0) */ +	for (i = 1; i < 8 - 1; i++) +		I915_WRITE_FW(SPGAMC(pipe, plane_id, i - 1), +			      gamma[i] << 16 | +			      gamma[i] << 8 | +			      gamma[i]); +} +  static void  vlv_update_plane(struct intel_plane *plane,  		 const struct intel_crtc_state *crtc_state, @@ -916,6 +985,7 @@ vlv_update_plane(struct intel_plane *plane,  		      intel_plane_ggtt_offset(plane_state) + sprsurf_offset);  	vlv_update_clrc(plane_state); +	vlv_update_gamma(plane_state);  	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);  } @@ -1013,6 +1083,8 @@ static u32 ivb_sprite_ctl(const struct intel_crtc_state *crtc_state,  		return 0;  	} +	sprctl |= SPRITE_INT_GAMMA_DISABLE; +  	if (plane_state->base.color_encoding == DRM_COLOR_YCBCR_BT709)  		sprctl |= SPRITE_YUV_TO_RGB_CSC_FORMAT_BT709; @@ -1033,6 +1105,45 @@ static u32 ivb_sprite_ctl(const struct intel_crtc_state *crtc_state,  	return sprctl;  } +static void ivb_sprite_linear_gamma(u16 gamma[18]) +{ +	int i; + +	for (i = 0; i < 17; i++) +		gamma[i] = (i << 10) / 16; + +	gamma[i] = 3 << 10; +	i++; +} + +static void ivb_update_gamma(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); +	enum pipe pipe = plane->pipe; +	u16 gamma[18]; +	int i; + +	ivb_sprite_linear_gamma(gamma); + +	/* FIXME these register are single buffered :( */ +	for (i = 0; i < 16; i++) +		I915_WRITE_FW(SPRGAMC(pipe, i), +			      gamma[i] << 20 | +			      gamma[i] << 10 | +			      gamma[i]); + +	I915_WRITE_FW(SPRGAMC16(pipe, 0), gamma[i]); +	I915_WRITE_FW(SPRGAMC16(pipe, 1), gamma[i]); +	I915_WRITE_FW(SPRGAMC16(pipe, 2), gamma[i]); +	i++; + +	I915_WRITE_FW(SPRGAMC17(pipe, 0), gamma[i]); +	I915_WRITE_FW(SPRGAMC17(pipe, 1), gamma[i]); +	I915_WRITE_FW(SPRGAMC17(pipe, 2), gamma[i]); +	i++; +} +  static void  ivb_update_plane(struct intel_plane *plane,  		 const struct intel_crtc_state *crtc_state, @@ -1099,6 +1210,8 @@ ivb_update_plane(struct intel_plane *plane,  	I915_WRITE_FW(SPRSURF(pipe),  		      intel_plane_ggtt_offset(plane_state) + sprsurf_offset); +	ivb_update_gamma(plane_state); +  	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);  } @@ -1224,6 +1337,66 @@ static u32 g4x_sprite_ctl(const struct intel_crtc_state *crtc_state,  	return dvscntr;  } +static void g4x_update_gamma(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; +	u16 gamma[8]; +	int i; + +	/* Seems RGB data bypasses the gamma always */ +	if (!fb->format->is_yuv) +		return; + +	i9xx_plane_linear_gamma(gamma); + +	/* FIXME these register are single buffered :( */ +	/* The two end points are implicit (0.0 and 1.0) */ +	for (i = 1; i < 8 - 1; i++) +		I915_WRITE_FW(DVSGAMC_G4X(pipe, i - 1), +			      gamma[i] << 16 | +			      gamma[i] << 8 | +			      gamma[i]); +} + +static void ilk_sprite_linear_gamma(u16 gamma[17]) +{ +	int i; + +	for (i = 0; i < 17; i++) +		gamma[i] = (i << 10) / 16; +} + +static void ilk_update_gamma(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; +	u16 gamma[17]; +	int i; + +	/* Seems RGB data bypasses the gamma always */ +	if (!fb->format->is_yuv) +		return; + +	ilk_sprite_linear_gamma(gamma); + +	/* FIXME these register are single buffered :( */ +	for (i = 0; i < 16; i++) +		I915_WRITE_FW(DVSGAMC_ILK(pipe, i), +			      gamma[i] << 20 | +			      gamma[i] << 10 | +			      gamma[i]); + +	I915_WRITE_FW(DVSGAMCMAX_ILK(pipe, 0), gamma[i]); +	I915_WRITE_FW(DVSGAMCMAX_ILK(pipe, 1), gamma[i]); +	I915_WRITE_FW(DVSGAMCMAX_ILK(pipe, 2), gamma[i]); +	i++; +} +  static void  g4x_update_plane(struct intel_plane *plane,  		 const struct intel_crtc_state *crtc_state, @@ -1283,6 +1456,11 @@ g4x_update_plane(struct intel_plane *plane,  	I915_WRITE_FW(DVSSURF(pipe),  		      intel_plane_ggtt_offset(plane_state) + dvssurf_offset); +	if (IS_G4X(dev_priv)) +		g4x_update_gamma(plane_state); +	else +		ilk_update_gamma(plane_state); +  	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);  } @@ -1347,7 +1525,7 @@ g4x_sprite_check_scaling(struct intel_crtc_state *crtc_state,  	const struct drm_framebuffer *fb = plane_state->base.fb;  	const struct drm_rect *src = &plane_state->base.src;  	const struct drm_rect *dst = &plane_state->base.dst; -	int src_x, src_y, src_w, src_h, crtc_w, crtc_h; +	int src_x, src_w, src_h, crtc_w, crtc_h;  	const struct drm_display_mode *adjusted_mode =  		&crtc_state->base.adjusted_mode;  	unsigned int cpp = fb->format->cpp[0]; @@ -1358,7 +1536,6 @@ g4x_sprite_check_scaling(struct intel_crtc_state *crtc_state,  	crtc_h = drm_rect_height(dst);  	src_x = src->x1 >> 16; -	src_y = src->y1 >> 16;  	src_w = drm_rect_width(src) >> 16;  	src_h = drm_rect_height(src) >> 16; @@ -1852,28 +2029,7 @@ static const u32 skl_plane_formats[] = {  	DRM_FORMAT_VYUY,  }; -static const u32 icl_plane_formats[] = { -	DRM_FORMAT_C8, -	DRM_FORMAT_RGB565, -	DRM_FORMAT_XRGB8888, -	DRM_FORMAT_XBGR8888, -	DRM_FORMAT_ARGB8888, -	DRM_FORMAT_ABGR8888, -	DRM_FORMAT_XRGB2101010, -	DRM_FORMAT_XBGR2101010, -	DRM_FORMAT_YUYV, -	DRM_FORMAT_YVYU, -	DRM_FORMAT_UYVY, -	DRM_FORMAT_VYUY, -	DRM_FORMAT_Y210, -	DRM_FORMAT_Y212, -	DRM_FORMAT_Y216, -	DRM_FORMAT_XVYU2101010, -	DRM_FORMAT_XVYU12_16161616, -	DRM_FORMAT_XVYU16161616, -}; - -static const u32 icl_hdr_plane_formats[] = { +static const u32 skl_planar_formats[] = {  	DRM_FORMAT_C8,  	DRM_FORMAT_RGB565,  	DRM_FORMAT_XRGB8888, @@ -1882,23 +2038,14 @@ static const u32 icl_hdr_plane_formats[] = {  	DRM_FORMAT_ABGR8888,  	DRM_FORMAT_XRGB2101010,  	DRM_FORMAT_XBGR2101010, -	DRM_FORMAT_XRGB16161616F, -	DRM_FORMAT_XBGR16161616F, -	DRM_FORMAT_ARGB16161616F, -	DRM_FORMAT_ABGR16161616F,  	DRM_FORMAT_YUYV,  	DRM_FORMAT_YVYU,  	DRM_FORMAT_UYVY,  	DRM_FORMAT_VYUY, -	DRM_FORMAT_Y210, -	DRM_FORMAT_Y212, -	DRM_FORMAT_Y216, -	DRM_FORMAT_XVYU2101010, -	DRM_FORMAT_XVYU12_16161616, -	DRM_FORMAT_XVYU16161616, +	DRM_FORMAT_NV12,  }; -static const u32 skl_planar_formats[] = { +static const u32 glk_planar_formats[] = {  	DRM_FORMAT_C8,  	DRM_FORMAT_RGB565,  	DRM_FORMAT_XRGB8888, @@ -1912,9 +2059,12 @@ static const u32 skl_planar_formats[] = {  	DRM_FORMAT_UYVY,  	DRM_FORMAT_VYUY,  	DRM_FORMAT_NV12, +	DRM_FORMAT_P010, +	DRM_FORMAT_P012, +	DRM_FORMAT_P016,  }; -static const u32 glk_planar_formats[] = { +static const u32 icl_sdr_y_plane_formats[] = {  	DRM_FORMAT_C8,  	DRM_FORMAT_RGB565,  	DRM_FORMAT_XRGB8888, @@ -1927,13 +2077,15 @@ static const u32 glk_planar_formats[] = {  	DRM_FORMAT_YVYU,  	DRM_FORMAT_UYVY,  	DRM_FORMAT_VYUY, -	DRM_FORMAT_NV12, -	DRM_FORMAT_P010, -	DRM_FORMAT_P012, -	DRM_FORMAT_P016, +	DRM_FORMAT_Y210, +	DRM_FORMAT_Y212, +	DRM_FORMAT_Y216, +	DRM_FORMAT_XVYU2101010, +	DRM_FORMAT_XVYU12_16161616, +	DRM_FORMAT_XVYU16161616,  }; -static const u32 icl_planar_formats[] = { +static const u32 icl_sdr_uv_plane_formats[] = {  	DRM_FORMAT_C8,  	DRM_FORMAT_RGB565,  	DRM_FORMAT_XRGB8888, @@ -1958,7 +2110,7 @@ static const u32 icl_planar_formats[] = {  	DRM_FORMAT_XVYU16161616,  }; -static const u32 icl_hdr_planar_formats[] = { +static const u32 icl_hdr_plane_formats[] = {  	DRM_FORMAT_C8,  	DRM_FORMAT_RGB565,  	DRM_FORMAT_XRGB8888, @@ -2201,9 +2353,6 @@ static bool skl_plane_has_fbc(struct drm_i915_private *dev_priv,  static bool skl_plane_has_planar(struct drm_i915_private *dev_priv,  				 enum pipe pipe, enum plane_id plane_id)  { -	if (INTEL_GEN(dev_priv) >= 11) -		return plane_id <= PLANE_SPRITE3; -  	/* Display WA #0870: skl, bxt */  	if (IS_SKYLAKE(dev_priv) || IS_BROXTON(dev_priv))  		return false; @@ -2217,6 +2366,48 @@ static bool skl_plane_has_planar(struct drm_i915_private *dev_priv,  	return true;  } +static const u32 *skl_get_plane_formats(struct drm_i915_private *dev_priv, +					enum pipe pipe, enum plane_id plane_id, +					int *num_formats) +{ +	if (skl_plane_has_planar(dev_priv, pipe, plane_id)) { +		*num_formats = ARRAY_SIZE(skl_planar_formats); +		return skl_planar_formats; +	} else { +		*num_formats = ARRAY_SIZE(skl_plane_formats); +		return skl_plane_formats; +	} +} + +static const u32 *glk_get_plane_formats(struct drm_i915_private *dev_priv, +					enum pipe pipe, enum plane_id plane_id, +					int *num_formats) +{ +	if (skl_plane_has_planar(dev_priv, pipe, plane_id)) { +		*num_formats = ARRAY_SIZE(glk_planar_formats); +		return glk_planar_formats; +	} else { +		*num_formats = ARRAY_SIZE(skl_plane_formats); +		return skl_plane_formats; +	} +} + +static const u32 *icl_get_plane_formats(struct drm_i915_private *dev_priv, +					enum pipe pipe, enum plane_id plane_id, +					int *num_formats) +{ +	if (icl_is_hdr_plane(dev_priv, plane_id)) { +		*num_formats = ARRAY_SIZE(icl_hdr_plane_formats); +		return icl_hdr_plane_formats; +	} else if (icl_is_nv12_y_plane(plane_id)) { +		*num_formats = ARRAY_SIZE(icl_sdr_y_plane_formats); +		return icl_sdr_y_plane_formats; +	} else { +		*num_formats = ARRAY_SIZE(icl_sdr_uv_plane_formats); +		return icl_sdr_uv_plane_formats; +	} +} +  static bool skl_plane_has_ccs(struct drm_i915_private *dev_priv,  			      enum pipe pipe, enum plane_id plane_id)  { @@ -2270,30 +2461,15 @@ skl_universal_plane_create(struct drm_i915_private *dev_priv,  	if (icl_is_nv12_y_plane(plane_id))  		plane->update_slave = icl_update_slave; -	if (skl_plane_has_planar(dev_priv, pipe, plane_id)) { -		if (icl_is_hdr_plane(dev_priv, plane_id)) { -			formats = icl_hdr_planar_formats; -			num_formats = ARRAY_SIZE(icl_hdr_planar_formats); -		} else if (INTEL_GEN(dev_priv) >= 11) { -			formats = icl_planar_formats; -			num_formats = ARRAY_SIZE(icl_planar_formats); -		} else if (INTEL_GEN(dev_priv) == 10 || IS_GEMINILAKE(dev_priv)) { -			formats = glk_planar_formats; -			num_formats = ARRAY_SIZE(glk_planar_formats); -		} else { -			formats = skl_planar_formats; -			num_formats = ARRAY_SIZE(skl_planar_formats); -		} -	} else if (icl_is_hdr_plane(dev_priv, plane_id)) { -		formats = icl_hdr_plane_formats; -		num_formats = ARRAY_SIZE(icl_hdr_plane_formats); -	} else if (INTEL_GEN(dev_priv) >= 11) { -		formats = icl_plane_formats; -		num_formats = ARRAY_SIZE(icl_plane_formats); -	} else { -		formats = skl_plane_formats; -		num_formats = ARRAY_SIZE(skl_plane_formats); -	} +	if (INTEL_GEN(dev_priv) >= 11) +		formats = icl_get_plane_formats(dev_priv, pipe, +						plane_id, &num_formats); +	else if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) +		formats = glk_get_plane_formats(dev_priv, pipe, +						plane_id, &num_formats); +	else +		formats = skl_get_plane_formats(dev_priv, pipe, +						plane_id, &num_formats);  	plane->has_ccs = skl_plane_has_ccs(dev_priv, pipe, plane_id);  	if (plane->has_ccs)  |