drm/msm/sde: add p010 format support in sde

Add MOD_QCOM_DX modifier on top of DRM_FORMAT_NV12
base format and update plane size calculation to support
linear and compressed p010 buffers.

Change-Id: I93bd9557e5c4a4a038891f24730edbbec1dba262
Signed-off-by: Alexander Beykun <abeykun@codeaurora.org>
diff --git a/drivers/gpu/drm/msm/sde/sde_formats.c b/drivers/gpu/drm/msm/sde/sde_formats.c
index 41180f5..31d31f2 100644
--- a/drivers/gpu/drm/msm/sde/sde_formats.c
+++ b/drivers/gpu/drm/msm/sde/sde_formats.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -11,12 +11,15 @@
  */
 
 #include <uapi/drm/drm_fourcc.h>
+#include <uapi/media/msm_media_info.h>
 
 #include "sde_kms.h"
 #include "sde_formats.h"
 
 #define SDE_UBWC_META_MACRO_W_H		16
 #define SDE_UBWC_META_BLOCK_SIZE	256
+#define SDE_UBWC_PLANE_SIZE_ALIGNMENT	4096
+
 #define SDE_MAX_IMG_WIDTH		0x3FFF
 #define SDE_MAX_IMG_HEIGHT		0x3FFF
 
@@ -81,6 +84,23 @@
 	.num_planes = np                                                  \
 }
 
+#define PSEUDO_YUV_FMT_LOOSE(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 = 1,                                            \
+	.unpack_tight = 0,                                                \
+	.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)                                                      \
 {                                                                         \
@@ -99,6 +119,16 @@
 	.num_planes = np                                                  \
 }
 
+/*
+ * struct sde_media_color_map - maps drm format to media format
+ * @format: DRM base pixel format
+ * @color: Media API color related to DRM format
+ */
+struct sde_media_color_map {
+	uint32_t format;
+	uint32_t color;
+};
+
 static const struct sde_format sde_format_map[] = {
 	INTERLEAVED_RGB_FMT(ARGB8888,
 		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
@@ -421,6 +451,22 @@
 		SDE_FETCH_UBWC, 4),
 };
 
+static const struct sde_format sde_format_map_p010[] = {
+	PSEUDO_YUV_FMT_LOOSE(NV12,
+		0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
+		C1_B_Cb, C2_R_Cr,
+		SDE_CHROMA_420, (SDE_FORMAT_FLAG_YUV | SDE_FORMAT_FLAG_DX),
+		SDE_FETCH_LINEAR, 2),
+};
+
+static const struct sde_format sde_format_map_p010_ubwc[] = {
+	PSEUDO_YUV_FMT_LOOSE(NV12,
+		0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
+		C1_B_Cb, C2_R_Cr,
+		SDE_CHROMA_420, (SDE_FORMAT_FLAG_YUV | SDE_FORMAT_FLAG_DX),
+		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
  */
@@ -452,6 +498,37 @@
 	}
 }
 
+static int _sde_format_get_media_color_ubwc(const struct sde_format *fmt)
+{
+	static const struct sde_media_color_map sde_media_ubwc_map[] = {
+		{DRM_FORMAT_RGBA8888, COLOR_FMT_RGBA8888_UBWC},
+		{DRM_FORMAT_RGBX8888, COLOR_FMT_RGBA8888_UBWC},
+		{DRM_FORMAT_RGBA1010102, COLOR_FMT_RGBA1010102_UBWC},
+		{DRM_FORMAT_RGBX1010102, COLOR_FMT_RGBA1010102_UBWC},
+		{DRM_FORMAT_RGB565, COLOR_FMT_RGB565_UBWC},
+	};
+	int color_fmt = -1;
+	int i;
+
+	if (fmt->base.pixel_format == DRM_FORMAT_NV12) {
+		if (SDE_FORMAT_IS_DX(fmt)) {
+			if (fmt->unpack_tight)
+				color_fmt = COLOR_FMT_NV12_BPP10_UBWC;
+			else
+				color_fmt = COLOR_FMT_P010_UBWC;
+		} else
+			color_fmt = COLOR_FMT_NV12_UBWC;
+		return color_fmt;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(sde_media_ubwc_map); ++i)
+		if (fmt->base.pixel_format == sde_media_ubwc_map[i].format) {
+			color_fmt = sde_media_ubwc_map[i].color;
+			break;
+		}
+	return color_fmt;
+}
+
 static int _sde_format_get_plane_sizes_ubwc(
 		const struct sde_format *fmt,
 		const uint32_t width,
@@ -459,6 +536,7 @@
 		struct sde_hw_fmt_layout *layout)
 {
 	int i;
+	int color;
 
 	memset(layout, 0, sizeof(struct sde_hw_fmt_layout));
 	layout->format = fmt;
@@ -466,85 +544,55 @@
 	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_RGBA1010102 ||
-		fmt->base.pixel_format == DRM_FORMAT_RGBX1010102 ||
-		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 {
+	color = _sde_format_get_media_color_ubwc(fmt);
+	if (color < 0) {
 		DRM_ERROR("UBWC format not supported for fmt:0x%X\n",
 			fmt->base.pixel_format);
 		return -EINVAL;
 	}
 
+	if (SDE_FORMAT_IS_YUV(layout->format)) {
+		uint32_t y_sclines, uv_sclines;
+		uint32_t y_meta_scanlines = 0;
+		uint32_t uv_meta_scanlines = 0;
+
+		layout->num_planes = 4;
+		layout->plane_pitch[0] = VENUS_Y_STRIDE(color, width);
+		y_sclines = VENUS_Y_SCANLINES(color, height);
+		layout->plane_size[0] = MSM_MEDIA_ALIGN(layout->plane_pitch[0] *
+			y_sclines, SDE_UBWC_PLANE_SIZE_ALIGNMENT);
+
+		layout->plane_pitch[1] = VENUS_UV_STRIDE(color, width);
+		uv_sclines = VENUS_UV_SCANLINES(color, height);
+		layout->plane_size[1] = MSM_MEDIA_ALIGN(layout->plane_pitch[1] *
+			uv_sclines, SDE_UBWC_PLANE_SIZE_ALIGNMENT);
+
+		layout->plane_pitch[2] = VENUS_Y_META_STRIDE(color, width);
+		y_meta_scanlines = VENUS_Y_META_SCANLINES(color, height);
+		layout->plane_size[2] = MSM_MEDIA_ALIGN(layout->plane_pitch[2] *
+			y_meta_scanlines, SDE_UBWC_PLANE_SIZE_ALIGNMENT);
+
+		layout->plane_pitch[3] = VENUS_UV_META_STRIDE(color, width);
+		uv_meta_scanlines = VENUS_UV_META_SCANLINES(color, height);
+		layout->plane_size[3] = MSM_MEDIA_ALIGN(layout->plane_pitch[3] *
+			uv_meta_scanlines, SDE_UBWC_PLANE_SIZE_ALIGNMENT);
+
+	} else {
+		uint32_t rgb_scanlines, rgb_meta_scanlines;
+
+		layout->num_planes = 3;
+
+		layout->plane_pitch[0] = VENUS_RGB_STRIDE(color, width);
+		rgb_scanlines = VENUS_RGB_SCANLINES(color, height);
+		layout->plane_size[0] = MSM_MEDIA_ALIGN(layout->plane_pitch[0] *
+			rgb_scanlines, SDE_UBWC_PLANE_SIZE_ALIGNMENT);
+
+		layout->plane_pitch[2] = VENUS_RGB_META_STRIDE(color, width);
+		rgb_meta_scanlines = VENUS_RGB_META_SCANLINES(color, height);
+		layout->plane_size[2] = MSM_MEDIA_ALIGN(layout->plane_pitch[2] *
+			rgb_meta_scanlines, SDE_UBWC_PLANE_SIZE_ALIGNMENT);
+	}
+
 	for (i = 0; i < SDE_MAX_PLANES; i++)
 		layout->total_size += layout->plane_size[i];
 
@@ -573,6 +621,7 @@
 	} else {
 		uint32_t v_subsample, h_subsample;
 		uint32_t chroma_samp;
+		uint32_t bpp = 1;
 
 		chroma_samp = fmt->chroma_sample;
 		_sde_get_v_h_subsample_rate(chroma_samp, &v_subsample,
@@ -583,8 +632,11 @@
 			return -EINVAL;
 		}
 
-		layout->plane_pitch[0] = width;
-		layout->plane_pitch[1] = width / h_subsample;
+		if ((fmt->base.pixel_format == DRM_FORMAT_NV12) &&
+			(SDE_FORMAT_IS_DX(fmt)))
+			bpp = 2;
+		layout->plane_pitch[0] = width * bpp;
+		layout->plane_pitch[1] = layout->plane_pitch[0] / h_subsample;
 		layout->plane_size[0] = layout->plane_pitch[0] * height;
 		layout->plane_size[1] = layout->plane_pitch[1] *
 				(height / v_subsample);
@@ -925,6 +977,16 @@
 		map_size = ARRAY_SIZE(sde_format_map_ubwc);
 		DBG("found fmt 0x%X DRM_FORMAT_MOD_QCOM_COMPRESSED", format);
 		break;
+	case DRM_FORMAT_MOD_QCOM_DX:
+		map = sde_format_map_p010;
+		map_size = ARRAY_SIZE(sde_format_map_p010);
+		DBG("found fmt 0x%X DRM_FORMAT_MOD_QCOM_DX", format);
+		break;
+	case (DRM_FORMAT_MOD_QCOM_DX | DRM_FORMAT_MOD_QCOM_COMPRESSED):
+		map = sde_format_map_p010_ubwc;
+		map_size = ARRAY_SIZE(sde_format_map_p010_ubwc);
+		DBG("found fmt 0x%X DRM_FORMAT_MOD_QCOM_COMPRESSED/DX", format);
+		break;
 	default:
 		DRM_ERROR("unsupported format modifier %llX\n", mod0);
 		return NULL;
diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h
index 98fefc6..d11c295 100644
--- a/include/uapi/drm/drm_fourcc.h
+++ b/include/uapi/drm/drm_fourcc.h
@@ -241,8 +241,15 @@
  */
 #define DRM_FORMAT_MOD_QCOM_COMPRESSED	fourcc_mod_code(QCOM, 1)
 
+/*
+ * QTI DX Format
+ *
+ * Refers to a DX variant of the base format.
+ * Implementation may be platform and base-format specific.
+ */
+#define DRM_FORMAT_MOD_QCOM_DX	fourcc_mod_code(QCOM, 0x2)
+
 #if defined(__cplusplus)
 }
 #endif
-
 #endif /* DRM_FOURCC_H */