msm: mdss: Add overlay source side histogram LUT

Allow for overlay API to set histogram LUT. Currently multiple pipes can be
specified by the overlay requests; however, only the pipe that was
allocated by the request will have the histogram LUT applied to it.

Change-Id: Ifebca3fd3cc03e4ed9df638555da1b6d850e070b
Signed-off-by: Carl Vanderlip <carlv@codeaurora.org>
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 51776db..baedd03 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -878,6 +878,7 @@
 {
 	int i, j;
 	char *offset;
+	struct mdss_mdp_pipe *vig;
 
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 	mdata->mdp_rev = MDSS_MDP_REG_READ(MDSS_MDP_REG_HW_VERSION);
@@ -899,7 +900,16 @@
 			writel_relaxed(j, offset);
 
 		/* swap */
-		writel_relaxed(i, offset + 4);
+		writel_relaxed(1, offset + 4);
+	}
+	vig = mdata->vig_pipes;
+	for (i = 0; i < mdata->nvig_pipes; i++) {
+		offset = vig[i].base +
+			MDSS_MDP_REG_VIG_HIST_LUT_BASE;
+		for (j = 0; j < ENHIST_LUT_ENTRIES; j++)
+			writel_relaxed(j, offset);
+		/* swap */
+		writel_relaxed(1, offset + 16);
 	}
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 	pr_debug("MDP hw init done\n");
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 27db359..eaff2f4 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -248,6 +248,7 @@
 struct mdss_pipe_pp_res {
 	u32 igc_c0_c1[IGC_LUT_ENTRIES];
 	u32 igc_c2[IGC_LUT_ENTRIES];
+	u32 hist_lut[ENHIST_LUT_ENTRIES];
 	struct pp_hist_col_info hist;
 	struct pp_sts_type pp_sts;
 };
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 8bb5ce1..a0ede3c 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -405,6 +405,16 @@
 						pipe->pp_cfg.hist_cfg.block);
 			}
 		}
+		len = pipe->pp_cfg.hist_lut_cfg.len;
+		if ((pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_HIST_LUT_CFG) &&
+						(len == ENHIST_LUT_ENTRIES)) {
+			ret = copy_from_user(pipe->pp_res.hist_lut,
+					pipe->pp_cfg.hist_lut_cfg.data,
+					sizeof(uint32_t) * len);
+			if (ret)
+				return -ENOMEM;
+			pipe->pp_cfg.hist_lut_cfg.data = pipe->pp_res.hist_lut;
+		}
 	}
 
 	if (pipe->flags & MDP_DEINTERLACE) {
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 9fb4e1e..cf9a8b6 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -169,7 +169,8 @@
 				struct mdp_ar_gc_lut_data *lut_data);
 static void pp_update_argc_lut(u32 offset,
 				struct mdp_pgc_lut_data *config);
-static void pp_update_hist_lut(u32 offset, struct mdp_hist_lut_data *cfg);
+static void pp_update_hist_lut(char __iomem *base,
+				struct mdp_hist_lut_data *cfg);
 static void pp_pa_config(unsigned long flags, u32 base,
 				struct pp_sts_type *pp_sts,
 				struct mdp_pa_cfg *pa_config);
@@ -180,7 +181,7 @@
 				struct pp_sts_type *pp_sts,
 				struct mdp_igc_lut_data *igc_config,
 				u32 pipe_num);
-static void pp_enhist_config(unsigned long flags, u32 base,
+static void pp_enhist_config(unsigned long flags, char __iomem *base,
 				struct pp_sts_type *pp_sts,
 				struct mdp_hist_lut_data *enhist_cfg);
 static void pp_sharp_config(char __iomem *offset,
@@ -381,7 +382,7 @@
 	}
 }
 
-static void pp_enhist_config(unsigned long flags, u32 base,
+static void pp_enhist_config(unsigned long flags, char __iomem *base,
 				struct pp_sts_type *pp_sts,
 				struct mdp_hist_lut_data *enhist_cfg)
 {
@@ -421,6 +422,7 @@
 {
 	u32 opmode = 0, base = 0;
 	unsigned long flags = 0;
+	char __iomem *offset;
 
 	pr_debug("pnum=%x\n", pipe->num);
 
@@ -467,6 +469,26 @@
 			if (pipe->pp_res.pp_sts.pa_sts & PP_STS_ENABLE)
 				opmode |= (1 << 4); /* PA_EN */
 		}
+
+		if (pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_HIST_LUT_CFG) {
+			pp_enhist_config(PP_FLAGS_DIRTY_ENHIST,
+				pipe->base + MDSS_MDP_REG_VIG_HIST_LUT_BASE,
+				&pipe->pp_res.pp_sts,
+				&pipe->pp_cfg.hist_lut_cfg);
+		}
+	}
+
+	if (pipe->pp_res.pp_sts.enhist_sts & PP_STS_ENABLE) {
+		/* Enable HistLUT and PA */
+		opmode |= BIT(10) | BIT(4);
+		if (!(pipe->pp_res.pp_sts.pa_sts & PP_STS_ENABLE)) {
+			/* Program default value */
+			offset = pipe->base + MDSS_MDP_REG_VIG_PA_BASE;
+			writel_relaxed(0, offset);
+			writel_relaxed(0, offset + 4);
+			writel_relaxed(0, offset + 8);
+			writel_relaxed(0, offset + 12);
+		}
 	}
 
 	*op = opmode;
@@ -918,7 +940,7 @@
 	pp_igc_config(flags, MDSS_MDP_REG_IGC_DSPP_BASE, pp_sts,
 				&mdss_pp_res->igc_disp_cfg[disp_num], dspp_num);
 
-	pp_enhist_config(flags, base + MDSS_MDP_REG_DSPP_HIST_LUT_BASE,
+	pp_enhist_config(flags, basel + MDSS_MDP_REG_DSPP_HIST_LUT_BASE,
 			pp_sts, &mdss_pp_res->enhist_disp_cfg[disp_num]);
 
 	if (pp_sts->pa_sts & PP_STS_ENABLE)
@@ -1617,13 +1639,17 @@
 }
 
 /* Note: Assumes that its inputs have been checked by calling function */
-static void pp_update_hist_lut(u32 offset, struct mdp_hist_lut_data *cfg)
+static void pp_update_hist_lut(char __iomem *offset,
+				struct mdp_hist_lut_data *cfg)
 {
 	int i;
 	for (i = 0; i < ENHIST_LUT_ENTRIES; i++)
-		MDSS_MDP_REG_WRITE(offset, cfg->data[i]);
+		writel_relaxed(cfg->data[i], offset);
 	/* swap */
-	MDSS_MDP_REG_WRITE(offset + 4, 1);
+	if (PP_LOCAT(cfg->block) == MDSS_PP_DSPP_CFG)
+		writel_relaxed(1, offset + 4);
+	else
+		writel_relaxed(1, offset + 16);
 }
 
 int mdss_mdp_argc_config(struct mdss_mdp_ctl *ctl,
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index c686f82..b9d4a6f 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -332,6 +332,7 @@
 #define MDP_OVERLAY_PP_IGC_CFG         0x8
 #define MDP_OVERLAY_PP_SHARP_CFG       0x10
 #define MDP_OVERLAY_PP_HIST_CFG        0x20
+#define MDP_OVERLAY_PP_HIST_LUT_CFG    0x40
 
 #define MDP_CSC_FLAG_ENABLE	0x1
 #define MDP_CSC_FLAG_YUV_IN	0x2
@@ -375,6 +376,13 @@
 	uint16_t num_bins;
 };
 
+struct mdp_hist_lut_data {
+	uint32_t block;
+	uint32_t ops;
+	uint32_t len;
+	uint32_t *data;
+};
+
 struct mdp_overlay_pp_params {
 	uint32_t config_ops;
 	struct mdp_csc_cfg csc_cfg;
@@ -383,6 +391,7 @@
 	struct mdp_igc_lut_data igc_cfg;
 	struct mdp_sharp_cfg sharp_cfg;
 	struct mdp_histogram_cfg hist_cfg;
+	struct mdp_hist_lut_data hist_lut_cfg;
 };
 
 struct mdp_overlay {
@@ -517,13 +526,6 @@
 };
 
 
-struct mdp_hist_lut_data {
-	uint32_t block;
-	uint32_t ops;
-	uint32_t len;
-	uint32_t *data;
-};
-
 struct mdp_lut_cfg_data {
 	uint32_t lut_type;
 	union {