Merge "msm: remote_spinlock: add dt support"
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_iommu_domains.txt b/Documentation/devicetree/bindings/arm/msm/msm_iommu_domains.txt
new file mode 100644
index 0000000..7d69749
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/msm_iommu_domains.txt
@@ -0,0 +1,50 @@
+IOMMU Domains
+
+An IOMMU domain is a collection of IOMMU context banks and an optional
+virtual address space that is to be used with the domain. Domains that are
+defined will be created at bootup and associated with an iommu group. Clients
+can then refer to the iommu group and perform operations on the iommu group
+instead of individual devices/contexts.
+
+Required properties
+
+- compatible: "qcom,iommu-domains"
+
+- At least one child that defines a domain is required with the
+  following properties:
+
+	- label: Name of the domain
+	- qcom,iommu-contexts: List of phandles to context that belongs to
+	  this domain.
+
+	Optional properties
+
+		- qcom,virtual-addr-pool: List of <start_address size> pairs
+		  that define the virtual address space for this domain.
+		- qcom,secure-domain: boolean indicating that this is a secure
+		  domain that is to be programmed by Trustzone.
+		- qcom,l2-redirect: boolean indicating that page tables should
+		  be cached in L2 cache.
+Example:
+	qcom,iommu-domains {
+		compatible = "qcom,iommu-domains";
+
+		qcom,iommu-domain1 {
+			label = "lpass_secure";
+			qcom,iommu-contexts = <&lpass_q6_fw>;
+			qcom,virtual-addr-pool = <0x00000000 0x0FFFFFFF
+						  0xF0000000 0x0FFFFFFF>;
+		};
+
+		qcom,iommu-domain2 {
+			label = "lpass_audio";
+			qcom,iommu-contexts = <&lpass_audio_shared>;
+			qcom,virtual-addr-pool = <0x10000000 0x0FFFFFFF>;
+		};
+
+		qcom,iommu-domain3 {
+			label = "lpass_video";
+			qcom,iommu-contexts = <&lpass_video_shared>;
+			qcom,virtual-addr-pool = <0x20000000 0x0FFFFFFF>;
+		};
+	};
diff --git a/Documentation/devicetree/bindings/gpio/gpio-msm.txt b/Documentation/devicetree/bindings/gpio/gpio-msm.txt
index a5d50fd..1f88037 100644
--- a/Documentation/devicetree/bindings/gpio/gpio-msm.txt
+++ b/Documentation/devicetree/bindings/gpio/gpio-msm.txt
@@ -10,6 +10,9 @@
 - #interrupt-cells : Should be 2.
 - interrupt-controller: Mark the device node as an interrupt controller
 - interrupts : Specify the TLMM summary interrupt number
+- ngpio : Specify the number of MSM GPIOs
+- qcom,direct-connect-irqs : Specifies the number of GPIOs that can be used as
+  direct connect interrupts
 
 Example:
 
@@ -21,6 +24,8 @@
 		#interrupt-cells = <2>;
 		reg = <0xfd510000 0x4000>;
 		interrupts = <0 208 0>;
+		ngpio = <150>;
+		qcom,direct-connect-irqs = <8>;
 	};
 
 To specify gpios for a device:
diff --git a/arch/arm/boot/dts/mpq8092.dtsi b/arch/arm/boot/dts/mpq8092.dtsi
index 0ab0a0c..339faa9 100644
--- a/arch/arm/boot/dts/mpq8092.dtsi
+++ b/arch/arm/boot/dts/mpq8092.dtsi
@@ -35,7 +35,9 @@
 		interrupt-controller;
 		#interrupt-cells = <2>;
 		reg = <0xfd510000 0x4000>;
+		ngpio = <146>;
 		interrupts = <0 208 0>;
+		qcom,direct-connect-irqs = <8>;
 	};
 
 	timer {
diff --git a/arch/arm/boot/dts/msm-iommu-v1.dtsi b/arch/arm/boot/dts/msm-iommu-v1.dtsi
index 5a08f51..ea4fa75 100644
--- a/arch/arm/boot/dts/msm-iommu-v1.dtsi
+++ b/arch/arm/boot/dts/msm-iommu-v1.dtsi
@@ -21,28 +21,28 @@
 		label = "lpass_iommu";
 		status = "disabled";
 
-		qcom,iommu-ctx@fd000000 {
+		lpass_q6_fw: qcom,iommu-ctx@fd000000 {
 			reg = <0xfd000000 0x1000>;
 			interrupts = <0 250 0>;
 			qcom,iommu-ctx-mids = <0 15>;
 			label = "q6_fw";
 		};
 
-		qcom,iommu-ctx@fd001000 {
+		lpass_audio_shared: qcom,iommu-ctx@fd001000 {
 			reg = <0xfd001000 0x1000>;
 			interrupts = <0 250 0>;
 			qcom,iommu-ctx-mids = <1>;
 			label = "audio_shared";
 		};
 
-		qcom,iommu-ctx@fd002000 {
+		lpass_video_shared: qcom,iommu-ctx@fd002000 {
 			reg = <0xfd002000 0x1000>;
 			interrupts = <0 250 0>;
 			qcom,iommu-ctx-mids = <2>;
 			label = "video_shared";
 		};
 
-		qcom,iommu-ctx@fd003000 {
+		lpass_q6_spare: qcom,iommu-ctx@fd003000 {
 			reg = <0xfd003000 0x1000>;
 			interrupts = <0 250 0>;
 			qcom,iommu-ctx-mids = <3 4 5 6 7 8 9 10 11 12 13 14>;
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index 3c8ea84..bba15a3 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -34,7 +34,9 @@
 		reg = <0xfd510000 0x4000>;
 		gpio-controller;
 		#gpio-cells = <2>;
+		ngpio = <117>;
 		interrupts = <0 208 0>;
+		qcom,direct-connect-irqs = <8>;
 	};
 
 	timer {
diff --git a/arch/arm/boot/dts/msm8910-iommu-domains.dtsi b/arch/arm/boot/dts/msm8910-iommu-domains.dtsi
new file mode 100644
index 0000000..dbdbd5f
--- /dev/null
+++ b/arch/arm/boot/dts/msm8910-iommu-domains.dtsi
@@ -0,0 +1,36 @@
+/* Copyright (c) 2012, 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.
+ */
+
+/ {
+	qcom,iommu-domains {
+		compatible = "qcom,iommu-domains";
+
+		qcom,iommu-domain1 {
+			label = "lpass_secure";
+			qcom,iommu-contexts = <&lpass_q6_fw>;
+			qcom,virtual-addr-pool = <0x00000000 0x0FFFFFFF
+						  0xF0000000 0x0FFFFFFF>;
+		};
+
+		qcom,iommu-domain2 {
+			label = "lpass_audio";
+			qcom,iommu-contexts = <&lpass_audio_shared>;
+			qcom,virtual-addr-pool = <0x10000000 0x0FFFFFFF>;
+		};
+
+		qcom,iommu-domain3 {
+			label = "lpass_video";
+			qcom,iommu-contexts = <&lpass_video_shared>;
+			qcom,virtual-addr-pool = <0x20000000 0x0FFFFFFF>;
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/msm8910.dtsi b/arch/arm/boot/dts/msm8910.dtsi
index 61f1dcd..a08c165 100644
--- a/arch/arm/boot/dts/msm8910.dtsi
+++ b/arch/arm/boot/dts/msm8910.dtsi
@@ -35,7 +35,9 @@
 		reg = <0xfd510000 0x4000>;
 		gpio-controller;
 		#gpio-cells = <2>;
+		ngpio = <102>;
 		interrupts = <0 208 0>;
+		qcom,direct-connect-irqs = <8>;
 	};
 
 	timer {
@@ -340,5 +342,7 @@
 	status = "ok";
 };
 
+/include/ "msm8910-iommu-domains.dtsi"
+
 /include/ "msm8910-regulator.dtsi"
 /include/ "msm-pm8110.dtsi"
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index bd0711c..6a9a071 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -40,7 +40,9 @@
 		interrupt-controller;
 		#interrupt-cells = <2>;
 		reg = <0xfd510000 0x4000>;
+		ngpio = <146>;
 		interrupts = <0 208 0>;
+		qcom,direct-connect-irqs = <8>;
 	};
 
 	wcd9xxx_intc: wcd9xxx-irq {
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index bf66de6..75a0ae5 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -42,7 +42,9 @@
 		interrupt-controller;
 		#interrupt-cells = <2>;
 		reg = <0xfd510000 0x4000>;
+		ngpio = <76>;
 		interrupts = <0 208 0>;
+		qcom,direct-connect-irqs = <8>;
 	};
 
 	timer: msm-qtimer@f9021000 {
diff --git a/arch/arm/configs/msm8910_defconfig b/arch/arm/configs/msm8910_defconfig
index 67fabd4..bf163e0 100644
--- a/arch/arm/configs/msm8910_defconfig
+++ b/arch/arm/configs/msm8910_defconfig
@@ -157,7 +157,6 @@
 CONFIG_DEBUG_FS=y
 CONFIG_SCHEDSTATS=y
 CONFIG_TIMER_STATS=y
-# CONFIG_DEBUG_PREEMPT is not set
 CONFIG_DEBUG_INFO=y
 CONFIG_DEBUG_MEMORY_INIT=y
 CONFIG_DYNAMIC_DEBUG=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 0f8c469..158e9eb 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -419,7 +419,6 @@
 CONFIG_TIMER_STATS=y
 CONFIG_DEBUG_KMEMLEAK=y
 CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
-# CONFIG_DEBUG_PREEMPT is not set
 CONFIG_DEBUG_SPINLOCK=y
 CONFIG_DEBUG_MUTEXES=y
 CONFIG_DEBUG_ATOMIC_SLEEP=y
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index cbdcc5b..bc6275e 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -88,7 +88,13 @@
 CONFIG_NF_CONNTRACK=y
 CONFIG_NF_CONNTRACK_EVENTS=y
 CONFIG_NF_CONNTRACK_TIMESTAMP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
 CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_SNMP=y
 CONFIG_NF_CONNTRACK_PPTP=y
 CONFIG_NF_CONNTRACK_SIP=y
 CONFIG_NF_CONNTRACK_TFTP=y
@@ -97,6 +103,8 @@
 CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=y
 CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
 CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_DSCP=y
+CONFIG_NETFILTER_XT_MATCH_ESP=y
 CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
 CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
 CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
diff --git a/arch/arm/mach-msm/board-8092-gpiomux.c b/arch/arm/mach-msm/board-8092-gpiomux.c
index 823ef70..7cefe8a 100644
--- a/arch/arm/mach-msm/board-8092-gpiomux.c
+++ b/arch/arm/mach-msm/board-8092-gpiomux.c
@@ -43,9 +43,9 @@
 {
 	int rc;
 
-	rc = msm_gpiomux_init(NR_GPIO_IRQS);
+	rc = msm_gpiomux_init_dt();
 	if (rc) {
-		pr_err(KERN_ERR "mpq8092_init_gpiomux failed %d\n", rc);
+		pr_err("%s failed %d\n", __func__, rc);
 		return;
 	}
 
diff --git a/arch/arm/mach-msm/board-8226-gpiomux.c b/arch/arm/mach-msm/board-8226-gpiomux.c
index eb88ef4..2b5399f 100644
--- a/arch/arm/mach-msm/board-8226-gpiomux.c
+++ b/arch/arm/mach-msm/board-8226-gpiomux.c
@@ -21,9 +21,9 @@
 {
 	int rc;
 
-	rc = msm_gpiomux_init(NR_GPIO_IRQS);
+	rc = msm_gpiomux_init_dt();
 	if (rc) {
-		pr_err(KERN_ERR "msm_8226_init_gpiomux failed %d\n", rc);
+		pr_err("%s failed %d\n", __func__, rc);
 		return;
 	}
 }
diff --git a/arch/arm/mach-msm/board-8910-gpiomux.c b/arch/arm/mach-msm/board-8910-gpiomux.c
index a67f916..a295a17 100644
--- a/arch/arm/mach-msm/board-8910-gpiomux.c
+++ b/arch/arm/mach-msm/board-8910-gpiomux.c
@@ -21,9 +21,9 @@
 {
 	int rc;
 
-	rc = msm_gpiomux_init(NR_GPIO_IRQS);
+	rc = msm_gpiomux_init_dt();
 	if (rc) {
-		pr_err(KERN_ERR "msm_8910_init_gpiomux failed %d\n", rc);
+		pr_err("%s failed %d\n", __func__, rc);
 		return;
 	}
 }
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 9b19810..c85d8a7 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -3002,6 +3002,9 @@
 		kgsl_3d0_pdata->chipid = ADRENO_CHIPID(3, 2, 1, 0);
 		/* 8960PRO nominal clock rate is 320Mhz */
 		kgsl_3d0_pdata->pwrlevel[1].gpu_freq = 320000000;
+#ifdef CONFIG_MSM_BUS_SCALING
+		kgsl_3d0_pdata->bus_scale_table = &grp3d_bus_scale_pdata_ab;
+#endif
 
 		/*
 		 * If this an A320 GPU device (MSM8960AB), then
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index 4bd100d..fdad2e5 100644
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -862,9 +862,9 @@
 {
 	int rc;
 
-	rc = msm_gpiomux_init(NR_GPIO_IRQS);
+	rc = msm_gpiomux_init_dt();
 	if (rc) {
-		pr_err(KERN_ERR "msm_8974_init_gpiomux failed %d\n", rc);
+		pr_err("%s failed %d\n", __func__, rc);
 		return;
 	}
 
diff --git a/arch/arm/mach-msm/board-9625-gpiomux.c b/arch/arm/mach-msm/board-9625-gpiomux.c
index 686bb41..4465440 100644
--- a/arch/arm/mach-msm/board-9625-gpiomux.c
+++ b/arch/arm/mach-msm/board-9625-gpiomux.c
@@ -280,9 +280,9 @@
 {
 	int rc;
 
-	rc = msm_gpiomux_init(NR_GPIO_IRQS);
+	rc = msm_gpiomux_init_dt();
 	if (rc) {
-		pr_err(KERN_ERR "msm9625_init_gpiomux failed %d\n", rc);
+		pr_err("%s failed %d\n", __func__, rc);
 		return;
 	}
 
diff --git a/arch/arm/mach-msm/clock-9625.c b/arch/arm/mach-msm/clock-9625.c
index ccf6755..3b1df2e 100644
--- a/arch/arm/mach-msm/clock-9625.c
+++ b/arch/arm/mach-msm/clock-9625.c
@@ -2171,6 +2171,7 @@
 	CLK_LOOKUP("core_clk", qdss_clk.c, "fc319000.funnel"),
 	CLK_LOOKUP("core_clk", qdss_clk.c, "fc31a000.funnel"),
 	CLK_LOOKUP("core_clk", qdss_clk.c, "fc321000.stm"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc332000.etm"),
 
 	CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc322000.tmc"),
 	CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc318000.tpiu"),
@@ -2180,6 +2181,7 @@
 	CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc319000.funnel"),
 	CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc31a000.funnel"),
 	CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc321000.stm"),
+	CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc332000.etm"),
 
 };
 
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 4780c57..446f3f2 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -19,6 +19,7 @@
 #include <linux/gpio.h>
 #include <linux/coresight.h>
 #include <asm/clkdev.h>
+#include <mach/gpio.h>
 #include <mach/kgsl.h>
 #include <linux/android_pmem.h>
 #include <mach/irqs-8960.h>
@@ -3131,6 +3132,81 @@
 	},
 };
 
+struct msm_bus_vectors grp3d_init_vectors_1[] = {
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_3D,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_3D_PORT1,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+};
+
+struct msm_bus_vectors grp3d_low_vectors_1[] = {
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_3D,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = KGSL_CONVERT_TO_MBPS(1000),
+	},
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_3D_PORT1,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = KGSL_CONVERT_TO_MBPS(1000),
+	},
+};
+
+struct msm_bus_vectors grp3d_nominal_low_vectors_1[] = {
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_3D,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = KGSL_CONVERT_TO_MBPS(2048),
+	},
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_3D_PORT1,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = KGSL_CONVERT_TO_MBPS(2048),
+	},
+};
+
+struct msm_bus_vectors grp3d_nominal_high_vectors_1[] = {
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_3D,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = KGSL_CONVERT_TO_MBPS(2656),
+	},
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_3D_PORT1,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = KGSL_CONVERT_TO_MBPS(2656),
+	},
+};
+
+struct msm_bus_vectors grp3d_max_vectors_1[] = {
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_3D,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = KGSL_CONVERT_TO_MBPS(3968),
+	},
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_3D_PORT1,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = KGSL_CONVERT_TO_MBPS(3968),
+	},
+};
+
 static struct msm_bus_paths grp3d_bus_scale_usecases[] = {
 	{
 		ARRAY_SIZE(grp3d_init_vectors),
@@ -3154,12 +3230,41 @@
 	},
 };
 
+struct msm_bus_paths grp3d_bus_scale_usecases_1[] = {
+	{
+		ARRAY_SIZE(grp3d_init_vectors_1),
+		grp3d_init_vectors_1,
+	},
+	{
+		ARRAY_SIZE(grp3d_low_vectors_1),
+		grp3d_low_vectors_1,
+	},
+	{
+		ARRAY_SIZE(grp3d_nominal_low_vectors_1),
+		grp3d_nominal_low_vectors_1,
+	},
+	{
+		ARRAY_SIZE(grp3d_nominal_high_vectors_1),
+		grp3d_nominal_high_vectors_1,
+	},
+	{
+		ARRAY_SIZE(grp3d_max_vectors_1),
+		grp3d_max_vectors_1,
+	},
+};
+
 static struct msm_bus_scale_pdata grp3d_bus_scale_pdata = {
 	grp3d_bus_scale_usecases,
 	ARRAY_SIZE(grp3d_bus_scale_usecases),
 	.name = "grp3d",
 };
 
+struct msm_bus_scale_pdata grp3d_bus_scale_pdata_ab = {
+	grp3d_bus_scale_usecases_1,
+	ARRAY_SIZE(grp3d_bus_scale_usecases_1),
+	.name = "grp3d",
+};
+
 static struct msm_bus_vectors grp2d0_init_vectors[] = {
 	{
 		.src = MSM_BUS_MASTER_GRAPHICS_2D_CORE0,
@@ -4438,11 +4543,17 @@
 	},
 };
 
+static struct msm_gpio_pdata msm8960_gpio_pdata = {
+	.ngpio = 152,
+	.direct_connect_irqs = 8,
+};
+
 struct platform_device msm_gpio_device = {
-	.name = "msmgpio",
-	.id = -1,
-	.num_resources	= ARRAY_SIZE(msm_gpio_resources),
-	.resource	= msm_gpio_resources,
+	.name			= "msmgpio",
+	.id			= -1,
+	.num_resources		= ARRAY_SIZE(msm_gpio_resources),
+	.resource		= msm_gpio_resources,
+	.dev.platform_data	= &msm8960_gpio_pdata,
 };
 
 struct platform_device mdm_sglte_device = {
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index fc65cb7..cec57fd 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -34,6 +34,7 @@
 #include <mach/dma.h>
 #include "pm.h"
 #include "devices.h"
+#include <mach/gpio.h>
 #include <mach/mpm.h>
 #include "spm.h"
 #include "rpm_resources.h"
@@ -1514,11 +1515,17 @@
 	},
 };
 
+static struct msm_gpio_pdata msm9615_gpio_pdata = {
+	.ngpio = 88,
+	.direct_connect_irqs = 8,
+};
+
 struct platform_device msm_gpio_device = {
-	.name = "msmgpio",
-	.id = -1,
-	.num_resources	= ARRAY_SIZE(msm_gpio_resources),
-	.resource	= msm_gpio_resources,
+	.name			= "msmgpio",
+	.id			= -1,
+	.num_resources		= ARRAY_SIZE(msm_gpio_resources),
+	.resource		= msm_gpio_resources,
+	.dev.platform_data	= &msm9615_gpio_pdata,
 };
 
 void __init msm9615_device_init(void)
diff --git a/arch/arm/mach-msm/devices-msm8x60.c b/arch/arm/mach-msm/devices-msm8x60.c
index 0a080b1..5a517df 100644
--- a/arch/arm/mach-msm/devices-msm8x60.c
+++ b/arch/arm/mach-msm/devices-msm8x60.c
@@ -108,11 +108,17 @@
 	},
 };
 
+static struct msm_gpio_pdata msm8660_gpio_pdata = {
+	.ngpio = 173,
+	.direct_connect_irqs = 10,
+};
+
 struct platform_device msm_gpio_device = {
-	.name = "msmgpio",
-	.id = -1,
-	.num_resources	= ARRAY_SIZE(msm_gpio_resources),
-	.resource	= msm_gpio_resources,
+	.name			= "msmgpio",
+	.id			= -1,
+	.num_resources		= ARRAY_SIZE(msm_gpio_resources),
+	.resource		= msm_gpio_resources,
+	.dev.platform_data	= &msm8660_gpio_pdata,
 };
 
 static void charm_ap2mdm_kpdpwr_on(void)
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index b676518..2339706 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -330,6 +330,9 @@
 
 extern struct resource kgsl_3d0_resources_8960ab[];
 extern int kgsl_num_resources_8960ab;
+#ifdef CONFIG_MSM_BUS_SCALING
+extern struct msm_bus_scale_pdata grp3d_bus_scale_pdata_ab;
+#endif
 
 extern struct platform_device msm_mipi_dsi1_device;
 extern struct platform_device mipi_dsi_device;
diff --git a/arch/arm/mach-msm/gpiomux.c b/arch/arm/mach-msm/gpiomux.c
index 85936ba..0af83e8 100644
--- a/arch/arm/mach-msm/gpiomux.c
+++ b/arch/arm/mach-msm/gpiomux.c
@@ -10,6 +10,7 @@
  * GNU General Public License for more details.
  */
 #include <linux/module.h>
+#include <linux/of.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <mach/gpiomux.h>
@@ -148,3 +149,26 @@
 	}
 }
 EXPORT_SYMBOL(msm_gpiomux_install);
+
+int msm_gpiomux_init_dt(void)
+{
+	int rc;
+	unsigned int ngpio;
+	struct device_node *of_gpio_node;
+
+	of_gpio_node = of_find_compatible_node(NULL, NULL, "qcom,msm-gpio");
+	if (!of_gpio_node) {
+		pr_err("%s: Failed to find qcom,msm-gpio node\n", __func__);
+		return -ENODEV;
+	}
+
+	rc = of_property_read_u32(of_gpio_node, "ngpio", &ngpio);
+	if (rc) {
+		pr_err("%s: Failed to find ngpio property in msm-gpio device node %d\n"
+				, __func__, rc);
+		return rc;
+	}
+
+	return msm_gpiomux_init(ngpio);
+}
+EXPORT_SYMBOL(msm_gpiomux_init_dt);
diff --git a/arch/arm/mach-msm/include/mach/gpio.h b/arch/arm/mach-msm/include/mach/gpio.h
index a0bcd2b..137d243 100644
--- a/arch/arm/mach-msm/include/mach/gpio.h
+++ b/arch/arm/mach-msm/include/mach/gpio.h
@@ -40,6 +40,11 @@
 	const char *label;
 };
 
+struct msm_gpio_pdata {
+	int ngpio;
+	int direct_connect_irqs;
+};
+
 /**
  * msm_gpios_request_enable() - request and enable set of GPIOs
  *
diff --git a/arch/arm/mach-msm/include/mach/gpiomux.h b/arch/arm/mach-msm/include/mach/gpiomux.h
index f75b0e0..f16caed 100644
--- a/arch/arm/mach-msm/include/mach/gpiomux.h
+++ b/arch/arm/mach-msm/include/mach/gpiomux.h
@@ -117,6 +117,11 @@
  */
 int msm_gpiomux_init(size_t ngpio);
 
+/* DT Variant of msm_gpiomux_init. This will look up the number of gpios from
+ * device tree rather than relying on NR_GPIO_IRQS
+ */
+int msm_gpiomux_init_dt(void);
+
 /* Install a block of gpiomux configurations in gpiomux.  This is functionally
  * identical to calling msm_gpiomux_write many times.
  */
diff --git a/arch/arm/mach-msm/include/mach/iommu.h b/arch/arm/mach-msm/include/mach/iommu.h
index 8ebd0cf..8b39e34 100644
--- a/arch/arm/mach-msm/include/mach/iommu.h
+++ b/arch/arm/mach-msm/include/mach/iommu.h
@@ -130,6 +130,7 @@
  * @secure_context	true if this is a secure context programmed by
 			the secure environment, false otherwise
  * @asid		ASID used with this context.
+ * @attach_count	Number of time this context has been attached.
  *
  * A msm_iommu_ctx_drvdata holds the driver data for a single context bank
  * within each IOMMU hardware instance
@@ -144,6 +145,7 @@
 	unsigned int nsid;
 	unsigned int secure_context;
 	int asid;
+	int attach_count;
 };
 
 /*
diff --git a/arch/arm/mach-msm/include/mach/iommu_domains.h b/arch/arm/mach-msm/include/mach/iommu_domains.h
index 01bc479..07f82ec 100644
--- a/arch/arm/mach-msm/include/mach/iommu_domains.h
+++ b/arch/arm/mach-msm/include/mach/iommu_domains.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, 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
@@ -77,6 +77,7 @@
 #if defined(CONFIG_MSM_IOMMU)
 
 extern struct iommu_domain *msm_get_iommu_domain(int domain_num);
+extern int msm_find_domain_no(const struct iommu_domain *domain);
 
 extern int msm_allocate_iova_address(unsigned int iommu_domain,
 					unsigned int partition_no,
@@ -123,6 +124,10 @@
 	*msm_get_iommu_domain(int subsys_id) { return NULL; }
 
 
+static inline int msm_find_domain_no(const struct iommu_domain *domain)
+{
+	return -EINVAL;
+}
 
 static inline int msm_allocate_iova_address(unsigned int iommu_domain,
 					unsigned int partition_no,
diff --git a/arch/arm/mach-msm/include/mach/irqs-8x60.h b/arch/arm/mach-msm/include/mach/irqs-8x60.h
index d08f645..1e2c606 100644
--- a/arch/arm/mach-msm/include/mach/irqs-8x60.h
+++ b/arch/arm/mach-msm/include/mach/irqs-8x60.h
@@ -242,7 +242,6 @@
 #define SMPSS_SPARE_6				(GIC_SPI_START + 222)
 #define SMPSS_SPARE_7				(GIC_SPI_START + 223)
 
-#define NR_TLMM_MSM_DIR_CONN_IRQ 10
 #define NR_GPIO_IRQS 173
 #define NR_MSM_GPIOS NR_GPIO_IRQS
 #define NR_MSM_IRQS 256
diff --git a/arch/arm/mach-msm/include/mach/irqs-9615.h b/arch/arm/mach-msm/include/mach/irqs-9615.h
index b9c66c3..35b5848 100644
--- a/arch/arm/mach-msm/include/mach/irqs-9615.h
+++ b/arch/arm/mach-msm/include/mach/irqs-9615.h
@@ -181,7 +181,6 @@
 #define NR_WCD9XXX_IRQS 49
 #define NR_TABLA_IRQS NR_WCD9XXX_IRQS
 #define NR_BOARD_IRQS (NR_PM8018_IRQS + NR_WCD9XXX_IRQS)
-#define NR_TLMM_MSM_DIR_CONN_IRQ 8 /*Need to Verify this Count*/
 #define NR_MSM_GPIOS NR_GPIO_IRQS
 
 /* Backwards compatible IRQ macros. */
diff --git a/arch/arm/mach-msm/include/mach/irqs-9625.h b/arch/arm/mach-msm/include/mach/irqs-9625.h
index 9ba77af..278c6a5 100644
--- a/arch/arm/mach-msm/include/mach/irqs-9625.h
+++ b/arch/arm/mach-msm/include/mach/irqs-9625.h
@@ -20,10 +20,6 @@
 #define APCC_QGICL2PERFMONIRPTREQ	(GIC_SPI_START + 1)
 #define SC_SICL2PERFMONIRPTREQ		APCC_QGICL2PERFMONIRPTREQ
 
-#define NR_MSM_IRQS 288
-#define NR_GPIO_IRQS 76
-#define NR_BOARD_IRQS 0
 #define NR_TLMM_MSM_DIR_CONN_IRQ 8 /*Need to Verify this Count*/
-#define NR_MSM_GPIOS NR_GPIO_IRQS
 
 #endif
diff --git a/arch/arm/mach-msm/include/mach/irqs.h b/arch/arm/mach-msm/include/mach/irqs.h
index 8c6b959..6955c80 100644
--- a/arch/arm/mach-msm/include/mach/irqs.h
+++ b/arch/arm/mach-msm/include/mach/irqs.h
@@ -37,22 +37,6 @@
 #include "irqs-8092.h"
 #endif
 
-#define NR_MSM_IRQS 1020 /* Should be 256 - but higher due to bug in sim */
-#define NR_GPIO_IRQS 146
-#define NR_QPNP_IRQS 32768
-#define NR_BOARD_IRQS NR_QPNP_IRQS
-#define NR_TLMM_MSM_DIR_CONN_IRQ 8
-#define NR_MSM_GPIOS NR_GPIO_IRQS
-
-#elif defined(CONFIG_ARCH_MSM8910) || defined(CONFIG_ARCH_MSM8226)
-
-#define NR_MSM_IRQS 256
-#define NR_GPIO_IRQS 117
-#define NR_QPNP_IRQS 32768
-#define NR_BOARD_IRQS NR_QPNP_IRQS
-#define NR_TLMM_MSM_DIR_CONN_IRQ 8
-#define NR_MSM_GPIOS NR_GPIO_IRQS
-
 #elif defined(CONFIG_ARCH_MSM8960) || defined(CONFIG_ARCH_APQ8064) || \
 	defined(CONFIG_ARCH_MSM8930)
 
@@ -85,7 +69,6 @@
 #define NR_BOARD_IRQS (NR_PM8921_IRQS + NR_PM8821_IRQS + \
 		NR_WCD9XXX_IRQS + NR_GPIO_EXPANDER_IRQS)
 #endif
-#define NR_TLMM_MSM_DIR_CONN_IRQ 8 /*Need to Verify this Count*/
 #define NR_MSM_GPIOS NR_GPIO_IRQS
 
 #else
@@ -113,17 +96,36 @@
 #elif defined(CONFIG_ARCH_FSM9XXX)
 #include "irqs-fsm9xxx.h"
 #include "sirc.h"
-#else
-#error "Unknown architecture specification"
 #endif
 
 #endif
 
 #if !defined(CONFIG_SPARSE_IRQ)
+
+#if defined(CONFIG_ARCH_MSM8974) || defined(CONFIG_ARCH_MPQ8092)
+#define NR_MSM_IRQS 1020 /* Should be 256 - but higher due to bug in sim */
+#define NR_GPIO_IRQS 146
+#define NR_QPNP_IRQS 32768
+#define NR_BOARD_IRQS NR_QPNP_IRQS
+
+#elif defined(CONFIG_ARCH_MSM8910) || defined(CONFIG_ARCH_MSM8226)
+#define NR_MSM_IRQS 256
+#define NR_GPIO_IRQS 117
+#define NR_QPNP_IRQS 32768
+#define NR_BOARD_IRQS NR_QPNP_IRQS
+
+#elif defined(CONFIG_ARCH_MSM9625)
+#define NR_MSM_IRQS 288
+#define NR_GPIO_IRQS 76
+#define NR_BOARD_IRQS 0
+
+#endif
+
 #define NR_IRQS (NR_MSM_IRQS + NR_GPIO_IRQS + NR_BOARD_IRQS)
 #define MSM_GPIO_TO_INT(n) (NR_MSM_IRQS + (n))
 #define FIRST_GPIO_IRQ MSM_GPIO_TO_INT(0)
 #define MSM_INT_TO_REG(base, irq) (base + irq / 32)
+
 #endif
 
 #if defined(CONFIG_PCI_MSI) && defined(CONFIG_MSM_PCIE)
diff --git a/arch/arm/mach-msm/iommu_domains.c b/arch/arm/mach-msm/iommu_domains.c
index 75e56fe..dc67403 100644
--- a/arch/arm/mach-msm/iommu_domains.c
+++ b/arch/arm/mach-msm/iommu_domains.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, 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
@@ -25,6 +25,9 @@
 #include <mach/iommu_domains.h>
 #include <mach/socinfo.h>
 #include <mach/msm_subsystem_map.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
 
 /* dummy 64K for overmapping */
 char iommu_dummy[2*SZ_64K-4];
@@ -269,6 +272,27 @@
 }
 EXPORT_SYMBOL(msm_get_iommu_domain);
 
+int msm_find_domain_no(const struct iommu_domain *domain)
+{
+	struct rb_root *root = &domain_root;
+	struct rb_node *n;
+	struct msm_iova_data *node;
+	int domain_num = -EINVAL;
+
+	mutex_lock(&domain_mutex);
+
+	for (n = rb_first(root); n; n = rb_next(n)) {
+		node = rb_entry(n, struct msm_iova_data, node);
+		if (node->domain == domain) {
+			domain_num = node->domain_num;
+			break;
+		}
+	}
+	mutex_unlock(&domain_mutex);
+	return domain_num;
+}
+EXPORT_SYMBOL(msm_find_domain_no);
+
 int msm_allocate_iova_address(unsigned int iommu_domain,
 					unsigned int partition_no,
 					unsigned long size,
@@ -411,7 +435,170 @@
 }
 EXPORT_SYMBOL(msm_register_domain);
 
-static int __init iommu_domain_probe(struct platform_device *pdev)
+static int find_and_add_contexts(struct iommu_group *group,
+				 const struct device_node *node,
+				 unsigned int num_contexts)
+{
+	unsigned int i;
+	struct device *ctx;
+	const char *name;
+	struct device_node *ctx_node;
+	int ret_val = 0;
+
+	for (i = 0; i < num_contexts; ++i) {
+		ctx_node = of_parse_phandle((struct device_node *) node,
+					    "qcom,iommu-contexts", i);
+		if (!ctx_node) {
+			pr_err("Unable to parse phandle #%u\n", i);
+			ret_val = -EINVAL;
+			goto out;
+		}
+		if (of_property_read_string(ctx_node, "label", &name)) {
+			pr_err("Could not find label property\n");
+			ret_val = -EINVAL;
+			goto out;
+		}
+		ctx = msm_iommu_get_ctx(name);
+		if (!ctx) {
+			pr_err("Unable to find context %s\n", name);
+			ret_val = -EINVAL;
+			goto out;
+		}
+		iommu_group_add_device(group, ctx);
+	}
+out:
+	return ret_val;
+}
+
+static int create_and_add_domain(struct iommu_group *group,
+				 const struct device_node *node)
+{
+	unsigned int ret_val = 0;
+	unsigned int i;
+	struct msm_iova_layout l;
+	struct msm_iova_partition *part = 0;
+	struct iommu_domain *domain = 0;
+	unsigned int *addr_array;
+	unsigned int array_size;
+	int domain_no;
+	int secure_domain;
+	int l2_redirect;
+
+	if (of_get_property(node, "qcom,virtual-addr-pool", &array_size)) {
+		l.npartitions = array_size / sizeof(unsigned int) / 2;
+		part = kmalloc(
+			sizeof(struct msm_iova_partition) * l.npartitions,
+			       GFP_KERNEL);
+		if (!part) {
+			pr_err("%s: could not allocate space for partition",
+				__func__);
+			ret_val = -ENOMEM;
+			goto out;
+		}
+		addr_array = kmalloc(array_size, GFP_KERNEL);
+		if (!addr_array) {
+			pr_err("%s: could not allocate space for partition",
+				__func__);
+			ret_val = -ENOMEM;
+			goto free_mem;
+		}
+
+		ret_val = of_property_read_u32_array(node,
+					"qcom,virtual-addr-pool",
+					addr_array,
+					array_size/sizeof(unsigned int));
+		if (ret_val) {
+			ret_val = -EINVAL;
+			goto free_mem;
+		}
+
+		for (i = 0; i < l.npartitions * 2; i += 2) {
+			part[i].start = addr_array[i];
+			part[i].size = addr_array[i+1];
+		}
+	} else {
+		l.npartitions = 1;
+		part = kmalloc(
+			sizeof(struct msm_iova_partition) * l.npartitions,
+			       GFP_KERNEL);
+		if (!part) {
+			pr_err("%s: could not allocate space for partition",
+				__func__);
+			ret_val = -ENOMEM;
+			goto out;
+		}
+		part[0].start = 0x0;
+		part[0].size = 0xFFFFFFFF;
+	}
+
+	l.partitions = part;
+
+	secure_domain = of_property_read_bool(node, "qcom,secure-domain");
+	l.is_secure = (secure_domain) ? MSM_IOMMU_DOMAIN_SECURE : 0;
+
+	l2_redirect = of_property_read_bool(node, "qcom,l2-redirect");
+	l.domain_flags = (l2_redirect) ? MSM_IOMMU_DOMAIN_PT_CACHEABLE : 0;
+
+	domain_no = msm_register_domain(&l);
+	if (domain_no >= 0)
+		domain = msm_get_iommu_domain(domain_no);
+	else
+		ret_val = domain_no;
+
+	iommu_group_set_iommudata(group, domain, NULL);
+
+free_mem:
+	kfree(part);
+out:
+	return ret_val;
+}
+
+static int iommu_domain_parse_dt(const struct device_node *dt_node)
+{
+	struct device_node *node;
+	int sz;
+	unsigned int num_contexts;
+	int ret_val = 0;
+	struct iommu_group *group = 0;
+	const char *name;
+
+	for_each_child_of_node(dt_node, node) {
+		group = iommu_group_alloc();
+		if (IS_ERR(group)) {
+			ret_val = PTR_ERR(group);
+			goto out;
+		}
+		if (of_property_read_string(node, "label", &name)) {
+			ret_val = -EINVAL;
+			goto free_group;
+		}
+		iommu_group_set_name(group, name);
+
+		if (!of_get_property(node, "qcom,iommu-contexts", &sz)) {
+			pr_err("Could not find qcom,iommu-contexts property\n");
+			ret_val = -EINVAL;
+			goto free_group;
+		}
+		num_contexts = sz / sizeof(unsigned int);
+
+		ret_val = find_and_add_contexts(group, node, num_contexts);
+		if (ret_val) {
+			ret_val = -EINVAL;
+			goto free_group;
+		}
+		ret_val = create_and_add_domain(group, node);
+		if (ret_val) {
+			ret_val = -EINVAL;
+			goto free_group;
+		}
+	}
+free_group:
+	/* No iommu_group_free() function */
+out:
+	return ret_val;
+}
+
+static int iommu_domain_probe(struct platform_device *pdev)
 {
 	struct iommu_domains_pdata *p  = pdev->dev.platform_data;
 	int i, j;
@@ -419,7 +606,9 @@
 	if (!msm_use_iommu())
 		return -ENODEV;
 
-	if (!p)
+	if (pdev->dev.of_node)
+		return iommu_domain_parse_dt(pdev->dev.of_node);
+	else if (!p)
 		return -ENODEV;
 
 	for (i = 0; i < p->ndomains; i++) {
@@ -465,26 +654,48 @@
 			continue;
 
 		if (iommu_attach_device(domain, ctx)) {
-			WARN(1, "%s: could not attach domain %p to context %s."
-				" iommu programming will not occur.\n",
-				__func__, domain,
-				p->domain_names[i].name);
+			WARN(1, "%s: could not attach domain %p to context %s. iommu programming will not occur.\n",
+				__func__, domain, p->domain_names[i].name);
 			continue;
 		}
 	}
-
 	return 0;
 }
 
+static int __devexit iommu_domain_exit(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static struct of_device_id msm_iommu_domain_match_table[] = {
+	{ .name = "qcom,iommu-domains", },
+	{}
+};
+
 static struct platform_driver iommu_domain_driver = {
 	.driver         = {
 		.name = "iommu_domains",
+		.of_match_table = msm_iommu_domain_match_table,
 		.owner = THIS_MODULE
 	},
+	.probe		= iommu_domain_probe,
+	.remove		= __devexit_p(iommu_domain_exit),
 };
 
 static int __init msm_subsystem_iommu_init(void)
 {
-	return platform_driver_probe(&iommu_domain_driver, iommu_domain_probe);
+	int ret;
+	ret = platform_driver_register(&iommu_domain_driver);
+	if (ret != 0)
+		pr_err("Failed to register IOMMU domain driver\n");
+	return ret;
 }
+
+static void __exit msm_subsystem_iommu_exit(void)
+{
+	platform_driver_unregister(&iommu_domain_driver);
+}
+
 device_initcall(msm_subsystem_iommu_init);
+module_exit(msm_subsystem_iommu_exit);
+
diff --git a/arch/arm/mach-msm/pil-q6v5.c b/arch/arm/mach-msm/pil-q6v5.c
index ab88749..de3a544 100644
--- a/arch/arm/mach-msm/pil-q6v5.c
+++ b/arch/arm/mach-msm/pil-q6v5.c
@@ -118,7 +118,7 @@
 	val &= ~(Q6SS_L2DATA_SLP_NRET_N | Q6SS_SLP_RET_N |
 		 Q6SS_L2TAG_SLP_NRET_N | Q6SS_ETB_SLP_NRET_N |
 		 Q6SS_L2DATA_STBY_N);
-	writel_relaxed(Q6SS_CLAMP_IO, drv->reg_base + QDSP6SS_PWR_CTL);
+	writel_relaxed(val, drv->reg_base + QDSP6SS_PWR_CTL);
 
 	/* Assert Q6 resets */
 	val = readl_relaxed(drv->reg_base + QDSP6SS_RESET);
diff --git a/arch/arm/mach-msm/restart.c b/arch/arm/mach-msm/restart.c
index 7966177..58d445e 100644
--- a/arch/arm/mach-msm/restart.c
+++ b/arch/arm/mach-msm/restart.c
@@ -266,6 +266,9 @@
 {
 	int rc;
 
+	if (use_restart_v2())
+		return 0;
+
 	if (pmic_reset_irq != 0) {
 		rc = request_any_context_irq(pmic_reset_irq,
 					resout_irq_handler, IRQF_TRIGGER_HIGH,
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index ad42505..c607202 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -657,8 +657,8 @@
 };
 
 struct smd_channel {
-	volatile void *send; /* some variant of smd_half_channel */
-	volatile void *recv; /* some variant of smd_half_channel */
+	volatile void __iomem *send; /* some variant of smd_half_channel */
+	volatile void __iomem *recv; /* some variant of smd_half_channel */
 	unsigned char *send_data;
 	unsigned char *recv_data;
 	unsigned fifo_size;
diff --git a/arch/arm/mach-msm/smd_private.c b/arch/arm/mach-msm/smd_private.c
index 5a78b6f..4cde8eb 100644
--- a/arch/arm/mach-msm/smd_private.c
+++ b/arch/arm/mach-msm/smd_private.c
@@ -12,227 +12,256 @@
 
 #include "smd_private.h"
 
-void set_state(volatile void *half_channel, unsigned data)
+void set_state(volatile void __iomem *half_channel, unsigned data)
 {
-	((struct smd_half_channel *)(half_channel))->state = data;
+	((struct smd_half_channel __force *)(half_channel))->state = data;
 }
 
-unsigned get_state(volatile void *half_channel)
+unsigned get_state(volatile void __iomem *half_channel)
 {
-	return ((struct smd_half_channel *)(half_channel))->state;
+	return ((struct smd_half_channel __force *)(half_channel))->state;
 }
 
-void set_fDSR(volatile void *half_channel, unsigned char data)
+void set_fDSR(volatile void __iomem *half_channel, unsigned char data)
 {
-	((struct smd_half_channel *)(half_channel))->fDSR = data;
+	((struct smd_half_channel __force *)(half_channel))->fDSR = data;
 }
 
-unsigned get_fDSR(volatile void *half_channel)
+unsigned get_fDSR(volatile void __iomem *half_channel)
 {
-	return ((struct smd_half_channel *)(half_channel))->fDSR;
+	return ((struct smd_half_channel __force *)(half_channel))->fDSR;
 }
 
-void set_fCTS(volatile void *half_channel, unsigned char data)
+void set_fCTS(volatile void __iomem *half_channel, unsigned char data)
 {
-	((struct smd_half_channel *)(half_channel))->fCTS = data;
+	((struct smd_half_channel __force *)(half_channel))->fCTS = data;
 }
 
-unsigned get_fCTS(volatile void *half_channel)
+unsigned get_fCTS(volatile void __iomem *half_channel)
 {
-	return ((struct smd_half_channel *)(half_channel))->fCTS;
+	return ((struct smd_half_channel __force *)(half_channel))->fCTS;
 }
 
-void set_fCD(volatile void *half_channel, unsigned char data)
+void set_fCD(volatile void __iomem *half_channel, unsigned char data)
 {
-	((struct smd_half_channel *)(half_channel))->fCD = data;
+	((struct smd_half_channel __force *)(half_channel))->fCD = data;
 }
 
-unsigned get_fCD(volatile void *half_channel)
+unsigned get_fCD(volatile void __iomem *half_channel)
 {
-	return ((struct smd_half_channel *)(half_channel))->fCD;
+	return ((struct smd_half_channel __force *)(half_channel))->fCD;
 }
 
-void set_fRI(volatile void *half_channel, unsigned char data)
+void set_fRI(volatile void __iomem *half_channel, unsigned char data)
 {
-	((struct smd_half_channel *)(half_channel))->fRI = data;
+	((struct smd_half_channel __force *)(half_channel))->fRI = data;
 }
 
-unsigned get_fRI(volatile void *half_channel)
+unsigned get_fRI(volatile void __iomem *half_channel)
 {
-	return ((struct smd_half_channel *)(half_channel))->fRI;
+	return ((struct smd_half_channel __force *)(half_channel))->fRI;
 }
 
-void set_fHEAD(volatile void *half_channel, unsigned char data)
+void set_fHEAD(volatile void __iomem *half_channel, unsigned char data)
 {
-	((struct smd_half_channel *)(half_channel))->fHEAD = data;
+	((struct smd_half_channel __force *)(half_channel))->fHEAD = data;
 }
 
-unsigned get_fHEAD(volatile void *half_channel)
+unsigned get_fHEAD(volatile void __iomem *half_channel)
 {
-	return ((struct smd_half_channel *)(half_channel))->fHEAD;
+	return ((struct smd_half_channel __force *)(half_channel))->fHEAD;
 }
 
-void set_fTAIL(volatile void *half_channel, unsigned char data)
+void set_fTAIL(volatile void __iomem *half_channel, unsigned char data)
 {
-	((struct smd_half_channel *)(half_channel))->fTAIL = data;
+	((struct smd_half_channel __force *)(half_channel))->fTAIL = data;
 }
 
-unsigned get_fTAIL(volatile void *half_channel)
+unsigned get_fTAIL(volatile void __iomem *half_channel)
 {
-	return ((struct smd_half_channel *)(half_channel))->fTAIL;
+	return ((struct smd_half_channel __force *)(half_channel))->fTAIL;
 }
 
-void set_fSTATE(volatile void *half_channel, unsigned char data)
+void set_fSTATE(volatile void __iomem *half_channel, unsigned char data)
 {
-	((struct smd_half_channel *)(half_channel))->fSTATE = data;
+	((struct smd_half_channel __force *)(half_channel))->fSTATE = data;
 }
 
-unsigned get_fSTATE(volatile void *half_channel)
+unsigned get_fSTATE(volatile void __iomem *half_channel)
 {
-	return ((struct smd_half_channel *)(half_channel))->fSTATE;
+	return ((struct smd_half_channel __force *)(half_channel))->fSTATE;
 }
 
-void set_fBLOCKREADINTR(volatile void *half_channel, unsigned char data)
+void set_fBLOCKREADINTR(volatile void __iomem *half_channel, unsigned char data)
 {
-	((struct smd_half_channel *)(half_channel))->fBLOCKREADINTR = data;
+	((struct smd_half_channel __force *)
+				(half_channel))->fBLOCKREADINTR = data;
 }
 
-unsigned get_fBLOCKREADINTR(volatile void *half_channel)
+unsigned get_fBLOCKREADINTR(volatile void __iomem *half_channel)
 {
-	return ((struct smd_half_channel *)(half_channel))->fBLOCKREADINTR;
+	return ((struct smd_half_channel __force *)
+				(half_channel))->fBLOCKREADINTR;
 }
 
-void set_tail(volatile void *half_channel, unsigned data)
+void set_tail(volatile void __iomem *half_channel, unsigned data)
 {
-	((struct smd_half_channel *)(half_channel))->tail = data;
+	((struct smd_half_channel __force *)(half_channel))->tail = data;
 }
 
-unsigned get_tail(volatile void *half_channel)
+unsigned get_tail(volatile void __iomem *half_channel)
 {
-	return ((struct smd_half_channel *)(half_channel))->tail;
+	return ((struct smd_half_channel __force *)(half_channel))->tail;
 }
 
-void set_head(volatile void *half_channel, unsigned data)
+void set_head(volatile void __iomem *half_channel, unsigned data)
 {
-	((struct smd_half_channel *)(half_channel))->head = data;
+	((struct smd_half_channel __force *)(half_channel))->head = data;
 }
 
-unsigned get_head(volatile void *half_channel)
+unsigned get_head(volatile void __iomem *half_channel)
 {
-	return ((struct smd_half_channel *)(half_channel))->head;
+	return ((struct smd_half_channel __force *)(half_channel))->head;
 }
 
-void set_state_word_access(volatile void *half_channel, unsigned data)
+void set_state_word_access(volatile void __iomem *half_channel, unsigned data)
 {
-	((struct smd_half_channel_word_access *)(half_channel))->state = data;
+	((struct smd_half_channel_word_access __force *)
+					(half_channel))->state = data;
 }
 
-unsigned get_state_word_access(volatile void *half_channel)
+unsigned get_state_word_access(volatile void __iomem *half_channel)
 {
-	return ((struct smd_half_channel_word_access *)(half_channel))->state;
+	return ((struct smd_half_channel_word_access __force *)
+					(half_channel))->state;
 }
 
-void set_fDSR_word_access(volatile void *half_channel, unsigned char data)
+void set_fDSR_word_access(volatile void __iomem *half_channel,
+						unsigned char data)
 {
-	((struct smd_half_channel_word_access *)(half_channel))->fDSR = data;
+	((struct smd_half_channel_word_access __force *)
+					(half_channel))->fDSR = data;
 }
 
-unsigned get_fDSR_word_access(volatile void *half_channel)
+unsigned get_fDSR_word_access(volatile void __iomem *half_channel)
 {
-	return ((struct smd_half_channel_word_access *)(half_channel))->fDSR;
+	return ((struct smd_half_channel_word_access __force *)
+					(half_channel))->fDSR;
 }
 
-void set_fCTS_word_access(volatile void *half_channel, unsigned char data)
+void set_fCTS_word_access(volatile void __iomem *half_channel,
+						unsigned char data)
 {
-	((struct smd_half_channel_word_access *)(half_channel))->fCTS = data;
+	((struct smd_half_channel_word_access __force *)
+					(half_channel))->fCTS = data;
 }
 
-unsigned get_fCTS_word_access(volatile void *half_channel)
+unsigned get_fCTS_word_access(volatile void __iomem *half_channel)
 {
-	return ((struct smd_half_channel_word_access *)(half_channel))->fCTS;
+	return ((struct smd_half_channel_word_access __force *)
+					(half_channel))->fCTS;
 }
 
-void set_fCD_word_access(volatile void *half_channel, unsigned char data)
+void set_fCD_word_access(volatile void __iomem *half_channel,
+						unsigned char data)
 {
-	((struct smd_half_channel_word_access *)(half_channel))->fCD = data;
+	((struct smd_half_channel_word_access __force *)
+					(half_channel))->fCD = data;
 }
 
-unsigned get_fCD_word_access(volatile void *half_channel)
+unsigned get_fCD_word_access(volatile void __iomem *half_channel)
 {
-	return ((struct smd_half_channel_word_access *)(half_channel))->fCD;
+	return ((struct smd_half_channel_word_access __force *)
+					(half_channel))->fCD;
 }
 
-void set_fRI_word_access(volatile void *half_channel, unsigned char data)
+void set_fRI_word_access(volatile void __iomem *half_channel,
+						unsigned char data)
 {
-	((struct smd_half_channel_word_access *)(half_channel))->fRI = data;
+	((struct smd_half_channel_word_access __force *)
+					(half_channel))->fRI = data;
 }
 
-unsigned get_fRI_word_access(volatile void *half_channel)
+unsigned get_fRI_word_access(volatile void __iomem *half_channel)
 {
-	return ((struct smd_half_channel_word_access *)(half_channel))->fRI;
+	return ((struct smd_half_channel_word_access __force *)
+					(half_channel))->fRI;
 }
 
-void set_fHEAD_word_access(volatile void *half_channel, unsigned char data)
+void set_fHEAD_word_access(volatile void __iomem *half_channel,
+						unsigned char data)
 {
-	((struct smd_half_channel_word_access *)(half_channel))->fHEAD = data;
+	((struct smd_half_channel_word_access __force *)
+					(half_channel))->fHEAD = data;
 }
 
-unsigned get_fHEAD_word_access(volatile void *half_channel)
+unsigned get_fHEAD_word_access(volatile void __iomem *half_channel)
 {
-	return ((struct smd_half_channel_word_access *)(half_channel))->fHEAD;
+	return ((struct smd_half_channel_word_access __force *)
+					(half_channel))->fHEAD;
 }
 
-void set_fTAIL_word_access(volatile void *half_channel, unsigned char data)
+void set_fTAIL_word_access(volatile void __iomem *half_channel,
+						unsigned char data)
 {
-	((struct smd_half_channel_word_access *)(half_channel))->fTAIL = data;
+	((struct smd_half_channel_word_access __force *)
+					(half_channel))->fTAIL = data;
 }
 
-unsigned get_fTAIL_word_access(volatile void *half_channel)
+unsigned get_fTAIL_word_access(volatile void __iomem *half_channel)
 {
-	return ((struct smd_half_channel_word_access *)(half_channel))->fTAIL;
+	return ((struct smd_half_channel_word_access __force *)
+					(half_channel))->fTAIL;
 }
 
-void set_fSTATE_word_access(volatile void *half_channel, unsigned char data)
+void set_fSTATE_word_access(volatile void __iomem *half_channel,
+						unsigned char data)
 {
-	((struct smd_half_channel_word_access *)(half_channel))->fSTATE = data;
+	((struct smd_half_channel_word_access __force *)
+					(half_channel))->fSTATE = data;
 }
 
-unsigned get_fSTATE_word_access(volatile void *half_channel)
+unsigned get_fSTATE_word_access(volatile void __iomem *half_channel)
 {
-	return ((struct smd_half_channel_word_access *)(half_channel))->fSTATE;
+	return ((struct smd_half_channel_word_access __force *)
+					(half_channel))->fSTATE;
 }
 
-void set_fBLOCKREADINTR_word_access(volatile void *half_channel,
+void set_fBLOCKREADINTR_word_access(volatile void __iomem *half_channel,
 							unsigned char data)
 {
-	((struct smd_half_channel_word_access *)
+	((struct smd_half_channel_word_access __force *)
 					(half_channel))->fBLOCKREADINTR = data;
 }
 
-unsigned get_fBLOCKREADINTR_word_access(volatile void *half_channel)
+unsigned get_fBLOCKREADINTR_word_access(volatile void __iomem *half_channel)
 {
-	return ((struct smd_half_channel_word_access *)
-						(half_channel))->fBLOCKREADINTR;
+	return ((struct smd_half_channel_word_access __force *)
+					(half_channel))->fBLOCKREADINTR;
 }
 
-void set_tail_word_access(volatile void *half_channel, unsigned data)
+void set_tail_word_access(volatile void __iomem *half_channel, unsigned data)
 {
-	((struct smd_half_channel_word_access *)(half_channel))->tail = data;
+	((struct smd_half_channel_word_access __force *)
+					(half_channel))->tail = data;
 }
 
-unsigned get_tail_word_access(volatile void *half_channel)
+unsigned get_tail_word_access(volatile void __iomem *half_channel)
 {
-	return ((struct smd_half_channel_word_access *)(half_channel))->tail;
+	return ((struct smd_half_channel_word_access __force *)
+					(half_channel))->tail;
 }
 
-void set_head_word_access(volatile void *half_channel, unsigned data)
+void set_head_word_access(volatile void __iomem *half_channel, unsigned data)
 {
-	((struct smd_half_channel_word_access *)(half_channel))->head = data;
+	((struct smd_half_channel_word_access __force *)
+					(half_channel))->head = data;
 }
 
-unsigned get_head_word_access(volatile void *half_channel)
+unsigned get_head_word_access(volatile void __iomem *half_channel)
 {
-	return ((struct smd_half_channel_word_access *)(half_channel))->head;
+	return ((struct smd_half_channel_word_access __force *)
+					(half_channel))->head;
 }
 
 int is_word_access_ch(unsigned ch_type)
diff --git a/arch/arm/mach-msm/smd_private.h b/arch/arm/mach-msm/smd_private.h
index 7f39a24..2033fbe 100644
--- a/arch/arm/mach-msm/smd_private.h
+++ b/arch/arm/mach-msm/smd_private.h
@@ -147,29 +147,36 @@
 };
 
 struct smd_half_channel_access {
-	void (*set_state)(volatile void *half_channel, unsigned data);
-	unsigned (*get_state)(volatile void *half_channel);
-	void (*set_fDSR)(volatile void *half_channel, unsigned char data);
-	unsigned (*get_fDSR)(volatile void *half_channel);
-	void (*set_fCTS)(volatile void *half_channel, unsigned char data);
-	unsigned (*get_fCTS)(volatile void *half_channel);
-	void (*set_fCD)(volatile void *half_channel, unsigned char data);
-	unsigned (*get_fCD)(volatile void *half_channel);
-	void (*set_fRI)(volatile void *half_channel, unsigned char data);
-	unsigned (*get_fRI)(volatile void *half_channel);
-	void (*set_fHEAD)(volatile void *half_channel, unsigned char data);
-	unsigned (*get_fHEAD)(volatile void *half_channel);
-	void (*set_fTAIL)(volatile void *half_channel, unsigned char data);
-	unsigned (*get_fTAIL)(volatile void *half_channel);
-	void (*set_fSTATE)(volatile void *half_channel, unsigned char data);
-	unsigned (*get_fSTATE)(volatile void *half_channel);
-	void (*set_fBLOCKREADINTR)(volatile void *half_channel,
+	void (*set_state)(volatile void __iomem *half_channel, unsigned data);
+	unsigned (*get_state)(volatile void __iomem *half_channel);
+	void (*set_fDSR)(volatile void __iomem *half_channel,
 					unsigned char data);
-	unsigned (*get_fBLOCKREADINTR)(volatile void *half_channel);
-	void (*set_tail)(volatile void *half_channel, unsigned data);
-	unsigned (*get_tail)(volatile void *half_channel);
-	void (*set_head)(volatile void *half_channel, unsigned data);
-	unsigned (*get_head)(volatile void *half_channel);
+	unsigned (*get_fDSR)(volatile void __iomem *half_channel);
+	void (*set_fCTS)(volatile void __iomem *half_channel,
+					unsigned char data);
+	unsigned (*get_fCTS)(volatile void __iomem *half_channel);
+	void (*set_fCD)(volatile void __iomem *half_channel,
+					unsigned char data);
+	unsigned (*get_fCD)(volatile void __iomem *half_channel);
+	void (*set_fRI)(volatile void __iomem *half_channel,
+					unsigned char data);
+	unsigned (*get_fRI)(volatile void __iomem *half_channel);
+	void (*set_fHEAD)(volatile void __iomem *half_channel,
+					unsigned char data);
+	unsigned (*get_fHEAD)(volatile void __iomem *half_channel);
+	void (*set_fTAIL)(volatile void __iomem *half_channel,
+					unsigned char data);
+	unsigned (*get_fTAIL)(volatile void __iomem *half_channel);
+	void (*set_fSTATE)(volatile void __iomem *half_channel,
+					unsigned char data);
+	unsigned (*get_fSTATE)(volatile void __iomem *half_channel);
+	void (*set_fBLOCKREADINTR)(volatile void __iomem *half_channel,
+					unsigned char data);
+	unsigned (*get_fBLOCKREADINTR)(volatile void __iomem *half_channel);
+	void (*set_tail)(volatile void __iomem *half_channel, unsigned data);
+	unsigned (*get_tail)(volatile void __iomem *half_channel);
+	void (*set_head)(volatile void __iomem *half_channel, unsigned data);
+	unsigned (*get_head)(volatile void __iomem *half_channel);
 };
 
 int is_word_access_ch(unsigned ch_type);
diff --git a/drivers/gpio/gpio-msm-common.c b/drivers/gpio/gpio-msm-common.c
index 150c434..3332fc5 100644
--- a/drivers/gpio/gpio-msm-common.c
+++ b/drivers/gpio/gpio-msm-common.c
@@ -24,6 +24,7 @@
 #include <linux/of.h>
 #include <linux/err.h>
 #include <linux/platform_device.h>
+#include <linux/slab.h>
 
 #include <asm/mach/irq.h>
 
@@ -48,7 +49,7 @@
 };
 #endif
 
-static int tlmm_msm_summary_irq;
+static int tlmm_msm_summary_irq, nr_direct_connect_irqs;
 
 struct tlmm_field_cfg {
 	enum msm_tlmm_register reg;
@@ -117,9 +118,9 @@
  */
 struct msm_gpio_dev {
 	struct gpio_chip gpio_chip;
-	DECLARE_BITMAP(enabled_irqs, NR_MSM_GPIOS);
-	DECLARE_BITMAP(wake_irqs, NR_MSM_GPIOS);
-	DECLARE_BITMAP(dual_edge_irqs, NR_MSM_GPIOS);
+	unsigned long *enabled_irqs;
+	unsigned long *wake_irqs;
+	unsigned long *dual_edge_irqs;
 	struct irq_domain *domain;
 };
 
@@ -207,7 +208,6 @@
 	.gpio_chip = {
 		.label		  = "msmgpio",
 		.base             = 0,
-		.ngpio            = NR_MSM_GPIOS,
 		.direction_input  = msm_gpio_direction_input,
 		.direction_output = msm_gpio_direction_output,
 		.get              = msm_gpio_get,
@@ -362,12 +362,13 @@
 	unsigned long i;
 	struct irq_desc *desc = irq_to_desc(irq);
 	struct irq_chip *chip = irq_desc_get_chip(desc);
+	int ngpio = msm_gpio.gpio_chip.ngpio;
 
 	chained_irq_enter(chip, desc);
 
-	for (i = find_first_bit(msm_gpio.enabled_irqs, NR_MSM_GPIOS);
-	     i < NR_MSM_GPIOS;
-	     i = find_next_bit(msm_gpio.enabled_irqs, NR_MSM_GPIOS, i + 1)) {
+	for (i = find_first_bit(msm_gpio.enabled_irqs, ngpio);
+	     i < ngpio;
+	     i = find_next_bit(msm_gpio.enabled_irqs, ngpio, i + 1)) {
 		if (__msm_gpio_get_intr_status(i))
 			generic_handle_irq(msm_gpio_to_irq(&msm_gpio.gpio_chip,
 							   i));
@@ -380,14 +381,15 @@
 static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
 {
 	int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
+	int ngpio = msm_gpio.gpio_chip.ngpio;
 
 	if (on) {
-		if (bitmap_empty(msm_gpio.wake_irqs, NR_MSM_GPIOS))
+		if (bitmap_empty(msm_gpio.wake_irqs, ngpio))
 			irq_set_irq_wake(tlmm_msm_summary_irq, 1);
 		set_bit(gpio, msm_gpio.wake_irqs);
 	} else {
 		clear_bit(gpio, msm_gpio.wake_irqs);
-		if (bitmap_empty(msm_gpio.wake_irqs, NR_MSM_GPIOS))
+		if (bitmap_empty(msm_gpio.wake_irqs, ngpio))
 			irq_set_irq_wake(tlmm_msm_summary_irq, 0);
 	}
 
@@ -412,12 +414,13 @@
 {
 	unsigned long irq_flags;
 	unsigned long i;
+	int ngpio = msm_gpio.gpio_chip.ngpio;
 
 	spin_lock_irqsave(&tlmm_lock, irq_flags);
-	for_each_set_bit(i, msm_gpio.enabled_irqs, NR_MSM_GPIOS)
+	for_each_set_bit(i, msm_gpio.enabled_irqs, ngpio)
 		__msm_gpio_set_intr_cfg_enable(i, 0);
 
-	for_each_set_bit(i, msm_gpio.wake_irqs, NR_MSM_GPIOS)
+	for_each_set_bit(i, msm_gpio.wake_irqs, ngpio)
 		__msm_gpio_set_intr_cfg_enable(i, 1);
 	mb();
 	spin_unlock_irqrestore(&tlmm_lock, irq_flags);
@@ -428,12 +431,13 @@
 {
 	unsigned long irq_flags;
 	int i, irq, intstat;
+	int ngpio = msm_gpio.gpio_chip.ngpio;
 
 	if (!msm_show_resume_irq_mask)
 		return;
 
 	spin_lock_irqsave(&tlmm_lock, irq_flags);
-	for_each_set_bit(i, msm_gpio.wake_irqs, NR_MSM_GPIOS) {
+	for_each_set_bit(i, msm_gpio.wake_irqs, ngpio) {
 		intstat = __msm_gpio_get_intr_status(i);
 		if (intstat) {
 			irq = msm_gpio_to_irq(&msm_gpio.gpio_chip, i);
@@ -448,14 +452,15 @@
 {
 	unsigned long irq_flags;
 	unsigned long i;
+	int ngpio = msm_gpio.gpio_chip.ngpio;
 
 	msm_gpio_show_resume_irq();
 
 	spin_lock_irqsave(&tlmm_lock, irq_flags);
-	for_each_set_bit(i, msm_gpio.wake_irqs, NR_MSM_GPIOS)
+	for_each_set_bit(i, msm_gpio.wake_irqs, ngpio)
 		__msm_gpio_set_intr_cfg_enable(i, 0);
 
-	for_each_set_bit(i, msm_gpio.enabled_irqs, NR_MSM_GPIOS)
+	for_each_set_bit(i, msm_gpio.enabled_irqs, ngpio)
 		__msm_gpio_set_intr_cfg_enable(i, 1);
 	mb();
 	spin_unlock_irqrestore(&tlmm_lock, irq_flags);
@@ -502,8 +507,9 @@
 int gpio_tlmm_config(unsigned config, unsigned disable)
 {
 	unsigned gpio = GPIO_PIN(config);
+	int ngpio = msm_gpio.gpio_chip.ngpio;
 
-	if (gpio > NR_MSM_GPIOS)
+	if (gpio > ngpio)
 		return -EINVAL;
 
 	__gpio_tlmm_config(config);
@@ -517,8 +523,9 @@
 					unsigned int input_polarity)
 {
 	unsigned long irq_flags;
+	int ngpio = msm_gpio.gpio_chip.ngpio;
 
-	if (gpio >= NR_MSM_GPIOS || irq >= NR_TLMM_MSM_DIR_CONN_IRQ)
+	if (gpio >= ngpio || irq >= nr_direct_connect_irqs)
 		return -EINVAL;
 
 	spin_lock_irqsave(&tlmm_lock, irq_flags);
@@ -536,37 +543,89 @@
  */
 static struct lock_class_key msm_gpio_lock_class;
 
+static inline void msm_gpio_set_irq_handler(struct device *dev)
+{
+	int irq, i;
+
+	if (!dev->of_node) {
+		for (i = 0; i < msm_gpio.gpio_chip.ngpio; ++i) {
+			irq = msm_gpio_to_irq(&msm_gpio.gpio_chip, i);
+			irq_set_lockdep_class(irq, &msm_gpio_lock_class);
+			irq_set_chip_and_handler(irq, &msm_gpio_irq_chip,
+						 handle_level_irq);
+			set_irq_flags(irq, IRQF_VALID);
+		}
+	}
+}
+
 static int __devinit msm_gpio_probe(struct platform_device *pdev)
 {
-	int ret;
-#ifndef CONFIG_OF
-	int irq, i;
-#endif
+	int ret, ngpio = 0;
+	struct msm_gpio_pdata *pdata = pdev->dev.platform_data;
+
+	if (pdev->dev.of_node) {
+		ret = of_property_read_u32(pdev->dev.of_node, "ngpio", &ngpio);
+		if (ret) {
+			pr_err("%s: Failed to find ngpio property\n", __func__);
+			return ret;
+		}
+		ret = of_property_read_u32(pdev->dev.of_node,
+					"qcom,direct-connect-irqs",
+					&nr_direct_connect_irqs);
+		if (ret) {
+			pr_err("%s: Failed to find qcom,direct-connect-irqs property\n"
+				, __func__);
+			return ret;
+		}
+	} else {
+		ngpio = pdata->ngpio;
+		nr_direct_connect_irqs = pdata->direct_connect_irqs;
+	}
+
 	tlmm_msm_summary_irq = platform_get_irq(pdev, 0);
 	if (tlmm_msm_summary_irq < 0) {
 		pr_err("%s: No interrupt defined for msmgpio\n", __func__);
 		return -ENXIO;
 	}
+
 	msm_gpio.gpio_chip.dev = &pdev->dev;
+	msm_gpio.gpio_chip.ngpio = ngpio;
 	spin_lock_init(&tlmm_lock);
-	bitmap_zero(msm_gpio.enabled_irqs, NR_MSM_GPIOS);
-	bitmap_zero(msm_gpio.wake_irqs, NR_MSM_GPIOS);
-	bitmap_zero(msm_gpio.dual_edge_irqs, NR_MSM_GPIOS);
+	msm_gpio.enabled_irqs = devm_kzalloc(&pdev->dev, sizeof(unsigned long)
+					* BITS_TO_LONGS(ngpio), GFP_KERNEL);
+	if (!msm_gpio.enabled_irqs) {
+		dev_err(&pdev->dev, "%s failed to allocated enabled_irqs bitmap\n"
+				, __func__);
+		return -ENOMEM;
+	}
+
+	msm_gpio.wake_irqs = devm_kzalloc(&pdev->dev, sizeof(unsigned long) *
+					BITS_TO_LONGS(ngpio), GFP_KERNEL);
+	if (!msm_gpio.wake_irqs) {
+		dev_err(&pdev->dev, "%s failed to allocated wake_irqs bitmap\n"
+				, __func__);
+		return -ENOMEM;
+	}
+	msm_gpio.dual_edge_irqs = devm_kzalloc(&pdev->dev, sizeof(unsigned long)
+					* BITS_TO_LONGS(ngpio), GFP_KERNEL);
+	if (!msm_gpio.dual_edge_irqs) {
+		dev_err(&pdev->dev, "%s failed to allocated dual_edge_irqs bitmap\n"
+				, __func__);
+		return -ENOMEM;
+	}
+
+	bitmap_zero(msm_gpio.enabled_irqs, ngpio);
+	bitmap_zero(msm_gpio.wake_irqs, ngpio);
+	bitmap_zero(msm_gpio.dual_edge_irqs, ngpio);
 	ret = gpiochip_add(&msm_gpio.gpio_chip);
 	if (ret < 0)
 		return ret;
 
-#ifndef CONFIG_OF
-	for (i = 0; i < msm_gpio.gpio_chip.ngpio; ++i) {
-		irq = msm_gpio_to_irq(&msm_gpio.gpio_chip, i);
-		irq_set_lockdep_class(irq, &msm_gpio_lock_class);
-		irq_set_chip_and_handler(irq, &msm_gpio_irq_chip,
-					 handle_level_irq);
-		set_irq_flags(irq, IRQF_VALID);
-	}
-#endif
-	ret = request_irq(tlmm_msm_summary_irq, msm_summary_irq_handler,
-			IRQF_TRIGGER_HIGH, "msmgpio", NULL);
+	msm_gpio_set_irq_handler(&pdev->dev);
+
+	ret = devm_request_irq(&pdev->dev, tlmm_msm_summary_irq,
+			msm_summary_irq_handler, IRQF_TRIGGER_HIGH,
+			"msmgpio", NULL);
 	if (ret) {
 		pr_err("Request_irq failed for tlmm_msm_summary_irq - %d\n",
 				ret);
@@ -658,7 +717,14 @@
 int __init msm_gpio_of_init(struct device_node *node,
 			    struct device_node *parent)
 {
-	msm_gpio.domain = irq_domain_add_linear(node, NR_MSM_GPIOS,
+	int ngpio, ret;
+
+	ret = of_property_read_u32(node, "ngpio", &ngpio);
+	if (ret) {
+		WARN(1, "Cannot get numgpios from device tree\n");
+		return ret;
+	}
+	msm_gpio.domain = irq_domain_add_linear(node, ngpio,
 			&msm_gpio_irq_domain_ops, &msm_gpio);
 	if (!msm_gpio.domain) {
 		WARN(1, "Cannot allocate irq_domain\n");
diff --git a/drivers/iommu/msm_iommu.c b/drivers/iommu/msm_iommu.c
index 1ce1cf8..38e6fb7 100644
--- a/drivers/iommu/msm_iommu.c
+++ b/drivers/iommu/msm_iommu.c
@@ -428,7 +428,7 @@
 
 	if (!priv || !dev) {
 		ret = -EINVAL;
-		goto fail;
+		goto unlock;
 	}
 
 	iommu_drvdata = dev_get_drvdata(dev->parent);
@@ -436,23 +436,28 @@
 
 	if (!iommu_drvdata || !ctx_drvdata) {
 		ret = -EINVAL;
-		goto fail;
+		goto unlock;
 	}
 
+	++ctx_drvdata->attach_count;
+
+	if (ctx_drvdata->attach_count > 1)
+		goto unlock;
+
 	if (!list_empty(&ctx_drvdata->attached_elm)) {
 		ret = -EBUSY;
-		goto fail;
+		goto unlock;
 	}
 
 	list_for_each_entry(tmp_drvdata, &priv->list_attached, attached_elm)
 		if (tmp_drvdata == ctx_drvdata) {
 			ret = -EBUSY;
-			goto fail;
+			goto unlock;
 		}
 
 	ret = __enable_clocks(iommu_drvdata);
 	if (ret)
-		goto fail;
+		goto unlock;
 
 	__program_context(iommu_drvdata->base, iommu_drvdata->glb_base,
 			  ctx_drvdata->num, iommu_drvdata->ncb,
@@ -463,7 +468,7 @@
 	list_add(&(ctx_drvdata->attached_elm), &priv->list_attached);
 
 	ctx_drvdata->attached_domain = domain;
-fail:
+unlock:
 	mutex_unlock(&msm_iommu_lock);
 	return ret;
 }
@@ -472,7 +477,6 @@
 				 struct device *dev)
 {
 	struct msm_priv *priv;
-	struct msm_iommu_ctx_dev *ctx_dev;
 	struct msm_iommu_drvdata *iommu_drvdata;
 	struct msm_iommu_ctx_drvdata *ctx_drvdata;
 	int ret;
@@ -481,33 +485,38 @@
 	priv = domain->priv;
 
 	if (!priv || !dev)
-		goto fail;
+		goto unlock;
 
 	iommu_drvdata = dev_get_drvdata(dev->parent);
 	ctx_drvdata = dev_get_drvdata(dev);
-	ctx_dev = dev->platform_data;
 
-	if (!iommu_drvdata || !ctx_drvdata || !ctx_dev)
-		goto fail;
+	if (!iommu_drvdata || !ctx_drvdata)
+		goto unlock;
+
+	--ctx_drvdata->attach_count;
+	BUG_ON(ctx_drvdata->attach_count < 0);
+
+	if (ctx_drvdata->attach_count > 0)
+		goto unlock;
 
 	ret = __enable_clocks(iommu_drvdata);
 	if (ret)
-		goto fail;
+		goto unlock;
 
 	msm_iommu_remote_spin_lock();
 
-	SET_TLBIASID(iommu_drvdata->base, ctx_dev->num,
-		     GET_CONTEXTIDR_ASID(iommu_drvdata->base, ctx_dev->num));
+	SET_TLBIASID(iommu_drvdata->base, ctx_drvdata->num,
+		    GET_CONTEXTIDR_ASID(iommu_drvdata->base, ctx_drvdata->num));
 
 	__reset_context(iommu_drvdata->base, iommu_drvdata->glb_base,
-			ctx_dev->num);
+			ctx_drvdata->num);
 
 	msm_iommu_remote_spin_unlock();
 
 	__disable_clocks(iommu_drvdata);
 	list_del_init(&ctx_drvdata->attached_elm);
 	ctx_drvdata->attached_domain = NULL;
-fail:
+unlock:
 	mutex_unlock(&msm_iommu_lock);
 }
 
diff --git a/drivers/iommu/msm_iommu_dev.c b/drivers/iommu/msm_iommu_dev.c
index 44fe454..470d8ce 100644
--- a/drivers/iommu/msm_iommu_dev.c
+++ b/drivers/iommu/msm_iommu_dev.c
@@ -489,6 +489,7 @@
 	ctx_drvdata->pdev = pdev;
 	INIT_LIST_HEAD(&ctx_drvdata->attached_elm);
 	platform_set_drvdata(pdev, ctx_drvdata);
+	ctx_drvdata->attach_count = 0;
 
 	if (pdev->dev.of_node) {
 		ret = msm_iommu_ctx_parse_dt(pdev, ctx_drvdata);
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index b748228..0f4cc6d 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -331,48 +331,6 @@
 	return ret;
 }
 
-static ssize_t
-min_sectors_to_check_bkops_status_show(struct device *dev,
-				  struct device_attribute *attr, char *buf)
-{
-	struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
-	unsigned int min_sectors_to_check_bkops_status;
-	struct mmc_card *card = md->queue.card;
-	int ret;
-
-	if (!card)
-		ret = -EINVAL;
-	else {
-	    min_sectors_to_check_bkops_status =
-		    card->bkops_info.min_sectors_to_queue_delayed_work;
-	    ret = snprintf(buf, PAGE_SIZE, "%d\n",
-			   min_sectors_to_check_bkops_status);
-	}
-
-	mmc_blk_put(md);
-	return ret;
-}
-
-static ssize_t
-min_sectors_to_check_bkops_status_store(struct device *dev,
-				 struct device_attribute *attr,
-				 const char *buf, size_t count)
-{
-	int value;
-	struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
-	struct mmc_card *card = md->queue.card;
-
-	if (!card)
-		return -EINVAL;
-
-	sscanf(buf, "%d", &value);
-	if (value >= 0)
-		card->bkops_info.min_sectors_to_queue_delayed_work = value;
-
-	mmc_blk_put(md);
-	return count;
-}
-
 static int mmc_blk_open(struct block_device *bdev, fmode_t mode)
 {
 	struct mmc_blk_data *md = mmc_blk_get(bdev->bd_disk);
@@ -1000,9 +958,6 @@
 	from = blk_rq_pos(req);
 	nr = blk_rq_sectors(req);
 
-	if (card->ext_csd.bkops_en)
-		card->bkops_info.sectors_changed += blk_rq_sectors(req);
-
 	if (mmc_can_discard(card))
 		arg = MMC_DISCARD_ARG;
 	else if (mmc_can_trim(card))
@@ -1702,12 +1657,8 @@
 			break;
 		}
 
-		if (rq_data_dir(next) == WRITE) {
+		if (rq_data_dir(next) == WRITE)
 			mq->num_of_potential_packed_wr_reqs++;
-			if (card->ext_csd.bkops_en)
-				card->bkops_info.sectors_changed +=
-					blk_rq_sectors(next);
-		}
 		list_add_tail(&next->queuelist, &mq->mqrq_cur->packed_list);
 		cur = next;
 		reqs++;
@@ -1940,8 +1891,6 @@
 		return 0;
 
 	if (rqc) {
-		if ((card->ext_csd.bkops_en) && (rq_data_dir(rqc) == WRITE))
-			card->bkops_info.sectors_changed += blk_rq_sectors(rqc);
 		reqs = mmc_blk_prep_packed_list(mq, rqc);
 	}
 
@@ -2110,9 +2059,15 @@
 	}
 #endif
 
-	if (req && !mq->mqrq_prev->req)
+	if (req && !mq->mqrq_prev->req) {
 		/* claim host only for the first request */
 		mmc_claim_host(card->host);
+		if (card->ext_csd.bkops_en &&
+		    card->bkops_info.started_delayed_bkops) {
+			card->bkops_info.started_delayed_bkops = false;
+			mmc_stop_bkops(card);
+		}
+	}
 
 	ret = mmc_blk_part_switch(card, md);
 	if (ret) {
@@ -2442,24 +2397,8 @@
 	if (ret)
 		goto num_wr_reqs_to_start_packing_fail;
 
-	md->min_sectors_to_check_bkops_status.show =
-		min_sectors_to_check_bkops_status_show;
-	md->min_sectors_to_check_bkops_status.store =
-		min_sectors_to_check_bkops_status_store;
-	sysfs_attr_init(&md->min_sectors_to_check_bkops_status.attr);
-	md->min_sectors_to_check_bkops_status.attr.name =
-		"min_sectors_to_check_bkops_status";
-	md->min_sectors_to_check_bkops_status.attr.mode = S_IRUGO | S_IWUSR;
-	ret = device_create_file(disk_to_dev(md->disk),
-				 &md->min_sectors_to_check_bkops_status);
-	if (ret)
-		goto min_sectors_to_check_bkops_status_fails;
-
 	return ret;
 
-min_sectors_to_check_bkops_status_fails:
-	device_remove_file(disk_to_dev(md->disk),
-			   &md->num_wr_reqs_to_start_packing);
 num_wr_reqs_to_start_packing_fail:
 	device_remove_file(disk_to_dev(md->disk), &md->power_ro_lock);
 power_ro_lock_fail:
diff --git a/drivers/mmc/card/mmc_block_test.c b/drivers/mmc/card/mmc_block_test.c
index 08c75a0..5d571a5 100644
--- a/drivers/mmc/card/mmc_block_test.c
+++ b/drivers/mmc/card/mmc_block_test.c
@@ -1244,9 +1244,9 @@
 		break;
 	case TEST_PACKING_NOT_EXP_LESS_THAN_TRIGGER_REQUESTS:
 	case TEST_PACKING_NOT_EXP_TRIGGER_REQUESTS:
-		mbtd->exp_packed_stats.packing_events[num_packed_reqs] = 1;
 		break;
 	default:
+		BUG_ON(num_packed_reqs < 0);
 		mbtd->exp_packed_stats.pack_stop_reason[EMPTY_QUEUE] = 1;
 		mbtd->exp_packed_stats.packing_events[num_packed_reqs] = 1;
 	}
@@ -1893,8 +1893,6 @@
 	case BKOPS_DELAYED_WORK_LEVEL_1:
 		bkops_stat->ignore_card_bkops_status = true;
 		card->ext_csd.raw_bkops_status = 1;
-		card->bkops_info.sectors_changed =
-			card->bkops_info.min_sectors_to_queue_delayed_work + 1;
 		mbtd->bkops_stage = BKOPS_STAGE_1;
 
 		__blk_run_queue(q);
@@ -1911,8 +1909,6 @@
 	case BKOPS_DELAYED_WORK_LEVEL_1_HPI:
 		bkops_stat->ignore_card_bkops_status = true;
 		card->ext_csd.raw_bkops_status = 1;
-		card->bkops_info.sectors_changed =
-			card->bkops_info.min_sectors_to_queue_delayed_work + 1;
 		mbtd->bkops_stage = BKOPS_STAGE_1;
 
 		__blk_run_queue(q);
@@ -1941,8 +1937,6 @@
 	case BKOPS_CANCEL_DELAYED_WORK:
 		bkops_stat->ignore_card_bkops_status = true;
 		card->ext_csd.raw_bkops_status = 1;
-		card->bkops_info.sectors_changed =
-			card->bkops_info.min_sectors_to_queue_delayed_work + 1;
 		mbtd->bkops_stage = BKOPS_STAGE_1;
 
 		__blk_run_queue(q);
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index 7b80dfb..dc27db6 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -89,17 +89,6 @@
 		spin_unlock_irq(q->queue_lock);
 
 		if (req || mq->mqrq_prev->req) {
-			/*
-			 * If this is the first request, BKOPs might be in
-			 * progress and needs to be stopped before issuing the
-			 * request
-			 */
-			if (card->ext_csd.bkops_en &&
-			    card->bkops_info.started_delayed_bkops) {
-				card->bkops_info.started_delayed_bkops = false;
-				mmc_stop_bkops(card);
-			}
-
 			set_current_state(TASK_RUNNING);
 			mq->issue_fn(mq, req);
 			if (mq->flags & MMC_QUEUE_NEW_REQUEST) {
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 1ea580e..864dfa7 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -357,15 +357,9 @@
 	if (!card || !card->ext_csd.bkops_en || mmc_card_doing_bkops(card))
 		return;
 
-	if (card->bkops_info.sectors_changed <
-	    card->bkops_info.min_sectors_to_queue_delayed_work)
-		return;
-
 	pr_debug("%s: %s: queueing delayed_bkops_work\n",
 		 mmc_hostname(card->host), __func__);
 
-	card->bkops_info.sectors_changed = 0;
-
 	/*
 	 * cancel_delayed_bkops_work will prevent a race condition between
 	 * fetching a request by the mmcqd and the delayed work, in case
@@ -931,8 +925,6 @@
 
 	BUG_ON(!card);
 
-	mmc_claim_host(card->host);
-
 	/*
 	 * Notify the delayed work to be cancelled, in case it was already
 	 * removed from the queue, but was not started yet
@@ -957,7 +949,6 @@
 	MMC_UPDATE_BKOPS_STATS_HPI(card->bkops_info.bkops_stats);
 
 out:
-	mmc_release_host(card->host);
 	return err;
 }
 EXPORT_SYMBOL(mmc_stop_bkops);
@@ -3238,7 +3229,9 @@
 	case PM_HIBERNATION_PREPARE:
 	case PM_SUSPEND_PREPARE:
 		if (host->card && mmc_card_mmc(host->card)) {
+			mmc_claim_host(host);
 			err = mmc_stop_bkops(host->card);
+			mmc_release_host(host);
 			if (err) {
 				pr_err("%s: didn't stop bkops\n",
 					mmc_hostname(host));
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index c1a6b28..f3653b8 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1413,9 +1413,6 @@
 				card->bkops_info.delay_ms = min(
 					card->bkops_info.delay_ms,
 				      card->bkops_info.host_suspend_tout_ms/2);
-
-			card->bkops_info.min_sectors_to_queue_delayed_work =
-				BKOPS_MIN_SECTORS_TO_QUEUE_DELAYED_WORK;
 		}
 	}
 
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index 12bdf30..874ef0d 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -1716,6 +1716,8 @@
 
 	chg_time_sec = DIV_ROUND_UP(the_chip->charge_time_us, USEC_PER_SEC);
 	catch_up_sec = DIV_ROUND_UP(the_chip->catch_up_time_us, USEC_PER_SEC);
+	if (catch_up_sec == 0)
+		return new_soc;
 	pr_debug("cts= %d catch_up_sec = %d\n", chg_time_sec, catch_up_sec);
 
 	/*
@@ -2012,8 +2014,7 @@
 	}
 
 	/* last_soc < soc  ... scale and catch up */
-	if (last_soc != -EINVAL && last_soc < soc && soc != 100
-				&& chip->catch_up_time_us != 0)
+	if (last_soc != -EINVAL && last_soc < soc && soc != 100)
 		soc = scale_soc_while_chg(chip, delta_time_us, soc, last_soc);
 
 	last_soc = soc;
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index bd62cf1..77db1f6 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -2538,7 +2538,11 @@
 			break;
 		}
 	}
-	pm_chg_masked_write(chip, ovpreg, OVP_DEBOUNCE_TIME, 0x2);
+	if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917)
+		pm_chg_masked_write(chip, ovpreg, OVP_DEBOUNCE_TIME, 0x6);
+	else
+		pm_chg_masked_write(chip, ovpreg, OVP_DEBOUNCE_TIME, 0x2);
+
 	pr_debug("Exit count=%d chg_gone=%d, active_valid=%d\n",
 		count, chg_gone, active_chg_plugged_in);
 	return;
@@ -4237,8 +4241,16 @@
 			pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0xAC);
 	}
 
-	/* Enable isub_fine resolution AICL for PM8917 */
 	if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917) {
+		/* Set PM8917 USB_OVP debounce time to 15 ms */
+		rc = pm_chg_masked_write(chip, USB_OVP_CONTROL,
+			OVP_DEBOUNCE_TIME, 0x6);
+		if (rc) {
+			pr_err("Failed to set USB OVP db rc=%d\n", rc);
+			return rc;
+		}
+
+		/* Enable isub_fine resolution AICL for PM8917 */
 		chip->iusb_fine_res = true;
 		if (chip->uvd_voltage_mv) {
 			rc = pm_chg_uvd_threshold_set(chip,
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index 5dbf3c2..1bc027c 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -89,7 +89,7 @@
 struct soc_params {
 	int		fcc_uah;
 	int		cc_uah;
-	int		rbatt;
+	int		rbatt_mohm;
 	int		iavg_ua;
 	int		uuc_uah;
 	int		ocv_charge_uah;
@@ -174,6 +174,7 @@
 	unsigned int			vadc_v0625;
 	unsigned int			vadc_v1250;
 
+	int				ibat_max_ua;
 	int				prev_iavg_ua;
 	int				prev_uuc_iavg_ma;
 	int				prev_pc_unusable;
@@ -199,6 +200,7 @@
 	POWER_SUPPLY_PROP_ONLINE,
 	POWER_SUPPLY_PROP_CAPACITY,
 	POWER_SUPPLY_PROP_CURRENT_NOW,
+	POWER_SUPPLY_PROP_CURRENT_MAX,
 	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
 };
 
@@ -855,7 +857,7 @@
 		new_unusable_mv = chip->v_cutoff_uv/1000;
 
 	new_iavg_ma = (new_unusable_mv * 1000 - chip->v_cutoff_uv)
-						/ params->rbatt;
+						/ params->rbatt_mohm;
 	if (new_iavg_ma == 0)
 		new_iavg_ma = 1;
 	chip->prev_uuc_iavg_ma = new_iavg_ma;
@@ -1002,7 +1004,7 @@
 							/ params->fcc_uah;
 	if (soc_rbatt < 0)
 		soc_rbatt = 0;
-	params->rbatt = get_rbatt(chip, soc_rbatt, batt_temp);
+	params->rbatt_mohm = get_rbatt(chip, soc_rbatt, batt_temp);
 
 	calculate_iavg(chip, params->cc_uah, &params->iavg_ua);
 
@@ -1213,7 +1215,11 @@
 
 	delta_ocv_uv_limit = DIV_ROUND_CLOSEST(ibat_ua, 1000);
 
-	ocv_est_uv = vbat_uv + (ibat_ua * params->rbatt)/1000;
+	ocv_est_uv = vbat_uv + (ibat_ua * params->rbatt_mohm)/1000;
+
+	chip->ibat_max_ua = (ocv_est_uv - chip->v_cutoff_uv) * 1000
+					/ (params->rbatt_mohm);
+
 	pc_est = calculate_pc(chip, ocv_est_uv, batt_temp);
 	soc_est = div_s64((s64)params->fcc_uah * pc_est - params->uuc_uah*100,
 				(s64)params->fcc_uah - params->uuc_uah);
@@ -1308,7 +1314,7 @@
 	pr_debug("ibat_ua = %d, vbat_uv = %d, ocv_est_uv = %d, pc_est = %d, soc_est = %d, n = %d, delta_ocv_uv = %d, last_ocv_uv = %d, pc_new = %d, soc_new = %d, rbatt = %d, slope = %d\n",
 		ibat_ua, vbat_uv, ocv_est_uv, pc_est,
 		soc_est, n, delta_ocv_uv, chip->last_ocv_uv,
-		pc_new, soc_new, params->rbatt, slope);
+		pc_new, soc_new, params->rbatt_mohm, slope);
 
 	return soc;
 }
@@ -1713,10 +1719,15 @@
 	return report_state_of_charge(chip);
 }
 
+/* Returns estimated max current that the battery can supply in uA */
+static int get_prop_bms_current_max(struct qpnp_bms_chip *chip)
+{
+	return chip->ibat_max_ua;
+}
+
 /* Returns instantaneous current in uA */
 static int get_prop_bms_current_now(struct qpnp_bms_chip *chip)
 {
-	/* temporarily return 0 until a real algorithm is put in */
 	int rc, result_ua;
 
 	rc = get_battery_current(chip, &result_ua);
@@ -1771,6 +1782,9 @@
 	case POWER_SUPPLY_PROP_CURRENT_NOW:
 		val->intval = get_prop_bms_current_now(chip);
 		break;
+	case POWER_SUPPLY_PROP_CURRENT_MAX:
+		val->intval = get_prop_bms_current_max(chip);
+		break;
 	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
 		val->intval = get_prop_bms_charge_full_design(chip);
 		break;
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 005f789..0aa36f1 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -77,10 +77,12 @@
 #define CHGR_BAT_IF_PRES_STATUS			0x08
 #define CHGR_STATUS				0x09
 #define CHGR_BAT_IF_VCP				0x42
+#define CHGR_BAT_IF_BATFET_STS			0x0B
 #define CHGR_BAT_IF_BATFET_CTRL1		0x90
 #define CHGR_MISC_BOOT_DONE			0x42
 #define CHGR_BUCK_COMPARATOR_OVRIDE_3		0xED
-#define MISC_REVISION2				0x01
+#define CHGR_BUCK_MIN_PON			0x71
+#define REVISION4				0x3
 #define SEC_ACCESS				0xD0
 
 /* SMBB peripheral subtype values */
@@ -99,6 +101,7 @@
 #define CHGR_BOOT_DONE			BIT(7)
 #define CHGR_CHG_EN			BIT(7)
 #define CHGR_ON_BAT_FORCE_BIT		BIT(0)
+#define BAT_IF_BATFET_STS_BIT		BIT(7)
 
 /* Interrupt definitions */
 /* smbb_chg_interrupts */
@@ -143,8 +146,17 @@
 /* smbb_misc_interrupts */
 #define TFTWDOG_IRQ			BIT(0)
 
+/* smbb revision */
+#define SMBB_REVISION_1			0x0
+#define SMBB_REVISION_2			0x1
+#define SMBB_REVISION_3			0x3
+
 /* Workaround flags */
 #define CHG_FLAGS_VCP_WA		BIT(0)
+#define CHG_FLAGS_ARB_WA		BIT(1)
+
+/* ARB workaround */
+#define ARB_CHECK_WAIT_PERIOD_MS 200
 
 /**
  * struct qpnp_chg_chip - device information
@@ -174,6 +186,8 @@
  * @batt_psy:			power supply to export information to userspace
  * @flags:			flags to activate specific workarounds
  *				throughout the driver
+ * @arb_check_work:		checks for accidental reverse booting (ARB)
+ * @arb_wake_lock:		wake_lock for arb workaround
  *
  */
 struct qpnp_chg_chip {
@@ -208,6 +222,8 @@
 	struct power_supply		*bms_psy;
 	struct power_supply		batt_psy;
 	uint32_t			flags;
+	struct delayed_work		arb_check_work;
+	struct wake_lock		arb_wake_lock;
 };
 
 static struct of_device_id qpnp_charger_match_table[] = {
@@ -421,8 +437,14 @@
 
 	if (chip->usb_present ^ usb_present) {
 		chip->usb_present = usb_present;
-		power_supply_set_present(chip->usb_psy,
-			chip->usb_present);
+		power_supply_set_present(chip->usb_psy, chip->usb_present);
+	}
+
+	if (usb_present && (chip->flags & CHG_FLAGS_ARB_WA)) {
+		wake_lock(&chip->arb_wake_lock);
+		schedule_delayed_work(&chip->arb_check_work,
+			round_jiffies_relative(msecs_to_jiffies
+				(ARB_CHECK_WAIT_PERIOD_MS)));
 	}
 
 	return IRQ_HANDLED;
@@ -1056,16 +1078,108 @@
 	temp = (voltage - QPNP_CHG_V_MIN_MV) / QPNP_CHG_V_STEP_MV;
 
 	pr_debug("voltage=%d setting %02x\n", voltage, temp);
-	return qpnp_chg_write(chip, &temp,
-		chip->chgr_base + CHGR_VDD_MAX, 1);
+	return qpnp_chg_write(chip, &temp, chip->chgr_base + CHGR_VDD_MAX, 1);
 }
 
-
-static void
-qpnp_chg_setup_flags(struct qpnp_chg_chip *chip)
+#define ARB_RETRY_COUNT		5
+#define ARB_SLEEP_MS		5
+#define ARB_VIN_MIN_MV		5500
+static void qpnp_chg_arb_check_worker(struct work_struct *work)
 {
-	if (chip->revision > 0)
+	struct delayed_work *dwork = to_delayed_work(work);
+	struct qpnp_chg_chip *chip = container_of(dwork,
+				struct qpnp_chg_chip, arb_check_work);
+	int rc = 0, i;
+	union power_supply_propval ret = {0,};
+	u8 batfet_sts;
+
+	if (!qpnp_chg_is_usb_chg_plugged_in(chip)) {
+		pr_debug("stopping worker usb disconnected\n");
+		wake_unlock(&chip->arb_wake_lock);
+		return;
+	}
+
+	if (chip->bms_psy) {
+		chip->bms_psy->get_property(chip->bms_psy,
+			  POWER_SUPPLY_PROP_CURRENT_NOW, &ret);
+
+		/* Charging so check later */
+		if (ret.intval < 0) {
+			pr_debug("charging - check again later\n");
+			goto check_again_later;
+		}
+	} else {
+		pr_err("no bms supply available - check again later\n");
+		goto check_again_later;
+	}
+
+	rc = qpnp_chg_read(chip, &batfet_sts,
+		chip->bat_if_base + CHGR_BAT_IF_BATFET_STS, 1);
+	if (rc)
+		pr_err("failed to batfet sts register rc=%d\n", rc);
+
+	if (!(batfet_sts & BAT_IF_BATFET_STS_BIT)) {
+		pr_debug("batfet off - check again later\n");
+		goto check_again_later;
+	}
+
+	pr_debug("Force to run charger on battery\n");
+
+	rc = qpnp_chg_force_run_on_batt(chip, 1);
+	if (rc)
+		pr_err("Failed to disable charging rc = %d\n", rc);
+
+	for (i = 0; i < ARB_RETRY_COUNT; i++) {
+		msleep(ARB_SLEEP_MS);
+		if (!qpnp_chg_is_usb_chg_plugged_in(chip))
+			break;
+	}
+
+	rc = qpnp_chg_force_run_on_batt(chip, 0);
+	if (rc)
+		pr_err("Failed to disable charging rc = %d\n", rc);
+
+	if (!qpnp_chg_is_usb_chg_plugged_in(chip)) {
+		pr_debug("Charger removal detected - stopping worker.\n");
+		wake_unlock(&chip->arb_wake_lock);
+		return;
+	}
+
+check_again_later:
+	schedule_delayed_work(&chip->arb_check_work,
+		round_jiffies_relative(msecs_to_jiffies
+			(ARB_CHECK_WAIT_PERIOD_MS)));
+}
+
+static int
+qpnp_chg_setup_flags_and_wa_init(struct qpnp_chg_chip *chip)
+{
+	int rc;
+	u8 reg;
+
+	rc = qpnp_chg_read(chip, &reg, chip->misc_base + REVISION4, 1);
+	if (rc) {
+		pr_err("failed to read revision register rc=%d\n", rc);
+		return rc;
+	}
+	chip->revision = reg;
+
+	/* Initialize first to avoid scheduling uninitialized work */
+	if (chip->revision <= SMBB_REVISION_2) {
+		wake_lock_init(&chip->arb_wake_lock, WAKE_LOCK_SUSPEND,
+			"qpnp-charger-arb-lock");
+		INIT_DELAYED_WORK(&chip->arb_check_work,
+			qpnp_chg_arb_check_worker);
+	}
+
+	/* Assign flags to enable them in various places of the driver */
+	if (chip->revision > SMBB_REVISION_1)
 		chip->flags |= CHG_FLAGS_VCP_WA;
+	if (chip->revision <= SMBB_REVISION_2)
+		chip->flags |= CHG_FLAGS_ARB_WA;
+	pr_debug("revision 0x%x flags 0x%x\n", chip->revision, chip->flags);
+
+	return rc;
 }
 
 #define WDOG_EN_BIT	BIT(7)
@@ -1074,7 +1188,6 @@
 				struct spmi_resource *spmi_resource)
 {
 	int rc = 0;
-	u8 reg;
 
 	switch (subtype) {
 	case SMBB_CHGR_SUBTYPE:
@@ -1211,14 +1324,7 @@
 		rc = qpnp_chg_masked_write(chip,
 			chip->misc_base + CHGR_MISC_BOOT_DONE,
 			CHGR_BOOT_DONE, CHGR_BOOT_DONE, 1);
-		rc = qpnp_chg_read(chip, &reg,
-				 chip->misc_base + MISC_REVISION2, 1);
-		if (rc) {
-			pr_err("failed to read revision register rc=%d\n", rc);
-			return rc;
-		}
 
-		chip->revision = reg;
 		break;
 	default:
 		pr_err("Invalid peripheral subtype\n");
@@ -1440,6 +1546,13 @@
 	chip->batt_psy.external_power_changed =
 				qpnp_batt_external_power_changed;
 
+	/* Turn on appropriate workaround flags */
+	rc = qpnp_chg_setup_flags_and_wa_init(chip);
+	if (rc) {
+		pr_err("failed to setup workaround flags rc=%d\n", rc);
+		goto fail_chg_enable;
+	}
+
 	rc = power_supply_register(chip->dev, &chip->dc_psy);
 	if (rc < 0) {
 		pr_err("power_supply_register usb failed rc = %d\n", rc);
@@ -1452,19 +1565,26 @@
 		goto unregister_dc;
 	}
 
-	/* Turn on appropriate workaround flags */
-	qpnp_chg_setup_flags(chip);
-
 	power_supply_set_present(chip->usb_psy,
 			qpnp_chg_is_usb_chg_plugged_in(chip));
 
 	qpnp_chg_charge_en(chip, !chip->charging_disabled);
 	qpnp_chg_force_run_on_batt(chip, chip->charging_disabled);
 
+	if (qpnp_chg_is_usb_chg_plugged_in(chip)
+			&& (chip->flags & CHG_FLAGS_ARB_WA)) {
+		wake_lock(&chip->arb_wake_lock);
+		schedule_delayed_work(&chip->arb_check_work,
+			round_jiffies_relative(msecs_to_jiffies
+				(ARB_CHECK_WAIT_PERIOD_MS)));
+	}
+
 	pr_info("Probe success !\n");
 	return 0;
 
 unregister_dc:
+	if (chip->flags & CHG_FLAGS_ARB_WA)
+		wake_lock_destroy(&chip->arb_wake_lock);
 	power_supply_unregister(&chip->dc_psy);
 fail_chg_enable:
 	kfree(chip);
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c
index a82feb9..f8c26ff 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c
@@ -280,6 +280,25 @@
 		return VCD_ERR_ILLEGAL_OP;
 	}
 	encoder = &ddl->codec_data.encoder;
+	if (DDL_IS_LTR_ENABLED(encoder)) {
+		DDL_MSG_HIGH("LTR enabled, mode %u count %u",
+			(u32)encoder->ltr_control.ltrmode.ltr_mode,
+			(u32)encoder->ltr_control.ltr_count);
+		status = ddl_allocate_ltr_list(&encoder->ltr_control);
+		if (status) {
+			DDL_MSG_ERROR("%s: allocate ltr list failed",
+				__func__);
+			return status;
+		} else {
+			ddl_clear_ltr_list(&encoder->ltr_control, false);
+		}
+		encoder->num_references_for_p_frame = 2;
+		encoder->ltr_control.callback_reqd = false;
+		encoder->ltr_control.curr_ltr_id = (u32)DDL_LTR_FRAME_START_ID;
+		DDL_MSG_HIGH("num_ref_for_p_frames %u, curr_ltr_id = %u",
+			(u32)encoder->num_references_for_p_frame,
+			(u32)encoder->ltr_control.curr_ltr_id);
+	}
 	status = ddl_allocate_enc_hw_buffers(ddl);
 	if (status)
 		return status;
@@ -393,7 +412,7 @@
 		(struct ddl_client_context *) ddl_handle;
 	struct ddl_context *ddl_context;
 	struct ddl_decoder_data *decoder;
-	DDL_MSG_HIGH("ddl_decode_frame");
+	DDL_MSG_MED("ddl_decode_frame");
 	ddl_context = ddl_get_context();
 	if (!DDL_IS_INITIALIZED(ddl_context)) {
 		DDL_MSG_ERROR("ddl_dec_frame:Not_inited");
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
index 8836b33..0404e82 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
@@ -52,6 +52,19 @@
 #define DDLCLIENT_STATE_IS(ddl, state) \
 	(state == (ddl)->client_state)
 
+#define DDL_IS_LTR_ENABLED(encoder) \
+	((encoder->ltr_control.ltrmode.ltr_mode == \
+		VCD_LTR_MODE_AUTO || \
+	encoder->ltr_control.ltrmode.ltr_mode == \
+		VCD_LTR_MODE_MANUAL) && \
+	(encoder->ltr_control.ltr_count > 0))
+
+#define DDL_IS_LTR_IN_AUTO_MODE(encoder) \
+	((encoder->ltr_control.ltrmode.ltr_mode == \
+		VCD_LTR_MODE_AUTO) && \
+	(encoder->ltr_control.ltr_count > 0) && \
+	(encoder->ltr_control.ltr_period > 0))
+
 #define DDL_DPB_OP_INIT       1
 #define DDL_DPB_OP_MARK_FREE  2
 #define DDL_DPB_OP_MARK_BUSY  3
@@ -72,6 +85,7 @@
 #define DDL_ENC_CHANGE_BITRATE    0x04
 #define DDL_ENC_CHANGE_FRAMERATE  0x08
 #define DDL_ENC_CHANGE_CIR        0x10
+#define DDL_ENC_LTR_USE_FRAME     0x20
 
 #define DDL_DEC_REQ_OUTPUT_FLUSH  0x1
 
@@ -86,6 +100,9 @@
 
 #define MDP_MIN_TILE_HEIGHT			96
 
+#define DDL_MAX_NUM_LTR_FRAMES                  2
+#define DDL_LTR_FRAME_START_ID                  1
+
 enum ddl_mem_area {
 	DDL_FW_MEM	= 0x0,
 	DDL_MM_MEM	= 0x1,
@@ -242,6 +259,43 @@
 	u32 seqdisp_extdump_enable;
 	u32 seq_extdump_enable;
 };
+
+
+struct ddl_ltrlist {
+	bool ltr_in_use;
+	u32 ltr_id;
+};
+
+struct ddl_ltr_encoding_type {
+	struct vcd_property_ltrmode_type  ltrmode;
+	struct vcd_property_ltruse_type  failed_use_cmd;
+	struct ddl_ltrlist *ltr_list;
+	u32 ltr_count;
+	u32 ltr_period;
+	u32 ltr_use_frames;
+	u32 curr_ltr_id;
+	u32 storing_idx;
+	u32 out_frame_cnt_to_use_this_ltr;
+	u32 out_frame_cnt_before_next_idr;
+	bool storing;
+	bool callback_reqd;
+	bool meta_data_reqd;
+	bool using;
+	bool first_ltr_use_arvd;
+	bool use_ltr_reqd;
+	bool store_for_intraframe_insertion;
+	bool pending_chg_ltr_useframes; /* True if
+		 * corresponding driver context of
+		 * out_frame_cnt_to_use_this_ltr
+		 * is pending to be changed with
+		 * client settings
+		 */
+	bool store_ltr0;
+	bool store_ltr1;
+	bool use_ltr0;
+	bool use_ltr1;
+};
+
 struct ddl_encoder_data{
 	struct ddl_codec_data_hdr   hdr;
 	struct vcd_property_codec   codec;
@@ -275,6 +329,7 @@
 	struct ddl_enc_buffers  hw_bufs;
 	struct ddl_yuv_buffer_size  input_buf_size;
 	struct vidc_1080p_enc_frame_info enc_frame_info;
+	struct ddl_ltr_encoding_type  ltr_control;
 	u32  plusptype_enable;
 	u32  meta_data_enable_flag;
 	u32  suffix;
@@ -291,6 +346,7 @@
 	u32  num_references_for_p_frame;
 	u32  closed_gop;
 	u32  num_slices_comp;
+	bool  intra_period_changed;
 	struct vcd_property_slice_delivery_info slice_delivery_info;
 	struct ddl_batch_frame_data batch_frame;
 	u32 avc_delimiter_enable;
@@ -496,7 +552,7 @@
 #ifdef DDL_BUF_LOG
 void ddl_list_buffers(struct ddl_client_context *ddl);
 #endif
-#ifdef DDL_MSG_LOG
+#if DDL_MSG_LOG
 s8 *ddl_get_state_string(enum ddl_client_state client_state);
 #endif
 extern unsigned char *vidc_video_codec_fw;
@@ -510,4 +566,21 @@
 void ddl_vidc_decode_reset_avg_time(struct ddl_client_context *ddl);
 void ddl_calc_core_proc_time(const char *func_name, u32 index,
 		struct ddl_client_context *ddl);
+s32 ddl_encoder_ltr_control(struct ddl_client_context *ddl);
+void ddl_encoder_use_ltr_fail_callback(
+	struct ddl_client_context *ddl);
+void ddl_handle_ltr_in_framedone(struct ddl_client_context *ddl);
+s32 ddl_clear_ltr_list(struct ddl_ltr_encoding_type *ltr_control,
+	bool only_use_flag);
+s32 ddl_find_oldest_ltr_not_in_use(
+	struct ddl_ltr_encoding_type *ltr_control);
+s32 ddl_find_ltr_in_use(struct ddl_ltr_encoding_type *ltr_control);
+s32 ddl_find_ltr_from_list(struct ddl_ltr_encoding_type *ltr_control,
+	u32 ltr_id);
+s32 ddl_use_ltr_from_list(struct ddl_ltr_encoding_type *ltr_control,
+	u32 ltr_idx);
+s32 ddl_allocate_ltr_list(struct ddl_ltr_encoding_type *ltr_control);
+s32 ddl_free_ltr_list(struct ddl_ltr_encoding_type *ltr_control);
+void ddl_print_ltr_list(struct ddl_ltr_encoding_type *ltr_control);
+
 #endif
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h
index db8a777..ddfd7e8 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h
@@ -154,4 +154,10 @@
 #define VIDC_SM_ERR_CONCEALMENT_INTER_SLICE_MB_COPY		2
 #define VIDC_SM_ERR_CONCEALMENT_INTRA_SLICE_COLOR_CONCEALMENT	1
 
+#define DDL_MAX_P_FRAMES_IN_INTRA_INTERVAL      0xffff
+
+#define DDL_SATURATE_P_FRAMES_IN_INTRA_INTERVAL(p_rames) \
+	(((p_rames) > (DDL_MAX_P_FRAMES_IN_INTRA_INTERVAL - 1)) ? \
+	(DDL_MAX_P_FRAMES_IN_INTRA_INTERVAL) : (p_rames))
+
 #endif
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
index 1782fd2..15b37a1b 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
@@ -22,7 +22,7 @@
 	return &ddl_context;
 }
 
-#ifdef DDL_MSG_LOG
+#if DDL_MSG_LOG
 s8 *ddl_get_state_string(enum ddl_client_state client_state)
 {
 	s8 *ptr;
@@ -265,7 +265,7 @@
 	luma_size = ddl_get_yuv_buf_size(decoder->frame_size.width,
 			decoder->frame_size.height, DDL_YUV_BUF_TYPE_TILE);
 	dpb = decoder->dp_buf.no_of_dec_pic_buf;
-	DDL_MSG_LOW("%s Decoder num DPB buffers = %u Luma Size = %u"
+	DDL_MSG_LOW("%s Decoder num DPB buffers = %u Luma Size = %u",
 				 __func__, dpb, luma_size);
 	if (dpb > DDL_MAX_BUFFER_COUNT)
 		dpb = DDL_MAX_BUFFER_COUNT;
@@ -298,7 +298,7 @@
 		luma[i] = DDL_OFFSET(ddl_context->dram_base_a.
 			align_physical_addr, frame[i].vcd_frm.physical);
 		chroma[i] = luma[i] + luma_size;
-		DDL_MSG_LOW("%s Decoder Luma address = %x Chroma address = %x"
+		DDL_MSG_LOW("%s Decoder Luma address = %x Chroma address = %x",
 					__func__, luma[i], chroma[i]);
 	}
 	switch (decoder->codec.codec) {
@@ -403,6 +403,7 @@
 		ddl_vidc_encode_dynamic_property(ddl, false);
 		encoder->dynamic_prop_change = 0;
 		ddl_free_enc_hw_buffers(ddl);
+		ddl_free_ltr_list(&encoder->ltr_control);
 	}
 	ddl_pmem_free(&ddl->shared_mem[0]);
 	ddl_pmem_free(&ddl->shared_mem[1]);
@@ -999,7 +1000,7 @@
 	u32 luma_size, i, dpb;
 	luma_size = decoder->dpb_buf_size.size_y;
 	dpb = decoder->dp_buf.no_of_dec_pic_buf;
-	DDL_MSG_HIGH("%s Decoder num DPB buffers = %u Luma Size = %u"
+	DDL_MSG_HIGH("%s Decoder num DPB buffers = %u Luma Size = %u",
 			 __func__, dpb, luma_size);
 	if (dpb > DDL_MAX_BUFFER_COUNT)
 		dpb = DDL_MAX_BUFFER_COUNT;
@@ -1137,8 +1138,295 @@
 				vidc_time_out = temp;
 		}
 	}
-	DDL_MSG_HIGH("%s Video core time out value = 0x%x",
+	DDL_MSG_LOW("%s Video core time out value = 0x%x",
 		 __func__, vidc_time_out);
 	vidc_sm_set_video_core_timeout_value(
 		&ddl->shared_mem[ddl->command_channel], vidc_time_out);
 }
+
+void ddl_handle_ltr_in_framedone(struct ddl_client_context *ddl)
+{
+	struct ddl_ltr_encoding_type *ltr_control =
+		&ddl->codec_data.encoder.ltr_control;
+	DDL_MSG_LOW("%s:", __func__);
+	if (ltr_control->storing) {
+		ltr_control->ltr_list[ltr_control->storing_idx].ltr_id =
+			ltr_control->curr_ltr_id;
+		DDL_MSG_MED("Encoder output stores LTR ID %d into entry %d",
+			ltr_control->curr_ltr_id, ltr_control->storing_idx);
+		ltr_control->meta_data_reqd = true;
+		ltr_control->storing = false;
+	}
+	ltr_control->out_frame_cnt_before_next_idr++;
+	if (ltr_control->out_frame_cnt_to_use_this_ltr) {
+		ltr_control->out_frame_cnt_to_use_this_ltr--;
+		if (!ltr_control->out_frame_cnt_to_use_this_ltr)
+			ddl_clear_ltr_list(ltr_control, true);
+	}
+}
+
+s32 ddl_encoder_ltr_control(struct ddl_client_context *ddl)
+{
+	s32 vcd_status = VCD_S_SUCCESS;
+	struct ddl_encoder_data *encoder = &ddl->codec_data.encoder;
+	struct ddl_ltr_encoding_type *ltr_ctrl = &encoder->ltr_control;
+	bool intra_period_reached = false;
+
+	DDL_MSG_LOW("%s:", __func__);
+	ddl_print_ltr_list(ltr_ctrl);
+
+	if (DDL_IS_LTR_IN_AUTO_MODE(encoder)) {
+		bool finite_i_period, infinite_i_period;
+		DDL_MSG_LOW("%s: before LTR encoding: output "\
+			"count before next IDR %d", __func__,
+			ltr_ctrl->out_frame_cnt_before_next_idr);
+		finite_i_period =
+			(DDL_MAX_P_FRAMES_IN_INTRA_INTERVAL !=
+			encoder->i_period.p_frames) &&
+			(!(ltr_ctrl->out_frame_cnt_before_next_idr %
+			(encoder->i_period.p_frames + 1)));
+		infinite_i_period =
+			((DDL_MAX_P_FRAMES_IN_INTRA_INTERVAL ==
+			encoder->i_period.p_frames) &&
+			(!ltr_ctrl->out_frame_cnt_before_next_idr));
+		if (finite_i_period || infinite_i_period) {
+			DDL_MSG_HIGH("%s: Intra period reached. "\
+			"finite_i_period (%u), infinite_i_period (%u)",
+			__func__, (u32)finite_i_period,
+			(u32)infinite_i_period);
+			intra_period_reached = true;
+		}
+		if (intra_period_reached ||
+			ltr_ctrl->store_for_intraframe_insertion ||
+			encoder->intra_period_changed) {
+			ddl_clear_ltr_list(ltr_ctrl, false);
+			ltr_ctrl->out_frame_cnt_before_next_idr = 0;
+			ltr_ctrl->first_ltr_use_arvd = false;
+			ltr_ctrl->store_for_intraframe_insertion = false;
+		} else {
+			if (ltr_ctrl->first_ltr_use_arvd == false) {
+				ddl_use_ltr_from_list(ltr_ctrl, 0);
+				ltr_ctrl->out_frame_cnt_to_use_this_ltr =
+					0xFFFFFFFF;
+				ltr_ctrl->use_ltr_reqd = true;
+			}
+		}
+		if (!(ltr_ctrl->out_frame_cnt_before_next_idr %
+			ltr_ctrl->ltr_period)) {
+			s32 idx;
+			DDL_MSG_HIGH("%s: reached LTR period "\
+				"out_frame_cnt_before_next_idr %d",
+				__func__, ltr_ctrl->\
+				out_frame_cnt_before_next_idr);
+			idx = ddl_find_oldest_ltr_not_in_use(
+					ltr_ctrl);
+			if (idx >= 0) {
+				ltr_ctrl->storing = true;
+				ltr_ctrl->storing_idx = idx;
+				if (idx == 0)
+					ltr_ctrl->store_ltr0 = true;
+				else if (idx == 1)
+					ltr_ctrl->store_ltr1 = true;
+			}
+		}
+	}
+	if (encoder->intra_frame_insertion) {
+		DDL_MSG_HIGH("%s: I-frame insertion requested, "\
+			"delay LTR store for one frame", __func__);
+		ltr_ctrl->store_for_intraframe_insertion = true;
+	}
+	if (ltr_ctrl->pending_chg_ltr_useframes) {
+		ltr_ctrl->out_frame_cnt_to_use_this_ltr =
+			ltr_ctrl->ltr_use_frames;
+		ltr_ctrl->pending_chg_ltr_useframes = false;
+	}
+	if (ltr_ctrl->out_frame_cnt_to_use_this_ltr)
+		ltr_ctrl->use_ltr_reqd = true;
+	if (ltr_ctrl->use_ltr_reqd) {
+		s32 idx;
+		idx = ddl_find_ltr_in_use(ltr_ctrl);
+		if (idx == 0)
+			ltr_ctrl->use_ltr0 = true;
+		else if (idx == 1)
+			ltr_ctrl->use_ltr1 = true;
+		ltr_ctrl->using = true;
+		ltr_ctrl->use_ltr_reqd = false;
+	} else {
+		DDL_MSG_HIGH("%s: use_ltr_reqd skipped", __func__);
+	}
+
+	return vcd_status;
+}
+
+
+s32 ddl_allocate_ltr_list(struct ddl_ltr_encoding_type *ltr_control)
+{
+	s32 vcd_status = VCD_S_SUCCESS;
+
+	DDL_MSG_LOW("%s: lrr_cout = %u", __func__, ltr_control->ltr_count);
+	if (!ltr_control->ltr_list) {
+		if (ltr_control->ltr_count) {
+			ltr_control->ltr_list = (struct ddl_ltrlist *)
+				kmalloc(sizeof(struct ddl_ltrlist)*
+					ltr_control->ltr_count, GFP_KERNEL);
+			if (!ltr_control->ltr_list) {
+				DDL_MSG_ERROR("ddl_allocate_ltr_list failed");
+				vcd_status = VCD_ERR_ALLOC_FAIL;
+			}
+		} else {
+			DDL_MSG_ERROR("%s: failed, zero LTR count", __func__);
+			vcd_status = VCD_ERR_FAIL;
+		}
+	} else {
+		DDL_MSG_HIGH("WARN: ltr_list already allocated");
+	}
+
+	return vcd_status;
+}
+
+s32 ddl_free_ltr_list(struct ddl_ltr_encoding_type *ltr_control)
+{
+	s32 vcd_status = VCD_S_SUCCESS;
+
+	DDL_MSG_LOW("%s:", __func__);
+	kfree(ltr_control->ltr_list);
+	ltr_control->ltr_list = NULL;
+
+	return vcd_status;
+}
+
+s32 ddl_clear_ltr_list(struct ddl_ltr_encoding_type *ltr_control,
+	bool only_use_flag)
+{
+	s32 vcd_status = VCD_S_SUCCESS;
+	u32 i;
+
+	DDL_MSG_LOW("%s:", __func__);
+	for (i = 0; i < ltr_control->ltr_count; i++) {
+		ltr_control->ltr_list[i].ltr_in_use = false;
+		if (!only_use_flag)
+			ltr_control->ltr_list[i].ltr_id = 0;
+	}
+
+	return vcd_status;
+}
+
+s32 ddl_find_oldest_ltr_not_in_use(struct ddl_ltr_encoding_type *ltr_control)
+{
+	s32 found_idx = -1;
+	u32 i;
+
+	if (ltr_control->ltr_list) {
+		if (ltr_control->ltr_count == 1)
+			found_idx = 0;
+		else {
+			for (i = 0; i < ltr_control->ltr_count; i++) {
+				if ((ltr_control->ltr_list[i].ltr_in_use ==
+					false) && (found_idx < 0)) {
+					found_idx = i;
+				}
+				if ((found_idx >= 0) &&
+					(ltr_control->ltr_list[i].\
+					ltr_in_use == false) &&
+					(ltr_control->ltr_list[i].ltr_id <
+					ltr_control->ltr_list[found_idx].\
+					ltr_id)) {
+					found_idx = i;
+				}
+			}
+		}
+	}
+
+	DDL_MSG_LOW("%s: found_idx = %d", __func__, found_idx);
+	return found_idx;
+}
+
+s32 ddl_find_ltr_in_use(struct ddl_ltr_encoding_type *ltr_control)
+{
+	s32 found_idx = -1;
+	u32 i;
+
+	if (ltr_control->ltr_list) {
+		for (i = 0; i < ltr_control->ltr_count; i++) {
+			if (ltr_control->ltr_list[i].ltr_in_use == true)
+				found_idx = i;
+		}
+	}
+
+	DDL_MSG_LOW("%s: found_idx = %d", __func__, found_idx);
+	return found_idx;
+}
+
+s32 ddl_find_ltr_from_list(struct ddl_ltr_encoding_type *ltr_control,
+	u32 ltr_id)
+{
+	s32 found_idx = -1;
+	u32 i;
+
+	if (ltr_control->ltr_list) {
+		for (i = 0; i < ltr_control->ltr_count; i++) {
+			if (ltr_control->ltr_list[i].ltr_id == ltr_id) {
+				found_idx = i;
+				break;
+			}
+		}
+	} else {
+		DDL_MSG_ERROR("%s: ltr_list is NULL", __func__);
+	}
+
+	DDL_MSG_LOW("%s: found_idx = %d", __func__, found_idx);
+	return found_idx;
+}
+
+s32 ddl_use_ltr_from_list(struct ddl_ltr_encoding_type *ltr_control,
+	u32 ltr_idx)
+{
+	s32 vcd_status = VCD_S_SUCCESS;
+	u32 i;
+
+	DDL_MSG_LOW("%s: ltr_idx = %u", __func__, ltr_idx);
+	if (ltr_idx > ltr_control->ltr_count) {
+		DDL_MSG_ERROR("%s: fail, idx %d larger than "\
+			"the list array count %d", __func__,
+			ltr_idx, ltr_control->ltr_count);
+		vcd_status = VCD_ERR_FAIL;
+	} else {
+		for (i = 0; i < ltr_control->ltr_count; i++) {
+			if (i == ltr_idx)
+				ltr_control->ltr_list[ltr_idx].ltr_in_use =
+					true;
+			else
+				ltr_control->ltr_list[i].ltr_in_use = false;
+		}
+	}
+
+	return vcd_status;
+}
+
+void ddl_encoder_use_ltr_fail_callback(struct ddl_client_context *ddl)
+{
+	struct ddl_encoder_data *encoder = &(ddl->codec_data.encoder);
+	struct ddl_context *ddl_context = ddl->ddl_context;
+
+	DDL_MSG_ERROR("%s: LTR use failed, callback "\
+		"requested with LTR ID %d", __func__,
+		encoder->ltr_control.failed_use_cmd.ltr_id);
+
+	ddl_context->ddl_callback(VCD_EVT_IND_INFO_LTRUSE_FAILED,
+			VCD_ERR_ILLEGAL_PARM,
+			&(encoder->ltr_control.failed_use_cmd),
+			sizeof(struct vcd_property_ltruse_type),
+			(u32 *)ddl,
+			ddl->client_data);
+}
+
+void ddl_print_ltr_list(struct ddl_ltr_encoding_type *ltr_control)
+{
+	u32 i;
+
+	for (i = 0; i < ltr_control->ltr_count; i++) {
+		DDL_MSG_MED("%s: ltr_id: %d, ltr_in_use: %d",
+			__func__, ltr_control->ltr_list[i].ltr_id,
+			ltr_control->ltr_list[i].ltr_in_use);
+	}
+}
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
index d189408..163af21 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
@@ -822,13 +822,13 @@
 			pixel_cache_stats;
 			vidc_pix_cache_get_statistics(&pixel_cache_stats);
 
-			DDL_MSG_HIGH(" pixel cache hits = %d,"
+			DDL_MSG_LOW(" pixel cache hits = %d,"
 				"miss = %d", pixel_cache_stats.access_hit,
 				pixel_cache_stats.access_miss);
-			DDL_MSG_HIGH(" pixel cache core reqs = %d,"
+			DDL_MSG_LOW(" pixel cache core reqs = %d,"
 				"axi reqs = %d", pixel_cache_stats.core_req,
 				pixel_cache_stats.axi_req);
-			DDL_MSG_HIGH(" pixel cache core bus stats = %d,"
+			DDL_MSG_LOW(" pixel cache core bus stats = %d,"
 			"axi bus stats = %d", pixel_cache_stats.core_bus,
 				pixel_cache_stats.axi_bus);
 		}
@@ -1313,7 +1313,7 @@
 			DDL_MSG_LOW("%s y_cb_cr_size = %u "
 				"actual_output_buf_req.sz = %u"
 				"min_output_buf_req.sz = %u\n",
-				decoder->y_cb_cr_size,
+				__func__, decoder->y_cb_cr_size,
 				decoder->actual_output_buf_req.sz,
 				decoder->min_output_buf_req.sz);
 			vidc_sm_set_chroma_addr_change(
@@ -1474,7 +1474,7 @@
 		}
 	} else
 		status = false;
-	DDL_MSG_HIGH("Enc Frame Type %u", (u32)frame->frame);
+	DDL_MSG_LOW("Enc Frame Type %u", (u32)frame->frame);
 	return status;
 }
 
@@ -1764,7 +1764,17 @@
 			(unsigned long) output_frame->alloc_len,
 			ION_IOC_INV_CACHES);
 	}
-	ddl_process_encoder_metadata(ddl);
+
+	if ((VIDC_1080P_ENCODE_FRAMETYPE_SKIPPED !=
+		encoder->enc_frame_info.enc_frame) &&
+		(VIDC_1080P_ENCODE_FRAMETYPE_NOT_CODED !=
+		encoder->enc_frame_info.enc_frame)) {
+		if (DDL_IS_LTR_ENABLED(encoder))
+			ddl_handle_ltr_in_framedone(ddl);
+		ddl_process_encoder_metadata(ddl);
+		encoder->ltr_control.meta_data_reqd = false;
+	}
+	encoder->ltr_control.using = false;
 	ddl_vidc_encode_dynamic_property(ddl, false);
 	ddl->input_frame.frm_trans_end = false;
 	input_buffer_address = ddl_context->dram_base_a.align_physical_addr +
@@ -1828,9 +1838,9 @@
 			encoder->batch_frame.output_frame[actual_idx].vcd_frm);
 		DDL_MSG_LOW("OutBfr: vcd_frm 0x%x frmbfr(virtual) 0x%x"
 			"frmbfr(physical) 0x%x\n",
-			&output_frame,
-			output_frame.virtual_base_addr,
-			output_frame.physical_base_addr);
+			(u32)output_frame,
+			(u32)output_frame->virtual,
+			(u32)output_frame->physical);
 		vidc_1080p_get_encode_frame_info(&encoder->enc_frame_info);
 		vidc_sm_get_frame_tags(&ddl->shared_mem
 			[ddl->command_channel],
@@ -1908,17 +1918,17 @@
 		actual_idx =
 			slice_output->slice_info[start_bfr_idx+index]. \
 			stream_buffer_idx;
-		DDL_MSG_LOW("Slice Info: OutBfrIndex %d SliceSize %d",
+		DDL_MSG_LOW("Slice Info: OutBfrIndex %u SliceSize %u",
 			actual_idx,
 			slice_output->slice_info[start_bfr_idx+index]. \
-			stream_buffer_size, 0);
+			stream_buffer_size);
 		output_frame =
 		&(encoder->batch_frame.output_frame[actual_idx].vcd_frm);
 		DDL_MSG_LOW("OutBfr: vcd_frm 0x%x frmbfr(virtual) 0x%x"
 				"frmbfr(physical) 0x%x",
-				&output_frame,
-				output_frame.virtual_base_addr,
-				output_frame.physical_base_addr);
+				(u32)output_frame,
+				(u32)output_frame->virtual,
+				(u32)output_frame->physical);
 		vidc_1080p_get_encode_frame_info(
 			&encoder->enc_frame_info);
 		vidc_sm_get_frame_tags(&ddl->shared_mem
@@ -1936,8 +1946,8 @@
 			slice_output->slice_info[actual_idx].stream_buffer_size;
 		ddl->output_frame =
 			encoder->batch_frame.output_frame[actual_idx];
-		DDL_MSG_LOW(" %s actual_idx = %d"
-		"encoder->batch_frame.num_output_frames = %d\n", __func__,
+		DDL_MSG_LOW("%s: actual_idx = %u "\
+		"encoder->batch_frame.num_output_frames = %u\n", __func__,
 		actual_idx, encoder->batch_frame.num_output_frames);
 		if (encoder->batch_frame.num_output_frames == (actual_idx+1)) {
 			output_frame->flags |= VCD_FRAME_FLAG_ENDOFFRAME;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.c
index f70c47c..1aee3d9 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.c
@@ -75,6 +75,9 @@
 		case VCD_METADATA_QCOMFILLER:
 			skip_words = 6;
 		break;
+		case VCD_METADATA_LTR_INFO:
+			skip_words = 9;
+		break;
 		}
 	}
 	buffer += skip_words;
@@ -146,17 +149,21 @@
 		hdr_entry[DDL_METADATA_HDR_VERSION_INDEX] = 0x00000101;
 		hdr_entry[DDL_METADATA_HDR_PORT_INDEX] = 1;
 		hdr_entry[DDL_METADATA_HDR_TYPE_INDEX] = VCD_METADATA_ENC_SLICE;
+
+		hdr_entry = ddl_metadata_hdr_entry(ddl, VCD_METADATA_LTR_INFO);
+		hdr_entry[DDL_METADATA_HDR_VERSION_INDEX] = 0x00000101;
+		hdr_entry[DDL_METADATA_HDR_PORT_INDEX] = 1;
+		hdr_entry[DDL_METADATA_HDR_TYPE_INDEX] = VCD_METADATA_LTR_INFO;
 	}
 }
 
 static u32 ddl_supported_metadata_flag(struct ddl_client_context *ddl)
 {
 	u32 flag = 0;
+	enum vcd_codec codec =
+		ddl->codec_data.decoder.codec.codec;
 
 	if (ddl->decoding) {
-		enum vcd_codec codec =
-			ddl->codec_data.decoder.codec.codec;
-
 		flag |= (VCD_METADATA_CONCEALMB | VCD_METADATA_PASSTHROUGH |
 				VCD_METADATA_QPARRAY);
 		if (codec == VCD_CODEC_H264)
@@ -167,8 +174,12 @@
 		else if (codec == VCD_CODEC_MPEG2)
 			flag |= (VCD_METADATA_USER_DATA |
 				VCD_METADATA_EXT_DATA);
-	} else
-		flag |= VCD_METADATA_ENC_SLICE;
+	} else {
+		if (codec == VCD_CODEC_H264)
+			flag |= VCD_METADATA_ENC_SLICE | VCD_METADATA_LTR_INFO;
+		else
+			flag |= VCD_METADATA_ENC_SLICE;
+	}
 	return flag;
 }
 
@@ -272,6 +283,12 @@
 		DDL_METADATA_ALIGNSIZE(size);
 		suffix += size;
 	}
+	if (flag & VCD_METADATA_LTR_INFO) {
+		size = DDL_METADATA_HDR_SIZE;
+		size += DDL_METADATA_LTR_INFO_PAYLOAD_SIZE;
+		DDL_METADATA_ALIGNSIZE(size);
+		suffix += size;
+	}
 	size = DDL_METADATA_EXTRADATANONE_SIZE;
 	DDL_METADATA_ALIGNSIZE(size);
 	suffix += (size);
@@ -497,27 +514,92 @@
 		&(ddl->output_frame.vcd_frm);
 	u32 *qfiller_hdr, *qfiller, start_addr;
 	u32 qfiller_size;
+	u8 *extradata_addr;
+	u32 metadata_available = false;
+
+	out_frame->flags &= ~(VCD_FRAME_FLAG_EXTRADATA);
 	if (!encoder->meta_data_enable_flag) {
-		out_frame->flags &= ~(VCD_FRAME_FLAG_EXTRADATA);
-		return;
+		DDL_MSG_HIGH("meta_data is not enabled");
+		goto exit;
 	}
-	if (!encoder->enc_frame_info.meta_data_exists) {
-		out_frame->flags &= ~(VCD_FRAME_FLAG_EXTRADATA);
-		return;
-	}
-	out_frame->flags |= VCD_FRAME_FLAG_EXTRADATA;
-	DDL_MSG_LOW("processing metadata for encoder");
 	start_addr = (u32) ((u8 *)out_frame->virtual + out_frame->offset);
-	qfiller = (u32 *)((out_frame->data_len +
+	extradata_addr = (u8 *)((out_frame->data_len +
 				start_addr + 3) & ~3);
+	qfiller = (u32 *)extradata_addr;
 	qfiller_size = (u32)((encoder->meta_data_offset +
 		(u8 *) out_frame->virtual) - (u8 *) qfiller);
+	if (qfiller_size & 3) {
+		DDL_MSG_ERROR("qfiller_size is not 4 bytes aligned");
+		goto exit;
+	}
 	qfiller_hdr = ddl_metadata_hdr_entry(ddl, VCD_METADATA_QCOMFILLER);
 	*qfiller++ = qfiller_size;
 	*qfiller++ = qfiller_hdr[DDL_METADATA_HDR_VERSION_INDEX];
 	*qfiller++ = qfiller_hdr[DDL_METADATA_HDR_PORT_INDEX];
 	*qfiller++ = qfiller_hdr[DDL_METADATA_HDR_TYPE_INDEX];
 	*qfiller = (u32)(qfiller_size - DDL_METADATA_HDR_SIZE);
+	extradata_addr += qfiller_size;
+	if ((u32)extradata_addr !=
+		(u32)((u8 *)start_addr + encoder->meta_data_offset)) {
+		DDL_MSG_ERROR("wrong qfiller size");
+		goto exit;
+	}
+	if (encoder->meta_data_enable_flag & VCD_METADATA_ENC_SLICE) {
+		u32 *sliceinfo = (u32 *)extradata_addr;
+		if (sliceinfo[3] != VCD_METADATA_ENC_SLICE) {
+			DDL_MSG_ERROR("wrong slice info extradata. " \
+				"data: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x",
+				sliceinfo[0], sliceinfo[1],	sliceinfo[2],
+				sliceinfo[3], sliceinfo[4],	sliceinfo[5]);
+			goto metadata_end;
+		}
+		extradata_addr += sliceinfo[0];
+		metadata_available = true;
+		DDL_MSG_HIGH("%s: Send %u slices info in metadata",
+			__func__, sliceinfo[5]);
+	}
+	if ((encoder->meta_data_enable_flag & VCD_METADATA_LTR_INFO) &&
+		(encoder->ltr_control.meta_data_reqd == true)) {
+		u32 *ltrinfo_hdr = ddl_metadata_hdr_entry(ddl,
+				VCD_METADATA_LTR_INFO);
+		u32 *ltrinfo = (u32 *)extradata_addr;
+		if ((u32)extradata_addr > (u32)((u8 *)out_frame->virtual +
+			out_frame->alloc_len)) {
+			metadata_available = false;
+			DDL_MSG_ERROR("Error: extradata_addr = 0x%p, "\
+				"buffer_start = 0x%p, size = %u",
+				extradata_addr, out_frame->virtual,
+				out_frame->alloc_len);
+			goto metadata_end;
+		}
+		ltrinfo[0] = DDL_METADATA_LTR_INFO_PAYLOAD_SIZE +
+				DDL_METADATA_HDR_SIZE;
+		ltrinfo[1] = ltrinfo_hdr[DDL_METADATA_HDR_VERSION_INDEX];
+		ltrinfo[2] = ltrinfo_hdr[DDL_METADATA_HDR_PORT_INDEX];
+		ltrinfo[3] = ltrinfo_hdr[DDL_METADATA_HDR_TYPE_INDEX];
+		ltrinfo[4] = DDL_METADATA_LTR_INFO_PAYLOAD_SIZE;
+		ltrinfo[5] = encoder->ltr_control.curr_ltr_id;
+		extradata_addr += ltrinfo[0];
+		encoder->ltr_control.curr_ltr_id++;
+		metadata_available = true;
+		DDL_MSG_HIGH("%s: Send curr_ltr_id = %u in metadata",
+			__func__, (u32)encoder->ltr_control.curr_ltr_id);
+	}
+metadata_end:
+	if (metadata_available == true) {
+		u32 *data_none_hdr = ddl_metadata_hdr_entry(ddl,
+				VCD_METADATA_DATANONE);
+		u32 *data_none = (u32 *)extradata_addr;
+		DDL_MSG_LOW("prepare metadata_none header");
+		data_none[0] = DDL_METADATA_EXTRADATANONE_SIZE;
+		data_none[1] = data_none_hdr[DDL_METADATA_HDR_VERSION_INDEX];
+		data_none[2] = data_none_hdr[DDL_METADATA_HDR_PORT_INDEX];
+		data_none[3] = data_none_hdr[DDL_METADATA_HDR_TYPE_INDEX];
+		data_none[4] = 0;
+		out_frame->flags |= VCD_FRAME_FLAG_EXTRADATA;
+	}
+exit:
+	return;
 }
 
 void ddl_process_decoder_metadata(struct ddl_client_context *ddl)
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.h
index e03a9b7..4426828 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.h
@@ -26,6 +26,7 @@
 #define DDL_METADATA_SEI_PAYLOAD_SIZE          100
 #define DDL_METADATA_SEI_MAX                     5
 #define DDL_METADATA_VUI_PAYLOAD_SIZE          256
+#define DDL_METADATA_LTR_INFO_PAYLOAD_SIZE     (4)
 #define DDL_METADATA_PASSTHROUGH_PAYLOAD_SIZE   68
 #define DDL_METADATA_EXT_PAYLOAD_SIZE         (640)
 #define DDL_METADATA_USER_PAYLOAD_SIZE        (2048)
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
index 2b65d7e..94ec12e 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
@@ -163,6 +163,28 @@
 		DDL_MSG_ERROR("H264BaseLineCABAC!!");
 		return false;
 	}
+	if (DDL_IS_LTR_ENABLED(encoder)) {
+		if ((encoder->codec.codec != VCD_CODEC_H264) ||
+			(encoder->i_period.b_frames)) {
+			DDL_MSG_ERROR("%s: Only support LTR encoding "\
+				"for H264 without B frame. Current "\
+				"codec %d, B-frame %d", __func__,
+				encoder->codec.codec,
+				encoder->i_period.b_frames);
+			return false;
+		}
+		if (encoder->ltr_control.ltrmode.ltr_mode ==
+				VCD_LTR_MODE_MANUAL) {
+			DDL_MSG_ERROR("%s: Manual LTR mode not supported!",
+				__func__);
+			return false;
+		}
+		DDL_MSG_HIGH("%s: LTR: mode = %u, count = %u, period = %u",
+			__func__, (u32)encoder->ltr_control.ltrmode.ltr_mode,
+			encoder->ltr_control.ltr_count,
+			encoder->ltr_control.ltr_period);
+	}
+
 	return true;
 }
 
@@ -617,8 +639,9 @@
 		struct vcd_property_multi_slice *multi_slice =
 			(struct vcd_property_multi_slice *)
 				property_value;
-		DDL_MSG_HIGH("VCD_I_MULTI_SLICE eMSliceSel %d  nMSliceSize %d"
-				"Tot#of MB %d encoder->frame_size.width = %d"
+		DDL_MSG_HIGH("VCD_I_MULTI_SLICE eMSliceSel %d  "\
+				"nMSliceSize %d Tot#of MB %d "\
+				"encoder->frame_size.width = %d "\
 				"encoder->frame_size.height = %d",
 				(int)multi_slice->m_slice_sel,
 				multi_slice->m_slice_size,
@@ -1044,6 +1067,41 @@
 		}
 		break;
 	}
+	case VCD_I_LTR_MODE:
+		if (sizeof(struct vcd_property_ltrmode_type) ==
+			property_hdr->sz && encoder->codec.codec ==
+			VCD_CODEC_H264) {
+			struct vcd_property_ltrmode_type *ltrmode =
+				(struct vcd_property_ltrmode_type *)
+				property_value;
+			encoder->ltr_control.ltrmode.ltr_mode =
+				ltrmode->ltr_mode;
+			DDL_MSG_HIGH("%s: set LTR mode = %u", __func__,
+				(u32)encoder->ltr_control.ltrmode.ltr_mode);
+			vcd_status = VCD_S_SUCCESS;
+		}
+	break;
+	case VCD_I_LTR_COUNT:
+		if (sizeof(struct vcd_property_ltrcount_type) ==
+			property_hdr->sz && encoder->codec.codec ==
+			VCD_CODEC_H264) {
+			struct vcd_property_ltrcount_type *ltrcount =
+				(struct vcd_property_ltrcount_type *)
+				property_value;
+			if (ltrcount->ltr_count > DDL_MAX_NUM_LTR_FRAMES) {
+				DDL_MSG_ERROR("%s: set LTR count failed. "\
+					"LTR count %u beyond maximum of %u",
+					__func__, ltrcount->ltr_count,
+					(u32)DDL_MAX_NUM_LTR_FRAMES);
+			} else {
+				encoder->ltr_control.ltr_count =
+					ltrcount->ltr_count;
+				DDL_MSG_HIGH("%s: set LTR count = %u", __func__,
+					encoder->ltr_control.ltr_count);
+				vcd_status = VCD_S_SUCCESS;
+			}
+		}
+	break;
 	case VCD_REQ_PERF_LEVEL:
 		vcd_status = VCD_S_SUCCESS;
 		break;
@@ -1091,7 +1149,8 @@
 		break;
 	}
 	default:
-		DDL_MSG_ERROR("INVALID ID %d\n", (int)property_hdr->prop_id);
+		DDL_MSG_ERROR("%s: unknown prop_id = 0x%x", __func__,
+			property_hdr->prop_id);
 		vcd_status = VCD_ERR_ILLEGAL_OP;
 	break;
 	}
@@ -1552,7 +1611,7 @@
 	break;
 	case VCD_I_METADATA_ENABLE:
 	case VCD_I_METADATA_HEADER:
-		DDL_MSG_ERROR("Meta Data Interface is Requested");
+		DDL_MSG_HIGH("Meta Data Interface is Requested");
 		vcd_status = ddl_get_metadata_params(ddl, property_hdr,
 			property_value);
 		vcd_status = VCD_S_SUCCESS;
@@ -1591,7 +1650,67 @@
 			vcd_status = VCD_S_SUCCESS;
 		}
 		break;
+	case VCD_I_CAPABILITY_LTR_COUNT:
+		if (sizeof(struct vcd_property_range_type) ==
+			property_hdr->sz) {
+			struct vcd_property_range_type capability_ltr_range;
+			capability_ltr_range.max = DDL_MAX_NUM_LTR_FRAMES;
+			capability_ltr_range.min = 1;
+			capability_ltr_range.step_size = 1;
+			*(struct vcd_property_range_type *)property_value =
+				capability_ltr_range;
+			DDL_MSG_HIGH("%s: capability_ltr_count = %u",
+				__func__, ((struct vcd_property_range_type *)
+				property_value)->max);
+			vcd_status = VCD_S_SUCCESS;
+		}
+	break;
+	case VCD_I_LTR_MODE:
+		if (sizeof(struct vcd_property_ltrmode_type) ==
+			property_hdr->sz) {
+			((struct vcd_property_ltrmode_type *)
+			property_value)->ltr_mode =
+				encoder->ltr_control.ltrmode.ltr_mode;
+			DDL_MSG_HIGH("%s: ltr_mode = %u", __func__,
+				(u32)(((struct vcd_property_ltrmode_type *)
+				property_value)->ltr_mode));
+			vcd_status = VCD_S_SUCCESS;
+		}
+	break;
+	case VCD_I_LTR_COUNT:
+		if (sizeof(struct vcd_property_ltrcount_type) ==
+			property_hdr->sz) {
+			struct vcd_property_ltrcount_type ltr_count;
+			ltr_count.ltr_count =
+				encoder->ltr_control.ltr_count;
+			*(struct vcd_property_ltrcount_type *)property_value =
+				ltr_count;
+			DDL_MSG_HIGH("%s: ltr_count = %u", __func__,
+				((struct vcd_property_ltrcount_type *)
+				property_value)->ltr_count);
+			vcd_status = VCD_S_SUCCESS;
+		}
+	break;
+	case VCD_I_LTR_PERIOD:
+		if (sizeof(struct vcd_property_ltrperiod_type) ==
+			property_hdr->sz) {
+			struct vcd_property_ltrperiod_type ltr_period;
+			if (!encoder->ltr_control.ltr_period)
+				ltr_period.ltr_period = 0;
+			else
+				ltr_period.ltr_period =
+					encoder->ltr_control.ltr_period - 1;
+			*(struct vcd_property_ltrperiod_type *)property_value =
+				ltr_period;
+			DDL_MSG_HIGH("%s: ltr_period = %u", __func__,
+				((struct vcd_property_ltrperiod_type *)
+				property_value)->ltr_period);
+			vcd_status = VCD_S_SUCCESS;
+		}
+	break;
 	default:
+		DDL_MSG_ERROR("%s: unknown prop_id = 0x%x", __func__,
+			property_hdr->prop_id);
 		vcd_status = VCD_ERR_ILLEGAL_OP;
 		break;
 	}
@@ -1680,6 +1799,77 @@
 		}
 	}
 	break;
+	case VCD_I_LTR_PERIOD:
+	{
+		if (sizeof(struct vcd_property_ltrperiod_type) ==
+			property_hdr->sz) {
+			struct vcd_property_ltrperiod_type *ltrperiod =
+				(struct vcd_property_ltrperiod_type *)
+				property_value;
+			encoder->ltr_control.ltr_period =
+				(ltrperiod->ltr_period == 0xFFFFFFFF) ?
+				0xFFFFFFFF : (ltrperiod->ltr_period + 1);
+			DDL_MSG_HIGH("%s: set ltr_period = %u", __func__,
+				encoder->ltr_control.ltr_period);
+			vcd_status = VCD_S_SUCCESS;
+		}
+	}
+	break;
+	case VCD_I_LTR_USE:
+	{
+		if (sizeof(struct vcd_property_ltruse_type) ==
+			property_hdr->sz) {
+			struct vcd_property_ltruse_type *ltruse =
+				(struct vcd_property_ltruse_type *)
+				property_value;
+			if (ltruse->ltr_id >= DDL_LTR_FRAME_START_ID) {
+				struct ddl_ltr_encoding_type *ltr_ctrl =
+					&encoder->ltr_control;
+				s32 idx;
+				idx = ddl_find_ltr_from_list(ltr_ctrl,
+					ltruse->ltr_id);
+				if (idx < 0) {
+					ltr_ctrl->callback_reqd = true;
+					ltr_ctrl->failed_use_cmd.ltr_id =
+						ltruse->ltr_id;
+					ltr_ctrl->failed_use_cmd.ltr_frames =
+						ltruse->ltr_frames;
+					DDL_MSG_ERROR("%s: index (%d) "\
+					"not found. Callback requested. "\
+					"ltr_id = %u, ltr_frames = %u",
+					__func__, idx, ltruse->ltr_id,
+					ltruse->ltr_frames);
+				} else {
+					ddl_use_ltr_from_list(ltr_ctrl, idx);
+					ltr_ctrl->ltr_use_frames =
+						ltruse->ltr_frames;
+					if (ltr_ctrl->using == false)
+						ltr_ctrl->\
+						out_frame_cnt_to_use_this_ltr =
+							ltruse->ltr_frames;
+					else
+						ltr_ctrl->\
+						pending_chg_ltr_useframes =
+							true;
+					ltr_ctrl->first_ltr_use_arvd = true;
+					ltr_ctrl->use_ltr_reqd = true;
+					DDL_MSG_HIGH("%s: index (%d) found. "\
+					"num frames to use this ltr_id (%u) "\
+					"is %u", __func__, idx,
+					ltruse->ltr_id, ltruse->ltr_frames);
+				}
+				dynamic_prop_change = DDL_ENC_LTR_USE_FRAME;
+				vcd_status = VCD_S_SUCCESS;
+			} else {
+				DDL_MSG_ERROR("%s: LTRUse ID %d failed. "\
+					"LTR ID starts from %d", __func__,
+					ltruse->ltr_id,
+					(u32)DDL_LTR_FRAME_START_ID);
+				vcd_status = VCD_ERR_ILLEGAL_OP;
+			}
+		}
+	}
+	break;
 	default:
 		vcd_status = VCD_ERR_ILLEGAL_OP;
 		break;
@@ -1747,6 +1937,9 @@
 	encoder->num_references_for_p_frame = DDL_MIN_NUM_REF_FOR_P_FRAME;
 	if (encoder->codec.codec == VCD_CODEC_MPEG4)
 		encoder->closed_gop = true;
+	encoder->intra_period_changed = false;
+	memset(&encoder->ltr_control, 0,
+		sizeof(struct ddl_ltr_encoding_type));
 	ddl_set_default_metadata_flag(ddl);
 	ddl_set_default_encoder_buffer_req(encoder);
 	encoder->slice_delivery_info.enable = 0;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
index de3fc4f..4c73bef 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
@@ -87,6 +87,8 @@
 #define VIDC_SM_ENC_EXT_CTRL_TIMING_INFO_EN_SHFT     14
 #define VIDC_SM_ENC_EXT_CTRL_AU_DELIMITER_EN_BMSK    0x00000800
 #define VIDC_SM_ENC_EXT_CTRL_AU_DELIMITER_EN_SHFT    11
+#define VIDC_SM_ENC_EXT_CTRL_LONG_TERM_REF_ENABLE_BMSK      0x00000400
+#define VIDC_SM_ENC_EXT_CTRL_LONG_TERM_REF_ENABLE_SHFT      10
 #define VIDC_SM_ENC_EXT_CTRL_H263_CPCFC_ENABLE_BMSK  0x80
 #define VIDC_SM_ENC_EXT_CTRL_H263_CPCFC_ENABLE_SHFT  7
 #define VIDC_SM_ENC_EXT_CTRL_SPS_PPS_CONTROL_BMSK    0X100
@@ -458,8 +460,8 @@
 	enum VIDC_SM_frame_skip frame_skip_mode,
 	u32 seq_hdr_in_band, u32 vbv_buffer_size, u32 cpcfc_enable,
 	u32 sps_pps_control, u32 closed_gop_enable,
-	u32 au_delim_enable,
-	u32 vui_timing_info_enable)
+	u32 au_delim_enable, u32 vui_timing_info_enable,
+	u32 ltr_enable)
 {
 	u32 enc_ctrl;
 	enc_ctrl = VIDC_SETFIELD((hec_enable) ? 1 : 0,
@@ -488,8 +490,10 @@
 			VIDC_SM_ENC_EXT_CTRL_AU_DELIMITER_EN_BMSK) |
 			VIDC_SETFIELD((vui_timing_info_enable) ? 1 : 0,
 			VIDC_SM_ENC_EXT_CTRL_TIMING_INFO_EN_SHFT,
-			VIDC_SM_ENC_EXT_CTRL_TIMING_INFO_EN_BMSK);
-
+			VIDC_SM_ENC_EXT_CTRL_TIMING_INFO_EN_BMSK) |
+			VIDC_SETFIELD((ltr_enable) ? 1 : 0,
+			VIDC_SM_ENC_EXT_CTRL_LONG_TERM_REF_ENABLE_SHFT,
+			VIDC_SM_ENC_EXT_CTRL_LONG_TERM_REF_ENABLE_BMSK);
 	DDL_MEM_WRITE_32(shared_mem, VIDC_SM_ENC_EXT_CTRL_ADDR, enc_ctrl);
 }
 
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
index 2eef99d..f344460 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
@@ -106,7 +106,8 @@
 	struct ddl_buf_addr *shared_mem, u32 hec_enable,
 	enum VIDC_SM_frame_skip  frame_skip_mode, u32 seq_hdr_in_band,
 	u32 vbv_buffer_size, u32 cpcfc_enable, u32 sps_pps_control,
-	u32 closed_gop_enable, u32 au_delim_enable, u32 vui_timing_info_enable);
+	u32 closed_gop_enable, u32 au_delim_enable, u32 vui_timing_info_enable,
+	u32 ltr_enable);
 void vidc_sm_set_encoder_param_change(struct ddl_buf_addr *shared_mem,
 	u32 bit_rate_chg, u32 frame_rate_chg, u32 i_period_chg);
 void vidc_sm_set_encoder_vop_time(struct ddl_buf_addr *shared_mem,
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.h
index 4963874..a099ade 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.h
@@ -34,7 +34,7 @@
 		printk(KERN_DEBUG x); \
 } while (0)
 
-#ifdef DDL_MSG_LOG
+#if DDL_MSG_LOG
 #define DDL_MSG_LOW(x...)    printk(KERN_INFO x)
 #define DDL_MSG_MED(x...)    printk(KERN_INFO x)
 #define DDL_MSG_HIGH(x...)   printk(KERN_INFO x)
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
index 1bf242d..b84ec66 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
@@ -331,7 +331,7 @@
 {
 	struct ddl_encoder_data *encoder = &(ddl->codec_data.encoder);
 	u32 frame_rate_change = false, bit_rate_change = false;
-	u32 i_period_change = false, reset_req = false;
+	u32 reset_req = false;
 
 	if (!enable) {
 		if (encoder->dynmic_prop_change_req) {
@@ -344,6 +344,17 @@
 			encoder->dynamic_prop_change &=
 				~(DDL_ENC_REQ_IFRAME);
 		}
+		if (encoder->dynamic_prop_change & DDL_ENC_LTR_USE_FRAME) {
+			if (encoder->ltr_control.callback_reqd) {
+				DDL_MSG_ERROR("%s: LTR use failed", __func__);
+				ddl_encoder_use_ltr_fail_callback(ddl);
+				encoder->ltr_control.callback_reqd = false;
+			} else {
+				encoder->ltr_control.use_ltr_reqd = true;
+			}
+			encoder->dynamic_prop_change &=
+				~(DDL_ENC_LTR_USE_FRAME);
+		}
 		if ((encoder->dynamic_prop_change &
 			DDL_ENC_CHANGE_BITRATE)) {
 			bit_rate_change = true;
@@ -355,7 +366,7 @@
 		}
 		if ((encoder->dynamic_prop_change
 			& DDL_ENC_CHANGE_IPERIOD)) {
-			i_period_change = true;
+			encoder->intra_period_changed = true;
 			vidc_sm_set_encoder_new_i_period(
 				&ddl->shared_mem[ddl->command_channel],
 				encoder->i_period.p_frames);
@@ -387,7 +398,7 @@
 		vidc_sm_set_encoder_param_change(
 			&ddl->shared_mem[ddl->command_channel],
 			bit_rate_change, frame_rate_change,
-			i_period_change);
+			encoder->intra_period_changed);
 	}
 }
 
@@ -580,7 +591,7 @@
 	u32 index, luma[4], chroma[4], hdr_ext_control = false;
 	const u32 recon_bufs = 4;
 	u32 h263_cpfc_enable = false;
-	u32 scaled_frame_rate;
+	u32 scaled_frame_rate, ltr_enable;
 
 	ddl_vidc_encode_set_profile_level(ddl);
 	vidc_1080p_set_encode_frame_size(encoder->frame_size.width,
@@ -601,12 +612,14 @@
 		(DDL_FRAMERATE_SCALE(DDL_INITIAL_FRAME_RATE)
 		 != scaled_frame_rate) && encoder->plusptype_enable)
 		h263_cpfc_enable = true;
+	ltr_enable = DDL_IS_LTR_ENABLED(encoder);
+	DDL_MSG_HIGH("ltr_enable = %u", ltr_enable);
 	vidc_sm_set_extended_encoder_control(&ddl->shared_mem
 		[ddl->command_channel], hdr_ext_control,
 		r_cframe_skip, false, 0,
 		h263_cpfc_enable, encoder->sps_pps.sps_pps_for_idr_enable_flag,
 		encoder->closed_gop, encoder->avc_delimiter_enable,
-		encoder->vui_timinginfo_enable);
+		encoder->vui_timinginfo_enable, ltr_enable);
 	if (encoder->vui_timinginfo_enable) {
 		vidc_sm_set_h264_encoder_timing_info(
 			&ddl->shared_mem[ddl->command_channel],
@@ -809,7 +822,8 @@
 		encoder->dynmic_prop_change_req = true;
 		ddl_vidc_encode_dynamic_property(ddl, true);
 	}
-
+	if (DDL_IS_LTR_ENABLED(encoder))
+		ddl_encoder_ltr_control(ddl);
 	vidc_1080p_set_encode_circular_intra_refresh(
 		encoder->intra_refresh.cir_mb_number);
 	ddl_vidc_encode_set_multi_slice_info(encoder);
@@ -824,13 +838,21 @@
 	ddl_context->dram_base_a.align_physical_addr, stream->physical);
 	enc_param.stream_buffer_size =
 		encoder->client_output_buf_req.sz;
-
 	enc_param.intra_frame = encoder->intra_frame_insertion;
-	if (encoder->intra_frame_insertion)
-		encoder->intra_frame_insertion = false;
 	enc_param.input_flush = false;
 	enc_param.slice_enable = false;
-		vidc_sm_set_encoder_vop_time(
+	enc_param.store_ltr0 = encoder->ltr_control.store_ltr0;
+	enc_param.store_ltr1 = encoder->ltr_control.store_ltr1;
+	enc_param.use_ltr0 = encoder->ltr_control.use_ltr0;
+	enc_param.use_ltr1 = encoder->ltr_control.use_ltr1;
+
+	encoder->intra_frame_insertion = false;
+	encoder->intra_period_changed = false;
+	encoder->ltr_control.store_ltr0 = false;
+	encoder->ltr_control.store_ltr1 = false;
+	encoder->ltr_control.use_ltr0 = false;
+	encoder->ltr_control.use_ltr1 = false;
+	vidc_sm_set_encoder_vop_time(
 			&ddl->shared_mem[ddl->command_channel], true,
 			encoder->vop_timing.vop_time_resolution,
 			ddl->input_frame.frm_delta);
diff --git a/drivers/video/msm/vidc/1080p/ddl/vidc.c b/drivers/video/msm/vidc/1080p/ddl/vidc.c
index 3c445bc..396adaf 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vidc.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vidc.c
@@ -83,6 +83,17 @@
 #define VIDC_1080P_SI_RG10_ENCODE_SLICE_IF_ENABLE_SHFT      31
 #define VIDC_1080P_MAX_INTRA_PERIOD 0xffff
 
+#define VIDC_1080P_COMMON_CHX_RG6_I_FRAME_BMASK              0x00000001
+#define VIDC_1080P_COMMON_CHX_RG6_I_FRAME_SHIFT              0
+#define VIDC_1080P_COMMON_CHX_RG6_STORE_LTR0_BMASK           0x00000008
+#define VIDC_1080P_COMMON_CHX_RG6_STORE_LTR0_SHIFT           3
+#define VIDC_1080P_COMMON_CHX_RG6_STORE_LTR1_BMASK           0x00000010
+#define VIDC_1080P_COMMON_CHX_RG6_STORE_LTR1_SHIFT           4
+#define VIDC_1080P_COMMON_CHX_RG6_USE_LTR0_BMASK             0x00000020
+#define VIDC_1080P_COMMON_CHX_RG6_USE_LTR0_SHIFT             5
+#define VIDC_1080P_COMMON_CHX_RG6_USE_LTR1_BMASK             0x00000040
+#define VIDC_1080P_COMMON_CHX_RG6_USE_LTR1_SHIFT             6
+
 u8 *VIDC_BASE_PTR;
 
 void vidc_1080p_do_sw_reset(enum vidc_1080p_reset init_flag)
@@ -787,7 +798,9 @@
 void vidc_1080p_encode_frame_start_ch0(
 	struct vidc_1080p_enc_frame_start_param *param)
 {
-	u32 input_flush;
+	u32 input_flush = 0;
+	u32 frame_insertion = 0;
+
 	VIDC_HWIO_OUT(REG_695082, VIDC_1080P_RISC2HOST_CMD_EMPTY);
 	VIDC_HWIO_OUT(REG_666957, VIDC_1080P_INIT_CH_INST_ID);
 	VIDC_HWIO_OUT(REG_117192,
@@ -798,7 +811,22 @@
 		VIDC_1080P_BASE_OFFSET_SHIFT);
 	VIDC_HWIO_OUT(REG_175608, param->current_c_addr_offset >>
 		VIDC_1080P_BASE_OFFSET_SHIFT);
-	VIDC_HWIO_OUT(REG_190381, param->intra_frame);
+	frame_insertion = VIDC_SETFIELD(param->intra_frame,
+			VIDC_1080P_COMMON_CHX_RG6_I_FRAME_SHIFT,
+			VIDC_1080P_COMMON_CHX_RG6_I_FRAME_BMASK);
+	frame_insertion |= VIDC_SETFIELD(param->store_ltr0,
+			VIDC_1080P_COMMON_CHX_RG6_STORE_LTR0_SHIFT,
+			VIDC_1080P_COMMON_CHX_RG6_STORE_LTR0_BMASK);
+	frame_insertion |= VIDC_SETFIELD(param->store_ltr1,
+			VIDC_1080P_COMMON_CHX_RG6_STORE_LTR1_SHIFT,
+			VIDC_1080P_COMMON_CHX_RG6_STORE_LTR1_BMASK);
+	frame_insertion |= VIDC_SETFIELD(param->use_ltr0,
+			VIDC_1080P_COMMON_CHX_RG6_USE_LTR0_SHIFT,
+			VIDC_1080P_COMMON_CHX_RG6_USE_LTR0_BMASK);
+	frame_insertion |= VIDC_SETFIELD(param->use_ltr1,
+			VIDC_1080P_COMMON_CHX_RG6_USE_LTR1_SHIFT,
+			VIDC_1080P_COMMON_CHX_RG6_USE_LTR1_BMASK);
+	VIDC_HWIO_OUT(REG_190381, frame_insertion);
 	VIDC_HWIO_OUT(REG_889944, param->shared_mem_addr_offset);
 	input_flush = VIDC_SETFIELD(param->input_flush,
 			VIDC_1080P_SI_RG10_ENCODE_INPUT_BUFFER_FLUSH_SHFT,
@@ -816,7 +844,9 @@
 void vidc_1080p_encode_frame_start_ch1(
 	struct vidc_1080p_enc_frame_start_param *param)
 {
-	u32 input_flush;
+	u32 input_flush = 0;
+	u32 frame_insertion = 0;
+
 	VIDC_HWIO_OUT(REG_695082, VIDC_1080P_RISC2HOST_CMD_EMPTY);
 	VIDC_HWIO_OUT(REG_313350, VIDC_1080P_INIT_CH_INST_ID);
 	VIDC_HWIO_OUT(REG_980194,
@@ -827,7 +857,22 @@
 		VIDC_1080P_BASE_OFFSET_SHIFT);
 	VIDC_HWIO_OUT(REG_548308,  param->current_c_addr_offset >>
 		VIDC_1080P_BASE_OFFSET_SHIFT);
-	VIDC_HWIO_OUT(REG_887095, param->intra_frame);
+	frame_insertion = VIDC_SETFIELD(param->intra_frame,
+			VIDC_1080P_COMMON_CHX_RG6_I_FRAME_SHIFT,
+			VIDC_1080P_COMMON_CHX_RG6_I_FRAME_BMASK);
+	frame_insertion |= VIDC_SETFIELD(param->store_ltr0,
+			VIDC_1080P_COMMON_CHX_RG6_STORE_LTR0_SHIFT,
+			VIDC_1080P_COMMON_CHX_RG6_STORE_LTR0_BMASK);
+	frame_insertion |= VIDC_SETFIELD(param->store_ltr1,
+			VIDC_1080P_COMMON_CHX_RG6_STORE_LTR1_SHIFT,
+			VIDC_1080P_COMMON_CHX_RG6_STORE_LTR1_BMASK);
+	frame_insertion |= VIDC_SETFIELD(param->use_ltr0,
+			VIDC_1080P_COMMON_CHX_RG6_USE_LTR0_SHIFT,
+			VIDC_1080P_COMMON_CHX_RG6_USE_LTR0_BMASK);
+	frame_insertion |= VIDC_SETFIELD(param->use_ltr1,
+			VIDC_1080P_COMMON_CHX_RG6_USE_LTR1_SHIFT,
+			VIDC_1080P_COMMON_CHX_RG6_USE_LTR1_BMASK);
+	VIDC_HWIO_OUT(REG_887095, frame_insertion);
 	VIDC_HWIO_OUT(REG_652528, param->shared_mem_addr_offset);
 	input_flush = VIDC_SETFIELD(param->input_flush,
 			VIDC_1080P_SI_RG10_ENCODE_INPUT_BUFFER_FLUSH_SHFT,
diff --git a/drivers/video/msm/vidc/1080p/ddl/vidc.h b/drivers/video/msm/vidc/1080p/ddl/vidc.h
index 117612b..be4c35b 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vidc.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vidc.h
@@ -400,6 +400,10 @@
 	u32 intra_frame;
 	u32 input_flush;
 	u32 slice_enable;
+	u32 store_ltr0;
+	u32 store_ltr1;
+	u32 use_ltr0;
+	u32 use_ltr1;
 	enum vidc_1080p_encode encode;
 };
 struct vidc_1080p_enc_frame_info{
diff --git a/drivers/video/msm/vidc/common/enc/venc.c b/drivers/video/msm/vidc/common/enc/venc.c
index 763fbda..c05e568 100644
--- a/drivers/video/msm/vidc/common/enc/venc.c
+++ b/drivers/video/msm/vidc/common/enc/venc.c
@@ -218,15 +218,15 @@
 
 	switch (event) {
 	case VCD_EVT_RESP_OUTPUT_DONE:
-	   DBG("Send INPUT_DON message to client = %p\n",
+	   DBG("Send OUTPUT_DON message to client = %p\n",
 			client_ctx);
 	   break;
 	case VCD_EVT_RESP_OUTPUT_FLUSHED:
-	   DBG("Send INPUT_FLUSHED message to client = %p\n",
+	   DBG("Send OUTPUT_FLUSHED message to client = %p\n",
 		   client_ctx);
 	   break;
 	default:
-	   ERR("QVD: vid_enc_output_frame_done invalid cmd type: %d\n", event);
+	   ERR("vid_enc_output_frame_done: invalid cmd type: %d\n", event);
 	   venc_msg->venc_msg_info.statuscode = VEN_S_EFATAL;
 	   break;
 	}
@@ -336,6 +336,12 @@
 		venc_msg->venc_msg_info.msgcode =
 			VEN_MSG_PAUSE;
 		break;
+	case VCD_EVT_IND_INFO_LTRUSE_FAILED:
+		INFO("\n msm_vidc_enc: Sending VEN_MSG_LTRUSE_FAILED"\
+			 " to client");
+		venc_msg->venc_msg_info.msgcode =
+			VEN_MSG_LTRUSE_FAILED;
+		break;
 
 	default:
 		ERR("%s() : unknown event type %u\n",
@@ -394,6 +400,7 @@
 	case VCD_EVT_IND_OUTPUT_RECONFIG:
 	case VCD_EVT_IND_HWERRFATAL:
 	case VCD_EVT_IND_RESOURCES_LOST:
+	case VCD_EVT_IND_INFO_LTRUSE_FAILED:
 		vid_enc_lean_event(client_ctx, event, status);
 		break;
 
@@ -790,17 +797,18 @@
 		struct venc_buffer enc_buffer;
 		if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
 			return -EFAULT;
-		DBG("VEN_IOCTL_CMD_ENCODE_FRAME"
-			"/VEN_IOCTL_CMD_FILL_OUTPUT_BUFFER\n");
 		if (copy_from_user(&enc_buffer, venc_msg.in,
 						   sizeof(enc_buffer)))
 			return -EFAULT;
-		if (cmd == VEN_IOCTL_CMD_ENCODE_FRAME)
+		if (cmd == VEN_IOCTL_CMD_ENCODE_FRAME) {
+			DBG("VEN_IOCTL_CMD_ENCODE_FRAME\n");
 			result = vid_enc_encode_frame(client_ctx,
 					&enc_buffer);
-		else
+		} else {
+			DBG("VEN_IOCTL_CMD_FILL_OUTPUT_BUFFER\n");
 			result = vid_enc_fill_output_buffer(client_ctx,
 					&enc_buffer);
+		}
 		if (!result) {
 			DBG("\n VEN_IOCTL_CMD_ENCODE_FRAME/"
 				"VEN_IOCTL_CMD_FILL_OUTPUT_BUFFER failed");
@@ -866,19 +874,19 @@
 		if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
 			return -EFAULT;
 
-		DBG("VEN_IOCTL_SET_INPUT_BUFFER_REQ"
-			"/VEN_IOCTL_SET_OUTPUT_BUFFER_REQ\n");
-
 		if (copy_from_user(&allocatorproperty, venc_msg.in,
 			sizeof(allocatorproperty)))
 			return -EFAULT;
 
-		if (cmd == VEN_IOCTL_SET_OUTPUT_BUFFER_REQ)
-				result = vid_enc_set_buffer_req(client_ctx,
-						&allocatorproperty, false);
-		else
+		if (cmd == VEN_IOCTL_SET_OUTPUT_BUFFER_REQ) {
+			DBG("VEN_IOCTL_SET_OUTPUT_BUFFER_REQ\n");
+			result = vid_enc_set_buffer_req(client_ctx,
+					&allocatorproperty, false);
+		} else {
+			DBG("VEN_IOCTL_SET_INPUT_BUFFER_REQ\n");
 			result = vid_enc_set_buffer_req(client_ctx,
 					&allocatorproperty, true);
+		}
 		if (!result) {
 			DBG("setting VEN_IOCTL_SET_OUTPUT_BUFFER_REQ/"
 			"VEN_IOCTL_SET_INPUT_BUFFER_REQ failed\n");
@@ -893,15 +901,15 @@
 		if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
 			return -EFAULT;
 
-		DBG("VEN_IOCTL_GET_INPUT_BUFFER_REQ/"
-			"VEN_IOCTL_GET_OUTPUT_BUFFER_REQ\n");
-
-		if (cmd == VEN_IOCTL_GET_OUTPUT_BUFFER_REQ)
+		if (cmd == VEN_IOCTL_GET_OUTPUT_BUFFER_REQ) {
+			DBG("VEN_IOCTL_GET_OUTPUT_BUFFER_REQ\n");
 			result = vid_enc_get_buffer_req(client_ctx,
 					&allocatorproperty, false);
-		else
+		} else {
+			DBG("VEN_IOCTL_GET_INPUT_BUFFER_REQ\n");
 			result = vid_enc_get_buffer_req(client_ctx,
 					&allocatorproperty, true);
+		}
 		if (!result)
 			return -EIO;
 		if (copy_to_user(venc_msg.out, &allocatorproperty,
@@ -1342,6 +1350,7 @@
 	}
 	case VEN_IOCTL_CMD_REQUEST_IFRAME:
 	{
+		DBG("VEN_IOCTL_CMD_REQUEST_IFRAME\n");
 		result = vid_enc_request_iframe(client_ctx);
 		if (!result) {
 			ERR("setting VEN_IOCTL_CMD_REQUEST_IFRAME failed\n");
@@ -1565,6 +1574,7 @@
 		struct vcd_property_hdr vcd_property_hdr;
 		struct vcd_property_live live_mode;
 
+		DBG("VEN_IOCTL_SET_METABUFFER_MODE\n");
 		if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
 			return -EFAULT;
 		if (copy_from_user(&metabuffer_mode, venc_msg.in,
@@ -1614,6 +1624,7 @@
 		struct vcd_property_hdr vcd_property_hdr;
 		u32 vcd_status = VCD_ERR_FAIL;
 		u32 enable = true;
+		DBG("VEN_IOCTL_SET_SLICE_DELIVERY_MODE\n");
 		vcd_property_hdr.prop_id = VCD_I_SLICE_DELIVERY_MODE;
 		vcd_property_hdr.sz = sizeof(u32);
 		vcd_status = vcd_set_property(client_ctx->vcd_handle,
@@ -1647,6 +1658,143 @@
 		}
 		break;
 	}
+	case VEN_IOCTL_SET_LTRMODE:
+	case VEN_IOCTL_GET_LTRMODE:
+	{
+		struct venc_ltrmode encoder_ltrmode;
+		if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
+			return -EFAULT;
+		if (cmd == VEN_IOCTL_SET_LTRMODE) {
+			DBG("VEN_IOCTL_SET_LTRMODE\n");
+			if (copy_from_user(&encoder_ltrmode, venc_msg.in,
+					sizeof(encoder_ltrmode)))
+				return -EFAULT;
+			result = vid_enc_set_get_ltrmode(client_ctx,
+					&encoder_ltrmode, true);
+		} else {
+			DBG("VEN_IOCTL_GET_LTRMODE\n");
+			result = vid_enc_set_get_ltrmode(client_ctx,
+					&encoder_ltrmode, false);
+			if (result) {
+				if (copy_to_user(venc_msg.out, &encoder_ltrmode,
+						sizeof(encoder_ltrmode)))
+					return -EFAULT;
+			}
+		}
+		if (!result) {
+			ERR("VEN_IOCTL_(G)SET_LTRMODE failed\n");
+			return -EIO;
+		}
+		break;
+	}
+	case VEN_IOCTL_SET_LTRCOUNT:
+	case VEN_IOCTL_GET_LTRCOUNT:
+	{
+		struct venc_ltrcount encoder_ltrcount;
+		if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
+			return -EFAULT;
+		if (cmd == VEN_IOCTL_SET_LTRCOUNT) {
+			DBG("VEN_IOCTL_SET_LTRCOUNT\n");
+			if (copy_from_user(&encoder_ltrcount, venc_msg.in,
+					sizeof(encoder_ltrcount)))
+				return -EFAULT;
+			result = vid_enc_set_get_ltrcount(client_ctx,
+					&encoder_ltrcount, true);
+		} else {
+			DBG("VEN_IOCTL_GET_LTRCOUNT\n");
+			result = vid_enc_set_get_ltrcount(client_ctx,
+					&encoder_ltrcount, false);
+			if (result) {
+				if (copy_to_user(venc_msg.out,
+					&encoder_ltrcount,
+					sizeof(encoder_ltrcount)))
+					return -EFAULT;
+			}
+		}
+		if (!result) {
+			ERR("VEN_IOCTL_(G)SET_LTRCOUNT failed\n");
+			return -EIO;
+		}
+		break;
+	}
+	case VEN_IOCTL_SET_LTRPERIOD:
+	case VEN_IOCTL_GET_LTRPERIOD:
+	{
+		struct venc_ltrperiod encoder_ltrperiod;
+		if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
+			return -EFAULT;
+		if (cmd == VEN_IOCTL_SET_LTRPERIOD) {
+			DBG("VEN_IOCTL_SET_LTRPERIOD\n");
+			if (copy_from_user(&encoder_ltrperiod, venc_msg.in,
+					sizeof(encoder_ltrperiod)))
+				return -EFAULT;
+			result = vid_enc_set_get_ltrperiod(client_ctx,
+					&encoder_ltrperiod, true);
+		} else {
+			DBG("VEN_IOCTL_GET_LTRPERIOD\n");
+			result = vid_enc_set_get_ltrperiod(client_ctx,
+					&encoder_ltrperiod, false);
+			if (result) {
+				if (copy_to_user(venc_msg.out,
+					&encoder_ltrperiod,
+					sizeof(encoder_ltrperiod)))
+					return -EFAULT;
+			}
+		}
+		if (!result) {
+			ERR("VEN_IOCTL_(G)SET_LTRPERIOD failed\n");
+			return -EIO;
+		}
+		break;
+	}
+	case VEN_IOCTL_GET_CAPABILITY_LTRCOUNT:
+	{
+		struct venc_range venc_capltrcount;
+		if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
+			return -EFAULT;
+		DBG("VEN_IOCTL_GET_CAPABILITY_LTRCOUNT\n");
+		result = vid_enc_get_capability_ltrcount(client_ctx,
+					&venc_capltrcount);
+		if (result) {
+			if (copy_to_user(venc_msg.out, &venc_capltrcount,
+					sizeof(venc_capltrcount)))
+				return -EFAULT;
+		} else {
+			ERR("VEN_IOCTL_GET_CAPABILITY_LTRCOUNT failed\n");
+			return -EIO;
+		}
+		break;
+	}
+	case VEN_IOCTL_SET_LTRUSE:
+	case VEN_IOCTL_GET_LTRUSE:
+	{
+		struct venc_ltruse encoder_ltruse;
+		if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
+			return -EFAULT;
+		if (cmd == VEN_IOCTL_SET_LTRUSE) {
+			DBG("VEN_IOCTL_SET_LTRUSE\n");
+			if (copy_from_user(&encoder_ltruse, venc_msg.in,
+					sizeof(encoder_ltruse)))
+				return -EFAULT;
+			result = vid_enc_set_get_ltruse(client_ctx,
+						&encoder_ltruse, true);
+		} else {
+			DBG("VEN_IOCTL_GET_LTRUSE\n");
+			result = vid_enc_set_get_ltruse(client_ctx,
+						&encoder_ltruse, false);
+			if (result) {
+				if (copy_to_user(venc_msg.out,
+					&encoder_ltruse,
+					sizeof(encoder_ltruse)))
+					return -EFAULT;
+			}
+		}
+		if (!result) {
+			ERR("VEN_IOCTL_(G)SET_LTRUSE failed\n");
+			return -EIO;
+		}
+		break;
+	}
 	case VEN_IOCTL_SET_AC_PREDICTION:
 	case VEN_IOCTL_GET_AC_PREDICTION:
 	case VEN_IOCTL_SET_RVLC:
diff --git a/drivers/video/msm/vidc/common/enc/venc_internal.c b/drivers/video/msm/vidc/common/enc/venc_internal.c
index 8779432..7a26d2e 100644
--- a/drivers/video/msm/vidc/common/enc/venc_internal.c
+++ b/drivers/video/msm/vidc/common/enc/venc_internal.c
@@ -328,6 +328,42 @@
 	vcd_property_hdr.prop_id = VCD_I_METADATA_ENABLE;
 	vcd_property_hdr.sz = sizeof(struct vcd_property_meta_data_enable);
 	if (set_flag) {
+		DBG("vcd_set_property: VCD_I_METADATA_ENABLE = %x\n",
+				(u32)*extradata_flag);
+		vcd_meta_data.meta_data_enable_flag = *extradata_flag;
+		vcd_status = vcd_set_property(client_ctx->vcd_handle,
+					&vcd_property_hdr, &vcd_meta_data);
+		if (vcd_status) {
+			ERR("%s(): Set VCD_I_METADATA_ENABLE Failed\n",
+				__func__);
+			return false;
+		}
+	} else {
+		vcd_status = vcd_get_property(client_ctx->vcd_handle,
+					&vcd_property_hdr, &vcd_meta_data);
+		if (vcd_status) {
+			ERR("%s(): Get VCD_I_METADATA_ENABLE Failed\n",
+				__func__);
+			return false;
+		}
+		*extradata_flag = vcd_meta_data.meta_data_enable_flag;
+		DBG("vcd_get_property: VCD_I_METADATA_ENABLE = 0x%x\n",
+				(u32)*extradata_flag);
+	}
+	return true;
+}
+
+u32 vid_enc_set_get_extradata_cfg(struct video_client_ctx *client_ctx,
+		u32 *extradata_flag, u32 set_flag)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_meta_data_enable vcd_meta_data;
+	u32 vcd_status = VCD_ERR_FAIL;
+	if (!client_ctx || !extradata_flag)
+		return false;
+	vcd_property_hdr.prop_id = VCD_I_METADATA_ENABLE;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_meta_data_enable);
+	if (set_flag) {
 		DBG("vcd_set_property: VCD_I_METADATA_ENABLE = %d\n",
 				*extradata_flag);
 		vcd_meta_data.meta_data_enable_flag = *extradata_flag;
@@ -1995,3 +2031,215 @@
 			return false;
 		}
 }
+
+u32 vid_enc_set_get_ltrmode(struct video_client_ctx *client_ctx,
+		struct venc_ltrmode *venc_ltrmode, u32 set_flag)
+{
+	struct vcd_property_ltrmode_type vcd_property_ltrmode;
+	struct vcd_property_hdr vcd_property_hdr;
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	if (!client_ctx || !venc_ltrmode)
+		return false;
+
+	vcd_property_hdr.prop_id = VCD_I_LTR_MODE;
+	vcd_property_hdr.sz =
+		sizeof(struct vcd_property_ltrmode_type);
+
+	if (set_flag) {
+		vcd_property_ltrmode.ltr_mode = (enum vcd_property_ltrmode)
+			venc_ltrmode->ltr_mode;
+		DBG("%s: Set ltr_mode = %u", __func__,
+			(u32)vcd_property_ltrmode.ltr_mode);
+		vcd_status = vcd_set_property(client_ctx->vcd_handle,
+				&vcd_property_hdr, &vcd_property_ltrmode);
+		if (vcd_status) {
+			ERR("%s(): Set VCD_I_LTR_MODE Failed\n",
+					__func__);
+			return false;
+		}
+	} else {
+		vcd_status = vcd_get_property(client_ctx->vcd_handle,
+				&vcd_property_hdr, &vcd_property_ltrmode);
+		if (vcd_status) {
+			ERR("%s(): Get VCD_I_LTR_MODE Failed\n",
+					__func__);
+			return false;
+		} else {
+			venc_ltrmode->ltr_mode = (unsigned long)
+				vcd_property_ltrmode.ltr_mode;
+			DBG("%s: Got ltr_mode = %u", __func__,
+				(u32)vcd_property_ltrmode.ltr_mode);
+		}
+	}
+
+	return true;
+}
+
+u32 vid_enc_set_get_ltrcount(struct video_client_ctx *client_ctx,
+		struct venc_ltrcount *venc_ltrcount, u32 set_flag)
+{
+	struct vcd_property_ltrcount_type vcd_property_ltrcount;
+	struct vcd_property_hdr vcd_property_hdr;
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	if (!client_ctx || !venc_ltrcount)
+		return false;
+
+	vcd_property_hdr.prop_id = VCD_I_LTR_COUNT;
+	vcd_property_hdr.sz =
+		sizeof(struct vcd_property_ltrcount_type);
+
+	if (set_flag) {
+		vcd_property_ltrcount.ltr_count = (u32)
+			venc_ltrcount->ltr_count;
+		DBG("%s: Set ltr_count = %u", __func__,
+			(u32)vcd_property_ltrcount.ltr_count);
+		vcd_status = vcd_set_property(client_ctx->vcd_handle,
+				&vcd_property_hdr, &vcd_property_ltrcount);
+		if (vcd_status) {
+			ERR("%s(): Set VCD_I_LTR_COUNT Failed\n",
+					__func__);
+			return false;
+		}
+	} else {
+		vcd_status = vcd_get_property(client_ctx->vcd_handle,
+				&vcd_property_hdr, &vcd_property_ltrcount);
+		if (vcd_status) {
+			ERR("%s(): Get VCD_I_LTR_COUNT Failed\n",
+					__func__);
+			return false;
+		} else {
+			venc_ltrcount->ltr_count = (unsigned long)
+				vcd_property_ltrcount.ltr_count;
+			DBG("%s: Got ltr_count = %u", __func__,
+				(u32)vcd_property_ltrcount.ltr_count);
+		}
+	}
+
+	return true;
+}
+
+u32 vid_enc_set_get_ltrperiod(struct video_client_ctx *client_ctx,
+		struct venc_ltrperiod *venc_ltrperiod, u32 set_flag)
+{
+	struct vcd_property_ltrperiod_type vcd_property_ltrperiod;
+	struct vcd_property_hdr vcd_property_hdr;
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	if (!client_ctx || !venc_ltrperiod)
+		return false;
+
+	vcd_property_hdr.prop_id = VCD_I_LTR_PERIOD;
+	vcd_property_hdr.sz =
+		sizeof(struct vcd_property_ltrperiod_type);
+
+	if (set_flag) {
+		vcd_property_ltrperiod.ltr_period = (u32)
+			venc_ltrperiod->ltr_period;
+		DBG("%s: Set ltr_period = %u", __func__,
+			(u32)vcd_property_ltrperiod.ltr_period);
+		vcd_status = vcd_set_property(client_ctx->vcd_handle,
+				&vcd_property_hdr, &vcd_property_ltrperiod);
+		if (vcd_status) {
+			ERR("%s(): Set VCD_I_LTR_PERIOD Failed\n",
+					__func__);
+			return false;
+		}
+	} else {
+		vcd_status = vcd_get_property(client_ctx->vcd_handle,
+				&vcd_property_hdr, &vcd_property_ltrperiod);
+		if (vcd_status) {
+			ERR("%s(): Get VCD_I_LTR_PERIOD Failed\n",
+					__func__);
+			return false;
+		} else {
+			venc_ltrperiod->ltr_period = (unsigned long)
+				vcd_property_ltrperiod.ltr_period;
+			DBG("%s: Got ltr_period = %u", __func__,
+				(u32)vcd_property_ltrperiod.ltr_period);
+		}
+	}
+
+	return true;
+}
+
+u32 vid_enc_set_get_ltruse(struct video_client_ctx *client_ctx,
+		struct venc_ltruse *venc_ltruse, u32 set_flag)
+{
+	struct vcd_property_ltruse_type vcd_property_ltruse;
+	struct vcd_property_hdr vcd_property_hdr;
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	if (!client_ctx || !venc_ltruse)
+		return false;
+
+	vcd_property_hdr.prop_id = VCD_I_LTR_USE;
+	vcd_property_hdr.sz =
+		sizeof(struct vcd_property_ltruse_type);
+
+	if (set_flag) {
+		vcd_property_ltruse.ltr_id = (u32)
+			venc_ltruse->ltr_id;
+		vcd_property_ltruse.ltr_frames = (u32)
+			venc_ltruse->ltr_frames;
+		DBG("%s: Set ltr_id = %u, ltr_frames = %u",
+			__func__, vcd_property_ltruse.ltr_id,
+			vcd_property_ltruse.ltr_frames);
+		vcd_status = vcd_set_property(client_ctx->vcd_handle,
+				&vcd_property_hdr, &vcd_property_ltruse);
+		if (vcd_status) {
+			ERR("%s(): Set VCD_I_LTR_USE Failed\n",
+					__func__);
+			return false;
+		}
+	} else {
+		vcd_status = vcd_get_property(client_ctx->vcd_handle,
+				&vcd_property_hdr, &vcd_property_ltruse);
+		if (vcd_status) {
+			ERR("%s(): Get VCD_I_LTR_USE Failed\n",
+					__func__);
+			return false;
+		} else {
+			venc_ltruse->ltr_id = (unsigned long)
+				vcd_property_ltruse.ltr_id;
+			venc_ltruse->ltr_frames = (unsigned long)
+				vcd_property_ltruse.ltr_frames;
+			DBG("%s: Got ltr_id = %u, ltr_frames = %u",
+				__func__, vcd_property_ltruse.ltr_id,
+				vcd_property_ltruse.ltr_frames);
+		}
+	}
+
+	return true;
+}
+
+u32 vid_enc_get_capability_ltrcount(struct video_client_ctx *client_ctx,
+		struct venc_range *venc_capltrcount)
+{
+	struct vcd_property_range_type vcd_property_range;
+	struct vcd_property_hdr vcd_property_hdr;
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	if (!client_ctx || !venc_capltrcount)
+		return false;
+
+	vcd_property_hdr.prop_id = VCD_I_CAPABILITY_LTR_COUNT;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_range_type);
+	vcd_status = vcd_get_property(client_ctx->vcd_handle,
+					&vcd_property_hdr, &vcd_property_range);
+	if (vcd_status) {
+		ERR("%s(): Get VCD_I_CAPABILITY_LTR_COUNT Failed\n",
+			__func__);
+		return false;
+	} else {
+		venc_capltrcount->min = vcd_property_range.min;
+		venc_capltrcount->max = vcd_property_range.max;
+		venc_capltrcount->step_size = vcd_property_range.step_size;
+		DBG("%s: Got min: %lu, max: %lu, step_size: %lu", __func__,
+			venc_capltrcount->min, venc_capltrcount->max,
+			venc_capltrcount->step_size);
+	}
+
+	return true;
+}
diff --git a/drivers/video/msm/vidc/common/enc/venc_internal.h b/drivers/video/msm/vidc/common/enc/venc_internal.h
index 8a07fdb..17cefbb 100644
--- a/drivers/video/msm/vidc/common/enc/venc_internal.h
+++ b/drivers/video/msm/vidc/common/enc/venc_internal.h
@@ -151,4 +151,19 @@
 u32 vid_enc_get_recon_buffer_size(struct video_client_ctx *client_ctx,
 		struct venc_recon_buff_size *venc_recon_size);
 
+u32 vid_enc_set_get_ltrmode(struct video_client_ctx *client_ctx,
+		struct venc_ltrmode *encoder_ltrmode, u32 set_flag);
+
+u32 vid_enc_set_get_ltrcount(struct video_client_ctx *client_ctx,
+		struct venc_ltrcount *encoder_ltrcount, u32 set_flag);
+
+u32 vid_enc_set_get_ltrperiod(struct video_client_ctx *client_ctx,
+		struct venc_ltrperiod *encoder_ltrperiod, u32 set_flag);
+
+u32 vid_enc_get_capability_ltrcount(struct video_client_ctx *client_ctx,
+		struct venc_range *venc_capltrcount);
+
+u32 vid_enc_set_get_ltruse(struct video_client_ctx *client_ctx,
+		struct venc_ltruse *encoder_ltruse, u32 set_flag);
+
 #endif
diff --git a/drivers/video/msm/vidc/common/vcd/vcd.h b/drivers/video/msm/vidc/common/vcd/vcd.h
index a22adeb..5b2450e 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd.h
+++ b/drivers/video/msm/vidc/common/vcd/vcd.h
@@ -402,4 +402,7 @@
 struct vcd_transc *vcd_get_first_in_use_trans_for_clnt(
 	struct vcd_clnt_ctxt *cctxt);
 
+u32 vcd_handle_ltr_use_failed(struct vcd_clnt_ctxt *cctxt,
+	void *payload, size_t sz, u32 status);
+
 #endif
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c b/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
index 8f52f83..983923b 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
@@ -964,6 +964,12 @@
 			vcd_handle_ind_info_output_reconfig(cctxt, status);
 			break;
 		}
+	case VCD_EVT_IND_INFO_LTRUSE_FAILED:
+		{
+			rc = vcd_handle_ltr_use_failed(cctxt,
+					payload, sz, status);
+			break;
+		}
 	default:
 		{
 			VCD_MSG_ERROR
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_sub.c b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
index a4c44f3..78d77d1 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_sub.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
@@ -3516,3 +3516,14 @@
 	}
 	return rc;
 }
+
+u32 vcd_handle_ltr_use_failed(struct vcd_clnt_ctxt *cctxt,
+	void *payload, size_t sz, u32 status)
+{
+	u32 rc = VCD_S_SUCCESS;
+	if (payload && cctxt) {
+		cctxt->callback(VCD_EVT_IND_INFO_LTRUSE_FAILED,
+			status, payload, sz, cctxt, cctxt->client_data);
+	}
+	return rc;
+}
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index d2f8faf..3e5c8cb 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -270,14 +270,11 @@
  *        should be cancelled
  * @started_delayed_bkops:  A flag to indicate if the delayed
  *        work was scheduled
- * @sectors_changed:  number of  sectors written or
- *       discard since the last idle BKOPS were scheduled
  */
 struct mmc_bkops_info {
 	struct delayed_work	dw;
 	unsigned int		host_suspend_tout_ms;
 	unsigned int		delay_ms;
-	unsigned int		min_sectors_to_queue_delayed_work;
 	struct mmc_bkops_stats  bkops_stats;    /* BKOPS statistics */
 /*
  * A default time for checking the need for non urgent BKOPS once mmcqd
@@ -290,16 +287,6 @@
 #define BKOPS_COMPLETION_POLLING_INTERVAL_MS 1000 /* in ms */
 	bool			cancel_delayed_work;
 	bool			started_delayed_bkops;
-	unsigned int		sectors_changed;
-/*
- * Since canceling the delayed work might have significant effect on the
- * performance of small requests we won't queue the delayed work every time
- * mmcqd thread is idle.
- * The delayed work for idle BKOPS will be scheduled only after a significant
- * amount of write or discard data.
- * 100MB is chosen based on benchmark tests.
- */
-#define BKOPS_MIN_SECTORS_TO_QUEUE_DELAYED_WORK 204800 /* 100MB */
 };
 
 /**
diff --git a/include/linux/msm_vidc_enc.h b/include/linux/msm_vidc_enc.h
index ea7db81..dde126c 100644
--- a/include/linux/msm_vidc_enc.h
+++ b/include/linux/msm_vidc_enc.h
@@ -44,6 +44,8 @@
 #define VEN_MSG_PAUSE	8
 #define VEN_MSG_RESUME	9
 #define VEN_MSG_STOP_READING_MSG	10
+#define VEN_MSG_LTRUSE_FAILED	    11
+
 
 /*Buffer flags bits masks*/
 #define VEN_BUFFLAG_EOS	0x00000001
@@ -56,6 +58,7 @@
 #define VEN_EXTRADATA_NONE          0x001
 #define VEN_EXTRADATA_QCOMFILLER    0x002
 #define VEN_EXTRADATA_SLICEINFO     0x100
+#define VEN_EXTRADATA_LTRINFO       0x200
 
 /*ENCODER CONFIGURATION CONSTANTS*/
 
@@ -461,6 +464,55 @@
 #define VEN_IOCTL_SET_H263_PLUSPTYPE \
 	_IOW(VEN_IOCTLBASE_ENC, 51, struct venc_ioctl_msg)
 
+/*IOCTL params:SET: InputData - venc_range, OutputData - NULL.*/
+#define VEN_IOCTL_SET_CAPABILITY_LTRCOUNT \
+	_IOW(VEN_IOCTLBASE_ENC, 52, struct venc_ioctl_msg)
+/*IOCTL params:GET: InputData - NULL, OutputData - venc_range.*/
+#define VEN_IOCTL_GET_CAPABILITY_LTRCOUNT \
+	_IOR(VEN_IOCTLBASE_ENC, 53, struct venc_ioctl_msg)
+
+/*IOCTL params:SET: InputData - venc_ltrmode, OutputData - NULL.*/
+#define VEN_IOCTL_SET_LTRMODE \
+	_IOW(VEN_IOCTLBASE_ENC, 54, struct venc_ioctl_msg)
+/*IOCTL params:GET: InputData - NULL, OutputData - venc_ltrmode.*/
+#define VEN_IOCTL_GET_LTRMODE \
+	_IOR(VEN_IOCTLBASE_ENC, 55, struct venc_ioctl_msg)
+
+/*IOCTL params:SET: InputData - venc_ltrcount, OutputData - NULL.*/
+#define VEN_IOCTL_SET_LTRCOUNT \
+	_IOW(VEN_IOCTLBASE_ENC, 56, struct venc_ioctl_msg)
+/*IOCTL params:GET: InputData - NULL, OutputData - venc_ltrcount.*/
+#define VEN_IOCTL_GET_LTRCOUNT \
+	_IOR(VEN_IOCTLBASE_ENC, 57, struct venc_ioctl_msg)
+
+/*IOCTL params:SET: InputData - venc_ltrperiod, OutputData - NULL.*/
+#define VEN_IOCTL_SET_LTRPERIOD \
+	_IOW(VEN_IOCTLBASE_ENC, 58, struct venc_ioctl_msg)
+/*IOCTL params:GET: InputData - NULL, OutputData - venc_ltrperiod.*/
+#define VEN_IOCTL_GET_LTRPERIOD \
+	_IOR(VEN_IOCTLBASE_ENC, 59, struct venc_ioctl_msg)
+
+/*IOCTL params:SET: InputData - venc_ltruse, OutputData - NULL.*/
+#define VEN_IOCTL_SET_LTRUSE \
+	_IOW(VEN_IOCTLBASE_ENC, 60, struct venc_ioctl_msg)
+/*IOCTL params:GET: InputData - NULL, OutputData - venc_ltruse.*/
+#define VEN_IOCTL_GET_LTRUSE \
+	_IOR(VEN_IOCTLBASE_ENC, 61, struct venc_ioctl_msg)
+
+/*IOCTL params:SET: InputData - venc_ltrmark, OutputData - NULL.*/
+#define VEN_IOCTL_SET_LTRMARK \
+	_IOW(VEN_IOCTLBASE_ENC, 62, struct venc_ioctl_msg)
+/*IOCTL params:GET: InputData - NULL, OutputData - venc_ltrmark.*/
+#define VEN_IOCTL_GET_LTRMARK \
+	_IOR(VEN_IOCTLBASE_ENC, 63, struct venc_ioctl_msg)
+
+
+struct venc_range {
+	unsigned long	max;
+	unsigned long	min;
+	unsigned long	step_size;
+};
+
 struct venc_switch{
 	unsigned char	status;
 };
@@ -622,4 +674,21 @@
 	int alignment;
 };
 
+struct venc_ltrmode {
+	unsigned long   ltr_mode;
+};
+
+struct venc_ltrcount {
+	unsigned long   ltr_count;
+};
+
+struct venc_ltrperiod {
+	unsigned long   ltr_period;
+};
+
+struct venc_ltruse {
+	unsigned long   ltr_id;
+	unsigned long   ltr_frames;
+};
+
 #endif /* _MSM_VIDC_ENC_H_ */
diff --git a/include/media/msm/vcd_property.h b/include/media/msm/vcd_property.h
index 2ce1a88..ed9bffb 100644
--- a/include/media/msm/vcd_property.h
+++ b/include/media/msm/vcd_property.h
@@ -58,7 +58,12 @@
 #define VCD_I_ENABLE_DELIMITER_FLAG (VCD_START_BASE + 0x2A)
 #define VCD_I_ENABLE_VUI_TIMING_INFO (VCD_START_BASE + 0x2B)
 #define VCD_I_H263_PLUSPTYPE (VCD_START_BASE + 0x2C)
-
+#define VCD_I_LTR_MODE (VCD_START_BASE + 0x2D)
+#define VCD_I_LTR_COUNT (VCD_START_BASE + 0x2E)
+#define VCD_I_LTR_PERIOD (VCD_START_BASE + 0x2F)
+#define VCD_I_LTR_USE (VCD_START_BASE + 0x30)
+#define VCD_I_CAPABILITY_LTR_COUNT (VCD_START_BASE + 0x31)
+#define VCD_I_LTR_MARK (VCD_START_BASE + 0x32)
 
 #define VCD_START_REQ      (VCD_START_BASE + 0x1000)
 #define VCD_I_REQ_IFRAME   (VCD_START_REQ + 0x1)
@@ -116,10 +121,11 @@
 #define VCD_METADATA_VC1            0x040
 #define VCD_METADATA_PASSTHROUGH    0x080
 #define VCD_METADATA_ENC_SLICE      0x100
-
+#define VCD_METADATA_LTR_INFO       0x200
 #define VCD_METADATA_EXT_DATA       0x0800
 #define VCD_METADATA_USER_DATA      0x1000
 
+
 struct vcd_property_meta_data_enable {
 	u32 meta_data_enable_flag;
 };
@@ -389,4 +395,34 @@
 	u32 vui_timing_info;
 };
 
+struct vcd_property_range_type {
+	u32 min;
+	u32 max;
+	u32 step_size;
+};
+
+enum vcd_property_ltrmode {
+	VCD_LTR_MODE_DISABLE = 0,
+	VCD_LTR_MODE_MANUAL  = 1,
+	VCD_LTR_MODE_AUTO    = 2,
+	VCD_LTR_MODE_MAX     = 0x7fffffff
+};
+
+struct vcd_property_ltrmode_type {
+	enum vcd_property_ltrmode ltr_mode;
+};
+
+struct vcd_property_ltrcount_type {
+	u32 ltr_count;
+};
+
+struct vcd_property_ltrperiod_type {
+	u32 ltr_period;
+};
+
+struct vcd_property_ltruse_type {
+	u32 ltr_id;
+	u32 ltr_frames;
+};
+
 #endif
diff --git a/include/media/msm/vcd_status.h b/include/media/msm/vcd_status.h
index 7e8ec0b..631501d 100644
--- a/include/media/msm/vcd_status.h
+++ b/include/media/msm/vcd_status.h
@@ -33,6 +33,7 @@
 #define VCD_EVT_IND_RESOURCES_LOST        (VCD_EVT_IND_BASE + 0x4)
 #define VCD_EVT_IND_INFO_OUTPUT_RECONFIG  (VCD_EVT_IND_BASE + 0x5)
 #define VCD_EVT_IND_INFO_FIELD_DROPPED    (VCD_EVT_IND_BASE + 0x6)
+#define VCD_EVT_IND_INFO_LTRUSE_FAILED    (VCD_EVT_IND_BASE + 0x7)
 
 #define VCD_S_SUCCESS           0x0
 
diff --git a/include/media/msm/vidc_type.h b/include/media/msm/vidc_type.h
index d4db0a0..809ec00 100644
--- a/include/media/msm/vidc_type.h
+++ b/include/media/msm/vidc_type.h
@@ -23,8 +23,9 @@
 #include <linux/dma-mapping.h>
 #include <linux/android_pmem.h>
 
-#define DEBUG   0
+#define DDL_MSG_LOG 0
+#define DEBUG 0
 #define VIDC_ENABLE_DBGFS
-
 #define USE_RES_TRACKER
+
 #endif
diff --git a/sound/soc/codecs/wcd9304.c b/sound/soc/codecs/wcd9304.c
index 3fc3f32..0d5771b 100644
--- a/sound/soc/codecs/wcd9304.c
+++ b/sound/soc/codecs/wcd9304.c
@@ -1919,7 +1919,7 @@
 				     int mask)
 {
 	/* XXX: wake_lock_timeout()? */
-	snd_soc_jack_report(jack, status, mask);
+	snd_soc_jack_report_no_dapm(jack, status, mask);
 }
 
 static void hphocp_off_report(struct sitar_priv *sitar,