diff -Naur -X kernel-source-2.6.16-2.6.16.rel/Documentation/dontdiff kernel-source-2.6.16-2.6.16.rel/arch/arm/mach-omap1/board-nokia770.c kernel-source-2.6.16-2.6.16.my/arch/arm/mach-omap1/board-nokia770.c
--- kernel-source-2.6.16-2.6.16.rel/arch/arm/mach-omap1/board-nokia770.c	2006-11-28 14:16:52.000000000 +0100
+++ kernel-source-2.6.16-2.6.16.my/arch/arm/mach-omap1/board-nokia770.c	2008-04-06 21:46:43.000000000 +0200
@@ -257,6 +257,47 @@
 	platform_device_register(&retu_headset_device);
 }
 
+/*
+ We do our own pin muxing here,
+ CONFIG_OMAP_MUX is disabled for 770 kernel as all pin muxing is done in NOLO bootloader,
+ we cannot enable it since random pieces of kernel would then change muxing of other pins.
+*/
+
+static void __init nokia770_mux_pin(char *cfg_name, char *mux_reg_name, unsigned int mux_reg,
+					unsigned char value, unsigned char offset)
+{
+	static DEFINE_SPINLOCK(nokia770_mux_spin_lock);
+	unsigned long flags;
+	unsigned int reg_orig = 0, reg = 0;
+	unsigned int tmp1, tmp2;
+	unsigned int mask, warn = 0;
+	spin_lock_irqsave(&nokia770_mux_spin_lock, flags);
+	reg_orig = omap_readl(mux_reg);
+	/* The mux registers always seem to be 3 bits long */
+	mask = (0x7 << offset);
+	tmp1 = reg_orig & mask;
+	reg = reg_orig & ~mask;
+	tmp2 = (value << offset);
+	reg |= tmp2;
+	if (tmp1 != tmp2)
+		warn = 1;
+	omap_writel(reg, mux_reg);
+	spin_unlock_irqrestore(&nokia770_mux_spin_lock, flags);
+	if (warn) {
+		printk("MUX: Setting %s\n", cfg_name);
+		printk("      %s (0x%08x) = 0x%08x -> 0x%08x\n",
+	        	mux_reg_name, mux_reg, reg_orig, reg);
+	}
+}
+
+static void __init nokia770_mux_init(void)
+{
+	// TE pin of S1D13742 is connected to ball G20
+	// set correct muxing for TE (tearing enabled) SOSSI pin on ball G20
+	//omap_cfg_reg(G20_SOSSI_TE);
+	nokia770_mux_pin("G20_SOSSI_TE","FUNC_MUX_CTRL_4",FUNC_MUX_CTRL_4,6,6);
+}
+
 static void __init nokia770_init(void)
 {
 	nokia770_config[0].data = &nokia770_usb_config;
@@ -267,6 +308,7 @@
 	omap_board_config = nokia770_config;
 	omap_board_config_size = ARRAY_SIZE(nokia770_config);
 	omap_gpio_init();
+	nokia770_mux_init();
 	omap_serial_init();
 	omap_dsp_audio_pwr_up_request = nokia770_audio_pwr_up_request;
 	omap_dsp_audio_pwr_down_request = nokia770_audio_pwr_down_request;
diff -Naur -X kernel-source-2.6.16-2.6.16.rel/Documentation/dontdiff kernel-source-2.6.16-2.6.16.rel/arch/arm/mach-omap1/clock.c kernel-source-2.6.16-2.6.16.my/arch/arm/mach-omap1/clock.c
--- kernel-source-2.6.16-2.6.16.rel/arch/arm/mach-omap1/clock.c	2008-04-07 09:52:44.000000000 +0200
+++ kernel-source-2.6.16-2.6.16.my/arch/arm/mach-omap1/clock.c	2007-05-06 21:04:45.000000000 +0200
@@ -46,6 +46,15 @@
 		clk->rate = 12000000;
 }
 
+static void omap1_sossi_recalc(struct clk *clk)
+{
+	u32 div = omap_readl(MOD_CONF_CTRL_1);
+
+	div = (div >> 17) & 0x7;
+	div++;
+	clk->rate = clk->parent->rate / div;
+}
+
 static int omap1_clk_enable_dsp_domain(struct clk *clk)
 {
 	int retval;
@@ -389,6 +398,31 @@
 	return 0;
 }
 
+static int omap1_set_sossi_rate(struct clk *clk, unsigned long rate)
+{
+	u32 l;
+	int div;
+	unsigned long p_rate;
+
+	p_rate = clk->parent->rate;
+	/* Round towards slower frequency */
+	div = (p_rate + rate - 1) / rate;
+	div--;
+	if (div < 0 || div > 7)
+		return -EINVAL;
+
+	l = omap_readl(MOD_CONF_CTRL_1);
+	l &= ~(7 << 17);
+	l |= div << 17;
+	omap_writel(l, MOD_CONF_CTRL_1);
+
+	clk->rate = p_rate / (div + 1);
+	if (unlikely(clk->flags & RATE_PROPAGATES))
+		propagate_rate(clk);
+
+	return 0;
+}
+
 static long omap1_round_ext_clk_rate(struct clk * clk, unsigned long rate)
 {
 	return 96000000 / calc_ext_dsor(rate);
diff -Naur -X kernel-source-2.6.16-2.6.16.rel/Documentation/dontdiff kernel-source-2.6.16-2.6.16.rel/arch/arm/mach-omap1/clock.h kernel-source-2.6.16-2.6.16.my/arch/arm/mach-omap1/clock.h
--- kernel-source-2.6.16-2.6.16.rel/arch/arm/mach-omap1/clock.h	2008-04-07 09:52:44.000000000 +0200
+++ kernel-source-2.6.16-2.6.16.my/arch/arm/mach-omap1/clock.h	2007-05-06 21:04:45.000000000 +0200
@@ -17,6 +17,8 @@
 static void omap1_clk_disable_generic(struct clk * clk);
 static void omap1_ckctl_recalc(struct clk * clk);
 static void omap1_watchdog_recalc(struct clk * clk);
+static int omap1_set_sossi_rate(struct clk *clk, unsigned long rate);
+static void omap1_sossi_recalc(struct clk *clk);
 static void omap1_ckctl_recalc_dsp_domain(struct clk * clk);
 static int omap1_clk_enable_dsp_domain(struct clk * clk);
 static int omap1_clk_set_rate_dsp_domain(struct clk * clk, unsigned long rate);
@@ -167,9 +169,10 @@
 
 static struct arm_idlect1_clk ck_dpll1out = {
 	.clk = {
-	       	.name		= "ck_dpll1out",
+		.name		= "ck_dpll1out",
 		.parent		= &ck_dpll1,
-		.flags		= CLOCK_IN_OMAP16XX | CLOCK_IDLE_CONTROL,
+		.flags		= CLOCK_IN_OMAP16XX | CLOCK_IDLE_CONTROL |
+				  ENABLE_REG_32BIT | RATE_PROPAGATES,
 		.enable_reg	= (void __iomem *)ARM_IDLECT2,
 		.enable_bit	= EN_CKOUT_ARM,
 		.recalc		= &followparent_recalc,
@@ -179,6 +182,19 @@
 	.idlect_shift	= 12,
 };
 
+static struct clk sossi_ck = {
+	.name		= "ck_sossi",
+	.parent		= &ck_dpll1out.clk,
+	.flags		= CLOCK_IN_OMAP16XX | CLOCK_NO_IDLE_PARENT |
+			  ENABLE_REG_32BIT,
+	.enable_reg	= (void __iomem *)MOD_CONF_CTRL_1,
+	.enable_bit	= 16,
+	.recalc		= &omap1_sossi_recalc,
+	.set_rate	= &omap1_set_sossi_rate,
+	.enable		= &omap1_clk_enable_generic,
+	.disable	= &omap1_clk_disable_generic,
+};
+
 static struct clk arm_ck = {
 	.name		= "arm_ck",
 	.parent		= &ck_dpll1,
@@ -759,6 +775,7 @@
 	&ck_dpll1,
 	/* CK_GEN1 clocks */
 	&ck_dpll1out.clk,
+	&sossi_ck,
 	&arm_ck,
 	&armper_ck.clk,
 	&arm_gpio_ck,
diff -Naur -X kernel-source-2.6.16-2.6.16.rel/Documentation/dontdiff kernel-source-2.6.16-2.6.16.rel/arch/arm/mach-omap1/mux.c kernel-source-2.6.16-2.6.16.my/arch/arm/mach-omap1/mux.c
--- kernel-source-2.6.16-2.6.16.rel/arch/arm/mach-omap1/mux.c	2006-11-28 14:16:52.000000000 +0100
+++ kernel-source-2.6.16-2.6.16.my/arch/arm/mach-omap1/mux.c	2008-04-05 22:32:36.000000000 +0200
@@ -273,6 +273,12 @@
 MUX_CFG("V10_1610_CF_IREQ",	 A,   24,    3,	  2,   14,   0,	  2,	 0,  1)
 MUX_CFG("W10_1610_CF_RESET",	 A,   18,    3,	  2,   12,   1,	  2,	 1,  1)
 MUX_CFG("W11_1610_CF_CD1",	10,   15,    3,	  3,    8,   1,	  3,	 1,  1)
+
+/*
+ *	 description		mux  mode   mux	 pull pull  pull  pu_pd	 pu  dbg
+ *				reg  offset mode reg  bit   ena	  reg
+ */
+MUX_CFG("G20_SOSSI_TE",		4,   6,     6,   NA,   0,   0,    NA , 0,  1)
 };
 #endif	/* CONFIG_ARCH_OMAP15XX || CONFIG_ARCH_OMAP16XX */
 
diff -Naur -X kernel-source-2.6.16-2.6.16.rel/Documentation/dontdiff kernel-source-2.6.16-2.6.16.rel/drivers/video/omap/hwa742.c kernel-source-2.6.16-2.6.16.my/drivers/video/omap/hwa742.c
--- kernel-source-2.6.16-2.6.16.rel/drivers/video/omap/hwa742.c	2008-04-07 09:52:45.000000000 +0200
+++ kernel-source-2.6.16-2.6.16.my/drivers/video/omap/hwa742.c	2007-05-29 12:36:53.000000000 +0200
@@ -86,17 +86,17 @@
 #define REQ_POOL_SIZE			24
 #define IRQ_REQ_POOL_SIZE		4
 
+#define REQ_FROM_IRQ_POOL 0x01
+
+#define REQ_COMPLETE	0
+#define REQ_PENDING	1
+
 struct update_param {
 	int	x, y, width, height;
 	int	color_mode;
 	int	flags;
 };
 
-#define REQ_FROM_IRQ_POOL 0x01
-
-#define REQ_COMPLETE	0
-#define REQ_PENDING	1
-
 struct hwa742_request {
 	struct list_head entry;
 	unsigned int	 flags;
@@ -118,6 +118,8 @@
 	struct timer_list	auto_update_timer;
 	int			stop_auto_update;
 	struct omapfb_update_window	auto_update_window;
+	unsigned		te_connected:1;
+	unsigned		vsync_only:1;
 
 	struct hwa742_request	req_pool[REQ_POOL_SIZE];
 	struct list_head	pending_req_list;
@@ -134,6 +136,9 @@
 
 	u32			max_transmit_size;
 	u32			extif_clk_period;
+	unsigned long		pix_tx_time;
+	unsigned long		line_upd_time;
+
 
 	struct omapfb_device	*fbdev;
 	struct lcd_ctrl_extif	*extif;
@@ -197,6 +202,45 @@
 	hwa742_write_reg(HWA742_WINDOW_TYPE, hwa742.window_type);
 }
 
+static void enable_tearsync(int y, int width, int height, int screen_height,
+			    int force_vsync)
+{
+	u8 b;
+
+	b = hwa742_read_reg(HWA742_NDP_CTRL);
+	b |= 1 << 2;
+	hwa742_write_reg(HWA742_NDP_CTRL, b);
+
+	if (likely(hwa742.vsync_only || force_vsync)) {
+		hwa742.extif->enable_tearsync(1, 0);
+		return;
+	}
+
+	if (width * hwa742.pix_tx_time < hwa742.line_upd_time) {
+		hwa742.extif->enable_tearsync(1, 0);
+		return;
+	}
+
+	if ((width * hwa742.pix_tx_time / 1000) * height <
+	    (y + height) * (hwa742.line_upd_time / 1000)) {
+		hwa742.extif->enable_tearsync(1, 0);
+		return;
+	}
+
+	hwa742.extif->enable_tearsync(1, y + 1);
+}
+
+static void disable_tearsync(void)
+{
+	u8 b;
+
+	hwa742.extif->enable_tearsync(0, 0);
+
+	b = hwa742_read_reg(HWA742_NDP_CTRL);
+	b &= ~(1 << 2);
+	hwa742_write_reg(HWA742_NDP_CTRL, b);
+}
+
 static inline struct hwa742_request *alloc_req(void)
 {
 	unsigned long flags;
@@ -306,6 +350,20 @@
 	process_pending_requests();
 }
 
+/* Wait until the YYC color space converter is idle. */                                                                                                      
+static void hwa742_wait_yyc(void)
+{
+	unsigned long tmo = jiffies + msecs_to_jiffies(30);
+
+	while (hwa742_read_reg(HWA742_NDP_CTRL) & (1 << 4)) {
+		if (time_after(jiffies, tmo)) {
+			if (printk_ratelimit())
+				dev_err(hwa742.fbdev->dev,"hwa742: YYC not ready\n");
+			break;
+		}
+	}
+}
+
 static int send_frame_handler(struct hwa742_request *req)
 {
 	struct update_param *par = &req->par.update;
@@ -313,29 +371,38 @@
 	int y = par->y;
 	int w = par->width;
 	int h = par->height;
-	int bpp;
 	int conv, transl;
 	unsigned long offset;
 	int color_mode = par->color_mode;
+	int prev_color_mode;
 	int flags = par->flags;
-	int scr_width = 800;
+	int scr_width = hwa742.fbdev->panel->x_res;
+	int scr_height = hwa742.fbdev->panel->y_res;
+	int scr_bpp = hwa742.fbdev->panel->bpp;
 
 	DBGPRINT(2, "x %d y %d w %d h %d scr_width %d color_mode %d flags %d\n",
 		x, y, w, h, scr_width, color_mode, flags);
 
 	switch (color_mode) {
 	case OMAPFB_COLOR_YUV422:
-		bpp = 16;
 		conv = 0x08;
 		transl = 0x25;
+               /* X, Y, height must be aligned at 2, width at 4 pixels */      
+                x &= ~1;                                                        
+                y &= ~1;                                                        
+                h &= ~1;                                   
+                w &= ~3;                                             
 		break;
 	case OMAPFB_COLOR_YUV420:
-		bpp = 12;
 		conv = 0x09;
 		transl = 0x25;
+               /* X, Y, height must be aligned at 2, width at 4 pixels */      
+                x &= ~1;                                                        
+                y &= ~1;                                                        
+                h &= ~1;                                   
+                w &= ~3;                                             
 		break;
 	case OMAPFB_COLOR_RGB565:
-		bpp = 16;
 		conv = 0x01;
 		transl = 0x05;
 		break;
@@ -343,21 +410,39 @@
 		return -EINVAL;
 	}
 
+	prev_color_mode = hwa742.prev_color_mode; // remember for YYC check below
 	if (hwa742.prev_flags != flags ||
 	    hwa742.prev_color_mode != color_mode) {
 		set_format_regs(conv, transl, flags);
 		hwa742.prev_color_mode = color_mode;
 		hwa742.prev_flags = flags;
 	}
+	flags = req->par.update.flags;
+	if (flags & OMAPFB_FORMAT_FLAG_TEARSYNC)
+		enable_tearsync(y, scr_width, h, scr_height,
+				flags & OMAPFB_FORMAT_FLAG_FORCE_VSYNC);
+	else
+		disable_tearsync();
 
+	if (prev_color_mode==OMAPFB_COLOR_YUV420) { // wait for YYC converter for YUV420 mode
+		  hwa742_wait_yyc();                                                                                                                         
+	}
+	
 	set_window_regs(x, y, x + w, y + h);
 
-	offset = (scr_width * y + x) * bpp / 8;
+	offset = (scr_width * y + x) * scr_bpp / 8;
 
 	hwa742.int_ctrl->setup_plane(OMAPFB_PLANE_GFX,
 			OMAPFB_CHANNEL_OUT_LCD, offset, scr_width, 0, 0, w, h,
 			color_mode);
 
+	if (color_mode==OMAPFB_COLOR_YUV420){
+        	/* Currently only the 16 bits/pixel cycle format is
+		* supported on the external interface. Adjust the number
+		* of transfer elements per line for 12bpp format.
+		*/
+		w = (w + 1) * 3 / 4;
+	}
 	hwa742.extif->set_bits_per_cycle(16);
 
 	hwa742.int_ctrl->enable_plane(OMAPFB_PLANE_GFX, 1);
@@ -395,13 +480,14 @@
 	int color_mode;
 	int flags;
 
-	flags = win->format & OMAPFB_FORMAT_FLAG_DOUBLE;
+	flags = win->format & ~OMAPFB_FORMAT_MASK;
 	color_mode = win->format & OMAPFB_FORMAT_MASK;
 
 	if (x & 1) {
 		ADD_PREQ(x, y, 1, height);
 		width--;
 		x++;
+		flags &= ~OMAPFB_FORMAT_FLAG_TEARSYNC;
 	}
 	if (width & ~1) {
 		unsigned int xspan = width & ~1;
@@ -413,11 +499,13 @@
 			ADD_PREQ(x, ystart, xspan, yspan);
 			ystart += yspan;
 			yspan = height - yspan;
+			flags &= ~OMAPFB_FORMAT_FLAG_TEARSYNC;
 		}
 
 		ADD_PREQ(x, ystart, xspan, yspan);
 		x += xspan;
 		width -= xspan;
+		flags &= ~OMAPFB_FORMAT_FLAG_TEARSYNC;
 	}
 	if (width)
 		ADD_PREQ(x, y, 1, height);
@@ -467,8 +555,10 @@
 		r = -EINVAL;
 		goto out;
 	}
-	if (unlikely(win->format & ~(0x03 | OMAPFB_FORMAT_FLAG_DOUBLE))) {
-		DBGPRINT(1, "invalid window flag");
+	if (unlikely(win->format &
+	    ~(0x03 | OMAPFB_FORMAT_FLAG_DOUBLE |
+	    OMAPFB_FORMAT_FLAG_TEARSYNC | OMAPFB_FORMAT_FLAG_FORCE_VSYNC))) {
+		DBGPRINT(1,"invalid window flag");
 		r = -EINVAL;
 		goto out;
 	}
@@ -705,7 +795,7 @@
 	return hwa742.extif->convert_timings(t);
 }
 
-static int calc_extif_timings(unsigned long sysclk)
+static int calc_extif_timings(unsigned long sysclk, int *extif_mem_div)
 {
 	int max_clk_div;
 	int div;
@@ -715,25 +805,161 @@
 		if (calc_reg_timing(sysclk, div) == 0)
 			break;
 	}
-	if (div == max_clk_div)
+	if (div > max_clk_div)
 		goto err;
 
+	*extif_mem_div = div;
+
 	for (div = 1; div < max_clk_div; div++) {
 		if (calc_lut_timing(sysclk, div) == 0)
 			break;
 	}
 
-	if (div < max_clk_div)
-		return 0;
+	if (div > max_clk_div)
+		goto err;
+
+	return 0;
 
 err:
 	pr_err("can't setup timings\n");
 	return -1;
 }
 
+static void calc_hwa742_clk_rates(unsigned long ext_clk,
+				unsigned long *sys_clk, unsigned long *pix_clk)
+{
+	int pix_clk_src;
+	int sys_div = 0, sys_mul = 0;
+	int pix_div;
+
+	pix_clk_src = hwa742_read_reg(HWA742_CLK_SRC_REG);
+	pix_div = ((pix_clk_src >> 3) & 0x1f) + 1;
+	if ((pix_clk_src & (0x3 << 1)) == 0) {
+		/* Source is the PLL */
+		sys_div = (hwa742_read_reg(HWA742_PLL_DIV_REG) & 0x3f) + 1;
+		sys_mul = (hwa742_read_reg(HWA742_PLL_4_REG) & 0x7f) + 1;
+		*sys_clk = ext_clk * sys_mul / sys_div;
+	} else	/* else source is ext clk, or oscillator */
+		*sys_clk = ext_clk;
+
+	*pix_clk = *sys_clk / pix_div;			/* HZ */
+	DBGPRINT(1,
+		"ext_clk %ld pix_src %d pix_div %d sys_div %d sys_mul %d\n",
+		ext_clk, pix_clk_src & (0x3 << 1), pix_div, sys_div, sys_mul);
+	DBGPRINT(1, "sys_clk %ld pix_clk %ld\n",
+		*sys_clk, *pix_clk);
+}
+
+
+static int setup_tearsync(unsigned long pix_clk, int extif_div)
+{
+	int hdisp, vdisp;
+	int hndp, vndp;
+	int hsw, vsw;
+	int hs, vs;
+	int hs_pol_inv, vs_pol_inv;
+	int use_hsvs, use_ndp;
+	u8  b;
+
+	hsw = hwa742_read_reg(HWA742_HS_W_REG);
+	vsw = hwa742_read_reg(HWA742_VS_W_REG);
+	hs_pol_inv = !(hsw & 0x80);
+	vs_pol_inv = !(vsw & 0x80);
+	hsw = hsw & 0x7f;
+	vsw = vsw & 0x3f;
+
+	hdisp = (hwa742_read_reg(HWA742_H_DISP_REG) & 0x7f) * 8;
+	vdisp = hwa742_read_reg(HWA742_V_DISP_1_REG) +
+		((hwa742_read_reg(HWA742_V_DISP_2_REG) & 0x3) << 8);
+
+	hndp = hwa742_read_reg(HWA742_H_NDP_REG) & 0x7f;
+	vndp = hwa742_read_reg(HWA742_V_NDP_REG);
+
+	/* time to transfer one pixel (16bpp) in ps */
+	hwa742.pix_tx_time = hwa742.reg_timings.we_cycle_time;
+	if (hwa742.extif->get_max_tx_rate != NULL) {
+		/* The external interface might have a rate limitation,
+		 * if so, we have to maximize our transfer rate.
+		 */
+		unsigned long min_tx_time;
+		unsigned long max_tx_rate = hwa742.extif->get_max_tx_rate();
+
+		DBGPRINT(1, "max_tx_rate %ld HZ\n",
+			max_tx_rate);
+		min_tx_time = 1000000000 / (max_tx_rate / 1000);  /* ps */
+		if (hwa742.pix_tx_time < min_tx_time)
+			hwa742.pix_tx_time = min_tx_time;
+	}
+
+	/* time to update one line in ps */
+	hwa742.line_upd_time = (hdisp + hndp) * 1000000 / (pix_clk / 1000);
+	hwa742.line_upd_time *= 1000;
+	if (hdisp * hwa742.pix_tx_time > hwa742.line_upd_time)
+		/* transfer speed too low, we might have to use both
+		 * HS and VS */
+		use_hsvs = 1;
+	else
+		/* decent transfer speed, we'll always use only VS */
+		use_hsvs = 0;
+
+	if (use_hsvs && (hs_pol_inv || vs_pol_inv)) {
+		/* HS or'ed with VS doesn't work, use the active high
+		 * TE signal based on HNDP / VNDP */
+		use_ndp = 1;
+		hs_pol_inv = 0;
+		vs_pol_inv = 0;
+		hs = hndp;
+		vs = vndp;
+	} else {
+		/* Use HS or'ed with VS as a TE signal if both are needed
+		 * or VNDP if only vsync is needed. */
+		use_ndp = 0;
+		hs = hsw;
+		vs = vsw;
+		if (!use_hsvs) {
+			hs_pol_inv = 0;
+			vs_pol_inv = 0;
+		}
+	}
+
+	hs = hs * 1000000 / (pix_clk / 1000);			/* ps */
+	hs *= 1000;
+
+	vs = vs * (hdisp + hndp) * 1000000 / (pix_clk / 1000);	/* ps */
+	vs *= 1000;
+
+	if (vs <= hs)
+		return -EDOM;
+	/* set VS to 120% of HS to minimize VS detection time */
+	vs = hs * 12 / 10;
+	/* minimize HS too */
+	hs = 10000;
+
+	b = hwa742_read_reg(HWA742_NDP_CTRL);
+	b &= ~0x3;
+	b |= use_hsvs ? 1 : 0;
+	b |= (use_ndp && use_hsvs) ? 0 : 2;
+	hwa742_write_reg(HWA742_NDP_CTRL, b);
+
+	hwa742.vsync_only = !use_hsvs;
+
+	DBGPRINT(1,"pix_clk %ld HZ pix_tx_time %ld ps line_upd_time %ld ps\n",
+		pix_clk, hwa742.pix_tx_time, hwa742.line_upd_time);
+	DBGPRINT(1,"hs %d ps vs %d ps mode %d vsync_only %d\n",
+		hs, vs, (b & 0x3), !use_hsvs);
+
+	return hwa742.extif->setup_tearsync(1, hs, vs,
+					    hs_pol_inv, vs_pol_inv, extif_div);
+}
+
 static unsigned long hwa742_get_caps(void)
 {
-	return OMAPFB_CAPS_MANUAL_UPDATE;
+	unsigned long caps;
+
+	caps = OMAPFB_CAPS_MANUAL_UPDATE;
+	if (hwa742.te_connected)
+		caps |= OMAPFB_CAPS_TEARSYNC;
+	return caps;
 }
 
 static void hwa742_suspend(void)
@@ -840,21 +1066,15 @@
 	int r = 0, i;
 	u8 rev, conf;
 	unsigned long sysfreq;
-	int div, nd;
+	//int div, nd;
 
-	DBGENTER(1);
+	unsigned long sys_clk, pix_clk;
+	int extif_mem_div;
 
-	hwa742.sys_ck = clk_get(0, "bclk");
-	if (IS_ERR(hwa742.sys_ck)) {
-		pr_err("can't get SYS clock\n");
-		return PTR_ERR(hwa742.sys_ck);
-	}
+	struct omapfb_platform_data *omapfb_conf;
+	struct hwa742_platform_data *ctrl_conf;
 
-	if ((r = clk_enable(hwa742.sys_ck)) != 0) {
-		pr_err("can't enable SYS clock\n");
-		clk_put(hwa742.sys_ck);
-		return r;
-	}
+	DBGENTER(1);
 
 	BUG_ON(!fbdev->ext_if || !fbdev->int_ctrl);
 
@@ -862,27 +1082,51 @@
 	hwa742.extif = fbdev->ext_if;
 	hwa742.int_ctrl = fbdev->int_ctrl;
 
+	omapfb_conf = fbdev->dev->platform_data;
+#if 0
+	ctrl_conf = omapfb_conf->ctrl_platform_data;
+	if (ctrl_conf == NULL || ctrl_conf->get_clock_rate == NULL) {
+		pr_err( "HWA742: missing platform data\n");
+		r = -ENOENT;
+		goto err1;
+	}
+#endif
 	spin_lock_init(&hwa742.req_lock);
 
 	if ((r = hwa742.int_ctrl->init(fbdev, 1, req_vram_size)) < 0)
 		goto err1;
 
-	if ((r = hwa742.extif->init()) < 0)
+	if ((r = hwa742.extif->init(fbdev)) < 0)
 		goto err2;
 
 	hwa742_ctrl.get_vram_layout = hwa742.int_ctrl->get_vram_layout;
 	hwa742_ctrl.mmap = hwa742.int_ctrl->mmap;
 
+	hwa742.sys_ck = clk_get(0, "bclk");
+	if (IS_ERR(hwa742.sys_ck)) {
+		pr_err("can't get SYS clock\n");
+		//return PTR_ERR(hwa742.sys_ck);
+		goto err2;
+	}
+
 	sysfreq = clk_get_rate(hwa742.sys_ck);
-	if ((r = calc_extif_timings(sysfreq)) < 0)
+	if ((r = calc_extif_timings(sysfreq, &extif_mem_div)) < 0)
 		goto err3;
 	hwa742.extif->set_timings(&hwa742.reg_timings);
+	
+	if ((r = clk_enable(hwa742.sys_ck)) != 0) {
+		pr_err("can't enable SYS clock\n");
+		goto err3;
+	}
+
+	calc_hwa742_clk_rates(sysfreq, &sys_clk, &pix_clk);
 
+#if 0
 	div = (hwa742_read_reg(HWA742_PLL_DIV_REG) & 0x3f) + 1;
 
 	nd = (hwa742_read_reg(HWA742_PLL_4_REG) & 0x7f) + 1;
-
-	if ((r = calc_extif_timings(sysfreq / div * nd)) < 0)
+#endif
+	if ((r = calc_extif_timings(sys_clk, &extif_mem_div)) < 0)
 		goto err3;
 	hwa742.extif->set_timings(&hwa742.reg_timings);
 
@@ -893,15 +1137,19 @@
 		goto err3;
 	}
 
-	conf = hwa742_read_reg(HWA742_CONFIG_REG);
-	pr_info(MODULE_NAME ": Epson HWA742 LCD controller rev. %d "
-			"initialized (CNF pins %x)\n", rev, conf & 0x03);
 
 	if (!(hwa742_read_reg(HWA742_PLL_DIV_REG) & 0x80)) {
 		pr_err("controller not initialized by the bootloader\n");
 		r = -ENODEV;
 		goto err2;
 	}
+//	if (ctrl_conf->te_connected) {
+		if ((r = setup_tearsync(pix_clk, extif_mem_div)) < 0) {
+			pr_err("HWA742: can't setup tearing synchronization\n");
+			goto err3;
+		} else
+			hwa742.te_connected = 1;
+//	}
 
 	hwa742.max_transmit_size = hwa742.extif->max_transmit_size;
 
@@ -929,6 +1177,10 @@
 	BUG_ON(i <= IRQ_REQ_POOL_SIZE);
 	sema_init(&hwa742.req_sema, i - IRQ_REQ_POOL_SIZE);
 
+	conf = hwa742_read_reg(HWA742_CONFIG_REG);
+	pr_info(MODULE_NAME ": Epson HWA742 LCD controller rev. %d "
+			"initialized (CNF pins %x)\n", rev, conf & 0x03);
+
 	return 0;
 err3:
 	hwa742.extif->cleanup();
diff -Naur -X kernel-source-2.6.16-2.6.16.rel/Documentation/dontdiff kernel-source-2.6.16-2.6.16.rel/drivers/video/omap/omapfb_main.c kernel-source-2.6.16-2.6.16.my/drivers/video/omap/omapfb_main.c
--- kernel-source-2.6.16-2.6.16.rel/drivers/video/omap/omapfb_main.c	2007-05-30 21:38:59.000000000 +0200
+++ kernel-source-2.6.16-2.6.16.my/drivers/video/omap/omapfb_main.c	2007-05-01 14:19:47.000000000 +0200
@@ -76,6 +76,7 @@
         const char *name;
 } omapfb_caps_table[] = {
 	{ OMAPFB_CAPS_MANUAL_UPDATE, "manual update" },
+	{ OMAPFB_CAPS_TEARSYNC,      "tearing synchronization" },
 	{ OMAPFB_CAPS_SET_BACKLIGHT, "backlight setting" },
 };
 
diff -Naur -X kernel-source-2.6.16-2.6.16.rel/Documentation/dontdiff kernel-source-2.6.16-2.6.16.rel/drivers/video/omap/sossi.c kernel-source-2.6.16-2.6.16.my/drivers/video/omap/sossi.c
--- kernel-source-2.6.16-2.6.16.rel/drivers/video/omap/sossi.c	2008-04-07 09:52:45.000000000 +0200
+++ kernel-source-2.6.16-2.6.16.my/drivers/video/omap/sossi.c	2007-05-06 20:43:48.000000000 +0200
@@ -20,11 +20,11 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  */
-
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/mm.h>
 #include <linux/clk.h>
+#include <linux/interrupt.h>
 
 #include <asm/io.h>
 
@@ -33,10 +33,6 @@
 
 #include "lcdc.h"
 
-/* #define OMAPFB_DBG 1 */
-
-#include "debug.h"
-
 #define MODULE_NAME		"omapfb-sossi"
 
 #define OMAP_SOSSI_BASE         0xfffbac00
@@ -55,19 +51,25 @@
 #define DMA_LCD_CTRL      0xfffee3c4
 #define DMA_LCD_LCH_CTRL  0xfffee3ea
 
+#define CONF_SOSSI_RESET_R      (1 << 23)
+
 #define RD_ACCESS		0
 #define WR_ACCESS		1
 
 #define SOSSI_MAX_XMIT_BYTES	(512 * 1024)
 
-#define pr_err(fmt, args...) printk(KERN_ERR MODULE_NAME ": " fmt, ## args)
-
-static struct sossi {
-	int		base;
-	unsigned long	dpll_khz;
+static struct {
+	void __iomem	*base;
+	struct clk	*fck;
+	unsigned long	fck_hz;
+	spinlock_t	lock;
+	int		bus_pick_count;
 	int		bus_pick_width;
+	int		tearsync_mode;
+	int		tearsync_line;
 	void		(*lcdc_callback)(void *data);
 	void		*lcdc_callback_data;
+	int		vsync_dma_pending;
 	/* timing for read and write access */
 	int		clk_div;
 	u8		clk_tw0[2];
@@ -76,9 +78,9 @@
 	 * the timings
 	 */
 	int		last_access;
-} sossi;
 
-struct lcd_ctrl_extif sossi_extif;
+	struct omapfb_device	*fbdev;
+} sossi;
 
 static inline u32 sossi_read_reg(int reg)
 {
@@ -120,95 +122,11 @@
         sossi_write_reg(reg, sossi_read_reg(reg) & ~bits);
 }
 
-#define MOD_CONF_CTRL_1   0xfffe1110
-#define CONF_SOSSI_RESET_R      (1 << 23)
-#define CONF_MOD_SOSSI_CLK_EN_R (1 << 16)
-
-static void sossi_dma_callback(void *data);
-
-static int sossi_init(void)
-{
-	u32 l, k;
-	struct clk *dpll_clk;
-	int r;
-
-	sossi.base = IO_ADDRESS(OMAP_SOSSI_BASE);
-
-	dpll_clk = clk_get(NULL, "ck_dpll1");
-	if (IS_ERR(dpll_clk)) {
-		pr_err("can't get dpll1 clock\n");
-		return PTR_ERR(dpll_clk);
-	}
-
-	sossi.dpll_khz = clk_get_rate(dpll_clk) / 1000;
-	clk_put(dpll_clk);
-
-	sossi_extif.max_transmit_size = SOSSI_MAX_XMIT_BYTES;
-
-	/* Reset and enable the SoSSI module */
-	l = omap_readl(MOD_CONF_CTRL_1);
-	l |= CONF_SOSSI_RESET_R;
-	omap_writel(l, MOD_CONF_CTRL_1);
-	l &= ~CONF_SOSSI_RESET_R;
-	omap_writel(l, MOD_CONF_CTRL_1);
-
-	l |= CONF_MOD_SOSSI_CLK_EN_R;
-	omap_writel(l, MOD_CONF_CTRL_1);
-
-	omap_writel(omap_readl(ARM_IDLECT2) | (1 << 11), ARM_IDLECT2);
-	omap_writel(omap_readl(ARM_IDLECT1) | (1 << 6), ARM_IDLECT1);
-
-	l = sossi_read_reg(SOSSI_INIT2_REG);
-	/* Enable and reset the SoSSI block */
-	l |= (1 << 0) | (1 << 1);
-	sossi_write_reg(SOSSI_INIT2_REG, l);
-	/* Take SoSSI out of reset */
-	l &= ~(1 << 1);
-	sossi_write_reg(SOSSI_INIT2_REG, l);
-
-	sossi_write_reg(SOSSI_ID_REG, 0);
-	l = sossi_read_reg(SOSSI_ID_REG);
-	k = sossi_read_reg(SOSSI_ID_REG);
-
-	if (l != 0x55555555 || k != 0xaaaaaaaa) {
-		pr_err("Invalid SoSSI sync pattern: %08x, %08x\n", l, k);
-		return -ENODEV;
-	}
-
-	if ((r = omap_lcdc_set_dma_callback(sossi_dma_callback, NULL)) < 0) {
-		pr_err("can't get LCDC IRQ\n");
-		return r;
-	}
-
-	l = sossi_read_reg(SOSSI_ID_REG); /* Component code */
-	l = sossi_read_reg(SOSSI_ID_REG);
-	pr_info(MODULE_NAME ": version %d.%d initialized\n",
-			l >> 16, l & 0xffff);
-
-	l = sossi_read_reg(SOSSI_INIT1_REG);
-	l |= (1 << 19); /* DMA_MODE */
-	l &= ~(1 << 31); /* REORDERING */
-	sossi_write_reg(SOSSI_INIT1_REG, l);
-
-	return 0;
-}
-
-static void sossi_cleanup(void)
-{
-	omap_lcdc_free_dma_callback();
-}
-
-#define KHZ_TO_PS(x)	(1000000000 / (x))
-
-static void sossi_get_clk_info(u32 *clk_period, u32 *max_clk_div)
-{
-	*clk_period = KHZ_TO_PS(sossi.dpll_khz);
-	*max_clk_div = 8;
-}
+#define HZ_TO_PS(x)	(1000000000 / (x / 1000))
 
 static u32 ps_to_sossi_ticks(u32 ps, int div)
 {
-	u32 clk_period = KHZ_TO_PS(sossi.dpll_khz) * div;
+	u32 clk_period = HZ_TO_PS(sossi.fck_hz) * div;
 	return (clk_period + ps - 1) / clk_period;
 }
 
@@ -299,59 +217,48 @@
 	return 0;
 }
 
-static int sossi_convert_timings(struct extif_timings *t)
+static void _set_timing(int div, int tw0, int tw1)
 {
-	int r = 0;
-	int div = t->clk_div;
-
-	t->converted = 0;
-
-	if (div <= 0 || div > 8)
-		return -1;
-
-	/* no CS on SOSSI, so ignore cson, csoff, cs_pulsewidth */
-	if ((r = calc_rd_timings(t)) < 0)
-		return r;
-
-	if ((r = calc_wr_timings(t)) < 0)
-		return r;
-
-	t->tim[4] = div - 1;
+	u32 l;
 
-	t->converted = 1;
+#ifdef VERBOSE
+	dev_dbg(sossi.fbdev->dev, "Using TW0 = %d, TW1 = %d, div = %d\n",
+		 tw0 + 1, tw1 + 1, div);
+#endif
 
-	return 0;
+	clk_set_rate(sossi.fck, sossi.fck_hz / div);
+	clk_enable(sossi.fck);
+	l = sossi_read_reg(SOSSI_INIT1_REG);
+	l &= ~((0x0f << 20) | (0x3f << 24));
+	l |= (tw0 << 20) | (tw1 << 24);
+	sossi_write_reg(SOSSI_INIT1_REG, l);
+	clk_disable(sossi.fck);
 }
 
-static void sossi_set_timings(const struct extif_timings *t)
+static void _set_bits_per_cycle(int bus_pick_count, int bus_pick_width)
 {
-	BUG_ON(!t->converted);
-
-	sossi.clk_tw0[RD_ACCESS] = t->tim[0];
-	sossi.clk_tw1[RD_ACCESS] = t->tim[1];
-
-	sossi.clk_tw0[WR_ACCESS] = t->tim[2];
-	sossi.clk_tw1[WR_ACCESS] = t->tim[3];
+	u32 l;
 
-	sossi.clk_div = t->tim[4];
+	l = sossi_read_reg(SOSSI_INIT3_REG);
+	l &= ~0x3ff;
+	l |= ((bus_pick_count - 1) << 5) | ((bus_pick_width - 1) & 0x1f);
+	sossi_write_reg(SOSSI_INIT3_REG, l);
 }
 
-static void _set_timing(int div, int tw0, int tw1)
+static void _set_tearsync_mode(int mode, unsigned line)
 {
 	u32 l;
 
-	DBGPRINT(2, "Using TW0 = %d, TW1 = %d, div = %d\n",
-		 tw0 + 1, tw1 + 1, div + 1);
-
-	l = omap_readl(MOD_CONF_CTRL_1);
-	l &= ~(7 << 17);
-	l |= div << 17;
-	omap_writel(l, MOD_CONF_CTRL_1);
-
-	l = sossi_read_reg(SOSSI_INIT1_REG);
-	l &= ~((0x0f << 20) | (0x3f << 24));
-	l |= (tw0 << 20) | (tw1 << 24);
-	sossi_write_reg(SOSSI_INIT1_REG, l);
+	l = sossi_read_reg(SOSSI_TEARING_REG);
+	l &= ~(((1 << 11) - 1) << 15);
+	l |= line << 15;
+	l &= ~(0x3 << 26);
+	l |= mode << 26;
+	sossi_write_reg(SOSSI_TEARING_REG, l);
+	if (mode)
+		sossi_set_bits(SOSSI_INIT2_REG, 1 << 6);	/* TE logic */
+	else
+		sossi_clear_bits(SOSSI_INIT2_REG, 1 << 6);
 }
 
 static inline void set_timing(int access)
@@ -363,43 +270,12 @@
 	}
 }
 
-static void sossi_set_bits_per_cycle(int bpc)
-{
-	u32 l;
-	int bus_pick_count, bus_pick_width;
-
-	DBGPRINT(2, "bits_per_cycle %d\n", bpc);
-	/* We set explicitly the the bus_pick_count as well, although
-	 * with remapping/reordering disabled it will be calculated by HW
-	 * as (32 / bus_pick_width).
-	 */
-	switch (bpc) {
-	case 8:
-		bus_pick_count = 4;
-		bus_pick_width = 8;
-		break;
-	case 16:
-		bus_pick_count = 2;
-		bus_pick_width = 16;
-		break;
-	default:
-		BUG();
-		return;
-	}
-	l = sossi_read_reg(SOSSI_INIT3_REG);
-	sossi.bus_pick_width = bus_pick_width;
-	l &= ~0x3ff;
-	l |= ((bus_pick_count - 1) << 5) | ((bus_pick_width - 1) & 0x1f);
-	sossi_write_reg(SOSSI_INIT3_REG, l);
-}
-
 static void sossi_start_transfer(void)
 {
 	/* WE */
 	sossi_clear_bits(SOSSI_INIT2_REG, 1 << 4);
 	/* CS active low */
 	sossi_clear_bits(SOSSI_INIT1_REG, 1 << 30);
-	/* FIXME: locking? */
 }
 
 static void sossi_stop_transfer(void)
@@ -408,7 +284,6 @@
 	sossi_set_bits(SOSSI_INIT2_REG, 1 << 4);
 	/* CS active low */
 	sossi_set_bits(SOSSI_INIT1_REG, 1 << 30);
-	/* FIXME: locking? */
 }
 
 static void wait_end_of_write(void)
@@ -446,9 +321,143 @@
 	sossi_set_bits(SOSSI_INIT1_REG, (nr_cycles - 1) & 0x3ffff);
 }
 
+static int sossi_convert_timings(struct extif_timings *t)
+{
+	int r = 0;
+	int div = t->clk_div;
+
+	t->converted = 0;
+
+	if (div <= 0 || div > 8)
+		return -1;
+
+	/* no CS on SOSSI, so ignore cson, csoff, cs_pulsewidth */
+	if ((r = calc_rd_timings(t)) < 0)
+		return r;
+
+	if ((r = calc_wr_timings(t)) < 0)
+		return r;
+
+	t->tim[4] = div;
+
+	t->converted = 1;
+
+	return 0;
+}
+
+static void sossi_set_timings(const struct extif_timings *t)
+{
+	BUG_ON(!t->converted);
+
+	sossi.clk_tw0[RD_ACCESS] = t->tim[0];
+	sossi.clk_tw1[RD_ACCESS] = t->tim[1];
+
+	sossi.clk_tw0[WR_ACCESS] = t->tim[2];
+	sossi.clk_tw1[WR_ACCESS] = t->tim[3];
+
+	sossi.clk_div = t->tim[4];
+}
+
+static void sossi_get_clk_info(u32 *clk_period, u32 *max_clk_div)
+{
+	*clk_period = HZ_TO_PS(sossi.fck_hz);
+	*max_clk_div = 8;
+}
+
+static void sossi_set_bits_per_cycle(int bpc)
+{
+	int bus_pick_count, bus_pick_width;
+
+	/* We set explicitly the the bus_pick_count as well, although
+	 * with remapping/reordering disabled it will be calculated by HW
+	 * as (32 / bus_pick_width).
+	 */
+	switch (bpc) {
+	case 8:
+		bus_pick_count = 4;
+		bus_pick_width = 8;
+		break;
+	case 16:
+		bus_pick_count = 2;
+		bus_pick_width = 16;
+		break;
+	default:
+		BUG();
+		return;
+	}
+	sossi.bus_pick_width = bus_pick_width;
+	sossi.bus_pick_count = bus_pick_count;
+}
+
+static int sossi_setup_tearsync(unsigned pin_cnt,
+				unsigned hs_pulse_time, unsigned vs_pulse_time,
+				int hs_pol_inv, int vs_pol_inv, int div)
+{
+	int hs, vs;
+	u32 l;
+
+	if (pin_cnt != 1 || div < 1 || div > 8)
+		return -EINVAL;
+
+	hs = ps_to_sossi_ticks(hs_pulse_time, div);
+	vs = ps_to_sossi_ticks(vs_pulse_time, div);
+	if (vs < 8 || vs <= hs || vs >= (1 << 12))
+		return -EDOM;
+	vs /= 8;
+	vs--;
+	if (hs > 8)
+		hs = 8;
+	if (hs)
+		hs--;
+
+	dev_dbg(sossi.fbdev->dev,
+		"setup_tearsync: hs %d vs %d hs_inv %d vs_inv %d\n",
+		hs, vs, hs_pol_inv, vs_pol_inv);
+
+	clk_enable(sossi.fck);
+	l = sossi_read_reg(SOSSI_TEARING_REG);
+	l &= ~((1 << 15) - 1);
+	l |= vs << 3;
+	l |= hs;
+	if (hs_pol_inv)
+		l |= 1 << 29;
+	else
+		l &= ~(1 << 29);
+	if (vs_pol_inv)
+		l |= 1 << 28;
+	else
+		l &= ~(1 << 28);
+	sossi_write_reg(SOSSI_TEARING_REG, l);
+	clk_disable(sossi.fck);
+
+	return 0;
+}
+
+static int sossi_enable_tearsync(int enable, unsigned line)
+{
+	int mode;
+
+	dev_dbg(sossi.fbdev->dev, "tearsync %d line %d\n", enable, line);
+	if (line >= 1 << 11)
+		return -EINVAL;
+	if (enable) {
+		if (line)
+			mode = 2;		/* HS or VS */
+		else
+			mode = 3;		/* VS only */
+	} else
+		mode = 0;
+	sossi.tearsync_line = line;
+	sossi.tearsync_mode = mode;
+
+	return 0;
+}
+
 static void sossi_write_command(const void *data, unsigned int len)
 {
+	clk_enable(sossi.fck);
 	set_timing(WR_ACCESS);
+	_set_bits_per_cycle(sossi.bus_pick_count, sossi.bus_pick_width);
 	/* CMD#/DATA */
 	sossi_clear_bits(SOSSI_INIT1_REG, 1 << 18);
 	set_cycles(len);
@@ -456,11 +465,14 @@
 	send_data(data, len);
 	sossi_stop_transfer();
 	wait_end_of_write();
+	clk_disable(sossi.fck);
 }
 
 static void sossi_write_data(const void *data, unsigned int len)
 {
+	clk_enable(sossi.fck);
 	set_timing(WR_ACCESS);
+	_set_bits_per_cycle(sossi.bus_pick_count, sossi.bus_pick_width);
 	/* CMD#/DATA */
 	sossi_set_bits(SOSSI_INIT1_REG, 1 << 18);
 	set_cycles(len);
@@ -468,6 +480,7 @@
 	send_data(data, len);
 	sossi_stop_transfer();
 	wait_end_of_write();
+	clk_disable(sossi.fck);
 }
 
 static void sossi_transfer_area(int width, int height,
@@ -478,27 +491,44 @@
 	sossi.lcdc_callback = callback;
 	sossi.lcdc_callback_data = data;
 
+	clk_enable(sossi.fck);
 	set_timing(WR_ACCESS);
+	_set_bits_per_cycle(sossi.bus_pick_count, sossi.bus_pick_width);
+	_set_tearsync_mode(sossi.tearsync_mode, sossi.tearsync_line);
 	/* CMD#/DATA */
 	sossi_set_bits(SOSSI_INIT1_REG, 1 << 18);
 	set_cycles(width * height * sossi.bus_pick_width / 8);
 
-	DBGPRINT(2, "SOSSI_INIT1_REG %08x\n", sossi_read_reg(SOSSI_INIT1_REG));
-
 	sossi_start_transfer();
-	omap_enable_lcd_dma();
+	if (sossi.tearsync_mode) {
+		/* Wait for the sync signal and start the transfer only
+		 * then. We can't seem to be able to use HW sync DMA for
+		 * this since LCD DMA shows huge latencies, as if it
+		 * would ignore some of the DMA requests from SoSSI.
+		 */
+		unsigned long flags;
+
+		spin_lock_irqsave(&sossi.lock, flags);
+		sossi.vsync_dma_pending++;
+		spin_unlock_irqrestore(&sossi.lock, flags);
+	} else
+		/* Just start the transfer right away. */
+		omap_enable_lcd_dma();
 }
 
 static void sossi_dma_callback(void *data)
 {
 	omap_stop_lcd_dma();
 	sossi_stop_transfer();
+	clk_disable(sossi.fck);
 	sossi.lcdc_callback(sossi.lcdc_callback_data);
 }
 
 static void sossi_read_data(void *data, unsigned int len)
 {
+	clk_enable(sossi.fck);
 	set_timing(RD_ACCESS);
+	_set_bits_per_cycle(sossi.bus_pick_count, sossi.bus_pick_width);
 	/* CMD#/DATA */
 	sossi_set_bits(SOSSI_INIT1_REG, 1 << 18);
 	set_cycles(len);
@@ -519,6 +549,118 @@
 		data++;
 	}
 	sossi_stop_transfer();
+	clk_disable(sossi.fck);
+}
+
+static irqreturn_t sossi_match_irq(int irq, void *data, struct pt_regs *r)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&sossi.lock, flags);
+	if (sossi.vsync_dma_pending) {
+		sossi.vsync_dma_pending--;
+		omap_enable_lcd_dma();
+	}
+	spin_unlock_irqrestore(&sossi.lock, flags);
+	return IRQ_HANDLED;
+}
+
+static int sossi_init(struct omapfb_device *fbdev)
+{
+	u32 l, k;
+	struct clk *fck;
+	struct clk *dpll1out_ck;
+	int r;
+
+	sossi.base = (void __iomem *)IO_ADDRESS(OMAP_SOSSI_BASE);
+	sossi.fbdev = fbdev;
+	spin_lock_init(&sossi.lock);
+
+	dpll1out_ck = clk_get(fbdev->dev, "ck_dpll1out");
+	if (IS_ERR(dpll1out_ck)) {
+		dev_err(fbdev->dev, "can't get DPLL1OUT clock\n");
+		return PTR_ERR(dpll1out_ck);
+	}
+	/* We need the parent clock rate, which we might divide further
+	 * depending on the timing requirements of the controller. See
+	 * _set_timings.
+	 */
+	sossi.fck_hz = clk_get_rate(dpll1out_ck);
+	clk_put(dpll1out_ck);
+
+	fck = clk_get(fbdev->dev, "ck_sossi");
+	if (IS_ERR(fck)) {
+		dev_err(fbdev->dev, "can't get SoSSI functional clock\n");
+		return PTR_ERR(fck);
+	}
+	sossi.fck = fck;
+
+	/* Reset and enable the SoSSI module */
+	l = omap_readl(MOD_CONF_CTRL_1);
+	l |= CONF_SOSSI_RESET_R;
+	omap_writel(l, MOD_CONF_CTRL_1);
+	l &= ~CONF_SOSSI_RESET_R;
+	omap_writel(l, MOD_CONF_CTRL_1);
+
+	clk_enable(sossi.fck);
+	l = omap_readl(ARM_IDLECT2);
+	l &= ~(1 << 8);			/* DMACK_REQ */
+	omap_writel(l, ARM_IDLECT2);
+
+	l = sossi_read_reg(SOSSI_INIT2_REG);
+	/* Enable and reset the SoSSI block */
+	l |= (1 << 0) | (1 << 1);
+	sossi_write_reg(SOSSI_INIT2_REG, l);
+	/* Take SoSSI out of reset */
+	l &= ~(1 << 1);
+	sossi_write_reg(SOSSI_INIT2_REG, l);
+
+	sossi_write_reg(SOSSI_ID_REG, 0);
+	l = sossi_read_reg(SOSSI_ID_REG);
+	k = sossi_read_reg(SOSSI_ID_REG);
+
+	if (l != 0x55555555 || k != 0xaaaaaaaa) {
+		dev_err(fbdev->dev,
+			"invalid SoSSI sync pattern: %08x, %08x\n", l, k);
+		r = -ENODEV;
+		goto err;
+	}
+
+	if ((r = omap_lcdc_set_dma_callback(sossi_dma_callback, NULL)) < 0) {
+		dev_err(fbdev->dev, "can't get LCDC IRQ\n");
+		r = -ENODEV;
+		goto err;
+	}
+
+	l = sossi_read_reg(SOSSI_ID_REG); /* Component code */
+	l = sossi_read_reg(SOSSI_ID_REG);
+	dev_info(fbdev->dev, "SoSSI version %d.%d initialized\n",
+		l >> 16, l & 0xffff);
+
+	l = sossi_read_reg(SOSSI_INIT1_REG);
+	l |= (1 << 19); /* DMA_MODE */
+	l &= ~(1 << 31); /* REORDERING */
+	sossi_write_reg(SOSSI_INIT1_REG, l);
+
+	if ((r = request_irq(INT_SOSSI_MATCH, sossi_match_irq, IRQT_FALLING,
+	     "sossi_match", sossi.fbdev->dev)) < 0) {
+		dev_err(sossi.fbdev->dev, "can't get SoSSI match IRQ\n");
+		goto err;
+	}
+
+	clk_disable(sossi.fck);
+	return 0;
+
+err:
+	clk_disable(sossi.fck);
+	clk_put(sossi.fck);
+	return r;
+}
+
+static void sossi_cleanup(void)
+{
+	omap_lcdc_free_dma_callback();
+	clk_put(sossi.fck);
 }
 
 struct lcd_ctrl_extif sossi_extif = {
@@ -528,8 +670,13 @@
 	.convert_timings	= sossi_convert_timings,
 	.set_timings		= sossi_set_timings,
 	.set_bits_per_cycle	= sossi_set_bits_per_cycle,
+	.setup_tearsync		= sossi_setup_tearsync,
+	.enable_tearsync	= sossi_enable_tearsync,
 	.write_command		= sossi_write_command,
 	.read_data		= sossi_read_data,
 	.write_data		= sossi_write_data,
 	.transfer_area		= sossi_transfer_area,
+
+	.max_transmit_size	= SOSSI_MAX_XMIT_BYTES,
 };
+
diff -Naur -X kernel-source-2.6.16-2.6.16.rel/Documentation/dontdiff kernel-source-2.6.16-2.6.16.rel/include/asm-arm/arch-omap/irqs.h kernel-source-2.6.16-2.6.16.my/include/asm-arm/arch-omap/irqs.h
--- kernel-source-2.6.16-2.6.16.rel/include/asm-arm/arch-omap/irqs.h	2008-04-07 09:52:45.000000000 +0200
+++ kernel-source-2.6.16-2.6.16.my/include/asm-arm/arch-omap/irqs.h	2007-04-29 21:36:06.000000000 +0200
@@ -123,6 +123,7 @@
 #define INT_UART2		(15 + IH2_BASE)
 #define INT_BT_MCSI1TX		(16 + IH2_BASE)
 #define INT_BT_MCSI1RX		(17 + IH2_BASE)
+#define INT_SOSSI_MATCH         (19 + IH2_BASE)
 #define INT_USB_W2FC		(20 + IH2_BASE)
 #define INT_1WIRE		(21 + IH2_BASE)
 #define INT_OS_TIMER		(22 + IH2_BASE)
diff -Naur -X kernel-source-2.6.16-2.6.16.rel/Documentation/dontdiff kernel-source-2.6.16-2.6.16.rel/include/asm-arm/arch-omap/mux.h kernel-source-2.6.16-2.6.16.my/include/asm-arm/arch-omap/mux.h
--- kernel-source-2.6.16-2.6.16.rel/include/asm-arm/arch-omap/mux.h	2006-11-28 14:17:04.000000000 +0100
+++ kernel-source-2.6.16-2.6.16.my/include/asm-arm/arch-omap/mux.h	2008-04-05 21:04:15.000000000 +0200
@@ -395,6 +395,9 @@
 	V10_1610_CF_IREQ,
 	W10_1610_CF_RESET,
 	W11_1610_CF_CD1,
+
+	/* SOSSI tearing enabled*/
+	G20_SOSSI_TE,
 };
 
 enum omap24xx_index {
diff -Naur -X kernel-source-2.6.16-2.6.16.rel/Documentation/dontdiff kernel-source-2.6.16-2.6.16.rel/include/asm-arm/arch-omap/omapfb.h kernel-source-2.6.16-2.6.16.my/include/asm-arm/arch-omap/omapfb.h
--- kernel-source-2.6.16-2.6.16.rel/include/asm-arm/arch-omap/omapfb.h	2008-04-07 09:52:45.000000000 +0200
+++ kernel-source-2.6.16-2.6.16.my/include/asm-arm/arch-omap/omapfb.h	2007-05-01 13:48:41.000000000 +0200
@@ -50,11 +50,14 @@
 #define OMAPFB_CAPS_PANEL_MASK		0xff000000
 
 #define OMAPFB_CAPS_MANUAL_UPDATE	0x00001000
+#define OMAPFB_CAPS_TEARSYNC            0x00002000
 #define OMAPFB_CAPS_SET_BACKLIGHT	0x01000000
 
 /* Values from DSP must map to lower 16-bits */
 #define OMAPFB_FORMAT_MASK         0x00ff
 #define OMAPFB_FORMAT_FLAG_DOUBLE  0x0100
+#define OMAPFB_FORMAT_FLAG_TEARSYNC     0x0200
+#define OMAPFB_FORMAT_FLAG_FORCE_VSYNC  0x0400
 
 enum omapfb_color_format {
 	OMAPFB_COLOR_RGB565 = 0,
@@ -205,9 +208,10 @@
 };
 
 struct lcd_ctrl_extif {
-	int  (*init)		(void);
+	int  (*init)		(struct omapfb_device *fbdev);
 	void (*cleanup)		(void);
 	void (*get_clk_info)	(u32 *clk_period, u32 *max_clk_div);
+	unsigned long (*get_max_tx_rate)(void);
 	int  (*convert_timings)	(struct extif_timings *timings);
 	void (*set_timings)	(const struct extif_timings *timings);
 	void (*set_bits_per_cycle)(int bpc);
@@ -217,6 +221,12 @@
 	void (*transfer_area)	(int width, int height,
 				 void (callback)(void * data), void *data);
 	unsigned long		max_transmit_size;
+        int  (*setup_tearsync)  (unsigned pin_cnt,
+                                 unsigned hs_pulse_time, unsigned vs_pulse_time,
+                                  int hs_pol_inv, int vs_pol_inv, int div);
+	int  (*enable_tearsync) (int enable, unsigned line);
+										  
+										  
 };
 
 struct omapfb_notifier_block {
