video: msm: Adding CSC support for other MDP blocks

Adding support for VG1, VG2, DMA_S and Overlay Mixer 1.

Change-Id: I95a5832a70fd893970e82dadcec1e11ed608d79c
Signed-off-by: Carl Vanderlip <carlv@codeaurora.org>
diff --git a/drivers/video/msm/mdp.h b/drivers/video/msm/mdp.h
index 7b67905..35a1453 100644
--- a/drivers/video/msm/mdp.h
+++ b/drivers/video/msm/mdp.h
@@ -42,6 +42,7 @@
 extern ulong mdp4_display_intf;
 extern spinlock_t mdp_spin_lock;
 extern int mdp_rev;
+extern struct mdp_csc_cfg mdp_csc_convert[4];
 
 #define MDP4_REVISION_V1		0
 #define MDP4_REVISION_V2		1
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index 7b5f464..eed9549 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -698,6 +698,8 @@
 void mdp4_hsic_set(struct mdp4_overlay_pipe *pipe, struct dpp_ctrl *ctrl);
 void mdp4_hsic_update(struct mdp4_overlay_pipe *pipe);
 int mdp4_csc_config(struct mdp_csc_cfg_data *config);
+void mdp4_csc_write(struct mdp_csc_cfg *data, uint32_t base);
+int mdp4_csc_enable(struct mdp_csc_cfg_data *config);
 
 u32  mdp4_allocate_writeback_buf(struct msm_fb_data_type *mfd, u32 mix_num);
 void mdp4_init_writeback_buf(struct msm_fb_data_type *mfd, u32 mix_num);
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index 1fd0766..1d1d5f1 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -546,7 +546,7 @@
 	char *vg_base;
 	uint32 frame_size, src_size, src_xy, dst_size, dst_xy;
 	uint32 format, pattern, luma_offset, chroma_offset;
-	uint32 mask;
+	uint32 mask, curr;
 	int pnum, ptype;
 
 	pnum = pipe->pipe_num - OVERLAY_PIPE_VG1; /* start from 0 */
@@ -564,8 +564,9 @@
 	pattern = mdp4_overlay_unpack_pattern(pipe);
 
 	/* not RGB use VG pipe, pure VG pipe */
+	pipe->op_mode |= MDP4_OP_CSC_EN;
 	if (ptype != OVERLAY_TYPE_RGB)
-		pipe->op_mode |= (MDP4_OP_CSC_EN | MDP4_OP_SRC_DATA_YCBCR);
+		pipe->op_mode |= MDP4_OP_SRC_DATA_YCBCR;
 
 #ifdef MDP4_IGC_LUT_ENABLE
 	pipe->op_mode |= MDP4_OP_IGC_LUT_EN;
@@ -609,6 +610,17 @@
 			&chroma_offset);
 	}
 
+	/* Ensure proper covert matrix loaded when color space swaps */
+	curr = inpdw(vg_base + 0x0058);
+	mask = 0x600;
+	if ((curr & mask) != (pipe->op_mode & mask)) {
+		curr = ((uint32_t)vg_base) + 0x4000;
+		if (ptype != OVERLAY_TYPE_RGB)
+			mdp4_csc_write(&(mdp_csc_convert[1]), curr);
+		else
+			mdp4_csc_write(&(mdp_csc_convert[0]), curr);
+	}
+
 	/* luma component plane */
 	outpdw(vg_base + 0x0010, pipe->srcp0_addr + luma_offset);
 
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index ba6c746..40056f0 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -1232,15 +1232,60 @@
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 }
 
+struct mdp_csc_cfg mdp_csc_convert[4] = {
+	{ /*RGB2RGB*/
+		0,
+		{
+			0x0200, 0x0000, 0x0000,
+			0x0000, 0x0200, 0x0000,
+			0x0000, 0x0000, 0x0200,
+		},
+		{ 0x0, 0x0, 0x0, },
+		{ 0x0, 0x0, 0x0, },
+		{ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, },
+		{ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, },
+	},
+	{ /*YUV2RGB*/
+		0,
+		{
+			0x0254, 0x0000, 0x0331,
+			0x0254, 0xff37, 0xfe60,
+			0x0254, 0x0409, 0x0000,
+		},
+		{ 0xfff0, 0xff80, 0xff80, },
+		{ 0x0, 0x0, 0x0, },
+		{ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, },
+		{ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, },
+	},
+	{ /*RGB2YUV*/
+		0,
+		{
+			0x0083, 0x0102, 0x0032,
+			0x1fb5, 0x1f6c, 0x00e1,
+			0x00e1, 0x1f45, 0x1fdc
+		},
+		{ 0x0, 0x0, 0x0, },
+		{ 0x0010, 0x0080, 0x0080, },
+		{ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, },
+		{ 0x0010, 0x00eb, 0x0010, 0x00f0, 0x0010, 0x00f0, },
+	},
+	{ /*YUV2YUV ???*/
+		0,
+		{
+			0x0200, 0x0000, 0x0000,
+			0x0000, 0x0200, 0x0000,
+			0x0000, 0x0000, 0x0200,
+		},
+		{ 0x0, 0x0, 0x0, },
+		{ 0x0, 0x0, 0x0, },
+		{ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, },
+		{ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, },
+	},
+};
 
-struct mdp4_csc_matrix {
-uint32 csc_mv[9];
-uint32 csc_pre_bv[3];
-uint32 csc_post_bv[3];
-uint32 csc_pre_lv[6];
-uint32 csc_post_lv[6];
-} csc_matrix[3] = {
+struct mdp_csc_cfg csc_matrix[3] = {
 	{
+		(MDP_CSC_FLAG_YUV_OUT),
 		{
 			0x0254, 0x0000, 0x0331,
 			0x0254, 0xff37, 0xfe60,
@@ -1260,6 +1305,7 @@
 		},
 	},
 	{
+		(MDP_CSC_FLAG_YUV_OUT),
 		{
 			0x0254, 0x0000, 0x0331,
 			0x0254, 0xff37, 0xfe60,
@@ -1279,6 +1325,7 @@
 		},
 	},
 	{
+		(0),
 		{
 			0x0200, 0x0000, 0x0000,
 			0x0000, 0x0200, 0x0000,
@@ -1392,6 +1439,25 @@
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 }
 
+void mdp4_vg_csc_convert_setup(int vp_num)
+{
+	struct mdp_csc_cfg_data cfg;
+
+	switch (vp_num) {
+	case 0:
+		cfg.block = MDP_BLOCK_VG_1;
+		break;
+	case 1:
+		cfg.block = MDP_BLOCK_VG_2;
+		break;
+	default:
+		pr_err("%s - invalid vp_num = %d", __func__, vp_num);
+		return;
+	}
+	cfg.csc_data = csc_matrix[vp_num];
+	mdp4_csc_enable(&cfg);
+}
+
 void mdp4_vg_csc_setup(int vp_num)
 {
 		/* yuv2rgb */
@@ -1400,6 +1466,7 @@
 		mdp4_vg_csc_post_bv_setup(vp_num);
 		mdp4_vg_csc_pre_lv_setup(vp_num);
 		mdp4_vg_csc_post_lv_setup(vp_num);
+		mdp4_vg_csc_convert_setup(vp_num);
 }
 void mdp4_vg_csc_update(struct mdp_csc *p)
 {
@@ -2347,13 +2414,15 @@
 	case MDP_BLOCK_DMA_P:
 		base = 0x93000;
 		break;
+	case MDP_BLOCK_DMA_S:
+		base = (mdp_rev >= MDP_REV_42) ? 0xA3000 : 0x0;
 	default:
 		break;
 	}
 	return base;
 }
 
-static int mdp4_csc_enable(struct mdp_csc_cfg_data *config)
+int mdp4_csc_enable(struct mdp_csc_cfg_data *config)
 {
 	uint32_t output, base, temp, mask;
 
@@ -2365,9 +2434,32 @@
 		output |= temp;
 		mask = 0x08 | 0x1800;
 		break;
+	case MDP_BLOCK_DMA_S:
+		base = 0xA0028;
+		output = (config->csc_data.flags << 3) & (0x08);
+		temp = (config->csc_data.flags << 10) & (0x1800);
+		output |= temp;
+		mask = 0x08 | 0x1800;
+		break;
 	case MDP_BLOCK_VG_1:
+		base = 0x20058;
+		output = (config->csc_data.flags << 11) & (0x800);
+		temp = (config->csc_data.flags << 8) & (0x600);
+		output |= temp;
+		mask = 0x800 | 0x600;
+		break;
 	case MDP_BLOCK_VG_2:
+		base = 0x30058;
+		output = (config->csc_data.flags << 11) & (0x800);
+		temp = (config->csc_data.flags << 8) & (0x600);
+		output |= temp;
+		mask = 0x800 | 0x600;
+		break;
 	case MDP_BLOCK_OVERLAY_1:
+		base = 0x18200;
+		output = config->csc_data.flags;
+		mask = 0x07;
+		break;
 	default:
 		pr_err("%s - CSC block does not exist on MDP_BLOCK = %d\n",
 						__func__, config->block);
@@ -2387,46 +2479,49 @@
 #define CSC_LV_OFF	0x600
 #define CSC_POST_OFF	0x80
 
-int mdp4_csc_config(struct mdp_csc_cfg_data *config)
+void mdp4_csc_write(struct mdp_csc_cfg *data, uint32_t base)
 {
-	int ret = 0;
 	int i;
-	uint32_t base, *off;
-
-	base = mdp4_csc_block2base(config->block);
-	if (!base)
-		return -EINVAL;
-
-	/* TODO: implement other CSC block support */
-	if (config->block != MDP_BLOCK_DMA_P) {
-		pr_warn("%s: Only DMA_P currently supported by CSC.\n",
-		__func__);
-		return -EINVAL;
-	}
+	uint32_t *off;
 
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	off = (uint32_t *) (MDP_BASE + base + CSC_MV_OFF);
+	off = (uint32_t *) ((uint32_t) base + CSC_MV_OFF);
 	for (i = 0; i < 9; i++) {
-		outpdw(off, config->csc_data.csc_mv[i]);
+		outpdw(off, data->csc_mv[i]);
 		off++;
 	}
 
-	off = (uint32_t *) (MDP_BASE + base + CSC_BV_OFF);
+	off = (uint32_t *) ((uint32_t) base + CSC_BV_OFF);
 	for (i = 0; i < 3; i++) {
-		outpdw(off, config->csc_data.csc_pre_bv[i]);
+		outpdw(off, data->csc_pre_bv[i]);
 		outpdw((uint32_t *)((uint32_t)off + CSC_POST_OFF),
-					config->csc_data.csc_post_bv[i]);
+					data->csc_post_bv[i]);
 		off++;
 	}
 
-	off = (uint32_t *) (MDP_BASE + base + CSC_LV_OFF);
+	off = (uint32_t *) ((uint32_t) base + CSC_LV_OFF);
 	for (i = 0; i < 6; i++) {
-		outpdw(off, config->csc_data.csc_pre_lv[i]);
+		outpdw(off, data->csc_pre_lv[i]);
 		outpdw((uint32_t *)((uint32_t)off + CSC_POST_OFF),
-					config->csc_data.csc_post_lv[i]);
+					data->csc_post_lv[i]);
 		off++;
 	}
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+}
+
+int mdp4_csc_config(struct mdp_csc_cfg_data *config)
+{
+	int ret = 0;
+	uint32_t base;
+
+	base = mdp4_csc_block2base(config->block);
+	if (!base) {
+		pr_warn("%s: Block type %d isn't supported by CSC.\n",
+				__func__, config->block);
+		return -EINVAL;
+	}
+
+	mdp4_csc_write(&config->csc_data, (uint32_t) (MDP_BASE + base));
 
 	ret = mdp4_csc_enable(config);
 
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index cac7758..427465d 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -335,6 +335,10 @@
 	struct mdp_pcc_coeff r, g, b;
 };
 
+#define MDP_CSC_FLAG_ENABLE	0x1
+#define MDP_CSC_FLAG_YUV_IN	0x2
+#define MDP_CSC_FLAG_YUV_OUT	0x4
+
 struct mdp_csc_cfg {
 	/* flags for enable CSC, toggling RGB,YUV input/output */
 	uint32_t flags;