Merge remote branch 'origin/msm-3.0' into msm-3.4

* origin/msm-3.0: (87 commits)
  Revert "msm: kgsl: Add VBIF error detection"
  tspp: 8960: adding TSPP driver for 8960
  board-8960: Merge secure and non secure firmware heaps.
  msm: msm_dsps: Move to the new clk_prepare/unprepare API.
  diag: Protect SMD channel from getting NULL value
  camera: Mercury hardware JPEG decoder driver support.
  msm: 8064-regulator: Remove 5V FRC gpio external regulator
  diag: Respond to Get Subsystem Mask request
  Revert "msm_fb: display: Attach and detach MDP IOMMU on suspend/resume"
  Revert "msm_fb: display: Add MDP IOMMU detach support for DTV"
  msm: rpm-8930: Fix incorrect RPM enumeration and DMM
  msm: board-8930: Configure GPU turbo clock to 400MHz
  usb: mdm_bridge: Fix bug in handling error condition
  msm: vidc: Invalidate the cache before processing metadata.
  video: msm: wfd: Add turbo mode support
  tty: n_smux: Add Dedicated Power Control Queue
  defconfig: msm-copper: Enable SPI ethernet support
  msm: acpuclock-8960: Add PVS support on 8064
  ASoC: mdm9615: Set correct GPIOs for AUX PCM
  msm: 9615: Add auxpcm support over secondary audio interface
  ...

Conflicts:
	arch/arm/configs/msm-copper_defconfig
	drivers/char/diag/diagchar_core.c
	drivers/char/diag/diagfwd_hsic.h
	drivers/media/video/msm/msm_camera.c
	drivers/media/video/msm/msm_mctl.c
	drivers/mfd/Kconfig
	drivers/mfd/Makefile
	drivers/mfd/wcd9xxx-slimslave.c
	drivers/spmi/spmi.c
	drivers/tty/n_smux.c
	drivers/usb/otg/msm_otg.c
	sound/soc/msm/msm-pcm-routing.h

Signed-off-by: Steve Muckle <smuckle@codeaurora.org>
Change-Id: I49d4ceff17714a7ba51243de63f27b7e78647bda
diff --git a/drivers/char/diag/Kconfig b/drivers/char/diag/Kconfig
index 53df29b..8f8707f 100644
--- a/drivers/char/diag/Kconfig
+++ b/drivers/char/diag/Kconfig
@@ -32,10 +32,10 @@
 
 menu "HSIC support for DIAG"
 
-config DIAG_HSIC_PIPE
+config DIAG_BRIDGE_CODE
 	depends on USB_QCOM_DIAG_BRIDGE
 	default y
-	bool "Enable 9K DIAG traffic over HSIC"
+	bool "Enable QSC/9K DIAG traffic over SMUX/HSIC"
 	help
-	 HSIC Transport Layer for DIAG Router
+	 SMUX/HSIC Transport Layer for DIAG Router
 endmenu
diff --git a/drivers/char/diag/Makefile b/drivers/char/diag/Makefile
index 3181d29..ea75ffd 100644
--- a/drivers/char/diag/Makefile
+++ b/drivers/char/diag/Makefile
@@ -1,4 +1,5 @@
 obj-$(CONFIG_DIAG_CHAR) := diagchar.o
 obj-$(CONFIG_DIAG_SDIO_PIPE) += diagfwd_sdio.o
-obj-$(CONFIG_DIAG_HSIC_PIPE) += diagfwd_hsic.o
+obj-$(CONFIG_DIAG_BRIDGE_CODE) += diagfwd_hsic.o
+obj-$(CONFIG_DIAG_BRIDGE_CODE) += diagfwd_smux.o
 diagchar-objs := diagchar_core.o diagchar_hdlc.o diagfwd.o diagmem.o diagfwd_cntl.o diag_dci.o
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 49d687d..7e7b514 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -41,6 +41,7 @@
 #define SDIO_DATA		4
 #define WCNSS_DATA		5
 #define HSIC_DATA		6
+#define SMUX_DATA		7
 #define MODEM_PROC		0
 #define APPS_PROC		1
 #define QDSP_PROC		2
@@ -254,24 +255,30 @@
 	struct diag_request *usb_read_mdm_ptr;
 	struct diag_request *write_ptr_mdm;
 #endif
-#ifdef CONFIG_DIAG_HSIC_PIPE
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+	/* SGLTE variables */
+	int lcid;
+	unsigned char *buf_in_smux;
+	int in_busy_smux;
+	int diag_smux_enabled;
+	/* HSIC variables */
 	unsigned char *buf_in_hsic;
-	unsigned char *usb_buf_mdm_out;
-	int hsic_initialized;
 	int hsic_ch;
 	int hsic_device_enabled;
 	int hsic_device_opened;
 	int hsic_suspend;
-	int read_len_mdm;
 	int in_busy_hsic_read_on_device;
 	int in_busy_hsic_write_on_device;
 	int in_busy_hsic_write;
 	int in_busy_hsic_read;
-	int usb_mdm_connected;
-	struct usb_diag_ch *mdm_ch;
-	struct workqueue_struct *diag_hsic_wq;
-	struct work_struct diag_read_mdm_work;
 	struct work_struct diag_read_hsic_work;
+	/* USB MDM channel variables */
+	int usb_mdm_connected;
+	int read_len_mdm;
+	unsigned char *usb_buf_mdm_out;
+	struct usb_diag_ch *mdm_ch;
+	struct workqueue_struct *diag_bridge_wq;
+	struct work_struct diag_read_mdm_work;
 	struct work_struct diag_disconnect_work;
 	struct work_struct diag_usb_read_complete_work;
 	struct diag_request *usb_read_mdm_ptr;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 58a8676..d6a6e66 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -32,8 +32,9 @@
 #ifdef CONFIG_DIAG_SDIO_PIPE
 #include "diagfwd_sdio.h"
 #endif
-#ifdef CONFIG_DIAG_HSIC_PIPE
+#ifdef CONFIG_DIAG_BRIDGE_CODE
 #include "diagfwd_hsic.h"
+#include "diagfwd_smux.h"
 #endif
 #include <linux/timer.h>
 
@@ -234,9 +235,9 @@
 	if (driver->logging_process_id == current->tgid) {
 		driver->logging_mode = USB_MODE;
 		diagfwd_connect();
-#ifdef CONFIG_DIAG_HSIC_PIPE
+#ifdef CONFIG_DIAG_BRIDGE_CODE
 		diagfwd_cancel_hsic();
-		diagfwd_connect_hsic(0);
+		diagfwd_connect_bridge(0);
 #endif
 	}
 #endif /* DIAG over USB */
@@ -481,8 +482,8 @@
 #ifdef CONFIG_DIAG_SDIO_PIPE
 			driver->in_busy_sdio = 1;
 #endif
-#ifdef CONFIG_DIAG_HSIC_PIPE
-			diagfwd_disconnect_hsic(0);
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+			diagfwd_disconnect_bridge(0);
 #endif
 		} else if (temp == NO_LOGGING_MODE && driver->logging_mode
 							== MEMORY_DEVICE_MODE) {
@@ -509,22 +510,22 @@
 				queue_work(driver->diag_sdio_wq,
 					&(driver->diag_read_sdio_work));
 #endif
-#ifdef CONFIG_DIAG_HSIC_PIPE
-			diagfwd_connect_hsic(0);
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+			diagfwd_connect_bridge(0);
 #endif
 		}
 #ifdef CONFIG_DIAG_OVER_USB
 		else if (temp == USB_MODE && driver->logging_mode
 							 == NO_LOGGING_MODE) {
 			diagfwd_disconnect();
-#ifdef CONFIG_DIAG_HSIC_PIPE
-			diagfwd_disconnect_hsic(0);
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+			diagfwd_disconnect_bridge(0);
 #endif
 		} else if (temp == NO_LOGGING_MODE && driver->logging_mode
 								== USB_MODE) {
 			diagfwd_connect();
-#ifdef CONFIG_DIAG_HSIC_PIPE
-			diagfwd_connect_hsic(0);
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+			diagfwd_connect_bridge(0);
 #endif
 		} else if (temp == USB_MODE && driver->logging_mode
 							== MEMORY_DEVICE_MODE) {
@@ -552,16 +553,16 @@
 				queue_work(driver->diag_sdio_wq,
 					&(driver->diag_read_sdio_work));
 #endif
-#ifdef CONFIG_DIAG_HSIC_PIPE
+#ifdef CONFIG_DIAG_BRIDGE_CODE
 			diagfwd_cancel_hsic();
-			diagfwd_connect_hsic(0);
+			diagfwd_connect_bridge(0);
 #endif
 		} else if (temp == MEMORY_DEVICE_MODE &&
 				 driver->logging_mode == USB_MODE) {
 			diagfwd_connect();
-#ifdef CONFIG_DIAG_HSIC_PIPE
+#ifdef CONFIG_DIAG_BRIDGE_CODE
 			diagfwd_cancel_hsic();
-			diagfwd_connect_hsic(0);
+			diagfwd_connect_bridge(0);
 #endif
 		}
 #endif /* DIAG over USB */
@@ -720,7 +721,7 @@
 			driver->in_busy_sdio = 0;
 		}
 #endif
-#ifdef CONFIG_DIAG_HSIC_PIPE
+#ifdef CONFIG_DIAG_BRIDGE_CODE
 		pr_debug("diag: Copy data to user space %d\n",
 			 driver->in_busy_hsic_write_on_device);
 		if (driver->in_busy_hsic_write_on_device == 1) {
@@ -898,7 +899,7 @@
 			}
 		}
 #endif
-#ifdef CONFIG_DIAG_HSIC_PIPE
+#ifdef CONFIG_DIAG_BRIDGE_CODE
 		/* send masks to 9k too */
 		if (driver->hsic_ch && (payload_size > 0)) {
 			/* wait sending mask updates if HSIC ch not ready */
@@ -1199,6 +1200,18 @@
 inline void diag_sdio_fn(int type) {}
 #endif
 
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+void diag_bridge_fn(int type)
+{
+	if (type == INIT)
+		diagfwd_bridge_init();
+	else if (type == EXIT)
+		diagfwd_bridge_exit();
+}
+#else
+inline void diag_bridge_fn(int type) {}
+#endif
+
 static int __init diagchar_init(void)
 {
 	dev_t dev;
@@ -1243,9 +1256,7 @@
 		diagfwd_cntl_init();
 		driver->dci_state = diag_dci_init();
 		diag_sdio_fn(INIT);
-#ifdef CONFIG_DIAG_HSIC_PIPE
-		diagfwd_hsic_init();
-#endif
+		diag_bridge_fn(INIT);
 		pr_debug("diagchar initializing ..\n");
 		driver->num = 1;
 		driver->name = ((void *)driver) + sizeof(struct diagchar_dev);
@@ -1279,9 +1290,7 @@
 	diagfwd_exit();
 	diagfwd_cntl_exit();
 	diag_sdio_fn(EXIT);
-#ifdef CONFIG_DIAG_HSIC_PIPE
-	diagfwd_hsic_exit();
-#endif
+	diag_bridge_fn(EXIT);
 	return -1;
 }
 
@@ -1294,9 +1303,7 @@
 	diagfwd_exit();
 	diagfwd_cntl_exit();
 	diag_sdio_fn(EXIT);
-#ifdef CONFIG_DIAG_HSIC_PIPE
-	diagfwd_hsic_exit();
-#endif
+	diag_bridge_fn(EXIT);
 	diag_debugfs_cleanup();
 	diagchar_cleanup();
 	printk(KERN_INFO "done diagchar exit\n");
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 4ac2643..83d65b1 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -49,7 +49,7 @@
 unsigned char diag_debug_buf[1024];
 static unsigned int buf_tbl_size = 8; /*Number of entries in table of buffers */
 struct diag_master_table entry;
-smd_channel_t *ch_temp, *chqdsp_temp, *ch_wcnss_temp;
+smd_channel_t *ch_temp = NULL, *chqdsp_temp = NULL, *ch_wcnss_temp = NULL;
 int diag_event_num_bytes;
 int diag_event_config;
 struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
@@ -300,12 +300,12 @@
 				&(driver->diag_read_sdio_work));
 		}
 #endif
-#ifdef CONFIG_DIAG_HSIC_PIPE
+#ifdef CONFIG_DIAG_BRIDGE_CODE
 		else if (proc_num == HSIC_DATA) {
 			driver->in_busy_hsic_read = 0;
 			driver->in_busy_hsic_write_on_device = 0;
 			if (driver->hsic_ch)
-				queue_work(driver->diag_hsic_wq,
+				queue_work(driver->diag_bridge_wq,
 					&(driver->diag_read_hsic_work));
 		}
 #endif
@@ -352,7 +352,7 @@
 						"while USB write\n");
 		}
 #endif
-#ifdef CONFIG_DIAG_HSIC_PIPE
+#ifdef CONFIG_DIAG_BRIDGE_CODE
 		else if (proc_num == HSIC_DATA) {
 			if (driver->hsic_device_enabled) {
 				write_ptr->buf = buf;
@@ -360,6 +360,10 @@
 			} else
 				pr_err("diag: Incorrect hsic data "
 						"while USB write\n");
+		} else if (proc_num == SMUX_DATA) {
+				write_ptr->buf = buf;
+				pr_debug("diag: writing SMUX data\n");
+				err = usb_diag_write(driver->mdm_ch, write_ptr);
 		}
 #endif
 		APPEND_DEBUG('d');
@@ -922,8 +926,10 @@
 {
 	uint16_t subsys_cmd_code;
 	int subsys_id, ssid_first, ssid_last, ssid_range;
-	int packet_type = 1, i, cmd_code, rt_mask;
+	int packet_type = 1, i, cmd_code;
+	int rt_mask, rt_first_ssid, rt_last_ssid, rt_mask_size;
 	unsigned char *temp = buf;
+	uint8_t *rt_mask_ptr;
 	int data_type;
 #if defined(CONFIG_DIAG_OVER_USB)
 	int payload_length;
@@ -983,6 +989,38 @@
 			return 0;
 		}
 #endif
+	} /* Get runtime message mask  */
+	else if ((*buf == 0x7d) && (*(buf+1) == 0x3)) {
+		ssid_first = *(uint16_t *)(buf + 2);
+		ssid_last = *(uint16_t *)(buf + 4);
+#if defined(CONFIG_DIAG_OVER_USB)
+		if (!(driver->ch) && chk_apps_only()) {
+			driver->apps_rsp_buf[0] = 0x7d;
+			driver->apps_rsp_buf[1] = 0x3;
+			*(uint16_t *)(driver->apps_rsp_buf+2) = ssid_first;
+			*(uint16_t *)(driver->apps_rsp_buf+4) = ssid_last;
+			driver->apps_rsp_buf[6] = 0x1; /* Success Status */
+			driver->apps_rsp_buf[7] = 0x0;
+			rt_mask_ptr = driver->msg_masks;
+			while (*(uint32_t *)(rt_mask_ptr + 4)) {
+				rt_first_ssid = *(uint32_t *)rt_mask_ptr;
+				rt_mask_ptr += 4;
+				rt_last_ssid = *(uint32_t *)rt_mask_ptr;
+				rt_mask_ptr += 4;
+				if (ssid_first == rt_first_ssid && ssid_last ==
+								 rt_last_ssid) {
+					rt_mask_size = 4 * (rt_last_ssid -
+							 rt_first_ssid + 1);
+					memcpy(driver->apps_rsp_buf+8,
+						 rt_mask_ptr, rt_mask_size);
+					ENCODE_RSP_AND_SEND(8+rt_mask_size-1);
+					return 0;
+				}
+				ptr += MAX_SSID_PER_RANGE*4;
+			}
+		} else
+			buf = temp;
+#endif
 	} /* Set runtime message mask  */
 	else if ((*buf == 0x7d) && (*(buf+1) == 0x4)) {
 		ssid_first = *(uint16_t *)(buf + 2);
@@ -1695,7 +1733,8 @@
 		driver->ch = 0;
 		return;
 	} else if (event == SMD_EVENT_OPEN) {
-		driver->ch = ch_temp;
+		if (ch_temp)
+			driver->ch = ch_temp;
 	}
 	queue_work(driver->diag_wq, &(driver->diag_read_smd_work));
 }
@@ -1709,7 +1748,8 @@
 		driver->chqdsp = 0;
 		return;
 	} else if (event == SMD_EVENT_OPEN) {
-		driver->chqdsp = chqdsp_temp;
+		if (chqdsp_temp)
+			driver->chqdsp = chqdsp_temp;
 	}
 	queue_work(driver->diag_wq, &(driver->diag_read_smd_qdsp_work));
 }
@@ -1723,7 +1763,8 @@
 		driver->ch_wcnss = 0;
 		return;
 	} else if (event == SMD_EVENT_OPEN) {
-		driver->ch_wcnss = ch_wcnss_temp;
+		if (ch_wcnss_temp)
+			driver->ch_wcnss = ch_wcnss_temp;
 	}
 	queue_work(driver->diag_wq, &(driver->diag_read_smd_wcnss_work));
 }
diff --git a/drivers/char/diag/diagfwd_hsic.c b/drivers/char/diag/diagfwd_hsic.c
index a3c6f26..d54d3dc 100644
--- a/drivers/char/diag/diagfwd_hsic.c
+++ b/drivers/char/diag/diagfwd_hsic.c
@@ -19,6 +19,7 @@
 #include <linux/workqueue.h>
 #include <linux/pm_runtime.h>
 #include <linux/platform_device.h>
+#include <linux/smux.h>
 #include <asm/current.h>
 #ifdef CONFIG_DIAG_OVER_USB
 #include <mach/usbdiag.h>
@@ -28,6 +29,7 @@
 #include "diagchar.h"
 #include "diagfwd.h"
 #include "diagfwd_hsic.h"
+#include "diagfwd_smux.h"
 
 static void diag_read_hsic_work_fn(struct work_struct *work)
 {
@@ -71,7 +73,8 @@
 	 * the next read
 	 */
 	if (!driver->in_busy_hsic_read)
-		queue_work(driver->diag_hsic_wq, &driver->diag_read_hsic_work);
+		queue_work(driver->diag_bridge_wq,
+				 &driver->diag_read_hsic_work);
 }
 
 static void diag_hsic_read_complete_callback(void *ctxt, char *buf,
@@ -114,7 +117,8 @@
 	if (!driver->in_busy_hsic_write_on_device && ((driver->logging_mode
 			== MEMORY_DEVICE_MODE) || (driver->usb_mdm_connected &&
 						    !driver->hsic_suspend)))
-		queue_work(driver->diag_hsic_wq, &driver->diag_read_hsic_work);
+		queue_work(driver->diag_bridge_wq,
+				 &driver->diag_read_hsic_work);
 }
 
 static void diag_hsic_write_complete_callback(void *ctxt, char *buf,
@@ -132,7 +136,7 @@
 		pr_err("DIAG in %s: actual_size: %d\n", __func__, actual_size);
 
 	if (driver->usb_mdm_connected)
-		queue_work(driver->diag_hsic_wq, &driver->diag_read_mdm_work);
+		queue_work(driver->diag_bridge_wq, &driver->diag_read_mdm_work);
 }
 
 static int diag_hsic_suspend(void *ctxt)
@@ -157,7 +161,8 @@
 
 	if (!driver->in_busy_hsic_write_on_device && (driver->logging_mode
 			== MEMORY_DEVICE_MODE || driver->usb_mdm_connected))
-		queue_work(driver->diag_hsic_wq, &driver->diag_read_hsic_work);
+		queue_work(driver->diag_bridge_wq,
+			 &driver->diag_read_hsic_work);
 }
 
 static struct diag_bridge_ops hsic_diag_bridge_ops = {
@@ -209,42 +214,48 @@
 	return 0;
 }
 
-/* diagfwd_connect_hsic is called when the USB mdm channel is connected */
-int diagfwd_connect_hsic(int process_cable)
+/* diagfwd_connect_bridge is called when the USB mdm channel is connected */
+int diagfwd_connect_bridge(int process_cable)
 {
 	int err;
 
-	pr_debug("DIAG in %s\n", __func__);
+	pr_debug("diag: in %s\n", __func__);
 
 	/* If the usb cable is being connected */
 	if (process_cable) {
 		err = usb_diag_alloc_req(driver->mdm_ch, N_MDM_WRITE,
 			N_MDM_READ);
 		if (err)
-			pr_err("DIAG: unable to alloc USB req on mdm"
+			pr_err("diag: unable to alloc USB req on mdm"
 				" ch err:%d\n", err);
 
 		driver->usb_mdm_connected = 1;
 	}
 
-	driver->in_busy_hsic_write_on_device = 0;
-	driver->in_busy_hsic_read_on_device = 0;
-	driver->in_busy_hsic_write = 0;
-	driver->in_busy_hsic_read = 0;
+	if (driver->hsic_device_enabled) {
+		driver->in_busy_hsic_write_on_device = 0;
+		driver->in_busy_hsic_read_on_device = 0;
+		driver->in_busy_hsic_write = 0;
+		driver->in_busy_hsic_read = 0;
+	} else if (driver->diag_smux_enabled) {
+		driver->in_busy_smux = 0;
+		diagfwd_connect_smux();
+		return 0;
+	}
 
 	/* If the hsic (diag_bridge) platform device is not open */
 	if (driver->hsic_device_enabled) {
 		if (!driver->hsic_device_opened) {
 			err = diag_bridge_open(&hsic_diag_bridge_ops);
 			if (err) {
-				pr_err("DIAG: HSIC channel open error: %d\n",
+				pr_err("diag: HSIC channel open error: %d\n",
 					err);
 			} else {
-				pr_debug("DIAG: opened HSIC channel\n");
+				pr_debug("diag: opened HSIC channel\n");
 				driver->hsic_device_opened = 1;
 			}
 		} else {
-			pr_debug("DIAG: HSIC channel already open\n");
+			pr_debug("diag: HSIC channel already open\n");
 		}
 
 		/*
@@ -256,24 +267,25 @@
 
 		/* Poll USB mdm channel to check for data */
 		if (driver->logging_mode == USB_MODE)
-			queue_work(driver->diag_hsic_wq,
+			queue_work(driver->diag_bridge_wq,
 					&driver->diag_read_mdm_work);
 
 		/* Poll HSIC channel to check for data */
-		queue_work(driver->diag_hsic_wq, &driver->diag_read_hsic_work);
+		queue_work(driver->diag_bridge_wq,
+				 &driver->diag_read_hsic_work);
 	} else {
 		/* The hsic device driver has not yet been enabled */
-		pr_info("DIAG: HSIC channel not yet enabled\n");
+		pr_info("diag: HSIC channel not yet enabled\n");
 	}
 
 	return 0;
 }
 
 /*
- * diagfwd_disconnect_hsic is called when the USB mdm channel
+ * diagfwd_disconnect_bridge is called when the USB mdm channel
  * is disconnected
  */
-int diagfwd_disconnect_hsic(int process_cable)
+int diagfwd_disconnect_bridge(int process_cable)
 {
 	pr_debug("DIAG in %s\n", __func__);
 
@@ -284,12 +296,19 @@
 	}
 
 	if (driver->logging_mode != MEMORY_DEVICE_MODE) {
-		driver->in_busy_hsic_write_on_device = 1;
-		driver->in_busy_hsic_read_on_device = 1;
-		driver->in_busy_hsic_write = 1;
-		driver->in_busy_hsic_read = 1;
-		/* Turn off communication over usb mdm and hsic */
-		return diag_hsic_close();
+		if (driver->hsic_device_enabled) {
+			driver->in_busy_hsic_write_on_device = 1;
+			driver->in_busy_hsic_read_on_device = 1;
+			driver->in_busy_hsic_write = 1;
+			driver->in_busy_hsic_read = 1;
+			/* Turn off communication over usb mdm and hsic */
+			return diag_hsic_close();
+		} else if (driver->diag_smux_enabled) {
+			driver->in_busy_smux = 1;
+			driver->lcid = LCID_INVALID;
+			/* Turn off communication over usb mdm and smux */
+			msm_smux_close(LCID_VALID);
+		}
 	}
 	return 0;
 }
@@ -313,18 +332,23 @@
 	APPEND_DEBUG('q');
 
 	/* Read data from the hsic */
-	queue_work(driver->diag_hsic_wq, &driver->diag_read_hsic_work);
+	queue_work(driver->diag_bridge_wq, &driver->diag_read_hsic_work);
 
 	return 0;
 }
 
 /* Called after the asychronous usb_diag_read() on mdm channel is complete */
-static int diagfwd_read_complete_hsic(struct diag_request *diag_read_ptr)
+static int diagfwd_read_complete_bridge(struct diag_request *diag_read_ptr)
 {
 	/* The read of the usb driver on the mdm (not hsic) has completed */
 	driver->in_busy_hsic_read_on_device = 0;
 	driver->read_len_mdm = diag_read_ptr->actual;
 
+	if (driver->diag_smux_enabled) {
+		diagfwd_read_complete_smux();
+		return 0;
+	}
+	/* If SMUX not enabled, check for HSIC */
 	if (!driver->hsic_ch) {
 		pr_err("DIAG in %s: driver->hsic_ch == 0\n", __func__);
 		return 0;
@@ -366,30 +390,34 @@
 	 * hsic channel
 	 */
 	if (!driver->in_busy_hsic_write)
-		queue_work(driver->diag_hsic_wq, &driver->diag_read_mdm_work);
+		queue_work(driver->diag_bridge_wq, &driver->diag_read_mdm_work);
 
 	return 0;
 }
 
-static void diagfwd_hsic_notifier(void *priv, unsigned event,
+static void diagfwd_bridge_notifier(void *priv, unsigned event,
 					struct diag_request *d_req)
 {
 	switch (event) {
 	case USB_DIAG_CONNECT:
-		diagfwd_connect_hsic(1);
+		diagfwd_connect_bridge(1);
 		break;
 	case USB_DIAG_DISCONNECT:
-		queue_work(driver->diag_hsic_wq, &driver->diag_disconnect_work);
+		queue_work(driver->diag_bridge_wq,
+			 &driver->diag_disconnect_work);
 		break;
 	case USB_DIAG_READ_DONE:
-		queue_work(driver->diag_hsic_wq,
+		queue_work(driver->diag_bridge_wq,
 				&driver->diag_usb_read_complete_work);
 		break;
 	case USB_DIAG_WRITE_DONE:
-		diagfwd_write_complete_hsic();
+		if (driver->hsic_device_enabled)
+			diagfwd_write_complete_hsic();
+		else if (driver->diag_smux_enabled)
+			diagfwd_write_complete_smux();
 		break;
 	default:
-		pr_err("DIAG in %s: Unknown event from USB diag:%u\n",
+		pr_err("diag: in %s: Unknown event from USB diag:%u\n",
 			__func__, event);
 		break;
 	}
@@ -397,16 +425,33 @@
 
 static void diag_usb_read_complete_fn(struct work_struct *w)
 {
-	diagfwd_read_complete_hsic(driver->usb_read_mdm_ptr);
+	diagfwd_read_complete_bridge(driver->usb_read_mdm_ptr);
 }
 
 static void diag_disconnect_work_fn(struct work_struct *w)
 {
-	diagfwd_disconnect_hsic(1);
+	diagfwd_disconnect_bridge(1);
 }
 
 static void diag_read_mdm_work_fn(struct work_struct *work)
 {
+	int ret;
+	if (driver->diag_smux_enabled) {
+		if (driver->lcid && driver->usb_buf_mdm_out &&
+					 (driver->read_len_mdm > 0)) {
+			ret = msm_smux_write(driver->lcid,  NULL,
+		 driver->usb_buf_mdm_out, driver->read_len_mdm);
+			if (ret)
+				pr_err("diag: writing to SMUX ch, r = %d,"
+					"lcid = %d\n", ret, driver->lcid);
+		}
+		driver->usb_read_mdm_ptr->buf = driver->usb_buf_mdm_out;
+		driver->usb_read_mdm_ptr->length = USB_MAX_OUT_BUF;
+		usb_diag_read(driver->mdm_ch, driver->usb_read_mdm_ptr);
+		return;
+	}
+
+	/* if SMUX not enabled, check for HSIC */
 	if (!driver->hsic_ch) {
 		pr_err("DIAG in %s: driver->hsic_ch == 0\n", __func__);
 		return;
@@ -434,7 +479,8 @@
 	 * queue up the reading of data from the mdm channel
 	 */
 	if (!driver->in_busy_hsic_read_on_device)
-		queue_work(driver->diag_hsic_wq, &driver->diag_read_mdm_work);
+		queue_work(driver->diag_bridge_wq,
+			 &driver->diag_read_mdm_work);
 }
 
 static int diag_hsic_probe(struct platform_device *pdev)
@@ -442,31 +488,10 @@
 	int err = 0;
 	pr_debug("diag: in %s\n", __func__);
 	if (!driver->hsic_device_enabled) {
-		driver->read_len_mdm = 0;
 		if (driver->buf_in_hsic == NULL)
 			driver->buf_in_hsic = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
-		if (driver->buf_in_hsic == NULL)
-			goto err;
-		if (driver->usb_buf_mdm_out  == NULL)
-			driver->usb_buf_mdm_out = kzalloc(USB_MAX_OUT_BUF,
-								 GFP_KERNEL);
-		if (driver->usb_buf_mdm_out == NULL)
-			goto err;
-		if (driver->write_ptr_mdm == NULL)
-			driver->write_ptr_mdm = kzalloc(
-			sizeof(struct diag_request), GFP_KERNEL);
-		if (driver->write_ptr_mdm == NULL)
-			goto err;
-		if (driver->usb_read_mdm_ptr == NULL)
-			driver->usb_read_mdm_ptr = kzalloc(
-			sizeof(struct diag_request), GFP_KERNEL);
-		if (driver->usb_read_mdm_ptr == NULL)
-			goto err;
-#ifdef CONFIG_DIAG_OVER_USB
-		INIT_WORK(&(driver->diag_read_mdm_work), diag_read_mdm_work_fn);
-#endif
 		INIT_WORK(&(driver->diag_read_hsic_work),
-						 diag_read_hsic_work_fn);
+					 diag_read_hsic_work_fn);
 		driver->hsic_device_enabled = 1;
 	}
 
@@ -495,25 +520,16 @@
 
 		if (driver->usb_mdm_connected) {
 			/* Poll USB mdm channel to check for data */
-			queue_work(driver->diag_hsic_wq,
+			queue_work(driver->diag_bridge_wq,
 					 &driver->diag_read_mdm_work);
 		}
 
 		/* Poll HSIC channel to check for data */
-		queue_work(driver->diag_hsic_wq, &driver->diag_read_hsic_work);
+		queue_work(driver->diag_bridge_wq,
+				 &driver->diag_read_hsic_work);
 	}
 
 	return err;
-err:
-	pr_err("DIAG could not initialize buf for HSIC\n");
-	kfree(driver->buf_in_hsic);
-	kfree(driver->usb_buf_mdm_out);
-	kfree(driver->write_ptr_mdm);
-	kfree(driver->usb_read_mdm_ptr);
-	if (driver->diag_hsic_wq)
-		destroy_workqueue(driver->diag_hsic_wq);
-
-	return -ENOMEM;
 }
 
 static int diag_hsic_remove(struct platform_device *pdev)
@@ -550,55 +566,93 @@
 		   },
 };
 
-void diagfwd_hsic_init(void)
+void diagfwd_bridge_init(void)
 {
 	int ret;
 
-	pr_debug("DIAG in %s\n", __func__);
+	pr_debug("diag: in %s\n", __func__);
+	driver->diag_bridge_wq = create_singlethread_workqueue(
+							"diag_bridge_wq");
+	driver->read_len_mdm = 0;
+	if (driver->usb_buf_mdm_out  == NULL)
+		driver->usb_buf_mdm_out = kzalloc(USB_MAX_OUT_BUF,
+							 GFP_KERNEL);
+	if (driver->usb_buf_mdm_out == NULL)
+		goto err;
+	if (driver->write_ptr_mdm == NULL)
+		driver->write_ptr_mdm = kzalloc(
+		sizeof(struct diag_request), GFP_KERNEL);
+	if (driver->write_ptr_mdm == NULL)
+		goto err;
+	if (driver->usb_read_mdm_ptr == NULL)
+		driver->usb_read_mdm_ptr = kzalloc(
+		sizeof(struct diag_request), GFP_KERNEL);
+	if (driver->usb_read_mdm_ptr == NULL)
+		goto err;
 
-	driver->diag_hsic_wq = create_singlethread_workqueue("diag_hsic_wq");
+#ifdef CONFIG_DIAG_OVER_USB
+	INIT_WORK(&(driver->diag_read_mdm_work), diag_read_mdm_work_fn);
+#endif
 	INIT_WORK(&(driver->diag_disconnect_work), diag_disconnect_work_fn);
 	INIT_WORK(&(driver->diag_usb_read_complete_work),
 			diag_usb_read_complete_fn);
-
 #ifdef CONFIG_DIAG_OVER_USB
-	driver->mdm_ch = usb_diag_open(DIAG_MDM, driver, diagfwd_hsic_notifier);
+	driver->mdm_ch = usb_diag_open(DIAG_MDM, driver,
+						 diagfwd_bridge_notifier);
 	if (IS_ERR(driver->mdm_ch)) {
-		pr_err("DIAG Unable to open USB diag MDM channel\n");
+		pr_err("diag: Unable to open USB diag MDM channel\n");
 		goto err;
 	}
 #endif
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+	INIT_WORK(&(driver->diag_disconnect_work), diag_disconnect_work_fn);
+	INIT_WORK(&(driver->diag_usb_read_complete_work),
+			diag_usb_read_complete_fn);
+	/* register HSIC device */
 	ret = platform_driver_register(&msm_hsic_ch_driver);
 	if (ret)
-		pr_err("DIAG could not register HSIC device, ret: %d\n", ret);
-	else
-		driver->hsic_initialized = 1;
-
+		pr_err("diag: could not register HSIC device, ret: %d\n", ret);
+	/* register SMUX device */
+	ret = platform_driver_register(&msm_diagfwd_smux_driver);
+	if (ret)
+		pr_err("diag: could not register SMUX device, ret: %d\n", ret);
+#endif
 	return;
 err:
-	pr_err("DIAG could not initialize for HSIC execution\n");
-}
-
-void diagfwd_hsic_exit(void)
-{
-	pr_debug("DIAG in %s\n", __func__);
-
-	if (driver->hsic_initialized)
-		diag_hsic_close();
-
-#ifdef CONFIG_DIAG_OVER_USB
-	if (driver->usb_mdm_connected)
-		usb_diag_free_req(driver->mdm_ch);
-#endif
-	platform_driver_unregister(&msm_hsic_ch_driver);
-#ifdef CONFIG_DIAG_OVER_USB
-	usb_diag_close(driver->mdm_ch);
-#endif
-	kfree(driver->buf_in_hsic);
+	pr_err("diag: Could not initialize for bridge forwarding\n");
 	kfree(driver->usb_buf_mdm_out);
 	kfree(driver->write_ptr_mdm);
 	kfree(driver->usb_read_mdm_ptr);
-	destroy_workqueue(driver->diag_hsic_wq);
+	if (driver->diag_bridge_wq)
+		destroy_workqueue(driver->diag_bridge_wq);
 
-	driver->hsic_device_enabled = 0;
+	return;
+}
+
+void diagfwd_bridge_exit(void)
+{
+	pr_debug("diag: in %s\n", __func__);
+
+	if (driver->hsic_device_enabled) {
+		diag_hsic_close();
+		kfree(driver->buf_in_hsic);
+		driver->hsic_device_enabled = 0;
+	}
+	if (driver->diag_smux_enabled) {
+		driver->lcid = LCID_INVALID;
+		kfree(driver->buf_in_smux);
+		driver->diag_smux_enabled = 0;
+	}
+	platform_driver_unregister(&msm_hsic_ch_driver);
+	platform_driver_unregister(&msm_diagfwd_smux_driver);
+	/* destroy USB MDM specific variables */
+#ifdef CONFIG_DIAG_OVER_USB
+	if (driver->usb_mdm_connected)
+		usb_diag_free_req(driver->mdm_ch);
+	usb_diag_close(driver->mdm_ch);
+#endif
+	kfree(driver->usb_buf_mdm_out);
+	kfree(driver->write_ptr_mdm);
+	kfree(driver->usb_read_mdm_ptr);
+	destroy_workqueue(driver->diag_bridge_wq);
 }
diff --git a/drivers/char/diag/diagfwd_hsic.h b/drivers/char/diag/diagfwd_hsic.h
index a47ee26..b189c94 100644
--- a/drivers/char/diag/diagfwd_hsic.h
+++ b/drivers/char/diag/diagfwd_hsic.h
@@ -17,11 +17,11 @@
 #define N_MDM_WRITE	1 /* Upgrade to 2 with ping pong buffer */
 #define N_MDM_READ	1
 
-void __init diagfwd_hsic_init(void);
-int diagfwd_connect_hsic(int);
-int diagfwd_disconnect_hsic(int);
+int diagfwd_connect_bridge(int);
+int diagfwd_disconnect_bridge(int);
 int diagfwd_write_complete_hsic(void);
 int diagfwd_cancel_hsic(void);
-void diagfwd_hsic_exit(void);
+void diagfwd_bridge_init(void);
+void diagfwd_bridge_exit(void);
 
 #endif
diff --git a/drivers/char/diag/diagfwd_smux.c b/drivers/char/diag/diagfwd_smux.c
new file mode 100644
index 0000000..8bbc67e
--- /dev/null
+++ b/drivers/char/diag/diagfwd_smux.c
@@ -0,0 +1,156 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/termios.h>
+#include <linux/slab.h>
+#include <linux/diagchar.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <mach/usbdiag.h>
+#include "diagchar.h"
+#include "diagfwd.h"
+#include "diagfwd_smux.h"
+
+void diag_smux_event(void *priv, int event_type, const void *metadata)
+{
+	unsigned char *rx_buf;
+	int len;
+
+	switch (event_type) {
+	case SMUX_CONNECTED:
+		pr_debug("diag: SMUX_CONNECTED received\n");
+		driver->in_busy_smux = 0;
+		/* read data from USB MDM channel & Initiate first write */
+		queue_work(driver->diag_bridge_wq,
+				 &(driver->diag_read_mdm_work));
+		break;
+	case SMUX_DISCONNECTED:
+		pr_info("diag: SMUX_DISCONNECTED received\n");
+		break;
+	case SMUX_WRITE_DONE:
+		pr_debug("diag: SMUX Write done\n");
+		break;
+	case SMUX_WRITE_FAIL:
+		pr_info("diag: SMUX Write Failed\n");
+		break;
+	case SMUX_READ_FAIL:
+		pr_info("diag: SMUX Read Failed\n");
+		break;
+	case SMUX_READ_DONE:
+		len = ((struct smux_meta_read *)metadata)->len;
+		rx_buf = ((struct smux_meta_read *)metadata)->buffer;
+		driver->write_ptr_mdm->length = len;
+		diag_device_write(driver->buf_in_smux, SMUX_DATA,
+						 driver->write_ptr_mdm);
+		break;
+	};
+}
+
+int diagfwd_write_complete_smux(void)
+{
+	pr_debug("diag: clear in_busy_smux\n");
+	driver->in_busy_smux = 0;
+	return 0;
+}
+
+int diagfwd_read_complete_smux(void)
+{
+	queue_work(driver->diag_bridge_wq, &(driver->diag_read_mdm_work));
+	return 0;
+}
+
+int diag_get_rx_buffer(void *priv, void **pkt_priv, void **buffer, int size)
+{
+	if (!driver->in_busy_smux) {
+		*pkt_priv = (void *)0x1234;
+		*buffer = driver->buf_in_smux;
+		pr_debug("diag: set in_busy_smux as 1\n");
+		driver->in_busy_smux = 1;
+	} else {
+		pr_debug("diag: read buffer for SMUX is BUSY\n");
+		return -EAGAIN;
+	}
+	return 0;
+}
+
+static int diagfwd_smux_runtime_suspend(struct device *dev)
+{
+	dev_dbg(dev, "pm_runtime: suspending...\n");
+	return 0;
+}
+
+static int diagfwd_smux_runtime_resume(struct device *dev)
+{
+	dev_dbg(dev, "pm_runtime: resuming...\n");
+	return 0;
+}
+
+static const struct dev_pm_ops diagfwd_smux_dev_pm_ops = {
+	.runtime_suspend = diagfwd_smux_runtime_suspend,
+	.runtime_resume = diagfwd_smux_runtime_resume,
+};
+
+int diagfwd_connect_smux(void)
+{
+	void *priv = NULL;
+	int ret = 0;
+
+	if (driver->lcid == LCID_INVALID) {
+		ret = msm_smux_open(LCID_VALID, priv, diag_smux_event,
+						 diag_get_rx_buffer);
+		if (!ret) {
+			driver->lcid = LCID_VALID;
+			msm_smux_tiocm_set(driver->lcid, TIOCM_DTR, 0);
+			pr_info("diag: open SMUX ch, r = %d\n", ret);
+		} else {
+			pr_err("diag: failed to open SMUX ch, r = %d\n", ret);
+		}
+	}
+	/* Poll USB channel to check for data*/
+	queue_work(driver->diag_bridge_wq, &(driver->diag_read_mdm_work));
+	return ret;
+}
+
+static int diagfwd_smux_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+
+	pr_info("diag: SMUX probe called\n");
+	driver->lcid = LCID_INVALID;
+	driver->diag_smux_enabled = 1;
+	if (driver->buf_in_smux == NULL) {
+		driver->buf_in_smux = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
+		if (driver->buf_in_smux == NULL)
+			goto err;
+	}
+	/* Only required for Local loopback test
+	 * ret = msm_smux_set_ch_option(LCID_VALID,
+				 SMUX_CH_OPTION_LOCAL_LOOPBACK, 0);
+	 * if (ret)
+	 *	pr_err("diag: error setting SMUX ch option, r = %d\n", ret);
+	 */
+	ret = diagfwd_connect_smux();
+	return ret;
+
+err:
+	pr_err("diag: Could not initialize SMUX buffer\n");
+	kfree(driver->buf_in_smux);
+	return ret;
+}
+
+struct platform_driver msm_diagfwd_smux_driver = {
+	.probe = diagfwd_smux_probe,
+	.driver = {
+		   .name = "SMUX_DIAG",
+		   .owner = THIS_MODULE,
+		   .pm   = &diagfwd_smux_dev_pm_ops,
+		   },
+};
diff --git a/drivers/char/diag/diagfwd_smux.h b/drivers/char/diag/diagfwd_smux.h
new file mode 100644
index 0000000..e78b7ed
--- /dev/null
+++ b/drivers/char/diag/diagfwd_smux.h
@@ -0,0 +1,25 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef DIAGFWD_SMUX_H
+#define DIAGFWD_SMUX_H
+
+#include <linux/smux.h>
+#define LCID_VALID	SMUX_USB_DIAG_0
+#define LCID_INVALID	0
+
+int diagfwd_read_complete_smux(void);
+int diagfwd_write_complete_smux(void);
+int diagfwd_connect_smux(void);
+extern struct platform_driver msm_diagfwd_smux_driver;
+
+#endif
diff --git a/drivers/gpu/msm/a3xx_reg.h b/drivers/gpu/msm/a3xx_reg.h
index 35af06e..0a71982 100644
--- a/drivers/gpu/msm/a3xx_reg.h
+++ b/drivers/gpu/msm/a3xx_reg.h
@@ -248,10 +248,6 @@
 #define A3XX_VBIF_ARB_CTL 0x303C
 #define A3XX_VBIF_OUT_AXI_AOOO_EN 0x305E
 #define A3XX_VBIF_OUT_AXI_AOOO 0x305F
-#define A3XX_VBIF_ERR_PENDING  0x3064
-#define A3XX_VBIF_ERR_MASK 0x3066
-#define A3XX_VBIF_ERR_CLEAR 0x3067
-#define A3XX_VBIF_ERR_INFO 0x3068
 
 /* Bit flags for RBBM_CTL */
 #define RBBM_RBBM_CTL_RESET_PWR_CTR1  (1 << 1)
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 66baee1..6041cd8 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -254,7 +254,7 @@
 	int sizedwords = 0;
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 	struct kgsl_memdesc **reg_map_desc;
-	void *reg_map_array;
+	void *reg_map_array = NULL;
 	int num_iommu_units, i;
 
 	if (!adreno_dev->drawctxt_active)
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index 09eae17..1902f50 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -2336,39 +2336,6 @@
 	adreno_ringbuffer_submit(rb);
 }
 
-#define VBIF_MAX_CLIENTS 6
-
-static void a3xx_vbif_callback(struct adreno_device *adreno_dev,
-	unsigned int status)
-{
-	struct kgsl_device *device = &adreno_dev->dev;
-	int i;
-	char str[80], *ptr = str;
-	int slen = sizeof(str) - 1;
-
-	KGSL_DRV_INFO(device, "VBIF error | status=%X\n",
-		status);
-
-	for (i = 0; i < VBIF_MAX_CLIENTS; i++) {
-		if (status & (1 << i)) {
-			unsigned int err;
-			int ret;
-
-			adreno_regwrite(device, A3XX_VBIF_ERR_INFO, i);
-			adreno_regread(device, A3XX_VBIF_ERR_INFO, &err);
-
-			ret = snprintf(ptr, slen, "%d:%8.8X ", i, err);
-			ptr += ret;
-			slen -= ret;
-		}
-	}
-
-	KGSL_DRV_INFO(device, "%s\n", str);
-
-	/* Clear the errors */
-	adreno_regwrite(device, A3XX_VBIF_ERR_CLEAR, status);
-}
-
 static void a3xx_err_callback(struct adreno_device *adreno_dev, int bit)
 {
 	struct kgsl_device *device = &adreno_dev->dev;
@@ -2472,7 +2439,6 @@
 
 #define A3XX_INT_MASK \
 	((1 << A3XX_INT_RBBM_AHB_ERROR) |        \
-	 (1 << A3XX_INT_RBBM_REG_TIMEOUT) |      \
 	 (1 << A3XX_INT_RBBM_ATB_BUS_OVERFLOW) | \
 	 (1 << A3XX_INT_CP_T0_PACKET_IN_IB) |    \
 	 (1 << A3XX_INT_CP_OPCODE_ERROR) |       \
@@ -2545,15 +2511,6 @@
 	if (status)
 		adreno_regwrite(&adreno_dev->dev, A3XX_RBBM_INT_CLEAR_CMD,
 			status);
-
-	/* Check for VBIF errors */
-	adreno_regread(&adreno_dev->dev, A3XX_VBIF_ERR_PENDING, &status);
-
-	if (status) {
-		a3xx_vbif_callback(adreno_dev, status);
-		ret = IRQ_HANDLED;
-	}
-
 	return ret;
 }
 
@@ -2561,17 +2518,10 @@
 {
 	struct kgsl_device *device = &adreno_dev->dev;
 
-	if (state) {
+	if (state)
 		adreno_regwrite(device, A3XX_RBBM_INT_0_MASK, A3XX_INT_MASK);
-
-		/* Enable VBIF interrupts - write 0 to enable them all */
-		adreno_regwrite(device, A3XX_VBIF_ERR_MASK, 0);
-		/* Clear outstanding VBIF errors */
-		adreno_regwrite(device, A3XX_VBIF_ERR_CLEAR, 0x3F);
-	} else {
+	else
 		adreno_regwrite(device, A3XX_RBBM_INT_0_MASK, 0);
-		adreno_regwrite(device, A3XX_VBIF_ERR_MASK, 0xFFFFFFFF);
-	}
 }
 
 static unsigned int a3xx_busy_cycles(struct adreno_device *adreno_dev)
diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c
index a0907d7..5572695 100644
--- a/drivers/gpu/msm/adreno_snapshot.c
+++ b/drivers/gpu/msm/adreno_snapshot.c
@@ -674,6 +674,12 @@
 				adreno_find_ctxtmem(device, ptbase, ibaddr,
 					ibsize);
 
+			/* IOMMU uses a NOP IB placed in setsate memory */
+			if (NULL == memdesc)
+				if (kgsl_gpuaddr_in_memdesc(
+						&device->mmu.setstate_memory,
+						ibaddr, ibsize))
+					memdesc = &device->mmu.setstate_memory;
 			/*
 			 * The IB from CP_IB1_BASE and the IBs for legacy
 			 * context switch go into the snapshot all
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index ff9f0b8..5216b34 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -761,7 +761,7 @@
 		return 0;
 
 	spin_lock(&pt->lock);
-	if (pt->tlb_flags && (1<<id)) {
+	if (pt->tlb_flags & (1<<id)) {
 		result = KGSL_MMUFLAGS_TLBFLUSH;
 		pt->tlb_flags &= ~(1<<id);
 	}
diff --git a/drivers/media/video/msm/Kconfig b/drivers/media/video/msm/Kconfig
index 5d3a948..964218f 100644
--- a/drivers/media/video/msm/Kconfig
+++ b/drivers/media/video/msm/Kconfig
@@ -248,6 +248,12 @@
 	---help---
 	  Enable support for Gemini Jpeg Engine
 
+config MSM_MERCURY
+        tristate "Qualcomm MSM Mercury Jpeg Decoder Engine support"
+        depends on MSM_CAMERA && ARCH_MSM8960
+        ---help---
+          Enable support for Mercury Jpeg Engine
+
 config MSM_VPE
 	tristate "Qualcomm MSM Video Pre-processing Engine support"
 	depends on MSM_CAMERA && (ARCH_MSM7X30 || ARCH_MSM8X60)
diff --git a/drivers/media/video/msm/Makefile b/drivers/media/video/msm/Makefile
index e4d4081..67da5ea 100644
--- a/drivers/media/video/msm/Makefile
+++ b/drivers/media/video/msm/Makefile
@@ -18,7 +18,7 @@
 else
   obj-$(CONFIG_MSM_CAMERA) += msm_camera.o
 endif
-obj-$(CONFIG_MSM_CAMERA) += msm_axi_qos.o gemini/
+obj-$(CONFIG_MSM_CAMERA) += msm_axi_qos.o gemini/ mercury/
 obj-$(CONFIG_MSM_CAMERA_FLASH) += flash.o
 obj-$(CONFIG_ARCH_MSM_ARM11) += msm_vfe7x.o
 ifeq ($(CONFIG_MSM_CAMERA_V4L2),y)
diff --git a/drivers/media/video/msm/gemini/msm_gemini_platform.h b/drivers/media/video/msm/gemini/msm_gemini_platform.h
index 4542129..eb6b9f0 100644
--- a/drivers/media/video/msm/gemini/msm_gemini_platform.h
+++ b/drivers/media/video/msm/gemini/msm_gemini_platform.h
@@ -16,6 +16,7 @@
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/ion.h>
+#include <linux/iommu.h>
 void msm_gemini_platform_p2v(struct file  *file,
 				struct ion_handle **ionhandle);
 uint32_t msm_gemini_platform_v2p(int fd, uint32_t len, struct file **file,
diff --git a/drivers/media/video/msm/gemini/msm_gemini_sync.c b/drivers/media/video/msm/gemini/msm_gemini_sync.c
index fe7c99f..b55ec18 100644
--- a/drivers/media/video/msm/gemini/msm_gemini_sync.c
+++ b/drivers/media/video/msm/gemini/msm_gemini_sync.c
@@ -453,6 +453,7 @@
 {
 	struct msm_gemini_core_buf *buf_p;
 	struct msm_gemini_buf buf_cmd;
+	int rc = 0;
 
 	if (copy_from_user(&buf_cmd, arg, sizeof(struct msm_gemini_buf))) {
 		GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
@@ -469,17 +470,25 @@
 		(int) buf_cmd.vaddr, buf_cmd.y_len);
 
 	if (pgmn_dev->op_mode == MSM_GEMINI_MODE_REALTIME_ENCODE) {
-		buf_p->y_buffer_addr    = buf_cmd.y_off;
+		rc = msm_iommu_map_contig_buffer(
+			(unsigned long)buf_cmd.y_off, CAMERA_DOMAIN, GEN_POOL,
+			((buf_cmd.y_len + buf_cmd.cbcr_len + 4095) & (~4095)),
+			SZ_4K, IOMMU_WRITE | IOMMU_READ,
+			(unsigned long *)&buf_p->y_buffer_addr);
+		if (rc < 0) {
+			pr_err("%s iommu mapping failed with error %d\n",
+				 __func__, rc);
+			kfree(buf_p);
+			return rc;
+		}
 	} else {
 	buf_p->y_buffer_addr    = msm_gemini_platform_v2p(buf_cmd.fd,
 		buf_cmd.y_len + buf_cmd.cbcr_len, &buf_p->file,
 		&buf_p->handle)	+ buf_cmd.offset;
 	}
 	buf_p->y_len          = buf_cmd.y_len;
-
 	buf_p->cbcr_buffer_addr = buf_p->y_buffer_addr + buf_cmd.y_len;
 	buf_p->cbcr_len       = buf_cmd.cbcr_len;
-
 	buf_p->num_of_mcu_rows = buf_cmd.num_of_mcu_rows;
 	GMN_DBG("%s: y_addr=%x,y_len=%x,cbcr_addr=%x,cbcr_len=%x\n", __func__,
 		buf_p->y_buffer_addr, buf_p->y_len, buf_p->cbcr_buffer_addr,
diff --git a/drivers/media/video/msm/mercury/Makefile b/drivers/media/video/msm/mercury/Makefile
new file mode 100644
index 0000000..ce4c86d
--- /dev/null
+++ b/drivers/media/video/msm/mercury/Makefile
@@ -0,0 +1,3 @@
+GCC_VERSION      := $(shell $(CONFIG_SHELL) $(PWD)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc)
+EXTRA_CFLAGS += -Idrivers/media/video/msm
+obj-$(CONFIG_MSM_MERCURY) += msm_mercury_dev.o msm_mercury_core.o msm_mercury_hw.o msm_mercury_platform.o msm_mercury_sync.o
diff --git a/drivers/media/video/msm/mercury/msm_mercury_common.h b/drivers/media/video/msm/mercury/msm_mercury_common.h
new file mode 100644
index 0000000..f5939c1
--- /dev/null
+++ b/drivers/media/video/msm/mercury/msm_mercury_common.h
@@ -0,0 +1,24 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_MERCURY_COMMON_H
+#define MSM_MERCURY_COMMON_H
+
+#define MSM_MERCURY_DEBUG
+#ifdef MSM_MERCURY_DEBUG
+#define MCR_DBG(fmt, args...) pr_debug(fmt, ##args)
+#else
+#define MCR_DBG(fmt, args...) do { } while (0)
+#endif
+
+#define MCR_PR_ERR   pr_err
+#endif /* MSM_MERCURY_COMMON_H */
diff --git a/drivers/media/video/msm/mercury/msm_mercury_core.c b/drivers/media/video/msm/mercury/msm_mercury_core.c
new file mode 100644
index 0000000..a91c257
--- /dev/null
+++ b/drivers/media/video/msm/mercury/msm_mercury_core.c
@@ -0,0 +1,136 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <mach/clk.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
+#include "msm_mercury_hw.h"
+#include "msm_mercury_core.h"
+#include "msm_mercury_platform.h"
+#include "msm_mercury_common.h"
+
+static int reset_done_ack;
+static spinlock_t reset_lock;
+static wait_queue_head_t reset_wait;
+
+int mercury_core_reset(void)
+{
+	struct clk *clk = NULL;
+
+	/*Resettting MMSS Fabric*/
+
+	clk = clk_get(NULL, "jpegd_clk");
+
+	if (!IS_ERR(clk))
+		clk_enable(clk);
+
+	msm_bus_axi_porthalt(MSM_BUS_MASTER_JPEG_DEC);
+	clk_reset(clk, CLK_RESET_ASSERT);
+
+	/*need to have some delay here, there is no
+	 other way to know if hardware reset is complete*/
+	usleep_range(1000, 1200);
+
+	msm_bus_axi_portunhalt(MSM_BUS_MASTER_JPEG_DEC);
+	clk_reset(clk, CLK_RESET_DEASSERT);
+
+	return 0;
+}
+
+int msm_mercury_core_reset(void)
+{
+	unsigned long flags;
+	int rc = 0;
+	int tm = 500;/*500ms*/
+	MCR_DBG("\n%s\n(%d)%s()\n", __FILE__, __LINE__, __func__);
+
+	spin_lock_irqsave(&reset_lock, flags);
+	reset_done_ack = 0;
+	spin_unlock_irqrestore(&reset_lock, flags);
+
+	msm_mercury_hw_reset();
+	rc = wait_event_interruptible_timeout(reset_wait,
+		reset_done_ack,
+		msecs_to_jiffies(tm));
+
+	if (!reset_done_ack) {
+		MCR_DBG("%s: reset ACK failed %d", __func__, rc);
+		return -EBUSY;
+	}
+
+	MCR_DBG("(%d)%s() reset_done_ack rc %d\n\n", __LINE__, __func__, rc);
+	spin_lock_irqsave(&reset_lock, flags);
+	reset_done_ack = 0;
+	spin_unlock_irqrestore(&reset_lock, flags);
+
+	return 0;
+}
+
+void msm_mercury_core_init(void)
+{
+	init_waitqueue_head(&reset_wait);
+	spin_lock_init(&reset_lock);
+}
+
+static int (*msm_mercury_irq_handler) (int, void *, void *);
+
+irqreturn_t msm_mercury_core_irq(int irq_num, void *context)
+{
+	void *data = NULL;
+	unsigned long flags;
+	uint16_t mcr_rd_irq;
+	uint16_t mcr_wr_irq;
+	uint32_t jpeg_status;
+
+	MCR_DBG("\n(%d)%s() irq_number = %d", __LINE__, __func__, irq_num);
+
+	spin_lock_irqsave(&reset_lock, flags);
+	reset_done_ack = 1;
+	spin_unlock_irqrestore(&reset_lock, flags);
+
+	msm_mercury_hw_irq_get_status(&mcr_rd_irq, &mcr_wr_irq);
+	msm_mercury_hw_get_jpeg_status(&jpeg_status);
+	MCR_DBG("mercury_rd_irq = 0x%08X\n", mcr_rd_irq);
+	MCR_DBG("mercury_wr_irq = 0x%08X\n", mcr_wr_irq);
+	MCR_DBG("jpeg_status = 0x%08X\n", jpeg_status);
+	if (mcr_wr_irq & MSM_MERCURY_HW_IRQ_SW_RESET_ACK) {
+		MCR_DBG("*** SW Reset IRQ received ***\n");
+		wake_up(&reset_wait);
+		msm_mercury_hw_wr_irq_clear(MSM_MERCURY_HW_IRQ_SW_RESET_ACK);
+	}
+	if (mcr_wr_irq & MSM_MERCURY_HW_IRQ_WR_ERR_ACK) {
+		MCR_DBG("   *** Error IRQ received ***\n");
+		msm_mercury_irq_handler(MSM_MERCURY_HW_IRQ_WR_ERR_ACK,
+								context, data);
+	}
+	if (mcr_wr_irq & MSM_MERCURY_HW_IRQ_WR_EOI_ACK) {
+		MCR_DBG("   *** WE_EOI IRQ received ***\n");
+		msm_mercury_irq_handler(MSM_MERCURY_HW_IRQ_WR_EOI_ACK,
+								context, data);
+	}
+	return IRQ_HANDLED;
+}
+
+void msm_mercury_core_irq_install(int (*irq_handler) (int, void *, void *))
+{
+	msm_mercury_irq_handler = irq_handler;
+}
+
+void msm_mercury_core_irq_remove(void)
+{
+	msm_mercury_irq_handler = NULL;
+}
diff --git a/drivers/media/video/msm/mercury/msm_mercury_core.h b/drivers/media/video/msm/mercury/msm_mercury_core.h
new file mode 100644
index 0000000..e374cee
--- /dev/null
+++ b/drivers/media/video/msm/mercury/msm_mercury_core.h
@@ -0,0 +1,29 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_MERCURY_CORE_H
+#define MSM_MERCURY_CORE_H
+
+#include <linux/interrupt.h>
+#include "msm_mercury_hw.h"
+
+#define msm_mercury_core_buf msm_mercury_hw_buf
+
+irqreturn_t msm_mercury_core_irq(int irq_num, void *context);
+
+void msm_mercury_core_irq_install(int (*irq_handler) (int, void *, void *));
+void msm_mercury_core_irq_remove(void);
+
+int msm_mercury_core_reset(void);
+void msm_mercury_core_init(void);
+
+#endif /* MSM_MERCURY_CORE_H */
diff --git a/drivers/media/video/msm/mercury/msm_mercury_dev.c b/drivers/media/video/msm/mercury/msm_mercury_dev.c
new file mode 100644
index 0000000..df32b26
--- /dev/null
+++ b/drivers/media/video/msm/mercury/msm_mercury_dev.c
@@ -0,0 +1,256 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/uaccess.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <media/msm_mercury.h>
+#include <mach/board.h>
+#include "msm_mercury_sync.h"
+#include "msm_mercury_common.h"
+#include "msm.h"
+
+#define MSM_MERCURY_NAME "mercury"
+
+static int msm_mercury_open(struct inode *inode, struct file *filp)
+{
+	int rc;
+
+	struct msm_mercury_device *pmercury_dev = container_of(inode->i_cdev,
+		struct msm_mercury_device, cdev);
+	filp->private_data = pmercury_dev;
+
+	MCR_DBG("\n---(%d)%s()\n", __LINE__, __func__);
+
+	rc = __msm_mercury_open(pmercury_dev);
+
+	MCR_DBG("%s:%d] %s open_count = %d\n", __func__, __LINE__,
+		filp->f_path.dentry->d_name.name, pmercury_dev->open_count);
+
+	return rc;
+}
+
+static int msm_mercury_release(struct inode *inode, struct file *filp)
+{
+	int rc;
+
+	struct msm_mercury_device *pmercury_dev = filp->private_data;
+
+	MCR_DBG("\n---(%d)%s()\n", __LINE__, __func__);
+
+	rc = __msm_mercury_release(pmercury_dev);
+
+	MCR_DBG("%s:%d] %s open_count = %d\n", __func__, __LINE__,
+		filp->f_path.dentry->d_name.name, pmercury_dev->open_count);
+	return rc;
+}
+
+static long msm_mercury_ioctl(struct file *filp, unsigned int cmd,
+	unsigned long arg) {
+	int rc;
+	struct msm_mercury_device *pmercury_dev = filp->private_data;
+	rc = __msm_mercury_ioctl(pmercury_dev, cmd, arg);
+	return rc;
+}
+
+static const struct file_operations msm_mercury_fops = {
+	.owner     = THIS_MODULE,
+	.open    = msm_mercury_open,
+	.release = msm_mercury_release,
+	.unlocked_ioctl = msm_mercury_ioctl,
+};
+
+static struct class *msm_mercury_class;
+static dev_t msm_mercury_devno;
+static struct msm_mercury_device *msm_mercury_device_p;
+
+int msm_mercury_subdev_init(struct v4l2_subdev *mercury_sd)
+{
+	int rc;
+	struct msm_mercury_device *pgmn_dev =
+		(struct msm_mercury_device *)mercury_sd->host_priv;
+
+	MCR_DBG("%s:%d: mercury_sd=0x%x pgmn_dev=0x%x\n",
+		__func__, __LINE__, (uint32_t)mercury_sd, (uint32_t)pgmn_dev);
+	rc = __msm_mercury_open(pgmn_dev);
+	MCR_DBG("%s:%d: rc=%d\n",
+		__func__, __LINE__, rc);
+	return rc;
+}
+
+static long msm_mercury_subdev_ioctl(struct v4l2_subdev *sd,
+	unsigned int cmd, void *arg)
+{
+	long rc;
+	struct msm_mercury_device *pgmn_dev =
+		(struct msm_mercury_device *)sd->host_priv;
+
+	MCR_DBG("%s: cmd=%d\n", __func__, cmd);
+
+	MCR_DBG("%s: pgmn_dev 0x%x", __func__, (uint32_t)pgmn_dev);
+
+	MCR_DBG("%s: Calling __msm_mercury_ioctl\n", __func__);
+
+	rc = __msm_mercury_ioctl(pgmn_dev, cmd, (unsigned long)arg);
+	pr_debug("%s: X\n", __func__);
+	return rc;
+}
+
+void msm_mercury_subdev_release(struct v4l2_subdev *mercury_sd)
+{
+	int rc;
+	struct msm_mercury_device *pgmn_dev =
+		(struct msm_mercury_device *)mercury_sd->host_priv;
+	MCR_DBG("%s:pgmn_dev=0x%x", __func__, (uint32_t)pgmn_dev);
+	rc = __msm_mercury_release(pgmn_dev);
+	MCR_DBG("%s:rc=%d", __func__, rc);
+}
+
+static const struct v4l2_subdev_core_ops msm_mercury_subdev_core_ops = {
+	.ioctl = msm_mercury_subdev_ioctl,
+};
+
+static const struct v4l2_subdev_ops msm_mercury_subdev_ops = {
+	.core = &msm_mercury_subdev_core_ops,
+};
+
+static int msm_mercury_init(struct platform_device *pdev)
+{
+	int rc = -1;
+	struct device *dev;
+
+	MCR_DBG("%s:\n", __func__);
+	msm_mercury_device_p = __msm_mercury_init(pdev);
+	if (msm_mercury_device_p == NULL) {
+		MCR_PR_ERR("%s: initialization failed\n", __func__);
+		goto fail;
+	}
+
+	v4l2_subdev_init(&msm_mercury_device_p->subdev,
+		&msm_mercury_subdev_ops);
+	v4l2_set_subdev_hostdata(&msm_mercury_device_p->subdev,
+		msm_mercury_device_p);
+	pr_debug("%s: msm_mercury_device_p 0x%x", __func__,
+		(uint32_t)msm_mercury_device_p);
+	MCR_DBG("%s:mercury: platform_set_drvdata\n", __func__);
+	platform_set_drvdata(pdev, &msm_mercury_device_p->subdev);
+
+	rc = alloc_chrdev_region(&msm_mercury_devno, 0, 1, MSM_MERCURY_NAME);
+	if (rc < 0) {
+		MCR_PR_ERR("%s: failed to allocate chrdev\n", __func__);
+		goto fail_1;
+	}
+
+	if (!msm_mercury_class) {
+		msm_mercury_class = class_create(THIS_MODULE, MSM_MERCURY_NAME);
+		if (IS_ERR(msm_mercury_class)) {
+			rc = PTR_ERR(msm_mercury_class);
+			MCR_PR_ERR("%s: create device class failed\n",
+				__func__);
+			goto fail_2;
+		}
+	}
+
+	dev = device_create(msm_mercury_class, NULL,
+		MKDEV(MAJOR(msm_mercury_devno), MINOR(msm_mercury_devno)), NULL,
+		"%s%d", MSM_MERCURY_NAME, 0);
+
+	if (IS_ERR(dev)) {
+		MCR_PR_ERR("%s: error creating device\n", __func__);
+		rc = -ENODEV;
+		goto fail_3;
+	}
+
+	cdev_init(&msm_mercury_device_p->cdev, &msm_mercury_fops);
+	msm_mercury_device_p->cdev.owner = THIS_MODULE;
+	msm_mercury_device_p->cdev.ops   =
+		(const struct file_operations *) &msm_mercury_fops;
+	rc = cdev_add(&msm_mercury_device_p->cdev, msm_mercury_devno, 1);
+	if (rc < 0) {
+		MCR_PR_ERR("%s: error adding cdev\n", __func__);
+		rc = -ENODEV;
+		goto fail_4;
+	}
+
+	MCR_DBG("%s %s: success\n", __func__, MSM_MERCURY_NAME);
+
+	return rc;
+
+fail_4:
+	device_destroy(msm_mercury_class, msm_mercury_devno);
+
+fail_3:
+	class_destroy(msm_mercury_class);
+
+fail_2:
+	unregister_chrdev_region(msm_mercury_devno, 1);
+
+fail_1:
+	__msm_mercury_exit(msm_mercury_device_p);
+
+fail:
+	return rc;
+}
+
+static void msm_mercury_exit(void)
+{
+	cdev_del(&msm_mercury_device_p->cdev);
+	device_destroy(msm_mercury_class, msm_mercury_devno);
+	class_destroy(msm_mercury_class);
+	unregister_chrdev_region(msm_mercury_devno, 1);
+
+	__msm_mercury_exit(msm_mercury_device_p);
+}
+
+static int __msm_mercury_probe(struct platform_device *pdev)
+{
+	return msm_mercury_init(pdev);
+}
+
+static int __msm_mercury_remove(struct platform_device *pdev)
+{
+	msm_mercury_exit();
+	return 0;
+}
+
+static struct platform_driver msm_mercury_driver = {
+	.probe  = __msm_mercury_probe,
+	.remove = __msm_mercury_remove,
+	.driver = {
+		.name = MSM_MERCURY_DRV_NAME,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init msm_mercury_driver_init(void)
+{
+	int rc;
+	rc = platform_driver_register(&msm_mercury_driver);
+	return rc;
+}
+
+static void __exit msm_mercury_driver_exit(void)
+{
+	platform_driver_unregister(&msm_mercury_driver);
+}
+
+MODULE_DESCRIPTION("msm mercury jpeg driver");
+
+module_init(msm_mercury_driver_init);
+module_exit(msm_mercury_driver_exit);
diff --git a/drivers/media/video/msm/mercury/msm_mercury_hw.c b/drivers/media/video/msm/mercury/msm_mercury_hw.c
new file mode 100644
index 0000000..7bc4abe
--- /dev/null
+++ b/drivers/media/video/msm/mercury/msm_mercury_hw.c
@@ -0,0 +1,361 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include "msm_mercury_hw.h"
+#include "msm_mercury_common.h"
+#include "msm_mercury_hw_reg.h"
+#include "msm_mercury_macros.h"
+
+static void *mercury_region_base;
+static uint32_t mercury_region_size;
+
+
+void msm_mercury_hw_write(struct msm_mercury_hw_cmd *hw_cmd_p)
+{
+	uint32_t *paddr;
+	uint32_t old_data, new_data;
+
+	paddr = mercury_region_base + hw_cmd_p->offset;
+
+	if (hw_cmd_p->mask == 0xffffffff) {
+		old_data = 0;
+	} else {
+		old_data = readl_relaxed(paddr);
+		old_data &= ~hw_cmd_p->mask;
+	}
+
+	new_data = hw_cmd_p->data & hw_cmd_p->mask;
+	new_data |= old_data;
+	writel_relaxed(new_data, paddr);
+}
+
+uint32_t msm_mercury_hw_read(struct msm_mercury_hw_cmd *hw_cmd_p)
+{
+	uint32_t *paddr;
+	uint32_t data;
+
+	paddr = mercury_region_base + hw_cmd_p->offset;
+
+	data = readl_relaxed(paddr);
+	data &= hw_cmd_p->mask;
+
+	MCR_DBG("MERCURY_READ: offset=0x%04X data=0x%08X\n",
+		hw_cmd_p->offset, data);
+
+	return data;
+}
+
+void msm_mercury_hw_start_decode(void)
+{
+	struct msm_mercury_hw_cmd hw_cmd;
+
+	mercury_kread(JPEG_STATUS);
+	mercury_kread(RTDMA_JPEG_RD_STA_ACK);
+	mercury_kread(RTDMA_JPEG_WR_STA_ACK);
+	mercury_kread(RTDMA_JPEG_RD_BUF_Y_PNTR);
+	mercury_kread(RTDMA_JPEG_WR_BUF_Y_PNTR);
+	mercury_kread(RTDMA_JPEG_WR_BUF_U_PNTR);
+	mercury_kwrite(RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO, (7<<2));
+	return;
+}
+
+void msm_mercury_hw_bitstream_buf_cfg(uint32_t bitstream_buf_addr)
+{
+	struct msm_mercury_hw_cmd hw_cmd;
+
+	mercury_kwrite(RTDMA_JPEG_RD_BUF_Y_PNTR, bitstream_buf_addr);
+	return;
+}
+
+
+void msm_mercury_hw_output_y_buf_cfg(uint32_t y_buf_addr)
+{
+	struct msm_mercury_hw_cmd hw_cmd;
+
+	mercury_kwrite(RTDMA_JPEG_WR_BUF_Y_PNTR, y_buf_addr);
+	return;
+}
+
+void msm_mercury_hw_output_u_buf_cfg(uint32_t u_buf_addr)
+{
+	struct msm_mercury_hw_cmd hw_cmd;
+
+	mercury_kwrite(RTDMA_JPEG_WR_BUF_U_PNTR, u_buf_addr);
+	return;
+}
+
+void msm_mercury_hw_output_v_buf_cfg(uint32_t v_buf_addr)
+{
+	struct msm_mercury_hw_cmd hw_cmd;
+
+	mercury_kwrite(RTDMA_JPEG_WR_BUF_V_PNTR, v_buf_addr);
+	return;
+}
+
+int msm_mercury_hw_wait(struct msm_mercury_hw_cmd *hw_cmd_p, int m_us)
+{
+	int tm = hw_cmd_p->n;
+	uint32_t data;
+	uint32_t wait_data = hw_cmd_p->data & hw_cmd_p->mask;
+
+	data = msm_mercury_hw_read(hw_cmd_p);
+	if (data != wait_data) {
+		while (tm) {
+			udelay(m_us);
+			data = msm_mercury_hw_read(hw_cmd_p);
+			if (data == wait_data)
+				break;
+			tm--;
+		}
+	}
+	hw_cmd_p->data = data;
+	return tm;
+}
+
+void msm_mercury_hw_irq_get_status(uint16_t *rd_irq, uint16_t *wr_irq)
+{
+	struct msm_mercury_hw_cmd hw_cmd;
+	rmb();
+	mercury_kread(RTDMA_JPEG_RD_STA_ACK);
+	*rd_irq = hw_cmd.data;
+
+	mercury_kread(RTDMA_JPEG_WR_STA_ACK);
+	*wr_irq = hw_cmd.data;
+	rmb();
+}
+
+void msm_mercury_hw_get_jpeg_status(uint32_t *jpeg_status)
+{
+	struct msm_mercury_hw_cmd hw_cmd;
+
+	rmb();
+	mercury_kread(JPEG_STATUS);
+	*jpeg_status = hw_cmd.data;
+	rmb();
+}
+
+uint32_t msm_mercury_get_restartInterval(void)
+{
+	struct msm_mercury_hw_cmd hw_cmd;
+
+	rmb();
+	mercury_kread(JPEG_DRI);
+	rmb();
+	return hw_cmd.data;
+
+}
+
+void msm_mercury_hw_rd_irq_clear(uint32_t val)
+{
+	struct msm_mercury_hw_cmd hw_cmd;
+	mercury_kwrite(RTDMA_JPEG_RD_STA_ACK, val);
+}
+
+void msm_mercury_hw_wr_irq_clear(uint32_t val)
+{
+	struct msm_mercury_hw_cmd hw_cmd;
+
+	mercury_kwrite(RTDMA_JPEG_WR_STA_ACK, val);
+}
+
+void msm_mercury_hw_set_rd_irq_mask(uint32_t val)
+{
+	struct msm_mercury_hw_cmd hw_cmd;
+
+	mercury_kwrite(RTDMA_JPEG_RD_INT_EN, val);
+}
+
+void msm_mercury_hw_set_wr_irq_mask(uint32_t val)
+{
+	struct msm_mercury_hw_cmd hw_cmd;
+
+	mercury_kwrite(RTDMA_JPEG_WR_INT_EN, val);
+}
+
+void msm_mercury_set_jpeg_ctl_common(uint32_t val)
+{
+	struct msm_mercury_hw_cmd hw_cmd;
+
+	mercury_kwrite(JPEG_CTRL_COMMON, val);
+}
+
+void msm_mercury_hw_reset(void)
+{
+	uint32_t val;
+	struct msm_mercury_hw_cmd hw_cmd;
+
+	wmb();
+	/* disable all interrupts*/
+	mercury_kwrite(RTDMA_JPEG_RD_INT_EN, 0);
+
+	mercury_kwrite(RTDMA_JPEG_WR_INT_EN, 0);
+
+	/* clear pending interrupts*/
+	val = 0;
+	MEM_OUTF2(&val, RTDMA_JPEG_WR_STA_ACK,
+		SW_RESET_ABORT_RDY_ACK,
+		ERR_ACK, 1, 1);
+	MEM_OUTF2(&val, RTDMA_JPEG_WR_STA_ACK, EOF_ACK, SOF_ACK, 1, 1);
+	mercury_kwrite(RTDMA_JPEG_WR_STA_ACK, val);
+
+	val = 0;
+	MEM_OUTF2(&val, RTDMA_JPEG_RD_STA_ACK, EOF_ACK, SOF_ACK, 1, 1);
+	mercury_kwrite(RTDMA_JPEG_RD_STA_ACK, val);
+
+	/* enable SWResetAbortRdyInt for core reset*/
+	val = 0;
+	MEM_OUTF(&val, RTDMA_JPEG_WR_INT_EN, SW_RESET_ABORT_RDY_EN, 1);
+	mercury_kwrite(RTDMA_JPEG_WR_INT_EN, val);
+
+	/* Reset Core from MMSS Fabric*/
+	mercury_core_reset();
+
+	/* disable all interrupts*/
+	mercury_kwrite(RTDMA_JPEG_WR_INT_EN, 0);
+
+	/* clear pending interrupts*/
+	val = 0;
+	MEM_OUTF2(&val, RTDMA_JPEG_WR_STA_ACK,
+		SW_RESET_ABORT_RDY_ACK,
+		ERR_ACK, 1, 1);
+	MEM_OUTF2(&val, RTDMA_JPEG_WR_STA_ACK, EOF_ACK, SOF_ACK, 1, 1);
+	mercury_kwrite(RTDMA_JPEG_WR_STA_ACK, val);
+
+	val = 0;
+	MEM_OUTF2(&val, RTDMA_JPEG_RD_STA_ACK, EOF_ACK, SOF_ACK, 1, 1);
+	mercury_kwrite(RTDMA_JPEG_RD_STA_ACK, val);
+
+	/* enable neccessary interrupt source*/
+	val = 0;
+	MEM_OUTF2(&val, RTDMA_JPEG_WR_INT_EN, EOF_EN, ERR_EN, 1, 1);
+	MEM_OUTF(&val, RTDMA_JPEG_WR_INT_EN, SW_RESET_ABORT_RDY_EN, 1);
+	mercury_kwrite(RTDMA_JPEG_WR_INT_EN, val);
+
+	wmb();
+
+}
+
+void msm_mercury_hw_init(void *base, int size)
+{
+	mercury_region_base = base;
+	mercury_region_size = size;
+}
+
+
+void msm_mercury_hw_delay(struct msm_mercury_hw_cmd *hw_cmd_p, int m_us)
+{
+	int tm = hw_cmd_p->n;
+	while (tm) {
+		udelay(m_us);
+		tm--;
+	}
+}
+
+int msm_mercury_hw_exec_cmds(struct msm_mercury_hw_cmd *hw_cmd_p, int m_cmds)
+{
+	int is_copy_to_user = -1;
+	uint32_t data;
+	if (m_cmds > 1)
+		MCR_DBG("m_cmds = %d\n", m_cmds);
+
+	while (m_cmds--) {
+		if (hw_cmd_p->offset > mercury_region_size) {
+			MCR_PR_ERR("%s:%d] %d exceed hw region %d\n",
+					__func__, __LINE__, hw_cmd_p->offset,
+					mercury_region_size);
+			return -EFAULT;
+		}
+
+		switch (hw_cmd_p->type) {
+		case MSM_MERCURY_HW_CMD_TYPE_READ:
+			hw_cmd_p->data = msm_mercury_hw_read(hw_cmd_p);
+			is_copy_to_user = 1;
+			break;
+
+		case MSM_MERCURY_HW_CMD_TYPE_WRITE:
+			msm_mercury_hw_write(hw_cmd_p);
+			break;
+
+		case MSM_MERCURY_HW_CMD_TYPE_WRITE_OR:
+			data = msm_mercury_hw_read(hw_cmd_p);
+			hw_cmd_p->data = (hw_cmd_p->data & hw_cmd_p->mask) |
+				data;
+			msm_mercury_hw_write(hw_cmd_p);
+			break;
+
+		case MSM_MERCURY_HW_CMD_TYPE_UWAIT:
+			msm_mercury_hw_wait(hw_cmd_p, 1);
+			break;
+
+		case MSM_MERCURY_HW_CMD_TYPE_MWAIT:
+			msm_mercury_hw_wait(hw_cmd_p, 1000);
+			break;
+
+		case MSM_MERCURY_HW_CMD_TYPE_UDELAY:
+			msm_mercury_hw_delay(hw_cmd_p, 1);
+			break;
+
+		case MSM_MERCURY_HW_CMD_TYPE_MDELAY:
+			msm_mercury_hw_delay(hw_cmd_p, 1000);
+			break;
+
+		default:
+			MCR_DBG("wrong hw command type\n");
+			break;
+		}
+
+		hw_cmd_p++;
+	}
+	return is_copy_to_user;
+}
+
+void msm_mercury_hw_region_dump(int size)
+{
+	uint32_t *p;
+	uint8_t *p8;
+
+	MCR_DBG("(%d)%s()\n", __LINE__, __func__);
+	if (size > mercury_region_size)
+		MCR_DBG("%s:%d] wrong region dump size\n",
+			__func__, __LINE__);
+
+	p = (uint32_t *) mercury_region_base;
+	while (size >= 16) {
+		MCR_DBG("0x%08X] %08X %08X %08X %08X\n",
+			mercury_region_size - size,
+			readl_relaxed(p), readl_relaxed(p+1),
+			readl_relaxed(p+2), readl_relaxed(p+3));
+		p += 4;
+		size -= 16;
+	}
+
+	if (size > 0) {
+		uint32_t d;
+		MCR_DBG("0x%08X] ", mercury_region_size - size);
+		while (size >= 4) {
+			MCR_DBG("%08X ", readl_relaxed(p++));
+			size -= 4;
+		}
+
+		d = readl_relaxed(p);
+		p8 = (uint8_t *) &d;
+		while (size) {
+			MCR_DBG("%02X", *p8++);
+			size--;
+		}
+
+		MCR_DBG("\n");
+	}
+}
diff --git a/drivers/media/video/msm/mercury/msm_mercury_hw.h b/drivers/media/video/msm/mercury/msm_mercury_hw.h
new file mode 100644
index 0000000..f6e3e49
--- /dev/null
+++ b/drivers/media/video/msm/mercury/msm_mercury_hw.h
@@ -0,0 +1,70 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_MERCURY_HW_H
+#define MSM_MERCURY_HW_H
+
+#include <media/msm_mercury.h>
+
+/*number of pel per block (horiz/vert)*/
+#define JPEGDEC_BLOCK_SIZE                 (8)
+/* Hardware alignment*/
+#define JPEGDEC_HW_ALIGN                   (8)
+#define JPEGDEC_HW_SAMPLING_RATIO_MAX      (4)
+
+#define MSM_MERCURY_HW_IRQ_SW_RESET_ACK    (1<<3)
+#define MSM_MERCURY_HW_IRQ_WR_ERR_ACK      (1<<2)
+#define MSM_MERCURY_HW_IRQ_WR_EOI_ACK      (1<<1)
+#define MSM_MERCURY_HW_IRQ_WR_SOF_ACK      (1<<0)
+
+#define MSM_MERCURY_HW_IRQ_RD_EOF_ACK      (1<<1)
+#define MSM_MERCURY_HW_IRQ_RD_SOF_ACK      (1<<0)
+
+extern int mercury_core_reset(void);
+
+struct msm_mercury_hw_buf {
+		struct msm_mercury_buf vbuf;
+		struct file  *file;
+		uint32_t framedone_len;
+		uint32_t y_buffer_addr;
+		uint32_t y_len;
+		uint32_t cbcr_buffer_addr;
+		uint32_t cbcr_len;
+		uint32_t num_of_mcu_rows;
+		struct msm_mapped_buffer *msm_buffer;
+		int *subsystem_id;
+		struct ion_handle *handle;
+};
+
+
+void msm_mercury_hw_reset(void);
+void msm_mercury_hw_init(void *base, int size);
+void msm_mercury_hw_rd_irq_clear(uint32_t val);
+void msm_mercury_hw_wr_irq_clear(uint32_t val);
+
+uint32_t msm_mercury_hw_read(struct msm_mercury_hw_cmd *hw_cmd_p);
+void msm_mercury_hw_write(struct msm_mercury_hw_cmd *hw_cmd_p);
+int msm_mercury_hw_wait(struct msm_mercury_hw_cmd *hw_cmd_p, int m_us);
+void msm_mercury_hw_delay(struct msm_mercury_hw_cmd *hw_cmd_p, int m_us);
+int msm_mercury_hw_exec_cmds(struct msm_mercury_hw_cmd *hw_cmd_p, int m_cmds);
+void msm_mercury_hw_region_dump(int size);
+
+
+void msm_mercury_hw_irq_get_status(uint16_t *rd_irq, uint16_t *wr_irq);
+void msm_mercury_hw_start_decode(void);
+void msm_mercury_hw_get_jpeg_status(uint32_t *jpeg_status);
+void msm_mercury_hw_output_y_buf_cfg(uint32_t y_buf_addr);
+void msm_mercury_hw_output_u_buf_cfg(uint32_t u_buf_addr);
+void msm_mercury_hw_output_v_buf_cfg(uint32_t v_buf_addr);
+void msm_mercury_hw_bitstream_buf_cfg(uint32_t bitstream_buf_addr);
+
+#endif /* MSM_MERCURY_HW_H */
diff --git a/drivers/media/video/msm/mercury/msm_mercury_hw_reg.h b/drivers/media/video/msm/mercury/msm_mercury_hw_reg.h
new file mode 100644
index 0000000..671bc66
--- /dev/null
+++ b/drivers/media/video/msm/mercury/msm_mercury_hw_reg.h
@@ -0,0 +1,715 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_MERCURY_HW_REG_H
+#define MSM_MERCURY_HW_REG_H
+
+
+#define JPEGD_BASE  0x00000000
+
+/* Register ADDR, RMSK, and SHFT*/
+/* RW */
+#define JPEG_CTRL_COMMON                        JPEG_CTRL_COMMON
+#define HWIO_JPEG_CTRL_COMMON_ADDR            (JPEGD_BASE+0x00000000)
+#define HWIO_JPEG_CTRL_COMMON__POR                    0x00000000
+#define HWIO_JPEG_CTRL_COMMON__RMSK                   0x0000001F
+#define HWIO_JPEG_CTRL_COMMON__SHFT                            0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_CTRL_COMMON__JPEG_CTRL_COMMON_ZZ_OVERRIDE_EN__BMSK 0x00000010
+#define HWIO_JPEG_CTRL_COMMON__JPEG_CTRL_COMMON_ZZ_OVERRIDE_EN__SHFT          4
+#define HWIO_JPEG_CTRL_COMMON__JPEG_CTRL_COMMON_MODE__BMSK           0x0000000F
+#define HWIO_JPEG_CTRL_COMMON__JPEG_CTRL_COMMON_MODE__SHFT                    0
+
+/* Register Field FMSK and SHFT*/
+/* RW */
+#define JPEG_CTRL_ENCODE                     JPEG_CTRL_ENCODE
+#define HWIO_JPEG_CTRL_ENCODE_ADDR        (JPEGD_BASE+0x00000008)
+#define HWIO_JPEG_CTRL_ENCODE__POR                 0x00000000
+#define HWIO_JPEG_CTRL_ENCODE__RMSK                0x00000010
+#define HWIO_JPEG_CTRL_ENCODE__SHFT                         4
+/* Register Element MIN and MAX*/
+#define HWIO_JPEG_CTRL_ENCODE___S                           4
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_CTRL_ENCODE__JPEG_CTRL_ENCODE_EOI_MARKER_EN__BMSK  0x00000010
+#define HWIO_JPEG_CTRL_ENCODE__JPEG_CTRL_ENCODE_EOI_MARKER_EN__SHFT           4
+
+/* Register Field FMSK and SHFT*/
+#define JPEG_STATUS                        JPEG_STATUS
+#define HWIO_JPEG_STATUS_ADDR        (JPEGD_BASE+0x00000010)
+#define HWIO_JPEG_STATUS__POR               0x00000000
+#define HWIO_JPEG_STATUS__RMSK              0x00003FF0
+#define HWIO_JPEG_STATUS__SHFT                       4
+/* Register Element MIN and MAX*/
+#define HWIO_JPEG_STATUS___S                         4
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_STATUS__JPEG_STATUS_REGISTER_TIMEOUT__BMSK       0x00002000
+#define HWIO_JPEG_STATUS__JPEG_STATUS_REGISTER_TIMEOUT__SHFT               13
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_EOI__BMSK               0x00001000
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_EOI__SHFT                       12
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_UNESCAPED_FF__BMSK  0x00000800
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_UNESCAPED_FF__SHFT          11
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_INV_HUFFCODE__BMSK  0x00000400
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_INV_HUFFCODE__SHFT          10
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_INV_MARKER__BMSK    0x00000200
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_INV_MARKER__SHFT             9
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_RSTRT_SEQ__BMSK     0x00000100
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_RSTRT_SEQ__SHFT              8
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_RSTRT_OVRFLW__BMSK  0x00000080
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_RSTRT_OVRFLW__SHFT           7
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_RSTRT_UNDFLW__BMSK  0x00000040
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_RSTRT_UNDFLW__SHFT           6
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_SCAN_OVRFLW__BMSK   0x00000020
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_SCAN_OVRFLW__SHFT            5
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_SCAN_UNDFLW__BMSK   0x00000010
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_SCAN_UNDFLW__SHFT            4
+
+/* Register ADDR, RMSK, and SHFT*/
+/* R */
+#define JPEG_SOF_REG_0                               JPEG_SOF_REG_0
+#define HWIO_JPEG_SOF_REG_0_ADDR  /* RW */               (JPEGD_BASE+0x00000014)
+#define HWIO_JPEG_SOF_REG_0__POR                         0x00000000
+#define HWIO_JPEG_SOF_REG_0__RMSK                        0x000000FF
+#define HWIO_JPEG_SOF_REG_0__SHFT                                 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_SOF_REG_0__JPEG_SOF_REG_0_NF__BMSK     0x000000FF
+#define HWIO_JPEG_SOF_REG_0__JPEG_SOF_REG_0_NF__SHFT              0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_SOF_REG_1                               JPEG_SOF_REG_1
+#define HWIO_JPEG_SOF_REG_1_ADDR  /* RW */               (JPEGD_BASE+0x00000018)
+#define HWIO_JPEG_SOF_REG_1__POR                         0x00000000
+#define HWIO_JPEG_SOF_REG_1__RMSK                        0x00FFFFFF
+#define HWIO_JPEG_SOF_REG_1__SHFT                                 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_SOF_REG_1__JPEG_SOF_REG_1_C__BMSK      0x00FF0000
+#define HWIO_JPEG_SOF_REG_1__JPEG_SOF_REG_1_C__SHFT              16
+#define HWIO_JPEG_SOF_REG_1__JPEG_SOF_REG_1_H__BMSK      0x0000F000
+#define HWIO_JPEG_SOF_REG_1__JPEG_SOF_REG_1_H__SHFT              12
+#define HWIO_JPEG_SOF_REG_1__JPEG_SOF_REG_1_V__BMSK      0x00000F00
+#define HWIO_JPEG_SOF_REG_1__JPEG_SOF_REG_1_V__SHFT               8
+#define HWIO_JPEG_SOF_REG_1__JPEG_SOF_REG_1_TQ__BMSK     0x000000FF
+#define HWIO_JPEG_SOF_REG_1__JPEG_SOF_REG_1_TQ__SHFT              0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_SOF_REG_2                               JPEG_SOF_REG_2
+#define HWIO_JPEG_SOF_REG_2_ADDR  /* RW */               (JPEGD_BASE+0x0000001C)
+#define HWIO_JPEG_SOF_REG_2__POR                         0x00000000
+#define HWIO_JPEG_SOF_REG_2__RMSK                        0xFFFFFFFF
+#define HWIO_JPEG_SOF_REG_2__SHFT                                 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_SOF_REG_2__JPEG_SOF_REG_2_Y__BMSK      0xFFFF0000
+#define HWIO_JPEG_SOF_REG_2__JPEG_SOF_REG_2_Y__SHFT              16
+#define HWIO_JPEG_SOF_REG_2__JPEG_SOF_REG_2_X__BMSK      0x0000FFFF
+#define HWIO_JPEG_SOF_REG_2__JPEG_SOF_REG_2_X__SHFT               0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_SOS_REG_0                               JPEG_SOS_REG_0
+#define HWIO_JPEG_SOS_REG_0_ADDR  /* RW */               (JPEGD_BASE+0x00000020)
+#define HWIO_JPEG_SOS_REG_0__POR                         0x00000000
+#define HWIO_JPEG_SOS_REG_0__RMSK                        0xFF000000
+#define HWIO_JPEG_SOS_REG_0__SHFT                                24
+/*Register Element MIN and MAX*/
+#define HWIO_JPEG_SOS_REG_0___S                                  24
+#define HWIO_JPEG_SOS_REG_0___S                                  24
+#define HWIO_JPEG_SOS_REG_0___S                                  24
+#define HWIO_JPEG_SOS_REG_0___S                                  24
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_SOS_REG_0__JPEG_SOS_REG_0_NS__BMSK       0xFF000000
+#define HWIO_JPEG_SOS_REG_0__JPEG_SOS_REG_0_NS__SHFT               24
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_SOS_REG_1                                   JPEG_SOS_REG_1
+#define HWIO_JPEG_SOS_REG_1_ADDR  /* RW */              (JPEGD_BASE+0x00000024)
+#define HWIO_JPEG_SOS_REG_1__POR                        0x00000000
+#define HWIO_JPEG_SOS_REG_1__RMSK                       0x0000FFFF
+#define HWIO_JPEG_SOS_REG_1__SHFT                                0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_SOS_REG_1__JPEG_SOS_REG_1_CS__BMSK    0x0000FF00
+#define HWIO_JPEG_SOS_REG_1__JPEG_SOS_REG_1_CS__SHFT             8
+#define HWIO_JPEG_SOS_REG_1__JPEG_SOS_REG_1_TD__BMSK    0x000000F0
+#define HWIO_JPEG_SOS_REG_1__JPEG_SOS_REG_1_TD__SHFT             4
+#define HWIO_JPEG_SOS_REG_1__JPEG_SOS_REG_1_TA__BMSK    0x0000000F
+#define HWIO_JPEG_SOS_REG_1__JPEG_SOS_REG_1_TA__SHFT             0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_QT_IDX                                       JPEG_QT_IDX
+#define HWIO_JPEG_QT_IDX_ADDR       (JPEGD_BASE+0x00000030)
+#define HWIO_JPEG_QT_IDX__POR                              0x00000000
+#define HWIO_JPEG_QT_IDX__RMSK                             0x0000FFFF
+#define HWIO_JPEG_QT_IDX__SHFT                                      0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_QT_IDX__JPEG_QT_IDX_TABLE_1__BMSK        0x0000FF00
+#define HWIO_JPEG_QT_IDX__JPEG_QT_IDX_TABLE_1__SHFT                  8
+#define HWIO_JPEG_QT_IDX__JPEG_QT_IDX_TABLE_0__BMSK         0x000000FF
+#define HWIO_JPEG_QT_IDX__JPEG_QT_IDX_TABLE_0__SHFT                  0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_DQT                                        JPEG_DQT
+#define HWIO_JPEG_DQT_ADDR  /* RW */                    (JPEGD_BASE+0x00000034)
+#define HWIO_JPEG_DQT__POR                              0x00000000
+#define HWIO_JPEG_DQT__RMSK                             0x0F00FFFF
+#define HWIO_JPEG_DQT__SHFT                             0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_DQT__JPEG_DQT_TQ__BMSK                0x0F000000
+#define HWIO_JPEG_DQT__JPEG_DQT_TQ__SHFT                24
+#define HWIO_JPEG_DQT__JPEG_DQT_QK__BMSK                0x0000FFFF
+#define HWIO_JPEG_DQT__JPEG_DQT_QK__SHFT                0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_DRI                                JPEG_DRI
+#define HWIO_JPEG_DRI_ADDR  /* RW */            (JPEGD_BASE+0x00000040)
+#define HWIO_JPEG_DRI__POR                      0x00000000
+#define HWIO_JPEG_DRI__RMSK                     0x0000FFFF
+#define HWIO_JPEG_DRI__SHFT                              0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_DRI__JPEG_DRI_RI__BMSK        0x0000FFFF
+#define HWIO_JPEG_DRI__JPEG_DRI_RI__SHFT                 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_DHT_REG_0                               JPEG_DHT_REG_0
+#define HWIO_JPEG_DHT_REG_0_ADDR  /* RW */               (JPEGD_BASE+0x00000050)
+#define HWIO_JPEG_DHT_REG_0__POR                         0x00000000
+#define HWIO_JPEG_DHT_REG_0__RMSK                        0x000000FF
+#define HWIO_JPEG_DHT_REG_0__SHFT                                 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_DHT_REG_0__JPEG_DHT_REG_0_TH__BMSK     0x000000F0
+#define HWIO_JPEG_DHT_REG_0__JPEG_DHT_REG_0_TH__SHFT              4
+#define HWIO_JPEG_DHT_REG_0__JPEG_DHT_REG_0_TC__BMSK     0x0000000F
+#define HWIO_JPEG_DHT_REG_0__JPEG_DHT_REG_0_TC__SHFT              0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_DHT_IDX                                        JPEG_DHT_IDX
+#define HWIO_JPEG_DHT_IDX_ADDR  /* RW */      (JPEGD_BASE+0x00000054)
+#define HWIO_JPEG_DHT_IDX__POR                                0x00000000
+#define HWIO_JPEG_DHT_IDX__RMSK                               0x00000FFF
+#define HWIO_JPEG_DHT_IDX__SHFT                                        0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_DHT_IDX__JPEG_DHT_IDX_CCC_MAX__BMSK         0x00000F00
+#define HWIO_JPEG_DHT_IDX__JPEG_DHT_IDX_CCC_MAX__SHFT                  8
+#define HWIO_JPEG_DHT_IDX__JPEG_DHT_IDX_VIJ__BMSK             0x000000FF
+#define HWIO_JPEG_DHT_IDX__JPEG_DHT_IDX_VIJ__SHFT                      0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_DHT_REG_1                          JPEG_DHT_REG_1
+#define HWIO_JPEG_DHT_REG_1_ADDR  /* RW */          (JPEGD_BASE+0x00000058)
+#define HWIO_JPEG_DHT_REG_1__POR                    0x00000000
+#define HWIO_JPEG_DHT_REG_1__RMSK                   0xFFFFFFFF
+#define HWIO_JPEG_DHT_REG_1__SHFT                            0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_DHT_REG_1__JPEG_DHT_REG_1_VIJ_0__BMSK       0xFF000000
+#define HWIO_JPEG_DHT_REG_1__JPEG_DHT_REG_1_VIJ_0__SHFT               24
+#define HWIO_JPEG_DHT_REG_1__JPEG_DHT_REG_1_VIJ_1__BMSK       0x00FF0000
+#define HWIO_JPEG_DHT_REG_1__JPEG_DHT_REG_1_VIJ_1__SHFT               16
+#define HWIO_JPEG_DHT_REG_1__JPEG_DHT_REG_1_VIJ_2__BMSK       0x0000FF00
+#define HWIO_JPEG_DHT_REG_1__JPEG_DHT_REG_1_VIJ_2__SHFT                8
+#define HWIO_JPEG_DHT_REG_1__JPEG_DHT_REG_1_VIJ_3__BMSK       0x000000FF
+#define HWIO_JPEG_DHT_REG_1__JPEG_DHT_REG_1_VIJ_3__SHFT                0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_DHT_CCC_MAX                          JPEG_DHT_CCC_MAX
+#define HWIO_JPEG_DHT_CCC_MAX_ADDR  /* RW */            (JPEGD_BASE+0x0000005C)
+#define HWIO_JPEG_DHT_CCC_MAX__POR                      0x00000000
+#define HWIO_JPEG_DHT_CCC_MAX__RMSK                     0xFFFFFFFF
+#define HWIO_JPEG_DHT_CCC_MAX__SHFT                              0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_DHT_CCC_MAX__JPEG_DHT_CCC_MAX_MAX__BMSK    0xFFFF0000
+#define HWIO_JPEG_DHT_CCC_MAX__JPEG_DHT_CCC_MAX_MAX__SHFT            16
+#define HWIO_JPEG_DHT_CCC_MAX__JPEG_DHT_CCC_MAX_CCC__BMSK    0x0000FFFF
+#define HWIO_JPEG_DHT_CCC_MAX__JPEG_DHT_CCC_MAX_CCC__SHFT             0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_DHT_CCC_MAX__JPEG_DHT_CCC_MAX_MAX__BMSK    0xFFFF0000
+#define HWIO_JPEG_DHT_CCC_MAX__JPEG_DHT_CCC_MAX_MAX__SHFT            16
+#define HWIO_JPEG_DHT_CCC_MAX__JPEG_DHT_CCC_MAX_CCC__BMSK    0x0000FFFF
+#define HWIO_JPEG_DHT_CCC_MAX__JPEG_DHT_CCC_MAX_CCC__SHFT             0
+#define HWIO_JPEG_DHT_CCC_MAX__JPEG_DHT_LI__BMSK       0x000000FF
+#define HWIO_JPEG_DHT_CCC_MAX__JPEG_DHT_LI__SHFT                0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_DEC_SCALE                       JPEG_DEC_SCALE
+#define HWIO_JPEG_DEC_SCALE_ADDR  /* RW */       (JPEGD_BASE+0x00000060)
+#define HWIO_JPEG_DEC_SCALE__POR                 0x00000000
+#define HWIO_JPEG_DEC_SCALE__RMSK                0x00000003
+#define HWIO_JPEG_DEC_SCALE__SHFT                         0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_DEC_SCALE__JPEG_DEC_SCALE_RATIO__BMSK       0x00000003
+#define HWIO_JPEG_DEC_SCALE__JPEG_DEC_SCALE_RATIO__SHFT                0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_CONVERT                         JPEG_CONVERT
+#define HWIO_JPEG_CONVERT_ADDR  /* RW */       (JPEGD_BASE+0x00000064)
+#define HWIO_JPEG_CONVERT__POR                 0x00000000
+#define HWIO_JPEG_CONVERT__RMSK                0xFFFF13FF
+#define HWIO_JPEG_CONVERT__SHFT                         0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_MONO_CB_VALUE__BMSK      0xFF000000
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_MONO_CB_VALUE__SHFT              24
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_MONO_CR_VALUE__BMSK      0x00FF0000
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_MONO_CR_VALUE__SHFT              16
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_CLAMP_EN__BMSK           0x00001000
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_CLAMP_EN__SHFT                   12
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_CBCR_SWITCH__BMSK        0x00000200
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_CBCR_SWITCH__SHFT                 9
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_MONOCHROME_EN__BMSK      0x00000100
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_MONOCHROME_EN__SHFT               8
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_MEM_ORG__BMSK            0x000000C0
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_MEM_ORG__SHFT                     6
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_422_MCU_TYPE__BMSK       0x00000030
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_422_MCU_TYPE__SHFT                4
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_OUTPUT_FORMAT__BMSK      0x0000000C
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_OUTPUT_FORMAT__SHFT               2
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_INPUT_FORMAT__BMSK       0x00000003
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_INPUT_FORMAT__SHFT                0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_ENC_BYTE_CNT                       JPEG_ENC_BYTE_CNT
+#define HWIO_JPEG_ENC_BYTE_CNT_ADDR  /* RW */          (JPEGD_BASE+0x00000070)
+#define HWIO_JPEG_ENC_BYTE_CNT__POR                    0x00000000
+#define HWIO_JPEG_ENC_BYTE_CNT__RMSK                   0xFFFFFFFF
+#define HWIO_JPEG_ENC_BYTE_CNT__SHFT                            0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_ENC_BYTE_CNT__JPEG_ENC_BYTE_CNT_TOT__BMSK     0xFFFFFFFF
+#define HWIO_JPEG_ENC_BYTE_CNT__JPEG_ENC_BYTE_CNT_TOT__SHFT              0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_DEBUG                                  JPEG_DEBUG
+#define HWIO_JPEG_DEBUG_ADDR  /* RW */              (JPEGD_BASE+0x00000080)
+#define HWIO_JPEG_DEBUG__POR                        0x4A504547
+#define HWIO_JPEG_DEBUG__RMSK                       0xFFFFFFFF
+#define HWIO_JPEG_DEBUG__SHFT                                0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_DEBUG__JPEG_DEBUG__BMSK            0xFFFFFFFF
+#define HWIO_JPEG_DEBUG__JPEG_DEBUG__SHFT                     0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_SPARE                                JPEG_SPARE
+#define HWIO_JPEG_SPARE_ADDR  /* RW */            (JPEGD_BASE+0x00000084)
+#define HWIO_JPEG_SPARE__POR                      0x00000000
+#define HWIO_JPEG_SPARE__RMSK                     0xFFFFFFFF
+#define HWIO_JPEG_SPARE__SHFT                              0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_SPARE__JPEG_SPARE_00__BMSK            0xFFFFFFFF
+#define HWIO_JPEG_SPARE__JPEG_SPARE_00__SHFT                     0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_REGISTER_TIMEOUT                       JPEG_REGISTER_TIMEOUT
+#define HWIO_JPEG_REGISTER_TIMEOUT_ADDR    (JPEGD_BASE+0x00000088)
+#define HWIO_JPEG_REGISTER_TIMEOUT__POR                        0x0000FFFF
+#define HWIO_JPEG_REGISTER_TIMEOUT__RMSK                       0x0000FFFF
+#define HWIO_JPEG_REGISTER_TIMEOUT__SHFT                                0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_REGISTER_TIMEOUT__JPEG_TIMEOUT_VALUE__BMSK        0x0000FFFF
+#define HWIO_JPEG_REGISTER_TIMEOUT__JPEG_TIMEOUT_VALUE__SHFT                 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEGD_STATUS_BUS_DATA                     JPEGD_STATUS_BUS_DATA
+#define HWIO_JPEGD_STATUS_BUS_DATA_ADDR  /* RW */       (JPEGD_BASE+0x00000258)
+#define HWIO_JPEGD_STATUS_BUS_DATA__POR                      0x00000000
+#define HWIO_JPEGD_STATUS_BUS_DATA__RMSK                     0xFFFFFFFF
+#define HWIO_JPEGD_STATUS_BUS_DATA__SHFT                              0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEGD_STATUS_BUS_DATA__STATUS_BUS_DATA__BMSK      0xFFFFFFFF
+#define HWIO_JPEGD_STATUS_BUS_DATA__STATUS_BUS_DATA__SHFT               0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEGD_STATUS_BUS_CONFIG                     JPEGD_STATUS_BUS_CONFIG
+#define HWIO_JPEGD_STATUS_BUS_CONFIG_ADDR  /* RW */     (JPEGD_BASE+0x0000025C)
+#define HWIO_JPEGD_STATUS_BUS_CONFIG__POR                        0x00000000
+#define HWIO_JPEGD_STATUS_BUS_CONFIG__RMSK                       0x0000001F
+#define HWIO_JPEGD_STATUS_BUS_CONFIG__SHFT                                0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEGD_STATUS_BUS_CONFIG__STATUS_BUS_SEL__BMSK         0x0000001F
+#define HWIO_JPEGD_STATUS_BUS_CONFIG__STATUS_BUS_SEL__SHFT                  0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_AXI_CONFIG                       RTDMA_JPEG_AXI_CONFIG
+#define HWIO_RTDMA_JPEG_AXI_CONFIG_ADDR  /* RW */        (JPEGD_BASE+0x00000260)
+#define HWIO_RTDMA_JPEG_AXI_CONFIG__POR                        0x00000024
+#define HWIO_RTDMA_JPEG_AXI_CONFIG__RMSK                       0x00000FFF
+#define HWIO_RTDMA_JPEG_AXI_CONFIG__SHFT                                0
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_AXI_CONFIG__OUT_OF_ORDER_WR__BMSK          0x00000800
+#define HWIO_RTDMA_JPEG_AXI_CONFIG__OUT_OF_ORDER_WR__SHFT                  11
+#define HWIO_RTDMA_JPEG_AXI_CONFIG__OUT_OF_ORDER_RD__BMSK          0x00000400
+#define HWIO_RTDMA_JPEG_AXI_CONFIG__OUT_OF_ORDER_RD__SHFT                  10
+#define HWIO_RTDMA_JPEG_AXI_CONFIG__BOUND_LIMIT__BMSK              0x00000300
+#define HWIO_RTDMA_JPEG_AXI_CONFIG__BOUND_LIMIT__SHFT                       8
+#define HWIO_RTDMA_JPEG_AXI_CONFIG__PACK_TIMEOUT__BMSK             0x000000F0
+#define HWIO_RTDMA_JPEG_AXI_CONFIG__PACK_TIMEOUT__SHFT                      4
+#define HWIO_RTDMA_JPEG_AXI_CONFIG__PACK_MAX_BLEN__BMSK            0x0000000F
+#define HWIO_RTDMA_JPEG_AXI_CONFIG__PACK_MAX_BLEN__SHFT                     0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEGD_CLK_CONTROL                             JPEGD_CLK_CONTROL
+#define HWIO_JPEGD_CLK_CONTROL_ADDR  /* RW */   (JPEGD_BASE+0x00000264)
+#define HWIO_JPEGD_CLK_CONTROL__POR             0x00000005
+#define HWIO_JPEGD_CLK_CONTROL__RMSK                         0x0000000F
+#define HWIO_JPEGD_CLK_CONTROL__SHFT                                  0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEGD_CLK_CONTROL__JPEG_CLKIDLE__BMSK           0x00000008
+#define HWIO_JPEGD_CLK_CONTROL__JPEG_CLKIDLE__SHFT                    3
+#define HWIO_JPEGD_CLK_CONTROL__JPEG_CLKON__BMSK             0x00000004
+#define HWIO_JPEGD_CLK_CONTROL__JPEG_CLKON__SHFT                      2
+#define HWIO_JPEGD_CLK_CONTROL__AXI_CLKIDLE__BMSK            0x00000002
+#define HWIO_JPEGD_CLK_CONTROL__AXI_CLKIDLE__SHFT                     1
+#define HWIO_JPEGD_CLK_CONTROL__AXI_CLKON__BMSK              0x00000001
+#define HWIO_JPEGD_CLK_CONTROL__AXI_CLKON__SHFT                       0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_WR_BUF_CONFIG                     RTDMA_JPEG_WR_BUF_CONFIG
+#define HWIO_RTDMA_JPEG_WR_BUF_CONFIG_ADDR  /* RW */   (JPEGD_BASE+0x00000200)
+#define HWIO_RTDMA_JPEG_WR_BUF_CONFIG__POR             0x00000000
+#define HWIO_RTDMA_JPEG_WR_BUF_CONFIG__RMSK            0x0000001F
+#define HWIO_RTDMA_JPEG_WR_BUF_CONFIG__SHFT                     0
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_WR_BUF_CONFIG__BUF_FORMAT__BMSK         0x0000001C
+#define HWIO_RTDMA_JPEG_WR_BUF_CONFIG__BUF_FORMAT__SHFT                  2
+#define HWIO_RTDMA_JPEG_WR_BUF_CONFIG__NUM_OF_PLANES__BMSK      0x00000003
+#define HWIO_RTDMA_JPEG_WR_BUF_CONFIG__NUM_OF_PLANES__SHFT               0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_WR_OP                               RTDMA_JPEG_WR_OP
+#define HWIO_RTDMA_JPEG_WR_OP_ADDR  /* RW */        (JPEGD_BASE+0x00000204)
+#define HWIO_RTDMA_JPEG_WR_OP__POR                  0x00000000
+#define HWIO_RTDMA_JPEG_WR_OP__RMSK                 0x00000013
+#define HWIO_RTDMA_JPEG_WR_OP__SHFT                          0
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_WR_OP__ALIGN__BMSK          0x00000010
+#define HWIO_RTDMA_JPEG_WR_OP__ALIGN__SHFT                   4
+#define HWIO_RTDMA_JPEG_WR_OP__FLIP__BMSK           0x00000002
+#define HWIO_RTDMA_JPEG_WR_OP__FLIP__SHFT                    1
+#define HWIO_RTDMA_JPEG_WR_OP__MIRROR__BMSK         0x00000001
+#define HWIO_RTDMA_JPEG_WR_OP__MIRROR__SHFT                  0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_WR_BUF_Y_PNTR                      RTDMA_JPEG_WR_BUF_Y_PNTR
+#define HWIO_RTDMA_JPEG_WR_BUF_Y_PNTR_ADDR    (JPEGD_BASE+0x00000208)
+#define HWIO_RTDMA_JPEG_WR_BUF_Y_PNTR__POR                0x00000000
+#define HWIO_RTDMA_JPEG_WR_BUF_Y_PNTR__RMSK               0xFFFFFFF8
+#define HWIO_RTDMA_JPEG_WR_BUF_Y_PNTR__SHFT                        3
+/* Register Element MIN and MAX*/
+#define HWIO_RTDMA_JPEG_WR_BUF_Y_PNTR___S                          3
+#define HWIO_RTDMA_JPEG_WR_BUF_Y_PNTR___S                          3
+#define HWIO_RTDMA_JPEG_WR_BUF_Y_PNTR___S                          3
+#define HWIO_RTDMA_JPEG_WR_BUF_Y_PNTR___S                          3
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_WR_BUF_Y_PNTR__PNTR__BMSK         0xFFFFFFF8
+#define HWIO_RTDMA_JPEG_WR_BUF_Y_PNTR__PNTR__SHFT                  3
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_WR_BUF_U_PNTR                      RTDMA_JPEG_WR_BUF_U_PNTR
+#define HWIO_RTDMA_JPEG_WR_BUF_U_PNTR_ADDR  /* RW */     (JPEGD_BASE+0x0000020C)
+#define HWIO_RTDMA_JPEG_WR_BUF_U_PNTR__POR               0x00000000
+#define HWIO_RTDMA_JPEG_WR_BUF_U_PNTR__RMSK              0xFFFFFFF8
+#define HWIO_RTDMA_JPEG_WR_BUF_U_PNTR__SHFT                       3
+
+/* Register Element MIN and MAX*/
+#define HWIO_RTDMA_JPEG_WR_BUF_U_PNTR___S                         3
+#define HWIO_RTDMA_JPEG_WR_BUF_U_PNTR___S                         3
+#define HWIO_RTDMA_JPEG_WR_BUF_U_PNTR___S                         3
+#define HWIO_RTDMA_JPEG_WR_BUF_U_PNTR___S                         3
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_WR_BUF_U_PNTR__PNTR__BMSK        0xFFFFFFF8
+#define HWIO_RTDMA_JPEG_WR_BUF_U_PNTR__PNTR__SHFT                 3
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_WR_BUF_V_PNTR                       RTDMA_JPEG_WR_BUF_V_PNTR
+#define HWIO_RTDMA_JPEG_WR_BUF_V_PNTR_ADDR   (JPEGD_BASE+0x00000210)
+#define HWIO_RTDMA_JPEG_WR_BUF_V_PNTR__POR                0x00000000
+#define HWIO_RTDMA_JPEG_WR_BUF_V_PNTR__RMSK               0xFFFFFFF8
+#define HWIO_RTDMA_JPEG_WR_BUF_V_PNTR__SHFT                        3
+
+/* Register Element MIN and MAX*/
+#define HWIO_RTDMA_JPEG_WR_BUF_V_PNTR___S                          3
+#define HWIO_RTDMA_JPEG_WR_BUF_V_PNTR___S                          3
+#define HWIO_RTDMA_JPEG_WR_BUF_V_PNTR___S                          3
+#define HWIO_RTDMA_JPEG_WR_BUF_V_PNTR___S                          3
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_WR_BUF_V_PNTR__PNTR__BMSK         0xFFFFFFF8
+#define HWIO_RTDMA_JPEG_WR_BUF_V_PNTR__PNTR__SHFT                  3
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_WR_BUF_PITCH                         RTDMA_JPEG_WR_BUF_PITCH
+#define HWIO_RTDMA_JPEG_WR_BUF_PITCH_ADDR  /* RW */    (JPEGD_BASE+0x00000214)
+#define HWIO_RTDMA_JPEG_WR_BUF_PITCH__POR              0x00000000
+#define HWIO_RTDMA_JPEG_WR_BUF_PITCH__RMSK             0x00003FF8
+#define HWIO_RTDMA_JPEG_WR_BUF_PITCH__SHFT                      3
+
+/* Register Element MIN and MAX*/
+#define HWIO_RTDMA_JPEG_WR_BUF_PITCH___S                        3
+#define HWIO_RTDMA_JPEG_WR_BUF_PITCH___S                        3
+#define HWIO_RTDMA_JPEG_WR_BUF_PITCH___S                        3
+#define HWIO_RTDMA_JPEG_WR_BUF_PITCH___S                        3
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_WR_BUF_PITCH__PITCH__BMSK          0x00003FF8
+#define HWIO_RTDMA_JPEG_WR_BUF_PITCH__PITCH__SHFT                   3
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_WR_PLANE_SIZE                      RTDMA_JPEG_WR_PLANE_SIZE
+#define HWIO_RTDMA_JPEG_WR_PLANE_SIZE_ADDR  /* RW */  (JPEGD_BASE+0x00000218)
+#define HWIO_RTDMA_JPEG_WR_PLANE_SIZE__POR            0x00000000
+#define HWIO_RTDMA_JPEG_WR_PLANE_SIZE__RMSK           0x1FFF1FFF
+#define HWIO_RTDMA_JPEG_WR_PLANE_SIZE__SHFT                    0
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_WR_PLANE_SIZE__PLANE_VSIZE__BMSK       0x1FFF0000
+#define HWIO_RTDMA_JPEG_WR_PLANE_SIZE__PLANE_VSIZE__SHFT               16
+#define HWIO_RTDMA_JPEG_WR_PLANE_SIZE__PLANE_HSIZE__BMSK       0x00001FFF
+#define HWIO_RTDMA_JPEG_WR_PLANE_SIZE__PLANE_HSIZE__SHFT                0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_WR_BLOCK_SIZE                      RTDMA_JPEG_WR_BLOCK_SIZE
+#define HWIO_RTDMA_JPEG_WR_BLOCK_SIZE_ADDR  /* RW */    (JPEGD_BASE+0x0000021C)
+#define HWIO_RTDMA_JPEG_WR_BLOCK_SIZE__POR              0x00000000
+#define HWIO_RTDMA_JPEG_WR_BLOCK_SIZE__RMSK             0x00000FFF
+#define HWIO_RTDMA_JPEG_WR_BLOCK_SIZE__SHFT                      0
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_WR_BLOCK_SIZE__BLOCK_VSIZE__BMSK           0x00000FC0
+#define HWIO_RTDMA_JPEG_WR_BLOCK_SIZE__BLOCK_VSIZE__SHFT                    6
+#define HWIO_RTDMA_JPEG_WR_BLOCK_SIZE__BLOCK_HSIZE__BMSK           0x0000003F
+#define HWIO_RTDMA_JPEG_WR_BLOCK_SIZE__BLOCK_HSIZE__SHFT                    0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_WR_BUFFER_SIZE                      RTDMA_JPEG_WR_BUFFER_SIZE
+#define HWIO_RTDMA_JPEG_WR_BUFFER_SIZE_ADDR  /* RW */   (JPEGD_BASE+0x00000220)
+#define HWIO_RTDMA_JPEG_WR_BUFFER_SIZE__POR             0x00000000
+#define HWIO_RTDMA_JPEG_WR_BUFFER_SIZE__RMSK            0x00001FFF
+#define HWIO_RTDMA_JPEG_WR_BUFFER_SIZE__SHFT                     0
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_WR_BUFFER_SIZE__BUFFER_VSIZE__BMSK         0x00001FFF
+#define HWIO_RTDMA_JPEG_WR_BUFFER_SIZE__BUFFER_VSIZE__SHFT                  0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_WR_STA_ACK                      RTDMA_JPEG_WR_STA_ACK
+#define HWIO_RTDMA_JPEG_WR_STA_ACK_ADDR  /* RW */   (JPEGD_BASE+0x00000224)
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__POR             0x00000000
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__RMSK            0x0000000F
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__SHFT                     3
+
+/* Register Element MIN and MAX*/
+#define HWIO_RTDMA_JPEG_WR_STA_ACK___S                       3
+#define HWIO_RTDMA_JPEG_WR_STA_ACK___S                       3
+#define HWIO_RTDMA_JPEG_WR_STA_ACK___S                       3
+#define HWIO_RTDMA_JPEG_WR_STA_ACK___S                       3
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__SW_RESET_ABORT_RDY_STA__BMSK   0x00000008
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__SW_RESET_ABORT_RDY_STA__SHFT            3
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__SW_RESET_ABORT_RDY_ACK__BMSK   0x00000008
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__SW_RESET_ABORT_RDY_ACK__SHFT            3
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__ERR_STA__BMSK                  0x00000004
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__ERR_STA__SHFT                           2
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__ERR_ACK__BMSK                  0x00000004
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__ERR_ACK__SHFT                           2
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__EOF_STA__BMSK                  0x00000002
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__EOF_STA__SHFT                           1
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__EOF_ACK__BMSK                  0x00000002
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__EOF_ACK__SHFT                           1
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__SOF_STA__BMSK                  0x00000001
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__SOF_STA__SHFT                           0
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__SOF_ACK__BMSK           0x00000001
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__SOF_ACK__SHFT                    0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_WR_INT_EN                      RTDMA_JPEG_WR_INT_EN
+#define HWIO_RTDMA_JPEG_WR_INT_EN_ADDR  /* W */        (JPEGD_BASE+0x00000228)
+#define HWIO_RTDMA_JPEG_WR_INT_EN__POR                 0x00000000
+#define HWIO_RTDMA_JPEG_WR_INT_EN__RMSK                0x0000000F
+#define HWIO_RTDMA_JPEG_WR_INT_EN__SHFT                         0
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_WR_INT_EN__SW_RESET_ABORT_RDY_EN__BMSK 0x00000008
+#define HWIO_RTDMA_JPEG_WR_INT_EN__SW_RESET_ABORT_RDY_EN__SHFT          3
+#define HWIO_RTDMA_JPEG_WR_INT_EN__ERR_EN__BMSK                0x00000004
+#define HWIO_RTDMA_JPEG_WR_INT_EN__ERR_EN__SHFT                         2
+#define HWIO_RTDMA_JPEG_WR_INT_EN__EOF_EN__BMSK                0x00000002
+#define HWIO_RTDMA_JPEG_WR_INT_EN__EOF_EN__SHFT                         1
+#define HWIO_RTDMA_JPEG_WR_INT_EN__SOF_EN__BMSK                0x00000001
+#define HWIO_RTDMA_JPEG_WR_INT_EN__SOF_EN__SHFT                         0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_RD_BUF_CONFIG                     RTDMA_JPEG_RD_BUF_CONFIG
+#define HWIO_RTDMA_JPEG_RD_BUF_CONFIG_ADDR  /* RW */     (JPEGD_BASE+0x00000100)
+#define HWIO_RTDMA_JPEG_RD_BUF_CONFIG__POR               0x00000000
+#define HWIO_RTDMA_JPEG_RD_BUF_CONFIG__RMSK              0x0000001F
+#define HWIO_RTDMA_JPEG_RD_BUF_CONFIG__SHFT                       0
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_RD_BUF_CONFIG__BUF_FORMAT__BMSK          0x0000001C
+#define HWIO_RTDMA_JPEG_RD_BUF_CONFIG__BUF_FORMAT__SHFT                   2
+#define HWIO_RTDMA_JPEG_RD_BUF_CONFIG__NUM_OF_PLANES__BMSK       0x00000003
+#define HWIO_RTDMA_JPEG_RD_BUF_CONFIG__NUM_OF_PLANES__SHFT                0
+
+/* Register ADDR, RMSK, and SHFT, W */
+#define RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO   RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO
+#define HWIO_RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO_ADDR  (JPEGD_BASE+0x00000104)
+#define HWIO_RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO__POR            0x00000000
+#define HWIO_RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO__RMSK           0x0000001C
+#define HWIO_RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO__SHFT                    2
+
+/* Register Element MIN and MAX*/
+#define HWIO_RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO___S                      2
+#define HWIO_RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO___S                      2
+#define HWIO_RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO___S                      2
+#define HWIO_RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO___S                      2
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO__BUF_APPLY__BMSK   0x00000010
+#define HWIO_RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO__BUF_APPLY__SHFT            4
+#define HWIO_RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO__BUF_EOF__BMSK     0x00000008
+#define HWIO_RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO__BUF_EOF__SHFT              3
+#define HWIO_RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO__BUF_SOF__BMSK     0x00000004
+#define HWIO_RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO__BUF_SOF__SHFT              2
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_RD_BUF_Y_PNTR                        RTDMA_JPEG_RD_BUF_Y_PNTR
+#define HWIO_RTDMA_JPEG_RD_BUF_Y_PNTR_ADDR  /* RW */   (JPEGD_BASE+0x0000010C)
+#define HWIO_RTDMA_JPEG_RD_BUF_Y_PNTR__POR             0x00000000
+#define HWIO_RTDMA_JPEG_RD_BUF_Y_PNTR__RMSK            0xFFFFFFF8
+#define HWIO_RTDMA_JPEG_RD_BUF_Y_PNTR__SHFT                     3
+
+/* Register Element MIN and MAX*/
+#define HWIO_RTDMA_JPEG_RD_BUF_Y_PNTR___S                       3
+#define HWIO_RTDMA_JPEG_RD_BUF_Y_PNTR___S                       3
+#define HWIO_RTDMA_JPEG_RD_BUF_Y_PNTR___S                       3
+#define HWIO_RTDMA_JPEG_RD_BUF_Y_PNTR___S                       3
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_RD_BUF_Y_PNTR__PNTR__BMSK      0xFFFFFFF8
+#define HWIO_RTDMA_JPEG_RD_BUF_Y_PNTR__PNTR__SHFT               3
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_RD_BUF_U_PNTR                     RTDMA_JPEG_RD_BUF_U_PNTR
+#define HWIO_RTDMA_JPEG_RD_BUF_U_PNTR_ADDR  /* RW */ (JPEGD_BASE+0x00000110)
+#define HWIO_RTDMA_JPEG_RD_BUF_U_PNTR__POR           0x00000000
+#define HWIO_RTDMA_JPEG_RD_BUF_U_PNTR__RMSK          0xFFFFFFF8
+#define HWIO_RTDMA_JPEG_RD_BUF_U_PNTR__SHFT                   3
+
+/* Register Element MIN and MAX*/
+#define HWIO_RTDMA_JPEG_RD_BUF_U_PNTR___S                     3
+#define HWIO_RTDMA_JPEG_RD_BUF_U_PNTR___S                     3
+#define HWIO_RTDMA_JPEG_RD_BUF_U_PNTR___S                     3
+#define HWIO_RTDMA_JPEG_RD_BUF_U_PNTR___S                     3
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_RD_BUF_U_PNTR__PNTR__BMSK        0xFFFFFFF8
+#define HWIO_RTDMA_JPEG_RD_BUF_U_PNTR__PNTR__SHFT               3
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_RD_BUF_V_PNTR                     RTDMA_JPEG_RD_BUF_V_PNTR
+#define HWIO_RTDMA_JPEG_RD_BUF_V_PNTR_ADDR  /* RW */    (JPEGD_BASE+0x00000114)
+#define HWIO_RTDMA_JPEG_RD_BUF_V_PNTR__POR              0x00000000
+#define HWIO_RTDMA_JPEG_RD_BUF_V_PNTR__RMSK             0xFFFFFFF8
+#define HWIO_RTDMA_JPEG_RD_BUF_V_PNTR__SHFT                      3
+
+/* Register Element MIN and MAX*/
+#define HWIO_RTDMA_JPEG_RD_BUF_V_PNTR___S                        3
+#define HWIO_RTDMA_JPEG_RD_BUF_V_PNTR___S                        3
+#define HWIO_RTDMA_JPEG_RD_BUF_V_PNTR___S                        3
+#define HWIO_RTDMA_JPEG_RD_BUF_V_PNTR___S                        3
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_RD_BUF_V_PNTR__PNTR__BMSK       0xFFFFFFF8
+#define HWIO_RTDMA_JPEG_RD_BUF_V_PNTR__PNTR__SHFT                3
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_RD_BUF_PITCH                       RTDMA_JPEG_RD_BUF_PITCH
+#define HWIO_RTDMA_JPEG_RD_BUF_PITCH_ADDR  /* RW */    (JPEGD_BASE+0x00000118)
+#define HWIO_RTDMA_JPEG_RD_BUF_PITCH__POR              0x00000000
+#define HWIO_RTDMA_JPEG_RD_BUF_PITCH__RMSK             0x00003FF8
+#define HWIO_RTDMA_JPEG_RD_BUF_PITCH__SHFT                      3
+
+/* Register Element MIN and MAX*/
+#define HWIO_RTDMA_JPEG_RD_BUF_PITCH___S                        3
+#define HWIO_RTDMA_JPEG_RD_BUF_PITCH___S                        3
+#define HWIO_RTDMA_JPEG_RD_BUF_PITCH___S                        3
+#define HWIO_RTDMA_JPEG_RD_BUF_PITCH___S                        3
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_RD_BUF_PITCH__PITCH__BMSK            0x00003FF8
+#define HWIO_RTDMA_JPEG_RD_BUF_PITCH__PITCH__SHFT                     3
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_RD_PLANE_SIZE                     RTDMA_JPEG_RD_PLANE_SIZE
+#define HWIO_RTDMA_JPEG_RD_PLANE_SIZE_ADDR  /* RW */  (JPEGD_BASE+0x0000011C)
+#define HWIO_RTDMA_JPEG_RD_PLANE_SIZE__POR            0x00000000
+#define HWIO_RTDMA_JPEG_RD_PLANE_SIZE__RMSK            0x1FFF1FFF
+#define HWIO_RTDMA_JPEG_RD_PLANE_SIZE__SHFT                     0
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_RD_PLANE_SIZE__PLANE_VSIZE__BMSK         0x1FFF0000
+#define HWIO_RTDMA_JPEG_RD_PLANE_SIZE__PLANE_VSIZE__SHFT                 16
+#define HWIO_RTDMA_JPEG_RD_PLANE_SIZE__PLANE_HSIZE__BMSK         0x00001FFF
+#define HWIO_RTDMA_JPEG_RD_PLANE_SIZE__PLANE_HSIZE__SHFT                  0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_RD_BLOCK_SIZE                       RTDMA_JPEG_RD_BLOCK_SIZE
+#define HWIO_RTDMA_JPEG_RD_BLOCK_SIZE_ADDR  /* RW */    (JPEGD_BASE+0x00000120)
+#define HWIO_RTDMA_JPEG_RD_BLOCK_SIZE__POR              0x000003CF
+#define HWIO_RTDMA_JPEG_RD_BLOCK_SIZE__RMSK             0x00000FFF
+#define HWIO_RTDMA_JPEG_RD_BLOCK_SIZE__SHFT                      0
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_RD_BLOCK_SIZE__BLOCK_VSIZE__BMSK       0x00000FC0
+#define HWIO_RTDMA_JPEG_RD_BLOCK_SIZE__BLOCK_VSIZE__SHFT                6
+#define HWIO_RTDMA_JPEG_RD_BLOCK_SIZE__BLOCK_HSIZE__BMSK       0x0000003F
+#define HWIO_RTDMA_JPEG_RD_BLOCK_SIZE__BLOCK_HSIZE__SHFT                0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_RD_BUFFER_SIZE               RTDMA_JPEG_RD_BUFFER_SIZE
+#define HWIO_RTDMA_JPEG_RD_BUFFER_SIZE_ADDR  (JPEGD_BASE+0x00000124)
+#define HWIO_RTDMA_JPEG_RD_BUFFER_SIZE__POR               0x00000000
+#define HWIO_RTDMA_JPEG_RD_BUFFER_SIZE__RMSK              0x00001FFF
+#define HWIO_RTDMA_JPEG_RD_BUFFER_SIZE__SHFT                       0
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_RD_BUFFER_SIZE__BUFFER_VSIZE__BMSK      0x00001FFF
+#define HWIO_RTDMA_JPEG_RD_BUFFER_SIZE__BUFFER_VSIZE__SHFT                0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_RD_STA_ACK                     RTDMA_JPEG_RD_STA_ACK
+#define HWIO_RTDMA_JPEG_RD_STA_ACK_ADDR         (JPEGD_BASE+0x00000128)
+#define HWIO_RTDMA_JPEG_RD_STA_ACK__POR                     0x00000000
+#define HWIO_RTDMA_JPEG_RD_STA_ACK__RMSK                    0x00000003
+#define HWIO_RTDMA_JPEG_RD_STA_ACK__SHFT                             0
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_RD_STA_ACK__EOF_STA__BMSK           0x00000002
+#define HWIO_RTDMA_JPEG_RD_STA_ACK__EOF_STA__SHFT                    1
+#define HWIO_RTDMA_JPEG_RD_STA_ACK__SOF_STA__BMSK           0x00000001
+#define HWIO_RTDMA_JPEG_RD_STA_ACK__SOF_STA__SHFT                    0
+#define HWIO_RTDMA_JPEG_RD_STA_ACK__EOF_ACK__BMSK           0x00000002
+#define HWIO_RTDMA_JPEG_RD_STA_ACK__EOF_ACK__SHFT                    1
+#define HWIO_RTDMA_JPEG_RD_STA_ACK__SOF_ACK__BMSK           0x00000001
+#define HWIO_RTDMA_JPEG_RD_STA_ACK__SOF_ACK__SHFT                    0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_RD_INT_EN                      RTDMA_JPEG_RD_INT_EN
+#define HWIO_RTDMA_JPEG_RD_INT_EN_ADDR  /* W */        (JPEGD_BASE+0x0000012C)
+#define HWIO_RTDMA_JPEG_RD_INT_EN__POR                      0x00000000
+#define HWIO_RTDMA_JPEG_RD_INT_EN__RMSK                     0x00000003
+#define HWIO_RTDMA_JPEG_RD_INT_EN__SHFT                              0
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_RD_INT_EN__EOF_EN__BMSK             0x00000002
+#define HWIO_RTDMA_JPEG_RD_INT_EN__EOF_EN__SHFT                      1
+#define HWIO_RTDMA_JPEG_RD_INT_EN__SOF_EN__BMSK             0x00000001
+#define HWIO_RTDMA_JPEG_RD_INT_EN__SOF_EN__SHFT                      0
+
+#endif /* MSM_MERCURY_HW_REG_H */
diff --git a/drivers/media/video/msm/mercury/msm_mercury_macros.h b/drivers/media/video/msm/mercury/msm_mercury_macros.h
new file mode 100644
index 0000000..33c4f9a
--- /dev/null
+++ b/drivers/media/video/msm/mercury/msm_mercury_macros.h
@@ -0,0 +1,118 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_MERCURY_MACROS_H
+#define MSM_MERCURY_MACROS_H
+
+#include <media/msm_mercury.h>
+
+#define mercury_kread(reg) \
+	hw_cmd.type = MSM_MERCURY_HW_CMD_TYPE_READ; \
+	hw_cmd.n = 1; \
+	hw_cmd.offset = HWIO_##reg##_ADDR; \
+	hw_cmd.mask = HWIO_##reg##__RMSK; \
+	hw_cmd.data = 0x0; \
+	msm_mercury_hw_exec_cmds(&hw_cmd, 1);
+
+#define mercury_kwrite(reg, val) \
+	hw_cmd.offset = HWIO_##reg##_ADDR; \
+	hw_cmd.mask = HWIO_##reg##__RMSK; \
+	hw_cmd.type = MSM_MERCURY_HW_CMD_TYPE_WRITE; \
+	hw_cmd.n = 1; \
+	hw_cmd.data = val; \
+	msm_mercury_hw_exec_cmds(&hw_cmd, 1);
+
+#define GET_FVAL(val, reg, field) ((val & HWIO_FMSK(reg, field)) >> \
+	HWIO_SHFT(reg, field))
+
+#define byte unsigned char
+#define word unsigned short
+#define dword unsigned long
+
+#define inp(port)    (*((dword *) (port)))
+#define inpb(port)     (*((byte *) (port)))
+#define inpw(port)   (*((word *) (port)))
+#define inpdw(port)   (*((dword *)(port)))
+
+#define outp(port, val)   (*((dword *) (port)) = ((dword) (val)))
+#define outpb(port, val)   (*((byte *) (port)) = ((byte) (val)))
+#define outpw(port, val)  (*((word *) (port)) = ((word) (val)))
+#define outpdw(port, val) (*((dword *) (port)) = ((dword) (val)))
+
+
+#define in_byte(addr)				(inp(addr))
+#define in_byte_masked(addr, mask)	(inp(addr) & (byte)mask)
+#define out_byte(addr, val)			 outp(addr, val)
+#define in_word(addr)				(inpw(addr))
+#define in_word_masked(addr, mask)	(inpw(addr) & (word)mask)
+#define out_word(addr, val)			 outpw(addr, val)
+#define in_dword(addr)				(inpdw(addr))
+#define in_dword_masked(addr, mask)	(inpdw(addr) & mask)
+#define out_dword(addr, val)			 outpdw(addr, val)
+
+/* shadowed, masked output for write-only registers */
+#define out_byte_masked(io, mask, val, shadow)  \
+	do { \
+		shadow = (shadow & (word)(~(mask))) | \
+		((word)((val) & (mask))); \
+		(void) out_byte(io, shadow);\
+	} while (0);
+
+#define out_word_masked(io, mask, val, shadow)  \
+	do { \
+		shadow = (shadow & (word)(~(mask))) | \
+		((word)((val) & (mask))); \
+		(void) out_word(io, shadow); \
+	} while (0);
+
+#define out_dword_masked(io, mask, val, shadow)  \
+	do { \
+		shadow = (shadow & (dword)(~(mask))) | \
+		((dword)((val) & (mask))); \
+		(void) out_dword(io, shadow);\
+	} while (0);
+
+#define out_byte_masked_ns(io, mask, val, current_reg_content)  \
+	(void) out_byte(io, ((current_reg_content & \
+	(word)(~(mask))) | ((word)((val) & (mask)))))
+
+#define out_word_masked_ns(io, mask, val, current_reg_content)  \
+	(void) out_word(io, ((current_reg_content & \
+	(word)(~(mask))) | ((word)((val) & (mask)))))
+
+#define out_dword_masked_ns(io, mask, val, current_reg_content) \
+	(void) out_dword(io, ((current_reg_content & \
+	(dword)(~(mask))) | ((dword)((val) & (mask)))))
+
+#define MEM_INF(val, reg, field)	((val & HWIO_FMSK(reg, field)) >> \
+	HWIO_SHFT(reg, field))
+
+#define MEM_OUTF(mem, reg, field, val)\
+	out_dword_masked_ns(mem, HWIO_FMSK(reg, field), \
+	(unsigned  int)val<<HWIO_SHFT(reg, field), in_dword(mem))
+
+#define MEM_OUTF2(mem, reg, field2, field1, val2, val1)  \
+	out_dword_masked_ns(mem, (HWIO_FMSK(reg, field2)| \
+	HWIO_FMSK(reg, field1)), \
+	(((unsigned int)val2<<HWIO_SHFT(reg, field2))| \
+	((unsigned int)val1<<HWIO_SHFT(reg, field1))), in_dword(mem))
+
+#define MEM_OUTF3(mem, reg, fld3, fld2, fld1, val3, val2, val1)  \
+	out_dword_masked_ns(mem, (HWIO_FMSK(reg, fld3)| \
+	HWIO_FMSK(reg, fld2)|HWIO_FMSK(reg, fld1)), \
+	(((unsigned int)val3<<HWIO_SHFT(reg, fld3))| \
+	((unsigned int)val2<<HWIO_SHFT(reg, fld2))| \
+	((unsigned int)val1<<HWIO_SHFT(reg, fld1))), in_dword(mem))
+
+#define HWIO_FMSK(reg, field)   HWIO_##reg##__##field##__BMSK
+#define HWIO_SHFT(reg, field)   HWIO_##reg##__##field##__SHFT
+#endif
diff --git a/drivers/media/video/msm/mercury/msm_mercury_platform.c b/drivers/media/video/msm/mercury/msm_mercury_platform.c
new file mode 100644
index 0000000..9366ef3
--- /dev/null
+++ b/drivers/media/video/msm/mercury/msm_mercury_platform.c
@@ -0,0 +1,194 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/pm_qos_params.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/android_pmem.h>
+#include <mach/clk.h>
+#include <mach/camera.h>
+#include <mach/msm_subsystem_map.h>
+
+#include "msm_mercury_platform.h"
+#include "msm_mercury_sync.h"
+#include "msm_mercury_common.h"
+#include "msm_mercury_hw.h"
+
+
+struct ion_client *mercury_client;
+
+static struct msm_cam_clk_info mercury_jpegd_clk_info[] = {
+	{"core_clk", 200000000},
+	{"iface_clk", -1}
+};
+
+void msm_mercury_platform_p2v(struct file  *file,
+	struct ion_handle **ionhandle)
+{
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+	ion_unmap_iommu(mercury_client, *ionhandle, CAMERA_DOMAIN,
+		GEN_POOL);
+	ion_free(mercury_client, *ionhandle);
+	*ionhandle = NULL;
+#elif CONFIG_ANDROID_PMEM
+	put_pmem_file(file);
+#endif
+}
+
+uint32_t msm_mercury_platform_v2p(int fd, uint32_t len,
+	struct file **file_p,
+	struct ion_handle **ionhandle)
+{
+	unsigned long paddr;
+	unsigned long size;
+	int rc;
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+	*ionhandle = ion_import_fd(mercury_client, fd);
+	if (IS_ERR_OR_NULL(*ionhandle))
+		return 0;
+
+	rc = ion_map_iommu(mercury_client, *ionhandle, CAMERA_DOMAIN,
+		GEN_POOL, SZ_4K, 0, &paddr,
+		(unsigned long *)&size, UNCACHED, 0);
+#elif CONFIG_ANDROID_PMEM
+	unsigned long kvstart;
+	rc = get_pmem_file(fd, &paddr, &kvstart, &size, file_p);
+#else
+	rc = 0;
+	paddr = 0;
+	size = 0;
+#endif
+	if (rc < 0) {
+		MCR_PR_ERR("%s: get_pmem_file fd %d error %d\n", __func__, fd,
+			rc);
+		goto error1;
+	}
+
+	/* validate user input */
+	if (len > size) {
+		MCR_PR_ERR("%s: invalid offset + len\n", __func__);
+		goto error1;
+	}
+
+	return paddr;
+error1:
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+	ion_free(mercury_client, *ionhandle);
+#endif
+	return 0;
+}
+
+int msm_mercury_platform_init(struct platform_device *pdev,
+	struct resource **mem,
+	void **base,
+	int *irq,
+	irqreturn_t (*handler) (int, void *),
+	void *context)
+{
+	int rc = 0;
+	int mercury_irq;
+	struct resource *mercury_mem, *mercury_io, *mercury_irq_res;
+	void *mercury_base;
+	struct msm_mercury_device *pmercury_dev =
+		(struct msm_mercury_device *) context;
+
+	MCR_DBG("%s:%d]\n", __func__, __LINE__);
+
+	mercury_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mercury_mem) {
+		MCR_PR_ERR("%s: no mem resource?\n", __func__);
+		return -ENODEV;
+	}
+
+	mercury_irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!mercury_irq_res) {
+		MCR_PR_ERR("no irq resource?\n");
+		return -ENODEV;
+	}
+	mercury_irq = mercury_irq_res->start;
+
+	mercury_io = request_mem_region(mercury_mem->start,
+		resource_size(mercury_mem), pdev->name);
+	if (!mercury_io) {
+		MCR_PR_ERR("%s: region already claimed\n", __func__);
+		return -EBUSY;
+	}
+	MCR_DBG("%s:%d]\n", __func__, __LINE__);
+	mercury_base = ioremap(mercury_mem->start,
+		resource_size(mercury_mem));
+	if (!mercury_base) {
+		rc = -ENOMEM;
+		MCR_PR_ERR("%s: ioremap failed\n", __func__);
+		goto fail1;
+	}
+	MCR_DBG("%s:%d]\n", __func__, __LINE__);
+
+	rc = msm_cam_clk_enable(&pmercury_dev->pdev->dev,
+		mercury_jpegd_clk_info, pmercury_dev->mercury_clk,
+		ARRAY_SIZE(mercury_jpegd_clk_info), 1);
+	if (rc < 0)
+		MCR_PR_ERR("%s:%d] rc = %d\n", __func__, __LINE__, rc);
+
+	MCR_DBG("%s:%d]\n", __func__, __LINE__);
+	msm_mercury_hw_init(mercury_base, resource_size(mercury_mem));
+	rc = request_irq(mercury_irq, handler, IRQF_TRIGGER_RISING,
+		"mercury", context);
+	if (rc) {
+		MCR_PR_ERR("%s: request_irq failed, %d\n", __func__,
+			mercury_irq);
+		goto fail3;
+	}
+	MCR_DBG("%s:%d]\n", __func__, __LINE__);
+	*mem  = mercury_mem;
+	*base = mercury_base;
+	*irq  = mercury_irq;
+	MCR_DBG("%s:%d]\n", __func__, __LINE__);
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+	mercury_client = msm_ion_client_create(-1, "camera/mercury");
+#endif
+	MCR_PR_ERR("%s:%d] success\n", __func__, __LINE__);
+	return rc;
+fail3:
+	MCR_DBG("%s:%d]\n", __func__, __LINE__);
+	msm_cam_clk_enable(&pmercury_dev->pdev->dev, mercury_jpegd_clk_info,
+		pmercury_dev->mercury_clk,
+		ARRAY_SIZE(mercury_jpegd_clk_info), 0);
+	MCR_DBG("%s:%d]\n", __func__, __LINE__);
+	iounmap(mercury_base);
+fail1:
+	MCR_DBG("%s:%d]\n", __func__, __LINE__);
+	release_mem_region(mercury_mem->start, resource_size(mercury_mem));
+	MCR_DBG("%s:%d]\n", __func__, __LINE__);
+	return rc;
+}
+
+int msm_mercury_platform_release(struct resource *mem, void *base,
+	int irq, void *context)
+{
+	int result = 0;
+	struct msm_mercury_device *pmercury_dev =
+		(struct msm_mercury_device *) context;
+
+	free_irq(irq, context);
+	msm_cam_clk_enable(&pmercury_dev->pdev->dev, mercury_jpegd_clk_info,
+		pmercury_dev->mercury_clk, ARRAY_SIZE(mercury_jpegd_clk_info),
+		0);
+	iounmap(base);
+	release_mem_region(mem->start, resource_size(mem));
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+	ion_client_destroy(mercury_client);
+#endif
+	MCR_DBG("%s:%d] success\n", __func__, __LINE__);
+	return result;
+}
+
diff --git a/drivers/media/video/msm/mercury/msm_mercury_platform.h b/drivers/media/video/msm/mercury/msm_mercury_platform.h
new file mode 100644
index 0000000..8f4a7e3
--- /dev/null
+++ b/drivers/media/video/msm/mercury/msm_mercury_platform.h
@@ -0,0 +1,39 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_MERCURY_PLATFORM_H
+#define MSM_MERCURY_PLATFORM_H
+
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/ion.h>
+
+int msm_mercury_platform_clk_enable(void);
+int msm_mercury_platform_clk_disable(void);
+
+void msm_mercury_platform_p2v(struct file  *file,
+	struct ion_handle **ionhandle);
+
+uint32_t msm_mercury_platform_v2p(int fd, uint32_t len, struct file **file,
+	struct ion_handle **ionhandle);
+
+int msm_mercury_platform_init(struct platform_device *pdev,
+	struct resource **mem,
+	void **base,
+	int *irq,
+	irqreturn_t (*handler) (int, void *),
+	void *context);
+
+int msm_mercury_platform_release(struct resource *mem, void *base, int irq,
+	void *context);
+
+#endif /* MSM_MERCURY_PLATFORM_H */
diff --git a/drivers/media/video/msm/mercury/msm_mercury_sync.c b/drivers/media/video/msm/mercury/msm_mercury_sync.c
new file mode 100644
index 0000000..31fb8b4
--- /dev/null
+++ b/drivers/media/video/msm/mercury/msm_mercury_sync.c
@@ -0,0 +1,614 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <media/msm_mercury.h>
+
+#include "msm_mercury_sync.h"
+#include "msm_mercury_core.h"
+#include "msm_mercury_platform.h"
+#include "msm_mercury_common.h"
+#include "msm_mercury_macros.h"
+#include "msm_mercury_hw_reg.h"
+
+static struct msm_mercury_core_buf out_buf_local;
+static struct msm_mercury_core_buf in_buf_local;
+
+/*************** queue helper ****************/
+inline void msm_mercury_q_init(char const *name, struct msm_mercury_q *q_p)
+{
+	MCR_DBG("%s:%d] %s\n", __func__, __LINE__, name);
+	q_p->name = name;
+	spin_lock_init(&q_p->lck);
+	INIT_LIST_HEAD(&q_p->q);
+	init_waitqueue_head(&q_p->wait);
+	q_p->unblck = 0;
+}
+
+inline void *msm_mercury_q_out(struct msm_mercury_q *q_p)
+{
+	unsigned long flags;
+	struct msm_mercury_q_entry *q_entry_p = NULL;
+	void *data = NULL;
+
+	MCR_DBG("(%d)%s()  %s\n", __LINE__, __func__, q_p->name);
+	spin_lock_irqsave(&q_p->lck, flags);
+	if (!list_empty(&q_p->q)) {
+		q_entry_p = list_first_entry(&q_p->q,
+			struct msm_mercury_q_entry,
+			list);
+		list_del_init(&q_entry_p->list);
+	}
+	spin_unlock_irqrestore(&q_p->lck, flags);
+
+	if (q_entry_p) {
+		data = q_entry_p->data;
+		kfree(q_entry_p);
+	} else {
+		MCR_DBG("%s:%d] %s no entry\n", __func__, __LINE__, q_p->name);
+	}
+
+	return data;
+}
+
+inline int msm_mercury_q_in(struct msm_mercury_q *q_p, void *data)
+{
+	unsigned long flags;
+
+	struct msm_mercury_q_entry *q_entry_p;
+
+	MCR_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+
+	q_entry_p = kmalloc(sizeof(struct msm_mercury_q_entry), GFP_ATOMIC);
+	if (!q_entry_p) {
+		MCR_PR_ERR("%s: no mem\n", __func__);
+		return -EFAULT;
+	}
+	q_entry_p->data = data;
+
+	spin_lock_irqsave(&q_p->lck, flags);
+	list_add_tail(&q_entry_p->list, &q_p->q);
+	spin_unlock_irqrestore(&q_p->lck, flags);
+
+	return 0;
+}
+
+inline int msm_mercury_q_in_buf(struct msm_mercury_q *q_p,
+	struct msm_mercury_core_buf *buf)
+{
+	struct msm_mercury_core_buf *buf_p;
+
+	MCR_DBG("%s:%d]\n", __func__, __LINE__);
+	buf_p = kmalloc(sizeof(struct msm_mercury_core_buf), GFP_ATOMIC);
+	if (!buf_p) {
+		MCR_PR_ERR("%s: no mem\n", __func__);
+		return -EFAULT;
+	}
+
+	memcpy(buf_p, buf, sizeof(struct msm_mercury_core_buf));
+
+	msm_mercury_q_in(q_p, buf_p);
+	return 0;
+}
+
+inline int msm_mercury_q_wait(struct msm_mercury_q *q_p)
+{
+	int tm = MAX_SCHEDULE_TIMEOUT; /* 500ms */
+	int rc;
+
+	MCR_DBG("%s:%d %s wait\n", __func__, __LINE__, q_p->name);
+	rc = wait_event_interruptible_timeout(q_p->wait,
+		(!list_empty_careful(&q_p->q) || q_p->unblck),
+		msecs_to_jiffies(tm));
+
+	MCR_DBG("%s:%d %s wait done (rc=%d)\n", __func__,
+		__LINE__, q_p->name, rc);
+	if (list_empty_careful(&q_p->q)) {
+		if (rc == 0) {
+			rc = -ETIMEDOUT;
+			MCR_PR_ERR("%s:%d] %s timeout\n", __func__,
+				__LINE__, q_p->name);
+		} else if (q_p->unblck) {
+			MCR_DBG("%s:%d %s unblock is true", __func__,
+				__LINE__, q_p->name);
+			rc = q_p->unblck;
+			q_p->unblck = 0;
+		} else if (rc < 0) {
+			MCR_PR_ERR("%s:%d %s rc %d\n", __func__, __LINE__,
+				q_p->name, rc);
+		}
+	}
+	return rc;
+}
+
+inline int msm_mercury_q_wakeup(struct msm_mercury_q *q_p)
+{
+	MCR_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+	wake_up(&q_p->wait);
+	return 0;
+}
+
+inline int msm_mercury_q_wr_eoi(struct msm_mercury_q *q_p)
+{
+	MCR_DBG("%s:%d] Wake up %s\n", __func__, __LINE__, q_p->name);
+	q_p->unblck = MSM_MERCURY_EVT_FRAMEDONE;
+	wake_up(&q_p->wait);
+	return 0;
+}
+
+inline int msm_mercury_q_wr_err(struct msm_mercury_q *q_p)
+{
+	MCR_DBG("%s:%d] Wake up %s\n", __func__, __LINE__, q_p->name);
+	q_p->unblck = MSM_MERCURY_EVT_ERR;
+	wake_up(&q_p->wait);
+	return 0;
+}
+
+inline int msm_mercury_q_unblock(struct msm_mercury_q *q_p)
+{
+	MCR_DBG("%s:%d] Wake up %s\n", __func__, __LINE__, q_p->name);
+	q_p->unblck = MSM_MERCURY_EVT_UNBLOCK;
+	wake_up(&q_p->wait);
+	return 0;
+}
+
+inline void msm_mercury_q_cleanup(struct msm_mercury_q *q_p)
+{
+	void *data;
+	MCR_DBG("\n%s:%d] %s\n", __func__, __LINE__, q_p->name);
+	do {
+		data = msm_mercury_q_out(q_p);
+		if (data) {
+			MCR_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+			kfree(data);
+		}
+	} while (data);
+	q_p->unblck = 0;
+}
+
+/*************** event queue ****************/
+int msm_mercury_framedone_irq(struct msm_mercury_device *pmercury_dev)
+{
+	MCR_DBG("%s:%d] Enter\n", __func__, __LINE__);
+	msm_mercury_q_unblock(&pmercury_dev->evt_q);
+
+	MCR_DBG("%s:%d] Exit\n", __func__, __LINE__);
+	return 0;
+}
+
+int msm_mercury_evt_get(struct msm_mercury_device *pmercury_dev,
+	void __user *arg)
+{
+	struct msm_mercury_ctrl_cmd ctrl_cmd;
+	int rc = 0;
+
+	MCR_DBG("(%d)%s() Enter\n", __LINE__, __func__);
+	ctrl_cmd.type = (uint32_t)msm_mercury_q_wait(&pmercury_dev->evt_q);
+
+	rc = copy_to_user(arg, &ctrl_cmd, sizeof(ctrl_cmd));
+
+	if (rc) {
+		MCR_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+int msm_mercury_evt_get_unblock(struct msm_mercury_device *pmercury_dev)
+{
+	MCR_DBG("--(%d)%s() Enter\n", __LINE__, __func__);
+	msm_mercury_q_unblock(&pmercury_dev->evt_q);
+	return 0;
+}
+
+int msm_mercury_output_buf_cfg(struct msm_mercury_device *pmercury_dev,
+	void __user *arg)
+{
+	struct msm_mercury_buf buf_cmd;
+
+
+	MCR_DBG("%s:%d] Enter\n", __func__, __LINE__);
+	if (copy_from_user(&buf_cmd, arg, sizeof(struct msm_mercury_buf))) {
+		MCR_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	out_buf_local.y_buffer_addr = msm_mercury_platform_v2p(buf_cmd.fd,
+		buf_cmd.y_len, &out_buf_local.file, &out_buf_local.handle);
+	out_buf_local.cbcr_buffer_addr = out_buf_local.y_buffer_addr +
+		buf_cmd.y_len;
+
+	if (!out_buf_local.y_buffer_addr) {
+		MCR_PR_ERR("%s:%d] v2p wrong\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	msm_mercury_hw_output_y_buf_cfg(out_buf_local.y_buffer_addr);
+	msm_mercury_hw_output_u_buf_cfg(out_buf_local.cbcr_buffer_addr);
+
+	MCR_DBG("(%d)%s()\n  y_buf=0x%08X, y_len=0x%08X, vaddr=0x%08X\n"
+		"  u_buf=0x%08X, u_len=0x%08X\n\n", __LINE__, __func__,
+		out_buf_local.y_buffer_addr, buf_cmd.y_len, (int) buf_cmd.vaddr,
+		out_buf_local.cbcr_buffer_addr, buf_cmd.cbcr_len);
+
+	return 0;
+}
+
+int msm_mercury_input_buf_cfg(struct msm_mercury_device *pmercury_dev,
+	void __user *arg)
+{
+	struct msm_mercury_buf buf_cmd;
+
+
+	MCR_DBG("%s:%d] Enter\n", __func__, __LINE__);
+	if (copy_from_user(&buf_cmd, arg, sizeof(struct msm_mercury_buf))) {
+		MCR_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	in_buf_local.y_buffer_addr = msm_mercury_platform_v2p(buf_cmd.fd,
+		buf_cmd.y_len, &in_buf_local.file, &in_buf_local.handle);
+
+	if (!in_buf_local.y_buffer_addr) {
+		MCR_PR_ERR("%s:%d] v2p wrong\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	msm_mercury_hw_bitstream_buf_cfg(in_buf_local.y_buffer_addr);
+
+	MCR_DBG("(%d)%s()\n  bitstream_buf=0x%08X, len=0x%08X, vaddr=0x%08X\n",
+		__LINE__, __func__, in_buf_local.y_buffer_addr, buf_cmd.y_len,
+		(int) buf_cmd.vaddr);
+
+	return 0;
+}
+
+int msm_mercury_output_get(struct msm_mercury_device *pmercury_dev,
+	void __user *to)
+{
+	MCR_DBG("%s:%d] Enter\n", __func__, __LINE__);
+	msm_mercury_platform_p2v(out_buf_local.file, &out_buf_local.handle);
+	return 0;
+}
+
+int msm_mercury_input_get(struct msm_mercury_device *pmercury_dev,
+	void __user *to)
+{
+
+
+	MCR_DBG("%s:%d] Enter\n", __func__, __LINE__);
+	msm_mercury_platform_p2v(in_buf_local.file, &in_buf_local.handle);
+	return 0;
+}
+
+int msm_mercury_ioctl_dump_regs(void)
+{
+	uint32_t mercury_regs[] = {
+		0x0000, 0x0008, 0x0010, 0x0014, 0x0018, 0x001C, 0x0020, 0x0024,
+		0x0030, 0x0034, 0x0040, 0x0050, 0x0054, 0x0058, 0x005C, 0x0060,
+		0x0064, 0x0070, 0x0080, 0x0084, 0x0088, 0x0258, 0x025C, 0x0260,
+		0x0264, 0x0200, 0x0204, 0x0208, 0x020C, 0x0210, 0x0214, 0x0218,
+		0x021C, 0x0220, 0x0224, 0x0228, 0x0100, 0x0104, 0x010C, 0x0110,
+		0x0114, 0x0118, 0x011C, 0x0120, 0x0124, 0x0128, 0x012C};
+
+	struct msm_mercury_hw_cmd hw_cmd;
+	int len = sizeof(mercury_regs)/4;
+	int i;
+
+	MCR_DBG("\n%s\n  (%d)%s()\n", __FILE__, __LINE__, __func__);
+
+	hw_cmd.mask = 0xFFFFFFFF;
+	hw_cmd.type = MSM_MERCURY_HW_CMD_TYPE_READ;
+	hw_cmd.n = 1;
+
+	for (i = 0; i < len; i++) {
+		hw_cmd.offset = mercury_regs[i];
+		msm_mercury_hw_exec_cmds(&hw_cmd, 1);
+	}
+
+	return 0;
+}
+
+int msm_mercury_ioctl_magic_code(struct msm_mercury_device *pmercury_dev,
+	void * __user arg)
+{
+	struct msm_mercury_hw_cmd hw_cmd;
+	int rc = 0;
+
+	rc = copy_from_user(&hw_cmd, arg, sizeof(struct msm_mercury_hw_cmd));
+	if (rc) {
+		printk(KERN_ERR "%s:%d] failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	hw_cmd.data = 0x600D600D;
+	rc = copy_to_user(arg, &hw_cmd, sizeof(hw_cmd));
+
+	if (rc) {
+		printk(KERN_ERR "%s:%d] failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+int msm_mercury_irq(int event, void *context, void *data)
+{
+	struct msm_mercury_device *pmercury_dev =
+		(struct msm_mercury_device *) context;
+
+	switch (event) {
+	case MSM_MERCURY_HW_IRQ_SW_RESET_ACK:
+		/* wake up evt_q*/
+		MCR_DBG("(%d)%s Wake up event q from Reset IRQ\n", __LINE__,
+			__func__);
+		msm_mercury_q_wakeup(&pmercury_dev->evt_q);
+		break;
+	case MSM_MERCURY_HW_IRQ_WR_EOI_ACK:
+		/*wake up evt_q*/
+		MCR_DBG("%d%s Wake up eventq from WR_EOI IRQ\n", __LINE__,
+			__func__);
+		msm_mercury_q_wr_eoi(&pmercury_dev->evt_q);
+		break;
+	case MSM_MERCURY_HW_IRQ_WR_ERR_ACK:
+		MCR_DBG("(%d)%s Wake up eventq from WR_ERR IRQ\n",
+			__LINE__, __func__);
+		msm_mercury_q_wr_err(&pmercury_dev->evt_q);
+		break;
+	default:
+		MCR_DBG("(%d)%s (default) Wake up event q from WR_ERR IRQ\n",
+			__LINE__, __func__);
+		msm_mercury_q_wr_err(&pmercury_dev->evt_q);
+	}
+	return 0;
+}
+
+int __msm_mercury_open(struct msm_mercury_device *pmercury_dev)
+{
+	int rc = 0;
+
+	mutex_lock(&pmercury_dev->lock);
+	if (pmercury_dev->open_count) {
+		/* only open once */
+		MCR_PR_ERR("%s:%d] busy\n", __func__, __LINE__);
+		mutex_unlock(&pmercury_dev->lock);
+		return -EBUSY;
+	}
+	pmercury_dev->open_count++;
+	mutex_unlock(&pmercury_dev->lock);
+
+	msm_mercury_core_irq_install(msm_mercury_irq);
+
+	rc = msm_mercury_platform_init(pmercury_dev->pdev,
+		&pmercury_dev->mem, &pmercury_dev->base,
+		&pmercury_dev->irq, msm_mercury_core_irq, pmercury_dev);
+	if (rc) {
+		MCR_PR_ERR("%s:%d] platform_init fail %d\n", __func__,
+			__LINE__, rc);
+		return rc;
+	}
+
+	MCR_DBG("\n%s:%d] platform resources - mem 0x%p, base 0x%p, irq %d\n",
+		__func__, __LINE__, pmercury_dev->mem, pmercury_dev->base,
+		pmercury_dev->irq);
+
+	msm_mercury_q_cleanup(&pmercury_dev->evt_q);
+	msm_mercury_core_init();
+
+	MCR_DBG("\n%s:%d] success\n", __func__, __LINE__);
+	return rc;
+}
+
+int __msm_mercury_release(struct msm_mercury_device *pmercury_dev)
+{
+	MCR_DBG("%s:%d] Enter\n", __func__, __LINE__);
+	mutex_lock(&pmercury_dev->lock);
+	if (!pmercury_dev->open_count) {
+		MCR_PR_ERR(KERN_ERR "%s: not opened\n", __func__);
+		mutex_unlock(&pmercury_dev->lock);
+		return -EINVAL;
+	}
+	pmercury_dev->open_count--;
+	mutex_unlock(&pmercury_dev->lock);
+
+	msm_mercury_q_cleanup(&pmercury_dev->evt_q);
+
+	if (pmercury_dev->open_count)
+		MCR_PR_ERR(KERN_ERR "%s: multiple opens\n", __func__);
+
+	if (pmercury_dev->open_count)
+		MCR_PR_ERR(KERN_ERR "%s: multiple opens\n", __func__);
+
+
+	msm_mercury_platform_release(pmercury_dev->mem, pmercury_dev->base,
+		pmercury_dev->irq, pmercury_dev);
+
+	return 0;
+}
+
+int msm_mercury_ioctl_hw_cmd(struct msm_mercury_device *pmercury_dev,
+	void * __user arg)
+{
+	struct msm_mercury_hw_cmd hw_cmd;
+	int is_copy_to_user;
+	int rc = 0;
+
+	rc = copy_from_user(&hw_cmd, arg, sizeof(struct msm_mercury_hw_cmd));
+	if (rc) {
+		MCR_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	is_copy_to_user = msm_mercury_hw_exec_cmds(&hw_cmd, 1);
+	if (is_copy_to_user >= 0) {
+		rc = copy_to_user(arg, &hw_cmd, sizeof(hw_cmd));
+
+		if (rc) {
+			MCR_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+			return -EFAULT;
+		}
+	}
+
+	return 0;
+}
+
+int msm_mercury_ioctl_hw_cmds(struct msm_mercury_device *pmercury_dev,
+	void * __user arg)
+{
+	int is_copy_to_user;
+	int len;
+	uint32_t m;
+	struct msm_mercury_hw_cmds *hw_cmds_p;
+	struct msm_mercury_hw_cmd *hw_cmd_p;
+
+	if (copy_from_user(&m, arg, sizeof(m))) {
+		MCR_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	len = sizeof(struct msm_mercury_hw_cmds) +
+		sizeof(struct msm_mercury_hw_cmd) * (m - 1);
+	hw_cmds_p = kmalloc(len, GFP_KERNEL);
+	if (!hw_cmds_p) {
+		MCR_PR_ERR("[%d]%s() no mem %d\n", __LINE__, __func__, len);
+		return -EFAULT;
+	}
+
+	if (copy_from_user(hw_cmds_p, arg, len)) {
+		MCR_PR_ERR("[%d]%s Fail to copy hw_cmds of len %d from user\n",
+			__LINE__, __func__, len);
+		kfree(hw_cmds_p);
+		return -EFAULT;
+	}
+
+	hw_cmd_p = (struct msm_mercury_hw_cmd *) &(hw_cmds_p->hw_cmd);
+
+	is_copy_to_user = msm_mercury_hw_exec_cmds(hw_cmd_p, m);
+
+	if (is_copy_to_user >= 0) {
+		if (copy_to_user(arg, hw_cmds_p, len)) {
+			MCR_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+			kfree(hw_cmds_p);
+			return -EFAULT;
+		}
+	}
+	kfree(hw_cmds_p);
+	return 0;
+}
+
+int msm_mercury_ioctl_reset(struct msm_mercury_device *pmercury_dev,
+	void * __user arg)
+{
+	int rc = 0;
+
+	MCR_DBG("(%d)%s() Enter\n", __LINE__, __func__);
+	rc = msm_mercury_core_reset();
+
+	return rc;
+}
+
+long __msm_mercury_ioctl(struct msm_mercury_device *pmercury_dev,
+	unsigned int cmd, unsigned long arg)
+{
+	int rc = 0;
+
+	switch (cmd) {
+	case MSM_MCR_IOCTL_GET_HW_VERSION:
+		rc = msm_mercury_ioctl_magic_code(pmercury_dev,
+			(void __user *) arg);
+		break;
+
+	case MSM_MCR_IOCTL_RESET:
+		rc = msm_mercury_ioctl_reset(pmercury_dev, (void __user *) arg);
+		break;
+
+	case MSM_MCR_IOCTL_EVT_GET:
+		rc = msm_mercury_evt_get(pmercury_dev, (void __user *) arg);
+		break;
+
+	case MSM_MCR_IOCTL_EVT_GET_UNBLOCK:
+		rc = msm_mercury_evt_get_unblock(pmercury_dev);
+		break;
+
+	case MSM_MCR_IOCTL_HW_CMD:
+		rc = msm_mercury_ioctl_hw_cmd(pmercury_dev,
+			(void __user *) arg);
+		break;
+
+	case MSM_MCR_IOCTL_HW_CMDS:
+		rc = msm_mercury_ioctl_hw_cmds(pmercury_dev,
+			(void __user *) arg);
+		break;
+
+	case MSM_MCR_IOCTL_INPUT_BUF_CFG:
+		rc = msm_mercury_input_buf_cfg(pmercury_dev,
+			(void __user *) arg);
+		break;
+
+	case MSM_MCR_IOCTL_OUTPUT_BUF_CFG:
+		rc = msm_mercury_output_buf_cfg(pmercury_dev,
+			(void __user *) arg);
+		break;
+
+	case MSM_MCR_IOCTL_OUTPUT_GET:
+		rc = msm_mercury_output_get(pmercury_dev,
+			(void __user *) arg);
+		break;
+
+	case MSM_MCR_IOCTL_INPUT_GET:
+		rc = msm_mercury_input_get(pmercury_dev,
+			(void __user *) arg);
+		break;
+
+	case MSM_MCR_IOCTL_TEST_DUMP_REGION:
+		rc = msm_mercury_ioctl_dump_regs();
+		break;
+
+	default:
+		printk(KERN_ERR "(%d)%s()  cmd = %d not supported\n",
+			__LINE__, __func__, _IOC_NR(cmd));
+		rc = -EINVAL;
+		break;
+	}
+	return rc;
+}
+
+struct msm_mercury_device *__msm_mercury_init(struct platform_device *pdev)
+{
+	struct msm_mercury_device *pmercury_dev;
+	pmercury_dev = kzalloc(sizeof(struct msm_mercury_device), GFP_ATOMIC);
+	if (!pmercury_dev) {
+		printk(KERN_ERR "%s:%d]no mem\n", __func__, __LINE__);
+		return NULL;
+	}
+
+	mutex_init(&pmercury_dev->lock);
+
+	pmercury_dev->pdev = pdev;
+
+	msm_mercury_q_init("evt_q", &pmercury_dev->evt_q);
+
+	return pmercury_dev;
+}
+
+int __msm_mercury_exit(struct msm_mercury_device *pmercury_dev)
+{
+	mutex_destroy(&pmercury_dev->lock);
+	kfree(pmercury_dev);
+	return 0;
+}
+
diff --git a/drivers/media/video/msm/mercury/msm_mercury_sync.h b/drivers/media/video/msm/mercury/msm_mercury_sync.h
new file mode 100644
index 0000000..f392907
--- /dev/null
+++ b/drivers/media/video/msm/mercury/msm_mercury_sync.h
@@ -0,0 +1,67 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_MERCURY_SYNC_H
+#define MSM_MERCURY_SYNC_H
+
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/cdev.h>
+#include <linux/platform_device.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include "msm_mercury_core.h"
+
+struct msm_mercury_q {
+		char const  *name;
+		struct list_head  q;
+		spinlock_t  lck;
+		wait_queue_head_t wait;
+		int        unblck;
+};
+
+struct msm_mercury_q_entry {
+		struct list_head list;
+		void   *data;
+};
+
+struct msm_mercury_device {
+		struct platform_device *pdev;
+		struct resource        *mem;
+		int                     irq;
+		void                   *base;
+		struct clk *mercury_clk[2];
+		struct device *device;
+		struct cdev   cdev;
+		struct mutex  lock;
+		char      open_count;
+		uint8_t       op_mode;
+
+		/* event queue including frame done & err indications*/
+		struct msm_mercury_q evt_q;
+		struct v4l2_subdev subdev;
+
+};
+
+int __msm_mercury_open(struct msm_mercury_device *pmcry_dev);
+int __msm_mercury_release(struct msm_mercury_device *pmcry_dev);
+
+long __msm_mercury_ioctl(struct msm_mercury_device *pmcry_dev,
+	unsigned int cmd, unsigned long arg);
+
+struct msm_mercury_device *__msm_mercury_init(struct platform_device *pdev);
+int __msm_mercury_exit(struct msm_mercury_device *pmcry_dev);
+int msm_mercury_ioctl_hw_cmds(struct msm_mercury_device *pmcry_dev,
+	void * __user arg);
+int msm_mercury_ioctl_hw_cmds_wo(struct msm_mercury_device *pmcry_dev,
+	void * __user arg);
+#endif /* MSM_MERCURY_SYNC_H */
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index 8500d47..caa2d32 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -20,6 +20,7 @@
 #include <linux/i2c.h>
 #include <linux/videodev2.h>
 #include <linux/pm_qos.h>
+#include <linux/wakelock.h>
 #include <media/v4l2-dev.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-device.h>
@@ -32,6 +33,7 @@
 #include <mach/camera.h>
 #include <media/msm_isp.h>
 #include <linux/ion.h>
+#include <linux/iommu.h>
 #include <media/msm_gestures.h>
 
 #define MSM_V4L2_DIMENSION_SIZE 96
@@ -49,6 +51,7 @@
 #define MSM_VFE_DRV_NAME "msm_vfe"
 #define MSM_VPE_DRV_NAME "msm_vpe"
 #define MSM_GEMINI_DRV_NAME "msm_gemini"
+#define MSM_MERCURY_DRV_NAME "msm_mercury"
 #define MSM_I2C_MUX_DRV_NAME "msm_cam_i2c_mux"
 
 #define MAX_NUM_CSIPHY_DEV 3
@@ -258,7 +261,7 @@
 	uint8_t opencnt; /*mctl ref count*/
 	const char *apps_id; /*ID for app that open this session*/
 	struct mutex lock;
-	struct pm_qos_request idle_pm_qos; /*avoid low power mode when active*/
+	struct wake_lock wake_lock; /*avoid low power mode when active*/
 	struct pm_qos_request pm_qos_req_list;
 	struct msm_mctl_pp_info pp_info;
 	struct msm_mctl_stats_t stats_info; /*stats pmem info*/
@@ -271,6 +274,12 @@
 
 	/*sensor info*/
 	struct msm_camera_sensor_info *sdata;
+
+	/*IOMMU mapped IMEM addresses*/
+	uint32_t ping_imem_y;
+	uint32_t ping_imem_cbcr;
+	uint32_t pong_imem_y;
+	uint32_t pong_imem_cbcr;
 };
 
 /* abstract camera device represents a VFE and connected sensor */
@@ -284,7 +293,8 @@
 		 unsigned int cmd, unsigned long arg);
 	int (*isp_notify)(struct v4l2_subdev *sd,
 		unsigned int notification, void *arg);
-	void (*isp_release)(struct v4l2_subdev *sd);
+	void (*isp_release)(struct msm_cam_media_controller *mctl,
+		struct v4l2_subdev *sd);
 	int (*isp_pp_cmd)(struct msm_cam_media_controller *pmctl,
 		 struct msm_mctl_pp_cmd, void *data);
 
diff --git a/drivers/media/video/msm/msm_camera.c b/drivers/media/video/msm/msm_camera.c
index ec1e253..624fe9b 100644
--- a/drivers/media/video/msm/msm_camera.c
+++ b/drivers/media/video/msm/msm_camera.c
@@ -36,7 +36,6 @@
 #include <linux/hrtimer.h>
 #include <linux/ion.h>
 
-#include <mach/cpuidle.h>
 DEFINE_MUTEX(ctrl_cmd_lock);
 
 #define CAMERA_STOP_VIDEO 58
@@ -3086,7 +3085,7 @@
 		msm_queue_drain(&sync->pict_q, list_pict);
 		msm_queue_drain(&sync->event_q, list_config);
 
-		pm_qos_update_request(&sync->idle_pm_qos, PM_QOS_DEFAULT_VALUE);
+		wake_unlock(&sync->wake_lock);
 		sync->apps_id = NULL;
 		sync->core_powered_on = 0;
 	}
@@ -3746,8 +3745,7 @@
 	sync->apps_id = apps_id;
 
 	if (!sync->core_powered_on && !is_controlnode) {
-		pm_qos_update_request(&sync->idle_pm_qos,
-				      msm_cpuidle_get_deep_idle_latency());
+		wake_lock(&sync->wake_lock);
 
 		msm_camvfe_fn_init(&sync->vfefn, sync);
 		if (sync->vfefn.vfe_init) {
@@ -3961,12 +3959,11 @@
 	msm_queue_init(&sync->pict_q, "pict");
 	msm_queue_init(&sync->vpe_q, "vpe");
 
-	pm_qos_add_request(&sync->idle_pm_qos, PM_QOS_CPU_DMA_LATENCY,
-				PM_QOS_DEFAULT_VALUE);
+	wake_lock_init(&sync->wake_lock, WAKE_LOCK_SUSPEND, "msm_camera");
 
 	rc = msm_camio_probe_on(pdev);
 	if (rc < 0) {
-		pm_qos_remove_request(&sync->idle_pm_qos);
+		wake_lock_destroy(&sync->wake_lock);
 		return rc;
 	}
 	rc = sensor_probe(sync->sdata, &sctrl);
@@ -3979,7 +3976,7 @@
 		pr_err("%s: failed to initialize %s\n",
 			__func__,
 			sync->sdata->sensor_name);
-		pm_qos_remove_request(&sync->idle_pm_qos);
+		wake_lock_destroy(&sync->wake_lock);
 		return rc;
 	}
 
@@ -3998,7 +3995,7 @@
 
 static int msm_sync_destroy(struct msm_sync *sync)
 {
-	pm_qos_remove_request(&sync->idle_pm_qos);
+	wake_lock_destroy(&sync->wake_lock);
 	return 0;
 }
 
diff --git a/drivers/media/video/msm/msm_isp.c b/drivers/media/video/msm/msm_isp.c
index 148f8b5..848beda 100644
--- a/drivers/media/video/msm/msm_isp.c
+++ b/drivers/media/video/msm/msm_isp.c
@@ -211,9 +211,9 @@
 	case VFE_MSG_V32_JPEG_CAPTURE:
 		D("%s:VFE_MSG_V32_JPEG_CAPTURE vdata->type %d\n", __func__,
 			vdata->type);
-		free_buf.num_planes = 1;
-		free_buf.ch_paddr[0] = IMEM_Y_PING_OFFSET;
-		free_buf.ch_paddr[1] = IMEM_CBCR_PING_OFFSET;
+		free_buf.num_planes = 2;
+		free_buf.ch_paddr[0] = pmctl->ping_imem_y;
+		free_buf.ch_paddr[1] = pmctl->ping_imem_cbcr;
 		cfgcmd.cmd_type = CMD_CONFIG_PING_ADDR;
 		cfgcmd.value = &vfe_id;
 		vfe_params.vfe_cfg = &cfgcmd;
@@ -222,8 +222,8 @@
 			__func__, free_buf.ch_paddr[0], free_buf.ch_paddr[1]);
 		rc = v4l2_subdev_call(sd, core, ioctl, 0, &vfe_params);
 		/* Write the same buffer into PONG */
-		free_buf.ch_paddr[0] = IMEM_Y_PONG_OFFSET;
-		free_buf.ch_paddr[1] = IMEM_CBCR_PONG_OFFSET;
+		free_buf.ch_paddr[0] = pmctl->pong_imem_y;
+		free_buf.ch_paddr[1] = pmctl->pong_imem_cbcr;
 		cfgcmd.cmd_type = CMD_CONFIG_PONG_ADDR;
 		cfgcmd.value = &vfe_id;
 		vfe_params.vfe_cfg = &cfgcmd;
@@ -467,19 +467,54 @@
 		return -EINVAL;
 	}
 
+	rc = msm_iommu_map_contig_buffer(
+		(unsigned long)IMEM_Y_PING_OFFSET, CAMERA_DOMAIN, GEN_POOL,
+		((IMEM_Y_SIZE + IMEM_CBCR_SIZE + 4095) & (~4095)),
+		SZ_4K, IOMMU_WRITE | IOMMU_READ,
+		(unsigned long *)&mctl->ping_imem_y);
+	mctl->ping_imem_cbcr = mctl->ping_imem_y + IMEM_Y_SIZE;
+	if (rc < 0) {
+		pr_err("%s: ping iommu mapping returned error %d\n",
+			__func__, rc);
+		mctl->ping_imem_y = 0;
+		mctl->ping_imem_cbcr = 0;
+	}
+	msm_iommu_map_contig_buffer(
+		(unsigned long)IMEM_Y_PONG_OFFSET, CAMERA_DOMAIN, GEN_POOL,
+		((IMEM_Y_SIZE + IMEM_CBCR_SIZE + 4095) & (~4095)),
+		SZ_4K, IOMMU_WRITE | IOMMU_READ,
+		(unsigned long *)&mctl->pong_imem_y);
+	mctl->pong_imem_cbcr = mctl->pong_imem_y + IMEM_Y_SIZE;
+	if (rc < 0) {
+		pr_err("%s: pong iommu mapping returned error %d\n",
+			 __func__, rc);
+		mctl->pong_imem_y = 0;
+		mctl->pong_imem_cbcr = 0;
+	}
+
 	rc = msm_vfe_subdev_init(sd, mctl);
 	if (rc < 0) {
 		pr_err("%s: vfe_init failed at %d\n",
-					__func__, rc);
+			__func__, rc);
 	}
 	return rc;
 }
 
-static void msm_isp_release(
+static void msm_isp_release(struct msm_cam_media_controller *mctl,
 	struct v4l2_subdev *sd)
 {
 	D("%s\n", __func__);
 	msm_vfe_subdev_release(sd);
+	msm_iommu_unmap_contig_buffer(mctl->ping_imem_y,
+		CAMERA_DOMAIN, GEN_POOL,
+		((IMEM_Y_SIZE + IMEM_CBCR_SIZE + 4095) & (~4095)));
+	msm_iommu_unmap_contig_buffer(mctl->pong_imem_y,
+		CAMERA_DOMAIN, GEN_POOL,
+		((IMEM_Y_SIZE + IMEM_CBCR_SIZE + 4095) & (~4095)));
+	mctl->ping_imem_y = 0;
+	mctl->ping_imem_cbcr = 0;
+	mctl->pong_imem_y = 0;
+	mctl->pong_imem_cbcr = 0;
 }
 
 static int msm_config_vfe(struct v4l2_subdev *sd,
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index 716575a..e6523cd 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -20,6 +20,7 @@
 #include <linux/videodev2.h>
 #include <linux/proc_fs.h>
 #include <linux/vmalloc.h>
+#include <linux/wakelock.h>
 
 #include <media/v4l2-dev.h>
 #include <media/v4l2-ioctl.h>
@@ -27,8 +28,6 @@
 
 #include <linux/android_pmem.h>
 
-#include <mach/cpuidle.h>
-
 #include "msm.h"
 #include "msm_cam_server.h"
 #include "msm_csid.h"
@@ -570,8 +569,7 @@
 	/* open sub devices - once only*/
 	if (!p_mctl->opencnt) {
 		uint32_t csid_version;
-		pm_qos_update_request(&p_mctl->idle_pm_qos,
-				      msm_cpuidle_get_deep_idle_latency());
+		wake_lock(&p_mctl->wake_lock);
 
 		csid_core = camdev->csid_core;
 		rc = msm_mctl_register_subdevs(p_mctl, csid_core);
@@ -667,12 +665,11 @@
 			}
 		}
 
-		if (camdev->is_ispif) {
-			pm_qos_add_request(&p_mctl->pm_qos_req_list,
-				PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
-			pm_qos_update_request(&p_mctl->pm_qos_req_list,
-				MSM_V4L2_SWFI_LATENCY);
-		}
+		pm_qos_add_request(&p_mctl->pm_qos_req_list,
+			PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
+		pm_qos_update_request(&p_mctl->pm_qos_req_list,
+			MSM_V4L2_SWFI_LATENCY);
+
 		p_mctl->apps_id = apps_id;
 		p_mctl->opencnt++;
 	} else {
@@ -694,7 +691,7 @@
 			pr_err("%s: axi release failed %d\n", __func__, rc);
 axi_init_failed:
 	if (p_mctl->isp_sdev && p_mctl->isp_sdev->isp_release)
-		p_mctl->isp_sdev->isp_release(p_mctl->isp_sdev->sd);
+		p_mctl->isp_sdev->isp_release(p_mctl, p_mctl->isp_sdev->sd);
 isp_open_failed:
 	if (camdev->is_csic)
 		if (v4l2_subdev_call(p_mctl->csic_sdev, core, ioctl,
@@ -720,7 +717,7 @@
 		pr_err("%s: sensor powerdown failed: %d\n", __func__, rc);
 sensor_sdev_failed:
 register_sdev_failed:
-	pm_qos_update_request(&p_mctl->idle_pm_qos, PM_QOS_DEFAULT_VALUE);
+	wake_unlock(&p_mctl->wake_lock);
 	mutex_unlock(&p_mctl->lock);
 	return rc;
 }
@@ -757,7 +754,7 @@
 	}
 
 	if (p_mctl->isp_sdev && p_mctl->isp_sdev->isp_release)
-		p_mctl->isp_sdev->isp_release(
+		p_mctl->isp_sdev->isp_release(p_mctl,
 			p_mctl->isp_sdev->sd);
 
 	if (camdev->is_csid) {
@@ -770,18 +767,16 @@
 			VIDIOC_MSM_CSIPHY_RELEASE, NULL);
 	}
 
-	if (camdev->is_ispif) {
-		pm_qos_update_request(&p_mctl->pm_qos_req_list,
-				PM_QOS_DEFAULT_VALUE);
-		pm_qos_remove_request(&p_mctl->pm_qos_req_list);
-	}
-
 	if (p_mctl->act_sdev)
 		v4l2_subdev_call(p_mctl->act_sdev, core, s_power, 0);
 
 	v4l2_subdev_call(p_mctl->sensor_sdev, core, s_power, 0);
 
-	pm_qos_update_request(&p_mctl->idle_pm_qos, PM_QOS_DEFAULT_VALUE);
+	pm_qos_update_request(&p_mctl->pm_qos_req_list,
+				PM_QOS_DEFAULT_VALUE);
+	pm_qos_remove_request(&p_mctl->pm_qos_req_list);
+
+	wake_unlock(&p_mctl->wake_lock);
 	return rc;
 }
 
@@ -865,8 +860,7 @@
 		return -EINVAL;
 	}
 
-	pm_qos_add_request(&pmctl->idle_pm_qos, PM_QOS_CPU_DMA_LATENCY,
-				PM_QOS_DEFAULT_VALUE);
+	wake_lock_init(&pmctl->wake_lock, WAKE_LOCK_SUSPEND, "msm_camera");
 	mutex_init(&pmctl->lock);
 	pmctl->opencnt = 0;
 
@@ -906,7 +900,7 @@
 	}
 
 	mutex_destroy(&pmctl->lock);
-	pm_qos_remove_request(&pmctl->idle_pm_qos);
+	wake_lock_destroy(&pmctl->wake_lock);
 	msm_cam_server_free_mctl(pcam->mctl_handle);
 	return rc;
 }
diff --git a/drivers/media/video/msm/sensors/ov5647_v4l2.c b/drivers/media/video/msm/sensors/ov5647_v4l2.c
index aac2f2b..9dfbf8d 100644
--- a/drivers/media/video/msm/sensors/ov5647_v4l2.c
+++ b/drivers/media/video/msm/sensors/ov5647_v4l2.c
@@ -458,7 +458,7 @@
 	CDBG(KERN_ERR "snapshot exposure seting 0x%x, 0x%x, %d"
 		, gain, line, line);
 	s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl);
-	if (line > 1964 && line <= 1968) {
+	if (line > 1964) {
 		msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
 			s_ctrl->sensor_output_reg_addr->frame_length_lines,
 			(uint8_t)((line+4) >> 8),
@@ -556,10 +556,10 @@
 static int32_t ov5647_write_prev_exp_gain(struct msm_sensor_ctrl_t *s_ctrl,
 						uint16_t gain, uint32_t line)
 {
-
-	static uint16_t max_line = 984;
 	u8 intg_time_hsb, intg_time_msb, intg_time_lsb;
 	uint8_t gain_lsb, gain_hsb;
+	uint32_t fl_lines = s_ctrl->curr_frame_length_lines;
+	uint8_t offset = s_ctrl->sensor_exp_gain_info->vert_offset;
 
 	CDBG(KERN_ERR "preview exposure setting 0x%x, 0x%x, %d",
 		 gain, line, line);
@@ -567,33 +567,23 @@
 	gain_lsb = (uint8_t) (gain);
 	gain_hsb = (uint8_t)((gain & 0x300)>>8);
 
+	fl_lines = (fl_lines * s_ctrl->fps_divider) / Q10;
+
 	s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl);
 
 	/* adjust frame rate */
-	if (line > 980 && line <= 984) {
-		msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+	if (line > (fl_lines - offset))
+		fl_lines = line + offset;
+
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
 		s_ctrl->sensor_output_reg_addr->frame_length_lines,
-		(uint8_t)((line+4) >> 8),
+		(uint8_t)(fl_lines >> 8),
 		MSM_CAMERA_I2C_BYTE_DATA);
 
-		msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
 		s_ctrl->sensor_output_reg_addr->frame_length_lines + 1,
-		(uint8_t)((line+4) & 0x00FF),
+		(uint8_t)(fl_lines & 0x00FF),
 		MSM_CAMERA_I2C_BYTE_DATA);
-		max_line = line + 4;
-	} else if (max_line > 984) {
-
-		msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
-		s_ctrl->sensor_output_reg_addr->frame_length_lines,
-		(uint8_t)(984 >> 8),
-		MSM_CAMERA_I2C_BYTE_DATA);
-
-		msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
-		s_ctrl->sensor_output_reg_addr->frame_length_lines + 1 ,
-		(uint8_t)(984 & 0x00FF),
-		MSM_CAMERA_I2C_BYTE_DATA);
-		max_line = 984;
-	}
 
 	line = line<<4;
 	/* ov5647 need this operation */
diff --git a/drivers/media/video/msm/wfd/enc-subdev.c b/drivers/media/video/msm/wfd/enc-subdev.c
index c94fa13..a5f2634 100644
--- a/drivers/media/video/msm/wfd/enc-subdev.c
+++ b/drivers/media/video/msm/wfd/enc-subdev.c
@@ -1297,17 +1297,33 @@
 	return rc;
 }
 static long venc_set_max_perf_level(struct video_client_ctx *client_ctx,
-		int val)
+		__s32 value)
 {
 	int rc = 0;
 	struct vcd_property_hdr vcd_property_hdr;
 	struct vcd_property_perf_level perf;
+	int level = 0;
+
+	switch (value) {
+	case V4L2_CID_MPEG_QCOM_PERF_LEVEL_PERFORMANCE:
+		level = VCD_PERF_LEVEL2;
+		break;
+	case V4L2_CID_MPEG_QCOM_PERF_LEVEL_TURBO:
+		level = VCD_PERF_LEVEL_TURBO;
+		break;
+	default:
+		WFD_MSG_ERR("Unknown performance level: %d\n", value);
+		rc = -ENOTSUPP;
+		goto err_set_perf_level;
+	}
+
 	vcd_property_hdr.prop_id = VCD_REQ_PERF_LEVEL;
 	vcd_property_hdr.sz =
 		sizeof(struct vcd_property_perf_level);
-	perf.level = VCD_PERF_LEVEL2;
+	perf.level = level;
 	rc = vcd_set_property(client_ctx->vcd_handle,
 				&vcd_property_hdr, &perf);
+err_set_perf_level:
 	return rc;
 }
 static long venc_set_header_mode(struct video_client_ctx *client_ctx,
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 7c61bf3..f4e7fda 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -936,6 +936,14 @@
 	  This is required to use certain other PM 8xxx features, such as GPIO
 	  and MPP.
 
+config MFD_PM8821_IRQ
+	bool "Support for Qualcomm PM8821 IRQ features"
+	default y if MFD_PM8821_CORE
+	help
+	  This is the IRQ driver for Qualcomm PM 8821 PMIC chips.
+
+	  This is required to use certain other PM 8821 features, such as MPPs.
+
 config TPS65911_COMPARATOR
 	tristate
 
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index e81e4b1..099e45f 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -137,6 +137,7 @@
 obj-$(CONFIG_MFD_PM8018_CORE) 	+= pm8018-core.o
 obj-$(CONFIG_MFD_PM8038_CORE) 	+= pm8038-core.o
 obj-$(CONFIG_MFD_PM8XXX_IRQ) 	+= pm8xxx-irq.o
+obj-$(CONFIG_MFD_PM8821_IRQ) 	+= pm8821-irq.o
 obj-$(CONFIG_MFD_PM8XXX_DEBUG) 	+= pm8xxx-debug.o
 obj-$(CONFIG_MFD_PM8XXX_PWM) 	+= pm8xxx-pwm.o
 obj-$(CONFIG_MFD_PM8XXX_MISC) 	+= pm8xxx-misc.o
diff --git a/drivers/mfd/marimba-tsadc.c b/drivers/mfd/marimba-tsadc.c
index 8a7b781..32b93e1 100644
--- a/drivers/mfd/marimba-tsadc.c
+++ b/drivers/mfd/marimba-tsadc.c
@@ -437,7 +437,7 @@
 	struct marimba_tsadc *tsadc = dev_get_drvdata(dev);
 
 	if (tsadc->clk_enabled == true) {
-		clk_disable(tsadc->codec_ssbi);
+		clk_disable_unprepare(tsadc->codec_ssbi);
 		tsadc->clk_enabled = false;
 	}
 
@@ -462,7 +462,7 @@
 	marimba_tsadc_configure(tsadc_dev);
 fail_shutdown:
 	if (tsadc->clk_enabled == false) {
-		ret = clk_enable(tsadc->codec_ssbi);
+		ret = clk_prepare_enable(tsadc->codec_ssbi);
 		if (ret == 0)
 			tsadc->clk_enabled = true;
 	}
@@ -475,7 +475,7 @@
 	struct marimba_tsadc *tsadc = dev_get_drvdata(dev);
 
 	if (tsadc->clk_enabled == false) {
-		rc = clk_enable(tsadc->codec_ssbi);
+		rc = clk_prepare_enable(tsadc->codec_ssbi);
 		if (rc != 0) {
 			pr_err("%s: Clk enable failed\n", __func__);
 			return rc;
@@ -515,7 +515,7 @@
 		tsadc->pdata->marimba_tsadc_power(0);
 fail_tsadc_power:
 	if (tsadc->clk_enabled == true) {
-		clk_disable(tsadc->codec_ssbi);
+		clk_disable_unprepare(tsadc->codec_ssbi);
 		tsadc->clk_enabled = false;
 	}
 	return rc;
@@ -591,7 +591,7 @@
 		rc = PTR_ERR(tsadc->codec_ssbi);
 		goto fail_clk_get;
 	}
-	rc = clk_enable(tsadc->codec_ssbi);
+	rc = clk_prepare_enable(tsadc->codec_ssbi);
 	if (rc != 0)
 		goto fail_clk_enable;
 
@@ -623,7 +623,7 @@
 	return rc;
 
 fail_add_subdev:
-	clk_disable(tsadc->codec_ssbi);
+	clk_disable_unprepare(tsadc->codec_ssbi);
 
 fail_clk_enable:
 	clk_put(tsadc->codec_ssbi);
@@ -647,7 +647,7 @@
 	device_init_wakeup(&pdev->dev, 0);
 
 	if (tsadc->clk_enabled == true)
-		clk_disable(tsadc->codec_ssbi);
+		clk_disable_unprepare(tsadc->codec_ssbi);
 
 	clk_put(tsadc->codec_ssbi);
 
diff --git a/drivers/mfd/pm8821-core.c b/drivers/mfd/pm8821-core.c
index df9d2e1..1d3c927a 100644
--- a/drivers/mfd/pm8821-core.c
+++ b/drivers/mfd/pm8821-core.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -27,7 +27,7 @@
 #define REG_HWREV_2		0x0E8  /* PMIC4 revision 2 */
 
 #define REG_MPP_BASE		0x050
-#define REG_IRQ_BASE		0x1BB
+#define REG_IRQ_BASE		0x100
 
 #define PM8821_VERSION_MASK	0xFFF0
 #define PM8821_VERSION_VALUE	0x0BF0
@@ -86,7 +86,7 @@
 	const struct pm8xxx_drvdata *pm8821_drvdata = dev_get_drvdata(dev);
 	const struct pm8821 *pmic = pm8821_drvdata->pm_chip_data;
 
-	return pm8xxx_get_irq_stat(pmic->irq_chip, irq);
+	return pm8821_get_irq_stat(pmic->irq_chip, irq);
 }
 
 static enum pm8xxx_version pm8821_get_version(const struct device *dev)
@@ -154,7 +154,7 @@
 		pdata->irq_pdata->irq_cdata.nirqs = PM8821_NR_IRQS;
 		pdata->irq_pdata->irq_cdata.base_addr = REG_IRQ_BASE;
 		irq_base = pdata->irq_pdata->irq_base;
-		irq_chip = pm8xxx_irq_init(pmic->dev, pdata->irq_pdata);
+		irq_chip = pm8821_irq_init(pmic->dev, pdata->irq_pdata);
 
 		if (IS_ERR(irq_chip)) {
 			pr_err("Failed to init interrupts ret=%ld\n",
@@ -186,7 +186,7 @@
 	return 0;
 bail:
 	if (pmic->irq_chip) {
-		pm8xxx_irq_exit(pmic->irq_chip);
+		pm8821_irq_exit(pmic->irq_chip);
 		pmic->irq_chip = NULL;
 	}
 	return ret;
@@ -281,7 +281,7 @@
 	if (pmic)
 		mfd_remove_devices(pmic->dev);
 	if (pmic->irq_chip) {
-		pm8xxx_irq_exit(pmic->irq_chip);
+		pm8821_irq_exit(pmic->irq_chip);
 		pmic->irq_chip = NULL;
 	}
 	platform_set_drvdata(pdev, NULL);
diff --git a/drivers/mfd/pm8821-irq.c b/drivers/mfd/pm8821-irq.c
new file mode 100644
index 0000000..2dcc792
--- /dev/null
+++ b/drivers/mfd/pm8821-irq.c
@@ -0,0 +1,425 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt)	"%s: " fmt, __func__
+
+#include <linux/export.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/mfd/pm8xxx/core.h>
+#include <linux/mfd/pm8xxx/pm8821-irq.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#define PM8821_TOTAL_IRQ_MASTERS	2
+#define PM8821_BLOCKS_PER_MASTER	7
+#define PM8821_IRQ_MASTER1_SET		0x01
+#define PM8821_IRQ_CLEAR_OFFSET		0x01
+#define PM8821_IRQ_RT_STATUS_OFFSET	0x0F
+#define PM8821_IRQ_MASK_REG_OFFSET	0x08
+#define SSBI_REG_ADDR_IRQ_MASTER0	0x30
+#define SSBI_REG_ADDR_IRQ_MASTER1	0xB0
+
+#define SSBI_REG_ADDR_IRQ_IT_STATUS(master_base, block) (master_base + block)
+
+/*
+ * Block 0 does not exist in PM8821 IRQ SSBI address space,
+ * IRQ0 is assigned to bit0 of block1.
+ */
+#define SSBI_REG_ADDR_IRQ_IT_CLEAR(master_base, block) \
+	(master_base + PM8821_IRQ_CLEAR_OFFSET + block)
+
+#define SSBI_REG_ADDR_IRQ_RT_STATUS(master_base, block) \
+	(master_base + PM8821_IRQ_RT_STATUS_OFFSET + block)
+
+#define SSBI_REG_ADDR_IRQ_MASK(master_base, block) \
+	(master_base + PM8821_IRQ_MASK_REG_OFFSET + block)
+
+struct pm_irq_chip {
+	struct device		*dev;
+	spinlock_t		pm_irq_lock;
+	unsigned int		base_addr;
+	unsigned int		devirq;
+	unsigned int		irq_base;
+	unsigned int		num_irqs;
+	int			masters[PM8821_TOTAL_IRQ_MASTERS];
+};
+
+static int pm8821_irq_masked_write(struct pm_irq_chip *chip, u16 addr,
+							u8 mask, u8 val)
+{
+	int rc;
+	u8 reg;
+
+	rc = pm8xxx_readb(chip->dev, addr, &reg);
+	if (rc) {
+		pr_err("read failed addr = %03X, rc = %d\n", addr, rc);
+		return rc;
+	}
+
+	reg &= ~mask;
+	reg |= val & mask;
+
+	rc = pm8xxx_writeb(chip->dev, addr, reg);
+	if (rc) {
+		pr_err("write failed addr = %03X, rc = %d\n", addr, rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+static int pm8821_read_master_irq(const struct pm_irq_chip *chip,
+						int m, u8 *master)
+{
+	return pm8xxx_readb(chip->dev, chip->masters[m], master);
+}
+
+static int pm8821_read_block_irq(struct pm_irq_chip *chip, int master,
+						u8 block, u8 *bits)
+{
+	int rc;
+
+	spin_lock(&chip->pm_irq_lock);
+
+	rc = pm8xxx_readb(chip->dev,
+	    SSBI_REG_ADDR_IRQ_IT_STATUS(chip->masters[master], block), bits);
+	if (rc)
+		pr_err("Failed Reading Status rc=%d\n", rc);
+
+	spin_unlock(&chip->pm_irq_lock);
+	return rc;
+}
+
+
+static int pm8821_irq_block_handler(struct pm_irq_chip *chip,
+					int master_number, int block)
+{
+	int pmirq, irq, i, ret;
+	u8 bits;
+
+	ret = pm8821_read_block_irq(chip, master_number, block, &bits);
+	if (ret) {
+		pr_err("Failed reading %d block ret=%d", block, ret);
+		return ret;
+	}
+	if (!bits) {
+		pr_err("block bit set in master but no irqs: %d", block);
+		return 0;
+	}
+
+	/* Convert block offset to global block number */
+	block += (master_number * PM8821_BLOCKS_PER_MASTER) - 1;
+
+	/* Check IRQ bits */
+	for (i = 0; i < 8; i++) {
+		if (bits & BIT(i)) {
+			pmirq = (block << 3) + i;
+			irq = pmirq + chip->irq_base;
+			generic_handle_irq(irq);
+		}
+	}
+	return 0;
+}
+
+static int pm8821_irq_read_master(struct pm_irq_chip *chip,
+				int master_number, u8 master_val)
+{
+	int ret = 0;
+	int block;
+
+	for (block = 1; block < 8; block++) {
+		if (master_val & BIT(block)) {
+			ret |= pm8821_irq_block_handler(chip,
+					master_number, block);
+		}
+	}
+
+	return ret;
+}
+
+static irqreturn_t pm8821_irq_handler(int irq, void *data)
+{
+	struct pm_irq_chip *chip = data;
+	int ret;
+	u8 master;
+
+	ret = pm8821_read_master_irq(chip, 0, &master);
+	if (ret) {
+		pr_err("Failed to read master 0 ret=%d\n", ret);
+		return ret;
+	}
+
+	if (master & ~PM8821_IRQ_MASTER1_SET)
+		pm8821_irq_read_master(chip, 0, master);
+
+	if (!(master & PM8821_IRQ_MASTER1_SET))
+		goto done;
+
+	ret = pm8821_read_master_irq(chip, 1, &master);
+	if (ret) {
+		pr_err("Failed to read master 1 ret=%d\n", ret);
+		return ret;
+	}
+
+	pm8821_irq_read_master(chip, 1, master);
+
+done:
+	return IRQ_HANDLED;
+}
+
+static void pm8821_irq_mask(struct irq_data *d)
+{
+	struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
+	unsigned int pmirq = d->irq - chip->irq_base;
+	int irq_bit, rc;
+	u8 block, master;
+
+	block = pmirq >> 3;
+	master = block / PM8821_BLOCKS_PER_MASTER;
+	irq_bit = pmirq % 8;
+	block %= PM8821_BLOCKS_PER_MASTER;
+
+	spin_lock(&chip->pm_irq_lock);
+
+	rc = pm8821_irq_masked_write(chip,
+		SSBI_REG_ADDR_IRQ_MASK(chip->masters[master], block),
+		BIT(irq_bit), BIT(irq_bit));
+
+	if (rc)
+		pr_err("Failed to read/write mask IRQ:%d rc=%d\n", pmirq, rc);
+
+	spin_unlock(&chip->pm_irq_lock);
+}
+
+static void pm8821_irq_mask_ack(struct irq_data *d)
+{
+	struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
+	unsigned int pmirq = d->irq - chip->irq_base;
+	int irq_bit, rc;
+	u8 block, master;
+
+	block = pmirq >> 3;
+	master = block / PM8821_BLOCKS_PER_MASTER;
+	irq_bit = pmirq % 8;
+	block %= PM8821_BLOCKS_PER_MASTER;
+
+	spin_lock(&chip->pm_irq_lock);
+
+	rc = pm8821_irq_masked_write(chip,
+		SSBI_REG_ADDR_IRQ_MASK(chip->masters[master], block),
+		BIT(irq_bit), BIT(irq_bit));
+
+	if (rc) {
+		pr_err("Failed to read/write mask IRQ:%d rc=%d\n", pmirq, rc);
+		goto fail;
+	}
+
+	rc = pm8821_irq_masked_write(chip,
+		SSBI_REG_ADDR_IRQ_IT_CLEAR(chip->masters[master], block),
+		BIT(irq_bit), BIT(irq_bit));
+
+	if (rc) {
+		pr_err("Failed to read/write IT_CLEAR IRQ:%d rc=%d\n",
+								pmirq, rc);
+	}
+
+fail:
+	spin_unlock(&chip->pm_irq_lock);
+}
+
+static void pm8821_irq_unmask(struct irq_data *d)
+{
+	struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
+	unsigned int pmirq = d->irq - chip->irq_base;
+	int irq_bit, rc;
+	u8 block, master;
+
+	block = pmirq >> 3;
+	master = block / PM8821_BLOCKS_PER_MASTER;
+	irq_bit = pmirq % 8;
+	block %= PM8821_BLOCKS_PER_MASTER;
+
+	spin_lock(&chip->pm_irq_lock);
+
+	rc = pm8821_irq_masked_write(chip,
+		SSBI_REG_ADDR_IRQ_MASK(chip->masters[master], block),
+		BIT(irq_bit), ~BIT(irq_bit));
+
+	if (rc)
+		pr_err("Failed to read/write unmask IRQ:%d rc=%d\n", pmirq, rc);
+
+	spin_unlock(&chip->pm_irq_lock);
+}
+
+static int pm8821_irq_set_type(struct irq_data *d, unsigned int flow_type)
+{
+	/*
+	 * PM8821 IRQ controller does not have explicit software support for
+	 * IRQ flow type.
+	 */
+	return 0;
+}
+
+static int pm8821_irq_set_wake(struct irq_data *d, unsigned int on)
+{
+	return 0;
+}
+
+static int pm8821_irq_read_line(struct irq_data *d)
+{
+	struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
+
+	return pm8821_get_irq_stat(chip, d->irq);
+}
+
+static struct irq_chip pm_irq_chip = {
+	.name		= "pm8821-irq",
+	.irq_mask	= pm8821_irq_mask,
+	.irq_mask_ack	= pm8821_irq_mask_ack,
+	.irq_unmask	= pm8821_irq_unmask,
+	.irq_set_type	= pm8821_irq_set_type,
+	.irq_set_wake	= pm8821_irq_set_wake,
+	.irq_read_line	= pm8821_irq_read_line,
+	.flags		= IRQCHIP_MASK_ON_SUSPEND,
+};
+
+/**
+ * pm8821_get_irq_stat - get the status of the irq line
+ * @chip: pointer to identify a pmic irq controller
+ * @irq: the irq number
+ *
+ * The pm8821 gpio and mpp rely on the interrupt block to read
+ * the values on their pins. This function is to facilitate reading
+ * the status of a gpio or an mpp line. The caller has to convert the
+ * gpio number to irq number.
+ *
+ * RETURNS:
+ * an int indicating the value read on that line
+ */
+int pm8821_get_irq_stat(struct pm_irq_chip *chip, int irq)
+{
+	int pmirq, rc;
+	u8 block, bits, bit, master;
+	unsigned long flags;
+
+	if (chip == NULL || irq < chip->irq_base
+	    || irq >= chip->irq_base + chip->num_irqs)
+		return -EINVAL;
+
+	pmirq = irq - chip->irq_base;
+
+	block = pmirq >> 3;
+	master = block / PM8821_BLOCKS_PER_MASTER;
+	bit = pmirq % 8;
+	block %= PM8821_BLOCKS_PER_MASTER;
+
+	spin_lock_irqsave(&chip->pm_irq_lock, flags);
+
+	rc = pm8xxx_readb(chip->dev,
+		SSBI_REG_ADDR_IRQ_RT_STATUS(chip->masters[master], block),
+		&bits);
+	if (rc) {
+		pr_err("Failed Configuring irq=%d pmirq=%d blk=%d rc=%d\n",
+						irq, pmirq, block, rc);
+		goto bail_out;
+	}
+
+	rc = (bits & BIT(bit)) ? 1 : 0;
+
+bail_out:
+	spin_unlock_irqrestore(&chip->pm_irq_lock, flags);
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(pm8821_get_irq_stat);
+
+struct pm_irq_chip *  __devinit pm8821_irq_init(struct device *dev,
+				const struct pm8xxx_irq_platform_data *pdata)
+{
+	struct pm_irq_chip	*chip;
+	int			devirq, rc, blocks, masters;
+	unsigned int		pmirq;
+
+	if (!pdata) {
+		pr_err("No platform data\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	devirq = pdata->devirq;
+	if (devirq < 0) {
+		pr_err("missing devirq\n");
+		rc = devirq;
+		return ERR_PTR(-EINVAL);
+	}
+
+	chip = kzalloc(sizeof(struct pm_irq_chip)
+			+ sizeof(u8) * pdata->irq_cdata.nirqs, GFP_KERNEL);
+	if (!chip) {
+		pr_err("Cannot alloc pm_irq_chip struct\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	chip->dev	= dev;
+	chip->devirq	= devirq;
+	chip->irq_base	= pdata->irq_base;
+	chip->num_irqs	= pdata->irq_cdata.nirqs;
+	chip->base_addr = pdata->irq_cdata.base_addr;
+	blocks		= DIV_ROUND_UP(pdata->irq_cdata.nirqs, 8);
+	masters		= DIV_ROUND_UP(blocks, PM8821_BLOCKS_PER_MASTER);
+	chip->masters[0] = chip->base_addr + SSBI_REG_ADDR_IRQ_MASTER0;
+	chip->masters[1] = chip->base_addr + SSBI_REG_ADDR_IRQ_MASTER1;
+
+	if (masters != PM8821_TOTAL_IRQ_MASTERS) {
+		pr_err("Unequal number of masters, passed: %d, "
+		"should have been: %d\n", masters, PM8821_TOTAL_IRQ_MASTERS);
+		kfree(chip);
+		return ERR_PTR(-EINVAL);
+	}
+
+	spin_lock_init(&chip->pm_irq_lock);
+
+	for (pmirq = 0; pmirq < chip->num_irqs; pmirq++) {
+		irq_set_chip_and_handler(chip->irq_base + pmirq,
+				&pm_irq_chip, handle_level_irq);
+		irq_set_chip_data(chip->irq_base + pmirq, chip);
+#ifdef CONFIG_ARM
+		set_irq_flags(chip->irq_base + pmirq, IRQF_VALID);
+#else
+		irq_set_noprobe(chip->irq_base + pmirq);
+#endif
+	}
+
+	if (devirq != 0) {
+		rc = request_irq(devirq, pm8821_irq_handler,
+			pdata->irq_trigger_flag, "pm8821_sec_irq", chip);
+		if (rc) {
+			pr_err("failed to request_irq for %d rc=%d\n",
+							devirq, rc);
+			kfree(chip);
+			return ERR_PTR(rc);
+		} else
+			irq_set_irq_wake(devirq, 1);
+	}
+
+	return chip;
+}
+
+int pm8821_irq_exit(struct pm_irq_chip *chip)
+{
+	irq_set_chained_handler(chip->devirq, NULL);
+	kfree(chip);
+	return 0;
+}
diff --git a/drivers/mfd/wcd9xxx-slimslave.c b/drivers/mfd/wcd9xxx-slimslave.c
index 538ca7c..705a57b 100644
--- a/drivers/mfd/wcd9xxx-slimslave.c
+++ b/drivers/mfd/wcd9xxx-slimslave.c
@@ -510,7 +510,6 @@
 		sph[i] = tx[idx].sph;
 		grph = tx[idx].grph;
 	}
-
 	/* slim_control_ch (REMOVE) */
 	ret = slim_control_ch(wcd9xxx->slim, grph, SLIM_CH_REMOVE, true);
 	if (ret < 0) {
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 02d1581..e7838f5 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -376,8 +376,8 @@
 {
 	host->curr.data = NULL;
 	host->curr.got_dataend = 0;
-	host->curr.wait_for_auto_prog_done = 0;
-	host->curr.got_auto_prog_done = 0;
+	host->curr.wait_for_auto_prog_done = false;
+	host->curr.got_auto_prog_done = false;
 	writel_relaxed(readl_relaxed(host->base + MMCIDATACTRL) &
 			(~(MCI_DPSM_ENABLE)), host->base + MMCIDATACTRL);
 	msmsdcc_sync_reg_wr(host); /* Allow the DPSM to be reset */
@@ -1118,7 +1118,7 @@
 	host->curr.xfer_remain = host->curr.xfer_size;
 	host->curr.data_xfered = 0;
 	host->curr.got_dataend = 0;
-	host->curr.got_auto_prog_done = 0;
+	host->curr.got_auto_prog_done = false;
 
 	datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
 
@@ -1644,7 +1644,7 @@
 					host->curr.cmd = cmd;
 			} else {
 				host->prog_enable = 0;
-				host->curr.wait_for_auto_prog_done = 0;
+				host->curr.wait_for_auto_prog_done = false;
 				if (host->dummy_52_needed)
 					host->dummy_52_needed = 0;
 				if (cmd->data && cmd->error)
@@ -1808,7 +1808,7 @@
 			/* Check for prog done */
 			if (host->curr.wait_for_auto_prog_done &&
 				(status & MCI_PROGDONE))
-				host->curr.got_auto_prog_done = 1;
+				host->curr.got_auto_prog_done = true;
 
 			/* Check for data done */
 			if (!host->curr.got_dataend && (status & MCI_DATAEND))
@@ -2026,35 +2026,26 @@
 			 msecs_to_jiffies(host->curr.req_tout_ms)));
 
 	host->curr.mrq = mrq;
+	if (mrq->sbc) {
+		mrq->sbc->mrq = mrq;
+		mrq->sbc->data = mrq->data;
+	}
+
 	if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
-		if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
-			mrq->cmd->opcode == 54) {
-			if (!host->sdcc_version)
+		if (host->sdcc_version) {
+			if (!mrq->stop)
+				host->curr.wait_for_auto_prog_done = true;
+		} else {
+			if ((mrq->cmd->opcode == SD_IO_RW_EXTENDED) ||
+			    (mrq->cmd->opcode == 54))
 				host->dummy_52_needed = 1;
-			else
-				/*
-				 * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
-				 * write operations using CMD53 and CMD54.
-				 * Setting this bit with CMD53 would
-				 * automatically triggers PROG_DONE interrupt
-				 * without the need of sending dummy CMD52.
-				 */
-				host->curr.wait_for_auto_prog_done = 1;
-		} else if (mrq->cmd->opcode == MMC_WRITE_BLOCK &&
-				host->sdcc_version) {
-			host->curr.wait_for_auto_prog_done = 1;
 		}
+
 		if ((mrq->cmd->opcode == MMC_WRITE_BLOCK) ||
 		    (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK))
 			host->curr.use_wr_data_pend = true;
 	}
 
-	if (mrq->data && mrq->sbc) {
-		mrq->sbc->mrq = mrq;
-		mrq->sbc->data = mrq->data;
-		if (mrq->data->flags & MMC_DATA_WRITE)
-			host->curr.wait_for_auto_prog_done = 1;
-	}
 	msmsdcc_request_start(host, mrq);
 
 	spin_unlock_irqrestore(&host->lock, flags);
@@ -4363,7 +4354,7 @@
 }
 
 static ssize_t
-set_polling(struct device *dev, struct device_attribute *attr,
+store_polling(struct device *dev, struct device_attribute *attr,
 		const char *buf, size_t count)
 {
 	struct mmc_host *mmc = dev_get_drvdata(dev);
@@ -4387,9 +4378,6 @@
 	return count;
 }
 
-static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
-		show_polling, set_polling);
-
 static ssize_t
 show_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
 			char *buf)
@@ -4402,7 +4390,7 @@
 }
 
 static ssize_t
-set_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
+store_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
 		const char *buf, size_t count)
 {
 	struct mmc_host *mmc = dev_get_drvdata(dev);
@@ -4419,20 +4407,6 @@
 	return count;
 }
 
-static DEVICE_ATTR(max_bus_bw, S_IRUGO | S_IWUSR,
-		show_sdcc_to_mem_max_bus_bw, set_sdcc_to_mem_max_bus_bw);
-
-static struct attribute *dev_attrs[] = {
-	&dev_attr_max_bus_bw.attr,
-	/* if polling is enabled, this will be filled with dev_attr_polling */
-	NULL,
-	NULL,
-};
-
-static struct attribute_group dev_attr_grp = {
-	.attrs = dev_attrs,
-};
-
 #ifdef CONFIG_HAS_EARLYSUSPEND
 static void msmsdcc_early_suspend(struct early_suspend *h)
 {
@@ -4568,7 +4542,7 @@
 			}
 		} else {
 			host->prog_enable = 0;
-			host->curr.wait_for_auto_prog_done = 0;
+			host->curr.wait_for_auto_prog_done = false;
 			msmsdcc_reset_and_restore(host);
 			msmsdcc_request_end(host, mrq);
 		}
@@ -5189,14 +5163,30 @@
 #if defined(CONFIG_DEBUG_FS)
 	msmsdcc_dbg_createhost(host);
 #endif
-	if (!plat->status_irq)
-		dev_attrs[1] = &dev_attr_polling.attr;
 
-	ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
+	host->max_bus_bw.show = show_sdcc_to_mem_max_bus_bw;
+	host->max_bus_bw.store = store_sdcc_to_mem_max_bus_bw;
+	sysfs_attr_init(&host->max_bus_bw.attr);
+	host->max_bus_bw.attr.name = "max_bus_bw";
+	host->max_bus_bw.attr.mode = S_IRUGO | S_IWUSR;
+	ret = device_create_file(&pdev->dev, &host->max_bus_bw);
 	if (ret)
 		goto platform_irq_free;
+
+	if (!plat->status_irq) {
+		host->polling.show = show_polling;
+		host->polling.store = store_polling;
+		sysfs_attr_init(&host->polling.attr);
+		host->polling.attr.name = "polling";
+		host->polling.attr.mode = S_IRUGO | S_IWUSR;
+		ret = device_create_file(&pdev->dev, &host->polling);
+		if (ret)
+			goto remove_max_bus_bw_file;
+	}
 	return 0;
 
+ remove_max_bus_bw_file:
+	device_remove_file(&pdev->dev, &host->max_bus_bw);
  platform_irq_free:
 	del_timer_sync(&host->req_tout_timer);
 	pm_runtime_disable(&(pdev)->dev);
@@ -5273,8 +5263,9 @@
 	DBG(host, "Removing SDCC device = %d\n", pdev->id);
 	plat = host->plat;
 
+	device_remove_file(&pdev->dev, &host->max_bus_bw);
 	if (!plat->status_irq)
-		sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
+		device_remove_file(&pdev->dev, &host->polling);
 
 	del_timer_sync(&host->req_tout_timer);
 	tasklet_kill(&host->dma_tlet);
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index ecf4950..1fe5129 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -293,8 +293,8 @@
 	unsigned int		xfer_remain;	/* Bytes remaining to send */
 	unsigned int		data_xfered;	/* Bytes acked by BLKEND irq */
 	int			got_dataend;
-	int			wait_for_auto_prog_done;
-	int			got_auto_prog_done;
+	bool			wait_for_auto_prog_done;
+	bool			got_auto_prog_done;
 	bool			use_wr_data_pend;
 	int			user_pages;
 	u32			req_tout_ms;
@@ -411,6 +411,8 @@
 	struct mutex clk_mutex;
 	bool pending_resume;
 	struct msmsdcc_msm_bus_vote msm_bus_vote;
+	struct device_attribute	max_bus_bw;
+	struct device_attribute	polling;
 };
 
 int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave);
diff --git a/drivers/spmi/spmi.c b/drivers/spmi/spmi.c
index 3f63532..0342b97 100644
--- a/drivers/spmi/spmi.c
+++ b/drivers/spmi/spmi.c
@@ -20,6 +20,7 @@
 #include <linux/platform_device.h>
 #include <linux/spmi.h>
 #include <linux/module.h>
+#include <linux/pm_runtime.h>
 
 struct spmii_boardinfo {
 	struct list_head	list;
diff --git a/drivers/tty/n_smux.c b/drivers/tty/n_smux.c
index df335d2..65bcb08 100644
--- a/drivers/tty/n_smux.c
+++ b/drivers/tty/n_smux.c
@@ -25,13 +25,14 @@
 #include <linux/types.h>
 #include <linux/platform_device.h>
 #include <linux/delay.h>
+#include <mach/subsystem_notif.h>
+#include <mach/subsystem_restart.h>
 #include <mach/msm_serial_hs.h>
 #include "smux_private.h"
 #include "smux_loopback.h"
 
 #define SMUX_NOTIFY_FIFO_SIZE	128
 #define SMUX_TX_QUEUE_SIZE	256
-#define SMUX_GET_RX_BUFF_MAX_RETRY_CNT 2
 #define SMUX_WM_LOW 2
 #define SMUX_WM_HIGH 4
 #define SMUX_PKT_LOG_SIZE 80
@@ -49,6 +50,10 @@
 /* inactivity timeout for no rx/tx activity */
 #define SMUX_INACTIVITY_TIMEOUT_MS 1000
 
+/* RX get_rx_buffer retry timeout values */
+#define SMUX_RX_RETRY_MIN_MS (1 << 0)  /* 1 ms */
+#define SMUX_RX_RETRY_MAX_MS (1 << 10) /* 1024 ms */
+
 enum {
 	MSM_SMUX_DEBUG = 1U << 0,
 	MSM_SMUX_INFO = 1U << 1,
@@ -175,6 +180,11 @@
 	int (*get_rx_buffer)(void *priv, void **pkt_priv, void **buffer,
 								int size);
 
+	/* RX Info */
+	struct list_head rx_retry_queue;
+	unsigned rx_retry_queue_cnt;
+	struct delayed_work rx_retry_work;
+
 	/* TX Info */
 	spinlock_t tx_lock_lhb2;
 	struct list_head tx_queue;
@@ -198,25 +208,54 @@
 };
 
 /**
+ * Get RX Buffer Retry structure.
+ *
+ * This is used for clients that are unable to provide an RX buffer
+ * immediately.  This temporary structure will be used to temporarily hold the
+ * data and perform a retry.
+ */
+struct smux_rx_pkt_retry {
+	struct smux_pkt_t *pkt;
+	struct list_head rx_retry_list;
+	unsigned timeout_in_ms;
+};
+
+/**
+ * Receive worker data structure.
+ *
+ * One instance is created for every call to smux_rx_state_machine.
+ */
+struct smux_rx_worker_data {
+	const unsigned char *data;
+	int len;
+	int flag;
+
+	struct work_struct work;
+	struct completion work_complete;
+};
+
+/**
  * Line discipline and module structure.
  *
  * Only one instance since multiple instances of line discipline are not
  * allowed.
  */
 struct smux_ldisc_t {
-	spinlock_t lock_lha0;
+	struct mutex mutex_lha0;
 
 	int is_initialized;
 	int in_reset;
 	int ld_open_count;
 	struct tty_struct *tty;
 
-	/* RX State Machine */
-	spinlock_t rx_lock_lha1;
+	/* RX State Machine (singled-threaded access by smux_rx_wq) */
 	unsigned char recv_buf[SMUX_MAX_PKT_SIZE];
 	unsigned int recv_len;
 	unsigned int pkt_remain;
 	unsigned rx_state;
+
+	/* RX Activity - accessed by multiple threads */
+	spinlock_t rx_lock_lha1;
 	unsigned rx_activity_flag;
 
 	/* TX / Power */
@@ -226,6 +265,7 @@
 	unsigned pwr_wakeup_delay_us;
 	unsigned tx_activity_flag;
 	unsigned powerdown_enabled;
+	struct list_head power_queue;
 };
 
 
@@ -259,10 +299,13 @@
 static DEFINE_SPINLOCK(notify_lock_lhc1);
 
 static struct workqueue_struct *smux_tx_wq;
+static struct workqueue_struct *smux_rx_wq;
 static void smux_tx_worker(struct work_struct *work);
 static DECLARE_WORK(smux_tx_work, smux_tx_worker);
 
 static void smux_wakeup_worker(struct work_struct *work);
+static void smux_rx_retry_worker(struct work_struct *work);
+static void smux_rx_worker(struct work_struct *work);
 static DECLARE_WORK(smux_wakeup_work, smux_wakeup_worker);
 static DECLARE_DELAYED_WORK(smux_wakeup_delayed_work, smux_wakeup_worker);
 
@@ -275,6 +318,13 @@
 static void list_channel(struct smux_lch_t *ch);
 static int smux_send_status_cmd(struct smux_lch_t *ch);
 static int smux_dispatch_rx_pkt(struct smux_pkt_t *pkt);
+static void smux_flush_tty(void);
+static void smux_purge_ch_tx_queue(struct smux_lch_t *ch);
+static int schedule_notify(uint8_t lcid, int event,
+			const union notifier_metadata *metadata);
+static int ssr_notifier_cb(struct notifier_block *this,
+				unsigned long code,
+				void *data);
 
 /**
  * Convert TTY Error Flags to string for logging purposes.
@@ -321,6 +371,7 @@
 
 	smux_notify_wq = create_singlethread_workqueue("smux_notify_wq");
 	smux_tx_wq = create_singlethread_workqueue("smux_tx_wq");
+	smux_rx_wq = create_singlethread_workqueue("smux_rx_wq");
 
 	if (IS_ERR(smux_notify_wq) || IS_ERR(smux_tx_wq)) {
 		SMUX_DBG("%s: create_singlethread_workqueue ENOMEM\n",
@@ -354,6 +405,10 @@
 		ch->notify = 0;
 		ch->get_rx_buffer = 0;
 
+		INIT_LIST_HEAD(&ch->rx_retry_queue);
+		ch->rx_retry_queue_cnt = 0;
+		INIT_DELAYED_WORK(&ch->rx_retry_work, smux_rx_retry_worker);
+
 		spin_lock_init(&ch->tx_lock_lhb2);
 		INIT_LIST_HEAD(&ch->tx_queue);
 		INIT_LIST_HEAD(&ch->tx_ready_list);
@@ -364,6 +419,82 @@
 	return 0;
 }
 
+/**
+ * Empty and cleanup all SMUX logical channels for subsystem restart or line
+ * discipline disconnect.
+ */
+static void smux_lch_purge(void)
+{
+	struct smux_lch_t *ch;
+	unsigned long flags;
+	int i;
+
+	/* Empty TX ready list */
+	spin_lock_irqsave(&smux.tx_lock_lha2, flags);
+	while (!list_empty(&smux.lch_tx_ready_list)) {
+		SMUX_DBG("%s: emptying ready list %p\n",
+				__func__, smux.lch_tx_ready_list.next);
+		ch = list_first_entry(&smux.lch_tx_ready_list,
+						struct smux_lch_t,
+						tx_ready_list);
+		list_del(&ch->tx_ready_list);
+		INIT_LIST_HEAD(&ch->tx_ready_list);
+	}
+
+	/* Purge Power Queue */
+	while (!list_empty(&smux.power_queue)) {
+		struct smux_pkt_t *pkt;
+
+		pkt =  list_first_entry(&smux.power_queue,
+						struct smux_pkt_t,
+						list);
+		SMUX_DBG("%s: emptying power queue pkt=%p\n",
+				__func__, pkt);
+		smux_free_pkt(pkt);
+	}
+	spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
+
+	/* Close all ports */
+	for (i = 0 ; i < SMUX_NUM_LOGICAL_CHANNELS; i++) {
+		ch = &smux_lch[i];
+		SMUX_DBG("%s: cleaning up lcid %d\n", __func__, i);
+
+		spin_lock_irqsave(&ch->state_lock_lhb1, flags);
+
+		/* Purge TX queue */
+		spin_lock(&ch->tx_lock_lhb2);
+		smux_purge_ch_tx_queue(ch);
+		spin_unlock(&ch->tx_lock_lhb2);
+
+		/* Notify user of disconnect and reset channel state */
+		if (ch->local_state == SMUX_LCH_LOCAL_OPENED ||
+			ch->local_state == SMUX_LCH_LOCAL_CLOSING) {
+			union notifier_metadata meta;
+
+			meta.disconnected.is_ssr = smux.in_reset;
+			schedule_notify(ch->lcid, SMUX_DISCONNECTED, &meta);
+		}
+
+		ch->local_state = SMUX_LCH_LOCAL_CLOSED;
+		ch->local_mode = SMUX_LCH_MODE_NORMAL;
+		ch->remote_state = SMUX_LCH_REMOTE_CLOSED;
+		ch->remote_mode = SMUX_LCH_MODE_NORMAL;
+		ch->tx_flow_control = 0;
+
+		/* Purge RX retry queue */
+		if (ch->rx_retry_queue_cnt)
+			queue_delayed_work(smux_rx_wq, &ch->rx_retry_work, 0);
+
+		spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+	}
+
+	/* Flush TX/RX workqueues */
+	SMUX_DBG("%s: flushing tx wq\n", __func__);
+	flush_workqueue(smux_tx_wq);
+	SMUX_DBG("%s: flushing rx wq\n", __func__);
+	flush_workqueue(smux_rx_wq);
+}
+
 int smux_assert_lch_id(uint32_t lcid)
 {
 	if (lcid >= SMUX_NUM_LOGICAL_CHANNELS)
@@ -785,7 +916,7 @@
 	if (!data)
 		return 0;
 
-	while (len > 0) {
+	while (len > 0 && !smux.in_reset) {
 		data_written = smux.tty->ops->write(smux.tty, data, len);
 		if (data_written >= 0) {
 			len -= data_written;
@@ -799,8 +930,6 @@
 		if (len)
 			tty_wait_until_sent(smux.tty,
 				msecs_to_jiffies(TTY_BUFFER_FULL_WAIT_MS));
-
-		/* FUTURE - add SSR logic */
 	}
 	return 0;
 }
@@ -866,19 +995,20 @@
  */
 static void smux_send_byte(char ch)
 {
-	struct smux_pkt_t pkt;
+	struct smux_pkt_t *pkt;
 
-	smux_init_pkt(&pkt);
+	pkt = smux_alloc_pkt();
+	if (!pkt) {
+		pr_err("%s: alloc failure for byte %x\n", __func__, ch);
+		return;
+	}
+	pkt->hdr.cmd = SMUX_CMD_BYTE;
+	pkt->hdr.flags = ch;
+	pkt->hdr.lcid = SMUX_BROADCAST_LCID;
+	pkt->hdr.flags = ch;
 
-	pkt.hdr.cmd = SMUX_CMD_BYTE;
-	pkt.hdr.flags = ch;
-	pkt.hdr.lcid = 0;
-	pkt.hdr.flags = ch;
-	SMUX_LOG_PKT_TX(&pkt);
-	if (!smux_byte_loopback)
-		smux_tx_tty(&pkt);
-	else
-		smux_tx_loopback(&pkt);
+	list_add_tail(&pkt->list, &smux.power_queue);
+	queue_work(smux_tx_wq, &smux_tx_work);
 }
 
 /**
@@ -888,8 +1018,6 @@
  * @lcid Logical channel ID for packet
  *
  * @returns 0 for success
- *
- * Called with rx_lock_lha1 locked.
  */
 static int smux_receive_byte(char ch, int lcid)
 {
@@ -931,8 +1059,6 @@
  * @pkt  Received packet
  *
  * @returns 0 for success
- *
- * Called with rx_lock_lha1 already locked.
  */
 static int smux_handle_rx_open_ack(struct smux_pkt_t *pkt)
 {
@@ -1021,8 +1147,6 @@
  * @pkt  Received packet
  *
  * @returns 0 for success
- *
- * Called with rx_lock_lha1 already locked.
  */
 static int smux_handle_rx_open_cmd(struct smux_pkt_t *pkt)
 {
@@ -1030,6 +1154,7 @@
 	int ret;
 	struct smux_lch_t *ch;
 	struct smux_pkt_t *ack_pkt;
+	unsigned long flags;
 	int tx_ready = 0;
 	int enable_powerdown = 0;
 
@@ -1039,7 +1164,7 @@
 	lcid = pkt->hdr.lcid;
 	ch = &smux_lch[lcid];
 
-	spin_lock(&ch->state_lock_lhb1);
+	spin_lock_irqsave(&ch->state_lock_lhb1, flags);
 
 	if (ch->remote_state == SMUX_LCH_REMOTE_CLOSED) {
 		SMUX_DBG("lcid %d remote state 0x%x -> 0x%x\n", lcid,
@@ -1100,13 +1225,16 @@
 	}
 
 out:
-	spin_unlock(&ch->state_lock_lhb1);
+	spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
 
 	if (enable_powerdown) {
-		spin_lock(&smux.tx_lock_lha2);
-		smux.powerdown_enabled = 1;
-		SMUX_DBG("%s: enabling power-collapse support\n", __func__);
-		spin_unlock(&smux.tx_lock_lha2);
+		spin_lock_irqsave(&smux.tx_lock_lha2, flags);
+		if (!smux.powerdown_enabled) {
+			smux.powerdown_enabled = 1;
+			SMUX_DBG("%s: enabling power-collapse support\n",
+					__func__);
+		}
+		spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
 	}
 
 	if (tx_ready)
@@ -1121,8 +1249,6 @@
  * @pkt  Received packet
  *
  * @returns 0 for success
- *
- * Called with rx_lock_lha1 already locked.
  */
 static int smux_handle_rx_close_cmd(struct smux_pkt_t *pkt)
 {
@@ -1131,6 +1257,7 @@
 	struct smux_lch_t *ch;
 	struct smux_pkt_t *ack_pkt;
 	union notifier_metadata meta_disconnected;
+	unsigned long flags;
 	int tx_ready = 0;
 
 	if (pkt->hdr.flags & SMUX_CMD_CLOSE_ACK)
@@ -1140,7 +1267,7 @@
 	ch = &smux_lch[lcid];
 	meta_disconnected.disconnected.is_ssr = 0;
 
-	spin_lock(&ch->state_lock_lhb1);
+	spin_lock_irqsave(&ch->state_lock_lhb1, flags);
 	if (ch->remote_state == SMUX_LCH_REMOTE_OPENED) {
 		SMUX_DBG("lcid %d remote state 0x%x -> 0x%x\n", lcid,
 				SMUX_LCH_REMOTE_OPENED,
@@ -1191,7 +1318,7 @@
 		ret = -EINVAL;
 	}
 out:
-	spin_unlock(&ch->state_lock_lhb1);
+	spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
 	if (tx_ready)
 		list_channel(ch);
 
@@ -1204,25 +1331,30 @@
  * @pkt  Received packet
  *
  * @returns 0 for success
- *
- * Called with rx_lock_lha1 already locked.
  */
 static int smux_handle_rx_data_cmd(struct smux_pkt_t *pkt)
 {
 	uint8_t lcid;
-	int ret;
-	int i;
+	int ret = 0;
+	int do_retry = 0;
 	int tmp;
 	int rx_len;
 	struct smux_lch_t *ch;
 	union notifier_metadata metadata;
 	int remote_loopback;
-	int tx_ready = 0;
 	struct smux_pkt_t *ack_pkt;
 	unsigned long flags;
 
-	if (!pkt || smux_assert_lch_id(pkt->hdr.lcid))
-		return -ENXIO;
+	if (!pkt || smux_assert_lch_id(pkt->hdr.lcid)) {
+		ret = -ENXIO;
+		goto out;
+	}
+
+	rx_len = pkt->hdr.payload_len;
+	if (rx_len == 0) {
+		ret = -EINVAL;
+		goto out;
+	}
 
 	lcid = pkt->hdr.lcid;
 	ch = &smux_lch[lcid];
@@ -1234,6 +1366,7 @@
 		pr_err("smux: ch %d error data on local state 0x%x",
 					lcid, ch->local_state);
 		ret = -EIO;
+		spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
 		goto out;
 	}
 
@@ -1241,69 +1374,110 @@
 		pr_err("smux: ch %d error data on remote state 0x%x",
 					lcid, ch->remote_state);
 		ret = -EIO;
+		spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
 		goto out;
 	}
 
-	rx_len = pkt->hdr.payload_len;
-	if (rx_len == 0) {
-		ret = -EINVAL;
-		goto out;
+	if (!list_empty(&ch->rx_retry_queue)) {
+		do_retry = 1;
+		if ((ch->rx_retry_queue_cnt + 1) > SMUX_RX_RETRY_MAX_PKTS) {
+			/* retry queue full */
+			schedule_notify(lcid, SMUX_READ_FAIL, NULL);
+			ret = -ENOMEM;
+			spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+			goto out;
+		}
 	}
+	spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
 
-	for (i = 0; i < SMUX_GET_RX_BUFF_MAX_RETRY_CNT; ++i) {
+	if (remote_loopback) {
+		/* Echo the data back to the remote client. */
+		ack_pkt = smux_alloc_pkt();
+		if (ack_pkt) {
+			ack_pkt->hdr.lcid = lcid;
+			ack_pkt->hdr.cmd = SMUX_CMD_DATA;
+			ack_pkt->hdr.flags = 0;
+			ack_pkt->hdr.payload_len = pkt->hdr.payload_len;
+			if (ack_pkt->hdr.payload_len) {
+				smux_alloc_pkt_payload(ack_pkt);
+				memcpy(ack_pkt->payload, pkt->payload,
+						ack_pkt->hdr.payload_len);
+			}
+			ack_pkt->hdr.pad_len = pkt->hdr.pad_len;
+			smux_tx_queue(ack_pkt, ch, 0);
+			list_channel(ch);
+		} else {
+			pr_err("%s: Remote loopack allocation failure\n",
+					__func__);
+		}
+	} else if (!do_retry) {
+		/* request buffer from client */
 		metadata.read.pkt_priv = 0;
 		metadata.read.buffer = 0;
+		tmp = ch->get_rx_buffer(ch->priv,
+				(void **)&metadata.read.pkt_priv,
+				(void **)&metadata.read.buffer,
+				rx_len);
 
-		if (!remote_loopback) {
-			tmp = ch->get_rx_buffer(ch->priv,
-					(void **)&metadata.read.pkt_priv,
-					(void **)&metadata.read.buffer,
+		if (tmp == 0 && metadata.read.buffer) {
+			/* place data into RX buffer */
+			memcpy(metadata.read.buffer, pkt->payload,
 					rx_len);
-			if (tmp == 0 && metadata.read.buffer) {
-				/* place data into RX buffer */
-				memcpy(metadata.read.buffer, pkt->payload,
-								rx_len);
-				metadata.read.len = rx_len;
-				schedule_notify(lcid, SMUX_READ_DONE,
-								&metadata);
-				ret = 0;
-				break;
-			} else if (tmp == -EAGAIN) {
-				ret = -ENOMEM;
-			} else if (tmp < 0) {
-				schedule_notify(lcid, SMUX_READ_FAIL, NULL);
-				ret = -ENOMEM;
-				break;
-			} else if (!metadata.read.buffer) {
-				pr_err("%s: get_rx_buffer() buffer is NULL\n",
-					__func__);
-				ret = -ENOMEM;
-			}
-		} else {
-			/* Echo the data back to the remote client. */
-			ack_pkt = smux_alloc_pkt();
-			if (ack_pkt) {
-				ack_pkt->hdr.lcid = lcid;
-				ack_pkt->hdr.cmd = SMUX_CMD_DATA;
-				ack_pkt->hdr.flags = 0;
-				ack_pkt->hdr.payload_len = pkt->hdr.payload_len;
-				ack_pkt->payload = pkt->payload;
-				ack_pkt->hdr.pad_len = pkt->hdr.pad_len;
-				smux_tx_queue(ack_pkt, ch, 0);
-				tx_ready = 1;
-			} else {
-				pr_err("%s: Remote loopack allocation failure\n",
-						__func__);
-			}
+			metadata.read.len = rx_len;
+			schedule_notify(lcid, SMUX_READ_DONE,
+							&metadata);
+		} else if (tmp == -EAGAIN ||
+				(tmp == 0 && !metadata.read.buffer)) {
+			/* buffer allocation failed - add to retry queue */
+			do_retry = 1;
+		} else if (tmp < 0) {
+			schedule_notify(lcid, SMUX_READ_FAIL, NULL);
+			ret = -ENOMEM;
 		}
 	}
 
+	if (do_retry) {
+		struct smux_rx_pkt_retry *retry;
+
+		retry = kmalloc(sizeof(struct smux_rx_pkt_retry), GFP_KERNEL);
+		if (!retry) {
+			pr_err("%s: retry alloc failure\n", __func__);
+			ret = -ENOMEM;
+			schedule_notify(lcid, SMUX_READ_FAIL, NULL);
+			goto out;
+		}
+		INIT_LIST_HEAD(&retry->rx_retry_list);
+		retry->timeout_in_ms = SMUX_RX_RETRY_MIN_MS;
+
+		/* copy packet */
+		retry->pkt = smux_alloc_pkt();
+		if (!retry->pkt) {
+			kfree(retry);
+			pr_err("%s: pkt alloc failure\n", __func__);
+			ret = -ENOMEM;
+			schedule_notify(lcid, SMUX_READ_FAIL, NULL);
+			goto out;
+		}
+		retry->pkt->hdr.lcid = lcid;
+		retry->pkt->hdr.payload_len = pkt->hdr.payload_len;
+		retry->pkt->hdr.pad_len = pkt->hdr.pad_len;
+		if (retry->pkt->hdr.payload_len) {
+			smux_alloc_pkt_payload(retry->pkt);
+			memcpy(retry->pkt->payload, pkt->payload,
+					retry->pkt->hdr.payload_len);
+		}
+
+		/* add to retry queue */
+		spin_lock_irqsave(&ch->state_lock_lhb1, flags);
+		list_add_tail(&retry->rx_retry_list, &ch->rx_retry_queue);
+		++ch->rx_retry_queue_cnt;
+		if (ch->rx_retry_queue_cnt == 1)
+			queue_delayed_work(smux_rx_wq, &ch->rx_retry_work,
+				msecs_to_jiffies(retry->timeout_in_ms));
+		spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+	}
+
 out:
-	spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
-
-	if (tx_ready)
-		list_channel(ch);
-
 	return ret;
 }
 
@@ -1322,8 +1496,10 @@
 	union notifier_metadata metadata;
 	unsigned long flags;
 
-	if (!pkt || smux_assert_lch_id(pkt->hdr.lcid))
+	if (!pkt || smux_assert_lch_id(pkt->hdr.lcid)) {
+		pr_err("%s: invalid packet or channel id\n", __func__);
 		return -ENXIO;
+	}
 
 	lcid = pkt->hdr.lcid;
 	ch = &smux_lch[lcid];
@@ -1359,8 +1535,6 @@
  * @pkt  Received packet
  *
  * @returns 0 for success
- *
- * Called with rx_lock_lha1 already locked.
  */
 static int smux_handle_rx_status_cmd(struct smux_pkt_t *pkt)
 {
@@ -1416,15 +1590,13 @@
  * @pkt  Received packet
  *
  * @returns 0 for success
- *
- * Called with rx_lock_lha1 already locked.
  */
 static int smux_handle_rx_power_cmd(struct smux_pkt_t *pkt)
 {
-	int tx_ready = 0;
 	struct smux_pkt_t *ack_pkt = NULL;
+	unsigned long flags;
 
-	spin_lock(&smux.tx_lock_lha2);
+	spin_lock_irqsave(&smux.tx_lock_lha2, flags);
 	if (pkt->hdr.flags & SMUX_CMD_PWR_CTL_ACK) {
 		/* local sleep request ack */
 		if (smux.power_state == SMUX_PWR_TURNING_OFF) {
@@ -1438,7 +1610,17 @@
 					__func__, smux.power_state);
 		}
 	} else {
-		/* remote sleep request */
+		/*
+		 * Remote sleep request
+		 *
+		 * Even if we have data pending, we need to transition to the
+		 * POWER_OFF state and then perform a wakeup since the remote
+		 * side has requested a power-down.
+		 *
+		 * The state here is set to SMUX_PWR_TURNING_OFF_FLUSH and
+		 * the TX thread will set the state to SMUX_PWR_TURNING_OFF
+		 * when it sends the packet.
+		 */
 		if (smux.power_state == SMUX_PWR_ON
 			|| smux.power_state == SMUX_PWR_TURNING_OFF) {
 			ack_pkt = smux_alloc_pkt();
@@ -1447,28 +1629,22 @@
 						smux.power_state,
 						SMUX_PWR_TURNING_OFF_FLUSH);
 
-				/* send power-down request */
+				smux.power_state = SMUX_PWR_TURNING_OFF_FLUSH;
+
+				/* send power-down ack */
 				ack_pkt->hdr.cmd = SMUX_CMD_PWR_CTL;
 				ack_pkt->hdr.flags = SMUX_CMD_PWR_CTL_ACK;
-				ack_pkt->hdr.lcid = pkt->hdr.lcid;
-				smux_tx_queue(ack_pkt,
-					      &smux_lch[ack_pkt->hdr.lcid], 0);
-				tx_ready = 1;
-				smux.power_state = SMUX_PWR_TURNING_OFF_FLUSH;
-				queue_delayed_work(smux_tx_wq,
-					&smux_delayed_inactivity_work,
-					msecs_to_jiffies(
-						SMUX_INACTIVITY_TIMEOUT_MS));
+				ack_pkt->hdr.lcid = SMUX_BROADCAST_LCID;
+				list_add_tail(&ack_pkt->list,
+						&smux.power_queue);
+				queue_work(smux_tx_wq, &smux_tx_work);
 			}
 		} else {
 			pr_err("%s: sleep request invalid in state %d\n",
 					__func__, smux.power_state);
 		}
 	}
-	spin_unlock(&smux.tx_lock_lha2);
-
-	if (tx_ready)
-		list_channel(&smux_lch[ack_pkt->hdr.lcid]);
+	spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
 
 	return 0;
 }
@@ -1479,8 +1655,6 @@
  * @pkt Packet to process
  *
  * @returns 0 for success
- *
- * Called with rx_lock_lha1 already locked.
  */
 static int smux_dispatch_rx_pkt(struct smux_pkt_t *pkt)
 {
@@ -1527,8 +1701,6 @@
  * @len     Length of the data
  *
  * @returns 0 for success
- *
- * Called with rx_lock_lha1 already locked.
  */
 static int smux_deserialize(unsigned char *data, int len)
 {
@@ -1562,12 +1734,12 @@
 
 /**
  * Handle wakeup request byte.
- *
- * Called with rx_lock_lha1 already locked.
  */
 static void smux_handle_wakeup_req(void)
 {
-	spin_lock(&smux.tx_lock_lha2);
+	unsigned long flags;
+
+	spin_lock_irqsave(&smux.tx_lock_lha2, flags);
 	if (smux.power_state == SMUX_PWR_OFF
 		|| smux.power_state == SMUX_PWR_TURNING_ON) {
 		/* wakeup system */
@@ -1582,17 +1754,17 @@
 	} else {
 		smux_send_byte(SMUX_WAKEUP_ACK);
 	}
-	spin_unlock(&smux.tx_lock_lha2);
+	spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
 }
 
 /**
  * Handle wakeup request ack.
- *
- * Called with rx_lock_lha1 already locked.
  */
 static void smux_handle_wakeup_ack(void)
 {
-	spin_lock(&smux.tx_lock_lha2);
+	unsigned long flags;
+
+	spin_lock_irqsave(&smux.tx_lock_lha2, flags);
 	if (smux.power_state == SMUX_PWR_TURNING_ON) {
 		/* received response to wakeup request */
 		SMUX_DBG("%s: Power %d->%d\n", __func__,
@@ -1607,7 +1779,7 @@
 		pr_err("%s: wakeup request ack invalid in state %d\n",
 				__func__, smux.power_state);
 	}
-	spin_unlock(&smux.tx_lock_lha2);
+	spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
 }
 
 /**
@@ -1617,8 +1789,6 @@
  * @len   Length of the data
  * @used  Return value of length processed
  * @flag  Error flag - TTY_NORMAL 0 for no failure
- *
- * Called with rx_lock_lha1 locked.
  */
 static void smux_rx_handle_idle(const unsigned char *data,
 		int len, int *used, int flag)
@@ -1666,8 +1836,6 @@
  * @len   Length of the data
  * @used  Return value of length processed
  * @flag  Error flag - TTY_NORMAL 0 for no failure
- *
- * Called with rx_lock_lha1 locked.
  */
 static void smux_rx_handle_magic(const unsigned char *data,
 		int len, int *used, int flag)
@@ -1707,8 +1875,6 @@
  * @len   Length of the data
  * @used  Return value of length processed
  * @flag  Error flag - TTY_NORMAL 0 for no failure
- *
- * Called with rx_lock_lha1 locked.
  */
 static void smux_rx_handle_hdr(const unsigned char *data,
 		int len, int *used, int flag)
@@ -1744,8 +1910,6 @@
  * @len   Length of the data
  * @used  Return value of length processed
  * @flag  Error flag - TTY_NORMAL 0 for no failure
- *
- * Called with rx_lock_lha1 locked.
  */
 static void smux_rx_handle_pkt_payload(const unsigned char *data,
 		int len, int *used, int flag)
@@ -1784,47 +1948,20 @@
  * @data Pointer to data block
  * @len  Length of data
  * @flag TTY_NORMAL (0) for no error, otherwise TTY Error Flag
- *
- * Called with rx_lock_lha1 locked.
  */
 void smux_rx_state_machine(const unsigned char *data,
 						int len, int flag)
 {
-	unsigned long flags;
-	int used;
-	int initial_rx_state;
+	struct smux_rx_worker_data work;
 
+	work.data = data;
+	work.len = len;
+	work.flag = flag;
+	INIT_WORK_ONSTACK(&work.work, smux_rx_worker);
+	work.work_complete = COMPLETION_INITIALIZER_ONSTACK(work.work_complete);
 
-	SMUX_DBG("%s: %p, len=%d, flag=%d\n", __func__, data, len, flag);
-	spin_lock_irqsave(&smux.rx_lock_lha1, flags);
-	used = 0;
-	smux.rx_activity_flag = 1;
-	do {
-		SMUX_DBG("%s: state %d; %d of %d\n",
-				__func__, smux.rx_state, used, len);
-		initial_rx_state = smux.rx_state;
-
-		switch (smux.rx_state) {
-		case SMUX_RX_IDLE:
-			smux_rx_handle_idle(data, len, &used, flag);
-			break;
-		case SMUX_RX_MAGIC:
-			smux_rx_handle_magic(data, len, &used, flag);
-			break;
-		case SMUX_RX_HDR:
-			smux_rx_handle_hdr(data, len, &used, flag);
-			break;
-		case SMUX_RX_PAYLOAD:
-			smux_rx_handle_pkt_payload(data, len, &used, flag);
-			break;
-		default:
-			SMUX_DBG("%s: invalid state %d\n",
-					__func__, smux.rx_state);
-			smux.rx_state = SMUX_RX_IDLE;
-			break;
-		}
-	} while (used < len || smux.rx_state != initial_rx_state);
-	spin_unlock_irqrestore(&smux.rx_lock_lha1, flags);
+	queue_work(smux_rx_wq, &work.work);
+	wait_for_completion(&work.work_complete);
 }
 
 /**
@@ -1889,6 +2026,67 @@
 }
 
 /**
+ * Flush pending TTY TX data.
+ */
+static void smux_flush_tty(void)
+{
+	if (!smux.tty) {
+		pr_err("%s: ldisc not loaded\n", __func__);
+		return;
+	}
+
+	tty_wait_until_sent(smux.tty,
+			msecs_to_jiffies(TTY_BUFFER_FULL_WAIT_MS));
+
+	if (tty_chars_in_buffer(smux.tty) > 0)
+		pr_err("%s: unable to flush UART queue\n", __func__);
+}
+
+/**
+ * Purge TX queue for logical channel.
+ *
+ * @ch     Logical channel pointer
+ *
+ * Must be called with the following spinlocks locked:
+ *  state_lock_lhb1
+ *  tx_lock_lhb2
+ */
+static void smux_purge_ch_tx_queue(struct smux_lch_t *ch)
+{
+	struct smux_pkt_t *pkt;
+	int send_disconnect = 0;
+
+	while (!list_empty(&ch->tx_queue)) {
+		pkt = list_first_entry(&ch->tx_queue, struct smux_pkt_t,
+							list);
+		list_del(&pkt->list);
+
+		if (pkt->hdr.cmd == SMUX_CMD_OPEN_LCH) {
+			/* Open was never sent, just force to closed state */
+			ch->local_state = SMUX_LCH_LOCAL_CLOSED;
+			send_disconnect = 1;
+		} else if (pkt->hdr.cmd == SMUX_CMD_DATA) {
+			/* Notify client of failed write */
+			union notifier_metadata meta_write;
+
+			meta_write.write.pkt_priv = pkt->priv;
+			meta_write.write.buffer = pkt->payload;
+			meta_write.write.len = pkt->hdr.payload_len;
+			schedule_notify(ch->lcid, SMUX_WRITE_FAIL, &meta_write);
+		}
+		smux_free_pkt(pkt);
+	}
+
+	if (send_disconnect) {
+		union notifier_metadata meta_disconnected;
+
+		meta_disconnected.disconnected.is_ssr = smux.in_reset;
+		schedule_notify(ch->lcid, SMUX_DISCONNECTED,
+			&meta_disconnected);
+	}
+}
+
+/**
  * Power-up the UART.
  */
 static void smux_uart_power_on(void)
@@ -1934,7 +2132,7 @@
 	unsigned wakeup_delay;
 	int complete = 0;
 
-	for (;;) {
+	while (!smux.in_reset) {
 		spin_lock_irqsave(&smux.tx_lock_lha2, flags);
 		if (smux.power_state == SMUX_PWR_ON) {
 			/* wakeup complete */
@@ -1990,7 +2188,6 @@
  */
 static void smux_inactivity_worker(struct work_struct *work)
 {
-	int tx_ready = 0;
 	struct smux_pkt_t *pkt;
 	unsigned long flags;
 
@@ -2012,11 +2209,13 @@
 					/* send power-down request */
 					pkt->hdr.cmd = SMUX_CMD_PWR_CTL;
 					pkt->hdr.flags = 0;
-					pkt->hdr.lcid = 0;
-					smux_tx_queue(pkt,
-						&smux_lch[SMUX_TEST_LCID],
-						0);
-					tx_ready = 1;
+					pkt->hdr.lcid = SMUX_BROADCAST_LCID;
+					list_add_tail(&pkt->list,
+							&smux.power_queue);
+					queue_work(smux_tx_wq, &smux_tx_work);
+				} else {
+					pr_err("%s: packet alloc failed\n",
+							__func__);
 				}
 			}
 		} else {
@@ -2027,21 +2226,26 @@
 	smux.tx_activity_flag = 0;
 	smux.rx_activity_flag = 0;
 
-	spin_unlock(&smux.tx_lock_lha2);
-	spin_unlock_irqrestore(&smux.rx_lock_lha1, flags);
-
-	if (tx_ready)
-		list_channel(&smux_lch[SMUX_TEST_LCID]);
-
-	if ((smux.power_state == SMUX_PWR_OFF_FLUSH) ||
-	    (smux.power_state == SMUX_PWR_TURNING_OFF_FLUSH)) {
+	if (smux.power_state == SMUX_PWR_OFF_FLUSH) {
 		/* ready to power-down the UART */
+		smux.power_state = SMUX_PWR_OFF;
 		SMUX_DBG("%s: Power %d->%d\n", __func__,
 				smux.power_state, SMUX_PWR_OFF);
+
+		/* if data is pending, schedule a new wakeup */
+		if (!list_empty(&smux.lch_tx_ready_list) ||
+		   !list_empty(&smux.power_queue))
+			queue_work(smux_tx_wq, &smux_tx_work);
+
+		spin_unlock(&smux.tx_lock_lha2);
+		spin_unlock_irqrestore(&smux.rx_lock_lha1, flags);
+
+		/* flush UART output queue and power down */
+		smux_flush_tty();
 		smux_uart_power_off();
-		spin_lock_irqsave(&smux.tx_lock_lha2, flags);
-		smux.power_state = SMUX_PWR_OFF;
-		spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
+	} else {
+		spin_unlock(&smux.tx_lock_lha2);
+		spin_unlock_irqrestore(&smux.rx_lock_lha1, flags);
 	}
 
 	/* reschedule inactivity worker */
@@ -2051,6 +2255,167 @@
 }
 
 /**
+ * Remove RX retry packet from channel and free it.
+ *
+ * Must be called with state_lock_lhb1 locked.
+ *
+ * @ch    Channel for retry packet
+ * @retry Retry packet to remove
+ */
+void smux_remove_rx_retry(struct smux_lch_t *ch,
+		struct smux_rx_pkt_retry *retry)
+{
+	list_del(&retry->rx_retry_list);
+	--ch->rx_retry_queue_cnt;
+	smux_free_pkt(retry->pkt);
+	kfree(retry);
+}
+
+/**
+ * RX worker handles all receive operations.
+ *
+ * @work  Work structure contained in TBD structure
+ */
+static void smux_rx_worker(struct work_struct *work)
+{
+	unsigned long flags;
+	int used;
+	int initial_rx_state;
+	struct smux_rx_worker_data *w;
+	const unsigned char *data;
+	int len;
+	int flag;
+
+	w =  container_of(work, struct smux_rx_worker_data, work);
+	data = w->data;
+	len = w->len;
+	flag = w->flag;
+
+	spin_lock_irqsave(&smux.rx_lock_lha1, flags);
+	smux.rx_activity_flag = 1;
+	spin_unlock_irqrestore(&smux.rx_lock_lha1, flags);
+
+	SMUX_DBG("%s: %p, len=%d, flag=%d\n", __func__, data, len, flag);
+	used = 0;
+	do {
+		SMUX_DBG("%s: state %d; %d of %d\n",
+				__func__, smux.rx_state, used, len);
+		initial_rx_state = smux.rx_state;
+
+		switch (smux.rx_state) {
+		case SMUX_RX_IDLE:
+			smux_rx_handle_idle(data, len, &used, flag);
+			break;
+		case SMUX_RX_MAGIC:
+			smux_rx_handle_magic(data, len, &used, flag);
+			break;
+		case SMUX_RX_HDR:
+			smux_rx_handle_hdr(data, len, &used, flag);
+			break;
+		case SMUX_RX_PAYLOAD:
+			smux_rx_handle_pkt_payload(data, len, &used, flag);
+			break;
+		default:
+			SMUX_DBG("%s: invalid state %d\n",
+					__func__, smux.rx_state);
+			smux.rx_state = SMUX_RX_IDLE;
+			break;
+		}
+	} while (used < len || smux.rx_state != initial_rx_state);
+
+	complete(&w->work_complete);
+}
+
+/**
+ * RX Retry worker handles retrying get_rx_buffer calls that previously failed
+ * because the client was not ready (-EAGAIN).
+ *
+ * @work  Work structure contained in smux_lch_t structure
+ */
+static void smux_rx_retry_worker(struct work_struct *work)
+{
+	struct smux_lch_t *ch;
+	struct smux_rx_pkt_retry *retry;
+	union notifier_metadata metadata;
+	int tmp;
+	unsigned long flags;
+
+	ch = container_of(work, struct smux_lch_t, rx_retry_work.work);
+
+	/* get next retry packet */
+	spin_lock_irqsave(&ch->state_lock_lhb1, flags);
+	if (ch->local_state != SMUX_LCH_LOCAL_OPENED) {
+		/* port has been closed - remove all retries */
+		while (!list_empty(&ch->rx_retry_queue)) {
+			retry = list_first_entry(&ch->rx_retry_queue,
+						struct smux_rx_pkt_retry,
+						rx_retry_list);
+			smux_remove_rx_retry(ch, retry);
+		}
+	}
+
+	if (list_empty(&ch->rx_retry_queue)) {
+		SMUX_DBG("%s: retry list empty for channel %d\n",
+				__func__, ch->lcid);
+		spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+		return;
+	}
+	retry = list_first_entry(&ch->rx_retry_queue,
+					struct smux_rx_pkt_retry,
+					rx_retry_list);
+	spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+
+	SMUX_DBG("%s: retrying rx pkt %p\n", __func__, retry);
+	metadata.read.pkt_priv = 0;
+	metadata.read.buffer = 0;
+	tmp = ch->get_rx_buffer(ch->priv,
+			(void **)&metadata.read.pkt_priv,
+			(void **)&metadata.read.buffer,
+			retry->pkt->hdr.payload_len);
+	if (tmp == 0 && metadata.read.buffer) {
+		/* have valid RX buffer */
+		memcpy(metadata.read.buffer, retry->pkt->payload,
+						retry->pkt->hdr.payload_len);
+		metadata.read.len = retry->pkt->hdr.payload_len;
+
+		spin_lock_irqsave(&ch->state_lock_lhb1, flags);
+		smux_remove_rx_retry(ch, retry);
+		spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+
+		schedule_notify(ch->lcid, SMUX_READ_DONE, &metadata);
+	} else if (tmp == -EAGAIN ||
+			(tmp == 0 && !metadata.read.buffer)) {
+		/* retry again */
+		retry->timeout_in_ms <<= 1;
+		if (retry->timeout_in_ms > SMUX_RX_RETRY_MAX_MS) {
+			/* timed out */
+			spin_lock_irqsave(&ch->state_lock_lhb1, flags);
+			smux_remove_rx_retry(ch, retry);
+			schedule_notify(ch->lcid, SMUX_READ_FAIL, NULL);
+			spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+		}
+	} else {
+		/* client error - drop packet */
+		spin_lock_irqsave(&ch->state_lock_lhb1, flags);
+		smux_remove_rx_retry(ch, retry);
+		spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+
+		schedule_notify(ch->lcid, SMUX_READ_FAIL, NULL);
+	}
+
+	/* schedule next retry */
+	spin_lock_irqsave(&ch->state_lock_lhb1, flags);
+	if (!list_empty(&ch->rx_retry_queue)) {
+		retry = list_first_entry(&ch->rx_retry_queue,
+						struct smux_rx_pkt_retry,
+						rx_retry_list);
+		queue_delayed_work(smux_rx_wq, &ch->rx_retry_work,
+				msecs_to_jiffies(retry->timeout_in_ms));
+	}
+	spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+}
+
+/**
  * Transmit worker handles serializing and transmitting packets onto the
  * underlying transport.
  *
@@ -2078,27 +2443,17 @@
 	 * inserting after the tail.  The locks can then be released
 	 * while the packet is processed.
 	 */
-	for (;;) {
+	while (!smux.in_reset) {
 		pkt = NULL;
 		low_wm_notif = 0;
 
-		/* get the next ready channel */
 		spin_lock_irqsave(&smux.tx_lock_lha2, flags);
-		if (list_empty(&smux.lch_tx_ready_list)) {
-			/* no ready channels */
-			SMUX_DBG("%s: no more ready channels, exiting\n",
-					__func__);
-			spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
-			break;
-		}
-		smux.tx_activity_flag = 1;
 
-		if (smux.power_state != SMUX_PWR_ON
-			&& smux.power_state != SMUX_PWR_TURNING_OFF
-			&& smux.power_state != SMUX_PWR_TURNING_OFF_FLUSH) {
-			/* Link isn't ready to transmit */
-			if (smux.power_state == SMUX_PWR_OFF) {
-				/* link is off, trigger wakeup */
+		/* handle wakeup if needed */
+		if (smux.power_state == SMUX_PWR_OFF) {
+			if (!list_empty(&smux.lch_tx_ready_list) ||
+			   !list_empty(&smux.power_queue)) {
+				/* data to transmit, do wakeup */
 				smux.pwr_wakeup_delay_us = 1;
 				SMUX_DBG("%s: Power %d->%d\n", __func__,
 						smux.power_state,
@@ -2109,15 +2464,65 @@
 				smux_uart_power_on();
 				queue_work(smux_tx_wq, &smux_wakeup_work);
 			} else {
-				SMUX_DBG("%s: can not tx with power state %d\n",
-						__func__,
-						smux.power_state);
+				/* no activity -- stay asleep */
 				spin_unlock_irqrestore(&smux.tx_lock_lha2,
 						flags);
 			}
 			break;
 		}
 
+		/* process any pending power packets */
+		if (!list_empty(&smux.power_queue)) {
+			pkt = list_first_entry(&smux.power_queue,
+					struct smux_pkt_t, list);
+			list_del(&pkt->list);
+			spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
+
+			/* send the packet */
+			SMUX_LOG_PKT_TX(pkt);
+			if (!smux_byte_loopback) {
+				smux_tx_tty(pkt);
+				smux_flush_tty();
+			} else {
+				smux_tx_loopback(pkt);
+			}
+
+			/* Adjust power state if this is a flush command */
+			spin_lock_irqsave(&smux.tx_lock_lha2, flags);
+			if (smux.power_state == SMUX_PWR_TURNING_OFF_FLUSH &&
+				pkt->hdr.cmd == SMUX_CMD_PWR_CTL &&
+				(pkt->hdr.flags & SMUX_CMD_PWR_CTL_ACK)) {
+				SMUX_DBG("%s: Power %d->%d\n", __func__,
+						smux.power_state,
+						SMUX_PWR_OFF_FLUSH);
+				smux.power_state = SMUX_PWR_OFF_FLUSH;
+				queue_work(smux_tx_wq, &smux_inactivity_work);
+			}
+			spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
+
+			smux_free_pkt(pkt);
+			continue;
+		}
+
+		/* get the next ready channel */
+		if (list_empty(&smux.lch_tx_ready_list)) {
+			/* no ready channels */
+			SMUX_DBG("%s: no more ready channels, exiting\n",
+					__func__);
+			spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
+			break;
+		}
+		smux.tx_activity_flag = 1;
+
+		if (smux.power_state != SMUX_PWR_ON) {
+			/* channel not ready to transmit */
+			SMUX_DBG("%s: can not tx with power state %d\n",
+					__func__,
+					smux.power_state);
+			spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
+			break;
+		}
+
 		/* get the next packet to send and rotate channel list */
 		ch = list_first_entry(&smux.lch_tx_ready_list,
 						struct smux_lch_t,
@@ -2355,30 +2760,7 @@
 
 	/* Purge TX queue */
 	spin_lock(&ch->tx_lock_lhb2);
-	while (!list_empty(&ch->tx_queue)) {
-		pkt = list_first_entry(&ch->tx_queue, struct smux_pkt_t,
-							list);
-		list_del(&pkt->list);
-
-		if (pkt->hdr.cmd == SMUX_CMD_OPEN_LCH) {
-			/* Open was never sent, just force to closed state */
-			union notifier_metadata meta_disconnected;
-
-			ch->local_state = SMUX_LCH_LOCAL_CLOSED;
-			meta_disconnected.disconnected.is_ssr = 0;
-			schedule_notify(lcid, SMUX_DISCONNECTED,
-				&meta_disconnected);
-		} else if (pkt->hdr.cmd == SMUX_CMD_DATA) {
-			/* Notify client of failed write */
-			union notifier_metadata meta_write;
-
-			meta_write.write.pkt_priv = pkt->priv;
-			meta_write.write.buffer = pkt->payload;
-			meta_write.write.len = pkt->hdr.payload_len;
-			schedule_notify(ch->lcid, SMUX_WRITE_FAIL, &meta_write);
-		}
-		smux_free_pkt(pkt);
-	}
+	smux_purge_ch_tx_queue(ch);
 	spin_unlock(&ch->tx_lock_lhb2);
 
 	/* Send Close Command */
@@ -2402,6 +2784,10 @@
 			pr_err("%s: pkt allocation failed\n", __func__);
 			ret = -ENOMEM;
 		}
+
+		/* Purge RX retry queue */
+		if (ch->rx_retry_queue_cnt)
+			queue_delayed_work(smux_rx_wq, &ch->rx_retry_work, 0);
 	}
 	spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
 
@@ -2700,8 +3086,59 @@
 }
 
 /**********************************************************************/
+/* Subsystem Restart                                                  */
+/**********************************************************************/
+static struct notifier_block ssr_notifier = {
+	.notifier_call = ssr_notifier_cb,
+};
+
+/**
+ * Handle Subsystem Restart (SSR) notifications.
+ *
+ * @this Pointer to ssr_notifier
+ * @code SSR Code
+ * @data Data pointer (not used)
+ */
+static int ssr_notifier_cb(struct notifier_block *this,
+				unsigned long code,
+				void *data)
+{
+	unsigned long flags;
+	int power_off_uart = 0;
+
+	if (code != SUBSYS_AFTER_SHUTDOWN)
+		return NOTIFY_DONE;
+
+	/* Cleanup channels */
+	smux_lch_purge();
+
+	/* Power-down UART */
+	spin_lock_irqsave(&smux.tx_lock_lha2, flags);
+	if (smux.power_state != SMUX_PWR_OFF) {
+		SMUX_DBG("%s: SSR - turning off UART\n", __func__);
+		smux.power_state = SMUX_PWR_OFF;
+		power_off_uart = 1;
+	}
+	spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
+
+	if (power_off_uart)
+		smux_uart_power_off();
+
+	return NOTIFY_DONE;
+}
+
+/**********************************************************************/
 /* Line Discipline Interface                                          */
 /**********************************************************************/
+static void smux_pdev_release(struct device *dev)
+{
+	struct platform_device *pdev;
+
+	pdev = container_of(dev, struct platform_device, dev);
+	SMUX_DBG("%s: releasing pdev %p '%s'\n", __func__, pdev, pdev->name);
+	memset(&pdev->dev, 0x0, sizeof(pdev->dev));
+}
+
 static int smuxld_open(struct tty_struct *tty)
 {
 	int i;
@@ -2711,66 +3148,94 @@
 	if (!smux.is_initialized)
 		return -ENODEV;
 
-	spin_lock_irqsave(&smux.lock_lha0, flags);
+	mutex_lock(&smux.mutex_lha0);
 	if (smux.ld_open_count) {
 		pr_err("%s: %p multiple instances not supported\n",
 			__func__, tty);
-		spin_unlock_irqrestore(&smux.lock_lha0, flags);
+		mutex_unlock(&smux.mutex_lha0);
 		return -EEXIST;
 	}
 
-	++smux.ld_open_count;
 	if (tty->ops->write == NULL) {
-		spin_unlock_irqrestore(&smux.lock_lha0, flags);
+		pr_err("%s: tty->ops->write already NULL\n", __func__);
+		mutex_unlock(&smux.mutex_lha0);
 		return -EINVAL;
 	}
 
 	/* connect to TTY */
+	++smux.ld_open_count;
+	smux.in_reset = 0;
 	smux.tty = tty;
 	tty->disc_data = &smux;
 	tty->receive_room = TTY_RECEIVE_ROOM;
 	tty_driver_flush_buffer(tty);
 
 	/* power-down the UART if we are idle */
-	spin_lock(&smux.tx_lock_lha2);
+	spin_lock_irqsave(&smux.tx_lock_lha2, flags);
 	if (smux.power_state == SMUX_PWR_OFF) {
 		SMUX_DBG("%s: powering off uart\n", __func__);
 		smux.power_state = SMUX_PWR_OFF_FLUSH;
-		spin_unlock(&smux.tx_lock_lha2);
+		spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
 		queue_work(smux_tx_wq, &smux_inactivity_work);
 	} else {
-		spin_unlock(&smux.tx_lock_lha2);
+		spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
 	}
-	spin_unlock_irqrestore(&smux.lock_lha0, flags);
 
 	/* register platform devices */
 	for (i = 0; i < ARRAY_SIZE(smux_devs); ++i) {
+		SMUX_DBG("%s: register pdev '%s'\n",
+				__func__, smux_devs[i].name);
+		smux_devs[i].dev.release = smux_pdev_release;
 		tmp = platform_device_register(&smux_devs[i]);
 		if (tmp)
 			pr_err("%s: error %d registering device %s\n",
 				   __func__, tmp, smux_devs[i].name);
 	}
+	mutex_unlock(&smux.mutex_lha0);
 	return 0;
 }
 
 static void smuxld_close(struct tty_struct *tty)
 {
 	unsigned long flags;
+	int power_up_uart = 0;
 	int i;
 
-	spin_lock_irqsave(&smux.lock_lha0, flags);
+	SMUX_DBG("%s: ldisc unload\n", __func__);
+	mutex_lock(&smux.mutex_lha0);
 	if (smux.ld_open_count <= 0) {
 		pr_err("%s: invalid ld count %d\n", __func__,
 			smux.ld_open_count);
-		spin_unlock_irqrestore(&smux.lock_lha0, flags);
+		mutex_unlock(&smux.mutex_lha0);
 		return;
 	}
-	spin_unlock_irqrestore(&smux.lock_lha0, flags);
-
-	for (i = 0; i < ARRAY_SIZE(smux_devs); ++i)
-		platform_device_unregister(&smux_devs[i]);
-
+	smux.in_reset = 1;
 	--smux.ld_open_count;
+
+	/* Cleanup channels */
+	smux_lch_purge();
+
+	/* Unregister platform devices */
+	for (i = 0; i < ARRAY_SIZE(smux_devs); ++i) {
+		SMUX_DBG("%s: unregister pdev '%s'\n",
+				__func__, smux_devs[i].name);
+		platform_device_unregister(&smux_devs[i]);
+	}
+
+	/* Schedule UART power-up if it's down */
+	spin_lock_irqsave(&smux.tx_lock_lha2, flags);
+	if (smux.power_state == SMUX_PWR_OFF)
+		power_up_uart = 1;
+	smux.power_state = SMUX_PWR_OFF;
+	spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
+
+	if (power_up_uart)
+		smux_uart_power_on();
+
+	/* Disconnect from TTY */
+	smux.tty = NULL;
+	mutex_unlock(&smux.mutex_lha0);
+	SMUX_DBG("%s: ldisc complete\n", __func__);
 }
 
 /**
@@ -2879,13 +3344,14 @@
 {
 	int ret;
 
-	spin_lock_init(&smux.lock_lha0);
+	mutex_init(&smux.mutex_lha0);
 
 	spin_lock_init(&smux.rx_lock_lha1);
 	smux.rx_state = SMUX_RX_IDLE;
 	smux.power_state = SMUX_PWR_OFF;
 	smux.pwr_wakeup_delay_us = 1;
 	smux.powerdown_enabled = 0;
+	INIT_LIST_HEAD(&smux.power_queue);
 	smux.rx_activity_flag = 0;
 	smux.tx_activity_flag = 0;
 	smux.recv_len = 0;
@@ -2905,6 +3371,8 @@
 		return ret;
 	}
 
+	subsys_notif_register_notifier("qsc", &ssr_notifier);
+
 	ret = lch_init();
 	if (ret != 0) {
 		pr_err("%s: lch_init failed\n", __func__);
diff --git a/drivers/tty/serial/msm_serial_hs_lite.c b/drivers/tty/serial/msm_serial_hs_lite.c
index 59104ed..4a65177 100644
--- a/drivers/tty/serial/msm_serial_hs_lite.c
+++ b/drivers/tty/serial/msm_serial_hs_lite.c
@@ -1220,6 +1220,9 @@
 	msm_hsl_write(port, CR_PROTECTION_EN, regmap[vid][UARTDM_CR]);
 	msm_hsl_write(port, UARTDM_CR_TX_EN_BMSK, regmap[vid][UARTDM_CR]);
 
+	msm_hsl_write(port, 1, regmap[vid][UARTDM_NCF_TX]);
+	msm_hsl_read(port, regmap[vid][UARTDM_NCF_TX]);
+
 	printk(KERN_INFO "msm_serial_hsl: console setup on port #%d\n",
 	       port->line);
 
diff --git a/drivers/tty/smux_private.h b/drivers/tty/smux_private.h
index 6bd9713..f644ff0 100644
--- a/drivers/tty/smux_private.h
+++ b/drivers/tty/smux_private.h
@@ -16,6 +16,7 @@
 #define SMUX_PRIVATE_H
 
 #define SMUX_MAX_PKT_SIZE   8192
+#define SMUX_BROADCAST_LCID 0xFF
 
 /* SMUX Protocol Characters */
 #define SMUX_MAGIC          0x33FC
@@ -29,6 +30,9 @@
 #define SMUX_UT_ECHO_ACK_OK 0xF1
 #define SMUX_UT_ECHO_ACK_FAIL 0xF2
 
+/* Maximum number of packets in retry queue */
+#define SMUX_RX_RETRY_MAX_PKTS 32
+
 struct tty_struct;
 
 /* Packet header. */
diff --git a/drivers/tty/smux_test.c b/drivers/tty/smux_test.c
index 242c66e..62e9465 100644
--- a/drivers/tty/smux_test.c
+++ b/drivers/tty/smux_test.c
@@ -75,9 +75,44 @@
 	} \
 	do {} while (0)
 
+/**
+ * In-range unit test assertion for test cases.
+ *
+ * @a lval
+ * @minv Minimum value
+ * @maxv Maximum value
+ *
+ * Assertion fails if @a is not on the exclusive range minv, maxv
+ * ((@a < @minv) or (@a > @maxv)).  In the failure case, the macro
+ * logs the function and line number where the error occurred along
+ * with the values of @a and @minv, @maxv.
+ *
+ * Assumes that the following local variables exist:
+ * @buf - buffer to write failure message to
+ * @i - number of bytes written to buffer
+ * @max - maximum size of the buffer
+ * @failed - set to true if test fails
+ */
+#define UT_ASSERT_INT_IN_RANGE(a, minv, maxv) \
+	if (((a) < (minv)) || ((a) > (maxv))) { \
+		i += scnprintf(buf + i, max - i, \
+			"%s:%d Fail: " #a "(%d) < " #minv "(%d) or " \
+				 #a "(%d) > " #maxv "(%d)\n", \
+				__func__, __LINE__, \
+				a, minv, a, maxv); \
+		failed = 1; \
+		break; \
+	} \
+	do {} while (0)
+
+
 static unsigned char test_array[] = {1, 1, 2, 3, 5, 8, 13, 21, 34, 55,
 					89, 144, 233};
 
+/* when 1, forces failure of get_rx_buffer_mock function */
+static int get_rx_buffer_mock_fail;
+
+
 /* Used for mapping local to remote TIOCM signals */
 struct tiocm_test_vector {
 	uint32_t input;
@@ -93,7 +128,7 @@
 {
 	void *rx_buf;
 
-	rx_buf = kmalloc(size, GFP_ATOMIC);
+	rx_buf = kmalloc(size, GFP_KERNEL);
 	*pkt_priv = (void *)0x1234;
 	*buffer = rx_buf;
 
@@ -118,6 +153,13 @@
 	struct smux_meta_write meta;
 };
 
+/* Mock object metadata for get_rx_buffer failure event */
+struct mock_get_rx_buff_event {
+	struct list_head list;
+	int size;
+	unsigned long jiffies;
+};
+
 /* Mock object for all SMUX callback events */
 struct smux_mock_callback {
 	int cb_count;
@@ -140,6 +182,10 @@
 	int event_read_failed;
 	struct list_head read_events;
 
+	/* read retry data */
+	int get_rx_buff_retry_count;
+	struct list_head get_rx_buff_retry_events;
+
 	/* write event data */
 	int event_write_done;
 	int event_write_failed;
@@ -156,6 +202,7 @@
 	init_completion(&cb->cb_completion);
 	spin_lock_init(&cb->lock);
 	INIT_LIST_HEAD(&cb->read_events);
+	INIT_LIST_HEAD(&cb->get_rx_buff_retry_events);
 	INIT_LIST_HEAD(&cb->write_events);
 }
 
@@ -191,6 +238,16 @@
 		kfree(meta);
 	}
 
+	cb->get_rx_buff_retry_count = 0;
+	while (!list_empty(&cb->get_rx_buff_retry_events)) {
+		struct mock_get_rx_buff_event *meta;
+		meta = list_first_entry(&cb->get_rx_buff_retry_events,
+				struct mock_get_rx_buff_event,
+				list);
+		list_del(&meta->list);
+		kfree(meta);
+	}
+
 	cb->event_write_done = 0;
 	cb->event_write_failed = 0;
 	while (!list_empty(&cb->write_events)) {
@@ -229,6 +286,8 @@
 		"\tevent_read_done=%d\n"
 		"\tevent_read_failed=%d\n"
 		"\tread_events=%d\n"
+		"\tget_rx_retry=%d\n"
+		"\tget_rx_retry_events=%d\n"
 		"\tevent_write_done=%d\n"
 		"\tevent_write_failed=%d\n"
 		"\twrite_events=%d\n",
@@ -243,6 +302,8 @@
 		cb->event_read_done,
 		cb->event_read_failed,
 		!list_empty(&cb->read_events),
+		cb->get_rx_buff_retry_count,
+		!list_empty(&cb->get_rx_buff_retry_events),
 		cb->event_write_done,
 		cb->event_write_failed,
 		list_empty(&cb->write_events)
@@ -268,83 +329,105 @@
 		return;
 	}
 
-	spin_lock_irqsave(&cb_data_ptr->lock, flags);
 	switch (event) {
 	case SMUX_CONNECTED:
+		spin_lock_irqsave(&cb_data_ptr->lock, flags);
 		++cb_data_ptr->event_connected;
+		spin_unlock_irqrestore(&cb_data_ptr->lock, flags);
 		break;
 
 	case SMUX_DISCONNECTED:
+		spin_lock_irqsave(&cb_data_ptr->lock, flags);
 		++cb_data_ptr->event_disconnected;
 		cb_data_ptr->event_disconnected_ssr =
 			((struct smux_meta_disconnected *)metadata)->is_ssr;
+		spin_unlock_irqrestore(&cb_data_ptr->lock, flags);
 		break;
 
 	case SMUX_READ_DONE:
-		++cb_data_ptr->event_read_done;
 		read_event_meta = kmalloc(sizeof(struct mock_read_event),
-						GFP_ATOMIC);
+						GFP_KERNEL);
+		spin_lock_irqsave(&cb_data_ptr->lock, flags);
+		++cb_data_ptr->event_read_done;
 		if (read_event_meta) {
 			read_event_meta->meta =
 				*(struct smux_meta_read *)metadata;
 			list_add_tail(&read_event_meta->list,
 						&cb_data_ptr->read_events);
 		}
+		spin_unlock_irqrestore(&cb_data_ptr->lock, flags);
 		break;
 
 	case SMUX_READ_FAIL:
-		++cb_data_ptr->event_read_failed;
 		read_event_meta = kmalloc(sizeof(struct mock_read_event),
-						GFP_ATOMIC);
+						GFP_KERNEL);
+		spin_lock_irqsave(&cb_data_ptr->lock, flags);
+		++cb_data_ptr->event_read_failed;
 		if (read_event_meta) {
-			read_event_meta->meta =
+			if (metadata)
+				read_event_meta->meta =
 					*(struct smux_meta_read *)metadata;
+			else
+				memset(&read_event_meta->meta, 0x0,
+						sizeof(struct smux_meta_read));
 			list_add_tail(&read_event_meta->list,
 					&cb_data_ptr->read_events);
 		}
+		spin_unlock_irqrestore(&cb_data_ptr->lock, flags);
 		break;
 
 	case SMUX_WRITE_DONE:
-		++cb_data_ptr->event_write_done;
 		write_event_meta = kmalloc(sizeof(struct mock_write_event),
-						GFP_ATOMIC);
+						GFP_KERNEL);
+		spin_lock_irqsave(&cb_data_ptr->lock, flags);
+		++cb_data_ptr->event_write_done;
 		if (write_event_meta) {
 			write_event_meta->meta =
 					*(struct smux_meta_write *)metadata;
 			list_add_tail(&write_event_meta->list,
 					&cb_data_ptr->write_events);
 		}
+		spin_unlock_irqrestore(&cb_data_ptr->lock, flags);
 		break;
 
 	case SMUX_WRITE_FAIL:
-		++cb_data_ptr->event_write_failed;
 		write_event_meta = kmalloc(sizeof(struct mock_write_event),
-						GFP_ATOMIC);
+						GFP_KERNEL);
+		spin_lock_irqsave(&cb_data_ptr->lock, flags);
+		++cb_data_ptr->event_write_failed;
 		if (write_event_meta) {
 			write_event_meta->meta =
 				*(struct smux_meta_write *)metadata;
 			list_add_tail(&write_event_meta->list,
 					&cb_data_ptr->write_events);
 		}
+		spin_unlock_irqrestore(&cb_data_ptr->lock, flags);
 		break;
 
 	case SMUX_LOW_WM_HIT:
+		spin_lock_irqsave(&cb_data_ptr->lock, flags);
 		++cb_data_ptr->event_low_wm;
+		spin_unlock_irqrestore(&cb_data_ptr->lock, flags);
 		break;
 
 	case SMUX_HIGH_WM_HIT:
+		spin_lock_irqsave(&cb_data_ptr->lock, flags);
 		++cb_data_ptr->event_high_wm;
+		spin_unlock_irqrestore(&cb_data_ptr->lock, flags);
 		break;
 
 	case SMUX_TIOCM_UPDATE:
+		spin_lock_irqsave(&cb_data_ptr->lock, flags);
 		++cb_data_ptr->event_tiocm;
 		cb_data_ptr->tiocm_meta = *(struct smux_meta_tiocm *)metadata;
+		spin_unlock_irqrestore(&cb_data_ptr->lock, flags);
 		break;
 
 	default:
 		pr_err("%s: unknown event %d\n", __func__, event);
 	};
 
+	spin_lock_irqsave(&cb_data_ptr->lock, flags);
 	++cb_data_ptr->cb_count;
 	complete(&cb_data_ptr->cb_completion);
 	spin_unlock_irqrestore(&cb_data_ptr->lock, flags);
@@ -1153,6 +1236,338 @@
 	return i;
 }
 
+/**
+ * Allocates a new buffer or returns a failure based upon the
+ * global @get_rx_buffer_mock_fail.
+ */
+static int get_rx_buffer_mock(void *priv, void **pkt_priv,
+		void **buffer, int size)
+{
+	void *rx_buf;
+	unsigned long flags;
+	struct smux_mock_callback *cb_ptr;
+
+	cb_ptr = (struct smux_mock_callback *)priv;
+	if (!cb_ptr) {
+		pr_err("%s: no callback data\n", __func__);
+		return -ENXIO;
+	}
+
+	if (get_rx_buffer_mock_fail) {
+		/* force failure and log failure event */
+		struct mock_get_rx_buff_event *meta;
+		meta = kmalloc(sizeof(struct mock_get_rx_buff_event),
+				GFP_KERNEL);
+		if (!meta) {
+			pr_err("%s: unable to allocate metadata\n", __func__);
+			return -ENOMEM;
+		}
+		INIT_LIST_HEAD(&meta->list);
+		meta->size = size;
+		meta->jiffies = jiffies;
+
+		spin_lock_irqsave(&cb_ptr->lock, flags);
+		++cb_ptr->get_rx_buff_retry_count;
+		list_add_tail(&meta->list, &cb_ptr->get_rx_buff_retry_events);
+		++cb_ptr->cb_count;
+		complete(&cb_ptr->cb_completion);
+		spin_unlock_irqrestore(&cb_ptr->lock, flags);
+		return -EAGAIN;
+	} else {
+		rx_buf = kmalloc(size, GFP_KERNEL);
+		*pkt_priv = (void *)0x1234;
+		*buffer = rx_buf;
+		return 0;
+	}
+	return 0;
+}
+
+/**
+ * Verify get_rx_buffer callback retry.
+ *
+ * @buf  Buffer for status message
+ * @max  Size of buffer
+ *
+ * @returns Number of bytes written to @buf
+ */
+static int smux_ut_local_get_rx_buff_retry(char *buf, int max)
+{
+	static struct smux_mock_callback cb_data;
+	static int cb_initialized;
+	int i = 0;
+	int failed = 0;
+	char try_two[] = "try 2";
+	int ret;
+	unsigned long start_j;
+	struct mock_get_rx_buff_event *event;
+	struct mock_read_event *read_event;
+	int try;
+
+	i += scnprintf(buf + i, max - i, "Running %s\n", __func__);
+	pr_err("%s", buf);
+
+	if (!cb_initialized)
+		mock_cb_data_init(&cb_data);
+
+	mock_cb_data_reset(&cb_data);
+	smux_byte_loopback = SMUX_TEST_LCID;
+	while (!failed) {
+		/* open port for loopback */
+		ret = msm_smux_set_ch_option(SMUX_TEST_LCID,
+				SMUX_CH_OPTION_LOCAL_LOOPBACK,
+				0);
+		UT_ASSERT_INT(ret, ==, 0);
+
+		ret = msm_smux_open(SMUX_TEST_LCID, &cb_data,
+				smux_mock_cb, get_rx_buffer_mock);
+		UT_ASSERT_INT(ret, ==, 0);
+		UT_ASSERT_INT(
+				(int)wait_for_completion_timeout(
+					&cb_data.cb_completion, HZ), >, 0);
+		UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+		UT_ASSERT_INT(cb_data.event_connected, ==, 1);
+		mock_cb_data_reset(&cb_data);
+
+		/*
+		 * Force get_rx_buffer failure for a single RX packet
+		 *
+		 * The get_rx_buffer calls should follow an exponential
+		 * back-off with a maximum timeout of 1024 ms after which we
+		 * will get a failure notification.
+		 *
+		 * Try   Post Delay (ms)
+		 *  0      -
+		 *  1      1
+		 *  2      2
+		 *  3      4
+		 *  4      8
+		 *  5     16
+		 *  6     32
+		 *  7     64
+		 *  8    128
+		 *  9    256
+		 * 10    512
+		 * 11   1024
+		 * 12   Fail
+		 *
+		 * All times are limited by the precision of the timer
+		 * framework, so ranges are used in the test
+		 * verification.
+		 */
+		get_rx_buffer_mock_fail = 1;
+		start_j = jiffies;
+		ret = msm_smux_write(SMUX_TEST_LCID, (void *)1,
+					test_array, sizeof(test_array));
+		UT_ASSERT_INT(ret, ==, 0);
+		ret = msm_smux_write(SMUX_TEST_LCID, (void *)2,
+					try_two, sizeof(try_two));
+		UT_ASSERT_INT(ret, ==, 0);
+
+		/* wait for RX failure event */
+		while (cb_data.event_read_failed == 0) {
+			UT_ASSERT_INT(
+				(int)wait_for_completion_timeout(
+					&cb_data.cb_completion, 2*HZ),
+				>, 0);
+			INIT_COMPLETION(cb_data.cb_completion);
+		}
+		if (failed)
+			break;
+
+		/* verify retry attempts */
+		UT_ASSERT_INT(cb_data.get_rx_buff_retry_count, ==, 12);
+		event = list_first_entry(&cb_data.get_rx_buff_retry_events,
+				struct mock_get_rx_buff_event, list);
+		pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+				jiffies_to_msecs(event->jiffies - start_j));
+		UT_ASSERT_INT_IN_RANGE(
+				jiffies_to_msecs(event->jiffies - start_j),
+				0, 0 + 20);
+		start_j = event->jiffies;
+
+		event = list_first_entry(&event->list,
+				struct mock_get_rx_buff_event, list);
+		pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+				jiffies_to_msecs(event->jiffies - start_j));
+		UT_ASSERT_INT_IN_RANGE(
+				jiffies_to_msecs(event->jiffies - start_j),
+				1, 1 + 20);
+		start_j = event->jiffies;
+
+		event = list_first_entry(&event->list,
+				struct mock_get_rx_buff_event, list);
+		pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+				jiffies_to_msecs(event->jiffies - start_j));
+		UT_ASSERT_INT_IN_RANGE(
+				jiffies_to_msecs(event->jiffies - start_j),
+				2, 2 + 20);
+		start_j = event->jiffies;
+
+		event = list_first_entry(&event->list,
+				struct mock_get_rx_buff_event, list);
+		pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+				jiffies_to_msecs(event->jiffies - start_j));
+		UT_ASSERT_INT_IN_RANGE(
+				jiffies_to_msecs(event->jiffies - start_j),
+				4, 4 + 20);
+		start_j = event->jiffies;
+
+		event = list_first_entry(&event->list,
+				struct mock_get_rx_buff_event, list);
+		pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+				jiffies_to_msecs(event->jiffies - start_j));
+		UT_ASSERT_INT_IN_RANGE(
+				jiffies_to_msecs(event->jiffies - start_j),
+				8, 8 + 20);
+		start_j = event->jiffies;
+
+		event = list_first_entry(&event->list,
+				struct mock_get_rx_buff_event, list);
+		pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+				jiffies_to_msecs(event->jiffies - start_j));
+		UT_ASSERT_INT_IN_RANGE(
+				jiffies_to_msecs(event->jiffies - start_j),
+				16, 16 + 20);
+		start_j = event->jiffies;
+
+		event = list_first_entry(&event->list,
+				struct mock_get_rx_buff_event, list);
+		pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+				jiffies_to_msecs(event->jiffies - start_j));
+		UT_ASSERT_INT_IN_RANGE(
+				jiffies_to_msecs(event->jiffies - start_j),
+				32 - 20, 32 + 20);
+		start_j = event->jiffies;
+
+		event = list_first_entry(&event->list,
+				struct mock_get_rx_buff_event, list);
+		pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+				jiffies_to_msecs(event->jiffies - start_j));
+		UT_ASSERT_INT_IN_RANGE(
+				jiffies_to_msecs(event->jiffies - start_j),
+				64 - 20, 64 + 20);
+		start_j = event->jiffies;
+
+		event = list_first_entry(&event->list,
+				struct mock_get_rx_buff_event, list);
+		pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+				jiffies_to_msecs(event->jiffies - start_j));
+		UT_ASSERT_INT_IN_RANGE(
+				jiffies_to_msecs(event->jiffies - start_j),
+				128 - 20, 128 + 20);
+		start_j = event->jiffies;
+
+		event = list_first_entry(&event->list,
+				struct mock_get_rx_buff_event, list);
+		pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+				jiffies_to_msecs(event->jiffies - start_j));
+		UT_ASSERT_INT_IN_RANGE(
+				jiffies_to_msecs(event->jiffies - start_j),
+				256 - 20, 256 + 20);
+		start_j = event->jiffies;
+
+		event = list_first_entry(&event->list,
+				struct mock_get_rx_buff_event, list);
+		pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+				jiffies_to_msecs(event->jiffies - start_j));
+		UT_ASSERT_INT_IN_RANGE(
+				jiffies_to_msecs(event->jiffies - start_j),
+				512 - 20, 512 + 20);
+		start_j = event->jiffies;
+
+		event = list_first_entry(&event->list,
+				struct mock_get_rx_buff_event, list);
+		pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+				jiffies_to_msecs(event->jiffies - start_j));
+		UT_ASSERT_INT_IN_RANGE(
+				jiffies_to_msecs(event->jiffies - start_j),
+				1024 - 20, 1024 + 20);
+		mock_cb_data_reset(&cb_data);
+
+		/* verify 2nd pending RX packet goes through */
+		get_rx_buffer_mock_fail = 0;
+		INIT_COMPLETION(cb_data.cb_completion);
+		if (cb_data.event_read_done == 0)
+			UT_ASSERT_INT(
+				(int)wait_for_completion_timeout(
+					&cb_data.cb_completion, HZ),
+				>, 0);
+		UT_ASSERT_INT(cb_data.event_read_done, ==, 1);
+		UT_ASSERT_INT(list_empty(&cb_data.read_events), ==, 0);
+		read_event = list_first_entry(&cb_data.read_events,
+				struct mock_read_event, list);
+		UT_ASSERT_PTR(read_event->meta.pkt_priv, ==, (void *)0x1234);
+		UT_ASSERT_PTR(read_event->meta.buffer, !=, NULL);
+		UT_ASSERT_INT(0, ==, memcmp(read_event->meta.buffer, try_two,
+				sizeof(try_two)));
+		mock_cb_data_reset(&cb_data);
+
+		/* Test maximum retry queue size */
+		get_rx_buffer_mock_fail = 1;
+		for (try = 0; try < (SMUX_RX_RETRY_MAX_PKTS + 1); ++try) {
+			mock_cb_data_reset(&cb_data);
+			ret = msm_smux_write(SMUX_TEST_LCID, (void *)1,
+						test_array, sizeof(test_array));
+			UT_ASSERT_INT(ret, ==, 0);
+			UT_ASSERT_INT(
+				(int)wait_for_completion_timeout(
+					&cb_data.cb_completion, HZ),
+				>, 0);
+		}
+
+		/* should have 32 successful rx packets and 1 failed */
+		while (cb_data.event_read_failed == 0) {
+			UT_ASSERT_INT(
+				(int)wait_for_completion_timeout(
+					&cb_data.cb_completion, 2*HZ),
+				>, 0);
+			INIT_COMPLETION(cb_data.cb_completion);
+		}
+		if (failed)
+			break;
+
+		get_rx_buffer_mock_fail = 0;
+		while (cb_data.event_read_done < SMUX_RX_RETRY_MAX_PKTS) {
+			UT_ASSERT_INT(
+				(int)wait_for_completion_timeout(
+					&cb_data.cb_completion, 2*HZ),
+				>, 0);
+			INIT_COMPLETION(cb_data.cb_completion);
+		}
+		if (failed)
+			break;
+
+		UT_ASSERT_INT(1, ==, cb_data.event_read_failed);
+		UT_ASSERT_INT(SMUX_RX_RETRY_MAX_PKTS, ==,
+				cb_data.event_read_done);
+		mock_cb_data_reset(&cb_data);
+
+		/* close port */
+		ret = msm_smux_close(SMUX_TEST_LCID);
+		UT_ASSERT_INT(ret, ==, 0);
+		UT_ASSERT_INT(
+			(int)wait_for_completion_timeout(
+				&cb_data.cb_completion, HZ),
+			>, 0);
+		UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+		UT_ASSERT_INT(cb_data.event_disconnected, ==, 1);
+		UT_ASSERT_INT(cb_data.event_disconnected_ssr, ==, 0);
+		break;
+	}
+
+	if (!failed) {
+		i += scnprintf(buf + i, max - i, "\tOK\n");
+	} else {
+		pr_err("%s: Failed\n", __func__);
+		i += scnprintf(buf + i, max - i, "\tFailed\n");
+		i += mock_cb_data_print(&cb_data, buf + i, max - i);
+		msm_smux_close(SMUX_TEST_LCID);
+	}
+	smux_byte_loopback = 0;
+	mock_cb_data_reset(&cb_data);
+	return i;
+}
+
 static char debug_buffer[DEBUG_BUFMAX];
 
 static ssize_t debug_read(struct file *file, char __user *buf,
@@ -1214,6 +1629,8 @@
 	debug_create("ut_local_wm", 0444, dent, smux_ut_local_wm);
 	debug_create("ut_local_smuxld_receive_buf", 0444, dent,
 			smux_ut_local_smuxld_receive_buf);
+	debug_create("ut_local_get_rx_buff_retry", 0444, dent,
+			smux_ut_local_get_rx_buff_retry);
 
 	return 0;
 }
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index 6bd0577..5ed16cc 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -690,6 +690,13 @@
 
 skip_phy_resume:
 
+	if (!(readl_relaxed(USB_USBCMD) & CMD_RUN) &&
+			(readl_relaxed(USB_PORTSC) & PORT_SUSPEND)) {
+		writel_relaxed(readl_relaxed(USB_USBCMD) | CMD_RUN ,
+				USB_USBCMD);
+		dbg_log_event(NULL, "Set RS", readl_relaxed(USB_USBCMD));
+	}
+
 	usb_hcd_resume_root_hub(hcd);
 
 	atomic_set(&mehci->in_lpm, 0);
diff --git a/drivers/usb/misc/mdm_data_bridge.c b/drivers/usb/misc/mdm_data_bridge.c
index bf8e5f4..6ee3204 100644
--- a/drivers/usb/misc/mdm_data_bridge.c
+++ b/drivers/usb/misc/mdm_data_bridge.c
@@ -479,7 +479,7 @@
 	result = usb_autopm_get_interface(dev->intf);
 	if (result < 0) {
 		dev_err(&dev->udev->dev, "%s: resume failure\n", __func__);
-		goto error;
+		goto pm_error;
 	}
 
 	txurb = usb_alloc_urb(0, GFP_KERNEL);
@@ -536,7 +536,7 @@
 error:
 	dev->txurb_drp_cnt++;
 	usb_autopm_put_interface(dev->intf);
-
+pm_error:
 	return result;
 }
 EXPORT_SYMBOL(data_bridge_write);
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 59f01f6..61fbac0 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -838,10 +838,14 @@
 	clk_disable_unprepare(motg->core_clk);
 
 	/* usb phy no more require TCXO clock, hence vote for TCXO disable */
-	ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_OFF);
-	if (ret)
-		dev_err(phy->dev, "%s failed to devote for "
-			"TCXO D0 buffer%d\n", __func__, ret);
+	if (!host_bus_suspend) {
+		ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_OFF);
+		if (ret)
+			dev_err(phy->dev, "%s failed to devote for "
+				"TCXO D0 buffer%d\n", __func__, ret);
+		else
+			motg->lpm_flags |= XO_SHUTDOWN;
+	}
 
 	if (motg->caps & ALLOW_PHY_POWER_COLLAPSE &&
 			!host_bus_suspend && !dcp) {
@@ -886,10 +890,13 @@
 	wake_lock(&motg->wlock);
 
 	/* Vote for TCXO when waking up the phy */
-	ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_ON);
-	if (ret)
-		dev_err(phy->dev, "%s failed to vote for "
-			"TCXO D0 buffer%d\n", __func__, ret);
+	if (motg->lpm_flags & XO_SHUTDOWN) {
+		ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_ON);
+		if (ret)
+			dev_err(phy->dev, "%s failed to vote for "
+				"TCXO D0 buffer%d\n", __func__, ret);
+		motg->lpm_flags &= ~XO_SHUTDOWN;
+	}
 
 	clk_prepare_enable(motg->core_clk);
 
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index 7fd2d91..ca5d2c6 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -93,7 +93,7 @@
 static struct delayed_work mdp_pipe_ctrl_worker;
 
 static boolean mdp_suspended = FALSE;
-static DEFINE_MUTEX(mdp_suspend_mutex);
+DEFINE_MUTEX(mdp_suspend_mutex);
 
 #ifdef CONFIG_FB_MSM_MDP40
 struct mdp_dma_data dma2_data;
@@ -1887,7 +1887,7 @@
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 
 	if (mdp_rev >= MDP_REV_41 && mfd->panel.type == MIPI_CMD_PANEL)
-		mdp_dsi_cmd_overlay_suspend();
+		mdp_dsi_cmd_overlay_suspend(mfd);
 	return ret;
 }
 
@@ -1897,7 +1897,6 @@
 
 #ifdef CONFIG_FB_MSM_MDP40
 	struct msm_fb_data_type *mfd;
-	mdp4_overlay_ctrl_db_reset();
 
 	mfd = platform_get_drvdata(pdev);
 
@@ -2575,17 +2574,6 @@
 	return rc;
 }
 
-unsigned int mdp_check_suspended(void)
-{
-	unsigned int ret;
-
-	mutex_lock(&mdp_suspend_mutex);
-	ret = mdp_suspended;
-	mutex_unlock(&mdp_suspend_mutex);
-
-	return ret;
-}
-
 void mdp_footswitch_ctrl(boolean on)
 {
 	mutex_lock(&mdp_suspend_mutex);
@@ -2652,7 +2640,6 @@
 #ifdef CONFIG_FB_MSM_DTV
 	mdp4_dtv_set_black_screen();
 #endif
-	mdp4_iommu_detach();
 	mdp_footswitch_ctrl(FALSE);
 }
 
diff --git a/drivers/video/msm/mdp.h b/drivers/video/msm/mdp.h
index b104b33..511edb6 100644
--- a/drivers/video/msm/mdp.h
+++ b/drivers/video/msm/mdp.h
@@ -801,7 +801,6 @@
 void mdp_histogram_handle_isr(struct mdp_hist_mgmt *mgmt);
 void __mdp_histogram_kickoff(struct mdp_hist_mgmt *mgmt);
 void __mdp_histogram_reset(struct mdp_hist_mgmt *mgmt);
-unsigned int mdp_check_suspended(void);
 void mdp_footswitch_ctrl(boolean on);
 
 #ifdef CONFIG_FB_MSM_MDP303
@@ -825,14 +824,10 @@
 #endif
 
 #ifndef CONFIG_FB_MSM_MDP40
-static inline void mdp_dsi_cmd_overlay_suspend(void)
+static inline void mdp_dsi_cmd_overlay_suspend(struct msm_fb_data_type *mfd)
 {
 	/* empty */
 }
-static inline void mdp4_iommu_detach(void)
-{
-    /* empty */
-}
 #endif
 
 int mdp_ppp_v4l2_overlay_set(struct fb_info *info, struct mdp_overlay *req);
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index a7161fe..16fede1 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -173,6 +173,7 @@
 	MDP4_MIXER_STAGE0,	/* zorder 0 */
 	MDP4_MIXER_STAGE1,	/* zorder 1 */
 	MDP4_MIXER_STAGE2,	/* zorder 2 */
+	MDP4_MIXER_STAGE3,	/* zorder 3 */
 	MDP4_MIXER_STAGE_MAX
 };
 
@@ -256,6 +257,19 @@
 	u8 mark_unmap;
 };
 
+struct blend_cfg {
+	u32 op;
+	u32 bg_alpha;
+	u32 fg_alpha;
+	u32 co3_sel;
+	u32 transp_low0;
+	u32 transp_low1;
+	u32 transp_high0;
+	u32 transp_high1;
+	int solidfill;
+	struct mdp4_overlay_pipe *solidfill_pipe;
+};
+
 struct mdp4_overlay_pipe {
 	uint32 pipe_used;
 	uint32 pipe_type;		/* rgb, video/graphic */
@@ -403,6 +417,7 @@
 void mdp4_intr_clear_set(ulong clear, ulong set);
 void mdp4_dma_p_cfg(void);
 unsigned is_mdp4_hw_reset(void);
+void mdp4_overlay_cfg_init(void);
 void mdp4_hw_init(void);
 void mdp4_isr_read(int);
 void mdp4_clear_lcdc(void);
@@ -417,6 +432,7 @@
 uint32 mdp4_overlay_format(struct mdp4_overlay_pipe *pipe);
 uint32 mdp4_overlay_unpack_pattern(struct mdp4_overlay_pipe *pipe);
 uint32 mdp4_overlay_op_mode(struct mdp4_overlay_pipe *pipe);
+void mdp4_lcdc_base_swap(struct mdp4_overlay_pipe *pipe);
 void mdp4_lcdc_overlay(struct msm_fb_data_type *mfd);
 #ifdef CONFIG_FB_MSM_DTV
 void mdp4_overlay_dtv_start(void);
@@ -489,6 +505,7 @@
 			struct mdp4_overlay_pipe *pipe);
 int mdp4_overlay_dtv_unset(struct msm_fb_data_type *mfd,
 			struct mdp4_overlay_pipe *pipe);
+void mdp4_dtv_base_swap(struct mdp4_overlay_pipe *pipe);
 void mdp4_dtv_overlay(struct msm_fb_data_type *mfd);
 int mdp4_dtv_on(struct platform_device *pdev);
 int mdp4_dtv_off(struct platform_device *pdev);
@@ -506,7 +523,7 @@
 int mdp4_overlay_dsi_state_get(void);
 void mdp4_overlay_rgb_setup(struct mdp4_overlay_pipe *pipe);
 void mdp4_overlay_reg_flush(struct mdp4_overlay_pipe *pipe, int all);
-void mdp4_mixer_blend_setup(struct mdp4_overlay_pipe *pipe);
+void mdp4_mixer_blend_setup(int mixer);
 struct mdp4_overlay_pipe *mdp4_overlay_stage_pipe(int mixer, int stage);
 void mdp4_mixer_stage_up(struct mdp4_overlay_pipe *pipe);
 void mdp4_mixer_stage_down(struct mdp4_overlay_pipe *pipe);
@@ -519,6 +536,7 @@
 int mdp4_overlay_get(struct fb_info *info, struct mdp_overlay *req);
 int mdp4_overlay_set(struct fb_info *info, struct mdp_overlay *req);
 int mdp4_overlay_unset(struct fb_info *info, int ndx);
+int mdp4_overlay_unset_mixer(int mixer);
 int mdp4_overlay_play_wait(struct fb_info *info,
 	struct msmfb_overlay_data *req);
 int mdp4_overlay_play(struct fb_info *info, struct msmfb_overlay_data *req);
@@ -533,7 +551,7 @@
 void mdp4_overlay0_done_lcdc(struct mdp_dma_data *dma);
 void mdp4_overlay0_done_mddi(struct mdp_dma_data *dma);
 void mdp4_dma_s_done_mddi(void);
-void mdp4_dma_p_done_mddi(void);
+void mdp4_dma_p_done_mddi(struct mdp_dma_data *dma);
 void mdp4_dma_p_done_dsi(struct mdp_dma_data *dma);
 void mdp4_dma_p_done_dsi_video(struct mdp_dma_data *dma);
 void mdp4_dma_p_done_lcdc(void);
@@ -557,10 +575,32 @@
 {
 	/* empty */
 }
+static inline void mdp4_mddi_blt_dmap_busy_wait(struct msm_fb_data_type *mfd)
+{
+	/* empty */
+}
 static inline void mdp4_mddi_overlay_restore(void)
 {
 	/* empty */
 }
+static inline void mdp4_mddi_overlay_blt_start(struct msm_fb_data_type *mfd)
+{
+	/*empty*/
+}
+static inline void mdp4_mddi_overlay_blt_stop(struct msm_fb_data_type *mfd)
+{
+	/*empty*/
+}
+static inline void mdp4_mddi_overlay_blt_offset(struct msm_fb_data_type *mfd,
+					struct msmfb_overlay_blt *req)
+{
+	/* empty */
+}
+static inline void mdp4_mddi_overlay_blt(struct msm_fb_data_type *mfd,
+					struct msmfb_overlay_blt *req)
+{
+	/* empty*/
+}
 #endif
 
 void mdp4_mddi_overlay_kickoff(struct msm_fb_data_type *mfd,
@@ -590,6 +630,7 @@
 					struct msmfb_overlay_blt *req);
 int mdp4_dsi_video_overlay_blt_offset(struct msm_fb_data_type *mfd,
 					struct msmfb_overlay_blt *req);
+void mdp4_dsi_video_base_swap(struct mdp4_overlay_pipe *pipe);
 
 #ifdef CONFIG_FB_MSM_MDP40
 static inline void mdp3_dsi_cmd_dma_busy_wait(struct msm_fb_data_type *mfd)
@@ -598,6 +639,13 @@
 }
 #endif
 #else
+int mdp4_mddi_overlay_blt_offset(struct msm_fb_data_type *mfd,
+					struct msmfb_overlay_blt *req);
+void mdp4_mddi_overlay_blt(struct msm_fb_data_type *mfd,
+					struct msmfb_overlay_blt *req);
+int mdp4_mddi_overlay_blt_start(struct msm_fb_data_type *mfd);
+int mdp4_mddi_overlay_blt_stop(struct msm_fb_data_type *mfd);
+void mdp4_mddi_blt_dmap_busy_wait(struct msm_fb_data_type *mfd);
 static inline int mdp4_dsi_overlay_blt_start(struct msm_fb_data_type *mfd)
 {
 	return -ENODEV;
@@ -630,6 +678,10 @@
 {
 	return -ENODEV;
 }
+static inline void mdp4_dsi_video_base_swap(struct mdp4_overlay_pipe *pipe)
+{
+	/* empty */
+}
 #endif
 
 void mdp4_lcdc_overlay_blt(struct msm_fb_data_type *mfd,
@@ -640,9 +692,6 @@
 void mdp4_lcdc_overlay_blt_stop(struct msm_fb_data_type *mfd);
 void mdp4_dtv_overlay_blt_start(struct msm_fb_data_type *mfd);
 void mdp4_dtv_overlay_blt_stop(struct msm_fb_data_type *mfd);
-
-int mdp4_mddi_overlay_blt_offset(int *off);
-void mdp4_mddi_overlay_blt(ulong addr);
 void mdp4_overlay_panel_mode(int mixer_num, uint32 mode);
 void mdp4_overlay_panel_mode_unset(int mixer_num, uint32 mode);
 int mdp4_overlay_mixer_play(int mixer_num);
@@ -664,7 +713,7 @@
 void mdp4_overlay_dsi_video_vsync_push(struct msm_fb_data_type *mfd,
 				struct mdp4_overlay_pipe *pipe);
 void mdp4_dsi_cmd_overlay_restore(void);
-void mdp_dsi_cmd_overlay_suspend(void);
+void mdp_dsi_cmd_overlay_suspend(struct msm_fb_data_type *mfd);
 #else
 static inline void mdp4_dsi_cmd_dma_busy_wait(struct msm_fb_data_type *mfd)
 {
@@ -688,7 +737,7 @@
 	/* empty */
 }
 #ifdef CONFIG_FB_MSM_MDP40
-static inline void mdp_dsi_cmd_overlay_suspend(void)
+static inline void mdp_dsi_cmd_overlay_suspend(struct msm_fb_data_type *mfd)
 {
 	/* empty */
 }
@@ -701,6 +750,7 @@
 				struct mdp4_overlay_pipe *pipe);
 void mdp4_dsi_cmd_overlay_kickoff(struct msm_fb_data_type *mfd,
 				struct mdp4_overlay_pipe *pipe);
+void mdp4_dsi_cmd_base_swap(struct mdp4_overlay_pipe *pipe);
 
 void mdp4_overlay_panel_3d(int mixer_num, uint32 panel_3d);
 int mdp4_overlay_3d_sbys(struct fb_info *info, struct msmfb_overlay_3d *req);
@@ -721,7 +771,7 @@
 void mdp4_overlay_dsi_video_wait4vsync(struct msm_fb_data_type *mfd);
 void mdp4_primary_vsync_dsi_video(void);
 uint32_t mdp4_ss_table_value(int8_t param, int8_t index);
-void mdp4_overlay_ctrl_db_reset(void);
+void mdp4_overlay_borderfill_stage_down(struct mdp4_overlay_pipe *pipe);
 
 int mdp4_overlay_writeback_on(struct platform_device *pdev);
 int mdp4_overlay_writeback_off(struct platform_device *pdev);
@@ -759,7 +809,6 @@
 int mdp4_igc_lut_config(struct mdp_igc_lut_data *cfg);
 void mdp4_iommu_unmap(struct mdp4_overlay_pipe *pipe);
 void mdp4_iommu_attach(void);
-void mdp4_iommu_detach(void);
 int mdp4_v4l2_overlay_set(struct fb_info *info, struct mdp_overlay *req,
 		struct mdp4_overlay_pipe **ppipe);
 void mdp4_v4l2_overlay_clear(struct mdp4_overlay_pipe *pipe);
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index 6d4e44b..2a15506 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -46,8 +46,12 @@
 struct mdp4_overlay_ctrl {
 	struct mdp4_overlay_pipe plist[OVERLAY_PIPE_MAX];
 	struct mdp4_overlay_pipe *stage[MDP4_MIXER_MAX][MDP4_MIXER_STAGE_MAX];
+	struct mdp4_overlay_pipe *baselayer[MDP4_MIXER_MAX];
+	struct blend_cfg blend[MDP4_MIXER_MAX][MDP4_MIXER_STAGE_MAX];
 	uint32 mixer_cfg[MDP4_MIXER_MAX];
+	uint32 flush[MDP4_MIXER_MAX];
 	uint32 cs_controller;
+	uint32 hw_version;
 	uint32 panel_3d;
 	uint32 panel_mode;
 	uint32 mixer0_played;
@@ -198,14 +202,6 @@
 	}
 }
 
-void mdp4_overlay_ctrl_db_reset(void)
-{
-	int i;
-
-	for (i = MDP4_MIXER0; i < MDP4_MIXER_MAX; i++)
-		ctrl->mixer_cfg[i] = 0;
-}
-
 int mdp4_overlay_mixer_play(int mixer_num)
 {
 	if (mixer_num == MDP4_MIXER2)
@@ -236,6 +232,20 @@
 	return ctrl->panel_mode;
 }
 
+void mdp4_overlay_cfg_init(void)
+{
+	if (ctrl->hw_version == 0) {
+		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+		ctrl->hw_version = inpdw(MDP_BASE + 0x0); /* MDP_HW_VERSION */
+		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+	}
+
+	if (ctrl->hw_version >= 0x0402030b) {
+		/* MDP_LAYERMIXER_IN_CFG_UPDATE_METHOD */
+		outpdw(MDP_BASE + 0x100fc, 0x01);
+	}
+}
+
 void mdp4_overlay_dmae_cfg(struct msm_fb_data_type *mfd, int atv)
 {
 	uint32	dmae_cfg_reg;
@@ -847,6 +857,8 @@
 	case MDP_YCRCB_H1V1:
 	case MDP_YCBCR_H1V1:
 		return OVERLAY_TYPE_VIDEO;
+	case MDP_RGB_BORDERFILL:
+		return OVERLAY_TYPE_BF;
 	default:
 		mdp4_stat.err_format++;
 		return -ERANGE;
@@ -1120,6 +1132,9 @@
 			pipe->element2 = C2_R_Cr;   /* R */
 		}
 		pipe->bpp = 3;  /* 3 bpp */
+	case MDP_RGB_BORDERFILL:
+		pipe->alpha_enable = 0;
+		pipe->alpha = 0;
 		break;
 	default:
 		/* not likely */
@@ -1441,13 +1456,13 @@
 		return -ENODEV;
 
 	cnt = 0;
-	ndx = 1; /* ndx 0 if not used */
-
+	ndx = MDP4_MIXER_STAGE_BASE;
 	for ( ; ndx < MDP4_MIXER_STAGE_MAX; ndx++) {
 		pipe = ctrl->stage[mixer_num][ndx];
 		if (pipe == NULL)
 			continue;
 		info->z_order = pipe->mixer_stage - MDP4_MIXER_STAGE0;
+		/* z_order == -1, means base layer */
 		info->ptype = pipe->pipe_type;
 		info->pnum = pipe->pipe_num;
 		info->pndx = pipe->pipe_ndx;
@@ -1458,331 +1473,458 @@
 	return cnt;
 }
 
-static void mdp4_overlay_bg_solidfill_clear(uint32 mixer_num)
-{
-	struct mdp4_overlay_pipe *bg_pipe;
-	unsigned char *rgb_base;
-	uint32 rgb_src_format;
-	int pnum;
-
-	bg_pipe = mdp4_overlay_stage_pipe(mixer_num,
-		MDP4_MIXER_STAGE_BASE);
-	if (bg_pipe && bg_pipe->pipe_type == OVERLAY_TYPE_BF) {
-		bg_pipe = mdp4_overlay_stage_pipe(mixer_num,
-				MDP4_MIXER_STAGE0);
-	}
-
-	if (bg_pipe && bg_pipe->pipe_type == OVERLAY_TYPE_RGB) {
-		rgb_src_format = mdp4_overlay_format(bg_pipe);
-		if (!(rgb_src_format & MDP4_FORMAT_SOLID_FILL)) {
-			pnum = bg_pipe->pipe_num - OVERLAY_PIPE_RGB1;
-			rgb_base = MDP_BASE + MDP4_RGB_BASE;
-			rgb_base += MDP4_RGB_OFF * pnum;
-			outpdw(rgb_base + 0x50, rgb_src_format);
-			outpdw(rgb_base + 0x0058, bg_pipe->op_mode);
-			mdp4_overlay_reg_flush(bg_pipe, 0);
-		}
-	}
-}
-
-void mdp4_mixer_pipe_cleanup(int mixer)
-{
-	struct mdp4_overlay_pipe *pipe;
-	int j;
-
-	for (j = MDP4_MIXER_STAGE_MAX - 1; j > MDP4_MIXER_STAGE_BASE; j--) {
-		pipe = ctrl->stage[mixer][j];
-		if (pipe == NULL)
-			continue;
-		pr_debug("%s(): pipe %u\n", __func__, pipe->pipe_ndx);
-		mdp4_mixer_stage_down(pipe);
-		mdp4_overlay_pipe_free(pipe);
-	}
-}
-
 static void mdp4_mixer_stage_commit(int mixer)
 {
 	struct mdp4_overlay_pipe *pipe;
-	int i, j, off;
-	u32 data = 0, stage, flush_bits = 0, pipe_cnt = 0, pull_mode = 0;
-	u32 cfg[MDP4_MIXER_MAX];
+	int i, num;
+	u32 data, stage;
+	int off;
+	unsigned long flags;
 
-	if (mixer == MDP4_MIXER0)
-		flush_bits |= 0x1;
-	else if (mixer == MDP4_MIXER1)
-		flush_bits |= 0x2;
+	data = 0;
+	for (i = MDP4_MIXER_STAGE_BASE; i < MDP4_MIXER_STAGE_MAX; i++) {
+		pipe = ctrl->stage[mixer][i];
+		if (pipe == NULL)
+			continue;
+		pr_debug("%s: mixer=%d ndx=%d stage=%d\n", __func__,
+					mixer, pipe->pipe_ndx, i);
+		stage = pipe->mixer_stage;
+		if (mixer >= MDP4_MIXER1)
+			stage += 8;
+		stage <<= (4 * pipe->pipe_num);
+		data |= stage;
+	}
 
-	for (i = MDP4_MIXER0; i < MDP4_MIXER_MAX; i++) {
-		cfg[i] = 0;
-		for (j = MDP4_MIXER_STAGE_BASE; j < MDP4_MIXER_STAGE_MAX; j++) {
-			pipe = ctrl->stage[i][j];
-			if (pipe == NULL)
-				break;
-			stage = pipe->mixer_stage;
-			if (i >= MDP4_MIXER1)
-				stage += 8;
-			stage <<= (4 * pipe->pipe_num);
-			cfg[i] |= stage;
-			pipe_cnt++;
+	mdp4_mixer_blend_setup(mixer);
 
-			mdp4_mixer_blend_setup(pipe);
+	off = 0;
+	if (data != ctrl->mixer_cfg[mixer]) {
+		ctrl->mixer_cfg[mixer] = data;
+		if (mixer >= MDP4_MIXER2) {
+			/* MDP_LAYERMIXER2_IN_CFG */
+			off = 0x100f0;
+		} else {
+			/* mixer 0 or 1 */
+			num = mixer + 1;
+			num &= 0x01;
+			data |= ctrl->mixer_cfg[num];
+			off = 0x10100;
 		}
+		pr_debug("%s: mixer=%d data=%x flush=%x\n", __func__,
+				mixer, data, ctrl->flush[mixer]);
 	}
 
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	if (ctrl->mixer_cfg[mixer] != cfg[mixer]) {
-		if ((ctrl->mixer_cfg[MDP4_MIXER0] != cfg[MDP4_MIXER0]) ||
-		    (ctrl->mixer_cfg[MDP4_MIXER1] != cfg[MDP4_MIXER1])) {
-			off = 0x10100;
-			if (ctrl->mixer_cfg[MDP4_MIXER0] != cfg[MDP4_MIXER0]) {
-				flush_bits |= 0x1;
-				ctrl->mixer_cfg[MDP4_MIXER0] = cfg[MDP4_MIXER0];
+	local_irq_save(flags);
+	if (off)
+		outpdw(MDP_BASE + off, data);
 
-				if ((ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) ||
-				    (ctrl->panel_mode & MDP4_PANEL_LCDC))
-					pull_mode = 1;
-			}
-			if (ctrl->mixer_cfg[MDP4_MIXER1] != cfg[MDP4_MIXER1]) {
-				flush_bits |= 0x2;
-				ctrl->mixer_cfg[MDP4_MIXER1] = cfg[MDP4_MIXER1];
-
-				pull_mode = 1;
-			}
-
-			data = cfg[MDP4_MIXER0] | cfg[MDP4_MIXER1];
-
-			pr_debug("%s: mixer=%d data=%x flush=%x\n", __func__,
-			       mixer, data, flush_bits);
-
-			outpdw(MDP_BASE + off, data); /* LAYERMIXER_IN_CFG */
-			if (pull_mode) {
-				outpdw(MDP_BASE + 0x18000, flush_bits);
-			/* wait for vsync on both pull mode interfaces */
-				msleep(20);
-			}
-		}
-
-		if (ctrl->mixer_cfg[MDP4_MIXER2] != cfg[MDP4_MIXER2]) {
-			off = 0x100F0;
-			ctrl->mixer_cfg[MDP4_MIXER2] = cfg[MDP4_MIXER2];
-			data = cfg[MDP4_MIXER2];
-
-			pr_debug("%s: mixer=%d data=%x\n", __func__,
-			       mixer, data);
-
-			outpdw(MDP_BASE + off, data); /* LAYERMIXER_IN_CFG */
-		}
-	} else {
-		if (mixer == MDP4_MIXER0) {
-			if ((ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) ||
-			(ctrl->panel_mode & MDP4_PANEL_LCDC))
-				pull_mode = 1;
-		} else if (mixer == MDP4_MIXER1) {
-			pull_mode = 1;
-		}
-
-		if (pull_mode)
-			outpdw(MDP_BASE + 0x18000, flush_bits);
+	if (ctrl->flush[mixer]) {
+		outpdw(MDP_BASE + 0x18000, ctrl->flush[mixer]);
+		ctrl->flush[mixer] = 0;
 	}
+	local_irq_restore(flags);
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-
-	if (data && pipe_cnt == 1)
-		mdp4_update_perf_level(OVERLAY_PERF_LEVEL4);
 }
 
+
 void mdp4_mixer_stage_up(struct mdp4_overlay_pipe *pipe)
 {
-	struct mdp4_overlay_pipe *spipe;
-	int mixer;
+	struct mdp4_overlay_pipe *pp;
+	int i, mixer;
 
 	mixer = pipe->mixer_num;
 
-	spipe = ctrl->stage[mixer][pipe->mixer_stage];
-	if ((spipe != NULL) && (spipe->pipe_num != pipe->pipe_num)) {
-		mdp4_stat.err_stage++;
-		return;
+	for (i = MDP4_MIXER_STAGE_BASE; i < MDP4_MIXER_STAGE_MAX; i++) {
+		pp = ctrl->stage[mixer][i];
+		if (pp == pipe) {
+			ctrl->stage[mixer][i] = NULL;
+			break;
+		}
 	}
 
 	ctrl->stage[mixer][pipe->mixer_stage] = pipe;	/* keep it */
 
-	if (!(pipe->flags & MDP_OV_PLAY_NOWAIT))
+	if (!(pipe->flags & MDP_OV_PLAY_NOWAIT)) {
+		pr_debug("%s: mixer=%d ndx=%d stage=%d flags=%x\n",
+			__func__, mixer, pipe->pipe_ndx,
+				pipe->mixer_stage, pipe->flags);
 		mdp4_mixer_stage_commit(mixer);
+	}
 }
 
 void mdp4_mixer_stage_down(struct mdp4_overlay_pipe *pipe)
 {
-	struct mdp4_overlay_pipe *spipe;
+	struct mdp4_overlay_pipe *pp;
+	int i, mixer;
 
-	spipe = ctrl->stage[pipe->mixer_num][pipe->mixer_stage];
-	if (spipe == NULL)	/* not running */
+	mixer = pipe->mixer_num;
+
+	for (i = MDP4_MIXER_STAGE_BASE; i < MDP4_MIXER_STAGE_MAX; i++) {
+		pp = ctrl->stage[mixer][i];
+		if (pp == pipe)
+			ctrl->stage[mixer][i] = NULL;  /* clear it */
+	}
+
+	if (!(pipe->flags & MDP_OV_PLAY_NOWAIT)) {
+		pr_debug("%s: mixer=%d ndx=%d stage=%d flags=%x\n",
+			__func__, pipe->mixer_num, pipe->pipe_ndx,
+				pipe->mixer_stage, pipe->flags);
+		mdp4_mixer_stage_commit(pipe->mixer_num);
+	}
+}
+/*
+ * mixer0: rgb3: border color at register 0x15004, 0x15008
+ * mixer1:  vg3: border color at register 0x1D004, 0x1D008
+ * mixer2:  xxx: border color at register 0x8D004, 0x8D008
+ */
+void mdp4_overlay_borderfill_stage_up(struct mdp4_overlay_pipe *pipe)
+{
+	struct mdp4_overlay_pipe *bspipe;
+	int ptype, pnum, pndx, mixer;
+	int format, alpha_enable, alpha;
+
+	if (pipe->pipe_type != OVERLAY_TYPE_BF)
 		return;
 
-	ctrl->stage[pipe->mixer_num][pipe->mixer_stage] = NULL;	/* clear it */
+	mixer = pipe->mixer_num;
 
-	mdp4_mixer_stage_commit(pipe->mixer_num);
+	if (ctrl->baselayer[mixer])
+		return;
+
+	bspipe = ctrl->stage[mixer][MDP4_MIXER_STAGE_BASE];
+
+	/* save original base layer */
+	ctrl->baselayer[mixer] = bspipe;
+
+	pipe->alpha = 0;	/* make sure bf pipe has alpha 0 */
+	ptype = pipe->pipe_type;
+	pnum = pipe->pipe_num;
+	pndx = pipe->pipe_ndx;
+	format = pipe->src_format;
+	alpha_enable = pipe->alpha_enable;
+	alpha = pipe->alpha;
+	*pipe = *bspipe;	/* keep base layer configuration */
+	pipe->pipe_type = ptype;
+	pipe->pipe_num = pnum;
+	pipe->pipe_ndx = pndx;
+	pipe->src_format = format;
+	pipe->alpha_enable = alpha_enable;
+	pipe->alpha = alpha;
+
+	/* free original base layer pipe to be sued as normal pipe */
+	bspipe->pipe_used = 0;
+
+	if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO)
+		mdp4_dsi_video_base_swap(pipe);
+	else if (ctrl->panel_mode & MDP4_PANEL_LCDC)
+		mdp4_lcdc_base_swap(pipe);
+	else if (ctrl->panel_mode & MDP4_PANEL_DTV)
+		mdp4_dtv_base_swap(pipe);
+
+	mdp4_overlay_reg_flush(bspipe, 1);
+	/* borderfill pipe as base layer */
+	mdp4_mixer_stage_up(pipe);
 }
 
-void mdp4_mixer_blend_setup(struct mdp4_overlay_pipe *pipe)
+void mdp4_overlay_borderfill_stage_down(struct mdp4_overlay_pipe *pipe)
 {
-	struct mdp4_overlay_pipe *bg_pipe;
-	unsigned char *overlay_base, *rgb_base;
-	uint32 c0, c1, c2, blend_op, constant_color = 0, rgb_src_format;
-	uint32 fg_color3_out, fg_alpha = 0, bg_alpha = 0;
-	int off, pnum;
+	struct mdp4_overlay_pipe *bspipe;
+	int ptype, pnum, pndx, mixer;
+	int format, alpha_enable, alpha;
 
-	if (pipe->mixer_stage == MDP4_MIXER_STAGE_BASE)
+	if (pipe->pipe_type != OVERLAY_TYPE_BF)
 		return;
 
+	mixer = pipe->mixer_num;
+
+	/* retrieve original base layer */
+	bspipe = ctrl->baselayer[mixer];
+	if (bspipe == NULL) {
+		pr_err("%s: no base layer at mixer=%d\n",
+				__func__, mixer);
+		return;
+	}
+
+	ptype = bspipe->pipe_type;
+	pnum = bspipe->pipe_num;
+	pndx = bspipe->pipe_ndx;
+	format = bspipe->src_format;
+	alpha_enable = bspipe->alpha_enable;
+	alpha = bspipe->alpha;
+	*bspipe = *pipe;	/* restore base layer configuration */
+	bspipe->pipe_type = ptype;
+	bspipe->pipe_num = pnum;
+	bspipe->pipe_ndx = pndx;
+	bspipe->src_format = format;
+	bspipe->alpha_enable = alpha_enable;
+	bspipe->alpha = alpha;
+
+	bspipe->pipe_used++;	/* mark base layer pipe used */
+
+	ctrl->baselayer[mixer] = NULL;
+
+	/* free borderfill pipe */
+	pipe->pipe_used = 0;
+
+	mdp4_dsi_video_base_swap(bspipe);
+
+	/* free borderfill pipe */
+	mdp4_overlay_reg_flush(pipe, 1);
+	mdp4_mixer_stage_down(pipe);
+	mdp4_overlay_pipe_free(pipe);
+
+	/* stage up base layer */
+	mdp4_overlay_reg_flush(bspipe, 1);
+	/* restore original base layer */
+	mdp4_mixer_stage_up(bspipe);
+}
+
+
+static struct mdp4_overlay_pipe *mdp4_background_layer(int mixer,
+			struct mdp4_overlay_pipe *sp)
+{
+	struct mdp4_overlay_pipe *pp;
+	struct mdp4_overlay_pipe *kp;
+	int i;
+
+	kp = ctrl->stage[mixer][MDP4_MIXER_STAGE_BASE];
+	for (i = MDP4_MIXER_STAGE_BASE; i < MDP4_MIXER_STAGE_MAX; i++) {
+		pp = ctrl->stage[mixer][i];
+		if (pp == NULL)
+			continue;
+		if (pp == sp)
+			break;
+
+		if ((pp->dst_x <= sp->dst_x) &&
+			((pp->dst_x + pp->dst_w) >= (sp->dst_x + sp->dst_w))) {
+			if ((pp->dst_y <= sp->dst_y) &&
+				((pp->dst_y + pp->dst_h) >=
+					(sp->dst_y + sp->dst_h))) {
+				kp = pp;
+			}
+		}
+	}
+	return kp;
+}
+
+static void mdp4_overlay_bg_solidfill(struct blend_cfg *blend)
+{
+	struct mdp4_overlay_pipe *pipe;
+	char *base;
+	u32 op_mode, format;
+	int pnum, ptype;
+
+	pipe = blend->solidfill_pipe;
+	if (pipe == NULL)
+		return;
+
+	if (pipe->pipe_type == OVERLAY_TYPE_BF)
+		return;
+
+	ptype = mdp4_overlay_format2type(pipe->src_format);
+	if (ptype == OVERLAY_TYPE_RGB) {
+		pnum = pipe->pipe_num - OVERLAY_PIPE_RGB1;
+		base = MDP_BASE + MDP4_RGB_BASE;
+		base += MDP4_RGB_OFF * pnum;
+	} else {
+		pnum = pipe->pipe_num - OVERLAY_PIPE_VG1;
+		base = MDP_BASE + MDP4_VIDEO_BASE;
+		base += MDP4_VIDEO_OFF * pnum;
+	}
+
+	format = inpdw(base + 0x50);
+	if (blend->solidfill) {
+		format |= MDP4_FORMAT_SOLID_FILL;
+		/*
+		 * If solid fill is enabled, flip and scale
+		 * have to be disabled. otherwise, h/w
+		 * underruns.
+		 */
+		op_mode = inpdw(base + 0x0058);
+		op_mode &= ~(MDP4_OP_FLIP_LR + MDP4_OP_SCALEX_EN);
+		op_mode &= ~(MDP4_OP_FLIP_UD + MDP4_OP_SCALEY_EN);
+		outpdw(base + 0x0058, op_mode);
+		outpdw(base + 0x1008, 0);	/* black */
+	} else {
+		format &= ~MDP4_FORMAT_SOLID_FILL;
+		blend->solidfill_pipe = NULL;
+	}
+
+	outpdw(base + 0x50, format);
+
+	mdp4_overlay_reg_flush(pipe, 0);
+}
+
+/*
+ * D(i+1) = Ks * S + Kd * D(i)
+ */
+void mdp4_mixer_blend_setup(int mixer)
+{
+	struct mdp4_overlay_pipe *d_pipe;
+	struct mdp4_overlay_pipe *s_pipe;
+	struct blend_cfg *blend;
+	int i, off, ptype;
+	int d_alpha, s_alpha;
+	unsigned char *overlay_base;
+	uint32 c0, c1, c2;
+
+
+	d_pipe = ctrl->stage[mixer][MDP4_MIXER_STAGE_BASE];
+	if (d_pipe == NULL) {
+		pr_err("%s: Error: no bg_pipe at mixer=%d\n", __func__, mixer);
+		return;
+	}
+
+	blend = &ctrl->blend[mixer][MDP4_MIXER_STAGE0];
+	for (i = MDP4_MIXER_STAGE0; i < MDP4_MIXER_STAGE_MAX; i++) {
+		blend->solidfill = 0;
+		blend->op = (MDP4_BLEND_FG_ALPHA_FG_CONST |
+				    MDP4_BLEND_BG_ALPHA_BG_CONST);
+		s_pipe = ctrl->stage[mixer][i];
+		if (s_pipe == NULL) {
+			blend++;
+			d_pipe = NULL;
+			d_alpha = 0;
+			continue;
+		}
+		d_pipe = mdp4_background_layer(mixer, s_pipe);
+		d_alpha = d_pipe->alpha_enable;
+		s_alpha = s_pipe->alpha_enable;
+		pr_debug("%s: stage=%d: bg: ndx=%d da=%d dalpha=%x "
+			"fg: ndx=%d sa=%d salpha=%x is_fg=%d\n",
+		 __func__, i-2, d_pipe->pipe_ndx, d_alpha, d_pipe->alpha,
+		s_pipe->pipe_ndx, s_alpha, s_pipe->alpha, s_pipe->is_fg);
+
+		/* base on fg's alpha */
+		blend->bg_alpha = 0x0ff - s_pipe->alpha;
+		blend->fg_alpha = s_pipe->alpha;
+		blend->co3_sel = 1; /* use fg alpha */
+
+		if (s_pipe->is_fg) {
+			if (s_pipe->alpha == 0xff) {
+				blend->solidfill = 1;
+				blend->solidfill_pipe = d_pipe;
+			}
+		} else if (s_alpha) {
+			blend->op = (MDP4_BLEND_BG_ALPHA_FG_PIXEL |
+				    MDP4_BLEND_BG_INV_ALPHA);
+		} else if (d_alpha) {
+			ptype = mdp4_overlay_format2type(s_pipe->src_format);
+			if (ptype == OVERLAY_TYPE_VIDEO) {
+				blend->op = (MDP4_BLEND_BG_ALPHA_BG_PIXEL |
+				    MDP4_BLEND_FG_ALPHA_BG_PIXEL |
+				    MDP4_BLEND_FG_INV_ALPHA);
+				blend->co3_sel = 0; /* use bg alpha */
+			} else {
+				/* s_pipe is rgb without alpha */
+				blend->op = (MDP4_BLEND_FG_ALPHA_FG_CONST |
+					    MDP4_BLEND_BG_ALPHA_BG_CONST);
+				blend->bg_alpha = 0;
+			}
+		}
+
+		if (s_pipe->transp != MDP_TRANSP_NOP) {
+			if (s_pipe->is_fg) {
+				transp_color_key(s_pipe->src_format,
+						s_pipe->transp, &c0, &c1, &c2);
+				/* Fg blocked */
+				blend->op |= MDP4_BLEND_FG_TRANSP_EN;
+				/* lower limit */
+				blend->transp_low0 = (c1 << 16 | c0);
+				blend->transp_low1 = c2;
+				/* upper limit */
+				blend->transp_high0 = (c1 << 16 | c0);
+				blend->transp_high1 = c2;
+			} else {
+				transp_color_key(d_pipe->src_format,
+						s_pipe->transp, &c0, &c1, &c2);
+				/* Fg blocked */
+				blend->op |= MDP4_BLEND_BG_TRANSP_EN;
+				blend--; /* one stage back */
+				/* lower limit */
+				blend->transp_low0 = (c1 << 16 | c0);
+				blend->transp_low1 = c2;
+				/* upper limit */
+				blend->transp_high0 = (c1 << 16 | c0);
+				blend->transp_high1 = c2;
+				blend++; /* back to original stage */
+			}
+		}
+		blend++;
+	}
+
 	/* mixer numer, /dev/fb0, /dev/fb1, /dev/fb2 */
-	if (pipe->mixer_num == MDP4_MIXER2)
+	if (mixer == MDP4_MIXER2)
 		overlay_base = MDP_BASE + MDP4_OVERLAYPROC2_BASE;/* 0x88000 */
-	else if (pipe->mixer_num == MDP4_MIXER1)
+	else if (mixer == MDP4_MIXER1)
 		overlay_base = MDP_BASE + MDP4_OVERLAYPROC1_BASE;/* 0x18000 */
 	else
 		overlay_base = MDP_BASE + MDP4_OVERLAYPROC0_BASE;/* 0x10000 */
 
-	/* stage 0 to stage 2 */
-	off = 0x20 * (pipe->mixer_stage - MDP4_MIXER_STAGE0);
-
-	bg_pipe = mdp4_overlay_stage_pipe(pipe->mixer_num,
-					  MDP4_MIXER_STAGE_BASE);
-	if (bg_pipe == NULL) {
-		pr_err("%s: Error: no bg_pipe\n", __func__);
-		return;
-	}
-
-	if (bg_pipe->pipe_type == OVERLAY_TYPE_BF &&
-	    pipe->mixer_stage > MDP4_MIXER_STAGE0) {
-		bg_pipe = mdp4_overlay_stage_pipe(pipe->mixer_num,
-						  MDP4_MIXER_STAGE0);
-	}
-
-	if (pipe->alpha_enable) {
-		/* alpha channel is lost on VG pipe when downscaling */
-		if (pipe->pipe_type == OVERLAY_TYPE_VIDEO &&
-		    (pipe->dst_w < pipe->src_w || pipe->dst_h < pipe->src_h))
-			fg_alpha = 0;
-		else
-			fg_alpha = 1;
-	}
-
-	if (!fg_alpha && bg_pipe && bg_pipe->alpha_enable) {
-		struct mdp4_overlay_pipe *tmp;
-		int stage;
-
-		bg_alpha = 1;
-		/* check all bg layers are opaque to propagate bg alpha */
-		stage = bg_pipe->mixer_stage + 1;
-		for (; stage < pipe->mixer_stage; stage++) {
-			tmp = mdp4_overlay_stage_pipe(pipe->mixer_num, stage);
-			if (!tmp || tmp->alpha_enable || tmp->is_fg) {
-				bg_alpha = 0;
-				break;
-			}
-		}
-	}
-
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+	blend = &ctrl->blend[mixer][MDP4_MIXER_STAGE_BASE];
+	/* lower limit */
+	outpdw(overlay_base + 0x180, blend->transp_low0);
+	outpdw(overlay_base + 0x184,  blend->transp_low1);
+	/* upper limit */
+	outpdw(overlay_base + 0x188, blend->transp_high0);
+	outpdw(overlay_base + 0x18c,  blend->transp_high1);
+	blend++; /* stage0 */
+	for (i = MDP4_MIXER_STAGE0; i < MDP4_MIXER_STAGE_MAX; i++) {
+		off = 20 * i;
+		off = 0x20 * (i - MDP4_MIXER_STAGE0);
+		if (i == MDP4_MIXER_STAGE3)
+			off -= 4;
 
-	blend_op = (MDP4_BLEND_FG_ALPHA_FG_CONST |
-		    MDP4_BLEND_BG_ALPHA_BG_CONST);
-	outpdw(overlay_base + off + 0x108, pipe->alpha);
-	outpdw(overlay_base + off + 0x10c, 0xff - pipe->alpha);
-	fg_color3_out = 1; /* keep fg alpha by default */
+		if (blend->solidfill_pipe)
+			mdp4_overlay_bg_solidfill(blend);
 
-	if (pipe->is_fg) {
-		if (pipe->alpha == 0xff &&
-			bg_pipe->pipe_type == OVERLAY_TYPE_RGB) {
-			u32 op_mode;
-			pnum = bg_pipe->pipe_num - OVERLAY_PIPE_RGB1;
-			rgb_base = MDP_BASE + MDP4_RGB_BASE;
-			rgb_base += MDP4_RGB_OFF * pnum;
-			rgb_src_format = inpdw(rgb_base + 0x50);
-			rgb_src_format |= MDP4_FORMAT_SOLID_FILL;
-			/*
-			 * If solid fill is enabled, flip and scale
-			 * have to be disabled. otherwise, h/w
-			 * underruns. Also flush the pipe inorder
-			 * to take solid fill into effect.
-			 */
-			op_mode = inpdw(rgb_base + 0x0058);
-			op_mode &= ~(MDP4_OP_FLIP_LR + MDP4_OP_SCALEX_EN);
-			op_mode &= ~(MDP4_OP_FLIP_UD + MDP4_OP_SCALEY_EN);
-			outpdw(rgb_base + 0x0058, op_mode);
-			outpdw(rgb_base + 0x50, rgb_src_format);
-			outpdw(rgb_base + 0x1008, constant_color);
-			mdp4_overlay_reg_flush(bg_pipe, 0);
-		}
-	} else if (fg_alpha) {
-		blend_op = (MDP4_BLEND_BG_ALPHA_FG_PIXEL |
-			    MDP4_BLEND_BG_INV_ALPHA);
-		fg_color3_out = 1; /* keep fg alpha */
-	} else if (bg_alpha) {
-		blend_op = (MDP4_BLEND_BG_ALPHA_BG_PIXEL |
-			    MDP4_BLEND_FG_ALPHA_BG_PIXEL |
-			    MDP4_BLEND_FG_INV_ALPHA);
-		fg_color3_out = 0; /* keep bg alpha */
-	}
-
-	if (pipe->transp != MDP_TRANSP_NOP) {
-		if (pipe->is_fg) {
-			transp_color_key(pipe->src_format, pipe->transp,
-					&c0, &c1, &c2);
-			/* Fg blocked */
-			blend_op |= MDP4_BLEND_FG_TRANSP_EN;
-			/* lower limit */
-			outpdw(overlay_base + off + 0x110,
-					(c1 << 16 | c0));/* low */
-			outpdw(overlay_base + off + 0x114, c2);/* low */
+		outpdw(overlay_base + off + 0x108, blend->fg_alpha);
+		outpdw(overlay_base + off + 0x10c, blend->bg_alpha);
+		outpdw(overlay_base + off + 0x104, blend->op);
+		outpdw(overlay_base + (off << 5) + 0x1004, blend->co3_sel);
+		outpdw(overlay_base + off + 0x110, blend->transp_low0);/* low */
+		outpdw(overlay_base + off + 0x114, blend->transp_low1);/* low */
 			/* upper limit */
-			outpdw(overlay_base + off + 0x118,
-					(c1 << 16 | c0));
-			outpdw(overlay_base + off + 0x11c, c2);
-		} else if (bg_pipe) {
-			transp_color_key(bg_pipe->src_format,
-				pipe->transp, &c0, &c1, &c2);
-			/* bg blocked */
-			blend_op |= MDP4_BLEND_BG_TRANSP_EN;
-			/* lower limit */
-			outpdw(overlay_base + 0x180,
-					(c1 << 16 | c0));/* low */
-			outpdw(overlay_base + 0x184, c2);/* low */
-			/* upper limit */
-			outpdw(overlay_base + 0x188,
-					(c1 << 16 | c0));/* high */
-			outpdw(overlay_base + 0x18c, c2);/* high */
-		}
+		outpdw(overlay_base + off + 0x118, blend->transp_high0);
+		outpdw(overlay_base + off + 0x11c, blend->transp_high1);
+		blend++;
 	}
-
-	outpdw(overlay_base + off + 0x104, blend_op);
-	outpdw(overlay_base + (off << 5) + 0x1004, fg_color3_out);
-
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 }
 
 void mdp4_overlay_reg_flush(struct mdp4_overlay_pipe *pipe, int all)
 {
-	struct mdp4_overlay_pipe *bg_pipe;
-	uint32 bits = 0;
+	int mixer;
+	uint32 *reg;
+
+	mixer = pipe->mixer_num;
+	reg = &ctrl->flush[mixer];
+	*reg |= (1 << (2 + pipe->pipe_num));
 
 	if (all) {
-		if (pipe->mixer_num == MDP4_MIXER1)
-			bits |= 0x02;
+		if (mixer == MDP4_MIXER0)
+			*reg |= 0x01;
 		else
-			bits |= 0x01;
+			*reg |= 0x02;
 	}
+}
 
-	if (pipe->pipe_num <= OVERLAY_PIPE_RGB2)
-		bits |= 1 << (2 + pipe->pipe_num);
-	if (pipe->is_fg && pipe->alpha == 0xFF) {
-		bg_pipe = mdp4_overlay_stage_pipe(pipe->mixer_num,
-						  MDP4_MIXER_STAGE_BASE);
-		bits |= 1 << (2 + bg_pipe->pipe_num);
-	}
+void mdp4_overlay_flush_piggyback(int m0, int m1)
+{
+	u32 data;
 
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	outpdw(MDP_BASE + 0x18000, bits);	/* MDP_OVERLAY_REG_FLUSH */
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+	data = ctrl->flush[m0] | ctrl->flush[m1];
+	ctrl->flush[m0] = data;
+}
+
+void mdp4_overlay_reg_flush_reset(struct mdp4_overlay_pipe *pipe)
+{
+	int mixer;
+
+	mixer = pipe->mixer_num;
+	ctrl->flush[mixer] = 0;
 }
 
 struct mdp4_overlay_pipe *mdp4_overlay_stage_pipe(int mixer, int stage)
@@ -1810,6 +1952,11 @@
 	int i;
 	struct mdp4_overlay_pipe *pipe;
 
+	if (ptype == OVERLAY_TYPE_BF) {
+		if (!mdp4_overlay_borderfill_supported())
+			return NULL;
+	}
+
 	for (i = 0; i < OVERLAY_PIPE_MAX; i++) {
 		pipe = &ctrl->plist[i];
 		if ((pipe->pipe_used == 0) && ((pipe->pipe_type == ptype) ||
@@ -1951,7 +2098,7 @@
 		return -ERANGE;
 	}
 
-	if (req->z_order < 0 || req->z_order > 2) {
+	if (req->z_order < 0 || req->z_order > 3) {
 		pr_err("%s: z_order=%d out of range!\n", __func__,
 				req->z_order);
 		mdp4_stat.err_zorder++;
@@ -2076,12 +2223,12 @@
 	if (req->id == MSMFB_NEW_REQUEST) {  /* new request */
 		pipe->pipe_used++;
 		pipe->mixer_num = mixer;
-		pipe->mixer_stage = req->z_order + MDP4_MIXER_STAGE0;
 		pr_debug("%s: zorder=%d pipe ndx=%d num=%d\n", __func__,
 			req->z_order, pipe->pipe_ndx, pipe->pipe_num);
 
 	}
 
+	pipe->mixer_stage = req->z_order + MDP4_MIXER_STAGE0;
 	pipe->src_width = req->src.width & 0x1fff;	/* source img width */
 	pipe->src_height = req->src.height & 0x1fff;	/* source img height */
 	pipe->src_h = req->src_rect.h & 0x07ff;
@@ -2217,6 +2364,8 @@
 		mdp4_dsi_video_overlay_blt(mfd, req);
 	else if (ctrl->panel_mode & MDP4_PANEL_LCDC)
 		mdp4_lcdc_overlay_blt(mfd, req);
+	else if (ctrl->panel_mode & MDP4_PANEL_MDDI)
+		mdp4_mddi_overlay_blt(mfd, req);
 
 	mutex_unlock(&mfd->dma->ov_mutex);
 
@@ -2238,6 +2387,8 @@
 		ret = mdp4_dsi_video_overlay_blt_offset(mfd, req);
 	else if (ctrl->panel_mode & MDP4_PANEL_LCDC)
 		ret = mdp4_lcdc_overlay_blt_offset(mfd, req);
+	else if (ctrl->panel_mode & MDP4_PANEL_MDDI)
+		mdp4_mddi_overlay_blt_offset(mfd, req);
 
 	mutex_unlock(&mfd->dma->ov_mutex);
 
@@ -2331,7 +2482,14 @@
 
 void mdp4_update_perf_level(u32 perf_level)
 {
+	static int first = 1;
+
 	new_perf_level = perf_level;
+
+	if (first) {
+		first = 0;
+		mdp4_set_perf_level();
+	}
 }
 
 void mdp4_set_perf_level(void)
@@ -2365,6 +2523,8 @@
 			mdp4_dsi_video_blt_start(mfd);
 		else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD)
 			mdp4_dsi_overlay_blt_start(mfd);
+		else if (ctrl->panel_mode & MDP4_PANEL_MDDI)
+			mdp4_mddi_overlay_blt_start(mfd);
 	} else {
 		if (mfd->panel_info.type == LCDC_PANEL ||
 		    mfd->panel_info.type == LVDS_PANEL)
@@ -2373,6 +2533,8 @@
 			mdp4_dsi_video_blt_stop(mfd);
 		else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD)
 			mdp4_dsi_overlay_blt_stop(mfd);
+		else if (ctrl->panel_mode & MDP4_PANEL_MDDI)
+			mdp4_mddi_overlay_blt_stop(mfd);
 	}
 	mfd->ov0_blt_state = mfd->use_ov0_blt;
 }
@@ -2413,6 +2575,12 @@
 			use_blt = 1;
 	}
 
+	if (mfd->panel_info.type == MDDI_PANEL) {
+		if ((req->src_rect.h/2) >= req->dst_rect.h ||
+			(req->src_rect.w/2) >= req->dst_rect.w)
+				use_blt = 1;
+	}
+
 	if (mfd->mdp_rev == MDP_REV_41) {
 		/*
 		* writeback (blt) mode to provide work around for
@@ -2539,6 +2707,7 @@
 					mdp4_set_perf_level();
 			} else if (ctrl->panel_mode & MDP4_PANEL_MDDI) {
 				mdp4_mddi_dma_busy_wait(mfd);
+				mdp4_mddi_blt_dmap_busy_wait(mfd);
 				mdp4_set_perf_level();
 			}
 		} else {
@@ -2553,6 +2722,24 @@
 	return 0;
 }
 
+int mdp4_overlay_unset_mixer(int mixer)
+{
+	struct mdp4_overlay_pipe *pipe;
+	int i, cnt = 0;
+
+	for (i = MDP4_MIXER_STAGE3; i >= MDP4_MIXER_STAGE_BASE; i--) {
+		pipe = ctrl->stage[mixer][i];
+		if (pipe == NULL)
+			continue;
+		pipe->flags &= ~MDP_OV_PLAY_NOWAIT;
+		mdp4_mixer_stage_down(pipe);
+		mdp4_overlay_pipe_free(pipe);
+		cnt++;
+	}
+
+	return cnt;
+}
+
 int mdp4_overlay_unset(struct fb_info *info, int ndx)
 {
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
@@ -2573,6 +2760,12 @@
 		return -ENODEV;
 	}
 
+	if (pipe->pipe_type == OVERLAY_TYPE_BF) {
+		mdp4_overlay_borderfill_stage_down(pipe);
+		mutex_unlock(&mfd->dma->ov_mutex);
+		return 0;
+	}
+
 	if (pipe->mixer_num == MDP4_MIXER2)
 		ctrl->mixer2_played = 0;
 	else if (pipe->mixer_num == MDP4_MIXER1)
@@ -2589,21 +2782,17 @@
 #else
 		if (ctrl->panel_mode & MDP4_PANEL_MDDI) {
 			if (mfd->panel_power_on)
-				mdp4_mddi_dma_busy_wait(mfd);
+				mdp4_mddi_blt_dmap_busy_wait(mfd);
 		}
 #endif
 	}
 
-	if (mfd->mdp_rev >= MDP_REV_41 &&
-		mdp4_overlay_is_rgb_type(pipe->src_format) &&
-		!mfd->use_ov0_blt && (pipe->mixer_num == MDP4_MIXER0 ||
-		hdmi_prim_display)) {
-			ctrl->stage[pipe->mixer_num][pipe->mixer_stage] = NULL;
-	} else {
-		if (pipe->is_fg &&
-			!mdp4_overlay_is_rgb_type(pipe->src_format)) {
-			mdp4_overlay_bg_solidfill_clear(pipe->mixer_num);
-			pipe->is_fg = 0;
+	{
+		mdp4_overlay_reg_flush(pipe, 1);
+
+		if (mfd->use_ov0_blt || pipe->mixer_num == MDP4_MIXER1) {
+			/* unstage pipe forcedly */
+			pipe->flags &= ~MDP_OV_PLAY_NOWAIT;
 		}
 
 		mdp4_mixer_stage_down(pipe);
@@ -2764,6 +2953,12 @@
 	if (mutex_lock_interruptible(&mfd->dma->ov_mutex))
 		return -EINTR;
 
+	if (pipe->pipe_type == OVERLAY_TYPE_BF) {
+		mdp4_overlay_borderfill_stage_up(pipe);
+		mutex_unlock(&mfd->dma->ov_mutex);
+		return 0;
+	}
+
 	img = &req->data;
 	get_img(img, info, pipe, 0, &start, &len, &srcp0_file,
 		&ps0_need, &srcp0_ihdl);
@@ -2778,6 +2973,10 @@
 	pipe->srcp0_addr = addr;
 	pipe->srcp0_ystride = pipe->src_width * pipe->bpp;
 
+
+	pr_debug("%s: mixer=%d ndx=%x addr=%x flags=%x\n", __func__,
+		pipe->mixer_num, pipe->pipe_ndx, (int)addr, pipe->flags);
+
 	if ((req->version_key & VERSION_KEY_MASK) == 0xF9E8D700)
 		overlay_version = (req->version_key & ~VERSION_KEY_MASK);
 
@@ -2874,6 +3073,7 @@
 	if (mfd->use_ov1_blt)
 		mdp4_overlay1_update_blt_mode(mfd);
 
+
 	if (pipe->pipe_type == OVERLAY_TYPE_VIDEO) {
 		mdp4_overlay_vg_setup(pipe);	/* video/graphic pipe */
 	} else {
@@ -2886,11 +3086,7 @@
 		mdp4_overlay_rgb_setup(pipe);	/* rgb pipe */
 	}
 
-	if ((ctrl->panel_mode & MDP4_PANEL_DTV) ||
-		(ctrl->panel_mode & MDP4_PANEL_LCDC) ||
-		(ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO))
-		mdp4_overlay_reg_flush(pipe, 0);
-
+	mdp4_overlay_reg_flush(pipe, 1);
 	mdp4_mixer_stage_up(pipe);
 
 	if (pipe->mixer_num == MDP4_MIXER2) {
@@ -2905,6 +3101,9 @@
 		ctrl->mixer1_played++;
 		/* enternal interface */
 		if (ctrl->panel_mode & MDP4_PANEL_DTV) {
+			if (pipe->flags & MDP_OV_PLAY_NOWAIT)
+				mdp4_overlay_flush_piggyback(MDP4_MIXER0,
+							MDP4_MIXER1);
 			mdp4_overlay_dtv_start();
 			mdp4_overlay_dtv_ov_done_push(mfd, pipe);
 			if (!mfd->use_ov1_blt)
@@ -2933,6 +3132,7 @@
 		}
 #endif
 		else {
+			mdp4_overlay_reg_flush_reset(pipe);
 			/* mddi & mipi dsi cmd mode */
 			if (pipe->flags & MDP_OV_PLAY_NOWAIT) {
 				mdp4_stat.overlay_play[pipe->mixer_num]++;
@@ -3002,7 +3202,6 @@
 	},
 };
 
-static int iommu_enabled;
 static int mdp_iommu_fault_handler(struct iommu_domain *domain,
 	struct device *dev, unsigned long iova, int flags)
 {
@@ -3012,10 +3211,11 @@
 
 void mdp4_iommu_attach(void)
 {
+	static int done;
 	struct iommu_domain *domain;
 	int i;
 
-	if (!iommu_enabled) {
+	if (!done) {
 		for (i = 0; i < ARRAY_SIZE(msm_iommu_ctx_names); i++) {
 			int domain_idx;
 			struct device *ctx = msm_iommu_get_ctx(
@@ -3040,38 +3240,7 @@
 				continue;
 			}
 		}
-		pr_debug("Attached MDP IOMMU device\n");
-		iommu_enabled = 1;
-	}
-}
-
-void mdp4_iommu_detach(void)
-{
-	struct iommu_domain *domain;
-	int i;
-
-	if (!mdp_check_suspended() || mdp4_extn_disp)
-		return;
-
-	if (iommu_enabled) {
-		for (i = 0; i < ARRAY_SIZE(msm_iommu_ctx_names); i++) {
-			int domain_idx;
-			struct device *ctx = msm_iommu_get_ctx(
-				msm_iommu_ctx_names[i].name);
-
-			if (!ctx)
-				continue;
-
-			domain_idx = msm_iommu_ctx_names[i].domain;
-
-			domain = msm_get_iommu_domain(domain_idx);
-			if (!domain)
-				continue;
-
-			iommu_detach_device(domain,	ctx);
-		}
-		pr_debug("Detached MDP IOMMU device\n");
-		iommu_enabled = 0;
+		done = 1;
 	}
 }
 
@@ -3092,7 +3261,7 @@
 		return err;
 	}
 
-	mdp4_mixer_blend_setup(pipe);
+	mdp4_mixer_blend_setup(pipe->mixer_num);
 	*ppipe = pipe;
 
 	return 0;
diff --git a/drivers/video/msm/mdp4_overlay_dsi_cmd.c b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
index a5b4b3e..7ba4e75 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_cmd.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
@@ -114,6 +114,11 @@
 	}
 }
 
+void mdp4_dsi_cmd_base_swap(struct mdp4_overlay_pipe *pipe)
+{
+	dsi_pipe = pipe;
+}
+
 void mdp4_overlay_update_dsi_cmd(struct msm_fb_data_type *mfd)
 {
 	MDPIBUF *iBuf = &mfd->ibuf;
@@ -162,6 +167,14 @@
 	} else {
 		pipe = dsi_pipe;
 	}
+
+	if (pipe->pipe_used == 0 ||
+			pipe->mixer_stage != MDP4_MIXER_STAGE_BASE) {
+		pr_err("%s: NOT baselayer\n", __func__);
+		mutex_unlock(&mfd->dma->ov_mutex);
+		return;
+	}
+
 	/*
 	 * configure dsi stream id
 	 * dma_p = 0, dma_s = 1
@@ -207,6 +220,8 @@
 
 	mdp4_overlay_rgb_setup(pipe);
 
+	mdp4_overlay_reg_flush(pipe, 1);
+
 	mdp4_mixer_stage_up(pipe);
 
 	mdp4_overlayproc_cfg(pipe);
@@ -240,6 +255,12 @@
 	dsi_pipe->src_width_3d = r3d->width;
 
 	pipe = dsi_pipe;
+	if (pipe->pipe_used == 0 ||
+			pipe->mixer_stage != MDP4_MIXER_STAGE_BASE) {
+		pr_err("%s: NOT baselayer\n", __func__);
+		mutex_unlock(&mfd->dma->ov_mutex);
+		return;
+	}
 
 	if (pipe->is_3d)
 		mdp4_overlay_panel_3d(pipe->mixer_num, MDP4_3D_SIDE_BY_SIDE);
@@ -282,6 +303,8 @@
 
 	mdp4_overlay_rgb_setup(pipe);
 
+	mdp4_overlay_reg_flush(pipe, 1);
+
 	mdp4_mixer_stage_up(pipe);
 
 	mdp4_overlayproc_cfg(pipe);
@@ -651,12 +674,22 @@
 	mdp4_stat.kickoff_ov0++;
 }
 
-void mdp_dsi_cmd_overlay_suspend(void)
+void mdp_dsi_cmd_overlay_suspend(struct msm_fb_data_type *mfd)
 {
 	/* dis-engage rgb0 from mixer0 */
 	if (dsi_pipe) {
-		mdp4_mixer_stage_down(dsi_pipe);
-		mdp4_iommu_unmap(dsi_pipe);
+		if (mfd->ref_cnt == 0) {
+			/* adb stop */
+			if (dsi_pipe->pipe_type == OVERLAY_TYPE_BF)
+				mdp4_overlay_borderfill_stage_down(dsi_pipe);
+
+			/* dsi_pipe == rgb1 */
+			mdp4_overlay_unset_mixer(dsi_pipe->mixer_num);
+			dsi_pipe = NULL;
+		} else {
+			mdp4_mixer_stage_down(dsi_pipe);
+			mdp4_iommu_unmap(dsi_pipe);
+		}
 	}
 }
 
diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c
index fb71cc1..05c6fe8 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_video.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_video.c
@@ -69,6 +69,11 @@
 static void mdp4_overlay_dsi_video_wait4event(struct msm_fb_data_type *mfd,
 						int intr_done);
 
+void mdp4_dsi_video_base_swap(struct mdp4_overlay_pipe *pipe)
+{
+	dsi_pipe = pipe;
+}
+
 int mdp4_dsi_video_on(struct platform_device *pdev)
 {
 	int dsi_width;
@@ -118,8 +123,6 @@
 	if (mfd->key != MFD_KEY)
 		return -EINVAL;
 
-	mdp4_overlay_ctrl_db_reset();
-
 	fbi = mfd->fbi;
 	var = &fbi->var;
 
@@ -192,8 +195,9 @@
 
 	mdp4_overlay_dmap_xy(pipe);	/* dma_p */
 	mdp4_overlay_dmap_cfg(mfd, 1);
-
 	mdp4_overlay_rgb_setup(pipe);
+	mdp4_overlay_reg_flush(pipe, 1);
+	mdp4_mixer_stage_up(pipe);
 
 	mdp4_overlayproc_cfg(pipe);
 
@@ -291,10 +295,12 @@
 int mdp4_dsi_video_off(struct platform_device *pdev)
 {
 	int ret = 0;
+	struct msm_fb_data_type *mfd;
+
+	mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
 
 	/* MDP cmd block enable */
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	mdp4_mixer_pipe_cleanup(dsi_pipe->mixer_num);
 	MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE, 0);
 	dsi_video_enabled = 0;
 	/* MDP cmd block disable */
@@ -308,8 +314,18 @@
 
 	/* dis-engage rgb0 from mixer0 */
 	if (dsi_pipe) {
-		mdp4_mixer_stage_down(dsi_pipe);
-		mdp4_iommu_unmap(dsi_pipe);
+		if (mfd->ref_cnt == 0) {
+			/* adb stop */
+			if (dsi_pipe->pipe_type == OVERLAY_TYPE_BF)
+				mdp4_overlay_borderfill_stage_down(dsi_pipe);
+
+			/* dsi_pipe == rgb1 */
+			mdp4_overlay_unset_mixer(dsi_pipe->mixer_num);
+			dsi_pipe = NULL;
+		} else {
+			mdp4_mixer_stage_down(dsi_pipe);
+			mdp4_iommu_unmap(dsi_pipe);
+		}
 	}
 
 	return ret;
@@ -384,7 +400,6 @@
 	mdp4_overlay_dmap_cfg(mfd, 1);
 
 	mdp4_overlay_reg_flush(pipe, 1);
-
 	mdp4_mixer_stage_up(pipe);
 
 	mb();
@@ -632,7 +647,6 @@
 
 	spin_unlock_irqrestore(&mdp_spin_lock, flag);
 
-
 	/*
 	 * may need mutex here to sync with whom dsiable
 	 * timing generator
@@ -693,6 +707,12 @@
 	mutex_lock(&mfd->dma->ov_mutex);
 
 	pipe = dsi_pipe;
+	if (pipe->pipe_used == 0 ||
+			pipe->mixer_stage != MDP4_MIXER_STAGE_BASE) {
+		pr_err("%s: NOT baselayer\n", __func__);
+		mutex_unlock(&mfd->dma->ov_mutex);
+		return;
+	}
 
 	if (mfd->display_iova)
 		pipe->srcp0_addr = mfd->display_iova + buf_offset;
@@ -700,7 +720,7 @@
 		pipe->srcp0_addr = (uint32)(buf + buf_offset);
 
 	mdp4_overlay_rgb_setup(pipe);
-	mdp4_overlay_reg_flush(pipe, 0);
+	mdp4_overlay_reg_flush(pipe, 1);
 	mdp4_mixer_stage_up(pipe);
 	mdp4_overlay_dsi_video_start();
 	mdp4_overlay_dsi_video_vsync_push(mfd, pipe);
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index dd96439..aa1795f 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -56,6 +56,12 @@
 static struct mdp4_overlay_pipe *dtv_pipe;
 static DECLARE_COMPLETION(dtv_comp);
 
+void mdp4_dtv_base_swap(struct mdp4_overlay_pipe *pipe)
+{
+	if (hdmi_prim_display)
+		dtv_pipe = pipe;
+}
+
 static int mdp4_dtv_start(struct msm_fb_data_type *mfd)
 {
 	int dtv_width;
@@ -208,7 +214,6 @@
 
 	/* MDP cmd block enable */
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	mdp4_mixer_pipe_cleanup(dtv_pipe->mixer_num);
 	msleep(20);
 	MDP_OUTP(MDP_BASE + DTV_BASE, 0);
 	dtv_enabled = 0;
@@ -262,19 +267,24 @@
 
 	if (dtv_pipe != NULL) {
 		mdp4_dtv_stop(mfd);
+		if (hdmi_prim_display && mfd->ref_cnt == 0) {
+			/* adb stop */
+			if (dtv_pipe->pipe_type == OVERLAY_TYPE_BF)
+				mdp4_overlay_borderfill_stage_down(dtv_pipe);
 
-		/* delay to make sure the last frame finishes */
-		msleep(20);
-
-		mdp4_mixer_stage_down(dtv_pipe);
-		mdp4_overlay_pipe_free(dtv_pipe);
-		mdp4_iommu_unmap(dtv_pipe);
-		dtv_pipe = NULL;
+			/* dtv_pipe == rgb1 */
+			mdp4_overlay_unset_mixer(dtv_pipe->mixer_num);
+			dtv_pipe = NULL;
+		} else {
+			mdp4_mixer_stage_down(dtv_pipe);
+			mdp4_overlay_pipe_free(dtv_pipe);
+			mdp4_iommu_unmap(dtv_pipe);
+			dtv_pipe = NULL;
+		}
 	}
 	mdp4_overlay_panel_mode_unset(MDP4_MIXER1, MDP4_PANEL_DTV);
 
 	ret = panel_next_off(pdev);
-	mdp4_iommu_detach();
 	mdp_footswitch_ctrl(FALSE);
 
 	dev_info(&pdev->dev, "mdp4_overlay_dtv: off");
@@ -610,7 +620,8 @@
 	*/
 	temp_src_format = inpdw(rgb_base + 0x0050);
 	MDP_OUTP(rgb_base + 0x0050, temp_src_format | BIT(22));
-	mdp4_overlay_reg_flush(dtv_pipe, 0);
+	mdp4_overlay_reg_flush(dtv_pipe, 1);
+	mdp4_mixer_stage_up(dtv_pipe);
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 }
 
@@ -696,11 +707,19 @@
 	}
 	mutex_lock(&mfd->dma->ov_mutex);
 	pipe = dtv_pipe;
+
+	if (hdmi_prim_display && (pipe->pipe_used == 0 ||
+			pipe->mixer_stage != MDP4_MIXER_STAGE_BASE)) {
+		pr_err("%s: NOT baselayer\n", __func__);
+		mutex_unlock(&mfd->dma->ov_mutex);
+		return;
+	}
+
 	if (pipe->pipe_type == OVERLAY_TYPE_RGB) {
 		pipe->srcp0_addr = (uint32) mfd->ibuf.buf;
 		mdp4_overlay_rgb_setup(pipe);
 	}
-	mdp4_overlay_reg_flush(pipe, 0);
+	mdp4_overlay_reg_flush(pipe, 1);
 	mdp4_mixer_stage_up(pipe);
 	mdp4_overlay_dtv_start();
 	mdp4_overlay_dtv_ov_done_push(mfd, pipe);
diff --git a/drivers/video/msm/mdp4_overlay_lcdc.c b/drivers/video/msm/mdp4_overlay_lcdc.c
index a1fecb6..18d2107 100644
--- a/drivers/video/msm/mdp4_overlay_lcdc.c
+++ b/drivers/video/msm/mdp4_overlay_lcdc.c
@@ -46,6 +46,11 @@
 static struct mdp4_overlay_pipe *lcdc_pipe;
 static struct completion lcdc_comp;
 
+void mdp4_lcdc_base_swap(struct mdp4_overlay_pipe *pipe)
+{
+	lcdc_pipe = pipe;
+}
+
 int mdp_lcdc_on(struct platform_device *pdev)
 {
 	int lcdc_width;
@@ -95,8 +100,6 @@
 	if (mfd->key != MFD_KEY)
 		return -EINVAL;
 
-	mdp4_overlay_ctrl_db_reset();
-
 	fbi = mfd->fbi;
 	var = &fbi->var;
 
@@ -155,6 +158,8 @@
 	mdp4_overlay_dmap_cfg(mfd, 1);
 
 	mdp4_overlay_rgb_setup(pipe);
+	mdp4_overlay_reg_flush(pipe, 1);
+	mdp4_mixer_stage_up(pipe);
 
 	mdp4_overlayproc_cfg(pipe);
 
@@ -263,7 +268,6 @@
 
 	/* MDP cmd block enable */
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	mdp4_mixer_pipe_cleanup(lcdc_pipe->mixer_num);
 	MDP_OUTP(MDP_BASE + LCDC_BASE, 0);
 	lcdc_enabled = 0;
 	/* MDP cmd block disable */
@@ -280,8 +284,18 @@
 
 	/* dis-engage rgb0 from mixer0 */
 	if (lcdc_pipe) {
-		mdp4_mixer_stage_down(lcdc_pipe);
-		mdp4_iommu_unmap(lcdc_pipe);
+		if (mfd->ref_cnt == 0) {
+			/* adb stop */
+			if (lcdc_pipe->pipe_type == OVERLAY_TYPE_BF)
+				mdp4_overlay_borderfill_stage_down(lcdc_pipe);
+
+			/* lcdc_pipe == rgb1 */
+			mdp4_overlay_unset_mixer(lcdc_pipe->mixer_num);
+			lcdc_pipe = NULL;
+		} else {
+			mdp4_mixer_stage_down(lcdc_pipe);
+			mdp4_iommu_unmap(lcdc_pipe);
+		}
 	}
 
 #ifdef CONFIG_MSM_BUS_SCALING
@@ -494,7 +508,7 @@
 	}
 }
 /*
- * make sure the MIPI_DSI_WRITEBACK_SIZE defined at boardfile
+ * make sure the WRITEBACK_SIZE defined at boardfile
  * has enough space h * w * 3 * 2
  */
 static void mdp4_lcdc_do_blt(struct msm_fb_data_type *mfd, int enable)
@@ -585,6 +599,12 @@
 	mutex_lock(&mfd->dma->ov_mutex);
 
 	pipe = lcdc_pipe;
+	if (pipe->pipe_used == 0 ||
+			pipe->mixer_stage != MDP4_MIXER_STAGE_BASE) {
+		pr_err("%s: NOT baselayer\n", __func__);
+		mutex_unlock(&mfd->dma->ov_mutex);
+		return;
+	}
 
 	if (mfd->display_iova)
 		pipe->srcp0_addr = mfd->display_iova + buf_offset;
@@ -592,7 +612,7 @@
 		pipe->srcp0_addr = (uint32)(buf + buf_offset);
 
 	mdp4_overlay_rgb_setup(pipe);
-	mdp4_overlay_reg_flush(pipe, 0);
+	mdp4_overlay_reg_flush(pipe, 1);
 	mdp4_mixer_stage_up(pipe);
 	mdp4_overlay_lcdc_start();
 	mdp4_overlay_lcdc_vsync_push(mfd, pipe);
diff --git a/drivers/video/msm/mdp4_overlay_mddi.c b/drivers/video/msm/mdp4_overlay_mddi.c
index 5aa5965..82864918 100644
--- a/drivers/video/msm/mdp4_overlay_mddi.c
+++ b/drivers/video/msm/mdp4_overlay_mddi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -124,7 +124,6 @@
 			printk(KERN_INFO "%s: format2type failed\n", __func__);
 
 		mddi_pipe = pipe; /* keep it */
-		mddi_pipe->blt_end = 1;	/* mark as end */
 		mddi_ld_param = 0;
 		mddi_vdo_packet_reg = mfd->panel_info.mddi.vdopkt;
 
@@ -163,6 +162,8 @@
 			 (MDDI_VDO_PACKET_DESC << 16) | mddi_vdo_packet_reg);
 
 		MDP_OUTP(MDP_BASE + 0x00098, 0x01);
+		mdp4_init_writeback_buf(mfd, MDP4_MIXER0);
+		pipe->blt_addr = 0;
 	} else {
 		pipe = mddi_pipe;
 	}
@@ -246,59 +247,82 @@
 
 	/* MDP cmd block disable */
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-
 }
 
-int mdp4_mddi_overlay_blt_offset(int *off)
-{
-	if (mdp_hw_revision < MDP4_REVISION_V2_1) { /* need dmas dmap switch */
-		if (mddi_pipe->blt_end ||
-			(mdp4_overlay_mixer_play(mddi_pipe->mixer_num) == 0)) {
-			*off = -1;
-			return -EINVAL;
-		}
-	} else {
-		/* no dmas dmap switch */
-		if (mddi_pipe->blt_end) {
-			*off = -1;
-			return -EINVAL;
-		}
-	}
-
-	if (mddi_pipe->blt_cnt & 0x01)
-		*off = mddi_pipe->src_height * mddi_pipe->src_width * 3;
-	else
-		*off = 0;
-
-	return 0;
-}
-
-void mdp4_mddi_overlay_blt(ulong addr)
+int mdp4_mddi_overlay_blt_start(struct msm_fb_data_type *mfd)
 {
 	unsigned long flag;
 
-	spin_lock_irqsave(&mdp_spin_lock, flag);
-	if (addr) {
-		mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-		mdp_intr_mask |= INTR_DMA_P_DONE;
-		outp32(MDP_INTR_ENABLE, mdp_intr_mask);
-		mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-		mddi_pipe->blt_cnt = 0;
-		mddi_pipe->blt_end = 0;
-		mddi_pipe->blt_addr = addr;
-	} else {
-		mddi_pipe->blt_end = 1;	/* mark as end */
+	pr_debug("%s: blt_end=%d blt_addr=%x pid=%d\n",
+	__func__, mddi_pipe->blt_end, (int)mddi_pipe->blt_addr, current->pid);
+
+	mdp4_allocate_writeback_buf(mfd, MDP4_MIXER0);
+
+	if (mfd->ov0_wb_buf->phys_addr == 0) {
+		pr_info("%s: no blt_base assigned\n", __func__);
+		return -EBUSY;
 	}
-	spin_unlock_irqrestore(&mdp_spin_lock, flag);
+
+	if (mddi_pipe->blt_addr == 0) {
+		mdp4_mddi_dma_busy_wait(mfd);
+		spin_lock_irqsave(&mdp_spin_lock, flag);
+		mddi_pipe->blt_end = 0;
+		mddi_pipe->blt_cnt = 0;
+		mddi_pipe->ov_cnt = 0;
+		mddi_pipe->dmap_cnt = 0;
+		mddi_pipe->blt_addr = mfd->ov0_wb_buf->phys_addr;
+		mdp4_stat.blt_mddi++;
+		spin_unlock_irqrestore(&mdp_spin_lock, flag);
+	return 0;
+}
+
+	return -EBUSY;
+}
+
+int mdp4_mddi_overlay_blt_stop(struct msm_fb_data_type *mfd)
+{
+	unsigned long flag;
+
+	pr_debug("%s: blt_end=%d blt_addr=%x\n",
+		 __func__, mddi_pipe->blt_end, (int)mddi_pipe->blt_addr);
+
+	if ((mddi_pipe->blt_end == 0) && mddi_pipe->blt_addr) {
+		spin_lock_irqsave(&mdp_spin_lock, flag);
+		mddi_pipe->blt_end = 1;	/* mark as end */
+		spin_unlock_irqrestore(&mdp_spin_lock, flag);
+		return 0;
+	}
+
+	return -EBUSY;
+}
+
+int mdp4_mddi_overlay_blt_offset(struct msm_fb_data_type *mfd,
+					struct msmfb_overlay_blt *req)
+{
+	req->offset = 0;
+	req->width = mddi_pipe->src_width;
+	req->height = mddi_pipe->src_height;
+	req->bpp = mddi_pipe->bpp;
+
+	return sizeof(*req);
+}
+
+void mdp4_mddi_overlay_blt(struct msm_fb_data_type *mfd,
+					struct msmfb_overlay_blt *req)
+{
+	if (req->enable)
+		mdp4_mddi_overlay_blt_start(mfd);
+	else if (req->enable == 0)
+		mdp4_mddi_overlay_blt_stop(mfd);
+
 }
 
 void mdp4_blt_xy_update(struct mdp4_overlay_pipe *pipe)
 {
-	uint32 off, addr;
+	uint32 off, addr, addr2;
 	int bpp;
 	char *overlay_base;
 
-
 	if (pipe->blt_addr == 0)
 		return;
 
@@ -317,29 +341,62 @@
 	/* dmap */
 	MDP_OUTP(MDP_BASE + 0x90008, addr);
 
+	off = 0;
+	if (pipe->ov_cnt & 0x01)
+		off = pipe->src_height * pipe->src_width * bpp;
+	addr2 = pipe->blt_addr + off;
 	/* overlay 0 */
 	overlay_base = MDP_BASE + MDP4_OVERLAYPROC0_BASE;/* 0x10000 */
-	outpdw(overlay_base + 0x000c, addr);
-	outpdw(overlay_base + 0x001c, addr);
+	outpdw(overlay_base + 0x000c, addr2);
+	outpdw(overlay_base + 0x001c, addr2);
 }
 
 /*
  * mdp4_dmap_done_mddi: called from isr
  */
-void mdp4_dma_p_done_mddi(void)
+void mdp4_dma_p_done_mddi(struct mdp_dma_data *dma)
 {
-	if (mddi_pipe->blt_end) {
-		mddi_pipe->blt_addr = 0;
-		mdp_intr_mask &= ~INTR_DMA_P_DONE;
-		outp32(MDP_INTR_ENABLE, mdp_intr_mask);
-		mdp4_overlayproc_cfg(mddi_pipe);
-		mdp4_overlay_dmap_xy(mddi_pipe);
+	int diff;
+
+	mddi_pipe->dmap_cnt++;
+	diff = mddi_pipe->ov_cnt - mddi_pipe->dmap_cnt;
+	pr_debug("%s: ov_cnt=%d dmap_cnt=%d\n",
+			__func__, mddi_pipe->ov_cnt, mddi_pipe->dmap_cnt);
+
+	if (diff <= 0) {
+		spin_lock(&mdp_spin_lock);
+		dma->dmap_busy = FALSE;
+		complete(&dma->dmap_comp);
+		spin_unlock(&mdp_spin_lock);
+
+		if (mddi_pipe->blt_end) {
+			mddi_pipe->blt_end = 0;
+			mddi_pipe->blt_addr = 0;
+			pr_debug("%s: END, ov_cnt=%d dmap_cnt=%d\n", __func__,
+				mddi_pipe->ov_cnt, mddi_pipe->dmap_cnt);
+			mdp_intr_mask &= ~INTR_DMA_P_DONE;
+			outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+		}
+
+		mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_OFF, TRUE);
+		mdp_disable_irq_nosync(MDP_DMA2_TERM);  /* disable intr */
+		return;
 	}
 
-	/*
-	 * single buffer, no need to increase
-	 * mdd_pipe->dmap_cnt here
-	 */
+	spin_lock(&mdp_spin_lock);
+	dma->busy = FALSE;
+	spin_unlock(&mdp_spin_lock);
+	complete(&dma->comp);
+	if (busy_wait_cnt)
+		busy_wait_cnt--;
+
+	pr_debug("%s: kickoff dmap\n", __func__);
+
+	mdp4_blt_xy_update(mddi_pipe);
+	/* kick off dmap */
+	outpdw(MDP_BASE + 0x000c, 0x0);
+	mdp4_stat.kickoff_dmap++;
+	mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_OFF, TRUE);
 }
 
 /*
@@ -347,37 +404,60 @@
  */
 void mdp4_overlay0_done_mddi(struct mdp_dma_data *dma)
 {
-	mdp_disable_irq_nosync(MDP_OVERLAY0_TERM);
+	int diff;
 
+	if (mddi_pipe->blt_addr == 0) {
+		mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_OFF, TRUE);
+		spin_lock(&mdp_spin_lock);
+		dma->busy = FALSE;
+		spin_unlock(&mdp_spin_lock);
+		complete(&dma->comp);
+
+		if (busy_wait_cnt)
+			busy_wait_cnt--;
+		mdp_disable_irq_nosync(MDP_OVERLAY0_TERM);
+
+		return;
+	}
+
+	/* blt enabled */
+	if (mddi_pipe->blt_end == 0)
+		mddi_pipe->ov_cnt++;
+
+	pr_debug("%s: ov_cnt=%d dmap_cnt=%d\n",
+			__func__, mddi_pipe->ov_cnt, mddi_pipe->dmap_cnt);
+
+	if (mddi_pipe->blt_cnt == 0) {
+		/* first kickoff since blt enabled */
+		mdp_intr_mask |= INTR_DMA_P_DONE;
+		outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+	}
+
+	mddi_pipe->blt_cnt++;
+
+	diff = mddi_pipe->ov_cnt - mddi_pipe->dmap_cnt;
+	if (diff >= 2) {
+		mdp_disable_irq_nosync(MDP_OVERLAY0_TERM);
+		return;
+	}
+
+	spin_lock(&mdp_spin_lock);
 	dma->busy = FALSE;
+	dma->dmap_busy = TRUE;
+	spin_unlock(&mdp_spin_lock);
 	complete(&dma->comp);
-	mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK,
-			MDP_BLOCK_POWER_OFF, TRUE);
 
 	if (busy_wait_cnt)
 		busy_wait_cnt--;
 
-	pr_debug("%s: ISR-done\n", __func__);
+	pr_debug("%s: kickoff dmap\n", __func__);
 
-	if (mddi_pipe->blt_addr) {
-		if (mddi_pipe->blt_cnt == 0) {
-			mdp4_overlayproc_cfg(mddi_pipe);
-			mdp4_overlay_dmap_xy(mddi_pipe);
-			mddi_pipe->ov_cnt = 0;
-			mddi_pipe->dmap_cnt = 0;
-			/* BLT start from next frame */
-		} else {
-			mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_ON,
-						FALSE);
-			mdp4_blt_xy_update(mddi_pipe);
-			outpdw(MDP_BASE + 0x000c, 0x0); /* start DMAP */
-		}
-		mddi_pipe->blt_cnt++;
-		mddi_pipe->ov_cnt++;
-	}
-
-
-
+	mdp4_blt_xy_update(mddi_pipe);
+	mdp_enable_irq(MDP_DMA2_TERM);	/* enable intr */
+	/* kick off dmap */
+	outpdw(MDP_BASE + 0x000c, 0x0);
+	mdp4_stat.kickoff_dmap++;
+	mdp_disable_irq_nosync(MDP_OVERLAY0_TERM);
 }
 
 void mdp4_mddi_overlay_restore(void)
@@ -392,6 +472,9 @@
 	if (mddi_mfd && mddi_pipe) {
 		mdp4_mddi_dma_busy_wait(mddi_mfd);
 		mdp4_overlay_update_lcd(mddi_mfd);
+
+		if (mddi_pipe->blt_addr)
+			mdp4_mddi_blt_dmap_busy_wait(mddi_mfd);
 		mdp4_mddi_overlay_kickoff(mddi_mfd, mddi_pipe);
 		mddi_mfd->dma_update_flag = 1;
 	}
@@ -399,9 +482,27 @@
 		mdp4_mddi_overlay_dmas_restore();
 }
 
+void mdp4_mddi_blt_dmap_busy_wait(struct msm_fb_data_type *mfd)
+{
+	unsigned long flag;
+	int need_wait = 0;
+
+	spin_lock_irqsave(&mdp_spin_lock, flag);
+	if (mfd->dma->dmap_busy == TRUE) {
+		INIT_COMPLETION(mfd->dma->dmap_comp);
+		need_wait++;
+	}
+	spin_unlock_irqrestore(&mdp_spin_lock, flag);
+
+	if (need_wait) {
+		/* wait until DMA finishes the current job */
+		wait_for_completion(&mfd->dma->dmap_comp);
+	}
+}
+
 /*
  * mdp4_mddi_cmd_dma_busy_wait: check mddi link activity
- * dsi link is a shared resource and it can only be used
+ * mddi link is a shared resource and it can only be used
  * while it is in idle state.
  * ov_mutex need to be acquired before call this function.
  */
@@ -432,7 +533,24 @@
 void mdp4_mddi_kickoff_video(struct msm_fb_data_type *mfd,
 				struct mdp4_overlay_pipe *pipe)
 {
-	pr_debug("%s: pid=%d\n", __func__, current->pid);
+	/*
+	 * a video kickoff may happen before UI kickoff after
+	 * blt enabled. mdp4_overlay_update_lcd() need
+	 * to be called before kickoff.
+	 * vice versa for blt disabled.
+	 */
+	if (mddi_pipe->blt_addr && mddi_pipe->blt_cnt == 0)
+		mdp4_overlay_update_lcd(mfd); /* first time */
+	else if (mddi_pipe->blt_addr == 0  && mddi_pipe->blt_cnt) {
+		mdp4_overlay_update_lcd(mfd); /* last time */
+		mddi_pipe->blt_cnt = 0;
+	}
+
+	pr_debug("%s: blt_addr=%d blt_cnt=%d\n",
+		__func__, (int)mddi_pipe->blt_addr, mddi_pipe->blt_cnt);
+
+	if (mddi_pipe->blt_addr)
+		mdp4_mddi_blt_dmap_busy_wait(mddi_mfd);
 	mdp4_mddi_overlay_kickoff(mfd, pipe);
 }
 
@@ -447,11 +565,16 @@
 void mdp4_mddi_overlay_kickoff(struct msm_fb_data_type *mfd,
 				struct mdp4_overlay_pipe *pipe)
 {
+	unsigned long flag;
 	/* change mdp clk while mdp is idle` */
 	mdp4_set_perf_level();
 
 	mdp_enable_irq(MDP_OVERLAY0_TERM);
+	spin_lock_irqsave(&mdp_spin_lock, flag);
 	mfd->dma->busy = TRUE;
+	if (mddi_pipe->blt_addr)
+		mfd->dma->dmap_busy = TRUE;
+	spin_unlock_irqrestore(&mdp_spin_lock, flag);
 	/* start OVERLAY pipe */
 	mdp_pipe_kickoff(MDP_OVERLAY0_TERM, mfd);
 	mdp4_stat.kickoff_ov0++;
@@ -533,7 +656,10 @@
 	mdp4_set_perf_level();
 
 	mdp_enable_irq(MDP_DMA_S_TERM);
-	mfd->dma->busy = TRUE;
+
+	if (mddi_pipe->blt_addr == 0)
+		mfd->dma->busy = TRUE;
+
 	mfd->ibuf_flushed = TRUE;
 	/* start dma_s pipe */
 	mdp_pipe_kickoff(MDP_DMA_S_TERM, mfd);
@@ -561,6 +687,10 @@
 
 	if (mfd && mfd->panel_power_on) {
 		mdp4_mddi_dma_busy_wait(mfd);
+
+		if (mddi_pipe && mddi_pipe->blt_addr)
+			mdp4_mddi_blt_dmap_busy_wait(mfd);
+
 		mdp4_overlay_update_lcd(mfd);
 
 		if (mdp_hw_revision < MDP4_REVISION_V2_1) {
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index b2657cf..f192b12 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -314,6 +314,8 @@
 	clk_rate = mdp_get_core_clk();
 	mdp4_fetch_cfg(clk_rate);
 
+	mdp4_overlay_cfg_init();
+
 	/* Mark hardware as initialized. Only revisions > v2.1 have a register
 	 * for tracking core reset status. */
 	if (mdp_hw_revision > MDP4_REVISION_V2_1)
@@ -378,6 +380,7 @@
 	outpdw(MDP_INTR_CLEAR, isr);
 
 	if (isr & INTR_PRIMARY_INTF_UDERRUN) {
+		pr_debug("%s: UNDERRUN -- primary\n", __func__);
 		mdp4_stat.intr_underrun_p++;
 		/* When underun occurs mdp clear the histogram registers
 		that are set before in hw_init so restore them back so
@@ -395,8 +398,10 @@
 		}
 	}
 
-	if (isr & INTR_EXTERNAL_INTF_UDERRUN)
+	if (isr & INTR_EXTERNAL_INTF_UDERRUN) {
+		pr_debug("%s: UNDERRUN -- external\n", __func__);
 		mdp4_stat.intr_underrun_e++;
+	}
 
 	isr &= mask;
 
@@ -522,7 +527,7 @@
 		}
 #else
 		else { /* MDDI */
-			mdp4_dma_p_done_mddi();
+			mdp4_dma_p_done_mddi(dma);
 			mdp_pipe_ctrl(MDP_DMA2_BLOCK,
 				MDP_BLOCK_POWER_OFF, TRUE);
 			complete(&dma->comp);
diff --git a/drivers/video/msm/mdp_debugfs.c b/drivers/video/msm/mdp_debugfs.c
index 7defd82..4a0ea4c 100644
--- a/drivers/video/msm/mdp_debugfs.c
+++ b/drivers/video/msm/mdp_debugfs.c
@@ -437,38 +437,38 @@
 	len = snprintf(bp, dlen, "frame_push:\n");
 	bp += len;
 	dlen -= len;
-	len = snprintf(bp, dlen, "rgb1:  %08lu\t\t",
+	len = snprintf(bp, dlen, "rgb1:   %08lu\t",
 		       mdp4_stat.pipe[OVERLAY_PIPE_RGB1]);
 	bp += len;
 	dlen -= len;
-	len = snprintf(bp, dlen, "rgb2:  %08lu\n",
+	len = snprintf(bp, dlen, "rgb2:   %08lu\n",
 		       mdp4_stat.pipe[OVERLAY_PIPE_RGB2]);
 	bp += len;
 	dlen -= len;
-	len = snprintf(bp, dlen, "vg1:   %08lu\t\t",
+	len = snprintf(bp, dlen, "vg1 :   %08lu\t",
 		       mdp4_stat.pipe[OVERLAY_PIPE_VG1]);
 	bp += len;
 	dlen -= len;
-	len = snprintf(bp, dlen, "vg2:   %08lu\n",
+	len = snprintf(bp, dlen, "vg2 :   %08lu\n",
 		       mdp4_stat.pipe[OVERLAY_PIPE_VG2]);
 	bp += len;
 	dlen -= len;
-	len = snprintf(bp, dlen, "err_mixer: %08lu\t", mdp4_stat.err_mixer);
+	len = snprintf(bp, dlen, "err_mixer : %08lu\t", mdp4_stat.err_mixer);
 	bp += len;
 	dlen -= len;
-	len = snprintf(bp, dlen, "err_size : %08lu\n", mdp4_stat.err_size);
+	len = snprintf(bp, dlen, "err_size  : %08lu\n", mdp4_stat.err_size);
 	bp += len;
 	dlen -= len;
-	len = snprintf(bp, dlen, "err_scale: %08lu\t", mdp4_stat.err_scale);
+	len = snprintf(bp, dlen, "err_scale : %08lu\t", mdp4_stat.err_scale);
 	bp += len;
 	dlen -= len;
 	len = snprintf(bp, dlen, "err_format: %08lu\n", mdp4_stat.err_format);
 	bp += len;
 	dlen -= len;
-	len = snprintf(bp, dlen, "err_play:  %08lu\t", mdp4_stat.err_play);
+	len = snprintf(bp, dlen, "err_play  : %08lu\t", mdp4_stat.err_play);
 	bp += len;
 	dlen -= len;
-	len = snprintf(bp, dlen, "err_stage: %08lu\n", mdp4_stat.err_stage);
+	len = snprintf(bp, dlen, "err_stage : %08lu\n", mdp4_stat.err_stage);
 	bp += len;
 	dlen -= len;
 	len = snprintf(bp, dlen, "err_underflow: %08lu\n\n",
diff --git a/drivers/video/msm/mdp_ppp_v20.c b/drivers/video/msm/mdp_ppp_v20.c
index d271b85..418528e 100644
--- a/drivers/video/msm/mdp_ppp_v20.c
+++ b/drivers/video/msm/mdp_ppp_v20.c
@@ -2403,7 +2403,10 @@
 			   uint32 width,
 			   uint32 height, int bpp, MDPIBUF *iBuf, int layer)
 {
-	*src0 += (x + y * width) * bpp;
+	if (iBuf->mdpImg.imgType == MDP_Y_CBCR_H2V2_ADRENO && layer == 0)
+		*src0 += (x + y * ALIGN(width, 32)) * bpp;
+	else
+		*src0 += (x + y * width) * bpp;
 
 	/* if it's dest/bg buffer, we need to adjust it for rotation */
 	if (layer != 0)
@@ -2414,9 +2417,14 @@
 		 * MDP_Y_CBCR_H2V2/MDP_Y_CRCB_H2V2 cosite for now
 		 * we need to shift x direction same as y dir for offsite
 		 */
-		*src1 +=
-		    ((x / h_slice) * h_slice +
-		     ((y == 0) ? 0 : ((y + 1) / v_slice - 1) * width)) * bpp;
+		if (iBuf->mdpImg.imgType == MDP_Y_CBCR_H2V2_ADRENO
+							&& layer == 0)
+			*src1 += ((x / h_slice) * h_slice + ((y == 0) ? 0 :
+			(((y + 1) / v_slice - 1) * (ALIGN(width/2, 32) * 2))))
+									* bpp;
+		else
+			*src1 += ((x / h_slice) * h_slice +
+			((y == 0) ? 0 : ((y + 1) / v_slice - 1) * width)) * bpp;
 
 		/* if it's dest/bg buffer, we need to adjust it for rotation */
 		if (layer != 0)
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h
index 50c3696..8a33512 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h
@@ -30,6 +30,9 @@
 #define DDL_MAX_FRAME_WIDTH   1920
 #define DDL_MAX_FRAME_HEIGHT  1088
 
+#define DDL_MAX_VC1_FRAME_WIDTH		(DDL_MAX_FRAME_WIDTH)
+#define DDL_MAX_VC1_FRAME_HEIGHT	(1280)
+
 #define MAX_DPB_SIZE_L4PT0_MBS    DDL_KILO_BYTE(32)
 #define MAX_FRAME_SIZE_L4PT0_MBS  DDL_KILO_BYTE(8)
 
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
index 3487f53..58d1f23 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
@@ -312,6 +312,20 @@
 					return process_further;
 				}
 			break;
+		case VCD_CODEC_VC1:
+		case VCD_CODEC_VC1_RCV:
+			if ((seq_hdr_info.img_size_x >
+					DDL_MAX_VC1_FRAME_WIDTH) ||
+				(seq_hdr_info.img_size_y >
+					DDL_MAX_VC1_FRAME_HEIGHT)) {
+				DDL_MSG_ERROR("Unsupported VC1 clip: "
+					"Resolution X=%d and Y=%d",
+					seq_hdr_info.img_size_x,
+					seq_hdr_info.img_size_y);
+					ddl_client_fatal_cb(ddl);
+					return process_further;
+			}
+			break;
 		default:
 			break;
 		}
@@ -1703,6 +1717,13 @@
 	(void)ddl_get_encoded_frame(output_frame,
 		encoder->codec.codec, encoder->enc_frame_info.enc_frame
 								);
+	if (!IS_ERR_OR_NULL(output_frame->buff_ion_handle)) {
+		msm_ion_do_cache_op(ddl_context->video_ion_client,
+			output_frame->buff_ion_handle,
+			(unsigned long *) output_frame->virtual,
+			(unsigned long) output_frame->alloc_len,
+			ION_IOC_INV_CACHES);
+	}
 	ddl_process_encoder_metadata(ddl);
 	ddl_vidc_encode_dynamic_property(ddl, false);
 	ddl->input_frame.frm_trans_end = false;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
index 878db62..839a9c1 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
@@ -207,7 +207,7 @@
 #define VIDC_SM_MPEG4_ASPECT_RATIO_INFO_SHFT         0x0
 #define VIDC_SM_EXTENDED_PAR_ADDR                    0x00cc
 #define VIDC_SM_EXTENDED_PAR_WIDTH_BMSK              0xffff0000
-#define VIDC_SM_EXTENDED_PAR_WIDTH_SHFT              0xf
+#define VIDC_SM_EXTENDED_PAR_WIDTH_SHFT              16
 #define VIDC_SM_EXTENDED_PAR_HEIGHT_BMSK             0x0000ffff
 #define VIDC_SM_EXTENDED_PAR_HEIGHT_SHFT             0x0
 
diff --git a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
index d90b8ca..5b22b21 100644
--- a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
+++ b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
@@ -28,8 +28,8 @@
 #define PIL_FW_BASE_ADDR 0x9fe00000
 #define PIL_FW_SIZE 0x200000
 
-static unsigned int vidc_clk_table[3] = {
-	48000000, 133330000, 200000000
+static unsigned int vidc_clk_table[4] = {
+	48000000, 133330000, 200000000, 228570000,
 };
 static unsigned int restrk_mmu_subsystem[] =	{
 		MSM_SUBSYSTEM_VIDEO, MSM_SUBSYSTEM_VIDEO_FWARE};
@@ -544,17 +544,27 @@
 			enc_perf_level += cctxt_itr->reqd_perf_lvl;
 		cctxt_itr = cctxt_itr->next;
 	}
+
 	if (!enc_perf_level)
 		client_type = 1;
 	if (perf_level <= RESTRK_1080P_VGA_PERF_LEVEL)
 		bus_clk_index = 0;
 	else if (perf_level <= RESTRK_1080P_720P_PERF_LEVEL)
 		bus_clk_index = 1;
-	else
+	else if (perf_level <= RESTRK_1080P_MAX_PERF_LEVEL)
 		bus_clk_index = 2;
+	else
+		bus_clk_index = 3;
 
 	if (dev_ctxt->reqd_perf_lvl + dev_ctxt->curr_perf_lvl == 0)
 		bus_clk_index = 2;
+	else if (resource_context.vidc_platform_data->disable_turbo
+						&& bus_clk_index == 3) {
+		VCDRES_MSG_ERROR("Warning: Turbo mode not supported "
+				" falling back to 1080p bus\n");
+		bus_clk_index = 2;
+	}
+
 	bus_clk_index = (bus_clk_index << 1) + (client_type + 1);
 	VCDRES_MSG_LOW("%s(), bus_clk_index = %d", __func__, bus_clk_index);
 	VCDRES_MSG_LOW("%s(),context.pcl = %x", __func__, resource_context.pcl);
@@ -575,6 +585,13 @@
 		return false;
 	}
 	VCDRES_MSG_LOW("%s(), req_perf_lvl = %d", __func__, req_perf_lvl);
+
+	if (resource_context.vidc_platform_data->disable_turbo
+			&& req_perf_lvl > RESTRK_1080P_MAX_PERF_LEVEL) {
+		VCDRES_MSG_ERROR("%s(): Turbo not supported! dev_ctxt(%p)\n",
+			__func__, dev_ctxt);
+	}
+
 #ifdef CONFIG_MSM_BUS_SCALING
 	if (!res_trk_update_bus_perf_level(dev_ctxt, req_perf_lvl) < 0) {
 		VCDRES_MSG_ERROR("%s(): update buf perf level failed\n",
@@ -592,10 +609,22 @@
 	} else if (req_perf_lvl <= RESTRK_1080P_720P_PERF_LEVEL) {
 		vidc_freq = vidc_clk_table[1];
 		*pn_set_perf_lvl = RESTRK_1080P_720P_PERF_LEVEL;
+	} else if (req_perf_lvl <= RESTRK_1080P_MAX_PERF_LEVEL) {
+		vidc_freq = vidc_clk_table[2];
+		*pn_set_perf_lvl = RESTRK_1080P_MAX_PERF_LEVEL;
 	} else {
+		vidc_freq = vidc_clk_table[3];
+		*pn_set_perf_lvl = RESTRK_1080P_TURBO_PERF_LEVEL;
+	}
+
+	if (resource_context.vidc_platform_data->disable_turbo &&
+		*pn_set_perf_lvl == RESTRK_1080P_TURBO_PERF_LEVEL) {
+		VCDRES_MSG_ERROR("Warning: Turbo mode not supported "
+				" falling back to 1080p clocks\n");
 		vidc_freq = vidc_clk_table[2];
 		*pn_set_perf_lvl = RESTRK_1080P_MAX_PERF_LEVEL;
 	}
+
 	resource_context.perf_level = *pn_set_perf_lvl;
 	VCDRES_MSG_MED("VIDC: vidc_freq = %u, req_perf_lvl = %u\n",
 		vidc_freq, req_perf_lvl);
@@ -969,6 +998,9 @@
 	case VCD_PERF_LEVEL2:
 		res_trk_perf_level = RESTRK_1080P_MAX_PERF_LEVEL;
 		break;
+	case VCD_PERF_LEVEL_TURBO:
+		res_trk_perf_level = RESTRK_1080P_TURBO_PERF_LEVEL;
+		break;
 	default:
 		VCD_MSG_ERROR("Invalid perf level: %d\n", perf_level);
 		res_trk_perf_level = -EINVAL;
diff --git a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.h b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.h
index bf8607d..d5e656b 100644
--- a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.h
+++ b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.h
@@ -28,6 +28,7 @@
 
 #define RESTRK_1080P_MIN_PERF_LEVEL RESTRK_1080P_VGA_PERF_LEVEL
 #define RESTRK_1080P_MAX_PERF_LEVEL RESTRK_1080P_1080P_PERF_LEVEL
+#define RESTRK_1080P_TURBO_PERF_LEVEL (RESTRK_1080P_MAX_PERF_LEVEL + 1)
 
 struct res_trk_context {
 	struct device *device;
diff --git a/drivers/video/msm/vidc/common/enc/venc.c b/drivers/video/msm/vidc/common/enc/venc.c
index 1b77b67..67917b9 100644
--- a/drivers/video/msm/vidc/common/enc/venc.c
+++ b/drivers/video/msm/vidc/common/enc/venc.c
@@ -252,6 +252,8 @@
 		/* Timestamp pass-through from input frame */
 		venc_msg->venc_msg_info.buf.timestamp =
 			vcd_frame_data->time_stamp;
+		venc_msg->venc_msg_info.buf.sz =
+			vcd_frame_data->alloc_len;
 
 		/* Decoded picture width and height */
 		venc_msg->venc_msg_info.msgdata_size =
@@ -269,7 +271,7 @@
 			msm_ion_do_cache_op(client_ctx->user_ion_client,
 				buff_handle,
 				(unsigned long *) kernel_vaddr,
-				(unsigned long)venc_msg->venc_msg_info.buf.len,
+				(unsigned long)venc_msg->venc_msg_info.buf.sz,
 				ION_IOC_CLEAN_INV_CACHES);
 		}
 	}
diff --git a/drivers/video/msm/vidc/common/enc/venc_internal.c b/drivers/video/msm/vidc/common/enc/venc_internal.c
index bbbe0cf..43e8d5e 100644
--- a/drivers/video/msm/vidc/common/enc/venc_internal.c
+++ b/drivers/video/msm/vidc/common/enc/venc_internal.c
@@ -1723,6 +1723,7 @@
 	struct file *file;
 	s32 buffer_index = -1;
 	u32 vcd_status = VCD_ERR_FAIL;
+	struct ion_handle *buff_handle = NULL;
 
 	struct vcd_frame_data vcd_frame;
 
@@ -1738,9 +1739,13 @@
 
 		memset((void *)&vcd_frame, 0,
 					 sizeof(struct vcd_frame_data));
+		vidc_get_fd_info(client_ctx, BUFFER_TYPE_OUTPUT,
+				pmem_fd, kernel_vaddr, buffer_index,
+				&buff_handle);
 		vcd_frame.virtual = (u8 *) kernel_vaddr;
 		vcd_frame.frm_clnt_data = (u32) output_frame_info->clientdata;
 		vcd_frame.alloc_len = output_frame_info->sz;
+		vcd_frame.buff_ion_handle = buff_handle;
 
 		vcd_status = vcd_fill_output_buffer(client_ctx->vcd_handle,
 								&vcd_frame);