Browse Source

disp: msm: sde: pre-downscale support for inline rotation v2

Add support for enabling pre-downscale block to increase the
maximum downscale capability for true inline rotation use cases.

Change-Id: Ifa544bb0ae69439abef4bd427134290090fe7230
Signed-off-by: Steve Cohen <[email protected]>
Steve Cohen 6 years ago
parent
commit
60133f5ebb
7 changed files with 193 additions and 40 deletions
  1. 29 17
      msm/sde/sde_hw_catalog.c
  2. 8 2
      msm/sde/sde_hw_catalog.h
  3. 21 1
      msm/sde/sde_hw_sspp.c
  4. 8 0
      msm/sde/sde_hw_sspp.h
  5. 7 0
      msm/sde/sde_hw_util.h
  6. 119 20
      msm/sde/sde_plane.c
  7. 1 0
      msm/sde/sde_plane.h

+ 29 - 17
msm/sde/sde_hw_catalog.c

@@ -69,9 +69,12 @@
 #define MAX_DOWNSCALE_RATIO		4
 #define SSPP_UNITY_SCALE		1
 
-#define MAX_DOWNSCALE_RATIO_INLINE_ROT_RT_NUMERATOR	11
-#define MAX_DOWNSCALE_RATIO_INLINE_ROT_RT_DENOMINATOR	5
-#define MAX_DOWNSCALE_RATIO_INLINE_ROT_NRT_DEFAULT	4
+#define MAX_DOWNSCALE_RATIO_INROT_NOPD_RT_NUMERATOR	11
+#define MAX_DOWNSCALE_RATIO_INROT_NOPD_RT_DENOMINATOR	5
+#define MAX_DOWNSCALE_RATIO_INROT_PD_RT_NUMERATOR	4
+#define MAX_DOWNSCALE_RATIO_INROT_PD_RT_DENOMINATOR	1
+#define MAX_DOWNSCALE_RATIO_INROT_NRT_DEFAULT		4
+
 #define MAX_PRE_ROT_HEIGHT_INLINE_ROT_DEFAULT	1088
 
 #define MAX_HORZ_DECIMATION		4
@@ -1255,8 +1258,10 @@ static void _sde_sspp_setup_vig(struct sde_mdss_cfg *sde_cfg,
 
 	sblk->format_list = sde_cfg->vig_formats;
 	sblk->virt_format_list = sde_cfg->virt_vig_formats;
-	if (IS_SDE_INLINE_ROT_REV_100(sde_cfg->true_inline_rot_rev)) {
-		set_bit(SDE_SSPP_TRUE_INLINE_ROT_V1, &sspp->features);
+	if (IS_SDE_INLINE_ROT_REV_100(sde_cfg->true_inline_rot_rev) ||
+			IS_SDE_INLINE_ROT_REV_200(
+			sde_cfg->true_inline_rot_rev)) {
+		set_bit(SDE_SSPP_TRUE_INLINE_ROT, &sspp->features);
 		sblk->in_rot_format_list = sde_cfg->inline_rot_formats;
 		sblk->in_rot_maxdwnscale_rt_num =
 			sde_cfg->true_inline_dwnscale_rt_num;
@@ -1274,6 +1279,14 @@ static void _sde_sspp_setup_vig(struct sde_mdss_cfg *sde_cfg,
 			sde_cfg->true_inline_prefill_lines;
 	}
 
+	if (IS_SDE_INLINE_ROT_REV_200(sde_cfg->true_inline_rot_rev)) {
+		set_bit(SDE_SSPP_PREDOWNSCALE, &sspp->features);
+		sblk->in_rot_minpredwnscale_num =
+				MAX_DOWNSCALE_RATIO_INROT_NOPD_RT_NUMERATOR;
+		sblk->in_rot_minpredwnscale_denom =
+				MAX_DOWNSCALE_RATIO_INROT_NOPD_RT_DENOMINATOR;
+	}
+
 	if (sde_cfg->sc_cfg.has_sys_cache) {
 		set_bit(SDE_PERF_SSPP_SYS_CACHE, &sspp->perf_features);
 		sblk->llcc_scid = sde_cfg->sc_cfg.llcc_scid;
@@ -2311,8 +2324,7 @@ static int sde_rot_parse_dt(struct device_node *np,
 	if (rc) {
 		/*
 		 * This is not a fatal error, system cache can be disabled
-		 * in device tree, anyways recommendation is to have it
-		 * enabled, so print an error but don't fail
+		 * in device tree
 		 */
 		SDE_DEBUG("sys cache will be disabled rc:%d\n", rc);
 		rc = 0;
@@ -4310,11 +4322,11 @@ static int _sde_hardware_pre_caps(struct sde_mdss_cfg *sde_cfg, uint32_t hw_rev)
 		sde_cfg->has_vig_p010 = true;
 		sde_cfg->true_inline_rot_rev = SDE_INLINE_ROT_VERSION_1_0_0;
 		sde_cfg->true_inline_dwnscale_rt_num =
-			MAX_DOWNSCALE_RATIO_INLINE_ROT_RT_NUMERATOR;
+			MAX_DOWNSCALE_RATIO_INROT_NOPD_RT_NUMERATOR;
 		sde_cfg->true_inline_dwnscale_rt_denom =
-			MAX_DOWNSCALE_RATIO_INLINE_ROT_RT_DENOMINATOR;
+			MAX_DOWNSCALE_RATIO_INROT_NOPD_RT_DENOMINATOR;
 		sde_cfg->true_inline_dwnscale_nrt =
-			MAX_DOWNSCALE_RATIO_INLINE_ROT_NRT_DEFAULT;
+			MAX_DOWNSCALE_RATIO_INROT_NRT_DEFAULT;
 		sde_cfg->true_inline_prefill_fudge_lines = 2;
 		sde_cfg->true_inline_prefill_lines_nv12 = 32;
 		sde_cfg->true_inline_prefill_lines = 48;
@@ -4341,11 +4353,11 @@ static int _sde_hardware_pre_caps(struct sde_mdss_cfg *sde_cfg, uint32_t hw_rev)
 		sde_cfg->has_vig_p010 = true;
 		sde_cfg->true_inline_rot_rev = SDE_INLINE_ROT_VERSION_1_0_0;
 		sde_cfg->true_inline_dwnscale_rt_num =
-			MAX_DOWNSCALE_RATIO_INLINE_ROT_RT_NUMERATOR;
+			MAX_DOWNSCALE_RATIO_INROT_NOPD_RT_NUMERATOR;
 		sde_cfg->true_inline_dwnscale_rt_denom =
-			MAX_DOWNSCALE_RATIO_INLINE_ROT_RT_DENOMINATOR;
+			MAX_DOWNSCALE_RATIO_INROT_NOPD_RT_DENOMINATOR;
 		sde_cfg->true_inline_dwnscale_nrt =
-			MAX_DOWNSCALE_RATIO_INLINE_ROT_NRT_DEFAULT;
+			MAX_DOWNSCALE_RATIO_INROT_NRT_DEFAULT;
 		sde_cfg->true_inline_prefill_fudge_lines = 2;
 		sde_cfg->true_inline_prefill_lines_nv12 = 32;
 		sde_cfg->true_inline_prefill_lines = 48;
@@ -4395,13 +4407,13 @@ static int _sde_hardware_pre_caps(struct sde_mdss_cfg *sde_cfg, uint32_t hw_rev)
 		sde_cfg->has_hdr_plus = true;
 		set_bit(SDE_MDP_DHDR_MEMPOOL, &sde_cfg->mdp[0].features);
 		sde_cfg->has_vig_p010 = true;
-		sde_cfg->true_inline_rot_rev = SDE_INLINE_ROT_VERSION_1_0_0;
+		sde_cfg->true_inline_rot_rev = SDE_INLINE_ROT_VERSION_2_0_0;
 		sde_cfg->true_inline_dwnscale_rt_num =
-			MAX_DOWNSCALE_RATIO_INLINE_ROT_RT_NUMERATOR;
+				MAX_DOWNSCALE_RATIO_INROT_PD_RT_NUMERATOR;
 		sde_cfg->true_inline_dwnscale_rt_denom =
-			MAX_DOWNSCALE_RATIO_INLINE_ROT_RT_DENOMINATOR;
+				MAX_DOWNSCALE_RATIO_INROT_PD_RT_DENOMINATOR;
 		sde_cfg->true_inline_dwnscale_nrt =
-			MAX_DOWNSCALE_RATIO_INLINE_ROT_NRT_DEFAULT;
+				MAX_DOWNSCALE_RATIO_INROT_NRT_DEFAULT;
 		sde_cfg->true_inline_prefill_fudge_lines = 2;
 		sde_cfg->true_inline_prefill_lines_nv12 = 32;
 		sde_cfg->true_inline_prefill_lines = 48;

+ 8 - 2
msm/sde/sde_hw_catalog.h

@@ -216,7 +216,8 @@ enum {
  * @SDE_SSPP_SEC_UI_ALLOWED   Allows secure-ui layers
  * @SDE_SSPP_BLOCK_SEC_UI    Blocks secure-ui layers
  * @SDE_SSPP_SCALER_QSEED3LITE Qseed3lite algorithm support
- * @SDE_SSPP_TRUE_INLINE_ROT_V1, Support of SSPP true inline rotation v1
+ * @SDE_SSPP_TRUE_INLINE_ROT Support of SSPP true inline rotation v1
+ * @SDE_SSPP_PREDOWNSCALE    Support pre-downscale X-direction by 2 for inline
  * @SDE_SSPP_INLINE_CONST_CLR Inline rotation requires const clr disabled
  * @SDE_SSPP_MAX             maximum value
  */
@@ -245,7 +246,8 @@ enum {
 	SDE_SSPP_SEC_UI_ALLOWED,
 	SDE_SSPP_BLOCK_SEC_UI,
 	SDE_SSPP_SCALER_QSEED3LITE,
-	SDE_SSPP_TRUE_INLINE_ROT_V1,
+	SDE_SSPP_TRUE_INLINE_ROT,
+	SDE_SSPP_PREDOWNSCALE,
 	SDE_SSPP_INLINE_CONST_CLR,
 	SDE_SSPP_MAX
 };
@@ -622,6 +624,8 @@ struct sde_qos_lut_tbl {
  * @in_rot_maxdwnscale_rt_denom: max downscale ratio for inline rotation
  *                                 rt clients - denominator
  * @in_rot_maxdwnscale_nrt: max downscale ratio for inline rotation nrt clients
+ * @in_rot_minpredwnscale_num: min downscale ratio to enable pre-downscale
+ * @in_rot_minpredwnscale_denom: min downscale ratio to enable pre-downscale
  * @in_rot_maxheight: max pre rotated height for inline rotation
  * @in_rot_prefill_fudge_lines: prefill fudge lines for inline rotation
  * @in_rot_prefill_lines_mv12: prefill lines for nv12 format inline rotation
@@ -661,6 +665,8 @@ struct sde_sspp_sub_blks {
 	u32 in_rot_maxdwnscale_rt_num;
 	u32 in_rot_maxdwnscale_rt_denom;
 	u32 in_rot_maxdwnscale_nrt;
+	u32 in_rot_minpredwnscale_num;
+	u32 in_rot_minpredwnscale_denom;
 	u32 in_rot_maxheight;
 	u32 in_rot_prefill_fudge_lines;
 	u32 in_rot_prefill_lines_nv12;

+ 21 - 1
msm/sde/sde_hw_sspp.c

@@ -67,7 +67,8 @@
 #define SSPP_SRC_CONSTANT_COLOR            0x3c
 #define SSPP_EXCL_REC_CTL                  0x40
 #define SSPP_UBWC_STATIC_CTRL              0x44
-#define SSPP_FETCH_CONFIG                  0x048
+#define SSPP_FETCH_CONFIG                  0x48
+#define SSPP_PRE_DOWN_SCALE                0x50
 #define SSPP_DANGER_LUT                    0x60
 #define SSPP_SAFE_LUT                      0x64
 #define SSPP_CREQ_LUT                      0x68
@@ -596,6 +597,22 @@ static void _sde_hw_sspp_setup_scaler3(struct sde_hw_pipe *ctx,
 		ctx->cap->sblk->scaler_blk.version, idx, sspp->layout.format);
 }
 
+static void sde_hw_sspp_setup_pre_downscale(struct sde_hw_pipe *ctx,
+		struct sde_hw_inline_pre_downscale_cfg *pre_down)
+{
+	u32 idx, val;
+
+	if (!ctx || !pre_down || _sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx))
+		return;
+
+	val = pre_down->pre_downscale_x_0 |
+			(pre_down->pre_downscale_x_1 << 4) |
+			(pre_down->pre_downscale_y_0 << 8) |
+			(pre_down->pre_downscale_y_1 << 12);
+
+	SDE_REG_WRITE(&ctx->hw, SSPP_PRE_DOWN_SCALE + idx, val);
+}
+
 static u32 _sde_hw_sspp_get_scaler3_ver(struct sde_hw_pipe *ctx)
 {
 	u32 idx;
@@ -1242,6 +1259,9 @@ static void _setup_layer_ops(struct sde_hw_pipe *c,
 			c->ops.setup_scaler = reg_dmav1_setup_vig_qseed3;
 	}
 
+	if (test_bit(SDE_SSPP_PREDOWNSCALE, &features))
+		c->ops.setup_pre_downscale = sde_hw_sspp_setup_pre_downscale;
+
 	if (test_bit(SDE_PERF_SSPP_SYS_CACHE, &perf_features))
 		c->ops.setup_sys_cache = sde_hw_sspp_setup_sys_cache;
 

+ 8 - 0
msm/sde/sde_hw_sspp.h

@@ -516,6 +516,14 @@ struct sde_hw_sspp_ops {
 			struct sde_hw_scaler3_cfg *scaler3_cfg,
 			u32 offset);
 
+	/**
+	 * setup_pre_downscale - setup pre-downscaler for inline rotation
+	 * @ctx: Pointer to pipe context
+	 * @pre_down: Pointer to pre-downscaler configuration
+	 */
+	void (*setup_pre_downscale)(struct sde_hw_pipe *ctx,
+		struct sde_hw_inline_pre_downscale_cfg *pre_down);
+
 	/**
 	 * get_scaler_ver - get scaler h/w version
 	 * @ctx: Pointer to pipe context

+ 7 - 0
msm/sde/sde_hw_util.h

@@ -160,6 +160,13 @@ struct sde_hw_scaler3_lut_cfg {
 	size_t sep_len;
 };
 
+struct sde_hw_inline_pre_downscale_cfg {
+	u32 pre_downscale_x_0;
+	u32 pre_downscale_x_1;
+	u32 pre_downscale_y_0;
+	u32 pre_downscale_y_1;
+};
+
 u32 *sde_hw_util_get_log_mask_ptr(void);
 
 void sde_reg_write(struct sde_hw_blk_reg_map *c,

+ 119 - 20
msm/sde/sde_plane.c

@@ -1512,6 +1512,10 @@ static void _sde_plane_setup_scaler(struct sde_plane *psde,
 				pe->btm_ftch[i] = pe->num_ext_pxls_btm[i];
 		}
 	}
+
+	if (psde->pipe_hw->ops.setup_pre_downscale)
+		psde->pipe_hw->ops.setup_pre_downscale(psde->pipe_hw,
+				&pstate->pre_down);
 }
 
 /**
@@ -1652,7 +1656,7 @@ static int sde_plane_rot_atomic_check(struct drm_plane *plane,
 			!psde->pipe_sblk->in_rot_maxdwnscale_nrt ||
 			!psde->pipe_sblk->in_rot_maxheight ||
 			!psde->pipe_sblk->in_rot_format_list ||
-			!(psde->features & BIT(SDE_SSPP_TRUE_INLINE_ROT_V1))) {
+			!(psde->features & BIT(SDE_SSPP_TRUE_INLINE_ROT))) {
 			SDE_ERROR_PLANE(psde,
 			    "wrong config rt:%d/%d nrt:%d fmt:%d h:%d 0x%x\n",
 				!psde->pipe_sblk->in_rot_maxdwnscale_rt_num,
@@ -1787,7 +1791,7 @@ static void sde_plane_rot_install_properties(struct drm_plane *plane,
 		return;
 	}
 
-	if (psde->features & BIT(SDE_SSPP_TRUE_INLINE_ROT_V1))
+	if (psde->features & BIT(SDE_SSPP_TRUE_INLINE_ROT))
 		supported_rotations |= DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 |
 			DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270;
 
@@ -2269,6 +2273,12 @@ int sde_plane_validate_src_addr(struct drm_plane *plane,
 	return ret;
 }
 
+static inline bool _sde_plane_is_pre_downscale_enabled(
+		struct sde_hw_inline_pre_downscale_cfg *pre_down)
+{
+	return pre_down->pre_downscale_x_0 || pre_down->pre_downscale_y_0;
+}
+
 static int _sde_plane_validate_scaler_v2(struct sde_plane *psde,
 		struct sde_plane_state *pstate,
 		const struct sde_format *fmt,
@@ -2276,6 +2286,8 @@ static int _sde_plane_validate_scaler_v2(struct sde_plane *psde,
 		uint32_t src_w, uint32_t src_h,
 		uint32_t deci_w, uint32_t deci_h)
 {
+	struct sde_hw_inline_pre_downscale_cfg *pd_cfg;
+	bool pre_down_en;
 	int i;
 
 	if (!psde || !pstate || !fmt) {
@@ -2288,6 +2300,9 @@ static int _sde_plane_validate_scaler_v2(struct sde_plane *psde,
 	    pstate->scaler_check_state != SDE_PLANE_SCLCHECK_SCALER_V2_CHECK))
 		return 0;
 
+	pd_cfg = &pstate->pre_down;
+	pre_down_en = _sde_plane_is_pre_downscale_enabled(pd_cfg);
+
 	pstate->scaler_check_state = SDE_PLANE_SCLCHECK_INVALID;
 
 	for (i = 0; i < SDE_MAX_PLANES; i++) {
@@ -2295,12 +2310,26 @@ static int _sde_plane_validate_scaler_v2(struct sde_plane *psde,
 		uint32_t vert_req_pixels, vert_fetch_pixels;
 		uint32_t src_w_tmp, src_h_tmp;
 		uint32_t scaler_w, scaler_h;
+		uint32_t pre_down_ratio_x = 1, pre_down_ratio_y = 1;
 		bool rot;
 
 		/* re-use color plane 1's config for plane 2 */
 		if (i == 2)
 			continue;
 
+		if (pre_down_en) {
+			if (i == 0 && pd_cfg->pre_downscale_x_0)
+				pre_down_ratio_x = pd_cfg->pre_downscale_x_0;
+			if (i == 0 && pd_cfg->pre_downscale_y_0)
+				pre_down_ratio_y = pd_cfg->pre_downscale_y_0;
+			if ((i == 1 || i == 2) && pd_cfg->pre_downscale_x_1)
+				pre_down_ratio_x = pd_cfg->pre_downscale_x_1;
+			if ((i == 1 || i == 2) && pd_cfg->pre_downscale_y_1)
+				pre_down_ratio_y = pd_cfg->pre_downscale_y_1;
+			SDE_DEBUG_PLANE(psde, "pre_down[%d]: x:%d, y:%d\n",
+					i, pre_down_ratio_x, pre_down_ratio_y);
+		}
+
 		src_w_tmp = src_w;
 		src_h_tmp = src_h;
 
@@ -2359,13 +2388,14 @@ static int _sde_plane_validate_scaler_v2(struct sde_plane *psde,
 		 * repeat/drop, src_width and src_height are only specified
 		 * for Y and UV plane
 		 */
-		if (i != 3 && (hor_req_pixels != scaler_w ||
-					vert_req_pixels != scaler_h)) {
+		if (i != 3 && (hor_req_pixels / pre_down_ratio_x != scaler_w ||
+					vert_req_pixels / pre_down_ratio_y !=
+					scaler_h)) {
 			SDE_ERROR_PLANE(psde,
-			    "roi[%d] roi:%dx%d scaler:%dx%d src:%dx%d rot:%d\n",
+			"roi[%d] roi:%dx%d scaler:%dx%d src:%dx%d rot:%d pd:%d/%d\n",
 				i, pstate->pixel_ext.roi_w[i],
-				pstate->pixel_ext.roi_h[i],
-				scaler_w, scaler_h, src_w, src_h, rot);
+				pstate->pixel_ext.roi_h[i], scaler_w, scaler_h,
+				src_w, src_h, rot, pre_down_ratio_x, pre_down_ratio_y);
 			return -EINVAL;
 		}
 
@@ -2393,6 +2423,39 @@ static int _sde_plane_validate_scaler_v2(struct sde_plane *psde,
 	return 0;
 }
 
+static int _sde_atomic_check_pre_downscale(struct sde_plane *psde,
+		struct sde_plane_state *pstate, struct sde_rect *dst,
+		u32 scaler_src_w, u32 scaler_src_h)
+{
+	int ret = 0;
+	u32 min_ratio_numer, min_ratio_denom;
+
+	min_ratio_numer = psde->pipe_sblk->in_rot_minpredwnscale_num;
+	min_ratio_denom = psde->pipe_sblk->in_rot_minpredwnscale_denom;
+
+	if (!(psde->features & BIT(SDE_SSPP_PREDOWNSCALE))) {
+		SDE_ERROR_PLANE(psde,
+			"hw does not support pre-downscaler: 0x%x\n",
+			psde->features);
+		ret = -EINVAL;
+	} else if (!min_ratio_numer || !min_ratio_denom) {
+		SDE_ERROR_PLANE(psde,
+			"min downscale ratio not set! %u / %u\n",
+			min_ratio_numer, min_ratio_denom);
+		ret = -EINVAL;
+	} else if ((scaler_src_w < mult_frac(dst->w, min_ratio_numer,
+			min_ratio_denom)) || (scaler_src_h < mult_frac(
+			dst->h, min_ratio_numer, min_ratio_denom))) {
+		SDE_ERROR_PLANE(psde,
+			"failed min downscale check %ux%u->%ux%u, %u/%u\n",
+			scaler_src_w, scaler_src_h, dst->w, dst->h,
+			min_ratio_numer, min_ratio_denom);
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
 static int _sde_atomic_check_decimation_scaler(struct drm_plane_state *state,
 	struct sde_plane *psde, const struct sde_format *fmt,
 	struct sde_plane_state *pstate, struct sde_rect *src,
@@ -2403,7 +2466,7 @@ static int _sde_atomic_check_decimation_scaler(struct drm_plane_state *state,
 	uint32_t scaler_src_w, scaler_src_h;
 	uint32_t max_downscale_num, max_downscale_denom;
 	uint32_t max_upscale, max_linewidth;
-	bool inline_rotation, rt_client;
+	bool inline_rotation, rt_client, pre_down_en = false;
 	struct drm_crtc *crtc;
 	struct drm_crtc_state *new_cstate;
 
@@ -2430,16 +2493,25 @@ static int _sde_atomic_check_decimation_scaler(struct drm_plane_state *state,
 
 	max_upscale = psde->pipe_sblk->maxupscale;
 	max_linewidth = psde->pipe_sblk->maxlinewidth;
+	if (psde->features & BIT(SDE_SSPP_PREDOWNSCALE))
+		pre_down_en = _sde_plane_is_pre_downscale_enabled(
+				&pstate->pre_down);
 
 	crtc = state->crtc;
 	new_cstate = drm_atomic_get_new_crtc_state(state->state, crtc);
 
 	rt_client = sde_crtc_is_rt_client(crtc, new_cstate);
 
+	max_downscale_num = psde->pipe_sblk->maxdwnscale;
 	max_downscale_denom = 1;
 	/* inline rotation RT clients have a different max downscaling limit */
 	if (inline_rotation) {
-		if (rt_client) {
+		if (rt_client && !pre_down_en) {
+			max_downscale_num =
+				psde->pipe_sblk->in_rot_minpredwnscale_num;
+			max_downscale_denom =
+				psde->pipe_sblk->in_rot_minpredwnscale_denom;
+		} else if (rt_client) {
 			max_downscale_num =
 				psde->pipe_sblk->in_rot_maxdwnscale_rt_num;
 			max_downscale_denom =
@@ -2448,8 +2520,6 @@ static int _sde_atomic_check_decimation_scaler(struct drm_plane_state *state,
 			max_downscale_num =
 				psde->pipe_sblk->in_rot_maxdwnscale_nrt;
 		}
-	} else {
-		max_downscale_num = psde->pipe_sblk->maxdwnscale;
 	}
 
 	/* decimation validation */
@@ -2477,23 +2547,31 @@ static int _sde_atomic_check_decimation_scaler(struct drm_plane_state *state,
 				"invalid src w:%u, deci w:%u, line w:%u\n",
 				src->w, src_deci_w, max_linewidth);
 		ret = -E2BIG;
-	}
 
 	/* check max scaler capability */
-	else if (((scaler_src_w * max_upscale) < dst->w) ||
+	} else if (((scaler_src_w * max_upscale) < dst->w) ||
 		((scaler_src_h * max_upscale) < dst->h) ||
 		(((dst->w * max_downscale_num) / max_downscale_denom)
 			< scaler_src_w) ||
 		(((dst->h * max_downscale_num) / max_downscale_denom)
 			< scaler_src_h)) {
 		SDE_ERROR_PLANE(psde,
-			"too much scaling requested %ux%u->%ux%u rot:%d\n",
+			"too much scaling %ux%u->%ux%u rot:%d dwn:%d/%d\n",
 			scaler_src_w, scaler_src_h, dst->w, dst->h,
-			inline_rotation);
+			inline_rotation, max_downscale_num,
+			max_downscale_denom);
 		ret = -E2BIG;
+
+	/* check inline pre-downscale support */
+	} else if (inline_rotation && pre_down_en &&
+			_sde_atomic_check_pre_downscale(psde, pstate, dst,
+			scaler_src_w, scaler_src_h)) {
+		ret = -EINVAL;
+
+	/* QSEED validation */
 	} else if (_sde_plane_validate_scaler_v2(psde, pstate, fmt,
-				width, height,
-				src->w, src->h, deci_w, deci_h)) {
+				width, height, src->w, src->h,
+				deci_w, deci_h)) {
 		ret = -EINVAL;
 	}
 
@@ -3571,10 +3649,11 @@ static void _sde_plane_install_properties(struct drm_plane *plane,
 	if (psde->features & BIT(SDE_SSPP_BLOCK_SEC_UI))
 		sde_kms_info_add_keyint(info, "block_sec_ui", 1);
 
-	if (psde->features & BIT(SDE_SSPP_TRUE_INLINE_ROT_V1)) {
+	if (psde->features & BIT(SDE_SSPP_TRUE_INLINE_ROT)) {
 		const struct sde_format_extended *inline_rot_fmt_list;
 
-		sde_kms_info_add_keyint(info, "true_inline_rot_rev", 1);
+		sde_kms_info_add_keyint(info, "true_inline_rot_rev",
+				catalog->true_inline_rot_rev);
 		sde_kms_info_add_keyint(info,
 			"true_inline_dwnscale_rt",
 			(int) (psde->pipe_sblk->in_rot_maxdwnscale_rt_num /
@@ -3769,6 +3848,15 @@ static inline void _sde_plane_set_scaler_v1(struct sde_plane *psde,
 	SDE_DEBUG_PLANE(psde, "user property data copied\n");
 }
 
+static void _sde_plane_clear_predownscale_settings(
+		struct sde_plane_state *pstate)
+{
+	pstate->pre_down.pre_downscale_x_0 = 0;
+	pstate->pre_down.pre_downscale_x_1 = 0;
+	pstate->pre_down.pre_downscale_y_0 = 0;
+	pstate->pre_down.pre_downscale_y_1 = 0;
+}
+
 static inline void _sde_plane_set_scaler_v2(struct sde_plane *psde,
 		struct sde_plane_state *pstate, void __user *usr)
 {
@@ -3776,6 +3864,7 @@ static inline void _sde_plane_set_scaler_v2(struct sde_plane *psde,
 	struct sde_hw_pixel_ext *pe;
 	int i;
 	struct sde_hw_scaler3_cfg *cfg;
+	struct sde_hw_inline_pre_downscale_cfg *pd_cfg;
 
 	if (!psde || !pstate) {
 		SDE_ERROR("invalid argument(s)\n");
@@ -3783,10 +3872,12 @@ static inline void _sde_plane_set_scaler_v2(struct sde_plane *psde,
 	}
 
 	cfg = &pstate->scaler3_cfg;
+	pd_cfg = &pstate->pre_down;
 	pstate->scaler_check_state = SDE_PLANE_SCLCHECK_NONE;
 	if (!usr) {
 		SDE_DEBUG_PLANE(psde, "scale data removed\n");
 		cfg->enable = 0;
+		_sde_plane_clear_predownscale_settings(pstate);
 		goto end;
 	}
 
@@ -3799,12 +3890,20 @@ static inline void _sde_plane_set_scaler_v2(struct sde_plane *psde,
 	if (!scale_v2.enable) {
 		SDE_DEBUG_PLANE(psde, "scale data removed\n");
 		cfg->enable = 0;
+		_sde_plane_clear_predownscale_settings(pstate);
 		goto end;
 	}
 
 	/* populate from user space */
 	sde_set_scaler_v2(cfg, &scale_v2);
 
+	if (psde->features & BIT(SDE_SSPP_PREDOWNSCALE)) {
+		pd_cfg->pre_downscale_x_0 = scale_v2.pre_downscale_x_0;
+		pd_cfg->pre_downscale_x_1 = scale_v2.pre_downscale_x_1;
+		pd_cfg->pre_downscale_y_0 = scale_v2.pre_downscale_y_0;
+		pd_cfg->pre_downscale_y_1 = scale_v2.pre_downscale_y_1;
+	}
+
 	pe = &pstate->pixel_ext;
 	memset(pe, 0, sizeof(struct sde_hw_pixel_ext));
 
@@ -4311,7 +4410,7 @@ static int _sde_plane_init_debugfs(struct drm_plane *plane)
 				psde->debugfs_root,
 				&psde->debugfs_default_scale);
 
-	if (cfg->features & BIT(SDE_SSPP_TRUE_INLINE_ROT_V1)) {
+	if (cfg->features & BIT(SDE_SSPP_TRUE_INLINE_ROT)) {
 		debugfs_create_u32("in_rot_max_downscale_rt_num",
 			0600,
 			psde->debugfs_root,

+ 1 - 0
msm/sde/sde_plane.h

@@ -102,6 +102,7 @@ struct sde_plane_state {
 	struct sde_hw_scaler3_cfg scaler3_cfg;
 	struct sde_hw_pixel_ext pixel_ext;
 	enum sde_plane_sclcheck_state scaler_check_state;
+	struct sde_hw_inline_pre_downscale_cfg pre_down;
 
 	/* @sc_cfg: system_cache configuration */
 	struct sde_hw_pipe_sc_cfg sc_cfg;