Merge "diag: Defer usb connect/disconnect processing"
diff --git a/Documentation/devicetree/bindings/fb/mdss-mdp.txt b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
index 0422b57..bb19768 100644
--- a/Documentation/devicetree/bindings/fb/mdss-mdp.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
@@ -108,7 +108,10 @@
 - qcom,mdss-rot-block-size:	The size of a memory block (in pixels) to be used
 				by the rotator. If this property is not specified,
 				then a default value of 128 pixels would be used.
-
+- qcom,mdss-has-bwc: Boolean property to indicate the presence of bandwidth
+		      compression feature in the rotator.
+- qcom,mdss-has-decimation: Boolean property to indicate the presence of
+			    decimation feature in fetch.
 Optional subnodes:
 Child nodes representing the frame buffer virtual devices.
 
@@ -141,6 +144,8 @@
 		qcom,mdss-pipe-dma-fetch-id = <10 13>;
 		qcom,mdss-smp-data = <22 4096>;
 		qcom,mdss-rot-block-size = <64>;
+		qcom,mdss-has-bwc;
+		qcom,mdss-has-decimation;
 
 		qcom,mdss-ctl-off = <0x00000600 0x00000700 0x00000800
 				     0x00000900 0x0000A00>;
diff --git a/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt b/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt
index fbe8ffa..418447d 100644
--- a/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt
+++ b/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt
@@ -16,7 +16,10 @@
 - interrupt-names : Should contain "eoc-int-en-set".
 - qcom,adc-bit-resolution : Bit resolution of the ADC.
 - qcom,adc-vdd-reference : Voltage reference used by the ADC.
-- qcom,rsense : Internal rsense resistor used for current measurements.
+
+Optional properties:
+- qcom,rsense : Use this property when external rsense should be used
+		for current calculation and specify the units in nano-ohms.
 
 Channel node
 NOTE: Atleast one Channel node is required.
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 70f8b55..ac8ea73 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt
@@ -14,6 +14,8 @@
 - interrupts:         The lpass watchdog interrupt
 - vdd_cx-supply:      Reference to the regulator that supplies the vdd_cx domain.
 - 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.
 
 Optional properties:
 - vdd_pll-supply:     Reference to the regulator that supplies the PLL's rail.
@@ -29,4 +31,10 @@
 		interrupts = <0 194 1>;
 		vdd_cx-supply = <&pm8841_s2>;
 	        qcom,firmware-name = "lpass";
+
+		/* GPIO input from lpass */
+		qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_2_in 0 0>;
+
+		/* GPIO output to lpass */
+		qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_2_out 0 0>;
 	};
diff --git a/Documentation/devicetree/bindings/regulator/krait-regulator.txt b/Documentation/devicetree/bindings/regulator/krait-regulator.txt
index 6a02e86..aaa731e 100644
--- a/Documentation/devicetree/bindings/regulator/krait-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/krait-regulator.txt
@@ -13,8 +13,6 @@
 				register base
 - reg-names:			"apcs_gcc" -string to identify the area where
 				the APCS GCC registers reside.
-- qcom,pfm-threshold		The power coeff threshold in abstract power units below which
-				pmic will be made to operate in PFM mode.
 
 Optional properties:
 - qcom,use-phase-switching	indicates whether the driver should add/shed phases on the PMIC
@@ -53,7 +51,6 @@
 		reg-names = "apcs_gcc";
 		compatible = "qcom,krait-pdn";
 		qcom,use-phase-switching;
-		qcom,pfm-threshold = <376975>;
 		#address-cells = <1>;
 		#size-cells = <1>;
 		ranges;
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/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt
index fd5b93e..6d54f7e 100644
--- a/Documentation/devicetree/bindings/usb/dwc3.txt
+++ b/Documentation/devicetree/bindings/usb/dwc3.txt
@@ -12,6 +12,7 @@
 
 Optional properties:
  - tx-fifo-resize: determines if the FIFO *has* to be reallocated.
+ - host-only-mode: if present then dwc3 should be run in HOST only mode.
 
 This is usually a subnode to DWC3 glue to which it is connected.
 
diff --git a/arch/arm/boot/dts/msm-pm8110-rpm-regulator.dtsi b/arch/arm/boot/dts/msm-pm8110-rpm-regulator.dtsi
new file mode 100644
index 0000000..0de72b0
--- /dev/null
+++ b/arch/arm/boot/dts/msm-pm8110-rpm-regulator.dtsi
@@ -0,0 +1,381 @@
+/* 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.
+ */
+
+&rpm_bus {
+	rpm-regulator-smpa1 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "smpa";
+		qcom,resource-id = <1>;
+		qcom,regulator-type = <1>;
+		qcom,hpm-min-load = <100000>;
+		status = "disabled";
+
+		regulator-s1 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8110_s1";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-smpa3 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "smpa";
+		qcom,resource-id = <3>;
+		qcom,regulator-type = <1>;
+		qcom,hpm-min-load = <100000>;
+		status = "disabled";
+
+		regulator-s3 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8110_s3";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-smpa4 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "smpa";
+		qcom,resource-id = <4>;
+		qcom,regulator-type = <1>;
+		qcom,hpm-min-load = <100000>;
+		status = "disabled";
+
+		regulator-s4 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8110_s4";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa1 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <1>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l1 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8110_l1";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa2 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <2>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l2 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8110_l2";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa3 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <3>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l3 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8110_l3";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa4 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <4>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l4 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8110_l4";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa5 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <5>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l5 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8110_l5";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa6 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <6>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l6 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8110_l6";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa7 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <7>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l7 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8110_l7";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa8 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <8>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <5000>;
+		status = "disabled";
+
+		regulator-l8 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8110_l8";
+			qcom,set = <1>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa9 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <9>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l9 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8110_l9";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa10 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <10>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l10 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8110_l10";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa12 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <12>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l12 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8110_l12";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa14 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <14>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l14 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8110_l14";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa15 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <15>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l15 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8110_l15";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa16 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <16>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l16 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8110_l16";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa17 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <17>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l17 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8110_l17";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa18 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <18>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l18 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8110_l18";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa19 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <19>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l19 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8110_l19";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa20 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <20>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <5000>;
+		status = "disabled";
+
+		regulator-l20 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8110_l20";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa21 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <21>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l21 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8110_l21";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa22 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <22>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l22 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8110_l22";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/msm-pm8110.dtsi b/arch/arm/boot/dts/msm-pm8110.dtsi
index 28766cf..fe4cada 100644
--- a/arch/arm/boot/dts/msm-pm8110.dtsi
+++ b/arch/arm/boot/dts/msm-pm8110.dtsi
@@ -22,6 +22,98 @@
 		#address-cells = <1>;
 		#size-cells = <1>;
 
+		pm8110_chg: qcom,charger {
+			spmi-dev-container;
+			compatible = "qcom,qpnp-charger";
+			#address-cells = <1>;
+			#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,chg-chgr@1000 {
+				status = "disabled";
+				reg = <0x1000 0x100>;
+				interrupts =	<0x0 0x10 0x0>,
+						<0x0 0x10 0x1>,
+						<0x0 0x10 0x2>,
+						<0x0 0x10 0x3>,
+						<0x0 0x10 0x4>,
+						<0x0 0x10 0x5>,
+						<0x0 0x10 0x6>,
+						<0x0 0x10 0x7>;
+
+				interrupt-names =	"vbat-det-lo",
+							"vbat-det-hi",
+							"chgwdog",
+							"state-change",
+							"trkl-chg-on",
+							"fast-chg-on",
+							"chg-failed",
+							"chg-done";
+			};
+
+			qcom,chg-buck@1100 {
+				status = "disabled";
+				reg = <0x1100 0x100>;
+				interrupts =	<0x0 0x11 0x0>,
+						<0x0 0x11 0x1>,
+						<0x0 0x11 0x2>,
+						<0x0 0x11 0x3>,
+						<0x0 0x11 0x4>,
+						<0x0 0x11 0x5>,
+						<0x0 0x11 0x6>;
+
+				interrupt-names =	"vbat-ov",
+							"vreg-ov",
+							"overtemp",
+							"vchg-loop",
+							"ichg-loop",
+							"ibat-loop",
+							"vdd-loop";
+			};
+
+			qcom,chg-bat-if@1200 {
+				status = "disabled";
+				reg = <0x1200 0x100>;
+				interrupts =	<0x0 0x12 0x0>,
+						<0x0 0x12 0x1>,
+						<0x0 0x12 0x2>,
+						<0x0 0x12 0x3>,
+						<0x0 0x12 0x4>;
+
+				interrupt-names =	"batt-pres",
+							"bat-temp-ok",
+							"bat-fet-on",
+							"vcp-on",
+							"psi";
+			};
+
+			qcom,chg-usb-chgpth@1300 {
+				status = "disabled";
+				reg = <0x1300 0x100>;
+				interrupts =	<0 0x13 0x0>,
+						<0 0x13 0x1>,
+						<0x0 0x13 0x2>;
+
+				interrupt-names =	"coarse-det-usb",
+							"usbin-valid",
+							"chg-gone";
+			};
+
+			qcom,chg-misc@1600 {
+				status = "disabled";
+				reg = <0x1600 0x100>;
+			};
+		};
+
 		pm8110_vadc: vadc@3100 {
 			compatible = "qcom,qpnp-vadc";
 			reg = <0x3100 0x100>;
@@ -75,7 +167,6 @@
 			interrupt-names = "eoc-int-en-set";
 			qcom,adc-bit-resolution = <16>;
 			qcom,adc-vdd-reference = <1800>;
-			qcom,rsense = <1500>;
 
 			chan@0 {
 				label = "internal_rsense";
@@ -106,6 +197,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/msm-pm8226.dtsi b/arch/arm/boot/dts/msm-pm8226.dtsi
index 12641c5..99410b3 100644
--- a/arch/arm/boot/dts/msm-pm8226.dtsi
+++ b/arch/arm/boot/dts/msm-pm8226.dtsi
@@ -368,7 +368,6 @@
 			interrupt-names = "eoc-int-en-set";
 			qcom,adc-bit-resolution = <16>;
 			qcom,adc-vdd-reference = <1800>;
-			qcom,rsense = <1500>;
 
 			chan@0 {
 				label = "internal_rsense";
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index 776b9d6..43b7d03 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -791,7 +791,6 @@
 			interrupt-names = "eoc-int-en-set";
 			qcom,adc-bit-resolution = <16>;
 			qcom,adc-vdd-reference = <1800>;
-			qcom,rsense = <1500>;
 
 			chan@0 {
 				label = "internal_rsense";
diff --git a/arch/arm/boot/dts/msm8226-cdp.dts b/arch/arm/boot/dts/msm8226-cdp.dts
index 5f0dcc3..19d451b 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>;
@@ -266,7 +266,7 @@
 		qcom,mode = <1>;		/* Digital output */
 		qcom,output-type = <0>;	/* CMOS logic */
 		qcom,pull = <5>;		/* QPNP_PIN_PULL_NO*/
-		qcom,vin-sel = <2>;		/* QPNP_PIN_VIN2 */
+		qcom,vin-sel = <3>;		/* QPNP_PIN_VIN3 */
 		qcom,out-strength = <3>;/* QPNP_PIN_OUT_STRENGTH_HIGH */
 		qcom,src-sel = <2>;		/* QPNP_PIN_SEL_FUNC_1 */
 		qcom,master-en = <1>;	/* Enable GPIO */
@@ -276,7 +276,7 @@
 		qcom,mode = <1>;
 		qcom,output-type = <0>;
 		qcom,pull = <5>;
-		qcom,vin-sel = <2>;
+		qcom,vin-sel = <3>;
 		qcom,out-strength = <3>;
 		qcom,src-sel = <2>;
 		qcom,master-en = <1>;
diff --git a/arch/arm/boot/dts/msm8226-mtp.dts b/arch/arm/boot/dts/msm8226-mtp.dts
index 59741c6..156c72d 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>;
@@ -259,7 +259,7 @@
 		qcom,mode = <1>;		/* Digital output */
 		qcom,output-type = <0>;	/* CMOS logic */
 		qcom,pull = <5>;		/* QPNP_PIN_PULL_NO*/
-		qcom,vin-sel = <2>;		/* QPNP_PIN_VIN2 */
+		qcom,vin-sel = <3>;		/* QPNP_PIN_VIN3 */
 		qcom,out-strength = <3>;/* QPNP_PIN_OUT_STRENGTH_HIGH */
 		qcom,src-sel = <2>;		/* QPNP_PIN_SEL_FUNC_1 */
 		qcom,master-en = <1>;	/* Enable GPIO */
@@ -269,7 +269,7 @@
 		qcom,mode = <1>;
 		qcom,output-type = <0>;
 		qcom,pull = <5>;
-		qcom,vin-sel = <2>;
+		qcom,vin-sel = <3>;
 		qcom,out-strength = <3>;
 		qcom,src-sel = <2>;
 		qcom,master-en = <1>;
@@ -359,3 +359,7 @@
 &pm8226_bms {
 	status = "ok";
 };
+
+&pm8226_chg {
+	qcom,charging-disabled;
+};
diff --git a/arch/arm/boot/dts/msm8226-qrd.dts b/arch/arm/boot/dts/msm8226-qrd.dts
index bbde23f..64cc869 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>;
@@ -269,7 +269,7 @@
 		qcom,mode = <1>;		/* Digital output */
 		qcom,output-type = <0>;	/* CMOS logic */
 		qcom,pull = <5>;		/* QPNP_PIN_PULL_NO*/
-		qcom,vin-sel = <2>;		/* QPNP_PIN_VIN2 */
+		qcom,vin-sel = <3>;		/* QPNP_PIN_VIN3 */
 		qcom,out-strength = <3>;/* QPNP_PIN_OUT_STRENGTH_HIGH */
 		qcom,src-sel = <2>;		/* QPNP_PIN_SEL_FUNC_1 */
 		qcom,master-en = <1>;	/* Enable GPIO */
@@ -279,7 +279,7 @@
 		qcom,mode = <1>;
 		qcom,output-type = <0>;
 		qcom,pull = <5>;
-		qcom,vin-sel = <2>;
+		qcom,vin-sel = <3>;
 		qcom,out-strength = <3>;
 		qcom,src-sel = <2>;
 		qcom,master-en = <1>;
diff --git a/arch/arm/boot/dts/msm8226-smp2p.dtsi b/arch/arm/boot/dts/msm8226-smp2p.dtsi
index 91029e2..079e4ca 100644
--- a/arch/arm/boot/dts/msm8226-smp2p.dtsi
+++ b/arch/arm/boot/dts/msm8226-smp2p.dtsi
@@ -148,6 +148,29 @@
 		gpios = <&smp2pgpio_smp2p_2_out 0 0>;
 	};
 
+	/* SMP2P SSR Driver for inbound entry from lpass. */
+	smp2pgpio_ssr_smp2p_2_in: qcom,smp2pgpio-ssr-smp2p-2-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "slave-kernel";
+		qcom,remote-pid = <2>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	/* SMP2P SSR Driver for outbound entry to lpass */
+	smp2pgpio_ssr_smp2p_2_out: qcom,smp2pgpio-ssr-smp2p-2-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "master-kernel";
+		qcom,remote-pid = <2>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
 	smp2pgpio_smp2p_4_in: qcom,smp2pgpio-smp2p-4-in {
 		compatible = "qcom,smp2pgpio";
 		qcom,entry-name = "smp2p";
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index cb2047f..b949d3b 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -755,6 +755,12 @@
 		interrupts = <0 162 1>;
 
 		qcom,firmware-name = "adsp";
+
+		/* GPIO input from lpass */
+		qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_2_in 0 0>;
+
+		/* GPIO output to lpass */
+		qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_2_out 0 0>;
 	};
 
 	qcom,mss@fc880000 {
diff --git a/arch/arm/boot/dts/msm8610-cdp.dts b/arch/arm/boot/dts/msm8610-cdp.dts
index 08da115..a8a2446 100644
--- a/arch/arm/boot/dts/msm8610-cdp.dts
+++ b/arch/arm/boot/dts/msm8610-cdp.dts
@@ -24,6 +24,24 @@
 	};
 };
 
+&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;
@@ -79,3 +97,25 @@
 
 	status = "ok";
 };
+
+&pm8110_chg {
+	status = "ok";
+	qcom,chg-charging-disabled;
+	qcom,chg-use-default-batt-values;
+
+	qcom,chg-chgr@1000 {
+		status = "ok";
+	};
+
+	qcom,chg-buck@1100 {
+		status = "ok";
+	};
+
+	qcom,chg-usb-chgpth@1300 {
+		status = "ok";
+	};
+
+	qcom,chg-misc@1600 {
+		status = "ok";
+	};
+};
diff --git a/arch/arm/boot/dts/msm8610-mtp.dts b/arch/arm/boot/dts/msm8610-mtp.dts
index e3eed72..b1511ff 100644
--- a/arch/arm/boot/dts/msm8610-mtp.dts
+++ b/arch/arm/boot/dts/msm8610-mtp.dts
@@ -24,6 +24,24 @@
 	};
 };
 
+&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;
@@ -79,3 +97,28 @@
 
 	status = "ok";
 };
+
+&pm8110_chg {
+	status = "ok";
+	qcom,chg-charging-disabled;
+
+	qcom,chg-chgr@1000 {
+		status = "ok";
+	};
+
+	qcom,chg-buck@1100 {
+		status = "ok";
+	};
+
+	qcom,chg-bat-if@1200 {
+		status = "ok";
+	};
+
+	qcom,chg-usb-chgpth@1300 {
+		status = "ok";
+	};
+
+	qcom,chg-misc@1600 {
+		status = "ok";
+	};
+};
diff --git a/arch/arm/boot/dts/msm8610-regulator.dtsi b/arch/arm/boot/dts/msm8610-regulator.dtsi
index d50902c..67eee5c 100644
--- a/arch/arm/boot/dts/msm8610-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8610-regulator.dtsi
@@ -10,19 +10,6 @@
  * GNU General Public License for more details.
  */
 
- /* Stub Regulators */
-
-/ {
-	pm8110_s1_corner: regulator-s1-corner {
-		compatible = "qcom,stub-regulator";
-		regulator-name = "8110_s1_corner";
-		qcom,hpm-min-load = <100000>;
-		regulator-min-microvolt = <1>;
-		regulator-max-microvolt = <7>;
-		qcom,consumer-supplies = "vdd_dig", "", "vdd_sr2_dig", "";
-	};
-};
-
 /* SPM controlled regulators */
 
 &spmi_bus {
@@ -60,195 +47,274 @@
 	};
 };
 
-/* QPNP controlled regulators: */
+/* RPM controlled regulators: */
 
-&spmi_bus {
+&rpm_bus {
 
-	qcom,pm8110@1 {
-
-		pm8110_s1: regulator@1400 {
+	rpm-regulator-smpa1 {
+		status = "okay";
+		pm8110_s1: regulator-s1 {
 			status = "okay";
-			regulator-min-microvolt = <1150000>;
-			regulator-max-microvolt = <1150000>;
-			qcom,enable-time = <500>;
-			qcom,system-load = <100000>;
-			regulator-always-on;
+			regulator-min-microvolt = <500000>;
+			regulator-max-microvolt = <1275000>;
 		};
 
-		pm8110_s3: regulator@1a00 {
-			status = "okay";
-			regulator-min-microvolt = <1350000>;
+		pm8110_s1_corner: regulator-s1-corner {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8110_s1_corner";
+			qcom,set = <3>;
+			regulator-min-microvolt = <1>;
+			regulator-max-microvolt = <7>;
+			qcom,use-voltage-corner;
+			qcom,consumer-supplies = "vdd_dig", "", "vdd_sr2_dig", "";
+		};
+
+		pm8110_s1_corner_ao: regulator-s1-corner-ao {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8110_s1_corner_ao";
+			qcom,set = <1>;
+			regulator-min-microvolt = <1>;
+			regulator-max-microvolt = <7>;
+			qcom,use-voltage-corner;
+		};
+	};
+
+	rpm-regulator-smpa3 {
+		status = "okay";
+		pm8110_s3: regulator-s3 {
+			regulator-min-microvolt = <1200000>;
 			regulator-max-microvolt = <1350000>;
-			qcom,enable-time = <500>;
-			qcom,system-load = <100000>;
-			regulator-always-on;
-		};
-
-		pm8110_s4: regulator@1d00 {
+			qcom,init-voltage = <1200000>;
 			status = "okay";
+		};
+	};
+
+	rpm-regulator-smpa4 {
+		status = "okay";
+		pm8110_s4: regulator-s4 {
 			regulator-min-microvolt = <2150000>;
 			regulator-max-microvolt = <2150000>;
-			qcom,enable-time = <500>;
-			qcom,system-load = <100000>;
-			regulator-always-on;
-		};
-
-		pm8110_l1: regulator@4000 {
+			qcom,init-voltage = <2150000>;
 			status = "okay";
-			parent-supply = <&pm8110_s3>;
+		};
+	};
+
+	rpm-regulator-ldoa1 {
+		status = "okay";
+		pm8110_l1: regulator-l1 {
 			regulator-min-microvolt = <1225000>;
 			regulator-max-microvolt = <1225000>;
-			qcom,enable-time = <200>;
-		};
-
-		pm8110_l2: regulator@4100 {
+			qcom,init-voltage = <1225000>;
 			status = "okay";
-			parent-supply = <&pm8110_s3>;
+		};
+	};
+
+	rpm-regulator-ldoa2 {
+		status = "okay";
+		pm8110_l2: regulator-l2 {
 			regulator-min-microvolt = <1200000>;
 			regulator-max-microvolt = <1200000>;
-			qcom,enable-time = <200>;
-			qcom,system-load = <10000>;
-			regulator-always-on;
+			qcom,init-voltage = <1200000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa3 {
+		status = "okay";
+		pm8110_l3: regulator-l3 {
+			regulator-min-microvolt = <750000>;
+			regulator-max-microvolt = <1275000>;
+			status = "okay";
 		};
 
-		pm8110_l3: regulator@4200 {
+		pm8110_l3_ao: regulator-l3-ao {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8110_l3_ao";
+			qcom,set = <1>;
+			regulator-min-microvolt = <750000>;
+			regulator-max-microvolt = <1275000>;
 			status = "okay";
-			parent-supply = <&pm8110_s3>;
-			regulator-min-microvolt = <1150000>;
-			regulator-max-microvolt = <1150000>;
-			qcom,enable-time = <200>;
-			qcom,system-load = <10000>;
-			regulator-always-on;
 		};
 
-		pm8110_l4: regulator@4300 {
+		pm8110_l3_so: regulator-l3-so {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8110_l3_so";
+			qcom,set = <2>;
+			regulator-min-microvolt = <750000>;
+			regulator-max-microvolt = <1275000>;
+			qcom,init-voltage = <750000>;
 			status = "okay";
-			parent-supply = <&pm8110_s3>;
+		};
+	};
+
+	rpm-regulator-ldoa4 {
+		status = "okay";
+		pm8110_l4: regulator-l4 {
 			regulator-min-microvolt = <1200000>;
 			regulator-max-microvolt = <1200000>;
-			qcom,enable-time = <200>;
-		};
-
-		pm8110_l5: regulator@4400 {
+			qcom,init-voltage = <1200000>;
 			status = "okay";
-			parent-supply = <&pm8110_s3>;
+		};
+	};
+
+	rpm-regulator-ldoa5 {
+		status = "okay";
+		pm8110_l5: regulator-l5 {
 			regulator-min-microvolt = <1300000>;
 			regulator-max-microvolt = <1300000>;
-			qcom,enable-time = <200>;
-		};
-
-		pm8110_l6: regulator@4500 {
+			qcom,init-voltage = <1300000>;
 			status = "okay";
-			parent-supply = <&pm8110_s4>;
+		};
+	};
+
+	rpm-regulator-ldoa6 {
+		status = "okay";
+		pm8110_l6: regulator-l6 {
 			regulator-min-microvolt = <1800000>;
 			regulator-max-microvolt = <1800000>;
-			qcom,enable-time = <200>;
-			qcom,system-load = <10000>;
-			regulator-always-on;
-		};
-
-		pm8110_l7: regulator@4600 {
+			qcom,init-voltage = <1800000>;
 			status = "okay";
-			parent-supply = <&pm8110_s4>;
+		};
+	};
+
+	rpm-regulator-ldoa7 {
+		status = "okay";
+		pm8110_l7: regulator-l7 {
 			regulator-min-microvolt = <2050000>;
 			regulator-max-microvolt = <2050000>;
-			qcom,enable-time = <200>;
-		};
-
-		pm8110_l8: regulator@4700 {
+			qcom,init-voltage = <2050000>;
 			status = "okay";
-			parent-supply = <&pm8110_s4>;
+		};
+	};
+
+	rpm-regulator-ldoa8 {
+		status = "okay";
+		pm8110_l8: regulator-l8 {
 			regulator-min-microvolt = <1800000>;
 			regulator-max-microvolt = <1800000>;
-			qcom,enable-time = <200>;
-		};
-
-		pm8110_l9: regulator@4800 {
+			qcom,init-voltage = <1800000>;
 			status = "okay";
-			parent-supply = <&pm8110_s4>;
+		};
+	};
+
+	rpm-regulator-ldoa9 {
+		status = "okay";
+		pm8110_l9: regulator-l9 {
 			regulator-min-microvolt = <2050000>;
 			regulator-max-microvolt = <2050000>;
-			qcom,enable-time = <200>;
-		};
-
-		pm8110_l10: regulator@4900 {
+			qcom,init-voltage = <2050000>;
 			status = "okay";
-			parent-supply = <&pm8110_s4>;
+		};
+	};
+
+	rpm-regulator-ldoa10 {
+		status = "okay";
+		pm8110_l10: regulator-l10 {
 			regulator-min-microvolt = <1800000>;
 			regulator-max-microvolt = <1800000>;
-			qcom,enable-time = <200>;
+			qcom,init-voltage = <1800000>;
+			status = "okay";
 			qcom,consumer-supplies = "vdd_sr2_pll", "";
 		};
+	};
 
-		pm8110_l12: regulator@4b00 {
-			status = "okay";
+	rpm-regulator-ldoa12 {
+		status = "okay";
+		pm8110_l12: regulator-l12 {
 			regulator-min-microvolt = <1800000>;
 			regulator-max-microvolt = <3300000>;
-			qcom,enable-time = <200>;
-		};
-
-		pm8110_l14: regulator@4d00 {
+			qcom,init-voltage = <3300000>;
 			status = "okay";
-			parent-supply = <&pm8110_s4>;
+		};
+	};
+
+	rpm-regulator-ldoa14 {
+		status = "okay";
+		pm8110_l14: regulator-l14 {
 			regulator-min-microvolt = <1800000>;
 			regulator-max-microvolt = <1800000>;
-			qcom,enable-time = <200>;
-		};
-
-		pm8110_l15: regulator@4e00 {
+			qcom,init-voltage = <1800000>;
 			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa15 {
+		status = "okay";
+		pm8110_l15: regulator-l15 {
 			regulator-min-microvolt = <1800000>;
 			regulator-max-microvolt = <3300000>;
-			qcom,enable-time = <200>;
-		};
-
-		pm8110_l16: regulator@4f00 {
+			qcom,init-voltage = <3300000>;
 			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa16 {
+		status = "okay";
+		pm8110_l16: regulator-l16 {
 			regulator-min-microvolt = <3000000>;
 			regulator-max-microvolt = <3000000>;
-			qcom,enable-time = <200>;
-		};
-
-		pm8110_l17: regulator@5000 {
+			qcom,init-voltage = <3000000>;
 			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa17 {
+		status = "okay";
+		pm8110_l17: regulator-l17 {
 			regulator-min-microvolt = <2900000>;
 			regulator-max-microvolt = <2900000>;
-			qcom,enable-time = <200>;
-		};
-
-		pm8110_l18: regulator@5100 {
+			qcom,init-voltage = <2900000>;
 			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa18 {
+		status = "okay";
+		pm8110_l18: regulator-l18 {
 			regulator-min-microvolt = <1800000>;
 			regulator-max-microvolt = <2950000>;
-			qcom,enable-time = <200>;
-		};
-
-		pm8110_l19: regulator@5200 {
+			qcom,init-voltage = <2950000>;
 			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa19 {
+		status = "okay";
+		pm8110_l19: regulator-l19 {
 			regulator-min-microvolt = <2850000>;
 			regulator-max-microvolt = <2850000>;
-			qcom,enable-time = <200>;
-		};
-
-		pm8110_l20: regulator@5300 {
+			qcom,init-voltage = <2850000>;
 			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa20 {
+		status = "okay";
+		pm8110_l20: regulator-l20 {
 			regulator-min-microvolt = <3075000>;
 			regulator-max-microvolt = <3075000>;
-			qcom,enable-time = <200>;
-		};
-
-		pm8110_l21: regulator@5400 {
+			qcom,init-voltage = <3075000>;
 			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa21 {
+		status = "okay";
+		pm8110_l21: regulator-l21 {
 			regulator-min-microvolt = <1800000>;
 			regulator-max-microvolt = <2950000>;
-			qcom,enable-time = <200>;
-		};
-
-		pm8110_l22: regulator@5500 {
+			qcom,init-voltage = <2950000>;
 			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa22 {
+		status = "okay";
+		pm8110_l22: regulator-l22 {
 			regulator-min-microvolt = <1800000>;
 			regulator-max-microvolt = <3300000>;
-			qcom,enable-time = <200>;
+			qcom,init-voltage = <3300000>;
+			status = "okay";
 		};
 	};
 };
diff --git a/arch/arm/boot/dts/msm8610-smp2p.dtsi b/arch/arm/boot/dts/msm8610-smp2p.dtsi
index 91029e2..079e4ca 100644
--- a/arch/arm/boot/dts/msm8610-smp2p.dtsi
+++ b/arch/arm/boot/dts/msm8610-smp2p.dtsi
@@ -148,6 +148,29 @@
 		gpios = <&smp2pgpio_smp2p_2_out 0 0>;
 	};
 
+	/* SMP2P SSR Driver for inbound entry from lpass. */
+	smp2pgpio_ssr_smp2p_2_in: qcom,smp2pgpio-ssr-smp2p-2-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "slave-kernel";
+		qcom,remote-pid = <2>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	/* SMP2P SSR Driver for outbound entry to lpass */
+	smp2pgpio_ssr_smp2p_2_out: qcom,smp2pgpio-ssr-smp2p-2-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "master-kernel";
+		qcom,remote-pid = <2>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
 	smp2pgpio_smp2p_4_in: qcom,smp2pgpio-smp2p-4-in {
 		compatible = "qcom,smp2pgpio";
 		qcom,entry-name = "smp2p";
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index 0df70df..b6a4315 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -401,7 +401,7 @@
 		reg = <0xf9011050 0x8>;
 		reg-names = "rcg_base";
 		a7_cpu-supply = <&apc_vreg_corner>;
-		a7_mem-supply = <&pm8110_l3>;
+		a7_mem-supply = <&pm8110_l3_ao>;
 	};
 
 	spmi_bus: qcom,spmi@fc4c0000 {
@@ -639,6 +639,12 @@
 		interrupts = <0 162 1>;
 		vdd_cx-supply = <&pm8110_s1_corner>;
 		qcom,firmware-name = "adsp";
+
+		/* GPIO input from lpass */
+		qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_2_in 0 0>;
+
+		/* GPIO output to lpass */
+		qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_2_out 0 0>;
 	};
 
 	tsens: tsens@fc4a8000 {
@@ -693,6 +699,45 @@
 				<55 512 3936000 393600>,
 				<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>,
+		      <0xfc340000 0x1000>;
+		reg-names = "etm-base","debug-base";
+	};
+
+	jtag_mm1: jtagmm@fc34d000 {
+		compatible = "qcom,jtag-mm";
+		reg = <0xfc34d000 0x1000>,
+		      <0xfc342000 0x1000>;
+		reg-names = "etm-base","debug-base";
+	};
+
+	jtag_mm2: jtagmm@fc34e000 {
+		compatible = "qcom,jtag-mm";
+		reg = <0xfc34e000 0x1000>,
+		      <0xfc344000 0x1000>;
+		reg-names = "etm-base","debug-base";
+	};
+
+	jtag_mm3: jtagmm@fc34f000 {
+		compatible = "qcom,jtag-mm";
+		reg = <0xfc34f000 0x1000>,
+		      <0xfc346000 0x1000>;
+		reg-names = "etm-base","debug-base";
+	};
+
+	qcom,tz-log@fe805720 {
+		compatible = "qcom,tz-log";
+		reg = <0x0fe805720 0x1000>;
+	};
 };
 
 &gdsc_vfe {
@@ -729,6 +774,7 @@
 
 /include/ "msm8610-iommu-domains.dtsi"
 
+/include/ "msm-pm8110-rpm-regulator.dtsi"
 /include/ "msm-pm8110.dtsi"
 /include/ "msm8610-regulator.dtsi"
 
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-fluid.dtsi b/arch/arm/boot/dts/msm8974-fluid.dtsi
index 79e6371..25d0885 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-fluid.dtsi
@@ -353,7 +353,7 @@
 
 &pm8941_chg {
 	status = "ok";
-	qcom,chg-charging-disabled;
+	qcom,charging-disabled;
 
 	qcom,chgr@1000 {
 		status = "ok";
diff --git a/arch/arm/boot/dts/msm8974-mtp.dtsi b/arch/arm/boot/dts/msm8974-mtp.dtsi
index cd83668..8b9ef87 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-mtp.dtsi
@@ -336,7 +336,7 @@
 
 &pm8941_chg {
 	status = "ok";
-	qcom,chg-charging-disabled;
+	qcom,charging-disabled;
 
 	qcom,chgr@1000 {
 		status = "ok";
diff --git a/arch/arm/boot/dts/msm8974-regulator.dtsi b/arch/arm/boot/dts/msm8974-regulator.dtsi
index 49450f3..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";
 		};
 	};
@@ -448,7 +466,6 @@
 		#address-cells = <1>;
 		#size-cells = <1>;
 		ranges;
-		qcom,pfm-threshold = <376975>;
 
 		krait0_vreg: regulator@f9088000 {
 			compatible = "qcom,krait-regulator";
diff --git a/arch/arm/boot/dts/msm8974-smp2p.dtsi b/arch/arm/boot/dts/msm8974-smp2p.dtsi
index 91029e2..079e4ca 100644
--- a/arch/arm/boot/dts/msm8974-smp2p.dtsi
+++ b/arch/arm/boot/dts/msm8974-smp2p.dtsi
@@ -148,6 +148,29 @@
 		gpios = <&smp2pgpio_smp2p_2_out 0 0>;
 	};
 
+	/* SMP2P SSR Driver for inbound entry from lpass. */
+	smp2pgpio_ssr_smp2p_2_in: qcom,smp2pgpio-ssr-smp2p-2-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "slave-kernel";
+		qcom,remote-pid = <2>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	/* SMP2P SSR Driver for outbound entry to lpass */
+	smp2pgpio_ssr_smp2p_2_out: qcom,smp2pgpio-ssr-smp2p-2-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "master-kernel";
+		qcom,remote-pid = <2>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
 	smp2pgpio_smp2p_4_in: qcom,smp2pgpio-smp2p-4-in {
 		compatible = "qcom,smp2pgpio";
 		qcom,entry-name = "smp2p";
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-v2.dtsi b/arch/arm/boot/dts/msm8974-v2.dtsi
index 777d26c..494b12c 100644
--- a/arch/arm/boot/dts/msm8974-v2.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2.dtsi
@@ -63,6 +63,8 @@
 	qcom,mdss-intf-off = <0x00012500 0x00012700
 			      0x00012900 0x00012b00>;
 	qcom,mdss-pingpong-off = <0x00012D00 0x00012E00 0x00012F00>;
+	qcom,mdss-has-bwc;
+	qcom,mdss-has-decimation;
 };
 
 &mdss_hdmi_tx {
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 9f11839..a9685cc 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -833,6 +833,12 @@
 		interrupts = <0 162 1>;
 
 		qcom,firmware-name = "adsp";
+
+		/* GPIO input from lpass */
+		qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_2_in 0 0>;
+
+		/* GPIO output to lpass */
+		qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_2_out 0 0>;
 	};
 
 	qcom,msm-adsp-loader {
diff --git a/arch/arm/boot/dts/msm9625-v2-1-cdp.dts b/arch/arm/boot/dts/msm9625-cdp.dtsi
similarity index 79%
rename from arch/arm/boot/dts/msm9625-v2-1-cdp.dts
rename to arch/arm/boot/dts/msm9625-cdp.dtsi
index da07100..1f9cbb0 100644
--- a/arch/arm/boot/dts/msm9625-v2-1-cdp.dts
+++ b/arch/arm/boot/dts/msm9625-cdp.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, 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
@@ -10,17 +10,10 @@
  * GNU General Public License for more details.
  */
 
-/dts-v1/;
-
-/include/ "msm9625-v2-1.dtsi"
+/include/ "msm9625-display.dtsi"
+/include/ "qpic-panel-ili-qvga.dtsi"
 
 / {
-	model = "Qualcomm MSM 9625V2.1 CDP";
-	compatible = "qcom,msm9625-cdp", "qcom,msm9625", "qcom,cdp";
-	qcom,msm-id = <134 1 0x20001>, <152 1 0x20001>, <149 1 0x20001>,
-		      <150 1 0x20001>, <151 1 0x20001>, <148 1 0x20001>,
-		      <173 1 0x20001>, <174 1 0x20001>, <175 1 0x20001>;
-
 	i2c@f9925000 {
 		charger@57 {
 			compatible = "summit,smb137c";
@@ -42,10 +35,18 @@
 
 	wlan0: qca,wlan {
 		cell-index = <0>;
-		compatible = "qca,ar6004-sdio";
+		compatible = "qca,ar6004-hsic";
 		qca,chip-pwd-l-gpios = <&msmgpio 62 0>;
 		qca,pm-enable-gpios = <&pm8019_gpios 3 0x0>;
-		qca,ar6004-vdd-io-supply = <&pm8019_l11>;
+		qca,vdd-io-supply = <&pm8019_l11>;
+	};
+
+	qca,wlan_ar6003 {
+		cell-index = <0>;
+		compatible = "qca,ar6003-sdio";
+		qca,chip-pwd-l-gpios = <&msmgpio 62 0>;
+		qca,pm-enable-gpios = <&pm8019_gpios 3 0x0>;
+		qca,vdd-io-supply = <&pm8019_l11>;
 	};
 };
 
diff --git a/arch/arm/boot/dts/msm9625-v2-1-cdp.dts b/arch/arm/boot/dts/msm9625-mtp.dtsi
similarity index 73%
copy from arch/arm/boot/dts/msm9625-v2-1-cdp.dts
copy to arch/arm/boot/dts/msm9625-mtp.dtsi
index da07100..cc0bf5e 100644
--- a/arch/arm/boot/dts/msm9625-v2-1-cdp.dts
+++ b/arch/arm/boot/dts/msm9625-mtp.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, 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
@@ -10,17 +10,7 @@
  * GNU General Public License for more details.
  */
 
-/dts-v1/;
-
-/include/ "msm9625-v2-1.dtsi"
-
 / {
-	model = "Qualcomm MSM 9625V2.1 CDP";
-	compatible = "qcom,msm9625-cdp", "qcom,msm9625", "qcom,cdp";
-	qcom,msm-id = <134 1 0x20001>, <152 1 0x20001>, <149 1 0x20001>,
-		      <150 1 0x20001>, <151 1 0x20001>, <148 1 0x20001>,
-		      <173 1 0x20001>, <174 1 0x20001>, <175 1 0x20001>;
-
 	i2c@f9925000 {
 		charger@57 {
 			compatible = "summit,smb137c";
@@ -42,10 +32,18 @@
 
 	wlan0: qca,wlan {
 		cell-index = <0>;
-		compatible = "qca,ar6004-sdio";
+		compatible = "qca,ar6004-hsic";
 		qca,chip-pwd-l-gpios = <&msmgpio 62 0>;
 		qca,pm-enable-gpios = <&pm8019_gpios 3 0x0>;
-		qca,ar6004-vdd-io-supply = <&pm8019_l11>;
+		qca,vdd-io-supply = <&pm8019_l11>;
+	};
+
+	qca,wlan_ar6003 {
+		cell-index = <0>;
+		compatible = "qca,ar6003-sdio";
+		qca,chip-pwd-l-gpios = <&msmgpio 62 0>;
+		qca,pm-enable-gpios = <&pm8019_gpios 3 0x0>;
+		qca,vdd-io-supply = <&pm8019_l11>;
 	};
 };
 
@@ -89,11 +87,23 @@
 	};
 
 	mpp@a300 { /* MPP 4 */
+		/* VADC channel 19 */
+		qcom,mode = <4>;
+		qcom,ain-route = <3>; /* AMUX 8 */
+		qcom,master-en = <1>;
+		qcom,src-sel = <0>; /* Function constant */
+		qcom,invert = <1>;
 	};
 
 	mpp@a400 { /* MPP 5 */
 	};
 
 	mpp@a500 { /* MPP 6 */
+		/* channel 21 */
+		qcom,mode = <4>;
+		qcom,ain-route = <1>; /* AMUX 6 */
+		qcom,master-en = <1>;
+		qcom,src-sel = <0>; /* Function constant */
+		qcom,invert = <1>;
 	};
 };
diff --git a/arch/arm/boot/dts/msm9625-v1-cdp.dts b/arch/arm/boot/dts/msm9625-v1-cdp.dts
index cf17c69..d7537eb 100644
--- a/arch/arm/boot/dts/msm9625-v1-cdp.dts
+++ b/arch/arm/boot/dts/msm9625-v1-cdp.dts
@@ -13,6 +13,7 @@
 /dts-v1/;
 
 /include/ "msm9625-v1.dtsi"
+/include/ "msm9625-cdp.dtsi"
 
 / {
 	model = "Qualcomm MSM 9625V1 CDP";
@@ -20,88 +21,4 @@
 	qcom,msm-id = <134 1 0>, <152 1 0>, <149 1 0>, <150 1 0>,
 		      <151 1 0>, <148 1 0>, <173 1 0>, <174 1 0>,
 		      <175 1 0>;
-
-	i2c@f9925000 {
-		charger@57 {
-			compatible = "summit,smb137c";
-			reg = <0x57>;
-			summit,chg-current-ma = <1500>;
-			summit,term-current-ma = <50>;
-			summit,pre-chg-current-ma = <100>;
-			summit,float-voltage-mv = <4200>;
-			summit,thresh-voltage-mv = <3000>;
-			summit,recharge-thresh-mv = <75>;
-			summit,system-voltage-mv = <4250>;
-			summit,charging-timeout = <382>;
-			summit,pre-charge-timeout = <48>;
-			summit,therm-current-ua = <10>;
-			summit,temperature-min = <4>; /*  0 C */
-			summit,temperature-max = <3>; /* 45 C */
-		};
-	};
-
-	wlan0: qca,wlan {
-		cell-index = <0>;
-		compatible = "qca,ar6004-sdio";
-		qca,chip-pwd-l-gpios = <&msmgpio 62 0>;
-		qca,pm-enable-gpios = <&pm8019_gpios 3 0x0>;
-		qca,vdd-io-supply = <&pm8019_l11>;
-	};
-
-	qca,wlan_ar6003 {
-		cell-index = <0>;
-		compatible = "qca,ar6003-sdio";
-		qca,chip-pwd-l-gpios = <&msmgpio 62 0>;
-		qca,pm-enable-gpios = <&pm8019_gpios 3 0x0>;
-		qca,vdd-io-supply = <&pm8019_l11>;
-	};
-};
-
-/* PM8019 GPIO and MPP configuration */
-&pm8019_gpios {
-	gpio@c000 { /* GPIO 1 */
-	};
-
-	gpio@c100 { /* GPIO 2 */
-	};
-
-	gpio@c200 { /* GPIO 3 */
-	};
-
-	gpio@c300 { /* GPIO 4 */
-		/* ext_2p95v regulator enable config */
-		qcom,mode = <1>; /* Digital output */
-		qcom,output-type = <0>; /* CMOS */
-		qcom,invert = <0>; /* Output low */
-		qcom,out-strength = <1>; /* Low */
-		qcom,vin-sel = <2>; /* PM8019 L11 - 1.8V */
-		qcom,src-sel = <0>; /* Constant */
-		qcom,master-en = <1>; /* Enable GPIO */
-	};
-
-	gpio@c400 { /* GPIO 5 */
-	};
-
-	gpio@c500 { /* GPIO 6 */
-	};
-};
-
-&pm8019_mpps {
-	mpp@a000 { /* MPP 1 */
-	};
-
-	mpp@a100 { /* MPP 2 */
-	};
-
-	mpp@a200 { /* MPP 3 */
-	};
-
-	mpp@a300 { /* MPP 4 */
-	};
-
-	mpp@a400 { /* MPP 5 */
-	};
-
-	mpp@a500 { /* MPP 6 */
-	};
 };
diff --git a/arch/arm/boot/dts/msm9625-v1-mtp.dts b/arch/arm/boot/dts/msm9625-v1-mtp.dts
index 24aa3af..a70ec1a 100644
--- a/arch/arm/boot/dts/msm9625-v1-mtp.dts
+++ b/arch/arm/boot/dts/msm9625-v1-mtp.dts
@@ -13,6 +13,7 @@
 /dts-v1/;
 
 /include/ "msm9625-v1.dtsi"
+/include/ "msm9625-mtp.dtsi"
 
 / {
 	model = "Qualcomm MSM 9625V1 MTP";
@@ -20,100 +21,4 @@
 	qcom,msm-id = <134 7 0>, <152 7 0>, <149 7 0>, <150 7 0>,
 		      <151 7 0>, <148 7 0>, <173 7 0>, <174 7 0>,
 		      <175 7 0>;
-
-	i2c@f9925000 {
-		charger@57 {
-			compatible = "summit,smb137c";
-			reg = <0x57>;
-			summit,chg-current-ma = <1500>;
-			summit,term-current-ma = <50>;
-			summit,pre-chg-current-ma = <100>;
-			summit,float-voltage-mv = <4200>;
-			summit,thresh-voltage-mv = <3000>;
-			summit,recharge-thresh-mv = <75>;
-			summit,system-voltage-mv = <4250>;
-			summit,charging-timeout = <382>;
-			summit,pre-charge-timeout = <48>;
-			summit,therm-current-ua = <10>;
-			summit,temperature-min = <4>; /*  0 C */
-			summit,temperature-max = <3>; /* 45 C */
-		};
-	};
-
-	wlan0: qca,wlan {
-		cell-index = <0>;
-		compatible = "qca,ar6004-sdio";
-		qca,chip-pwd-l-gpios = <&msmgpio 62 0>;
-		qca,pm-enable-gpios = <&pm8019_gpios 3 0x0>;
-		qca,vdd-io-supply = <&pm8019_l11>;
-	};
-
-	qca,wlan_ar6003 {
-		cell-index = <0>;
-		compatible = "qca,ar6003-sdio";
-		qca,chip-pwd-l-gpios = <&msmgpio 62 0>;
-		qca,pm-enable-gpios = <&pm8019_gpios 3 0x0>;
-		qca,vdd-io-supply = <&pm8019_l11>;
-	};
-};
-
-/* PM8019 GPIO and MPP configuration */
-&pm8019_gpios {
-	gpio@c000 { /* GPIO 1 */
-	};
-
-	gpio@c100 { /* GPIO 2 */
-	};
-
-	gpio@c200 { /* GPIO 3 */
-	};
-
-	gpio@c300 { /* GPIO 4 */
-		/* ext_2p95v regulator enable config */
-		qcom,mode = <1>; /* Digital output */
-		qcom,output-type = <0>; /* CMOS */
-		qcom,invert = <0>; /* Output low */
-		qcom,out-strength = <1>; /* Low */
-		qcom,vin-sel = <2>; /* PM8019 L11 - 1.8V */
-		qcom,src-sel = <0>; /* Constant */
-		qcom,master-en = <1>; /* Enable GPIO */
-	};
-
-	gpio@c400 { /* GPIO 5 */
-	};
-
-	gpio@c500 { /* GPIO 6 */
-	};
-};
-
-&pm8019_mpps {
-	mpp@a000 { /* MPP 1 */
-	};
-
-	mpp@a100 { /* MPP 2 */
-	};
-
-	mpp@a200 { /* MPP 3 */
-	};
-
-	mpp@a300 { /* MPP 4 */
-		/* VADC channel 19 */
-		qcom,mode = <4>;
-		qcom,ain-route = <3>; /* AMUX 8 */
-		qcom,master-en = <1>;
-		qcom,src-sel = <0>; /* Function constant */
-		qcom,invert = <1>;
-	};
-
-	mpp@a400 { /* MPP 5 */
-	};
-
-	mpp@a500 { /* MPP 6 */
-		/* VADC channel 21 */
-		qcom,mode = <4>;
-		qcom,ain-route = <1>; /* AMUX 6 */
-		qcom,master-en = <1>;
-		qcom,src-sel = <0>; /* Function constant */
-		qcom,invert = <1>;
-	};
 };
diff --git a/arch/arm/boot/dts/msm9625-v2-1-mtp.dts b/arch/arm/boot/dts/msm9625-v2-1-mtp.dts
deleted file mode 100644
index 1e0f3c0..0000000
--- a/arch/arm/boot/dts/msm9625-v2-1-mtp.dts
+++ /dev/null
@@ -1,99 +0,0 @@
-/* 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/ "msm9625-v2-1.dtsi"
-
-/ {
-	model = "Qualcomm MSM 9625V2.1 MTP";
-	compatible = "qcom,msm9625-mtp", "qcom,msm9625", "qcom,mtp";
-	qcom,msm-id = <134 7 0x20001>, <152 7 0x20001>, <149 7 0x20001>,
-		      <150 7 0x20001>, <151 7 0x20001>, <148 7 0x20001>,
-		      <173 7 0x20001>, <174 7 0x20001>, <175 7 0x20001>;
-
-	i2c@f9925000 {
-		charger@57 {
-			compatible = "summit,smb137c";
-			reg = <0x57>;
-			summit,chg-current-ma = <1500>;
-			summit,term-current-ma = <50>;
-			summit,pre-chg-current-ma = <100>;
-			summit,float-voltage-mv = <4200>;
-			summit,thresh-voltage-mv = <3000>;
-			summit,recharge-thresh-mv = <75>;
-			summit,system-voltage-mv = <4250>;
-			summit,charging-timeout = <382>;
-			summit,pre-charge-timeout = <48>;
-			summit,therm-current-ua = <10>;
-			summit,temperature-min = <4>; /*  0 C */
-			summit,temperature-max = <3>; /* 45 C */
-		};
-	};
-
-	wlan0: qca,wlan {
-		cell-index = <0>;
-		compatible = "qca,ar6004-sdio";
-		qca,chip-pwd-l-gpios = <&msmgpio 62 0>;
-		qca,pm-enable-gpios = <&pm8019_gpios 3 0x0>;
-		qca,ar6004-vdd-io-supply = <&pm8019_l11>;
-	};
-};
-
-/* PM8019 GPIO and MPP configuration */
-&pm8019_gpios {
-	gpio@c000 { /* GPIO 1 */
-	};
-
-	gpio@c100 { /* GPIO 2 */
-	};
-
-	gpio@c200 { /* GPIO 3 */
-	};
-
-	gpio@c300 { /* GPIO 4 */
-		/* ext_2p95v regulator enable config */
-		qcom,mode = <1>; /* Digital output */
-		qcom,output-type = <0>; /* CMOS */
-		qcom,invert = <0>; /* Output low */
-		qcom,out-strength = <1>; /* Low */
-		qcom,vin-sel = <2>; /* PM8019 L11 - 1.8V */
-		qcom,src-sel = <0>; /* Constant */
-		qcom,master-en = <1>; /* Enable GPIO */
-	};
-
-	gpio@c400 { /* GPIO 5 */
-	};
-
-	gpio@c500 { /* GPIO 6 */
-	};
-};
-
-&pm8019_mpps {
-	mpp@a000 { /* MPP 1 */
-	};
-
-	mpp@a100 { /* MPP 2 */
-	};
-
-	mpp@a200 { /* MPP 3 */
-	};
-
-	mpp@a300 { /* MPP 4 */
-	};
-
-	mpp@a400 { /* MPP 5 */
-	};
-
-	mpp@a500 { /* MPP 6 */
-	};
-};
diff --git a/arch/arm/boot/dts/msm9625-v2-cdp.dts b/arch/arm/boot/dts/msm9625-v2-cdp.dts
index 660bdbd..9fbe5ec 100644
--- a/arch/arm/boot/dts/msm9625-v2-cdp.dts
+++ b/arch/arm/boot/dts/msm9625-v2-cdp.dts
@@ -13,8 +13,7 @@
 /dts-v1/;
 
 /include/ "msm9625-v2.dtsi"
-/include/ "msm9625-display.dtsi"
-/include/ "qpic-panel-ili-qvga.dtsi"
+/include/ "msm9625-cdp.dtsi"
 
 / {
 	model = "Qualcomm MSM 9625V2 CDP";
@@ -22,88 +21,4 @@
 	qcom,msm-id = <134 1 0x20000>, <152 1 0x20000>, <149 1 0x20000>,
 		      <150 1 0x20000>, <151 1 0x20000>, <148 1 0x20000>,
 		      <173 1 0x20000>, <174 1 0x20000>, <175 1 0x20000>;
-
-	i2c@f9925000 {
-		charger@57 {
-			compatible = "summit,smb137c";
-			reg = <0x57>;
-			summit,chg-current-ma = <1500>;
-			summit,term-current-ma = <50>;
-			summit,pre-chg-current-ma = <100>;
-			summit,float-voltage-mv = <4200>;
-			summit,thresh-voltage-mv = <3000>;
-			summit,recharge-thresh-mv = <75>;
-			summit,system-voltage-mv = <4250>;
-			summit,charging-timeout = <382>;
-			summit,pre-charge-timeout = <48>;
-			summit,therm-current-ua = <10>;
-			summit,temperature-min = <4>; /*  0 C */
-			summit,temperature-max = <3>; /* 45 C */
-		};
-	};
-
-	wlan0: qca,wlan {
-		cell-index = <0>;
-		compatible = "qca,ar6004-hsic";
-		qca,chip-pwd-l-gpios = <&msmgpio 62 0>;
-		qca,pm-enable-gpios = <&pm8019_gpios 3 0x0>;
-		qca,vdd-io-supply = <&pm8019_l11>;
-	};
-
-	qca,wlan_ar6003 {
-		cell-index = <0>;
-		compatible = "qca,ar6003-sdio";
-		qca,chip-pwd-l-gpios = <&msmgpio 62 0>;
-		qca,pm-enable-gpios = <&pm8019_gpios 3 0x0>;
-		qca,vdd-io-supply = <&pm8019_l11>;
-	};
-};
-
-/* PM8019 GPIO and MPP configuration */
-&pm8019_gpios {
-	gpio@c000 { /* GPIO 1 */
-	};
-
-	gpio@c100 { /* GPIO 2 */
-	};
-
-	gpio@c200 { /* GPIO 3 */
-	};
-
-	gpio@c300 { /* GPIO 4 */
-		/* ext_2p95v regulator enable config */
-		qcom,mode = <1>; /* Digital output */
-		qcom,output-type = <0>; /* CMOS */
-		qcom,invert = <0>; /* Output low */
-		qcom,out-strength = <1>; /* Low */
-		qcom,vin-sel = <2>; /* PM8019 L11 - 1.8V */
-		qcom,src-sel = <0>; /* Constant */
-		qcom,master-en = <1>; /* Enable GPIO */
-	};
-
-	gpio@c400 { /* GPIO 5 */
-	};
-
-	gpio@c500 { /* GPIO 6 */
-	};
-};
-
-&pm8019_mpps {
-	mpp@a000 { /* MPP 1 */
-	};
-
-	mpp@a100 { /* MPP 2 */
-	};
-
-	mpp@a200 { /* MPP 3 */
-	};
-
-	mpp@a300 { /* MPP 4 */
-	};
-
-	mpp@a400 { /* MPP 5 */
-	};
-
-	mpp@a500 { /* MPP 6 */
-	};
 };
diff --git a/arch/arm/boot/dts/msm9625-v2-mtp.dts b/arch/arm/boot/dts/msm9625-v2-mtp.dts
index c9e54be..5324e2c 100644
--- a/arch/arm/boot/dts/msm9625-v2-mtp.dts
+++ b/arch/arm/boot/dts/msm9625-v2-mtp.dts
@@ -13,6 +13,7 @@
 /dts-v1/;
 
 /include/ "msm9625-v2.dtsi"
+/include/ "msm9625-mtp.dtsi"
 
 / {
 	model = "Qualcomm MSM 9625V2 MTP";
diff --git a/arch/arm/boot/dts/msm9625-v2.1-cdp.dts b/arch/arm/boot/dts/msm9625-v2.1-cdp.dts
new file mode 100644
index 0000000..b643593
--- /dev/null
+++ b/arch/arm/boot/dts/msm9625-v2.1-cdp.dts
@@ -0,0 +1,24 @@
+/* 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/ "msm9625-v2.1.dtsi"
+/include/ "msm9625-cdp.dtsi"
+
+/ {
+	model = "Qualcomm MSM 9625V2.1 CDP";
+	compatible = "qcom,msm9625-cdp", "qcom,msm9625", "qcom,cdp";
+	qcom,msm-id = <134 1 0x20001>, <152 1 0x20001>, <149 1 0x20001>,
+		      <150 1 0x20001>, <151 1 0x20001>, <148 1 0x20001>,
+		      <173 1 0x20001>, <174 1 0x20001>, <175 1 0x20001>;
+};
diff --git a/arch/arm/boot/dts/msm9625-v2.1-mtp.dts b/arch/arm/boot/dts/msm9625-v2.1-mtp.dts
new file mode 100644
index 0000000..8bbcc0d
--- /dev/null
+++ b/arch/arm/boot/dts/msm9625-v2.1-mtp.dts
@@ -0,0 +1,24 @@
+/* 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/ "msm9625-v2.1.dtsi"
+/include/ "msm9625-mtp.dtsi"
+
+/ {
+	model = "Qualcomm MSM 9625V2.1 MTP";
+	compatible = "qcom,msm9625-mtp", "qcom,msm9625", "qcom,mtp";
+	qcom,msm-id = <134 7 0x20001>, <152 7 0x20001>, <149 7 0x20001>,
+		      <150 7 0x20001>, <151 7 0x20001>, <148 7 0x20001>,
+		      <173 7 0x20001>, <174 7 0x20001>, <175 7 0x20001>;
+};
diff --git a/arch/arm/boot/dts/msm9625-v2-1.dtsi b/arch/arm/boot/dts/msm9625-v2.1.dtsi
similarity index 100%
rename from arch/arm/boot/dts/msm9625-v2-1.dtsi
rename to arch/arm/boot/dts/msm9625-v2.1.dtsi
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index 348e8c9..faec7af 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -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/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index f67cb0d..aa2c028 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -98,6 +98,7 @@
 CONFIG_CPU_FREQ_GOV_POWERSAVE=y
 CONFIG_CPU_FREQ_GOV_USERSPACE=y
 CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
 CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
 CONFIG_CPU_IDLE=y
 CONFIG_VFP=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index b5e67fd..bbfcad9 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
@@ -102,6 +103,7 @@
 CONFIG_CPU_FREQ_GOV_POWERSAVE=y
 CONFIG_CPU_FREQ_GOV_USERSPACE=y
 CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
 CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
 CONFIG_CPU_IDLE=y
 CONFIG_VFP=y
diff --git a/arch/arm/configs/msm9625-perf_defconfig b/arch/arm/configs/msm9625-perf_defconfig
index 42acd99..ae73bad 100644
--- a/arch/arm/configs/msm9625-perf_defconfig
+++ b/arch/arm/configs/msm9625-perf_defconfig
@@ -230,9 +230,6 @@
 CONFIG_REGULATOR_QPNP=y
 CONFIG_ION=y
 CONFIG_ION_MSM=y
-CONFIG_FB=y
-CONFIG_FB_MSM=y
-CONFIG_FB_MSM_QPIC_PANEL_DETECT=y
 CONFIG_SOUND=y
 CONFIG_SND=y
 CONFIG_SND_SOC=y
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index 041e89a..f7c3bff 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -231,9 +231,6 @@
 CONFIG_REGULATOR_QPNP=y
 CONFIG_ION=y
 CONFIG_ION_MSM=y
-CONFIG_FB=y
-CONFIG_FB_MSM=y
-CONFIG_FB_MSM_QPIC_PANEL_DETECT=y
 CONFIG_SOUND=y
 CONFIG_SND=y
 CONFIG_SND_SOC=y
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index f20f6ae..8c366da 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -76,8 +76,8 @@
         dtb-$(CONFIG_ARCH_MSM9625)	+= msm9625-v1-rumi.dtb
 	dtb-$(CONFIG_ARCH_MSM9625)      += msm9625-v2-cdp.dtb
 	dtb-$(CONFIG_ARCH_MSM9625)      += msm9625-v2-mtp.dtb
-	dtb-$(CONFIG_ARCH_MSM9625)      += msm9625-v2-1-mtp.dtb
-	dtb-$(CONFIG_ARCH_MSM9625)      += msm9625-v2-1-cdp.dtb
+	dtb-$(CONFIG_ARCH_MSM9625)      += msm9625-v2.1-mtp.dtb
+	dtb-$(CONFIG_ARCH_MSM9625)      += msm9625-v2.1-cdp.dtb
 
 # MSM8226
    zreladdr-$(CONFIG_ARCH_MSM8226)	:= 0x00008000
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/acpuclock-8974.c b/arch/arm/mach-msm/acpuclock-8974.c
index a61f5ca..c60e89a 100644
--- a/arch/arm/mach-msm/acpuclock-8974.c
+++ b/arch/arm/mach-msm/acpuclock-8974.c
@@ -128,122 +128,122 @@
 };
 
 static struct acpu_level acpu_freq_tbl_v1_pvs0[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 }, L2(0),   825000,  73 },
-	{ 0, {  345600, HFPLL, 2,  36 }, L2(3),   825000,  85 },
-	{ 1, {  422400, HFPLL, 2,  44 }, L2(3),   825000, 104 },
-	{ 0, {  499200, HFPLL, 2,  52 }, L2(6),   825000, 124 },
-	{ 1, {  576000, HFPLL, 1,  30 }, L2(6),   825000, 144 },
-	{ 1, {  652800, HFPLL, 1,  34 }, L2(7),   825000, 165 },
-	{ 1, {  729600, HFPLL, 1,  38 }, L2(7),   825000, 186 },
-	{ 0, {  806400, HFPLL, 1,  42 }, L2(10),  835000, 208 },
-	{ 1, {  883200, HFPLL, 1,  46 }, L2(10),  845000, 229 },
-	{ 0, {  960000, HFPLL, 1,  50 }, L2(10),  860000, 252 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  880000, 275 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(12),  905000, 298 },
-	{ 0, { 1190400, HFPLL, 1,  62 }, L2(12),  920000, 321 },
-	{ 0, { 1267200, HFPLL, 1,  66 }, L2(12),  940000, 346 },
-	{ 1, { 1344000, HFPLL, 1,  70 }, L2(12),  960000, 371 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(16),  980000, 397 },
-	{ 0, { 1497600, HFPLL, 1,  78 }, L2(16),  995000, 423 },
-	{ 0, { 1574400, HFPLL, 1,  82 }, L2(16), 1015000, 450 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(16), 1030000, 477 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(16), 1050000, 506 },
+	{ 1, {  300000, PLL_0, 0,   0 }, L2(0),   825000,  400000 },
+	{ 0, {  345600, HFPLL, 2,  36 }, L2(3),   825000, 3200000 },
+	{ 1, {  422400, HFPLL, 2,  44 }, L2(3),   825000, 3200000 },
+	{ 0, {  499200, HFPLL, 2,  52 }, L2(6),   825000, 3200000 },
+	{ 1, {  576000, HFPLL, 1,  30 }, L2(6),   825000, 3200000 },
+	{ 1, {  652800, HFPLL, 1,  34 }, L2(7),   825000, 3200000 },
+	{ 1, {  729600, HFPLL, 1,  38 }, L2(7),   825000, 3200000 },
+	{ 0, {  806400, HFPLL, 1,  42 }, L2(10),  835000, 3200000 },
+	{ 1, {  883200, HFPLL, 1,  46 }, L2(10),  845000, 3200000 },
+	{ 0, {  960000, HFPLL, 1,  50 }, L2(10),  860000, 3200000 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  880000, 3200000 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(12),  905000, 3200000 },
+	{ 0, { 1190400, HFPLL, 1,  62 }, L2(12),  920000, 3200000 },
+	{ 0, { 1267200, HFPLL, 1,  66 }, L2(12),  940000, 3200000 },
+	{ 1, { 1344000, HFPLL, 1,  70 }, L2(12),  960000, 3200000 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(16),  980000, 3200000 },
+	{ 0, { 1497600, HFPLL, 1,  78 }, L2(16),  995000, 3200000 },
+	{ 0, { 1574400, HFPLL, 1,  82 }, L2(16), 1015000, 3200000 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(16), 1030000, 3200000 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(16), 1050000, 3200000 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_v1_pvs1[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 }, L2(0),   825000,  73 },
-	{ 0, {  345600, HFPLL, 2,  36 }, L2(3),   825000,  85 },
-	{ 1, {  422400, HFPLL, 2,  44 }, L2(3),   825000, 104 },
-	{ 0, {  499200, HFPLL, 2,  52 }, L2(6),   825000, 124 },
-	{ 1, {  576000, HFPLL, 1,  30 }, L2(6),   825000, 144 },
-	{ 1, {  652800, HFPLL, 1,  34 }, L2(7),   825000, 165 },
-	{ 1, {  729600, HFPLL, 1,  38 }, L2(7),   825000, 186 },
-	{ 0, {  806400, HFPLL, 1,  42 }, L2(10),  835000, 208 },
-	{ 1, {  883200, HFPLL, 1,  46 }, L2(10),  845000, 229 },
-	{ 0, {  960000, HFPLL, 1,  50 }, L2(10),  860000, 252 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  880000, 275 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(12),  905000, 298 },
-	{ 0, { 1190400, HFPLL, 1,  62 }, L2(12),  920000, 321 },
-	{ 0, { 1267200, HFPLL, 1,  66 }, L2(12),  940000, 346 },
-	{ 1, { 1344000, HFPLL, 1,  70 }, L2(12),  960000, 371 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(16),  980000, 397 },
-	{ 0, { 1497600, HFPLL, 1,  78 }, L2(16),  995000, 423 },
-	{ 0, { 1574400, HFPLL, 1,  82 }, L2(16), 1015000, 450 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(16), 1030000, 477 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(16), 1050000, 506 },
+	{ 1, {  300000, PLL_0, 0,   0 }, L2(0),   825000,  400000 },
+	{ 0, {  345600, HFPLL, 2,  36 }, L2(3),   825000, 3200000 },
+	{ 1, {  422400, HFPLL, 2,  44 }, L2(3),   825000, 3200000 },
+	{ 0, {  499200, HFPLL, 2,  52 }, L2(6),   825000, 3200000 },
+	{ 1, {  576000, HFPLL, 1,  30 }, L2(6),   825000, 3200000 },
+	{ 1, {  652800, HFPLL, 1,  34 }, L2(7),   825000, 3200000 },
+	{ 1, {  729600, HFPLL, 1,  38 }, L2(7),   825000, 3200000 },
+	{ 0, {  806400, HFPLL, 1,  42 }, L2(10),  835000, 3200000 },
+	{ 1, {  883200, HFPLL, 1,  46 }, L2(10),  845000, 3200000 },
+	{ 0, {  960000, HFPLL, 1,  50 }, L2(10),  860000, 3200000 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  880000, 3200000 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(12),  905000, 3200000 },
+	{ 0, { 1190400, HFPLL, 1,  62 }, L2(12),  920000, 3200000 },
+	{ 0, { 1267200, HFPLL, 1,  66 }, L2(12),  940000, 3200000 },
+	{ 1, { 1344000, HFPLL, 1,  70 }, L2(12),  960000, 3200000 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(16),  980000, 3200000 },
+	{ 0, { 1497600, HFPLL, 1,  78 }, L2(16),  995000, 3200000 },
+	{ 0, { 1574400, HFPLL, 1,  82 }, L2(16), 1015000, 3200000 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(16), 1030000, 3200000 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(16), 1050000, 3200000 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_v1_pvs2[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 }, L2(0),   825000,  73 },
-	{ 0, {  345600, HFPLL, 2,  36 }, L2(3),   825000,  85 },
-	{ 1, {  422400, HFPLL, 2,  44 }, L2(3),   825000, 104 },
-	{ 0, {  499200, HFPLL, 2,  52 }, L2(6),   825000, 124 },
-	{ 1, {  576000, HFPLL, 1,  30 }, L2(6),   825000, 144 },
-	{ 1, {  652800, HFPLL, 1,  34 }, L2(7),   825000, 165 },
-	{ 1, {  729600, HFPLL, 1,  38 }, L2(7),   825000, 186 },
-	{ 0, {  806400, HFPLL, 1,  42 }, L2(10),  825000, 208 },
-	{ 1, {  883200, HFPLL, 1,  46 }, L2(10),  825000, 229 },
-	{ 0, {  960000, HFPLL, 1,  50 }, L2(10),  835000, 252 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  855000, 275 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(12),  875000, 298 },
-	{ 0, { 1190400, HFPLL, 1,  62 }, L2(12),  895000, 321 },
-	{ 0, { 1267200, HFPLL, 1,  66 }, L2(12),  915000, 346 },
-	{ 1, { 1344000, HFPLL, 1,  70 }, L2(12),  930000, 371 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(16),  945000, 397 },
-	{ 0, { 1497600, HFPLL, 1,  78 }, L2(16),  960000, 423 },
-	{ 0, { 1574400, HFPLL, 1,  82 }, L2(16),  975000, 450 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(16),  990000, 477 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(16), 1000000, 506 },
+	{ 1, {  300000, PLL_0, 0,   0 }, L2(0),   825000,  400000 },
+	{ 0, {  345600, HFPLL, 2,  36 }, L2(3),   825000, 3200000 },
+	{ 1, {  422400, HFPLL, 2,  44 }, L2(3),   825000, 3200000 },
+	{ 0, {  499200, HFPLL, 2,  52 }, L2(6),   825000, 3200000 },
+	{ 1, {  576000, HFPLL, 1,  30 }, L2(6),   825000, 3200000 },
+	{ 1, {  652800, HFPLL, 1,  34 }, L2(7),   825000, 3200000 },
+	{ 1, {  729600, HFPLL, 1,  38 }, L2(7),   825000, 3200000 },
+	{ 0, {  806400, HFPLL, 1,  42 }, L2(10),  825000, 3200000 },
+	{ 1, {  883200, HFPLL, 1,  46 }, L2(10),  825000, 3200000 },
+	{ 0, {  960000, HFPLL, 1,  50 }, L2(10),  835000, 3200000 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  855000, 3200000 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(12),  875000, 3200000 },
+	{ 0, { 1190400, HFPLL, 1,  62 }, L2(12),  895000, 3200000 },
+	{ 0, { 1267200, HFPLL, 1,  66 }, L2(12),  915000, 3200000 },
+	{ 1, { 1344000, HFPLL, 1,  70 }, L2(12),  930000, 3200000 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(16),  945000, 3200000 },
+	{ 0, { 1497600, HFPLL, 1,  78 }, L2(16),  960000, 3200000 },
+	{ 0, { 1574400, HFPLL, 1,  82 }, L2(16),  975000, 3200000 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(16),  990000, 3200000 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(16), 1000000, 3200000 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_v1_pvs3[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 }, L2(0),   825000,  73 },
-	{ 0, {  345600, HFPLL, 2,  36 }, L2(3),   825000,  85 },
-	{ 1, {  422400, HFPLL, 2,  44 }, L2(3),   825000, 104 },
-	{ 0, {  499200, HFPLL, 2,  52 }, L2(6),   825000, 124 },
-	{ 1, {  576000, HFPLL, 1,  30 }, L2(6),   825000, 144 },
-	{ 1, {  652800, HFPLL, 1,  34 }, L2(7),   825000, 165 },
-	{ 1, {  729600, HFPLL, 1,  38 }, L2(7),   825000, 186 },
-	{ 0, {  806400, HFPLL, 1,  42 }, L2(10),  825000, 208 },
-	{ 1, {  883200, HFPLL, 1,  46 }, L2(10),  825000, 229 },
-	{ 0, {  960000, HFPLL, 1,  50 }, L2(10),  835000, 252 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  855000, 275 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(12),  875000, 298 },
-	{ 0, { 1190400, HFPLL, 1,  62 }, L2(12),  895000, 321 },
-	{ 0, { 1267200, HFPLL, 1,  66 }, L2(12),  915000, 346 },
-	{ 1, { 1344000, HFPLL, 1,  70 }, L2(12),  930000, 371 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(16),  945000, 397 },
-	{ 0, { 1497600, HFPLL, 1,  78 }, L2(16),  960000, 423 },
-	{ 0, { 1574400, HFPLL, 1,  82 }, L2(16),  975000, 450 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(16),  990000, 477 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(16), 1000000, 506 },
+	{ 1, {  300000, PLL_0, 0,   0 }, L2(0),   825000,  400000 },
+	{ 0, {  345600, HFPLL, 2,  36 }, L2(3),   825000, 3200000 },
+	{ 1, {  422400, HFPLL, 2,  44 }, L2(3),   825000, 3200000 },
+	{ 0, {  499200, HFPLL, 2,  52 }, L2(6),   825000, 3200000 },
+	{ 1, {  576000, HFPLL, 1,  30 }, L2(6),   825000, 3200000 },
+	{ 1, {  652800, HFPLL, 1,  34 }, L2(7),   825000, 3200000 },
+	{ 1, {  729600, HFPLL, 1,  38 }, L2(7),   825000, 3200000 },
+	{ 0, {  806400, HFPLL, 1,  42 }, L2(10),  825000, 3200000 },
+	{ 1, {  883200, HFPLL, 1,  46 }, L2(10),  825000, 3200000 },
+	{ 0, {  960000, HFPLL, 1,  50 }, L2(10),  835000, 3200000 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  855000, 3200000 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(12),  875000, 3200000 },
+	{ 0, { 1190400, HFPLL, 1,  62 }, L2(12),  895000, 3200000 },
+	{ 0, { 1267200, HFPLL, 1,  66 }, L2(12),  915000, 3200000 },
+	{ 1, { 1344000, HFPLL, 1,  70 }, L2(12),  930000, 3200000 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(16),  945000, 3200000 },
+	{ 0, { 1497600, HFPLL, 1,  78 }, L2(16),  960000, 3200000 },
+	{ 0, { 1574400, HFPLL, 1,  82 }, L2(16),  975000, 3200000 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(16),  990000, 3200000 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(16), 1000000, 3200000 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_v1_pvs4[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 }, L2(0),  825000,  73 },
-	{ 0, {  345600, HFPLL, 2,  36 }, L2(3),  825000,  85 },
-	{ 1, {  422400, HFPLL, 2,  44 }, L2(3),  825000, 104 },
-	{ 0, {  499200, HFPLL, 2,  52 }, L2(6),  825000, 124 },
-	{ 1, {  576000, HFPLL, 1,  30 }, L2(6),  825000, 144 },
-	{ 1, {  652800, HFPLL, 1,  34 }, L2(7),  825000, 165 },
-	{ 1, {  729600, HFPLL, 1,  38 }, L2(7),  825000, 186 },
-	{ 0, {  806400, HFPLL, 1,  42 }, L2(10), 825000, 208 },
-	{ 1, {  883200, HFPLL, 1,  46 }, L2(10), 825000, 229 },
-	{ 0, {  960000, HFPLL, 1,  50 }, L2(10), 825000, 252 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10), 825000, 275 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(12), 835000, 298 },
-	{ 0, { 1190400, HFPLL, 1,  62 }, L2(12), 855000, 321 },
-	{ 0, { 1267200, HFPLL, 1,  66 }, L2(12), 870000, 346 },
-	{ 1, { 1344000, HFPLL, 1,  70 }, L2(12), 885000, 371 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(16), 900000, 397 },
-	{ 0, { 1497600, HFPLL, 1,  78 }, L2(16), 910000, 423 },
-	{ 0, { 1574400, HFPLL, 1,  82 }, L2(16), 925000, 450 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(16), 940000, 477 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(16), 950000, 506 },
+	{ 1, {  300000, PLL_0, 0,   0 }, L2(0),  825000,  400000 },
+	{ 0, {  345600, HFPLL, 2,  36 }, L2(3),  825000, 3200000 },
+	{ 1, {  422400, HFPLL, 2,  44 }, L2(3),  825000, 3200000 },
+	{ 0, {  499200, HFPLL, 2,  52 }, L2(6),  825000, 3200000 },
+	{ 1, {  576000, HFPLL, 1,  30 }, L2(6),  825000, 3200000 },
+	{ 1, {  652800, HFPLL, 1,  34 }, L2(7),  825000, 3200000 },
+	{ 1, {  729600, HFPLL, 1,  38 }, L2(7),  825000, 3200000 },
+	{ 0, {  806400, HFPLL, 1,  42 }, L2(10), 825000, 3200000 },
+	{ 1, {  883200, HFPLL, 1,  46 }, L2(10), 825000, 3200000 },
+	{ 0, {  960000, HFPLL, 1,  50 }, L2(10), 825000, 3200000 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10), 825000, 3200000 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(12), 835000, 3200000 },
+	{ 0, { 1190400, HFPLL, 1,  62 }, L2(12), 855000, 3200000 },
+	{ 0, { 1267200, HFPLL, 1,  66 }, L2(12), 870000, 3200000 },
+	{ 1, { 1344000, HFPLL, 1,  70 }, L2(12), 885000, 3200000 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(16), 900000, 3200000 },
+	{ 0, { 1497600, HFPLL, 1,  78 }, L2(16), 910000, 3200000 },
+	{ 0, { 1574400, HFPLL, 1,  82 }, L2(16), 925000, 3200000 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(16), 940000, 3200000 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(16), 950000, 3200000 },
 	{ 0, { 0 } }
 };
 
@@ -284,618 +284,618 @@
 };
 
 static struct acpu_level acpu_freq_tbl_2g_pvs0[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  815000,  73 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  825000,  85 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  835000, 104 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  845000, 124 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  855000, 144 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  865000, 165 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  875000, 186 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  890000, 208 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  900000, 229 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  915000, 252 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  925000, 275 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  940000, 298 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  950000, 321 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  965000, 346 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  980000, 371 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  995000, 397 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16), 1010000, 423 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17), 1025000, 450 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17), 1040000, 477 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18), 1055000, 506 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18), 1070000, 536 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1085000, 567 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1100000, 598 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  815000,  400000 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  825000, 3200000 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  835000, 3200000 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  845000, 3200000 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  855000, 3200000 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  865000, 3200000 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  875000, 3200000 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  890000, 3200000 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  900000, 3200000 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  915000, 3200000 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  925000, 3200000 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  940000, 3200000 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  950000, 3200000 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  965000, 3200000 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  980000, 3200000 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  995000, 3200000 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16), 1010000, 3200000 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17), 1025000, 3200000 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17), 1040000, 3200000 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18), 1055000, 3200000 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18), 1070000, 3200000 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1085000, 3200000 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1100000, 3200000 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_2g_pvs1[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  800000,  73 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  810000,  85 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  820000, 104 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  830000, 124 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  840000, 144 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  850000, 165 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  860000, 186 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  875000, 208 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  885000, 229 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  895000, 252 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  910000, 275 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  920000, 298 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  930000, 321 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  945000, 346 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  960000, 371 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  975000, 397 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  990000, 423 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17), 1005000, 450 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17), 1020000, 477 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18), 1030000, 506 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18), 1045000, 536 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1060000, 567 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1075000, 598 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  800000,  400000 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  810000, 3200000 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  820000, 3200000 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  830000, 3200000 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  840000, 3200000 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  850000, 3200000 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  860000, 3200000 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  875000, 3200000 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  885000, 3200000 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  895000, 3200000 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  910000, 3200000 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  920000, 3200000 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  930000, 3200000 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  945000, 3200000 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  960000, 3200000 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  975000, 3200000 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  990000, 3200000 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17), 1005000, 3200000 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17), 1020000, 3200000 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18), 1030000, 3200000 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18), 1045000, 3200000 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1060000, 3200000 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1075000, 3200000 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_2g_pvs2[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  785000,  73 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  795000,  85 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  805000, 104 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  815000, 124 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  825000, 144 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  835000, 165 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  845000, 186 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  855000, 208 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  865000, 229 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  875000, 252 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  890000, 275 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  900000, 298 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  910000, 321 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  925000, 346 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  940000, 371 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  955000, 397 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  970000, 423 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  980000, 450 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  995000, 477 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18), 1005000, 506 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18), 1020000, 536 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1035000, 567 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1050000, 598 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  785000,  400000 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  795000, 3200000 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  805000, 3200000 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  815000, 3200000 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  825000, 3200000 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  835000, 3200000 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  845000, 3200000 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  855000, 3200000 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  865000, 3200000 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  875000, 3200000 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  890000, 3200000 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  900000, 3200000 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  910000, 3200000 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  925000, 3200000 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  940000, 3200000 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  955000, 3200000 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  970000, 3200000 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  980000, 3200000 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  995000, 3200000 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18), 1005000, 3200000 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18), 1020000, 3200000 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1035000, 3200000 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1050000, 3200000 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_2g_pvs3[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  73 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  780000,  85 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  790000, 104 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  800000, 124 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  810000, 144 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  820000, 165 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  830000, 186 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  840000, 208 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  850000, 229 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  860000, 252 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  875000, 275 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  885000, 298 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  895000, 321 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  910000, 346 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  925000, 371 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  935000, 397 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  950000, 423 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  960000, 450 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  970000, 477 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  985000, 506 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  995000, 536 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1010000, 567 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1025000, 598 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  400000 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  780000, 3200000 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  790000, 3200000 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  800000, 3200000 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  810000, 3200000 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  820000, 3200000 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  830000, 3200000 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  840000, 3200000 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  850000, 3200000 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  860000, 3200000 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  875000, 3200000 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  885000, 3200000 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  895000, 3200000 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  910000, 3200000 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  925000, 3200000 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  935000, 3200000 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  950000, 3200000 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  960000, 3200000 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  970000, 3200000 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  985000, 3200000 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  995000, 3200000 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1010000, 3200000 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1025000, 3200000 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_2g_pvs4[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  73 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000,  85 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  780000, 104 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  790000, 124 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  800000, 144 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  810000, 165 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  820000, 186 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  830000, 208 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  840000, 229 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  850000, 252 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  860000, 275 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  870000, 298 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  880000, 321 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  895000, 346 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  910000, 371 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  920000, 397 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  930000, 423 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  940000, 450 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  950000, 477 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  960000, 506 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  975000, 536 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  985000, 567 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1000000, 598 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  400000 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000, 3200000 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  780000, 3200000 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  790000, 3200000 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  800000, 3200000 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  810000, 3200000 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  820000, 3200000 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  830000, 3200000 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  840000, 3200000 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  850000, 3200000 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  860000, 3200000 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  870000, 3200000 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  880000, 3200000 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  895000, 3200000 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  910000, 3200000 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  920000, 3200000 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  930000, 3200000 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  940000, 3200000 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  950000, 3200000 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  960000, 3200000 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  975000, 3200000 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  985000, 3200000 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1000000, 3200000 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_2g_pvs5[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  73 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  760000,  85 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  770000, 104 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  780000, 124 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  790000, 144 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  800000, 165 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  810000, 186 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  820000, 208 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  830000, 229 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  840000, 252 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  850000, 275 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  860000, 298 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  870000, 321 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  880000, 346 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  890000, 371 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  900000, 397 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  910000, 423 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  920000, 450 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  930000, 477 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  940000, 506 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  955000, 536 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  965000, 567 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  975000, 598 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  400000 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  760000, 3200000 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  770000, 3200000 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  780000, 3200000 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  790000, 3200000 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  800000, 3200000 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  810000, 3200000 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  820000, 3200000 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  830000, 3200000 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  840000, 3200000 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  850000, 3200000 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  860000, 3200000 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  870000, 3200000 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  880000, 3200000 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  890000, 3200000 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  900000, 3200000 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  910000, 3200000 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  920000, 3200000 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  930000, 3200000 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  940000, 3200000 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  955000, 3200000 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  965000, 3200000 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  975000, 3200000 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_2g_pvs6[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  73 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000,  85 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  760000, 104 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  770000, 124 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  780000, 144 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  790000, 165 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  800000, 186 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  810000, 208 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  820000, 229 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  830000, 252 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  840000, 275 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  850000, 298 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  860000, 321 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  870000, 346 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  875000, 371 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  885000, 397 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  895000, 423 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  905000, 450 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  915000, 477 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  920000, 506 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  930000, 536 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  940000, 567 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  950000, 598 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  400000 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000, 3200000 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  760000, 3200000 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  770000, 3200000 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  780000, 3200000 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  790000, 3200000 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  800000, 3200000 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  810000, 3200000 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  820000, 3200000 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  830000, 3200000 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  840000, 3200000 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  850000, 3200000 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  860000, 3200000 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  870000, 3200000 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  875000, 3200000 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  885000, 3200000 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  895000, 3200000 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  905000, 3200000 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  915000, 3200000 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  920000, 3200000 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  930000, 3200000 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  940000, 3200000 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  950000, 3200000 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_2p2g_pvs0[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  800000,  72 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  800000,  83 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  805000, 102 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  815000, 121 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  825000, 141 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  835000, 161 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  845000, 181 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  855000, 202 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  865000, 223 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  875000, 245 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  890000, 267 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  900000, 289 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  915000, 313 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  925000, 336 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  940000, 360 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  950000, 383 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  965000, 409 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  980000, 435 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  995000, 461 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18), 1010000, 488 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18), 1025000, 516 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1040000, 543 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1055000, 573 },
-	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1070000, 604 },
-	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1085000, 636 },
-	{ 1, { 2150400, HFPLL, 1, 112 }, L2(19), 1100000, 656 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  800000,  400000 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  800000, 3200000 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  805000, 3200000 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  815000, 3200000 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  825000, 3200000 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  835000, 3200000 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  845000, 3200000 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  855000, 3200000 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  865000, 3200000 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  875000, 3200000 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  890000, 3200000 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  900000, 3200000 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  915000, 3200000 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  925000, 3200000 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  940000, 3200000 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  950000, 3200000 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  965000, 3200000 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  980000, 3200000 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  995000, 3200000 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18), 1010000, 3200000 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18), 1025000, 3200000 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1040000, 3200000 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1055000, 3200000 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1070000, 3200000 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1085000, 3200000 },
+	{ 1, { 2150400, HFPLL, 1, 112 }, L2(19), 1100000, 3200000 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_2p2g_pvs1[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  800000,  72 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  800000,  83 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  800000, 102 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  800000, 121 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  810000, 141 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  820000, 161 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  830000, 181 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  840000, 202 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  850000, 223 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  860000, 245 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  875000, 267 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  885000, 289 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  895000, 313 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  910000, 336 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  920000, 360 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  930000, 383 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  945000, 409 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  960000, 435 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  975000, 461 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  990000, 488 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18), 1005000, 516 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1020000, 543 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1030000, 573 },
-	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1045000, 604 },
-	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1060000, 636 },
-	{ 1, { 2150400, HFPLL, 1, 112 }, L2(19), 1075000, 656 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  800000,  400000 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  800000, 3200000 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  800000, 3200000 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  800000, 3200000 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  810000, 3200000 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  820000, 3200000 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  830000, 3200000 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  840000, 3200000 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  850000, 3200000 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  860000, 3200000 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  875000, 3200000 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  885000, 3200000 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  895000, 3200000 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  910000, 3200000 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  920000, 3200000 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  930000, 3200000 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  945000, 3200000 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  960000, 3200000 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  975000, 3200000 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  990000, 3200000 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18), 1005000, 3200000 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1020000, 3200000 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1030000, 3200000 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1045000, 3200000 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1060000, 3200000 },
+	{ 1, { 2150400, HFPLL, 1, 112 }, L2(19), 1075000, 3200000 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_2p2g_pvs2[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  72 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000,  83 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  775000, 102 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  785000, 121 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  795000, 141 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  805000, 161 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  815000, 181 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  825000, 202 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  835000, 223 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  845000, 245 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  855000, 267 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  865000, 289 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  875000, 313 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  890000, 336 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  900000, 360 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  910000, 383 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  925000, 409 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  940000, 435 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  955000, 461 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  970000, 488 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  980000, 516 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  995000, 543 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1005000, 573 },
-	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1020000, 604 },
-	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1035000, 636 },
-	{ 1, { 2150400, HFPLL, 1, 112 }, L2(19), 1050000, 656 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  400000 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000, 3200000 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  775000, 3200000 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  785000, 3200000 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  795000, 3200000 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  805000, 3200000 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  815000, 3200000 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  825000, 3200000 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  835000, 3200000 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  845000, 3200000 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  855000, 3200000 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  865000, 3200000 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  875000, 3200000 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  890000, 3200000 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  900000, 3200000 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  910000, 3200000 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  925000, 3200000 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  940000, 3200000 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  955000, 3200000 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  970000, 3200000 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  980000, 3200000 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  995000, 3200000 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1005000, 3200000 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1020000, 3200000 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1035000, 3200000 },
+	{ 1, { 2150400, HFPLL, 1, 112 }, L2(19), 1050000, 3200000 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_2p2g_pvs3[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  72 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000,  83 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  775000, 102 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  775000, 121 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  780000, 141 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  790000, 161 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  800000, 181 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  810000, 202 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  820000, 223 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  830000, 245 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  840000, 267 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  850000, 289 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  860000, 313 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  875000, 336 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  885000, 360 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  895000, 383 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  910000, 409 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  925000, 435 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  935000, 461 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  950000, 488 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  960000, 516 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  970000, 543 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  985000, 573 },
-	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  995000, 604 },
-	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1010000, 636 },
-	{ 1, { 2150400, HFPLL, 1, 112 }, L2(19), 1025000, 656 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  400000 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000, 3200000 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  775000, 3200000 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  775000, 3200000 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  780000, 3200000 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  790000, 3200000 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  800000, 3200000 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  810000, 3200000 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  820000, 3200000 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  830000, 3200000 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  840000, 3200000 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  850000, 3200000 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  860000, 3200000 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  875000, 3200000 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  885000, 3200000 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  895000, 3200000 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  910000, 3200000 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  925000, 3200000 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  935000, 3200000 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  950000, 3200000 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  960000, 3200000 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  970000, 3200000 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  985000, 3200000 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  995000, 3200000 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1010000, 3200000 },
+	{ 1, { 2150400, HFPLL, 1, 112 }, L2(19), 1025000, 3200000 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_2p2g_pvs4[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  72 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000,  83 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  775000, 102 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  775000, 121 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  775000, 141 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  780000, 161 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  790000, 181 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  800000, 202 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  810000, 223 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  820000, 245 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  830000, 267 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  840000, 289 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  850000, 313 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  860000, 336 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  870000, 360 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  880000, 383 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  895000, 409 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  910000, 435 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  920000, 461 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  930000, 488 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  940000, 516 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  950000, 543 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  960000, 573 },
-	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  975000, 604 },
-	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  985000, 636 },
-	{ 1, { 2150400, HFPLL, 1, 112 }, L2(19), 1000000, 656 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  400000 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000, 3200000 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  775000, 3200000 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  775000, 3200000 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  775000, 3200000 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  780000, 3200000 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  790000, 3200000 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  800000, 3200000 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  810000, 3200000 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  820000, 3200000 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  830000, 3200000 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  840000, 3200000 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  850000, 3200000 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  860000, 3200000 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  870000, 3200000 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  880000, 3200000 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  895000, 3200000 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  910000, 3200000 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  920000, 3200000 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  930000, 3200000 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  940000, 3200000 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  950000, 3200000 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  960000, 3200000 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  975000, 3200000 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  985000, 3200000 },
+	{ 1, { 2150400, HFPLL, 1, 112 }, L2(19), 1000000, 3200000 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_2p2g_pvs5[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  72 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000,  83 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  750000, 102 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  750000, 121 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  760000, 141 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  770000, 161 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  780000, 181 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  790000, 202 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  800000, 223 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  810000, 245 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  820000, 267 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  830000, 289 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  840000, 313 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  850000, 336 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  860000, 360 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  870000, 383 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  880000, 409 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  890000, 435 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  900000, 461 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  910000, 488 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  920000, 516 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  930000, 543 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  940000, 573 },
-	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  955000, 604 },
-	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  965000, 636 },
-	{ 1, { 2150400, HFPLL, 1, 112 }, L2(19),  975000, 656 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  400000 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000, 3200000 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  750000, 3200000 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  750000, 3200000 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  760000, 3200000 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  770000, 3200000 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  780000, 3200000 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  790000, 3200000 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  800000, 3200000 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  810000, 3200000 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  820000, 3200000 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  830000, 3200000 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  840000, 3200000 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  850000, 3200000 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  860000, 3200000 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  870000, 3200000 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  880000, 3200000 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  890000, 3200000 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  900000, 3200000 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  910000, 3200000 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  920000, 3200000 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  930000, 3200000 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  940000, 3200000 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  955000, 3200000 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  965000, 3200000 },
+	{ 1, { 2150400, HFPLL, 1, 112 }, L2(19),  975000, 3200000 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_2p2g_pvs6[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  72 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000,  83 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  750000, 102 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  750000, 121 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  750000, 141 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  760000, 161 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  770000, 181 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  780000, 202 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  790000, 223 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  800000, 245 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  810000, 267 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  820000, 289 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  830000, 313 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  840000, 336 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  850000, 360 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  860000, 383 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  870000, 409 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  875000, 435 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  885000, 461 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  895000, 488 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  905000, 516 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  915000, 543 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  920000, 573 },
-	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  930000, 604 },
-	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  940000, 636 },
-	{ 1, { 2150400, HFPLL, 1, 112 }, L2(19),  950000, 656 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  400000 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000, 3200000 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  750000, 3200000 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  750000, 3200000 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  750000, 3200000 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  760000, 3200000 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  770000, 3200000 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  780000, 3200000 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  790000, 3200000 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  800000, 3200000 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  810000, 3200000 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  820000, 3200000 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  830000, 3200000 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  840000, 3200000 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  850000, 3200000 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  860000, 3200000 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  870000, 3200000 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  875000, 3200000 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  885000, 3200000 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  895000, 3200000 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  905000, 3200000 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  915000, 3200000 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  920000, 3200000 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  930000, 3200000 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  940000, 3200000 },
+	{ 1, { 2150400, HFPLL, 1, 112 }, L2(19),  950000, 3200000 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_2p3g_pvs0[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  800000,  72 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  800000,  83 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  800000, 101 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  805000, 120 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  815000, 139 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  825000, 159 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  835000, 180 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  845000, 200 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  855000, 221 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  865000, 242 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  875000, 264 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  890000, 287 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  900000, 308 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  915000, 333 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  925000, 356 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  940000, 380 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  950000, 404 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  965000, 430 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  980000, 456 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  995000, 482 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18), 1010000, 510 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1025000, 538 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1040000, 565 },
-	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1055000, 596 },
-	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1070000, 627 },
-	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1085000, 659 },
-	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1100000, 691 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  800000,  400000 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  800000, 3200000 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  800000, 3200000 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  805000, 3200000 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  815000, 3200000 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  825000, 3200000 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  835000, 3200000 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  845000, 3200000 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  855000, 3200000 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  865000, 3200000 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  875000, 3200000 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  890000, 3200000 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  900000, 3200000 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  915000, 3200000 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  925000, 3200000 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  940000, 3200000 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  950000, 3200000 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  965000, 3200000 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  980000, 3200000 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  995000, 3200000 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18), 1010000, 3200000 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1025000, 3200000 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1040000, 3200000 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1055000, 3200000 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1070000, 3200000 },
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1085000, 3200000 },
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1100000, 3200000 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_2p3g_pvs1[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  800000,  72 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  800000,  83 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  800000, 101 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  800000, 120 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  800000, 139 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  810000, 159 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  820000, 180 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  830000, 200 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  840000, 221 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  850000, 242 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  860000, 264 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  875000, 287 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  885000, 308 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  895000, 333 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  910000, 356 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  920000, 380 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  930000, 404 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  945000, 430 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  960000, 456 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  975000, 482 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  990000, 510 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1005000, 538 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1020000, 565 },
-	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1030000, 596 },
-	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1045000, 627 },
-	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1060000, 659 },
-	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1075000, 691 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  800000,  400000 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  800000, 3200000 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  800000, 3200000 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  800000, 3200000 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  800000, 3200000 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  810000, 3200000 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  820000, 3200000 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  830000, 3200000 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  840000, 3200000 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  850000, 3200000 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  860000, 3200000 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  875000, 3200000 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  885000, 3200000 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  895000, 3200000 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  910000, 3200000 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  920000, 3200000 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  930000, 3200000 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  945000, 3200000 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  960000, 3200000 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  975000, 3200000 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  990000, 3200000 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1005000, 3200000 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1020000, 3200000 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1030000, 3200000 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1045000, 3200000 },
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1060000, 3200000 },
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1075000, 3200000 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_2p3g_pvs2[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  72 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000,  83 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  775000, 101 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  775000, 120 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  785000, 139 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  795000, 159 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  805000, 180 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  815000, 200 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  825000, 221 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  835000, 242 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  845000, 264 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  855000, 287 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  865000, 308 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  875000, 333 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  890000, 356 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  900000, 380 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  910000, 404 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  925000, 430 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  940000, 456 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  955000, 482 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  970000, 510 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  980000, 538 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  995000, 565 },
-	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1005000, 596 },
-	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1020000, 627 },
-	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1035000, 659 },
-	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1050000, 691 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  400000 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000, 3200000 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  775000, 3200000 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  775000, 3200000 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  785000, 3200000 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  795000, 3200000 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  805000, 3200000 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  815000, 3200000 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  825000, 3200000 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  835000, 3200000 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  845000, 3200000 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  855000, 3200000 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  865000, 3200000 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  875000, 3200000 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  890000, 3200000 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  900000, 3200000 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  910000, 3200000 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  925000, 3200000 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  940000, 3200000 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  955000, 3200000 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  970000, 3200000 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  980000, 3200000 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  995000, 3200000 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1005000, 3200000 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1020000, 3200000 },
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1035000, 3200000 },
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1050000, 3200000 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_2p3g_pvs3[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  72 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000,  83 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  775000, 101 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  775000, 120 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  775000, 139 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  780000, 159 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  790000, 180 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  800000, 200 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  810000, 221 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  820000, 242 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  830000, 264 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  840000, 287 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  850000, 308 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  860000, 333 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  875000, 356 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  885000, 380 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  895000, 404 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  910000, 430 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  925000, 456 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  935000, 482 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  950000, 510 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  960000, 538 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  970000, 565 },
-	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  985000, 596 },
-	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  995000, 627 },
-	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1010000, 659 },
-	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1025000, 691 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  400000 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000, 3200000 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  775000, 3200000 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  775000, 3200000 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  775000, 3200000 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  780000, 3200000 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  790000, 3200000 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  800000, 3200000 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  810000, 3200000 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  820000, 3200000 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  830000, 3200000 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  840000, 3200000 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  850000, 3200000 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  860000, 3200000 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  875000, 3200000 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  885000, 3200000 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  895000, 3200000 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  910000, 3200000 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  925000, 3200000 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  935000, 3200000 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  950000, 3200000 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  960000, 3200000 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  970000, 3200000 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  985000, 3200000 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  995000, 3200000 },
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1010000, 3200000 },
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1025000, 3200000 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_2p3g_pvs4[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  72 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000,  83 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  775000, 101 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  775000, 120 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  775000, 139 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  775000, 159 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  780000, 180 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  790000, 200 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  800000, 221 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  810000, 242 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  820000, 264 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  830000, 287 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  840000, 308 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  850000, 333 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  860000, 356 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  870000, 380 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  880000, 404 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  895000, 430 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  910000, 456 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  920000, 482 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  930000, 510 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  940000, 538 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  950000, 565 },
-	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  960000, 596 },
-	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  975000, 627 },
-	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  985000, 659 },
-	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1000000, 691 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  400000 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000, 3200000 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  775000, 3200000 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  775000, 3200000 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  775000, 3200000 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  775000, 3200000 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  780000, 3200000 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  790000, 3200000 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  800000, 3200000 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  810000, 3200000 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  820000, 3200000 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  830000, 3200000 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  840000, 3200000 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  850000, 3200000 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  860000, 3200000 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  870000, 3200000 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  880000, 3200000 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  895000, 3200000 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  910000, 3200000 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  920000, 3200000 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  930000, 3200000 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  940000, 3200000 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  950000, 3200000 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  960000, 3200000 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  975000, 3200000 },
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  985000, 3200000 },
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1000000, 3200000 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_2p3g_pvs5[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  72 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000,  83 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  750000, 101 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  750000, 120 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  750000, 139 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  760000, 159 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  770000, 180 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  780000, 200 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  790000, 221 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  800000, 242 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  810000, 264 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  820000, 287 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  830000, 308 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  840000, 333 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  850000, 356 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  860000, 380 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  870000, 404 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  880000, 430 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  890000, 456 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  900000, 482 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  910000, 510 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  920000, 538 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  930000, 565 },
-	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  940000, 596 },
-	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  955000, 627 },
-	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  965000, 659 },
-	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  975000, 691 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  400000 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000, 3200000 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  750000, 3200000 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  750000, 3200000 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  750000, 3200000 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  760000, 3200000 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  770000, 3200000 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  780000, 3200000 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  790000, 3200000 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  800000, 3200000 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  810000, 3200000 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  820000, 3200000 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  830000, 3200000 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  840000, 3200000 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  850000, 3200000 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  860000, 3200000 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  870000, 3200000 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  880000, 3200000 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  890000, 3200000 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  900000, 3200000 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  910000, 3200000 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  920000, 3200000 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  930000, 3200000 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  940000, 3200000 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  955000, 3200000 },
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  965000, 3200000 },
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  975000, 3200000 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_2p3g_pvs6[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  72 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000,  83 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  750000, 101 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  750000, 120 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  750000, 139 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  750000, 159 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  760000, 180 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  770000, 200 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  780000, 221 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  790000, 242 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  800000, 264 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  810000, 287 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  820000, 308 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  830000, 333 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  840000, 356 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  850000, 380 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  860000, 404 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  870000, 430 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  875000, 456 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  885000, 482 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  895000, 510 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  905000, 538 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  915000, 565 },
-	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  920000, 596 },
-	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  930000, 627 },
-	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  940000, 659 },
-	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  950000, 691 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  400000 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000, 3200000 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  750000, 3200000 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  750000, 3200000 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  750000, 3200000 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  750000, 3200000 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  760000, 3200000 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  770000, 3200000 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  780000, 3200000 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  790000, 3200000 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  800000, 3200000 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  810000, 3200000 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  820000, 3200000 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  830000, 3200000 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  840000, 3200000 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  850000, 3200000 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  860000, 3200000 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  870000, 3200000 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  875000, 3200000 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  885000, 3200000 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  895000, 3200000 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  905000, 3200000 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  915000, 3200000 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  920000, 3200000 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  930000, 3200000 },
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  940000, 3200000 },
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  950000, 3200000 },
 	{ 0, { 0 } }
 };
 
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index a0644e6..bed794b 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -913,8 +913,10 @@
 	if (!bam_is_connected) {
 		read_unlock(&ul_wakeup_lock);
 		ul_wakeup();
-		if (unlikely(in_global_reset == 1))
+		if (unlikely(in_global_reset == 1)) {
+			kfree(hdr);
 			return -EFAULT;
+		}
 		read_lock(&ul_wakeup_lock);
 		notify_all(BAM_DMUX_UL_CONNECTED, (unsigned long)(NULL));
 	}
@@ -1384,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) {
@@ -1756,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-8064.c b/arch/arm/mach-msm/board-8064.c
index 0fe94d5..f969e31 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -437,7 +437,7 @@
 
 			if (fixed_position != NOT_FIXED)
 				fixed_size += heap->size;
-			else
+			else if (!use_cma)
 				reserve_mem_for_ion(MEMTYPE_EBI1, heap->size);
 
 			if (fixed_position == FIXED_LOW) {
@@ -3585,6 +3585,18 @@
 	if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917)
 		apq8064_pm8917_pdata_fixup();
 	platform_device_register(&msm_gpio_device);
+	if (cpu_is_apq8064ab())
+		apq8064ab_update_krait_spm();
+	if (cpu_is_krait_v3()) {
+		struct msm_pm_init_data_type *pdata =
+		msm8064_pm_8x60.dev.platform_data;
+		pdata->retention_calls_tz = false;
+		apq8064ab_update_retention_spm();
+	}
+	platform_device_register(&msm8064_pm_8x60);
+
+	msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
+	msm_spm_l2_init(msm_spm_l2_data);
 	msm_tsens_early_init(&apq_tsens_pdata);
 	msm_thermal_init(&msm_thermal_pdata);
 	if (socinfo_init() < 0)
@@ -3699,18 +3711,6 @@
 		apq8064_init_dsps();
 		platform_device_register(&msm_8960_riva);
 	}
-	if (cpu_is_apq8064ab())
-		apq8064ab_update_krait_spm();
-	if (cpu_is_krait_v3()) {
-		struct msm_pm_init_data_type *pdata =
-			msm8064_pm_8x60.dev.platform_data;
-		pdata->retention_calls_tz = false;
-		apq8064ab_update_retention_spm();
-	}
-	platform_device_register(&msm8064_pm_8x60);
-
-	msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
-	msm_spm_l2_init(msm_spm_l2_data);
 	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
 	apq8064_epm_adc_init();
 }
diff --git a/arch/arm/mach-msm/board-8610.c b/arch/arm/mach-msm/board-8610.c
index 67334d5..2cd7134 100644
--- a/arch/arm/mach-msm/board-8610.c
+++ b/arch/arm/mach-msm/board-8610.c
@@ -44,6 +44,7 @@
 #include <mach/clk-provider.h>
 #include <mach/msm_smd.h>
 #include <mach/rpm-smd.h>
+#include <mach/rpm-regulator-smd.h>
 #include <linux/msm_thermal.h>
 #include "board-dt.h"
 #include "clock.h"
@@ -105,6 +106,7 @@
 	msm_rpm_driver_init();
 	msm_lpmrs_module_init();
 	msm_spm_device_init();
+	rpm_regulator_smd_driver_init();
 	qpnp_regulator_init();
 	tsens_tm_init_driver();
 	msm_thermal_device_init();
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 8be128c..6ccaba6 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -477,7 +477,7 @@
 
 			if (fixed_position != NOT_FIXED)
 				fixed_size += heap->size;
-			else
+			else if (!use_cma)
 				reserve_mem_for_ion(MEMTYPE_EBI1, heap->size);
 
 			if (fixed_position == FIXED_LOW) {
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index c5fc418..5d96389 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -532,7 +532,7 @@
 
 			if (fixed_position != NOT_FIXED)
 				fixed_size += heap->size;
-			else
+			else if (!use_cma)
 				reserve_mem_for_ion(MEMTYPE_EBI1, heap->size);
 
 			if (fixed_position == FIXED_LOW) {
diff --git a/arch/arm/mach-msm/board-9625-gpiomux.c b/arch/arm/mach-msm/board-9625-gpiomux.c
index 75aaaec..a6ac986 100644
--- a/arch/arm/mach-msm/board-9625-gpiomux.c
+++ b/arch/arm/mach-msm/board-9625-gpiomux.c
@@ -276,6 +276,7 @@
 	},
 };
 
+#ifdef CONFIG_FB_MSM_QPIC
 static struct gpiomux_setting qpic_lcdc_a_d = {
 	.func = GPIOMUX_FUNC_1,
 	.drv = GPIOMUX_DRV_10MA,
@@ -327,6 +328,17 @@
 	},
 };
 
+static void msm9625_disp_init_gpiomux(void)
+{
+	msm_gpiomux_install(msm9625_qpic_lcdc_configs,
+			ARRAY_SIZE(msm9625_qpic_lcdc_configs));
+}
+#else
+static void msm9625_disp_init_gpiomux(void)
+{
+}
+#endif /* CONFIG_FB_MSM_QPIC */
+
 void __init msm9625_init_gpiomux(void)
 {
 	int rc;
@@ -347,7 +359,5 @@
 			ARRAY_SIZE(mdm9625_cdc_reset_config));
 	msm_gpiomux_install(sdc2_card_det_config,
 		ARRAY_SIZE(sdc2_card_det_config));
-	msm_gpiomux_install(msm9625_qpic_lcdc_configs,
-			ARRAY_SIZE(msm9625_qpic_lcdc_configs));
-
+	msm9625_disp_init_gpiomux();
 }
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index 5f9eafd..18c922d 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -3060,7 +3060,7 @@
 
 	/* WCNSS CLOCKS */
 	CLK_LOOKUP("xo", cxo_wlan_clk.c, "fb000000.qcom,wcnss-wlan"),
-	CLK_LOOKUP("rf_clk",   cxo_a2.c, "fb000000.qcom,wcnss-wlan"),
+	CLK_LOOKUP("rf_clk",   cxo_a1.c, "fb000000.qcom,wcnss-wlan"),
 
 	/* BUS DRIVER */
 	CLK_LOOKUP("bus_clk", cnoc_msmbus_clk.c, "msm_config_noc"),
@@ -3328,6 +3328,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 2e35d8a..fae09d0 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -462,9 +462,9 @@
 
 #define D0_ID		 1
 #define D1_ID		 2
-#define A0_ID		 3
-#define A1_ID		 4
-#define A2_ID		 5
+#define A0_ID		 4
+#define A1_ID		 5
+#define A2_ID		 6
 #define DIFF_CLK_ID	 7
 #define DIV_CLK_ID	11
 
@@ -2620,6 +2620,10 @@
 	CLK_LOOKUP("core_clk", qdss_clk.c, "fc352000.cti"),
 	CLK_LOOKUP("core_clk", qdss_clk.c, "fc353000.cti"),
 	CLK_LOOKUP("core_clk", qdss_clk.c, "fc354000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc34c000.jtagmm"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc34d000.jtagmm"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc34e000.jtagmm"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc34f000.jtagmm"),
 
 
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc326000.tmc"),
@@ -2649,6 +2653,10 @@
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc352000.cti"),
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc353000.cti"),
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc354000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc34c000.jtagmm"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc34d000.jtagmm"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc34e000.jtagmm"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc34f000.jtagmm"),
 
 
 
@@ -2706,7 +2714,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"),
@@ -2804,7 +2812,7 @@
 	CLK_LOOKUP("measure_clk",   l2_m_clk, ""),
 
 	CLK_LOOKUP("xo",   gcc_xo_clk_src.c, "fb000000.qcom,wcnss-wlan"),
-	CLK_LOOKUP("rf_clk",       cxo_a2.c, "fb000000.qcom,wcnss-wlan"),
+	CLK_LOOKUP("rf_clk",       cxo_a1.c, "fb000000.qcom,wcnss-wlan"),
 
 	CLK_LOOKUP("iface_clk", mdp_ahb_clk.c, "fd900000.qcom,mdss_mdp"),
 	CLK_LOOKUP("core_clk", mdp_axi_clk.c, "fd900000.qcom,mdss_mdp"),
@@ -2822,6 +2830,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 73e44b1..2de8799 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -4757,7 +4757,8 @@
 	CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f991f000.serial"),
 	CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9924000.i2c"),
 	CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f991e000.serial"),
-	CLK_LOOKUP("core_clk", gcc_blsp1_qup1_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup1_i2c_apps_clk.c, "f9923000.i2c"),
+	CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9923000.i2c"),
 	CLK_LOOKUP("core_clk", gcc_blsp1_qup2_i2c_apps_clk.c, "f9924000.i2c"),
 	CLK_LOOKUP("core_clk", gcc_blsp1_qup2_spi_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk", gcc_blsp1_qup1_spi_apps_clk.c, "f9923000.spi"),
@@ -5012,14 +5013,6 @@
 	/* 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/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/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/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index d81dbb4..0d617a6 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -1587,9 +1587,11 @@
 				if (!rport_ptr)
 					pr_err("%s: Remote port create "
 					       "failed\n", __func__);
-				rport_ptr->sec_rule =
-					msm_ipc_get_security_rule(
-					msg->srv.service, msg->srv.instance);
+				else
+					rport_ptr->sec_rule =
+						msm_ipc_get_security_rule(
+						msg->srv.service,
+						msg->srv.instance);
 			}
 			wake_up(&newserver_wait);
 		}
@@ -1890,6 +1892,7 @@
 	head_skb = skb_peek(pkt->pkt_fragment_q);
 	if (!head_skb) {
 		pr_err("%s: pkt_fragment_q is empty\n", __func__);
+		release_pkt(pkt);
 		return -EINVAL;
 	}
 	hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
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/ipc_socket.c b/arch/arm/mach-msm/ipc_socket.c
index c0422a1..342663e 100644
--- a/arch/arm/mach-msm/ipc_socket.c
+++ b/arch/arm/mach-msm/ipc_socket.c
@@ -367,7 +367,8 @@
 	if (port_ptr->type == CLIENT_PORT)
 		wait_for_irsc_completion();
 	ipc_buf = skb_peek(msg);
-	msm_ipc_router_ipc_log(IPC_SEND, ipc_buf, port_ptr);
+	if (ipc_buf)
+		msm_ipc_router_ipc_log(IPC_SEND, ipc_buf, port_ptr);
 	ret = msm_ipc_router_send_to(port_ptr, msg, &dest->address);
 	if (ret == (IPC_ROUTER_HDR_SIZE + total_len))
 		ret = total_len;
@@ -429,7 +430,8 @@
 
 	ret = msm_ipc_router_extract_msg(m, msg);
 	ipc_buf = skb_peek(msg);
-	msm_ipc_router_ipc_log(IPC_RECV, ipc_buf, port_ptr);
+	if (ipc_buf)
+		msm_ipc_router_ipc_log(IPC_RECV, ipc_buf, port_ptr);
 	msm_ipc_router_release_msg(msg);
 	msg = NULL;
 	release_sock(sk);
diff --git a/arch/arm/mach-msm/krait-regulator.c b/arch/arm/mach-msm/krait-regulator.c
index af2fbab..953f941d 100644
--- a/arch/arm/mach-msm/krait-regulator.c
+++ b/arch/arm/mach-msm/krait-regulator.c
@@ -61,7 +61,9 @@
 #define PMIC_VOLTAGE_MAX		1355000
 #define LV_RANGE_STEP			5000
 
-#define CORE_VOLTAGE_BOOTUP		900000
+#define LOAD_PER_PHASE			3200000
+
+#define CORE_VOLTAGE_MIN		900000
 
 #define KRAIT_LDO_VOLTAGE_MIN		465000
 #define KRAIT_LDO_VOLTAGE_OFFSET	465000
@@ -133,7 +135,6 @@
 #define LDO_DELTA_MIN		10000
 #define LDO_DELTA_MAX		100000
 
-#define MSM_L2_SAW_PHYS		0xf9012000
 /**
  * struct pmic_gang_vreg -
  * @name:			the string used to represent the gang
@@ -145,10 +146,7 @@
  *				regulator's callback functions to prevent
  *				simultaneous updates to the pmic's phase
  *				voltage.
- * @apcs_gcc_base:		virtual address of the APCS GCC registers
- * @manage_phases:		begin phase control
- * @pfm_threshold:		the sum of coefficients below which PFM can be
- *				enabled
+ * @apcs_gcc_base		virtual address of the APCS GCC registers
  */
 struct pmic_gang_vreg {
 	const char		*name;
@@ -161,8 +159,6 @@
 	bool			retention_enabled;
 	bool			use_phase_switching;
 	void __iomem		*apcs_gcc_base;
-	bool			manage_phases;
-	int			pfm_threshold;
 };
 
 static struct pmic_gang_vreg *the_gang;
@@ -172,9 +168,6 @@
 	LDO_MODE = REGULATOR_MODE_IDLE,
 };
 
-#define WAIT_FOR_LOAD		0x2
-#define WAIT_FOR_VOLTAGE	0x1
-
 struct krait_power_vreg {
 	struct list_head		link;
 	struct regulator_desc		desc;
@@ -182,7 +175,7 @@
 	const char			*name;
 	struct pmic_gang_vreg		*pvreg;
 	int				uV;
-	int				load;
+	int				load_uA;
 	enum krait_supply_mode		mode;
 	void __iomem			*reg_base;
 	void __iomem			*mdd_base;
@@ -192,10 +185,7 @@
 	int				ldo_threshold_uV;
 	int				ldo_delta_uV;
 	int				cpu_num;
-	int				coeff1;
-	int				coeff2;
 	bool				online;
-	int				online_at_probe;
 };
 
 DEFINE_PER_CPU(struct krait_power_vreg *, krait_vregs);
@@ -303,229 +293,6 @@
 	return 0;
 }
 
-#define COEFF2_UV_THRESHOLD 850000
-static int get_coeff2(int krait_uV)
-{
-	int coeff2 = 0;
-	int krait_mV = krait_uV / 1000;
-
-	if (krait_uV <= COEFF2_UV_THRESHOLD)
-		coeff2 = (612229 * krait_mV) / 1000 - 211258;
-	else
-		coeff2 = (892564 * krait_mV) / 1000 - 449543;
-
-	return  coeff2;
-}
-
-static int get_coeff1(int actual_uV, int requested_uV, int load)
-{
-	int ratio = actual_uV * 1000 / requested_uV;
-	int coeff1 = 330 * load + (load * 673 * ratio / 1000);
-
-	return coeff1;
-}
-
-static int get_coeff_total(struct krait_power_vreg *from)
-{
-	int coeff_total = 0;
-	struct krait_power_vreg *kvreg;
-	struct pmic_gang_vreg *pvreg = from->pvreg;
-
-	list_for_each_entry(kvreg, &pvreg->krait_power_vregs, link) {
-		if (!kvreg->online)
-			continue;
-
-		if (kvreg->mode == LDO_MODE) {
-			kvreg->coeff1 =
-				get_coeff1(kvreg->uV - kvreg->ldo_delta_uV,
-							kvreg->uV, kvreg->load);
-			kvreg->coeff2 =
-				get_coeff2(kvreg->uV - kvreg->ldo_delta_uV);
-		} else {
-			kvreg->coeff1 =
-				get_coeff1(pvreg->pmic_vmax_uV,
-							kvreg->uV, kvreg->load);
-			kvreg->coeff2 = get_coeff2(pvreg->pmic_vmax_uV);
-		}
-		coeff_total += kvreg->coeff1 + kvreg->coeff2;
-	}
-
-	return coeff_total;
-}
-
-static int set_pmic_gang_phases(struct pmic_gang_vreg *pvreg, int phase_count)
-{
-	pr_debug("programming phase_count = %d\n", phase_count);
-	if (pvreg->use_phase_switching)
-		/*
-		 * note the PMIC sets the phase count to one more than
-		 * the value in the register - hence subtract 1 from it
-		 */
-		return msm_spm_apcs_set_phase(phase_count - 1);
-	else
-		return 0;
-}
-
-static int num_online(struct pmic_gang_vreg *pvreg)
-{
-	int online_total = 0;
-	struct krait_power_vreg *kvreg;
-
-	list_for_each_entry(kvreg, &pvreg->krait_power_vregs, link) {
-		if (kvreg->online)
-			online_total++;
-	}
-	return online_total;
-}
-
-static bool enable_phase_management(struct pmic_gang_vreg *pvreg)
-{
-	struct krait_power_vreg *kvreg;
-
-	list_for_each_entry(kvreg, &pvreg->krait_power_vregs, link) {
-		pr_debug("%s online_at_probe:0x%x\n", kvreg->name,
-							kvreg->online_at_probe);
-		if (kvreg->online_at_probe)
-			return false;
-	}
-	return true;
-}
-
-#define PMIC_FTS_MODE_PFM	0x00
-#define PMIC_FTS_MODE_PWM	0x80
-#define ONE_PHASE_COEFF		1000000
-#define TWO_PHASE_COEFF		2000000
-
-#define PHASE_SETTLING_TIME_US		10
-static unsigned int pmic_gang_set_phases(struct krait_power_vreg *from,
-				int coeff_total)
-{
-	struct pmic_gang_vreg *pvreg = from->pvreg;
-	int phase_count;
-	int rc = 0;
-	int n_online = num_online(pvreg);
-
-	if (pvreg->manage_phases == false) {
-		if (enable_phase_management(pvreg))
-			pvreg->manage_phases = true;
-		else
-			return 0;
-	}
-
-	/* First check if the coeff is low for PFM mode */
-	if (coeff_total < pvreg->pfm_threshold && n_online == 1) {
-		if (!pvreg->pfm_mode) {
-			rc = msm_spm_enable_fts_lpm(PMIC_FTS_MODE_PFM);
-			if (rc) {
-				pr_err("%s PFM en failed coeff_t %d rc = %d\n",
-					from->name, coeff_total, rc);
-				return rc;
-			} else {
-				pvreg->pfm_mode = true;
-			}
-		}
-		return rc;
-	}
-
-	/* coeff is high switch to PWM mode before changing phases */
-	if (pvreg->pfm_mode) {
-		rc = msm_spm_enable_fts_lpm(PMIC_FTS_MODE_PWM);
-		if (rc) {
-			pr_err("%s PFM exit failed load %d rc = %d\n",
-				from->name, coeff_total, rc);
-			return rc;
-		} else {
-			pvreg->pfm_mode = false;
-		}
-	}
-
-	/* calculate phases */
-	if (coeff_total < ONE_PHASE_COEFF)
-		phase_count = 1;
-	else if (coeff_total < TWO_PHASE_COEFF)
-		phase_count = 2;
-	else
-		phase_count = 4;
-
-	/* don't increase the phase count higher than number of online cpus */
-	if (phase_count > n_online)
-		phase_count = n_online;
-
-	if (phase_count != pvreg->pmic_phase_count) {
-		rc = set_pmic_gang_phases(pvreg, phase_count);
-		if (rc < 0) {
-			pr_err("%s failed set phase %d rc = %d\n",
-				from->name, phase_count, rc);
-			return rc;
-		}
-
-		/* complete the writes before the delay */
-		mb();
-
-		/*
-		 * delay until the phases are settled when
-		 * the count is raised
-		 */
-		if (phase_count > pvreg->pmic_phase_count)
-			udelay(PHASE_SETTLING_TIME_US);
-
-		pvreg->pmic_phase_count = phase_count;
-	}
-
-	return rc;
-}
-
-static unsigned int _get_optimum_mode(struct regulator_dev *rdev,
-			int input_uV, int output_uV, int load)
-{
-	struct krait_power_vreg *kvreg = rdev_get_drvdata(rdev);
-	int coeff_total;
-	int rc;
-
-	kvreg->online_at_probe &= ~WAIT_FOR_LOAD;
-	coeff_total = get_coeff_total(kvreg);
-
-	rc = pmic_gang_set_phases(kvreg, coeff_total);
-	if (rc < 0) {
-		dev_err(&rdev->dev, "%s failed set mode %d rc = %d\n",
-				kvreg->name, coeff_total, rc);
-	}
-
-	return kvreg->mode;
-}
-
-static unsigned int krait_power_get_optimum_mode(struct regulator_dev *rdev,
-			int input_uV, int output_uV, int load_uA)
-{
-	struct krait_power_vreg *kvreg = rdev_get_drvdata(rdev);
-	struct pmic_gang_vreg *pvreg = kvreg->pvreg;
-	int rc;
-
-	mutex_lock(&pvreg->krait_power_vregs_lock);
-	kvreg->load = load_uA;
-	if (!kvreg->online) {
-		mutex_unlock(&pvreg->krait_power_vregs_lock);
-		return kvreg->mode;
-	}
-
-	rc = _get_optimum_mode(rdev, input_uV, output_uV, load_uA);
-	mutex_unlock(&pvreg->krait_power_vregs_lock);
-
-	return rc;
-}
-
-static int krait_power_set_mode(struct regulator_dev *rdev, unsigned int mode)
-{
-	return 0;
-}
-
-static unsigned int krait_power_get_mode(struct regulator_dev *rdev)
-{
-	struct krait_power_vreg *kvreg = rdev_get_drvdata(rdev);
-
-	return kvreg->mode;
-}
-
 static int switch_to_using_hs(struct krait_power_vreg *kvreg)
 {
 	if (kvreg->mode == HS_MODE)
@@ -601,6 +368,19 @@
 	return 0;
 }
 
+static int set_pmic_gang_phases(struct pmic_gang_vreg *pvreg, int phase_count)
+{
+	pr_debug("programming phase_count = %d\n", phase_count);
+	if (pvreg->use_phase_switching)
+		/*
+		 * note the PMIC sets the phase count to one more than
+		 * the value in the register - hence subtract 1 from it
+		 */
+		return msm_spm_apcs_set_phase(phase_count - 1);
+	else
+		return 0;
+}
+
 static int set_pmic_gang_voltage(struct pmic_gang_vreg *pvreg, int uV)
 {
 	int setpoint;
@@ -744,6 +524,46 @@
 	return rc;
 }
 
+#define PHASE_SETTLING_TIME_US		10
+static unsigned int pmic_gang_set_phases(struct krait_power_vreg *from,
+				int load_uA)
+{
+	struct pmic_gang_vreg *pvreg = from->pvreg;
+	int phase_count = DIV_ROUND_UP(load_uA, LOAD_PER_PHASE);
+	int rc = 0;
+
+	if (phase_count <= 0)
+		phase_count = 1;
+
+	 /* Increase phases if it is less than the number of cpus online */
+	if (phase_count < num_online_cpus()) {
+		phase_count = num_online_cpus();
+	}
+
+	if (phase_count != pvreg->pmic_phase_count) {
+		rc = set_pmic_gang_phases(pvreg, phase_count);
+		if (rc < 0) {
+			dev_err(&from->rdev->dev,
+				"%s failed set phase %d rc = %d\n",
+				pvreg->name, phase_count, rc);
+			return rc;
+		}
+
+		/* complete the writes before the delay */
+		mb();
+
+		/*
+		 * delay until the phases are settled when
+		 * the count is raised
+		 */
+		if (phase_count > pvreg->pmic_phase_count)
+			udelay(PHASE_SETTLING_TIME_US);
+
+		pvreg->pmic_phase_count = phase_count;
+	}
+	return rc;
+}
+
 static int krait_power_get_voltage(struct regulator_dev *rdev)
 {
 	struct krait_power_vreg *kvreg = rdev_get_drvdata(rdev);
@@ -770,6 +590,21 @@
 	return vmax;
 }
 
+static int get_total_load(struct krait_power_vreg *from)
+{
+	int load_total = 0;
+	struct krait_power_vreg *kvreg;
+	struct pmic_gang_vreg *pvreg = from->pvreg;
+
+	list_for_each_entry(kvreg, &pvreg->krait_power_vregs, link) {
+		if (!kvreg->online)
+			continue;
+		load_total += kvreg->load_uA;
+	}
+
+	return load_total;
+}
+
 #define ROUND_UP_VOLTAGE(v, res) (DIV_ROUND_UP(v, res) * res)
 static int _set_voltage(struct regulator_dev *rdev,
 			int orig_krait_uV, int requested_uV)
@@ -778,7 +613,6 @@
 	struct pmic_gang_vreg *pvreg = kvreg->pvreg;
 	int rc;
 	int vmax;
-	int coeff_total;
 
 	pr_debug("%s: %d to %d\n", kvreg->name, orig_krait_uV, requested_uV);
 	/*
@@ -802,11 +636,6 @@
 				kvreg->name, requested_uV, orig_krait_uV, rc);
 	}
 
-	kvreg->online_at_probe &= ~WAIT_FOR_VOLTAGE;
-	coeff_total = get_coeff_total(kvreg);
-	/* adjust the phases since coeff2 would have changed */
-	rc = pmic_gang_set_phases(kvreg, coeff_total);
-
 	return rc;
 }
 
@@ -841,6 +670,89 @@
 	return rc;
 }
 
+#define PMIC_FTS_MODE_PFM	0x00
+#define PMIC_FTS_MODE_PWM	0x80
+#define PFM_LOAD_UA		500000
+static unsigned int _get_optimum_mode(struct regulator_dev *rdev,
+			int input_uV, int output_uV, int load_uA)
+{
+	struct krait_power_vreg *kvreg = rdev_get_drvdata(rdev);
+	struct pmic_gang_vreg *pvreg = kvreg->pvreg;
+	int rc;
+	int load_total_uA;
+
+	load_total_uA = get_total_load(kvreg);
+
+	if (load_total_uA < PFM_LOAD_UA) {
+		if (!pvreg->pfm_mode) {
+			rc = msm_spm_enable_fts_lpm(PMIC_FTS_MODE_PFM);
+			if (rc) {
+				dev_err(&rdev->dev,
+					"%s enter PFM failed load %d rc = %d\n",
+					kvreg->name, load_total_uA, rc);
+				goto out;
+			} else {
+				pvreg->pfm_mode = true;
+			}
+		}
+		return kvreg->mode;
+	}
+
+	if (pvreg->pfm_mode) {
+		rc = msm_spm_enable_fts_lpm(PMIC_FTS_MODE_PWM);
+		if (rc) {
+			dev_err(&rdev->dev,
+				"%s exit PFM failed load %d rc = %d\n",
+				kvreg->name, load_total_uA, rc);
+			goto out;
+		} else {
+			pvreg->pfm_mode = false;
+		}
+	}
+
+	rc = pmic_gang_set_phases(kvreg, load_total_uA);
+	if (rc < 0) {
+		dev_err(&rdev->dev, "%s failed set mode %d rc = %d\n",
+				kvreg->name, load_total_uA, rc);
+		goto out;
+	}
+
+out:
+	return kvreg->mode;
+}
+
+static unsigned int krait_power_get_optimum_mode(struct regulator_dev *rdev,
+			int input_uV, int output_uV, int load_uA)
+{
+	struct krait_power_vreg *kvreg = rdev_get_drvdata(rdev);
+	struct pmic_gang_vreg *pvreg = kvreg->pvreg;
+	int rc;
+
+	mutex_lock(&pvreg->krait_power_vregs_lock);
+	kvreg->load_uA = load_uA;
+	if (!kvreg->online) {
+		mutex_unlock(&pvreg->krait_power_vregs_lock);
+		return kvreg->mode;
+	}
+
+	rc = _get_optimum_mode(rdev, input_uV, output_uV, load_uA);
+	mutex_unlock(&pvreg->krait_power_vregs_lock);
+
+	return rc;
+}
+
+static int krait_power_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+	return 0;
+}
+
+static unsigned int krait_power_get_mode(struct regulator_dev *rdev)
+{
+	struct krait_power_vreg *kvreg = rdev_get_drvdata(rdev);
+
+	return kvreg->mode;
+}
+
 static int krait_power_is_enabled(struct regulator_dev *rdev)
 {
 	struct krait_power_vreg *kvreg = rdev_get_drvdata(rdev);
@@ -857,7 +769,7 @@
 	mutex_lock(&pvreg->krait_power_vregs_lock);
 	__krait_power_mdd_enable(kvreg, true);
 	kvreg->online = true;
-	rc = _get_optimum_mode(rdev, kvreg->uV, kvreg->uV, kvreg->load);
+	rc = _get_optimum_mode(rdev, kvreg->uV, kvreg->uV, kvreg->load_uA);
 	if (rc < 0)
 		goto en_err;
 	/*
@@ -879,7 +791,8 @@
 	mutex_lock(&pvreg->krait_power_vregs_lock);
 	kvreg->online = false;
 
-	rc = _get_optimum_mode(rdev, kvreg->uV, kvreg->uV, kvreg->load);
+	rc = _get_optimum_mode(rdev, kvreg->uV, kvreg->uV,
+							kvreg->load_uA);
 	if (rc < 0)
 		goto dis_err;
 
@@ -938,10 +851,8 @@
 DEFINE_SIMPLE_ATTRIBUTE(retention_fops,
 			get_retention_dbg_uV, set_retention_dbg_uV, "%llu\n");
 
-#define CPU_PWR_CTL_ONLINE_MASK 0x80
 static void kvreg_hw_init(struct krait_power_vreg *kvreg)
 {
-	int online;
 	/*
 	 * bhs_cnt value sets the ramp-up time from power collapse,
 	 * initialize the ramp up time
@@ -954,10 +865,6 @@
 	/* Enable MDD */
 	writel_relaxed(0x00000002, kvreg->mdd_base + MDD_MODE);
 	mb();
-	online = CPU_PWR_CTL_ONLINE_MASK
-			& readl_relaxed(kvreg->reg_base + CPU_PWR_CTL);
-	kvreg->online_at_probe
-		= online ? (WAIT_FOR_LOAD | WAIT_FOR_VOLTAGE) : 0x0;
 }
 
 static void glb_init(void __iomem *apcs_gcc_base)
@@ -1105,7 +1012,7 @@
 	kvreg->desc.ops		= &krait_power_ops;
 	kvreg->desc.type	= REGULATOR_VOLTAGE;
 	kvreg->desc.owner	= THIS_MODULE;
-	kvreg->uV		= CORE_VOLTAGE_BOOTUP;
+	kvreg->uV		= CORE_VOLTAGE_MIN;
 	kvreg->mode		= HS_MODE;
 	kvreg->desc.ops		= &krait_power_ops;
 	kvreg->headroom_uV	= headroom_uV;
@@ -1204,7 +1111,6 @@
 {
 	int rc;
 	bool use_phase_switching = false;
-	int pfm_threshold;
 	struct device *dev = &pdev->dev;
 	struct device_node *node = dev->of_node;
 	struct pmic_gang_vreg *pvreg;
@@ -1217,13 +1123,6 @@
 
 	use_phase_switching = of_property_read_bool(node,
 						"qcom,use-phase-switching");
-
-	rc = of_property_read_u32(node, "qcom,pfm-threshold", &pfm_threshold);
-	if (rc < 0) {
-		dev_err(dev, "pfm-threshold missing rc=%d, pfm disabled\n", rc);
-		return -EINVAL;
-	}
-
 	pvreg = devm_kzalloc(&pdev->dev,
 			sizeof(struct pmic_gang_vreg), GFP_KERNEL);
 	if (!pvreg) {
@@ -1249,7 +1148,6 @@
 	pvreg->retention_enabled = true;
 	pvreg->pmic_min_uV_for_retention = INT_MAX;
 	pvreg->use_phase_switching = use_phase_switching;
-	pvreg->pfm_threshold = pfm_threshold;
 
 	mutex_init(&pvreg->krait_power_vregs_lock);
 	INIT_LIST_HEAD(&pvreg->krait_power_vregs);
@@ -1310,8 +1208,6 @@
 
 void secondary_cpu_hs_init(void *base_ptr)
 {
-	void *l2_saw_base;
-
 	/* Turn on the BHS, turn off LDO Bypass and power down LDO */
 	writel_relaxed(
 		BHS_CNT_DEFAULT << BHS_CNT_BIT_POS
@@ -1338,23 +1234,6 @@
 		| BHS_SEG_EN_DEFAULT << BHS_SEG_EN_BIT_POS
 		| BHS_EN_MASK,
 		base_ptr + APC_PWR_GATE_CTL);
-
-	if (the_gang && the_gang->manage_phases)
-		return;
-
-	/* If the driver has not yet started to manage phases then enable
-	 * max phases.
-	 */
-	l2_saw_base = ioremap_nocache(MSM_L2_SAW_PHYS, SZ_4K);
-	if (!l2_saw_base) {
-		__WARN();
-		return;
-	}
-	writel_relaxed(0x10003, l2_saw_base + 0x1c);
-	mb();
-	udelay(PHASE_SETTLING_TIME_US);
-
-	iounmap(l2_saw_base);
 }
 
 MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/pil-q6v5-lpass.c b/arch/arm/mach-msm/pil-q6v5-lpass.c
index 3b2bbf3..608c5e0 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();
 }
 
@@ -399,6 +402,17 @@
 	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;
+
+	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);
@@ -470,10 +484,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 +523,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 +537,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 8a9042e..a213112 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -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;
@@ -1053,8 +1054,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 +1185,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 +1204,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 +2132,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) {
@@ -3838,6 +3882,12 @@
 
 	for_each_child_of_node(pdev->dev.of_node, node) {
 		compatible = of_get_property(node, "compatible", NULL);
+		if (!compatible) {
+			pr_err("%s: invalid child node: compatible null\n",
+				__func__);
+			ret = -ENODEV;
+			goto rollback_subnodes;
+		}
 		if (!strcmp(compatible, "qcom,smd")) {
 			ret = parse_smd_devicetree(node, irq_out_base);
 			if (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/spm_devices.c b/arch/arm/mach-msm/spm_devices.c
index 233c5a5..174d444 100644
--- a/arch/arm/mach-msm/spm_devices.c
+++ b/arch/arm/mach-msm/spm_devices.c
@@ -74,6 +74,7 @@
 
 	info.cpu = cpu;
 	info.vlevel = vlevel;
+	info.err = -ENODEV;
 
 	if (cpu_online(cpu)) {
 		/**
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 d630ab2..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;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index c17fbc0..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;
 	}
 
@@ -1949,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;
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index a0c4bb7..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);
 			}
@@ -693,8 +693,7 @@
 		diag_update_sleeping_process(entry.process_id, PKT_TYPE);
 	} else {
 		if (len > 0) {
-			if ((entry.client_id >= 0) &&
-				(entry.client_id < NUM_SMD_DATA_CHANNELS)) {
+			if (entry.client_id < NUM_SMD_DATA_CHANNELS) {
 				int index = entry.client_id;
 				if (driver->smd_data[index].ch) {
 					if ((index == MODEM_DATA) &&
@@ -907,94 +906,186 @@
 		/* bld time masks */
 		switch (ssid_first) {
 		case MSG_SSID_0:
+			if (ssid_range > sizeof(msg_bld_masks_0)) {
+				pr_warning("diag: truncating ssid range for ssid 0");
+				ssid_range = sizeof(msg_bld_masks_0);
+			}
 			for (i = 0; i < ssid_range; i += 4)
 				*(int *)(ptr + i) = msg_bld_masks_0[i/4];
 			break;
 		case MSG_SSID_1:
+			if (ssid_range > sizeof(msg_bld_masks_1)) {
+				pr_warning("diag: truncating ssid range for ssid 1");
+				ssid_range = sizeof(msg_bld_masks_1);
+			}
 			for (i = 0; i < ssid_range; i += 4)
 				*(int *)(ptr + i) = msg_bld_masks_1[i/4];
 			break;
 		case MSG_SSID_2:
+			if (ssid_range > sizeof(msg_bld_masks_2)) {
+				pr_warning("diag: truncating ssid range for ssid 2");
+				ssid_range = sizeof(msg_bld_masks_2);
+			}
 			for (i = 0; i < ssid_range; i += 4)
 				*(int *)(ptr + i) = msg_bld_masks_2[i/4];
 			break;
 		case MSG_SSID_3:
+			if (ssid_range > sizeof(msg_bld_masks_3)) {
+				pr_warning("diag: truncating ssid range for ssid 3");
+				ssid_range = sizeof(msg_bld_masks_3);
+			}
 			for (i = 0; i < ssid_range; i += 4)
 				*(int *)(ptr + i) = msg_bld_masks_3[i/4];
 			break;
 		case MSG_SSID_4:
+			if (ssid_range > sizeof(msg_bld_masks_4)) {
+				pr_warning("diag: truncating ssid range for ssid 4");
+				ssid_range = sizeof(msg_bld_masks_4);
+			}
 			for (i = 0; i < ssid_range; i += 4)
 				*(int *)(ptr + i) = msg_bld_masks_4[i/4];
 			break;
 		case MSG_SSID_5:
+			if (ssid_range > sizeof(msg_bld_masks_5)) {
+				pr_warning("diag: truncating ssid range for ssid 5");
+				ssid_range = sizeof(msg_bld_masks_5);
+			}
 			for (i = 0; i < ssid_range; i += 4)
 				*(int *)(ptr + i) = msg_bld_masks_5[i/4];
 			break;
 		case MSG_SSID_6:
+			if (ssid_range > sizeof(msg_bld_masks_6)) {
+				pr_warning("diag: truncating ssid range for ssid 6");
+				ssid_range = sizeof(msg_bld_masks_6);
+			}
 			for (i = 0; i < ssid_range; i += 4)
 				*(int *)(ptr + i) = msg_bld_masks_6[i/4];
 			break;
 		case MSG_SSID_7:
+			if (ssid_range > sizeof(msg_bld_masks_7)) {
+				pr_warning("diag: truncating ssid range for ssid 7");
+				ssid_range = sizeof(msg_bld_masks_7);
+			}
 			for (i = 0; i < ssid_range; i += 4)
 				*(int *)(ptr + i) = msg_bld_masks_7[i/4];
 			break;
 		case MSG_SSID_8:
+			if (ssid_range > sizeof(msg_bld_masks_8)) {
+				pr_warning("diag: truncating ssid range for ssid 8");
+				ssid_range = sizeof(msg_bld_masks_8);
+			}
 			for (i = 0; i < ssid_range; i += 4)
 				*(int *)(ptr + i) = msg_bld_masks_8[i/4];
 			break;
 		case MSG_SSID_9:
+			if (ssid_range > sizeof(msg_bld_masks_9)) {
+				pr_warning("diag: truncating ssid range for ssid 9");
+				ssid_range = sizeof(msg_bld_masks_9);
+			}
 			for (i = 0; i < ssid_range; i += 4)
 				*(int *)(ptr + i) = msg_bld_masks_9[i/4];
 			break;
 		case MSG_SSID_10:
+			if (ssid_range > sizeof(msg_bld_masks_10)) {
+				pr_warning("diag: truncating ssid range for ssid 10");
+				ssid_range = sizeof(msg_bld_masks_10);
+			}
 			for (i = 0; i < ssid_range; i += 4)
 				*(int *)(ptr + i) = msg_bld_masks_10[i/4];
 			break;
 		case MSG_SSID_11:
+			if (ssid_range > sizeof(msg_bld_masks_11)) {
+				pr_warning("diag: truncating ssid range for ssid 11");
+				ssid_range = sizeof(msg_bld_masks_11);
+			}
 			for (i = 0; i < ssid_range; i += 4)
 				*(int *)(ptr + i) = msg_bld_masks_11[i/4];
 			break;
 		case MSG_SSID_12:
+			if (ssid_range > sizeof(msg_bld_masks_12)) {
+				pr_warning("diag: truncating ssid range for ssid 12");
+				ssid_range = sizeof(msg_bld_masks_12);
+			}
 			for (i = 0; i < ssid_range; i += 4)
 				*(int *)(ptr + i) = msg_bld_masks_12[i/4];
 			break;
 		case MSG_SSID_13:
+			if (ssid_range > sizeof(msg_bld_masks_13)) {
+				pr_warning("diag: truncating ssid range for ssid 13");
+				ssid_range = sizeof(msg_bld_masks_13);
+			}
 			for (i = 0; i < ssid_range; i += 4)
 				*(int *)(ptr + i) = msg_bld_masks_13[i/4];
 			break;
 		case MSG_SSID_14:
+			if (ssid_range > sizeof(msg_bld_masks_14)) {
+				pr_warning("diag: truncating ssid range for ssid 14");
+				ssid_range = sizeof(msg_bld_masks_14);
+			}
 			for (i = 0; i < ssid_range; i += 4)
 				*(int *)(ptr + i) = msg_bld_masks_14[i/4];
 			break;
 		case MSG_SSID_15:
+			if (ssid_range > sizeof(msg_bld_masks_15)) {
+				pr_warning("diag: truncating ssid range for ssid 15");
+				ssid_range = sizeof(msg_bld_masks_15);
+			}
 			for (i = 0; i < ssid_range; i += 4)
 				*(int *)(ptr + i) = msg_bld_masks_15[i/4];
 			break;
 		case MSG_SSID_16:
+			if (ssid_range > sizeof(msg_bld_masks_16)) {
+				pr_warning("diag: truncating ssid range for ssid 16");
+				ssid_range = sizeof(msg_bld_masks_16);
+			}
 			for (i = 0; i < ssid_range; i += 4)
 				*(int *)(ptr + i) = msg_bld_masks_16[i/4];
 			break;
 		case MSG_SSID_17:
+			if (ssid_range > sizeof(msg_bld_masks_17)) {
+				pr_warning("diag: truncating ssid range for ssid 17");
+				ssid_range = sizeof(msg_bld_masks_17);
+			}
 			for (i = 0; i < ssid_range; i += 4)
 				*(int *)(ptr + i) = msg_bld_masks_17[i/4];
 			break;
 		case MSG_SSID_18:
+			if (ssid_range > sizeof(msg_bld_masks_18)) {
+				pr_warning("diag: truncating ssid range for ssid 18");
+				ssid_range = sizeof(msg_bld_masks_18);
+			}
 			for (i = 0; i < ssid_range; i += 4)
 				*(int *)(ptr + i) = msg_bld_masks_18[i/4];
 			break;
 		case MSG_SSID_19:
+			if (ssid_range > sizeof(msg_bld_masks_19)) {
+				pr_warning("diag: truncating ssid range for ssid 19");
+				ssid_range = sizeof(msg_bld_masks_19);
+			}
 			for (i = 0; i < ssid_range; i += 4)
 				*(int *)(ptr + i) = msg_bld_masks_19[i/4];
 			break;
 		case MSG_SSID_20:
+			if (ssid_range > sizeof(msg_bld_masks_20)) {
+				pr_warning("diag: truncating ssid range for ssid 20");
+				ssid_range = sizeof(msg_bld_masks_20);
+			}
 			for (i = 0; i < ssid_range; i += 4)
 				*(int *)(ptr + i) = msg_bld_masks_20[i/4];
 			break;
 		case MSG_SSID_21:
+			if (ssid_range > sizeof(msg_bld_masks_21)) {
+				pr_warning("diag: truncating ssid range for ssid 21");
+				ssid_range = sizeof(msg_bld_masks_21);
+			}
 			for (i = 0; i < ssid_range; i += 4)
 				*(int *)(ptr + i) = msg_bld_masks_21[i/4];
 			break;
 		case MSG_SSID_22:
+			if (ssid_range > sizeof(msg_bld_masks_22)) {
+				pr_warning("diag: truncating ssid range for ssid 22");
+				ssid_range = sizeof(msg_bld_masks_22);
+			}
 			for (i = 0; i < ssid_range; i += 4)
 				*(int *)(ptr + i) = msg_bld_masks_22[i/4];
 			break;
@@ -1704,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),
@@ -1787,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);
 }
@@ -1820,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/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/char/msm_rotator.c b/drivers/char/msm_rotator.c
index e946b42..9a43ea4 100644
--- a/drivers/char/msm_rotator.c
+++ b/drivers/char/msm_rotator.c
@@ -181,8 +181,7 @@
 		pr_err("ion_import_dma_buf() failed\n");
 		return PTR_ERR(*pihdl);
 	}
-	pr_debug("%s(): ion_hdl %p, ion_fd %d\n", __func__, *pihdl,
-		ion_share_dma_buf(msm_rotator_dev->client, *pihdl));
+	pr_debug("%s(): ion_hdl %p, ion_fd %d\n", __func__, *pihdl, mem_id);
 
 	if (rot_iommu_split_domain) {
 		if (secure) {
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/qce.c b/drivers/crypto/msm/qce.c
index 24cf30a..7778477 100644
--- a/drivers/crypto/msm/qce.c
+++ b/drivers/crypto/msm/qce.c
@@ -2203,6 +2203,18 @@
 }
 EXPORT_SYMBOL(qce_process_sha_req);
 
+int qce_enable_clk(void *handle)
+{
+	return 0;
+}
+EXPORT_SYMBOL(qce_enable_clk);
+
+int qce_disable_clk(void *handle)
+{
+	return 0;
+}
+EXPORT_SYMBOL(qce_disable_clk);
+
 /*
  * crypto engine open function.
  */
diff --git a/drivers/crypto/msm/qce.h b/drivers/crypto/msm/qce.h
index 3ff84cf..51a74b6 100644
--- a/drivers/crypto/msm/qce.h
+++ b/drivers/crypto/msm/qce.h
@@ -160,5 +160,7 @@
 int qce_ablk_cipher_req(void *handle, struct qce_req *req);
 int qce_hw_support(void *handle, struct ce_hw_support *support);
 int qce_process_sha_req(void *handle, struct qce_sha_req *s_req);
+int qce_enable_clk(void *handle);
+int qce_disable_clk(void *handle);
 
 #endif /* __CRYPTO_MSM_QCE_H */
diff --git a/drivers/crypto/msm/qce40.c b/drivers/crypto/msm/qce40.c
index 7b0964d..5249917 100644
--- a/drivers/crypto/msm/qce40.c
+++ b/drivers/crypto/msm/qce40.c
@@ -2426,6 +2426,18 @@
 }
 EXPORT_SYMBOL(qce_process_sha_req);
 
+int qce_enable_clk(void *handle)
+{
+	return 0;
+}
+EXPORT_SYMBOL(qce_enable_clk);
+
+int qce_disable_clk(void *handle)
+{
+	return 0;
+}
+EXPORT_SYMBOL(qce_disable_clk);
+
 /* crypto engine open function. */
 void *qce_open(struct platform_device *pdev, int *rc)
 {
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index 739a753..245272b 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -39,7 +39,7 @@
 #include "qcryptohw_50.h"
 
 #define CRYPTO_CONFIG_RESET 0xE001F
-#define QCE_MAX_NUM_DSCR    0x400
+#define QCE_MAX_NUM_DSCR    0x500
 #define QCE_SECTOR_SIZE	    0x200
 
 static DEFINE_MUTEX(bam_register_cnt);
@@ -919,17 +919,23 @@
 	iovec->flags |= flag;
 }
 
-static void _qce_sps_add_data(uint32_t addr, uint32_t len,
+static int _qce_sps_add_data(uint32_t addr, uint32_t len,
 		struct sps_transfer *sps_bam_pipe)
 {
 	struct sps_iovec *iovec = sps_bam_pipe->iovec +
 					sps_bam_pipe->iovec_count;
+	if (sps_bam_pipe->iovec_count == QCE_MAX_NUM_DSCR) {
+		pr_err("Num of descrptor %d exceed max (%d)",
+			sps_bam_pipe->iovec_count, (uint32_t)QCE_MAX_NUM_DSCR);
+		return -ENOMEM;
+	}
 	if (len) {
 		iovec->size = len;
 		iovec->addr = addr;
 		iovec->flags = 0;
 		sps_bam_pipe->iovec_count++;
 	}
+	return 0;
 }
 
 static int _qce_sps_add_sg_data(struct qce_device *pce_dev,
@@ -947,6 +953,12 @@
 		if (pce_dev->ce_sps.minor_version == 0)
 			len = ALIGN(len, pce_dev->ce_sps.ce_burst_size);
 		while (len > 0) {
+			if (sps_bam_pipe->iovec_count == QCE_MAX_NUM_DSCR) {
+				pr_err("Num of descrptor %d exceed max (%d)",
+						sps_bam_pipe->iovec_count,
+						(uint32_t)QCE_MAX_NUM_DSCR);
+				return -ENOMEM;
+			}
 			if (len > SPS_MAX_PKT_SIZE) {
 				data_cnt = SPS_MAX_PKT_SIZE;
 				iovec->size = data_cnt;
@@ -1325,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 *)
@@ -1353,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 *)
@@ -1400,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)
@@ -2359,31 +2332,23 @@
 		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,
 					&pce_dev->ce_sps.in_transfer);
 
 	if (pce_dev->ce_sps.minor_version == 0) {
-		_qce_sps_add_sg_data(pce_dev, areq->src, totallen_in,
-					&pce_dev->ce_sps.in_transfer);
+		if (_qce_sps_add_sg_data(pce_dev, areq->src, totallen_in,
+					&pce_dev->ce_sps.in_transfer))
+			goto bad;
 
 		_qce_set_flag(&pce_dev->ce_sps.in_transfer,
 				SPS_IOVEC_FLAG_EOT|SPS_IOVEC_FLAG_NWD);
 
-		_qce_sps_add_sg_data(pce_dev, areq->dst, out_len +
+		if (_qce_sps_add_sg_data(pce_dev, areq->dst, out_len +
 					areq->assoclen + hw_pad_out,
-				&pce_dev->ce_sps.out_transfer);
+				&pce_dev->ce_sps.out_transfer))
+			goto bad;
 		if (totallen_in > SPS_MAX_PKT_SIZE) {
 			_qce_set_flag(&pce_dev->ce_sps.out_transfer,
 							SPS_IOVEC_FLAG_INT);
@@ -2391,42 +2356,52 @@
 							SPS_O_DESC_DONE;
 			pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_IDLE;
 		} else {
-			_qce_sps_add_data(GET_PHYS_ADDR(
+			if (_qce_sps_add_data(GET_PHYS_ADDR(
 					pce_dev->ce_sps.result_dump),
 					CRYPTO_RESULT_DUMP_SIZE,
-					  &pce_dev->ce_sps.out_transfer);
+					&pce_dev->ce_sps.out_transfer))
+				goto bad;
 			_qce_set_flag(&pce_dev->ce_sps.out_transfer,
 							SPS_IOVEC_FLAG_INT);
 			pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_COMP;
 		}
 	} else {
-		_qce_sps_add_sg_data(pce_dev, areq->assoc, areq->assoclen,
-					 &pce_dev->ce_sps.in_transfer);
-		_qce_sps_add_data((uint32_t)pce_dev->phy_iv_in, ivsize,
-					&pce_dev->ce_sps.in_transfer);
-		_qce_sps_add_sg_data(pce_dev, areq->src, areq->cryptlen,
-					&pce_dev->ce_sps.in_transfer);
+		if (_qce_sps_add_sg_data(pce_dev, areq->assoc, areq->assoclen,
+					 &pce_dev->ce_sps.in_transfer))
+			goto bad;
+		if (_qce_sps_add_data((uint32_t)pce_dev->phy_iv_in, ivsize,
+					&pce_dev->ce_sps.in_transfer))
+			goto bad;
+		if (_qce_sps_add_sg_data(pce_dev, areq->src, areq->cryptlen,
+					&pce_dev->ce_sps.in_transfer))
+			goto bad;
 		_qce_set_flag(&pce_dev->ce_sps.in_transfer,
 				SPS_IOVEC_FLAG_EOT|SPS_IOVEC_FLAG_NWD);
 
 		/* Pass through to ignore associated (+iv, if applicable) data*/
-		_qce_sps_add_data(GET_PHYS_ADDR(pce_dev->ce_sps.ignore_buffer),
+		if (_qce_sps_add_data(
+				GET_PHYS_ADDR(pce_dev->ce_sps.ignore_buffer),
 				(ivsize + areq->assoclen),
-				&pce_dev->ce_sps.out_transfer);
-		_qce_sps_add_sg_data(pce_dev, areq->dst, out_len,
-					&pce_dev->ce_sps.out_transfer);
+				&pce_dev->ce_sps.out_transfer))
+			goto bad;
+		if (_qce_sps_add_sg_data(pce_dev, areq->dst, out_len,
+					&pce_dev->ce_sps.out_transfer))
+			goto bad;
 		/* Pass through to ignore hw_pad (padding of the MAC data) */
-		_qce_sps_add_data(GET_PHYS_ADDR(pce_dev->ce_sps.ignore_buffer),
-				hw_pad_out, &pce_dev->ce_sps.out_transfer);
+		if (_qce_sps_add_data(
+				GET_PHYS_ADDR(pce_dev->ce_sps.ignore_buffer),
+				hw_pad_out, &pce_dev->ce_sps.out_transfer))
+			goto bad;
 		if (totallen_in > SPS_MAX_PKT_SIZE) {
 			_qce_set_flag(&pce_dev->ce_sps.out_transfer,
 							SPS_IOVEC_FLAG_INT);
 			pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_IDLE;
 		} else {
-			_qce_sps_add_data(
+			if (_qce_sps_add_data(
 				GET_PHYS_ADDR(pce_dev->ce_sps.result_dump),
 					CRYPTO_RESULT_DUMP_SIZE,
-					  &pce_dev->ce_sps.out_transfer);
+					  &pce_dev->ce_sps.out_transfer))
+				goto bad;
 			_qce_set_flag(&pce_dev->ce_sps.out_transfer,
 							SPS_IOVEC_FLAG_INT);
 			pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_COMP;
@@ -2515,37 +2490,30 @@
 		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,
 					&pce_dev->ce_sps.in_transfer);
-	_qce_sps_add_sg_data(pce_dev, areq->src, areq->nbytes,
-					&pce_dev->ce_sps.in_transfer);
+	if (_qce_sps_add_sg_data(pce_dev, areq->src, areq->nbytes,
+					&pce_dev->ce_sps.in_transfer))
+		goto bad;
 	_qce_set_flag(&pce_dev->ce_sps.in_transfer,
 				SPS_IOVEC_FLAG_EOT|SPS_IOVEC_FLAG_NWD);
 
-	_qce_sps_add_sg_data(pce_dev, areq->dst, areq->nbytes,
-					&pce_dev->ce_sps.out_transfer);
+	if (_qce_sps_add_sg_data(pce_dev, areq->dst, areq->nbytes,
+					&pce_dev->ce_sps.out_transfer))
+		goto bad;
 	if (areq->nbytes > SPS_MAX_PKT_SIZE) {
 		_qce_set_flag(&pce_dev->ce_sps.out_transfer,
 							SPS_IOVEC_FLAG_INT);
 		pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_IDLE;
 	} else {
 		pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_COMP;
-		_qce_sps_add_data(GET_PHYS_ADDR(pce_dev->ce_sps.result_dump),
-					CRYPTO_RESULT_DUMP_SIZE,
-					  &pce_dev->ce_sps.out_transfer);
+		if (_qce_sps_add_data(
+				GET_PHYS_ADDR(pce_dev->ce_sps.result_dump),
+				CRYPTO_RESULT_DUMP_SIZE,
+				&pce_dev->ce_sps.out_transfer))
+			goto bad;
 		_qce_set_flag(&pce_dev->ce_sps.out_transfer,
 							SPS_IOVEC_FLAG_INT);
 	}
@@ -2598,29 +2566,20 @@
 		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,
 					&pce_dev->ce_sps.in_transfer);
-	_qce_sps_add_sg_data(pce_dev, areq->src, areq->nbytes,
-						 &pce_dev->ce_sps.in_transfer);
+	if (_qce_sps_add_sg_data(pce_dev, areq->src, areq->nbytes,
+						 &pce_dev->ce_sps.in_transfer))
+		goto bad;
 	_qce_set_flag(&pce_dev->ce_sps.in_transfer,
 				SPS_IOVEC_FLAG_EOT|SPS_IOVEC_FLAG_NWD);
 
-	_qce_sps_add_data(GET_PHYS_ADDR(pce_dev->ce_sps.result_dump),
+	if (_qce_sps_add_data(GET_PHYS_ADDR(pce_dev->ce_sps.result_dump),
 					CRYPTO_RESULT_DUMP_SIZE,
-					  &pce_dev->ce_sps.out_transfer);
+					  &pce_dev->ce_sps.out_transfer))
+		goto bad;
 	_qce_set_flag(&pce_dev->ce_sps.out_transfer, SPS_IOVEC_FLAG_INT);
 	rc = _qce_sps_transfer(pce_dev);
 	if (rc)
@@ -2800,7 +2759,7 @@
 	}
 }
 
-static int __qce_enable_clk(void *handle)
+int qce_enable_clk(void *handle)
 {
 	struct qce_device *pce_dev = (struct qce_device *) handle;
 	int rc = 0;
@@ -2813,6 +2772,7 @@
 			return rc;
 		}
 	}
+
 	/* Enable CE clk */
 	if (pce_dev->ce_clk != NULL) {
 		rc = clk_prepare_enable(pce_dev->ce_clk);
@@ -2834,8 +2794,9 @@
 	}
 	return rc;
 }
+EXPORT_SYMBOL(qce_enable_clk);
 
-static int __qce_disable_clk(void *handle)
+int qce_disable_clk(void *handle)
 {
 	struct qce_device *pce_dev = (struct qce_device *) handle;
 	int rc = 0;
@@ -2849,6 +2810,7 @@
 
 	return rc;
 }
+EXPORT_SYMBOL(qce_disable_clk);
 
 /* crypto engine open function. */
 void *qce_open(struct platform_device *pdev, int *rc)
@@ -2886,19 +2848,20 @@
 	if (*rc)
 		goto err_mem;
 
-	*rc = __qce_enable_clk(pce_dev);
+	*rc = qce_enable_clk(pce_dev);
 	if (*rc)
 		goto err;
 
 	if (_probe_ce_engine(pce_dev)) {
 		*rc = -ENXIO;
-		__qce_disable_clk(pce_dev);
 		goto err;
 	}
 	*rc = 0;
 	qce_setup_ce_sps_data(pce_dev);
 	qce_sps_init(pce_dev);
 
+	qce_disable_clk(pce_dev);
+
 	return pce_dev;
 err:
 	__qce_deinit_clk(pce_dev);
@@ -2932,7 +2895,7 @@
 		dma_free_coherent(pce_dev->pdev, pce_dev->memsize,
 				pce_dev->coh_vmem, pce_dev->coh_pmem);
 
-	__qce_disable_clk(pce_dev);
+	qce_disable_clk(pce_dev);
 	__qce_deinit_clk(pce_dev);
 
 	qce_sps_exit(pce_dev);
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index 8cc42df..e91dcaa 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -98,7 +98,7 @@
 };
 
 static DEFINE_MUTEX(send_cmd_lock);
-static DEFINE_MUTEX(sent_bw_req);
+static DEFINE_MUTEX(qcedev_sent_bw_req);
 /**********************************************************************
  * Register ourselves as a misc device to be able to access the dev driver
  * from userspace. */
@@ -177,25 +177,51 @@
 {
 	int ret = 0;
 
-	mutex_lock(&sent_bw_req);
+	mutex_lock(&qcedev_sent_bw_req);
 	if (high_bw_req) {
-		if (podev->high_bw_req_count == 0)
+		if (podev->high_bw_req_count == 0) {
+			ret = qce_enable_clk(podev->qce);
+			if (ret) {
+				pr_err("%s Unable enable clk\n", __func__);
+				mutex_unlock(&qcedev_sent_bw_req);
+				return;
+			}
 			ret = msm_bus_scale_client_update_request(
 					podev->bus_scale_handle, 1);
-		if (ret)
-			pr_err("%s Unable to set to high bandwidth\n",
+			if (ret) {
+				pr_err("%s Unable to set to high bandwidth\n",
 							__func__);
+				ret = qce_disable_clk(podev->qce);
+				mutex_unlock(&qcedev_sent_bw_req);
+				return;
+			}
+		}
 		podev->high_bw_req_count++;
 	} else {
-		if (podev->high_bw_req_count == 1)
+		if (podev->high_bw_req_count == 1) {
 			ret = msm_bus_scale_client_update_request(
 					podev->bus_scale_handle, 0);
-		if (ret)
-			pr_err("%s Unable to set to low bandwidth\n",
+			if (ret) {
+				pr_err("%s Unable to set to low bandwidth\n",
 							__func__);
+				mutex_unlock(&qcedev_sent_bw_req);
+				return;
+			}
+			ret = qce_disable_clk(podev->qce);
+			if (ret) {
+				pr_err("%s Unable disable clk\n", __func__);
+				ret = msm_bus_scale_client_update_request(
+					podev->bus_scale_handle, 1);
+				if (ret)
+					pr_err("%s Unable to set to high bandwidth\n",
+							__func__);
+				mutex_unlock(&qcedev_sent_bw_req);
+				return;
+			}
+		}
 		podev->high_bw_req_count--;
 	}
-	mutex_unlock(&sent_bw_req);
+	mutex_unlock(&qcedev_sent_bw_req);
 }
 
 
@@ -1854,6 +1880,14 @@
 		podev->platform_support.hw_key_support = 0;
 		podev->platform_support.bus_scale_table = NULL;
 		podev->platform_support.sha_hmac = 1;
+
+		if (podev->ce_support.is_shared == false) {
+			podev->platform_support.bus_scale_table =
+				(struct msm_bus_scale_pdata *)
+						msm_bus_cl_get_pdata(pdev);
+			if (!podev->platform_support.bus_scale_table)
+				pr_err("bus_scale_table is NULL\n");
+		}
 	} else {
 		platform_support =
 			(struct msm_ce_hw_support *)pdev->dev.platform_data;
diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c
index 85c25c7..40fb29ac 100644
--- a/drivers/crypto/msm/qcrypto.c
+++ b/drivers/crypto/msm/qcrypto.c
@@ -121,7 +121,7 @@
 #define NUM_RETRY				1000
 #define CE_BUSY				        55
 
-static DEFINE_MUTEX(sent_bw_req);
+static DEFINE_MUTEX(qcrypto_sent_bw_req);
 
 static int qcrypto_scm_cmd(int resource, int cmd, int *response)
 {
@@ -346,25 +346,51 @@
 {
 	int ret = 0;
 
-	mutex_lock(&sent_bw_req);
+	mutex_lock(&qcrypto_sent_bw_req);
 	if (high_bw_req) {
-		if (cp->high_bw_req_count == 0)
+		if (cp->high_bw_req_count == 0) {
+			ret = qce_enable_clk(cp->qce);
+			if (ret) {
+				pr_err("%s Unable enable clk\n", __func__);
+				mutex_unlock(&qcrypto_sent_bw_req);
+				return;
+			}
 			ret = msm_bus_scale_client_update_request(
-				cp->bus_scale_handle, 1);
-		if (ret)
-			pr_err("%s Unable to set to high bandwidth\n",
+					cp->bus_scale_handle, 1);
+			if (ret) {
+				pr_err("%s Unable to set to high bandwidth\n",
 							__func__);
+				qce_disable_clk(cp->qce);
+				mutex_unlock(&qcrypto_sent_bw_req);
+				return;
+			}
+		}
 		cp->high_bw_req_count++;
 	} else {
-		if (cp->high_bw_req_count == 1)
+		if (cp->high_bw_req_count == 1) {
 			ret = msm_bus_scale_client_update_request(
-				cp->bus_scale_handle, 0);
-		if (ret)
-			pr_err("%s Unable to set to low bandwidth\n",
+					cp->bus_scale_handle, 0);
+			if (ret) {
+				pr_err("%s Unable to set to low bandwidth\n",
 							__func__);
+				mutex_unlock(&qcrypto_sent_bw_req);
+				return;
+			}
+			ret = qce_disable_clk(cp->qce);
+			if (ret) {
+				pr_err("%s Unable disable clk\n", __func__);
+				ret = msm_bus_scale_client_update_request(
+					cp->bus_scale_handle, 1);
+				if (ret)
+					pr_err("%s Unable to set to high bandwidth\n",
+							__func__);
+				mutex_unlock(&qcrypto_sent_bw_req);
+				return;
+			}
+		}
 		cp->high_bw_req_count--;
 	}
-	mutex_unlock(&sent_bw_req);
+	mutex_unlock(&qcrypto_sent_bw_req);
 }
 
 static int _start_qcrypto_process(struct crypto_priv *cp);
@@ -3336,6 +3362,14 @@
 		cp->platform_support.hw_key_support = 0;
 		cp->platform_support.bus_scale_table =	NULL;
 		cp->platform_support.sha_hmac = 1;
+
+		if (cp->ce_support.is_shared == false) {
+			cp->platform_support.bus_scale_table =
+				(struct msm_bus_scale_pdata *)
+						msm_bus_cl_get_pdata(pdev);
+			if (!cp->platform_support.bus_scale_table)
+				pr_warn("bus_scale_table is NULL\n");
+		}
 	} else {
 		platform_support =
 			(struct msm_ce_hw_support *)pdev->dev.platform_data;
diff --git a/drivers/gpu/ion/Makefile b/drivers/gpu/ion/Makefile
index f4f9a92..d7ff73a 100644
--- a/drivers/gpu/ion/Makefile
+++ b/drivers/gpu/ion/Makefile
@@ -1,4 +1,6 @@
-obj-$(CONFIG_ION) +=	ion.o ion_heap.o ion_system_heap.o ion_carveout_heap.o ion_iommu_heap.o ion_cp_heap.o ion_removed_heap.o
+obj-$(CONFIG_ION) +=	ion.o ion_heap.o ion_system_heap.o ion_carveout_heap.o \
+			ion_iommu_heap.o ion_cp_heap.o ion_removed_heap.o \
+			ion_page_pool.o ion_chunk_heap.o
 obj-$(CONFIG_CMA) += ion_cma_heap.o ion_cma_secure_heap.o
 obj-$(CONFIG_ION_TEGRA) += tegra/
 obj-$(CONFIG_ION_MSM) += msm/
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index a01ef3f..4282f02 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -1,4 +1,5 @@
 /*
+
  * drivers/gpu/ion/ion.c
  *
  * Copyright (C) 2011 Google, Inc.
@@ -18,15 +19,18 @@
 #include <linux/module.h>
 #include <linux/device.h>
 #include <linux/file.h>
+#include <linux/freezer.h>
 #include <linux/fs.h>
 #include <linux/anon_inodes.h>
 #include <linux/ion.h>
+#include <linux/kthread.h>
 #include <linux/list.h>
 #include <linux/memblock.h>
 #include <linux/miscdevice.h>
 #include <linux/mm.h>
 #include <linux/mm_types.h>
 #include <linux/rbtree.h>
+#include <linux/rtmutex.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/seq_file.h>
@@ -43,16 +47,18 @@
 /**
  * struct ion_device - the metadata of the ion device node
  * @dev:		the actual misc device
- * @buffers:	an rb tree of all the existing buffers
- * @lock:		lock protecting the buffers & heaps trees
+ * @buffers:		an rb tree of all the existing buffers
+ * @buffer_lock:	lock protecting the tree of buffers
+ * @lock:		rwsem protecting the tree of heaps and clients
  * @heaps:		list of all the heaps in the system
  * @user_clients:	list of all the clients created from userspace
  */
 struct ion_device {
 	struct miscdevice dev;
 	struct rb_root buffers;
-	struct mutex lock;
-	struct rb_root heaps;
+	struct mutex buffer_lock;
+	struct rw_semaphore lock;
+	struct plist_head heaps;
 	long (*custom_ioctl) (struct ion_client *client, unsigned int cmd,
 			      unsigned long arg);
 	struct rb_root clients;
@@ -65,7 +71,6 @@
  * @dev:		backpointer to ion device
  * @handles:		an rb tree of all the handles in this client
  * @lock:		lock protecting the tree of handles
- * @heap_mask:		mask of all supported heaps
  * @name:		used for debugging
  * @task:		used for debugging
  *
@@ -78,7 +83,7 @@
 	struct ion_device *dev;
 	struct rb_root handles;
 	struct mutex lock;
-	unsigned int heap_mask;
+	unsigned int heap_type_mask;
 	char *name;
 	struct task_struct *task;
 	pid_t pid;
@@ -112,6 +117,11 @@
                 !(buffer->flags & ION_FLAG_CACHED_NEEDS_SYNC));
 }
 
+bool ion_buffer_cached(struct ion_buffer *buffer)
+{
+        return !!(buffer->flags & ION_FLAG_CACHED);
+}
+
 /* this function should only be called while dev->lock is held */
 static void ion_buffer_add(struct ion_device *dev,
 			   struct ion_buffer *buffer)
@@ -140,6 +150,7 @@
 
 static int ion_buffer_alloc_dirty(struct ion_buffer *buffer);
 
+static bool ion_heap_drain_freelist(struct ion_heap *heap);
 /* this function should only be called while dev->lock is held */
 static struct ion_buffer *ion_buffer_create(struct ion_heap *heap,
 				     struct ion_device *dev,
@@ -161,9 +172,16 @@
 	kref_init(&buffer->ref);
 
 	ret = heap->ops->allocate(heap, buffer, len, align, flags);
+
 	if (ret) {
-		kfree(buffer);
-		return ERR_PTR(ret);
+		if (!(heap->flags & ION_HEAP_FLAG_DEFER_FREE))
+			goto err2;
+
+		ion_heap_drain_freelist(heap);
+		ret = heap->ops->allocate(heap, buffer, len, align,
+					  flags);
+		if (ret)
+			goto err2;
 	}
 
 	buffer->dev = dev;
@@ -208,12 +226,15 @@
 		if (sg_dma_address(sg) == 0)
 			sg_dma_address(sg) = sg_phys(sg);
 	}
+	mutex_lock(&dev->buffer_lock);
 	ion_buffer_add(dev, buffer);
+	mutex_unlock(&dev->buffer_lock);
 	return buffer;
 
 err:
 	heap->ops->unmap_dma(heap, buffer);
 	heap->ops->free(buffer);
+err2:
 	kfree(buffer);
 	return ERR_PTR(ret);
 }
@@ -224,25 +245,39 @@
 		buffer->heap->ops->unsecure_buffer(buffer, 1);
 }
 
-static void ion_buffer_destroy(struct kref *kref)
+static void _ion_buffer_destroy(struct ion_buffer *buffer)
 {
-	struct ion_buffer *buffer = container_of(kref, struct ion_buffer, ref);
-	struct ion_device *dev = buffer->dev;
-
 	if (WARN_ON(buffer->kmap_cnt > 0))
 		buffer->heap->ops->unmap_kernel(buffer->heap, buffer);
 	buffer->heap->ops->unmap_dma(buffer->heap, buffer);
 
 	ion_delayed_unsecure(buffer);
 	buffer->heap->ops->free(buffer);
-	mutex_lock(&dev->lock);
-	rb_erase(&buffer->node, &dev->buffers);
-	mutex_unlock(&dev->lock);
 	if (buffer->flags & ION_FLAG_CACHED)
 		kfree(buffer->dirty);
 	kfree(buffer);
 }
 
+static void ion_buffer_destroy(struct kref *kref)
+{
+	struct ion_buffer *buffer = container_of(kref, struct ion_buffer, ref);
+	struct ion_heap *heap = buffer->heap;
+	struct ion_device *dev = buffer->dev;
+
+	mutex_lock(&dev->buffer_lock);
+	rb_erase(&buffer->node, &dev->buffers);
+	mutex_unlock(&dev->buffer_lock);
+
+	if (heap->flags & ION_HEAP_FLAG_DEFER_FREE) {
+		rt_mutex_lock(&heap->lock);
+		list_add(&buffer->list, &heap->free_list);
+		rt_mutex_unlock(&heap->lock);
+		wake_up(&heap->waitqueue);
+		return;
+	}
+	_ion_buffer_destroy(buffer);
+}
+
 static void ion_buffer_get(struct ion_buffer *buffer)
 {
 	kref_get(&buffer->ref);
@@ -253,6 +288,37 @@
 	return kref_put(&buffer->ref, ion_buffer_destroy);
 }
 
+static void ion_buffer_add_to_handle(struct ion_buffer *buffer)
+{
+	mutex_lock(&buffer->lock);
+	buffer->handle_count++;
+	mutex_unlock(&buffer->lock);
+}
+
+static void ion_buffer_remove_from_handle(struct ion_buffer *buffer)
+{
+	/*
+	 * when a buffer is removed from a handle, if it is not in
+	 * any other handles, copy the taskcomm and the pid of the
+	 * process it's being removed from into the buffer.  At this
+	 * point there will be no way to track what processes this buffer is
+	 * being used by, it only exists as a dma_buf file descriptor.
+	 * The taskcomm and pid can provide a debug hint as to where this fd
+	 * is in the system
+	 */
+	mutex_lock(&buffer->lock);
+	buffer->handle_count--;
+	BUG_ON(buffer->handle_count < 0);
+	if (!buffer->handle_count) {
+		struct task_struct *task;
+
+		task = current->group_leader;
+		get_task_comm(buffer->task_comm, task);
+		buffer->pid = task_pid_nr(task);
+	}
+	mutex_unlock(&buffer->lock);
+}
+
 static struct ion_handle *ion_handle_create(struct ion_client *client,
 				     struct ion_buffer *buffer)
 {
@@ -265,6 +331,7 @@
 	rb_init_node(&handle->node);
 	handle->client = client;
 	ion_buffer_get(buffer);
+	ion_buffer_add_to_handle(buffer);
 	handle->buffer = buffer;
 
 	return handle;
@@ -286,7 +353,9 @@
 	if (!RB_EMPTY_NODE(&handle->node))
 		rb_erase(&handle->node, &client->handles);
 
+	ion_buffer_remove_from_handle(buffer);
 	ion_buffer_put(buffer);
+
 	kfree(handle);
 }
 
@@ -359,13 +428,13 @@
 }
 
 struct ion_handle *ion_alloc(struct ion_client *client, size_t len,
-			     size_t align, unsigned int heap_mask,
+			     size_t align, unsigned int heap_id_mask,
 			     unsigned int flags)
 {
-	struct rb_node *n;
 	struct ion_handle *handle;
 	struct ion_device *dev = client->dev;
 	struct ion_buffer *buffer = NULL;
+	struct ion_heap *heap;
 	unsigned long secure_allocation = flags & ION_FLAG_SECURE;
 	const unsigned int MAX_DBG_STR_LEN = 64;
 	char dbg_str[MAX_DBG_STR_LEN];
@@ -381,8 +450,8 @@
 	 */
 	flags |= ION_FLAG_CACHED_NEEDS_SYNC;
 
-	pr_debug("%s: len %d align %d heap_mask %u flags %x\n", __func__, len,
-		 align, heap_mask, flags);
+	pr_debug("%s: len %d align %d heap_id_mask %u flags %x\n", __func__,
+		 len, align, heap_id_mask, flags);
 	/*
 	 * traverse the list of heaps available in this system in priority
 	 * order.  If the heap type is supported by the client, and matches the
@@ -394,29 +463,26 @@
 
 	len = PAGE_ALIGN(len);
 
-	mutex_lock(&dev->lock);
-	for (n = rb_first(&dev->heaps); n != NULL; n = rb_next(n)) {
-		struct ion_heap *heap = rb_entry(n, struct ion_heap, node);
-		/* if the client doesn't support this heap type */
-		if (!((1 << heap->type) & client->heap_mask))
-			continue;
-		/* if the caller didn't specify this heap type */
-		if (!((1 << heap->id) & heap_mask))
+	down_read(&dev->lock);
+	plist_for_each_entry(heap, &dev->heaps, node) {
+		/* if the caller didn't specify this heap id */
+		if (!((1 << heap->id) & heap_id_mask))
 			continue;
 		/* Do not allow un-secure heap if secure is specified */
 		if (secure_allocation &&
 		    !ion_heap_allow_secure_allocation(heap->type))
 			continue;
 		trace_ion_alloc_buffer_start(client->name, heap->name, len,
-					     heap_mask, flags);
+					     heap_id_mask, flags);
 		buffer = ion_buffer_create(heap, dev, len, align, flags);
 		trace_ion_alloc_buffer_end(client->name, heap->name, len,
-					   heap_mask, flags);
+					   heap_id_mask, flags);
 		if (!IS_ERR_OR_NULL(buffer))
 			break;
 
 		trace_ion_alloc_buffer_fallback(client->name, heap->name, len,
-					    heap_mask, flags, PTR_ERR(buffer));
+					    heap_id_mask, flags,
+					    PTR_ERR(buffer));
 		if (dbg_str_idx < MAX_DBG_STR_LEN) {
 			unsigned int len_left = MAX_DBG_STR_LEN-dbg_str_idx-1;
 			int ret_value = snprintf(&dbg_str[dbg_str_idx],
@@ -433,21 +499,21 @@
 			}
 		}
 	}
-	mutex_unlock(&dev->lock);
+	up_read(&dev->lock);
 
 	if (buffer == NULL) {
 		trace_ion_alloc_buffer_fail(client->name, dbg_str, len,
-					    heap_mask, flags, -ENODEV);
+					    heap_id_mask, flags, -ENODEV);
 		return ERR_PTR(-ENODEV);
 	}
 
 	if (IS_ERR(buffer)) {
 		trace_ion_alloc_buffer_fail(client->name, dbg_str, len,
-					    heap_mask, flags, PTR_ERR(buffer));
+					    heap_id_mask, flags,
+					    PTR_ERR(buffer));
 		pr_debug("ION is unable to allocate 0x%x bytes (alignment: "
-			 "0x%x) from heap(s) %sfor client %s with heap "
-			 "mask 0x%x\n",
-			len, align, dbg_str, client->name, client->heap_mask);
+			 "0x%x) from heap(s) %sfor client %s\n",
+			len, align, dbg_str, client->name);
 		return ERR_PTR(PTR_ERR(buffer));
 	}
 
@@ -620,6 +686,7 @@
 	for (n = rb_first(&client->handles); n; n = rb_next(n)) {
 		struct ion_handle *handle = rb_entry(n, struct ion_handle,
 						     node);
+
 		enum ion_heap_type type = handle->buffer->heap->type;
 
 		seq_printf(s, "%16.16s: %16x : %16d : %12p",
@@ -638,7 +705,6 @@
 		seq_printf(s, "\n");
 	}
 	mutex_unlock(&client->lock);
-
 	return 0;
 }
 
@@ -655,7 +721,6 @@
 };
 
 struct ion_client *ion_client_create(struct ion_device *dev,
-				     unsigned int heap_mask,
 				     const char *name)
 {
 	struct ion_client *client;
@@ -705,11 +770,10 @@
 		strlcpy(client->name, name, name_len+1);
 	}
 
-	client->heap_mask = heap_mask;
 	client->task = task;
 	client->pid = pid;
 
-	mutex_lock(&dev->lock);
+	down_write(&dev->lock);
 	p = &dev->clients.rb_node;
 	while (*p) {
 		parent = *p;
@@ -727,96 +791,16 @@
 	client->debug_root = debugfs_create_file(name, 0664,
 						 dev->debug_root, client,
 						 &debug_client_fops);
-	mutex_unlock(&dev->lock);
+	up_write(&dev->lock);
 
 	return client;
 }
-
-/**
- * ion_mark_dangling_buffers_locked() - Mark dangling buffers
- * @dev:	the ion device whose buffers will be searched
- *
- * Sets marked=1 for all known buffers associated with `dev' that no
- * longer have a handle pointing to them. dev->lock should be held
- * across a call to this function (and should only be unlocked after
- * checking for marked buffers).
- */
-static void ion_mark_dangling_buffers_locked(struct ion_device *dev)
-{
-	struct rb_node *n, *n2;
-	/* mark all buffers as 1 */
-	for (n = rb_first(&dev->buffers); n; n = rb_next(n)) {
-		struct ion_buffer *buf = rb_entry(n, struct ion_buffer,
-						node);
-
-		buf->marked = 1;
-	}
-
-	/* now see which buffers we can access */
-	for (n = rb_first(&dev->clients); n; n = rb_next(n)) {
-		struct ion_client *client = rb_entry(n, struct ion_client,
-						node);
-
-		mutex_lock(&client->lock);
-		for (n2 = rb_first(&client->handles); n2; n2 = rb_next(n2)) {
-			struct ion_handle *handle
-				= rb_entry(n2, struct ion_handle, node);
-
-			handle->buffer->marked = 0;
-
-		}
-		mutex_unlock(&client->lock);
-
-	}
-}
-
-#ifdef CONFIG_ION_LEAK_CHECK
-static u32 ion_debug_check_leaks_on_destroy;
-
-static int ion_check_for_and_print_leaks(struct ion_device *dev)
-{
-	struct rb_node *n;
-	int num_leaks = 0;
-
-	if (!ion_debug_check_leaks_on_destroy)
-		return 0;
-
-	/* check for leaked buffers (those that no longer have a
-	 * handle pointing to them) */
-	ion_mark_dangling_buffers_locked(dev);
-
-	/* Anyone still marked as a 1 means a leaked handle somewhere */
-	for (n = rb_first(&dev->buffers); n; n = rb_next(n)) {
-		struct ion_buffer *buf = rb_entry(n, struct ion_buffer,
-						node);
-
-		if (buf->marked == 1) {
-			pr_info("Leaked ion buffer at %p\n", buf);
-			num_leaks++;
-		}
-	}
-	return num_leaks;
-}
-static void setup_ion_leak_check(struct dentry *debug_root)
-{
-	debugfs_create_bool("check_leaks_on_destroy", 0664, debug_root,
-			&ion_debug_check_leaks_on_destroy);
-}
-#else
-static int ion_check_for_and_print_leaks(struct ion_device *dev)
-{
-	return 0;
-}
-static void setup_ion_leak_check(struct dentry *debug_root)
-{
-}
-#endif
+EXPORT_SYMBOL(ion_client_create);
 
 void ion_client_destroy(struct ion_client *client)
 {
 	struct ion_device *dev = client->dev;
 	struct rb_node *n;
-	int num_leaks;
 
 	pr_debug("%s: %d\n", __func__, __LINE__);
 	while ((n = rb_first(&client->handles))) {
@@ -824,25 +808,13 @@
 						     node);
 		ion_handle_destroy(&handle->ref);
 	}
-	mutex_lock(&dev->lock);
+	down_write(&dev->lock);
 	if (client->task)
 		put_task_struct(client->task);
 	rb_erase(&client->node, &dev->clients);
 	debugfs_remove_recursive(client->debug_root);
 
-	num_leaks = ion_check_for_and_print_leaks(dev);
-
-	mutex_unlock(&dev->lock);
-
-	if (num_leaks) {
-		struct task_struct *current_task = current;
-		char current_task_name[TASK_COMM_LEN];
-		get_task_comm(current_task_name, current_task);
-		WARN(1, "%s: Detected %d leaked ion buffer%s.\n",
-			__func__, num_leaks, num_leaks == 1 ? "" : "s");
-		pr_info("task name at time of leak: %s, pid: %d\n",
-			current_task_name, current_task->pid);
-	}
+	up_write(&dev->lock);
 
 	kfree(client->name);
 	kfree(client);
@@ -1115,7 +1087,7 @@
 static void *ion_dma_buf_kmap(struct dma_buf *dmabuf, unsigned long offset)
 {
 	struct ion_buffer *buffer = dmabuf->priv;
-	return buffer->vaddr + offset;
+	return buffer->vaddr + offset * PAGE_SIZE;
 }
 
 static void ion_dma_buf_kunmap(struct dma_buf *dmabuf, unsigned long offset,
@@ -1171,19 +1143,19 @@
 	.kunmap = ion_dma_buf_kunmap,
 };
 
-int ion_share_dma_buf(struct ion_client *client, struct ion_handle *handle)
+struct dma_buf *ion_share_dma_buf(struct ion_client *client,
+						struct ion_handle *handle)
 {
 	struct ion_buffer *buffer;
 	struct dma_buf *dmabuf;
 	bool valid_handle;
-	int fd;
 
 	mutex_lock(&client->lock);
 	valid_handle = ion_handle_validate(client, handle);
 	mutex_unlock(&client->lock);
 	if (!valid_handle) {
 		WARN(1, "%s: invalid handle passed to share.\n", __func__);
-		return -EINVAL;
+		return ERR_PTR(-EINVAL);
 	}
 
 	buffer = handle->buffer;
@@ -1191,15 +1163,29 @@
 	dmabuf = dma_buf_export(buffer, &dma_buf_ops, buffer->size, O_RDWR);
 	if (IS_ERR(dmabuf)) {
 		ion_buffer_put(buffer);
-		return PTR_ERR(dmabuf);
+		return dmabuf;
 	}
+
+	return dmabuf;
+}
+EXPORT_SYMBOL(ion_share_dma_buf);
+
+int ion_share_dma_buf_fd(struct ion_client *client, struct ion_handle *handle)
+{
+	struct dma_buf *dmabuf;
+	int fd;
+
+	dmabuf = ion_share_dma_buf(client, handle);
+	if (IS_ERR(dmabuf))
+		return PTR_ERR(dmabuf);
+
 	fd = dma_buf_fd(dmabuf, O_CLOEXEC);
 	if (fd < 0)
 		dma_buf_put(dmabuf);
 
 	return fd;
 }
-EXPORT_SYMBOL(ion_share_dma_buf);
+EXPORT_SYMBOL(ion_share_dma_buf_fd);
 
 struct ion_handle *ion_import_dma_buf(struct ion_client *client, int fd)
 {
@@ -1308,7 +1294,8 @@
 		if (copy_from_user(&data, (void __user *)arg, sizeof(data)))
 			return -EFAULT;
 
-		data.fd = ion_share_dma_buf(client, data.handle);
+		data.fd = ion_share_dma_buf_fd(client, data.handle);
+
 		if (copy_to_user((void __user *)arg, &data, sizeof(data)))
 			return -EFAULT;
 		if (data.fd < 0)
@@ -1388,7 +1375,7 @@
 
 	pr_debug("%s: %d\n", __func__, __LINE__);
 	snprintf(debug_name, 64, "%u", task_pid_nr(current->group_leader));
-	client = ion_client_create(dev, -1, debug_name);
+	client = ion_client_create(dev, debug_name);
 	if (IS_ERR_OR_NULL(client))
 		return PTR_ERR(client);
 	file->private_data = client;
@@ -1570,9 +1557,12 @@
 	struct ion_heap *heap = s->private;
 	struct ion_device *dev = heap->dev;
 	struct rb_node *n;
+	size_t total_size = 0;
+	size_t total_orphaned_size = 0;
 
-	mutex_lock(&dev->lock);
+	mutex_lock(&dev->buffer_lock);
 	seq_printf(s, "%16.s %16.s %16.s\n", "client", "pid", "size");
+	seq_printf(s, "----------------------------------------------------\n");
 
 	for (n = rb_first(&dev->clients); n; n = rb_next(n)) {
 		struct ion_client *client = rb_entry(n, struct ion_client,
@@ -1591,8 +1581,28 @@
 				   client->pid, size);
 		}
 	}
+	seq_printf(s, "----------------------------------------------------\n");
+	seq_printf(s, "orphaned allocations (info is from last known client):"
+		   "\n");
+	for (n = rb_first(&dev->buffers); n; n = rb_next(n)) {
+		struct ion_buffer *buffer = rb_entry(n, struct ion_buffer,
+						     node);
+		if (buffer->heap->type == heap->type)
+			total_size += buffer->size;
+		if (!buffer->handle_count) {
+			seq_printf(s, "%16.s %16u %16u\n", buffer->task_comm,
+				   buffer->pid, buffer->size);
+			total_orphaned_size += buffer->size;
+		}
+	}
+	seq_printf(s, "----------------------------------------------------\n");
+	seq_printf(s, "%16.s %16u\n", "total orphaned",
+		   total_orphaned_size);
+	seq_printf(s, "%16.s %16u\n", "total ", total_size);
+	seq_printf(s, "----------------------------------------------------\n");
+
 	ion_heap_print_debug(s, heap);
-	mutex_unlock(&dev->lock);
+	mutex_unlock(&dev->buffer_lock);
 	return 0;
 }
 
@@ -1608,40 +1618,90 @@
 	.release = single_release,
 };
 
+static size_t ion_heap_free_list_is_empty(struct ion_heap *heap)
+{
+	bool is_empty;
+
+	rt_mutex_lock(&heap->lock);
+	is_empty = list_empty(&heap->free_list);
+	rt_mutex_unlock(&heap->lock);
+
+	return is_empty;
+}
+
+static int ion_heap_deferred_free(void *data)
+{
+	struct ion_heap *heap = data;
+
+	while (true) {
+		struct ion_buffer *buffer;
+
+		wait_event_freezable(heap->waitqueue,
+				     !ion_heap_free_list_is_empty(heap));
+
+		rt_mutex_lock(&heap->lock);
+		if (list_empty(&heap->free_list)) {
+			rt_mutex_unlock(&heap->lock);
+			continue;
+		}
+		buffer = list_first_entry(&heap->free_list, struct ion_buffer,
+					  list);
+		list_del(&buffer->list);
+		rt_mutex_unlock(&heap->lock);
+		_ion_buffer_destroy(buffer);
+	}
+
+	return 0;
+}
+
+static bool ion_heap_drain_freelist(struct ion_heap *heap)
+{
+	struct ion_buffer *buffer, *tmp;
+
+	if (ion_heap_free_list_is_empty(heap))
+		return false;
+	rt_mutex_lock(&heap->lock);
+	list_for_each_entry_safe(buffer, tmp, &heap->free_list, list) {
+		_ion_buffer_destroy(buffer);
+		list_del(&buffer->list);
+	}
+	BUG_ON(!list_empty(&heap->free_list));
+	rt_mutex_unlock(&heap->lock);
+
+
+	return true;
+}
+
 void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap)
 {
-	struct rb_node **p = &dev->heaps.rb_node;
-	struct rb_node *parent = NULL;
-	struct ion_heap *entry;
+	struct sched_param param = { .sched_priority = 0 };
 
 	if (!heap->ops->allocate || !heap->ops->free || !heap->ops->map_dma ||
 	    !heap->ops->unmap_dma)
 		pr_err("%s: can not add heap with invalid ops struct.\n",
 		       __func__);
 
-	heap->dev = dev;
-	mutex_lock(&dev->lock);
-	while (*p) {
-		parent = *p;
-		entry = rb_entry(parent, struct ion_heap, node);
-
-		if (heap->id < entry->id) {
-			p = &(*p)->rb_left;
-		} else if (heap->id > entry->id ) {
-			p = &(*p)->rb_right;
-		} else {
-			pr_err("%s: can not insert multiple heaps with "
-				"id %d\n", __func__, heap->id);
-			goto end;
-		}
+	if (heap->flags & ION_HEAP_FLAG_DEFER_FREE) {
+		INIT_LIST_HEAD(&heap->free_list);
+		rt_mutex_init(&heap->lock);
+		init_waitqueue_head(&heap->waitqueue);
+		heap->task = kthread_run(ion_heap_deferred_free, heap,
+					 "%s", heap->name);
+		sched_setscheduler(heap->task, SCHED_IDLE, &param);
+		if (IS_ERR(heap->task))
+			pr_err("%s: creating thread for deferred free failed\n",
+			       __func__);
 	}
 
-	rb_link_node(&heap->node, parent, p);
-	rb_insert_color(&heap->node, &dev->heaps);
+	heap->dev = dev;
+	down_write(&dev->lock);
+	/* use negative heap->id to reverse the priority -- when traversing
+	   the list later attempt higher id numbers first */
+	plist_node_init(&heap->node, -heap->id);
+	plist_add(&heap->node, &dev->heaps);
 	debugfs_create_file(heap->name, 0664, dev->debug_root, heap,
 			    &debug_heap_fops);
-end:
-	mutex_unlock(&dev->lock);
+	up_write(&dev->lock);
 }
 
 int ion_secure_handle(struct ion_client *client, struct ion_handle *handle,
@@ -1714,16 +1774,15 @@
 int ion_secure_heap(struct ion_device *dev, int heap_id, int version,
 			void *data)
 {
-	struct rb_node *n;
 	int ret_val = 0;
+	struct ion_heap *heap;
 
 	/*
 	 * traverse the list of heaps available in this system
 	 * and find the heap that is specified.
 	 */
-	mutex_lock(&dev->lock);
-	for (n = rb_first(&dev->heaps); n != NULL; n = rb_next(n)) {
-		struct ion_heap *heap = rb_entry(n, struct ion_heap, node);
+	down_write(&dev->lock);
+	plist_for_each_entry(heap, &dev->heaps, node) {
 		if (!ion_heap_allow_heap_secure(heap->type))
 			continue;
 		if (ION_HEAP(heap->id) != heap_id)
@@ -1734,7 +1793,7 @@
 			ret_val = -EINVAL;
 		break;
 	}
-	mutex_unlock(&dev->lock);
+	up_write(&dev->lock);
 	return ret_val;
 }
 EXPORT_SYMBOL(ion_secure_heap);
@@ -1742,16 +1801,15 @@
 int ion_unsecure_heap(struct ion_device *dev, int heap_id, int version,
 			void *data)
 {
-	struct rb_node *n;
 	int ret_val = 0;
+	struct ion_heap *heap;
 
 	/*
 	 * traverse the list of heaps available in this system
 	 * and find the heap that is specified.
 	 */
-	mutex_lock(&dev->lock);
-	for (n = rb_first(&dev->heaps); n != NULL; n = rb_next(n)) {
-		struct ion_heap *heap = rb_entry(n, struct ion_heap, node);
+	down_write(&dev->lock);
+	plist_for_each_entry(heap, &dev->heaps, node) {
 		if (!ion_heap_allow_heap_secure(heap->type))
 			continue;
 		if (ION_HEAP(heap->id) != heap_id)
@@ -1762,50 +1820,11 @@
 			ret_val = -EINVAL;
 		break;
 	}
-	mutex_unlock(&dev->lock);
+	up_write(&dev->lock);
 	return ret_val;
 }
 EXPORT_SYMBOL(ion_unsecure_heap);
 
-static int ion_debug_leak_show(struct seq_file *s, void *unused)
-{
-	struct ion_device *dev = s->private;
-	struct rb_node *n;
-
-	seq_printf(s, "%16.s %16.s %16.s %16.s\n", "buffer", "heap", "size",
-		"ref cnt");
-
-	mutex_lock(&dev->lock);
-	ion_mark_dangling_buffers_locked(dev);
-
-	/* Anyone still marked as a 1 means a leaked handle somewhere */
-	for (n = rb_first(&dev->buffers); n; n = rb_next(n)) {
-		struct ion_buffer *buf = rb_entry(n, struct ion_buffer,
-						     node);
-
-		if (buf->marked == 1)
-			seq_printf(s, "%16.x %16.s %16.x %16.d\n",
-				(int)buf, buf->heap->name, buf->size,
-				atomic_read(&buf->ref.refcount));
-	}
-	mutex_unlock(&dev->lock);
-	return 0;
-}
-
-static int ion_debug_leak_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, ion_debug_leak_show, inode->i_private);
-}
-
-static const struct file_operations debug_leak_fops = {
-	.open = ion_debug_leak_open,
-	.read = seq_read,
-	.llseek = seq_lseek,
-	.release = single_release,
-};
-
-
-
 struct ion_device *ion_device_create(long (*custom_ioctl)
 				     (struct ion_client *client,
 				      unsigned int cmd,
@@ -1834,13 +1853,10 @@
 
 	idev->custom_ioctl = custom_ioctl;
 	idev->buffers = RB_ROOT;
-	mutex_init(&idev->lock);
-	idev->heaps = RB_ROOT;
+	mutex_init(&idev->buffer_lock);
+	init_rwsem(&idev->lock);
+	plist_head_init(&idev->heaps);
 	idev->clients = RB_ROOT;
-	debugfs_create_file("check_leaked_fds", 0664, idev->debug_root, idev,
-			    &debug_leak_fops);
-
-	setup_ion_leak_check(idev->debug_root);
 	return idev;
 }
 
@@ -1853,16 +1869,35 @@
 
 void __init ion_reserve(struct ion_platform_data *data)
 {
-	int i, ret;
+	int i;
 
 	for (i = 0; i < data->nr; i++) {
 		if (data->heaps[i].size == 0)
 			continue;
-		ret = memblock_reserve(data->heaps[i].base,
-				       data->heaps[i].size);
-		if (ret)
-			pr_err("memblock reserve of %x@%pa failed\n",
-			       data->heaps[i].size,
-			       &data->heaps[i].base);
+
+		if (data->heaps[i].base == 0) {
+			phys_addr_t paddr;
+			paddr = memblock_alloc_base(data->heaps[i].size,
+						    data->heaps[i].align,
+						    MEMBLOCK_ALLOC_ANYWHERE);
+			if (!paddr) {
+				pr_err("%s: error allocating memblock for "
+				       "heap %d\n",
+					__func__, i);
+				continue;
+			}
+			data->heaps[i].base = paddr;
+		} else {
+			int ret = memblock_reserve(data->heaps[i].base,
+					       data->heaps[i].size);
+			if (ret)
+				pr_err("memblock reserve of %x@%pa failed\n",
+				       data->heaps[i].size,
+				       &data->heaps[i].base);
+		}
+		pr_info("%s: %s reserved base %pa size %d\n", __func__,
+			data->heaps[i].name,
+			&data->heaps[i].base,
+			data->heaps[i].size);
 	}
 }
diff --git a/drivers/gpu/ion/ion_chunk_heap.c b/drivers/gpu/ion/ion_chunk_heap.c
new file mode 100644
index 0000000..b76f898
--- /dev/null
+++ b/drivers/gpu/ion/ion_chunk_heap.c
@@ -0,0 +1,180 @@
+/*
+ * drivers/gpu/ion/ion_chunk_heap.c
+ *
+ * Copyright (C) 2012 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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/spinlock.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/genalloc.h>
+#include <linux/io.h>
+#include <linux/ion.h>
+#include <linux/mm.h>
+#include <linux/scatterlist.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include "ion_priv.h"
+
+#include <asm/mach/map.h>
+
+struct ion_chunk_heap {
+	struct ion_heap heap;
+	struct gen_pool *pool;
+	ion_phys_addr_t base;
+	unsigned long chunk_size;
+	unsigned long size;
+	unsigned long allocated;
+};
+
+static int ion_chunk_heap_allocate(struct ion_heap *heap,
+				      struct ion_buffer *buffer,
+				      unsigned long size, unsigned long align,
+				      unsigned long flags)
+{
+	struct ion_chunk_heap *chunk_heap =
+		container_of(heap, struct ion_chunk_heap, heap);
+	struct sg_table *table;
+	struct scatterlist *sg;
+	int ret, i;
+	unsigned long num_chunks;
+
+	if (ion_buffer_fault_user_mappings(buffer))
+		return -ENOMEM;
+
+	num_chunks = ALIGN(size, chunk_heap->chunk_size) /
+		chunk_heap->chunk_size;
+	buffer->size = num_chunks * chunk_heap->chunk_size;
+
+	if (buffer->size > chunk_heap->size - chunk_heap->allocated)
+		return -ENOMEM;
+
+	table = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
+	if (!table)
+		return -ENOMEM;
+	ret = sg_alloc_table(table, num_chunks, GFP_KERNEL);
+	if (ret) {
+		kfree(table);
+		return ret;
+	}
+
+	sg = table->sgl;
+	for (i = 0; i < num_chunks; i++) {
+		unsigned long paddr = gen_pool_alloc(chunk_heap->pool,
+						     chunk_heap->chunk_size);
+		if (!paddr)
+			goto err;
+		sg_set_page(sg, phys_to_page(paddr), chunk_heap->chunk_size, 0);
+		sg = sg_next(sg);
+	}
+
+	buffer->priv_virt = table;
+	chunk_heap->allocated += buffer->size;
+	return 0;
+err:
+	sg = table->sgl;
+	for (i -= 1; i >= 0; i--) {
+		gen_pool_free(chunk_heap->pool, page_to_phys(sg_page(sg)),
+			      sg_dma_len(sg));
+		sg = sg_next(sg);
+	}
+	sg_free_table(table);
+	kfree(table);
+	return -ENOMEM;
+}
+
+static void ion_chunk_heap_free(struct ion_buffer *buffer)
+{
+	struct ion_heap *heap = buffer->heap;
+	struct ion_chunk_heap *chunk_heap =
+		container_of(heap, struct ion_chunk_heap, heap);
+	struct sg_table *table = buffer->priv_virt;
+	struct scatterlist *sg;
+	int i;
+
+	ion_heap_buffer_zero(buffer);
+
+	for_each_sg(table->sgl, sg, table->nents, i) {
+		if (ion_buffer_cached(buffer))
+			dma_sync_sg_for_device(NULL, sg, 1, DMA_BIDIRECTIONAL);
+		gen_pool_free(chunk_heap->pool, page_to_phys(sg_page(sg)),
+			      sg_dma_len(sg));
+	}
+	chunk_heap->allocated -= buffer->size;
+	sg_free_table(table);
+	kfree(table);
+}
+
+struct sg_table *ion_chunk_heap_map_dma(struct ion_heap *heap,
+					 struct ion_buffer *buffer)
+{
+	return buffer->priv_virt;
+}
+
+void ion_chunk_heap_unmap_dma(struct ion_heap *heap,
+			       struct ion_buffer *buffer)
+{
+	return;
+}
+
+static struct ion_heap_ops chunk_heap_ops = {
+	.allocate = ion_chunk_heap_allocate,
+	.free = ion_chunk_heap_free,
+	.map_dma = ion_chunk_heap_map_dma,
+	.unmap_dma = ion_chunk_heap_unmap_dma,
+	.map_user = ion_heap_map_user,
+	.map_kernel = ion_heap_map_kernel,
+	.unmap_kernel = ion_heap_unmap_kernel,
+};
+
+struct ion_heap *ion_chunk_heap_create(struct ion_platform_heap *heap_data)
+{
+	struct ion_chunk_heap *chunk_heap;
+	struct scatterlist sg;
+
+	chunk_heap = kzalloc(sizeof(struct ion_chunk_heap), GFP_KERNEL);
+	if (!chunk_heap)
+		return ERR_PTR(-ENOMEM);
+
+	chunk_heap->chunk_size = (unsigned long)heap_data->priv;
+	chunk_heap->pool = gen_pool_create(get_order(chunk_heap->chunk_size) +
+					   PAGE_SHIFT, -1);
+	if (!chunk_heap->pool) {
+		kfree(chunk_heap);
+		return ERR_PTR(-ENOMEM);
+	}
+	chunk_heap->base = heap_data->base;
+	chunk_heap->size = heap_data->size;
+	chunk_heap->allocated = 0;
+
+	sg_init_table(&sg, 1);
+	sg_set_page(&sg, phys_to_page(heap_data->base), heap_data->size, 0);
+	dma_sync_sg_for_device(NULL, &sg, 1, DMA_BIDIRECTIONAL);
+	gen_pool_add(chunk_heap->pool, chunk_heap->base, heap_data->size, -1);
+	chunk_heap->heap.ops = &chunk_heap_ops;
+	chunk_heap->heap.type = ION_HEAP_TYPE_CHUNK;
+	chunk_heap->heap.flags = ION_HEAP_FLAG_DEFER_FREE;
+	pr_info("%s: base %pa size %zd align %pa\n", __func__,
+		&chunk_heap->base, heap_data->size, &heap_data->align);
+
+	return &chunk_heap->heap;
+}
+
+void ion_chunk_heap_destroy(struct ion_heap *heap)
+{
+	struct ion_chunk_heap *chunk_heap =
+	     container_of(heap, struct  ion_chunk_heap, heap);
+
+	gen_pool_destroy(chunk_heap->pool);
+	kfree(chunk_heap);
+	chunk_heap = NULL;
+}
diff --git a/drivers/gpu/ion/ion_cma_heap.c b/drivers/gpu/ion/ion_cma_heap.c
index f64ad4d..193f4d4 100644
--- a/drivers/gpu/ion/ion_cma_heap.c
+++ b/drivers/gpu/ion/ion_cma_heap.c
@@ -47,7 +47,7 @@
 int ion_cma_get_sgtable(struct device *dev, struct sg_table *sgt,
 			void *cpu_addr, dma_addr_t handle, size_t size)
 {
-	struct page *page = virt_to_page(cpu_addr);
+	struct page *page = phys_to_page(handle);
 	int ret;
 
 	ret = sg_alloc_table(sgt, 1, GFP_KERNEL);
diff --git a/drivers/gpu/ion/ion_cma_secure_heap.c b/drivers/gpu/ion/ion_cma_secure_heap.c
index d622a51..e1b3eea 100644
--- a/drivers/gpu/ion/ion_cma_secure_heap.c
+++ b/drivers/gpu/ion/ion_cma_secure_heap.c
@@ -52,7 +52,7 @@
 int ion_secure_cma_get_sgtable(struct device *dev, struct sg_table *sgt,
 			void *cpu_addr, dma_addr_t handle, size_t size)
 {
-	struct page *page = virt_to_page(cpu_addr);
+	struct page *page = phys_to_page(handle);
 	int ret;
 
 	ret = sg_alloc_table(sgt, 1, GFP_KERNEL);
diff --git a/drivers/gpu/ion/ion_heap.c b/drivers/gpu/ion/ion_heap.c
index 510b9ce..3d37541 100644
--- a/drivers/gpu/ion/ion_heap.c
+++ b/drivers/gpu/ion/ion_heap.c
@@ -17,8 +17,120 @@
 
 #include <linux/err.h>
 #include <linux/ion.h>
+#include <linux/mm.h>
+#include <linux/scatterlist.h>
+#include <linux/vmalloc.h>
 #include "ion_priv.h"
 
+void *ion_heap_map_kernel(struct ion_heap *heap,
+			  struct ion_buffer *buffer)
+{
+	struct scatterlist *sg;
+	int i, j;
+	void *vaddr;
+	pgprot_t pgprot;
+	struct sg_table *table = buffer->sg_table;
+	int npages = PAGE_ALIGN(buffer->size) / PAGE_SIZE;
+	struct page **pages = vmalloc(sizeof(struct page *) * npages);
+	struct page **tmp = pages;
+
+	if (!pages)
+		return 0;
+
+	if (buffer->flags & ION_FLAG_CACHED)
+		pgprot = PAGE_KERNEL;
+	else
+		pgprot = pgprot_writecombine(PAGE_KERNEL);
+
+	for_each_sg(table->sgl, sg, table->nents, i) {
+		int npages_this_entry = PAGE_ALIGN(sg_dma_len(sg)) / PAGE_SIZE;
+		struct page *page = sg_page(sg);
+		BUG_ON(i >= npages);
+		for (j = 0; j < npages_this_entry; j++) {
+			*(tmp++) = page++;
+		}
+	}
+	vaddr = vmap(pages, npages, VM_MAP, pgprot);
+	vfree(pages);
+
+	return vaddr;
+}
+
+void ion_heap_unmap_kernel(struct ion_heap *heap,
+			   struct ion_buffer *buffer)
+{
+	vunmap(buffer->vaddr);
+}
+
+int ion_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer,
+		      struct vm_area_struct *vma)
+{
+	struct sg_table *table = buffer->sg_table;
+	unsigned long addr = vma->vm_start;
+	unsigned long offset = vma->vm_pgoff * PAGE_SIZE;
+	struct scatterlist *sg;
+	int i;
+
+	for_each_sg(table->sgl, sg, table->nents, i) {
+		struct page *page = sg_page(sg);
+		unsigned long remainder = vma->vm_end - addr;
+		unsigned long len = sg_dma_len(sg);
+
+		if (offset >= sg_dma_len(sg)) {
+			offset -= sg_dma_len(sg);
+			continue;
+		} else if (offset) {
+			page += offset / PAGE_SIZE;
+			len = sg_dma_len(sg) - offset;
+			offset = 0;
+		}
+		len = min(len, remainder);
+		remap_pfn_range(vma, addr, page_to_pfn(page), len,
+				vma->vm_page_prot);
+		addr += len;
+		if (addr >= vma->vm_end)
+			return 0;
+	}
+	return 0;
+}
+
+int ion_heap_buffer_zero(struct ion_buffer *buffer)
+{
+	struct sg_table *table = buffer->sg_table;
+	pgprot_t pgprot;
+	struct scatterlist *sg;
+	struct vm_struct *vm_struct;
+	int i, j, ret = 0;
+
+	if (buffer->flags & ION_FLAG_CACHED)
+		pgprot = PAGE_KERNEL;
+	else
+		pgprot = pgprot_writecombine(PAGE_KERNEL);
+
+	vm_struct = get_vm_area(PAGE_SIZE, VM_ALLOC);
+	if (!vm_struct)
+		return -ENOMEM;
+
+	for_each_sg(table->sgl, sg, table->nents, i) {
+		struct page *page = sg_page(sg);
+		unsigned long len = sg_dma_len(sg);
+
+		for (j = 0; j < len / PAGE_SIZE; j++) {
+			struct page *sub_page = page + j;
+			struct page **pages = &sub_page;
+			ret = map_vm_area(vm_struct, pgprot, &pages);
+			if (ret)
+				goto end;
+			memset(vm_struct->addr, 0, PAGE_SIZE);
+			unmap_kernel_range((unsigned long)vm_struct->addr,
+					   PAGE_SIZE);
+		}
+	}
+end:
+	free_vm_area(vm_struct);
+	return ret;
+}
+
 struct ion_heap *ion_heap_create(struct ion_platform_heap *heap_data)
 {
 	struct ion_heap *heap = NULL;
@@ -33,6 +145,9 @@
 	case ION_HEAP_TYPE_CARVEOUT:
 		heap = ion_carveout_heap_create(heap_data);
 		break;
+	case ION_HEAP_TYPE_CHUNK:
+		heap = ion_chunk_heap_create(heap_data);
+		break;
 	default:
 		pr_err("%s: Invalid heap type %d\n", __func__,
 		       heap_data->type);
@@ -67,6 +182,9 @@
 	case ION_HEAP_TYPE_CARVEOUT:
 		ion_carveout_heap_destroy(heap);
 		break;
+	case ION_HEAP_TYPE_CHUNK:
+		ion_chunk_heap_destroy(heap);
+		break;
 	default:
 		pr_err("%s: Invalid heap type %d\n", __func__,
 		       heap->type);
diff --git a/drivers/gpu/ion/ion_iommu_heap.c b/drivers/gpu/ion/ion_iommu_heap.c
index ca29016..53d853d 100644
--- a/drivers/gpu/ion/ion_iommu_heap.c
+++ b/drivers/gpu/ion/ion_iommu_heap.c
@@ -111,7 +111,7 @@
 		int j;
 		void *ptr = NULL;
 		unsigned int npages_to_vmap, total_pages, num_large_pages = 0;
-		long size_remaining = PAGE_ALIGN(size);
+		unsigned long size_remaining = PAGE_ALIGN(size);
 		unsigned int max_order = ION_IS_CACHED(flags) ? 0 : orders[0];
 
 		data = kmalloc(sizeof(*data), GFP_KERNEL);
diff --git a/drivers/gpu/ion/ion_page_pool.c b/drivers/gpu/ion/ion_page_pool.c
new file mode 100644
index 0000000..e8b5489
--- /dev/null
+++ b/drivers/gpu/ion/ion_page_pool.c
@@ -0,0 +1,282 @@
+/*
+ * drivers/gpu/ion/ion_mem_pool.c
+ *
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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/debugfs.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/shrinker.h>
+#include "ion_priv.h"
+
+/* #define DEBUG_PAGE_POOL_SHRINKER */
+
+static struct plist_head pools = PLIST_HEAD_INIT(pools);
+static struct shrinker shrinker;
+
+struct ion_page_pool_item {
+	struct page *page;
+	struct list_head list;
+};
+
+static void *ion_page_pool_alloc_pages(struct ion_page_pool *pool)
+{
+	struct page *page = alloc_pages(pool->gfp_mask, pool->order);
+	struct scatterlist sg;
+
+	if (!page)
+		return NULL;
+
+	sg_init_table(&sg, 1);
+	sg_set_page(&sg, page, PAGE_SIZE << pool->order, 0);
+	dma_sync_sg_for_device(NULL, &sg, 1, DMA_BIDIRECTIONAL);
+
+	return page;
+}
+
+static void ion_page_pool_free_pages(struct ion_page_pool *pool,
+				     struct page *page)
+{
+	__free_pages(page, pool->order);
+}
+
+static int ion_page_pool_add(struct ion_page_pool *pool, struct page *page)
+{
+	struct ion_page_pool_item *item;
+
+	item = kmalloc(sizeof(struct ion_page_pool_item), GFP_KERNEL);
+	if (!item)
+		return -ENOMEM;
+
+	mutex_lock(&pool->mutex);
+	item->page = page;
+	if (PageHighMem(page)) {
+		list_add_tail(&item->list, &pool->high_items);
+		pool->high_count++;
+	} else {
+		list_add_tail(&item->list, &pool->low_items);
+		pool->low_count++;
+	}
+	mutex_unlock(&pool->mutex);
+	return 0;
+}
+
+static struct page *ion_page_pool_remove(struct ion_page_pool *pool, bool high)
+{
+	struct ion_page_pool_item *item;
+	struct page *page;
+
+	if (high) {
+		BUG_ON(!pool->high_count);
+		item = list_first_entry(&pool->high_items,
+					struct ion_page_pool_item, list);
+		pool->high_count--;
+	} else {
+		BUG_ON(!pool->low_count);
+		item = list_first_entry(&pool->low_items,
+					struct ion_page_pool_item, list);
+		pool->low_count--;
+	}
+
+	list_del(&item->list);
+	page = item->page;
+	kfree(item);
+	return page;
+}
+
+void *ion_page_pool_alloc(struct ion_page_pool *pool)
+{
+	struct page *page = NULL;
+
+	BUG_ON(!pool);
+
+	mutex_lock(&pool->mutex);
+	if (pool->high_count)
+		page = ion_page_pool_remove(pool, true);
+	else if (pool->low_count)
+		page = ion_page_pool_remove(pool, false);
+	mutex_unlock(&pool->mutex);
+
+	if (!page)
+		page = ion_page_pool_alloc_pages(pool);
+
+	return page;
+}
+
+void ion_page_pool_free(struct ion_page_pool *pool, struct page* page)
+{
+	int ret;
+
+	ret = ion_page_pool_add(pool, page);
+	if (ret)
+		ion_page_pool_free_pages(pool, page);
+}
+
+#ifdef DEBUG_PAGE_POOL_SHRINKER
+static int debug_drop_pools_set(void *data, u64 val)
+{
+	struct shrink_control sc;
+	int objs;
+
+	sc.gfp_mask = -1;
+	sc.nr_to_scan = 0;
+
+	if (!val)
+		return 0;
+
+	objs = shrinker.shrink(&shrinker, &sc);
+	sc.nr_to_scan = objs;
+
+	shrinker.shrink(&shrinker, &sc);
+	return 0;
+}
+
+static int debug_drop_pools_get(void *data, u64 *val)
+{
+	struct shrink_control sc;
+	int objs;
+
+	sc.gfp_mask = -1;
+	sc.nr_to_scan = 0;
+
+	objs = shrinker.shrink(&shrinker, &sc);
+	*val = objs;
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(debug_drop_pools_fops, debug_drop_pools_get,
+                        debug_drop_pools_set, "%llu\n");
+
+static int debug_grow_pools_set(void *data, u64 val)
+{
+	struct ion_page_pool *pool;
+	struct page *page;
+
+	plist_for_each_entry(pool, &pools, list) {
+		if (val != pool->list.prio)
+			continue;
+		page = ion_page_pool_alloc_pages(pool);
+		if (page)
+			ion_page_pool_add(pool, page);
+	}
+
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(debug_grow_pools_fops, debug_drop_pools_get,
+			debug_grow_pools_set, "%llu\n");
+#endif
+
+static int ion_page_pool_total(bool high)
+{
+	struct ion_page_pool *pool;
+	int total = 0;
+
+	plist_for_each_entry(pool, &pools, list) {
+		total += high ? (pool->high_count + pool->low_count) *
+			(1 << pool->order) :
+			pool->low_count * (1 << pool->order);
+	}
+	return total;
+}
+
+static int ion_page_pool_shrink(struct shrinker *shrinker,
+				 struct shrink_control *sc)
+{
+	struct ion_page_pool *pool;
+	int nr_freed = 0;
+	int i;
+	bool high;
+	int nr_to_scan = sc->nr_to_scan;
+
+	if (sc->gfp_mask & __GFP_HIGHMEM)
+		high = true;
+
+	if (nr_to_scan == 0)
+		return ion_page_pool_total(high);
+
+	plist_for_each_entry(pool, &pools, list) {
+		for (i = 0; i < nr_to_scan; i++) {
+			struct page *page;
+
+			mutex_lock(&pool->mutex);
+			if (high && pool->high_count) {
+				page = ion_page_pool_remove(pool, true);
+			} else if (pool->low_count) {
+				page = ion_page_pool_remove(pool, false);
+			} else {
+				mutex_unlock(&pool->mutex);
+				break;
+			}
+			mutex_unlock(&pool->mutex);
+			ion_page_pool_free_pages(pool, page);
+			nr_freed += (1 << pool->order);
+		}
+		nr_to_scan -= i;
+	}
+
+	return ion_page_pool_total(high);
+}
+
+struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order)
+{
+	struct ion_page_pool *pool = kmalloc(sizeof(struct ion_page_pool),
+					     GFP_KERNEL);
+	if (!pool)
+		return NULL;
+	pool->high_count = 0;
+	pool->low_count = 0;
+	INIT_LIST_HEAD(&pool->low_items);
+	INIT_LIST_HEAD(&pool->high_items);
+	pool->gfp_mask = gfp_mask;
+	pool->order = order;
+	mutex_init(&pool->mutex);
+	plist_node_init(&pool->list, order);
+	plist_add(&pool->list, &pools);
+
+	return pool;
+}
+
+void ion_page_pool_destroy(struct ion_page_pool *pool)
+{
+	plist_del(&pool->list, &pools);
+	kfree(pool);
+}
+
+static int __init ion_page_pool_init(void)
+{
+	shrinker.shrink = ion_page_pool_shrink;
+	shrinker.seeks = DEFAULT_SEEKS;
+	shrinker.batch = 0;
+	register_shrinker(&shrinker);
+#ifdef DEBUG_PAGE_POOL_SHRINKER
+	debugfs_create_file("ion_pools_shrink", 0644, NULL, NULL,
+			    &debug_drop_pools_fops);
+	debugfs_create_file("ion_pools_grow", 0644, NULL, NULL,
+			    &debug_grow_pools_fops);
+#endif
+	return 0;
+}
+
+static void __exit ion_page_pool_exit(void)
+{
+	unregister_shrinker(&shrinker);
+}
+
+module_init(ion_page_pool_init);
+module_exit(ion_page_pool_exit);
diff --git a/drivers/gpu/ion/ion_priv.h b/drivers/gpu/ion/ion_priv.h
index 71527ae..4b724df 100644
--- a/drivers/gpu/ion/ion_priv.h
+++ b/drivers/gpu/ion/ion_priv.h
@@ -18,14 +18,17 @@
 #ifndef _ION_PRIV_H
 #define _ION_PRIV_H
 
+#include <linux/ion.h>
 #include <linux/kref.h>
 #include <linux/mm_types.h>
 #include <linux/mutex.h>
 #include <linux/rbtree.h>
-#include <linux/ion.h>
 #include <linux/seq_file.h>
 
 #include "msm_ion_priv.h"
+#include <linux/sched.h>
+#include <linux/shrinker.h>
+#include <linux/types.h>
 
 struct ion_buffer *ion_handle_buffer(struct ion_handle *handle);
 
@@ -46,10 +49,22 @@
  * @vaddr:		the kenrel mapping if kmap_cnt is not zero
  * @dmap_cnt:		number of times the buffer is mapped for dma
  * @sg_table:		the sg table for the buffer if dmap_cnt is not zero
+ * @dirty:		bitmask representing which pages of this buffer have
+ *			been dirtied by the cpu and need cache maintenance
+ *			before dma
+ * @vmas:		list of vma's mapping this buffer
+ * @handle_count:	count of handles referencing this buffer
+ * @task_comm:		taskcomm of last client to reference this buffer in a
+ *			handle, used for debugging
+ * @pid:		pid of last client to reference this buffer in a
+ *			handle, used for debugging
 */
 struct ion_buffer {
 	struct kref ref;
-	struct rb_node node;
+	union {
+		struct rb_node node;
+		struct list_head list;
+	};
 	struct ion_device *dev;
 	struct ion_heap *heap;
 	unsigned long flags;
@@ -65,7 +80,10 @@
 	struct sg_table *sg_table;
 	unsigned long *dirty;
 	struct list_head vmas;
-	int marked;
+	/* used to track orphaned buffers */
+	int handle_count;
+	char task_comm[TASK_COMM_LEN];
+	pid_t pid;
 };
 
 /**
@@ -106,16 +124,28 @@
 };
 
 /**
+ * heap flags - flags between the heaps and core ion code
+ */
+#define ION_HEAP_FLAG_DEFER_FREE (1 << 0)
+
+/**
  * struct ion_heap - represents a heap in the system
  * @node:		rb node to put the heap on the device's tree of heaps
  * @dev:		back pointer to the ion_device
  * @type:		type of heap
  * @ops:		ops struct as above
+ * @flags:		flags
  * @id:			id of heap, also indicates priority of this heap when
  *			allocating.  These are specified by platform data and
  *			MUST be unique
  * @name:		used for debugging
  * @priv:		private heap data
+ * @free_list:		free list head if deferred free is used
+ * @lock:		protects the free list
+ * @waitqueue:		queue to wait on from deferred free thread
+ * @task:		task struct of deferred free thread
+ * @debug_show:		called when heap debug file is read to add any
+ *			heap specific debug info to output
  *
  * Represents a pool of memory from which buffers can be made.  In some
  * systems the only heap is regular system memory allocated via vmalloc.
@@ -123,16 +153,30 @@
  * that are allocated from a specially reserved heap.
  */
 struct ion_heap {
-	struct rb_node node;
+	struct plist_node node;
 	struct ion_device *dev;
 	enum ion_heap_type type;
 	struct ion_heap_ops *ops;
-	int id;
+	unsigned long flags;
+	unsigned int id;
 	const char *name;
 	void *priv;
+	struct list_head free_list;
+	struct rt_mutex lock;
+	wait_queue_head_t waitqueue;
+	struct task_struct *task;
+	int (*debug_show)(struct ion_heap *heap, struct seq_file *, void *);
 };
 
 /**
+ * ion_buffer_cached - this ion buffer is cached
+ * @buffer:		buffer
+ *
+ * indicates whether this ion buffer is cached
+ */
+bool ion_buffer_cached(struct ion_buffer *buffer);
+
+/**
  * ion_buffer_fault_user_mappings - fault in user mappings of this buffer
  * @buffer:		buffer
  *
@@ -166,6 +210,17 @@
 void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap);
 
 /**
+ * some helpers for common operations on buffers using the sg_table
+ * and vaddr fields
+ */
+void *ion_heap_map_kernel(struct ion_heap *, struct ion_buffer *);
+void ion_heap_unmap_kernel(struct ion_heap *, struct ion_buffer *);
+int ion_heap_map_user(struct ion_heap *, struct ion_buffer *,
+			struct vm_area_struct *);
+int ion_heap_buffer_zero(struct ion_buffer *buffer);
+
+
+/**
  * functions for creating and destroying the built in ion heaps.
  * architectures can add their own custom architecture specific
  * heaps as appropriate.
@@ -173,7 +228,6 @@
 
 struct ion_heap *ion_heap_create(struct ion_platform_heap *);
 void ion_heap_destroy(struct ion_heap *);
-
 struct ion_heap *ion_system_heap_create(struct ion_platform_heap *);
 void ion_system_heap_destroy(struct ion_heap *);
 
@@ -183,6 +237,8 @@
 struct ion_heap *ion_carveout_heap_create(struct ion_platform_heap *);
 void ion_carveout_heap_destroy(struct ion_heap *);
 
+struct ion_heap *ion_chunk_heap_create(struct ion_platform_heap *);
+void ion_chunk_heap_destroy(struct ion_heap *);
 /**
  * kernel api to allocate/free from carveout -- used when carveout is
  * used to back an architecture specific custom heap
@@ -198,4 +254,52 @@
  */
 #define ION_CARVEOUT_ALLOCATE_FAIL -1
 
+
+/**
+ * functions for creating and destroying a heap pool -- allows you
+ * to keep a pool of pre allocated memory to use from your heap.  Keeping
+ * a pool of memory that is ready for dma, ie any cached mapping have been
+ * invalidated from the cache, provides a significant peformance benefit on
+ * many systems */
+
+/**
+ * struct ion_page_pool - pagepool struct
+ * @high_count:		number of highmem items in the pool
+ * @low_count:		number of lowmem items in the pool
+ * @high_items:		list of highmem items
+ * @low_items:		list of lowmem items
+ * @shrinker:		a shrinker for the items
+ * @mutex:		lock protecting this struct and especially the count
+ *			item list
+ * @alloc:		function to be used to allocate pageory when the pool
+ *			is empty
+ * @free:		function to be used to free pageory back to the system
+ *			when the shrinker fires
+ * @gfp_mask:		gfp_mask to use from alloc
+ * @order:		order of pages in the pool
+ * @list:		plist node for list of pools
+ *
+ * Allows you to keep a pool of pre allocated pages to use from your heap.
+ * Keeping a pool of pages that is ready for dma, ie any cached mapping have
+ * been invalidated from the cache, provides a significant peformance benefit
+ * on many systems
+ */
+struct ion_page_pool {
+	int high_count;
+	int low_count;
+	struct list_head high_items;
+	struct list_head low_items;
+	struct mutex mutex;
+	void *(*alloc)(struct ion_page_pool *pool);
+	void (*free)(struct ion_page_pool *pool, struct page *page);
+	gfp_t gfp_mask;
+	unsigned int order;
+	struct plist_node list;
+};
+
+struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order);
+void ion_page_pool_destroy(struct ion_page_pool *);
+void *ion_page_pool_alloc(struct ion_page_pool *);
+void ion_page_pool_free(struct ion_page_pool *, struct page *);
+
 #endif /* _ION_PRIV_H */
diff --git a/drivers/gpu/ion/ion_system_heap.c b/drivers/gpu/ion/ion_system_heap.c
index f3f627d..02f6d93 100644
--- a/drivers/gpu/ion/ion_system_heap.c
+++ b/drivers/gpu/ion/ion_system_heap.c
@@ -22,6 +22,7 @@
 #include <linux/ion.h>
 #include <linux/mm.h>
 #include <linux/scatterlist.h>
+#include <linux/seq_file.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/seq_file.h>
@@ -34,30 +35,111 @@
 static atomic_t system_heap_allocated;
 static atomic_t system_contig_heap_allocated;
 
+static unsigned int high_order_gfp_flags = (GFP_HIGHUSER | __GFP_ZERO |
+					    __GFP_NOWARN | __GFP_NORETRY |
+					    __GFP_NO_KSWAPD) & ~__GFP_WAIT;
+static unsigned int low_order_gfp_flags  = (GFP_HIGHUSER | __GFP_ZERO |
+					 __GFP_NOWARN);
+static const unsigned int orders[] = {8, 4, 0};
+static const int num_orders = ARRAY_SIZE(orders);
+static int order_to_index(unsigned int order)
+{
+	int i;
+	for (i = 0; i < num_orders; i++)
+		if (order == orders[i])
+			return i;
+	BUG();
+	return -1;
+}
+
+static unsigned int order_to_size(int order)
+{
+	return PAGE_SIZE << order;
+}
+
+struct ion_system_heap {
+	struct ion_heap heap;
+	struct ion_page_pool **pools;
+};
+
 struct page_info {
 	struct page *page;
-	unsigned long order;
+	unsigned int order;
 	struct list_head list;
 };
 
-static struct page_info *alloc_largest_available(unsigned long size,
-						 bool split_pages)
+static struct page *alloc_buffer_page(struct ion_system_heap *heap,
+				      struct ion_buffer *buffer,
+				      unsigned long order)
 {
-	static unsigned int orders[] = {8, 4, 0};
+	bool cached = ion_buffer_cached(buffer);
+	bool split_pages = ion_buffer_fault_user_mappings(buffer);
+	struct ion_page_pool *pool = heap->pools[order_to_index(order)];
+	struct page *page;
+
+	if (!cached) {
+		page = ion_page_pool_alloc(pool);
+	} else {
+		struct scatterlist sg;
+		gfp_t gfp_flags = low_order_gfp_flags;
+
+		if (order > 4)
+			gfp_flags = high_order_gfp_flags;
+		page = alloc_pages(gfp_flags, order);
+		if (!page)
+			return 0;
+		sg_init_table(&sg, 1);
+		sg_set_page(&sg, page, PAGE_SIZE << order, 0);
+		dma_sync_sg_for_device(NULL, &sg, 1, DMA_BIDIRECTIONAL);
+	}
+	if (!page)
+		return 0;
+
+	if (split_pages)
+		split_page(page, order);
+	return page;
+}
+
+static void free_buffer_page(struct ion_system_heap *heap,
+			     struct ion_buffer *buffer, struct page *page,
+			     unsigned int order)
+{
+	bool cached = ion_buffer_cached(buffer);
+	bool split_pages = ion_buffer_fault_user_mappings(buffer);
+	int i;
+
+	if (!cached) {
+		struct ion_page_pool *pool = heap->pools[order_to_index(order)];
+		ion_page_pool_free(pool, page);
+	} else if (split_pages) {
+		for (i = 0; i < (1 << order); i++)
+			__free_page(page + i);
+	} else {
+		__free_pages(page, order);
+	}
+}
+
+
+static struct page_info *alloc_largest_available(struct ion_system_heap *heap,
+						 struct ion_buffer *buffer,
+						 unsigned long size,
+						 unsigned int max_order)
+{
 	struct page *page;
 	struct page_info *info;
 	int i;
 
-	for (i = 0; i < ARRAY_SIZE(orders); i++) {
-		if (size < (1 << orders[i]) * PAGE_SIZE)
+	for (i = 0; i < num_orders; i++) {
+		if (size < order_to_size(orders[i]))
 			continue;
-		page = alloc_pages(GFP_HIGHUSER | __GFP_ZERO |
-				   __GFP_NOWARN | __GFP_NORETRY, orders[i]);
+		if (max_order < orders[i])
+			continue;
+
+		page = alloc_buffer_page(heap, buffer, orders[i]);
 		if (!page)
 			continue;
-		if (split_pages)
-			split_page(page, orders[i]);
-		info = kmalloc(sizeof(struct page_info *), GFP_KERNEL);
+
+		info = kmalloc(sizeof(struct page_info), GFP_KERNEL);
 		info->page = page;
 		info->order = orders[i];
 		return info;
@@ -70,23 +152,27 @@
 				     unsigned long size, unsigned long align,
 				     unsigned long flags)
 {
+	struct ion_system_heap *sys_heap = container_of(heap,
+							struct ion_system_heap,
+							heap);
 	struct sg_table *table;
 	struct scatterlist *sg;
 	int ret;
 	struct list_head pages;
 	struct page_info *info, *tmp_info;
 	int i = 0;
-	long size_remaining = PAGE_ALIGN(size);
+	unsigned long size_remaining = PAGE_ALIGN(size);
+	unsigned int max_order = orders[0];
 	bool split_pages = ion_buffer_fault_user_mappings(buffer);
 
-
 	INIT_LIST_HEAD(&pages);
 	while (size_remaining > 0) {
-		info = alloc_largest_available(size_remaining, split_pages);
+		info = alloc_largest_available(sys_heap, buffer, size_remaining, max_order);
 		if (!info)
 			goto err;
 		list_add_tail(&info->list, &pages);
 		size_remaining -= (1 << info->order) * PAGE_SIZE;
+		max_order = info->order;
 		i++;
 	}
 
@@ -106,7 +192,6 @@
 	sg = table->sgl;
 	list_for_each_entry_safe(info, tmp_info, &pages, list) {
 		struct page *page = info->page;
-
 		if (split_pages) {
 			for (i = 0; i < (1 << info->order); i++) {
 				sg_set_page(sg, page + i, PAGE_SIZE, 0);
@@ -121,9 +206,6 @@
 		kfree(info);
 	}
 
-	dma_sync_sg_for_device(NULL, table->sgl, table->nents,
-			       DMA_BIDIRECTIONAL);
-
 	buffer->priv_virt = table;
 	atomic_add(size, &system_heap_allocated);
 	return 0;
@@ -131,12 +213,7 @@
 	kfree(table);
 err:
 	list_for_each_entry(info, &pages, list) {
-		if (split_pages)
-			for (i = 0; i < (1 << info->order); i++)
-				__free_page(info->page + i);
-		else
-			__free_pages(info->page, info->order);
-
+		free_buffer_page(sys_heap, buffer, info->page, info->order);
 		kfree(info);
 	}
 	return -ENOMEM;
@@ -144,15 +221,26 @@
 
 void ion_system_heap_free(struct ion_buffer *buffer)
 {
-	int i;
+	struct ion_heap *heap = buffer->heap;
+	struct ion_system_heap *sys_heap = container_of(heap,
+							struct ion_system_heap,
+							heap);
+	struct sg_table *table = buffer->sg_table;
+	bool cached = ion_buffer_cached(buffer);
 	struct scatterlist *sg;
-	struct sg_table *table = buffer->priv_virt;
+	LIST_HEAD(pages);
+	int i;
+
+	/* uncached pages come from the page pools, zero them before returning
+	   for security purposes (other allocations are zerod at alloc time */
+	if (!cached)
+		ion_heap_buffer_zero(buffer);
 
 	for_each_sg(table->sgl, sg, table->nents, i)
-		__free_pages(sg_page(sg), get_order(sg_dma_len(sg)));
-	if (buffer->sg_table)
-		sg_free_table(buffer->sg_table);
-	kfree(buffer->sg_table);
+		free_buffer_page(sys_heap, buffer, sg_page(sg),
+				get_order(sg_dma_len(sg)));
+	sg_free_table(table);
+	kfree(table);
 	atomic_sub(buffer->size, &system_heap_allocated);
 }
 
@@ -168,70 +256,6 @@
 	return;
 }
 
-void *ion_system_heap_map_kernel(struct ion_heap *heap,
-				 struct ion_buffer *buffer)
-{
-	struct scatterlist *sg;
-	int i, j;
-	void *vaddr;
-	pgprot_t pgprot;
-	struct sg_table *table = buffer->priv_virt;
-	int npages = PAGE_ALIGN(buffer->size) / PAGE_SIZE;
-	struct page **pages = kzalloc(sizeof(struct page *) * npages,
-				     GFP_KERNEL);
-	struct page **tmp = pages;
-
-	if (buffer->flags & ION_FLAG_CACHED)
-		pgprot = PAGE_KERNEL;
-	else
-		pgprot = pgprot_writecombine(PAGE_KERNEL);
-
-	for_each_sg(table->sgl, sg, table->nents, i) {
-		int npages_this_entry = PAGE_ALIGN(sg_dma_len(sg)) / PAGE_SIZE;
-		struct page *page = sg_page(sg);
-		BUG_ON(i >= npages);
-		for (j = 0; j < npages_this_entry; j++) {
-			*(tmp++) = page++;
-		}
-	}
-	vaddr = vmap(pages, npages, VM_MAP, pgprot);
-	kfree(pages);
-
-	return vaddr;
-}
-
-void ion_system_heap_unmap_kernel(struct ion_heap *heap,
-				  struct ion_buffer *buffer)
-{
-	vunmap(buffer->vaddr);
-}
-
-int ion_system_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer,
-			     struct vm_area_struct *vma)
-{
-	struct sg_table *table = buffer->priv_virt;
-	unsigned long addr = vma->vm_start;
-	unsigned long offset = vma->vm_pgoff;
-	struct scatterlist *sg;
-	int i;
-
-	if (!ION_IS_CACHED(buffer->flags)) {
-		pr_err("%s: cannot map system heap uncached\n", __func__);
-		return -EINVAL;
-	}
-
-	for_each_sg(table->sgl, sg, table->nents, i) {
-		if (offset) {
-			offset--;
-			continue;
-		}
-		remap_pfn_range(vma, addr, page_to_pfn(sg_page(sg)),
-				sg_dma_len(sg), vma->vm_page_prot);
-		addr += sg_dma_len(sg);
-	}
-	return 0;
-}
-
 static int ion_system_print_debug(struct ion_heap *heap, struct seq_file *s,
 				  const struct rb_root *unused)
 {
@@ -241,32 +265,65 @@
 	return 0;
 }
 
-static struct ion_heap_ops vmalloc_ops = {
+static struct ion_heap_ops system_heap_ops = {
 	.allocate = ion_system_heap_allocate,
 	.free = ion_system_heap_free,
 	.map_dma = ion_system_heap_map_dma,
 	.unmap_dma = ion_system_heap_unmap_dma,
-	.map_kernel = ion_system_heap_map_kernel,
-	.unmap_kernel = ion_system_heap_unmap_kernel,
-	.map_user = ion_system_heap_map_user,
+	.map_kernel = ion_heap_map_kernel,
+	.unmap_kernel = ion_heap_unmap_kernel,
+	.map_user = ion_heap_map_user,
 	.print_debug = ion_system_print_debug,
 };
 
 struct ion_heap *ion_system_heap_create(struct ion_platform_heap *pheap)
 {
-	struct ion_heap *heap;
+	struct ion_system_heap *heap;
+	int i;
 
-	heap = kzalloc(sizeof(struct ion_heap), GFP_KERNEL);
+	heap = kzalloc(sizeof(struct ion_system_heap), GFP_KERNEL);
 	if (!heap)
 		return ERR_PTR(-ENOMEM);
-	heap->ops = &vmalloc_ops;
-	heap->type = ION_HEAP_TYPE_SYSTEM;
-	return heap;
+	heap->heap.ops = &system_heap_ops;
+	heap->heap.type = ION_HEAP_TYPE_SYSTEM;
+	heap->heap.flags = ION_HEAP_FLAG_DEFER_FREE;
+	heap->pools = kzalloc(sizeof(struct ion_page_pool *) * num_orders,
+			      GFP_KERNEL);
+	if (!heap->pools)
+		goto err_alloc_pools;
+	for (i = 0; i < num_orders; i++) {
+		struct ion_page_pool *pool;
+		gfp_t gfp_flags = low_order_gfp_flags;
+
+		if (orders[i] > 4)
+			gfp_flags = high_order_gfp_flags;
+		pool = ion_page_pool_create(gfp_flags, orders[i]);
+		if (!pool)
+			goto err_create_pool;
+		heap->pools[i] = pool;
+	}
+	return &heap->heap;
+err_create_pool:
+	for (i = 0; i < num_orders; i++)
+		if (heap->pools[i])
+			ion_page_pool_destroy(heap->pools[i]);
+	kfree(heap->pools);
+err_alloc_pools:
+	kfree(heap);
+	return ERR_PTR(-ENOMEM);
 }
 
 void ion_system_heap_destroy(struct ion_heap *heap)
 {
-	kfree(heap);
+	struct ion_system_heap *sys_heap = container_of(heap,
+							struct ion_system_heap,
+							heap);
+	int i;
+
+	for (i = 0; i < num_orders; i++)
+		ion_page_pool_destroy(sys_heap->pools[i]);
+	kfree(sys_heap->pools);
+	kfree(sys_heap);
 }
 
 static int ion_system_contig_heap_allocate(struct ion_heap *heap,
@@ -367,8 +424,8 @@
 	.phys = ion_system_contig_heap_phys,
 	.map_dma = ion_system_contig_heap_map_dma,
 	.unmap_dma = ion_system_contig_heap_unmap_dma,
-	.map_kernel = ion_system_contig_heap_map_kernel,
-	.unmap_kernel = ion_system_contig_heap_unmap_kernel,
+	.map_kernel = ion_heap_map_kernel,
+	.unmap_kernel = ion_heap_unmap_kernel,
 	.map_user = ion_system_contig_heap_map_user,
 	.print_debug = ion_system_contig_print_debug,
 };
diff --git a/drivers/gpu/ion/msm/ion_iommu_map.c b/drivers/gpu/ion/msm/ion_iommu_map.c
index ae4ae37..5ce03db 100644
--- a/drivers/gpu/ion/msm/ion_iommu_map.c
+++ b/drivers/gpu/ion/msm/ion_iommu_map.c
@@ -206,8 +206,8 @@
 	 * biggest entry. To take advantage of bigger mapping sizes both the
 	 * VA and PA addresses have to be aligned to the biggest size.
 	 */
-	if (table->sgl->length > align)
-		align = table->sgl->length;
+	if (sg_dma_len(table->sgl) > align)
+		align = sg_dma_len(table->sgl);
 
 	ret = msm_allocate_iova_address(domain_num, partition_num,
 						data->mapped_size, align,
diff --git a/drivers/gpu/ion/msm/msm_ion.c b/drivers/gpu/ion/msm/msm_ion.c
index 9259de2..f43d276 100644
--- a/drivers/gpu/ion/msm/msm_ion.c
+++ b/drivers/gpu/ion/msm/msm_ion.c
@@ -128,7 +128,7 @@
 struct ion_client *msm_ion_client_create(unsigned int heap_mask,
 					const char *name)
 {
-	return ion_client_create(idev, heap_mask, name);
+	return ion_client_create(idev, name);
 }
 EXPORT_SYMBOL(msm_ion_client_create);
 
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 5589ff0..d5904b9 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"
@@ -2782,7 +2781,7 @@
 	if (device->state == KGSL_STATE_ACTIVE) {
 		/* Is the ring buffer is empty? */
 		GSL_RB_GET_READPTR(rb, &rb->rptr);
-		if (!device->active_cnt && (rb->rptr == rb->wptr)) {
+		if (rb->rptr == rb->wptr) {
 			/*
 			 * Are there interrupts pending? If so then pretend we
 			 * are not idle - this avoids the possiblity that we go
@@ -2952,7 +2951,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));
@@ -3040,7 +3039,7 @@
 
 		if (context && device->state != KGSL_STATE_SLUMBER) {
 			adreno_ringbuffer_issuecmds(device, context->devctxt,
-					KGSL_CMD_FLAGS_NONE, NULL, 0);
+					KGSL_CMD_FLAGS_GET_INT, NULL, 0);
 		}
 	}
 
@@ -3596,15 +3595,20 @@
 {
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
-	unsigned int cycles;
+	unsigned int cycles = 0;
 
-	/* Get the busy cycles counted since the counter was last reset */
-	/* Calling this function also resets and restarts the counter */
+	/*
+	 * Get the busy cycles counted since the counter was last reset.
+	 * If we're not currently active, there shouldn't have been
+	 * any cycles since the last time this function was called.
+	 */
+	if (device->state == KGSL_STATE_ACTIVE)
+		cycles = adreno_dev->gpudev->busy_cycles(adreno_dev);
 
-	cycles = adreno_dev->gpudev->busy_cycles(adreno_dev);
-
-	/* In order to calculate idle you have to have run the algorithm *
-	 * at least once to get a start time. */
+	/*
+	 * In order to calculate idle you have to have run the algorithm
+	 * at least once to get a start time.
+	 */
 	if (pwr->time != 0) {
 		s64 tmp = ktime_to_us(ktime_get());
 		stats->total_time = tmp - pwr->time;
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 90d6027..3935cd8 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -34,6 +34,7 @@
 #define KGSL_CMD_FLAGS_NONE             0x00000000
 #define KGSL_CMD_FLAGS_PMODE		0x00000001
 #define KGSL_CMD_FLAGS_INTERNAL_ISSUE	0x00000002
+#define KGSL_CMD_FLAGS_GET_INT		0x00000004
 #define KGSL_CMD_FLAGS_EOF	        0x00000100
 
 /* Command identifiers */
diff --git a/drivers/gpu/msm/adreno_debugfs.c b/drivers/gpu/msm/adreno_debugfs.c
index ef599e9..980ff13 100644
--- a/drivers/gpu/msm/adreno_debugfs.c
+++ b/drivers/gpu/msm/adreno_debugfs.c
@@ -93,4 +93,7 @@
 	 adreno_dev->ft_pf_policy = KGSL_FT_PAGEFAULT_DEFAULT_POLICY;
 	 debugfs_create_u32("ft_pagefault_policy", 0644, device->d_debugfs,
 			&adreno_dev->ft_pf_policy);
+
+	debugfs_create_u32("active_cnt", 0444, device->d_debugfs,
+			   &device->active_cnt);
 }
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index a4bb4fa..8c96884 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"
@@ -544,13 +543,15 @@
 	/*
 	 * if the context was not created with per context timestamp
 	 * support, we must use the global timestamp since issueibcmds
-	 * will be returning that one.
+	 * will be returning that one, or if an internal issue then
+	 * use global timestamp.
 	 */
-	if (context && context->flags & CTXT_FLAGS_PER_CONTEXT_TS)
+	if ((context && (context->flags & CTXT_FLAGS_PER_CONTEXT_TS)) &&
+		!(flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE))
 		context_id = context->id;
 
-	if ((context && context->flags & CTXT_FLAGS_USER_GENERATED_TS) &&
-			(!(flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE))) {
+	if ((context && (context->flags & CTXT_FLAGS_USER_GENERATED_TS)) &&
+		!(flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE)) {
 		if (timestamp_cmp(rb->timestamp[context_id],
 						timestamp) >= 0) {
 			KGSL_DRV_ERR(rb->device,
@@ -574,6 +575,11 @@
 	/* Add CP_COND_EXEC commands to generate CP_INTERRUPT */
 	total_sizedwords += context ? 13 : 0;
 
+	if ((context) && (context->flags & CTXT_FLAGS_PER_CONTEXT_TS) &&
+		(flags & (KGSL_CMD_FLAGS_INTERNAL_ISSUE |
+		KGSL_CMD_FLAGS_GET_INT)))
+			total_sizedwords += 2;
+
 	if (adreno_is_a3xx(adreno_dev))
 		total_sizedwords += 7;
 
@@ -584,11 +590,9 @@
 	total_sizedwords += 3; /* sop timestamp */
 	total_sizedwords += 4; /* eop timestamp */
 
-	if (context && context->flags & CTXT_FLAGS_PER_CONTEXT_TS &&
-			!(flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE)) {
+	if (KGSL_MEMSTORE_GLOBAL != context_id)
 		total_sizedwords += 3; /* global timestamp without cache
 					* flush for non-zero context */
-	}
 
 	if (adreno_is_a20x(adreno_dev))
 		total_sizedwords += 2; /* CACHE_FLUSH */
@@ -619,12 +623,12 @@
 	/* always increment the global timestamp. once. */
 	rb->timestamp[KGSL_MEMSTORE_GLOBAL]++;
 
-	/* Do not update context's timestamp for internal submissions */
-	if (context && !(flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE)) {
-		if (context_id == KGSL_MEMSTORE_GLOBAL)
-			rb->timestamp[context->id] =
-				rb->timestamp[KGSL_MEMSTORE_GLOBAL];
-		else if (context->flags & CTXT_FLAGS_USER_GENERATED_TS)
+	/*
+	 * If global timestamp then we are not using per context ts for
+	 * this submission
+	 */
+	if (context_id != KGSL_MEMSTORE_GLOBAL) {
+		if (context->flags & CTXT_FLAGS_USER_GENERATED_TS)
 			rb->timestamp[context_id] = timestamp;
 		else
 			rb->timestamp[context_id]++;
@@ -695,9 +699,7 @@
 		KGSL_MEMSTORE_OFFSET(context_id, eoptimestamp)));
 	GSL_RB_WRITE(ringcmds, rcmd_gpu, timestamp);
 
-	if (context && context->flags & CTXT_FLAGS_PER_CONTEXT_TS
-			&& !(flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE)) {
-
+	if (KGSL_MEMSTORE_GLOBAL != context_id) {
 		GSL_RB_WRITE(ringcmds, rcmd_gpu,
 			cp_type3_packet(CP_MEM_WRITE, 2));
 		GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
@@ -749,6 +751,19 @@
 		GSL_RB_WRITE(ringcmds, rcmd_gpu, CP_INT_CNTL__RB_INT_MASK);
 	}
 
+	/*
+	 * If per context timestamps are enabled and any of the kgsl
+	 * internal commands want INT to be generated trigger the INT
+	*/
+	if ((context) && (context->flags & CTXT_FLAGS_PER_CONTEXT_TS) &&
+		(flags & (KGSL_CMD_FLAGS_INTERNAL_ISSUE |
+		KGSL_CMD_FLAGS_GET_INT))) {
+			GSL_RB_WRITE(ringcmds, rcmd_gpu,
+				cp_type3_packet(CP_INTERRUPT, 1));
+			GSL_RB_WRITE(ringcmds, rcmd_gpu,
+				CP_INT_CNTL__RB_INT_MASK);
+	}
+
 	if (adreno_is_a3xx(adreno_dev)) {
 		/* Dummy set-constant to trigger context rollover */
 		GSL_RB_WRITE(ringcmds, rcmd_gpu,
@@ -1107,7 +1122,7 @@
 		ret = 0;
 
 done:
-	trace_kgsl_issueibcmds(device, context->id, ibdesc, numibs,
+	kgsl_trace_issueibcmds(device, context->id, ibdesc, numibs,
 		*timestamp, flags, ret, drawctxt->type);
 
 	kfree(link);
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 53ef392..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;
@@ -413,27 +453,6 @@
 	kfree(context);
 }
 
-static void kgsl_check_idle_locked(struct kgsl_device *device)
-{
-	if (device->pwrctrl.nap_allowed == true &&
-	    device->state == KGSL_STATE_ACTIVE &&
-		device->requested_state == KGSL_STATE_NONE) {
-		kgsl_pwrctrl_request_state(device, KGSL_STATE_NAP);
-		kgsl_pwrscale_idle(device);
-		if (kgsl_pwrctrl_sleep(device) != 0)
-			mod_timer(&device->idle_timer,
-				  jiffies +
-				  device->pwrctrl.interval_timeout);
-	}
-}
-
-static void kgsl_check_idle(struct kgsl_device *device)
-{
-	mutex_lock(&device->mutex);
-	kgsl_check_idle_locked(device);
-	mutex_unlock(&device->mutex);
-}
-
 struct kgsl_device *kgsl_get_device(int dev_idx)
 {
 	int i;
@@ -496,13 +515,12 @@
 	policy_saved = device->pwrscale.policy;
 	device->pwrscale.policy = NULL;
 	kgsl_pwrctrl_request_state(device, KGSL_STATE_SUSPEND);
-	/* Make sure no user process is waiting for a timestamp *
-	 * before supending */
-	if (device->active_cnt != 0) {
-		mutex_unlock(&device->mutex);
-		wait_for_completion(&device->suspend_gate);
-		mutex_lock(&device->mutex);
-	}
+	/*
+	 * Make sure no user process is waiting for a timestamp
+	 * before supending.
+	 */
+	kgsl_active_count_wait(device);
+
 	/* Don't let the timer wake us during suspended sleep. */
 	del_timer_sync(&device->idle_timer);
 	switch (device->state) {
@@ -513,6 +531,8 @@
 			device->ftbl->idle(device);
 		case KGSL_STATE_NAP:
 		case KGSL_STATE_SLEEP:
+			/* make sure power is on to stop the device */
+			kgsl_pwrctrl_enable(device);
 			/* Get the completion ready to be waited upon. */
 			INIT_COMPLETION(device->hwaccess_gate);
 			device->ftbl->suspend_context(device);
@@ -632,9 +652,16 @@
 	device->pwrctrl.restore_slumber = false;
 	if (device->pwrscale.policy == NULL)
 		kgsl_pwrctrl_pwrlevel_change(device, KGSL_PWRLEVEL_TURBO);
-	kgsl_pwrctrl_wake(device);
+	if (kgsl_pwrctrl_wake(device) != 0)
+		return;
+	/*
+	 * We don't have a way to go directly from
+	 * a deeper sleep state to NAP, which is
+	 * the desired state here.
+	 */
+	kgsl_pwrctrl_request_state(device, KGSL_STATE_NAP);
+	kgsl_pwrctrl_sleep(device);
 	mutex_unlock(&device->mutex);
-	kgsl_check_idle(device);
 	KGSL_PWR_WARN(device, "late resume end\n");
 }
 EXPORT_SYMBOL(kgsl_late_resume_driver);
@@ -745,7 +772,7 @@
 	filep->private_data = NULL;
 
 	mutex_lock(&device->mutex);
-	kgsl_check_suspended(device);
+	kgsl_active_count_get(device);
 
 	while (1) {
 		context = idr_get_next(&device->context_idr, &next);
@@ -767,10 +794,17 @@
 
 	device->open_count--;
 	if (device->open_count == 0) {
+		BUG_ON(device->active_cnt > 1);
 		result = device->ftbl->stop(device);
 		kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
+		/*
+		 * active_cnt special case: we just stopped the device,
+		 * so no need to use kgsl_active_count_put()
+		 */
+		device->active_cnt--;
+	} else {
+		kgsl_active_count_put(device);
 	}
-
 	mutex_unlock(&device->mutex);
 	kfree(dev_priv);
 
@@ -816,9 +850,14 @@
 	filep->private_data = dev_priv;
 
 	mutex_lock(&device->mutex);
-	kgsl_check_suspended(device);
 
 	if (device->open_count == 0) {
+		/*
+		 * active_cnt special case: we are starting up for the first
+		 * time, so use this sequence instead of the kgsl_pwrctrl_wake()
+		 * which will be called by kgsl_active_count_get().
+		 */
+		device->active_cnt++;
 		kgsl_sharedmem_set(&device->memstore, 0, 0,
 				device->memstore.size);
 
@@ -831,6 +870,7 @@
 			goto err_freedevpriv;
 
 		kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE);
+		kgsl_active_count_put(device);
 	}
 	device->open_count++;
 	mutex_unlock(&device->mutex);
@@ -856,10 +896,15 @@
 	mutex_lock(&device->mutex);
 	device->open_count--;
 	if (device->open_count == 0) {
+		/* make sure power is on to stop the device */
+		kgsl_pwrctrl_enable(device);
 		result = device->ftbl->stop(device);
 		kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
 	}
 err_freedevpriv:
+	/* only the first open takes an active count */
+	if (device->open_count == 0)
+		device->active_cnt--;
 	mutex_unlock(&device->mutex);
 	filep->private_data = NULL;
 	kfree(dev_priv);
@@ -1073,10 +1118,6 @@
 	struct kgsl_device *device = dev_priv->device;
 	unsigned int context_id = context ? context->id : KGSL_MEMSTORE_GLOBAL;
 
-	/* Set the active count so that suspend doesn't do the wrong thing */
-
-	device->active_cnt++;
-
 	trace_kgsl_waittimestamp_entry(device, context_id,
 				       kgsl_readtimestamp(device, context,
 							KGSL_TIMESTAMP_RETIRED),
@@ -1090,9 +1131,6 @@
 							KGSL_TIMESTAMP_RETIRED),
 				      result);
 
-	/* Fire off any pending suspend operations that are in flight */
-	kgsl_active_count_put(dev_priv->device);
-
 	return result;
 }
 
@@ -1887,7 +1925,6 @@
 
 	trace_kgsl_mem_map(entry, param->fd);
 
-	kgsl_check_idle(dev_priv->device);
 	return result;
 
 error_unmap:
@@ -1907,7 +1944,6 @@
 	}
 error:
 	kfree(entry);
-	kgsl_check_idle(dev_priv->device);
 	return result;
 }
 
@@ -2035,7 +2071,6 @@
 
 	entry->memtype = KGSL_MEM_ENTRY_KERNEL;
 
-	kgsl_check_idle(dev_priv->device);
 	*ret_entry = entry;
 	return result;
 err:
@@ -2370,7 +2405,7 @@
 			kgsl_ioctl_cff_user_event, 0),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_TIMESTAMP_EVENT,
 			kgsl_ioctl_timestamp_event,
-			KGSL_IOCTL_LOCK),
+			KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_SETPROPERTY,
 			kgsl_ioctl_device_setproperty,
 			KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE),
@@ -2462,14 +2497,19 @@
 
 	if (lock) {
 		mutex_lock(&dev_priv->device->mutex);
-		if (use_hw)
-			kgsl_check_suspended(dev_priv->device);
+		if (use_hw) {
+			ret = kgsl_active_count_get(dev_priv->device);
+			if (ret < 0)
+				goto unlock;
+		}
 	}
 
 	ret = func(dev_priv, cmd, uptr);
 
+unlock:
 	if (lock) {
-		kgsl_check_idle_locked(dev_priv->device);
+		if (use_hw)
+			kgsl_active_count_put(dev_priv->device);
 		mutex_unlock(&dev_priv->device->mutex);
 	}
 
@@ -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,
@@ -3032,11 +3094,7 @@
 	/* For a manual dump, make sure that the system is idle */
 
 	if (manual) {
-		if (device->active_cnt != 0) {
-			mutex_unlock(&device->mutex);
-			wait_for_completion(&device->suspend_gate);
-			mutex_lock(&device->mutex);
-		}
+		kgsl_active_count_wait(device);
 
 		if (device->state == KGSL_STATE_ACTIVE)
 			kgsl_idle(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_device.h b/drivers/gpu/msm/kgsl_device.h
index 0d11660..ac82820 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -454,23 +454,4 @@
 	kref_put(&context->refcount, kgsl_context_destroy);
 }
 
-/**
- * kgsl_active_count_put - Decrease the device active count
- * @device: Pointer to a KGSL device
- *
- * Decrease the active count for the KGSL device and trigger the suspend_gate
- * completion if it hits zero
- */
-static inline void
-kgsl_active_count_put(struct kgsl_device *device)
-{
-	if (device->active_cnt == 1)
-		INIT_COMPLETION(device->suspend_gate);
-
-	device->active_cnt--;
-
-	if (device->active_cnt == 0)
-		complete(&device->suspend_gate);
-}
-
 #endif  /* __KGSL_DEVICE_H */
diff --git a/drivers/gpu/msm/kgsl_events.c b/drivers/gpu/msm/kgsl_events.c
index 9e9c0da..d872783 100644
--- a/drivers/gpu/msm/kgsl_events.c
+++ b/drivers/gpu/msm/kgsl_events.c
@@ -51,6 +51,7 @@
 	void (*cb)(struct kgsl_device *, void *, u32, u32), void *priv,
 	void *owner)
 {
+	int ret;
 	struct kgsl_event *event;
 	unsigned int cur_ts;
 	struct kgsl_context *context = NULL;
@@ -82,6 +83,16 @@
 	if (event == NULL)
 		return -ENOMEM;
 
+	/*
+	 * Increase the active count on the device to avoid going into power
+	 * saving modes while events are pending
+	 */
+	ret = kgsl_active_count_get_light(device);
+	if (ret < 0) {
+		kfree(event);
+		return ret;
+	}
+
 	event->context = context;
 	event->timestamp = ts;
 	event->priv = priv;
@@ -112,13 +123,6 @@
 	} else
 		_add_event_to_list(&device->events, event);
 
-	/*
-	 * Increase the active count on the device to avoid going into power
-	 * saving modes while events are pending
-	 */
-
-	device->active_cnt++;
-
 	queue_work(device->work_queue, &device->ts_expired_ws);
 	return 0;
 }
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_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 2f8d93e..5909153 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -1055,6 +1055,14 @@
 	pwr->power_flags = 0;
 }
 
+/**
+ * kgsl_idle_check() - Work function for GPU interrupts and idle timeouts.
+ * @device: The device
+ *
+ * This function is called for work that is queued by the interrupt
+ * handler or the idle timer. It attempts to transition to a clocks
+ * off state if the active_cnt is 0 and the hardware is idle.
+ */
 void kgsl_idle_check(struct work_struct *work)
 {
 	struct kgsl_device *device = container_of(work, struct kgsl_device,
@@ -1064,15 +1072,22 @@
 		return;
 
 	mutex_lock(&device->mutex);
-	if (device->state & (KGSL_STATE_ACTIVE | KGSL_STATE_NAP)) {
-		kgsl_pwrscale_idle(device);
 
-		if (kgsl_pwrctrl_sleep(device) != 0) {
+	kgsl_pwrscale_idle(device);
+
+	if (device->state == KGSL_STATE_ACTIVE
+		   || device->state ==  KGSL_STATE_NAP) {
+		if (device->active_cnt > 0 || kgsl_pwrctrl_sleep(device) != 0) {
+
+			kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
+
 			mod_timer(&device->idle_timer,
 					jiffies +
 					device->pwrctrl.interval_timeout);
-			/* If the GPU has been too busy to sleep, make sure *
-			 * that is acurately reflected in the % busy numbers. */
+			/*
+			 * If the GPU has been too busy to sleep, make sure
+			 * that is acurately reflected in the % busy numbers.
+			 */
 			device->pwrctrl.clk_stats.no_nap_cnt++;
 			if (device->pwrctrl.clk_stats.no_nap_cnt >
 							 UPDATE_BUSY) {
@@ -1087,6 +1102,7 @@
 
 	mutex_unlock(&device->mutex);
 }
+EXPORT_SYMBOL(kgsl_idle_check);
 
 void kgsl_timer(unsigned long data)
 {
@@ -1104,54 +1120,26 @@
 	}
 }
 
+
+/**
+ * kgsl_pre_hwaccess - Enforce preconditions for touching registers
+ * @device: The device
+ *
+ * This function ensures that the correct lock is held and that the GPU
+ * clock is on immediately before a register is read or written. Note
+ * that this function does not check active_cnt because the registers
+ * must be accessed during device start and stop, when the active_cnt
+ * may legitimately be 0.
+ */
 void kgsl_pre_hwaccess(struct kgsl_device *device)
 {
+	/* In order to touch a register you must hold the device mutex...*/
 	BUG_ON(!mutex_is_locked(&device->mutex));
-	switch (device->state) {
-	case KGSL_STATE_ACTIVE:
-		return;
-	case KGSL_STATE_NAP:
-	case KGSL_STATE_SLEEP:
-	case KGSL_STATE_SLUMBER:
-		kgsl_pwrctrl_wake(device);
-		break;
-	case KGSL_STATE_SUSPEND:
-		kgsl_check_suspended(device);
-		break;
-	case KGSL_STATE_INIT:
-	case KGSL_STATE_HUNG:
-	case KGSL_STATE_DUMP_AND_FT:
-		if (test_bit(KGSL_PWRFLAGS_CLK_ON,
-					 &device->pwrctrl.power_flags))
-			break;
-		else
-			KGSL_PWR_ERR(device,
-					"hw access while clocks off from state %d\n",
-					device->state);
-		break;
-	default:
-		KGSL_PWR_ERR(device, "hw access while in unknown state %d\n",
-					 device->state);
-		break;
-	}
+	/* and have the clock on! */
+	BUG_ON(!test_bit(KGSL_PWRFLAGS_CLK_ON, &device->pwrctrl.power_flags));
 }
 EXPORT_SYMBOL(kgsl_pre_hwaccess);
 
-void kgsl_check_suspended(struct kgsl_device *device)
-{
-	if (device->requested_state == KGSL_STATE_SUSPEND ||
-				device->state == KGSL_STATE_SUSPEND) {
-		mutex_unlock(&device->mutex);
-		wait_for_completion(&device->hwaccess_gate);
-		mutex_lock(&device->mutex);
-	} else if (device->state == KGSL_STATE_DUMP_AND_FT) {
-		mutex_unlock(&device->mutex);
-		wait_for_completion(&device->ft_gate);
-		mutex_lock(&device->mutex);
-	} else if (device->state == KGSL_STATE_SLUMBER)
-		kgsl_pwrctrl_wake(device);
-}
-
 static int
 _nap(struct kgsl_device *device)
 {
@@ -1230,6 +1218,8 @@
 	case KGSL_STATE_NAP:
 	case KGSL_STATE_SLEEP:
 		del_timer_sync(&device->idle_timer);
+		/* make sure power is on to stop the device*/
+		kgsl_pwrctrl_enable(device);
 		device->ftbl->suspend_context(device);
 		device->ftbl->stop(device);
 		_sleep_accounting(device);
@@ -1278,9 +1268,9 @@
 
 /******************************************************************/
 /* Caller must hold the device mutex. */
-void kgsl_pwrctrl_wake(struct kgsl_device *device)
+int kgsl_pwrctrl_wake(struct kgsl_device *device)
 {
-	int status;
+	int status = 0;
 	unsigned int context_id;
 	unsigned int state = device->state;
 	unsigned int ts_processed = 0xdeaddead;
@@ -1329,8 +1319,10 @@
 		KGSL_PWR_WARN(device, "unhandled state %s\n",
 				kgsl_pwrstate_to_str(device->state));
 		kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
+		status = -EINVAL;
 		break;
 	}
+	return status;
 }
 EXPORT_SYMBOL(kgsl_pwrctrl_wake);
 
@@ -1396,3 +1388,124 @@
 }
 EXPORT_SYMBOL(kgsl_pwrstate_to_str);
 
+
+/**
+ * kgsl_active_count_get() - Increase the device active count
+ * @device: Pointer to a KGSL device
+ *
+ * Increase the active count for the KGSL device and turn on
+ * clocks if this is the first reference. Code paths that need
+ * to touch the hardware or wait for the hardware to complete
+ * an operation must hold an active count reference until they
+ * are finished. An error code will be returned if waking the
+ * device fails. The device mutex must be held while *calling
+ * this function.
+ */
+int kgsl_active_count_get(struct kgsl_device *device)
+{
+	int ret = 0;
+	BUG_ON(!mutex_is_locked(&device->mutex));
+
+	if (device->active_cnt == 0) {
+		if (device->requested_state == KGSL_STATE_SUSPEND ||
+				device->state == KGSL_STATE_SUSPEND) {
+			mutex_unlock(&device->mutex);
+			wait_for_completion(&device->hwaccess_gate);
+			mutex_lock(&device->mutex);
+		} else if (device->state == KGSL_STATE_DUMP_AND_FT) {
+			mutex_unlock(&device->mutex);
+			wait_for_completion(&device->ft_gate);
+			mutex_lock(&device->mutex);
+		}
+		ret = kgsl_pwrctrl_wake(device);
+	}
+	if (ret == 0)
+		device->active_cnt++;
+	return ret;
+}
+EXPORT_SYMBOL(kgsl_active_count_get);
+
+/**
+ * kgsl_active_count_get_light() - Increase the device active count
+ * @device: Pointer to a KGSL device
+ *
+ * Increase the active count for the KGSL device WITHOUT
+ * turning on the clocks. Currently this is only used for creating
+ * kgsl_events. The device mutex must be held while calling this function.
+ */
+int kgsl_active_count_get_light(struct kgsl_device *device)
+{
+	BUG_ON(!mutex_is_locked(&device->mutex));
+
+	if (device->state != KGSL_STATE_ACTIVE) {
+		dev_WARN_ONCE(device->dev, 1, "device in unexpected state %s\n",
+				kgsl_pwrstate_to_str(device->state));
+		return -EINVAL;
+	}
+
+	if (device->active_cnt == 0) {
+		dev_WARN_ONCE(device->dev, 1, "active count is 0!\n");
+		return -EINVAL;
+	}
+
+	device->active_cnt++;
+	return 0;
+}
+EXPORT_SYMBOL(kgsl_active_count_get_light);
+
+/**
+ * kgsl_active_count_put() - Decrease the device active count
+ * @device: Pointer to a KGSL device
+ *
+ * Decrease the active count for the KGSL device and turn off
+ * clocks if there are no remaining references. This function will
+ * transition the device to NAP if there are no other pending state
+ * changes. It also completes the suspend gate.  The device mutex must
+ * be held while calling this function.
+ */
+void kgsl_active_count_put(struct kgsl_device *device)
+{
+	BUG_ON(!mutex_is_locked(&device->mutex));
+	BUG_ON(device->active_cnt == 0);
+
+	kgsl_pwrscale_idle(device);
+	if (device->active_cnt > 1) {
+		device->active_cnt--;
+		return;
+	}
+
+	INIT_COMPLETION(device->suspend_gate);
+
+	if (device->pwrctrl.nap_allowed == true &&
+			(device->state == KGSL_STATE_ACTIVE &&
+			device->requested_state == KGSL_STATE_NONE)) {
+		kgsl_pwrctrl_request_state(device, KGSL_STATE_NAP);
+		if (kgsl_pwrctrl_sleep(device) != 0)
+			mod_timer(&device->idle_timer,
+					jiffies
+					+ device->pwrctrl.interval_timeout);
+	}
+	device->active_cnt--;
+
+	if (device->active_cnt == 0)
+		complete(&device->suspend_gate);
+}
+EXPORT_SYMBOL(kgsl_active_count_put);
+
+/**
+ * kgsl_active_count_wait() - Wait for activity to finish.
+ * @device: Pointer to a KGSL device
+ *
+ * Block until all active_cnt users put() their reference.
+ */
+void kgsl_active_count_wait(struct kgsl_device *device)
+{
+	BUG_ON(!mutex_is_locked(&device->mutex));
+
+	if (device->active_cnt != 0) {
+		mutex_unlock(&device->mutex);
+		wait_for_completion(&device->suspend_gate);
+		mutex_lock(&device->mutex);
+	}
+}
+EXPORT_SYMBOL(kgsl_active_count_wait);
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h
index ced52e1..0fd64c3 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.h
+++ b/drivers/gpu/msm/kgsl_pwrctrl.h
@@ -99,9 +99,8 @@
 void kgsl_timer(unsigned long data);
 void kgsl_idle_check(struct work_struct *work);
 void kgsl_pre_hwaccess(struct kgsl_device *device);
-void kgsl_check_suspended(struct kgsl_device *device);
 int kgsl_pwrctrl_sleep(struct kgsl_device *device);
-void kgsl_pwrctrl_wake(struct kgsl_device *device);
+int kgsl_pwrctrl_wake(struct kgsl_device *device);
 void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device,
 	unsigned int level);
 int kgsl_pwrctrl_init_sysfs(struct kgsl_device *device);
@@ -115,4 +114,10 @@
 
 void kgsl_pwrctrl_set_state(struct kgsl_device *device, unsigned int state);
 void kgsl_pwrctrl_request_state(struct kgsl_device *device, unsigned int state);
+
+int kgsl_active_count_get(struct kgsl_device *device);
+int kgsl_active_count_get_light(struct kgsl_device *device);
+void kgsl_active_count_put(struct kgsl_device *device);
+void kgsl_active_count_wait(struct kgsl_device *device);
+
 #endif /* __KGSL_PWRCTRL_H */
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_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-current.c b/drivers/hwmon/qpnp-adc-current.c
index 0b02a34..66811bf 100644
--- a/drivers/hwmon/qpnp-adc-current.c
+++ b/drivers/hwmon/qpnp-adc-current.c
@@ -129,6 +129,7 @@
 struct qpnp_iadc_drv {
 	struct qpnp_adc_drv			*adc;
 	int32_t					rsense;
+	bool					external_rsense;
 	struct device				*iadc_hwmon;
 	bool					iadc_initialized;
 	int64_t					die_temp_calib_offset;
@@ -543,6 +544,9 @@
 	if (!iadc || !iadc->iadc_initialized)
 		return -EPROBE_DEFER;
 
+	if (iadc->external_rsense)
+		*rsense = iadc->rsense;
+
 	rc = qpnp_iadc_read_reg(QPNP_IADC_NOMINAL_RSENSE, &rslt_rsense);
 	if (rc < 0) {
 		pr_err("qpnp adc rsense read failed with %d\n", rc);
@@ -571,15 +575,21 @@
 {
 	struct qpnp_iadc_drv *iadc = qpnp_iadc;
 	struct qpnp_vadc_result result_pmic_therm;
+	int64_t die_temp_offset;
 	int rc = 0;
 
 	rc = qpnp_vadc_read(DIE_TEMP, &result_pmic_therm);
 	if (rc < 0)
 		return rc;
 
-	if (((uint64_t) (result_pmic_therm.physical -
-				iadc->die_temp_calib_offset))
-			> QPNP_IADC_DIE_TEMP_CALIB_OFFSET) {
+	die_temp_offset = result_pmic_therm.physical -
+			iadc->die_temp_calib_offset;
+	if (die_temp_offset < 0)
+		die_temp_offset = -die_temp_offset;
+
+	if (die_temp_offset > QPNP_IADC_DIE_TEMP_CALIB_OFFSET) {
+		iadc->die_temp_calib_offset =
+			result_pmic_therm.physical;
 		rc = qpnp_iadc_calibrate_for_trim();
 		if (rc)
 			pr_err("periodic IADC calibration failed\n");
@@ -822,9 +832,11 @@
 
 	rc = of_property_read_u32(node, "qcom,rsense",
 			&iadc->rsense);
-	if (rc) {
-		pr_err("Invalid rsens reference property\n");
-		goto fail;
+	if (rc)
+		pr_debug("Defaulting to internal rsense\n");
+	else {
+		pr_debug("Use external rsense\n");
+		iadc->external_rsense = true;
 	}
 
 	rc = devm_request_irq(&spmi->dev, iadc->adc->adc_irq_eoc,
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 0ea230a..29b269a 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -128,6 +128,7 @@
 #define MXT_SPT_DIGITIZER_T43		43
 #define MXT_SPT_MESSAGECOUNT_T44	44
 #define MXT_SPT_CTECONFIG_T46		46
+#define MXT_SPT_EXTRANOISESUPCTRLS_T58	58
 #define MXT_SPT_TIMER_T61		61
 
 /* MXT_GEN_COMMAND_T6 field */
@@ -396,6 +397,7 @@
 	atomic_t st_enabled;
 	atomic_t st_pending_irqs;
 	struct completion st_completion;
+	struct completion st_powerdown;
 #endif
 };
 
@@ -432,6 +434,7 @@
 	case MXT_SPT_USERDATA_T38:
 	case MXT_SPT_DIGITIZER_T43:
 	case MXT_SPT_CTECONFIG_T46:
+	case MXT_SPT_EXTRANOISESUPCTRLS_T58:
 	case MXT_SPT_TIMER_T61:
 	case MXT_PROCI_ADAPTIVETHRESHOLD_T55:
 		return true;
@@ -469,6 +472,7 @@
 	case MXT_SPT_USERDATA_T38:
 	case MXT_SPT_DIGITIZER_T43:
 	case MXT_SPT_CTECONFIG_T46:
+	case MXT_SPT_EXTRANOISESUPCTRLS_T58:
 	case MXT_SPT_TIMER_T61:
 	case MXT_PROCI_ADAPTIVETHRESHOLD_T55:
 		return true;
@@ -998,8 +1002,8 @@
 static irqreturn_t mxt_filter_interrupt(struct mxt_data *data)
 {
 	if (atomic_read(&data->st_enabled)) {
-		atomic_cmpxchg(&data->st_pending_irqs, 0, 1);
-		complete(&data->st_completion);
+		if (atomic_cmpxchg(&data->st_pending_irqs, 0, 1) == 0)
+			complete(&data->st_completion);
 		return IRQ_HANDLED;
 	}
 	return IRQ_NONE;
@@ -1993,6 +1997,7 @@
 		atomic_set(&data->st_enabled, 0);
 		complete(&data->st_completion);
 		mxt_interrupt(data->client->irq, data);
+		complete(&data->st_powerdown);
 		break;
 	case 1:
 		if (atomic_read(&data->st_enabled)) {
@@ -2005,6 +2010,8 @@
 			err = -EIO;
 			break;
 		}
+		INIT_COMPLETION(data->st_completion);
+		INIT_COMPLETION(data->st_powerdown);
 		atomic_set(&data->st_pending_irqs, 0);
 		atomic_set(&data->st_enabled, 1);
 		break;
@@ -2032,7 +2039,7 @@
 		return err;
 
 	if (atomic_cmpxchg(&data->st_pending_irqs, 1, 0) != 1)
-		return -EBADF;
+		return -EINVAL;
 
 	return scnprintf(buf, PAGE_SIZE, "%u", 1);
 }
@@ -2061,9 +2068,25 @@
 	.attrs = mxt_attrs,
 };
 
+
+#if defined(CONFIG_SECURE_TOUCH)
+static void mxt_secure_touch_stop(struct mxt_data *data)
+{
+	if (atomic_read(&data->st_enabled)) {
+		complete(&data->st_completion);
+		wait_for_completion_interruptible(&data->st_powerdown);
+	}
+}
+#else
+static void mxt_secure_touch_stop(struct mxt_data *data)
+{
+}
+#endif
+
 static int mxt_start(struct mxt_data *data)
 {
 	int error;
+	mxt_secure_touch_stop(data);
 
 	/* restore the old power state values and reenable touch */
 	error = __mxt_write_reg(data->client, data->t7_start_addr,
@@ -2081,6 +2104,7 @@
 {
 	int error;
 	u8 t7_data[T7_DATA_SIZE] = {0};
+	mxt_secure_touch_stop(data);
 
 	error = __mxt_write_reg(data->client, data->t7_start_addr,
 				T7_DATA_SIZE, t7_data);
@@ -2462,6 +2486,7 @@
 
 	/* calibrate */
 	if (data->pdata->need_calibration) {
+		mxt_secure_touch_stop(data);
 		error = mxt_write_object(data, MXT_GEN_COMMAND_T6,
 					MXT_COMMAND_CALIBRATE, 1);
 		if (error < 0)
@@ -2797,12 +2822,13 @@
 #endif
 
 #if defined(CONFIG_SECURE_TOUCH)
-static void __devinit secure_touch_init(struct mxt_data *data)
+static void __devinit mxt_secure_touch_init(struct mxt_data *data)
 {
 	init_completion(&data->st_completion);
+	init_completion(&data->st_powerdown);
 }
 #else
-static void __devinit secure_touch_init(struct mxt_data *data)
+static void __devinit mxt_secure_touch_init(struct mxt_data *data)
 {
 }
 #endif
@@ -2999,7 +3025,7 @@
 
 	mxt_debugfs_init(data);
 
-	secure_touch_init(data);
+	mxt_secure_touch_init(data);
 
 	return 0;
 
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.c b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
index 417ef83..4e2b1a4 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.c
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
@@ -34,6 +34,9 @@
 
 #define DRIVER_NAME "synaptics_rmi4_i2c"
 #define INPUT_PHYS_NAME "synaptics_rmi4_i2c/input0"
+
+#define RESET_DELAY 100
+
 #define TYPE_B_PROTOCOL
 
 #define NO_0D_WHILE_2D
@@ -68,6 +71,16 @@
 #define NO_SLEEP_OFF (0 << 2)
 #define NO_SLEEP_ON (1 << 2)
 
+enum device_status {
+	STATUS_NO_ERROR = 0x00,
+	STATUS_RESET_OCCURED = 0x01,
+	STATUS_INVALID_CONFIG = 0x02,
+	STATUS_DEVICE_FAILURE = 0x03,
+	STATUS_CONFIG_CRC_FAILURE = 0x04,
+	STATUS_FIRMWARE_CRC_FAILURE = 0x05,
+	STATUS_CRC_IN_PROGRESS = 0x06
+};
+
 #define RMI4_VTG_MIN_UV		2700000
 #define RMI4_VTG_MAX_UV		3300000
 #define RMI4_ACTIVE_LOAD_UA	15000
@@ -79,7 +92,6 @@
 #define RMI4_I2C_LPM_LOAD_UA	10
 
 #define RMI4_GPIO_SLEEP_LOW_US 10000
-#define RMI4_GPIO_WAIT_HIGH_MS 25
 
 static int synaptics_rmi4_i2c_read(struct synaptics_rmi4_data *rmi4_data,
 		unsigned short addr, unsigned char *data,
@@ -1482,6 +1494,16 @@
 				if (retval < 0)
 					return retval;
 
+				while (status.status_code == STATUS_CRC_IN_PROGRESS) {
+					msleep(1);
+					retval = synaptics_rmi4_i2c_read(rmi4_data,
+						rmi4_data->f01_data_base_addr,
+						status.data,
+						sizeof(status.data));
+					if (retval < 0)
+						return retval;
+				}
+
 				if (status.flash_prog == 1) {
 					pr_notice("%s: In flash prog mode, status = 0x%02x\n",
 							__func__,
@@ -1645,7 +1667,7 @@
 		return retval;
 	}
 
-	msleep(100);
+	msleep(RESET_DELAY);
 	return retval;
 };
 
@@ -2110,7 +2132,7 @@
 		gpio_set_value(platform_data->reset_gpio, 0);
 		usleep(RMI4_GPIO_SLEEP_LOW_US);
 		gpio_set_value(platform_data->reset_gpio, 1);
-		msleep(RMI4_GPIO_WAIT_HIGH_MS);
+		msleep(RESET_DELAY);
 	} else
 		synaptics_rmi4_reset_command(rmi4_data);
 
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/platform/msm/camera_v2/isp/msm_buf_mgr.c b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
index 22e8400..263241b 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,
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..066d02a 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 {
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..2b047ad 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
@@ -121,7 +121,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 +=
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..90cc61c 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:
@@ -536,11 +326,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,
@@ -615,8 +400,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 +492,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 +501,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 +525,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 +576,6 @@
 	}
 
 end:
-	msm_ispif_clk_enable(ispif, params, 0);
-
 	return rc;
 }
 
@@ -886,15 +646,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 +661,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,21 +715,6 @@
 	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;
-		}
-	}
 
 	ispif->base = ioremap(ispif->mem->start,
 		resource_size(ispif->mem));
@@ -1022,20 +749,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 +762,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,9 +771,6 @@
 
 	iounmap(ispif->base);
 
-	for (i = 0; i < ispif->vfe_info.num_vfe; i++)
-		msm_ispif_clk_enable_one(ispif, i, 0);
-
 	ispif->ispif_state = ISPIF_POWER_DOWN;
 }
 
@@ -1177,7 +889,6 @@
 {
 	int rc;
 	struct ispif_device *ispif;
-	int i;
 
 	ispif = kzalloc(sizeof(struct ispif_device), GFP_KERNEL);
 	if (!ispif) {
@@ -1235,9 +946,6 @@
 	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..fae7a38 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.h
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.h
@@ -47,16 +47,12 @@
 	void __iomem *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/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/dvb/demux/mpq_dmx_plugin_common.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
index 431d35d..14d1197 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
@@ -1085,7 +1085,7 @@
 	feed_data->buffer_desc.desc[0].read_ptr = 0;
 	feed_data->buffer_desc.desc[0].write_ptr = 0;
 	feed_data->buffer_desc.desc[0].handle =
-		ion_share_dma_buf(client, temp_handle);
+		ion_share_dma_buf_fd(client, temp_handle);
 	if (IS_ERR_VALUE(feed_data->buffer_desc.desc[0].handle)) {
 		MPQ_DVB_ERR_PRINT(
 			"%s: FAILED to share payload buffer %d\n",
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index ef3e698..ddf271e 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -1057,6 +1057,40 @@
 		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_CONFIG_VENC_INTRA_PERIOD:
 	{
 		struct hfi_intra_period *hfi;
@@ -1203,6 +1237,16 @@
 	}
 	case HAL_CONFIG_VPE_DEINTERLACE:
 		break;
+	case HAL_PARAM_VENC_H264_GENERATE_AUDNAL:
+	{
+		struct hfi_enable *hfi;
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_H264_GENERATE_AUDNAL;
+		hfi = (struct hfi_enable *) &pkt->rg_property_data[1];
+		hfi->enable = ((struct hal_enable *) pdata)->enable;
+		pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+		break;
+	}
 	/* FOLLOWING PROPERTIES ARE NOT IMPLEMENTED IN CORE YET */
 	case HAL_CONFIG_BUFFER_REQUIREMENTS:
 	case HAL_CONFIG_PRIORITY:
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index da97c7a..464cb05 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -419,6 +419,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,
@@ -641,6 +665,15 @@
 			V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_DISABLED,
 		.cluster = MSM_VENC_CTRL_CLUSTER_TIMING,
 	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_H264_AU_DELIMITER,
+		.name = "H264 AU Delimiter",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_H264_AU_DELIMITER_DISABLED,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_H264_AU_DELIMITER_ENABLED,
+		.default_value =
+			V4L2_MPEG_VIDC_VIDEO_H264_AU_DELIMITER_DISABLED,
+	},
 };
 
 #define NUM_CTRLS ARRAY_SIZE(msm_venc_ctrls)
@@ -1129,6 +1162,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;
@@ -1458,6 +1492,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;
 
@@ -1680,6 +1752,23 @@
 		pdata = &vui_timing_info;
 		break;
 	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_H264_AU_DELIMITER:
+		property_id = HAL_PARAM_VENC_H264_GENERATE_AUDNAL;
+
+		switch (ctrl->val) {
+		case V4L2_MPEG_VIDC_VIDEO_H264_AU_DELIMITER_DISABLED:
+			enable.enable = 0;
+			break;
+		case V4L2_MPEG_VIDC_VIDEO_H264_AU_DELIMITER_ENABLED:
+			enable.enable = 1;
+			break;
+		default:
+			rc = -ENOTSUPP;
+			break;
+		}
+
+		pdata = &enable;
+		break;
 	default:
 		rc = -ENOTSUPP;
 		break;
@@ -1713,10 +1802,13 @@
 
 	for (c = 0; c < ctrl->ncontrols; ++c) {
 		if (ctrl->cluster[c]->is_new) {
-			rc = try_set_ctrl(inst, ctrl->cluster[c]);
+			struct v4l2_ctrl *temp = ctrl->cluster[c];
+
+			rc = try_set_ctrl(inst, temp);
 			if (rc) {
-				dprintk(VIDC_ERR, "Failed setting %x",
-						ctrl->cluster[c]->id);
+				dprintk(VIDC_ERR, "Failed setting %s (%x)",
+						v4l2_ctrl_get_name(temp->id),
+						temp->id);
 				break;
 			}
 		}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index dc08c64..d925de3 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -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);
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 8031c74..ddb3063 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -547,7 +547,7 @@
 	q_info = &device->iface_queues[VIDC_IFACEQ_CMDQ_IDX];
 	if (!q_info) {
 		dprintk(VIDC_ERR, "cannot write to shared Q's");
-		goto err_q_write;
+		goto err_q_null;
 	}
 	mutex_lock(&device->clock_lock);
 	result = venus_hfi_clk_gating_off(device);
@@ -572,8 +572,9 @@
 		dprintk(VIDC_ERR, "venus_hfi_iface_cmdq_write:queue_full");
 	}
 err_q_write:
-	mutex_unlock(&device->write_lock);
 	mutex_unlock(&device->clock_lock);
+err_q_null:
+	mutex_unlock(&device->write_lock);
 	return result;
 }
 
@@ -592,7 +593,7 @@
 		q_array.align_virtual_addr == 0) {
 		dprintk(VIDC_ERR, "cannot read from shared MSG Q's");
 		rc = -ENODATA;
-		goto read_error;
+		goto read_error_null;
 	}
 	q_info = &device->iface_queues[VIDC_IFACEQ_MSGQ_IDX];
 	mutex_lock(&device->clock_lock);
@@ -614,8 +615,9 @@
 		rc = -ENODATA;
 	}
 read_error:
-	mutex_unlock(&device->read_lock);
 	mutex_unlock(&device->clock_lock);
+read_error_null:
+	mutex_unlock(&device->read_lock);
 	return rc;
 }
 
@@ -634,7 +636,7 @@
 		q_array.align_virtual_addr == 0) {
 		dprintk(VIDC_ERR, "cannot read from shared DBG Q's");
 		rc = -ENODATA;
-		goto dbg_error;
+		goto dbg_error_null;
 	}
 	mutex_lock(&device->clock_lock);
 	rc = venus_hfi_clk_gating_off(device);
@@ -656,8 +658,9 @@
 		rc = -ENODATA;
 	}
 dbg_error:
-	mutex_unlock(&device->read_lock);
 	mutex_unlock(&device->clock_lock);
+dbg_error_null:
+	mutex_unlock(&device->read_lock);
 	return rc;
 }
 
@@ -1070,8 +1073,8 @@
 			disable_irq_nosync(dev->hal_data->irq);
 		dev->intr_status = 0;
 		venus_hfi_interface_queues_release(dev);
+		mutex_unlock(&dev->clock_lock);
 	}
-	mutex_unlock(&dev->clock_lock);
 	dprintk(VIDC_INFO, "HAL exited\n");
 	return 0;
 }
@@ -1867,8 +1870,8 @@
 	if (((ctrl_status & VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_IDLE_MSG_BMSK)
 		!= 0) && !rc)
 		venus_hfi_clk_gating_on(device);
-	mutex_unlock(&device->write_lock);
 	mutex_unlock(&device->clock_lock);
+	mutex_unlock(&device->write_lock);
 	return rc;
 }
 
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index 3729c3a..5ba191f 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,
@@ -168,6 +169,7 @@
 	HAL_PARAM_VENC_H264_ENTROPY_CABAC_MODEL,
 	HAL_CONFIG_VENC_MAX_BITRATE,
 	HAL_PARAM_VENC_H264_VUI_TIMING_INFO,
+	HAL_PARAM_VENC_H264_GENERATE_AUDNAL,
 };
 
 enum hal_domain {
@@ -595,6 +597,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/misc/qseecom.c b/drivers/misc/qseecom.c
index 05a15b1..55e3e4e 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -565,13 +565,14 @@
 		if (wait_event_freezable(qseecom.send_resp_wq,
 				__qseecom_listener_has_sent_rsp(data))) {
 			pr_warning("Interrupted: exiting send_cmd loop\n");
-			return -ERESTARTSYS;
+			ret = -ERESTARTSYS;
 		}
 
-		if (data->abort) {
-			pr_err("Aborting listener service %d\n",
-				data->listener.id);
-			rc = -ENODEV;
+		if ((data->abort) || (ret == -ERESTARTSYS)) {
+			pr_err("Abort clnt %d waiting on lstnr svc %d, ret %d",
+				data->client.app_id, lstnr, ret);
+			if (data->abort)
+				rc = -ENODEV;
 			send_data_rsp.status  = QSEOS_RESULT_FAILURE;
 		} else {
 			send_data_rsp.status  = QSEOS_RESULT_SUCCESS;
@@ -672,7 +673,7 @@
 		app_id = ret;
 
 	if (app_id) {
-		pr_warn("App id %d (%s) already exists\n", app_id,
+		pr_debug("App id %d (%s) already exists\n", app_id,
 			(char *)(req.app_name));
 		spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
 		list_for_each_entry(entry,
@@ -830,7 +831,7 @@
 					break;
 				} else {
 					ptr_app->ref_cnt--;
-					pr_warn("Can't unload app(%d) inuse\n",
+					pr_debug("Can't unload app(%d) inuse\n",
 							ptr_app->app_id);
 					break;
 				}
@@ -2315,7 +2316,7 @@
 		pr_err(" scm call to check if app is loaded failed");
 		return ret;	/* scm call failed */
 	} else if (ret > 0) {
-		pr_warn("App id %d (%s) already exists\n", ret,
+		pr_debug("App id %d (%s) already exists\n", ret,
 			(char *)(req.app_name));
 		spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
 		list_for_each_entry(entry,
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index d1909aa..49222b9 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -2262,6 +2262,7 @@
 	msm_host->mmc->caps2 |= MMC_CAP2_CACHE_CTRL;
 	msm_host->mmc->caps2 |= MMC_CAP2_POWEROFF_NOTIFY;
 	msm_host->mmc->caps2 |= MMC_CAP2_CLK_SCALE;
+	msm_host->mmc->caps2 |= MMC_CAP2_STOP_REQUEST;
 
 	if (msm_host->pdata->nonremovable)
 		msm_host->mmc->caps |= MMC_CAP_NONREMOVABLE;
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 70a9e96..0549b4a 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2124,6 +2124,11 @@
 	sdhci_runtime_pm_put(host);
 }
 
+static int sdhci_stop_request(struct mmc_host *mmc)
+{
+	return -ENOSYS;
+}
+
 static const struct mmc_host_ops sdhci_ops = {
 	.pre_req	= sdhci_pre_req,
 	.post_req	= sdhci_post_req,
@@ -2137,6 +2142,7 @@
 	.enable_preset_value		= sdhci_enable_preset_value,
 	.enable		= sdhci_enable,
 	.disable	= sdhci_disable,
+	.stop_request = sdhci_stop_request,
 };
 
 /*****************************************************************************\
diff --git a/drivers/platform/msm/ipa/ipa.c b/drivers/platform/msm/ipa/ipa.c
index 5cc5d46..16f722c 100644
--- a/drivers/platform/msm/ipa/ipa.c
+++ b/drivers/platform/msm/ipa/ipa.c
@@ -1460,6 +1460,41 @@
 		WARN_ON(1);
 }
 
+/**
+* ipa_inc_client_enable_clks() - Increase active clients counter, and
+* enable ipa clocks if necessary
+*
+* Return codes:
+* None
+*/
+void ipa_inc_client_enable_clks(void)
+{
+	mutex_lock(&ipa_ctx->ipa_active_clients_lock);
+	ipa_ctx->ipa_active_clients++;
+	if (ipa_ctx->ipa_active_clients == 1)
+		if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_NORMAL)
+			ipa_enable_clks();
+	mutex_unlock(&ipa_ctx->ipa_active_clients_lock);
+}
+
+/**
+* ipa_dec_client_disable_clks() - Decrease active clients counter, and
+* disable ipa clocks if necessary
+*
+* Return codes:
+* None
+*/
+void ipa_dec_client_disable_clks(void)
+{
+	mutex_lock(&ipa_ctx->ipa_active_clients_lock);
+	ipa_ctx->ipa_active_clients--;
+	if (ipa_ctx->ipa_active_clients == 0)
+		if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_NORMAL)
+			ipa_disable_clks();
+	mutex_unlock(&ipa_ctx->ipa_active_clients_lock);
+}
+
+
 static int ipa_setup_bam_cfg(const struct ipa_plat_drv_res *res)
 {
 	void *bam_cnfg_bits;
@@ -1845,7 +1880,8 @@
 	ipa_ctx->flt_rule_hdl_tree = RB_ROOT;
 	ipa_ctx->tag_tree = RB_ROOT;
 
-	atomic_set(&ipa_ctx->ipa_active_clients, 0);
+	mutex_init(&ipa_ctx->ipa_active_clients_lock);
+	ipa_ctx->ipa_active_clients = 0;
 
 	result = ipa_bridge_init();
 	if (result) {
diff --git a/drivers/platform/msm/ipa/ipa_bridge.c b/drivers/platform/msm/ipa/ipa_bridge.c
index dd00081..83b7175 100644
--- a/drivers/platform/msm/ipa/ipa_bridge.c
+++ b/drivers/platform/msm/ipa/ipa_bridge.c
@@ -726,10 +726,7 @@
 		return -EINVAL;
 	}
 
-	if (atomic_inc_return(&ipa_ctx->ipa_active_clients) == 1) {
-		if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_NORMAL)
-			ipa_enable_clks();
-	}
+	ipa_inc_client_enable_clks();
 
 	if (setup_bridge_to_ipa(dir, type, props, clnt_hdl)) {
 		IPAERR("fail to setup SYS pipe to IPA dir=%d type=%d\n",
@@ -751,10 +748,7 @@
 bail_a2:
 	ipa_bridge_teardown(dir, type, *clnt_hdl);
 bail_ipa:
-	if (atomic_dec_return(&ipa_ctx->ipa_active_clients) == 0) {
-		if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_NORMAL)
-			ipa_disable_clks();
-	}
+	ipa_dec_client_disable_clks();
 	return ret;
 }
 EXPORT_SYMBOL(ipa_bridge_setup);
@@ -826,10 +820,7 @@
 
 	memset(&ipa_ctx->ep[clnt_hdl], 0, sizeof(struct ipa_ep_context));
 
-	if (atomic_dec_return(&ipa_ctx->ipa_active_clients) == 0) {
-		if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_NORMAL)
-			ipa_disable_clks();
-	}
+	ipa_dec_client_disable_clks();
 
 	return 0;
 }
diff --git a/drivers/platform/msm/ipa/ipa_client.c b/drivers/platform/msm/ipa/ipa_client.c
index f2f80bf..6033510 100644
--- a/drivers/platform/msm/ipa/ipa_client.c
+++ b/drivers/platform/msm/ipa/ipa_client.c
@@ -204,9 +204,7 @@
 	int result = -EFAULT;
 	struct ipa_ep_context *ep;
 
-	if (atomic_inc_return(&ipa_ctx->ipa_active_clients) == 1)
-		if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_NORMAL)
-			ipa_enable_clks();
+	ipa_inc_client_enable_clks();
 
 	if (in == NULL || sps == NULL || clnt_hdl == NULL ||
 	    in->client >= IPA_CLIENT_MAX ||
@@ -342,11 +340,7 @@
 ipa_cfg_ep_fail:
 	memset(&ipa_ctx->ep[ipa_ep_idx], 0, sizeof(struct ipa_ep_context));
 fail:
-	if (atomic_dec_return(&ipa_ctx->ipa_active_clients) == 0) {
-		if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_NORMAL)
-			ipa_disable_clks();
-	}
-
+	ipa_dec_client_disable_clks();
 	return result;
 }
 EXPORT_SYMBOL(ipa_connect);
@@ -421,10 +415,7 @@
 	ipa_enable_data_path(clnt_hdl);
 	memset(&ipa_ctx->ep[clnt_hdl], 0, sizeof(struct ipa_ep_context));
 
-	if (atomic_dec_return(&ipa_ctx->ipa_active_clients) == 0) {
-		if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_NORMAL)
-			ipa_disable_clks();
-	}
+	ipa_dec_client_disable_clks();
 
 	IPADBG("client (ep: %d) disconnected\n", clnt_hdl);
 
diff --git a/drivers/platform/msm/ipa/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_debugfs.c
index 51a950d..bc5aa6f 100644
--- a/drivers/platform/msm/ipa/ipa_debugfs.c
+++ b/drivers/platform/msm/ipa/ipa_debugfs.c
@@ -563,7 +563,7 @@
 			ipa_ctx->stats.rx_repl_repost,
 			ipa_ctx->stats.x_intr_repost,
 			ipa_ctx->stats.rx_q_len,
-			atomic_read(&ipa_ctx->ipa_active_clients),
+			ipa_ctx->ipa_active_clients,
 			connect);
 	cnt += nbytes;
 
diff --git a/drivers/platform/msm/ipa/ipa_dp.c b/drivers/platform/msm/ipa/ipa_dp.c
index 2555c6b..228c77fe 100644
--- a/drivers/platform/msm/ipa/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_dp.c
@@ -433,9 +433,7 @@
 	struct ipa_desc *desc;
 	int result = 0;
 
-	if (atomic_inc_return(&ipa_ctx->ipa_active_clients) == 1)
-		if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_NORMAL)
-			ipa_enable_clks();
+	ipa_inc_client_enable_clks();
 
 	if (num_desc == 1) {
 		init_completion(&descr->xfer_done);
@@ -471,9 +469,7 @@
 
 	IPA_STATS_INC_IC_CNT(num_desc, descr, ipa_ctx->stats.imm_cmds);
 bail:
-	if (atomic_dec_return(&ipa_ctx->ipa_active_clients) == 0)
-		if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_NORMAL)
-			ipa_disable_clks();
+	ipa_dec_client_disable_clks();
 	return result;
 }
 
@@ -1087,6 +1083,7 @@
 	int inactive_cycles = 0;
 	int cnt;
 
+	ipa_inc_client_enable_clks();
 	do {
 		cnt = ipa_handle_rx_core(true, true);
 		if (cnt == 0) {
@@ -1098,6 +1095,7 @@
 	} while (inactive_cycles <= POLLING_INACTIVITY);
 
 	ipa_rx_switch_to_intr_mode();
+	ipa_dec_client_disable_clks();
 }
 
 /**
diff --git a/drivers/platform/msm/ipa/ipa_i.h b/drivers/platform/msm/ipa/ipa_i.h
index cb67514..a03ba16 100644
--- a/drivers/platform/msm/ipa/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_i.h
@@ -644,7 +644,8 @@
 	struct ipa_mem_buffer empty_rt_tbl_mem;
 	struct gen_pool *pipe_mem_pool;
 	struct dma_pool *dma_pool;
-	atomic_t ipa_active_clients;
+	struct mutex ipa_active_clients_lock;
+	int ipa_active_clients;
 	u32 clnt_hdl_cmd;
 	u32 clnt_hdl_data_in;
 	u32 clnt_hdl_data_out;
@@ -795,6 +796,8 @@
 struct ipa_context *ipa_get_ctx(void);
 void ipa_enable_clks(void);
 void ipa_disable_clks(void);
+void ipa_inc_client_enable_clks(void);
+void ipa_dec_client_disable_clks(void);
 int __ipa_del_rt_rule(u32 rule_hdl);
 int __ipa_del_hdr(u32 hdr_hdl);
 int __ipa_release_hdr(u32 hdr_hdl);
diff --git a/drivers/platform/msm/ipa/ipa_rm_resource.c b/drivers/platform/msm/ipa/ipa_rm_resource.c
index 0a6771c..3615952 100644
--- a/drivers/platform/msm/ipa/ipa_rm_resource.c
+++ b/drivers/platform/msm/ipa/ipa_rm_resource.c
@@ -80,7 +80,8 @@
 	int result = 0;
 	int driver_result;
 	unsigned long flags;
-	IPADBG("IPA RM ::ipa_rm_resource_consumer_request ENTER\n");
+	IPADBG("IPA RM ::ipa_rm_resource_consumer_request %d ENTER\n",
+		consumer->resource.name);
 	spin_lock_irqsave(&consumer->resource.state_lock, flags);
 	switch (consumer->resource.state) {
 	case IPA_RM_RELEASED:
@@ -114,7 +115,8 @@
 	consumer->usage_count++;
 bail:
 	spin_unlock_irqrestore(&consumer->resource.state_lock, flags);
-	IPADBG("IPA RM ::ipa_rm_resource_consumer_request EXIT [%d]\n", result);
+	IPADBG("IPA RM ::ipa_rm_resource_consumer_request %d EXIT %d\n",
+		consumer->resource.name, result);
 	return result;
 }
 
@@ -125,7 +127,8 @@
 	int driver_result;
 	unsigned long flags;
 	enum ipa_rm_resource_state save_state;
-	IPADBG("IPA RM ::ipa_rm_resource_consumer_release ENTER\n");
+	IPADBG("IPA RM ::ipa_rm_resource_consumer_release %d ENTER\n",
+		consumer->resource.name);
 	spin_lock_irqsave(&consumer->resource.state_lock, flags);
 	switch (consumer->resource.state) {
 	case IPA_RM_RELEASED:
@@ -160,7 +163,8 @@
 	}
 bail:
 	spin_unlock_irqrestore(&consumer->resource.state_lock, flags);
-	IPADBG("IPA RM ::ipa_rm_resource_consumer_release EXIT [%d]\n", result);
+	IPADBG("IPA RM ::ipa_rm_resource_consumer_release %d EXIT %d\n",
+		consumer->resource.name, result);
 	return result;
 }
 
@@ -564,7 +568,7 @@
 	unsigned long flags;
 	struct ipa_rm_resource *consumer;
 	int consumer_result;
-	IPADBG("IPA RM ::ipa_rm_resource_producer_request [%d] ENTER\n",
+	IPADBG("IPA RM ::ipa_rm_resource_producer_request %d ENTER\n",
 			producer->resource.name);
 	if (ipa_rm_peers_list_is_empty(producer->resource.peers_list)) {
 		spin_lock_irqsave(&producer->resource.state_lock, flags);
@@ -628,7 +632,8 @@
 unlock_and_bail:
 	spin_unlock_irqrestore(&producer->resource.state_lock, flags);
 bail:
-	IPADBG("IPA RM ::ipa_rm_resource_producer_request EXIT[%d]\n", result);
+	IPADBG("IPA RM ::ipa_rm_resource_producer_request %d EXIT %d\n",
+		producer->resource.name, result);
 	return result;
 }
 
@@ -646,7 +651,8 @@
 	unsigned long flags;
 	struct ipa_rm_resource *consumer;
 	int consumer_result;
-	IPADBG("IPA RM ::ipa_rm_resource_producer_release ENTER\n");
+	IPADBG("IPA RM ::ipa_rm_resource_producer_release %d ENTER\n",
+		producer->resource.name);
 	if (ipa_rm_peers_list_is_empty(producer->resource.peers_list)) {
 		spin_lock_irqsave(&producer->resource.state_lock, flags);
 		producer->resource.state = IPA_RM_RELEASED;
@@ -702,7 +708,8 @@
 	return result;
 bail:
 	spin_unlock_irqrestore(&producer->resource.state_lock, flags);
-	IPADBG("IPA RM ::ipa_rm_resource_producer_release EXIT[%d]\n", result);
+	IPADBG("IPA RM ::ipa_rm_resource_producer_release %d EXIT %d\n",
+		producer->resource.name, result);
 	return result;
 }
 
diff --git a/drivers/platform/msm/ipa/teth_bridge.c b/drivers/platform/msm/ipa/teth_bridge.c
index 5b26e41..774c0e6 100644
--- a/drivers/platform/msm/ipa/teth_bridge.c
+++ b/drivers/platform/msm/ipa/teth_bridge.c
@@ -58,6 +58,8 @@
 #define TETH_AGGR_MAX_DATAGRAMS_DEFAULT 16
 #define TETH_AGGR_MAX_AGGR_PACKET_SIZE_DEFAULT (8*1024)
 
+#define TETH_MTU_BYTE 1500
+
 struct mac_addresses_type {
 	u8 host_pc_mac_addr[ETH_ALEN];
 	bool host_pc_mac_addr_known;
@@ -283,14 +285,7 @@
 		TETH_ERR("Configuration of header removal/insertion failed\n");
 		goto bail;
 	}
-
-	res = ipa_commit_hdr();
-	if (res) {
-		TETH_ERR("Failed committing headers\n");
-		goto bail;
-	}
 	TETH_DBG_FUNC_EXIT();
-
 bail:
 	return res;
 }
@@ -425,20 +420,7 @@
 		TETH_ERR("A2 to USB routing block configuration failed\n");
 		goto bail;
 	}
-
-	/* Commit all the changes to HW in one shot */
-	res = ipa_commit_rt(IPA_IP_v4);
-	if (res) {
-		TETH_ERR("Failed commiting IPv4 routing tables\n");
-		goto bail;
-	}
-	res = ipa_commit_rt(IPA_IP_v6);
-	if (res) {
-		TETH_ERR("Failed commiting IPv6 routing tables\n");
-		goto bail;
-	}
 	TETH_DBG_FUNC_EXIT();
-
 bail:
 	return res;
 }
@@ -533,20 +515,7 @@
 		TETH_ERR("A2_PROD filtering configuration failed\n");
 		goto bail;
 	}
-
-	/* Commit all the changes to HW in one shot */
-	res = ipa_commit_flt(IPA_IP_v4);
-	if (res) {
-		TETH_ERR("Failed commiting IPv4 filtering tables\n");
-		goto bail;
-	}
-	res = ipa_commit_flt(IPA_IP_v6);
-	if (res) {
-		TETH_ERR("Failed commiting IPv6 filtering tables\n");
-		goto bail;
-	}
 	TETH_DBG_FUNC_EXIT();
-
 bail:
 	return res;
 }
@@ -578,8 +547,15 @@
 		return -EFAULT;
 	}
 
+	/*
+	 * Due to a HW 'feature', the maximal aggregated packet size may be the
+	 * requested aggr_byte_limit plus the MTU. Therefore, the MTU is
+	 * subtracted from the requested aggr_byte_limit so that the requested
+	 * byte limit is honored .
+	 */
 	ipa_aggr_params->aggr_byte_limit =
-		teth_aggr_params->max_transfer_size_byte / 1024;
+		(teth_aggr_params->max_transfer_size_byte - TETH_MTU_BYTE) /
+		1024;
 	ipa_aggr_params->aggr_time_limit = TETH_DEFAULT_AGGR_TIME_LIMIT;
 	TETH_DBG_FUNC_EXIT();
 
@@ -699,9 +675,6 @@
 static void complete_hw_bridge(struct work_struct *work)
 {
 	int res;
-	static DEFINE_MUTEX(f_lock);
-
-	mutex_lock(&f_lock);
 
 	TETH_DBG_FUNC_ENTRY();
 	TETH_DBG("Completing HW bridge in %s mode\n",
@@ -715,17 +688,6 @@
 		goto bail;
 	}
 
-	/*
-	 * Reset the Header, Routing and Filtering blocks.
-	 * Resetting the Header block will also reset the other blocks.
-	 * This reset is not comitted to HW.
-	 */
-	res = ipa_reset_hdr();
-	if (res) {
-		TETH_ERR("Failed resetting IPA\n");
-		goto bail;
-	}
-
 	res = configure_ipa_header_block();
 	if (res) {
 		TETH_ERR("Configuration of IPA header block Failed\n");
@@ -744,10 +706,19 @@
 		goto bail;
 	}
 
+	/*
+	 * Commit all the data to HW, including header, routing and filtering
+	 * blocks, IPv4 and IPv6
+	 */
+	res = ipa_commit_hdr();
+	if (res) {
+		TETH_ERR("Failed committing headers / routing / filtering.\n");
+		goto bail;
+	}
+
 	teth_ctx->is_hw_bridge_complete = true;
-	teth_ctx->comp_hw_bridge_in_progress = false;
 bail:
-	mutex_unlock(&f_lock);
+	teth_ctx->comp_hw_bridge_in_progress = false;
 	TETH_DBG_FUNC_EXIT();
 
 	return;
@@ -1102,6 +1073,19 @@
 		return -EINVAL;
 	}
 
+	/*
+	 * In case the requested max transfer size is larger than 8K, set it to
+	 * to the default 8K
+	 */
+	if (aggr_params->dl.max_transfer_size_byte >
+	    TETH_AGGR_MAX_AGGR_PACKET_SIZE_DEFAULT)
+		aggr_params->dl.max_transfer_size_byte =
+			TETH_AGGR_MAX_AGGR_PACKET_SIZE_DEFAULT;
+	if (aggr_params->ul.max_transfer_size_byte >
+	    TETH_AGGR_MAX_AGGR_PACKET_SIZE_DEFAULT)
+		aggr_params->ul.max_transfer_size_byte =
+			TETH_AGGR_MAX_AGGR_PACKET_SIZE_DEFAULT;
+
 	memcpy(&teth_ctx->aggr_params,
 	       aggr_params,
 	       sizeof(struct teth_aggr_params));
@@ -1110,10 +1094,8 @@
 
 	teth_ctx->aggr_params_known = true;
 	res = teth_set_aggregation();
-	if (res) {
+	if (res)
 		TETH_ERR("Failed setting aggregation params\n");
-		res = -EFAULT;
-	}
 
 	return res;
 }
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index 459ab1d..e00e1c3 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -213,6 +213,8 @@
  * @alarm_high_mv:		the battery alarm voltage high
  * @cool_temp_dc:		the cool temp threshold in deciCelcius
  * @warm_temp_dc:		the warm temp threshold in deciCelcius
+ * @hysteresis_temp_dc:		the hysteresis between temp thresholds in
+ *				deciCelcius
  * @resume_voltage_delta:	the voltage delta from vdd max at which the
  *				battery should resume charging
  * @term_current:		The charging based term current
@@ -235,6 +237,7 @@
 	unsigned int			alarm_high_mv;
 	int				cool_temp_dc;
 	int				warm_temp_dc;
+	int				hysteresis_temp_dc;
 	unsigned int			temp_check_period;
 	unsigned int			cool_bat_chg_current;
 	unsigned int			warm_bat_chg_current;
@@ -308,6 +311,7 @@
 static int thermal_mitigation;
 
 static struct pm8921_chg_chip *the_chip;
+static void check_temp_thresholds(struct pm8921_chg_chip *chip);
 
 #define LPM_ENABLE_BIT	BIT(2)
 static int pm8921_chg_set_lpm(struct pm8921_chg_chip *chip, int enable)
@@ -3162,6 +3166,22 @@
 	struct delayed_work *dwork = to_delayed_work(work);
 	struct pm8921_chg_chip *chip = container_of(dwork,
 				struct pm8921_chg_chip, update_heartbeat_work);
+	bool chg_present = chip->usb_present || chip->dc_present;
+
+	/* for battery health when charger is not connected */
+	if (chip->btc_override && !chg_present)
+		schedule_delayed_work(&chip->btc_override_work,
+			round_jiffies_relative(msecs_to_jiffies
+					(chip->btc_delay_ms)));
+
+	/*
+	 * check temp thresholds when charger is present and
+	 * and battery is FULL. The temperature here can impact
+	 * the charging restart conditions.
+	 */
+	if (chip->btc_override && chg_present &&
+				!wake_lock_active(&chip->eoc_wake_lock))
+		check_temp_thresholds(chip);
 
 	power_supply_changed(&chip->batt_psy);
 	if (chip->recent_reported_soc <= 20)
@@ -3317,7 +3337,7 @@
 
 	if (chip->warm_temp_dc != INT_MIN) {
 		if (chip->is_bat_warm
-			&& temp < chip->warm_temp_dc - TEMP_HYSTERISIS_DECIDEGC)
+			&& temp < chip->warm_temp_dc - chip->hysteresis_temp_dc)
 			battery_warm(false);
 		else if (!chip->is_bat_warm && temp >= chip->warm_temp_dc)
 			battery_warm(true);
@@ -3325,7 +3345,7 @@
 
 	if (chip->cool_temp_dc != INT_MIN) {
 		if (chip->is_bat_cool
-			&& temp > chip->cool_temp_dc + TEMP_HYSTERISIS_DECIDEGC)
+			&& temp > chip->cool_temp_dc + chip->hysteresis_temp_dc)
 			battery_cool(false);
 		else if (!chip->is_bat_cool && temp <= chip->cool_temp_dc)
 			battery_cool(true);
@@ -3543,7 +3563,8 @@
 
 	temp = pm_chg_get_rt_status(chip, BATTTEMP_HOT_IRQ);
 	if (temp) {
-		if (decidegc < chip->btc_override_hot_decidegc)
+		if (decidegc < chip->btc_override_hot_decidegc -
+				chip->hysteresis_temp_dc)
 			/* stop forcing batt hot */
 			rc = pm_chg_override_hot(chip, 0);
 			if (rc)
@@ -3558,7 +3579,8 @@
 
 	temp = pm_chg_get_rt_status(chip, BATTTEMP_COLD_IRQ);
 	if (temp) {
-		if (decidegc > chip->btc_override_cold_decidegc)
+		if (decidegc > chip->btc_override_cold_decidegc +
+				chip->hysteresis_temp_dc)
 			/* stop forcing batt cold */
 			rc = pm_chg_override_cold(chip, 0);
 			if (rc)
@@ -3622,7 +3644,8 @@
 
 	end = is_charging_finished(chip, vbat_batt_terminal_uv, ichg_meas_ma);
 
-	if (end == CHG_NOT_IN_PROGRESS) {
+	if (end == CHG_NOT_IN_PROGRESS && (!chip->btc_override ||
+		!(chip->usb_present || chip->dc_present))) {
 		count = 0;
 		goto eoc_worker_stop;
 	}
@@ -3650,7 +3673,8 @@
 		chgdone_irq_handler(chip->pmic_chg_irq[CHGDONE_IRQ], chip);
 	} else {
 		check_temp_thresholds(chip);
-		adjust_vdd_max_for_fastchg(chip, vbat_batt_terminal_uv);
+		if (end != CHG_NOT_IN_PROGRESS)
+			adjust_vdd_max_for_fastchg(chip, vbat_batt_terminal_uv);
 		pr_debug("EOC count = %d\n", count);
 		schedule_delayed_work(&chip->eoc_work,
 			      round_jiffies_relative(msecs_to_jiffies
@@ -3659,9 +3683,9 @@
 	}
 
 eoc_worker_stop:
-	wake_unlock(&chip->eoc_wake_lock);
 	/* set the vbatdet back, in case it was changed to trigger charging */
 	set_appropriate_vbatdet(chip);
+	wake_unlock(&chip->eoc_wake_lock);
 }
 
 /**
@@ -3795,6 +3819,11 @@
 		schedule_delayed_work(&chip->unplug_check_work,
 			msecs_to_jiffies(UNPLUG_CHECK_WAIT_PERIOD_MS));
 		pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
+
+		if (chip->btc_override)
+			schedule_delayed_work(&chip->btc_override_work,
+					round_jiffies_relative(msecs_to_jiffies
+						(chip->btc_delay_ms)));
 	}
 
 	pm8921_chg_enable_irq(chip, DCIN_VALID_IRQ);
@@ -4600,6 +4629,8 @@
 					is_usb_chg_plugged_in(the_chip)))
 		schedule_delayed_work(&chip->btc_override_work, 0);
 
+	schedule_delayed_work(&chip->update_heartbeat_work, 0);
+
 	return 0;
 }
 
@@ -4607,6 +4638,8 @@
 {
 	struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
 
+	cancel_delayed_work_sync(&chip->update_heartbeat_work);
+
 	if (chip->btc_override)
 		cancel_delayed_work_sync(&chip->btc_override_work);
 
@@ -4663,6 +4696,11 @@
 	else
 		chip->warm_temp_dc = INT_MIN;
 
+	if (pdata->hysteresis_temp)
+		chip->hysteresis_temp_dc = pdata->hysteresis_temp * 10;
+	else
+		chip->hysteresis_temp_dc = TEMP_HYSTERISIS_DECIDEGC;
+
 	chip->temp_check_period = pdata->temp_check_period;
 	chip->max_bat_chg_current = pdata->max_bat_chg_current;
 	/* Assign to corresponding module parameter */
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index da0a5b6..a875c92 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -1383,6 +1383,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 +1392,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 +1403,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;
 
@@ -1679,10 +1683,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:
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/thermal/msm8974-tsens.c b/drivers/thermal/msm8974-tsens.c
index 676f69d..95378c5 100644
--- a/drivers/thermal/msm8974-tsens.c
+++ b/drivers/thermal/msm8974-tsens.c
@@ -284,7 +284,7 @@
 
 	while (i < tmdev->tsens_num_sensor && !id_found) {
 		if (sensor_hw_num == tmdev->sensor[i].sensor_hw_num) {
-			*sensor_sw_idx = i;
+			*sensor_sw_idx = tmdev->sensor[i].sensor_sw_id;
 			id_found = true;
 		}
 		i++;
@@ -304,7 +304,7 @@
 
 	while (i < tmdev->tsens_num_sensor && !id_found) {
 		if (sensor_sw_id == tmdev->sensor[i].sensor_sw_id) {
-			*sensor_hw_num = i;
+			*sensor_hw_num = tmdev->sensor[i].sensor_hw_num;
 			id_found = true;
 		}
 		i++;
@@ -1373,12 +1373,16 @@
 		"qcom,sensor-id", sensor_id, tsens_num_sensors);
 	if (rc) {
 		pr_debug("Default sensor id mapping\n");
-		for (i = 0; i < tsens_num_sensors; i++)
+		for (i = 0; i < tsens_num_sensors; i++) {
 			tmdev->sensor[i].sensor_hw_num = i;
+			tmdev->sensor[i].sensor_sw_id = i;
+		}
 	} else {
 		pr_debug("Use specified sensor id mapping\n");
-		for (i = 0; i < tsens_num_sensors; i++)
+		for (i = 0; i < tsens_num_sensors; i++) {
 			tmdev->sensor[i].sensor_hw_num = sensor_id[i];
+			tmdev->sensor[i].sensor_sw_id = i;
+		}
 	}
 
 	tmdev->tsens_irq = platform_get_irq(pdev, 0);
diff --git a/drivers/thermal/qpnp-adc-tm.c b/drivers/thermal/qpnp-adc-tm.c
index e7d2e0f..d848a18 100644
--- a/drivers/thermal/qpnp-adc-tm.c
+++ b/drivers/thermal/qpnp-adc-tm.c
@@ -36,6 +36,8 @@
 
 /* QPNP VADC TM register definition */
 #define QPNP_REVISION3					0x2
+#define QPNP_PERPH_SUBTYPE				0x5
+#define QPNP_PERPH_TYPE2				0x2
 #define QPNP_REVISION_EIGHT_CHANNEL_SUPPORT		2
 #define QPNP_STATUS1					0x8
 #define QPNP_STATUS1_OP_MODE				4
@@ -366,7 +368,7 @@
 
 static int32_t qpnp_adc_tm_check_revision(uint32_t btm_chan_num)
 {
-	u8 rev;
+	u8 rev, perph_subtype;
 	int rc = 0;
 
 	rc = qpnp_adc_tm_read_reg(QPNP_REVISION3, &rev);
@@ -375,10 +377,18 @@
 		return rc;
 	}
 
-	if ((rev < QPNP_REVISION_EIGHT_CHANNEL_SUPPORT) &&
-		(btm_chan_num > QPNP_ADC_TM_M4_ADC_CH_SEL_CTL)) {
-		pr_debug("Version does not support more than 5 channels\n");
-		return -EINVAL;
+	rc = qpnp_adc_tm_read_reg(QPNP_PERPH_SUBTYPE, &perph_subtype);
+	if (rc) {
+		pr_err("adc-tm perph_subtype read failed\n");
+		return rc;
+	}
+
+	if (perph_subtype == QPNP_PERPH_TYPE2) {
+		if ((rev < QPNP_REVISION_EIGHT_CHANNEL_SUPPORT) &&
+			(btm_chan_num > QPNP_ADC_TM_M4_ADC_CH_SEL_CTL)) {
+			pr_debug("Version does not support more than 5 channels\n");
+			return -EINVAL;
+		}
 	}
 
 	return rc;
@@ -1584,6 +1594,8 @@
 		adc_tm->sensor[sen_idx].sensor_num = sen_idx;
 		pr_debug("btm_chan:%x, vadc_chan:%x\n", btm_channel_num,
 			adc_tm->adc->adc_channels[sen_idx].channel_num);
+		thermal_node = of_property_read_bool(child,
+					"qcom,thermal-node");
 		if (thermal_node) {
 			/* Register with the thermal zone */
 			pr_debug("thermal node%x\n", btm_channel_num);
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 6619e96..fc8f4b3 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -475,6 +475,7 @@
 	void			*mem;
 
 	u8			mode;
+	bool			host_only_mode;
 
 	mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
 	if (!mem) {
@@ -548,6 +549,7 @@
 		dwc->maximum_speed = DWC3_DCFG_SUPERSPEED;
 
 	dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize");
+	host_only_mode = of_property_read_bool(node, "host-only-mode");
 
 	pm_runtime_no_callbacks(dev);
 	pm_runtime_set_active(dev);
@@ -561,6 +563,12 @@
 
 	mode = DWC3_MODE(dwc->hwparams.hwparams0);
 
+	/* Override mode if user selects host-only config with DRD core */
+	if (host_only_mode && (mode == DWC3_MODE_DRD)) {
+		dev_dbg(dev, "host only mode selected\n");
+		mode = DWC3_MODE_HOST;
+	}
+
 	switch (mode) {
 	case DWC3_MODE_DEVICE:
 		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 7a6765b..924e8f4 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -127,6 +127,8 @@
 #define DBM_TRB_DMA		0x20000000
 #define DBM_TRB_EP_NUM(ep)	(ep<<24)
 
+#define USB3_PORTSC		(0x430)
+#define PORT_PE			(0x1 << 1)
 /**
  *  USB QSCRATCH Hardware registers
  *
@@ -177,6 +179,9 @@
 	struct regulator	*hsusb_vddcx;
 	struct regulator	*ssusb_1p8;
 	struct regulator	*ssusb_vddcx;
+
+	/* VBUS regulator if no OTG and running in host only mode */
+	struct regulator	*vbus_otg;
 	struct dwc3_ext_xceiv	ext_xceiv;
 	bool			resume_pending;
 	atomic_t                pm_suspended;
@@ -210,6 +215,9 @@
 	bool			vbus_active;
 	bool			ext_inuse;
 	enum dwc3_id_state	id_state;
+	unsigned long		lpm_flags;
+#define MDWC3_CORECLK_OFF		BIT(0)
+#define MDWC3_TCXO_SHUTDOWN		BIT(1)
 };
 
 #define USB_HSPHY_3P3_VOL_MIN		3050000 /* uV */
@@ -1585,6 +1593,7 @@
 	int ret;
 	bool dcp;
 	bool host_bus_suspend;
+	bool host_ss_active;
 
 	dev_dbg(mdwc->dev, "%s: entering lpm\n", __func__);
 
@@ -1593,6 +1602,7 @@
 		return 0;
 	}
 
+	host_ss_active = dwc3_msm_read_reg(mdwc->base, USB3_PORTSC) & PORT_PE;
 	if (mdwc->hs_phy_irq)
 		disable_irq(mdwc->hs_phy_irq);
 
@@ -1606,7 +1616,8 @@
 								0x37, 0x0);
 	}
 
-	dcp = mdwc->charger.chg_type == DWC3_DCP_CHARGER;
+	dcp = ((mdwc->charger.chg_type == DWC3_DCP_CHARGER) ||
+	      (mdwc->charger.chg_type == DWC3_PROPRIETARY_CHARGER));
 	host_bus_suspend = mdwc->host_mode == 1;
 
 	/* Sequence to put SSPHY in low power state:
@@ -1661,14 +1672,19 @@
 
 	/* make sure above writes are completed before turning off clocks */
 	wmb();
-	clk_disable_unprepare(mdwc->core_clk);
+	if (!host_bus_suspend || !host_ss_active) {
+		clk_disable_unprepare(mdwc->core_clk);
+		mdwc->lpm_flags |= MDWC3_CORECLK_OFF;
+	}
 	clk_disable_unprepare(mdwc->iface_clk);
 
-	if (!host_bus_suspend) {
+	if (!host_bus_suspend)
 		clk_disable_unprepare(mdwc->utmi_clk);
 
+	if (!host_bus_suspend) {
 		/* USB PHY no more requires TCXO */
 		clk_disable_unprepare(mdwc->xo_clk);
+		mdwc->lpm_flags |= MDWC3_TCXO_SHUTDOWN;
 	}
 
 	if (mdwc->bus_perf_client) {
@@ -1684,15 +1700,19 @@
 
 	dwc3_ssusb_ldo_enable(0);
 	dwc3_ssusb_config_vddcx(0);
-	if (!host_bus_suspend)
+	if (!host_bus_suspend && !dcp)
 		dwc3_hsusb_config_vddcx(0);
 	wake_unlock(&mdwc->wlock);
 	atomic_set(&mdwc->in_lpm, 1);
 
 	dev_info(mdwc->dev, "DWC3 in low power mode\n");
 
-	if (mdwc->hs_phy_irq)
+	if (mdwc->hs_phy_irq) {
 		enable_irq(mdwc->hs_phy_irq);
+		/* with DCP we dont require wakeup using HS_PHY_IRQ */
+		if (dcp)
+			disable_irq_wake(mdwc->hs_phy_irq);
+	}
 
 	return 0;
 }
@@ -1719,17 +1739,22 @@
 			dev_err(mdwc->dev, "Failed to vote for bus scaling\n");
 	}
 
-	dcp = mdwc->charger.chg_type == DWC3_DCP_CHARGER;
+	dcp = ((mdwc->charger.chg_type == DWC3_DCP_CHARGER) ||
+	      (mdwc->charger.chg_type == DWC3_PROPRIETARY_CHARGER));
 	host_bus_suspend = mdwc->host_mode == 1;
 
-	if (!host_bus_suspend) {
+	if (mdwc->lpm_flags & MDWC3_TCXO_SHUTDOWN) {
 		/* Vote for TCXO while waking up USB HSPHY */
 		ret = clk_prepare_enable(mdwc->xo_clk);
 		if (ret)
 			dev_err(mdwc->dev, "%s failed to vote TCXO buffer%d\n",
 						__func__, ret);
+		mdwc->lpm_flags &= ~MDWC3_TCXO_SHUTDOWN;
 	}
 
+	if (!host_bus_suspend)
+		clk_prepare_enable(mdwc->utmi_clk);
+
 	if (mdwc->otg_xceiv && mdwc->ext_xceiv.otg_capability && !dcp &&
 							!host_bus_suspend)
 		dwc3_hsusb_ldo_enable(1);
@@ -1737,16 +1762,17 @@
 	dwc3_ssusb_ldo_enable(1);
 	dwc3_ssusb_config_vddcx(1);
 
-	if (!host_bus_suspend) {
+	if (!host_bus_suspend && !dcp)
 		dwc3_hsusb_config_vddcx(1);
-		clk_prepare_enable(mdwc->utmi_clk);
-	}
 
 	clk_prepare_enable(mdwc->ref_clk);
 	usleep_range(1000, 1200);
 
 	clk_prepare_enable(mdwc->iface_clk);
-	clk_prepare_enable(mdwc->core_clk);
+	if (mdwc->lpm_flags & MDWC3_CORECLK_OFF) {
+		clk_prepare_enable(mdwc->core_clk);
+		mdwc->lpm_flags &= ~MDWC3_CORECLK_OFF;
+	}
 
 	if (host_bus_suspend) {
 		/* Disable HV interrupt */
@@ -1809,6 +1835,9 @@
 		enable_irq(mdwc->hs_phy_irq);
 		mdwc->lpm_irq_seen = false;
 	}
+	/* it must DCP disconnect, re-enable HS_PHY wakeup IRQ */
+	if (mdwc->hs_phy_irq && dcp)
+		enable_irq_wake(mdwc->hs_phy_irq);
 
 	dev_info(mdwc->dev, "DWC3 exited from low power mode\n");
 
@@ -1838,7 +1867,7 @@
 		if (mdwc->otg_xceiv)
 			mdwc->ext_xceiv.notify_ext_events(mdwc->otg_xceiv->otg,
 							DWC3_EVENT_PHY_RESUME);
-		pm_runtime_put_sync(mdwc->dev);
+		pm_runtime_put_noidle(mdwc->dev);
 		if (mdwc->otg_xceiv && (mdwc->ext_xceiv.otg_capability))
 			mdwc->ext_xceiv.notify_ext_events(mdwc->otg_xceiv->otg,
 							DWC3_EVENT_XCEIV_STATE);
@@ -2529,24 +2558,28 @@
 		goto disable_hs_ldo;
 	}
 
-	msm->usb_psy.name = "usb";
-	msm->usb_psy.type = POWER_SUPPLY_TYPE_USB;
-	msm->usb_psy.supplied_to = dwc3_msm_pm_power_supplied_to;
-	msm->usb_psy.num_supplicants = ARRAY_SIZE(
-					dwc3_msm_pm_power_supplied_to);
-	msm->usb_psy.properties = dwc3_msm_pm_power_props_usb;
-	msm->usb_psy.num_properties = ARRAY_SIZE(dwc3_msm_pm_power_props_usb);
-	msm->usb_psy.get_property = dwc3_msm_power_get_property_usb;
-	msm->usb_psy.set_property = dwc3_msm_power_set_property_usb;
-	msm->usb_psy.external_power_changed =
-				dwc3_msm_external_power_changed;
+	/* usb_psy required only for vbus_notifications or charging support */
+	if (msm->ext_xceiv.otg_capability || !msm->charger.charging_disabled) {
+		msm->usb_psy.name = "usb";
+		msm->usb_psy.type = POWER_SUPPLY_TYPE_USB;
+		msm->usb_psy.supplied_to = dwc3_msm_pm_power_supplied_to;
+		msm->usb_psy.num_supplicants = ARRAY_SIZE(
+						dwc3_msm_pm_power_supplied_to);
+		msm->usb_psy.properties = dwc3_msm_pm_power_props_usb;
+		msm->usb_psy.num_properties =
+					ARRAY_SIZE(dwc3_msm_pm_power_props_usb);
+		msm->usb_psy.get_property = dwc3_msm_power_get_property_usb;
+		msm->usb_psy.set_property = dwc3_msm_power_set_property_usb;
+		msm->usb_psy.external_power_changed =
+					dwc3_msm_external_power_changed;
 
-	ret = power_supply_register(&pdev->dev, &msm->usb_psy);
-	if (ret < 0) {
-		dev_err(&pdev->dev,
-				"%s:power_supply_register usb failed\n",
-					__func__);
-		goto disable_hs_ldo;
+		ret = power_supply_register(&pdev->dev, &msm->usb_psy);
+		if (ret < 0) {
+			dev_err(&pdev->dev,
+					"%s:power_supply_register usb failed\n",
+						__func__);
+			goto disable_hs_ldo;
+		}
 	}
 
 	if (node) {
@@ -2571,7 +2604,8 @@
 	}
 
 	msm->otg_xceiv = usb_get_transceiver();
-	if (msm->otg_xceiv) {
+	/* Register with OTG if present, ignore USB2 OTG using other PHY */
+	if (msm->otg_xceiv && !(msm->otg_xceiv->flags & ENABLE_SECONDARY_PHY)) {
 		msm->charger.start_detection = dwc3_start_chg_det;
 		ret = dwc3_set_charger(msm->otg_xceiv->otg, &msm->charger);
 		if (ret || !msm->charger.notify_detection_complete) {
@@ -2589,7 +2623,20 @@
 			goto put_xcvr;
 		}
 	} else {
-		dev_err(&pdev->dev, "%s: No OTG transceiver found\n", __func__);
+		dev_dbg(&pdev->dev, "No OTG, DWC3 running in host only mode\n");
+		msm->host_mode = 1;
+		msm->vbus_otg = devm_regulator_get(&pdev->dev, "vbus_dwc3");
+		if (IS_ERR(msm->vbus_otg)) {
+			dev_dbg(&pdev->dev, "Failed to get vbus regulator\n");
+			msm->vbus_otg = 0;
+		} else {
+			ret = regulator_enable(msm->vbus_otg);
+			if (ret) {
+				msm->vbus_otg = 0;
+				dev_err(&pdev->dev, "Failed to enable vbus_otg\n");
+			}
+		}
+		msm->otg_xceiv = NULL;
 	}
 
 	wake_lock_init(&msm->wlock, WAKE_LOCK_SUSPEND, "msm_dwc3");
@@ -2601,7 +2648,8 @@
 put_xcvr:
 	usb_put_transceiver(msm->otg_xceiv);
 put_psupply:
-	power_supply_unregister(&msm->usb_psy);
+	if (msm->usb_psy.dev)
+		power_supply_unregister(&msm->usb_psy);
 disable_hs_ldo:
 	dwc3_hsusb_ldo_enable(0);
 free_hs_ldo_init:
@@ -2650,6 +2698,10 @@
 		dwc3_start_chg_det(&msm->charger, false);
 		usb_put_transceiver(msm->otg_xceiv);
 	}
+	if (msm->usb_psy.dev)
+		power_supply_unregister(&msm->usb_psy);
+	if (msm->vbus_otg)
+		regulator_disable(msm->vbus_otg);
 
 	pm_runtime_disable(msm->dev);
 	wake_lock_destroy(&msm->wlock);
diff --git a/drivers/usb/dwc3/dwc3_otg.c b/drivers/usb/dwc3/dwc3_otg.c
index 1d67cee..a3b2617 100644
--- a/drivers/usb/dwc3/dwc3_otg.c
+++ b/drivers/usb/dwc3/dwc3_otg.c
@@ -198,8 +198,6 @@
 	} else {
 		dev_dbg(otg->phy->dev, "%s: turn off host\n", __func__);
 
-		platform_device_del(dwc->xhci);
-
 		ret = regulator_disable(dotg->vbus_otg);
 		if (ret) {
 			dev_err(otg->phy->dev, "unable to disable vbus_otg\n");
@@ -207,6 +205,7 @@
 		}
 		dwc3_otg_notify_host_mode(otg, on);
 
+		platform_device_del(dwc->xhci);
 		/*
 		 * Perform USB hardware RESET (both core reset and DBM reset)
 		 * when moving from host to peripheral. This is required for
diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c
index d6d8a76..420d030 100644
--- a/drivers/usb/dwc3/host.c
+++ b/drivers/usb/dwc3/host.c
@@ -79,6 +79,7 @@
 
 	/* Add XHCI device if !OTG, otherwise OTG takes care of this */
 	if (!dwc->dotg) {
+		xhci->dev.parent = dwc->dev;
 		ret = platform_device_add(xhci);
 		if (ret) {
 			dev_err(dwc->dev, "failed to register xHCI device\n");
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index 79dcf2f..46b5ce4 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -16,6 +16,7 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/usb/otg.h>
+#include <linux/usb/msm_hsusb.h>
 
 #include "xhci.h"
 
@@ -140,6 +141,10 @@
 		goto release_mem_region;
 	}
 
+	pm_runtime_set_active(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_get_sync(&pdev->dev);
+
 	ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
 	if (ret)
 		goto unmap_registers;
@@ -166,7 +171,8 @@
 		goto put_usb3_hcd;
 
 	phy = usb_get_transceiver();
-	if (phy && phy->otg) {
+	/* Register with OTG if present, ignore USB2 OTG using other PHY */
+	if (phy && phy->otg && !(phy->flags & ENABLE_SECONDARY_PHY)) {
 		dev_dbg(&pdev->dev, "%s otg support available\n", __func__);
 		ret = otg_set_host(phy->otg, &hcd->self);
 		if (ret) {
@@ -175,15 +181,12 @@
 			usb_put_transceiver(phy);
 			goto put_usb3_hcd;
 		}
-		pm_runtime_set_active(&pdev->dev);
-		pm_runtime_enable(&pdev->dev);
 	} else {
 		pm_runtime_no_callbacks(&pdev->dev);
-		pm_runtime_set_active(&pdev->dev);
-		pm_runtime_enable(&pdev->dev);
-		pm_runtime_get(&pdev->dev);
 	}
 
+	pm_runtime_put(&pdev->dev);
+
 	return 0;
 
 put_usb3_hcd:
@@ -222,9 +225,6 @@
 	if (phy && phy->otg) {
 		otg_set_host(phy->otg, NULL);
 		usb_put_transceiver(phy);
-	} else {
-		pm_runtime_put(&dev->dev);
-		pm_runtime_disable(&dev->dev);
 	}
 
 	return 0;
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index e8d7489..afa7b97 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -245,7 +245,7 @@
 		return PTR_ERR(*srcp_ihdl);
 	}
 	pr_debug("%s(): ion_hdl %p, ion_buf %d\n", __func__, *srcp_ihdl,
-		ion_share_dma_buf(display_iclient, *srcp_ihdl));
+		mem_id);
 	pr_debug("mixer %u, pipe %u, plane %u\n", pipe->mixer_num,
 		pipe->pipe_ndx, plane);
 	if (ion_map_iommu(display_iclient, *srcp_ihdl,
diff --git a/drivers/video/msm/mdss/dsi_host_v2.c b/drivers/video/msm/mdss/dsi_host_v2.c
index 453cbaa..887dde7 100644
--- a/drivers/video/msm/mdss/dsi_host_v2.c
+++ b/drivers/video/msm/mdss/dsi_host_v2.c
@@ -29,6 +29,7 @@
 #define DSI_POLL_SLEEP_US 1000
 #define DSI_POLL_TIMEOUT_US 16000
 #define DSI_ESC_CLK_RATE 19200000
+#define DSI_DMA_CMD_TIMEOUT_MS 200
 
 struct dsi_host_v2_private {
 	struct completion dma_comp;
@@ -426,18 +427,15 @@
 
 	dsi_ctrl = MIPI_INP(ctrl_base + DSI_CTRL);
 	/*If Video enabled, Keep Video and Cmd mode ON */
-	if (dsi_ctrl & 0x02)
-		dsi_ctrl &= ~0x05;
-	else
-		dsi_ctrl &= ~0x07;
+
+
+	dsi_ctrl &= ~0x06;
 
 	if (mode == DSI_VIDEO_MODE) {
-		dsi_ctrl |= 0x03;
+		dsi_ctrl |= 0x02;
 		intr_ctrl = DSI_INTR_CMD_DMA_DONE_MASK;
 	} else {		/* command mode */
-		dsi_ctrl |= 0x05;
-		if (pdata->panel_info.type == MIPI_VIDEO_PANEL)
-			dsi_ctrl |= 0x02;
+		dsi_ctrl |= 0x04;
 
 		intr_ctrl = DSI_INTR_CMD_DMA_DONE_MASK | DSI_INTR_ERROR_MASK |
 				DSI_INTR_CMD_MDP_DONE_MASK;
@@ -480,7 +478,7 @@
 
 int msm_dsi_cmd_dma_tx(struct dsi_buf *tp)
 {
-	int len;
+	int len, rc;
 	unsigned long size, addr;
 	unsigned char *ctrl_base = dsi_host_private->dsi_base;
 
@@ -505,12 +503,17 @@
 	MIPI_OUTP(ctrl_base + DSI_CMD_MODE_DMA_SW_TRIGGER, 0x01);
 	wmb();
 
-	wait_for_completion_interruptible(&dsi_host_private->dma_comp);
+	rc = wait_for_completion_timeout(&dsi_host_private->dma_comp,
+				msecs_to_jiffies(DSI_DMA_CMD_TIMEOUT_MS));
+	if (rc == 0) {
+		pr_err("DSI command transaction time out\n");
+		rc = -ETIME;
+	}
 
 	dma_unmap_single(&dsi_host_private->dis_dev, tp->dmap, size,
 			DMA_TO_DEVICE);
 	tp->dmap = 0;
-	return 0;
+	return rc;
 }
 
 int msm_dsi_cmd_dma_rx(struct dsi_buf *rp, int rlen)
@@ -723,6 +726,7 @@
 
 static int msm_dsi_cal_clk_rate(struct mdss_panel_data *pdata,
 				u32 *bitclk_rate,
+				u32 *dsiclk_rate,
 				u32 *byteclk_rate,
 				u32 *pclk_rate)
 {
@@ -761,10 +765,11 @@
 	*bitclk_rate /= lanes;
 
 	*byteclk_rate = *bitclk_rate / 8;
+	*dsiclk_rate = *byteclk_rate * lanes;
 	*pclk_rate = *byteclk_rate * lanes * 8 / pdata->panel_info.bpp;
 
-	pr_debug("bitclk=%u, byteclk=%u, pck_=%u\n",
-		*bitclk_rate, *byteclk_rate, *pclk_rate);
+	pr_debug("dsiclk_rate=%u, byteclk=%u, pck_=%u\n",
+		*dsiclk_rate, *byteclk_rate, *pclk_rate);
 	return 0;
 }
 
@@ -777,7 +782,7 @@
 	u32 hbp, hfp, vbp, vfp, hspw, vspw, width, height;
 	u32 ystride, bpp, data;
 	u32 dummy_xres, dummy_yres;
-	u32 bitclk_rate = 0, byteclk_rate = 0, pclk_rate = 0;
+	u32 bitclk_rate = 0, byteclk_rate = 0, pclk_rate = 0, dsiclk_rate = 0;
 	unsigned char *ctrl_base = dsi_host_private->dsi_base;
 
 	pr_debug("msm_dsi_on\n");
@@ -794,8 +799,10 @@
 	msm_dsi_phy_sw_reset(dsi_host_private->dsi_base);
 	msm_dsi_phy_init(dsi_host_private->dsi_base, pdata);
 
-	msm_dsi_cal_clk_rate(pdata, &bitclk_rate, &byteclk_rate, &pclk_rate);
-	msm_dsi_clk_set_rate(DSI_ESC_CLK_RATE, byteclk_rate, pclk_rate);
+	msm_dsi_cal_clk_rate(pdata, &bitclk_rate, &dsiclk_rate,
+				&byteclk_rate, &pclk_rate);
+	msm_dsi_clk_set_rate(DSI_ESC_CLK_RATE, dsiclk_rate,
+				byteclk_rate, pclk_rate);
 	msm_dsi_prepare_clocks();
 	msm_dsi_clk_enable();
 
@@ -879,12 +886,11 @@
 	int ret = 0;
 
 	pr_debug("msm_dsi_off\n");
-	msm_dsi_clk_set_rate(0, 0, 0);
+	msm_dsi_controller_cfg(0);
+	msm_dsi_clk_set_rate(DSI_ESC_CLK_RATE, 0, 0, 0);
 	msm_dsi_clk_disable();
 	msm_dsi_unprepare_clocks();
 
-	/* disable DSI controller */
-	msm_dsi_controller_cfg(0);
 	msm_dsi_ahb_ctrl(0);
 
 	ret = msm_dsi_regulator_disable();
diff --git a/drivers/video/msm/mdss/dsi_io_v2.c b/drivers/video/msm/mdss/dsi_io_v2.c
index 0486c4c..93f2c76 100644
--- a/drivers/video/msm/mdss/dsi_io_v2.c
+++ b/drivers/video/msm/mdss/dsi_io_v2.c
@@ -29,6 +29,7 @@
 	struct clk *dsi_esc_clk;
 	struct clk *dsi_pixel_clk;
 	struct clk *dsi_ahb_clk;
+	struct clk *dsi_clk;
 	int msm_dsi_clk_on;
 	int msm_dsi_ahb_clk_on;
 };
@@ -97,6 +98,13 @@
 {
 	int rc = 0;
 
+	dsi_io_private->dsi_clk = clk_get(&dev->dev, "dsi_clk");
+	if (IS_ERR(dsi_io_private->dsi_clk)) {
+		pr_err("can't find dsi core_clk\n");
+		rc = PTR_ERR(dsi_io_private->dsi_clk);
+		dsi_io_private->dsi_clk = NULL;
+		return rc;
+	}
 	dsi_io_private->dsi_byte_clk = clk_get(&dev->dev, "byte_clk");
 	if (IS_ERR(dsi_io_private->dsi_byte_clk)) {
 		pr_err("can't find dsi byte_clk\n");
@@ -135,6 +143,10 @@
 
 void msm_dsi_clk_deinit(void)
 {
+	if (dsi_io_private->dsi_clk) {
+		clk_put(dsi_io_private->dsi_clk);
+		dsi_io_private->dsi_clk = NULL;
+	}
 	if (dsi_io_private->dsi_byte_clk) {
 		clk_put(dsi_io_private->dsi_byte_clk);
 		dsi_io_private->dsi_byte_clk = NULL;
@@ -156,6 +168,7 @@
 
 int msm_dsi_prepare_clocks(void)
 {
+	clk_prepare(dsi_io_private->dsi_clk);
 	clk_prepare(dsi_io_private->dsi_byte_clk);
 	clk_prepare(dsi_io_private->dsi_esc_clk);
 	clk_prepare(dsi_io_private->dsi_pixel_clk);
@@ -164,16 +177,24 @@
 
 int msm_dsi_unprepare_clocks(void)
 {
+	clk_unprepare(dsi_io_private->dsi_clk);
 	clk_unprepare(dsi_io_private->dsi_esc_clk);
 	clk_unprepare(dsi_io_private->dsi_byte_clk);
 	clk_unprepare(dsi_io_private->dsi_pixel_clk);
 	return 0;
 }
 
-int msm_dsi_clk_set_rate(unsigned long esc_rate, unsigned long byte_rate,
+int msm_dsi_clk_set_rate(unsigned long esc_rate,
+			unsigned long dsi_rate,
+			unsigned long byte_rate,
 			unsigned long pixel_rate)
 {
 	int rc;
+	rc = clk_set_rate(dsi_io_private->dsi_clk, dsi_rate);
+	if (rc) {
+		pr_err("dsi_esc_clk - clk_set_rate failed =%d\n", rc);
+		return rc;
+	}
 
 	rc = clk_set_rate(dsi_io_private->dsi_esc_clk, esc_rate);
 	if (rc) {
@@ -202,6 +223,7 @@
 		return 0;
 	}
 
+	clk_enable(dsi_io_private->dsi_clk);
 	clk_enable(dsi_io_private->dsi_esc_clk);
 	clk_enable(dsi_io_private->dsi_byte_clk);
 	clk_enable(dsi_io_private->dsi_pixel_clk);
@@ -217,6 +239,7 @@
 		return 0;
 	}
 
+	clk_disable(dsi_io_private->dsi_clk);
 	clk_disable(dsi_io_private->dsi_byte_clk);
 	clk_disable(dsi_io_private->dsi_esc_clk);
 	clk_disable(dsi_io_private->dsi_pixel_clk);
@@ -246,7 +269,7 @@
 
 void msm_dsi_regulator_deinit(void)
 {
-	if (dsi_io_private->vdda_vreg) {
+	if (!IS_ERR(dsi_io_private->vdda_vreg)) {
 		devm_regulator_put(dsi_io_private->vdda_vreg);
 		dsi_io_private->vdda_vreg = NULL;
 	}
diff --git a/drivers/video/msm/mdss/dsi_io_v2.h b/drivers/video/msm/mdss/dsi_io_v2.h
index 25ecd7f..285bf30 100644
--- a/drivers/video/msm/mdss/dsi_io_v2.h
+++ b/drivers/video/msm/mdss/dsi_io_v2.h
@@ -29,7 +29,9 @@
 
 int msm_dsi_unprepare_clocks(void);
 
-int msm_dsi_clk_set_rate(unsigned long esc_rate, unsigned long byte_rate,
+int msm_dsi_clk_set_rate(unsigned long esc_rate,
+			unsigned long dsi_rate,
+			unsigned long byte_rate,
 			unsigned long pixel_rate);
 
 int msm_dsi_clk_enable(void);
diff --git a/drivers/video/msm/mdss/dsi_panel_v2.c b/drivers/video/msm/mdss/dsi_panel_v2.c
index 6686de3..e46ea3b 100644
--- a/drivers/video/msm/mdss/dsi_panel_v2.c
+++ b/drivers/video/msm/mdss/dsi_panel_v2.c
@@ -20,6 +20,7 @@
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/leds.h>
+#include <linux/err.h>
 #include <linux/regulator/consumer.h>
 
 #include "dsi_v2.h"
@@ -32,6 +33,7 @@
 
 	int rst_gpio;
 	int disp_en_gpio;
+	int video_mode_gpio;
 	char bl_ctrl;
 
 	struct regulator *vddio_vreg;
@@ -40,6 +42,9 @@
 	struct dsi_panel_cmds_list *on_cmds_list;
 	struct dsi_panel_cmds_list *off_cmds_list;
 	struct mdss_dsi_phy_ctrl phy_params;
+
+	char *on_cmds;
+	char *off_cmds;
 };
 
 static struct dsi_panel_private *panel_private;
@@ -82,15 +87,54 @@
 	kfree(panel_private->dsi_panel_tx_buf.start);
 	kfree(panel_private->dsi_panel_rx_buf.start);
 
-	if (panel_private->vddio_vreg)
+	if (!IS_ERR(panel_private->vddio_vreg))
 		devm_regulator_put(panel_private->vddio_vreg);
 
-	if (panel_private->vdda_vreg)
-		devm_regulator_put(panel_private->vddio_vreg);
+	if (!IS_ERR(panel_private->vdda_vreg))
+		devm_regulator_put(panel_private->vdda_vreg);
 
+	if (panel_private->on_cmds_list) {
+		kfree(panel_private->on_cmds_list->buf);
+		kfree(panel_private->on_cmds_list);
+	}
+	if (panel_private->off_cmds_list) {
+		kfree(panel_private->off_cmds_list->buf);
+		kfree(panel_private->off_cmds_list);
+	}
+
+	kfree(panel_private->on_cmds);
+	kfree(panel_private->off_cmds);
 	kfree(panel_private);
 	panel_private = NULL;
 }
+int dsi_panel_power(int enable)
+{
+	int ret;
+	if (enable) {
+		ret = regulator_enable(panel_private->vddio_vreg);
+		if (ret) {
+			pr_err("dsi_panel_power regulator enable vddio fail\n");
+			return ret;
+		}
+		ret = regulator_enable(panel_private->vdda_vreg);
+		if (ret) {
+			pr_err("dsi_panel_power regulator enable vdda fail\n");
+			return ret;
+		}
+	} else {
+		ret = regulator_disable(panel_private->vddio_vreg);
+		if (ret) {
+			pr_err("dsi_panel_power regulator disable vddio fail\n");
+			return ret;
+		}
+		ret = regulator_disable(panel_private->vdda_vreg);
+		if (ret) {
+			pr_err("dsi_panel_power regulator dsiable vdda fail\n");
+			return ret;
+		}
+	}
+	return 0;
+}
 
 void dsi_panel_reset(struct mdss_panel_data *pdata, int enable)
 {
@@ -113,6 +157,8 @@
 	pr_debug("%s: enable = %d\n", __func__, enable);
 
 	if (enable) {
+		dsi_panel_power(1);
+		gpio_request(panel_private->rst_gpio, "panel_reset");
 		gpio_set_value(panel_private->rst_gpio, 1);
 		/*
 		 * these delay values are by experiments currently, will need
@@ -123,12 +169,34 @@
 		udelay(200);
 		gpio_set_value(panel_private->rst_gpio, 1);
 		msleep(20);
-		if (gpio_is_valid(panel_private->disp_en_gpio))
+		if (gpio_is_valid(panel_private->disp_en_gpio)) {
+			gpio_request(panel_private->disp_en_gpio,
+					"panel_enable");
 			gpio_set_value(panel_private->disp_en_gpio, 1);
+		}
+		if (gpio_is_valid(panel_private->video_mode_gpio)) {
+			gpio_request(panel_private->video_mode_gpio,
+					"panel_video_mdoe");
+			if (pdata->panel_info.mipi.mode == DSI_VIDEO_MODE)
+				gpio_set_value(panel_private->video_mode_gpio,
+						1);
+			else
+				gpio_set_value(panel_private->video_mode_gpio,
+						0);
+		}
 	} else {
 		gpio_set_value(panel_private->rst_gpio, 0);
-		if (gpio_is_valid(panel_private->disp_en_gpio))
+		gpio_free(panel_private->rst_gpio);
+
+		if (gpio_is_valid(panel_private->disp_en_gpio)) {
 			gpio_set_value(panel_private->disp_en_gpio, 0);
+			gpio_free(panel_private->disp_en_gpio);
+		}
+
+		if (gpio_is_valid(panel_private->video_mode_gpio))
+			gpio_free(panel_private->video_mode_gpio);
+
+		dsi_panel_power(0);
 	}
 }
 
@@ -196,13 +264,42 @@
 	panel_private->disp_en_gpio = of_get_named_gpio(np,
 						"qcom,enable-gpio", 0);
 	panel_private->rst_gpio = of_get_named_gpio(np, "qcom,rst-gpio", 0);
+	panel_private->video_mode_gpio = of_get_named_gpio(np,
+						"qcom,mode-selection-gpio", 0);
 	return 0;
 }
 
 static int dsi_panel_parse_regulator(struct platform_device *pdev)
 {
+	int ret;
 	panel_private->vddio_vreg = devm_regulator_get(&pdev->dev, "vddio");
+	if (IS_ERR(panel_private->vddio_vreg)) {
+		pr_err("%s: could not get vddio vreg, rc=%ld\n",
+			__func__, PTR_ERR(panel_private->vddio_vreg));
+		return PTR_ERR(panel_private->vddio_vreg);
+	}
+	ret = regulator_set_voltage(panel_private->vddio_vreg,
+					1800000,
+					1800000);
+	if (ret) {
+		pr_err("%s: set voltage failed on vddio_vreg, rc=%d\n",
+			__func__, ret);
+		return ret;
+	}
 	panel_private->vdda_vreg = devm_regulator_get(&pdev->dev, "vdda");
+	if (IS_ERR(panel_private->vdda_vreg)) {
+		pr_err("%s: could not get vdda_vreg , rc=%ld\n",
+			__func__, PTR_ERR(panel_private->vdda_vreg));
+		return PTR_ERR(panel_private->vdda_vreg);
+	}
+	ret = regulator_set_voltage(panel_private->vdda_vreg,
+					2850000,
+					2850000);
+	if (ret) {
+		pr_err("%s: set voltage failed on vdda_vreg, rc=%d\n",
+			__func__, ret);
+		return ret;
+	}
 	return 0;
 }
 
@@ -398,180 +495,163 @@
 	int cmd_plen, data_offset;
 	const char *data;
 	const char *on_cmds_state, *off_cmds_state;
-	char *on_cmds = NULL, *off_cmds = NULL;
 	int num_of_on_cmds = 0, num_of_off_cmds = 0;
 
 	data = of_get_property(np, "qcom,panel-on-cmds", &len);
 	if (!data) {
 		pr_err("%s:%d, Unable to read ON cmds", __func__, __LINE__);
-		goto parse_init_cmds_error;
+		return -EINVAL;
 	}
 
-	on_cmds = kzalloc(sizeof(char) * len, GFP_KERNEL);
-	if (!on_cmds)
-		goto parse_init_cmds_error;
+	panel_private->on_cmds = kzalloc(sizeof(char) * len, GFP_KERNEL);
+	if (!panel_private->on_cmds)
+		return -ENOMEM;
 
-	memcpy(on_cmds, data, len);
+	memcpy(panel_private->on_cmds, data, len);
 
 	data_offset = 0;
 	cmd_plen = 0;
 	while ((len - data_offset) >= DT_CMD_HDR) {
 		data_offset += (DT_CMD_HDR - 1);
-		cmd_plen = on_cmds[data_offset++];
+		cmd_plen = panel_private->on_cmds[data_offset++];
 		data_offset += cmd_plen;
 		num_of_on_cmds++;
 	}
 	if (!num_of_on_cmds) {
 		pr_err("%s:%d, No ON cmds specified", __func__, __LINE__);
-		goto parse_init_cmds_error;
+		return -EINVAL;
 	}
 
-	panel_data->dsi_panel_on_cmds =
+	panel_private->on_cmds_list =
 		kzalloc(sizeof(struct dsi_panel_cmds_list), GFP_KERNEL);
-	if (!panel_data->dsi_panel_on_cmds)
-		goto parse_init_cmds_error;
+	if (!panel_private->on_cmds_list)
+		return -ENOMEM;
 
-	(panel_data->dsi_panel_on_cmds)->buf =
+	panel_private->on_cmds_list->buf =
 		kzalloc((num_of_on_cmds * sizeof(struct dsi_cmd_desc)),
 			GFP_KERNEL);
-	if (!(panel_data->dsi_panel_on_cmds)->buf)
-		goto parse_init_cmds_error;
+	if (!panel_private->on_cmds_list->buf)
+		return -ENOMEM;
 
 	data_offset = 0;
 	for (i = 0; i < num_of_on_cmds; i++) {
-		panel_data->dsi_panel_on_cmds->buf[i].dtype =
-						on_cmds[data_offset++];
-		panel_data->dsi_panel_on_cmds->buf[i].last =
-						on_cmds[data_offset++];
-		panel_data->dsi_panel_on_cmds->buf[i].vc =
-						on_cmds[data_offset++];
-		panel_data->dsi_panel_on_cmds->buf[i].ack =
-						on_cmds[data_offset++];
-		panel_data->dsi_panel_on_cmds->buf[i].wait =
-						on_cmds[data_offset++];
-		panel_data->dsi_panel_on_cmds->buf[i].dlen =
-						on_cmds[data_offset++];
-		panel_data->dsi_panel_on_cmds->buf[i].payload =
-						&on_cmds[data_offset];
-		data_offset += (panel_data->dsi_panel_on_cmds->buf[i].dlen);
+		panel_private->on_cmds_list->buf[i].dtype =
+					panel_private->on_cmds[data_offset++];
+		panel_private->on_cmds_list->buf[i].last =
+					panel_private->on_cmds[data_offset++];
+		panel_private->on_cmds_list->buf[i].vc =
+					panel_private->on_cmds[data_offset++];
+		panel_private->on_cmds_list->buf[i].ack =
+					panel_private->on_cmds[data_offset++];
+		panel_private->on_cmds_list->buf[i].wait =
+					panel_private->on_cmds[data_offset++];
+		panel_private->on_cmds_list->buf[i].dlen =
+					panel_private->on_cmds[data_offset++];
+		panel_private->on_cmds_list->buf[i].payload =
+					&panel_private->on_cmds[data_offset];
+		data_offset += (panel_private->on_cmds_list->buf[i].dlen);
 	}
 
 	if (data_offset != len) {
 		pr_err("%s:%d, Incorrect ON command entries",
 						__func__, __LINE__);
-		goto parse_init_cmds_error;
+		return -EINVAL;
 	}
 
-	(panel_data->dsi_panel_on_cmds)->size = num_of_on_cmds;
+	panel_private->on_cmds_list->size = num_of_on_cmds;
 
 	on_cmds_state = of_get_property(pdev->dev.of_node,
 					"qcom,on-cmds-dsi-state", NULL);
 	if (!strncmp(on_cmds_state, "DSI_LP_MODE", 11)) {
-		(panel_data->dsi_panel_on_cmds)->ctrl_state = DSI_LP_MODE;
+		panel_private->on_cmds_list->ctrl_state = DSI_LP_MODE;
 	} else if (!strncmp(on_cmds_state, "DSI_HS_MODE", 11)) {
-		(panel_data->dsi_panel_on_cmds)->ctrl_state = DSI_HS_MODE;
+		panel_private->on_cmds_list->ctrl_state = DSI_HS_MODE;
 	} else {
 		pr_debug("%s: ON cmds state not specified. Set Default\n",
 							__func__);
-		(panel_data->dsi_panel_on_cmds)->ctrl_state = DSI_LP_MODE;
+		panel_private->on_cmds_list->ctrl_state = DSI_LP_MODE;
 	}
 
-	panel_private->on_cmds_list = panel_data->dsi_panel_on_cmds;
+	panel_data->dsi_panel_on_cmds = panel_private->on_cmds_list;
+
 	data = of_get_property(np, "qcom,panel-off-cmds", &len);
 	if (!data) {
 		pr_err("%s:%d, Unable to read OFF cmds", __func__, __LINE__);
-		goto parse_init_cmds_error;
+		return -EINVAL;
 	}
 
-	off_cmds = kzalloc(sizeof(char) * len, GFP_KERNEL);
-	if (!off_cmds)
-		goto parse_init_cmds_error;
+	panel_private->off_cmds = kzalloc(sizeof(char) * len, GFP_KERNEL);
+	if (!panel_private->off_cmds)
+		return -ENOMEM;
 
-	memcpy(off_cmds, data, len);
+	memcpy(panel_private->off_cmds, data, len);
 
 	data_offset = 0;
 	cmd_plen = 0;
 	while ((len - data_offset) >= DT_CMD_HDR) {
 		data_offset += (DT_CMD_HDR - 1);
-		cmd_plen = off_cmds[data_offset++];
+		cmd_plen = panel_private->off_cmds[data_offset++];
 		data_offset += cmd_plen;
 		num_of_off_cmds++;
 	}
 	if (!num_of_off_cmds) {
 		pr_err("%s:%d, No OFF cmds specified", __func__, __LINE__);
-		goto parse_init_cmds_error;
+		return -ENOMEM;
 	}
 
-	panel_data->dsi_panel_off_cmds =
+	panel_private->off_cmds_list =
 		kzalloc(sizeof(struct dsi_panel_cmds_list), GFP_KERNEL);
-	if (!panel_data->dsi_panel_off_cmds)
-		goto parse_init_cmds_error;
+	if (!panel_private->off_cmds_list)
+		return -ENOMEM;
 
-	(panel_data->dsi_panel_off_cmds)->buf = kzalloc(num_of_off_cmds
+	panel_private->off_cmds_list->buf = kzalloc(num_of_off_cmds
 					* sizeof(struct dsi_cmd_desc),
 						GFP_KERNEL);
-	if (!(panel_data->dsi_panel_off_cmds)->buf)
-		goto parse_init_cmds_error;
+	if (!panel_private->off_cmds_list->buf)
+		return -ENOMEM;
 
 	data_offset = 0;
 	for (i = 0; i < num_of_off_cmds; i++) {
-		panel_data->dsi_panel_off_cmds->buf[i].dtype =
-						off_cmds[data_offset++];
-		panel_data->dsi_panel_off_cmds->buf[i].last =
-						off_cmds[data_offset++];
-		panel_data->dsi_panel_off_cmds->buf[i].vc =
-						off_cmds[data_offset++];
-		panel_data->dsi_panel_off_cmds->buf[i].ack =
-						off_cmds[data_offset++];
-		panel_data->dsi_panel_off_cmds->buf[i].wait =
-						off_cmds[data_offset++];
-		panel_data->dsi_panel_off_cmds->buf[i].dlen =
-						off_cmds[data_offset++];
-		panel_data->dsi_panel_off_cmds->buf[i].payload =
-						&off_cmds[data_offset];
-		data_offset += (panel_data->dsi_panel_off_cmds->buf[i].dlen);
+		panel_private->off_cmds_list->buf[i].dtype =
+					panel_private->off_cmds[data_offset++];
+		panel_private->off_cmds_list->buf[i].last =
+					panel_private->off_cmds[data_offset++];
+		panel_private->off_cmds_list->buf[i].vc =
+					panel_private->off_cmds[data_offset++];
+		panel_private->off_cmds_list->buf[i].ack =
+					panel_private->off_cmds[data_offset++];
+		panel_private->off_cmds_list->buf[i].wait =
+					panel_private->off_cmds[data_offset++];
+		panel_private->off_cmds_list->buf[i].dlen =
+					panel_private->off_cmds[data_offset++];
+		panel_private->off_cmds_list->buf[i].payload =
+					&panel_private->off_cmds[data_offset];
+		data_offset += (panel_private->off_cmds_list->buf[i].dlen);
 	}
 
 	if (data_offset != len) {
 		pr_err("%s:%d, Incorrect OFF command entries",
 						__func__, __LINE__);
-		goto parse_init_cmds_error;
+		return -EINVAL;
 	}
 
-	(panel_data->dsi_panel_off_cmds)->size = num_of_off_cmds;
-			off_cmds_state = of_get_property(pdev->dev.of_node,
+	panel_private->off_cmds_list->size = num_of_off_cmds;
+	off_cmds_state = of_get_property(pdev->dev.of_node,
 				"qcom,off-cmds-dsi-state", NULL);
 	if (!strncmp(off_cmds_state, "DSI_LP_MODE", 11)) {
-		(panel_data->dsi_panel_off_cmds)->ctrl_state =
+		panel_private->off_cmds_list->ctrl_state =
 						DSI_LP_MODE;
 	} else if (!strncmp(off_cmds_state, "DSI_HS_MODE", 11)) {
-		(panel_data->dsi_panel_off_cmds)->ctrl_state = DSI_HS_MODE;
+		panel_private->off_cmds_list->ctrl_state = DSI_HS_MODE;
 	} else {
 		pr_debug("%s: ON cmds state not specified. Set Default\n",
 							__func__);
-		(panel_data->dsi_panel_off_cmds)->ctrl_state = DSI_LP_MODE;
+		panel_private->off_cmds_list->ctrl_state = DSI_LP_MODE;
 	}
 
-	panel_private->off_cmds_list = panel_data->dsi_panel_on_cmds;
-	kfree(on_cmds);
-	kfree(off_cmds);
+	panel_data->dsi_panel_off_cmds = panel_private->off_cmds_list;
 
 	return 0;
-parse_init_cmds_error:
-	if (panel_data->dsi_panel_on_cmds) {
-		kfree((panel_data->dsi_panel_on_cmds)->buf);
-		kfree(panel_data->dsi_panel_on_cmds);
-		panel_data->dsi_panel_on_cmds = NULL;
-	}
-	if (panel_data->dsi_panel_off_cmds) {
-		kfree((panel_data->dsi_panel_off_cmds)->buf);
-		kfree(panel_data->dsi_panel_off_cmds);
-		panel_data->dsi_panel_off_cmds = NULL;
-	}
-
-	kfree(on_cmds);
-	kfree(off_cmds);
-	return -EINVAL;
 }
 
 static int dsi_panel_parse_backlight(struct platform_device *pdev,
@@ -709,6 +789,7 @@
 
 	vendor_pdata.on = dsi_panel_on;
 	vendor_pdata.off = dsi_panel_off;
+	vendor_pdata.reset = dsi_panel_reset;
 	vendor_pdata.bl_fnc = dsi_panel_bl_ctrl;
 
 	rc = dsi_panel_device_register_v2(pdev, &vendor_pdata,
diff --git a/drivers/video/msm/mdss/dsi_v2.c b/drivers/video/msm/mdss/dsi_v2.c
index 5e46bf5..5833796 100644
--- a/drivers/video/msm/mdss/dsi_v2.c
+++ b/drivers/video/msm/mdss/dsi_v2.c
@@ -29,6 +29,14 @@
 	if (!panel_common_data || !pdata)
 		return -ENODEV;
 
+	if (dsi_intf.op_mode_config)
+		dsi_intf.op_mode_config(DSI_CMD_MODE, pdata);
+
+	pr_debug("panel off commands\n");
+	if (panel_common_data->off)
+		panel_common_data->off(pdata);
+
+	pr_debug("turn off dsi controller\n");
 	if (dsi_intf.off)
 		rc = dsi_intf.off(pdata);
 
@@ -37,9 +45,9 @@
 		return rc;
 	}
 
-	pr_debug("dsi_off reset\n");
-	if (panel_common_data->off)
-		panel_common_data->off(pdata);
+	pr_debug("turn off panel power\n");
+	if (panel_common_data->reset)
+		panel_common_data->reset(pdata, 0);
 
 	return rc;
 }
@@ -53,8 +61,6 @@
 	if (!panel_common_data || !pdata)
 		return -ENODEV;
 
-	if (panel_common_data->reset)
-		panel_common_data->reset(1);
 
 	pr_debug("dsi_on DSI controller ont\n");
 	if (dsi_intf.on)
@@ -64,6 +70,9 @@
 		pr_err("mdss_dsi_on DSI failed %d\n", rc);
 		return rc;
 	}
+	pr_debug("dsi_on power on panel\n");
+	if (panel_common_data->reset)
+		panel_common_data->reset(pdata, 1);
 
 	pr_debug("dsi_on DSI panel ont\n");
 	if (panel_common_data->on)
diff --git a/drivers/video/msm/mdss/dsi_v2.h b/drivers/video/msm/mdss/dsi_v2.h
index fa868ab..f68527c 100644
--- a/drivers/video/msm/mdss/dsi_v2.h
+++ b/drivers/video/msm/mdss/dsi_v2.h
@@ -189,7 +189,7 @@
 	struct mdss_panel_info panel_info;
 	int (*on) (struct mdss_panel_data *pdata);
 	int (*off) (struct mdss_panel_data *pdata);
-	void (*reset)(int enable);
+	void (*reset)(struct mdss_panel_data *pdata, int enable);
 	void (*bl_fnc) (struct mdss_panel_data *pdata, u32 bl_level);
 	struct dsi_panel_cmds_list *dsi_panel_on_cmds;
 	struct dsi_panel_cmds_list *dsi_panel_off_cmds;
diff --git a/drivers/video/msm/mdss/mdp3.c b/drivers/video/msm/mdss/mdp3.c
index 890b00b..52243eb 100644
--- a/drivers/video/msm/mdss/mdp3.c
+++ b/drivers/video/msm/mdss/mdp3.c
@@ -47,7 +47,7 @@
 #include "mdp3_hwio.h"
 #include "mdp3_ctrl.h"
 
-#define MDP_CORE_HW_VERSION	0x03030304
+#define MDP_CORE_HW_VERSION	0x03040310
 struct mdp3_hw_resource *mdp3_res;
 
 #define MDP_BUS_VECTOR_ENTRY(ab_val, ib_val)		\
@@ -302,16 +302,7 @@
 	return ret;
 }
 
-int mdp3_vsync_clk_enable(int enable)
-{
-	int ret = 0;
 
-	pr_debug("vsync clk enable=%d\n", enable);
-	mutex_lock(&mdp3_res->res_mutex);
-	mdp3_clk_update(MDP3_CLK_VSYNC, enable);
-	mutex_unlock(&mdp3_res->res_mutex);
-	return ret;
-}
 
 int mdp3_clk_set_rate(int clk_type, unsigned long clk_rate)
 {
@@ -400,6 +391,9 @@
 	if (rc)
 		return rc;
 
+	rc = mdp3_clk_register("dsi_clk", MDP3_CLK_DSI);
+	if (rc)
+		return rc;
 	return rc;
 }
 
@@ -409,6 +403,7 @@
 	clk_put(mdp3_res->clocks[MDP3_CLK_CORE]);
 	clk_put(mdp3_res->clocks[MDP3_CLK_VSYNC]);
 	clk_put(mdp3_res->clocks[MDP3_CLK_LCDC]);
+	clk_put(mdp3_res->clocks[MDP3_CLK_DSI]);
 }
 
 int mdp3_clk_enable(int enable)
@@ -421,6 +416,7 @@
 	rc = mdp3_clk_update(MDP3_CLK_AHB, enable);
 	rc |= mdp3_clk_update(MDP3_CLK_CORE, enable);
 	rc |= mdp3_clk_update(MDP3_CLK_VSYNC, enable);
+	rc |= mdp3_clk_update(MDP3_CLK_DSI, enable);
 	mutex_unlock(&mdp3_res->res_mutex);
 	return rc;
 }
@@ -577,12 +573,14 @@
 	int rc;
 
 	rc = mdp3_clk_update(MDP3_CLK_AHB, 1);
+	rc |= mdp3_clk_update(MDP3_CLK_CORE, 1);
 	if (rc)
 		return rc;
 
 	mdp3_res->mdp_rev = MDP3_REG_READ(MDP3_REG_HW_VERSION);
 
 	rc = mdp3_clk_update(MDP3_CLK_AHB, 0);
+	rc |= mdp3_clk_update(MDP3_CLK_CORE, 0);
 	if (rc)
 		pr_err("fail to turn off the MDP3_CLK_AHB clk\n");
 
diff --git a/drivers/video/msm/mdss/mdp3.h b/drivers/video/msm/mdss/mdp3.h
index c853664..5774e5a 100644
--- a/drivers/video/msm/mdss/mdp3.h
+++ b/drivers/video/msm/mdss/mdp3.h
@@ -29,6 +29,7 @@
 	MDP3_CLK_CORE,
 	MDP3_CLK_VSYNC,
 	MDP3_CLK_LCDC,
+	MDP3_CLK_DSI,
 	MDP3_MAX_CLK
 };
 
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index e07c0a4..99b7604 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -28,7 +28,7 @@
 
 void vsync_notify_handler(void *arg)
 {
-	struct mdp3_session_data *session = (struct mdp3_session_data *)session;
+	struct mdp3_session_data *session = (struct mdp3_session_data *)arg;
 	complete(&session->vsync_comp);
 }
 
@@ -100,18 +100,30 @@
 	.attrs = vsync_fs_attrs,
 };
 
-static int mdp3_ctrl_res_req_dma(struct msm_fb_data_type *mfd, int status)
+static int mdp3_ctrl_res_req_bus(struct msm_fb_data_type *mfd, int status)
 {
 	int rc = 0;
 	if (status) {
 		struct mdss_panel_info *panel_info = mfd->panel_info;
 		int ab = 0;
 		int ib = 0;
-		unsigned long core_clk = 0;
-		int vtotal = 0;
 		ab = panel_info->xres * panel_info->yres * 4;
 		ab *= panel_info->mipi.frame_rate;
 		ib = (ab * 3) / 2;
+		rc = mdp3_bus_scale_set_quota(MDP3_BW_CLIENT_DMA_P, ab, ib);
+	} else {
+		rc = mdp3_bus_scale_set_quota(MDP3_BW_CLIENT_DMA_P, 0, 0);
+	}
+	return rc;
+}
+
+static int mdp3_ctrl_res_req_clk(struct msm_fb_data_type *mfd, int status)
+{
+	int rc = 0;
+	if (status) {
+		struct mdss_panel_info *panel_info = mfd->panel_info;
+		unsigned long core_clk;
+		int vtotal;
 		vtotal = panel_info->lcdc.v_back_porch +
 			panel_info->lcdc.v_front_porch +
 			panel_info->lcdc.v_pulse_width +
@@ -126,10 +138,8 @@
 		if (rc)
 			return rc;
 
-		mdp3_bus_scale_set_quota(MDP3_BW_CLIENT_DMA_P, ab, ib);
 	} else {
 		rc = mdp3_clk_enable(false);
-		rc |= mdp3_bus_scale_set_quota(MDP3_BW_CLIENT_DMA_P, 0, 0);
 	}
 	return rc;
 }
@@ -285,13 +295,25 @@
 	}
 	mutex_lock(&mdp3_session->lock);
 	if (mdp3_session->status) {
-		pr_info("fb%d is on already", mfd->index);
+		pr_debug("fb%d is on already", mfd->index);
 		goto on_error;
 	}
 
-	rc = mdp3_ctrl_res_req_dma(mfd, 1);
+	/* request bus bandwidth before DSI DMA traffic */
+	rc = mdp3_ctrl_res_req_bus(mfd, 1);
+	if (rc)
+		pr_err("fail to request bus resource\n");
+
+	panel = mdp3_session->panel;
+	if (panel->event_handler)
+		rc = panel->event_handler(panel, MDSS_EVENT_PANEL_ON, NULL);
 	if (rc) {
-		pr_err("resource request for dma on failed\n");
+		pr_err("fail to turn on the panel\n");
+		goto on_error;
+	}
+	rc = mdp3_ctrl_res_req_clk(mfd, 1);
+	if (rc) {
+		pr_err("fail to request mdp clk resource\n");
 		goto on_error;
 	}
 
@@ -304,16 +326,9 @@
 	rc = mdp3_ctrl_intf_init(mfd, mdp3_session->intf);
 	if (rc) {
 		pr_err("display interface init failed\n");
-		goto on_error;
-	}
 
-	panel = mdp3_session->panel;
 
-	if (panel->event_handler)
-		rc = panel->event_handler(panel, MDSS_EVENT_PANEL_ON, NULL);
 
-	if (rc) {
-		pr_err("fail to turn on the panel\n");
 		goto on_error;
 	}
 
@@ -348,26 +363,31 @@
 	mutex_lock(&mdp3_session->lock);
 
 	if (!mdp3_session->status) {
-		pr_info("fb%d is off already", mfd->index);
+		pr_debug("fb%d is off already", mfd->index);
 		goto off_error;
 	}
 
-	panel = mdp3_session->panel;
-	if (panel->event_handler)
-		rc = panel->event_handler(panel, MDSS_EVENT_PANEL_OFF, NULL);
-
-	if (rc)
-		pr_err("fail to turn off the panel\n");
+	pr_debug("mdp3_ctrl_off stop mdp3 dma engine\n");
 
 	rc = mdp3_session->dma->stop(mdp3_session->dma, mdp3_session->intf);
 
 	if (rc)
 		pr_err("fail to stop the MDP3 dma\n");
 
-	rc = mdp3_ctrl_res_req_dma(mfd, 0);
+	pr_debug("mdp3_ctrl_off stop dsi panel and controller\n");
+	panel = mdp3_session->panel;
+	if (panel->event_handler)
+		rc = panel->event_handler(panel, MDSS_EVENT_PANEL_OFF, NULL);
 	if (rc)
-		pr_err("resource release  for dma on failed\n");
+		pr_err("fail to turn off the panel\n");
 
+	pr_debug("mdp3_ctrl_off release bus and clock\n");
+	rc = mdp3_ctrl_res_req_bus(mfd, 0);
+	if (rc)
+		pr_err("mdp bus resource release failed\n");
+	rc = mdp3_ctrl_res_req_clk(mfd, 0);
+	if (rc)
+		pr_err("mdp clock resource release failed\n");
 off_error:
 	mdp3_session->status = 0;
 
diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h
index 763c7f6..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;
@@ -73,12 +71,13 @@
 	u32 irq_mask;
 	u32 irq_ena;
 	u32 irq_buzy;
+	u32 has_bwc;
+	u32 has_decimation;
 
 	u32 mdp_irq_mask;
 	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..c3957c5 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -1431,6 +1431,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 +1465,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 baedd03..2f09fee 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -330,7 +330,6 @@
 			hw->hw_ndx, mdss_res->mdp_irq_mask,
 			mdss_res->mdp_hist_irq_mask);
 	} else {
-		mdss_irq_handlers[hw->hw_ndx] = NULL;
 		mdss_res->irq_mask &= ~ndx_bit;
 		if (mdss_res->irq_mask == 0) {
 			mdss_res->irq_ena = false;
@@ -622,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,
@@ -935,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",
@@ -1508,6 +1476,10 @@
 		&data);
 	mdata->rot_block_size = (!rc ? data : 128);
 
+	mdata->has_bwc = of_property_read_bool(pdev->dev.of_node,
+					       "qcom,mdss-has-bwc");
+	mdata->has_decimation = of_property_read_bool(pdev->dev.of_node,
+		"qcom,mdss-has-decimation");
 	return 0;
 }
 
@@ -1569,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);
 
@@ -1668,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 175a07f..d1fdbab 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -38,6 +38,7 @@
 #define MAX_PLANES		4
 #define MAX_DOWNSCALE_RATIO	4
 #define MAX_UPSCALE_RATIO	20
+#define MAX_DECIMATION		4
 
 #define C3_ALPHA	3	/* alpha */
 #define C2_R_Cr		2	/* R/Cr */
@@ -128,6 +129,7 @@
 	u16 width;
 	u16 height;
 	u32 dst_format;
+	bool is_secure;
 
 	u32 bus_ab_quota;
 	u32 bus_ib_quota;
@@ -268,6 +270,8 @@
 
 	u16 img_width;
 	u16 img_height;
+	u8 horz_deci;
+	u8 vert_deci;
 	struct mdss_mdp_img_rect src;
 	struct mdss_mdp_img_rect dst;
 
@@ -287,6 +291,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;
@@ -451,6 +456,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 03a33cd..abec9b9 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -289,6 +289,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;
@@ -1084,14 +1085,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);
@@ -1235,6 +1228,7 @@
 {
 	struct mdss_mdp_ctl *ctl;
 	struct mdss_mdp_mixer *mixer;
+	int i;
 
 	if (!pipe)
 		return -EINVAL;
@@ -1258,7 +1252,12 @@
 
 	if (params_changed) {
 		mixer->params_changed++;
-		mixer->stage_pipe[pipe->mixer_stage] = pipe;
+		for (i = 0; i < MDSS_MDP_MAX_STAGE; i++) {
+			if (i == pipe->mixer_stage)
+				mixer->stage_pipe[i] = pipe;
+			else if (mixer->stage_pipe[i] == pipe)
+				mixer->stage_pipe[i] = NULL;
+		}
 	}
 
 	if (pipe->type == MDSS_MDP_PIPE_TYPE_DMA)
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
index d50f47e..5221106 100644
--- a/drivers/video/msm/mdss/mdss_mdp_hwio.h
+++ b/drivers/video/msm/mdss/mdss_mdp_hwio.h
@@ -190,8 +190,7 @@
 #define MDSS_MDP_REG_SSPP_CURRENT_SRC1_ADDR		0x0A8
 #define MDSS_MDP_REG_SSPP_CURRENT_SRC2_ADDR		0x0AC
 #define MDSS_MDP_REG_SSPP_CURRENT_SRC3_ADDR		0x0B0
-#define MDSS_MDP_REG_SSPP_LINE_SKIP_STEP_C03		0x0B4
-#define MDSS_MDP_REG_SSPP_LINE_SKIP_STEP_C12		0x0B8
+#define MDSS_MDP_REG_SSPP_DECIMATION_CONFIG		0x0B4
 
 #define MDSS_MDP_REG_VIG_OP_MODE			0x200
 #define MDSS_MDP_REG_VIG_QSEED2_CONFIG			0x204
@@ -349,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 3cce4f9..48bab7f 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -98,8 +98,20 @@
 		return -EOVERFLOW;
 	}
 
+	if (req->horz_deci || req->vert_deci) {
+		if (!mdata->has_decimation) {
+			pr_err("No Decimation in MDP V=%x\n", mdata->mdp_rev);
+			return -EINVAL;
+		} else if ((req->horz_deci > MAX_DECIMATION) ||
+				(req->vert_deci > MAX_DECIMATION))  {
+			pr_err("Invalid decimation factors horz=%d vert=%d\n",
+					req->horz_deci, req->vert_deci);
+			return -EINVAL;
+		}
+	}
+
 	if (!(req->flags & MDSS_MDP_ROT_ONLY)) {
-		u32 dst_w, dst_h;
+		u32 src_w, src_h, dst_w, dst_h;
 
 		if ((CHECK_BOUNDS(req->dst_rect.x, req->dst_rect.w, xres) ||
 		     CHECK_BOUNDS(req->dst_rect.y, req->dst_rect.h, yres))) {
@@ -117,27 +129,36 @@
 			dst_h = req->dst_rect.h;
 		}
 
-		if ((req->src_rect.w * MAX_UPSCALE_RATIO) < dst_w) {
+		src_w = req->src_rect.w >> req->horz_deci;
+		src_h = req->src_rect.h >> req->vert_deci;
+
+		if (src_w > MAX_MIXER_WIDTH) {
+			pr_err("invalid source width=%d HDec=%d\n",
+					req->src_rect.w, req->horz_deci);
+			return -EINVAL;
+		}
+
+		if ((src_w * MAX_UPSCALE_RATIO) < dst_w) {
 			pr_err("too much upscaling Width %d->%d\n",
 			       req->src_rect.w, req->dst_rect.w);
 			return -EINVAL;
 		}
 
-		if ((req->src_rect.h * MAX_UPSCALE_RATIO) < dst_h) {
+		if ((src_h * MAX_UPSCALE_RATIO) < dst_h) {
 			pr_err("too much upscaling. Height %d->%d\n",
 			       req->src_rect.h, req->dst_rect.h);
 			return -EINVAL;
 		}
 
-		if (req->src_rect.w > (dst_w * MAX_DOWNSCALE_RATIO)) {
-			pr_err("too much downscaling. Width %d->%d\n",
-			       req->src_rect.w, req->dst_rect.w);
+		if (src_w > (dst_w * MAX_DOWNSCALE_RATIO)) {
+			pr_err("too much downscaling. Width %d->%d H Dec=%d\n",
+			       src_w, req->dst_rect.w, req->horz_deci);
 			return -EINVAL;
 		}
 
-		if (req->src_rect.h > (dst_h * MAX_DOWNSCALE_RATIO)) {
-			pr_err("too much downscaling. Height %d->%d\n",
-			       req->src_rect.h, req->dst_rect.h);
+		if (src_h > (dst_h * MAX_DOWNSCALE_RATIO)) {
+			pr_err("too much downscaling. Height %d->%d V Dec=%d\n",
+			       src_h, req->dst_rect.h, req->vert_deci);
 			return -EINVAL;
 		}
 
@@ -176,6 +197,7 @@
 	struct mdss_mdp_rotator_session *rot;
 	struct mdss_mdp_format_params *fmt;
 	int ret = 0;
+	u32 bwc_enabled;
 
 	pr_debug("rot ctl=%u req id=%x\n", mdp5_data->ctl->num, req->id);
 
@@ -212,7 +234,14 @@
 	rot->flags = req->flags & (MDP_ROT_90 | MDP_FLIP_LR | MDP_FLIP_UD |
 				   MDP_SECURE_OVERLAY_SESSION);
 
-	rot->bwc_mode = (req->flags & MDP_BWC_EN) ? 1 : 0;
+	bwc_enabled = req->flags & MDP_BWC_EN;
+	if (bwc_enabled  &&  !mdp5_data->mdata->has_bwc) {
+		pr_err("BWC is not supported in MDP version %x\n",
+			mdp5_data->mdata->mdp_rev);
+		rot->bwc_mode = 0;
+	} else {
+		rot->bwc_mode = bwc_enabled ? 1 : 0;
+	}
 	rot->format = fmt->format;
 	rot->img_width = req->src.width;
 	rot->img_height = req->src.height;
@@ -248,6 +277,7 @@
 	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 	struct mdp_histogram_start_req hist;
 	int ret;
+	u32 bwc_enabled;
 
 	if (mdp5_data->ctl == NULL)
 		return -ENODEV;
@@ -344,8 +374,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,
@@ -356,8 +386,15 @@
 	}
 
 	pipe->flags = req->flags;
-	pipe->bwc_mode = pipe->mixer->rotator_mode ?
-		0 : (req->flags & MDP_BWC_EN ? 1 : 0) ;
+	bwc_enabled = req->flags & MDP_BWC_EN;
+	if (bwc_enabled  &&  !mdp5_data->mdata->has_bwc) {
+		pr_err("BWC is not supported in MDP version %x\n",
+			mdp5_data->mdata->mdp_rev);
+		pipe->bwc_mode = 0;
+	} else {
+		pipe->bwc_mode = pipe->mixer->rotator_mode ?
+			0 : (bwc_enabled ? 1 : 0) ;
+	}
 	pipe->img_width = req->src.width & 0x3fff;
 	pipe->img_height = req->src.height & 0x3fff;
 	pipe->src.x = req->src_rect.x;
@@ -368,7 +405,8 @@
 	pipe->dst.y = req->dst_rect.y;
 	pipe->dst.w = req->dst_rect.w;
 	pipe->dst.h = req->dst_rect.h;
-
+	pipe->horz_deci = req->horz_deci;
+	pipe->vert_deci = req->vert_deci;
 	pipe->src_fmt = fmt;
 
 	pipe->mixer_stage = req->z_order;
@@ -436,6 +474,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;
@@ -445,6 +489,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,
@@ -694,15 +757,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);
 		}
 	}
 
@@ -778,12 +842,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);
@@ -793,6 +858,7 @@
 	else
 		ret = mdss_mdp_overlay_release(mfd, ndx);
 
+done:
 	mutex_unlock(&mdp5_data->ov_lock);
 
 	return ret;
@@ -934,14 +1000,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) {
@@ -954,6 +1020,7 @@
 		ret = mdss_mdp_overlay_queue(mfd, req);
 	}
 
+done:
 	mutex_unlock(&mdp5_data->ov_lock);
 
 	return ret;
@@ -1562,6 +1629,10 @@
 	caps->vig_pipes = mdata->nvig_pipes;
 	caps->rgb_pipes = mdata->nrgb_pipes;
 	caps->dma_pipes = mdata->ndma_pipes;
+	if (mdata->has_bwc)
+		caps->features |= MDP_BWC_EN;
+	if (mdata->has_decimation)
+		caps->features |= MDP_DECIMATION_EN;
 	return 0;
 }
 
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index d9b4483..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) {
@@ -126,11 +148,10 @@
 			return rc;
 		pr_debug("BWC SMP strides ystride0=%x ystride1=%x\n",
 			ps.ystride[0], ps.ystride[1]);
-	} else if ((mdata->mdp_rev >= MDSS_MDP_HW_REV_102) &&
-			pipe->src_fmt->is_yuv) {
+	} else if (mdata->has_decimation && pipe->src_fmt->is_yuv) {
 		ps.num_planes = 2;
-		ps.ystride[0] = pipe->src.w;
-		ps.ystride[1] = pipe->src.w;
+		ps.ystride[0] = pipe->src.w >> pipe->horz_deci;
+		ps.ystride[1] = pipe->src.h >> pipe->vert_deci;
 	} else {
 		rc = mdss_mdp_get_plane_sizes(pipe->src_fmt->format,
 			pipe->src.w, pipe->src.h, &ps, 0);
@@ -141,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)
@@ -172,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;
@@ -256,11 +279,12 @@
 	}
 
 	if (pipe) {
-		pr_info("type=%x   pnum=%d\n", pipe->type, pipe->num);
+		pr_debug("type=%x   pnum=%d\n", pipe->type, pipe->num);
 		mutex_init(&pipe->pp_res.hist.hist_mutex);
 		spin_lock_init(&pipe->pp_res.hist.hist_lock);
-	} else
+	} else {
 		pr_err("no %d type pipes available\n", type);
+	}
 
 	return pipe;
 }
@@ -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;
 }
 
@@ -376,6 +402,7 @@
 {
 	u32 img_size, src_size, src_xy, dst_size, dst_xy, ystride0, ystride1;
 	u32 width, height;
+	u32 decimation;
 
 	pr_debug("pnum=%d wh=%dx%d src={%d,%d,%d,%d} dst={%d,%d,%d,%d}\n",
 		   pipe->num, pipe->img_width, pipe->img_height,
@@ -396,6 +423,12 @@
 		height /= 2;
 	}
 
+	decimation = ((1 << pipe->horz_deci) - 1) << 8;
+	decimation |= ((1 << pipe->vert_deci) - 1);
+	if (decimation)
+		pr_debug("Image decimation h=%d v=%d\n",
+				pipe->horz_deci, pipe->vert_deci);
+
 	img_size = (height << 16) | width;
 	src_size = (pipe->src.h << 16) | pipe->src.w;
 	src_xy = (pipe->src.y << 16) | pipe->src.x;
@@ -418,6 +451,8 @@
 	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_OUT_XY, dst_xy);
 	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_YSTRIDE0, ystride0);
 	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_YSTRIDE1, ystride1);
+	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_DECIMATION_CONFIG,
+		decimation);
 
 	return 0;
 }
@@ -636,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 cf9a8b6..8bd5674 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -536,6 +536,7 @@
 	u32 chroma_sample;
 	u32 filter_mode;
 	struct mdss_data_type *mdata;
+	u32 src_w, src_h;
 
 	mdata = mdss_mdp_get_mdata();
 	if (mdata->mdp_rev >= MDSS_MDP_HW_REV_102 && pipe->src_fmt->is_yuv)
@@ -552,6 +553,9 @@
 		}
 	}
 
+	src_w = pipe->src.w >> pipe->horz_deci;
+	src_h = pipe->src.h >> pipe->vert_deci;
+
 	chroma_sample = pipe->src_fmt->chroma_sample;
 	if (pipe->flags & MDP_SOURCE_ROTATED_90) {
 		if (chroma_sample == MDSS_MDP_CHROMA_H1V2)
@@ -570,23 +574,22 @@
 	}
 
 	if ((pipe->src_fmt->is_yuv) &&
-		!((pipe->dst.w < pipe->src.w) || (pipe->dst.h < pipe->src.h))) {
+		!((pipe->dst.w < src_w) || (pipe->dst.h < src_h))) {
 		pp_sharp_config(pipe->base +
 		   MDSS_MDP_REG_VIG_QSEED2_SHARP,
 		   &pipe->pp_res.pp_sts,
 		   &pipe->pp_cfg.sharp_cfg);
 	}
 
-	if ((pipe->src.h != pipe->dst.h) ||
+	if ((src_h != pipe->dst.h) ||
 	    (pipe->pp_res.pp_sts.sharp_sts & PP_STS_ENABLE) ||
 	    (chroma_sample == MDSS_MDP_CHROMA_420) ||
 	    (chroma_sample == MDSS_MDP_CHROMA_H1V2)) {
-		pr_debug("scale y - src_h=%d dst_h=%d\n",
-				pipe->src.h, pipe->dst.h);
+		pr_debug("scale y - src_h=%d dst_h=%d\n", src_h, pipe->dst.h);
 
-		if ((pipe->src.h / MAX_DOWNSCALE_RATIO) > pipe->dst.h) {
+		if ((src_h / MAX_DOWNSCALE_RATIO) > pipe->dst.h) {
 			pr_err("too much downscaling height=%d->%d",
-			       pipe->src.h, pipe->dst.h);
+			       src_h, pipe->dst.h);
 			return -EINVAL;
 		}
 
@@ -594,11 +597,12 @@
 
 		if (pipe->type == MDSS_MDP_PIPE_TYPE_VIG) {
 			u32 chr_dst_h = pipe->dst.h;
-			if ((chroma_sample == MDSS_MDP_CHROMA_420) ||
-			    (chroma_sample == MDSS_MDP_CHROMA_H1V2))
+			if (!pipe->vert_deci &&
+			    ((chroma_sample == MDSS_MDP_CHROMA_420) ||
+			    (chroma_sample == MDSS_MDP_CHROMA_H1V2)))
 				chr_dst_h *= 2;	/* 2x upsample chroma */
 
-			if (pipe->src.h <= pipe->dst.h) {
+			if (src_h <= pipe->dst.h) {
 				scale_config |= /* G/Y, A */
 					(filter_mode << 10) |
 					(MDSS_MDP_SCALE_FILTER_NEAREST << 18);
@@ -607,7 +611,7 @@
 					(MDSS_MDP_SCALE_FILTER_PCMN << 10) |
 					(MDSS_MDP_SCALE_FILTER_PCMN << 18);
 
-			if (pipe->src.h <= chr_dst_h)
+			if (src_h <= chr_dst_h)
 				scale_config |= /* CrCb */
 					(MDSS_MDP_SCALE_FILTER_BIL << 14);
 			else
@@ -615,12 +619,12 @@
 					(MDSS_MDP_SCALE_FILTER_PCMN << 14);
 
 			phasey_step = mdss_mdp_scale_phase_step(
-				PHASE_STEP_SHIFT, pipe->src.h, chr_dst_h);
+				PHASE_STEP_SHIFT, src_h, chr_dst_h);
 
 			writel_relaxed(phasey_step, pipe->base +
 				MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPY);
 		} else {
-			if (pipe->src.h <= pipe->dst.h)
+			if (src_h <= pipe->dst.h)
 				scale_config |= /* RGB, A */
 					(MDSS_MDP_SCALE_FILTER_BIL << 10) |
 					(MDSS_MDP_SCALE_FILTER_NEAREST << 18);
@@ -631,19 +635,18 @@
 		}
 
 		phasey_step = mdss_mdp_scale_phase_step(
-			PHASE_STEP_SHIFT, pipe->src.h, pipe->dst.h);
+			PHASE_STEP_SHIFT, src_h, pipe->dst.h);
 	}
 
-	if ((pipe->src.w != pipe->dst.w) ||
+	if ((src_w != pipe->dst.w) ||
 	    (pipe->pp_res.pp_sts.sharp_sts & PP_STS_ENABLE) ||
 	    (chroma_sample == MDSS_MDP_CHROMA_420) ||
 	    (chroma_sample == MDSS_MDP_CHROMA_H2V1)) {
-		pr_debug("scale x - src_w=%d dst_w=%d\n",
-				pipe->src.w, pipe->dst.w);
+		pr_debug("scale x - src_w=%d dst_w=%d\n", src_w, pipe->dst.w);
 
-		if ((pipe->src.w / MAX_DOWNSCALE_RATIO) > pipe->dst.w) {
+		if ((src_w / MAX_DOWNSCALE_RATIO) > pipe->dst.w) {
 			pr_err("too much downscaling width=%d->%d",
-			       pipe->src.w, pipe->dst.w);
+			       src_w, pipe->dst.w);
 			return -EINVAL;
 		}
 
@@ -652,11 +655,12 @@
 		if (pipe->type == MDSS_MDP_PIPE_TYPE_VIG) {
 			u32 chr_dst_w = pipe->dst.w;
 
-			if ((chroma_sample == MDSS_MDP_CHROMA_420) ||
-			    (chroma_sample == MDSS_MDP_CHROMA_H2V1))
+			if (!pipe->horz_deci &&
+			    ((chroma_sample == MDSS_MDP_CHROMA_420) ||
+			    (chroma_sample == MDSS_MDP_CHROMA_H2V1)))
 				chr_dst_w *= 2;	/* 2x upsample chroma */
 
-			if (pipe->src.w <= pipe->dst.w) {
+			if (src_w <= pipe->dst.w) {
 				scale_config |= /* G/Y, A */
 					(filter_mode << 8) |
 					(MDSS_MDP_SCALE_FILTER_NEAREST << 16);
@@ -665,7 +669,7 @@
 					(MDSS_MDP_SCALE_FILTER_PCMN << 8) |
 					(MDSS_MDP_SCALE_FILTER_PCMN << 16);
 
-			if (pipe->src.w <= chr_dst_w)
+			if (src_w <= chr_dst_w)
 				scale_config |= /* CrCb */
 					(MDSS_MDP_SCALE_FILTER_BIL << 12);
 			else
@@ -673,11 +677,11 @@
 					(MDSS_MDP_SCALE_FILTER_PCMN << 12);
 
 			phasex_step = mdss_mdp_scale_phase_step(
-				PHASE_STEP_SHIFT, pipe->src.w, chr_dst_w);
+				PHASE_STEP_SHIFT, src_w, chr_dst_w);
 			writel_relaxed(phasex_step, pipe->base +
 				MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPX);
 		} else {
-			if (pipe->src.w <= pipe->dst.w)
+			if (src_w <= pipe->dst.w)
 				scale_config |= /* RGB, A */
 					(MDSS_MDP_SCALE_FILTER_BIL << 8) |
 					(MDSS_MDP_SCALE_FILTER_NEAREST << 16);
@@ -688,7 +692,7 @@
 		}
 
 		phasex_step = mdss_mdp_scale_phase_step(
-			PHASE_STEP_SHIFT, pipe->src.w, pipe->dst.w);
+			PHASE_STEP_SHIFT, src_w, pipe->dst.w);
 	}
 
 	writel_relaxed(scale_config, pipe->base +
@@ -1519,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;
@@ -1712,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;
 		}
@@ -1792,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;
 		}
@@ -2031,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;
@@ -2149,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++) {
@@ -2169,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++) {
@@ -2181,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/drivers/video/msm/mdss/mdss_qpic.c b/drivers/video/msm/mdss/mdss_qpic.c
index be02113..fa6bd3d 100644
--- a/drivers/video/msm/mdss/mdss_qpic.c
+++ b/drivers/video/msm/mdss/mdss_qpic.c
@@ -428,7 +428,7 @@
 					param[0]);
 				param++;
 				bytes_left -= 4;
-				space++;
+				space--;
 			} else if (bytes_left == 2) {
 				QPIC_OUTPW(QPIC_REG_QPIC_LCDC_FIFO_DATA_PORT0,
 					*(u16 *)param);
diff --git a/include/linux/ion.h b/include/linux/ion.h
index 88ad9a0..4983316 100644
--- a/include/linux/ion.h
+++ b/include/linux/ion.h
@@ -35,6 +35,7 @@
 	ION_HEAP_TYPE_SYSTEM,
 	ION_HEAP_TYPE_SYSTEM_CONTIG,
 	ION_HEAP_TYPE_CARVEOUT,
+	ION_HEAP_TYPE_CHUNK,
 	ION_HEAP_TYPE_CUSTOM, /* must be last so device specific heaps always
 				 are at the end of this enum */
 	ION_NUM_HEAPS,
@@ -44,8 +45,10 @@
 #define ION_HEAP_SYSTEM_CONTIG_MASK	(1 << ION_HEAP_TYPE_SYSTEM_CONTIG)
 #define ION_HEAP_CARVEOUT_MASK		(1 << ION_HEAP_TYPE_CARVEOUT)
 
+#define ION_NUM_HEAP_IDS		sizeof(unsigned int) * 8
+
 /**
- * heap flags - the lower 16 bits are used by core ion, the upper 16
+ * allocation flags - the lower 16 bits are used by core ion, the upper 16
  * bits are reserved for use by the heaps themselves.
  */
 #define ION_FLAG_CACHED 1		/* mappings of this buffer should be
@@ -74,8 +77,9 @@
 /**
  * struct ion_platform_heap - defines a heap in the given platform
  * @type:	type of the heap from ion_heap_type enum
- * @id:		unique identifier for heap.  When allocating (lower numbers
- * 		will be allocated from first)
+ * @id:		unique identifier for heap.  When allocating higher numbers
+ * 		will be allocated from first.  At allocation these are passed
+ *		as a bit mask and therefore can not exceed ION_NUM_HEAP_IDS.
  * @name:	used for debug purposes
  * @base:	base address of heap in physical memory if applicable
  * @size:	size of the heap in bytes if applicable
@@ -83,6 +87,10 @@
  * @has_outer_cache:    set to 1 if outer cache is used, 0 otherwise.
  * @extra_data:	Extra data specific to each heap type
  * @priv:	heap private data
+ * @align:	required alignment in physical memory if applicable
+ * @priv:	private info passed from the board file
+ *
+ * Provided by the board file.
  */
 struct ion_platform_heap {
 	enum ion_heap_type type;
@@ -93,6 +101,7 @@
 	enum ion_memory_types memory_type;
 	unsigned int has_outer_cache;
 	void *extra_data;
+	ion_phys_addr_t align;
 	void *priv;
 };
 
@@ -125,12 +134,12 @@
 
 /**
  * ion_client_create() -  allocate a client and returns it
- * @dev:	the global ion device
- * @heap_mask:	mask of heaps this client can allocate from
- * @name:	used for debugging
+ * @dev:		the global ion device
+ * @heap_type_mask:	mask of heaps this client can allocate from
+ * @name:		used for debugging
  */
 struct ion_client *ion_client_create(struct ion_device *dev,
-				     unsigned int heap_mask, const char *name);
+				     const char *name);
 
 /**
  * ion_client_destroy() -  free's a client and all it's handles
@@ -143,21 +152,22 @@
 
 /**
  * ion_alloc - allocate ion memory
- * @client:	the client
- * @len:	size of the allocation
- * @align:	requested allocation alignment, lots of hardware blocks have
- *		alignment requirements of some kind
- * @heap_mask:	mask of heaps to allocate from, if multiple bits are set
- *		heaps will be tried in order from lowest to highest order bit
- * @flags:	heap flags, the low 16 bits are consumed by ion, the high 16
- *		bits are passed on to the respective heap and can be heap
- *		custom
+ * @client:		the client
+ * @len:		size of the allocation
+ * @align:		requested allocation alignment, lots of hardware blocks
+ *			have alignment requirements of some kind
+ * @heap_id_mask:	mask of heaps to allocate from, if multiple bits are set
+ *			heaps will be tried in order from highest to lowest
+ *			id
+ * @flags:		heap flags, the low 16 bits are consumed by ion, the
+ *			high 16 bits are passed on to the respective heap and
+ *			can be heap custom
  *
  * Allocate memory in one of the heaps provided in heap mask and return
  * an opaque handle to it.
  */
 struct ion_handle *ion_alloc(struct ion_client *client, size_t len,
-			     size_t align, unsigned int heap_mask,
+			     size_t align, unsigned int heap_id_mask,
 			     unsigned int flags);
 
 /**
@@ -217,11 +227,19 @@
 void ion_unmap_kernel(struct ion_client *client, struct ion_handle *handle);
 
 /**
- * ion_share_dma_buf() - given an ion client, create a dma-buf fd
+ * ion_share_dma_buf() - share buffer as dma-buf
  * @client:	the client
  * @handle:	the handle
  */
-int ion_share_dma_buf(struct ion_client *client, struct ion_handle *handle);
+struct dma_buf *ion_share_dma_buf(struct ion_client *client,
+						struct ion_handle *handle);
+
+/**
+ * ion_share_dma_buf_fd() - given an ion client, create a dma-buf fd
+ * @client:	the client
+ * @handle:	the handle
+ */
+int ion_share_dma_buf_fd(struct ion_client *client, struct ion_handle *handle);
 
 /**
  * ion_import_dma_buf() - given an dma-buf fd from the ion exporter get handle
@@ -310,12 +328,12 @@
 
 /**
  * struct ion_allocation_data - metadata passed from userspace for allocations
- * @len:	size of the allocation
- * @align:	required alignment of the allocation
- * @heap_mask:	mask of heaps to allocate from
- * @flags:	flags passed to heap
- * @handle:	pointer that will be populated with a cookie to use to refer
- *		to this allocation
+ * @len:		size of the allocation
+ * @align:		required alignment of the allocation
+ * @heap_id_mask:	mask of heap ids to allocate from
+ * @flags:		flags passed to heap
+ * @handle:		pointer that will be populated with a cookie to use to 
+ *			refer to this allocation
  *
  * Provided by userspace as an argument to the ioctl
  */
diff --git a/include/linux/iopoll.h b/include/linux/iopoll.h
index 8aa758d..b882fe2 100644
--- a/include/linux/iopoll.h
+++ b/include/linux/iopoll.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
@@ -40,8 +40,12 @@
 	might_sleep_if(timeout_us); \
 	for (;;) { \
 		(val) = readl(addr); \
-		if ((cond) || (timeout_us && time_after(jiffies, timeout))) \
+		if (cond) \
 			break; \
+		if (timeout_us && time_after(jiffies, timeout)) { \
+			(val) = readl(addr); \
+			break; \
+		} \
 		if (sleep_us) \
 			usleep_range(DIV_ROUND_UP(sleep_us, 4), sleep_us); \
 	} \
diff --git a/include/linux/mfd/pm8xxx/pm8921-charger.h b/include/linux/mfd/pm8xxx/pm8921-charger.h
index 1c67b1e..5439fd1 100644
--- a/include/linux/mfd/pm8xxx/pm8921-charger.h
+++ b/include/linux/mfd/pm8xxx/pm8921-charger.h
@@ -165,6 +165,7 @@
 	unsigned int			warm_bat_chg_current;
 	unsigned int			cool_bat_voltage;
 	unsigned int			warm_bat_voltage;
+	int				hysteresis_temp;
 	unsigned int			(*get_batt_capacity_percent) (void);
 	int64_t				batt_id_min;
 	int64_t				batt_id_max;
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index db5c69c..f9e483c 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -173,6 +173,7 @@
 #define MDP_OV_PIPE_FORCE_DMA		0x00004000
 #define MDP_MEMORY_ID_TYPE_FB		0x00001000
 #define MDP_BWC_EN			0x00000400
+#define MDP_DECIMATION_EN		0x00000800
 #define MDP_TRANSP_NOP 0xffffffff
 #define MDP_ALPHA_NOP 0xff
 
@@ -406,7 +407,9 @@
 	uint32_t transp_mask;
 	uint32_t flags;
 	uint32_t id;
-	uint32_t user_data[8];
+	uint32_t user_data[7];
+	uint8_t horz_deci;
+	uint8_t vert_deci;
 	struct mdp_overlay_pp_params overlay_pp_cfg;
 };
 
@@ -696,6 +699,7 @@
 	uint8_t rgb_pipes;
 	uint8_t vig_pipes;
 	uint8_t dma_pipes;
+	uint32_t features;
 };
 
 struct msmfb_metadata {
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/kernel/sched/fair.c b/kernel/sched/fair.c
index b175073..7f4a46c 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -4626,7 +4626,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/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-dolby-dap-config.c b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
index b43c3bd..f77ec0f 100644
--- a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
+++ b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
@@ -305,6 +305,7 @@
 	}
 	if (idx >= NUM_DOLBY_ENDP_DEVICE) {
 		pr_err("%s: device is not set accordingly\n", __func__);
+		kfree(params_value);
 		return -EINVAL;
 	}
 	for (i = 0; i < DOLBY_ENDDEP_PARAM_LENGTH; i++) {
@@ -367,6 +368,7 @@
 						params_length);
 		if (rc) {
 			pr_err("%s: send dolby params failed\n", __func__);
+			kfree(params_value);
 			return -EINVAL;
 		}
 		for (i = 0; i < MAX_DOLBY_PARAMS; i++) {
@@ -584,7 +586,7 @@
 	if (rc) {
 		pr_err("%s: get parameters failed\n", __func__);
 		kfree(params_value);
-		rc = -EINVAL;
+		return -EINVAL;
 	}
 	update_params_value = (int *)params_value;
 	ucontrol->value.integer.value[0] = dolby_dap_params_get.device_id;
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 8257023..17934eb 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 */
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",