drm/msm/sde: enable blending across all planes

Updates to sspp to enable dma pipe support, and adjust plane
property creation based on pipe availability. Enable support
for the BLEND_OP property within the crtc.

Change-Id: Iec063eb2a3b206fb3d66fb2a176536d7838b08bf
Signed-off-by: Clarence Ip <cip@codeaurora.org>
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 6110da8..dd653a46 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -79,7 +79,6 @@
 	/* range properties */
 	PLANE_PROP_ZPOS = PLANE_PROP_BLOBCOUNT,
 	PLANE_PROP_ALPHA,
-	PLANE_PROP_PREMULTIPLIED,
 	PLANE_PROP_H_DECIMATE,
 	PLANE_PROP_V_DECIMATE,
 	PLANE_PROP_SYNC_FENCE,
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index 313b82d..76d1d90 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -11,6 +11,7 @@
  */
 
 #include <linux/sort.h>
+#include <uapi/drm/sde_drm.h>
 #include <drm/drm_mode.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
@@ -199,52 +200,62 @@
 {
 	struct drm_plane *plane;
 	const struct mdp_format *format;
+	uint32_t blend_op;
 
 	format = to_mdp_format(
 			msm_framebuffer_format(pstate->base.fb));
 	plane = pstate->base.plane;
 
 	memset(cfg, 0, sizeof(*cfg));
-	cfg->fg.const_alpha = pstate->property_values[PLANE_PROP_ALPHA];
+
+	/* default to opaque blending */
+	cfg->fg.alpha_sel = ALPHA_FG_CONST;
+	cfg->bg.alpha_sel = ALPHA_BG_CONST;
+	cfg->fg.const_alpha =
+		sde_plane_get_property32(pstate, PLANE_PROP_ALPHA);
 	cfg->bg.const_alpha = 0xFF - cfg->fg.const_alpha;
 
-	if (format->alpha_enable &&
-			pstate->property_values[PLANE_PROP_PREMULTIPLIED]) {
-		cfg->fg.alpha_sel = ALPHA_FG_CONST;
-		cfg->bg.alpha_sel = ALPHA_FG_PIXEL;
-		if (pstate->property_values[PLANE_PROP_ALPHA] != 0xff) {
-			cfg->bg.const_alpha =
-				(u32)pstate->property_values[PLANE_PROP_ALPHA];
-			cfg->bg.inv_alpha_sel = 1;
-			cfg->bg.mod_alpha = 1;
-		} else {
-			cfg->bg.inv_mode_alpha = 1;
-		}
-	} else if (format->alpha_enable) {
-		cfg->fg.alpha_sel = ALPHA_FG_PIXEL;
-		cfg->bg.alpha_sel = ALPHA_FG_PIXEL;
-		if (pstate->property_values[PLANE_PROP_ALPHA] != 0xff) {
-			cfg->bg.const_alpha =
-				(u32)pstate->property_values[PLANE_PROP_ALPHA];
-			cfg->fg.mod_alpha = 1;
-			cfg->bg.inv_alpha_sel = 1;
-			cfg->bg.mod_alpha = 1;
-			cfg->bg.inv_mode_alpha = 1;
-		} else {
-			cfg->bg.inv_mode_alpha = 1;
+	blend_op = sde_plane_get_property32(pstate, PLANE_PROP_BLEND_OP);
+
+	if (format->alpha_enable) {
+		switch (blend_op) {
+		case SDE_DRM_BLEND_OP_PREMULTIPLIED:
+			cfg->fg.alpha_sel = ALPHA_FG_CONST;
+			cfg->bg.alpha_sel = ALPHA_FG_PIXEL;
+			if (cfg->fg.const_alpha != 0xff) {
+				cfg->bg.const_alpha = cfg->fg.const_alpha;
+				cfg->bg.mod_alpha = 1;
+				cfg->bg.inv_alpha_sel = 1;
+			} else {
+				cfg->bg.inv_mode_alpha = 1;
+			}
+			break;
+		case SDE_DRM_BLEND_OP_COVERAGE:
+			cfg->fg.alpha_sel = ALPHA_FG_PIXEL;
+			cfg->bg.alpha_sel = ALPHA_FG_PIXEL;
+			if (cfg->fg.const_alpha != 0xff) {
+				cfg->bg.const_alpha = cfg->fg.const_alpha;
+				cfg->fg.mod_alpha = 1;
+				cfg->bg.inv_alpha_sel = 1;
+				cfg->bg.mod_alpha = 1;
+				cfg->bg.inv_mode_alpha = 1;
+			} else {
+				cfg->bg.inv_mode_alpha = 1;
+			}
+			break;
+		default:
+			/* do nothing */
+			break;
 		}
 	} else {
-		/* opaque blending */
-		cfg->fg.alpha_sel = ALPHA_FG_CONST;
-		cfg->bg.alpha_sel = ALPHA_BG_CONST;
 		cfg->bg.inv_alpha_sel = 1;
 		cfg->fg.const_alpha = 0xFF;
 		cfg->bg.const_alpha = 0x00;
 	}
 
-	DBG("format 0x%x, alpha_enable %u premultiplied %llu",
+	DBG("format 0x%x, alpha_enable %u blend_op %u",
 			format->base.pixel_format, format->alpha_enable,
-			pstate->property_values[PLANE_PROP_PREMULTIPLIED]);
+			blend_op);
 	DBG("fg alpha config %d %d %d %d %d",
 		cfg->fg.alpha_sel, cfg->fg.const_alpha, cfg->fg.mod_alpha,
 		cfg->fg.inv_alpha_sel, cfg->fg.inv_mode_alpha);
@@ -290,7 +301,7 @@
 			pstate = to_sde_plane_state(plane->state);
 			stage_cfg.stage[pstate->stage][i] =
 				sde_plane_pipe(plane);
-			DBG(" crtc_id %d, layer %d, at stage %d\n",
+			DBG("crtc_id %d, layer %d, at stage %d",
 					sde_crtc->id,
 					sde_plane_pipe(plane),
 					pstate->stage);
@@ -566,8 +577,8 @@
 	struct plane_state *pa = (struct plane_state *)a;
 	struct plane_state *pb = (struct plane_state *)b;
 
-	return (int)pa->state->property_values[PLANE_PROP_ZPOS] -
-		(int)pb->state->property_values[PLANE_PROP_ZPOS];
+	return (int)sde_plane_get_property(pa->state, PLANE_PROP_ZPOS) -
+		(int)sde_plane_get_property(pb->state, PLANE_PROP_ZPOS);
 }
 
 static int sde_crtc_atomic_check(struct drm_crtc *crtc,
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog_8996.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog_8996.c
index 6e425ce..20e0cc5 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog_8996.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog_8996.c
@@ -58,6 +58,9 @@
 #define WB2_17X_MASK \
 	(BIT(SDE_WB_LINE_MODE) | BIT(SDE_WB_TRAFFIC_SHAPER))
 
+#define DECIMATION_17X_MAX_H	4
+#define DECIMATION_17X_MAX_V	4
+
 /**
  * set_cfg_1xx_init(): populate sde sub-blocks reg offsets and instance counts
  */
@@ -70,7 +73,8 @@
 		.danger_lut = 0xFFFF,
 		.safe_lut = 0xFF00,
 		.maxdwnscale = 4, .maxupscale = 20,
-		.maxhdeciexp = 4, .maxvdeciexp = 4,
+		.maxhdeciexp = DECIMATION_17X_MAX_H,
+		.maxvdeciexp = DECIMATION_17X_MAX_V,
 		.src_blk = {.id = SDE_SSPP_SRC,
 			.base = 0x00, .len = 0x150,},
 		.scaler_blk = {.id = SDE_SSPP_SCALER_QSEED2,
@@ -90,12 +94,13 @@
 		.danger_lut = 0xFFFF,
 		.safe_lut = 0xFF00,
 		.maxdwnscale = 0, .maxupscale = 0,
-		.maxhdeciexp = 4, .maxvdeciexp = 4,
-		.src_blk = {.id = SDE_SSPP_SRC, .base = 0x00, .len = 0x0,},
+		.maxhdeciexp = DECIMATION_17X_MAX_H,
+		.maxvdeciexp = DECIMATION_17X_MAX_V,
+		.src_blk = {.id = SDE_SSPP_SRC, .base = 0x00, .len = 0x150,},
 		.scaler_blk = {.id = 0, .base = 0x00, .len = 0x0,},
 		.csc_blk = {.id = 0, .base = 0x00, .len = 0x0,},
-		.pa_blk = {.id = 0, .base = 0x00, .len = 0x0,},
-		.hist_lut = {.id = 0, .base = 0x00, .len = 0x0,},
+		.pa_blk = {.id = 0, .base = 0x200, .len = 0x0,},
+		.hist_lut = {.id = 0, .base = 0xA00, .len = 0x0,},
 		.pcc_blk = {.id = SDE_SSPP_PCC, .base = 0x01780, .len = 0x64,},
 	};
 
@@ -104,8 +109,9 @@
 		.danger_lut = 0xFFFF,
 		.safe_lut = 0xFF00,
 		.maxdwnscale = 0, .maxupscale = 0,
-		.maxhdeciexp = 4, .maxvdeciexp = 4,
-		.src_blk = {.id = SDE_SSPP_SRC, .base = 0x00, .len = 0x0,},
+		.maxhdeciexp = DECIMATION_17X_MAX_H,
+		.maxvdeciexp = DECIMATION_17X_MAX_V,
+		.src_blk = {.id = SDE_SSPP_SRC, .base = 0x00, .len = 0x150,},
 		.scaler_blk = {.id = 0, .base = 0x00, .len = 0x0,},
 		.csc_blk = {.id = 0, .base = 0x00, .len = 0x0,},
 		.pa_blk = {.id = 0, .base = 0x00, .len = 0x0,},
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ctl.c b/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
index 2eac304..47c5cda 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
@@ -256,7 +256,7 @@
 				break;
 			case SSPP_VIG3:
 				mixercfg |= (i + 1) << 26;
-				mixercfg_ext |= ((i > SDE_STAGE_5) ? 1:0) << 4;
+				mixercfg_ext |= ((i > SDE_STAGE_5) ? 1:0) << 6;
 				break;
 			case SSPP_RGB0:
 				mixercfg |= (i + 1) << 9;
@@ -275,12 +275,12 @@
 				mixercfg_ext |= ((i > SDE_STAGE_5) ? 1:0) << 14;
 				break;
 			case SSPP_DMA0:
-				mixercfg |= (i + 1) << 0;
-				mixercfg_ext |= ((i > SDE_STAGE_5) ? 1:0) << 0;
+				mixercfg |= (i + 1) << 18;
+				mixercfg_ext |= ((i > SDE_STAGE_5) ? 1:0) << 16;
 				break;
 			case SSPP_DMA1:
-				mixercfg |= (i + 1) << 0;
-				mixercfg_ext |= ((i > SDE_STAGE_5) ? 1:0) << 0;
+				mixercfg |= (i + 1) << 21;
+				mixercfg_ext |= ((i > SDE_STAGE_5) ? 1:0) << 18;
 				break;
 			case SSPP_CURSOR0:
 				mixercfg_ext |= (i + 1) << 20;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_sspp.c b/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
index f998225..1c5089a 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
@@ -444,7 +444,8 @@
 	struct sde_hw_blk_reg_map *c;
 	u32 idx;
 
-	if (_sspp_subblk_offset(ctx, SDE_SSPP_SCALER_QSEED2, &idx) || !cfg)
+	if (_sspp_subblk_offset(ctx, SDE_SSPP_SCALER_QSEED2, &idx) || !cfg ||
+			!test_bit(SDE_SSPP_SCALER_QSEED2, &ctx->cap->features))
 		return;
 
 	c = &ctx->hw;
@@ -521,7 +522,7 @@
 		unsigned long features)
 {
 	if (test_bit(SDE_SSPP_SRC, &features)) {
-		ops->setup_sourceformat = sde_hw_sspp_setup_format;
+		ops->setup_format = sde_hw_sspp_setup_format;
 		ops->setup_rects = sde_hw_sspp_setup_rects;
 		ops->setup_sourceaddress = sde_hw_sspp_setup_sourceaddress;
 		ops->setup_solidfill = sde_hw_sspp_setup_solidfill;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_sspp.h b/drivers/gpu/drm/msm/sde/sde_hw_sspp.h
index db6f14f..6b1833b2 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_sspp.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_sspp.h
@@ -161,12 +161,12 @@
  */
 struct sde_hw_sspp_ops {
 	/**
-	 * setup_sourceformat - setup pixel format cropping rectangle, flip
+	 * setup_format - setup pixel format cropping rectangle, flip
 	 * @ctx: Pointer to pipe context
 	 * @cfg: Pointer to pipe config structure
-	 * @flags: Format flags
+	 * @flags: Extra flags for format config
 	 */
-	void (*setup_sourceformat)(struct sde_hw_pipe *ctx,
+	void (*setup_format)(struct sde_hw_pipe *ctx,
 			struct sde_hw_pipe_cfg *cfg,
 			u32 flags);
 
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.h b/drivers/gpu/drm/msm/sde/sde_kms.h
index ea183a98..c4d3881 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.h
+++ b/drivers/gpu/drm/msm/sde/sde_kms.h
@@ -141,7 +141,30 @@
 };
 
 #define to_sde_plane_state(x) \
-		container_of(x, struct sde_plane_state, base)
+	container_of(x, struct sde_plane_state, base)
+
+/**
+ * sde_plane_get_property - Query integer value of plane property
+ *
+ * @S: Pointer to plane state
+ * @X: Property index, from enum msm_mdp_plane_property
+ *
+ * Return: Integer value of requested property
+ */
+#define sde_plane_get_property(S, X) \
+	((S) && ((X) < PLANE_PROP_COUNT) ? ((S)->property_values[(X)]) : 0)
+
+/**
+ * sde_plane_get_property32 - Query 32-bit representation of plane property
+ *
+ * @S: Pointer to plane state
+ * @X: Property index, from enum msm_mdp_plane_property
+ *
+ * Return: 32-bit value of requested property
+ */
+#define sde_plane_get_property32(S, X) \
+	((S) && ((X) < PLANE_PROP_COUNT) ? \
+	 (uint32_t)((S)->property_values[(X)]) : 0)
 
 int sde_disable(struct sde_kms *sde_kms);
 int sde_enable(struct sde_kms *sde_kms);
@@ -348,7 +371,7 @@
  */
 enum sde_sspp sde_plane_pipe(struct drm_plane *plane);
 struct drm_plane *sde_plane_init(struct drm_device *dev, uint32_t pipe,
-		bool private_plane);
+		bool primary_plane);
 
 /**
  * CRTC functions
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index 00daa6b..8817a3b 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -43,6 +43,8 @@
 	struct sde_hw_sharp_cfg sharp_cfg;
 	struct sde_hw_scaler3_cfg scaler3_cfg;
 
+	const struct sde_sspp_sub_blks *pipe_sblk;
+
 	char pipe_name[SDE_NAME_SIZE];
 
 	/* debugfs related stuff */
@@ -53,12 +55,6 @@
 };
 #define to_sde_plane(x) container_of(x, struct sde_plane, base)
 
-/* macro to obtain int/enum value from plane state, no error checking */
-#define SDE_PLANE_GETINT(S, X)   ((S)->property_values[(X)])
-
-/* macro to obtain blob ptr from plane state, no error checking */
-#define SDE_PLANE_GETBLOB(S, X)  ((S)->property_blobs[(X)])
-
 static bool sde_plane_enabled(struct drm_plane_state *state)
 {
 	return state->fb && state->crtc;
@@ -74,7 +70,7 @@
 
 	if (pipe_cfg && fb && psde->pipe_hw->ops.setup_sourceaddress) {
 		/* stride */
-		if (SDE_PLANE_GETINT(pstate, PLANE_PROP_SRC_CONFIG) &
+		if (sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG) &
 				BIT(SDE_DRM_DEINTERLACE))
 			shift = 1;
 		else
@@ -109,7 +105,7 @@
 		enum sde_hw_filter *filter, struct sde_mdp_format_params *fmt,
 		uint32_t chroma_subsampling)
 {
-	/* calcualte phase steps, leave init phase as zero */
+	/* calculate phase steps, leave init phase as zero */
 	phase_steps[SDE_SSPP_COMP_0] =
 		mult_frac(1 << PHASE_STEP_SHIFT, src, dst);
 	phase_steps[SDE_SSPP_COMP_1_2] =
@@ -224,8 +220,10 @@
 	size_t len = 0;
 	void *ret = 0;
 
-	if (pstate && (property < PLANE_PROP_BLOBCOUNT)) {
-		blob = SDE_PLANE_GETBLOB(pstate, property);
+	if (!pstate || (property >= PLANE_PROP_BLOBCOUNT)) {
+		DRM_ERROR("Invalid argument(s)\n");
+	} else {
+		blob = pstate->property_blobs[property];
 		if (blob) {
 			len = blob->length;
 			ret = &blob->data;
@@ -429,21 +427,21 @@
 
 	/* decimation */
 	psde->pipe_cfg.horz_decimation =
-		SDE_PLANE_GETINT(pstate, PLANE_PROP_H_DECIMATE);
+		sde_plane_get_property(pstate, PLANE_PROP_H_DECIMATE);
 	psde->pipe_cfg.vert_decimation =
-		SDE_PLANE_GETINT(pstate, PLANE_PROP_V_DECIMATE);
+		sde_plane_get_property(pstate, PLANE_PROP_V_DECIMATE);
 
 	/* flags */
 	DBG("Flags 0x%llX, rotation 0x%llX",
-			SDE_PLANE_GETINT(pstate, PLANE_PROP_SRC_CONFIG),
-			SDE_PLANE_GETINT(pstate, PLANE_PROP_ROTATION));
-	if (SDE_PLANE_GETINT(pstate, PLANE_PROP_ROTATION) &
+			sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG),
+			sde_plane_get_property(pstate, PLANE_PROP_ROTATION));
+	if (sde_plane_get_property(pstate, PLANE_PROP_ROTATION) &
 		BIT(DRM_REFLECT_X))
 		src_fmt_flags |= SDE_SSPP_FLIP_LR;
-	if (SDE_PLANE_GETINT(pstate, PLANE_PROP_ROTATION) &
+	if (sde_plane_get_property(pstate, PLANE_PROP_ROTATION) &
 		BIT(DRM_REFLECT_Y))
 		src_fmt_flags |= SDE_SSPP_FLIP_UD;
-	if (SDE_PLANE_GETINT(pstate, PLANE_PROP_SRC_CONFIG) &
+	if (sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG) &
 		BIT(SDE_DRM_DEINTERLACE)) {
 		src_h /= 2;
 		src_y  = DIV_ROUND_UP(src_y, 2);
@@ -594,8 +592,8 @@
 		}
 	}
 
-	if (psde->pipe_hw->ops.setup_sourceformat)
-		psde->pipe_hw->ops.setup_sourceformat(psde->pipe_hw,
+	if (psde->pipe_hw->ops.setup_format)
+		psde->pipe_hw->ops.setup_format(psde->pipe_hw,
 				&psde->pipe_cfg, src_fmt_flags);
 	if (psde->pipe_hw->ops.setup_rects)
 		psde->pipe_hw->ops.setup_rects(psde->pipe_hw,
@@ -831,9 +829,40 @@
 	}
 }
 
+static int _sde_plane_get_property_index(struct drm_plane *plane,
+		struct drm_property *property)
+{
+	struct drm_property **prop_array;
+	int idx = PLANE_PROP_COUNT;
+
+	if (!plane) {
+		DRM_ERROR("Invalid plane\n");
+	} else if (!plane->dev || !plane->dev->dev_private) {
+		/* don't access dev_private if !dev */
+		DRM_ERROR("Invalid device\n");
+	} else if (!property) {
+		DRM_ERROR("Incoming property is NULL\n");
+	} else {
+		prop_array = ((struct msm_drm_private *)
+				(plane->dev->dev_private))->plane_property;
+		if (!prop_array)
+			/* should never hit this */
+			DRM_ERROR("Invalid property array\n");
+
+		/* linear search is okay */
+		for (idx = 0; idx < PLANE_PROP_COUNT; ++idx) {
+			if (prop_array[idx] == property)
+				break;
+		}
+	}
+
+	return idx;
+}
+
 /* helper to install properties which are common to planes and crtcs */
 static void _sde_plane_install_properties(struct drm_plane *plane,
-		struct drm_mode_object *obj)
+		struct drm_mode_object *obj,
+		struct sde_mdss_cfg *catalog)
 {
 	static const struct drm_prop_enum_list e_blend_op[] = {
 		{SDE_DRM_BLEND_OP_NOT_DEFINED,    "not_defined"},
@@ -847,33 +876,29 @@
 	struct sde_plane *psde = to_sde_plane(plane);
 	struct drm_device *dev = plane->dev;
 	struct msm_drm_private *dev_priv = dev->dev_private;
-	const struct sde_sspp_sub_blks *sblk = 0;
-	const struct sde_sspp_cfg *cfg = 0;
 
 	DBG("");
 
-	if (psde && psde->pipe_hw)
-		cfg = psde->pipe_hw->cap;
-	if (cfg)
-		sblk = cfg->sblk;
-	if (!sblk) {
+	if (!psde || !psde->pipe_sblk || !catalog) {
 		DRM_ERROR("Failed to identify catalog definition\n");
 		return;
 	}
 
 	/* range properties */
-	_sde_plane_install_range_property(plane, dev, "zpos", 1, 255, 1,
+	_sde_plane_install_range_property(plane, dev, "zpos", 0, 255, 1,
 			&(dev_priv->plane_property[PLANE_PROP_ZPOS]));
 
 	_sde_plane_install_range_property(plane, dev, "alpha", 0, 255, 255,
 			&(dev_priv->plane_property[PLANE_PROP_ALPHA]));
 
+	/* max range of first pipe will be used */
 	_sde_plane_install_range_property(plane, dev, "h_decimate",
-			0, sblk->maxhdeciexp, 0,
+			0, psde->pipe_sblk->maxhdeciexp, 0,
 			&(dev_priv->plane_property[PLANE_PROP_H_DECIMATE]));
 
+	/* max range of first pipe will be used */
 	_sde_plane_install_range_property(plane, dev, "v_decimate",
-			0, sblk->maxvdeciexp, 0,
+			0, psde->pipe_sblk->maxvdeciexp, 0,
 			&(dev_priv->plane_property[PLANE_PROP_V_DECIMATE]));
 
 	_sde_plane_install_range_property(plane, dev, "sync_fence", 0, ~0, 0,
@@ -892,60 +917,56 @@
 			&(dev_priv->plane_property[PLANE_PROP_SRC_CONFIG]));
 
 	/* blob properties */
-	_sde_plane_install_blob_property(plane, dev, "scaler",
+	if (psde->features & SDE_SSPP_SCALER)
+		_sde_plane_install_blob_property(plane, dev, "scaler",
 			&(dev_priv->plane_property[PLANE_PROP_SCALER]));
-	_sde_plane_install_blob_property(plane, dev, "csc",
-			&(dev_priv->plane_property[PLANE_PROP_CSC]));
+	if (psde->features & BIT(SDE_SSPP_CSC))
+		_sde_plane_install_blob_property(plane, dev, "csc",
+				&(dev_priv->plane_property[PLANE_PROP_CSC]));
 }
 
 static int sde_plane_atomic_set_property(struct drm_plane *plane,
 		struct drm_plane_state *state, struct drm_property *property,
 		uint64_t val)
 {
-	struct drm_device *dev = plane->dev;
 	struct sde_plane_state *pstate;
-	struct drm_property_blob *blob, **prp_blob;
-	struct msm_drm_private *dev_priv = dev->dev_private;
+	struct drm_property_blob *blob, **pr_blob;
 	int idx, ret = -EINVAL;
 
 	DBG("");
 
-	pstate = to_sde_plane_state(state);
+	idx = _sde_plane_get_property_index(plane, property);
+	if (!state) {
+		DRM_ERROR("Invalid state\n");
+	} else if (idx < PLANE_PROP_COUNT) {
+		DBG("Set property %d <= %d", idx, (int)val);
+		pstate = to_sde_plane_state(state);
 
-	for (idx = 0; idx < PLANE_PROP_COUNT && ret; ++idx) {
-		if (dev_priv->plane_property[idx] == property) {
-			DBG("Set property %d <= %d", idx, (int)val);
+		/* extra handling for incoming blob properties */
+		if ((property->flags & DRM_MODE_PROP_BLOB) &&
+			(idx < PLANE_PROP_BLOBCOUNT)) {
+			/* DRM lookup also takes a reference */
+			blob = drm_property_lookup_blob(plane->dev,
+				(uint32_t)val);
+			if (!blob) {
+				DRM_ERROR("Blob not found\n");
+				val = 0;
+			} else {
+				DBG("Blob %u saved", blob->base.id);
+				val = blob->base.id;
 
-			/* extra handling for incoming blob properties */
-			if ((property->flags & DRM_MODE_PROP_BLOB) &&
-				(idx < PLANE_PROP_BLOBCOUNT)) {
-				/* DRM lookup also takes a reference */
-				blob = drm_property_lookup_blob(dev,
-					(uint32_t)val);
-				if (!blob) {
-					DRM_ERROR("Blob not found\n");
-					val = 0;
-				} else {
-					DBG("Blob %u saved", blob->base.id);
-					val = blob->base.id;
-
-					/* save blobs for later */
-					prp_blob = &pstate->property_blobs[idx];
-					/* need to clear previous reference */
-					if (*prp_blob)
-						drm_property_unreference_blob(
-						    *prp_blob);
-					*prp_blob = blob;
-				}
+				/* save blobs for later */
+				pr_blob = &pstate->property_blobs[idx];
+				/* need to clear previous reference */
+				if (*pr_blob)
+					drm_property_unreference_blob(*pr_blob);
+				*pr_blob = blob;
 			}
-			pstate->property_values[idx] = val;
-			ret = 0;
 		}
+		pstate->property_values[idx] = val;
+		ret = 0;
 	}
 
-	if (ret == -EINVAL)
-		DRM_ERROR("Invalid property set\n");
-
 	return ret;
 }
 
@@ -955,6 +976,10 @@
 	int rc;
 
 	DBG("");
+
+	if (!plane)
+		return -EINVAL;
+
 	rc = sde_plane_atomic_set_property(plane, plane->state, property, val);
 	return rc;
 }
@@ -963,26 +988,24 @@
 		const struct drm_plane_state *state,
 		struct drm_property *property, uint64_t *val)
 {
-	struct drm_device *dev = plane->dev;
 	struct sde_plane_state *pstate;
-	struct msm_drm_private *dev_priv = dev->dev_private;
 	int idx, ret = -EINVAL;
 
 	DBG("");
-	pstate = to_sde_plane_state(state);
 
-	for (idx = 0; idx < PLANE_PROP_COUNT; ++idx) {
-		if (dev_priv->plane_property[idx] == property) {
-			*val = pstate->property_values[idx];
-			DBG("Get property %d %lld", idx, *val);
-			ret = 0;
-			break;
-		}
+	idx = _sde_plane_get_property_index(plane, property);
+	if (!state) {
+		DRM_ERROR("Invalid state\n");
+	} else if (!val) {
+		DRM_ERROR("Value pointer is NULL\n");
+	} else if (idx < PLANE_PROP_COUNT) {
+		pstate = to_sde_plane_state(state);
+
+		*val = pstate->property_values[idx];
+		DBG("Get property %d %lld", idx, *val);
+		ret = 0;
 	}
 
-	if (ret == -EINVAL)
-		DRM_ERROR("Invalid property get\n");
-
 	return ret;
 }
 
@@ -997,14 +1020,14 @@
 
 		debugfs_remove_recursive(psde->debugfs_root);
 
-		if (psde->pipe_hw)
-			sde_hw_sspp_destroy(psde->pipe_hw);
-
 		drm_plane_helper_disable(plane);
 
 		/* this will destroy the states as well */
 		drm_plane_cleanup(plane);
 
+		if (psde->pipe_hw)
+			sde_hw_sspp_destroy(psde->pipe_hw);
+
 		kfree(psde);
 	}
 }
@@ -1075,7 +1098,6 @@
 
 	/* assign default blend parameters */
 	pstate->property_values[PLANE_PROP_ALPHA] = 255;
-	pstate->property_values[PLANE_PROP_PREMULTIPLIED] = 0;
 
 	if (plane->type == DRM_PLANE_TYPE_PRIMARY)
 		pstate->property_values[PLANE_PROP_ZPOS] = STAGE_BASE;
@@ -1131,7 +1153,7 @@
 					sde_debugfs_get_root(kms));
 		if (psde->debugfs_root) {
 			/* don't error check these */
-			debugfs_create_x32("features", 0444,
+			debugfs_create_x32("features", 0644,
 					psde->debugfs_root, &psde->features);
 
 			/* add register dump support */
@@ -1162,15 +1184,19 @@
 
 /* initialize plane */
 struct drm_plane *sde_plane_init(struct drm_device *dev,
-		uint32_t pipe, bool private_plane)
+		uint32_t pipe, bool primary_plane)
 {
 	struct drm_plane *plane = NULL;
 	struct sde_plane *psde;
 	struct msm_drm_private *priv;
 	struct sde_kms *kms;
-	struct sde_mdss_cfg *sde_cat;
-	int ret;
 	enum drm_plane_type type;
+	int ret = -EINVAL;
+
+	if (!dev) {
+		DRM_ERROR("[%u]Device is NULL\n", pipe);
+		goto exit;
+	}
 
 	priv = dev->dev_private;
 	if (!priv) {
@@ -1184,61 +1210,80 @@
 	}
 	kms = to_sde_kms(priv->kms);
 
+	if (!kms->catalog) {
+		DRM_ERROR("[%u]Invalid catalog reference\n", pipe);
+		goto exit;
+	}
+
 	/* create and zero local structure */
 	psde = kzalloc(sizeof(*psde), GFP_KERNEL);
 	if (!psde) {
+		DRM_ERROR("[%u]Failed to allocate local plane struct\n", pipe);
 		ret = -ENOMEM;
-		goto fail;
+		goto exit;
 	}
 
+	/* cache local stuff for later */
 	plane = &psde->base;
-
 	psde->pipe = pipe;
+	psde->mmu_id = kms->mmu_id;
 
-	if (kms) {
-		/* mmu id for buffer mapping */
-		psde->mmu_id = kms->mmu_id;
-
-		/* check catalog for features mask */
-		sde_cat = kms->catalog;
-		if (sde_cat)
-			psde->features = sde_cat->sspp[pipe].features;
+	/* initialize underlying h/w driver */
+	psde->pipe_hw = sde_hw_sspp_init(pipe, kms->mmio, kms->catalog);
+	if (IS_ERR(psde->pipe_hw)) {
+		DRM_ERROR("[%u]SSPP init failed\n", pipe);
+		ret = PTR_ERR(psde->pipe_hw);
+		goto clean_plane;
+	} else if (!psde->pipe_hw->cap || !psde->pipe_hw->cap->sblk) {
+		DRM_ERROR("[%u]SSPP init returned invalid cfg\n", pipe);
+		goto clean_sspp;
 	}
+
+	/* cache features mask for later */
+	psde->features = psde->pipe_hw->cap->features;
+	psde->pipe_sblk = psde->pipe_hw->cap->sblk;
+
+	/* add plane to DRM framework */
 	psde->nformats = mdp_get_formats(psde->formats,
 		ARRAY_SIZE(psde->formats),
 		!(psde->features & BIT(SDE_SSPP_CSC)) ||
 		!(psde->features & SDE_SSPP_SCALER));
 
-	type = private_plane ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
+	if (!psde->nformats) {
+		DRM_ERROR("[%u]No valid formats for plane\n", pipe);
+		goto clean_sspp;
+	}
+
+	if (psde->features & BIT(SDE_SSPP_CURSOR))
+		type = DRM_PLANE_TYPE_CURSOR;
+	else if (primary_plane)
+		type = DRM_PLANE_TYPE_PRIMARY;
+	else
+		type = DRM_PLANE_TYPE_OVERLAY;
 	ret = drm_universal_plane_init(dev, plane, 0xff, &sde_plane_funcs,
 				psde->formats, psde->nformats,
 				type);
 	if (ret)
-		goto fail;
+		goto clean_sspp;
 
+	/* success! finalize initialization */
 	drm_plane_helper_add(plane, &sde_plane_helper_funcs);
 
-	psde->pipe_hw = sde_hw_sspp_init(pipe, kms->mmio, sde_cat);
-	if (IS_ERR(psde->pipe_hw)) {
-		ret = PTR_ERR(psde->pipe_hw);
-		psde->pipe_hw = NULL;
-		goto fail;
-	}
-
-	_sde_plane_install_properties(plane, &plane->base);
+	_sde_plane_install_properties(plane, &plane->base, kms->catalog);
 
 	/* save user friendly pipe name for later */
 	snprintf(psde->pipe_name, SDE_NAME_SIZE, "plane%u", plane->base.id);
 
 	_sde_plane_init_debugfs(psde, kms);
 
-	DRM_INFO("Successfully created plane for %s\n", psde->pipe_name);
+	DRM_INFO("[%u]Successfully created %s\n", pipe, psde->pipe_name);
 	return plane;
 
-fail:
-	DRM_ERROR("Plane creation failed\n");
-	if (plane)
-		sde_plane_destroy(plane);
+clean_sspp:
+	if (psde && psde->pipe_hw)
+		sde_hw_sspp_destroy(psde->pipe_hw);
+clean_plane:
+	kfree(psde);
 exit:
 	return ERR_PTR(ret);
 }