diff mbox series

[v4,9/9] Gen-12 display can decompress surfaces compressed by the media engine.

Message ID 20190926105512.25818-1-dhinakaran.pandiyan@intel.com (mailing list archive)
State New, archived
Headers show
Series None | expand

Commit Message

Dhinakaran Pandiyan Sept. 26, 2019, 10:55 a.m. UTC
Detect the modifier corresponding to media compression to enable
display decompression for YUV and xRGB packed formats. A new modifier is
added so that the driver can distinguish between media and render
compressed buffers. Unlike render decompression, plane 6 and  plane 7 do not
support media decompression.

v2: Fix checkpatch warnings on code style (Lucas)

From DK:
Separate modifier array for planes that cannot decompress media (Ville)

v3: Support planar formats
v4: Switch plane order

Cc: Nanley G Chery <nanley.g.chery@intel.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Matt Roper <matthew.d.roper@intel.com>
Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
Signed-off-by: Lucas De Marchi <lucas.demarchi@intel.com>
---
 drivers/gpu/drm/i915/display/intel_display.c  | 290 +++++++++++++-----
 .../drm/i915/display/intel_display_types.h    |   2 +-
 drivers/gpu/drm/i915/display/intel_sprite.c   |  55 +++-
 drivers/gpu/drm/i915/i915_reg.h               |   1 +
 4 files changed, 267 insertions(+), 81 deletions(-)

Comments

Ville Syrjälä Oct. 4, 2019, 3:36 p.m. UTC | #1
On Thu, Sep 26, 2019 at 03:55:12AM -0700, Dhinakaran Pandiyan wrote:
> Detect the modifier corresponding to media compression to enable
> display decompression for YUV and xRGB packed formats. A new modifier is
> added so that the driver can distinguish between media and render
> compressed buffers. Unlike render decompression, plane 6 and  plane 7 do not
> support media decompression.
> 
> v2: Fix checkpatch warnings on code style (Lucas)
> 
> From DK:
> Separate modifier array for planes that cannot decompress media (Ville)
> 
> v3: Support planar formats
> v4: Switch plane order
> 
> Cc: Nanley G Chery <nanley.g.chery@intel.com>
> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> Cc: Matt Roper <matthew.d.roper@intel.com>
> Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
> Signed-off-by: Lucas De Marchi <lucas.demarchi@intel.com>
> ---
>  drivers/gpu/drm/i915/display/intel_display.c  | 290 +++++++++++++-----
>  .../drm/i915/display/intel_display_types.h    |   2 +-
>  drivers/gpu/drm/i915/display/intel_sprite.c   |  55 +++-
>  drivers/gpu/drm/i915/i915_reg.h               |   1 +
>  4 files changed, 267 insertions(+), 81 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
> index 8ea55d67442c..df3ebaa167ab 100644
> --- a/drivers/gpu/drm/i915/display/intel_display.c
> +++ b/drivers/gpu/drm/i915/display/intel_display.c
> @@ -1888,6 +1888,22 @@ static void intel_disable_pipe(const struct intel_crtc_state *old_crtc_state)
>  		intel_wait_for_pipe_off(old_crtc_state);
>  }
>  
> +bool is_ccs_modifier(u64 modifier)
> +{
> +	return modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS ||
> +	       modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS ||
> +	       modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
> +	       modifier == I915_FORMAT_MOD_Yf_TILED_CCS;
> +}
> +
> +static bool is_ccs_plane(const struct drm_framebuffer *fb, int color_plane)
> +{
> +	if (!is_ccs_modifier(fb->modifier))
> +		return false;

A comment here could help clarify things for the reader. Eg.:
/*
 * [0] RGB
 * [1] RGB CCS
 * or
 * [0] Y
 * [1] CbCr
 * [2] Y CCS
 * [3] CbCr CCS
 */

> +
> +	return color_plane >= fb->format->num_planes / 2;
> +}
> +
>  static unsigned int intel_tile_size(const struct drm_i915_private *dev_priv)
>  {
>  	return IS_GEN(dev_priv, 2) ? 2048 : 4096;
> @@ -1908,11 +1924,13 @@ intel_tile_width_bytes(const struct drm_framebuffer *fb, int color_plane)
>  		else
>  			return 512;
>  	case I915_FORMAT_MOD_Y_TILED_CCS:
> -		if (color_plane == 1)
> +		if (is_ccs_plane(fb, color_plane))
>  			return 128;
>  		/* fall through */
> +	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
> +		/* fall through */
>  	case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
> -		if (color_plane == 1)
> +		if (is_ccs_plane(fb, color_plane))
>  			return 64;
>  		/* fall through */
>  	case I915_FORMAT_MOD_Y_TILED:
> @@ -1921,7 +1939,7 @@ intel_tile_width_bytes(const struct drm_framebuffer *fb, int color_plane)
>  		else
>  			return 512;
>  	case I915_FORMAT_MOD_Yf_TILED_CCS:
> -		if (color_plane == 1)
> +		if (is_ccs_plane(fb, color_plane))
>  			return 128;
>  		/* fall through */
>  	case I915_FORMAT_MOD_Yf_TILED:
> @@ -1949,8 +1967,9 @@ static unsigned int
>  intel_tile_height(const struct drm_framebuffer *fb, int color_plane)
>  {
>  	switch (fb->modifier) {
> +	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
>  	case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
> -		if (color_plane == 1)
> +		if (is_ccs_plane(fb, color_plane))
>  			return 1;
>  		/* fall through */
>  	default:
> @@ -2055,6 +2074,7 @@ static unsigned int intel_surf_alignment(const struct drm_framebuffer *fb,
>  		if (INTEL_GEN(dev_priv) >= 9)
>  			return 256 * 1024;
>  		return 0;
> +	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
>  	case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
>  		return 16 * 1024;
>  	case I915_FORMAT_MOD_Y_TILED_CCS:
> @@ -2254,10 +2274,17 @@ static u32 intel_adjust_tile_offset(int *x, int *y,
>  	return new_offset;
>  }
>  
> -static bool is_surface_linear(u64 modifier, int color_plane)
> +static bool is_surface_linear(const struct drm_framebuffer *fb, int color_plane)
>  {
> -	return modifier == DRM_FORMAT_MOD_LINEAR ||
> -	       (modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS && color_plane == 1);
> +	switch (fb->modifier) {
> +	case DRM_FORMAT_MOD_LINEAR:
> +		return true;
> +	case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
> +	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
> +		return is_ccs_plane(fb, color_plane);
> +	default:
> +		return false;
> +	}
>  }
>  
>  static u32 intel_adjust_aligned_offset(int *x, int *y,
> @@ -2272,7 +2299,7 @@ static u32 intel_adjust_aligned_offset(int *x, int *y,
>  
>  	WARN_ON(new_offset > old_offset);
>  
> -	if (!is_surface_linear(fb->modifier, color_plane)) {
> +	if (!is_surface_linear(fb, color_plane)) {
>  		unsigned int tile_size, tile_width, tile_height;
>  		unsigned int pitch_tiles;
>  
> @@ -2342,7 +2369,7 @@ static u32 intel_compute_aligned_offset(struct drm_i915_private *dev_priv,
>  	if (alignment)
>  		alignment--;
>  
> -	if (!is_surface_linear(fb->modifier, color_plane)) {
> +	if (!is_surface_linear(fb, color_plane)) {
>  		unsigned int tile_size, tile_width, tile_height;
>  		unsigned int tile_rows, tiles, pitch_tiles;
>  
> @@ -2445,6 +2472,7 @@ static unsigned int intel_fb_modifier_to_tiling(u64 fb_modifier)
>  	case I915_FORMAT_MOD_Y_TILED:
>  	case I915_FORMAT_MOD_Y_TILED_CCS:
>  	case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
> +	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
>  		return I915_TILING_Y;
>  	default:
>  		return I915_TILING_NONE;
> @@ -2494,6 +2522,13 @@ static const struct drm_format_info gen12_ccs_formats[] = {
>  	  .cpp = { 4, 1, }, .hsub = 2, .vsub = 32, .has_alpha = true },
>  };
>  
> +static const struct drm_format_info gen12_mc_ccs_formats[] = {
> +	{ .format = DRM_FORMAT_YUYV, .num_planes = 2,
> +	  .cpp = { 2, 1, }, .hsub = 4, .vsub = 32, .is_yuv = true },
> +	{ .format = DRM_FORMAT_NV12, .num_planes = 4,
> +	  .cpp = { 1, 2, 1, 1}, .hsub = 2, .vsub = 2, .is_yuv = true },
> +};
> +
>  static const struct drm_format_info *
>  lookup_format_info(const struct drm_format_info formats[],
>  		   int num_formats, u32 format)
> @@ -2511,12 +2546,21 @@ lookup_format_info(const struct drm_format_info formats[],
>  static const struct drm_format_info *
>  intel_get_format_info(const struct drm_mode_fb_cmd2 *cmd)
>  {
> +	const struct drm_format_info *info;
> +
>  	switch (cmd->modifier[0]) {
>  	case I915_FORMAT_MOD_Y_TILED_CCS:
>  	case I915_FORMAT_MOD_Yf_TILED_CCS:
>  		return lookup_format_info(skl_ccs_formats,
>  					  ARRAY_SIZE(skl_ccs_formats),
>  					  cmd->pixel_format);
> +	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
> +		info = lookup_format_info(gen12_mc_ccs_formats,
> +					  ARRAY_SIZE(gen12_mc_ccs_formats),
> +					  cmd->pixel_format);
> +		if (info)
> +			return info;
> +		/* fall through */
>  	case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
>  		return lookup_format_info(gen12_ccs_formats,
>  					  ARRAY_SIZE(gen12_ccs_formats),
> @@ -2526,13 +2570,6 @@ intel_get_format_info(const struct drm_mode_fb_cmd2 *cmd)
>  	}
>  }
>  
> -bool is_ccs_modifier(u64 modifier)
> -{
> -	return modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS ||
> -	       modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
> -	       modifier == I915_FORMAT_MOD_Yf_TILED_CCS;
> -}
> -
>  u32 intel_plane_fb_max_stride(struct drm_i915_private *dev_priv,
>  			      u32 pixel_format, u64 modifier)
>  {
> @@ -2576,7 +2613,7 @@ intel_fb_stride_alignment(const struct drm_framebuffer *fb, int color_plane)
>  	struct drm_i915_private *dev_priv = to_i915(fb->dev);
>  	u32 tile_width;
>  
> -	if (is_surface_linear(fb->modifier, color_plane)) {
> +	if (is_surface_linear(fb, color_plane)) {
>  		u32 max_stride = intel_plane_fb_max_stride(dev_priv,
>  							   fb->format->format,
>  							   fb->modifier);
> @@ -2592,7 +2629,7 @@ intel_fb_stride_alignment(const struct drm_framebuffer *fb, int color_plane)
>  	}
>  
>  	tile_width = intel_tile_width_bytes(fb, color_plane);
> -	if (is_ccs_modifier(fb->modifier) && color_plane == 0) {
> +	if (is_ccs_modifier(fb->modifier)) {
>  		/*
>  		 * Display WA #0531: skl,bxt,kbl,glk
>  		 *
> @@ -2602,7 +2639,7 @@ intel_fb_stride_alignment(const struct drm_framebuffer *fb, int color_plane)
>  		 * require the entire fb to accommodate that to avoid
>  		 * potential runtime errors at plane configuration time.
>  		 */
> -		if (IS_GEN(dev_priv, 9) && fb->width > 3840)
> +		if (IS_GEN(dev_priv, 9) && color_plane == 0 && fb->width > 3840)
>  			tile_width *= 4;
>  		/*
>  		 * The main surface pitch must be padded to a multiple of four
> @@ -2682,25 +2719,75 @@ static bool intel_plane_needs_remap(const struct intel_plane_state *plane_state)
>  	return stride > max_stride;
>  }
>  
> +static void
> +intel_fb_plane_get_subsampling(int *hsub, int *vsub, const struct drm_framebuffer *fb, int color_plane)
> +{
> +	int i;
> +	static const struct {
> +		u32 format;
> +		int vsub[4];
> +		int hsub[4];
> +	} mc_ccs_subsampling[] = { { .hsub = { 1, 2, 8, 16 },
> +				     .vsub = { 1, 2, 32, 32 },
> +				     .format = DRM_FORMAT_NV12, },
> +				 };
> +
> +	*hsub = fb->format->hsub;
> +	*vsub = fb->format->vsub;
> +
> +	if (fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS &&
> +	    fb->format->num_planes == 4) {
> +		for (i = 0; i < ARRAY_SIZE(mc_ccs_subsampling); i++) {
> +			if  (mc_ccs_subsampling[i].format == fb->format->format) {
> +				*hsub = mc_ccs_subsampling[i].hsub[color_plane];
> +				*vsub = mc_ccs_subsampling[i].vsub[color_plane];
> +				break;
> +			}
> +		}
> +		WARN_ON(i == ARRAY_SIZE(mc_ccs_subsampling));
> +	}

Hmm. I wonder if we could switch over to that block size stuff
in the format info? As is I don't think framebuffer_check() will
do the right thing for this stuff.

> +}
> +
> +static void
> +intel_fb_plane_dims(int *w, int *h, struct drm_framebuffer *fb, int color_plane)
> +{
> +	int hsub, vsub;
> +
> +	intel_fb_plane_get_subsampling(&hsub, &vsub, fb, color_plane);
> +	*w = fb->width/hsub;
> +	*h = fb->height/vsub;
> +}
> +
>  static int
> -intel_fb_check_ccs_xy(struct drm_framebuffer *fb, int x, int y)
> +intel_fb_check_ccs_xy(struct drm_framebuffer *fb, int aux_plane, int x, int y)
>  {
>  	struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
> -	int hsub = fb->format->hsub;
> -	int vsub = fb->format->vsub;
> +	int hsub, vsub;
> +	int hsub_main, vsub_main;
>  	int tile_width, tile_height;
>  	int ccs_x, ccs_y;
>  	int main_x, main_y;
> +	int main_plane;
> +
> +	if (!is_ccs_plane(fb, aux_plane))
> +		return 0;
> +
> +	main_plane = (aux_plane - 1) / 2;

'aux_plane - num_planes/2' might be a clearer way to write that.
The num_planes/2 already made an appearance in the is_ccs_plane() thing.

Could also extract this to a small helper to help readability.

> +	intel_tile_dims(fb, aux_plane, &tile_width, &tile_height);
> +	intel_fb_plane_get_subsampling(&hsub, &vsub, fb, aux_plane);
> +	intel_fb_plane_get_subsampling(&hsub_main, &vsub_main, fb,
> +				       main_plane);
>  
> -	intel_tile_dims(fb, 1, &tile_width, &tile_height);
> +	hsub /= hsub_main;
> +	vsub /= vsub_main;
>  
>  	tile_width *= hsub;
>  	tile_height *= vsub;
>  
>  	ccs_x = (x * hsub) % tile_width;
>  	ccs_y = (y * vsub) % tile_height;
> -	main_x = intel_fb->normal[0].x % tile_width;
> -	main_y = intel_fb->normal[0].y % tile_height;
> +	main_x = intel_fb->normal[main_plane].x % tile_width;
> +	main_y = intel_fb->normal[main_plane].y % tile_height;
>  
>  	/*
>  	* CCS doesn't have its own x/y offset register, so the intra CCS tile
> @@ -2710,8 +2797,8 @@ intel_fb_check_ccs_xy(struct drm_framebuffer *fb, int x, int y)
>  		DRM_DEBUG_KMS("Bad CCS x/y (main %d,%d ccs %d,%d) full (main %d,%d ccs %d,%d)\n",
>  			      main_x, main_y,
>  			      ccs_x, ccs_y,
> -			      intel_fb->normal[0].x,
> -			      intel_fb->normal[0].y,
> +			      intel_fb->normal[main_plane].x,
> +			      intel_fb->normal[main_plane].y,
>  			      x, y);
>  		return -EINVAL;
>  	}
> @@ -2739,8 +2826,7 @@ intel_fill_fb_info(struct drm_i915_private *dev_priv,
>  		int ret;
>  
>  		cpp = fb->format->cpp[i];
> -		width = drm_framebuffer_plane_width(fb->width, fb, i);
> -		height = drm_framebuffer_plane_height(fb->height, fb, i);
> +		intel_fb_plane_dims(&width, &height, fb, i);
>  
>  		ret = intel_fb_offset_to_xy(&x, &y, fb, i);
>  		if (ret) {
> @@ -2749,11 +2835,9 @@ intel_fill_fb_info(struct drm_i915_private *dev_priv,
>  			return ret;
>  		}
>  
> -		if (is_ccs_modifier(fb->modifier) && i == 1) {
> -			ret = intel_fb_check_ccs_xy(fb, x, y);
> -			if (ret)
> -				return ret;
> -		}
> +		ret = intel_fb_check_ccs_xy(fb, i, x, y);
> +		if (ret)
> +			return ret;
>  
>  		/*
>  		 * The fence (if used) is aligned to the start of the object
> @@ -3371,6 +3455,7 @@ static int skl_max_plane_width(const struct drm_framebuffer *fb,
>  			return 5120;
>  	case I915_FORMAT_MOD_Y_TILED_CCS:
>  	case I915_FORMAT_MOD_Yf_TILED_CCS:
> +	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
>  		/* FIXME AUX plane? */
>  	case I915_FORMAT_MOD_Y_TILED:
>  	case I915_FORMAT_MOD_Yf_TILED:
> @@ -3430,16 +3515,18 @@ static int icl_max_plane_height(void)
>  }
>  
>  static bool skl_check_main_ccs_coordinates(struct intel_plane_state *plane_state,
> -					   int main_x, int main_y, u32 main_offset)
> +					   int main_x, int main_y,
> +					   u32 main_offset, int aux_plane)
>  {
>  	const struct drm_framebuffer *fb = plane_state->base.fb;
> -	int hsub = fb->format->hsub;
> -	int vsub = fb->format->vsub;
> -	int aux_x = plane_state->color_plane[1].x;
> -	int aux_y = plane_state->color_plane[1].y;
> -	u32 aux_offset = plane_state->color_plane[1].offset;
> -	u32 alignment = intel_surf_alignment(fb, 1);
> -
> +	int hsub;
> +	int vsub;
> +	int aux_x = plane_state->color_plane[aux_plane].x;
> +	int aux_y = plane_state->color_plane[aux_plane].y;
> +	u32 aux_offset = plane_state->color_plane[aux_plane].offset;
> +	u32 alignment = intel_surf_alignment(fb, aux_plane);
> +
> +	intel_fb_plane_get_subsampling(&hsub, &vsub, fb, aux_plane);
>  	while (aux_offset >= main_offset && aux_y <= main_y) {
>  		int x, y;
>  
> @@ -3451,7 +3538,7 @@ static bool skl_check_main_ccs_coordinates(struct intel_plane_state *plane_state
>  
>  		x = aux_x / hsub;
>  		y = aux_y / vsub;
> -		aux_offset = intel_plane_adjust_aligned_offset(&x, &y, plane_state, 1,
> +		aux_offset = intel_plane_adjust_aligned_offset(&x, &y, plane_state, aux_plane,
>  							       aux_offset, aux_offset - alignment);
>  		aux_x = x * hsub + aux_x % hsub;
>  		aux_y = y * vsub + aux_y % vsub;
> @@ -3460,9 +3547,9 @@ static bool skl_check_main_ccs_coordinates(struct intel_plane_state *plane_state
>  	if (aux_x != main_x || aux_y != main_y)
>  		return false;
>  
> -	plane_state->color_plane[1].offset = aux_offset;
> -	plane_state->color_plane[1].x = aux_x;
> -	plane_state->color_plane[1].y = aux_y;
> +	plane_state->color_plane[aux_plane].offset = aux_offset;
> +	plane_state->color_plane[aux_plane].x = aux_x;
> +	plane_state->color_plane[aux_plane].y = aux_y;
>  
>  	return true;
>  }
> @@ -3478,7 +3565,8 @@ static int skl_check_main_surface(struct intel_plane_state *plane_state)
>  	int h = drm_rect_height(&plane_state->base.src) >> 16;
>  	int max_width;
>  	int max_height;
> -	u32 alignment, offset, aux_offset = plane_state->color_plane[1].offset;
> +	int aux_plane = fb->format->num_planes / 2;
> +	u32 alignment, offset, aux_offset = plane_state->color_plane[aux_plane].offset;
>  
>  	if (INTEL_GEN(dev_priv) >= 11)
>  		max_width = icl_max_plane_width(fb, 0, rotation);
> @@ -3536,7 +3624,9 @@ static int skl_check_main_surface(struct intel_plane_state *plane_state)
>  	 * they match with the main surface x/y offsets.
>  	 */
>  	if (is_ccs_modifier(fb->modifier)) {
> -		while (!skl_check_main_ccs_coordinates(plane_state, x, y, offset)) {
> +
> +		while (!skl_check_main_ccs_coordinates(plane_state, x, y,
> +						       offset, aux_plane)) {
>  			if (offset == 0)
>  				break;
>  
> @@ -3544,7 +3634,8 @@ static int skl_check_main_surface(struct intel_plane_state *plane_state)
>  								   offset, offset - alignment);
>  		}
>  
> -		if (x != plane_state->color_plane[1].x || y != plane_state->color_plane[1].y) {
> +		if (x != plane_state->color_plane[aux_plane].x ||
> +		    y != plane_state->color_plane[aux_plane].y) {
>  			DRM_DEBUG_KMS("Unable to find suitable display surface offset due to CCS\n");
>  			return -EINVAL;
>  		}
> @@ -3587,6 +3678,41 @@ static int skl_check_nv12_aux_surface(struct intel_plane_state *plane_state)
>  		return -EINVAL;
>  	}
>  
> +	if (is_ccs_modifier(fb->modifier)) {
> +		int aux_offset = plane_state->color_plane[3].offset;
> +		int alignment = intel_surf_alignment(fb, 1);
> +
> +		if (offset > aux_offset) {
> +			int hsub, vsub;
> +			int main_x = x, main_y = y;
> +
> +
> +			intel_fb_plane_get_subsampling(&hsub, &vsub, fb, 1);
> +			x = main_x / hsub;
> +			y = main_y / vsub;
> +			offset = intel_plane_adjust_aligned_offset(&x, &y, plane_state, 1,
> +								   offset,
> +								   aux_offset & ~(alignment - 1));
> +			x = x * hsub + main_x % hsub;
> +			y = y * vsub + main_y % vsub;
> +
> +		}
> +
> +		while (!skl_check_main_ccs_coordinates(plane_state, x, y, offset, 3)) {
> +			if (offset == 0)
> +				break;
> +
> +			offset = intel_plane_adjust_aligned_offset(&x, &y, plane_state, 1,
> +								   offset, offset - alignment);
> +		}
> +
> +		if (x != plane_state->color_plane[3].x ||
> +		    y != plane_state->color_plane[3].y) {
> +			DRM_DEBUG_KMS("Unable to find suitable display surface offset due to CCS\n");
> +			return -EINVAL;
> +		}

Probably time to refactor some of the stuff so we don't have to copy
paste so much.

> +	}
> +
>  	plane_state->color_plane[1].offset = offset;
>  	plane_state->color_plane[1].x = x;
>  	plane_state->color_plane[1].y = y;
> @@ -3599,19 +3725,30 @@ static int skl_check_ccs_aux_surface(struct intel_plane_state *plane_state)
>  	const struct drm_framebuffer *fb = plane_state->base.fb;
>  	int src_x = plane_state->base.src.x1 >> 16;
>  	int src_y = plane_state->base.src.y1 >> 16;
> -	int hsub = fb->format->hsub;
> -	int vsub = fb->format->vsub;
> -	int x = src_x / hsub;
> -	int y = src_y / vsub;
>  	u32 offset;
> +	int ccs;
>  
> -	intel_add_fb_offsets(&x, &y, plane_state, 1);
> -	offset = intel_plane_compute_aligned_offset(&x, &y, plane_state, 1);
>  
> -	plane_state->color_plane[1].offset = offset;
> -	plane_state->color_plane[1].x = x * hsub + src_x % hsub;
> -	plane_state->color_plane[1].y = y * vsub + src_y % vsub;
> +	for (ccs = fb->format->num_planes / 2;

I guess another helper to do the main->aux index calculation would make
this less magicy.

ccs < fb->format->num_planes; ccs++) {
> +		int hsub, vsub;
> +		int main_hsub, main_vsub;
> +		int x, y;
> +
> +		intel_fb_plane_get_subsampling(&hsub, &vsub, fb, ccs);
> +		intel_fb_plane_get_subsampling(&main_hsub, &main_vsub, fb, (ccs - 1)/ 2);
> +
> +		hsub /= main_hsub;
> +		vsub /= main_vsub;
> +		x = src_x / hsub;
> +		y = src_y / vsub;
>  
> +		intel_add_fb_offsets(&x, &y, plane_state, ccs);
> +		offset = intel_plane_compute_aligned_offset(&x, &y,
> +							    plane_state, ccs);
> +		plane_state->color_plane[ccs].offset = offset;
> +		plane_state->color_plane[ccs].x = x * hsub + src_x % hsub;
> +		plane_state->color_plane[ccs].y = y * vsub + src_y % vsub;
> +	}
>  	return 0;
>  }
>  
> @@ -3619,6 +3756,7 @@ int skl_check_plane_surface(struct intel_plane_state *plane_state)
>  {
>  	const struct drm_framebuffer *fb = plane_state->base.fb;
>  	int ret;
> +	bool needs_aux = false;
>  
>  	ret = intel_plane_compute_gtt(plane_state);
>  	if (ret)
> @@ -3628,21 +3766,31 @@ int skl_check_plane_surface(struct intel_plane_state *plane_state)
>  		return 0;
>  
>  	/*
> -	 * Handle the AUX surface first since
> -	 * the main surface setup depends on it.
> +	 * Handle the AUX surface first since the main surface setup depends on
> +	 * it.
>  	 */
> -	if (drm_format_info_is_yuv_semiplanar(fb->format)) {
> -		ret = skl_check_nv12_aux_surface(plane_state);
> +	if (is_ccs_modifier(fb->modifier)) {
> +		needs_aux = true;
> +		ret = skl_check_ccs_aux_surface(plane_state);
>  		if (ret)
>  			return ret;
> -	} else if (is_ccs_modifier(fb->modifier)) {
> -		ret = skl_check_ccs_aux_surface(plane_state);
> +	}
> +
> +	if (drm_format_info_is_yuv_semiplanar(fb->format)) {
> +		needs_aux = true;
> +		ret = skl_check_nv12_aux_surface(plane_state);
>  		if (ret)
>  			return ret;
> -	} else {
> -		plane_state->color_plane[1].offset = ~0xfff;
> -		plane_state->color_plane[1].x = 0;
> -		plane_state->color_plane[1].y = 0;
> +	}
> +
> +	if (!needs_aux) {
> +		int i;
> +
> +		for (i = 1; i < fb->format->num_planes; i++) {
> +			plane_state->color_plane[i].offset = ~0xfff;
> +			plane_state->color_plane[i].x = 0;
> +			plane_state->color_plane[i].y = 0;
> +		}
>  	}
>  
>  	ret = skl_check_main_surface(plane_state);
> @@ -4030,7 +4178,7 @@ static unsigned int skl_plane_stride_mult(const struct drm_framebuffer *fb,
>  	 * The stride is either expressed as a multiple of 64 bytes chunks for
>  	 * linear buffers or in number of tiles for tiled buffers.
>  	 */
> -	if (is_surface_linear(fb->modifier, color_plane))
> +	if (is_surface_linear(fb, color_plane))
>  		return 64;
>  	else if (drm_rotation_90_or_270(rotation))
>  		return intel_tile_height(fb, color_plane);
> @@ -4160,6 +4308,8 @@ static u32 skl_plane_ctl_tiling(u64 fb_modifier)
>  		return PLANE_CTL_TILED_Y |
>  		       PLANE_CTL_RENDER_DECOMPRESSION_ENABLE |
>  		       PLANE_CTL_CLEAR_COLOR_DISABLE;
> +	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
> +		return PLANE_CTL_TILED_Y | PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE;
>  	case I915_FORMAT_MOD_Yf_TILED:
>  		return PLANE_CTL_TILED_YF;
>  	case I915_FORMAT_MOD_Yf_TILED_CCS:
> @@ -9968,6 +10118,8 @@ skylake_get_initial_plane_config(struct intel_crtc *crtc,
>  			fb->modifier = INTEL_GEN(dev_priv) >= 12 ?
>  				I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS :
>  				I915_FORMAT_MOD_Y_TILED_CCS;
> +		else if (val & PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE)
> +			fb->modifier = I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS;
>  		else
>  			fb->modifier = I915_FORMAT_MOD_Y_TILED;
>  		break;
> diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
> index 976669f01a8c..5998b959225c 100644
> --- a/drivers/gpu/drm/i915/display/intel_display_types.h
> +++ b/drivers/gpu/drm/i915/display/intel_display_types.h
> @@ -530,7 +530,7 @@ struct intel_plane_state {
>  		 */
>  		u32 stride;
>  		int x, y;
> -	} color_plane[2];
> +	} color_plane[4];
>  
>  	/* plane control register */
>  	u32 ctl;
> diff --git a/drivers/gpu/drm/i915/display/intel_sprite.c b/drivers/gpu/drm/i915/display/intel_sprite.c
> index 9b9b41b0fc91..788d0fc8d8ef 100644
> --- a/drivers/gpu/drm/i915/display/intel_sprite.c
> +++ b/drivers/gpu/drm/i915/display/intel_sprite.c
> @@ -532,11 +532,13 @@ skl_program_plane(struct intel_plane *plane,
>  	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
>  	enum plane_id plane_id = plane->id;
>  	enum pipe pipe = plane->pipe;
> +	const struct drm_framebuffer *fb = plane_state->base.fb;
> +	int aux_plane = fb->format->num_planes / 2 + color_plane;
>  	const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
>  	u32 surf_addr = plane_state->color_plane[color_plane].offset;
>  	u32 stride = skl_plane_stride(plane_state, color_plane);
> -	u32 aux_dist = plane_state->color_plane[1].offset - surf_addr;
> -	u32 aux_stride = skl_plane_stride(plane_state, 1);
> +	u32 aux_dist = plane_state->color_plane[aux_plane].offset - surf_addr;
> +	u32 aux_stride = skl_plane_stride(plane_state, aux_plane);
>  	int crtc_x = plane_state->base.dst.x1;
>  	int crtc_y = plane_state->base.dst.y1;
>  	u32 x = plane_state->color_plane[color_plane].x;
> @@ -544,7 +546,6 @@ skl_program_plane(struct intel_plane *plane,
>  	u32 src_w = drm_rect_width(&plane_state->base.src) >> 16;
>  	u32 src_h = drm_rect_height(&plane_state->base.src) >> 16;
>  	struct intel_plane *linked = plane_state->planar_linked_plane;
> -	const struct drm_framebuffer *fb = plane_state->base.fb;
>  	u8 alpha = plane_state->base.alpha >> 8;
>  	u32 plane_color_ctl = 0;
>  	unsigned long irqflags;
> @@ -619,8 +620,8 @@ skl_program_plane(struct intel_plane *plane,
>  
>  	if (INTEL_GEN(dev_priv) < 11)
>  		I915_WRITE_FW(PLANE_AUX_OFFSET(pipe, plane_id),
> -			      (plane_state->color_plane[1].y << 16) |
> -			      plane_state->color_plane[1].x);
> +			      (plane_state->color_plane[aux_plane].y << 16) |
> +			      plane_state->color_plane[aux_plane].x);
>  
>  	/*
>  	 * The control register self-arms if the plane was previously
> @@ -1737,7 +1738,8 @@ static int skl_plane_check_fb(const struct intel_crtc_state *crtc_state,
>  	     fb->modifier == I915_FORMAT_MOD_Yf_TILED ||
>  	     fb->modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
>  	     fb->modifier == I915_FORMAT_MOD_Yf_TILED_CCS ||
> -	     fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS)) {
> +	     fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS ||
> +	     fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS)) {
>  		DRM_DEBUG_KMS("Y/Yf tiling not supported in IF-ID mode\n");
>  		return -EINVAL;
>  	}
> @@ -2149,7 +2151,16 @@ static const u64 skl_plane_format_modifiers_ccs[] = {
>  	DRM_FORMAT_MOD_INVALID
>  };
>  
> -static const u64 gen12_plane_format_modifiers_ccs[] = {
> +static const u64 gen12_plane_format_modifiers_mc_ccs[] = {
> +	I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS,
> +	I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS,
> +	I915_FORMAT_MOD_Y_TILED,
> +	I915_FORMAT_MOD_X_TILED,
> +	DRM_FORMAT_MOD_LINEAR,
> +	DRM_FORMAT_MOD_INVALID
> +};
> +
> +static const u64 gen12_plane_format_modifiers_rc_ccs[] = {
>  	I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS,
>  	I915_FORMAT_MOD_Y_TILED,
>  	I915_FORMAT_MOD_X_TILED,
> @@ -2305,10 +2316,21 @@ static bool skl_plane_format_mod_supported(struct drm_plane *_plane,
>  	}
>  }
>  
> +static bool gen12_plane_supports_mc_ccs(enum plane_id plane_id)

plane_has_foo() is the common idiom.

> +{
> +	return plane_id < PLANE_SPRITE4;
> +}
> +
>  static bool gen12_plane_format_mod_supported(struct drm_plane *_plane,
>  					     u32 format, u64 modifier)
>  {
> +	struct intel_plane *plane = to_intel_plane(_plane);
> +
>  	switch (modifier) {
> +	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
> +		if (!gen12_plane_supports_mc_ccs(plane->id))
> +			return false;
> +		/* fall through */
>  	case DRM_FORMAT_MOD_LINEAR:
>  	case I915_FORMAT_MOD_X_TILED:
>  	case I915_FORMAT_MOD_Y_TILED:
> @@ -2326,14 +2348,17 @@ static bool gen12_plane_format_mod_supported(struct drm_plane *_plane,
>  		if (is_ccs_modifier(modifier))
>  			return true;
>  		/* fall through */
> -	case DRM_FORMAT_RGB565:
> -	case DRM_FORMAT_XRGB2101010:
> -	case DRM_FORMAT_XBGR2101010:
>  	case DRM_FORMAT_YUYV:
>  	case DRM_FORMAT_YVYU:
>  	case DRM_FORMAT_UYVY:
>  	case DRM_FORMAT_VYUY:
> +		if (modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS)
> +			return true;
> +		/* fall through */
>  	case DRM_FORMAT_NV12:
> +	case DRM_FORMAT_RGB565:
> +	case DRM_FORMAT_XRGB2101010:
> +	case DRM_FORMAT_XBGR2101010:
>  	case DRM_FORMAT_P010:
>  	case DRM_FORMAT_P012:
>  	case DRM_FORMAT_P016:
> @@ -2470,6 +2495,14 @@ static const u32 *icl_get_plane_formats(struct drm_i915_private *dev_priv,
>  	}
>  }
>  
> +static const u64 *gen12_get_plane_modifiers(enum plane_id plane_id)
> +{
> +	if (gen12_plane_supports_mc_ccs(plane_id))
> +		return gen12_plane_format_modifiers_mc_ccs;
> +	else
> +		return gen12_plane_format_modifiers_rc_ccs;
> +}
> +
>  static bool skl_plane_has_ccs(struct drm_i915_private *dev_priv,
>  			      enum pipe pipe, enum plane_id plane_id)
>  {
> @@ -2536,7 +2569,7 @@ skl_universal_plane_create(struct drm_i915_private *dev_priv,
>  
>  	plane->has_ccs = skl_plane_has_ccs(dev_priv, pipe, plane_id);
>  	if (INTEL_GEN(dev_priv) >= 12) {
> -		modifiers = gen12_plane_format_modifiers_ccs;
> +		modifiers = gen12_get_plane_modifiers(plane_id);
>  		plane_funcs = &gen12_plane_funcs;
>  	} else {
>  		if (plane->has_ccs)
> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> index 519cfb0a5c42..02eaef8adac0 100644
> --- a/drivers/gpu/drm/i915/i915_reg.h
> +++ b/drivers/gpu/drm/i915/i915_reg.h
> @@ -6697,6 +6697,7 @@ enum {
>  #define   PLANE_CTL_TILED_Y			(4 << 10)
>  #define   PLANE_CTL_TILED_YF			(5 << 10)
>  #define   PLANE_CTL_FLIP_HORIZONTAL		(1 << 8)
> +#define   PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE	(1 << 4) /* TGL+ */
>  #define   PLANE_CTL_ALPHA_MASK			(0x3 << 4) /* Pre-GLK */
>  #define   PLANE_CTL_ALPHA_DISABLE		(0 << 4)
>  #define   PLANE_CTL_ALPHA_SW_PREMULTIPLY	(2 << 4)
> -- 
> 2.17.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
Matt Roper Oct. 4, 2019, 8:27 p.m. UTC | #2
On Thu, Sep 26, 2019 at 03:55:12AM -0700, Dhinakaran Pandiyan wrote:
> Detect the modifier corresponding to media compression to enable
> display decompression for YUV and xRGB packed formats. A new modifier is
> added so that the driver can distinguish between media and render
> compressed buffers. Unlike render decompression, plane 6 and  plane 7 do not
> support media decompression.
> 
> v2: Fix checkpatch warnings on code style (Lucas)
> 
> From DK:
> Separate modifier array for planes that cannot decompress media (Ville)
> 
> v3: Support planar formats
> v4: Switch plane order
> 
> Cc: Nanley G Chery <nanley.g.chery@intel.com>
> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> Cc: Matt Roper <matthew.d.roper@intel.com>
> Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
> Signed-off-by: Lucas De Marchi <lucas.demarchi@intel.com>
> ---
>  drivers/gpu/drm/i915/display/intel_display.c  | 290 +++++++++++++-----
>  .../drm/i915/display/intel_display_types.h    |   2 +-
>  drivers/gpu/drm/i915/display/intel_sprite.c   |  55 +++-
>  drivers/gpu/drm/i915/i915_reg.h               |   1 +
>  4 files changed, 267 insertions(+), 81 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
> index 8ea55d67442c..df3ebaa167ab 100644
> --- a/drivers/gpu/drm/i915/display/intel_display.c
> +++ b/drivers/gpu/drm/i915/display/intel_display.c
> @@ -1888,6 +1888,22 @@ static void intel_disable_pipe(const struct intel_crtc_state *old_crtc_state)
>  		intel_wait_for_pipe_off(old_crtc_state);
>  }
>  
> +bool is_ccs_modifier(u64 modifier)
> +{
> +	return modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS ||
> +	       modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS ||
> +	       modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
> +	       modifier == I915_FORMAT_MOD_Yf_TILED_CCS;
> +}
> +
> +static bool is_ccs_plane(const struct drm_framebuffer *fb, int color_plane)
> +{
> +	if (!is_ccs_modifier(fb->modifier))
> +		return false;
> +
> +	return color_plane >= fb->format->num_planes / 2;
> +}

This appears to contradict what you indicated on the modifier patch:

  + * Y-tile widths. For semi-planar formats like NV12, CCS plane follows the
  + * Y and UV planes i.e., planes 0 and 2 are used for Y and UV surfaces,
  + * planes 1 and 3 for the respective CCS.

Based on that comment I'd expect something more like (color_plane % 2).


> +
>  static unsigned int intel_tile_size(const struct drm_i915_private *dev_priv)
>  {
>  	return IS_GEN(dev_priv, 2) ? 2048 : 4096;
> @@ -1908,11 +1924,13 @@ intel_tile_width_bytes(const struct drm_framebuffer *fb, int color_plane)
>  		else
>  			return 512;
>  	case I915_FORMAT_MOD_Y_TILED_CCS:
> -		if (color_plane == 1)
> +		if (is_ccs_plane(fb, color_plane))
>  			return 128;
>  		/* fall through */
> +	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
> +		/* fall through */
>  	case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
> -		if (color_plane == 1)
> +		if (is_ccs_plane(fb, color_plane))
>  			return 64;
>  		/* fall through */
>  	case I915_FORMAT_MOD_Y_TILED:
> @@ -1921,7 +1939,7 @@ intel_tile_width_bytes(const struct drm_framebuffer *fb, int color_plane)
>  		else
>  			return 512;
>  	case I915_FORMAT_MOD_Yf_TILED_CCS:
> -		if (color_plane == 1)
> +		if (is_ccs_plane(fb, color_plane))
>  			return 128;
>  		/* fall through */
>  	case I915_FORMAT_MOD_Yf_TILED:
> @@ -1949,8 +1967,9 @@ static unsigned int
>  intel_tile_height(const struct drm_framebuffer *fb, int color_plane)
>  {
>  	switch (fb->modifier) {
> +	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
>  	case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
> -		if (color_plane == 1)
> +		if (is_ccs_plane(fb, color_plane))
>  			return 1;
>  		/* fall through */
>  	default:
> @@ -2055,6 +2074,7 @@ static unsigned int intel_surf_alignment(const struct drm_framebuffer *fb,
>  		if (INTEL_GEN(dev_priv) >= 9)
>  			return 256 * 1024;
>  		return 0;
> +	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
>  	case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
>  		return 16 * 1024;
>  	case I915_FORMAT_MOD_Y_TILED_CCS:
> @@ -2254,10 +2274,17 @@ static u32 intel_adjust_tile_offset(int *x, int *y,
>  	return new_offset;
>  }
>  
> -static bool is_surface_linear(u64 modifier, int color_plane)
> +static bool is_surface_linear(const struct drm_framebuffer *fb, int color_plane)
>  {
> -	return modifier == DRM_FORMAT_MOD_LINEAR ||
> -	       (modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS && color_plane == 1);
> +	switch (fb->modifier) {
> +	case DRM_FORMAT_MOD_LINEAR:
> +		return true;
> +	case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
> +	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
> +		return is_ccs_plane(fb, color_plane);
> +	default:
> +		return false;
> +	}
>  }
>  
>  static u32 intel_adjust_aligned_offset(int *x, int *y,
> @@ -2272,7 +2299,7 @@ static u32 intel_adjust_aligned_offset(int *x, int *y,
>  
>  	WARN_ON(new_offset > old_offset);
>  
> -	if (!is_surface_linear(fb->modifier, color_plane)) {
> +	if (!is_surface_linear(fb, color_plane)) {
>  		unsigned int tile_size, tile_width, tile_height;
>  		unsigned int pitch_tiles;
>  
> @@ -2342,7 +2369,7 @@ static u32 intel_compute_aligned_offset(struct drm_i915_private *dev_priv,
>  	if (alignment)
>  		alignment--;
>  
> -	if (!is_surface_linear(fb->modifier, color_plane)) {
> +	if (!is_surface_linear(fb, color_plane)) {
>  		unsigned int tile_size, tile_width, tile_height;
>  		unsigned int tile_rows, tiles, pitch_tiles;
>  
> @@ -2445,6 +2472,7 @@ static unsigned int intel_fb_modifier_to_tiling(u64 fb_modifier)
>  	case I915_FORMAT_MOD_Y_TILED:
>  	case I915_FORMAT_MOD_Y_TILED_CCS:
>  	case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
> +	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
>  		return I915_TILING_Y;
>  	default:
>  		return I915_TILING_NONE;
> @@ -2494,6 +2522,13 @@ static const struct drm_format_info gen12_ccs_formats[] = {
>  	  .cpp = { 4, 1, }, .hsub = 2, .vsub = 32, .has_alpha = true },
>  };
>  
> +static const struct drm_format_info gen12_mc_ccs_formats[] = {
> +	{ .format = DRM_FORMAT_YUYV, .num_planes = 2,
> +	  .cpp = { 2, 1, }, .hsub = 4, .vsub = 32, .is_yuv = true },
> +	{ .format = DRM_FORMAT_NV12, .num_planes = 4,
> +	  .cpp = { 1, 2, 1, 1}, .hsub = 2, .vsub = 2, .is_yuv = true },
> +};

Don't we also support media compression on RGB and more packed YUV
formats?  I.e., see the matrix on bspec page 49250.

> +
>  static const struct drm_format_info *
>  lookup_format_info(const struct drm_format_info formats[],
>  		   int num_formats, u32 format)
> @@ -2511,12 +2546,21 @@ lookup_format_info(const struct drm_format_info formats[],
>  static const struct drm_format_info *
>  intel_get_format_info(const struct drm_mode_fb_cmd2 *cmd)
>  {
> +	const struct drm_format_info *info;
> +
>  	switch (cmd->modifier[0]) {
>  	case I915_FORMAT_MOD_Y_TILED_CCS:
>  	case I915_FORMAT_MOD_Yf_TILED_CCS:
>  		return lookup_format_info(skl_ccs_formats,
>  					  ARRAY_SIZE(skl_ccs_formats),
>  					  cmd->pixel_format);
> +	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
> +		info = lookup_format_info(gen12_mc_ccs_formats,
> +					  ARRAY_SIZE(gen12_mc_ccs_formats),
> +					  cmd->pixel_format);
> +		if (info)
> +			return info;
> +		/* fall through */

Oh, I see.  You're effectively unioning gen12_ccs_formats in with this
fall through.  I still thing that winds up being a bit confusing so I'd
at least put a comment up above the mc_ccs_formats table.  Although I
also worry that a future platform might allow render compression on some
format that it doesn't support media compression on, which would force
us to decouple the tables at that point.

Even given the union of the two tables, are we still missing some of the
arrangements of YUV422 (i.e., YVYU, UYVY, and VYUY)?

>  	case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
>  		return lookup_format_info(gen12_ccs_formats,
>  					  ARRAY_SIZE(gen12_ccs_formats),
> @@ -2526,13 +2570,6 @@ intel_get_format_info(const struct drm_mode_fb_cmd2 *cmd)
>  	}
>  }
>  
> -bool is_ccs_modifier(u64 modifier)
> -{
> -	return modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS ||
> -	       modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
> -	       modifier == I915_FORMAT_MOD_Yf_TILED_CCS;
> -}
> -
>  u32 intel_plane_fb_max_stride(struct drm_i915_private *dev_priv,
>  			      u32 pixel_format, u64 modifier)
>  {
> @@ -2576,7 +2613,7 @@ intel_fb_stride_alignment(const struct drm_framebuffer *fb, int color_plane)
>  	struct drm_i915_private *dev_priv = to_i915(fb->dev);
>  	u32 tile_width;
>  
> -	if (is_surface_linear(fb->modifier, color_plane)) {
> +	if (is_surface_linear(fb, color_plane)) {
>  		u32 max_stride = intel_plane_fb_max_stride(dev_priv,
>  							   fb->format->format,
>  							   fb->modifier);
> @@ -2592,7 +2629,7 @@ intel_fb_stride_alignment(const struct drm_framebuffer *fb, int color_plane)
>  	}
>  
>  	tile_width = intel_tile_width_bytes(fb, color_plane);
> -	if (is_ccs_modifier(fb->modifier) && color_plane == 0) {
> +	if (is_ccs_modifier(fb->modifier)) {
>  		/*
>  		 * Display WA #0531: skl,bxt,kbl,glk
>  		 *
> @@ -2602,7 +2639,7 @@ intel_fb_stride_alignment(const struct drm_framebuffer *fb, int color_plane)
>  		 * require the entire fb to accommodate that to avoid
>  		 * potential runtime errors at plane configuration time.
>  		 */
> -		if (IS_GEN(dev_priv, 9) && fb->width > 3840)
> +		if (IS_GEN(dev_priv, 9) && color_plane == 0 && fb->width > 3840)
>  			tile_width *= 4;
>  		/*
>  		 * The main surface pitch must be padded to a multiple of four
> @@ -2682,25 +2719,75 @@ static bool intel_plane_needs_remap(const struct intel_plane_state *plane_state)
>  	return stride > max_stride;
>  }
>  
> +static void
> +intel_fb_plane_get_subsampling(int *hsub, int *vsub, const struct drm_framebuffer *fb, int color_plane)
> +{
> +	int i;
> +	static const struct {
> +		u32 format;
> +		int vsub[4];
> +		int hsub[4];
> +	} mc_ccs_subsampling[] = { { .hsub = { 1, 2, 8, 16 },
> +				     .vsub = { 1, 2, 32, 32 },
> +				     .format = DRM_FORMAT_NV12, },
> +				 };
> +
> +	*hsub = fb->format->hsub;
> +	*vsub = fb->format->vsub;
> +
> +	if (fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS &&
> +	    fb->format->num_planes == 4) {
> +		for (i = 0; i < ARRAY_SIZE(mc_ccs_subsampling); i++) {
> +			if  (mc_ccs_subsampling[i].format == fb->format->format) {
> +				*hsub = mc_ccs_subsampling[i].hsub[color_plane];
> +				*vsub = mc_ccs_subsampling[i].vsub[color_plane];
> +				break;
> +			}
> +		}
> +		WARN_ON(i == ARRAY_SIZE(mc_ccs_subsampling));
> +	}
> +}
> +
> +static void
> +intel_fb_plane_dims(int *w, int *h, struct drm_framebuffer *fb, int color_plane)
> +{
> +	int hsub, vsub;
> +
> +	intel_fb_plane_get_subsampling(&hsub, &vsub, fb, color_plane);
> +	*w = fb->width/hsub;
> +	*h = fb->height/vsub;
> +}
> +
>  static int
> -intel_fb_check_ccs_xy(struct drm_framebuffer *fb, int x, int y)
> +intel_fb_check_ccs_xy(struct drm_framebuffer *fb, int aux_plane, int x, int y)
>  {
>  	struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
> -	int hsub = fb->format->hsub;
> -	int vsub = fb->format->vsub;
> +	int hsub, vsub;
> +	int hsub_main, vsub_main;
>  	int tile_width, tile_height;
>  	int ccs_x, ccs_y;
>  	int main_x, main_y;
> +	int main_plane;
> +
> +	if (!is_ccs_plane(fb, aux_plane))
> +		return 0;
> +
> +	main_plane = (aux_plane - 1) / 2;

This also doesn't mention the modifier description comment.  So I guess
that comment just needs to be updated, and maybe with a description that
the drm_framebuffer color plane ordering doesn't match the order that
they show up in memory.

> +	intel_tile_dims(fb, aux_plane, &tile_width, &tile_height);
> +	intel_fb_plane_get_subsampling(&hsub, &vsub, fb, aux_plane);
> +	intel_fb_plane_get_subsampling(&hsub_main, &vsub_main, fb,
> +				       main_plane);
>  
> -	intel_tile_dims(fb, 1, &tile_width, &tile_height);
> +	hsub /= hsub_main;
> +	vsub /= vsub_main;
>  
>  	tile_width *= hsub;
>  	tile_height *= vsub;
>  
>  	ccs_x = (x * hsub) % tile_width;
>  	ccs_y = (y * vsub) % tile_height;
> -	main_x = intel_fb->normal[0].x % tile_width;
> -	main_y = intel_fb->normal[0].y % tile_height;
> +	main_x = intel_fb->normal[main_plane].x % tile_width;
> +	main_y = intel_fb->normal[main_plane].y % tile_height;
>  
>  	/*
>  	* CCS doesn't have its own x/y offset register, so the intra CCS tile
> @@ -2710,8 +2797,8 @@ intel_fb_check_ccs_xy(struct drm_framebuffer *fb, int x, int y)
>  		DRM_DEBUG_KMS("Bad CCS x/y (main %d,%d ccs %d,%d) full (main %d,%d ccs %d,%d)\n",
>  			      main_x, main_y,
>  			      ccs_x, ccs_y,
> -			      intel_fb->normal[0].x,
> -			      intel_fb->normal[0].y,
> +			      intel_fb->normal[main_plane].x,
> +			      intel_fb->normal[main_plane].y,
>  			      x, y);
>  		return -EINVAL;
>  	}
> @@ -2739,8 +2826,7 @@ intel_fill_fb_info(struct drm_i915_private *dev_priv,
>  		int ret;
>  
>  		cpp = fb->format->cpp[i];
> -		width = drm_framebuffer_plane_width(fb->width, fb, i);
> -		height = drm_framebuffer_plane_height(fb->height, fb, i);
> +		intel_fb_plane_dims(&width, &height, fb, i);
>  
>  		ret = intel_fb_offset_to_xy(&x, &y, fb, i);
>  		if (ret) {
> @@ -2749,11 +2835,9 @@ intel_fill_fb_info(struct drm_i915_private *dev_priv,
>  			return ret;
>  		}
>  
> -		if (is_ccs_modifier(fb->modifier) && i == 1) {
> -			ret = intel_fb_check_ccs_xy(fb, x, y);
> -			if (ret)
> -				return ret;
> -		}
> +		ret = intel_fb_check_ccs_xy(fb, i, x, y);
> +		if (ret)
> +			return ret;
>  
>  		/*
>  		 * The fence (if used) is aligned to the start of the object
> @@ -3371,6 +3455,7 @@ static int skl_max_plane_width(const struct drm_framebuffer *fb,
>  			return 5120;
>  	case I915_FORMAT_MOD_Y_TILED_CCS:
>  	case I915_FORMAT_MOD_Yf_TILED_CCS:
> +	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
>  		/* FIXME AUX plane? */
>  	case I915_FORMAT_MOD_Y_TILED:
>  	case I915_FORMAT_MOD_Yf_TILED:
> @@ -3430,16 +3515,18 @@ static int icl_max_plane_height(void)
>  }
>  
>  static bool skl_check_main_ccs_coordinates(struct intel_plane_state *plane_state,
> -					   int main_x, int main_y, u32 main_offset)
> +					   int main_x, int main_y,
> +					   u32 main_offset, int aux_plane)
>  {
>  	const struct drm_framebuffer *fb = plane_state->base.fb;
> -	int hsub = fb->format->hsub;
> -	int vsub = fb->format->vsub;
> -	int aux_x = plane_state->color_plane[1].x;
> -	int aux_y = plane_state->color_plane[1].y;
> -	u32 aux_offset = plane_state->color_plane[1].offset;
> -	u32 alignment = intel_surf_alignment(fb, 1);
> -
> +	int hsub;
> +	int vsub;
> +	int aux_x = plane_state->color_plane[aux_plane].x;
> +	int aux_y = plane_state->color_plane[aux_plane].y;
> +	u32 aux_offset = plane_state->color_plane[aux_plane].offset;
> +	u32 alignment = intel_surf_alignment(fb, aux_plane);
> +
> +	intel_fb_plane_get_subsampling(&hsub, &vsub, fb, aux_plane);
>  	while (aux_offset >= main_offset && aux_y <= main_y) {
>  		int x, y;
>  
> @@ -3451,7 +3538,7 @@ static bool skl_check_main_ccs_coordinates(struct intel_plane_state *plane_state
>  
>  		x = aux_x / hsub;
>  		y = aux_y / vsub;
> -		aux_offset = intel_plane_adjust_aligned_offset(&x, &y, plane_state, 1,
> +		aux_offset = intel_plane_adjust_aligned_offset(&x, &y, plane_state, aux_plane,
>  							       aux_offset, aux_offset - alignment);
>  		aux_x = x * hsub + aux_x % hsub;
>  		aux_y = y * vsub + aux_y % vsub;
> @@ -3460,9 +3547,9 @@ static bool skl_check_main_ccs_coordinates(struct intel_plane_state *plane_state
>  	if (aux_x != main_x || aux_y != main_y)
>  		return false;
>  
> -	plane_state->color_plane[1].offset = aux_offset;
> -	plane_state->color_plane[1].x = aux_x;
> -	plane_state->color_plane[1].y = aux_y;
> +	plane_state->color_plane[aux_plane].offset = aux_offset;
> +	plane_state->color_plane[aux_plane].x = aux_x;
> +	plane_state->color_plane[aux_plane].y = aux_y;
>  
>  	return true;
>  }
> @@ -3478,7 +3565,8 @@ static int skl_check_main_surface(struct intel_plane_state *plane_state)
>  	int h = drm_rect_height(&plane_state->base.src) >> 16;
>  	int max_width;
>  	int max_height;
> -	u32 alignment, offset, aux_offset = plane_state->color_plane[1].offset;
> +	int aux_plane = fb->format->num_planes / 2;
> +	u32 alignment, offset, aux_offset = plane_state->color_plane[aux_plane].offset;
>  
>  	if (INTEL_GEN(dev_priv) >= 11)
>  		max_width = icl_max_plane_width(fb, 0, rotation);
> @@ -3536,7 +3624,9 @@ static int skl_check_main_surface(struct intel_plane_state *plane_state)
>  	 * they match with the main surface x/y offsets.
>  	 */
>  	if (is_ccs_modifier(fb->modifier)) {
> -		while (!skl_check_main_ccs_coordinates(plane_state, x, y, offset)) {
> +
> +		while (!skl_check_main_ccs_coordinates(plane_state, x, y,
> +						       offset, aux_plane)) {
>  			if (offset == 0)
>  				break;
>  
> @@ -3544,7 +3634,8 @@ static int skl_check_main_surface(struct intel_plane_state *plane_state)
>  								   offset, offset - alignment);
>  		}
>  
> -		if (x != plane_state->color_plane[1].x || y != plane_state->color_plane[1].y) {
> +		if (x != plane_state->color_plane[aux_plane].x ||
> +		    y != plane_state->color_plane[aux_plane].y) {
>  			DRM_DEBUG_KMS("Unable to find suitable display surface offset due to CCS\n");
>  			return -EINVAL;
>  		}
> @@ -3587,6 +3678,41 @@ static int skl_check_nv12_aux_surface(struct intel_plane_state *plane_state)
>  		return -EINVAL;
>  	}
>  
> +	if (is_ccs_modifier(fb->modifier)) {
> +		int aux_offset = plane_state->color_plane[3].offset;
> +		int alignment = intel_surf_alignment(fb, 1);
> +
> +		if (offset > aux_offset) {
> +			int hsub, vsub;
> +			int main_x = x, main_y = y;
> +
> +
> +			intel_fb_plane_get_subsampling(&hsub, &vsub, fb, 1);
> +			x = main_x / hsub;
> +			y = main_y / vsub;
> +			offset = intel_plane_adjust_aligned_offset(&x, &y, plane_state, 1,
> +								   offset,
> +								   aux_offset & ~(alignment - 1));
> +			x = x * hsub + main_x % hsub;
> +			y = y * vsub + main_y % vsub;
> +
> +		}
> +
> +		while (!skl_check_main_ccs_coordinates(plane_state, x, y, offset, 3)) {
> +			if (offset == 0)
> +				break;
> +
> +			offset = intel_plane_adjust_aligned_offset(&x, &y, plane_state, 1,
> +								   offset, offset - alignment);
> +		}
> +
> +		if (x != plane_state->color_plane[3].x ||
> +		    y != plane_state->color_plane[3].y) {
> +			DRM_DEBUG_KMS("Unable to find suitable display surface offset due to CCS\n");
> +			return -EINVAL;
> +		}
> +	}
> +
>  	plane_state->color_plane[1].offset = offset;
>  	plane_state->color_plane[1].x = x;
>  	plane_state->color_plane[1].y = y;
> @@ -3599,19 +3725,30 @@ static int skl_check_ccs_aux_surface(struct intel_plane_state *plane_state)
>  	const struct drm_framebuffer *fb = plane_state->base.fb;
>  	int src_x = plane_state->base.src.x1 >> 16;
>  	int src_y = plane_state->base.src.y1 >> 16;
> -	int hsub = fb->format->hsub;
> -	int vsub = fb->format->vsub;
> -	int x = src_x / hsub;
> -	int y = src_y / vsub;
>  	u32 offset;
> +	int ccs;
>  
> -	intel_add_fb_offsets(&x, &y, plane_state, 1);
> -	offset = intel_plane_compute_aligned_offset(&x, &y, plane_state, 1);
>  
> -	plane_state->color_plane[1].offset = offset;
> -	plane_state->color_plane[1].x = x * hsub + src_x % hsub;
> -	plane_state->color_plane[1].y = y * vsub + src_y % vsub;
> +	for (ccs = fb->format->num_planes / 2; ccs < fb->format->num_planes; ccs++) {
> +		int hsub, vsub;
> +		int main_hsub, main_vsub;
> +		int x, y;
> +
> +		intel_fb_plane_get_subsampling(&hsub, &vsub, fb, ccs);
> +		intel_fb_plane_get_subsampling(&main_hsub, &main_vsub, fb, (ccs - 1)/ 2);
> +
> +		hsub /= main_hsub;
> +		vsub /= main_vsub;
> +		x = src_x / hsub;
> +		y = src_y / vsub;
>  
> +		intel_add_fb_offsets(&x, &y, plane_state, ccs);
> +		offset = intel_plane_compute_aligned_offset(&x, &y,
> +							    plane_state, ccs);
> +		plane_state->color_plane[ccs].offset = offset;
> +		plane_state->color_plane[ccs].x = x * hsub + src_x % hsub;
> +		plane_state->color_plane[ccs].y = y * vsub + src_y % vsub;
> +	}
>  	return 0;
>  }
>  
> @@ -3619,6 +3756,7 @@ int skl_check_plane_surface(struct intel_plane_state *plane_state)
>  {
>  	const struct drm_framebuffer *fb = plane_state->base.fb;
>  	int ret;
> +	bool needs_aux = false;
>  
>  	ret = intel_plane_compute_gtt(plane_state);
>  	if (ret)
> @@ -3628,21 +3766,31 @@ int skl_check_plane_surface(struct intel_plane_state *plane_state)
>  		return 0;
>  
>  	/*
> -	 * Handle the AUX surface first since
> -	 * the main surface setup depends on it.
> +	 * Handle the AUX surface first since the main surface setup depends on
> +	 * it.
>  	 */
> -	if (drm_format_info_is_yuv_semiplanar(fb->format)) {
> -		ret = skl_check_nv12_aux_surface(plane_state);
> +	if (is_ccs_modifier(fb->modifier)) {
> +		needs_aux = true;
> +		ret = skl_check_ccs_aux_surface(plane_state);
>  		if (ret)
>  			return ret;
> -	} else if (is_ccs_modifier(fb->modifier)) {
> -		ret = skl_check_ccs_aux_surface(plane_state);
> +	}
> +
> +	if (drm_format_info_is_yuv_semiplanar(fb->format)) {
> +		needs_aux = true;
> +		ret = skl_check_nv12_aux_surface(plane_state);
>  		if (ret)
>  			return ret;
> -	} else {
> -		plane_state->color_plane[1].offset = ~0xfff;
> -		plane_state->color_plane[1].x = 0;
> -		plane_state->color_plane[1].y = 0;
> +	}
> +
> +	if (!needs_aux) {
> +		int i;
> +
> +		for (i = 1; i < fb->format->num_planes; i++) {
> +			plane_state->color_plane[i].offset = ~0xfff;
> +			plane_state->color_plane[i].x = 0;
> +			plane_state->color_plane[i].y = 0;
> +		}
>  	}
>  
>  	ret = skl_check_main_surface(plane_state);
> @@ -4030,7 +4178,7 @@ static unsigned int skl_plane_stride_mult(const struct drm_framebuffer *fb,
>  	 * The stride is either expressed as a multiple of 64 bytes chunks for
>  	 * linear buffers or in number of tiles for tiled buffers.
>  	 */
> -	if (is_surface_linear(fb->modifier, color_plane))
> +	if (is_surface_linear(fb, color_plane))
>  		return 64;
>  	else if (drm_rotation_90_or_270(rotation))
>  		return intel_tile_height(fb, color_plane);
> @@ -4160,6 +4308,8 @@ static u32 skl_plane_ctl_tiling(u64 fb_modifier)
>  		return PLANE_CTL_TILED_Y |
>  		       PLANE_CTL_RENDER_DECOMPRESSION_ENABLE |
>  		       PLANE_CTL_CLEAR_COLOR_DISABLE;
> +	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
> +		return PLANE_CTL_TILED_Y | PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE;
>  	case I915_FORMAT_MOD_Yf_TILED:
>  		return PLANE_CTL_TILED_YF;
>  	case I915_FORMAT_MOD_Yf_TILED_CCS:
> @@ -9968,6 +10118,8 @@ skylake_get_initial_plane_config(struct intel_crtc *crtc,
>  			fb->modifier = INTEL_GEN(dev_priv) >= 12 ?
>  				I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS :
>  				I915_FORMAT_MOD_Y_TILED_CCS;
> +		else if (val & PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE)
> +			fb->modifier = I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS;
>  		else
>  			fb->modifier = I915_FORMAT_MOD_Y_TILED;
>  		break;
> diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
> index 976669f01a8c..5998b959225c 100644
> --- a/drivers/gpu/drm/i915/display/intel_display_types.h
> +++ b/drivers/gpu/drm/i915/display/intel_display_types.h
> @@ -530,7 +530,7 @@ struct intel_plane_state {
>  		 */
>  		u32 stride;
>  		int x, y;
> -	} color_plane[2];
> +	} color_plane[4];
>  
>  	/* plane control register */
>  	u32 ctl;
> diff --git a/drivers/gpu/drm/i915/display/intel_sprite.c b/drivers/gpu/drm/i915/display/intel_sprite.c
> index 9b9b41b0fc91..788d0fc8d8ef 100644
> --- a/drivers/gpu/drm/i915/display/intel_sprite.c
> +++ b/drivers/gpu/drm/i915/display/intel_sprite.c
> @@ -532,11 +532,13 @@ skl_program_plane(struct intel_plane *plane,
>  	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
>  	enum plane_id plane_id = plane->id;
>  	enum pipe pipe = plane->pipe;
> +	const struct drm_framebuffer *fb = plane_state->base.fb;
> +	int aux_plane = fb->format->num_planes / 2 + color_plane;
>  	const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
>  	u32 surf_addr = plane_state->color_plane[color_plane].offset;
>  	u32 stride = skl_plane_stride(plane_state, color_plane);
> -	u32 aux_dist = plane_state->color_plane[1].offset - surf_addr;
> -	u32 aux_stride = skl_plane_stride(plane_state, 1);
> +	u32 aux_dist = plane_state->color_plane[aux_plane].offset - surf_addr;
> +	u32 aux_stride = skl_plane_stride(plane_state, aux_plane);
>  	int crtc_x = plane_state->base.dst.x1;
>  	int crtc_y = plane_state->base.dst.y1;
>  	u32 x = plane_state->color_plane[color_plane].x;
> @@ -544,7 +546,6 @@ skl_program_plane(struct intel_plane *plane,
>  	u32 src_w = drm_rect_width(&plane_state->base.src) >> 16;
>  	u32 src_h = drm_rect_height(&plane_state->base.src) >> 16;
>  	struct intel_plane *linked = plane_state->planar_linked_plane;
> -	const struct drm_framebuffer *fb = plane_state->base.fb;
>  	u8 alpha = plane_state->base.alpha >> 8;
>  	u32 plane_color_ctl = 0;
>  	unsigned long irqflags;
> @@ -619,8 +620,8 @@ skl_program_plane(struct intel_plane *plane,
>  
>  	if (INTEL_GEN(dev_priv) < 11)
>  		I915_WRITE_FW(PLANE_AUX_OFFSET(pipe, plane_id),
> -			      (plane_state->color_plane[1].y << 16) |
> -			      plane_state->color_plane[1].x);
> +			      (plane_state->color_plane[aux_plane].y << 16) |
> +			      plane_state->color_plane[aux_plane].x);
>  
>  	/*
>  	 * The control register self-arms if the plane was previously
> @@ -1737,7 +1738,8 @@ static int skl_plane_check_fb(const struct intel_crtc_state *crtc_state,
>  	     fb->modifier == I915_FORMAT_MOD_Yf_TILED ||
>  	     fb->modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
>  	     fb->modifier == I915_FORMAT_MOD_Yf_TILED_CCS ||
> -	     fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS)) {
> +	     fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS ||
> +	     fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS)) {
>  		DRM_DEBUG_KMS("Y/Yf tiling not supported in IF-ID mode\n");
>  		return -EINVAL;
>  	}
> @@ -2149,7 +2151,16 @@ static const u64 skl_plane_format_modifiers_ccs[] = {
>  	DRM_FORMAT_MOD_INVALID
>  };
>  
> -static const u64 gen12_plane_format_modifiers_ccs[] = {
> +static const u64 gen12_plane_format_modifiers_mc_ccs[] = {
> +	I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS,
> +	I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS,
> +	I915_FORMAT_MOD_Y_TILED,
> +	I915_FORMAT_MOD_X_TILED,
> +	DRM_FORMAT_MOD_LINEAR,
> +	DRM_FORMAT_MOD_INVALID
> +};
> +
> +static const u64 gen12_plane_format_modifiers_rc_ccs[] = {
>  	I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS,
>  	I915_FORMAT_MOD_Y_TILED,
>  	I915_FORMAT_MOD_X_TILED,
> @@ -2305,10 +2316,21 @@ static bool skl_plane_format_mod_supported(struct drm_plane *_plane,
>  	}
>  }
>  
> +static bool gen12_plane_supports_mc_ccs(enum plane_id plane_id)
> +{
> +	return plane_id < PLANE_SPRITE4;
> +}
> +
>  static bool gen12_plane_format_mod_supported(struct drm_plane *_plane,
>  					     u32 format, u64 modifier)
>  {
> +	struct intel_plane *plane = to_intel_plane(_plane);
> +
>  	switch (modifier) {
> +	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
> +		if (!gen12_plane_supports_mc_ccs(plane->id))
> +			return false;
> +		/* fall through */
>  	case DRM_FORMAT_MOD_LINEAR:
>  	case I915_FORMAT_MOD_X_TILED:
>  	case I915_FORMAT_MOD_Y_TILED:
> @@ -2326,14 +2348,17 @@ static bool gen12_plane_format_mod_supported(struct drm_plane *_plane,
>  		if (is_ccs_modifier(modifier))
>  			return true;
>  		/* fall through */
> -	case DRM_FORMAT_RGB565:
> -	case DRM_FORMAT_XRGB2101010:
> -	case DRM_FORMAT_XBGR2101010:
>  	case DRM_FORMAT_YUYV:
>  	case DRM_FORMAT_YVYU:
>  	case DRM_FORMAT_UYVY:
>  	case DRM_FORMAT_VYUY:
> +		if (modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS)
> +			return true;
> +		/* fall through */
>  	case DRM_FORMAT_NV12:
> +	case DRM_FORMAT_RGB565:
> +	case DRM_FORMAT_XRGB2101010:
> +	case DRM_FORMAT_XBGR2101010:
>  	case DRM_FORMAT_P010:
>  	case DRM_FORMAT_P012:
>  	case DRM_FORMAT_P016:
> @@ -2470,6 +2495,14 @@ static const u32 *icl_get_plane_formats(struct drm_i915_private *dev_priv,
>  	}
>  }
>  
> +static const u64 *gen12_get_plane_modifiers(enum plane_id plane_id)
> +{
> +	if (gen12_plane_supports_mc_ccs(plane_id))
> +		return gen12_plane_format_modifiers_mc_ccs;
> +	else
> +		return gen12_plane_format_modifiers_rc_ccs;
> +}
> +
>  static bool skl_plane_has_ccs(struct drm_i915_private *dev_priv,
>  			      enum pipe pipe, enum plane_id plane_id)
>  {
> @@ -2536,7 +2569,7 @@ skl_universal_plane_create(struct drm_i915_private *dev_priv,
>  
>  	plane->has_ccs = skl_plane_has_ccs(dev_priv, pipe, plane_id);
>  	if (INTEL_GEN(dev_priv) >= 12) {
> -		modifiers = gen12_plane_format_modifiers_ccs;
> +		modifiers = gen12_get_plane_modifiers(plane_id);
>  		plane_funcs = &gen12_plane_funcs;
>  	} else {
>  		if (plane->has_ccs)
> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> index 519cfb0a5c42..02eaef8adac0 100644
> --- a/drivers/gpu/drm/i915/i915_reg.h
> +++ b/drivers/gpu/drm/i915/i915_reg.h
> @@ -6697,6 +6697,7 @@ enum {
>  #define   PLANE_CTL_TILED_Y			(4 << 10)
>  #define   PLANE_CTL_TILED_YF			(5 << 10)
>  #define   PLANE_CTL_FLIP_HORIZONTAL		(1 << 8)
> +#define   PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE	(1 << 4) /* TGL+ */
>  #define   PLANE_CTL_ALPHA_MASK			(0x3 << 4) /* Pre-GLK */
>  #define   PLANE_CTL_ALPHA_DISABLE		(0 << 4)
>  #define   PLANE_CTL_ALPHA_SW_PREMULTIPLY	(2 << 4)
> -- 
> 2.17.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
Dhinakaran Pandiyan Oct. 4, 2019, 11:20 p.m. UTC | #3
On Fri, 2019-10-04 at 13:27 -0700, Matt Roper wrote:
> On Thu, Sep 26, 2019 at 03:55:12AM -0700, Dhinakaran Pandiyan wrote:
> > Detect the modifier corresponding to media compression to enable
> > display decompression for YUV and xRGB packed formats. A new modifier is
> > added so that the driver can distinguish between media and render
> > compressed buffers. Unlike render decompression, plane 6 and  plane 7 do not
> > support media decompression.
> > 
> > v2: Fix checkpatch warnings on code style (Lucas)
> > 
> > From DK:
> > Separate modifier array for planes that cannot decompress media (Ville)
> > 
> > v3: Support planar formats
> > v4: Switch plane order
> > 
> > Cc: Nanley G Chery <nanley.g.chery@intel.com>
> > Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > Cc: Matt Roper <matthew.d.roper@intel.com>
> > Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
> > Signed-off-by: Lucas De Marchi <lucas.demarchi@intel.com>
> > ---
> >  drivers/gpu/drm/i915/display/intel_display.c  | 290 +++++++++++++-----
> >  .../drm/i915/display/intel_display_types.h    |   2 +-
> >  drivers/gpu/drm/i915/display/intel_sprite.c   |  55 +++-
> >  drivers/gpu/drm/i915/i915_reg.h               |   1 +
> >  4 files changed, 267 insertions(+), 81 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/display/intel_display.c
> > b/drivers/gpu/drm/i915/display/intel_display.c
> > index 8ea55d67442c..df3ebaa167ab 100644
> > --- a/drivers/gpu/drm/i915/display/intel_display.c
> > +++ b/drivers/gpu/drm/i915/display/intel_display.c
> > @@ -1888,6 +1888,22 @@ static void intel_disable_pipe(const struct intel_crtc_state
> > *old_crtc_state)
> >  		intel_wait_for_pipe_off(old_crtc_state);
> >  }
> >  
> > +bool is_ccs_modifier(u64 modifier)
> > +{
> > +	return modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS ||
> > +	       modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS ||
> > +	       modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
> > +	       modifier == I915_FORMAT_MOD_Yf_TILED_CCS;
> > +}
> > +
> > +static bool is_ccs_plane(const struct drm_framebuffer *fb, int color_plane)
> > +{
> > +	if (!is_ccs_modifier(fb->modifier))
> > +		return false;
> > +
> > +	return color_plane >= fb->format->num_planes / 2;
> > +}
> 
> This appears to contradict what you indicated on the modifier patch:
> 
>   + * Y-tile widths. For semi-planar formats like NV12, CCS plane follows the
>   + * Y and UV planes i.e., planes 0 and 2 are used for Y and UV surfaces,
>   + * planes 1 and 3 for the respective CCS.
> 
> Based on that comment I'd expect something more like (color_plane % 2).

I need to update the comment in the modifier patch, thanks for catching this. The major change in
this version is 

for planar formats: planes 2 and 3 will be used for CCS instead of 1 and 3. 
for packed formats: plane 1 will be used for CCS

> 
> 
> > +
> >  static unsigned int intel_tile_size(const struct drm_i915_private *dev_priv)
> >  {
> >  	return IS_GEN(dev_priv, 2) ? 2048 : 4096;
> > @@ -1908,11 +1924,13 @@ intel_tile_width_bytes(const struct drm_framebuffer *fb, int
> > color_plane)
> >  		else
> >  			return 512;
> >  	case I915_FORMAT_MOD_Y_TILED_CCS:
> > -		if (color_plane == 1)
> > +		if (is_ccs_plane(fb, color_plane))
> >  			return 128;
> >  		/* fall through */
> > +	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
> > +		/* fall through */
> >  	case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
> > -		if (color_plane == 1)
> > +		if (is_ccs_plane(fb, color_plane))
> >  			return 64;
> >  		/* fall through */
> >  	case I915_FORMAT_MOD_Y_TILED:
> > @@ -1921,7 +1939,7 @@ intel_tile_width_bytes(const struct drm_framebuffer *fb, int color_plane)
> >  		else
> >  			return 512;
> >  	case I915_FORMAT_MOD_Yf_TILED_CCS:
> > -		if (color_plane == 1)
> > +		if (is_ccs_plane(fb, color_plane))
> >  			return 128;
> >  		/* fall through */
> >  	case I915_FORMAT_MOD_Yf_TILED:
> > @@ -1949,8 +1967,9 @@ static unsigned int
> >  intel_tile_height(const struct drm_framebuffer *fb, int color_plane)
> >  {
> >  	switch (fb->modifier) {
> > +	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
> >  	case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
> > -		if (color_plane == 1)
> > +		if (is_ccs_plane(fb, color_plane))
> >  			return 1;
> >  		/* fall through */
> >  	default:
> > @@ -2055,6 +2074,7 @@ static unsigned int intel_surf_alignment(const struct drm_framebuffer *fb,
> >  		if (INTEL_GEN(dev_priv) >= 9)
> >  			return 256 * 1024;
> >  		return 0;
> > +	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
> >  	case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
> >  		return 16 * 1024;
> >  	case I915_FORMAT_MOD_Y_TILED_CCS:
> > @@ -2254,10 +2274,17 @@ static u32 intel_adjust_tile_offset(int *x, int *y,
> >  	return new_offset;
> >  }
> >  
> > -static bool is_surface_linear(u64 modifier, int color_plane)
> > +static bool is_surface_linear(const struct drm_framebuffer *fb, int color_plane)
> >  {
> > -	return modifier == DRM_FORMAT_MOD_LINEAR ||
> > -	       (modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS && color_plane == 1);
> > +	switch (fb->modifier) {
> > +	case DRM_FORMAT_MOD_LINEAR:
> > +		return true;
> > +	case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
> > +	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
> > +		return is_ccs_plane(fb, color_plane);
> > +	default:
> > +		return false;
> > +	}
> >  }
> >  
> >  static u32 intel_adjust_aligned_offset(int *x, int *y,
> > @@ -2272,7 +2299,7 @@ static u32 intel_adjust_aligned_offset(int *x, int *y,
> >  
> >  	WARN_ON(new_offset > old_offset);
> >  
> > -	if (!is_surface_linear(fb->modifier, color_plane)) {
> > +	if (!is_surface_linear(fb, color_plane)) {
> >  		unsigned int tile_size, tile_width, tile_height;
> >  		unsigned int pitch_tiles;
> >  
> > @@ -2342,7 +2369,7 @@ static u32 intel_compute_aligned_offset(struct drm_i915_private *dev_priv,
> >  	if (alignment)
> >  		alignment--;
> >  
> > -	if (!is_surface_linear(fb->modifier, color_plane)) {
> > +	if (!is_surface_linear(fb, color_plane)) {
> >  		unsigned int tile_size, tile_width, tile_height;
> >  		unsigned int tile_rows, tiles, pitch_tiles;
> >  
> > @@ -2445,6 +2472,7 @@ static unsigned int intel_fb_modifier_to_tiling(u64 fb_modifier)
> >  	case I915_FORMAT_MOD_Y_TILED:
> >  	case I915_FORMAT_MOD_Y_TILED_CCS:
> >  	case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
> > +	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
> >  		return I915_TILING_Y;
> >  	default:
> >  		return I915_TILING_NONE;
> > @@ -2494,6 +2522,13 @@ static const struct drm_format_info gen12_ccs_formats[] = {
> >  	  .cpp = { 4, 1, }, .hsub = 2, .vsub = 32, .has_alpha = true },
> >  };
> >  
> > +static const struct drm_format_info gen12_mc_ccs_formats[] = {
> > +	{ .format = DRM_FORMAT_YUYV, .num_planes = 2,
> > +	  .cpp = { 2, 1, }, .hsub = 4, .vsub = 32, .is_yuv = true },
> > +	{ .format = DRM_FORMAT_NV12, .num_planes = 4,
> > +	  .cpp = { 1, 2, 1, 1}, .hsub = 2, .vsub = 2, .is_yuv = true },
> > +};
> 
> Don't we also support media compression on RGB and more packed YUV
> formats?  I.e., see the matrix on bspec page 49250.
> 
> > +
> >  static const struct drm_format_info *
> >  lookup_format_info(const struct drm_format_info formats[],
> >  		   int num_formats, u32 format)
> > @@ -2511,12 +2546,21 @@ lookup_format_info(const struct drm_format_info formats[],
> >  static const struct drm_format_info *
> >  intel_get_format_info(const struct drm_mode_fb_cmd2 *cmd)
> >  {
> > +	const struct drm_format_info *info;
> > +
> >  	switch (cmd->modifier[0]) {
> >  	case I915_FORMAT_MOD_Y_TILED_CCS:
> >  	case I915_FORMAT_MOD_Yf_TILED_CCS:
> >  		return lookup_format_info(skl_ccs_formats,
> >  					  ARRAY_SIZE(skl_ccs_formats),
> >  					  cmd->pixel_format);
> > +	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
> > +		info = lookup_format_info(gen12_mc_ccs_formats,
> > +					  ARRAY_SIZE(gen12_mc_ccs_formats),
> > +					  cmd->pixel_format);
> > +		if (info)
> > +			return info;
> > +		/* fall through */
> 
> Oh, I see.  You're effectively unioning gen12_ccs_formats in with this
> fall through.  I still thing that winds up being a bit confusing so I'd
> at least put a comment up above the mc_ccs_formats table.  Although I
> also worry that a future platform might allow render compression on some
> format that it doesn't support media compression on, which would force
> us to decouple the tables at that point.
> 
> Even given the union of the two tables, are we still missing some of the
> arrangements of YUV422 (i.e., YVYU, UYVY, and VYUY)?

I did not include all the supported formats I wanted to get feedback on the interface for planar
formats. I'll add them in the next version.
 
> 
> >  	case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
> >  		return lookup_format_info(gen12_ccs_formats,
> >  					  ARRAY_SIZE(gen12_ccs_formats),
> > @@ -2526,13 +2570,6 @@ intel_get_format_info(const struct drm_mode_fb_cmd2 *cmd)
> >  	}
> >  }
> >  
> > -bool is_ccs_modifier(u64 modifier)
> > -{
> > -	return modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS ||
> > -	       modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
> > -	       modifier == I915_FORMAT_MOD_Yf_TILED_CCS;
> > -}
> > -
> >  u32 intel_plane_fb_max_stride(struct drm_i915_private *dev_priv,
> >  			      u32 pixel_format, u64 modifier)
> >  {
> > @@ -2576,7 +2613,7 @@ intel_fb_stride_alignment(const struct drm_framebuffer *fb, int
> > color_plane)
> >  	struct drm_i915_private *dev_priv = to_i915(fb->dev);
> >  	u32 tile_width;
> >  
> > -	if (is_surface_linear(fb->modifier, color_plane)) {
> > +	if (is_surface_linear(fb, color_plane)) {
> >  		u32 max_stride = intel_plane_fb_max_stride(dev_priv,
> >  							   fb->format->format,
> >  							   fb->modifier);
> > @@ -2592,7 +2629,7 @@ intel_fb_stride_alignment(const struct drm_framebuffer *fb, int
> > color_plane)
> >  	}
> >  
> >  	tile_width = intel_tile_width_bytes(fb, color_plane);
> > -	if (is_ccs_modifier(fb->modifier) && color_plane == 0) {
> > +	if (is_ccs_modifier(fb->modifier)) {
> >  		/*
> >  		 * Display WA #0531: skl,bxt,kbl,glk
> >  		 *
> > @@ -2602,7 +2639,7 @@ intel_fb_stride_alignment(const struct drm_framebuffer *fb, int
> > color_plane)
> >  		 * require the entire fb to accommodate that to avoid
> >  		 * potential runtime errors at plane configuration time.
> >  		 */
> > -		if (IS_GEN(dev_priv, 9) && fb->width > 3840)
> > +		if (IS_GEN(dev_priv, 9) && color_plane == 0 && fb->width > 3840)
> >  			tile_width *= 4;
> >  		/*
> >  		 * The main surface pitch must be padded to a multiple of four
> > @@ -2682,25 +2719,75 @@ static bool intel_plane_needs_remap(const struct intel_plane_state
> > *plane_state)
> >  	return stride > max_stride;
> >  }
> >  
> > +static void
> > +intel_fb_plane_get_subsampling(int *hsub, int *vsub, const struct drm_framebuffer *fb, int
> > color_plane)
> > +{
> > +	int i;
> > +	static const struct {
> > +		u32 format;
> > +		int vsub[4];
> > +		int hsub[4];
> > +	} mc_ccs_subsampling[] = { { .hsub = { 1, 2, 8, 16 },
> > +				     .vsub = { 1, 2, 32, 32 },
> > +				     .format = DRM_FORMAT_NV12, },
> > +				 };
> > +
> > +	*hsub = fb->format->hsub;
> > +	*vsub = fb->format->vsub;
> > +
> > +	if (fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS &&
> > +	    fb->format->num_planes == 4) {
> > +		for (i = 0; i < ARRAY_SIZE(mc_ccs_subsampling); i++) {
> > +			if  (mc_ccs_subsampling[i].format == fb->format->format) {
> > +				*hsub = mc_ccs_subsampling[i].hsub[color_plane];
> > +				*vsub = mc_ccs_subsampling[i].vsub[color_plane];
> > +				break;
> > +			}
> > +		}
> > +		WARN_ON(i == ARRAY_SIZE(mc_ccs_subsampling));
> > +	}
> > +}
> > +
> > +static void
> > +intel_fb_plane_dims(int *w, int *h, struct drm_framebuffer *fb, int color_plane)
> > +{
> > +	int hsub, vsub;
> > +
> > +	intel_fb_plane_get_subsampling(&hsub, &vsub, fb, color_plane);
> > +	*w = fb->width/hsub;
> > +	*h = fb->height/vsub;
> > +}
> > +
> >  static int
> > -intel_fb_check_ccs_xy(struct drm_framebuffer *fb, int x, int y)
> > +intel_fb_check_ccs_xy(struct drm_framebuffer *fb, int aux_plane, int x, int y)
> >  {
> >  	struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
> > -	int hsub = fb->format->hsub;
> > -	int vsub = fb->format->vsub;
> > +	int hsub, vsub;
> > +	int hsub_main, vsub_main;
> >  	int tile_width, tile_height;
> >  	int ccs_x, ccs_y;
> >  	int main_x, main_y;
> > +	int main_plane;
> > +
> > +	if (!is_ccs_plane(fb, aux_plane))
> > +		return 0;
> > +
> > +	main_plane = (aux_plane - 1) / 2;
> 
> This also doesn't mention the modifier description comment.  So I guess
> that comment just needs to be updated, 
Yeah.

> and maybe with a description that
> the drm_framebuffer color plane ordering doesn't match the order that
> they show up in memory.

The color plane ordering is expected to match the surfaces positions in memory. My understanding is
that UMD's have the flexibility in their ordering, with the only constraints being 
1) CCS must be placed after the corresponding main surface
2) UV must be placed after Y.

Thanks for the feedback.

-DK

> 
> > +	intel_tile_dims(fb, aux_plane, &tile_width, &tile_height);
> > +	intel_fb_plane_get_subsampling(&hsub, &vsub, fb, aux_plane);
> > +	intel_fb_plane_get_subsampling(&hsub_main, &vsub_main, fb,
> > +				       main_plane);
> >  
> > -	intel_tile_dims(fb, 1, &tile_width, &tile_height);
> > +	hsub /= hsub_main;
> > +	vsub /= vsub_main;
> >  
> >  	tile_width *= hsub;
> >  	tile_height *= vsub;
> >  
> >  	ccs_x = (x * hsub) % tile_width;
> >  	ccs_y = (y * vsub) % tile_height;
> > -	main_x = intel_fb->normal[0].x % tile_width;
> > -	main_y = intel_fb->normal[0].y % tile_height;
> > +	main_x = intel_fb->normal[main_plane].x % tile_width;
> > +	main_y = intel_fb->normal[main_plane].y % tile_height;
> >  
> >  	/*
> >  	* CCS doesn't have its own x/y offset register, so the intra CCS tile
> > @@ -2710,8 +2797,8 @@ intel_fb_check_ccs_xy(struct drm_framebuffer *fb, int x, int y)
> >  		DRM_DEBUG_KMS("Bad CCS x/y (main %d,%d ccs %d,%d) full (main %d,%d ccs %d,%d)\n",
> >  			      main_x, main_y,
> >  			      ccs_x, ccs_y,
> > -			      intel_fb->normal[0].x,
> > -			      intel_fb->normal[0].y,
> > +			      intel_fb->normal[main_plane].x,
> > +			      intel_fb->normal[main_plane].y,
> >  			      x, y);
> >  		return -EINVAL;
> >  	}
> > @@ -2739,8 +2826,7 @@ intel_fill_fb_info(struct drm_i915_private *dev_priv,
> >  		int ret;
> >  
> >  		cpp = fb->format->cpp[i];
> > -		width = drm_framebuffer_plane_width(fb->width, fb, i);
> > -		height = drm_framebuffer_plane_height(fb->height, fb, i);
> > +		intel_fb_plane_dims(&width, &height, fb, i);
> >  
> >  		ret = intel_fb_offset_to_xy(&x, &y, fb, i);
> >  		if (ret) {
> > @@ -2749,11 +2835,9 @@ intel_fill_fb_info(struct drm_i915_private *dev_priv,
> >  			return ret;
> >  		}
> >  
> > -		if (is_ccs_modifier(fb->modifier) && i == 1) {
> > -			ret = intel_fb_check_ccs_xy(fb, x, y);
> > -			if (ret)
> > -				return ret;
> > -		}
> > +		ret = intel_fb_check_ccs_xy(fb, i, x, y);
> > +		if (ret)
> > +			return ret;
> >  
> >  		/*
> >  		 * The fence (if used) is aligned to the start of the object
> > @@ -3371,6 +3455,7 @@ static int skl_max_plane_width(const struct drm_framebuffer *fb,
> >  			return 5120;
> >  	case I915_FORMAT_MOD_Y_TILED_CCS:
> >  	case I915_FORMAT_MOD_Yf_TILED_CCS:
> > +	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
> >  		/* FIXME AUX plane? */
> >  	case I915_FORMAT_MOD_Y_TILED:
> >  	case I915_FORMAT_MOD_Yf_TILED:
> > @@ -3430,16 +3515,18 @@ static int icl_max_plane_height(void)
> >  }
> >  
> >  static bool skl_check_main_ccs_coordinates(struct intel_plane_state *plane_state,
> > -					   int main_x, int main_y, u32 main_offset)
> > +					   int main_x, int main_y,
> > +					   u32 main_offset, int aux_plane)
> >  {
> >  	const struct drm_framebuffer *fb = plane_state->base.fb;
> > -	int hsub = fb->format->hsub;
> > -	int vsub = fb->format->vsub;
> > -	int aux_x = plane_state->color_plane[1].x;
> > -	int aux_y = plane_state->color_plane[1].y;
> > -	u32 aux_offset = plane_state->color_plane[1].offset;
> > -	u32 alignment = intel_surf_alignment(fb, 1);
> > -
> > +	int hsub;
> > +	int vsub;
> > +	int aux_x = plane_state->color_plane[aux_plane].x;
> > +	int aux_y = plane_state->color_plane[aux_plane].y;
> > +	u32 aux_offset = plane_state->color_plane[aux_plane].offset;
> > +	u32 alignment = intel_surf_alignment(fb, aux_plane);
> > +
> > +	intel_fb_plane_get_subsampling(&hsub, &vsub, fb, aux_plane);
> >  	while (aux_offset >= main_offset && aux_y <= main_y) {
> >  		int x, y;
> >  
> > @@ -3451,7 +3538,7 @@ static bool skl_check_main_ccs_coordinates(struct intel_plane_state
> > *plane_state
> >  
> >  		x = aux_x / hsub;
> >  		y = aux_y / vsub;
> > -		aux_offset = intel_plane_adjust_aligned_offset(&x, &y, plane_state, 1,
> > +		aux_offset = intel_plane_adjust_aligned_offset(&x, &y, plane_state, aux_plane,
> >  							       aux_offset, aux_offset - alignment);
> >  		aux_x = x * hsub + aux_x % hsub;
> >  		aux_y = y * vsub + aux_y % vsub;
> > @@ -3460,9 +3547,9 @@ static bool skl_check_main_ccs_coordinates(struct intel_plane_state
> > *plane_state
> >  	if (aux_x != main_x || aux_y != main_y)
> >  		return false;
> >  
> > -	plane_state->color_plane[1].offset = aux_offset;
> > -	plane_state->color_plane[1].x = aux_x;
> > -	plane_state->color_plane[1].y = aux_y;
> > +	plane_state->color_plane[aux_plane].offset = aux_offset;
> > +	plane_state->color_plane[aux_plane].x = aux_x;
> > +	plane_state->color_plane[aux_plane].y = aux_y;
> >  
> >  	return true;
> >  }
> > @@ -3478,7 +3565,8 @@ static int skl_check_main_surface(struct intel_plane_state *plane_state)
> >  	int h = drm_rect_height(&plane_state->base.src) >> 16;
> >  	int max_width;
> >  	int max_height;
> > -	u32 alignment, offset, aux_offset = plane_state->color_plane[1].offset;
> > +	int aux_plane = fb->format->num_planes / 2;
> > +	u32 alignment, offset, aux_offset = plane_state->color_plane[aux_plane].offset;
> >  
> >  	if (INTEL_GEN(dev_priv) >= 11)
> >  		max_width = icl_max_plane_width(fb, 0, rotation);
> > @@ -3536,7 +3624,9 @@ static int skl_check_main_surface(struct intel_plane_state *plane_state)
> >  	 * they match with the main surface x/y offsets.
> >  	 */
> >  	if (is_ccs_modifier(fb->modifier)) {
> > -		while (!skl_check_main_ccs_coordinates(plane_state, x, y, offset)) {
> > +
> > +		while (!skl_check_main_ccs_coordinates(plane_state, x, y,
> > +						       offset, aux_plane)) {
> >  			if (offset == 0)
> >  				break;
> >  
> > @@ -3544,7 +3634,8 @@ static int skl_check_main_surface(struct intel_plane_state *plane_state)
> >  								   offset, offset - alignment);
> >  		}
> >  
> > -		if (x != plane_state->color_plane[1].x || y != plane_state->color_plane[1].y) {
> > +		if (x != plane_state->color_plane[aux_plane].x ||
> > +		    y != plane_state->color_plane[aux_plane].y) {
> >  			DRM_DEBUG_KMS("Unable to find suitable display surface offset due to
> > CCS\n");
> >  			return -EINVAL;
> >  		}
> > @@ -3587,6 +3678,41 @@ static int skl_check_nv12_aux_surface(struct intel_plane_state
> > *plane_state)
> >  		return -EINVAL;
> >  	}
> >  
> > +	if (is_ccs_modifier(fb->modifier)) {
> > +		int aux_offset = plane_state->color_plane[3].offset;
> > +		int alignment = intel_surf_alignment(fb, 1);
> > +
> > +		if (offset > aux_offset) {
> > +			int hsub, vsub;
> > +			int main_x = x, main_y = y;
> > +
> > +
> > +			intel_fb_plane_get_subsampling(&hsub, &vsub, fb, 1);
> > +			x = main_x / hsub;
> > +			y = main_y / vsub;
> > +			offset = intel_plane_adjust_aligned_offset(&x, &y, plane_state, 1,
> > +								   offset,
> > +								   aux_offset & ~(alignment - 1));
> > +			x = x * hsub + main_x % hsub;
> > +			y = y * vsub + main_y % vsub;
> > +
> > +		}
> > +
> > +		while (!skl_check_main_ccs_coordinates(plane_state, x, y, offset, 3)) {
> > +			if (offset == 0)
> > +				break;
> > +
> > +			offset = intel_plane_adjust_aligned_offset(&x, &y, plane_state, 1,
> > +								   offset, offset - alignment);
> > +		}
> > +
> > +		if (x != plane_state->color_plane[3].x ||
> > +		    y != plane_state->color_plane[3].y) {
> > +			DRM_DEBUG_KMS("Unable to find suitable display surface offset due to
> > CCS\n");
> > +			return -EINVAL;
> > +		}
> > +	}
> > +
> >  	plane_state->color_plane[1].offset = offset;
> >  	plane_state->color_plane[1].x = x;
> >  	plane_state->color_plane[1].y = y;
> > @@ -3599,19 +3725,30 @@ static int skl_check_ccs_aux_surface(struct intel_plane_state
> > *plane_state)
> >  	const struct drm_framebuffer *fb = plane_state->base.fb;
> >  	int src_x = plane_state->base.src.x1 >> 16;
> >  	int src_y = plane_state->base.src.y1 >> 16;
> > -	int hsub = fb->format->hsub;
> > -	int vsub = fb->format->vsub;
> > -	int x = src_x / hsub;
> > -	int y = src_y / vsub;
> >  	u32 offset;
> > +	int ccs;
> >  
> > -	intel_add_fb_offsets(&x, &y, plane_state, 1);
> > -	offset = intel_plane_compute_aligned_offset(&x, &y, plane_state, 1);
> >  
> > -	plane_state->color_plane[1].offset = offset;
> > -	plane_state->color_plane[1].x = x * hsub + src_x % hsub;
> > -	plane_state->color_plane[1].y = y * vsub + src_y % vsub;
> > +	for (ccs = fb->format->num_planes / 2; ccs < fb->format->num_planes; ccs++) {
> > +		int hsub, vsub;
> > +		int main_hsub, main_vsub;
> > +		int x, y;
> > +
> > +		intel_fb_plane_get_subsampling(&hsub, &vsub, fb, ccs);
> > +		intel_fb_plane_get_subsampling(&main_hsub, &main_vsub, fb, (ccs - 1)/ 2);
> > +
> > +		hsub /= main_hsub;
> > +		vsub /= main_vsub;
> > +		x = src_x / hsub;
> > +		y = src_y / vsub;
> >  
> > +		intel_add_fb_offsets(&x, &y, plane_state, ccs);
> > +		offset = intel_plane_compute_aligned_offset(&x, &y,
> > +							    plane_state, ccs);
> > +		plane_state->color_plane[ccs].offset = offset;
> > +		plane_state->color_plane[ccs].x = x * hsub + src_x % hsub;
> > +		plane_state->color_plane[ccs].y = y * vsub + src_y % vsub;
> > +	}
> >  	return 0;
> >  }
> >  
> > @@ -3619,6 +3756,7 @@ int skl_check_plane_surface(struct intel_plane_state *plane_state)
> >  {
> >  	const struct drm_framebuffer *fb = plane_state->base.fb;
> >  	int ret;
> > +	bool needs_aux = false;
> >  
> >  	ret = intel_plane_compute_gtt(plane_state);
> >  	if (ret)
> > @@ -3628,21 +3766,31 @@ int skl_check_plane_surface(struct intel_plane_state *plane_state)
> >  		return 0;
> >  
> >  	/*
> > -	 * Handle the AUX surface first since
> > -	 * the main surface setup depends on it.
> > +	 * Handle the AUX surface first since the main surface setup depends on
> > +	 * it.
> >  	 */
> > -	if (drm_format_info_is_yuv_semiplanar(fb->format)) {
> > -		ret = skl_check_nv12_aux_surface(plane_state);
> > +	if (is_ccs_modifier(fb->modifier)) {
> > +		needs_aux = true;
> > +		ret = skl_check_ccs_aux_surface(plane_state);
> >  		if (ret)
> >  			return ret;
> > -	} else if (is_ccs_modifier(fb->modifier)) {
> > -		ret = skl_check_ccs_aux_surface(plane_state);
> > +	}
> > +
> > +	if (drm_format_info_is_yuv_semiplanar(fb->format)) {
> > +		needs_aux = true;
> > +		ret = skl_check_nv12_aux_surface(plane_state);
> >  		if (ret)
> >  			return ret;
> > -	} else {
> > -		plane_state->color_plane[1].offset = ~0xfff;
> > -		plane_state->color_plane[1].x = 0;
> > -		plane_state->color_plane[1].y = 0;
> > +	}
> > +
> > +	if (!needs_aux) {
> > +		int i;
> > +
> > +		for (i = 1; i < fb->format->num_planes; i++) {
> > +			plane_state->color_plane[i].offset = ~0xfff;
> > +			plane_state->color_plane[i].x = 0;
> > +			plane_state->color_plane[i].y = 0;
> > +		}
> >  	}
> >  
> >  	ret = skl_check_main_surface(plane_state);
> > @@ -4030,7 +4178,7 @@ static unsigned int skl_plane_stride_mult(const struct drm_framebuffer
> > *fb,
> >  	 * The stride is either expressed as a multiple of 64 bytes chunks for
> >  	 * linear buffers or in number of tiles for tiled buffers.
> >  	 */
> > -	if (is_surface_linear(fb->modifier, color_plane))
> > +	if (is_surface_linear(fb, color_plane))
> >  		return 64;
> >  	else if (drm_rotation_90_or_270(rotation))
> >  		return intel_tile_height(fb, color_plane);
> > @@ -4160,6 +4308,8 @@ static u32 skl_plane_ctl_tiling(u64 fb_modifier)
> >  		return PLANE_CTL_TILED_Y |
> >  		       PLANE_CTL_RENDER_DECOMPRESSION_ENABLE |
> >  		       PLANE_CTL_CLEAR_COLOR_DISABLE;
> > +	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
> > +		return PLANE_CTL_TILED_Y | PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE;
> >  	case I915_FORMAT_MOD_Yf_TILED:
> >  		return PLANE_CTL_TILED_YF;
> >  	case I915_FORMAT_MOD_Yf_TILED_CCS:
> > @@ -9968,6 +10118,8 @@ skylake_get_initial_plane_config(struct intel_crtc *crtc,
> >  			fb->modifier = INTEL_GEN(dev_priv) >= 12 ?
> >  				I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS :
> >  				I915_FORMAT_MOD_Y_TILED_CCS;
> > +		else if (val & PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE)
> > +			fb->modifier = I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS;
> >  		else
> >  			fb->modifier = I915_FORMAT_MOD_Y_TILED;
> >  		break;
> > diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h
> > b/drivers/gpu/drm/i915/display/intel_display_types.h
> > index 976669f01a8c..5998b959225c 100644
> > --- a/drivers/gpu/drm/i915/display/intel_display_types.h
> > +++ b/drivers/gpu/drm/i915/display/intel_display_types.h
> > @@ -530,7 +530,7 @@ struct intel_plane_state {
> >  		 */
> >  		u32 stride;
> >  		int x, y;
> > -	} color_plane[2];
> > +	} color_plane[4];
> >  
> >  	/* plane control register */
> >  	u32 ctl;
> > diff --git a/drivers/gpu/drm/i915/display/intel_sprite.c
> > b/drivers/gpu/drm/i915/display/intel_sprite.c
> > index 9b9b41b0fc91..788d0fc8d8ef 100644
> > --- a/drivers/gpu/drm/i915/display/intel_sprite.c
> > +++ b/drivers/gpu/drm/i915/display/intel_sprite.c
> > @@ -532,11 +532,13 @@ skl_program_plane(struct intel_plane *plane,
> >  	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
> >  	enum plane_id plane_id = plane->id;
> >  	enum pipe pipe = plane->pipe;
> > +	const struct drm_framebuffer *fb = plane_state->base.fb;
> > +	int aux_plane = fb->format->num_planes / 2 + color_plane;
> >  	const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
> >  	u32 surf_addr = plane_state->color_plane[color_plane].offset;
> >  	u32 stride = skl_plane_stride(plane_state, color_plane);
> > -	u32 aux_dist = plane_state->color_plane[1].offset - surf_addr;
> > -	u32 aux_stride = skl_plane_stride(plane_state, 1);
> > +	u32 aux_dist = plane_state->color_plane[aux_plane].offset - surf_addr;
> > +	u32 aux_stride = skl_plane_stride(plane_state, aux_plane);
> >  	int crtc_x = plane_state->base.dst.x1;
> >  	int crtc_y = plane_state->base.dst.y1;
> >  	u32 x = plane_state->color_plane[color_plane].x;
> > @@ -544,7 +546,6 @@ skl_program_plane(struct intel_plane *plane,
> >  	u32 src_w = drm_rect_width(&plane_state->base.src) >> 16;
> >  	u32 src_h = drm_rect_height(&plane_state->base.src) >> 16;
> >  	struct intel_plane *linked = plane_state->planar_linked_plane;
> > -	const struct drm_framebuffer *fb = plane_state->base.fb;
> >  	u8 alpha = plane_state->base.alpha >> 8;
> >  	u32 plane_color_ctl = 0;
> >  	unsigned long irqflags;
> > @@ -619,8 +620,8 @@ skl_program_plane(struct intel_plane *plane,
> >  
> >  	if (INTEL_GEN(dev_priv) < 11)
> >  		I915_WRITE_FW(PLANE_AUX_OFFSET(pipe, plane_id),
> > -			      (plane_state->color_plane[1].y << 16) |
> > -			      plane_state->color_plane[1].x);
> > +			      (plane_state->color_plane[aux_plane].y << 16) |
> > +			      plane_state->color_plane[aux_plane].x);
> >  
> >  	/*
> >  	 * The control register self-arms if the plane was previously
> > @@ -1737,7 +1738,8 @@ static int skl_plane_check_fb(const struct intel_crtc_state *crtc_state,
> >  	     fb->modifier == I915_FORMAT_MOD_Yf_TILED ||
> >  	     fb->modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
> >  	     fb->modifier == I915_FORMAT_MOD_Yf_TILED_CCS ||
> > -	     fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS)) {
> > +	     fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS ||
> > +	     fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS)) {
> >  		DRM_DEBUG_KMS("Y/Yf tiling not supported in IF-ID mode\n");
> >  		return -EINVAL;
> >  	}
> > @@ -2149,7 +2151,16 @@ static const u64 skl_plane_format_modifiers_ccs[] = {
> >  	DRM_FORMAT_MOD_INVALID
> >  };
> >  
> > -static const u64 gen12_plane_format_modifiers_ccs[] = {
> > +static const u64 gen12_plane_format_modifiers_mc_ccs[] = {
> > +	I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS,
> > +	I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS,
> > +	I915_FORMAT_MOD_Y_TILED,
> > +	I915_FORMAT_MOD_X_TILED,
> > +	DRM_FORMAT_MOD_LINEAR,
> > +	DRM_FORMAT_MOD_INVALID
> > +};
> > +
> > +static const u64 gen12_plane_format_modifiers_rc_ccs[] = {
> >  	I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS,
> >  	I915_FORMAT_MOD_Y_TILED,
> >  	I915_FORMAT_MOD_X_TILED,
> > @@ -2305,10 +2316,21 @@ static bool skl_plane_format_mod_supported(struct drm_plane *_plane,
> >  	}
> >  }
> >  
> > +static bool gen12_plane_supports_mc_ccs(enum plane_id plane_id)
> > +{
> > +	return plane_id < PLANE_SPRITE4;
> > +}
> > +
> >  static bool gen12_plane_format_mod_supported(struct drm_plane *_plane,
> >  					     u32 format, u64 modifier)
> >  {
> > +	struct intel_plane *plane = to_intel_plane(_plane);
> > +
> >  	switch (modifier) {
> > +	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
> > +		if (!gen12_plane_supports_mc_ccs(plane->id))
> > +			return false;
> > +		/* fall through */
> >  	case DRM_FORMAT_MOD_LINEAR:
> >  	case I915_FORMAT_MOD_X_TILED:
> >  	case I915_FORMAT_MOD_Y_TILED:
> > @@ -2326,14 +2348,17 @@ static bool gen12_plane_format_mod_supported(struct drm_plane *_plane,
> >  		if (is_ccs_modifier(modifier))
> >  			return true;
> >  		/* fall through */
> > -	case DRM_FORMAT_RGB565:
> > -	case DRM_FORMAT_XRGB2101010:
> > -	case DRM_FORMAT_XBGR2101010:
> >  	case DRM_FORMAT_YUYV:
> >  	case DRM_FORMAT_YVYU:
> >  	case DRM_FORMAT_UYVY:
> >  	case DRM_FORMAT_VYUY:
> > +		if (modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS)
> > +			return true;
> > +		/* fall through */
> >  	case DRM_FORMAT_NV12:
> > +	case DRM_FORMAT_RGB565:
> > +	case DRM_FORMAT_XRGB2101010:
> > +	case DRM_FORMAT_XBGR2101010:
> >  	case DRM_FORMAT_P010:
> >  	case DRM_FORMAT_P012:
> >  	case DRM_FORMAT_P016:
> > @@ -2470,6 +2495,14 @@ static const u32 *icl_get_plane_formats(struct drm_i915_private
> > *dev_priv,
> >  	}
> >  }
> >  
> > +static const u64 *gen12_get_plane_modifiers(enum plane_id plane_id)
> > +{
> > +	if (gen12_plane_supports_mc_ccs(plane_id))
> > +		return gen12_plane_format_modifiers_mc_ccs;
> > +	else
> > +		return gen12_plane_format_modifiers_rc_ccs;
> > +}
> > +
> >  static bool skl_plane_has_ccs(struct drm_i915_private *dev_priv,
> >  			      enum pipe pipe, enum plane_id plane_id)
> >  {
> > @@ -2536,7 +2569,7 @@ skl_universal_plane_create(struct drm_i915_private *dev_priv,
> >  
> >  	plane->has_ccs = skl_plane_has_ccs(dev_priv, pipe, plane_id);
> >  	if (INTEL_GEN(dev_priv) >= 12) {
> > -		modifiers = gen12_plane_format_modifiers_ccs;
> > +		modifiers = gen12_get_plane_modifiers(plane_id);
> >  		plane_funcs = &gen12_plane_funcs;
> >  	} else {
> >  		if (plane->has_ccs)
> > diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> > index 519cfb0a5c42..02eaef8adac0 100644
> > --- a/drivers/gpu/drm/i915/i915_reg.h
> > +++ b/drivers/gpu/drm/i915/i915_reg.h
> > @@ -6697,6 +6697,7 @@ enum {
> >  #define   PLANE_CTL_TILED_Y			(4 << 10)
> >  #define   PLANE_CTL_TILED_YF			(5 << 10)
> >  #define   PLANE_CTL_FLIP_HORIZONTAL		(1 << 8)
> > +#define   PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE	(1 << 4) /* TGL+ */
> >  #define   PLANE_CTL_ALPHA_MASK			(0x3 << 4) /* Pre-GLK */
> >  #define   PLANE_CTL_ALPHA_DISABLE		(0 << 4)
> >  #define   PLANE_CTL_ALPHA_SW_PREMULTIPLY	(2 << 4)
> > -- 
> > 2.17.1
> > 
> > _______________________________________________
> > Intel-gfx mailing list
> > Intel-gfx@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/intel-gfx
> 
>
Dhinakaran Pandiyan Oct. 4, 2019, 11:54 p.m. UTC | #4
On Fri, 2019-10-04 at 18:36 +0300, Ville Syrjälä wrote:
> On Thu, Sep 26, 2019 at 03:55:12AM -0700, Dhinakaran Pandiyan wrote:
> > Detect the modifier corresponding to media compression to enable
> > display decompression for YUV and xRGB packed formats. A new modifier is
> > added so that the driver can distinguish between media and render
> > compressed buffers. Unlike render decompression, plane 6 and  plane 7 do not
> > support media decompression.
> > 
> > v2: Fix checkpatch warnings on code style (Lucas)
> > 
> > From DK:
> > Separate modifier array for planes that cannot decompress media (Ville)
> > 
> > v3: Support planar formats
> > v4: Switch plane order
> > 
> > Cc: Nanley G Chery <nanley.g.chery@intel.com>
> > Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > Cc: Matt Roper <matthew.d.roper@intel.com>
> > Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
> > Signed-off-by: Lucas De Marchi <lucas.demarchi@intel.com>
> > ---
> >  drivers/gpu/drm/i915/display/intel_display.c  | 290 +++++++++++++-----
> >  .../drm/i915/display/intel_display_types.h    |   2 +-
> >  drivers/gpu/drm/i915/display/intel_sprite.c   |  55 +++-
> >  drivers/gpu/drm/i915/i915_reg.h               |   1 +
> >  4 files changed, 267 insertions(+), 81 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/display/intel_display.c
> > b/drivers/gpu/drm/i915/display/intel_display.c
> > index 8ea55d67442c..df3ebaa167ab 100644
> > --- a/drivers/gpu/drm/i915/display/intel_display.c
> > +++ b/drivers/gpu/drm/i915/display/intel_display.c
> > @@ -1888,6 +1888,22 @@ static void intel_disable_pipe(const struct intel_crtc_state
> > *old_crtc_state)
> >  		intel_wait_for_pipe_off(old_crtc_state);
> >  }
> >  
> > +bool is_ccs_modifier(u64 modifier)
> > +{
> > +	return modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS ||
> > +	       modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS ||
> > +	       modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
> > +	       modifier == I915_FORMAT_MOD_Yf_TILED_CCS;
> > +}
> > +
> > +static bool is_ccs_plane(const struct drm_framebuffer *fb, int color_plane)
> > +{
> > +	if (!is_ccs_modifier(fb->modifier))
> > +		return false;
> 
> A comment here could help clarify things for the reader. Eg.:
> /*
>  * [0] RGB
>  * [1] RGB CCS
>  * or
>  * [0] Y
>  * [1] CbCr
>  * [2] Y CCS
>  * [3] CbCr CCS
>  */
> 
Will do.

> > +
> > +	return color_plane >= fb->format->num_planes / 2;
> > +}
> > +
> >  static unsigned int intel_tile_size(const struct drm_i915_private *dev_priv)
> >  {
> >  	return IS_GEN(dev_priv, 2) ? 2048 : 4096;
> > @@ -1908,11 +1924,13 @@ intel_tile_width_bytes(const struct drm_framebuffer *fb, int
> > color_plane)
> >  		else
> >  			return 512;
> >  	case I915_FORMAT_MOD_Y_TILED_CCS:
> > -		if (color_plane == 1)
> > +		if (is_ccs_plane(fb, color_plane))
> >  			return 128;
> >  		/* fall through */
> > +	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
> > +		/* fall through */
> >  	case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
> > -		if (color_plane == 1)
> > +		if (is_ccs_plane(fb, color_plane))
> >  			return 64;
> >  		/* fall through */
> >  	case I915_FORMAT_MOD_Y_TILED:
> > @@ -1921,7 +1939,7 @@ intel_tile_width_bytes(const struct drm_framebuffer *fb, int color_plane)
> >  		else
> >  			return 512;
> >  	case I915_FORMAT_MOD_Yf_TILED_CCS:
> > -		if (color_plane == 1)
> > +		if (is_ccs_plane(fb, color_plane))
> >  			return 128;
> >  		/* fall through */
> >  	case I915_FORMAT_MOD_Yf_TILED:
> > @@ -1949,8 +1967,9 @@ static unsigned int
> >  intel_tile_height(const struct drm_framebuffer *fb, int color_plane)
> >  {
> >  	switch (fb->modifier) {
> > +	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
> >  	case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
> > -		if (color_plane == 1)
> > +		if (is_ccs_plane(fb, color_plane))
> >  			return 1;
> >  		/* fall through */
> >  	default:
> > @@ -2055,6 +2074,7 @@ static unsigned int intel_surf_alignment(const struct drm_framebuffer *fb,
> >  		if (INTEL_GEN(dev_priv) >= 9)
> >  			return 256 * 1024;
> >  		return 0;
> > +	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
> >  	case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
> >  		return 16 * 1024;
> >  	case I915_FORMAT_MOD_Y_TILED_CCS:
> > @@ -2254,10 +2274,17 @@ static u32 intel_adjust_tile_offset(int *x, int *y,
> >  	return new_offset;
> >  }
> >  
> > -static bool is_surface_linear(u64 modifier, int color_plane)
> > +static bool is_surface_linear(const struct drm_framebuffer *fb, int color_plane)
> >  {
> > -	return modifier == DRM_FORMAT_MOD_LINEAR ||
> > -	       (modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS && color_plane == 1);
> > +	switch (fb->modifier) {
> > +	case DRM_FORMAT_MOD_LINEAR:
> > +		return true;
> > +	case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
> > +	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
> > +		return is_ccs_plane(fb, color_plane);
> > +	default:
> > +		return false;
> > +	}
> >  }
> >  
> >  static u32 intel_adjust_aligned_offset(int *x, int *y,
> > @@ -2272,7 +2299,7 @@ static u32 intel_adjust_aligned_offset(int *x, int *y,
> >  
> >  	WARN_ON(new_offset > old_offset);
> >  
> > -	if (!is_surface_linear(fb->modifier, color_plane)) {
> > +	if (!is_surface_linear(fb, color_plane)) {
> >  		unsigned int tile_size, tile_width, tile_height;
> >  		unsigned int pitch_tiles;
> >  
> > @@ -2342,7 +2369,7 @@ static u32 intel_compute_aligned_offset(struct drm_i915_private *dev_priv,
> >  	if (alignment)
> >  		alignment--;
> >  
> > -	if (!is_surface_linear(fb->modifier, color_plane)) {
> > +	if (!is_surface_linear(fb, color_plane)) {
> >  		unsigned int tile_size, tile_width, tile_height;
> >  		unsigned int tile_rows, tiles, pitch_tiles;
> >  
> > @@ -2445,6 +2472,7 @@ static unsigned int intel_fb_modifier_to_tiling(u64 fb_modifier)
> >  	case I915_FORMAT_MOD_Y_TILED:
> >  	case I915_FORMAT_MOD_Y_TILED_CCS:
> >  	case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
> > +	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
> >  		return I915_TILING_Y;
> >  	default:
> >  		return I915_TILING_NONE;
> > @@ -2494,6 +2522,13 @@ static const struct drm_format_info gen12_ccs_formats[] = {
> >  	  .cpp = { 4, 1, }, .hsub = 2, .vsub = 32, .has_alpha = true },
> >  };
> >  
> > +static const struct drm_format_info gen12_mc_ccs_formats[] = {
> > +	{ .format = DRM_FORMAT_YUYV, .num_planes = 2,
> > +	  .cpp = { 2, 1, }, .hsub = 4, .vsub = 32, .is_yuv = true },
> > +	{ .format = DRM_FORMAT_NV12, .num_planes = 4,
> > +	  .cpp = { 1, 2, 1, 1}, .hsub = 2, .vsub = 2, .is_yuv = true },
> > +};
> > +
> >  static const struct drm_format_info *
> >  lookup_format_info(const struct drm_format_info formats[],
> >  		   int num_formats, u32 format)
> > @@ -2511,12 +2546,21 @@ lookup_format_info(const struct drm_format_info formats[],
> >  static const struct drm_format_info *
> >  intel_get_format_info(const struct drm_mode_fb_cmd2 *cmd)
> >  {
> > +	const struct drm_format_info *info;
> > +
> >  	switch (cmd->modifier[0]) {
> >  	case I915_FORMAT_MOD_Y_TILED_CCS:
> >  	case I915_FORMAT_MOD_Yf_TILED_CCS:
> >  		return lookup_format_info(skl_ccs_formats,
> >  					  ARRAY_SIZE(skl_ccs_formats),
> >  					  cmd->pixel_format);
> > +	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
> > +		info = lookup_format_info(gen12_mc_ccs_formats,
> > +					  ARRAY_SIZE(gen12_mc_ccs_formats),
> > +					  cmd->pixel_format);
> > +		if (info)
> > +			return info;
> > +		/* fall through */
> >  	case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
> >  		return lookup_format_info(gen12_ccs_formats,
> >  					  ARRAY_SIZE(gen12_ccs_formats),
> > @@ -2526,13 +2570,6 @@ intel_get_format_info(const struct drm_mode_fb_cmd2 *cmd)
> >  	}
> >  }
> >  
> > -bool is_ccs_modifier(u64 modifier)
> > -{
> > -	return modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS ||
> > -	       modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
> > -	       modifier == I915_FORMAT_MOD_Yf_TILED_CCS;
> > -}
> > -
> >  u32 intel_plane_fb_max_stride(struct drm_i915_private *dev_priv,
> >  			      u32 pixel_format, u64 modifier)
> >  {
> > @@ -2576,7 +2613,7 @@ intel_fb_stride_alignment(const struct drm_framebuffer *fb, int
> > color_plane)
> >  	struct drm_i915_private *dev_priv = to_i915(fb->dev);
> >  	u32 tile_width;
> >  
> > -	if (is_surface_linear(fb->modifier, color_plane)) {
> > +	if (is_surface_linear(fb, color_plane)) {
> >  		u32 max_stride = intel_plane_fb_max_stride(dev_priv,
> >  							   fb->format->format,
> >  							   fb->modifier);
> > @@ -2592,7 +2629,7 @@ intel_fb_stride_alignment(const struct drm_framebuffer *fb, int
> > color_plane)
> >  	}
> >  
> >  	tile_width = intel_tile_width_bytes(fb, color_plane);
> > -	if (is_ccs_modifier(fb->modifier) && color_plane == 0) {
> > +	if (is_ccs_modifier(fb->modifier)) {
> >  		/*
> >  		 * Display WA #0531: skl,bxt,kbl,glk
> >  		 *
> > @@ -2602,7 +2639,7 @@ intel_fb_stride_alignment(const struct drm_framebuffer *fb, int
> > color_plane)
> >  		 * require the entire fb to accommodate that to avoid
> >  		 * potential runtime errors at plane configuration time.
> >  		 */
> > -		if (IS_GEN(dev_priv, 9) && fb->width > 3840)
> > +		if (IS_GEN(dev_priv, 9) && color_plane == 0 && fb->width > 3840)
> >  			tile_width *= 4;
> >  		/*
> >  		 * The main surface pitch must be padded to a multiple of four
> > @@ -2682,25 +2719,75 @@ static bool intel_plane_needs_remap(const struct intel_plane_state
> > *plane_state)
> >  	return stride > max_stride;
> >  }
> >  
> > +static void
> > +intel_fb_plane_get_subsampling(int *hsub, int *vsub, const struct drm_framebuffer *fb, int
> > color_plane)
> > +{
> > +	int i;
> > +	static const struct {
> > +		u32 format;
> > +		int vsub[4];
> > +		int hsub[4];
> > +	} mc_ccs_subsampling[] = { { .hsub = { 1, 2, 8, 16 },
> > +				     .vsub = { 1, 2, 32, 32 },
> > +				     .format = DRM_FORMAT_NV12, },
> > +				 };
> > +
> > +	*hsub = fb->format->hsub;
> > +	*vsub = fb->format->vsub;
> > +
> > +	if (fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS &&
> > +	    fb->format->num_planes == 4) {
> > +		for (i = 0; i < ARRAY_SIZE(mc_ccs_subsampling); i++) {
> > +			if  (mc_ccs_subsampling[i].format == fb->format->format) {
> > +				*hsub = mc_ccs_subsampling[i].hsub[color_plane];
> > +				*vsub = mc_ccs_subsampling[i].vsub[color_plane];
> > +				break;
> > +			}
> > +		}
> > +		WARN_ON(i == ARRAY_SIZE(mc_ccs_subsampling));
> > +	}
> 
> Hmm. I wonder if we could switch over to that block size stuff
> in the format info? As is I don't think framebuffer_check() will
> do the right thing for this stuff.

Thought about it quite a bit (even coded some parts). I wasn't 100% sure if it matches what we need
and had too many questions about it's intended usage. Are block dimensions for each plane
independent of each other? Should relative plane dimensions be taken into account or we just define
the dimensions based on each plane's unit block? Do the block dimensions complement vsub and hsub or
is that an alternative?

In any case, felt it would be better to convert all formats/modifiers to switch to using blocks
together. Thoughts?

-DK
> 
> > +}
> > +
> > +static void
> > +intel_fb_plane_dims(int *w, int *h, struct drm_framebuffer *fb, int color_plane)
> > +{
> > +	int hsub, vsub;
> > +
> > +	intel_fb_plane_get_subsampling(&hsub, &vsub, fb, color_plane);
> > +	*w = fb->width/hsub;
> > +	*h = fb->height/vsub;
> > +}
> > +
> >  static int
> > -intel_fb_check_ccs_xy(struct drm_framebuffer *fb, int x, int y)
> > +intel_fb_check_ccs_xy(struct drm_framebuffer *fb, int aux_plane, int x, int y)
> >  {
> >  	struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
> > -	int hsub = fb->format->hsub;
> > -	int vsub = fb->format->vsub;
> > +	int hsub, vsub;
> > +	int hsub_main, vsub_main;
> >  	int tile_width, tile_height;
> >  	int ccs_x, ccs_y;
> >  	int main_x, main_y;
> > +	int main_plane;
> > +
> > +	if (!is_ccs_plane(fb, aux_plane))
> > +		return 0;
> > +
> > +	main_plane = (aux_plane - 1) / 2;
> 
> 'aux_plane - num_planes/2' might be a clearer way to write that.
> The num_planes/2 already made an appearance in the is_ccs_plane() thing.
> 
> Could also extract this to a small helper to help readability.
Okay.

> 
> > +	intel_tile_dims(fb, aux_plane, &tile_width, &tile_height);
> > +	intel_fb_plane_get_subsampling(&hsub, &vsub, fb, aux_plane);
> > +	intel_fb_plane_get_subsampling(&hsub_main, &vsub_main, fb,
> > +				       main_plane);
> >  
> > -	intel_tile_dims(fb, 1, &tile_width, &tile_height);
> > +	hsub /= hsub_main;
> > +	vsub /= vsub_main;
> >  
> >  	tile_width *= hsub;
> >  	tile_height *= vsub;
> >  
> >  	ccs_x = (x * hsub) % tile_width;
> >  	ccs_y = (y * vsub) % tile_height;
> > -	main_x = intel_fb->normal[0].x % tile_width;
> > -	main_y = intel_fb->normal[0].y % tile_height;
> > +	main_x = intel_fb->normal[main_plane].x % tile_width;
> > +	main_y = intel_fb->normal[main_plane].y % tile_height;
> >  
> >  	/*
> >  	* CCS doesn't have its own x/y offset register, so the intra CCS tile
> > @@ -2710,8 +2797,8 @@ intel_fb_check_ccs_xy(struct drm_framebuffer *fb, int x, int y)
> >  		DRM_DEBUG_KMS("Bad CCS x/y (main %d,%d ccs %d,%d) full (main %d,%d ccs %d,%d)\n",
> >  			      main_x, main_y,
> >  			      ccs_x, ccs_y,
> > -			      intel_fb->normal[0].x,
> > -			      intel_fb->normal[0].y,
> > +			      intel_fb->normal[main_plane].x,
> > +			      intel_fb->normal[main_plane].y,
> >  			      x, y);
> >  		return -EINVAL;
> >  	}
> > @@ -2739,8 +2826,7 @@ intel_fill_fb_info(struct drm_i915_private *dev_priv,
> >  		int ret;
> >  
> >  		cpp = fb->format->cpp[i];
> > -		width = drm_framebuffer_plane_width(fb->width, fb, i);
> > -		height = drm_framebuffer_plane_height(fb->height, fb, i);
> > +		intel_fb_plane_dims(&width, &height, fb, i);
> >  
> >  		ret = intel_fb_offset_to_xy(&x, &y, fb, i);
> >  		if (ret) {
> > @@ -2749,11 +2835,9 @@ intel_fill_fb_info(struct drm_i915_private *dev_priv,
> >  			return ret;
> >  		}
> >  
> > -		if (is_ccs_modifier(fb->modifier) && i == 1) {
> > -			ret = intel_fb_check_ccs_xy(fb, x, y);
> > -			if (ret)
> > -				return ret;
> > -		}
> > +		ret = intel_fb_check_ccs_xy(fb, i, x, y);
> > +		if (ret)
> > +			return ret;
> >  
> >  		/*
> >  		 * The fence (if used) is aligned to the start of the object
> > @@ -3371,6 +3455,7 @@ static int skl_max_plane_width(const struct drm_framebuffer *fb,
> >  			return 5120;
> >  	case I915_FORMAT_MOD_Y_TILED_CCS:
> >  	case I915_FORMAT_MOD_Yf_TILED_CCS:
> > +	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
> >  		/* FIXME AUX plane? */
> >  	case I915_FORMAT_MOD_Y_TILED:
> >  	case I915_FORMAT_MOD_Yf_TILED:
> > @@ -3430,16 +3515,18 @@ static int icl_max_plane_height(void)
> >  }
> >  
> >  static bool skl_check_main_ccs_coordinates(struct intel_plane_state *plane_state,
> > -					   int main_x, int main_y, u32 main_offset)
> > +					   int main_x, int main_y,
> > +					   u32 main_offset, int aux_plane)
> >  {
> >  	const struct drm_framebuffer *fb = plane_state->base.fb;
> > -	int hsub = fb->format->hsub;
> > -	int vsub = fb->format->vsub;
> > -	int aux_x = plane_state->color_plane[1].x;
> > -	int aux_y = plane_state->color_plane[1].y;
> > -	u32 aux_offset = plane_state->color_plane[1].offset;
> > -	u32 alignment = intel_surf_alignment(fb, 1);
> > -
> > +	int hsub;
> > +	int vsub;
> > +	int aux_x = plane_state->color_plane[aux_plane].x;
> > +	int aux_y = plane_state->color_plane[aux_plane].y;
> > +	u32 aux_offset = plane_state->color_plane[aux_plane].offset;
> > +	u32 alignment = intel_surf_alignment(fb, aux_plane);
> > +
> > +	intel_fb_plane_get_subsampling(&hsub, &vsub, fb, aux_plane);
> >  	while (aux_offset >= main_offset && aux_y <= main_y) {
> >  		int x, y;
> >  
> > @@ -3451,7 +3538,7 @@ static bool skl_check_main_ccs_coordinates(struct intel_plane_state
> > *plane_state
> >  
> >  		x = aux_x / hsub;
> >  		y = aux_y / vsub;
> > -		aux_offset = intel_plane_adjust_aligned_offset(&x, &y, plane_state, 1,
> > +		aux_offset = intel_plane_adjust_aligned_offset(&x, &y, plane_state, aux_plane,
> >  							       aux_offset, aux_offset - alignment);
> >  		aux_x = x * hsub + aux_x % hsub;
> >  		aux_y = y * vsub + aux_y % vsub;
> > @@ -3460,9 +3547,9 @@ static bool skl_check_main_ccs_coordinates(struct intel_plane_state
> > *plane_state
> >  	if (aux_x != main_x || aux_y != main_y)
> >  		return false;
> >  
> > -	plane_state->color_plane[1].offset = aux_offset;
> > -	plane_state->color_plane[1].x = aux_x;
> > -	plane_state->color_plane[1].y = aux_y;
> > +	plane_state->color_plane[aux_plane].offset = aux_offset;
> > +	plane_state->color_plane[aux_plane].x = aux_x;
> > +	plane_state->color_plane[aux_plane].y = aux_y;
> >  
> >  	return true;
> >  }
> > @@ -3478,7 +3565,8 @@ static int skl_check_main_surface(struct intel_plane_state *plane_state)
> >  	int h = drm_rect_height(&plane_state->base.src) >> 16;
> >  	int max_width;
> >  	int max_height;
> > -	u32 alignment, offset, aux_offset = plane_state->color_plane[1].offset;
> > +	int aux_plane = fb->format->num_planes / 2;
> > +	u32 alignment, offset, aux_offset = plane_state->color_plane[aux_plane].offset;
> >  
> >  	if (INTEL_GEN(dev_priv) >= 11)
> >  		max_width = icl_max_plane_width(fb, 0, rotation);
> > @@ -3536,7 +3624,9 @@ static int skl_check_main_surface(struct intel_plane_state *plane_state)
> >  	 * they match with the main surface x/y offsets.
> >  	 */
> >  	if (is_ccs_modifier(fb->modifier)) {
> > -		while (!skl_check_main_ccs_coordinates(plane_state, x, y, offset)) {
> > +
> > +		while (!skl_check_main_ccs_coordinates(plane_state, x, y,
> > +						       offset, aux_plane)) {
> >  			if (offset == 0)
> >  				break;
> >  
> > @@ -3544,7 +3634,8 @@ static int skl_check_main_surface(struct intel_plane_state *plane_state)
> >  								   offset, offset - alignment);
> >  		}
> >  
> > -		if (x != plane_state->color_plane[1].x || y != plane_state->color_plane[1].y) {
> > +		if (x != plane_state->color_plane[aux_plane].x ||
> > +		    y != plane_state->color_plane[aux_plane].y) {
> >  			DRM_DEBUG_KMS("Unable to find suitable display surface offset due to
> > CCS\n");
> >  			return -EINVAL;
> >  		}
> > @@ -3587,6 +3678,41 @@ static int skl_check_nv12_aux_surface(struct intel_plane_state
> > *plane_state)
> >  		return -EINVAL;
> >  	}
> >  
> > +	if (is_ccs_modifier(fb->modifier)) {
> > +		int aux_offset = plane_state->color_plane[3].offset;
> > +		int alignment = intel_surf_alignment(fb, 1);
> > +
> > +		if (offset > aux_offset) {
> > +			int hsub, vsub;
> > +			int main_x = x, main_y = y;
> > +
> > +
> > +			intel_fb_plane_get_subsampling(&hsub, &vsub, fb, 1);
> > +			x = main_x / hsub;
> > +			y = main_y / vsub;
> > +			offset = intel_plane_adjust_aligned_offset(&x, &y, plane_state, 1,
> > +								   offset,
> > +								   aux_offset & ~(alignment - 1));
> > +			x = x * hsub + main_x % hsub;
> > +			y = y * vsub + main_y % vsub;
> > +
> > +		}
> > +
> > +		while (!skl_check_main_ccs_coordinates(plane_state, x, y, offset, 3)) {
> > +			if (offset == 0)
> > +				break;
> > +
> > +			offset = intel_plane_adjust_aligned_offset(&x, &y, plane_state, 1,
> > +								   offset, offset - alignment);
> > +		}
> > +
> > +		if (x != plane_state->color_plane[3].x ||
> > +		    y != plane_state->color_plane[3].y) {
> > +			DRM_DEBUG_KMS("Unable to find suitable display surface offset due to
> > CCS\n");
> > +			return -EINVAL;
> > +		}
> 
> Probably time to refactor some of the stuff so we don't have to copy
> paste so much.
> 
> > +	}
> > +
> >  	plane_state->color_plane[1].offset = offset;
> >  	plane_state->color_plane[1].x = x;
> >  	plane_state->color_plane[1].y = y;
> > @@ -3599,19 +3725,30 @@ static int skl_check_ccs_aux_surface(struct intel_plane_state
> > *plane_state)
> >  	const struct drm_framebuffer *fb = plane_state->base.fb;
> >  	int src_x = plane_state->base.src.x1 >> 16;
> >  	int src_y = plane_state->base.src.y1 >> 16;
> > -	int hsub = fb->format->hsub;
> > -	int vsub = fb->format->vsub;
> > -	int x = src_x / hsub;
> > -	int y = src_y / vsub;
> >  	u32 offset;
> > +	int ccs;
> >  
> > -	intel_add_fb_offsets(&x, &y, plane_state, 1);
> > -	offset = intel_plane_compute_aligned_offset(&x, &y, plane_state, 1);
> >  
> > -	plane_state->color_plane[1].offset = offset;
> > -	plane_state->color_plane[1].x = x * hsub + src_x % hsub;
> > -	plane_state->color_plane[1].y = y * vsub + src_y % vsub;
> > +	for (ccs = fb->format->num_planes / 2;
> 
> I guess another helper to do the main->aux index calculation would make
> this less magicy.
> 
> ccs < fb->format->num_planes; ccs++) {
> > +		int hsub, vsub;
> > +		int main_hsub, main_vsub;
> > +		int x, y;
> > +
> > +		intel_fb_plane_get_subsampling(&hsub, &vsub, fb, ccs);
> > +		intel_fb_plane_get_subsampling(&main_hsub, &main_vsub, fb, (ccs - 1)/ 2);
> > +
> > +		hsub /= main_hsub;
> > +		vsub /= main_vsub;
> > +		x = src_x / hsub;
> > +		y = src_y / vsub;
> >  
> > +		intel_add_fb_offsets(&x, &y, plane_state, ccs);
> > +		offset = intel_plane_compute_aligned_offset(&x, &y,
> > +							    plane_state, ccs);
> > +		plane_state->color_plane[ccs].offset = offset;
> > +		plane_state->color_plane[ccs].x = x * hsub + src_x % hsub;
> > +		plane_state->color_plane[ccs].y = y * vsub + src_y % vsub;
> > +	}
> >  	return 0;
> >  }
> >  
> > @@ -3619,6 +3756,7 @@ int skl_check_plane_surface(struct intel_plane_state *plane_state)
> >  {
> >  	const struct drm_framebuffer *fb = plane_state->base.fb;
> >  	int ret;
> > +	bool needs_aux = false;
> >  
> >  	ret = intel_plane_compute_gtt(plane_state);
> >  	if (ret)
> > @@ -3628,21 +3766,31 @@ int skl_check_plane_surface(struct intel_plane_state *plane_state)
> >  		return 0;
> >  
> >  	/*
> > -	 * Handle the AUX surface first since
> > -	 * the main surface setup depends on it.
> > +	 * Handle the AUX surface first since the main surface setup depends on
> > +	 * it.
> >  	 */
> > -	if (drm_format_info_is_yuv_semiplanar(fb->format)) {
> > -		ret = skl_check_nv12_aux_surface(plane_state);
> > +	if (is_ccs_modifier(fb->modifier)) {
> > +		needs_aux = true;
> > +		ret = skl_check_ccs_aux_surface(plane_state);
> >  		if (ret)
> >  			return ret;
> > -	} else if (is_ccs_modifier(fb->modifier)) {
> > -		ret = skl_check_ccs_aux_surface(plane_state);
> > +	}
> > +
> > +	if (drm_format_info_is_yuv_semiplanar(fb->format)) {
> > +		needs_aux = true;
> > +		ret = skl_check_nv12_aux_surface(plane_state);
> >  		if (ret)
> >  			return ret;
> > -	} else {
> > -		plane_state->color_plane[1].offset = ~0xfff;
> > -		plane_state->color_plane[1].x = 0;
> > -		plane_state->color_plane[1].y = 0;
> > +	}
> > +
> > +	if (!needs_aux) {
> > +		int i;
> > +
> > +		for (i = 1; i < fb->format->num_planes; i++) {
> > +			plane_state->color_plane[i].offset = ~0xfff;
> > +			plane_state->color_plane[i].x = 0;
> > +			plane_state->color_plane[i].y = 0;
> > +		}
> >  	}
> >  
> >  	ret = skl_check_main_surface(plane_state);
> > @@ -4030,7 +4178,7 @@ static unsigned int skl_plane_stride_mult(const struct drm_framebuffer
> > *fb,
> >  	 * The stride is either expressed as a multiple of 64 bytes chunks for
> >  	 * linear buffers or in number of tiles for tiled buffers.
> >  	 */
> > -	if (is_surface_linear(fb->modifier, color_plane))
> > +	if (is_surface_linear(fb, color_plane))
> >  		return 64;
> >  	else if (drm_rotation_90_or_270(rotation))
> >  		return intel_tile_height(fb, color_plane);
> > @@ -4160,6 +4308,8 @@ static u32 skl_plane_ctl_tiling(u64 fb_modifier)
> >  		return PLANE_CTL_TILED_Y |
> >  		       PLANE_CTL_RENDER_DECOMPRESSION_ENABLE |
> >  		       PLANE_CTL_CLEAR_COLOR_DISABLE;
> > +	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
> > +		return PLANE_CTL_TILED_Y | PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE;
> >  	case I915_FORMAT_MOD_Yf_TILED:
> >  		return PLANE_CTL_TILED_YF;
> >  	case I915_FORMAT_MOD_Yf_TILED_CCS:
> > @@ -9968,6 +10118,8 @@ skylake_get_initial_plane_config(struct intel_crtc *crtc,
> >  			fb->modifier = INTEL_GEN(dev_priv) >= 12 ?
> >  				I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS :
> >  				I915_FORMAT_MOD_Y_TILED_CCS;
> > +		else if (val & PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE)
> > +			fb->modifier = I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS;
> >  		else
> >  			fb->modifier = I915_FORMAT_MOD_Y_TILED;
> >  		break;
> > diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h
> > b/drivers/gpu/drm/i915/display/intel_display_types.h
> > index 976669f01a8c..5998b959225c 100644
> > --- a/drivers/gpu/drm/i915/display/intel_display_types.h
> > +++ b/drivers/gpu/drm/i915/display/intel_display_types.h
> > @@ -530,7 +530,7 @@ struct intel_plane_state {
> >  		 */
> >  		u32 stride;
> >  		int x, y;
> > -	} color_plane[2];
> > +	} color_plane[4];
> >  
> >  	/* plane control register */
> >  	u32 ctl;
> > diff --git a/drivers/gpu/drm/i915/display/intel_sprite.c
> > b/drivers/gpu/drm/i915/display/intel_sprite.c
> > index 9b9b41b0fc91..788d0fc8d8ef 100644
> > --- a/drivers/gpu/drm/i915/display/intel_sprite.c
> > +++ b/drivers/gpu/drm/i915/display/intel_sprite.c
> > @@ -532,11 +532,13 @@ skl_program_plane(struct intel_plane *plane,
> >  	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
> >  	enum plane_id plane_id = plane->id;
> >  	enum pipe pipe = plane->pipe;
> > +	const struct drm_framebuffer *fb = plane_state->base.fb;
> > +	int aux_plane = fb->format->num_planes / 2 + color_plane;
> >  	const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
> >  	u32 surf_addr = plane_state->color_plane[color_plane].offset;
> >  	u32 stride = skl_plane_stride(plane_state, color_plane);
> > -	u32 aux_dist = plane_state->color_plane[1].offset - surf_addr;
> > -	u32 aux_stride = skl_plane_stride(plane_state, 1);
> > +	u32 aux_dist = plane_state->color_plane[aux_plane].offset - surf_addr;
> > +	u32 aux_stride = skl_plane_stride(plane_state, aux_plane);
> >  	int crtc_x = plane_state->base.dst.x1;
> >  	int crtc_y = plane_state->base.dst.y1;
> >  	u32 x = plane_state->color_plane[color_plane].x;
> > @@ -544,7 +546,6 @@ skl_program_plane(struct intel_plane *plane,
> >  	u32 src_w = drm_rect_width(&plane_state->base.src) >> 16;
> >  	u32 src_h = drm_rect_height(&plane_state->base.src) >> 16;
> >  	struct intel_plane *linked = plane_state->planar_linked_plane;
> > -	const struct drm_framebuffer *fb = plane_state->base.fb;
> >  	u8 alpha = plane_state->base.alpha >> 8;
> >  	u32 plane_color_ctl = 0;
> >  	unsigned long irqflags;
> > @@ -619,8 +620,8 @@ skl_program_plane(struct intel_plane *plane,
> >  
> >  	if (INTEL_GEN(dev_priv) < 11)
> >  		I915_WRITE_FW(PLANE_AUX_OFFSET(pipe, plane_id),
> > -			      (plane_state->color_plane[1].y << 16) |
> > -			      plane_state->color_plane[1].x);
> > +			      (plane_state->color_plane[aux_plane].y << 16) |
> > +			      plane_state->color_plane[aux_plane].x);
> >  
> >  	/*
> >  	 * The control register self-arms if the plane was previously
> > @@ -1737,7 +1738,8 @@ static int skl_plane_check_fb(const struct intel_crtc_state *crtc_state,
> >  	     fb->modifier == I915_FORMAT_MOD_Yf_TILED ||
> >  	     fb->modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
> >  	     fb->modifier == I915_FORMAT_MOD_Yf_TILED_CCS ||
> > -	     fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS)) {
> > +	     fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS ||
> > +	     fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS)) {
> >  		DRM_DEBUG_KMS("Y/Yf tiling not supported in IF-ID mode\n");
> >  		return -EINVAL;
> >  	}
> > @@ -2149,7 +2151,16 @@ static const u64 skl_plane_format_modifiers_ccs[] = {
> >  	DRM_FORMAT_MOD_INVALID
> >  };
> >  
> > -static const u64 gen12_plane_format_modifiers_ccs[] = {
> > +static const u64 gen12_plane_format_modifiers_mc_ccs[] = {
> > +	I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS,
> > +	I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS,
> > +	I915_FORMAT_MOD_Y_TILED,
> > +	I915_FORMAT_MOD_X_TILED,
> > +	DRM_FORMAT_MOD_LINEAR,
> > +	DRM_FORMAT_MOD_INVALID
> > +};
> > +
> > +static const u64 gen12_plane_format_modifiers_rc_ccs[] = {
> >  	I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS,
> >  	I915_FORMAT_MOD_Y_TILED,
> >  	I915_FORMAT_MOD_X_TILED,
> > @@ -2305,10 +2316,21 @@ static bool skl_plane_format_mod_supported(struct drm_plane *_plane,
> >  	}
> >  }
> >  
> > +static bool gen12_plane_supports_mc_ccs(enum plane_id plane_id)
> 
> plane_has_foo() is the common idiom.
> 
> > +{
> > +	return plane_id < PLANE_SPRITE4;
> > +}
> > +
> >  static bool gen12_plane_format_mod_supported(struct drm_plane *_plane,
> >  					     u32 format, u64 modifier)
> >  {
> > +	struct intel_plane *plane = to_intel_plane(_plane);
> > +
> >  	switch (modifier) {
> > +	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
> > +		if (!gen12_plane_supports_mc_ccs(plane->id))
> > +			return false;
> > +		/* fall through */
> >  	case DRM_FORMAT_MOD_LINEAR:
> >  	case I915_FORMAT_MOD_X_TILED:
> >  	case I915_FORMAT_MOD_Y_TILED:
> > @@ -2326,14 +2348,17 @@ static bool gen12_plane_format_mod_supported(struct drm_plane *_plane,
> >  		if (is_ccs_modifier(modifier))
> >  			return true;
> >  		/* fall through */
> > -	case DRM_FORMAT_RGB565:
> > -	case DRM_FORMAT_XRGB2101010:
> > -	case DRM_FORMAT_XBGR2101010:
> >  	case DRM_FORMAT_YUYV:
> >  	case DRM_FORMAT_YVYU:
> >  	case DRM_FORMAT_UYVY:
> >  	case DRM_FORMAT_VYUY:
> > +		if (modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS)
> > +			return true;
> > +		/* fall through */
> >  	case DRM_FORMAT_NV12:
> > +	case DRM_FORMAT_RGB565:
> > +	case DRM_FORMAT_XRGB2101010:
> > +	case DRM_FORMAT_XBGR2101010:
> >  	case DRM_FORMAT_P010:
> >  	case DRM_FORMAT_P012:
> >  	case DRM_FORMAT_P016:
> > @@ -2470,6 +2495,14 @@ static const u32 *icl_get_plane_formats(struct drm_i915_private
> > *dev_priv,
> >  	}
> >  }
> >  
> > +static const u64 *gen12_get_plane_modifiers(enum plane_id plane_id)
> > +{
> > +	if (gen12_plane_supports_mc_ccs(plane_id))
> > +		return gen12_plane_format_modifiers_mc_ccs;
> > +	else
> > +		return gen12_plane_format_modifiers_rc_ccs;
> > +}
> > +
> >  static bool skl_plane_has_ccs(struct drm_i915_private *dev_priv,
> >  			      enum pipe pipe, enum plane_id plane_id)
> >  {
> > @@ -2536,7 +2569,7 @@ skl_universal_plane_create(struct drm_i915_private *dev_priv,
> >  
> >  	plane->has_ccs = skl_plane_has_ccs(dev_priv, pipe, plane_id);
> >  	if (INTEL_GEN(dev_priv) >= 12) {
> > -		modifiers = gen12_plane_format_modifiers_ccs;
> > +		modifiers = gen12_get_plane_modifiers(plane_id);
> >  		plane_funcs = &gen12_plane_funcs;
> >  	} else {
> >  		if (plane->has_ccs)
> > diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> > index 519cfb0a5c42..02eaef8adac0 100644
> > --- a/drivers/gpu/drm/i915/i915_reg.h
> > +++ b/drivers/gpu/drm/i915/i915_reg.h
> > @@ -6697,6 +6697,7 @@ enum {
> >  #define   PLANE_CTL_TILED_Y			(4 << 10)
> >  #define   PLANE_CTL_TILED_YF			(5 << 10)
> >  #define   PLANE_CTL_FLIP_HORIZONTAL		(1 << 8)
> > +#define   PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE	(1 << 4) /* TGL+ */
> >  #define   PLANE_CTL_ALPHA_MASK			(0x3 << 4) /* Pre-GLK */
> >  #define   PLANE_CTL_ALPHA_DISABLE		(0 << 4)
> >  #define   PLANE_CTL_ALPHA_SW_PREMULTIPLY	(2 << 4)
> > -- 
> > 2.17.1
> > 
> > _______________________________________________
> > Intel-gfx mailing list
> > Intel-gfx@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/intel-gfx
> 
>
diff mbox series

Patch

diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
index 8ea55d67442c..df3ebaa167ab 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -1888,6 +1888,22 @@  static void intel_disable_pipe(const struct intel_crtc_state *old_crtc_state)
 		intel_wait_for_pipe_off(old_crtc_state);
 }
 
+bool is_ccs_modifier(u64 modifier)
+{
+	return modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS ||
+	       modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS ||
+	       modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
+	       modifier == I915_FORMAT_MOD_Yf_TILED_CCS;
+}
+
+static bool is_ccs_plane(const struct drm_framebuffer *fb, int color_plane)
+{
+	if (!is_ccs_modifier(fb->modifier))
+		return false;
+
+	return color_plane >= fb->format->num_planes / 2;
+}
+
 static unsigned int intel_tile_size(const struct drm_i915_private *dev_priv)
 {
 	return IS_GEN(dev_priv, 2) ? 2048 : 4096;
@@ -1908,11 +1924,13 @@  intel_tile_width_bytes(const struct drm_framebuffer *fb, int color_plane)
 		else
 			return 512;
 	case I915_FORMAT_MOD_Y_TILED_CCS:
-		if (color_plane == 1)
+		if (is_ccs_plane(fb, color_plane))
 			return 128;
 		/* fall through */
+	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
+		/* fall through */
 	case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
-		if (color_plane == 1)
+		if (is_ccs_plane(fb, color_plane))
 			return 64;
 		/* fall through */
 	case I915_FORMAT_MOD_Y_TILED:
@@ -1921,7 +1939,7 @@  intel_tile_width_bytes(const struct drm_framebuffer *fb, int color_plane)
 		else
 			return 512;
 	case I915_FORMAT_MOD_Yf_TILED_CCS:
-		if (color_plane == 1)
+		if (is_ccs_plane(fb, color_plane))
 			return 128;
 		/* fall through */
 	case I915_FORMAT_MOD_Yf_TILED:
@@ -1949,8 +1967,9 @@  static unsigned int
 intel_tile_height(const struct drm_framebuffer *fb, int color_plane)
 {
 	switch (fb->modifier) {
+	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
 	case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
-		if (color_plane == 1)
+		if (is_ccs_plane(fb, color_plane))
 			return 1;
 		/* fall through */
 	default:
@@ -2055,6 +2074,7 @@  static unsigned int intel_surf_alignment(const struct drm_framebuffer *fb,
 		if (INTEL_GEN(dev_priv) >= 9)
 			return 256 * 1024;
 		return 0;
+	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
 	case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
 		return 16 * 1024;
 	case I915_FORMAT_MOD_Y_TILED_CCS:
@@ -2254,10 +2274,17 @@  static u32 intel_adjust_tile_offset(int *x, int *y,
 	return new_offset;
 }
 
-static bool is_surface_linear(u64 modifier, int color_plane)
+static bool is_surface_linear(const struct drm_framebuffer *fb, int color_plane)
 {
-	return modifier == DRM_FORMAT_MOD_LINEAR ||
-	       (modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS && color_plane == 1);
+	switch (fb->modifier) {
+	case DRM_FORMAT_MOD_LINEAR:
+		return true;
+	case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
+	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
+		return is_ccs_plane(fb, color_plane);
+	default:
+		return false;
+	}
 }
 
 static u32 intel_adjust_aligned_offset(int *x, int *y,
@@ -2272,7 +2299,7 @@  static u32 intel_adjust_aligned_offset(int *x, int *y,
 
 	WARN_ON(new_offset > old_offset);
 
-	if (!is_surface_linear(fb->modifier, color_plane)) {
+	if (!is_surface_linear(fb, color_plane)) {
 		unsigned int tile_size, tile_width, tile_height;
 		unsigned int pitch_tiles;
 
@@ -2342,7 +2369,7 @@  static u32 intel_compute_aligned_offset(struct drm_i915_private *dev_priv,
 	if (alignment)
 		alignment--;
 
-	if (!is_surface_linear(fb->modifier, color_plane)) {
+	if (!is_surface_linear(fb, color_plane)) {
 		unsigned int tile_size, tile_width, tile_height;
 		unsigned int tile_rows, tiles, pitch_tiles;
 
@@ -2445,6 +2472,7 @@  static unsigned int intel_fb_modifier_to_tiling(u64 fb_modifier)
 	case I915_FORMAT_MOD_Y_TILED:
 	case I915_FORMAT_MOD_Y_TILED_CCS:
 	case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
+	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
 		return I915_TILING_Y;
 	default:
 		return I915_TILING_NONE;
@@ -2494,6 +2522,13 @@  static const struct drm_format_info gen12_ccs_formats[] = {
 	  .cpp = { 4, 1, }, .hsub = 2, .vsub = 32, .has_alpha = true },
 };
 
+static const struct drm_format_info gen12_mc_ccs_formats[] = {
+	{ .format = DRM_FORMAT_YUYV, .num_planes = 2,
+	  .cpp = { 2, 1, }, .hsub = 4, .vsub = 32, .is_yuv = true },
+	{ .format = DRM_FORMAT_NV12, .num_planes = 4,
+	  .cpp = { 1, 2, 1, 1}, .hsub = 2, .vsub = 2, .is_yuv = true },
+};
+
 static const struct drm_format_info *
 lookup_format_info(const struct drm_format_info formats[],
 		   int num_formats, u32 format)
@@ -2511,12 +2546,21 @@  lookup_format_info(const struct drm_format_info formats[],
 static const struct drm_format_info *
 intel_get_format_info(const struct drm_mode_fb_cmd2 *cmd)
 {
+	const struct drm_format_info *info;
+
 	switch (cmd->modifier[0]) {
 	case I915_FORMAT_MOD_Y_TILED_CCS:
 	case I915_FORMAT_MOD_Yf_TILED_CCS:
 		return lookup_format_info(skl_ccs_formats,
 					  ARRAY_SIZE(skl_ccs_formats),
 					  cmd->pixel_format);
+	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
+		info = lookup_format_info(gen12_mc_ccs_formats,
+					  ARRAY_SIZE(gen12_mc_ccs_formats),
+					  cmd->pixel_format);
+		if (info)
+			return info;
+		/* fall through */
 	case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
 		return lookup_format_info(gen12_ccs_formats,
 					  ARRAY_SIZE(gen12_ccs_formats),
@@ -2526,13 +2570,6 @@  intel_get_format_info(const struct drm_mode_fb_cmd2 *cmd)
 	}
 }
 
-bool is_ccs_modifier(u64 modifier)
-{
-	return modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS ||
-	       modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
-	       modifier == I915_FORMAT_MOD_Yf_TILED_CCS;
-}
-
 u32 intel_plane_fb_max_stride(struct drm_i915_private *dev_priv,
 			      u32 pixel_format, u64 modifier)
 {
@@ -2576,7 +2613,7 @@  intel_fb_stride_alignment(const struct drm_framebuffer *fb, int color_plane)
 	struct drm_i915_private *dev_priv = to_i915(fb->dev);
 	u32 tile_width;
 
-	if (is_surface_linear(fb->modifier, color_plane)) {
+	if (is_surface_linear(fb, color_plane)) {
 		u32 max_stride = intel_plane_fb_max_stride(dev_priv,
 							   fb->format->format,
 							   fb->modifier);
@@ -2592,7 +2629,7 @@  intel_fb_stride_alignment(const struct drm_framebuffer *fb, int color_plane)
 	}
 
 	tile_width = intel_tile_width_bytes(fb, color_plane);
-	if (is_ccs_modifier(fb->modifier) && color_plane == 0) {
+	if (is_ccs_modifier(fb->modifier)) {
 		/*
 		 * Display WA #0531: skl,bxt,kbl,glk
 		 *
@@ -2602,7 +2639,7 @@  intel_fb_stride_alignment(const struct drm_framebuffer *fb, int color_plane)
 		 * require the entire fb to accommodate that to avoid
 		 * potential runtime errors at plane configuration time.
 		 */
-		if (IS_GEN(dev_priv, 9) && fb->width > 3840)
+		if (IS_GEN(dev_priv, 9) && color_plane == 0 && fb->width > 3840)
 			tile_width *= 4;
 		/*
 		 * The main surface pitch must be padded to a multiple of four
@@ -2682,25 +2719,75 @@  static bool intel_plane_needs_remap(const struct intel_plane_state *plane_state)
 	return stride > max_stride;
 }
 
+static void
+intel_fb_plane_get_subsampling(int *hsub, int *vsub, const struct drm_framebuffer *fb, int color_plane)
+{
+	int i;
+	static const struct {
+		u32 format;
+		int vsub[4];
+		int hsub[4];
+	} mc_ccs_subsampling[] = { { .hsub = { 1, 2, 8, 16 },
+				     .vsub = { 1, 2, 32, 32 },
+				     .format = DRM_FORMAT_NV12, },
+				 };
+
+	*hsub = fb->format->hsub;
+	*vsub = fb->format->vsub;
+
+	if (fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS &&
+	    fb->format->num_planes == 4) {
+		for (i = 0; i < ARRAY_SIZE(mc_ccs_subsampling); i++) {
+			if  (mc_ccs_subsampling[i].format == fb->format->format) {
+				*hsub = mc_ccs_subsampling[i].hsub[color_plane];
+				*vsub = mc_ccs_subsampling[i].vsub[color_plane];
+				break;
+			}
+		}
+		WARN_ON(i == ARRAY_SIZE(mc_ccs_subsampling));
+	}
+}
+
+static void
+intel_fb_plane_dims(int *w, int *h, struct drm_framebuffer *fb, int color_plane)
+{
+	int hsub, vsub;
+
+	intel_fb_plane_get_subsampling(&hsub, &vsub, fb, color_plane);
+	*w = fb->width/hsub;
+	*h = fb->height/vsub;
+}
+
 static int
-intel_fb_check_ccs_xy(struct drm_framebuffer *fb, int x, int y)
+intel_fb_check_ccs_xy(struct drm_framebuffer *fb, int aux_plane, int x, int y)
 {
 	struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
-	int hsub = fb->format->hsub;
-	int vsub = fb->format->vsub;
+	int hsub, vsub;
+	int hsub_main, vsub_main;
 	int tile_width, tile_height;
 	int ccs_x, ccs_y;
 	int main_x, main_y;
+	int main_plane;
+
+	if (!is_ccs_plane(fb, aux_plane))
+		return 0;
+
+	main_plane = (aux_plane - 1) / 2;
+	intel_tile_dims(fb, aux_plane, &tile_width, &tile_height);
+	intel_fb_plane_get_subsampling(&hsub, &vsub, fb, aux_plane);
+	intel_fb_plane_get_subsampling(&hsub_main, &vsub_main, fb,
+				       main_plane);
 
-	intel_tile_dims(fb, 1, &tile_width, &tile_height);
+	hsub /= hsub_main;
+	vsub /= vsub_main;
 
 	tile_width *= hsub;
 	tile_height *= vsub;
 
 	ccs_x = (x * hsub) % tile_width;
 	ccs_y = (y * vsub) % tile_height;
-	main_x = intel_fb->normal[0].x % tile_width;
-	main_y = intel_fb->normal[0].y % tile_height;
+	main_x = intel_fb->normal[main_plane].x % tile_width;
+	main_y = intel_fb->normal[main_plane].y % tile_height;
 
 	/*
 	* CCS doesn't have its own x/y offset register, so the intra CCS tile
@@ -2710,8 +2797,8 @@  intel_fb_check_ccs_xy(struct drm_framebuffer *fb, int x, int y)
 		DRM_DEBUG_KMS("Bad CCS x/y (main %d,%d ccs %d,%d) full (main %d,%d ccs %d,%d)\n",
 			      main_x, main_y,
 			      ccs_x, ccs_y,
-			      intel_fb->normal[0].x,
-			      intel_fb->normal[0].y,
+			      intel_fb->normal[main_plane].x,
+			      intel_fb->normal[main_plane].y,
 			      x, y);
 		return -EINVAL;
 	}
@@ -2739,8 +2826,7 @@  intel_fill_fb_info(struct drm_i915_private *dev_priv,
 		int ret;
 
 		cpp = fb->format->cpp[i];
-		width = drm_framebuffer_plane_width(fb->width, fb, i);
-		height = drm_framebuffer_plane_height(fb->height, fb, i);
+		intel_fb_plane_dims(&width, &height, fb, i);
 
 		ret = intel_fb_offset_to_xy(&x, &y, fb, i);
 		if (ret) {
@@ -2749,11 +2835,9 @@  intel_fill_fb_info(struct drm_i915_private *dev_priv,
 			return ret;
 		}
 
-		if (is_ccs_modifier(fb->modifier) && i == 1) {
-			ret = intel_fb_check_ccs_xy(fb, x, y);
-			if (ret)
-				return ret;
-		}
+		ret = intel_fb_check_ccs_xy(fb, i, x, y);
+		if (ret)
+			return ret;
 
 		/*
 		 * The fence (if used) is aligned to the start of the object
@@ -3371,6 +3455,7 @@  static int skl_max_plane_width(const struct drm_framebuffer *fb,
 			return 5120;
 	case I915_FORMAT_MOD_Y_TILED_CCS:
 	case I915_FORMAT_MOD_Yf_TILED_CCS:
+	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
 		/* FIXME AUX plane? */
 	case I915_FORMAT_MOD_Y_TILED:
 	case I915_FORMAT_MOD_Yf_TILED:
@@ -3430,16 +3515,18 @@  static int icl_max_plane_height(void)
 }
 
 static bool skl_check_main_ccs_coordinates(struct intel_plane_state *plane_state,
-					   int main_x, int main_y, u32 main_offset)
+					   int main_x, int main_y,
+					   u32 main_offset, int aux_plane)
 {
 	const struct drm_framebuffer *fb = plane_state->base.fb;
-	int hsub = fb->format->hsub;
-	int vsub = fb->format->vsub;
-	int aux_x = plane_state->color_plane[1].x;
-	int aux_y = plane_state->color_plane[1].y;
-	u32 aux_offset = plane_state->color_plane[1].offset;
-	u32 alignment = intel_surf_alignment(fb, 1);
-
+	int hsub;
+	int vsub;
+	int aux_x = plane_state->color_plane[aux_plane].x;
+	int aux_y = plane_state->color_plane[aux_plane].y;
+	u32 aux_offset = plane_state->color_plane[aux_plane].offset;
+	u32 alignment = intel_surf_alignment(fb, aux_plane);
+
+	intel_fb_plane_get_subsampling(&hsub, &vsub, fb, aux_plane);
 	while (aux_offset >= main_offset && aux_y <= main_y) {
 		int x, y;
 
@@ -3451,7 +3538,7 @@  static bool skl_check_main_ccs_coordinates(struct intel_plane_state *plane_state
 
 		x = aux_x / hsub;
 		y = aux_y / vsub;
-		aux_offset = intel_plane_adjust_aligned_offset(&x, &y, plane_state, 1,
+		aux_offset = intel_plane_adjust_aligned_offset(&x, &y, plane_state, aux_plane,
 							       aux_offset, aux_offset - alignment);
 		aux_x = x * hsub + aux_x % hsub;
 		aux_y = y * vsub + aux_y % vsub;
@@ -3460,9 +3547,9 @@  static bool skl_check_main_ccs_coordinates(struct intel_plane_state *plane_state
 	if (aux_x != main_x || aux_y != main_y)
 		return false;
 
-	plane_state->color_plane[1].offset = aux_offset;
-	plane_state->color_plane[1].x = aux_x;
-	plane_state->color_plane[1].y = aux_y;
+	plane_state->color_plane[aux_plane].offset = aux_offset;
+	plane_state->color_plane[aux_plane].x = aux_x;
+	plane_state->color_plane[aux_plane].y = aux_y;
 
 	return true;
 }
@@ -3478,7 +3565,8 @@  static int skl_check_main_surface(struct intel_plane_state *plane_state)
 	int h = drm_rect_height(&plane_state->base.src) >> 16;
 	int max_width;
 	int max_height;
-	u32 alignment, offset, aux_offset = plane_state->color_plane[1].offset;
+	int aux_plane = fb->format->num_planes / 2;
+	u32 alignment, offset, aux_offset = plane_state->color_plane[aux_plane].offset;
 
 	if (INTEL_GEN(dev_priv) >= 11)
 		max_width = icl_max_plane_width(fb, 0, rotation);
@@ -3536,7 +3624,9 @@  static int skl_check_main_surface(struct intel_plane_state *plane_state)
 	 * they match with the main surface x/y offsets.
 	 */
 	if (is_ccs_modifier(fb->modifier)) {
-		while (!skl_check_main_ccs_coordinates(plane_state, x, y, offset)) {
+
+		while (!skl_check_main_ccs_coordinates(plane_state, x, y,
+						       offset, aux_plane)) {
 			if (offset == 0)
 				break;
 
@@ -3544,7 +3634,8 @@  static int skl_check_main_surface(struct intel_plane_state *plane_state)
 								   offset, offset - alignment);
 		}
 
-		if (x != plane_state->color_plane[1].x || y != plane_state->color_plane[1].y) {
+		if (x != plane_state->color_plane[aux_plane].x ||
+		    y != plane_state->color_plane[aux_plane].y) {
 			DRM_DEBUG_KMS("Unable to find suitable display surface offset due to CCS\n");
 			return -EINVAL;
 		}
@@ -3587,6 +3678,41 @@  static int skl_check_nv12_aux_surface(struct intel_plane_state *plane_state)
 		return -EINVAL;
 	}
 
+	if (is_ccs_modifier(fb->modifier)) {
+		int aux_offset = plane_state->color_plane[3].offset;
+		int alignment = intel_surf_alignment(fb, 1);
+
+		if (offset > aux_offset) {
+			int hsub, vsub;
+			int main_x = x, main_y = y;
+
+
+			intel_fb_plane_get_subsampling(&hsub, &vsub, fb, 1);
+			x = main_x / hsub;
+			y = main_y / vsub;
+			offset = intel_plane_adjust_aligned_offset(&x, &y, plane_state, 1,
+								   offset,
+								   aux_offset & ~(alignment - 1));
+			x = x * hsub + main_x % hsub;
+			y = y * vsub + main_y % vsub;
+
+		}
+
+		while (!skl_check_main_ccs_coordinates(plane_state, x, y, offset, 3)) {
+			if (offset == 0)
+				break;
+
+			offset = intel_plane_adjust_aligned_offset(&x, &y, plane_state, 1,
+								   offset, offset - alignment);
+		}
+
+		if (x != plane_state->color_plane[3].x ||
+		    y != plane_state->color_plane[3].y) {
+			DRM_DEBUG_KMS("Unable to find suitable display surface offset due to CCS\n");
+			return -EINVAL;
+		}
+	}
+
 	plane_state->color_plane[1].offset = offset;
 	plane_state->color_plane[1].x = x;
 	plane_state->color_plane[1].y = y;
@@ -3599,19 +3725,30 @@  static int skl_check_ccs_aux_surface(struct intel_plane_state *plane_state)
 	const struct drm_framebuffer *fb = plane_state->base.fb;
 	int src_x = plane_state->base.src.x1 >> 16;
 	int src_y = plane_state->base.src.y1 >> 16;
-	int hsub = fb->format->hsub;
-	int vsub = fb->format->vsub;
-	int x = src_x / hsub;
-	int y = src_y / vsub;
 	u32 offset;
+	int ccs;
 
-	intel_add_fb_offsets(&x, &y, plane_state, 1);
-	offset = intel_plane_compute_aligned_offset(&x, &y, plane_state, 1);
 
-	plane_state->color_plane[1].offset = offset;
-	plane_state->color_plane[1].x = x * hsub + src_x % hsub;
-	plane_state->color_plane[1].y = y * vsub + src_y % vsub;
+	for (ccs = fb->format->num_planes / 2; ccs < fb->format->num_planes; ccs++) {
+		int hsub, vsub;
+		int main_hsub, main_vsub;
+		int x, y;
+
+		intel_fb_plane_get_subsampling(&hsub, &vsub, fb, ccs);
+		intel_fb_plane_get_subsampling(&main_hsub, &main_vsub, fb, (ccs - 1)/ 2);
+
+		hsub /= main_hsub;
+		vsub /= main_vsub;
+		x = src_x / hsub;
+		y = src_y / vsub;
 
+		intel_add_fb_offsets(&x, &y, plane_state, ccs);
+		offset = intel_plane_compute_aligned_offset(&x, &y,
+							    plane_state, ccs);
+		plane_state->color_plane[ccs].offset = offset;
+		plane_state->color_plane[ccs].x = x * hsub + src_x % hsub;
+		plane_state->color_plane[ccs].y = y * vsub + src_y % vsub;
+	}
 	return 0;
 }
 
@@ -3619,6 +3756,7 @@  int skl_check_plane_surface(struct intel_plane_state *plane_state)
 {
 	const struct drm_framebuffer *fb = plane_state->base.fb;
 	int ret;
+	bool needs_aux = false;
 
 	ret = intel_plane_compute_gtt(plane_state);
 	if (ret)
@@ -3628,21 +3766,31 @@  int skl_check_plane_surface(struct intel_plane_state *plane_state)
 		return 0;
 
 	/*
-	 * Handle the AUX surface first since
-	 * the main surface setup depends on it.
+	 * Handle the AUX surface first since the main surface setup depends on
+	 * it.
 	 */
-	if (drm_format_info_is_yuv_semiplanar(fb->format)) {
-		ret = skl_check_nv12_aux_surface(plane_state);
+	if (is_ccs_modifier(fb->modifier)) {
+		needs_aux = true;
+		ret = skl_check_ccs_aux_surface(plane_state);
 		if (ret)
 			return ret;
-	} else if (is_ccs_modifier(fb->modifier)) {
-		ret = skl_check_ccs_aux_surface(plane_state);
+	}
+
+	if (drm_format_info_is_yuv_semiplanar(fb->format)) {
+		needs_aux = true;
+		ret = skl_check_nv12_aux_surface(plane_state);
 		if (ret)
 			return ret;
-	} else {
-		plane_state->color_plane[1].offset = ~0xfff;
-		plane_state->color_plane[1].x = 0;
-		plane_state->color_plane[1].y = 0;
+	}
+
+	if (!needs_aux) {
+		int i;
+
+		for (i = 1; i < fb->format->num_planes; i++) {
+			plane_state->color_plane[i].offset = ~0xfff;
+			plane_state->color_plane[i].x = 0;
+			plane_state->color_plane[i].y = 0;
+		}
 	}
 
 	ret = skl_check_main_surface(plane_state);
@@ -4030,7 +4178,7 @@  static unsigned int skl_plane_stride_mult(const struct drm_framebuffer *fb,
 	 * The stride is either expressed as a multiple of 64 bytes chunks for
 	 * linear buffers or in number of tiles for tiled buffers.
 	 */
-	if (is_surface_linear(fb->modifier, color_plane))
+	if (is_surface_linear(fb, color_plane))
 		return 64;
 	else if (drm_rotation_90_or_270(rotation))
 		return intel_tile_height(fb, color_plane);
@@ -4160,6 +4308,8 @@  static u32 skl_plane_ctl_tiling(u64 fb_modifier)
 		return PLANE_CTL_TILED_Y |
 		       PLANE_CTL_RENDER_DECOMPRESSION_ENABLE |
 		       PLANE_CTL_CLEAR_COLOR_DISABLE;
+	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
+		return PLANE_CTL_TILED_Y | PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE;
 	case I915_FORMAT_MOD_Yf_TILED:
 		return PLANE_CTL_TILED_YF;
 	case I915_FORMAT_MOD_Yf_TILED_CCS:
@@ -9968,6 +10118,8 @@  skylake_get_initial_plane_config(struct intel_crtc *crtc,
 			fb->modifier = INTEL_GEN(dev_priv) >= 12 ?
 				I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS :
 				I915_FORMAT_MOD_Y_TILED_CCS;
+		else if (val & PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE)
+			fb->modifier = I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS;
 		else
 			fb->modifier = I915_FORMAT_MOD_Y_TILED;
 		break;
diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
index 976669f01a8c..5998b959225c 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -530,7 +530,7 @@  struct intel_plane_state {
 		 */
 		u32 stride;
 		int x, y;
-	} color_plane[2];
+	} color_plane[4];
 
 	/* plane control register */
 	u32 ctl;
diff --git a/drivers/gpu/drm/i915/display/intel_sprite.c b/drivers/gpu/drm/i915/display/intel_sprite.c
index 9b9b41b0fc91..788d0fc8d8ef 100644
--- a/drivers/gpu/drm/i915/display/intel_sprite.c
+++ b/drivers/gpu/drm/i915/display/intel_sprite.c
@@ -532,11 +532,13 @@  skl_program_plane(struct intel_plane *plane,
 	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
 	enum plane_id plane_id = plane->id;
 	enum pipe pipe = plane->pipe;
+	const struct drm_framebuffer *fb = plane_state->base.fb;
+	int aux_plane = fb->format->num_planes / 2 + color_plane;
 	const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
 	u32 surf_addr = plane_state->color_plane[color_plane].offset;
 	u32 stride = skl_plane_stride(plane_state, color_plane);
-	u32 aux_dist = plane_state->color_plane[1].offset - surf_addr;
-	u32 aux_stride = skl_plane_stride(plane_state, 1);
+	u32 aux_dist = plane_state->color_plane[aux_plane].offset - surf_addr;
+	u32 aux_stride = skl_plane_stride(plane_state, aux_plane);
 	int crtc_x = plane_state->base.dst.x1;
 	int crtc_y = plane_state->base.dst.y1;
 	u32 x = plane_state->color_plane[color_plane].x;
@@ -544,7 +546,6 @@  skl_program_plane(struct intel_plane *plane,
 	u32 src_w = drm_rect_width(&plane_state->base.src) >> 16;
 	u32 src_h = drm_rect_height(&plane_state->base.src) >> 16;
 	struct intel_plane *linked = plane_state->planar_linked_plane;
-	const struct drm_framebuffer *fb = plane_state->base.fb;
 	u8 alpha = plane_state->base.alpha >> 8;
 	u32 plane_color_ctl = 0;
 	unsigned long irqflags;
@@ -619,8 +620,8 @@  skl_program_plane(struct intel_plane *plane,
 
 	if (INTEL_GEN(dev_priv) < 11)
 		I915_WRITE_FW(PLANE_AUX_OFFSET(pipe, plane_id),
-			      (plane_state->color_plane[1].y << 16) |
-			      plane_state->color_plane[1].x);
+			      (plane_state->color_plane[aux_plane].y << 16) |
+			      plane_state->color_plane[aux_plane].x);
 
 	/*
 	 * The control register self-arms if the plane was previously
@@ -1737,7 +1738,8 @@  static int skl_plane_check_fb(const struct intel_crtc_state *crtc_state,
 	     fb->modifier == I915_FORMAT_MOD_Yf_TILED ||
 	     fb->modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
 	     fb->modifier == I915_FORMAT_MOD_Yf_TILED_CCS ||
-	     fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS)) {
+	     fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS ||
+	     fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS)) {
 		DRM_DEBUG_KMS("Y/Yf tiling not supported in IF-ID mode\n");
 		return -EINVAL;
 	}
@@ -2149,7 +2151,16 @@  static const u64 skl_plane_format_modifiers_ccs[] = {
 	DRM_FORMAT_MOD_INVALID
 };
 
-static const u64 gen12_plane_format_modifiers_ccs[] = {
+static const u64 gen12_plane_format_modifiers_mc_ccs[] = {
+	I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS,
+	I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS,
+	I915_FORMAT_MOD_Y_TILED,
+	I915_FORMAT_MOD_X_TILED,
+	DRM_FORMAT_MOD_LINEAR,
+	DRM_FORMAT_MOD_INVALID
+};
+
+static const u64 gen12_plane_format_modifiers_rc_ccs[] = {
 	I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS,
 	I915_FORMAT_MOD_Y_TILED,
 	I915_FORMAT_MOD_X_TILED,
@@ -2305,10 +2316,21 @@  static bool skl_plane_format_mod_supported(struct drm_plane *_plane,
 	}
 }
 
+static bool gen12_plane_supports_mc_ccs(enum plane_id plane_id)
+{
+	return plane_id < PLANE_SPRITE4;
+}
+
 static bool gen12_plane_format_mod_supported(struct drm_plane *_plane,
 					     u32 format, u64 modifier)
 {
+	struct intel_plane *plane = to_intel_plane(_plane);
+
 	switch (modifier) {
+	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
+		if (!gen12_plane_supports_mc_ccs(plane->id))
+			return false;
+		/* fall through */
 	case DRM_FORMAT_MOD_LINEAR:
 	case I915_FORMAT_MOD_X_TILED:
 	case I915_FORMAT_MOD_Y_TILED:
@@ -2326,14 +2348,17 @@  static bool gen12_plane_format_mod_supported(struct drm_plane *_plane,
 		if (is_ccs_modifier(modifier))
 			return true;
 		/* fall through */
-	case DRM_FORMAT_RGB565:
-	case DRM_FORMAT_XRGB2101010:
-	case DRM_FORMAT_XBGR2101010:
 	case DRM_FORMAT_YUYV:
 	case DRM_FORMAT_YVYU:
 	case DRM_FORMAT_UYVY:
 	case DRM_FORMAT_VYUY:
+		if (modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS)
+			return true;
+		/* fall through */
 	case DRM_FORMAT_NV12:
+	case DRM_FORMAT_RGB565:
+	case DRM_FORMAT_XRGB2101010:
+	case DRM_FORMAT_XBGR2101010:
 	case DRM_FORMAT_P010:
 	case DRM_FORMAT_P012:
 	case DRM_FORMAT_P016:
@@ -2470,6 +2495,14 @@  static const u32 *icl_get_plane_formats(struct drm_i915_private *dev_priv,
 	}
 }
 
+static const u64 *gen12_get_plane_modifiers(enum plane_id plane_id)
+{
+	if (gen12_plane_supports_mc_ccs(plane_id))
+		return gen12_plane_format_modifiers_mc_ccs;
+	else
+		return gen12_plane_format_modifiers_rc_ccs;
+}
+
 static bool skl_plane_has_ccs(struct drm_i915_private *dev_priv,
 			      enum pipe pipe, enum plane_id plane_id)
 {
@@ -2536,7 +2569,7 @@  skl_universal_plane_create(struct drm_i915_private *dev_priv,
 
 	plane->has_ccs = skl_plane_has_ccs(dev_priv, pipe, plane_id);
 	if (INTEL_GEN(dev_priv) >= 12) {
-		modifiers = gen12_plane_format_modifiers_ccs;
+		modifiers = gen12_get_plane_modifiers(plane_id);
 		plane_funcs = &gen12_plane_funcs;
 	} else {
 		if (plane->has_ccs)
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 519cfb0a5c42..02eaef8adac0 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -6697,6 +6697,7 @@  enum {
 #define   PLANE_CTL_TILED_Y			(4 << 10)
 #define   PLANE_CTL_TILED_YF			(5 << 10)
 #define   PLANE_CTL_FLIP_HORIZONTAL		(1 << 8)
+#define   PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE	(1 << 4) /* TGL+ */
 #define   PLANE_CTL_ALPHA_MASK			(0x3 << 4) /* Pre-GLK */
 #define   PLANE_CTL_ALPHA_DISABLE		(0 << 4)
 #define   PLANE_CTL_ALPHA_SW_PREMULTIPLY	(2 << 4)