drm/msm/sde: add planes color fill/fence timeout

To prepare for input fence support, add a property to configure the
input fence timeout. Also, enable support for color fill (through
a plane property) so that it can be enabled if input fences ever time
out.

Change-Id: Iae79ebadb4731db444f39d3b7207b65cb2aa9243
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 a99a354..b8bbfbe 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -79,7 +79,9 @@
 	/* range properties */
 	PLANE_PROP_ZPOS = PLANE_PROP_BLOBCOUNT,
 	PLANE_PROP_ALPHA,
+	PLANE_PROP_COLOR_FILL,
 	PLANE_PROP_SYNC_FENCE,
+	PLANE_PROP_SYNC_FENCE_TIMEOUT,
 
 	/* enum/bitmask properties */
 	PLANE_PROP_ROTATION,
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_sspp.c b/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
index 1c5089a..af9aded 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
@@ -77,12 +77,6 @@
 #define VIG_0_QSEED2_SHARP                 0x30
 
 /*
- * MDP Solid fill configuration
- * argb8888
- */
-#define SSPP_SOLID_FILL                   0x4037ff
-
-/*
  * Definitions for ViG op modes
  */
 #define VIG_OP_CSC_DST_DATAFMT BIT(19)
@@ -161,17 +155,15 @@
  * Setup source pixel format, flip,
  */
 static void sde_hw_sspp_setup_format(struct sde_hw_pipe *ctx,
-		struct sde_hw_pipe_cfg *cfg,
-		u32 flags)
+		struct sde_mdp_format_params *fmt, u32 flags)
 {
 	struct sde_hw_blk_reg_map *c;
-	struct sde_mdp_format_params *fmt;
 	u32 chroma_samp, unpack, src_format;
 	u32 secure = 0;
 	u32 opmode = 0;
 	u32 idx;
 
-	if (_sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx) || !cfg)
+	if (_sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx) || !fmt)
 		return;
 
 	c = &ctx->hw;
@@ -179,11 +171,6 @@
 	opmode &= ~(MDSS_MDP_OP_FLIP_LR | MDSS_MDP_OP_FLIP_UD |
 			MDSS_MDP_OP_BWC_EN | MDSS_MDP_OP_PE_OVERRIDE);
 
-	/* format info */
-	fmt = cfg->src.format;
-	if (WARN_ON(!fmt))
-		return;
-
 	if (flags & SDE_SSPP_SECURE_OVERLAY_SESSION)
 		secure = 0xF;
 
@@ -211,6 +198,9 @@
 			fmt->fetch_planes != SDE_MDP_PLANE_INTERLEAVED)
 		src_format |= BIT(8); /* SRCC3_EN */
 
+	if (flags & SDE_SSPP_SOLID_FILL)
+		src_format |= BIT(22);
+
 	unpack = (fmt->element[3] << 24) | (fmt->element[2] << 16) |
 		(fmt->element[1] << 8) | (fmt->element[0] << 0);
 	src_format |= ((fmt->unpack_count - 1) << 12) |
@@ -219,7 +209,8 @@
 		((fmt->bpp - 1) << 9);
 
 	if (fmt->fetch_mode != SDE_MDP_FETCH_LINEAR) {
-		opmode |= MDSS_MDP_OP_BWC_EN;
+		if (SDE_FORMAT_IS_UBWC(fmt))
+			opmode |= MDSS_MDP_OP_BWC_EN;
 		src_format |= (fmt->fetch_mode & 3) << 30; /*FRAME_FORMAT */
 		SDE_REG_WRITE(c, SSPP_FETCH_CONFIG,
 			SDE_MDP_FETCH_CONFIG_RESET_VALUE |
@@ -379,14 +370,10 @@
 		sde_hw_sspp_setup_pe_config(ctx, pe_ext);
 
 	/* src and dest rect programming */
-	src_xy = (cfg->src_rect.y << 16) |
-		(cfg->src_rect.x);
-	src_size = (cfg->src_rect.h << 16) |
-		(cfg->src_rect.w);
-	dst_xy = (cfg->dst_rect.y << 16) |
-		(cfg->dst_rect.x);
-	dst_size = (cfg->dst_rect.h << 16) |
-		(cfg->dst_rect.w);
+	src_xy = (cfg->src_rect.y << 16) | (cfg->src_rect.x);
+	src_size = (cfg->src_rect.h << 16) | (cfg->src_rect.w);
+	dst_xy = (cfg->dst_rect.y << 16) | (cfg->dst_rect.x);
+	dst_size = (cfg->dst_rect.h << 16) | (cfg->dst_rect.w);
 
 	ystride0 =  (cfg->src.ystride[0]) |
 		(cfg->src.ystride[1] << 16);
@@ -402,8 +389,8 @@
 		_sde_hw_sspp_setup_scaler(ctx, pe_ext);
 	}
 
-	/* Rectangle Register programming */
-	SDE_REG_WRITE(c, SSPP_SRC_SIZE + idx,  src_size);
+	/* rectangle register programming */
+	SDE_REG_WRITE(c, SSPP_SRC_SIZE + idx, src_size);
 	SDE_REG_WRITE(c, SSPP_SRC_XY + idx, src_xy);
 	SDE_REG_WRITE(c, SSPP_OUT_SIZE + idx, dst_size);
 	SDE_REG_WRITE(c, SSPP_OUT_XY + idx, dst_xy);
@@ -456,32 +443,14 @@
 	SDE_REG_WRITE(c, VIG_0_QSEED2_SHARP + idx + 0xC, cfg->noise_thr);
 }
 
-static void sde_hw_sspp_setup_solidfill(struct sde_hw_pipe *ctx,
-		u32 const_color,
-		u32 flags)
+static void sde_hw_sspp_setup_solidfill(struct sde_hw_pipe *ctx, u32 color)
 {
-	struct sde_hw_blk_reg_map *c;
-	u32 secure = 0;
-	u32 unpack, src_format, opmode = 0;
 	u32 idx;
 
 	if (_sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx))
 		return;
 
-	c = &ctx->hw;
-
-	/* format info */
-	src_format = SSPP_SOLID_FILL;
-	unpack = (C3_ALPHA << 24) | (C2_R_Cr << 16) |
-		(C1_B_Cb << 8) | (C0_G_Y << 0);
-	secure = (flags & SDE_SSPP_SECURE_OVERLAY_SESSION) ? 0xF : 0x00;
-	opmode = MDSS_MDP_OP_PE_OVERRIDE;
-
-	SDE_REG_WRITE(c, SSPP_SRC_FORMAT + idx, src_format);
-	SDE_REG_WRITE(c, SSPP_SRC_UNPACK_PATTERN + idx, unpack);
-	SDE_REG_WRITE(c, SSPP_SRC_ADDR_SW_STATUS + idx, secure);
-	SDE_REG_WRITE(c, SSPP_SRC_CONSTANT_COLOR + idx, const_color);
-	SDE_REG_WRITE(c, SSPP_SRC_OP_MODE + idx, opmode);
+	SDE_REG_WRITE(&ctx->hw, SSPP_SRC_CONSTANT_COLOR + idx, color);
 }
 
 static void sde_hw_sspp_setup_histogram_v1(struct sde_hw_pipe *ctx,
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_sspp.h b/drivers/gpu/drm/msm/sde/sde_hw_sspp.h
index 6b1833b2..1bfbc21 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_sspp.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_sspp.h
@@ -16,6 +16,7 @@
 #include "sde_hw_catalog.h"
 #include "sde_hw_mdss.h"
 #include "sde_hw_util.h"
+#include "sde_formats.h"
 
 struct sde_hw_pipe;
 
@@ -27,6 +28,7 @@
 #define SDE_SSPP_FLIP_UD	 0x4
 #define SDE_SSPP_SOURCE_ROTATED_90 0x8
 #define SDE_SSPP_ROT_90  0x10
+#define SDE_SSPP_SOLID_FILL 0x20
 
 /**
  * Define all scaler feature bits in catalog
@@ -167,8 +169,7 @@
 	 * @flags: Extra flags for format config
 	 */
 	void (*setup_format)(struct sde_hw_pipe *ctx,
-			struct sde_hw_pipe_cfg *cfg,
-			u32 flags);
+			struct sde_mdp_format_params *fmt, u32 flags);
 
 	/**
 	 * setup_rects - setup pipe ROI rectangles
@@ -201,9 +202,7 @@
 	 * @const_color: Fill color value
 	 * @flags: Pipe flags
 	 */
-	void (*setup_solidfill)(struct sde_hw_pipe *ctx,
-			u32 const_color,
-			u32 flags);
+	void (*setup_solidfill)(struct sde_hw_pipe *ctx, u32 color);
 
 	/**
 	 * setup_sharpening - setup sharpening
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.h b/drivers/gpu/drm/msm/sde/sde_kms.h
index 0ffdb82..915732e 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.h
+++ b/drivers/gpu/drm/msm/sde/sde_kms.h
@@ -376,6 +376,18 @@
 void sde_plane_complete_flip(struct drm_plane *plane);
 struct drm_plane *sde_plane_init(struct drm_device *dev,
 		uint32_t pipe, bool primary_plane);
+int sde_plane_wait_sync_fence(struct drm_plane *plane);
+
+/**
+ * sde_plane_color_fill(): Enables color fill on plane
+ * @plane:  Pointer to DRM plane object
+ * @color:  RGB fill color value, [23..16] Blue, [15..8] Green, [7..0] Red
+ * @alpha:  8-bit fill alpha value, 255 selects 100% alpha
+ *
+ * Returns: 0 on success
+ */
+int sde_plane_color_fill(struct drm_plane *plane,
+		uint32_t color, uint32_t alpha);
 
 /**
  * CRTC functions
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index 6666532..fa35b7a 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -92,10 +92,12 @@
 	DBG("0x%llX", fd);
 }
 
-void *sde_plane_get_sync_fence(struct drm_plane *plane)
+int sde_plane_wait_sync_fence(struct drm_plane *plane)
 {
 	struct sde_plane_state *pstate;
-	void *ret = NULL;
+	void *sync_fence;
+	long wait_ms;
+	int ret = -EINVAL;
 
 	if (!plane) {
 		DRM_ERROR("Invalid plane\n");
@@ -103,11 +105,24 @@
 		DRM_ERROR("Invalid plane state\n");
 	} else {
 		pstate = to_sde_plane_state(plane->state);
-		ret = pstate->sync_fence;
+		sync_fence = pstate->sync_fence;
 
-		DBG("%s", to_sde_plane(plane)->pipe_name);
+		if (sync_fence) {
+			wait_ms = (long)sde_plane_get_property(pstate,
+					PLANE_PROP_SYNC_FENCE_TIMEOUT);
+
+			DBG("%s", to_sde_plane(plane)->pipe_name);
+			ret = sde_sync_wait(sync_fence, wait_ms);
+			if (!ret)
+				DBG("signaled");
+			else if (ret == -ETIME)
+				DRM_ERROR("timeout\n");
+			else
+				DRM_ERROR("error %d\n", ret);
+		} else {
+			ret = 0;
+		}
 	}
-
 	return ret;
 }
 
@@ -148,7 +163,7 @@
 	}
 }
 
-static void _sde_plane_setup_scaler3(struct drm_plane *plane,
+static void _sde_plane_setup_scaler3(struct sde_plane *psde,
 		uint32_t src_w, uint32_t src_h, uint32_t dst_w, uint32_t dst_h,
 		struct sde_hw_scaler3_cfg *scale_cfg,
 		struct sde_mdp_format_params *fmt,
@@ -156,11 +171,28 @@
 {
 }
 
-static void _sde_plane_setup_scaler2(struct drm_plane *plane,
+/**
+ * _sde_plane_setup_scaler2(): Determine default scaler phase steps/filter type
+ * @psde: Pointer to SDE plane object
+ * @src: Source size
+ * @dst: Destination size
+ * @phase_steps: Pointer to output array for phase steps
+ * @filter: Pointer to output array for filter type
+ * @fmt: Pointer to format definition
+ * @chroma_subsampling: Subsampling amount for chroma channel
+ *
+ * Returns: 0 on success
+ */
+static int _sde_plane_setup_scaler2(struct sde_plane *psde,
 		uint32_t src, uint32_t dst, uint32_t *phase_steps,
 		enum sde_hw_filter *filter, struct sde_mdp_format_params *fmt,
 		uint32_t chroma_subsampling)
 {
+	if (!psde || !phase_steps || !filter || !fmt) {
+		DRM_ERROR("Invalid arguments\n");
+		return -EINVAL;
+	}
+
 	/* calculate phase steps, leave init phase as zero */
 	phase_steps[SDE_SSPP_COMP_0] =
 		mult_frac(1 << PHASE_STEP_SHIFT, src, dst);
@@ -185,13 +217,30 @@
 		}
 	} else {
 		/* disable scaler */
+		DBG("Disable scaler");
 		filter[SDE_SSPP_COMP_0] = SDE_MDP_SCALE_FILTER_MAX;
 		filter[SDE_SSPP_COMP_1_2] = SDE_MDP_SCALE_FILTER_MAX;
 		filter[SDE_SSPP_COMP_3] = SDE_MDP_SCALE_FILTER_MAX;
 	}
+	return 0;
 }
 
-static void _sde_plane_setup_pixel_ext(struct drm_plane *plane,
+/**
+ * _sde_plane_setup_pixel_ext - determine default pixel extension values
+ * @psde: Pointer to SDE plane object
+ * @src: Source size
+ * @dst: Destination size
+ * @decimated_src: Source size after decimation, if any
+ * @phase_steps: Pointer to output array for phase steps
+ * @out_src: Output array for pixel extension values
+ * @out_edge1: Output array for pixel extension first edge
+ * @out_edge2: Output array for pixel extension second edge
+ * @filter: Pointer to array for filter type
+ * @fmt: Pointer to format definition
+ * @chroma_subsampling: Subsampling amount for chroma channel
+ * @post_compare: Whether to chroma subsampled source size for comparisions
+ */
+static void _sde_plane_setup_pixel_ext(struct sde_plane *psde,
 		uint32_t src, uint32_t dst, uint32_t decimated_src,
 		uint32_t *phase_steps, uint32_t *out_src, int *out_edge1,
 		int *out_edge2, enum sde_hw_filter *filter,
@@ -202,7 +251,7 @@
 	uint32_t src_work;
 	int i, tmp;
 
-	if (plane && phase_steps && out_src && out_edge1 &&
+	if (psde && phase_steps && out_src && out_edge1 &&
 			out_edge2 && filter && fmt) {
 		/* handle CAF for YUV formats */
 		if (SDE_FORMAT_IS_YUV(fmt) &&
@@ -429,95 +478,20 @@
 	psde->pipe_hw->ops.setup_csc(psde->pipe_hw, psde->csc_ptr);
 }
 
-static int _sde_plane_mode_set(struct drm_plane *plane,
-		struct drm_crtc *crtc, struct drm_framebuffer *fb,
-		int crtc_x, int crtc_y,
-		unsigned int crtc_w, unsigned int crtc_h,
-		uint32_t src_x, uint32_t src_y,
-		uint32_t src_w, uint32_t src_h)
+static void _sde_plane_setup_scaler(struct sde_plane *psde,
+		struct sde_mdp_format_params *fmt,
+		struct sde_plane_state *pstate)
 {
-	struct sde_plane *psde;
-	struct sde_plane_state *pstate;
-	const struct mdp_format *format;
-	uint32_t nplanes, pix_format, tmp;
-	uint32_t chroma_subsmpl_h, chroma_subsmpl_v;
-	uint32_t src_fmt_flags;
-	int i;
-	struct sde_mdp_format_params *fmt;
-	struct sde_hw_pixel_ext *pe;
-	size_t sc_u_size = 0;
+	struct sde_hw_pixel_ext *pe = NULL;
 	struct sde_drm_scaler *sc_u = NULL;
 	struct sde_drm_scaler_v1 *sc_u1 = NULL;
+	size_t sc_u_size = 0;
+	uint32_t chroma_subsmpl_h, chroma_subsmpl_v;
+	uint32_t tmp;
+	int i;
 
-	DBG("");
-
-	if (!plane || !plane->state) {
-		DRM_ERROR("Invalid plane/state\n");
-		return -EINVAL;
-	}
-	if (!crtc || !fb) {
-		DRM_ERROR("Invalid crtc/fb\n");
-		return -EINVAL;
-	}
-
-	psde = to_sde_plane(plane);
-	pstate = to_sde_plane_state(plane->state);
-	nplanes = drm_format_num_planes(fb->pixel_format);
-
-	format = to_mdp_format(msm_framebuffer_format(fb));
-	pix_format = format->base.pixel_format;
-
-	/* src values are in Q16 fixed point, convert to integer */
-	src_x = src_x >> 16;
-	src_y = src_y >> 16;
-	src_w = src_w >> 16;
-	src_h = src_h >> 16;
-
-	DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u", psde->pipe_name,
-			fb->base.id, src_x, src_y, src_w, src_h,
-			crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h);
-
-	/* update format configuration */
-	memset(&(psde->pipe_cfg), 0, sizeof(struct sde_hw_pipe_cfg));
-	src_fmt_flags = 0;
-
-	psde->pipe_cfg.src.format = sde_mdp_get_format_params(pix_format,
-			fb->modifier[0]);
-	psde->pipe_cfg.src.width = fb->width;
-	psde->pipe_cfg.src.height = fb->height;
-	psde->pipe_cfg.src.num_planes = nplanes;
-
-	_sde_plane_set_scanout(plane, pstate, &psde->pipe_cfg, fb);
-
-	/* flags */
-	DBG("Flags 0x%llX, rotation 0x%llX",
-			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_get_property(pstate, PLANE_PROP_ROTATION) &
-		BIT(DRM_REFLECT_Y))
-		src_fmt_flags |= SDE_SSPP_FLIP_UD;
-	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);
-		src_y &= ~0x1;
-	}
-
-	psde->pipe_cfg.src_rect.x = src_x;
-	psde->pipe_cfg.src_rect.y = src_y;
-	psde->pipe_cfg.src_rect.w = src_w;
-	psde->pipe_cfg.src_rect.h = src_h;
-
-	psde->pipe_cfg.dst_rect.x = crtc_x;
-	psde->pipe_cfg.dst_rect.y = crtc_y;
-	psde->pipe_cfg.dst_rect.w = crtc_w;
-	psde->pipe_cfg.dst_rect.h = crtc_h;
-
-	/* get sde pixel format definition */
-	fmt = psde->pipe_cfg.src.format;
+	if (!psde || !fmt)
+		return;
 
 	pe = &(psde->pixel_ext);
 	memset(pe, 0, sizeof(struct sde_hw_pixel_ext));
@@ -543,21 +517,28 @@
 	if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_DECIMATE)) {
 		psde->pipe_cfg.horz_decimation = sc_u1->horz_decimate;
 		psde->pipe_cfg.vert_decimation = sc_u1->vert_decimate;
+	} else {
+		psde->pipe_cfg.horz_decimation = 0;
+		psde->pipe_cfg.vert_decimation = 0;
 	}
 
 	/* don't chroma subsample if decimating */
 	chroma_subsmpl_h = psde->pipe_cfg.horz_decimation ? 1 :
-		drm_format_horz_chroma_subsampling(pix_format);
+		drm_format_horz_chroma_subsampling(fmt->format);
 	chroma_subsmpl_v = psde->pipe_cfg.vert_decimation ? 1 :
-		drm_format_vert_chroma_subsampling(pix_format);
+		drm_format_vert_chroma_subsampling(fmt->format);
 
 	/* update scaler */
 	if (psde->features & BIT(SDE_SSPP_SCALER_QSEED3)) {
 		if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_SCALER_3))
-			DBG("QSEED3 blob detected");
+			DBG("SCALER3 blob detected");
 		else
-			_sde_plane_setup_scaler3(plane, src_w, src_h, crtc_w,
-					crtc_h, &psde->scaler3_cfg, fmt,
+			_sde_plane_setup_scaler3(psde,
+					psde->pipe_cfg.src_rect.w,
+					psde->pipe_cfg.src_rect.h,
+					psde->pipe_cfg.dst_rect.w,
+					psde->pipe_cfg.dst_rect.h,
+					&psde->scaler3_cfg, fmt,
 					chroma_subsmpl_h, chroma_subsmpl_v);
 	} else {
 		/* always calculate basic scaler config */
@@ -574,10 +555,14 @@
 			}
 		} else {
 			/* calculate phase steps */
-			_sde_plane_setup_scaler2(plane, src_w, crtc_w,
+			_sde_plane_setup_scaler2(psde,
+					psde->pipe_cfg.src_rect.w,
+					psde->pipe_cfg.dst_rect.w,
 					pe->phase_step_x,
 					pe->horz_filter, fmt, chroma_subsmpl_h);
-			_sde_plane_setup_scaler2(plane, src_h, crtc_h,
+			_sde_plane_setup_scaler2(psde,
+					psde->pipe_cfg.src_rect.h,
+					psde->pipe_cfg.dst_rect.h,
 					pe->phase_step_y,
 					pe->vert_filter, fmt, chroma_subsmpl_v);
 		}
@@ -586,6 +571,7 @@
 	/* update pixel extensions */
 	if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_PIX_EXT)) {
 		/* populate from user space */
+		DBG("PIXEXT blob detected");
 		for (i = 0; i < SDE_MAX_PLANES; i++) {
 			pe->num_ext_pxls_left[i] = sc_u1->lr.num_pxls_start[i];
 			pe->num_ext_pxls_right[i] = sc_u1->lr.num_pxls_end[i];
@@ -605,20 +591,22 @@
 		}
 	} else {
 		/* calculate left/right/top/bottom pixel extensions */
-		tmp = DECIMATED_DIMENSION(src_w,
+		tmp = DECIMATED_DIMENSION(psde->pipe_cfg.src_rect.w,
 				psde->pipe_cfg.horz_decimation);
 		if (SDE_FORMAT_IS_YUV(fmt))
 			tmp &= ~0x1;
-		_sde_plane_setup_pixel_ext(plane, src_w, crtc_w, tmp,
+		_sde_plane_setup_pixel_ext(psde, psde->pipe_cfg.src_rect.w,
+				psde->pipe_cfg.dst_rect.w, tmp,
 				pe->phase_step_x,
 				pe->roi_w,
 				pe->num_ext_pxls_left,
 				pe->num_ext_pxls_right, pe->horz_filter, fmt,
 				chroma_subsmpl_h, 0);
 
-		tmp = DECIMATED_DIMENSION(src_h,
+		tmp = DECIMATED_DIMENSION(psde->pipe_cfg.src_rect.h,
 				psde->pipe_cfg.vert_decimation);
-		_sde_plane_setup_pixel_ext(plane, src_h, crtc_h, tmp,
+		_sde_plane_setup_pixel_ext(psde, psde->pipe_cfg.src_rect.h,
+				psde->pipe_cfg.dst_rect.h, tmp,
 				pe->phase_step_y,
 				pe->roi_h,
 				pe->num_ext_pxls_top,
@@ -655,10 +643,152 @@
 					pe->num_ext_pxls_btm[i];
 		}
 	}
+}
+
+int sde_plane_color_fill(struct drm_plane *plane,
+		uint32_t color, uint32_t alpha)
+{
+	struct sde_plane *psde;
+	struct sde_mdp_format_params *fmt;
+
+	if (!plane) {
+		DRM_ERROR("Invalid plane\n");
+		return -EINVAL;
+	}
+
+	psde = to_sde_plane(plane);
+	if (!psde->pipe_hw) {
+		DRM_ERROR("Invalid plane h/w pointer\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * select fill format to match user property expectation,
+	 * h/w only supports RGB variants
+	 */
+	fmt = sde_mdp_get_format_params(DRM_FORMAT_ABGR8888, 0);
+
+	/* update sspp */
+	if (fmt && psde->pipe_hw->ops.setup_solidfill) {
+		psde->pipe_hw->ops.setup_solidfill(psde->pipe_hw,
+				(color & 0xFFFFFF) | ((alpha & 0xFF) << 24));
+
+		/* override scaler/decimation if solid fill */
+		psde->pipe_cfg.src_rect.x = 0;
+		psde->pipe_cfg.src_rect.y = 0;
+		psde->pipe_cfg.src_rect.w = psde->pipe_cfg.dst_rect.w;
+		psde->pipe_cfg.src_rect.h = psde->pipe_cfg.dst_rect.h;
+
+		_sde_plane_setup_scaler(psde, fmt, 0);
+
+		if (psde->pipe_hw->ops.setup_format)
+			psde->pipe_hw->ops.setup_format(psde->pipe_hw,
+					fmt, SDE_SSPP_SOLID_FILL);
+
+		if (psde->pipe_hw->ops.setup_rects)
+			psde->pipe_hw->ops.setup_rects(psde->pipe_hw,
+					&psde->pipe_cfg, &psde->pixel_ext);
+	}
+
+	return 0;
+}
+
+static int _sde_plane_mode_set(struct drm_plane *plane,
+		struct drm_crtc *crtc, struct drm_framebuffer *fb,
+		int crtc_x, int crtc_y,
+		unsigned int crtc_w, unsigned int crtc_h,
+		uint32_t src_x, uint32_t src_y,
+		uint32_t src_w, uint32_t src_h)
+{
+	struct sde_plane *psde;
+	struct sde_plane_state *pstate;
+	const struct mdp_format *format;
+	uint32_t nplanes, tmp;
+	uint32_t src_flags;
+	struct sde_mdp_format_params *fmt;
+
+	DBG("");
+
+	if (!plane || !plane->state) {
+		DRM_ERROR("Invalid plane/state\n");
+		return -EINVAL;
+	}
+	if (!crtc || !fb) {
+		DRM_ERROR("Invalid crtc/fb\n");
+		return -EINVAL;
+	}
+
+	psde = to_sde_plane(plane);
+	pstate = to_sde_plane_state(plane->state);
+	nplanes = drm_format_num_planes(fb->pixel_format);
+
+	format = to_mdp_format(msm_framebuffer_format(fb));
+	tmp = format->base.pixel_format;
+
+	/* src values are in Q16 fixed point, convert to integer */
+	src_x = src_x >> 16;
+	src_y = src_y >> 16;
+	src_w = src_w >> 16;
+	src_h = src_h >> 16;
+
+	DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u", psde->pipe_name,
+			fb->base.id, src_x, src_y, src_w, src_h,
+			crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h);
+
+	/* update format configuration */
+	memset(&(psde->pipe_cfg), 0, sizeof(struct sde_hw_pipe_cfg));
+	src_flags = 0;
+
+	psde->pipe_cfg.src.format = sde_mdp_get_format_params(tmp,
+			fb->modifier[0]);
+	psde->pipe_cfg.src.width = fb->width;
+	psde->pipe_cfg.src.height = fb->height;
+	psde->pipe_cfg.src.num_planes = nplanes;
+
+	/* flags */
+	DBG("Flags 0x%llX, rotation 0x%llX",
+			sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG),
+			sde_plane_get_property(pstate, PLANE_PROP_ROTATION));
+	if (sde_plane_get_property(pstate, PLANE_PROP_ROTATION) &
+		BIT(DRM_REFLECT_X))
+		src_flags |= SDE_SSPP_FLIP_LR;
+	if (sde_plane_get_property(pstate, PLANE_PROP_ROTATION) &
+		BIT(DRM_REFLECT_Y))
+		src_flags |= SDE_SSPP_FLIP_UD;
+	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);
+		src_y &= ~0x1;
+	}
+
+	psde->pipe_cfg.src_rect.x = src_x;
+	psde->pipe_cfg.src_rect.y = src_y;
+	psde->pipe_cfg.src_rect.w = src_w;
+	psde->pipe_cfg.src_rect.h = src_h;
+
+	psde->pipe_cfg.dst_rect.x = crtc_x;
+	psde->pipe_cfg.dst_rect.y = crtc_y;
+	psde->pipe_cfg.dst_rect.w = crtc_w;
+	psde->pipe_cfg.dst_rect.h = crtc_h;
+
+	/* get sde pixel format definition */
+	fmt = psde->pipe_cfg.src.format;
+
+	/* check for color fill */
+	tmp = (uint32_t)sde_plane_get_property(pstate, PLANE_PROP_COLOR_FILL);
+	if (tmp & BIT(31)) {
+		/* force 100% alpha, stop other processing */
+		return sde_plane_color_fill(plane, tmp, 0xFF);
+	}
+
+	_sde_plane_set_scanout(plane, pstate, &psde->pipe_cfg, fb);
+
+	_sde_plane_setup_scaler(psde, fmt, pstate);
 
 	if (psde->pipe_hw->ops.setup_format)
 		psde->pipe_hw->ops.setup_format(psde->pipe_hw,
-				&psde->pipe_cfg, src_fmt_flags);
+				fmt, src_flags);
 	if (psde->pipe_hw->ops.setup_rects)
 		psde->pipe_hw->ops.setup_rects(psde->pipe_hw,
 				&psde->pipe_cfg, &psde->pixel_ext);
@@ -1134,8 +1264,8 @@
 
 	DBG("");
 
-	if (!psde || !psde->pipe_sblk || !catalog) {
-		DRM_ERROR("Failed to identify catalog definition\n");
+	if (!psde || !psde->pipe_hw || !psde->pipe_sblk || !catalog) {
+		DRM_ERROR("Catalog or h/w driver definition error\n");
 		return;
 	}
 
@@ -1148,9 +1278,18 @@
 	_sde_plane_install_range_property(plane, dev, "alpha", 0, 255, 255,
 			PLANE_PROP_ALPHA);
 
+	if (psde->pipe_hw->ops.setup_solidfill)
+		_sde_plane_install_range_property(plane, dev, "color_fill",
+				0, 0xFFFFFFFF, 0,
+				PLANE_PROP_COLOR_FILL);
+
 	_sde_plane_install_range_property(plane, dev, "sync_fence", 0, ~0, ~0,
 			PLANE_PROP_SYNC_FENCE);
 
+	_sde_plane_install_range_property(plane, dev, "sync_fence_timeout",
+			0, ~0, 10000,
+			PLANE_PROP_SYNC_FENCE_TIMEOUT);
+
 	/* standard properties */
 	_sde_plane_install_rotation_property(plane, dev, PLANE_PROP_ROTATION);