minigbm: Add support for CCS Media Compression on MTL

BUG=b:201620358
TEST=null_platform_test -m I915_FORMAT_MOD_4_TILED_MTL_MC_CCS success

cat /sys/kernel/debug/dri/1/i915_display_info during rendering

uapi: [FB:434] XR24 little-endian (0x34325258),0x10000000000000e,1920x1200, visible=visible, src=1920.000000x1200.000000+0.000000+0.000000, dst=1920x1200+0+0, rotation=0 (0x00000001)
                hw: [FB:434] XR24 little-endian (0x34325258),0x10000000000000e,1920x1200, visible=yes, src=1920.000000x1200.000000+0.000000+0.000000, dst=1920x1200+0+0, rotation=0 (0x00000001)
        [PLANE:47:plane 2A]: type=OVL

and make sure the modifier shows 0x10000000000000e

v3: Rebased the patch as per latest tip and fixes.

Credits-to: Bai, Guangyao <guangyao.bai@intel.com>
		Heikkila, Juha-pekka <juha-pekka.heikkila@intel.com>
		Ma, Zhaoliang <zhaoliang.ma@intel.com>

Change-Id: I9d9391a2f9b1f8d78f2a70b729f1fcc86b76679d
Signed-off-by: Lobo, Melanie <melanie.lobo@intel.com>
Signed-off-by: Santa, Carlos <carlos.santa@intel.com>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/minigbm/+/5351727
Commit-Queue: Vidya Srinivas <vidya.srinivas@intel.com>
Reviewed-by: Dominik Behr <dbehr@chromium.org>
diff --git a/drv.h b/drv.h
index b61aedf..245fd57 100644
--- a/drv.h
+++ b/drv.h
@@ -98,6 +98,22 @@
 #define I915_FORMAT_MOD_4_TILED_MTL_RC_CCS fourcc_mod_code(INTEL, 13)
 #endif
 
+#ifndef I915_FORMAT_MOD_4_TILED_MTL_MC_CCS
+//TODO: remove this defination once drm_fourcc.h contains it.
+/*
+ * Intel color control surfaces (CCS) for display ver 14 media compression
+ *
+ * The main surface is tile4 and at plane index 0, the CCS is linear and
+ * at index 1. A 64B CCS cache line corresponds to an area of 4x1 tiles in
+ * main surface. In other words, 4 bits in CCS map to a main surface cache
+ * line pair. The main surface pitch is required to be a multiple of four
+ * tile4 widths. For semi-planar formats like NV12, CCS planes follow the
+ * Y and UV planes i.e., planes 0 and 1 are used for Y and UV surfaces,
+ * planes 2 and 3 for the respective CCS.
+ */
+#define I915_FORMAT_MOD_4_TILED_MTL_MC_CCS fourcc_mod_code(INTEL, 14)
+#endif
+
 // clang-format on
 struct driver;
 struct bo;
diff --git a/i915.c b/i915.c
index b9e377f..fd00781 100644
--- a/i915.c
+++ b/i915.c
@@ -46,7 +46,9 @@
 						 DRM_FORMAT_MOD_LINEAR };
 
 static const uint64_t xe_lpdp_modifier_order[] = { I915_FORMAT_MOD_4_TILED_MTL_RC_CCS,
-						   I915_FORMAT_MOD_4_TILED, I915_FORMAT_MOD_X_TILED,
+						   I915_FORMAT_MOD_4_TILED_MTL_MC_CCS,
+						   I915_FORMAT_MOD_4_TILED,
+						   I915_FORMAT_MOD_X_TILED,
 						   DRM_FORMAT_MOD_LINEAR };
 
 struct modifier_support_t {
@@ -562,7 +564,8 @@
 	    modifier == I915_FORMAT_MOD_4_TILED_MTL_RC_CCS) {
 		assert(num_planes == 1);
 		return 2;
-	} else if (modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS) {
+	} else if (modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS ||
+		   modifier == I915_FORMAT_MOD_4_TILED_MTL_MC_CCS) {
 		assert(num_planes == 2);
 		return 4;
 	}
@@ -570,6 +573,13 @@
 	return num_planes;
 }
 
+#define gbm_fls(x) ((x) ? __builtin_choose_expr(sizeof(x) == 8, \
+						64 - __builtin_clzll(x), \
+						32 - __builtin_clz(x)) : 0)
+
+#define roundup_power_of_two(x) ((x) != 0 ? 1ULL << gbm_fls((x) - 1) : 0)
+
+
 static int i915_bo_compute_metadata(struct bo *bo, uint32_t width, uint32_t height, uint32_t format,
 				    uint64_t use_flags, const uint64_t *modifiers, uint32_t count)
 {
@@ -590,15 +600,18 @@
 		 * on |use_flags|. Instead the client should request them explicitly through
 		 * gbm_bo_create_with_modifiers().
 		 */
-		assert(modifier != I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS);
+		assert(modifier != I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS &&
+			modifier != I915_FORMAT_MOD_4_TILED_MTL_MC_CCS);
 		/* TODO(b/323863689): Account for driver's bandwidth compression in minigbm for
 		 * media compressed buffers. */
 	}
-	if (modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS &&
-	    !(format == DRM_FORMAT_NV12 || format == DRM_FORMAT_P010)) {
-		drv_loge("Media compression is only supported for NV12 and P010\n");
-		return -EINVAL;
-	}
+	if ((modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS ||
+                        modifier == I915_FORMAT_MOD_4_TILED_MTL_MC_CCS) &&
+                        !(format == DRM_FORMAT_NV12 || format == DRM_FORMAT_P010))
+                {
+                        drv_loge("Media compression is only supported for NV12 and P010\n");
+                        return -EINVAL;
+                }
 
 	/*
 	 * i915 only supports linear/x-tiled above 4096 wide on Gen9/Gen10 GPU.
@@ -656,6 +669,7 @@
 		break;
 	case I915_FORMAT_MOD_4_TILED:
 	case I915_FORMAT_MOD_4_TILED_MTL_RC_CCS:
+	case I915_FORMAT_MOD_4_TILED_MTL_MC_CCS:
 		bo->meta.tiling = I915_TILING_4;
 		break;
 	}
@@ -782,39 +796,67 @@
 		/* Total number of planes & sizes */
 		bo->meta.num_planes = plane + a_plane;
 		bo->meta.total_size = offset;
-	} else if (modifier == I915_FORMAT_MOD_4_TILED_MTL_RC_CCS) {
-
-		/*
-		 * considering only 128 byte compression and one cache line of
-		 * aux buffer(64B) contains compression status of 4-Y tiles.
-		 * Which is 4 * (128B * 32L).
-		 * line stride(bytes) is 4 * 128B
-		 * and tile stride(lines) is 32L
+	} else if (modifier == I915_FORMAT_MOD_4_TILED_MTL_RC_CCS ||
+		   modifier == I915_FORMAT_MOD_4_TILED_MTL_MC_CCS) {
+		/* Media compression modifiers should only be possible via the
+		 * gbm_bo_create_with_modifiers() path, i.e., the minigbm client needs to
+		 * explicitly request it.
 		 */
-		uint32_t stride = ALIGN(drv_stride_from_format(format, width, 0), 512);
-		stride = ALIGN(stride, 256);
+		assert(modifier != I915_FORMAT_MOD_4_TILED_MTL_MC_CCS ||
+			use_flags == BO_USE_NONE);
+		assert(modifier != I915_FORMAT_MOD_4_TILED_MTL_MC_CCS ||
+			bo->meta.use_flags == BO_USE_NONE);
+		assert(modifier != I915_FORMAT_MOD_4_TILED_MTL_MC_CCS ||
+			(!!modifiers && count > 0));
+		assert(modifier != I915_FORMAT_MOD_4_TILED_MTL_MC_CCS ||
+			(format == DRM_FORMAT_NV12 || format == DRM_FORMAT_P010 ||
+			 format == DRM_FORMAT_XRGB8888 || format == DRM_FORMAT_XBGR8888));
+		assert(drv_num_planes_from_format(format) > 0);
 
-		height = ALIGN(drv_height_from_format(format, height, 0), 32);
+		uint32_t offset = 0, stride = 0;
+		size_t plane = 0;
+		size_t a_plane = 0;
+		for(plane = 0; plane < drv_num_planes_from_format(format); plane++) {
+			uint32_t alignment = 0, val, tmpoffset = 0;
 
+			/*
+			 * tile_align = 4 (for width) for CCS and
+			 * tile_width = 128, tile_height = 32 for MC CCS
+			 */
+			stride = ALIGN(drv_stride_from_format(format, width, plane), 512);
+			height = ALIGN(drv_height_from_format(format, height, plane), 32);
+			bo->meta.strides[plane] = stride;
 
-		bo->meta.strides[0] = stride;
-		/* size calculation and alignment are 64KB aligned
-		 * size as per spec
-		 */
-		bo->meta.sizes[0] = ALIGN(stride * height, 65536);
-		bo->meta.offsets[0] = 0;
+			/* MTL needs 1MB Alignment */
+			bo->meta.sizes[plane] = ALIGN(stride * height, 0x100000);
+			if (plane == 1 && (format == DRM_FORMAT_NV12 || format == DRM_FORMAT_P010)) {
+				alignment = 1 << 20;
+				offset += alignment - (offset % alignment);
+				tmpoffset = offset;
+				val = roundup_power_of_two(stride);
+				if ((stride * val) > tmpoffset)
+					offset = stride * val;
+			}
+
+			bo->meta.offsets[plane] = offset;
+			offset += bo->meta.sizes[plane];
+		}
 
 		/* Aux buffer is linear and page aligned. It is placed after
 		 * other planes and aligned to main buffer stride.
 		 */
-		bo->meta.strides[1] = bo->meta.strides[0] / 8;
+		for(a_plane = 0; a_plane < plane; a_plane++) {
+			stride = bo->meta.strides[a_plane] / 8;
+			bo->meta.strides[a_plane + plane] = stride;
 
-		/* Aligned to page size */
-		bo->meta.sizes[1] = ALIGN(bo->meta.sizes[0] / 256, getpagesize());
-		bo->meta.offsets[1] = bo->meta.sizes[0];
-		/* Total number of planes & sizes */
-		bo->meta.num_planes = 2;
-		bo->meta.total_size = bo->meta.sizes[0] + bo->meta.sizes[1];
+			/* Aligned to page size */
+			bo->meta.sizes[a_plane + plane] = ALIGN(bo->meta.sizes[a_plane] / 256, getpagesize());
+			bo->meta.offsets[a_plane + plane] = offset;
+			/* next buffer offset */
+			offset += bo->meta.sizes[plane + a_plane];
+		}
+		bo->meta.num_planes = a_plane + plane;
+		bo->meta.total_size = offset;
 	} else {
 		return i915_bo_from_format(bo, width, height, format);
 	}
@@ -933,7 +975,8 @@
 	    (bo->meta.format_modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS) ||
 	    (bo->meta.format_modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS) ||
 	    (bo->meta.format_modifier == I915_FORMAT_MOD_4_TILED) ||
-	    (bo->meta.format_modifier == I915_FORMAT_MOD_4_TILED_MTL_RC_CCS))
+	    (bo->meta.format_modifier == I915_FORMAT_MOD_4_TILED_MTL_RC_CCS) ||
+	    (bo->meta.format_modifier == I915_FORMAT_MOD_4_TILED_MTL_MC_CCS))
 		return MAP_FAILED;
 
 	if (bo->meta.tiling == I915_TILING_NONE) {