Merge "defconfig: 8610: disable ethernet"
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
index 0588c5e..b55bd53 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -55,6 +55,10 @@
 - label:		        	A string used as a descriptive name of the panel
 - qcom,enable-gpio:			Specifies the panel lcd/display enable gpio.
 - qcom,rst-gpio:			Specifies the panel reset gpio.
+- qcom,te-gpio:				Specifies the gpio used for TE.
+- qcom,dsi-lpg-channel :		LPG channel for backlight.
+- qcom,dsi-pwm-period :			PWM period in microseconds.
+- qcom,dsi-pwm-gpio :			PWM gpio.
 - qcom,mdss-pan-broadcast-mode:		Boolean used to enable broadcast mode.
 - qcom,cont-splash-enabled:		Boolean used to enable continuous splash mode.
 - qcom,mdss-pan-porch-values:		An array of size 6 that specifies the panel blanking values.
@@ -71,6 +75,15 @@
 - qcom,mdss-pan-dsi-mode:		Specifies the panel operating mode.
 					0 = enable video mode(default mode).
 					1 = enable command mode.
+- qcom,mdss-vsync-enable:		Specifies Tear Check configuration.
+					0 = TE disable.
+					1 = TE enable.
+- qcom,mdss-hw-vsync-mode:		Specifies TE type.
+					0 = software vsync.
+					1 = hardware vsync (TE gpio pin).
+- qcom,mdss-pan-te-sel:			Specifies TE operating mode.
+					0 = TE through embedded dcs command
+					1 = TE through TE gpio pin.
 - qcom,mdss-pan-dsi-h-pulse-mode:	Specifies the pulse mode option for the panel.
 					0 = Don't send hsa/he following vs/ve packet(default)
 					1 = Send hsa/he following vs/ve packet
diff --git a/Documentation/devicetree/bindings/fb/mdss-mdp.txt b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
index 497471a..0422b57 100644
--- a/Documentation/devicetree/bindings/fb/mdss-mdp.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
@@ -75,6 +75,12 @@
 				The number of dspp blocks should match the
 				number of mixers driving data to interface
 				defined in property: qcom,mdss-mixer-intf-off
+- qcom,mdss-pingpong-off:	Array of offset addresses for the available
+				pingpong blocks. These offsets are calculated
+				from regsiter "mdp_phys" defined in reg property.
+				The number of pingpong blocks should match the
+				number of mixers driving data to interface
+				defined in property: qcom,mdss-mixer-intf-off
 - qcom,mdss-mixer-wb-off: 	Array of offset addresses for the available
 				mixer blocks that can be drive data to writeback
 				block.  These offsets will be calculated from
@@ -142,6 +148,7 @@
 					    0x00003A00>;
 		qcom,mdss-mixer-wb-off = <0x00003E00 0x00004200>;
 		qcom,mdss-dspp-off = <0x00004600 0x00004A00 0x00004E00>;
+		qcom,mdss-pingpong-off = <0x00012D00 0x00012E00 0x00012F00>;
 		qcom,mdss-wb-off = <0x00011100 0x00013100 0x00015100
 				    0x00017100 0x00019100>;
 		qcom,mdss-intf-off = <0x00021100 0x00021300
diff --git a/arch/arm/boot/dts/msm8226-mdss.dtsi b/arch/arm/boot/dts/msm8226-mdss.dtsi
index 9c76512..7ab76f1 100644
--- a/arch/arm/boot/dts/msm8226-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8226-mdss.dtsi
@@ -32,6 +32,7 @@
 		qcom,mdss-mixer-intf-off = <0x00003200>;
 		qcom,mdss-mixer-wb-off = <0x00003E00>;
 		qcom,mdss-dspp-off = <0x00004600>;
+		qcom,mdss-pingpong-off = <0x00021B00>;
 		qcom,mdss-wb-off = <0x00011100 0x00013100>;
 		qcom,mdss-intf-off = <0x00000000 0x00021300>;
 		qcom,mdss-rot-block-size = <64>;
diff --git a/arch/arm/boot/dts/msm8226-regulator.dtsi b/arch/arm/boot/dts/msm8226-regulator.dtsi
index 448a5be..9c21707 100644
--- a/arch/arm/boot/dts/msm8226-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8226-regulator.dtsi
@@ -24,6 +24,29 @@
 	};
 };
 
+/* CPR controlled regulator */
+
+/ {
+	apc_vreg_corner: regulator@f9018000 {
+		status = "okay";
+		compatible = "qcom,cpr-regulator";
+		reg = <0xf9018000 0x1000>,
+			<0xfc4b80b0 8>;
+		reg-names = "rbcpr", "efuse_phys";
+		regulator-name = "apc_corner";
+		regulator-min-microvolt = <1>;
+		regulator-max-microvolt = <4>;
+		qcom,num-efuse-bits = <5>;
+		qcom,efuse-bit-pos = <6 7 8 9 10>;
+		qcom,pvs-bin-process = <0 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2
+					2 2 2 2 3 3 3 3 3 3 3 3 0 0 0 0>;
+		qcom,pvs-corner-ceiling-slow = <1050000 1150000 1275000 1350000>;
+		qcom,pvs-corner-ceiling-nom  =  <975000 1075000 1200000 1200000>;
+		qcom,pvs-corner-ceiling-fast =  <900000 1000000 1140000 1140000>;
+		vdd-apc-supply = <&pm8226_s2>;
+	};
+};
+
 /* RPM controlled regulators: */
 
 &rpm_bus {
diff --git a/arch/arm/boot/dts/msm8974-v1.dtsi b/arch/arm/boot/dts/msm8974-v1.dtsi
index bccf0fe..ae8cf83 100644
--- a/arch/arm/boot/dts/msm8974-v1.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1.dtsi
@@ -56,6 +56,10 @@
 	qcom,write-64bit;
 };
 
+&mdss_mdp {
+	qcom,mdss-pingpong-off = <0x00021B00 0x00021C00 0x00021D00>;
+};
+
 &msm_vidc {
 	qcom,vidc-cp-map = <0x1000000 0x3f000000>;
 	qcom,vidc-ns-map = <0x40000000 0x40000000>;
diff --git a/arch/arm/boot/dts/msm8974-v2.dtsi b/arch/arm/boot/dts/msm8974-v2.dtsi
index 16cdeb1..61f2c4f 100644
--- a/arch/arm/boot/dts/msm8974-v2.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2.dtsi
@@ -64,6 +64,7 @@
 			    0x00011900 0x00011D00 0x00012100>;
 	qcom,mdss-intf-off = <0x00012500 0x00012700
 			      0x00012900 0x00012b00>;
+	qcom,mdss-pingpong-off = <0x00012D00 0x00012E00 0x00012F00>;
 };
 
 &msm_vidc {
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 1f47a1a..85738d0 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -57,6 +57,7 @@
 CONFIG_MSM_TZ_LOG=y
 CONFIG_MSM_DIRECT_SCLK_ACCESS=y
 CONFIG_MSM_WATCHDOG_V2=y
+CONFIG_MSM_MEMORY_DUMP=y
 CONFIG_MSM_DLOAD_MODE=y
 CONFIG_MSM_ADSP_LOADER=m
 CONFIG_MSM_OCMEM=y
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index a1ed251..5ab4a53 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -475,6 +475,9 @@
 	.low_voltage_calc_ms		= 1000,
 	.alarm_low_mv			= 3400,
 	.alarm_high_mv			= 4000,
+	.high_ocv_correction_limit_uv	= 50,
+	.low_ocv_correction_limit_uv	= 100,
+	.hold_soc_est			= 3,
 };
 
 static struct pm8921_platform_data
diff --git a/arch/arm/mach-msm/board-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c
index 4f398f4..ef65613 100644
--- a/arch/arm/mach-msm/board-8930-pmic.c
+++ b/arch/arm/mach-msm/board-8930-pmic.c
@@ -478,6 +478,9 @@
 	.low_voltage_calc_ms		= 1000,
 	.alarm_low_mv			= 3400,
 	.alarm_high_mv			= 4000,
+	.high_ocv_correction_limit_uv	= 50,
+	.low_ocv_correction_limit_uv	= 100,
+	.hold_soc_est			= 3,
 };
 
 static struct pm8038_platform_data pm8038_platform_data __devinitdata = {
diff --git a/arch/arm/mach-msm/board-8960-pmic.c b/arch/arm/mach-msm/board-8960-pmic.c
index 8c16984..c87d966 100644
--- a/arch/arm/mach-msm/board-8960-pmic.c
+++ b/arch/arm/mach-msm/board-8960-pmic.c
@@ -435,6 +435,9 @@
 	.low_voltage_calc_ms		= 1000,
 	.alarm_low_mv			= 3400,
 	.alarm_high_mv			= 4000,
+	.high_ocv_correction_limit_uv	= 50,
+	.low_ocv_correction_limit_uv	= 100,
+	.hold_soc_est			= 3,
 };
 
 #define	PM8921_LC_LED_MAX_CURRENT	4	/* I = 4mA */
diff --git a/arch/arm/mach-msm/smd_tty.c b/arch/arm/mach-msm/smd_tty.c
index 21e1bf4..8a2c23f 100644
--- a/arch/arm/mach-msm/smd_tty.c
+++ b/arch/arm/mach-msm/smd_tty.c
@@ -58,13 +58,10 @@
 static void *smd_tty_log_ctx;
 static DEFINE_MUTEX(smd_tty_lock);
 
-static uint smd_tty_modem_wait;
-module_param_named(modem_wait, smd_tty_modem_wait,
-			uint, S_IRUGO | S_IWUSR | S_IWGRP);
-
 struct smd_tty_info {
 	smd_channel_t *ch;
 	struct tty_port port;
+	struct device *device_ptr;
 	struct wake_lock wake_lock;
 	int open_count;
 	struct tasklet_struct tty_tsklt;
@@ -75,6 +72,7 @@
 	int in_reset;
 	int in_reset_updated;
 	int is_open;
+	unsigned int open_wait;
 	wait_queue_head_t ch_opened_wait_queue;
 	spinlock_t reset_lock;
 	spinlock_t ra_lock;		/* Read Available Lock*/
@@ -137,6 +135,57 @@
 	spin_unlock_irqrestore(&info->reset_lock, flags);
 }
 
+static ssize_t open_timeout_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t n)
+{
+	unsigned int num_dev;
+	unsigned long wait;
+	if (dev == NULL) {
+		SMD_TTY_INFO("%s: Invalid Device passed", __func__);
+		return -EINVAL;
+	}
+	for (num_dev = 0; num_dev < MAX_SMD_TTYS; num_dev++) {
+		if (dev == smd_tty[num_dev].device_ptr)
+			break;
+	}
+	if (num_dev >= MAX_SMD_TTYS) {
+		SMD_TTY_ERR("[%s]: Device Not found", __func__);
+		return -EINVAL;
+	}
+	if (!kstrtoul(buf, 10, &wait)) {
+		smd_tty[num_dev].open_wait = wait;
+		return n;
+	} else {
+		SMD_TTY_INFO("[%s]: Unable to convert %s to an int",
+			__func__, buf);
+		return -EINVAL;
+	}
+}
+
+static ssize_t open_timeout_show(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	unsigned int num_dev;
+
+	if (dev == NULL) {
+		SMD_TTY_INFO("%s: Invalid Device passed", __func__);
+		return -EINVAL;
+	}
+	for (num_dev = 0; num_dev < MAX_SMD_TTYS; num_dev++) {
+		if (dev == smd_tty[num_dev].device_ptr)
+			break;
+	}
+	if (num_dev >= MAX_SMD_TTYS)
+		SMD_TTY_ERR("[%s]: Device Not Found", __func__);
+
+	return snprintf(buf, PAGE_SIZE, "%d\n",
+			smd_tty[num_dev].open_wait);
+}
+
+static DEVICE_ATTR
+	(open_timeout, 0664, open_timeout_show, open_timeout_store);
+
 static void smd_tty_read(unsigned long param)
 {
 	unsigned char *ptr;
@@ -289,6 +338,16 @@
 		if (peripheral) {
 			info->pil = subsystem_get(peripheral);
 			if (IS_ERR(info->pil)) {
+				SMD_TTY_INFO(
+					"%s failed on smd_tty device :%s subsystem_get failed for %s",
+					__func__, smd_tty[n].smd->port_name,
+					peripheral);
+				/*
+				 * Sleep, inorder to reduce the frequency of
+				 * retry by user-space modules and to avoid
+				 * possible watchdog bite.
+				 */
+				msleep((smd_tty[n].open_wait * 1000));
 				res = PTR_ERR(info->pil);
 				goto out;
 			}
@@ -311,10 +370,10 @@
 			 * Wait for a channel to be allocated so we know
 			 * the modem is ready enough.
 			 */
-			if (smd_tty_modem_wait) {
+			if (smd_tty[n].open_wait) {
 				res = wait_for_completion_interruptible_timeout(
 					&info->ch_allocated,
-					msecs_to_jiffies(smd_tty_modem_wait *
+					msecs_to_jiffies(smd_tty[n].open_wait *
 									1000));
 
 				if (res == 0) {
@@ -664,7 +723,14 @@
 		tty_port_init(port);
 		port->ops = &smd_tty_port_ops;
 		/* TODO: For kernel >= 3.7 use tty_port_register_device */
-		tty_register_device(smd_tty_driver, idx, 0);
+		smd_tty[idx].device_ptr =
+			tty_register_device(smd_tty_driver, idx, 0);
+		if (device_create_file(smd_tty[idx].device_ptr,
+					&dev_attr_open_timeout))
+			SMD_TTY_ERR(
+				"%s: Unable to create device attributes for %s",
+				__func__, smd_configs[n].port_name);
+
 		init_completion(&smd_tty[idx].ch_allocated);
 
 		/* register platform device */
diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c
index 45c9023..ed91480 100644
--- a/drivers/base/dma-contiguous.c
+++ b/drivers/base/dma-contiguous.c
@@ -227,7 +227,7 @@
 
 	pr_info("Found %s, memory base %lx, size %ld MiB\n", uname,
 		(unsigned long)base, (unsigned long)size / SZ_1M);
-	dma_contiguous_reserve_area(size, &base, MEMBLOCK_ALLOC_ANYWHERE, name);
+	dma_contiguous_reserve_area(size, &base, 0, name);
 
 	return 0;
 }
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index 9128177..85e2ec9 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -39,7 +39,6 @@
 
 #include <mach/iommu_domains.h>
 #include "ion_priv.h"
-#define DEBUG
 
 /**
  * struct ion_device - the metadata of the ion device node
@@ -107,6 +106,12 @@
 	unsigned int iommu_map_cnt;
 };
 
+bool ion_buffer_fault_user_mappings(struct ion_buffer *buffer)
+{
+        return ((buffer->flags & ION_FLAG_CACHED) &&
+                !(buffer->flags & ION_FLAG_CACHED_NEEDS_SYNC));
+}
+
 static void ion_iommu_release(struct kref *kref);
 
 /* this function should only be called while dev->lock is held */
@@ -190,6 +195,8 @@
 	return NULL;
 }
 
+static int ion_buffer_alloc_dirty(struct ion_buffer *buffer);
+
 /* this function should only be called while dev->lock is held */
 static struct ion_buffer *ion_buffer_create(struct ion_heap *heap,
 				     struct ion_device *dev,
@@ -199,13 +206,15 @@
 {
 	struct ion_buffer *buffer;
 	struct sg_table *table;
-	int ret;
+	struct scatterlist *sg;
+	int i, ret;
 
 	buffer = kzalloc(sizeof(struct ion_buffer), GFP_KERNEL);
 	if (!buffer)
 		return ERR_PTR(-ENOMEM);
 
 	buffer->heap = heap;
+	buffer->flags = flags;
 	kref_init(&buffer->ref);
 
 	ret = heap->ops->allocate(heap, buffer, len, align, flags);
@@ -216,19 +225,52 @@
 
 	buffer->dev = dev;
 	buffer->size = len;
-	buffer->flags = flags;
 
-	table = buffer->heap->ops->map_dma(buffer->heap, buffer);
+	table = heap->ops->map_dma(heap, buffer);
 	if (IS_ERR_OR_NULL(table)) {
 		heap->ops->free(buffer);
 		kfree(buffer);
 		return ERR_PTR(PTR_ERR(table));
 	}
 	buffer->sg_table = table;
+	if (ion_buffer_fault_user_mappings(buffer)) {
+		for_each_sg(buffer->sg_table->sgl, sg, buffer->sg_table->nents,
+			    i) {
+			if (sg_dma_len(sg) == PAGE_SIZE)
+				continue;
+			pr_err("%s: cached mappings that will be faulted in "
+			       "must have pagewise sg_lists\n", __func__);
+			ret = -EINVAL;
+			goto err;
+		}
 
+		ret = ion_buffer_alloc_dirty(buffer);
+		if (ret)
+			goto err;
+	}
+
+	buffer->dev = dev;
+	buffer->size = len;
+	INIT_LIST_HEAD(&buffer->vmas);
 	mutex_init(&buffer->lock);
+	/* this will set up dma addresses for the sglist -- it is not
+	   technically correct as per the dma api -- a specific
+	   device isn't really taking ownership here.  However, in practice on
+	   our systems the only dma_address space is physical addresses.
+	   Additionally, we can't afford the overhead of invalidating every
+	   allocation via dma_map_sg. The implicit contract here is that
+	   memory comming from the heaps is ready for dma, ie if it has a
+	   cached mapping that mapping has been invalidated */
+	for_each_sg(buffer->sg_table->sgl, sg, buffer->sg_table->nents, i)
+		sg_dma_address(sg) = sg_phys(sg);
 	ion_buffer_add(dev, buffer);
 	return buffer;
+
+err:
+	heap->ops->unmap_dma(heap, buffer);
+	heap->ops->free(buffer);
+	kfree(buffer);
+	return ERR_PTR(ret);
 }
 
 /**
@@ -276,7 +318,6 @@
 
 	if (WARN_ON(buffer->kmap_cnt > 0))
 		buffer->heap->ops->unmap_kernel(buffer->heap, buffer);
-
 	buffer->heap->ops->unmap_dma(buffer->heap, buffer);
 
 	ion_delayed_unsecure(buffer);
@@ -285,6 +326,8 @@
 	mutex_lock(&dev->lock);
 	rb_erase(&buffer->node, &dev->buffers);
 	mutex_unlock(&dev->lock);
+	if (buffer->flags & ION_FLAG_CACHED)
+		kfree(buffer->dirty);
 	kfree(buffer);
 }
 
@@ -419,6 +462,16 @@
 	dbg_str[0] = '\0';
 
 	/*
+	 * For now, we don't want to fault in pages individually since
+	 * clients are already doing manual cache maintenance. In
+	 * other words, the implicit caching infrastructure is in
+	 * place (in code) but should not be used.
+	 */
+	flags |= ION_FLAG_CACHED_NEEDS_SYNC;
+
+	pr_debug("%s: len %d align %d heap_mask %u flags %x\n", __func__, len,
+		 align, heap_mask, flags);
+	/*
 	 * traverse the list of heaps available in this system in priority
 	 * order.  If the heap type is supported by the client, and matches the
 	 * request of the caller allocate from it.  Repeat until allocate has
@@ -1205,12 +1258,46 @@
 }
 EXPORT_SYMBOL(ion_sg_table);
 
+struct sg_table *ion_create_chunked_sg_table(phys_addr_t buffer_base,
+					size_t chunk_size, size_t total_size)
+{
+	struct sg_table *table;
+	int i, n_chunks, ret;
+	struct scatterlist *sg;
+
+	table = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
+	if (!table)
+		return ERR_PTR(-ENOMEM);
+
+	n_chunks = DIV_ROUND_UP(total_size, chunk_size);
+	pr_debug("creating sg_table with %d chunks\n", n_chunks);
+
+	ret = sg_alloc_table(table, n_chunks, GFP_KERNEL);
+	if (ret)
+		goto err0;
+
+	for_each_sg(table->sgl, sg, table->nents, i) {
+		dma_addr_t addr = buffer_base + i * chunk_size;
+		sg_dma_address(sg) = addr;
+	}
+
+	return table;
+err0:
+	kfree(table);
+	return ERR_PTR(ret);
+}
+
+static void ion_buffer_sync_for_device(struct ion_buffer *buffer,
+				       struct device *dev,
+				       enum dma_data_direction direction);
+
 static struct sg_table *ion_map_dma_buf(struct dma_buf_attachment *attachment,
 					enum dma_data_direction direction)
 {
 	struct dma_buf *dmabuf = attachment->dmabuf;
 	struct ion_buffer *buffer = dmabuf->priv;
 
+	ion_buffer_sync_for_device(buffer, attachment->dev, direction);
 	return buffer->sg_table;
 }
 
@@ -1220,24 +1307,119 @@
 {
 }
 
-static void ion_vma_close(struct vm_area_struct *vma)
+static int ion_buffer_alloc_dirty(struct ion_buffer *buffer)
+{
+	unsigned long pages = buffer->sg_table->nents;
+	unsigned long length = (pages + BITS_PER_LONG - 1)/BITS_PER_LONG;
+
+	buffer->dirty = kzalloc(length * sizeof(unsigned long), GFP_KERNEL);
+	if (!buffer->dirty)
+		return -ENOMEM;
+	return 0;
+}
+
+struct ion_vma_list {
+	struct list_head list;
+	struct vm_area_struct *vma;
+};
+
+static void ion_buffer_sync_for_device(struct ion_buffer *buffer,
+				       struct device *dev,
+				       enum dma_data_direction dir)
+{
+	struct scatterlist *sg;
+	int i;
+	struct ion_vma_list *vma_list;
+
+	pr_debug("%s: syncing for device %s\n", __func__,
+		 dev ? dev_name(dev) : "null");
+
+	if (!ion_buffer_fault_user_mappings(buffer))
+		return;
+
+	mutex_lock(&buffer->lock);
+	for_each_sg(buffer->sg_table->sgl, sg, buffer->sg_table->nents, i) {
+		if (!test_bit(i, buffer->dirty))
+			continue;
+		dma_sync_sg_for_device(dev, sg, 1, dir);
+		clear_bit(i, buffer->dirty);
+	}
+	list_for_each_entry(vma_list, &buffer->vmas, list) {
+		struct vm_area_struct *vma = vma_list->vma;
+
+		zap_page_range(vma, vma->vm_start, vma->vm_end - vma->vm_start,
+			       NULL);
+	}
+	mutex_unlock(&buffer->lock);
+}
+
+int ion_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
 	struct ion_buffer *buffer = vma->vm_private_data;
+	struct scatterlist *sg;
+	int i;
 
-	pr_debug("%s: %d\n", __func__, __LINE__);
+	mutex_lock(&buffer->lock);
+	set_bit(vmf->pgoff, buffer->dirty);
+
+	for_each_sg(buffer->sg_table->sgl, sg, buffer->sg_table->nents, i) {
+		if (i != vmf->pgoff)
+			continue;
+		dma_sync_sg_for_cpu(NULL, sg, 1, DMA_BIDIRECTIONAL);
+		vm_insert_page(vma, (unsigned long)vmf->virtual_address,
+			       sg_page(sg));
+		break;
+	}
+	mutex_unlock(&buffer->lock);
+	return VM_FAULT_NOPAGE;
+}
+
+static void ion_vm_open(struct vm_area_struct *vma)
+{
+	struct ion_buffer *buffer = vma->vm_private_data;
+	struct ion_vma_list *vma_list;
+
+	vma_list = kmalloc(sizeof(struct ion_vma_list), GFP_KERNEL);
+	if (!vma_list)
+		return;
+	vma_list->vma = vma;
+	mutex_lock(&buffer->lock);
+	list_add(&vma_list->list, &buffer->vmas);
+	mutex_unlock(&buffer->lock);
+	pr_debug("%s: adding %p\n", __func__, vma);
+}
+
+static void ion_vm_close(struct vm_area_struct *vma)
+{
+	struct ion_buffer *buffer = vma->vm_private_data;
+	struct ion_vma_list *vma_list, *tmp;
+
+	pr_debug("%s\n", __func__);
+	mutex_lock(&buffer->lock);
+	list_for_each_entry_safe(vma_list, tmp, &buffer->vmas, list) {
+		if (vma_list->vma != vma)
+			continue;
+		list_del(&vma_list->list);
+		kfree(vma_list);
+		pr_debug("%s: deleting %p\n", __func__, vma);
+		break;
+	}
+	mutex_unlock(&buffer->lock);
 
 	if (buffer->heap->ops->unmap_user)
 		buffer->heap->ops->unmap_user(buffer->heap, buffer);
 }
 
-static struct vm_operations_struct ion_vm_ops = {
-	.close = ion_vma_close,
+struct vm_operations_struct ion_vma_ops = {
+	.open = ion_vm_open,
+	.close = ion_vm_close,
+	.fault = ion_vm_fault,
 };
 
 static int ion_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
 {
 	struct ion_buffer *buffer = dmabuf->priv;
-	int ret;
+	int ret = 0;
 
 	if (!buffer->heap->ops->map_user) {
 		pr_err("%s: this heap does not define a method for mapping "
@@ -1245,22 +1427,26 @@
 		return -EINVAL;
 	}
 
+	if (ion_buffer_fault_user_mappings(buffer)) {
+		vma->vm_private_data = buffer;
+		vma->vm_ops = &ion_vma_ops;
+		vma->vm_flags |= VM_MIXEDMAP;
+		ion_vm_open(vma);
+		return 0;
+	}
+
+	if (!(buffer->flags & ION_FLAG_CACHED))
+		vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+
 	mutex_lock(&buffer->lock);
 	/* now map it to userspace */
 	ret = buffer->heap->ops->map_user(buffer->heap, buffer, vma);
 	mutex_unlock(&buffer->lock);
 
-	if (ret) {
+	if (ret)
 		pr_err("%s: failure mapping buffer to userspace\n",
 		       __func__);
-	} else {
-		vma->vm_ops = &ion_vm_ops;
-		/*
-		 * move the buffer into the vm_private_data so we can access it
-		 * from vma_open/close
-		 */
-		vma->vm_private_data = buffer;
-	}
+
 	return ret;
 }
 
@@ -1396,6 +1582,30 @@
 }
 EXPORT_SYMBOL(ion_import_dma_buf);
 
+static int ion_sync_for_device(struct ion_client *client, int fd)
+{
+	struct dma_buf *dmabuf;
+	struct ion_buffer *buffer;
+
+	dmabuf = dma_buf_get(fd);
+	if (IS_ERR_OR_NULL(dmabuf))
+		return PTR_ERR(dmabuf);
+
+	/* if this memory came from ion */
+	if (dmabuf->ops != &dma_buf_ops) {
+		pr_err("%s: can not sync dmabuf from another exporter\n",
+		       __func__);
+		dma_buf_put(dmabuf);
+		return -EINVAL;
+	}
+	buffer = dmabuf->priv;
+
+	dma_sync_sg_for_device(NULL, buffer->sg_table->sgl,
+			       buffer->sg_table->nents, DMA_BIDIRECTIONAL);
+	dma_buf_put(dmabuf);
+	return 0;
+}
+
 static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
 	struct ion_client *client = filp->private_data;
@@ -1468,6 +1678,15 @@
 			return ret;
 		break;
 	}
+	case ION_IOC_SYNC:
+	{
+		struct ion_fd_data data;
+		if (copy_from_user(&data, (void __user *)arg,
+				   sizeof(struct ion_fd_data)))
+			return -EFAULT;
+		ion_sync_for_device(client, data.fd);
+		break;
+	}
 	case ION_IOC_CUSTOM:
 	{
 		struct ion_device *dev = client->dev;
diff --git a/drivers/gpu/ion/ion_carveout_heap.c b/drivers/gpu/ion/ion_carveout_heap.c
index 798c027..9610dfe 100644
--- a/drivers/gpu/ion/ion_carveout_heap.c
+++ b/drivers/gpu/ion/ion_carveout_heap.c
@@ -112,26 +112,13 @@
 struct sg_table *ion_carveout_heap_map_dma(struct ion_heap *heap,
 					      struct ion_buffer *buffer)
 {
-	struct sg_table *table;
-	int ret;
+	size_t chunk_size = buffer->size;
 
-	table = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
-	if (!table)
-		return ERR_PTR(-ENOMEM);
+	if (ION_IS_CACHED(buffer->flags))
+		chunk_size = PAGE_SIZE;
 
-	ret = sg_alloc_table(table, 1, GFP_KERNEL);
-	if (ret)
-		goto err0;
-
-	table->sgl->length = buffer->size;
-	table->sgl->offset = 0;
-	table->sgl->dma_address = buffer->priv_phys;
-
-	return table;
-
-err0:
-	kfree(table);
-	return ERR_PTR(ret);
+	return ion_create_chunked_sg_table(buffer->priv_phys, chunk_size,
+					buffer->size);
 }
 
 void ion_carveout_heap_unmap_dma(struct ion_heap *heap,
diff --git a/drivers/gpu/ion/ion_cp_heap.c b/drivers/gpu/ion/ion_cp_heap.c
index 8a5e5c9..2ef285b 100644
--- a/drivers/gpu/ion/ion_cp_heap.c
+++ b/drivers/gpu/ion/ion_cp_heap.c
@@ -457,6 +457,12 @@
 	struct ion_cp_buffer *buf;
 	phys_addr_t addr;
 
+	/*
+	 * we never want Ion to fault pages in for us with this
+	 * heap. We want to set up the mappings ourselves in .map_user
+	 */
+	flags |= ION_FLAG_CACHED_NEEDS_SYNC;
+
 	buf = kzalloc(sizeof(*buf), GFP_KERNEL);
 	if (!buf)
 		return ION_CP_ALLOCATE_FAIL;
@@ -491,9 +497,6 @@
 struct sg_table *ion_cp_heap_create_sg_table(struct ion_buffer *buffer)
 {
 	size_t chunk_size = buffer->size;
-	struct sg_table *table;
-	int ret, i, n_chunks;
-	struct scatterlist *sg;
 	struct ion_cp_buffer *buf = buffer->priv_virt;
 
 	if (ION_IS_CACHED(buffer->flags))
@@ -501,26 +504,8 @@
 	else if (buf->is_secure && IS_ALIGNED(buffer->size, SZ_1M))
 		chunk_size = SZ_1M;
 
-	table = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
-	if (!table)
-		return ERR_PTR(-ENOMEM);
-
-	n_chunks = DIV_ROUND_UP(buffer->size, chunk_size);
-
-	ret = sg_alloc_table(table, n_chunks, GFP_KERNEL);
-	if (ret)
-		goto err0;
-
-	for_each_sg(table->sgl, sg, table->nents, i) {
-		sg_dma_address(sg) = buf->buffer + i * chunk_size;
-		sg->length = chunk_size;
-		sg->offset = 0;
-	}
-
-	return table;
-err0:
-	kfree(table);
-	return ERR_PTR(ret);
+	return ion_create_chunked_sg_table(buf->buffer, chunk_size,
+					buffer->size);
 }
 
 struct sg_table *ion_cp_heap_map_dma(struct ion_heap *heap,
diff --git a/drivers/gpu/ion/ion_priv.h b/drivers/gpu/ion/ion_priv.h
index 2ab2ed6..28ef1a5 100644
--- a/drivers/gpu/ion/ion_priv.h
+++ b/drivers/gpu/ion/ion_priv.h
@@ -98,6 +98,8 @@
 	void *vaddr;
 	int dmap_cnt;
 	struct sg_table *sg_table;
+	unsigned long *dirty;
+	struct list_head vmas;
 	unsigned int iommu_map_cnt;
 	struct rb_root iommu_maps;
 	int marked;
@@ -179,6 +181,15 @@
 };
 
 /**
+ * ion_buffer_fault_user_mappings - fault in user mappings of this buffer
+ * @buffer:		buffer
+ *
+ * indicates whether userspace mappings of this buffer will be faulted
+ * in, this can affect how buffers are allocated from the heap.
+ */
+bool ion_buffer_fault_user_mappings(struct ion_buffer *buffer);
+
+/**
  * struct mem_map_data - represents information about the memory map for a heap
  * @node:		rb node used to store in the tree of mem_map_data
  * @addr:		start address of memory region.
@@ -330,4 +341,16 @@
 int ion_heap_allow_heap_secure(enum ion_heap_type type);
 
 int ion_heap_allow_handle_secure(enum ion_heap_type type);
+
+/**
+ * ion_create_chunked_sg_table - helper function to create sg table
+ * with specified chunk size
+ * @buffer_base:	The starting address used for the sg dma address
+ * @chunk_size:		The size of each entry in the sg table
+ * @total_size:		The total size of the sg table (i.e. the sum of the
+ *			entries). This will be rounded up to the nearest
+ *			multiple of `chunk_size'
+ */
+struct sg_table *ion_create_chunked_sg_table(phys_addr_t buffer_base,
+					size_t chunk_size, size_t total_size);
 #endif /* _ION_PRIV_H */
diff --git a/drivers/gpu/ion/ion_system_heap.c b/drivers/gpu/ion/ion_system_heap.c
index 7046709..ceb30a4 100644
--- a/drivers/gpu/ion/ion_system_heap.c
+++ b/drivers/gpu/ion/ion_system_heap.c
@@ -15,7 +15,10 @@
  *
  */
 
+#include <asm/page.h>
+#include <linux/dma-mapping.h>
 #include <linux/err.h>
+#include <linux/highmem.h>
 #include <linux/ion.h>
 #include <linux/mm.h>
 #include <linux/scatterlist.h>
@@ -35,6 +38,37 @@
 static unsigned int system_heap_has_outer_cache;
 static unsigned int system_heap_contig_has_outer_cache;
 
+struct page_info {
+	struct page *page;
+	unsigned long order;
+	struct list_head list;
+};
+
+static struct page_info *alloc_largest_available(unsigned long size,
+						 bool split_pages)
+{
+	static unsigned int orders[] = {8, 4, 0};
+	struct page *page;
+	struct page_info *info;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(orders); i++) {
+		if (size < (1 << orders[i]) * PAGE_SIZE)
+			continue;
+		page = alloc_pages(GFP_HIGHUSER | __GFP_ZERO |
+				   __GFP_NOWARN | __GFP_NORETRY, orders[i]);
+		if (!page)
+			continue;
+		if (split_pages)
+			split_page(page, orders[i]);
+		info = kmap(page);
+		info->page = page;
+		info->order = orders[i];
+		return info;
+	}
+	return NULL;
+}
+
 static int ion_system_heap_allocate(struct ion_heap *heap,
 				     struct ion_buffer *buffer,
 				     unsigned long size, unsigned long align,
@@ -42,31 +76,73 @@
 {
 	struct sg_table *table;
 	struct scatterlist *sg;
-	int i, j;
-	int npages = PAGE_ALIGN(size) / PAGE_SIZE;
+	int ret;
+	struct list_head pages;
+	struct page_info *info, *tmp_info;
+	int i = 0;
+	long size_remaining = PAGE_ALIGN(size);
+	bool split_pages = ion_buffer_fault_user_mappings(buffer);
+
+
+	INIT_LIST_HEAD(&pages);
+	while (size_remaining > 0) {
+		info = alloc_largest_available(size_remaining, split_pages);
+		if (!info)
+			goto err;
+		list_add_tail(&info->list, &pages);
+		size_remaining -= (1 << info->order) * PAGE_SIZE;
+		i++;
+	}
 
 	table = kmalloc(sizeof(struct sg_table), GFP_KERNEL);
 	if (!table)
-		return -ENOMEM;
-	i = sg_alloc_table(table, npages, GFP_KERNEL);
-	if (i)
-		goto err0;
-	for_each_sg(table->sgl, sg, table->nents, i) {
-		struct page *page;
-		page = alloc_page(GFP_KERNEL|__GFP_ZERO);
-		if (!page)
-			goto err1;
-		sg_set_page(sg, page, PAGE_SIZE, 0);
+		goto err;
+
+	if (split_pages)
+		ret = sg_alloc_table(table, PAGE_ALIGN(size) / PAGE_SIZE,
+				     GFP_KERNEL);
+	else
+		ret = sg_alloc_table(table, i, GFP_KERNEL);
+
+	if (ret)
+		goto err1;
+
+	sg = table->sgl;
+	list_for_each_entry_safe(info, tmp_info, &pages, list) {
+		struct page *page = info->page;
+
+		if (split_pages) {
+			for (i = 0; i < (1 << info->order); i++) {
+				sg_set_page(sg, page + i, PAGE_SIZE, 0);
+				sg = sg_next(sg);
+			}
+		} else {
+			sg_set_page(sg, page, (1 << info->order) * PAGE_SIZE,
+				    0);
+			sg = sg_next(sg);
+		}
+		list_del(&info->list);
+		kunmap(page);
 	}
+
+	dma_sync_sg_for_device(NULL, table->sgl, table->nents,
+			       DMA_BIDIRECTIONAL);
+
 	buffer->priv_virt = table;
 	atomic_add(size, &system_heap_allocated);
 	return 0;
 err1:
-	for_each_sg(table->sgl, sg, i, j)
-		__free_page(sg_page(sg));
-	sg_free_table(table);
-err0:
 	kfree(table);
+err:
+	list_for_each_entry(info, &pages, list) {
+		if (split_pages)
+			for (i = 0; i < (1 << info->order); i++)
+				__free_page(info->page + i);
+		else
+			__free_pages(info->page, info->order);
+
+		kunmap(info->page);
+	}
 	return -ENOMEM;
 }
 
@@ -77,7 +153,7 @@
 	struct sg_table *table = buffer->priv_virt;
 
 	for_each_sg(table->sgl, sg, table->nents, i)
-		__free_page(sg_page(sg));
+		__free_pages(sg_page(sg), get_order(sg_dma_len(sg)));
 	if (buffer->sg_table)
 		sg_free_table(buffer->sg_table);
 	kfree(buffer->sg_table);
@@ -99,25 +175,33 @@
 void *ion_system_heap_map_kernel(struct ion_heap *heap,
 				 struct ion_buffer *buffer)
 {
-	if (!ION_IS_CACHED(buffer->flags)) {
-		pr_err("%s: cannot map system heap uncached\n", __func__);
-		return ERR_PTR(-EINVAL);
-	} else {
-		struct scatterlist *sg;
-		int i;
-		void *vaddr;
-		struct sg_table *table = buffer->priv_virt;
-		struct page **pages = kmalloc(
-					sizeof(struct page *) * table->nents,
-					GFP_KERNEL);
+	struct scatterlist *sg;
+	int i, j;
+	void *vaddr;
+	pgprot_t pgprot;
+	struct sg_table *table = buffer->priv_virt;
+	int npages = PAGE_ALIGN(buffer->size) / PAGE_SIZE;
+	struct page **pages = kzalloc(sizeof(struct page *) * npages,
+				     GFP_KERNEL);
+	struct page **tmp = pages;
 
-		for_each_sg(table->sgl, sg, table->nents, i)
-			pages[i] = sg_page(sg);
-		vaddr = vmap(pages, table->nents, VM_MAP, PAGE_KERNEL);
-		kfree(pages);
+	if (buffer->flags & ION_FLAG_CACHED)
+		pgprot = PAGE_KERNEL;
+	else
+		pgprot = pgprot_writecombine(PAGE_KERNEL);
 
-		return vaddr;
+	for_each_sg(table->sgl, sg, table->nents, i) {
+		int npages_this_entry = PAGE_ALIGN(sg_dma_len(sg)) / PAGE_SIZE;
+		struct page *page = sg_page(sg);
+		BUG_ON(i >= npages);
+		for (j = 0; j < npages_this_entry; j++) {
+			*(tmp++) = page++;
+		}
 	}
+	vaddr = vmap(pages, npages, VM_MAP, pgprot);
+	kfree(pages);
+
+	return vaddr;
 }
 
 void ion_system_heap_unmap_kernel(struct ion_heap *heap,
@@ -155,26 +239,27 @@
 int ion_system_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer,
 			     struct vm_area_struct *vma)
 {
+	struct sg_table *table = buffer->priv_virt;
+	unsigned long addr = vma->vm_start;
+	unsigned long offset = vma->vm_pgoff;
+	struct scatterlist *sg;
+	int i;
+
 	if (!ION_IS_CACHED(buffer->flags)) {
 		pr_err("%s: cannot map system heap uncached\n", __func__);
 		return -EINVAL;
-	} else {
-		struct sg_table *table = buffer->priv_virt;
-		unsigned long addr = vma->vm_start;
-		unsigned long offset = vma->vm_pgoff;
-		struct scatterlist *sg;
-		int i;
-
-		for_each_sg(table->sgl, sg, table->nents, i) {
-			if (offset) {
-				offset--;
-				continue;
-			}
-			vm_insert_page(vma, addr, sg_page(sg));
-			addr += PAGE_SIZE;
-		}
-		return 0;
 	}
+
+	for_each_sg(table->sgl, sg, table->nents, i) {
+		if (offset) {
+			offset--;
+			continue;
+		}
+		remap_pfn_range(vma, addr, page_to_pfn(sg_page(sg)),
+				sg_dma_len(sg), vma->vm_page_prot);
+		addr += sg_dma_len(sg);
+	}
+	return 0;
 }
 
 int ion_system_heap_cache_ops(struct ion_heap *heap, struct ion_buffer *buffer,
@@ -382,7 +467,7 @@
 }
 
 struct sg_table *ion_system_contig_heap_map_dma(struct ion_heap *heap,
-						   struct ion_buffer *buffer)
+						struct ion_buffer *buffer)
 {
 	struct sg_table *table;
 	int ret;
@@ -400,6 +485,13 @@
 	return table;
 }
 
+void ion_system_contig_heap_unmap_dma(struct ion_heap *heap,
+				      struct ion_buffer *buffer)
+{
+	sg_free_table(buffer->sg_table);
+	kfree(buffer->sg_table);
+}
+
 int ion_system_contig_heap_map_user(struct ion_heap *heap,
 				    struct ion_buffer *buffer,
 				    struct vm_area_struct *vma)
@@ -561,7 +653,7 @@
 	.free = ion_system_contig_heap_free,
 	.phys = ion_system_contig_heap_phys,
 	.map_dma = ion_system_contig_heap_map_dma,
-	.unmap_dma = ion_system_heap_unmap_dma,
+	.unmap_dma = ion_system_contig_heap_unmap_dma,
 	.map_kernel = ion_system_contig_heap_map_kernel,
 	.unmap_kernel = ion_system_contig_heap_unmap_kernel,
 	.map_user = ion_system_contig_heap_map_user,
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index 1bfbaa6..e5696be 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -37,7 +37,7 @@
 #define MSM_VIDC_VERSION KERNEL_VERSION(0, 0, 1);
 #define MAX_DEBUGFS_NAME 50
 #define DEFAULT_TIMEOUT 3
-#define DEFAULT_HEIGHT 1080
+#define DEFAULT_HEIGHT 1088
 #define DEFAULT_WIDTH 1920
 #define MIN_SUPPORTED_WIDTH 32
 #define MIN_SUPPORTED_HEIGHT 32
diff --git a/drivers/media/platform/msm/vidc/q6_hfi.c b/drivers/media/platform/msm/vidc/q6_hfi.c
index bf6c7db..123b654 100644
--- a/drivers/media/platform/msm/vidc/q6_hfi.c
+++ b/drivers/media/platform/msm/vidc/q6_hfi.c
@@ -479,7 +479,7 @@
 
 	q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr), HFI_CMD_SYS_INIT);
 
-	rc = create_pkt_cmd_sys_init(&apr.pkt, HFI_ARCH_OX_OFFSET);
+	rc = create_pkt_cmd_sys_init(&apr.pkt, HFI_VIDEO_ARCH_OX);
 	if (rc) {
 		dprintk(VIDC_ERR, "Failed to create sys init pkt");
 		goto err_core_init;
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index b5dd15d..779b996 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -990,7 +990,7 @@
 		goto err_core_init;
 	}
 
-	rc = create_pkt_cmd_sys_init(&pkt, HFI_ARCH_OX_OFFSET);
+	rc = create_pkt_cmd_sys_init(&pkt, HFI_VIDEO_ARCH_OX);
 	if (rc) {
 		dprintk(VIDC_ERR, "Failed to create sys init pkt");
 		goto err_core_init;
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index a2701ce..91aaf3c 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -170,6 +170,9 @@
 	int			disable_flat_portion_ocv;
 	int			ocv_dis_high_soc;
 	int			ocv_dis_low_soc;
+	int			high_ocv_correction_limit_uv;
+	int			low_ocv_correction_limit_uv;
+	int			hold_soc_est;
 	int			prev_vbat_batt_terminal_uv;
 	int			vbatt_cutoff_count;
 	int			low_voltage_detect;
@@ -1861,6 +1864,7 @@
 	int m = 0;
 	int rc = 0;
 	int delta_ocv_uv_limit = 0;
+	int correction_limit_uv = 0;
 
 	rc = pm8921_bms_get_simultaneous_battery_voltage_and_current(
 							&ibat_ua,
@@ -1905,17 +1909,13 @@
 
 	/*
 	 * do not adjust
-	 * if soc is same as what bms calculated
-	 * if soc_est is between 45 and 25, this is the flat portion of the
-	 * curve where soc_est is not so accurate. We generally don't want to
-	 * adjust when soc_est is inaccurate except for the cases when soc is
-	 * way far off (higher than 50 or lesser than 20).
-	 * Also don't adjust soc if it is above 90 becuase we might pull it low
+	 * if soc_est is same as what bms calculated
+	 * OR if soc_est > 15
+	 * OR if soc it is above 90 because we might pull it low
 	 * and  cause a bad user experience
 	 */
 	if (soc_est == soc
-		|| (is_between(45, chip->adjust_soc_low_threshold, soc_est)
-		&& is_between(50, chip->adjust_soc_low_threshold - 5, soc))
+		|| soc_est > 15
 		|| soc >= 90)
 		goto out;
 
@@ -1964,6 +1964,22 @@
 		pr_debug("new delta ocv = %d\n", delta_ocv_uv);
 	}
 
+	if (chip->last_ocv_uv > 3800000)
+		correction_limit_uv = the_chip->high_ocv_correction_limit_uv;
+	else
+		correction_limit_uv = the_chip->low_ocv_correction_limit_uv;
+
+	if (abs(delta_ocv_uv) > correction_limit_uv) {
+		pr_debug("limiting delta ocv %d limit = %d\n", delta_ocv_uv,
+				correction_limit_uv);
+
+		if (delta_ocv_uv > 0)
+			delta_ocv_uv = correction_limit_uv;
+		else
+			delta_ocv_uv = -1 * correction_limit_uv;
+		pr_debug("new delta ocv = %d\n", delta_ocv_uv);
+	}
+
 	chip->last_ocv_uv -= delta_ocv_uv;
 
 	if (chip->last_ocv_uv >= chip->max_voltage_uv)
@@ -1980,7 +1996,7 @@
 	 * if soc_new is ZERO force it higher so that phone doesnt report soc=0
 	 * soc = 0 should happen only when soc_est == 0
 	 */
-	if (soc_new == 0 && soc_est != 0)
+	if (soc_new == 0 && soc_est >= the_chip->hold_soc_est)
 		soc_new = 1;
 
 	soc = soc_new;
@@ -2479,9 +2495,18 @@
 
 	/* last_soc < soc  ... scale and catch up */
 	if (last_soc != -EINVAL && last_soc < soc && soc != 100)
-		soc = scale_soc_while_chg(chip, delta_time_us, soc, last_soc);
+			soc = scale_soc_while_chg(chip, delta_time_us,
+							soc, last_soc);
 
-	last_soc = soc;
+	/* restrict soc to 1% change */
+	if (last_soc != -EINVAL) {
+		if (soc < last_soc && soc != 0)
+			soc = last_soc - 1;
+		if (soc > last_soc && soc != 100)
+			soc = last_soc + 1;
+	}
+
+	last_soc = bound_soc(soc);
 	backup_soc_and_iavg(chip, batt_temp, last_soc);
 	pr_debug("Reported SOC = %d\n", last_soc);
 	chip->t_soc_queried = now;
@@ -2986,6 +3011,7 @@
 	GET_VBAT_VSENSE_SIMULTANEOUS,
 	STOP_OCV,
 	START_OCV,
+	SET_OCV,
 };
 
 static int test_batt_temp = 5;
@@ -3227,6 +3253,8 @@
 				(void *)STOP_OCV, &calc_fops);
 	debugfs_create_file("start_ocv", 0644, chip->dent,
 				(void *)START_OCV, &calc_fops);
+	debugfs_create_file("set_ocv", 0644, chip->dent,
+				(void *)SET_OCV, &calc_fops);
 
 	debugfs_create_file("simultaneous", 0644, chip->dent,
 			(void *)GET_VBAT_VSENSE_SIMULTANEOUS, &calc_fops);
@@ -3372,6 +3400,11 @@
 	chip->ocv_dis_high_soc = pdata->ocv_dis_high_soc;
 	chip->ocv_dis_low_soc = pdata->ocv_dis_low_soc;
 
+	chip->high_ocv_correction_limit_uv
+					= pdata->high_ocv_correction_limit_uv;
+	chip->low_ocv_correction_limit_uv = pdata->low_ocv_correction_limit_uv;
+	chip->hold_soc_est = pdata->hold_soc_est;
+
 	chip->alarm_low_mv = pdata->alarm_low_mv;
 	chip->alarm_high_mv = pdata->alarm_high_mv;
 	chip->low_voltage_detect = pdata->low_voltage_detect;
@@ -3463,6 +3496,18 @@
 	return 0;
 }
 
+static int pm8921_bms_suspend(struct device *dev)
+{
+	/*
+	 * set the last reported soc to invalid, so that
+	 * next time we resume we don't want to restrict
+	 * the decrease of soc by only 1%
+	 */
+	last_soc = -EINVAL;
+
+	return 0;
+}
+
 static int pm8921_bms_resume(struct device *dev)
 {
 	int rc;
@@ -3490,6 +3535,7 @@
 
 static const struct dev_pm_ops pm8921_bms_pm_ops = {
 	.resume		= pm8921_bms_resume,
+	.suspend	= pm8921_bms_suspend,
 };
 
 static struct platform_driver pm8921_bms_driver = {
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index 08cf71e..5575139 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -1608,10 +1608,9 @@
 	pr_debug("SOC before adjustment = %d\n", soc);
 	new_calculated_soc = adjust_soc(chip, &params, soc, batt_temp);
 
-	/* clamp soc due to BMS HW inaccuracies in pm8941v2.0 */
-	if (chip->revision1 == 0 && chip->revision2 == 0)
-		new_calculated_soc = clamp_soc_based_on_voltage(chip,
-						new_calculated_soc);
+	/* always clamp soc due to BMS hw/sw immaturities */
+	new_calculated_soc = clamp_soc_based_on_voltage(chip,
+					new_calculated_soc);
 
 done_calculating:
 	if (new_calculated_soc != chip->calculated_soc
diff --git a/drivers/usb/gadget/f_rmnet.c b/drivers/usb/gadget/f_rmnet.c
index 4b9dfbf..2dccca8 100644
--- a/drivers/usb/gadget/f_rmnet.c
+++ b/drivers/usb/gadget/f_rmnet.c
@@ -387,7 +387,7 @@
 	unsigned		port_num;
 	enum transport_type	cxport = rmnet_ports[dev->port_num].ctrl_xport;
 	enum transport_type	dxport = rmnet_ports[dev->port_num].data_xport;
-	u8			src_connection_idx, dst_connection_idx;
+	int			src_connection_idx = 0, dst_connection_idx = 0;
 	struct usb_gadget	*gadget = dev->cdev->gadget;
 
 	pr_debug("%s: ctrl xport: %s data xport: %s dev: %p portno: %d\n",
@@ -439,7 +439,6 @@
 	port_num = rmnet_ports[dev->port_num].data_xport_num;
 
 	switch (dxport) {
-	case USB_GADGET_XPORT_BAM:
 	case USB_GADGET_XPORT_BAM2BAM:
 		src_connection_idx = usb_bam_get_connection_idx(gadget->name,
 			A2_P_BAM, USB_TO_PEER_PERIPHERAL, port_num);
@@ -451,6 +450,7 @@
 			gsmd_ctrl_disconnect(&dev->port, port_num);
 			return ret;
 		}
+	case USB_GADGET_XPORT_BAM:
 		ret = gbam_connect(&dev->port, port_num,
 			dxport, src_connection_idx, dst_connection_idx);
 		if (ret) {
diff --git a/drivers/video/msm/mdss/Makefile b/drivers/video/msm/mdss/Makefile
index a710fef..7fafbc64 100644
--- a/drivers/video/msm/mdss/Makefile
+++ b/drivers/video/msm/mdss/Makefile
@@ -1,6 +1,7 @@
 mdss-mdp-objs := mdss_mdp.o mdss_mdp_ctl.o mdss_mdp_pipe.o mdss_mdp_util.o
 mdss-mdp-objs += mdss_mdp_pp.o
 mdss-mdp-objs += mdss_mdp_intf_video.o
+mdss-mdp-objs += mdss_mdp_intf_cmd.o
 mdss-mdp-objs += mdss_mdp_intf_writeback.o
 mdss-mdp-objs += mdss_mdp_rotator.o
 mdss-mdp-objs += mdss_mdp_overlay.o
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index bfcd7ec..faf3e6f 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -25,6 +25,7 @@
 #include "mdss.h"
 #include "mdss_panel.h"
 #include "mdss_dsi.h"
+#include "mdss_debug.h"
 
 static unsigned char *mdss_dsi_base;
 
@@ -250,32 +251,6 @@
 	return 0;
 }
 
-static int mdss_dsi_ctrl_unprepare(struct mdss_panel_data *pdata)
-{
-	struct mdss_panel_info *pinfo;
-	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
-	int ret = 0;
-
-	if (pdata == NULL) {
-		pr_err("%s: Invalid input data\n", __func__);
-		return -EINVAL;
-	}
-
-	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
-				panel_data);
-	pinfo = &pdata->panel_info;
-
-	mdss_dsi_op_mode_config(DSI_CMD_MODE, pdata);
-
-	ret = ctrl_pdata->off(pdata);
-	if (ret) {
-		pr_err("%s: Panel OFF failed\n", __func__);
-		return ret;
-	}
-
-	return ret;
-}
-
 static void mdss_dsi_put_dt_vreg_data(struct device *dev,
 	struct dss_module_power *module_power)
 {
@@ -443,6 +418,10 @@
 
 	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
 				panel_data);
+
+	pr_debug("%s+: ctrl=%p ndx=%d\n", __func__,
+				ctrl_pdata, ctrl_pdata->ndx);
+
 	mdss_dsi_clk_disable(pdata);
 	mdss_dsi_unprepare_clocks(ctrl_pdata);
 
@@ -514,6 +493,10 @@
 
 	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
 				panel_data);
+
+	pr_debug("%s+: ctrl=%p ndx=%d\n",
+				__func__, ctrl_pdata, ctrl_pdata->ndx);
+
 	pinfo = &pdata->panel_info;
 
 	ret = mdss_dsi_panel_power_on(pdata, 1);
@@ -597,6 +580,27 @@
 		wmb();
 	}
 
+	pr_debug("%s-:\n", __func__);
+	return 0;
+}
+
+static int mdss_dsi_unblank(struct mdss_panel_data *pdata)
+{
+	int ret = 0;
+	struct mipi_panel_info *mipi;
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+
+	pr_debug("%s+:\n", __func__);
+
+	if (pdata == NULL) {
+		pr_err("%s: Invalid input data\n", __func__);
+		return -EINVAL;
+	}
+
+	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+				panel_data);
+	mipi  = &pdata->panel_info.mipi;
+
 	ret = ctrl_pdata->on(pdata);
 	if (ret) {
 		pr_err("%s: unable to initialize the panel\n", __func__);
@@ -605,6 +609,34 @@
 
 	mdss_dsi_op_mode_config(mipi->mode, pdata);
 
+	pr_debug("%s-:\n", __func__);
+
+	return ret;
+}
+
+static int mdss_dsi_blank(struct mdss_panel_data *pdata)
+{
+	int ret = 0;
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+
+	pr_debug("%s+:\n", __func__);
+
+	if (pdata == NULL) {
+		pr_err("%s: Invalid input data\n", __func__);
+		return -EINVAL;
+	}
+
+	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+				panel_data);
+
+	mdss_dsi_op_mode_config(DSI_CMD_MODE, pdata);
+
+	ret = ctrl_pdata->off(pdata);
+	if (ret) {
+		pr_err("%s: Panel OFF failed\n", __func__);
+		return ret;
+	}
+
 	pr_debug("%s-:End\n", __func__);
 	return ret;
 }
@@ -621,33 +653,27 @@
 	}
 	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
 				panel_data);
+	pr_debug("%s+:event=%d\n", __func__, event);
+
 	switch (event) {
 	case MDSS_EVENT_UNBLANK:
+		rc = mdss_dsi_on(pdata);
 		if (ctrl_pdata->on_cmds->ctrl_state == DSI_LP_MODE) {
-			rc = mdss_dsi_on(pdata);
-		} else {
-			pr_debug("%s:event=%d, Dsi On not called: ctrl_state: %d\n",
-				 __func__, event,
-				 ctrl_pdata->on_cmds->ctrl_state);
-			rc = -EINVAL;
+			rc = mdss_dsi_unblank(pdata);
 		}
 		break;
+	case MDSS_EVENT_PANEL_ON:
+		if (ctrl_pdata->on_cmds->ctrl_state == DSI_HS_MODE)
+			rc = mdss_dsi_unblank(pdata);
+		break;
 	case MDSS_EVENT_BLANK:
 		if (ctrl_pdata->off_cmds->ctrl_state == DSI_HS_MODE) {
-			rc = mdss_dsi_ctrl_unprepare(pdata);
-		} else {
-			pr_debug("%s:event=%d,Unprepare not called.Ctrl_state: %d\n",
-				 __func__, event,
-				 ctrl_pdata->on_cmds->ctrl_state);
-			rc = -EINVAL;
+			rc = mdss_dsi_blank(pdata);
 		}
 		break;
-	case MDSS_EVENT_TIMEGEN_OFF:
+	case MDSS_EVENT_PANEL_OFF:
 		if (ctrl_pdata->off_cmds->ctrl_state == DSI_LP_MODE) {
-			pr_debug("%s:event=%d, calling unprepare: ctrl_state: %d\n",
-				 __func__, event,
-				 ctrl_pdata->on_cmds->ctrl_state);
-			rc = mdss_dsi_ctrl_unprepare(pdata);
+			rc = mdss_dsi_blank(pdata);
 		}
 		rc = mdss_dsi_off(pdata);
 		break;
@@ -665,6 +691,7 @@
 		pr_debug("%s: unhandled event=%d\n", __func__, event);
 		break;
 	}
+	pr_debug("%s-:event=%d, rc=%d\n", __func__, event, rc);
 	return rc;
 }
 
@@ -674,8 +701,6 @@
 	u32 index;
 	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
 
-	pr_debug("%s\n", __func__);
-
 	if (pdev->dev.of_node) {
 		struct resource *mdss_dsi_mres;
 		const char *ctrl_name;
@@ -789,7 +814,7 @@
 struct device dsi_dev;
 
 int mdss_dsi_retrieve_ctrl_resources(struct platform_device *pdev, int mode,
-			    unsigned char **ctrl_base)
+			struct mdss_dsi_ctrl_pdata *ctrl)
 {
 	int rc = 0;
 	u32 index;
@@ -828,21 +853,25 @@
 		return -ENOMEM;
 	}
 
-	*ctrl_base = ioremap(mdss_dsi_mres->start,
+	ctrl->ctrl_base = ioremap(mdss_dsi_mres->start,
 		resource_size(mdss_dsi_mres));
-	if (!(*ctrl_base)) {
+	if (!(ctrl->ctrl_base)) {
 		pr_err("%s:%d unable to remap dsi resources",
 			       __func__, __LINE__);
 		return -ENOMEM;
 	}
 
+	ctrl->reg_size = resource_size(mdss_dsi_mres);
+
+	pr_info("%s: dsi base=%x size=%x\n",
+		__func__, (int)ctrl->ctrl_base, ctrl->reg_size);
+
 	return 0;
 }
 
 
 int dsi_panel_device_register(struct platform_device *pdev,
-			      struct mdss_panel_common_pdata *panel_data,
-			      char backlight_ctrl)
+			      struct mdss_panel_common_pdata *panel_data)
 {
 	struct mipi_panel_info *mipi;
 	int rc;
@@ -851,7 +880,6 @@
 	struct mdss_dsi_ctrl_pdata *ctrl_pdata;
 	struct device_node *dsi_ctrl_np = NULL;
 	struct platform_device *ctrl_pdev = NULL;
-	unsigned char *ctrl_addr;
 	bool broadcast;
 	bool cont_splash_enabled = false;
 
@@ -891,8 +919,7 @@
 	else
 		bpp = 3;		/* Default format set to RGB888 */
 
-	if (panel_data->panel_info.type == MIPI_VIDEO_PANEL &&
-		!panel_data->panel_info.clk_rate) {
+	if (!panel_data->panel_info.clk_rate) {
 		h_period += panel_data->panel_info.lcdc.xres_pad;
 		v_period += panel_data->panel_info.lcdc.yres_pad;
 
@@ -961,6 +988,45 @@
 		}
 	}
 
+	ctrl_pdata->disp_te_gpio = of_get_named_gpio(pdev->dev.of_node,
+						     "qcom,te-gpio", 0);
+	if (!gpio_is_valid(ctrl_pdata->disp_te_gpio)) {
+		pr_err("%s:%d, Disp_te gpio not specified\n",
+						__func__, __LINE__);
+	} else {
+		rc = gpio_request(ctrl_pdata->disp_te_gpio, "disp_te");
+		if (rc) {
+			pr_err("request TE gpio failed, rc=%d\n",
+			       rc);
+			gpio_free(ctrl_pdata->disp_te_gpio);
+			return -ENODEV;
+		}
+		rc = gpio_tlmm_config(GPIO_CFG(
+				ctrl_pdata->disp_te_gpio, 1,
+				GPIO_CFG_INPUT,
+				GPIO_CFG_PULL_DOWN,
+				GPIO_CFG_2MA),
+				GPIO_CFG_ENABLE);
+
+		if (rc) {
+			pr_err("%s: unable to config tlmm = %d\n",
+				__func__, ctrl_pdata->disp_te_gpio);
+			gpio_free(ctrl_pdata->disp_te_gpio);
+			return -ENODEV;
+		}
+
+		rc = gpio_direction_input(ctrl_pdata->disp_te_gpio);
+		if (rc) {
+			pr_err("set_direction for disp_en gpio failed, rc=%d\n",
+			       rc);
+			gpio_free(ctrl_pdata->disp_te_gpio);
+			return -ENODEV;
+		}
+		pr_debug("%s: te_gpio=%d\n", __func__,
+					ctrl_pdata->disp_te_gpio);
+	}
+
+
 	ctrl_pdata->rst_gpio = of_get_named_gpio(pdev->dev.of_node,
 						 "qcom,rst-gpio", 0);
 	if (!gpio_is_valid(ctrl_pdata->rst_gpio)) {
@@ -985,12 +1051,11 @@
 
 	if (mdss_dsi_retrieve_ctrl_resources(ctrl_pdev,
 					     panel_data->panel_info.pdest,
-					     &ctrl_addr)) {
+					     ctrl_pdata)) {
 		pr_err("%s: unable to get Dsi controller res\n", __func__);
 		return -EPERM;
 	}
 
-	pr_debug("%s: ctrl base address: 0x%x\n", __func__, (int)ctrl_addr);
 	ctrl_pdata->panel_data.event_handler = mdss_dsi_event_handler;
 
 	ctrl_pdata->on_cmds = panel_data->dsi_panel_on_cmds;
@@ -1001,9 +1066,16 @@
 				       sizeof(struct mdss_panel_info));
 
 	mdss_dsi_irq_handler_config(ctrl_pdata);
-	(ctrl_pdata->panel_data).set_backlight = panel_data->bl_fnc;
-	(ctrl_pdata->ctrl_base) = ctrl_addr;
-	(ctrl_pdata->bl_ctrl) = backlight_ctrl;
+	ctrl_pdata->panel_data.set_backlight = panel_data->bl_fnc;
+	ctrl_pdata->bklt_ctrl = panel_data->panel_info.bklt_ctrl;
+	ctrl_pdata->pwm_gpio = panel_data->panel_info.pwm_gpio;
+	ctrl_pdata->pwm_period = panel_data->panel_info.pwm_period;
+	ctrl_pdata->pwm_lpg_chan = panel_data->panel_info.pwm_lpg_chan;
+	ctrl_pdata->bklt_max = panel_data->panel_info.bl_max;
+
+	if (ctrl_pdata->bklt_ctrl == BL_PWM)
+		mdss_dsi_panel_pwm_cfg(ctrl_pdata);
+
 	/*
 	 * register in mdp driver
 	 */
@@ -1047,6 +1119,16 @@
 	pr_debug("%s: pclk=%d, bclk=%d\n", __func__,
 			ctrl_pdata->pclk_rate, ctrl_pdata->byte_clk_rate);
 
+	if (panel_data->panel_info.pdest == DISPLAY_1) {
+		mdss_debug_register_base("dsi0",
+			ctrl_pdata->ctrl_base, ctrl_pdata->reg_size);
+		ctrl_pdata->ndx = 0;
+	} else {
+		mdss_debug_register_base("dsi1",
+			ctrl_pdata->ctrl_base, ctrl_pdata->reg_size);
+		ctrl_pdata->ndx = 1;
+	}
+
 	pr_debug("%s: Panal data initialized\n", __func__);
 	return 0;
 }
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index b365f36..197ff7a 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -273,17 +273,27 @@
 };
 
 struct mdss_dsi_ctrl_pdata {
+	int ndx;
 	int (*on) (struct mdss_panel_data *pdata);
 	int (*off) (struct mdss_panel_data *pdata);
 	struct mdss_panel_data panel_data;
+	struct mdss_hw *mdss_hw;
 	unsigned char *ctrl_base;
-	char bl_ctrl;
+	int reg_size;
 	struct clk *byte_clk;
 	struct clk *esc_clk;
 	struct clk *pixel_clk;
+	int irq_cnt;
 	int mdss_dsi_clk_on;
 	int rst_gpio;
 	int disp_en_gpio;
+	int disp_te_gpio;
+	int bklt_ctrl;	/* backlight ctrl */
+	int pwm_period;
+	int pwm_gpio;
+	int pwm_lpg_chan;
+	int bklt_max;
+	struct pwm_device *pwm_bl;
 	struct dsi_panel_cmds_list *on_cmds;
 	struct dsi_panel_cmds_list *off_cmds;
 	struct dsi_drv_cm_data shared_pdata;
@@ -293,8 +303,7 @@
 };
 
 int dsi_panel_device_register(struct platform_device *pdev,
-			      struct mdss_panel_common_pdata *panel_data,
-			      char bl_ctrl);
+			      struct mdss_panel_common_pdata *panel_data);
 
 char *mdss_dsi_buf_reserve_hdr(struct dsi_buf *dp, int hlen);
 char *mdss_dsi_buf_init(struct dsi_buf *dp);
@@ -343,5 +352,7 @@
 void mdss_dsi_phy_enable(unsigned char *ctrl_base, int on);
 void mdss_dsi_phy_init(struct mdss_panel_data *pdata);
 void mdss_dsi_phy_sw_reset(unsigned char *ctrl_base);
+void mdss_dsi_cmd_test_pattern(struct mdss_panel_data *pdata);
+void mdss_dsi_panel_pwm_cfg(struct mdss_dsi_ctrl_pdata *ctrl);
 
 #endif /* MDSS_DSI_H */
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index 6f7023c..ccec0fc 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -26,7 +26,6 @@
 #include "mdss_dsi.h"
 
 static struct completion dsi_dma_comp;
-static int dsi_irq_enabled;
 static spinlock_t dsi_irq_lock;
 static spinlock_t dsi_mdp_lock;
 static int dsi_mdp_busy;
@@ -51,90 +50,47 @@
 	spin_lock_init(&dsi_mdp_lock);
 }
 
-void mdss_dsi_irq_handler_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+void mdss_dsi_irq_handler_config(struct mdss_dsi_ctrl_pdata *ctrl)
 {
-	if (ctrl_pdata->panel_data.panel_info.pdest == DISPLAY_1)
-		mdss_dsi0_hw.ptr = (void *)(ctrl_pdata);
-	else
-		mdss_dsi1_hw.ptr = (void *)(ctrl_pdata);
+	if (ctrl->panel_data.panel_info.pdest == DISPLAY_1) {
+		mdss_dsi0_hw.ptr = (void *)(ctrl);
+		ctrl->mdss_hw = &mdss_dsi0_hw;
+	} else {
+		mdss_dsi1_hw.ptr = (void *)(ctrl);
+		ctrl->mdss_hw = &mdss_dsi1_hw;
+	}
 }
 
-void mdss_dsi_enable_irq(struct mdss_panel_data *pdata)
+void mdss_dsi_irq_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable, int isr)
 {
 	unsigned long flags;
-	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
 
-	if (pdata == NULL) {
-		pr_err("%s: Invalid input data\n", __func__);
+	if (ctrl == NULL) {
+		pr_err("%s: Invalid ctrl\n", __func__);
 		return;
 	}
 
-	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
-				panel_data);
-
 	spin_lock_irqsave(&dsi_irq_lock, flags);
-	if (dsi_irq_enabled) {
-		pr_debug("%s: IRQ aleady enabled\n", __func__);
-		spin_unlock_irqrestore(&dsi_irq_lock, flags);
-		return;
+	if (enable) {
+		if (ctrl->irq_cnt == 0)
+			mdss_enable_irq(ctrl->mdss_hw);
+		ctrl->irq_cnt++;
+	} else {
+		if (ctrl->irq_cnt) {
+			ctrl->irq_cnt--;
+			if (ctrl->irq_cnt == 0) {
+				if (isr)
+					mdss_disable_irq_nosync(ctrl->mdss_hw);
+				else
+					mdss_disable_irq(ctrl->mdss_hw);
+			}
+		}
 	}
-
-	if ((ctrl_pdata->panel_data).panel_info.pdest == DISPLAY_1)
-		mdss_enable_irq(&mdss_dsi0_hw);
-	else
-		mdss_enable_irq(&mdss_dsi1_hw);
-
-	dsi_irq_enabled = 1;
-	/* TO DO: Check whether MDSS IRQ is enabled */
+	pr_debug("%s: ctrl=%d enable=%d cnt=%d\n", __func__,
+					ctrl->ndx, enable, ctrl->irq_cnt);
 	spin_unlock_irqrestore(&dsi_irq_lock, flags);
 }
 
-void mdss_dsi_disable_irq(struct mdss_panel_data *pdata)
-{
-	unsigned long flags;
-	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
-
-	if (pdata == NULL) {
-		pr_err("%s: Invalid input data\n", __func__);
-		return;
-	}
-
-	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
-				panel_data);
-
-	spin_lock_irqsave(&dsi_irq_lock, flags);
-	if (dsi_irq_enabled == 0) {
-		pr_debug("%s: IRQ already disabled\n", __func__);
-		spin_unlock_irqrestore(&dsi_irq_lock, flags);
-		return;
-	}
-	if (ctrl_pdata->panel_data.panel_info.pdest == DISPLAY_1)
-		mdss_disable_irq(&mdss_dsi0_hw);
-	else
-		mdss_disable_irq(&mdss_dsi1_hw);
-
-	dsi_irq_enabled = 0;
-	/* TO DO: Check whether MDSS IRQ is Disabled */
-	spin_unlock_irqrestore(&dsi_irq_lock, flags);
-}
-
-/*
- * mdss_dsi_disale_irq_nosync() should be called
- * from interrupt context
- */
-void mdss_dsi_disable_irq_nosync(void)
-{
-	spin_lock(&dsi_irq_lock);
-	if (dsi_irq_enabled == 0) {
-		pr_debug("%s: IRQ cannot be disabled\n", __func__);
-		spin_unlock(&dsi_irq_lock);
-		return;
-	}
-
-	dsi_irq_enabled = 0;
-	spin_unlock(&dsi_irq_lock);
-}
-
 /*
  * mipi dsi buf mechanism
  */
@@ -689,6 +645,30 @@
 	return len;
 }
 
+void mdss_dsi_cmd_test_pattern(struct mdss_panel_data *pdata)
+{
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+	int i;
+
+	if (pdata == NULL) {
+		pr_err("%s: Invalid input data\n", __func__);
+		return;
+	}
+
+	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+				panel_data);
+
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x015c, 0x201);
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x016c, 0xff0000); /* red */
+	i = 0;
+	while (i++ < 50) {
+		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0184, 0x1);
+		/* Add sleep to get ~50 fps frame rate*/
+		msleep(20);
+	}
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x015c, 0x0);
+}
+
 void mdss_dsi_host_init(struct mipi_panel_info *pinfo,
 				struct mdss_panel_data *pdata)
 {
@@ -745,7 +725,7 @@
 		if (pinfo->r_sel)
 			data |= BIT(4);
 		data |= (pinfo->dst_format & 0x0f);	/* 4 bits */
-		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x003c, data);
+		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0040, data);
 
 		/* DSI_COMMAND_MODE_MDP_DCS_CMD_CTRL */
 		data = pinfo->wr_mem_continue & 0x0ff;
@@ -830,6 +810,7 @@
 
 	dsi_ctrl |= BIT(0);	/* enable dsi */
 	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004, dsi_ctrl);
+	mdss_dsi_irq_ctrl(ctrl_pdata, 1, 0); /* enable dsi irq */
 
 	wmb();
 }
@@ -977,8 +958,6 @@
 				DSI_INTR_CMD_MDP_DONE_MASK;
 	}
 
-	pr_debug("%s: dsi_ctrl=%x intr=%x\n", __func__, dsi_ctrl, intr_ctrl);
-
 	if (ctrl_pdata->shared_pdata.broadcast_enable)
 		if ((pdata->panel_info.pdest == DISPLAY_2)
 		  && (left_ctrl_pdata != NULL)) {
@@ -994,17 +973,6 @@
 	wmb();
 }
 
-void mdss_dsi_cmd_mdp_start(struct mdss_panel_data *pdata)
-{
-	unsigned long flag;
-
-	spin_lock_irqsave(&dsi_mdp_lock, flag);
-	mdss_dsi_enable_irq(pdata);
-	dsi_mdp_busy = true;
-	spin_unlock_irqrestore(&dsi_mdp_lock, flag);
-}
-
-
 void mdss_dsi_cmd_bta_sw_trigger(struct mdss_panel_data *pdata)
 {
 	u32 status;
@@ -1116,7 +1084,7 @@
 	}
 
 	spin_lock_irqsave(&dsi_mdp_lock, flag);
-	mdss_dsi_enable_irq(pdata);
+	mdss_dsi_irq_ctrl(ctrl_pdata, 1, 0);
 
 	dsi_mdp_busy = true;
 	spin_unlock_irqrestore(&dsi_mdp_lock, flag);
@@ -1134,7 +1102,7 @@
 
 	spin_lock_irqsave(&dsi_mdp_lock, flag);
 	dsi_mdp_busy = false;
-	mdss_dsi_disable_irq(pdata);
+	mdss_dsi_irq_ctrl(ctrl_pdata, 0, 0);
 	spin_unlock_irqrestore(&dsi_mdp_lock, flag);
 
 	if (video_mode)
@@ -1206,7 +1174,7 @@
 	}
 
 	spin_lock_irqsave(&dsi_mdp_lock, flag);
-	mdss_dsi_enable_irq(pdata);
+	mdss_dsi_irq_ctrl(ctrl_pdata, 1, 0);
 	dsi_mdp_busy = true;
 	spin_unlock_irqrestore(&dsi_mdp_lock, flag);
 
@@ -1243,7 +1211,7 @@
 
 	spin_lock_irqsave(&dsi_mdp_lock, flag);
 	dsi_mdp_busy = false;
-	mdss_dsi_disable_irq(pdata);
+	mdss_dsi_irq_ctrl(ctrl_pdata, 0, 0);
 	spin_unlock_irqrestore(&dsi_mdp_lock, flag);
 
 	if (pdata->panel_info.mipi.no_max_pkt_size) {
@@ -1288,7 +1256,6 @@
 			struct mdss_panel_data *pdata)
 {
 	int len;
-	int i;
 	int domain = MDSS_IOMMU_DOMAIN_UNSECURE;
 	char *bp;
 	unsigned long size, addr;
@@ -1303,12 +1270,6 @@
 				panel_data);
 	bp = tp->data;
 
-	pr_debug("%s: ", __func__);
-	for (i = 0; i < tp->len; i++)
-		pr_debug("%x ", *bp++);
-
-	pr_debug("\n");
-
 	len = ALIGN(tp->len, 4);
 	size = ALIGN(tp->len, SZ_4K);
 
@@ -1495,6 +1456,8 @@
 			MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0110, isr0);
 		}
 
+	pr_debug("%s: isr=%x %x", __func__, isr, (int)DSI_INTR_ERROR);
+
 	if (isr & DSI_INTR_ERROR)
 		mdss_dsi_error(dsi_base);
 
@@ -1510,7 +1473,6 @@
 	if (isr & DSI_INTR_CMD_MDP_DONE) {
 		spin_lock(&dsi_mdp_lock);
 		dsi_mdp_busy = false;
-		mdss_dsi_disable_irq_nosync();
 		spin_unlock(&dsi_mdp_lock);
 	}
 
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
index 8d38737..d24ed16 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -13,11 +13,14 @@
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/of.h>
-#include <linux/qpnp/pin.h>
+#include <linux/of_gpio.h>
 #include <linux/gpio.h>
+#include <linux/qpnp/pin.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/leds.h>
+#include <linux/pwm.h>
+#include <linux/err.h>
 
 #include "mdss_dsi.h"
 
@@ -30,6 +33,64 @@
 
 static struct mdss_dsi_phy_ctrl phy_params;
 
+void mdss_dsi_panel_pwm_cfg(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+	int ret;
+
+	if (!gpio_is_valid(ctrl->pwm_gpio)) {
+		pr_err("%s: pwm_gpio=%d Invalid\n", __func__,
+				ctrl->pwm_gpio);
+		return;
+	}
+
+	ret = gpio_request(ctrl->pwm_gpio, "disp_pwm");
+	if (ret) {
+		pr_err("%s: pwm_gpio=%d request failed\n", __func__,
+				ctrl->pwm_gpio);
+		return;
+	}
+
+	ctrl->pwm_bl = pwm_request(ctrl->pwm_lpg_chan, "lcd-bklt");
+	if (ctrl->pwm_bl == NULL || IS_ERR(ctrl->pwm_bl)) {
+		pr_err("%s: lpg_chan=%d pwm request failed", __func__,
+				ctrl->pwm_lpg_chan);
+		gpio_free(ctrl->pwm_gpio);
+		ctrl->pwm_gpio = -1;
+	}
+}
+
+static void mdss_dsi_panel_bklt_pwm(struct mdss_dsi_ctrl_pdata *ctrl, int level)
+{
+	int ret;
+	u32 duty;
+
+	if (ctrl->pwm_bl == NULL) {
+		pr_err("%s: no PWM\n", __func__);
+		return;
+	}
+
+	duty = level * ctrl->pwm_period;
+	duty /= ctrl->bklt_max;
+
+	pr_debug("%s: bklt_ctrl=%d pwm_period=%d pwm_gpio=%d pwm_lpg_chan=%d\n",
+			__func__, ctrl->bklt_ctrl, ctrl->pwm_period,
+				ctrl->pwm_gpio, ctrl->pwm_lpg_chan);
+
+	pr_debug("%s: ndx=%d level=%d duty=%d\n", __func__,
+					ctrl->ndx, level, duty);
+
+	ret = pwm_config(ctrl->pwm_bl, duty, ctrl->pwm_period);
+	if (ret) {
+		pr_err("%s: pwm_config() failed err=%d.\n", __func__, ret);
+		return;
+	}
+
+	ret = pwm_enable(ctrl->pwm_bl);
+	if (ret)
+		pr_err("%s: pwm_enable() failed err=%d\n", __func__, ret);
+}
+
+
 void mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable)
 {
 	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
@@ -84,46 +145,51 @@
 	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
 				panel_data);
 
-	if (ctrl_pdata->bl_ctrl) {
-		switch (ctrl_pdata->bl_ctrl) {
-		case BL_WLED:
-			led_trigger_event(bl_led_trigger, bl_level);
-			break;
-
-		default:
-			pr_err("%s: Unknown bl_ctrl configuration\n",
-				__func__);
-			break;
-		}
-	} else
-		pr_err("%s:%d, bl_ctrl not configured", __func__, __LINE__);
+	switch (ctrl_pdata->bklt_ctrl) {
+	case BL_WLED:
+		led_trigger_event(bl_led_trigger, bl_level);
+		break;
+	case BL_PWM:
+		mdss_dsi_panel_bklt_pwm(ctrl_pdata, bl_level);
+		break;
+	default:
+		pr_err("%s: Unknown bl_ctrl configuration\n",
+			__func__);
+		break;
+	}
 }
 
+static char set_tear_on[2] = {0x35, 0x00};
+static struct dsi_cmd_desc dsi_tear_on_cmd = {
+	DTYPE_DCS_WRITE1, 1, 0, 0, 0, sizeof(set_tear_on), set_tear_on};
+
+static char set_tear_off[2] = {0x34, 0x00};
+static struct dsi_cmd_desc dsi_tear_off_cmd = {
+	DTYPE_DCS_WRITE, 1, 0, 0, 0, sizeof(set_tear_off), set_tear_off};
+
 static int mdss_dsi_panel_on(struct mdss_panel_data *pdata)
 {
 	struct mipi_panel_info *mipi;
-	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+	struct mdss_dsi_ctrl_pdata *ctrl = NULL;
 
 	if (pdata == NULL) {
 		pr_err("%s: Invalid input data\n", __func__);
 		return -EINVAL;
 	}
 
-	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+	ctrl = container_of(pdata, struct mdss_dsi_ctrl_pdata,
 				panel_data);
 	mipi  = &pdata->panel_info.mipi;
 
-	pr_debug("%s:%d, debug info (mode) : %d\n", __func__, __LINE__,
-		 mipi->mode);
+	pr_debug("%s: ctrl=%p ndx=%d\n", __func__, ctrl, ctrl->ndx);
 
-	if (mipi->mode == DSI_VIDEO_MODE) {
+	if (ctrl->on_cmds->size)
 		mdss_dsi_cmds_tx(pdata, &dsi_panel_tx_buf,
-				 ctrl_pdata->on_cmds->buf,
-				 ctrl_pdata->on_cmds->size);
-	} else {
-		pr_err("%s:%d, CMD MODE NOT SUPPORTED", __func__, __LINE__);
-		return -EINVAL;
-	}
+				 ctrl->on_cmds->buf,
+				 ctrl->on_cmds->size);
+
+	mdss_dsi_cmds_tx(pdata, &dsi_panel_tx_buf,
+			&dsi_tear_on_cmd, 1);
 
 	return 0;
 }
@@ -131,34 +197,33 @@
 static int mdss_dsi_panel_off(struct mdss_panel_data *pdata)
 {
 	struct mipi_panel_info *mipi;
-	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+	struct mdss_dsi_ctrl_pdata *ctrl = NULL;
 
 	if (pdata == NULL) {
 		pr_err("%s: Invalid input data\n", __func__);
 		return -EINVAL;
 	}
 
-	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+	ctrl = container_of(pdata, struct mdss_dsi_ctrl_pdata,
 				panel_data);
+
+	pr_debug("%s: ctrl=%p ndx=%d\n", __func__, ctrl, ctrl->ndx);
+
 	mipi  = &pdata->panel_info.mipi;
 
-	pr_debug("%s:%d, debug info\n", __func__, __LINE__);
+	mdss_dsi_cmds_tx(pdata, &dsi_panel_tx_buf,
+			&dsi_tear_off_cmd, 1);
 
-	if (mipi->mode == DSI_VIDEO_MODE) {
+	if (ctrl->off_cmds->size)
 		mdss_dsi_cmds_tx(pdata, &dsi_panel_tx_buf,
-				 ctrl_pdata->off_cmds->buf,
-				 ctrl_pdata->off_cmds->size);
-	} else {
-		pr_debug("%s:%d, CMD mode not supported", __func__, __LINE__);
-		return -EINVAL;
-	}
+				 ctrl->off_cmds->buf,
+				 ctrl->off_cmds->size);
 
 	return 0;
 }
 
 static int mdss_panel_parse_dt(struct platform_device *pdev,
-			       struct mdss_panel_common_pdata *panel_data,
-			       char *bl_ctrl)
+			       struct mdss_panel_common_pdata *panel_data)
 {
 	struct device_node *np = pdev->dev.of_node;
 	u32 res[6], tmp;
@@ -229,7 +294,32 @@
 	if ((bl_ctrl_type) && (!strncmp(bl_ctrl_type, "bl_ctrl_wled", 12))) {
 		led_trigger_register_simple("bkl-trigger", &bl_led_trigger);
 		pr_debug("%s: SUCCESS-> WLED TRIGGER register\n", __func__);
-		*bl_ctrl = BL_WLED;
+
+		panel_data->panel_info.bklt_ctrl = BL_WLED;
+	} else if (!strncmp(bl_ctrl_type, "bl_ctrl_pwm", 11)) {
+		panel_data->panel_info.bklt_ctrl = BL_PWM;
+
+		rc = of_property_read_u32(np, "qcom,dsi-pwm-period", &tmp);
+		if (rc) {
+			pr_err("%s:%d, Error, dsi pwm_period\n",
+						__func__, __LINE__);
+			return -EINVAL;
+		}
+		panel_data->panel_info.pwm_period = tmp;
+
+		rc = of_property_read_u32(np, "qcom,dsi-lpg-channel", &tmp);
+		if (rc) {
+			pr_err("%s:%d, Error, dsi lpg channel\n",
+						__func__, __LINE__);
+			return -EINVAL;
+		}
+		panel_data->panel_info.pwm_lpg_chan = tmp;
+
+		tmp = of_get_named_gpio(np, "qcom,dsi-pwm-gpio", 0);
+		panel_data->panel_info.pwm_gpio =  tmp;
+	} else {
+		pr_debug("%s: Unknown backlight control\n", __func__);
+		panel_data->panel_info.bklt_ctrl = UNKNOWN_CTRL;
 	}
 
 	rc = of_property_read_u32_array(np,
@@ -240,6 +330,13 @@
 	rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-mode", &tmp);
 	panel_data->panel_info.mipi.mode = (!rc ? tmp : DSI_VIDEO_MODE);
 
+	rc = of_property_read_u32(np, "qcom,mdss-vsync-enable", &tmp);
+	panel_data->panel_info.mipi.vsync_enable = (!rc ? tmp : 0);
+
+	rc = of_property_read_u32(np, "qcom,mdss-hw-vsync-mode", &tmp);
+	panel_data->panel_info.mipi.hw_vsync_mode = (!rc ? tmp : 0);
+
+
 	rc = of_property_read_u32(np,
 		"qcom,mdss-pan-dsi-h-pulse-mode", &tmp);
 	panel_data->panel_info.mipi.pulse_mode_hsa_he = (!rc ? tmp : false);
@@ -263,6 +360,26 @@
 			(!rc ? tmp : DSI_NON_BURST_SYNCH_PULSE);
 
 	rc = of_property_read_u32(np,
+		"qcom,mdss-pan-insert-dcs-cmd", &tmp);
+	panel_data->panel_info.mipi.insert_dcs_cmd =
+			(!rc ? tmp : 1);
+
+	rc = of_property_read_u32(np,
+		"qcom,mdss-pan-wr-mem-continue", &tmp);
+	panel_data->panel_info.mipi.wr_mem_continue =
+			(!rc ? tmp : 0x3c);
+
+	rc = of_property_read_u32(np,
+		"qcom,mdss-pan-wr-mem-start", &tmp);
+	panel_data->panel_info.mipi.wr_mem_start =
+			(!rc ? tmp : 0x2c);
+
+	rc = of_property_read_u32(np,
+		"qcom,mdss-pan-te-sel", &tmp);
+	panel_data->panel_info.mipi.te_sel =
+			(!rc ? tmp : 1);
+
+	rc = of_property_read_u32(np,
 		"qcom,mdss-pan-dsi-dst-format", &tmp);
 	panel_data->panel_info.mipi.dst_format =
 			(!rc ? tmp : DSI_VIDEO_DST_FORMAT_RGB888);
@@ -313,6 +430,9 @@
 	rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-frame-rate", &tmp);
 	panel_data->panel_info.mipi.frame_rate = (!rc ? tmp : 60);
 
+	rc = of_property_read_u32(np, "qcom,mdss-pan-clk-rate", &tmp);
+	panel_data->panel_info.clk_rate = (!rc ? tmp : 0);
+
 	data = of_get_property(np, "qcom,panel-phy-regulatorSettings", &len);
 	if ((!data) || (len != 7)) {
 		pr_err("%s:%d, Unable to read Phy regulator settings",
@@ -533,7 +653,6 @@
 	int rc = 0;
 	static struct mdss_panel_common_pdata vendor_pdata;
 	static const char *panel_name;
-	char bl_ctrl = UNKNOWN_CTRL;
 
 	pr_debug("%s:%d, debug info id=%d", __func__, __LINE__, pdev->id);
 	if (!pdev->dev.of_node)
@@ -546,7 +665,7 @@
 	else
 		pr_info("%s: Panel Name = %s\n", __func__, panel_name);
 
-	rc = mdss_panel_parse_dt(pdev, &vendor_pdata, &bl_ctrl);
+	rc = mdss_panel_parse_dt(pdev, &vendor_pdata);
 	if (rc)
 		return rc;
 
@@ -554,7 +673,7 @@
 	vendor_pdata.off = mdss_dsi_panel_off;
 	vendor_pdata.bl_fnc = mdss_dsi_panel_bl_ctrl;
 
-	rc = dsi_panel_device_register(pdev, &vendor_pdata, bl_ctrl);
+	rc = dsi_panel_device_register(pdev, &vendor_pdata);
 	if (rc)
 		return rc;
 
diff --git a/drivers/video/msm/mdss/mdss_edp.c b/drivers/video/msm/mdss/mdss_edp.c
index 6986117..aea2de0 100644
--- a/drivers/video/msm/mdss/mdss_edp.c
+++ b/drivers/video/msm/mdss/mdss_edp.c
@@ -363,7 +363,7 @@
 	case MDSS_EVENT_UNBLANK:
 		rc = mdss_edp_on(pdata);
 		break;
-	case MDSS_EVENT_TIMEGEN_OFF:
+	case MDSS_EVENT_PANEL_OFF:
 		rc = mdss_edp_off(pdata);
 		break;
 	}
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index b93efd9..6a96369 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -2539,7 +2539,7 @@
 				__func__, rc);
 		break;
 
-	case MDSS_EVENT_TIMEGEN_ON:
+	case MDSS_EVENT_PANEL_ON:
 		if (hdmi_ctrl->hdcp_feature_on && hdmi_ctrl->present_hdcp) {
 			DEV_DBG("%s: Starting HDCP authentication\n", __func__);
 			rc = hdmi_hdcp_authenticate(
@@ -2575,7 +2575,7 @@
 		}
 		break;
 
-	case MDSS_EVENT_TIMEGEN_OFF:
+	case MDSS_EVENT_PANEL_OFF:
 		hdmi_ctrl->timing_gen_on = false;
 		break;
 
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 217ac18..d92422c 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -1212,9 +1212,10 @@
 static int mdss_mdp_parse_dt_mixer(struct platform_device *pdev)
 {
 
-	u32 nmixers, ndspp;
+	u32 nmixers, ndspp, npingpong;
 	int rc = 0;
-	u32 *mixer_offsets = NULL, *dspp_offsets = NULL;
+	u32 *mixer_offsets = NULL, *dspp_offsets = NULL,
+	    *pingpong_offsets = NULL;
 
 	struct mdss_data_type *mdata = platform_get_drvdata(pdev);
 
@@ -1224,6 +1225,8 @@
 				"qcom,mdss-mixer-wb-off");
 	ndspp = mdss_mdp_parse_dt_prop_len(pdev,
 				"qcom,mdss-dspp-off");
+	npingpong = mdss_mdp_parse_dt_prop_len(pdev,
+				"qcom,mdss-pingpong-off");
 	nmixers = mdata->nmixers_intf + mdata->nmixers_wb;
 
 	if (mdata->nmixers_intf != ndspp) {
@@ -1231,6 +1234,11 @@
 		return -EINVAL;
 	}
 
+	if (mdata->nmixers_intf != npingpong) {
+		pr_err("device tree err: unequal no of pingpong and intf mixers\n");
+		return -EINVAL;
+	}
+
 	mixer_offsets = kzalloc(sizeof(u32) * nmixers, GFP_KERNEL);
 	if (!mixer_offsets) {
 		pr_err("no mem assigned: kzalloc fail\n");
@@ -1243,6 +1251,12 @@
 		rc = -ENOMEM;
 		goto dspp_alloc_fail;
 	}
+	pingpong_offsets = kzalloc(sizeof(u32) * npingpong, GFP_KERNEL);
+	if (!pingpong_offsets) {
+		pr_err("no mem assigned: kzalloc fail\n");
+		rc = -ENOMEM;
+		goto pingpong_alloc_fail;
+	}
 
 	rc = mdss_mdp_parse_dt_handler(pdev, "qcom,mdss-mixer-intf-off",
 		mixer_offsets, mdata->nmixers_intf);
@@ -1259,19 +1273,26 @@
 	if (rc)
 		goto parse_done;
 
+	rc = mdss_mdp_parse_dt_handler(pdev, "qcom,mdss-pingpong-off",
+		pingpong_offsets, npingpong);
+	if (rc)
+		goto parse_done;
+
 	rc = mdss_mdp_mixer_addr_setup(mdata, mixer_offsets,
-			dspp_offsets, MDSS_MDP_MIXER_TYPE_INTF,
-			mdata->nmixers_intf);
+			dspp_offsets, pingpong_offsets,
+			MDSS_MDP_MIXER_TYPE_INTF, mdata->nmixers_intf);
 	if (rc)
 		goto parse_done;
 
 	rc = mdss_mdp_mixer_addr_setup(mdata, mixer_offsets +
-			mdata->nmixers_intf, NULL,
+			mdata->nmixers_intf, NULL, NULL,
 			MDSS_MDP_MIXER_TYPE_WRITEBACK, mdata->nmixers_wb);
 	if (rc)
 		goto parse_done;
 
 parse_done:
+	kfree(pingpong_offsets);
+pingpong_alloc_fail:
 	kfree(dspp_offsets);
 dspp_alloc_fail:
 	kfree(mixer_offsets);
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 14c1e52..8af3cc0 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -156,6 +156,7 @@
 	u32 ref_cnt;
 	char __iomem *base;
 	char __iomem *dspp_base;
+	char __iomem *pingpong_base;
 	u8 type;
 	u8 params_changed;
 	u16 width;
@@ -295,6 +296,17 @@
 	return readl_relaxed(ctl->base + reg);
 }
 
+static inline void mdss_mdp_pingpong_write(struct mdss_mdp_mixer *mixer,
+				      u32 reg, u32 val)
+{
+	writel_relaxed(val, mixer->pingpong_base + reg);
+}
+
+static inline u32 mdss_mdp_pingpong_read(struct mdss_mdp_mixer *mixer, u32 reg)
+{
+	return readl_relaxed(mixer->pingpong_base + reg);
+}
+
 irqreturn_t mdss_mdp_isr(int irq, void *ptr);
 int mdss_iommu_attach(struct mdss_data_type *mdata);
 int mdss_mdp_copy_splash_screen(struct mdss_panel_data *pdata);
@@ -319,6 +331,7 @@
 int mdss_mdp_video_addr_setup(struct mdss_data_type *mdata,
 		u32 *offsets,  u32 count);
 int mdss_mdp_video_start(struct mdss_mdp_ctl *ctl);
+int mdss_mdp_cmd_start(struct mdss_mdp_ctl *ctl);
 int mdss_mdp_writeback_start(struct mdss_mdp_ctl *ctl);
 int mdss_mdp_overlay_kickoff(struct mdss_mdp_ctl *ctl);
 
@@ -400,7 +413,7 @@
 int mdss_mdp_pipe_addr_setup(struct mdss_data_type *mdata, u32 *offsets,
 		u32 *ftch_y_id, u32 type, u32 num_base, u32 len);
 int mdss_mdp_mixer_addr_setup(struct mdss_data_type *mdata, u32 *mixer_offsets,
-		u32 *dspp_offsets, u32 type, u32 len);
+		u32 *dspp_offsets, u32 *pingpong_offsets, u32 type, u32 len);
 int mdss_mdp_ctl_addr_setup(struct mdss_data_type *mdata, u32 *ctl_offsets,
 		u32 *wb_offsets, u32 len);
 
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index e850321..66e1a0c 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -599,6 +599,15 @@
 		ctl->opmode = MDSS_MDP_CTL_OP_VIDEO_MODE;
 		ctl->start_fnc = mdss_mdp_video_start;
 		break;
+	case MIPI_CMD_PANEL:
+		if (pdata->panel_info.pdest == DISPLAY_1)
+			ctl->intf_num = MDSS_MDP_INTF1;
+		else
+			ctl->intf_num = MDSS_MDP_INTF2;
+		ctl->intf_type = MDSS_INTF_DSI;
+		ctl->opmode = MDSS_MDP_CTL_OP_CMD_MODE;
+		ctl->start_fnc = mdss_mdp_cmd_start;
+		break;
 	case DTV_PANEL:
 		ctl->intf_num = MDSS_MDP_INTF3;
 		ctl->intf_type = MDSS_INTF_HDMI;
@@ -1032,7 +1041,8 @@
 }
 
 int mdss_mdp_mixer_addr_setup(struct mdss_data_type *mdata,
-	 u32 *mixer_offsets, u32 *dspp_offsets, u32 type, u32 len)
+	 u32 *mixer_offsets, u32 *dspp_offsets, u32 *pingpong_offsets,
+	 u32 type, u32 len)
 {
 	struct mdss_mdp_mixer *head;
 	u32 i;
@@ -1052,8 +1062,11 @@
 		head[i].base = mdata->mdp_base + mixer_offsets[i];
 		head[i].ref_cnt = 0;
 		head[i].num = i;
-		if (type == MDSS_MDP_MIXER_TYPE_INTF)
+		if (type == MDSS_MDP_MIXER_TYPE_INTF) {
 			head[i].dspp_base = mdata->mdp_base + dspp_offsets[i];
+			head[i].pingpong_base = mdata->mdp_base +
+				pingpong_offsets[i];
+		}
 	}
 
 	switch (type) {
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
index 18c38a0..bf78c61 100644
--- a/drivers/video/msm/mdss/mdss_mdp_hwio.h
+++ b/drivers/video/msm/mdss/mdss_mdp_hwio.h
@@ -431,8 +431,6 @@
 	MDSS_MDP_MAX_PINGPONG
 };
 
-#define MDSS_MDP_REG_PP_OFFSET(pp)	(0x21B00 + ((pp) * 0x100))
-
 #define MDSS_MDP_REG_PP_TEAR_CHECK_EN			0x000
 #define MDSS_MDP_REG_PP_SYNC_CONFIG_VSYNC		0x004
 #define MDSS_MDP_REG_PP_SYNC_CONFIG_HEIGHT		0x008
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
new file mode 100644
index 0000000..d6b0fb2
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
@@ -0,0 +1,333 @@
+/* Copyright (c) 2013, The Linux Foundation. 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/kernel.h>
+#include "mdss_panel.h"
+#include "mdss_mdp.h"
+
+#define START_THRESHOLD 4
+#define CONTINUE_TRESHOLD 4
+
+#define MAX_SESSIONS 2
+
+struct mdss_mdp_cmd_ctx {
+	u32 pp_num;
+	u8 ref_cnt;
+
+	struct completion pp_comp;
+	atomic_t vsync_ref;
+	spinlock_t vsync_lock;
+	mdp_vsync_handler_t vsync_handler;
+	int panel_on;
+
+	/* te config */
+	u8 tear_check;
+	u16 total_lcd_lines;
+	u16 v_porch;	/* vertical porches */
+	u32 vsync_cnt;
+};
+
+struct mdss_mdp_cmd_ctx mdss_mdp_cmd_ctx_list[MAX_SESSIONS];
+
+static int mdss_mdp_cmd_tearcheck_cfg(struct mdss_mdp_mixer *mixer,
+			struct mdss_mdp_cmd_ctx *ctx, int enable)
+{
+	u32 cfg;
+
+	cfg = BIT(19); /* VSYNC_COUNTER_EN */
+	if (ctx->tear_check)
+		cfg |= BIT(20);	/* VSYNC_IN_EN */
+	cfg |= ctx->vsync_cnt;
+
+	mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_SYNC_CONFIG_VSYNC, cfg);
+	mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_SYNC_CONFIG_HEIGHT,
+				0xfff0); /* set to verh height */
+	mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_VSYNC_INIT_VAL, 0);
+	mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_RD_PTR_IRQ, 0);
+
+	mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_START_POS, ctx->v_porch);
+	mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_SYNC_THRESH,
+			   (CONTINUE_TRESHOLD << 16) | (START_THRESHOLD));
+
+	mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_TEAR_CHECK_EN, enable);
+	return 0;
+}
+
+static int mdss_mdp_cmd_tearcheck_setup(struct mdss_mdp_ctl *ctl, int enable)
+{
+	struct mdss_mdp_cmd_ctx *ctx = ctl->priv_data;
+	struct mdss_panel_info *pinfo;
+	struct mdss_mdp_mixer *mixer;
+
+	pinfo = &ctl->panel_data->panel_info;
+
+	if (pinfo->mipi.vsync_enable && enable) {
+		u32 mdp_vsync_clk_speed_hz, total_lines;
+		u32 vsync_cnt_cfg_dem;
+
+		mdss_mdp_vsync_clk_enable(1);
+
+		mdp_vsync_clk_speed_hz =
+		mdss_mdp_get_clk_rate(MDSS_CLK_MDP_VSYNC);
+		pr_debug("%s: vsync_clk_rate=%d\n", __func__,
+					mdp_vsync_clk_speed_hz);
+
+		if (mdp_vsync_clk_speed_hz == 0) {
+			pr_err("can't get clk speed\n");
+			return -EINVAL;
+		}
+
+		ctx->tear_check = pinfo->mipi.hw_vsync_mode;
+
+		total_lines = pinfo->lcdc.v_back_porch +
+				    pinfo->lcdc.v_front_porch +
+				    pinfo->lcdc.v_pulse_width + pinfo->yres;
+
+		vsync_cnt_cfg_dem =
+			mult_frac(pinfo->mipi.frame_rate * total_lines,
+						1, 100);
+
+		ctx->vsync_cnt = mdp_vsync_clk_speed_hz / vsync_cnt_cfg_dem;
+
+		ctx->v_porch = pinfo->lcdc.v_back_porch +
+				    pinfo->lcdc.v_front_porch +
+				    pinfo->lcdc.v_pulse_width;
+		ctx->total_lcd_lines = total_lines;
+	} else {
+		enable = 0;
+	}
+
+	mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_LEFT);
+	if (mixer)
+		mdss_mdp_cmd_tearcheck_cfg(mixer, ctx, enable);
+
+	mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_RIGHT);
+	if (mixer)
+		mdss_mdp_cmd_tearcheck_cfg(mixer, ctx, enable);
+
+	return 0;
+}
+
+static inline void cmd_readptr_irq_enable(struct mdss_mdp_ctl *ctl)
+{
+	struct mdss_mdp_cmd_ctx *ctx = ctl->priv_data;
+
+	if (atomic_inc_return(&ctx->vsync_ref) == 1) {
+		pr_debug("%s:\n", __func__);
+		mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_RD_PTR, ctx->pp_num);
+	}
+}
+
+static inline void cmd_readptr_irq_disable(struct mdss_mdp_ctl *ctl)
+{
+	struct mdss_mdp_cmd_ctx *ctx = ctl->priv_data;
+
+	if (atomic_dec_return(&ctx->vsync_ref) == 0) {
+		pr_debug("%s:\n", __func__);
+		mdss_mdp_irq_disable(MDSS_MDP_IRQ_PING_PONG_RD_PTR,
+							ctx->pp_num);
+	}
+}
+
+int mdss_mdp_cmd_set_vsync_handler(struct mdss_mdp_ctl *ctl,
+		mdp_vsync_handler_t vsync_handler)
+{
+	struct mdss_mdp_cmd_ctx *ctx;
+	unsigned long flags;
+
+	ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
+	if (!ctx) {
+		pr_err("invalid ctx for ctl=%d\n", ctl->num);
+		return -ENODEV;
+	}
+
+	spin_lock_irqsave(&ctx->vsync_lock, flags);
+
+	if (!ctx->vsync_handler && vsync_handler) {
+		ctx->vsync_handler = vsync_handler;
+		cmd_readptr_irq_enable(ctl);
+	} else if (ctx->vsync_handler && !vsync_handler) {
+		cmd_readptr_irq_disable(ctl);
+		ctx->vsync_handler = vsync_handler;
+	}
+
+	spin_unlock_irqrestore(&ctx->vsync_lock, flags);
+
+	return 0;
+}
+
+static void mdss_mdp_cmd_readptr_done(void *arg)
+{
+	struct mdss_mdp_ctl *ctl = arg;
+	struct mdss_mdp_cmd_ctx *ctx = ctl->priv_data;
+	ktime_t vsync_time;
+
+	if (!ctx) {
+		pr_err("invalid ctx\n");
+		return;
+	}
+
+	pr_debug("%s: ctl=%d intf_num=%d\n", __func__, ctl->num, ctl->intf_num);
+
+	vsync_time = ktime_get();
+
+	spin_lock(&ctx->vsync_lock);
+	if (ctx->vsync_handler)
+		ctx->vsync_handler(ctl, vsync_time);
+	spin_unlock(&ctx->vsync_lock);
+}
+
+static void mdss_mdp_cmd_pingpong_done(void *arg)
+{
+	struct mdss_mdp_ctl *ctl = arg;
+	struct mdss_mdp_cmd_ctx *ctx = ctl->priv_data;
+
+	pr_debug("%s: intf_num=%d ctx=%p\n", __func__, ctl->intf_num, ctx);
+
+	mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num);
+
+	if (ctx)
+		complete(&ctx->pp_comp);
+}
+
+int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg)
+{
+	struct mdss_mdp_cmd_ctx *ctx;
+	int rc;
+
+	ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
+	pr_debug("%s: kickoff intf_num=%d ctx=%p\n", __func__,
+					ctl->intf_num, ctx);
+
+	if (!ctx) {
+		pr_err("invalid ctx\n");
+		return -ENODEV;
+	}
+
+	if (ctx->panel_on == 0) {
+		rc = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_UNBLANK, NULL);
+		WARN(rc, "intf %d unblank error (%d)\n", ctl->intf_num, rc);
+
+		ctx->panel_on++;
+
+		rc = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_PANEL_ON, NULL);
+		WARN(rc, "intf %d panel on error (%d)\n", ctl->intf_num, rc);
+	}
+
+	INIT_COMPLETION(ctx->pp_comp);
+	mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num);
+
+	mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_START, 1);
+
+	wait_for_completion_interruptible(&ctx->pp_comp);
+
+	return 0;
+}
+
+int mdss_mdp_cmd_stop(struct mdss_mdp_ctl *ctl)
+{
+	struct mdss_mdp_cmd_ctx *ctx;
+	int ret;
+
+	pr_debug("%s: +\n", __func__);
+
+	ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
+	if (!ctx) {
+		pr_err("invalid ctx\n");
+		return -ENODEV;
+	}
+
+	ctx->panel_on = 0;
+
+	mdss_mdp_cmd_set_vsync_handler(ctl, NULL);
+
+	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_RD_PTR, ctl->intf_num,
+				   NULL, NULL);
+	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num,
+				   NULL, NULL);
+
+	memset(ctx, 0, sizeof(*ctx));
+	ctl->priv_data = NULL;
+
+	ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_BLANK, NULL);
+	WARN(ret, "intf %d unblank error (%d)\n", ctl->intf_num, ret);
+
+	ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_PANEL_OFF, NULL);
+	WARN(ret, "intf %d unblank error (%d)\n", ctl->intf_num, ret);
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+	pr_debug("%s:-\n", __func__);
+
+	return 0;
+}
+
+int mdss_mdp_cmd_start(struct mdss_mdp_ctl *ctl)
+{
+	struct mdss_mdp_cmd_ctx *ctx;
+	struct mdss_mdp_mixer *mixer;
+	int i, ret;
+
+	pr_debug("%s:+\n", __func__);
+
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+
+	mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_LEFT);
+	if (!mixer) {
+		pr_err("mixer not setup correctly\n");
+		return -ENODEV;
+	}
+
+	for (i = 0; i < MAX_SESSIONS; i++) {
+		ctx = &mdss_mdp_cmd_ctx_list[i];
+		if (ctx->ref_cnt == 0) {
+			ctx->ref_cnt++;
+			break;
+		}
+	}
+	if (i == MAX_SESSIONS) {
+		pr_err("too many sessions\n");
+		return -ENOMEM;
+	}
+
+	ctl->priv_data = ctx;
+	if (!ctx) {
+		pr_err("invalid ctx\n");
+		return -ENODEV;
+	}
+
+	ctx->pp_num = mixer->num;
+	init_completion(&ctx->pp_comp);
+	spin_lock_init(&ctx->vsync_lock);
+	atomic_set(&ctx->vsync_ref, 0);
+
+	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_RD_PTR, ctx->pp_num,
+				   mdss_mdp_cmd_readptr_done, ctl);
+
+	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num,
+				   mdss_mdp_cmd_pingpong_done, ctl);
+
+	ret = mdss_mdp_cmd_tearcheck_setup(ctl, 1);
+	if (ret) {
+		pr_err("tearcheck setup failed\n");
+		return ret;
+	}
+
+	ctl->stop_fnc = mdss_mdp_cmd_stop;
+	ctl->display_fnc = mdss_mdp_cmd_kickoff;
+	ctl->set_vsync_handler = mdss_mdp_cmd_set_vsync_handler;
+
+	pr_debug("%s:-\n", __func__);
+
+	return 0;
+}
+
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index dab8674..e7f70b6 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -242,7 +242,7 @@
 		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 		ctx->timegen_en = false;
 
-		rc = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_TIMEGEN_OFF, NULL);
+		rc = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_PANEL_OFF, NULL);
 		WARN(rc, "intf %d timegen off error (%d)\n", ctl->intf_num, rc);
 
 		mdss_mdp_irq_disable(MDSS_MDP_IRQ_INTF_UNDER_RUN,
@@ -359,8 +359,8 @@
 				rc, ctl->num);
 
 		ctx->timegen_en = true;
-		rc = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_TIMEGEN_ON, NULL);
-		WARN(rc, "intf %d timegen on error (%d)\n", ctl->intf_num, rc);
+		rc = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_PANEL_ON, NULL);
+		WARN(rc, "intf %d panel on error (%d)\n", ctl->intf_num, rc);
 	}
 
 	return 0;
diff --git a/drivers/video/msm/mdss/mdss_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c
index b54e0ec..8ce5ab5 100644
--- a/drivers/video/msm/mdss/mdss_mdp_util.c
+++ b/drivers/video/msm/mdss/mdss_mdp_util.c
@@ -42,6 +42,9 @@
 	MDP_INTR_PING_PONG_0,
 	MDP_INTR_PING_PONG_1,
 	MDP_INTR_PING_PONG_2,
+	MDP_INTR_PING_PONG_0_RD_PTR,
+	MDP_INTR_PING_PONG_1_RD_PTR,
+	MDP_INTR_PING_PONG_2_RD_PTR,
 	MDP_INTR_WB_0,
 	MDP_INTR_WB_1,
 	MDP_INTR_WB_2,
@@ -69,6 +72,9 @@
 	case MDSS_MDP_IRQ_PING_PONG_COMP:
 		index = MDP_INTR_PING_PONG_0 + intf_num;
 		break;
+	case MDSS_MDP_IRQ_PING_PONG_RD_PTR:
+		index = MDP_INTR_PING_PONG_0_RD_PTR + intf_num;
+		break;
 	case MDSS_MDP_IRQ_WB_ROT_COMP:
 		index = MDP_INTR_WB_0 + intf_num;
 		break;
@@ -126,11 +132,12 @@
 	if (isr == 0)
 		goto mdp_isr_done;
 
-	pr_debug("isr=%x\n", isr);
 
 	mask = MDSS_MDP_REG_READ(MDSS_MDP_REG_INTR_EN);
 	MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_CLEAR, isr);
 
+	pr_debug("%s: isr=%x mask=%x\n", __func__, isr, mask);
+
 	isr &= mask;
 	if (isr == 0)
 		goto mdp_isr_done;
@@ -156,6 +163,15 @@
 	if (isr & MDSS_MDP_INTR_PING_PONG_2_DONE)
 		mdss_mdp_intr_done(MDP_INTR_PING_PONG_2);
 
+	if (isr & MDSS_MDP_INTR_PING_PONG_0_RD_PTR)
+		mdss_mdp_intr_done(MDP_INTR_PING_PONG_0_RD_PTR);
+
+	if (isr & MDSS_MDP_INTR_PING_PONG_1_RD_PTR)
+		mdss_mdp_intr_done(MDP_INTR_PING_PONG_1_RD_PTR);
+
+	if (isr & MDSS_MDP_INTR_PING_PONG_2_RD_PTR)
+		mdss_mdp_intr_done(MDP_INTR_PING_PONG_2_RD_PTR);
+
 	if (isr & MDSS_MDP_INTR_INTF_0_VSYNC)
 		mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_0);
 
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index 31fb2e7..23f7445 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -58,9 +58,9 @@
 enum mdss_intf_events {
 	MDSS_EVENT_RESET,
 	MDSS_EVENT_UNBLANK,
-	MDSS_EVENT_TIMEGEN_ON,
+	MDSS_EVENT_PANEL_ON,
 	MDSS_EVENT_BLANK,
-	MDSS_EVENT_TIMEGEN_OFF,
+	MDSS_EVENT_PANEL_OFF,
 	MDSS_EVENT_CLOSE,
 	MDSS_EVENT_SUSPEND,
 	MDSS_EVENT_RESUME,
@@ -69,19 +69,7 @@
 	MDSS_EVENT_FB_REGISTERED,
 };
 
-/* panel info type */
 struct lcd_panel_info {
-	u32 vsync_enable;
-	u32 refx100;
-	u32 v_back_porch;
-	u32 v_front_porch;
-	u32 v_pulse_width;
-	u32 hw_vsync_mode;
-	u32 vsync_notifier_period;
-	u32 rev;
-};
-
-struct lcdc_panel_info {
 	u32 h_back_porch;
 	u32 h_front_porch;
 	u32 h_pulse_width;
@@ -153,6 +141,9 @@
 	char no_max_pkt_size;
 	/* Clock required during LP commands */
 	char force_clk_lane_hs;
+
+	char vsync_enable;
+	char hw_vsync_mode;
 };
 
 enum lvds_mode {
@@ -183,13 +174,16 @@
 	u32 is_3d_panel;
 	u32 out_format;
 	u32 vic; /* video identification code */
+	int bklt_ctrl;	/* backlight ctrl */
+	int pwm_gpio;
+	int pwm_lpg_chan;
+	int pwm_period;
 
 	u32 cont_splash_enabled;
 	struct ion_handle *splash_ihdl;
 	u32 panel_power_on;
 
-	struct lcd_panel_info lcd;
-	struct lcdc_panel_info lcdc;
+	struct lcd_panel_info lcdc;
 	struct mipi_panel_info mipi;
 	struct lvds_panel_info lvds;
 };
diff --git a/include/linux/ion.h b/include/linux/ion.h
index fb1c5f6..7c54004 100644
--- a/include/linux/ion.h
+++ b/include/linux/ion.h
@@ -59,6 +59,9 @@
 					   cached, ion will do cache
 					   maintenance when the buffer is
 					   mapped for dma */
+#define ION_FLAG_CACHED_NEEDS_SYNC 2	/* mappings of this buffer will created
+					   at mmap time, if this is set
+					   caches must be managed manually */
 
 #ifdef __KERNEL__
 #include <linux/err.h>
@@ -606,6 +609,16 @@
 #define ION_IOC_IMPORT		_IOWR(ION_IOC_MAGIC, 5, struct ion_fd_data)
 
 /**
+ * DOC: ION_IOC_SYNC - syncs a shared file descriptors to memory
+ *
+ * Deprecated in favor of using the dma_buf api's correctly (syncing
+ * will happend automatically when the buffer is mapped to a device).
+ * If necessary should be used after touching a cached buffer from the cpu,
+ * this will make the buffer in memory coherent.
+ */
+#define ION_IOC_SYNC		_IOWR(ION_IOC_MAGIC, 7, struct ion_fd_data)
+
+/**
  * DOC: ION_IOC_CUSTOM - call architecture specific ion ioctl
  *
  * Takes the argument of the architecture specific ioctl to call and
diff --git a/include/linux/mfd/pm8xxx/pm8921-bms.h b/include/linux/mfd/pm8xxx/pm8921-bms.h
index 9461c76..5e6a8c3 100644
--- a/include/linux/mfd/pm8xxx/pm8921-bms.h
+++ b/include/linux/mfd/pm8xxx/pm8921-bms.h
@@ -46,6 +46,14 @@
  * @ocv_dis_low_soc:		the low soc percent when ocv should be enabled
  * @low_voltage_detect:		feature to enable 0 SOC reporting on low volatge
  * @vbatt_cutoff_retries:	number of tries before we report a 0 SOC
+ * @high_ocv_correction_limit_uv:	the max amount of OCV corrections
+ *					allowed when ocv is high
+ *					(higher than 3.8V)
+ * @low_ocv_correction_limit_uv:	the max amount of OCV corrections
+ *					allowed when ocv is low
+ *					(lower or equal to 3.8V)
+ * @hold_soc_est:		the min est soc below which the calculated soc
+ *				is allowed to go to 0%
  */
 struct pm8921_bms_platform_data {
 	struct pm8xxx_bms_core_data	bms_cdata;
@@ -69,6 +77,9 @@
 	int				ocv_dis_low_soc;
 	int				low_voltage_detect;
 	int				vbatt_cutoff_retries;
+	int				high_ocv_correction_limit_uv;
+	int				low_ocv_correction_limit_uv;
+	int				hold_soc_est;
 };
 
 #if defined(CONFIG_PM8921_BMS) || defined(CONFIG_PM8921_BMS_MODULE)
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 0ab5143..84e099d 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -1704,9 +1704,14 @@
  * @__NL80211_RATE_INFO_INVALID: attribute number 0 is reserved
  * @NL80211_RATE_INFO_BITRATE: total bitrate (u16, 100kbit/s)
  * @NL80211_RATE_INFO_MCS: mcs index for 802.11n (u8)
- * @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 Mhz dualchannel bitrate
+ * @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 MHz dualchannel bitrate
  * @NL80211_RATE_INFO_SHORT_GI: 400ns guard interval
  * @NL80211_RATE_INFO_MAX: highest rate_info number currently defined
+ * @NL80211_RATE_INFO_VHT_MCS: MCS index for VHT (u8)
+ * @NL80211_RATE_INFO_VHT_NSS: number of streams in VHT (u8)
+ * @NL80211_RATE_INFO_80_MHZ_WIDTH: 80 MHz VHT rate
+ * @NL80211_RATE_INFO_80P80_MHZ_WIDTH: 80+80 MHz VHT rate
+ * @NL80211_RATE_INFO_160_MHZ_WIDTH: 160 MHz VHT rate
  * @__NL80211_RATE_INFO_AFTER_LAST: internal use
  */
 enum nl80211_rate_info {
@@ -1715,6 +1720,11 @@
 	NL80211_RATE_INFO_MCS,
 	NL80211_RATE_INFO_40_MHZ_WIDTH,
 	NL80211_RATE_INFO_SHORT_GI,
+	NL80211_RATE_INFO_VHT_MCS,
+	NL80211_RATE_INFO_VHT_NSS,
+	NL80211_RATE_INFO_80_MHZ_WIDTH,
+	NL80211_RATE_INFO_80P80_MHZ_WIDTH,
+	NL80211_RATE_INFO_160_MHZ_WIDTH,
 
 	/* keep last */
 	__NL80211_RATE_INFO_AFTER_LAST,
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 52811ae..bfa0eca 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -578,14 +578,24 @@
  * Used by the driver to indicate the specific rate transmission
  * type for 802.11n transmissions.
  *
- * @RATE_INFO_FLAGS_MCS: @tx_bitrate_mcs filled
- * @RATE_INFO_FLAGS_40_MHZ_WIDTH: 40 Mhz width transmission
+ * @RATE_INFO_FLAGS_MCS: mcs field filled with HT MCS
+ * @RATE_INFO_FLAGS_VHT_MCS: mcs field filled with VHT MCS
+ * @RATE_INFO_FLAGS_40_MHZ_WIDTH: 40 MHz width transmission
+ * @RATE_INFO_FLAGS_80_MHZ_WIDTH: 80 MHz width transmission
+ * @RATE_INFO_FLAGS_80P80_MHZ_WIDTH: 80+80 MHz width transmission
+ * @RATE_INFO_FLAGS_160_MHZ_WIDTH: 160 MHz width transmission
  * @RATE_INFO_FLAGS_SHORT_GI: 400ns guard interval
+ * @RATE_INFO_FLAGS_60G: 60GHz MCS
  */
 enum rate_info_flags {
-	RATE_INFO_FLAGS_MCS		= 1<<0,
-	RATE_INFO_FLAGS_40_MHZ_WIDTH	= 1<<1,
-	RATE_INFO_FLAGS_SHORT_GI	= 1<<2,
+	RATE_INFO_FLAGS_MCS			= BIT(0),
+	RATE_INFO_FLAGS_VHT_MCS			= BIT(1),
+	RATE_INFO_FLAGS_40_MHZ_WIDTH		= BIT(2),
+	RATE_INFO_FLAGS_80_MHZ_WIDTH		= BIT(3),
+	RATE_INFO_FLAGS_80P80_MHZ_WIDTH		= BIT(4),
+	RATE_INFO_FLAGS_160_MHZ_WIDTH		= BIT(5),
+	RATE_INFO_FLAGS_SHORT_GI		= BIT(6),
+	RATE_INFO_FLAGS_60G			= BIT(7),
 };
 
 /**
@@ -596,11 +606,13 @@
  * @flags: bitflag of flags from &enum rate_info_flags
  * @mcs: mcs index if struct describes a 802.11n bitrate
  * @legacy: bitrate in 100kbit/s for 802.11abg
+ * @nss: number of streams (VHT only)
  */
 struct rate_info {
 	u8 flags;
 	u8 mcs;
 	u16 legacy;
+	u8 nss;
 };
 
 /**
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 69318b0..5097036 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -2384,25 +2384,46 @@
 
 	rate = nla_nest_start(msg, attr);
 	if (!rate)
-		goto nla_put_failure;
+		return false;
 
 	/* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */
 	bitrate = cfg80211_calculate_bitrate(info);
 	if (bitrate > 0)
-		NLA_PUT_U16(msg, NL80211_RATE_INFO_BITRATE, bitrate);
+		nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate);
 
-	if (info->flags & RATE_INFO_FLAGS_MCS)
-		NLA_PUT_U8(msg, NL80211_RATE_INFO_MCS, info->mcs);
-	if (info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH)
-		NLA_PUT_FLAG(msg, NL80211_RATE_INFO_40_MHZ_WIDTH);
-	if (info->flags & RATE_INFO_FLAGS_SHORT_GI)
-		NLA_PUT_FLAG(msg, NL80211_RATE_INFO_SHORT_GI);
+	if (info->flags & RATE_INFO_FLAGS_MCS) {
+		if (nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs))
+			return false;
+		if (info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH &&
+		    nla_put_flag(msg, NL80211_RATE_INFO_40_MHZ_WIDTH))
+			return false;
+		if (info->flags & RATE_INFO_FLAGS_SHORT_GI &&
+		    nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))
+			return false;
+	} else if (info->flags & RATE_INFO_FLAGS_VHT_MCS) {
+		if (nla_put_u8(msg, NL80211_RATE_INFO_VHT_MCS, info->mcs))
+			return false;
+		if (nla_put_u8(msg, NL80211_RATE_INFO_VHT_NSS, info->nss))
+			return false;
+		if (info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH &&
+		    nla_put_flag(msg, NL80211_RATE_INFO_40_MHZ_WIDTH))
+			return false;
+		if (info->flags & RATE_INFO_FLAGS_80_MHZ_WIDTH &&
+		    nla_put_flag(msg, NL80211_RATE_INFO_80_MHZ_WIDTH))
+			return false;
+		if (info->flags & RATE_INFO_FLAGS_80P80_MHZ_WIDTH &&
+		    nla_put_flag(msg, NL80211_RATE_INFO_80P80_MHZ_WIDTH))
+			return false;
+		if (info->flags & RATE_INFO_FLAGS_160_MHZ_WIDTH &&
+		    nla_put_flag(msg, NL80211_RATE_INFO_160_MHZ_WIDTH))
+			return false;
+		if (info->flags & RATE_INFO_FLAGS_SHORT_GI &&
+		    nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))
+			return false;
+	}
 
 	nla_nest_end(msg, rate);
 	return true;
-
-nla_put_failure:
-	return false;
 }
 
 static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 017d4fc..b89fb94 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -876,13 +876,86 @@
 	return err;
 }
 
+static u32 cfg80211_calculate_bitrate_vht(struct rate_info *rate)
+{
+	static const u32 base[4][10] = {
+		{   6500000,
+		   13000000,
+		   19500000,
+		   26000000,
+		   39000000,
+		   52000000,
+		   58500000,
+		   65000000,
+		   78000000,
+		   0,
+		},
+		{  13500000,
+		   27000000,
+		   40500000,
+		   54000000,
+		   81000000,
+		  108000000,
+		  121500000,
+		  135000000,
+		  162000000,
+		  180000000,
+		},
+		{  29300000,
+		   58500000,
+		   87800000,
+		  117000000,
+		  175500000,
+		  234000000,
+		  263300000,
+		  292500000,
+		  351000000,
+		  390000000,
+		},
+		{  58500000,
+		  117000000,
+		  175500000,
+		  234000000,
+		  351000000,
+		  468000000,
+		  526500000,
+		  585000000,
+		  702000000,
+		  780000000,
+		},
+	};
+	u32 bitrate;
+	int idx;
+
+	if (WARN_ON_ONCE(rate->mcs > 9))
+		return 0;
+
+	idx = rate->flags & (RATE_INFO_FLAGS_160_MHZ_WIDTH |
+			     RATE_INFO_FLAGS_80P80_MHZ_WIDTH) ? 3 :
+		  rate->flags & RATE_INFO_FLAGS_80_MHZ_WIDTH ? 2 :
+		  rate->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH ? 1 : 0;
+
+	bitrate = base[idx][rate->mcs];
+	bitrate *= rate->nss;
+
+	if (rate->flags & RATE_INFO_FLAGS_SHORT_GI)
+		bitrate = (bitrate / 9) * 10;
+
+	/* do NOT round down here */
+	return (bitrate + 50000) / 100000;
+}
+
 u16 cfg80211_calculate_bitrate(struct rate_info *rate)
 {
 	int modulation, streams, bitrate;
 
-	if (!(rate->flags & RATE_INFO_FLAGS_MCS))
+	if (!(rate->flags & RATE_INFO_FLAGS_MCS) &&
+	    !(rate->flags & RATE_INFO_FLAGS_VHT_MCS))
 		return rate->legacy;
 
+	if (rate->flags & RATE_INFO_FLAGS_VHT_MCS)
+		return cfg80211_calculate_bitrate_vht(rate);
+
 	/* the formula below does only work for MCS values smaller than 32 */
 	if (rate->mcs >= 32)
 		return 0;
diff --git a/sound/soc/msm/msm8960.c b/sound/soc/msm/msm8960.c
index 8c0d1a9..65b3a57 100644
--- a/sound/soc/msm/msm8960.c
+++ b/sound/soc/msm/msm8960.c
@@ -746,21 +746,21 @@
 	btn_low = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_LOW);
 	btn_high = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_HIGH);
 	btn_low[0] = -50;
-	btn_high[0] = 10;
-	btn_low[1] = 11;
-	btn_high[1] = 52;
-	btn_low[2] = 53;
-	btn_high[2] = 94;
-	btn_low[3] = 95;
-	btn_high[3] = 133;
-	btn_low[4] = 134;
-	btn_high[4] = 171;
-	btn_low[5] = 172;
-	btn_high[5] = 208;
-	btn_low[6] = 209;
-	btn_high[6] = 244;
-	btn_low[7] = 245;
-	btn_high[7] = 330;
+	btn_high[0] = 21;
+	btn_low[1] = 22;
+	btn_high[1] = 67;
+	btn_low[2] = 68;
+	btn_high[2] = 111;
+	btn_low[3] = 112;
+	btn_high[3] = 153;
+	btn_low[4] = 154;
+	btn_high[4] = 191;
+	btn_low[5] = 192;
+	btn_high[5] = 233;
+	btn_low[6] = 234;
+	btn_high[6] = 272;
+	btn_low[7] = 273;
+	btn_high[7] = 400;
 	n_ready = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_N_READY);
 	n_ready[0] = 80;
 	n_ready[1] = 68;
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 3b1727c..fed0d81 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -2363,11 +2363,11 @@
 static void config_debug_fs_init(void)
 {
 	debugfs_afelb = debugfs_create_file("afe_loopback",
-	S_IFREG | S_IWUGO, NULL, (void *) "afe_loopback",
+	S_IRUGO | S_IWUSR | S_IWGRP, NULL, (void *) "afe_loopback",
 	&afe_debug_fops);
 
 	debugfs_afelb_gain = debugfs_create_file("afe_loopback_gain",
-	S_IFREG | S_IWUGO, NULL, (void *) "afe_loopback_gain",
+	S_IRUGO | S_IWUSR | S_IWGRP, NULL, (void *) "afe_loopback_gain",
 	&afe_debug_fops);
 }
 static void config_debug_fs_exit(void)
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index ea2b5c6..49b6d03 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -279,13 +279,13 @@
 {
 	out_buffer = kmalloc(OUT_BUFFER_SIZE, GFP_KERNEL);
 	out_dentry = debugfs_create_file("audio_out_latency_measurement_node",\
-				S_IFREG | S_IRUGO | S_IWUGO,\
+				S_IRUGO | S_IWUSR | S_IWGRP,\
 				NULL, NULL, &audio_output_latency_debug_fops);
 	if (IS_ERR(out_dentry))
 		pr_err("debugfs_create_file failed\n");
 	in_buffer = kmalloc(IN_BUFFER_SIZE, GFP_KERNEL);
 	in_dentry = debugfs_create_file("audio_in_latency_measurement_node",\
-				S_IFREG | S_IRUGO | S_IWUGO,\
+				S_IRUGO | S_IWUSR | S_IWGRP,\
 				NULL, NULL, &audio_input_latency_debug_fops);
 	if (IS_ERR(in_dentry))
 		pr_err("debugfs_create_file failed\n");