drm/msm/sde: add qseedv3.x support for sde

Qseedv3.x block supports filtering, scaling and sharpening.
Change adds support to program scaler, detail enhancer
and LUT coefficients.

Change-Id: Idfec866dd9f7acb73c79780e2c3b6b6ce73d42c8
Signed-off-by: abeykun <abeykun@codeaurora.org>
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index 86e44ad..28c3606 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -86,7 +86,7 @@
 	struct sde_hw_pipe *pipe_hw;
 	struct sde_hw_pipe_cfg pipe_cfg;
 	struct sde_hw_sharp_cfg sharp_cfg;
-	struct sde_hw_scaler3_cfg scaler3_cfg;
+	struct sde_hw_scaler3_cfg *scaler3_cfg;
 	struct sde_hw_pipe_qos_cfg pipe_qos_cfg;
 	uint32_t color_fill;
 	bool is_error;
@@ -547,6 +547,29 @@
 		psde->pipe_hw->ops.setup_sourceaddress(psde->pipe_hw, pipe_cfg);
 }
 
+static int _sde_plane_setup_scaler3_lut(struct sde_plane *psde,
+		struct sde_plane_state *pstate)
+{
+	struct sde_hw_scaler3_cfg *cfg = psde->scaler3_cfg;
+	int ret = 0;
+
+	cfg->dir_lut = msm_property_get_blob(
+			&psde->property_info,
+			pstate->property_blobs, &cfg->dir_len,
+			PLANE_PROP_SCALER_LUT_ED);
+	cfg->cir_lut = msm_property_get_blob(
+			&psde->property_info,
+			pstate->property_blobs, &cfg->cir_len,
+			PLANE_PROP_SCALER_LUT_CIR);
+	cfg->sep_lut = msm_property_get_blob(
+			&psde->property_info,
+			pstate->property_blobs, &cfg->sep_len,
+			PLANE_PROP_SCALER_LUT_SEP);
+	if (!cfg->dir_lut || !cfg->cir_lut || !cfg->sep_lut)
+		ret = -ENODATA;
+	return ret;
+}
+
 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,
@@ -766,14 +789,17 @@
 
 	/* update scaler */
 	if (psde->features & BIT(SDE_SSPP_SCALER_QSEED3)) {
-		if (!psde->pixel_ext_usr) {
+		int error;
+
+		error = _sde_plane_setup_scaler3_lut(psde, pstate);
+		if (error || !psde->pixel_ext_usr) {
 			/* calculate default config for QSEED3 */
 			_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,
+					psde->scaler3_cfg, fmt,
 					chroma_subsmpl_h, chroma_subsmpl_v);
 		}
 	} else if (!psde->pixel_ext_usr) {
@@ -888,7 +914,8 @@
 
 		if (psde->pipe_hw->ops.setup_rects)
 			psde->pipe_hw->ops.setup_rects(psde->pipe_hw,
-					&psde->pipe_cfg, &psde->pixel_ext);
+					&psde->pipe_cfg, &psde->pixel_ext,
+					psde->scaler3_cfg);
 	}
 
 	return 0;
@@ -932,6 +959,7 @@
 	while ((idx = msm_property_pop_dirty(&psde->property_info)) >= 0) {
 		switch (idx) {
 		case PLANE_PROP_SCALER_V1:
+		case PLANE_PROP_SCALER_V2:
 		case PLANE_PROP_H_DECIMATE:
 		case PLANE_PROP_V_DECIMATE:
 		case PLANE_PROP_SRC_CONFIG:
@@ -1012,7 +1040,8 @@
 			_sde_plane_setup_scaler(psde, fmt, pstate);
 
 			psde->pipe_hw->ops.setup_rects(psde->pipe_hw,
-					&psde->pipe_cfg, &psde->pixel_ext);
+					&psde->pipe_cfg, &psde->pixel_ext,
+					psde->scaler3_cfg);
 		}
 	}
 
@@ -1428,7 +1457,16 @@
 				PLANE_PROP_V_DECIMATE);
 	}
 
-	if (psde->features & SDE_SSPP_SCALER) {
+	if (psde->features & BIT(SDE_SSPP_SCALER_QSEED3)) {
+		msm_property_install_volatile_range(&psde->property_info,
+			"scaler_v2", 0x0, 0, ~0, 0, PLANE_PROP_SCALER_V2);
+		msm_property_install_blob(&psde->property_info, "lut_ed", 0,
+			PLANE_PROP_SCALER_LUT_ED);
+		msm_property_install_blob(&psde->property_info, "lut_cir", 0,
+			PLANE_PROP_SCALER_LUT_CIR);
+		msm_property_install_blob(&psde->property_info, "lut_sep", 0,
+			PLANE_PROP_SCALER_LUT_SEP);
+	} else if (psde->features & SDE_SSPP_SCALER) {
 		msm_property_install_volatile_range(&psde->property_info,
 			"scaler_v1", 0x0, 0, ~0, 0, PLANE_PROP_SCALER_V1);
 	}
@@ -1581,6 +1619,99 @@
 	SDE_DEBUG_PLANE(psde, "user property data copied\n");
 }
 
+static inline void _sde_plane_set_scaler_v2(struct sde_plane *psde,
+		struct sde_plane_state *pstate, void *usr)
+{
+	struct sde_drm_scaler_v2 scale_v2;
+	struct sde_hw_pixel_ext *pe;
+	int i;
+	struct sde_hw_scaler3_cfg *cfg;
+
+	if (!psde) {
+		SDE_ERROR("invalid plane\n");
+		return;
+	}
+
+	cfg = psde->scaler3_cfg;
+	psde->pixel_ext_usr = false;
+	if (!usr) {
+		SDE_DEBUG_PLANE(psde, "scale data removed\n");
+		return;
+	}
+
+	if (copy_from_user(&scale_v2, usr, sizeof(scale_v2))) {
+		SDE_ERROR_PLANE(psde, "failed to copy scale data\n");
+		return;
+	}
+
+	/* populate from user space */
+	pe = &(psde->pixel_ext);
+	memset(pe, 0, sizeof(struct sde_hw_pixel_ext));
+	cfg->enable = scale_v2.enable;
+	cfg->dir_en = scale_v2.dir_en;
+	for (i = 0; i < SDE_MAX_PLANES; i++) {
+		cfg->init_phase_x[i] = scale_v2.init_phase_x[i];
+		cfg->phase_step_x[i] = scale_v2.phase_step_x[i];
+		cfg->init_phase_y[i] = scale_v2.init_phase_y[i];
+		cfg->phase_step_y[i] = scale_v2.phase_step_y[i];
+
+		cfg->preload_x[i] = scale_v2.preload_x[i];
+		cfg->preload_y[i] = scale_v2.preload_y[i];
+		cfg->src_width[i] = scale_v2.src_width[i];
+		cfg->src_height[i] = scale_v2.src_height[i];
+	}
+	cfg->dst_width = scale_v2.dst_width;
+	cfg->dst_height = scale_v2.dst_height;
+
+	cfg->y_rgb_filter_cfg = scale_v2.y_rgb_filter_cfg;
+	cfg->uv_filter_cfg = scale_v2.uv_filter_cfg;
+	cfg->alpha_filter_cfg = scale_v2.alpha_filter_cfg;
+	cfg->blend_cfg = scale_v2.blend_cfg;
+
+	cfg->lut_flag = scale_v2.lut_flag;
+	cfg->dir_lut_idx = scale_v2.dir_lut_idx;
+	cfg->y_rgb_cir_lut_idx = scale_v2.y_rgb_cir_lut_idx;
+	cfg->uv_cir_lut_idx = scale_v2.uv_cir_lut_idx;
+	cfg->y_rgb_sep_lut_idx = scale_v2.y_rgb_sep_lut_idx;
+	cfg->uv_sep_lut_idx = scale_v2.uv_sep_lut_idx;
+
+	cfg->de.enable = scale_v2.de.enable;
+	cfg->de.sharpen_level1 = scale_v2.de.sharpen_level1;
+	cfg->de.sharpen_level2 = scale_v2.de.sharpen_level2;
+	cfg->de.clip = scale_v2.de.clip;
+	cfg->de.limit = scale_v2.de.limit;
+	cfg->de.thr_quiet = scale_v2.de.thr_quiet;
+	cfg->de.thr_dieout = scale_v2.de.thr_dieout;
+	cfg->de.thr_low = scale_v2.de.thr_low;
+	cfg->de.thr_high = scale_v2.de.thr_high;
+	cfg->de.prec_shift = scale_v2.de.prec_shift;
+	for (i = 0; i < SDE_MAX_DE_CURVES; i++) {
+		cfg->de.adjust_a[i] = scale_v2.de.adjust_a[i];
+		cfg->de.adjust_b[i] = scale_v2.de.adjust_b[i];
+		cfg->de.adjust_c[i] = scale_v2.de.adjust_c[i];
+	}
+	for (i = 0; i < SDE_MAX_PLANES; i++) {
+		pe->num_ext_pxls_left[i] = scale_v2.lr.num_pxls_start[i];
+		pe->num_ext_pxls_right[i] = scale_v2.lr.num_pxls_end[i];
+		pe->left_ftch[i] = scale_v2.lr.ftch_start[i];
+		pe->right_ftch[i] = scale_v2.lr.ftch_end[i];
+		pe->left_rpt[i] = scale_v2.lr.rpt_start[i];
+		pe->right_rpt[i] = scale_v2.lr.rpt_end[i];
+		pe->roi_w[i] = scale_v2.lr.roi[i];
+
+		pe->num_ext_pxls_top[i] = scale_v2.tb.num_pxls_start[i];
+		pe->num_ext_pxls_btm[i] = scale_v2.tb.num_pxls_end[i];
+		pe->top_ftch[i] = scale_v2.tb.ftch_start[i];
+		pe->btm_ftch[i] = scale_v2.tb.ftch_end[i];
+		pe->top_rpt[i] = scale_v2.tb.rpt_start[i];
+		pe->btm_rpt[i] = scale_v2.tb.rpt_end[i];
+		pe->roi_h[i] = scale_v2.tb.roi[i];
+	}
+	psde->pixel_ext_usr = true;
+
+	SDE_DEBUG_PLANE(psde, "user property data copied\n");
+}
+
 static int sde_plane_atomic_set_property(struct drm_plane *plane,
 		struct drm_plane_state *state, struct drm_property *property,
 		uint64_t val)
@@ -1613,6 +1744,10 @@
 			case PLANE_PROP_SCALER_V1:
 				_sde_plane_set_scaler_v1(psde, (void *)val);
 				break;
+			case PLANE_PROP_SCALER_V2:
+				_sde_plane_set_scaler_v2(psde, pstate,
+					(void *)val);
+				break;
 			default:
 				/* nothing to do */
 				break;
@@ -1930,6 +2065,17 @@
 		goto clean_sspp;
 	}
 
+	if (psde->features & BIT(SDE_SSPP_SCALER_QSEED3)) {
+		psde->scaler3_cfg = kzalloc(sizeof(struct sde_hw_scaler3_cfg),
+			GFP_KERNEL);
+		if (!psde->scaler3_cfg) {
+			SDE_ERROR("[%u]failed to allocate scale struct\n",
+				pipe);
+			ret = -ENOMEM;
+			goto clean_sspp;
+		}
+	}
+
 	/* add plane to DRM framework */
 	psde->nformats = sde_populate_formats(psde->pipe_sblk->format_list,
 			psde->formats,
@@ -1975,6 +2121,9 @@
 clean_sspp:
 	if (psde && psde->pipe_hw)
 		sde_hw_sspp_destroy(psde->pipe_hw);
+
+	if (psde && psde->scaler3_cfg)
+		kfree(psde->scaler3_cfg);
 clean_plane:
 	kfree(psde);
 exit: