[PATCH 13/133] [Jaunty SRU] ARM.imx51 Freescale:ENGR00108339 Add TV Encoder V2 support for MX51 TO2

Brad Figg brad.figg at canonical.com
Thu Jul 9 16:48:03 UTC 2009


From: Lily Zhang <r58066 at freescale.com>

1. TVE driver changed to support NTSC/PAL video on TVE v2
2. DI waveform generation was changed for interlaced video,
to support 2 VSYNC pulses per frame, 1 VSYNC for each field.
Old IPU driver generated 1 VSYNC per frame, and VSYNC for the
other field was replicated by the TVE v1 encoder. TVE v2 no
longer supports this format
3. DI clock was re-defined. Two different clocks DI0 and DI1
were defined for maximum flexibility, cause these two clocks
can be set (and will be set when HD will be introduced) to
different frequencies.
4. Add tve cable detect support

Signed-off-by: Gubeskys Arik <RM05686 at freescale.com>
Signed-off-by: Brad Figg <brad.figg at canonical.com>
---
 arch/arm/mach-mx51/clock.c    |   85 ++++++++--
 arch/arm/mach-mx51/crm_regs.h |    8 +-
 arch/arm/mach-mx51/devices.c  |    2 +-
 drivers/mxc/ipu3/ipu_disp.c   |  311 +++++++++++++++++++++++++-------
 drivers/mxc/ipu3/ipu_regs.h   |    8 +-
 drivers/video/mxc/tve.c       |  396 +++++++++++++++++++++++++++++++++--------
 6 files changed, 647 insertions(+), 163 deletions(-)

diff --git a/arch/arm/mach-mx51/clock.c b/arch/arm/mach-mx51/clock.c
index 6940b3d..375224e 100644
--- a/arch/arm/mach-mx51/clock.c
+++ b/arch/arm/mach-mx51/clock.c
@@ -279,6 +279,49 @@ static void _clk_pll_recalc(struct clk *clk)
 	clk->rate = temp;
 }
 
+static int _clk_pll_set_rate(struct clk *clk, unsigned long rate)
+{
+	u32 reg;
+	u32 pllbase;
+
+	long mfi, pdf, mfn, mfd = 999999;
+	s64 temp64;
+	unsigned long quad_parent_rate;
+	unsigned long pll_hfsm, dp_ctl;
+
+	pllbase = _get_pll_base(clk);
+
+	quad_parent_rate = 4*clk->parent->rate;
+	pdf = mfi = -1;
+	while (++pdf < 16 && mfi < 5)
+		mfi = rate * (pdf+1) / quad_parent_rate;
+	if (mfi > 15)
+		return -1;
+	pdf--;
+
+	temp64 = rate*(pdf+1) - quad_parent_rate*mfi;
+	do_div(temp64, quad_parent_rate/1000000);
+	mfn = (long)temp64;
+
+	dp_ctl = __raw_readl(pllbase + MXC_PLL_DP_CTL);
+	/* use dpdck0_2 */
+	__raw_writel(dp_ctl | 0x1000L, pllbase + MXC_PLL_DP_CTL);
+	pll_hfsm = dp_ctl & MXC_PLL_DP_CTL_HFSM;
+	if (pll_hfsm == 0) {
+		reg = mfi<<4 | pdf;
+		__raw_writel(reg, pllbase + MXC_PLL_DP_OP);
+		__raw_writel(mfd, pllbase + MXC_PLL_DP_MFD);
+		__raw_writel(mfn, pllbase + MXC_PLL_DP_MFN);
+	} else {
+		reg = mfi<<4 | pdf;
+		__raw_writel(reg, pllbase + MXC_PLL_DP_HFS_OP);
+		__raw_writel(mfd, pllbase + MXC_PLL_DP_HFS_MFD);
+		__raw_writel(mfn, pllbase + MXC_PLL_DP_HFS_MFN);
+	}
+
+	return 0;
+}
+
 static int _clk_pll_enable(struct clk *clk)
 {
 	u32 reg;
@@ -383,6 +426,7 @@ static struct clk pll2_sw_clk = {
 static struct clk pll3_sw_clk = {
 	.name = "pll3",
 	.parent = &osc_clk,
+	.set_rate = _clk_pll_set_rate,
 	.recalc = _clk_pll_recalc,
 	.enable = _clk_pll_enable,
 	.disable = _clk_pll_disable,
@@ -960,17 +1004,17 @@ static int _clk_ipu_di_set_parent(struct clk *clk, struct clk *parent)
 	u32 reg;
 
 	reg = __raw_readl(MXC_CCM_CSCMR2);
-	reg &= ~MXC_CCM_CSCMR2_DI_CLK_SEL_MASK;
+	reg &= ~MXC_CCM_CSCMR2_DI_CLK_SEL_MASK(clk->id);
 	if (parent == &pll3_sw_clk)
 		;
 	else if (parent == &osc_clk)
-		reg |= 1 << MXC_CCM_CSCMR2_DI_CLK_SEL_OFFSET;
+		reg |= 1 << MXC_CCM_CSCMR2_DI_CLK_SEL_OFFSET(clk->id);
 	else if (parent == &ckih_clk)
-		reg |= 2 << MXC_CCM_CSCMR2_DI_CLK_SEL_OFFSET;
+		reg |= 2 << MXC_CCM_CSCMR2_DI_CLK_SEL_OFFSET(clk->id);
 	else if (parent == &tve_clk)
-		reg |= 3 << MXC_CCM_CSCMR2_DI_CLK_SEL_OFFSET;
-	else	/* Assume any other clock is external clock pin */
-		reg |= 4 << MXC_CCM_CSCMR2_DI_CLK_SEL_OFFSET;
+		reg |= 3 << MXC_CCM_CSCMR2_DI_CLK_SEL_OFFSET(clk->id);
+	else		/* Assume any other clock is external clock pin */
+		reg |= 4 << MXC_CCM_CSCMR2_DI_CLK_SEL_OFFSET(clk->id);
 	__raw_writel(reg, MXC_CCM_CSCMR2);
 
 	return 0;
@@ -981,8 +1025,8 @@ static void _clk_ipu_di_recalc(struct clk *clk)
 	u32 reg, div, mux;
 
 	reg = __raw_readl(MXC_CCM_CSCMR2);
-	mux = (reg & MXC_CCM_CSCMR2_DI_CLK_SEL_MASK) >>
-		MXC_CCM_CSCMR2_DI_CLK_SEL_OFFSET;
+	mux = (reg & MXC_CCM_CSCMR2_DI_CLK_SEL_MASK(clk->id)) >>
+		MXC_CCM_CSCMR2_DI_CLK_SEL_OFFSET(clk->id);
 	if (mux == 0) {
 		reg = __raw_readl(MXC_CCM_CDCDR) &
 		    MXC_CCM_CDCDR_DI_CLK_PRED_MASK;
@@ -995,15 +1039,29 @@ static void _clk_ipu_di_recalc(struct clk *clk)
 	}
 }
 
-static struct clk ipu_di_clk = {
-	.name = "ipu_di_clk",
+static struct clk ipu_di_clk[] = {
+	{
+	.name = "ipu_di0_clk",
+	.id = 0,
 	.parent = &pll3_sw_clk,
-	.enable_reg = MXC_CCM_CCGR5,
-	.enable_shift = MXC_CCM_CCGR5_CG6_OFFSET,
+	.enable_reg = MXC_CCM_CCGR6,
+	.enable_shift = MXC_CCM_CCGR6_CG5_OFFSET,
+	.recalc = _clk_ipu_di_recalc,
+	.set_parent = _clk_ipu_di_set_parent,
+	.enable = _clk_enable,
+	.disable = _clk_disable,
+	},
+	{
+	.name = "ipu_di1_clk",
+	.id = 1,
+	.parent = &pll3_sw_clk,
+	.enable_reg = MXC_CCM_CCGR6,
+	.enable_shift = MXC_CCM_CCGR6_CG6_OFFSET,
 	.recalc = _clk_ipu_di_recalc,
 	.set_parent = _clk_ipu_di_set_parent,
 	.enable = _clk_enable,
 	.disable = _clk_disable,
+	},
 };
 
 static int _clk_csi0_set_parent(struct clk *clk, struct clk *parent)
@@ -2701,7 +2759,8 @@ static struct clk *mxc_clks[] = {
 	&sdma_clk[1],
 	&ipu_clk[0],
 	&ipu_clk[1],
-	&ipu_di_clk,
+	&ipu_di_clk[0],
+	&ipu_di_clk[1],
 	&tve_clk,
 	&csi0_clk,
 	&csi1_clk,
diff --git a/arch/arm/mach-mx51/crm_regs.h b/arch/arm/mach-mx51/crm_regs.h
index c570b8a..9bc5122 100644
--- a/arch/arm/mach-mx51/crm_regs.h
+++ b/arch/arm/mach-mx51/crm_regs.h
@@ -224,8 +224,8 @@
 #define MXC_CCM_CSCMR1_SSI_EXT1_COM_CLK_SEL			(0x1)
 
 /* Define the bits in register CSCMR2 */
-#define MXC_CCM_CSCMR2_DI_CLK_SEL_OFFSET		(26)
-#define MXC_CCM_CSCMR2_DI_CLK_SEL_MASK		(0x7 << 26)
+#define MXC_CCM_CSCMR2_DI_CLK_SEL_OFFSET(n)		(26+n*3)
+#define MXC_CCM_CSCMR2_DI_CLK_SEL_MASK(n)		(0x7 << (26+n*3))
 #define MXC_CCM_CSCMR2_CSI_MCLK2_CLK_SEL_OFFSET	(24)
 #define MXC_CCM_CSCMR2_CSI_MCLK2_CLK_SEL_MASK	(0x3 << 24)
 #define MXC_CCM_CSCMR2_CSI_MCLK1_CLK_SEL_OFFSET	(22)
@@ -565,7 +565,11 @@
 #define MXC_CCM_CCGR5_CG2_MASK			(0x3 << 4)
 #define MXC_CCM_CCGR5_CG1_OFFSET			2
 #define MXC_CCM_CCGR5_CG0_OFFSET			0
+#define MXC_CCM_CCGR6_CG6_OFFSET			12
 
+#define MXC_CCM_CCGR6_CG6_MASK			(0x3 << 12)
+#define MXC_CCM_CCGR6_CG5_OFFSET			10
+#define MXC_CCM_CCGR6_CG5_MASK			(0x3 << 10)
 #define MXC_CCM_CCGR6_CG4_OFFSET			8
 #define MXC_CCM_CCGR6_CG4_MASK			(0x3 << 8)
 #define MXC_CCM_CCGR6_CG3_OFFSET			6
diff --git a/arch/arm/mach-mx51/devices.c b/arch/arm/mach-mx51/devices.c
index 04c8753..aeb1ed4 100644
--- a/arch/arm/mach-mx51/devices.c
+++ b/arch/arm/mach-mx51/devices.c
@@ -240,7 +240,7 @@ static void mxc_init_ipu(void)
 	if (cpu_is_mx51_rev(CHIP_REV_2_0) > 0)
 		mxc_ipu_data.rev = 2;
 
-	mxc_ipu_data.di_clk[1] = clk_get(NULL, "ipu_di_clk");
+	mxc_ipu_data.di_clk[1] = clk_get(NULL, "ipu_di1_clk");
 	clk = clk_get(NULL, "tve_clk");
 	clk_set_parent(mxc_ipu_data.di_clk[1], clk);
 	clk_put(clk);
diff --git a/drivers/mxc/ipu3/ipu_disp.c b/drivers/mxc/ipu3/ipu_disp.c
index 888c740..f0d1471 100644
--- a/drivers/mxc/ipu3/ipu_disp.c
+++ b/drivers/mxc/ipu3/ipu_disp.c
@@ -737,7 +737,7 @@ int32_t ipu_init_sync_panel(int disp, uint32_t pixel_clk,
 	uint32_t field1_offset;
 	uint32_t reg;
 	uint32_t disp_gen, di_gen, vsync_cnt;
-	uint32_t div;
+	uint32_t div, up;
 	uint32_t h_total, v_total;
 	int map;
 	struct clk *di_clk;
@@ -797,6 +797,7 @@ int32_t ipu_init_sync_panel(int disp, uint32_t pixel_clk,
 
 	map = _ipu_pixfmt_to_map(pixel_fmt);
 	if (map < 0) {
+		dev_dbg(g_ipu_dev, "IPU_DISP: No MAP\n");
 		spin_unlock_irqrestore(&ipu_lock, lock_flags);
 		return -EINVAL;
 	}
@@ -805,83 +806,259 @@ int32_t ipu_init_sync_panel(int disp, uint32_t pixel_clk,
 	if (sig.ext_clk)
 		di_gen |= DI_GEN_DI_CLK_EXT;
 
-	/* Setup internal HSYNC waveform */
-	_ipu_di_sync_config(disp, 1, h_total - 1, DI_SYNC_CLK,
-			    0, DI_SYNC_NONE, 0, DI_SYNC_NONE, 0, DI_SYNC_NONE,
-			    DI_SYNC_NONE, 0, 0);
 	if (sig.interlaced) {
-		field1_offset = v_sync_width + v_start_width + height / 2 +
-		    v_end_width;
-		if (sig.odd_field_first) {
-			field0_offset = field1_offset - 1;
-			field1_offset = 0;
+		if (cpu_is_mx51_rev(CHIP_REV_2_0)) {
+			/* Setup internal HSYNC waveform */
+			_ipu_di_sync_config(
+					disp, 			/* display */
+					1, 				/* counter */
+					h_total/2 - 1, 	/* run count */
+					DI_SYNC_CLK,		 /* run_resolution */
+					0, 				/* offset */
+					DI_SYNC_NONE, 	/* offset resolution */
+					0, 				/* repeat count */
+					DI_SYNC_NONE, 	/* CNT_CLR_SEL */
+					0, 				/* CNT_POLARITY_GEN_EN */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_CLR_SEL */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_TRIGGER_SEL */
+					0, 				/* COUNT UP */
+					0				/* COUNT DOWN */
+					);
+
+			/* Field 1 VSYNC waveform */
+			_ipu_di_sync_config(
+					disp, 			/* display */
+					2, 				/* counter */
+					h_total - 1, 		/* run count */
+					DI_SYNC_CLK,		/* run_resolution */
+					0, 				/* offset */
+					DI_SYNC_NONE, 	/* offset resolution */
+					0, 				/* repeat count */
+					DI_SYNC_NONE, 	/* CNT_CLR_SEL */
+					0, 				/* CNT_POLARITY_GEN_EN */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_CLR_SEL */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_TRIGGER_SEL */
+					0, 				/* COUNT UP */
+					4				/* COUNT DOWN */
+					);
+
+			/* Setup internal HSYNC waveform */
+			_ipu_di_sync_config(
+					disp, 			/* display */
+					3, 				/* counter */
+					v_total*2 - 1, 	/* run count */
+					DI_SYNC_INT_HSYNC,	/* run_resolution */
+					1, 				/* offset */
+					DI_SYNC_INT_HSYNC, 	/* offset resolution */
+					0, 				/* repeat count */
+					DI_SYNC_NONE, 	/* CNT_CLR_SEL */
+					0, 				/* CNT_POLARITY_GEN_EN */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_CLR_SEL */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_TRIGGER_SEL */
+					0, 				/* COUNT UP */
+					4				/* COUNT DOWN */
+					);
+
+			/* Active Field ? */
+			_ipu_di_sync_config(
+					disp, 			/* display */
+					4, 				/* counter */
+					v_total/2 - 1, 	/* run count */
+					DI_SYNC_HSYNC,	/* run_resolution */
+					v_start_width, 	/*  offset */
+					DI_SYNC_HSYNC, 	/* offset resolution */
+					2, 				/* repeat count */
+					DI_SYNC_VSYNC, 	/* CNT_CLR_SEL */
+					0, 				/* CNT_POLARITY_GEN_EN */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_CLR_SEL */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_TRIGGER_SEL */
+					0, 				/* COUNT UP */
+					0				/* COUNT DOWN */
+					);
+
+			/* Active Line */
+			_ipu_di_sync_config(
+					disp, 			/* display */
+					5, 				/* counter */
+					0, 				/* run count */
+					DI_SYNC_HSYNC,	/* run_resolution */
+					0, 				/*  offset */
+					DI_SYNC_NONE, 	/* offset resolution */
+					height/2, 		/* repeat count */
+					4, 				/* CNT_CLR_SEL */
+					0, 				/* CNT_POLARITY_GEN_EN */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_CLR_SEL */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_TRIGGER_SEL */
+					0, 				/* COUNT UP */
+					0				/* COUNT DOWN */
+					);
+
+			/* Field 0 VSYNC waveform */
+			_ipu_di_sync_config(
+					disp, 			/* display */
+					6, 				/* counter */
+					v_total - 1, 	/* run count */
+					DI_SYNC_HSYNC,	/* run_resolution */
+					0, 				/* offset */
+					DI_SYNC_NONE, 	/* offset resolution */
+					0, 				/* repeat count */
+					DI_SYNC_NONE, 	/* CNT_CLR_SEL  */
+					0, 				/* CNT_POLARITY_GEN_EN */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_CLR_SEL */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_TRIGGER_SEL */
+					0, 				/* COUNT UP */
+					0				/* COUNT DOWN */
+					);
+
+			/* DC VSYNC waveform */
+			vsync_cnt = 7;
+			_ipu_di_sync_config(
+					disp, 			/* display */
+					7, 				/* counter */
+					v_total/2 - 1, 	/* run count */
+					DI_SYNC_HSYNC,	/* run_resolution  */
+					9, 				/* offset  */
+					DI_SYNC_HSYNC, 	/* offset resolution */
+					2, 				/* repeat count */
+					DI_SYNC_VSYNC, 	/* CNT_CLR_SEL */
+					0, 				/* CNT_POLARITY_GEN_EN */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_CLR_SEL */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_TRIGGER_SEL */
+					0, 				/* COUNT UP */
+					0				/* COUNT DOWN */
+					);
+
+			/* active pixel waveform */
+			_ipu_di_sync_config(
+					disp, 			/* display */
+					8, 				/* counter */
+					0, 	/* run count  */
+					DI_SYNC_CLK,	/* run_resolution */
+					h_start_width, 				/* offset  */
+					DI_SYNC_CLK, 	/* offset resolution */
+					width, 				/* repeat count  */
+					5, 	/* CNT_CLR_SEL  */
+					0, 				/* CNT_POLARITY_GEN_EN  */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_CLR_SEL */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_TRIGGER_SEL  */
+					0, 				/* COUNT UP  */
+					0				/* COUNT DOWN */
+					);
+
+			/* ??? */
+			_ipu_di_sync_config(
+					disp, 			/* display */
+					9, 				/* counter */
+					v_total - 1, 	/* run count */
+					DI_SYNC_INT_HSYNC,	/* run_resolution */
+					v_total/2, 			/* offset  */
+					DI_SYNC_INT_HSYNC, 	/* offset resolution  */
+					0, 				/* repeat count */
+					DI_SYNC_HSYNC, 	/* CNT_CLR_SEL */
+					0, 				/* CNT_POLARITY_GEN_EN  */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_CLR_SEL  */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_TRIGGER_SEL */
+					0, 				/* COUNT UP */
+					4				/* COUNT DOWN */
+					);
+
+			/* set gentime select and tag sel */
+			reg = __raw_readl(DI_SW_GEN1(disp, 9));
+			reg &= 0x1FFFFFFF;
+			reg |= (3-1)<<29 | 0x00008000;
+			__raw_writel(reg, DI_SW_GEN1(disp, 9));
+
+			__raw_writel(v_total / 2 - 1, DI_SCR_CONF(disp));
+
+			/* set y_sel = 1 */
+			di_gen |= 0x10000000;
+			di_gen |= DI_GEN_POLARITY_5;
+			di_gen |= DI_GEN_POLARITY_8;
+		} else {
+			/* Setup internal HSYNC waveform */
+			_ipu_di_sync_config(disp, 1, h_total - 1, DI_SYNC_CLK,
+					0, DI_SYNC_NONE, 0, DI_SYNC_NONE, 0, DI_SYNC_NONE,
+					DI_SYNC_NONE, 0, 0);
+
+			field1_offset = v_sync_width + v_start_width + height / 2 +
+				v_end_width;
+			if (sig.odd_field_first) {
+				field0_offset = field1_offset - 1;
+				field1_offset = 0;
+			}
+			v_total += v_start_width + v_end_width;
+
+			/* Field 1 VSYNC waveform */
+			_ipu_di_sync_config(disp, 2, v_total - 1, 1,
+					field0_offset,
+					field0_offset ? 1 : DI_SYNC_NONE,
+					0, DI_SYNC_NONE, 0,
+					DI_SYNC_NONE, DI_SYNC_NONE, 0, 4);
+
+			/* Setup internal HSYNC waveform */
+			_ipu_di_sync_config(disp, 3, h_total - 1, DI_SYNC_CLK,
+					0, DI_SYNC_NONE, 0, DI_SYNC_NONE, 0,
+					DI_SYNC_NONE, DI_SYNC_NONE, 0, 4);
+
+			/* Active Field ? */
+			_ipu_di_sync_config(disp, 4,
+					field0_offset ?
+					field0_offset : field1_offset - 2,
+					1, v_start_width + v_sync_width, 1, 2, 2,
+					0, DI_SYNC_NONE, DI_SYNC_NONE, 0, 0);
+
+			/* Active Line */
+			_ipu_di_sync_config(disp, 5, 0, 1,
+					0, DI_SYNC_NONE,
+					height / 2, 4, 0, DI_SYNC_NONE,
+					DI_SYNC_NONE, 0, 0);
+
+			/* Field 0 VSYNC waveform */
+			_ipu_di_sync_config(disp, 6, v_total - 1, 1,
+					0, DI_SYNC_NONE,
+					0, DI_SYNC_NONE, 0, DI_SYNC_NONE,
+					DI_SYNC_NONE, 0, 0);
+
+			/* DC VSYNC waveform */
+			vsync_cnt = 7;
+			_ipu_di_sync_config(disp, 7, 0, 1,
+					field1_offset,
+					field1_offset ? 1 : DI_SYNC_NONE,
+					1, 2, 0, DI_SYNC_NONE, DI_SYNC_NONE, 0, 0);
+
+			/* active pixel waveform */
+			_ipu_di_sync_config(disp, 8, 0, DI_SYNC_CLK,
+					h_sync_width + h_start_width, DI_SYNC_CLK,
+					width, 5, 0, DI_SYNC_NONE, DI_SYNC_NONE,
+					0, 0);
+
+			/* ??? */
+			_ipu_di_sync_config(disp, 9, v_total - 1, 2,
+					0, DI_SYNC_NONE,
+					0, DI_SYNC_NONE, 6, DI_SYNC_NONE,
+					DI_SYNC_NONE, 0, 0);
+
+			reg = __raw_readl(DI_SW_GEN1(disp, 9));
+			reg |= 0x8000;
+			__raw_writel(reg, DI_SW_GEN1(disp, 9));
+
+			__raw_writel(v_sync_width + v_start_width +
+					v_end_width + height / 2 - 1, DI_SCR_CONF(disp));
 		}
-		v_total += v_start_width + v_end_width;
-
-		/* Field 1 VSYNC waveform */
-		_ipu_di_sync_config(disp, 2, v_total - 1, 1,
-				    field0_offset,
-				    field0_offset ? 1 : DI_SYNC_NONE,
-				    0, DI_SYNC_NONE, 0,
-				    DI_SYNC_NONE, DI_SYNC_NONE, 0, 4);
-
-		/* Setup internal HSYNC waveform */
-		_ipu_di_sync_config(disp, 3, h_total - 1, DI_SYNC_CLK,
-				    0, DI_SYNC_NONE, 0, DI_SYNC_NONE, 0,
-				    DI_SYNC_NONE, DI_SYNC_NONE, 0, 4);
-
-		/* Active Field ? */
-		_ipu_di_sync_config(disp, 4,
-				    field0_offset ?
-				    field0_offset : field1_offset - 2,
-				    1, v_start_width + v_sync_width, 1, 2, 2,
-				    0, DI_SYNC_NONE, DI_SYNC_NONE, 0, 0);
-
-		/* Active Line */
-		_ipu_di_sync_config(disp, 5, 0, 1,
-				    0, DI_SYNC_NONE,
-				    height / 2, 4, 0, DI_SYNC_NONE,
-				    DI_SYNC_NONE, 0, 0);
-
-		/* Field 0 VSYNC waveform */
-		_ipu_di_sync_config(disp, 6, v_total - 1, 1,
-				    0, DI_SYNC_NONE,
-				    0, DI_SYNC_NONE, 0, DI_SYNC_NONE,
-				    DI_SYNC_NONE, 0, 0);
-
-		/* DC VSYNC waveform */
-		vsync_cnt = 7;
-		_ipu_di_sync_config(disp, 7, 0, 1,
-				    field1_offset,
-				    field1_offset ? 1 : DI_SYNC_NONE,
-				    1, 2, 0, DI_SYNC_NONE, DI_SYNC_NONE, 0, 0);
-
-		/* active pixel waveform */
-		_ipu_di_sync_config(disp, 8, 0, DI_SYNC_CLK,
-				    h_sync_width + h_start_width, DI_SYNC_CLK,
-				    width, 5, 0, DI_SYNC_NONE, DI_SYNC_NONE,
-				    0, 0);
-
-		/* ??? */
-		_ipu_di_sync_config(disp, 9, v_total - 1, 2,
-				    0, DI_SYNC_NONE,
-				    0, DI_SYNC_NONE, 6, DI_SYNC_NONE,
-				    DI_SYNC_NONE, 0, 0);
-		reg = __raw_readl(DI_SW_GEN1(disp, 9));
-		reg |= 0x8000;
-		__raw_writel(reg, DI_SW_GEN1(disp, 9));
 
 		/* Init template microcode */
 		_ipu_dc_write_tmpl(0, WROD(0), 0, map, SYNC_WAVE, 0, 8);
 
-		__raw_writel(v_sync_width + v_start_width +
-			     v_end_width + height / 2 - 1, DI_SCR_CONF(disp));
-
 		if (sig.Hsync_pol)
 			di_gen |= DI_GEN_POLARITY_3;
 		if (sig.Vsync_pol)
 			di_gen |= DI_GEN_POLARITY_2;
 	} else {
+		/* Setup internal HSYNC waveform */
+		_ipu_di_sync_config(disp, 1, h_total - 1, DI_SYNC_CLK,
+					0, DI_SYNC_NONE, 0, DI_SYNC_NONE, 0, DI_SYNC_NONE,
+					DI_SYNC_NONE, 0, 0);
+
 		/* Setup external (delayed) HSYNC waveform */
 		_ipu_di_sync_config(disp, DI_SYNC_HSYNC, h_total - 1,
 				    DI_SYNC_CLK, div * v_to_h_sync, DI_SYNC_CLK,
diff --git a/drivers/mxc/ipu3/ipu_regs.h b/drivers/mxc/ipu3/ipu_regs.h
index 746b4c8..4723c22 100644
--- a/drivers/mxc/ipu3/ipu_regs.h
+++ b/drivers/mxc/ipu3/ipu_regs.h
@@ -555,10 +555,10 @@ enum {
 	DI_GEN_POLARITY_2 = 0x00000002,
 	DI_GEN_POLARITY_3 = 0x00000004,
 	DI_GEN_POLARITY_4 = 0x00000008,
-	DI_GEN_POLARITY_5 = 0x00000008,
-	DI_GEN_POLARITY_6 = 0x00000008,
-	DI_GEN_POLARITY_7 = 0x00000008,
-	DI_GEN_POLARITY_8 = 0x00000008,
+	DI_GEN_POLARITY_5 = 0x00000010,
+	DI_GEN_POLARITY_6 = 0x00000020,
+	DI_GEN_POLARITY_7 = 0x00000040,
+	DI_GEN_POLARITY_8 = 0x00000080,
 
 	DI_POL_DRDY_DATA_POLARITY = 0x00000080,
 	DI_POL_DRDY_POLARITY_15 = 0x00000010,
diff --git a/drivers/video/mxc/tve.c b/drivers/video/mxc/tve.c
index 9058801..10436d4 100644
--- a/drivers/video/mxc/tve.c
+++ b/drivers/video/mxc/tve.c
@@ -24,8 +24,10 @@
 #include <linux/clk.h>
 #include <linux/ctype.h>
 #include <linux/delay.h>
+#include <linux/device.h>
 #include <linux/spinlock.h>
 #include <linux/interrupt.h>
+#include <linux/sysfs.h>
 #include <linux/irq.h>
 #include <linux/sysfs.h>
 #include <linux/platform_device.h>
@@ -33,25 +35,31 @@
 #include <linux/regulator/consumer.h>
 #include <asm/uaccess.h>
 #include <asm/atomic.h>
-#include <mach/gpio.h>
-
-#define TVE_COM_CONF_REG	0
-#define TVE_CD_CONT_REG		0x14
-#define TVE_INT_CONT_REG	0x28
-#define TVE_STAT_REG		0x2C
-#define TVE_MV_CONT_REG		0x48
 
-#define CD_EN			0x00000001
-#define CD_TRIG_MODE		0x00000002
+#define TVE_ENABLE			(1UL)
+#define TVE_DAC_FULL_RATE		(0UL<<1)
+#define TVE_DAC_DIV2_RATE		(1UL<<1)
+#define TVE_DAC_DIV4_RATE		(2UL<<1)
+#define TVE_IPU_CLK_ENABLE		(1UL<<3)
 
 #define CD_LM_INT		0x00000001
 #define CD_SM_INT		0x00000002
 #define CD_MON_END_INT		0x00000004
-#define CD_MAN_TRIG		0x00010000
-
-#define TVOUT_FMT_OFF	0
-#define TVOUT_FMT_NTSC	1
-#define TVOUT_FMT_PAL	2
+#define CD_CH_0_LM_ST		0x00000001
+#define CD_CH_0_SM_ST		0x00000010
+#define CD_CH_1_LM_ST		0x00000002
+#define CD_CH_1_SM_ST		0x00000020
+#define CD_CH_2_LM_ST		0x00000004
+#define CD_CH_2_SM_ST		0x00000040
+#define CD_MAN_TRIG		0x00000100
+
+#define TVE_STAND_MASK			(0x0F<<8)
+#define TVE_NTSC_STAND			(0UL<<8)
+#define TVE_PAL_STAND			(3UL<<8)
+
+#define TVOUT_FMT_OFF			0
+#define TVOUT_FMT_NTSC			1
+#define TVOUT_FMT_PAL			2
 
 static int enabled;		/* enable power on or not */
 
@@ -60,20 +68,65 @@ static struct fb_info *tve_fbi;
 struct tve_data {
 	struct platform_device *pdev;
 	int cur_mode;
+	int output_mode;
 	int detect;
 	void *base;
 	int irq;
 	struct clk *clk;
 	struct regulator *dac_reg;
 	struct regulator *dig_reg;
+	struct delayed_work cd_work;
 } tve;
 
+struct tve_reg_mapping {
+	u32 tve_com_conf_reg;
+	u32 tve_cd_cont_reg;
+	u32 tve_int_cont_reg;
+	u32 tve_stat_reg;
+	u32 tve_mv_cont_reg;
+};
+
+struct tve_reg_fields_mapping {
+	u32 cd_en;
+	u32 cd_trig_mode;
+	u32 cd_lm_int;
+	u32 cd_sm_int;
+	u32 cd_mon_end_int;
+	u32 cd_man_trig;
+	u32 sync_ch_mask;
+	u32 tvout_mode_mask;
+	u32 sync_ch_offset;
+	u32 tvout_mode_offset;
+	u32 cd_ch_stat_offset;
+};
+
+static struct tve_reg_mapping tve_regs_v1 = {
+	0, 0x14, 0x28, 0x2C, 0x48
+};
+
+static struct tve_reg_fields_mapping tve_reg_fields_v1 = {
+	1, 2, 1, 2, 4, 0x00010000, 0x7000, 0x70, 12, 4, 8
+};
+
+static struct tve_reg_mapping tve_regs_v2 = {
+	0, 0x34, 0x64, 0x68, 0xDC
+};
+
+static struct tve_reg_fields_mapping tve_reg_fields_v2 = {
+	1, 2, 1, 2, 4, 0x01000000, 0x700000, 0x7000, 20, 12, 16
+};
+
+
+struct tve_reg_mapping *tve_regs;
+struct tve_reg_fields_mapping *tve_reg_fields;
+
+/* For MX37 need modify some fields in tve_probe */
 static struct fb_videomode video_modes[] = {
 	{
 	 /* NTSC TV output */
 	 "TV-NTSC", 60, 720, 480, 74074,
-	 121, 16,
-	 17, 5,
+	 122, 15,
+	 18, 26,
 	 1, 1,
 	 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT | FB_SYNC_EXT,
 	 FB_VMODE_INTERLACED,
@@ -81,14 +134,52 @@ static struct fb_videomode video_modes[] = {
 	{
 	 /* PAL TV output */
 	 "TV-PAL", 50, 720, 576, 74074,
-	 131, 12,
-	 21, 3,
+	 132, 11,
+	 22, 26,
 	 1, 1,
 	 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT | FB_SYNC_EXT,
 	 FB_VMODE_INTERLACED | FB_VMODE_ODD_FLD_FIRST,
 	 0,},
 };
 
+enum tvout_mode {
+	TV_OFF,
+	CVBS0,
+	CVBS2,
+	CVBS02,
+	SVIDEO,
+	SVIDEO_CVBS,
+	YPBPR,
+	RGB
+};
+
+static unsigned short tvout_mode_to_channel_map[8] = {
+	0,	/* TV_OFF */
+	1,	/* CVBS0 */
+	4,	/* CVBS2 */
+	5,	/* CVBS02 */
+	1,	/* SVIDEO */
+	5,	/* SVIDEO_CVBS */
+	1,	/* YPBPR */
+	7	/* RGB */
+};
+
+
+static void tve_set_tvout_mode(int mode)
+{
+	u32 conf_reg;
+
+	conf_reg = __raw_readl(tve.base + tve_regs->tve_com_conf_reg);
+	conf_reg &= ~(tve_reg_fields->sync_ch_mask |
+				tve_reg_fields->tvout_mode_mask);
+	/* clear sync_ch and tvout_mode fields */
+	conf_reg |=
+		mode << tve_reg_fields->
+		tvout_mode_offset | tvout_mode_to_channel_map[mode] <<
+		tve_reg_fields->sync_ch_offset;
+	__raw_writel(conf_reg, tve.base + tve_regs->tve_com_conf_reg);
+}
+
 /**
  * tve_setup
  * initial the CH7024 chipset by setting register
@@ -100,6 +191,8 @@ static struct fb_videomode video_modes[] = {
  */
 static int tve_setup(int mode)
 {
+	u32 reg;
+
 	if (tve.cur_mode == mode)
 		return 0;
 
@@ -110,13 +203,18 @@ static int tve_setup(int mode)
 
 	/* select output video format */
 	if (mode == TVOUT_FMT_PAL) {
-		__raw_writel(0x00840328, tve.base + TVE_COM_CONF_REG);
+		reg = __raw_readl(tve.base + tve_regs->tve_com_conf_reg);
+		reg = (reg & ~TVE_STAND_MASK) | TVE_PAL_STAND;
+		__raw_writel(reg, tve.base + tve_regs->tve_com_conf_reg);
 		pr_debug("TVE: change to PAL video\n");
 	} else if (mode == TVOUT_FMT_NTSC) {
-		__raw_writel(0x00840028, tve.base + TVE_COM_CONF_REG);
+		reg = __raw_readl(tve.base + tve_regs->tve_com_conf_reg);
+		reg = (reg & ~TVE_STAND_MASK) | TVE_NTSC_STAND;
+		__raw_writel(reg, tve.base + tve_regs->tve_com_conf_reg);
 		pr_debug("TVE: change to NTSC video\n");
 	} else if (mode == TVOUT_FMT_OFF) {
-		__raw_writel(0x0, tve.base + TVE_COM_CONF_REG);
+		__raw_writel(0x0, tve.base + tve_regs->tve_com_conf_reg);
+		pr_debug("TVE: change to OFF video\n");
 	} else {
 		pr_debug("TVE: no such video format.\n");
 		if (!enabled)
@@ -141,10 +239,17 @@ static void tve_enable(void)
 	if (!enabled) {
 		enabled = 1;
 		clk_enable(tve.clk);
-		reg = __raw_readl(tve.base + TVE_COM_CONF_REG);
-		__raw_writel(reg | 0x09, tve.base + TVE_COM_CONF_REG);
+		reg = __raw_readl(tve.base + tve_regs->tve_com_conf_reg);
+		__raw_writel(reg | TVE_IPU_CLK_ENABLE | TVE_ENABLE,
+					tve.base + tve_regs->tve_com_conf_reg);
 		pr_debug("TVE power on.\n");
 	}
+
+	/* enable interrupt */
+	__raw_writel(CD_SM_INT | CD_LM_INT | CD_MON_END_INT,
+				tve.base + tve_regs->tve_stat_reg);
+	__raw_writel(CD_SM_INT | CD_LM_INT | CD_MON_END_INT,
+				tve.base + tve_regs->tve_int_cont_reg);
 }
 
 /**
@@ -157,8 +262,10 @@ static void tve_disable(void)
 
 	if (enabled) {
 		enabled = 0;
-		reg = __raw_readl(tve.base + TVE_COM_CONF_REG);
-		__raw_writel(reg & ~0x09, tve.base + TVE_COM_CONF_REG);
+		reg = __raw_readl(tve.base + tve_regs->tve_com_conf_reg);
+		__raw_writel(reg & ~TVE_ENABLE & ~TVE_IPU_CLK_ENABLE,
+				tve.base + tve_regs->tve_com_conf_reg);
+		tve_set_tvout_mode(TV_OFF);
 		clk_disable(tve.clk);
 		pr_debug("TVE power off.\n");
 	}
@@ -167,30 +274,87 @@ static void tve_disable(void)
 static int tve_update_detect_status(void)
 {
 	int old_detect = tve.detect;
-	u32 stat = __raw_readl(tve.base + TVE_STAT_REG);
+	u32 stat_lm, stat_sm, stat;
+	u32 int_ctl = __raw_readl(tve.base + tve_regs->tve_int_cont_reg);
+	u32 cd_cont_reg =
+		__raw_readl(tve.base + tve_regs->tve_cd_cont_reg);
+	u32 timeout = 40;
+
+	if ((cd_cont_reg & 0x1) == 0) {
+		pr_warning("Warning: pls enable TVE CD first!\n");
+		return tve.detect;
+	}
 
-	if ((stat & CD_MON_END_INT) == 0)
+	stat = __raw_readl(tve.base + tve_regs->tve_stat_reg);
+	while (((stat & CD_MON_END_INT) == 0) && (timeout > 0)) {
+		msleep(2);
+		timeout -= 2;
+		stat = __raw_readl(tve.base + tve_regs->tve_stat_reg);
+	}
+	if (((stat & CD_MON_END_INT) == 0) && (timeout <= 0)) {
+		pr_warning("Warning: get detect resultwithout CD_MON_END_INT!\n");
 		return tve.detect;
+	}
 
-	if (stat & CD_LM_INT) {
-		if (stat & CD_SM_INT)
+	stat = stat >> tve_reg_fields->cd_ch_stat_offset;
+	stat_lm = stat & (CD_CH_0_LM_ST | CD_CH_1_LM_ST | CD_CH_2_LM_ST);
+	if ((stat_lm == (CD_CH_0_LM_ST | CD_CH_1_LM_ST | CD_CH_2_LM_ST)) &&
+		((stat & (CD_CH_0_SM_ST | CD_CH_1_SM_ST | CD_CH_2_SM_ST)) == 0)
+		) {
+			tve.detect = 3;
+			tve.output_mode = YPBPR;
+	} else if ((stat_lm == (CD_CH_0_LM_ST | CD_CH_1_LM_ST)) &&
+		((stat & (CD_CH_0_SM_ST | CD_CH_1_SM_ST)) == 0)) {
+			tve.detect = 4;
+			tve.output_mode = SVIDEO;
+	} else if (stat_lm == CD_CH_0_LM_ST) {
+		stat_sm = stat & CD_CH_0_SM_ST;
+		if (stat_sm != 0) {
+			/* headset */
 			tve.detect = 2;
-		else
+			tve.output_mode = TV_OFF;
+		} else {
+			tve.detect = 1;
+			tve.output_mode = CVBS0;
+		}
+	} else if (stat_lm == CD_CH_2_LM_ST) {
+		stat_sm = stat & CD_CH_2_SM_ST;
+		if (stat_sm != 0) {
+			/* headset */
+			tve.detect = 2;
+			tve.output_mode = TV_OFF;
+		} else {
 			tve.detect = 1;
+			tve.output_mode = CVBS2;
+		}
 	} else {
+		/* none */
 		tve.detect = 0;
+		tve.output_mode = TV_OFF;
 	}
 
-	__raw_writel(CD_SM_INT | CD_LM_INT | CD_MON_END_INT,
-		     tve.base + TVE_STAT_REG);
+	tve_set_tvout_mode(tve.output_mode);
+
+	/* clear interrupt */
+	__raw_writel(CD_MON_END_INT | CD_LM_INT | CD_SM_INT,
+			tve.base + tve_regs->tve_stat_reg);
+
+	__raw_writel(int_ctl | CD_SM_INT | CD_LM_INT,
+			tve.base + tve_regs->tve_int_cont_reg);
 
 	if (old_detect != tve.detect)
 		sysfs_notify(&tve.pdev->dev.kobj, NULL, "headphone");
 
-	dev_dbg(&tve.pdev->dev, "detect = %d\n", tve.detect);
+	dev_dbg(&tve.pdev->dev, "detect = %d mode = %d\n",
+			tve.detect, tve.output_mode);
 	return tve.detect;
 }
 
+static void cd_work_func(struct work_struct *work)
+{
+	tve_update_detect_status();
+}
+
 static int tve_man_detect(void)
 {
 	u32 cd_cont;
@@ -199,41 +363,44 @@ static int tve_man_detect(void)
 	if (!enabled)
 		return -1;
 
-	int_cont = __raw_readl(tve.base + TVE_INT_CONT_REG);
-	__raw_writel(int_cont & ~(CD_SM_INT | CD_LM_INT),
-		     tve.base + TVE_INT_CONT_REG);
+	int_cont = __raw_readl(tve.base + tve_regs->tve_int_cont_reg);
+	__raw_writel(int_cont &
+				~(tve_reg_fields->cd_sm_int | tve_reg_fields->cd_lm_int),
+				tve.base + tve_regs->tve_int_cont_reg);
 
-	cd_cont = __raw_readl(tve.base + TVE_CD_CONT_REG);
-	__raw_writel(cd_cont | CD_TRIG_MODE, tve.base + TVE_CD_CONT_REG);
+	cd_cont = __raw_readl(tve.base + tve_regs->tve_cd_cont_reg);
+	__raw_writel(cd_cont | tve_reg_fields->cd_trig_mode,
+				tve.base + tve_regs->tve_cd_cont_reg);
 
-	__raw_writel(CD_SM_INT | CD_LM_INT | CD_MON_END_INT | CD_MAN_TRIG,
-		     tve.base + TVE_STAT_REG);
+	__raw_writel(tve_reg_fields->cd_sm_int | tve_reg_fields->
+			cd_lm_int | tve_reg_fields->
+			cd_mon_end_int | tve_reg_fields->cd_man_trig,
+			tve.base + tve_regs->tve_stat_reg);
 
-	while ((__raw_readl(tve.base + TVE_STAT_REG) & CD_MON_END_INT) == 0)
+	while ((__raw_readl(tve.base + tve_regs->tve_stat_reg)
+		& tve_reg_fields->cd_mon_end_int) == 0)
 		msleep(5);
 
 	tve_update_detect_status();
 
-	__raw_writel(cd_cont, tve.base + TVE_CD_CONT_REG);
-	__raw_writel(int_cont, tve.base + TVE_INT_CONT_REG);
+	__raw_writel(cd_cont, tve.base + tve_regs->tve_cd_cont_reg);
+	__raw_writel(int_cont, tve.base + tve_regs->tve_int_cont_reg);
 
 	return tve.detect;
 }
 
 static irqreturn_t tve_detect_handler(int irq, void *data)
 {
-	u32 stat;
-	int old_detect = tve.detect;
-
-	stat = __raw_readl(tve.base + TVE_STAT_REG);
-	stat &= __raw_readl(tve.base + TVE_INT_CONT_REG);
+	u32 int_ctl = __raw_readl(tve.base + tve_regs->tve_int_cont_reg);
 
-	tve_update_detect_status();
+	/* disable INT first */
+	int_ctl &= ~(CD_SM_INT | CD_LM_INT | CD_MON_END_INT);
+	__raw_writel(int_ctl, tve.base + tve_regs->tve_int_cont_reg);
 
-	__raw_writel(stat | CD_MON_END_INT, tve.base + TVE_STAT_REG);
+	__raw_writel(CD_MON_END_INT | CD_LM_INT | CD_SM_INT,
+			tve.base + tve_regs->tve_stat_reg);
 
-	if (old_detect != tve.detect)
-		sysfs_notify(&tve.pdev->dev.kobj, NULL, "headphone");
+	schedule_delayed_work(&tve.cd_work, msecs_to_jiffies(1000));
 
 	return IRQ_HANDLED;
 }
@@ -279,12 +446,27 @@ int tve_fb_event(struct notifier_block *nb, unsigned long val, void *v)
 		}
 		break;
 	case FB_EVENT_BLANK:
-		if ((tve_fbi != fbi) || (tve.cur_mode == TVOUT_FMT_OFF))
+		if ((tve_fbi != fbi) || (fbi->mode == NULL))
 			return 0;
 
-		if (*((int *)event->data) == FB_BLANK_UNBLANK)
-			tve_enable();
-		else
+		if (*((int *)event->data) == FB_BLANK_UNBLANK) {
+			if (fb_mode_is_equal(fbi->mode, &video_modes[0])) {
+				if (tve.cur_mode != TVOUT_FMT_NTSC) {
+					tve_disable();
+					tve_setup(TVOUT_FMT_NTSC);
+				}
+				tve_enable();
+			} else if (fb_mode_is_equal(fbi->mode,
+					&video_modes[1])) {
+				if (tve.cur_mode != TVOUT_FMT_PAL) {
+					tve_disable();
+					tve_setup(TVOUT_FMT_PAL);
+				}
+				tve_enable();
+			} else {
+				tve_setup(TVOUT_FMT_OFF);
+			}
+		} else
 			tve_disable();
 		break;
 	}
@@ -295,7 +477,8 @@ static struct notifier_block nb = {
 	.notifier_call = tve_fb_event,
 };
 
-static ssize_t show_headphone(struct device_driver *dev, char *buf)
+static ssize_t show_headphone(struct device *dev,
+		struct device_attribute *attr, char *buf)
 {
 	int detect;
 
@@ -310,19 +493,43 @@ static ssize_t show_headphone(struct device_driver *dev, char *buf)
 		strcpy(buf, "none\n");
 	else if (detect == 1)
 		strcpy(buf, "cvbs\n");
-	else
+	else if (detect == 2)
 		strcpy(buf, "headset\n");
+	else if (detect == 3)
+		strcpy(buf, "component\n");
+	else
+		strcpy(buf, "svideo\n");
 
 	return strlen(buf);
 }
 
-static DRIVER_ATTR(headphone, 0644, show_headphone, NULL);
+static DEVICE_ATTR(headphone, S_IRUGO | S_IWUSR, show_headphone, NULL);
+
+static int _tve_get_revision(void)
+{
+	u32 conf_reg;
+	u32 rev = 0;
+
+	/* find out TVE rev based on the base addr default value
+	 * can be used at the init/probe ONLY */
+	conf_reg = __raw_readl(tve.base);
+	switch (conf_reg) {
+	case 0x00842000:
+		rev = 1;
+		break;
+	case 0x00100000:
+		rev = 2;
+		break;
+	}
+	return rev;
+}
 
 static int tve_probe(struct platform_device *pdev)
 {
 	int ret, i;
 	struct resource *res;
 	struct tve_platform_data *plat_data = pdev->dev.platform_data;
+	u32 conf_reg;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (res == NULL)
@@ -337,11 +544,12 @@ static int tve_probe(struct platform_device *pdev)
 		goto err0;
 	}
 
+	INIT_DELAYED_WORK(&tve.cd_work, cd_work_func);
 	ret = request_irq(tve.irq, tve_detect_handler, 0, pdev->name, pdev);
 	if (ret < 0)
 		goto err0;
 
-	ret = driver_create_file(pdev->dev.driver, &driver_attr_headphone);
+	ret = device_create_file(&pdev->dev, &dev_attr_headphone);
 	if (ret < 0)
 		goto err1;
 
@@ -351,6 +559,19 @@ static int tve_probe(struct platform_device *pdev)
 			break;
 		}
 	}
+
+	/* adjust video mode for mx37 */
+	if (cpu_is_mx37()) {
+		video_modes[0].left_margin = 121;
+		video_modes[0].right_margin = 16;
+		video_modes[0].upper_margin = 17;
+		video_modes[0].lower_margin = 5;
+		video_modes[1].left_margin = 131;
+		video_modes[1].right_margin = 12;
+		video_modes[1].upper_margin = 21;
+		video_modes[1].lower_margin = 3;
+	}
+
 	if (tve_fbi != NULL) {
 		fb_add_videomode(&video_modes[0], &tve_fbi->modelist);
 		fb_add_videomode(&video_modes[1], &tve_fbi->modelist);
@@ -372,19 +593,27 @@ static int tve_probe(struct platform_device *pdev)
 	clk_set_rate(tve.clk, 216000000);
 	clk_enable(tve.clk);
 
-	/* Setup cable detect */
-	__raw_writel(0x010777F1, tve.base + TVE_CD_CONT_REG);
+	if (_tve_get_revision() == 1) {
+		tve_regs = &tve_regs_v1;
+		tve_reg_fields = &tve_reg_fields_v1;
+	} else {
+		tve_regs = &tve_regs_v2;
+		tve_reg_fields = &tve_reg_fields_v2;
+	}
+
+	/* Setup cable detect, for YPrPb mode, default use channel#0 for Y */
+	__raw_writel(0x01067701, tve.base + tve_regs->tve_cd_cont_reg);
 	/* tve_man_detect(); not working */
 
-	__raw_writel(CD_SM_INT | CD_LM_INT, tve.base + TVE_STAT_REG);
-	__raw_writel(CD_SM_INT | CD_LM_INT, tve.base + TVE_INT_CONT_REG);
+	conf_reg = 0;
+	__raw_writel(conf_reg, tve.base + tve_regs->tve_com_conf_reg);
 
-	__raw_writel(0x00000000, tve.base + 0x34);
-	__raw_writel(0x00000000, tve.base + 0x38);
-	__raw_writel(0x00000000, tve.base + 0x3C);
-	__raw_writel(0x00000000, tve.base + 0x40);
-	__raw_writel(0x00000000, tve.base + 0x44);
-	__raw_writel(0x00000000, tve.base + TVE_MV_CONT_REG);
+	__raw_writel(0x00000000, tve.base + tve_regs->tve_mv_cont_reg - 4 * 5);
+	__raw_writel(0x00000000, tve.base + tve_regs->tve_mv_cont_reg - 4 * 4);
+	__raw_writel(0x00000000, tve.base + tve_regs->tve_mv_cont_reg - 4 * 3);
+	__raw_writel(0x00000000, tve.base + tve_regs->tve_mv_cont_reg - 4 * 2);
+	__raw_writel(0x00000000, tve.base + tve_regs->tve_mv_cont_reg - 4);
+	__raw_writel(0x00000000, tve.base + tve_regs->tve_mv_cont_reg);
 
 	clk_disable(tve.clk);
 
@@ -394,7 +623,7 @@ static int tve_probe(struct platform_device *pdev)
 
 	return 0;
 err2:
-	driver_remove_file(pdev->dev.driver, &driver_attr_headphone);
+	device_remove_file(&pdev->dev, &dev_attr_headphone);
 err1:
 	free_irq(tve.irq, pdev);
 err0:
@@ -409,7 +638,7 @@ static int tve_remove(struct platform_device *pdev)
 		enabled = 0;
 	}
 	free_irq(tve.irq, pdev);
-	driver_remove_file(pdev->dev.driver, &driver_attr_headphone);
+	device_remove_file(&pdev->dev, &dev_attr_headphone);
 	fb_unregister_client(&nb);
 	return 0;
 }
@@ -420,9 +649,9 @@ static int tve_remove(struct platform_device *pdev)
 static int tve_suspend(struct platform_device *pdev, pm_message_t state)
 {
 	if (enabled) {
-		__raw_writel(0, tve.base + TVE_INT_CONT_REG);
-		__raw_writel(0, tve.base + TVE_CD_CONT_REG);
-		__raw_writel(0, tve.base + TVE_COM_CONF_REG);
+		__raw_writel(0, tve.base + tve_regs->tve_int_cont_reg);
+		__raw_writel(0, tve.base + tve_regs->tve_cd_cont_reg);
+		__raw_writel(0, tve.base + tve_regs->tve_com_conf_reg);
 		clk_disable(tve.clk);
 	}
 	return 0;
@@ -430,9 +659,24 @@ static int tve_suspend(struct platform_device *pdev, pm_message_t state)
 
 static int tve_resume(struct platform_device *pdev)
 {
-	if (enabled)
+	if (enabled) {
 		clk_enable(tve.clk);
 
+		/* Setup cable detect */
+		__raw_writel(0x01067701, tve.base + tve_regs->tve_cd_cont_reg);
+
+		if (tve.cur_mode == TVOUT_FMT_NTSC) {
+			tve_disable();
+			tve.cur_mode = TVOUT_FMT_OFF;
+			tve_setup(TVOUT_FMT_NTSC);
+		} else if (tve.cur_mode == TVOUT_FMT_PAL) {
+			tve_disable();
+			tve.cur_mode = TVOUT_FMT_OFF;
+			tve_setup(TVOUT_FMT_PAL);
+		}
+		tve_enable();
+	}
+
 	return 0;
 }
 
-- 
1.6.0.4





More information about the kernel-team mailing list