Merge "msm: mdss: wake up cpu before vsync for video interface"
diff --git a/Documentation/devicetree/bindings/bluetooth/bluetooth_power.txt b/Documentation/devicetree/bindings/bluetooth/bluetooth_power.txt
index 88d69e0..86d863c 100644
--- a/Documentation/devicetree/bindings/bluetooth/bluetooth_power.txt
+++ b/Documentation/devicetree/bindings/bluetooth/bluetooth_power.txt
@@ -5,12 +5,26 @@
 Required properties:
   - compatible: Should be "qca,ar3002"
   - qca,bt-reset-gpio: GPIO pin to bring BT Controller out of reset
+  - qca,bt-vdd-io-supply: Bluetooth VDD IO regulator handle
+  - qca,bt-vdd-pa-supply: Bluetooth VDD PA regulator handle
 
 Optional properties:
-  None
+  -qca,bt-vdd-ldo-supply: Bluetooth VDD LDO regulator handle. Kept under optional parameters
+		as some of the chipsets doesn't require ldo or it may use from same vddio.
+  - qca,bt-chip-pwd-supply: Chip power down gpio is required when bluetooth module
+		and other modules like wifi co-exist in a singe chip and shares a
+		common gpio to bring chip out of reset.
+  - qca,bt-vdd-io-voltage-level: min and max voltages for the vdd io regulator
+  - qca,bt-vdd-pa-voltage-level: min and max voltages for the vdd pa regulator
+  - qca,bt-vdd-ldo-voltage-level: min and max voltages for the vdd ldo regulator
 
 Example:
   bt-ar3002 {
     compatible = "qca,ar3002";
     qca,bt-reset-gpio = <&pm8941_gpios 34 0>;
+    qca,bt-vdd-io-supply = <&pm8941_s3>;
+    qca,bt-vdd-pa-supply = <&pm8941_l19>;
+    qca,bt-chip-pwd-supply = <&ath_chip_pwd_l>;
+    qca,bt-vdd-io-supply = <1800000 1800000>;
+    qca,bt-vdd-pa-supply = <2900000 2900000>;
   };
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp.txt b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
index 4f31f07..a221433 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
@@ -68,8 +68,30 @@
 - qcom,default-state:  default state of the led, should be "on" or "off"
 - qcom,turn-off-delay-ms: delay in millisecond for turning off the led when its default-state is "on". Value is being ignored in case default-state is "off".
 
+MPP LED is an LED controled through a Multi Purpose Pin.
+
+Optional properties for MPP LED:
+- 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"
+- qcom,source-sel: select power source, default 1 (enabled)
+- qcom,mode-ctrl: select operation mode, default 0x60 = Mode Sink
+
 Example:
 
+	qcom,leds@a200 {
+		status = "okay";
+		qcom,led_mpp_3 {
+			label = "mpp";
+			linux,name = "wled-backlight";
+			linux-default-trigger = "none";
+			qcom,default-state = "on";
+			qcom,max-current = <40>;
+			qcom,id = <6>;
+			qcom,source-sel = <1>;
+			qcom,mode-ctrl = <0x10>;
+		};
+	};
+
 	qcom,leds@d000 {
 		status = "okay";
 		qcom,rgb_pwm {
@@ -151,3 +173,4 @@
 				linux,name = "led:wled_backlight";
 			};
 	};
+
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt
index ac8ea73..4cbff52 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt
@@ -16,6 +16,7 @@
 - qcom,firmware-name: Base name of the firmware image. Ex. "lpass"
 - qcom,gpio-err-fatal: GPIO used by the lpass to indicate error fatal to the apps.
 - qcom,gpio-force-stop: GPIO used by the apps to force the lpass to shutdown.
+- qcom,gpio-proxy-unvote: GPIO used by the lpass to indicate apps clock is ready.
 
 Optional properties:
 - vdd_pll-supply:     Reference to the regulator that supplies the PLL's rail.
@@ -32,8 +33,9 @@
 		vdd_cx-supply = <&pm8841_s2>;
 	        qcom,firmware-name = "lpass";
 
-		/* GPIO input from lpass */
+		/* GPIO inputs from lpass */
 		qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_2_in 0 0>;
+		qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_2_in 2 0>;
 
 		/* GPIO output to lpass */
 		qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_2_out 0 0>;
diff --git a/Documentation/devicetree/bindings/regulator/qpnp-regulator.txt b/Documentation/devicetree/bindings/regulator/qpnp-regulator.txt
index 2116888..041928d 100644
--- a/Documentation/devicetree/bindings/regulator/qpnp-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/qpnp-regulator.txt
@@ -16,12 +16,17 @@
 	the spmi-slave-container property
 
 Optional properties:
+- interrupts:                  List of interrupts used by the regulator.
+- interrupt-names:             List of strings defining the names of the
+				interrupts in the 'interrupts' property 1-to-1.
+				Supported values are "ocp" for voltage switch
+				type regulators.  If an OCP interrupt is
+				specified, then the voltage switch will be
+				toggled off and back on when OCP triggers in
+				order to handle high in-rush current.
 - qcom,system-load:            Load in uA present on regulator that is not
 				captured by any consumer request
 - qcom,enable-time:            Time in us to delay after enabling the regulator
-- qcom,ocp-enable-time:        Time to delay in us between enabling a switch and
-				subsequently enabling over current protection
-				(OCP) for the switch
 - qcom,auto-mode-enable:       1 = Enable automatic hardware selection of
 				regulator mode (HPM vs LPM); not available on
 				boost type regulators
@@ -30,11 +35,18 @@
 				so that it acts like a switch and simply outputs
 				its input voltage
 			       0 = Do not enable bypass mode
-- qcom,ocp-enable:             1 = Enable over current protection (OCP) for
-				voltage switch type regulators so that they
-				latch off automatically when over current is
-				detected
+- qcom,ocp-enable:             1 = Allow over current protection (OCP) to be
+				enabled for voltage switch type regulators so
+				that they latch off automatically when over
+				current is detected.  OCP is enabled when in
+				HPM or auto mode.
 			       0 = Disable OCP
+- qcom,ocp-max-retries:        Maximum number of times to try toggling a voltage
+				switch off and back on as a result of
+				consecutive over current events.
+- qcom,ocp-retry-delay:        Time to delay in milliseconds between each
+				voltage switch toggle after an over current
+				event takes place.
 - qcom,pull-down-enable:       1 = Enable output pull down resistor when the
 				regulator is disabled
 			       0 = Disable pull down resistor
@@ -76,6 +88,16 @@
 					1 = 0.25 uA
 					2 = 0.55 uA
 					3 = 0.75 uA
+- qcom,hpm-enable:             1 = Enable high power mode (HPM), also referred
+				to as NPM.  HPM consumes more ground current
+				than LPM, but it can source significantly higher
+				load current.  HPM is not available on boost
+				type regulators.  For voltage switch type
+				regulators, HPM implies that over current
+				protection and soft start are active all the
+				time.  This configuration can be overwritten
+				by changing the regulator's mode dynamically.
+			       0 = Do not enable HPM
 - qcom,force-type: 	       Override the type and subtype register values. Useful for some
 				regulators that have invalid types advertised by the hardware.
 				The format is two unsigned integers of the form <type subtype>.
diff --git a/arch/arm/boot/dts/apq8074-v2-liquid.dts b/arch/arm/boot/dts/apq8074-v2-liquid.dts
new file mode 100644
index 0000000..4ec1cdd
--- /dev/null
+++ b/arch/arm/boot/dts/apq8074-v2-liquid.dts
@@ -0,0 +1,34 @@
+/* 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.
+ */
+
+/dts-v1/;
+
+/include/ "apq8074-v2.dtsi"
+/include/ "msm8974-liquid.dtsi"
+
+/ {
+	model = "Qualcomm APQ 8074v2 LIQUID";
+	compatible = "qcom,apq8074-liquid", "qcom,apq8074", "qcom,liquid";
+	qcom,msm-id = <184 9 0x20000>;
+};
+
+&usb3 {
+	interrupt-parent = <&usb3>;
+	interrupts = <0 1>;
+	#interrupt-cells = <1>;
+	interrupt-map-mask = <0x0 0xffffffff>;
+	interrupt-map = <0x0 0 &intc 0 133 0
+			0x0 1 &spmi_bus 0x0 0x0 0x9 0x0>;
+	interrupt-names = "hs_phy_irq", "pmic_id_irq";
+
+	qcom,misc-ref = <&pm8941_misc>;
+};
diff --git a/arch/arm/boot/dts/apq8074-v2.dtsi b/arch/arm/boot/dts/apq8074-v2.dtsi
new file mode 100644
index 0000000..0f867e0
--- /dev/null
+++ b/arch/arm/boot/dts/apq8074-v2.dtsi
@@ -0,0 +1,48 @@
+/* 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.
+ */
+
+/*
+ * As a general rule, only version-specific property overrides should be placed
+ * inside this file. However, device definitions should be placed inside the
+ * msm8974.dtsi file.
+ */
+
+/include/ "msm8974-v2.dtsi"
+
+/ {
+	qcom,qseecom@7f00000 {
+		compatible = "qcom,qseecom";
+		reg = <0x07f00000 0x500000>;
+		reg-names = "secapp-region";
+		qcom,disk-encrypt-pipe-pair = <2>;
+		qcom,hlos-ce-hw-instance = <1>;
+		qcom,qsee-ce-hw-instance = <0>;
+		qcom,msm-bus,name = "qseecom-noc";
+		qcom,msm-bus,num-cases = <4>;
+		qcom,msm-bus,active-only = <0>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+				<55 512 0 0>,
+				<55 512 3936000 393600>,
+				<55 512 3936000 393600>,
+				<55 512 3936000 393600>;
+	};
+};
+
+&memory_hole {
+	qcom,memblock-remove = <0x07f00000 0x8000000>; /* Address and size of the hole */
+};
+
+&qseecom {
+	status = "enabled";
+};
+
diff --git a/arch/arm/boot/dts/msmzinc-ion.dtsi b/arch/arm/boot/dts/apq8084-ion.dtsi
similarity index 100%
rename from arch/arm/boot/dts/msmzinc-ion.dtsi
rename to arch/arm/boot/dts/apq8084-ion.dtsi
diff --git a/arch/arm/boot/dts/msmzinc-sim.dts b/arch/arm/boot/dts/apq8084-sim.dts
similarity index 83%
rename from arch/arm/boot/dts/msmzinc-sim.dts
rename to arch/arm/boot/dts/apq8084-sim.dts
index e410344..cb16c07 100644
--- a/arch/arm/boot/dts/msmzinc-sim.dts
+++ b/arch/arm/boot/dts/apq8084-sim.dts
@@ -12,11 +12,11 @@
 
 /dts-v1/;
 
-/include/ "msmzinc.dtsi"
+/include/ "apq8084.dtsi"
 
 / {
-	model = "Qualcomm MSM ZINC Simulator";
-	compatible = "qcom,msmzinc-sim", "qcom,msmzinc", "qcom,sim";
+	model = "Qualcomm APQ 8084 Simulator";
+	compatible = "qcom,apq8084-sim", "qcom,apq8084", "qcom,sim";
 	qcom,msm-id = <178 0 0>;
 
 	aliases {
diff --git a/arch/arm/boot/dts/msmzinc.dtsi b/arch/arm/boot/dts/apq8084.dtsi
similarity index 95%
rename from arch/arm/boot/dts/msmzinc.dtsi
rename to arch/arm/boot/dts/apq8084.dtsi
index 642597d..c2e5ef4 100644
--- a/arch/arm/boot/dts/msmzinc.dtsi
+++ b/arch/arm/boot/dts/apq8084.dtsi
@@ -11,11 +11,11 @@
  */
 
 /include/ "skeleton.dtsi"
-/include/ "msmzinc-ion.dtsi"
+/include/ "apq8084-ion.dtsi"
 
 / {
-	model = "Qualcomm MSM ZINC";
-	compatible = "qcom,msmzinc";
+	model = "Qualcomm APQ 8084";
+	compatible = "qcom,apq8084";
 	interrupt-parent = <&intc>;
 
 	intc: interrupt-controller@f9000000 {
diff --git a/arch/arm/boot/dts/mpq8092.dtsi b/arch/arm/boot/dts/mpq8092.dtsi
index 75f168d..5c904b4 100644
--- a/arch/arm/boot/dts/mpq8092.dtsi
+++ b/arch/arm/boot/dts/mpq8092.dtsi
@@ -85,7 +85,7 @@
 
 		qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
 		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-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
 		qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
 
 		qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
@@ -105,7 +105,7 @@
 
 		qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
 		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-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
 		qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
 
 		qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
diff --git a/arch/arm/boot/dts/msm-pm8110.dtsi b/arch/arm/boot/dts/msm-pm8110.dtsi
index 9ebfb56..b88b991 100644
--- a/arch/arm/boot/dts/msm-pm8110.dtsi
+++ b/arch/arm/boot/dts/msm-pm8110.dtsi
@@ -29,16 +29,18 @@
 			#size-cells = <1>;
 			status = "disabled";
 
-			qcom,chg-vddmax-mv = <4200>;
-			qcom,chg-vddsafe-mv = <4200>;
-			qcom,chg-vinmin-mv = <4200>;
-			qcom,chg-vbatdet-mv = <4100>;
-			qcom,chg-ibatmax-ma = <1500>;
-			qcom,chg-ibatterm-ma = <200>;
-			qcom,chg-ibatsafe-ma = <1500>;
-			qcom,chg-thermal-mitigation = <1500 700 600 325>;
+			qcom,vddmax-mv = <4200>;
+			qcom,vddsafe-mv = <4200>;
+			qcom,vinmin-mv = <4200>;
+			qcom,vbatdet-mv = <4100>;
+			qcom,ibatmax-ma = <1500>;
+			qcom,ibatterm-ma = <200>;
+			qcom,ibatsafe-ma = <1500>;
+			qcom,thermal-mitigation = <1500 700 600 325>;
+			qcom,vbatdet-delta-mv = <350>;
+			qcom,tchg-mins = <150>;
 
-			qcom,chg-chgr@1000 {
+			qcom,chgr@1000 {
 				status = "disabled";
 				reg = <0x1000 0x100>;
 				interrupts =	<0x0 0x10 0x0>,
@@ -60,7 +62,7 @@
 							"chg-done";
 			};
 
-			qcom,chg-buck@1100 {
+			qcom,buck@1100 {
 				status = "disabled";
 				reg = <0x1100 0x100>;
 				interrupts =	<0x0 0x11 0x0>,
@@ -80,7 +82,7 @@
 							"vdd-loop";
 			};
 
-			qcom,chg-bat-if@1200 {
+			qcom,bat-if@1200 {
 				status = "disabled";
 				reg = <0x1200 0x100>;
 				interrupts =	<0x0 0x12 0x0>,
@@ -96,7 +98,7 @@
 							"psi";
 			};
 
-			qcom,chg-usb-chgpth@1300 {
+			qcom,usb-chgpth@1300 {
 				status = "disabled";
 				reg = <0x1300 0x100>;
 				interrupts =	<0 0x13 0x0>,
@@ -197,6 +199,12 @@
 				interrupts = <0x0 0x61 0x1>;
 			};
 		};
+
+		qcom,leds@a200 {
+			compatible = "qcom,leds-qpnp";
+			reg = <0xa200 0x100>;
+			label = "mpp";
+		};
 	};
 
 	qcom,pm8110@1 {
diff --git a/arch/arm/boot/dts/msm8226-cdp.dts b/arch/arm/boot/dts/msm8226-cdp.dts
index e4700a1..e8e58c4 100644
--- a/arch/arm/boot/dts/msm8226-cdp.dts
+++ b/arch/arm/boot/dts/msm8226-cdp.dts
@@ -33,7 +33,7 @@
 			compatible = "synaptics,rmi4";
 			reg = <0x20>;
 			interrupt-parent = <&msmgpio>;
-			interrupts = <17 0x2>;
+			interrupts = <17 0x2008>;
 			vdd-supply = <&pm8226_l19>;
 			vcc_i2c-supply = <&pm8226_lvs1>;
 			synaptics,reset-gpio = <&msmgpio 16 0x00>;
@@ -131,7 +131,7 @@
 
 	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
 	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
-	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 16mA, 10mA, 10mA */
+	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
 	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
 
 	qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
@@ -180,7 +180,7 @@
 
 	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
 	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
-	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 16mA, 10mA, 10mA */
+	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
 	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
 
 	qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
diff --git a/arch/arm/boot/dts/msm8226-ion.dtsi b/arch/arm/boot/dts/msm8226-ion.dtsi
index 9cef5a9..f433a49 100644
--- a/arch/arm/boot/dts/msm8226-ion.dtsi
+++ b/arch/arm/boot/dts/msm8226-ion.dtsi
@@ -50,5 +50,19 @@
 			qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
 			qcom,memory-reservation-size = <0x314000>;
 		};
+		qcom,ion-heap@23 { /* OTHER PIL HEAP */
+			compatible = "qcom,msm-ion-reserve";
+			reg = <23>;
+			qcom,heap-align = <0x1000>;
+			qcom,memory-fixed = <0x06400000 0x2000000>;
+		};
+		qcom,ion-heap@26 { /* MODEM PIL HEAP */
+			compatible = "qcom,msm-ion-reserve";
+			reg = <26>;
+			qcom,heap-align = <0x1000>;
+			qcom,memory-fixed = <0x08400000 0x4E00000>;
+
+		};
+
 	};
 };
diff --git a/arch/arm/boot/dts/msm8226-mtp.dts b/arch/arm/boot/dts/msm8226-mtp.dts
index 478d064..a732722 100644
--- a/arch/arm/boot/dts/msm8226-mtp.dts
+++ b/arch/arm/boot/dts/msm8226-mtp.dts
@@ -33,7 +33,7 @@
 			compatible = "synaptics,rmi4";
 			reg = <0x20>;
 			interrupt-parent = <&msmgpio>;
-			interrupts = <17 0x2>;
+			interrupts = <17 0x2008>;
 			vdd-supply = <&pm8226_l19>;
 			vcc_i2c-supply = <&pm8226_lvs1>;
 			synaptics,reset-gpio = <&msmgpio 16 0x00>;
@@ -123,7 +123,7 @@
 
 	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
 	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
-	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 16mA, 10mA, 10mA */
+	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
 	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
 
 	qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
@@ -172,7 +172,7 @@
 
 	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
 	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
-	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 16mA, 10mA, 10mA */
+	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
 	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
 
 	qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
diff --git a/arch/arm/boot/dts/msm8226-qrd.dts b/arch/arm/boot/dts/msm8226-qrd.dts
index ecb3b5a..e694cef 100644
--- a/arch/arm/boot/dts/msm8226-qrd.dts
+++ b/arch/arm/boot/dts/msm8226-qrd.dts
@@ -33,7 +33,7 @@
 			compatible = "synaptics,rmi4";
 			reg = <0x20>;
 			interrupt-parent = <&msmgpio>;
-			interrupts = <17 0x2>;
+			interrupts = <17 0x2008>;
 			vdd-supply = <&pm8226_l19>;
 			vcc_i2c-supply = <&pm8226_lvs1>;
 			synaptics,reset-gpio = <&msmgpio 16 0x00>;
@@ -123,7 +123,7 @@
 
 	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
 	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
-	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 16mA, 10mA, 10mA */
+	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
 	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
 
 	qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
diff --git a/arch/arm/boot/dts/msm8226-sim.dts b/arch/arm/boot/dts/msm8226-sim.dts
index a86dc48..00c0e2e 100644
--- a/arch/arm/boot/dts/msm8226-sim.dts
+++ b/arch/arm/boot/dts/msm8226-sim.dts
@@ -36,7 +36,7 @@
 
 	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
 	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-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
 	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
 
 	vdd-supply = <&pm8226_l17>;
@@ -62,7 +62,7 @@
 
 	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
 	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-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
 	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
 
 	qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index b949d3b..9ee78a4 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -756,8 +756,9 @@
 
 		qcom,firmware-name = "adsp";
 
-		/* GPIO input from lpass */
+		/* GPIO inputs from lpass */
 		qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_2_in 0 0>;
+		qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_2_in 2 0>;
 
 		/* GPIO output to lpass */
 		qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_2_out 0 0>;
@@ -794,7 +795,7 @@
 
 	qcom,msm-mem-hole {
 		compatible = "qcom,msm-mem-hole";
-		qcom,memblock-remove = <0x8400000 0x7b00000>; /* Address and Size of Hole */
+		qcom,memblock-remove = <0x6400000 0x9b00000>; /* Address and Size of Hole */
 	};
 
 	tsens: tsens@fc4a8000 {
diff --git a/arch/arm/boot/dts/msm8610-cdp.dts b/arch/arm/boot/dts/msm8610-cdp.dts
index 533ad53..9b114cc 100644
--- a/arch/arm/boot/dts/msm8610-cdp.dts
+++ b/arch/arm/boot/dts/msm8610-cdp.dts
@@ -17,13 +17,32 @@
 / {
 	model = "Qualcomm MSM 8610 CDP";
 	compatible = "qcom,msm8610-cdp", "qcom,msm8610", "qcom,cdp";
-	qcom,msm-id = <147 1 0>, <165 1 0>;
+	qcom,msm-id = <147 1 0>, <165 1 0>, <161 1 0>, <162 1 0>,
+		      <163 1 0>, <164 1 0>, <166 1 0>;
 
 	serial@f991e000 {
 		status = "ok";
 	};
 };
 
+&spmi_bus {
+	qcom,pm8110@0 {
+		qcom,leds@a200 {
+			status = "okay";
+			qcom,led_mpp_3 {
+				label = "mpp";
+				linux,name = "wled-backlight";
+				linux-default-trigger = "none";
+				qcom,default-state = "on";
+				qcom,max-current = <40>;
+				qcom,id = <6>;
+				qcom,source-sel = <1>;
+				qcom,mode-ctrl = <0x10>;
+			};
+		};
+	};
+};
+
 &sdhc_1 {
 	vdd-supply = <&pm8110_l17>;
 	qcom,vdd-always-on;
@@ -82,18 +101,18 @@
 
 &pm8110_chg {
 	status = "ok";
-	qcom,chg-charging-disabled;
-	qcom,chg-use-default-batt-values;
+	qcom,charging-disabled;
+	qcom,use-default-batt-values;
 
-	qcom,chg-chgr@1000 {
+	qcom,chgr@1000 {
 		status = "ok";
 	};
 
-	qcom,chg-buck@1100 {
+	qcom,buck@1100 {
 		status = "ok";
 	};
 
-	qcom,chg-usb-chgpth@1300 {
+	qcom,usb-chgpth@1300 {
 		status = "ok";
 	};
 
diff --git a/arch/arm/boot/dts/msm8610-gpu.dtsi b/arch/arm/boot/dts/msm8610-gpu.dtsi
index 5e57430..5580f73 100644
--- a/arch/arm/boot/dts/msm8610-gpu.dtsi
+++ b/arch/arm/boot/dts/msm8610-gpu.dtsi
@@ -27,8 +27,9 @@
 		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 */
+		qcom,clk-map = <0x000005E>; /* KGSL_CLK_CORE |
+			KGSL_CLK_IFACE | KGSL_CLK_MEM | KGSL_CLK_MEM_IFACE |
+			KGSL_CLK_ALT_MEM_IFACE */
 
 		/* Bus Scale Settings */
 		qcom,msm-bus,name = "grp3d";
diff --git a/arch/arm/boot/dts/msm8610-mtp.dts b/arch/arm/boot/dts/msm8610-mtp.dts
index c906e89..3a26376 100644
--- a/arch/arm/boot/dts/msm8610-mtp.dts
+++ b/arch/arm/boot/dts/msm8610-mtp.dts
@@ -17,13 +17,32 @@
 / {
 	model = "Qualcomm MSM 8610 MTP";
 	compatible = "qcom,msm8610-mtp", "qcom,msm8610", "qcom,mtp";
-	qcom,msm-id = <147 8 0>, <165 8 0>;
+	qcom,msm-id = <147 8 0>, <165 8 0>, <161 8 0>, <162 8 0>,
+		      <163 8 0>, <164 8 0>, <166 8 0>;
 
-	serial@f991f000 {
+	serial@f991e000 {
 		status = "ok";
 	};
 };
 
+&spmi_bus {
+	qcom,pm8110@0 {
+		qcom,leds@a200 {
+			status = "okay";
+			qcom,led_mpp_3 {
+				label = "mpp";
+				linux,name = "wled-backlight";
+				linux-default-trigger = "none";
+				qcom,default-state = "on";
+				qcom,max-current = <40>;
+				qcom,id = <6>;
+				qcom,source-sel = <1>;
+				qcom,mode-ctrl = <0x10>;
+			};
+		};
+	};
+};
+
 &sdhc_1 {
 	vdd-supply = <&pm8110_l17>;
 	qcom,vdd-always-on;
@@ -82,21 +101,21 @@
 
 &pm8110_chg {
 	status = "ok";
-	qcom,chg-charging-disabled;
+	qcom,charging-disabled;
 
-	qcom,chg-chgr@1000 {
+	qcom,chgr@1000 {
 		status = "ok";
 	};
 
-	qcom,chg-buck@1100 {
+	qcom,buck@1100 {
 		status = "ok";
 	};
 
-	qcom,chg-bat-if@1200 {
+	qcom,bat-if@1200 {
 		status = "ok";
 	};
 
-	qcom,chg-usb-chgpth@1300 {
+	qcom,usb-chgpth@1300 {
 		status = "ok";
 	};
 
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index ad8b24b..e406ba8 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -233,7 +233,7 @@
 
 		qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
 		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-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
 		qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
 
 		qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
@@ -265,7 +265,7 @@
 
 		qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
 		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-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
 		qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
 
 		qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
@@ -414,7 +414,6 @@
 		/* 190,ee0_krait_hlos_spmi_periph_irq */
 		/* 187,channel_0_krait_hlos_trans_done_irq */
 		interrupts = <0 190 0>, <0 187 0>;
-		qcom,not-wakeup;
 		qcom,pmic-arb-ee = <0>;
 		qcom,pmic-arb-channel = <0>;
 	};
@@ -640,8 +639,9 @@
 		vdd_cx-supply = <&pm8110_s1_corner>;
 		qcom,firmware-name = "adsp";
 
-		/* GPIO input from lpass */
+		/* GPIO inputs from lpass */
 		qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_2_in 0 0>;
+		qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_2_in 2 0>;
 
 		/* GPIO output to lpass */
 		qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_2_out 0 0>;
@@ -700,6 +700,12 @@
 				<55 512 3936000 393600>;
 	};
 
+        qcom,msm-rng@f9bff000 {
+                compatible = "qcom,msm-rng";
+                reg = <0xf9bff000 0x200>;
+                qcom,msm-rng-iface-clk;
+        };
+
 	jtag_mm0: jtagmm@fc34c000 {
 		compatible = "qcom,jtag-mm";
 		reg = <0xfc34c000 0x1000>,
@@ -727,6 +733,11 @@
 		      <0xfc346000 0x1000>;
 		reg-names = "etm-base","debug-base";
 	};
+
+	qcom,tz-log@fe805720 {
+		compatible = "qcom,tz-log";
+		reg = <0x0fe805720 0x1000>;
+	};
 };
 
 &gdsc_vfe {
diff --git a/arch/arm/boot/dts/msm8974-bus.dtsi b/arch/arm/boot/dts/msm8974-bus.dtsi
index bb4b48e..3e0ef04 100644
--- a/arch/arm/boot/dts/msm8974-bus.dtsi
+++ b/arch/arm/boot/dts/msm8974-bus.dtsi
@@ -1349,30 +1349,18 @@
 			qcom,hw-sel = "NoC";
 		};
 
-		mas-video-p0-ocmem {
+		mas-video-ocmem {
 			cell-id = <68>;
-			label = "mas-video-p0-ocmem";
-			qcom,masterp = <3>;
+			label = "mas-video-ocmem";
+			qcom,masterp = <3 4>;
 			qcom,tier = <2>;
 			qcom,perm-mode = "Fixed";
 			qcom,mode = "Fixed";
-			qcom,qport = <2>;
+			qcom,qport = <2 3>;
 			qcom,mas-hw-id = <15>;
 			qcom,hw-sel = "NoC";
 		};
 
-		mas-video-p1-ocmem {
-			cell-id = <69>;
-			label = "mas-video-p1-ocmem";
-			qcom,masterp = <4>;
-			qcom,tier = <2>;
-			qcom,perm-mode = "Fixed";
-			qcom,mode = "Fixed";
-			qcom,qport = <3>;
-			qcom,mas-hw-id = <16>;
-			qcom,hw-sel = "NoC";
-		};
-
 		mas-vfe-ocmem {
 			cell-id = <70>;
 			label = "mas-vfe-ocmem";
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi
index df0db7e..b574a31 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi
@@ -111,7 +111,7 @@
 		reg = <0x6c 0x0>;
 		qcom,slave-id = <0x6c 0x300A 0x2720>;
 		qcom,csiphy-sd-index = <2>;
-		qcom,csid-sd-index = <0>;
+		qcom,csid-sd-index = <2>;
 		qcom,mount-angle = <90>;
 		qcom,sensor-name = "ov2720";
 		cam_vdig-supply = <&pm8941_l3>;
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
index f58c1e2..748d5f7 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
@@ -112,7 +112,7 @@
 		reg = <0x6c>;
 		qcom,slave-id = <0x6c 0x300A 0x2720>;
 		qcom,csiphy-sd-index = <2>;
-		qcom,csid-sd-index = <0>;
+		qcom,csid-sd-index = <2>;
 		qcom,mount-angle = <90>;
 		qcom,sensor-name = "ov2720";
 		cam_vdig-supply = <&pm8941_l3>;
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi
index 767a705..53f6e9e 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi
@@ -113,7 +113,7 @@
 		reg = <0x6c>;
 		qcom,slave-id = <0x6c 0x300A 0x2720>;
 		qcom,csiphy-sd-index = <2>;
-		qcom,csid-sd-index = <0>;
+		qcom,csid-sd-index = <2>;
 		qcom,mount-angle = <90>;
 		qcom,sensor-name = "ov2720";
 		cam_vdig-supply = <&pm8941_l3>;
diff --git a/arch/arm/boot/dts/msm8974-camera.dtsi b/arch/arm/boot/dts/msm8974-camera.dtsi
index 3a78a15..94a28f7 100644
--- a/arch/arm/boot/dts/msm8974-camera.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera.dtsi
@@ -23,8 +23,9 @@
 	qcom,csiphy@fda0ac00 {
 		cell-index = <0>;
 		compatible = "qcom,csiphy";
-		reg = <0xfda0ac00 0x200>;
-		reg-names = "csiphy";
+		reg = <0xfda0ac00 0x200>,
+                      <0xfda00030 0x4>;
+		reg-names = "csiphy", "csiphy_clk_mux";
 		interrupts = <0 78 0>;
 		interrupt-names = "csiphy";
 	};
@@ -32,8 +33,9 @@
 	qcom,csiphy@fda0b000 {
 		cell-index = <1>;
 		compatible = "qcom,csiphy";
-		reg = <0xfda0b000 0x200>;
-		reg-names = "csiphy";
+		reg = <0xfda0b000 0x200>,
+                      <0xfda00038 0x4>;
+		reg-names = "csiphy", "csiphy_clk_mux";
 		interrupts = <0 79 0>;
 		interrupt-names = "csiphy";
 	};
@@ -41,8 +43,9 @@
 	qcom,csiphy@fda0b400 {
 		cell-index = <2>;
 		compatible = "qcom,csiphy";
-		reg = <0xfda0b400 0x200>;
-		reg-names = "csiphy";
+		reg = <0xfda0b400 0x200>,
+                      <0xfda00040 0x4>;
+		reg-names = "csiphy", "csiphy_clk_mux";
 		interrupts = <0 80 0>;
 		interrupt-names = "csiphy";
 	};
@@ -94,8 +97,9 @@
 	qcom,ispif@fda0A000 {
 		cell-index = <0>;
 		compatible = "qcom,ispif";
-		reg = <0xfda0A000 0x500>;
-		reg-names = "ispif";
+		reg = <0xfda0A000 0x500>,
+                      <0xfda00020 0x10>;
+		reg-names = "ispif", "csi_clk_mux";
 		interrupts = <0 55 0>;
 		interrupt-names = "ispif";
 	};
diff --git a/arch/arm/boot/dts/msm8974-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
index 0319128..3c1711c 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-cdp.dtsi
@@ -344,7 +344,7 @@
 
 	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
 	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-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
 	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
 
 	qcom,nonremovable;
@@ -374,11 +374,31 @@
 
 	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
 	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-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
 	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
 	status = "ok";
 };
 
+/* Drive strength recommendations for clock line from hardware team is 10 mA.
+ * But since the driver has been been using the below values from the start
+ * without any problems, continue to use those.
+ */
+&sdcc1 {
+	qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
+};
+
+&sdcc2 {
+	qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
+};
+
+&sdhc_1 {
+	qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
+};
+
+&sdhc_2 {
+	qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
+};
+
 &uart7 {
 	status = "ok";
 	qcom,tx-gpio = <&msmgpio 41 0x00>;
diff --git a/arch/arm/boot/dts/msm8974-fluid.dtsi b/arch/arm/boot/dts/msm8974-fluid.dtsi
index 25d0885..eaf326e 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-fluid.dtsi
@@ -308,7 +308,7 @@
 
 	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
 	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-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
 	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
 
 	qcom,nonremovable;
@@ -338,11 +338,31 @@
 
 	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
 	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-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
 	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
 	status = "ok";
 };
 
+/* Drive strength recommendations for clock line from hardware team is 10 mA.
+ * But since the driver has been been using the below values from the start
+ * without any problems, continue to use those.
+ */
+&sdcc1 {
+	qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
+};
+
+&sdcc2 {
+	qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
+};
+
+&sdhc_1 {
+	qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
+};
+
+&sdhc_2 {
+	qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
+};
+
 &usb3 {
 	qcom,otg-capability;
 };
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index be890b1..a458869 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -786,7 +786,7 @@
 
 	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
 	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-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
 	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
 
 	qcom,nonremovable;
@@ -805,7 +805,27 @@
 
 	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
 	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-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
 	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
 	status = "ok";
 };
+
+/* Drive strength recommendations for clock line from hardware team is 10 mA.
+ * But since the driver has been been using the below values from the start
+ * without any problems, continue to use those.
+ */
+&sdcc1 {
+	qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
+};
+
+&sdcc2 {
+	qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
+};
+
+&sdhc_1 {
+	qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
+};
+
+&sdhc_2 {
+	qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
+};
diff --git a/arch/arm/boot/dts/msm8974-mtp.dtsi b/arch/arm/boot/dts/msm8974-mtp.dtsi
index 8b9ef87..ca5f663 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-mtp.dtsi
@@ -283,7 +283,7 @@
 
 	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
 	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-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
 	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
 
 	qcom,nonremovable;
@@ -313,11 +313,31 @@
 
 	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
 	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-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
 	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
 	status = "ok";
 };
 
+/* Drive strength recommendations for clock line from hardware team is 10 mA.
+ * But since the driver has been been using the below values from the start
+ * without any problems, continue to use those.
+ */
+&sdcc1 {
+	qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
+};
+
+&sdcc2 {
+	qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
+};
+
+&sdhc_1 {
+	qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
+};
+
+&sdhc_2 {
+	qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
+};
+
 &usb_otg {
 	qcom,hsusb-otg-otg-control = <2>;
 };
diff --git a/arch/arm/boot/dts/msm8974-regulator.dtsi b/arch/arm/boot/dts/msm8974-regulator.dtsi
index 05451671..0be3756 100644
--- a/arch/arm/boot/dts/msm8974-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8974-regulator.dtsi
@@ -26,15 +26,33 @@
 
 		pm8941_mvs1: regulator@8300 {
 			parent-supply = <&pm8941_boost>;
-			qcom,enable-time = <200>;
+			qcom,enable-time = <1000>;
 			qcom,pull-down-enable = <1>;
+			interrupts = <0x1 0x83 0x2>;
+			interrupt-names = "ocp";
+			qcom,ocp-enable = <1>;
+			qcom,ocp-max-retries = <10>;
+			qcom,ocp-retry-delay = <30>;
+			qcom,soft-start-enable = <1>;
+			qcom,vs-soft-start-strength = <0>;
+			qcom,hpm-enable = <1>;
+			qcom,auto-mode-enable = <0>;
 			status = "okay";
 		};
 
 		pm8941_mvs2: regulator@8400 {
 			parent-supply = <&pm8941_boost>;
-			qcom,enable-time = <200>;
+			qcom,enable-time = <1000>;
 			qcom,pull-down-enable = <1>;
+			interrupts = <0x1 0x84 0x2>;
+			interrupt-names = "ocp";
+			qcom,ocp-enable = <1>;
+			qcom,ocp-max-retries = <10>;
+			qcom,ocp-retry-delay = <30>;
+			qcom,soft-start-enable = <1>;
+			qcom,vs-soft-start-strength = <0>;
+			qcom,hpm-enable = <1>;
+			qcom,auto-mode-enable = <0>;
 			status = "okay";
 		};
 	};
diff --git a/arch/arm/boot/dts/msm8974-v1-pm.dtsi b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
index ec6b14a..f9c0920 100644
--- a/arch/arm/boot/dts/msm8974-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
@@ -142,7 +142,7 @@
 			qcom,type = <0x62706d73>;	/* "smpb" */
 			qcom,id = <0x02>;
 			qcom,key = <0x6e726f63>;	/* "corn" */
-			qcom,init-value = <5>;		/* Super Turbo */
+			qcom,init-value = <6>;		/* Super Turbo */
 		};
 
 		qcom,lpm-resources@1 {
diff --git a/arch/arm/boot/dts/msm8974-v2-pm.dtsi b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
index 41837c1..5a1c047 100644
--- a/arch/arm/boot/dts/msm8974-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
@@ -142,7 +142,7 @@
 			qcom,type = <0x62706d73>;	/* "smpb" */
 			qcom,id = <0x02>;
 			qcom,key = <0x6e726f63>;	/* "corn" */
-			qcom,init-value = <5>;		/* Super Turbo */
+			qcom,init-value = <6>;		/* Super Turbo */
 		};
 
 		qcom,lpm-resources@1 {
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index a9685cc..3227370 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -246,7 +246,7 @@
 
 		qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
 		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-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
 		qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
 
 		qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 200000000>;
@@ -291,7 +291,7 @@
 
 		qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
 		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-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
 		qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
 
 		qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 200000000>;
@@ -834,8 +834,9 @@
 
 		qcom,firmware-name = "adsp";
 
-		/* GPIO input from lpass */
+		/* GPIO inputs from lpass */
 		qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_2_in 0 0>;
+		qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_2_in 2 0>;
 
 		/* GPIO output to lpass */
 		qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_2_out 0 0>;
@@ -1197,7 +1198,7 @@
                reg = <0xf9bff000 0x200>;
         };
 
-	qcom,qseecom@fe806000 {
+	qseecom: qcom,qseecom@7f00000 {
 		compatible = "qcom,qseecom";
 		reg = <0x7f00000 0x500000>;
 		reg-names = "secapp-region";
@@ -1369,8 +1370,8 @@
 		qcom,core-control-mask = <0xe>;
 		qcom,vdd-restriction-temp = <5>;
 		qcom,vdd-restriction-temp-hysteresis = <10>;
-		qcom,pmic-sw-mode-temp = <90>;
-		qcom,pmic-sw-mode-temp-hysteresis = <70>;
+		qcom,pmic-sw-mode-temp = <85>;
+		qcom,pmic-sw-mode-temp-hysteresis = <75>;
 		qcom,pmic-sw-mode-regs = "vdd_dig";
 		vdd_dig-supply = <&pm8841_s2_floor_corner>;
 		vdd_gfx-supply = <&pm8841_s4_floor_corner>;
@@ -1396,7 +1397,7 @@
 		qcom,rx-ring-size = <64>;
 	};
 
-        qcom,msm-mem-hole {
+        memory_hole: qcom,msm-mem-hole {
                 compatible = "qcom,msm-mem-hole";
                 qcom,memblock-remove = <0x7f00000 0x8000000>; /* Address and Size of Hole */
         };
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index 348e8c9..a79f403 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -392,7 +392,7 @@
 
 		qcom,pad-pull-on = <0x0 0x3 0x3>;
 		qcom,pad-pull-off = <0x0 0x3 0x3>;
-		qcom,pad-drv-on = <0x7 0x4 0x4>;
+		qcom,pad-drv-on = <0x4 0x4 0x4>;
 		qcom,pad-drv-off = <0x0 0x0 0x0>;
 
 		qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
@@ -761,9 +761,9 @@
 		qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_1_out 0 0>;
 	};
 
-	qcom,smem@fa00000 {
+	qcom,smem@0 {
 		compatible = "qcom,smem";
-		reg = <0xfa00000 0x200000>,
+		reg = <0x0 0x100000>,
 			<0xf9011000 0x1000>,
 			<0xfc428000 0x4000>;
 		reg-names = "smem", "irq-reg-base", "aux-mem1";
diff --git a/arch/arm/configs/msmzinc_defconfig b/arch/arm/configs/apq8084_defconfig
similarity index 99%
rename from arch/arm/configs/msmzinc_defconfig
rename to arch/arm/configs/apq8084_defconfig
index d0ea87a..c47117e 100644
--- a/arch/arm/configs/msmzinc_defconfig
+++ b/arch/arm/configs/apq8084_defconfig
@@ -34,7 +34,7 @@
 CONFIG_EFI_PARTITION=y
 CONFIG_IOSCHED_TEST=y
 CONFIG_ARCH_MSM=y
-CONFIG_ARCH_MSMZINC=y
+CONFIG_ARCH_APQ8084=y
 CONFIG_MSM_KRAIT_TBB_ABORT_HANDLER=y
 CONFIG_MSM_RPM_SMD=y
 # CONFIG_MSM_STACKED_MEMORY is not set
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index aa2c028..23244dc 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -239,6 +239,7 @@
 CONFIG_CMA=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
+CONFIG_TSPP=m
 CONFIG_HAPTIC_ISA1200=y
 CONFIG_QSEECOM=y
 CONFIG_QPNP_MISC=y
@@ -321,6 +322,7 @@
 CONFIG_MEDIA_CONTROLLER=y
 CONFIG_VIDEO_DEV=y
 CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_DVB_CORE=m
 # CONFIG_MSM_CAMERA is not set
 CONFIG_MT9M114=y
 CONFIG_OV2720=y
@@ -338,6 +340,8 @@
 CONFIG_MSMB_JPEG=y
 CONFIG_MSM_VIDC_V4L2=y
 CONFIG_MSM_WFD=y
+CONFIG_DVB_MPQ=m
+CONFIG_DVB_MPQ_DEMUX=m
 CONFIG_VIDEOBUF2_MSM_MEM=y
 CONFIG_USB_VIDEO_CLASS=y
 CONFIG_V4L_PLATFORM_DRIVERS=y
@@ -387,6 +391,8 @@
 CONFIG_USB_STORAGE_CYPRESS_ATACB=y
 CONFIG_USB_STORAGE_ENE_UB6250=y
 CONFIG_USB_EHSET_TEST_FIXTURE=y
+CONFIG_USB_QCOM_DIAG_BRIDGE=y
+CONFIG_USB_QCOM_KS_BRIDGE=y
 CONFIG_USB_GADGET=y
 CONFIG_USB_GADGET_DEBUG_FILES=y
 CONFIG_USB_CI13XXX_MSM=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index c9f068a..df1837f 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -85,6 +85,7 @@
 CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
 CONFIG_MSM_UARTDM_Core_v14=y
 CONFIG_MSM_BOOT_STATS=y
+CONFIG_MSM_XPU_ERR_FATAL=y
 CONFIG_STRICT_MEMORY_RWX=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
@@ -396,6 +397,8 @@
 CONFIG_USB_STORAGE_CYPRESS_ATACB=y
 CONFIG_USB_STORAGE_ENE_UB6250=y
 CONFIG_USB_EHSET_TEST_FIXTURE=y
+CONFIG_USB_QCOM_DIAG_BRIDGE=y
+CONFIG_USB_QCOM_KS_BRIDGE=y
 CONFIG_USB_GADGET=y
 CONFIG_USB_GADGET_DEBUG_FILES=y
 CONFIG_USB_CI13XXX_MSM=y
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index a6e6914..cc85d70 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -286,8 +286,8 @@
 	select MSM_RPM_LOG
 	select ARCH_WANT_KMAP_ATOMIC_FLUSH
 
-config ARCH_MSMZINC
-	bool "MSMZINC"
+config ARCH_APQ8084
+	bool "APQ8084"
 	select ARCH_MSM_KRAITMP
 	select GPIO_MSM_V3
 	select ARM_GIC
@@ -1086,7 +1086,7 @@
 	default "0x80200000" if ARCH_MSM8960
 	default "0x80200000" if ARCH_MSM8930
 	default "0x00000000" if ARCH_MSM8974
-	default "0x00000000" if ARCH_MSMZINC
+	default "0x00000000" if ARCH_APQ8084
 	default "0x00000000" if ARCH_MPQ8092
 	default "0x00000000" if ARCH_MSM8226
 	default "0x00000000" if ARCH_MSM8610
@@ -1239,13 +1239,13 @@
                   Say Y here if you want the debug print routines to direct
                   their output to the serial port on MPQ8092 devices.
 
-	config DEBUG_MSMZINC_UART
-                bool "Kernel low-level debugging messages via MSMZINC UART"
-                depends on ARCH_MSMZINC
+	config DEBUG_APQ8084_UART
+                bool "Kernel low-level debugging messages via APQ8084 UART"
+                depends on ARCH_APQ8084
                 select MSM_HAS_DEBUG_UART_HS_V14
                 help
                   Say Y here if you want the debug print routines to direct
-                  their output to the serial port on MSMZINC devices.
+                  their output to the serial port on APQ8084 devices.
 endchoice
 
 choice
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 7c78395..a45f5ec 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -120,7 +120,7 @@
 ifndef CONFIG_ARCH_MSM9625
 ifndef CONFIG_ARCH_MPQ8092
 ifndef CONFIG_ARCH_MSM8610
-ifndef CONFIG_ARCH_MSMZINC
+ifndef CONFIG_ARCH_APQ8084
 ifndef CONFIG_ARCH_MSMKRYPTON
 	obj-y += nand_partitions.o
 endif
@@ -297,7 +297,7 @@
 obj-$(CONFIG_MACH_MPQ8064_DTV) += board-8064-all.o board-8064-regulator.o
 obj-$(CONFIG_ARCH_MSM9615) += board-9615.o devices-9615.o board-9615-regulator.o board-9615-gpiomux.o board-9615-storage.o board-9615-display.o
 obj-$(CONFIG_ARCH_MSM9615) += clock-local.o clock-9615.o acpuclock-9615.o clock-rpm.o clock-pll.o
-obj-$(CONFIG_ARCH_MSMZINC) += board-zinc.o board-zinc-gpiomux.o
+obj-$(CONFIG_ARCH_APQ8084) += board-8084.o board-8084-gpiomux.o
 obj-$(CONFIG_ARCH_MSM8974) += board-8974.o board-8974-gpiomux.o
 obj-$(CONFIG_ARCH_MSM8974) += acpuclock-8974.o
 obj-$(CONFIG_ARCH_MSM8974) += clock-local2.o clock-pll.o clock-8974.o clock-rpm.o clock-voter.o clock-mdss-8974.o
@@ -375,7 +375,7 @@
 obj-$(CONFIG_ARCH_MPQ8092) += gpiomux-v2.o gpiomux.o
 obj-$(CONFIG_ARCH_MSM8226) += gpiomux-v2.o gpiomux.o
 obj-$(CONFIG_ARCH_MSM8610) += gpiomux-v2.o gpiomux.o
-obj-$(CONFIG_ARCH_MSMZINC) += gpiomux-v2.o gpiomux.o
+obj-$(CONFIG_ARCH_APQ8084) += gpiomux-v2.o gpiomux.o
 
 obj-$(CONFIG_MSM_SLEEP_STATS_DEVICE) += idle_stats_device.o
 obj-$(CONFIG_MSM_DCVS) += msm_dcvs_scm.o msm_dcvs.o msm_mpdecision.o
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index 8c366da..b2fe474 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -57,10 +57,11 @@
         dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974-v2-fluid.dtb
         dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974-v2-liquid.dtb
         dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974-v2-mtp.dtb
+        dtb-$(CONFIG_ARCH_MSM8974)	+= apq8074-v2-liquid.dtb
 
-# MSMZINC
-   zreladdr-$(CONFIG_ARCH_MSMZINC)	:= 0x00008000
-        dtb-$(CONFIG_ARCH_MSMZINC)	+= msmzinc-sim.dtb
+# APQ8084
+   zreladdr-$(CONFIG_ARCH_APQ8084)	:= 0x00008000
+        dtb-$(CONFIG_ARCH_APQ8084)	+= apq8084-sim.dtb
 
 # MSMKRYPTON
    zreladdr-$(CONFIG_ARCH_MSMKRYPTON)	:= 0x00208000
diff --git a/arch/arm/mach-msm/acpuclock-8226.c b/arch/arm/mach-msm/acpuclock-8226.c
index 799d629..25bebd1 100644
--- a/arch/arm/mach-msm/acpuclock-8226.c
+++ b/arch/arm/mach-msm/acpuclock-8226.c
@@ -26,12 +26,13 @@
 #include <mach/msm_bus.h>
 #include <mach/msm_bus_board.h>
 #include <mach/rpm-regulator-smd.h>
+#include <mach/socinfo.h>
 
 #include "acpuclock-cortex.h"
 
 #define RCG_CONFIG_UPDATE_BIT		BIT(0)
 
-static struct msm_bus_paths bw_level_tbl[] = {
+static struct msm_bus_paths bw_level_tbl_8226[] = {
 	[0] =  BW_MBPS(152), /* At least 19 MHz on bus. */
 	[1] =  BW_MBPS(300), /* At least 37.5 MHz on bus. */
 	[2] =  BW_MBPS(400), /* At least 50 MHz on bus. */
@@ -42,9 +43,18 @@
 	[7] = BW_MBPS(4264), /* At least 533 MHz on bus. */
 };
 
+static struct msm_bus_paths bw_level_tbl_8610[] = {
+	[0] =  BW_MBPS(152), /* At least 19 MHz on bus. */
+	[1] =  BW_MBPS(300), /* At least 37.5 MHz on bus. */
+	[2] =  BW_MBPS(400), /* At least 50 MHz on bus. */
+	[3] =  BW_MBPS(800), /* At least 100 MHz on bus. */
+	[4] = BW_MBPS(1600), /* At least 200 MHz on bus. */
+	[5] = BW_MBPS(2128), /* At least 266 MHz on bus. */
+};
+
 static struct msm_bus_scale_pdata bus_client_pdata = {
-	.usecase = bw_level_tbl,
-	.num_usecases = ARRAY_SIZE(bw_level_tbl),
+	.usecase = bw_level_tbl_8226,
+	.num_usecases = ARRAY_SIZE(bw_level_tbl_8226),
 	.active_only = 1,
 	.name = "acpuclock",
 };
@@ -54,7 +64,7 @@
  * 2) Update bus bandwidth
  * 3) Depending on Frodo version, may need minimum of LVL_NOM
  */
-static struct clkctl_acpu_speed acpu_freq_tbl[] = {
+static struct clkctl_acpu_speed acpu_freq_tbl_8226[] = {
 	{ 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 },
@@ -65,8 +75,19 @@
 	{ 0 }
 };
 
+static struct clkctl_acpu_speed acpu_freq_tbl_8610[] = {
+	{ 0,   19200, CXO,     0, 0,   CPR_CORNER_SVS,   1150000, 0 },
+	{ 1,  300000, PLL0,    4, 2,   CPR_CORNER_SVS,   1150000, 3 },
+	{ 1,  384000, ACPUPLL, 5, 0,   CPR_CORNER_SVS,   1150000, 3 },
+	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_NORMAL,   1150000, 4 },
+	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_NORMAL,   1150000, 4 },
+	{ 0,  998400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,   1275000, 5 },
+	{ 0, 1190400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,   1275000, 5 },
+	{ 0 }
+};
+
 static struct acpuclk_drv_data drv_data = {
-	.freq_tbl = acpu_freq_tbl,
+	.freq_tbl = acpu_freq_tbl_8226,
 	.current_speed = &(struct clkctl_acpu_speed){ 0 },
 	.bus_scale = &bus_client_pdata,
 	.vdd_max_cpu = CPR_CORNER_TURBO,
@@ -146,8 +167,18 @@
 	},
 };
 
+void msm8610_acpu_init(void)
+{
+	drv_data.bus_scale->usecase = bw_level_tbl_8610;
+	drv_data.bus_scale->num_usecases = ARRAY_SIZE(bw_level_tbl_8610);
+	drv_data.freq_tbl = acpu_freq_tbl_8610;
+}
+
 static int __init acpuclk_a7_init(void)
 {
+	if (cpu_is_msm8610())
+		msm8610_acpu_init();
+
 	return platform_driver_probe(&acpuclk_a7_driver, acpuclk_a7_probe);
 }
 device_initcall(acpuclk_a7_init);
diff --git a/arch/arm/mach-msm/acpuclock-8960ab.c b/arch/arm/mach-msm/acpuclock-8960ab.c
index 38658a2..0fa2cde 100644
--- a/arch/arm/mach-msm/acpuclock-8960ab.c
+++ b/arch/arm/mach-msm/acpuclock-8960ab.c
@@ -109,12 +109,12 @@
 
 static struct acpu_level freq_tbl_PVS0[] __initdata = {
 	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   950000, AVS(0x70001F) },
-	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(3),   950000, AVS(0x0) },
-	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(3),   975000, AVS(0x0) },
-	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(3),  1000000, AVS(0x0) },
-	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(3),  1025000, AVS(0x0) },
-	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(3),  1050000, AVS(0x0) },
-	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(3),  1075000, AVS(0x0) },
+	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(4),   950000, AVS(0x0) },
+	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(4),   975000, AVS(0x0) },
+	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(4),  1000000, AVS(0x0) },
+	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(4),  1025000, AVS(0x0) },
+	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(4),  1050000, AVS(0x0) },
+	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(4),  1075000, AVS(0x0) },
 	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(9),  1100000, AVS(0x70000D) },
 	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(9),  1125000, AVS(0x0) },
 	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(9),  1150000, AVS(0x0) },
@@ -127,12 +127,12 @@
 
 static struct acpu_level freq_tbl_PVS1[] __initdata = {
 	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   925000, AVS(0x70001F) },
-	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(3),   925000, AVS(0x0) },
-	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(3),   950000, AVS(0x0) },
-	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(3),   975000, AVS(0x0) },
-	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(3),  1000000, AVS(0x0) },
-	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(3),  1025000, AVS(0x0) },
-	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(3),  1050000, AVS(0x0) },
+	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(4),   925000, AVS(0x0) },
+	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(4),   950000, AVS(0x0) },
+	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(4),   975000, AVS(0x0) },
+	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(4),  1000000, AVS(0x0) },
+	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(4),  1025000, AVS(0x0) },
+	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(4),  1050000, AVS(0x0) },
 	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(9),  1075000, AVS(0x70000D) },
 	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(9),  1100000, AVS(0x0) },
 	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(9),  1125000, AVS(0x0) },
@@ -145,12 +145,12 @@
 
 static struct acpu_level freq_tbl_PVS2[] __initdata = {
 	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   900000, AVS(0x70001F) },
-	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(3),   900000, AVS(0x0) },
-	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(3),   925000, AVS(0x0) },
-	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(3),   950000, AVS(0x0) },
-	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(3),   975000, AVS(0x0) },
-	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(3),  1000000, AVS(0x0) },
-	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(3),  1025000, AVS(0x0) },
+	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(4),   900000, AVS(0x0) },
+	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(4),   925000, AVS(0x0) },
+	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(4),   950000, AVS(0x0) },
+	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(4),   975000, AVS(0x0) },
+	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(4),  1000000, AVS(0x0) },
+	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(4),  1025000, AVS(0x0) },
 	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(9),  1050000, AVS(0x70000D) },
 	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(9),  1075000, AVS(0x0) },
 	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(9),  1100000, AVS(0x0) },
@@ -163,12 +163,12 @@
 
 static struct acpu_level freq_tbl_PVS3[] __initdata = {
 	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   900000, AVS(0x70001F) },
-	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(3),   900000, AVS(0x0) },
-	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(3),   900000, AVS(0x0) },
-	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(3),   925000, AVS(0x0) },
-	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(3),   950000, AVS(0x0) },
-	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(3),   975000, AVS(0x0) },
-	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(3),  1000000, AVS(0x0) },
+	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(4),   900000, AVS(0x0) },
+	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(4),   900000, AVS(0x0) },
+	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(4),   925000, AVS(0x0) },
+	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(4),   950000, AVS(0x0) },
+	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(4),   975000, AVS(0x0) },
+	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(4),  1000000, AVS(0x0) },
 	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(9),  1025000, AVS(0x70000D) },
 	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(9),  1050000, AVS(0x0) },
 	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(9),  1075000, AVS(0x0) },
@@ -181,12 +181,12 @@
 
 static struct acpu_level freq_tbl_PVS4[] __initdata = {
 	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   875000, AVS(0x70001F) },
-	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(3),   875000, AVS(0x0) },
-	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(3),   875000, AVS(0x0) },
-	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(3),   900000, AVS(0x0) },
-	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(3),   925000, AVS(0x0) },
-	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(3),   950000, AVS(0x0) },
-	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(3),   975000, AVS(0x0) },
+	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(4),   875000, AVS(0x0) },
+	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(4),   875000, AVS(0x0) },
+	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(4),   900000, AVS(0x0) },
+	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(4),   925000, AVS(0x0) },
+	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(4),   950000, AVS(0x0) },
+	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(4),   975000, AVS(0x0) },
 	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(9),  1000000, AVS(0x70000D) },
 	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(9),  1025000, AVS(0x0) },
 	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(9),  1050000, AVS(0x0) },
@@ -199,12 +199,12 @@
 
 static struct acpu_level freq_tbl_PVS5[] __initdata = {
 	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   875000, AVS(0x70001F) },
-	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(3),   875000, AVS(0x0) },
-	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(3),   875000, AVS(0x0) },
-	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(3),   875000, AVS(0x0) },
-	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(3),   900000, AVS(0x0) },
-	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(3),   925000, AVS(0x0) },
-	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(3),   950000, AVS(0x0) },
+	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(4),   875000, AVS(0x0) },
+	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(4),   875000, AVS(0x0) },
+	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(4),   875000, AVS(0x0) },
+	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(4),   900000, AVS(0x0) },
+	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(4),   925000, AVS(0x0) },
+	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(4),   950000, AVS(0x0) },
 	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(9),   975000, AVS(0x70000D) },
 	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(9),  1000000, AVS(0x0) },
 	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(9),  1025000, AVS(0x0) },
@@ -217,12 +217,12 @@
 
 static struct acpu_level freq_tbl_PVS6[] __initdata = {
 	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   850000, AVS(0x70001F) },
-	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(3),   850000, AVS(0x0) },
-	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(3),   850000, AVS(0x0) },
-	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(3),   850000, AVS(0x0) },
-	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(3),   875000, AVS(0x0) },
-	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(3),   900000, AVS(0x0) },
-	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(3),   925000, AVS(0x0) },
+	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(4),   850000, AVS(0x0) },
+	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(4),   850000, AVS(0x0) },
+	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(4),   850000, AVS(0x0) },
+	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(4),   875000, AVS(0x0) },
+	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(4),   900000, AVS(0x0) },
+	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(4),   925000, AVS(0x0) },
 	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(9),   950000, AVS(0x70000D) },
 	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(9),   975000, AVS(0x0) },
 	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(9),  1000000, AVS(0x0) },
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index 2f09162..bed794b 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -1386,12 +1386,11 @@
 	struct list_head *temp;
 	struct outside_notify_func *func;
 
+	BAM_DMUX_LOG("%s: event=%d, data=%lu\n", __func__, event, data);
+
 	for (i = 0; i < BAM_DMUX_NUM_CHANNELS; ++i) {
-		if (bam_ch_is_open(i)) {
+		if (bam_ch_is_open(i))
 			bam_ch[i].notify(bam_ch[i].priv, event, data);
-			BAM_DMUX_LOG("%s: cid=%d, event=%d, data=%lu\n",
-					__func__, i, event, data);
-		}
 	}
 
 	__list_for_each(temp, &bam_other_notify_funcs) {
@@ -1758,10 +1757,13 @@
 	/* in_ssr documentation/assumptions found in restart_notifier_cb */
 	if (!power_management_only_mode) {
 		if (likely(!in_ssr)) {
+			BAM_DMUX_LOG("%s: disconnect tx\n", __func__);
 			sps_disconnect(bam_tx_pipe);
+			BAM_DMUX_LOG("%s: disconnect rx\n", __func__);
 			sps_disconnect(bam_rx_pipe);
 			__memzero(rx_desc_mem_buf.base, rx_desc_mem_buf.size);
 			__memzero(tx_desc_mem_buf.base, tx_desc_mem_buf.size);
+			BAM_DMUX_LOG("%s: device reset\n", __func__);
 			sps_device_reset(a2_device_handle);
 		} else {
 			ssr_skipped_disconnect = 1;
diff --git a/arch/arm/mach-msm/board-zinc-gpiomux.c b/arch/arm/mach-msm/board-8084-gpiomux.c
similarity index 94%
rename from arch/arm/mach-msm/board-zinc-gpiomux.c
rename to arch/arm/mach-msm/board-8084-gpiomux.c
index ac4daa8..8d5bb49 100644
--- a/arch/arm/mach-msm/board-zinc-gpiomux.c
+++ b/arch/arm/mach-msm/board-8084-gpiomux.c
@@ -17,7 +17,7 @@
 #include <mach/board.h>
 #include <mach/gpiomux.h>
 
-void __init msmzinc_init_gpiomux(void)
+void __init apq8084_init_gpiomux(void)
 {
 	int rc;
 
diff --git a/arch/arm/mach-msm/board-zinc.c b/arch/arm/mach-msm/board-8084.c
similarity index 67%
rename from arch/arm/mach-msm/board-zinc.c
rename to arch/arm/mach-msm/board-8084.c
index 444444f..828ae9c 100644
--- a/arch/arm/mach-msm/board-zinc.c
+++ b/arch/arm/mach-msm/board-8084.c
@@ -32,7 +32,7 @@
 #include "devices.h"
 #include "platsmp.h"
 
-static struct memtype_reserve msmzinc_reserve_table[] __initdata = {
+static struct memtype_reserve apq8084_reserve_table[] __initdata = {
 	[MEMTYPE_SMI] = {
 	},
 	[MEMTYPE_EBI0] = {
@@ -43,27 +43,27 @@
 	},
 };
 
-static int msmzinc_paddr_to_memtype(phys_addr_t paddr)
+static int apq8084_paddr_to_memtype(phys_addr_t paddr)
 {
 	return MEMTYPE_EBI1;
 }
 
-static struct reserve_info msmzinc_reserve_info __initdata = {
-	.memtype_reserve_table = msmzinc_reserve_table,
-	.paddr_to_memtype = msmzinc_paddr_to_memtype,
+static struct reserve_info apq8084_reserve_info __initdata = {
+	.memtype_reserve_table = apq8084_reserve_table,
+	.paddr_to_memtype = apq8084_paddr_to_memtype,
 };
 
-void __init msmzinc_reserve(void)
+void __init apq8084_reserve(void)
 {
-	reserve_info = &msmzinc_reserve_info;
-	of_scan_flat_dt(dt_scan_for_memory_reserve, msmzinc_reserve_table);
+	reserve_info = &apq8084_reserve_info;
+	of_scan_flat_dt(dt_scan_for_memory_reserve, apq8084_reserve_table);
 	msm_reserve();
 }
 
-static void __init msmzinc_early_memory(void)
+static void __init apq8084_early_memory(void)
 {
-	reserve_info = &msmzinc_reserve_info;
-	of_scan_flat_dt(dt_scan_for_memory_hole, msmzinc_reserve_table);
+	reserve_info = &apq8084_reserve_info;
+	of_scan_flat_dt(dt_scan_for_memory_hole, apq8084_reserve_table);
 }
 
 static struct clk_lookup msm_clocks_dummy[] = {
@@ -82,46 +82,46 @@
  * into this category, and thus the driver should not be added here. The
  * EPROBE_DEFER can satisfy most dependency problems.
  */
-void __init msmzinc_add_drivers(void)
+void __init apq8084_add_drivers(void)
 {
 	msm_smd_init();
 	msm_clock_init(&msm_dummy_clock_init_data);
 }
 
-static void __init msmzinc_map_io(void)
+static void __init apq8084_map_io(void)
 {
-	msm_map_zinc_io();
+	msm_map_8084_io();
 }
 
-void __init msmzinc_init(void)
+void __init apq8084_init(void)
 {
 	if (socinfo_init() < 0)
 		pr_err("%s: socinfo_init() failed\n", __func__);
 
-	msmzinc_init_gpiomux();
+	apq8084_init_gpiomux();
 	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
-	msmzinc_add_drivers();
+	apq8084_add_drivers();
 }
 
-void __init msmzinc_init_very_early(void)
+void __init apq8084_init_very_early(void)
 {
-	msmzinc_early_memory();
+	apq8084_early_memory();
 }
 
-static const char *msmzinc_dt_match[] __initconst = {
-	"qcom,msmzinc",
+static const char *apq8084_dt_match[] __initconst = {
+	"qcom,apq8084",
 	NULL
 };
 
-DT_MACHINE_START(MSMZINC_DT, "Qualcomm MSM ZINC (Flattened Device Tree)")
-	.map_io = msmzinc_map_io,
+DT_MACHINE_START(APQ8084_DT, "Qualcomm APQ 8084 (Flattened Device Tree)")
+	.map_io = apq8084_map_io,
 	.init_irq = msm_dt_init_irq,
-	.init_machine = msmzinc_init,
+	.init_machine = apq8084_init,
 	.handle_irq = gic_handle_irq,
 	.timer = &msm_dt_timer,
-	.dt_compat = msmzinc_dt_match,
-	.reserve = msmzinc_reserve,
-	.init_very_early = msmzinc_init_very_early,
+	.dt_compat = apq8084_dt_match,
+	.reserve = apq8084_reserve,
+	.init_very_early = apq8084_init_very_early,
 	.restart = msm_restart,
 	.smp = &msm8974_smp_ops,
 MACHINE_END
diff --git a/arch/arm/mach-msm/board-8974.c b/arch/arm/mach-msm/board-8974.c
index cfa1628..3eed219 100644
--- a/arch/arm/mach-msm/board-8974.c
+++ b/arch/arm/mach-msm/board-8974.c
@@ -174,6 +174,7 @@
 
 static const char *msm8974_dt_match[] __initconst = {
 	"qcom,msm8974",
+	"qcom,apq8074",
 	NULL
 };
 
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index 4eb3d29..6d76c41 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -2697,7 +2697,6 @@
 	.base = &virt_bases[LPASS_BASE],
 	.c = {
 		.dbg_name = "q6ss_xo_clk",
-		.parent = &xo.c,
 		.ops = &clk_ops_branch,
 		CLK_INIT(q6ss_xo_clk.c),
 	},
@@ -3328,6 +3327,8 @@
 	CLK_LOOKUP("csi1_rdi_clk", camss_csi1rdi_clk.c,  "fda08400.qcom,csid"),
 
 	/* ISPIF clocks */
+	CLK_LOOKUP("ispif_ahb_clk", camss_ispif_ahb_clk.c,
+		"fda0a000.qcom,ispif"),
 	CLK_LOOKUP("camss_vfe_vfe_clk", camss_vfe_vfe0_clk.c,
 		"fda0a000.qcom,ispif"),
 	CLK_LOOKUP("camss_csi_vfe_clk", camss_csi_vfe0_clk.c,
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index 8880661..3cb3ea4 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -2245,7 +2245,6 @@
 	.bcr_reg = LPASS_Q6SS_BCR,
 	.base = &virt_bases[LPASS_BASE],
 	.c = {
-		.parent = &gcc_xo_clk_src.c,
 		.dbg_name = "q6ss_xo_clk",
 		.ops = &clk_ops_branch,
 		CLK_INIT(q6ss_xo_clk.c),
@@ -2714,7 +2713,7 @@
 	CLK_LOOKUP("core_clk",      gcc_mss_q6_bimc_axi_clk.c, ""),
 	CLK_LOOKUP("core_clk",                 gcc_pdm2_clk.c, ""),
 	CLK_LOOKUP("iface_clk",              gcc_pdm_ahb_clk.c, ""),
-	CLK_LOOKUP("iface_clk",             gcc_prng_ahb_clk.c, ""),
+	CLK_LOOKUP("iface_clk", gcc_prng_ahb_clk.c, "f9bff000.qcom,msm-rng"),
 	CLK_LOOKUP("iface_clk",            gcc_sdcc1_ahb_clk.c, "msm_sdcc.1"),
 	CLK_LOOKUP("core_clk",           gcc_sdcc1_apps_clk.c, "msm_sdcc.1"),
 	CLK_LOOKUP("iface_clk",            gcc_sdcc2_ahb_clk.c, "msm_sdcc.2"),
@@ -2830,6 +2829,11 @@
 	CLK_LOOKUP("iface_clk",    gcc_ce1_ahb_clk.c,  "qseecom"),
 	CLK_LOOKUP("bus_clk",      gcc_ce1_axi_clk.c,  "qseecom"),
 	CLK_LOOKUP("core_clk_src", ce1_clk_src.c,      "qseecom"),
+
+	CLK_LOOKUP("core_clk",     gcc_ce1_clk.c,      "scm"),
+	CLK_LOOKUP("iface_clk",    gcc_ce1_ahb_clk.c,  "scm"),
+	CLK_LOOKUP("bus_clk",      gcc_ce1_axi_clk.c,  "scm"),
+	CLK_LOOKUP("core_clk_src", ce1_clk_src.c,      "scm"),
 };
 
 static struct clk_lookup msm_clocks_8610_rumi[] = {
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 509443d..be6d965 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -5419,11 +5419,6 @@
 	CLK_LOOKUP("csi_phy_clk",	csi0_phy_clk.c,		"msm_csid.0"),
 	CLK_LOOKUP("csi_phy_clk",	csi1_phy_clk.c,		"msm_csid.1"),
 	CLK_LOOKUP("csi_phy_clk",	csi2_phy_clk.c,		"msm_csid.2"),
-	CLK_LOOKUP("csi_pix_clk",	csi_pix_clk.c,		"msm_ispif.0"),
-	CLK_LOOKUP("csi_pix1_clk",	csi_pix1_clk.c,		"msm_ispif.0"),
-	CLK_LOOKUP("csi_rdi_clk",	csi_rdi_clk.c,		"msm_ispif.0"),
-	CLK_LOOKUP("csi_rdi1_clk",	csi_rdi1_clk.c,		"msm_ispif.0"),
-	CLK_LOOKUP("csi_rdi2_clk",	csi_rdi2_clk.c,		"msm_ispif.0"),
 	CLK_LOOKUP("csiphy_timer_src_clk",
 			   csiphy_timer_src_clk.c, "msm_csiphy.0"),
 	CLK_LOOKUP("csiphy_timer_src_clk",
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 1d7af9b..707e6b6 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -4947,80 +4947,79 @@
 		"fda0b400.qcom,csiphy"),
 	CLK_LOOKUP("csiphy_timer_clk", camss_phy2_csi2phytimer_clk.c,
 		"fda0b400.qcom,csiphy"),
+
 	/* CSID clocks */
-	CLK_LOOKUP("camss_top_ahb_clk", camss_top_ahb_clk.c,
-		"fda08000.qcom,csid"),
 	CLK_LOOKUP("ispif_ahb_clk", camss_ispif_ahb_clk.c,
-		"fda08000.qcom,csid"),
-	CLK_LOOKUP("csi0_ahb_clk", camss_csi0_ahb_clk.c, "fda08000.qcom,csid"),
-	CLK_LOOKUP("csi0_src_clk", csi0_clk_src.c, "fda08000.qcom,csid"),
-	CLK_LOOKUP("csi0_phy_clk", camss_csi0phy_clk.c, "fda08000.qcom,csid"),
-	CLK_LOOKUP("csi0_clk", camss_csi0_clk.c, "fda08000.qcom,csid"),
-	CLK_LOOKUP("csi0_pix_clk", camss_csi0pix_clk.c, "fda08000.qcom,csid"),
-	CLK_LOOKUP("csi0_rdi_clk", camss_csi0rdi_clk.c, "fda08000.qcom,csid"),
+					"fda08000.qcom,csid"),
+	CLK_LOOKUP("camss_top_ahb_clk", camss_top_ahb_clk.c,
+					"fda08000.qcom,csid"),
+	CLK_LOOKUP("csi_ahb_clk", camss_csi0_ahb_clk.c,
+					"fda08000.qcom,csid"),
+	CLK_LOOKUP("csi_src_clk", csi0_clk_src.c,
+					"fda08000.qcom,csid"),
+	CLK_LOOKUP("csi_phy_clk", camss_csi0phy_clk.c,
+					"fda08000.qcom,csid"),
+	CLK_LOOKUP("csi_clk", camss_csi0_clk.c,
+					"fda08000.qcom,csid"),
+	CLK_LOOKUP("csi_pix_clk", camss_csi0pix_clk.c,
+					"fda08000.qcom,csid"),
+	CLK_LOOKUP("csi_rdi_clk", camss_csi0rdi_clk.c,
+					"fda08000.qcom,csid"),
 
-	CLK_LOOKUP("camss_top_ahb_clk", camss_top_ahb_clk.c,
-		"fda08400.qcom,csid"),
 	CLK_LOOKUP("ispif_ahb_clk", camss_ispif_ahb_clk.c,
-		"fda08400.qcom,csid"),
-	CLK_LOOKUP("csi0_ahb_clk", camss_csi0_ahb_clk.c, "fda08400.qcom,csid"),
-	CLK_LOOKUP("csi1_ahb_clk", camss_csi1_ahb_clk.c, "fda08400.qcom,csid"),
-	CLK_LOOKUP("csi0_src_clk", csi0_clk_src.c, "fda08400.qcom,csid"),
-	CLK_LOOKUP("csi1_src_clk", csi1_clk_src.c, "fda08400.qcom,csid"),
-	CLK_LOOKUP("csi0_phy_clk", camss_csi0phy_clk.c, "fda08400.qcom,csid"),
-	CLK_LOOKUP("csi1_phy_clk", camss_csi1phy_clk.c, "fda08400.qcom,csid"),
-	CLK_LOOKUP("csi0_clk", camss_csi0_clk.c, "fda08400.qcom,csid"),
-	CLK_LOOKUP("csi1_clk", camss_csi1_clk.c, "fda08400.qcom,csid"),
-	CLK_LOOKUP("csi0_pix_clk", camss_csi0pix_clk.c, "fda08400.qcom,csid"),
-	CLK_LOOKUP("csi1_pix_clk", camss_csi1pix_clk.c, "fda08400.qcom,csid"),
-	CLK_LOOKUP("csi0_rdi_clk", camss_csi0rdi_clk.c, "fda08400.qcom,csid"),
-	CLK_LOOKUP("csi1_rdi_clk", camss_csi1rdi_clk.c, "fda08400.qcom,csid"),
+					"fda08400.qcom,csid"),
+	CLK_LOOKUP("camss_top_ahb_clk", camss_top_ahb_clk.c,
+					"fda08400.qcom,csid"),
+	CLK_LOOKUP("csi_ahb_clk", camss_csi1_ahb_clk.c,
+					"fda08400.qcom,csid"),
+	CLK_LOOKUP("csi_src_clk", csi1_clk_src.c,
+					"fda08400.qcom,csid"),
+	CLK_LOOKUP("csi_phy_clk", camss_csi1phy_clk.c,
+					"fda08400.qcom,csid"),
+	CLK_LOOKUP("csi_clk", camss_csi1_clk.c,
+					"fda08400.qcom,csid"),
+	CLK_LOOKUP("csi_pix_clk", camss_csi1pix_clk.c,
+					"fda08400.qcom,csid"),
+	CLK_LOOKUP("csi_rdi_clk", camss_csi1rdi_clk.c,
+					"fda08400.qcom,csid"),
 
-	CLK_LOOKUP("camss_top_ahb_clk", camss_top_ahb_clk.c,
-		"fda08800.qcom,csid"),
 	CLK_LOOKUP("ispif_ahb_clk", camss_ispif_ahb_clk.c,
-		"fda08800.qcom,csid"),
-	CLK_LOOKUP("csi0_ahb_clk", camss_csi0_ahb_clk.c, "fda08800.qcom,csid"),
-	CLK_LOOKUP("csi2_ahb_clk", camss_csi2_ahb_clk.c, "fda08800.qcom,csid"),
-	CLK_LOOKUP("csi0_src_clk", csi0_clk_src.c, "fda08800.qcom,csid"),
-	CLK_LOOKUP("csi2_src_clk", csi2_clk_src.c, "fda08800.qcom,csid"),
-	CLK_LOOKUP("csi0_phy_clk", camss_csi0phy_clk.c, "fda08800.qcom,csid"),
-	CLK_LOOKUP("csi2_phy_clk", camss_csi2phy_clk.c, "fda08800.qcom,csid"),
-	CLK_LOOKUP("csi0_clk", camss_csi0_clk.c, "fda08800.qcom,csid"),
-	CLK_LOOKUP("csi2_clk", camss_csi2_clk.c, "fda08800.qcom,csid"),
-	CLK_LOOKUP("csi0_pix_clk", camss_csi0pix_clk.c, "fda08800.qcom,csid"),
-	CLK_LOOKUP("csi2_pix_clk", camss_csi2pix_clk.c, "fda08800.qcom,csid"),
-	CLK_LOOKUP("csi0_rdi_clk", camss_csi0rdi_clk.c, "fda08800.qcom,csid"),
-	CLK_LOOKUP("csi2_rdi_clk", camss_csi2rdi_clk.c, "fda08800.qcom,csid"),
+					"fda08800.qcom,csid"),
+	CLK_LOOKUP("camss_top_ahb_clk", camss_top_ahb_clk.c,
+					"fda08800.qcom,csid"),
+	CLK_LOOKUP("csi_ahb_clk", camss_csi2_ahb_clk.c,
+					"fda08800.qcom,csid"),
+	CLK_LOOKUP("csi_src_clk", csi2_clk_src.c,
+					"fda08800.qcom,csid"),
+	CLK_LOOKUP("csi_phy_clk", camss_csi2phy_clk.c,
+					"fda08800.qcom,csid"),
+	CLK_LOOKUP("csi_clk", camss_csi2_clk.c,
+					"fda08800.qcom,csid"),
+	CLK_LOOKUP("csi_pix_clk", camss_csi2pix_clk.c,
+					"fda08800.qcom,csid"),
+	CLK_LOOKUP("csi_rdi_clk", camss_csi2rdi_clk.c,
+					"fda08800.qcom,csid"),
 
-	CLK_LOOKUP("camss_top_ahb_clk", camss_top_ahb_clk.c,
-		"fda08c00.qcom,csid"),
 	CLK_LOOKUP("ispif_ahb_clk", camss_ispif_ahb_clk.c,
-		"fda08c00.qcom,csid"),
-	CLK_LOOKUP("csi0_ahb_clk", camss_csi0_ahb_clk.c, "fda08c00.qcom,csid"),
-	CLK_LOOKUP("csi3_ahb_clk", camss_csi3_ahb_clk.c, "fda08c00.qcom,csid"),
-	CLK_LOOKUP("csi0_src_clk", csi0_clk_src.c, "fda08c00.qcom,csid"),
-	CLK_LOOKUP("csi3_src_clk", csi3_clk_src.c, "fda08c00.qcom,csid"),
-	CLK_LOOKUP("csi0_phy_clk", camss_csi0phy_clk.c, "fda08c00.qcom,csid"),
-	CLK_LOOKUP("csi3_phy_clk", camss_csi3phy_clk.c, "fda08c00.qcom,csid"),
-	CLK_LOOKUP("csi0_clk", camss_csi0_clk.c, "fda08c00.qcom,csid"),
-	CLK_LOOKUP("csi3_clk", camss_csi3_clk.c, "fda08c00.qcom,csid"),
-	CLK_LOOKUP("csi0_pix_clk", camss_csi0pix_clk.c, "fda08c00.qcom,csid"),
-	CLK_LOOKUP("csi3_pix_clk", camss_csi3pix_clk.c, "fda08c00.qcom,csid"),
-	CLK_LOOKUP("csi0_rdi_clk", camss_csi0rdi_clk.c, "fda08c00.qcom,csid"),
-	CLK_LOOKUP("csi3_rdi_clk", camss_csi3rdi_clk.c, "fda08c00.qcom,csid"),
+					"fda08c00.qcom,csid"),
+	CLK_LOOKUP("camss_top_ahb_clk", camss_top_ahb_clk.c,
+					"fda08c00.qcom,csid"),
+	CLK_LOOKUP("csi_ahb_clk", camss_csi3_ahb_clk.c,
+					"fda08c00.qcom,csid"),
+	CLK_LOOKUP("csi_src_clk", csi3_clk_src.c,
+					"fda08c00.qcom,csid"),
+	CLK_LOOKUP("csi_phy_clk", camss_csi3phy_clk.c,
+					"fda08c00.qcom,csid"),
+	CLK_LOOKUP("csi_clk", camss_csi3_clk.c,
+					"fda08c00.qcom,csid"),
+	CLK_LOOKUP("csi_pix_clk", camss_csi3pix_clk.c,
+					"fda08c00.qcom,csid"),
+	CLK_LOOKUP("csi_rdi_clk", camss_csi3rdi_clk.c,
+					"fda08c00.qcom,csid"),
 
 	/* ISPIF clocks */
 	CLK_LOOKUP("ispif_ahb_clk", camss_ispif_ahb_clk.c,
 		"fda0a000.qcom,ispif"),
-	CLK_LOOKUP("camss_vfe_vfe_clk", camss_vfe_vfe0_clk.c,
-		"fda0a000.qcom,ispif"),
-	CLK_LOOKUP("camss_csi_vfe_clk", camss_csi_vfe0_clk.c,
-		"fda0a000.qcom,ispif"),
-	CLK_LOOKUP("camss_vfe_vfe_clk1", camss_vfe_vfe1_clk.c,
-		"fda0a000.qcom,ispif"),
-	CLK_LOOKUP("camss_csi_vfe_clk1", camss_csi_vfe1_clk.c,
-		"fda0a000.qcom,ispif"),
 
 	/*VFE clocks*/
 	CLK_LOOKUP("camss_top_ahb_clk", camss_top_ahb_clk.c,
diff --git a/arch/arm/mach-msm/clock-local2.c b/arch/arm/mach-msm/clock-local2.c
index 8c2121f..0d1104e 100644
--- a/arch/arm/mach-msm/clock-local2.c
+++ b/arch/arm/mach-msm/clock-local2.c
@@ -596,6 +596,13 @@
 		ret = -EINVAL;
 	}
 	writel_relaxed(cbcr_val, CBCR_REG(branch));
+	/*
+	 * 8974v2.2 has a requirement that writes to set bits 13 and 14 are
+	 * separated by at least 2 bus cycles. Cover one of these cycles by
+	 * performing an extra write here. The other cycle is covered by the
+	 * read-modify-write design of this function.
+	 */
+	writel_relaxed(cbcr_val, CBCR_REG(branch));
 	spin_unlock_irqrestore(&local_clock_reg_lock, irq_flags);
 
 	/* Make sure write is issued before returning. */
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 72f5051..22f74c8 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -600,7 +600,7 @@
 void msm_map_msm7x30_io(void);
 void msm_map_fsm9xxx_io(void);
 void msm_map_8974_io(void);
-void msm_map_zinc_io(void);
+void msm_map_8084_io(void);
 void msm_map_msmkrypton_io(void);
 void msm_map_msm8625_io(void);
 void msm_map_msm9625_io(void);
@@ -610,7 +610,7 @@
 void msm_8974_reserve(void);
 void msm_8974_very_early(void);
 void msm_8974_init_gpiomux(void);
-void msmzinc_init_gpiomux(void);
+void apq8084_init_gpiomux(void);
 void msm9625_init_gpiomux(void);
 void msmkrypton_init_gpiomux(void);
 void msm_map_mpq8092_io(void);
@@ -653,7 +653,7 @@
 void msm_snddev_tx_route_config(void);
 void msm_snddev_tx_route_deconfig(void);
 
-extern unsigned int msm_shared_ram_phys; /* defined in arch/arm/mach-msm/io.c */
+extern phys_addr_t msm_shared_ram_phys; /* defined in arch/arm/mach-msm/io.c */
 
 
 #endif
diff --git a/arch/arm/mach-msm/include/mach/iommu.h b/arch/arm/mach-msm/include/mach/iommu.h
index f750dc8..23d204a 100644
--- a/arch/arm/mach-msm/include/mach/iommu.h
+++ b/arch/arm/mach-msm/include/mach/iommu.h
@@ -129,6 +129,7 @@
  * @iommu_power_off:    Turn off power to unit
  * @iommu_clk_on:       Turn on clks to unit
  * @iommu_clk_off:      Turn off clks to unit
+ * @iommu_lock_initialize: Initialize the remote lock
  * @iommu_lock_acquire: Acquire any locks needed
  * @iommu_lock_release: Release locks needed
  */
@@ -137,6 +138,7 @@
 	void (*iommu_power_off)(struct msm_iommu_drvdata *);
 	int (*iommu_clk_on)(struct msm_iommu_drvdata *);
 	void (*iommu_clk_off)(struct msm_iommu_drvdata *);
+	void * (*iommu_lock_initialize)(void);
 	void (*iommu_lock_acquire)(void);
 	void (*iommu_lock_release)(void);
 };
diff --git a/arch/arm/mach-msm/include/mach/ipa.h b/arch/arm/mach-msm/include/mach/ipa.h
index cc03c48..90757b6 100644
--- a/arch/arm/mach-msm/include/mach/ipa.h
+++ b/arch/arm/mach-msm/include/mach/ipa.h
@@ -557,17 +557,6 @@
 int ipa_set_single_ndp_per_mbim(bool enable);
 
 /*
- * rmnet bridge
- */
-int rmnet_bridge_init(void);
-
-int rmnet_bridge_disconnect(void);
-
-int rmnet_bridge_connect(u32 producer_hdl,
-			 u32 consumer_hdl,
-			 int wwan_logical_channel_id);
-
-/*
  * SW bridge (between IPA and A2)
  */
 int ipa_bridge_setup(enum ipa_bridge_dir dir, enum ipa_bridge_type type,
@@ -917,26 +906,6 @@
 }
 
 /*
- * rmnet bridge
- */
-static inline int rmnet_bridge_init(void)
-{
-	return -EPERM;
-}
-
-static inline int rmnet_bridge_disconnect(void)
-{
-	return -EPERM;
-}
-
-static inline int rmnet_bridge_connect(u32 producer_hdl,
-			 u32 consumer_hdl,
-			 int wwan_logical_channel_id)
-{
-	return -EPERM;
-}
-
-/*
  * SW bridge (between IPA and A2)
  */
 static inline int ipa_bridge_setup(enum ipa_bridge_dir dir,
diff --git a/arch/arm/mach-msm/include/mach/kgsl.h b/arch/arm/mach-msm/include/mach/kgsl.h
index b68aff8..349dbe7 100644
--- a/arch/arm/mach-msm/include/mach/kgsl.h
+++ b/arch/arm/mach-msm/include/mach/kgsl.h
@@ -20,6 +20,7 @@
 #define KGSL_CLK_MEM	0x00000008
 #define KGSL_CLK_MEM_IFACE 0x00000010
 #define KGSL_CLK_AXI	0x00000020
+#define KGSL_CLK_ALT_MEM_IFACE 0x00000040
 
 #define KGSL_MAX_PWRLEVELS 10
 
@@ -50,9 +51,19 @@
 	enum kgsl_iommu_context_id ctx_id;
 };
 
+/*
+ * struct kgsl_device_iommu_data - Struct holding iommu context data obtained
+ * from dtsi file
+ * @iommu_ctxs:		Pointer to array of struct hoding context name and id
+ * @iommu_ctx_count:	Number of contexts defined in the dtsi file
+ * @iommu_halt_enable:	Indicated if smmu halt h/w feature is supported
+ * @physstart:		Start of iommu registers physical address
+ * @physend:		End of iommu registers physical address
+ */
 struct kgsl_device_iommu_data {
 	const struct kgsl_iommu_ctx *iommu_ctxs;
 	int iommu_ctx_count;
+	int iommu_halt_enable;
 	unsigned int physstart;
 	unsigned int physend;
 };
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-zinc.h b/arch/arm/mach-msm/include/mach/msm_iomap-8084.h
similarity index 74%
rename from arch/arm/mach-msm/include/mach/msm_iomap-zinc.h
rename to arch/arm/mach-msm/include/mach/msm_iomap-8084.h
index 0a33055..43f1de0 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-zinc.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8084.h
@@ -11,8 +11,8 @@
  */
 
 
-#ifndef __ASM_ARCH_MSM_IOMAP_zinc_H
-#define __ASM_ARCH_MSM_IOMAP_zinc_H
+#ifndef __ASM_ARCH_MSM_IOMAP_8084_H
+#define __ASM_ARCH_MSM_IOMAP_8084_H
 
 /* Physical base address and size of peripherals.
  * Ordered by the virtual base addresses they will be mapped at.
@@ -23,15 +23,15 @@
  *
  */
 
-#define MSMZINC_SHARED_RAM_PHYS     0x0FA00000
+#define APQ8084_SHARED_RAM_PHYS     0x0FA00000
 
-#define MSMZINC_QGIC_DIST_PHYS	0xF9000000
-#define MSMZINC_QGIC_DIST_SIZE	SZ_4K
+#define APQ8084_QGIC_DIST_PHYS	0xF9000000
+#define APQ8084_QGIC_DIST_SIZE	SZ_4K
 
-#define MSMZINC_TLMM_PHYS	0xFD510000
-#define MSMZINC_TLMM_SIZE	SZ_16K
+#define APQ8084_TLMM_PHYS	0xFD510000
+#define APQ8084_TLMM_SIZE	SZ_16K
 
-#ifdef CONFIG_DEBUG_MSMZINC_UART
+#ifdef CONFIG_DEBUG_APQ8084_UART
 #define MSM_DEBUG_UART_BASE	IOMEM(0xFA71E000)
 #define MSM_DEBUG_UART_PHYS	0xF991E000
 #endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap.h b/arch/arm/mach-msm/include/mach/msm_iomap.h
index f27eb36..a90e78a 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap.h
@@ -129,7 +129,7 @@
 #include "msm_iomap-8064.h"
 #include "msm_iomap-9615.h"
 #include "msm_iomap-8974.h"
-#include "msm_iomap-zinc.h"
+#include "msm_iomap-8084.h"
 #include "msm_iomap-9625.h"
 #include "msm_iomap-8092.h"
 #include "msm_iomap-8226.h"
diff --git a/arch/arm/mach-msm/include/mach/msm_smd.h b/arch/arm/mach-msm/include/mach/msm_smd.h
index a8c7bb7..d155c6f 100644
--- a/arch/arm/mach-msm/include/mach/msm_smd.h
+++ b/arch/arm/mach-msm/include/mach/msm_smd.h
@@ -279,6 +279,17 @@
  */
 int smd_write_end(smd_channel_t *ch);
 
+/**
+ * smd_write_segment_avail() - available write space for packet transactions
+ * @ch: channel to write packet to
+ * @returns: number of bytes available to write to, or -ENODEV for invalid ch
+ *
+ * This is a version of smd_write_avail() intended for use with packet
+ * transactions.  This version correctly accounts for any internal reserved
+ * space at all stages of the transaction.
+ */
+int smd_write_segment_avail(smd_channel_t *ch);
+
 /*
  * Returns a pointer to the subsystem name or NULL if no
  * subsystem name is available.
@@ -441,6 +452,11 @@
 	return -ENODEV;
 }
 
+static inline int smd_write_segment_avail(smd_channel_t *ch)
+{
+	return -ENODEV;
+}
+
 static inline const char *smd_edge_to_subsystem(uint32_t type)
 {
 	return NULL;
diff --git a/arch/arm/mach-msm/include/mach/msm_smsm.h b/arch/arm/mach-msm/include/mach/msm_smsm.h
index d983ce5..81a6399 100644
--- a/arch/arm/mach-msm/include/mach/msm_smsm.h
+++ b/arch/arm/mach-msm/include/mach/msm_smsm.h
@@ -256,6 +256,18 @@
 int smsm_check_for_modem_crash(void);
 void *smem_find(unsigned id, unsigned size);
 void *smem_get_entry(unsigned id, unsigned *size);
+
+/**
+ * smem_virt_to_phys() - Convert SMEM address to physical address.
+ *
+ * @smem_address: Virtual address returned by smem_alloc()/smem_alloc2()
+ * @returns: Physical address (or NULL if there is a failure)
+ *
+ * This function should only be used if an SMEM item needs to be handed
+ * off to a DMA engine.
+ */
+phys_addr_t smem_virt_to_phys(void *smem_address);
+
 #else
 static inline void *smem_alloc(unsigned id, unsigned size)
 {
@@ -339,5 +351,9 @@
 {
 	return NULL;
 }
+static inline phys_addr_t smem_virt_to_phys(void *smem_address)
+{
+	return NULL;
+}
 #endif
 #endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/q6core.h b/arch/arm/mach-msm/include/mach/qdsp6v2/q6core.h
index 91e4ef1..ea345fb 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/q6core.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/q6core.h
@@ -53,19 +53,10 @@
 	uint8_t   model_ID[128];
 };
 
-#define ADSP_CMD_SET_DOLBY_MANUFACTURER_ID 0x00012918
-
-struct adsp_dolby_manufacturer_id {
-	struct apr_hdr hdr;
-	int manufacturer_id;
-};
-
 int core_req_bus_bandwith(u16 bus_id, u32 ab_bps, u32 ib_bps);
 
 uint32_t core_get_adsp_version(void);
 
 uint32_t core_set_dts_model_id(uint32_t id_size, uint8_t *id);
 
-uint32_t core_set_dolby_manufacturer_id(int manufacturer_id);
-
 #endif /* __Q6CORE_H__ */
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
index 7c9882e..d4ea4ac 100644
--- a/arch/arm/mach-msm/include/mach/socinfo.h
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -46,8 +46,8 @@
 	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msm8610")
 #define early_machine_is_mpq8092()	\
 	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,mpq8092")
-#define early_machine_is_msmzinc()	\
-	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msmzinc")
+#define early_machine_is_apq8084()	\
+	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,apq8084")
 #define early_machine_is_msmkrypton()	\
 	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msmkrypton")
 #else
@@ -63,7 +63,7 @@
 
 #define early_machine_is_msm8610()	0
 #define early_machine_is_mpq8092()	0
-#define early_machine_is_msmzinc()	0
+#define early_machine_is_apq8084()	0
 #define early_machine_is_msmkrypton()	0
 #endif
 
@@ -102,7 +102,7 @@
 	MSM_CPU_8226,
 	MSM_CPU_8610,
 	MSM_CPU_8625Q,
-	MSM_CPU_ZINC,
+	MSM_CPU_8084,
 	MSM_CPU_KRYPTON,
 };
 
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index ecac4a5..37dbbab 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -45,7 +45,7 @@
 /* msm_shared_ram_phys default value of 0x00100000 is the most common value
  * and should work as-is for any target without stacked memory.
  */
-unsigned int msm_shared_ram_phys = 0x00100000;
+phys_addr_t msm_shared_ram_phys = 0x00100000;
 
 static void __init msm_map_io(struct map_desc *io_desc, int size)
 {
@@ -321,27 +321,27 @@
 }
 #endif /* CONFIG_ARCH_MSM8974 */
 
-#ifdef CONFIG_ARCH_MSMZINC
-static struct map_desc msm_zinc_io_desc[] __initdata = {
-	MSM_CHIP_DEVICE(QGIC_DIST, MSMZINC),
-	MSM_CHIP_DEVICE(TLMM, MSMZINC),
+#ifdef CONFIG_ARCH_APQ8084
+static struct map_desc msm_8084_io_desc[] __initdata = {
+	MSM_CHIP_DEVICE(QGIC_DIST, APQ8084),
+	MSM_CHIP_DEVICE(TLMM, APQ8084),
 	{
 		.virtual =  (unsigned long) MSM_SHARED_RAM_BASE,
 		.length =   MSM_SHARED_RAM_SIZE,
 		.type =     MT_DEVICE,
 	},
-#ifdef CONFIG_DEBUG_MSMZINC_UART
+#ifdef CONFIG_DEBUG_APQ8084_UART
 	MSM_DEVICE(DEBUG_UART),
 #endif
 };
 
-void __init msm_map_zinc_io(void)
+void __init msm_map_8084_io(void)
 {
-	msm_shared_ram_phys = MSMZINC_SHARED_RAM_PHYS;
-	msm_map_io(msm_zinc_io_desc, ARRAY_SIZE(msm_zinc_io_desc));
+	msm_shared_ram_phys = APQ8084_SHARED_RAM_PHYS;
+	msm_map_io(msm_8084_io_desc, ARRAY_SIZE(msm_8084_io_desc));
 	of_scan_flat_dt(msm_scan_dt_map_imem, NULL);
 }
-#endif /* CONFIG_ARCH_MSMZINC */
+#endif /* CONFIG_ARCH_APQ8084 */
 
 #ifdef CONFIG_ARCH_MSM7X30
 static struct map_desc msm7x30_io_desc[] __initdata = {
diff --git a/arch/arm/mach-msm/ipc_router_smd_xprt.c b/arch/arm/mach-msm/ipc_router_smd_xprt.c
index 88ab8e0..b2ec816 100644
--- a/arch/arm/mach-msm/ipc_router_smd_xprt.c
+++ b/arch/arm/mach-msm/ipc_router_smd_xprt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-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
@@ -146,11 +146,11 @@
 	skb_queue_walk(pkt->pkt_fragment_q, ipc_rtr_pkt) {
 		offset = 0;
 		while (offset < ipc_rtr_pkt->len) {
-			if (!smd_write_avail(smd_xprtp->channel))
+			if (!smd_write_segment_avail(smd_xprtp->channel))
 				smd_enable_read_intr(smd_xprtp->channel);
 
 			wait_event(smd_xprtp->write_avail_wait_q,
-				(smd_write_avail(smd_xprtp->channel) ||
+				(smd_write_segment_avail(smd_xprtp->channel) ||
 				smd_xprtp->ss_reset));
 			smd_disable_read_intr(smd_xprtp->channel);
 			spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
@@ -175,11 +175,11 @@
 	}
 
 	if (align_sz) {
-		if (smd_write_avail(smd_xprtp->channel) < align_sz)
+		if (smd_write_segment_avail(smd_xprtp->channel) < align_sz)
 			smd_enable_read_intr(smd_xprtp->channel);
 
 		wait_event(smd_xprtp->write_avail_wait_q,
-			((smd_write_avail(smd_xprtp->channel) >=
+			((smd_write_segment_avail(smd_xprtp->channel) >=
 			 align_sz) || smd_xprtp->ss_reset));
 		smd_disable_read_intr(smd_xprtp->channel);
 		spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
@@ -357,7 +357,7 @@
 		if (smd_read_avail(smd_xprtp->channel))
 			queue_delayed_work(smd_xprtp->smd_xprt_wq,
 					   &smd_xprtp->read_work, 0);
-		if (smd_write_avail(smd_xprtp->channel))
+		if (smd_write_segment_avail(smd_xprtp->channel))
 			wake_up(&smd_xprtp->write_avail_wait_q);
 		break;
 
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c b/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
index 3c8348d..cd6693e 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
@@ -477,9 +477,11 @@
 #define M_MODE_ADDR(b, n) \
 		(M_REG_BASE(b) + (0x4000 * (n)) + 0x00000210)
 enum bimc_m_mode {
-	M_MODE_RMSK				= 0xf0000001,
+	M_MODE_RMSK				= 0xf0000011,
 	M_MODE_WR_GATHER_BEATS_BMSK		= 0xf0000000,
 	M_MODE_WR_GATHER_BEATS_SHFT		= 0x1c,
+	M_MODE_NARROW_WR_BMSK			= 0x10,
+	M_MODE_NARROW_WR_SHFT			= 0x4,
 	M_MODE_ORDERING_MODEL_BMSK		= 0x1,
 	M_MODE_ORDERING_MODEL_SHFT		= 0x0,
 };
@@ -1526,10 +1528,10 @@
 		reg_val = readl_relaxed(M_PRIOLVL_OVERRIDE_ADDR(binfo->
 			base, mas_index)) & M_PRIOLVL_OVERRIDE_RMSK;
 		val =  qmode->fixed.prio_level <<
-			M_PRIOLVL_OVERRIDE_OVERRIDE_PRIOLVL_SHFT;
+			M_PRIOLVL_OVERRIDE_SHFT;
 		writel_relaxed(((reg_val &
-			~(M_PRIOLVL_OVERRIDE_OVERRIDE_PRIOLVL_BMSK)) | (val
-			& M_PRIOLVL_OVERRIDE_OVERRIDE_PRIOLVL_BMSK)),
+			~(M_PRIOLVL_OVERRIDE_BMSK)) | (val
+			& M_PRIOLVL_OVERRIDE_BMSK)),
 			M_PRIOLVL_OVERRIDE_ADDR(binfo->base, mas_index));
 
 		reg_val = readl_relaxed(M_RD_CMD_OVERRIDE_ADDR(binfo->
diff --git a/arch/arm/mach-msm/msm_watchdog.c b/arch/arm/mach-msm/msm_watchdog.c
index b1c8b30..dcfe13c 100644
--- a/arch/arm/mach-msm/msm_watchdog.c
+++ b/arch/arm/mach-msm/msm_watchdog.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-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
@@ -23,6 +23,7 @@
 #include <linux/suspend.h>
 #include <linux/percpu.h>
 #include <linux/interrupt.h>
+#include <linux/reboot.h>
 #include <asm/fiq.h>
 #include <asm/hardware/gic.h>
 #include <mach/msm_iomap.h>
@@ -64,6 +65,12 @@
 module_param(enable, int, 0);
 
 /*
+ * Watchdog bark reboot timeout in seconds.
+ * Can be specified in kernel command line.
+ */
+static int reboot_bark_timeout = 22;
+module_param(reboot_bark_timeout, int, 0644);
+/*
  * If the watchdog is enabled at bootup (enable=1),
  * the runtime_disable sysfs node at
  * /sys/module/msm_watchdog/runtime_disable
@@ -154,6 +161,27 @@
 	.notifier_call	= panic_wdog_handler,
 };
 
+#define get_sclk_hz(t_ms) ((t_ms / 1000) * WDT_HZ)
+#define get_reboot_bark_timeout(t_s) ((t_s * MSEC_PER_SEC) < bark_time ? \
+		get_sclk_hz(bark_time) : get_sclk_hz(t_s * MSEC_PER_SEC))
+
+static int msm_watchdog_reboot_notifier(struct notifier_block *this,
+		unsigned long code, void *unused)
+{
+
+	u64 timeout = get_reboot_bark_timeout(reboot_bark_timeout);
+	__raw_writel(timeout, msm_wdt_base + WDT_BARK_TIME);
+	__raw_writel(timeout + 3 * WDT_HZ,
+			msm_wdt_base + WDT_BITE_TIME);
+	__raw_writel(1, msm_wdt_base + WDT_RST);
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block msm_reboot_notifier = {
+	.notifier_call = msm_watchdog_reboot_notifier,
+};
+
 struct wdog_disable_work_data {
 	struct work_struct work;
 	struct completion complete;
@@ -177,6 +205,7 @@
 	}
 	enable = 0;
 	atomic_notifier_chain_unregister(&panic_notifier_list, &panic_blk);
+	unregister_reboot_notifier(&msm_reboot_notifier);
 	cancel_delayed_work(&dogwork_struct);
 	/* may be suspended after the first write above */
 	__raw_writel(0, msm_wdt_base + WDT_EN);
@@ -373,6 +402,10 @@
 	atomic_notifier_chain_register(&panic_notifier_list,
 				       &panic_blk);
 
+	ret = register_reboot_notifier(&msm_reboot_notifier);
+	if (ret)
+		pr_err("Failed to register reboot notifier\n");
+
 	__raw_writel(1, msm_wdt_base + WDT_EN);
 	__raw_writel(1, msm_wdt_base + WDT_RST);
 	last_pet = sched_clock();
@@ -395,6 +428,11 @@
 	}
 
 	bark_time = pdata->bark_time;
+	/* reboot_bark_timeout (in seconds) might have been supplied as
+	 * module parameter.
+	 */
+	if ((reboot_bark_timeout * MSEC_PER_SEC) < bark_time)
+		reboot_bark_timeout = (bark_time / MSEC_PER_SEC);
 	has_vic = pdata->has_vic;
 	if (!pdata->has_secure) {
 		appsbark = 1;
diff --git a/arch/arm/mach-msm/pil-q6v5-lpass.c b/arch/arm/mach-msm/pil-q6v5-lpass.c
index 3b2bbf3..277addc 100644
--- a/arch/arm/mach-msm/pil-q6v5-lpass.c
+++ b/arch/arm/mach-msm/pil-q6v5-lpass.c
@@ -22,6 +22,7 @@
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/sysfs.h>
+#include <linux/of_gpio.h>
 
 #include <mach/clk.h>
 #include <mach/subsystem_restart.h>
@@ -50,6 +51,8 @@
 	void *wcnss_notif_hdle;
 	void *modem_notif_hdle;
 	int crash_shutdown;
+	unsigned int err_fatal_irq;
+	int force_stop_gpio;
 };
 
 #define subsys_to_drv(d) container_of(d, struct lpass_data, subsys_desc)
@@ -259,20 +262,19 @@
 	restart_adsp(drv);
 }
 
-static void adsp_smsm_state_cb(void *data, uint32_t old_state,
-				uint32_t new_state)
+static irqreturn_t adsp_err_fatal_intr_handler (int irq, void *dev_id)
 {
-	struct lpass_data *drv = data;
+	struct lpass_data *drv = dev_id;
 
-	/* Ignore if we're the one that set SMSM_RESET */
+	/* Ignore if we're the one that set the force stop bit in the outbound
+	 * entry
+	 */
 	if (drv->crash_shutdown)
-		return;
+		return IRQ_HANDLED;
 
-	if (new_state & SMSM_RESET) {
-		pr_err("%s: ADSP SMSM state changed to SMSM_RESET, new_state = %#x, old_state = %#x\n",
-				__func__, new_state, old_state);
-		restart_adsp(drv);
-	}
+	pr_err("Fatal error on the ADSP!\n");
+	restart_adsp(drv);
+	return IRQ_HANDLED;
 }
 
 #define SCM_Q6_NMI_CMD 0x1
@@ -356,6 +358,7 @@
 	struct lpass_data *drv = subsys_to_lpass(subsys);
 
 	drv->crash_shutdown = 1;
+	gpio_set_value(drv->force_stop_gpio, 1);
 	send_q6_nmi();
 }
 
@@ -388,7 +391,7 @@
 	struct q6v5_data *q6;
 	struct pil_desc *desc;
 	struct resource *res;
-	int ret;
+	int ret, gpio_clk_ready;
 
 	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
 	if (!drv)
@@ -399,6 +402,23 @@
 	if (drv->wdog_irq < 0)
 		return drv->wdog_irq;
 
+	ret = gpio_to_irq(of_get_named_gpio(pdev->dev.of_node,
+					    "qcom,gpio-err-fatal", 0));
+	if (ret < 0)
+		return ret;
+	drv->err_fatal_irq = ret;
+
+	ret = gpio_to_irq(of_get_named_gpio(pdev->dev.of_node,
+					    "qcom,gpio-proxy-unvote", 0));
+	if (ret < 0)
+		return ret;
+	gpio_clk_ready = ret;
+
+	drv->force_stop_gpio = of_get_named_gpio(pdev->dev.of_node,
+						"qcom,gpio-force-stop", 0);
+	if (drv->force_stop_gpio < 0)
+		return drv->force_stop_gpio;
+
 	q6 = pil_q6v5_init(pdev);
 	if (IS_ERR(q6))
 		return PTR_ERR(q6);
@@ -407,6 +427,7 @@
 	desc = &q6->desc;
 	desc->owner = THIS_MODULE;
 	desc->proxy_timeout = PROXY_TIMEOUT_MS;
+	desc->proxy_unvote_irq = gpio_clk_ready;
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "restart_reg");
 	q6->restart_reg = devm_request_and_ioremap(&pdev->dev, res);
@@ -470,10 +491,12 @@
 	if (ret)
 		goto err_irq;
 
-	ret = smsm_state_cb_register(SMSM_Q6_STATE, SMSM_RESET,
-			adsp_smsm_state_cb, drv);
-	if (ret < 0)
-		goto err_smsm;
+	ret = devm_request_irq(&pdev->dev, drv->err_fatal_irq,
+				adsp_err_fatal_intr_handler,
+				IRQF_TRIGGER_RISING,
+				dev_name(&pdev->dev), drv);
+	if (ret)
+		goto err_irq;
 
 	drv->wcnss_notif_hdle = subsys_notif_register_notifier("wcnss", &wnb);
 	if (IS_ERR(drv->wcnss_notif_hdle)) {
@@ -507,9 +530,6 @@
 err_notif_modem:
 	subsys_notif_unregister_notifier(drv->wcnss_notif_hdle, &wnb);
 err_notif_wcnss:
-	smsm_state_cb_deregister(SMSM_Q6_STATE, SMSM_RESET,
-			adsp_smsm_state_cb, drv);
-err_smsm:
 err_irq:
 	subsys_unregister(drv->subsys);
 err_subsys:
@@ -524,8 +544,6 @@
 	struct lpass_data *drv = platform_get_drvdata(pdev);
 	subsys_notif_unregister_notifier(drv->wcnss_notif_hdle, &wnb);
 	subsys_notif_unregister_notifier(drv->modem_notif_hdle, &mnb);
-	smsm_state_cb_deregister(SMSM_Q6_STATE, SMSM_RESET,
-			adsp_smsm_state_cb, drv);
 	subsys_unregister(drv->subsys);
 	destroy_ramdump_device(drv->ramdump_dev);
 	pil_desc_release(&drv->q6->desc);
diff --git a/arch/arm/mach-msm/pil-q6v5-mss.c b/arch/arm/mach-msm/pil-q6v5-mss.c
index 8f7d262..c3a0d32 100644
--- a/arch/arm/mach-msm/pil-q6v5-mss.c
+++ b/arch/arm/mach-msm/pil-q6v5-mss.c
@@ -608,8 +608,15 @@
 	if (ret)
 		return ret;
 	ret = pil_boot(&drv->desc);
-	if (ret)
+	if (ret) {
 		pil_shutdown(&drv->q6->desc);
+		/*
+		 * We know now that the unvote interrupt is not coming.
+		 * Remove the proxy votes immediately.
+		 */
+		if (drv->q6->desc.proxy_unvote_irq)
+			pil_q6v5_mss_remove_proxy_votes(&drv->q6->desc);
+	}
 	return ret;
 }
 
diff --git a/arch/arm/mach-msm/pil-q6v5.c b/arch/arm/mach-msm/pil-q6v5.c
index 0263faf..c6add8f 100644
--- a/arch/arm/mach-msm/pil-q6v5.c
+++ b/arch/arm/mach-msm/pil-q6v5.c
@@ -46,7 +46,9 @@
 #define Q6SS_CLK_ENA			BIT(1)
 
 /* QDSP6SS_PWR_CTL */
-#define Q6SS_L2DATA_SLP_NRET_N		(BIT(0)|BIT(1)|BIT(2))
+#define Q6SS_L2DATA_SLP_NRET_N_0	BIT(0)
+#define Q6SS_L2DATA_SLP_NRET_N_1	BIT(1)
+#define Q6SS_L2DATA_SLP_NRET_N_2	BIT(2)
 #define Q6SS_L2TAG_SLP_NRET_N		BIT(16)
 #define Q6SS_ETB_SLP_NRET_N		BIT(17)
 #define Q6SS_L2DATA_STBY_N		BIT(18)
@@ -160,7 +162,8 @@
 	writel_relaxed(val, drv->reg_base + QDSP6SS_PWR_CTL);
 
 	/* Turn off Q6 memories */
-	val &= ~(Q6SS_L2DATA_SLP_NRET_N | Q6SS_SLP_RET_N |
+	val &= ~(Q6SS_L2DATA_SLP_NRET_N_0 | Q6SS_L2DATA_SLP_NRET_N_1 |
+		 Q6SS_L2DATA_SLP_NRET_N_2 | Q6SS_SLP_RET_N |
 		 Q6SS_L2TAG_SLP_NRET_N | Q6SS_ETB_SLP_NRET_N |
 		 Q6SS_L2DATA_STBY_N);
 	writel_relaxed(val, drv->reg_base + QDSP6SS_PWR_CTL);
@@ -194,11 +197,19 @@
 	mb();
 	udelay(1);
 
-	/* Turn on memories */
+	/*
+	 * Turn on memories. L2 banks should be done individually
+	 * to minimize inrush current.
+	 */
 	val = readl_relaxed(drv->reg_base + QDSP6SS_PWR_CTL);
-	val |= Q6SS_L2DATA_SLP_NRET_N | Q6SS_SLP_RET_N |
-	       Q6SS_L2TAG_SLP_NRET_N | Q6SS_ETB_SLP_NRET_N |
-	       Q6SS_L2DATA_STBY_N;
+	val |= Q6SS_SLP_RET_N | Q6SS_L2TAG_SLP_NRET_N |
+	       Q6SS_ETB_SLP_NRET_N | Q6SS_L2DATA_STBY_N;
+	writel_relaxed(val, drv->reg_base + QDSP6SS_PWR_CTL);
+	val |= Q6SS_L2DATA_SLP_NRET_N_2;
+	writel_relaxed(val, drv->reg_base + QDSP6SS_PWR_CTL);
+	val |= Q6SS_L2DATA_SLP_NRET_N_1;
+	writel_relaxed(val, drv->reg_base + QDSP6SS_PWR_CTL);
+	val |= Q6SS_L2DATA_SLP_NRET_N_0;
 	writel_relaxed(val, drv->reg_base + QDSP6SS_PWR_CTL);
 
 	/* Remove IO clamp */
diff --git a/arch/arm/mach-msm/qdsp6v2/Makefile b/arch/arm/mach-msm/qdsp6v2/Makefile
index 88e2894..6bd3efb 100644
--- a/arch/arm/mach-msm/qdsp6v2/Makefile
+++ b/arch/arm/mach-msm/qdsp6v2/Makefile
@@ -12,7 +12,7 @@
 obj-$(CONFIG_FB_MSM_HDMI_MSM_PANEL) += lpa_if_hdmi.o
 endif
 obj-$(CONFIG_MSM_QDSP6_APR) += apr.o apr_v1.o apr_tal.o q6core.o dsp_debug.o
-obj-$(CONFIG_MSM_QDSP6_APRV2) += apr.o apr_v2.o apr_tal.o q6core.o dsp_debug.o
+obj-$(CONFIG_MSM_QDSP6_APRV2) += apr.o apr_v2.o apr_tal.o dsp_debug.o
 ifdef CONFIG_ARCH_MSM9615
 obj-y += audio_acdb.o
 obj-y += rtac.o
diff --git a/arch/arm/mach-msm/qdsp6v2/q6core.c b/arch/arm/mach-msm/qdsp6v2/q6core.c
index 6594b08..fd699df 100644
--- a/arch/arm/mach-msm/qdsp6v2/q6core.c
+++ b/arch/arm/mach-msm/qdsp6v2/q6core.c
@@ -69,12 +69,12 @@
 		switch (payload1[0]) {
 
 		case ADSP_CMD_SET_POWER_COLLAPSE_STATE:
-			pr_info("Cmd = ADSP_CMD_SET_POWER_COLLAPSE_STATE"
-				" status[0x%x]\n", payload1[1]);
+			pr_info("Cmd = ADSP_CMD_SET_POWER_COLLAPSE_STATE status[0x%x]\n",
+								payload1[1]);
 			break;
 		case ADSP_CMD_REMOTE_BUS_BW_REQUEST:
-			pr_info("%s: cmd = ADSP_CMD_REMOTE_BUS_BW_REQUEST"
-				"  status = 0x%x\n", __func__, payload1[1]);
+			pr_info("%s: cmd = ADSP_CMD_REMOTE_BUS_BW_REQUEST status = 0x%x\n",
+							__func__, payload1[1]);
 
 			bus_bw_resp_received = 1;
 			wake_up(&bus_bw_req_wait);
@@ -160,10 +160,9 @@
 		core_handle_q = apr_register("ADSP", "CORE",
 					aprv2_core_fn_q, 0xFFFFFFFF, NULL);
 	}
-	pr_info("Open_q %p\n", core_handle_q);
-	if (core_handle_q == NULL) {
+	pr_debug("Open_q %p\n", core_handle_q);
+	if (core_handle_q == NULL)
 		pr_err("%s: Unable to register CORE\n", __func__);
-	}
 }
 
 int core_req_bus_bandwith(u16 bus_id, u32 ab_bps, u32 ib_bps)
@@ -352,7 +351,7 @@
 			pc.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_EVENT,
 					APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
 			pc.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
-						sizeof(uint32_t));;
+						sizeof(uint32_t));
 			pc.hdr.src_port = 0;
 			pc.hdr.dest_port = 0;
 			pc.hdr.token = 0;
@@ -413,32 +412,6 @@
 	return rc;
 }
 
-uint32_t core_set_dolby_manufacturer_id(int manufacturer_id)
-{
-	struct adsp_dolby_manufacturer_id payload;
-	int rc = 0;
-	pr_debug("%s manufacturer_id :%d\n", __func__, manufacturer_id);
-	core_open();
-	if (core_handle_q) {
-		payload.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_EVENT,
-			APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
-		payload.hdr.pkt_size =
-			sizeof(struct adsp_dolby_manufacturer_id);
-		payload.hdr.src_port = 0;
-		payload.hdr.dest_port = 0;
-		payload.hdr.token = 0;
-		payload.hdr.opcode = ADSP_CMD_SET_DOLBY_MANUFACTURER_ID;
-		payload.manufacturer_id = manufacturer_id;
-		pr_debug("Send Dolby security opcode=%x manufacturer ID = %d\n",
-			payload.hdr.opcode, payload.manufacturer_id);
-		rc = apr_send_pkt(core_handle_q, (uint32_t *)&payload);
-		if (rc < 0)
-			pr_err("%s: SET_DOLBY_MANUFACTURER_ID failed op[0x%x]rc[%d]\n",
-				__func__, payload.hdr.opcode, rc);
-	}
-	return rc;
-}
-
 static const struct file_operations apr_debug_fops = {
 	.write = apr_debug_write,
 	.open = apr_debug_open,
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index 07ac930..3590e6b 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -34,7 +34,6 @@
 #include <linux/kfifo.h>
 #include <linux/wakelock.h>
 #include <linux/notifier.h>
-#include <linux/sort.h>
 #include <linux/suspend.h>
 #include <linux/of.h>
 #include <linux/of_irq.h>
@@ -47,6 +46,7 @@
 #include <mach/proc_comm.h>
 #include <mach/msm_ipc_logging.h>
 #include <mach/ramdump.h>
+#include <mach/board.h>
 
 #include <asm/cacheflush.h>
 
@@ -76,6 +76,7 @@
 #define SMSM_SNAPSHOT_CNT 64
 #define SMSM_SNAPSHOT_SIZE ((SMSM_NUM_ENTRIES + 1) * 4)
 #define RSPIN_INIT_WAIT_MS 1000
+#define SMD_FIFO_FULL_RESERVE 4
 
 uint32_t SMSM_NUM_ENTRIES = 8;
 uint32_t SMSM_NUM_HOSTS = 3;
@@ -183,7 +184,7 @@
 static struct smem_area *smem_areas;
 static struct ramdump_segment *smem_ramdump_segments;
 static void *smem_ramdump_dev;
-static void *smem_range_check(phys_addr_t base, unsigned offset);
+static void *smem_phys_to_virt(phys_addr_t base, unsigned offset);
 static void *smd_dev;
 
 struct interrupt_stat interrupt_stats[NUM_SMD_SUBSYSTEMS];
@@ -243,6 +244,17 @@
 #define SMx_POWER_INFO(x...) do { } while (0)
 #endif
 
+/**
+ * OVERFLOW_ADD_UNSIGNED() - check for unsigned overflow
+ *
+ * @type: type to check for overflow
+ * @a: left value to use
+ * @b: right value to use
+ * @returns: true if a + b will result in overflow; false otherwise
+ */
+#define OVERFLOW_ADD_UNSIGNED(type, a, b) \
+	(((type)~0 - (a)) < (b) ? true : false)
+
 static unsigned last_heap_free = 0xffffffff;
 
 static inline void smd_write_intr(unsigned int val,
@@ -1053,8 +1065,16 @@
 /* how many bytes we are free to write */
 static int smd_stream_write_avail(struct smd_channel *ch)
 {
-	return ch->fifo_mask - ((ch->half_ch->get_head(ch->send) -
-			ch->half_ch->get_tail(ch->send)) & ch->fifo_mask);
+	int bytes_avail;
+
+	bytes_avail = ch->fifo_mask - ((ch->half_ch->get_head(ch->send) -
+			ch->half_ch->get_tail(ch->send)) & ch->fifo_mask) + 1;
+
+	if (bytes_avail < SMD_FIFO_FULL_RESERVE)
+		bytes_avail = 0;
+	else
+		bytes_avail -= SMD_FIFO_FULL_RESERVE;
+	return bytes_avail;
 }
 
 static int smd_packet_read_avail(struct smd_channel *ch)
@@ -1176,7 +1196,18 @@
 	}
 }
 
-/* provide a pointer and length to next free space in the fifo */
+/**
+ * ch_write_buffer() - Provide a pointer and length for the next segment of
+ * free space in the FIFO.
+ * @ch: channel
+ * @ptr: Address to pointer for the next segment write
+ * @returns: Maximum size that can be written until the FIFO is either full
+ *           or the end of the FIFO has been reached.
+ *
+ * The returned pointer and length are passed to memcpy, so the next segment is
+ * defined as either the space available between the read index (tail) and the
+ * write index (head) or the space available to the end of the FIFO.
+ */
 static unsigned ch_write_buffer(struct smd_channel *ch, void **ptr)
 {
 	unsigned head = ch->half_ch->get_head(ch->send);
@@ -1184,10 +1215,11 @@
 	*ptr = (void *) (ch->send_data + head);
 
 	if (head < tail) {
-		return tail - head - 1;
+		return tail - head - SMD_FIFO_FULL_RESERVE;
 	} else {
-		if (tail == 0)
-			return ch->fifo_size - head - 1;
+		if (tail < SMD_FIFO_FULL_RESERVE)
+			return ch->fifo_size + tail - head
+					- SMD_FIFO_FULL_RESERVE;
 		else
 			return ch->fifo_size - head;
 	}
@@ -2111,6 +2143,29 @@
 }
 EXPORT_SYMBOL(smd_write_end);
 
+int smd_write_segment_avail(smd_channel_t *ch)
+{
+	int n;
+
+	if (!ch) {
+		pr_err("%s: Invalid channel specified\n", __func__);
+		return -ENODEV;
+	}
+	if (!ch->is_pkt_ch) {
+		pr_err("%s: non-packet channel specified\n", __func__);
+		return -ENODEV;
+	}
+
+	n = smd_stream_write_avail(ch);
+
+	/* pkt hdr already written, no need to reserve space for it */
+	if (ch->pending_pkt_sz)
+		return n;
+
+	return n > SMD_HEADER_SIZE ? n - SMD_HEADER_SIZE : 0;
+}
+EXPORT_SYMBOL(smd_write_segment_avail);
+
 int smd_read(smd_channel_t *ch, void *data, int len)
 {
 	if (!ch) {
@@ -2356,37 +2411,107 @@
 
 /* -------------------------------------------------------------------------- */
 
-/*
- * Shared Memory Range Check
- *
- * Takes a physical address and an offset and checks if the resulting physical
- * address would fit into one of the aux smem regions.  If so, returns the
- * corresponding virtual address.  Otherwise returns NULL.  Expects the array
- * of smem regions to be in ascending physical address order.
+/**
+ * smem_phys_to_virt() - Convert a physical base and offset to virtual address
  *
  * @base: physical base address to check
  * @offset: offset from the base to get the final address
+ * @returns: virtual SMEM address; NULL for failure
+ *
+ * Takes a physical address and an offset and checks if the resulting physical
+ * address would fit into one of the smem regions.  If so, returns the
+ * corresponding virtual address.  Otherwise returns NULL.
  */
-static void *smem_range_check(phys_addr_t base, unsigned offset)
+static void *smem_phys_to_virt(phys_addr_t base, unsigned offset)
 {
 	int i;
 	phys_addr_t phys_addr;
 	resource_size_t size;
 
+	if (OVERFLOW_ADD_UNSIGNED(phys_addr_t, base, offset))
+		return NULL;
+
+	if (!smem_areas) {
+		/*
+		 * Early boot - no area configuration yet, so default
+		 * to using the main memory region.
+		 *
+		 * To remove the MSM_SHARED_RAM_BASE and the static
+		 * mapping of SMEM in the future, add dump_stack()
+		 * to identify the early callers of smem_get_entry()
+		 * (which calls this function) and replace those calls
+		 * with a new function that knows how to lookup the
+		 * SMEM base address before SMEM has been probed.
+		 */
+		phys_addr = msm_shared_ram_phys;
+		size = MSM_SHARED_RAM_SIZE;
+
+		if (base >= phys_addr && base + offset < phys_addr + size) {
+			if (OVERFLOW_ADD_UNSIGNED(uintptr_t,
+				(uintptr_t)MSM_SHARED_RAM_BASE, offset)) {
+				pr_err("%s: overflow %p %x\n", __func__,
+					MSM_SHARED_RAM_BASE, offset);
+				return NULL;
+			}
+
+			return MSM_SHARED_RAM_BASE + offset;
+		} else {
+			return NULL;
+		}
+	}
 	for (i = 0; i < num_smem_areas; ++i) {
 		phys_addr = smem_areas[i].phys_addr;
 		size = smem_areas[i].size;
-		if (base < phys_addr)
-			return NULL;
-		if (base > phys_addr + size)
+
+		if (base < phys_addr || base + offset >= phys_addr + size)
 			continue;
-		if (base >= phys_addr && base + offset < phys_addr + size)
-			return smem_areas[i].virt_addr + offset;
+
+		if (OVERFLOW_ADD_UNSIGNED(uintptr_t,
+				(uintptr_t)smem_areas[i].virt_addr, offset)) {
+			pr_err("%s: overflow %p %x\n", __func__,
+				smem_areas[i].virt_addr, offset);
+			return NULL;
+		}
+
+		return smem_areas[i].virt_addr + offset;
 	}
 
 	return NULL;
 }
 
+/**
+ * smem_virt_to_phys() - Convert SMEM address to physical address.
+ *
+ * @smem_address: Address of SMEM item (returned by smem_alloc(), etc)
+ * @returns: Physical address (or NULL if there is a failure)
+ *
+ * This function should only be used if an SMEM item needs to be handed
+ * off to a DMA engine.
+ */
+phys_addr_t smem_virt_to_phys(void *smem_address)
+{
+	phys_addr_t phys_addr = 0;
+	int i;
+	void *vend;
+
+	if (!smem_areas)
+		return phys_addr;
+
+	for (i = 0; i < num_smem_areas; ++i) {
+		vend = (void *)(smem_areas[i].virt_addr + smem_areas[i].size);
+
+		if (smem_address >= smem_areas[i].virt_addr &&
+				smem_address < vend) {
+			phys_addr = smem_address - smem_areas[i].virt_addr;
+			phys_addr +=  smem_areas[i].phys_addr;
+			break;
+		}
+	}
+
+	return phys_addr;
+}
+EXPORT_SYMBOL(smem_virt_to_phys);
+
 /* smem_alloc returns the pointer to smem item if it is already allocated.
  * Otherwise, it returns NULL.
  */
@@ -2460,14 +2585,15 @@
 		remote_spin_lock_irqsave(&remote_spinlock, flags);
 	/* toc is in device memory and cannot be speculatively accessed */
 	if (toc[id].allocated) {
+		phys_addr_t phys_base;
+
 		*size = toc[id].size;
 		barrier();
-		if (!(toc[id].reserved & BASE_ADDR_MASK))
-			ret = (void *) (MSM_SHARED_RAM_BASE + toc[id].offset);
-		else
-			ret = smem_range_check(
-				toc[id].reserved & BASE_ADDR_MASK,
-				toc[id].offset);
+
+		phys_base = toc[id].reserved & BASE_ADDR_MASK;
+		if (!phys_base)
+			phys_base = (phys_addr_t)msm_shared_ram_phys;
+		ret = smem_phys_to_virt(phys_base, toc[id].offset);
 	} else {
 		*size = 0;
 	}
@@ -3420,14 +3546,6 @@
 	return ret;
 }
 
-int sort_cmp_func(const void *a, const void *b)
-{
-	struct smem_area *left = (struct smem_area *)(a);
-	struct smem_area *right = (struct smem_area *)(b);
-
-	return left->phys_addr - right->phys_addr;
-}
-
 int smd_core_platform_init(struct platform_device *pdev)
 {
 	int i;
@@ -3438,7 +3556,8 @@
 	struct smd_subsystem_config *cfg;
 	int err_ret = 0;
 	struct smd_smem_regions *smd_smem_areas;
-	int smem_idx = 0;
+	struct smem_area *smem_areas_tmp = NULL;
+	int smem_idx;
 
 	smd_platform_data = pdev->dev.platform_data;
 	num_ss = smd_platform_data->num_ss_configs;
@@ -3449,37 +3568,54 @@
 			   smd_ssr_config->disable_smsm_reset_handshake;
 
 	smd_smem_areas = smd_platform_data->smd_smem_areas;
-	if (smd_smem_areas) {
-		num_smem_areas = smd_platform_data->num_smem_areas;
-		smem_areas = kmalloc(sizeof(struct smem_area) * num_smem_areas,
-						GFP_KERNEL);
-		if (!smem_areas) {
-			pr_err("%s: smem_areas kmalloc failed\n", __func__);
+	num_smem_areas = smd_platform_data->num_smem_areas + 1;
+
+	/* Initialize main SMEM region */
+	smem_areas_tmp = kmalloc_array(num_smem_areas, sizeof(struct smem_area),
+				GFP_KERNEL);
+	if (!smem_areas_tmp) {
+		pr_err("%s: smem_areas kmalloc failed\n", __func__);
+		err_ret = -ENOMEM;
+		goto smem_areas_alloc_fail;
+	}
+
+	smem_areas_tmp[0].phys_addr =  msm_shared_ram_phys;
+	smem_areas_tmp[0].size = MSM_SHARED_RAM_SIZE;
+	smem_areas_tmp[0].virt_addr = MSM_SHARED_RAM_BASE;
+
+	/* Configure auxiliary SMEM regions */
+	for (smem_idx = 1; smem_idx < num_smem_areas; ++smem_idx) {
+		smem_areas_tmp[smem_idx].phys_addr =
+				smd_smem_areas[smem_idx].phys_addr;
+		smem_areas_tmp[smem_idx].size =
+				smd_smem_areas[smem_idx].size;
+		smem_areas_tmp[smem_idx].virt_addr = ioremap_nocache(
+			(unsigned long)(smem_areas_tmp[smem_idx].phys_addr),
+			smem_areas_tmp[smem_idx].size);
+		if (!smem_areas_tmp[smem_idx].virt_addr) {
+			pr_err("%s: ioremap_nocache() of addr: %pa size: %pa\n",
+				__func__,
+				&smem_areas_tmp[smem_idx].phys_addr,
+				&smem_areas_tmp[smem_idx].size);
 			err_ret = -ENOMEM;
-			goto smem_areas_alloc_fail;
+			goto smem_failed;
 		}
 
-		for (smem_idx = 0; smem_idx < num_smem_areas; ++smem_idx) {
-			smem_areas[smem_idx].phys_addr =
-					smd_smem_areas[smem_idx].phys_addr;
-			smem_areas[smem_idx].size =
-					smd_smem_areas[smem_idx].size;
-			smem_areas[smem_idx].virt_addr = ioremap_nocache(
-				(unsigned long)(smem_areas[smem_idx].phys_addr),
-				smem_areas[smem_idx].size);
-			if (!smem_areas[smem_idx].virt_addr) {
-				pr_err("%s: ioremap_nocache() of addr: %pa size: %pa\n",
-					__func__,
-					&smem_areas[smem_idx].phys_addr,
-					&smem_areas[smem_idx].size);
-				err_ret = -ENOMEM;
-				++smem_idx;
-				goto smem_failed;
-			}
+		if (OVERFLOW_ADD_UNSIGNED(uintptr_t,
+				(uintptr_t)smem_areas_tmp[smem_idx].virt_addr,
+				smem_areas_tmp[smem_idx].size)) {
+			pr_err("%s: invalid virtual address block %i: %p:%pa\n",
+					__func__, smem_idx,
+					smem_areas_tmp[smem_idx].virt_addr,
+					&smem_areas_tmp[smem_idx].size);
+			++smem_idx;
+			err_ret = -EINVAL;
+			goto smem_failed;
 		}
-		sort(smem_areas, num_smem_areas,
-				sizeof(struct smem_area),
-				sort_cmp_func, NULL);
+
+		SMD_DBG("%s: %d = %pa %pa", __func__, smem_idx,
+				&smd_smem_areas[smem_idx].phys_addr,
+				&smd_smem_areas[smem_idx].size);
 	}
 
 	for (i = 0; i < num_ss; i++) {
@@ -3523,8 +3659,9 @@
 				cfg->subsys_name, SMD_MAX_CH_NAME_LEN);
 	}
 
-
 	SMD_INFO("smd_core_platform_init() done\n");
+
+	smem_areas = smem_areas_tmp;
 	return 0;
 
 intr_failed:
@@ -3542,9 +3679,12 @@
 				);
 	}
 smem_failed:
-	for (smem_idx = smem_idx - 1; smem_idx >= 0; --smem_idx)
-		iounmap(smem_areas[smem_idx].virt_addr);
-	kfree(smem_areas);
+	for (smem_idx = smem_idx - 1; smem_idx >= 1; --smem_idx)
+		iounmap(smem_areas_tmp[smem_idx].virt_addr);
+
+	num_smem_areas = 0;
+	kfree(smem_areas_tmp);
+
 smem_areas_alloc_fail:
 	return err_ret;
 }
@@ -3718,12 +3858,14 @@
 	resource_size_t aux_mem_size;
 	int temp_string_size = 11; /* max 3 digit count */
 	char temp_string[temp_string_size];
-	int count;
 	struct device_node *node;
 	int ret;
 	const char *compatible;
-	struct ramdump_segment *ramdump_segments_tmp;
+	struct ramdump_segment *ramdump_segments_tmp = NULL;
+	struct smem_area *smem_areas_tmp = NULL;
+	int smem_idx = 0;
 	int subnode_num = 0;
+	int i;
 	resource_size_t irq_out_size;
 
 	disable_smsm_reset_handshake = 1;
@@ -3743,97 +3885,105 @@
 	}
 	SMD_DBG("%s: %s = %p", __func__, key, irq_out_base);
 
-	count = 1;
+	num_smem_areas = 1;
 	while (1) {
-		scnprintf(temp_string, temp_string_size, "aux-mem%d", count);
+		scnprintf(temp_string, temp_string_size, "aux-mem%d",
+				num_smem_areas);
 		r = platform_get_resource_byname(pdev, IORESOURCE_MEM,
 								temp_string);
 		if (!r)
 			break;
 
 		++num_smem_areas;
-		++count;
-		if (count > 999) {
+		if (num_smem_areas > 999) {
 			pr_err("%s: max num aux mem regions reached\n",
 								__func__);
 			break;
 		}
 	}
 
-	/* initialize SSR ramdump regions */
+	/* Initialize main SMEM region and SSR ramdump region */
 	key = "smem";
 	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, key);
 	if (!r) {
 		pr_err("%s: missing '%s'\n", __func__, key);
 		return -ENODEV;
 	}
-	ramdump_segments_tmp = kmalloc_array(num_smem_areas + 1,
-			sizeof(struct ramdump_segment), GFP_KERNEL);
 
+	smem_areas_tmp = kmalloc_array(num_smem_areas, sizeof(struct smem_area),
+				GFP_KERNEL);
+	if (!smem_areas_tmp) {
+		pr_err("%s: smem areas kmalloc failed\n", __func__);
+		ret = -ENOMEM;
+		goto free_smem_areas;
+	}
+
+	ramdump_segments_tmp = kmalloc_array(num_smem_areas,
+			sizeof(struct ramdump_segment), GFP_KERNEL);
 	if (!ramdump_segments_tmp) {
 		pr_err("%s: ramdump segment kmalloc failed\n", __func__);
 		ret = -ENOMEM;
 		goto free_smem_areas;
 	}
-	ramdump_segments_tmp[0].address = r->start;
-	ramdump_segments_tmp[0].size = resource_size(r);
 
-	if (num_smem_areas) {
+	smem_areas_tmp[smem_idx].phys_addr =  r->start;
+	smem_areas_tmp[smem_idx].size = resource_size(r);
+	smem_areas_tmp[smem_idx].virt_addr = MSM_SHARED_RAM_BASE;
 
-		smem_areas = kmalloc(sizeof(struct smem_area) * num_smem_areas,
-					GFP_KERNEL);
+	ramdump_segments_tmp[smem_idx].address = r->start;
+	ramdump_segments_tmp[smem_idx].size = resource_size(r);
+	++smem_idx;
 
-		if (!smem_areas) {
-			pr_err("%s: smem areas kmalloc failed\n", __func__);
+	/* Configure auxiliary SMEM regions */
+	while (1) {
+		scnprintf(temp_string, temp_string_size, "aux-mem%d",
+								smem_idx);
+		r = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+							temp_string);
+		if (!r)
+			break;
+		aux_mem_base = r->start;
+		aux_mem_size = resource_size(r);
+
+		ramdump_segments_tmp[smem_idx].address = aux_mem_base;
+		ramdump_segments_tmp[smem_idx].size = aux_mem_size;
+
+		smem_areas_tmp[smem_idx].phys_addr = aux_mem_base;
+		smem_areas_tmp[smem_idx].size = aux_mem_size;
+		smem_areas_tmp[smem_idx].virt_addr = ioremap_nocache(
+			(unsigned long)(smem_areas_tmp[smem_idx].phys_addr),
+			smem_areas_tmp[smem_idx].size);
+		SMD_DBG("%s: %s = %pa %pa -> %p", __func__, temp_string,
+				&aux_mem_base, &aux_mem_size,
+				smem_areas_tmp[smem_idx].virt_addr);
+
+		if (!smem_areas_tmp[smem_idx].virt_addr) {
+			pr_err("%s: ioremap_nocache() of addr:%pa size: %pa\n",
+				__func__,
+				&smem_areas_tmp[smem_idx].phys_addr,
+				&smem_areas_tmp[smem_idx].size);
 			ret = -ENOMEM;
 			goto free_smem_areas;
 		}
-		count = 1;
-		while (1) {
-			scnprintf(temp_string, temp_string_size, "aux-mem%d",
-									count);
-			r = platform_get_resource_byname(pdev, IORESOURCE_MEM,
-								temp_string);
-			if (!r)
-				break;
-			aux_mem_base = r->start;
-			aux_mem_size = resource_size(r);
 
-			/*
-			 * Add to ram-dumps segments.
-			 * ramdump_segments_tmp[0] is the main SMEM region,
-			 * so auxiliary segments are indexed by count
-			 * instead of count - 1.
-			 */
-			ramdump_segments_tmp[count].address = aux_mem_base;
-			ramdump_segments_tmp[count].size = aux_mem_size;
-
-			SMD_DBG("%s: %s = %pa %pa", __func__, temp_string,
-					&aux_mem_base, &aux_mem_size);
-			smem_areas[count - 1].phys_addr = aux_mem_base;
-			smem_areas[count - 1].size = aux_mem_size;
-			smem_areas[count - 1].virt_addr = ioremap_nocache(
-				(unsigned long)(smem_areas[count-1].phys_addr),
-				smem_areas[count - 1].size);
-			if (!smem_areas[count - 1].virt_addr) {
-				pr_err("%s: ioremap_nocache() of addr:%pa size: %pa\n",
-					__func__,
-					&smem_areas[count - 1].phys_addr,
-					&smem_areas[count - 1].size);
-				ret = -ENOMEM;
-				goto free_smem_areas;
-			}
-
-			++count;
-			if (count > 999) {
-				pr_err("%s: max num aux mem regions reached\n",
-								__func__);
-				break;
-			}
+		if (OVERFLOW_ADD_UNSIGNED(uintptr_t,
+				(uintptr_t)smem_areas_tmp[smem_idx].virt_addr,
+				smem_areas_tmp[smem_idx].size)) {
+			pr_err("%s: invalid virtual address block %i: %p:%pa\n",
+					__func__, smem_idx,
+					smem_areas_tmp[smem_idx].virt_addr,
+					&smem_areas_tmp[smem_idx].size);
+			++smem_idx;
+			ret = -EINVAL;
+			goto free_smem_areas;
 		}
-		sort(smem_areas, num_smem_areas,
-				sizeof(struct smem_area),
-				sort_cmp_func, NULL);
+
+		++smem_idx;
+		if (smem_idx > 999) {
+			pr_err("%s: max num aux mem regions reached\n",
+							__func__);
+			break;
+		}
 	}
 
 	for_each_child_of_node(pdev->dev.of_node, node) {
@@ -3861,15 +4011,16 @@
 		++subnode_num;
 	}
 
+	smem_areas = smem_areas_tmp;
 	smem_ramdump_segments = ramdump_segments_tmp;
 	return 0;
 
 rollback_subnodes:
-	count = 0;
+	i = 0;
 	for_each_child_of_node(pdev->dev.of_node, node) {
-		if (count >= subnode_num)
+		if (i >= subnode_num)
 			break;
-		++count;
+		++i;
 		compatible = of_get_property(node, "compatible", NULL);
 		if (!strcmp(compatible, "qcom,smd"))
 			unparse_smd_devicetree(node);
@@ -3877,10 +4028,12 @@
 			unparse_smsm_devicetree(node);
 	}
 free_smem_areas:
+	for (smem_idx = smem_idx - 1; smem_idx >= 1; --smem_idx)
+		iounmap(smem_areas_tmp[smem_idx].virt_addr);
+
 	num_smem_areas = 0;
 	kfree(ramdump_segments_tmp);
-	kfree(smem_areas);
-	smem_areas = NULL;
+	kfree(smem_areas_tmp);
 	return ret;
 }
 
diff --git a/arch/arm/mach-msm/smd_pkt.c b/arch/arm/mach-msm/smd_pkt.c
index 7eb9ead..424d310 100644
--- a/arch/arm/mach-msm/smd_pkt.c
+++ b/arch/arm/mach-msm/smd_pkt.c
@@ -509,7 +509,7 @@
 	do {
 		prepare_to_wait(&smd_pkt_devp->ch_write_wait_queue,
 				&write_wait, TASK_UNINTERRUPTIBLE);
-		if (!smd_write_avail(smd_pkt_devp->ch) &&
+		if (!smd_write_segment_avail(smd_pkt_devp->ch) &&
 		    !smd_pkt_devp->has_reset) {
 			smd_enable_read_intr(smd_pkt_devp->ch);
 			schedule();
@@ -631,7 +631,7 @@
 		return;
 	}
 
-	sz = smd_write_avail(smd_pkt_devp->ch);
+	sz = smd_write_segment_avail(smd_pkt_devp->ch);
 	if (sz) {
 		D_WRITE("%s: %d bytes write space in smd_pkt_dev id:%d\n",
 			__func__, sz, smd_pkt_devp->i);
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 83f7a1d..12a3ceb 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -328,7 +328,12 @@
 
 	/* 8610 IDs */
 	[147] = MSM_CPU_8610,
+	[161] = MSM_CPU_8610,
+	[162] = MSM_CPU_8610,
+	[163] = MSM_CPU_8610,
+	[164] = MSM_CPU_8610,
 	[165] = MSM_CPU_8610,
+	[166] = MSM_CPU_8610,
 
 	/* 8064AB IDs */
 	[153] = MSM_CPU_8064AB,
@@ -348,8 +353,8 @@
 	/* 8064AA IDs */
 	[172] = MSM_CPU_8064AA,
 
-	/* zinc IDs */
-	[178] = MSM_CPU_ZINC,
+	/* 8084 IDs */
+	[178] = MSM_CPU_8084,
 
 	/* krypton IDs */
 	[187] = MSM_CPU_KRYPTON,
@@ -853,9 +858,9 @@
 		dummy_socinfo.id = 146;
 		strlcpy(dummy_socinfo.build_id, "mpq8092 - ",
 		sizeof(dummy_socinfo.build_id));
-	} else if (early_machine_is_msmzinc()) {
+	} else if (early_machine_is_apq8084()) {
 		dummy_socinfo.id = 178;
-		strlcpy(dummy_socinfo.build_id, "msmzinc - ",
+		strlcpy(dummy_socinfo.build_id, "apq8084 - ",
 			sizeof(dummy_socinfo.build_id));
 	} else if (early_machine_is_msmkrypton()) {
 		dummy_socinfo.id = 187;
diff --git a/drivers/bluetooth/bluetooth-power.c b/drivers/bluetooth/bluetooth-power.c
index d7c69db..13c9080 100644
--- a/drivers/bluetooth/bluetooth-power.c
+++ b/drivers/bluetooth/bluetooth-power.c
@@ -23,38 +23,227 @@
 #include <linux/gpio.h>
 #include <linux/of_gpio.h>
 #include <linux/delay.h>
+#include <linux/bluetooth-power.h>
+#include <linux/slab.h>
+#include <linux/regulator/consumer.h>
 
-static struct of_device_id ar3002_match_table[] = {
+#define BT_PWR_DBG(fmt, arg...)  pr_debug("%s: " fmt "\n" , __func__ , ## arg)
+#define BT_PWR_INFO(fmt, arg...) pr_info("%s: " fmt "\n" , __func__ , ## arg)
+#define BT_PWR_ERR(fmt, arg...)  pr_err("%s: " fmt "\n" , __func__ , ## arg)
+
+
+static struct of_device_id bt_power_match_table[] = {
 	{	.compatible = "qca,ar3002" },
 	{}
 };
 
-static int bt_reset_gpio;
-
+static struct bluetooth_power_platform_data *bt_power_pdata;
+static struct platform_device *btpdev;
 static bool previous;
 
-static int bluetooth_power(int on)
+static int bt_vreg_init(struct bt_power_vreg_data *vreg)
 {
-	int rc;
+	int rc = 0;
+	struct device *dev = &btpdev->dev;
 
-	pr_debug("%s  bt_gpio= %d\n", __func__, bt_reset_gpio);
+	BT_PWR_DBG("vreg_get for : %s", vreg->name);
+
+	/* Get the regulator handle */
+	vreg->reg = regulator_get(dev, vreg->name);
+	if (IS_ERR(vreg->reg)) {
+		rc = PTR_ERR(vreg->reg);
+		pr_err("%s: regulator_get(%s) failed. rc=%d\n",
+			__func__, vreg->name, rc);
+		goto out;
+	}
+
+	if ((regulator_count_voltages(vreg->reg) > 0)
+			&& (vreg->low_vol_level) && (vreg->high_vol_level))
+		vreg->set_voltage_sup = 1;
+
+out:
+	return rc;
+}
+
+static int bt_vreg_enable(struct bt_power_vreg_data *vreg)
+{
+	int rc = 0;
+
+	BT_PWR_DBG("vreg_en for : %s", vreg->name);
+
+	if (!vreg->is_enabled) {
+		if (vreg->set_voltage_sup) {
+			rc = regulator_set_voltage(vreg->reg,
+						vreg->low_vol_level,
+						vreg->high_vol_level);
+			if (rc < 0) {
+				BT_PWR_ERR("vreg_set_vol(%s) failed rc=%d\n",
+						vreg->name, rc);
+				goto out;
+			}
+		}
+
+		rc = regulator_enable(vreg->reg);
+		if (rc < 0) {
+			BT_PWR_ERR("regulator_enable(%s) failed. rc=%d\n",
+					vreg->name, rc);
+			goto out;
+		}
+		vreg->is_enabled = true;
+	}
+out:
+	return rc;
+}
+
+static int bt_vreg_disable(struct bt_power_vreg_data *vreg)
+{
+	int rc = 0;
+
+	if (!vreg)
+		return rc;
+
+	BT_PWR_DBG("vreg_disable for : %s", vreg->name);
+
+	if (vreg->is_enabled) {
+		rc = regulator_disable(vreg->reg);
+		if (rc < 0) {
+			BT_PWR_ERR("regulator_disable(%s) failed. rc=%d\n",
+					vreg->name, rc);
+			goto out;
+		}
+		vreg->is_enabled = false;
+
+		if (vreg->set_voltage_sup) {
+			/* Set the min voltage to 0 */
+			rc = regulator_set_voltage(vreg->reg,
+						0,
+						vreg->high_vol_level);
+			if (rc < 0) {
+				BT_PWR_ERR("vreg_set_vol(%s) failed rc=%d\n",
+						vreg->name, rc);
+				goto out;
+
+			}
+		}
+	}
+out:
+	return rc;
+}
+
+static int bt_configure_vreg(struct bt_power_vreg_data *vreg)
+{
+	int rc = 0;
+
+	BT_PWR_DBG("config %s", vreg->name);
+
+	/* Get the regulator handle for vreg */
+	if (!(vreg->reg)) {
+		rc = bt_vreg_init(vreg);
+		if (rc < 0)
+			return rc;
+	}
+	rc = bt_vreg_enable(vreg);
+
+	return rc;
+}
+
+static int bt_configure_gpios(int on)
+{
+	int rc = 0;
+	int bt_reset_gpio = bt_power_pdata->bt_gpio_sys_rst;
+
+	BT_PWR_DBG("%s  bt_gpio= %d on: %d", __func__, bt_reset_gpio, on);
+
 	if (on) {
+		rc = gpio_request(bt_reset_gpio, "bt_sys_rst_n");
+		if (rc) {
+			BT_PWR_ERR("unable to request gpio %d (%d)\n",
+					bt_reset_gpio, rc);
+			return rc;
+		}
+
+		rc = gpio_direction_output(bt_reset_gpio, 0);
+		if (rc) {
+			BT_PWR_ERR("Unable to set direction\n");
+			return rc;
+		}
+
 		rc = gpio_direction_output(bt_reset_gpio, 1);
 		if (rc) {
-			pr_err("%s: Unable to set direction\n", __func__);
+			BT_PWR_ERR("Unable to set direction\n");
 			return rc;
 		}
 		msleep(100);
 	} else {
 		gpio_set_value(bt_reset_gpio, 0);
+
 		rc = gpio_direction_input(bt_reset_gpio);
-		if (rc) {
-			pr_err("%s: Unable to set direction\n", __func__);
-			return rc;
-		}
+		if (rc)
+			BT_PWR_ERR("Unable to set direction\n");
+
 		msleep(100);
 	}
-	return 0;
+	return rc;
+}
+
+static int bluetooth_power(int on)
+{
+	int rc = 0;
+
+	BT_PWR_DBG("on: %d", on);
+
+	if (on) {
+		if (bt_power_pdata->bt_vdd_io) {
+			rc = bt_configure_vreg(bt_power_pdata->bt_vdd_io);
+			if (rc < 0) {
+				BT_PWR_ERR("bt_power vddio config failed");
+				goto out;
+			}
+		}
+		if (bt_power_pdata->bt_vdd_ldo) {
+			rc = bt_configure_vreg(bt_power_pdata->bt_vdd_ldo);
+			if (rc < 0) {
+				BT_PWR_ERR("bt_power vddldo config failed");
+				goto vdd_ldo_fail;
+			}
+		}
+		if (bt_power_pdata->bt_vdd_pa) {
+			rc = bt_configure_vreg(bt_power_pdata->bt_vdd_pa);
+			if (rc < 0) {
+				BT_PWR_ERR("bt_power vddpa config failed");
+				goto vdd_pa_fail;
+			}
+		}
+		if (bt_power_pdata->bt_chip_pwd) {
+			rc = bt_configure_vreg(bt_power_pdata->bt_chip_pwd);
+			if (rc < 0) {
+				BT_PWR_ERR("bt_power vddldo config failed");
+				goto chip_pwd_fail;
+			}
+		}
+		if (bt_power_pdata->bt_gpio_sys_rst) {
+			rc = bt_configure_gpios(on);
+			if (rc < 0) {
+				BT_PWR_ERR("bt_power gpio config failed");
+				goto gpio_fail;
+			}
+		}
+	} else {
+		bt_configure_gpios(on);
+gpio_fail:
+		if (bt_power_pdata->bt_gpio_sys_rst)
+			gpio_free(bt_power_pdata->bt_gpio_sys_rst);
+		bt_vreg_disable(bt_power_pdata->bt_chip_pwd);
+chip_pwd_fail:
+		bt_vreg_disable(bt_power_pdata->bt_vdd_pa);
+vdd_pa_fail:
+		bt_vreg_disable(bt_power_pdata->bt_vdd_ldo);
+vdd_ldo_fail:
+		bt_vreg_disable(bt_power_pdata->bt_vdd_io);
+	}
+
+out:
+	return rc;
 }
 
 static int bluetooth_toggle_radio(void *data, bool blocked)
@@ -62,7 +251,9 @@
 	int ret = 0;
 	int (*power_control)(int enable);
 
-	power_control = data;
+	power_control =
+		((struct bluetooth_power_platform_data *)data)->bt_power_setup;
+
 	if (previous != blocked)
 		ret = (*power_control)(!blocked);
 	if (!ret)
@@ -117,47 +308,146 @@
 	platform_set_drvdata(pdev, NULL);
 }
 
+#define MAX_PROP_SIZE 32
+static int bt_dt_parse_vreg_info(struct device *dev,
+		struct bt_power_vreg_data **vreg_data, const char *vreg_name)
+{
+	int len, ret = 0;
+	const __be32 *prop;
+	char prop_name[MAX_PROP_SIZE];
+	struct bt_power_vreg_data *vreg;
+	struct device_node *np = dev->of_node;
+
+	BT_PWR_DBG("vreg dev tree parse for %s", vreg_name);
+
+	snprintf(prop_name, MAX_PROP_SIZE, "%s-supply", vreg_name);
+	if (of_parse_phandle(np, prop_name, 0)) {
+		vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
+		if (!vreg) {
+			dev_err(dev, "No memory for vreg: %s\n", vreg_name);
+			ret = -ENOMEM;
+			goto err;
+		}
+
+		vreg->name = vreg_name;
+
+		snprintf(prop_name, MAX_PROP_SIZE,
+				"qcom,%s-voltage-level", vreg_name);
+		prop = of_get_property(np, prop_name, &len);
+		if (!prop || (len != (2 * sizeof(__be32)))) {
+			dev_warn(dev, "%s %s property\n",
+				prop ? "invalid format" : "no", prop_name);
+		} else {
+			vreg->low_vol_level = be32_to_cpup(&prop[0]);
+			vreg->high_vol_level = be32_to_cpup(&prop[1]);
+		}
+
+		*vreg_data = vreg;
+		BT_PWR_DBG("%s: vol=[%d %d]uV\n",
+			vreg->name, vreg->low_vol_level,
+			vreg->high_vol_level);
+	} else
+		BT_PWR_INFO("%s: is not provided in device tree", vreg_name);
+
+err:
+	return ret;
+}
+
+static int bt_power_populate_dt_pinfo(struct platform_device *pdev)
+{
+	int rc;
+
+	BT_PWR_DBG("");
+
+	if (!bt_power_pdata)
+		return -ENOMEM;
+
+	if (pdev->dev.of_node) {
+		bt_power_pdata->bt_gpio_sys_rst =
+			of_get_named_gpio(pdev->dev.of_node,
+						"qca,bt-reset-gpio", 0);
+		if (bt_power_pdata->bt_gpio_sys_rst < 0) {
+			BT_PWR_ERR("bt-reset-gpio not provided in device tree");
+			return bt_power_pdata->bt_gpio_sys_rst;
+		}
+
+		rc = bt_dt_parse_vreg_info(&pdev->dev,
+					&bt_power_pdata->bt_vdd_io,
+					"qca,bt-vdd-io");
+		if (rc < 0)
+			return rc;
+
+		rc = bt_dt_parse_vreg_info(&pdev->dev,
+					&bt_power_pdata->bt_vdd_pa,
+					"qca,bt-vdd-pa");
+		if (rc < 0)
+			return rc;
+
+		rc = bt_dt_parse_vreg_info(&pdev->dev,
+					&bt_power_pdata->bt_vdd_ldo,
+					"qca,bt-vdd-ldo");
+		if (rc < 0)
+			return rc;
+
+		rc = bt_dt_parse_vreg_info(&pdev->dev,
+					&bt_power_pdata->bt_chip_pwd,
+					"qca,bt-chip-pwd");
+		if (rc < 0)
+			return rc;
+
+	}
+
+	bt_power_pdata->bt_power_setup = bluetooth_power;
+
+	return 0;
+}
+
 static int __devinit bt_power_probe(struct platform_device *pdev)
 {
 	int ret = 0;
 
 	dev_dbg(&pdev->dev, "%s\n", __func__);
 
-	if (!pdev->dev.platform_data) {
-		/* Update the platform data if the
-		device node exists as part of device tree.*/
-		if (pdev->dev.of_node) {
-			pdev->dev.platform_data = bluetooth_power;
-		} else {
-			dev_err(&pdev->dev, "device node not set\n");
-			return -ENOSYS;
-		}
+	bt_power_pdata =
+		kzalloc(sizeof(struct bluetooth_power_platform_data),
+			GFP_KERNEL);
+
+	if (!bt_power_pdata) {
+		BT_PWR_ERR("Failed to allocate memory");
+		return -ENOMEM;
 	}
+
 	if (pdev->dev.of_node) {
-		bt_reset_gpio = of_get_named_gpio(pdev->dev.of_node,
-							"qca,bt-reset-gpio", 0);
-		if (bt_reset_gpio < 0) {
-			pr_err("bt-reset-gpio not available");
-			return bt_reset_gpio;
+		ret = bt_power_populate_dt_pinfo(pdev);
+		if (ret < 0) {
+			BT_PWR_ERR("Failed to populate device tree info");
+			goto free_pdata;
 		}
+		pdev->dev.platform_data = bt_power_pdata;
+	} else if (pdev->dev.platform_data) {
+		/* Optional data set to default if not provided */
+		if (!((struct bluetooth_power_platform_data *)
+			(pdev->dev.platform_data))->bt_power_setup)
+			((struct bluetooth_power_platform_data *)
+				(pdev->dev.platform_data))->bt_power_setup =
+						bluetooth_power;
+
+		memcpy(bt_power_pdata, pdev->dev.platform_data,
+			sizeof(struct bluetooth_power_platform_data));
+	} else {
+		BT_PWR_ERR("Failed to get platform data");
+		goto free_pdata;
 	}
 
-	ret = gpio_request(bt_reset_gpio, "bt sys_rst_n");
-	if (ret) {
-		pr_err("%s: unable to request gpio %d (%d)\n",
-			__func__, bt_reset_gpio, ret);
-		return ret;
-	}
+	if (bluetooth_power_rfkill_probe(pdev) < 0)
+		goto free_pdata;
 
-	/* When booting up, de-assert BT reset pin */
-	ret = gpio_direction_output(bt_reset_gpio, 0);
-	if (ret) {
-		pr_err("%s: Unable to set direction\n", __func__);
-		return ret;
-	}
+	btpdev = pdev;
 
-	ret = bluetooth_power_rfkill_probe(pdev);
+	return 0;
 
+free_pdata:
+	kfree(bt_power_pdata);
 	return ret;
 }
 
@@ -167,6 +457,11 @@
 
 	bluetooth_power_rfkill_remove(pdev);
 
+	if (bt_power_pdata->bt_chip_pwd->reg)
+		regulator_put(bt_power_pdata->bt_chip_pwd->reg);
+
+	kfree(bt_power_pdata);
+
 	return 0;
 }
 
@@ -176,7 +471,7 @@
 	.driver = {
 		.name = "bt_power",
 		.owner = THIS_MODULE,
-		.of_match_table = ar3002_match_table,
+		.of_match_table = bt_power_match_table,
 	},
 };
 
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index d78327f..51578e0 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -527,11 +527,9 @@
 {
 	struct fastrpc_apps *me = &gfa;
 
-	if (me->chan)
-		(void)smd_close(me->chan);
+	smd_close(me->chan);
 	context_list_dtor(&me->clst);
-	if (me->iclient)
-		ion_client_destroy(me->iclient);
+	ion_client_destroy(me->iclient);
 	me->iclient = 0;
 	me->chan = 0;
 }
@@ -584,25 +582,32 @@
 			INIT_HLIST_HEAD(&me->htbl[i]);
 		VERIFY(err, 0 == context_list_ctor(&me->clst, SZ_4K));
 		if (err)
-			goto bail;
+			goto context_list_bail;
 		me->iclient = msm_ion_client_create(ION_HEAP_CARVEOUT_MASK,
 							DEVICE_NAME);
 		VERIFY(err, 0 == IS_ERR_OR_NULL(me->iclient));
 		if (err)
-			goto bail;
+			goto ion_bail;
 		VERIFY(err, 0 == smd_named_open_on_edge(FASTRPC_SMD_GUID,
 						SMD_APPS_QDSP, &me->chan,
 						me, smd_event_handler));
 		if (err)
-			goto bail;
+			goto smd_bail;
 		VERIFY(err, 0 != wait_for_completion_timeout(&me->work,
 							RPC_TIMEOUT));
 		if (err)
-			goto bail;
+			goto completion_bail;
 	}
- bail:
-	if (err)
-		fastrpc_deinit();
+
+	return 0;
+
+completion_bail:
+	smd_close(me->chan);
+smd_bail:
+	ion_client_destroy(me->iclient);
+ion_bail:
+	context_list_dtor(&me->clst);
+context_list_bail:
 	return err;
 }
 
@@ -1090,35 +1095,37 @@
 
 	VERIFY(err, 0 == fastrpc_init());
 	if (err)
-		goto bail;
+		goto fastrpc_bail;
 	VERIFY(err, 0 == alloc_chrdev_region(&me->dev_no, 0, 1, DEVICE_NAME));
 	if (err)
-		goto bail;
+		goto alloc_chrdev_bail;
 	cdev_init(&me->cdev, &fops);
 	me->cdev.owner = THIS_MODULE;
 	VERIFY(err, 0 == cdev_add(&me->cdev, MKDEV(MAJOR(me->dev_no), 0), 1));
 	if (err)
-		goto bail;
+		goto cdev_init_bail;
 	me->class = class_create(THIS_MODULE, "chardrv");
 	VERIFY(err, !IS_ERR(me->class));
 	if (err)
-		goto bail;
+		goto class_create_bail;
 	me->dev = device_create(me->class, NULL, MKDEV(MAJOR(me->dev_no), 0),
 				NULL, DEVICE_NAME);
 	VERIFY(err, !IS_ERR(me->dev));
 	if (err)
-		goto bail;
+		goto device_create_bail;
 	pr_info("'created /dev/%s c %d 0'\n", DEVICE_NAME, MAJOR(me->dev_no));
- bail:
-	if (err) {
-		if (me->dev_no)
-			unregister_chrdev_region(me->dev_no, 1);
-		if (me->class)
-			class_destroy(me->class);
-		if (me->cdev.owner)
-			cdev_del(&me->cdev);
-		fastrpc_deinit();
-	}
+
+	return 0;
+
+device_create_bail:
+	class_destroy(me->class);
+class_create_bail:
+	cdev_del(&me->cdev);
+cdev_init_bail:
+	unregister_chrdev_region(me->dev_no, 1);
+alloc_chrdev_bail:
+	fastrpc_deinit();
+fastrpc_bail:
 	return err;
 }
 
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index 6d28042..682d876 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -1090,6 +1090,12 @@
 		diag_smd_destructor(&driver->smd_dci[i]);
 
 	platform_driver_unregister(&msm_diag_dci_driver);
+
+	if (driver->dci_client_tbl) {
+		for (i = 0; i < MAX_DCI_CLIENTS; i++)
+			kfree(driver->dci_client_tbl[i].dci_data);
+	}
+
 	kfree(driver->req_tracking_tbl);
 	kfree(driver->dci_client_tbl);
 	kfree(driver->apps_dci_buf);
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 6f37608..684f11d 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -37,6 +37,7 @@
 #define HDLC_OUT_BUF_SIZE	8192
 #define POOL_TYPE_COPY		1
 #define POOL_TYPE_HDLC		2
+#define POOL_TYPE_USER		3
 #define POOL_TYPE_WRITE_STRUCT	4
 #define POOL_TYPE_HSIC		5
 #define POOL_TYPE_HSIC_2	6
@@ -55,7 +56,7 @@
 #define MSG_MASK_SIZE 10000
 #define LOG_MASK_SIZE 8000
 #define EVENT_MASK_SIZE 1000
-#define USER_SPACE_DATA 8000
+#define USER_SPACE_DATA 8192
 #define PKT_SIZE 4096
 #define MAX_EQUIP_ID 15
 #define DIAG_CTRL_MSG_LOG_MASK	9
@@ -234,16 +235,20 @@
 	unsigned int poolsize;
 	unsigned int itemsize_hdlc;
 	unsigned int poolsize_hdlc;
+	unsigned int itemsize_user;
+	unsigned int poolsize_user;
 	unsigned int itemsize_write_struct;
 	unsigned int poolsize_write_struct;
 	unsigned int debug_flag;
 	/* State for the mempool for the char driver */
 	mempool_t *diagpool;
 	mempool_t *diag_hdlc_pool;
+	mempool_t *diag_user_pool;
 	mempool_t *diag_write_struct_pool;
 	struct mutex diagmem_mutex;
 	int count;
 	int count_hdlc_pool;
+	int count_user_pool;
 	int count_write_struct_pool;
 	int used;
 	/* Buffers for masks */
@@ -259,7 +264,6 @@
 	struct diag_smd_info smd_dci[NUM_SMD_DCI_CHANNELS];
 	unsigned char *usb_buf_out;
 	unsigned char *apps_rsp_buf;
-	unsigned char *user_space_data;
 	/* buffer for updating mask to peripherals */
 	unsigned char *buf_msg_mask_update;
 	unsigned char *buf_log_mask_update;
@@ -276,6 +280,8 @@
 	struct usb_diag_ch *legacy_ch;
 	struct work_struct diag_proc_hdlc_work;
 	struct work_struct diag_read_work;
+	struct work_struct diag_usb_connect_work;
+	struct work_struct diag_usb_disconnect_work;
 #endif
 	struct workqueue_struct *diag_wq;
 	struct work_struct diag_drain_work;
@@ -312,6 +318,7 @@
 #ifdef CONFIG_DIAGFWD_BRIDGE_CODE
 	spinlock_t hsic_ready_spinlock;
 	/* common for all bridges */
+	struct work_struct diag_connect_work;
 	struct work_struct diag_disconnect_work;
 	/* SGLTE variables */
 	int lcid;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index a0c32f5..2ebae71 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -56,13 +56,16 @@
 /* The following variables can be specified by module options */
  /* for copy buffer */
 static unsigned int itemsize = 4096; /*Size of item in the mempool */
-static unsigned int poolsize = 10; /*Number of items in the mempool */
+static unsigned int poolsize = 12; /*Number of items in the mempool */
 /* for hdlc buffer */
 static unsigned int itemsize_hdlc = 8192; /*Size of item in the mempool */
-static unsigned int poolsize_hdlc = 8;  /*Number of items in the mempool */
+static unsigned int poolsize_hdlc = 10;  /*Number of items in the mempool */
+/* for user buffer */
+static unsigned int itemsize_user = 8192; /*Size of item in the mempool */
+static unsigned int poolsize_user = 8;  /*Number of items in the mempool */
 /* for write structure buffer */
 static unsigned int itemsize_write_struct = 20; /*Size of item in the mempool */
-static unsigned int poolsize_write_struct = 8; /* Num of items in the mempool */
+static unsigned int poolsize_write_struct = 10;/* Num of items in the mempool */
 /* This is the max number of user-space clients supported at initialization*/
 static unsigned int max_clients = 15;
 static unsigned int threshold_client_limit = 30;
@@ -781,10 +784,26 @@
 {
 	int i, temp, success = -EINVAL, status;
 	int temp_realtime_mode = driver->real_time_mode;
+	int requested_mode = (int)ioarg;
+
+	switch (requested_mode) {
+	case USB_MODE:
+	case MEMORY_DEVICE_MODE:
+	case NO_LOGGING_MODE:
+	case UART_MODE:
+	case SOCKET_MODE:
+	case CALLBACK_MODE:
+	case MEMORY_DEVICE_MODE_NRT:
+		break;
+	default:
+		pr_err("diag: In %s, request to switch to invalid mode: %d\n",
+			__func__, requested_mode);
+		return -EINVAL;
+	}
 
 	mutex_lock(&driver->diagchar_mutex);
 	temp = driver->logging_mode;
-	driver->logging_mode = (int)ioarg;
+	driver->logging_mode = requested_mode;
 
 	if (driver->logging_mode == MEMORY_DEVICE_MODE_NRT) {
 		diag_send_diag_mode_update(MODE_NONREALTIME);
@@ -1013,6 +1032,8 @@
 					 current->tgid)
 					driver->req_tracking_tbl[i].pid = 0;
 			driver->dci_client_tbl[result].client = NULL;
+			kfree(driver->dci_client_tbl[result].dci_data);
+			driver->dci_client_tbl[result].dci_data = NULL;
 			driver->num_dci_client--;
 		}
 		mutex_unlock(&driver->dci_mutex);
@@ -1362,6 +1383,7 @@
 	struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
 	struct diag_hdlc_dest_type enc = { NULL, NULL, 0 };
 	void *buf_copy = NULL;
+	void *user_space_data = NULL;
 	unsigned int payload_size;
 
 	index = 0;
@@ -1388,31 +1410,50 @@
 	}
 #endif /* DIAG over USB */
 	if (pkt_type == DCI_DATA_TYPE) {
-		err = copy_from_user(driver->user_space_data, buf + 4,
-							 payload_size);
+		user_space_data = diagmem_alloc(driver, payload_size,
+								POOL_TYPE_USER);
+		if (!user_space_data) {
+			driver->dropped_count++;
+			return -ENOMEM;
+		}
+		err = copy_from_user(user_space_data, buf + 4, payload_size);
 		if (err) {
 			pr_alert("diag: copy failed for DCI data\n");
 			return DIAG_DCI_SEND_DATA_FAIL;
 		}
-		err = diag_process_dci_transaction(driver->user_space_data,
+		err = diag_process_dci_transaction(user_space_data,
 							payload_size);
+		diagmem_free(driver, user_space_data, POOL_TYPE_USER);
 		return err;
 	}
 	if (pkt_type == CALLBACK_DATA_TYPE) {
-		err = copy_from_user(driver->user_space_data, buf + 4,
-							 payload_size);
-		 if (err) {
+		if (payload_size > itemsize) {
+			pr_err("diag: Dropping packet, packet payload size crosses 4KB limit. Current payload size %d\n",
+				payload_size);
+			driver->dropped_count++;
+			return -EBADMSG;
+		}
+
+		buf_copy = diagmem_alloc(driver, payload_size, POOL_TYPE_COPY);
+		if (!buf_copy) {
+			driver->dropped_count++;
+			return -ENOMEM;
+		}
+
+		err = copy_from_user(buf_copy, 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);
+		remote_proc = diag_get_remote(*(int *)buf_copy);
 
 		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);
+			ret = diag_process_apps_pkt(buf_copy, payload_size);
+			diagmem_free(driver, buf_copy, POOL_TYPE_COPY);
+			return ret;
 		}
 		/* The packet is for the remote processor */
 		token_offset = 4;
@@ -1420,8 +1461,8 @@
 		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 -
+		send.pkt = (void *)(buf_copy + token_offset);
+		send.last = (void *)(buf_copy + token_offset -
 							1 + payload_size);
 		send.terminate = 1;
 
@@ -1503,21 +1544,30 @@
 			}
 		}
 #endif
+		diagmem_free(driver, buf_copy, POOL_TYPE_COPY);
 		diagmem_free(driver, buf_hdlc, POOL_TYPE_HDLC);
+		buf_copy = NULL;
 		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,
+		user_space_data = diagmem_alloc(driver, payload_size,
+								POOL_TYPE_USER);
+		if (!user_space_data) {
+			driver->dropped_count++;
+			return -ENOMEM;
+		}
+		err = copy_from_user(user_space_data, buf + 4,
 							 payload_size);
 		if (err) {
 			pr_err("diag: copy failed for user space data\n");
+			diagmem_free(driver, user_space_data, POOL_TYPE_USER);
 			return -EIO;
 		}
 		/* Check for proc_type */
-		remote_proc = diag_get_remote(*(int *)driver->user_space_data);
+		remote_proc = diag_get_remote(*(int *)user_space_data);
 
 		if (remote_proc) {
 			token_offset = 4;
@@ -1527,9 +1577,11 @@
 
 		/* Check masks for On-Device logging */
 		if (driver->mask_check) {
-			if (!mask_request_validate(driver->user_space_data +
+			if (!mask_request_validate(user_space_data +
 							 token_offset)) {
 				pr_alert("diag: mask request Invalid\n");
+				diagmem_free(driver, user_space_data,
+							POOL_TYPE_USER);
 				return -EFAULT;
 			}
 		}
@@ -1537,7 +1589,7 @@
 #ifdef DIAG_DEBUG
 		pr_debug("diag: user space data %d\n", payload_size);
 		for (i = 0; i < payload_size; i++)
-			pr_debug("\t %x", *((driver->user_space_data
+			pr_debug("\t %x", *((user_space_data
 						+ token_offset)+i));
 #endif
 #ifdef CONFIG_DIAG_SDIO_PIPE
@@ -1548,7 +1600,7 @@
 					 payload_size));
 			if (driver->sdio_ch && (payload_size > 0)) {
 				sdio_write(driver->sdio_ch, (void *)
-				   (driver->user_space_data + token_offset),
+				   (user_space_data + token_offset),
 				   payload_size);
 			}
 		}
@@ -1578,8 +1630,8 @@
 				diag_hsic[index].in_busy_hsic_read_on_device =
 									0;
 				err = diag_bridge_write(index,
-						driver->user_space_data +
-						token_offset, payload_size);
+						user_space_data + token_offset,
+						payload_size);
 				if (err) {
 					pr_err("diag: err sending mask to MDM: %d\n",
 					       err);
@@ -1600,11 +1652,13 @@
 						&& driver->lcid) {
 			if (payload_size > 0) {
 				err = msm_smux_write(driver->lcid, NULL,
-					driver->user_space_data + token_offset,
+					user_space_data + token_offset,
 					payload_size);
 				if (err) {
 					pr_err("diag:send mask to MDM err %d",
 							err);
+					diagmem_free(driver, user_space_data,
+								POOL_TYPE_USER);
 					return err;
 				}
 			}
@@ -1613,8 +1667,8 @@
 		/* send masks to 8k now */
 		if (!remote_proc)
 			diag_process_hdlc((void *)
-				(driver->user_space_data + token_offset),
-				 payload_size);
+				(user_space_data + token_offset), payload_size);
+		diagmem_free(driver, user_space_data, POOL_TYPE_USER);
 		return 0;
 	}
 
@@ -1885,6 +1939,11 @@
 }
 
 #ifdef CONFIG_DIAGFWD_BRIDGE_CODE
+static void diag_connect_work_fn(struct work_struct *w)
+{
+	diagfwd_connect_bridge(1);
+}
+
 static void diag_disconnect_work_fn(struct work_struct *w)
 {
 	diagfwd_disconnect_bridge(1);
@@ -1944,6 +2003,8 @@
 		driver->poolsize = poolsize;
 		driver->itemsize_hdlc = itemsize_hdlc;
 		driver->poolsize_hdlc = poolsize_hdlc;
+		driver->itemsize_user = itemsize_user;
+		driver->poolsize_user = poolsize_user;
 		driver->itemsize_write_struct = itemsize_write_struct;
 		driver->poolsize_write_struct = poolsize_write_struct;
 		driver->num_clients = max_clients;
@@ -1969,6 +2030,8 @@
 			pr_err("diag: could not register HSIC device, ret: %d\n",
 				ret);
 		diagfwd_bridge_init(SMUX);
+		INIT_WORK(&(driver->diag_connect_work),
+						 diag_connect_work_fn);
 		INIT_WORK(&(driver->diag_disconnect_work),
 						 diag_disconnect_work_fn);
 #endif
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index a4003ff..151e304 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -402,7 +402,7 @@
 				return;
 			}
 			if (pkt_len > r) {
-				pr_err("diag: In %s, SMD sending partial pkt %d %d %d %d %d %d\n",
+				pr_debug("diag: In %s, SMD sending partial pkt %d %d %d %d %d %d\n",
 				__func__, pkt_len, r, total_recd, loop_count,
 				smd_info->peripheral, smd_info->type);
 			}
@@ -1282,6 +1282,16 @@
 #define N_LEGACY_WRITE	(driver->poolsize + 6)
 #define N_LEGACY_READ	1
 
+static void diag_usb_connect_work_fn(struct work_struct *w)
+{
+	diagfwd_connect();
+}
+
+static void diag_usb_disconnect_work_fn(struct work_struct *w)
+{
+	diagfwd_disconnect();
+}
+
 int diagfwd_connect(void)
 {
 	int err;
@@ -1448,10 +1458,12 @@
 {
 	switch (event) {
 	case USB_DIAG_CONNECT:
-		diagfwd_connect();
+		queue_work(driver->diag_wq,
+			 &driver->diag_usb_connect_work);
 		break;
 	case USB_DIAG_DISCONNECT:
-		diagfwd_disconnect();
+		queue_work(driver->diag_wq,
+			 &driver->diag_usb_disconnect_work);
 		break;
 	case USB_DIAG_READ_DONE:
 		diagfwd_read_complete(d_req);
@@ -1783,11 +1795,6 @@
 	    && (driver->hdlc_buf = kzalloc(HDLC_MAX, GFP_KERNEL)) == NULL)
 		goto err;
 	kmemleak_not_leak(driver->hdlc_buf);
-	if (driver->user_space_data == NULL)
-		driver->user_space_data = kzalloc(USER_SPACE_DATA, GFP_KERNEL);
-		if (driver->user_space_data == NULL)
-			goto err;
-	kmemleak_not_leak(driver->user_space_data);
 	if (driver->client_map == NULL &&
 	    (driver->client_map = kzalloc
 	     ((driver->num_clients) * sizeof(struct diag_client_map),
@@ -1832,6 +1839,10 @@
 	}
 	driver->diag_wq = create_singlethread_workqueue("diag_wq");
 #ifdef CONFIG_DIAG_OVER_USB
+	INIT_WORK(&(driver->diag_usb_connect_work),
+						 diag_usb_connect_work_fn);
+	INIT_WORK(&(driver->diag_usb_disconnect_work),
+						 diag_usb_disconnect_work_fn);
 	INIT_WORK(&(driver->diag_proc_hdlc_work), diag_process_hdlc_fn);
 	INIT_WORK(&(driver->diag_read_work), diag_read_work_fn);
 	driver->legacy_ch = usb_diag_open(DIAG_LEGACY, driver,
@@ -1862,7 +1873,6 @@
 	kfree(driver->pkt_buf);
 	kfree(driver->usb_read_ptr);
 	kfree(driver->apps_rsp_buf);
-	kfree(driver->user_space_data);
 	if (driver->diag_wq)
 		destroy_workqueue(driver->diag_wq);
 }
@@ -1895,6 +1905,5 @@
 	kfree(driver->pkt_buf);
 	kfree(driver->usb_read_ptr);
 	kfree(driver->apps_rsp_buf);
-	kfree(driver->user_space_data);
 	destroy_workqueue(driver->diag_wq);
 }
diff --git a/drivers/char/diag/diagfwd_bridge.c b/drivers/char/diag/diagfwd_bridge.c
index 475f5ba..8c07219b 100644
--- a/drivers/char/diag/diagfwd_bridge.c
+++ b/drivers/char/diag/diagfwd_bridge.c
@@ -233,7 +233,8 @@
 
 	switch (event) {
 	case USB_DIAG_CONNECT:
-		diagfwd_connect_bridge(1);
+		queue_work(driver->diag_wq,
+			 &driver->diag_connect_work);
 		break;
 	case USB_DIAG_DISCONNECT:
 		queue_work(driver->diag_wq,
diff --git a/drivers/char/diag/diagmem.c b/drivers/char/diag/diagmem.c
index 0cd8267..bd339e2 100644
--- a/drivers/char/diag/diagmem.c
+++ b/drivers/char/diag/diagmem.c
@@ -45,6 +45,15 @@
 								 GFP_ATOMIC);
 			}
 		}
+	} else if (pool_type == POOL_TYPE_USER) {
+		if (driver->diag_user_pool) {
+			if (driver->count_user_pool < driver->poolsize_user) {
+				atomic_add(1,
+					(atomic_t *)&driver->count_user_pool);
+				buf = mempool_alloc(driver->diag_user_pool,
+					GFP_ATOMIC);
+			}
+		}
 	} else if (pool_type == POOL_TYPE_WRITE_STRUCT) {
 		if (driver->diag_write_struct_pool) {
 			if (driver->count_write_struct_pool <
@@ -98,8 +107,9 @@
 			mempool_destroy(driver->diagpool);
 			driver->diagpool = NULL;
 		} else if (driver->ref_count == 0 && pool_type ==
-							POOL_TYPE_ALL)
-			printk(KERN_ALERT "Unable to destroy COPY mempool");
+							POOL_TYPE_ALL) {
+			pr_err("diag: Unable to destroy COPY mempool");
+		}
 	}
 
 	if (driver->diag_hdlc_pool) {
@@ -107,8 +117,19 @@
 			mempool_destroy(driver->diag_hdlc_pool);
 			driver->diag_hdlc_pool = NULL;
 		} else if (driver->ref_count == 0 && pool_type ==
-							POOL_TYPE_ALL)
-			printk(KERN_ALERT "Unable to destroy HDLC mempool");
+							POOL_TYPE_ALL) {
+			pr_err("diag: Unable to destroy HDLC mempool");
+		}
+	}
+
+	if (driver->diag_user_pool) {
+		if (driver->count_user_pool == 0 && driver->ref_count == 0) {
+			mempool_destroy(driver->diag_user_pool);
+			driver->diag_user_pool = NULL;
+		} else if (driver->ref_count == 0 && pool_type ==
+							POOL_TYPE_ALL) {
+			pr_err("diag: Unable to destroy USER mempool");
+		}
 	}
 
 	if (driver->diag_write_struct_pool) {
@@ -119,8 +140,9 @@
 			mempool_destroy(driver->diag_write_struct_pool);
 			driver->diag_write_struct_pool = NULL;
 		} else if (driver->ref_count == 0 && pool_type ==
-								POOL_TYPE_ALL)
-			printk(KERN_ALERT "Unable to destroy STRUCT mempool");
+							POOL_TYPE_ALL) {
+			pr_err("diag: Unable to destroy STRUCT mempool");
+		}
 	}
 #ifdef CONFIG_DIAGFWD_BRIDGE_CODE
 	for (index = 0; index < MAX_HSIC_CH; index++) {
@@ -163,16 +185,25 @@
 			mempool_free(buf, driver->diagpool);
 			atomic_add(-1, (atomic_t *)&driver->count);
 		} else
-			pr_err("diag: Attempt to free up DIAG driver "
-	       "mempool memory which is already free %d", driver->count);
+			pr_err("diag: Attempt to free up DIAG driver mempool memory which is already free %d",
+							driver->count);
 	} else if (pool_type == POOL_TYPE_HDLC) {
 		if (driver->diag_hdlc_pool != NULL &&
 			 driver->count_hdlc_pool > 0) {
 			mempool_free(buf, driver->diag_hdlc_pool);
 			atomic_add(-1, (atomic_t *)&driver->count_hdlc_pool);
 		} else
-			pr_err("diag: Attempt to free up DIAG driver "
-	"HDLC mempool which is already free %d ", driver->count_hdlc_pool);
+			pr_err("diag: Attempt to free up DIAG driver HDLC mempool which is already free %d ",
+						driver->count_hdlc_pool);
+	} else if (pool_type == POOL_TYPE_USER) {
+		if (driver->diag_user_pool != NULL &&
+			driver->count_user_pool > 0) {
+			mempool_free(buf, driver->diag_user_pool);
+			atomic_add(-1, (atomic_t *)&driver->count_user_pool);
+		} else {
+			pr_err("diag: Attempt to free up DIAG driver USER mempool which is already free %d ",
+						driver->count_user_pool);
+		}
 	} else if (pool_type == POOL_TYPE_WRITE_STRUCT) {
 		if (driver->diag_write_struct_pool != NULL &&
 			 driver->count_write_struct_pool > 0) {
@@ -180,9 +211,8 @@
 			atomic_add(-1,
 				 (atomic_t *)&driver->count_write_struct_pool);
 		} else
-			pr_err("diag: Attempt to free up DIAG driver "
-			   "USB structure mempool which is already free %d ",
-				    driver->count_write_struct_pool);
+			pr_err("diag: Attempt to free up DIAG driver USB structure mempool which is already free %d ",
+					driver->count_write_struct_pool);
 #ifdef CONFIG_DIAGFWD_BRIDGE_CODE
 	} else if (pool_type == POOL_TYPE_HSIC ||
 				pool_type == POOL_TYPE_HSIC_2) {
@@ -229,18 +259,25 @@
 		driver->diag_hdlc_pool = mempool_create_kmalloc_pool(
 				driver->poolsize_hdlc, driver->itemsize_hdlc);
 
+	if (driver->count_user_pool == 0)
+		driver->diag_user_pool = mempool_create_kmalloc_pool(
+				driver->poolsize_user, driver->itemsize_user);
+
 	if (driver->count_write_struct_pool == 0)
 		driver->diag_write_struct_pool = mempool_create_kmalloc_pool(
 		driver->poolsize_write_struct, driver->itemsize_write_struct);
 
 	if (!driver->diagpool)
-		printk(KERN_INFO "Cannot allocate diag mempool\n");
+		pr_err("diag: Cannot allocate diag mempool\n");
 
 	if (!driver->diag_hdlc_pool)
-		printk(KERN_INFO "Cannot allocate diag HDLC mempool\n");
+		pr_err("diag: Cannot allocate diag HDLC mempool\n");
+
+	if (!driver->diag_user_pool)
+		pr_err("diag: Cannot allocate diag USER mempool\n");
 
 	if (!driver->diag_write_struct_pool)
-		printk(KERN_INFO "Cannot allocate diag USB struct mempool\n");
+		pr_err("diag: Cannot allocate diag USB struct mempool\n");
 }
 
 #ifdef CONFIG_DIAGFWD_BRIDGE_CODE
diff --git a/drivers/coresight/coresight-etm.c b/drivers/coresight/coresight-etm.c
index 2777769..5a5c0cf 100644
--- a/drivers/coresight/coresight-etm.c
+++ b/drivers/coresight/coresight-etm.c
@@ -276,23 +276,32 @@
 }
 
 /*
- * Memory mapped writes to clear os lock are not supported on Krait v1, v2
- * and OS lock must be unlocked before any memory mapped access, otherwise
- * memory mapped reads/writes will be invalid.
+ * Unlock OS lock to allow memory mapped access on Krait and in general
+ * so that ETMSR[1] can be polled while clearing the ETMCR[10] prog bit
+ * since ETMSR[1] is set when prog bit is set or OS lock is set.
  */
 static void etm_os_unlock(void *info)
 {
 	struct etm_drvdata *drvdata = (struct etm_drvdata *) info;
 
-	ETM_UNLOCK(drvdata);
+	/*
+	 * Memory mapped writes to clear os lock are not supported on Krait v1,
+	 * v2 and OS lock must be unlocked before any memory mapped access,
+	 * otherwise memory mapped reads/writes will be invalid.
+	 */
 	if (cpu_is_krait()) {
 		etm_writel_cp14(0x0, ETMOSLAR);
+		/* ensure os lock is unlocked before we return */
 		isb();
-	} else if (etm_os_lock_present(drvdata)) {
-		etm_writel(drvdata, 0x0, ETMOSLAR);
-		mb();
+	} else {
+		ETM_UNLOCK(drvdata);
+		if (etm_os_lock_present(drvdata)) {
+			etm_writel(drvdata, 0x0, ETMOSLAR);
+			/* ensure os lock is unlocked before we return */
+			mb();
+		}
+		ETM_LOCK(drvdata);
 	}
-	ETM_LOCK(drvdata);
 }
 
 /*
@@ -1876,11 +1885,26 @@
 			    void *hcpu)
 {
 	unsigned int cpu = (unsigned long)hcpu;
+	static bool clk_disable[NR_CPUS];
+	int ret;
 
 	if (!etmdrvdata[cpu])
 		goto out;
 
 	switch (action & (~CPU_TASKS_FROZEN)) {
+	case CPU_UP_PREPARE:
+		if (!etmdrvdata[cpu]->os_unlock) {
+			ret = clk_prepare_enable(etmdrvdata[cpu]->clk);
+			if (ret) {
+				dev_err(etmdrvdata[cpu]->dev,
+					"ETM clk enable during hotplug failed"
+					"for cpu: %d, ret: %d\n", cpu, ret);
+				return notifier_from_errno(ret);
+			}
+			clk_disable[cpu] = true;
+		}
+		break;
+
 	case CPU_STARTING:
 		spin_lock(&etmdrvdata[cpu]->spinlock);
 		if (!etmdrvdata[cpu]->os_unlock) {
@@ -1894,6 +1918,11 @@
 		break;
 
 	case CPU_ONLINE:
+		if (clk_disable[cpu]) {
+			clk_disable_unprepare(etmdrvdata[cpu]->clk);
+			clk_disable[cpu] = false;
+		}
+
 		if (etmdrvdata[cpu]->boot_enable &&
 		    !etmdrvdata[cpu]->sticky_enable)
 			coresight_enable(etmdrvdata[cpu]->csdev);
@@ -1903,6 +1932,13 @@
 			__etm_store_pcsave(etmdrvdata[cpu], 1);
 		break;
 
+	case CPU_UP_CANCELED:
+		if (clk_disable[cpu]) {
+			clk_disable_unprepare(etmdrvdata[cpu]->clk);
+			clk_disable[cpu] = false;
+		}
+		break;
+
 	case CPU_DYING:
 		spin_lock(&etmdrvdata[cpu]->spinlock);
 		if (etmdrvdata[cpu]->enable && etmdrvdata[cpu]->round_robin)
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index 2b1ad80..245272b 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -1337,19 +1337,6 @@
 	}
 };
 
-static void _aead_sps_consumer_callback(struct sps_event_notify *notify)
-{
-	struct qce_device *pce_dev = (struct qce_device *)
-		((struct sps_event_notify *)notify)->user;
-
-	pce_dev->ce_sps.notify = *notify;
-	pr_debug("sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
-			notify->event_id,
-			notify->data.transfer.iovec.addr,
-			notify->data.transfer.iovec.size,
-			notify->data.transfer.iovec.flags);
-};
-
 static void _sha_sps_producer_callback(struct sps_event_notify *notify)
 {
 	struct qce_device *pce_dev = (struct qce_device *)
@@ -1365,19 +1352,6 @@
 	_sha_complete(pce_dev);
 };
 
-static void _sha_sps_consumer_callback(struct sps_event_notify *notify)
-{
-	struct qce_device *pce_dev = (struct qce_device *)
-		((struct sps_event_notify *)notify)->user;
-
-	pce_dev->ce_sps.notify = *notify;
-	pr_debug("sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
-			notify->event_id,
-			notify->data.transfer.iovec.addr,
-			notify->data.transfer.iovec.size,
-			notify->data.transfer.iovec.flags);
-};
-
 static void _ablk_cipher_sps_producer_callback(struct sps_event_notify *notify)
 {
 	struct qce_device *pce_dev = (struct qce_device *)
@@ -1412,19 +1386,6 @@
 	}
 };
 
-static void _ablk_cipher_sps_consumer_callback(struct sps_event_notify *notify)
-{
-	struct qce_device *pce_dev = (struct qce_device *)
-		((struct sps_event_notify *)notify)->user;
-
-	pce_dev->ce_sps.notify = *notify;
-	pr_debug("sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
-			notify->event_id,
-			notify->data.transfer.iovec.addr,
-			notify->data.transfer.iovec.size,
-			notify->data.transfer.iovec.flags);
-};
-
 static void qce_add_cmd_element(struct qce_device *pdev,
 			struct sps_command_element **cmd_ptr, u32 addr,
 			u32 data, struct sps_command_element **populate)
@@ -2371,16 +2332,6 @@
 		pr_err("Producer callback registration failed rc = %d\n", rc);
 		goto bad;
 	}
-	/* Register callback event for EOT (End of transfer) event. */
-	pce_dev->ce_sps.consumer.event.callback = _aead_sps_consumer_callback;
-	pce_dev->ce_sps.consumer.event.options = SPS_O_DESC_DONE;
-	rc = sps_register_event(pce_dev->ce_sps.consumer.pipe,
-					&pce_dev->ce_sps.consumer.event);
-	if (rc) {
-		pr_err("Consumer callback registration failed rc = %d\n", rc);
-		goto bad;
-	}
-
 	_qce_sps_iovec_count_init(pce_dev);
 
 	_qce_sps_add_cmd(pce_dev, SPS_IOVEC_FLAG_LOCK, cmdlistinfo,
@@ -2539,17 +2490,6 @@
 		pr_err("Producer callback registration failed rc = %d\n", rc);
 		goto bad;
 	}
-	/* Register callback event for EOT (End of transfer) event. */
-	pce_dev->ce_sps.consumer.event.callback =
-			_ablk_cipher_sps_consumer_callback;
-	pce_dev->ce_sps.consumer.event.options = SPS_O_DESC_DONE;
-	rc = sps_register_event(pce_dev->ce_sps.consumer.pipe,
-					&pce_dev->ce_sps.consumer.event);
-	if (rc) {
-		pr_err("Consumer callback registration failed rc = %d\n", rc);
-		goto bad;
-	}
-
 	_qce_sps_iovec_count_init(pce_dev);
 
 	_qce_sps_add_cmd(pce_dev, SPS_IOVEC_FLAG_LOCK, cmdlistinfo,
@@ -2626,17 +2566,6 @@
 		pr_err("Producer callback registration failed rc = %d\n", rc);
 		goto bad;
 	}
-
-	/* Register callback event for EOT (End of transfer) event. */
-	pce_dev->ce_sps.consumer.event.callback = _sha_sps_consumer_callback;
-	pce_dev->ce_sps.consumer.event.options = SPS_O_DESC_DONE;
-	rc = sps_register_event(pce_dev->ce_sps.consumer.pipe,
-					&pce_dev->ce_sps.consumer.event);
-	if (rc) {
-		pr_err("Consumer callback registration failed rc = %d\n", rc);
-		goto bad;
-	}
-
 	_qce_sps_iovec_count_init(pce_dev);
 
 	_qce_sps_add_cmd(pce_dev, SPS_IOVEC_FLAG_LOCK, cmdlistinfo,
diff --git a/drivers/gpu/msm/a3xx_reg.h b/drivers/gpu/msm/a3xx_reg.h
index c768bb7..5f435f3 100644
--- a/drivers/gpu/msm/a3xx_reg.h
+++ b/drivers/gpu/msm/a3xx_reg.h
@@ -179,6 +179,7 @@
 #define A3XX_CP_MEQ_ADDR 0x1DA
 #define A3XX_CP_MEQ_DATA 0x1DB
 #define A3XX_CP_PERFCOUNTER_SELECT 0x445
+#define A3XX_CP_WFI_PEND_CTR 0x01F5
 #define A3XX_CP_HW_FAULT  0x45C
 #define A3XX_CP_AHB_FAULT 0x54D
 #define A3XX_CP_PROTECT_CTRL 0x45E
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 439ecdc..9a2e901 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -30,7 +30,6 @@
 #include "kgsl_cffdump.h"
 #include "kgsl_sharedmem.h"
 #include "kgsl_iommu.h"
-#include "kgsl_trace.h"
 
 #include "adreno.h"
 #include "adreno_pm4types.h"
@@ -607,41 +606,15 @@
 	return result;
 }
 
-static void adreno_iommu_setstate(struct kgsl_device *device,
-					unsigned int context_id,
-					uint32_t flags)
+static unsigned int _adreno_iommu_setstate_v0(struct kgsl_device *device,
+					unsigned int *cmds_orig,
+					unsigned int pt_val,
+					int num_iommu_units, uint32_t flags)
 {
-	unsigned int pt_val, reg_pt_val;
-	unsigned int link[230];
-	unsigned int *cmds = &link[0];
-	int sizedwords = 0;
+	unsigned int reg_pt_val;
+	unsigned int *cmds = cmds_orig;
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
-	int num_iommu_units, i;
-	struct kgsl_context *context;
-	struct adreno_context *adreno_ctx = NULL;
-
-	/*
-	 * If we're idle and we don't need to use the GPU to save context
-	 * state, use the CPU instead of the GPU to reprogram the
-	 * iommu for simplicity's sake.
-	 */
-	 if (!adreno_dev->drawctxt_active || device->ftbl->isidle(device))
-		return kgsl_mmu_device_setstate(&device->mmu, flags);
-
-	num_iommu_units = kgsl_mmu_get_num_iommu_units(&device->mmu);
-
-	context = idr_find(&device->context_idr, context_id);
-	if (context == NULL)
-		return;
-	adreno_ctx = context->devctxt;
-
-	if (kgsl_mmu_enable_clk(&device->mmu,
-				KGSL_IOMMU_CONTEXT_USER))
-		return;
-
-	cmds += __adreno_add_idle_indirect_cmds(cmds,
-		device->mmu.setstate_memory.gpuaddr +
-		KGSL_IOMMU_SETSTATE_NOP_OFFSET);
+	int i;
 
 	if (cpu_is_msm8960())
 		cmds += adreno_add_change_mh_phys_limit_cmds(cmds, 0xFFFFF000,
@@ -658,8 +631,6 @@
 	/* Acquire GPU-CPU sync Lock here */
 	cmds += kgsl_mmu_sync_lock(&device->mmu, cmds);
 
-	pt_val = kgsl_mmu_get_pt_base_addr(&device->mmu,
-					device->mmu.hwpagetable);
 	if (flags & KGSL_MMUFLAGS_PTUPDATE) {
 		/*
 		 * We need to perfrom the following operations for all
@@ -736,25 +707,169 @@
 
 	cmds += adreno_add_idle_cmds(adreno_dev, cmds);
 
-	sizedwords += (cmds - &link[0]);
-	if (sizedwords) {
-		/* invalidate all base pointers */
-		*cmds++ = cp_type3_packet(CP_INVALIDATE_STATE, 1);
-		*cmds++ = 0x7fff;
-		sizedwords += 2;
-		/* This returns the per context timestamp but we need to
-		 * use the global timestamp for iommu clock disablement */
-		adreno_ringbuffer_issuecmds(device, adreno_ctx,
-			KGSL_CMD_FLAGS_PMODE,
-			&link[0], sizedwords);
-		kgsl_mmu_disable_clk_on_ts(&device->mmu,
-		adreno_dev->ringbuffer.timestamp[KGSL_MEMSTORE_GLOBAL], true);
+	return cmds - cmds_orig;
+}
+
+static unsigned int _adreno_iommu_setstate_v1(struct kgsl_device *device,
+					unsigned int *cmds_orig,
+					unsigned int pt_val,
+					int num_iommu_units, uint32_t flags)
+{
+	unsigned int reg_pt_val;
+	unsigned int *cmds = cmds_orig;
+	int i;
+	unsigned int ttbr0, tlbiall, tlbstatus, tlbsync, mmu_ctrl;
+
+	for (i = 0; i < num_iommu_units; i++) {
+		reg_pt_val = (pt_val + kgsl_mmu_get_pt_lsb(&device->mmu,
+				i, KGSL_IOMMU_CONTEXT_USER));
+		if (flags & KGSL_MMUFLAGS_PTUPDATE) {
+			mmu_ctrl = kgsl_mmu_get_reg_ahbaddr(
+				&device->mmu, i,
+				KGSL_IOMMU_CONTEXT_USER,
+				KGSL_IOMMU_IMPLDEF_MICRO_MMU_CTRL) >> 2;
+
+			ttbr0 = kgsl_mmu_get_reg_ahbaddr(&device->mmu, i,
+						KGSL_IOMMU_CONTEXT_USER,
+						KGSL_IOMMU_CTX_TTBR0) >> 2;
+
+			if (kgsl_mmu_hw_halt_supported(&device->mmu, i)) {
+				*cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
+				*cmds++ = 0;
+				/*
+				 * glue commands together until next
+				 * WAIT_FOR_ME
+				 */
+				cmds += adreno_wait_reg_eq(cmds,
+				A3XX_CP_WFI_PEND_CTR, 1, 0xFFFFFFFF, 0xF);
+
+				/* set the iommu lock bit */
+				*cmds++ = cp_type3_packet(CP_REG_RMW, 3);
+				*cmds++ = mmu_ctrl;
+				/* AND to unmask the lock bit */
+				*cmds++ =
+				 ~(KGSL_IOMMU_IMPLDEF_MICRO_MMU_CTRL_HALT);
+				/* OR to set the IOMMU lock bit */
+				*cmds++ =
+				   KGSL_IOMMU_IMPLDEF_MICRO_MMU_CTRL_HALT;
+				/* wait for smmu to lock */
+				cmds += adreno_wait_reg_eq(cmds, mmu_ctrl,
+				KGSL_IOMMU_IMPLDEF_MICRO_MMU_CTRL_IDLE,
+				KGSL_IOMMU_IMPLDEF_MICRO_MMU_CTRL_IDLE, 0xF);
+			}
+			/* set ttbr0 */
+			*cmds++ = cp_type0_packet(ttbr0, 1);
+			*cmds++ = reg_pt_val;
+			if (kgsl_mmu_hw_halt_supported(&device->mmu, i)) {
+				/* unlock the IOMMU lock */
+				*cmds++ = cp_type3_packet(CP_REG_RMW, 3);
+				*cmds++ = mmu_ctrl;
+				/* AND to unmask the lock bit */
+				*cmds++ =
+				   ~(KGSL_IOMMU_IMPLDEF_MICRO_MMU_CTRL_HALT);
+				/* OR with 0 so lock bit is unset */
+				*cmds++ = 0;
+				/* release all commands with wait_for_me */
+				*cmds++ = cp_type3_packet(CP_WAIT_FOR_ME, 1);
+				*cmds++ = 0;
+			}
+		}
+		if (flags & KGSL_MMUFLAGS_TLBFLUSH) {
+			tlbiall = kgsl_mmu_get_reg_ahbaddr(&device->mmu, i,
+						KGSL_IOMMU_CONTEXT_USER,
+						KGSL_IOMMU_CTX_TLBIALL) >> 2;
+			*cmds++ = cp_type0_packet(tlbiall, 1);
+			*cmds++ = 1;
+
+			tlbsync = kgsl_mmu_get_reg_ahbaddr(&device->mmu, i,
+						KGSL_IOMMU_CONTEXT_USER,
+						KGSL_IOMMU_CTX_TLBSYNC) >> 2;
+			*cmds++ = cp_type0_packet(tlbsync, 1);
+			*cmds++ = 0;
+
+			tlbstatus = kgsl_mmu_get_reg_ahbaddr(&device->mmu, i,
+					KGSL_IOMMU_CONTEXT_USER,
+					KGSL_IOMMU_CTX_TLBSTATUS) >> 2;
+			cmds += adreno_wait_reg_eq(cmds, tlbstatus, 0,
+					KGSL_IOMMU_CTX_TLBSTATUS_SACTIVE, 0xF);
+		}
 	}
+	return cmds - cmds_orig;
+}
+
+static void adreno_iommu_setstate(struct kgsl_device *device,
+					unsigned int context_id,
+					uint32_t flags)
+{
+	unsigned int pt_val;
+	unsigned int link[230];
+	unsigned int *cmds = &link[0];
+	int sizedwords = 0;
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	int num_iommu_units;
+	struct kgsl_context *context;
+	struct adreno_context *adreno_ctx = NULL;
+
+	if (!adreno_dev->drawctxt_active) {
+		kgsl_mmu_device_setstate(&device->mmu, flags);
+		return;
+	}
+	num_iommu_units = kgsl_mmu_get_num_iommu_units(&device->mmu);
+
+	context = idr_find(&device->context_idr, context_id);
+	if (context == NULL)
+		return;
+
+	kgsl_context_get(context);
+
+	adreno_ctx = context->devctxt;
+
+	if (kgsl_mmu_enable_clk(&device->mmu,
+				KGSL_IOMMU_CONTEXT_USER))
+		return;
+
+	pt_val = kgsl_mmu_get_pt_base_addr(&device->mmu,
+				device->mmu.hwpagetable);
+
+	cmds += __adreno_add_idle_indirect_cmds(cmds,
+		device->mmu.setstate_memory.gpuaddr +
+		KGSL_IOMMU_SETSTATE_NOP_OFFSET);
+
+	if (msm_soc_version_supports_iommu_v0())
+		cmds += _adreno_iommu_setstate_v0(device, cmds, pt_val,
+						num_iommu_units, flags);
+	else
+		cmds += _adreno_iommu_setstate_v1(device, cmds, pt_val,
+						num_iommu_units, flags);
+
+	sizedwords += (cmds - &link[0]);
+	if (sizedwords == 0) {
+		KGSL_DRV_ERR(device, "no commands generated\n");
+		BUG();
+	}
+	/* invalidate all base pointers */
+	*cmds++ = cp_type3_packet(CP_INVALIDATE_STATE, 1);
+	*cmds++ = 0x7fff;
+	sizedwords += 2;
 
 	if (sizedwords > (ARRAY_SIZE(link))) {
 		KGSL_DRV_ERR(device, "Temp command buffer overflow\n");
 		BUG();
 	}
+	/*
+	 * This returns the per context timestamp but we need to
+	 * use the global timestamp for iommu clock disablement
+	 */
+	adreno_ringbuffer_issuecmds(device, adreno_ctx, KGSL_CMD_FLAGS_PMODE,
+			&link[0], sizedwords);
+	/* timestamp based clock gating is currently unstable on iommuv1 */
+	if (msm_soc_version_supports_iommu_v0()) {
+		struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
+		kgsl_mmu_disable_clk_on_ts(&device->mmu,
+			rb->timestamp[KGSL_MEMSTORE_GLOBAL], true);
+	}
+
+	kgsl_context_put(context);
 }
 
 static void adreno_gpummu_setstate(struct kgsl_device *device,
@@ -1284,6 +1399,8 @@
 
 	data->physstart = reg_val[0];
 	data->physend = data->physstart + reg_val[1] - 1;
+	data->iommu_halt_enable = of_property_read_bool(node,
+					"qcom,iommu-enable-halt");
 
 	data->iommu_ctx_count = 0;
 
@@ -2187,6 +2304,7 @@
 		context->wait_on_invalid_ts = false;
 
 		if (!(adreno_context->flags & CTXT_FLAGS_PER_CONTEXT_TS)) {
+			ft_data->status = 1;
 			KGSL_FT_ERR(device, "Fault tolerance not supported\n");
 			goto play_good_cmds;
 		}
@@ -2221,6 +2339,7 @@
 
 	/* If long IB detected do not attempt replay of bad cmds */
 	if (long_ib) {
+		ft_data->status = 1;
 		_adreno_debug_ft_info(device, ft_data);
 		goto play_good_cmds;
 	}
@@ -2952,7 +3071,7 @@
 	if (!in_interrupt())
 		kgsl_pre_hwaccess(device);
 
-	trace_kgsl_regwrite(device, offsetwords, value);
+	kgsl_trace_regwrite(device, offsetwords, value);
 
 	kgsl_cffdump_regwrite(device->id, offsetwords << 2, value);
 	reg = (unsigned int *)(device->reg_virt + (offsetwords << 2));
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 3935cd8..fa892b9 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -507,4 +507,25 @@
 	return cmds - start;
 }
 
+/*
+ * adreno_wait_reg_eq() - Add a CP_WAIT_REG_EQ command
+ * @cmds:	Pointer to memory where commands are to be added
+ * @addr:	Regiater address to poll for
+ * @val:	Value to poll for
+ * @mask:	The value against which register value is masked
+ * @interval:	wait interval
+ */
+static inline int adreno_wait_reg_eq(unsigned int *cmds, unsigned int addr,
+					unsigned int val, unsigned int mask,
+					unsigned int interval)
+{
+	unsigned int *start = cmds;
+	*cmds++ = cp_type3_packet(CP_WAIT_REG_EQ, 4);
+	*cmds++ = addr;
+	*cmds++ = val;
+	*cmds++ = mask;
+	*cmds++ = interval;
+	return cmds - start;
+}
+
 #endif /*__ADRENO_H */
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index be5c786..a4b3121 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -2758,7 +2758,7 @@
 {
 	unsigned int in, out, bit, sel;
 
-	if (countable > 0x7f)
+	if (counter > 1 || countable > 0x7f)
 		return;
 
 	adreno_regread(device, A3XX_VBIF_PERF_CNT_EN, &in);
@@ -2767,7 +2767,7 @@
 	if (counter == 0) {
 		bit = VBIF_PERF_CNT_0;
 		sel = (sel & ~VBIF_PERF_CNT_0_SEL_MASK) | countable;
-	} else if (counter == 1) {
+	} else {
 		bit = VBIF_PERF_CNT_1;
 		sel = (sel & ~VBIF_PERF_CNT_1_SEL_MASK)
 			| (countable << VBIF_PERF_CNT_1_SEL);
@@ -2821,10 +2821,10 @@
 	unsigned int val = 0;
 	struct a3xx_perfcounter_register *reg;
 
-	if (group > ARRAY_SIZE(a3xx_perfcounter_reglist))
+	if (group >= ARRAY_SIZE(a3xx_perfcounter_reglist))
 		return;
 
-	if (counter > a3xx_perfcounter_reglist[group].count)
+	if (counter >= a3xx_perfcounter_reglist[group].count)
 		return;
 
 	/* Special cases */
@@ -2858,7 +2858,10 @@
 	unsigned int lo = 0, hi = 0;
 	unsigned int val;
 
-	if (group > ARRAY_SIZE(a3xx_perfcounter_reglist))
+	if (group >= ARRAY_SIZE(a3xx_perfcounter_reglist))
+		return 0;
+
+	if (counter >= a3xx_perfcounter_reglist[group].count)
 		return 0;
 
 	reg = &(a3xx_perfcounter_reglist[group].regs[counter]);
diff --git a/drivers/gpu/msm/adreno_postmortem.c b/drivers/gpu/msm/adreno_postmortem.c
index 5396196..2249907 100644
--- a/drivers/gpu/msm/adreno_postmortem.c
+++ b/drivers/gpu/msm/adreno_postmortem.c
@@ -69,6 +69,8 @@
 	{CP_SET_PROTECTED_MODE,	"ST_PRT_M"},
 	{CP_SET_SHADER_BASES,		"ST_SHD_B"},
 	{CP_WAIT_FOR_IDLE,		"WAIT4IDL"},
+	{CP_WAIT_FOR_ME,		"WAIT4ME"},
+	{CP_WAIT_REG_EQ,		"WAITRGEQ"},
 };
 
 static const struct pm_id_name pm3_nop_values[] = {
@@ -854,7 +856,12 @@
 			(num_iommu_units && this_cmd ==
 			kgsl_mmu_get_reg_gpuaddr(&device->mmu, 0,
 						KGSL_IOMMU_CONTEXT_USER,
-						KGSL_IOMMU_CTX_TTBR0))) {
+						KGSL_IOMMU_CTX_TTBR0)) ||
+			(num_iommu_units && this_cmd == cp_type0_packet(
+						kgsl_mmu_get_reg_ahbaddr(
+						&device->mmu, 0,
+						KGSL_IOMMU_CONTEXT_USER,
+						KGSL_IOMMU_CTX_TTBR0), 1))) {
 			KGSL_LOG_DUMP(device, "Current pagetable: %x\t"
 				"pagetable base: %x\n",
 				kgsl_mmu_get_ptname_from_ptbase(&device->mmu,
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index 628d38c..479f9b8 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -18,7 +18,6 @@
 #include "kgsl.h"
 #include "kgsl_sharedmem.h"
 #include "kgsl_cffdump.h"
-#include "kgsl_trace.h"
 
 #include "adreno.h"
 #include "adreno_pm4types.h"
@@ -1123,8 +1122,9 @@
 		ret = 0;
 
 done:
-	trace_kgsl_issueibcmds(device, context->id, ibdesc, numibs,
-		*timestamp, flags, ret, drawctxt->type);
+	kgsl_trace_issueibcmds(device, context ? context->id : 0, ibdesc,
+		numibs, *timestamp, flags, ret,
+		drawctxt ? drawctxt->type : 0);
 
 	kfree(link);
 	return ret;
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 08dd886..5275267 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -53,6 +53,46 @@
 
 static struct ion_client *kgsl_ion_client;
 
+/**
+ * kgsl_trace_issueibcmds() - Call trace_issueibcmds by proxy
+ * device: KGSL device
+ * id: ID of the context submitting the command
+ * ibdesc: Pointer to the list of IB descriptors
+ * numib: Number of IBs in the list
+ * timestamp: Timestamp assigned to the command batch
+ * flags: Flags sent by the user
+ * result: Result of the submission attempt
+ * type: Type of context issuing the command
+ *
+ * Wrap the issueibcmds ftrace hook into a function that can be called from the
+ * GPU specific modules.
+ */
+void kgsl_trace_issueibcmds(struct kgsl_device *device, int id,
+		struct kgsl_ibdesc *ibdesc, int numibs,
+		unsigned int timestamp, unsigned int flags,
+		int result, unsigned int type)
+{
+	trace_kgsl_issueibcmds(device, id, ibdesc, numibs,
+		timestamp, flags, result, type);
+}
+EXPORT_SYMBOL(kgsl_trace_issueibcmds);
+
+/**
+ * kgsl_trace_regwrite - call regwrite ftrace function by proxy
+ * device: KGSL device
+ * offset: dword offset of the register being written
+ * value: Value of the register being written
+ *
+ * Wrap the regwrite ftrace hook into a function that can be called from the
+ * GPU specific modules.
+ */
+void kgsl_trace_regwrite(struct kgsl_device *device, unsigned int offset,
+		unsigned int value)
+{
+	trace_kgsl_regwrite(device, offset, value);
+}
+EXPORT_SYMBOL(kgsl_trace_regwrite);
+
 int kgsl_memfree_hist_init(void)
 {
 	void *base;
@@ -2600,12 +2640,18 @@
 	return ret;
 }
 
+static inline bool
+mmap_range_valid(unsigned long addr, unsigned long len)
+{
+	return (addr + len) > addr && (addr + len) < TASK_SIZE;
+}
+
 static unsigned long
 kgsl_get_unmapped_area(struct file *file, unsigned long addr,
 			unsigned long len, unsigned long pgoff,
 			unsigned long flags)
 {
-	unsigned long ret = 0;
+	unsigned long ret = 0, orig_len = len;
 	unsigned long vma_offset = pgoff << PAGE_SHIFT;
 	struct kgsl_device_private *dev_priv = file->private_data;
 	struct kgsl_process_private *private = dev_priv->process_priv;
@@ -2650,10 +2696,26 @@
 
 	if (align)
 		len += 1 << align;
+
+	if (!mmap_range_valid(addr, len))
+		addr = 0;
 	do {
 		ret = get_unmapped_area(NULL, addr, len, pgoff, flags);
-		if (IS_ERR_VALUE(ret))
+		if (IS_ERR_VALUE(ret)) {
+			/*
+			 * If we are really fragmented, there may not be room
+			 * for the alignment padding, so try again without it.
+			 */
+			if (!retry && (ret == (unsigned long)-ENOMEM)
+				&& (align > PAGE_SHIFT)) {
+				align = PAGE_SHIFT;
+				addr = 0;
+				len = orig_len;
+				retry = 1;
+				continue;
+			}
 			break;
+		}
 		if (align)
 			ret = ALIGN(ret, (1 << align));
 
@@ -2675,13 +2737,13 @@
 		 * the whole address space at least once by wrapping
 		 * back around once.
 		 */
-		if (!retry && (addr + len >= TASK_SIZE)) {
+		if (!retry && !mmap_range_valid(addr, len)) {
 			addr = 0;
 			retry = 1;
 		} else {
 			ret = -EBUSY;
 		}
-	} while (addr + len < TASK_SIZE);
+	} while (mmap_range_valid(addr, len));
 
 	if (IS_ERR_VALUE(ret))
 		KGSL_MEM_INFO(device,
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index c568db5..abe9100 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -226,6 +226,14 @@
 void kgsl_early_suspend_driver(struct early_suspend *h);
 void kgsl_late_resume_driver(struct early_suspend *h);
 
+void kgsl_trace_regwrite(struct kgsl_device *device, unsigned int offset,
+		unsigned int value);
+
+void kgsl_trace_issueibcmds(struct kgsl_device *device, int id,
+		struct kgsl_ibdesc *ibdesc, int numibs,
+		unsigned int timestamp, unsigned int flags,
+		int result, unsigned int type);
+
 #ifdef CONFIG_MSM_KGSL_DRM
 extern int kgsl_drm_init(struct platform_device *dev);
 extern void kgsl_drm_exit(void);
diff --git a/drivers/gpu/msm/kgsl_gpummu.c b/drivers/gpu/msm/kgsl_gpummu.c
index 5cc0dff..8d071d1 100644
--- a/drivers/gpu/msm/kgsl_gpummu.c
+++ b/drivers/gpu/msm/kgsl_gpummu.c
@@ -759,7 +759,9 @@
 	.mmu_disable_clk_on_ts = NULL,
 	.mmu_get_pt_lsb = NULL,
 	.mmu_get_reg_gpuaddr = NULL,
+	.mmu_get_reg_ahbaddr = NULL,
 	.mmu_get_num_iommu_units = kgsl_gpummu_get_num_iommu_units,
+	.mmu_hw_halt_supported = NULL,
 };
 
 struct kgsl_mmu_pt_ops gpummu_pt_ops = {
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 739fcff..15f35c9 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -37,31 +37,51 @@
 
 
 static struct kgsl_iommu_register_list kgsl_iommuv0_reg[KGSL_IOMMU_REG_MAX] = {
-	{ 0, 0, 0 },				/* GLOBAL_BASE */
-	{ 0x10, 0x0003FFFF, 14 },		/* TTBR0 */
-	{ 0x14, 0x0003FFFF, 14 },		/* TTBR1 */
-	{ 0x20, 0, 0 },				/* FSR */
-	{ 0x800, 0, 0 },			/* TLBIALL */
-	{ 0x820, 0, 0 },			/* RESUME */
-	{ 0x03C, 0, 0 },			/* TLBLKCR */
-	{ 0x818, 0, 0 },			/* V2PUR */
-	{ 0x2C, 0, 0 },                         /* FSYNR0 */
-	{ 0x2C, 0, 0 },                         /* FSYNR0 */
+	{ 0, 0 },			/* GLOBAL_BASE */
+	{ 0x10, 1 },			/* TTBR0 */
+	{ 0x14, 1 },			/* TTBR1 */
+	{ 0x20, 1 },			/* FSR */
+	{ 0x800, 1 },			/* TLBIALL */
+	{ 0x820, 1 },			/* RESUME */
+	{ 0x03C, 1 },			/* TLBLKCR */
+	{ 0x818, 1 },			/* V2PUR */
+	{ 0x2C, 1 },			/* FSYNR0 */
+	{ 0x2C, 1 },			/* FSYNR0 */
+	{ 0, 0 },			/* TLBSYNC, not in v0 */
+	{ 0, 0 },			/* TLBSTATUS, not in v0 */
+	{ 0, 0 }			/* IMPLDEF_MICRO_MMU_CRTL, not in v0 */
 };
 
 static struct kgsl_iommu_register_list kgsl_iommuv1_reg[KGSL_IOMMU_REG_MAX] = {
-	{ 0, 0, 0 },				/* GLOBAL_BASE */
-	{ 0x20, 0x00FFFFFF, 14 },		/* TTBR0 */
-	{ 0x28, 0x00FFFFFF, 14 },		/* TTBR1 */
-	{ 0x58, 0, 0 },				/* FSR */
-	{ 0x618, 0, 0 },			/* TLBIALL */
-	{ 0x008, 0, 0 },			/* RESUME */
-	{ 0, 0, 0 },				/* TLBLKCR */
-	{ 0, 0, 0 },				/* V2PUR */
-	{ 0x68, 0, 0 },				/* FSYNR0 */
-	{ 0x6C, 0, 0 }				/* FSYNR1 */
+	{ 0, 0 },			/* GLOBAL_BASE */
+	{ 0x20, 1 },			/* TTBR0 */
+	{ 0x28, 1 },			/* TTBR1 */
+	{ 0x58, 1 },			/* FSR */
+	{ 0x618, 1 },			/* TLBIALL */
+	{ 0x008, 1 },			/* RESUME */
+	{ 0, 0 },			/* TLBLKCR not in V1 */
+	{ 0, 0 },			/* V2PUR not in V1 */
+	{ 0x68, 0 },			/* FSYNR0 */
+	{ 0x6C, 0 },			/* FSYNR1 */
+	{ 0x7F0, 1 },			/* TLBSYNC */
+	{ 0x7F4, 1 },			/* TLBSTATUS */
+	{ 0x2000, 0 }			/* IMPLDEF_MICRO_MMU_CRTL */
 };
 
+static struct iommu_access_ops *iommu_access_ops;
+
+static void _iommu_lock(void)
+{
+	if (iommu_access_ops && iommu_access_ops->iommu_lock_acquire)
+		iommu_access_ops->iommu_lock_acquire();
+}
+
+static void _iommu_unlock(void)
+{
+	if (iommu_access_ops && iommu_access_ops->iommu_lock_release)
+		iommu_access_ops->iommu_lock_release();
+}
+
 struct remote_iommu_petersons_spinlock kgsl_iommu_sync_lock_vars;
 
 static int get_iommu_unit(struct device *dev, struct kgsl_mmu **mmu_out,
@@ -582,18 +602,13 @@
 				struct kgsl_pagetable *pt,
 				unsigned int pt_base)
 {
-	struct kgsl_iommu *iommu = mmu->priv;
 	struct kgsl_iommu_pt *iommu_pt = pt ? pt->priv : NULL;
 	unsigned int domain_ptbase = iommu_pt ?
 				iommu_get_pt_base_addr(iommu_pt->domain) : 0;
 	/* Only compare the valid address bits of the pt_base */
-	domain_ptbase &=
-		(iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
-		iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
+	domain_ptbase &= KGSL_IOMMU_CTX_TTBR0_ADDR_MASK;
 
-	pt_base &=
-		(iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
-		iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
+	pt_base &= KGSL_IOMMU_CTX_TTBR0_ADDR_MASK;
 
 	return domain_ptbase && pt_base &&
 		(domain_ptbase == pt_base);
@@ -649,15 +664,18 @@
 	domain_num = msm_register_domain(&kgsl_layout);
 	if (domain_num >= 0) {
 		iommu_pt->domain = msm_get_iommu_domain(domain_num);
-		iommu_set_fault_handler(iommu_pt->domain,
-			kgsl_iommu_fault_handler, NULL);
-	} else {
-		KGSL_CORE_ERR("Failed to create iommu domain\n");
-		kfree(iommu_pt);
-		return NULL;
+
+		if (iommu_pt->domain) {
+			iommu_set_fault_handler(iommu_pt->domain,
+				kgsl_iommu_fault_handler, NULL);
+
+			return iommu_pt;
+		}
 	}
 
-	return iommu_pt;
+	KGSL_CORE_ERR("Failed to create iommu domain\n");
+	kfree(iommu_pt);
+	return NULL;
 }
 
 /*
@@ -889,11 +907,14 @@
 	if (iommu->sync_lock_initialized)
 		return status;
 
-	/* Get the physical address of the Lock variables */
-	lock_phy_addr = (msm_iommu_lock_initialize()
+	iommu_access_ops = get_iommu_access_ops_v0();
+
+	if (iommu_access_ops && iommu_access_ops->iommu_lock_initialize)
+		lock_phy_addr = (iommu_access_ops->iommu_lock_initialize()
 			- MSM_SHARED_RAM_BASE + msm_shared_ram_phys);
 
 	if (!lock_phy_addr) {
+		iommu_access_ops = NULL;
 		KGSL_DRV_ERR(mmu->device,
 				"GPU CPU sync lock is not supported by kernel\n");
 		return -ENXIO;
@@ -911,8 +932,10 @@
 				 iommu->sync_lock_desc.physaddr,
 				 iommu->sync_lock_desc.size);
 
-	if (status)
+	if (status) {
+		iommu_access_ops = NULL;
 		return status;
+	}
 
 	/* Flag Sync Lock is Initialized  */
 	iommu->sync_lock_initialized = 1;
@@ -1092,6 +1115,9 @@
 				iommu_unit->reg_map.size);
 		if (ret)
 			goto err;
+
+		iommu_unit->iommu_halt_enable = data.iommu_halt_enable;
+		iommu_unit->ahb_base = data.physstart - mmu->device->reg_phys;
 	}
 	iommu->unit_count = pdata_dev->iommu_count;
 	return ret;
@@ -1118,11 +1144,9 @@
 static unsigned int kgsl_iommu_get_pt_base_addr(struct kgsl_mmu *mmu,
 						struct kgsl_pagetable *pt)
 {
-	struct kgsl_iommu *iommu = mmu->priv;
 	struct kgsl_iommu_pt *iommu_pt = pt->priv;
 	return iommu_get_pt_base_addr(iommu_pt->domain) &
-			(iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
-			iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
+			KGSL_IOMMU_CTX_TTBR0_ADDR_MASK;
 }
 
 /*
@@ -1241,6 +1265,30 @@
 }
 
 
+/*
+ * kgsl_iommu_get_reg_ahbaddr - Returns the ahb address of the register
+ * @mmu - Pointer to mmu structure
+ * @iommu_unit - The iommu unit for which base address is requested
+ * @ctx_id - The context ID of the IOMMU ctx
+ * @reg - The register for which address is required
+ *
+ * Return - The address of register which can be used in type0 packet
+ */
+static unsigned int kgsl_iommu_get_reg_ahbaddr(struct kgsl_mmu *mmu,
+					int iommu_unit, int ctx_id,
+					enum kgsl_iommu_reg_map reg)
+{
+	struct kgsl_iommu *iommu = mmu->priv;
+
+	if (iommu->iommu_reg_list[reg].ctx_reg)
+		return iommu->iommu_units[iommu_unit].ahb_base +
+			iommu->iommu_reg_list[reg].reg_offset +
+			(ctx_id << KGSL_IOMMU_CTX_SHIFT) + iommu->ctx_offset;
+	else
+		return iommu->iommu_units[iommu_unit].ahb_base +
+			iommu->iommu_reg_list[reg].reg_offset;
+}
+
 static int kgsl_iommu_init(struct kgsl_mmu *mmu)
 {
 	/*
@@ -1265,13 +1313,15 @@
 	status = kgsl_set_register_map(mmu);
 	if (status)
 		goto done;
-	status = kgsl_iommu_init_sync_lock(mmu);
-	if (status)
-		goto done;
 
-	/* We presently do not support per-process for IOMMU-v1 */
+	/*
+	 * IOMMU-v1 requires hardware halt support to do in stream
+	 * pagetable switching. This check assumes that if there are
+	 * multiple units, they will be matching hardware.
+	 */
 	mmu->pt_per_process = KGSL_MMU_USE_PER_PROCESS_PT &&
-				msm_soc_version_supports_iommu_v0();
+				(msm_soc_version_supports_iommu_v0() ||
+				 iommu->iommu_units[0].iommu_halt_enable);
 
 	/*
 	 * For IOMMU per-process pagetables, the allocatable range
@@ -1294,6 +1344,9 @@
 		mmu->use_cpu_map = false;
 	}
 
+	status = kgsl_iommu_init_sync_lock(mmu);
+	if (status)
+		goto done;
 
 	iommu->iommu_reg_list = kgsl_iommuv0_reg;
 	iommu->ctx_offset = KGSL_IOMMU_CTX_OFFSET_V0;
@@ -1535,7 +1588,7 @@
 	 * changing pagetables we can use this lsb value of the pagetable w/o
 	 * having to read it again
 	 */
-	msm_iommu_lock();
+	_iommu_lock();
 	for (i = 0; i < iommu->unit_count; i++) {
 		struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
 		for (j = 0; j < iommu_unit->dev_count; j++) {
@@ -1547,7 +1600,7 @@
 		}
 	}
 	kgsl_iommu_lock_rb_in_tlb(mmu);
-	msm_iommu_unlock();
+	_iommu_unlock();
 
 	/* For complete CFF */
 	kgsl_cffdump_setmem(mmu->setstate_memory.gpuaddr +
@@ -1667,12 +1720,12 @@
 				for (j = 0; j < iommu_unit->dev_count; j++) {
 					if (iommu_unit->dev[j].fault) {
 						kgsl_iommu_enable_clk(mmu, j);
-						msm_iommu_lock();
+						_iommu_lock();
 						KGSL_IOMMU_SET_CTX_REG(iommu,
 						iommu_unit,
 						iommu_unit->dev[j].ctx_id,
 						RESUME, 1);
-						msm_iommu_unlock();
+						_iommu_unlock();
 						iommu_unit->dev[j].fault = 0;
 					}
 				}
@@ -1732,9 +1785,7 @@
 					KGSL_IOMMU_CONTEXT_USER,
 					TTBR0);
 	kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
-	return pt_base &
-		(iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
-		iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
+	return pt_base & KGSL_IOMMU_CTX_TTBR0_ADDR_MASK;
 }
 
 /*
@@ -1764,15 +1815,14 @@
 		return;
 	}
 	/* Mask off the lsb of the pt base address since lsb will not change */
-	pt_base &= (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
-			iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
+	pt_base &= KGSL_IOMMU_CTX_TTBR0_ADDR_MASK;
 
 	/* For v0 SMMU GPU needs to be idle for tlb invalidate as well */
 	if (msm_soc_version_supports_iommu_v0())
 		kgsl_idle(mmu->device);
 
 	/* Acquire GPU-CPU sync Lock here */
-	msm_iommu_lock();
+	_iommu_lock();
 
 	if (flags & KGSL_MMUFLAGS_PTUPDATE) {
 		if (!msm_soc_version_supports_iommu_v0())
@@ -1795,15 +1845,42 @@
 	}
 	/* Flush tlb */
 	if (flags & KGSL_MMUFLAGS_TLBFLUSH) {
+		unsigned long wait_for_flush;
 		for (i = 0; i < iommu->unit_count; i++) {
 			KGSL_IOMMU_SET_CTX_REG(iommu, (&iommu->iommu_units[i]),
 				KGSL_IOMMU_CONTEXT_USER, TLBIALL, 1);
 			mb();
+			/*
+			 * Wait for flush to complete by polling the flush
+			 * status bit of TLBSTATUS register for not more than
+			 * 2 s. After 2s just exit, at that point the SMMU h/w
+			 * may be stuck and will eventually cause GPU to hang
+			 * or bring the system down.
+			 */
+			if (!msm_soc_version_supports_iommu_v0()) {
+				wait_for_flush = jiffies +
+						msecs_to_jiffies(2000);
+				KGSL_IOMMU_SET_CTX_REG(iommu,
+					(&iommu->iommu_units[i]),
+					KGSL_IOMMU_CONTEXT_USER, TLBSYNC, 0);
+				while (KGSL_IOMMU_GET_CTX_REG(iommu,
+					(&iommu->iommu_units[i]),
+					KGSL_IOMMU_CONTEXT_USER, TLBSTATUS) &
+					(KGSL_IOMMU_CTX_TLBSTATUS_SACTIVE)) {
+					if (time_after(jiffies,
+						wait_for_flush)) {
+						KGSL_DRV_ERR(mmu->device,
+						"Wait limit reached for IOMMU tlb flush\n");
+						break;
+					}
+					cpu_relax();
+				}
+			}
 		}
 	}
 
 	/* Release GPU-CPU sync Lock here */
-	msm_iommu_unlock();
+	_iommu_unlock();
 
 	/* Disable smmu clock */
 	kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
@@ -1816,8 +1893,7 @@
  * @ctx_id - The context ID of the IOMMU ctx
  * @reg - The register for which address is required
  *
- * Return - The number of iommu units which is also the number of register
- * mapped descriptor arrays which the out parameter will have
+ * Return - The gpu address of register which can be used in type3 packet
  */
 static unsigned int kgsl_iommu_get_reg_gpuaddr(struct kgsl_mmu *mmu,
 					int iommu_unit, int ctx_id, int reg)
@@ -1826,10 +1902,25 @@
 
 	if (KGSL_IOMMU_GLOBAL_BASE == reg)
 		return iommu->iommu_units[iommu_unit].reg_map.gpuaddr;
-	else
+
+	if (iommu->iommu_reg_list[reg].ctx_reg)
 		return iommu->iommu_units[iommu_unit].reg_map.gpuaddr +
 			iommu->iommu_reg_list[reg].reg_offset +
 			(ctx_id << KGSL_IOMMU_CTX_SHIFT) + iommu->ctx_offset;
+	else
+		return iommu->iommu_units[iommu_unit].reg_map.gpuaddr +
+			iommu->iommu_reg_list[reg].reg_offset;
+}
+/*
+ * kgsl_iommu_hw_halt_supported - Returns whether IOMMU halt command is
+ * supported
+ * @mmu - Pointer to mmu structure
+ * @iommu_unit - The iommu unit for which the property is requested
+ */
+static int kgsl_iommu_hw_halt_supported(struct kgsl_mmu *mmu, int iommu_unit)
+{
+	struct kgsl_iommu *iommu = mmu->priv;
+	return iommu->iommu_units[iommu_unit].iommu_halt_enable;
 }
 
 static int kgsl_iommu_get_num_iommu_units(struct kgsl_mmu *mmu)
@@ -1851,9 +1942,11 @@
 	.mmu_disable_clk_on_ts = kgsl_iommu_disable_clk_on_ts,
 	.mmu_get_pt_lsb = kgsl_iommu_get_pt_lsb,
 	.mmu_get_reg_gpuaddr = kgsl_iommu_get_reg_gpuaddr,
+	.mmu_get_reg_ahbaddr = kgsl_iommu_get_reg_ahbaddr,
 	.mmu_get_num_iommu_units = kgsl_iommu_get_num_iommu_units,
 	.mmu_pt_equal = kgsl_iommu_pt_equal,
 	.mmu_get_pt_base_addr = kgsl_iommu_get_pt_base_addr,
+	.mmu_hw_halt_supported = kgsl_iommu_hw_halt_supported,
 	/* These callbacks will be set on some chipsets */
 	.mmu_setup_pt = NULL,
 	.mmu_cleanup_pt = NULL,
diff --git a/drivers/gpu/msm/kgsl_iommu.h b/drivers/gpu/msm/kgsl_iommu.h
index c09bc4b..b1b83c0 100644
--- a/drivers/gpu/msm/kgsl_iommu.h
+++ b/drivers/gpu/msm/kgsl_iommu.h
@@ -46,6 +46,16 @@
 #define KGSL_IOMMU_V1_FSYNR0_WNR_MASK		0x00000001
 #define KGSL_IOMMU_V1_FSYNR0_WNR_SHIFT		4
 
+/* TTBR0 register fields */
+#define KGSL_IOMMU_CTX_TTBR0_ADDR_MASK		0xFFFFC000
+
+/* TLBSTATUS register fields */
+#define KGSL_IOMMU_CTX_TLBSTATUS_SACTIVE BIT(0)
+
+/* IMPLDEF_MICRO_MMU_CTRL register fields */
+#define KGSL_IOMMU_IMPLDEF_MICRO_MMU_CTRL_HALT BIT(2)
+#define KGSL_IOMMU_IMPLDEF_MICRO_MMU_CTRL_IDLE BIT(3)
+
 enum kgsl_iommu_reg_map {
 	KGSL_IOMMU_GLOBAL_BASE = 0,
 	KGSL_IOMMU_CTX_TTBR0,
@@ -57,15 +67,31 @@
 	KGSL_IOMMU_CTX_V2PUR,
 	KGSL_IOMMU_CTX_FSYNR0,
 	KGSL_IOMMU_CTX_FSYNR1,
+	KGSL_IOMMU_CTX_TLBSYNC,
+	KGSL_IOMMU_CTX_TLBSTATUS,
+	KGSL_IOMMU_IMPLDEF_MICRO_MMU_CTRL,
 	KGSL_IOMMU_REG_MAX
 };
 
 struct kgsl_iommu_register_list {
 	unsigned int reg_offset;
-	unsigned int reg_mask;
-	unsigned int reg_shift;
+	int ctx_reg;
 };
 
+#ifdef CONFIG_MSM_IOMMU
+extern struct iommu_access_ops iommu_access_ops_v0;
+
+static inline struct iommu_access_ops *get_iommu_access_ops_v0(void)
+{
+	return &iommu_access_ops_v0;
+}
+#else
+static inline struct iommu_access_ops *get_iommu_access_ops_v0(void)
+{
+	return NULL;
+}
+#endif
+
 /*
  * Max number of iommu units that the gpu core can have
  * On APQ8064, KGSL can control a maximum of 2 IOMMU units.
@@ -91,10 +117,8 @@
 		iommu->ctx_offset)
 
 /* Gets the lsb value of pagetable */
-#define KGSL_IOMMMU_PT_LSB(iommu, pt_val) \
-	(pt_val &							\
-	~(iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<	\
-	iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift))
+#define KGSL_IOMMMU_PT_LSB(iommu, pt_val)				\
+	(pt_val & ~(KGSL_IOMMU_CTX_TTBR0_ADDR_MASK))
 
 /* offset at which a nop command is placed in setstate_memory */
 #define KGSL_IOMMU_SETSTATE_NOP_OFFSET	1024
@@ -130,11 +154,18 @@
  * @dev_count: Number of IOMMU contexts that are valid in the previous feild
  * @reg_map: Memory descriptor which holds the mapped address of this IOMMU
  * units register range
+ * @ahb_base - The base address from where IOMMU registers can be accesed from
+ * ahb bus
+ * @iommu_halt_enable: Valid only on IOMMU-v1, when set indicates that the iommu
+ * unit supports halting of the IOMMU, which can be enabled while programming
+ * the IOMMU registers for synchronization
  */
 struct kgsl_iommu_unit {
 	struct kgsl_iommu_device dev[KGSL_IOMMU_MAX_DEVS_PER_UNIT];
 	unsigned int dev_count;
 	struct kgsl_memdesc reg_map;
+	unsigned int ahb_base;
+	int iommu_halt_enable;
 };
 
 /*
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index 4e95373..6e41707 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -610,6 +610,7 @@
 	 * kgsl_pwrctrl_irq() is called
 	 */
 }
+EXPORT_SYMBOL(kgsl_mh_start);
 
 int
 kgsl_mmu_map(struct kgsl_pagetable *pagetable,
diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h
index d7d9516..ef5b0f4 100644
--- a/drivers/gpu/msm/kgsl_mmu.h
+++ b/drivers/gpu/msm/kgsl_mmu.h
@@ -14,7 +14,7 @@
 #define __KGSL_MMU_H
 
 #include <mach/iommu.h>
-
+#include "kgsl_iommu.h"
 /*
  * These defines control the address range for allocations that
  * are mapped into all pagetables.
@@ -150,6 +150,9 @@
 				enum kgsl_iommu_context_id ctx_id);
 	unsigned int (*mmu_get_reg_gpuaddr)(struct kgsl_mmu *mmu,
 			int iommu_unit_num, int ctx_id, int reg);
+	unsigned int (*mmu_get_reg_ahbaddr)(struct kgsl_mmu *mmu,
+			int iommu_unit_num, int ctx_id,
+			enum kgsl_iommu_reg_map reg);
 	int (*mmu_get_num_iommu_units)(struct kgsl_mmu *mmu);
 	int (*mmu_pt_equal) (struct kgsl_mmu *mmu,
 			struct kgsl_pagetable *pt,
@@ -165,6 +168,7 @@
 			(struct kgsl_mmu *mmu, unsigned int *cmds);
 	unsigned int (*mmu_sync_unlock)
 			(struct kgsl_mmu *mmu, unsigned int *cmds);
+	int (*mmu_hw_halt_supported)(struct kgsl_mmu *mmu, int iommu_unit_num);
 };
 
 struct kgsl_mmu_pt_ops {
@@ -337,6 +341,29 @@
 		return 0;
 }
 
+/*
+ * kgsl_mmu_get_reg_ahbaddr() - Calls the mmu specific function pointer to
+ * return the address that GPU can use to access register
+ * @mmu:		Pointer to the device mmu
+ * @iommu_unit_num:	There can be multiple iommu units used for graphics.
+ *			This parameter is an index to the iommu unit being used
+ * @ctx_id:		The context id within the iommu unit
+ * @reg:		Register whose address is to be returned
+ *
+ * Returns the ahb address of reg else 0
+ */
+static inline unsigned int kgsl_mmu_get_reg_ahbaddr(struct kgsl_mmu *mmu,
+						int iommu_unit_num,
+						int ctx_id,
+						enum kgsl_iommu_reg_map reg)
+{
+	if (mmu->mmu_ops && mmu->mmu_ops->mmu_get_reg_ahbaddr)
+		return mmu->mmu_ops->mmu_get_reg_ahbaddr(mmu, iommu_unit_num,
+							ctx_id, reg);
+	else
+		return 0;
+}
+
 static inline int kgsl_mmu_get_num_iommu_units(struct kgsl_mmu *mmu)
 {
 	if (mmu->mmu_ops && mmu->mmu_ops->mmu_get_num_iommu_units)
@@ -346,6 +373,22 @@
 }
 
 /*
+ * kgsl_mmu_hw_halt_supported() - Runtime check for iommu hw halt
+ * @mmu: the mmu
+ *
+ * Returns non-zero if the iommu supports hw halt,
+ * 0 if not.
+ */
+static inline int kgsl_mmu_hw_halt_supported(struct kgsl_mmu *mmu,
+						int iommu_unit_num)
+{
+	if (mmu->mmu_ops && mmu->mmu_ops->mmu_hw_halt_supported)
+		return mmu->mmu_ops->mmu_hw_halt_supported(mmu, iommu_unit_num);
+	else
+		return 0;
+}
+
+/*
  * kgsl_mmu_is_perprocess() - Runtime check for per-process
  * pagetables.
  * @mmu: the mmu
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 7d05aea..ef22c41 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -59,6 +59,10 @@
 		.name = "mem_iface_clk",
 		.map = KGSL_CLK_MEM_IFACE,
 	},
+	{
+		.name = "alt_mem_iface_clk",
+		.map = KGSL_CLK_ALT_MEM_IFACE,
+	},
 };
 
 /* Update the elapsed time at a particular clock level
@@ -1102,6 +1106,7 @@
 
 	mutex_unlock(&device->mutex);
 }
+EXPORT_SYMBOL(kgsl_idle_check);
 
 void kgsl_timer(unsigned long data)
 {
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h
index 0fd64c3..bb45829 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.h
+++ b/drivers/gpu/msm/kgsl_pwrctrl.h
@@ -23,7 +23,7 @@
 #define KGSL_PWRLEVEL_NOMINAL 1
 #define KGSL_PWRLEVEL_LAST_OFFSET 2
 
-#define KGSL_MAX_CLKS 5
+#define KGSL_MAX_CLKS 6
 
 struct platform_device;
 
diff --git a/drivers/gpu/msm/kgsl_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c
index 02ada38..afef62e 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.c
+++ b/drivers/gpu/msm/kgsl_pwrscale.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-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
@@ -240,6 +240,7 @@
 		device->pwrscale.policy->busy(device,
 				&device->pwrscale);
 }
+EXPORT_SYMBOL(kgsl_pwrscale_busy);
 
 void kgsl_pwrscale_idle(struct kgsl_device *device)
 {
diff --git a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
index 9b2ac70..5d5d5b1 100644
--- a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
+++ b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
@@ -31,6 +31,7 @@
 	unsigned int no_switch_cnt;
 	unsigned int skip_cnt;
 	struct kgsl_power_stats bin;
+	unsigned int idle_dcvs;
 };
 spinlock_t tz_lock;
 
@@ -47,24 +48,32 @@
 #define SKIP_COUNTER		500
 #define TZ_RESET_ID		0x3
 #define TZ_UPDATE_ID		0x4
+#define TZ_INIT_ID		0x6
 
-#ifdef CONFIG_MSM_SCM
 /* Trap into the TrustZone, and call funcs there. */
-static int __secure_tz_entry(u32 cmd, u32 val, u32 id)
+static int __secure_tz_entry2(u32 cmd, u32 val1, u32 val2)
 {
 	int ret;
 	spin_lock(&tz_lock);
+	/* sync memory before sending the commands to tz*/
 	__iowmb();
-	ret = scm_call_atomic2(SCM_SVC_IO, cmd, val, id);
+	ret = scm_call_atomic2(SCM_SVC_IO, cmd, val1, val2);
 	spin_unlock(&tz_lock);
 	return ret;
 }
-#else
-static int __secure_tz_entry(u32 cmd, u32 val, u32 id)
+
+static int __secure_tz_entry3(u32 cmd, u32 val1, u32 val2,
+				u32 val3)
 {
-	return 0;
+	int ret;
+	spin_lock(&tz_lock);
+	/* sync memory before sending the commands to tz*/
+	__iowmb();
+	ret = scm_call_atomic3(SCM_SVC_IO, cmd, val1, val2,
+				val3);
+	spin_unlock(&tz_lock);
+	return ret;
 }
-#endif /* CONFIG_MSM_SCM */
 
 static ssize_t tz_governor_show(struct kgsl_device *device,
 				struct kgsl_pwrscale *pwrscale,
@@ -172,11 +181,21 @@
 	 */
 	if (priv->bin.busy_time > CEILING) {
 		val = -1;
-	} else {
+	} else if (priv->idle_dcvs) {
 		idle = priv->bin.total_time - priv->bin.busy_time;
 		idle = (idle > 0) ? idle : 0;
-		val = __secure_tz_entry(TZ_UPDATE_ID, idle, device->id);
+		val = __secure_tz_entry2(TZ_UPDATE_ID, idle, device->id);
+	} else {
+		if (pwr->step_mul > 1)
+			val = __secure_tz_entry3(TZ_UPDATE_ID,
+				(pwr->active_pwrlevel + 1)/2,
+				priv->bin.total_time, priv->bin.busy_time);
+		else
+			val = __secure_tz_entry3(TZ_UPDATE_ID,
+				pwr->active_pwrlevel,
+				priv->bin.total_time, priv->bin.busy_time);
 	}
+
 	priv->bin.total_time = 0;
 	priv->bin.busy_time = 0;
 
@@ -201,7 +220,7 @@
 {
 	struct tz_priv *priv = pwrscale->priv;
 
-	__secure_tz_entry(TZ_RESET_ID, 0, device->id);
+	__secure_tz_entry2(TZ_RESET_ID, 0, 0);
 	priv->no_switch_cnt = 0;
 	priv->bin.total_time = 0;
 	priv->bin.busy_time = 0;
@@ -210,16 +229,32 @@
 #ifdef CONFIG_MSM_SCM
 static int tz_init(struct kgsl_device *device, struct kgsl_pwrscale *pwrscale)
 {
+	int i = 0, j = 1, ret = 0;
 	struct tz_priv *priv;
+	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
+	unsigned int tz_pwrlevels[KGSL_MAX_PWRLEVELS + 1];
 
 	priv = pwrscale->priv = kzalloc(sizeof(struct tz_priv), GFP_KERNEL);
 	if (pwrscale->priv == NULL)
 		return -ENOMEM;
-
+	priv->idle_dcvs = 0;
 	priv->governor = TZ_GOVERNOR_ONDEMAND;
 	spin_lock_init(&tz_lock);
 	kgsl_pwrscale_policy_add_files(device, pwrscale, &tz_attr_group);
-
+	for (i = 0; i < pwr->num_pwrlevels - 1; i++) {
+		if (i == 0)
+			tz_pwrlevels[j] = pwr->pwrlevels[i].gpu_freq;
+		else if (pwr->pwrlevels[i].gpu_freq !=
+				pwr->pwrlevels[i - 1].gpu_freq) {
+			j++;
+			tz_pwrlevels[j] = pwr->pwrlevels[i].gpu_freq;
+		}
+	}
+	tz_pwrlevels[0] = j;
+	ret = scm_call(SCM_SVC_DCVS, TZ_INIT_ID, tz_pwrlevels,
+				sizeof(tz_pwrlevels), NULL, 0);
+	if (ret)
+		priv->idle_dcvs = 1;
 	return 0;
 }
 #else
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index 595f78f..62db513 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -607,16 +607,22 @@
 
 	while (len > 0) {
 		struct page *page;
-		unsigned int gfp_mask = GFP_KERNEL | __GFP_HIGHMEM |
-			__GFP_NOWARN | __GFP_NORETRY;
+		unsigned int gfp_mask = __GFP_HIGHMEM;
 		int j;
 
 		/* don't waste space at the end of the allocation*/
 		if (len < page_size)
 			page_size = PAGE_SIZE;
 
+		/*
+		 * Don't do some of the more aggressive memory recovery
+		 * techniques for large order allocations
+		 */
 		if (page_size != PAGE_SIZE)
-			gfp_mask |= __GFP_COMP;
+			gfp_mask |= __GFP_COMP | __GFP_NORETRY |
+				__GFP_NO_KSWAPD | __GFP_NOWARN;
+		else
+			gfp_mask |= GFP_KERNEL | __GFP_NORETRY;
 
 		page = alloc_pages(gfp_mask, get_order(page_size));
 
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index 4c9c744..abcebfb 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -325,6 +325,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL(kgsl_snapshot_have_object);
 
 /* kgsl_snapshot_get_object - Mark a GPU buffer to be frozen
  * @device - the device that is being snapshotted
diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c
index a07959b..49265fc 100644
--- a/drivers/gpu/msm/z180.c
+++ b/drivers/gpu/msm/z180.c
@@ -17,7 +17,6 @@
 #include "kgsl.h"
 #include "kgsl_cffdump.h"
 #include "kgsl_sharedmem.h"
-#include "kgsl_trace.h"
 
 #include "z180.h"
 #include "z180_reg.h"
@@ -485,7 +484,7 @@
 	z180_cmdwindow_write(device, ADDR_VGV3_CONTROL, 0);
 error:
 
-	trace_kgsl_issueibcmds(device, context->id, ibdesc, numibs,
+	kgsl_trace_issueibcmds(device, context->id, ibdesc, numibs,
 		*timestamp, ctrl, result, 0);
 
 	return (int)result;
diff --git a/drivers/hwmon/qpnp-adc-common.c b/drivers/hwmon/qpnp-adc-common.c
index 1458bc5..b3b5643 100644
--- a/drivers/hwmon/qpnp-adc-common.c
+++ b/drivers/hwmon/qpnp-adc-common.c
@@ -638,20 +638,21 @@
 {
 	struct qpnp_vadc_linear_graph vbatt_param;
 	int rc = 0;
+	int64_t low_thr = 0, high_thr = 0;
 
 	rc = qpnp_get_vadc_gain_and_offset(&vbatt_param, CALIB_ABSOLUTE);
 	if (rc < 0)
 		return rc;
 
-	*low_threshold = (((param->low_thr/3) - QPNP_ADC_625_UV) *
+	low_thr = (((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;
+	do_div(low_thr, QPNP_ADC_625_UV);
+	*low_threshold = low_thr + vbatt_param.adc_gnd;
 
-	*high_threshold = (((param->high_thr/3) - QPNP_ADC_625_UV) *
+	high_thr = (((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;
+	do_div(high_thr, QPNP_ADC_625_UV);
+	*high_threshold = high_thr + vbatt_param.adc_gnd;
 
 	pr_debug("high_volt:%d, low_volt:%d\n", param->high_thr,
 				param->low_thr);
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index f35f0e7..aa69475 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -16,7 +16,7 @@
 # MSM IOMMU support
 config MSM_IOMMU
 	bool "MSM IOMMU Support"
-	depends on ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_APQ8064 || ARCH_MSM8974 || ARCH_MPQ8092 || ARCH_MSM8610 || ARCH_MSM8226 || ARCH_MSMZINC
+	depends on ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_APQ8064 || ARCH_MSM8974 || ARCH_MPQ8092 || ARCH_MSM8610 || ARCH_MSM8226 || ARCH_APQ8084
 	select IOMMU_API
 	help
 	  Support for the IOMMUs found on certain Qualcomm SOCs.
diff --git a/drivers/iommu/msm_iommu-v0.c b/drivers/iommu/msm_iommu-v0.c
index c0a4720..b1960c6 100644
--- a/drivers/iommu/msm_iommu-v0.c
+++ b/drivers/iommu/msm_iommu-v0.c
@@ -55,6 +55,9 @@
 	.name = "msm_iommu_sec_bus",
 };
 
+static int msm_iommu_unmap_range(struct iommu_domain *domain, unsigned int va,
+				 unsigned int len);
+
 static inline void clean_pte(unsigned long *start, unsigned long *end,
 			     int redirect)
 {
@@ -167,6 +170,11 @@
 	/* No need to do anything. IOMMUv0 is always on. */
 }
 
+static void *_iommu_lock_initialize(void)
+{
+	return msm_iommu_lock_initialize();
+}
+
 static void _iommu_lock_acquire(void)
 {
 	msm_iommu_lock();
@@ -182,6 +190,7 @@
 	.iommu_power_off = __disable_regulators,
 	.iommu_clk_on = __enable_clocks,
 	.iommu_clk_off = __disable_clocks,
+	.iommu_lock_initialize = _iommu_lock_initialize,
 	.iommu_lock_acquire = _iommu_lock_acquire,
 	.iommu_lock_release = _iommu_lock_release,
 };
@@ -953,6 +962,7 @@
 			       int prot)
 {
 	unsigned int pa;
+	unsigned int start_va = va;
 	unsigned int offset = 0;
 	unsigned long *fl_table;
 	unsigned long *fl_pte;
@@ -1026,12 +1036,6 @@
 				chunk_offset = 0;
 				sg = sg_next(sg);
 				pa = get_phys_addr(sg);
-				if (pa == 0) {
-					pr_debug("No dma address for sg %p\n",
-							sg);
-					ret = -EINVAL;
-					goto fail;
-				}
 			}
 			continue;
 		}
@@ -1085,12 +1089,6 @@
 				chunk_offset = 0;
 				sg = sg_next(sg);
 				pa = get_phys_addr(sg);
-				if (pa == 0) {
-					pr_debug("No dma address for sg %p\n",
-							sg);
-					ret = -EINVAL;
-					goto fail;
-				}
 			}
 		}
 
@@ -1103,6 +1101,8 @@
 	__flush_iotlb(domain);
 fail:
 	mutex_unlock(&msm_iommu_lock);
+	if (ret && offset > 0)
+		msm_iommu_unmap_range(domain, start_va, offset);
 	return ret;
 }
 
diff --git a/drivers/iommu/msm_iommu_pagetable.c b/drivers/iommu/msm_iommu_pagetable.c
index b62bb76..9614692 100644
--- a/drivers/iommu/msm_iommu_pagetable.c
+++ b/drivers/iommu/msm_iommu_pagetable.c
@@ -431,6 +431,7 @@
 		       struct scatterlist *sg, unsigned int len, int prot)
 {
 	phys_addr_t pa;
+	unsigned int start_va = va;
 	unsigned int offset = 0;
 	unsigned long *fl_pte;
 	unsigned long fl_offset;
@@ -495,12 +496,6 @@
 				chunk_offset = 0;
 				sg = sg_next(sg);
 				pa = get_phys_addr(sg);
-				if (pa == 0) {
-					pr_debug("No dma address for sg %p\n",
-							sg);
-					ret = -EINVAL;
-					goto fail;
-				}
 			}
 			continue;
 		}
@@ -553,12 +548,6 @@
 				chunk_offset = 0;
 				sg = sg_next(sg);
 				pa = get_phys_addr(sg);
-				if (pa == 0) {
-					pr_debug("No dma address for sg %p\n",
-							sg);
-					ret = -EINVAL;
-					goto fail;
-				}
 			}
 		}
 
@@ -569,6 +558,9 @@
 	}
 
 fail:
+	if (ret && offset > 0)
+		msm_iommu_pagetable_unmap_range(pt, start_va, offset);
+
 	return ret;
 }
 
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index 1d34b06..3667296 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -159,6 +159,27 @@
 #define	PWM_LUT_MAX_SIZE		63
 #define RGB_LED_DISABLE			0x00
 
+#define MPP_MAX_LEVEL			LED_FULL
+#define LED_MPP_MODE_CTRL(base)		(base + 0x40)
+#define LED_MPP_VIN_CTRL(base)		(base + 0x41)
+#define LED_MPP_EN_CTRL(base)		(base + 0x46)
+#define LED_MPP_SINK_CTRL(base)		(base + 0x4C)
+
+#define LED_MPP_CURRENT_DEFAULT		10
+#define LED_MPP_SOURCE_SEL_DEFAULT	LED_MPP_MODE_ENABLE
+
+#define LED_MPP_SINK_MASK		0x07
+#define LED_MPP_MODE_MASK		0x7F
+#define LED_MPP_EN_MASK			0x80
+
+#define LED_MPP_MODE_SINK		(0x06 << 4)
+#define LED_MPP_MODE_ENABLE		0x01
+#define LED_MPP_MODE_OUTPUT		0x10
+#define LED_MPP_MODE_DISABLE		0x00
+#define LED_MPP_EN_ENABLE		0x80
+#define LED_MPP_EN_DISABLE		0x00
+
+#define MPP_SOURCE_DTEST1		0x08
 /**
  * enum qpnp_leds - QPNP supported led ids
  * @QPNP_ID_WLED - White led backlight
@@ -170,6 +191,7 @@
 	QPNP_ID_RGB_RED,
 	QPNP_ID_RGB_GREEN,
 	QPNP_ID_RGB_BLUE,
+	QPNP_ID_LED_MPP,
 	QPNP_ID_MAX,
 };
 
@@ -240,6 +262,11 @@
 static u8 rgb_pwm_debug_regs[] = {
 	0x45, 0x46, 0x47,
 };
+
+static u8 mpp_debug_regs[] = {
+	0x40, 0x41, 0x42, 0x45, 0x46, 0x4c,
+};
+
 /**
  *  wled_config_data - wled configuration data
  *  @num_strings - number of wled strings supported
@@ -264,6 +291,16 @@
 };
 
 /**
+ *  mpp_config_data - mpp configuration data
+ *  @current_setting - current setting, 5ma-40ma in 5ma increments
+ */
+struct mpp_config_data {
+	u8	current_setting;
+	u8	source_sel;
+	u8	mode_ctrl;
+};
+
+/**
  *  flash_config_data - flash configuration data
  *  @current_prgm - current to be programmed, scaled by max level
  *  @clamp_curr - clamp current to use
@@ -336,6 +373,7 @@
 	struct wled_config_data *wled_cfg;
 	struct flash_config_data	*flash_cfg;
 	struct rgb_config_data	*rgb_cfg;
+	struct mpp_config_data	*mpp_cfg;
 	int			max_current;
 	bool			default_on;
 	int			turn_off_delay_ms;
@@ -458,6 +496,68 @@
 	return 0;
 }
 
+static int qpnp_mpp_set(struct qpnp_led_data *led)
+{
+	int rc, val;
+
+	if (led->cdev.brightness) {
+		val = (led->cdev.brightness * LED_MPP_SINK_MASK) / LED_FULL;
+		rc = qpnp_led_masked_write(led,
+				LED_MPP_SINK_CTRL(led->base),
+				LED_MPP_SINK_MASK, val);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"Failed to write led enable reg\n");
+			return rc;
+		}
+
+		val = led->mpp_cfg->source_sel | led->mpp_cfg->mode_ctrl;
+
+		rc = qpnp_led_masked_write(led,
+		LED_MPP_MODE_CTRL(led->base), LED_MPP_MODE_MASK,
+		val);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+					"Failed to write led mode reg\n");
+			return rc;
+		}
+
+		rc = qpnp_led_masked_write(led,
+				LED_MPP_EN_CTRL(led->base), LED_MPP_EN_MASK,
+				LED_MPP_EN_ENABLE);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+						"Failed to write led enable " \
+						"reg\n");
+				return rc;
+			}
+	} else {
+		rc = qpnp_led_masked_write(led,
+					LED_MPP_MODE_CTRL(led->base),
+					LED_MPP_MODE_MASK,
+					LED_MPP_MODE_DISABLE);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+					"Failed to write led mode reg\n");
+			return rc;
+		}
+
+		rc = qpnp_led_masked_write(led,
+					LED_MPP_EN_CTRL(led->base),
+					LED_MPP_EN_MASK,
+					LED_MPP_EN_DISABLE);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+					"Failed to write led enable reg\n");
+			return rc;
+		}
+	}
+
+	qpnp_dump_regs(led, mpp_debug_regs, ARRAY_SIZE(mpp_debug_regs));
+
+	return 0;
+}
+
 static int qpnp_flash_set(struct qpnp_led_data *led)
 {
 	int rc;
@@ -750,6 +850,12 @@
 			dev_err(&led->spmi_dev->dev,
 				"RGB set brightness failed (%d)\n", rc);
 		break;
+	case QPNP_ID_LED_MPP:
+		rc = qpnp_mpp_set(led);
+		if (rc < 0)
+			dev_err(&led->spmi_dev->dev,
+					"MPP set brightness failed (%d)\n", rc);
+		break;
 	default:
 		dev_err(&led->spmi_dev->dev, "Invalid LED(%d)\n", led->id);
 		break;
@@ -772,6 +878,9 @@
 	case QPNP_ID_RGB_BLUE:
 		led->cdev.max_brightness = RGB_MAX_LEVEL;
 		break;
+	case QPNP_ID_LED_MPP:
+		led->cdev.max_brightness = MPP_MAX_LEVEL;
+		break;
 	default:
 		dev_err(&led->spmi_dev->dev, "Invalid LED(%d)\n", led->id);
 		return -EINVAL;
@@ -1211,6 +1320,8 @@
 			dev_err(&led->spmi_dev->dev,
 				"RGB initialize failed(%d)\n", rc);
 		break;
+	case QPNP_ID_LED_MPP:
+		break;
 	default:
 		dev_err(&led->spmi_dev->dev, "Invalid LED(%d)\n", led->id);
 		return -EINVAL;
@@ -1536,6 +1647,43 @@
 	return 0;
 }
 
+static int __devinit qpnp_get_config_mpp(struct qpnp_led_data *led,
+		struct device_node *node)
+{
+	int rc;
+	u32 val;
+
+	led->mpp_cfg = devm_kzalloc(&led->spmi_dev->dev,
+			sizeof(struct mpp_config_data), GFP_KERNEL);
+	if (!led->mpp_cfg) {
+		dev_err(&led->spmi_dev->dev, "Unable to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	led->mpp_cfg->current_setting = LED_MPP_CURRENT_DEFAULT;
+	rc = of_property_read_u32(node, "qcom,current-setting", &val);
+	if (!rc)
+		led->mpp_cfg->current_setting = (u8) val;
+	else if (rc != -EINVAL)
+		return rc;
+
+	led->mpp_cfg->source_sel = LED_MPP_SOURCE_SEL_DEFAULT;
+	rc = of_property_read_u32(node, "qcom,source-sel", &val);
+	if (!rc)
+		led->mpp_cfg->source_sel = (u8) val;
+	else if (rc != -EINVAL)
+		return rc;
+
+	led->mpp_cfg->mode_ctrl = LED_MPP_MODE_SINK;
+	rc = of_property_read_u32(node, "qcom,mode-ctrl", &val);
+	if (!rc)
+		led->mpp_cfg->mode_ctrl = (u8) val;
+	else if (rc != -EINVAL)
+		return rc;
+
+	return 0;
+}
+
 static int __devinit qpnp_leds_probe(struct spmi_device *spmi)
 {
 	struct qpnp_led_data *led, *led_array;
@@ -1638,6 +1786,13 @@
 					"Unable to read rgb config data\n");
 				goto fail_id_check;
 			}
+		} else if (strncmp(led_label, "mpp", sizeof("mpp")) == 0) {
+			rc = qpnp_get_config_mpp(led, temp);
+			if (rc < 0) {
+				dev_err(&led->spmi_dev->dev,
+						"Unable to read mpp config data\n");
+				goto fail_id_check;
+			}
 		} else {
 			dev_err(&led->spmi_dev->dev, "No LED matching label\n");
 			rc = -EINVAL;
diff --git a/drivers/media/dvb/dvb-core/demux.h b/drivers/media/dvb/dvb-core/demux.h
index f0b9b05..89500f9 100644
--- a/drivers/media/dvb/dvb-core/demux.h
+++ b/drivers/media/dvb/dvb-core/demux.h
@@ -127,6 +127,7 @@
 			u32 cont_err_counter;
 			u32 ts_packets_num;
 			u32 ts_dropped_bytes;
+			u64 stc;
 		} buf;
 
 		struct {
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index ca71c06..5e7a09e 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -2406,6 +2406,7 @@
 		event.params.es_data.pts = dmx_data_ready->buf.pts;
 		event.params.es_data.dts_valid = dmx_data_ready->buf.dts_exists;
 		event.params.es_data.dts = dmx_data_ready->buf.dts;
+		event.params.es_data.stc = dmx_data_ready->buf.stc;
 		event.params.es_data.transport_error_indicator_counter =
 				dmx_data_ready->buf.tei_counter;
 		event.params.es_data.continuity_error_counter =
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
index 22e8400..04afec0 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
@@ -281,13 +281,16 @@
 		list_for_each_entry(temp_buf_info,
 			&bufq->share_head, share_list) {
 			if (!temp_buf_info->buf_used[id]) {
-				*buf_info = temp_buf_info;
 				temp_buf_info->buf_used[id] = 1;
 				temp_buf_info->buf_get_count++;
 				if (temp_buf_info->buf_get_count ==
 					bufq->buf_client_count)
 					list_del_init(
 					&temp_buf_info->share_list);
+				if (temp_buf_info->buf_reuse_flag)
+					kfree(temp_buf_info);
+				else
+					*buf_info = temp_buf_info;
 				spin_unlock_irqrestore(
 					&bufq->bufq_lock, flags);
 				return 0;
@@ -322,21 +325,30 @@
 	}
 
 	if (!(*buf_info)) {
-		spin_unlock_irqrestore(&bufq->bufq_lock, flags);
-		return rc;
-	}
-
-	(*buf_info)->state = MSM_ISP_BUFFER_STATE_DEQUEUED;
-	if (bufq->buf_type == ISP_SHARE_BUF) {
-		memset((*buf_info)->buf_used, 0,
-			   sizeof(uint8_t) * bufq->buf_client_count);
-		(*buf_info)->buf_used[id] = 1;
-		(*buf_info)->buf_get_count = 1;
-		(*buf_info)->buf_put_count = 0;
-		list_add_tail(&(*buf_info)->share_list, &bufq->share_head);
+		if (bufq->buf_type == ISP_SHARE_BUF) {
+			temp_buf_info = kzalloc(
+			   sizeof(struct msm_isp_buffer), GFP_ATOMIC);
+			temp_buf_info->buf_reuse_flag = 1;
+			temp_buf_info->buf_used[id] = 1;
+			temp_buf_info->buf_get_count = 1;
+			list_add_tail(&temp_buf_info->share_list,
+						  &bufq->share_head);
+		}
+	} else {
+		(*buf_info)->state = MSM_ISP_BUFFER_STATE_DEQUEUED;
+		if (bufq->buf_type == ISP_SHARE_BUF) {
+			memset((*buf_info)->buf_used, 0,
+				   sizeof(uint8_t) * bufq->buf_client_count);
+			(*buf_info)->buf_used[id] = 1;
+			(*buf_info)->buf_get_count = 1;
+			(*buf_info)->buf_put_count = 0;
+			list_add_tail(&(*buf_info)->share_list,
+						  &bufq->share_head);
+		}
+		rc = 0;
 	}
 	spin_unlock_irqrestore(&bufq->bufq_lock, flags);
-	return 0;
+	return rc;
 }
 
 static int msm_isp_put_buf(struct msm_isp_buf_mgr *buf_mgr,
@@ -648,22 +660,35 @@
 	}
 }
 
-static int msm_isp_attach_ctx(struct msm_isp_buf_mgr *buf_mgr,
-	struct device *iommu_ctx)
+static void msm_isp_register_ctx(struct msm_isp_buf_mgr *buf_mgr,
+	struct device **iommu_ctx, int num_iommu_ctx)
 {
-	int rc;
-	rc = iommu_attach_device(buf_mgr->iommu_domain, iommu_ctx);
-	if (rc) {
-		pr_err("%s: Iommu attach error\n", __func__);
-		return -EINVAL;
+	int i;
+	buf_mgr->num_iommu_ctx = num_iommu_ctx;
+	for (i = 0; i < num_iommu_ctx; i++)
+		buf_mgr->iommu_ctx[i] = iommu_ctx[i];
+}
+
+static int msm_isp_attach_ctx(struct msm_isp_buf_mgr *buf_mgr)
+{
+	int rc, i;
+	for (i = 0; i < buf_mgr->num_iommu_ctx; i++) {
+		rc = iommu_attach_device(buf_mgr->iommu_domain,
+			buf_mgr->iommu_ctx[i]);
+		if (rc) {
+			pr_err("%s: Iommu attach error\n", __func__);
+			return -EINVAL;
+		}
 	}
 	return 0;
 }
 
-static void msm_isp_detach_ctx(struct msm_isp_buf_mgr *buf_mgr,
-	struct device *iommu_ctx)
+static void msm_isp_detach_ctx(struct msm_isp_buf_mgr *buf_mgr)
 {
-	iommu_detach_device(buf_mgr->iommu_domain, iommu_ctx);
+	int i;
+	for (i = 0; i < buf_mgr->num_iommu_ctx; i++)
+		iommu_detach_device(buf_mgr->iommu_domain,
+			buf_mgr->iommu_ctx[i]);
 }
 
 static int msm_isp_init_isp_buf_mgr(
@@ -680,6 +705,7 @@
 	}
 
 	CDBG("%s: E\n", __func__);
+	msm_isp_attach_ctx(buf_mgr);
 	buf_mgr->num_buf_q = num_buf_q;
 	buf_mgr->bufq =
 		kzalloc(sizeof(struct msm_isp_bufq) * num_buf_q,
@@ -704,6 +730,7 @@
 	ion_client_destroy(buf_mgr->client);
 	kfree(buf_mgr->bufq);
 	buf_mgr->num_buf_q = 0;
+	msm_isp_detach_ctx(buf_mgr);
 	return 0;
 }
 
@@ -740,8 +767,7 @@
 	.flush_buf = msm_isp_flush_buf,
 	.buf_done = msm_isp_buf_done,
 	.buf_divert = msm_isp_buf_divert,
-	.attach_ctx = msm_isp_attach_ctx,
-	.detach_ctx = msm_isp_detach_ctx,
+	.register_ctx = msm_isp_register_ctx,
 	.buf_mgr_init = msm_isp_init_isp_buf_mgr,
 	.buf_mgr_deinit = msm_isp_deinit_isp_buf_mgr,
 };
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.h b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.h
index d4e7c88..fda1a57 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.h
@@ -65,6 +65,7 @@
 	uint8_t buf_used[ISP_SHARE_BUF_CLIENT];
 	uint8_t buf_get_count;
 	uint8_t buf_put_count;
+	uint8_t buf_reuse_flag;
 };
 
 struct msm_isp_bufq {
@@ -111,10 +112,8 @@
 	int (*buf_divert) (struct msm_isp_buf_mgr *buf_mgr,
 		uint32_t bufq_handle, uint32_t buf_index,
 		struct timeval *tv, uint32_t frame_id);
-	int (*attach_ctx) (struct msm_isp_buf_mgr *buf_mgr,
-		struct device *iommu_ctx);
-	void (*detach_ctx) (struct msm_isp_buf_mgr *buf_mgr,
-		struct device *iommu_ctx);
+	void (*register_ctx) (struct msm_isp_buf_mgr *buf_mgr,
+		struct device **iommu_ctx, int num_iommu_ctx);
 	int (*buf_mgr_init) (struct msm_isp_buf_mgr *buf_mgr,
 		const char *ctx_name, uint16_t num_buf_q);
 	int (*buf_mgr_deinit) (struct msm_isp_buf_mgr *buf_mgr);
@@ -136,6 +135,9 @@
 	/*IOMMU specific*/
 	int iommu_domain_num;
 	struct iommu_domain *iommu_domain;
+
+	int num_iommu_ctx;
+	struct device *iommu_ctx[2];
 };
 
 int msm_isp_create_isp_buf_mgr(struct msm_isp_buf_mgr *buf_mgr,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
index 447c752..b31b3f1 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
@@ -138,6 +138,8 @@
 		kfree(vfe_dev);
 		return -EINVAL;
 	}
+	vfe_dev->buf_mgr->ops->register_ctx(vfe_dev->buf_mgr,
+		&vfe_dev->iommu_ctx[0], vfe_dev->hw_info->num_iommu_ctx);
 	vfe_dev->vfe_open_cnt = 0;
 end:
 	return rc;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
index 1b762ea..7bc2b7d 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
@@ -148,7 +148,8 @@
 		struct msm_vfe_stats_stream *stream_info);
 	void (*clear_framedrop) (struct vfe_device *vfe_dev,
 		struct msm_vfe_stats_stream *stream_info);
-	void (*cfg_comp_mask) (struct vfe_device *vfe_dev);
+	void (*cfg_comp_mask) (struct vfe_device *vfe_dev,
+		uint32_t stats_mask, uint8_t enable);
 	void (*cfg_wm_irq_mask) (struct vfe_device *vfe_dev,
 		struct msm_vfe_stats_stream *stream_info);
 	void (*clear_wm_irq_mask) (struct vfe_device *vfe_dev,
@@ -294,6 +295,7 @@
 		composite_info[MAX_NUM_COMPOSITE_MASK];
 	uint8_t num_used_composite_mask;
 	uint32_t stream_update;
+	enum msm_isp_camif_update_state pipeline_update;
 	struct msm_vfe_src_info src_info[VFE_SRC_MAX];
 	uint16_t stream_handle_cnt;
 	unsigned long event_mask;
@@ -312,6 +314,7 @@
 	STATS_ACTIVE,
 	STATS_START_PENDING,
 	STATS_STOP_PENDING,
+	STATS_STARTING,
 	STATS_STOPPING,
 };
 
@@ -319,9 +322,11 @@
 	uint32_t session_id;
 	uint32_t stream_id;
 	uint32_t stream_handle;
+	uint32_t composite_flag;
 	enum msm_isp_stats_type stats_type;
 	enum msm_vfe_stats_state state;
 	uint32_t framedrop_pattern;
+	uint32_t framedrop_period;
 	uint32_t irq_subsample_pattern;
 
 	uint32_t buffer_offset;
@@ -331,11 +336,10 @@
 
 struct msm_vfe_stats_shared_data {
 	struct msm_vfe_stats_stream stream_info[MSM_ISP_STATS_MAX];
-	enum msm_vfe_stats_pipeline_policy stats_pipeline_policy;
-	uint32_t comp_framedrop_pattern;
-	uint32_t comp_irq_subsample_pattern;
 	uint8_t num_active_stream;
+	atomic_t stats_comp_mask;
 	uint16_t stream_handle_cnt;
+	atomic_t stats_update;
 };
 
 struct msm_vfe_tasklet_queue_cmd {
@@ -380,6 +384,7 @@
 	struct completion reset_complete;
 	struct completion halt_complete;
 	struct completion stream_config_complete;
+	struct completion stats_config_complete;
 	struct mutex realtime_mutex;
 	struct mutex core_mutex;
 
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
index d4f6a07..a251f0a 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
@@ -114,7 +114,7 @@
 	msm_camera_io_w(0x07FFFFFF, vfe_dev->vfe_base + 0xC);
 	/* BUS_CFG */
 	msm_camera_io_w(0x00000001, vfe_dev->vfe_base + 0x3C);
-	msm_camera_io_w(0x00000025, vfe_dev->vfe_base + 0x1C);
+	msm_camera_io_w(0x01000025, vfe_dev->vfe_base + 0x1C);
 	msm_camera_io_w_mb(0x1DFFFFFF, vfe_dev->vfe_base + 0x20);
 	msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x24);
 	msm_camera_io_w_mb(0x1FFFFFFF, vfe_dev->vfe_base + 0x28);
@@ -304,6 +304,8 @@
 
 	if (vfe_dev->axi_data.stream_update)
 		msm_isp_axi_stream_update(vfe_dev);
+	if (atomic_read(&vfe_dev->stats_data.stats_update))
+		msm_isp_stats_stream_update(vfe_dev);
 	msm_isp_update_framedrop_reg(vfe_dev);
 	msm_isp_update_error_frame_count(vfe_dev);
 
@@ -767,7 +769,8 @@
 	}
 }
 
-static void msm_vfe32_stats_cfg_comp_mask(struct vfe_device *vfe_dev)
+static void msm_vfe32_stats_cfg_comp_mask(struct vfe_device *vfe_dev,
+	uint32_t stats_mask, uint8_t enable)
 {
 	return;
 }
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
index 256d136..5a17635 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -266,7 +266,7 @@
 	msm_camera_io_w(0xC001FF7F, vfe_dev->vfe_base + 0x974);
 	/* BUS_CFG */
 	msm_camera_io_w(0x10000001, vfe_dev->vfe_base + 0x50);
-	msm_camera_io_w(0x800000F3, vfe_dev->vfe_base + 0x28);
+	msm_camera_io_w(0xE00000F3, vfe_dev->vfe_base + 0x28);
 	msm_camera_io_w_mb(0xFEFFFFFF, vfe_dev->vfe_base + 0x2C);
 	msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x30);
 	msm_camera_io_w_mb(0xFEFFFFFF, vfe_dev->vfe_base + 0x34);
@@ -466,6 +466,8 @@
 
 	if (vfe_dev->axi_data.stream_update)
 		msm_isp_axi_stream_update(vfe_dev);
+	if (atomic_read(&vfe_dev->stats_data.stats_update))
+		msm_isp_stats_stream_update(vfe_dev);
 	msm_isp_update_framedrop_reg(vfe_dev);
 	msm_isp_update_error_frame_count(vfe_dev);
 
@@ -1003,12 +1005,16 @@
 	}
 }
 
-static void msm_vfe40_stats_cfg_comp_mask(struct vfe_device *vfe_dev)
+static void msm_vfe40_stats_cfg_comp_mask(struct vfe_device *vfe_dev,
+	uint32_t stats_mask, uint8_t enable)
 {
-	if (vfe_dev->stats_data.stats_pipeline_policy == STATS_COMP_ALL)
-		msm_camera_io_w(0x00FF0000, vfe_dev->vfe_base + 0x44);
+	uint32_t comp_mask;
+	comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x44) >> 16;
+	if (enable)
+		comp_mask |= stats_mask;
 	else
-		msm_camera_io_w(0x00000000, vfe_dev->vfe_base + 0x44);
+		comp_mask &= ~stats_mask;
+	msm_camera_io_w(comp_mask << 16, vfe_dev->vfe_base + 0x44);
 }
 
 static void msm_vfe40_stats_cfg_wm_irq_mask(
@@ -1039,9 +1045,10 @@
 	uint32_t stats_base = VFE40_STATS_BASE(stats_idx);
 
 	/*WR_ADDR_CFG*/
-	msm_camera_io_w(0x7C, vfe_dev->vfe_base + stats_base + 0x8);
+	msm_camera_io_w(stream_info->framedrop_period << 2,
+		vfe_dev->vfe_base + stats_base + 0x8);
 	/*WR_IRQ_FRAMEDROP_PATTERN*/
-	msm_camera_io_w(0xFFFFFFFF,
+	msm_camera_io_w(stream_info->framedrop_pattern,
 		vfe_dev->vfe_base + stats_base + 0x10);
 	/*WR_IRQ_SUBSAMPLE_PATTERN*/
 	msm_camera_io_w(0xFFFFFFFF,
@@ -1189,11 +1196,9 @@
 		goto vfe_no_resource;
 	}
 
-	if (vfe_dev->pdev->id == 0)
-		vfe_dev->iommu_ctx[0] = msm_iommu_get_ctx("vfe0");
-	else if (vfe_dev->pdev->id == 1)
-		vfe_dev->iommu_ctx[0] = msm_iommu_get_ctx("vfe1");
-	if (!vfe_dev->iommu_ctx[0]) {
+	vfe_dev->iommu_ctx[0] = msm_iommu_get_ctx("vfe0");
+	vfe_dev->iommu_ctx[1] = msm_iommu_get_ctx("vfe1");
+	if (!vfe_dev->iommu_ctx[0] || !vfe_dev->iommu_ctx[1]) {
 		pr_err("%s: cannot get iommu_ctx\n", __func__);
 		rc = -ENODEV;
 		goto vfe_no_resource;
@@ -1245,7 +1250,7 @@
 };
 
 struct msm_vfe_hardware_info vfe40_hw_info = {
-	.num_iommu_ctx = 1,
+	.num_iommu_ctx = 2,
 	.vfe_clk_idx = VFE40_CLK_IDX,
 	.vfe_ops = {
 		.irq_ops = {
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index 477985d..728e172 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -389,31 +389,6 @@
 	msm_isp_send_event(vfe_dev, ISP_EVENT_SOF, &sof_event);
 }
 
-uint32_t msm_isp_get_framedrop_period(
-	enum msm_vfe_frame_skip_pattern frame_skip_pattern)
-{
-	switch (frame_skip_pattern) {
-	case NO_SKIP:
-	case EVERY_2FRAME:
-	case EVERY_3FRAME:
-	case EVERY_4FRAME:
-	case EVERY_5FRAME:
-	case EVERY_6FRAME:
-	case EVERY_7FRAME:
-	case EVERY_8FRAME:
-		return frame_skip_pattern + 1;
-	case EVERY_16FRAME:
-		return 16;
-		break;
-	case EVERY_32FRAME:
-		return 32;
-		break;
-	default:
-		return 1;
-	}
-	return 1;
-}
-
 void msm_isp_calculate_framedrop(
 	struct msm_vfe_axi_shared_data *axi_data,
 	struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd)
@@ -611,6 +586,13 @@
 				ACTIVE : INACTIVE;
 		}
 	}
+
+	if (vfe_dev->axi_data.pipeline_update == DISABLE_CAMIF) {
+		vfe_dev->hw_info->vfe_ops.stats_ops.
+			enable_module(vfe_dev, 0xFF, 0);
+		vfe_dev->axi_data.pipeline_update = NO_UPDATE;
+	}
+
 	vfe_dev->axi_data.stream_update--;
 	if (vfe_dev->axi_data.stream_update == 0)
 		complete(&vfe_dev->stream_config_complete);
@@ -849,12 +831,14 @@
 	return rc;
 }
 
-static int msm_isp_axi_wait_for_cfg_done(struct vfe_device *vfe_dev)
+static int msm_isp_axi_wait_for_cfg_done(struct vfe_device *vfe_dev,
+	enum msm_isp_camif_update_state camif_update)
 {
 	int rc;
 	unsigned long flags;
 	spin_lock_irqsave(&vfe_dev->shared_data_lock, flags);
 	init_completion(&vfe_dev->stream_config_complete);
+	vfe_dev->axi_data.pipeline_update = camif_update;
 	vfe_dev->axi_data.stream_update = 2;
 	spin_unlock_irqrestore(&vfe_dev->shared_data_lock, flags);
 	rc = wait_for_completion_interruptible_timeout(
@@ -958,7 +942,7 @@
 			update_camif_state(vfe_dev, camif_update);
 
 	if (wait_for_complete)
-		rc = msm_isp_axi_wait_for_cfg_done(vfe_dev);
+		rc = msm_isp_axi_wait_for_cfg_done(vfe_dev, camif_update);
 
 	return rc;
 }
@@ -976,7 +960,7 @@
 		stream_info->state = STOP_PENDING;
 	}
 
-	rc = msm_isp_axi_wait_for_cfg_done(vfe_dev);
+	rc = msm_isp_axi_wait_for_cfg_done(vfe_dev, camif_update);
 	if (rc < 0) {
 		pr_err("%s: wait for config done failed\n", __func__);
 		return rc;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
index c47209f..e08dea2 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
@@ -10,6 +10,7 @@
  * GNU General Public License for more details.
  */
 #include <linux/io.h>
+#include <linux/atomic.h>
 #include <media/v4l2-subdev.h>
 #include "msm_isp_util.h"
 #include "msm_isp_stats_util.h"
@@ -67,6 +68,7 @@
 	struct msm_isp_buffer *done_buf;
 	struct msm_vfe_stats_stream *stream_info = NULL;
 	uint32_t pingpong_status;
+	uint32_t comp_stats_type_mask = 0;
 	uint32_t stats_comp_mask = 0, stats_irq_mask = 0;
 	stats_comp_mask = vfe_dev->hw_info->vfe_ops.stats_ops.
 		get_comp_mask(irq_status0, irq_status1);
@@ -76,13 +78,17 @@
 		return;
 	ISP_DBG("%s: status: 0x%x\n", __func__, irq_status0);
 
-	if (vfe_dev->stats_data.stats_pipeline_policy == STATS_COMP_ALL) {
-		if (!stats_comp_mask)
-			return;
-		stats_irq_mask = 0xFFFFFFFF;
-	}
+	if (!stats_comp_mask)
+		stats_irq_mask &=
+			~atomic_read(&vfe_dev->stats_data.stats_comp_mask);
+	else
+		stats_irq_mask |=
+			atomic_read(&vfe_dev->stats_data.stats_comp_mask);
 
 	memset(&buf_event, 0, sizeof(struct msm_isp_event_data));
+	buf_event.timestamp = ts->event_time;
+	buf_event.frame_id =
+		vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id;
 	pingpong_status = vfe_dev->hw_info->
 		vfe_ops.stats_ops.get_pingpong_status(vfe_dev);
 
@@ -98,22 +104,32 @@
 				done_buf->bufq_handle, done_buf->buf_idx,
 				&ts->buf_time, vfe_dev->axi_data.
 				src_info[VFE_PIX_0].frame_id);
-			if (rc == 0) {
-				stats_event->stats_mask |=
+			if (rc != 0)
+				continue;
+
+			stats_event->stats_buf_idxs[stream_info->stats_type] =
+				done_buf->buf_idx;
+			if (!stream_info->composite_flag) {
+				stats_event->stats_mask =
 					1 << stream_info->stats_type;
-				stats_event->stats_buf_idxs[
-					stream_info->stats_type] =
-					done_buf->buf_idx;
+				ISP_DBG("%s: stats event frame id: 0x%x\n",
+					__func__, buf_event.frame_id);
+				msm_isp_send_event(vfe_dev,
+					ISP_EVENT_STATS_NOTIFY +
+					stream_info->stats_type, &buf_event);
+			} else {
+				comp_stats_type_mask |=
+					1 << stream_info->stats_type;
 			}
 		}
 	}
 
-	if (stats_event->stats_mask) {
-		buf_event.timestamp = ts->event_time;
-		buf_event.frame_id =
-			vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id;
-		msm_isp_send_event(vfe_dev, ISP_EVENT_STATS_NOTIFY +
-				stream_info->stats_type, &buf_event);
+	if (comp_stats_type_mask) {
+		ISP_DBG("%s: composite stats event frame id: 0x%x mask: 0x%x\n",
+			__func__, buf_event.frame_id, comp_stats_type_mask);
+		stats_event->stats_mask = comp_stats_type_mask;
+		msm_isp_send_event(vfe_dev,
+			ISP_EVENT_COMP_STATS_NOTIFY, &buf_event);
 	}
 }
 
@@ -140,36 +156,19 @@
 		return rc;
 	}
 
-	if (stats_data->stats_pipeline_policy != STATS_COMP_ALL) {
-		if (stream_req_cmd->framedrop_pattern >= MAX_SKIP) {
-			pr_err("%s: Invalid framedrop pattern\n", __func__);
-			return rc;
-		}
+	if (stream_req_cmd->framedrop_pattern >= MAX_SKIP) {
+		pr_err("%s: Invalid framedrop pattern\n", __func__);
+		return rc;
+	}
 
-		if (stream_req_cmd->irq_subsample_pattern >= MAX_SKIP) {
-			pr_err("%s: Invalid irq subsample pattern\n", __func__);
-			return rc;
-		}
-	} else {
-		if (stats_data->comp_framedrop_pattern >= MAX_SKIP) {
-			pr_err("%s: Invalid comp framedrop pattern\n",
-				__func__);
-			return rc;
-		}
-
-		if (stats_data->comp_irq_subsample_pattern >= MAX_SKIP) {
-			pr_err("%s: Invalid comp irq subsample pattern\n",
-				__func__);
-			return rc;
-		}
-		stream_req_cmd->framedrop_pattern =
-			vfe_dev->stats_data.comp_framedrop_pattern;
-		stream_req_cmd->irq_subsample_pattern =
-			vfe_dev->stats_data.comp_irq_subsample_pattern;
+	if (stream_req_cmd->irq_subsample_pattern >= MAX_SKIP) {
+		pr_err("%s: Invalid irq subsample pattern\n", __func__);
+		return rc;
 	}
 
 	stream_info->session_id = stream_req_cmd->session_id;
 	stream_info->stream_id = stream_req_cmd->stream_id;
+	stream_info->composite_flag = stream_req_cmd->composite_flag;
 	stream_info->stats_type = stream_req_cmd->stats_type;
 	stream_info->buffer_offset = stream_req_cmd->buffer_offset;
 	stream_info->framedrop_pattern = stream_req_cmd->framedrop_pattern;
@@ -193,6 +192,7 @@
 	struct msm_vfe_stats_stream_request_cmd *stream_req_cmd = arg;
 	struct msm_vfe_stats_stream *stream_info = NULL;
 	struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
+	uint32_t framedrop_period;
 	uint32_t stats_idx;
 
 	rc = msm_isp_stats_create_stream(vfe_dev, stream_req_cmd);
@@ -204,31 +204,12 @@
 	stats_idx = STATS_IDX(stream_req_cmd->stream_handle);
 	stream_info = &stats_data->stream_info[stats_idx];
 
-	switch (stream_info->framedrop_pattern) {
-	case NO_SKIP:
-		stream_info->framedrop_pattern = VFE_NO_DROP;
-		break;
-	case EVERY_2FRAME:
-		stream_info->framedrop_pattern = VFE_DROP_EVERY_2FRAME;
-		break;
-	case EVERY_4FRAME:
-		stream_info->framedrop_pattern = VFE_DROP_EVERY_4FRAME;
-		break;
-	case EVERY_8FRAME:
-		stream_info->framedrop_pattern = VFE_DROP_EVERY_8FRAME;
-		break;
-	case EVERY_16FRAME:
-		stream_info->framedrop_pattern = VFE_DROP_EVERY_16FRAME;
-		break;
-	case EVERY_32FRAME:
-		stream_info->framedrop_pattern = VFE_DROP_EVERY_32FRAME;
-		break;
-	default:
-		stream_info->framedrop_pattern = VFE_NO_DROP;
-		break;
-	}
+	framedrop_period = msm_isp_get_framedrop_period(
+	   stream_req_cmd->framedrop_pattern);
+	stream_info->framedrop_pattern = 0x1;
+	stream_info->framedrop_period = framedrop_period - 1;
 
-	if (stats_data->stats_pipeline_policy == STATS_COMP_NONE)
+	if (!stream_info->composite_flag)
 		vfe_dev->hw_info->vfe_ops.stats_ops.
 			cfg_wm_irq_mask(vfe_dev, stream_info);
 
@@ -257,7 +238,7 @@
 		rc = msm_isp_cfg_stats_stream(vfe_dev, &stream_cfg_cmd);
 	}
 
-	if (stats_data->stats_pipeline_policy == STATS_COMP_NONE)
+	if (!stream_info->composite_flag)
 		vfe_dev->hw_info->vfe_ops.stats_ops.
 			clear_wm_irq_mask(vfe_dev, stream_info);
 
@@ -266,18 +247,145 @@
 	return 0;
 }
 
-int msm_isp_cfg_stats_stream(struct vfe_device *vfe_dev, void *arg)
+static int msm_isp_init_stats_ping_pong_reg(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_stats_stream *stream_info)
+{
+	int rc = 0;
+	stream_info->bufq_handle =
+		vfe_dev->buf_mgr->ops->get_bufq_handle(
+		vfe_dev->buf_mgr, stream_info->session_id,
+		stream_info->stream_id);
+	if (stream_info->bufq_handle == 0) {
+		pr_err("%s: no buf configured for stream: 0x%x\n",
+			__func__, stream_info->stream_handle);
+		return -EINVAL;
+	}
+
+	rc = msm_isp_stats_cfg_ping_pong_address(vfe_dev,
+		stream_info, VFE_PING_FLAG, NULL);
+	if (rc < 0) {
+		pr_err("%s: No free buffer for ping\n", __func__);
+		return rc;
+	}
+	rc = msm_isp_stats_cfg_ping_pong_address(vfe_dev,
+		stream_info, VFE_PONG_FLAG, NULL);
+	if (rc < 0) {
+		pr_err("%s: No free buffer for pong\n", __func__);
+		return rc;
+	}
+	return rc;
+}
+
+void msm_isp_stats_stream_update(struct vfe_device *vfe_dev)
+{
+	int i;
+	uint32_t stats_mask = 0, comp_stats_mask = 0;
+	uint32_t enable = 0;
+	struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
+	for (i = 0; i < vfe_dev->hw_info->stats_hw_info->num_stats_type; i++) {
+		if (stats_data->stream_info[i].state == STATS_START_PENDING ||
+				stats_data->stream_info[i].state ==
+					STATS_STOP_PENDING) {
+			stats_mask |= i;
+			enable = stats_data->stream_info[i].state ==
+				STATS_START_PENDING ? 1 : 0;
+			stats_data->stream_info[i].state =
+				stats_data->stream_info[i].state ==
+				STATS_START_PENDING ?
+				STATS_STARTING : STATS_STOPPING;
+			vfe_dev->hw_info->vfe_ops.stats_ops.enable_module(
+				vfe_dev, BIT(i), enable);
+			vfe_dev->hw_info->vfe_ops.stats_ops.cfg_comp_mask(
+			   vfe_dev, BIT(i), enable);
+		} else if (stats_data->stream_info[i].state == STATS_STARTING ||
+			stats_data->stream_info[i].state == STATS_STOPPING) {
+			if (stats_data->stream_info[i].composite_flag)
+				comp_stats_mask |= i;
+			if (stats_data->stream_info[i].state == STATS_STARTING)
+				atomic_add(BIT(i),
+					&stats_data->stats_comp_mask);
+			else
+				atomic_sub(BIT(i),
+					&stats_data->stats_comp_mask);
+			stats_data->stream_info[i].state =
+				stats_data->stream_info[i].state ==
+				STATS_STARTING ? STATS_ACTIVE : STATS_INACTIVE;
+		}
+	}
+	atomic_sub(1, &stats_data->stats_update);
+	if (!atomic_read(&stats_data->stats_update))
+		complete(&vfe_dev->stats_config_complete);
+}
+
+static int msm_isp_stats_wait_for_cfg_done(struct vfe_device *vfe_dev)
+{
+	int rc;
+	init_completion(&vfe_dev->stats_config_complete);
+	atomic_set(&vfe_dev->stats_data.stats_update, 2);
+	rc = wait_for_completion_interruptible_timeout(
+		&vfe_dev->stats_config_complete,
+		msecs_to_jiffies(500));
+	if (rc == 0) {
+		pr_err("%s: wait timeout\n", __func__);
+		rc = -1;
+	} else {
+		rc = 0;
+	}
+	return rc;
+}
+
+static int msm_isp_start_stats_stream(struct vfe_device *vfe_dev,
+	struct msm_vfe_stats_stream_cfg_cmd *stream_cfg_cmd)
 {
 	int i, rc = 0;
-	struct msm_vfe_stats_stream_cfg_cmd *stream_cfg_cmd = arg;
+	uint32_t stats_mask = 0, comp_stats_mask = 0, idx;
 	struct msm_vfe_stats_stream *stream_info;
 	struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
-	int idx;
-	uint32_t stats_mask = 0;
+	for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
+		idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]);
+		stream_info = &stats_data->stream_info[idx];
+		if (stream_info->stream_handle !=
+				stream_cfg_cmd->stream_handle[i]) {
+			pr_err("%s: Invalid stream handle: 0x%x received\n",
+				__func__, stream_cfg_cmd->stream_handle[i]);
+			continue;
+		}
+		rc = msm_isp_init_stats_ping_pong_reg(vfe_dev, stream_info);
+		if (rc < 0) {
+			pr_err("%s: No buffer for stream%d\n", __func__, idx);
+			return rc;
+		}
 
-	if (stats_data->num_active_stream == 0)
-		vfe_dev->hw_info->vfe_ops.stats_ops.cfg_ub(vfe_dev);
+		if (vfe_dev->axi_data.src_info[VFE_PIX_0].active)
+			stream_info->state = STATS_START_PENDING;
+		else
+			stream_info->state = STATS_ACTIVE;
 
+		stats_data->num_active_stream++;
+		stats_mask |= 1 << idx;
+		if (stream_info->composite_flag)
+			comp_stats_mask |= 1 << idx;
+	}
+	if (vfe_dev->axi_data.src_info[VFE_PIX_0].active) {
+		rc = msm_isp_stats_wait_for_cfg_done(vfe_dev);
+	} else {
+		vfe_dev->hw_info->vfe_ops.stats_ops.enable_module(
+			vfe_dev, stats_mask, stream_cfg_cmd->enable);
+		atomic_add(comp_stats_mask, &stats_data->stats_comp_mask);
+		vfe_dev->hw_info->vfe_ops.stats_ops.cfg_comp_mask(
+		   vfe_dev, comp_stats_mask, 1);
+	}
+	return rc;
+}
+
+static int msm_isp_stop_stats_stream(struct vfe_device *vfe_dev,
+	struct msm_vfe_stats_stream_cfg_cmd *stream_cfg_cmd)
+{
+	int i, rc = 0;
+	uint32_t stats_mask = 0, comp_stats_mask = 0, idx;
+	struct msm_vfe_stats_stream *stream_info;
+	struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
 	for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
 		idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]);
 		stream_info = &stats_data->stream_info[idx];
@@ -288,71 +396,39 @@
 			continue;
 		}
 
-		if (stream_cfg_cmd->enable) {
-			stream_info->bufq_handle =
-				vfe_dev->buf_mgr->ops->get_bufq_handle(
-				vfe_dev->buf_mgr, stream_info->session_id,
-				stream_info->stream_id);
-				if (stream_info->bufq_handle == 0) {
-					pr_err("%s: no buf configured for stream: 0x%x\n",
-						__func__,
-						stream_info->stream_handle);
-					return -EINVAL;
-				}
-
-			msm_isp_stats_cfg_ping_pong_address(vfe_dev,
-				stream_info, VFE_PING_FLAG, NULL);
-			msm_isp_stats_cfg_ping_pong_address(vfe_dev,
-				stream_info, VFE_PONG_FLAG, NULL);
-			stream_info->state = STATS_START_PENDING;
-			stats_data->num_active_stream++;
-		} else {
+		if (vfe_dev->axi_data.src_info[VFE_PIX_0].active)
 			stream_info->state = STATS_STOP_PENDING;
-			stats_data->num_active_stream--;
-		}
+		else
+			stream_info->state = STATS_INACTIVE;
+
+		stats_data->num_active_stream--;
 		stats_mask |= 1 << idx;
+		if (stream_info->composite_flag)
+			comp_stats_mask |= 1 << idx;
 	}
-	vfe_dev->hw_info->vfe_ops.stats_ops.
-		enable_module(vfe_dev, stats_mask, stream_cfg_cmd->enable);
+	if (vfe_dev->axi_data.src_info[VFE_PIX_0].active) {
+		rc = msm_isp_stats_wait_for_cfg_done(vfe_dev);
+	} else {
+		vfe_dev->hw_info->vfe_ops.stats_ops.enable_module(
+			vfe_dev, stats_mask, stream_cfg_cmd->enable);
+		atomic_sub(comp_stats_mask, &stats_data->stats_comp_mask);
+		vfe_dev->hw_info->vfe_ops.stats_ops.cfg_comp_mask(
+		   vfe_dev, comp_stats_mask, 0);
+	}
 	return rc;
 }
 
-int msm_isp_cfg_stats_comp_policy(struct vfe_device *vfe_dev, void *arg)
+int msm_isp_cfg_stats_stream(struct vfe_device *vfe_dev, void *arg)
 {
-	int rc = -1;
-	struct msm_vfe_stats_comp_policy_cfg *policy_cfg_cmd = arg;
-	struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
+	int rc = 0;
+	struct msm_vfe_stats_stream_cfg_cmd *stream_cfg_cmd = arg;
+	if (vfe_dev->stats_data.num_active_stream == 0)
+		vfe_dev->hw_info->vfe_ops.stats_ops.cfg_ub(vfe_dev);
 
-	if (stats_data->num_active_stream != 0) {
-		pr_err("%s: Cannot update policy when there are active streams\n",
-			   __func__);
-		return rc;
-	}
+	if (stream_cfg_cmd->enable)
+		rc = msm_isp_start_stats_stream(vfe_dev, stream_cfg_cmd);
+	else
+		rc = msm_isp_stop_stats_stream(vfe_dev, stream_cfg_cmd);
 
-	if (policy_cfg_cmd->stats_pipeline_policy >= MAX_STATS_POLICY) {
-		pr_err("%s: Invalid stats composite policy\n", __func__);
-		return rc;
-	}
-
-	if (policy_cfg_cmd->comp_framedrop_pattern >= MAX_SKIP) {
-		pr_err("%s: Invalid comp framedrop pattern\n", __func__);
-		return rc;
-	}
-
-	if (policy_cfg_cmd->comp_irq_subsample_pattern >= MAX_SKIP) {
-		pr_err("%s: Invalid comp irq subsample pattern\n", __func__);
-		return rc;
-	}
-
-	stats_data->stats_pipeline_policy =
-		policy_cfg_cmd->stats_pipeline_policy;
-	stats_data->comp_framedrop_pattern =
-		policy_cfg_cmd->comp_framedrop_pattern;
-	stats_data->comp_irq_subsample_pattern =
-		policy_cfg_cmd->comp_irq_subsample_pattern;
-
-	vfe_dev->hw_info->vfe_ops.stats_ops.cfg_comp_mask(vfe_dev);
-
-	return 0;
+	return rc;
 }
-
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.h
index 13e1fd6..7b4c4b4 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.h
@@ -18,8 +18,8 @@
 void msm_isp_process_stats_irq(struct vfe_device *vfe_dev,
 	uint32_t irq_status0, uint32_t irq_status1,
 	struct msm_isp_timestamp *ts);
+void msm_isp_stats_stream_update(struct vfe_device *vfe_dev);
 int msm_isp_cfg_stats_stream(struct vfe_device *vfe_dev, void *arg);
 int msm_isp_release_stats_stream(struct vfe_device *vfe_dev, void *arg);
 int msm_isp_request_stats_stream(struct vfe_device *vfe_dev, void *arg);
-int msm_isp_cfg_stats_comp_policy(struct vfe_device *vfe_dev, void *arg);
 #endif /* __MSM_ISP_STATS_UTIL_H__ */
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
index 9fd87f3..c981901 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
@@ -12,6 +12,7 @@
 #include <linux/mutex.h>
 #include <linux/io.h>
 #include <media/v4l2-subdev.h>
+#include <linux/ratelimit.h>
 
 #include "msm.h"
 #include "msm_isp_util.h"
@@ -121,7 +122,7 @@
 	path->vectors[0].ab = MSM_ISP_MIN_AB;
 	path->vectors[0].ib = MSM_ISP_MIN_IB;
 	for (i = 0; i < MAX_ISP_CLIENT; i++) {
-		if (isp_bandwidth_mgr.client_info[client].active) {
+		if (isp_bandwidth_mgr.client_info[i].active) {
 			path->vectors[0].ab +=
 				isp_bandwidth_mgr.client_info[i].ab;
 			path->vectors[0].ib +=
@@ -154,6 +155,31 @@
 	mutex_unlock(&bandwidth_mgr_mutex);
 }
 
+uint32_t msm_isp_get_framedrop_period(
+	enum msm_vfe_frame_skip_pattern frame_skip_pattern)
+{
+	switch (frame_skip_pattern) {
+	case NO_SKIP:
+	case EVERY_2FRAME:
+	case EVERY_3FRAME:
+	case EVERY_4FRAME:
+	case EVERY_5FRAME:
+	case EVERY_6FRAME:
+	case EVERY_7FRAME:
+	case EVERY_8FRAME:
+		return frame_skip_pattern + 1;
+	case EVERY_16FRAME:
+		return 16;
+		break;
+	case EVERY_32FRAME:
+		return 32;
+		break;
+	default:
+		return 1;
+	}
+	return 1;
+}
+
 static inline void msm_isp_get_timestamp(struct msm_isp_timestamp *time_stamp)
 {
 	struct timespec ts;
@@ -355,11 +381,6 @@
 		rc = msm_isp_cfg_stats_stream(vfe_dev, arg);
 		mutex_unlock(&vfe_dev->core_mutex);
 		break;
-	case VIDIOC_MSM_ISP_CFG_STATS_COMP_POLICY:
-		mutex_lock(&vfe_dev->core_mutex);
-		rc = msm_isp_cfg_stats_comp_policy(vfe_dev, arg);
-		mutex_unlock(&vfe_dev->core_mutex);
-		break;
 	case VIDIOC_MSM_ISP_UPDATE_STREAM:
 		mutex_lock(&vfe_dev->core_mutex);
 		rc = msm_isp_update_axi_stream(vfe_dev, arg);
@@ -686,6 +707,11 @@
 {
 	int i;
 	struct msm_vfe_error_info *error_info = &vfe_dev->error_info;
+	static DEFINE_RATELIMIT_STATE(rs,
+		DEFAULT_RATELIMIT_INTERVAL, DEFAULT_RATELIMIT_BURST);
+	static DEFINE_RATELIMIT_STATE(rs_stats,
+		DEFAULT_RATELIMIT_INTERVAL, DEFAULT_RATELIMIT_BURST);
+
 	if (error_info->error_count == 1 ||
 		!(error_info->info_dump_frame_count % 100)) {
 		vfe_dev->hw_info->vfe_ops.core_ops.
@@ -695,7 +721,8 @@
 		error_info->camif_status = 0;
 		error_info->violation_status = 0;
 		for (i = 0; i < MAX_NUM_STREAM; i++) {
-			if (error_info->stream_framedrop_count[i] != 0) {
+			if (error_info->stream_framedrop_count[i] != 0 &&
+				__ratelimit(&rs)) {
 				pr_err("%s: Stream[%d]: dropped %d frames\n",
 					__func__, i,
 					error_info->stream_framedrop_count[i]);
@@ -703,7 +730,8 @@
 			}
 		}
 		for (i = 0; i < MSM_ISP_STATS_MAX; i++) {
-			if (error_info->stats_framedrop_count[i] != 0) {
+			if (error_info->stats_framedrop_count[i] != 0 &&
+				__ratelimit(&rs_stats)) {
 				pr_err("%s: Stats stream[%d]: dropped %d frames\n",
 					__func__, i,
 					error_info->stats_framedrop_count[i]);
@@ -750,7 +778,8 @@
 	spin_lock_irqsave(&vfe_dev->tasklet_lock, flags);
 	queue_cmd = &vfe_dev->tasklet_queue_cmd[vfe_dev->taskletq_idx];
 	if (queue_cmd->cmd_used) {
-		pr_err("%s: Tasklet queue overflow\n", __func__);
+		pr_err_ratelimited("%s: Tasklet queue overflow: %d\n",
+			__func__, vfe_dev->pdev->id);
 		list_del(&queue_cmd->list);
 	} else {
 		atomic_add(1, &vfe_dev->irq_cnt);
@@ -818,7 +847,6 @@
 
 int msm_isp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 {
-	uint32_t i;
 	struct vfe_device *vfe_dev = v4l2_get_subdevdata(sd);
 	long rc;
 	ISP_DBG("%s\n", __func__);
@@ -851,9 +879,6 @@
 
 	vfe_dev->hw_info->vfe_ops.core_ops.init_hw_reg(vfe_dev);
 
-	for (i = 0; i < vfe_dev->hw_info->num_iommu_ctx; i++)
-		vfe_dev->buf_mgr->ops->attach_ctx(vfe_dev->buf_mgr,
-			vfe_dev->iommu_ctx[i]);
 	vfe_dev->buf_mgr->ops->buf_mgr_init(vfe_dev->buf_mgr, "msm_isp", 28);
 
 	memset(&vfe_dev->axi_data, 0, sizeof(struct msm_vfe_axi_shared_data));
@@ -870,7 +895,6 @@
 
 int msm_isp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 {
-	int i;
 	long rc;
 	struct vfe_device *vfe_dev = v4l2_get_subdevdata(sd);
 	ISP_DBG("%s\n", __func__);
@@ -888,11 +912,6 @@
 		pr_err("%s: halt timeout\n", __func__);
 
 	vfe_dev->buf_mgr->ops->buf_mgr_deinit(vfe_dev->buf_mgr);
-
-	for (i = vfe_dev->hw_info->num_iommu_ctx - 1; i >= 0; i--)
-		vfe_dev->buf_mgr->ops->detach_ctx(vfe_dev->buf_mgr,
-			vfe_dev->iommu_ctx[i]);
-
 	vfe_dev->hw_info->vfe_ops.core_ops.release_hw(vfe_dev);
 
 	vfe_dev->vfe_open_cnt--;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h
index 7934f26..34b9859 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h
@@ -43,6 +43,9 @@
 	struct msm_isp_bandwidth_info client_info[MAX_ISP_CLIENT];
 };
 
+uint32_t msm_isp_get_framedrop_period(
+	enum msm_vfe_frame_skip_pattern frame_skip_pattern);
+
 int msm_isp_init_bandwidth_mgr(enum msm_isp_hw_client client);
 int msm_isp_update_bandwidth(enum msm_isp_hw_client client,
 	uint64_t ab, uint64_t ib);
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 9dcd64c..962c079 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
@@ -11,7 +11,6 @@
  */
 
 #include <linux/delay.h>
-#include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/jiffies.h>
@@ -60,113 +59,6 @@
 		false : true;
 }
 
-static struct msm_cam_clk_info ispif_8960_clk_info[] = {
-	{"csi_pix_clk", 0},
-	{"csi_rdi_clk", 0},
-	{"csi_pix1_clk", 0},
-	{"csi_rdi1_clk", 0},
-	{"csi_rdi2_clk", 0},
-};
-
-static struct msm_cam_clk_info ispif_8974_clk_info_vfe0[] = {
-	{"camss_vfe_vfe_clk", -1},
-	{"camss_csi_vfe_clk", -1},
-};
-
-static struct msm_cam_clk_info ispif_8974_clk_info_vfe1[] = {
-	{"camss_vfe_vfe_clk1", -1},
-	{"camss_csi_vfe_clk1", -1},
-};
-
-static int msm_ispif_clk_enable_one(struct ispif_device *ispif,
-	enum msm_ispif_vfe_intf vfe_intf, int enable)
-{
-	int rc = 0;
-
-	if (enable)
-		pr_debug("enable clk for VFE%d\n", vfe_intf);
-	else
-		pr_debug("disable clk for VFE%d\n", vfe_intf);
-
-	if (ispif->csid_version < CSID_VERSION_V2) {
-		rc = msm_cam_clk_enable(&ispif->pdev->dev, ispif_8960_clk_info,
-			ispif->ispif_clk[vfe_intf], 2, enable);
-		if (rc) {
-			pr_err("%s: cannot enable clock, error = %d\n",
-				__func__, rc);
-			goto end;
-		}
-	} else if (ispif->csid_version == CSID_VERSION_V2) {
-		rc = msm_cam_clk_enable(&ispif->pdev->dev, ispif_8960_clk_info,
-			ispif->ispif_clk[vfe_intf],
-			ARRAY_SIZE(ispif_8960_clk_info),
-			enable);
-		if (rc) {
-			pr_err("%s: cannot enable clock, error = %d\n",
-				__func__, rc);
-			goto end;
-		}
-	} else if (ispif->csid_version >= CSID_VERSION_V3) {
-		if (vfe_intf == VFE0) {
-			rc = msm_cam_clk_enable(&ispif->pdev->dev,
-				ispif_8974_clk_info_vfe0,
-				ispif->ispif_clk[vfe_intf],
-				ARRAY_SIZE(ispif_8974_clk_info_vfe0), enable);
-		} else {
-			rc = msm_cam_clk_enable(&ispif->pdev->dev,
-				ispif_8974_clk_info_vfe1,
-				ispif->ispif_clk[vfe_intf],
-				ARRAY_SIZE(ispif_8974_clk_info_vfe1), enable);
-		}
-		if (rc) {
-			pr_err("%s: cannot enable clock, error = %d, vfeid = %d\n",
-				__func__, rc, vfe_intf);
-			goto end;
-		}
-	} else {
-		pr_err("%s: unsupported version=%d\n", __func__,
-			ispif->csid_version);
-		goto end;
-	}
-
-end:
-	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 struct msm_cam_clk_info ispif_8974_ahb_clk_info[] = {
 	{"ispif_ahb_clk", -1},
 };
@@ -191,139 +83,51 @@
 	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;
-	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->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);
-			break;
-		case RDI0:
-			data |= (RDI_0_VFE_RST_STB | RDI_0_CSID_RST_STB);
-			break;
-		case PIX1:
-			data |= (PIX_1_VFE_RST_STB | PIX_1_CSID_RST_STB);
-			break;
-		case RDI1:
-			data |= (RDI_1_VFE_RST_STB | RDI_1_CSID_RST_STB);
-			break;
-		case RDI2:
-			data |= (RDI_2_VFE_RST_STB | RDI_2_CSID_RST_STB);
-			break;
-		default:
-			rc = -EINVAL;
-			break;
-		}
-		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[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;
-}
-
 static int msm_ispif_reset(struct ispif_device *ispif)
 {
 	int rc = 0;
-	long lrc = 0;
-	unsigned long jiffes = msecs_to_jiffies(500);
-	unsigned long flags;
-
-	spin_lock_irqsave(&ispif->auto_complete_lock, flags);
-	ispif->wait_timeout[VFE0] = 0;
-	init_completion(&ispif->reset_complete[VFE0]);
-	if (ispif->csid_version >= CSID_VERSION_V3 &&
-		ispif->vfe_info.num_vfe > 1) {
-		ispif->wait_timeout[VFE1] = 0;
-		init_completion(&ispif->reset_complete[VFE1]);
-	}
-	spin_unlock_irqrestore(&ispif->auto_complete_lock, flags);
+	int i;
 
 	BUG_ON(!ispif);
 
 	memset(ispif->sof_count, 0, sizeof(ispif->sof_count));
 
-	msm_camera_io_w(ISPIF_RST_CMD_MASK, ispif->base + ISPIF_RST_CMD_ADDR);
+	for (i = 0; i < ispif->vfe_info.num_vfe; i++) {
 
-	lrc = wait_for_completion_interruptible_timeout(
-		&ispif->reset_complete[VFE0], jiffes);
+		msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_CTRL_0(i));
+		msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_IRQ_MASK_0(i));
+		msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_IRQ_MASK_1(i));
+		msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_IRQ_MASK_2(i));
+		msm_camera_io_w(0xFFFFFFFF, ispif->base +
+			ISPIF_VFE_m_IRQ_CLEAR_0(i));
+		msm_camera_io_w(0xFFFFFFFF, ispif->base +
+			ISPIF_VFE_m_IRQ_CLEAR_1(i));
+		msm_camera_io_w(0xFFFFFFFF, ispif->base +
+			ISPIF_VFE_m_IRQ_CLEAR_2(i));
+		msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_INPUT_SEL(i));
+		msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_INTF_CMD_0(i));
+		msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_INTF_CMD_1(i));
 
-	if (lrc < 0 || !lrc) {
-		pr_err("%s: wait timeout ret = %ld, vfeid = %d\n",
-			__func__, lrc, VFE0);
-		rc = -EIO;
+		msm_camera_io_w(0, ispif->base +
+			ISPIF_VFE_m_PIX_INTF_n_CID_MASK(i, 0));
+		msm_camera_io_w(0, ispif->base +
+			ISPIF_VFE_m_PIX_INTF_n_CID_MASK(i, 1));
+		msm_camera_io_w(0, ispif->base +
+			ISPIF_VFE_m_PIX_INTF_n_CID_MASK(i, 0));
+		msm_camera_io_w(0, ispif->base +
+			ISPIF_VFE_m_PIX_INTF_n_CID_MASK(i, 1));
+		msm_camera_io_w(0, ispif->base +
+			ISPIF_VFE_m_PIX_INTF_n_CID_MASK(i, 2));
 
-		spin_lock_irqsave(&ispif->auto_complete_lock, flags);
-		ispif->wait_timeout[VFE0] = 1;
-		spin_unlock_irqrestore(&ispif->auto_complete_lock, flags);
-
-		goto end;
+		msm_camera_io_w(0, ispif->base +
+			ISPIF_VFE_m_PIX_INTF_n_CROP(i, 0));
+		msm_camera_io_w(0, ispif->base +
+			ISPIF_VFE_m_PIX_INTF_n_CROP(i, 1));
 	}
 
-	if (ispif->csid_version >= CSID_VERSION_V3 &&
-		ispif->vfe_info.num_vfe > 1) {
-		msm_camera_io_w_mb(ISPIF_RST_CMD_1_MASK, ispif->base +
-			ISPIF_RST_CMD_1_ADDR);
+	msm_camera_io_w_mb(ISPIF_IRQ_GLOBAL_CLEAR_CMD, ispif->base +
+		ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR);
 
-		lrc = wait_for_completion_interruptible_timeout(
-			&ispif->reset_complete[VFE1], jiffes);
-
-		if (lrc < 0 || !lrc) {
-			pr_err("%s: wait timeout ret = %ld, vfeid = %d\n",
-				__func__, lrc, VFE1);
-			rc = -EIO;
-
-			spin_lock_irqsave(&ispif->auto_complete_lock, flags);
-			ispif->wait_timeout[VFE1] = 1;
-			spin_unlock_irqrestore(&ispif->auto_complete_lock,
-				flags);
-		}
-
-	}
-
-end:
 	return rc;
 }
 
@@ -339,7 +143,6 @@
 static void msm_ispif_sel_csid_core(struct ispif_device *ispif,
 	uint8_t intftype, uint8_t csid, uint8_t vfe_intf)
 {
-	int rc = 0;
 	uint32_t data;
 
 	BUG_ON(!ispif);
@@ -349,19 +152,6 @@
 		return;
 	}
 
-	if (ispif->csid_version <= CSID_VERSION_V2) {
-		if (ispif->ispif_clk[vfe_intf][intftype] == NULL) {
-			CDBG("%s: ispif NULL clk\n", __func__);
-			return;
-		}
-
-		rc = clk_set_rate(ispif->ispif_clk[vfe_intf][intftype], csid);
-		if (rc) {
-			pr_err("%s: clk_set_rate failed %d\n", __func__, rc);
-			return;
-		}
-	}
-
 	data = msm_camera_io_r(ispif->base + ISPIF_VFE_m_INPUT_SEL(vfe_intf));
 	switch (intftype) {
 	case PIX0:
@@ -385,9 +175,9 @@
 		data |= (csid << 20);
 		break;
 	}
-	if (data)
-		msm_camera_io_w_mb(data, ispif->base +
-			ISPIF_VFE_m_INPUT_SEL(vfe_intf));
+
+	msm_camera_io_w_mb(data, ispif->base +
+		ISPIF_VFE_m_INPUT_SEL(vfe_intf));
 }
 
 static void msm_ispif_enable_crop(struct ispif_device *ispif,
@@ -504,6 +294,58 @@
 	return rc;
 }
 
+static void msm_ispif_select_clk_mux(struct ispif_device *ispif,
+	uint8_t intftype, uint8_t csid, uint8_t vfe_intf)
+{
+	uint32_t data = 0;
+
+	switch (intftype) {
+	case PIX0:
+		data = msm_camera_io_r(ispif->clk_mux_base);
+		data &= ~(0xf << (vfe_intf * 8));
+		data |= (csid << (vfe_intf * 8));
+		msm_camera_io_w(data, ispif->clk_mux_base);
+		break;
+
+	case RDI0:
+		data = msm_camera_io_r(ispif->clk_mux_base +
+			ISPIF_RDI_CLK_MUX_SEL_ADDR);
+		data &= ~(0xf << (vfe_intf * 12));
+		data |= (csid << (vfe_intf * 12));
+		msm_camera_io_w(data, ispif->clk_mux_base +
+			ISPIF_RDI_CLK_MUX_SEL_ADDR);
+		break;
+
+	case PIX1:
+		data = msm_camera_io_r(ispif->clk_mux_base);
+		data &= ~(0xf0 << (vfe_intf * 8));
+		data |= (csid << (4 + (vfe_intf * 8)));
+		msm_camera_io_w(data, ispif->clk_mux_base);
+		break;
+
+	case RDI1:
+		data = msm_camera_io_r(ispif->clk_mux_base +
+			ISPIF_RDI_CLK_MUX_SEL_ADDR);
+		data &= ~(0xf << (4 + (vfe_intf * 12)));
+		data |= (csid << (4 + (vfe_intf * 12)));
+		msm_camera_io_w(data, ispif->clk_mux_base +
+			ISPIF_RDI_CLK_MUX_SEL_ADDR);
+		break;
+
+	case RDI2:
+		data = msm_camera_io_r(ispif->clk_mux_base +
+			ISPIF_RDI_CLK_MUX_SEL_ADDR);
+		data &= ~(0xf << (8 + (vfe_intf * 12)));
+		data |= (csid << (8 + (vfe_intf * 12)));
+		msm_camera_io_w(data, ispif->clk_mux_base +
+			ISPIF_RDI_CLK_MUX_SEL_ADDR);
+		break;
+	}
+	CDBG("%s intftype %d data %x\n", __func__, intftype, data);
+	mb();
+	return;
+}
+
 static uint16_t msm_ispif_get_cids_mask_from_cfg(
 	struct msm_ispif_params_entry *entry)
 {
@@ -536,11 +378,6 @@
 		return rc;
 	}
 
-	rc = msm_ispif_clk_enable(ispif, params, 1);
-	if (rc < 0) {
-		pr_err("%s: unable to enable clocks", __func__);
-		return rc;
-	}
 	for (i = 0; i < params->num; i++) {
 		vfe_intf = params->entries[i].vfe_intf;
 		if (!msm_ispif_is_intf_valid(ispif->csid_version,
@@ -573,6 +410,10 @@
 			return -EINVAL;
 		}
 
+		if (ispif->csid_version >= CSID_VERSION_V3)
+				msm_ispif_select_clk_mux(ispif, intftype,
+				params->entries[i].csid, vfe_intf);
+
 		rc = msm_ispif_validate_intf_status(ispif, intftype, vfe_intf);
 		if (rc) {
 			pr_err("%s:validate_intf_status failed, rc = %d\n",
@@ -615,8 +456,6 @@
 	msm_camera_io_w_mb(ISPIF_IRQ_GLOBAL_CLEAR_CMD, ispif->base +
 		ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR);
 
-	msm_ispif_clk_enable(ispif, params, 0);
-
 	return rc;
 }
 
@@ -709,7 +548,7 @@
 static int msm_ispif_start_frame_boundary(struct ispif_device *ispif,
 	struct msm_ispif_param_data *params)
 {
-	int rc;
+	int rc = 0;
 
 	if (ispif->ispif_state != ISPIF_POWER_UP) {
 		pr_err("%s: ispif invalid state %d\n", __func__,
@@ -718,23 +557,8 @@
 		return rc;
 	}
 
-	rc = msm_ispif_clk_enable(ispif, params, 1);
-	if (rc < 0) {
-		pr_err("%s: unable to enable clocks", __func__);
-		return rc;
-	}
-
-	rc = msm_ispif_intf_reset(ispif, params);
-	if (rc) {
-		pr_err("%s: msm_ispif_intf_reset failed. rc=%d\n",
-			__func__, rc);
-		goto end;
-	}
-
 	msm_ispif_intf_cmd(ispif, ISPIF_INTF_CMD_ENABLE_FRAME_BOUNDARY, params);
 
-end:
-	msm_ispif_clk_enable(ispif, params, 0);
 	return rc;
 }
 
@@ -757,12 +581,6 @@
 		return rc;
 	}
 
-	rc = msm_ispif_clk_enable(ispif, params, 1);
-	if (rc < 0) {
-		pr_err("%s: unable to enable clocks", __func__);
-		return rc;
-	}
-
 	for (i = 0; i < params->num; i++) {
 		if (!msm_ispif_is_intf_valid(ispif->csid_version,
 				params->entries[i].vfe_intf)) {
@@ -814,8 +632,6 @@
 	}
 
 end:
-	msm_ispif_clk_enable(ispif, params, 0);
-
 	return rc;
 }
 
@@ -886,15 +702,6 @@
 	ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR);
 
 	if (out[VFE0].ispifIrqStatus0 & ISPIF_IRQ_STATUS_MASK) {
-		if (out[VFE0].ispifIrqStatus0 & RESET_DONE_IRQ) {
-			unsigned long flags;
-			spin_lock_irqsave(&ispif->auto_complete_lock, flags);
-			if (ispif->wait_timeout[VFE0] == 0)
-				complete(&ispif->reset_complete[VFE0]);
-			spin_unlock_irqrestore(
-				&ispif->auto_complete_lock, flags);
-		}
-
 		if (out[VFE0].ispifIrqStatus0 & PIX_INTF_0_OVERFLOW_IRQ)
 			pr_err("%s: VFE0 pix0 overflow.\n", __func__);
 
@@ -910,15 +717,6 @@
 		ispif_process_irq(ispif, out, VFE0);
 	}
 	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);
-			if (ispif->wait_timeout[VFE1] == 0)
-				complete(&ispif->reset_complete[VFE1]);
-			spin_unlock_irqrestore(
-				&ispif->auto_complete_lock, flags);
-		}
-
 		if (out[VFE1].ispifIrqStatus0 & PIX_INTF_0_OVERFLOW_IRQ)
 			pr_err("%s: VFE1 pix0 overflow.\n", __func__);
 
@@ -973,19 +771,20 @@
 	memset(ispif->sof_count, 0, sizeof(ispif->sof_count));
 
 	ispif->csid_version = csid_version;
-	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;
-	}
 
-	if (ispif->csid_version >= CSID_VERSION_V3 &&
-		ispif->vfe_info.num_vfe > 1) {
-		rc = msm_ispif_clk_enable_one(ispif, VFE1, 1);
-		if (rc < 0) {
-			pr_err("%s: unable to enable clocks for VFE1",
-				__func__);
-			goto error_clk1;
+	if (ispif->csid_version >= CSID_VERSION_V3) {
+		if (!ispif->clk_mux_mem || !ispif->clk_mux_io) {
+			pr_err("%s csi clk mux mem %p io %p\n", __func__,
+				ispif->clk_mux_mem, ispif->clk_mux_io);
+			rc = -ENOMEM;
+			return rc;
+		}
+		ispif->clk_mux_base = ioremap(ispif->clk_mux_mem->start,
+			resource_size(ispif->clk_mux_mem));
+		if (!ispif->clk_mux_base) {
+			pr_err("%s: clk_mux_mem ioremap failed\n", __func__);
+			rc = -ENOMEM;
+			return rc;
 		}
 	}
 
@@ -1022,20 +821,11 @@
 	iounmap(ispif->base);
 
 end:
-	if (ispif->csid_version >= CSID_VERSION_V3 &&
-		ispif->vfe_info.num_vfe > 1)
-		msm_ispif_clk_enable_one(ispif, VFE1, 0);
-
-error_clk1:
-	msm_ispif_clk_enable_one(ispif, VFE0, 0);
-
-error_clk0:
 	return rc;
 }
 
 static void msm_ispif_release(struct ispif_device *ispif)
 {
-	int i;
 	BUG_ON(!ispif);
 
 	if (ispif->ispif_state != ISPIF_POWER_UP) {
@@ -1044,9 +834,6 @@
 		return;
 	}
 
-	for (i = 0; i < ispif->vfe_info.num_vfe; i++)
-		msm_ispif_clk_enable_one(ispif, i, 1);
-
 	/* make sure no streaming going on */
 	msm_ispif_reset(ispif);
 
@@ -1056,8 +843,7 @@
 
 	iounmap(ispif->base);
 
-	for (i = 0; i < ispif->vfe_info.num_vfe; i++)
-		msm_ispif_clk_enable_one(ispif, i, 0);
+	iounmap(ispif->clk_mux_base);
 
 	ispif->ispif_state = ISPIF_POWER_DOWN;
 }
@@ -1177,7 +963,6 @@
 {
 	int rc;
 	struct ispif_device *ispif;
-	int i;
 
 	ispif = kzalloc(sizeof(struct ispif_device), GFP_KERNEL);
 	if (!ispif) {
@@ -1231,13 +1016,20 @@
 		rc = -EBUSY;
 		goto error;
 	}
+	ispif->clk_mux_mem = platform_get_resource_byname(pdev,
+		IORESOURCE_MEM, "csi_clk_mux");
+	if (ispif->clk_mux_mem) {
+		ispif->clk_mux_io = request_mem_region(
+			ispif->clk_mux_mem->start,
+			resource_size(ispif->clk_mux_mem),
+			ispif->clk_mux_mem->name);
+		if (!ispif->clk_mux_io)
+			pr_err("%s: no valid csi_mux region\n", __func__);
+	}
 
 	ispif->pdev = pdev;
 	ispif->ispif_state = ISPIF_POWER_DOWN;
 	ispif->open_cnt = 0;
-	spin_lock_init(&ispif->auto_complete_lock);
-	for (i = 0; i < VFE_MAX; i++)
-		ispif->wait_timeout[i] = 0;
 
 	return 0;
 
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.h b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.h
index 945b5b8..faa32aa 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.h
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.h
@@ -42,21 +42,20 @@
 	struct platform_device *pdev;
 	struct msm_sd_subdev msm_sd;
 	struct resource *mem;
+	struct resource *clk_mux_mem;
 	struct resource *irq;
 	struct resource *io;
+	struct resource *clk_mux_io;
 	void __iomem *base;
+	void __iomem *clk_mux_base;
 	struct mutex mutex;
 	uint8_t start_ack_pending;
-	struct completion reset_complete[VFE_MAX];
-	spinlock_t auto_complete_lock;
-	uint8_t wait_timeout[VFE_MAX];
 	uint32_t csid_version;
 	int enb_dump_reg;
 	uint32_t open_cnt;
 	struct ispif_sof_count sof_count[VFE_MAX];
 	struct ispif_intf_cmd applied_intf_cmd[VFE_MAX];
 	enum msm_ispif_state_t ispif_state;
-	struct clk *ispif_clk[VFE_MAX][INTF_MAX];
 	struct msm_ispif_vfe_info vfe_info;
 	struct clk *ahb_clk;
 };
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v1.h b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v1.h
index 9f8b2fa..6396486 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v1.h
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v1.h
@@ -50,6 +50,8 @@
 
 
 
+/* CSID CLK MUX SEL REGISTERS */
+#define ISPIF_RDI_CLK_MUX_SEL_ADDR              0x8
 
 /*ISPIF RESET BITS*/
 #define VFE_CLK_DOMAIN_RST                 BIT(31)
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v2.h b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v2.h
index 5e61a4d..c805c3d 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v2.h
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v2.h
@@ -46,6 +46,9 @@
 #define ISPIF_VFE_m_RDI_INTF_n_STATUS(m, n)      (0x2D0 + ISPIF_VFE(m) + 4*(n))
 #define ISPIF_VFE_m_3D_DESKEW_SIZE(m)            (0x2E4 + ISPIF_VFE(m))
 
+/* CSID CLK MUX SEL REGISTERS */
+#define ISPIF_RDI_CLK_MUX_SEL_ADDR               0x8
+
 /*ISPIF RESET BITS*/
 #define VFE_CLK_DOMAIN_RST                       BIT(31)
 #define PIX_1_CLK_DOMAIN_RST                     BIT(30)
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 1203d17..8cdaa4b 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
@@ -588,7 +588,7 @@
 		pr_err("%s: Bandwidth registration Failed!\n", __func__);
 		goto bus_scale_register_failed;
 	}
-	msm_isp_update_bandwidth(ISP_CPP, 981345600, 1600020000);
+	msm_isp_update_bandwidth(ISP_CPP, 981345600, 1066680000);
 
 	if (cpp_dev->fs_cpp == NULL) {
 		cpp_dev->fs_cpp =
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 fbd4a2e..33eaa69 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
@@ -185,49 +185,15 @@
 	{"csi_pclk", -1},
 };
 
-static struct msm_cam_clk_info csid0_8974_clk_info[] = {
+static struct msm_cam_clk_info csid_8974_clk_info[] = {
 	{"camss_top_ahb_clk", -1},
 	{"ispif_ahb_clk", -1},
-	{"csi0_ahb_clk", -1},
-	{"csi0_src_clk", 200000000},
-	{"csi0_clk", -1},
-	{"csi0_phy_clk", -1},
-	{"csi0_pix_clk", -1},
-	{"csi0_rdi_clk", -1},
-};
-
-static struct msm_cam_clk_info csid1_8974_clk_info[] = {
-	{"csi1_ahb_clk", -1},
-	{"csi1_src_clk", 200000000},
-	{"csi1_clk", -1},
-	{"csi1_phy_clk", -1},
-	{"csi1_pix_clk", -1},
-	{"csi1_rdi_clk", -1},
-};
-
-static struct msm_cam_clk_info csid2_8974_clk_info[] = {
-	{"csi2_ahb_clk", -1},
-	{"csi2_src_clk", 200000000},
-	{"csi2_clk", -1},
-	{"csi2_phy_clk", -1},
-	{"csi2_pix_clk", -1},
-	{"csi2_rdi_clk", -1},
-};
-
-static struct msm_cam_clk_info csid3_8974_clk_info[] = {
-	{"csi3_ahb_clk", -1},
-	{"csi3_src_clk", 200000000},
-	{"csi3_clk", -1},
-	{"csi3_phy_clk", -1},
-	{"csi3_pix_clk", -1},
-	{"csi3_rdi_clk", -1},
-};
-
-static struct msm_cam_clk_setting csid_8974_clk_info[] = {
-	{&csid0_8974_clk_info[0], ARRAY_SIZE(csid0_8974_clk_info)},
-	{&csid1_8974_clk_info[0], ARRAY_SIZE(csid1_8974_clk_info)},
-	{&csid2_8974_clk_info[0], ARRAY_SIZE(csid2_8974_clk_info)},
-	{&csid3_8974_clk_info[0], ARRAY_SIZE(csid3_8974_clk_info)},
+	{"csi_ahb_clk", -1},
+	{"csi_src_clk", 200000000},
+	{"csi_clk", -1},
+	{"csi_phy_clk", -1},
+	{"csi_pix_clk", -1},
+	{"csi_rdi_clk", -1},
 };
 
 static struct camera_vreg_t csid_8960_vreg_info[] = {
@@ -241,7 +207,6 @@
 static int msm_csid_init(struct csid_device *csid_dev, uint32_t *csid_version)
 {
 	int rc = 0;
-	uint8_t core_id = 0;
 
 	if (!csid_version) {
 		pr_err("%s:%d csid_version NULL\n", __func__, __LINE__);
@@ -306,26 +271,14 @@
 		}
 
 		rc = msm_cam_clk_enable(&csid_dev->pdev->dev,
-			csid_8974_clk_info[0].clk_info, csid_dev->csid0_clk,
-			csid_8974_clk_info[0].num_clk_info, 1);
+			csid_8974_clk_info, csid_dev->csid_clk,
+			ARRAY_SIZE(csid_8974_clk_info), 1);
 		if (rc < 0) {
 			pr_err("%s: clock enable failed\n", __func__);
-			goto csid0_clk_enable_failed;
-		}
-		core_id = csid_dev->pdev->id;
-		if (core_id) {
-			rc = msm_cam_clk_enable(&csid_dev->pdev->dev,
-				csid_8974_clk_info[core_id].clk_info,
-				csid_dev->csid_clk,
-				csid_8974_clk_info[core_id].num_clk_info, 1);
-			if (rc < 0) {
-				pr_err("%s: clock enable failed\n",
-					__func__);
-				goto clk_enable_failed;
-			}
+			goto clk_enable_failed;
 		}
 	}
-
+		CDBG("%s:%d called\n", __func__, __LINE__);
 	csid_dev->hw_version =
 		msm_camera_io_r(csid_dev->base + CSID_HW_VERSION_ADDR);
 	CDBG("%s:%d called csid_dev->hw_version %x\n", __func__, __LINE__,
@@ -341,12 +294,6 @@
 	return rc;
 
 clk_enable_failed:
-	if (CSID_VERSION >= CSID_VERSION_V3) {
-		msm_cam_clk_enable(&csid_dev->pdev->dev,
-			csid_8974_clk_info[0].clk_info, csid_dev->csid0_clk,
-			csid_8974_clk_info[0].num_clk_info, 0);
-	}
-csid0_clk_enable_failed:
 	if (CSID_VERSION <= CSID_VERSION_V2) {
 		msm_camera_enable_vreg(&csid_dev->pdev->dev,
 			csid_8960_vreg_info, ARRAY_SIZE(csid_8960_vreg_info),
@@ -375,7 +322,6 @@
 static int msm_csid_release(struct csid_device *csid_dev)
 {
 	uint32_t irq;
-	uint8_t core_id = 0;
 
 	if (csid_dev->csid_state != CSID_POWER_UP) {
 		pr_err("%s: csid invalid state %d\n", __func__,
@@ -401,16 +347,8 @@
 			csid_8960_vreg_info, ARRAY_SIZE(csid_8960_vreg_info),
 			NULL, 0, &csid_dev->csi_vdd, 0);
 	} else if (csid_dev->hw_version >= CSID_VERSION_V3) {
-		core_id = csid_dev->pdev->id;
-		if (core_id)
-			msm_cam_clk_enable(&csid_dev->pdev->dev,
-				csid_8974_clk_info[core_id].clk_info,
-				csid_dev->csid_clk,
-				csid_8974_clk_info[core_id].num_clk_info, 0);
-
-		msm_cam_clk_enable(&csid_dev->pdev->dev,
-			csid_8974_clk_info[0].clk_info, csid_dev->csid0_clk,
-			csid_8974_clk_info[0].num_clk_info, 0);
+		msm_cam_clk_enable(&csid_dev->pdev->dev, csid_8974_clk_info,
+			csid_dev->csid_clk, ARRAY_SIZE(csid_8974_clk_info), 0);
 
 		msm_camera_enable_vreg(&csid_dev->pdev->dev,
 			csid_vreg_info, ARRAY_SIZE(csid_vreg_info),
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.h b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.h
index 7ae1392..fd4db79 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.h
@@ -38,7 +38,6 @@
 	uint32_t hw_version;
 	enum msm_csid_state_t csid_state;
 
-	struct clk *csid0_clk[11];
 	struct clk *csid_clk[11];
 };
 
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
index df3ee60..7d3a1fc 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
@@ -43,14 +43,15 @@
 	uint8_t lane_cnt = 0;
 	uint16_t lane_mask = 0;
 	void __iomem *csiphybase;
+	uint8_t csiphy_id = csiphy_dev->pdev->id;
 	csiphybase = csiphy_dev->base;
 	if (!csiphybase) {
 		pr_err("%s: csiphybase NULL\n", __func__);
 		return -EINVAL;
 	}
 
-	csiphy_dev->lane_mask[csiphy_dev->pdev->id] |= csiphy_params->lane_mask;
-	lane_mask = csiphy_dev->lane_mask[csiphy_dev->pdev->id];
+	csiphy_dev->lane_mask[csiphy_id] |= csiphy_params->lane_mask;
+	lane_mask = csiphy_dev->lane_mask[csiphy_id];
 	lane_cnt = csiphy_params->lane_cnt;
 	if (csiphy_params->lane_cnt < 1 || csiphy_params->lane_cnt > 4) {
 		pr_err("%s: unsupported lane cnt %d\n",
@@ -58,11 +59,28 @@
 		return rc;
 	}
 
-	CDBG("%s csiphy_params, mask = %x, cnt = %d, settle cnt = %x\n",
+	CDBG("%s csiphy_params, mask = %x cnt = %d settle cnt = %x csid %d\n",
 		__func__,
 		csiphy_params->lane_mask,
 		csiphy_params->lane_cnt,
-		csiphy_params->settle_cnt);
+		csiphy_params->settle_cnt,
+		csiphy_params->csid_core);
+
+	if (csiphy_dev->hw_version >= CSIPHY_VERSION_V3) {
+		val = msm_camera_io_r(csiphy_dev->clk_mux_base);
+		if (csiphy_params->combo_mode &&
+			(csiphy_params->lane_mask & 0x18)) {
+			val &= ~0xf0;
+			val |= csiphy_params->csid_core << 4;
+		} else {
+			val &= ~0xf;
+			val |= csiphy_params->csid_core;
+		}
+		msm_camera_io_w(val, csiphy_dev->clk_mux_base);
+		CDBG("%s clk mux addr %p val 0x%x\n", __func__,
+			csiphy_dev->clk_mux_base, val);
+		mb();
+	}
 	msm_camera_io_w(0x1, csiphybase + MIPI_CSIPHY_GLBL_T_INIT_CFG0_ADDR);
 	msm_camera_io_w(0x1, csiphybase + MIPI_CSIPHY_T_WAKEUP_CFG0_ADDR);
 
@@ -204,6 +222,22 @@
 			csiphy_8960_clk_info, csiphy_dev->csiphy_clk,
 			ARRAY_SIZE(csiphy_8960_clk_info), 1);
 	} else {
+		if (!csiphy_dev->clk_mux_mem || !csiphy_dev->clk_mux_io) {
+			pr_err("%s clk mux mem %p io %p\n", __func__,
+				csiphy_dev->clk_mux_mem,
+				csiphy_dev->clk_mux_io);
+			rc = -ENOMEM;
+			return rc;
+		}
+		csiphy_dev->clk_mux_base = ioremap(
+			csiphy_dev->clk_mux_mem->start,
+			resource_size(csiphy_dev->clk_mux_mem));
+		if (!csiphy_dev->clk_mux_base) {
+			pr_err("%s: ERROR %d\n", __func__, __LINE__);
+			rc = -ENOMEM;
+			return rc;
+		}
+
 		CDBG("%s:%d called\n", __func__, __LINE__);
 		rc = msm_cam_clk_enable(&csiphy_dev->pdev->dev,
 			csiphy_8974_clk_info, csiphy_dev->csiphy_clk,
@@ -269,12 +303,31 @@
 	}
 	CDBG("%s:%d called\n", __func__, __LINE__);
 
+
 	if (CSIPHY_VERSION < CSIPHY_VERSION_V3) {
 		CDBG("%s:%d called\n", __func__, __LINE__);
 		rc = msm_cam_clk_enable(&csiphy_dev->pdev->dev,
 			csiphy_8960_clk_info, csiphy_dev->csiphy_clk,
 			ARRAY_SIZE(csiphy_8960_clk_info), 1);
 	} else {
+
+		if (!csiphy_dev->clk_mux_mem || !csiphy_dev->clk_mux_io) {
+			pr_err("%s clk mux mem %p io %p\n", __func__,
+				csiphy_dev->clk_mux_mem,
+				csiphy_dev->clk_mux_io);
+			rc = -ENOMEM;
+			return rc;
+		}
+
+		csiphy_dev->clk_mux_base = ioremap(
+			csiphy_dev->clk_mux_mem->start,
+			resource_size(csiphy_dev->clk_mux_mem));
+		if (!csiphy_dev->clk_mux_base) {
+			pr_err("%s: ERROR %d\n", __func__, __LINE__);
+			rc = -ENOMEM;
+			return rc;
+		}
+
 		CDBG("%s:%d called\n", __func__, __LINE__);
 		rc = msm_cam_clk_enable(&csiphy_dev->pdev->dev,
 			csiphy_8974_clk_info, csiphy_dev->csiphy_clk,
@@ -359,14 +412,16 @@
 
 	disable_irq(csiphy_dev->irq->start);
 
-	if (CSIPHY_VERSION < CSIPHY_VERSION_V3)
+	if (CSIPHY_VERSION < CSIPHY_VERSION_V3) {
 		msm_cam_clk_enable(&csiphy_dev->pdev->dev,
 			csiphy_8960_clk_info, csiphy_dev->csiphy_clk,
 			ARRAY_SIZE(csiphy_8960_clk_info), 0);
-	else
+	} else {
 		msm_cam_clk_enable(&csiphy_dev->pdev->dev,
 			csiphy_8974_clk_info, csiphy_dev->csiphy_clk,
 			ARRAY_SIZE(csiphy_8974_clk_info), 0);
+			iounmap(csiphy_dev->clk_mux_base);
+	}
 
 	iounmap(csiphy_dev->base);
 	csiphy_dev->base = NULL;
@@ -426,20 +481,23 @@
 	msm_camera_io_w(0x0, csiphy_dev->base + MIPI_CSIPHY_LNCK_CFG2_ADDR);
 	msm_camera_io_w(0x0, csiphy_dev->base + MIPI_CSIPHY_GLBL_PWR_CFG_ADDR);
 
-	if (CSIPHY_VERSION < CSIPHY_VERSION_V3)
+	if (CSIPHY_VERSION < CSIPHY_VERSION_V3) {
 		msm_cam_clk_enable(&csiphy_dev->pdev->dev,
 			csiphy_8960_clk_info, csiphy_dev->csiphy_clk,
 			ARRAY_SIZE(csiphy_8960_clk_info), 0);
-	else
+	} else {
 		msm_cam_clk_enable(&csiphy_dev->pdev->dev,
 			csiphy_8974_clk_info, csiphy_dev->csiphy_clk,
 			ARRAY_SIZE(csiphy_8974_clk_info), 0);
+			iounmap(csiphy_dev->clk_mux_base);
+	}
 
 	iounmap(csiphy_dev->base);
 	csiphy_dev->base = NULL;
 	csiphy_dev->csiphy_state = CSIPHY_POWER_DOWN;
 	return 0;
 }
+
 #endif
 
 static long msm_csiphy_cmd(struct csiphy_device *csiphy_dev, void *arg)
@@ -588,6 +646,17 @@
 	}
 	disable_irq(new_csiphy_dev->irq->start);
 
+	new_csiphy_dev->clk_mux_mem = platform_get_resource_byname(pdev,
+		IORESOURCE_MEM, "csiphy_clk_mux");
+	if (new_csiphy_dev->clk_mux_mem) {
+		new_csiphy_dev->clk_mux_io = request_mem_region(
+			new_csiphy_dev->clk_mux_mem->start,
+			resource_size(new_csiphy_dev->clk_mux_mem),
+			new_csiphy_dev->clk_mux_mem->name);
+		if (!new_csiphy_dev->clk_mux_io)
+			pr_err("%s: ERROR %d\n", __func__, __LINE__);
+	}
+
 	new_csiphy_dev->pdev = pdev;
 	new_csiphy_dev->msm_sd.sd.internal_ops = &msm_csiphy_internal_ops;
 	new_csiphy_dev->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.h b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.h
index e19be34..a11b958 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.h
@@ -32,9 +32,12 @@
 	struct msm_sd_subdev msm_sd;
 	struct v4l2_subdev subdev;
 	struct resource *mem;
+	struct resource *clk_mux_mem;
 	struct resource *irq;
 	struct resource *io;
+	struct resource *clk_mux_io;
 	void __iomem *base;
+	void __iomem *clk_mux_base;
 	struct mutex mutex;
 	uint32_t hw_version;
 	enum msm_csiphy_state_t csiphy_state;
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 14d1197..b56378a 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
@@ -25,6 +25,9 @@
 /* Length of mandatory fields that must exist in header of video PES */
 #define PES_MANDATORY_FIELDS_LEN			9
 
+/* Index of first byte in TS packet holding STC */
+#define STC_LOCATION_IDX			188
+
 #define MAX_PES_LENGTH	(SZ_64K)
 
 #define MAX_TS_PACKETS_FOR_SDMX_PROCESS	(500)
@@ -2202,6 +2205,14 @@
 	size_t len = 0;
 	struct dmx_pts_dts_info *pts_dts;
 
+	if (meta_data->packet_type == DMX_PES_PACKET) {
+		pts_dts = &meta_data->info.pes.pts_dts_info;
+		data->buf.stc = meta_data->info.pes.stc;
+	} else {
+		pts_dts = &meta_data->info.framing.pts_dts_info;
+		data->buf.stc = meta_data->info.framing.stc;
+	}
+
 	pts_dts = meta_data->packet_type == DMX_PES_PACKET ?
 		&meta_data->info.pes.pts_dts_info :
 		&meta_data->info.framing.pts_dts_info;
@@ -2313,6 +2324,7 @@
 		packet.raw_data_offset = feed_data->frame_offset;
 		meta_data.info.framing.pattern_type =
 			feed_data->last_framing_match_type;
+		meta_data.info.framing.stc = feed_data->last_framing_match_stc;
 
 		mpq_streambuffer_get_buffer_handle(stream_buffer,
 			0, /* current write buffer handle */
@@ -2385,6 +2397,7 @@
 		mpq_dmx_save_pts_dts(feed_data);
 
 		meta_data.packet_type = DMX_PES_PACKET;
+		meta_data.info.pes.stc = feed_data->prev_stc;
 
 		mpq_dmx_update_decoder_stat(mpq_demux);
 
@@ -2411,7 +2424,8 @@
 
 static int mpq_dmx_process_video_packet_framing(
 			struct dvb_demux_feed *feed,
-			const u8 *buf)
+			const u8 *buf,
+			u64 curr_stc)
 {
 	int bytes_avail;
 	u32 ts_payload_offset;
@@ -2596,7 +2610,8 @@
 	 * pass data to decoder only after sequence header
 	 * or equivalent is found. Otherwise the data is dropped.
 	 */
-	if (!(feed_data->found_sequence_header_pattern)) {
+	if (!feed_data->found_sequence_header_pattern) {
+		feed_data->prev_stc = curr_stc;
 		spin_unlock(&feed_data->video_buffer_lock);
 		return 0;
 	}
@@ -2699,6 +2714,12 @@
 					framing_res.info[i].type;
 				feed_data->last_pattern_offset =
 					framing_res.info[i].offset;
+				if (framing_res.info[i].used_prefix_size)
+					feed_data->last_framing_match_stc =
+						feed_data->prev_stc;
+				else
+					feed_data->last_framing_match_stc =
+						curr_stc;
 				continue;
 			}
 			/*
@@ -2744,6 +2765,8 @@
 			packet.raw_data_offset = feed_data->frame_offset;
 			meta_data.info.framing.pattern_type =
 				feed_data->last_framing_match_type;
+			meta_data.info.framing.stc =
+				feed_data->last_framing_match_stc;
 
 			mpq_streambuffer_get_buffer_handle(
 				stream_buffer,
@@ -2784,8 +2807,13 @@
 			framing_res.info[i].type;
 		feed_data->last_pattern_offset =
 			framing_res.info[i].offset;
+		if (framing_res.info[i].used_prefix_size)
+			feed_data->last_framing_match_stc = feed_data->prev_stc;
+		else
+			feed_data->last_framing_match_stc = curr_stc;
 	}
 
+	feed_data->prev_stc = curr_stc;
 	feed_data->first_prefix_size = 0;
 
 	if (pending_data_len) {
@@ -2810,7 +2838,8 @@
 
 static int mpq_dmx_process_video_packet_no_framing(
 			struct dvb_demux_feed *feed,
-			const u8 *buf)
+			const u8 *buf,
+			u64 curr_stc)
 {
 	int bytes_avail;
 	u32 ts_payload_offset;
@@ -2886,6 +2915,7 @@
 				mpq_dmx_save_pts_dts(feed_data);
 
 				meta_data.packet_type = DMX_PES_PACKET;
+				meta_data.info.pes.stc = feed_data->prev_stc;
 
 				mpq_dmx_update_decoder_stat(mpq_demux);
 
@@ -2928,6 +2958,8 @@
 		} else {
 			feed->pusi_seen = 1;
 		}
+
+		feed_data->prev_stc = curr_stc;
 	}
 
 	/*
@@ -3077,10 +3109,25 @@
 			struct dvb_demux_feed *feed,
 			const u8 *buf)
 {
+	u64 curr_stc;
+	struct mpq_demux *mpq_demux = feed->demux->priv;
+
+	if ((mpq_demux->source >= DMX_SOURCE_DVR0) &&
+		(mpq_demux->demux.tsp_format != DMX_TSP_FORMAT_192_TAIL)) {
+		curr_stc = 0;
+	} else {
+		curr_stc = buf[STC_LOCATION_IDX + 2] << 16;
+		curr_stc += buf[STC_LOCATION_IDX + 1] << 8;
+		curr_stc += buf[STC_LOCATION_IDX];
+		curr_stc *= 256; /* convert from 105.47 KHZ to 27MHz */
+	}
+
 	if (mpq_dmx_info.decoder_framing)
-		return mpq_dmx_process_video_packet_no_framing(feed, buf);
+		return mpq_dmx_process_video_packet_no_framing(feed, buf,
+				curr_stc);
 	else
-		return mpq_dmx_process_video_packet_framing(feed, buf);
+		return mpq_dmx_process_video_packet_framing(feed, buf,
+				curr_stc);
 }
 EXPORT_SYMBOL(mpq_dmx_process_video_packet);
 
@@ -3151,9 +3198,9 @@
 		(mpq_demux->demux.tsp_format != DMX_TSP_FORMAT_192_TAIL)) {
 		stc = 0;
 	} else {
-		stc = buf[190] << 16;
-		stc += buf[189] << 8;
-		stc += buf[188];
+		stc = buf[STC_LOCATION_IDX + 2] << 16;
+		stc += buf[STC_LOCATION_IDX + 1] << 8;
+		stc += buf[STC_LOCATION_IDX];
 		stc *= 256; /* convert from 105.47 KHZ to 27MHz */
 	}
 
@@ -4190,6 +4237,9 @@
 		pes_header = (struct pes_packet_header *)
 			&metadata_buf[pes_header_offset];
 		meta_data.packet_type = DMX_PES_PACKET;
+		/* TODO - set to real STC when SDMX supports it */
+		meta_data.info.pes.stc = 0;
+
 		if (pes_header->pts_dts_flag & 0x2) {
 			meta_data.info.pes.pts_dts_info.pts_exist = 1;
 			meta_data.info.pes.pts_dts_info.pts =
@@ -4544,7 +4594,7 @@
 	}
 
 	MPQ_DVB_DBG_PRINT(
-		"\n\n%s: Before SDMX_process: input read_offset=%u, fill count=%u\n",
+		"%s: Before SDMX_process: input read_offset=%u, fill count=%u\n",
 		__func__, read_offset, fill_count);
 
 	process_start_time = current_kernel_time();
@@ -4587,14 +4637,19 @@
 int mpq_sdmx_process(struct mpq_demux *mpq_demux,
 	struct sdmx_buff_descr *input,
 	u32 fill_count,
-	u32 read_offset)
+	u32 read_offset,
+	size_t tsp_size)
 {
 	int ret;
 	int todo;
 	int total_bytes_read = 0;
-	int limit = mpq_sdmx_proc_limit * mpq_demux->demux.ts_packet_size;
+	int limit = mpq_sdmx_proc_limit * tsp_size;
 
-	while (fill_count >= mpq_demux->demux.ts_packet_size) {
+	MPQ_DVB_DBG_PRINT(
+		"\n\n%s: read_offset=%u, fill_count=%u, tsp_size=%u\n",
+		__func__, read_offset, fill_count, tsp_size);
+
+	while (fill_count >= tsp_size) {
 		todo = fill_count > limit ? limit : fill_count;
 		ret = mpq_sdmx_process_buffer(mpq_demux, input, todo,
 			read_offset);
@@ -4643,7 +4698,8 @@
 	}
 	read_offset = mpq_demux->demux.dmx.dvr_input.ringbuff->pread;
 
-	return mpq_sdmx_process(mpq_demux, &buf_desc, count, read_offset);
+	return mpq_sdmx_process(mpq_demux, &buf_desc, count,
+				read_offset, mpq_demux->demux.ts_packet_size);
 }
 
 int mpq_dmx_write(struct dmx_demux *demux, const char *buf, size_t count)
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.h b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.h
index 80b5428..ca7c15a 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.h
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.h
@@ -244,6 +244,8 @@
  * reported for this frame.
  * @last_framing_match_type: Used for saving the type of
  * the previous pattern match found in this video feed.
+ * @last_framing_match_stc: Used for saving the STC attached to TS packet
+ * of the previous pattern match found in this video feed.
  * @found_sequence_header_pattern: Flag used to note that an MPEG-2
  * Sequence Header, H.264 SPS or VC-1 Sequence Header pattern
  * (whichever is relevant according to the video standard) had already
@@ -272,6 +274,7 @@
  * buffer space.
  * @last_pkt_index: used to save the last streambuffer packet index reported in
  * a new elementary stream data event.
+ * @prev_stc: STC attached to the previous video TS packet
  */
 struct mpq_video_feed_info {
 	struct mpq_streambuffer *video_buffer;
@@ -289,6 +292,7 @@
 	u32 last_pattern_offset;
 	u32 pending_pattern_len;
 	u64 last_framing_match_type;
+	u64 last_framing_match_stc;
 	int found_sequence_header_pattern;
 	struct dvb_dmx_video_prefix_size_masks prefix_size;
 	u32 first_prefix_size;
@@ -303,6 +307,7 @@
 	u32 ts_packets_num;
 	u32 ts_dropped_bytes;
 	int last_pkt_index;
+	u64 prev_stc;
 };
 
 /**
@@ -716,13 +721,15 @@
  * @input: input buffer descriptor
  * @fill_count: number of data bytes in input buffer that can be read
  * @read_offset: offset in buffer for reading
+ * @tsp_size: size of single TS packet
  *
  * Return number of bytes read or error code
  */
 int mpq_sdmx_process(struct mpq_demux *mpq_demux,
 	struct sdmx_buff_descr *input,
 	u32 fill_count,
-	u32 read_offset);
+	u32 read_offset,
+	size_t tsp_size);
 
 /**
  * mpq_sdmx_loaded - Returns 1 if secure demux application is loaded,
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c
index 193141a..43a65e9 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c
@@ -382,7 +382,8 @@
 			buff_current_addr_phys - buff_start_addr_phys);
 
 		mpq_sdmx_process(mpq_demux, &input, aggregate_len,
-			buff_current_addr_phys - buff_start_addr_phys);
+			buff_current_addr_phys - buff_start_addr_phys,
+			TSPP_RAW_TTS_SIZE);
 	}
 
 	for (i = 0; i < aggregate_count; i++)
diff --git a/drivers/media/platform/msm/dvb/include/mpq_adapter.h b/drivers/media/platform/msm/dvb/include/mpq_adapter.h
index 19abbbe..a2ade18 100644
--- a/drivers/media/platform/msm/dvb/include/mpq_adapter.h
+++ b/drivers/media/platform/msm/dvb/include/mpq_adapter.h
@@ -64,11 +64,17 @@
 
 	/** PTS/DTS information */
 	struct dmx_pts_dts_info pts_dts_info;
+
+	/** STC value attached to first TS packet holding the pattern */
+	u64 stc;
 };
 
 struct dmx_pes_packet_info {
 	/** PTS/DTS information */
 	struct dmx_pts_dts_info pts_dts_info;
+
+	/** STC value attached to first TS packet holding the PES */
+	u64 stc;
 };
 
 struct dmx_marker_info {
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index 0d5dc8c..7fc8810 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -1057,6 +1057,51 @@
 		pkt->size += sizeof(u32) + sizeof(struct hfi_quantization);
 		break;
 	}
+	case HAL_PARAM_VENC_SESSION_QP_RANGE:
+	{
+		struct hfi_quantization_range *hfi;
+		struct hfi_quantization_range *hal_range =
+			(struct hfi_quantization_range *) pdata;
+		u32 min_qp, max_qp;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE;
+		hfi = (struct hfi_quantization_range *)
+				&pkt->rg_property_data[1];
+
+		min_qp = hal_range->min_qp;
+		max_qp = hal_range->max_qp;
+
+		/* We'll be packing in the qp, so make sure we
+		 * won't be losing data when masking */
+		if (min_qp > 0xff || max_qp > 0xff) {
+			dprintk(VIDC_ERR, "qp value out of range\n");
+			rc = -ERANGE;
+			break;
+		}
+
+		/* When creating the packet, pack the qp value as
+		 * 0xiippbb, where ii = qp range for I-frames,
+		 * pp = qp range for P-frames, etc. */
+		hfi->min_qp = min_qp | min_qp << 8 | min_qp << 16;
+		hfi->max_qp = max_qp | max_qp << 8 | max_qp << 16;
+		hfi->layer_id = hal_range->layer_id;
+
+		pkt->size += sizeof(u32) +
+			sizeof(struct hfi_quantization_range);
+		break;
+	}
+	case HAL_PARAM_VENC_MAX_NUM_B_FRAMES:
+	{
+		struct hfi_max_num_b_frames *hfi;
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_MAX_NUM_B_FRAMES;
+		hfi = (struct hfi_max_num_b_frames *) &pkt->rg_property_data[1];
+		memcpy(hfi, (struct hfi_max_num_b_frames *) pdata,
+				sizeof(struct hfi_max_num_b_frames));
+		pkt->size += sizeof(u32) + sizeof(struct hfi_max_num_b_frames);
+		break;
+	}
 	case HAL_CONFIG_VENC_INTRA_PERIOD:
 	{
 		struct hfi_intra_period *hfi;
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
index 91fb514..43a3dad 100644
--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -174,8 +174,8 @@
 
 	switch (pkt->event_id) {
 	case HFI_EVENT_SYS_ERROR:
-		dprintk(VIDC_ERR, "HFI_EVENT_SYS_ERROR: %d\n",
-			pkt->event_data1);
+		dprintk(VIDC_ERR, "HFI_EVENT_SYS_ERROR: %d, 0x%x\n",
+			pkt->event_data1, pkt->event_data2);
 		hfi_process_sys_error(callback, device_id);
 		break;
 	case HFI_EVENT_SESSION_ERROR:
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index 8ce7414..5f47ae1 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -35,6 +35,7 @@
 #define P_FRAME_QP 28
 #define B_FRAME_QP 30
 #define MAX_INTRA_REFRESH_MBS 300
+#define MAX_NUM_B_FRAMES 4
 #define L_MODE V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY
 #define CODING V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY
 
@@ -419,6 +420,30 @@
 		.cluster = MSM_VENC_CTRL_CLUSTER_QP,
 	},
 	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_MIN_QP,
+		.name = "H264 Minimum QP",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 51,
+		.default_value = 1,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+		.cluster = MSM_VENC_CTRL_CLUSTER_QP,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_MAX_QP,
+		.name = "H264 Maximum QP",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 51,
+		.default_value = 51,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+		.cluster = MSM_VENC_CTRL_CLUSTER_QP,
+	},
+	{
 		.id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE,
 		.name = "Slice Mode",
 		.type = V4L2_CTRL_TYPE_MENU,
@@ -737,7 +762,7 @@
 	struct v4l2_ctrl *ctrl = NULL;
 	u32 extradata = 0;
 	if (!q || !q->drv_priv) {
-		dprintk(VIDC_ERR, "Invalid input, q = %p\n", q);
+		dprintk(VIDC_ERR, "Invalid input\n");
 		return -EINVAL;
 	}
 	inst = q->drv_priv;
@@ -1138,6 +1163,7 @@
 	struct hal_h264_db_control h264_db_control;
 	struct hal_enable enable;
 	struct hal_h264_vui_timing_info vui_timing_info;
+	struct hal_quantization_range qp_range;
 	u32 property_id = 0, property_val = 0;
 	void *pdata = NULL;
 	struct v4l2_ctrl *temp_ctrl = NULL;
@@ -1212,11 +1238,24 @@
 		break;
 	case V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES:
 		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES);
-
-		property_id =
-			HAL_CONFIG_VENC_INTRA_PERIOD;
 		intra_period.bframes = ctrl->val;
 		intra_period.pframes = temp_ctrl->val;
+		if (intra_period.bframes) {
+			u32 max_num_b_frames = MAX_NUM_B_FRAMES;
+			property_id =
+				HAL_PARAM_VENC_MAX_NUM_B_FRAMES;
+			pdata = &max_num_b_frames;
+			rc = call_hfi_op(hdev, session_set_property,
+				(void *)inst->session, property_id, pdata);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"Failed : Setprop MAX_NUM_B_FRAMES"
+					"%d", rc);
+				break;
+			}
+		}
+		property_id =
+			HAL_CONFIG_VENC_INTRA_PERIOD;
 		pdata = &intra_period;
 		break;
 	case V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_IFRAME:
@@ -1467,6 +1506,44 @@
 		pdata = &quantization;
 		break;
 	}
+	case V4L2_CID_MPEG_VIDEO_H264_MIN_QP: {
+		struct v4l2_ctrl *qp_max;
+
+		qp_max = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_MAX_QP);
+		if (ctrl->val >= qp_max->val) {
+			dprintk(VIDC_ERR, "Bad range: Min QP (%d) > Max QP(%d)",
+					ctrl->val, qp_max->val);
+			rc = -ERANGE;
+			break;
+		}
+
+		property_id = HAL_PARAM_VENC_SESSION_QP_RANGE;
+		qp_range.layer_id = 0;
+		qp_range.max_qp = qp_max->val;
+		qp_range.min_qp = ctrl->val;
+
+		pdata = &qp_range;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_H264_MAX_QP: {
+		struct v4l2_ctrl *qp_min;
+
+		qp_min = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_MIN_QP);
+		if (ctrl->val <= qp_min->val) {
+			dprintk(VIDC_ERR, "Bad range: Max QP (%d) < Min QP(%d)",
+					ctrl->val, qp_min->val);
+			rc = -ERANGE;
+			break;
+		}
+
+		property_id = HAL_PARAM_VENC_SESSION_QP_RANGE;
+		qp_range.layer_id = 0;
+		qp_range.max_qp = ctrl->val;
+		qp_range.min_qp = qp_min->val;
+
+		pdata = &qp_range;
+		break;
+	}
 	case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: {
 		int temp = 0;
 
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index dc08c64..d880016 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 200
+#define HW_RESPONSE_TIMEOUT 1000
 
 #define IS_ALREADY_IN_STATE(__p, __d) ({\
 	int __rc = (__p >= __d);\
@@ -1282,7 +1282,6 @@
 	}
 
 	hdev = inst->core->device;
-
 	if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_LOAD_RESOURCES)) {
 		dprintk(VIDC_INFO, "inst: %p is already in state: %d\n",
 						inst, inst->state);
@@ -1668,6 +1667,7 @@
 			core->state == VIDC_CORE_INVALID) {
 		dprintk(VIDC_ERR,
 				"Core is in bad state can't change the state");
+		rc = -EINVAL;
 		goto exit;
 	}
 	flipped_state = get_flipped_state(inst->state, state);
@@ -1901,8 +1901,14 @@
 		dprintk(VIDC_ERR, "%s invalid parameters", __func__);
 		return -EINVAL;
 	}
-	hdev = inst->core->device;
 
+	if (inst->state == MSM_VIDC_CORE_INVALID ||
+			inst->core->state == VIDC_CORE_INVALID) {
+		dprintk(VIDC_ERR,
+				"Core is in bad state can't query get_bufreqs()");
+		return -EINVAL;
+	}
+	hdev = inst->core->device;
 	mutex_lock(&inst->sync_lock);
 	if (inst->state < MSM_VIDC_OPEN_DONE || inst->state >= MSM_VIDC_CLOSE) {
 		dprintk(VIDC_ERR,
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index ddb3063..ed4f317 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -1874,17 +1874,42 @@
 	mutex_unlock(&device->write_lock);
 	return rc;
 }
+static void venus_hfi_process_msg_event_notify(
+	struct venus_hfi_device *device, void *packet)
+{
+	struct hfi_sfr_struct *vsfr = NULL;
+	struct hfi_msg_event_notify_packet *event_pkt;
+	struct vidc_hal_msg_pkt_hdr *msg_hdr;
 
+	msg_hdr = (struct vidc_hal_msg_pkt_hdr *)packet;
+	event_pkt =
+		(struct hfi_msg_event_notify_packet *)msg_hdr;
+	if (event_pkt && event_pkt->event_id ==
+		HFI_EVENT_SYS_ERROR) {
+		vsfr = (struct hfi_sfr_struct *)
+				device->sfr.align_virtual_addr;
+		if (vsfr)
+			dprintk(VIDC_ERR, "SFR Message from FW : %s",
+				vsfr->rg_data);
+	}
+}
 static void venus_hfi_response_handler(struct venus_hfi_device *device)
 {
 	u8 packet[VIDC_IFACEQ_MED_PKT_SIZE];
 	u32 rc = 0;
+	struct hfi_sfr_struct *vsfr = NULL;
 	dprintk(VIDC_INFO, "#####venus_hfi_response_handler#####\n");
 	if (device) {
 		if ((device->intr_status &
 			VIDC_WRAPPER_INTR_CLEAR_A2HWD_BMSK)) {
 			dprintk(VIDC_ERR, "Received: Watchdog timeout %s",
 				__func__);
+			vsfr = (struct hfi_sfr_struct *)
+					device->sfr.align_virtual_addr;
+			if (vsfr)
+				dprintk(VIDC_ERR,
+					"SFR Message from FW : %s",
+						vsfr->rg_data);
 			venus_hfi_process_sys_watchdog_timeout(device);
 		}
 
@@ -1892,6 +1917,9 @@
 			rc = hfi_process_msg_packet(device->callback,
 				device->device_id,
 				(struct vidc_hal_msg_pkt_hdr *) packet);
+			if (rc == HFI_MSG_EVENT_NOTIFY)
+				venus_hfi_process_msg_event_notify(
+					device, (void *)packet);
 		}
 		while (!venus_hfi_iface_dbgq_read(device, packet)) {
 			struct hfi_msg_sys_debug_packet *pkt =
@@ -2752,9 +2780,10 @@
 		return;
 	}
 	if (device->resources.fw.cookie) {
+		flush_workqueue(device->vidc_workq);
 		venus_hfi_disable_clks(device);
-		venus_hfi_iommu_detach(device);
 		subsystem_put(device->resources.fw.cookie);
+		venus_hfi_iommu_detach(device);
 		device->resources.fw.cookie = NULL;
 	}
 }
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index c91d1d2..3fbfec4 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -130,6 +130,7 @@
 	HAL_PARAM_VENC_H264_DEBLOCK_CONTROL,
 	HAL_PARAM_VENC_TEMPORAL_SPATIAL_TRADEOFF,
 	HAL_PARAM_VENC_SESSION_QP,
+	HAL_PARAM_VENC_SESSION_QP_RANGE,
 	HAL_CONFIG_VENC_INTRA_PERIOD,
 	HAL_CONFIG_VENC_IDR_PERIOD,
 	HAL_CONFIG_VPE_OPERATIONS,
@@ -169,6 +170,7 @@
 	HAL_CONFIG_VENC_MAX_BITRATE,
 	HAL_PARAM_VENC_H264_VUI_TIMING_INFO,
 	HAL_PARAM_VENC_H264_GENERATE_AUDNAL,
+	HAL_PARAM_VENC_MAX_NUM_B_FRAMES,
 };
 
 enum hal_domain {
@@ -596,6 +598,12 @@
 	u32 layer_id;
 };
 
+struct hal_quantization_range {
+	u32 min_qp;
+	u32 max_qp;
+	u32 layer_id;
+};
+
 struct hal_intra_period {
 	u32 pframes;
 	u32 bframes;
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
index 2d0c3bd..66eade1 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
@@ -304,7 +304,8 @@
 	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01E)
 #define HFI_PROPERTY_PARAM_VENC_VC1_PERF_CFG		\
 	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01F)
-
+#define  HFI_PROPERTY_PARAM_VENC_MAX_NUM_B_FRAMES \
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x020)
 #define HFI_PROPERTY_CONFIG_VENC_COMMON_START				\
 	(HFI_DOMAIN_BASE_VENC + HFI_ARCH_COMMON_OFFSET + 0x6000)
 #define HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE				\
@@ -424,6 +425,10 @@
 	u32 idr_period;
 };
 
+struct hfi_max_num_b_frames {
+	u32 max_num_b_frames;
+};
+
 struct hfi_intra_period {
 	u32 pframes;
 	u32 bframes;
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 55e3e4e..ac77bfb 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -1648,7 +1648,6 @@
 	data->abort = 0;
 	data->type = QSEECOM_CLIENT_APP;
 	data->released = false;
-	data->client.app_id = ret;
 	data->client.sb_length = size;
 	data->client.user_virt_sb_base = 0;
 	data->client.ihandle = NULL;
@@ -1693,7 +1692,7 @@
 		*handle = NULL;
 		return -EINVAL;
 	}
-
+	data->client.app_id = ret;
 	if (ret > 0) {
 		pr_warn("App id %d for [%s] app exists\n", ret,
 			(char *)app_ireq.app_name);
diff --git a/drivers/misc/tspp.c b/drivers/misc/tspp.c
index dbb4f5e..73cae32 100644
--- a/drivers/misc/tspp.c
+++ b/drivers/misc/tspp.c
@@ -1571,6 +1571,7 @@
 	int id;
 	int table_idx;
 	u32 val;
+	unsigned long flags;
 
 	struct sps_connect *config;
 	struct tspp_device *pdev;
@@ -1591,6 +1592,15 @@
 	if (!channel->used)
 		return 0;
 
+	/*
+	 * Need to protect access to used and waiting fields, as they are
+	 * used by the tasklet which is invoked from interrupt context
+	 */
+	spin_lock_irqsave(&pdev->spinlock, flags);
+	channel->used = 0;
+	channel->waiting = NULL;
+	spin_unlock_irqrestore(&pdev->spinlock, flags);
+
 	if (channel->expiration_period_ms)
 		del_timer(&channel->expiration_timer);
 
@@ -1644,9 +1654,7 @@
 	channel->buffer_count = 0;
 	channel->data = NULL;
 	channel->read = NULL;
-	channel->waiting = NULL;
 	channel->locked = NULL;
-	channel->used = 0;
 
 	if (tspp_channels_in_use(pdev) == 0) {
 		wake_unlock(&pdev->wake_lock);
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 5b7f08f..9f12142 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -67,12 +67,19 @@
 			(rq_data_dir(req) == WRITE))
 #define PACKED_CMD_VER		0x01
 #define PACKED_CMD_WR		0x02
+#define PACKED_TRIGGER_MAX_ELEMENTS	5000
 #define MMC_BLK_UPDATE_STOP_REASON(stats, reason)			\
 	do {								\
 		if (stats->enabled)					\
 			stats->pack_stop_reason[reason]++;		\
 	} while (0)
 
+#define PCKD_TRGR_INIT_MEAN_POTEN	17
+#define PCKD_TRGR_POTEN_LOWER_BOUND	5
+#define PCKD_TRGR_URGENT_PENALTY	2
+#define PCKD_TRGR_LOWER_BOUND		5
+#define PCKD_TRGR_PRECISION_MULTIPLIER	100
+
 static DEFINE_MUTEX(block_mutex);
 
 /*
@@ -1862,6 +1869,80 @@
 }
 EXPORT_SYMBOL(mmc_blk_disable_wr_packing);
 
+static int get_packed_trigger(int potential, struct mmc_card *card,
+			      struct request *req, int curr_trigger)
+{
+	static int num_mean_elements = 1;
+	static unsigned long mean_potential = PCKD_TRGR_INIT_MEAN_POTEN;
+	unsigned int trigger = curr_trigger;
+	unsigned int pckd_trgr_upper_bound = card->ext_csd.max_packed_writes;
+
+	/* scale down the upper bound to 75% */
+	pckd_trgr_upper_bound = (pckd_trgr_upper_bound * 3) / 4;
+
+	/*
+	 * since the most common calls for this function are with small
+	 * potential write values and since we don't want these calls to affect
+	 * the packed trigger, set a lower bound and ignore calls with
+	 * potential lower than that bound
+	 */
+	if (potential <= PCKD_TRGR_POTEN_LOWER_BOUND)
+		return trigger;
+
+	/*
+	 * this is to prevent integer overflow in the following calculation:
+	 * once every PACKED_TRIGGER_MAX_ELEMENTS reset the algorithm
+	 */
+	if (num_mean_elements > PACKED_TRIGGER_MAX_ELEMENTS) {
+		num_mean_elements = 1;
+		mean_potential = PCKD_TRGR_INIT_MEAN_POTEN;
+	}
+
+	/*
+	 * get next mean value based on previous mean value and current
+	 * potential packed writes. Calculation is as follows:
+	 * mean_pot[i+1] =
+	 *	((mean_pot[i] * num_mean_elem) + potential)/(num_mean_elem + 1)
+	 */
+	mean_potential *= num_mean_elements;
+	/*
+	 * add num_mean_elements so that the division of two integers doesn't
+	 * lower mean_potential too much
+	 */
+	if (potential > mean_potential)
+		mean_potential += num_mean_elements;
+	mean_potential += potential;
+	/* this is for gaining more precision when dividing two integers */
+	mean_potential *= PCKD_TRGR_PRECISION_MULTIPLIER;
+	/* this completes the mean calculation */
+	mean_potential /= ++num_mean_elements;
+	mean_potential /= PCKD_TRGR_PRECISION_MULTIPLIER;
+
+	/*
+	 * if current potential packed writes is greater than the mean potential
+	 * then the heuristic is that the following workload will contain many
+	 * write requests, therefore we lower the packed trigger. In the
+	 * opposite case we want to increase the trigger in order to get less
+	 * packing events.
+	 */
+	if (potential >= mean_potential)
+		trigger = (trigger <= PCKD_TRGR_LOWER_BOUND) ?
+				PCKD_TRGR_LOWER_BOUND : trigger - 1;
+	else
+		trigger = (trigger >= pckd_trgr_upper_bound) ?
+				pckd_trgr_upper_bound : trigger + 1;
+
+	/*
+	 * an urgent read request indicates a packed list being interrupted
+	 * by this read, therefore we aim for less packing, hence the trigger
+	 * gets increased
+	 */
+	if (req && (req->cmd_flags & REQ_URGENT) && (rq_data_dir(req) == READ))
+		trigger += PCKD_TRGR_URGENT_PENALTY;
+
+	return trigger;
+}
+
 static void mmc_blk_write_packing_control(struct mmc_queue *mq,
 					  struct request *req)
 {
@@ -1889,6 +1970,10 @@
 		if (mq->num_of_potential_packed_wr_reqs >
 				mq->num_wr_reqs_to_start_packing)
 			mq->wr_packing_enabled = true;
+		mq->num_wr_reqs_to_start_packing =
+			get_packed_trigger(mq->num_of_potential_packed_wr_reqs,
+					   mq->card, req,
+					   mq->num_wr_reqs_to_start_packing);
 		mq->num_of_potential_packed_wr_reqs = 0;
 		return;
 	}
@@ -1897,6 +1982,12 @@
 
 	if (data_dir == READ) {
 		mmc_blk_disable_wr_packing(mq);
+		mq->num_wr_reqs_to_start_packing =
+			get_packed_trigger(mq->num_of_potential_packed_wr_reqs,
+					   mq->card, req,
+					   mq->num_wr_reqs_to_start_packing);
+		mq->num_of_potential_packed_wr_reqs = 0;
+		mq->wr_packing_enabled = false;
 		return;
 	} else if (data_dir == WRITE) {
 		mq->num_of_potential_packed_wr_reqs++;
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index 4e12bb7..147e378 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -1127,6 +1127,33 @@
 }
 #endif
 
+static inline unsigned long get_vm_size(struct vm_area_struct *vma)
+{
+	return vma->vm_end - vma->vm_start;
+}
+
+static inline resource_size_t get_vm_offset(struct vm_area_struct *vma)
+{
+	return (resource_size_t) vma->vm_pgoff << PAGE_SHIFT;
+}
+
+/*
+ * Set a new vm offset.
+ *
+ * Verify that the incoming offset really works as a page offset,
+ * and that the offset and size fit in a resource_size_t.
+ */
+static inline int set_vm_offset(struct vm_area_struct *vma, resource_size_t off)
+{
+	pgoff_t pgoff = off >> PAGE_SHIFT;
+	if (off != (resource_size_t) pgoff << PAGE_SHIFT)
+		return -EINVAL;
+	if (off + get_vm_size(vma) - 1 < off)
+		return -EINVAL;
+	vma->vm_pgoff = pgoff;
+	return 0;
+}
+
 /*
  * set up a mapping for shared memory segments
  */
@@ -1136,20 +1163,29 @@
 	struct mtd_file_info *mfi = file->private_data;
 	struct mtd_info *mtd = mfi->mtd;
 	struct map_info *map = mtd->priv;
-	unsigned long start;
-	unsigned long off;
-	u32 len;
+	resource_size_t start, off;
+	unsigned long len, vma_len;
 
 	if (mtd->type == MTD_RAM || mtd->type == MTD_ROM) {
-		off = vma->vm_pgoff << PAGE_SHIFT;
+		off = get_vm_offset(vma);
 		start = map->phys;
 		len = PAGE_ALIGN((start & ~PAGE_MASK) + map->size);
 		start &= PAGE_MASK;
-		if ((vma->vm_end - vma->vm_start + off) > len)
+		vma_len = get_vm_size(vma);
+
+		/* Overflow in off+len? */
+		if (vma_len + off < off)
+			return -EINVAL;
+		/* Does it fit in the mapping? */
+		if (vma_len + off > len)
 			return -EINVAL;
 
 		off += start;
-		vma->vm_pgoff = off >> PAGE_SHIFT;
+		/* Did that overflow? */
+		if (off < start)
+			return -EINVAL;
+		if (set_vm_offset(vma, off) < 0)
+			return -EINVAL;
 		vma->vm_flags |= VM_IO | VM_RESERVED;
 
 #ifdef pgprot_noncached
diff --git a/drivers/net/ethernet/msm/ecm_ipa.c b/drivers/net/ethernet/msm/ecm_ipa.c
index 114b23d..f6b8051 100644
--- a/drivers/net/ethernet/msm/ecm_ipa.c
+++ b/drivers/net/ethernet/msm/ecm_ipa.c
@@ -22,13 +22,13 @@
 #include <mach/ecm_ipa.h>
 
 #define DRIVER_NAME "ecm_ipa"
-#define DRIVER_VERSION "20-Mar-2013"
 #define ECM_IPA_IPV4_HDR_NAME "ecm_eth_ipv4"
 #define ECM_IPA_IPV6_HDR_NAME "ecm_eth_ipv6"
 #define IPA_TO_USB_CLIENT	IPA_CLIENT_USB_CONS
 #define INACTIVITY_MSEC_DELAY 100
 #define DEFAULT_OUTSTANDING_HIGH 64
 #define DEFAULT_OUTSTANDING_LOW 32
+#define DEBUGFS_TEMP_BUF_SIZE 4
 
 #define ECM_IPA_ERROR(fmt, args...) \
 	pr_err(DRIVER_NAME "@%s@%d@ctx:%s: "\
@@ -57,6 +57,7 @@
  * @tx_file: saved debugfs entry to allow cleanup
  * @rx_file: saved debugfs entry to allow cleanup
  * @rm_file: saved debugfs entry to allow cleanup
+ * @outstanding_file:  saved debugfs entry to allow cleanup
  * @outstanding_high_file saved debugfs entry to allow cleanup
  * @outstanding_low_file saved debugfs entry to allow cleanup
  * @dma_file: saved debugfs entry to allow cleanup
@@ -82,6 +83,7 @@
 	struct dentry *outstanding_high_file;
 	struct dentry *outstanding_low_file;
 	struct dentry *dma_file;
+	struct dentry *outstanding_file;
 	uint32_t eth_ipv4_hdr_hdl;
 	uint32_t eth_ipv6_hdr_hdl;
 	u32 usb_to_ipa_hdl;
@@ -129,8 +131,11 @@
 static int ecm_ipa_debugfs_rx_open(struct inode *inode, struct file *file);
 static int ecm_ipa_debugfs_rm_open(struct inode *inode, struct file *file);
 static int ecm_ipa_debugfs_dma_open(struct inode *inode, struct file *file);
+static int ecm_ipa_debugfs_atomic_open(struct inode *inode, struct file *file);
 static ssize_t ecm_ipa_debugfs_enable_read(struct file *file,
 		char __user *ubuf, size_t count, loff_t *ppos);
+static ssize_t ecm_ipa_debugfs_atomic_read(struct file *file,
+		char __user *ubuf, size_t count, loff_t *ppos);
 static ssize_t ecm_ipa_debugfs_enable_write(struct file *file,
 		const char __user *buf, size_t count, loff_t *ppos);
 static ssize_t ecm_ipa_debugfs_enable_write_dma(struct file *file,
@@ -169,6 +174,11 @@
 	.write = ecm_ipa_debugfs_enable_write_dma,
 };
 
+const struct file_operations ecm_ipa_debugfs_atomic_ops = {
+		.open = ecm_ipa_debugfs_atomic_open,
+		.read = ecm_ipa_debugfs_atomic_read,
+};
+
 /**
  * ecm_ipa_init() - initializes internal data structures
  * @ecm_ipa_rx_dp_notify: supplied callback to be called by the IPA
@@ -195,7 +205,7 @@
 	struct net_device *net;
 	struct ecm_ipa_dev *dev;
 	ECM_IPA_LOG_ENTRY();
-	pr_debug("%s version %s\n", DRIVER_NAME, DRIVER_VERSION);
+	pr_debug("%s initializing\n", DRIVER_NAME);
 	NULL_CHECK(ecm_ipa_rx_dp_notify);
 	NULL_CHECK(ecm_ipa_tx_dp_notify);
 	NULL_CHECK(priv);
@@ -833,6 +843,15 @@
 	return 0;
 }
 
+static int ecm_ipa_debugfs_atomic_open(struct inode *inode, struct file *file)
+{
+	struct ecm_ipa_dev *dev = inode->i_private;
+	ECM_IPA_LOG_ENTRY();
+	file->private_data = &(dev->outstanding_pkts);
+	ECM_IPA_LOG_EXIT();
+	return 0;
+}
+
 static ssize_t ecm_ipa_debugfs_enable_write_dma(struct file *file,
 		const char __user *buf, size_t count, loff_t *ppos)
 {
@@ -904,9 +923,22 @@
 	return size;
 }
 
+static ssize_t ecm_ipa_debugfs_atomic_read(struct file *file,
+		char __user *ubuf, size_t count, loff_t *ppos)
+{
+	int nbytes;
+	u8 atomic_str[DEBUGFS_TEMP_BUF_SIZE] = {0};
+	atomic_t *atomic_var = file->private_data;
+	nbytes = scnprintf(atomic_str, sizeof(atomic_str), "%d\n",
+			atomic_read(atomic_var));
+	return simple_read_from_buffer(ubuf, count, ppos, atomic_str, nbytes);
+}
+
+
 static int ecm_ipa_debugfs_init(struct ecm_ipa_dev *dev)
 {
 	const mode_t flags = S_IRUGO | S_IWUGO;
+	const mode_t flags_read_only = S_IRUGO;
 
 	int ret = -EINVAL;
 	ECM_IPA_LOG_ENTRY();
@@ -961,6 +993,14 @@
 		ret = -EFAULT;
 		goto fail_file;
 	}
+	dev->outstanding_file = debugfs_create_file("outstanding",
+			flags_read_only, dev->folder, dev,
+			&ecm_ipa_debugfs_atomic_ops);
+	if (!dev->outstanding_file) {
+		ECM_IPA_ERROR("could not create outstanding file\n");
+		ret = -EFAULT;
+		goto fail_file;
+	}
 
 	ECM_IPA_LOG_EXIT();
 	return 0;
@@ -980,7 +1020,6 @@
 {
 	ECM_IPA_LOG_ENTRY();
 	strlcpy(drv_info->driver, DRIVER_NAME, sizeof(drv_info->driver));
-	strlcpy(drv_info->version, DRIVER_VERSION, sizeof(drv_info->version));
 	ECM_IPA_LOG_EXIT();
 }
 
diff --git a/drivers/platform/msm/ipa/Makefile b/drivers/platform/msm/ipa/Makefile
index b7eca61..2b6ce75 100644
--- a/drivers/platform/msm/ipa/Makefile
+++ b/drivers/platform/msm/ipa/Makefile
@@ -1,4 +1,4 @@
 obj-$(CONFIG_IPA) += ipat.o
 ipat-y := ipa.o ipa_debugfs.o ipa_hdr.o ipa_flt.o ipa_rt.o ipa_dp.o ipa_client.o \
-	ipa_utils.o ipa_nat.o rmnet_bridge.o a2_service.o ipa_bridge.o ipa_intf.o teth_bridge.o \
+	ipa_utils.o ipa_nat.o a2_service.o ipa_bridge.o ipa_intf.o teth_bridge.o \
 	ipa_rm.o ipa_rm_dependency_graph.o ipa_rm_peers_list.o ipa_rm_resource.o ipa_rm_inactivity_timer.o
diff --git a/drivers/platform/msm/ipa/a2_service.c b/drivers/platform/msm/ipa/a2_service.c
index 4b5f0a2..1b33dc0 100644
--- a/drivers/platform/msm/ipa/a2_service.c
+++ b/drivers/platform/msm/ipa/a2_service.c
@@ -205,6 +205,7 @@
 	smsm_change_state(SMSM_APPS_STATE,
 				clear_bit & SMSM_A2_POWER_CONTROL_ACK,
 				~clear_bit & SMSM_A2_POWER_CONTROL_ACK);
+	IPA_STATS_INC_CNT(ipa_ctx->stats.a2_power_apps_acks);
 	clear_bit = ~clear_bit;
 }
 
@@ -216,10 +217,13 @@
 	if (a2_mux_ctx->bam_dmux_uplink_vote == vote)
 		IPADBG("%s: warning - duplicate power vote\n", __func__);
 	a2_mux_ctx->bam_dmux_uplink_vote = vote;
-	if (vote)
+	if (vote) {
 		smsm_change_state(SMSM_APPS_STATE, 0, SMSM_A2_POWER_CONTROL);
-	else
+		IPA_STATS_INC_CNT(ipa_ctx->stats.a2_power_on_reqs_out);
+	} else {
 		smsm_change_state(SMSM_APPS_STATE, SMSM_A2_POWER_CONTROL, 0);
+		IPA_STATS_INC_CNT(ipa_ctx->stats.a2_power_off_reqs_out);
+	}
 }
 
 static inline void ul_powerdown(void)
@@ -634,12 +638,14 @@
 	last_processed_state = new_state & SMSM_A2_POWER_CONTROL;
 	if (new_state & SMSM_A2_POWER_CONTROL) {
 		IPADBG("%s: MODEM PWR CTRL 1\n", __func__);
+		IPA_STATS_INC_CNT(ipa_ctx->stats.a2_power_on_reqs_in);
 		grab_wakelock();
 		(void) connect_to_bam();
 		queue_work(a2_mux_ctx->a2_mux_tx_workqueue,
 			   &a2_mux_ctx->kickoff_ul_request_resource);
 	} else if (!(new_state & SMSM_A2_POWER_CONTROL)) {
 		IPADBG("%s: MODEM PWR CTRL 0\n", __func__);
+		IPA_STATS_INC_CNT(ipa_ctx->stats.a2_power_off_reqs_in);
 		(void) disconnect_to_bam();
 		release_wakelock();
 	} else {
@@ -653,6 +659,7 @@
 {
 	IPADBG("%s: 0x%08x -> 0x%08x\n", __func__, old_state,
 			new_state);
+	IPA_STATS_INC_CNT(ipa_ctx->stats.a2_power_modem_acks);
 	complete_all(&a2_mux_ctx->ul_wakeup_ack_completion);
 }
 
@@ -1492,6 +1499,7 @@
 	a2_props.options		= SPS_BAM_OPT_IRQ_WAKEUP;
 	a2_props.num_pipes		= A2_NUM_PIPES;
 	a2_props.summing_threshold	= A2_SUMMING_THRESHOLD;
+	a2_props.manage                 = SPS_BAM_MGR_DEVICE_REMOTE;
 	/* need to free on tear down */
 	rc = sps_register_bam_device(&a2_props, &h);
 	if (rc < 0) {
diff --git a/drivers/platform/msm/ipa/ipa.c b/drivers/platform/msm/ipa/ipa.c
index 16f722c..466e694 100644
--- a/drivers/platform/msm/ipa/ipa.c
+++ b/drivers/platform/msm/ipa/ipa.c
@@ -50,6 +50,13 @@
 #define IPA_AGGR_STR_IN_BYTES(str) \
 	(strnlen((str), IPA_AGGR_MAX_STR_LENGTH - 1) + 1)
 
+/*
+ * This equals a timer value of 162.56us. This value was
+ * determined empirically and shows good bi-directional
+ * WLAN throughputs
+ */
+#define IPA_HOLB_TMR_DEFAULT_VAL 0x7f
+
 static struct ipa_plat_drv_res ipa_res = {0, };
 static struct of_device_id ipa_plat_drv_match[] = {
 	{
@@ -73,6 +80,18 @@
 		.ab = 0,
 		.ib = 0,
 	},
+	{
+		.src = MSM_BUS_MASTER_BAM_DMA,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_BAM_DMA,
+		.dst = MSM_BUS_SLAVE_OCIMEM,
+		.ab = 0,
+		.ib = 0,
+	},
 };
 
 static struct msm_bus_vectors ipa_max_perf_vectors[]  = {
@@ -82,6 +101,18 @@
 		.ab = 50000000,
 		.ib = 960000000,
 	},
+	{
+		.src = MSM_BUS_MASTER_BAM_DMA,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 50000000,
+		.ib = 960000000,
+	},
+	{
+		.src = MSM_BUS_MASTER_BAM_DMA,
+		.dst = MSM_BUS_SLAVE_OCIMEM,
+		.ab = 50000000,
+		.ib = 960000000,
+	},
 };
 
 static struct msm_bus_paths ipa_usecases[]  = {
@@ -901,7 +932,7 @@
 	/* LAN-WAN OUT (A5->IPA) */
 	memset(&sys_in, 0, sizeof(struct ipa_sys_connect_params));
 	sys_in.client = IPA_CLIENT_A5_LAN_WAN_PROD;
-	sys_in.desc_fifo_sz = IPA_SYS_DESC_FIFO_SZ;
+	sys_in.desc_fifo_sz = IPA_SYS_TX_DATA_DESC_FIFO_SZ;
 	sys_in.ipa_ep_cfg.mode.mode = IPA_BASIC;
 	sys_in.ipa_ep_cfg.mode.dst = IPA_CLIENT_A5_LAN_WAN_CONS;
 	if (ipa_setup_sys_pipe(&sys_in, &ipa_ctx->clnt_hdl_data_out)) {
@@ -1123,7 +1154,7 @@
 	u32 producer_hdl = 0;
 	u32 consumer_hdl = 0;
 
-	rmnet_bridge_get_client_handles(&producer_hdl, &consumer_hdl);
+	teth_bridge_get_client_handles(&producer_hdl, &consumer_hdl);
 
 	/* configure aggregation on producer */
 	memset(&agg_params, 0, sizeof(struct ipa_ep_cfg_aggr));
@@ -1630,6 +1661,8 @@
 		result = -ENOMEM;
 		goto fail_mem;
 	}
+	ipa_ctx->hol_en = 0x1;
+	ipa_ctx->hol_timer = IPA_HOLB_TMR_DEFAULT_VAL;
 
 	IPADBG("polling_mode=%u delay_ms=%u\n", polling_mode, polling_delay_ms);
 	ipa_ctx->polling_mode = polling_mode;
@@ -1712,6 +1745,7 @@
 	bam_props.num_pipes = IPA_NUM_PIPES;
 	bam_props.summing_threshold = IPA_SUMMING_THRESHOLD;
 	bam_props.event_threshold = IPA_EVENT_THRESHOLD;
+	bam_props.options |= SPS_BAM_NO_LOCAL_CLK_GATING;
 
 	result = sps_register_bam_device(&bam_props, &ipa_ctx->bam_handle);
 	if (result) {
@@ -1887,7 +1921,7 @@
 	if (result) {
 		IPAERR("ipa bridge init err.\n");
 		result = -ENODEV;
-		goto fail_bridge_init;
+		goto fail_a5_pipes;
 	}
 
 	/* setup the A5-IPA pipes */
@@ -2008,8 +2042,6 @@
 	ipa_cleanup_rx();
 	ipa_teardown_a5_pipes();
 fail_a5_pipes:
-	ipa_bridge_cleanup();
-fail_bridge_init:
 	destroy_workqueue(ipa_ctx->tx_wq);
 fail_tx_wq:
 	destroy_workqueue(ipa_ctx->rx_wq);
diff --git a/drivers/platform/msm/ipa/ipa_bridge.c b/drivers/platform/msm/ipa/ipa_bridge.c
index 83b7175..3ff604c 100644
--- a/drivers/platform/msm/ipa/ipa_bridge.c
+++ b/drivers/platform/msm/ipa/ipa_bridge.c
@@ -12,10 +12,52 @@
 
 #include <linux/delay.h>
 #include <linux/ratelimit.h>
+#include <mach/msm_smsm.h>
 #include "ipa_i.h"
 
-#define A2_EMBEDDED_PIPE_TX 4
-#define A2_EMBEDDED_PIPE_RX 5
+/*
+ * EP0 (teth)
+ * A2_BAM(1)->(12)DMA_BAM->DMA_BAM(13)->(6)IPA_BAM->IPA_BAM(10)->USB_BAM(0)
+ * A2_BAM(0)<-(15)DMA_BAM<-DMA_BAM(14)<-(7)IPA_BAM<-IPA_BAM(11)<-USB_BAM(1)
+ *
+ * EP2 (emb)
+ * A2_BAM(5)->(16)DMA_BAM->DMA_BAM(17)->(8)IPA_BAM->
+ * A2_BAM(4)<-(19)DMA_BAM<-DMA_BAM(18)<-(9)IPA_BAM<-
+ */
+
+#define A2_TETHERED_PIPE_UL      0
+#define DMA_A2_TETHERED_PIPE_UL  15
+#define DMA_IPA_TETHERED_PIPE_UL 14
+#define A2_TETHERED_PIPE_DL      1
+#define DMA_A2_TETHERED_PIPE_DL  12
+#define DMA_IPA_TETHERED_PIPE_DL 13
+
+#define A2_EMBEDDED_PIPE_UL      4
+#define DMA_A2_EMBEDDED_PIPE_UL  19
+#define DMA_IPA_EMBEDDED_PIPE_UL 18
+#define A2_EMBEDDED_PIPE_DL      5
+#define DMA_A2_EMBEDDED_PIPE_DL  16
+#define DMA_IPA_EMBEDDED_PIPE_DL 17
+
+#define IPA_SMEM_PIPE_MEM_SZ 32768
+
+#define IPA_UL_DATA_FIFO_SZ 0xc00
+#define IPA_UL_DESC_FIFO_SZ 0x530
+#define IPA_DL_DATA_FIFO_SZ 0x2400
+#define IPA_DL_DESC_FIFO_SZ 0x8a0
+
+#define IPA_SMEM_UL_DATA_FIFO_OFST 0x3dd0
+#define IPA_SMEM_UL_DESC_FIFO_OFST 0x49d0
+#define IPA_SMEM_DL_DATA_FIFO_OFST 0x4f00
+#define IPA_SMEM_DL_DESC_FIFO_OFST 0x7300
+
+#define IPA_OCIMEM_UL_DATA_FIFO_OFST 0
+#define IPA_OCIMEM_UL_DESC_FIFO_OFST (IPA_OCIMEM_UL_DATA_FIFO_OFST + \
+		IPA_UL_DATA_FIFO_SZ)
+#define IPA_OCIMEM_DL_DATA_FIFO_OFST (IPA_OCIMEM_UL_DESC_FIFO_OFST + \
+		IPA_UL_DESC_FIFO_SZ)
+#define IPA_OCIMEM_DL_DESC_FIFO_OFST (IPA_OCIMEM_DL_DATA_FIFO_OFST + \
+		IPA_DL_DATA_FIFO_SZ)
 
 enum ipa_pipe_type {
 	IPA_DL_FROM_A2,
@@ -25,678 +67,383 @@
 	IPA_PIPE_TYPE_MAX
 };
 
-static int polling_min_sleep[IPA_BRIDGE_DIR_MAX] = { 950, 950 };
-static int polling_max_sleep[IPA_BRIDGE_DIR_MAX] = { 1050, 1050 };
-static int polling_inactivity[IPA_BRIDGE_DIR_MAX] = { 4, 4 };
-
-struct ipa_pkt_info {
-	void *buffer;
-	dma_addr_t dma_address;
-	uint32_t len;
-	struct list_head link;
-};
-
 struct ipa_bridge_pipe_context {
-	struct list_head head_desc_list;
 	struct sps_pipe *pipe;
-	struct sps_connect connection;
-	struct sps_mem_buffer desc_mem_buf;
-	struct sps_register_event register_event;
-	struct list_head free_desc_list;
+	bool ipa_facing;
 	bool valid;
 };
 
 struct ipa_bridge_context {
 	struct ipa_bridge_pipe_context pipe[IPA_PIPE_TYPE_MAX];
-	struct workqueue_struct *ul_wq;
-	struct workqueue_struct *dl_wq;
-	struct work_struct ul_work;
-	struct work_struct dl_work;
 	enum ipa_bridge_type type;
 };
 
 static struct ipa_bridge_context bridge[IPA_BRIDGE_TYPE_MAX];
 
-static void ipa_do_bridge_work(enum ipa_bridge_dir dir,
-		struct ipa_bridge_context *ctx);
-
-static void ul_work_func(struct work_struct *work)
+static void ipa_get_dma_pipe_num(enum ipa_bridge_dir dir,
+		enum ipa_bridge_type type, int *a2, int *ipa)
 {
-	struct ipa_bridge_context *ctx = container_of(work,
-			struct ipa_bridge_context, ul_work);
-	ipa_do_bridge_work(IPA_BRIDGE_DIR_UL, ctx);
+	if (type == IPA_BRIDGE_TYPE_TETHERED) {
+		if (dir == IPA_BRIDGE_DIR_UL) {
+			*a2 = DMA_A2_TETHERED_PIPE_UL;
+			*ipa = DMA_IPA_TETHERED_PIPE_UL;
+		} else {
+			*a2 = DMA_A2_TETHERED_PIPE_DL;
+			*ipa = DMA_IPA_TETHERED_PIPE_DL;
+		}
+	} else {
+		if (dir == IPA_BRIDGE_DIR_UL) {
+			*a2 = DMA_A2_EMBEDDED_PIPE_UL;
+			*ipa = DMA_IPA_EMBEDDED_PIPE_UL;
+		} else {
+			*a2 = DMA_A2_EMBEDDED_PIPE_DL;
+			*ipa = DMA_IPA_EMBEDDED_PIPE_DL;
+		}
+	}
 }
 
-static void dl_work_func(struct work_struct *work)
+static int ipa_get_desc_fifo_sz(enum ipa_bridge_dir dir,
+		enum ipa_bridge_type type)
 {
-	struct ipa_bridge_context *ctx = container_of(work,
-			struct ipa_bridge_context, dl_work);
-	ipa_do_bridge_work(IPA_BRIDGE_DIR_DL, ctx);
+	int sz;
+
+	if (type == IPA_BRIDGE_TYPE_TETHERED) {
+		if (dir == IPA_BRIDGE_DIR_UL)
+			sz = IPA_UL_DESC_FIFO_SZ;
+		else
+			sz = IPA_DL_DESC_FIFO_SZ;
+	} else {
+		if (dir == IPA_BRIDGE_DIR_UL)
+			sz = IPA_UL_DESC_FIFO_SZ;
+		else
+			sz = IPA_DL_DESC_FIFO_SZ;
+	}
+
+	return sz;
 }
 
-static int ipa_switch_to_intr_mode(enum ipa_bridge_dir dir,
-				    struct ipa_bridge_context *ctx)
+static int ipa_get_data_fifo_sz(enum ipa_bridge_dir dir,
+		enum ipa_bridge_type type)
+{
+	int sz;
+
+	if (type == IPA_BRIDGE_TYPE_TETHERED) {
+		if (dir == IPA_BRIDGE_DIR_UL)
+			sz = IPA_UL_DATA_FIFO_SZ;
+		else
+			sz = IPA_DL_DATA_FIFO_SZ;
+	} else {
+		if (dir == IPA_BRIDGE_DIR_UL)
+			sz = IPA_UL_DATA_FIFO_SZ;
+		else
+			sz = IPA_DL_DATA_FIFO_SZ;
+	}
+
+	return sz;
+}
+
+static int ipa_get_a2_pipe_num(enum ipa_bridge_dir dir,
+		enum ipa_bridge_type type)
+{
+	int ep;
+
+	if (type == IPA_BRIDGE_TYPE_TETHERED) {
+		if (dir == IPA_BRIDGE_DIR_UL)
+			ep = A2_TETHERED_PIPE_UL;
+		else
+			ep = A2_TETHERED_PIPE_DL;
+	} else {
+		if (dir == IPA_BRIDGE_DIR_UL)
+			ep = A2_EMBEDDED_PIPE_UL;
+		else
+			ep = A2_EMBEDDED_PIPE_DL;
+	}
+
+	return ep;
+}
+
+int ipa_setup_a2_dma_fifos(enum ipa_bridge_dir dir,
+		enum ipa_bridge_type type,
+		struct sps_mem_buffer *desc,
+		struct sps_mem_buffer *data)
 {
 	int ret;
-	struct ipa_bridge_pipe_context *sys = &ctx->pipe[2 * dir];
 
-	ret = sps_get_config(sys->pipe, &sys->connection);
-	if (ret) {
-		IPAERR("sps_get_config() failed %d type=%d dir=%d\n",
-				ret, ctx->type, dir);
-		goto fail;
-	}
-	sys->register_event.options = SPS_O_EOT;
-	ret = sps_register_event(sys->pipe, &sys->register_event);
-	if (ret) {
-		IPAERR("sps_register_event() failed %d type=%d dir=%d\n",
-				ret, ctx->type, dir);
-		goto fail;
-	}
-	sys->connection.options =
-	   SPS_O_AUTO_ENABLE | SPS_O_ACK_TRANSFERS | SPS_O_EOT;
-	ret = sps_set_config(sys->pipe, &sys->connection);
-	if (ret) {
-		IPAERR("sps_set_config() failed %d type=%d dir=%d\n",
-				ret, ctx->type, dir);
-		goto fail;
-	}
-	ret = 0;
-fail:
-	return ret;
-}
+	if (type == IPA_BRIDGE_TYPE_EMBEDDED) {
+		if (dir == IPA_BRIDGE_DIR_UL) {
+			desc->base = ipa_ctx->smem_pipe_mem +
+				IPA_SMEM_UL_DESC_FIFO_OFST;
+			desc->phys_base = smem_virt_to_phys(desc->base);
+			desc->size = ipa_get_desc_fifo_sz(dir, type);
+			data->base = ipa_ctx->smem_pipe_mem +
+				IPA_SMEM_UL_DATA_FIFO_OFST;
+			data->phys_base = smem_virt_to_phys(data->base);
+			data->size = ipa_get_data_fifo_sz(dir, type);
+		} else {
+			desc->base = ipa_ctx->smem_pipe_mem +
+				IPA_SMEM_DL_DESC_FIFO_OFST;
+			desc->phys_base = smem_virt_to_phys(desc->base);
+			desc->size = ipa_get_desc_fifo_sz(dir, type);
+			data->base = ipa_ctx->smem_pipe_mem +
+				IPA_SMEM_DL_DATA_FIFO_OFST;
+			data->phys_base = smem_virt_to_phys(data->base);
+			data->size = ipa_get_data_fifo_sz(dir, type);
+		}
+	} else {
+		if (dir == IPA_BRIDGE_DIR_UL) {
+			ret = sps_setup_bam2bam_fifo(data,
+					IPA_OCIMEM_UL_DATA_FIFO_OFST,
+					ipa_get_data_fifo_sz(dir, type), 1);
+			if (ret) {
+				IPAERR("DAFIFO setup fail %d dir %d type %d\n",
+						ret, dir, type);
+				return ret;
+			}
 
-static int ipa_switch_to_poll_mode(enum ipa_bridge_dir dir,
-				    enum ipa_bridge_type type)
-{
-	int ret;
-	struct ipa_bridge_pipe_context *sys = &bridge[type].pipe[2 * dir];
+			ret = sps_setup_bam2bam_fifo(desc,
+					IPA_OCIMEM_UL_DESC_FIFO_OFST,
+					ipa_get_desc_fifo_sz(dir, type), 1);
+			if (ret) {
+				IPAERR("DEFIFO setup fail %d dir %d type %d\n",
+						ret, dir, type);
+				return ret;
+			}
+		} else {
+			ret = sps_setup_bam2bam_fifo(data,
+					IPA_OCIMEM_DL_DATA_FIFO_OFST,
+					ipa_get_data_fifo_sz(dir, type), 1);
+			if (ret) {
+				IPAERR("DAFIFO setup fail %d dir %d type %d\n",
+						ret, dir, type);
+				return ret;
+			}
 
-	ret = sps_get_config(sys->pipe, &sys->connection);
-	if (ret) {
-		IPAERR("sps_get_config() failed %d type=%d dir=%d\n",
-				ret, type, dir);
-		goto fail;
-	}
-	sys->connection.options =
-	   SPS_O_AUTO_ENABLE | SPS_O_ACK_TRANSFERS | SPS_O_POLL;
-	ret = sps_set_config(sys->pipe, &sys->connection);
-	if (ret) {
-		IPAERR("sps_set_config() failed %d type=%d dir=%d\n",
-				ret, type, dir);
-		goto fail;
-	}
-	ret = 0;
-fail:
-	return ret;
-}
-
-static int queue_rx_single(enum ipa_bridge_dir dir, enum ipa_bridge_type type)
-{
-	struct ipa_bridge_pipe_context *sys_rx = &bridge[type].pipe[2 * dir];
-	struct ipa_pkt_info *info;
-	int ret;
-
-	info = kmalloc(sizeof(struct ipa_pkt_info), GFP_KERNEL);
-	if (!info) {
-		IPAERR("unable to alloc rx_pkt_info type=%d dir=%d\n",
-				type, dir);
-		goto fail_pkt;
+			ret = sps_setup_bam2bam_fifo(desc,
+					IPA_OCIMEM_DL_DESC_FIFO_OFST,
+					ipa_get_desc_fifo_sz(dir, type), 1);
+			if (ret) {
+				IPAERR("DEFIFO setup fail %d dir %d type %d\n",
+						ret, dir, type);
+				return ret;
+			}
+		}
 	}
 
-	info->buffer = kmalloc(IPA_RX_SKB_SIZE, GFP_KERNEL | GFP_DMA);
-	if (!info->buffer) {
-		IPAERR("unable to alloc rx_pkt_buffer type=%d dir=%d\n",
-				type, dir);
-		goto fail_buffer;
-	}
+	IPADBG("dir=%d type=%d Dpa=%x Dsz=%u Dva=%p dpa=%x dsz=%u dva=%p\n",
+			dir, type, data->phys_base, data->size, data->base,
+			desc->phys_base, desc->size, desc->base);
 
-	info->dma_address = dma_map_single(NULL, info->buffer, IPA_RX_SKB_SIZE,
-					   DMA_BIDIRECTIONAL);
-	if (info->dma_address == 0 || info->dma_address == ~0) {
-		IPAERR("dma_map_single failure %p for %p type=%d dir=%d\n",
-				(void *)info->dma_address, info->buffer,
-				type, dir);
-		goto fail_dma;
-	}
-
-	list_add_tail(&info->link, &sys_rx->head_desc_list);
-	ret = sps_transfer_one(sys_rx->pipe, info->dma_address,
-			       IPA_RX_SKB_SIZE, info,
-			       SPS_IOVEC_FLAG_INT);
-	if (ret) {
-		list_del(&info->link);
-		dma_unmap_single(NULL, info->dma_address, IPA_RX_SKB_SIZE,
-				 DMA_BIDIRECTIONAL);
-		IPAERR("sps_transfer_one failed %d type=%d dir=%d\n", ret,
-				type, dir);
-		goto fail_dma;
-	}
 	return 0;
-
-fail_dma:
-	kfree(info->buffer);
-fail_buffer:
-	kfree(info);
-fail_pkt:
-	IPAERR("failed type=%d dir=%d\n", type, dir);
-	return -ENOMEM;
 }
 
-static int ipa_reclaim_tx(struct ipa_bridge_pipe_context *sys_tx, bool all)
-{
-	struct sps_iovec iov;
-	struct ipa_pkt_info *tx_pkt;
-	int cnt = 0;
-	int ret;
-
-	do {
-		iov.addr = 0;
-		ret = sps_get_iovec(sys_tx->pipe, &iov);
-		if (ret || iov.addr == 0) {
-			break;
-		} else {
-			tx_pkt = list_first_entry(&sys_tx->head_desc_list,
-						  struct ipa_pkt_info,
-						  link);
-			list_move_tail(&tx_pkt->link,
-					&sys_tx->free_desc_list);
-			cnt++;
-		}
-	} while (all);
-
-	return cnt;
-}
-
-static void ipa_do_bridge_work(enum ipa_bridge_dir dir,
-			       struct ipa_bridge_context *ctx)
-{
-	struct ipa_bridge_pipe_context *sys_rx = &ctx->pipe[2 * dir];
-	struct ipa_bridge_pipe_context *sys_tx = &ctx->pipe[2 * dir + 1];
-	struct ipa_pkt_info *tx_pkt;
-	struct ipa_pkt_info *rx_pkt;
-	struct ipa_pkt_info *tmp_pkt;
-	struct sps_iovec iov;
-	int ret;
-	int inactive_cycles = 0;
-
-	while (1) {
-		++inactive_cycles;
-
-		if (ipa_reclaim_tx(sys_tx, false))
-			inactive_cycles = 0;
-
-		iov.addr = 0;
-		ret = sps_get_iovec(sys_rx->pipe, &iov);
-		if (ret || iov.addr == 0) {
-			/* no-op */
-		} else {
-			inactive_cycles = 0;
-
-			rx_pkt = list_first_entry(&sys_rx->head_desc_list,
-						  struct ipa_pkt_info,
-						  link);
-			list_del(&rx_pkt->link);
-			rx_pkt->len = iov.size;
-
-retry_alloc_tx:
-			if (list_empty(&sys_tx->free_desc_list)) {
-				tmp_pkt = kmalloc(sizeof(struct ipa_pkt_info),
-						GFP_KERNEL);
-				if (!tmp_pkt) {
-					pr_debug_ratelimited("%s: unable to alloc tx_pkt_info type=%d dir=%d\n",
-					       __func__, ctx->type, dir);
-					usleep_range(polling_min_sleep[dir],
-							polling_max_sleep[dir]);
-					goto retry_alloc_tx;
-				}
-
-				tmp_pkt->buffer = kmalloc(IPA_RX_SKB_SIZE,
-						GFP_KERNEL | GFP_DMA);
-				if (!tmp_pkt->buffer) {
-					pr_debug_ratelimited("%s: unable to alloc tx_pkt_buffer type=%d dir=%d\n",
-					       __func__, ctx->type, dir);
-					kfree(tmp_pkt);
-					usleep_range(polling_min_sleep[dir],
-							polling_max_sleep[dir]);
-					goto retry_alloc_tx;
-				}
-
-				tmp_pkt->dma_address = dma_map_single(NULL,
-						tmp_pkt->buffer,
-						IPA_RX_SKB_SIZE,
-						DMA_BIDIRECTIONAL);
-				if (tmp_pkt->dma_address == 0 ||
-						tmp_pkt->dma_address == ~0) {
-					pr_debug_ratelimited("%s: dma_map_single failure %p for %p type=%d dir=%d\n",
-					       __func__,
-					       (void *)tmp_pkt->dma_address,
-					       tmp_pkt->buffer, ctx->type, dir);
-				}
-
-				list_add_tail(&tmp_pkt->link,
-						&sys_tx->free_desc_list);
-			}
-
-			tx_pkt = list_first_entry(&sys_tx->free_desc_list,
-						  struct ipa_pkt_info,
-						  link);
-			list_del(&tx_pkt->link);
-
-retry_add_rx:
-			list_add_tail(&tx_pkt->link,
-					&sys_rx->head_desc_list);
-			ret = sps_transfer_one(sys_rx->pipe,
-					tx_pkt->dma_address,
-					IPA_RX_SKB_SIZE,
-					tx_pkt,
-					SPS_IOVEC_FLAG_INT);
-			if (ret) {
-				list_del(&tx_pkt->link);
-				pr_debug_ratelimited("%s: sps_transfer_one failed %d type=%d dir=%d\n",
-						__func__, ret, ctx->type, dir);
-				usleep_range(polling_min_sleep[dir],
-						polling_max_sleep[dir]);
-				goto retry_add_rx;
-			}
-
-retry_add_tx:
-			list_add_tail(&rx_pkt->link,
-					&sys_tx->head_desc_list);
-			ret = sps_transfer_one(sys_tx->pipe,
-					       rx_pkt->dma_address,
-					       iov.size,
-					       rx_pkt,
-					       SPS_IOVEC_FLAG_INT |
-					       SPS_IOVEC_FLAG_EOT);
-			if (ret) {
-				pr_debug_ratelimited("%s: fail to add to TX type=%d dir=%d\n",
-						__func__, ctx->type, dir);
-				list_del(&rx_pkt->link);
-				ipa_reclaim_tx(sys_tx, true);
-				usleep_range(polling_min_sleep[dir],
-						polling_max_sleep[dir]);
-				goto retry_add_tx;
-			}
-			IPA_STATS_INC_BRIDGE_CNT(ctx->type, dir,
-					ipa_ctx->stats.bridged_pkts);
-		}
-
-		if (inactive_cycles >= polling_inactivity[dir]) {
-			ipa_switch_to_intr_mode(dir, ctx);
-			break;
-		}
-	}
-}
-
-static void ipa_sps_irq_rx_notify(struct sps_event_notify *notify)
-{
-	enum ipa_bridge_type type = (enum ipa_bridge_type) notify->user;
-
-	switch (notify->event_id) {
-	case SPS_EVENT_EOT:
-		ipa_switch_to_poll_mode(IPA_BRIDGE_DIR_UL, type);
-		queue_work(bridge[type].ul_wq, &bridge[type].ul_work);
-		break;
-	default:
-		IPAERR("recieved unexpected event id %d type %d\n",
-				notify->event_id, type);
-	}
-}
-
-static int setup_bridge_to_ipa(enum ipa_bridge_dir dir,
+static int setup_dma_bam_bridge(enum ipa_bridge_dir dir,
 			       enum ipa_bridge_type type,
 			       struct ipa_sys_connect_params *props,
 			       u32 *clnt_hdl)
 {
-	struct ipa_bridge_pipe_context *sys;
-	dma_addr_t dma_addr;
-	enum ipa_pipe_type pipe_type;
-	int ipa_ep_idx;
-	int ret;
-	int i;
-
-	ipa_ep_idx = ipa_get_ep_mapping(ipa_ctx->mode, props->client);
-	if (ipa_ep_idx == -1) {
-		IPAERR("Invalid client=%d mode=%d type=%d dir=%d\n",
-				props->client, ipa_ctx->mode, type, dir);
-		ret = -EINVAL;
-		goto alloc_endpoint_failed;
-	}
-
-	if (ipa_ctx->ep[ipa_ep_idx].valid) {
-		IPAERR("EP %d already allocated type=%d dir=%d\n", ipa_ep_idx,
-				type, dir);
-		ret = -EINVAL;
-		goto alloc_endpoint_failed;
-	}
-
-	pipe_type = (dir == IPA_BRIDGE_DIR_DL) ? IPA_DL_TO_IPA :
-						 IPA_UL_FROM_IPA;
-
-	sys = &bridge[type].pipe[pipe_type];
-	sys->pipe = sps_alloc_endpoint();
-	if (sys->pipe == NULL) {
-		IPAERR("alloc endpoint failed type=%d dir=%d\n", type, dir);
-		ret = -ENOMEM;
-		goto alloc_endpoint_failed;
-	}
-	ret = sps_get_config(sys->pipe, &sys->connection);
-	if (ret) {
-		IPAERR("get config failed %d type=%d dir=%d\n", ret, type, dir);
-		ret = -EINVAL;
-		goto get_config_failed;
-	}
-
-	if (dir == IPA_BRIDGE_DIR_DL) {
-		sys->connection.source = SPS_DEV_HANDLE_MEM;
-		sys->connection.src_pipe_index = ipa_ctx->a5_pipe_index++;
-		sys->connection.destination = ipa_ctx->bam_handle;
-		sys->connection.dest_pipe_index = ipa_ep_idx;
-		sys->connection.mode = SPS_MODE_DEST;
-		sys->connection.options =
-		   SPS_O_AUTO_ENABLE | SPS_O_ACK_TRANSFERS | SPS_O_POLL;
-	} else {
-		sys->connection.source = ipa_ctx->bam_handle;
-		sys->connection.src_pipe_index = ipa_ep_idx;
-		sys->connection.destination = SPS_DEV_HANDLE_MEM;
-		sys->connection.dest_pipe_index = ipa_ctx->a5_pipe_index++;
-		sys->connection.mode = SPS_MODE_SRC;
-		sys->connection.options = SPS_O_AUTO_ENABLE | SPS_O_EOT |
-		      SPS_O_ACK_TRANSFERS | SPS_O_NO_DISABLE;
-	}
-
-	sys->desc_mem_buf.size = props->desc_fifo_sz;
-	sys->desc_mem_buf.base = dma_alloc_coherent(NULL,
-						    sys->desc_mem_buf.size,
-						    &dma_addr,
-						    0);
-	if (sys->desc_mem_buf.base == NULL) {
-		IPAERR("memory alloc failed type=%d dir=%d\n", type, dir);
-		ret = -ENOMEM;
-		goto get_config_failed;
-	}
-	sys->desc_mem_buf.phys_base = dma_addr;
-	memset(sys->desc_mem_buf.base, 0x0, sys->desc_mem_buf.size);
-	sys->connection.desc = sys->desc_mem_buf;
-	sys->connection.event_thresh = IPA_EVENT_THRESHOLD;
-
-	ret = sps_connect(sys->pipe, &sys->connection);
-	if (ret < 0) {
-		IPAERR("connect error %d type=%d dir=%d\n", ret, type, dir);
-		goto connect_failed;
-	}
-
-	INIT_LIST_HEAD(&sys->head_desc_list);
-	INIT_LIST_HEAD(&sys->free_desc_list);
-
-	memset(&ipa_ctx->ep[ipa_ep_idx], 0,
-	       sizeof(struct ipa_ep_context));
-
-	ipa_ctx->ep[ipa_ep_idx].valid = 1;
-	ipa_ctx->ep[ipa_ep_idx].client_notify = props->notify;
-	ipa_ctx->ep[ipa_ep_idx].priv = props->priv;
-
-	ret = ipa_cfg_ep(ipa_ep_idx, &props->ipa_ep_cfg);
-	if (ret < 0) {
-		IPAERR("ep cfg set error %d type=%d dir=%d\n", ret, type, dir);
-		ipa_ctx->ep[ipa_ep_idx].valid = 0;
-		goto event_reg_failed;
-	}
-
-	if (dir == IPA_BRIDGE_DIR_UL) {
-		sys->register_event.options = SPS_O_EOT;
-		sys->register_event.mode = SPS_TRIGGER_CALLBACK;
-		sys->register_event.xfer_done = NULL;
-		sys->register_event.callback = ipa_sps_irq_rx_notify;
-		sys->register_event.user = (void *)type;
-		ret = sps_register_event(sys->pipe, &sys->register_event);
-		if (ret < 0) {
-			IPAERR("register event error %d type=%d dir=%d\n", ret,
-					type, dir);
-			goto event_reg_failed;
-		}
-
-		for (i = 0; i < IPA_RX_POOL_CEIL; i++) {
-			ret = queue_rx_single(dir, type);
-			if (ret < 0)
-				IPAERR("queue fail dir=%d type=%d iter=%d\n",
-				       dir, type, i);
-		}
-	}
-
-	*clnt_hdl = ipa_ep_idx;
-	sys->valid = true;
-
-	return 0;
-
-event_reg_failed:
-	sps_disconnect(sys->pipe);
-connect_failed:
-	dma_free_coherent(NULL,
-			  sys->desc_mem_buf.size,
-			  sys->desc_mem_buf.base,
-			  sys->desc_mem_buf.phys_base);
-get_config_failed:
-	sps_free_endpoint(sys->pipe);
-alloc_endpoint_failed:
-	return ret;
-}
-
-static void bam_mux_rx_notify(struct sps_event_notify *notify)
-{
-	enum ipa_bridge_type type = (enum ipa_bridge_type) notify->user;
-
-	switch (notify->event_id) {
-	case SPS_EVENT_EOT:
-		ipa_switch_to_poll_mode(IPA_BRIDGE_DIR_DL, type);
-		queue_work(bridge[type].dl_wq, &bridge[type].dl_work);
-		break;
-	default:
-		IPAERR("recieved unexpected event id %d type %d\n",
-				notify->event_id, type);
-	}
-}
-
-static int setup_bridge_to_a2(enum ipa_bridge_dir dir,
-			      enum ipa_bridge_type type,
-			      u32 desc_fifo_sz)
-{
-	struct ipa_bridge_pipe_context *sys;
-	struct a2_mux_pipe_connection pipe_conn = { 0 };
-	dma_addr_t dma_addr;
-	u32 a2_handle;
+	struct ipa_connect_params ipa_in_params;
+	struct ipa_sps_params sps_out_params;
+	int dma_a2_pipe;
+	int dma_ipa_pipe;
+	struct sps_pipe *pipe;
+	struct sps_pipe *pipe_a2;
+	struct sps_connect _connection;
+	struct sps_connect *connection = &_connection;
+	struct a2_mux_pipe_connection pipe_conn = {0};
 	enum a2_mux_pipe_direction pipe_dir;
-	enum ipa_pipe_type pipe_type;
+	u32 dma_hdl = sps_dma_get_bam_handle();
+	u32 a2_hdl;
 	u32 pa;
 	int ret;
-	int i;
+
+	memset(&ipa_in_params, 0, sizeof(ipa_in_params));
+	memset(&sps_out_params, 0, sizeof(sps_out_params));
 
 	pipe_dir = (dir == IPA_BRIDGE_DIR_UL) ? IPA_TO_A2 : A2_TO_IPA;
 
 	ret = ipa_get_a2_mux_pipe_info(pipe_dir, &pipe_conn);
 	if (ret) {
-		IPAERR("ipa_get_a2_mux_pipe_info failed type=%d dir=%d\n",
-				type, dir);
-		ret = -EINVAL;
-		goto alloc_endpoint_failed;
+		IPAERR("ipa_get_a2_mux_pipe_info failed dir=%d type=%d\n",
+				dir, type);
+		goto fail_get_a2_prop;
 	}
 
 	pa = (dir == IPA_BRIDGE_DIR_UL) ? pipe_conn.dst_phy_addr :
 					  pipe_conn.src_phy_addr;
 
-	ret = sps_phy2h(pa, &a2_handle);
+	ret = sps_phy2h(pa, &a2_hdl);
 	if (ret) {
-		IPAERR("sps_phy2h failed (A2 BAM) %d type=%d dir=%d\n",
-				ret, type, dir);
-		ret = -EINVAL;
-		goto alloc_endpoint_failed;
+		IPAERR("sps_phy2h failed (A2 BAM) %d dir=%d type=%d\n",
+				ret, dir, type);
+		goto fail_get_a2_prop;
 	}
 
-	pipe_type = (dir == IPA_BRIDGE_DIR_UL) ? IPA_UL_TO_A2 : IPA_DL_FROM_A2;
+	ipa_get_dma_pipe_num(dir, type, &dma_a2_pipe, &dma_ipa_pipe);
 
-	sys = &bridge[type].pipe[pipe_type];
-	sys->pipe = sps_alloc_endpoint();
-	if (sys->pipe == NULL) {
-		IPAERR("alloc endpoint failed type=%d dir=%d\n", type, dir);
+	ipa_in_params.ipa_ep_cfg = props->ipa_ep_cfg;
+	ipa_in_params.client = props->client;
+	ipa_in_params.client_bam_hdl = dma_hdl;
+	ipa_in_params.client_ep_idx = dma_ipa_pipe;
+	ipa_in_params.priv = props->priv;
+	ipa_in_params.notify = props->notify;
+	ipa_in_params.desc_fifo_sz = ipa_get_desc_fifo_sz(dir, type);
+	ipa_in_params.data_fifo_sz = ipa_get_data_fifo_sz(dir, type);
+
+	if (ipa_connect(&ipa_in_params, &sps_out_params, clnt_hdl)) {
+		IPAERR("ipa connect failed dir=%d type=%d\n", dir, type);
+		goto fail_get_a2_prop;
+	}
+
+	pipe = sps_alloc_endpoint();
+	if (pipe == NULL) {
+		IPAERR("sps_alloc_endpoint failed dir=%d type=%d\n", dir, type);
 		ret = -ENOMEM;
-		goto alloc_endpoint_failed;
+		goto fail_sps_alloc;
 	}
-	ret = sps_get_config(sys->pipe, &sys->connection);
+
+	memset(&_connection, 0, sizeof(_connection));
+	ret = sps_get_config(pipe, connection);
 	if (ret) {
-		IPAERR("get config failed %d type=%d dir=%d\n", ret, type, dir);
-		ret = -EINVAL;
-		goto get_config_failed;
+		IPAERR("sps_get_config failed %d dir=%d type=%d\n", ret, dir,
+				type);
+		goto fail_sps_get_config;
 	}
 
-	if (dir == IPA_BRIDGE_DIR_UL) {
-		sys->connection.source = SPS_DEV_HANDLE_MEM;
-		sys->connection.src_pipe_index = ipa_ctx->a5_pipe_index++;
-		sys->connection.destination = a2_handle;
-		if (type == IPA_BRIDGE_TYPE_TETHERED)
-			sys->connection.dest_pipe_index =
-			   pipe_conn.dst_pipe_index;
-		else
-			sys->connection.dest_pipe_index = A2_EMBEDDED_PIPE_TX;
-		sys->connection.mode = SPS_MODE_DEST;
-		sys->connection.options =
-		   SPS_O_AUTO_ENABLE | SPS_O_ACK_TRANSFERS | SPS_O_POLL;
-	} else {
-		sys->connection.source = a2_handle;
-		if (type == IPA_BRIDGE_TYPE_TETHERED)
-			sys->connection.src_pipe_index =
-			   pipe_conn.src_pipe_index;
-		else
-			sys->connection.src_pipe_index = A2_EMBEDDED_PIPE_RX;
-		sys->connection.destination = SPS_DEV_HANDLE_MEM;
-		sys->connection.dest_pipe_index = ipa_ctx->a5_pipe_index++;
-		sys->connection.mode = SPS_MODE_SRC;
-		sys->connection.options = SPS_O_AUTO_ENABLE | SPS_O_EOT |
-		      SPS_O_ACK_TRANSFERS;
-	}
-
-	sys->desc_mem_buf.size = desc_fifo_sz;
-	sys->desc_mem_buf.base = dma_alloc_coherent(NULL,
-						    sys->desc_mem_buf.size,
-						    &dma_addr,
-						    0);
-	if (sys->desc_mem_buf.base == NULL) {
-		IPAERR("memory alloc failed type=%d dir=%d\n", type, dir);
-		ret = -ENOMEM;
-		goto get_config_failed;
-	}
-	sys->desc_mem_buf.phys_base = dma_addr;
-	memset(sys->desc_mem_buf.base, 0x0, sys->desc_mem_buf.size);
-	sys->connection.desc = sys->desc_mem_buf;
-	sys->connection.event_thresh = IPA_EVENT_THRESHOLD;
-
-	ret = sps_connect(sys->pipe, &sys->connection);
-	if (ret < 0) {
-		IPAERR("connect error %d type=%d dir=%d\n", ret, type, dir);
-		ret = -EINVAL;
-		goto connect_failed;
-	}
-
-	INIT_LIST_HEAD(&sys->head_desc_list);
-	INIT_LIST_HEAD(&sys->free_desc_list);
-
 	if (dir == IPA_BRIDGE_DIR_DL) {
-		sys->register_event.options = SPS_O_EOT;
-		sys->register_event.mode = SPS_TRIGGER_CALLBACK;
-		sys->register_event.xfer_done = NULL;
-		sys->register_event.callback = bam_mux_rx_notify;
-		sys->register_event.user = (void *)type;
-		ret = sps_register_event(sys->pipe, &sys->register_event);
-		if (ret < 0) {
-			IPAERR("register event error %d type=%d dir=%d\n",
-					ret, type, dir);
-			ret = -EINVAL;
-			goto event_reg_failed;
-		}
-
-		for (i = 0; i < IPA_RX_POOL_CEIL; i++) {
-			ret = queue_rx_single(dir, type);
-			if (ret < 0)
-				IPAERR("queue fail dir=%d type=%d iter=%d\n",
-				       dir, type, i);
-		}
+		connection->mode = SPS_MODE_SRC;
+		connection->source = dma_hdl;
+		connection->destination = sps_out_params.ipa_bam_hdl;
+		connection->src_pipe_index = dma_ipa_pipe;
+		connection->dest_pipe_index = sps_out_params.ipa_ep_idx;
+	} else {
+		connection->mode = SPS_MODE_DEST;
+		connection->source = sps_out_params.ipa_bam_hdl;
+		connection->destination = dma_hdl;
+		connection->src_pipe_index = sps_out_params.ipa_ep_idx;
+		connection->dest_pipe_index = dma_ipa_pipe;
 	}
 
-	sys->valid = true;
+	connection->event_thresh = IPA_EVENT_THRESHOLD;
+	connection->data = sps_out_params.data;
+	connection->desc = sps_out_params.desc;
+	connection->options = SPS_O_AUTO_ENABLE;
+
+	ret = sps_connect(pipe, connection);
+	if (ret) {
+		IPAERR("sps_connect failed %d dir=%d type=%d\n", ret, dir,
+				type);
+		goto fail_sps_get_config;
+	}
+
+	if (dir == IPA_BRIDGE_DIR_DL) {
+		bridge[type].pipe[IPA_DL_TO_IPA].pipe = pipe;
+		bridge[type].pipe[IPA_DL_TO_IPA].ipa_facing = true;
+		bridge[type].pipe[IPA_DL_TO_IPA].valid = true;
+	} else {
+		bridge[type].pipe[IPA_UL_FROM_IPA].pipe = pipe;
+		bridge[type].pipe[IPA_UL_FROM_IPA].ipa_facing = true;
+		bridge[type].pipe[IPA_UL_FROM_IPA].valid = true;
+	}
+
+	IPADBG("dir=%d type=%d (ipa) src(0x%x:%u)->dst(0x%x:%u)\n", dir, type,
+			connection->source, connection->src_pipe_index,
+			connection->destination, connection->dest_pipe_index);
+
+	pipe_a2 = sps_alloc_endpoint();
+	if (pipe_a2 == NULL) {
+		IPAERR("sps_alloc_endpoint failed2 dir=%d type=%d\n", dir,
+				type);
+		ret = -ENOMEM;
+		goto fail_sps_alloc_a2;
+	}
+
+	memset(&_connection, 0, sizeof(_connection));
+	ret = sps_get_config(pipe_a2, connection);
+	if (ret) {
+		IPAERR("sps_get_config failed2 %d dir=%d type=%d\n", ret, dir,
+				type);
+		goto fail_sps_get_config_a2;
+	}
+
+	if (dir == IPA_BRIDGE_DIR_DL) {
+		connection->mode = SPS_MODE_DEST;
+		connection->source = a2_hdl;
+		connection->destination = dma_hdl;
+		connection->src_pipe_index = ipa_get_a2_pipe_num(dir, type);
+		connection->dest_pipe_index = dma_a2_pipe;
+	} else {
+		connection->mode = SPS_MODE_SRC;
+		connection->source = dma_hdl;
+		connection->destination = a2_hdl;
+		connection->src_pipe_index = dma_a2_pipe;
+		connection->dest_pipe_index = ipa_get_a2_pipe_num(dir, type);
+	}
+
+	connection->event_thresh = IPA_EVENT_THRESHOLD;
+
+	if (ipa_setup_a2_dma_fifos(dir, type, &connection->desc,
+				&connection->data)) {
+		IPAERR("fail to setup A2-DMA FIFOs dir=%d type=%d\n",
+				dir, type);
+		goto fail_sps_get_config_a2;
+	}
+
+	connection->options = SPS_O_AUTO_ENABLE;
+
+	ret = sps_connect(pipe_a2, connection);
+	if (ret) {
+		IPAERR("sps_connect failed2 %d dir=%d type=%d\n", ret, dir,
+				type);
+		goto fail_sps_get_config_a2;
+	}
+
+	if (dir == IPA_BRIDGE_DIR_DL) {
+		bridge[type].pipe[IPA_DL_FROM_A2].pipe = pipe_a2;
+		bridge[type].pipe[IPA_DL_FROM_A2].valid = true;
+	} else {
+		bridge[type].pipe[IPA_UL_TO_A2].pipe = pipe_a2;
+		bridge[type].pipe[IPA_UL_TO_A2].valid = true;
+	}
+
+	IPADBG("dir=%d type=%d (a2) src(0x%x:%u)->dst(0x%x:%u)\n", dir, type,
+			connection->source, connection->src_pipe_index,
+			connection->destination, connection->dest_pipe_index);
 
 	return 0;
 
-event_reg_failed:
-	sps_disconnect(sys->pipe);
-connect_failed:
-	dma_free_coherent(NULL,
-			  sys->desc_mem_buf.size,
-			  sys->desc_mem_buf.base,
-			  sys->desc_mem_buf.phys_base);
-get_config_failed:
-	sps_free_endpoint(sys->pipe);
-alloc_endpoint_failed:
+fail_sps_get_config_a2:
+	sps_free_endpoint(pipe_a2);
+fail_sps_alloc_a2:
+	sps_disconnect(pipe);
+fail_sps_get_config:
+	sps_free_endpoint(pipe);
+fail_sps_alloc:
+	ipa_disconnect(*clnt_hdl);
+fail_get_a2_prop:
 	return ret;
 }
 
 /**
- * ipa_bridge_init() - create workqueues and work items serving SW bridges
+ * ipa_bridge_init()
  *
  * Return codes: 0: success, -ENOMEM: failure
  */
 int ipa_bridge_init(void)
 {
-	int ret;
 	int i;
 
-	bridge[IPA_BRIDGE_TYPE_TETHERED].ul_wq =
-		create_singlethread_workqueue("ipa_ul_teth");
-	if (!bridge[IPA_BRIDGE_TYPE_TETHERED].ul_wq) {
-		IPAERR("ipa ul teth wq alloc failed\n");
-		ret = -ENOMEM;
-		goto fail_ul_teth;
+	ipa_ctx->smem_pipe_mem = smem_alloc(SMEM_BAM_PIPE_MEMORY,
+			IPA_SMEM_PIPE_MEM_SZ);
+	if (!ipa_ctx->smem_pipe_mem) {
+		IPAERR("smem alloc failed\n");
+		return -ENOMEM;
 	}
+	IPADBG("smem_pipe_mem = %p\n", ipa_ctx->smem_pipe_mem);
 
-	bridge[IPA_BRIDGE_TYPE_TETHERED].dl_wq =
-		create_singlethread_workqueue("ipa_dl_teth");
-	if (!bridge[IPA_BRIDGE_TYPE_TETHERED].dl_wq) {
-		IPAERR("ipa dl teth wq alloc failed\n");
-		ret = -ENOMEM;
-		goto fail_dl_teth;
-	}
-
-	bridge[IPA_BRIDGE_TYPE_EMBEDDED].ul_wq =
-		create_singlethread_workqueue("ipa_ul_emb");
-	if (!bridge[IPA_BRIDGE_TYPE_EMBEDDED].ul_wq) {
-		IPAERR("ipa ul emb wq alloc failed\n");
-		ret = -ENOMEM;
-		goto fail_ul_emb;
-	}
-
-	bridge[IPA_BRIDGE_TYPE_EMBEDDED].dl_wq =
-		create_singlethread_workqueue("ipa_dl_emb");
-	if (!bridge[IPA_BRIDGE_TYPE_EMBEDDED].dl_wq) {
-		IPAERR("ipa dl emb wq alloc failed\n");
-		ret = -ENOMEM;
-		goto fail_dl_emb;
-	}
-
-	for (i = 0; i < IPA_BRIDGE_TYPE_MAX; i++) {
-		INIT_WORK(&bridge[i].ul_work, ul_work_func);
-		INIT_WORK(&bridge[i].dl_work, dl_work_func);
+	for (i = 0; i < IPA_BRIDGE_TYPE_MAX; i++)
 		bridge[i].type = i;
-	}
 
 	return 0;
-
-fail_dl_emb:
-	destroy_workqueue(bridge[IPA_BRIDGE_TYPE_EMBEDDED].ul_wq);
-fail_ul_emb:
-	destroy_workqueue(bridge[IPA_BRIDGE_TYPE_TETHERED].dl_wq);
-fail_dl_teth:
-	destroy_workqueue(bridge[IPA_BRIDGE_TYPE_TETHERED].ul_wq);
-fail_ul_teth:
-	return ret;
 }
 
 /**
@@ -720,7 +467,7 @@
 
 	if (props == NULL || clnt_hdl == NULL ||
 	    type >= IPA_BRIDGE_TYPE_MAX || dir >= IPA_BRIDGE_DIR_MAX ||
-	    props->client >= IPA_CLIENT_MAX || props->desc_fifo_sz == 0) {
+	    props->client >= IPA_CLIENT_MAX) {
 		IPAERR("Bad param props=%p clnt_hdl=%p type=%d dir=%d\n",
 		       props, clnt_hdl, type, dir);
 		return -EINVAL;
@@ -728,52 +475,21 @@
 
 	ipa_inc_client_enable_clks();
 
-	if (setup_bridge_to_ipa(dir, type, props, clnt_hdl)) {
+	if (setup_dma_bam_bridge(dir, type, props, clnt_hdl)) {
 		IPAERR("fail to setup SYS pipe to IPA dir=%d type=%d\n",
 		       dir, type);
 		ret = -EINVAL;
 		goto bail_ipa;
 	}
 
-	if (setup_bridge_to_a2(dir, type, props->desc_fifo_sz)) {
-		IPAERR("fail to setup SYS pipe to A2 dir=%d type=%d\n",
-		       dir, type);
-		ret = -EINVAL;
-		goto bail_a2;
-	}
-
-
 	return 0;
 
-bail_a2:
-	ipa_bridge_teardown(dir, type, *clnt_hdl);
 bail_ipa:
 	ipa_dec_client_disable_clks();
 	return ret;
 }
 EXPORT_SYMBOL(ipa_bridge_setup);
 
-static void ipa_bridge_free_pkt(struct ipa_pkt_info *pkt)
-{
-	list_del(&pkt->link);
-	dma_unmap_single(NULL, pkt->dma_address, IPA_RX_SKB_SIZE,
-			 DMA_BIDIRECTIONAL);
-	kfree(pkt->buffer);
-	kfree(pkt);
-}
-
-static void ipa_bridge_free_resources(struct ipa_bridge_pipe_context *pipe)
-{
-	struct ipa_pkt_info *pkt;
-	struct ipa_pkt_info *n;
-
-	list_for_each_entry_safe(pkt, n, &pipe->head_desc_list, link)
-		ipa_bridge_free_pkt(pkt);
-
-	list_for_each_entry_safe(pkt, n, &pipe->free_desc_list, link)
-		ipa_bridge_free_pkt(pkt);
-}
-
 /**
  * ipa_bridge_teardown() - teardown SW bridge leg
  * @dir: downlink or uplink (from air interface perspective)
@@ -808,12 +524,10 @@
 	for (; lo <= hi; lo++) {
 		sys = &bridge[type].pipe[lo];
 		if (sys->valid) {
+			if (sys->ipa_facing)
+				ipa_disconnect(clnt_hdl);
 			sps_disconnect(sys->pipe);
-			dma_free_coherent(NULL, sys->desc_mem_buf.size,
-					  sys->desc_mem_buf.base,
-					  sys->desc_mem_buf.phys_base);
 			sps_free_endpoint(sys->pipe);
-			ipa_bridge_free_resources(sys);
 			sys->valid = false;
 		}
 	}
@@ -825,19 +539,3 @@
 	return 0;
 }
 EXPORT_SYMBOL(ipa_bridge_teardown);
-
-/**
- * ipa_bridge_cleanup() - destroy workqueues serving the SW bridges
- *
- * Return codes:
- * None
- */
-void ipa_bridge_cleanup(void)
-{
-	int i;
-
-	for (i = 0; i < IPA_BRIDGE_TYPE_MAX; i++) {
-		destroy_workqueue(bridge[i].dl_wq);
-		destroy_workqueue(bridge[i].ul_wq);
-	}
-}
diff --git a/drivers/platform/msm/ipa/ipa_client.c b/drivers/platform/msm/ipa/ipa_client.c
index 6033510..a78879d 100644
--- a/drivers/platform/msm/ipa/ipa_client.c
+++ b/drivers/platform/msm/ipa/ipa_client.c
@@ -13,8 +13,6 @@
 #include <linux/delay.h>
 #include "ipa_i.h"
 
-#define IPA_HOLB_TMR_VAL 0xff
-
 static void ipa_enable_data_path(u32 clnt_hdl)
 {
 	struct ipa_ep_context *ep = &ipa_ctx->ep[clnt_hdl];
@@ -302,13 +300,13 @@
 			in->client == IPA_CLIENT_HSIC3_CONS ||
 			in->client == IPA_CLIENT_HSIC4_CONS) {
 		IPADBG("disable holb for ep=%d tmr=%d\n", ipa_ep_idx,
-			IPA_HOLB_TMR_VAL);
+			ipa_ctx->hol_timer);
 		ipa_write_reg(ipa_ctx->mmio,
 			IPA_ENDP_INIT_HOL_BLOCK_EN_n_OFST(ipa_ep_idx),
-			0x1);
+			ipa_ctx->hol_en);
 		ipa_write_reg(ipa_ctx->mmio,
 			IPA_ENDP_INIT_HOL_BLOCK_TIMER_n_OFST(ipa_ep_idx),
-			IPA_HOLB_TMR_VAL);
+			ipa_ctx->hol_timer);
 	}
 
 	IPADBG("client %d (ep: %d) connected\n", in->client, ipa_ep_idx);
diff --git a/drivers/platform/msm/ipa/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_debugfs.c
index bc5aa6f..fb69817 100644
--- a/drivers/platform/msm/ipa/ipa_debugfs.c
+++ b/drivers/platform/msm/ipa/ipa_debugfs.c
@@ -94,6 +94,8 @@
 static struct dentry *dent;
 static struct dentry *dfile_gen_reg;
 static struct dentry *dfile_ep_reg;
+static struct dentry *dfile_ep_hol_en;
+static struct dentry *dfile_ep_hol_timer;
 static struct dentry *dfile_hdr;
 static struct dentry *dfile_ip4_rt;
 static struct dentry *dfile_ip6_rt;
@@ -144,6 +146,58 @@
 	return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, nbytes);
 }
 
+static ssize_t ipa_write_ep_hol_en_reg(struct file *file,
+		const char __user *buf, size_t count, loff_t *ppos)
+{
+	u32 endp_reg_val;
+	unsigned long missing;
+
+	if (sizeof(dbg_buff) < count + 1)
+		return -EFAULT;
+
+	missing = copy_from_user(dbg_buff, buf, count);
+	if (missing)
+		return -EFAULT;
+
+	dbg_buff[count] = '\0';
+	if (kstrtou32(dbg_buff, 16, &endp_reg_val))
+		return -EFAULT;
+
+	ipa_write_reg(ipa_ctx->mmio,
+		IPA_ENDP_INIT_HOL_BLOCK_EN_n_OFST(ep_reg_idx),
+		endp_reg_val);
+
+	ipa_ctx->hol_en = endp_reg_val;
+
+	return count;
+}
+
+static ssize_t ipa_write_ep_hol_timer_reg(struct file *file,
+		const char __user *buf, size_t count, loff_t *ppos)
+{
+	u32 endp_reg_val;
+	unsigned long missing;
+
+	if (sizeof(dbg_buff) < count + 1)
+		return -EFAULT;
+
+	missing = copy_from_user(dbg_buff, buf, count);
+	if (missing)
+		return -EFAULT;
+
+	dbg_buff[count] = '\0';
+	if (kstrtou32(dbg_buff, 16, &endp_reg_val))
+		return -EFAULT;
+
+	ipa_write_reg(ipa_ctx->mmio,
+		IPA_ENDP_INIT_HOL_BLOCK_TIMER_n_OFST(ep_reg_idx),
+		endp_reg_val);
+
+	ipa_ctx->hol_timer = endp_reg_val;
+
+	return count;
+}
+
 static ssize_t ipa_write_ep_reg(struct file *file, const char __user *buf,
 		size_t count, loff_t *ppos)
 {
@@ -556,7 +610,13 @@
 			"x_intr_repost=%u\n"
 			"rx_q_len=%u\n"
 			"act_clnt=%u\n"
-			"con_clnt_bmap=0x%x\n",
+			"con_clnt_bmap=0x%x\n"
+			"a2_power_on_reqs_in=%u\n"
+			"a2_power_on_reqs_out=%u\n"
+			"a2_power_off_reqs_in=%u\n"
+			"a2_power_off_reqs_out=%u\n"
+			"a2_power_modem_acks=%u\n"
+			"a2_power_apps_acks=%u\n",
 			ipa_ctx->stats.tx_sw_pkts,
 			ipa_ctx->stats.tx_hw_pkts,
 			ipa_ctx->stats.rx_pkts,
@@ -564,7 +624,13 @@
 			ipa_ctx->stats.x_intr_repost,
 			ipa_ctx->stats.rx_q_len,
 			ipa_ctx->ipa_active_clients,
-			connect);
+			connect,
+			ipa_ctx->stats.a2_power_on_reqs_in,
+			ipa_ctx->stats.a2_power_on_reqs_out,
+			ipa_ctx->stats.a2_power_off_reqs_in,
+			ipa_ctx->stats.a2_power_off_reqs_out,
+			ipa_ctx->stats.a2_power_modem_acks,
+			ipa_ctx->stats.a2_power_apps_acks);
 	cnt += nbytes;
 
 	for (i = 0; i < MAX_NUM_EXCP; i++) {
@@ -663,6 +729,13 @@
 	.write = ipa_write_ep_reg,
 };
 
+const struct file_operations ipa_ep_hol_en_ops = {
+	.write = ipa_write_ep_hol_en_reg,
+};
+const struct file_operations ipa_ep_hol_timer_ops = {
+	.write = ipa_write_ep_hol_timer_reg,
+};
+
 const struct file_operations ipa_hdr_ops = {
 	.read = ipa_read_hdr,
 };
@@ -695,6 +768,7 @@
 	const mode_t read_only_mode = S_IRUSR | S_IRGRP | S_IROTH;
 	const mode_t read_write_mode = S_IRUSR | S_IRGRP | S_IROTH |
 			S_IWUSR | S_IWGRP | S_IWOTH;
+	const mode_t write_only_mode = S_IWUSR | S_IWGRP | S_IWOTH;
 
 	dent = debugfs_create_dir("ipa", 0);
 	if (IS_ERR(dent)) {
@@ -716,6 +790,20 @@
 		goto fail;
 	}
 
+	dfile_ep_hol_en = debugfs_create_file("hol_en", write_only_mode, dent,
+			0, &ipa_ep_hol_en_ops);
+	if (!dfile_ep_hol_en || IS_ERR(dfile_ep_hol_en)) {
+		IPAERR("fail to create file for debug_fs dfile_ep_hol_en\n");
+		goto fail;
+	}
+
+	dfile_ep_hol_timer = debugfs_create_file("hol_timer", write_only_mode,
+			dent, 0, &ipa_ep_hol_timer_ops);
+	if (!dfile_ep_hol_timer || IS_ERR(dfile_ep_hol_timer)) {
+		IPAERR("fail to create file for debug_fs dfile_ep_hol_timer\n");
+		goto fail;
+	}
+
 	dfile_hdr = debugfs_create_file("hdr", read_only_mode, dent, 0,
 			&ipa_hdr_ops);
 	if (!dfile_hdr || IS_ERR(dfile_hdr)) {
diff --git a/drivers/platform/msm/ipa/ipa_flt.c b/drivers/platform/msm/ipa/ipa_flt.c
index b63b939..edb9fb1 100644
--- a/drivers/platform/msm/ipa/ipa_flt.c
+++ b/drivers/platform/msm/ipa/ipa_flt.c
@@ -368,6 +368,7 @@
 	return 0;
 proc_err:
 	dma_free_coherent(NULL, mem->size, mem->base, mem->phys_base);
+	mem->base = NULL;
 error:
 
 	return -EPERM;
@@ -456,7 +457,7 @@
 
 	if (mem->size > avail) {
 		IPAERR("tbl too big, needed %d avail %d\n", mem->size, avail);
-		goto fail_hw_tbl_gen;
+		goto fail_send_cmd;
 	}
 
 	if (ip == IPA_IP_v4) {
diff --git a/drivers/platform/msm/ipa/ipa_hdr.c b/drivers/platform/msm/ipa/ipa_hdr.c
index 7d0bc24..9618da2 100644
--- a/drivers/platform/msm/ipa/ipa_hdr.c
+++ b/drivers/platform/msm/ipa/ipa_hdr.c
@@ -89,7 +89,7 @@
 	if (ipa_ctx->hdr_tbl_lcl && mem->size > IPA_RAM_HDR_SIZE) {
 		IPAERR("tbl too big, needed %d avail %d\n", mem->size,
 				IPA_RAM_HDR_SIZE);
-		goto fail_hw_tbl_gen;
+		goto fail_send_cmd;
 	}
 
 	cmd->hdr_table_addr = mem->phys_base;
@@ -126,7 +126,7 @@
 	return 0;
 
 fail_send_cmd:
-	if (mem->phys_base)
+	if (mem->base)
 		dma_free_coherent(NULL, mem->size, mem->base, mem->phys_base);
 fail_hw_tbl_gen:
 	kfree(cmd);
diff --git a/drivers/platform/msm/ipa/ipa_i.h b/drivers/platform/msm/ipa/ipa_i.h
index a03ba16..cc3e630 100644
--- a/drivers/platform/msm/ipa/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_i.h
@@ -30,7 +30,8 @@
 #define IPA_COOKIE 0xfacefeed
 
 #define IPA_NUM_PIPES 0x14
-#define IPA_SYS_DESC_FIFO_SZ (0x800)
+#define IPA_SYS_DESC_FIFO_SZ 0x800
+#define IPA_SYS_TX_DATA_DESC_FIFO_SZ 0x1000
 
 #ifdef IPA_DEBUG
 #define IPADBG(fmt, args...) \
@@ -40,10 +41,11 @@
 #define IPADBG(fmt, args...)
 #endif
 
-#define WLAN_AMPDU_TX_EP (15)
-#define WLAN_PROD_TX_EP (19)
-#define MAX_NUM_EXCP	 (8)
-#define MAX_NUM_IMM_CMD	 (17)
+#define WLAN_AMPDU_TX_EP 15
+#define WLAN_PROD_TX_EP  19
+
+#define MAX_NUM_EXCP     8
+#define MAX_NUM_IMM_CMD 17
 
 #define IPA_STATS
 
@@ -531,6 +533,12 @@
 	u32 rx_q_len;
 	u32 msg_w[IPA_EVENT_MAX];
 	u32 msg_r[IPA_EVENT_MAX];
+	u32 a2_power_on_reqs_in;
+	u32 a2_power_on_reqs_out;
+	u32 a2_power_off_reqs_in;
+	u32 a2_power_off_reqs_out;
+	u32 a2_power_modem_acks;
+	u32 a2_power_apps_acks;
 };
 
 /**
@@ -659,6 +667,10 @@
 	enum ipa_hw_mode ipa_hw_mode;
 	/* featurize if memory footprint becomes a concern */
 	struct ipa_stats stats;
+	void *smem_pipe_mem;
+	/* store HOLB configuration for WLAN TX pipes */
+	u32 hol_en;
+	u32 hol_timer;
 };
 
 /**
@@ -743,7 +755,7 @@
 				struct a2_mux_pipe_connection *pipe_connect);
 int ipa_get_a2_mux_bam_info(u32 *a2_bam_mem_base, u32 *a2_bam_mem_size,
 			    u32 *a2_bam_irq);
-void rmnet_bridge_get_client_handles(u32 *producer_handle,
+void teth_bridge_get_client_handles(u32 *producer_handle,
 		u32 *consumer_handle);
 int ipa_send_one(struct ipa_sys_context *sys, struct ipa_desc *desc,
 		bool in_atomic);
diff --git a/drivers/platform/msm/ipa/ipa_rt.c b/drivers/platform/msm/ipa/ipa_rt.c
index fc5f668..6430c07 100644
--- a/drivers/platform/msm/ipa/ipa_rt.c
+++ b/drivers/platform/msm/ipa/ipa_rt.c
@@ -305,6 +305,7 @@
 			  rt_tbl_mem.base, rt_tbl_mem.phys_base);
 proc_err:
 	dma_free_coherent(NULL, mem->size, mem->base, mem->phys_base);
+	mem->base = NULL;
 error:
 	return -EPERM;
 }
@@ -378,7 +379,7 @@
 
 	if (mem->size > avail) {
 		IPAERR("tbl too big, needed %d avail %d\n", mem->size, avail);
-		goto fail_hw_tbl_gen;
+		goto fail_send_cmd;
 	}
 
 	if (ip == IPA_IP_v4) {
@@ -413,7 +414,7 @@
 	return 0;
 
 fail_send_cmd:
-	if (mem->phys_base)
+	if (mem->base)
 		dma_free_coherent(NULL, mem->size, mem->base, mem->phys_base);
 fail_hw_tbl_gen:
 	kfree(cmd);
diff --git a/drivers/platform/msm/ipa/rmnet_bridge.c b/drivers/platform/msm/ipa/rmnet_bridge.c
deleted file mode 100644
index 696b363..0000000
--- a/drivers/platform/msm/ipa/rmnet_bridge.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/* 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
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <linux/export.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <mach/bam_dmux.h>
-#include <mach/ipa.h>
-#include <mach/sps.h>
-
-static struct rmnet_bridge_cb_type {
-	u32 producer_handle;
-	u32 consumer_handle;
-	u32 ipa_producer_handle;
-	u32 ipa_consumer_handle;
-	bool is_connected;
-} rmnet_bridge_cb;
-
-/**
-* rmnet_bridge_init() - Initialize RmNet bridge module
-*
-* Return codes:
-* 0: success
-*/
-int rmnet_bridge_init(void)
-{
-	memset(&rmnet_bridge_cb, 0, sizeof(struct rmnet_bridge_cb_type));
-
-	return 0;
-}
-EXPORT_SYMBOL(rmnet_bridge_init);
-
-/**
-* rmnet_bridge_disconnect() - Disconnect RmNet bridge module
-*
-* Return codes:
-* 0: success
-* -EINVAL: invalid parameters
-*/
-int rmnet_bridge_disconnect(void)
-{
-	int ret = 0;
-	if (false == rmnet_bridge_cb.is_connected) {
-		pr_err("%s: trying to disconnect already disconnected RmNet bridge\n",
-		       __func__);
-		goto bail;
-	}
-
-	rmnet_bridge_cb.is_connected = false;
-
-	ret = ipa_bridge_teardown(IPA_BRIDGE_DIR_DL, IPA_BRIDGE_TYPE_TETHERED,
-				  rmnet_bridge_cb.ipa_consumer_handle);
-	ret = ipa_bridge_teardown(IPA_BRIDGE_DIR_UL, IPA_BRIDGE_TYPE_TETHERED,
-				  rmnet_bridge_cb.ipa_producer_handle);
-bail:
-	return ret;
-}
-EXPORT_SYMBOL(rmnet_bridge_disconnect);
-
-/**
-* rmnet_bridge_connect() - Connect RmNet bridge module
-* @producer_hdl:	IPA producer handle
-* @consumer_hdl:	IPA consumer handle
-* @wwan_logical_channel_id:	WWAN logical channel ID
-*
-* Return codes:
-* 0: success
-* -EINVAL: invalid parameters
-*/
-int rmnet_bridge_connect(u32 producer_hdl,
-			 u32 consumer_hdl,
-			 int wwan_logical_channel_id)
-{
-	struct ipa_sys_connect_params props;
-	int ret = 0;
-
-	if (true == rmnet_bridge_cb.is_connected) {
-		ret = 0;
-		pr_err("%s: trying to connect already connected RmNet bridge\n",
-		       __func__);
-		goto bail;
-	}
-
-	rmnet_bridge_cb.consumer_handle = consumer_hdl;
-	rmnet_bridge_cb.producer_handle = producer_hdl;
-	rmnet_bridge_cb.is_connected = true;
-
-	memset(&props, 0, sizeof(props));
-	props.ipa_ep_cfg.mode.mode = IPA_DMA;
-	props.ipa_ep_cfg.mode.dst = IPA_CLIENT_USB_CONS;
-	props.client = IPA_CLIENT_A2_TETHERED_PROD;
-	props.desc_fifo_sz = 0x800;
-	/* setup notification callback if needed */
-
-	ret = ipa_bridge_setup(IPA_BRIDGE_DIR_DL, IPA_BRIDGE_TYPE_TETHERED,
-			&props, &rmnet_bridge_cb.ipa_consumer_handle);
-	if (ret) {
-		pr_err("%s: IPA DL bridge setup failure\n", __func__);
-		goto bail_dl;
-	}
-
-	memset(&props, 0, sizeof(props));
-	props.client = IPA_CLIENT_A2_TETHERED_CONS;
-	props.desc_fifo_sz = 0x800;
-	/* setup notification callback if needed */
-
-	ret = ipa_bridge_setup(IPA_BRIDGE_DIR_UL, IPA_BRIDGE_TYPE_TETHERED,
-			&props, &rmnet_bridge_cb.ipa_producer_handle);
-	if (ret) {
-		pr_err("%s: IPA UL bridge setup failure\n", __func__);
-		goto bail_ul;
-	}
-	return 0;
-bail_ul:
-	ipa_bridge_teardown(IPA_BRIDGE_DIR_DL, IPA_BRIDGE_TYPE_TETHERED,
-			    rmnet_bridge_cb.ipa_consumer_handle);
-bail_dl:
-	rmnet_bridge_cb.is_connected = false;
-bail:
-	return ret;
-}
-EXPORT_SYMBOL(rmnet_bridge_connect);
-
-void rmnet_bridge_get_client_handles(u32 *producer_handle,
-		u32 *consumer_handle)
-{
-	if (producer_handle == NULL || consumer_handle == NULL)
-		return;
-
-	*producer_handle = rmnet_bridge_cb.producer_handle;
-	*consumer_handle = rmnet_bridge_cb.consumer_handle;
-}
diff --git a/drivers/platform/msm/ipa/teth_bridge.c b/drivers/platform/msm/ipa/teth_bridge.c
index 774c0e6..40c8fc7 100644
--- a/drivers/platform/msm/ipa/teth_bridge.c
+++ b/drivers/platform/msm/ipa/teth_bridge.c
@@ -60,6 +60,15 @@
 
 #define TETH_MTU_BYTE 1500
 
+#define TETH_INACTIVITY_TIME_MSEC (1000)
+
+#define TETH_WORKQUEUE_NAME "tethering_bridge_wq"
+
+#define TETH_TOTAL_HDR_ENTRIES 6
+#define TETH_TOTAL_RT_ENTRIES_IP 3
+#define TETH_TOTAL_FLT_ENTRIES_IP 2
+#define TETH_IP_FAMILIES 2
+
 struct mac_addresses_type {
 	u8 host_pc_mac_addr[ETH_ALEN];
 	bool host_pc_mac_addr_known;
@@ -70,6 +79,7 @@
 struct stats {
 	u64 a2_to_usb_num_sw_tx_packets;
 	u64 usb_to_a2_num_sw_tx_packets;
+	u64 num_sw_tx_packets_during_resource_wakeup;
 };
 
 struct teth_bridge_ctx {
@@ -94,9 +104,24 @@
 	bool comp_hw_bridge_in_progress;
 	struct teth_aggr_capabilities *aggr_caps;
 	struct stats stats;
+	struct workqueue_struct *teth_wq;
+	u16 a2_ipa_hdr_len;
+	struct ipa_ioc_del_hdr *hdr_del;
+	struct ipa_ioc_del_rt_rule *routing_del[TETH_IP_FAMILIES];
+	struct ipa_ioc_del_flt_rule *filtering_del[TETH_IP_FAMILIES];
+};
+static struct teth_bridge_ctx *teth_ctx;
+
+enum teth_packet_direction {
+	TETH_USB_TO_A2,
+	TETH_A2_TO_USB,
 };
 
-static struct teth_bridge_ctx *teth_ctx;
+struct teth_work {
+	struct work_struct work;
+	struct sk_buff *skb;
+	enum teth_packet_direction dir;
+};
 
 #ifdef CONFIG_DEBUG_FS
 #define TETH_MAX_MSG_LEN 512
@@ -110,6 +135,7 @@
 	struct ipa_ioc_add_hdr *hdrs;
 	struct ethhdr hdr_ipv4;
 	struct ethhdr hdr_ipv6;
+	int idx1;
 
 	TETH_DBG_FUNC_ENTRY();
 	memcpy(hdr_ipv4.h_source, src_mac_addr, ETH_ALEN);
@@ -144,6 +170,13 @@
 	res = ipa_add_hdr(hdrs);
 	if (res || hdrs->hdr[0].status || hdrs->hdr[1].status)
 		TETH_ERR("Header insertion failed\n");
+
+	/* Save the headers handles in order to delete them later */
+	for (idx1 = 0; idx1 < hdrs->num_hdrs; idx1++) {
+		int idx2 = teth_ctx->hdr_del->num_hdls++;
+		teth_ctx->hdr_del->hdl[idx2].hdl = hdrs->hdr[idx1].hdr_hdl;
+	}
+
 	kfree(hdrs);
 	TETH_DBG_FUNC_EXIT();
 
@@ -169,6 +202,7 @@
 	}
 
 	hdr_cfg.hdr_len = a2_ipa_hdr_len;
+	teth_ctx->a2_ipa_hdr_len = a2_ipa_hdr_len;
 	res = ipa_cfg_ep_hdr(teth_ctx->a2_ipa_pipe_hdl, &hdr_cfg);
 	if (res) {
 		TETH_ERR("Header removal config for A2->IPA pipe failed\n");
@@ -200,6 +234,7 @@
 	int res;
 	struct ipa_ioc_add_hdr *mbim_hdr;
 	u8 mbim_stream_id = 0;
+	int idx;
 
 	TETH_DBG_FUNC_ENTRY();
 	mbim_hdr = kzalloc(sizeof(struct ipa_ioc_add_hdr) +
@@ -223,6 +258,11 @@
 	} else {
 		TETH_DBG("Added MBIM stream ID header\n");
 	}
+
+	/* Save the header handle in order to delete it later */
+	idx = teth_ctx->hdr_del->num_hdls++;
+	teth_ctx->hdr_del->hdl[idx].hdl = mbim_hdr->hdr[0].hdr_hdl;
+
 	kfree(mbim_hdr);
 	TETH_DBG_FUNC_EXIT();
 
@@ -299,6 +339,7 @@
 	struct ipa_ioc_add_rt_rule *rt_rule;
 	struct ipa_ioc_get_hdr hdr_info;
 	int res;
+	int idx;
 
 	TETH_DBG_FUNC_ENTRY();
 	/* Get the header handle */
@@ -325,6 +366,12 @@
 	res = ipa_add_rt_rule(rt_rule);
 	if (res || rt_rule->rules[0].status)
 		TETH_ERR("Failed adding routing rule\n");
+
+	/* Save the routing rule handle in order to delete it later */
+	idx = teth_ctx->routing_del[ip_address_family]->num_hdls++;
+	teth_ctx->routing_del[ip_address_family]->hdl[idx].hdl =
+		rt_rule->rules[0].rt_rule_hdl;
+
 	kfree(rt_rule);
 	TETH_DBG_FUNC_EXIT();
 
@@ -432,6 +479,7 @@
 	struct ipa_ioc_add_flt_rule *flt_tbl;
 	struct ipa_ioc_get_rt_tbl rt_tbl_info;
 	int res;
+	int idx;
 
 	TETH_DBG_FUNC_ENTRY();
 	/* Get the needed routing table handle */
@@ -462,6 +510,12 @@
 	res = ipa_add_flt_rule(flt_tbl);
 	if (res || flt_tbl->rules[0].status)
 		TETH_ERR("Failed adding filtering table\n");
+
+	/* Save the filtering rule handle in order to delete it later */
+	idx = teth_ctx->filtering_del[ip_address_family]->num_hdls++;
+	teth_ctx->filtering_del[ip_address_family]->hdl[idx].hdl =
+		flt_tbl->rules[0].flt_rule_hdl;
+
 	kfree(flt_tbl);
 	TETH_DBG_FUNC_EXIT();
 
@@ -568,7 +622,6 @@
 	u32 pipe_hdl)
 {
 	struct ipa_ep_cfg_aggr agg_params;
-	struct ipa_ep_cfg_hdr hdr_params;
 	int res;
 
 	TETH_DBG_FUNC_ENTRY();
@@ -585,18 +638,7 @@
 		TETH_ERR("ipa_cfg_ep_aggr() failed\n");
 		goto bail;
 	}
-
-	if (!client_is_prod) {
-		memset(&hdr_params, 0, sizeof(hdr_params));
-		hdr_params.hdr_len = 1;
-		res = ipa_cfg_ep_hdr(pipe_hdl, &hdr_params);
-		if (res) {
-			TETH_ERR("ipa_cfg_ep_hdr() failed\n");
-			goto bail;
-		}
-	}
 	TETH_DBG_FUNC_EXIT();
-
 bail:
 	return res;
 }
@@ -627,6 +669,19 @@
 	char aggr_prot_str[20];
 
 	TETH_DBG_FUNC_ENTRY();
+	if (!teth_ctx->aggr_params_known) {
+		TETH_ERR("Aggregation parameters unknown.\n");
+		return -EINVAL;
+	}
+
+	if ((teth_ctx->usb_ipa_pipe_hdl == 0) ||
+	    (teth_ctx->ipa_usb_pipe_hdl == 0))
+		return 0;
+		/*
+		 * Returning 0 in case pipe handles are 0 becuase aggregation
+		 * params will be set later
+		 */
+
 	if (teth_ctx->aggr_params.ul.aggr_prot == TETH_AGGR_PROTOCOL_MBIM ||
 	    teth_ctx->aggr_params.dl.aggr_prot == TETH_AGGR_PROTOCOL_MBIM) {
 		res = ipa_set_aggr_mode(IPA_MBIM);
@@ -672,6 +727,23 @@
 	return res;
 }
 
+static int teth_request_resource(void)
+{
+	int res;
+
+	INIT_COMPLETION(teth_ctx->is_bridge_prod_up);
+	res = ipa_rm_inactivity_timer_request_resource(
+		IPA_RM_RESOURCE_BRIDGE_PROD);
+	if (res < 0) {
+		if (res == -EINPROGRESS)
+			wait_for_completion(&teth_ctx->is_bridge_prod_up);
+		else
+			return res;
+	}
+
+	return 0;
+}
+
 static void complete_hw_bridge(struct work_struct *work)
 {
 	int res;
@@ -682,6 +754,12 @@
 		 "ETHERNET" :
 		 "IP");
 
+	res = teth_request_resource();
+	if (res) {
+		TETH_ERR("request_resource() failed.\n");
+		goto bail;
+	}
+
 	res = teth_set_aggregation();
 	if (res) {
 		TETH_ERR("Failed setting aggregation params\n");
@@ -719,6 +797,7 @@
 	teth_ctx->is_hw_bridge_complete = true;
 bail:
 	teth_ctx->comp_hw_bridge_in_progress = false;
+	ipa_rm_inactivity_timer_release_resource(IPA_RM_RESOURCE_BRIDGE_PROD);
 	TETH_DBG_FUNC_EXIT();
 
 	return;
@@ -758,10 +837,78 @@
 	    (teth_ctx->aggr_params_known)) {
 		INIT_WORK(&teth_ctx->comp_hw_bridge_work, complete_hw_bridge);
 		teth_ctx->comp_hw_bridge_in_progress = true;
-		schedule_work(&teth_ctx->comp_hw_bridge_work);
+		queue_work(teth_ctx->teth_wq, &teth_ctx->comp_hw_bridge_work);
 	}
 }
 
+static void teth_send_skb_work(struct work_struct *work)
+{
+	struct teth_work *work_data =
+		container_of(work, struct teth_work, work);
+	int res;
+
+	res = teth_request_resource();
+	if (res) {
+		TETH_ERR("Packet send failure, dropping packet !\n");
+		goto bail;
+	}
+
+	switch (work_data->dir) {
+	case TETH_USB_TO_A2:
+		res = a2_mux_write(A2_MUX_TETHERED_0, work_data->skb);
+		if (res) {
+			TETH_ERR("Packet send failure, dropping packet !\n");
+			goto bail;
+		}
+		teth_ctx->stats.usb_to_a2_num_sw_tx_packets++;
+		break;
+
+	case TETH_A2_TO_USB:
+		res = ipa_tx_dp(IPA_CLIENT_USB_CONS, work_data->skb, NULL);
+		if (res) {
+			TETH_ERR("Packet send failure, dropping packet !\n");
+			goto bail;
+		}
+		teth_ctx->stats.a2_to_usb_num_sw_tx_packets++;
+		break;
+
+	default:
+		TETH_ERR("Unsupported direction to send !\n");
+		WARN_ON(1);
+	}
+	ipa_rm_inactivity_timer_release_resource(IPA_RM_RESOURCE_BRIDGE_PROD);
+	kfree(work_data);
+	teth_ctx->stats.num_sw_tx_packets_during_resource_wakeup++;
+
+	return;
+bail:
+	ipa_rm_inactivity_timer_release_resource(IPA_RM_RESOURCE_BRIDGE_PROD);
+	dev_kfree_skb(work_data->skb);
+	kfree(work_data);
+}
+
+static void defer_skb_send(struct sk_buff *skb, enum teth_packet_direction dir)
+{
+	struct teth_work *work = kmalloc(sizeof(struct teth_work), GFP_KERNEL);
+
+	if (!work) {
+		TETH_ERR("No mem, dropping packet\n");
+		dev_kfree_skb(skb);
+		ipa_rm_inactivity_timer_release_resource
+			(IPA_RM_RESOURCE_BRIDGE_PROD);
+		return;
+	}
+
+	/*
+	 * Since IPA uses a single Rx thread, we don't
+	 * want to wait for completion here
+	 */
+	INIT_WORK(&work->work, teth_send_skb_work);
+	work->dir = dir;
+	work->skb = skb;
+	queue_work(teth_ctx->teth_wq, &work->work);
+}
+
 static void usb_notify_cb(void *priv,
 			  enum ipa_dp_evt_type evt,
 			  unsigned long data)
@@ -778,13 +925,36 @@
 				&teth_ctx->mac_addresses.host_pc_mac_addr_known,
 				&teth_ctx->mac_addresses.device_mac_addr_known);
 
-		/* Send the packet to A2, using a2_service driver API */
-		teth_ctx->stats.usb_to_a2_num_sw_tx_packets++;
+		/*
+		 * Request the BRIDGE_PROD resource, send the packet and release
+		 * the resource
+		 */
+		res = ipa_rm_inactivity_timer_request_resource(
+			IPA_RM_RESOURCE_BRIDGE_PROD);
+		if (res < 0) {
+			if (res == -EINPROGRESS) {
+				/* The resource is waking up */
+				defer_skb_send(skb, TETH_USB_TO_A2);
+			} else {
+				TETH_ERR(
+					"Packet send failure, dropping packet !\n");
+				dev_kfree_skb(skb);
+			}
+			ipa_rm_inactivity_timer_release_resource(
+				IPA_RM_RESOURCE_BRIDGE_PROD);
+			return;
+		}
 		res = a2_mux_write(A2_MUX_TETHERED_0, skb);
 		if (res) {
 			TETH_ERR("Packet send failure, dropping packet !\n");
 			dev_kfree_skb(skb);
+			ipa_rm_inactivity_timer_release_resource(
+				IPA_RM_RESOURCE_BRIDGE_PROD);
+			return;
 		}
+		teth_ctx->stats.usb_to_a2_num_sw_tx_packets++;
+		ipa_rm_inactivity_timer_release_resource(
+			IPA_RM_RESOURCE_BRIDGE_PROD);
 		break;
 
 	case IPA_WRITE_DONE:
@@ -816,13 +986,37 @@
 				&teth_ctx->
 				mac_addresses.host_pc_mac_addr_known);
 
-		/* Send the packet to USB */
-		teth_ctx->stats.a2_to_usb_num_sw_tx_packets++;
+		/*
+		 * Request the BRIDGE_PROD resource, send the packet and release
+		 * the resource
+		 */
+		res = ipa_rm_inactivity_timer_request_resource(
+			IPA_RM_RESOURCE_BRIDGE_PROD);
+		if (res < 0) {
+			if (res == -EINPROGRESS) {
+				/* The resource is waking up */
+				defer_skb_send(skb, TETH_A2_TO_USB);
+			} else {
+				TETH_ERR(
+					"Packet send failure, dropping packet !\n");
+				dev_kfree_skb(skb);
+			}
+			ipa_rm_inactivity_timer_release_resource(
+				IPA_RM_RESOURCE_BRIDGE_PROD);
+			return;
+		}
+
 		res = ipa_tx_dp(IPA_CLIENT_USB_CONS, skb, NULL);
 		if (res) {
 			TETH_ERR("Packet send failure, dropping packet !\n");
 			dev_kfree_skb(skb);
+			ipa_rm_inactivity_timer_release_resource(
+				IPA_RM_RESOURCE_BRIDGE_PROD);
+			return;
 		}
+		teth_ctx->stats.a2_to_usb_num_sw_tx_packets++;
+		ipa_rm_inactivity_timer_release_resource(
+			IPA_RM_RESOURCE_BRIDGE_PROD);
 		break;
 
 	case A2_MUX_WRITE_DONE:
@@ -841,8 +1035,28 @@
 				  enum ipa_rm_event event,
 				  unsigned long data)
 {
+	int res;
+	struct ipa_ep_cfg ipa_ep_cfg;
+
 	switch (event) {
 	case IPA_RM_RESOURCE_GRANTED:
+		res = a2_mux_get_tethered_client_handles(
+			A2_MUX_TETHERED_0,
+			&teth_ctx->ipa_a2_pipe_hdl,
+			&teth_ctx->a2_ipa_pipe_hdl);
+		if (res) {
+			TETH_ERR(
+				"a2_mux_get_tethered_client_handles() failed, res = %d\n",
+				res);
+			return;
+		}
+
+		/* Reset the various endpoints configuration */
+		memset(&ipa_ep_cfg, 0, sizeof(ipa_ep_cfg));
+		ipa_cfg_ep(teth_ctx->ipa_a2_pipe_hdl, &ipa_ep_cfg);
+
+		ipa_ep_cfg.hdr.hdr_len = teth_ctx->a2_ipa_hdr_len;
+		ipa_cfg_ep(teth_ctx->a2_ipa_pipe_hdl, &ipa_ep_cfg);
 		complete(&teth_ctx->is_bridge_prod_up);
 		break;
 
@@ -886,32 +1100,34 @@
 	/* Build IPA Resource manager dependency graph */
 	res = ipa_rm_add_dependency(IPA_RM_RESOURCE_BRIDGE_PROD,
 				    IPA_RM_RESOURCE_USB_CONS);
-	if (res && res != -EEXIST) {
+	if (res && res != -EINPROGRESS) {
 		TETH_ERR("ipa_rm_add_dependency() failed\n");
 		goto bail;
 	}
 
 	res = ipa_rm_add_dependency(IPA_RM_RESOURCE_BRIDGE_PROD,
 				    IPA_RM_RESOURCE_A2_CONS);
-	if (res && res != -EEXIST) {
+	if (res && res != -EINPROGRESS) {
 		TETH_ERR("ipa_rm_add_dependency() failed\n");
 		goto fail_add_dependency_1;
 	}
 
 	res = ipa_rm_add_dependency(IPA_RM_RESOURCE_USB_PROD,
 				    IPA_RM_RESOURCE_A2_CONS);
-	if (res && res != -EEXIST) {
+	if (res && res != -EINPROGRESS) {
 		TETH_ERR("ipa_rm_add_dependency() failed\n");
 		goto fail_add_dependency_2;
 	}
 
 	res = ipa_rm_add_dependency(IPA_RM_RESOURCE_A2_PROD,
 				    IPA_RM_RESOURCE_USB_CONS);
-	if (res && res != -EEXIST) {
+	if (res && res != -EINPROGRESS) {
 		TETH_ERR("ipa_rm_add_dependency() failed\n");
 		goto fail_add_dependency_3;
 	}
 
+	/* Return 0 as EINPROGRESS is a valid return value at this point */
+	res = 0;
 	goto bail;
 
 fail_add_dependency_3:
@@ -929,6 +1145,57 @@
 }
 EXPORT_SYMBOL(teth_bridge_init);
 
+static void initialize_context(void)
+{
+	TETH_DBG_FUNC_ENTRY();
+	/* Initialize context variables */
+	teth_ctx->usb_ipa_pipe_hdl = 0;
+	teth_ctx->ipa_a2_pipe_hdl = 0;
+	teth_ctx->a2_ipa_pipe_hdl = 0;
+	teth_ctx->ipa_usb_pipe_hdl = 0;
+	teth_ctx->is_connected = false;
+
+	/* The default link protocol is Ethernet */
+	teth_ctx->link_protocol = TETH_LINK_PROTOCOL_ETHERNET;
+
+	memset(&teth_ctx->mac_addresses, 0, sizeof(teth_ctx->mac_addresses));
+	teth_ctx->is_hw_bridge_complete = false;
+	memset(&teth_ctx->aggr_params, 0, sizeof(teth_ctx->aggr_params));
+	teth_ctx->aggr_params_known = false;
+	teth_ctx->tethering_mode = 0;
+	INIT_COMPLETION(teth_ctx->is_bridge_prod_up);
+	INIT_COMPLETION(teth_ctx->is_bridge_prod_down);
+	teth_ctx->comp_hw_bridge_in_progress = false;
+	memset(&teth_ctx->stats, 0, sizeof(teth_ctx->stats));
+	teth_ctx->a2_ipa_hdr_len = 0;
+	memset(teth_ctx->hdr_del,
+	       0,
+	       sizeof(struct ipa_ioc_del_hdr) + TETH_TOTAL_HDR_ENTRIES *
+	       sizeof(struct ipa_hdr_del));
+	memset(teth_ctx->routing_del[IPA_IP_v4],
+	       0,
+	       sizeof(struct ipa_ioc_del_rt_rule) +
+	       TETH_TOTAL_RT_ENTRIES_IP * sizeof(struct ipa_rt_rule_del));
+	teth_ctx->routing_del[IPA_IP_v4]->ip = IPA_IP_v4;
+	memset(teth_ctx->routing_del[IPA_IP_v6],
+	       0,
+	       sizeof(struct ipa_ioc_del_rt_rule) +
+	       TETH_TOTAL_RT_ENTRIES_IP * sizeof(struct ipa_rt_rule_del));
+	teth_ctx->routing_del[IPA_IP_v6]->ip = IPA_IP_v6;
+	memset(teth_ctx->filtering_del[IPA_IP_v4],
+	       0,
+	       sizeof(struct ipa_ioc_del_flt_rule) +
+	       TETH_TOTAL_FLT_ENTRIES_IP * sizeof(struct ipa_flt_rule_del));
+	teth_ctx->filtering_del[IPA_IP_v4]->ip = IPA_IP_v4;
+	memset(teth_ctx->filtering_del[IPA_IP_v6],
+	       0,
+	       sizeof(struct ipa_ioc_del_flt_rule) +
+	       TETH_TOTAL_FLT_ENTRIES_IP * sizeof(struct ipa_flt_rule_del));
+	teth_ctx->filtering_del[IPA_IP_v6]->ip = IPA_IP_v6;
+
+	TETH_DBG_FUNC_EXIT();
+}
+
 /**
 * teth_bridge_disconnect() - Disconnect tethering bridge module
 *
@@ -938,38 +1205,82 @@
 */
 int teth_bridge_disconnect(void)
 {
-	int res = -EPERM;
+	int res;
 
 	TETH_DBG_FUNC_ENTRY();
 	if (!teth_ctx->is_connected) {
 		TETH_ERR(
-		"Trying to disconnect an already disconnected bridge\n");
+			"Trying to disconnect an already disconnected bridge\n");
+		goto bail;
+	}
+
+	/* Request the BRIDGE_PROD resource */
+	res = teth_request_resource();
+	if (res) {
+		TETH_ERR("request_resource() failed.\n");
 		goto bail;
 	}
 
 	teth_ctx->is_connected = false;
 
-	res = ipa_rm_release_resource(IPA_RM_RESOURCE_BRIDGE_PROD);
-	if (res == -EINPROGRESS)
-		wait_for_completion(&teth_ctx->is_bridge_prod_down);
+	/* Close the channel to A2 */
+	if (a2_mux_close_channel(A2_MUX_TETHERED_0))
+		TETH_ERR("a2_mux_close_channel() failed\n");
 
-	/* Initialize statistics */
-	memset(&teth_ctx->stats, 0, sizeof(teth_ctx->stats));
+	if (teth_ctx->is_hw_bridge_complete) {
+		/* Delete header entries */
+		if (ipa_del_hdr(teth_ctx->hdr_del))
+			TETH_ERR("ipa_del_hdr() failed\n");
+
+		/* Delete installed routing rules */
+		if (ipa_del_rt_rule(teth_ctx->routing_del[IPA_IP_v4]))
+			TETH_ERR("ipa_del_rt_rule() failed\n");
+		if (ipa_del_rt_rule(teth_ctx->routing_del[IPA_IP_v6]))
+			TETH_ERR("ipa_del_rt_rule() failed\n");
+
+		/* Delete installed filtering rules */
+		if (ipa_del_flt_rule(teth_ctx->filtering_del[IPA_IP_v4]))
+			TETH_ERR("ipa_del_flt_rule() failed\n");
+		if (ipa_del_flt_rule(teth_ctx->filtering_del[IPA_IP_v6]))
+			TETH_ERR("ipa_del_flt_rule() failed\n");
+
+		/*
+		 * Commit all the data to HW, including header, routing and
+		 * filtering blocks, IPv4 and IPv6
+		 */
+		if (ipa_commit_hdr())
+			TETH_ERR("Failed committing headers\n");
+	}
+
+	initialize_context();
+
+	ipa_rm_inactivity_timer_release_resource(IPA_RM_RESOURCE_BRIDGE_PROD);
 
 	/* Delete IPA Resource manager dependency graph */
 	res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_BRIDGE_PROD,
 				       IPA_RM_RESOURCE_USB_CONS);
-	res |= ipa_rm_delete_dependency(IPA_RM_RESOURCE_BRIDGE_PROD,
-					IPA_RM_RESOURCE_A2_CONS);
-	res |= ipa_rm_delete_dependency(IPA_RM_RESOURCE_USB_PROD,
-					IPA_RM_RESOURCE_A2_CONS);
-	res |= ipa_rm_delete_dependency(IPA_RM_RESOURCE_A2_PROD,
-					IPA_RM_RESOURCE_USB_CONS);
-	if (res)
-		TETH_ERR("Failed deleting ipa_rm dependency.\n");
+	if ((res != 0) && (res != -EINPROGRESS))
+		TETH_ERR(
+			"Failed deleting ipa_rm dependency BRIDGE_PROD <-> USB_CONS\n");
+	res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_BRIDGE_PROD,
+				       IPA_RM_RESOURCE_A2_CONS);
+	if ((res != 0) && (res != -EINPROGRESS))
+		TETH_ERR(
+			"Failed deleting ipa_rm dependency BRIDGE_PROD <-> A2_CONS\n");
+	res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_USB_PROD,
+				       IPA_RM_RESOURCE_A2_CONS);
+	if ((res != 0) && (res != -EINPROGRESS))
+		TETH_ERR(
+			"Failed deleting ipa_rm dependency USB_PROD <-> A2_CONS\n");
+	res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_A2_PROD,
+				       IPA_RM_RESOURCE_USB_CONS);
+	if ((res != 0) && (res != -EINPROGRESS))
+		TETH_ERR(
+			"Failed deleting ipa_rm dependency A2_PROD <-> USB_CONS\n");
 bail:
 	TETH_DBG_FUNC_EXIT();
-	return res;
+
+	return 0;
 }
 EXPORT_SYMBOL(teth_bridge_disconnect);
 
@@ -1003,12 +1314,10 @@
 	teth_ctx->usb_ipa_pipe_hdl = connect_params->usb_ipa_pipe_hdl;
 	teth_ctx->tethering_mode = connect_params->tethering_mode;
 
-	res = ipa_rm_request_resource(IPA_RM_RESOURCE_BRIDGE_PROD);
-	if (res < 0) {
-		if (res == -EINPROGRESS)
-			wait_for_completion(&teth_ctx->is_bridge_prod_up);
-		else
-			goto bail;
+	res = teth_request_resource();
+	if (res) {
+		TETH_ERR("request_resource() failed.\n");
+		goto bail;
 	}
 
 	res = a2_mux_open_channel(A2_MUX_TETHERED_0,
@@ -1039,10 +1348,28 @@
 
 	if (teth_ctx->tethering_mode == TETH_TETHERING_MODE_MBIM)
 		teth_ctx->link_protocol = TETH_LINK_PROTOCOL_IP;
-	TETH_DBG_FUNC_EXIT();
+
+	if (teth_ctx->aggr_params_known) {
+		res = teth_set_aggregation();
+		if (res) {
+			TETH_ERR("Failed setting aggregation params\n");
+			goto bail;
+		}
+	}
+
+	/* In case of IP link protocol, complete HW bridge */
+	if ((teth_ctx->link_protocol == TETH_LINK_PROTOCOL_IP) &&
+	    (!teth_ctx->comp_hw_bridge_in_progress) &&
+	    (teth_ctx->aggr_params_known) &&
+	    (!teth_ctx->is_hw_bridge_complete)) {
+		INIT_WORK(&teth_ctx->comp_hw_bridge_work, complete_hw_bridge);
+		teth_ctx->comp_hw_bridge_in_progress = true;
+		queue_work(teth_ctx->teth_wq, &teth_ctx->comp_hw_bridge_work);
+	}
 bail:
-	if (res)
-		ipa_rm_release_resource(IPA_RM_RESOURCE_BRIDGE_PROD);
+	ipa_rm_inactivity_timer_release_resource(IPA_RM_RESOURCE_BRIDGE_PROD);
+	TETH_DBG_FUNC_EXIT();
+
 	return res;
 }
 EXPORT_SYMBOL(teth_bridge_connect);
@@ -1068,6 +1395,7 @@
 {
 	int res;
 
+	TETH_DBG_FUNC_ENTRY();
 	if (!aggr_params) {
 		TETH_ERR("Invalid parameter\n");
 		return -EINVAL;
@@ -1086,6 +1414,14 @@
 		aggr_params->ul.max_transfer_size_byte =
 			TETH_AGGR_MAX_AGGR_PACKET_SIZE_DEFAULT;
 
+	/* Ethernet link protocol and MBIM aggregation is not supported */
+	if (teth_ctx->link_protocol == TETH_LINK_PROTOCOL_ETHERNET &&
+	    (aggr_params->dl.aggr_prot == TETH_AGGR_PROTOCOL_MBIM ||
+	     aggr_params->ul.aggr_prot == TETH_AGGR_PROTOCOL_MBIM)) {
+		TETH_ERR("Ethernet with MBIM is not supported.\n");
+		return -EINVAL;
+	}
+
 	memcpy(&teth_ctx->aggr_params,
 	       aggr_params,
 	       sizeof(struct teth_aggr_params));
@@ -1096,6 +1432,7 @@
 	res = teth_set_aggregation();
 	if (res)
 		TETH_ERR("Failed setting aggregation params\n");
+	TETH_DBG_FUNC_EXIT();
 
 	return res;
 }
@@ -1135,6 +1472,19 @@
 		}
 
 		res = teth_bridge_set_aggr_params(&aggr_params);
+		if (res)
+			break;
+
+		/* In case of IP link protocol, complete HW bridge */
+		if ((teth_ctx->link_protocol == TETH_LINK_PROTOCOL_IP) &&
+		    (!teth_ctx->comp_hw_bridge_in_progress) &&
+		    (!teth_ctx->is_hw_bridge_complete)) {
+			INIT_WORK(&teth_ctx->comp_hw_bridge_work,
+				  complete_hw_bridge);
+			teth_ctx->comp_hw_bridge_in_progress = true;
+			queue_work(teth_ctx->teth_wq,
+				   &teth_ctx->comp_hw_bridge_work);
+		}
 		break;
 
 	case TETH_BRIDGE_IOC_GET_AGGR_PARAMS:
@@ -1190,7 +1540,7 @@
 	return res;
 }
 
-static void set_aggr_capabilities(void)
+static int set_aggr_capabilities(void)
 {
 	u16 NUM_PROTOCOLS = 2;
 
@@ -1198,9 +1548,9 @@
 				      NUM_PROTOCOLS *
 				      sizeof(struct teth_aggr_params_link),
 				      GFP_KERNEL);
-	if (teth_ctx->aggr_caps == NULL) {
+	if (!teth_ctx->aggr_caps) {
 		TETH_ERR("Memory alloc failed for aggregation capabilities.\n");
-		return;
+		return -ENOMEM;
 	}
 
 	teth_ctx->aggr_caps->num_protocols = NUM_PROTOCOLS;
@@ -1210,8 +1560,15 @@
 
 	teth_ctx->aggr_caps->prot_caps[1].aggr_prot = TETH_AGGR_PROTOCOL_TLP;
 	set_aggr_default_params(&teth_ctx->aggr_caps->prot_caps[1]);
+
+	return 0;
 }
 
+/**
+* teth_bridge_get_client_handles() - Get USB <--> IPA pipe handles
+* @producer_handle:	USB --> IPA pipe handle
+* @consumer_handle:	IPA --> USB pipe handle
+*/
 void teth_bridge_get_client_handles(u32 *producer_handle,
 		u32 *consumer_handle)
 {
@@ -1379,6 +1736,11 @@
 			    TETH_MAX_MSG_LEN - nbytes,
 			   "A2 to USB SW Tx packets: %lld\n",
 			    teth_ctx->stats.a2_to_usb_num_sw_tx_packets);
+	nbytes += scnprintf(
+		&dbg_buff[nbytes],
+		TETH_MAX_MSG_LEN - nbytes,
+		"SW Tx packets sent during resource wakeup: %lld\n",
+		teth_ctx->stats.num_sw_tx_packets_during_resource_wakeup);
 	return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, nbytes);
 }
 
@@ -1505,7 +1867,59 @@
 		return -ENOMEM;
 	}
 
-	set_aggr_capabilities();
+	res = set_aggr_capabilities();
+	if (res) {
+		TETH_ERR("kzalloc err.\n");
+		goto fail_alloc_aggr_caps;
+	}
+
+	res = -ENOMEM;
+	teth_ctx->hdr_del = kzalloc(sizeof(struct ipa_ioc_del_hdr) +
+				    TETH_TOTAL_HDR_ENTRIES *
+				    sizeof(struct ipa_hdr_del),
+				    GFP_KERNEL);
+	if (!teth_ctx->hdr_del) {
+		TETH_ERR("kzalloc err.\n");
+		goto fail_alloc_hdr_del;
+	}
+
+	teth_ctx->routing_del[IPA_IP_v4] =
+		kzalloc(sizeof(struct ipa_ioc_del_rt_rule) +
+			TETH_TOTAL_RT_ENTRIES_IP *
+			sizeof(struct ipa_rt_rule_del),
+			GFP_KERNEL);
+	if (!teth_ctx->routing_del[IPA_IP_v4]) {
+		TETH_ERR("kzalloc err.\n");
+		goto fail_alloc_routing_del_ipv4;
+	}
+	teth_ctx->routing_del[IPA_IP_v6] =
+		kzalloc(sizeof(struct ipa_ioc_del_rt_rule) +
+			TETH_TOTAL_RT_ENTRIES_IP *
+			sizeof(struct ipa_rt_rule_del),
+			GFP_KERNEL);
+	if (!teth_ctx->routing_del[IPA_IP_v6]) {
+		TETH_ERR("kzalloc err.\n");
+		goto fail_alloc_routing_del_ipv6;
+	}
+
+	teth_ctx->filtering_del[IPA_IP_v4] =
+		kzalloc(sizeof(struct ipa_ioc_del_flt_rule) +
+			TETH_TOTAL_FLT_ENTRIES_IP *
+			sizeof(struct ipa_flt_rule_del),
+			GFP_KERNEL);
+	if (!teth_ctx->filtering_del[IPA_IP_v4]) {
+		TETH_ERR("kzalloc err.\n");
+		goto fail_alloc_filtering_del_ipv4;
+	}
+	teth_ctx->filtering_del[IPA_IP_v6] =
+		kzalloc(sizeof(struct ipa_ioc_del_flt_rule) +
+			TETH_TOTAL_FLT_ENTRIES_IP *
+			sizeof(struct ipa_flt_rule_del),
+			GFP_KERNEL);
+	if (!teth_ctx->filtering_del[IPA_IP_v6]) {
+		TETH_ERR("kzalloc err.\n");
+		goto fail_alloc_filtering_del_ipv6;
+	}
 
 	teth_ctx->class = class_create(THIS_MODULE, TETH_BRIDGE_DRV_NAME);
 
@@ -1536,8 +1950,6 @@
 		goto fail_cdev_add;
 	}
 
-	teth_ctx->comp_hw_bridge_in_progress = false;
-
 	teth_debugfs_init();
 
 	/* Create BRIDGE_PROD entity in IPA Resource Manager */
@@ -1552,9 +1964,21 @@
 	init_completion(&teth_ctx->is_bridge_prod_up);
 	init_completion(&teth_ctx->is_bridge_prod_down);
 
-	/* The default link protocol is Ethernet */
-	teth_ctx->link_protocol = TETH_LINK_PROTOCOL_ETHERNET;
+	res = ipa_rm_inactivity_timer_init(IPA_RM_RESOURCE_BRIDGE_PROD,
+					   TETH_INACTIVITY_TIME_MSEC);
+	if (res) {
+		TETH_ERR("ipa_rm_inactivity_timer_init() failed, res=%d\n",
+			 res);
+		goto fail_cdev_add;
+	}
 
+	teth_ctx->teth_wq = create_workqueue(TETH_WORKQUEUE_NAME);
+	if (!teth_ctx->teth_wq) {
+		TETH_ERR("workqueue creation failed\n");
+		goto fail_cdev_add;
+	}
+
+	initialize_context();
 	TETH_DBG("Tethering bridge driver init OK\n");
 
 	return 0;
@@ -1563,7 +1987,18 @@
 fail_device_create:
 	unregister_chrdev_region(teth_ctx->dev_num, 1);
 fail_alloc_chrdev_region:
+	kfree(teth_ctx->filtering_del[IPA_IP_v6]);
+fail_alloc_filtering_del_ipv6:
+	kfree(teth_ctx->filtering_del[IPA_IP_v4]);
+fail_alloc_filtering_del_ipv4:
+	kfree(teth_ctx->routing_del[IPA_IP_v6]);
+fail_alloc_routing_del_ipv6:
+	kfree(teth_ctx->routing_del[IPA_IP_v4]);
+fail_alloc_routing_del_ipv4:
+	kfree(teth_ctx->hdr_del);
+fail_alloc_hdr_del:
 	kfree(teth_ctx->aggr_caps);
+fail_alloc_aggr_caps:
 	kfree(teth_ctx);
 	teth_ctx = NULL;
 
diff --git a/drivers/power/battery_current_limit.c b/drivers/power/battery_current_limit.c
index ecda153..69fa4a8 100644
--- a/drivers/power/battery_current_limit.c
+++ b/drivers/power/battery_current_limit.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
@@ -120,8 +120,10 @@
 
 	if (psy == NULL) {
 		psy = power_supply_get_by_name("battery");
-		if (psy == NULL)
+		if (psy == NULL) {
+			pr_err("failed to get ps battery\n");
 			return;
+		}
 	}
 
 	if (psy->get_property(psy, POWER_SUPPLY_PROP_CURRENT_NOW, &ret))
@@ -143,6 +145,7 @@
 	gbcl->bcl_imax_ma = imax_ma;
 	gbcl->bcl_vbat_mv = vbatt_mv;
 
+	pr_debug("ibatt %d, imax %d, vbatt %d\n", ibatt_ma, imax_ma, vbatt_mv);
 	if (gbcl->bcl_threshold_mode[BCL_IBAT_IMAX_THRESHOLD_TYPE_HIGH]
 		== BCL_IBAT_IMAX_THRESHOLD_ENABLED) {
 		imax_high_threshold =
@@ -179,8 +182,7 @@
 		bcl_calculate_imax_trigger();
 		/* restart the delay work for caculating imax */
 		schedule_delayed_work(&bcl->bcl_imax_work,
-			round_jiffies_relative(msecs_to_jiffies
-				(bcl->bcl_poll_interval_msec)));
+			msecs_to_jiffies(bcl->bcl_poll_interval_msec));
 	}
 }
 
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index da0a5b6..34adb6a 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -85,6 +85,9 @@
 #define CHGR_BUCK_BCK_VBAT_REG_MODE		0x74
 #define MISC_REVISION2				0x01
 #define USB_OVP_CTL				0x42
+#define USB_CHG_GONE_REV_BST			0xED
+#define BUCK_VCHG_OV				0x77
+#define BUCK_TEST_SMBC_MODES			0xE6
 #define SEC_ACCESS				0xD0
 
 #define REG_OFFSET_PERP_SUBTYPE			0x05
@@ -232,6 +235,7 @@
 	u16				freq_base;
 	unsigned int			usbin_valid_irq;
 	unsigned int			dcin_valid_irq;
+	unsigned int			chg_gone_irq;
 	unsigned int			chg_fastchg_irq;
 	unsigned int			chg_trklchg_irq;
 	unsigned int			chg_failed_irq;
@@ -272,6 +276,7 @@
 	uint32_t			flags;
 	struct qpnp_adc_tm_btm_param	adc_param;
 	struct work_struct		adc_measure_work;
+	struct delayed_work		arb_stop_work;
 };
 
 static struct of_device_id qpnp_charger_match_table[] = {
@@ -524,7 +529,41 @@
 			enable ? USB_SUSPEND_BIT : 0, 1);
 }
 
-static void qpnp_bat_if_adc_measure_work(struct work_struct *work)
+static int
+qpnp_chg_charge_en(struct qpnp_chg_chip *chip, int enable)
+{
+	return qpnp_chg_masked_write(chip, chip->chgr_base + CHGR_CHG_CTRL,
+			CHGR_CHG_EN,
+			enable ? CHGR_CHG_EN : 0, 1);
+}
+
+static int
+qpnp_chg_force_run_on_batt(struct qpnp_chg_chip *chip, int disable)
+{
+	/* Don't run on battery for batteryless hardware */
+	if (chip->use_default_batt_values)
+		return 0;
+
+	/* This bit forces the charger to run off of the battery rather
+	 * than a connected charger */
+	return qpnp_chg_masked_write(chip, chip->chgr_base + CHGR_CHG_CTRL,
+			CHGR_ON_BAT_FORCE_BIT,
+			disable ? CHGR_ON_BAT_FORCE_BIT : 0, 1);
+}
+
+static void
+qpnp_arb_stop_work(struct work_struct *work)
+{
+	struct delayed_work *dwork = to_delayed_work(work);
+	struct qpnp_chg_chip *chip = container_of(dwork,
+				struct qpnp_chg_chip, arb_stop_work);
+
+	qpnp_chg_charge_en(chip, !chip->charging_disabled);
+	qpnp_chg_force_run_on_batt(chip, chip->charging_disabled);
+}
+
+static void
+qpnp_bat_if_adc_measure_work(struct work_struct *work)
 {
 	struct qpnp_chg_chip *chip = container_of(work,
 				struct qpnp_chg_chip, adc_measure_work);
@@ -533,6 +572,23 @@
 		pr_err("request ADC error\n");
 }
 
+#define ARB_STOP_WORK_MS	1000
+static irqreturn_t
+qpnp_chg_usb_chg_gone_irq_handler(int irq, void *_chip)
+{
+	struct qpnp_chg_chip *chip = _chip;
+
+	pr_debug("chg_gone triggered\n");
+	if (qpnp_chg_is_usb_chg_plugged_in(chip)) {
+		qpnp_chg_charge_en(chip, 0);
+		qpnp_chg_force_run_on_batt(chip, chip->charging_disabled);
+		schedule_delayed_work(&chip->arb_stop_work,
+			msecs_to_jiffies(ARB_STOP_WORK_MS));
+	}
+
+	return IRQ_HANDLED;
+}
+
 #define ENUM_T_STOP_BIT		BIT(0)
 static irqreturn_t
 qpnp_chg_usb_usbin_valid_irq_handler(int irq, void *_chip)
@@ -552,7 +608,8 @@
 	if (chip->usb_present ^ usb_present) {
 		chip->usb_present = usb_present;
 		if (!usb_present)
-			qpnp_chg_iusbmax_set(chip, QPNP_CHG_I_MAX_MIN_100);
+			qpnp_chg_usb_suspend_enable(chip, 1);
+
 		power_supply_set_present(chip->usb_psy,
 			chip->usb_present);
 	}
@@ -661,28 +718,6 @@
 }
 
 static int
-qpnp_chg_charge_en(struct qpnp_chg_chip *chip, int enable)
-{
-	return qpnp_chg_masked_write(chip, chip->chgr_base + CHGR_CHG_CTRL,
-			CHGR_CHG_EN,
-			enable ? CHGR_CHG_EN : 0, 1);
-}
-
-static int
-qpnp_chg_force_run_on_batt(struct qpnp_chg_chip *chip, int disable)
-{
-	/* Don't run on battery for batteryless hardware */
-	if (chip->use_default_batt_values)
-		return 0;
-
-	/* This bit forces the charger to run off of the battery rather
-	 * than a connected charger */
-	return qpnp_chg_masked_write(chip, chip->chgr_base + CHGR_CHG_CTRL,
-			CHGR_ON_BAT_FORCE_BIT,
-			disable ? CHGR_ON_BAT_FORCE_BIT : 0, 1);
-}
-
-static int
 qpnp_chg_buck_control(struct qpnp_chg_chip *chip, int enable)
 {
 	int rc;
@@ -1059,8 +1094,8 @@
 			  POWER_SUPPLY_PROP_CURRENT_MAX, &ret);
 		if (ret.intval <= 2 && !chip->use_default_batt_values &&
 						get_prop_batt_present(chip)) {
-			qpnp_chg_iusbmax_set(chip, QPNP_CHG_I_MAX_MIN_100);
 			qpnp_chg_usb_suspend_enable(chip, 1);
+			qpnp_chg_iusbmax_set(chip, QPNP_CHG_I_MAX_MIN_100);
 		} else {
 			qpnp_chg_usb_suspend_enable(chip, 0);
 			qpnp_chg_iusbmax_set(chip, ret.intval / 1000);
@@ -1383,6 +1418,7 @@
 
 	if (state == ADC_TM_WARM_STATE) {
 		if (temp > chip->warm_bat_decidegc) {
+			/* Normal to warm */
 			bat_warm = true;
 			bat_cool = false;
 			chip->adc_param.low_temp =
@@ -1391,6 +1427,7 @@
 				ADC_TM_COOL_THR_ENABLE;
 		} else if (temp >
 				chip->cool_bat_decidegc + HYSTERISIS_DECIDEGC){
+			/* Cool to normal */
 			bat_warm = false;
 			bat_cool = false;
 
@@ -1401,14 +1438,16 @@
 		}
 	} else {
 		if (temp < chip->cool_bat_decidegc) {
+			/* Normal to cool */
 			bat_warm = false;
 			bat_cool = true;
 			chip->adc_param.high_temp =
 				chip->cool_bat_decidegc + HYSTERISIS_DECIDEGC;
 			chip->adc_param.state_request =
 				ADC_TM_WARM_THR_ENABLE;
-		} else if (temp >
+		} else if (temp <
 				chip->warm_bat_decidegc - HYSTERISIS_DECIDEGC){
+			/* Warm to normal */
 			bat_warm = false;
 			bat_cool = false;
 
@@ -1592,7 +1631,24 @@
 						chip->usbin_valid_irq, rc);
 				return rc;
 			}
+
+			chip->chg_gone_irq = spmi_get_irq_byname(spmi,
+						spmi_resource, "chg-gone");
+			if (chip->chg_gone_irq < 0) {
+				pr_err("Unable to get chg-gone irq\n");
+				return rc;
+			}
+			rc = devm_request_irq(chip->dev, chip->chg_gone_irq,
+				qpnp_chg_usb_chg_gone_irq_handler,
+				IRQF_TRIGGER_RISING,
+					"chg_gone_irq", chip);
+			if (rc < 0) {
+				pr_err("Can't request %d chg_gone: %d\n",
+						chip->chg_gone_irq, rc);
+				return rc;
+			}
 			enable_irq_wake(chip->usbin_valid_irq);
+			enable_irq_wake(chip->chg_gone_irq);
 			break;
 		case SMBB_DC_CHGPTH_SUBTYPE:
 			chip->dcin_valid_irq = spmi_get_irq_byname(spmi,
@@ -1679,10 +1735,10 @@
 		rc = qpnp_chg_masked_write(chip, chip->chgr_base + 0x62,
 			0xFF, 0xA0, 1);
 
-		/* HACK: use digital EOC */
+		/* HACK: use analog EOC */
 		rc = qpnp_chg_masked_write(chip, chip->chgr_base +
 			CHGR_IBAT_TERM_CHGR,
-			0x88, 0x80, 1);
+			0x80, 0x00, 1);
 
 		break;
 	case SMBB_BUCK_SUBTYPE:
@@ -1726,6 +1782,16 @@
 			ENUM_T_STOP_BIT,
 			ENUM_T_STOP_BIT, 1);
 
+		rc = qpnp_chg_masked_write(chip,
+			chip->usb_chgpth_base + SEC_ACCESS,
+			0xFF,
+			0xA5, 1);
+
+		rc = qpnp_chg_masked_write(chip,
+			chip->usb_chgpth_base + USB_CHG_GONE_REV_BST,
+			0xFF,
+			0x80, 1);
+
 		break;
 	case SMBB_DC_CHGPTH_SUBTYPE:
 		break;
@@ -1927,6 +1993,27 @@
 						subtype, rc);
 				goto fail_chg_enable;
 			}
+
+			rc = qpnp_chg_masked_write(chip,
+				chip->buck_base + SEC_ACCESS,
+				0xFF,
+				0xA5, 1);
+
+			rc = qpnp_chg_masked_write(chip,
+				chip->buck_base + BUCK_VCHG_OV,
+				0xff,
+				0x00, 1);
+
+			rc = qpnp_chg_masked_write(chip,
+				chip->buck_base + SEC_ACCESS,
+				0xFF,
+				0xA5, 1);
+
+			rc = qpnp_chg_masked_write(chip,
+				chip->buck_base + BUCK_TEST_SMBC_MODES,
+				0xFF,
+				0x80, 1);
+
 			break;
 		case SMBB_BAT_IF_SUBTYPE:
 		case SMBBP_BAT_IF_SUBTYPE:
@@ -2021,6 +2108,7 @@
 		}
 		INIT_WORK(&chip->adc_measure_work,
 			qpnp_bat_if_adc_measure_work);
+		INIT_DELAYED_WORK(&chip->arb_stop_work, qpnp_arb_stop_work);
 	}
 
 	if (chip->dc_chgpth_base) {
diff --git a/drivers/regulator/qpnp-regulator.c b/drivers/regulator/qpnp-regulator.c
index 4cdfaeb..2d10f89 100644
--- a/drivers/regulator/qpnp-regulator.c
+++ b/drivers/regulator/qpnp-regulator.c
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -19,12 +19,14 @@
 #include <linux/string.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/bitops.h>
 #include <linux/slab.h>
 #include <linux/spmi.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
+#include <linux/ktime.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/of_regulator.h>
 #include <linux/regulator/qpnp-regulator.h>
@@ -36,6 +38,7 @@
 	QPNP_VREG_DEBUG_INIT		= BIT(2), /* Show state after probe */
 	QPNP_VREG_DEBUG_WRITES		= BIT(3), /* Show SPMI writes */
 	QPNP_VREG_DEBUG_READS		= BIT(4), /* Show SPMI reads */
+	QPNP_VREG_DEBUG_OCP		= BIT(5), /* Show VS OCP IRQ events */
 };
 
 static int qpnp_vreg_debug_mask;
@@ -156,9 +159,8 @@
 #define QPNP_LDO_SOFT_START_ENABLE_MASK		0x80
 
 /* VS regulator over current protection control register layout */
-#define QPNP_VS_OCP_ENABLE_MASK			0x80
-#define QPNP_VS_OCP_OVERRIDE_MASK		0x01
-#define QPNP_VS_OCP_DISABLE			0x00
+#define QPNP_VS_OCP_OVERRIDE			0x01
+#define QPNP_VS_OCP_NO_OVERRIDE			0x00
 
 /* VS regulator soft start control register layout */
 #define QPNP_VS_SOFT_START_ENABLE_MASK		0x80
@@ -168,6 +170,11 @@
 #define QPNP_BOOST_CURRENT_LIMIT_ENABLE_MASK	0x80
 #define QPNP_BOOST_CURRENT_LIMIT_MASK		0x07
 
+#define QPNP_VS_OCP_DEFAULT_MAX_RETRIES		10
+#define QPNP_VS_OCP_DEFAULT_RETRY_DELAY_MS	30
+#define QPNP_VS_OCP_FALL_DELAY_US		90
+#define QPNP_VS_OCP_FAULT_DELAY_US		20000
+
 /*
  * This voltage in uV is returned by get_voltage functions when there is no way
  * to determine the current voltage level.  It is needed because the regulator
@@ -203,17 +210,22 @@
 
 struct qpnp_regulator {
 	struct regulator_desc			rdesc;
+	struct delayed_work			ocp_work;
 	struct spmi_device			*spmi_dev;
 	struct regulator_dev			*rdev;
 	struct qpnp_voltage_set_points		*set_points;
 	enum qpnp_regulator_logical_type	logical_type;
 	int					enable_time;
-	int					ocp_enable_time;
 	int					ocp_enable;
+	int					ocp_irq;
+	int					ocp_count;
+	int					ocp_max_retries;
+	int					ocp_retry_delay_ms;
 	int					system_load;
 	int					hpm_min_load;
 	u32					write_count;
 	u32					prev_write_count;
+	ktime_t					vs_enable_time;
 	u16					base_addr;
 	/* ctrl_reg provides a shadow copy of register values 0x40 to 0x47. */
 	u8					ctrl_reg[8];
@@ -501,35 +513,11 @@
 static int qpnp_regulator_vs_enable(struct regulator_dev *rdev)
 {
 	struct qpnp_regulator *vreg = rdev_get_drvdata(rdev);
-	int rc;
-	u8 reg;
 
-	if (vreg->ocp_enable == QPNP_REGULATOR_ENABLE) {
-		/* Disable OCP */
-		reg = QPNP_VS_OCP_DISABLE;
-		rc = qpnp_vreg_write(vreg, QPNP_VS_REG_OCP, &reg, 1);
-		if (rc)
-			goto fail;
-	}
+	if (vreg->ocp_irq)
+		vreg->vs_enable_time = ktime_get();
 
-	rc = qpnp_regulator_common_enable(rdev);
-	if (rc)
-		goto fail;
-
-	if (vreg->ocp_enable == QPNP_REGULATOR_ENABLE) {
-		/* Wait for inrush current to subsided, then enable OCP. */
-		udelay(vreg->ocp_enable_time);
-		reg = QPNP_VS_OCP_ENABLE_MASK;
-		rc = qpnp_vreg_write(vreg, QPNP_VS_REG_OCP, &reg, 1);
-		if (rc)
-			goto fail;
-	}
-
-	return rc;
-fail:
-	vreg_err(vreg, "qpnp_vreg_write failed, rc=%d\n", rc);
-
-	return rc;
+	return qpnp_regulator_common_enable(rdev);
 }
 
 static int qpnp_regulator_common_disable(struct regulator_dev *rdev)
@@ -785,6 +773,88 @@
 	return vreg->enable_time;
 }
 
+static int qpnp_regulator_vs_clear_ocp(struct qpnp_regulator *vreg)
+{
+	int rc;
+
+	rc = qpnp_vreg_masked_write(vreg, QPNP_COMMON_REG_ENABLE,
+		QPNP_COMMON_DISABLE, QPNP_COMMON_ENABLE_MASK,
+		&vreg->ctrl_reg[QPNP_COMMON_IDX_ENABLE]);
+	if (rc)
+		vreg_err(vreg, "qpnp_vreg_masked_write failed, rc=%d\n", rc);
+
+	vreg->vs_enable_time = ktime_get();
+
+	rc = qpnp_vreg_masked_write(vreg, QPNP_COMMON_REG_ENABLE,
+		QPNP_COMMON_ENABLE, QPNP_COMMON_ENABLE_MASK,
+		&vreg->ctrl_reg[QPNP_COMMON_IDX_ENABLE]);
+	if (rc)
+		vreg_err(vreg, "qpnp_vreg_masked_write failed, rc=%d\n", rc);
+
+	if (qpnp_vreg_debug_mask & QPNP_VREG_DEBUG_OCP) {
+		pr_info("%s: switch state toggled after OCP event\n",
+			vreg->rdesc.name);
+	}
+
+	return rc;
+}
+
+static void qpnp_regulator_vs_ocp_work(struct work_struct *work)
+{
+	struct delayed_work *dwork
+		= container_of(work, struct delayed_work, work);
+	struct qpnp_regulator *vreg
+		= container_of(dwork, struct qpnp_regulator, ocp_work);
+
+	qpnp_regulator_vs_clear_ocp(vreg);
+
+	return;
+}
+
+static irqreturn_t qpnp_regulator_vs_ocp_isr(int irq, void *data)
+{
+	struct qpnp_regulator *vreg = data;
+	ktime_t ocp_irq_time;
+	s64 ocp_trigger_delay_us;
+
+	ocp_irq_time = ktime_get();
+	ocp_trigger_delay_us = ktime_us_delta(ocp_irq_time,
+						vreg->vs_enable_time);
+
+	/*
+	 * Reset the OCP count if there is a large delay between switch enable
+	 * and when OCP triggers.  This is indicative of a hotplug event as
+	 * opposed to a fault.
+	 */
+	if (ocp_trigger_delay_us > QPNP_VS_OCP_FAULT_DELAY_US)
+		vreg->ocp_count = 0;
+
+	/* Wait for switch output to settle back to 0 V after OCP triggered. */
+	udelay(QPNP_VS_OCP_FALL_DELAY_US);
+
+	vreg->ocp_count++;
+
+	if (qpnp_vreg_debug_mask & QPNP_VREG_DEBUG_OCP) {
+		pr_info("%s: VS OCP triggered, count = %d, delay = %lld us\n",
+			vreg->rdesc.name, vreg->ocp_count,
+			ocp_trigger_delay_us);
+	}
+
+	if (vreg->ocp_count == 1) {
+		/* Immediately clear the over current condition. */
+		qpnp_regulator_vs_clear_ocp(vreg);
+	} else if (vreg->ocp_count <= vreg->ocp_max_retries) {
+		/* Schedule the over current clear task to run later. */
+		schedule_delayed_work(&vreg->ocp_work,
+			msecs_to_jiffies(vreg->ocp_retry_delay_ms) + 1);
+	} else {
+		vreg_err(vreg, "OCP triggered %d times; no further retries\n",
+			vreg->ocp_count);
+	}
+
+	return IRQ_HANDLED;
+}
+
 static const char const *qpnp_print_actions[] = {
 	[QPNP_REGULATOR_ACTION_INIT]	= "initial    ",
 	[QPNP_REGULATOR_ACTION_ENABLE]	= "enable     ",
@@ -834,7 +904,8 @@
 
 	if (type == QPNP_REGULATOR_LOGICAL_TYPE_SMPS
 	    || type == QPNP_REGULATOR_LOGICAL_TYPE_LDO
-	    || type == QPNP_REGULATOR_LOGICAL_TYPE_FTSMPS) {
+	    || type == QPNP_REGULATOR_LOGICAL_TYPE_FTSMPS
+	    || type == QPNP_REGULATOR_LOGICAL_TYPE_VS) {
 		mode = qpnp_regulator_common_get_mode(rdev);
 		mode_label = mode == REGULATOR_MODE_NORMAL ? "HPM" : "LPM";
 	}
@@ -903,9 +974,9 @@
 		pc_mode_label[1] =
 		     mode_reg & QPNP_COMMON_MODE_FOLLOW_AWAKE_MASK  ? 'W' : '_';
 
-		pr_info("%s %-11s: %s, pc_en=%s, alt_mode=%s\n",
+		pr_info("%s %-11s: %s, mode=%s, pc_en=%s, alt_mode=%s\n",
 			action_label, vreg->rdesc.name, enable_label,
-			pc_enable_label, pc_mode_label);
+			mode_label, pc_enable_label, pc_mode_label);
 		break;
 	case QPNP_REGULATOR_LOGICAL_TYPE_BOOST:
 		pr_info("%s %-11s: %s, v=%7d uV\n",
@@ -1099,6 +1170,17 @@
 		    pdata->pin_ctrl_enable & QPNP_COMMON_ENABLE_FOLLOW_ALL_MASK;
 	}
 
+	/* Set up HPM control. */
+	if ((type == QPNP_REGULATOR_LOGICAL_TYPE_SMPS
+	     || type == QPNP_REGULATOR_LOGICAL_TYPE_LDO
+	     || type == QPNP_REGULATOR_LOGICAL_TYPE_VS
+	     || type == QPNP_REGULATOR_LOGICAL_TYPE_FTSMPS)
+	    && (pdata->hpm_enable != QPNP_REGULATOR_USE_HW_DEFAULT)) {
+		ctrl_reg[QPNP_COMMON_IDX_MODE] &= ~QPNP_COMMON_MODE_HPM_MASK;
+		ctrl_reg[QPNP_COMMON_IDX_MODE] |=
+		     (pdata->hpm_enable ? QPNP_COMMON_MODE_HPM_MASK : 0);
+	}
+
 	/* Set up auto mode control. */
 	if ((type == QPNP_REGULATOR_LOGICAL_TYPE_SMPS
 	     || type == QPNP_REGULATOR_LOGICAL_TYPE_LDO
@@ -1224,7 +1306,8 @@
 		}
 
 		if (pdata->ocp_enable != QPNP_REGULATOR_USE_HW_DEFAULT) {
-			reg = pdata->ocp_enable ? QPNP_VS_OCP_ENABLE_MASK : 0;
+			reg = pdata->ocp_enable ? QPNP_VS_OCP_NO_OVERRIDE
+						: QPNP_VS_OCP_OVERRIDE;
 			rc = qpnp_vreg_write(vreg, QPNP_VS_REG_OCP, &reg, 1);
 			if (rc) {
 				vreg_err(vreg, "spmi write failed, rc=%d\n",
@@ -1256,6 +1339,11 @@
 	}
 	pdata->base_addr = res->start;
 
+	/* OCP IRQ is optional so ignore get errors. */
+	pdata->ocp_irq = spmi_get_irq_byname(spmi, NULL, "ocp");
+	if (pdata->ocp_irq < 0)
+		pdata->ocp_irq = 0;
+
 	/*
 	 * Initialize configuration parameters to use hardware default in case
 	 * no value is specified via device tree.
@@ -1269,6 +1357,7 @@
 	pdata->pin_ctrl_enable	    = QPNP_REGULATOR_PIN_CTRL_ENABLE_HW_DEFAULT;
 	pdata->pin_ctrl_hpm	    = QPNP_REGULATOR_PIN_CTRL_HPM_HW_DEFAULT;
 	pdata->vs_soft_start_strength	= QPNP_VS_SOFT_START_STR_HW_DEFAULT;
+	pdata->hpm_enable		= QPNP_REGULATOR_USE_HW_DEFAULT;
 
 	/* These bindings are optional, so it is okay if they are not found. */
 	of_property_read_u32(node, "qcom,auto-mode-enable",
@@ -1276,6 +1365,10 @@
 	of_property_read_u32(node, "qcom,bypass-mode-enable",
 		&pdata->bypass_mode_enable);
 	of_property_read_u32(node, "qcom,ocp-enable", &pdata->ocp_enable);
+	of_property_read_u32(node, "qcom,ocp-max-retries",
+		&pdata->ocp_max_retries);
+	of_property_read_u32(node, "qcom,ocp-retry-delay",
+		&pdata->ocp_retry_delay_ms);
 	of_property_read_u32(node, "qcom,pull-down-enable",
 		&pdata->pull_down_enable);
 	of_property_read_u32(node, "qcom,soft-start-enable",
@@ -1285,12 +1378,11 @@
 	of_property_read_u32(node, "qcom,pin-ctrl-enable",
 		&pdata->pin_ctrl_enable);
 	of_property_read_u32(node, "qcom,pin-ctrl-hpm", &pdata->pin_ctrl_hpm);
+	of_property_read_u32(node, "qcom,hpm-enable", &pdata->hpm_enable);
 	of_property_read_u32(node, "qcom,vs-soft-start-strength",
 		&pdata->vs_soft_start_strength);
 	of_property_read_u32(node, "qcom,system-load", &pdata->system_load);
 	of_property_read_u32(node, "qcom,enable-time", &pdata->enable_time);
-	of_property_read_u32(node, "qcom,ocp-enable-time",
-		&pdata->ocp_enable_time);
 
 	return rc;
 }
@@ -1364,7 +1456,14 @@
 	vreg->enable_time	= pdata->enable_time;
 	vreg->system_load	= pdata->system_load;
 	vreg->ocp_enable	= pdata->ocp_enable;
-	vreg->ocp_enable_time	= pdata->ocp_enable_time;
+	vreg->ocp_irq		= pdata->ocp_irq;
+	vreg->ocp_max_retries	= pdata->ocp_max_retries;
+	vreg->ocp_retry_delay_ms = pdata->ocp_retry_delay_ms;
+
+	if (vreg->ocp_max_retries == 0)
+		vreg->ocp_max_retries = QPNP_VS_OCP_DEFAULT_MAX_RETRIES;
+	if (vreg->ocp_retry_delay_ms == 0)
+		vreg->ocp_retry_delay_ms = QPNP_VS_OCP_DEFAULT_RETRY_DELAY_MS;
 
 	rdesc			= &vreg->rdesc;
 	rdesc->id		= spmi->ctrl->nr;
@@ -1414,18 +1513,37 @@
 		goto bail;
 	}
 
+	if (vreg->logical_type != QPNP_REGULATOR_LOGICAL_TYPE_VS)
+		vreg->ocp_irq = 0;
+
+	if (vreg->ocp_irq) {
+		rc = devm_request_irq(&spmi->dev, vreg->ocp_irq,
+			qpnp_regulator_vs_ocp_isr, IRQF_TRIGGER_RISING, "ocp",
+			vreg);
+		if (rc < 0) {
+			vreg_err(vreg, "failed to request irq %d, rc=%d\n",
+				vreg->ocp_irq, rc);
+			goto bail;
+		}
+
+		INIT_DELAYED_WORK(&vreg->ocp_work, qpnp_regulator_vs_ocp_work);
+	}
+
 	vreg->rdev = regulator_register(rdesc, &spmi->dev,
 			&(pdata->init_data), vreg, spmi->dev.of_node);
 	if (IS_ERR(vreg->rdev)) {
 		rc = PTR_ERR(vreg->rdev);
 		vreg_err(vreg, "regulator_register failed, rc=%d\n", rc);
-		goto bail;
+		goto cancel_ocp_work;
 	}
 
 	qpnp_vreg_show_state(vreg->rdev, QPNP_REGULATOR_ACTION_INIT);
 
 	return 0;
 
+cancel_ocp_work:
+	if (vreg->ocp_irq)
+		cancel_delayed_work_sync(&vreg->ocp_work);
 bail:
 	if (rc)
 		vreg_err(vreg, "probe failed, rc=%d\n", rc);
@@ -1445,6 +1563,8 @@
 
 	if (vreg) {
 		regulator_unregister(vreg->rdev);
+		if (vreg->ocp_irq)
+			cancel_delayed_work_sync(&vreg->ocp_work);
 		kfree(vreg->rdesc.name);
 		kfree(vreg);
 	}
diff --git a/drivers/slimbus/slim-msm-ctrl.c b/drivers/slimbus/slim-msm-ctrl.c
index 9a864aa..4a3ea76 100644
--- a/drivers/slimbus/slim-msm-ctrl.c
+++ b/drivers/slimbus/slim-msm-ctrl.c
@@ -37,8 +37,6 @@
 #define QC_DEVID_SAT2	0x4
 #define QC_DEVID_PGD	0x5
 #define QC_MSM_DEVS	5
-#define INIT_MX_RETRIES 10
-#define DEF_RETRY_MS	10
 
 /* Manager registers */
 enum mgr_reg {
diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c
index 63d3750..a0179cb 100644
--- a/drivers/slimbus/slim-msm-ngd.c
+++ b/drivers/slimbus/slim-msm-ngd.c
@@ -631,6 +631,7 @@
 	if (mc == SLIM_USR_MC_MASTER_CAPABILITY &&
 		mt == SLIM_MSG_MT_SRC_REFERRED_USER) {
 		struct slim_msg_txn txn;
+		int retries = 0;
 		u8 wbuf[8];
 		txn.dt = SLIM_MSG_DEST_LOGICALADDR;
 		txn.ec = 0;
@@ -638,7 +639,6 @@
 		txn.mc = SLIM_USR_MC_REPORT_SATELLITE;
 		txn.mt = SLIM_MSG_MT_SRC_REFERRED_USER;
 		txn.la = SLIM_LA_MGR;
-		txn.rl = 8;
 		wbuf[0] = SAT_MAGIC_LSB;
 		wbuf[1] = SAT_MAGIC_MSB;
 		wbuf[2] = SAT_MSG_VER;
@@ -655,7 +655,8 @@
 			/* make sure NGD MSG-Q config goes through */
 			mb();
 		}
-
+capability_retry:
+		txn.rl = 8;
 		ret = ngd_xfer_msg(&dev->ctrl, &txn);
 		if (!ret) {
 			enum msm_ctrl_state prev_state = dev->state;
@@ -668,6 +669,13 @@
 			/* ADSP SSR, send device_up notifications */
 			if (prev_state == MSM_CTRL_DOWN)
 				schedule_work(&dev->slave_notify);
+		} else if (ret == -EIO) {
+			pr_info("capability message NACKed, retrying");
+			if (retries < INIT_MX_RETRIES) {
+				msleep(DEF_RETRY_MS);
+				retries++;
+				goto capability_retry;
+			}
 		}
 	}
 	if (mc == SLIM_MSG_MC_REPLY_INFORMATION ||
diff --git a/drivers/slimbus/slim-msm.h b/drivers/slimbus/slim-msm.h
index 6ff3f19..cf2d26f 100644
--- a/drivers/slimbus/slim-msm.h
+++ b/drivers/slimbus/slim-msm.h
@@ -50,6 +50,8 @@
 #define SLIM_MSG_ASM_FIRST_WORD(l, mt, mc, dt, ad) \
 		((l) | ((mt) << 5) | ((mc) << 8) | ((dt) << 15) | ((ad) << 16))
 
+#define INIT_MX_RETRIES 10
+#define DEF_RETRY_MS	10
 #define MSM_CONCUR_MSG	8
 #define SAT_CONCUR_MSG	8
 #define DEF_WATERMARK	(8 << 1)
diff --git a/drivers/tty/smux_ctl.c b/drivers/tty/smux_ctl.c
index 2e091cc..1b3a7abe 100644
--- a/drivers/tty/smux_ctl.c
+++ b/drivers/tty/smux_ctl.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
@@ -940,6 +940,7 @@
 static int smux_ctl_remove(struct platform_device *pdev)
 {
 	int i;
+	int ret;
 
 	SMUXCTL_DBG(SMUX_CTL_MODULE_NAME ": %s Begins\n", __func__);
 
@@ -950,6 +951,13 @@
 		devp->abort_wait = 1;
 		wake_up(&devp->write_wait_queue);
 		wake_up(&devp->read_wait_queue);
+
+		if (atomic_read(&devp->ref_count)) {
+			ret = msm_smux_close(devp->id);
+			if (ret)
+				pr_err("%s: unable to close ch %d, ret %d\n",
+						__func__, devp->id, ret);
+		}
 		mutex_unlock(&devp->dev_lock);
 
 		/* Empty RX queue */
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index fc8f4b3..fab5219 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -488,7 +488,7 @@
 	if (!dev->dma_mask)
 		dev->dma_mask = &dwc3_dma_mask;
 	if (!dev->coherent_dma_mask)
-		dev->coherent_dma_mask = DMA_BIT_MASK(32);
+		dev->coherent_dma_mask = DMA_BIT_MASK(64);
 
 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 	if (!res) {
diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c
index 93504eb..df95646 100644
--- a/drivers/usb/dwc3/debugfs.c
+++ b/drivers/usb/dwc3/debugfs.c
@@ -693,9 +693,10 @@
 	list_for_each(ptr, &dep->request_list) {
 		req = list_entry(ptr, struct dwc3_request, list);
 
-		seq_printf(s, "req:0x%p len: %d sts: %d dma:0x%x num_sgs: %d\n",
+		seq_printf(s,
+			"req:0x%p len: %d sts: %d dma:0x%pa num_sgs: %d\n",
 			req, req->request.length, req->request.status,
-			req->request.dma, req->request.num_sgs);
+			&req->request.dma, req->request.num_sgs);
 	}
 	spin_unlock_irqrestore(&dwc->lock, flags);
 
@@ -731,9 +732,10 @@
 	list_for_each(ptr, &dep->req_queued) {
 		req = list_entry(ptr, struct dwc3_request, list);
 
-		seq_printf(s, "req:0x%p len:%d sts:%d dma:%x nsg:%d trb:0x%p\n",
+		seq_printf(s,
+			"req:0x%p len:%d sts:%d dma:%pa nsg:%d trb:0x%p\n",
 			req, req->request.length, req->request.status,
-			req->request.dma, req->request.num_sgs, req->trb);
+			&req->request.dma, req->request.num_sgs, req->trb);
 	}
 	spin_unlock_irqrestore(&dwc->lock, flags);
 
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 6fca910..d0ebda1 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -445,7 +445,8 @@
 	int n = hw_ep_bit(num, dir);
 	struct ci13xxx_ep *mEp = &_udc->ci13xxx_ep[n];
 
-	if (_udc->skip_flush || list_empty(&mEp->qh.queue))
+	/* Flush ep0 even when queue is empty */
+	if (_udc->skip_flush || (num && list_empty(&mEp->qh.queue)))
 		return 0;
 
 	start = ktime_get();
@@ -2107,7 +2108,18 @@
 	if (mReq->zptr) {
 		if ((TD_STATUS_ACTIVE & mReq->zptr->token) != 0)
 			return -EBUSY;
-		dma_pool_free(mEp->td_pool, mReq->zptr, mReq->zdma);
+
+		/* The controller may access this dTD one more time.
+		 * Defer freeing this to next zero length dTD completion.
+		 * It is safe to assume that controller will no longer
+		 * access the previous dTD after next dTD completion.
+		 */
+		if (mEp->last_zptr)
+			dma_pool_free(mEp->td_pool, mEp->last_zptr,
+					mEp->last_zdma);
+		mEp->last_zptr = mReq->zptr;
+		mEp->last_zdma = mReq->zdma;
+
 		mReq->zptr = NULL;
 	}
 
@@ -2259,9 +2271,10 @@
 	usb_ep_fifo_flush(&udc->ep0out.ep);
 	usb_ep_fifo_flush(&udc->ep0in.ep);
 
-	if (udc->status != NULL) {
-		usb_ep_free_request(&udc->ep0in.ep, udc->status);
-		udc->status = NULL;
+	if (udc->ep0in.last_zptr) {
+		dma_pool_free(udc->ep0in.td_pool, udc->ep0in.last_zptr,
+				udc->ep0in.last_zdma);
+		udc->ep0in.last_zptr = NULL;
 	}
 
 	return 0;
@@ -2316,10 +2329,6 @@
 	if (retval)
 		goto done;
 
-	udc->status = usb_ep_alloc_request(&udc->ep0in.ep, GFP_ATOMIC);
-	if (udc->status == NULL)
-		retval = -ENOMEM;
-
 	spin_lock(udc->lock);
 
  done:
@@ -2388,8 +2397,8 @@
 		return;
 	}
 
-	kfree(req->buf);
-	usb_ep_free_request(ep, req);
+	if (req->status)
+		err("GET_STATUS failed");
 }
 
 /**
@@ -2405,8 +2414,7 @@
 __acquires(mEp->lock)
 {
 	struct ci13xxx_ep *mEp = &udc->ep0in;
-	struct usb_request *req = NULL;
-	gfp_t gfp_flags = GFP_ATOMIC;
+	struct usb_request *req = udc->status;
 	int dir, num, retval;
 
 	trace("%p, %p", mEp, setup);
@@ -2414,19 +2422,9 @@
 	if (mEp == NULL || setup == NULL)
 		return -EINVAL;
 
-	spin_unlock(mEp->lock);
-	req = usb_ep_alloc_request(&mEp->ep, gfp_flags);
-	spin_lock(mEp->lock);
-	if (req == NULL)
-		return -ENOMEM;
-
 	req->complete = isr_get_status_complete;
 	req->length   = 2;
-	req->buf      = kzalloc(req->length, gfp_flags);
-	if (req->buf == NULL) {
-		retval = -ENOMEM;
-		goto err_free_req;
-	}
+	req->buf      = udc->status_buf;
 
 	if ((setup->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
 		if (setup->wIndex == OTG_STATUS_SELECTOR) {
@@ -2449,18 +2447,7 @@
 	/* else do nothing; reserved for future use */
 
 	spin_unlock(mEp->lock);
-	retval = usb_ep_queue(&mEp->ep, req, gfp_flags);
-	spin_lock(mEp->lock);
-	if (retval)
-		goto err_free_buf;
-
-	return 0;
-
- err_free_buf:
-	kfree(req->buf);
- err_free_req:
-	spin_unlock(mEp->lock);
-	usb_ep_free_request(&mEp->ep, req);
+	retval = usb_ep_queue(&mEp->ep, req, GFP_ATOMIC);
 	spin_lock(mEp->lock);
 	return retval;
 }
@@ -2503,11 +2490,9 @@
 	trace("%p", udc);
 
 	mEp = (udc->ep0_dir == TX) ? &udc->ep0out : &udc->ep0in;
-	if (udc->status) {
-		udc->status->context = udc;
-		udc->status->complete = isr_setup_status_complete;
-	} else
-		return -EINVAL;
+	udc->status->context = udc;
+	udc->status->complete = isr_setup_status_complete;
+	udc->status->length = 0;
 
 	spin_unlock(mEp->lock);
 	retval = usb_ep_queue(&mEp->ep, udc->status, GFP_ATOMIC);
@@ -2941,6 +2926,12 @@
 
 	} while (mEp->dir != direction);
 
+	if (mEp->last_zptr) {
+		dma_pool_free(mEp->td_pool, mEp->last_zptr,
+				mEp->last_zdma);
+		mEp->last_zptr = NULL;
+	}
+
 	mEp->desc = NULL;
 	mEp->ep.desc = NULL;
 	mEp->ep.maxpacket = USHRT_MAX;
@@ -3475,6 +3466,14 @@
 	retval = usb_ep_enable(&udc->ep0in.ep);
 	if (retval)
 		return retval;
+	udc->status = usb_ep_alloc_request(&udc->ep0in.ep, GFP_KERNEL);
+	if (!udc->status)
+		return -ENOMEM;
+	udc->status_buf = kzalloc(2, GFP_KERNEL); /* for GET_STATUS */
+	if (!udc->status_buf) {
+		usb_ep_free_request(&udc->ep0in.ep, udc->status);
+		return -ENOMEM;
+	}
 	spin_lock_irqsave(udc->lock, flags);
 
 	udc->gadget.ep0 = &udc->ep0in.ep;
@@ -3558,6 +3557,9 @@
 	driver->unbind(&udc->gadget);               /* MAY SLEEP */
 	spin_lock_irqsave(udc->lock, flags);
 
+	usb_ep_free_request(&udc->ep0in.ep, udc->status);
+	kfree(udc->status_buf);
+
 	udc->gadget.dev.driver = NULL;
 
 	/* free resources */
diff --git a/drivers/usb/gadget/ci13xxx_udc.h b/drivers/usb/gadget/ci13xxx_udc.h
index 3145418..1530474 100644
--- a/drivers/usb/gadget/ci13xxx_udc.h
+++ b/drivers/usb/gadget/ci13xxx_udc.h
@@ -115,6 +115,8 @@
 	spinlock_t                            *lock;
 	struct device                         *device;
 	struct dma_pool                       *td_pool;
+	struct ci13xxx_td                     *last_zptr;
+	dma_addr_t                            last_zdma;
 	unsigned long dTD_update_fail_count;
 	unsigned long			      prime_fail_count;
 	int				      prime_timer_count;
@@ -153,6 +155,7 @@
 	struct dma_pool           *qh_pool;   /* DMA pool for queue heads */
 	struct dma_pool           *td_pool;   /* DMA pool for transfer descs */
 	struct usb_request        *status;    /* ep0 status request */
+	void                      *status_buf;/* GET_STATUS buffer */
 
 	struct usb_gadget          gadget;     /* USB slave device */
 	struct ci13xxx_ep          ci13xxx_ep[ENDPT_MAX]; /* extended endpts */
diff --git a/drivers/usb/gadget/f_diag.c b/drivers/usb/gadget/f_diag.c
index 3b1843b..3355e19 100644
--- a/drivers/usb/gadget/f_diag.c
+++ b/drivers/usb/gadget/f_diag.c
@@ -139,9 +139,6 @@
  * @out_desc: USB OUT endpoint descriptor struct
  * @read_pool: List of requests used for Rx (OUT ep)
  * @write_pool: List of requests used for Tx (IN ep)
- * @config_work: Work item schedule after interface is configured to notify
- *               CONNECT event to diag char driver and updating product id
- *               and serial number to MODEM/IMEM.
  * @lock: Spinlock to proctect read_pool, write_pool lists
  * @cdev: USB composite device struct
  * @ch: USB diag channel
@@ -153,7 +150,6 @@
 	struct usb_ep *in;
 	struct list_head read_pool;
 	struct list_head write_pool;
-	struct work_struct config_work;
 	spinlock_t lock;
 	unsigned configured;
 	struct usb_composite_dev *cdev;
@@ -176,21 +172,20 @@
 	return container_of(f, struct diag_context, function);
 }
 
-static void usb_config_work_func(struct work_struct *work)
+static void diag_update_pid_and_serial_num(struct diag_context *ctxt)
 {
-	struct diag_context *ctxt = container_of(work,
-			struct diag_context, config_work);
 	struct usb_composite_dev *cdev = ctxt->cdev;
 	struct usb_gadget_strings *table;
 	struct usb_string *s;
 
-	if (!ctxt->ch)
+	if (!ctxt->update_pid_and_serial_num)
 		return;
 
-	if (ctxt->ch->notify)
-		ctxt->ch->notify(ctxt->ch->priv, USB_DIAG_CONNECT, NULL);
-
-	if (!ctxt->update_pid_and_serial_num)
+	/*
+	 * update pid and serail number to dload only if diag
+	 * interface is zeroth interface.
+	 */
+	if (intf_desc.bInterfaceNumber)
 		return;
 
 	/* pass on product id and serial number to dload */
@@ -612,7 +607,6 @@
 		usb_ep_disable(dev->in);
 		return rc;
 	}
-	schedule_work(&dev->config_work);
 
 	dev->dpkts_tolaptop = 0;
 	dev->dpkts_tomodem = 0;
@@ -622,6 +616,9 @@
 	dev->configured = 1;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
+	if (dev->ch->notify)
+		dev->ch->notify(dev->ch->priv, USB_DIAG_CONNECT, NULL);
+
 	return rc;
 }
 
@@ -699,6 +696,7 @@
 		if (!f->ss_descriptors)
 			goto fail;
 	}
+	diag_update_pid_and_serial_num(ctxt);
 	return 0;
 fail:
 	if (f->ss_descriptors)
@@ -761,7 +759,6 @@
 	spin_lock_init(&dev->lock);
 	INIT_LIST_HEAD(&dev->read_pool);
 	INIT_LIST_HEAD(&dev->write_pool);
-	INIT_WORK(&dev->config_work, usb_config_work_func);
 
 	ret = usb_add_function(c, &dev->function);
 	if (ret) {
diff --git a/drivers/usb/gadget/f_qc_ecm.c b/drivers/usb/gadget/f_qc_ecm.c
index 51f0e50..46a6bba 100644
--- a/drivers/usb/gadget/f_qc_ecm.c
+++ b/drivers/usb/gadget/f_qc_ecm.c
@@ -849,6 +849,10 @@
 	usb_ep_free_request(ecm->notify, ecm->notify_req);
 
 	ecm_qc_string_defs[1].s = NULL;
+
+	if (ecm->xport == USB_GADGET_XPORT_BAM2BAM_IPA)
+		ecm_ipa_cleanup(ipa_params.ipa_priv);
+
 	kfree(ecm);
 }
 
diff --git a/drivers/usb/gadget/u_bam.c b/drivers/usb/gadget/u_bam.c
index 67c9a1a..c601000 100644
--- a/drivers/usb/gadget/u_bam.c
+++ b/drivers/usb/gadget/u_bam.c
@@ -717,6 +717,7 @@
 	ipa_notify_cb usb_notify_cb;
 	void *priv;
 	int ret;
+	unsigned long flags;
 
 	if (d->trans == USB_GADGET_XPORT_BAM2BAM) {
 		ret = usb_bam_connect(d->src_connection_idx, &d->src_pipe_idx);
@@ -769,9 +770,21 @@
 		}
 	}
 
-	d->rx_req = usb_ep_alloc_request(port->port_usb->out, GFP_KERNEL);
-	if (!d->rx_req)
+	spin_lock_irqsave(&port->port_lock_ul, flags);
+	spin_lock(&port->port_lock_dl);
+	if (!port->port_usb) {
+		pr_debug("%s: usb cable is disconnected, exiting\n", __func__);
+		spin_unlock(&port->port_lock_dl);
+		spin_unlock_irqrestore(&port->port_lock_ul, flags);
 		return;
+	}
+	d->rx_req = usb_ep_alloc_request(port->port_usb->out, GFP_ATOMIC);
+	if (!d->rx_req) {
+		spin_unlock(&port->port_lock_dl);
+		spin_unlock_irqrestore(&port->port_lock_ul, flags);
+		pr_err("%s: out of memory\n", __func__);
+		return;
+	}
 
 	d->rx_req->context = port;
 	d->rx_req->complete = gbam_endless_rx_complete;
@@ -779,9 +792,14 @@
 	sps_params = (MSM_SPS_MODE | d->src_pipe_idx |
 				 MSM_VENDOR_ID) & ~MSM_IS_FINITE_TRANSFER;
 	d->rx_req->udc_priv = sps_params;
-	d->tx_req = usb_ep_alloc_request(port->port_usb->in, GFP_KERNEL);
-	if (!d->tx_req)
+
+	d->tx_req = usb_ep_alloc_request(port->port_usb->in, GFP_ATOMIC);
+	spin_unlock(&port->port_lock_dl);
+	spin_unlock_irqrestore(&port->port_lock_ul, flags);
+	if (!d->tx_req) {
+		pr_err("%s: out of memory\n", __func__);
 		return;
+	}
 
 	d->tx_req->context = port;
 	d->tx_req->complete = gbam_endless_tx_complete;
diff --git a/drivers/usb/gadget/u_rmnet_ctrl_qti.c b/drivers/usb/gadget/u_rmnet_ctrl_qti.c
index e92978f..182cd40 100644
--- a/drivers/usb/gadget/u_rmnet_ctrl_qti.c
+++ b/drivers/usb/gadget/u_rmnet_ctrl_qti.c
@@ -259,20 +259,6 @@
 		return -EBUSY;
 	}
 
-	/* block until online */
-	while (!(atomic_read(&port->connected))) {
-		pr_debug("Not connected. Wait.\n");
-		ret = wait_event_interruptible(port->read_wq,
-			atomic_read(&port->connected));
-		if (ret < 0) {
-			rmnet_ctrl_unlock(&port->read_excl);
-			if (ret == -ERESTARTSYS)
-				return -ERESTARTSYS;
-			else
-				return -EINTR;
-		}
-	}
-
 	/* block until a new packet is available */
 	do {
 		spin_lock_irqsave(&port->lock, flags);
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index 4a085aa..7674d88 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -78,6 +78,7 @@
 	struct clk		*alt_core_clk;
 	struct clk		*phy_clk;
 	struct clk		*cal_clk;
+	struct clk		*inactivity_clk;
 	struct regulator	*hsic_vddcx;
 	struct regulator	*hsic_gdsc;
 	atomic_t		async_int;
@@ -575,6 +576,8 @@
 		clk_disable_unprepare(mehci->phy_clk);
 		clk_disable_unprepare(mehci->cal_clk);
 		clk_disable_unprepare(mehci->ahb_clk);
+		if (!IS_ERR(mehci->inactivity_clk))
+			clk_disable_unprepare(mehci->inactivity_clk);
 
 		ret = clk_reset(mehci->core_clk, CLK_RESET_ASSERT);
 		if (ret) {
@@ -596,6 +599,8 @@
 		clk_prepare_enable(mehci->phy_clk);
 		clk_prepare_enable(mehci->cal_clk);
 		clk_prepare_enable(mehci->ahb_clk);
+		if (!IS_ERR(mehci->inactivity_clk))
+			clk_prepare_enable(mehci->inactivity_clk);
 	}
 }
 
@@ -794,6 +799,8 @@
 	clk_disable_unprepare(mehci->phy_clk);
 	clk_disable_unprepare(mehci->cal_clk);
 	clk_disable_unprepare(mehci->ahb_clk);
+	if (!IS_ERR(mehci->inactivity_clk))
+		clk_disable_unprepare(mehci->inactivity_clk);
 
 	none_vol = vdd_val[mehci->vdd_type][VDD_NONE];
 	max_vol = vdd_val[mehci->vdd_type][VDD_MAX];
@@ -876,6 +883,8 @@
 	clk_prepare_enable(mehci->phy_clk);
 	clk_prepare_enable(mehci->cal_clk);
 	clk_prepare_enable(mehci->ahb_clk);
+	if (!IS_ERR(mehci->inactivity_clk))
+		clk_prepare_enable(mehci->inactivity_clk);
 
 	temp = readl_relaxed(USB_USBCMD);
 	temp &= ~ASYNC_INTR_CTRL;
@@ -1507,10 +1516,21 @@
 		goto put_cal_clk;
 	}
 
+	/*
+	 * Inactivity_clk is required for hsic bam inactivity timer.
+	 * This clock is not compulsory and is defined in clock lookup
+	 * only for targets that need to use the inactivity timer feature.
+	 */
+	mehci->inactivity_clk = clk_get(mehci->dev, "inactivity_clk");
+	if (IS_ERR(mehci->inactivity_clk))
+		dev_dbg(mehci->dev, "failed to get inactivity_clk\n");
+
 	clk_prepare_enable(mehci->core_clk);
 	clk_prepare_enable(mehci->phy_clk);
 	clk_prepare_enable(mehci->cal_clk);
 	clk_prepare_enable(mehci->ahb_clk);
+	if (!IS_ERR(mehci->inactivity_clk))
+		clk_prepare_enable(mehci->inactivity_clk);
 
 	return 0;
 
@@ -1520,7 +1540,11 @@
 		clk_disable_unprepare(mehci->phy_clk);
 		clk_disable_unprepare(mehci->cal_clk);
 		clk_disable_unprepare(mehci->ahb_clk);
+		if (!IS_ERR(mehci->inactivity_clk))
+			clk_disable_unprepare(mehci->inactivity_clk);
 	}
+	if (!IS_ERR(mehci->inactivity_clk))
+		clk_put(mehci->inactivity_clk);
 	clk_put(mehci->ahb_clk);
 put_cal_clk:
 	clk_put(mehci->cal_clk);
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index 99b7604..929e5f8 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -434,11 +434,32 @@
 	mutex_unlock(&mdp3_session->lock);
 }
 
+static int mdp3_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 =
+			mfd->panel_info->mipi.frame_rate;
+		break;
+	case metadata_op_get_caps:
+		metadata->data.caps.mdp_rev = 304;
+		break;
+	default:
+		pr_warn("Unsupported request to MDP META IOCTL.\n");
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
 static int mdp3_ctrl_ioctl_handler(struct msm_fb_data_type *mfd,
 					u32 cmd, void __user *argp)
 {
 	int rc = -EINVAL;
 	struct mdp3_session_data *mdp3_session;
+	struct msmfb_metadata metadata;
 	int val;
 
 	pr_debug("mdp3_ctrl_ioctl_handler\n");
@@ -464,6 +485,14 @@
 			rc = -EFAULT;
 		}
 		break;
+	case MSMFB_METADATA_GET:
+		rc = copy_from_user(&metadata, argp, sizeof(metadata));
+		if (rc)
+			return rc;
+		rc = mdp3_get_metadata(mfd, &metadata);
+		if (!rc)
+			rc = copy_to_user(argp, &metadata, sizeof(metadata));
+		break;
 	default:
 		break;
 	}
diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h
index 04217f5..5be0173 100644
--- a/drivers/video/msm/mdss/mdss.h
+++ b/drivers/video/msm/mdss/mdss.h
@@ -62,8 +62,6 @@
 	struct regulator *fs;
 	u32 max_mdp_clk_rate;
 
-	struct workqueue_struct *clk_ctrl_wq;
-	struct work_struct clk_ctrl_worker;
 	struct platform_device *pdev;
 	char __iomem *mdp_base;
 	size_t mdp_reg_size;
@@ -80,7 +78,6 @@
 	u32 mdp_hist_irq_mask;
 
 	int suspend_fs_ena;
-	atomic_t clk_ref;
 	u8 clk_ena;
 	u8 fs_ena;
 	u8 vsync_ena;
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index a5903cf..eb4eee2 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -1143,6 +1143,7 @@
 	struct mdp_display_commit disp_commit;
 	memset(&disp_commit, 0, sizeof(disp_commit));
 	disp_commit.wait_for_finish = true;
+	memcpy(&disp_commit.var, var, sizeof(struct fb_var_screeninfo));
 	return mdss_fb_pan_display_ex(info, &disp_commit);
 }
 
@@ -1431,6 +1432,7 @@
 	int i, fence_cnt = 0, ret = 0;
 	int acq_fen_fd[MDP_MAX_FENCE_FD];
 	struct sync_fence *fence;
+	u32 threshold;
 
 	if ((buf_sync->acq_fen_fd_cnt > MDP_MAX_FENCE_FD) ||
 		(mfd->timeline == NULL))
@@ -1464,8 +1466,13 @@
 	if (buf_sync->flags & MDP_BUF_SYNC_FLAG_WAIT)
 		mdss_fb_wait_for_fence(mfd);
 
+	if (mfd->panel.type == WRITEBACK_PANEL)
+		threshold = 1;
+	else
+		threshold = 2;
+
 	mfd->cur_rel_sync_pt = sw_sync_pt_create(mfd->timeline,
-			mfd->timeline_value + 2);
+			mfd->timeline_value + threshold);
 	if (mfd->cur_rel_sync_pt == NULL) {
 		pr_err("%s: cannot create sync point", __func__);
 		ret = -ENOMEM;
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index a3be773..2f09fee 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -621,71 +621,43 @@
 	return clk_rate;
 }
 
-static void mdss_mdp_clk_ctrl_update(struct mdss_data_type *mdata)
-{
-	int enable;
-
-	mutex_lock(&mdp_clk_lock);
-	enable = atomic_read(&mdata->clk_ref) > 0;
-	if (mdata->clk_ena == enable) {
-		mutex_unlock(&mdp_clk_lock);
-		return;
-	}
-	mdata->clk_ena = enable;
-
-	if (enable)
-		pm_runtime_get_sync(&mdata->pdev->dev);
-
-	pr_debug("MDP CLKS %s\n", (enable ? "Enable" : "Disable"));
-	mb();
-
-	mdss_mdp_clk_update(MDSS_CLK_AHB, enable);
-	mdss_mdp_clk_update(MDSS_CLK_AXI, enable);
-
-	mdss_mdp_clk_update(MDSS_CLK_MDP_CORE, enable);
-	mdss_mdp_clk_update(MDSS_CLK_MDP_LUT, enable);
-	if (mdata->vsync_ena)
-		mdss_mdp_clk_update(MDSS_CLK_MDP_VSYNC, enable);
-
-	if (!enable)
-		pm_runtime_put(&mdata->pdev->dev);
-
-	mutex_unlock(&mdp_clk_lock);
-}
-
-static void mdss_mdp_clk_ctrl_workqueue_handler(struct work_struct *work)
-{
-	struct mdss_data_type *mdata;
-
-	mdata = container_of(work, struct mdss_data_type, clk_ctrl_worker);
-	mdss_mdp_clk_ctrl_update(mdata);
-}
-
 void mdss_mdp_clk_ctrl(int enable, int isr)
 {
 	struct mdss_data_type *mdata = mdss_res;
+	static int mdp_clk_cnt;
+	int changed = 0;
 
-	pr_debug("clk enable=%d isr=%d ref= %d\n", enable, isr,
-			atomic_read(&mdata->clk_ref));
-
-	if (enable == MDP_BLOCK_POWER_ON) {
-		BUG_ON(isr);
-
-		if (atomic_inc_return(&mdata->clk_ref) == 1)
-			mdss_mdp_clk_ctrl_update(mdata);
+	mutex_lock(&mdp_clk_lock);
+	if (enable) {
+		if (mdp_clk_cnt == 0)
+			changed++;
+		mdp_clk_cnt++;
 	} else {
-		BUG_ON(atomic_read(&mdata->clk_ref) == 0);
-
-		if (atomic_dec_and_test(&mdata->clk_ref)) {
-			if (isr)
-				queue_work(mdata->clk_ctrl_wq,
-						&mdata->clk_ctrl_worker);
-			else
-				mdss_mdp_clk_ctrl_update(mdata);
-		}
+		mdp_clk_cnt--;
+		if (mdp_clk_cnt == 0)
+			changed++;
 	}
 
+	pr_debug("%s: clk_cnt=%d changed=%d enable=%d\n",
+			__func__, mdp_clk_cnt, changed, enable);
 
+	if (changed) {
+		mdata->clk_ena = enable;
+		if (enable)
+			pm_runtime_get_sync(&mdata->pdev->dev);
+
+		mdss_mdp_clk_update(MDSS_CLK_AHB, enable);
+		mdss_mdp_clk_update(MDSS_CLK_AXI, enable);
+		mdss_mdp_clk_update(MDSS_CLK_MDP_CORE, enable);
+		mdss_mdp_clk_update(MDSS_CLK_MDP_LUT, enable);
+		if (mdata->vsync_ena)
+			mdss_mdp_clk_update(MDSS_CLK_MDP_VSYNC, enable);
+
+		if (!enable)
+			pm_runtime_put(&mdata->pdev->dev);
+	}
+
+	mutex_unlock(&mdp_clk_lock);
 }
 
 static inline int mdss_mdp_irq_clk_register(struct mdss_data_type *mdata,
@@ -934,9 +906,6 @@
 	if (rc)
 		return rc;
 
-	mdata->clk_ctrl_wq = create_singlethread_workqueue("mdp_clk_wq");
-	INIT_WORK(&mdata->clk_ctrl_worker, mdss_mdp_clk_ctrl_workqueue_handler);
-
 	mdata->iclient = msm_ion_client_create(-1, mdata->pdev->name);
 	if (IS_ERR_OR_NULL(mdata->iclient)) {
 		pr_err("msm_ion_client_create() return error (%p)\n",
@@ -1572,8 +1541,6 @@
 
 static inline int mdss_mdp_suspend_sub(struct mdss_data_type *mdata)
 {
-	flush_workqueue(mdata->clk_ctrl_wq);
-
 	mdata->suspend_fs_ena = mdata->fs_ena;
 	mdss_mdp_footswitch_ctrl(mdata, false);
 
@@ -1671,8 +1638,6 @@
 
 	dev_dbg(dev, "pm_runtime: idling...\n");
 
-	flush_workqueue(mdata->clk_ctrl_wq);
-
 	return 0;
 }
 
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 01cfad5..6597329 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -129,6 +129,7 @@
 	u16 width;
 	u16 height;
 	u32 dst_format;
+	bool is_secure;
 
 	u32 bus_ab_quota;
 	u32 bus_ib_quota;
@@ -291,6 +292,7 @@
 	u32 params_changed;
 
 	unsigned long smp[MAX_PLANES];
+	unsigned long smp_reserved[MAX_PLANES];
 
 	struct mdss_mdp_data back_buf;
 	struct mdss_mdp_data front_buf;
@@ -458,6 +460,9 @@
 void mdss_mdp_pipe_unmap(struct mdss_mdp_pipe *pipe);
 struct mdss_mdp_pipe *mdss_mdp_pipe_alloc_dma(struct mdss_mdp_mixer *mixer);
 
+int mdss_mdp_smp_reserve(struct mdss_mdp_pipe *pipe);
+void mdss_mdp_smp_unreserve(struct mdss_mdp_pipe *pipe);
+
 int mdss_mdp_pipe_addr_setup(struct mdss_data_type *mdata, u32 *offsets,
 		u32 *ftch_y_id, u32 type, u32 num_base, u32 len);
 int mdss_mdp_mixer_addr_setup(struct mdss_data_type *mdata, u32 *mixer_offsets,
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index 692bdf6..5ec215d 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -292,6 +292,7 @@
 	}
 	mutex_lock(&mdss_mdp_ctl_lock);
 	ctl->ref_cnt--;
+	ctl->is_secure = false;
 	ctl->power_on = false;
 	ctl->start_fnc = NULL;
 	ctl->stop_fnc = NULL;
@@ -1088,14 +1089,6 @@
 					stage);
 		}
 
-		if (mixercfg == MDSS_MDP_LM_BORDER_COLOR &&
-				pipe->src_fmt->alpha_enable &&
-				pipe->dst.w == mixer->width &&
-				pipe->dst.h == mixer->height) {
-			pr_debug("setting pipe=%d as BG_PIPE\n", pipe->num);
-			bgalpha = 1;
-		}
-
 		mixercfg |= stage << (3 * pipe->num);
 
 		mdp_mixer_write(mixer, off + MDSS_MDP_REG_LM_OP_MODE, blend_op);
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
index c5c3cec..a59560e 100644
--- a/drivers/video/msm/mdss/mdss_mdp_hwio.h
+++ b/drivers/video/msm/mdss/mdss_mdp_hwio.h
@@ -348,6 +348,8 @@
 #define MDSS_MDP_REG_WB_OUT_SIZE			0x074
 #define MDSS_MDP_REG_WB_ALPHA_X_VALUE			0x078
 #define MDSS_MDP_REG_WB_CSC_BASE			0x260
+#define MDSS_MDP_REG_WB_DST_ADDR_SW_STATUS		0x2B0
+
 
 enum mdss_mdp_dspp_index {
 	MDSS_MDP_DSPP0,
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
index 006a8dd..fff8a6e 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
@@ -15,20 +15,32 @@
 #include "mdss_panel.h"
 #include "mdss_mdp.h"
 
+#define VSYNC_EXPIRE_TICK 4
+
 #define START_THRESHOLD 4
 #define CONTINUE_TRESHOLD 4
 
 #define MAX_SESSIONS 2
 
+/* wait for at most 2 vsync for lowest refresh rate (24hz) */
+#define KOFF_TIMEOUT msecs_to_jiffies(84)
+
 struct mdss_mdp_cmd_ctx {
 	u32 pp_num;
 	u8 ref_cnt;
-
 	struct completion pp_comp;
+	struct completion stop_comp;
 	atomic_t vsync_ref;
-	spinlock_t vsync_lock;
-	mdp_vsync_handler_t vsync_handler;
+	mdp_vsync_handler_t send_vsync;
 	int panel_on;
+	int koff_cnt;
+	int clk_enabled;
+	int clk_control;
+	int vsync_enabled;
+	int expire;
+	struct mutex clk_mtx;
+	spinlock_t clk_lock;
+	struct work_struct clk_work;
 
 	/* te config */
 	u8 tear_check;
@@ -118,54 +130,6 @@
 	return 0;
 }
 
-static inline void cmd_readptr_irq_enable(struct mdss_mdp_ctl *ctl)
-{
-	struct mdss_mdp_cmd_ctx *ctx = ctl->priv_data;
-
-	if (atomic_inc_return(&ctx->vsync_ref) == 1) {
-		pr_debug("%s:\n", __func__);
-		mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_RD_PTR, ctx->pp_num);
-	}
-}
-
-static inline void cmd_readptr_irq_disable(struct mdss_mdp_ctl *ctl)
-{
-	struct mdss_mdp_cmd_ctx *ctx = ctl->priv_data;
-
-	if (atomic_dec_return(&ctx->vsync_ref) == 0) {
-		pr_debug("%s:\n", __func__);
-		mdss_mdp_irq_disable(MDSS_MDP_IRQ_PING_PONG_RD_PTR,
-							ctx->pp_num);
-	}
-}
-
-int mdss_mdp_cmd_set_vsync_handler(struct mdss_mdp_ctl *ctl,
-		mdp_vsync_handler_t vsync_handler)
-{
-	struct mdss_mdp_cmd_ctx *ctx;
-	unsigned long flags;
-
-	ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
-	if (!ctx) {
-		pr_err("invalid ctx for ctl=%d\n", ctl->num);
-		return -ENODEV;
-	}
-
-	spin_lock_irqsave(&ctx->vsync_lock, flags);
-
-	if (!ctx->vsync_handler && vsync_handler) {
-		ctx->vsync_handler = vsync_handler;
-		cmd_readptr_irq_enable(ctl);
-	} else if (ctx->vsync_handler && !vsync_handler) {
-		cmd_readptr_irq_disable(ctl);
-		ctx->vsync_handler = vsync_handler;
-	}
-
-	spin_unlock_irqrestore(&ctx->vsync_lock, flags);
-
-	return 0;
-}
-
 static void mdss_mdp_cmd_readptr_done(void *arg)
 {
 	struct mdss_mdp_ctl *ctl = arg;
@@ -177,15 +141,29 @@
 		return;
 	}
 
-	pr_debug("%s: ctl=%d intf_num=%d\n", __func__, ctl->num, ctl->intf_num);
+	pr_debug("%s: num=%d ctx=%d expire=%d koff=%d\n", __func__, ctl->num,
+			ctx->pp_num, ctx->expire, ctx->koff_cnt);
 
 	vsync_time = ktime_get();
 	ctl->vsync_cnt++;
 
-	spin_lock(&ctx->vsync_lock);
-	if (ctx->vsync_handler)
-		ctx->vsync_handler(ctl, vsync_time);
-	spin_unlock(&ctx->vsync_lock);
+	spin_lock(&ctx->clk_lock);
+	if (ctx->send_vsync)
+		ctx->send_vsync(ctl, vsync_time);
+
+	if (ctx->expire) {
+		ctx->expire--;
+		if (ctx->expire == 0) {
+			if (ctx->koff_cnt <= 0) {
+				ctx->clk_control = 1;
+				schedule_work(&ctx->clk_work);
+			} else {
+				/* put off one vsync */
+				ctx->expire += 1;
+			}
+		}
+	}
+	spin_unlock(&ctx->clk_lock);
 }
 
 static void mdss_mdp_cmd_pingpong_done(void *arg)
@@ -193,12 +171,161 @@
 	struct mdss_mdp_ctl *ctl = arg;
 	struct mdss_mdp_cmd_ctx *ctx = ctl->priv_data;
 
-	pr_debug("%s: intf_num=%d ctx=%p\n", __func__, ctl->intf_num, ctx);
+	if (!ctx) {
+		pr_err("%s: invalid ctx\n", __func__);
+		return;
+	}
 
+	spin_lock(&ctx->clk_lock);
 	mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num);
 
-	if (ctx)
-		complete(&ctx->pp_comp);
+	complete_all(&ctx->pp_comp);
+
+	if (ctx->koff_cnt)
+		ctx->koff_cnt--;
+
+	pr_debug("%s: ctl_num=%d intf_num=%d ctx=%d kcnt=%d\n", __func__,
+		ctl->num, ctl->intf_num, ctx->pp_num, ctx->koff_cnt);
+
+	spin_unlock(&ctx->clk_lock);
+}
+
+static void clk_ctrl_work(struct work_struct *work)
+{
+	unsigned long flags;
+	struct mdss_mdp_cmd_ctx *ctx =
+		container_of(work, typeof(*ctx), clk_work);
+
+	if (!ctx) {
+		pr_err("%s: invalid ctx\n", __func__);
+		return;
+	}
+
+	pr_debug("%s:ctx=%p num=%d\n", __func__, ctx, ctx->pp_num);
+
+	mutex_lock(&ctx->clk_mtx);
+	spin_lock_irqsave(&ctx->clk_lock, flags);
+	if (ctx->clk_control && ctx->clk_enabled) {
+		ctx->clk_enabled = 0;
+		ctx->clk_control = 0;
+		spin_unlock_irqrestore(&ctx->clk_lock, flags);
+		/*
+		 * make sure dsi link is idle  here
+		 */
+		ctx->vsync_enabled = 0;
+		mdss_mdp_irq_disable(MDSS_MDP_IRQ_PING_PONG_RD_PTR,
+						ctx->pp_num);
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+		complete(&ctx->stop_comp);
+		pr_debug("%s: SET_CLK_OFF, pid=%d\n", __func__, current->pid);
+	} else {
+		spin_unlock_irqrestore(&ctx->clk_lock, flags);
+	}
+	mutex_unlock(&ctx->clk_mtx);
+}
+
+static int mdss_mdp_cmd_vsync_ctrl(struct mdss_mdp_ctl *ctl,
+		mdp_vsync_handler_t send_vsync)
+{
+	struct mdss_mdp_cmd_ctx *ctx;
+	unsigned long flags;
+	int enable;
+
+	ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
+	if (!ctx) {
+		pr_err("%s: invalid ctx\n", __func__);
+		return -ENODEV;
+	}
+
+	enable = (send_vsync != NULL);
+
+	pr_debug("%s: ctx=%p ctx=%d enabled=%d %d clk_enabled=%d clk_ctrl=%d\n",
+			__func__, ctx, ctx->pp_num, ctx->vsync_enabled, enable,
+					ctx->clk_enabled, ctx->clk_control);
+
+	mutex_lock(&ctx->clk_mtx);
+	if (ctx->vsync_enabled == enable) {
+		mutex_unlock(&ctx->clk_mtx);
+		return 0;
+	}
+
+	if (enable) {
+		spin_lock_irqsave(&ctx->clk_lock, flags);
+		ctx->clk_control = 0;
+		ctx->expire = 0;
+		ctx->send_vsync = send_vsync;
+		spin_unlock_irqrestore(&ctx->clk_lock, flags);
+		if (ctx->clk_enabled == 0) {
+			mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+			mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_RD_PTR,
+							ctx->pp_num);
+			ctx->vsync_enabled = 1;
+			ctx->clk_enabled = 1;
+			pr_debug("%s: SET_CLK_ON, pid=%d\n", __func__,
+						current->pid);
+		}
+	} else {
+		spin_lock_irqsave(&ctx->clk_lock, flags);
+		ctx->expire = VSYNC_EXPIRE_TICK;
+		spin_unlock_irqrestore(&ctx->clk_lock, flags);
+	}
+	mutex_unlock(&ctx->clk_mtx);
+
+	return 0;
+}
+
+static void mdss_mdp_cmd_chk_clock(struct mdss_mdp_cmd_ctx *ctx)
+{
+	unsigned long flags;
+	int set_clk_on = 0;
+
+	if (!ctx) {
+		pr_err("invalid ctx\n");
+		return;
+	}
+
+	pr_debug("%s: ctx=%p num=%d clk_enabled=%d\n", __func__,
+				ctx, ctx->pp_num, ctx->clk_enabled);
+
+	mutex_lock(&ctx->clk_mtx);
+	spin_lock_irqsave(&ctx->clk_lock, flags);
+	ctx->koff_cnt++;
+	ctx->clk_control = 0;
+	ctx->expire = VSYNC_EXPIRE_TICK;
+	if (ctx->clk_enabled == 0) {
+		set_clk_on++;
+		ctx->clk_enabled = 1;
+	}
+	spin_unlock_irqrestore(&ctx->clk_lock, flags);
+
+	if (set_clk_on) {
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+		ctx->vsync_enabled = 1;
+		mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_RD_PTR, ctx->pp_num);
+		pr_debug("%s: ctx=%p num=%d SET_CLK_ON\n", __func__,
+						ctx, ctx->pp_num);
+	}
+	mutex_unlock(&ctx->clk_mtx);
+}
+
+static int mdss_mdp_cmd_wait4comp(struct mdss_mdp_ctl *ctl, void *arg)
+{
+	struct mdss_mdp_cmd_ctx *ctx;
+	int rc;
+
+	ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
+	if (!ctx) {
+		pr_err("invalid ctx\n");
+		return -ENODEV;
+	}
+
+	pr_debug("%s: intf_num=%d ctx=%p\n", __func__, ctl->intf_num, ctx);
+
+	rc = wait_for_completion_interruptible_timeout(&ctx->pp_comp,
+			KOFF_TIMEOUT);
+	WARN(rc <= 0, "cmd kickoff timed out (%d) ctl=%d\n", rc, ctl->num);
+
+	return rc;
 }
 
 int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg)
@@ -207,14 +334,16 @@
 	int rc;
 
 	ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
-	pr_debug("%s: kickoff intf_num=%d ctx=%p\n", __func__,
-					ctl->intf_num, ctx);
-
 	if (!ctx) {
 		pr_err("invalid ctx\n");
 		return -ENODEV;
 	}
 
+	pr_debug("%s: kickoff intf_num=%d ctx=%p\n", __func__,
+					ctl->intf_num, ctx);
+
+	mdss_mdp_cmd_chk_clock(ctx);
+
 	if (ctx->panel_on == 0) {
 		rc = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_UNBLANK, NULL);
 		WARN(rc, "intf %d unblank error (%d)\n", ctl->intf_num, rc);
@@ -230,27 +359,37 @@
 
 	mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_START, 1);
 
-	wait_for_completion_interruptible(&ctx->pp_comp);
-
 	return 0;
 }
 
 int mdss_mdp_cmd_stop(struct mdss_mdp_ctl *ctl)
 {
 	struct mdss_mdp_cmd_ctx *ctx;
+	int need_wait = 0;
 	int ret;
 
-	pr_debug("%s: +\n", __func__);
-
 	ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
 	if (!ctx) {
 		pr_err("invalid ctx\n");
 		return -ENODEV;
 	}
 
+	pr_debug("%s:+ vaync_enable=%d expire=%d\n", __func__,
+		ctx->vsync_enabled, ctx->expire);
+
+	mutex_lock(&ctx->clk_mtx);
+	if (ctx->vsync_enabled) {
+		INIT_COMPLETION(ctx->stop_comp);
+		need_wait = 1;
+	}
+	mutex_unlock(&ctx->clk_mtx);
+
+	if (need_wait)
+		wait_for_completion_interruptible(&ctx->stop_comp);
+
 	ctx->panel_on = 0;
 
-	mdss_mdp_cmd_set_vsync_handler(ctl, NULL);
+	mdss_mdp_cmd_vsync_ctrl(ctl, NULL);
 
 	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_RD_PTR, ctl->intf_num,
 				   NULL, NULL);
@@ -265,7 +404,6 @@
 
 	ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_PANEL_OFF, NULL);
 	WARN(ret, "intf %d unblank error (%d)\n", ctl->intf_num, ret);
-	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 
 	pr_debug("%s:-\n", __func__);
 
@@ -280,8 +418,6 @@
 
 	pr_debug("%s:+\n", __func__);
 
-	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
-
 	mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_LEFT);
 	if (!mixer) {
 		pr_err("mixer not setup correctly\n");
@@ -308,8 +444,14 @@
 
 	ctx->pp_num = mixer->num;
 	init_completion(&ctx->pp_comp);
-	spin_lock_init(&ctx->vsync_lock);
+	init_completion(&ctx->stop_comp);
 	atomic_set(&ctx->vsync_ref, 0);
+	spin_lock_init(&ctx->clk_lock);
+	mutex_init(&ctx->clk_mtx);
+	INIT_WORK(&ctx->clk_work, clk_ctrl_work);
+
+	pr_debug("%s: ctx=%p num=%d mixer=%d\n", __func__,
+				ctx, ctx->pp_num, mixer->num);
 
 	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_RD_PTR, ctx->pp_num,
 				   mdss_mdp_cmd_readptr_done, ctl);
@@ -325,7 +467,8 @@
 
 	ctl->stop_fnc = mdss_mdp_cmd_stop;
 	ctl->display_fnc = mdss_mdp_cmd_kickoff;
-	ctl->set_vsync_handler = mdss_mdp_cmd_set_vsync_handler;
+	ctl->wait_fnc = mdss_mdp_cmd_wait4comp;
+	ctl->set_vsync_handler = mdss_mdp_cmd_vsync_ctrl;
 
 	pr_debug("%s:-\n", __func__);
 
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
index d86527b..0c08eda 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
@@ -17,6 +17,9 @@
 #include "mdss_mdp.h"
 #include "mdss_mdp_rotator.h"
 
+/* wait for at most 2 vsync for lowest refresh rate (24hz) */
+#define KOFF_TIMEOUT msecs_to_jiffies(84)
+
 enum mdss_mdp_writeback_type {
 	MDSS_MDP_WRITEBACK_TYPE_ROTATOR,
 	MDSS_MDP_WRITEBACK_TYPE_LINE,
@@ -28,6 +31,8 @@
 	char __iomem *base;
 	u8 ref_cnt;
 	u8 type;
+	struct completion wb_comp;
+	int comp_cnt;
 
 	u32 intr_type;
 	u32 intf_num;
@@ -321,10 +326,37 @@
 	pr_debug("intr wb_num=%d\n", ctx->wb_num);
 
 	mdss_mdp_irq_disable_nosync(ctx->intr_type, ctx->intf_num);
-	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, true);
 
 	if (ctx->callback_fnc)
 		ctx->callback_fnc(ctx->callback_arg);
+
+	complete_all(&ctx->wb_comp);
+}
+
+static int mdss_mdp_wb_wait4comp(struct mdss_mdp_ctl *ctl, void *arg)
+{
+	struct mdss_mdp_writeback_ctx *ctx;
+	int rc = 0;
+
+	ctx = (struct mdss_mdp_writeback_ctx *) ctl->priv_data;
+	if (!ctx) {
+		pr_err("invalid ctx\n");
+		return -ENODEV;
+	}
+
+	if (ctx->comp_cnt == 0)
+		return rc;
+
+	rc = wait_for_completion_interruptible_timeout(&ctx->wb_comp,
+			KOFF_TIMEOUT);
+	WARN(rc <= 0, "writeback kickoff timed out (%d) ctl=%d\n",
+							rc, ctl->num);
+
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); /* clock off */
+
+	ctx->comp_cnt--;
+
+	return rc;
 }
 
 static int mdss_mdp_writeback_display(struct mdss_mdp_ctl *ctl, void *arg)
@@ -338,6 +370,12 @@
 	if (!ctx)
 		return -ENODEV;
 
+	if (ctx->comp_cnt) {
+		pr_err("previous kickoff not completed yet, ctl=%d\n",
+					ctl->num);
+		return -EPERM;
+	}
+
 	wb_args = (struct mdss_mdp_writeback_arg *) arg;
 	if (!wb_args)
 		return -ENOENT;
@@ -352,14 +390,18 @@
 	ctx->callback_arg = wb_args->priv_data;
 
 	flush_bits = BIT(16); /* WB */
+	mdp_wb_write(ctx, MDSS_MDP_REG_WB_DST_ADDR_SW_STATUS, ctl->is_secure);
 	mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, flush_bits);
 
+	INIT_COMPLETION(ctx->wb_comp);
 	mdss_mdp_irq_enable(ctx->intr_type, ctx->intf_num);
 
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 	mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_START, 1);
 	wmb();
 
+	ctx->comp_cnt++;
+
 	return 0;
 }
 
@@ -387,6 +429,7 @@
 	ctx->wb_num = ctl->num;	/* wb num should match ctl num */
 	ctx->base = ctl->wb_base;
 	ctx->initialized = false;
+	init_completion(&ctx->wb_comp);
 
 	mdss_mdp_set_intr_callback(ctx->intr_type, ctx->intf_num,
 				   mdss_mdp_writeback_intr_done, ctx);
@@ -397,6 +440,7 @@
 		ctl->prepare_fnc = mdss_mdp_writeback_prepare_wfd;
 	ctl->stop_fnc = mdss_mdp_writeback_stop;
 	ctl->display_fnc = mdss_mdp_writeback_display;
+	ctl->wait_fnc = mdss_mdp_wb_wait4comp;
 
 	return ret;
 }
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index c69edd8..97704bf 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -375,8 +375,8 @@
 				pr_err("Can't switch mixer %d->%d pnum %d!\n",
 						pipe->mixer->num, mixer->num,
 						pipe->num);
-				mdss_mdp_pipe_unmap(pipe);
-				return -EINVAL;
+				ret = -EINVAL;
+				goto exit_fail;
 			}
 			pr_debug("switching pipe mixer %d->%d pnum %d\n",
 					pipe->mixer->num, mixer->num,
@@ -475,6 +475,12 @@
 		}
 	}
 
+	ret = mdss_mdp_smp_reserve(pipe);
+	if (ret) {
+		pr_debug("mdss_mdp_smp_reserve failed. ret=%d\n", ret);
+		goto exit_fail;
+	}
+
 	pipe->params_changed++;
 
 	req->id = pipe->ndx;
@@ -484,6 +490,25 @@
 	mdss_mdp_pipe_unmap(pipe);
 
 	return ret;
+
+exit_fail:
+	mdss_mdp_pipe_unmap(pipe);
+
+	mutex_lock(&mfd->lock);
+	if (pipe->play_cnt == 0) {
+		pr_debug("failed for pipe %d\n", pipe->num);
+		list_del(&pipe->used_list);
+		mdss_mdp_pipe_destroy(pipe);
+	}
+
+	/* invalidate any overlays in this framebuffer after failure */
+	list_for_each_entry(pipe, &mdp5_data->pipes_used, used_list) {
+		pr_debug("freeing allocations for pipe %d\n", pipe->num);
+		mdss_mdp_smp_unreserve(pipe);
+		pipe->params_changed = 0;
+	}
+	mutex_unlock(&mfd->lock);
+	return ret;
 }
 
 static int mdss_mdp_overlay_set(struct msm_fb_data_type *mfd,
@@ -746,15 +771,16 @@
 		} else if (pipe->front_buf.num_planes) {
 			buf = &pipe->front_buf;
 		} else {
-			pr_warn("pipe queue without buffer\n");
-			buf = NULL;
+			pr_warn("pipe queue w/o buffer. unstaging layer\n");
+			mdss_mdp_mixer_pipe_unstage(pipe);
+			continue;
 		}
 
 		ret = mdss_mdp_pipe_queue_data(pipe, buf);
 		if (IS_ERR_VALUE(ret)) {
 			pr_warn("Unable to queue data for pnum=%d\n",
 					pipe->num);
-			mdss_mdp_overlay_free_buf(buf);
+			mdss_mdp_mixer_pipe_unstage(pipe);
 		}
 	}
 
@@ -832,12 +858,13 @@
 	if (ndx == BORDERFILL_NDX) {
 		pr_debug("borderfill disable\n");
 		mdp5_data->borderfill_enable = false;
-		return 0;
+		ret = 0;
+		goto done;
 	}
 
 	if (!mfd->panel_power_on) {
-		mutex_unlock(&mdp5_data->ov_lock);
-		return -EPERM;
+		ret = -EPERM;
+		goto done;
 	}
 
 	pr_debug("unset ndx=%x\n", ndx);
@@ -847,6 +874,7 @@
 	else
 		ret = mdss_mdp_overlay_release(mfd, ndx);
 
+done:
 	mutex_unlock(&mdp5_data->ov_lock);
 
 	return ret;
@@ -988,14 +1016,14 @@
 		return ret;
 
 	if (!mfd->panel_power_on) {
-		mutex_unlock(&mdp5_data->ov_lock);
-		return -EPERM;
+		ret = -EPERM;
+		goto done;
 	}
 
 	ret = mdss_mdp_overlay_start(mfd);
 	if (ret) {
 		pr_err("unable to start overlay %d (%d)\n", mfd->index, ret);
-		return ret;
+		goto done;
 	}
 
 	if (req->id & MDSS_MDP_ROT_SESSION_MASK) {
@@ -1008,6 +1036,7 @@
 		ret = mdss_mdp_overlay_queue(mfd, req);
 	}
 
+done:
 	mutex_unlock(&mdp5_data->ov_lock);
 
 	return ret;
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index 746705d..0f65530 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -40,17 +40,18 @@
 	return readl_relaxed(pipe->base + reg);
 }
 
-static u32 mdss_mdp_smp_mmb_reserve(unsigned long *smp, size_t n)
+static u32 mdss_mdp_smp_mmb_reserve(unsigned long *existing,
+	unsigned long *reserve, size_t n)
 {
 	u32 i, mmb;
 
 	/* reserve more blocks if needed, but can't free mmb at this point */
-	for (i = bitmap_weight(smp, SMP_MB_CNT); i < n; i++) {
+	for (i = bitmap_weight(existing, SMP_MB_CNT); i < n; i++) {
 		if (bitmap_full(mdss_mdp_smp_mmb_pool, SMP_MB_CNT))
 			break;
 
 		mmb = find_first_zero_bit(mdss_mdp_smp_mmb_pool, SMP_MB_CNT);
-		set_bit(mmb, smp);
+		set_bit(mmb, reserve);
 		set_bit(mmb, mdss_mdp_smp_mmb_pool);
 	}
 	return i;
@@ -74,10 +75,17 @@
 	return cnt;
 }
 
-static void mdss_mdp_smp_mmb_free(unsigned long *smp)
+static void mdss_mdp_smp_mmb_amend(unsigned long *smp, unsigned long *extra)
+{
+	bitmap_or(smp, smp, extra, SMP_MB_CNT);
+	bitmap_zero(extra, SMP_MB_CNT);
+}
+
+static void mdss_mdp_smp_mmb_free(unsigned long *smp, bool write)
 {
 	if (!bitmap_empty(smp, SMP_MB_CNT)) {
-		mdss_mdp_smp_mmb_set(MDSS_MDP_SMP_CLIENT_UNUSED, smp);
+		if (write)
+			mdss_mdp_smp_mmb_set(MDSS_MDP_SMP_CLIENT_UNUSED, smp);
 		bitmap_andnot(mdss_mdp_smp_mmb_pool, mdss_mdp_smp_mmb_pool,
 			      smp, SMP_MB_CNT);
 		bitmap_zero(smp, SMP_MB_CNT);
@@ -104,19 +112,33 @@
 
 static void mdss_mdp_smp_free(struct mdss_mdp_pipe *pipe)
 {
+	int i;
+
 	mutex_lock(&mdss_mdp_smp_lock);
-	mdss_mdp_smp_mmb_free(&pipe->smp[0]);
-	mdss_mdp_smp_mmb_free(&pipe->smp[1]);
-	mdss_mdp_smp_mmb_free(&pipe->smp[2]);
+	for (i = 0; i < MAX_PLANES; i++) {
+		mdss_mdp_smp_mmb_free(&pipe->smp_reserved[i], false);
+		mdss_mdp_smp_mmb_free(&pipe->smp[i], true);
+	}
 	mutex_unlock(&mdss_mdp_smp_lock);
 }
 
-static int mdss_mdp_smp_reserve(struct mdss_mdp_pipe *pipe)
+void mdss_mdp_smp_unreserve(struct mdss_mdp_pipe *pipe)
+{
+	int i;
+
+	mutex_lock(&mdss_mdp_smp_lock);
+	for (i = 0; i < MAX_PLANES; i++)
+		mdss_mdp_smp_mmb_free(&pipe->smp_reserved[i], false);
+	mutex_unlock(&mdss_mdp_smp_lock);
+}
+
+int mdss_mdp_smp_reserve(struct mdss_mdp_pipe *pipe)
 {
 	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
 	u32 num_blks = 0, reserved = 0;
 	struct mdss_mdp_plane_sizes ps;
-	int i, rc;
+	int i;
+	int rc = 0;
 	u32 nlines;
 
 	if (pipe->bwc_mode) {
@@ -140,29 +162,29 @@
 	mutex_lock(&mdss_mdp_smp_lock);
 	for (i = 0; i < ps.num_planes; i++) {
 		nlines = pipe->bwc_mode ? ps.rau_h[i] : 2;
-		num_blks = DIV_ROUND_UP(nlines * ps.ystride[i],
-			mdss_res->smp_mb_size);
+		num_blks = DIV_ROUND_UP(nlines * ps.ystride[i], SMP_MB_SIZE);
 
 		if (mdata->mdp_rev == MDSS_MDP_HW_REV_100)
 			num_blks = roundup_pow_of_two(num_blks);
 
 		pr_debug("reserving %d mmb for pnum=%d plane=%d\n",
 				num_blks, pipe->num, i);
-		reserved = mdss_mdp_smp_mmb_reserve(&pipe->smp[i], num_blks);
+		reserved = mdss_mdp_smp_mmb_reserve(&pipe->smp[i],
+			&pipe->smp_reserved[i], num_blks);
 
 		if (reserved < num_blks)
 			break;
 	}
 
 	if (reserved < num_blks) {
-		pr_err("insufficient MMB blocks\n");
+		pr_debug("insufficient MMB blocks\n");
 		for (; i >= 0; i--)
-			mdss_mdp_smp_mmb_free(&pipe->smp[i]);
-		return -ENOMEM;
+			mdss_mdp_smp_mmb_free(&pipe->smp_reserved[i], false);
+		rc = -ENOMEM;
 	}
 	mutex_unlock(&mdss_mdp_smp_lock);
 
-	return 0;
+	return rc;
 }
 
 static int mdss_mdp_smp_alloc(struct mdss_mdp_pipe *pipe)
@@ -171,8 +193,10 @@
 	int cnt = 0;
 
 	mutex_lock(&mdss_mdp_smp_lock);
-	for (i = 0; i < MAX_PLANES; i++)
+	for (i = 0; i < MAX_PLANES; i++) {
+		mdss_mdp_smp_mmb_amend(&pipe->smp[i], &pipe->smp_reserved[i]);
 		cnt += mdss_mdp_smp_mmb_set(pipe->ftch_id + i, &pipe->smp[i]);
+	}
 	mdss_mdp_smp_set_wm_levels(pipe, cnt);
 	mutex_unlock(&mdss_mdp_smp_lock);
 	return 0;
@@ -307,14 +331,16 @@
 	mutex_lock(&mdss_mdp_sspp_lock);
 
 	pipe = mdss_mdp_pipe_search(mdata, ndx);
-	if (!pipe)
-		return ERR_PTR(-EINVAL);
+	if (!pipe) {
+		pipe = ERR_PTR(-EINVAL);
+		goto error;
+	}
 
 	if (mdss_mdp_pipe_map(pipe))
-		return ERR_PTR(-EACCES);
+		pipe = ERR_PTR(-EACCES);
 
+error:
 	mutex_unlock(&mdss_mdp_sspp_lock);
-
 	return pipe;
 }
 
@@ -645,13 +671,6 @@
 			mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_VIG_OP_MODE,
 			opmode);
 
-		ret = mdss_mdp_smp_reserve(pipe);
-		if (ret) {
-			pr_err("unable to reserve smp for pnum=%d\n",
-			       pipe->num);
-			goto done;
-		}
-
 		mdss_mdp_smp_alloc(pipe);
 	}
 
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 5a0c27e..8bd5674 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -1523,11 +1523,13 @@
 		if (copy_to_user(config->c0_c1_data, local_cfg.c2_data,
 			config->len * sizeof(u32))) {
 			ret = -EFAULT;
+			mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 			goto igc_config_exit;
 		}
 		if (copy_to_user(config->c2_data, local_cfg.c0_c1_data,
 			config->len * sizeof(u32))) {
 			ret = -EFAULT;
+			mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 			goto igc_config_exit;
 		}
 		*copyback = 1;
@@ -1716,16 +1718,19 @@
 		pp_read_argc_lut(&local_cfg, argc_offset);
 		if (copy_to_user(config->r_data,
 			&mdss_pp_res->gc_lut_r[disp_num][0], tbl_size)) {
+			mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 			ret = -EFAULT;
 			goto argc_config_exit;
 		}
 		if (copy_to_user(config->g_data,
 			&mdss_pp_res->gc_lut_g[disp_num][0], tbl_size)) {
+			mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 			ret = -EFAULT;
 			goto argc_config_exit;
 		}
 		if (copy_to_user(config->b_data,
 			&mdss_pp_res->gc_lut_b[disp_num][0], tbl_size)) {
+			mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 			ret = -EFAULT;
 			goto argc_config_exit;
 		}
@@ -1796,6 +1801,7 @@
 		if (copy_to_user(config->data,
 			&mdss_pp_res->enhist_lut[disp_num][0],
 			ENHIST_LUT_ENTRIES * sizeof(u32))) {
+			mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 			ret = -EFAULT;
 			goto enhist_config_exit;
 		}
@@ -2035,6 +2041,7 @@
 			if (IS_ERR_OR_NULL(pipe))
 				continue;
 			if (!pipe || pipe->num > MDSS_MDP_SSPP_VIG2) {
+				mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 				ret = -EINVAL;
 				pr_warn("Invalid Hist pipe (%d)", i);
 				goto hist_exit;
@@ -2153,7 +2160,7 @@
 		i = MDSS_PP_ARG_MASK & block;
 		if (!i) {
 			pr_warn("Must pass pipe arguments, %d", i);
-			goto hist_stop_exit;
+			goto hist_stop_clk;
 		}
 
 		for (i = 0; i < MDSS_PP_ARG_NUM; i++) {
@@ -2173,7 +2180,7 @@
 								ctl_base);
 			mdss_mdp_pipe_unmap(pipe);
 			if (ret)
-				goto hist_stop_exit;
+				goto hist_stop_clk;
 		}
 	} else if (PP_LOCAT(block) == MDSS_PP_DSPP_CFG) {
 		for (i = 0; i < mixer_cnt; i++) {
@@ -2185,13 +2192,14 @@
 			ret = pp_histogram_disable(hist_info, done_bit,
 								ctl_base);
 			if (ret)
-				goto hist_stop_exit;
+				goto hist_stop_clk;
 			mdss_pp_res->pp_disp_flags[disp_num] |=
 							PP_FLAGS_DIRTY_HIST_COL;
 		}
 	}
-hist_stop_exit:
+hist_stop_clk:
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+hist_stop_exit:
 	if (!ret && (PP_LOCAT(block) == MDSS_PP_DSPP_CFG))
 		mdss_mdp_pp_setup(ctl);
 	return ret;
diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.c b/drivers/video/msm/mdss/mdss_mdp_rotator.c
index ce4c28f..016c973 100644
--- a/drivers/video/msm/mdss/mdss_mdp_rotator.c
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.c
@@ -41,7 +41,6 @@
 			rot->ref_cnt++;
 			rot->session_id = i | MDSS_MDP_ROT_SESSION_MASK;
 			mutex_init(&rot->lock);
-			init_completion(&rot->comp);
 			break;
 		}
 	}
@@ -87,10 +86,18 @@
 
 static int mdss_mdp_rotator_busy_wait(struct mdss_mdp_rotator_session *rot)
 {
+	struct mdss_mdp_pipe *rot_pipe = NULL;
+	struct mdss_mdp_ctl *ctl = NULL;
+
+	rot_pipe = rot->pipe;
+	if (!rot_pipe)
+		return -ENODEV;
+
+	ctl = rot_pipe->mixer->ctl;
 	mutex_lock(&rot->lock);
 	if (rot->busy) {
 		pr_debug("waiting for rot=%d to complete\n", rot->pipe->num);
-		wait_for_completion_interruptible(&rot->comp);
+		mdss_mdp_display_wait4comp(ctl);
 		rot->busy = false;
 
 	}
@@ -99,28 +106,18 @@
 	return 0;
 }
 
-static void mdss_mdp_rotator_callback(void *arg)
-{
-	struct mdss_mdp_rotator_session *rot;
-
-	rot = (struct mdss_mdp_rotator_session *) arg;
-	if (rot)
-		complete(&rot->comp);
-}
-
 static int mdss_mdp_rotator_kickoff(struct mdss_mdp_ctl *ctl,
 				    struct mdss_mdp_rotator_session *rot,
 				    struct mdss_mdp_data *dst_data)
 {
 	int ret;
 	struct mdss_mdp_writeback_arg wb_args = {
-		.callback_fnc = mdss_mdp_rotator_callback,
+		.callback_fnc = NULL,
 		.data = dst_data,
 		.priv_data = rot,
 	};
 
 	mutex_lock(&rot->lock);
-	INIT_COMPLETION(rot->comp);
 	rot->busy = true;
 	ret = mdss_mdp_display_commit(ctl, &wb_args);
 	if (ret) {
@@ -204,9 +201,16 @@
 		rot_pipe->params_changed++;
 	}
 
+	ret = mdss_mdp_smp_reserve(rot->pipe);
+	if (ret) {
+		pr_err("unable to mdss_mdp_smp_reserve rot data\n");
+		return ret;
+	}
+
 	ret = mdss_mdp_pipe_queue_data(rot->pipe, src_data);
 	if (ret) {
 		pr_err("unable to queue rot data\n");
+		mdss_mdp_smp_unreserve(rot->pipe);
 		return ret;
 	}
 
diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.h b/drivers/video/msm/mdss/mdss_mdp_rotator.h
index c50d710..3401fe8 100644
--- a/drivers/video/msm/mdss/mdss_mdp_rotator.h
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.h
@@ -36,7 +36,6 @@
 	struct mdss_mdp_pipe *pipe;
 
 	struct mutex lock;
-	struct completion comp;
 	u8 busy;
 	u8 no_wait;
 
diff --git a/drivers/video/msm/mdss/mdss_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c
index 4de6d03..60f05ca 100644
--- a/drivers/video/msm/mdss/mdss_mdp_util.c
+++ b/drivers/video/msm/mdss/mdss_mdp_util.c
@@ -240,7 +240,7 @@
 			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[0] = 32 * 4 * fmt->bpp;
 		ps->ystride[1] = 0;
 		ps->rau_h[0] = 4;
 		ps->rau_h[1] = 0;
@@ -250,8 +250,8 @@
 	}
 
 	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->ystride[0] = ps->ystride[0] * ps->rau_cnt + stride_off;
+	ps->ystride[1] = ps->ystride[1] * ps->rau_cnt + stride_off;
 	ps->num_planes = 2;
 
 	return 0;
@@ -262,8 +262,7 @@
 {
 	struct mdss_mdp_format_params *fmt;
 	int i, rc;
-	u32 bpp, stride_off;
-
+	u32 bpp, ystride0_off, ystride1_off;
 	if (ps == NULL)
 		return -EINVAL;
 
@@ -281,12 +280,14 @@
 		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;
+		ystride0_off = DIV_ROUND_UP(h, ps->rau_h[0]);
+		ystride1_off = DIV_ROUND_UP(h, ps->rau_h[1]);
+		ps->plane_size[0] = (ps->ystride[0] * ystride0_off) +
+				    (ps->ystride[1] * ystride1_off);
+		ps->ystride[0] += ps->ystride[1];
 		ps->ystride[1] = 2;
-		ps->plane_size[1] = ps->rau_cnt * ps->ystride[1] * stride_off;
-
+		ps->plane_size[1] = ps->rau_cnt * ps->ystride[1] *
+				   (ystride0_off + ystride1_off);
 	} else {
 		if (fmt->fetch_planes == MDSS_MDP_PLANE_INTERLEAVED) {
 			ps->num_planes = 1;
@@ -346,43 +347,38 @@
 int mdss_mdp_data_check(struct mdss_mdp_data *data,
 			struct mdss_mdp_plane_sizes *ps)
 {
+	struct mdss_mdp_img_data *prev, *curr;
+	int i;
+
 	if (!ps)
 		return 0;
 
 	if (!data || data->num_planes == 0)
 		return -ENOMEM;
 
-	if (data->bwc_enabled) {
-		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;
+	pr_debug("srcp0=%x len=%u frame_size=%u\n", data->p[0].addr,
+		data->p[0].len, ps->total_size);
 
-		pr_debug("srcp0=%x len=%u frame_size=%u\n", data->p[0].addr,
-				data->p[0].len, ps->total_size);
-
-		for (i = 0; i < ps->num_planes; i++) {
-			curr = &data->p[i];
-			if (i >= data->num_planes) {
-				u32 psize = ps->plane_size[i-1];
-				prev = &data->p[i-1];
-				if (prev->len > psize) {
-					curr->len = prev->len - psize;
-					prev->len = psize;
-				}
-				curr->addr = prev->addr + psize;
+	for (i = 0; i < ps->num_planes; i++) {
+		curr = &data->p[i];
+		if (i >= data->num_planes) {
+			u32 psize = ps->plane_size[i-1];
+			prev = &data->p[i-1];
+			if (prev->len > psize) {
+				curr->len = prev->len - psize;
+				prev->len = psize;
 			}
-			if (curr->len < ps->plane_size[i]) {
-				pr_err("insufficient mem=%u p=%d len=%u\n",
-				       curr->len, i, ps->plane_size[i]);
-				return -ENOMEM;
-			}
-			pr_debug("plane[%d] addr=%x len=%u\n", i,
-					curr->addr, curr->len);
+			curr->addr = prev->addr + psize;
 		}
-		data->num_planes = ps->num_planes;
+		if (curr->len < ps->plane_size[i]) {
+			pr_err("insufficient mem=%u p=%d len=%u\n",
+			       curr->len, i, ps->plane_size[i]);
+			return -ENOMEM;
+		}
+		pr_debug("plane[%d] addr=%x len=%u\n", i,
+				curr->addr, curr->len);
 	}
+	data->num_planes = ps->num_planes;
 
 	return 0;
 }
diff --git a/drivers/video/msm/mdss/mdss_mdp_wb.c b/drivers/video/msm/mdss/mdss_mdp_wb.c
index c19e07a..7ccf1b9 100644
--- a/drivers/video/msm/mdss/mdss_mdp_wb.c
+++ b/drivers/video/msm/mdss/mdss_mdp_wb.c
@@ -132,7 +132,13 @@
 
 	pr_debug("setting secure=%d\n", enable);
 
+	ctl->is_secure = enable;
 	wb->is_secure = enable;
+
+	/* newer revisions don't require secure src pipe for secure session */
+	if (ctl->mdata->mdp_rev > MDSS_MDP_HW_REV_100)
+		return 0;
+
 	pipe = wb->secure_pipe;
 
 	if (!enable) {
@@ -243,6 +249,7 @@
 		mdss_mdp_pipe_destroy(wb->secure_pipe);
 	mutex_unlock(&wb->lock);
 
+	mdp5_data->ctl->is_secure = false;
 	mdp5_data->wb = NULL;
 	mutex_unlock(&mdss_mdp_wb_buf_lock);
 
diff --git a/fs/file.c b/fs/file.c
index ba3f605..2f989c3 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -476,6 +476,7 @@
 	spin_unlock(&files->file_lock);
 	return error;
 }
+EXPORT_SYMBOL(alloc_fd);
 
 int get_unused_fd(void)
 {
diff --git a/include/linux/bluetooth-power.h b/include/linux/bluetooth-power.h
new file mode 100644
index 0000000..ba53a40
--- /dev/null
+++ b/include/linux/bluetooth-power.h
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef __LINUX_BLUETOOTH_POWER_H
+#define __LINUX_BLUETOOTH_POWER_H
+
+/*
+ * voltage regulator information required for configuring the
+ * bluetooth chipset
+ */
+struct bt_power_vreg_data {
+	/* voltage regulator handle */
+	struct regulator *reg;
+	/* regulator name */
+	const char *name;
+	/* voltage levels to be set */
+	unsigned int low_vol_level;
+	unsigned int high_vol_level;
+	/*
+	 * is set voltage supported for this regulator?
+	 * false => set voltage is not supported
+	 * true  => set voltage is supported
+	 *
+	 * Some regulators (like gpio-regulators, LVS (low voltage swtiches)
+	 * PMIC regulators) dont have the capability to call
+	 * regulator_set_voltage or regulator_set_optimum_mode
+	 * Use this variable to indicate if its a such regulator or not
+	 */
+	bool set_voltage_sup;
+	/* is this regulator enabled? */
+	bool is_enabled;
+};
+
+/*
+ * Platform data for the bluetooth power driver.
+ */
+struct bluetooth_power_platform_data {
+	/* Bluetooth reset gpio */
+	int bt_gpio_sys_rst;
+	/* VDDIO voltage regulator */
+	struct bt_power_vreg_data *bt_vdd_io;
+	/* VDD_PA voltage regulator */
+	struct bt_power_vreg_data *bt_vdd_pa;
+	/* VDD_LDOIN voltage regulator */
+	struct bt_power_vreg_data *bt_vdd_ldo;
+	/* Optional: chip power down gpio-regulator
+	 * chip power down data is required when bluetooth module
+	 * and other modules like wifi co-exist in a single chip and
+	 * shares a common gpio to bring chip out of reset.
+	 */
+	struct bt_power_vreg_data *bt_chip_pwd;
+	/* Optional: Bluetooth power setup function */
+	int (*bt_power_setup) (int);
+};
+
+#endif /* __LINUX_BLUETOOTH_POWER_H */
diff --git a/include/linux/dvb/dmx.h b/include/linux/dvb/dmx.h
index c2b35c8..c219725 100644
--- a/include/linux/dvb/dmx.h
+++ b/include/linux/dvb/dmx.h
@@ -368,6 +368,9 @@
 	/* DTS value associated with the buffer */
 	__u64 dts;
 
+	/* STC value associated with the buffer in 27MHz */
+	__u64 stc;
+
 	/*
 	 * Number of TS packets with Transport Error Indicator (TEI) set
 	 * in the TS packet header since last reported event
diff --git a/include/linux/qpnp-misc.h b/include/linux/qpnp-misc.h
index b241e5d..ee614a4 100644
--- a/include/linux/qpnp-misc.h
+++ b/include/linux/qpnp-misc.h
@@ -30,7 +30,7 @@
 
 int qpnp_misc_irqs_available(struct device *consumer_dev);
 #else
-static int qpnp_misc_irq_available(struct device *consumer_dev)
+static int qpnp_misc_irqs_available(struct device *consumer_dev)
 {
 	return 0;
 }
diff --git a/include/linux/regulator/qpnp-regulator.h b/include/linux/regulator/qpnp-regulator.h
index ec580ab..c7afeb5 100644
--- a/include/linux/regulator/qpnp-regulator.h
+++ b/include/linux/regulator/qpnp-regulator.h
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -93,12 +93,24 @@
  * @system_load:            Load in uA present on regulator that is not captured
  *				by any consumer request
  * @enable_time:            Time in us to delay after enabling the regulator
- * @ocp_enable:             1 = Enable over current protection (OCP) for voltage
- *				switch type regulators so that they latch off
- *				automatically when over current is detected
+ * @ocp_enable:             1 = Allow over current protection (OCP) to be
+ *				enabled for voltage switch type regulators so
+ *				that they latch off automatically when over
+ *				current is detected.  OCP is enabled when in HPM
+ *				or auto mode.
  *			    0 = Disable OCP
  *			    QPNP_REGULATOR_USE_HW_DEFAULT = do not modify
  *			        OCP state
+ * @ocp_irq:                IRQ number of the voltage switch OCP IRQ.  If
+ *				specified the voltage switch will be toggled off
+ *				and back on when OCP triggers in order to handle
+ *				high in-rush current.
+ * @ocp_max_retries:        Maximum number of times to try toggling a voltage
+ *				switch off and back on as a result of
+ *				consecutive over current events.
+ * @ocp_retry_delay_ms:     Time to delay in milliseconds between each
+ *				voltage switch toggle after an over current
+ *				event takes place.
  * @boost_current_limit:    This parameter sets the current limit of boost type
  *				regulators.  Its value should be one of
  *				QPNP_BOOST_CURRENT_LIMIT_*.  If its value is
@@ -117,9 +129,6 @@
  *				its value is QPNP_VS_SOFT_START_STR_HW_DEFAULT,
  *				then the soft start strength will be left at its
  *				default hardware value.
- * @ocp_enable_time:        Time to delay in us between enabling a switch and
- *				subsequently enabling over current protection
- *				(OCP) for the switch
  * @auto_mode_enable:       1 = Enable automatic hardware selection of regulator
  *				mode (HPM vs LPM).  Auto mode is not available
  *				on boost type regulators
@@ -132,6 +141,18 @@
  *			    0 = Do not enable bypass mode
  *			    QPNP_REGULATOR_USE_HW_DEFAULT = do not modify
  *			        bypass mode state
+ * @hpm_enable:             1 = Enable high power mode (HPM), also referred to
+ *				as NPM.  HPM consumes more ground current than
+ *				LPM, but it can source significantly higher load
+ *				current.  HPM is not available on boost type
+ *				regulators.  For voltage switch type regulators,
+ *				HPM implies that over current protection and
+ *				soft start are active all the time.  This
+ *				configuration can be overwritten by changing the
+ *				regulator's mode dynamically.
+ *			    0 = Do not enable HPM
+ *			    QPNP_REGULATOR_USE_HW_DEFAULT = do not modify
+ *			        HPM state
  * @base_addr:              SMPI base address for the regulator peripheral
  */
 struct qpnp_regulator_platform_data {
@@ -142,12 +163,15 @@
 	int					system_load;
 	int					enable_time;
 	int					ocp_enable;
+	int					ocp_irq;
+	int					ocp_max_retries;
+	int					ocp_retry_delay_ms;
 	enum qpnp_boost_current_limit		boost_current_limit;
 	int					soft_start_enable;
 	enum qpnp_vs_soft_start_str		vs_soft_start_strength;
-	int					ocp_enable_time;
 	int					auto_mode_enable;
 	int					bypass_mode_enable;
+	int					hpm_enable;
 	u16					base_addr;
 };
 
diff --git a/include/media/msm_cam_sensor.h b/include/media/msm_cam_sensor.h
index bce6af3..b71aa30 100644
--- a/include/media/msm_cam_sensor.h
+++ b/include/media/msm_cam_sensor.h
@@ -207,6 +207,7 @@
 	uint8_t settle_cnt;
 	uint16_t lane_mask;
 	uint8_t combo_mode;
+	uint8_t csid_core;
 };
 
 struct msm_camera_csi2_params {
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index afd5a42..b4b3bfc 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -1396,6 +1396,7 @@
 	uint8_t settle_cnt;
 	uint16_t lane_mask;
 	uint8_t combo_mode;
+	uint8_t csid_core;
 };
 
 struct msm_camera_csi2_params {
diff --git a/include/media/msmb_isp.h b/include/media/msmb_isp.h
index 6fb1a65..bf6b23b 100644
--- a/include/media/msmb_isp.h
+++ b/include/media/msmb_isp.h
@@ -168,12 +168,6 @@
 	enum msm_vfe_frame_skip_pattern skip_pattern;
 };
 
-enum msm_vfe_stats_pipeline_policy {
-	STATS_COMP_ALL,
-	STATS_COMP_NONE,
-	MAX_STATS_POLICY,
-};
-
 enum msm_isp_stats_type {
 	MSM_ISP_STATS_AEC,   /* legacy based AEC */
 	MSM_ISP_STATS_AF,    /* legacy based AF */
@@ -193,11 +187,11 @@
 	uint32_t session_id;
 	uint32_t stream_id;
 	enum msm_isp_stats_type stats_type;
+	uint32_t composite_flag;
 	uint32_t framedrop_pattern;
 	uint32_t irq_subsample_pattern;
 	uint32_t buffer_offset;
 	uint32_t stream_handle;
-	uint8_t comp_flag;
 };
 
 struct msm_vfe_stats_stream_release_cmd {
@@ -209,12 +203,6 @@
 	uint8_t enable;
 };
 
-struct msm_vfe_stats_comp_policy_cfg {
-	enum msm_vfe_stats_pipeline_policy stats_pipeline_policy;
-	uint32_t comp_framedrop_pattern;
-	uint32_t comp_irq_subsample_pattern;
-};
-
 enum msm_vfe_reg_cfg_type {
 	VFE_WRITE,
 	VFE_WRITE_MB,
@@ -319,7 +307,7 @@
 #define ISP_EVENT_EOF             (ISP_EVENT_BASE + ISP_EOF)
 #define ISP_EVENT_BUF_DIVERT      (ISP_BUF_EVENT_BASE)
 #define ISP_EVENT_STATS_NOTIFY    (ISP_STATS_EVENT_BASE)
-
+#define ISP_EVENT_COMP_STATS_NOTIFY (ISP_EVENT_STATS_NOTIFY + MSM_ISP_STATS_MAX)
 /* The msm_v4l2_event_data structure should match the
  * v4l2_event.u.data field.
  * should not exceed 64 bytes */
@@ -412,10 +400,6 @@
 	_IOWR('V', BASE_VIDIOC_PRIVATE+11, \
 	struct msm_vfe_stats_stream_release_cmd)
 
-#define VIDIOC_MSM_ISP_CFG_STATS_COMP_POLICY \
-	_IOWR('V', BASE_VIDIOC_PRIVATE+12,   \
-	      struct msm_vfe_stats_comp_policy_cfg)
-
 #define VIDIOC_MSM_ISP_UPDATE_STREAM \
 	_IOWR('V', BASE_VIDIOC_PRIVATE+13, struct msm_vfe_axi_stream_update_cmd)
 
diff --git a/kernel/pid.c b/kernel/pid.c
index 9f08dfa..7acf590 100644
--- a/kernel/pid.c
+++ b/kernel/pid.c
@@ -430,6 +430,7 @@
 {
 	return find_task_by_pid_ns(vnr, current->nsproxy->pid_ns);
 }
+EXPORT_SYMBOL_GPL(find_task_by_vpid);
 
 struct pid *get_task_pid(struct task_struct *task, enum pid_type type)
 {
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index a2bad88..862e172 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -4757,6 +4757,7 @@
 	delayacct_blkio_end();
 	return ret;
 }
+EXPORT_SYMBOL(io_schedule_timeout);
 
 /**
  * sys_sched_get_priority_max - return maximum RT priority.
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index b175073..7e31770 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -2126,11 +2126,11 @@
 static void hrtick_start_fair(struct rq *rq, struct task_struct *p)
 {
 	struct sched_entity *se = &p->se;
-	struct cfs_rq *cfs_rq = cfs_rq_of(se);
+	struct cfs_rq *cfs_rq = &rq->cfs;
 
 	WARN_ON(task_rq(p) != rq);
 
-	if (cfs_rq->nr_running > 1) {
+	if (cfs_rq->h_nr_running > 1) {
 		u64 slice = sched_slice(cfs_rq, se);
 		u64 ran = se->sum_exec_runtime - se->prev_sum_exec_runtime;
 		s64 delta = slice - ran;
@@ -2154,8 +2154,7 @@
 
 /*
  * called from enqueue/dequeue and updates the hrtick when the
- * current task is from our class and nr_running is low enough
- * to matter.
+ * current task is from our class.
  */
 static void hrtick_update(struct rq *rq)
 {
@@ -2164,8 +2163,7 @@
 	if (!hrtick_enabled(rq) || curr->sched_class != &fair_sched_class)
 		return;
 
-	if (cfs_rq_of(&curr->se)->nr_running < sched_nr_latency)
-		hrtick_start_fair(rq, curr);
+	hrtick_start_fair(rq, curr);
 }
 #else /* !CONFIG_SCHED_HRTICK */
 static inline void
@@ -4626,7 +4624,7 @@
 
 	raw_spin_lock(&this_rq->lock);
 
-	if (pulled_task || time_after(jiffies, this_rq->next_balance)) {
+	if (!pulled_task || time_after(jiffies, this_rq->next_balance)) {
 		/*
 		 * We are going idle. next_balance may be set based on
 		 * a busy processor. So reset next_balance.
diff --git a/scripts/build-all.py b/scripts/build-all.py
index 3cecbe2..4789af7 100755
--- a/scripts/build-all.py
+++ b/scripts/build-all.py
@@ -88,7 +88,6 @@
         r'[fm]sm[0-9]*_defconfig',
         r'apq*_defconfig',
         r'qsd*_defconfig',
-        r'msmzinc*_defconfig',
         )
     for p in arch_pats:
         for n in glob.glob('arch/arm/configs/' + p):
diff --git a/sound/soc/codecs/wcd9306.c b/sound/soc/codecs/wcd9306.c
index a7069a6..67674f3 100644
--- a/sound/soc/codecs/wcd9306.c
+++ b/sound/soc/codecs/wcd9306.c
@@ -4371,6 +4371,12 @@
 	return ret;
 }
 
+static void tapan_cleanup_irqs(struct tapan_priv *tapan)
+{
+	struct snd_soc_codec *codec = tapan->codec;
+	wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS, tapan);
+}
+
 int tapan_hs_detect(struct snd_soc_codec *codec,
 		    struct wcd9xxx_mbhc_config *mbhc_cfg)
 {
@@ -4512,6 +4518,10 @@
 	mutex_unlock(&dapm->codec->mutex);
 
 	codec->ignore_pmdown_time = 1;
+
+	if (ret)
+		tapan_cleanup_irqs(tapan);
+
 	return ret;
 
 err_pdata:
@@ -4532,6 +4542,9 @@
 		wcd9xxx_resmgr_put_bandgap(&tapan->resmgr,
 					   WCD9XXX_BANDGAP_AUDIO_MODE);
 	WCD9XXX_BCL_UNLOCK(&tapan->resmgr);
+
+	tapan_cleanup_irqs(tapan);
+
 	/* cleanup MBHC */
 	wcd9xxx_mbhc_deinit(&tapan->mbhc);
 	/* cleanup resmgr */
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 7ba43c0..43a1042 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -5841,28 +5841,39 @@
 				taiko_codec_reg_init_val[i].val);
 }
 
-static int taiko_setup_irqs(struct taiko_priv *taiko)
+static void taiko_slim_interface_init_reg(struct snd_soc_codec *codec)
 {
 	int i;
-	int ret = 0;
-	struct snd_soc_codec *codec = taiko->codec;
-
-	ret = wcd9xxx_request_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS,
-				  taiko_slimbus_irq, "SLIMBUS Slave", taiko);
-	if (ret) {
-		pr_err("%s: Failed to request irq %d\n", __func__,
-		       WCD9XXX_IRQ_SLIMBUS);
-		goto exit;
-	}
 
 	for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++)
 		wcd9xxx_interface_reg_write(codec->control_data,
 					    TAIKO_SLIM_PGD_PORT_INT_EN0 + i,
 					    0xFF);
-exit:
+}
+
+static int taiko_setup_irqs(struct taiko_priv *taiko)
+{
+	int ret = 0;
+	struct snd_soc_codec *codec = taiko->codec;
+
+	ret = wcd9xxx_request_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS,
+				  taiko_slimbus_irq, "SLIMBUS Slave", taiko);
+	if (ret)
+		pr_err("%s: Failed to request irq %d\n", __func__,
+		       WCD9XXX_IRQ_SLIMBUS);
+	else
+		taiko_slim_interface_init_reg(codec);
+
 	return ret;
 }
 
+static void taiko_cleanup_irqs(struct taiko_priv *taiko)
+{
+	struct snd_soc_codec *codec = taiko->codec;
+
+	wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS, taiko);
+}
+
 int taiko_hs_detect(struct snd_soc_codec *codec,
 		    struct wcd9xxx_mbhc_config *mbhc_cfg)
 {
@@ -5921,6 +5932,7 @@
 		pr_err("%s: bad pdata\n", __func__);
 
 	taiko_init_slim_slave_cfg(codec);
+	taiko_slim_interface_init_reg(codec);
 
 	wcd9xxx_mbhc_deinit(&taiko->mbhc);
 	ret = wcd9xxx_mbhc_init(&taiko->mbhc, &taiko->resmgr, codec,
@@ -6063,10 +6075,8 @@
 			tx_hpf_corner_freq_callback);
 	}
 
-
 	snd_soc_codec_set_drvdata(codec, taiko);
 
-
 	/* codec resmgr module init */
 	wcd9xxx = codec->control_data;
 	pdata = dev_get_platdata(codec->dev->parent);
@@ -6074,7 +6084,7 @@
 				  &taiko_reg_address);
 	if (ret) {
 		pr_err("%s: wcd9xxx init failed %d\n", __func__, ret);
-		return ret;
+		goto err_init;
 	}
 
 	taiko->clsh_d.buck_mv = taiko_codec_get_buck_mv(codec);
@@ -6085,7 +6095,7 @@
 				WCD9XXX_MBHC_VERSION_TAIKO);
 	if (ret) {
 		pr_err("%s: mbhc init failed %d\n", __func__, ret);
-		return ret;
+		goto err_init;
 	}
 
 	taiko->codec = codec;
@@ -6179,7 +6189,11 @@
 
 	snd_soc_dapm_sync(dapm);
 
-	(void) taiko_setup_irqs(taiko);
+	ret = taiko_setup_irqs(taiko);
+	if (ret) {
+		pr_err("%s: taiko irq setup failed %d\n", __func__, ret);
+		goto err_irq;
+	}
 
 	atomic_set(&kp_taiko_priv, (unsigned long)taiko);
 	mutex_lock(&dapm->codec->mutex);
@@ -6194,10 +6208,13 @@
 	codec->ignore_pmdown_time = 1;
 	return ret;
 
+err_irq:
+	taiko_cleanup_irqs(taiko);
 err_pdata:
 	kfree(ptr);
 err_nomem_slimch:
 	kfree(taiko);
+err_init:
 	return ret;
 }
 static int taiko_codec_remove(struct snd_soc_codec *codec)
@@ -6212,6 +6229,8 @@
 					   WCD9XXX_BANDGAP_AUDIO_MODE);
 	WCD9XXX_BCL_UNLOCK(&taiko->resmgr);
 
+	taiko_cleanup_irqs(taiko);
+
 	/* cleanup MBHC */
 	wcd9xxx_mbhc_deinit(&taiko->mbhc);
 	/* cleanup resmgr */
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index 1d01d2e..daba6d5 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -3534,7 +3534,6 @@
 {
 	void *cdata = mbhc->codec->control_data;
 
-	wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_SLIMBUS, mbhc);
 	wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_MBHC_RELEASE, mbhc);
 	wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_MBHC_POTENTIAL, mbhc);
 	wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_MBHC_REMOVAL, mbhc);
@@ -3543,7 +3542,6 @@
 	wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_MBHC_JACK_SWITCH, mbhc);
 	wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT, mbhc);
 	wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT, mbhc);
-	wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_MBHC_RELEASE, mbhc);
 
 	if (mbhc->mbhc_fw)
 		release_firmware(mbhc->mbhc_fw);
diff --git a/sound/soc/msm/qdsp6v2/audio_ocmem.c b/sound/soc/msm/qdsp6v2/audio_ocmem.c
index ad96ae3..08d7277 100644
--- a/sound/soc/msm/qdsp6v2/audio_ocmem.c
+++ b/sound/soc/msm/qdsp6v2/audio_ocmem.c
@@ -125,7 +125,7 @@
 	atomic_t  audio_cond;
 	atomic_t  audio_exit;
 	spinlock_t audio_lock;
-	struct mutex protect_lock;
+	struct mutex state_process_lock;
 	struct workqueue_struct *audio_ocmem_workqueue;
 	struct workqueue_struct *voice_ocmem_workqueue;
 	bool ocmem_en;
@@ -252,6 +252,7 @@
 		if (ret != 0) {
 			pr_err("%s: get low power segments from DSP failed, rc=%d\n",
 					__func__, ret);
+			mutex_unlock(&audio_ocmem_lcl.state_process_lock);
 			goto fail_cmd;
 		}
 	}
@@ -273,7 +274,9 @@
 	buf = ocmem_allocate_nb(cid, AUDIO_OCMEM_BUF_SIZE);
 	if (IS_ERR_OR_NULL(buf)) {
 		pr_err("%s: failed: %d\n", __func__, cid);
-		return -ENOMEM;
+		ret = -ENOMEM;
+		mutex_unlock(&audio_ocmem_lcl.state_process_lock);
+		goto fail_cmd;
 	}
 
 	set_bit_pos(audio_ocmem_lcl.audio_state, OCMEM_STATE_ALLOC);
@@ -285,7 +288,7 @@
 	if (!buf->len) {
 		pr_debug("%s: buf.len is 0, waiting for ocmem region\n",
 								__func__);
-		mutex_unlock(&audio_ocmem_lcl.protect_lock);
+		mutex_unlock(&audio_ocmem_lcl.state_process_lock);
 		wait_event_interruptible(audio_ocmem_lcl.audio_wait,
 			(atomic_read(&audio_ocmem_lcl.audio_cond) == 0)	||
 			(atomic_read(&audio_ocmem_lcl.audio_exit) == 1));
@@ -302,7 +305,7 @@
 			goto fail_cmd;
 		}
 		clear_bit_pos(audio_ocmem_lcl.audio_state, OCMEM_STATE_GROW);
-		mutex_trylock(&audio_ocmem_lcl.protect_lock);
+		mutex_trylock(&audio_ocmem_lcl.state_process_lock);
 	}
 	pr_debug("%s: buf->len: %ld\n", __func__, (audio_ocmem_lcl.buf)->len);
 
@@ -333,7 +336,7 @@
 					_MAP_RESPONSE_BIT_MASK_) != 0);
 	atomic_set(&audio_ocmem_lcl.audio_cond, 1);
 
-	mutex_unlock(&audio_ocmem_lcl.protect_lock);
+	mutex_unlock(&audio_ocmem_lcl.state_process_lock);
 	pr_debug("%s: audio_cond[%d] audio_state[0x%x]\n", __func__,
 				atomic_read(&audio_ocmem_lcl.audio_cond),
 				atomic_read(&audio_ocmem_lcl.audio_state));
@@ -344,7 +347,7 @@
 		wait_event_interruptible(audio_ocmem_lcl.audio_wait,
 				(atomic_read(&audio_ocmem_lcl.audio_state) &
 						_BIT_MASK_) != 0);
-
+		mutex_lock(&audio_ocmem_lcl.state_process_lock);
 		state_bit = get_state_to_process(&audio_ocmem_lcl.audio_state);
 		switch (state_bit) {
 		case OCMEM_STATE_MAP_COMPL:
@@ -502,6 +505,7 @@
 				atomic_read(&audio_ocmem_lcl.audio_state));
 			break;
 		}
+		mutex_unlock(&audio_ocmem_lcl.state_process_lock);
 	}
 	ret = 0;
 fail_cmd:
@@ -531,7 +535,7 @@
 
 	wake_up(&audio_ocmem_lcl.audio_wait);
 
-	mutex_unlock(&audio_ocmem_lcl.protect_lock);
+	mutex_unlock(&audio_ocmem_lcl.state_process_lock);
 	pr_debug("%s: exit\n", __func__);
 	return 0;
 }
@@ -654,7 +658,7 @@
 			container_of(work, struct audio_ocmem_workdata, work);
 
 	en = audio_ocm_work->en;
-	mutex_lock(&audio_ocmem_lcl.protect_lock);
+	mutex_lock(&audio_ocmem_lcl.state_process_lock);
 	/* if previous work waiting for ocmem - signal it to exit */
 	atomic_set(&audio_ocmem_lcl.audio_exit, 1);
 	pr_debug("%s: acquired mutex for %d\n", __func__, en);
@@ -889,7 +893,7 @@
 	atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_DEFAULT);
 	atomic_set(&audio_ocmem_lcl.audio_exit, 0);
 	spin_lock_init(&audio_ocmem_lcl.audio_lock);
-	mutex_init(&audio_ocmem_lcl.protect_lock);
+	mutex_init(&audio_ocmem_lcl.state_process_lock);
 	audio_ocmem_lcl.ocmem_en = true;
 	audio_ocmem_lcl.audio_ocmem_running = false;
 
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
index a163f6a..27b3f56 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
@@ -33,6 +33,7 @@
 #include <sound/compress_offload.h>
 #include <sound/compress_driver.h>
 #include <sound/timer.h>
+#include <sound/pcm_params.h>
 
 #include "msm-pcm-q6-v2.h"
 #include "msm-pcm-routing-v2.h"
@@ -55,9 +56,10 @@
 				SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
 	.formats =              SNDRV_PCM_FMTBIT_S16_LE |
 					SNDRV_PCM_FMTBIT_S24_LE,
-	.rates =                SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT,
+	.rates =                SNDRV_PCM_RATE_8000_192000 |
+					SNDRV_PCM_RATE_KNOT,
 	.rate_min =             8000,
-	.rate_max =             48000,
+	.rate_max =             192000,
 	.channels_min =         1,
 	.channels_max =         2,
 	.buffer_bytes_max =     1024 * 1024,
@@ -70,7 +72,8 @@
 
 /* Conventional and unconventional sample rate supported */
 static unsigned int supported_sample_rates[] = {
-	8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+	8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000,
+	96000, 192000
 };
 
 static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
@@ -277,19 +280,7 @@
 static int msm_pcm_open(struct snd_pcm_substream *substream)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
 	struct msm_audio *prtd;
-	struct asm_softpause_params softpause = {
-		.enable = SOFT_PAUSE_ENABLE,
-		.period = SOFT_PAUSE_PERIOD,
-		.step = SOFT_PAUSE_STEP,
-		.rampingcurve = SOFT_PAUSE_CURVE_LINEAR,
-	};
-	struct asm_softvolume_params softvol = {
-		.period = SOFT_VOLUME_PERIOD,
-		.step = SOFT_VOLUME_STEP,
-		.rampingcurve = SOFT_VOLUME_CURVE_LINEAR,
-	};
 	int ret = 0;
 
 	pr_debug("%s\n", __func__);
@@ -307,31 +298,9 @@
 		kfree(prtd);
 		return -ENOMEM;
 	}
-	prtd->audio_client->perf_mode = false;
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		ret = q6asm_open_write(prtd->audio_client, FORMAT_LINEAR_PCM);
-		if (ret < 0) {
-			pr_err("%s: pcm out open failed\n", __func__);
-			q6asm_audio_client_free(prtd->audio_client);
-			kfree(prtd);
-			return -ENOMEM;
-		}
-		ret = q6asm_set_io_mode(prtd->audio_client, ASYNC_IO_MODE);
-		if (ret < 0) {
-			pr_err("%s: Set IO mode failed\n", __func__);
-			q6asm_audio_client_free(prtd->audio_client);
-			kfree(prtd);
-			return -ENOMEM;
-		}
-	}
 	/* Capture path */
 	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
 		return -EPERM;
-	pr_debug("%s: session ID %d\n", __func__, prtd->audio_client->session);
-	prtd->session_id = prtd->audio_client->session;
-	msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
-		prtd->audio_client->perf_mode,
-		prtd->session_id, substream->stream);
 
 	ret = snd_pcm_hw_constraint_list(runtime, 0,
 				SNDRV_PCM_HW_PARAM_RATE,
@@ -350,15 +319,6 @@
 	atomic_set(&lpa_audio.audio_ocmem_req, 0);
 	runtime->private_data = prtd;
 	lpa_audio.prtd = prtd;
-	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",
-			__func__, ret);
-	ret = q6asm_set_softvolume(lpa_audio.prtd->audio_client, &softvol);
-	if (ret < 0)
-		pr_err("%s: Send SoftVolume Param failed ret=%d\n",
-			__func__, ret);
 
 	return 0;
 }
@@ -407,22 +367,24 @@
 		prtd->pcm_irq_pos = 0;
 	}
 
-	dir = IN;
-	atomic_set(&prtd->pending_buffer, 0);
+	if (prtd->audio_client) {
+		dir = IN;
+		atomic_set(&prtd->pending_buffer, 0);
 
-	if (atomic_cmpxchg(&lpa_audio.audio_ocmem_req, 1, 0))
-		audio_ocmem_process_req(AUDIO, false);
-	lpa_audio.prtd = NULL;
-	q6asm_cmd(prtd->audio_client, CMD_CLOSE);
-	q6asm_audio_client_buf_free_contiguous(dir,
+		if (atomic_cmpxchg(&lpa_audio.audio_ocmem_req, 1, 0))
+			audio_ocmem_process_req(AUDIO, false);
+		lpa_audio.prtd = NULL;
+		q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+		q6asm_audio_client_buf_free_contiguous(dir,
 				prtd->audio_client);
 
-	atomic_set(&prtd->stop, 1);
-	pr_debug("%s\n", __func__);
+		atomic_set(&prtd->stop, 1);
+		q6asm_audio_client_free(prtd->audio_client);
+		pr_debug("%s\n", __func__);
+	}
 	msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
 		SNDRV_PCM_STREAM_PLAYBACK);
 	pr_debug("%s\n", __func__);
-	q6asm_audio_client_free(prtd->audio_client);
 	kfree(prtd);
 
 	return 0;
@@ -484,9 +446,59 @@
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct msm_audio *prtd = runtime->private_data;
+	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
 	struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
 	struct audio_buffer *buf;
+	uint16_t bits_per_sample = 16;
 	int dir, ret;
+	struct asm_softpause_params softpause = {
+		.enable = SOFT_PAUSE_ENABLE,
+		.period = SOFT_PAUSE_PERIOD,
+		.step = SOFT_PAUSE_STEP,
+		.rampingcurve = SOFT_PAUSE_CURVE_LINEAR,
+	};
+	struct asm_softvolume_params softvol = {
+		.period = SOFT_VOLUME_PERIOD,
+		.step = SOFT_VOLUME_STEP,
+		.rampingcurve = SOFT_VOLUME_CURVE_LINEAR,
+	};
+
+	prtd->audio_client->perf_mode = false;
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		if (params_format(params) == SNDRV_PCM_FORMAT_S24_LE)
+			bits_per_sample = 24;
+		ret = q6asm_open_write_v2(prtd->audio_client,
+				FORMAT_LINEAR_PCM, bits_per_sample);
+		if (ret < 0) {
+			pr_err("%s: pcm out open failed\n", __func__);
+			q6asm_audio_client_free(prtd->audio_client);
+			prtd->audio_client = NULL;
+			return -ENOMEM;
+		}
+		ret = q6asm_set_io_mode(prtd->audio_client, ASYNC_IO_MODE);
+		if (ret < 0) {
+			pr_err("%s: Set IO mode failed\n", __func__);
+			q6asm_audio_client_free(prtd->audio_client);
+			prtd->audio_client = NULL;
+			return -ENOMEM;
+		}
+	}
+
+	pr_debug("%s: session ID %d\n", __func__, prtd->audio_client->session);
+	prtd->session_id = prtd->audio_client->session;
+	msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
+		prtd->audio_client->perf_mode,
+		prtd->session_id, substream->stream);
+
+	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",
+			__func__, ret);
+	ret = q6asm_set_softvolume(lpa_audio.prtd->audio_client, &softvol);
+	if (ret < 0)
+		pr_err("%s: Send SoftVolume Param failed ret=%d\n",
+			__func__, ret);
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		dir = IN;
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 8257023..c651ec7 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -30,11 +30,11 @@
 #include <sound/tlv.h>
 #include <sound/asound.h>
 #include <sound/pcm_params.h>
-#include <mach/qdsp6v2/q6core.h>
 
 #include "msm-pcm-routing-v2.h"
 #include "msm-dolby-dap-config.h"
 #include "q6voice.h"
+#include "q6core.h"
 
 struct msm_pcm_routing_bdai_data {
 	u16 port_id; /* AFE port ID */
@@ -1618,6 +1618,12 @@
 	msm_routing_put_audio_mixer),
 };
 
+static const struct snd_kcontrol_new mmul4_mixer_controls[] = {
+	SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+};
+
 static const struct snd_kcontrol_new mmul5_mixer_controls[] = {
 	SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
@@ -2472,6 +2478,7 @@
 	SND_SOC_DAPM_AIF_IN("VOIP_DL", "VoIP Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("MM_UL1", "MultiMedia1 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("MM_UL2", "MultiMedia2 Capture", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("MM_UL4", "MultiMedia4 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("MM_UL5", "MultiMedia5 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("CS-VOICE_DL1", "CS-VOICE Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("CS-VOICE_UL1", "CS-VOICE Capture", 0, 0, 0, 0),
@@ -2621,6 +2628,8 @@
 	mmul1_mixer_controls, ARRAY_SIZE(mmul1_mixer_controls)),
 	SND_SOC_DAPM_MIXER("MultiMedia2 Mixer", SND_SOC_NOPM, 0, 0,
 	mmul2_mixer_controls, ARRAY_SIZE(mmul2_mixer_controls)),
+	SND_SOC_DAPM_MIXER("MultiMedia4 Mixer", SND_SOC_NOPM, 0, 0,
+	mmul4_mixer_controls, ARRAY_SIZE(mmul4_mixer_controls)),
 	SND_SOC_DAPM_MIXER("MultiMedia5 Mixer", SND_SOC_NOPM, 0, 0,
 	mmul5_mixer_controls, ARRAY_SIZE(mmul5_mixer_controls)),
 	SND_SOC_DAPM_MIXER("AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
@@ -2777,6 +2786,7 @@
 	{"MultiMedia1 Mixer", "VOC_REC_UL", "INCALL_RECORD_TX"},
 	{"MultiMedia1 Mixer", "VOC_REC_DL", "INCALL_RECORD_RX"},
 	{"MultiMedia1 Mixer", "SLIM_4_TX", "SLIMBUS_4_TX"},
+	{"MultiMedia4 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
 	{"MultiMedia5 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
 	{"MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
 	{"MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
@@ -2847,6 +2857,7 @@
 	{"MM_UL1", NULL, "MultiMedia1 Mixer"},
 	{"MultiMedia2 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
 	{"MM_UL2", NULL, "MultiMedia2 Mixer"},
+	{"MM_UL4", NULL, "MultiMedia4 Mixer"},
 	{"MM_UL5", NULL, "MultiMedia5 Mixer"},
 
 	{"AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 63af271..2b0d155 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -80,6 +80,8 @@
 
 static int32_t afe_callback(struct apr_client_data *data, void *priv)
 {
+	int i;
+
 	if (!data) {
 		pr_err("%s: Invalid param data\n", __func__);
 		return -EINVAL;
@@ -87,6 +89,12 @@
 	if (data->opcode == RESET_EVENTS) {
 		pr_debug("q6afe: reset event = %d %d apr[%p]\n",
 			data->reset_event, data->reset_proc, this_afe.apr);
+
+		for (i = 0; i < MAX_AUDPROC_TYPES; i++) {
+			this_afe.afe_cal_addr[i].cal_paddr = 0;
+			this_afe.afe_cal_addr[i].cal_size = 0;
+		}
+
 		if (this_afe.apr) {
 			apr_reset(this_afe.apr);
 			atomic_set(&this_afe.state, 0);
diff --git a/sound/soc/msm/qdsp6v2/q6core.c b/sound/soc/msm/qdsp6v2/q6core.c
index 557b326..42cbcd1 100644
--- a/sound/soc/msm/qdsp6v2/q6core.c
+++ b/sound/soc/msm/qdsp6v2/q6core.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
@@ -32,7 +32,7 @@
 	struct avcs_cmd_rsp_get_low_power_segments_info_t *lp_ocm_payload;
 };
 
-struct q6core_str q6core_lcl;
+static struct q6core_str q6core_lcl;
 
 static int32_t aprv2_core_fn_q(struct apr_client_data *data, void *priv)
 {
@@ -40,7 +40,7 @@
 	uint32_t nseg;
 	int i, j;
 
-	pr_info("core msg: payload len = %u, apr resp opcode = 0x%X\n",
+	pr_debug("core msg: payload len = %u, apr resp opcode = 0x%X\n",
 		data->payload_size, data->opcode);
 
 	switch (data->opcode) {
@@ -121,6 +121,33 @@
 		pr_err("%s: Unable to register CORE\n", __func__);
 }
 
+uint32_t core_set_dolby_manufacturer_id(int manufacturer_id)
+{
+	struct adsp_dolby_manufacturer_id payload;
+	int rc = 0;
+	pr_debug("%s manufacturer_id :%d\n", __func__, manufacturer_id);
+	ocm_core_open();
+	if (q6core_lcl.core_handle_q) {
+		payload.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_EVENT,
+			APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+		payload.hdr.pkt_size =
+			sizeof(struct adsp_dolby_manufacturer_id);
+		payload.hdr.src_port = 0;
+		payload.hdr.dest_port = 0;
+		payload.hdr.token = 0;
+		payload.hdr.opcode = ADSP_CMD_SET_DOLBY_MANUFACTURER_ID;
+		payload.manufacturer_id = manufacturer_id;
+		pr_debug("Send Dolby security opcode=%x manufacturer ID = %d\n",
+			payload.hdr.opcode, payload.manufacturer_id);
+		rc = apr_send_pkt(q6core_lcl.core_handle_q,
+						(uint32_t *)&payload);
+		if (rc < 0)
+			pr_err("%s: SET_DOLBY_MANUFACTURER_ID failed op[0x%x]rc[%d]\n",
+				__func__, payload.hdr.opcode, rc);
+	}
+	return rc;
+}
+
 int core_get_low_power_segments(
 		struct avcs_cmd_rsp_get_low_power_segments_info_t **lp_memseg)
 {
diff --git a/sound/soc/msm/qdsp6v2/q6core.h b/sound/soc/msm/qdsp6v2/q6core.h
index ff611d5..39bf4ab 100644
--- a/sound/soc/msm/qdsp6v2/q6core.h
+++ b/sound/soc/msm/qdsp6v2/q6core.h
@@ -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
@@ -90,4 +90,13 @@
 int core_get_low_power_segments(
 			struct avcs_cmd_rsp_get_low_power_segments_info_t **);
 
+#define ADSP_CMD_SET_DOLBY_MANUFACTURER_ID 0x00012918
+
+struct adsp_dolby_manufacturer_id {
+	struct apr_hdr hdr;
+	int manufacturer_id;
+};
+
+uint32_t core_set_dolby_manufacturer_id(int manufacturer_id);
+
 #endif /* __Q6CORE_H__ */
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 40595bf..519f325 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -1767,7 +1767,12 @@
 		    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
 			(be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
 		    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED) &&
-		    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
+		    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
+		    !((be->dpcm[stream].state == SND_SOC_DPCM_STATE_START) &&
+		      ((fe->dpcm[stream].state != SND_SOC_DPCM_STATE_START) &&
+			(fe->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED) &&
+			(fe->dpcm[stream].state !=
+						SND_SOC_DPCM_STATE_SUSPEND))))
 			continue;
 
 		dev_dbg(be->dev, "dpcm: hw_free BE %s\n",