drm/msm: fix atomic mode check for sde plane

Add additional mode check in sde plane to avoid
invalid configuration at atomic commit level.
It also fixes the z order property range and
input fence property range.

Change-Id: I8ad12df7d50d39e6a737b5609d299c5f3b254bfa
Signed-off-by: Dhaval Patel <pdhaval@codeaurora.org>
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index e20161c..956e1e8 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -70,8 +70,20 @@
 	struct sde_debugfs_regset32 debugfs_scaler;
 	struct sde_debugfs_regset32 debugfs_csc;
 };
+
 #define to_sde_plane(x) container_of(x, struct sde_plane, base)
 
+#define POPULATE_RECT(rect, a, b, c, d, Q16_flag) \
+	do {						\
+		(rect)->x = (Q16_flag) ? (a) >> 16 : (a);    \
+		(rect)->y = (Q16_flag) ? (b) >> 16 : (b);    \
+		(rect)->w = (Q16_flag) ? (c) >> 16 : (c);    \
+		(rect)->h = (Q16_flag) ? (d) >> 16 : (d);    \
+	} while (0)
+
+#define CHECK_LAYER_BOUNDS(offset, size, max_size) \
+	(((size) > (max_size)) || ((offset) > ((max_size) - (size))))
+
 static bool sde_plane_enabled(struct drm_plane_state *state)
 {
 	return state && state->fb && state->crtc;
@@ -91,7 +103,7 @@
 	/* get fence pointer for later */
 	pstate->input_fence = sde_sync_get(fd);
 
-	DBG("0x%llX", fd);
+	SDE_DEBUG("0x%llX\n", fd);
 }
 
 int sde_plane_wait_input_fence(struct drm_plane *plane, uint32_t wait_ms)
@@ -102,9 +114,9 @@
 	int ret = -EINVAL;
 
 	if (!plane) {
-		DRM_ERROR("Invalid plane\n");
+		SDE_ERROR("invalid plane\n");
 	} else if (!plane->state) {
-		DRM_ERROR("Invalid plane state\n");
+		SDE_ERROR("invalid plane state\n");
 	} else {
 		psde = to_sde_plane(plane);
 		pstate = to_sde_plane_state(plane->state);
@@ -114,15 +126,15 @@
 			ret = sde_sync_wait(input_fence, wait_ms);
 			switch (ret) {
 			case 0:
-				DBG("%s signaled", psde->pipe_name);
+				SDE_DEBUG("%s signaled\n", psde->pipe_name);
 				break;
 			case -ETIME:
-				DRM_ERROR("timeout on %s, %ums\n",
+				SDE_ERROR("timeout on %s, %ums\n",
 						psde->pipe_name, wait_ms);
 				psde->is_error = true;
 				break;
 			default:
-				DRM_ERROR("error on %s, %d\n",
+				SDE_ERROR("error on %s, %d\n",
 						psde->pipe_name, ret);
 				psde->is_error = true;
 				break;
@@ -149,7 +161,7 @@
 
 	ret = sde_format_populate_layout(psde->mmu_id, fb, &pipe_cfg->layout);
 	if (ret) {
-		DRM_ERROR("failed to get format layout, error: %d\n", ret);
+		SDE_ERROR("failed to get format layout, error: %d\n", ret);
 		return;
 	}
 
@@ -188,7 +200,7 @@
 		uint32_t chroma_subsampling)
 {
 	if (!psde || !phase_steps || !filter || !fmt) {
-		DRM_ERROR("Invalid arguments\n");
+		SDE_ERROR("invalid arguments\n");
 		return -EINVAL;
 	}
 
@@ -216,7 +228,7 @@
 		}
 	} else {
 		/* disable scaler */
-		DBG("Disable scaler");
+		SDE_DEBUG("disable scaler\n");
 		filter[SDE_SSPP_COMP_0] = SDE_SCALE_FILTER_MAX;
 		filter[SDE_SSPP_COMP_1_2] = SDE_SCALE_FILTER_MAX;
 		filter[SDE_SSPP_COMP_3] = SDE_SCALE_FILTER_MAX;
@@ -395,7 +407,7 @@
 	int i;
 
 	if (!psde || !pstate || !fmt) {
-		DRM_ERROR("Invalid arguments\n");
+		SDE_ERROR("invalid arguments\n");
 		return;
 	}
 	if (!psde->pipe_hw || !psde->pipe_hw->ops.setup_csc)
@@ -440,12 +452,12 @@
 			break;
 		}
 		if (!psde->csc_ptr)
-			DRM_ERROR("invalid csc blob, v%lld\n", csc->version);
+			SDE_ERROR("invalid csc blob, v%lld\n", csc->version);
 	}
 
 	/* revert to kernel default if override not available */
 	if (psde->csc_ptr)
-		DBG("user blob override for csc");
+		SDE_DEBUG("user blob override for csc\n");
 	else if (SDE_FORMAT_IS_YUV(fmt))
 		psde->csc_ptr = (struct sde_csc_cfg *)&sde_csc_YUV2RGB_601L;
 }
@@ -484,7 +496,8 @@
 				sc_u1 = &sc_u->v1;
 			break;
 		default:
-			DBG("Unrecognized scaler blob v%lld", sc_u->version);
+			SDE_DEBUG("unrecognized scaler blob v%lld\n",
+							sc_u->version);
 			break;
 		}
 	}
@@ -507,7 +520,7 @@
 	/* update scaler */
 	if (psde->features & BIT(SDE_SSPP_SCALER_QSEED3)) {
 		if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_SCALER_3))
-			DBG("SCALER3 blob detected");
+			SDE_DEBUG("SCALER3 blob detected\n");
 		else
 			_sde_plane_setup_scaler3(psde,
 					psde->pipe_cfg.src_rect.w,
@@ -547,7 +560,7 @@
 	/* update pixel extensions */
 	if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_PIX_EXT)) {
 		/* populate from user space */
-		DBG("PIXEXT blob detected");
+		SDE_DEBUG("pixel ext blob detected\n");
 		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];
@@ -635,13 +648,13 @@
 	const struct sde_format *fmt;
 
 	if (!plane) {
-		DRM_ERROR("Invalid plane\n");
+		SDE_ERROR("invalid plane\n");
 		return -EINVAL;
 	}
 
 	psde = to_sde_plane(plane);
 	if (!psde->pipe_hw) {
-		DRM_ERROR("Invalid plane h/w pointer\n");
+		SDE_ERROR("invalid plane h/w pointer\n");
 		return -EINVAL;
 	}
 
@@ -679,45 +692,43 @@
 }
 
 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 drm_plane_state *state)
 {
+	uint32_t nplanes, src_flags;
 	struct sde_plane *psde;
 	struct sde_plane_state *pstate;
-	uint32_t nplanes;
-	uint32_t src_flags;
 	const struct sde_format *fmt;
-
-	DBG("");
+	struct drm_crtc *crtc;
+	struct drm_framebuffer *fb;
+	struct sde_rect src, dst;
+	bool q16_data = true;
 
 	if (!plane || !plane->state) {
-		DRM_ERROR("Invalid plane/state\n");
-		return -EINVAL;
-	}
-	if (!crtc || !fb) {
-		DRM_ERROR("Invalid crtc/fb\n");
+		SDE_ERROR("invalid plane/state\n");
 		return -EINVAL;
 	}
 
 	psde = to_sde_plane(plane);
 	pstate = to_sde_plane_state(plane->state);
 
+	crtc = state->crtc;
+	fb = state->fb;
+	if (!crtc || !fb) {
+		SDE_ERROR("invalid crtc/fb\n");
+		return -EINVAL;
+	}
 	fmt = to_sde_format(msm_framebuffer_format(fb));
 	nplanes = fmt->num_planes;
 
-	/* 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;
+	POPULATE_RECT(&src, state->src_x, state->src_y,
+		state->src_w, state->src_h, q16_data);
+	POPULATE_RECT(&dst, state->crtc_x, state->crtc_y,
+		state->crtc_w, state->crtc_h, !q16_data);
 
-	DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u, %s ubwc %d",
+	SDE_DEBUG("%s:FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u, %s ubwc %d\n",
 			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,
+			fb->base.id, src.x, src.y, src.w, src.h,
+			crtc->base.id, dst.x, dst.y, dst.w, dst.h,
 			drm_get_format_name(fmt->base.pixel_format),
 			SDE_FORMAT_IS_UBWC(fmt));
 
@@ -726,7 +737,7 @@
 	src_flags = 0;
 
 	/* flags */
-	DBG("Flags 0x%llX, rotation 0x%llX",
+	SDE_DEBUG("flags 0x%llX, rotation 0x%llX\n",
 			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) &
@@ -737,20 +748,13 @@
 		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;
+		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;
+	psde->pipe_cfg.src_rect = src;
+	psde->pipe_cfg.dst_rect = dst;
 
 	/* check for color fill */
 	psde->color_fill = (uint32_t)sde_plane_get_property(pstate,
@@ -798,7 +802,7 @@
 	if (!new_state->fb)
 		return 0;
 
-	DBG("%s: FB[%u]", psde->pipe_name, fb->base.id);
+	SDE_DEBUG("%s: FB[%u]\n", psde->pipe_name, fb->base.id);
 	return msm_framebuffer_prepare(fb, psde->mmu_id);
 }
 
@@ -811,233 +815,232 @@
 	if (!fb)
 		return;
 
-	DBG("%s: FB[%u]", psde->pipe_name, fb->base.id);
+	SDE_DEBUG("%s: FB[%u]\n", psde->pipe_name, fb->base.id);
 	msm_framebuffer_cleanup(fb, psde->mmu_id);
 }
 
-static int _sde_plane_atomic_check_fb(struct sde_plane *psde,
-		struct sde_plane_state *pstate,
-		struct drm_framebuffer *fb)
-{
-	return 0;
-}
-
 static void _sde_plane_atomic_check_mode_changed(struct sde_plane *psde,
 		struct drm_plane_state *state,
 		struct drm_plane_state *old_state)
 {
 	struct sde_plane_state *pstate = to_sde_plane_state(state);
 
+	/* no need to check it again */
+	if (pstate->mode_changed)
+		return;
+
 	if (!(sde_plane_enabled(state) && sde_plane_enabled(old_state))) {
-		DBG("%s: pipe enabling/disabling full modeset required",
+		SDE_DEBUG("%s: pipe enabling/disabling full modeset required\n",
 			psde->pipe_name);
 		pstate->mode_changed = true;
 	} else if (to_sde_plane_state(old_state)->pending) {
-		DBG("%s: still pending", psde->pipe_name);
+		SDE_DEBUG("%s: still pending\n", psde->pipe_name);
 		pstate->mode_changed = true;
 	} else if (state->src_w != old_state->src_w ||
-			state->src_h != old_state->src_h) {
-		DBG("%s: src_w change", psde->pipe_name);
+		   state->src_h != old_state->src_h ||
+		   state->src_x != old_state->src_x ||
+		   state->src_y != old_state->src_y) {
+		SDE_DEBUG("%s: src rect updated\n", psde->pipe_name);
+		pstate->mode_changed = true;
+	} else if (state->crtc_w != old_state->crtc_w ||
+		   state->crtc_h != old_state->crtc_h ||
+		   state->crtc_x != old_state->crtc_x ||
+		   state->crtc_y != old_state->crtc_y) {
+		SDE_DEBUG("%s: crtc rect updated\n", psde->pipe_name);
 		pstate->mode_changed = true;
 	} else if (state->fb->pixel_format != old_state->fb->pixel_format) {
-		DBG("%s: format change!", psde->pipe_name);
+		SDE_DEBUG("%s: format change!\n", psde->pipe_name);
 		pstate->mode_changed = true;
-	}
-
-	if (!pstate->mode_changed) {
+	} else {
 		uint64_t *new_mods = state->fb->modifier;
 		uint64_t *old_mods = old_state->fb->modifier;
+		uint32_t *new_pitches = state->fb->pitches;
+		uint32_t *old_pitches = old_state->fb->pitches;
+		uint32_t *new_offset = state->fb->offsets;
+		uint32_t *old_offset = old_state->fb->offsets;
 		int i;
 
 		for (i = 0; i < ARRAY_SIZE(state->fb->modifier); i++) {
 			if (new_mods[i] != old_mods[i]) {
-				DBG("%s: format modifiers change",
-					psde->pipe_name);
+				SDE_DEBUG("%s: format modifiers change\"\
+					plane:%d new_mode:%llu old_mode:%llu\n",
+					psde->pipe_name, i, new_mods[i],
+					old_mods[i]);
 				pstate->mode_changed = true;
 				break;
 			}
 		}
-	}
-
-	if (!pstate->mode_changed) {
-		uint32_t *new_pitches = state->fb->pitches;
-		uint32_t *old_pitches = old_state->fb->pitches;
-		int i;
-
 		for (i = 0; i < ARRAY_SIZE(state->fb->pitches); i++) {
 			if (new_pitches[i] != old_pitches[i]) {
-				DBG("%s: pitches change plane %d: %u, %u",
+				SDE_DEBUG("%s: pitches change plane:%d\"\
+					old_pitches:%u new_pitches:%u\n",
 					psde->pipe_name, i, old_pitches[i],
 					new_pitches[i]);
 				pstate->mode_changed = true;
 				break;
 			}
 		}
+		for (i = 0; i < ARRAY_SIZE(state->fb->offsets); i++) {
+			if (new_offset[i] != old_offset[i]) {
+				SDE_DEBUG("%s: offset change plane:%d\"\
+					old_offset:%u new_offset:%u\n",
+					psde->pipe_name, i, old_offset[i],
+					new_offset[i]);
+				pstate->mode_changed = true;
+				break;
+			}
+		}
 	}
 }
 
+static bool __get_scale_data(struct sde_plane *psde,
+	struct sde_plane_state *pstate, struct sde_drm_scaler *sc_u,
+	size_t *sc_u_size)
+{
+	bool valid_flag = false;
+
+	sc_u = msm_property_get_blob(&psde->property_info,
+			pstate->property_blobs,
+			sc_u_size,
+			PLANE_PROP_SCALER);
+	if (sc_u) {
+		switch (sc_u->version) {
+		case SDE_DRM_SCALER_V1:
+			if (!_sde_plane_verify_blob(sc_u, *sc_u_size,
+				&sc_u->v1, sizeof(struct sde_drm_scaler_v1)))
+				valid_flag = true;
+			break;
+		default:
+			SDE_DEBUG("unrecognized scaler blob v%lld\n",
+							sc_u->version);
+			break;
+		}
+	}
+
+	return valid_flag;
+}
+
 static int sde_plane_atomic_check(struct drm_plane *plane,
 		struct drm_plane_state *state)
 {
+	int ret = 0, valid_scale_data;
 	struct sde_plane *psde;
 	struct sde_plane_state *pstate;
-	struct drm_plane_state *old_state;
 	const struct sde_format *fmt;
 	size_t sc_u_size = 0;
 	struct sde_drm_scaler *sc_u = NULL;
-	int ret = 0;
-
-	uint32_t src_x, src_y;
-	uint32_t src_w, src_h;
+	struct sde_rect src, dst;
 	uint32_t deci_w, deci_h, src_deci_w, src_deci_h;
-	uint32_t src_max_x, src_max_y, src_max_w, src_max_h;
-	uint32_t upscale_max, downscale_max;
-
-	DBG();
+	uint32_t max_upscale, max_downscale, min_src_size, max_linewidth;
+	bool q16_data = true;
 
 	if (!plane || !state) {
-		DRM_ERROR("Invalid plane/state\n");
+		SDE_ERROR("invalid plane/state\n");
 		ret = -EINVAL;
 		goto exit;
 	}
 
 	psde = to_sde_plane(plane);
 	pstate = to_sde_plane_state(state);
-	old_state = plane->state;
 
 	if (!psde->pipe_sblk) {
-		DRM_ERROR("Invalid plane catalog\n");
+		SDE_ERROR("invalid plane catalog\n");
 		ret = -EINVAL;
 		goto exit;
 	}
 
-	/* get decimation config from user space */
-	deci_w = 0;
-	deci_h = 0;
-	sc_u = msm_property_get_blob(&psde->property_info,
-			pstate->property_blobs,
-			&sc_u_size,
-			PLANE_PROP_SCALER);
-	if (sc_u) {
-		switch (sc_u->version) {
-		case SDE_DRM_SCALER_V1:
-			if (!_sde_plane_verify_blob(sc_u,
-					sc_u_size,
-					&sc_u->v1,
-					sizeof(struct sde_drm_scaler_v1))) {
-				deci_w = sc_u->v1.horz_decimate;
-				deci_h = sc_u->v1.vert_decimate;
-			}
-			break;
-		default:
-			DBG("Unrecognized scaler blob v%lld", sc_u->version);
-			break;
-		}
-	}
+	valid_scale_data = __get_scale_data(psde, pstate, sc_u, &sc_u_size);
+	deci_w = valid_scale_data && sc_u ? sc_u->v1.horz_decimate : 0;
+	deci_h = valid_scale_data && sc_u ? sc_u->v1.vert_decimate : 0;
 
 	/* src values are in Q16 fixed point, convert to integer */
-	src_x = state->src_x >> 16;
-	src_y = state->src_y >> 16;
-	src_w = state->src_w >> 16;
-	src_h = state->src_h >> 16;
+	POPULATE_RECT(&src, state->src_x, state->src_y, state->src_w,
+		state->src_h, q16_data);
+	POPULATE_RECT(&dst, state->crtc_x, state->crtc_y, state->crtc_w,
+		state->crtc_h, !q16_data);
 
-	src_deci_w = DECIMATED_DIMENSION(src_w, deci_w);
-	src_deci_h = DECIMATED_DIMENSION(src_h, deci_h);
+	src_deci_w = DECIMATED_DIMENSION(src.w, deci_w);
+	src_deci_h = DECIMATED_DIMENSION(src.h, deci_h);
 
-	src_max_x = 0xFFFF;
-	src_max_y = 0xFFFF;
-	src_max_w = 0x3FFF;
-	src_max_h = 0x3FFF;
-	upscale_max   = psde->pipe_sblk->maxupscale;
-	downscale_max = psde->pipe_sblk->maxdwnscale;
+	max_upscale = psde->pipe_sblk->maxupscale;
+	max_downscale = psde->pipe_sblk->maxdwnscale;
+	max_linewidth = psde->pipe_sblk->maxlinewidth;
 
-	/*
-	 * Including checks from mdss
-	 * - mdss_mdp_overlay_req_check()
-	 */
-	DBG("%s: check (%d -> %d)", psde->pipe_name,
-			sde_plane_enabled(old_state), sde_plane_enabled(state));
+	SDE_DEBUG("%s: check (%d -> %d)\n", psde->pipe_name,
+		sde_plane_enabled(plane->state), sde_plane_enabled(state));
 
-	if (sde_plane_enabled(state)) {
-		/* determine SDE format definition. State's fb is valid here. */
-		fmt = to_sde_format(msm_framebuffer_format(state->fb));
+	if (!sde_plane_enabled(state))
+		goto modeset_update;
 
-		/* don't check for other errors after first failure */
-		if (SDE_FORMAT_IS_YUV(fmt) &&
-			(!(psde->features & SDE_SSPP_SCALER) ||
-			 !(psde->features & BIT(SDE_SSPP_CSC)))) {
-			DRM_ERROR("Pipe doesn't support YUV\n");
+	fmt = to_sde_format(msm_framebuffer_format(state->fb));
+
+	min_src_size = SDE_FORMAT_IS_YUV(fmt) ? 2 : 1;
+
+	if (SDE_FORMAT_IS_YUV(fmt) &&
+		(!(psde->features & SDE_SSPP_SCALER) ||
+		 !(psde->features & BIT(SDE_SSPP_CSC)))) {
+		SDE_ERROR("plane doesn't have scaler/csc capability for yuv\n");
+		ret = -EINVAL;
+
+	/* check src bounds */
+	} else if (state->fb->width > MAX_IMG_WIDTH ||
+		state->fb->height > MAX_IMG_HEIGHT ||
+		src.w < min_src_size || src.h < min_src_size ||
+		CHECK_LAYER_BOUNDS(src.x, src.w, state->fb->width) ||
+		CHECK_LAYER_BOUNDS(src.y, src.h, state->fb->height)) {
+		SDE_ERROR("invalid source (%u, %u) -> (%u, %u)\n",
+			src.x, src.y, src.w, src.h);
+		ret = -E2BIG;
+
+	/* valid yuv image */
+	} else if (SDE_FORMAT_IS_YUV(fmt) && ((src.x & 0x1) || (src.y & 0x1) ||
+			 (src.w & 0x1) || (src.h & 0x1))) {
+		SDE_ERROR("invalid yuv source (%u, %u) -> (%u, %u)\n",
+				src.x, src.y, src.w, src.h);
+		ret = -EINVAL;
+
+	/* min dst support */
+	} else if (dst.w < 0x1 || dst.h < 0x1) {
+		SDE_ERROR("invalid dest rect (%u, %u) -> (%u, %u)\n",
+				dst.x, dst.y, dst.w, dst.h);
+		ret = -EINVAL;
+
+	/* decimation validation */
+	} else if (deci_w || deci_h) {
+		if ((deci_w > psde->pipe_sblk->maxhdeciexp) ||
+			(deci_h > psde->pipe_sblk->maxvdeciexp)) {
+			SDE_ERROR("too much decimation requested\n");
 			ret = -EINVAL;
-
-		/* verify source size/region */
-		} else if (!src_w || !src_h ||
-			(src_w > src_max_w) || (src_h > src_max_h) ||
-			(src_x > src_max_x) || (src_y > src_max_y) ||
-			(src_x + src_w > src_max_x) ||
-			(src_y + src_h > src_max_y)) {
-			DRM_ERROR("Invalid source (%u, %u) -> (%u, %u)\n",
-					src_x, src_y, src_x + src_w,
-					src_y + src_h);
-			ret = -EINVAL;
-
-		/* require even source for YUV */
-		} else if (SDE_FORMAT_IS_YUV(fmt) &&
-				((src_x & 0x1) || (src_y & 0x1) ||
-				 (src_w & 0x1) || (src_h & 0x1))) {
-			DRM_ERROR("Invalid odd src res/pos for YUV\n");
-			ret = -EINVAL;
-
-		/* verify scaler requirements */
-		} else if (!(psde->features & SDE_SSPP_SCALER) &&
-			((src_w != state->crtc_w) ||
-			 (src_h != state->crtc_h))) {
-			DRM_ERROR("Pipe doesn't support scaling %ux%u->%ux%u\n",
-					src_w, src_h, state->crtc_w,
-					state->crtc_h);
-			ret = -EINVAL;
-
-		/* check decimated source width */
-		} else if (src_deci_w > psde->pipe_sblk->maxlinewidth) {
-			DRM_ERROR("Invalid source [W:%u, Wd:%u] > %u\n",
-					src_w, src_deci_w,
-					psde->pipe_sblk->maxlinewidth);
-			ret = -EINVAL;
-
-		/* check max scaler capability */
-		} else if (((src_deci_w * upscale_max) < state->crtc_w) ||
-			((src_deci_h * upscale_max) < state->crtc_h) ||
-			((state->crtc_w * downscale_max) < src_deci_w) ||
-			((state->crtc_h * downscale_max) < src_deci_h)) {
-			DRM_ERROR("Too much scaling requested %ux%u -> %ux%u\n",
-					src_deci_w, src_deci_h,
-					state->crtc_w, state->crtc_h);
-			ret = -EINVAL;
-
-		/* check frame buffer */
-		} else if (_sde_plane_atomic_check_fb(
-				psde, pstate, state->fb)) {
+		} else if (fmt->fetch_mode != SDE_FETCH_LINEAR) {
+			SDE_ERROR("decimation requires linear fetch\n");
 			ret = -EINVAL;
 		}
 
-		/* check decimation (and bwc/fetch mode) */
-		if (!ret && (deci_w || deci_h)) {
-			if (SDE_FORMAT_IS_UBWC(fmt)) {
-				DRM_ERROR("No decimation with BWC\n");
-				ret = -EINVAL;
-			} else if ((deci_w > psde->pipe_sblk->maxhdeciexp) ||
-				(deci_h > psde->pipe_sblk->maxvdeciexp)) {
-				DRM_ERROR("Too much decimation requested\n");
-				ret = -EINVAL;
-			} else if (fmt->fetch_mode != SDE_FETCH_LINEAR) {
-				DRM_ERROR("Decimation requires linear fetch\n");
-				ret = -EINVAL;
-			}
-		}
+	} else if (!(psde->features & SDE_SSPP_SCALER) &&
+		((src.w != dst.w) || (src.h != dst.h))) {
+		SDE_ERROR("pipe doesn't support scaling %ux%u->%ux%u\n",
+			src.w, src.h, dst.w, dst.h);
+		ret = -EINVAL;
+
+	/* check decimated source width */
+	} else if (src_deci_w > max_linewidth) {
+		SDE_ERROR("invalid source width:%u, deci wid:%u, line wid:%u\n",
+				src.w, src_deci_w, max_linewidth);
+		ret = -E2BIG;
+
+	/* check max scaler capability */
+	} else if (((src_deci_w * max_upscale) < dst.w) ||
+		((src_deci_h * max_upscale) < dst.h) ||
+		((dst.w * max_downscale) < src_deci_w) ||
+		((dst.h * max_downscale) < src_deci_h)) {
+		SDE_ERROR("too much scaling requested %ux%u -> %ux%u\n",
+			src_deci_w, src_deci_h, dst.w, dst.h);
+		ret = -E2BIG;
 	}
 
+modeset_update:
 	if (!ret)
-		_sde_plane_atomic_check_mode_changed(psde, state, old_state);
-
+		_sde_plane_atomic_check_mode_changed(psde, state, plane->state);
 exit:
 	return ret;
 }
@@ -1081,7 +1084,7 @@
 	struct sde_plane_state *pstate;
 
 	if (!plane || !plane->state) {
-		DRM_ERROR("Invalid plane/state\n");
+		SDE_ERROR("invalid plane/state\n");
 		return;
 	}
 
@@ -1090,7 +1093,7 @@
 	state = plane->state;
 	pstate = to_sde_plane_state(state);
 
-	DBG("%s: update", sde_plane->pipe_name);
+	SDE_DEBUG("%s: update\n", sde_plane->pipe_name);
 
 	if (!sde_plane_enabled(state)) {
 		pstate->pending = true;
@@ -1098,12 +1101,7 @@
 		int ret;
 
 		pstate->pending = true;
-		ret = _sde_plane_mode_set(plane,
-				state->crtc, state->fb,
-				state->crtc_x, state->crtc_y,
-				state->crtc_w, state->crtc_h,
-				state->src_x,  state->src_y,
-				state->src_w, state->src_h);
+		ret = _sde_plane_mode_set(plane, state);
 		/* atomic_check should have ensured that this doesn't fail */
 		WARN_ON(ret < 0);
 	} else {
@@ -1112,8 +1110,10 @@
 	}
 }
 
+
 /* helper to install properties which are common to planes and crtcs */
-static void _sde_plane_install_properties(struct drm_plane *plane)
+static void _sde_plane_install_properties(struct drm_plane *plane,
+	u32 max_blendstages)
 {
 	static const struct drm_prop_enum_list e_blend_op[] = {
 		{SDE_DRM_BLEND_OP_NOT_DEFINED,    "not_defined"},
@@ -1128,55 +1128,46 @@
 	static struct sde_kms_info sde_info;
 	struct sde_plane *psde = to_sde_plane(plane);
 
-	DBG("");
-
 	if (!plane || !psde || !psde->pipe_hw || !psde->pipe_sblk) {
-		DRM_ERROR("Invalid argument(s)\n");
+		SDE_ERROR("Invalid argument(s)\n");
 		return;
 	}
 
-	/* range properties */
-	msm_property_install_range(&psde->property_info, "zpos", 0x0, 0, 255,
-			plane->type == DRM_PLANE_TYPE_PRIMARY ?
-				STAGE_BASE : STAGE0 + drm_plane_index(plane),
-			PLANE_PROP_ZPOS);
+	msm_property_install_range(&psde->property_info, "zpos", 0x0, 0,
+		max_blendstages, STAGE_BASE, PLANE_PROP_ZPOS);
 
 	msm_property_install_range(&psde->property_info, "alpha",
-			0x0, 0, 255, 255, PLANE_PROP_ALPHA);
+		0x0, 0, 255, 255, PLANE_PROP_ALPHA);
 
-	if (psde->pipe_hw->ops.setup_solidfill)
-		msm_property_install_range(&psde->property_info, "color_fill",
-				0, 0, 0xFFFFFFFF, 0,
-				PLANE_PROP_COLOR_FILL);
-
+	/* linux default file descriptor range on each process */
 	msm_property_install_range(&psde->property_info, "input_fence",
-			0x0, 0, ~0, ~0,
-			PLANE_PROP_INPUT_FENCE);
+		0x0, 0, 1024, 0, PLANE_PROP_INPUT_FENCE);
 
 	/* standard properties */
 	msm_property_install_rotation(&psde->property_info,
-			BIT(DRM_REFLECT_X) | BIT(DRM_REFLECT_Y),
-			PLANE_PROP_ROTATION);
+		BIT(DRM_REFLECT_X) | BIT(DRM_REFLECT_Y), PLANE_PROP_ROTATION);
 
-	/* enum/bitmask properties */
 	msm_property_install_enum(&psde->property_info, "blend_op", 0x0, 0,
-			e_blend_op, ARRAY_SIZE(e_blend_op),
-			PLANE_PROP_BLEND_OP);
-	msm_property_install_enum(&psde->property_info, "src_config", 0x0, 1,
-			e_src_config, ARRAY_SIZE(e_src_config),
-			PLANE_PROP_SRC_CONFIG);
+		e_blend_op, ARRAY_SIZE(e_blend_op), PLANE_PROP_BLEND_OP);
 
-	/* blob properties */
+	msm_property_install_enum(&psde->property_info, "src_config", 0x0, 1,
+		e_src_config, ARRAY_SIZE(e_src_config), PLANE_PROP_SRC_CONFIG);
+
+	if (psde->pipe_hw->ops.setup_solidfill)
+		msm_property_install_range(&psde->property_info, "color_fill",
+				0, 0, 0xFFFFFFFF, 0, PLANE_PROP_COLOR_FILL);
+
 	if (psde->features & SDE_SSPP_SCALER)
 		msm_property_install_blob(&psde->property_info, "scaler", 0,
 			PLANE_PROP_SCALER);
-	if (psde->features & BIT(SDE_SSPP_CSC)) {
+
+	if (psde->features & BIT(SDE_SSPP_CSC))
 		msm_property_install_blob(&psde->property_info, "csc", 0,
 			PLANE_PROP_CSC);
-	}
+
 	format_list = psde->pipe_sblk->format_list;
 	if (format_list) {
-		/* assume single thread */
+		/* it is called during probe - single threaded */
 		struct sde_kms_info *info = &sde_info;
 
 		msm_property_install_blob(&psde->property_info, "sde_info",
@@ -1210,9 +1201,9 @@
 	DBG("");
 
 	if (!plane) {
-		DRM_ERROR("Invalid plane\n");
+		SDE_ERROR("invalid plane\n");
 	} else if (!state) {
-		DRM_ERROR("Invalid state\n");
+		SDE_ERROR("invalid state\n");
 	} else {
 		psde = to_sde_plane(plane);
 		pstate = to_sde_plane_state(state);
@@ -1250,9 +1241,9 @@
 	DBG("");
 
 	if (!plane) {
-		DRM_ERROR("Invalid plane\n");
+		SDE_ERROR("invalid plane\n");
 	} else if (!state) {
-		DRM_ERROR("Invalid state\n");
+		SDE_ERROR("invalid state\n");
 	} else {
 		psde = to_sde_plane(plane);
 		pstate = to_sde_plane_state(state);
@@ -1299,7 +1290,7 @@
 	struct sde_plane_state *pstate;
 
 	if (!plane || !state) {
-		DRM_ERROR("Invalid plane/state\n");
+		SDE_ERROR("invalid plane/state\n");
 		return;
 	}
 
@@ -1366,12 +1357,12 @@
 	struct sde_plane_state *pstate;
 
 	if (!plane) {
-		DRM_ERROR("Invalid plane\n");
+		SDE_ERROR("invalid plane\n");
 		return;
 	}
 
 	psde = to_sde_plane(plane);
-	DBG("%s", psde->pipe_name);
+	SDE_DEBUG("%s\n", psde->pipe_name);
 
 	/* remove previous state, if present */
 	if (plane->state) {
@@ -1473,34 +1464,34 @@
 	struct msm_drm_private *priv;
 	struct sde_kms *kms;
 	enum drm_plane_type type;
-	int ret = -EINVAL;
+	int ret = -EINVAL, max_blendstages = 255;
 
 	if (!dev) {
-		DRM_ERROR("[%u]Device is NULL\n", pipe);
+		SDE_ERROR("[%u]device is NULL\n", pipe);
 		goto exit;
 	}
 
 	priv = dev->dev_private;
 	if (!priv) {
-		DRM_ERROR("[%u]Private data is NULL\n", pipe);
+		SDE_ERROR("[%u]private data is NULL\n", pipe);
 		goto exit;
 	}
 
 	if (!priv->kms) {
-		DRM_ERROR("[%u]Invalid KMS reference\n", pipe);
+		SDE_ERROR("[%u]invalid KMS reference\n", pipe);
 		goto exit;
 	}
 	kms = to_sde_kms(priv->kms);
 
 	if (!kms->catalog) {
-		DRM_ERROR("[%u]Invalid catalog reference\n", pipe);
+		SDE_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);
+		SDE_ERROR("[%u]failed to allocate local plane struct\n", pipe);
 		ret = -ENOMEM;
 		goto exit;
 	}
@@ -1513,11 +1504,11 @@
 	/* 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);
+		SDE_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);
+		SDE_ERROR("[%u]SSPP init returned invalid cfg\n", pipe);
 		goto clean_sspp;
 	}
 
@@ -1529,6 +1520,9 @@
 		goto clean_sspp;
 	}
 
+	if (kms->catalog && kms->catalog->mixer_count && kms->catalog->mixer)
+		max_blendstages = kms->catalog->mixer[0].sblk->maxblendstages;
+
 	/* add plane to DRM framework */
 	psde->nformats = sde_populate_formats(psde->pipe_sblk->format_list,
 			psde->formats,
@@ -1536,7 +1530,7 @@
 			ARRAY_SIZE(psde->formats));
 
 	if (!psde->nformats) {
-		DRM_ERROR("[%u]No valid formats for plane\n", pipe);
+		SDE_ERROR("[%u]no valid formats for plane\n", pipe);
 		goto clean_sspp;
 	}
 
@@ -1560,7 +1554,7 @@
 			PLANE_PROP_COUNT, PLANE_PROP_BLOBCOUNT,
 			sizeof(struct sde_plane_state));
 
-	_sde_plane_install_properties(plane);
+	_sde_plane_install_properties(plane, max_blendstages);
 
 	/* save user friendly pipe name for later */
 	snprintf(psde->pipe_name, SDE_NAME_SIZE, "plane%u", plane->base.id);
@@ -1569,7 +1563,7 @@
 
 	_sde_plane_init_debugfs(psde, kms);
 
-	DRM_INFO("[%u]Successfully created %s\n", pipe, psde->pipe_name);
+	DRM_INFO("[%u]successfully created %s\n", pipe, psde->pipe_name);
 	return plane;
 
 clean_sspp: