drm/msm/sde: explicitly enumerate supported plane formats

Explicitly list supported formats rather than attempting to
infer what is supported based on h/w features. This makes
the determination of supported formats more reliable, and
also opens the way to account for different h/w blocks
supporting different sets of formats.

Change-Id: I39b223638c2c126d57eee5551a57c7b8fd7cb1f5
Signed-off-by: Clarence Ip <cip@codeaurora.org>
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 74050e2..8dca108 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -74,6 +74,7 @@
 	/* blob properties, always put these first */
 	PLANE_PROP_SCALER,
 	PLANE_PROP_CSC,
+	PLANE_PROP_SDE_INFO,
 
 	/* # of blob properties */
 	PLANE_PROP_BLOBCOUNT,
diff --git a/drivers/gpu/drm/msm/sde/sde_formats.c b/drivers/gpu/drm/msm/sde/sde_formats.c
index 25dac8c..ac14bad 100644
--- a/drivers/gpu/drm/msm/sde/sde_formats.c
+++ b/drivers/gpu/drm/msm/sde/sde_formats.c
@@ -814,21 +814,34 @@
 	return NULL;
 }
 
-uint32_t sde_populate_formats(uint32_t *pixel_formats,
-		uint32_t pixel_formats_max, bool rgb_only)
+uint32_t sde_populate_formats(
+		const struct sde_format_extended *format_list,
+		uint32_t *pixel_formats,
+		uint64_t *pixel_modifiers,
+		uint32_t pixel_formats_max)
 {
-	uint32_t i;
+	uint32_t i, fourcc_format;
 
-	for (i = 0; i < ARRAY_SIZE(sde_format_map); i++) {
-		const struct sde_format *fmt = &sde_format_map[i];
+	if (!format_list || !pixel_formats)
+		return 0;
 
-		if (i == pixel_formats_max)
-			break;
+	for (i = 0, fourcc_format = 0;
+			format_list->fourcc_format && i < pixel_formats_max;
+			++format_list) {
+		/* verify if listed format is in sde_format_map? */
 
-		if (rgb_only && SDE_FORMAT_IS_YUV(fmt))
-			continue;
-
-		pixel_formats[i] = fmt->base.pixel_format;
+		/* optionally return modified formats */
+		if (pixel_modifiers) {
+			/* assume same modifier for all fb planes */
+			pixel_formats[i] = format_list->fourcc_format;
+			pixel_modifiers[i++] = format_list->modifier;
+		} else {
+			/* assume base formats grouped together */
+			if (fourcc_format != format_list->fourcc_format) {
+				fourcc_format = format_list->fourcc_format;
+				pixel_formats[i++] = fourcc_format;
+			}
+		}
 	}
 
 	return i;
diff --git a/drivers/gpu/drm/msm/sde/sde_formats.h b/drivers/gpu/drm/msm/sde/sde_formats.h
index 3400b14..c890484 100644
--- a/drivers/gpu/drm/msm/sde/sde_formats.h
+++ b/drivers/gpu/drm/msm/sde/sde_formats.h
@@ -45,16 +45,17 @@
 
 /**
  * sde_populate_formats - populate the given array with fourcc codes supported
- * @pixel_formats:   array to populate with fourcc codes
- * @max_formats:     length of pixel formats array
- * @rgb_only:        exclude any non-rgb formats from the list
- *
+ * @format_list:       pointer to list of possible formats
+ * @pixel_formats:     array to populate with fourcc codes
+ * @pixel_modifiers:   array to populate with drm modifiers, can be NULL
+ * @pixel_formats_max: length of pixel formats array
  * Return: number of elements populated
  */
 uint32_t sde_populate_formats(
+		const struct sde_format_extended *format_list,
 		uint32_t *pixel_formats,
-		uint32_t max_formats,
-		bool rgb_only);
+		uint64_t *pixel_modifiers,
+		uint32_t pixel_formats_max);
 
 /**
  * sde_format_check_modified_format - validate format and buffers for
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
index 0b0effa..c2d8eac 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
@@ -223,6 +223,17 @@
 };
 
 /**
+ * struct sde_format_extended - define sde specific pixel format+modifier
+ * @fourcc_format: Base FOURCC pixel format code
+ * @modifier: 64-bit drm format modifier, same modifier must be applied to all
+ *            framebuffer planes
+ */
+struct sde_format_extended {
+	uint32_t fourcc_format;
+	uint64_t modifier;
+};
+
+/**
  * struct sde_sspp_sub_blks : SSPP sub-blocks
  * @maxdwnscale: max downscale ratio supported(without DECIMATION)
  * @maxupscale:  maxupscale ratio supported
@@ -235,6 +246,7 @@
  * @pa_blk:
  * @hist_lut:
  * @pcc_blk:
+ * @format_list: Pointer to list of supported formats
  */
 struct sde_sspp_sub_blks {
 	u32 maxlinewidth;
@@ -250,6 +262,8 @@
 	struct sde_pp_blk pa_blk;
 	struct sde_pp_blk hist_lut;
 	struct sde_pp_blk pcc_blk;
+
+	const struct sde_format_extended *format_list;
 };
 
 /**
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog_8996.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog_8996.c
index 7a4542a..e0094bc 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog_8996.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog_8996.c
@@ -61,6 +61,84 @@
 #define DECIMATION_17X_MAX_H	4
 #define DECIMATION_17X_MAX_V	4
 
+static const struct sde_format_extended plane_formats[] = {
+	{DRM_FORMAT_ARGB8888, 0},
+	{DRM_FORMAT_ABGR8888, 0},
+	{DRM_FORMAT_RGBA8888, 0},
+	{DRM_FORMAT_RGBA8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
+	{DRM_FORMAT_BGRA8888, 0},
+	{DRM_FORMAT_XRGB8888, 0},
+	{DRM_FORMAT_RGBX8888, 0},
+	{DRM_FORMAT_RGBX8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
+	{DRM_FORMAT_RGB888, 0},
+	{DRM_FORMAT_BGR888, 0},
+	{DRM_FORMAT_RGB565, 0},
+	{DRM_FORMAT_RGB565, DRM_FORMAT_MOD_QCOM_COMPRESSED},
+	{DRM_FORMAT_BGR565, 0},
+	{DRM_FORMAT_ARGB1555, 0},
+	{DRM_FORMAT_ABGR1555, 0},
+	{DRM_FORMAT_RGBA5551, 0},
+	{DRM_FORMAT_BGRA5551, 0},
+	{DRM_FORMAT_XRGB1555, 0},
+	{DRM_FORMAT_XBGR1555, 0},
+	{DRM_FORMAT_RGBX5551, 0},
+	{DRM_FORMAT_BGRX5551, 0},
+	{DRM_FORMAT_ARGB4444, 0},
+	{DRM_FORMAT_ABGR4444, 0},
+	{DRM_FORMAT_RGBA4444, 0},
+	{DRM_FORMAT_BGRA4444, 0},
+	{DRM_FORMAT_XRGB4444, 0},
+	{DRM_FORMAT_XBGR4444, 0},
+	{DRM_FORMAT_RGBX4444, 0},
+	{DRM_FORMAT_BGRX4444, 0},
+	{0, 0},
+};
+
+static const struct sde_format_extended plane_formats_yuv[] = {
+	{DRM_FORMAT_ARGB8888, 0},
+	{DRM_FORMAT_ABGR8888, 0},
+	{DRM_FORMAT_RGBA8888, 0},
+	{DRM_FORMAT_RGBA8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
+	{DRM_FORMAT_BGRA8888, 0},
+	{DRM_FORMAT_XRGB8888, 0},
+	{DRM_FORMAT_RGBX8888, 0},
+	{DRM_FORMAT_RGBX8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
+	{DRM_FORMAT_RGB888, 0},
+	{DRM_FORMAT_BGR888, 0},
+	{DRM_FORMAT_RGB565, 0},
+	{DRM_FORMAT_RGB565, DRM_FORMAT_MOD_QCOM_COMPRESSED},
+	{DRM_FORMAT_BGR565, 0},
+	{DRM_FORMAT_ARGB1555, 0},
+	{DRM_FORMAT_ABGR1555, 0},
+	{DRM_FORMAT_RGBA5551, 0},
+	{DRM_FORMAT_BGRA5551, 0},
+	{DRM_FORMAT_XRGB1555, 0},
+	{DRM_FORMAT_XBGR1555, 0},
+	{DRM_FORMAT_RGBX5551, 0},
+	{DRM_FORMAT_BGRX5551, 0},
+	{DRM_FORMAT_ARGB4444, 0},
+	{DRM_FORMAT_ABGR4444, 0},
+	{DRM_FORMAT_RGBA4444, 0},
+	{DRM_FORMAT_BGRA4444, 0},
+	{DRM_FORMAT_XRGB4444, 0},
+	{DRM_FORMAT_XBGR4444, 0},
+	{DRM_FORMAT_RGBX4444, 0},
+	{DRM_FORMAT_BGRX4444, 0},
+
+	{DRM_FORMAT_NV12, 0},
+	{DRM_FORMAT_NV12, DRM_FORMAT_MOD_QCOM_COMPRESSED},
+	{DRM_FORMAT_NV21, 0},
+	{DRM_FORMAT_NV16, 0},
+	{DRM_FORMAT_NV61, 0},
+	{DRM_FORMAT_VYUY, 0},
+	{DRM_FORMAT_UYVY, 0},
+	{DRM_FORMAT_YUYV, 0},
+	{DRM_FORMAT_YVYU, 0},
+	{DRM_FORMAT_YUV420, 0},
+	{DRM_FORMAT_YVU420, 0},
+	{0, 0},
+};
+
 /**
  * set_cfg_1xx_init(): populate sde sub-blocks reg offsets and instance counts
  */
@@ -68,6 +146,28 @@
 {
 
 	/* Layer capability */
+	static const struct sde_sspp_sub_blks vig_layer = {
+		.maxlinewidth = 2560,
+		.danger_lut = 0xFFFF,
+		.safe_lut = 0xFF00,
+		.maxdwnscale = 4, .maxupscale = 20,
+		.maxhdeciexp = DECIMATION_17X_MAX_H,
+		.maxvdeciexp = DECIMATION_17X_MAX_V,
+		.src_blk = {.id = SDE_SSPP_SRC,
+			.base = 0x00, .len = 0x150,},
+		.scaler_blk = {.id = SDE_SSPP_SCALER_QSEED2,
+			.base = 0x200, .len = 0x70,},
+		.csc_blk = {.id = SDE_SSPP_CSC,
+			.base = 0x320, .len = 0x44,},
+		.pa_blk = {.id = SDE_SSPP_PA_V1,
+			.base = 0x200, .len = 0x0,},
+		.hist_lut = {.id = SDE_SSPP_HIST_V1,
+			.base = 0xA00, .len = 0x400,},
+		.pcc_blk = {.id = SDE_SSPP_PCC,
+			.base = 0x1780, .len = 0x64,},
+		.format_list = plane_formats_yuv,
+	};
+
 	static const struct sde_sspp_sub_blks layer = {
 		.maxlinewidth = 2560,
 		.danger_lut = 0xFFFF,
@@ -87,6 +187,7 @@
 			.base = 0xA00, .len = 0x400,},
 		.pcc_blk = {.id = SDE_SSPP_PCC,
 			.base = 0x1780, .len = 0x64,},
+		.format_list = plane_formats,
 	};
 
 	static const struct sde_sspp_sub_blks dma = {
@@ -102,6 +203,7 @@
 		.pa_blk = {.id = 0, .base = 0x200, .len = 0x0,},
 		.hist_lut = {.id = 0, .base = 0xA00, .len = 0x0,},
 		.pcc_blk = {.id = SDE_SSPP_PCC, .base = 0x01780, .len = 0x64,},
+		.format_list = plane_formats,
 	};
 
 	static const struct sde_sspp_sub_blks cursor = {
@@ -117,6 +219,7 @@
 		.pa_blk = {.id = 0, .base = 0x00, .len = 0x0,},
 		.hist_lut = {.id = 0, .base = 0x00, .len = 0x0,},
 		.pcc_blk = {.id = 0, .base = 0x00, .len = 0x0,},
+		.format_list = plane_formats,
 	};
 
 	/* MIXER capability */
@@ -176,13 +279,13 @@
 		.sspp_count = 12,
 		.sspp = {
 			{.id = SSPP_VIG0, .base = 0x00005000,
-			.features = VIG_17X_MASK, .sblk = &layer},
+			.features = VIG_17X_MASK, .sblk = &vig_layer},
 			{.id = SSPP_VIG1, .base = 0x00007000,
-			.features = VIG_17X_MASK, .sblk = &layer},
+			.features = VIG_17X_MASK, .sblk = &vig_layer},
 			{.id = SSPP_VIG2, .base = 0x00009000,
-			.features = VIG_17X_MASK, .sblk = &layer},
+			.features = VIG_17X_MASK, .sblk = &vig_layer},
 			{.id = SSPP_VIG3, .base = 0x0000b000,
-			.features = VIG_17X_MASK, .sblk = &layer},
+			.features = VIG_17X_MASK, .sblk = &vig_layer},
 
 			{.id = SSPP_RGB0, .base = 0x00015000,
 			.features = RGB_17X_MASK, .sblk = &layer},
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index 0f8a8e1..6841c2b 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -62,6 +62,7 @@
 
 	struct msm_property_info property_info;
 	struct msm_property_data property_data[PLANE_PROP_COUNT];
+	struct drm_property_blob *blob_sde_info;
 
 	/* debugfs related stuff */
 	struct dentry *debugfs_root;
@@ -1105,6 +1106,8 @@
 	static const struct drm_prop_enum_list e_src_config[] = {
 		{SDE_DRM_DEINTERLACE, "deinterlace"}
 	};
+	const struct sde_format_extended *format_list;
+	static struct sde_kms_info sde_info;
 	struct sde_plane *psde = to_sde_plane(plane);
 
 	DBG("");
@@ -1153,6 +1156,29 @@
 		msm_property_install_blob(&psde->property_info, "csc", 0,
 			PLANE_PROP_CSC);
 	}
+	format_list = psde->pipe_sblk->format_list;
+	if (format_list) {
+		/* assume single thread */
+		struct sde_kms_info *info = &sde_info;
+
+		msm_property_install_blob(&psde->property_info, "sde_info",
+				DRM_MODE_PROP_IMMUTABLE,
+				PLANE_PROP_SDE_INFO);
+		sde_kms_info_reset(info);
+		sde_kms_info_start(info, "pixel_formats");
+		while (format_list->fourcc_format) {
+			sde_kms_info_append_format(info,
+					format_list->fourcc_format,
+					format_list->modifier);
+			++format_list;
+		}
+		sde_kms_info_stop(info);
+		msm_property_set_blob(&psde->property_info,
+				&psde->blob_sde_info,
+				SDE_KMS_INFO_DATA(info),
+				SDE_KMS_INFO_DATALEN(info),
+				PLANE_PROP_SDE_INFO);
+	}
 }
 
 static int sde_plane_atomic_set_property(struct drm_plane *plane,
@@ -1231,6 +1257,8 @@
 
 		debugfs_remove_recursive(psde->debugfs_root);
 
+		if (psde->blob_sde_info)
+			drm_property_unreference_blob(psde->blob_sde_info);
 		msm_property_destroy(&psde->property_info);
 		mutex_destroy(&psde->lock);
 
@@ -1478,12 +1506,16 @@
 	/* cache features mask for later */
 	psde->features = psde->pipe_hw->cap->features;
 	psde->pipe_sblk = psde->pipe_hw->cap->sblk;
+	if (!psde->pipe_sblk) {
+		SDE_ERROR("invalid sblk on pipe %d\n", pipe);
+		goto clean_sspp;
+	}
 
 	/* add plane to DRM framework */
-	psde->nformats = sde_populate_formats(psde->formats,
-		ARRAY_SIZE(psde->formats),
-		!(psde->features & BIT(SDE_SSPP_CSC)) ||
-		!(psde->features & SDE_SSPP_SCALER));
+	psde->nformats = sde_populate_formats(psde->pipe_sblk->format_list,
+			psde->formats,
+			0,
+			ARRAY_SIZE(psde->formats));
 
 	if (!psde->nformats) {
 		DRM_ERROR("[%u]No valid formats for plane\n", pipe);