drm/msm/sde: support more formats including compression

Add support for variants of RGBX, RGBA4444, RGBA5551, RGB565,
and the appropriate compressed variants.

Change-Id: I3fef703d094967d722472a20197d4ccbaa12bb6a
Signed-off-by: Lloyd Atkinson <latkinso@codeaurora.org>
diff --git a/drivers/gpu/drm/msm/sde/sde_formats.c b/drivers/gpu/drm/msm/sde/sde_formats.c
index 78d672e..25dac8c 100644
--- a/drivers/gpu/drm/msm/sde/sde_formats.c
+++ b/drivers/gpu/drm/msm/sde/sde_formats.c
@@ -10,136 +10,756 @@
  * GNU General Public License for more details.
  */
 
+#include <uapi/drm/drm_fourcc.h>
+
 #include "sde_kms.h"
 #include "sde_formats.h"
 
-static struct sde_format sde_format_map[] = {
+#define SDE_UBWC_META_MACRO_W_H		16
+#define SDE_UBWC_META_BLOCK_SIZE	256
+#define SDE_MAX_IMG_WIDTH		0x3FFF
+#define SDE_MAX_IMG_HEIGHT		0x3FFF
+
+/**
+ * SDE supported format packing, bpp, and other format
+ * information.
+ * SDE currently only supports interleaved RGB formats
+ * UBWC support for a pixel format is indicated by the flag,
+ * there is additional meta data plane for such formats
+ */
+
+#define INTERLEAVED_RGB_FMT(fmt, a, r, g, b, e0, e1, e2, e3, uc, alpha,   \
+bp, flg, fm, np)                                                          \
+{                                                                         \
+	.base.pixel_format = DRM_FORMAT_ ## fmt,                          \
+	.fetch_planes = SDE_PLANE_INTERLEAVED,                            \
+	.alpha_enable = alpha,                                            \
+	.element = { (e0), (e1), (e2), (e3) },                            \
+	.bits = { g, b, r, a },                                           \
+	.chroma_sample = SDE_CHROMA_RGB,                                  \
+	.unpack_align_msb = 0,                                            \
+	.unpack_tight = 1,                                                \
+	.unpack_count = uc,                                               \
+	.bpp = bp,                                                        \
+	.fetch_mode = fm,                                                 \
+	.flag = flg,                                                      \
+	.num_planes = np                                                  \
+}
+
+#define INTERLEAVED_YUV_FMT(fmt, a, r, g, b, e0, e1, e2, e3,              \
+alpha, chroma, count, bp, flg, fm, np)                                    \
+{                                                                         \
+	.base.pixel_format = DRM_FORMAT_ ## fmt,                          \
+	.fetch_planes = SDE_PLANE_INTERLEAVED,                            \
+	.alpha_enable = alpha,                                            \
+	.element = { (e0), (e1), (e2), (e3)},                             \
+	.bits = { g, b, r, a },                                           \
+	.chroma_sample = chroma,                                          \
+	.unpack_align_msb = 0,                                            \
+	.unpack_tight = 1,                                                \
+	.unpack_count = count,                                            \
+	.bpp = bp,                                                        \
+	.fetch_mode = fm,                                                 \
+	.flag = flg,                                                      \
+	.num_planes = np                                                  \
+}
+
+#define PSEDUO_YUV_FMT(fmt, a, r, g, b, e0, e1, chroma, flg, fm, np)      \
+{                                                                         \
+	.base.pixel_format = DRM_FORMAT_ ## fmt,                          \
+	.fetch_planes = SDE_PLANE_PSEUDO_PLANAR,                          \
+	.alpha_enable = false,                                            \
+	.element = { (e0), (e1), 0, 0 },                                  \
+	.bits = { g, b, r, a },                                           \
+	.chroma_sample = chroma,                                          \
+	.unpack_align_msb = 0,                                            \
+	.unpack_tight = 1,                                                \
+	.unpack_count = 2,                                                \
+	.bpp = 2,                                                         \
+	.fetch_mode = fm,                                                 \
+	.flag = flg,                                                      \
+	.num_planes = np                                                  \
+}
+
+#define PLANAR_YUV_FMT(fmt, a, r, g, b, e0, e1, e2, alpha, chroma, bp,    \
+flg, fm, np)                                                      \
+{                                                                         \
+	.base.pixel_format = DRM_FORMAT_ ## fmt,                          \
+	.fetch_planes = SDE_PLANE_PLANAR,                                 \
+	.alpha_enable = alpha,                                            \
+	.element = { (e0), (e1), (e2), 0 },                               \
+	.bits = { g, b, r, a },                                           \
+	.chroma_sample = chroma,                                          \
+	.unpack_align_msb = 0,                                            \
+	.unpack_tight = 1,                                                \
+	.unpack_count = 1,                                                \
+	.bpp = bp,                                                        \
+	.fetch_mode = fm,                                                 \
+	.flag = flg,                                                      \
+	.num_planes = np                                                  \
+}
+
+static const struct sde_format sde_format_map[] = {
 	INTERLEAVED_RGB_FMT(ARGB8888,
 		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
 		C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
-		true, 4, SDE_FORMAT_FLAG_ROTATOR),
+		true, 4, 0,
+		SDE_FETCH_LINEAR, 1),
 
 	INTERLEAVED_RGB_FMT(ABGR8888,
 		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
 		C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
-		true, 4, SDE_FORMAT_FLAG_ROTATOR),
+		true, 4, 0,
+		SDE_FETCH_LINEAR, 1),
 
 	INTERLEAVED_RGB_FMT(RGBA8888,
 		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
 		C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
-		true, 4, SDE_FORMAT_FLAG_ROTATOR),
+		true, 4, 0,
+		SDE_FETCH_LINEAR, 1),
 
 	INTERLEAVED_RGB_FMT(BGRA8888,
 		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
 		C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
-		true, 4, SDE_FORMAT_FLAG_ROTATOR),
+		true, 4, 0,
+		SDE_FETCH_LINEAR, 1),
 
 	INTERLEAVED_RGB_FMT(XRGB8888,
 		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
 		C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
-		false, 4, SDE_FORMAT_FLAG_ROTATOR),
+		false, 4, 0,
+		SDE_FETCH_LINEAR, 1),
+
+	INTERLEAVED_RGB_FMT(RGBX8888,
+		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
+		C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
+		false, 4, 0,
+		SDE_FETCH_LINEAR, 1),
 
 	INTERLEAVED_RGB_FMT(RGB888,
 		0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
 		C1_B_Cb, C0_G_Y, C2_R_Cr, 0, 3,
-		false, 3, SDE_FORMAT_FLAG_ROTATOR),
+		false, 3, 0,
+		SDE_FETCH_LINEAR, 1),
 
 	INTERLEAVED_RGB_FMT(BGR888,
 		0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
 		C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3,
-		false, 3, SDE_FORMAT_FLAG_ROTATOR),
+		false, 3, 0,
+		SDE_FETCH_LINEAR, 1),
 
 	INTERLEAVED_RGB_FMT(RGB565,
 		0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT,
 		C1_B_Cb, C0_G_Y, C2_R_Cr, 0, 3,
-		false, 2, SDE_FORMAT_FLAG_ROTATOR),
+		false, 2, 0,
+		SDE_FETCH_LINEAR, 1),
 
 	INTERLEAVED_RGB_FMT(BGR565,
 		0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT,
 		C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3,
-		false, 2, SDE_FORMAT_FLAG_ROTATOR),
+		false, 2, 0,
+		SDE_FETCH_LINEAR, 1),
+
+	INTERLEAVED_RGB_FMT(ARGB1555,
+		COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
+		C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
+		true, 2, 0,
+		SDE_FETCH_LINEAR, 1),
+
+	INTERLEAVED_RGB_FMT(ABGR1555,
+		COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
+		C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+		true, 2, 0,
+		SDE_FETCH_LINEAR, 1),
+
+	INTERLEAVED_RGB_FMT(RGBA5551,
+		COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
+		C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
+		true, 2, 0,
+		SDE_FETCH_LINEAR, 1),
+
+	INTERLEAVED_RGB_FMT(BGRA5551,
+		COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
+		C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
+		true, 2, 0,
+		SDE_FETCH_LINEAR, 1),
+
+	INTERLEAVED_RGB_FMT(XRGB1555,
+		COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
+		C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
+		false, 2, 0,
+		SDE_FETCH_LINEAR, 1),
+
+	INTERLEAVED_RGB_FMT(XBGR1555,
+		COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
+		C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+		false, 2, 0,
+		SDE_FETCH_LINEAR, 1),
+
+	INTERLEAVED_RGB_FMT(RGBX5551,
+		COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
+		C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
+		false, 2, 0,
+		SDE_FETCH_LINEAR, 1),
+
+	INTERLEAVED_RGB_FMT(BGRX5551,
+		COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
+		C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
+		false, 2, 0,
+		SDE_FETCH_LINEAR, 1),
+
+	INTERLEAVED_RGB_FMT(ARGB4444,
+		COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
+		C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
+		true, 2, 0,
+		SDE_FETCH_LINEAR, 1),
+
+	INTERLEAVED_RGB_FMT(ABGR4444,
+		COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
+		C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+		true, 2, 0,
+		SDE_FETCH_LINEAR, 1),
+
+	INTERLEAVED_RGB_FMT(RGBA4444,
+		COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
+		C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
+		true, 2, 0,
+		SDE_FETCH_LINEAR, 1),
+
+	INTERLEAVED_RGB_FMT(BGRA4444,
+		COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
+		C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
+		true, 2, 0,
+		SDE_FETCH_LINEAR, 1),
+
+	INTERLEAVED_RGB_FMT(XRGB4444,
+		COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
+		C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
+		false, 2, 0,
+		SDE_FETCH_LINEAR, 1),
+
+	INTERLEAVED_RGB_FMT(XBGR4444,
+		COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
+		C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+		false, 2, 0,
+		SDE_FETCH_LINEAR, 1),
+
+	INTERLEAVED_RGB_FMT(RGBX4444,
+		COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
+		C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
+		false, 2, 0,
+		SDE_FETCH_LINEAR, 1),
+
+	INTERLEAVED_RGB_FMT(BGRX4444,
+		COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
+		C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
+		false, 2, 0,
+		SDE_FETCH_LINEAR, 1),
 
 	PSEDUO_YUV_FMT(NV12,
 		0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
 		C1_B_Cb, C2_R_Cr,
-		SDE_CHROMA_420, SDE_FORMAT_FLAG_ROTATOR),
+		SDE_CHROMA_420, SDE_FORMAT_FLAG_YUV,
+		SDE_FETCH_LINEAR, 2),
 
 	PSEDUO_YUV_FMT(NV21,
 		0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
 		C2_R_Cr, C1_B_Cb,
-		SDE_CHROMA_420, SDE_FORMAT_FLAG_ROTATOR),
+		SDE_CHROMA_420, SDE_FORMAT_FLAG_YUV,
+		SDE_FETCH_LINEAR, 2),
 
 	PSEDUO_YUV_FMT(NV16,
 		0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
 		C1_B_Cb, C2_R_Cr,
-		SDE_CHROMA_H2V1, SDE_FORMAT_FLAG_ROTATOR),
+		SDE_CHROMA_H2V1, SDE_FORMAT_FLAG_YUV,
+		SDE_FETCH_LINEAR, 2),
 
 	PSEDUO_YUV_FMT(NV61,
 		0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
 		C2_R_Cr, C1_B_Cb,
-		SDE_CHROMA_H2V1, SDE_FORMAT_FLAG_ROTATOR),
+		SDE_CHROMA_H2V1, SDE_FORMAT_FLAG_YUV,
+		SDE_FETCH_LINEAR, 2),
 
 	INTERLEAVED_YUV_FMT(VYUY,
 		0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
 		C2_R_Cr, C0_G_Y, C1_B_Cb, C0_G_Y,
-		false, SDE_CHROMA_H2V1, 4, 2,
-		0),
+		false, SDE_CHROMA_H2V1, 4, 2, SDE_FORMAT_FLAG_YUV,
+		SDE_FETCH_LINEAR, 2),
 
 	INTERLEAVED_YUV_FMT(UYVY,
 		0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
 		C1_B_Cb, C0_G_Y, C2_R_Cr, C0_G_Y,
-		false, SDE_CHROMA_H2V1, 4, 2,
-		0),
+		false, SDE_CHROMA_H2V1, 4, 2, SDE_FORMAT_FLAG_YUV,
+		SDE_FETCH_LINEAR, 2),
 
 	INTERLEAVED_YUV_FMT(YUYV,
 		0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
 		C0_G_Y, C1_B_Cb, C0_G_Y, C2_R_Cr,
-		false, SDE_CHROMA_H2V1, 4, 2,
-		0),
+		false, SDE_CHROMA_H2V1, 4, 2, SDE_FORMAT_FLAG_YUV,
+		SDE_FETCH_LINEAR, 2),
 
 	INTERLEAVED_YUV_FMT(YVYU,
 		0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
 		C0_G_Y, C2_R_Cr, C0_G_Y, C1_B_Cb,
-		false, SDE_CHROMA_H2V1, 4, 2,
-		0),
+		false, SDE_CHROMA_H2V1, 4, 2, SDE_FORMAT_FLAG_YUV,
+		SDE_FETCH_LINEAR, 2),
 
 	PLANAR_YUV_FMT(YUV420,
 		0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
 		C2_R_Cr, C1_B_Cb, C0_G_Y,
-		false, SDE_CHROMA_420, 2,
-		SDE_FORMAT_FLAG_ROTATOR),
+		false, SDE_CHROMA_420, 1, SDE_FORMAT_FLAG_YUV,
+		SDE_FETCH_LINEAR, 3),
 
 	PLANAR_YUV_FMT(YVU420,
 		0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
 		C1_B_Cb, C2_R_Cr, C0_G_Y,
-		false, SDE_CHROMA_420, 2,
-		SDE_FORMAT_FLAG_ROTATOR),
+		false, SDE_CHROMA_420, 1, SDE_FORMAT_FLAG_YUV,
+		SDE_FETCH_LINEAR, 3),
 };
 
+/*
+ * UBWC formats table:
+ * This table holds the UBWC formats supported.
+ * If a compression ratio needs to be used for this or any other format,
+ * the data will be passed by user-space.
+ */
+static const struct sde_format sde_format_map_ubwc[] = {
+	INTERLEAVED_RGB_FMT(RGB565,
+		0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT,
+		C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3,
+		false, 2, 0,
+		SDE_FETCH_UBWC, 2),
+
+	INTERLEAVED_RGB_FMT(RGBA8888,
+		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
+		C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+		true, 4, 0,
+		SDE_FETCH_UBWC, 2),
+
+	INTERLEAVED_RGB_FMT(RGBX8888,
+		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
+		C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+		false, 4, 0,
+		SDE_FETCH_UBWC, 2),
+
+	PSEDUO_YUV_FMT(NV12,
+		0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
+		C1_B_Cb, C2_R_Cr,
+		SDE_CHROMA_420, SDE_FORMAT_FLAG_YUV,
+		SDE_FETCH_UBWC, 4),
+};
+
+/* _sde_get_v_h_subsample_rate - Get subsample rates for all formats we support
+ *   Note: Not using the drm_format_*_subsampling since we have formats
+ */
+static void _sde_get_v_h_subsample_rate(
+	enum sde_chroma_samp_type chroma_sample,
+	uint32_t *v_sample,
+	uint32_t *h_sample)
+{
+	switch (chroma_sample) {
+	case SDE_CHROMA_H2V1:
+		*v_sample = 1;
+		*h_sample = 2;
+		break;
+	case SDE_CHROMA_H1V2:
+		*v_sample = 2;
+		*h_sample = 1;
+		break;
+	case SDE_CHROMA_420:
+		*v_sample = 2;
+		*h_sample = 2;
+		break;
+	default:
+		*v_sample = 1;
+		*h_sample = 1;
+		break;
+	}
+}
+
+static int _sde_format_get_plane_sizes_ubwc(
+		const struct sde_format *fmt,
+		const uint32_t width,
+		const uint32_t height,
+		struct sde_hw_fmt_layout *layout)
+{
+	int i;
+
+	memset(layout, 0, sizeof(struct sde_hw_fmt_layout));
+	layout->format = fmt;
+	layout->width = width;
+	layout->height = height;
+	layout->num_planes = fmt->num_planes;
+
+	if (fmt->base.pixel_format == DRM_FORMAT_NV12) {
+		uint32_t y_stride_alignment, uv_stride_alignment;
+		uint32_t y_height_alignment, uv_height_alignment;
+		uint32_t y_tile_width = 32;
+		uint32_t y_tile_height = 8;
+		uint32_t uv_tile_width = y_tile_width / 2;
+		uint32_t uv_tile_height = y_tile_height;
+		uint32_t y_bpp_numer = 1, y_bpp_denom = 1;
+		uint32_t uv_bpp_numer = 1, uv_bpp_denom = 1;
+
+		y_stride_alignment = 128;
+		uv_stride_alignment = 64;
+		y_height_alignment = 32;
+		uv_height_alignment = 32;
+		y_bpp_numer = 1;
+		uv_bpp_numer = 2;
+		y_bpp_denom = 1;
+		uv_bpp_denom = 1;
+
+		layout->num_planes = 4;
+		/* Y bitstream stride and plane size */
+		layout->plane_pitch[0] = ALIGN(width, y_stride_alignment);
+		layout->plane_pitch[0] = (layout->plane_pitch[0] * y_bpp_numer)
+				/ y_bpp_denom;
+		layout->plane_size[0] = ALIGN(layout->plane_pitch[0] *
+				ALIGN(height, y_height_alignment), 4096);
+
+		/* CbCr bitstream stride and plane size */
+		layout->plane_pitch[1] = ALIGN(width / 2, uv_stride_alignment);
+		layout->plane_pitch[1] = (layout->plane_pitch[1] * uv_bpp_numer)
+				/ uv_bpp_denom;
+		layout->plane_size[1] = ALIGN(layout->plane_pitch[1] *
+			ALIGN(height / 2, uv_height_alignment), 4096);
+
+		/* Y meta data stride and plane size */
+		layout->plane_pitch[2] = ALIGN(
+				DIV_ROUND_UP(width, y_tile_width), 64);
+		layout->plane_size[2] = ALIGN(layout->plane_pitch[2] *
+			ALIGN(DIV_ROUND_UP(height, y_tile_height), 16), 4096);
+
+		/* CbCr meta data stride and plane size */
+		layout->plane_pitch[3] = ALIGN(
+				DIV_ROUND_UP(width / 2, uv_tile_width), 64);
+		layout->plane_size[3] = ALIGN(layout->plane_pitch[3] *
+			ALIGN(DIV_ROUND_UP(height / 2, uv_tile_height), 16),
+			4096);
+
+	} else if (fmt->base.pixel_format == DRM_FORMAT_RGBA8888 ||
+		fmt->base.pixel_format == DRM_FORMAT_RGBX8888    ||
+		fmt->base.pixel_format == DRM_FORMAT_RGB565) {
+		uint32_t stride_alignment, aligned_bitstream_width;
+
+		if (fmt->base.pixel_format == DRM_FORMAT_RGB565)
+			stride_alignment = 128;
+		else
+			stride_alignment = 64;
+		layout->num_planes = 3;
+
+		/* Nothing in plane[1] */
+
+		/* RGB bitstream stride and plane size */
+		aligned_bitstream_width = ALIGN(width, stride_alignment);
+		layout->plane_pitch[0] = aligned_bitstream_width * fmt->bpp;
+		layout->plane_size[0] = ALIGN(fmt->bpp * aligned_bitstream_width
+				* ALIGN(height, 16), 4096);
+
+		/* RGB meta data stride and plane size */
+		layout->plane_pitch[2] = ALIGN(DIV_ROUND_UP(
+				aligned_bitstream_width, 16), 64);
+		layout->plane_size[2] = ALIGN(layout->plane_pitch[2] *
+			ALIGN(DIV_ROUND_UP(height, 4), 16), 4096);
+	} else {
+		DRM_ERROR("UBWC format not supported for fmt:0x%X\n",
+			fmt->base.pixel_format);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < SDE_MAX_PLANES; i++)
+		layout->total_size += layout->plane_size[i];
+
+	return 0;
+}
+
+static int _sde_format_get_plane_sizes_linear(
+		const struct sde_format *fmt,
+		const uint32_t width,
+		const uint32_t height,
+		struct sde_hw_fmt_layout *layout)
+{
+	int i;
+
+	memset(layout, 0, sizeof(struct sde_hw_fmt_layout));
+	layout->format = fmt;
+	layout->width = width;
+	layout->height = height;
+	layout->num_planes = fmt->num_planes;
+
+	/* Due to memset above, only need to set planes of interest */
+	if (fmt->fetch_planes == SDE_PLANE_INTERLEAVED) {
+		layout->num_planes = 1;
+		layout->plane_size[0] = width * height * layout->format->bpp;
+		layout->plane_pitch[0] = width * layout->format->bpp;
+	} else {
+		uint32_t v_subsample, h_subsample;
+		uint32_t chroma_samp;
+
+		chroma_samp = fmt->chroma_sample;
+		_sde_get_v_h_subsample_rate(chroma_samp, &v_subsample,
+				&h_subsample);
+
+		if (width % h_subsample || height % v_subsample) {
+			DRM_ERROR("mismatch in subsample vs dimensions\n");
+			return -EINVAL;
+		}
+
+		layout->plane_pitch[0] = width;
+		layout->plane_pitch[1] = width / h_subsample;
+		layout->plane_size[0] = layout->plane_pitch[0] * height;
+		layout->plane_size[1] = layout->plane_pitch[1] *
+				(height / v_subsample);
+
+		if (fmt->fetch_planes == SDE_PLANE_PSEUDO_PLANAR) {
+			layout->num_planes = 2;
+			layout->plane_size[1] *= 2;
+			layout->plane_pitch[1] *= 2;
+		} else {
+			/* planar */
+			layout->num_planes = 3;
+			layout->plane_size[2] = layout->plane_size[1];
+			layout->plane_pitch[2] = layout->plane_pitch[1];
+		}
+	}
+
+	for (i = 0; i < SDE_MAX_PLANES; i++)
+		layout->total_size += layout->plane_size[i];
+
+	return 0;
+}
+
+static int _sde_format_get_plane_sizes(
+		const struct sde_format *fmt,
+		const uint32_t w,
+		const uint32_t h,
+		struct sde_hw_fmt_layout *layout)
+{
+	if (!layout || !fmt) {
+		DRM_ERROR("invalid pointer\n");
+		return -EINVAL;
+	}
+
+	if ((w > SDE_MAX_IMG_WIDTH) || (h > SDE_MAX_IMG_HEIGHT)) {
+		DRM_ERROR("image dimensions outside max range\n");
+		return -ERANGE;
+	}
+
+	if (SDE_FORMAT_IS_UBWC(fmt))
+		return _sde_format_get_plane_sizes_ubwc(fmt, w, h, layout);
+
+	return _sde_format_get_plane_sizes_linear(fmt, w, h, layout);
+}
+
+static int _sde_format_populate_addrs_ubwc(
+		int mmu_id,
+		struct drm_framebuffer *fb,
+		struct sde_hw_fmt_layout *layout)
+{
+	uint32_t base_addr;
+
+	if (!fb || !layout) {
+		DRM_ERROR("invalid pointers\n");
+		return -EINVAL;
+	}
+
+	base_addr = msm_framebuffer_iova(fb, mmu_id, 0);
+	if (!base_addr) {
+		DRM_ERROR("failed to retrieve base addr\n");
+		return -EFAULT;
+	}
+
+	/* Per-format logic for verifying active planes */
+	if (SDE_FORMAT_IS_YUV(layout->format)) {
+		/************************************************/
+		/*      UBWC            **                      */
+		/*      buffer          **      SDE PLANE       */
+		/*      format          **                      */
+		/************************************************/
+		/* -------------------  ** -------------------- */
+		/* |      Y meta     |  ** |    Y bitstream   | */
+		/* |       data      |  ** |       plane      | */
+		/* -------------------  ** -------------------- */
+		/* |    Y bitstream  |  ** |  CbCr bitstream  | */
+		/* |       data      |  ** |       plane      | */
+		/* -------------------  ** -------------------- */
+		/* |   Cbcr metadata |  ** |       Y meta     | */
+		/* |       data      |  ** |       plane      | */
+		/* -------------------  ** -------------------- */
+		/* |  CbCr bitstream |  ** |     CbCr meta    | */
+		/* |       data      |  ** |       plane      | */
+		/* -------------------  ** -------------------- */
+		/************************************************/
+
+		/* configure Y bitstream plane */
+		layout->plane_addr[0] = base_addr + layout->plane_size[2];
+
+		/* configure CbCr bitstream plane */
+		layout->plane_addr[1] = base_addr + layout->plane_size[0]
+			+ layout->plane_size[2] + layout->plane_size[3];
+
+		/* configure Y metadata plane */
+		layout->plane_addr[2] = base_addr;
+
+		/* configure CbCr metadata plane */
+		layout->plane_addr[3] = base_addr + layout->plane_size[0]
+			+ layout->plane_size[2];
+
+	} else {
+		/************************************************/
+		/*      UBWC            **                      */
+		/*      buffer          **      SDE PLANE       */
+		/*      format          **                      */
+		/************************************************/
+		/* -------------------  ** -------------------- */
+		/* |      RGB meta   |  ** |   RGB bitstream  | */
+		/* |       data      |  ** |       plane      | */
+		/* -------------------  ** -------------------- */
+		/* |  RGB bitstream  |  ** |       NONE       | */
+		/* |       data      |  ** |                  | */
+		/* -------------------  ** -------------------- */
+		/*                      ** |     RGB meta     | */
+		/*                      ** |       plane      | */
+		/*                      ** -------------------- */
+		/************************************************/
+
+		layout->plane_addr[0] = base_addr + layout->plane_size[2];
+		layout->plane_addr[1] = 0;
+		layout->plane_addr[2] = base_addr;
+		layout->plane_addr[3] = 0;
+	}
+
+	return 0;
+}
+
+static int _sde_format_populate_addrs_linear(
+		int mmu_id,
+		struct drm_framebuffer *fb,
+		struct sde_hw_fmt_layout *layout)
+{
+	unsigned int i;
+
+	/* Can now check the pitches given vs pitches expected */
+	for (i = 0; i < layout->num_planes; ++i) {
+		if (layout->plane_pitch[i] != fb->pitches[i]) {
+			DRM_ERROR("plane %u expected pitch %u, fb %u\n",
+				i, layout->plane_pitch[i], fb->pitches[i]);
+			return -EINVAL;
+		}
+	}
+
+	/* Populate addresses for simple formats here */
+	for (i = 0; i < layout->num_planes; ++i) {
+		layout->plane_addr[i] = msm_framebuffer_iova(fb, mmu_id, i);
+		if (!layout->plane_addr[i]) {
+			DRM_ERROR("failed to retrieve base addr\n");
+			return -EFAULT;
+		}
+	}
+
+	return 0;
+}
+
+int sde_format_populate_layout(
+		int mmu_id,
+		struct drm_framebuffer *fb,
+		struct sde_hw_fmt_layout *layout)
+{
+	int ret;
+
+	if (!fb || !layout) {
+		DRM_ERROR("invalid arguments\n");
+		return -EINVAL;
+	}
+
+	if ((fb->width > SDE_MAX_IMG_WIDTH) ||
+			(fb->height > SDE_MAX_IMG_HEIGHT)) {
+		DRM_ERROR("image dimensions outside max range\n");
+		return -ERANGE;
+	}
+
+	layout->format = to_sde_format(msm_framebuffer_format(fb));
+
+	/* Populate the plane sizes etc via get_format */
+	ret = _sde_format_get_plane_sizes(layout->format, fb->width, fb->height,
+			layout);
+	if (ret)
+		return ret;
+
+	/* Populate the addresses given the fb */
+	if (SDE_FORMAT_IS_UBWC(layout->format))
+		ret = _sde_format_populate_addrs_ubwc(mmu_id, fb, layout);
+	else
+		ret = _sde_format_populate_addrs_linear(mmu_id, fb, layout);
+
+	return ret;
+}
+
+int sde_format_check_modified_format(
+		const struct msm_kms *kms,
+		const struct msm_format *msm_fmt,
+		const struct drm_mode_fb_cmd2 *cmd,
+		struct drm_gem_object **bos)
+{
+	int ret, i, num_base_fmt_planes;
+	const struct sde_format *fmt;
+	struct sde_hw_fmt_layout layout;
+	uint32_t bos_total_size = 0;
+
+	if (!msm_fmt || !cmd || !bos) {
+		DRM_ERROR("invalid arguments\n");
+		return -EINVAL;
+	}
+
+	fmt = to_sde_format(msm_fmt);
+	num_base_fmt_planes = drm_format_num_planes(fmt->base.pixel_format);
+
+	ret = _sde_format_get_plane_sizes(fmt, cmd->width, cmd->height,
+			&layout);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < num_base_fmt_planes; i++) {
+		if (!bos[i]) {
+			DRM_ERROR("invalid handle for plane %d\n", i);
+			return -EINVAL;
+		}
+		bos_total_size += bos[i]->size;
+	}
+
+	if (bos_total_size < layout.total_size) {
+		DRM_ERROR("buffers total size too small %u expected %u\n",
+				bos_total_size, layout.total_size);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 const struct sde_format *sde_get_sde_format_ext(
 		const uint32_t format,
 		const uint64_t *modifiers,
 		const uint32_t modifiers_len)
 {
-	u32 i = 0;
-	uint64_t modifier = 0;
-	struct sde_format *fmt = NULL;
+	uint32_t i = 0;
+	uint64_t mod0 = 0;
+	const struct sde_format *fmt = NULL;
+	const struct sde_format *map = NULL;
+	ssize_t map_size = 0;
 
 	/*
-	 * Currently only support exactly zero or one modifier, and it must be
-	 * identical for all planes
+	 * Currently only support exactly zero or one modifier.
+	 * All planes used must specify the same modifier.
 	 */
-	if ((modifiers_len && !modifiers) || (!modifiers_len && modifiers)) {
-		DRM_ERROR("unexpected modifiers array or len\n");
+	if (modifiers_len && !modifiers) {
+		DRM_ERROR("invalid modifiers array\n");
 		return NULL;
-	} else if (modifiers && modifiers_len) {
-		modifier = modifiers[0];
-		for (i = 0; i < modifiers_len; i++) {
-			if (modifiers[i])
-				DBG("plane %d format modifier 0x%llX", i,
-					modifiers[i]);
-
-			if (modifiers[i] != modifier) {
+	} else if (modifiers && modifiers_len && modifiers[0]) {
+		mod0 = modifiers[0];
+		DBG("plane format modifier 0x%llX", mod0);
+		for (i = 1; i < modifiers_len; i++) {
+			if (modifiers[i] != mod0) {
 				DRM_ERROR("bad fmt mod 0x%llX on plane %d\n",
 					modifiers[i], i);
 				return NULL;
@@ -147,17 +767,36 @@
 		}
 	}
 
-	for (i = 0; i < ARRAY_SIZE(sde_format_map); i++)
-		if (format == sde_format_map[i].base.pixel_format) {
-			fmt = &sde_format_map[i];
+	switch (mod0) {
+	case 0:
+		map = sde_format_map;
+		map_size = ARRAY_SIZE(sde_format_map);
+		break;
+	case DRM_FORMAT_MOD_QCOM_COMPRESSED:
+		map = sde_format_map_ubwc;
+		map_size = ARRAY_SIZE(sde_format_map_ubwc);
+		DBG("found fmt 0x%X DRM_FORMAT_MOD_QCOM_COMPRESSED", format);
+		break;
+	default:
+		DRM_ERROR("unsupported format modifier %llX\n", mod0);
+		return NULL;
+	}
+
+	for (i = 0; i < map_size; i++) {
+		if (format == map[i].base.pixel_format) {
+			fmt = &map[i];
 			break;
 		}
+	}
 
 	if (fmt == NULL)
 		DRM_ERROR("unsupported fmt 0x%X modifier 0x%llX\n",
-				format, modifier);
+				format, mod0);
 	else
-		DBG("found fmt 0x%X modifier 0x%llX", format, modifier);
+		DBG("fmt %s mod 0x%llX ubwc %d yuv %d",
+				drm_get_format_name(format), mod0,
+				SDE_FORMAT_IS_UBWC(fmt),
+				SDE_FORMAT_IS_YUV(fmt));
 
 	return fmt;
 }
diff --git a/drivers/gpu/drm/msm/sde/sde_formats.h b/drivers/gpu/drm/msm/sde/sde_formats.h
index 545633b..3400b14 100644
--- a/drivers/gpu/drm/msm/sde/sde_formats.h
+++ b/drivers/gpu/drm/msm/sde/sde_formats.h
@@ -16,93 +16,8 @@
 #include <drm/drm_fourcc.h>
 #include "sde_hw_mdss.h"
 
-#define SDE_FORMAT_FLAG_ROTATOR BIT(0)
-#define SDE_FORMAT_FLAG_UBWC    BIT(1)
-
-#define SDE_FORMAT_IS_YUV(X)        ((X)->is_yuv)
-#define SDE_FORMAT_IS_ROTATOR(X)    ((X)->flag & SDE_FORMAT_FLAG_ROTATOR)
-#define SDE_FORMAT_IS_UBWC(X)       ((X)->flag & SDE_FORMAT_FLAG_UBWC)
-
 /**
- * SDE supported format packing, bpp, and other format
- * information.
- * SDE currently only supports interleaved RGB formats
- * UBWC support for a pixel format is indicated by the flag,
- * there is additional meta data plane for such formats
- */
-
-#define INTERLEAVED_RGB_FMT(fmt, a, r, g, b, e0, e1, e2, e3, uc, alpha,   \
-bp, flg)                                                                  \
-{                                                                         \
-	.base.pixel_format = DRM_FORMAT_ ## fmt,                          \
-	.fetch_planes = SDE_PLANE_INTERLEAVED,                            \
-	.alpha_enable = alpha,                                            \
-	.element = { (e0), (e1), (e2), (e3) },                            \
-	.bits = { g, b, r, a },                                           \
-	.chroma_sample = SDE_CHROMA_RGB,                                  \
-	.unpack_align_msb = 0,                                            \
-	.unpack_tight = 1,                                                \
-	.unpack_count = uc,                                               \
-	.bpp = bp,                                                        \
-	.fetch_mode = SDE_FETCH_LINEAR,                                   \
-	.is_yuv = false,                                                  \
-	.flag = flg                                                       \
-}
-
-#define INTERLEAVED_YUV_FMT(fmt, a, r, g, b, e0, e1, e2, e3,              \
-alpha, chroma, count, bp, flg)                                            \
-{                                                                         \
-	.base.pixel_format = DRM_FORMAT_ ## fmt,                          \
-	.fetch_planes = SDE_PLANE_INTERLEAVED,                            \
-	.alpha_enable = alpha,                                            \
-	.element = { (e0), (e1), (e2), (e3)},                             \
-	.bits = { g, b, r, a },                                           \
-	.chroma_sample = chroma,                                          \
-	.unpack_align_msb = 0,                                            \
-	.unpack_tight = 1,                                                \
-	.unpack_count = count,                                            \
-	.bpp = bp,                                                        \
-	.fetch_mode = SDE_FETCH_LINEAR,                                   \
-	.is_yuv = true,                                                   \
-	.flag = flg                                                       \
-}
-
-#define PSEDUO_YUV_FMT(fmt, a, r, g, b, e0, e1, chroma, flg)              \
-{                                                                         \
-	.base.pixel_format = DRM_FORMAT_ ## fmt,                          \
-	.fetch_planes = SDE_PLANE_PSEUDO_PLANAR,                          \
-	.alpha_enable = false,                                            \
-	.element = { (e0), (e1), 0, 0 },                                  \
-	.bits = { g, b, r, a },                                           \
-	.chroma_sample = chroma,                                          \
-	.unpack_align_msb = 0,                                            \
-	.unpack_tight = 1,                                                \
-	.unpack_count = 2,                                                \
-	.bpp = 2,                                                         \
-	.fetch_mode = SDE_FETCH_LINEAR,                                   \
-	.is_yuv = true,                                                   \
-	.flag = flg                                                       \
-}
-
-#define PLANAR_YUV_FMT(fmt, a, r, g, b, e0, e1, e2, alpha, chroma, bp, flg)\
-{                                                                         \
-	.base.pixel_format = DRM_FORMAT_ ## fmt,                          \
-	.fetch_planes = SDE_PLANE_INTERLEAVED,                            \
-	.alpha_enable = alpha,                                            \
-	.element = { (e0), (e1), (e2), 0 },                               \
-	.bits = { g, b, r, a },                                           \
-	.chroma_sample = chroma,                                          \
-	.unpack_align_msb = 0,                                            \
-	.unpack_tight = 1,                                                \
-	.unpack_count = 0,                                                \
-	.bpp = bp,                                                        \
-	.fetch_mode = SDE_FETCH_LINEAR,                                   \
-	.is_yuv = true,                                                   \
-	.flag = flg                                                       \
-}
-
-/**
- * sde_get_sde_format_ext(): Returns sde format structure pointer.
+ * sde_get_sde_format_ext() - Returns sde format structure pointer.
  * @format:          DRM FourCC Code
  * @modifiers:       format modifier array from client, one per plane
  * @modifiers_len:   number of planes and array size for plane_modifiers
@@ -115,7 +30,7 @@
 #define sde_get_sde_format(f) sde_get_sde_format_ext(f, NULL, 0)
 
 /**
- * sde_get_msm_format: get an sde_format by its msm_format base
+ * sde_get_msm_format - get an sde_format by its msm_format base
  *                     callback function registers with the msm_kms layer
  * @kms:             kms driver
  * @format:          DRM FourCC Code
@@ -129,7 +44,7 @@
 		const uint32_t modifiers_len);
 
 /**
- * sde_populate_formats: populate the given array with fourcc codes supported
+ * 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
@@ -141,4 +56,34 @@
 		uint32_t max_formats,
 		bool rgb_only);
 
+/**
+ * sde_format_check_modified_format - validate format and buffers for
+ *                   sde non-standard, i.e. modified format
+ * @kms:             kms driver
+ * @msm_fmt:         pointer to the msm_fmt base pointer of an sde_format
+ * @cmd:             fb_cmd2 structure user request
+ * @bos:             gem buffer object list
+ *
+ * Return: error code on failure, 0 on success
+ */
+int sde_format_check_modified_format(
+		const struct msm_kms *kms,
+		const struct msm_format *msm_fmt,
+		const struct drm_mode_fb_cmd2 *cmd,
+		struct drm_gem_object **bos);
+
+/**
+ * sde_format_populate_layout - populate the given format layout based on
+ *                     mmu, fb, and format found in the fb
+ * @mmu_id:            mmu id handle
+ * @fb:                framebuffer pointer
+ * @fmtl:              format layout structure to populate
+ *
+ * Return: error code on failure, 0 on success
+ */
+int sde_format_populate_layout(
+		int mmu_id,
+		struct drm_framebuffer *fb,
+		struct sde_hw_fmt_layout *fmtl);
+
 #endif /*_SDE_FORMATS_H */
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_cdm.c b/drivers/gpu/drm/msm/sde/sde_hw_cdm.c
index 77cddba..c6ec854 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_cdm.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_cdm.c
@@ -223,7 +223,7 @@
 	u32 cdm_enable = 0;
 	u32 csc = 0;
 
-	if (!fmt->is_yuv)
+	if (!SDE_FORMAT_IS_YUV(fmt))
 		return 0;
 
 	if (cdm->output_type == CDM_CDWN_OUTPUT_HDMI) {
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_intf.c b/drivers/gpu/drm/msm/sde/sde_hw_intf.c
index fca3d792..d4c8a44 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_intf.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_intf.c
@@ -159,7 +159,7 @@
 		(vsync_polarity << 1) | /* VSYNC Polarity */
 		(hsync_polarity << 0);  /* HSYNC Polarity */
 
-	if (!fmt->is_yuv)
+	if (!SDE_FORMAT_IS_YUV(fmt))
 		panel_format = (fmt->bits[C0_G_Y] |
 				(fmt->bits[C1_B_Cb] << 2) |
 				(fmt->bits[C2_R_Cr] << 4) |
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_mdss.h b/drivers/gpu/drm/msm/sde/sde_hw_mdss.h
index d696cb8..9d2fea7 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_mdss.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_mdss.h
@@ -38,6 +38,13 @@
 
 #define PIPES_PER_STAGE			2
 
+#define SDE_FORMAT_FLAG_YUV		(1 << 0)
+#define SDE_FORMAT_FLAG_ROTATOR		(1 << 1)
+
+#define SDE_FORMAT_IS_YUV(X)		((X)->flag & SDE_FORMAT_FLAG_YUV)
+#define SDE_FORMAT_IS_ROTATOR(X)	((X)->flag & SDE_FORMAT_FLAG_ROTATOR)
+#define SDE_FORMAT_IS_UBWC(X)		((X)->fetch_mode == SDE_FETCH_UBWC)
+
 enum sde_mdp {
 	MDP_TOP = 0x1,
 	MDP_MAX,
@@ -223,11 +230,10 @@
 };
 
 /**
- * enum sde_fetch_type - format id, used by drm-driver only to map drm forcc
- * Defines How HW fetches data
- * @SDE_FETCH_LINEAR   : Fetch is line by line
- * @SDE_FETCH_TILE     : Fetches data in Z order from a tile
- * @SDE_FETCH_UBWC     : Fetch and decompress data
+ * sde_fetch_type - Defines How SDE HW fetches data
+ * @SDE_FETCH_LINEAR   : fetch is line by line
+ * @SDE_FETCH_TILE     : fetches data in Z order from a tile
+ * @SDE_FETCH_UBWC     : fetch and decompress data
  */
 enum sde_fetch_type {
 	SDE_FETCH_LINEAR,
@@ -240,10 +246,12 @@
  * expected by the HW programming.
  */
 enum {
-	COLOR_1BIT = 0,
-	COLOR_5BIT = 1,
-	COLOR_6BIT = 2,
-	COLOR_8BIT = 3,
+	COLOR_ALPHA_1BIT = 0,
+	COLOR_ALPHA_4BIT = 1,
+	COLOR_4BIT = 0,
+	COLOR_5BIT = 1, /* No 5-bit Alpha */
+	COLOR_6BIT = 2, /* 6-Bit Alpha also = 2 */
+	COLOR_8BIT = 3, /* 8-Bit Alpha also = 3 */
 };
 
 enum sde_alpha_blend_type {
@@ -254,7 +262,6 @@
 	ALPHA_MAX
 };
 
-
 /**
  * enum sde_3d_blend_mode
  * Desribes how the 3d data is blended
@@ -274,26 +281,24 @@
 	BLEND_3D_MAX
 };
 
-struct addr_info {
-	u32 plane[SDE_MAX_PLANES];
-};
-
-/**
- * struct sde_format - defines the format configuration which
+/** struct sde_format - defines the format configuration which
  * allows SDE HW to correctly fetch and decode the format
- * @base             : Base msm_format structure containing fourcc code
- * @fetch_planes
- * @element
- * @bits
- * @chroma_sample
- * @unpack_align_msb
- * @unpack_tight
- * @unpack_count
- * @bpp
- * @alpha_enable
- * @fetch_mode
- * @is_yuv
- * @flag
+ * @base: base msm_format struture containing fourcc code
+ * @fetch_planes: how the color components are packed in pixel format
+ * @element: element color ordering
+ * @bits: element bit widths
+ * @chroma_sample: chroma sub-samplng type
+ * @unpack_align_msb: unpack aligned, 0 to LSB, 1 to MSB
+ * @unpack_tight: 0 for loose, 1 for tight
+ * @unpack_count: 0 = 1 component, 1 = 2 component
+ * @bpp: bytes per pixel
+ * @alpha_enable: whether the format has an alpha channel
+ * @num_planes: number of planes (including meta data planes)
+ * @fetch_mode: linear, tiled, or ubwc hw fetch behavior
+ * @is_yuv: is format a yuv variant
+ * @flag: usage bit flags
+ * @tile_width: format tile width
+ * @tile_height: format tile height
  */
 struct sde_format {
 	struct msm_format base;
@@ -301,30 +306,39 @@
 	u8 element[SDE_MAX_PLANES];
 	u8 bits[SDE_MAX_PLANES];
 	enum sde_chroma_samp_type chroma_sample;
-	u8 unpack_align_msb;	/* 0 to LSB, 1 to MSB */
-	u8 unpack_tight;	/* 0 for loose, 1 for tight */
-	u8 unpack_count;	/* 0 = 1 component, 1 = 2 component ... */
-	u8 bpp;                 /* Bytes per pixel */
-	u8 alpha_enable;	/*  source has alpha */
+	u8 unpack_align_msb;
+	u8 unpack_tight;
+	u8 unpack_count;
+	u8 bpp;
+	u8 alpha_enable;
+	u8 num_planes;
 	enum sde_fetch_type fetch_mode;
-	u8 is_yuv;
 	u32 flag;
+	u16 tile_width;
+	u16 tile_height;
 };
 #define to_sde_format(x) container_of(x, struct sde_format, base)
 
 /**
- * struct sde_hw_source_info - format information of the source pixel data
- * @format : pixel format parameters
- * @width : image width @height: image height
- * @num_planes : number of planes including the meta data planes for the
- * compressed formats @plane: per plane information
+ * struct sde_hw_fmt_layout - format information of the source pixel data
+ * @format: pixel format parameters
+ * @num_planes: number of planes (including meta data planes)
+ * @width: image width
+ * @height: image height
+ * @total_size: total size in bytes
+ * @plane_addr: address of each plane
+ * @plane_size: length of each plane
+ * @plane_pitch: pitch of each plane
  */
-struct sde_hw_source_info {
+struct sde_hw_fmt_layout {
 	const struct sde_format *format;
-	u32 width;
-	u32 height;
-	u32 num_planes;
-	u32 ystride[SDE_MAX_PLANES];
+	uint32_t num_planes;
+	uint32_t width;
+	uint32_t height;
+	uint32_t total_size;
+	uint32_t plane_addr[SDE_MAX_PLANES];
+	uint32_t plane_size[SDE_MAX_PLANES];
+	uint32_t plane_pitch[SDE_MAX_PLANES];
 };
 
 struct sde_rect {
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_sspp.c b/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
index 94539ce..400a553 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
@@ -194,8 +194,7 @@
 	if (flags & SDE_SSPP_ROT_90)
 		src_format |= BIT(11); /* ROT90 */
 
-	if (fmt->alpha_enable &&
-			fmt->fetch_planes != SDE_PLANE_INTERLEAVED)
+	if (fmt->alpha_enable && fmt->fetch_planes == SDE_PLANE_INTERLEAVED)
 		src_format |= BIT(8); /* SRCC3_EN */
 
 	if (flags & SDE_SSPP_SOLID_FILL)
@@ -220,12 +219,12 @@
 	opmode |= MDSS_MDP_OP_PE_OVERRIDE;
 
 	/* if this is YUV pixel format, enable CSC */
-	if (fmt->is_yuv)
+	if (SDE_FORMAT_IS_YUV(fmt))
 		src_format |= BIT(15);
 
 	/* update scaler opmode, if appropriate */
 	_sspp_setup_opmode(ctx,
-		VIG_OP_CSC_EN | VIG_OP_CSC_SRC_DATAFMT, fmt->is_yuv);
+		VIG_OP_CSC_EN | VIG_OP_CSC_SRC_DATAFMT, SDE_FORMAT_IS_YUV(fmt));
 
 	SDE_REG_WRITE(c, SSPP_SRC_FORMAT + idx, src_format);
 	SDE_REG_WRITE(c, SSPP_SRC_UNPACK_PATTERN + idx, unpack);
@@ -375,10 +374,10 @@
 	dst_xy = (cfg->dst_rect.y << 16) | (cfg->dst_rect.x);
 	dst_size = (cfg->dst_rect.h << 16) | (cfg->dst_rect.w);
 
-	ystride0 =  (cfg->src.ystride[0]) |
-		(cfg->src.ystride[1] << 16);
-	ystride1 =  (cfg->src.ystride[2]) |
-		(cfg->src.ystride[3] << 16);
+	ystride0 = (cfg->layout.plane_pitch[0]) |
+			(cfg->layout.plane_pitch[1] << 16);
+	ystride1 = (cfg->layout.plane_pitch[2]) |
+			(cfg->layout.plane_pitch[3] << 16);
 
 	/* program scaler, phase registers, if pipes supporting scaling */
 	if (ctx->cap->features & SDE_SSPP_SCALER) {
@@ -409,9 +408,9 @@
 	if (_sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx))
 		return;
 
-	for (i = 0; i < cfg->src.num_planes; i++)
-		SDE_REG_WRITE(&ctx->hw, SSPP_SRC0_ADDR  + idx + i*0x4,
-			cfg->addr.plane[i]);
+	for (i = 0; i < ARRAY_SIZE(cfg->layout.plane_addr); i++)
+		SDE_REG_WRITE(&ctx->hw, SSPP_SRC0_ADDR + idx + i * 0x4,
+			cfg->layout.plane_addr[i]);
 }
 
 static void sde_hw_sspp_setup_csc(struct sde_hw_pipe *ctx,
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_sspp.h b/drivers/gpu/drm/msm/sde/sde_hw_sspp.h
index ab7ed86..7eb4981 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_sspp.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_sspp.h
@@ -125,7 +125,7 @@
 
 /**
  * struct sde_hw_pipe_cfg : Pipe description
- * @src:       source surface information
+ * @layout:    format layout information for programming buffer to hardware
  * @src_rect:  src ROI, caller takes into account the different operations
  *             such as decimation, flip etc to program this field
  * @dest_rect: destination ROI.
@@ -135,15 +135,13 @@
  *              4: Read 1 line/pixel drop 3  lines/pixels
  *              8: Read 1 line/pixel drop 7 lines/pixels
  *              16: Read 1 line/pixel drop 15 line/pixels
- * @addr:      source surface address
  */
 struct sde_hw_pipe_cfg {
-	struct sde_hw_source_info src;
+	struct sde_hw_fmt_layout layout;
 	struct sde_rect src_rect;
 	struct sde_rect dst_rect;
 	u8 horz_decimation;
 	u8 vert_decimation;
-	struct addr_info addr;
 };
 
 /**
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_wb.h b/drivers/gpu/drm/msm/sde/sde_hw_wb.h
index b5a12eb..093d2fb 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_wb.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_wb.h
@@ -20,7 +20,7 @@
 struct sde_hw_wb;
 
 struct sde_hw_wb_cfg {
-	struct sde_hw_source_info dest;
+	struct sde_hw_fmt_layout dest;
 };
 
 /**
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c
index 22d87f3..38afae4 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms.c
@@ -318,6 +318,7 @@
 	.wait_for_crtc_commit_done = sde_wait_for_crtc_commit_done,
 	.enable_vblank   = sde_enable_vblank,
 	.disable_vblank  = sde_disable_vblank,
+	.check_modified_format = sde_format_check_modified_format,
 	.get_format      = sde_get_msm_format,
 	.round_pixclk    = sde_round_pixclk,
 	.preclose        = sde_preclose,
@@ -627,6 +628,11 @@
 	dev->mode_config.max_width =  catalog->mixer[0].sblk->maxwidth;
 	dev->mode_config.max_height = 4096;
 
+	/*
+	 * Support format modifiers for compression etc.
+	 */
+	dev->mode_config.allow_fb_modifiers = true;
+
 	sde_kms->hw_intr = sde_rm_acquire_intr(sde_kms);
 
 	if (IS_ERR_OR_NULL(sde_kms->hw_intr))
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index a7c38bf..0f8a8e1 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -43,7 +43,7 @@
 	enum sde_sspp pipe;
 	uint32_t features;      /* capabilities from catalog */
 	uint32_t nformats;
-	uint32_t formats[32];
+	uint32_t formats[64];
 
 	struct sde_hw_pipe *pipe_hw;
 	struct sde_hw_pipe_cfg pipe_cfg;
@@ -135,39 +135,30 @@
 
 static void _sde_plane_set_scanout(struct drm_plane *plane,
 		struct sde_plane_state *pstate,
-		struct sde_hw_pipe_cfg *pipe_cfg, struct drm_framebuffer *fb)
+		struct sde_hw_pipe_cfg *pipe_cfg,
+		struct drm_framebuffer *fb)
 {
 	struct sde_plane *psde;
-	unsigned int shift;
-	int i;
+	int ret, i;
 
 	if (!plane || !pstate || !pipe_cfg || !fb)
 		return;
 
 	psde = to_sde_plane(plane);
 
-	if (psde->pipe_hw && psde->pipe_hw->ops.setup_sourceaddress) {
-		/* stride */
-		if (sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG) &
-				BIT(SDE_DRM_DEINTERLACE))
-			shift = 1;
-		else
-			shift = 0;
-
-		i = min_t(int, ARRAY_SIZE(fb->pitches), SDE_MAX_PLANES);
-		while (i) {
-			--i;
-			pipe_cfg->src.ystride[i] = fb->pitches[i] << shift;
-		}
-
-		/* address */
-		for (i = 0; i < ARRAY_SIZE(pipe_cfg->addr.plane); ++i)
-			pipe_cfg->addr.plane[i] = msm_framebuffer_iova(fb,
-					psde->mmu_id, i);
-
-		/* hw driver */
-		psde->pipe_hw->ops.setup_sourceaddress(psde->pipe_hw, pipe_cfg);
+	ret = sde_format_populate_layout(psde->mmu_id, fb, &pipe_cfg->layout);
+	if (ret) {
+		DRM_ERROR("failed to get format layout, error: %d\n", ret);
+		return;
 	}
+
+	if (sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG) &
+			BIT(SDE_DRM_DEINTERLACE))
+		for (i = 0; i < SDE_MAX_PLANES; ++i)
+			pipe_cfg->layout.plane_pitch[i] <<= 1;
+
+	if (psde->pipe_hw && psde->pipe_hw->ops.setup_sourceaddress)
+		psde->pipe_hw->ops.setup_sourceaddress(psde->pipe_hw, pipe_cfg);
 }
 
 static void _sde_plane_setup_scaler3(struct sde_plane *psde,
@@ -712,9 +703,9 @@
 
 	psde = to_sde_plane(plane);
 	pstate = to_sde_plane_state(plane->state);
-	nplanes = drm_format_num_planes(fb->pixel_format);
 
 	fmt = to_sde_format(msm_framebuffer_format(fb));
+	nplanes = fmt->num_planes;
 
 	/* src values are in Q16 fixed point, convert to integer */
 	src_x = src_x >> 16;
@@ -722,19 +713,17 @@
 	src_w = src_w >> 16;
 	src_h = src_h >> 16;
 
-	DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u", psde->pipe_name,
+	DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u, %s ubwc %d",
+			psde->pipe_name,
 			fb->base.id, src_x, src_y, src_w, src_h,
-			crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h);
+			crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h,
+			drm_get_format_name(fmt->base.pixel_format),
+			SDE_FORMAT_IS_UBWC(fmt));
 
 	/* update format configuration */
 	memset(&(psde->pipe_cfg), 0, sizeof(struct sde_hw_pipe_cfg));
 	src_flags = 0;
 
-	psde->pipe_cfg.src.format = fmt;
-	psde->pipe_cfg.src.width = fb->width;
-	psde->pipe_cfg.src.height = fb->height;
-	psde->pipe_cfg.src.num_planes = nplanes;
-
 	/* flags */
 	DBG("Flags 0x%llX, rotation 0x%llX",
 			sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG),
@@ -762,9 +751,6 @@
 	psde->pipe_cfg.dst_rect.w = crtc_w;
 	psde->pipe_cfg.dst_rect.h = crtc_h;
 
-	/* get sde pixel format definition */
-	fmt = psde->pipe_cfg.src.format;
-
 	/* check for color fill */
 	psde->color_fill = (uint32_t)sde_plane_get_property(pstate,
 			PLANE_PROP_COLOR_FILL);
@@ -835,6 +821,42 @@
 	return 0;
 }
 
+static void _sde_plane_atomic_check_mode_changed(struct sde_plane *psde,
+		struct drm_plane_state *state,
+		struct drm_plane_state *old_state)
+{
+	struct sde_plane_state *pstate = to_sde_plane_state(state);
+
+	if (!(sde_plane_enabled(state) && sde_plane_enabled(old_state))) {
+		DBG("%s: pipe enabling/disabling full modeset required",
+			psde->pipe_name);
+		pstate->mode_changed = true;
+	} else if (to_sde_plane_state(old_state)->pending) {
+		DBG("%s: still pending", psde->pipe_name);
+		pstate->mode_changed = true;
+	} else if (state->src_w != old_state->src_w ||
+			state->src_h != old_state->src_h) {
+		DBG("%s: src_w change", psde->pipe_name);
+		pstate->mode_changed = true;
+	} else if (state->fb->pixel_format != old_state->fb->pixel_format) {
+		DBG("%s: format change!", psde->pipe_name);
+		pstate->mode_changed = true;
+	} else {
+		uint64_t *new_mods = state->fb->modifier;
+		uint64_t *old_mods = old_state->fb->modifier;
+		int i;
+
+		for (i = 0; i < ARRAY_SIZE(state->fb->modifier); i++) {
+			if (new_mods[i] != old_mods[i]) {
+				DBG("%s: format modifiers change",
+					psde->pipe_name);
+				pstate->mode_changed = true;
+				break;
+			}
+		}
+	}
+}
+
 static int sde_plane_atomic_check(struct drm_plane *plane,
 		struct drm_plane_state *state)
 {
@@ -994,32 +1016,8 @@
 		}
 	}
 
-	if (!ret) {
-		if (sde_plane_enabled(state) &&
-			sde_plane_enabled(old_state)) {
-			bool full_modeset = false;
-
-			if (state->fb->pixel_format !=
-				old_state->fb->pixel_format) {
-				DBG("%s: format change!", psde->pipe_name);
-				full_modeset = true;
-			}
-			if (state->src_w != old_state->src_w ||
-				state->src_h != old_state->src_h) {
-				DBG("%s: src_w change!", psde->pipe_name);
-				full_modeset = true;
-			}
-			if (to_sde_plane_state(old_state)->pending) {
-				DBG("%s: still pending!", psde->pipe_name);
-				full_modeset = true;
-			}
-			if (full_modeset)
-				to_sde_plane_state(state)->mode_changed = true;
-
-		} else {
-			to_sde_plane_state(state)->mode_changed = true;
-		}
-	}
+	if (!ret)
+		_sde_plane_atomic_check_mode_changed(psde, state, old_state);
 
 exit:
 	return ret;