diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c
index e32424c..0c259ab 100644
--- a/drivers/video/omap2/displays/panel-taal.c
+++ b/drivers/video/omap2/displays/panel-taal.c
@@ -28,7 +28,6 @@
 #include <linux/fb.h>
 #include <linux/interrupt.h>
 #include <linux/gpio.h>
-#include <linux/completion.h>
 #include <linux/workqueue.h>
 #include <linux/slab.h>
 #include <linux/mutex.h>
@@ -65,6 +64,8 @@
 /* #define TAAL_USE_ESD_CHECK */
 #define TAAL_ESD_CHECK_PERIOD	msecs_to_jiffies(5000)
 
+static irqreturn_t taal_te_isr(int irq, void *data);
+static void taal_te_timeout_work_callback(struct work_struct *work);
 static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable);
 
 struct taal_data {
@@ -85,7 +86,15 @@ struct taal_data {
 
 	bool te_enabled;
 	bool use_ext_te;
-	struct completion te_completion;
+
+	atomic_t do_update;
+	struct {
+		u16 x;
+		u16 y;
+		u16 w;
+		u16 h;
+	} update_region;
+	struct delayed_work te_timeout_work;
 
 	bool use_dsi_bl;
 
@@ -346,16 +355,6 @@ static void taal_get_resolution(struct omap_dss_device *dssdev,
 	}
 }
 
-static irqreturn_t taal_te_isr(int irq, void *data)
-{
-	struct omap_dss_device *dssdev = data;
-	struct taal_data *td = dev_get_drvdata(&dssdev->dev);
-
-	complete_all(&td->te_completion);
-
-	return IRQ_HANDLED;
-}
-
 static ssize_t taal_num_errors_show(struct device *dev,
 		struct device_attribute *attr, char *buf)
 {
@@ -545,6 +544,8 @@ static int taal_probe(struct omap_dss_device *dssdev)
 
 	mutex_init(&td->lock);
 
+	atomic_set(&td->do_update, 0);
+
 	td->esd_wq = create_singlethread_workqueue("taal_esd");
 	if (td->esd_wq == NULL) {
 		dev_err(&dssdev->dev, "can't create ESD workqueue\n");
@@ -606,9 +607,12 @@ static int taal_probe(struct omap_dss_device *dssdev)
 			goto err_irq;
 		}
 
-		init_completion(&td->te_completion);
+		INIT_DELAYED_WORK_DEFERRABLE(&td->te_timeout_work,
+					taal_te_timeout_work_callback);
 
 		td->use_ext_te = true;
+
+		dev_dbg(&dssdev->dev, "Using GPIO TE\n");
 	}
 
 	r = sysfs_create_group(&dssdev->dev.kobj, &taal_attr_group);
@@ -909,6 +913,47 @@ static void taal_framedone_cb(int err, void *data)
 	dsi_bus_unlock();
 }
 
+static irqreturn_t taal_te_isr(int irq, void *data)
+{
+	struct omap_dss_device *dssdev = data;
+	struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+	int old;
+	int r;
+
+	old = atomic_cmpxchg(&td->do_update, 1, 0);
+
+	if (old) {
+		cancel_delayed_work(&td->te_timeout_work);
+
+		r = omap_dsi_update(dssdev, TCH,
+				td->update_region.x,
+				td->update_region.y,
+				td->update_region.w,
+				td->update_region.h,
+				taal_framedone_cb, dssdev);
+		if (r)
+			goto err;
+	}
+
+	return IRQ_HANDLED;
+err:
+	dev_err(&dssdev->dev, "start update failed\n");
+	dsi_bus_unlock();
+	return IRQ_HANDLED;
+}
+
+static void taal_te_timeout_work_callback(struct work_struct *work)
+{
+	struct taal_data *td = container_of(work, struct taal_data,
+					te_timeout_work.work);
+	struct omap_dss_device *dssdev = td->dssdev;
+
+	dev_err(&dssdev->dev, "TE not received for 250ms!\n");
+
+	atomic_set(&td->do_update, 0);
+	dsi_bus_unlock();
+}
+
 static int taal_update(struct omap_dss_device *dssdev,
 				    u16 x, u16 y, u16 w, u16 h)
 {
@@ -933,10 +978,21 @@ static int taal_update(struct omap_dss_device *dssdev,
 	if (r)
 		goto err;
 
-	r = omap_dsi_update(dssdev, TCH, x, y, w, h,
-			taal_framedone_cb, dssdev);
-	if (r)
-		goto err;
+	if (td->te_enabled && td->use_ext_te) {
+		td->update_region.x = x;
+		td->update_region.y = y;
+		td->update_region.w = w;
+		td->update_region.h = h;
+		barrier();
+		schedule_delayed_work(&td->te_timeout_work,
+				msecs_to_jiffies(250));
+		atomic_set(&td->do_update, 1);
+	} else {
+		r = omap_dsi_update(dssdev, TCH, x, y, w, h,
+				taal_framedone_cb, dssdev);
+		if (r)
+			goto err;
+	}
 
 	/* note: no bus_unlock here. unlock is in framedone_cb */
 	mutex_unlock(&td->lock);
@@ -972,7 +1028,8 @@ static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable)
 	else
 		r = taal_dcs_write_0(DCS_TEAR_OFF);
 
-	omapdss_dsi_enable_te(dssdev, enable);
+	if (!td->use_ext_te)
+		omapdss_dsi_enable_te(dssdev, enable);
 
 	/* XXX for some reason, DSI TE breaks if we don't wait here.
 	 * Panel bug? Needs more studying */
