Quellcode durchsuchen

msm: drm: sde: Add support for FP16 via AHB programming

Introduce support for the FP16 format and FP16 color processing
blocks. This includes support for FP16, FP16 UBWC, and inline
rotation on tiled FP16 pixel data.

Change-Id: I06a70cab5447140598682f687129d4f8662524b2
Signed-off-by: Christopher Braga <[email protected]>
Christopher Braga vor 5 Jahren
Ursprung
Commit
9a5a42c453

+ 37 - 1
include/uapi/display/drm/msm_drm_pp.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
 /*
- * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
  */
 
 #ifndef _MSM_DRM_PP_H_
@@ -683,4 +683,40 @@ struct drm_msm_rc_mask_cfg {
 	__u64 cfg_param_09[RC_DATA_SIZE_MAX];
 };
 
+#define FP16_SUPPORTED
+#define FP16_GC_FLAG_ALPHA_EN (1 << 0)
+
+ /* FP16 GC mode options */
+#define FP16_GC_MODE_INVALID 0
+#define FP16_GC_MODE_SRGB 1
+#define FP16_GC_MODE_PQ 2
+
+/**
+ * struct drm_msm_fp16_gc - FP16 GC configuration structure
+ * @in flags - Settings flags for FP16 GC
+ * @in mode - Gamma correction mode to use for FP16 GC
+ */
+struct drm_msm_fp16_gc {
+	__u64 flags;
+	__u64 mode;
+};
+
+/**
+ * struct drm_msm_fp16_csc - FP16 CSC configuration structure
+ * @in flags - Settings flags for FP16 CSC. Currently unused
+ * @in cfg_param_0_len - Length of data for cfg_param_0
+ * @in cfg_param_0 - Data for param 0. Max size is FP16_CSC_CFG0_PARAM_LEN
+ * @in cfg_param_1_len - Length of data for cfg_param_1
+ * @in cfg_param_1 - Data for param 1. Max size is FP16_CSC_CFG1_PARAM_LEN
+ */
+#define FP16_CSC_CFG0_PARAM_LEN 12
+#define FP16_CSC_CFG1_PARAM_LEN 8
+struct drm_msm_fp16_csc {
+	__u64 flags;
+	__u32 cfg_param_0_len;
+	__u32 cfg_param_0[FP16_CSC_CFG0_PARAM_LEN];
+	__u32 cfg_param_1_len;
+	__u32 cfg_param_1[FP16_CSC_CFG1_PARAM_LEN];
+};
+
 #endif /* _MSM_DRM_PP_H_ */

+ 8 - 0
include/uapi/display/drm/sde_drm.h

@@ -64,6 +64,14 @@ extern "C" {
  */
 #define DRM_FORMAT_MOD_QCOM_TILE	fourcc_mod_code(QCOM, 0x8)
 
+/**
+ * @DRM_FORMAT_MOD_QCOM_ALPHA_SWAP:	Refers to a pixel format for which
+ *					its alpha ordering has been reversed.
+ *					Implementation may be platform and
+ *					base-format specific.
+ */
+#define DRM_FORMAT_MOD_QCOM_ALPHA_SWAP	fourcc_mod_code(QCOM, 0x10)
+
 /**
  * Blend operations for "blend_op" property
  *

+ 56 - 0
include/uapi/display/media/mmm_color_fmt.h

@@ -765,6 +765,52 @@ enum mmm_color_fmts {
 	 *          + UV_Stride  * UV_Scanlines), 4096)
 	 */
 	MMM_COLOR_FMT_NV12_512,
+	/* Venus RGBA FP16 UBWC:
+	 * Contains 2 planes in the following order -
+	 * (A) Meta plane
+	 * (B) RGBA plane
+	 *
+	 * <--- RGB_Meta_Stride ---->
+	 * <-------- Width ------>
+	 * M M M M M M M M M M M M . .      ^           ^
+	 * M M M M M M M M M M M M . .      |           |
+	 * M M M M M M M M M M M M . .      Height      |
+	 * M M M M M M M M M M M M . .      |       Meta_RGB_Scanlines
+	 * M M M M M M M M M M M M . .      |           |
+	 * M M M M M M M M M M M M . .      |           |
+	 * M M M M M M M M M M M M . .      |           |
+	 * M M M M M M M M M M M M . .      V           |
+	 * . . . . . . . . . . . . . .                  |
+	 * . . . . . . . . . . . . . .                  |
+	 * . . . . . . . . . . . . . .      -------> Buffer size aligned to 4k
+	 * . . . . . . . . . . . . . .                  V
+	 * <-------- RGB_Stride -------->
+	 * <------- Width ------->
+	 * R R R R R R R R R R R R . . . .  ^           ^
+	 * R R R R R R R R R R R R . . . .  |           |
+	 * R R R R R R R R R R R R . . . .  Height      |
+	 * R R R R R R R R R R R R . . . .  |       RGB_Scanlines
+	 * R R R R R R R R R R R R . . . .  |           |
+	 * R R R R R R R R R R R R . . . .  |           |
+	 * R R R R R R R R R R R R . . . .  |           |
+	 * R R R R R R R R R R R R . . . .  V           |
+	 * . . . . . . . . . . . . . . . .              |
+	 * . . . . . . . . . . . . . . . .              |
+	 * . . . . . . . . . . . . . . . .    -------> Buffer size aligned to 4k
+	 * . . . . . . . . . . . . . . . .              V
+	 *
+	 * RGB_Stride = align(Width * 8, 256)
+	 * RGB_Scanlines = align(Height, 16)
+	 * RGB_Plane_size = align(RGB_Stride * RGB_Scanlines, 4096)
+	 * RGB_Meta_Stride = align(roundup(Width, RGB_TileWidth), 64)
+	 * RGB_Meta_Scanline = align(roundup(Height, RGB_TileHeight), 16)
+	 * RGB_Meta_Plane_size = align(RGB_Meta_Stride *
+	 *              RGB_Meta_Scanlines, 4096)
+	 * RGB_TileWidth = 8 pixels across is 1 tile
+	 * RGB_TileHeight = 4 pixels
+	 * Total size = align(RGB_Meta_Plane_size + RGB_Plane_size, 4096)
+	 */
+	MMM_COLOR_FMT_RGBA16161616F_UBWC,
 };
 
 /*
@@ -1087,6 +1133,10 @@ static inline unsigned int MMM_COLOR_FMT_RGB_STRIDE(unsigned int color_fmt,
 	case MMM_COLOR_FMT_RGBA1010102_UBWC:
 		alignment = 256;
 		break;
+	case MMM_COLOR_FMT_RGBA16161616F_UBWC:
+		alignment = 256;
+		bpp = 8;
+		break;
 	default:
 		goto invalid_input;
 	}
@@ -1112,6 +1162,7 @@ static inline unsigned int MMM_COLOR_FMT_RGB_SCANLINES(unsigned int color_fmt,
 	case MMM_COLOR_FMT_RGBA8888_UBWC:
 	case MMM_COLOR_FMT_RGBA1010102_UBWC:
 	case MMM_COLOR_FMT_RGB565_UBWC:
+	case MMM_COLOR_FMT_RGBA16161616F_UBWC:
 		alignment = 16;
 		break;
 	default:
@@ -1138,6 +1189,9 @@ static inline unsigned int MMM_COLOR_FMT_RGB_META_STRIDE(unsigned int color_fmt,
 	case MMM_COLOR_FMT_RGB565_UBWC:
 		rgb_tile_width = 16;
 		break;
+	case MMM_COLOR_FMT_RGBA16161616F_UBWC:
+		rgb_tile_width = 8;
+		break;
 	default:
 		goto invalid_input;
 	}
@@ -1161,6 +1215,7 @@ static inline unsigned int MMM_COLOR_FMT_RGB_META_SCANLINES(
 	case MMM_COLOR_FMT_RGBA8888_UBWC:
 	case MMM_COLOR_FMT_RGBA1010102_UBWC:
 	case MMM_COLOR_FMT_RGB565_UBWC:
+	case MMM_COLOR_FMT_RGBA16161616F_UBWC:
 		rgb_tile_height = 4;
 		break;
 	default:
@@ -1307,6 +1362,7 @@ static inline unsigned int MMM_COLOR_FMT_BUFFER_SIZE(unsigned int color_fmt,
 	case MMM_COLOR_FMT_RGBA8888_UBWC:
 	case MMM_COLOR_FMT_RGBA1010102_UBWC:
 	case MMM_COLOR_FMT_RGB565_UBWC:
+	case MMM_COLOR_FMT_RGBA16161616F_UBWC:
 		rgb_ubwc_plane = MMM_COLOR_FMT_ALIGN(rgb_stride * rgb_scanlines,
 							4096);
 		rgb_meta_stride = MMM_COLOR_FMT_RGB_META_STRIDE(color_fmt,

+ 4 - 0
msm/msm_drv.h

@@ -111,6 +111,8 @@ enum msm_mdp_plane_property {
 	PLANE_PROP_VIG_IGC,
 	PLANE_PROP_DMA_IGC,
 	PLANE_PROP_DMA_GC,
+	PLANE_PROP_FP16_GC,
+	PLANE_PROP_FP16_CSC,
 
 	/* # of blob properties */
 	PLANE_PROP_BLOBCOUNT,
@@ -132,6 +134,8 @@ enum msm_mdp_plane_property {
 	PLANE_PROP_SCALER_V1,
 	PLANE_PROP_SCALER_V2,
 	PLANE_PROP_INVERSE_PMA,
+	PLANE_PROP_FP16_IGC,
+	PLANE_PROP_FP16_UNMULT,
 
 	/* enum/bitmask properties */
 	PLANE_PROP_BLEND_OP,

+ 39 - 1
msm/sde/sde_formats.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
  */
 
 #define pr_fmt(fmt)	"[drm:%s:%d] " fmt, __func__, __LINE__
@@ -410,6 +410,18 @@ static const struct sde_format sde_format_map[] = {
 		false, 4, SDE_FORMAT_FLAG_DX,
 		SDE_FETCH_LINEAR, 1),
 
+	INTERLEAVED_RGB_FMT(ARGB16161616F,
+		COLOR_16BIT, COLOR_16BIT, COLOR_16BIT, COLOR_16BIT,
+		C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
+		true, 8, SDE_FORMAT_FLAG_FP16,
+		SDE_FETCH_LINEAR, 1),
+
+	INTERLEAVED_RGB_FMT(ABGR16161616F,
+		COLOR_16BIT, COLOR_16BIT, COLOR_16BIT, COLOR_16BIT,
+		C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+		true, 8, SDE_FORMAT_FLAG_FP16,
+		SDE_FETCH_LINEAR, 1),
+
 	PSEUDO_YUV_FMT(NV12,
 		0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
 		C1_B_Cb, C2_R_Cr,
@@ -471,6 +483,21 @@ static const struct sde_format sde_format_map[] = {
 		SDE_FETCH_LINEAR, 3),
 };
 
+/* Base formats supporting the alpha swapping modifier */
+static const struct sde_format sde_format_map_alpha_swap[] = {
+	INTERLEAVED_RGB_FMT(ARGB16161616F,
+		COLOR_16BIT, COLOR_16BIT, COLOR_16BIT, COLOR_16BIT,
+		C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
+		true, 8, SDE_FORMAT_FLAG_FP16 | SDE_FORMAT_FLAG_ALPHA_SWAP,
+		SDE_FETCH_LINEAR, 1),
+
+	INTERLEAVED_RGB_FMT(ABGR16161616F,
+		COLOR_16BIT, COLOR_16BIT, COLOR_16BIT, COLOR_16BIT,
+		C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
+		true, 8, SDE_FORMAT_FLAG_FP16 | SDE_FORMAT_FLAG_ALPHA_SWAP,
+		SDE_FETCH_LINEAR, 1),
+};
+
 /*
  * A5x tile formats tables:
  * These tables hold the A5x tile formats supported.
@@ -608,6 +635,12 @@ static const struct sde_format sde_format_map_ubwc[] = {
 		true, 4, SDE_FORMAT_FLAG_DX | SDE_FORMAT_FLAG_COMPRESSED,
 		SDE_FETCH_UBWC, 2, SDE_TILE_HEIGHT_UBWC),
 
+	INTERLEAVED_RGB_FMT_TILED(ABGR16161616F,
+		COLOR_16BIT, COLOR_16BIT, COLOR_16BIT, COLOR_16BIT,
+		C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+		true, 8, SDE_FORMAT_FLAG_FP16 | SDE_FORMAT_FLAG_COMPRESSED,
+		SDE_FETCH_UBWC, 2, SDE_TILE_HEIGHT_UBWC),
+
 	PSEUDO_YUV_FMT_TILED(NV12,
 		0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
 		C1_B_Cb, C2_R_Cr,
@@ -691,6 +724,7 @@ static int _sde_format_get_media_color_ubwc(const struct sde_format *fmt)
 		{DRM_FORMAT_ABGR2101010, MMM_COLOR_FMT_RGBA1010102_UBWC},
 		{DRM_FORMAT_XBGR2101010, MMM_COLOR_FMT_RGBA1010102_UBWC},
 		{DRM_FORMAT_BGR565, MMM_COLOR_FMT_RGB565_UBWC},
+		{DRM_FORMAT_ABGR16161616F, MMM_COLOR_FMT_RGBA16161616F_UBWC},
 	};
 	int color_fmt = -1;
 	int i;
@@ -1240,6 +1274,10 @@ const struct sde_format *sde_get_sde_format_ext(
 		map = sde_format_map;
 		map_size = ARRAY_SIZE(sde_format_map);
 		break;
+	case DRM_FORMAT_MOD_QCOM_ALPHA_SWAP:
+		map = sde_format_map_alpha_swap;
+		map_size = ARRAY_SIZE(sde_format_map_alpha_swap);
+		break;
 	case DRM_FORMAT_MOD_QCOM_COMPRESSED:
 	case DRM_FORMAT_MOD_QCOM_COMPRESSED | DRM_FORMAT_MOD_QCOM_TILE:
 		map = sde_format_map_ubwc;

+ 248 - 99
msm/sde/sde_hw_catalog.c

@@ -267,6 +267,7 @@ enum {
 };
 
 enum {
+	VIG_SUBBLOCK_INDEX,
 	VIG_QSEED_OFF,
 	VIG_QSEED_LEN,
 	VIG_CSC_OFF,
@@ -276,6 +277,10 @@ enum {
 	VIG_GAMUT_PROP,
 	VIG_IGC_PROP,
 	VIG_INVERSE_PMA,
+	VIG_FP16_IGC_PROP,
+	VIG_FP16_GC_PROP,
+	VIG_FP16_CSC_PROP,
+	VIG_FP16_UNMULT_PROP,
 	VIG_PROP_MAX,
 };
 
@@ -292,6 +297,10 @@ enum {
 	DMA_GC_PROP,
 	DMA_DGM_INVERSE_PMA,
 	DMA_CSC_OFF,
+	DMA_FP16_IGC_PROP,
+	DMA_FP16_GC_PROP,
+	DMA_FP16_CSC_PROP,
+	DMA_FP16_UNMULT_PROP,
 	DMA_PROP_MAX,
 };
 
@@ -664,16 +673,34 @@ static struct sde_prop_type sspp_prop[] = {
 };
 
 static struct sde_prop_type vig_prop[] = {
-	{VIG_QSEED_OFF, "qcom,sde-vig-qseed-off", false, PROP_TYPE_U32},
-	{VIG_QSEED_LEN, "qcom,sde-vig-qseed-size", false, PROP_TYPE_U32},
-	{VIG_CSC_OFF, "qcom,sde-vig-csc-off", false, PROP_TYPE_U32},
-	{VIG_HSIC_PROP, "qcom,sde-vig-hsic", false, PROP_TYPE_U32_ARRAY},
-	{VIG_MEMCOLOR_PROP, "qcom,sde-vig-memcolor", false,
-		PROP_TYPE_U32_ARRAY},
-	{VIG_PCC_PROP, "qcom,sde-vig-pcc", false, PROP_TYPE_U32_ARRAY},
-	{VIG_GAMUT_PROP, "qcom,sde-vig-gamut", false, PROP_TYPE_U32_ARRAY},
-	{VIG_IGC_PROP, "qcom,sde-vig-igc", false, PROP_TYPE_U32_ARRAY},
-	{VIG_INVERSE_PMA, "qcom,sde-vig-inverse-pma", false, PROP_TYPE_BOOL},
+	[VIG_SUBBLOCK_INDEX] = {VIG_SUBBLOCK_INDEX, "cell-index", false,
+                        PROP_TYPE_U32},
+	[VIG_QSEED_OFF] = {VIG_QSEED_OFF, "qcom,sde-vig-qseed-off", false,
+			PROP_TYPE_U32},
+	[VIG_QSEED_LEN] = {VIG_QSEED_LEN, "qcom,sde-vig-qseed-size", false,
+			PROP_TYPE_U32},
+	[VIG_CSC_OFF] = {VIG_CSC_OFF, "qcom,sde-vig-csc-off", false,
+			PROP_TYPE_U32},
+	[VIG_HSIC_PROP] = {VIG_HSIC_PROP, "qcom,sde-vig-hsic", false,
+			PROP_TYPE_U32_ARRAY},
+	[VIG_MEMCOLOR_PROP] = {VIG_MEMCOLOR_PROP, "qcom,sde-vig-memcolor",
+			false, PROP_TYPE_U32_ARRAY},
+	[VIG_PCC_PROP] = {VIG_PCC_PROP, "qcom,sde-vig-pcc", false,
+			PROP_TYPE_U32_ARRAY},
+	[VIG_GAMUT_PROP] = {VIG_GAMUT_PROP, "qcom,sde-vig-gamut", false,
+			PROP_TYPE_U32_ARRAY},
+	[VIG_IGC_PROP] = {VIG_IGC_PROP, "qcom,sde-vig-igc", false,
+			PROP_TYPE_U32_ARRAY},
+	[VIG_INVERSE_PMA] = {VIG_INVERSE_PMA, "qcom,sde-vig-inverse-pma", false,
+			PROP_TYPE_BOOL},
+	[VIG_FP16_IGC_PROP] = {VIG_FP16_IGC_PROP, "qcom,sde-fp16-igc", false,
+			PROP_TYPE_U32_ARRAY},
+	[VIG_FP16_GC_PROP] = {VIG_FP16_GC_PROP, "qcom,sde-fp16-gc", false,
+			PROP_TYPE_U32_ARRAY},
+	[VIG_FP16_CSC_PROP] = {VIG_FP16_CSC_PROP, "qcom,sde-fp16-csc", false,
+			PROP_TYPE_U32_ARRAY},
+	[VIG_FP16_UNMULT_PROP] = {VIG_FP16_UNMULT_PROP, "qcom,sde-fp16-unmult",
+			false, PROP_TYPE_U32_ARRAY},
 };
 
 static struct sde_prop_type rgb_prop[] = {
@@ -683,12 +710,24 @@ static struct sde_prop_type rgb_prop[] = {
 };
 
 static struct sde_prop_type dma_prop[] = {
-	{DMA_SUBBLOCK_INDEX, "cell-index", false, PROP_TYPE_U32},
-	{DMA_IGC_PROP, "qcom,sde-dma-igc", false, PROP_TYPE_U32_ARRAY},
-	{DMA_GC_PROP, "qcom,sde-dma-gc", false, PROP_TYPE_U32_ARRAY},
-	{DMA_DGM_INVERSE_PMA, "qcom,sde-dma-inverse-pma", false,
-		PROP_TYPE_BOOL},
-	{DMA_CSC_OFF, "qcom,sde-dma-csc-off", false, PROP_TYPE_U32},
+	[DMA_SUBBLOCK_INDEX] = {DMA_SUBBLOCK_INDEX, "cell-index", false,
+			PROP_TYPE_U32},
+	[DMA_IGC_PROP] = {DMA_IGC_PROP, "qcom,sde-dma-igc", false,
+			PROP_TYPE_U32_ARRAY},
+	[DMA_GC_PROP] = {DMA_GC_PROP, "qcom,sde-dma-gc", false,
+			PROP_TYPE_U32_ARRAY},
+	[DMA_DGM_INVERSE_PMA] = {DMA_DGM_INVERSE_PMA,
+			"qcom,sde-dma-inverse-pma", false, PROP_TYPE_BOOL},
+	[DMA_CSC_OFF] = {DMA_CSC_OFF, "qcom,sde-dma-csc-off", false,
+			PROP_TYPE_U32},
+	[DMA_FP16_IGC_PROP] = {DMA_FP16_IGC_PROP, "qcom,sde-fp16-igc", false,
+			PROP_TYPE_U32_ARRAY},
+	[DMA_FP16_GC_PROP] = {DMA_FP16_GC_PROP, "qcom,sde-fp16-gc", false,
+			PROP_TYPE_U32_ARRAY},
+	[DMA_FP16_CSC_PROP] = {DMA_FP16_CSC_PROP, "qcom,sde-fp16-csc", false,
+			PROP_TYPE_U32_ARRAY},
+	[DMA_FP16_UNMULT_PROP] = {DMA_FP16_UNMULT_PROP, "qcom,sde-fp16-unmult",
+			false, PROP_TYPE_U32_ARRAY},
 };
 
 static struct sde_prop_type ctl_prop[] = {
@@ -1319,83 +1358,58 @@ static int _add_to_irq_offset_list(struct sde_mdss_cfg *sde_cfg,
 	return 0;
 }
 
+/* VIG color management (VCM) feature setup */
+static bool _sde_sspp_setup_vcm(struct sde_sspp_cfg *sspp,
+		const struct sde_dt_props *props, const char *name,
+		struct sde_pp_blk *blk, u32 type, u32 prop, bool versioned)
+{
+	bool exists = props->exists[prop];
+
+	if (exists) {
+		blk->id = type;
+		blk->len = 0;
+		set_bit(type, (unsigned long *) &sspp->features_ext);
+		blk->base = PROP_VALUE_ACCESS(props->values, prop, 0);
+		snprintf(blk->name, SDE_HW_BLK_NAME_LEN, "%s%u", name,
+				sspp->id - SSPP_VIG0);
+		if (versioned)
+			blk->version = PROP_VALUE_ACCESS(props->values,
+					prop, 1);
+	} else {
+		blk->id = 0;
+	}
+
+	return exists;
+}
+
 static void _sde_sspp_setup_vigs_pp(struct sde_dt_props *props,
 		struct sde_mdss_cfg *sde_cfg, struct sde_sspp_cfg *sspp)
 {
 	struct sde_sspp_sub_blks *sblk = sspp->sblk;
+	if (!props)
+		return;
 
-	sblk->csc_blk.id = SDE_SSPP_CSC;
-	snprintf(sblk->csc_blk.name, SDE_HW_BLK_NAME_LEN,
-			"sspp_csc%u", sspp->id - SSPP_VIG0);
-	if (sde_cfg->csc_type == SDE_SSPP_CSC) {
-		set_bit(SDE_SSPP_CSC, &sspp->features);
-		sblk->csc_blk.base = PROP_VALUE_ACCESS(props->values,
-						VIG_CSC_OFF, 0);
-	} else if (sde_cfg->csc_type == SDE_SSPP_CSC_10BIT) {
-		set_bit(SDE_SSPP_CSC_10BIT, &sspp->features);
-		sblk->csc_blk.base = PROP_VALUE_ACCESS(props->values,
-						VIG_CSC_OFF, 0);
-	}
+	if (sde_cfg->csc_type == SDE_SSPP_CSC)
+		_sde_sspp_setup_vcm(sspp, props, "sspp_csc", &sblk->csc_blk,
+				SDE_SSPP_CSC, VIG_CSC_OFF, false);
+	else if (sde_cfg->csc_type == SDE_SSPP_CSC_10BIT)
+		_sde_sspp_setup_vcm(sspp, props, "sspp_csc", &sblk->csc_blk,
+				SDE_SSPP_CSC_10BIT, VIG_CSC_OFF, false);
 
-	sblk->hsic_blk.id = SDE_SSPP_HSIC;
-	snprintf(sblk->hsic_blk.name, SDE_HW_BLK_NAME_LEN,
-			"sspp_hsic%u", sspp->id - SSPP_VIG0);
-	if (props->exists[VIG_HSIC_PROP]) {
-		sblk->hsic_blk.base = PROP_VALUE_ACCESS(props->values,
-				VIG_HSIC_PROP, 0);
-		sblk->hsic_blk.version = PROP_VALUE_ACCESS(
-				props->values, VIG_HSIC_PROP, 1);
-		sblk->hsic_blk.len = 0;
-		set_bit(SDE_SSPP_HSIC, &sspp->features);
-	}
+	_sde_sspp_setup_vcm(sspp, props, "sspp_hsic", &sblk->hsic_blk,
+			SDE_SSPP_HSIC, VIG_HSIC_PROP, true);
 
-	sblk->memcolor_blk.id = SDE_SSPP_MEMCOLOR;
-	snprintf(sblk->memcolor_blk.name, SDE_HW_BLK_NAME_LEN,
-			"sspp_memcolor%u", sspp->id - SSPP_VIG0);
-	if (props->exists[VIG_MEMCOLOR_PROP]) {
-		sblk->memcolor_blk.base = PROP_VALUE_ACCESS(
-				props->values, VIG_MEMCOLOR_PROP, 0);
-		sblk->memcolor_blk.version = PROP_VALUE_ACCESS(
-				props->values, VIG_MEMCOLOR_PROP, 1);
-		sblk->memcolor_blk.len = 0;
-		set_bit(SDE_SSPP_MEMCOLOR, &sspp->features);
-	}
+	_sde_sspp_setup_vcm(sspp, props, "sspp_memcolor", &sblk->memcolor_blk,
+			SDE_SSPP_MEMCOLOR, VIG_MEMCOLOR_PROP, true);
 
-	sblk->pcc_blk.id = SDE_SSPP_PCC;
-	snprintf(sblk->pcc_blk.name, SDE_HW_BLK_NAME_LEN,
-			"sspp_pcc%u", sspp->id - SSPP_VIG0);
-	if (props->exists[VIG_PCC_PROP]) {
-		sblk->pcc_blk.base = PROP_VALUE_ACCESS(props->values,
-				VIG_PCC_PROP, 0);
-		sblk->pcc_blk.version = PROP_VALUE_ACCESS(props->values,
-				VIG_PCC_PROP, 1);
-		sblk->pcc_blk.len = 0;
-		set_bit(SDE_SSPP_PCC, &sspp->features);
-	}
+	_sde_sspp_setup_vcm(sspp, props, "sspp_pcc", &sblk->pcc_blk,
+			SDE_SSPP_PCC, VIG_PCC_PROP, true);
 
-	if (props->exists[VIG_GAMUT_PROP]) {
-		sblk->gamut_blk.id = SDE_SSPP_VIG_GAMUT;
-		snprintf(sblk->gamut_blk.name, SDE_HW_BLK_NAME_LEN,
-			"sspp_vig_gamut%u", sspp->id - SSPP_VIG0);
-		sblk->gamut_blk.base = PROP_VALUE_ACCESS(props->values,
-				VIG_GAMUT_PROP, 0);
-		sblk->gamut_blk.version = PROP_VALUE_ACCESS(
-				props->values, VIG_GAMUT_PROP, 1);
-		sblk->gamut_blk.len = 0;
-		set_bit(SDE_SSPP_VIG_GAMUT, &sspp->features);
-	}
+	_sde_sspp_setup_vcm(sspp, props, "sspp_vig_gamut", &sblk->gamut_blk,
+			SDE_SSPP_VIG_GAMUT, VIG_GAMUT_PROP, true);
 
-	if (props->exists[VIG_IGC_PROP]) {
-		sblk->igc_blk[0].id = SDE_SSPP_VIG_IGC;
-		snprintf(sblk->igc_blk[0].name, SDE_HW_BLK_NAME_LEN,
-			"sspp_vig_igc%u", sspp->id - SSPP_VIG0);
-		sblk->igc_blk[0].base = PROP_VALUE_ACCESS(props->values,
-				VIG_IGC_PROP, 0);
-		sblk->igc_blk[0].version = PROP_VALUE_ACCESS(
-				props->values, VIG_IGC_PROP, 1);
-		sblk->igc_blk[0].len = 0;
-		set_bit(SDE_SSPP_VIG_IGC, &sspp->features);
-	}
+	_sde_sspp_setup_vcm(sspp, props, "sspp_vig_igc", &sblk->igc_blk[0],
+			SDE_SSPP_VIG_IGC, VIG_IGC_PROP, true);
 
 	if (props->exists[VIG_INVERSE_PMA])
 		set_bit(SDE_SSPP_INVERSE_PMA, &sspp->features);
@@ -1404,21 +1418,59 @@ static void _sde_sspp_setup_vigs_pp(struct sde_dt_props *props,
 static int _sde_sspp_setup_vigs(struct device_node *np,
 		struct sde_mdss_cfg *sde_cfg)
 {
-	int i;
-	struct sde_dt_props *props;
+	int i = 0, j = 0, rc = 0;
+	struct sde_dt_props *props[SSPP_SUBBLK_COUNT_MAX] = {NULL, NULL};
+	struct sde_dt_props *props_tmp = NULL;
 	struct device_node *snp = NULL;
 	struct sde_sc_cfg *sc_cfg = sde_cfg->sc_cfg;
-	int vig_count = 0;
+	int vig_count = 0, vcm_count = 0;
 	const char *type;
 
 	snp = of_get_child_by_name(np, sspp_prop[SSPP_VIG_BLOCKS].prop_name);
 	if (!snp)
 		return 0;
 
-	props = sde_get_dt_props(snp, VIG_PROP_MAX, vig_prop,
-			ARRAY_SIZE(vig_prop), NULL);
-	if (IS_ERR(props))
-		return PTR_ERR(props);
+	/* Assume sub nodes are in rect order */
+	vcm_count = of_get_child_count(snp);
+	if (vcm_count > 0) {
+		struct device_node *vcm_snp;
+
+		if (vcm_count > SSPP_SUBBLK_COUNT_MAX) {
+			SDE_ERROR("exceeded max vcm sub-block count!");
+			vcm_count = SSPP_SUBBLK_COUNT_MAX;
+		}
+		for_each_child_of_node(snp, vcm_snp) {
+
+			props_tmp = sde_get_dt_props(vcm_snp,
+					VIG_PROP_MAX, vig_prop,
+					ARRAY_SIZE(vig_prop), NULL);
+			if (IS_ERR(props_tmp)) {
+				rc = PTR_ERR(props_tmp);
+				props_tmp = NULL;
+				goto end;
+			}
+
+			if (!props_tmp->exists[VIG_SUBBLOCK_INDEX]) {
+				SDE_ERROR("vcm rect index must be specified!");
+				goto end;
+			}
+
+			i = PROP_VALUE_ACCESS(props_tmp->values, VIG_SUBBLOCK_INDEX, 0);
+			if (i >= SSPP_SUBBLK_COUNT_MAX) {
+				SDE_ERROR("invalid vcm rect index: %d", i);
+				goto end;
+			} else if (props[i] != NULL) {
+				SDE_ERROR("vcm rect index must be unique! repeat: %d", i);
+				goto end;
+			}
+
+			props[i] = props_tmp;
+			props_tmp = NULL;
+		}
+	} else {
+		props[0] = sde_get_dt_props(snp, VIG_PROP_MAX, vig_prop,
+				ARRAY_SIZE(vig_prop), NULL);
+	}
 
 	for (i = 0; i < sde_cfg->sspp_count; ++i) {
 		struct sde_sspp_cfg *sspp = sde_cfg->sspp + i;
@@ -1445,21 +1497,59 @@ static int _sde_sspp_setup_vigs(struct device_node *np,
 
 		sblk->format_list = sde_cfg->vig_formats;
 		sblk->virt_format_list = sde_cfg->virt_vig_formats;
+		sblk->num_fp16_igc_blk = 0;
+		sblk->num_fp16_gc_blk = 0;
+		sblk->num_fp16_csc_blk = 0;
+		sblk->num_fp16_unmult_blk = 0;
 
-		if ((sde_cfg->qseed_sw_lib_rev == SDE_SSPP_SCALER_QSEED2) ||
+		for (j = 0; j < SSPP_SUBBLK_COUNT_MAX; j++) {
+			if (!props[j])
+				continue;
+
+			if (_sde_sspp_setup_vcm(sspp, props[j],
+					"sspp_vig_fp16_igc",
+					&sblk->fp16_igc_blk[j],
+					SDE_SSPP_FP16_IGC, VIG_FP16_IGC_PROP,
+					true))
+				sblk->num_fp16_igc_blk += 1;
+
+			if (_sde_sspp_setup_vcm(sspp, props[j],
+					"sspp_vig_fp16_gc",
+					&sblk->fp16_gc_blk[j],
+					SDE_SSPP_FP16_GC, VIG_FP16_GC_PROP,
+					true))
+				sblk->num_fp16_gc_blk += 1;
+
+			if (_sde_sspp_setup_vcm(sspp, props[j],
+					"sspp_vig_fp16_csc",
+					&sblk->fp16_csc_blk[j],
+					SDE_SSPP_FP16_CSC, VIG_FP16_CSC_PROP,
+					true))
+				sblk->num_fp16_csc_blk += 1;
+
+			if (_sde_sspp_setup_vcm(sspp, props[j],
+					"sspp_vig_fp16_unmult",
+					&sblk->fp16_unmult_blk[j],
+					SDE_SSPP_FP16_UNMULT,
+					VIG_FP16_UNMULT_PROP, true))
+				sblk->num_fp16_unmult_blk += 1;
+		}
+
+		/* PP + scaling only supported on VIG rect 0 */
+		if (props[0] && ((sde_cfg->qseed_sw_lib_rev == SDE_SSPP_SCALER_QSEED2) ||
 		    (sde_cfg->qseed_sw_lib_rev == SDE_SSPP_SCALER_QSEED3) ||
-		    (sde_cfg->qseed_sw_lib_rev == SDE_SSPP_SCALER_QSEED3LITE)) {
+		    (sde_cfg->qseed_sw_lib_rev == SDE_SSPP_SCALER_QSEED3LITE))) {
 			set_bit(sde_cfg->qseed_sw_lib_rev, &sspp->features);
 			sblk->scaler_blk.id = sde_cfg->qseed_sw_lib_rev;
-			sblk->scaler_blk.base = PROP_VALUE_ACCESS(props->values,
-				VIG_QSEED_OFF, 0);
-			sblk->scaler_blk.len = PROP_VALUE_ACCESS(props->values,
-				VIG_QSEED_LEN, 0);
+			sblk->scaler_blk.base = PROP_VALUE_ACCESS(
+					props[0]->values, VIG_QSEED_OFF, 0);
+			sblk->scaler_blk.len = PROP_VALUE_ACCESS(
+					props[0]->values, VIG_QSEED_LEN, 0);
 			snprintf(sblk->scaler_blk.name, SDE_HW_BLK_NAME_LEN,
 					"sspp_scaler%u", sspp->id - SSPP_VIG0);
 		}
 
-		_sde_sspp_setup_vigs_pp(props, sde_cfg, sspp);
+		_sde_sspp_setup_vigs_pp(props[0], sde_cfg, sspp);
 
 		if (sde_cfg->true_inline_rot_rev > 0) {
 			set_bit(SDE_SSPP_TRUE_INLINE_ROT, &sspp->features);
@@ -1503,8 +1593,12 @@ static int _sde_sspp_setup_vigs(struct device_node *np,
 
 	}
 
-	sde_put_dt_props(props);
-	return 0;
+end:
+	sde_put_dt_props(props_tmp);
+	for (i = 0; i < SSPP_SUBBLK_COUNT_MAX; i++)
+		sde_put_dt_props(props[i]);
+
+	return rc;
 }
 
 static void _sde_sspp_setup_rgbs_pp(struct sde_dt_props *props,
@@ -1716,6 +1810,34 @@ static int _sde_sspp_setup_dmas(struct device_node *np,
 				_sde_sspp_setup_dgm(sspp, props[j],
 					"sspp_dgm_csc", &sblk->dgm_csc_blk[j],
 					SDE_SSPP_DGM_CSC, DMA_CSC_OFF, false);
+
+			if (props[j]->exists[DMA_FP16_IGC_PROP])
+				_sde_sspp_setup_dgm(sspp, props[j],
+						"sspp_dma_fp16_igc",
+						&sblk->fp16_igc_blk[j],
+						SDE_SSPP_FP16_IGC,
+						DMA_FP16_IGC_PROP, true);
+
+			if (props[j]->exists[DMA_FP16_GC_PROP])
+				_sde_sspp_setup_dgm(sspp, props[j],
+						"sspp_dma_fp16_gc",
+						&sblk->fp16_gc_blk[j],
+						SDE_SSPP_FP16_GC,
+						DMA_FP16_GC_PROP, true);
+
+			if (props[j]->exists[DMA_FP16_CSC_PROP])
+				_sde_sspp_setup_dgm(sspp, props[j],
+						"sspp_dma_fp16_csc",
+						&sblk->fp16_csc_blk[j],
+						SDE_SSPP_FP16_CSC,
+						DMA_FP16_CSC_PROP, true);
+
+			if (props[j]->exists[DMA_FP16_UNMULT_PROP])
+				_sde_sspp_setup_dgm(sspp, props[j],
+						"sspp_dma_fp16_unmult",
+						&sblk->fp16_unmult_blk[j],
+						SDE_SSPP_FP16_UNMULT,
+						DMA_FP16_UNMULT_PROP, true);
 		}
 	}
 
@@ -4423,6 +4545,9 @@ static int sde_hardware_format_caps(struct sde_mdss_cfg *sde_cfg,
 
 	/* DMA pipe input formats */
 	dma_list_size = ARRAY_SIZE(plane_formats);
+	if (sde_cfg->has_fp16)
+		dma_list_size += ARRAY_SIZE(fp16_formats);
+
 	sde_cfg->dma_formats = kcalloc(dma_list_size,
 		sizeof(struct sde_format_extended), GFP_KERNEL);
 	if (!sde_cfg->dma_formats) {
@@ -4432,11 +4557,17 @@ static int sde_hardware_format_caps(struct sde_mdss_cfg *sde_cfg,
 
 	index = sde_copy_formats(sde_cfg->dma_formats, dma_list_size,
 			0, plane_formats, ARRAY_SIZE(plane_formats));
+	if (sde_cfg->has_fp16)
+		index += sde_copy_formats(sde_cfg->dma_formats, dma_list_size,
+			index, fp16_formats, ARRAY_SIZE(fp16_formats));
 
 	/* ViG pipe input formats */
 	vig_list_size = ARRAY_SIZE(plane_formats_vig);
 	if (sde_cfg->has_vig_p010)
 		vig_list_size += ARRAY_SIZE(p010_ubwc_formats);
+	if (sde_cfg->has_fp16)
+		vig_list_size += ARRAY_SIZE(fp16_formats);
+
 	sde_cfg->vig_formats = kcalloc(vig_list_size,
 		sizeof(struct sde_format_extended), GFP_KERNEL);
 	if (!sde_cfg->vig_formats) {
@@ -4450,9 +4581,15 @@ static int sde_hardware_format_caps(struct sde_mdss_cfg *sde_cfg,
 		index += sde_copy_formats(sde_cfg->vig_formats,
 				vig_list_size, index, p010_ubwc_formats,
 				ARRAY_SIZE(p010_ubwc_formats));
+	if (sde_cfg->has_fp16)
+		index += sde_copy_formats(sde_cfg->vig_formats, vig_list_size,
+			index, fp16_formats, ARRAY_SIZE(fp16_formats));
 
 	/* Virtual ViG pipe input formats (all virt pipes use DMA formats) */
 	virt_vig_list_size = ARRAY_SIZE(plane_formats);
+	if (sde_cfg->has_fp16)
+		virt_vig_list_size += ARRAY_SIZE(fp16_formats);
+
 	sde_cfg->virt_vig_formats = kcalloc(virt_vig_list_size,
 		sizeof(struct sde_format_extended), GFP_KERNEL);
 	if (!sde_cfg->virt_vig_formats) {
@@ -4462,6 +4599,10 @@ static int sde_hardware_format_caps(struct sde_mdss_cfg *sde_cfg,
 
 	index = sde_copy_formats(sde_cfg->virt_vig_formats, virt_vig_list_size,
 			0, plane_formats, ARRAY_SIZE(plane_formats));
+	if (sde_cfg->has_fp16)
+		index += sde_copy_formats(sde_cfg->virt_vig_formats,
+				virt_vig_list_size, index, fp16_formats,
+				ARRAY_SIZE(fp16_formats));
 
 	/* WB output formats */
 	wb2_list_size = ARRAY_SIZE(wb2_formats);
@@ -4486,6 +4627,9 @@ static int sde_hardware_format_caps(struct sde_mdss_cfg *sde_cfg,
 	}
 
 	if (in_rot_list_size) {
+		if (sde_cfg->has_fp16)
+			in_rot_list_size += ARRAY_SIZE(fp_16_inline_rot_fmts);
+
 		sde_cfg->inline_rot_formats = kcalloc(in_rot_list_size,
 			sizeof(struct sde_format_extended), GFP_KERNEL);
 		if (!sde_cfg->inline_rot_formats) {
@@ -4496,6 +4640,10 @@ static int sde_hardware_format_caps(struct sde_mdss_cfg *sde_cfg,
 
 		index = sde_copy_formats(sde_cfg->inline_rot_formats,
 			in_rot_list_size, 0, inline_fmt_tbl, in_rot_list_size);
+		if (sde_cfg->has_fp16)
+			index += sde_copy_formats(sde_cfg->inline_rot_formats,
+				in_rot_list_size, index, fp_16_inline_rot_fmts,
+				ARRAY_SIZE(fp_16_inline_rot_fmts));
 	}
 
 	return 0;
@@ -4850,6 +4998,7 @@ static int _sde_hardware_pre_caps(struct sde_mdss_cfg *sde_cfg, uint32_t hw_rev)
 		sde_cfg->mdss_hw_block_size = 0x158;
 		sde_cfg->syscache_supported = true;
 		sde_cfg->sspp_multirect_error = true;
+		sde_cfg->has_fp16 = true;
 	} else {
 		SDE_ERROR("unsupported chipset id:%X\n", hw_rev);
 		sde_cfg->perf.min_prefill_lines = 0xffff;

+ 35 - 3
msm/sde/sde_hw_catalog.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
  */
 
 #ifndef _SDE_HW_CATALOG_H
@@ -91,6 +91,9 @@
 #define SDE_COLOR_PROCESS_MAJOR(version) (((version) & 0xFFFF0000) >> 16)
 #define SDE_COLOR_PROCESS_MINOR(version) ((version) & 0xFFFF)
 
+#define IS_SDE_CP_VER_1_0(version) \
+	(version == SDE_COLOR_PROCESS_VER(0x1, 0x0))
+
 #define MAX_XIN_COUNT 16
 #define SSPP_SUBBLK_COUNT_MAX 2
 
@@ -256,6 +259,10 @@ enum {
  * @SDE_SSPP_PREDOWNSCALE    Support pre-downscale X-direction by 2 for inline
  * @SDE_SSPP_PREDOWNSCALE_Y  Support pre-downscale Y-direction for inline
  * @SDE_SSPP_INLINE_CONST_CLR Inline rotation requires const clr disabled
+ * @SDE_SSPP_FP16_IGC        FP16 IGC color processing block support
+ * @SDE_SSPP_FP16_GC         FP16 GC color processing block support
+ * @SDE_SSPP_FP16_CSC        FP16 CSC color processing block support
+ * @SDE_SSPP_FP16_UNMULT     FP16 alpha unmult color processing block support
  * @SDE_SSPP_MAX             maximum value
  */
 enum {
@@ -288,6 +295,10 @@ enum {
 	SDE_SSPP_PREDOWNSCALE,
 	SDE_SSPP_PREDOWNSCALE_Y,
 	SDE_SSPP_INLINE_CONST_CLR,
+	SDE_SSPP_FP16_IGC,
+	SDE_SSPP_FP16_GC,
+	SDE_SSPP_FP16_CSC,
+	SDE_SSPP_FP16_UNMULT,
 	SDE_SSPP_MAX
 };
 
@@ -581,7 +592,10 @@ enum {
 	u32 id; \
 	u32 base; \
 	u32 len; \
-	unsigned long features; \
+	union { \
+		unsigned long features; \
+		u64 features_ext; \
+	}; \
 	unsigned long perf_features
 
 /**
@@ -701,6 +715,14 @@ enum sde_qos_lut_usage {
  * @gc_blk: 1D LUT GC block
  * @num_dgm_csc_blk: number of DGM CSC blocks
  * @dgm_csc_blk: DGM CSC blocks
+ * @num_fp16_igc_blk: number of FP16 IGC blocks
+ * @fp16_igc_blk: FP16 IGC block array
+ * @num_fp16_gc_blk: number of FP16 GC blocks
+ * @fp16_gc_blk: FP16 GC block array
+ * @num_fp16_csc_blk: number of FP16 CSC blocks
+ * @fp16_csc_blk: FP16 CSC block array
+ * @num_fp16_unmult_blk: number of FP16 UNMULT blocks
+ * @fp16_unmult_blk: FP16 UNMULT block array
  * @format_list: Pointer to list of supported formats
  * @virt_format_list: Pointer to list of supported formats for virtual planes
  * @in_rot_format_list: Pointer to list of supported formats for inline rotation
@@ -743,6 +765,14 @@ struct sde_sspp_sub_blks {
 	struct sde_pp_blk gc_blk[SSPP_SUBBLK_COUNT_MAX];
 	u32 num_dgm_csc_blk;
 	struct sde_pp_blk dgm_csc_blk[SSPP_SUBBLK_COUNT_MAX];
+	u32 num_fp16_igc_blk;
+	struct sde_pp_blk fp16_igc_blk[SSPP_SUBBLK_COUNT_MAX];
+	u32 num_fp16_gc_blk;
+	struct sde_pp_blk fp16_gc_blk[SSPP_SUBBLK_COUNT_MAX];
+	u32 num_fp16_csc_blk;
+	struct sde_pp_blk fp16_csc_blk[SSPP_SUBBLK_COUNT_MAX];
+	u32 num_fp16_unmult_blk;
+	struct sde_pp_blk fp16_unmult_blk[SSPP_SUBBLK_COUNT_MAX];
 
 	const struct sde_format_extended *format_list;
 	const struct sde_format_extended *virt_format_list;
@@ -1448,8 +1478,9 @@ struct sde_perf_cfg {
  * @has_sui_blendstage  flag to indicate secure-ui has a blendstage restriction
  * @has_cursor    indicates if hardware cursor is supported
  * @has_vig_p010  indicates if vig pipe supports p010 format
+ * @has_fp16      indicates if FP16 format is supported on SSPP pipes
  * @mdss_hw_block_size  Max offset of MDSS_HW block (0 offset), used for debug
- * @inline_rot_formats	formats supported by the inline rotator feature
+ * @inline_rot_formats formats supported by the inline rotator feature
  * @irq_offset_list     list of sde_intr_irq_offsets to initialize irq table
  * @rc_count	number of rounded corner hardware instances
  * @demura_count number of demura hardware instances
@@ -1525,6 +1556,7 @@ struct sde_mdss_cfg {
 	bool has_hdr_plus;
 	bool has_cursor;
 	bool has_vig_p010;
+	bool has_fp16;
 	u32 mdss_hw_block_size;
 	u32 mdss_count;
 	struct sde_mdss_base_cfg mdss[MAX_BLOCKS];

+ 16 - 1
msm/sde/sde_hw_catalog_format.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2019, 2021 The Linux Foundation. All rights reserved.
  */
 
 #include "sde_hw_mdss.h"
@@ -164,3 +164,18 @@ static const struct sde_format_extended true_inline_rot_v2_fmts[] = {
 	P010_UBWC_FMTS,
 	{0, 0},
 };
+
+static const struct sde_format_extended fp16_formats[] = {
+	{DRM_FORMAT_ARGB16161616F, 0},
+	{DRM_FORMAT_ARGB16161616F, DRM_FORMAT_MOD_QCOM_ALPHA_SWAP},
+	{DRM_FORMAT_ABGR16161616F, 0},
+	{DRM_FORMAT_ABGR16161616F, DRM_FORMAT_MOD_QCOM_ALPHA_SWAP},
+	{DRM_FORMAT_ABGR16161616F, DRM_FORMAT_MOD_QCOM_COMPRESSED},
+	{0, 0}
+};
+
+static const struct sde_format_extended fp_16_inline_rot_fmts[] = {
+	{DRM_FORMAT_ABGR16161616F, DRM_FORMAT_MOD_QCOM_COMPRESSED},
+	{0, 0}
+};
+

+ 196 - 1
msm/sde/sde_hw_color_proc_v4.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
  */
 #include <drm/msm_drm_pp.h>
 #include "sde_hw_color_proc_common_v4.h"
@@ -413,3 +413,198 @@ void sde_demura_backlight_cfg(struct sde_hw_dspp *dspp, u64 val)
 	SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->demura.base + 0x8,
 			backlight);
 }
+
+void sde_setup_fp16_cscv1(struct sde_hw_pipe *ctx,
+		enum sde_sspp_multirect_index index, void *data)
+{
+	struct sde_hw_cp_cfg *hw_cfg = data;
+	struct drm_msm_fp16_csc *fp16_csc;
+	u32 csc_base, csc, i, offset = 0;
+
+	if (!ctx || !data || index == SDE_SSPP_RECT_MAX) {
+		DRM_ERROR("invalid parameter\tctx: %pK\tdata: %pK\tindex: %d\n",
+				ctx, data, index);
+		return;
+	}
+
+	if (index == SDE_SSPP_RECT_SOLO || index == SDE_SSPP_RECT_0)
+		csc_base = ctx->cap->sblk->fp16_csc_blk[0].base;
+	else
+		csc_base = ctx->cap->sblk->fp16_csc_blk[1].base;
+
+	if (!csc_base) {
+		DRM_ERROR("invalid offset for FP16 CSC CP block\tpipe: %d\tindex: %d\n",
+				ctx->idx, index);
+		return;
+	}
+
+	fp16_csc = (struct drm_msm_fp16_csc *)(hw_cfg->payload);
+	if (!fp16_csc)
+		goto write_base;
+
+	if (hw_cfg->len != sizeof(struct drm_msm_fp16_csc) ||
+			!hw_cfg->payload) {
+		DRM_ERROR("invalid hw_cfg payload\tpipe: %d\tindex: %d\tlen: %d\tpayload: %pK\n",
+				ctx->idx, index, hw_cfg->len, hw_cfg->payload);
+		return;
+	}
+
+	if (fp16_csc->cfg_param_0_len != FP16_CSC_CFG0_PARAM_LEN) {
+		DRM_ERROR("invalid param 0 length! Got: %d\tExpected: %d\tpipe: %d\tindex: %d\n",
+				fp16_csc->cfg_param_0_len, FP16_CSC_CFG0_PARAM_LEN,
+				ctx->idx, index);
+		return;
+	} else if (fp16_csc->cfg_param_1_len !=  FP16_CSC_CFG1_PARAM_LEN) {
+		DRM_ERROR("invalid param 1 length! Got: %d\tExpected: %d\tpipe: %d\tindex: %d\n",
+				fp16_csc->cfg_param_1_len, FP16_CSC_CFG1_PARAM_LEN,
+				ctx->idx, index);
+		return;
+	}
+
+	for (i = 0; i < (fp16_csc->cfg_param_0_len / 2); i++) {
+		offset += 0x4;
+		csc = fp16_csc->cfg_param_0[2 * i] & 0xFFFF;
+		csc |= (fp16_csc->cfg_param_0[2 * i + 1] & 0xFFFF) << 16;
+		SDE_REG_WRITE(&ctx->hw, csc_base + offset, csc);
+	}
+	for (i = 0; i < (fp16_csc->cfg_param_1_len / 2); i++) {
+		offset += 0x4;
+		csc = fp16_csc->cfg_param_1[2 * i] & 0xFFFF;
+		csc |= (fp16_csc->cfg_param_1[2 * i + 1] & 0xFFFF) << 16;
+		SDE_REG_WRITE(&ctx->hw, csc_base + offset, csc);
+	}
+
+write_base:
+	csc = SDE_REG_READ(&ctx->hw, csc_base);
+	if (fp16_csc)
+		csc |= BIT(2);
+	else
+		csc &= ~BIT(2);
+
+	SDE_REG_WRITE(&ctx->hw, csc_base, csc);
+}
+
+void sde_setup_fp16_gcv1(struct sde_hw_pipe *ctx,
+		enum sde_sspp_multirect_index index, void *data)
+{
+	struct sde_hw_cp_cfg *hw_cfg = data;
+	struct drm_msm_fp16_gc *fp16_gc;
+	u32 gc_base, gc;
+
+	if (!ctx || !data || index == SDE_SSPP_RECT_MAX) {
+		DRM_ERROR("invalid parameter\tctx: %pK\tdata: %pK\tindex: %d\n",
+				ctx, data, index);
+		return;
+	}
+
+	fp16_gc = (struct drm_msm_fp16_gc *)(hw_cfg->payload);
+	if (fp16_gc && (hw_cfg->len != sizeof(struct drm_msm_fp16_gc) ||
+			fp16_gc->mode == FP16_GC_MODE_INVALID)) {
+		DRM_ERROR("invalid hw_cfg payload\tpipe: %d\tindex: %d\tlen: %d\tmode: %d",
+				ctx->idx, index, hw_cfg->len, fp16_gc->mode);
+		return;
+	}
+
+	if (index == SDE_SSPP_RECT_SOLO || index == SDE_SSPP_RECT_0)
+		gc_base = ctx->cap->sblk->fp16_gc_blk[0].base;
+	else
+		gc_base = ctx->cap->sblk->fp16_gc_blk[1].base;
+
+	if (!gc_base) {
+		DRM_ERROR("invalid offset for FP16 GC CP block\tpipe: %d\tindex: %d\n",
+				ctx->idx, index);
+		return;
+	}
+
+	gc = SDE_REG_READ(&ctx->hw, gc_base);
+	gc &= ~0xF8;
+
+	if (fp16_gc) {
+		gc |= BIT(4);
+		if (fp16_gc->flags & FP16_GC_FLAG_ALPHA_EN)
+			gc |= BIT(3);
+
+		if (fp16_gc->mode == FP16_GC_MODE_PQ)
+			gc |= BIT(5);
+	}
+
+	SDE_REG_WRITE(&ctx->hw, gc_base, gc);
+}
+
+void sde_setup_fp16_igcv1(struct sde_hw_pipe *ctx,
+		enum sde_sspp_multirect_index index, void *data)
+{
+	struct sde_hw_cp_cfg *hw_cfg = data;
+	bool *fp16_igc;
+	u32 igc_base, igc;
+
+	if (!ctx || !data || index == SDE_SSPP_RECT_MAX) {
+		DRM_ERROR("invalid parameter\tctx: %pK\tdata: %pK\tindex: %d\n",
+				ctx, data, index);
+		return;
+	} else if (hw_cfg->len != sizeof(bool)) {
+		DRM_ERROR("invalid hw_cfg payload\tpipe: %d\tindex: %d\tlen: %d",
+				ctx->idx, index, hw_cfg->len);
+		return;
+	}
+
+	if (index == SDE_SSPP_RECT_SOLO || index == SDE_SSPP_RECT_0)
+		igc_base = ctx->cap->sblk->fp16_igc_blk[0].base;
+	else
+		igc_base = ctx->cap->sblk->fp16_igc_blk[1].base;
+
+	if (!igc_base) {
+		DRM_ERROR("invalid offset for FP16 IGC CP block\tpipe: %d\tindex: %d\n",
+				ctx->idx, index);
+		return;
+	}
+
+	igc = SDE_REG_READ(&ctx->hw, igc_base);
+	fp16_igc = (bool *)(hw_cfg->payload);
+
+	if (fp16_igc && *fp16_igc)
+		igc |= BIT(1);
+	else
+		igc &= ~BIT(1);
+
+	SDE_REG_WRITE(&ctx->hw, igc_base, igc);
+}
+
+void sde_setup_fp16_unmultv1(struct sde_hw_pipe *ctx,
+		enum sde_sspp_multirect_index index, void *data)
+{
+	struct sde_hw_cp_cfg *hw_cfg = data;
+	bool *fp16_unmult;
+	u32 unmult_base, unmult;
+
+	if (!ctx || !data || index == SDE_SSPP_RECT_MAX) {
+		DRM_ERROR("invalid parameter\tctx: %pK\tdata: %pK\tindex: %d\n",
+				ctx, data, index);
+		return;
+	} else if (hw_cfg->len != sizeof(bool)) {
+		DRM_ERROR("invalid hw_cfg payload\tpipe: %d\tindex: %d\tlen: %d",
+				ctx->idx, index, hw_cfg->len);
+		return;
+	}
+
+	if (index == SDE_SSPP_RECT_SOLO || index == SDE_SSPP_RECT_0)
+		unmult_base = ctx->cap->sblk->fp16_unmult_blk[0].base;
+	else
+		unmult_base = ctx->cap->sblk->fp16_unmult_blk[1].base;
+
+	if (!unmult_base) {
+		DRM_ERROR("invalid offset for FP16 UNMULT CP block\tpipe: %d\tindex: %d\n",
+				ctx->idx, index);
+		return;
+	}
+
+	unmult = SDE_REG_READ(&ctx->hw, unmult_base);
+	fp16_unmult = (bool *)(hw_cfg->payload);
+
+	if (fp16_unmult && *fp16_unmult)
+		unmult |= BIT(0);
+	else
+		unmult &= ~BIT(0);
+
+	SDE_REG_WRITE(&ctx->hw, unmult_base, unmult);
+}

+ 38 - 1
msm/sde/sde_hw_color_proc_v4.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
  */
 #ifndef _SDE_HW_COLOR_PROC_V4_H_
 #define _SDE_HW_COLOR_PROC_V4_H_
@@ -8,6 +8,8 @@
 #include "sde_hw_util.h"
 #include "sde_hw_catalog.h"
 #include "sde_hw_dspp.h"
+#include "sde_hw_sspp.h"
+
 /**
  * sde_setup_dspp_3d_gamutv4 - Function for 3d gamut v4 version feature
  *                             programming.
@@ -77,4 +79,39 @@ void sde_ltm_read_intr_status(struct sde_hw_dspp *dspp, u32 *status);
  */
 void sde_demura_backlight_cfg(struct sde_hw_dspp *dspp, u64 val);
 
+/**
+ * sde_setup_fp16_cscv1 - api to set FP16 CSC cp block
+ * @ctx: pointer to pipe object
+ * @index: pipe rectangle to operate on
+ * @data: pointer to sde_hw_cp_cfg object containing drm_msm_fp16_csc data
+ */
+void sde_setup_fp16_cscv1(struct sde_hw_pipe *ctx,
+		enum sde_sspp_multirect_index index, void *data);
+
+/**
+ * sde_setup_fp16_gcv1 - api to set FP16 GC cp block
+ * @ctx: pointer to pipe object
+ * @index: pipe rectangle to operate on
+ * @data: pointer to sde_hw_cp_cfg object containing drm_msm_fp16_gc data
+ */
+void sde_setup_fp16_gcv1(struct sde_hw_pipe *ctx,
+		enum sde_sspp_multirect_index index, void *data);
+
+/**
+ * sde_setup_fp16_igcv1 - api to set FP16 IGC cp block
+ * @ctx: pointer to pipe object
+ * @index: pipe rectangle to operate on
+ * @data: pointer to sde_hw_cp_cfg object containing bool data
+ */
+void sde_setup_fp16_igcv1(struct sde_hw_pipe *ctx,
+		enum sde_sspp_multirect_index index, void *data);
+
+/**
+ * sde_setup_fp16_unmultv1 - api to set FP16 UNMULT cp block
+ * @ctx: pointer to pipe object
+ * @index: pipe rectangle to operate on
+ * @data: pointer to sde_hw_cp_cfg object containing bool data
+ */
+void sde_setup_fp16_unmultv1(struct sde_hw_pipe *ctx,
+		enum sde_sspp_multirect_index index, void *data);
 #endif /* _SDE_HW_COLOR_PROC_V4_H_ */

+ 10 - 1
msm/sde/sde_hw_mdss.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
  */
 
 #ifndef _SDE_HW_MDSS_H
@@ -43,12 +43,16 @@ enum sde_format_flags {
 	SDE_FORMAT_FLAG_YUV_BIT,
 	SDE_FORMAT_FLAG_DX_BIT,
 	SDE_FORMAT_FLAG_COMPRESSED_BIT,
+	SDE_FORMAT_FLAG_ALPHA_SWAP_BIT,
+	SDE_FORMAT_FLAG_FP16_BIT,
 	SDE_FORMAT_FLAG_BIT_MAX,
 };
 
 #define SDE_FORMAT_FLAG_YUV		BIT(SDE_FORMAT_FLAG_YUV_BIT)
 #define SDE_FORMAT_FLAG_DX		BIT(SDE_FORMAT_FLAG_DX_BIT)
 #define SDE_FORMAT_FLAG_COMPRESSED	BIT(SDE_FORMAT_FLAG_COMPRESSED_BIT)
+#define SDE_FORMAT_FLAG_ALPHA_SWAP	BIT(SDE_FORMAT_FLAG_ALPHA_SWAP_BIT)
+#define SDE_FORMAT_FLAG_FP16		BIT(SDE_FORMAT_FLAG_FP16_BIT)
 #define SDE_FORMAT_IS_YUV(X)		\
 	(test_bit(SDE_FORMAT_FLAG_YUV_BIT, (X)->flag))
 #define SDE_FORMAT_IS_DX(X)		\
@@ -60,6 +64,10 @@ enum sde_format_flags {
 #define SDE_FORMAT_IS_UBWC(X) \
 	(((X)->fetch_mode == SDE_FETCH_UBWC) && \
 			test_bit(SDE_FORMAT_FLAG_COMPRESSED_BIT, (X)->flag))
+#define SDE_FORMAT_IS_ALPHA_SWAPPED(X) \
+	(test_bit(SDE_FORMAT_FLAG_ALPHA_SWAP_BIT, (X)->flag))
+#define SDE_FORMAT_IS_FP16(X) \
+	(test_bit(SDE_FORMAT_FLAG_FP16_BIT, (X)->flag))
 
 #define SDE_BLEND_FG_ALPHA_FG_CONST	(0 << 0)
 #define SDE_BLEND_FG_ALPHA_BG_CONST	(1 << 0)
@@ -402,6 +410,7 @@ enum {
 	COLOR_5BIT = 1, /* No 5-bit Alpha */
 	COLOR_6BIT = 2, /* 6-Bit Alpha also = 2 */
 	COLOR_8BIT = 3, /* 8-Bit Alpha also = 3 */
+	COLOR_16BIT = 3,
 };
 
 /**

+ 25 - 2
msm/sde/sde_hw_sspp.c

@@ -359,8 +359,15 @@ static void sde_hw_sspp_setup_format(struct sde_hw_pipe *ctx,
 		(fmt->element[1] << 8) | (fmt->element[0] << 0);
 	src_format |= ((fmt->unpack_count - 1) << 12) |
 		(fmt->unpack_tight << 17) |
-		(fmt->unpack_align_msb << 18) |
-		((fmt->bpp - 1) << 9);
+		(fmt->unpack_align_msb << 18);
+
+	if (SDE_FORMAT_IS_FP16(fmt)) {
+		src_format |= BIT(16) | BIT(10) | BIT(9);
+	} else if (fmt->bpp <= 4) {
+		src_format |= ((fmt->bpp - 1) << 9);
+	} else if (fmt->bpp <= 8) {
+		src_format |=  BIT(16) | ((fmt->bpp - 5) << 9);
+	}
 
 	if ((flags & SDE_SSPP_ROT_90) && test_bit(SDE_SSPP_INLINE_CONST_CLR,
 			&ctx->cap->features))
@@ -1192,6 +1199,22 @@ static void _setup_layer_ops_colorproc(struct sde_hw_pipe *c,
 				c->ops.setup_dma_gc = NULL;
 		}
 	}
+
+	if (test_bit(SDE_SSPP_FP16_IGC, &features) &&
+			IS_SDE_CP_VER_1_0(c->cap->sblk->fp16_igc_blk[0].version))
+		c->ops.setup_fp16_igc = sde_setup_fp16_igcv1;
+
+	if (test_bit(SDE_SSPP_FP16_GC, &features) &&
+			IS_SDE_CP_VER_1_0(c->cap->sblk->fp16_gc_blk[0].version))
+		c->ops.setup_fp16_gc = sde_setup_fp16_gcv1;
+
+	if (test_bit(SDE_SSPP_FP16_CSC, &features) &&
+			IS_SDE_CP_VER_1_0(c->cap->sblk->fp16_csc_blk[0].version))
+		c->ops.setup_fp16_csc = sde_setup_fp16_cscv1;
+
+	if (test_bit(SDE_SSPP_FP16_UNMULT, &features) &&
+			IS_SDE_CP_VER_1_0(c->cap->sblk->fp16_unmult_blk[0].version))
+		c->ops.setup_fp16_unmult = sde_setup_fp16_unmultv1;
 }
 
 static void sde_hw_sspp_setup_inverse_pma(struct sde_hw_pipe *ctx,

+ 36 - 0
msm/sde/sde_hw_sspp.h

@@ -618,6 +618,42 @@ struct sde_hw_sspp_ops {
 	 * @multirect_index: rec in use
 	 */
 	u32 (*get_ubwc_error)(struct sde_hw_pipe *ctx, uint32_t multirect_index);
+
+	/**
+	 * setup_fp16_csc - set FP16 CSC cp block
+	 * @ctx: Pointer to pipe object
+	 * @index: Pipe rectangle to operate on
+	 * @data: Pointer to sde_hw_cp_cfg object holding drm_msm_fp16_csc data
+	 */
+	void (*setup_fp16_csc)(struct sde_hw_pipe *ctx,
+		enum sde_sspp_multirect_index index, void *data);
+
+	/**
+	 * sde_setup_fp16_gcv1 - set FP16 GC cp block
+	 * @ctx: Pointer to pipe object
+	 * @index: Pipe rectangle to operate on
+	 * @data: Pointer to sde_hw_cp_cfg object holding drm_msm_fp16_gc data
+	 */
+	void (*setup_fp16_gc)(struct sde_hw_pipe *ctx,
+		enum sde_sspp_multirect_index index, void *data);
+
+	/**
+	 * sde_setup_fp16_igcv1 - set FP16 IGC cp block
+	 * @ctx: Pointer to pipe object
+	 * @index: Pipe rectangle to operate on
+	 * @data: Pointer to sde_hw_cp_cfg object containing bool data
+	 */
+	void (*setup_fp16_igc)(struct sde_hw_pipe *ctx,
+		enum sde_sspp_multirect_index index, void *data);
+
+	/**
+	 * sde_setup_fp16_unmultv1 - set FP16 UNMULT cp block
+	 * @ctx: Pointer to pipe object
+	 * @index: Pipe rectangle to operate on
+	 * @data: Pointer to sde_hw_cp_cfg object containing bool data
+	 */
+	void (*setup_fp16_unmult)(struct sde_hw_pipe *ctx,
+		enum sde_sspp_multirect_index index, void *data);
 };
 
 /**

+ 95 - 3
msm/sde/sde_plane.c

@@ -101,7 +101,7 @@ struct sde_plane {
 	struct mutex lock;
 
 	enum sde_sspp pipe;
-	uint32_t features;      /* capabilities from catalog */
+	uint64_t features;      /* capabilities from catalog */
 	uint32_t perf_features; /* perf capabilities from catalog */
 	uint32_t nformats;
 	uint32_t formats[64];
@@ -1156,6 +1156,9 @@ static void sde_color_process_plane_setup(struct drm_plane *plane)
 	size_t memcol_sz = 0, size = 0;
 	struct sde_hw_cp_cfg hw_cfg = {};
 	struct sde_hw_ctl *ctl = _sde_plane_get_hw_ctl(plane);
+	bool fp16_igc, fp16_unmult;
+	struct drm_msm_fp16_gc *fp16_gc = NULL;
+	struct drm_msm_fp16_csc *fp16_csc = NULL;
 
 	psde = to_sde_plane(plane);
 	pstate = to_sde_plane_state(plane->state);
@@ -1255,6 +1258,58 @@ static void sde_color_process_plane_setup(struct drm_plane *plane)
 		psde->pipe_hw->ops.setup_dma_gc(psde->pipe_hw, &hw_cfg,
 				pstate->multirect_index);
 	}
+
+	if (pstate->dirty & SDE_PLANE_DIRTY_FP16_IGC &&
+			psde->pipe_hw->ops.setup_fp16_igc) {
+		fp16_igc = !!sde_plane_get_property(pstate,
+				PLANE_PROP_FP16_IGC);
+		hw_cfg.last_feature = 0;
+		hw_cfg.ctl = ctl;
+		hw_cfg.len = sizeof(bool);
+		hw_cfg.payload = &fp16_igc;
+		psde->pipe_hw->ops.setup_fp16_igc(psde->pipe_hw,
+				pstate->multirect_index, &hw_cfg);
+	}
+
+	if (pstate->dirty & SDE_PLANE_DIRTY_FP16_GC &&
+			psde->pipe_hw->ops.setup_fp16_gc) {
+		fp16_gc = msm_property_get_blob(&psde->property_info,
+				&pstate->property_state,
+				&size,
+				PLANE_PROP_FP16_GC);
+		hw_cfg.last_feature = 0;
+		hw_cfg.ctl = ctl;
+		hw_cfg.len = size;
+		hw_cfg.payload = fp16_gc;
+		psde->pipe_hw->ops.setup_fp16_gc(psde->pipe_hw,
+				pstate->multirect_index, &hw_cfg);
+	}
+
+	if (pstate->dirty & SDE_PLANE_DIRTY_FP16_CSC &&
+			psde->pipe_hw->ops.setup_fp16_csc) {
+		fp16_csc = msm_property_get_blob(&psde->property_info,
+				&pstate->property_state,
+				&size,
+				PLANE_PROP_FP16_CSC);
+		hw_cfg.last_feature = 0;
+		hw_cfg.ctl = ctl;
+		hw_cfg.len = size;
+		hw_cfg.payload = fp16_csc;
+		psde->pipe_hw->ops.setup_fp16_csc(psde->pipe_hw,
+				pstate->multirect_index, &hw_cfg);
+	}
+
+	if (pstate->dirty & SDE_PLANE_DIRTY_FP16_UNMULT &&
+			psde->pipe_hw->ops.setup_fp16_unmult) {
+		fp16_unmult = !!sde_plane_get_property(pstate,
+				PLANE_PROP_FP16_UNMULT);
+		hw_cfg.last_feature = 0;
+		hw_cfg.ctl = ctl;
+		hw_cfg.len = sizeof(bool);
+		hw_cfg.payload = &fp16_unmult;
+		psde->pipe_hw->ops.setup_fp16_unmult(psde->pipe_hw,
+				pstate->multirect_index, &hw_cfg);
+	}
 }
 
 static void _sde_plane_setup_scaler(struct sde_plane *psde,
@@ -2840,6 +2895,11 @@ static void _sde_plane_map_prop_to_dirty_bits(void)
 	plane_prop_array[PLANE_PROP_VALUE_ADJUST] =
 	plane_prop_array[PLANE_PROP_CONTRAST_ADJUST] =
 		SDE_PLANE_DIRTY_ALL;
+
+	plane_prop_array[PLANE_PROP_FP16_IGC] = SDE_PLANE_DIRTY_FP16_IGC;
+	plane_prop_array[PLANE_PROP_FP16_GC] = SDE_PLANE_DIRTY_FP16_GC;
+	plane_prop_array[PLANE_PROP_FP16_CSC] = SDE_PLANE_DIRTY_FP16_CSC;
+	plane_prop_array[PLANE_PROP_FP16_UNMULT] = SDE_PLANE_DIRTY_FP16_UNMULT;
 }
 
 static inline bool _sde_plane_allow_uidle(struct sde_plane *psde,
@@ -3535,6 +3595,38 @@ static void _sde_plane_install_colorproc_properties(struct sde_plane *psde,
 		msm_property_install_blob(&psde->property_info, feature_name, 0,
 			PLANE_PROP_DMA_GC);
 	}
+
+	if (psde->features & BIT(SDE_SSPP_FP16_IGC)) {
+		snprintf(feature_name, sizeof(feature_name), "%s%d",
+			"SDE_SSPP_FP16_IGC_V",
+			psde->pipe_sblk->fp16_igc_blk[0].version >> 16);
+		msm_property_install_range(&psde->property_info, feature_name,
+				0x0, 0, 1, 0, PLANE_PROP_FP16_IGC);
+	}
+
+	if (psde->features & BIT(SDE_SSPP_FP16_GC)) {
+		snprintf(feature_name, sizeof(feature_name), "%s%d",
+			"SDE_SSPP_FP16_GC_V",
+			psde->pipe_sblk->fp16_gc_blk[0].version >> 16);
+		msm_property_install_blob(&psde->property_info, feature_name, 0,
+			PLANE_PROP_FP16_GC);
+	}
+
+	if (psde->features & BIT(SDE_SSPP_FP16_CSC)) {
+		snprintf(feature_name, sizeof(feature_name), "%s%d",
+			"SDE_SSPP_FP16_CSC_V",
+			psde->pipe_sblk->fp16_csc_blk[0].version >> 16);
+		msm_property_install_blob(&psde->property_info, feature_name, 0,
+			PLANE_PROP_FP16_CSC);
+	}
+
+	if (psde->features & BIT(SDE_SSPP_FP16_UNMULT)) {
+		snprintf(feature_name, sizeof(feature_name), "%s%d",
+			"SDE_SSPP_FP16_UNMULT_V",
+			psde->pipe_sblk->fp16_unmult_blk[0].version >> 16);
+		msm_property_install_range(&psde->property_info, feature_name,
+			0x0, 0, 1, 0, PLANE_PROP_FP16_UNMULT);
+	}
 }
 
 static void _sde_plane_setup_capabilities_blob(struct sde_plane *psde,
@@ -4476,7 +4568,7 @@ static int _sde_plane_init_debugfs(struct drm_plane *plane)
 		return -ENOMEM;
 
 	/* don't error check these */
-	debugfs_create_x32("features", 0400,
+	debugfs_create_x64("features", 0400,
 		psde->debugfs_root, &psde->features);
 
 	if (cfg->features & BIT(SDE_SSPP_SCALER_QSEED3) ||
@@ -4655,7 +4747,7 @@ struct drm_plane *sde_plane_init(struct drm_device *dev,
 	}
 
 	/* cache features mask for later */
-	psde->features = psde->pipe_hw->cap->features;
+	psde->features = psde->pipe_hw->cap->features_ext;
 	psde->perf_features = psde->pipe_hw->cap->perf_features;
 	psde->pipe_sblk = psde->pipe_hw->cap->sblk;
 	if (!psde->pipe_sblk) {

+ 7 - 1
msm/sde/sde_plane.h

@@ -38,9 +38,15 @@
 #define SDE_PLANE_DIRTY_DMA_IGC 0x80
 #define SDE_PLANE_DIRTY_DMA_GC 0x100
 #define SDE_PLANE_DIRTY_QOS     0x200
+#define SDE_PLANE_DIRTY_FP16_IGC 0x400
+#define SDE_PLANE_DIRTY_FP16_GC 0x800
+#define SDE_PLANE_DIRTY_FP16_CSC 0x1000
+#define SDE_PLANE_DIRTY_FP16_UNMULT 0x2000
 #define SDE_PLANE_DIRTY_CP (SDE_PLANE_DIRTY_VIG_GAMUT |\
 		SDE_PLANE_DIRTY_VIG_IGC | SDE_PLANE_DIRTY_DMA_IGC |\
-		SDE_PLANE_DIRTY_DMA_GC)
+		SDE_PLANE_DIRTY_DMA_GC | SDE_PLANE_DIRTY_FP16_IGC |\
+		SDE_PLANE_DIRTY_FP16_GC | SDE_PLANE_DIRTY_FP16_CSC |\
+		SDE_PLANE_DIRTY_FP16_UNMULT)
 #define SDE_PLANE_DIRTY_ALL	(0xFFFFFFFF & ~(SDE_PLANE_DIRTY_CP))
 
 /**