Ver código fonte

Merge "disp: msm: sde: update regdma offsets through target dtsi property"

qctecmdr 4 anos atrás
pai
commit
a49d0d9ce1

+ 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;

+ 302 - 110
msm/sde/sde_hw_catalog.c

@@ -156,6 +156,8 @@
 #define SDE_UIDLE_MAX_FPS_60 60
 #define SDE_UIDLE_MAX_FPS_90 90
 
+#define SSPP_GET_REGDMA_BASE(blk_base, top_off) ((blk_base) >= (top_off) ?\
+		(blk_base) - (top_off) : (blk_base))
 
 /*************************************************************
  *  DTSI PROPERTY INDEX
@@ -267,6 +269,8 @@ enum {
 };
 
 enum {
+	VIG_SUBBLOCK_INDEX,
+	VIG_TOP_OFF,
 	VIG_QSEED_OFF,
 	VIG_QSEED_LEN,
 	VIG_CSC_OFF,
@@ -276,6 +280,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,
 };
 
@@ -287,10 +295,16 @@ enum {
 };
 
 enum {
+	DMA_SUBBLOCK_INDEX,
+	DMA_TOP_OFF,
 	DMA_IGC_PROP,
 	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,
 };
 
@@ -663,16 +677,36 @@ 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_TOP_OFF] = {VIG_TOP_OFF, "qcom,sde-vig-top-off", 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[] = {
@@ -682,11 +716,26 @@ static struct sde_prop_type rgb_prop[] = {
 };
 
 static struct sde_prop_type dma_prop[] = {
-	{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_TOP_OFF] = {DMA_TOP_OFF, "qcom,sde-dma-top-off", 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[] = {
@@ -1317,83 +1366,59 @@ 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);
+		blk->regdma_base = SSPP_GET_REGDMA_BASE(blk->base, sspp->sblk->top_off);
+		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);
@@ -1402,21 +1427,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;
@@ -1441,23 +1504,69 @@ static int _sde_sspp_setup_vigs(struct device_node *np,
 			set_bit(SDE_PERF_SSPP_QOS_8LVL, &sspp->perf_features);
 		vig_count++;
 
+		/* Obtain sub block top, or maintain backwards compatibility */
+		if (props[0] && props[0]->exists[VIG_TOP_OFF])
+			sblk->top_off = PROP_VALUE_ACCESS(props[0]->values, VIG_TOP_OFF, 0);
+		else
+			sblk->top_off = 0x200;
+
 		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);
+			sblk->scaler_blk.regdma_base = SSPP_GET_REGDMA_BASE(sblk->scaler_blk.base,
+					sblk->top_off);
 			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);
@@ -1501,8 +1610,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,
@@ -1610,6 +1723,7 @@ static void _sde_sspp_setup_dgm(struct sde_sspp_cfg *sspp,
 	blk->len = 0;
 	set_bit(type, &sspp->features);
 	blk->base = PROP_VALUE_ACCESS(props->values, prop, 0);
+	blk->regdma_base = SSPP_GET_REGDMA_BASE(blk->base, sspp->sblk->top_off);
 	snprintf(blk->name, SDE_HW_BLK_NAME_LEN, "%s%u", name,
 			sspp->id - SSPP_DMA0);
 	if (versioned)
@@ -1622,6 +1736,7 @@ static int _sde_sspp_setup_dmas(struct device_node *np,
 	int i = 0, j;
 	int rc = 0, dma_count = 0, dgm_count = 0;
 	struct sde_dt_props *props[SSPP_SUBBLK_COUNT_MAX] = {NULL, NULL};
+	struct sde_dt_props *props_tmp = NULL;
 	struct device_node *snp = NULL;
 	const char *type;
 
@@ -1631,23 +1746,35 @@ static int _sde_sspp_setup_dmas(struct device_node *np,
 		if (dgm_count > 0) {
 			struct device_node *dgm_snp;
 
-			if (dgm_count > SSPP_SUBBLK_COUNT_MAX)
-				dgm_count = SSPP_SUBBLK_COUNT_MAX;
+			if (dgm_count > SSPP_SUBBLK_COUNT_MAX) {
+				SDE_ERROR("too many dgm subblocks defined");
+				goto end;
+			}
 
 			for_each_child_of_node(snp, dgm_snp) {
-				if (i >= SSPP_SUBBLK_COUNT_MAX)
-					break;
-
-				props[i] = sde_get_dt_props(dgm_snp,
+				props_tmp = sde_get_dt_props(dgm_snp,
 						DMA_PROP_MAX, dma_prop,
 						ARRAY_SIZE(dma_prop), NULL);
-				if (IS_ERR(props[i])) {
-					rc = PTR_ERR(props[i]);
-					props[i] = NULL;
+				if (IS_ERR(props_tmp)) {
+					rc = PTR_ERR(props_tmp);
+					props_tmp = NULL;
+					goto end;
+				} else if (!props_tmp->exists[DMA_SUBBLOCK_INDEX]) {
+					SDE_ERROR("dgm sub-block index must be defined");
 					goto end;
 				}
 
-				i++;
+				i = PROP_VALUE_ACCESS(props_tmp->values, DMA_SUBBLOCK_INDEX, 0);
+				if (i >= SSPP_SUBBLK_COUNT_MAX) {
+					SDE_ERROR("dgm sub-block index greater than max: %d", i);
+					goto end;
+				} else if (props[i] != NULL) {
+					SDE_ERROR("dgm sub-block index already defined: %d", i);
+					goto end;
+				}
+
+				props[i] = props_tmp;
+				props_tmp = NULL;
 			}
 		}
 	}
@@ -1675,10 +1802,19 @@ static int _sde_sspp_setup_dmas(struct device_node *np,
 			set_bit(SDE_PERF_SSPP_QOS_8LVL, &sspp->perf_features);
 		dma_count++;
 
+		/* Obtain sub block top, or maintain backwards compatibility */
+		if (props[0] && props[0]->exists[DMA_TOP_OFF])
+			sblk->top_off = PROP_VALUE_ACCESS(props[0]->values, DMA_TOP_OFF, 0);
+		else
+			sblk->top_off = 0x200;
+
 		sblk->num_igc_blk = dgm_count;
 		sblk->num_gc_blk = dgm_count;
 		sblk->num_dgm_csc_blk = dgm_count;
-		for (j = 0; j < dgm_count; j++) {
+		for (j = 0; j < SSPP_SUBBLK_COUNT_MAX; j++) {
+			if (props[j] == NULL)
+				continue;
+
 			if (props[j]->exists[DMA_IGC_PROP])
 				_sde_sspp_setup_dgm(sspp, props[j],
 					"sspp_dma_igc", &sblk->igc_blk[j],
@@ -1698,12 +1834,41 @@ 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);
 		}
 	}
 
 end:
-	for (i = 0; i < dgm_count; i++)
+	for (i = 0; i < SSPP_SUBBLK_COUNT_MAX; i++)
 		sde_put_dt_props(props[i]);
+	sde_put_dt_props(props_tmp);
 
 	return rc;
 }
@@ -4410,6 +4575,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) {
@@ -4419,11 +4587,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) {
@@ -4437,9 +4611,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) {
@@ -4449,6 +4629,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);
@@ -4473,6 +4657,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) {
@@ -4483,6 +4670,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;
@@ -4837,6 +5028,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;

+ 40 - 2
msm/sde/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
 
@@ -258,6 +261,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 {
@@ -290,6 +297,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
 };
 
@@ -585,7 +596,10 @@ enum {
 	u32 id; \
 	u32 base; \
 	u32 len; \
-	unsigned long features; \
+	union { \
+		unsigned long features; \
+		u64 features_ext; \
+	}; \
 	unsigned long perf_features
 
 /**
@@ -613,12 +627,14 @@ struct sde_src_blk {
 /**
  * struct sde_scaler_blk: Scaler information
  * @info:   HW register and features supported by this sub-blk
+ * @regdma_base: offset of this sub-block relative regdma top
  * @version: qseed block revision
  * @h_preload: horizontal preload
  * @v_preload: vertical preload
  */
 struct sde_scaler_blk {
 	SDE_HW_SUBBLK_INFO;
+	u32 regdma_base;
 	u32 version;
 	u32 h_preload;
 	u32 v_preload;
@@ -630,11 +646,13 @@ struct sde_csc_blk {
 
 /**
  * struct sde_pp_blk : Pixel processing sub-blk information
+ * @regdma_base: offset of this sub-block relative regdma top
  * @info:   HW register and features supported by this sub-blk
  * @version: HW Algorithm version
  */
 struct sde_pp_blk {
 	SDE_HW_SUBBLK_INFO;
+	u32 regdma_base;
 	u32 version;
 };
 
@@ -692,6 +710,7 @@ enum sde_qos_lut_usage {
  * @max_per_pipe_bw: maximum allowable bandwidth of this pipe in kBps
  * @max_per_pipe_bw_high: maximum allowable bandwidth of this pipe in kBps
  *				in case of no VFE
+ * @top_off: offset of the sub-block top register relative to sspp top
  * @src_blk:
  * @scaler_blk:
  * @csc_blk:
@@ -705,6 +724,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
@@ -734,6 +761,7 @@ struct sde_sspp_sub_blks {
 	u32 smart_dma_priority;
 	u32 max_per_pipe_bw;
 	u32 max_per_pipe_bw_high;
+	u32 top_off;
 	struct sde_src_blk src_blk;
 	struct sde_scaler_blk scaler_blk;
 	struct sde_pp_blk csc_blk;
@@ -747,6 +775,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;
@@ -1452,8 +1488,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
@@ -1529,6 +1566,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_ */

+ 9 - 0
msm/sde/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 MDP_TICK_COUNT                    16
 #define XO_CLK_RATE                       19200
@@ -409,6 +417,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,
 };
 
 /**

+ 12 - 16
msm/sde/sde_hw_reg_dma_v1_color_proc.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>
@@ -15,8 +15,6 @@
 
 /* Reserve space of 128 words for LUT dma payload set-up */
 #define REG_DMA_HEADERS_BUFFER_SZ (sizeof(u32) * 128)
-#define REG_DMA_VIG_SWI_DIFF 0x200
-#define REG_DMA_DMA_SWI_DIFF 0x200
 
 #define VLUT_MEM_SIZE ((128 * sizeof(u32)) + REG_DMA_HEADERS_BUFFER_SZ)
 #define VLUT_LEN (128 * sizeof(u32))
@@ -2184,7 +2182,7 @@ static void vig_gamutv5_off(struct sde_hw_pipe *ctx, void *cfg)
 	struct sde_hw_reg_dma_ops *dma_ops;
 	struct sde_reg_dma_setup_ops_cfg dma_write_cfg;
 	struct sde_reg_dma_kickoff_cfg kick_off;
-	u32 gamut_base = ctx->cap->sblk->gamut_blk.base - REG_DMA_VIG_SWI_DIFF;
+	u32 gamut_base = ctx->cap->sblk->gamut_blk.regdma_base;
 	enum sde_sspp_multirect_index idx = SDE_SSPP_RECT_0;
 
 	dma_ops = sde_reg_dma_get_ops();
@@ -2226,7 +2224,7 @@ void reg_dmav1_setup_vig_gamutv5(struct sde_hw_pipe *ctx, void *cfg)
 	struct sde_hw_reg_dma_ops *dma_ops;
 	struct sde_reg_dma_setup_ops_cfg dma_write_cfg;
 	struct sde_reg_dma_kickoff_cfg kick_off;
-	u32 gamut_base = ctx->cap->sblk->gamut_blk.base - REG_DMA_VIG_SWI_DIFF;
+	u32 gamut_base = ctx->cap->sblk->gamut_blk.regdma_base;
 	bool use_2nd_memory = false;
 	enum sde_sspp_multirect_index idx = SDE_SSPP_RECT_0;
 
@@ -2341,7 +2339,7 @@ static void vig_igcv5_off(struct sde_hw_pipe *ctx, void *cfg)
 	struct sde_hw_reg_dma_ops *dma_ops;
 	struct sde_reg_dma_setup_ops_cfg dma_write_cfg;
 	struct sde_reg_dma_kickoff_cfg kick_off;
-	u32 igc_base = ctx->cap->sblk->igc_blk[0].base - REG_DMA_VIG_SWI_DIFF;
+	u32 igc_base = ctx->cap->sblk->igc_blk[0].regdma_base;
 	enum sde_sspp_multirect_index idx = SDE_SSPP_RECT_0;
 
 	dma_ops = sde_reg_dma_get_ops();
@@ -2384,7 +2382,7 @@ static int reg_dmav1_setup_vig_igc_common(struct sde_hw_reg_dma_ops *dma_ops,
 	u32 offset = 0;
 	u32 lut_sel = 0, lut_enable = 0;
 	u32 *data = NULL, *data_ptr = NULL;
-	u32 igc_base = ctx->cap->sblk->igc_blk[0].base - REG_DMA_VIG_SWI_DIFF;
+	u32 igc_base = ctx->cap->sblk->igc_blk[0].regdma_base;
 	u32 *addr[IGC_TBL_NUM];
 
 	if (hw_cfg->len != sizeof(struct drm_msm_igc_lut)) {
@@ -2513,7 +2511,7 @@ void reg_dmav1_setup_vig_igcv6(struct sde_hw_pipe *ctx, void *cfg)
 	struct sde_hw_reg_dma_ops *dma_ops;
 	struct sde_reg_dma_kickoff_cfg kick_off;
 	struct sde_hw_cp_cfg *hw_cfg = cfg;
-	u32 igc_base = ctx->cap->sblk->igc_blk[0].base - REG_DMA_VIG_SWI_DIFF;
+	u32 igc_base = ctx->cap->sblk->igc_blk[0].regdma_base;
 	enum sde_sspp_multirect_index idx = SDE_SSPP_RECT_0;
 	struct drm_msm_igc_lut *igc_lut;
 	struct sde_reg_dma_setup_ops_cfg dma_write_cfg;
@@ -2668,13 +2666,11 @@ void reg_dmav1_setup_dma_igcv5(struct sde_hw_pipe *ctx, void *cfg,
 			((igc_lut->c2[2 * i + 1] & IGC_DATA_MASK) << 16);
 
 	if (idx == SDE_SSPP_RECT_SOLO || idx == SDE_SSPP_RECT_0) {
-		igc_base = ctx->cap->sblk->igc_blk[0].base -
-				REG_DMA_DMA_SWI_DIFF;
+		igc_base = ctx->cap->sblk->igc_blk[0].regdma_base;
 		igc_dither_off = igc_base + DMA_1D_LUT_IGC_DITHER_OFF;
 		igc_opmode_off = DMA_DGM_0_OP_MODE_OFF;
 	} else {
-		igc_base = ctx->cap->sblk->igc_blk[1].base -
-				REG_DMA_DMA_SWI_DIFF;
+		igc_base = ctx->cap->sblk->igc_blk[1].regdma_base;
 		igc_dither_off = igc_base + DMA_1D_LUT_IGC_DITHER_OFF;
 		igc_opmode_off = DMA_DGM_1_OP_MODE_OFF;
 	}
@@ -2809,10 +2805,10 @@ void reg_dmav1_setup_dma_gcv5(struct sde_hw_pipe *ctx, void *cfg,
 	}
 
 	if (idx == SDE_SSPP_RECT_SOLO || idx == SDE_SSPP_RECT_0) {
-		gc_base = ctx->cap->sblk->gc_blk[0].base - REG_DMA_DMA_SWI_DIFF;
+		gc_base = ctx->cap->sblk->gc_blk[0].regdma_base;
 		gc_opmode_off = DMA_DGM_0_OP_MODE_OFF;
 	} else {
-		gc_base = ctx->cap->sblk->gc_blk[1].base - REG_DMA_DMA_SWI_DIFF;
+		gc_base = ctx->cap->sblk->gc_blk[1].regdma_base;
 		gc_opmode_off = DMA_DGM_1_OP_MODE_OFF;
 	}
 
@@ -3092,7 +3088,7 @@ void reg_dmav1_setup_vig_qseed3(struct sde_hw_pipe *ctx,
 		return;
 	}
 
-	offset = ctx->cap->sblk->scaler_blk.base - REG_DMA_VIG_SWI_DIFF;
+	offset = ctx->cap->sblk->scaler_blk.regdma_base;
 	dma_ops = sde_reg_dma_get_ops();
 	dma_ops->reset_reg_dma_buf(sspp_buf[idx][QSEED][ctx->idx]);
 
@@ -4321,7 +4317,7 @@ void reg_dmav2_setup_vig_gamutv61(struct sde_hw_pipe *ctx, void *cfg)
 	int rc;
 	enum sde_sspp_multirect_index idx = SDE_SSPP_RECT_0;
 
-	u32 gamut_base = ctx->cap->sblk->gamut_blk.base - REG_DMA_VIG_SWI_DIFF;
+	u32 gamut_base = ctx->cap->sblk->gamut_blk.regdma_base;
 	u32 i, j, k = 0, len, table_select = 0;
 	u32 op_mode, scale_offset, scale_tbl_offset, transfer_size_bytes;
 	u16 *data;

+ 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))
 
 /**