Merge "arm/dt: msm8974: Report less busy time to the CPU"
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp.txt b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
index 812a895..4f31f07 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
@@ -30,7 +30,7 @@
 - qcom,ctrl-delay-us: delay in activation of led
 - qcom,dig-mod-gen-en: digital module generator
 - qcom,cs-out-en: current sink output enable
-- qcom,op-fdbck: selection of output as feedback for the boost
+- qcom,op-fdbck: selection of output as feedback for the boost, 00 = automatic selection, 01 = select LED1 output, 02 = select LED2 output, 03 = select LED3 output
 - qcom,cp-select: high pole capacitance
 - linux,default-trigger: trigger the led from external modules such as display
 - qcom,default-state:  default state of the led, should be "on" or "off"
@@ -138,7 +138,7 @@
 				linux,default-trigger = "bkl-trigger"
 				label = "wled";
 				qcom,cs-out-en;
-				qcom,op-fdbck;
+				qcom,op-fdbck = <1>;
 				qcom,default-state "off";
 				qcom,max-current = <25>;
 				qcom,ctrl-delay-us = <0>;
diff --git a/Documentation/devicetree/bindings/media/video/msm-vidc.txt b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
index bebdb5a..2caa959 100644
--- a/Documentation/devicetree/bindings/media/video/msm-vidc.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
@@ -40,6 +40,8 @@
   (enum hal_buffer) to its corresponding TZ usage. The TZ usages are defined
   as "enum cp_mem_usage" in include/linux/msm_ion.h
 - qcom,has-ocmem: indicate the target has ocmem if this property exists
+- qcom,max-hw-load: The maximum load the hardware can support expressed in units
+  of macroblocks per second.
 
 Example:
 
@@ -73,4 +75,5 @@
 		qcom,iommu-group-buffer-types = <0xfff 0x1ff>;
 		qcom,buffer-type-tz-usage-table = <0x1 0x1>,
 						<0x1fe 0x2>;
+		qcom,max-hw-load = <1224450>; /* 4k @ 30 + 1080p @ 30*/
 	};
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index 8e3bc70..9c0959d 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -814,7 +814,7 @@
 				qcom,calibration-type = "ratiometric";
 				qcom,scale-function = <2>;
 				qcom,hw-settle-time = <2>;
-				qcom,fast-avg-setup = <0>;
+				qcom,fast-avg-setup = <3>;
 				qcom,btm-channel-number = <0x48>;
 			};
 
@@ -826,7 +826,7 @@
 				qcom,calibration-type = "ratiometric";
 				qcom,scale-function = <1>;
 				qcom,hw-settle-time = <2>;
-				qcom,fast-avg-setup = <0>;
+				qcom,fast-avg-setup = <3>;
 				qcom,btm-channel-number = <0x68>;
 			};
 
@@ -838,8 +838,8 @@
 				qcom,calibration-type = "absolute";
 				qcom,scale-function = <1>;
 				qcom,hw-settle-time = <0>;
-				qcom,fast-avg-setup = <0>;
-				qcom,btm-channel-number = <0x88>;
+				qcom,fast-avg-setup = <3>;
+				qcom,btm-channel-number = <0x70>;
 			};
 
 			chan@6 {
@@ -848,10 +848,10 @@
 				qcom,decimation = <0>;
 				qcom,pre-div-channel-scaling = <1>;
 				qcom,calibration-type = "absolute";
-				qcom,scale-function = <3>;
+				qcom,scale-function = <0>;
 				qcom,hw-settle-time = <0>;
-				qcom,fast-avg-setup = <0>;
-				qcom,btm-channel-number = <0x90>;
+				qcom,fast-avg-setup = <3>;
+				qcom,btm-channel-number = <0x78>;
 			};
 
 			chan@b5 {
@@ -862,8 +862,8 @@
 				qcom,calibration-type = "absolute";
 				qcom,scale-function = <2>;
 				qcom,hw-settle-time = <2>;
-				qcom,fast-avg-setup = <0>;
-				qcom,btm-channel-number = <0x70>;
+				qcom,fast-avg-setup = <3>;
+				qcom,btm-channel-number = <0x80>;
 				qcom,thermal-node;
 			};
 
@@ -875,8 +875,8 @@
 				qcom,calibration-type = "ratiometric";
 				qcom,scale-function = <2>;
 				qcom,hw-settle-time = <2>;
-				qcom,fast-avg-setup = <0>;
-				qcom,btm-channel-number = <0x78>;
+				qcom,fast-avg-setup = <3>;
+				qcom,btm-channel-number = <0x88>;
 				qcom,thermal-node;
 			};
 
@@ -888,8 +888,8 @@
 				qcom,calibration-type = "ratiometric";
 				qcom,scale-function = <2>;
 				qcom,hw-settle-time = <2>;
-				qcom,fast-avg-setup = <0>;
-				qcom,btm-channel-number = <0x80>;
+				qcom,fast-avg-setup = <3>;
+				qcom,btm-channel-number = <0x90>;
 				qcom,thermal-node;
 			};
 
@@ -901,7 +901,7 @@
 				qcom,calibration-type = "ratiometric";
 				qcom,scale-function = <2>;
 				qcom,hw-settle-time = <2>;
-				qcom,fast-avg-setup = <0>;
+				qcom,fast-avg-setup = <3>;
 				qcom,btm-channel-number = <0x98>;
 				qcom,thermal-node;
 			};
diff --git a/arch/arm/boot/dts/msm8226-cdp.dts b/arch/arm/boot/dts/msm8226-cdp.dts
index 8d8aa79..eab8b07 100644
--- a/arch/arm/boot/dts/msm8226-cdp.dts
+++ b/arch/arm/boot/dts/msm8226-cdp.dts
@@ -189,7 +189,7 @@
 				linux,name = "wled:backlight";
 				linux,default-trigger = "bkl-trigger";
 				qcom,cs-out-en;
-				qcom,op-fdbck;
+				qcom,op-fdbck = <1>;
 				qcom,default-state = "on";
 				qcom,max-current = <25>;
 				qcom,ctrl-delay-us = <0>;
diff --git a/arch/arm/boot/dts/msm8226-mtp.dts b/arch/arm/boot/dts/msm8226-mtp.dts
index 32d9a95..5c6fbd5 100644
--- a/arch/arm/boot/dts/msm8226-mtp.dts
+++ b/arch/arm/boot/dts/msm8226-mtp.dts
@@ -182,7 +182,7 @@
 				linux,name = "wled:backlight";
 				linux,default-trigger = "bkl-trigger";
 				qcom,cs-out-en;
-				qcom,op-fdbck;
+				qcom,op-fdbck = <1>;
 				qcom,default-state = "on";
 				qcom,max-current = <25>;
 				qcom,ctrl-delay-us = <0>;
diff --git a/arch/arm/boot/dts/msm8226-pm.dtsi b/arch/arm/boot/dts/msm8226-pm.dtsi
index 34283e8..039c0b7 100644
--- a/arch/arm/boot/dts/msm8226-pm.dtsi
+++ b/arch/arm/boot/dts/msm8226-pm.dtsi
@@ -125,8 +125,8 @@
 			qcom,name = "vdd-mem";
 			qcom,type = <0x616F646C>;	/* "ldoa" */
 			qcom,id = <0x03>;
-			qcom,key = <0x7675>;		/* "uv" */
-			qcom,init-value = <1050000>;	/* Super Turbo */
+			qcom,key = <0x6e726f63>;	/* "corn" */
+			qcom,init-value = <3>;		/* Active */
 		};
 
 		qcom,lpm-resources@2 {
@@ -156,10 +156,10 @@
 			qcom,mode = "wfi";
 			qcom,xo = "xo_on";
 			qcom,l2 = "l2_cache_active";
-			qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
-			qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
-			qcom,vdd-dig-upper-bound = <5>; /* MAX */
-			qcom,vdd-dig-lower-bound = <3>;  /* ACTIVE */
+			qcom,vdd-mem-upper-bound = <5>; /* SUPER TURBO */
+			qcom,vdd-mem-lower-bound = <3>; /* NORMAL */
+			qcom,vdd-dig-upper-bound = <5>; /* SUPER TURBO */
+			qcom,vdd-dig-lower-bound = <3>;  /* NORMAL */
 			qcom,latency-us = <1>;
 			qcom,ss-power = <784>;
 			qcom,energy-overhead = <190000>;
@@ -171,10 +171,10 @@
 			qcom,mode = "retention";
 			qcom,xo = "xo_on";
 			qcom,l2 = "l2_cache_active";
-			qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
-			qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
-			qcom,vdd-dig-upper-bound = <5>; /* MAX */
-			qcom,vdd-dig-lower-bound = <3>;  /* ACTIVE */
+			qcom,vdd-mem-upper-bound = <5>; /* SUPER TURBO */
+			qcom,vdd-mem-lower-bound = <3>; /* NORMAL */
+			qcom,vdd-dig-upper-bound = <5>; /* SUPER TURBO */
+			qcom,vdd-dig-lower-bound = <3>;  /* NORMAL */
 			qcom,latency-us = <75>;
 			qcom,ss-power = <735>;
 			qcom,energy-overhead = <77341>;
@@ -187,10 +187,10 @@
 			qcom,mode = "standalone_pc";
 			qcom,xo = "xo_on";
 			qcom,l2 = "l2_cache_active";
-			qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
-			qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
-			qcom,vdd-dig-upper-bound = <5>; /* MAX */
-			qcom,vdd-dig-lower-bound = <3>;  /* ACTIVE */
+			qcom,vdd-mem-upper-bound = <5>; /* SUPER TURBO */
+			qcom,vdd-mem-lower-bound = <3>; /* NORMAL */
+			qcom,vdd-dig-upper-bound = <5>; /* SUPER TURBO */
+			qcom,vdd-dig-lower-bound = <3>;  /* NORMAL */
 			qcom,latency-us = <95>;
 			qcom,ss-power = <725>;
 			qcom,energy-overhead = <99500>;
@@ -202,10 +202,10 @@
 			qcom,mode = "pc";
 			qcom,xo = "xo_on";
 			qcom,l2 = "l2_cache_gdhs";
-			qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
-			qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
-			qcom,vdd-dig-upper-bound = <5>; /* MAX */
-			qcom,vdd-dig-lower-bound = <3>;  /* ACTIVE */
+			qcom,vdd-mem-upper-bound = <5>; /* SUPER TURBO */
+			qcom,vdd-mem-lower-bound = <3>; /* NORMAL */
+			qcom,vdd-dig-upper-bound = <5>; /* SUPER TURBO */
+			qcom,vdd-dig-lower-bound = <3>;  /* NORMAL */
 			qcom,latency-us = <2000>;
 			qcom,ss-power = <138>;
 			qcom,energy-overhead = <1208400>;
@@ -217,10 +217,10 @@
 			qcom,mode = "pc";
 			qcom,xo = "xo_on";
 			qcom,l2 = "l2_cache_pc";
-			qcom,vdd-mem-upper-bound = <1050000>; /* ACTIVE */
-			qcom,vdd-mem-lower-bound = <750000>;  /* RETENTION HIGH */
-			qcom,vdd-dig-upper-bound = <3>;  /* ACTIVE */
-			qcom,vdd-dig-lower-bound = <2>;  /* RETENTION HIGH */
+			qcom,vdd-mem-upper-bound = <3>; /* NORMAL */
+			qcom,vdd-mem-lower-bound = <2>;  /* SVS SOC */
+			qcom,vdd-dig-upper-bound = <3>;  /* NORMAL */
+			qcom,vdd-dig-lower-bound = <2>;  /* SVS SOC */
 			qcom,latency-us = <3000>;
 			qcom,ss-power = <110>;
 			qcom,energy-overhead = <1250300>;
@@ -232,10 +232,10 @@
 			qcom,mode = "pc";
 			qcom,xo = "xo_off";
 			qcom,l2 = "l2_cache_gdhs";
-			qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
-			qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
-			qcom,vdd-dig-upper-bound = <5>; /* MAX */
-			qcom,vdd-dig-lower-bound = <3>;  /* ACTIVE */
+			qcom,vdd-mem-upper-bound = <5>; /* SUPER TURBO */
+			qcom,vdd-mem-lower-bound = <3>; /* NORMAL */
+			qcom,vdd-dig-upper-bound = <5>; /* SUPER TURBO */
+			qcom,vdd-dig-lower-bound = <3>;  /* NORMAL */
 			qcom,latency-us = <3000>;
 			qcom,ss-power = <68>;
 			qcom,energy-overhead = <1350200>;
@@ -247,10 +247,10 @@
 			qcom,mode = "pc";
 			qcom,xo = "xo_off";
 			qcom,l2 = "l2_cache_pc";
-			qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
-			qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
-			qcom,vdd-dig-upper-bound = <5>; /* MAX */
-			qcom,vdd-dig-lower-bound = <3>;  /* ACTIVE */
+			qcom,vdd-mem-upper-bound = <5>; /* SUPER TURBO */
+			qcom,vdd-mem-lower-bound = <3>; /* NORMAL */
+			qcom,vdd-dig-upper-bound = <5>; /* SUPER TURBO */
+			qcom,vdd-dig-lower-bound = <3>;  /* NORMAL */
 			qcom,latency-us = <10300>;
 			qcom,ss-power = <63>;
 			qcom,energy-overhead = <2128000>;
@@ -262,10 +262,10 @@
 			qcom,mode = "pc";
 			qcom,xo = "xo_off";
 			qcom,l2 = "l2_cache_pc";
-			qcom,vdd-mem-upper-bound = <1050000>; /* ACTIVE */
-			qcom,vdd-mem-lower-bound = <750000>;  /* RETENTION HIGH */
-			qcom,vdd-dig-upper-bound = <3>;  /* ACTIVE */
-			qcom,vdd-dig-lower-bound = <2>;  /* RETIONTION HIGH */
+			qcom,vdd-mem-upper-bound = <3>; /* NORMAL */
+			qcom,vdd-mem-lower-bound = <2>;  /* SVS SOC */
+			qcom,vdd-dig-upper-bound = <3>;  /* NORMAL */
+			qcom,vdd-dig-lower-bound = <2>;  /* SVS SOC */
 			qcom,latency-us = <18000>;
 			qcom,ss-power = <10>;
 			qcom,energy-overhead = <3202600>;
@@ -277,10 +277,10 @@
 			qcom,mode = "pc";
 			qcom,xo = "xo_off";
 			qcom,l2 = "l2_cache_pc";
-			qcom,vdd-mem-upper-bound = <750000>; /* RETENTION HIGH */
-			qcom,vdd-mem-lower-bound = <750000>; /* RETENTION LOW */
-			qcom,vdd-dig-upper-bound = <2>; /* RETENTION HIGH */
-			qcom,vdd-dig-lower-bound = <0>; /* RETENTION LOW */
+			qcom,vdd-mem-upper-bound = <2>; /* SVS SOC */
+			qcom,vdd-mem-lower-bound = <0>; /* RETENTION */
+			qcom,vdd-dig-upper-bound = <2>; /* SVS SOC */
+			qcom,vdd-dig-lower-bound = <0>; /* RETENTION */
 			qcom,latency-us = <20000>;
 			qcom,ss-power = <2>;
 			qcom,energy-overhead = <4252000>;
diff --git a/arch/arm/boot/dts/msm8226-qrd.dts b/arch/arm/boot/dts/msm8226-qrd.dts
index ae97be9..df74bf9 100644
--- a/arch/arm/boot/dts/msm8226-qrd.dts
+++ b/arch/arm/boot/dts/msm8226-qrd.dts
@@ -185,7 +185,7 @@
 				linux,name = "wled:backlight";
 				linux,default-trigger = "bkl-trigger";
 				qcom,cs-out-en;
-				qcom,op-fdbck;
+				qcom,op-fdbck = <1>;
 				qcom,default-state = "on";
 				qcom,max-current = <25>;
 				qcom,ctrl-delay-us = <0>;
diff --git a/arch/arm/boot/dts/msm8226-regulator.dtsi b/arch/arm/boot/dts/msm8226-regulator.dtsi
index 9c21707..f24cea1 100644
--- a/arch/arm/boot/dts/msm8226-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8226-regulator.dtsi
@@ -64,7 +64,7 @@
 			regulator-min-microvolt = <1>;
 			regulator-max-microvolt = <7>;
 			qcom,use-voltage-corner;
-			qcom,consumer-supplies = "vdd_dig", "";
+			qcom,consumer-supplies = "vdd_dig", "", "vdd_sr2_dig", "";
 		};
 		pm8226_s1_corner_ao: regulator-s1-corner-ao {
 			compatible = "qcom,rpm-regulator-smd";
diff --git a/arch/arm/boot/dts/msm8226-smp2p.dtsi b/arch/arm/boot/dts/msm8226-smp2p.dtsi
index 1b08246..bdfc768 100644
--- a/arch/arm/boot/dts/msm8226-smp2p.dtsi
+++ b/arch/arm/boot/dts/msm8226-smp2p.dtsi
@@ -34,7 +34,6 @@
 		interrupts = <0 143 1>;
 	};
 
-	/* SMP2P Test Driver for inbound entries */
 	smp2pgpio_smp2p_7_in: qcom,smp2pgpio-smp2p-7-in {
 		compatible = "qcom,smp2pgpio";
 		qcom,entry-name = "smp2p";
@@ -51,7 +50,6 @@
 		gpios = <&smp2pgpio_smp2p_7_in 0 0>;
 	};
 
-	/* SMP2P Test Driver for outbound entries */
 	smp2pgpio_smp2p_7_out: qcom,smp2pgpio-smp2p-7-out {
 		compatible = "qcom,smp2pgpio";
 		qcom,entry-name = "smp2p";
@@ -67,7 +65,6 @@
 		gpios = <&smp2pgpio_smp2p_7_out 0 0>;
 	};
 
-	/* SMP2P Test Driver for modem inbound */
 	smp2pgpio_smp2p_1_in: qcom,smp2pgpio-smp2p-1-in {
 		compatible = "qcom,smp2pgpio";
 		qcom,entry-name = "smp2p";
@@ -84,7 +81,6 @@
 		gpios = <&smp2pgpio_smp2p_1_in 0 0>;
 	};
 
-	/* SMP2P Test Driver for modem output */
 	smp2pgpio_smp2p_1_out: qcom,smp2pgpio-smp2p-1-out {
 		compatible = "qcom,smp2pgpio";
 		qcom,entry-name = "smp2p";
@@ -100,7 +96,6 @@
 		gpios = <&smp2pgpio_smp2p_1_out 0 0>;
 	};
 
-	/* SMP2P SSR Driver for inbound entry from modem. */
 	smp2pgpio_ssr_smp2p_1_in: qcom,smp2pgpio-ssr-smp2p-1-in {
 		compatible = "qcom,smp2pgpio";
 		qcom,entry-name = "slave-kernel";
@@ -112,7 +107,6 @@
 		#interrupt-cells = <2>;
 	};
 
-	/* SMP2P SSR Driver for outbound entry to modem */
 	smp2pgpio_ssr_smp2p_1_out: qcom,smp2pgpio-ssr-smp2p-1-out {
 		compatible = "qcom,smp2pgpio";
 		qcom,entry-name = "master-kernel";
@@ -123,7 +117,6 @@
 		#interrupt-cells = <2>;
 	};
 
-	/* SMP2P Test Driver for adsp inbound */
 	smp2pgpio_smp2p_2_in: qcom,smp2pgpio-smp2p-2-in {
 		compatible = "qcom,smp2pgpio";
 		qcom,entry-name = "smp2p";
@@ -140,7 +133,6 @@
 		gpios = <&smp2pgpio_smp2p_2_in 0 0>;
 	};
 
-	/* SMP2P Test Driver for adsp output */
 	smp2pgpio_smp2p_2_out: qcom,smp2pgpio-smp2p-2-out {
 		compatible = "qcom,smp2pgpio";
 		qcom,entry-name = "smp2p";
@@ -156,7 +148,6 @@
 		gpios = <&smp2pgpio_smp2p_2_out 0 0>;
 	};
 
-	/* SMP2P Test Driver for wcnss inbound */
 	smp2pgpio_smp2p_4_in: qcom,smp2pgpio-smp2p-4-in {
 		compatible = "qcom,smp2pgpio";
 		qcom,entry-name = "smp2p";
@@ -173,7 +164,6 @@
 		gpios = <&smp2pgpio_smp2p_4_in 0 0>;
 	};
 
-	/* SMP2P Test Driver for wcnss output */
 	smp2pgpio_smp2p_4_out: qcom,smp2pgpio-smp2p-4-out {
 		compatible = "qcom,smp2pgpio";
 		qcom,entry-name = "smp2p";
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index 25c534b..b34fa1f 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -96,6 +96,7 @@
 		qcom,iommu-group-buffer-types = <0xfff 0x1ff>;
 		qcom,buffer-type-tz-usage-table = <0x1 0x1>,
 			<0x1fe 0x2>;
+		qcom,max-hw-load = <352800>; /* 720p @ 30 + 1080p @ 30 */
 	};
 
 	qcom,wfd {
@@ -574,7 +575,7 @@
 		compatible = "qcom,acpuclk-a7";
 		reg = <0xf9011050 0x8>;
 		reg-names = "rcg_base";
-		a7_cpu-supply = <&pm8226_s2>;
+		a7_cpu-supply = <&apc_vreg_corner>;
 		a7_mem-supply = <&pm8226_l3>;
 	};
 
diff --git a/arch/arm/boot/dts/msm8610-gpu.dtsi b/arch/arm/boot/dts/msm8610-gpu.dtsi
new file mode 100644
index 0000000..f3a8259
--- /dev/null
+++ b/arch/arm/boot/dts/msm8610-gpu.dtsi
@@ -0,0 +1,168 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+/ {
+	msm_gpu: qcom,kgsl-3d0@fdc00000 {
+		label = "kgsl-3d0";
+		compatible = "qcom,kgsl-3d0", "qcom,kgsl-3d";
+		reg = <0xfdc00000 0x10000
+		       0xfdc10000 0x10000>;
+		reg-names = "kgsl_3d0_reg_memory", "kgsl_3d0_shader_memory";
+		interrupts = <0 33 0>;
+		interrupt-names = "kgsl_3d0_irq";
+		qcom,id = <0>;
+
+		qcom,chipid = <0x03000520>;
+
+		qcom,initial-pwrlevel = <1>;
+
+		qcom,idle-timeout = <8>; /* <HZ/12> */
+		qcom,nap-allowed = <1>;
+		qcom,strtstp-sleepwake;
+		qcom,clk-map = <0x000001E>; /* KGSL_CLK_CORE |
+			KGSL_CLK_IFACE | KGSL_CLK_MEM | KGSL_CLK_MEM_IFACE */
+
+		/* Bus Scale Settings */
+		qcom,msm-bus,name = "grp3d";
+		qcom,msm-bus,num-cases = <4>;
+		qcom,msm-bus,active-only = <0>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+			<26 512 0 0>,
+			<26 512 0 800000>,
+			<26 512 0 1600000>,
+			<26 512 0 2128000>;
+
+		/* GDSC oxili regulators */
+		vdd-supply = <&gdsc_oxili_cx>;
+
+		/* IOMMU Data */
+		iommu = <&gfx_iommu>;
+
+		/* Power levels */
+		qcom,gpu-pwrlevels {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			compatible = "qcom,gpu-pwrlevels";
+
+			qcom,gpu-pwrlevel@0 {
+				reg = <0>;
+				qcom,gpu-freq = <400000000>;
+				qcom,bus-freq = <3>;
+				qcom,io-fraction = <0>;
+			};
+
+			qcom,gpu-pwrlevel@1 {
+				reg = <1>;
+				qcom,gpu-freq = <300000000>;
+				qcom,bus-freq = <2>;
+				qcom,io-fraction = <33>;
+			};
+
+			qcom,gpu-pwrlevel@2 {
+				reg = <2>;
+				qcom,gpu-freq = <200000000>;
+				qcom,bus-freq = <2>;
+				qcom,io-fraction = <33>;
+			};
+
+			qcom,gpu-pwrlevel@3 {
+				reg = <3>;
+				qcom,gpu-freq = <150000000>;
+				qcom,bus-freq = <1>;
+				qcom,io-fraction = <100>;
+			};
+
+			qcom,gpu-pwrlevel@4 {
+				reg = <4>;
+				qcom,gpu-freq = <27000000>;
+				qcom,bus-freq = <0>;
+				qcom,io-fraction = <0>;
+			};
+		};
+
+		/* DVCS Info */
+		qcom,dcvs-core-info {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			compatible = "qcom,dcvs-core-info";
+
+			qcom,num-cores = <1>;
+			qcom,sensors = <0>;
+
+			qcom,core-core-type = <1>;
+
+			qcom,algo-disable-pc-threshold = <0>;
+			qcom,algo-em-win-size-min-us = <100000>;
+			qcom,algo-em-win-size-max-us = <300000>;
+			qcom,algo-em-max-util-pct = <97>;
+			qcom,algo-group-id = <95>;
+			qcom,algo-max-freq-chg-time-us = <100000>;
+			qcom,algo-slack-mode-dynamic = <100000>;
+			qcom,algo-slack-weight-thresh-pct = <0>;
+			qcom,algo-slack-time-min-us = <39000>;
+			qcom,algo-slack-time-max-us = <39000>;
+			qcom,algo-ss-win-size-min-us = <1000000>;
+			qcom,algo-ss-win-size-max-us = <1000000>;
+			qcom,algo-ss-util-pct = <95>;
+			qcom,algo-ss-no-corr-below-freq = <0>;
+
+			qcom,energy-active-coeff-a = <2492>;
+			qcom,energy-active-coeff-b = <0>;
+			qcom,energy-active-coeff-c = <0>;
+			qcom,energy-leakage-coeff-a = <11>;
+			qcom,energy-leakage-coeff-b = <157150>;
+			qcom,energy-leakage-coeff-c = <0>;
+			qcom,energy-leakage-coeff-d = <0>;
+
+			qcom,power-current-temp = <25>;
+			qcom,power-num-freq = <4>;
+
+			qcom,dcvs-freq@0 {
+				reg = <0>;
+				qcom,freq = <0>;
+				qcom,voltage = <0>;
+				qcom,is_trans_level = <0>;
+				qcom,active-energy-offset = <100>;
+				qcom,leakage-energy-offset = <0>;
+			};
+
+			qcom,dcvs-freq@1 {
+				reg = <1>;
+				qcom,freq = <0>;
+				qcom,voltage = <0>;
+				qcom,is_trans_level = <0>;
+				qcom,active-energy-offset = <100>;
+				qcom,leakage-energy-offset = <0>;
+			};
+
+			qcom,dcvs-freq@2 {
+				reg = <2>;
+				qcom,freq = <0>;
+				qcom,voltage = <0>;
+				qcom,is_trans_level = <0>;
+				qcom,active-energy-offset = <100>;
+				qcom,leakage-energy-offset = <0>;
+			};
+
+			qcom,dcvs-freq@3 {
+				reg = <3>;
+				qcom,freq = <0>;
+				qcom,voltage = <0>;
+				qcom,is_trans_level = <0>;
+				qcom,active-energy-offset = <844545>;
+				qcom,leakage-energy-offset = <0>;
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/msm8610-regulator.dtsi b/arch/arm/boot/dts/msm8610-regulator.dtsi
index 1a88a2b..d50902c 100644
--- a/arch/arm/boot/dts/msm8610-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8610-regulator.dtsi
@@ -19,7 +19,7 @@
 		qcom,hpm-min-load = <100000>;
 		regulator-min-microvolt = <1>;
 		regulator-max-microvolt = <7>;
-		qcom,consumer-supplies = "vdd_dig", "";
+		qcom,consumer-supplies = "vdd_dig", "", "vdd_sr2_dig", "";
 	};
 };
 
@@ -37,6 +37,29 @@
 	};
 };
 
+/* CPR controlled regulator */
+
+/ {
+	apc_vreg_corner: regulator@f9018000 {
+		status = "okay";
+		compatible = "qcom,cpr-regulator";
+		reg = <0xf9018000 0x1000>,
+			<0xfc4b80b0 8>;
+		reg-names = "rbcpr", "efuse_phys";
+		regulator-name = "apc_corner";
+		regulator-min-microvolt = <1>;
+		regulator-max-microvolt = <4>;
+		qcom,num-efuse-bits = <5>;
+		qcom,efuse-bit-pos = <6 7 8 9 10>;
+		qcom,pvs-bin-process = <0 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2
+					2 2 2 2 3 3 3 3 3 3 3 3 0 0 0 0>;
+		qcom,pvs-corner-ceiling-slow = <1050000 1150000 1275000 1350000>;
+		qcom,pvs-corner-ceiling-nom  =  <975000 1075000 1200000 1200000>;
+		qcom,pvs-corner-ceiling-fast =  <900000 1000000 1140000 1140000>;
+		vdd-apc-supply = <&pm8110_s2>;
+	};
+};
+
 /* QPNP controlled regulators: */
 
 &spmi_bus {
diff --git a/arch/arm/boot/dts/msm8610-smp2p.dtsi b/arch/arm/boot/dts/msm8610-smp2p.dtsi
new file mode 100644
index 0000000..4a5273b
--- /dev/null
+++ b/arch/arm/boot/dts/msm8610-smp2p.dtsi
@@ -0,0 +1,184 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+/ {
+	qcom,smp2p-modem {
+		compatible = "qcom,smp2p";
+		reg = <0xfa006000 0x1000>, <0x8 0x0>;
+		reg-names = "irq-reg-base", "irq-reg-offset";
+		qcom,remote-pid = <1>;
+		qcom,irq-bitmask = <0x4000>;
+		interrupts = <0 27 1>;
+	};
+
+	qcom,smp2p-adsp {
+		compatible = "qcom,smp2p";
+		reg = <0xfa006000 0x1000>, <0x8 0x0>;
+		reg-names = "irq-reg-base", "irq-reg-offset";
+		qcom,remote-pid = <2>;
+		qcom,irq-bitmask = <0x400>;
+		interrupts = <0 158 1>;
+	};
+
+	qcom,smp2p-wcnss {
+		compatible = "qcom,smp2p";
+		reg = <0xfa006000 0x1000>, <0x8 0x0>;
+		reg-names = "irq-reg-base", "irq-reg-offset";
+		qcom,remote-pid = <4>;
+		qcom,irq-bitmask = <0x40000>;
+		interrupts = <0 143 1>;
+	};
+
+	smp2pgpio_smp2p_7_in: qcom,smp2pgpio-smp2p-7-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <7>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_7_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_7_in";
+		gpios = <&smp2pgpio_smp2p_7_in 0 0>;
+	};
+
+	smp2pgpio_smp2p_7_out: qcom,smp2pgpio-smp2p-7-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <7>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_7_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_7_out";
+		gpios = <&smp2pgpio_smp2p_7_out 0 0>;
+	};
+
+	smp2pgpio_smp2p_1_in: qcom,smp2pgpio-smp2p-1-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <1>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_1_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_1_in";
+		gpios = <&smp2pgpio_smp2p_1_in 0 0>;
+	};
+
+	smp2pgpio_smp2p_1_out: qcom,smp2pgpio-smp2p-1-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <1>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_1_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_1_out";
+		gpios = <&smp2pgpio_smp2p_1_out 0 0>;
+	};
+
+	smp2pgpio_ssr_smp2p_1_in: qcom,smp2pgpio-ssr-smp2p-1-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "slave-kernel";
+		qcom,remote-pid = <1>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	smp2pgpio_ssr_smp2p_1_out: qcom,smp2pgpio-ssr-smp2p-1-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "master-kernel";
+		qcom,remote-pid = <1>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	smp2pgpio_smp2p_2_in: qcom,smp2pgpio-smp2p-2-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <2>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_2_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_2_in";
+		gpios = <&smp2pgpio_smp2p_2_in 0 0>;
+	};
+
+	smp2pgpio_smp2p_2_out: qcom,smp2pgpio-smp2p-2-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <2>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_2_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_2_out";
+		gpios = <&smp2pgpio_smp2p_2_out 0 0>;
+	};
+
+	smp2pgpio_smp2p_4_in: qcom,smp2pgpio-smp2p-4-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <4>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_4_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_4_in";
+		gpios = <&smp2pgpio_smp2p_4_in 0 0>;
+	};
+
+	smp2pgpio_smp2p_4_out: qcom,smp2pgpio-smp2p-4-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <4>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_4_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_4_out";
+		gpios = <&smp2pgpio_smp2p_4_out 0 0>;
+	};
+};
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index d945619..91dfdbe 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -13,9 +13,11 @@
 /include/ "skeleton.dtsi"
 /include/ "msm-iommu-v0.dtsi"
 /include/ "msm8610-ion.dtsi"
+/include/ "msm8610-gpu.dtsi"
 /include/ "msm-gdsc.dtsi"
 /include/ "msm8610-coresight.dtsi"
 /include/ "msm8610-pm.dtsi"
+/include/ "msm8610-smp2p.dtsi"
 
 / {
 	model = "Qualcomm MSM 8610";
@@ -77,6 +79,7 @@
 		qcom,buffer-type-tz-usage-map = <0x1 0x1>,
 						<0x1fe 0x2>;
 		qcom,hfi = "q6";
+		qcom,max-hw-load = <97200>; /* FWVGA @ 30 * 2 */
 	};
 
 	usb@f9a55000 {
@@ -262,7 +265,7 @@
 		compatible = "qcom,acpuclk-a7";
 		reg = <0xf9011050 0x8>;
 		reg-names = "rcg_base";
-		a7_cpu-supply = <&pm8110_s2>;
+		a7_cpu-supply = <&apc_vreg_corner>;
 		a7_mem-supply = <&pm8110_l3>;
 	};
 
@@ -474,7 +477,7 @@
 		interrupts = <0 184 0>;
 		qcom,sensors = <2>;
 		qcom,slope = <2901 2846>;
-		qcom,calib-mode = "fuse_map2";
+		qcom,calib-mode = "fuse_map3";
 		qcom,calibration-less-mode;
 		qcom,tsens-local-init;
 	};
diff --git a/arch/arm/boot/dts/msm8974-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
index adab873..2919709 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-cdp.dtsi
@@ -247,7 +247,7 @@
 				linux,name = "wled:backlight";
 				linux,default-trigger = "bkl-trigger";
 				qcom,cs-out-en;
-				qcom,op-fdbck;
+				qcom,op-fdbck = <1>;
 				qcom,default-state = "on";
 				qcom,max-current = <25>;
 				qcom,ctrl-delay-us = <0>;
@@ -298,6 +298,10 @@
 	};
 };
 
+&sdcc1 {
+       status = "disabled";
+};
+
 &sdcc2 {
 	#address-cells = <0>;
 	interrupt-parent = <&sdcc2>;
@@ -310,6 +314,7 @@
 	interrupt-names = "core_irq", "bam_irq", "status_irq";
 	cd-gpios = <&msmgpio 62 0x1>;
 	wp-gpios = <&pm8941_gpios 29 0x1>;
+	status = "disabled";
 };
 
 &sdhc_1 {
@@ -331,6 +336,7 @@
 	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
 
 	qcom,nonremovable;
+	status = "ok";
 };
 
 &sdhc_2 {
@@ -358,6 +364,7 @@
 	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
 	qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
 	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+	status = "ok";
 };
 
 &uart7 {
diff --git a/arch/arm/boot/dts/msm8974-fluid.dtsi b/arch/arm/boot/dts/msm8974-fluid.dtsi
index e70d5d8..046939e 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-fluid.dtsi
@@ -224,7 +224,7 @@
 				linux,name = "wled:backlight";
 				linux,default-trigger = "bkl-trigger";
 				qcom,cs-out-en;
-				qcom,op-fdbck;
+				qcom,op-fdbck = <1>;
 				qcom,default-state = "on";
 				qcom,max-current = <25>;
 				qcom,ctrl-delay-us = <0>;
@@ -277,6 +277,7 @@
 
 &sdcc1 {
 	qcom,bus-width = <4>;
+	status = "disabled";
 };
 
 &sdcc2 {
@@ -290,6 +291,7 @@
 			2 &msmgpio 62 0x3>;
 	interrupt-names = "core_irq", "bam_irq", "status_irq";
 	cd-gpios = <&msmgpio 62 0x1>;
+	status = "disabled";
 };
 
 &sdhc_1 {
@@ -311,6 +313,7 @@
 	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
 
 	qcom,nonremovable;
+	status = "ok";
 };
 
 &sdhc_2 {
@@ -338,6 +341,7 @@
 	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
 	qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
 	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+	status = "ok";
 };
 
 &usb3 {
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index 8a8a8b7..0f38e44 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -764,6 +764,14 @@
 	};
 };
 
+&sdcc1 {
+       status = "disabled";
+};
+
+&sdcc2 {
+       status = "disabled";
+};
+
 &sdhc_1 {
 	vdd-supply = <&pm8941_l20>;
 	vdd-io-supply = <&pm8941_s3>;
@@ -783,6 +791,7 @@
 	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
 
 	qcom,nonremovable;
+	status = "ok";
 };
 
 &sdhc_2 {
@@ -799,4 +808,5 @@
 	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
 	qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
 	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+	status = "ok";
 };
diff --git a/arch/arm/boot/dts/msm8974-mtp.dtsi b/arch/arm/boot/dts/msm8974-mtp.dtsi
index d61de02..8fa1d75 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-mtp.dtsi
@@ -199,7 +199,7 @@
 				linux,name = "wled:backlight";
 				linux,default-trigger = "bkl-trigger";
 				qcom,cs-out-en;
-				qcom,op-fdbck;
+				qcom,op-fdbck = <1>;
 				qcom,default-state = "on";
 				qcom,max-current = <25>;
 				qcom,ctrl-delay-us = <0>;
@@ -250,6 +250,10 @@
 	};
 };
 
+&sdcc1 {
+       status = "disabled";
+};
+
 &sdcc2 {
 	#address-cells = <0>;
 	interrupt-parent = <&sdcc2>;
@@ -261,6 +265,7 @@
 			2 &msmgpio 62 0x3>;
 	interrupt-names = "core_irq", "bam_irq", "status_irq";
 	cd-gpios = <&msmgpio 62 0x1>;
+	status = "disabled";
 };
 
 &sdhc_1 {
@@ -282,6 +287,7 @@
 	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
 
 	qcom,nonremovable;
+	status = "ok";
 };
 
 &sdhc_2 {
@@ -309,6 +315,7 @@
 	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
 	qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
 	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+	status = "ok";
 };
 
 &usb_otg {
diff --git a/arch/arm/boot/dts/msm8974-smp2p.dtsi b/arch/arm/boot/dts/msm8974-smp2p.dtsi
index 1b08246..91029e2 100644
--- a/arch/arm/boot/dts/msm8974-smp2p.dtsi
+++ b/arch/arm/boot/dts/msm8974-smp2p.dtsi
@@ -34,7 +34,6 @@
 		interrupts = <0 143 1>;
 	};
 
-	/* SMP2P Test Driver for inbound entries */
 	smp2pgpio_smp2p_7_in: qcom,smp2pgpio-smp2p-7-in {
 		compatible = "qcom,smp2pgpio";
 		qcom,entry-name = "smp2p";
@@ -51,7 +50,6 @@
 		gpios = <&smp2pgpio_smp2p_7_in 0 0>;
 	};
 
-	/* SMP2P Test Driver for outbound entries */
 	smp2pgpio_smp2p_7_out: qcom,smp2pgpio-smp2p-7-out {
 		compatible = "qcom,smp2pgpio";
 		qcom,entry-name = "smp2p";
@@ -67,7 +65,6 @@
 		gpios = <&smp2pgpio_smp2p_7_out 0 0>;
 	};
 
-	/* SMP2P Test Driver for modem inbound */
 	smp2pgpio_smp2p_1_in: qcom,smp2pgpio-smp2p-1-in {
 		compatible = "qcom,smp2pgpio";
 		qcom,entry-name = "smp2p";
@@ -84,7 +81,6 @@
 		gpios = <&smp2pgpio_smp2p_1_in 0 0>;
 	};
 
-	/* SMP2P Test Driver for modem output */
 	smp2pgpio_smp2p_1_out: qcom,smp2pgpio-smp2p-1-out {
 		compatible = "qcom,smp2pgpio";
 		qcom,entry-name = "smp2p";
@@ -100,7 +96,6 @@
 		gpios = <&smp2pgpio_smp2p_1_out 0 0>;
 	};
 
-	/* SMP2P SSR Driver for inbound entry from modem. */
 	smp2pgpio_ssr_smp2p_1_in: qcom,smp2pgpio-ssr-smp2p-1-in {
 		compatible = "qcom,smp2pgpio";
 		qcom,entry-name = "slave-kernel";
@@ -112,7 +107,6 @@
 		#interrupt-cells = <2>;
 	};
 
-	/* SMP2P SSR Driver for outbound entry to modem */
 	smp2pgpio_ssr_smp2p_1_out: qcom,smp2pgpio-ssr-smp2p-1-out {
 		compatible = "qcom,smp2pgpio";
 		qcom,entry-name = "master-kernel";
@@ -123,7 +117,6 @@
 		#interrupt-cells = <2>;
 	};
 
-	/* SMP2P Test Driver for adsp inbound */
 	smp2pgpio_smp2p_2_in: qcom,smp2pgpio-smp2p-2-in {
 		compatible = "qcom,smp2pgpio";
 		qcom,entry-name = "smp2p";
@@ -140,7 +133,6 @@
 		gpios = <&smp2pgpio_smp2p_2_in 0 0>;
 	};
 
-	/* SMP2P Test Driver for adsp output */
 	smp2pgpio_smp2p_2_out: qcom,smp2pgpio-smp2p-2-out {
 		compatible = "qcom,smp2pgpio";
 		qcom,entry-name = "smp2p";
@@ -156,7 +148,6 @@
 		gpios = <&smp2pgpio_smp2p_2_out 0 0>;
 	};
 
-	/* SMP2P Test Driver for wcnss inbound */
 	smp2pgpio_smp2p_4_in: qcom,smp2pgpio-smp2p-4-in {
 		compatible = "qcom,smp2pgpio";
 		qcom,entry-name = "smp2p";
@@ -173,7 +164,6 @@
 		gpios = <&smp2pgpio_smp2p_4_in 0 0>;
 	};
 
-	/* SMP2P Test Driver for wcnss output */
 	smp2pgpio_smp2p_4_out: qcom,smp2pgpio-smp2p-4-out {
 		compatible = "qcom,smp2pgpio";
 		qcom,entry-name = "smp2p";
@@ -184,6 +174,27 @@
 		#interrupt-cells = <2>;
 	};
 
+	smp2pgpio_ssr_smp2p_4_in: qcom,smp2pgpio-ssr-smp2p-4-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "slave-kernel";
+		qcom,remote-pid = <4>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	smp2pgpio_ssr_smp2p_4_out: qcom,smp2pgpio-ssr-smp2p-4-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "master-kernel";
+		qcom,remote-pid = <4>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
 	qcom,smp2pgpio_test_smp2p_4_out {
 		compatible = "qcom,smp2pgpio_test_smp2p_4_out";
 		gpios = <&smp2pgpio_smp2p_4_out 0 0>;
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index c8bc3ab..c16feee 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -96,6 +96,7 @@
 		interrupts = <0 44 0>;
 		qcom,hfi = "venus";
 		qcom,has-ocmem;
+		qcom,max-hw-load = <1224450>; /* 4k @ 30 + 1080p @ 30*/
 	};
 
 	qcom,vidc {
@@ -209,6 +210,7 @@
 				<78 512 2048000 4096000>; /* Max. bandwidth */
 		qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000 100000000 200000000 4294967295>;
 		qcom,dat1-mpm-int = <42>;
+		status = "disable";
 	};
 
 	sdcc2: qcom,sdcc@f98a4000 {
@@ -255,6 +257,7 @@
 				<81 512 2048000 4096000>; /* Max. bandwidth */
 		qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000 100000000 200000000 4294967295>;
 		qcom,dat1-mpm-int = <44>;
+		status = "disable";
 	};
 
 	sdcc3: qcom,sdcc@f9864000 {
@@ -1020,6 +1023,12 @@
 		vdd_pronto_pll-supply = <&pm8941_l12>;
 
 		qcom,firmware-name = "wcnss";
+
+		/* GPIO input from wcnss */
+		qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_4_in 0 0>;
+
+		/* GPIO output to wcnss */
+		qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_4_out 0 0>;
 	};
 
 	qcom,iris-fm {
@@ -1269,6 +1278,7 @@
 		compatible = "qcom,bam_dmux";
 		reg = <0xfc834000 0x7000>;
 		interrupts = <0 29 1>;
+		qcom,rx-ring-size = <64>;
 	};
 
         qcom,msm-mem-hole {
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 85738d0..590692c 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -59,6 +59,7 @@
 CONFIG_MSM_WATCHDOG_V2=y
 CONFIG_MSM_MEMORY_DUMP=y
 CONFIG_MSM_DLOAD_MODE=y
+CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
 CONFIG_MSM_ADSP_LOADER=m
 CONFIG_MSM_OCMEM=y
 CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
diff --git a/arch/arm/configs/msm9625-perf_defconfig b/arch/arm/configs/msm9625-perf_defconfig
index 8d6bc81..42acd99 100644
--- a/arch/arm/configs/msm9625-perf_defconfig
+++ b/arch/arm/configs/msm9625-perf_defconfig
@@ -53,6 +53,7 @@
 CONFIG_MSM_WATCHDOG_V2=y
 CONFIG_MSM_MEMORY_DUMP=y
 CONFIG_MSM_DLOAD_MODE=y
+CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
 CONFIG_MSM_ADSP_LOADER=m
 CONFIG_MSM_RTB=y
 CONFIG_MSM_UARTDM_Core_v14=y
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index 9e9bba9..041e89a 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -53,6 +53,7 @@
 CONFIG_MSM_WATCHDOG_V2=y
 CONFIG_MSM_MEMORY_DUMP=y
 CONFIG_MSM_DLOAD_MODE=y
+CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
 CONFIG_MSM_ADSP_LOADER=m
 CONFIG_MSM_RTB=y
 CONFIG_MSM_UARTDM_Core_v14=y
diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c
index 2b3667f..366debb 100644
--- a/arch/arm/kernel/arch_timer.c
+++ b/arch/arm/kernel/arch_timer.c
@@ -381,6 +381,8 @@
 	.stop	= arch_timer_stop,
 };
 
+static struct clock_event_device arch_timer_global_evt;
+
 static int __init arch_timer_common_register(void)
 {
 	int err;
@@ -431,9 +433,19 @@
 	}
 
 	err = local_timer_register(&arch_timer_ops);
+	if (err) {
+		/*
+		 * We couldn't register as a local timer (could be
+		 * because we're on a UP platform, or because some
+		 * other local timer is already present...). Try as a
+		 * global timer instead.
+		 */
+		arch_timer_global_evt.cpumask = cpumask_of(0);
+		err = arch_timer_setup(&arch_timer_global_evt);
+	}
+
 	if (err)
 		goto out_free_irq;
-	percpu_timer_setup();
 
 	/* Use the architected timer for the delay loop. */
 	arch_delay_timer.read_current_timer = &arch_timer_read_current_timer;
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index cef66ec..c440f47 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -742,6 +742,7 @@
 static struct of_device_id armpmu_of_device_ids[] = {
 	{.compatible = "arm,cortex-a9-pmu"},
 	{.compatible = "arm,cortex-a8-pmu"},
+	{.compatible = "arm,cortex-a5-pmu"},
 	{.compatible = "arm,arm1136-pmu"},
 	{.compatible = "arm,arm1176-pmu"},
 	{.compatible = "qcom,krait-pmu"},
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index db53ae5..54806ae 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -368,10 +368,8 @@
 	select ARM_GIC
 	select MIGHT_HAVE_CACHE_L2X0
 	select ARCH_MSM_CORTEX_A5
-	select SMP
-	select MSM_SMP
 	select CPU_V7
-	select MSM_SCM if SMP
+	select MSM_SCM
 	select MSM_GPIOMUX
 	select MSM_RPM_SMD
 	select MSM_NATIVE_RESTART
@@ -428,6 +426,7 @@
 	select REGULATOR
 	select MSM_RPM_REGULATOR_SMD
 	select MSM_SPM_REGULATOR
+	select MSM_JTAG_MM if CORESIGHT_ETM
 	select MSM_CPR_REGULATOR
 
 config ARCH_MSM8226
diff --git a/arch/arm/mach-msm/acpuclock-8226.c b/arch/arm/mach-msm/acpuclock-8226.c
index 73ea435..6e93c57 100644
--- a/arch/arm/mach-msm/acpuclock-8226.c
+++ b/arch/arm/mach-msm/acpuclock-8226.c
@@ -19,6 +19,7 @@
 #include <linux/io.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/consumer.h>
+#include <linux/regulator/cpr-regulator.h>
 
 #include <mach/clk-provider.h>
 #include <mach/msm_bus.h>
@@ -53,13 +54,13 @@
  * 3) Depending on Frodo version, may need minimum of LVL_NOM
  */
 static struct clkctl_acpu_speed acpu_freq_tbl[] = {
-	{ 0,   19200, CXO,     0, 0,   1150000,   1150000, 0 },
-	{ 1,  300000, PLL0,    4, 2,   1150000,   1150000, 4 },
-	{ 1,  384000, ACPUPLL, 5, 0,   1150000,   1150000, 4 },
-	{ 1,  600000, PLL0,    4, 0,   1150000,   1150000, 6 },
-	{ 1,  787200, ACPUPLL, 5, 0,   1150000,   1150000, 7 },
-	{ 0,  998400, ACPUPLL, 5, 0,   1150000,   1150000, 7 },
-	{ 0, 1190400, ACPUPLL, 5, 0,   1150000,   1150000, 7 },
+	{ 0,   19200, CXO,     0, 0,   CPR_CORNER_SVS,   1150000, 0 },
+	{ 1,  300000, PLL0,    4, 2,   CPR_CORNER_SVS,   1150000, 4 },
+	{ 1,  384000, ACPUPLL, 5, 0,   CPR_CORNER_SVS,   1150000, 4 },
+	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_NORMAL,   1150000, 6 },
+	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_NORMAL,   1150000, 7 },
+	{ 0,  998400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,   1150000, 7 },
+	{ 0, 1190400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,   1150000, 7 },
 	{ 0 }
 };
 
@@ -67,8 +68,7 @@
 	.freq_tbl = acpu_freq_tbl,
 	.current_speed = &(struct clkctl_acpu_speed){ 0 },
 	.bus_scale = &bus_client_pdata,
-	/* FIXME regulator doesn't support corners yet */
-	.vdd_max_cpu = 1150000,
+	.vdd_max_cpu = CPR_CORNER_TURBO,
 	.vdd_max_mem = 1150000,
 	.src_clocks = {
 		[PLL0].name = "gpll0",
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index a645e9c..b7c46b4 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -345,9 +345,6 @@
 #define      gpll0_mm_source_val 5
 #define     gcc_xo_mm_source_val 0
 #define        mm_gnd_source_val 6
-#define     cxo_lpass_source_val 0
-#define lpapll0_lpass_source_val 1
-#define   gpll0_lpass_source_val 5
 #define     dsipll_mm_source_val 1
 
 #define F(f, s, div, m, n) \
@@ -404,17 +401,6 @@
 			| BVAL(10, 8, s##_mm_source_val), \
 	}
 
-#define F_LPASS(f, s, div, m, n) \
-	{ \
-		.freq_hz = (f), \
-		.src_clk = &s##_clk_src.c, \
-		.m_val = (m), \
-		.n_val = ~((n)-(m)) * !!(n), \
-		.d_val = ~(n),\
-		.div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
-			| BVAL(10, 8, s##_lpass_source_val), \
-	}
-
 #define VDD_DIG_FMAX_MAP1(l1, f1) \
 	.vdd_class = &vdd_dig,			\
 	.fmax = (unsigned long[VDD_DIG_NUM]) {	\
@@ -672,21 +658,6 @@
 	.base = &virt_bases[MMSS_BASE],
 };
 
-static struct pll_vote_clk lpapll0_clk_src = {
-	.en_reg = (void __iomem *)LPA_PLL_VOTE_APPS,
-	.en_mask = BIT(0),
-	.status_reg = (void __iomem *)LPAAUDIO_PLL_STATUS,
-	.status_mask = BIT(17),
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.parent = &gcc_xo_clk_src.c,
-		.rate = 491520000,
-		.dbg_name = "lpapll0_clk_src",
-		.ops = &clk_ops_pll_vote,
-		CLK_INIT(lpapll0_clk_src.c),
-	},
-};
-
 static struct clk_freq_tbl ftbl_gcc_blsp1_qup1_6_spi_apps_clk[] = {
 	F(  960000, gcc_xo, 10, 1, 2),
 	F( 4800000, gcc_xo,  4, 0, 0),
@@ -2227,197 +2198,6 @@
 	},
 };
 
-static struct clk_freq_tbl ftbl_audio_core_lpaif_clk[] = {
-	F_LPASS(  512000, lpapll0, 16, 1, 60),
-	F_LPASS(  768000, lpapll0, 16, 1, 40),
-	F_LPASS( 1024000, lpapll0, 16, 1, 30),
-	F_LPASS( 1536000, lpapll0, 16, 1, 20),
-	F_LPASS( 2048000, lpapll0, 16, 1, 15),
-	F_LPASS( 3072000, lpapll0, 16, 1, 10),
-	F_LPASS( 4096000, lpapll0, 15, 1,  8),
-	F_LPASS( 6144000, lpapll0, 10, 1,  8),
-	F_LPASS( 8192000, lpapll0, 15, 1,  4),
-	F_LPASS(12288000, lpapll0, 10, 1,  4),
-	F_END,
-};
-
-static struct rcg_clk lpaif_pri_clk_src = {
-	.cmd_rcgr_reg =  LPAIF_PRI_CMD_RCGR,
-	.set_rate = set_rate_mnd,
-	.freq_tbl = ftbl_audio_core_lpaif_clk,
-	.current_freq = &rcg_dummy_freq,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "lpaif_pri_clk_src",
-		.ops = &clk_ops_rcg_mnd,
-		VDD_DIG_FMAX_MAP2(LOW, 12290000, NOMINAL, 24580000),
-		CLK_INIT(lpaif_pri_clk_src.c),
-	},
-};
-
-static struct rcg_clk lpaif_quad_clk_src = {
-	.cmd_rcgr_reg =  LPAIF_QUAD_CMD_RCGR,
-	.set_rate = set_rate_mnd,
-	.freq_tbl = ftbl_audio_core_lpaif_clk,
-	.current_freq = &rcg_dummy_freq,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "lpaif_quad_clk_src",
-		.ops = &clk_ops_rcg_mnd,
-		VDD_DIG_FMAX_MAP2(LOW, 12290000, NOMINAL, 24580000),
-		CLK_INIT(lpaif_quad_clk_src.c),
-	},
-};
-
-static struct rcg_clk lpaif_sec_clk_src = {
-	.cmd_rcgr_reg =  LPAIF_SEC_CMD_RCGR,
-	.set_rate = set_rate_mnd,
-	.freq_tbl = ftbl_audio_core_lpaif_clk,
-	.current_freq = &rcg_dummy_freq,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "lpaif_sec_clk_src",
-		.ops = &clk_ops_rcg_mnd,
-		VDD_DIG_FMAX_MAP2(LOW, 12290000, NOMINAL, 24580000),
-		CLK_INIT(lpaif_sec_clk_src.c),
-	},
-};
-
-static struct rcg_clk lpaif_spkr_clk_src = {
-	.cmd_rcgr_reg =  LPAIF_SPKR_CMD_RCGR,
-	.set_rate = set_rate_mnd,
-	.freq_tbl = ftbl_audio_core_lpaif_clk,
-	.current_freq = &rcg_dummy_freq,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "lpaif_spkr_clk_src",
-		.ops = &clk_ops_rcg_mnd,
-		VDD_DIG_FMAX_MAP2(LOW, 12290000, NOMINAL, 24580000),
-		CLK_INIT(lpaif_spkr_clk_src.c),
-	},
-};
-
-static struct rcg_clk lpaif_ter_clk_src = {
-	.cmd_rcgr_reg =  LPAIF_TER_CMD_RCGR,
-	.set_rate = set_rate_mnd,
-	.freq_tbl = ftbl_audio_core_lpaif_clk,
-	.current_freq = &rcg_dummy_freq,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "lpaif_ter_clk_src",
-		.ops = &clk_ops_rcg_mnd,
-		VDD_DIG_FMAX_MAP2(LOW, 12290000, NOMINAL, 24580000),
-		CLK_INIT(lpaif_ter_clk_src.c),
-	},
-};
-
-static struct clk_freq_tbl ftbl_audio_core_lpaif_pcm0_1_clk[] = {
-	F_LPASS( 512000, lpapll0, 16, 1, 60),
-	F_LPASS( 768000, lpapll0, 16, 1, 40),
-	F_LPASS(1024000, lpapll0, 16, 1, 30),
-	F_LPASS(1536000, lpapll0, 16, 1, 20),
-	F_LPASS(2048000, lpapll0, 16, 1, 15),
-	F_LPASS(3072000, lpapll0, 16, 1, 10),
-	F_LPASS(4096000, lpapll0, 15, 1,  8),
-	F_LPASS(6144000, lpapll0, 10, 1,  8),
-	F_LPASS(8192000, lpapll0, 15, 1,  4),
-	F_END,
-};
-
-static struct rcg_clk lpaif_pcm0_clk_src = {
-	.cmd_rcgr_reg =  LPAIF_PCM0_CMD_RCGR,
-	.set_rate = set_rate_mnd,
-	.freq_tbl = ftbl_audio_core_lpaif_pcm0_1_clk,
-	.current_freq = &rcg_dummy_freq,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "lpaif_pcm0_clk_src",
-		.ops = &clk_ops_rcg_mnd,
-		VDD_DIG_FMAX_MAP2(LOW, 4100000, NOMINAL, 8192000),
-		CLK_INIT(lpaif_pcm0_clk_src.c),
-	},
-};
-
-static struct rcg_clk lpaif_pcm1_clk_src = {
-	.cmd_rcgr_reg =  LPAIF_PCM1_CMD_RCGR,
-	.set_rate = set_rate_mnd,
-	.freq_tbl = ftbl_audio_core_lpaif_pcm0_1_clk,
-	.current_freq = &rcg_dummy_freq,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "lpaif_pcm1_clk_src",
-		.ops = &clk_ops_rcg_mnd,
-		VDD_DIG_FMAX_MAP2(LOW, 4100000, NOMINAL, 8192000),
-		CLK_INIT(lpaif_pcm1_clk_src.c),
-	},
-};
-
-static struct rcg_clk lpaif_pcmoe_clk_src = {
-	.cmd_rcgr_reg =  LPAIF_PCMOE_CMD_RCGR,
-	.set_rate = set_rate_mnd,
-	.freq_tbl = ftbl_audio_core_lpaif_pcm0_1_clk,
-	.current_freq = &rcg_dummy_freq,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "lpaif_pcmoe_clk_src",
-		.ops = &clk_ops_rcg_mnd,
-		VDD_DIG_FMAX_MAP2(LOW, 6140000, NOMINAL, 12290000),
-		CLK_INIT(lpaif_pcmoe_clk_src.c),
-	},
-};
-
-static struct clk_freq_tbl ftbl_audio_core_slimbus_core_clock[] = {
-	F_LPASS(24576000, lpapll0, 4, 1, 5),
-	F_END
-};
-
-static struct rcg_clk audio_core_slimbus_core_clk_src = {
-	.cmd_rcgr_reg = SLIMBUS_CMD_RCGR,
-	.set_rate = set_rate_mnd,
-	.freq_tbl = ftbl_audio_core_slimbus_core_clock,
-	.current_freq = &rcg_dummy_freq,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "audio_core_slimbus_core_clk_src",
-		.ops = &clk_ops_rcg_mnd,
-		VDD_DIG_FMAX_MAP2(LOW, 12935000, NOMINAL, 25869000),
-		CLK_INIT(audio_core_slimbus_core_clk_src.c),
-	},
-};
-
-static struct branch_clk audio_core_slimbus_core_clk = {
-	.cbcr_reg = AUDIO_CORE_SLIMBUS_CORE_CBCR,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.parent = &audio_core_slimbus_core_clk_src.c,
-		.dbg_name = "audio_core_slimbus_core_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_slimbus_core_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_ixfabric_clk = {
-	.cbcr_reg = AUDIO_CORE_IXFABRIC_CBCR,
-	.has_sibling = 1,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "audio_core_ixfabric_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_ixfabric_clk.c),
-	},
-};
-
-static struct branch_clk audio_wrapper_br_clk = {
-	.cbcr_reg = AUDIO_WRAPPER_BR_CBCR,
-	.has_sibling = 1,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "audio_wrapper_br_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_wrapper_br_clk.c),
-	},
-};
-
 static struct branch_clk q6ss_ahb_lfabif_clk = {
 	.cbcr_reg = Q6SS_AHB_LFABIF_CBCR,
 	.has_sibling = 1,
@@ -2453,244 +2233,6 @@
 	},
 };
 
-static struct branch_clk audio_core_lpaif_pcm_data_oe_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_PCM_DATA_OE_CBCR,
-	.has_sibling = 0,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.parent = &lpaif_pcmoe_clk_src.c,
-		.dbg_name = "audio_core_lpaif_pcm_data_oe_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_pcm_data_oe_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_pri_ebit_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_PRI_EBIT_CBCR,
-	.has_sibling = 0,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "audio_core_lpaif_pri_ebit_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_pri_ebit_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_pri_ibit_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_PRI_IBIT_CBCR,
-	.has_sibling = 0,
-	.max_div = 511,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.parent = &lpaif_pri_clk_src.c,
-		.dbg_name = "audio_core_lpaif_pri_ibit_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_pri_ibit_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_pri_osr_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_PRI_OSR_CBCR,
-	.has_sibling = 0,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.parent = &lpaif_pri_clk_src.c,
-		.dbg_name = "audio_core_lpaif_pri_osr_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_pri_osr_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_pcm0_ebit_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_PCM0_EBIT_CBCR,
-	.has_sibling = 0,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "audio_core_lpaif_pcm0_ebit_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_pcm0_ebit_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_pcm0_ibit_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_PCM0_IBIT_CBCR,
-	.has_sibling = 0,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.parent = &lpaif_pcm0_clk_src.c,
-		.dbg_name = "audio_core_lpaif_pcm0_ibit_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_pcm0_ibit_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_quad_ebit_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_QUAD_EBIT_CBCR,
-	.has_sibling = 0,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "audio_core_lpaif_quad_ebit_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_quad_ebit_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_quad_ibit_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_QUAD_IBIT_CBCR,
-	.has_sibling = 0,
-	.max_div = 511,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.parent = &lpaif_quad_clk_src.c,
-		.dbg_name = "audio_core_lpaif_quad_ibit_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_quad_ibit_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_quad_osr_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_QUAD_OSR_CBCR,
-	.has_sibling = 0,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.parent = &lpaif_quad_clk_src.c,
-		.dbg_name = "audio_core_lpaif_quad_osr_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_quad_osr_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_sec_ebit_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_SEC_EBIT_CBCR,
-	.has_sibling = 0,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "audio_core_lpaif_sec_ebit_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_sec_ebit_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_sec_ibit_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_SEC_IBIT_CBCR,
-	.has_sibling = 0,
-	.max_div = 511,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.parent = &lpaif_sec_clk_src.c,
-		.dbg_name = "audio_core_lpaif_sec_ibit_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_sec_ibit_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_sec_osr_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_SEC_OSR_CBCR,
-	.has_sibling = 0,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.parent = &lpaif_sec_clk_src.c,
-		.dbg_name = "audio_core_lpaif_sec_osr_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_sec_osr_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_pcm1_ebit_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_PCM1_EBIT_CBCR,
-	.has_sibling = 0,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "audio_core_lpaif_pcm1_ebit_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_pcm1_ebit_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_pcm1_ibit_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_PCM1_IBIT_CBCR,
-	.has_sibling = 0,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.parent = &lpaif_pcm1_clk_src.c,
-		.dbg_name = "audio_core_lpaif_pcm1_ibit_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_pcm1_ibit_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_codec_spkr_ebit_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_CODEC_SPKR_EBIT_CBCR,
-	.has_sibling = 0,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "audio_core_lpaif_codec_spkr_ebit_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_codec_spkr_ebit_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_codec_spkr_ibit_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_CODEC_SPKR_IBIT_CBCR,
-	.has_sibling = 1,
-	.max_div = 511,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.parent = &lpaif_spkr_clk_src.c,
-		.dbg_name = "audio_core_lpaif_codec_spkr_ibit_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_codec_spkr_ibit_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_codec_spkr_osr_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_CODEC_SPKR_OSR_CBCR,
-	.has_sibling = 1,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.parent = &lpaif_spkr_clk_src.c,
-		.dbg_name = "audio_core_lpaif_codec_spkr_osr_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_codec_spkr_osr_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_ter_ebit_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_TER_EBIT_CBCR,
-	.has_sibling = 0,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "audio_core_lpaif_ter_ebit_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_ter_ebit_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_ter_ibit_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_TER_IBIT_CBCR,
-	.has_sibling = 0,
-	.max_div = 511,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.parent = &lpaif_ter_clk_src.c,
-		.dbg_name = "audio_core_lpaif_ter_ibit_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_ter_ibit_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_ter_osr_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_TER_OSR_CBCR,
-	.has_sibling = 0,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.parent = &lpaif_ter_clk_src.c,
-		.dbg_name = "audio_core_lpaif_ter_osr_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_ter_osr_clk.c),
-	},
-};
-
 #ifdef CONFIG_DEBUG_FS
 
 struct measure_mux_entry {
@@ -2781,20 +2323,9 @@
 	{         &csi1pix_clk.c, MMSS_BASE, 0x0025},
 	{        &bimc_gfx_clk.c, MMSS_BASE, 0x0032},
 
-	{             &lpaif_pcmoe_clk_src.c, LPASS_BASE, 0x000f},
-	{              &lpaif_pcm1_clk_src.c, LPASS_BASE, 0x0012},
-	{              &lpaif_pcm0_clk_src.c, LPASS_BASE, 0x0013},
-	{              &lpaif_quad_clk_src.c, LPASS_BASE, 0x0014},
-	{               &lpaif_ter_clk_src.c, LPASS_BASE, 0x0015},
-	{               &lpaif_sec_clk_src.c, LPASS_BASE, 0x0016},
-	{               &lpaif_pri_clk_src.c, LPASS_BASE, 0x0017},
-	{              &lpaif_spkr_clk_src.c, LPASS_BASE, 0x0018},
 	{                   &q6ss_ahbm_clk.c, LPASS_BASE, 0x001d},
 	{             &q6ss_ahb_lfabif_clk.c, LPASS_BASE, 0x001e},
-	{            &audio_wrapper_br_clk.c, LPASS_BASE, 0x0022},
 	{                     &q6ss_xo_clk.c, LPASS_BASE, 0x002b},
-	{&audio_core_lpaif_pcm_data_oe_clk.c, LPASS_BASE, 0x0030},
-	{         &audio_core_ixfabric_clk.c, LPASS_BASE, 0x0059},
 
 	{&apc0_m_clk,                    APCS_BASE, 0x10},
 	{&apc1_m_clk,                    APCS_BASE, 0x11},
@@ -3232,40 +2763,6 @@
 							 "fd010000.qcom,iommu"),
 	CLK_LOOKUP("core_clk",         pnoc_iommu_clk.c, "fd010000.qcom,iommu"),
 
-	CLK_LOOKUP("core_clk_src",                 lpaif_pri_clk_src.c, ""),
-	CLK_LOOKUP("core_clk_src",                lpaif_quad_clk_src.c, ""),
-	CLK_LOOKUP("core_clk_src",                 lpaif_sec_clk_src.c, ""),
-	CLK_LOOKUP("core_clk_src",                lpaif_spkr_clk_src.c, ""),
-	CLK_LOOKUP("core_clk_src",                 lpaif_ter_clk_src.c, ""),
-	CLK_LOOKUP("core_clk_src",                lpaif_pcm0_clk_src.c, ""),
-	CLK_LOOKUP("core_clk_src",                lpaif_pcm1_clk_src.c, ""),
-	CLK_LOOKUP("core_clk_src",               lpaif_pcmoe_clk_src.c, ""),
-	CLK_LOOKUP("core_clk",               audio_core_ixfabric_clk.c, ""),
-	CLK_LOOKUP("core_clk",                  audio_wrapper_br_clk.c, ""),
-	CLK_LOOKUP("core_clk",                   q6ss_ahb_lfabif_clk.c, ""),
-	CLK_LOOKUP("core_clk",                         q6ss_ahbm_clk.c, ""),
-	CLK_LOOKUP("core_clk",                           q6ss_xo_clk.c, ""),
-	CLK_LOOKUP("core_clk",      audio_core_lpaif_pcm_data_oe_clk.c, ""),
-	CLK_LOOKUP("core_clk",         audio_core_lpaif_pri_ebit_clk.c, ""),
-	CLK_LOOKUP("core_clk",         audio_core_lpaif_pri_ibit_clk.c, ""),
-	CLK_LOOKUP("core_clk",          audio_core_lpaif_pri_osr_clk.c, ""),
-	CLK_LOOKUP("core_clk",        audio_core_lpaif_pcm0_ebit_clk.c, ""),
-	CLK_LOOKUP("core_clk",        audio_core_lpaif_pcm0_ibit_clk.c, ""),
-	CLK_LOOKUP("core_clk",        audio_core_lpaif_quad_ebit_clk.c, ""),
-	CLK_LOOKUP("core_clk",        audio_core_lpaif_quad_ibit_clk.c, ""),
-	CLK_LOOKUP("core_clk",         audio_core_lpaif_quad_osr_clk.c, ""),
-	CLK_LOOKUP("core_clk",         audio_core_lpaif_sec_ebit_clk.c, ""),
-	CLK_LOOKUP("core_clk",         audio_core_lpaif_sec_ibit_clk.c, ""),
-	CLK_LOOKUP("core_clk",          audio_core_lpaif_sec_osr_clk.c, ""),
-	CLK_LOOKUP("core_clk",        audio_core_lpaif_pcm1_ebit_clk.c, ""),
-	CLK_LOOKUP("core_clk",        audio_core_lpaif_pcm1_ibit_clk.c, ""),
-	CLK_LOOKUP("core_clk",  audio_core_lpaif_codec_spkr_ebit_clk.c, ""),
-	CLK_LOOKUP("core_clk",  audio_core_lpaif_codec_spkr_ibit_clk.c, ""),
-	CLK_LOOKUP("core_clk",   audio_core_lpaif_codec_spkr_osr_clk.c, ""),
-	CLK_LOOKUP("core_clk",         audio_core_lpaif_ter_ebit_clk.c, ""),
-	CLK_LOOKUP("core_clk",         audio_core_lpaif_ter_ibit_clk.c, ""),
-	CLK_LOOKUP("core_clk",          audio_core_lpaif_ter_osr_clk.c, ""),
-
 	CLK_LOOKUP("core_clk",         q6ss_xo_clk.c,  "fe200000.qcom,lpass"),
 	CLK_LOOKUP("bus_clk", gcc_lpass_q6_axi_clk.c,  "fe200000.qcom,lpass"),
 	CLK_LOOKUP("iface_clk", q6ss_ahb_lfabif_clk.c, "fe200000.qcom,lpass"),
@@ -3316,32 +2813,6 @@
 	.size = ARRAY_SIZE(msm_clocks_8610_rumi),
 };
 
-static struct pll_config_regs gpll0_regs __initdata = {
-	.l_reg = (void __iomem *)GPLL0_L_VAL,
-	.m_reg = (void __iomem *)GPLL0_M_VAL,
-	.n_reg = (void __iomem *)GPLL0_N_VAL,
-	.config_reg = (void __iomem *)GPLL0_USER_CTL,
-	.mode_reg = (void __iomem *)GPLL0_MODE,
-	.base = &virt_bases[GCC_BASE],
-};
-
-/* GPLL0 at 600 MHz, main output enabled. */
-static struct pll_config gpll0_config __initdata = {
-	.l = 0x1f,
-	.m = 0x1,
-	.n = 0x4,
-	.vco_val = 0x0,
-	.vco_mask = BM(21, 20),
-	.pre_div_val = 0x0,
-	.pre_div_mask = BM(14, 12),
-	.post_div_val = 0x0,
-	.post_div_mask = BM(9, 8),
-	.mn_ena_val = BIT(24),
-	.mn_ena_mask = BIT(24),
-	.main_output_val = BIT(0),
-	.main_output_mask = BIT(0),
-};
-
 /* MMPLL0 at 800 MHz, main output enabled. */
 static struct pll_config mmpll0_config __initdata = {
 	.l = 0x29,
@@ -3376,32 +2847,6 @@
 	.main_output_mask = BIT(0),
 };
 
-static struct pll_config_regs lpapll0_regs __initdata = {
-	.l_reg = (void __iomem *)LPAAUDIO_PLL_L_VAL,
-	.m_reg = (void __iomem *)LPAAUDIO_PLL_M_VAL,
-	.n_reg = (void __iomem *)LPAAUDIO_PLL_N_VAL,
-	.config_reg = (void __iomem *)LPAAUDIO_PLL_USER_CTL,
-	.mode_reg = (void __iomem *)LPAAUDIO_PLL_MODE,
-	.base = &virt_bases[LPASS_BASE],
-};
-
-/* LPAPLL0 at 491.52 MHz, main output enabled. */
-static struct pll_config lpapll0_config __initdata = {
-	.l = 0x33,
-	.m = 0x1,
-	.n = 0x5,
-	.vco_val = 0x0,
-	.vco_mask = BM(21, 20),
-	.pre_div_val = BVAL(14, 12, 0x1),
-	.pre_div_mask = BM(14, 12),
-	.post_div_val = 0x0,
-	.post_div_mask = BM(9, 8),
-	.mn_ena_val = BIT(24),
-	.mn_ena_mask = BIT(24),
-	.main_output_val = BIT(0),
-	.main_output_mask = BIT(0),
-};
-
 #define PLL_AUX_OUTPUT_BIT 1
 #define PLL_AUX2_OUTPUT_BIT 2
 
@@ -3421,21 +2866,10 @@
 
 static void __init reg_init(void)
 {
-	u32 regval, status;
-	int ret;
-
-	if (!(readl_relaxed(GCC_REG_BASE(GPLL0_STATUS))
-			& gpll0_clk_src.status_mask))
-		configure_sr_hpm_lp_pll(&gpll0_config, &gpll0_regs, 1);
+	u32 regval;
 
 	configure_sr_hpm_lp_pll(&mmpll0_config, &mmpll0_regs, 1);
 	configure_sr_hpm_lp_pll(&mmpll1_config, &mmpll1_regs, 1);
-	configure_sr_hpm_lp_pll(&lpapll0_config, &lpapll0_regs, 1);
-
-	/* Enable GPLL0's aux outputs. */
-	regval = readl_relaxed(GCC_REG_BASE(GPLL0_USER_CTL));
-	regval |= BIT(PLL_AUX_OUTPUT_BIT) | BIT(PLL_AUX2_OUTPUT_BIT);
-	writel_relaxed(regval, GCC_REG_BASE(GPLL0_USER_CTL));
 
 	/* Vote for GPLL0 to turn on. Needed by acpuclock. */
 	regval = readl_relaxed(GCC_REG_BASE(APCS_GPLL_ENA_VOTE));
@@ -3447,31 +2881,6 @@
 	 * register.
 	 */
 	writel_relaxed(0x0, GCC_REG_BASE(APCS_CLOCK_SLEEP_ENA_VOTE));
-
-	/*
-	 * TODO: The following sequence enables the LPASS audio core GDSC.
-	 * Remove when this becomes unnecessary.
-	 */
-
-	/*
-	 * Disable HW trigger: collapse/restore occur based on registers writes.
-	 * Disable SW override: Use hardware state-machine for sequencing.
-	 */
-	regval = readl_relaxed(LPASS_REG_BASE(AUDIO_CORE_GDSCR));
-	regval &= ~(HW_CONTROL_MASK | SW_OVERRIDE_MASK);
-
-	/* Configure wait time between states. */
-	regval &= ~(EN_REST_WAIT_MASK | EN_FEW_WAIT_MASK | CLK_DIS_WAIT_MASK);
-	regval |= EN_REST_WAIT_VAL | EN_FEW_WAIT_VAL | CLK_DIS_WAIT_VAL;
-	writel_relaxed(regval, LPASS_REG_BASE(AUDIO_CORE_GDSCR));
-
-	regval = readl_relaxed(LPASS_REG_BASE(AUDIO_CORE_GDSCR));
-	regval &= ~BIT(0);
-	writel_relaxed(regval, LPASS_REG_BASE(AUDIO_CORE_GDSCR));
-
-	ret = readl_poll_timeout(LPASS_REG_BASE(AUDIO_CORE_GDSCR), status,
-				status & PWR_ON_MASK, 50, GDSC_TIMEOUT_US);
-	WARN(ret, "LPASS Audio Core GDSC did not power on.\n");
 }
 
 static void __init msm8610_clock_post_init(void)
@@ -3489,8 +2898,6 @@
 	clk_set_rate(&pdm2_clk_src.c, pdm2_clk_src.freq_tbl[0].freq_hz);
 	clk_set_rate(&mclk0_clk_src.c, mclk0_clk_src.freq_tbl[0].freq_hz);
 	clk_set_rate(&mclk1_clk_src.c, mclk1_clk_src.freq_tbl[0].freq_hz);
-	clk_set_rate(&audio_core_slimbus_core_clk_src.c,
-			audio_core_slimbus_core_clk_src.freq_tbl[0].freq_hz);
 }
 
 #define GCC_CC_PHYS		0xFC400000
@@ -3567,11 +2974,6 @@
 	/* TODO: Remove this once the bus driver is in place */
 	clk_set_rate(&axi_clk_src.c, 200000000);
 	clk_prepare_enable(&mmss_s0_axi_clk.c);
-
-	/* TODO: Temporarily enable a clock to allow access to LPASS core
-	 * registers.
-	 */
-	clk_prepare_enable(&audio_core_ixfabric_clk.c);
 }
 
 static int __init msm8610_clock_late_init(void)
diff --git a/arch/arm/mach-msm/clock-9625.c b/arch/arm/mach-msm/clock-9625.c
index d8e4ed5..6817c6c 100644
--- a/arch/arm/mach-msm/clock-9625.c
+++ b/arch/arm/mach-msm/clock-9625.c
@@ -147,6 +147,7 @@
 #define USB_HSIC_SYSTEM_CBCR                     0x040C
 #define USB_HSIC_CBCR                            0x0410
 #define USB_HSIC_IO_CAL_CBCR                     0x0414
+#define USB_HSIC_IO_CAL_SLEEP_CBCR		 0x0418
 #define USB_HSIC_XCVR_FS_CBCR                    0x042C
 #define USB_HS_SYSTEM_CBCR                       0x0484
 #define USB_HS_AHB_CBCR                          0x0488
@@ -187,6 +188,7 @@
 #define PDM2_CBCR                                0x0CCC
 #define PRNG_AHB_CBCR                            0x0D04
 #define BAM_DMA_AHB_CBCR                         0x0D44
+#define BAM_DMA_INACTIVITY_TIMERS_CBCR		 0x0D48
 #define MSG_RAM_AHB_CBCR                         0x0E44
 #define CE1_CBCR                                 0x1044
 #define CE1_AXI_CBCR                             0x1048
@@ -1002,6 +1004,18 @@
 	},
 };
 
+static struct local_vote_clk gcc_bam_dma_inactivity_timers_clk = {
+	.cbcr_reg = BAM_DMA_INACTIVITY_TIMERS_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(11),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_bam_dma_inactivity_timers_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_bam_dma_inactivity_timers_clk.c),
+	},
+};
+
 static struct local_vote_clk gcc_blsp1_ahb_clk = {
 	.cbcr_reg = BLSP1_AHB_CBCR,
 	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
@@ -1517,6 +1531,17 @@
 	},
 };
 
+static struct branch_clk gcc_usb_hsic_io_cal_sleep_clk = {
+	.cbcr_reg = USB_HSIC_IO_CAL_SLEEP_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hsic_io_cal_sleep_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hsic_io_cal_sleep_clk.c),
+	},
+};
+
 static struct branch_clk gcc_usb_hsic_system_clk = {
 	.cbcr_reg = USB_HSIC_SYSTEM_CBCR,
 	.bcr_reg = USB_HS_HSIC_BCR,
@@ -1554,6 +1579,7 @@
 
 struct measure_mux_entry measure_mux_common[] __initdata = {
 	{&gcc_pdm_ahb_clk.c,			GCC_BASE, 0x00d0},
+	{&gcc_usb_hsic_io_cal_sleep_clk.c,	GCC_BASE, 0x005c},
 	{&gcc_usb_hsic_xcvr_fs_clk.c,		GCC_BASE, 0x005d},
 	{&gcc_usb_hsic_system_clk.c,		GCC_BASE, 0x0059},
 	{&gcc_usb_hsic_io_cal_clk.c,		GCC_BASE, 0x005b},
@@ -1583,6 +1609,7 @@
 	{&gcc_sdcc2_apps_clk.c,			GCC_BASE, 0x0070},
 	{&gcc_blsp1_uart1_apps_clk.c,		GCC_BASE, 0x008c},
 	{&gcc_blsp1_qup4_i2c_apps_clk.c,	GCC_BASE, 0x0099},
+	{&gcc_bam_dma_inactivity_timers_clk.c,	GCC_BASE, 0x00E1},
 	{&gcc_boot_rom_ahb_clk.c,		GCC_BASE, 0x00f8},
 	{&gcc_ce1_ahb_clk.c,			GCC_BASE, 0x013a},
 	{&gcc_pdm2_clk.c,			GCC_BASE, 0x00d2},
@@ -1786,6 +1813,8 @@
 	CLK_LOOKUP("pll14", apcspll_clk_src.c, "f9010008.qcom,acpuclk"),
 
 	CLK_LOOKUP("dma_bam_pclk", gcc_bam_dma_ahb_clk.c, "msm_sps"),
+	CLK_LOOKUP("inactivity_clk", gcc_bam_dma_inactivity_timers_clk.c,
+								"msm_sps"),
 	CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "msm_serial_hsl.0"),
 	CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9924000.spi"),
 	CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9925000.i2c"),
@@ -1842,6 +1871,8 @@
 	CLK_LOOKUP("cal_clk", gcc_usb_hsic_io_cal_clk.c,  "msm_hsic_host"),
 	CLK_LOOKUP("core_clk", gcc_usb_hsic_system_clk.c, "msm_hsic_host"),
 	CLK_LOOKUP("alt_core_clk", gcc_usb_hsic_xcvr_fs_clk.c, ""),
+	CLK_LOOKUP("inactivity_clk", gcc_usb_hsic_io_cal_sleep_clk.c,
+							"msm_hsic_host"),
 
 	CLK_LOOKUP("core_clk", gcc_ce1_clk.c, "fd400000.qcom,qcedev"),
 	CLK_LOOKUP("iface_clk", gcc_ce1_ahb_clk.c, "fd400000.qcom,qcedev"),
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index d4c33e3..e70a0a8 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -1093,6 +1093,7 @@
 	.num_iommu_table = 2,
 	.load_table = vidc_v4l2_load_table,
 	.num_load_table = 2,
+	.max_load = 800*480*30/256,
 };
 
 struct platform_device msm_device_vidc_v4l2 = {
diff --git a/arch/arm/mach-msm/gdsc.c b/arch/arm/mach-msm/gdsc.c
index 6240195..e5b9d93 100644
--- a/arch/arm/mach-msm/gdsc.c
+++ b/arch/arm/mach-msm/gdsc.c
@@ -36,7 +36,7 @@
 #define EN_FEW_WAIT_VAL		(0x8 << 16)
 #define CLK_DIS_WAIT_VAL	(0x2 << 12)
 
-#define TIMEOUT_US		10
+#define TIMEOUT_US		100
 
 struct gdsc {
 	struct regulator_dev	*rdev;
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 3fa2d5e..35257b2 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -567,6 +567,8 @@
 	 */
 	int64_t **load_table;
 	int num_load_table;
+
+	uint32_t max_load;
 };
 
 struct vcap_platform_data {
diff --git a/arch/arm/mach-msm/ocmem_sched.c b/arch/arm/mach-msm/ocmem_sched.c
index 868fd1a..8afe695 100644
--- a/arch/arm/mach-msm/ocmem_sched.c
+++ b/arch/arm/mach-msm/ocmem_sched.c
@@ -377,6 +377,7 @@
 
 static int destroy_region(struct ocmem_region *region)
 {
+	idr_destroy(&region->region_idr);
 	kfree(region);
 	return 0;
 }
diff --git a/arch/arm/mach-msm/perf_debug.c b/arch/arm/mach-msm/perf_debug.c
index 7f2f528..96122de 100644
--- a/arch/arm/mach-msm/perf_debug.c
+++ b/arch/arm/mach-msm/perf_debug.c
@@ -28,6 +28,7 @@
 	"3  Perf: Correct irq for CPU hotplug detection\n"
 	"4  Perf: Check perf activity on correct CPU\n"
 	"5  Perf: Add DT support for L1 and L2 PMU\n"
+	"6  Perf: Add cortex A5 device tree support\n"
 ;
 
 static ssize_t desc_read(struct file *fp, char __user *buf,
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 555ffa0..6f37608 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -270,6 +270,7 @@
 	unsigned char *hdlc_buf;
 	unsigned hdlc_count;
 	unsigned hdlc_escape;
+	int in_busy_pktdata;
 #ifdef CONFIG_DIAG_OVER_USB
 	int usb_connected;
 	struct usb_diag_ch *legacy_ch;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index fb8efe4..a0c32f5 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -1310,6 +1310,7 @@
 		COPY_USER_SPACE_OR_EXIT(buf+4, *(driver->pkt_buf),
 							 driver->pkt_length);
 		driver->data_ready[index] ^= PKT_TYPE;
+		driver->in_busy_pktdata = 0;
 		goto exit;
 	}
 
@@ -1397,6 +1398,117 @@
 							payload_size);
 		return err;
 	}
+	if (pkt_type == CALLBACK_DATA_TYPE) {
+		err = copy_from_user(driver->user_space_data, buf + 4,
+							 payload_size);
+		 if (err) {
+			pr_err("diag: copy failed for user space data\n");
+			return -EIO;
+		}
+		/* Check for proc_type */
+		remote_proc = diag_get_remote(*(int *)driver->user_space_data);
+
+		if (!remote_proc) {
+			wait_event_interruptible(driver->wait_q,
+				 (driver->in_busy_pktdata == 0));
+			return diag_process_apps_pkt(driver->user_space_data,
+							payload_size);
+		}
+		/* The packet is for the remote processor */
+		token_offset = 4;
+		payload_size -= 4;
+		buf += 4;
+		/* Perform HDLC encoding on incoming data */
+		send.state = DIAG_STATE_START;
+		send.pkt = (void *)(driver->user_space_data + token_offset);
+		send.last = (void *)(driver->user_space_data + token_offset -
+							1 + payload_size);
+		send.terminate = 1;
+
+		mutex_lock(&driver->diagchar_mutex);
+		if (!buf_hdlc)
+			buf_hdlc = diagmem_alloc(driver, HDLC_OUT_BUF_SIZE,
+							POOL_TYPE_HDLC);
+		if (!buf_hdlc) {
+			ret = -ENOMEM;
+			goto fail_free_hdlc;
+		}
+		if (HDLC_OUT_BUF_SIZE < (2 * payload_size) + 3) {
+			pr_err("diag: Dropping packet, HDLC encoded packet payload size crosses buffer limit. Current payload size %d\n",
+					((2*payload_size) + 3));
+			driver->dropped_count++;
+			ret = -EBADMSG;
+			diagmem_free(driver, buf_hdlc, POOL_TYPE_HDLC);
+			goto fail_free_hdlc;
+		}
+		enc.dest = buf_hdlc + driver->used;
+		enc.dest_last = (void *)(buf_hdlc + driver->used +
+					(2 * payload_size) + token_offset - 1);
+		diag_hdlc_encode(&send, &enc);
+
+#ifdef CONFIG_DIAG_SDIO_PIPE
+		/* send masks to 9k too */
+		if (driver->sdio_ch && (remote_proc == MDM)) {
+			wait_event_interruptible(driver->wait_q,
+				 (sdio_write_avail(driver->sdio_ch) >=
+					 payload_size));
+			if (driver->sdio_ch && (payload_size > 0)) {
+				sdio_write(driver->sdio_ch, (void *)
+				   (char *)buf_hdlc, payload_size + 3);
+			}
+		}
+#endif
+#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
+		/* send masks to All 9k */
+		if ((remote_proc >= MDM) && (remote_proc <= MDM4)) {
+			index = remote_proc - MDM;
+			if (diag_hsic[index].hsic_ch && (payload_size > 0)) {
+				/* wait sending mask updates
+				 * if HSIC ch not ready */
+				if (diag_hsic[index].in_busy_hsic_write)
+					wait_event_interruptible(driver->wait_q,
+						(diag_hsic[index].
+						 in_busy_hsic_write != 1));
+				diag_hsic[index].in_busy_hsic_write = 1;
+				diag_hsic[index].in_busy_hsic_read_on_device =
+									0;
+				err = diag_bridge_write(index,
+					(char *)buf_hdlc, payload_size + 3);
+				if (err) {
+					pr_err("diag: err sending mask to MDM: %d\n",
+					       err);
+					/*
+					* If the error is recoverable, then
+					* clear the write flag, so we will
+					* resubmit a write on the next frame.
+					* Otherwise, don't resubmit a write
+					* on the next frame.
+					*/
+					if ((-ESHUTDOWN) != err)
+						diag_hsic[index].
+							in_busy_hsic_write = 0;
+				 }
+			 }
+		}
+		if (driver->diag_smux_enabled && (remote_proc == QSC)
+						&& driver->lcid) {
+			if (payload_size > 0) {
+				err = msm_smux_write(driver->lcid, NULL,
+					(char *)buf_hdlc, payload_size + 3);
+				if (err) {
+					pr_err("diag:send mask to MDM err %d",
+							err);
+					ret = err;
+				}
+			}
+		}
+#endif
+		diagmem_free(driver, buf_hdlc, POOL_TYPE_HDLC);
+		buf_hdlc = NULL;
+		driver->used = 0;
+		mutex_unlock(&driver->diagchar_mutex);
+		return ret;
+	}
 	if (pkt_type == USER_SPACE_DATA_TYPE) {
 		err = copy_from_user(driver->user_space_data, buf + 4,
 							 payload_size);
@@ -1839,6 +1951,7 @@
 		driver->socket_process = NULL;
 		driver->callback_process = NULL;
 		driver->mask_check = 0;
+		driver->in_busy_pktdata = 0;
 		mutex_init(&driver->diagchar_mutex);
 		init_waitqueue_head(&driver->wait_q);
 		init_waitqueue_head(&driver->smd_wait_q);
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index bb74370..5b929d7 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -641,9 +641,10 @@
 	unsigned char *temp = buf;
 
 	mutex_lock(&driver->diagchar_mutex);
-	if (CHK_OVERFLOW(ptr, ptr, ptr + PKT_SIZE, driver->pkt_length))
+	if (CHK_OVERFLOW(ptr, ptr, ptr + PKT_SIZE, driver->pkt_length)) {
 		memcpy(ptr, temp , driver->pkt_length);
-	else
+		driver->in_busy_pktdata = 1;
+	} else
 		printk(KERN_CRIT " Not enough buffer space for PKT_RESP\n");
 	mutex_unlock(&driver->diagchar_mutex);
 }
@@ -718,7 +719,7 @@
 	}
 }
 
-static int diag_process_apps_pkt(unsigned char *buf, int len)
+int diag_process_apps_pkt(unsigned char *buf, int len)
 {
 	uint16_t subsys_cmd_code;
 	int subsys_id, ssid_first, ssid_last, ssid_range;
diff --git a/drivers/char/diag/diagfwd.h b/drivers/char/diag/diagfwd.h
index 8cf15de..09f2f5e 100644
--- a/drivers/char/diag/diagfwd.h
+++ b/drivers/char/diag/diagfwd.h
@@ -48,6 +48,7 @@
 int diag_command_reg(unsigned long);
 void diag_cmp_logging_modes_sdio_pipe(int old_mode, int new_mode);
 void diag_cmp_logging_modes_diagfwd_bridge(int old_mode, int new_mode);
+int diag_process_apps_pkt(unsigned char *buf, int len);
 /* State for diag forwarding */
 #ifdef CONFIG_DIAG_OVER_USB
 int diagfwd_connect(void);
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index 4ddd78a..c3ff7dc 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -86,14 +86,15 @@
 			range = buf+HDR_SIZ+
 					sizeof(struct diag_ctrl_msg);
 			pkt_params->count = msg->count_entries;
-			temp = kzalloc(pkt_params->count * sizeof(struct
-					 bindpkt_params), GFP_KERNEL);
-			if (temp == NULL) {
+			pkt_params->params = kzalloc(pkt_params->count *
+				sizeof(struct bindpkt_params), GFP_KERNEL);
+			if (pkt_params->params == NULL) {
 				pr_alert("diag: In %s, Memory alloc fail\n",
 					__func__);
 				kfree(pkt_params);
 				return flag;
 			}
+			temp = pkt_params->params;
 			for (j = 0; j < pkt_params->count; j++) {
 				temp->cmd_code = msg->cmd_code;
 				temp->subsys_id = msg->subsysid;
@@ -104,8 +105,6 @@
 				range++;
 				temp++;
 			}
-			temp -= pkt_params->count;
-			pkt_params->params = temp;
 			flag = 1;
 			/* peripheral undergoing SSR should not
 			 * record new registration
@@ -116,7 +115,7 @@
 			else
 				pr_err("diag: drop reg proc %d\n",
 						smd_info->peripheral);
-			kfree(temp);
+			kfree(pkt_params->params);
 		} else if ((type == DIAG_CTRL_MSG_FEATURE) &&
 				(smd_info->peripheral == MODEM_DATA)) {
 			feature_mask_len = *(int *)(buf + 8);
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index 85e2ec9..ce25bfd 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -261,8 +261,10 @@
 	   allocation via dma_map_sg. The implicit contract here is that
 	   memory comming from the heaps is ready for dma, ie if it has a
 	   cached mapping that mapping has been invalidated */
-	for_each_sg(buffer->sg_table->sgl, sg, buffer->sg_table->nents, i)
-		sg_dma_address(sg) = sg_phys(sg);
+	for_each_sg(buffer->sg_table->sgl, sg, buffer->sg_table->nents, i) {
+		if (sg_dma_address(sg) == 0)
+			sg_dma_address(sg) = sg_phys(sg);
+	}
 	ion_buffer_add(dev, buffer);
 	return buffer;
 
@@ -1279,6 +1281,7 @@
 	for_each_sg(table->sgl, sg, table->nents, i) {
 		dma_addr_t addr = buffer_base + i * chunk_size;
 		sg_dma_address(sg) = addr;
+		sg_dma_len(sg) = chunk_size;
 	}
 
 	return table;
diff --git a/drivers/gpu/msm/a3xx_reg.h b/drivers/gpu/msm/a3xx_reg.h
index ed351bd..a2f0e60 100644
--- a/drivers/gpu/msm/a3xx_reg.h
+++ b/drivers/gpu/msm/a3xx_reg.h
@@ -66,15 +66,103 @@
 #define A3XX_RBBM_INT_0_MASK 0x063
 #define A3XX_RBBM_INT_0_STATUS 0x064
 #define A3XX_RBBM_PERFCTR_CTL 0x80
+#define A3XX_RBBM_PERFCTR_LOAD_CMD0 0x81
+#define A3XX_RBBM_PERFCTR_LOAD_CMD1 0x82
+#define A3XX_RBBM_PERFCTR_LOAD_VALUE_LO 0x84
+#define A3XX_RBBM_PERFCTR_LOAD_VALUE_HI 0x85
+#define A3XX_RBBM_PERFCOUNTER0_SELECT 0x86
+#define A3XX_RBBM_PERFCOUNTER1_SELECT 0x87
 #define A3XX_RBBM_GPU_BUSY_MASKED 0x88
+#define A3XX_RBBM_PERFCTR_CP_0_LO 0x90
+#define A3XX_RBBM_PERFCTR_CP_0_HI 0x91
+#define A3XX_RBBM_PERFCTR_RBBM_0_LO 0x92
+#define A3XX_RBBM_PERFCTR_RBBM_0_HI 0x93
+#define A3XX_RBBM_PERFCTR_RBBM_1_LO 0x94
+#define A3XX_RBBM_PERFCTR_RBBM_1_HI 0x95
+#define A3XX_RBBM_PERFCTR_PC_0_LO 0x96
+#define A3XX_RBBM_PERFCTR_PC_0_HI 0x97
+#define A3XX_RBBM_PERFCTR_PC_1_LO 0x98
+#define A3XX_RBBM_PERFCTR_PC_1_HI 0x99
+#define A3XX_RBBM_PERFCTR_PC_2_LO 0x9A
+#define A3XX_RBBM_PERFCTR_PC_2_HI 0x9B
+#define A3XX_RBBM_PERFCTR_PC_3_LO 0x9C
+#define A3XX_RBBM_PERFCTR_PC_3_HI 0x9D
+#define A3XX_RBBM_PERFCTR_VFD_0_LO 0x9E
+#define A3XX_RBBM_PERFCTR_VFD_0_HI 0x9F
+#define A3XX_RBBM_PERFCTR_VFD_1_LO 0xA0
+#define A3XX_RBBM_PERFCTR_VFD_1_HI 0xA1
+#define A3XX_RBBM_PERFCTR_HLSQ_0_LO 0xA2
+#define A3XX_RBBM_PERFCTR_HLSQ_0_HI 0xA3
+#define A3XX_RBBM_PERFCTR_HLSQ_1_LO 0xA4
+#define A3XX_RBBM_PERFCTR_HLSQ_1_HI 0xA5
+#define A3XX_RBBM_PERFCTR_HLSQ_2_LO 0xA6
+#define A3XX_RBBM_PERFCTR_HLSQ_2_HI 0xA7
+#define A3XX_RBBM_PERFCTR_HLSQ_3_LO 0xA8
+#define A3XX_RBBM_PERFCTR_HLSQ_3_HI 0xA9
+#define A3XX_RBBM_PERFCTR_HLSQ_4_LO 0xAA
+#define A3XX_RBBM_PERFCTR_HLSQ_4_HI 0xAB
+#define A3XX_RBBM_PERFCTR_HLSQ_5_LO 0xAC
+#define A3XX_RBBM_PERFCTR_HLSQ_5_HI 0xAD
+#define A3XX_RBBM_PERFCTR_VPC_0_LO 0xAE
+#define A3XX_RBBM_PERFCTR_VPC_0_HI 0xAF
+#define A3XX_RBBM_PERFCTR_VPC_1_LO 0xB0
+#define A3XX_RBBM_PERFCTR_VPC_1_HI 0xB1
+#define A3XX_RBBM_PERFCTR_TSE_0_LO 0xB2
+#define A3XX_RBBM_PERFCTR_TSE_0_HI 0xB3
+#define A3XX_RBBM_PERFCTR_TSE_1_LO 0xB4
+#define A3XX_RBBM_PERFCTR_TSE_1_HI 0xB5
+#define A3XX_RBBM_PERFCTR_RAS_0_LO 0xB6
+#define A3XX_RBBM_PERFCTR_RAS_0_HI 0xB7
+#define A3XX_RBBM_PERFCTR_RAS_1_LO 0xB8
+#define A3XX_RBBM_PERFCTR_RAS_1_HI 0xB9
+#define A3XX_RBBM_PERFCTR_UCHE_0_LO 0xBA
+#define A3XX_RBBM_PERFCTR_UCHE_0_HI 0xBB
+#define A3XX_RBBM_PERFCTR_UCHE_1_LO 0xBC
+#define A3XX_RBBM_PERFCTR_UCHE_1_HI 0xBD
+#define A3XX_RBBM_PERFCTR_UCHE_2_LO 0xBE
+#define A3XX_RBBM_PERFCTR_UCHE_2_HI 0xBF
+#define A3XX_RBBM_PERFCTR_UCHE_3_LO 0xC0
+#define A3XX_RBBM_PERFCTR_UCHE_3_HI 0xC1
+#define A3XX_RBBM_PERFCTR_UCHE_4_LO 0xC2
+#define A3XX_RBBM_PERFCTR_UCHE_4_HI 0xC3
+#define A3XX_RBBM_PERFCTR_UCHE_5_LO 0xC4
+#define A3XX_RBBM_PERFCTR_UCHE_5_HI 0xC5
+#define A3XX_RBBM_PERFCTR_TP_0_LO 0xC6
+#define A3XX_RBBM_PERFCTR_TP_0_HI 0xC7
+#define A3XX_RBBM_PERFCTR_TP_1_LO 0xC8
+#define A3XX_RBBM_PERFCTR_TP_1_HI 0xC9
+#define A3XX_RBBM_PERFCTR_TP_2_LO 0xCA
+#define A3XX_RBBM_PERFCTR_TP_2_HI 0xCB
+#define A3XX_RBBM_PERFCTR_TP_3_LO 0xCC
+#define A3XX_RBBM_PERFCTR_TP_3_HI 0xCD
+#define A3XX_RBBM_PERFCTR_TP_4_LO 0xCE
+#define A3XX_RBBM_PERFCTR_TP_4_HI 0xCF
+#define A3XX_RBBM_PERFCTR_TP_5_LO 0xD0
+#define A3XX_RBBM_PERFCTR_TP_5_HI 0xD1
+#define A3XX_RBBM_PERFCTR_SP_0_LO 0xD2
+#define A3XX_RBBM_PERFCTR_SP_0_HI 0xD3
+#define A3XX_RBBM_PERFCTR_SP_1_LO 0xD4
+#define A3XX_RBBM_PERFCTR_SP_1_HI 0xD5
+#define A3XX_RBBM_PERFCTR_SP_2_LO 0xD6
+#define A3XX_RBBM_PERFCTR_SP_2_HI 0xD7
+#define A3XX_RBBM_PERFCTR_SP_3_LO 0xD8
+#define A3XX_RBBM_PERFCTR_SP_3_HI 0xD9
+#define A3XX_RBBM_PERFCTR_SP_4_LO 0xDA
+#define A3XX_RBBM_PERFCTR_SP_4_HI 0xDB
 #define A3XX_RBBM_PERFCTR_SP_5_LO 0xDC
 #define A3XX_RBBM_PERFCTR_SP_5_HI 0xDD
 #define A3XX_RBBM_PERFCTR_SP_6_LO 0xDE
 #define A3XX_RBBM_PERFCTR_SP_6_HI 0xDF
 #define A3XX_RBBM_PERFCTR_SP_7_LO 0xE0
 #define A3XX_RBBM_PERFCTR_SP_7_HI 0xE1
+#define A3XX_RBBM_PERFCTR_RB_0_LO 0xE2
+#define A3XX_RBBM_PERFCTR_RB_0_HI 0xE3
+#define A3XX_RBBM_PERFCTR_RB_1_LO 0xE4
+#define A3XX_RBBM_PERFCTR_RB_1_HI 0xE5
+
 #define A3XX_RBBM_RBBM_CTL 0x100
-#define A3XX_RBBM_RBBM_CTL 0x100
+#define A3XX_RBBM_PERFCTR_PWR_0_LO 0x0EA
+#define A3XX_RBBM_PERFCTR_PWR_0_HI 0x0EB
 #define A3XX_RBBM_PERFCTR_PWR_1_LO 0x0EC
 #define A3XX_RBBM_PERFCTR_PWR_1_HI 0x0ED
 #define A3XX_RBBM_DEBUG_BUS_CTL             0x111
@@ -90,6 +178,7 @@
 #define A3XX_CP_MERCIU_DATA2 0x1D3
 #define A3XX_CP_MEQ_ADDR 0x1DA
 #define A3XX_CP_MEQ_DATA 0x1DB
+#define A3XX_CP_PERFCOUNTER_SELECT 0x445
 #define A3XX_CP_HW_FAULT  0x45C
 #define A3XX_CP_AHB_FAULT 0x54D
 #define A3XX_CP_PROTECT_CTRL 0x45E
@@ -138,6 +227,14 @@
 #define A3XX_VSC_PIPE_CONFIG_7 0xC1B
 #define A3XX_VSC_PIPE_DATA_ADDRESS_7 0xC1C
 #define A3XX_VSC_PIPE_DATA_LENGTH_7 0xC1D
+#define A3XX_PC_PERFCOUNTER0_SELECT 0xC48
+#define A3XX_PC_PERFCOUNTER1_SELECT 0xC49
+#define A3XX_PC_PERFCOUNTER2_SELECT 0xC4A
+#define A3XX_PC_PERFCOUNTER3_SELECT 0xC4B
+#define A3XX_GRAS_PERFCOUNTER0_SELECT 0xC88
+#define A3XX_GRAS_PERFCOUNTER1_SELECT 0xC89
+#define A3XX_GRAS_PERFCOUNTER2_SELECT 0xC8A
+#define A3XX_GRAS_PERFCOUNTER3_SELECT 0xC8B
 #define A3XX_GRAS_CL_USER_PLANE_X0 0xCA0
 #define A3XX_GRAS_CL_USER_PLANE_Y0 0xCA1
 #define A3XX_GRAS_CL_USER_PLANE_Z0 0xCA2
@@ -163,14 +260,42 @@
 #define A3XX_GRAS_CL_USER_PLANE_Z5 0xCB6
 #define A3XX_GRAS_CL_USER_PLANE_W5 0xCB7
 #define A3XX_RB_GMEM_BASE_ADDR 0xCC0
+#define A3XX_RB_PERFCOUNTER0_SELECT   0xCC6
+#define A3XX_RB_PERFCOUNTER1_SELECT   0xCC7
+#define A3XX_HLSQ_PERFCOUNTER0_SELECT 0xE00
+#define A3XX_HLSQ_PERFCOUNTER1_SELECT 0xE01
+#define A3XX_HLSQ_PERFCOUNTER2_SELECT 0xE02
+#define A3XX_HLSQ_PERFCOUNTER3_SELECT 0xE03
+#define A3XX_HLSQ_PERFCOUNTER4_SELECT 0xE04
+#define A3XX_HLSQ_PERFCOUNTER5_SELECT 0xE05
 #define A3XX_VFD_PERFCOUNTER0_SELECT 0xE44
+#define A3XX_VFD_PERFCOUNTER1_SELECT 0xE45
 #define A3XX_VPC_VPC_DEBUG_RAM_SEL 0xE61
 #define A3XX_VPC_VPC_DEBUG_RAM_READ 0xE62
+#define A3XX_VPC_PERFCOUNTER0_SELECT 0xE64
+#define A3XX_VPC_PERFCOUNTER1_SELECT 0xE65
 #define A3XX_UCHE_CACHE_MODE_CONTROL_REG 0xE82
+#define A3XX_UCHE_PERFCOUNTER0_SELECT 0xE84
+#define A3XX_UCHE_PERFCOUNTER1_SELECT 0xE85
+#define A3XX_UCHE_PERFCOUNTER2_SELECT 0xE86
+#define A3XX_UCHE_PERFCOUNTER3_SELECT 0xE87
+#define A3XX_UCHE_PERFCOUNTER4_SELECT 0xE88
+#define A3XX_UCHE_PERFCOUNTER5_SELECT 0xE89
 #define A3XX_UCHE_CACHE_INVALIDATE0_REG 0xEA0
+#define A3XX_SP_PERFCOUNTER0_SELECT 0xEC4
+#define A3XX_SP_PERFCOUNTER1_SELECT 0xEC5
+#define A3XX_SP_PERFCOUNTER2_SELECT 0xEC6
+#define A3XX_SP_PERFCOUNTER3_SELECT 0xEC7
+#define A3XX_SP_PERFCOUNTER4_SELECT 0xEC8
 #define A3XX_SP_PERFCOUNTER5_SELECT 0xEC9
 #define A3XX_SP_PERFCOUNTER6_SELECT 0xECA
 #define A3XX_SP_PERFCOUNTER7_SELECT 0xECB
+#define A3XX_TP_PERFCOUNTER0_SELECT 0xF04
+#define A3XX_TP_PERFCOUNTER1_SELECT 0xF05
+#define A3XX_TP_PERFCOUNTER2_SELECT 0xF06
+#define A3XX_TP_PERFCOUNTER3_SELECT 0xF07
+#define A3XX_TP_PERFCOUNTER4_SELECT 0xF08
+#define A3XX_TP_PERFCOUNTER5_SELECT 0xF09
 #define A3XX_GRAS_CL_CLIP_CNTL 0x2040
 #define A3XX_GRAS_CL_GB_CLIP_ADJ 0x2044
 #define A3XX_GRAS_CL_VPORT_XOFFSET 0x2048
@@ -273,8 +398,10 @@
 #define A3XX_VBIF_OUT_AXI_AOOO 0x305F
 
 /* Bit flags for RBBM_CTL */
-#define RBBM_RBBM_CTL_RESET_PWR_CTR1  (1 << 1)
-#define RBBM_RBBM_CTL_ENABLE_PWR_CTR1  (1 << 17)
+#define RBBM_RBBM_CTL_RESET_PWR_CTR0  BIT(0)
+#define RBBM_RBBM_CTL_RESET_PWR_CTR1  BIT(1)
+#define RBBM_RBBM_CTL_ENABLE_PWR_CTR0  BIT(16)
+#define RBBM_RBBM_CTL_ENABLE_PWR_CTR1  BIT(17)
 
 /* Various flags used by the context switch code */
 
@@ -540,6 +667,7 @@
 
 /* RBBM_CLOCK_CTL default value */
 #define A305_RBBM_CLOCK_CTL_DEFAULT   0xAAAAAAAA
+#define A305C_RBBM_CLOCK_CTL_DEFAULT  0xAAAAAAAA
 #define A320_RBBM_CLOCK_CTL_DEFAULT   0xBFFFFFFF
 #define A330_RBBM_CLOCK_CTL_DEFAULT   0xBFFCFFFF
 #define A330v2_RBBM_CLOCK_CTL_DEFAULT 0xBFFCFFFF
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index b9f00b5..6f7e61d 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -213,8 +213,318 @@
 	{ ADRENO_REV_A305B, 3, 0, 5, 0x10,
 		"a330_pm4.fw", "a330_pfp.fw", &adreno_a3xx_gpudev,
 		512, 0, 2, SZ_128K, NO_VER, NO_VER },
+	{ ADRENO_REV_A305C, 3, 0, 5, 0x20,
+		"a300_pm4.fw", "a300_pfp.fw", &adreno_a3xx_gpudev,
+		512, 0, 2, SZ_128K, 0x3FF037, 0x3FF016 },
 };
 
+/**
+ * adreno_perfcounter_init: Reserve kernel performance counters
+ * @device: device to configure
+ *
+ * The kernel needs/wants a certain group of performance counters for
+ * its own activities.  Reserve these performance counters at init time
+ * to ensure that they are always reserved for the kernel.  The performance
+ * counters used by the kernel can be obtained by the user, but these
+ * performance counters will remain active as long as the device is alive.
+ */
+
+static void adreno_perfcounter_init(struct kgsl_device *device)
+{
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+
+	if (adreno_dev->gpudev->perfcounter_init)
+		adreno_dev->gpudev->perfcounter_init(adreno_dev);
+};
+
+/**
+ * adreno_perfcounter_start: Enable performance counters
+ * @adreno_dev: Adreno device to configure
+ *
+ * Ensure all performance counters are enabled that are allocated.  Since
+ * the device was most likely stopped, we can't trust that the counters
+ * are still valid so make it so.
+ */
+
+static void adreno_perfcounter_start(struct adreno_device *adreno_dev)
+{
+	struct adreno_perfcounters *counters = adreno_dev->gpudev->perfcounters;
+	struct adreno_perfcount_group *group;
+	unsigned int i, j;
+
+	/* group id iter */
+	for (i = 0; i < counters->group_count; i++) {
+		group = &(counters->groups[i]);
+
+		/* countable iter */
+		for (j = 0; j < group->reg_count; j++) {
+			if (group->regs[j].countable ==
+					KGSL_PERFCOUNTER_NOT_USED)
+				continue;
+
+			if (adreno_dev->gpudev->perfcounter_enable)
+				adreno_dev->gpudev->perfcounter_enable(
+					adreno_dev, i, j,
+					group->regs[j].countable);
+		}
+	}
+}
+
+/**
+ * adreno_perfcounter_read_group: Determine which countables are in counters
+ * @adreno_dev: Adreno device to configure
+ * @reads: List of kgsl_perfcounter_read_groups
+ * @count: Length of list
+ *
+ * Read the performance counters for the groupid/countable pairs and return
+ * the 64 bit result for each pair
+ */
+
+int adreno_perfcounter_read_group(struct adreno_device *adreno_dev,
+	struct kgsl_perfcounter_read_group *reads, unsigned int count)
+{
+	struct adreno_perfcounters *counters = adreno_dev->gpudev->perfcounters;
+	struct adreno_perfcount_group *group;
+	struct kgsl_perfcounter_read_group *list = NULL;
+	unsigned int i, j;
+	int ret = 0;
+
+	/* perfcounter get/put/query/read not allowed on a2xx */
+	if (adreno_is_a2xx(adreno_dev))
+		return -EINVAL;
+
+	/* sanity check for later */
+	if (!adreno_dev->gpudev->perfcounter_read)
+		return -EINVAL;
+
+	/* sanity check params passed in */
+	if (reads == NULL || count == 0 || count > 100)
+		return -EINVAL;
+
+	/* verify valid inputs group ids and countables */
+	for (i = 0; i < count; i++) {
+		if (reads[i].groupid >= counters->group_count)
+			return -EINVAL;
+	}
+
+	list = kmalloc(sizeof(struct kgsl_perfcounter_read_group) * count,
+			GFP_KERNEL);
+	if (!list)
+		return -ENOMEM;
+
+	if (copy_from_user(list, reads,
+			sizeof(struct kgsl_perfcounter_read_group) * count)) {
+		ret = -EFAULT;
+		goto done;
+	}
+
+	/* list iterator */
+	for (j = 0; j < count; j++) {
+		list[j].value = 0;
+
+		group = &(counters->groups[list[j].groupid]);
+
+		/* group/counter iterator */
+		for (i = 0; i < group->reg_count; i++) {
+			if (group->regs[i].countable == list[j].countable) {
+				list[j].value =
+					adreno_dev->gpudev->perfcounter_read(
+					adreno_dev, list[j].groupid,
+					i, group->regs[i].offset);
+				break;
+			}
+		}
+	}
+
+	/* write the data */
+	if (copy_to_user(reads, list,
+			sizeof(struct kgsl_perfcounter_read_group) *
+			count) != 0)
+		ret = -EFAULT;
+
+done:
+	kfree(list);
+	return ret;
+}
+
+/**
+ * adreno_perfcounter_query_group: Determine which countables are in counters
+ * @adreno_dev: Adreno device to configure
+ * @groupid: Desired performance counter group
+ * @countables: Return list of all countables in the groups counters
+ * @count: Max length of the array
+ * @max_counters: max counters for the groupid
+ *
+ * Query the current state of counters for the group.
+ */
+
+int adreno_perfcounter_query_group(struct adreno_device *adreno_dev,
+	unsigned int groupid, unsigned int *countables, unsigned int count,
+	unsigned int *max_counters)
+{
+	struct adreno_perfcounters *counters = adreno_dev->gpudev->perfcounters;
+	struct adreno_perfcount_group *group;
+	unsigned int i;
+
+	*max_counters = 0;
+
+	/* perfcounter get/put/query not allowed on a2xx */
+	if (adreno_is_a2xx(adreno_dev))
+		return -EINVAL;
+
+	if (groupid >= counters->group_count)
+		return -EINVAL;
+
+	group = &(counters->groups[groupid]);
+	*max_counters = group->reg_count;
+
+	/*
+	 * if NULL countable or *count of zero, return max reg_count in
+	 * *max_counters and return success
+	 */
+	if (countables == NULL || count == 0)
+		return 0;
+
+	/*
+	 * Go through all available counters.  Write upto *count * countable
+	 * values.
+	 */
+	for (i = 0; i < group->reg_count && i < count; i++) {
+		if (copy_to_user(&countables[i], &(group->regs[i].countable),
+				sizeof(unsigned int)) != 0)
+			return -EFAULT;
+	}
+
+	return 0;
+}
+
+/**
+ * adreno_perfcounter_get: Try to put a countable in an available counter
+ * @adreno_dev: Adreno device to configure
+ * @groupid: Desired performance counter group
+ * @countable: Countable desired to be in a counter
+ * @offset: Return offset of the countable
+ * @flags: Used to setup kernel perf counters
+ *
+ * Try to place a countable in an available counter.  If the countable is
+ * already in a counter, reference count the counter/countable pair resource
+ * and return success
+ */
+
+int adreno_perfcounter_get(struct adreno_device *adreno_dev,
+	unsigned int groupid, unsigned int countable, unsigned int *offset,
+	unsigned int flags)
+{
+	struct adreno_perfcounters *counters = adreno_dev->gpudev->perfcounters;
+	struct adreno_perfcount_group *group;
+	unsigned int i, empty = -1;
+
+	/* always clear return variables */
+	if (offset)
+		*offset = 0;
+
+	/* perfcounter get/put/query not allowed on a2xx */
+	if (adreno_is_a2xx(adreno_dev))
+		return -EINVAL;
+
+	if (groupid >= counters->group_count)
+		return -EINVAL;
+
+	group = &(counters->groups[groupid]);
+
+	/*
+	 * Check if the countable is already associated with a counter.
+	 * Refcount and return the offset, otherwise, try and find an empty
+	 * counter and assign the countable to it.
+	 */
+	for (i = 0; i < group->reg_count; i++) {
+		if (group->regs[i].countable == countable) {
+			/* Countable already associated with counter */
+			group->regs[i].refcount++;
+			group->regs[i].flags |= flags;
+			if (offset)
+				*offset = group->regs[i].offset;
+			return 0;
+		} else if (group->regs[i].countable ==
+			KGSL_PERFCOUNTER_NOT_USED) {
+			/* keep track of unused counter */
+			empty = i;
+		}
+	}
+
+	/* no available counters, so do nothing else */
+	if (empty == -1)
+		return -EBUSY;
+
+	/* initialize the new counter */
+	group->regs[empty].countable = countable;
+	group->regs[empty].refcount = 1;
+
+	/* enable the new counter */
+	adreno_dev->gpudev->perfcounter_enable(adreno_dev, groupid, empty,
+		countable);
+
+	group->regs[empty].flags = flags;
+
+	if (offset)
+		*offset = group->regs[empty].offset;
+
+	return 0;
+}
+
+
+/**
+ * adreno_perfcounter_put: Release a countable from counter resource
+ * @adreno_dev: Adreno device to configure
+ * @groupid: Desired performance counter group
+ * @countable: Countable desired to be freed from a  counter
+ *
+ * Put a performance counter/countable pair that was previously received.  If
+ * noone else is using the countable, free up the counter for others.
+ */
+int adreno_perfcounter_put(struct adreno_device *adreno_dev,
+	unsigned int groupid, unsigned int countable)
+{
+	struct adreno_perfcounters *counters = adreno_dev->gpudev->perfcounters;
+	struct adreno_perfcount_group *group;
+
+	unsigned int i;
+
+	/* perfcounter get/put/query not allowed on a2xx */
+	if (adreno_is_a2xx(adreno_dev))
+		return -EINVAL;
+
+	if (groupid >= counters->group_count)
+		return -EINVAL;
+
+	group = &(counters->groups[groupid]);
+
+	for (i = 0; i < group->reg_count; i++) {
+		if (group->regs[i].countable == countable) {
+			if (group->regs[i].refcount > 0) {
+				group->regs[i].refcount--;
+
+				/*
+				 * book keeping to ensure we never free a
+				 * perf counter used by kernel
+				 */
+				if (group->regs[i].flags &&
+					group->regs[i].refcount == 0)
+					group->regs[i].refcount++;
+
+				/* make available if not used */
+				if (group->regs[i].refcount == 0)
+					group->regs[i].countable =
+						KGSL_PERFCOUNTER_NOT_USED;
+			}
+
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
 static irqreturn_t adreno_irq_handler(struct kgsl_device *device)
 {
 	irqreturn_t result;
@@ -1280,15 +1590,7 @@
 	 */
 	ft_detect_regs[0] = adreno_dev->gpudev->reg_rbbm_status;
 
-	/* Add A3XX specific registers for hang detection */
-	if (adreno_is_a3xx(adreno_dev)) {
-		ft_detect_regs[6] = A3XX_RBBM_PERFCTR_SP_7_LO;
-		ft_detect_regs[7] = A3XX_RBBM_PERFCTR_SP_7_HI;
-		ft_detect_regs[8] = A3XX_RBBM_PERFCTR_SP_6_LO;
-		ft_detect_regs[9] = A3XX_RBBM_PERFCTR_SP_6_HI;
-		ft_detect_regs[10] = A3XX_RBBM_PERFCTR_SP_5_LO;
-		ft_detect_regs[11] = A3XX_RBBM_PERFCTR_SP_5_HI;
-	}
+	adreno_perfcounter_init(device);
 
 	/* Power down the device */
 	kgsl_pwrctrl_disable(device);
@@ -1346,6 +1648,8 @@
 	if (KGSL_STATE_DUMP_AND_FT != device->state)
 		mod_timer(&device->idle_timer, jiffies + FIRST_TIMEOUT);
 
+	adreno_perfcounter_start(adreno_dev);
+
 	device->reset_counter++;
 
 	return 0;
@@ -3202,27 +3506,55 @@
 static long adreno_ioctl(struct kgsl_device_private *dev_priv,
 			      unsigned int cmd, void *data)
 {
+	struct kgsl_device *device = dev_priv->device;
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 	int result = 0;
-	struct kgsl_drawctxt_set_bin_base_offset *binbase;
-	struct kgsl_context *context;
 
 	switch (cmd) {
-	case IOCTL_KGSL_DRAWCTXT_SET_BIN_BASE_OFFSET:
+	case IOCTL_KGSL_DRAWCTXT_SET_BIN_BASE_OFFSET: {
+		struct kgsl_drawctxt_set_bin_base_offset *binbase = data;
+		struct kgsl_context *context;
+
 		binbase = data;
 
 		context = kgsl_find_context(dev_priv, binbase->drawctxt_id);
 		if (context) {
 			adreno_drawctxt_set_bin_base_offset(
-				dev_priv->device, context, binbase->offset);
+				device, context, binbase->offset);
 		} else {
 			result = -EINVAL;
-			KGSL_DRV_ERR(dev_priv->device,
+			KGSL_DRV_ERR(device,
 				"invalid drawctxt drawctxt_id %d "
 				"device_id=%d\n",
-				binbase->drawctxt_id, dev_priv->device->id);
+				binbase->drawctxt_id, device->id);
 		}
 		break;
-
+	}
+	case IOCTL_KGSL_PERFCOUNTER_GET: {
+		struct kgsl_perfcounter_get *get = data;
+		result = adreno_perfcounter_get(adreno_dev, get->groupid,
+			get->countable, &get->offset, PERFCOUNTER_FLAG_NONE);
+		break;
+	}
+	case IOCTL_KGSL_PERFCOUNTER_PUT: {
+		struct kgsl_perfcounter_put *put = data;
+		result = adreno_perfcounter_put(adreno_dev, put->groupid,
+			put->countable);
+		break;
+	}
+	case IOCTL_KGSL_PERFCOUNTER_QUERY: {
+		struct kgsl_perfcounter_query *query = data;
+		result = adreno_perfcounter_query_group(adreno_dev,
+			query->groupid, query->countables,
+			query->count, &query->max_counters);
+		break;
+	}
+	case IOCTL_KGSL_PERFCOUNTER_READ: {
+		struct kgsl_perfcounter_read *read = data;
+		result = adreno_perfcounter_read_group(adreno_dev,
+			read->reads, read->count);
+		break;
+	}
 	default:
 		KGSL_DRV_INFO(dev_priv->device,
 			"invalid ioctl code %08x\n", cmd);
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 6c57078..90d6027 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -73,6 +73,7 @@
 	ADRENO_REV_A220 = 220,
 	ADRENO_REV_A225 = 225,
 	ADRENO_REV_A305 = 305,
+	ADRENO_REV_A305C = 306,
 	ADRENO_REV_A320 = 320,
 	ADRENO_REV_A330 = 330,
 	ADRENO_REV_A305B = 335,
@@ -115,6 +116,44 @@
 	unsigned int gpu_cycles;
 };
 
+#define PERFCOUNTER_FLAG_NONE 0x0
+#define PERFCOUNTER_FLAG_KERNEL 0x1
+
+/* Structs to maintain the list of active performance counters */
+
+/**
+ * struct adreno_perfcount_register: register state
+ * @countable: countable the register holds
+ * @refcount: number of users of the register
+ * @offset: register hardware offset
+ */
+struct adreno_perfcount_register {
+	unsigned int countable;
+	unsigned int refcount;
+	unsigned int offset;
+	unsigned int flags;
+};
+
+/**
+ * struct adreno_perfcount_group: registers for a hardware group
+ * @regs: available registers for this group
+ * @reg_count: total registers for this group
+ */
+struct adreno_perfcount_group {
+	struct adreno_perfcount_register *regs;
+	unsigned int reg_count;
+};
+
+/**
+ * adreno_perfcounts: all available perfcounter groups
+ * @groups: available groups for this device
+ * @group_count: total groups for this device
+ */
+struct adreno_perfcounters {
+	struct adreno_perfcount_group *groups;
+	unsigned int group_count;
+};
+
 struct adreno_gpudev {
 	/*
 	 * These registers are in a different location on A3XX,  so define
@@ -126,6 +165,8 @@
 	/* keeps track of when we need to execute the draw workaround code */
 	int ctx_switches_since_last_draw;
 
+	struct adreno_perfcounters *perfcounters;
+
 	/* GPU specific function hooks */
 	int (*ctxt_create)(struct adreno_device *, struct adreno_context *);
 	void (*ctxt_save)(struct adreno_device *, struct adreno_context *);
@@ -137,8 +178,14 @@
 	unsigned int (*irq_pending)(struct adreno_device *);
 	void * (*snapshot)(struct adreno_device *, void *, int *, int);
 	int (*rb_init)(struct adreno_device *, struct adreno_ringbuffer *);
+	void (*perfcounter_init)(struct adreno_device *);
 	void (*start)(struct adreno_device *);
 	unsigned int (*busy_cycles)(struct adreno_device *);
+	void (*perfcounter_enable)(struct adreno_device *, unsigned int group,
+		unsigned int counter, unsigned int countable);
+	uint64_t (*perfcounter_read)(struct adreno_device *adreno_dev,
+		unsigned int group, unsigned int counter,
+		unsigned int offset);
 };
 
 /*
@@ -258,6 +305,13 @@
 unsigned int adreno_ft_detect(struct kgsl_device *device,
 						unsigned int *prev_reg_val);
 
+int adreno_perfcounter_get(struct adreno_device *adreno_dev,
+	unsigned int groupid, unsigned int countable, unsigned int *offset,
+	unsigned int flags);
+
+int adreno_perfcounter_put(struct adreno_device *adreno_dev,
+	unsigned int groupid, unsigned int countable);
+
 static inline int adreno_is_a200(struct adreno_device *adreno_dev)
 {
 	return (adreno_dev->gpurev == ADRENO_REV_A200);
@@ -314,6 +368,11 @@
 	return (adreno_dev->gpurev == ADRENO_REV_A305B);
 }
 
+static inline int adreno_is_a305c(struct adreno_device *adreno_dev)
+{
+	return (adreno_dev->gpurev == ADRENO_REV_A305C);
+}
+
 static inline int adreno_is_a320(struct adreno_device *adreno_dev)
 {
 	return (adreno_dev->gpurev == ADRENO_REV_A320);
@@ -438,6 +497,7 @@
 	*cmds++ = 0;
 
 	if ((adreno_dev->gpurev == ADRENO_REV_A305) ||
+		(adreno_dev->gpurev == ADRENO_REV_A305C) ||
 		(adreno_dev->gpurev == ADRENO_REV_A320)) {
 		*cmds++ = cp_type3_packet(CP_WAIT_FOR_ME, 1);
 		*cmds++ = 0;
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index f1024d6..19d9ca2 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -450,6 +450,8 @@
 {
 	if (adreno_is_a305(adreno_dev))
 		return A305_RBBM_CLOCK_CTL_DEFAULT;
+	else if (adreno_is_a305c(adreno_dev))
+		return A305C_RBBM_CLOCK_CTL_DEFAULT;
 	else if (adreno_is_a320(adreno_dev))
 		return A320_RBBM_CLOCK_CTL_DEFAULT;
 	else if (adreno_is_a330v2(adreno_dev))
@@ -2603,6 +2605,213 @@
 	queue_work(device->work_queue, &device->ts_expired_ws);
 }
 
+/**
+ * struct a3xx_perfcounter_register - Define a performance counter register
+ * @load_bit: the bit to set in RBBM_LOAD_CMD0/RBBM_LOAD_CMD1 to force the RBBM
+ * to load the reset value into the appropriate counter
+ * @select: The dword offset of the register to write the selected
+ * countable into
+ */
+
+struct a3xx_perfcounter_register {
+	unsigned int load_bit;
+	unsigned int select;
+};
+
+static struct a3xx_perfcounter_register a3xx_perfcounter_reg_cp[] = {
+	{ 0, A3XX_CP_PERFCOUNTER_SELECT },
+};
+
+static struct a3xx_perfcounter_register a3xx_perfcounter_reg_rbbm[] = {
+	{ 1, A3XX_RBBM_PERFCOUNTER0_SELECT },
+	{ 2, A3XX_RBBM_PERFCOUNTER1_SELECT },
+};
+
+static struct a3xx_perfcounter_register a3xx_perfcounter_reg_pc[] = {
+	{ 3, A3XX_PC_PERFCOUNTER0_SELECT },
+	{ 4, A3XX_PC_PERFCOUNTER1_SELECT },
+	{ 5, A3XX_PC_PERFCOUNTER2_SELECT },
+	{ 6, A3XX_PC_PERFCOUNTER3_SELECT },
+};
+
+static struct a3xx_perfcounter_register a3xx_perfcounter_reg_vfd[] = {
+	{ 7, A3XX_VFD_PERFCOUNTER0_SELECT },
+	{ 8, A3XX_VFD_PERFCOUNTER1_SELECT },
+};
+
+static struct a3xx_perfcounter_register a3xx_perfcounter_reg_hlsq[] = {
+	{ 9, A3XX_HLSQ_PERFCOUNTER0_SELECT },
+	{ 10, A3XX_HLSQ_PERFCOUNTER1_SELECT },
+	{ 11, A3XX_HLSQ_PERFCOUNTER2_SELECT },
+	{ 12, A3XX_HLSQ_PERFCOUNTER3_SELECT },
+	{ 13, A3XX_HLSQ_PERFCOUNTER4_SELECT },
+	{ 14, A3XX_HLSQ_PERFCOUNTER5_SELECT },
+};
+
+static struct a3xx_perfcounter_register a3xx_perfcounter_reg_vpc[] = {
+	{ 15, A3XX_VPC_PERFCOUNTER0_SELECT },
+	{ 16, A3XX_VPC_PERFCOUNTER1_SELECT },
+};
+
+static struct a3xx_perfcounter_register a3xx_perfcounter_reg_tse[] = {
+	{ 17, A3XX_GRAS_PERFCOUNTER0_SELECT },
+	{ 18, A3XX_GRAS_PERFCOUNTER1_SELECT },
+};
+
+static struct a3xx_perfcounter_register a3xx_perfcounter_reg_ras[] = {
+	{ 19, A3XX_GRAS_PERFCOUNTER2_SELECT },
+	{ 20, A3XX_GRAS_PERFCOUNTER3_SELECT },
+};
+
+static struct a3xx_perfcounter_register a3xx_perfcounter_reg_uche[] = {
+	{ 21, A3XX_UCHE_PERFCOUNTER0_SELECT },
+	{ 22, A3XX_UCHE_PERFCOUNTER1_SELECT },
+	{ 23, A3XX_UCHE_PERFCOUNTER2_SELECT },
+	{ 24, A3XX_UCHE_PERFCOUNTER3_SELECT },
+	{ 25, A3XX_UCHE_PERFCOUNTER4_SELECT },
+	{ 26, A3XX_UCHE_PERFCOUNTER5_SELECT },
+};
+
+static struct a3xx_perfcounter_register a3xx_perfcounter_reg_tp[] = {
+	{ 27, A3XX_TP_PERFCOUNTER0_SELECT },
+	{ 28, A3XX_TP_PERFCOUNTER1_SELECT },
+	{ 29, A3XX_TP_PERFCOUNTER2_SELECT },
+	{ 30, A3XX_TP_PERFCOUNTER3_SELECT },
+	{ 31, A3XX_TP_PERFCOUNTER4_SELECT },
+	{ 32, A3XX_TP_PERFCOUNTER5_SELECT },
+};
+
+static struct a3xx_perfcounter_register a3xx_perfcounter_reg_sp[] = {
+	{ 33, A3XX_SP_PERFCOUNTER0_SELECT },
+	{ 34, A3XX_SP_PERFCOUNTER1_SELECT },
+	{ 35, A3XX_SP_PERFCOUNTER2_SELECT },
+	{ 36, A3XX_SP_PERFCOUNTER3_SELECT },
+	{ 37, A3XX_SP_PERFCOUNTER4_SELECT },
+	{ 38, A3XX_SP_PERFCOUNTER5_SELECT },
+	{ 39, A3XX_SP_PERFCOUNTER6_SELECT },
+	{ 40, A3XX_SP_PERFCOUNTER7_SELECT },
+};
+
+static struct a3xx_perfcounter_register a3xx_perfcounter_reg_rb[] = {
+	{ 41, A3XX_RB_PERFCOUNTER0_SELECT },
+	{ 42, A3XX_RB_PERFCOUNTER1_SELECT },
+};
+
+#define REGCOUNTER_GROUP(_x) { (_x), ARRAY_SIZE((_x)) }
+
+static struct {
+	struct a3xx_perfcounter_register *regs;
+	int count;
+} a3xx_perfcounter_reglist[] = {
+	REGCOUNTER_GROUP(a3xx_perfcounter_reg_cp),
+	REGCOUNTER_GROUP(a3xx_perfcounter_reg_rbbm),
+	REGCOUNTER_GROUP(a3xx_perfcounter_reg_pc),
+	REGCOUNTER_GROUP(a3xx_perfcounter_reg_vfd),
+	REGCOUNTER_GROUP(a3xx_perfcounter_reg_hlsq),
+	REGCOUNTER_GROUP(a3xx_perfcounter_reg_vpc),
+	REGCOUNTER_GROUP(a3xx_perfcounter_reg_tse),
+	REGCOUNTER_GROUP(a3xx_perfcounter_reg_ras),
+	REGCOUNTER_GROUP(a3xx_perfcounter_reg_uche),
+	REGCOUNTER_GROUP(a3xx_perfcounter_reg_tp),
+	REGCOUNTER_GROUP(a3xx_perfcounter_reg_sp),
+	REGCOUNTER_GROUP(a3xx_perfcounter_reg_rb),
+};
+
+static void a3xx_perfcounter_enable_pwr(struct kgsl_device *device,
+	unsigned int countable)
+{
+	unsigned int in, out;
+
+	adreno_regread(device, A3XX_RBBM_RBBM_CTL, &in);
+
+	if (countable == 0)
+		out = in | RBBM_RBBM_CTL_RESET_PWR_CTR0;
+	else
+		out = in | RBBM_RBBM_CTL_RESET_PWR_CTR1;
+
+	adreno_regwrite(device, A3XX_RBBM_RBBM_CTL, out);
+
+	if (countable == 0)
+		out = in | RBBM_RBBM_CTL_ENABLE_PWR_CTR0;
+	else
+		out = in | RBBM_RBBM_CTL_ENABLE_PWR_CTR1;
+
+	adreno_regwrite(device, A3XX_RBBM_RBBM_CTL, out);
+
+	return;
+}
+
+/*
+ * a3xx_perfcounter_enable - Configure a performance counter for a countable
+ * @adreno_dev -  Adreno device to configure
+ * @group - Desired performance counter group
+ * @counter - Desired performance counter in the group
+ * @countable - Desired countable
+ *
+ * Physically set up a counter within a group with the desired countable
+ */
+
+static void a3xx_perfcounter_enable(struct adreno_device *adreno_dev,
+	unsigned int group, unsigned int counter, unsigned int countable)
+{
+	struct kgsl_device *device = &adreno_dev->dev;
+	unsigned int val = 0;
+	struct a3xx_perfcounter_register *reg;
+
+	if (group > ARRAY_SIZE(a3xx_perfcounter_reglist))
+		return;
+
+	if (counter > a3xx_perfcounter_reglist[group].count)
+		return;
+
+	/* Special case - power */
+	if (group == KGSL_PERFCOUNTER_GROUP_PWR)
+		return a3xx_perfcounter_enable_pwr(device, countable);
+
+	reg = &(a3xx_perfcounter_reglist[group].regs[counter]);
+
+	/* Select the desired perfcounter */
+	adreno_regwrite(device, reg->select, countable);
+
+	if (reg->load_bit < 32) {
+		val = 1 << reg->load_bit;
+		adreno_regwrite(device, A3XX_RBBM_PERFCTR_LOAD_CMD0, val);
+	} else {
+		val  = 1 << (reg->load_bit - 32);
+		adreno_regwrite(device, A3XX_RBBM_PERFCTR_LOAD_CMD1, val);
+	}
+}
+
+static uint64_t a3xx_perfcounter_read(struct adreno_device *adreno_dev,
+	unsigned int group, unsigned int counter,
+	unsigned int offset)
+{
+	struct kgsl_device *device = &adreno_dev->dev;
+	struct a3xx_perfcounter_register *reg = NULL;
+	unsigned int lo = 0, hi = 0;
+	unsigned int val;
+
+	if (group > ARRAY_SIZE(a3xx_perfcounter_reglist))
+		return 0;
+
+	reg = &(a3xx_perfcounter_reglist[group].regs[counter]);
+
+	/* Freeze the counter */
+	adreno_regread(device, A3XX_RBBM_PERFCTR_CTL, &val);
+	val &= ~reg->load_bit;
+	adreno_regwrite(device, A3XX_RBBM_PERFCTR_CTL, val);
+
+	/* Read the values */
+	adreno_regread(device, offset, &lo);
+	adreno_regread(device, offset + 1, &hi);
+
+	/* Re-Enable the counter */
+	val |= reg->load_bit;
+	adreno_regwrite(device, A3XX_RBBM_PERFCTR_CTL, val);
+
+	return (((uint64_t) hi) << 32) | lo;
+}
+
 #define A3XX_IRQ_CALLBACK(_c) { .func = _c }
 
 #define A3XX_INT_MASK \
@@ -2757,6 +2966,19 @@
 	{0, 0},
 };
 
+static struct a3xx_vbif_data a305c_vbif[] = {
+	{ A3XX_VBIF_IN_RD_LIM_CONF0, 0x00101010 },
+	{ A3XX_VBIF_IN_WR_LIM_CONF0, 0x00101010 },
+	{ A3XX_VBIF_OUT_RD_LIM_CONF0, 0x00000010 },
+	{ A3XX_VBIF_OUT_WR_LIM_CONF0, 0x00000010 },
+	{ A3XX_VBIF_DDR_OUT_MAX_BURST, 0x00000101 },
+	{ A3XX_VBIF_ARB_CTL, 0x00000010 },
+	/* Set up AOOO */
+	{ A3XX_VBIF_OUT_AXI_AOOO_EN, 0x00000007 },
+	{ A3XX_VBIF_OUT_AXI_AOOO, 0x00070007 },
+	{0, 0},
+};
+
 static struct a3xx_vbif_data a320_vbif[] = {
 	/* Set up 16 deep read/write request queues */
 	{ A3XX_VBIF_IN_RD_LIM_CONF0, 0x10101010 },
@@ -2828,6 +3050,7 @@
 	struct a3xx_vbif_data *vbif;
 } a3xx_vbif_platforms[] = {
 	{ adreno_is_a305, a305_vbif },
+	{ adreno_is_a305c, a305c_vbif },
 	{ adreno_is_a320, a320_vbif },
 	/* A330v2 needs to be ahead of A330 so the right device matches */
 	{ adreno_is_a330v2, a330v2_vbif },
@@ -2835,12 +3058,45 @@
 	{ adreno_is_a305b, a305b_vbif },
 };
 
+static void a3xx_perfcounter_init(struct adreno_device *adreno_dev)
+{
+	/*
+	 * Set SP to count SP_ALU_ACTIVE_CYCLES, it includes
+	 * all ALU instruction execution regardless precision or shader ID.
+	 * Set SP to count SP0_ICL1_MISSES, It counts
+	 * USP L1 instruction miss request.
+	 * Set SP to count SP_FS_FULL_ALU_INSTRUCTIONS, it
+	 * counts USP flow control instruction execution.
+	 * we will use this to augment our hang detection
+	 */
+	if (adreno_dev->fast_hang_detect) {
+		adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
+			SP_ALU_ACTIVE_CYCLES, &ft_detect_regs[6],
+			PERFCOUNTER_FLAG_KERNEL);
+		ft_detect_regs[7] = ft_detect_regs[6] + 1;
+		adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
+			SP0_ICL1_MISSES, &ft_detect_regs[8],
+			PERFCOUNTER_FLAG_KERNEL);
+		ft_detect_regs[9] = ft_detect_regs[8] + 1;
+		adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
+			SP_FS_CFLOW_INSTRUCTIONS, &ft_detect_regs[10],
+			PERFCOUNTER_FLAG_KERNEL);
+		ft_detect_regs[11] = ft_detect_regs[10] + 1;
+	}
+
+	adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
+		SP_FS_FULL_ALU_INSTRUCTIONS, NULL, PERFCOUNTER_FLAG_KERNEL);
+
+	/* Reserve and start countable 1 in the PWR perfcounter group */
+	adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_PWR, 1,
+			NULL, PERFCOUNTER_FLAG_KERNEL);
+}
+
 static void a3xx_start(struct adreno_device *adreno_dev)
 {
 	struct kgsl_device *device = &adreno_dev->dev;
 	struct a3xx_vbif_data *vbif = NULL;
 	int i;
-	unsigned int reg;
 
 	for (i = 0; i < ARRAY_SIZE(a3xx_vbif_platforms); i++) {
 		if (a3xx_vbif_platforms[i].devfunc(adreno_dev)) {
@@ -2904,39 +3160,121 @@
 	/* Turn on performance counters */
 	adreno_regwrite(device, A3XX_RBBM_PERFCTR_CTL, 0x01);
 
-	/*
-	 * Set SP perfcounter 5 to count SP_ALU_ACTIVE_CYCLES, it includes
-	 * all ALU instruction execution regardless precision or shader ID.
-	 * Set SP perfcounter 6 to count SP0_ICL1_MISSES, It counts
-	 * USP L1 instruction miss request.
-	 * Set SP perfcounter 7 to count SP_FS_FULL_ALU_INSTRUCTIONS, it
-	 * counts USP flow control instruction execution.
-	 * we will use this to augment our hang detection
-	 */
-	if (adreno_dev->fast_hang_detect) {
-		adreno_regwrite(device, A3XX_SP_PERFCOUNTER5_SELECT,
-			SP_ALU_ACTIVE_CYCLES);
-		adreno_regwrite(device, A3XX_SP_PERFCOUNTER6_SELECT,
-			SP0_ICL1_MISSES);
-		adreno_regwrite(device, A3XX_SP_PERFCOUNTER7_SELECT,
-			SP_FS_CFLOW_INSTRUCTIONS);
-	}
-
-	adreno_regwrite(device, A3XX_SP_PERFCOUNTER7_SELECT,
-		SP_FS_FULL_ALU_INSTRUCTIONS);
-
 	/* Turn on the GPU busy counter and let it run free */
 
 	adreno_dev->gpu_cycles = 0;
-
-	adreno_regread(device, A3XX_RBBM_RBBM_CTL, &reg);
-	reg |= RBBM_RBBM_CTL_RESET_PWR_CTR1;
-	adreno_regwrite(device, A3XX_RBBM_RBBM_CTL, reg);
-	reg &= ~RBBM_RBBM_CTL_RESET_PWR_CTR1;
-	reg |= RBBM_RBBM_CTL_ENABLE_PWR_CTR1;
-	adreno_regwrite(device, A3XX_RBBM_RBBM_CTL, reg);
 }
 
+/*
+ * Define the available perfcounter groups - these get used by
+ * adreno_perfcounter_get and adreno_perfcounter_put
+ */
+
+static struct adreno_perfcount_register a3xx_perfcounters_cp[] = {
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_CP_0_LO, 0 },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_rbbm[] = {
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_RBBM_0_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_RBBM_1_LO, 0 },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_pc[] = {
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_PC_0_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_PC_1_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_PC_2_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_PC_3_LO, 0 },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_vfd[] = {
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_VFD_0_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_VFD_1_LO, 0 },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_hlsq[] = {
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_HLSQ_0_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_HLSQ_1_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_HLSQ_2_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_HLSQ_3_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_HLSQ_4_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_HLSQ_5_LO, 0 },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_vpc[] = {
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_VPC_0_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_VPC_1_LO, 0 },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_tse[] = {
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_TSE_0_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_TSE_1_LO, 0 },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_ras[] = {
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_RAS_0_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_RAS_1_LO, 0 },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_uche[] = {
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_UCHE_0_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_UCHE_1_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_UCHE_2_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_UCHE_3_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_UCHE_4_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_UCHE_5_LO, 0 },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_tp[] = {
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_TP_0_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_TP_1_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_TP_2_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_TP_3_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_TP_4_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_TP_5_LO, 0 },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_sp[] = {
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_SP_0_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_SP_1_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_SP_2_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_SP_3_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_SP_4_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_SP_5_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_SP_6_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_SP_7_LO, 0 },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_rb[] = {
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_RB_0_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_RB_1_LO, 0 },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_pwr[] = {
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_PWR_0_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_PWR_1_LO, 0 },
+};
+
+static struct adreno_perfcount_group a3xx_perfcounter_groups[] = {
+	{ a3xx_perfcounters_cp, ARRAY_SIZE(a3xx_perfcounters_cp) },
+	{ a3xx_perfcounters_rbbm, ARRAY_SIZE(a3xx_perfcounters_rbbm) },
+	{ a3xx_perfcounters_pc, ARRAY_SIZE(a3xx_perfcounters_pc) },
+	{ a3xx_perfcounters_vfd, ARRAY_SIZE(a3xx_perfcounters_vfd) },
+	{ a3xx_perfcounters_hlsq, ARRAY_SIZE(a3xx_perfcounters_hlsq) },
+	{ a3xx_perfcounters_vpc, ARRAY_SIZE(a3xx_perfcounters_vpc) },
+	{ a3xx_perfcounters_tse, ARRAY_SIZE(a3xx_perfcounters_tse) },
+	{ a3xx_perfcounters_ras, ARRAY_SIZE(a3xx_perfcounters_ras) },
+	{ a3xx_perfcounters_uche, ARRAY_SIZE(a3xx_perfcounters_uche) },
+	{ a3xx_perfcounters_tp, ARRAY_SIZE(a3xx_perfcounters_tp) },
+	{ a3xx_perfcounters_sp, ARRAY_SIZE(a3xx_perfcounters_sp) },
+	{ a3xx_perfcounters_rb, ARRAY_SIZE(a3xx_perfcounters_rb) },
+	{ a3xx_perfcounters_pwr, ARRAY_SIZE(a3xx_perfcounters_pwr) },
+};
+
+static struct adreno_perfcounters a3xx_perfcounters = {
+	a3xx_perfcounter_groups,
+	ARRAY_SIZE(a3xx_perfcounter_groups),
+};
+
 /* Defined in adreno_a3xx_snapshot.c */
 void *a3xx_snapshot(struct adreno_device *adreno_dev, void *snapshot,
 	int *remain, int hang);
@@ -2945,16 +3283,20 @@
 	.reg_rbbm_status = A3XX_RBBM_STATUS,
 	.reg_cp_pfp_ucode_addr = A3XX_CP_PFP_UCODE_ADDR,
 	.reg_cp_pfp_ucode_data = A3XX_CP_PFP_UCODE_DATA,
+	.perfcounters = &a3xx_perfcounters,
 
 	.ctxt_create = a3xx_drawctxt_create,
 	.ctxt_save = a3xx_drawctxt_save,
 	.ctxt_restore = a3xx_drawctxt_restore,
 	.ctxt_draw_workaround = NULL,
 	.rb_init = a3xx_rb_init,
+	.perfcounter_init = a3xx_perfcounter_init,
 	.irq_control = a3xx_irq_control,
 	.irq_handler = a3xx_irq_handler,
 	.irq_pending = a3xx_irq_pending,
 	.busy_cycles = a3xx_busy_cycles,
 	.start = a3xx_start,
 	.snapshot = a3xx_snapshot,
+	.perfcounter_enable = a3xx_perfcounter_enable,
+	.perfcounter_read = a3xx_perfcounter_read,
 };
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index b746671..8c23a13 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -430,7 +430,8 @@
 		return status;
 
 	/* CP ROQ queue sizes (bytes) - RB:16, ST:16, IB1:32, IB2:64 */
-	if (adreno_is_a305(adreno_dev) || adreno_is_a320(adreno_dev))
+	if (adreno_is_a305(adreno_dev) || adreno_is_a305c(adreno_dev) ||
+		adreno_is_a320(adreno_dev))
 		adreno_regwrite(device, REG_CP_QUEUE_THRESHOLDS, 0x000E0602);
 	else if (adreno_is_a330(adreno_dev) || adreno_is_a305b(adreno_dev))
 		adreno_regwrite(device, REG_CP_QUEUE_THRESHOLDS, 0x003E2008);
diff --git a/drivers/hwmon/qpnp-adc-common.c b/drivers/hwmon/qpnp-adc-common.c
index b52df44..1458bc5 100644
--- a/drivers/hwmon/qpnp-adc-common.c
+++ b/drivers/hwmon/qpnp-adc-common.c
@@ -637,19 +637,26 @@
 		uint32_t *low_threshold, uint32_t *high_threshold)
 {
 	struct qpnp_vadc_linear_graph vbatt_param;
+	int rc = 0;
 
-	qpnp_get_vadc_gain_and_offset(&vbatt_param, CALIB_ABSOLUTE);
+	rc = qpnp_get_vadc_gain_and_offset(&vbatt_param, CALIB_ABSOLUTE);
+	if (rc < 0)
+		return rc;
 
-	*low_threshold = param->low_thr * vbatt_param.dy;
-	do_div(*low_threshold, vbatt_param.adc_vref);
+	*low_threshold = (((param->low_thr/3) - QPNP_ADC_625_UV) *
+				vbatt_param.dy);
+	do_div(*low_threshold, QPNP_ADC_625_UV);
 	*low_threshold += vbatt_param.adc_gnd;
 
-	*high_threshold = param->high_thr * vbatt_param.dy;
-	do_div(*high_threshold, vbatt_param.adc_vref);
+	*high_threshold = (((param->high_thr/3) - QPNP_ADC_625_UV) *
+				vbatt_param.dy);
+	do_div(*high_threshold, QPNP_ADC_625_UV);
 	*high_threshold += vbatt_param.adc_gnd;
 
 	pr_debug("high_volt:%d, low_volt:%d\n", param->high_thr,
 				param->low_thr);
+	pr_debug("adc_code_high:%x, adc_code_low:%x\n", *high_threshold,
+				*low_threshold);
 	return 0;
 }
 EXPORT_SYMBOL(qpnp_adc_vbatt_rscaler);
diff --git a/drivers/hwmon/qpnp-adc-current.c b/drivers/hwmon/qpnp-adc-current.c
index 60dcada..1fd4fee 100644
--- a/drivers/hwmon/qpnp-adc-current.c
+++ b/drivers/hwmon/qpnp-adc-current.c
@@ -409,7 +409,7 @@
 	return 0;
 }
 
-static int32_t qpnp_iadc_calibrate_for_trim(void)
+int32_t qpnp_iadc_calibrate_for_trim(void)
 {
 	struct qpnp_iadc_drv *iadc = qpnp_iadc;
 	uint8_t rslt_lsb, rslt_msb;
@@ -487,6 +487,7 @@
 	mutex_unlock(&iadc->adc->adc_lock);
 	return rc;
 }
+EXPORT_SYMBOL(qpnp_iadc_calibrate_for_trim);
 
 static void qpnp_iadc_work(struct work_struct *work)
 {
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index 202edc0..ac06fc5 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -61,6 +61,7 @@
 #define WLED_MAX_CURR_MASK		0x19
 #define WLED_OP_FDBCK_MASK		0x07
 #define WLED_OP_FDBCK_BIT_SHFT		0x00
+#define WLED_OP_FDBCK_DEFAULT		0x00
 
 #define WLED_MAX_LEVEL			4095
 #define WLED_8_BIT_MASK			0xFF
@@ -90,6 +91,8 @@
 #define FLASH_VREG_OK_FORCE(base)	(base + 0x4F)
 #define FLASH_ENABLE_CONTROL(base)	(base + 0x46)
 #define FLASH_LED_STROBE_CTRL(base)	(base + 0x47)
+#define FLASH_LED_UNLOCK_SECURE(base)	(base + 0xD0)
+#define FLASH_LED_TORCH(base)		(base + 0xE4)
 
 #define FLASH_MAX_LEVEL			0x4F
 #define	FLASH_NO_MASK			0x00
@@ -99,6 +102,7 @@
 #define FLASH_HEADROOM_MASK		0x03
 #define FLASH_SAFETY_TIMER_MASK		0x7F
 #define FLASH_CURRENT_MASK		0xFF
+#define FLASH_MAX_CURRENT_MASK		0x7F
 #define FLASH_TMR_MASK			0x03
 #define FLASH_TMR_WATCHDOG		0x03
 #define FLASH_TMR_SAFETY		0x00
@@ -117,17 +121,26 @@
 #define FLASH_ENABLE_LED_1		0x20
 #define FLASH_INIT_MASK			0xE0
 
-#define FLASH_STROBE_ALL		0xC0
-#define FLASH_STROBE_MASK		0xC0
+#define FLASH_STROBE_SW			0xC0
+#define FLASH_STROBE_HW			0xC4
+#define FLASH_STROBE_MASK		0xC7
 #define FLASH_LED_0_OUTPUT		0x80
 #define FLASH_LED_1_OUTPUT		0x40
 
 #define FLASH_CURRENT_PRGM_MIN		1
 #define FLASH_CURRENT_PRGM_SHIFT	1
+#define FLASH_CURRENT_MAX		0x4F
+#define FLASH_CURRENT_TORCH		0x0F
 
 #define FLASH_DURATION_200ms		0x13
 #define FLASH_CLAMP_200mA		0x0F
 
+#define FLASH_TORCH_MASK		0x03
+#define FLASH_LED_TORCH_ENABLE		0x00
+#define FLASH_LED_TORCH_DISABLE		0x03
+#define FLASH_UNLOCK_SECURE		0xA5
+#define FLASH_SECURE_MASK		0xFF
+
 #define LED_TRIGGER_DEFAULT		"none"
 
 #define RGB_LED_SRC_SEL(base)		(base + 0x45)
@@ -245,9 +258,9 @@
 	u8	cp_select;
 	u8	ctrl_delay_us;
 	u8	switch_freq;
+	u8	op_fdbck;
 	bool	dig_mod_gen_en;
 	bool	cs_out_en;
-	bool	op_fdbck;
 };
 
 /**
@@ -259,9 +272,11 @@
  *  @enable_module - enable address for particular flash
  *  @trigger_flash - trigger flash
  *  @startup_dly - startup delay for flash
+ *  @strobe_type - select between sw and hw strobe
  *  @current_addr - address to write for current
  *  @second_addr - address of secondary flash to be written
  *  @safety_timer - enable safety timer or watchdog timer
+ *  @torch_enable - enable flash LED torch mode
  */
 struct flash_config_data {
 	u8	current_prgm;
@@ -271,9 +286,11 @@
 	u8	enable_module;
 	u8	trigger_flash;
 	u8	startup_dly;
+	u8	strobe_type;
 	u16	current_addr;
 	u16	second_addr;
 	bool	safety_timer;
+	bool	torch_enable;
 };
 
 /**
@@ -456,62 +473,176 @@
 
 	/* Set led current */
 	if (val > 0) {
-		rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
-			FLASH_ENABLE_MODULE_MASK, FLASH_ENABLE_MODULE);
-		if (rc) {
-			dev_err(&led->spmi_dev->dev,
-				"Enable reg write failed(%d)\n", rc);
-			return rc;
+		if (led->flash_cfg->torch_enable) {
+			rc = qpnp_led_masked_write(led,
+				FLASH_LED_UNLOCK_SECURE(led->base),
+				FLASH_SECURE_MASK, FLASH_UNLOCK_SECURE);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"Secure reg write failed(%d)\n", rc);
+				return rc;
+			}
+
+			rc = qpnp_led_masked_write(led,
+				FLASH_LED_TORCH(led->base),
+				FLASH_TORCH_MASK, FLASH_LED_TORCH_ENABLE);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"Torch reg write failed(%d)\n", rc);
+				return rc;
+			}
+
+			qpnp_led_masked_write(led, FLASH_MAX_CURR(led->base),
+				FLASH_CURRENT_MASK, FLASH_CURRENT_TORCH);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"Max current reg write failed(%d)\n",
+					rc);
+				return rc;
+			}
+
+			rc = qpnp_led_masked_write(led,
+				led->flash_cfg->current_addr,
+				FLASH_CURRENT_MASK, FLASH_CURRENT_TORCH);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"Current reg write failed(%d)\n", rc);
+				return rc;
+			}
+
+			rc = qpnp_led_masked_write(led,
+				led->flash_cfg->second_addr,
+				FLASH_CURRENT_MASK, FLASH_CURRENT_TORCH);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"2nd Current reg write failed(%d)\n",
+					rc);
+				return rc;
+			}
+
+			rc = qpnp_led_masked_write(led,
+				FLASH_ENABLE_CONTROL(led->base),
+				FLASH_ENABLE_MODULE_MASK, FLASH_ENABLE_MODULE);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"Enable reg write failed(%d)\n", rc);
+				return rc;
+			}
+		} else {
+			rc = qpnp_led_masked_write(led,
+				FLASH_MAX_CURR(led->base),
+				FLASH_CURRENT_MASK, FLASH_CURRENT_MAX);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"Max current reg write failed(%d)\n",
+					rc);
+				return rc;
+			}
+
+			/* Write 0x80 to MODULE_ENABLE before writing 0xE0
+			 * in order to avoid reg value goes from 0x00 to
+			 * 0xE0. This causes a hardware bug.
+			 */
+			rc = qpnp_led_masked_write(led,
+				FLASH_ENABLE_CONTROL(led->base),
+				FLASH_ENABLE_MODULE_MASK, FLASH_ENABLE_MODULE);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"Enable reg write failed(%d)\n", rc);
+				return rc;
+			}
+
+			rc = qpnp_led_masked_write(led,
+				led->flash_cfg->current_addr,
+				FLASH_CURRENT_MASK,
+				led->flash_cfg->current_prgm);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"Current reg write failed(%d)\n", rc);
+				return rc;
+			}
+
+			rc = qpnp_led_masked_write(led,
+				led->flash_cfg->second_addr,
+				FLASH_CURRENT_MASK,
+				led->flash_cfg->current_prgm);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"2nd Current reg write failed(%d)\n",
+					rc);
+				return rc;
+			}
+
+			rc = qpnp_led_masked_write(led,
+				FLASH_CLAMP_CURR(led->base),
+				FLASH_CURRENT_MASK, FLASH_CURRENT_TORCH);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"Clamp Current reg write failed(%d)\n",
+					rc);
+				return rc;
+			}
+
+			rc = qpnp_led_masked_write(led,
+				FLASH_ENABLE_CONTROL(led->base),
+				FLASH_ENABLE_MASK, FLASH_ENABLE_ALL);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"Enable reg write failed(%d)\n", rc);
+				return rc;
+			}
 		}
 
-		rc = qpnp_led_masked_write(led, led->flash_cfg->current_addr,
-			FLASH_CURRENT_MASK, led->flash_cfg->current_prgm);
-		if (rc) {
-			dev_err(&led->spmi_dev->dev,
-				"Current reg write failed(%d)\n", rc);
-			return rc;
-		}
-
-		rc = qpnp_led_masked_write(led, led->flash_cfg->second_addr,
-			FLASH_CURRENT_MASK, led->flash_cfg->current_prgm);
-		if (rc) {
-			dev_err(&led->spmi_dev->dev,
-				"Current reg write failed(%d)\n", rc);
-			return rc;
-		}
-
-		rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
-			FLASH_ENABLE_MASK,
-			FLASH_ENABLE_ALL);
-		if (rc) {
-			dev_err(&led->spmi_dev->dev,
-				"Enable reg write failed(%d)\n", rc);
-			return rc;
-		}
-		rc = qpnp_led_masked_write(led,
-			FLASH_LED_STROBE_CTRL(led->base),
-			FLASH_STROBE_MASK, FLASH_STROBE_ALL);
-
-		if (rc) {
-			dev_err(&led->spmi_dev->dev,
-				"LED %d flash write failed(%d)\n", led->id, rc);
-			return rc;
-		}
-		rc = qpnp_led_masked_write(led, FLASH_VREG_OK_FORCE(led->base),
-			FLASH_VREG_MASK, FLASH_HW_VREG_OK);
-		if (rc) {
-			dev_err(&led->spmi_dev->dev,
-				"Vreg OK reg write failed(%d)\n", rc);
-			return rc;
+		if (!led->flash_cfg->strobe_type) {
+			rc = qpnp_led_masked_write(led,
+				FLASH_LED_STROBE_CTRL(led->base),
+				FLASH_STROBE_MASK, FLASH_STROBE_SW);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"LED %d strobe reg write failed(%d)\n",
+					led->id, rc);
+				return rc;
+			}
+		} else {
+			rc = qpnp_led_masked_write(led,
+				FLASH_LED_STROBE_CTRL(led->base),
+				FLASH_STROBE_MASK, FLASH_STROBE_HW);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"LED %d strobe reg write failed(%d)\n",
+					led->id, rc);
+				return rc;
+			}
 		}
 	} else {
-		rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
-			FLASH_ENABLE_MASK,
-			FLASH_DISABLE_ALL);
-		if (rc) {
-			dev_err(&led->spmi_dev->dev,
-				"Enable reg write failed(%d)\n", rc);
-			return rc;
+		if (led->flash_cfg->torch_enable) {
+			rc = qpnp_led_masked_write(led,
+				FLASH_LED_UNLOCK_SECURE(led->base),
+				FLASH_SECURE_MASK, FLASH_UNLOCK_SECURE);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"Secure reg write failed(%d)\n", rc);
+			}
+
+			rc = qpnp_led_masked_write(led,
+				FLASH_LED_TORCH(led->base),
+				FLASH_TORCH_MASK, FLASH_LED_TORCH_DISABLE);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"Torch reg write failed(%d)\n", rc);
+				return rc;
+			}
+
+			rc = qpnp_led_masked_write(led,
+				FLASH_SAFETY_TIMER(led->base),
+				FLASH_SAFETY_TIMER_MASK,
+				led->flash_cfg->duration);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"Safety timer reg write failed(%d)\n",
+					rc);
+				return rc;
+			}
 		}
 
 		rc = qpnp_led_masked_write(led,
@@ -523,6 +654,15 @@
 				"LED %d flash write failed(%d)\n", led->id, rc);
 			return rc;
 		}
+
+		rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
+			FLASH_ENABLE_MASK,
+			FLASH_DISABLE_ALL);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"Enable reg write failed(%d)\n", rc);
+			return rc;
+		}
 	}
 
 	qpnp_dump_regs(led, flash_debug_regs, ARRAY_SIZE(flash_debug_regs));
@@ -797,6 +937,66 @@
 	return 0;
 }
 
+static ssize_t led_mode_store(struct device *dev,
+			struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	struct qpnp_led_data *led;
+	unsigned long state;
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	ssize_t ret = -EINVAL;
+
+	ret = kstrtoul(buf, 10, &state);
+	if (ret)
+		return ret;
+
+	led = container_of(led_cdev, struct qpnp_led_data, cdev);
+
+	/* '1' to enable torch mode; '0' to switch to flash mode */
+	if (state == 1)
+		led->flash_cfg->torch_enable = true;
+	else
+		led->flash_cfg->torch_enable = false;
+
+	return count;
+}
+
+static ssize_t led_strobe_type_store(struct device *dev,
+			struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	struct qpnp_led_data *led;
+	unsigned long state;
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	ssize_t ret = -EINVAL;
+
+	ret = kstrtoul(buf, 10, &state);
+	if (ret)
+		return ret;
+
+	led = container_of(led_cdev, struct qpnp_led_data, cdev);
+
+	/* '0' for sw strobe; '1' for hw strobe */
+	if (state == 1)
+		led->flash_cfg->strobe_type = 1;
+	else
+		led->flash_cfg->strobe_type = 0;
+
+	return count;
+}
+
+static DEVICE_ATTR(led_mode, 0664, NULL, led_mode_store);
+static DEVICE_ATTR(strobe, 0664, NULL, led_strobe_type_store);
+
+static struct attribute *led_attrs[] = {
+	&dev_attr_led_mode.attr,
+	&dev_attr_strobe.attr,
+};
+
+static const struct attribute_group led_attr_group = {
+	.attrs = led_attrs,
+};
+
 static int __devinit qpnp_flash_init(struct qpnp_led_data *led)
 {
 	int rc;
@@ -890,7 +1090,7 @@
 		return rc;
 	}
 
-	/* Set led current and enable module */
+	/* Set led current and disable module */
 	rc = qpnp_led_masked_write(led, led->flash_cfg->current_addr,
 		FLASH_CURRENT_MASK, led->flash_cfg->current_prgm);
 	if (rc) {
@@ -906,6 +1106,10 @@
 			"Enable reg write failed(%d)\n", rc);
 		return rc;
 	}
+
+	led->flash_cfg->torch_enable = false;
+	led->flash_cfg->strobe_type = 0;
+
 	/* dump flash registers */
 	qpnp_dump_regs(led, flash_debug_regs, ARRAY_SIZE(flash_debug_regs));
 
@@ -1099,6 +1303,13 @@
 	else if (rc != -EINVAL)
 		return rc;
 
+	led->wled_cfg->op_fdbck = WLED_OP_FDBCK_DEFAULT;
+	rc = of_property_read_u32(node, "qcom,op-fdbck", &val);
+	if (!rc)
+		led->wled_cfg->op_fdbck = (u8) val;
+	else if (rc != -EINVAL)
+		return rc;
+
 	led->wled_cfg->switch_freq = WLED_SWITCH_FREQ_DEFAULT;
 	rc = of_property_read_u32(node, "qcom,switch-freq", &val);
 	if (!rc)
@@ -1112,9 +1323,6 @@
 	led->wled_cfg->cs_out_en =
 		of_property_read_bool(node, "qcom,cs-out-en");
 
-	led->wled_cfg->op_fdbck =
-		of_property_read_bool(node, "qcom,op-fdbck");
-
 	return 0;
 }
 
@@ -1451,6 +1659,16 @@
 						 led->id, rc);
 			goto fail_id_check;
 		}
+
+		if (led->id == QPNP_ID_FLASH1_LED0 ||
+			led->id == QPNP_ID_FLASH1_LED1) {
+			rc = sysfs_create_group(&led->cdev.dev->kobj,
+							&led_attr_group);
+			if (rc)
+				goto fail_id_check;
+
+		}
+
 		/* configure default state */
 		if (led->default_on) {
 			led->cdev.brightness = led->cdev.max_brightness;
@@ -1477,8 +1695,26 @@
 	struct qpnp_led_data *led_array  = dev_get_drvdata(&spmi->dev);
 	int i, parsed_leds = led_array->num_leds;
 
-	for (i = 0; i < parsed_leds; i++)
+	for (i = 0; i < parsed_leds; i++) {
 		led_classdev_unregister(&led_array[i].cdev);
+		switch (led_array[i].id) {
+		case QPNP_ID_WLED:
+			break;
+		case QPNP_ID_FLASH1_LED0:
+		case QPNP_ID_FLASH1_LED1:
+			sysfs_remove_group(&led_array[i].cdev.dev->kobj,
+							&led_attr_group);
+			break;
+		case QPNP_ID_RGB_RED:
+		case QPNP_ID_RGB_GREEN:
+		case QPNP_ID_RGB_BLUE:
+		default:
+			dev_err(&led_array[i].spmi_dev->dev,
+					"Invalid LED(%d)\n",
+					led_array[i].id);
+			return -EINVAL;
+		}
+	}
 
 	return 0;
 }
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index 2a0cde9..0fef315 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -1876,13 +1876,13 @@
 	if (dvbdemux->dmx.debugfs_demux_dir != NULL) {
 		debugfs_create_u32(
 			"total_processing_time",
-			S_IRUGO|S_IWUGO,
+			S_IRUGO | S_IWUSR | S_IWGRP,
 			dvbdemux->dmx.debugfs_demux_dir,
 			&dvbdemux->total_process_time);
 
 		debugfs_create_u32(
 			"total_crc_time",
-			S_IRUGO|S_IWUGO,
+			S_IRUGO | S_IWUSR | S_IWGRP,
 			dvbdemux->dmx.debugfs_demux_dir,
 			&dvbdemux->total_crc_time);
 	}
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
index 85788e9..22ce35b 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
@@ -78,7 +78,7 @@
 	{"camss_csi_vfe_clk1", -1},
 };
 
-static int msm_ispif_clk_enable(struct ispif_device *ispif,
+static int msm_ispif_clk_enable_one(struct ispif_device *ispif,
 	enum msm_ispif_vfe_intf vfe_intf, int enable)
 {
 	int rc = 0;
@@ -119,8 +119,8 @@
 				ARRAY_SIZE(ispif_8974_clk_info_vfe1), enable);
 		}
 		if (rc) {
-			pr_err("%s: cannot enable clock, error = %d\n",
-				__func__, rc);
+			pr_err("%s: cannot enable clock, error = %d, vfeid = %d\n",
+				__func__, rc, vfe_intf);
 			goto end;
 		}
 	} else {
@@ -133,17 +133,56 @@
 	return rc;
 }
 
+static int msm_ispif_clk_enable(struct ispif_device *ispif,
+	struct msm_ispif_param_data *params, int enable)
+{
+	int rc = 0;
+	int i, j;
+	uint32_t vfe_intf_mask = 0;
+
+	for (i = 0; i < params->num; i++) {
+		if (vfe_intf_mask & (1 << params->entries[i].vfe_intf))
+			continue;
+		rc = msm_ispif_clk_enable_one(ispif,
+			params->entries[i].vfe_intf, 1);
+		if (rc < 0 && enable) {
+			pr_err("%s: unable to enable clocks for VFE %d",
+				__func__, params->entries[i].vfe_intf);
+			for (j = 0; j < i; j++) {
+				/* if VFE clock is not enabled do
+				 * not disable the clock */
+				if (!(vfe_intf_mask & (1 <<
+						params->entries[i].vfe_intf)))
+					continue;
+				msm_ispif_clk_enable_one(ispif,
+					params->entries[j].vfe_intf, 0);
+				/* remove the VFE ID from the mask */
+				vfe_intf_mask &=
+					~(1 << params->entries[i].vfe_intf);
+			}
+			break;
+		}
+		vfe_intf_mask |= 1 << params->entries[i].vfe_intf;
+	}
+	return rc;
+}
+
 static int msm_ispif_intf_reset(struct ispif_device *ispif,
 	struct msm_ispif_param_data *params)
 {
 
 	int i, rc = 0;
 	enum msm_ispif_intftype intf_type;
-	uint32_t data = STROBED_RST_EN;
+	int vfe_intf = 0;
+	uint32_t data = 0;
 
 	for (i = 0; i < params->num; i++) {
+		data = STROBED_RST_EN;
+		vfe_intf = params->entries[i].vfe_intf;
 		intf_type = params->entries[i].intftype;
-		ispif->sof_count[params->vfe_intf].sof_cnt[intf_type] = 0;
+		ispif->sof_count[params->entries[i].vfe_intf].
+			sof_cnt[intf_type] = 0;
+
 		switch (intf_type) {
 		case PIX0:
 			data |= (PIX_0_VFE_RST_STB | PIX_0_CSID_RST_STB);
@@ -164,35 +203,40 @@
 			rc = -EINVAL;
 			break;
 		}
-	}
-	if (data > 0x1) {
-		unsigned long jiffes = msecs_to_jiffies(500);
-		long lrc = 0;
-		unsigned long flags;
+		if (data > 0x1) {
+			unsigned long jiffes = msecs_to_jiffies(500);
+			long lrc = 0;
+			unsigned long flags;
 
-		spin_lock_irqsave(&ispif->auto_complete_lock, flags);
-		ispif->wait_timeout[params->vfe_intf] = 0;
-		init_completion(&ispif->reset_complete[params->vfe_intf]);
-		spin_unlock_irqrestore(&ispif->auto_complete_lock, flags);
-
-		if (params->vfe_intf == VFE0)
-			msm_camera_io_w(data, ispif->base + ISPIF_RST_CMD_ADDR);
-		else
-			msm_camera_io_w(data, ispif->base +
-				ISPIF_RST_CMD_1_ADDR);
-
-		lrc = wait_for_completion_interruptible_timeout(
-			&ispif->reset_complete[params->vfe_intf], jiffes);
-		if (lrc < 0 || !lrc) {
-			pr_err("%s: wait timeout ret = %ld\n", __func__, lrc);
-			rc = -EIO;
-
-			spin_lock_irqsave(&ispif->auto_complete_lock, flags);
-			ispif->wait_timeout[params->vfe_intf] = 1;
+			spin_lock_irqsave(
+				&ispif->auto_complete_lock, flags);
+			ispif->wait_timeout[vfe_intf] = 0;
+			init_completion(&ispif->reset_complete[vfe_intf]);
 			spin_unlock_irqrestore(
 				&ispif->auto_complete_lock, flags);
+
+			if (vfe_intf == VFE0)
+				msm_camera_io_w(data, ispif->base +
+					ISPIF_RST_CMD_ADDR);
+			else
+				msm_camera_io_w(data, ispif->base +
+					ISPIF_RST_CMD_1_ADDR);
+			lrc = wait_for_completion_interruptible_timeout(
+				&ispif->reset_complete[vfe_intf], jiffes);
+			if (lrc < 0 || !lrc) {
+				pr_err("%s: wait timeout ret = %ld, vfe_id = %d\n",
+					__func__, lrc, vfe_intf);
+				rc = -EIO;
+
+				spin_lock_irqsave(
+					&ispif->auto_complete_lock, flags);
+				ispif->wait_timeout[vfe_intf] = 1;
+				spin_unlock_irqrestore(
+					&ispif->auto_complete_lock, flags);
+			}
 		}
 	}
+
 	return rc;
 }
 
@@ -223,7 +267,8 @@
 		&ispif->reset_complete[VFE0], jiffes);
 
 	if (lrc < 0 || !lrc) {
-		pr_err("%s: wait timeout ret = %ld\n", __func__, lrc);
+		pr_err("%s: wait timeout ret = %ld, vfeid = %d\n",
+			__func__, lrc, VFE0);
 		rc = -EIO;
 
 		spin_lock_irqsave(&ispif->auto_complete_lock, flags);
@@ -242,7 +287,8 @@
 			&ispif->reset_complete[VFE1], jiffes);
 
 		if (lrc < 0 || !lrc) {
-			pr_err("%s: wait timeout ret = %ld\n", __func__, lrc);
+			pr_err("%s: wait timeout ret = %ld, vfeid = %d\n",
+				__func__, lrc, VFE1);
 			rc = -EIO;
 
 			spin_lock_irqsave(&ispif->auto_complete_lock, flags);
@@ -320,6 +366,36 @@
 			ISPIF_VFE_m_INPUT_SEL(vfe_intf));
 }
 
+static void msm_ispif_enable_crop(struct ispif_device *ispif,
+	uint8_t intftype, uint8_t vfe_intf, uint16_t start_pixel,
+	uint16_t end_pixel)
+{
+	uint32_t data;
+	BUG_ON(!ispif);
+
+	if (!msm_ispif_is_intf_valid(ispif->csid_version, vfe_intf)) {
+		pr_err("%s: invalid interface type\n", __func__);
+		return;
+	}
+
+	data = msm_camera_io_r(ispif->base + ISPIF_VFE_m_CTRL_0(vfe_intf));
+	data |= (1 << (intftype + 7));
+	msm_camera_io_w(data,
+		ispif->base + ISPIF_VFE_m_CTRL_0(vfe_intf));
+
+	if (intftype == PIX0)
+		msm_camera_io_w_mb(start_pixel | (end_pixel << 16),
+			ispif->base + ISPIF_VFE_m_PIX_INTF_n_CROP(vfe_intf, 0));
+	else if (intftype == PIX1)
+		msm_camera_io_w_mb(start_pixel | (end_pixel << 16),
+			ispif->base + ISPIF_VFE_m_PIX_INTF_n_CROP(vfe_intf, 1));
+	else {
+		pr_err("%s: invalid intftype=%d\n", __func__, intftype);
+		BUG_ON(1);
+		return;
+	}
+}
+
 static void msm_ispif_enable_intf_cids(struct ispif_device *ispif,
 	uint8_t intftype, uint16_t cid_mask, uint8_t vfe_intf, uint8_t enable)
 {
@@ -427,28 +503,30 @@
 	BUG_ON(!ispif);
 	BUG_ON(!params);
 
-	vfe_intf = params->vfe_intf;
-
-	rc = msm_ispif_clk_enable(ispif, vfe_intf, 1);
+	rc = msm_ispif_clk_enable(ispif, params, 1);
 	if (rc < 0) {
-		pr_err("%s: unable to enable clocks for VFE%d", __func__,
-			vfe_intf);
+		pr_err("%s: unable to enable clocks", __func__);
 		return rc;
 	}
-
-	if (!msm_ispif_is_intf_valid(ispif->csid_version, vfe_intf)) {
-		pr_err("%s: invalid interface type\n", __func__);
-		return -EINVAL;
+	for (i = 0; i < params->num; i++) {
+		vfe_intf = params->entries[i].vfe_intf;
+		if (!msm_ispif_is_intf_valid(ispif->csid_version,
+				vfe_intf)) {
+			pr_err("%s: invalid interface type\n", __func__);
+			return -EINVAL;
+		}
+		msm_camera_io_w(0x0, ispif->base +
+			ISPIF_VFE_m_IRQ_MASK_0(vfe_intf));
+		msm_camera_io_w(0x0, ispif->base +
+			ISPIF_VFE_m_IRQ_MASK_1(vfe_intf));
+		msm_camera_io_w_mb(0x0, ispif->base +
+			ISPIF_VFE_m_IRQ_MASK_2(vfe_intf));
 	}
 
-	msm_camera_io_w(0x0, ispif->base + ISPIF_VFE_m_IRQ_MASK_0(vfe_intf));
-	msm_camera_io_w(0x0, ispif->base + ISPIF_VFE_m_IRQ_MASK_1(vfe_intf));
-	msm_camera_io_w_mb(0x0, ispif->base + ISPIF_VFE_m_IRQ_MASK_2(vfe_intf));
-
 	for (i = 0; i < params->num; i++) {
 		intftype = params->entries[i].intftype;
 
-		vfe_intf = params->vfe_intf;
+		vfe_intf = params->entries[i].vfe_intf;
 
 		CDBG("%s intftype %x, vfe_intf %d, csid %d\n", __func__,
 			intftype, vfe_intf, params->entries[i].csid);
@@ -475,31 +553,36 @@
 				&params->entries[i]);
 		msm_ispif_enable_intf_cids(ispif, intftype,
 			cid_mask, vfe_intf, 1);
+		if (params->entries[i].crop_enable)
+			msm_ispif_enable_crop(ispif, intftype, vfe_intf,
+				params->entries[i].crop_start_pixel,
+				params->entries[i].crop_end_pixel);
 	}
 
-	msm_camera_io_w(ISPIF_IRQ_STATUS_MASK, ispif->base +
-		ISPIF_VFE_m_IRQ_MASK_0(vfe_intf));
+	for (vfe_intf = 0; vfe_intf < 2; vfe_intf++) {
+		msm_camera_io_w(ISPIF_IRQ_STATUS_MASK, ispif->base +
+			ISPIF_VFE_m_IRQ_MASK_0(vfe_intf));
 
-	msm_camera_io_w(ISPIF_IRQ_STATUS_MASK, ispif->base +
-		ISPIF_VFE_m_IRQ_CLEAR_0(vfe_intf));
+		msm_camera_io_w(ISPIF_IRQ_STATUS_MASK, ispif->base +
+			ISPIF_VFE_m_IRQ_CLEAR_0(vfe_intf));
 
-	msm_camera_io_w(ISPIF_IRQ_STATUS_1_MASK, ispif->base +
-		ISPIF_VFE_m_IRQ_MASK_1(vfe_intf));
+		msm_camera_io_w(ISPIF_IRQ_STATUS_1_MASK, ispif->base +
+			ISPIF_VFE_m_IRQ_MASK_1(vfe_intf));
 
-	msm_camera_io_w(ISPIF_IRQ_STATUS_1_MASK, ispif->base +
-		ISPIF_VFE_m_IRQ_CLEAR_1(vfe_intf));
+		msm_camera_io_w(ISPIF_IRQ_STATUS_1_MASK, ispif->base +
+			ISPIF_VFE_m_IRQ_CLEAR_1(vfe_intf));
 
-	msm_camera_io_w(ISPIF_IRQ_STATUS_2_MASK, ispif->base +
-		ISPIF_VFE_m_IRQ_MASK_2(vfe_intf));
+		msm_camera_io_w(ISPIF_IRQ_STATUS_2_MASK, ispif->base +
+			ISPIF_VFE_m_IRQ_MASK_2(vfe_intf));
 
-	msm_camera_io_w(ISPIF_IRQ_STATUS_2_MASK, ispif->base +
-		ISPIF_VFE_m_IRQ_CLEAR_2(vfe_intf));
+		msm_camera_io_w(ISPIF_IRQ_STATUS_2_MASK, ispif->base +
+			ISPIF_VFE_m_IRQ_CLEAR_2(vfe_intf));
+	}
 
 	msm_camera_io_w_mb(ISPIF_IRQ_GLOBAL_CLEAR_CMD, ispif->base +
 		ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR);
 
-
-	rc = msm_ispif_clk_enable(ispif, vfe_intf, 0);
+	msm_ispif_clk_enable(ispif, params, 0);
 
 	return rc;
 }
@@ -511,18 +594,22 @@
 	int i, k;
 	enum msm_ispif_intftype intf_type;
 	enum msm_ispif_cid cid;
-	enum msm_ispif_vfe_intf vfe_intf = params->vfe_intf;
+	enum msm_ispif_vfe_intf vfe_intf;
 
 	BUG_ON(!ispif);
 	BUG_ON(!params);
 
-	if (!msm_ispif_is_intf_valid(ispif->csid_version, vfe_intf)) {
-		pr_err("%s: invalid interface type\n", __func__);
-		return;
+	for (i = 0; i < params->num; i++) {
+		vfe_intf = params->entries[i].vfe_intf;
+		if (!msm_ispif_is_intf_valid(ispif->csid_version, vfe_intf)) {
+			pr_err("%s: invalid interface type\n", __func__);
+			return;
+		}
 	}
 
 	for (i = 0; i < params->num; i++) {
 		intf_type = params->entries[i].intftype;
+		vfe_intf = params->entries[i].vfe_intf;
 		for (k = 0; k < params->entries[i].num_cids; k++) {
 			cid = params->entries[i].cids[k];
 			vc = cid % 4;
@@ -542,16 +629,19 @@
 					(cmd_bits << (vc * 2 + intf_type * 8));
 			}
 		}
+
+		/* cmd for PIX0, PIX1, RDI0, RDI1 */
+		if (ispif->applied_intf_cmd[vfe_intf].intf_cmd != 0xFFFFFFFF)
+			msm_camera_io_w_mb(
+				ispif->applied_intf_cmd[vfe_intf].intf_cmd,
+				ispif->base + ISPIF_VFE_m_INTF_CMD_0(vfe_intf));
+
+		/* cmd for RDI2 */
+		if (ispif->applied_intf_cmd[vfe_intf].intf_cmd1 != 0xFFFFFFFF)
+			msm_camera_io_w_mb(
+				ispif->applied_intf_cmd[vfe_intf].intf_cmd1,
+				ispif->base + ISPIF_VFE_m_INTF_CMD_1(vfe_intf));
 	}
-	/* cmd for PIX0, PIX1, RDI0, RDI1 */
-	if (ispif->applied_intf_cmd[vfe_intf].intf_cmd != 0xFFFFFFFF) {
-		msm_camera_io_w_mb(ispif->applied_intf_cmd[vfe_intf].intf_cmd,
-			ispif->base + ISPIF_VFE_m_INTF_CMD_0(vfe_intf));
-	}
-	/* cmd for RDI2 */
-	if (ispif->applied_intf_cmd[vfe_intf].intf_cmd1 != 0xFFFFFFFF)
-		msm_camera_io_w_mb(ispif->applied_intf_cmd[vfe_intf].intf_cmd1,
-			ispif->base + ISPIF_VFE_m_INTF_CMD_1(vfe_intf));
 }
 
 static int msm_ispif_stop_immediately(struct ispif_device *ispif,
@@ -570,7 +660,7 @@
 		cid_mask = msm_ispif_get_cids_mask_from_cfg(
 			&params->entries[i]);
 		msm_ispif_enable_intf_cids(ispif, params->entries[i].intftype,
-			cid_mask, params->vfe_intf, 0);
+			cid_mask, params->entries[i].vfe_intf, 0);
 	}
 
 	return rc;
@@ -581,10 +671,9 @@
 {
 	int rc;
 
-	rc = msm_ispif_clk_enable(ispif, params->vfe_intf, 1);
+	rc = msm_ispif_clk_enable(ispif, params, 1);
 	if (rc < 0) {
-		pr_err("%s: unable to enable clocks for VFE%d", __func__,
-			params->vfe_intf);
+		pr_err("%s: unable to enable clocks", __func__);
 		return rc;
 	}
 
@@ -592,13 +681,13 @@
 	if (rc) {
 		pr_err("%s: msm_ispif_intf_reset failed. rc=%d\n",
 			__func__, rc);
-		return rc;
+		goto end;
 	}
 
 	msm_ispif_intf_cmd(ispif, ISPIF_INTF_CMD_ENABLE_FRAME_BOUNDARY, params);
 
-	msm_ispif_clk_enable(ispif, params->vfe_intf, 0);
-
+end:
+	msm_ispif_clk_enable(ispif, params, 0);
 	return rc;
 }
 
@@ -613,18 +702,20 @@
 	BUG_ON(!ispif);
 	BUG_ON(!params);
 
-	vfe_intf = params->vfe_intf;
 
-	rc = msm_ispif_clk_enable(ispif, params->vfe_intf, 1);
+	rc = msm_ispif_clk_enable(ispif, params, 1);
 	if (rc < 0) {
-		pr_err("%s: unable to enable clocks for VFE%d", __func__,
-			params->vfe_intf);
+		pr_err("%s: unable to enable clocks", __func__);
 		return rc;
 	}
 
-	if (!msm_ispif_is_intf_valid(ispif->csid_version, vfe_intf)) {
-		pr_err("%s: invalid interface type\n", __func__);
-		return -EINVAL;
+	for (i = 0; i < params->num; i++) {
+		if (!msm_ispif_is_intf_valid(ispif->csid_version,
+				params->entries[i].vfe_intf)) {
+			pr_err("%s: invalid interface type\n", __func__);
+			rc = -EINVAL;
+			goto end;
+		}
 	}
 
 	msm_ispif_intf_cmd(ispif,
@@ -633,6 +724,7 @@
 	for (i = 0; i < params->num; i++) {
 		cid_mask =
 			msm_ispif_get_cids_mask_from_cfg(&params->entries[i]);
+		vfe_intf = params->entries[i].vfe_intf;
 
 		switch (params->entries[i].intftype) {
 		case PIX0:
@@ -653,7 +745,8 @@
 		default:
 			pr_err("%s: invalid intftype=%d\n", __func__,
 				params->entries[i].intftype);
-			return -EPERM;
+			rc = -EPERM;
+			goto end;
 		}
 
 		/* todo_bug_fix? very bad. use readl_poll_timeout */
@@ -666,7 +759,8 @@
 			cid_mask, vfe_intf, 0);
 	}
 
-	msm_ispif_clk_enable(ispif, vfe_intf, 0);
+end:
+	msm_ispif_clk_enable(ispif, params, 0);
 
 	return rc;
 }
@@ -718,6 +812,25 @@
 	msm_camera_io_w_mb(out[VFE0].ispifIrqStatus2,
 		ispif->base + ISPIF_VFE_m_IRQ_CLEAR_2(VFE0));
 
+	if (ispif->vfe_info.num_vfe > 1) {
+		out[VFE1].ispifIrqStatus0 = msm_camera_io_r(ispif->base +
+			ISPIF_VFE_m_IRQ_STATUS_0(VFE1));
+		msm_camera_io_w(out[VFE1].ispifIrqStatus0,
+			ispif->base + ISPIF_VFE_m_IRQ_CLEAR_0(VFE1));
+
+		out[VFE1].ispifIrqStatus1 = msm_camera_io_r(ispif->base +
+			ISPIF_VFE_m_IRQ_STATUS_1(VFE1));
+		msm_camera_io_w(out[VFE1].ispifIrqStatus1,
+				ispif->base + ISPIF_VFE_m_IRQ_CLEAR_1(VFE1));
+
+		out[VFE1].ispifIrqStatus2 = msm_camera_io_r(ispif->base +
+			ISPIF_VFE_m_IRQ_STATUS_2(VFE1));
+		msm_camera_io_w_mb(out[VFE1].ispifIrqStatus2,
+			ispif->base + ISPIF_VFE_m_IRQ_CLEAR_2(VFE1));
+	}
+	msm_camera_io_w_mb(ISPIF_IRQ_GLOBAL_CLEAR_CMD, ispif->base +
+	ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR);
+
 	if (out[VFE0].ispifIrqStatus0 & ISPIF_IRQ_STATUS_MASK) {
 		if (out[VFE0].ispifIrqStatus0 & RESET_DONE_IRQ) {
 			unsigned long flags;
@@ -742,24 +855,7 @@
 
 		ispif_process_irq(ispif, out, VFE0);
 	}
-	if (ispif->csid_version >= CSID_VERSION_V3 &&
-		ispif->vfe_info.num_vfe > 1) {
-		out[VFE1].ispifIrqStatus0 = msm_camera_io_r(ispif->base +
-			ISPIF_VFE_m_IRQ_STATUS_0(VFE1));
-		msm_camera_io_w(out[VFE1].ispifIrqStatus0,
-			ispif->base + ISPIF_VFE_m_IRQ_CLEAR_0(VFE1));
-
-		out[VFE1].ispifIrqStatus1 = msm_camera_io_r(ispif->base +
-			ISPIF_VFE_m_IRQ_STATUS_1(VFE1));
-		msm_camera_io_w(out[VFE1].ispifIrqStatus1,
-			ispif->base + ISPIF_VFE_m_IRQ_CLEAR_1(VFE1));
-
-		out[VFE1].ispifIrqStatus2 = msm_camera_io_r(ispif->base +
-			ISPIF_VFE_m_IRQ_STATUS_2(VFE1));
-		msm_camera_io_w_mb(out[VFE1].ispifIrqStatus2,
-			ispif->base + ISPIF_VFE_m_IRQ_CLEAR_2(VFE1));
-
-
+	if (ispif->vfe_info.num_vfe > 1) {
 		if (out[VFE1].ispifIrqStatus0 & RESET_DONE_IRQ) {
 			unsigned long flags;
 			spin_lock_irqsave(&ispif->auto_complete_lock, flags);
@@ -783,8 +879,6 @@
 
 		ispif_process_irq(ispif, out, VFE1);
 	}
-	msm_camera_io_w_mb(ISPIF_IRQ_GLOBAL_CLEAR_CMD, ispif->base +
-		ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR);
 }
 
 static irqreturn_t msm_io_ispif_irq(int irq_num, void *data)
@@ -825,7 +919,7 @@
 	memset(ispif->sof_count, 0, sizeof(ispif->sof_count));
 
 	ispif->csid_version = csid_version;
-	rc = msm_ispif_clk_enable(ispif, VFE0, 1);
+	rc = msm_ispif_clk_enable_one(ispif, VFE0, 1);
 	if (rc < 0) {
 		pr_err("%s: unable to enable clocks for VFE0", __func__);
 		goto error_clk0;
@@ -833,7 +927,7 @@
 
 	if (ispif->csid_version >= CSID_VERSION_V3 &&
 		ispif->vfe_info.num_vfe > 1) {
-		rc = msm_ispif_clk_enable(ispif, VFE1, 1);
+		rc = msm_ispif_clk_enable_one(ispif, VFE1, 1);
 		if (rc < 0) {
 			pr_err("%s: unable to enable clocks for VFE1",
 				__func__);
@@ -868,10 +962,10 @@
 end:
 	if (ispif->csid_version >= CSID_VERSION_V3 &&
 		ispif->vfe_info.num_vfe > 1)
-		msm_ispif_clk_enable(ispif, VFE1, 0);
+		msm_ispif_clk_enable_one(ispif, VFE1, 0);
 
 error_clk1:
-	msm_ispif_clk_enable(ispif, VFE0, 0);
+	msm_ispif_clk_enable_one(ispif, VFE0, 0);
 
 error_clk0:
 	return rc;
@@ -889,7 +983,7 @@
 	}
 
 	for (i = 0; i < ispif->vfe_info.num_vfe; i++)
-		msm_ispif_clk_enable(ispif, i, 1);
+		msm_ispif_clk_enable_one(ispif, i, 1);
 
 	/* make sure no streaming going on */
 	msm_ispif_reset(ispif);
@@ -899,7 +993,7 @@
 	iounmap(ispif->base);
 
 	for (i = 0; i < ispif->vfe_info.num_vfe; i++)
-		msm_ispif_clk_enable(ispif, i, 0);
+		msm_ispif_clk_enable_one(ispif, i, 0);
 
 	ispif->ispif_state = ISPIF_POWER_DOWN;
 }
@@ -961,7 +1055,7 @@
 	case VIDIOC_MSM_ISPIF_CFG:
 		return msm_ispif_cmd(sd, arg);
 	default:
-		pr_err("%s: invalid cmd received\n", __func__);
+		pr_err("%s: invalid cmd 0x%x received\n", __func__, cmd);
 		return -ENOIOCTLCMD;
 	}
 }
diff --git a/drivers/media/platform/msm/camera_v2/msm.c b/drivers/media/platform/msm/camera_v2/msm.c
index fbc2b93..e50ac3a 100644
--- a/drivers/media/platform/msm/camera_v2/msm.c
+++ b/drivers/media/platform/msm/camera_v2/msm.c
@@ -277,6 +277,7 @@
 {
 	struct msm_session *session = NULL;
 	struct msm_stream  *stream = NULL;
+	unsigned long flags;
 
 	session = msm_queue_find(msm_session_q, struct msm_session,
 		list, __msm_queue_find_session, &session_id);
@@ -287,9 +288,10 @@
 		list, __msm_queue_find_stream, &stream_id);
 	if (!stream)
 		return;
-
+	spin_lock_irqsave(&(session->stream_q.lock), flags);
 	list_del_init(&stream->list);
 	session->stream_q.len--;
+	spin_unlock_irqrestore(&(session->stream_q.lock), flags);
 	kzfree(stream);
 }
 
@@ -426,6 +428,7 @@
 {
 	struct msm_session *session;
 	struct msm_command_ack *cmd_ack;
+	unsigned long flags;
 
 	session = msm_queue_find(msm_session_q, struct msm_session,
 		list, __msm_queue_find_session, &session_id);
@@ -439,6 +442,11 @@
 		return;
 
 	msm_queue_drain(&cmd_ack->command_q, struct msm_command, list);
+
+	spin_lock_irqsave(&(session->command_ack_q.lock), flags);
+	list_del_init(&cmd_ack->list);
+	session->command_ack_q.len--;
+	spin_unlock_irqrestore(&(session->command_ack_q.lock), flags);
 }
 
 static inline int __msm_v4l2_subdev_shutdown(struct v4l2_subdev *sd)
diff --git a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
index 8a21512..35210a0 100644
--- a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
+++ b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
@@ -13,9 +13,15 @@
 
 static struct msm_buf_mngr_device *msm_buf_mngr_dev;
 
+struct v4l2_subdev *msm_buf_mngr_get_subdev(void)
+{
+	return &msm_buf_mngr_dev->subdev.sd;
+}
+
 static int msm_buf_mngr_get_buf(struct msm_buf_mngr_device *buf_mngr_dev,
 	void __user *argp)
 {
+	unsigned long flags;
 	struct msm_buf_mngr_info *buf_info =
 		(struct msm_buf_mngr_info *)argp;
 	struct msm_get_bufs *new_entry =
@@ -35,9 +41,9 @@
 	}
 	new_entry->session_id = buf_info->session_id;
 	new_entry->stream_id = buf_info->stream_id;
-	mutex_lock(&buf_mngr_dev->buf_q_lock);
+	spin_lock_irqsave(&buf_mngr_dev->buf_q_spinlock, flags);
 	list_add_tail(&new_entry->entry, &buf_mngr_dev->buf_qhead);
-	mutex_unlock(&buf_mngr_dev->buf_q_lock);
+	spin_unlock_irqrestore(&buf_mngr_dev->buf_q_spinlock, flags);
 	buf_info->index = new_entry->vb2_buf->v4l2_buf.index;
 	return 0;
 }
@@ -45,10 +51,11 @@
 static int msm_buf_mngr_buf_done(struct msm_buf_mngr_device *buf_mngr_dev,
 	struct msm_buf_mngr_info *buf_info)
 {
+	unsigned long flags;
 	struct msm_get_bufs *bufs, *save;
 	int ret = -EINVAL;
 
-	mutex_lock(&buf_mngr_dev->buf_q_lock);
+	spin_lock_irqsave(&buf_mngr_dev->buf_q_spinlock, flags);
 	list_for_each_entry_safe(bufs, save, &buf_mngr_dev->buf_qhead, entry) {
 		if ((bufs->session_id == buf_info->session_id) &&
 			(bufs->stream_id == buf_info->stream_id) &&
@@ -64,7 +71,7 @@
 			break;
 		}
 	}
-	mutex_unlock(&buf_mngr_dev->buf_q_lock);
+	spin_unlock_irqrestore(&buf_mngr_dev->buf_q_spinlock, flags);
 	return ret;
 }
 
@@ -72,10 +79,11 @@
 static int msm_buf_mngr_put_buf(struct msm_buf_mngr_device *buf_mngr_dev,
 	struct msm_buf_mngr_info *buf_info)
 {
+	unsigned long flags;
 	struct msm_get_bufs *bufs, *save;
 	int ret = -EINVAL;
 
-	mutex_lock(&buf_mngr_dev->buf_q_lock);
+	spin_lock_irqsave(&buf_mngr_dev->buf_q_spinlock, flags);
 	list_for_each_entry_safe(bufs, save, &buf_mngr_dev->buf_qhead, entry) {
 		if ((bufs->session_id == buf_info->session_id) &&
 			(bufs->stream_id == buf_info->stream_id) &&
@@ -87,7 +95,7 @@
 			break;
 		}
 	}
-	mutex_unlock(&buf_mngr_dev->buf_q_lock);
+	spin_unlock_irqrestore(&buf_mngr_dev->buf_q_spinlock, flags);
 	return ret;
 }
 
@@ -163,14 +171,13 @@
 		&msm_buf_mngr_dev->vb2_ops);
 
 	INIT_LIST_HEAD(&msm_buf_mngr_dev->buf_qhead);
-	mutex_init(&msm_buf_mngr_dev->buf_q_lock);
+	spin_lock_init(&msm_buf_mngr_dev->buf_q_spinlock);
 end:
 	return rc;
 }
 
 static void __exit msm_buf_mngr_exit(void)
 {
-	mutex_destroy(&msm_buf_mngr_dev->buf_q_lock);
 	kfree(msm_buf_mngr_dev);
 }
 
diff --git a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.h b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.h
index a2b3a7e..56886cd 100644
--- a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.h
+++ b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.h
@@ -33,7 +33,7 @@
 
 struct msm_buf_mngr_device {
 	struct list_head buf_qhead;
-	struct mutex buf_q_lock;
+	spinlock_t buf_q_spinlock;
 	struct msm_sd_subdev subdev;
 	struct msm_sd_req_vb2_q vb2_ops;
 };
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index 8f63d33..c06b009 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -22,7 +22,6 @@
 #include <linux/regulator/consumer.h>
 #include <linux/ion.h>
 #include <linux/proc_fs.h>
-#include <linux/debugfs.h>
 #include <linux/msm_ion.h>
 #include <linux/iommu.h>
 #include <mach/iommu_domains.h>
@@ -33,11 +32,14 @@
 #include <media/v4l2-ioctl.h>
 #include <media/msmb_camera.h>
 #include <media/msmb_pproc.h>
+#include <media/msmb_generic_buf_mgr.h>
 #include "msm_cpp.h"
 #include "msm_camera_io_util.h"
 
 #define MSM_CPP_DRV_NAME "msm_cpp"
 
+#define MSM_CPP_MAX_BUFF_QUEUE 16
+
 #define CONFIG_MSM_CPP_DBG 0
 
 #if CONFIG_MSM_CPP_DBG
@@ -126,6 +128,278 @@
 	return tmp;
 }
 
+static struct msm_cpp_buff_queue_info_t *msm_cpp_get_buff_queue_entry(
+	struct cpp_device *cpp_dev, uint32_t session_id, uint32_t stream_id)
+{
+	uint32_t i = 0;
+	struct msm_cpp_buff_queue_info_t *buff_queue_info = NULL;
+
+	for (i = 0; i < cpp_dev->num_buffq; i++) {
+		if ((cpp_dev->buff_queue[i].used == 1) &&
+			(cpp_dev->buff_queue[i].session_id == session_id) &&
+			(cpp_dev->buff_queue[i].stream_id == stream_id)) {
+			buff_queue_info = &cpp_dev->buff_queue[i];
+			break;
+		}
+	}
+
+	if (buff_queue_info == NULL) {
+		pr_err("error buffer queue entry for sess:%d strm:%d not found\n",
+			session_id, stream_id);
+	}
+	return buff_queue_info;
+}
+
+static unsigned long msm_cpp_get_phy_addr(struct cpp_device *cpp_dev,
+	struct msm_cpp_buff_queue_info_t *buff_queue_info, uint32_t buff_index,
+	uint8_t native_buff)
+{
+	unsigned long phy_add = 0;
+	struct list_head *buff_head;
+	struct msm_cpp_buffer_map_list_t *buff, *save;
+
+	if (native_buff)
+		buff_head = &buff_queue_info->native_buff_head;
+	else
+		buff_head = &buff_queue_info->vb2_buff_head;
+
+	list_for_each_entry_safe(buff, save, buff_head, entry) {
+		if (buff->map_info.buff_info.index == buff_index) {
+			phy_add = buff->map_info.phy_addr;
+			break;
+		}
+	}
+
+	return phy_add;
+}
+
+static unsigned long msm_cpp_queue_buffer_info(struct cpp_device *cpp_dev,
+	struct msm_cpp_buff_queue_info_t *buff_queue,
+	struct msm_cpp_buffer_info_t *buffer_info)
+{
+	struct list_head *buff_head;
+	struct msm_cpp_buffer_map_list_t *buff, *save;
+	int rc = 0;
+
+	if (buffer_info->native_buff)
+		buff_head = &buff_queue->native_buff_head;
+	else
+		buff_head = &buff_queue->vb2_buff_head;
+
+	list_for_each_entry_safe(buff, save, buff_head, entry) {
+		if (buff->map_info.buff_info.index == buffer_info->index) {
+			pr_err("error buffer index already queued\n");
+			return -EINVAL;
+		}
+	}
+
+	buff = kzalloc(
+		sizeof(struct msm_cpp_buffer_map_list_t), GFP_KERNEL);
+	if (!buff) {
+		pr_err("error allocating memory\n");
+		return -EINVAL;
+	}
+
+	buff->map_info.buff_info = *buffer_info;
+	buff->map_info.ion_handle = ion_import_dma_buf(cpp_dev->client,
+		buffer_info->fd);
+	if (IS_ERR_OR_NULL(buff->map_info.ion_handle)) {
+		pr_err("ION import failed\n");
+		goto QUEUE_BUFF_ERROR1;
+	}
+
+	rc = ion_map_iommu(cpp_dev->client, buff->map_info.ion_handle,
+		cpp_dev->domain_num, 0, SZ_4K, 0,
+		(unsigned long *)&buff->map_info.phy_addr,
+		&buff->map_info.len, 0, 0);
+	if (rc < 0) {
+		pr_err("ION mmap failed\n");
+		goto QUEUE_BUFF_ERROR2;
+	}
+
+	INIT_LIST_HEAD(&buff->entry);
+	list_add_tail(&buff->entry, buff_head);
+
+	return buff->map_info.phy_addr;
+
+QUEUE_BUFF_ERROR2:
+	ion_unmap_iommu(cpp_dev->client, buff->map_info.ion_handle,
+		cpp_dev->domain_num, 0);
+QUEUE_BUFF_ERROR1:
+	ion_free(cpp_dev->client, buff->map_info.ion_handle);
+	buff->map_info.ion_handle = NULL;
+	kzfree(buff);
+
+	return 0;
+}
+
+static void msm_cpp_dequeue_buffer_info(struct cpp_device *cpp_dev,
+	struct msm_cpp_buffer_map_list_t *buff)
+{
+	ion_unmap_iommu(cpp_dev->client, buff->map_info.ion_handle,
+		cpp_dev->domain_num, 0);
+	ion_free(cpp_dev->client, buff->map_info.ion_handle);
+	buff->map_info.ion_handle = NULL;
+
+	list_del_init(&buff->entry);
+	kzfree(buff);
+
+	return;
+}
+
+static unsigned long msm_cpp_fetch_buffer_info(struct cpp_device *cpp_dev,
+	struct msm_cpp_buffer_info_t *buffer_info, uint32_t session_id,
+	uint32_t stream_id)
+{
+	unsigned long phy_addr = 0;
+	struct msm_cpp_buff_queue_info_t *buff_queue_info;
+	uint8_t native_buff = buffer_info->native_buff;
+
+	buff_queue_info = msm_cpp_get_buff_queue_entry(cpp_dev, session_id,
+		stream_id);
+	if (buff_queue_info == NULL) {
+		pr_err("error finding buffer queue entry for sessid:%d strmid:%d\n",
+			session_id, stream_id);
+		return phy_addr;
+	}
+
+	phy_addr = msm_cpp_get_phy_addr(cpp_dev, buff_queue_info,
+		buffer_info->index, native_buff);
+	if ((phy_addr == 0) && (native_buff)) {
+		phy_addr = msm_cpp_queue_buffer_info(cpp_dev, buff_queue_info,
+			buffer_info);
+	}
+	return phy_addr;
+}
+
+static int32_t msm_cpp_enqueue_buff_info_list(struct cpp_device *cpp_dev,
+	struct msm_cpp_stream_buff_info_t *stream_buff_info)
+{
+	uint32_t j;
+	struct msm_cpp_buff_queue_info_t *buff_queue_info;
+
+	buff_queue_info = msm_cpp_get_buff_queue_entry(cpp_dev,
+			(stream_buff_info->identity >> 16) & 0xFFFF,
+			stream_buff_info->identity & 0xFFFF);
+	if (buff_queue_info == NULL) {
+		pr_err("error finding buffer queue entry for sessid:%d strmid:%d\n",
+			(stream_buff_info->identity >> 16) & 0xFFFF,
+			stream_buff_info->identity & 0xFFFF);
+		return -EINVAL;
+	}
+
+	for (j = 0; j < stream_buff_info->num_buffs; j++) {
+		msm_cpp_queue_buffer_info(cpp_dev, buff_queue_info,
+		&stream_buff_info->buffer_info[j]);
+	}
+	return 0;
+}
+
+static int32_t msm_cpp_dequeue_buff_info_list(struct cpp_device *cpp_dev,
+	struct msm_cpp_buff_queue_info_t *buff_queue_info)
+{
+	struct msm_cpp_buffer_map_list_t *buff, *save;
+	struct list_head *buff_head;
+
+	buff_head = &buff_queue_info->native_buff_head;
+	list_for_each_entry_safe(buff, save, buff_head, entry) {
+		msm_cpp_dequeue_buffer_info(cpp_dev, buff);
+	}
+
+	buff_head = &buff_queue_info->vb2_buff_head;
+	list_for_each_entry_safe(buff, save, buff_head, entry) {
+		msm_cpp_dequeue_buffer_info(cpp_dev, buff);
+	}
+
+	return 0;
+}
+
+static int32_t msm_cpp_add_buff_queue_entry(struct cpp_device *cpp_dev,
+	uint16_t session_id, uint16_t stream_id)
+{
+	uint32_t i;
+	struct msm_cpp_buff_queue_info_t *buff_queue_info;
+
+	for (i = 0; i < cpp_dev->num_buffq; i++) {
+		if (cpp_dev->buff_queue[i].used == 0) {
+			buff_queue_info = &cpp_dev->buff_queue[i];
+			buff_queue_info->used = 1;
+			buff_queue_info->session_id = session_id;
+			buff_queue_info->stream_id = stream_id;
+			INIT_LIST_HEAD(&buff_queue_info->vb2_buff_head);
+			INIT_LIST_HEAD(&buff_queue_info->native_buff_head);
+			return 0;
+		}
+	}
+	pr_err("buffer queue full. error for sessionid: %d streamid: %d\n",
+		session_id, stream_id);
+	return -EINVAL;
+}
+
+static int32_t msm_cpp_free_buff_queue_entry(struct cpp_device *cpp_dev,
+	uint32_t session_id, uint32_t stream_id)
+{
+	struct msm_cpp_buff_queue_info_t *buff_queue_info;
+
+	buff_queue_info = msm_cpp_get_buff_queue_entry(cpp_dev, session_id,
+		stream_id);
+	if (buff_queue_info == NULL) {
+		pr_err("error finding buffer queue entry for sessid:%d strmid:%d\n",
+			session_id, stream_id);
+		return -EINVAL;
+	}
+
+	buff_queue_info->used = 0;
+	buff_queue_info->session_id = 0;
+	buff_queue_info->stream_id = 0;
+	INIT_LIST_HEAD(&buff_queue_info->vb2_buff_head);
+	INIT_LIST_HEAD(&buff_queue_info->native_buff_head);
+	return 0;
+}
+
+static int32_t msm_cpp_create_buff_queue(struct cpp_device *cpp_dev,
+	uint32_t num_buffq)
+{
+	struct msm_cpp_buff_queue_info_t *buff_queue;
+	buff_queue = kzalloc(
+		sizeof(struct msm_cpp_buff_queue_info_t) * num_buffq,
+		GFP_KERNEL);
+	if (!buff_queue) {
+		pr_err("Buff queue allocation failure\n");
+		return -ENOMEM;
+	}
+
+	if (cpp_dev->buff_queue) {
+		pr_err("Buff queue not empty\n");
+		kzfree(buff_queue);
+		return -EINVAL;
+	} else {
+		cpp_dev->buff_queue = buff_queue;
+		cpp_dev->num_buffq = num_buffq;
+	}
+	return 0;
+}
+
+static void msm_cpp_delete_buff_queue(struct cpp_device *cpp_dev)
+{
+	uint32_t i;
+
+	for (i = 0; i < cpp_dev->num_buffq; i++) {
+		if (cpp_dev->buff_queue[i].used == 1) {
+			pr_err("Queue not free sessionid: %d, streamid: %d\n",
+				cpp_dev->buff_queue[i].session_id,
+				cpp_dev->buff_queue[i].stream_id);
+			msm_cpp_free_buff_queue_entry(cpp_dev,
+				cpp_dev->buff_queue[i].session_id,
+				cpp_dev->buff_queue[i].stream_id);
+		}
+	}
+	kzfree(cpp_dev->buff_queue);
+	cpp_dev->buff_queue = NULL;
+	cpp_dev->num_buffq = 0;
+	return;
+}
+
 static void msm_cpp_poll(void __iomem *cpp_base, u32 val)
 {
 	uint32_t tmp, retry = 0;
@@ -176,12 +450,13 @@
 
 static irqreturn_t msm_cpp_irq(int irq_num, void *data)
 {
+	unsigned long flags;
 	uint32_t tx_level;
 	uint32_t irq_status;
-	uint32_t msg_id, cmd_len;
 	uint32_t i;
-	uint32_t tx_fifo[16];
+	uint32_t tx_fifo[MSM_CPP_TX_FIFO_LEVEL];
 	struct cpp_device *cpp_dev = data;
+	struct msm_cpp_tasklet_queue_cmd *queue_cmd;
 	irq_status = msm_camera_io_r(cpp_dev->base + MSM_CPP_MICRO_IRQGEN_STAT);
 	CPP_DBG("status: 0x%x\n", irq_status);
 	if (irq_status & 0x8) {
@@ -192,6 +467,62 @@
 				MSM_CPP_MICRO_FIFO_TX_DATA);
 		}
 
+		spin_lock_irqsave(&cpp_dev->tasklet_lock, flags);
+		queue_cmd = &cpp_dev->tasklet_queue_cmd[cpp_dev->taskletq_idx];
+		if (queue_cmd->cmd_used) {
+			pr_err("%s: cpp tasklet queue overflow\n", __func__);
+			list_del(&queue_cmd->list);
+		} else {
+			atomic_add(1, &cpp_dev->irq_cnt);
+		}
+		queue_cmd->irq_status = irq_status;
+		queue_cmd->tx_level = tx_level;
+		memset(&queue_cmd->tx_fifo[0], 0, sizeof(queue_cmd->tx_fifo));
+		for (i = 0; i < tx_level; i++)
+			queue_cmd->tx_fifo[i] = tx_fifo[i];
+
+		queue_cmd->cmd_used = 1;
+		cpp_dev->taskletq_idx =
+			(cpp_dev->taskletq_idx + 1) % MSM_CPP_TASKLETQ_SIZE;
+		list_add_tail(&queue_cmd->list, &cpp_dev->tasklet_q);
+		spin_unlock_irqrestore(&cpp_dev->tasklet_lock, flags);
+
+		tasklet_schedule(&cpp_dev->cpp_tasklet);
+	}
+	msm_camera_io_w(irq_status, cpp_dev->base + MSM_CPP_MICRO_IRQGEN_CLR);
+	return IRQ_HANDLED;
+}
+
+void msm_cpp_do_tasklet(unsigned long data)
+{
+	unsigned long flags;
+	uint32_t irq_status;
+	uint32_t tx_level;
+	uint32_t msg_id, cmd_len;
+	uint32_t i;
+	uint32_t tx_fifo[MSM_CPP_TX_FIFO_LEVEL];
+	struct cpp_device *cpp_dev = (struct cpp_device *) data;
+	struct msm_cpp_tasklet_queue_cmd *queue_cmd;
+
+	while (atomic_read(&cpp_dev->irq_cnt)) {
+		spin_lock_irqsave(&cpp_dev->tasklet_lock, flags);
+		queue_cmd = list_first_entry(&cpp_dev->tasklet_q,
+		struct msm_cpp_tasklet_queue_cmd, list);
+		if (!queue_cmd) {
+			atomic_set(&cpp_dev->irq_cnt, 0);
+			spin_unlock_irqrestore(&cpp_dev->tasklet_lock, flags);
+			return;
+		}
+		atomic_sub(1, &cpp_dev->irq_cnt);
+		list_del(&queue_cmd->list);
+		queue_cmd->cmd_used = 0;
+		irq_status = queue_cmd->irq_status;
+		tx_level = queue_cmd->tx_level;
+		for (i = 0; i < tx_level; i++)
+			tx_fifo[i] = queue_cmd->tx_fifo[i];
+
+		spin_unlock_irqrestore(&cpp_dev->tasklet_lock, flags);
+
 		for (i = 0; i < tx_level; i++) {
 			if (tx_fifo[i] == MSM_CPP_MSG_ID_CMD) {
 				cmd_len = tx_fifo[i+1];
@@ -204,8 +535,6 @@
 			}
 		}
 	}
-	msm_camera_io_w(irq_status, cpp_dev->base + MSM_CPP_MICRO_IRQGEN_CLR);
-	return IRQ_HANDLED;
 }
 
 static void msm_cpp_boot_hw(struct cpp_device *cpp_dev)
@@ -309,6 +638,7 @@
 			rc = -EBUSY;
 			goto req_irq_fail;
 		}
+		cpp_dev->buf_mgr_subdev = msm_buf_mngr_get_subdev();
 	}
 
 	cpp_dev->hw_info.cpp_hw_version =
@@ -318,6 +648,9 @@
 		msm_camera_io_r(cpp_dev->cpp_hw_base + 0x4);
 	pr_debug("CPP HW Caps: 0x%x\n", cpp_dev->hw_info.cpp_hw_caps);
 	msm_camera_io_w(0x1, cpp_dev->vbif_base + 0x4);
+	cpp_dev->taskletq_idx = 0;
+	atomic_set(&cpp_dev->irq_cnt, 0);
+	msm_cpp_create_buff_queue(cpp_dev, MSM_CPP_MAX_BUFF_QUEUE);
 	if (cpp_dev->is_firmware_loaded == 1)
 		msm_cpp_boot_hw(cpp_dev);
 	return rc;
@@ -339,9 +672,12 @@
 
 static void cpp_release_hardware(struct cpp_device *cpp_dev)
 {
-	if (cpp_dev->state != CPP_STATE_BOOT)
+	if (cpp_dev->state != CPP_STATE_BOOT) {
 		free_irq(cpp_dev->irq->start, cpp_dev);
-
+		tasklet_kill(&cpp_dev->cpp_tasklet);
+		atomic_set(&cpp_dev->irq_cnt, 0);
+	}
+	msm_cpp_delete_buff_queue(cpp_dev);
 	iounmap(cpp_dev->base);
 	iounmap(cpp_dev->vbif_base);
 	iounmap(cpp_dev->cpp_hw_base);
@@ -504,6 +840,18 @@
 	.close = cpp_close_node,
 };
 
+static int msm_cpp_buffer_ops(struct cpp_device *cpp_dev,
+	uint32_t buff_mgr_ops, struct msm_buf_mngr_info *buff_mgr_info)
+{
+	int rc = -EINVAL;
+
+	rc = v4l2_subdev_call(cpp_dev->buf_mgr_subdev, core, ioctl,
+		buff_mgr_ops, buff_mgr_info);
+	if (rc < 0)
+		pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc);
+	return rc;
+}
+
 static int msm_cpp_notify_frame_done(struct cpp_device *cpp_dev)
 {
 	struct v4l2_event v4l2_evt;
@@ -511,10 +859,13 @@
 	struct msm_queue_cmd *event_qcmd;
 	struct msm_cpp_frame_info_t *processed_frame;
 	struct msm_device_queue *queue = &cpp_dev->processing_q;
+	struct msm_buf_mngr_info buff_mgr_info;
+	int rc = 0;
 
 	if (queue->len > 0) {
 		frame_qcmd = msm_dequeue(queue, list_frame);
 		processed_frame = frame_qcmd->command;
+		do_gettimeofday(&(processed_frame->out_time));
 		kfree(frame_qcmd);
 		event_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_ATOMIC);
 		if (!event_qcmd) {
@@ -526,78 +877,55 @@
 		CPP_DBG("fid %d\n", processed_frame->frame_id);
 		msm_enqueue(&cpp_dev->eventData_q, &event_qcmd->list_eventdata);
 
+		if (!processed_frame->output_buffer_info.processed_divert) {
+			memset(&buff_mgr_info, 0 ,
+				sizeof(struct msm_buf_mngr_info));
+			buff_mgr_info.session_id =
+				((processed_frame->identity >> 16) & 0xFFFF);
+			buff_mgr_info.stream_id =
+				(processed_frame->identity & 0xFFFF);
+			buff_mgr_info.frame_id = processed_frame->frame_id;
+			buff_mgr_info.timestamp = processed_frame->timestamp;
+			buff_mgr_info.index =
+				processed_frame->output_buffer_info.index;
+			rc = msm_cpp_buffer_ops(cpp_dev,
+				VIDIOC_MSM_BUF_MNGR_BUF_DONE,
+				&buff_mgr_info);
+			if (rc < 0) {
+				pr_err("error putting buffer\n");
+				rc = -EINVAL;
+			}
+		}
 		v4l2_evt.id = processed_frame->inst_id;
 		v4l2_evt.type = V4L2_EVENT_CPP_FRAME_DONE;
 		v4l2_event_queue(cpp_dev->msm_sd.sd.devnode, &v4l2_evt);
 	}
-	return 0;
+	return rc;
 }
 
-static int msm_cpp_send_frame_to_hardware(struct cpp_device *cpp_dev)
+static int msm_cpp_send_frame_to_hardware(struct cpp_device *cpp_dev,
+	struct msm_queue_cmd *frame_qcmd)
 {
 	uint32_t i;
-	struct msm_queue_cmd *frame_qcmd;
+	int32_t rc = -EINVAL;
 	struct msm_cpp_frame_info_t *process_frame;
-	struct msm_device_queue *queue;
 
 	if (cpp_dev->processing_q.len < MAX_CPP_PROCESSING_FRAME) {
-		while (cpp_dev->processing_q.len < MAX_CPP_PROCESSING_FRAME) {
-			if (cpp_dev->realtime_q.len != 0) {
-				queue = &cpp_dev->realtime_q;
-			} else if (cpp_dev->offline_q.len != 0) {
-				queue = &cpp_dev->offline_q;
-			} else {
-				pr_debug("All frames queued\n");
-				break;
-			}
-			frame_qcmd = msm_dequeue(queue, list_frame);
-			process_frame = frame_qcmd->command;
-			msm_enqueue(&cpp_dev->processing_q,
-						&frame_qcmd->list_frame);
-			msm_cpp_write(0x6, cpp_dev->base);
-			for (i = 0; i < process_frame->msg_len; i++)
-				msm_cpp_write(process_frame->cpp_cmd_msg[i],
-					cpp_dev->base);
-		}
+		process_frame = frame_qcmd->command;
+		msm_enqueue(&cpp_dev->processing_q,
+					&frame_qcmd->list_frame);
+		msm_cpp_write(0x6, cpp_dev->base);
+		for (i = 0; i < process_frame->msg_len; i++)
+			msm_cpp_write(process_frame->cpp_cmd_msg[i],
+				cpp_dev->base);
+		do_gettimeofday(&(process_frame->in_time));
+		rc = 0;
 	}
-	return 0;
+	return rc;
 }
 
 static int msm_cpp_flush_frames(struct cpp_device *cpp_dev)
 {
-	struct v4l2_event v4l2_evt;
-	struct msm_queue_cmd *frame_qcmd;
-	struct msm_cpp_frame_info_t *process_frame;
-	struct msm_device_queue *queue;
-	struct msm_queue_cmd *event_qcmd;
-
-	do {
-		if (cpp_dev->realtime_q.len != 0) {
-			queue = &cpp_dev->realtime_q;
-		} else if (cpp_dev->offline_q.len != 0) {
-			queue = &cpp_dev->offline_q;
-		} else {
-			pr_debug("All frames flushed\n");
-			break;
-		}
-		frame_qcmd = msm_dequeue(queue, list_frame);
-		process_frame = frame_qcmd->command;
-		kfree(frame_qcmd);
-		event_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_ATOMIC);
-		if (!event_qcmd) {
-			pr_err("Insufficient memory. return");
-			return -ENOMEM;
-		}
-		atomic_set(&event_qcmd->on_heap, 1);
-		event_qcmd->command = process_frame;
-		CPP_DBG("fid %d\n", process_frame->frame_id);
-		msm_enqueue(&cpp_dev->eventData_q, &event_qcmd->list_eventdata);
-
-		v4l2_evt.id = process_frame->inst_id;
-		v4l2_evt.type = V4L2_EVENT_CPP_FRAME_DONE;
-		v4l2_event_queue(cpp_dev->msm_sd.sd.devnode, &v4l2_evt);
-	} while ((cpp_dev->realtime_q.len != 0) ||
-		(cpp_dev->offline_q.len != 0));
 	return 0;
 }
 
@@ -609,9 +937,9 @@
 	struct msm_cpp_frame_info_t *new_frame =
 		kzalloc(sizeof(struct msm_cpp_frame_info_t), GFP_KERNEL);
 	uint32_t *cpp_frame_msg;
-	unsigned long len;
 	unsigned long in_phyaddr, out_phyaddr;
 	uint16_t num_stripes = 0;
+	struct msm_buf_mngr_info buff_mgr_info;
 
 	int i = 0;
 	if (!new_frame) {
@@ -646,44 +974,40 @@
 
 	new_frame->cpp_cmd_msg = cpp_frame_msg;
 
-	CPP_DBG("CPP in_fd: %d out_fd: %d\n", new_frame->src_fd,
-		new_frame->dst_fd);
-
-	new_frame->src_ion_handle = ion_import_dma_buf(cpp_dev->client,
-		new_frame->src_fd);
-	if (IS_ERR_OR_NULL(new_frame->src_ion_handle)) {
-		pr_err("ION import failed\n");
-		rc = PTR_ERR(new_frame->src_ion_handle);
+	in_phyaddr = msm_cpp_fetch_buffer_info(cpp_dev,
+		&new_frame->input_buffer_info,
+		((new_frame->identity >> 16) & 0xFFFF),
+		(new_frame->identity & 0xFFFF));
+	if (!in_phyaddr) {
+		pr_err("error gettting input physical address\n");
+		rc = -EINVAL;
 		goto ERROR2;
 	}
 
-	rc = ion_map_iommu(cpp_dev->client, new_frame->src_ion_handle,
-		cpp_dev->domain_num, 0, SZ_4K, 0,
-		(unsigned long *)&in_phyaddr, &len, 0, 0);
+	memset(&new_frame->output_buffer_info, 0,
+		sizeof(struct msm_cpp_buffer_info_t));
+	memset(&buff_mgr_info, 0, sizeof(struct msm_buf_mngr_info));
+	buff_mgr_info.session_id = ((new_frame->identity >> 16) & 0xFFFF);
+	buff_mgr_info.stream_id = (new_frame->identity & 0xFFFF);
+	rc = msm_cpp_buffer_ops(cpp_dev, VIDIOC_MSM_BUF_MNGR_GET_BUF,
+		&buff_mgr_info);
 	if (rc < 0) {
-		pr_err("ION import failed\n");
-		rc = PTR_ERR(new_frame->src_ion_handle);
+		pr_err("error getting buffer\n");
+		rc = -EINVAL;
+		goto ERROR2;
+	}
+
+	new_frame->output_buffer_info.index = buff_mgr_info.index;
+	out_phyaddr = msm_cpp_fetch_buffer_info(cpp_dev,
+		&new_frame->output_buffer_info,
+		((new_frame->identity >> 16) & 0xFFFF),
+		(new_frame->identity & 0xFFFF));
+	if (!out_phyaddr) {
+		pr_err("error gettting output physical address\n");
+		rc = -EINVAL;
 		goto ERROR3;
 	}
 
-	CPP_DBG("in phy addr: 0x%x len: %ld\n", (uint32_t) in_phyaddr, len);
-	new_frame->dest_ion_handle = ion_import_dma_buf(cpp_dev->client,
-		new_frame->dst_fd);
-	if (IS_ERR_OR_NULL(new_frame->dest_ion_handle)) {
-		pr_err("ION import failed\n");
-		rc = PTR_ERR(new_frame->dest_ion_handle);
-		goto ERROR4;
-	}
-
-	rc = ion_map_iommu(cpp_dev->client, new_frame->dest_ion_handle,
-		cpp_dev->domain_num, 0, SZ_4K, 0,
-		(unsigned long *)&out_phyaddr, &len, 0, 0);
-	if (rc < 0) {
-		rc = PTR_ERR(new_frame->dest_ion_handle);
-		goto ERROR5;
-	}
-
-	CPP_DBG("out phy addr: 0x%x len: %ld\n", (uint32_t)out_phyaddr, len);
 	num_stripes = ((cpp_frame_msg[12] >> 20) & 0x3FF) +
 		((cpp_frame_msg[12] >> 10) & 0x3FF) +
 		(cpp_frame_msg[12] & 0x3FF);
@@ -700,44 +1024,29 @@
 	if (!frame_qcmd) {
 		pr_err("Insufficient memory. return\n");
 		rc = -ENOMEM;
-		goto ERROR6;
+		goto ERROR3;
 	}
 
 	atomic_set(&frame_qcmd->on_heap, 1);
 	frame_qcmd->command = new_frame;
-	if (new_frame->frame_type == MSM_CPP_REALTIME_FRAME) {
-		msm_enqueue(&cpp_dev->realtime_q,
-					&frame_qcmd->list_frame);
-	} else if (new_frame->frame_type == MSM_CPP_OFFLINE_FRAME) {
-		msm_enqueue(&cpp_dev->offline_q,
-					&frame_qcmd->list_frame);
-	} else {
-		pr_err("Invalid frame type\n");
+	rc = msm_cpp_send_frame_to_hardware(cpp_dev, frame_qcmd);
+	if (rc < 0) {
+		pr_err("error cannot send frame to hardware\n");
 		rc = -EINVAL;
-		goto ERROR7;
+		goto ERROR4;
 	}
-	msm_cpp_send_frame_to_hardware(cpp_dev);
+
 	return rc;
-ERROR7:
-	kfree(frame_qcmd);
-ERROR6:
-	ion_unmap_iommu(cpp_dev->client, new_frame->dest_ion_handle,
-		cpp_dev->domain_num, 0);
-ERROR5:
-	ion_free(cpp_dev->client, new_frame->dest_ion_handle);
-	new_frame->dest_ion_handle = NULL;
 ERROR4:
-	ion_unmap_iommu(cpp_dev->client, new_frame->src_ion_handle,
-		cpp_dev->domain_num, 0);
+	kfree(frame_qcmd);
 ERROR3:
-	ion_free(cpp_dev->client, new_frame->src_ion_handle);
-	new_frame->src_ion_handle = NULL;
+	msm_cpp_buffer_ops(cpp_dev, VIDIOC_MSM_BUF_MNGR_PUT_BUF,
+		&buff_mgr_info);
 ERROR2:
 	kfree(cpp_frame_msg);
 ERROR1:
 	kfree(new_frame);
 	return rc;
-
 }
 
 long msm_cpp_subdev_ioctl(struct v4l2_subdev *sd,
@@ -795,6 +1104,97 @@
 	case VIDIOC_MSM_CPP_FLUSH_QUEUE:
 		rc = msm_cpp_flush_frames(cpp_dev);
 		break;
+	case VIDIOC_MSM_CPP_ENQUEUE_STREAM_BUFF_INFO: {
+		struct msm_cpp_stream_buff_info_t *u_stream_buff_info;
+		struct msm_cpp_stream_buff_info_t k_stream_buff_info;
+		if (sizeof(struct msm_cpp_stream_buff_info_t) !=
+			ioctl_ptr->len) {
+			pr_err("%s:%d: invalid length\n", __func__, __LINE__);
+			mutex_unlock(&cpp_dev->mutex);
+			return -EINVAL;
+		}
+
+		u_stream_buff_info = kzalloc(ioctl_ptr->len, GFP_KERNEL);
+		if (!u_stream_buff_info) {
+			pr_err("%s:%d: malloc error\n", __func__, __LINE__);
+			mutex_unlock(&cpp_dev->mutex);
+			return -EINVAL;
+		}
+
+		rc = (copy_from_user(u_stream_buff_info,
+				(void __user *)ioctl_ptr->ioctl_ptr,
+				ioctl_ptr->len) ? -EFAULT : 0);
+		if (rc) {
+			ERR_COPY_FROM_USER();
+			kfree(u_stream_buff_info);
+			mutex_unlock(&cpp_dev->mutex);
+			return -EINVAL;
+		}
+
+		k_stream_buff_info.num_buffs = u_stream_buff_info->num_buffs;
+		k_stream_buff_info.identity = u_stream_buff_info->identity;
+		k_stream_buff_info.buffer_info =
+			kzalloc(k_stream_buff_info.num_buffs *
+			sizeof(struct msm_cpp_buffer_info_t), GFP_KERNEL);
+		if (!k_stream_buff_info.buffer_info) {
+			pr_err("%s:%d: malloc error\n", __func__, __LINE__);
+			kfree(u_stream_buff_info);
+			mutex_unlock(&cpp_dev->mutex);
+			return -EINVAL;
+		}
+
+		rc = (copy_from_user(k_stream_buff_info.buffer_info,
+				(void __user *)u_stream_buff_info->buffer_info,
+				k_stream_buff_info.num_buffs *
+				sizeof(struct msm_cpp_buffer_info_t)) ?
+				-EFAULT : 0);
+		if (rc) {
+			ERR_COPY_FROM_USER();
+			kfree(k_stream_buff_info.buffer_info);
+			kfree(u_stream_buff_info);
+			mutex_unlock(&cpp_dev->mutex);
+			return -EINVAL;
+		}
+
+		rc = msm_cpp_add_buff_queue_entry(cpp_dev,
+			((k_stream_buff_info.identity >> 16) & 0xFFFF),
+			(k_stream_buff_info.identity & 0xFFFF));
+		if (!rc)
+			rc = msm_cpp_enqueue_buff_info_list(cpp_dev,
+				&k_stream_buff_info);
+
+		kfree(k_stream_buff_info.buffer_info);
+		kfree(u_stream_buff_info);
+		break;
+	}
+	case VIDIOC_MSM_CPP_DEQUEUE_STREAM_BUFF_INFO: {
+		uint32_t identity;
+		struct msm_cpp_buff_queue_info_t *buff_queue_info;
+
+		rc = (copy_from_user(&identity,
+				(void __user *)ioctl_ptr->ioctl_ptr,
+				ioctl_ptr->len) ? -EFAULT : 0);
+		if (rc) {
+			ERR_COPY_FROM_USER();
+			mutex_unlock(&cpp_dev->mutex);
+			return -EINVAL;
+		}
+
+		buff_queue_info = msm_cpp_get_buff_queue_entry(cpp_dev,
+			((identity >> 16) & 0xFFFF), (identity & 0xFFFF));
+		if (buff_queue_info == NULL) {
+			pr_err("error finding buffer queue entry for identity:%d\n",
+				identity);
+			mutex_unlock(&cpp_dev->mutex);
+			return -EINVAL;
+		}
+
+		msm_cpp_dequeue_buff_info_list(cpp_dev, buff_queue_info);
+		rc = msm_cpp_free_buff_queue_entry(cpp_dev,
+			buff_queue_info->session_id,
+			buff_queue_info->stream_id);
+		break;
+	}
 	case VIDIOC_MSM_CPP_GET_EVENTPAYLOAD: {
 		struct msm_device_queue *queue = &cpp_dev->eventData_q;
 		struct msm_queue_cmd *event_qcmd;
@@ -808,23 +1208,6 @@
 					mutex_unlock(&cpp_dev->mutex);
 					return -EINVAL;
 		}
-		if (process_frame->dest_ion_handle) {
-			ion_unmap_iommu(cpp_dev->client,
-				process_frame->dest_ion_handle,
-				cpp_dev->domain_num, 0);
-			ion_free(cpp_dev->client,
-				process_frame->dest_ion_handle);
-			process_frame->dest_ion_handle = NULL;
-		}
-
-		if (process_frame->src_ion_handle) {
-			ion_unmap_iommu(cpp_dev->client,
-				process_frame->src_ion_handle,
-				cpp_dev->domain_num, 0);
-			ion_free(cpp_dev->client,
-				process_frame->src_ion_handle);
-			process_frame->src_ion_handle = NULL;
-		}
 
 		kfree(process_frame->cpp_cmd_msg);
 		kfree(process_frame);
@@ -834,7 +1217,7 @@
 	}
 	mutex_unlock(&cpp_dev->mutex);
 	CPP_DBG("X\n");
-	return 0;
+	return rc;
 }
 
 int msm_cpp_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
@@ -861,8 +1244,6 @@
 	.core = &msm_cpp_subdev_core_ops,
 };
 
-static int msm_cpp_enable_debugfs(struct cpp_device *cpp_dev);
-
 static struct v4l2_file_operations msm_cpp_v4l2_subdev_fops;
 
 static long msm_cpp_subdev_do_ioctl(
@@ -960,6 +1341,7 @@
 	v4l2_set_subdevdata(&cpp_dev->msm_sd.sd, cpp_dev);
 	platform_set_drvdata(pdev, &cpp_dev->msm_sd.sd);
 	mutex_init(&cpp_dev->mutex);
+	spin_lock_init(&cpp_dev->tasklet_lock);
 
 	if (pdev->dev.of_node)
 		of_property_read_u32((&pdev->dev)->of_node,
@@ -1054,14 +1436,13 @@
 	cpp_release_hardware(cpp_dev);
 	cpp_dev->state = CPP_STATE_OFF;
 
-	msm_cpp_enable_debugfs(cpp_dev);
 	msm_queue_init(&cpp_dev->eventData_q, "eventdata");
-	msm_queue_init(&cpp_dev->offline_q, "frame");
-	msm_queue_init(&cpp_dev->realtime_q, "frame");
 	msm_queue_init(&cpp_dev->processing_q, "frame");
+	INIT_LIST_HEAD(&cpp_dev->tasklet_q);
+	tasklet_init(&cpp_dev->cpp_tasklet, msm_cpp_do_tasklet,
+		(unsigned long)cpp_dev);
 	cpp_dev->cpp_open_cnt = 0;
 	cpp_dev->is_firmware_loaded = 0;
-
 	return rc;
 
 ERROR3:
@@ -1126,65 +1507,6 @@
 	platform_driver_unregister(&cpp_driver);
 }
 
-static int msm_cpp_debugfs_stream_s(void *data, u64 val)
-{
-	struct cpp_device *cpp_dev = data;
-	CPP_DBG("CPP processing frame E\n");
-	while (1) {
-		mutex_lock(&cpp_dev->mutex);
-		msm_cpp_notify_frame_done(cpp_dev);
-		msm_cpp_send_frame_to_hardware(cpp_dev);
-		mutex_unlock(&cpp_dev->mutex);
-		msleep(20);
-	}
-	CPP_DBG("CPP processing frame X\n");
-	return 0;
-}
-
-static int msm_cpp_debugfs_load_fw(void *data, u64 val)
-{
-	const struct firmware *fw = NULL;
-	struct cpp_device *cpp_dev = data;
-	int rc = 0;
-	CPP_DBG("%s\n", __func__);
-	rc = request_firmware(&fw, "FIRMWARE.bin", &cpp_dev->pdev->dev);
-	if (rc) {
-		pr_err("request_fw failed\n");
-	} else {
-		CPP_DBG("request ok\n");
-		release_firmware(fw);
-	}
-	return 0;
-}
-
-DEFINE_SIMPLE_ATTRIBUTE(cpp_debugfs_stream, NULL,
-			msm_cpp_debugfs_stream_s, "%llu\n");
-DEFINE_SIMPLE_ATTRIBUTE(cpp_debugfs_fw, NULL,
-			msm_cpp_debugfs_load_fw, "%llu\n");
-
-static int msm_cpp_enable_debugfs(struct cpp_device *cpp_dev)
-{
-	struct dentry *debugfs_base, *debugfs_test;
-	debugfs_base = debugfs_create_dir("msm_camera", NULL);
-	if (!debugfs_base)
-		return -ENOMEM;
-
-	debugfs_test = debugfs_create_file("test", S_IRUGO | S_IWUSR,
-		debugfs_base, (void *)cpp_dev, &cpp_debugfs_stream);
-	if (!debugfs_test) {
-		debugfs_remove(debugfs_base);
-		return -ENOMEM;
-	}
-
-	if (!debugfs_create_file("fw", S_IRUGO | S_IWUSR, debugfs_base,
-			(void *)cpp_dev, &cpp_debugfs_fw)) {
-		debugfs_remove(debugfs_test);
-		debugfs_remove(debugfs_base);
-		return -ENOMEM;
-	}
-	return 0;
-}
-
 module_init(msm_cpp_init_module);
 module_exit(msm_cpp_exit_module);
 MODULE_DESCRIPTION("MSM CPP driver");
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
index 0c586ca..36a5fa5 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
@@ -17,6 +17,7 @@
 #include <linux/io.h>
 #include <linux/list.h>
 #include <linux/platform_device.h>
+#include <linux/interrupt.h>
 #include <media/v4l2-subdev.h>
 #include "msm_sd.h"
 
@@ -70,6 +71,8 @@
 #define MSM_CPP_END_ADDRESS			0x3F00
 
 #define MSM_CPP_POLL_RETRIES		20
+#define MSM_CPP_TASKLETQ_SIZE		16
+#define MSM_CPP_TX_FIFO_LEVEL		16
 
 struct cpp_subscribe_info {
 	struct v4l2_fh *vfh;
@@ -116,6 +119,34 @@
 	const char *name;
 };
 
+struct msm_cpp_tasklet_queue_cmd {
+	struct list_head list;
+	uint32_t irq_status;
+	uint32_t tx_fifo[MSM_CPP_TX_FIFO_LEVEL];
+	uint32_t tx_level;
+	uint8_t cmd_used;
+};
+
+struct msm_cpp_buffer_map_info_t {
+	unsigned long len;
+	unsigned long phy_addr;
+	struct ion_handle *ion_handle;
+	struct msm_cpp_buffer_info_t buff_info;
+};
+
+struct msm_cpp_buffer_map_list_t {
+	struct msm_cpp_buffer_map_info_t map_info;
+	struct list_head entry;
+};
+
+struct msm_cpp_buff_queue_info_t {
+	uint32_t used;
+	uint16_t session_id;
+	uint16_t stream_id;
+	struct list_head vb2_buff_head;
+	struct list_head native_buff_head;
+};
+
 struct cpp_device {
 	struct platform_device *pdev;
 	struct msm_sd_subdev msm_sd;
@@ -141,19 +172,28 @@
 	struct ion_client *client;
 	struct kref refcount;
 
+	/* Reusing proven tasklet from msm isp */
+	atomic_t irq_cnt;
+	uint8_t taskletq_idx;
+	spinlock_t  tasklet_lock;
+	struct list_head tasklet_q;
+	struct tasklet_struct cpp_tasklet;
+	struct msm_cpp_tasklet_queue_cmd
+		tasklet_queue_cmd[MSM_CPP_TASKLETQ_SIZE];
+
 	struct cpp_subscribe_info cpp_subscribe_list[MAX_ACTIVE_CPP_INSTANCE];
 	uint32_t cpp_open_cnt;
 	struct cpp_hw_info hw_info;
 
 	struct msm_device_queue eventData_q; /* V4L2 Event Payload Queue */
 
-	/* Offline Frame Queue process when realtime queue is empty */
-	struct msm_device_queue offline_q;
-	/* Realtime Frame Queue process with highest priority */
-	struct msm_device_queue realtime_q;
 	/* Processing Queue
 	 * store frame info for frames sent to microcontroller
 	 */
 	struct msm_device_queue processing_q;
+
+	struct msm_cpp_buff_queue_info_t *buff_queue;
+	uint32_t num_buffq;
+	struct v4l2_subdev *buf_mgr_subdev;
 };
 #endif /* __MSM_CPP_H__ */
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
index 0df0488..fbd4a2e 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
@@ -24,7 +24,7 @@
 #define CSID_VERSION_V3                      0x30000000
 #define MSM_CSID_DRV_NAME                    "msm_csid"
 
-#define DBG_CSID 1
+#define DBG_CSID 0
 
 #define TRUE   1
 #define FALSE  0
@@ -36,8 +36,6 @@
 #define CDBG(fmt, args...) do { } while (0)
 #endif
 
-static uint32_t irq_count;
-
 static int msm_csid_cid_lut(
 	struct msm_camera_csid_lut_params *csid_lut_params,
 	void __iomem *csidbase)
@@ -84,8 +82,8 @@
 {
 	uint32_t val = 0;
 	val = ((1 << csid_params->lane_cnt) - 1) << 20;
-	msm_camera_io_w(0x7f010801 | val, csidbase + CSID_IRQ_MASK_ADDR);
-	msm_camera_io_w(0x7f010801 | val, csidbase + CSID_IRQ_CLEAR_CMD_ADDR);
+	msm_camera_io_w(0x7f010800 | val, csidbase + CSID_IRQ_MASK_ADDR);
+	msm_camera_io_w(0x7f010800 | val, csidbase + CSID_IRQ_CLEAR_CMD_ADDR);
 }
 #else
 static void msm_csid_set_debug_reg(void __iomem *csidbase,
@@ -94,11 +92,8 @@
 
 static void msm_csid_reset(struct csid_device *csid_dev)
 {
-	CDBG("%s:%d called\n", __func__, __LINE__);
 	msm_camera_io_w(CSID_RST_STB_ALL, csid_dev->base + CSID_RST_CMD_ADDR);
-	CDBG("%s:%d called\n", __func__, __LINE__);
 	wait_for_completion_interruptible(&csid_dev->reset_complete);
-	CDBG("%s:%d called\n", __func__, __LINE__);
 	return;
 }
 
@@ -159,11 +154,6 @@
 		 __func__, csid_dev->pdev->id, irq);
 	if (irq & (0x1 << CSID_RST_DONE_IRQ_BITSHIFT))
 			complete(&csid_dev->reset_complete);
-	if (irq & 0x1) {
-		pr_debug("%s CSID%d_IRQ_STATUS_ADDR = 0x%x\n",
-			__func__, csid_dev->pdev->id, irq);
-		irq_count++;
-	}
 	msm_camera_io_w(irq, csid_dev->base + CSID_IRQ_CLEAR_CMD_ADDR);
 	return IRQ_HANDLED;
 }
@@ -253,13 +243,11 @@
 	int rc = 0;
 	uint8_t core_id = 0;
 
-	CDBG("%s:%d called\n", __func__, __LINE__);
 	if (!csid_version) {
 		pr_err("%s:%d csid_version NULL\n", __func__, __LINE__);
 		rc = -EINVAL;
 		return rc;
 	}
-	CDBG("%s:%d called\n", __func__, __LINE__);
 
 	if (csid_dev->csid_state == CSID_POWER_UP) {
 		pr_err("%s: csid invalid state %d\n", __func__,
@@ -267,7 +255,6 @@
 		rc = -EINVAL;
 		return rc;
 	}
-	CDBG("%s:%d called\n", __func__, __LINE__);
 
 	csid_dev->base = ioremap(csid_dev->mem->start,
 		resource_size(csid_dev->mem));
@@ -276,10 +263,8 @@
 		rc = -ENOMEM;
 		return rc;
 	}
-	CDBG("%s:%d called\n", __func__, __LINE__);
 
 	if (CSID_VERSION <= CSID_VERSION_V2) {
-		CDBG("%s:%d called\n", __func__, __LINE__);
 		rc = msm_camera_config_vreg(&csid_dev->pdev->dev,
 			csid_8960_vreg_info, ARRAY_SIZE(csid_8960_vreg_info),
 			NULL, 0, &csid_dev->csi_vdd, 1);
@@ -287,7 +272,6 @@
 			pr_err("%s: regulator on failed\n", __func__);
 			goto vreg_config_failed;
 		}
-		CDBG("%s:%d called\n", __func__, __LINE__);
 
 		rc = msm_camera_enable_vreg(&csid_dev->pdev->dev,
 			csid_8960_vreg_info, ARRAY_SIZE(csid_8960_vreg_info),
@@ -296,7 +280,6 @@
 			pr_err("%s: regulator enable failed\n", __func__);
 			goto vreg_enable_failed;
 		}
-		CDBG("%s:%d called\n", __func__, __LINE__);
 
 		rc = msm_cam_clk_enable(&csid_dev->pdev->dev,
 			csid_8960_clk_info, csid_dev->csid_clk,
@@ -305,9 +288,7 @@
 			pr_err("%s: clock enable failed\n", __func__);
 			goto clk_enable_failed;
 		}
-		CDBG("%s:%d called\n", __func__, __LINE__);
 	} else if (CSID_VERSION >= CSID_VERSION_V3) {
-		CDBG("%s:%d called\n", __func__, __LINE__);
 		rc = msm_camera_config_vreg(&csid_dev->pdev->dev,
 			csid_vreg_info, ARRAY_SIZE(csid_vreg_info),
 			NULL, 0, &csid_dev->csi_vdd, 1);
@@ -315,7 +296,6 @@
 			pr_err("%s: regulator on failed\n", __func__);
 			goto vreg_config_failed;
 		}
-		CDBG("%s:%d called\n", __func__, __LINE__);
 
 		rc = msm_camera_enable_vreg(&csid_dev->pdev->dev,
 			csid_vreg_info, ARRAY_SIZE(csid_vreg_info),
@@ -324,7 +304,6 @@
 			pr_err("%s: regulator enable failed\n", __func__);
 			goto vreg_enable_failed;
 		}
-		CDBG("%s:%d called\n", __func__, __LINE__);
 
 		rc = msm_cam_clk_enable(&csid_dev->pdev->dev,
 			csid_8974_clk_info[0].clk_info, csid_dev->csid0_clk,
@@ -333,10 +312,8 @@
 			pr_err("%s: clock enable failed\n", __func__);
 			goto csid0_clk_enable_failed;
 		}
-		CDBG("%s:%d called\n", __func__, __LINE__);
 		core_id = csid_dev->pdev->id;
 		if (core_id) {
-			CDBG("%s:%d called\n", __func__, __LINE__);
 			rc = msm_cam_clk_enable(&csid_dev->pdev->dev,
 				csid_8974_clk_info[core_id].clk_info,
 				csid_dev->csid_clk,
@@ -348,7 +325,6 @@
 			}
 		}
 	}
-		CDBG("%s:%d called\n", __func__, __LINE__);
 
 	csid_dev->hw_version =
 		msm_camera_io_r(csid_dev->base + CSID_HW_VERSION_ADDR);
@@ -356,17 +332,12 @@
 		csid_dev->hw_version);
 	*csid_version = csid_dev->hw_version;
 
-	CDBG("%s:%d called\n", __func__, __LINE__);
 	init_completion(&csid_dev->reset_complete);
-	CDBG("%s:%d called\n", __func__, __LINE__);
 
 	enable_irq(csid_dev->irq->start);
-	CDBG("%s:%d called\n", __func__, __LINE__);
 
 	msm_csid_reset(csid_dev);
-	CDBG("%s:%d called\n", __func__, __LINE__);
 	csid_dev->csid_state = CSID_POWER_UP;
-	irq_count = 0;
 	return rc;
 
 clk_enable_failed:
@@ -578,7 +549,6 @@
 	struct csid_device *new_csid_dev;
 	uint32_t csi_vdd_voltage = 0;
 	int rc = 0;
-	CDBG("%s:%d called\n", __func__, __LINE__);
 	new_csid_dev = kzalloc(sizeof(struct csid_device), GFP_KERNEL);
 	if (!new_csid_dev) {
 		pr_err("%s: no enough memory\n", __func__);
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
index 83b9bb3..b6bc0d7 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
@@ -640,109 +640,109 @@
 
 	debugfs_create_u32(
 		"hw_notification_interval",
-		S_IRUGO|S_IWUGO,
+		S_IRUGO | S_IWUSR | S_IWGRP,
 		mpq_demux->demux.dmx.debugfs_demux_dir,
 		&mpq_demux->hw_notification_interval);
 
 	debugfs_create_u32(
 		"hw_notification_min_interval",
-		S_IRUGO|S_IWUGO,
+		S_IRUGO | S_IWUSR | S_IWGRP,
 		mpq_demux->demux.dmx.debugfs_demux_dir,
 		&mpq_demux->hw_notification_min_interval);
 
 	debugfs_create_u32(
 		"hw_notification_count",
-		S_IRUGO|S_IWUGO,
+		S_IRUGO | S_IWUSR | S_IWGRP,
 		mpq_demux->demux.dmx.debugfs_demux_dir,
 		&mpq_demux->hw_notification_count);
 
 	debugfs_create_u32(
 		"hw_notification_size",
-		S_IRUGO|S_IWUGO,
+		S_IRUGO | S_IWUSR | S_IWGRP,
 		mpq_demux->demux.dmx.debugfs_demux_dir,
 		&mpq_demux->hw_notification_size);
 
 	debugfs_create_u32(
 		"hw_notification_min_size",
-		S_IRUGO|S_IWUGO,
+		S_IRUGO | S_IWUSR | S_IWGRP,
 		mpq_demux->demux.dmx.debugfs_demux_dir,
 		&mpq_demux->hw_notification_min_size);
 
 	debugfs_create_u32(
 		"decoder_drop_count",
-		S_IRUGO|S_IWUGO,
+		S_IRUGO | S_IWUSR | S_IWGRP,
 		mpq_demux->demux.dmx.debugfs_demux_dir,
 		&mpq_demux->decoder_drop_count);
 
 	debugfs_create_u32(
 		"decoder_out_count",
-		S_IRUGO|S_IWUGO,
+		S_IRUGO | S_IWUSR | S_IWGRP,
 		mpq_demux->demux.dmx.debugfs_demux_dir,
 		&mpq_demux->decoder_out_count);
 
 	debugfs_create_u32(
 		"decoder_out_interval_sum",
-		S_IRUGO|S_IWUGO,
+		S_IRUGO | S_IWUSR | S_IWGRP,
 		mpq_demux->demux.dmx.debugfs_demux_dir,
 		&mpq_demux->decoder_out_interval_sum);
 
 	debugfs_create_u32(
 		"decoder_out_interval_average",
-		S_IRUGO|S_IWUGO,
+		S_IRUGO | S_IWUSR | S_IWGRP,
 		mpq_demux->demux.dmx.debugfs_demux_dir,
 		&mpq_demux->decoder_out_interval_average);
 
 	debugfs_create_u32(
 		"decoder_out_interval_max",
-		S_IRUGO|S_IWUGO,
+		S_IRUGO | S_IWUSR | S_IWGRP,
 		mpq_demux->demux.dmx.debugfs_demux_dir,
 		&mpq_demux->decoder_out_interval_max);
 
 	debugfs_create_u32(
 		"decoder_ts_errors",
-		S_IRUGO|S_IWUGO,
+		S_IRUGO | S_IWUSR | S_IWGRP,
 		mpq_demux->demux.dmx.debugfs_demux_dir,
 		&mpq_demux->decoder_ts_errors);
 
 	debugfs_create_u32(
 		"sdmx_process_count",
-		S_IRUGO|S_IWUGO,
+		S_IRUGO | S_IWUSR | S_IWGRP,
 		mpq_demux->demux.dmx.debugfs_demux_dir,
 		&mpq_demux->sdmx_process_count);
 
 	debugfs_create_u32(
 		"sdmx_process_time_sum",
-		S_IRUGO|S_IWUGO,
+		S_IRUGO | S_IWUSR | S_IWGRP,
 		mpq_demux->demux.dmx.debugfs_demux_dir,
 		&mpq_demux->sdmx_process_time_sum);
 
 	debugfs_create_u32(
 		"sdmx_process_time_average",
-		S_IRUGO|S_IWUGO,
+		S_IRUGO | S_IWUSR | S_IWGRP,
 		mpq_demux->demux.dmx.debugfs_demux_dir,
 		&mpq_demux->sdmx_process_time_average);
 
 	debugfs_create_u32(
 		"sdmx_process_time_max",
-		S_IRUGO|S_IWUGO,
+		S_IRUGO | S_IWUSR | S_IWGRP,
 		mpq_demux->demux.dmx.debugfs_demux_dir,
 		&mpq_demux->sdmx_process_time_max);
 
 	debugfs_create_u32(
 		"sdmx_process_packets_sum",
-		S_IRUGO|S_IWUGO,
+		S_IRUGO | S_IWUSR | S_IWGRP,
 		mpq_demux->demux.dmx.debugfs_demux_dir,
 		&mpq_demux->sdmx_process_packets_sum);
 
 	debugfs_create_u32(
 		"sdmx_process_packets_average",
-		S_IRUGO|S_IWUGO,
+		S_IRUGO | S_IWUSR | S_IWGRP,
 		mpq_demux->demux.dmx.debugfs_demux_dir,
 		&mpq_demux->sdmx_process_packets_average);
 
 	debugfs_create_u32(
 		"sdmx_process_packets_min",
-		S_IRUGO|S_IWUGO,
+		S_IRUGO | S_IWUSR | S_IWGRP,
 		mpq_demux->demux.dmx.debugfs_demux_dir,
 		&mpq_demux->sdmx_process_packets_min);
 }
diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
index d782227..50adb13 100644
--- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
@@ -1245,6 +1245,15 @@
 			"Failed to load buffer usage table: %d\n", rc);
 		goto err_load_buffer_usage_table;
 	}
+
+	rc = of_property_read_u32(pdev->dev.of_node, "qcom,max-hw-load",
+			&res->max_load);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to determine max load supported: %d\n", rc);
+		goto err_load_buffer_usage_table;
+	}
+
 	return rc;
 
 err_load_buffer_usage_table:
@@ -1295,6 +1304,8 @@
 		res->load_freq_tbl[c].load = pdata->load_table[c][0];
 		res->load_freq_tbl[c].freq = pdata->load_table[c][1];
 	}
+
+	res->max_load = pdata->max_load;
 	return rc;
 }
 
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 30530d4..8eecb98 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -22,7 +22,7 @@
 #include "msm_smem.h"
 #include "msm_vidc_debug.h"
 
-#define HW_RESPONSE_TIMEOUT msecs_to_jiffies(200)
+#define HW_RESPONSE_TIMEOUT 200
 
 #define IS_ALREADY_IN_STATE(__p, __d) ({\
 	int __rc = (__p >= __d);\
@@ -49,11 +49,6 @@
 
 #define TIME_DIFF_THRESHOLD 200
 
-/*Load is in Macroblocks (MBs) per sec. This value is calculated
- * based on one 4k video instance @ 24 fps plus one 1080p video
- * instance @ 30fps. 1 MB = 16 X 16 pixels*/
-#define MAX_LOAD 1074240
-
 static int msm_comm_get_load(struct msm_vidc_core *core,
 	enum session_type type)
 {
@@ -1265,13 +1260,32 @@
 		dprintk(VIDC_ERR, "%s invalid parameters", __func__);
 		return -EINVAL;
 	}
+
 	num_mbs_per_sec = msm_comm_get_load(inst->core, MSM_VIDC_DECODER);
 	num_mbs_per_sec += msm_comm_get_load(inst->core, MSM_VIDC_ENCODER);
-	if (num_mbs_per_sec > MAX_LOAD) {
-		dprintk(VIDC_ERR, "HW is overloaded, needed:%d max: %d\n",
-			num_mbs_per_sec, MAX_LOAD);
+	if (num_mbs_per_sec > inst->core->resources.max_load) {
+		struct msm_vidc_inst *temp;
+
+		dprintk(VIDC_ERR, "HW is overloaded, needed: %d max: %d\n",
+			num_mbs_per_sec, inst->core->resources.max_load);
+		dprintk(VIDC_ERR, "Running instances:\n");
+		dprintk(VIDC_ERR, "%4s|%4s|%4s|%4s\n", "type", "w", "h", "fps");
+		list_for_each_entry(temp, &inst->core->instances, list) {
+			mutex_lock(&temp->lock);
+			if (temp->state >= MSM_VIDC_OPEN_DONE &&
+					temp->state < MSM_VIDC_STOP_DONE) {
+				dprintk(VIDC_ERR, "%4d|%4d|%4d|%4d\n",
+						temp->session_type,
+						temp->prop.width,
+						temp->prop.height,
+						temp->prop.fps);
+			}
+			mutex_unlock(&temp->lock);
+		}
+
 		return -ENOMEM;
 	}
+
 	hdev = inst->core->device;
 
 	if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_LOAD_RESOURCES)) {
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_resources.h b/drivers/media/platform/msm/vidc/msm_vidc_resources.h
index 86b824b..693c1a5 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_resources.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_resources.h
@@ -74,6 +74,7 @@
 	struct iommu_set iommu_group_set;
 	struct buffer_usage_set buffer_usage_set;
 	bool has_ocmem;
+	uint32_t max_load;
 	struct platform_device *pdev;
 };
 
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 779b996..8031c74 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -386,11 +386,22 @@
 	msm_smem_free(clnt, mem);
 }
 
-static void venus_hfi_write_register(u8 *base_addr, u32 reg,
+static void venus_hfi_write_register(struct venus_hfi_device *device, u32 reg,
 				u32 value, u8 *vaddr)
 {
 	u32 hwiosymaddr = reg;
+	u8 *base_addr;
+	if (!device) {
+		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
+		return;
+	}
 
+	base_addr = device->hal_data->register_base_addr;
+	if (!device->clocks_enabled) {
+		dprintk(VIDC_WARN,
+			"HFI Write register failed : Clocks are OFF\n");
+		return;
+	}
 	reg &= REG_ADDR_OFFSET_BITMASK;
 	if (reg == (u32)VIDC_CPU_CS_SCIACMDARG2) {
 		/* workaround to offset of FW bias */
@@ -416,14 +427,26 @@
 	wmb();
 }
 
-static int venus_hfi_read_register(u8 *base_addr, u32 reg)
+static int venus_hfi_read_register(struct venus_hfi_device *device, u32 reg)
 {
-	int rc = readl_relaxed((u32)base_addr + reg);
+	int rc ;
+	u8 *base_addr;
+	if (!device) {
+		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
+		return -EINVAL;
+	}
+
+	base_addr = device->hal_data->register_base_addr;
+	if (!device->clocks_enabled) {
+		dprintk(VIDC_WARN,
+			"HFI Read register failed : Clocks are OFF\n");
+		return -EINVAL;
+	}
+	rc = readl_relaxed((u32)base_addr + reg);
 	rmb();
 	return rc;
 }
-static inline void venus_hfi_clk_gating_on(struct venus_hfi_device *device,
-	enum vidc_clocks clk_level)
+static inline void venus_hfi_clk_gating_on(struct venus_hfi_device *device)
 {
 	int i;
 	struct venus_core_clock *cl;
@@ -431,19 +454,18 @@
 		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
 		return;
 	}
-	if (device->clocks_enabled == 0) {
-		dprintk(VIDC_DBG, "VCODEC clocks are already disabled");
+	if (!device->clocks_enabled) {
+		dprintk(VIDC_DBG, "Clocks are already disabled");
 		goto already_disabled;
 	}
-	for (i = 0; i < clk_level; i++) {
+	for (i = 0; i <= device->clk_gating_level; i++) {
 		cl = &device->resources.clock[i];
-		clk_disable_unprepare(cl->clk);
+		clk_disable(cl->clk);
 	}
 already_disabled:
 	device->clocks_enabled = 0;
 }
-static inline int venus_hfi_clk_gating_off(struct venus_hfi_device *device,
-	enum vidc_clocks clk_level)
+static inline int venus_hfi_clk_gating_off(struct venus_hfi_device *device)
 {
 	int i;
 	struct venus_core_clock *cl;
@@ -452,13 +474,13 @@
 		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
 		return -EINVAL;
 	}
-	if (device->clocks_enabled == 1) {
-		dprintk(VIDC_DBG, "VCODEC clocks are already enabled");
+	if (device->clocks_enabled) {
+		dprintk(VIDC_DBG, "Clocks are already enabled");
 		goto already_enabled;
 	}
-	for (i = 0; i < clk_level; i++) {
+	for (i = 0; i <= device->clk_gating_level; i++) {
 		cl = &device->resources.clock[i];
-		rc = clk_prepare_enable(cl->clk);
+		rc = clk_enable(cl->clk);
 		if (rc) {
 			dprintk(VIDC_ERR, "Failed to enable clocks\n");
 			goto fail_clk_enable;
@@ -472,7 +494,7 @@
 fail_clk_enable:
 	for (; i >= 0; i--) {
 		cl = &device->resources.clock[i];
-		clk_disable_unprepare(cl->clk);
+		clk_disable(cl->clk);
 	}
 	return rc;
 }
@@ -482,7 +504,7 @@
 {
 	int num_rows = clock->count;
 	struct load_freq_table *table = clock->load_freq_tbl;
-	unsigned long ret = table[num_rows-1].freq;
+	unsigned long ret = table[0].freq;
 	int i;
 	for (i = 0; i < num_rows; i++) {
 		if (num_mbs_per_sec > table[i].load)
@@ -497,11 +519,11 @@
 {
 	int rc = 0;
 	struct venus_hfi_device *device = dev;
-	device->load = load;
 	if (!device) {
 		dprintk(VIDC_ERR, "Invalid args: %p\n", device);
 		return -EINVAL;
 	}
+	device->load = load;
 	rc = clk_set_rate(device->resources.clock[VCODEC_CLK].clk,
 		venus_hfi_get_clock_rate(&device->resources.clock[VCODEC_CLK],
 			load));
@@ -527,20 +549,22 @@
 		dprintk(VIDC_ERR, "cannot write to shared Q's");
 		goto err_q_write;
 	}
-	result = venus_hfi_clk_gating_off(device, VCODEC_CLK);
+	mutex_lock(&device->clock_lock);
+	result = venus_hfi_clk_gating_off(device);
 	if (result) {
-		dprintk(VIDC_ERR, "VCODEC clock enable failed\n");
+		dprintk(VIDC_ERR, "%s : Clock enable failed\n",
+			__func__);
 		goto err_q_write;
 	}
 	result = venus_hfi_scale_clocks(device, device->load);
 	if (result) {
-		dprintk(VIDC_ERR, "VCODEC clock scaling failed\n");
+		dprintk(VIDC_ERR, "Clock scaling failed\n");
 		goto err_q_write;
 	}
 	if (!venus_hfi_write_queue(q_info, (u8 *)pkt, &rx_req_is_set)) {
 		if (rx_req_is_set)
 			venus_hfi_write_register(
-				device->hal_data->register_base_addr,
+				device,
 				VIDC_CPU_IC_SOFTINT,
 				1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT, 0);
 		result = 0;
@@ -549,6 +573,7 @@
 	}
 err_q_write:
 	mutex_unlock(&device->write_lock);
+	mutex_unlock(&device->clock_lock);
 	return result;
 }
 
@@ -570,11 +595,17 @@
 		goto read_error;
 	}
 	q_info = &device->iface_queues[VIDC_IFACEQ_MSGQ_IDX];
-
+	mutex_lock(&device->clock_lock);
+	rc = venus_hfi_clk_gating_off(device);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"%s : Clock enable failed\n", __func__);
+		goto read_error;
+	}
 	if (!venus_hfi_read_queue(q_info, (u8 *)pkt, &tx_req_is_set)) {
 		if (tx_req_is_set)
 			venus_hfi_write_register(
-				device->hal_data->register_base_addr,
+				device,
 				VIDC_CPU_IC_SOFTINT,
 				1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT, 0);
 		rc = 0;
@@ -584,6 +615,7 @@
 	}
 read_error:
 	mutex_unlock(&device->read_lock);
+	mutex_unlock(&device->clock_lock);
 	return rc;
 }
 
@@ -604,11 +636,18 @@
 		rc = -ENODATA;
 		goto dbg_error;
 	}
+	mutex_lock(&device->clock_lock);
+	rc = venus_hfi_clk_gating_off(device);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"%s : Clock enable failed\n", __func__);
+		goto dbg_error;
+	}
 	q_info = &device->iface_queues[VIDC_IFACEQ_DBGQ_IDX];
 	if (!venus_hfi_read_queue(q_info, (u8 *)pkt, &tx_req_is_set)) {
 		if (tx_req_is_set)
 			venus_hfi_write_register(
-				device->hal_data->register_base_addr,
+				device,
 				VIDC_CPU_IC_SOFTINT,
 				1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT, 0);
 		rc = 0;
@@ -618,6 +657,7 @@
 	}
 dbg_error:
 	mutex_unlock(&device->read_lock);
+	mutex_unlock(&device->clock_lock);
 	return rc;
 }
 
@@ -822,16 +862,16 @@
 		iface_q->q_array.align_device_addr;
 	q_hdr->qhdr_type |= HFI_Q_ID_CTRL_TO_HOST_DEBUG_Q;
 
-	venus_hfi_write_register(dev->hal_data->register_base_addr,
+	venus_hfi_write_register(dev,
 			VIDC_UC_REGION_ADDR,
 			(u32) dev->iface_q_table.align_device_addr, 0);
-	venus_hfi_write_register(dev->hal_data->register_base_addr,
+	venus_hfi_write_register(dev,
 			VIDC_UC_REGION_SIZE, SHARED_QSIZE, 0);
-	venus_hfi_write_register(dev->hal_data->register_base_addr,
+	venus_hfi_write_register(dev,
 		VIDC_CPU_CS_SCIACMDARG2,
 		(u32) dev->iface_q_table.align_device_addr,
 		dev->iface_q_table.align_virtual_addr);
-	venus_hfi_write_register(dev->hal_data->register_base_addr,
+	venus_hfi_write_register(dev,
 		VIDC_CPU_CS_SCIACMDARG1, 0x01,
 		dev->iface_q_table.align_virtual_addr);
 
@@ -851,14 +891,14 @@
 		dev->qdss.mem_data = NULL;
 	}
 	if (!IS_ERR_OR_NULL(dev->qdss.align_device_addr))
-		venus_hfi_write_register(dev->hal_data->register_base_addr,
+		venus_hfi_write_register(dev,
 			VIDC_MMAP_ADDR,
 			(u32) dev->qdss.align_device_addr, 0);
 
 	vsfr = (struct hfi_sfr_struct *) dev->sfr.align_virtual_addr;
 	vsfr->bufSize = SFR_SIZE;
 	if (!IS_ERR_OR_NULL(dev->sfr.align_device_addr))
-		venus_hfi_write_register(dev->hal_data->register_base_addr,
+		venus_hfi_write_register(dev,
 			VIDC_SFR_ADDR, (u32)dev->sfr.align_device_addr , 0);
 	return 0;
 fail_alloc_queue:
@@ -869,14 +909,14 @@
 {
 	u32 ctrl_status = 0, count = 0, rc = 0;
 	int max_tries = 100;
-	venus_hfi_write_register(device->hal_data->register_base_addr,
+	venus_hfi_write_register(device,
 			VIDC_WRAPPER_INTR_MASK, 0x8, 0);
-	venus_hfi_write_register(device->hal_data->register_base_addr,
+	venus_hfi_write_register(device,
 			VIDC_CPU_CS_SCIACMDARG3, 1, 0);
 
 	while (!ctrl_status && count < max_tries) {
 		ctrl_status = venus_hfi_read_register(
-				device->hal_data->register_base_addr,
+				device,
 				VIDC_CPU_CS_SCIACMDARG0);
 		if ((ctrl_status & 0xFE) == 0x4) {
 			dprintk(VIDC_ERR, "invalid setting for UC_REGION\n");
@@ -903,7 +943,7 @@
 
 	reg_set = &device->res->reg_set;
 	for (i = 0; i < reg_set->count; i++) {
-		venus_hfi_write_register(device->hal_data->register_base_addr,
+		venus_hfi_write_register(device,
 				reg_set->reg_tbl[i].reg,
 				reg_set->reg_tbl[i].value, 0);
 	}
@@ -981,7 +1021,7 @@
 		goto err_core_init;
 	}
 	enable_irq(dev->hal_data->irq);
-	venus_hfi_write_register(dev->hal_data->register_base_addr,
+	venus_hfi_write_register(dev,
 		VIDC_CTRL_INIT, 0x1, 0);
 	rc = venus_hfi_core_start_cpu(dev);
 	if (rc) {
@@ -1008,6 +1048,7 @@
 static int venus_hfi_core_release(void *device)
 {
 	struct venus_hfi_device *dev;
+	int rc = 0;
 	if (device) {
 		dev = device;
 	} else {
@@ -1015,13 +1056,22 @@
 		return -ENODEV;
 	}
 	if (dev->hal_client) {
-		venus_hfi_write_register(dev->hal_data->register_base_addr,
+		mutex_lock(&dev->clock_lock);
+		rc = venus_hfi_clk_gating_off(device);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"%s : Clock enable failed\n", __func__);
+			mutex_unlock(&dev->clock_lock);
+			return -EIO;
+		}
+		venus_hfi_write_register(dev,
 				VIDC_CPU_CS_SCIACMDARG3, 0, 0);
 		if (!(dev->intr_status & VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK))
 			disable_irq_nosync(dev->hal_data->irq);
 		dev->intr_status = 0;
 		venus_hfi_interface_queues_release(dev);
 	}
+	mutex_unlock(&dev->clock_lock);
 	dprintk(VIDC_INFO, "HAL exited\n");
 	return 0;
 }
@@ -1055,16 +1105,26 @@
 static void venus_hfi_core_clear_interrupt(struct venus_hfi_device *device)
 {
 	u32 intr_status = 0;
+	int rc = 0;
 
 	if (!device->callback)
 		return;
-
+	mutex_lock(&device->clock_lock);
+	rc = venus_hfi_clk_gating_off(device);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"%s : Clock enable failed\n", __func__);
+		mutex_unlock(&device->clock_lock);
+		return;
+	}
 	intr_status = venus_hfi_read_register(
-			device->hal_data->register_base_addr,
+			device,
 			VIDC_WRAPPER_INTR_STATUS);
 
 	if ((intr_status & VIDC_WRAPPER_INTR_STATUS_A2H_BMSK) ||
-		(intr_status & VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK)) {
+		(intr_status & VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK) ||
+		(intr_status &
+			VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_IDLE_MSG_BMSK)) {
 		device->intr_status |= intr_status;
 		dprintk(VIDC_DBG, "INTERRUPT for device: 0x%x: "
 			"times: %d interrupt_status: %d",
@@ -1074,10 +1134,11 @@
 			"times: %d interrupt_status: %d",
 			(u32) device, ++device->spur_count, intr_status);
 	}
-	venus_hfi_write_register(device->hal_data->register_base_addr,
+	venus_hfi_write_register(device,
 			VIDC_CPU_CS_A2HSOFTINTCLR, 1, 0);
-	venus_hfi_write_register(device->hal_data->register_base_addr,
+	venus_hfi_write_register(device,
 			VIDC_WRAPPER_INTR_CLEAR, intr_status, 0);
+	mutex_unlock(&device->clock_lock);
 	dprintk(VIDC_DBG, "Cleared WRAPPER/A2H interrupt");
 }
 
@@ -1798,14 +1859,16 @@
 		return -ENODEV;
 	}
 	mutex_lock(&device->write_lock);
+	mutex_lock(&device->clock_lock);
 	rc = venus_hfi_is_cmd_pending(device);
 	ctrl_status = venus_hfi_read_register(
-		device->hal_data->register_base_addr,
+		device,
 		VIDC_CPU_CS_SCIACMDARG0);
 	if (((ctrl_status & VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_IDLE_MSG_BMSK)
 		!= 0) && !rc)
-		venus_hfi_clk_gating_on(device, VCODEC_CLK);
+		venus_hfi_clk_gating_on(device);
 	mutex_unlock(&device->write_lock);
+	mutex_unlock(&device->clock_lock);
 	return rc;
 }
 
@@ -1826,15 +1889,14 @@
 			rc = hfi_process_msg_packet(device->callback,
 				device->device_id,
 				(struct vidc_hal_msg_pkt_hdr *) packet);
-			if (rc == HFI_MSG_SYS_IDLE)
-				rc = venus_hfi_try_clk_gating(device);
-
 		}
 		while (!venus_hfi_iface_dbgq_read(device, packet)) {
 			struct hfi_msg_sys_debug_packet *pkt =
 				(struct hfi_msg_sys_debug_packet *) packet;
 			dprintk(VIDC_FW, "FW-SAYS: %s", pkt->rg_msg_data);
 		}
+		if (rc == HFI_MSG_SYS_IDLE)
+			rc = venus_hfi_try_clk_gating(device);
 	} else {
 		dprintk(VIDC_ERR, "SPURIOUS_INTERRUPT");
 	}
@@ -2015,12 +2077,23 @@
 		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
 		return;
 	}
-
+	if (device->clocks_enabled) {
+		for (i = VCODEC_CLK; i < VCODEC_MAX_CLKS; i++) {
+			cl = &device->resources.clock[i];
+			clk_disable(cl->clk);
+		}
+	} else {
+		for (i = device->clk_gating_level + 1;
+			i < VCODEC_MAX_CLKS; i++) {
+			cl = &device->resources.clock[i];
+			clk_disable(cl->clk);
+		}
+	}
 	for (i = VCODEC_CLK; i < VCODEC_MAX_CLKS; i++) {
 		if (i == VCODEC_OCMEM_CLK && !device->res->has_ocmem)
 			continue;
 		cl = &device->resources.clock[i];
-		clk_disable_unprepare(cl->clk);
+		clk_unprepare(cl->clk);
 	}
 	device->clocks_enabled = 0;
 }
@@ -2311,6 +2384,7 @@
 	struct vidc_resource_hdr rhdr;
 	struct venus_hfi_device *device = dev;
 	int rc = 0;
+
 	if (!device) {
 		dprintk(VIDC_ERR, "%s Invalid params, device:%p\n",
 			__func__, device);
@@ -2323,7 +2397,6 @@
 		rc = -EINVAL;
 		goto ocmem_unset_failed;
 	}
-
 	rhdr.resource_id = VIDC_RESOURCE_OCMEM;
 	rhdr.resource_handle = (u32) &device->resources.ocmem;
 	rc = venus_hfi_core_release_resource(device, &rhdr);
@@ -2625,7 +2698,8 @@
 			__func__, device);
 		return -EINVAL;
 	}
-
+	mutex_init(&device->clock_lock);
+	device->clk_gating_level = VCODEC_CLK;
 	rc = venus_hfi_iommu_attach(device);
 	if (rc) {
 		dprintk(VIDC_ERR, "Failed to attach iommu");
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.h b/drivers/media/platform/msm/vidc/venus_hfi.h
index 7a96ff4..197c754 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.h
+++ b/drivers/media/platform/msm/vidc/venus_hfi.h
@@ -176,8 +176,10 @@
 	u32 device_id;
 	u32 load;
 	u32 clocks_enabled;
+	enum vidc_clocks clk_gating_level;
 	struct mutex read_lock;
 	struct mutex write_lock;
+	struct mutex clock_lock;
 	msm_vidc_callback callback;
 	struct vidc_mem_addr iface_q_table;
 	struct vidc_mem_addr qdss;
diff --git a/drivers/misc/tspp.c b/drivers/misc/tspp.c
index 9598d45..9ef86a7 100644
--- a/drivers/misc/tspp.c
+++ b/drivers/misc/tspp.c
@@ -2582,28 +2582,27 @@
 
 		debugfs_create_u32(
 			"stat_rx_chunks",
-			S_IRUGO|S_IWUGO,
+			S_IRUGO | S_IWUSR | S_IWGRP,
 			tsif_device->dent_tsif,
 			&tsif_device->stat_rx);
 
 		debugfs_create_u32(
 			"stat_overflow",
-			S_IRUGO|S_IWUGO,
+			S_IRUGO | S_IWUSR | S_IWGRP,
 			tsif_device->dent_tsif,
 			&tsif_device->stat_overflow);
 
 		debugfs_create_u32(
 			"stat_lost_sync",
-			S_IRUGO|S_IWUGO,
+			S_IRUGO | S_IWUSR | S_IWGRP,
 			tsif_device->dent_tsif,
 			&tsif_device->stat_lost_sync);
 
 		debugfs_create_u32(
 			"stat_timeout",
-			S_IRUGO|S_IWUGO,
+			S_IRUGO | S_IWUSR | S_IWGRP,
 			tsif_device->dent_tsif,
 			&tsif_device->stat_timeout);
-
 	}
 }
 
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index bea8428..ae47975 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -820,7 +820,15 @@
 					context_info->is_done_rcv = false;
 					break; /* return err */
 				} else {
+					/*
+					 * We have stopped the ongoing request
+					 * and are sure that mmc_request_done()
+					 * is not going to get called. Update
+					 * stuff that we ought to do when the
+					 * request actually completes.
+					 */
 					mmc_update_clk_scaling(host);
+					mmc_host_clk_release(host);
 				}
 				err = host->areq->update_interrupted_req(
 						host->card, host->areq);
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index dc129f7..60e0640 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -1166,6 +1166,7 @@
 	if (!retries) {
 		printk(KERN_ERR "%s(%s): Unable to re-detect card (%d)\n",
 		       __func__, mmc_hostname(host), err);
+		err = _mmc_detect_card_removed(host);
 	}
 #else
 	err = _mmc_detect_card_removed(host);
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 2769709..5090eea 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -2253,7 +2253,6 @@
 				MMC_CAP2_DETECT_ON_ERR);
 	msm_host->mmc->caps2 |= MMC_CAP2_SANITIZE;
 	msm_host->mmc->caps2 |= MMC_CAP2_CACHE_CTRL;
-	msm_host->mmc->caps2 |= MMC_CAP2_INIT_BKOPS;
 	msm_host->mmc->caps2 |= MMC_CAP2_POWEROFF_NOTIFY;
 	msm_host->mmc->caps2 |= MMC_CAP2_CLK_SCALE;
 
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index 91aaf3c..c09373a 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -2514,6 +2514,65 @@
 	return last_soc;
 }
 
+void pm8921_bms_battery_removed(void)
+{
+	if (!the_chip) {
+		pr_err("called before initialization\n");
+		return;
+	}
+	pr_info("Battery Removed Cleaning up\n");
+
+	cancel_delayed_work_sync(&the_chip->calculate_soc_delayed_work);
+	calculated_soc = 0;
+	the_chip->start_percent = -EINVAL;
+	the_chip->end_percent = -EINVAL;
+	/* cleanup for charge time catchup */
+	the_chip->charge_time_us = 0;
+	the_chip->catch_up_time_us = 0;
+	/* cleanup for charge time adjusting */
+	the_chip->soc_at_cv = -EINVAL;
+	the_chip->soc_at_cv = -EINVAL;
+	the_chip->prev_chg_soc = -EINVAL;
+	the_chip->ibat_at_cv_ua = 0;
+	the_chip->prev_vbat_batt_terminal_uv = 0;
+	/* ocv cleanups */
+	the_chip->ocv_reading_at_100 = OCV_RAW_UNINITIALIZED;
+	the_chip->prev_last_good_ocv_raw = OCV_RAW_UNINITIALIZED;
+	the_chip->last_ocv_temp_decidegc = -EINVAL;
+
+	/* cleanup delta time */
+	the_chip->tm_sec = 0;
+
+	/* cc and avg current cleanups */
+	the_chip->prev_iavg_ua = 0;
+	the_chip->last_cc_uah = INT_MIN;
+
+	/* report SOC cleanups */
+	the_chip->t_soc_queried.tv_sec = 0;
+	the_chip->t_soc_queried.tv_nsec = 0;
+
+	last_soc = -EINVAL;
+	/* store invalid soc */
+	pm8xxx_writeb(the_chip->dev->parent, TEMP_SOC_STORAGE, 0);
+
+	/* UUC related data is left as is - use the same historical load avg */
+	update_power_supply(the_chip);
+}
+EXPORT_SYMBOL(pm8921_bms_battery_removed);
+
+void pm8921_bms_battery_inserted(void)
+{
+	if (!the_chip) {
+		pr_err("called before initialization\n");
+		return;
+	}
+
+	pr_info("Battery Inserted\n");
+	the_chip->last_ocv_uv = estimate_ocv(the_chip);
+	schedule_delayed_work(&the_chip->calculate_soc_delayed_work, 0);
+}
+EXPORT_SYMBOL(pm8921_bms_battery_inserted);
+
 void pm8921_bms_invalidate_shutdown_soc(void)
 {
 	int calculate_soc = 0;
@@ -3012,6 +3071,7 @@
 	STOP_OCV,
 	START_OCV,
 	SET_OCV,
+	BATT_PRESENT,
 };
 
 static int test_batt_temp = 5;
@@ -3255,6 +3315,8 @@
 				(void *)START_OCV, &calc_fops);
 	debugfs_create_file("set_ocv", 0644, chip->dent,
 				(void *)SET_OCV, &calc_fops);
+	debugfs_create_file("batt_present", 0644, chip->dent,
+				(void *)BATT_PRESENT, &calc_fops);
 
 	debugfs_create_file("simultaneous", 0644, chip->dent,
 			(void *)GET_VBAT_VSENSE_SIMULTANEOUS, &calc_fops);
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index 5136fdf..e9cf973 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -3181,6 +3181,7 @@
 static int ichg_threshold_ua = -400000;
 module_param(ichg_threshold_ua, int, 0644);
 
+#define MIN_DELTA_MV_TO_INCREASE_VDD_MAX	13
 #define PM8921_CHG_VDDMAX_RES_MV	10
 static void adjust_vdd_max_for_fastchg(struct pm8921_chg_chip *chip,
 						int vbat_batt_terminal_uv)
@@ -3212,6 +3213,14 @@
 
 	delta_mv =  chip->max_voltage_mv - vbat_batt_terminal_mv;
 
+	if (delta_mv > 0) /* meaning we want to increase the vddmax */ {
+		if (delta_mv < MIN_DELTA_MV_TO_INCREASE_VDD_MAX) {
+			pr_debug("vterm = %d is not low enough to inc vdd\n",
+							vbat_batt_terminal_mv);
+			return;
+		}
+	}
+
 	adj_vdd_max_mv = programmed_vdd_max + delta_mv;
 	pr_debug("vdd_max needs to be changed by %d mv from %d to %d\n",
 			delta_mv,
@@ -3223,8 +3232,8 @@
 		return;
 	}
 
-	adj_vdd_max_mv = DIV_ROUND_UP(adj_vdd_max_mv, PM8921_CHG_VDDMAX_RES_MV)
-					* PM8921_CHG_VDDMAX_RES_MV;
+	adj_vdd_max_mv = (adj_vdd_max_mv / PM8921_CHG_VDDMAX_RES_MV)
+						* PM8921_CHG_VDDMAX_RES_MV;
 
 	if (adj_vdd_max_mv > (chip->max_voltage_mv + vdd_max_increase_mv))
 		adj_vdd_max_mv = chip->max_voltage_mv + vdd_max_increase_mv;
@@ -3382,9 +3391,11 @@
 		else
 			vbat_intended = chip->max_voltage_mv;
 
-		if (vbat_batt_terminal_uv / 1000 < vbat_intended) {
-			pr_debug("terminal_uv:%d < vbat_intended:%d.\n",
+		if (vbat_batt_terminal_uv / 1000
+			< vbat_intended - MIN_DELTA_MV_TO_INCREASE_VDD_MAX) {
+			pr_debug("terminal_uv:%d < vbat_intended:%d-hyst:%d\n",
 							vbat_batt_terminal_uv,
+							vbat_intended,
 							vbat_intended);
 			return CHG_IN_PROGRESS;
 		}
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index cb5be3d..2765836 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -71,9 +71,9 @@
 #define BMS1_VBAT_AVG_DATA0		0x9E
 #define BMS1_VBAT_AVG_DATA1		0x9F
 /* Extra bms registers */
-#define BMS1_BMS_DATA_REG_0		0xB0
+#define SOC_STORAGE_REG			0xB0
 #define IAVG_STORAGE_REG		0xB1
-#define SOC_STORAGE_REG			0xB2
+#define BMS1_BMS_DATA_REG_2		0xB2
 #define BMS1_BMS_DATA_REG_3		0xB3
 /* IADC Channel Select */
 #define IADC1_BMS_ADC_CH_SEL_CTL	0x48
@@ -83,7 +83,7 @@
 #define IAVG_STEP_SIZE_MA		50
 #define IAVG_START			600
 #define IAVG_INVALID			0xFF
-#define SOC_ZERO			0xFF
+#define SOC_INVALID			0xFF
 
 #define IAVG_SAMPLES 16
 
@@ -184,7 +184,6 @@
 	unsigned int			vadc_v1250;
 
 	int				ibat_max_ua;
-	int				prev_iavg_ua;
 	int				prev_uuc_iavg_ma;
 	int				prev_pc_unusable;
 	int				ibat_at_cv_ua;
@@ -849,33 +848,27 @@
 	return rbatt_mohm;
 }
 
+#define IAVG_MINIMAL_TIME	2
 static void calculate_iavg(struct qpnp_bms_chip *chip, int cc_uah,
 				int *iavg_ua, int delta_time_s)
 {
 	int delta_cc_uah = 0;
 
-	/* if anything fails report the previous iavg_ua */
-	*iavg_ua = chip->prev_iavg_ua;
-
-	if (chip->last_cc_uah == INT_MIN) {
+	/*
+	 * use the battery current if called too quickly
+	 */
+	if (delta_time_s < IAVG_MINIMAL_TIME
+			|| chip->last_cc_uah == INT_MIN) {
 		get_battery_current(chip, iavg_ua);
 		goto out;
 	}
 
-	/* use the previous iavg if called within 15 seconds */
-	if (delta_time_s < 15) {
-		*iavg_ua = chip->prev_iavg_ua;
-		goto out;
-	}
-
 	delta_cc_uah = cc_uah - chip->last_cc_uah;
 
 	*iavg_ua = div_s64((s64)delta_cc_uah * 3600, delta_time_s);
 
 out:
 	pr_debug("delta_cc = %d iavg_ua = %d\n", delta_cc_uah, (int)*iavg_ua);
-	/* remember the iavg */
-	chip->prev_iavg_ua = *iavg_ua;
 
 	/* remember cc_uah */
 	chip->last_cc_uah = cc_uah;
@@ -1734,10 +1727,7 @@
 	rc = qpnp_write_wrapper(chip, &temp,
 			chip->base + IAVG_STORAGE_REG, 1);
 
-	if (soc == 0)
-		temp = SOC_ZERO;
-	else
-		temp = soc;
+	temp = soc;
 
 	/* don't store soc if temperature is below 5degC */
 	if (batt_temp > IGNORE_SOC_TEMP_DECIDEG)
@@ -2069,12 +2059,10 @@
 		} else {
 			chip->shutdown_soc = temp;
 
-			if (chip->shutdown_soc == 0) {
+			if (chip->shutdown_soc == SOC_INVALID) {
 				pr_debug("No shutdown soc available\n");
 				chip->shutdown_soc_invalid = true;
 				chip->shutdown_iavg_ma = 0;
-			} else if (chip->shutdown_soc == SOC_ZERO) {
-				chip->shutdown_soc = 0;
 			}
 		}
 	}
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 35d8df9..b479477 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -1025,13 +1025,15 @@
 
 	/* Only honour requests while USB is present */
 	if (qpnp_chg_is_usb_chg_plugged_in(chip)) {
+		chip->usb_psy->get_property(chip->usb_psy,
+			  POWER_SUPPLY_PROP_CURRENT_MAX, &ret);
 		if (ret.intval <= 2 && !chip->use_default_batt_values &&
 						get_prop_batt_present(chip)) {
-			qpnp_chg_usb_suspend_enable(chip, 1);
 			qpnp_chg_iusbmax_set(chip, QPNP_CHG_I_MAX_MIN_100);
+			qpnp_chg_usb_suspend_enable(chip, 1);
 		} else {
-			qpnp_chg_iusbmax_set(chip, ret.intval / 1000);
 			qpnp_chg_usb_suspend_enable(chip, 0);
+			qpnp_chg_iusbmax_set(chip, ret.intval / 1000);
 		}
 	}
 
diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c
index 9b2f554..4251968 100644
--- a/drivers/staging/android/lowmemorykiller.c
+++ b/drivers/staging/android/lowmemorykiller.c
@@ -39,6 +39,13 @@
 #include <linux/notifier.h>
 #include <linux/mutex.h>
 #include <linux/delay.h>
+#include <linux/swap.h>
+
+#ifdef CONFIG_HIGHMEM
+#define _ZONE ZONE_HIGHMEM
+#else
+#define _ZONE ZONE_NORMAL
+#endif
 
 static uint32_t lowmem_debug_level = 1;
 static int lowmem_adj[6] = {
@@ -55,6 +62,7 @@
 	16 * 1024,	/* 64MB */
 };
 static int lowmem_minfree_size = 4;
+static int lmk_fast_run = 1;
 
 static unsigned long lowmem_deathpending_timeout;
 
@@ -82,6 +90,141 @@
 
 static DEFINE_MUTEX(scan_mutex);
 
+int can_use_cma_pages(gfp_t gfp_mask)
+{
+	int can_use = 0;
+	int mtype = allocflags_to_migratetype(gfp_mask);
+	int i = 0;
+	int *mtype_fallbacks = get_migratetype_fallbacks(mtype);
+
+	if (is_migrate_cma(mtype)) {
+		can_use = 1;
+	} else {
+		for (i = 0;; i++) {
+			int fallbacktype = mtype_fallbacks[i];
+
+			if (is_migrate_cma(fallbacktype)) {
+				can_use = 1;
+				break;
+			}
+
+			if (fallbacktype == MIGRATE_RESERVE)
+				break;
+		}
+	}
+	return can_use;
+}
+
+void tune_lmk_zone_param(struct zonelist *zonelist, int classzone_idx,
+					int *other_free, int *other_file,
+					int use_cma_pages)
+{
+	struct zone *zone;
+	struct zoneref *zoneref;
+	int zone_idx;
+
+	for_each_zone_zonelist(zone, zoneref, zonelist, MAX_NR_ZONES) {
+		zone_idx = zonelist_zone_idx(zoneref);
+		if (zone_idx == ZONE_MOVABLE) {
+			if (!use_cma_pages)
+				*other_free -=
+				    zone_page_state(zone, NR_FREE_CMA_PAGES);
+			continue;
+		}
+
+		if (zone_idx > classzone_idx) {
+			if (other_free != NULL)
+				*other_free -= zone_page_state(zone,
+							       NR_FREE_PAGES);
+			if (other_file != NULL)
+				*other_file -= zone_page_state(zone,
+							       NR_FILE_PAGES)
+					      - zone_page_state(zone, NR_SHMEM);
+		} else if (zone_idx < classzone_idx) {
+			if (zone_watermark_ok(zone, 0, 0, classzone_idx, 0)) {
+				if (!use_cma_pages) {
+					*other_free -= min(
+					  zone->lowmem_reserve[classzone_idx] +
+					  zone_page_state(
+					    zone, NR_FREE_CMA_PAGES),
+					  zone_page_state(
+					    zone, NR_FREE_PAGES));
+				} else {
+					*other_free -=
+					  zone->lowmem_reserve[classzone_idx];
+				}
+			} else {
+				*other_free -=
+					   zone_page_state(zone, NR_FREE_PAGES);
+			}
+		}
+	}
+}
+
+void tune_lmk_param(int *other_free, int *other_file, struct shrink_control *sc)
+{
+	gfp_t gfp_mask;
+	struct zone *preferred_zone;
+	struct zonelist *zonelist;
+	enum zone_type high_zoneidx, classzone_idx;
+	unsigned long balance_gap;
+	int use_cma_pages;
+
+	gfp_mask = sc->gfp_mask;
+	zonelist = node_zonelist(0, gfp_mask);
+	high_zoneidx = gfp_zone(gfp_mask);
+	first_zones_zonelist(zonelist, high_zoneidx, NULL, &preferred_zone);
+	classzone_idx = zone_idx(preferred_zone);
+	use_cma_pages = can_use_cma_pages(gfp_mask);
+
+	balance_gap = min(low_wmark_pages(preferred_zone),
+			  (preferred_zone->present_pages +
+			   KSWAPD_ZONE_BALANCE_GAP_RATIO-1) /
+			   KSWAPD_ZONE_BALANCE_GAP_RATIO);
+
+	if (likely(current_is_kswapd() && zone_watermark_ok(preferred_zone, 0,
+			  high_wmark_pages(preferred_zone) + SWAP_CLUSTER_MAX +
+			  balance_gap, 0, 0))) {
+		if (lmk_fast_run)
+			tune_lmk_zone_param(zonelist, classzone_idx, other_free,
+				       other_file, use_cma_pages);
+		else
+			tune_lmk_zone_param(zonelist, classzone_idx, other_free,
+				       NULL, use_cma_pages);
+
+		if (zone_watermark_ok(preferred_zone, 0, 0, _ZONE, 0)) {
+			if (!use_cma_pages) {
+				*other_free -= min(
+				  preferred_zone->lowmem_reserve[_ZONE]
+				  + zone_page_state(
+				    preferred_zone, NR_FREE_CMA_PAGES),
+				  zone_page_state(
+				    preferred_zone, NR_FREE_PAGES));
+			} else {
+				*other_free -=
+				  preferred_zone->lowmem_reserve[_ZONE];
+			}
+		} else {
+			*other_free -= zone_page_state(preferred_zone,
+						      NR_FREE_PAGES);
+		}
+
+		lowmem_print(4, "lowmem_shrink of kswapd tunning for highmem "
+			     "ofree %d, %d\n", *other_free, *other_file);
+	} else {
+		tune_lmk_zone_param(zonelist, classzone_idx, other_free,
+			       other_file, use_cma_pages);
+
+		if (!use_cma_pages) {
+			*other_free -=
+			  zone_page_state(preferred_zone, NR_FREE_CMA_PAGES);
+		}
+
+		lowmem_print(4, "lowmem_shrink tunning for others ofree %d, "
+			     "%d\n", *other_free, *other_file);
+	}
+}
+
 static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc)
 {
 	struct task_struct *tsk;
@@ -106,6 +249,8 @@
 	other_file = global_page_state(NR_FILE_PAGES) -
 						global_page_state(NR_SHMEM);
 
+	tune_lmk_param(&other_free, &other_file, sc);
+
 	if (lowmem_adj_size < array_size)
 		array_size = lowmem_adj_size;
 	if (lowmem_minfree_size < array_size)
@@ -311,6 +456,7 @@
 module_param_array_named(minfree, lowmem_minfree, uint, &lowmem_minfree_size,
 			 S_IRUGO | S_IWUSR);
 module_param_named(debug_level, lowmem_debug_level, uint, S_IRUGO | S_IWUSR);
+module_param_named(lmk_fast_run, lmk_fast_run, int, S_IRUGO | S_IWUSR);
 
 module_init(lowmem_init);
 module_exit(lowmem_exit);
diff --git a/drivers/thermal/msm8974-tsens.c b/drivers/thermal/msm8974-tsens.c
index 7d3664a..f7e5eee 100644
--- a/drivers/thermal/msm8974-tsens.c
+++ b/drivers/thermal/msm8974-tsens.c
@@ -74,6 +74,9 @@
 #define TSENS_EEPROM_8X26_2(n)		((n) + 0x444)
 #define TSENS_8X26_MAIN_CALIB_ADDR_RANGE	4
 
+#define TSENS_EEPROM_8X10_1(n)		((n) + 0x1a4)
+#define TSENS_EEPROM_8X10_1_OFFSET	8
+
 /* TSENS calibration Mask data */
 #define TSENS_BASE1_MASK		0xff
 #define TSENS0_POINT1_MASK		0x3f00
@@ -191,6 +194,19 @@
 #define TSENS5_8X26_POINT2_SHIFT	26
 #define TSENS6_8X26_POINT2_SHIFT	17
 
+#define TSENS_8X10_CAL_SEL_SHIFT	28
+#define TSENS_8X10_BASE1_SHIFT		8
+#define TSENS0_8X10_POINT1_SHIFT	16
+#define TSENS0_8X10_POINT2_SHIFT	22
+#define TSENS1_8X10_POINT2_SHIFT	6
+#define TSENS_8X10_BASE0_MASK		0xf
+#define TSENS_8X10_BASE1_MASK		0xf0
+#define TSENS0_8X10_POINT1_MASK		0x3f0000
+#define TSENS0_8X10_POINT2_MASK		0xfc00000
+#define TSENS_8X10_TSENS_CAL_SEL	0x70000000
+#define TSENS1_8X10_POINT1_MASK		0x3f
+#define TSENS1_8X10_POINT2_MASK		0xfc0
+
 #define TSENS_BIT_APPEND		0x3
 #define TSENS_CAL_DEGC_POINT1		30
 #define TSENS_CAL_DEGC_POINT2		120
@@ -599,6 +615,98 @@
 		TSENS_UPPER_LOWER_INTERRUPT_CTRL(tmdev->tsens_addr));
 }
 
+static int tsens_calib_8x10_sensors(void)
+{
+	int i, tsens_base0_data = 0, tsens0_point1 = 0, tsens1_point1 = 0;
+	int tsens0_point2 = 0, tsens1_point2 = 0;
+	int tsens_base1_data = 0, tsens_calibration_mode = 0;
+	uint32_t calib_data[2];
+	uint32_t calib_tsens_point1_data[2], calib_tsens_point2_data[2];
+
+	if (tmdev->calibration_less_mode)
+		goto calibration_less_mode;
+
+	calib_data[0] = readl_relaxed(
+			TSENS_EEPROM_8X10_1(tmdev->tsens_calib_addr));
+	calib_data[1] = readl_relaxed(
+		(TSENS_EEPROM_8X10_1(tmdev->tsens_calib_addr) +
+					TSENS_EEPROM_8X10_1_OFFSET));
+
+	tsens_calibration_mode = (calib_data[0] & TSENS_8X10_TSENS_CAL_SEL)
+			>> TSENS_8X10_CAL_SEL_SHIFT;
+
+	if ((tsens_calibration_mode == TSENS_TWO_POINT_CALIB) ||
+		(tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2)) {
+		tsens_base0_data = (calib_data[0] & TSENS_8X10_BASE0_MASK);
+		tsens0_point1 = (calib_data[0] & TSENS0_8X10_POINT1_MASK) >>
+				TSENS0_8X10_POINT1_SHIFT;
+		tsens1_point1 = calib_data[1] & TSENS1_8X10_POINT1_MASK;
+	} else
+		goto calibration_less_mode;
+
+	if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
+		tsens_base1_data = (calib_data[0] & TSENS_8X10_BASE1_MASK) >>
+				TSENS_8X10_BASE1_SHIFT;
+		tsens0_point2 = (calib_data[0] & TSENS0_8X10_POINT2_MASK) >>
+				TSENS0_8X10_POINT2_SHIFT;
+		tsens1_point2 = (calib_data[1] & TSENS1_8X10_POINT2_MASK) >>
+				TSENS1_8X10_POINT2_SHIFT;
+	}
+
+	if (tsens_calibration_mode == 0) {
+calibration_less_mode:
+		pr_debug("TSENS is calibrationless mode\n");
+		for (i = 0; i < tmdev->tsens_num_sensor; i++)
+			calib_tsens_point2_data[i] = 780;
+		calib_tsens_point1_data[0] = 595;
+		calib_tsens_point1_data[1] = 629;
+		goto compute_intercept_slope;
+	}
+
+	if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2) ||
+			(tsens_calibration_mode == TSENS_TWO_POINT_CALIB)) {
+		calib_tsens_point1_data[0] =
+			((((tsens_base0_data) + tsens0_point1) << 2) |
+						TSENS_BIT_APPEND);
+		calib_tsens_point1_data[1] =
+			((((tsens_base0_data) + tsens1_point1) << 2) |
+						TSENS_BIT_APPEND);
+	}
+
+	if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
+		pr_debug("two point calibration calculation\n");
+		calib_tsens_point2_data[0] =
+			(((tsens_base1_data + tsens0_point2) << 2) |
+					TSENS_BIT_APPEND);
+		calib_tsens_point2_data[1] =
+			(((tsens_base1_data + tsens1_point2) << 2) |
+					TSENS_BIT_APPEND);
+	}
+
+compute_intercept_slope:
+	for (i = 0; i < tmdev->tsens_num_sensor; i++) {
+		int32_t num = 0, den = 0;
+		tmdev->sensor[i].calib_data_point2 = calib_tsens_point2_data[i];
+		tmdev->sensor[i].calib_data_point1 = calib_tsens_point1_data[i];
+		if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
+			/* slope (m) = adc_code2 - adc_code1 (y2 - y1)/
+				temp_120_degc - temp_30_degc (x2 - x1) */
+			num = tmdev->sensor[i].calib_data_point2 -
+					tmdev->sensor[i].calib_data_point1;
+			num *= tmdev->tsens_factor;
+			den = TSENS_CAL_DEGC_POINT2 - TSENS_CAL_DEGC_POINT1;
+			tmdev->sensor[i].slope_mul_tsens_factor = num/den;
+		}
+		tmdev->sensor[i].offset = (tmdev->sensor[i].calib_data_point1 *
+			tmdev->tsens_factor) - (TSENS_CAL_DEGC_POINT1 *
+				tmdev->sensor[i].slope_mul_tsens_factor);
+		INIT_WORK(&tmdev->sensor[i].work, notify_uspace_tsens_fn);
+		tmdev->prev_reading_avail = false;
+	}
+
+	return 0;
+}
+
 static int tsens_calib_8x26_sensors(void)
 {
 	int i, tsens_base0_data = 0, tsens0_point1 = 0, tsens1_point1 = 0;
@@ -627,7 +735,6 @@
 
 	if ((tsens_calibration_mode == TSENS_TWO_POINT_CALIB) ||
 		(tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2)) {
-		pr_debug("backup one point calibrationless mode\n");
 		tsens_base0_data = (calib_data[0] & TSENS_8X26_BASE0_MASK)
 				>> TSENS_8X26_BASE0_SHIFT;
 		tsens0_point1 = (calib_data[0] & TSENS0_8X26_POINT1_MASK) >>
@@ -647,7 +754,6 @@
 		goto calibration_less_mode;
 
 	if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
-		pr_debug("backup two point calibrationless mode\n");
 		tsens_base1_data = (calib_data[3] & TSENS_8X26_BASE1_MASK);
 		tsens0_point2 = (calib_data[3] & TSENS0_8X26_POINT2_MASK) >>
 				TSENS0_8X26_POINT2_SHIFT;
@@ -670,10 +776,10 @@
 		pr_debug("TSENS is calibrationless mode\n");
 		for (i = 0; i < tmdev->tsens_num_sensor; i++)
 			calib_tsens_point2_data[i] = 780;
-		calib_tsens_point1_data[0] = 502;
-		calib_tsens_point1_data[1] = 509;
-		calib_tsens_point1_data[2] = 503;
-		calib_tsens_point1_data[3] = 509;
+		calib_tsens_point1_data[0] = 595;
+		calib_tsens_point1_data[1] = 625;
+		calib_tsens_point1_data[2] = 553;
+		calib_tsens_point1_data[3] = 578;
 		calib_tsens_point1_data[4] = 505;
 		calib_tsens_point1_data[5] = 509;
 		calib_tsens_point1_data[6] = 507;
@@ -682,7 +788,6 @@
 
 	if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2) ||
 			(tsens_calibration_mode == TSENS_TWO_POINT_CALIB)) {
-		pr_debug("one and two point calibration calculation\n");
 		calib_tsens_point1_data[0] =
 			((((tsens_base0_data) + tsens0_point1) << 2) |
 						TSENS_BIT_APPEND);
@@ -800,7 +905,6 @@
 				TSENS_TWO_POINT_CALIB) ||
 				(tsens_calibration_mode ==
 				TSENS_ONE_POINT_CALIB_OPTION_2)) {
-			pr_debug("backup one point calibrationless mode\n");
 			tsens_base1_data = (calib_data_backup[0] &
 						TSENS_BASE1_MASK);
 			tsens0_point1 = (calib_data_backup[0] &
@@ -833,7 +937,6 @@
 			goto calibration_less_mode;
 
 		if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
-			pr_debug("backup two point calibrationless mode\n");
 			tsens_base2_data = (calib_data_backup[2] &
 				TSENS_BASE2_BACKUP_MASK) >>
 				TSENS_POINT2_BASE_BACKUP_SHIFT;
@@ -879,7 +982,6 @@
 			(tsens_calibration_mode ==
 					TSENS_ONE_POINT_CALIB_OPTION_2) ||
 			(tsens_calibration_mode == TSENS_TWO_POINT_CALIB)) {
-			pr_debug("TSENS is one point calibrationless mode\n");
 			tsens_base1_data = (calib_data[0] & TSENS_BASE1_MASK);
 			tsens0_point1 = (calib_data[0] & TSENS0_POINT1_MASK) >>
 							TSENS0_POINT1_SHIFT;
@@ -905,7 +1007,6 @@
 			goto calibration_less_mode;
 
 		if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
-			pr_debug("TSENS is two point calibrationless mode\n");
 			tsens_base2_data = (calib_data[2] & TSENS_BASE2_MASK) >>
 						TSENS_POINT2_BASE_SHIFT;
 			tsens0_point2 = (calib_data[2] & TSENS0_POINT2_MASK) >>
@@ -951,7 +1052,6 @@
 	}
 
 	if (tsens_calibration_mode == TSENS_ONE_POINT_CALIB) {
-		pr_debug("old one point calibration calculation\n");
 		calib_tsens_point1_data[0] =
 			(((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
 							+ tsens0_point1;
@@ -989,7 +1089,6 @@
 
 	if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2) ||
 			(tsens_calibration_mode == TSENS_TWO_POINT_CALIB)) {
-		pr_debug("one and two point calibration calculation\n");
 		calib_tsens_point1_data[0] =
 			((((tsens_base1_data) + tsens0_point1) << 2) |
 						TSENS_BIT_APPEND);
@@ -1097,6 +1196,8 @@
 		rc = tsens_calib_8974_sensors();
 	else if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_8X26)
 		rc = tsens_calib_8x26_sensors();
+	else if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_8X10)
+		rc = tsens_calib_8x10_sensors();
 	else
 		rc = -ENODEV;
 
@@ -1163,7 +1264,7 @@
 				"qcom,calibration-less-mode");
 	tmdev->calib_mode = calib_type;
 	tmdev->tsens_local_init = of_property_read_bool(of_node,
-				"qcom,tsens_local_init");
+				"qcom,tsens-local-init");
 
 	tmdev->tsens_irq = platform_get_irq(pdev, 0);
 	if (tmdev->tsens_irq < 0) {
diff --git a/drivers/thermal/qpnp-adc-tm.c b/drivers/thermal/qpnp-adc-tm.c
index c02db14..e7d2e0f 100644
--- a/drivers/thermal/qpnp-adc-tm.c
+++ b/drivers/thermal/qpnp-adc-tm.c
@@ -35,7 +35,7 @@
 #include <linux/platform_device.h>
 
 /* QPNP VADC TM register definition */
-#define QPNP_REVISION3					0x3
+#define QPNP_REVISION3					0x2
 #define QPNP_REVISION_EIGHT_CHANNEL_SUPPORT		2
 #define QPNP_STATUS1					0x8
 #define QPNP_STATUS1_OP_MODE				4
@@ -544,7 +544,7 @@
 			i++;
 	}
 
-	if ((i == adc_tm->max_channels_available) && (!chan_found)) {
+	if (!chan_found) {
 		pr_err("Channel not found\n");
 		return -EINVAL;
 	}
@@ -1292,7 +1292,8 @@
 {
 	struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
 	uint32_t channel, dt_index = 0, scale_type = 0;
-	int rc = 0;
+	int rc = 0, i = 0;
+	bool chan_found = false;
 
 	if (!adc_tm || !adc_tm->adc_tm_initialized)
 		return -ENODEV;
@@ -1305,11 +1306,17 @@
 	mutex_lock(&adc_tm->adc->adc_lock);
 
 	channel = param->channel;
-	while ((adc_tm->adc->adc_channels[dt_index].channel_num
-		!= channel) && (dt_index < adc_tm->max_channels_available))
-		dt_index++;
+	while (i < adc_tm->max_channels_available) {
+		if (adc_tm->adc->adc_channels[i].channel_num ==
+							channel) {
+			dt_index = i;
+			chan_found = true;
+			i++;
+		} else
+			i++;
+	}
 
-	if (dt_index >= adc_tm->max_channels_available) {
+	if (!chan_found)  {
 		pr_err("not a valid ADC_TM channel\n");
 		rc = -EINVAL;
 		goto fail_unlock;
@@ -1330,11 +1337,11 @@
 					channel, scale_type, dt_index);
 	adc_tm->adc->amux_prop->amux_channel = channel;
 	adc_tm->adc->amux_prop->decimation =
-			adc_tm->adc->adc_channels[channel].adc_decimation;
+			adc_tm->adc->adc_channels[dt_index].adc_decimation;
 	adc_tm->adc->amux_prop->hw_settle_time =
-			adc_tm->adc->adc_channels[channel].hw_settle_time;
+			adc_tm->adc->adc_channels[dt_index].hw_settle_time;
 	adc_tm->adc->amux_prop->fast_avg_setup =
-			adc_tm->adc->adc_channels[channel].fast_avg_setup;
+			adc_tm->adc->adc_channels[dt_index].fast_avg_setup;
 	adc_tm->adc->amux_prop->mode_sel =
 		ADC_OP_MEASUREMENT_INTERVAL << QPNP_OP_MODE_SHIFT;
 	adc_tm->adc->amux_prop->chan_prop->meas_interval1 =
diff --git a/drivers/usb/gadget/u_bam.c b/drivers/usb/gadget/u_bam.c
index 3c3fbca..67c9a1a 100644
--- a/drivers/usb/gadget/u_bam.c
+++ b/drivers/usb/gadget/u_bam.c
@@ -363,10 +363,13 @@
 	switch (status) {
 	case 0:
 		/* successful completion */
+		break;
 	case -ECONNRESET:
 	case -ESHUTDOWN:
 		/* connection gone */
-		break;
+		dev_kfree_skb_any(skb);
+		usb_ep_free_request(ep, req);
+		return;
 	default:
 		pr_err("%s: data tx ep error %d\n",
 				__func__, status);
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 4e74858..ed730b3 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -45,11 +45,8 @@
 
 #include <mach/board.h>
 #include <mach/memory.h>
-#include <mach/msm_memtypes.h>
-#include <mach/iommu_domains.h>
 
 #include "mdss_fb.h"
-#include "mdss_mdp.h"
 
 #ifdef CONFIG_FB_MSM_TRIPLE_BUFFER
 #define MDSS_FB_NUM 3
@@ -68,6 +65,8 @@
 	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff
 };
 
+static struct msm_mdp_interface *mdp_instance;
+
 static int mdss_fb_register(struct msm_fb_data_type *mfd);
 static int mdss_fb_open(struct fb_info *info, int user);
 static int mdss_fb_release(struct fb_info *info, int user);
@@ -261,6 +260,7 @@
 	mfd->pdev = pdev;
 	if (pdata->next)
 		mfd->split_display = true;
+	mfd->mdp = *mdp_instance;
 
 	mutex_init(&mfd->lock);
 
@@ -272,6 +272,14 @@
 	if (rc)
 		return rc;
 
+	if (mfd->mdp.init_fnc) {
+		rc = mfd->mdp.init_fnc(mfd);
+		if (rc) {
+			pr_err("init_fnc failed\n");
+			return rc;
+		}
+	}
+
 	rc = pm_runtime_set_active(mfd->fbi->dev);
 	if (rc < 0)
 		pr_err("pm_runtime: fail to set active.\n");
@@ -301,11 +309,7 @@
 		}
 	}
 
-	rc = mdss_mdp_overlay_init(mfd);
-	if (rc)
-		pr_err("unable to init overlay\n");
-
-	return 0;
+	return rc;
 }
 
 static int mdss_fb_remove(struct platform_device *pdev)
@@ -503,24 +507,6 @@
 static int unset_bl_level, bl_updated;
 static int bl_level_old;
 
-static int mdss_bl_scale_config(struct msm_fb_data_type *mfd,
-						struct mdp_bl_scale_data *data)
-{
-	int ret = 0;
-	int curr_bl;
-	mutex_lock(&mfd->lock);
-	curr_bl = mfd->bl_level;
-	mfd->bl_scale = data->scale;
-	mfd->bl_min_lvl = data->min_lvl;
-	pr_debug("update scale = %d, min_lvl = %d\n", mfd->bl_scale,
-							mfd->bl_min_lvl);
-
-	/* update current backlight to use new scaling*/
-	mdss_fb_set_backlight(mfd, curr_bl);
-	mutex_unlock(&mfd->lock);
-	return ret;
-}
-
 static void mdss_fb_scale_bl(struct msm_fb_data_type *mfd, u32 *bl_lvl)
 {
 	u32 temp = *bl_lvl;
@@ -601,9 +587,8 @@
 
 	switch (blank_mode) {
 	case FB_BLANK_UNBLANK:
-		if (!mfd->panel_power_on) {
-			msleep(20);
-			ret = mfd->on_fnc(mfd);
+		if (!mfd->panel_power_on && mfd->mdp.on_fnc) {
+			ret = mfd->mdp.on_fnc(mfd);
 			if (ret == 0)
 				mfd->panel_power_on = true;
 		}
@@ -614,7 +599,7 @@
 	case FB_BLANK_NORMAL:
 	case FB_BLANK_POWERDOWN:
 	default:
-		if (mfd->panel_power_on) {
+		if (mfd->panel_power_on && mfd->mdp.off_fnc) {
 			int curr_pwr_state;
 
 			del_timer(&mfd->no_update.timer);
@@ -625,8 +610,7 @@
 			mfd->panel_power_on = false;
 			bl_updated = 0;
 
-			msleep(20);
-			ret = mfd->off_fnc(mfd);
+			ret = mfd->mdp.off_fnc(mfd);
 			if (ret)
 				mfd->panel_power_on = curr_pwr_state;
 			else
@@ -731,28 +715,11 @@
 
 static int mdss_fb_alloc_fbmem(struct msm_fb_data_type *mfd)
 {
-	void *virt = NULL;
-	unsigned long phys = 0;
-	size_t size;
-	u32 yres = mfd->fbi->var.yres_virtual;
-
-	size = PAGE_ALIGN(mfd->fbi->fix.line_length * yres);
-
-	if (mfd->index == 0) {
-		if (mdss_mdp_alloc_fb_mem(mfd, size, (u32 *)&phys, &virt))
-			return  -ENOMEM;
-		pr_info("allocating %u bytes at %p (%lx phys) for fb %d\n",
-			size, virt, phys, mfd->index);
-	} else {
-		pr_debug("no memory allocated for fb%d\n", mfd->index);
-		size = 0;
+	if (!mfd->mdp.fb_mem_alloc_fnc) {
+		pr_err("no fb memory allocator function defined\n");
+		return -ENOMEM;
 	}
-
-	mfd->fbi->screen_base = virt;
-	mfd->fbi->fix.smem_start = phys;
-	mfd->fbi->fix.smem_len = size;
-
-	return 0;
+	return mfd->mdp.fb_mem_alloc_fnc(mfd);
 }
 
 static int mdss_fb_register(struct msm_fb_data_type *mfd)
@@ -899,7 +866,11 @@
 		var->xres *= 2;
 
 	fix->type = panel_info->is_3d_panel;
-	fix->line_length = mdss_mdp_fb_stride(mfd->index, var->xres, bpp);
+	if (mfd->mdp.fb_stride)
+		fix->line_length = mfd->mdp.fb_stride(mfd->index, var->xres,
+							bpp);
+	else
+		fix->line_length = var->xres * bpp;
 
 	var->yres = panel_info->yres;
 	var->xres_virtual = var->xres;
@@ -949,15 +920,13 @@
 		pr_err("error: not enough memory!\n");
 		return -ENOMEM;
 	}
-	if (mfd->lut_update) {
-		ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
-		if (ret)
-			pr_err("fb_alloc_cmap() failed!\n");
-	}
+
+	ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
+	if (ret)
+		pr_err("fb_alloc_cmap() failed!\n");
 
 	if (register_framebuffer(fbi) < 0) {
-		if (mfd->lut_update)
-			fb_dealloc_cmap(&fbi->cmap);
+		fb_dealloc_cmap(&fbi->cmap);
 
 		mfd->op_enable = false;
 		return -EPERM;
@@ -1200,8 +1169,8 @@
 		(var->yoffset / info->fix.ypanstep) * info->fix.ypanstep;
 
 	mdss_fb_wait_for_fence(mfd);
-	if (mfd->dma_fnc)
-		mfd->dma_fnc(mfd);
+	if (mfd->mdp.dma_fnc)
+		mfd->mdp.dma_fnc(mfd);
 	else
 		pr_warn("dma function not set for panel type=%d\n",
 				mfd->panel.type);
@@ -1238,7 +1207,8 @@
 	if (fb_backup->disp_commit.flags &
 		MDP_DISPLAY_COMMIT_OVERLAY) {
 		mdss_fb_wait_for_fence(mfd);
-		mdss_mdp_overlay_kickoff(mfd->ctl);
+		if (mfd->mdp.kickoff_fnc)
+			mfd->mdp.kickoff_fnc(mfd);
 		mdss_fb_signal_timeline(mfd);
 	} else {
 		var = &fb_backup->disp_commit.var;
@@ -1403,8 +1373,14 @@
 		return -EINVAL;
 	}
 
-	mfd->fbi->fix.line_length = mdss_mdp_fb_stride(mfd->index, var->xres,
+
+	if (mfd->mdp.fb_stride)
+		mfd->fbi->fix.line_length = mfd->mdp.fb_stride(mfd->index,
+						var->xres,
 						var->bits_per_pixel / 8);
+	else
+		mfd->fbi->fix.line_length = var->xres * var->bits_per_pixel / 8;
+
 
 	if (mfd->panel_reconfig || (mfd->fb_imgType != old_imgType)) {
 		mdss_fb_blank_sub(FB_BLANK_POWERDOWN, info, mfd->op_enable);
@@ -1422,14 +1398,14 @@
 	struct fb_cursor cursor;
 	int ret;
 
-	if (!mfd->cursor_update)
+	if (!mfd->mdp.cursor_update)
 		return -ENODEV;
 
 	ret = copy_from_user(&cursor, p, sizeof(cursor));
 	if (ret)
 		return ret;
 
-	return mfd->cursor_update(mfd, &cursor);
+	return mfd->mdp.cursor_update(mfd, &cursor);
 }
 
 static int mdss_fb_set_lut(struct fb_info *info, void __user *p)
@@ -1438,86 +1414,17 @@
 	struct fb_cmap cmap;
 	int ret;
 
-	if (!mfd->lut_update)
+	if (!mfd->mdp.lut_update)
 		return -ENODEV;
 
 	ret = copy_from_user(&cmap, p, sizeof(cmap));
 	if (ret)
 		return ret;
 
-	mfd->lut_update(mfd, &cmap);
+	mfd->mdp.lut_update(mfd, &cmap);
 	return 0;
 }
 
-static int mdss_fb_handle_pp_ioctl(struct msm_fb_data_type *mfd,
-							void __user *argp)
-{
-	int ret;
-	struct msmfb_mdp_pp mdp_pp;
-	u32 copyback = 0;
-
-	ret = copy_from_user(&mdp_pp, argp, sizeof(mdp_pp));
-	if (ret)
-		return ret;
-
-	switch (mdp_pp.op) {
-	case mdp_op_pa_cfg:
-		ret = mdss_mdp_pa_config(mfd->ctl, &mdp_pp.data.pa_cfg_data,
-				&copyback);
-		break;
-
-	case mdp_op_pcc_cfg:
-		ret = mdss_mdp_pcc_config(mfd->ctl, &mdp_pp.data.pcc_cfg_data,
-			   &copyback);
-		break;
-
-	case mdp_op_lut_cfg:
-		switch (mdp_pp.data.lut_cfg_data.lut_type) {
-		case mdp_lut_igc:
-			ret = mdss_mdp_igc_lut_config(mfd->ctl,
-					(struct mdp_igc_lut_data *)
-					&mdp_pp.data.lut_cfg_data.data,
-					&copyback);
-			break;
-
-		case mdp_lut_pgc:
-			ret = mdss_mdp_argc_config(mfd->ctl,
-				&mdp_pp.data.lut_cfg_data.data.pgc_lut_data,
-				&copyback);
-			break;
-
-		case mdp_lut_hist:
-			ret = mdss_mdp_hist_lut_config(mfd->ctl,
-				(struct mdp_hist_lut_data *)
-				&mdp_pp.data.lut_cfg_data.data, &copyback);
-			break;
-
-		default:
-			ret = -ENOTSUPP;
-			break;
-		}
-		break;
-	case mdp_op_dither_cfg:
-		ret = mdss_mdp_dither_config(mfd->ctl,
-				&mdp_pp.data.dither_cfg_data, &copyback);
-		break;
-	case mdp_op_gamut_cfg:
-		ret = mdss_mdp_gamut_config(mfd->ctl,
-					&mdp_pp.data.gamut_cfg_data, &copyback);
-		break;
-	case mdp_bl_scale_cfg:
-		ret = mdss_bl_scale_config(mfd, (struct mdp_bl_scale_data *)
-						&mdp_pp.data.bl_scale_data);
-		break;
-	default:
-		pr_err("Unsupported request to MDP_PP IOCTL.\n");
-		ret = -EINVAL;
-		break;
-	}
-	if ((ret == 0) && copyback)
-		ret = copy_to_user(argp, &mdp_pp, sizeof(struct msmfb_mdp_pp));
-	return ret;
-}
 static int mdss_fb_handle_buf_sync_ioctl(struct msm_fb_data_type *mfd,
 						struct mdp_buf_sync *buf_sync)
 {
@@ -1618,74 +1525,15 @@
 	return ret;
 }
 
-static int mdss_fb_set_metadata(struct msm_fb_data_type *mfd,
-				struct msmfb_metadata *metadata)
-{
-	int ret = 0;
-	switch (metadata->op) {
-	case metadata_op_vic:
-		if (mfd->panel_info)
-			mfd->panel_info->vic =
-				metadata->data.video_info_code;
-		else
-			ret = -EINVAL;
-		break;
-	default:
-		pr_warn("unsupported request to MDP META IOCTL\n");
-		ret = -EINVAL;
-		break;
-	}
-	return ret;
-}
-
-static int mdss_fb_get_hw_caps(struct msm_fb_data_type *mfd,
-		struct mdss_hw_caps *caps)
-{
-	struct mdss_data_type *mdata = mfd->mdata;
-
-	if (!mdata)
-		return -ENODEV;
-
-	caps->mdp_rev = mdata->mdp_rev;
-	caps->vig_pipes = mdata->nvig_pipes;
-	caps->rgb_pipes = mdata->nrgb_pipes;
-	caps->dma_pipes = mdata->ndma_pipes;
-
-	return 0;
-}
-
-static int mdss_fb_get_metadata(struct msm_fb_data_type *mfd,
-				struct msmfb_metadata *metadata)
-{
-	int ret = 0;
-	switch (metadata->op) {
-	case metadata_op_frame_rate:
-		metadata->data.panel_frame_rate =
-			mdss_get_panel_framerate(mfd);
-		break;
-	case metadata_op_get_caps:
-		ret = mdss_fb_get_hw_caps(mfd, &metadata->data.caps);
-		break;
-	default:
-		pr_warn("Unsupported request to MDP META IOCTL.\n");
-		ret = -EINVAL;
-		break;
-	}
-	return ret;
-}
 
 static int mdss_fb_ioctl(struct fb_info *info, unsigned int cmd,
 			 unsigned long arg)
 {
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
 	void __user *argp = (void __user *)arg;
-	struct mdp_histogram_data hist;
-	struct mdp_histogram_start_req hist_req;
-	u32 block, hist_data_addr = 0;
 	struct mdp_page_protection fb_page_protection;
 	int ret = -ENOSYS;
 	struct mdp_buf_sync buf_sync;
-	struct msmfb_metadata metadata;
 
 	mdss_fb_power_setting_idle(mfd);
 
@@ -1700,43 +1548,6 @@
 		ret = mdss_fb_set_lut(info, argp);
 		break;
 
-	case MSMFB_HISTOGRAM:
-		if (!mfd->panel_power_on)
-			return -EPERM;
-
-		ret = copy_from_user(&hist, argp, sizeof(hist));
-		if (ret)
-			return ret;
-
-		ret = mdss_mdp_hist_collect(mfd->ctl, &hist, &hist_data_addr);
-		if ((ret == 0) && hist_data_addr) {
-			ret = copy_to_user(hist.c0, (u32 *)hist_data_addr,
-				sizeof(u32) * hist.bin_cnt);
-			if (ret == 0)
-				ret = copy_to_user(argp, &hist,
-						   sizeof(hist));
-		}
-		break;
-
-	case MSMFB_HISTOGRAM_START:
-		if (!mfd->panel_power_on)
-			return -EPERM;
-
-		ret = copy_from_user(&hist_req, argp, sizeof(hist_req));
-		if (ret)
-			return ret;
-
-		ret = mdss_mdp_histogram_start(mfd->ctl, &hist_req);
-		break;
-
-	case MSMFB_HISTOGRAM_STOP:
-		ret = copy_from_user(&block, argp, sizeof(int));
-		if (ret)
-			return ret;
-
-		ret = mdss_mdp_histogram_stop(mfd->ctl, block);
-		break;
-
 	case MSMFB_GET_PAGE_PROTECTION:
 		fb_page_protection.page_protection =
 			mfd->mdp_fb_page_protection;
@@ -1746,10 +1557,6 @@
 			return ret;
 		break;
 
-	case MSMFB_MDP_PP:
-		ret = mdss_fb_handle_pp_ioctl(mfd, argp);
-		break;
-
 	case MSMFB_BUFFER_SYNC:
 		ret = copy_from_user(&buf_sync, argp, sizeof(buf_sync));
 		if (ret)
@@ -1769,25 +1576,9 @@
 		ret = mdss_fb_display_commit(info, argp);
 		break;
 
-	case MSMFB_METADATA_SET:
-		ret = copy_from_user(&metadata, argp, sizeof(metadata));
-		if (ret)
-			return ret;
-		ret = mdss_fb_set_metadata(mfd, &metadata);
-		break;
-
-	case MSMFB_METADATA_GET:
-		ret = copy_from_user(&metadata, argp, sizeof(metadata));
-		if (ret)
-			return ret;
-		ret = mdss_fb_get_metadata(mfd, &metadata);
-		if (!ret)
-			ret = copy_to_user(argp, &metadata, sizeof(metadata));
-		break;
-
 	default:
-		if (mfd->ioctl_handler)
-			ret = mfd->ioctl_handler(mfd, cmd, argp);
+		if (mfd->mdp.ioctl_handler)
+			ret = mfd->mdp.ioctl_handler(mfd, cmd, argp);
 		break;
 	}
 
@@ -1853,6 +1644,11 @@
 		return -ENODEV;
 	}
 
+	if (!mdp_instance) {
+		pr_err("mdss mdp resource not initialized yet\n");
+		return -ENODEV;
+	}
+
 	node = of_parse_phandle(pdev->dev.of_node, "qcom,mdss-fb-map", 0);
 	if (!node) {
 		pr_err("Unable to find fb node for device: %s\n",
@@ -1876,23 +1672,27 @@
 		fb_pdev->dev.platform_data = pdata;
 	}
 
-	/*
-	 * Clocks are already on if continuous splash is enabled,
-	 * increasing ref_cnt to help balance clocks once done.
-	 */
-	if (pdata->panel_info.cont_splash_enabled) {
-		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
-		mdss_mdp_footswitch_ctrl_splash(1);
-		mdss_mdp_copy_splash_screen(pdata);
-	}
+	if (mdp_instance->panel_register_done)
+		mdp_instance->panel_register_done(pdata);
 
 mdss_notfound:
 	of_node_put(node);
-
 	return rc;
 }
 EXPORT_SYMBOL(mdss_register_panel);
 
+int mdss_fb_register_mdp_instance(struct msm_mdp_interface *mdp)
+{
+	if (mdp_instance) {
+		pr_err("multiple MDP instance registration");
+		return -EINVAL;
+	}
+
+	mdp_instance = mdp;
+	return 0;
+}
+EXPORT_SYMBOL(mdss_fb_register_mdp_instance);
+
 int mdss_fb_get_phys_info(unsigned long *start, unsigned long *len, int fb_num)
 {
 	struct fb_info *info;
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index db2e305..fdbbea9 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -19,7 +19,6 @@
 #include <linux/msm_mdp.h>
 #include <linux/types.h>
 
-#include "mdss_mdp.h"
 #include "mdss_panel.h"
 
 #define MSM_FB_DEFAULT_PAGE_SIZE 2
@@ -53,6 +52,26 @@
 	struct mutex lock;
 };
 
+struct msm_fb_data_type;
+
+struct msm_mdp_interface {
+	int (*fb_mem_alloc_fnc)(struct msm_fb_data_type *mfd);
+	int (*init_fnc)(struct msm_fb_data_type *mfd);
+	int (*on_fnc)(struct msm_fb_data_type *mfd);
+	int (*off_fnc)(struct msm_fb_data_type *mfd);
+	int (*kickoff_fnc)(struct msm_fb_data_type *mfd);
+	int (*ioctl_handler)(struct msm_fb_data_type *mfd, u32 cmd, void *arg);
+	void (*dma_fnc)(struct msm_fb_data_type *mfd);
+	int (*cursor_update)(struct msm_fb_data_type *mfd,
+				struct fb_cursor *cursor);
+	int (*lut_update)(struct msm_fb_data_type *mfd, struct fb_cmap *cmap);
+	int (*do_histogram)(struct msm_fb_data_type *mfd,
+				struct mdp_histogram *hist);
+	int (*panel_register_done)(struct mdss_panel_data *pdata);
+	u32 (*fb_stride)(u32 fb_index, u32 xres, int bpp);
+	void *private1;
+};
+
 struct msm_fb_data_type {
 	u32 key;
 	u32 index;
@@ -71,30 +90,9 @@
 	int panel_reconfig;
 
 	u32 dst_format;
-	int vsync_pending;
-	ktime_t vsync_time;
-	struct completion vsync_comp;
-	spinlock_t vsync_lock;
-	int borderfill_enable;
-
-	int hw_refresh;
-
-	int overlay_play_enable;
-
 	int panel_power_on;
 	struct disp_info_type_suspend suspend;
 
-	int (*on_fnc) (struct msm_fb_data_type *mfd);
-	int (*off_fnc) (struct msm_fb_data_type *mfd);
-	int (*kickoff_fnc) (struct mdss_mdp_ctl *ctl);
-	int (*ioctl_handler) (struct msm_fb_data_type *mfd, u32 cmd, void *arg);
-	void (*dma_fnc) (struct msm_fb_data_type *mfd);
-	int (*cursor_update) (struct msm_fb_data_type *mfd,
-			      struct fb_cursor *cursor);
-	int (*lut_update) (struct msm_fb_data_type *mfd, struct fb_cmap *cmap);
-	int (*do_histogram) (struct msm_fb_data_type *mfd,
-			     struct mdp_histogram *hist);
-
 	struct ion_handle *ihdl;
 	unsigned long iova;
 	void *cursor_buf;
@@ -105,21 +103,16 @@
 	u32 bl_scale;
 	u32 bl_min_lvl;
 	struct mutex lock;
-	struct mutex ov_lock;
 
 	struct platform_device *pdev;
 
 	u32 mdp_fb_page_protection;
 
-	struct mdss_data_type *mdata;
-	struct mdss_mdp_ctl *ctl;
-	struct mdss_mdp_wb *wb;
-	struct list_head overlay_list;
-	struct list_head pipes_used;
-	struct list_head pipes_cleanup;
 	struct disp_info_notify update;
 	struct disp_info_notify no_update;
 
+	struct msm_mdp_interface mdp;
+
 	u32 acq_fen_cnt;
 	struct sync_fence *acq_fen[MDP_MAX_FENCE_FD];
 	int cur_rel_fen_fd;
@@ -150,5 +143,5 @@
 void mdss_fb_update_backlight(struct msm_fb_data_type *mfd);
 void mdss_fb_wait_for_fence(struct msm_fb_data_type *mfd);
 void mdss_fb_signal_timeline(struct msm_fb_data_type *mfd);
-
+int mdss_fb_register_mdp_instance(struct msm_mdp_interface *mdp);
 #endif /* MDSS_FB_H */
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index d92422c..e89fc7a 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -55,6 +55,12 @@
 #include "mdss_debug.h"
 
 struct mdss_data_type *mdss_res;
+struct msm_mdp_interface mdp5 = {
+	.init_fnc = mdss_mdp_overlay_init,
+	.fb_mem_alloc_fnc = mdss_mdp_alloc_fb_mem,
+	.panel_register_done = mdss_panel_register_done,
+	.fb_stride = mdss_mdp_fb_stride,
+};
 
 #define IB_QUOTA 800000000
 #define AB_QUOTA 800000000
@@ -129,23 +135,36 @@
 static int mdss_mdp_parse_dt_smp(struct platform_device *pdev);
 static int mdss_mdp_parse_dt_misc(struct platform_device *pdev);
 
-int mdss_mdp_alloc_fb_mem(struct msm_fb_data_type *mfd,
-			  u32 size, u32 *phys, void **virt)
+int mdss_mdp_alloc_fb_mem(struct msm_fb_data_type *mfd)
 {
 	int dom;
-	void *fb_virt;
-	u32 fb_phys;
-	fb_virt = allocate_contiguous_memory(size, MEMTYPE_EBI1, SZ_1M, 0);
-	if (!fb_virt) {
-		pr_err("unable to alloc fbmem size=%u\n", size);
-		return -ENOMEM;
-	}
-	fb_phys = memory_pool_node_paddr(fb_virt);
-	dom = mdss_get_iommu_domain(MDSS_IOMMU_DOMAIN_UNSECURE);
-	msm_iommu_map_contig_buffer(fb_phys, dom, 0, size, SZ_4K,
-					0, &(mfd->iova));
-	*phys = fb_phys;
-	*virt = fb_virt;
+	void *virt = NULL;
+	unsigned long phys = 0;
+	size_t size;
+	u32 yres = mfd->fbi->var.yres_virtual;
+
+	size = PAGE_ALIGN(mfd->fbi->fix.line_length * yres);
+
+	if (mfd->index == 0) {
+		virt = allocate_contiguous_memory(size, MEMTYPE_EBI1, SZ_1M, 0);
+		if (!virt) {
+			pr_err("unable to alloc fbmem size=%u\n", size);
+			return -ENOMEM;
+		}
+		phys = memory_pool_node_paddr(virt);
+		dom = mdss_get_iommu_domain(MDSS_IOMMU_DOMAIN_UNSECURE);
+		msm_iommu_map_contig_buffer(phys, dom, 0, size, SZ_4K, 0,
+					&mfd->iova);
+
+		pr_debug("allocating %u bytes at %p (%lx phys) for fb %d\n",
+			size, virt, phys, mfd->index);
+	} else
+		size = 0;
+
+	mfd->fbi->screen_base = virt;
+	mfd->fbi->fix.smem_start = phys;
+	mfd->fbi->fix.smem_len = size;
+
 	return 0;
 }
 
@@ -994,6 +1013,10 @@
 	if (!pm_runtime_enabled(&pdev->dev))
 		mdss_mdp_footswitch_ctrl(mdata, true);
 
+	rc = mdss_fb_register_mdp_instance(&mdp5);
+	if (rc)
+		pr_err("unable to register mdp instance\n");
+
 probe_done:
 	if (IS_ERR_VALUE(rc)) {
 		mdss_res = NULL;
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 8af3cc0..df5e5d3 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -198,6 +198,8 @@
 	u32 plane_size[MAX_PLANES];
 	u32 total_size;
 	u32 ystride[MAX_PLANES];
+	u32 rau_cnt;
+	u32 rau_h[2];
 };
 
 struct mdss_mdp_img_data {
@@ -284,6 +286,24 @@
 	void *priv_data;
 };
 
+struct mdss_overlay_private {
+	int vsync_pending;
+	ktime_t vsync_time;
+	struct completion vsync_comp;
+	spinlock_t vsync_lock;
+	int borderfill_enable;
+	int overlay_play_enable;
+	int hw_refresh;
+
+	struct mdss_data_type *mdata;
+	struct mutex ov_lock;
+	struct mdss_mdp_ctl *ctl;
+	struct mdss_mdp_wb *wb;
+	struct list_head overlay_list;
+	struct list_head pipes_used;
+	struct list_head pipes_cleanup;
+};
+
 #define is_vig_pipe(_pipe_id_) ((_pipe_id_) <= MDSS_MDP_SSPP_VIG2)
 static inline void mdss_mdp_ctl_write(struct mdss_mdp_ctl *ctl,
 				      u32 reg, u32 val)
@@ -333,10 +353,10 @@
 int mdss_mdp_video_start(struct mdss_mdp_ctl *ctl);
 int mdss_mdp_cmd_start(struct mdss_mdp_ctl *ctl);
 int mdss_mdp_writeback_start(struct mdss_mdp_ctl *ctl);
-int mdss_mdp_overlay_kickoff(struct mdss_mdp_ctl *ctl);
+int mdss_mdp_overlay_kickoff(struct msm_fb_data_type *mfd);
 
 struct mdss_mdp_ctl *mdss_mdp_ctl_init(struct mdss_panel_data *pdata,
-				       struct msm_fb_data_type *mfd);
+					struct msm_fb_data_type *mfd);
 int mdss_mdp_ctl_setup(struct mdss_mdp_ctl *ctl);
 int mdss_mdp_ctl_split_display_setup(struct mdss_mdp_ctl *ctl,
 		struct mdss_panel_data *pdata);
@@ -424,17 +444,29 @@
 int mdss_mdp_data_check(struct mdss_mdp_data *data,
 			struct mdss_mdp_plane_sizes *ps);
 int mdss_mdp_get_plane_sizes(u32 format, u32 w, u32 h,
-			     struct mdss_mdp_plane_sizes *ps);
+			     struct mdss_mdp_plane_sizes *ps, u32 bwc_mode);
+int mdss_mdp_get_rau_strides(u32 w, u32 h, struct mdss_mdp_format_params *fmt,
+			       struct mdss_mdp_plane_sizes *ps);
 struct mdss_mdp_format_params *mdss_mdp_get_format_params(u32 format);
 int mdss_mdp_put_img(struct mdss_mdp_img_data *data);
 int mdss_mdp_get_img(struct msmfb_data *img, struct mdss_mdp_img_data *data);
 u32 mdss_get_panel_framerate(struct msm_fb_data_type *mfd);
 
-int mdss_mdp_wb_kickoff(struct mdss_mdp_ctl *ctl);
+int mdss_mdp_wb_kickoff(struct msm_fb_data_type *mfd);
 int mdss_mdp_wb_ioctl_handler(struct msm_fb_data_type *mfd, u32 cmd, void *arg);
 
 int mdss_mdp_get_ctl_mixers(u32 fb_num, u32 *mixer_id);
-int mdss_mdp_alloc_fb_mem(struct msm_fb_data_type *mfd,
-				  u32 size, u32 *phys, void **virt);
+int mdss_mdp_alloc_fb_mem(struct msm_fb_data_type *mfd);
 u32 mdss_mdp_fb_stride(u32 fb_index, u32 xres, int bpp);
+
+int mdss_panel_register_done(struct mdss_panel_data *pdata);
+
+#define mfd_to_mdp5_data(mfd) (mfd->mdp.private1)
+#define mfd_to_mdata(mfd) (((struct mdss_overlay_private *)\
+				(mfd->mdp.private1))->mdata)
+#define mfd_to_ctl(mfd) (((struct mdss_overlay_private *)\
+				(mfd->mdp.private1))->ctl)
+#define mfd_to_wb(mfd) (((struct mdss_overlay_private *)\
+				(mfd->mdp.private1))->wb)
+
 #endif /* MDSS_MDP_H */
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index 66e1a0c..97998d8c 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -200,6 +200,20 @@
 		total_ib_quota += ib_quota;
 		if (clk_rate > max_clk_rate)
 			max_clk_rate = clk_rate;
+
+		if (ctl->intf_type) {
+			struct mdss_panel_info *pinfo;
+
+			pinfo = &ctl->panel_data->panel_info;
+			clk_rate = (ctl->intf_type == MDSS_INTF_DSI) ?
+					pinfo->mipi.dsi_pclk_rate :
+					pinfo->clk_rate;
+
+			/* minimum clock rate due to inefficiency in 3dmux */
+			clk_rate = mult_frac(clk_rate >> 1, 9, 8);
+			if (clk_rate > max_clk_rate)
+				max_clk_rate = clk_rate;
+		}
 	}
 
 	/* request minimum bandwidth to have bus clock on when display is on */
@@ -575,7 +589,8 @@
 	struct mdss_mdp_ctl *ctl;
 	int ret = 0;
 
-	ctl = mdss_mdp_ctl_alloc(mfd->mdata);
+	struct mdss_data_type *mdata = mfd_to_mdata(mfd);
+	ctl = mdss_mdp_ctl_alloc(mdata);
 	if (!ctl) {
 		pr_err("unable to allocate ctl\n");
 		return ERR_PTR(-ENOMEM);
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
index b7b3c23..7fbb031 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
@@ -37,7 +37,7 @@
 	u16 width;
 	u16 height;
 	u8 rot90;
-
+	u32 bwc_mode;
 	int initialized;
 
 	struct mdss_mdp_plane_sizes dst_planes;
@@ -90,6 +90,9 @@
 
 	pr_debug("wb_num=%d addr=0x%x\n", ctx->wb_num, data->p[0].addr);
 
+	if (ctx->bwc_mode)
+		data->bwc_enabled = 1;
+
 	ret = mdss_mdp_data_check(data, &ctx->dst_planes);
 	if (ret)
 		return ret;
@@ -112,7 +115,8 @@
 	pr_debug("wb_num=%d format=%d\n", ctx->wb_num, ctx->format);
 
 	mdss_mdp_get_plane_sizes(ctx->format, ctx->width, ctx->height,
-				 &ctx->dst_planes);
+				 &ctx->dst_planes,
+				 ctx->opmode & MDSS_MDP_OP_BWC_EN);
 
 	fmt = mdss_mdp_get_format_params(ctx->format);
 	if (!fmt) {
@@ -252,7 +256,8 @@
 	if (ctl->mdata->rot_block_size == 128)
 		ctx->opmode |= BIT(4); /* block size 128 */
 
-	ctx->opmode |= rot->bwc_mode;
+	ctx->bwc_mode = rot->bwc_mode;
+	ctx->opmode |= ctx->bwc_mode;
 
 	ctx->width = rot->src_rect.w;
 	ctx->height = rot->src_rect.h;
@@ -260,12 +265,15 @@
 	ctx->format = rot->format;
 
 	ctx->rot90 = !!(rot->flags & MDP_ROT_90);
+
+	if (ctx->bwc_mode || ctx->rot90)
+		ctx->format = mdss_mdp_get_rotator_dst_format(rot->format);
+	else
+		ctx->format = rot->format;
+
 	if (ctx->rot90) {
 		ctx->opmode |= BIT(5); /* ROT 90 */
 		swap(ctx->width, ctx->height);
-		ctx->format = mdss_mdp_get_rotator_dst_format(rot->format);
-	} else {
-		ctx->format = rot->format;
 	}
 
 	return mdss_mdp_writeback_format_setup(ctx);
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 919e904..dae3e05 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -21,6 +21,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/uaccess.h>
 #include <linux/delay.h>
+#include <linux/msm_mdp.h>
 
 #include <mach/iommu_domains.h>
 
@@ -41,8 +42,9 @@
 				struct mdp_overlay *req)
 {
 	struct mdss_mdp_pipe *pipe;
+	struct mdss_data_type *mdata = mfd_to_mdata(mfd);
 
-	pipe = mdss_mdp_pipe_get(mfd->mdata, req->id);
+	pipe = mdss_mdp_pipe_get(mdata, req->id);
 	if (IS_ERR_OR_NULL(pipe)) {
 		pr_err("invalid pipe ndx=%x\n", req->id);
 		return pipe ? PTR_ERR(pipe) : -ENODEV;
@@ -60,11 +62,12 @@
 {
 	u32 xres, yres;
 	u32 min_src_size, min_dst_size;
+	struct mdss_data_type *mdata = mfd_to_mdata(mfd);
 
 	xres = mfd->fbi->var.xres;
 	yres = mfd->fbi->var.yres;
 
-	if (mfd->mdata->mdp_rev >= MDSS_MDP_HW_REV_102) {
+	if (mdata->mdp_rev >= MDSS_MDP_HW_REV_102) {
 		min_src_size = fmt->is_yuv ? 2 : 1;
 		min_dst_size = 1;
 	} else {
@@ -170,11 +173,12 @@
 static int mdss_mdp_overlay_rotator_setup(struct msm_fb_data_type *mfd,
 					  struct mdp_overlay *req)
 {
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 	struct mdss_mdp_rotator_session *rot;
 	struct mdss_mdp_format_params *fmt;
 	int ret = 0;
 
-	pr_debug("rot ctl=%u req id=%x\n", mfd->ctl->num, req->id);
+	pr_debug("rot ctl=%u req id=%x\n", mdp5_data->ctl->num, req->id);
 
 	fmt = mdss_mdp_get_format_params(req->src.format);
 	if (!fmt) {
@@ -209,6 +213,7 @@
 	rot->flags = req->flags & (MDP_ROT_90 | MDP_FLIP_LR | MDP_FLIP_UD |
 				   MDP_SECURE_OVERLAY_SESSION);
 
+	rot->bwc_mode = (req->flags & MDP_BWC_EN) ? 1 : 0;
 	rot->format = fmt->format;
 	rot->img_width = req->src.width;
 	rot->img_height = req->src.height;
@@ -237,9 +242,10 @@
 	struct mdss_mdp_pipe *pipe;
 	struct mdss_mdp_mixer *mixer = NULL;
 	u32 pipe_type, mixer_mux, len, src_format;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 	int ret;
 
-	if (mfd == NULL || mfd->ctl == NULL)
+	if (mdp5_data->ctl == NULL)
 		return -ENODEV;
 
 	if (req->flags & MDSS_MDP_RIGHT_MIXER)
@@ -247,7 +253,7 @@
 	else
 		mixer_mux = MDSS_MDP_MIXER_MUX_LEFT;
 
-	pr_debug("pipe ctl=%u req id=%x mux=%d\n", mfd->ctl->num, req->id,
+	pr_debug("pipe ctl=%u req id=%x mux=%d\n", mdp5_data->ctl->num, req->id,
 			mixer_mux);
 
 	if (req->flags & MDP_ROT_90) {
@@ -256,7 +262,7 @@
 	}
 
 	src_format = req->src.format;
-	if (req->flags & MDP_SOURCE_ROTATED_90)
+	if (req->flags & (MDP_SOURCE_ROTATED_90 | MDP_BWC_EN))
 		src_format = mdss_mdp_get_rotator_dst_format(src_format);
 
 	fmt = mdss_mdp_get_format_params(src_format);
@@ -269,14 +275,15 @@
 	if (ret)
 		return ret;
 
-	pipe = mdss_mdp_mixer_stage_pipe(mfd->ctl, mixer_mux, req->z_order);
+	pipe = mdss_mdp_mixer_stage_pipe(mdp5_data->ctl, mixer_mux,
+					req->z_order);
 	if (pipe && pipe->ndx != req->id) {
 		pr_debug("replacing pnum=%d at stage=%d mux=%d\n",
 				pipe->num, req->z_order, mixer_mux);
 		pipe->params_changed = true;
 	}
 
-	mixer = mdss_mdp_mixer_get(mfd->ctl, mixer_mux);
+	mixer = mdss_mdp_mixer_get(mdp5_data->ctl, mixer_mux);
 	if (!mixer) {
 		pr_err("unable to get mixer\n");
 		return -ENODEV;
@@ -310,13 +317,13 @@
 		}
 
 		mutex_lock(&mfd->lock);
-		list_add(&pipe->used_list, &mfd->pipes_used);
+		list_add(&pipe->used_list, &mdp5_data->pipes_used);
 		mutex_unlock(&mfd->lock);
 		pipe->mixer = mixer;
 		pipe->mfd = mfd;
 		pipe->play_cnt = 0;
 	} else {
-		pipe = mdss_mdp_pipe_get(mfd->mdata, req->id);
+		pipe = mdss_mdp_pipe_get(mdp5_data->mdata, req->id);
 		if (IS_ERR_OR_NULL(pipe)) {
 			pr_err("invalid pipe ndx=%x\n", req->id);
 			return pipe ? PTR_ERR(pipe) : -ENODEV;
@@ -339,7 +346,8 @@
 	}
 
 	pipe->flags = req->flags;
-
+	pipe->bwc_mode = pipe->mixer->rotator_mode ?
+		0 : (req->flags & MDP_BWC_EN ? 1 : 0) ;
 	pipe->img_width = req->src.width & 0x3fff;
 	pipe->img_height = req->src.height & 0x3fff;
 	pipe->src.x = req->src_rect.x;
@@ -406,14 +414,15 @@
 static int mdss_mdp_overlay_set(struct msm_fb_data_type *mfd,
 				struct mdp_overlay *req)
 {
-	int ret = 0;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+	int ret;
 
-	ret = mutex_lock_interruptible(&mfd->ov_lock);
+	ret = mutex_lock_interruptible(&mdp5_data->ov_lock);
 	if (ret)
 		return ret;
 
 	if (!mfd->panel_power_on) {
-		mutex_unlock(&mfd->ov_lock);
+		mutex_unlock(&mdp5_data->ov_lock);
 		return -EPERM;
 	}
 
@@ -432,7 +441,7 @@
 		req->z_order -= MDSS_MDP_STAGE_0;
 	}
 
-	mutex_unlock(&mfd->ov_lock);
+	mutex_unlock(&mdp5_data->ov_lock);
 
 	return ret;
 }
@@ -481,16 +490,18 @@
 static int mdss_mdp_overlay_cleanup(struct msm_fb_data_type *mfd)
 {
 	struct mdss_mdp_pipe *pipe, *tmp;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 	LIST_HEAD(destroy_pipes);
 
 	mutex_lock(&mfd->lock);
-	list_for_each_entry_safe(pipe, tmp, &mfd->pipes_cleanup, cleanup_list) {
+	list_for_each_entry_safe(pipe, tmp, &mdp5_data->pipes_cleanup,
+				cleanup_list) {
 		list_move(&pipe->cleanup_list, &destroy_pipes);
 		mdss_mdp_overlay_free_buf(&pipe->back_buf);
 		mdss_mdp_overlay_free_buf(&pipe->front_buf);
 	}
 
-	list_for_each_entry(pipe, &mfd->pipes_used, used_list) {
+	list_for_each_entry(pipe, &mdp5_data->pipes_used, used_list) {
 		if (pipe->back_buf.num_planes) {
 			/* make back buffer active */
 			mdss_mdp_overlay_free_buf(&pipe->front_buf);
@@ -595,8 +606,9 @@
 static int mdss_mdp_overlay_start(struct msm_fb_data_type *mfd)
 {
 	int rc;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 
-	if (mfd->ctl->power_on)
+	if (mdp5_data->ctl->power_on)
 		return 0;
 
 	pr_debug("starting fb%d overlay\n", mfd->index);
@@ -608,20 +620,20 @@
 	}
 
 	if (mfd->panel_info->cont_splash_enabled)
-		mdss_mdp_reconfigure_splash_done(mfd->ctl);
+		mdss_mdp_reconfigure_splash_done(mdp5_data->ctl);
 
 	if (!is_mdss_iommu_attached()) {
 		mdss_iommu_attach(mdss_res);
 		mdss_hw_init(mdss_res);
 	}
 
-	rc = mdss_mdp_ctl_start(mfd->ctl);
+	rc = mdss_mdp_ctl_start(mdp5_data->ctl);
 	if (rc == 0) {
 		atomic_inc(&ov_active_panels);
 	} else {
 		pr_err("overlay start failed.\n");
-		mdss_mdp_ctl_destroy(mfd->ctl);
-		mfd->ctl = NULL;
+		mdss_mdp_ctl_destroy(mdp5_data->ctl);
+		mdp5_data->ctl = NULL;
 
 		pm_runtime_put(&mfd->pdev->dev);
 	}
@@ -629,15 +641,15 @@
 	return rc;
 }
 
-int mdss_mdp_overlay_kickoff(struct mdss_mdp_ctl *ctl)
+int mdss_mdp_overlay_kickoff(struct msm_fb_data_type *mfd)
 {
-	struct msm_fb_data_type *mfd = ctl->mfd;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 	struct mdss_mdp_pipe *pipe;
 	int ret;
 
-	mutex_lock(&mfd->ov_lock);
+	mutex_lock(&mdp5_data->ov_lock);
 	mutex_lock(&mfd->lock);
-	list_for_each_entry(pipe, &mfd->pipes_used, used_list) {
+	list_for_each_entry(pipe, &mdp5_data->pipes_used, used_list) {
 		struct mdss_mdp_data *buf;
 		if (pipe->back_buf.num_planes) {
 			buf = &pipe->back_buf;
@@ -658,16 +670,17 @@
 		}
 	}
 
-	if (mfd->kickoff_fnc)
-		ret = mfd->kickoff_fnc(ctl);
+	if (mfd->panel.type == WRITEBACK_PANEL)
+		ret = mdss_mdp_wb_kickoff(mfd);
 	else
-		ret = mdss_mdp_display_commit(ctl, NULL);
+		ret = mdss_mdp_display_commit(mdp5_data->ctl, NULL);
+
 	mutex_unlock(&mfd->lock);
 
 	if (IS_ERR_VALUE(ret))
 		goto commit_fail;
 
-	ret = mdss_mdp_display_wait4comp(ctl);
+	ret = mdss_mdp_display_wait4comp(mdp5_data->ctl);
 
 	complete(&mfd->update.comp);
 	mutex_lock(&mfd->no_update.lock);
@@ -681,7 +694,7 @@
 commit_fail:
 	ret = mdss_mdp_overlay_cleanup(mfd);
 
-	mutex_unlock(&mfd->ov_lock);
+	mutex_unlock(&mdp5_data->ov_lock);
 
 	return ret;
 }
@@ -689,6 +702,7 @@
 static int mdss_mdp_overlay_release(struct msm_fb_data_type *mfd, int ndx)
 {
 	struct mdss_mdp_pipe *pipe;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 	u32 pipe_ndx, unset_ndx = 0;
 	int i;
 
@@ -696,14 +710,15 @@
 		pipe_ndx = BIT(i);
 		if (pipe_ndx & ndx) {
 			unset_ndx |= pipe_ndx;
-			pipe = mdss_mdp_pipe_get(mfd->mdata, pipe_ndx);
+			pipe = mdss_mdp_pipe_get(mdp5_data->mdata, pipe_ndx);
 			if (IS_ERR_OR_NULL(pipe)) {
 				pr_warn("unknown pipe ndx=%x\n", pipe_ndx);
 				continue;
 			}
 			mutex_lock(&mfd->lock);
 			list_del(&pipe->used_list);
-			list_add(&pipe->cleanup_list, &mfd->pipes_cleanup);
+			list_add(&pipe->cleanup_list,
+				&mdp5_data->pipes_cleanup);
 			mutex_unlock(&mfd->lock);
 			mdss_mdp_mixer_pipe_unstage(pipe);
 			mdss_mdp_pipe_unmap(pipe);
@@ -715,22 +730,23 @@
 static int mdss_mdp_overlay_unset(struct msm_fb_data_type *mfd, int ndx)
 {
 	int ret = 0;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 
-	if (!mfd || !mfd->ctl)
+	if (!mfd || !mdp5_data->ctl)
 		return -ENODEV;
 
-	ret = mutex_lock_interruptible(&mfd->ov_lock);
+	ret = mutex_lock_interruptible(&mdp5_data->ov_lock);
 	if (ret)
 		return ret;
 
 	if (ndx == BORDERFILL_NDX) {
 		pr_debug("borderfill disable\n");
-		mfd->borderfill_enable = false;
+		mdp5_data->borderfill_enable = false;
 		return 0;
 	}
 
 	if (!mfd->panel_power_on) {
-		mutex_unlock(&mfd->ov_lock);
+		mutex_unlock(&mdp5_data->ov_lock);
 		return -EPERM;
 	}
 
@@ -741,7 +757,7 @@
 	else
 		ret = mdss_mdp_overlay_release(mfd, ndx);
 
-	mutex_unlock(&mfd->ov_lock);
+	mutex_unlock(&mdp5_data->ov_lock);
 
 	return ret;
 }
@@ -749,18 +765,19 @@
 static int mdss_mdp_overlay_release_all(struct msm_fb_data_type *mfd)
 {
 	struct mdss_mdp_pipe *pipe;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 	u32 unset_ndx = 0;
 	int cnt = 0;
 
-	mutex_lock(&mfd->ov_lock);
+	mutex_lock(&mdp5_data->ov_lock);
 	mutex_lock(&mfd->lock);
-	list_for_each_entry(pipe, &mfd->pipes_used, used_list) {
+	list_for_each_entry(pipe, &mdp5_data->pipes_used, used_list) {
 		unset_ndx |= pipe->ndx;
 		cnt++;
 	}
 
-	if (cnt == 0 && !list_empty(&mfd->pipes_cleanup)) {
-		pr_debug("overlay release on fb%d called without commit!\n",
+	if (cnt == 0 && !list_empty(&mdp5_data->pipes_cleanup)) {
+		pr_debug("overlay release on fb%d called without commit!",
 			mfd->index);
 		cnt++;
 	}
@@ -771,10 +788,10 @@
 		pr_debug("%d pipes need cleanup (%x)\n", cnt, unset_ndx);
 		mdss_mdp_overlay_release(mfd, unset_ndx);
 	}
-	mutex_unlock(&mfd->ov_lock);
+	mutex_unlock(&mdp5_data->ov_lock);
 
 	if (cnt)
-		mdss_mdp_overlay_kickoff(mfd->ctl);
+		mfd->mdp.kickoff_fnc(mfd);
 
 	return 0;
 }
@@ -782,12 +799,12 @@
 static int mdss_mdp_overlay_play_wait(struct msm_fb_data_type *mfd,
 				      struct msmfb_overlay_data *req)
 {
-	int ret;
+	int ret = 0;
 
-	if (!mfd || !mfd->ctl)
+	if (!mfd)
 		return -ENODEV;
 
-	ret = mdss_mdp_overlay_kickoff(mfd->ctl);
+	ret = mfd->mdp.kickoff_fnc(mfd);
 	if (!ret)
 		pr_err("error displaying\n");
 
@@ -840,8 +857,9 @@
 	struct mdss_mdp_data *src_data;
 	int ret;
 	u32 flags;
+	struct mdss_data_type *mdata = mfd_to_mdata(mfd);
 
-	pipe = mdss_mdp_pipe_get(mfd->mdata, req->id);
+	pipe = mdss_mdp_pipe_get(mdata, req->id);
 	if (IS_ERR_OR_NULL(pipe)) {
 		pr_err("pipe ndx=%x doesn't exist\n", req->id);
 		return pipe ? PTR_ERR(pipe) : -ENODEV;
@@ -870,16 +888,17 @@
 static int mdss_mdp_overlay_play(struct msm_fb_data_type *mfd,
 				 struct msmfb_overlay_data *req)
 {
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 	int ret = 0;
 
 	pr_debug("play req id=%x\n", req->id);
 
-	ret = mutex_lock_interruptible(&mfd->ov_lock);
+	ret = mutex_lock_interruptible(&mdp5_data->ov_lock);
 	if (ret)
 		return ret;
 
 	if (!mfd->panel_power_on) {
-		mutex_unlock(&mfd->ov_lock);
+		mutex_unlock(&mdp5_data->ov_lock);
 		return -EPERM;
 	}
 
@@ -893,13 +912,13 @@
 		ret = mdss_mdp_overlay_rotate(mfd, req);
 	} else if (req->id == BORDERFILL_NDX) {
 		pr_debug("borderfill enable\n");
-		mfd->borderfill_enable = true;
+		mdp5_data->borderfill_enable = true;
 		ret = mdss_mdp_overlay_free_fb_pipe(mfd);
 	} else {
 		ret = mdss_mdp_overlay_queue(mfd, req);
 	}
 
-	mutex_unlock(&mfd->ov_lock);
+	mutex_unlock(&mdp5_data->ov_lock);
 
 	return ret;
 }
@@ -908,13 +927,16 @@
 {
 	struct mdss_mdp_pipe *pipe;
 	u32 fb_ndx = 0;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 
-	pipe = mdss_mdp_mixer_stage_pipe(mfd->ctl, MDSS_MDP_MIXER_MUX_LEFT,
+	pipe = mdss_mdp_mixer_stage_pipe(mdp5_data->ctl,
+					MDSS_MDP_MIXER_MUX_LEFT,
 					 MDSS_MDP_STAGE_BASE);
 	if (pipe)
 		fb_ndx |= pipe->ndx;
 
-	pipe = mdss_mdp_mixer_stage_pipe(mfd->ctl, MDSS_MDP_MIXER_MUX_RIGHT,
+	pipe = mdss_mdp_mixer_stage_pipe(mdp5_data->ctl,
+					MDSS_MDP_MIXER_MUX_RIGHT,
 					 MDSS_MDP_STAGE_BASE);
 	if (pipe)
 		fb_ndx |= pipe->ndx;
@@ -930,9 +952,10 @@
 					struct mdss_mdp_pipe **ppipe,
 					int mixer_mux)
 {
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 	struct mdss_mdp_pipe *pipe;
 
-	pipe = mdss_mdp_mixer_stage_pipe(mfd->ctl, mixer_mux,
+	pipe = mdss_mdp_mixer_stage_pipe(mdp5_data->ctl, mixer_mux,
 					 MDSS_MDP_STAGE_BASE);
 	if (pipe == NULL) {
 		struct mdp_overlay req;
@@ -940,7 +963,8 @@
 		struct mdss_mdp_mixer *mixer;
 		int ret, bpp;
 
-		mixer = mdss_mdp_mixer_get(mfd->ctl, MDSS_MDP_MIXER_MUX_LEFT);
+		mixer = mdss_mdp_mixer_get(mdp5_data->ctl,
+					MDSS_MDP_MIXER_MUX_LEFT);
 		if (!mixer) {
 			pr_err("unable to retrieve mixer\n");
 			return -ENODEV;
@@ -981,7 +1005,7 @@
 		if (ret)
 			return ret;
 
-		pr_debug("ctl=%d pnum=%d\n", mfd->ctl->num, pipe->num);
+		pr_debug("ctl=%d pnum=%d\n", mdp5_data->ctl->num, pipe->num);
 	}
 
 	*ppipe = pipe;
@@ -993,24 +1017,25 @@
 	struct mdss_mdp_data data;
 	struct mdss_mdp_pipe *pipe;
 	struct fb_info *fbi;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 	u32 offset;
 	int bpp, ret;
 
-	if (!mfd || !mfd->ctl)
+	if (!mfd || !mdp5_data->ctl)
 		return;
 
 	fbi = mfd->fbi;
 
-	if (fbi->fix.smem_len == 0 || mfd->borderfill_enable) {
-		mdss_mdp_overlay_kickoff(mfd->ctl);
+	if (fbi->fix.smem_len == 0 || mdp5_data->borderfill_enable) {
+		mfd->mdp.kickoff_fnc(mfd);
 		return;
 	}
 
-	if (mutex_lock_interruptible(&mfd->ov_lock))
+	if (mutex_lock_interruptible(&mdp5_data->ov_lock))
 		return;
 
 	if (!mfd->panel_power_on) {
-		mutex_unlock(&mfd->ov_lock);
+		mutex_unlock(&mdp5_data->ov_lock);
 		return;
 	}
 
@@ -1076,37 +1101,43 @@
 			goto pan_display_error;
 		}
 	}
-	mutex_unlock(&mfd->ov_lock);
+	mutex_unlock(&mdp5_data->ov_lock);
 
 	if ((fbi->var.activate & FB_ACTIVATE_VBL) ||
 	    (fbi->var.activate & FB_ACTIVATE_FORCE))
-		mdss_mdp_overlay_kickoff(mfd->ctl);
+		mfd->mdp.kickoff_fnc(mfd);
+
 	return;
 
 pan_display_error:
-	mutex_unlock(&mfd->ov_lock);
+	mutex_unlock(&mdp5_data->ov_lock);
 }
 
 /* function is called in irq context should have minimum processing */
-static void mdss_mdp_overlay_handle_vsync(struct mdss_mdp_ctl *ctl, ktime_t t)
+static void mdss_mdp_overlay_handle_vsync(struct mdss_mdp_ctl *ctl,
+						ktime_t t)
 {
 	struct msm_fb_data_type *mfd = ctl->mfd;
-	if (!mfd) {
+	struct mdss_overlay_private *mdp5_data;
+
+	if (!mfd || !mfd->mdp.private1) {
 		pr_warn("Invalid handle for vsync\n");
 		return;
 	}
 
+	mdp5_data = mfd_to_mdp5_data(mfd);
 	pr_debug("vsync on fb%d play_cnt=%d\n", mfd->index, ctl->play_cnt);
 
-	spin_lock(&mfd->vsync_lock);
-	mfd->vsync_time = t;
-	complete(&mfd->vsync_comp);
-	spin_unlock(&mfd->vsync_lock);
+	spin_lock(&mdp5_data->vsync_lock);
+	mdp5_data->vsync_time = t;
+	complete(&mdp5_data->vsync_comp);
+	spin_unlock(&mdp5_data->vsync_lock);
 }
 
 int mdss_mdp_overlay_vsync_ctrl(struct msm_fb_data_type *mfd, int en)
 {
-	struct mdss_mdp_ctl *ctl = mfd->ctl;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+	struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
 	unsigned long flags;
 	int rc;
 
@@ -1122,16 +1153,16 @@
 	if (!ctl->power_on) {
 		pr_debug("fb%d vsync pending first update en=%d\n",
 				mfd->index, en);
-		mfd->vsync_pending = en;
+		mdp5_data->vsync_pending = en;
 		mutex_unlock(&ctl->lock);
 		return 0;
 	}
 
 	pr_debug("fb%d vsync en=%d\n", mfd->index, en);
 
-	spin_lock_irqsave(&mfd->vsync_lock, flags);
-	INIT_COMPLETION(mfd->vsync_comp);
-	spin_unlock_irqrestore(&mfd->vsync_lock, flags);
+	spin_lock_irqsave(&mdp5_data->vsync_lock, flags);
+	INIT_COMPLETION(mdp5_data->vsync_comp);
+	spin_unlock_irqrestore(&mdp5_data->vsync_lock, flags);
 
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 	if (en)
@@ -1150,26 +1181,27 @@
 {
 	struct fb_info *fbi = dev_get_drvdata(dev);
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 	unsigned long flags;
 	u64 vsync_ticks;
 	unsigned long timeout;
 	int ret;
 
-	if (!mfd->ctl || !mfd->ctl->power_on)
+	if (!mdp5_data->ctl || !mdp5_data->ctl->power_on)
 		return 0;
 
 	timeout = msecs_to_jiffies(VSYNC_PERIOD * 5);
-	ret = wait_for_completion_interruptible_timeout(&mfd->vsync_comp,
+	ret = wait_for_completion_interruptible_timeout(&mdp5_data->vsync_comp,
 			timeout);
 	if (ret <= 0) {
 		pr_debug("Sending current time as vsync timestamp for fb%d\n",
 				mfd->index);
-		mfd->vsync_time = ktime_get();
+		mdp5_data->vsync_time = ktime_get();
 	}
 
-	spin_lock_irqsave(&mfd->vsync_lock, flags);
-	vsync_ticks = ktime_to_ns(mfd->vsync_time);
-	spin_unlock_irqrestore(&mfd->vsync_lock, flags);
+	spin_lock_irqsave(&mdp5_data->vsync_lock, flags);
+	vsync_ticks = ktime_to_ns(mdp5_data->vsync_time);
+	spin_unlock_irqrestore(&mdp5_data->vsync_lock, flags);
 
 	pr_debug("fb%d vsync=%llu", mfd->index, vsync_ticks);
 	ret = snprintf(buf, PAGE_SIZE, "VSYNC=%llu", vsync_ticks);
@@ -1191,6 +1223,7 @@
 static int mdss_mdp_hw_cursor_update(struct msm_fb_data_type *mfd,
 				     struct fb_cursor *cursor)
 {
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 	struct mdss_mdp_mixer *mixer;
 	struct fb_image *img = &cursor->image;
 	u32 blendcfg;
@@ -1219,12 +1252,12 @@
 		}
 	}
 
-	mixer = mdss_mdp_mixer_get(mfd->ctl, MDSS_MDP_MIXER_MUX_DEFAULT);
+	mixer = mdss_mdp_mixer_get(mdp5_data->ctl, MDSS_MDP_MIXER_MUX_DEFAULT);
 	off = MDSS_MDP_REG_LM_OFFSET(mixer->num);
 
 	if ((img->width > MDSS_MDP_CURSOR_WIDTH) ||
-	    (img->height > MDSS_MDP_CURSOR_HEIGHT) ||
-	    (img->depth != 32))
+		(img->height > MDSS_MDP_CURSOR_HEIGHT) ||
+		(img->depth != 32))
 		return -EINVAL;
 
 	pr_debug("mixer=%d enable=%x set=%x\n", mixer->num, cursor->enable,
@@ -1320,13 +1353,227 @@
 	return 0;
 }
 
+static int mdss_bl_scale_config(struct msm_fb_data_type *mfd,
+						struct mdp_bl_scale_data *data)
+{
+	int ret = 0;
+	int curr_bl;
+	mutex_lock(&mfd->lock);
+	curr_bl = mfd->bl_level;
+	mfd->bl_scale = data->scale;
+	mfd->bl_min_lvl = data->min_lvl;
+	pr_debug("update scale = %d, min_lvl = %d\n", mfd->bl_scale,
+							mfd->bl_min_lvl);
+
+	/* update current backlight to use new scaling*/
+	mdss_fb_set_backlight(mfd, curr_bl);
+	mutex_unlock(&mfd->lock);
+	return ret;
+}
+
+static int mdss_mdp_pp_ioctl(struct msm_fb_data_type *mfd,
+				void __user *argp)
+{
+	int ret;
+	struct msmfb_mdp_pp mdp_pp;
+	u32 copyback = 0;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+
+	ret = copy_from_user(&mdp_pp, argp, sizeof(mdp_pp));
+	if (ret)
+		return ret;
+
+	switch (mdp_pp.op) {
+	case mdp_op_pa_cfg:
+		ret = mdss_mdp_pa_config(mdp5_data->ctl,
+					&mdp_pp.data.pa_cfg_data,
+					&copyback);
+		break;
+
+	case mdp_op_pcc_cfg:
+		ret = mdss_mdp_pcc_config(mdp5_data->ctl,
+					&mdp_pp.data.pcc_cfg_data,
+					&copyback);
+		break;
+
+	case mdp_op_lut_cfg:
+		switch (mdp_pp.data.lut_cfg_data.lut_type) {
+		case mdp_lut_igc:
+			ret = mdss_mdp_igc_lut_config(
+					mdp5_data->ctl,
+					(struct mdp_igc_lut_data *)
+					&mdp_pp.data.lut_cfg_data.data,
+					&copyback);
+			break;
+
+		case mdp_lut_pgc:
+			ret = mdss_mdp_argc_config(
+				mdp5_data->ctl,
+				&mdp_pp.data.lut_cfg_data.data.pgc_lut_data,
+				&copyback);
+			break;
+
+		case mdp_lut_hist:
+			ret = mdss_mdp_hist_lut_config(
+				mdp5_data->ctl,
+				(struct mdp_hist_lut_data *)
+				&mdp_pp.data.lut_cfg_data.data, &copyback);
+			break;
+
+		default:
+			ret = -ENOTSUPP;
+			break;
+		}
+		break;
+	case mdp_op_dither_cfg:
+		ret = mdss_mdp_dither_config(
+				mdp5_data->ctl,
+				&mdp_pp.data.dither_cfg_data,
+				&copyback);
+		break;
+	case mdp_op_gamut_cfg:
+		ret = mdss_mdp_gamut_config(
+				mdp5_data->ctl,
+				&mdp_pp.data.gamut_cfg_data,
+				&copyback);
+		break;
+	case mdp_bl_scale_cfg:
+		ret = mdss_bl_scale_config(mfd, (struct mdp_bl_scale_data *)
+						&mdp_pp.data.bl_scale_data);
+		break;
+	default:
+		pr_err("Unsupported request to MDP_PP IOCTL.\n");
+		ret = -EINVAL;
+		break;
+	}
+	if ((ret == 0) && copyback)
+		ret = copy_to_user(argp, &mdp_pp, sizeof(struct msmfb_mdp_pp));
+	return ret;
+}
+
+static int mdss_mdp_histo_ioctl(struct msm_fb_data_type *mfd, u32 cmd,
+				void __user *argp)
+{
+	int ret = -ENOSYS;
+	struct mdp_histogram_data hist;
+	struct mdp_histogram_start_req hist_req;
+	u32 block, hist_data_addr = 0;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+
+	switch (cmd) {
+	case MSMFB_HISTOGRAM_START:
+		if (!mfd->panel_power_on)
+			return -EPERM;
+
+		ret = copy_from_user(&hist_req, argp, sizeof(hist_req));
+		if (ret)
+			return ret;
+
+		ret = mdss_mdp_histogram_start(mdp5_data->ctl, &hist_req);
+		break;
+
+	case MSMFB_HISTOGRAM_STOP:
+		ret = copy_from_user(&block, argp, sizeof(int));
+		if (ret)
+			return ret;
+
+		ret = mdss_mdp_histogram_stop(mdp5_data->ctl, block);
+		break;
+
+	case MSMFB_HISTOGRAM:
+		if (!mfd->panel_power_on)
+			return -EPERM;
+
+		ret = copy_from_user(&hist, argp, sizeof(hist));
+		if (ret)
+			return ret;
+
+		ret = mdss_mdp_hist_collect(mdp5_data->ctl, &hist,
+					&hist_data_addr);
+		if ((ret == 0) && hist_data_addr) {
+			ret = copy_to_user(hist.c0, (u32 *)hist_data_addr,
+				sizeof(u32) * hist.bin_cnt);
+			if (ret == 0)
+				ret = copy_to_user(argp, &hist,
+						   sizeof(hist));
+		}
+		break;
+	default:
+		break;
+	}
+	return ret;
+}
+
+static int mdss_fb_set_metadata(struct msm_fb_data_type *mfd,
+				struct msmfb_metadata *metadata)
+{
+	int ret = 0;
+	switch (metadata->op) {
+	case metadata_op_vic:
+		if (mfd->panel_info)
+			mfd->panel_info->vic =
+				metadata->data.video_info_code;
+		else
+			ret = -EINVAL;
+		break;
+	default:
+		pr_warn("unsupported request to MDP META IOCTL\n");
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
+static int mdss_fb_get_hw_caps(struct msm_fb_data_type *mfd,
+		struct mdss_hw_caps *caps)
+{
+	struct mdss_data_type *mdata = mfd_to_mdata(mfd);
+	caps->mdp_rev = mdata->mdp_rev;
+	caps->vig_pipes = mdata->nvig_pipes;
+	caps->rgb_pipes = mdata->nrgb_pipes;
+	caps->dma_pipes = mdata->ndma_pipes;
+	return 0;
+}
+
+static int mdss_fb_get_metadata(struct msm_fb_data_type *mfd,
+				struct msmfb_metadata *metadata)
+{
+	int ret = 0;
+	switch (metadata->op) {
+	case metadata_op_frame_rate:
+		metadata->data.panel_frame_rate =
+			mdss_get_panel_framerate(mfd);
+		break;
+	case metadata_op_get_caps:
+		ret = mdss_fb_get_hw_caps(mfd, &metadata->data.caps);
+		break;
+	default:
+		pr_warn("Unsupported request to MDP META IOCTL.\n");
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
 static int mdss_mdp_overlay_ioctl_handler(struct msm_fb_data_type *mfd,
 					  u32 cmd, void __user *argp)
 {
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 	struct mdp_overlay req;
 	int val, ret = -ENOSYS;
+	struct msmfb_metadata metadata;
 
 	switch (cmd) {
+	case MSMFB_MDP_PP:
+		ret = mdss_mdp_pp_ioctl(mfd, argp);
+		break;
+
+	case MSMFB_HISTOGRAM_START:
+	case MSMFB_HISTOGRAM_STOP:
+	case MSMFB_HISTOGRAM:
+		ret = mdss_mdp_histo_ioctl(mfd, cmd, argp);
+		break;
+
 	case MSMFB_OVERLAY_GET:
 		ret = copy_from_user(&req, argp, sizeof(req));
 		if (!ret) {
@@ -1364,7 +1611,7 @@
 
 	case MSMFB_OVERLAY_PLAY_ENABLE:
 		if (!copy_from_user(&val, argp, sizeof(val))) {
-			mfd->overlay_play_enable = val;
+			mdp5_data->overlay_play_enable = val;
 		} else {
 			pr_err("OVERLAY_PLAY_ENABLE failed (%d)\n", ret);
 			ret = -EFAULT;
@@ -1372,7 +1619,7 @@
 		break;
 
 	case MSMFB_OVERLAY_PLAY:
-		if (mfd->overlay_play_enable) {
+		if (mdp5_data->overlay_play_enable) {
 			struct msmfb_overlay_data data;
 
 			ret = copy_from_user(&data, argp, sizeof(data));
@@ -1392,7 +1639,7 @@
 		break;
 
 	case MSMFB_OVERLAY_PLAY_WAIT:
-		if (mfd->overlay_play_enable) {
+		if (mdp5_data->overlay_play_enable) {
 			struct msmfb_overlay_data data;
 
 			ret = copy_from_user(&data, argp, sizeof(data));
@@ -1419,9 +1666,23 @@
 		break;
 	case MSMFB_OVERLAY_COMMIT:
 		mdss_fb_wait_for_fence(mfd);
-		ret = mdss_mdp_overlay_kickoff(mfd->ctl);
+		ret = mfd->mdp.kickoff_fnc(mfd);
 		mdss_fb_signal_timeline(mfd);
 		break;
+	case MSMFB_METADATA_SET:
+		ret = copy_from_user(&metadata, argp, sizeof(metadata));
+		if (ret)
+			return ret;
+		ret = mdss_fb_set_metadata(mfd, &metadata);
+		break;
+	case MSMFB_METADATA_GET:
+		ret = copy_from_user(&metadata, argp, sizeof(metadata));
+		if (ret)
+			return ret;
+		ret = mdss_fb_get_metadata(mfd, &metadata);
+		if (!ret)
+			ret = copy_to_user(argp, &metadata, sizeof(metadata));
+		break;
 	default:
 		if (mfd->panel.type == WRITEBACK_PANEL)
 			ret = mdss_mdp_wb_ioctl_handler(mfd, cmd, argp);
@@ -1433,7 +1694,8 @@
 
 static int mdss_mdp_overlay_on(struct msm_fb_data_type *mfd)
 {
-	int rc = 0;
+	int rc;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 
 	if (!mfd)
 		return -ENODEV;
@@ -1441,7 +1703,7 @@
 	if (mfd->key != MFD_KEY)
 		return -EINVAL;
 
-	if (!mfd->ctl) {
+	if (!mdp5_data->ctl) {
 		struct mdss_mdp_ctl *ctl;
 		struct mdss_panel_data *pdata;
 
@@ -1466,22 +1728,22 @@
 				return rc;
 			}
 		}
-		mfd->ctl = ctl;
+		mdp5_data->ctl = ctl;
 	}
 
 	if (!mfd->panel_info->cont_splash_enabled) {
 		rc = mdss_mdp_overlay_start(mfd);
 		if (!IS_ERR_VALUE(rc) && (mfd->panel_info->type != DTV_PANEL))
-			rc = mdss_mdp_overlay_kickoff(mfd->ctl);
+			rc = mdss_mdp_overlay_kickoff(mfd);
 	} else {
-		rc = mdss_mdp_ctl_setup(mfd->ctl);
+		rc = mdss_mdp_ctl_setup(mdp5_data->ctl);
 		if (rc)
 			return rc;
 	}
 
-	if (!IS_ERR_VALUE(rc) && mfd->vsync_pending) {
-		mfd->vsync_pending = 0;
-		mdss_mdp_overlay_vsync_ctrl(mfd, mfd->vsync_pending);
+	if (!IS_ERR_VALUE(rc) && mdp5_data->vsync_pending) {
+		mdp5_data->vsync_pending = 0;
+		mdss_mdp_overlay_vsync_ctrl(mfd, mdp5_data->vsync_pending);
 	}
 
 	return rc;
@@ -1490,6 +1752,7 @@
 static int mdss_mdp_overlay_off(struct msm_fb_data_type *mfd)
 {
 	int rc;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 
 	if (!mfd)
 		return -ENODEV;
@@ -1497,22 +1760,22 @@
 	if (mfd->key != MFD_KEY)
 		return -EINVAL;
 
-	if (!mfd->ctl) {
+	if (!mdp5_data->ctl) {
 		pr_err("ctl not initialized\n");
 		return -ENODEV;
 	}
 
-	if (!mfd->ctl->power_on)
+	if (!mdp5_data->ctl->power_on)
 		return 0;
 
 	mdss_mdp_overlay_release_all(mfd);
 
-	rc = mdss_mdp_ctl_stop(mfd->ctl);
+	rc = mdss_mdp_ctl_stop(mdp5_data->ctl);
 	if (rc == 0) {
 		if (!mfd->ref_cnt) {
-			mfd->borderfill_enable = false;
-			mdss_mdp_ctl_destroy(mfd->ctl);
-			mfd->ctl = NULL;
+			mdp5_data->borderfill_enable = false;
+			mdss_mdp_ctl_destroy(mdp5_data->ctl);
+			mdp5_data->ctl = NULL;
 		}
 
 		if (atomic_dec_return(&ov_active_panels) == 0)
@@ -1526,39 +1789,63 @@
 	return rc;
 }
 
+int mdss_panel_register_done(struct mdss_panel_data *pdata)
+{
+	/*
+	 * Clocks are already on if continuous splash is enabled,
+	 * increasing ref_cnt to help balance clocks once done.
+	 */
+	if (pdata->panel_info.cont_splash_enabled) {
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+		mdss_mdp_footswitch_ctrl_splash(1);
+		mdss_mdp_copy_splash_screen(pdata);
+	}
+	return 0;
+}
+
 int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd)
 {
 	struct device *dev = mfd->fbi->dev;
+	struct msm_mdp_interface *mdp5_interface = &mfd->mdp;
+	struct mdss_overlay_private *mdp5_data = NULL;
 	int rc;
 
-	mfd->mdata = dev_get_drvdata(mfd->pdev->dev.parent);
-	if (!mfd->mdata) {
-		pr_err("unable to initialize overlay for fb%d\n", mfd->index);
-		return -ENODEV;
+	mdp5_interface->on_fnc = mdss_mdp_overlay_on;
+	mdp5_interface->off_fnc = mdss_mdp_overlay_off;
+	mdp5_interface->do_histogram = NULL;
+	mdp5_interface->cursor_update = mdss_mdp_hw_cursor_update;
+	mdp5_interface->dma_fnc = mdss_mdp_overlay_pan_display;
+	mdp5_interface->ioctl_handler = mdss_mdp_overlay_ioctl_handler;
+	mdp5_interface->panel_register_done = mdss_panel_register_done;
+	mdp5_interface->kickoff_fnc = mdss_mdp_overlay_kickoff;
+
+	mdp5_data = kmalloc(sizeof(struct mdss_overlay_private), GFP_KERNEL);
+	if (!mdp5_data) {
+		pr_err("fail to allocate mdp5 private data structure");
+		return -ENOMEM;
 	}
+	memset(mdp5_data, 0, sizeof(struct mdss_overlay_private));
 
-	mfd->on_fnc = mdss_mdp_overlay_on;
-	mfd->off_fnc = mdss_mdp_overlay_off;
-	mfd->hw_refresh = true;
-	mfd->do_histogram = NULL;
-	mfd->overlay_play_enable = true;
-	mfd->cursor_update = mdss_mdp_hw_cursor_update;
-	mfd->dma_fnc = mdss_mdp_overlay_pan_display;
-	mfd->ioctl_handler = mdss_mdp_overlay_ioctl_handler;
+	INIT_LIST_HEAD(&mdp5_data->pipes_used);
+	INIT_LIST_HEAD(&mdp5_data->pipes_cleanup);
+	init_completion(&mdp5_data->vsync_comp);
+	spin_lock_init(&mdp5_data->vsync_lock);
+	mutex_init(&mdp5_data->ov_lock);
+	mdp5_data->hw_refresh = true;
+	mdp5_data->overlay_play_enable = true;
 
-	if (mfd->panel.type == WRITEBACK_PANEL)
-		mfd->kickoff_fnc = mdss_mdp_wb_kickoff;
-
-	INIT_LIST_HEAD(&mfd->pipes_used);
-	INIT_LIST_HEAD(&mfd->pipes_cleanup);
-	init_completion(&mfd->vsync_comp);
-	spin_lock_init(&mfd->vsync_lock);
-	mutex_init(&mfd->ov_lock);
+	mdp5_data->mdata = dev_get_drvdata(mfd->pdev->dev.parent);
+	if (!mdp5_data->mdata) {
+		pr_err("unable to initialize overlay for fb%d\n", mfd->index);
+		rc = -ENODEV;
+		goto init_fail;
+	}
+	mfd->mdp.private1 = mdp5_data;
 
 	rc = sysfs_create_group(&dev->kobj, &vsync_fs_attr_group);
 	if (rc) {
 		pr_err("vsync sysfs group creation failed, ret=%d\n", rc);
-		return rc;
+		goto init_fail;
 	}
 
 	pm_runtime_set_suspended(&mfd->pdev->dev);
@@ -1568,4 +1855,7 @@
 	pr_debug("vsync kobject_uevent(KOBJ_ADD)\n");
 
 	return rc;
+init_fail:
+	kfree(mdp5_data);
+	return rc;
 }
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index ca741b1..b169c43 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -119,25 +119,32 @@
 	u32 num_blks = 0, reserved = 0;
 	struct mdss_mdp_plane_sizes ps;
 	int i, rc;
+	u32 nlines;
 
-	if ((mdata->mdp_rev >= MDSS_MDP_HW_REV_102) &&
+	if (pipe->bwc_mode) {
+		rc = mdss_mdp_get_rau_strides(pipe->src.w, pipe->src.h,
+			pipe->src_fmt, &ps);
+		if (rc)
+			return rc;
+		pr_debug("BWC SMP strides ystride0=%x ystride1=%x\n",
+			ps.ystride[0], ps.ystride[1]);
+	} else if ((mdata->mdp_rev >= MDSS_MDP_HW_REV_102) &&
 			pipe->src_fmt->is_yuv) {
 		ps.num_planes = 2;
 		ps.ystride[0] = pipe->src.w;
 		ps.ystride[1] = pipe->src.w;
 	} else {
 		rc = mdss_mdp_get_plane_sizes(pipe->src_fmt->format,
-				pipe->src.w, pipe->src.h, &ps);
+			pipe->src.w, pipe->src.h, &ps, 0);
 		if (rc)
 			return rc;
 	}
 
-	if ((ps.num_planes > 1) && (pipe->type == MDSS_MDP_PIPE_TYPE_RGB))
-		return -EINVAL;
-
 	mutex_lock(&mdss_mdp_smp_lock);
 	for (i = 0; i < ps.num_planes; i++) {
-		num_blks = DIV_ROUND_UP(2 * ps.ystride[i], SMP_MB_SIZE);
+		nlines = pipe->bwc_mode ? ps.rau_h[i] : 2;
+		num_blks = DIV_ROUND_UP(nlines * ps.ystride[i],
+			mdss_res->smp_mb_size);
 
 		if (mdata->mdp_rev == MDSS_MDP_HW_REV_100)
 			num_blks = roundup_pow_of_two(num_blks);
@@ -341,6 +348,8 @@
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 	mdss_mdp_pipe_sspp_term(pipe);
 	mdss_mdp_smp_free(pipe);
+	pipe->flags = 0;
+	pipe->bwc_mode = 0;
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 
 	return 0;
@@ -376,7 +385,7 @@
 	width = pipe->img_width;
 	height = pipe->img_height;
 	mdss_mdp_get_plane_sizes(pipe->src_fmt->format, width, height,
-			&pipe->src_planes);
+			&pipe->src_planes, pipe->bwc_mode);
 
 	if ((pipe->flags & MDP_DEINTERLACE) &&
 			!(pipe->flags & MDP_SOURCE_ROTATED_90)) {
@@ -416,8 +425,9 @@
 static int mdss_mdp_format_setup(struct mdss_mdp_pipe *pipe)
 {
 	struct mdss_mdp_format_params *fmt;
-	u32 opmode, chroma_samp, unpack, src_format;
+	u32 chroma_samp, unpack, src_format;
 	u32 secure = 0;
+	u32 opmode;
 
 	fmt = pipe->src_fmt;
 
@@ -554,8 +564,7 @@
 
 	pr_debug("pnum=%d\n", pipe->num);
 
-	if (!is_rot)
-		data->bwc_enabled = pipe->bwc_mode;
+	data->bwc_enabled = pipe->bwc_mode;
 
 	ret = mdss_mdp_data_check(data, &pipe->src_planes);
 	if (ret)
diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.c b/drivers/video/msm/mdss/mdss_mdp_rotator.c
index 8bff5cb..5711653 100644
--- a/drivers/video/msm/mdss/mdss_mdp_rotator.c
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.c
@@ -203,7 +203,6 @@
 		rot_pipe->img_height = rot->img_height;
 		rot_pipe->src = rot->src_rect;
 		rot_pipe->dst = rot->src_rect;
-		rot_pipe->bwc_mode = rot->bwc_mode;
 		rot_pipe->params_changed++;
 	}
 
diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.h b/drivers/video/msm/mdss/mdss_mdp_rotator.h
index c46f271..21ee9bb 100644
--- a/drivers/video/msm/mdss/mdss_mdp_rotator.h
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.h
@@ -45,10 +45,14 @@
 static inline u32 mdss_mdp_get_rotator_dst_format(u32 in_format)
 {
 	switch (in_format) {
+	case MDP_RGB_565:
+	case MDP_BGR_565:
+		return MDP_RGB_888;
 	case MDP_Y_CBCR_H2V2_VENUS:
-		return MDP_Y_CBCR_H2V2;
+	case MDP_Y_CB_CR_H2V2:
 	case MDP_Y_CR_CB_GH2V2:
-		return MDP_Y_CR_CB_H2V2;
+	case MDP_Y_CR_CB_H2V2:
+		return MDP_Y_CRCB_H2V2;
 	default:
 		return in_format;
 	}
diff --git a/drivers/video/msm/mdss/mdss_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c
index 8ce5ab5..5915f61 100644
--- a/drivers/video/msm/mdss/mdss_mdp_util.c
+++ b/drivers/video/msm/mdss/mdss_mdp_util.c
@@ -221,11 +221,48 @@
 	return NULL;
 }
 
+int mdss_mdp_get_rau_strides(u32 w, u32 h,
+			       struct mdss_mdp_format_params *fmt,
+			       struct mdss_mdp_plane_sizes *ps)
+{
+	u32 stride_off;
+	if (fmt->is_yuv) {
+		ps->rau_cnt = DIV_ROUND_UP(w, 64);
+		ps->ystride[0] = 64 * 4;
+		ps->rau_h[0] = 4;
+		ps->rau_h[1] = 2;
+		if (fmt->chroma_sample == MDSS_MDP_CHROMA_H1V2)
+			ps->ystride[1] = 64 * 2;
+		else if (fmt->chroma_sample == MDSS_MDP_CHROMA_H2V1) {
+			ps->ystride[1] = 32 * 4;
+			ps->rau_h[1] = 4;
+		} else
+			ps->ystride[1] = 32 * 2;
+	} else if (fmt->fetch_planes == MDSS_MDP_PLANE_INTERLEAVED) {
+		ps->rau_cnt = DIV_ROUND_UP(w, 32);
+		ps->ystride[0] = 32 * 4;
+		ps->ystride[1] = 0;
+		ps->rau_h[0] = 4;
+		ps->rau_h[1] = 0;
+	} else  {
+		pr_err("Invalid format=%d\n", fmt->format);
+		return -EINVAL;
+	}
+
+	stride_off = DIV_ROUND_UP(ps->rau_cnt, 8);
+	ps->ystride[0] = ps->ystride[0] * ps->rau_cnt * fmt->bpp + stride_off;
+	ps->ystride[1] = ps->ystride[1] * ps->rau_cnt * fmt->bpp + stride_off;
+	ps->num_planes = 2;
+
+	return 0;
+}
+
 int mdss_mdp_get_plane_sizes(u32 format, u32 w, u32 h,
-			     struct mdss_mdp_plane_sizes *ps)
+			     struct mdss_mdp_plane_sizes *ps, u32 bwc_mode)
 {
 	struct mdss_mdp_format_params *fmt;
-	int i;
+	int i, rc;
+	u32 bpp, stride_off;
 
 	if (ps == NULL)
 		return -EINVAL;
@@ -237,55 +274,69 @@
 	if (!fmt)
 		return -EINVAL;
 
+	bpp = fmt->bpp;
 	memset(ps, 0, sizeof(struct mdss_mdp_plane_sizes));
 
-	if (fmt->fetch_planes == MDSS_MDP_PLANE_INTERLEAVED) {
-		u32 bpp = fmt->bpp;
-		ps->num_planes = 1;
-		ps->plane_size[0] = w * h * bpp;
-		ps->ystride[0] = w * bpp;
-	} else if (format == MDP_Y_CBCR_H2V2_VENUS) {
-		int cf = COLOR_FMT_NV12;
-		ps->num_planes = 2;
-		ps->ystride[0] = VENUS_Y_STRIDE(cf, w);
-		ps->ystride[1] = VENUS_UV_STRIDE(cf, w);
-		ps->plane_size[0] = VENUS_Y_SCANLINES(cf, h) * ps->ystride[0];
-		ps->plane_size[1] = VENUS_UV_SCANLINES(cf, h) * ps->ystride[1];
+	if (bwc_mode) {
+		rc = mdss_mdp_get_rau_strides(w, h, fmt, ps);
+		if (rc)
+			return rc;
+		stride_off = DIV_ROUND_UP(h, ps->rau_h[0]);
+		ps->ystride[0] = ps->ystride[0] + ps->ystride[1];
+		ps->plane_size[0] = ps->ystride[0] * stride_off;
+		ps->ystride[1] = 2;
+		ps->plane_size[1] = ps->rau_cnt * ps->ystride[1] * stride_off;
+
 	} else {
-		u8 hmap[] = { 1, 2, 1, 2 };
-		u8 vmap[] = { 1, 1, 2, 2 };
-		u8 horiz, vert, stride_align, height_align;
-
-		horiz = hmap[fmt->chroma_sample];
-		vert = vmap[fmt->chroma_sample];
-
-		switch (format) {
-		case MDP_Y_CR_CB_GH2V2:
-			stride_align = 16;
-			height_align = 1;
-			break;
-		default:
-			stride_align = 1;
-			height_align = 1;
-			break;
-		}
-
-		ps->ystride[0] = ALIGN(w, stride_align);
-		ps->ystride[1] = ALIGN(w / horiz, stride_align);
-		ps->plane_size[0] = ps->ystride[0] * ALIGN(h, height_align);
-		ps->plane_size[1] = ps->ystride[1] * (h / vert);
-
-		if (fmt->fetch_planes == MDSS_MDP_PLANE_PSEUDO_PLANAR) {
+		if (fmt->fetch_planes == MDSS_MDP_PLANE_INTERLEAVED) {
+			ps->num_planes = 1;
+			ps->plane_size[0] = w * h * bpp;
+			ps->ystride[0] = w * bpp;
+		} else if (format == MDP_Y_CBCR_H2V2_VENUS) {
+			int cf = COLOR_FMT_NV12;
 			ps->num_planes = 2;
-			ps->plane_size[1] *= 2;
-			ps->ystride[1] *= 2;
-		} else { /* planar */
-			ps->num_planes = 3;
-			ps->plane_size[2] = ps->plane_size[1];
-			ps->ystride[2] = ps->ystride[1];
+			ps->ystride[0] = VENUS_Y_STRIDE(cf, w);
+			ps->ystride[1] = VENUS_UV_STRIDE(cf, w);
+			ps->plane_size[0] = VENUS_Y_SCANLINES(cf, h) *
+				ps->ystride[0];
+			ps->plane_size[1] = VENUS_UV_SCANLINES(cf, h) *
+				ps->ystride[1];
+		} else {
+			u8 hmap[] = { 1, 2, 1, 2 };
+			u8 vmap[] = { 1, 1, 2, 2 };
+			u8 horiz, vert, stride_align, height_align;
+
+			horiz = hmap[fmt->chroma_sample];
+			vert = vmap[fmt->chroma_sample];
+
+			switch (format) {
+			case MDP_Y_CR_CB_GH2V2:
+				stride_align = 16;
+				height_align = 1;
+				break;
+			default:
+				stride_align = 1;
+				height_align = 1;
+				break;
+			}
+
+			ps->ystride[0] = ALIGN(w, stride_align);
+			ps->ystride[1] = ALIGN(w / horiz, stride_align);
+			ps->plane_size[0] = ps->ystride[0] *
+				ALIGN(h, height_align);
+			ps->plane_size[1] = ps->ystride[1] * (h / vert);
+
+			if (fmt->fetch_planes == MDSS_MDP_PLANE_PSEUDO_PLANAR) {
+				ps->num_planes = 2;
+				ps->plane_size[1] *= 2;
+				ps->ystride[1] *= 2;
+			} else { /* planar */
+				ps->num_planes = 3;
+				ps->plane_size[2] = ps->plane_size[1];
+				ps->ystride[2] = ps->ystride[1];
+			}
 		}
 	}
-
 	for (i = 0; i < ps->num_planes; i++)
 		ps->total_size += ps->plane_size[i];
 
@@ -302,7 +353,8 @@
 		return -ENOMEM;
 
 	if (data->bwc_enabled) {
-		return -EPERM; /* not supported */
+		data->num_planes = ps->num_planes;
+		data->p[1].addr = data->p[0].addr + ps->plane_size[0];
 	} else {
 		struct mdss_mdp_img_data *prev, *curr;
 		int i;
diff --git a/drivers/video/msm/mdss/mdss_mdp_wb.c b/drivers/video/msm/mdss/mdss_mdp_wb.c
index d24a7c9..88e7605 100644
--- a/drivers/video/msm/mdss/mdss_mdp_wb.c
+++ b/drivers/video/msm/mdss/mdss_mdp_wb.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -124,18 +124,13 @@
 
 int mdss_mdp_wb_set_secure(struct msm_fb_data_type *mfd, int enable)
 {
-	struct mdss_mdp_wb *wb;
+	struct mdss_mdp_wb *wb = mfd_to_wb(mfd);
+	struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
 	struct mdss_mdp_pipe *pipe;
 	struct mdss_mdp_mixer *mixer;
 
 	pr_debug("setting secure=%d\n", enable);
 
-	wb = mfd->wb;
-	if (wb == NULL) {
-		pr_err("Invalid writeback session\n");
-		return -ENODEV;
-	}
-
 	wb->is_secure = enable;
 	pipe = wb->secure_pipe;
 
@@ -149,7 +144,7 @@
 		return 0;
 	}
 
-	mixer = mdss_mdp_mixer_get(mfd->ctl, MDSS_MDP_MIXER_MUX_DEFAULT);
+	mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_DEFAULT);
 	if (!mixer) {
 		pr_err("Unable to find mixer for wb\n");
 		return -ENOENT;
@@ -190,14 +185,14 @@
 
 static int mdss_mdp_wb_init(struct msm_fb_data_type *mfd)
 {
-	struct mdss_mdp_wb *wb;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+	struct mdss_mdp_wb *wb = mfd_to_wb(mfd);
 
 	mutex_lock(&mdss_mdp_wb_buf_lock);
-	wb = mfd->wb;
 	if (wb == NULL) {
 		wb = &mdss_mdp_wb_info;
 		wb->fb_ndx = mfd->index;
-		mfd->wb = wb;
+		mdp5_data->wb = wb;
 	} else if (mfd->index != wb->fb_ndx) {
 		pr_err("only one writeback intf supported at a time\n");
 		return -EMLINK;
@@ -214,14 +209,15 @@
 	wb->state = WB_OPEN;
 	init_waitqueue_head(&wb->wait_q);
 
-	mfd->wb = wb;
+	mdp5_data->wb = wb;
 	mutex_unlock(&mdss_mdp_wb_buf_lock);
 	return 0;
 }
 
 static int mdss_mdp_wb_terminate(struct msm_fb_data_type *mfd)
 {
-	struct mdss_mdp_wb *wb = mfd->wb;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+	struct mdss_mdp_wb *wb = mfd_to_wb(mfd);
 
 	if (!wb) {
 		pr_err("unable to terminate, writeback is not initialized\n");
@@ -246,7 +242,7 @@
 		mdss_mdp_pipe_destroy(wb->secure_pipe);
 	mutex_unlock(&wb->lock);
 
-	mfd->wb = NULL;
+	mdp5_data->wb = NULL;
 	mutex_unlock(&mdss_mdp_wb_buf_lock);
 
 	return 0;
@@ -254,7 +250,7 @@
 
 static int mdss_mdp_wb_start(struct msm_fb_data_type *mfd)
 {
-	struct mdss_mdp_wb *wb = mfd->wb;
+	struct mdss_mdp_wb *wb = mfd_to_wb(mfd);
 
 	if (!wb) {
 		pr_err("unable to start, writeback is not initialized\n");
@@ -271,7 +267,7 @@
 
 static int mdss_mdp_wb_stop(struct msm_fb_data_type *mfd)
 {
-	struct mdss_mdp_wb *wb = mfd->wb;
+	struct mdss_mdp_wb *wb = mfd_to_wb(mfd);
 
 	if (!wb) {
 		pr_err("unable to stop, writeback is not initialized\n");
@@ -343,8 +339,10 @@
 }
 
 static struct mdss_mdp_wb_data *get_user_node(struct msm_fb_data_type *mfd,
-					      struct msmfb_data *data) {
-	struct mdss_mdp_wb *wb = mfd->wb;
+						struct msmfb_data *data)
+{
+
+	struct mdss_mdp_wb *wb = mfd_to_wb(mfd);
 	struct mdss_mdp_wb_data *node;
 	struct mdss_mdp_img_data *buf;
 	int ret;
@@ -383,9 +381,9 @@
 }
 
 static int mdss_mdp_wb_queue(struct msm_fb_data_type *mfd,
-			     struct msmfb_data *data, int local)
+				struct msmfb_data *data, int local)
 {
-	struct mdss_mdp_wb *wb = mfd->wb;
+	struct mdss_mdp_wb *wb = mfd_to_wb(mfd);
 	struct mdss_mdp_wb_data *node = NULL;
 	int ret = 0;
 
@@ -426,9 +424,9 @@
 }
 
 static int mdss_mdp_wb_dequeue(struct msm_fb_data_type *mfd,
-			       struct msmfb_data *data)
+				struct msmfb_data *data)
 {
-	struct mdss_mdp_wb *wb = mfd->wb;
+	struct mdss_mdp_wb *wb = mfd_to_wb(mfd);
 	struct mdss_mdp_wb_data *node = NULL;
 	int ret;
 
@@ -473,9 +471,10 @@
 		complete((struct completion *) arg);
 }
 
-int mdss_mdp_wb_kickoff(struct mdss_mdp_ctl *ctl)
+int mdss_mdp_wb_kickoff(struct msm_fb_data_type *mfd)
 {
-	struct mdss_mdp_wb *wb;
+	struct mdss_mdp_wb *wb = mfd_to_wb(mfd);
+	struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
 	struct mdss_mdp_wb_data *node = NULL;
 	int ret = 0;
 	DECLARE_COMPLETION_ONSTACK(comp);
@@ -484,14 +483,10 @@
 		.priv_data = &comp,
 	};
 
-	if (!ctl || !ctl->mfd)
-		return -ENODEV;
-
 	if (!ctl->power_on)
 		return 0;
 
 	mutex_lock(&mdss_mdp_wb_buf_lock);
-	wb = ctl->mfd->wb;
 	if (wb) {
 		mutex_lock(&wb->lock);
 		/* in case of reinit of control path need to reset secure */
@@ -540,7 +535,8 @@
 	return ret;
 }
 
-int mdss_mdp_wb_ioctl_handler(struct msm_fb_data_type *mfd, u32 cmd, void *arg)
+int mdss_mdp_wb_ioctl_handler(struct msm_fb_data_type *mfd, u32 cmd,
+				void *arg)
 {
 	struct msmfb_data data;
 	int ret = -ENOSYS;
diff --git a/drivers/video/msm/mdss/mdss_qpic.c b/drivers/video/msm/mdss/mdss_qpic.c
index 647504f..be02113 100644
--- a/drivers/video/msm/mdss/mdss_qpic.c
+++ b/drivers/video/msm/mdss/mdss_qpic.c
@@ -113,11 +113,24 @@
 		(u32 *)fb_offset, size);
 }
 
-int mdss_mdp_alloc_fb_mem(struct msm_fb_data_type *mfd,
-			u32 size, u32 *phys, void **virt)
+int mdss_qpic_alloc_fb_mem(struct msm_fb_data_type *mfd)
 {
+	size_t size;
+	u32 yres = mfd->fbi->var.yres_virtual;
+
+	size = PAGE_ALIGN(mfd->fbi->fix.line_length * yres);
+
 	if (!qpic_res->res_init)
 		return -EINVAL;
+
+	if (mfd->index != 0) {
+		mfd->fbi->fix.smem_start = 0;
+		mfd->fbi->screen_base = NULL;
+		mfd->fbi->fix.smem_len = 0;
+		mfd->iova = 0;
+		return 0;
+	}
+
 	if (!qpic_res->fb_virt) {
 		qpic_res->fb_virt = (void *)dmam_alloc_coherent(
 						&qpic_res->pdev->dev,
@@ -132,29 +145,31 @@
 		qpic_res->cmd_buf_virt = qpic_res->fb_virt + size;
 		qpic_res->cmd_buf_phys = qpic_res->fb_phys + size;
 	}
-	*phys = qpic_res->fb_phys;
-	*virt = qpic_res->fb_virt;
+	mfd->fbi->fix.smem_start = qpic_res->fb_phys;
+	mfd->fbi->screen_base = qpic_res->fb_virt;
+	mfd->fbi->fix.smem_len = size;
+	mfd->iova = 0;
 	return 0;
 }
 
-u32 mdss_mdp_fb_stride(u32 fb_index, u32 xres, int bpp)
+u32 mdss_qpic_fb_stride(u32 fb_index, u32 xres, int bpp)
 {
 	return xres * bpp;
 }
 
-int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd)
+int mdss_qpic_overlay_init(struct msm_fb_data_type *mfd)
 {
-	mfd->on_fnc = qpic_on;
-	mfd->off_fnc = qpic_off;
-	mfd->dma_fnc = mdss_qpic_pan_display;
+	struct msm_mdp_interface *qpic_interface = &mfd->mdp;
+	qpic_interface->on_fnc = qpic_on;
+	qpic_interface->off_fnc = qpic_off;
+	qpic_interface->do_histogram = NULL;
+	qpic_interface->cursor_update = NULL;
+	qpic_interface->dma_fnc = mdss_qpic_pan_display;
+	qpic_interface->ioctl_handler = NULL;
+	qpic_interface->kickoff_fnc = NULL;
 	return 0;
 }
 
-u32 mdss_get_panel_framerate(struct msm_fb_data_type *mfd)
-{
-	return qpic_panel_get_framerate();
-}
-
 int qpic_register_panel(struct mdss_panel_data *pdata)
 {
 	struct platform_device *mdss_fb_dev = NULL;
@@ -511,6 +526,12 @@
 {
 	struct resource *res;
 	int rc = 0;
+	static struct msm_mdp_interface qpic_interface = {
+		.init_fnc = mdss_qpic_overlay_init,
+		.fb_mem_alloc_fnc = mdss_qpic_alloc_fb_mem,
+		.fb_stride = mdss_qpic_fb_stride,
+	};
+
 
 	if (!pdev->dev.of_node) {
 		pr_err("qpic driver only supports device tree probe\n");
@@ -564,6 +585,11 @@
 
 	qpic_res->irq = res->start;
 	qpic_res->res_init = true;
+
+	rc = mdss_fb_register_mdp_instance(&qpic_interface);
+	if (rc)
+		pr_err("unable to register QPIC instance\n");
+
 probe_done:
 	return rc;
 }
@@ -585,124 +611,4 @@
 
 module_init(mdss_qpic_driver_init);
 
-int mdss_mdp_pa_config(struct mdss_mdp_ctl *ctl,
-	struct mdp_pa_cfg_data *config, u32 *copyback)
-{
-	return 0;
-}
 
-int mdss_mdp_pcc_config(struct mdss_mdp_ctl *ctl,
-	struct mdp_pcc_cfg_data *cfg_ptr, u32 *copyback)
-{
-	return 0;
-}
-
-int mdss_mdp_igc_lut_config(struct mdss_mdp_ctl *ctl,
-	struct mdp_igc_lut_data *config, u32 *copyback)
-{
-	return 0;
-}
-
-int mdss_mdp_argc_config(struct mdss_mdp_ctl *ctl,
-	struct mdp_pgc_lut_data *config, u32 *copyback)
-{
-	return 0;
-}
-
-int mdss_mdp_hist_lut_config(struct mdss_mdp_ctl *ctl,
-	struct mdp_hist_lut_data *config, u32 *copyback)
-{
-	return 0;
-}
-
-int mdss_mdp_dither_config(struct mdss_mdp_ctl *ctl,
-	struct mdp_dither_cfg_data *config, u32 *copyback)
-{
-	return 0;
-}
-
-int mdss_mdp_gamut_config(struct mdss_mdp_ctl *ctl,
-	struct mdp_gamut_cfg_data *config, u32 *copyback)
-{
-	return 0;
-}
-
-int mdss_mdp_histogram_start(struct mdss_mdp_ctl *ctl,
-	struct mdp_histogram_start_req *req)
-{
-	return 0;
-}
-
-int mdss_mdp_histogram_stop(struct mdss_mdp_ctl *ctl, u32 block)
-{
-	return 0;
-}
-
-int mdss_mdp_hist_collect(struct mdss_mdp_ctl *ctl,
-				struct mdp_histogram_data *hist,
-				u32 *hist_data_addr)
-{
-	return 0;
-}
-
-int mdss_mdp_overlay_kickoff(struct mdss_mdp_ctl *ctl)
-{
-	return 0;
-}
-
-void mdss_mdp_clk_ctrl(int enable, int isr)
-{
-}
-
-int mdss_mdp_copy_splash_screen(struct mdss_panel_data *pdata)
-{
-	return 0;
-}
-
-void mdss_mdp_footswitch_ctrl_splash(int on)
-{
-}
-
-int msm_fb_writeback_init(struct fb_info *info)
-{
-	return 0;
-}
-EXPORT_SYMBOL(msm_fb_writeback_init);
-
-int msm_fb_writeback_start(struct fb_info *info)
-{
-	return 0;
-}
-EXPORT_SYMBOL(msm_fb_writeback_start);
-
-int msm_fb_writeback_queue_buffer(struct fb_info *info,
-		struct msmfb_data *data)
-{
-	return 0;
-}
-EXPORT_SYMBOL(msm_fb_writeback_queue_buffer);
-
-int msm_fb_writeback_dequeue_buffer(struct fb_info *info,
-		struct msmfb_data *data)
-{
-	return 0;
-}
-EXPORT_SYMBOL(msm_fb_writeback_dequeue_buffer);
-
-int msm_fb_writeback_stop(struct fb_info *info)
-{
-	return 0;
-}
-EXPORT_SYMBOL(msm_fb_writeback_stop);
-
-int msm_fb_writeback_terminate(struct fb_info *info)
-{
-	return 0;
-}
-EXPORT_SYMBOL(msm_fb_writeback_terminate);
-
-int msm_fb_get_iommu_domain(struct fb_info *info, int domain)
-{
-	return 0;
-}
-EXPORT_SYMBOL(msm_fb_get_iommu_domain);
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index 7939832..969b400 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -20,6 +20,7 @@
 #define DEINIT_TYPE			16
 #define USER_SPACE_DATA_TYPE		32
 #define DCI_DATA_TYPE			64
+#define CALLBACK_DATA_TYPE		128
 #define USB_MODE			1
 #define MEMORY_DEVICE_MODE		2
 #define NO_LOGGING_MODE			3
diff --git a/include/linux/mfd/pm8xxx/pm8921-bms.h b/include/linux/mfd/pm8xxx/pm8921-bms.h
index 5e6a8c3..a19c0b6 100644
--- a/include/linux/mfd/pm8xxx/pm8921-bms.h
+++ b/include/linux/mfd/pm8xxx/pm8921-bms.h
@@ -167,6 +167,19 @@
  *			value upon wakeup from sleep.
  */
 int pm8921_bms_cc_uah(int *cc_uah);
+
+/**
+ * pm8921_bms_battery_removed -	function to be called to tell the bms that
+ *			the battery is removed. The bms resets its internal
+ *			history data used to report soc.
+ */
+void pm8921_bms_battery_removed(void);
+/**
+ * pm8921_bms_battery_inseted -	function to be called to tell the bms that
+ *			the battery was inserted. The bms initiates calculations
+ *			for reporting soc.
+ */
+void pm8921_bms_battery_inserted(void);
 #else
 static inline int pm8921_bms_get_vsense_avg(int *result)
 {
@@ -213,6 +226,8 @@
 {
 	return -ENXIO;
 }
+static inline void pm8921_bms_battery_removed(void) {}
+static inline void pm8921_bms_battery_inserted(void) {}
 #endif
 
 #endif
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index 5dc65bd..ca7a586 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -61,6 +61,14 @@
 	MIGRATE_TYPES
 };
 
+/*
+ * Returns a list which contains the migrate types on to which
+ * an allocation falls back when the free list for the migrate
+ * type mtype is depleted.
+ * The end of the list is delimited by the type MIGRATE_RESERVE.
+ */
+extern int *get_migratetype_fallbacks(int mtype);
+
 #ifdef CONFIG_CMA
 bool is_cma_pageblock(struct page *page);
 #  define is_migrate_cma(migratetype) unlikely((migratetype) == MIGRATE_CMA)
diff --git a/include/linux/msm_kgsl.h b/include/linux/msm_kgsl.h
index b7d393f..307be2b 100644
--- a/include/linux/msm_kgsl.h
+++ b/include/linux/msm_kgsl.h
@@ -200,6 +200,26 @@
 	unsigned int dev_minor;
 };
 
+/* Performance counter groups */
+
+#define KGSL_PERFCOUNTER_GROUP_CP 0x0
+#define KGSL_PERFCOUNTER_GROUP_RBBM 0x1
+#define KGSL_PERFCOUNTER_GROUP_PC 0x2
+#define KGSL_PERFCOUNTER_GROUP_VFD 0x3
+#define KGSL_PERFCOUNTER_GROUP_HLSQ 0x4
+#define KGSL_PERFCOUNTER_GROUP_VPC 0x5
+#define KGSL_PERFCOUNTER_GROUP_TSE 0x6
+#define KGSL_PERFCOUNTER_GROUP_RAS 0x7
+#define KGSL_PERFCOUNTER_GROUP_UCHE 0x8
+#define KGSL_PERFCOUNTER_GROUP_TP 0x9
+#define KGSL_PERFCOUNTER_GROUP_SP 0xA
+#define KGSL_PERFCOUNTER_GROUP_RB 0xB
+#define KGSL_PERFCOUNTER_GROUP_PWR 0xC
+#define KGSL_PERFCOUNTER_GROUP_VBIF 0xD
+#define KGSL_PERFCOUNTER_GROUP_VBIF_PWR 0xE
+
+#define KGSL_PERFCOUNTER_NOT_USED 0xFFFFFFFF
+
 /* structure holds list of ibs */
 struct kgsl_ibdesc {
 	unsigned int gpuaddr;
@@ -650,6 +670,110 @@
 #define IOCTL_KGSL_GPUMEM_SYNC_CACHE \
 	_IOW(KGSL_IOC_TYPE, 0x37, struct kgsl_gpumem_sync_cache)
 
+/**
+ * struct kgsl_perfcounter_get - argument to IOCTL_KGSL_PERFCOUNTER_GET
+ * @groupid: Performance counter group ID
+ * @countable: Countable to select within the group
+ * @offset: Return offset of the reserved counter
+ *
+ * Get an available performance counter from a specified groupid.  The offset
+ * of the performance counter will be returned after successfully assigning
+ * the countable to the counter for the specified group.  An error will be
+ * returned and an offset of 0 if the groupid is invalid or there are no
+ * more counters left.  After successfully getting a perfcounter, the user
+ * must call kgsl_perfcounter_put(groupid, contable) when finished with
+ * the perfcounter to clear up perfcounter resources.
+ *
+ */
+struct kgsl_perfcounter_get {
+	unsigned int groupid;
+	unsigned int countable;
+	unsigned int offset;
+/* private: reserved for future use */
+	unsigned int __pad[2]; /* For future binary compatibility */
+};
+
+#define IOCTL_KGSL_PERFCOUNTER_GET \
+	_IOWR(KGSL_IOC_TYPE, 0x38, struct kgsl_perfcounter_get)
+
+/**
+ * struct kgsl_perfcounter_put - argument to IOCTL_KGSL_PERFCOUNTER_PUT
+ * @groupid: Performance counter group ID
+ * @countable: Countable to release within the group
+ *
+ * Put an allocated performance counter to allow others to have access to the
+ * resource that was previously taken.  This is only to be called after
+ * successfully getting a performance counter from kgsl_perfcounter_get().
+ *
+ */
+struct kgsl_perfcounter_put {
+	unsigned int groupid;
+	unsigned int countable;
+/* private: reserved for future use */
+	unsigned int __pad[2]; /* For future binary compatibility */
+};
+
+#define IOCTL_KGSL_PERFCOUNTER_PUT \
+	_IOW(KGSL_IOC_TYPE, 0x39, struct kgsl_perfcounter_put)
+
+/**
+ * struct kgsl_perfcounter_query - argument to IOCTL_KGSL_PERFCOUNTER_QUERY
+ * @groupid: Performance counter group ID
+ * @countable: Return active countables array
+ * @size: Size of active countables array
+ * @max_counters: Return total number counters for the group ID
+ *
+ * Query the available performance counters given a groupid.  The array
+ * *countables is used to return the current active countables in counters.
+ * The size of the array is passed in so the kernel will only write at most
+ * size or counter->size for the group id.  The total number of available
+ * counters for the group ID is returned in max_counters.
+ * If the array or size passed in are invalid, then only the maximum number
+ * of counters will be returned, no data will be written to *countables.
+ * If the groupid is invalid an error code will be returned.
+ *
+ */
+struct kgsl_perfcounter_query {
+	unsigned int groupid;
+	/* Array to return the current countable for up to size counters */
+	unsigned int *countables;
+	unsigned int count;
+	unsigned int max_counters;
+/* private: reserved for future use */
+	unsigned int __pad[2]; /* For future binary compatibility */
+};
+
+#define IOCTL_KGSL_PERFCOUNTER_QUERY \
+	_IOWR(KGSL_IOC_TYPE, 0x3A, struct kgsl_perfcounter_query)
+
+/**
+ * struct kgsl_perfcounter_query - argument to IOCTL_KGSL_PERFCOUNTER_QUERY
+ * @groupid: Performance counter group IDs
+ * @countable: Performance counter countable IDs
+ * @value: Return performance counter reads
+ * @size: Size of all arrays (groupid/countable pair and return value)
+ *
+ * Read in the current value of a performance counter given by the groupid
+ * and countable.
+ *
+ */
+
+struct kgsl_perfcounter_read_group {
+	unsigned int groupid;
+	unsigned int countable;
+	uint64_t value;
+};
+
+struct kgsl_perfcounter_read {
+	struct kgsl_perfcounter_read_group *reads;
+	unsigned int count;
+/* private: reserved for future use */
+	unsigned int __pad[2]; /* For future binary compatibility */
+};
+
+#define IOCTL_KGSL_PERFCOUNTER_READ \
+	_IOWR(KGSL_IOC_TYPE, 0x3B, struct kgsl_perfcounter_read)
+
 #ifdef __KERNEL__
 #ifdef CONFIG_MSM_KGSL_DRM
 int kgsl_gem_obj_addr(int drm_fd, int handle, unsigned long *start,
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 5deff7a..7e1a709 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -170,7 +170,7 @@
 #define MDP_SECURE_OVERLAY_SESSION      0x00008000
 #define MDP_OV_PIPE_FORCE_DMA		0x00004000
 #define MDP_MEMORY_ID_TYPE_FB		0x00001000
-
+#define MDP_BWC_EN			0x00000400
 #define MDP_TRANSP_NOP 0xffffffff
 #define MDP_ALPHA_NOP 0xff
 
diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h
index fc6ab91..15e5dc9 100644
--- a/include/linux/qpnp/qpnp-adc.h
+++ b/include/linux/qpnp/qpnp-adc.h
@@ -1359,6 +1359,12 @@
 int32_t qpnp_iadc_vadc_sync_read(
 	enum qpnp_iadc_channels i_channel, struct qpnp_iadc_result *i_result,
 	enum qpnp_vadc_channels v_channel, struct qpnp_vadc_result *v_result);
+/**
+ * qpnp_iadc_calibrate_for_trim() - Clients can use this API to re-calibrate
+ *		IADC.
+ * @result:	0 on success.
+ */
+int32_t qpnp_iadc_calibrate_for_trim(void);
 #else
 static inline int32_t qpnp_iadc_read(enum qpnp_iadc_channels channel,
 						struct qpnp_iadc_result *result)
@@ -1374,6 +1380,8 @@
 	enum qpnp_iadc_channels i_channel, struct qpnp_iadc_result *i_result,
 	enum qpnp_vadc_channels v_channel, struct qpnp_vadc_result *v_result)
 { return -ENXIO; }
+static inline int32_t qpnp_iadc_calibrate_for_trim(void)
+{ return -ENXIO; }
 #endif
 
 /* Public API */
diff --git a/include/media/msmb_generic_buf_mgr.h b/include/media/msmb_generic_buf_mgr.h
index 17cb947..efcb425 100644
--- a/include/media/msmb_generic_buf_mgr.h
+++ b/include/media/msmb_generic_buf_mgr.h
@@ -9,6 +9,7 @@
 	uint32_t index;
 };
 
+struct v4l2_subdev *msm_buf_mngr_get_subdev(void);
 
 #define VIDIOC_MSM_BUF_MNGR_GET_BUF \
 	_IOWR('V', BASE_VIDIOC_PRIVATE + 33, struct msm_buf_mngr_info)
diff --git a/include/media/msmb_ispif.h b/include/media/msmb_ispif.h
index 3546004..f0f015e 100644
--- a/include/media/msmb_ispif.h
+++ b/include/media/msmb_ispif.h
@@ -64,14 +64,17 @@
 };
 
 struct msm_ispif_params_entry {
+	enum msm_ispif_vfe_intf vfe_intf;
 	enum msm_ispif_intftype intftype;
 	int num_cids;
 	enum msm_ispif_cid cids[3];
 	enum msm_ispif_csid csid;
+	int crop_enable;
+	uint16_t crop_start_pixel;
+	uint16_t crop_end_pixel;
 };
 
 struct msm_ispif_param_data {
-	enum msm_ispif_vfe_intf vfe_intf;
 	uint32_t num;
 	struct msm_ispif_params_entry entries[INTF_MAX];
 };
diff --git a/include/media/msmb_pproc.h b/include/media/msmb_pproc.h
index 6f8e865..9000774 100644
--- a/include/media/msmb_pproc.h
+++ b/include/media/msmb_pproc.h
@@ -11,6 +11,7 @@
 #define MAX_PLANES VIDEO_MAX_PLANES
 
 #define MAX_NUM_CPP_STRIPS 8
+#define MSM_CPP_MAX_NUM_PLANES 3
 
 enum msm_cpp_frame_type {
 	MSM_CPP_OFFLINE_FRAME,
@@ -74,9 +75,25 @@
 	int postscale_crop_en;
 };
 
+struct msm_cpp_buffer_info_t {
+	int fd;
+	uint32_t index;
+	uint32_t offset;
+	uint8_t native_buff;
+	uint8_t processed_divert;
+};
+
+struct msm_cpp_stream_buff_info_t {
+	uint32_t identity;
+	uint32_t num_buffs;
+	struct msm_cpp_buffer_info_t *buffer_info;
+};
+
 struct msm_cpp_frame_info_t {
 	int32_t frame_id;
+	struct timeval timestamp;
 	uint32_t inst_id;
+	uint32_t identity;
 	uint32_t client_id;
 	enum msm_cpp_frame_type frame_type;
 	uint32_t num_strips;
@@ -87,6 +104,11 @@
 	int dst_fd;
 	struct ion_handle *src_ion_handle;
 	struct ion_handle *dest_ion_handle;
+	struct timeval in_time, out_time;
+	void *cookie;
+
+	struct msm_cpp_buffer_info_t input_buffer_info;
+	struct msm_cpp_buffer_info_t output_buffer_info;
 };
 
 struct cpp_hw_info {
@@ -112,6 +134,12 @@
 #define VIDIOC_MSM_CPP_FLUSH_QUEUE \
 	_IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct msm_camera_v4l2_ioctl_t)
 
+#define VIDIOC_MSM_CPP_ENQUEUE_STREAM_BUFF_INFO \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 6, struct msm_camera_v4l2_ioctl_t)
+
+#define VIDIOC_MSM_CPP_DEQUEUE_STREAM_BUFF_INFO \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 7, struct msm_camera_v4l2_ioctl_t)
+
 #define V4L2_EVENT_CPP_FRAME_DONE  (V4L2_EVENT_PRIVATE_START + 0)
 
 struct msm_camera_v4l2_ioctl_t {
diff --git a/include/video/Kbuild b/include/video/Kbuild
index ad3e622..53e13cb 100644
--- a/include/video/Kbuild
+++ b/include/video/Kbuild
@@ -1,3 +1,4 @@
 header-y += edid.h
 header-y += sisfb.h
 header-y += uvesafb.h
+header-y += msm_hdmi_modes.h
diff --git a/include/video/msm_hdmi_modes.h b/include/video/msm_hdmi_modes.h
new file mode 100644
index 0000000..a15272b
--- /dev/null
+++ b/include/video/msm_hdmi_modes.h
@@ -0,0 +1,334 @@
+#ifndef __MSM_HDMI_MODES_H__
+#define __MSM_HDMI_MODES_H__
+#include <linux/types.h>
+
+struct msm_hdmi_mode_timing_info {
+	uint32_t	video_format;
+	uint32_t	active_h;
+	uint32_t	front_porch_h;
+	uint32_t	pulse_width_h;
+	uint32_t	back_porch_h;
+	uint32_t	active_low_h;
+	uint32_t	active_v;
+	uint32_t	front_porch_v;
+	uint32_t	pulse_width_v;
+	uint32_t	back_porch_v;
+	uint32_t	active_low_v;
+	/* Must divide by 1000 to get the actual frequency in MHZ */
+	uint32_t	pixel_freq;
+	/* Must divide by 1000 to get the actual frequency in HZ */
+	uint32_t	refresh_rate;
+	uint32_t	interlaced;
+	uint32_t	supported;
+};
+
+#define MSM_HDMI_MODES_CEA		(1 << 0)
+#define MSM_HDMI_MODES_XTND		(1 << 1)
+#define MSM_HDMI_MODES_DVI		(1 << 2)
+#define MSM_HDMI_MODES_ALL		(MSM_HDMI_MODES_CEA |\
+					 MSM_HDMI_MODES_XTND |\
+					 MSM_HDMI_MODES_DVI)
+
+/* all video formats defined by CEA 861D */
+#define HDMI_VFRMT_UNKNOWN		0
+#define HDMI_VFRMT_640x480p60_4_3	1
+#define HDMI_VFRMT_720x480p60_4_3	2
+#define HDMI_VFRMT_720x480p60_16_9	3
+#define HDMI_VFRMT_1280x720p60_16_9	4
+#define HDMI_VFRMT_1920x1080i60_16_9	5
+#define HDMI_VFRMT_720x480i60_4_3	6
+#define HDMI_VFRMT_1440x480i60_4_3	HDMI_VFRMT_720x480i60_4_3
+#define HDMI_VFRMT_720x480i60_16_9	7
+#define HDMI_VFRMT_1440x480i60_16_9	HDMI_VFRMT_720x480i60_16_9
+#define HDMI_VFRMT_720x240p60_4_3	8
+#define HDMI_VFRMT_1440x240p60_4_3	HDMI_VFRMT_720x240p60_4_3
+#define HDMI_VFRMT_720x240p60_16_9	9
+#define HDMI_VFRMT_1440x240p60_16_9	HDMI_VFRMT_720x240p60_16_9
+#define HDMI_VFRMT_2880x480i60_4_3	10
+#define HDMI_VFRMT_2880x480i60_16_9	11
+#define HDMI_VFRMT_2880x240p60_4_3	12
+#define HDMI_VFRMT_2880x240p60_16_9	13
+#define HDMI_VFRMT_1440x480p60_4_3	14
+#define HDMI_VFRMT_1440x480p60_16_9	15
+#define HDMI_VFRMT_1920x1080p60_16_9	16
+#define HDMI_VFRMT_720x576p50_4_3	17
+#define HDMI_VFRMT_720x576p50_16_9	18
+#define HDMI_VFRMT_1280x720p50_16_9	19
+#define HDMI_VFRMT_1920x1080i50_16_9	20
+#define HDMI_VFRMT_720x576i50_4_3	21
+#define HDMI_VFRMT_1440x576i50_4_3	HDMI_VFRMT_720x576i50_4_3
+#define HDMI_VFRMT_720x576i50_16_9	22
+#define HDMI_VFRMT_1440x576i50_16_9	HDMI_VFRMT_720x576i50_16_9
+#define HDMI_VFRMT_720x288p50_4_3	23
+#define HDMI_VFRMT_1440x288p50_4_3	HDMI_VFRMT_720x288p50_4_3
+#define HDMI_VFRMT_720x288p50_16_9	24
+#define HDMI_VFRMT_1440x288p50_16_9	HDMI_VFRMT_720x288p50_16_9
+#define HDMI_VFRMT_2880x576i50_4_3	25
+#define HDMI_VFRMT_2880x576i50_16_9	26
+#define HDMI_VFRMT_2880x288p50_4_3	27
+#define HDMI_VFRMT_2880x288p50_16_9	28
+#define HDMI_VFRMT_1440x576p50_4_3	29
+#define HDMI_VFRMT_1440x576p50_16_9	30
+#define HDMI_VFRMT_1920x1080p50_16_9	31
+#define HDMI_VFRMT_1920x1080p24_16_9	32
+#define HDMI_VFRMT_1920x1080p25_16_9	33
+#define HDMI_VFRMT_1920x1080p30_16_9	34
+#define HDMI_VFRMT_2880x480p60_4_3	35
+#define HDMI_VFRMT_2880x480p60_16_9	36
+#define HDMI_VFRMT_2880x576p50_4_3	37
+#define HDMI_VFRMT_2880x576p50_16_9	38
+#define HDMI_VFRMT_1920x1250i50_16_9	39
+#define HDMI_VFRMT_1920x1080i100_16_9	40
+#define HDMI_VFRMT_1280x720p100_16_9	41
+#define HDMI_VFRMT_720x576p100_4_3	42
+#define HDMI_VFRMT_720x576p100_16_9	43
+#define HDMI_VFRMT_720x576i100_4_3	44
+#define HDMI_VFRMT_1440x576i100_4_3	HDMI_VFRMT_720x576i100_4_3
+#define HDMI_VFRMT_720x576i100_16_9	45
+#define HDMI_VFRMT_1440x576i100_16_9	HDMI_VFRMT_720x576i100_16_9
+#define HDMI_VFRMT_1920x1080i120_16_9	46
+#define HDMI_VFRMT_1280x720p120_16_9	47
+#define HDMI_VFRMT_720x480p120_4_3	48
+#define HDMI_VFRMT_720x480p120_16_9	49
+#define HDMI_VFRMT_720x480i120_4_3	50
+#define HDMI_VFRMT_1440x480i120_4_3	HDMI_VFRMT_720x480i120_4_3
+#define HDMI_VFRMT_720x480i120_16_9	51
+#define HDMI_VFRMT_1440x480i120_16_9	HDMI_VFRMT_720x480i120_16_9
+#define HDMI_VFRMT_720x576p200_4_3	52
+#define HDMI_VFRMT_720x576p200_16_9	53
+#define HDMI_VFRMT_720x576i200_4_3	54
+#define HDMI_VFRMT_1440x576i200_4_3	HDMI_VFRMT_720x576i200_4_3
+#define HDMI_VFRMT_720x576i200_16_9	55
+#define HDMI_VFRMT_1440x576i200_16_9	HDMI_VFRMT_720x576i200_16_9
+#define HDMI_VFRMT_720x480p240_4_3	56
+#define HDMI_VFRMT_720x480p240_16_9	57
+#define HDMI_VFRMT_720x480i240_4_3	58
+#define HDMI_VFRMT_1440x480i240_4_3	HDMI_VFRMT_720x480i240_4_3
+#define HDMI_VFRMT_720x480i240_16_9	59
+#define HDMI_VFRMT_1440x480i240_16_9	HDMI_VFRMT_720x480i240_16_9
+#define HDMI_VFRMT_1280x720p24_16_9	60
+#define HDMI_VFRMT_1280x720p25_16_9	61
+#define HDMI_VFRMT_1280x720p30_16_9	62
+#define HDMI_VFRMT_1920x1080p120_16_9	63
+#define HDMI_VFRMT_1920x1080p100_16_9	64
+/* Video Identification Codes from 65-127 are reserved for the future */
+#define HDMI_VFRMT_END			127
+
+/* extended video formats */
+#define HDMI_VFRMT_3840x2160p30_16_9	(HDMI_VFRMT_END + 1)
+#define HDMI_VFRMT_3840x2160p25_16_9	(HDMI_VFRMT_END + 2)
+#define HDMI_VFRMT_3840x2160p24_16_9	(HDMI_VFRMT_END + 3)
+#define HDMI_VFRMT_4096x2160p24_16_9	(HDMI_VFRMT_END + 4)
+#define HDMI_EVFRMT_END			HDMI_VFRMT_4096x2160p24_16_9
+
+/* VESA DMT TIMINGS */
+#define HDMI_VFRMT_2560x1600p60_16_9	(HDMI_EVFRMT_END + 1)
+#define HDMI_VFRMT_1280x1024p60_5_4	(HDMI_EVFRMT_END + 2)
+#define VESA_DMT_VFRMT_END		HDMI_VFRMT_1280x1024p60_5_4
+#define HDMI_VFRMT_MAX			(VESA_DMT_VFRMT_END + 1)
+#define HDMI_VFRMT_FORCE_32BIT		0x7FFFFFFF
+
+/* Timing information for supported modes */
+#define VFRMT_NOT_SUPPORTED(VFRMT) \
+	{VFRMT, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false}
+
+#define HDMI_VFRMT_640x480p60_4_3_TIMING				\
+	{HDMI_VFRMT_640x480p60_4_3, 640, 16, 96, 48, true,		\
+	 480, 10, 2, 33, true, 25200, 60000, false, true}
+#define HDMI_VFRMT_720x480p60_4_3_TIMING				\
+	{HDMI_VFRMT_720x480p60_4_3, 720, 16, 62, 60, true,		\
+	 480, 9, 6, 30, true, 27030, 60000, false, true}
+#define HDMI_VFRMT_720x480p60_16_9_TIMING				\
+	{HDMI_VFRMT_720x480p60_16_9, 720, 16, 62, 60, true,		\
+	 480, 9, 6, 30, true, 27030, 60000, false, true}
+#define HDMI_VFRMT_1280x720p60_16_9_TIMING				\
+	{HDMI_VFRMT_1280x720p60_16_9, 1280, 110, 40, 220, false,	\
+	 720, 5, 5, 20, false, 74250, 60000, false, true}
+#define HDMI_VFRMT_1920x1080i60_16_9_TIMING				\
+	{HDMI_VFRMT_1920x1080i60_16_9, 1920, 88, 44, 148, false,	\
+	 540, 2, 5, 5, false, 74250, 60000, false, true}
+#define HDMI_VFRMT_1440x480i60_4_3_TIMING				\
+	{HDMI_VFRMT_1440x480i60_4_3, 1440, 38, 124, 114, true,		\
+	 240, 4, 3, 15, true, 27000, 60000, true, true}
+#define HDMI_VFRMT_1440x480i60_16_9_TIMING				\
+	{HDMI_VFRMT_1440x480i60_16_9, 1440, 38, 124, 114, true,		\
+	 240, 4, 3, 15, true, 27000, 60000, true, true}
+#define HDMI_VFRMT_1920x1080p60_16_9_TIMING				\
+	{HDMI_VFRMT_1920x1080p60_16_9, 1920, 88, 44, 148, false,	\
+	 1080, 4, 5, 36, false, 148500, 60000, false, true}
+#define HDMI_VFRMT_720x576p50_4_3_TIMING				\
+	{HDMI_VFRMT_720x576p50_4_3, 720, 12, 64, 68, true,		\
+	 576,  5, 5, 39, true, 27000, 50000, false, true}
+#define HDMI_VFRMT_720x576p50_16_9_TIMING				\
+	{HDMI_VFRMT_720x576p50_16_9, 720, 12, 64, 68, true,		\
+	 576,  5, 5, 39, true, 27000, 50000, false, true}
+#define HDMI_VFRMT_1280x720p50_16_9_TIMING				\
+	{HDMI_VFRMT_1280x720p50_16_9, 1280, 440, 40, 220, false,	\
+	 720,  5, 5, 20, false, 74250, 50000, false, true}
+#define HDMI_VFRMT_1440x576i50_4_3_TIMING				\
+	{HDMI_VFRMT_1440x576i50_4_3, 1440, 24, 126, 138, true,		\
+	 288,  2, 3, 19, true, 27000, 50000, true, true}
+#define HDMI_VFRMT_1440x576i50_16_9_TIMING				\
+	{HDMI_VFRMT_1440x576i50_16_9, 1440, 24, 126, 138, true,		\
+	 288,  2, 3, 19, true, 27000, 50000, true, true}
+#define HDMI_VFRMT_1920x1080p50_16_9_TIMING				\
+	{HDMI_VFRMT_1920x1080p50_16_9, 1920, 528, 44, 148, false,	\
+	 1080, 4, 5, 36, false, 148500, 50000, false, true}
+#define HDMI_VFRMT_1920x1080p24_16_9_TIMING				\
+	{HDMI_VFRMT_1920x1080p24_16_9, 1920, 638, 44, 148, false,	\
+	 1080, 4, 5, 36, false, 74250, 24000, false, true}
+#define HDMI_VFRMT_1920x1080p25_16_9_TIMING				\
+	{HDMI_VFRMT_1920x1080p25_16_9, 1920, 528, 44, 148, false,	\
+	 1080, 4, 5, 36, false, 74250, 25000, false, true}
+#define HDMI_VFRMT_1920x1080p30_16_9_TIMING				\
+	{HDMI_VFRMT_1920x1080p30_16_9, 1920, 88, 44, 148, false,	\
+	 1080, 4, 5, 36, false, 74250, 30000, false, true}
+#define HDMI_VFRMT_1280x1024p60_5_4_TIMING				\
+	{HDMI_VFRMT_1280x1024p60_5_4, 1280, 48, 112, 248, false,	\
+	1024, 1, 3, 38, false, 108000, 60000, false, true}
+#define HDMI_VFRMT_2560x1600p60_16_9_TIMING				\
+	{HDMI_VFRMT_2560x1600p60_16_9, 2560, 48, 32, 80, false,		\
+	 1600, 3, 6, 37, false, 268500, 60000, false, true}
+#define HDMI_VFRMT_3840x2160p30_16_9_TIMING				\
+	{HDMI_VFRMT_3840x2160p30_16_9, 3840, 176, 88, 296, false,	\
+	 2160, 8, 10, 72, false, 297000, 30000, false, true}
+#define HDMI_VFRMT_3840x2160p25_16_9_TIMING				\
+	{HDMI_VFRMT_3840x2160p25_16_9, 3840, 1056, 88, 296, false,	\
+	 2160, 8, 10, 72, false, 297000, 25000, false, true}
+#define HDMI_VFRMT_3840x2160p24_16_9_TIMING				\
+	{HDMI_VFRMT_3840x2160p24_16_9, 3840, 1276, 88, 296, false,	\
+	 2160, 8, 10, 72, false, 297000, 24000, false, true}
+#define HDMI_VFRMT_4096x2160p24_16_9_TIMING				\
+	{HDMI_VFRMT_4096x2160p24_16_9, 4096, 1020, 88, 296, false,	\
+	 2160, 8, 10, 72, false, 297000, 24000, false, true}
+
+#define MSM_HDMI_MODES_SET_TIMING(LUT, MODE) do {		\
+	struct msm_hdmi_mode_timing_info mode = MODE##_TIMING;	\
+	LUT[MODE] = mode;\
+	} while (0)
+
+static inline void MSM_HDMI_MODES_INIT_TIMINGS(
+	struct msm_hdmi_mode_timing_info *lut)
+{
+	int i;
+
+	for (i = 0; i < HDMI_VFRMT_MAX; i++) {
+		struct msm_hdmi_mode_timing_info mode = VFRMT_NOT_SUPPORTED(i);
+		lut[i] = mode;
+	}
+}
+
+static inline void MSM_HDMI_MODES_SET_SUPP_TIMINGS(
+	struct msm_hdmi_mode_timing_info *lut, int type)
+{
+	if (type & MSM_HDMI_MODES_CEA) {
+		MSM_HDMI_MODES_SET_TIMING(lut, HDMI_VFRMT_640x480p60_4_3);
+		MSM_HDMI_MODES_SET_TIMING(lut, HDMI_VFRMT_720x480p60_4_3);
+		MSM_HDMI_MODES_SET_TIMING(lut, HDMI_VFRMT_720x480p60_16_9);
+		MSM_HDMI_MODES_SET_TIMING(lut, HDMI_VFRMT_1280x720p60_16_9);
+		MSM_HDMI_MODES_SET_TIMING(lut, HDMI_VFRMT_1920x1080i60_16_9);
+		MSM_HDMI_MODES_SET_TIMING(lut, HDMI_VFRMT_1440x480i60_4_3);
+		MSM_HDMI_MODES_SET_TIMING(lut, HDMI_VFRMT_1440x480i60_16_9);
+		MSM_HDMI_MODES_SET_TIMING(lut, HDMI_VFRMT_1920x1080p60_16_9);
+		MSM_HDMI_MODES_SET_TIMING(lut, HDMI_VFRMT_720x576p50_4_3);
+		MSM_HDMI_MODES_SET_TIMING(lut, HDMI_VFRMT_720x576p50_16_9);
+		MSM_HDMI_MODES_SET_TIMING(lut, HDMI_VFRMT_1280x720p50_16_9);
+		MSM_HDMI_MODES_SET_TIMING(lut, HDMI_VFRMT_1440x576i50_4_3);
+		MSM_HDMI_MODES_SET_TIMING(lut, HDMI_VFRMT_1440x576i50_16_9);
+		MSM_HDMI_MODES_SET_TIMING(lut, HDMI_VFRMT_1920x1080p50_16_9);
+		MSM_HDMI_MODES_SET_TIMING(lut, HDMI_VFRMT_1920x1080p24_16_9);
+		MSM_HDMI_MODES_SET_TIMING(lut, HDMI_VFRMT_1920x1080p25_16_9);
+		MSM_HDMI_MODES_SET_TIMING(lut, HDMI_VFRMT_1920x1080p30_16_9);
+	}
+
+	if (type & MSM_HDMI_MODES_XTND) {
+		MSM_HDMI_MODES_SET_TIMING(lut, HDMI_VFRMT_3840x2160p30_16_9);
+		MSM_HDMI_MODES_SET_TIMING(lut, HDMI_VFRMT_3840x2160p25_16_9);
+		MSM_HDMI_MODES_SET_TIMING(lut, HDMI_VFRMT_3840x2160p24_16_9);
+		MSM_HDMI_MODES_SET_TIMING(lut, HDMI_VFRMT_4096x2160p24_16_9);
+	}
+
+	if (type & MSM_HDMI_MODES_DVI) {
+		MSM_HDMI_MODES_SET_TIMING(lut, HDMI_VFRMT_1280x1024p60_5_4);
+		MSM_HDMI_MODES_SET_TIMING(lut, HDMI_VFRMT_2560x1600p60_16_9);
+	}
+}
+
+static inline const char *msm_hdmi_mode_2string(uint32_t mode)
+{
+	switch (mode) {
+	case HDMI_VFRMT_UNKNOWN:		return "Unknown";
+	case HDMI_VFRMT_640x480p60_4_3:		return "640x480 p60 4/3";
+	case HDMI_VFRMT_720x480p60_4_3:		return "720x480 p60 4/3";
+	case HDMI_VFRMT_720x480p60_16_9:	return "720x480 p60 16/9";
+	case HDMI_VFRMT_1280x720p60_16_9:	return "1280x 720 p60 16/9";
+	case HDMI_VFRMT_1920x1080i60_16_9:	return "1920x1080 i60 16/9";
+	case HDMI_VFRMT_1440x480i60_4_3:	return "1440x480 i60 4/3";
+	case HDMI_VFRMT_1440x480i60_16_9:	return "1440x480 i60 16/9";
+	case HDMI_VFRMT_1440x240p60_4_3:	return "1440x240 p60 4/3";
+	case HDMI_VFRMT_1440x240p60_16_9:	return "1440x240 p60 16/9";
+	case HDMI_VFRMT_2880x480i60_4_3:	return "2880x480 i60 4/3";
+	case HDMI_VFRMT_2880x480i60_16_9:	return "2880x480 i60 16/9";
+	case HDMI_VFRMT_2880x240p60_4_3:	return "2880x240 p60 4/3";
+	case HDMI_VFRMT_2880x240p60_16_9:	return "2880x240 p60 16/9";
+	case HDMI_VFRMT_1440x480p60_4_3:	return "1440x480 p60 4/3";
+	case HDMI_VFRMT_1440x480p60_16_9:	return "1440x480 p60 16/9";
+	case HDMI_VFRMT_1920x1080p60_16_9:	return "1920x1080 p60 16/9";
+	case HDMI_VFRMT_720x576p50_4_3:		return "720x576 p50 4/3";
+	case HDMI_VFRMT_720x576p50_16_9:	return "720x576 p50 16/9";
+	case HDMI_VFRMT_1280x720p50_16_9:	return "1280x720 p50 16/9";
+	case HDMI_VFRMT_1920x1080i50_16_9:	return "1920x1080 i50 16/9";
+	case HDMI_VFRMT_1440x576i50_4_3:	return "1440x576 i50 4/3";
+	case HDMI_VFRMT_1440x576i50_16_9:	return "1440x576 i50 16/9";
+	case HDMI_VFRMT_1440x288p50_4_3:	return "1440x288 p50 4/3";
+	case HDMI_VFRMT_1440x288p50_16_9:	return "1440x288 p50 16/9";
+	case HDMI_VFRMT_2880x576i50_4_3:	return "2880x576 i50 4/3";
+	case HDMI_VFRMT_2880x576i50_16_9:	return "2880x576 i50 16/9";
+	case HDMI_VFRMT_2880x288p50_4_3:	return "2880x288 p50 4/3";
+	case HDMI_VFRMT_2880x288p50_16_9:	return "2880x288 p50 16/9";
+	case HDMI_VFRMT_1440x576p50_4_3:	return "1440x576 p50 4/3";
+	case HDMI_VFRMT_1440x576p50_16_9:	return "1440x576 p50 16/9";
+	case HDMI_VFRMT_1920x1080p50_16_9:	return "1920x1080 p50 16/9";
+	case HDMI_VFRMT_1920x1080p24_16_9:	return "1920x1080 p24 16/9";
+	case HDMI_VFRMT_1920x1080p25_16_9:	return "1920x1080 p25 16/9";
+	case HDMI_VFRMT_1920x1080p30_16_9:	return "1920x1080 p30 16/9";
+	case HDMI_VFRMT_2880x480p60_4_3:	return "2880x480 p60 4/3";
+	case HDMI_VFRMT_2880x480p60_16_9:	return "2880x480 p60 16/9";
+	case HDMI_VFRMT_2880x576p50_4_3:	return "2880x576 p50 4/3";
+	case HDMI_VFRMT_2880x576p50_16_9:	return "2880x576 p50 16/9";
+	case HDMI_VFRMT_1920x1250i50_16_9:	return "1920x1250 i50 16/9";
+	case HDMI_VFRMT_1920x1080i100_16_9:	return "1920x1080 i100 16/9";
+	case HDMI_VFRMT_1280x720p100_16_9:	return "1280x720 p100 16/9";
+	case HDMI_VFRMT_720x576p100_4_3:	return "720x576 p100 4/3";
+	case HDMI_VFRMT_720x576p100_16_9:	return "720x576 p100 16/9";
+	case HDMI_VFRMT_1440x576i100_4_3:	return "1440x576 i100 4/3";
+	case HDMI_VFRMT_1440x576i100_16_9:	return "1440x576 i100 16/9";
+	case HDMI_VFRMT_1920x1080i120_16_9:	return "1920x1080 i120 16/9";
+	case HDMI_VFRMT_1280x720p120_16_9:	return "1280x720 p120 16/9";
+	case HDMI_VFRMT_720x480p120_4_3:	return "720x480 p120 4/3";
+	case HDMI_VFRMT_720x480p120_16_9:	return "720x480 p120 16/9";
+	case HDMI_VFRMT_1440x480i120_4_3:	return "1440x480 i120 4/3";
+	case HDMI_VFRMT_1440x480i120_16_9:	return "1440x480 i120 16/9";
+	case HDMI_VFRMT_720x576p200_4_3:	return "720x576 p200 4/3";
+	case HDMI_VFRMT_720x576p200_16_9:	return "720x576 p200 16/9";
+	case HDMI_VFRMT_1440x576i200_4_3:	return "1440x576 i200 4/3";
+	case HDMI_VFRMT_1440x576i200_16_9:	return "1440x576 i200 16/9";
+	case HDMI_VFRMT_720x480p240_4_3:	return "720x480 p240 4/3";
+	case HDMI_VFRMT_720x480p240_16_9:	return "720x480 p240 16/9";
+	case HDMI_VFRMT_1440x480i240_4_3:	return "1440x480 i240 4/3";
+	case HDMI_VFRMT_1440x480i240_16_9:	return "1440x480 i240 16/9";
+	case HDMI_VFRMT_1280x720p24_16_9:	return "1280x720 p24 16/9";
+	case HDMI_VFRMT_1280x720p25_16_9:	return "1280x720 p25 16/9";
+	case HDMI_VFRMT_1280x720p30_16_9:	return "1280x720 p30 16/9";
+	case HDMI_VFRMT_1920x1080p120_16_9:	return "1920x1080 p120 16/9";
+	case HDMI_VFRMT_1920x1080p100_16_9:	return "1920x1080 p100 16/9";
+	case HDMI_VFRMT_3840x2160p30_16_9:	return "3840x2160 p30 16/9";
+	case HDMI_VFRMT_3840x2160p25_16_9:	return "3840x2160 p25 16/9";
+	case HDMI_VFRMT_3840x2160p24_16_9:	return "3840x2160 p24 16/9";
+	case HDMI_VFRMT_4096x2160p24_16_9:	return "4096x2160 p24 16/9";
+	case HDMI_VFRMT_2560x1600p60_16_9:	return "2560x1600 p60 16/9";
+	case HDMI_VFRMT_1280x1024p60_5_4:	return "1280x1042 p60 5/4";
+	default:				return "???";
+	}
+}
+#endif /* __MSM_HDMI_MODES_H__ */
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index d1e73a4..edd656c 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -641,21 +641,9 @@
  * and expiry check is done in the hrtimer_interrupt or in the softirq.
  */
 static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer,
-					    struct hrtimer_clock_base *base,
-					    int wakeup)
+					    struct hrtimer_clock_base *base)
 {
-	if (base->cpu_base->hres_active && hrtimer_reprogram(timer, base)) {
-		if (wakeup) {
-			raw_spin_unlock(&base->cpu_base->lock);
-			raise_softirq_irqoff(HRTIMER_SOFTIRQ);
-			raw_spin_lock(&base->cpu_base->lock);
-		} else
-			__raise_softirq_irqoff(HRTIMER_SOFTIRQ);
-
-		return 1;
-	}
-
-	return 0;
+	return base->cpu_base->hres_active && hrtimer_reprogram(timer, base);
 }
 
 /*
@@ -726,8 +714,7 @@
 static inline void
 hrtimer_force_reprogram(struct hrtimer_cpu_base *base, int skip_equal) { }
 static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer,
-					    struct hrtimer_clock_base *base,
-					    int wakeup)
+					    struct hrtimer_clock_base *base)
 {
 	return 0;
 }
@@ -986,8 +973,21 @@
 	 *
 	 * XXX send_remote_softirq() ?
 	 */
-	if (leftmost && new_base->cpu_base == &__get_cpu_var(hrtimer_bases))
-		hrtimer_enqueue_reprogram(timer, new_base, wakeup);
+	if (leftmost && new_base->cpu_base == &__get_cpu_var(hrtimer_bases)
+		&& hrtimer_enqueue_reprogram(timer, new_base)) {
+		if (wakeup) {
+			/*
+			 * We need to drop cpu_base->lock to avoid a
+			 * lock ordering issue vs. rq->lock.
+			 */
+			raw_spin_unlock(&new_base->cpu_base->lock);
+			raise_softirq_irqoff(HRTIMER_SOFTIRQ);
+			local_irq_restore(flags);
+			return ret;
+		} else {
+			__raise_softirq_irqoff(HRTIMER_SOFTIRQ);
+		}
+	}
 
 	unlock_hrtimer_base(timer, &flags);
 
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index b179e71..d6dd07a 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -926,6 +926,11 @@
 	[MIGRATE_ISOLATE]     = { MIGRATE_RESERVE }, /* Never used */
 };
 
+int *get_migratetype_fallbacks(int mtype)
+{
+	return fallbacks[mtype];
+}
+
 /*
  * Move the free pages in a range to the free lists of the requested type.
  * Note that start_page and end_pages are not aligned on a pageblock
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index 764f4c6..cbfff1c 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -604,8 +604,12 @@
 		 ins ? "insert" : "removal");
 	/* Disable detection to avoid glitch */
 	snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MBHC_INSERT_DETECT, 1, 0);
-	snd_soc_write(mbhc->codec, WCD9XXX_A_MBHC_INSERT_DETECT,
-		      (0x68 | (ins ? (1 << 1) : 0)));
+	if (mbhc->mbhc_cfg->gpio_level_insert)
+		snd_soc_write(mbhc->codec, WCD9XXX_A_MBHC_INSERT_DETECT,
+			      (0x68 | (ins ? (1 << 1) : 0)));
+	else
+		snd_soc_write(mbhc->codec, WCD9XXX_A_MBHC_INSERT_DETECT,
+			      (0x6C | (ins ? (1 << 1) : 0)));
 	/* Re-enable detection */
 	snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MBHC_INSERT_DETECT, 1, 1);
 }
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
index 64f19ad..c8de460 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
@@ -349,7 +349,7 @@
 	atomic_set(&lpa_audio.audio_ocmem_req, 0);
 	runtime->private_data = prtd;
 	lpa_audio.prtd = prtd;
-	lpa_set_volume(lpa_audio.volume);
+	lpa_set_volume(0);
 	ret = q6asm_set_softpause(lpa_audio.prtd->audio_client, &softpause);
 	if (ret < 0)
 		pr_err("%s: Send SoftPause Param failed ret=%d\n",
diff --git a/sound/soc/msm/qdsp6v2/q6voice.h b/sound/soc/msm/qdsp6v2/q6voice.h
index babfddc..ef5c6e3 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.h
+++ b/sound/soc/msm/qdsp6v2/q6voice.h
@@ -1339,7 +1339,7 @@
 #define VOLTE_SESSION_NAME  "VoLTE session"
 #define VOICE2_SESSION_NAME "Voice2 session"
 
-#define VOICE2_SESSION_VSID "10dc1000"
+#define VOICE2_SESSION_VSID "10DC1000"
 
 /* called  by alsa driver */
 int voc_set_pp_enable(uint16_t session_id, uint32_t module_id,