Merge "msm: clock-rpm: Remove last_set_khz/last_set_sleep_khz from rpm clk"
diff --git a/Documentation/devicetree/bindings/arm/arch_timer.txt b/Documentation/devicetree/bindings/arm/arch_timer.txt
index eb3986e..7851d53 100644
--- a/Documentation/devicetree/bindings/arm/arch_timer.txt
+++ b/Documentation/devicetree/bindings/arm/arch_timer.txt
@@ -6,7 +6,7 @@
 The timer is attached to a GIC to deliver its two per-processor
 interrupts (one for the secure mode, one for the non-secure mode).
 
-** Timer node properties:
+** CP15 Timer node properties:
 
 - compatible : Should be "arm,armv7-timer"
 
@@ -21,3 +21,52 @@
 		interrupts = <1 13 0xf08 1 14 0xf08>;
 		clock-frequency = <100000000>;
 	};
+
+** Memory mapped timer node properties:
+
+- compatible : Should at least contain "arm,armv7-timer-mem".
+
+- clock-frequency : The frequency of the main counter, in Hz. Optional.
+
+- reg : The control frame base address.
+
+Note that #address-cells, #size-cells, and ranges shall be present to ensure
+the CPU can address the frame's registers.
+
+Each timer node has up to 8 frame sub-nodes with the following properties:
+
+- frame-number: 0 to 7.
+
+- interrupts : Interrupt list for physical and virtual timers in that order.
+  The virtual timer interrupt is optional.
+
+- reg : The first and second view base addresses in that order. The second view
+  base address is optional.
+
+- status : "disabled" indicates the frame is not available for use. Optional.
+
+Example:
+
+	timer@f0000000 {
+		compatible = "arm,armv7-timer-mem";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		reg = <0xf0000000 0x1000>;
+		clock-frequency = <50000000>;
+
+		frame0@f0001000 {
+			frame-number = <0>
+			interrupts = <0 13 0x8>,
+				     <0 14 0x8>;
+			reg = <0xf0001000 0x1000>,
+			      <0xf0002000 0x1000>;
+		};
+
+		frame1@f0003000 {
+			frame-number = <1>
+			interrupts = <0 15 0x8>;
+			reg = <0xf0003000 0x1000>;
+			status = "disabled";
+		};
+	};
diff --git a/Documentation/devicetree/bindings/power/qpnp-charger.txt b/Documentation/devicetree/bindings/power/qpnp-charger.txt
index f5465a4..b8a39d3 100644
--- a/Documentation/devicetree/bindings/power/qpnp-charger.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-charger.txt
@@ -7,12 +7,12 @@
 Each of these peripherals are implemented as subnodes in the example at the
 end of this file.
 
-- qcom,chg-chgr:	Supports charging control and status
+- qcom,chgr:		Supports charging control and status
 			reporting.
-- qcom,chg-bat-if:	Battery status reporting such as presence,
+- qcom,bat-if:		Battery status reporting such as presence,
 			temperature reporting and voltage collapse
 			protection.
-- qcom,chg-buck:	Charger buck configuration and status
+- qcom,buck:		Charger buck configuration and status
 			reporting with regards to several regulation
 			loops such as vdd, ibat etc.
 - qcom,usb-chgpth:	USB charge path detection and input current
@@ -23,38 +23,38 @@
 			settings, comparator override features etc.
 
 Parent node required properties:
-- qcom,chg-vddmax-mv:			Target voltage of battery in mV.
-- qcom,chg-vddsafe-mv:			Maximum Vdd voltage in mV.
-- qcom,chg-vinmin-mv:			Minimum input voltage in mV.
-- qcom,chg-ibatmax-ma:			Maximum battery charge current in mA
-- qcom,chg-ibatsafe-ma:			Safety battery current setting
-- qcom,chg-thermal-mitigation:		Array of ibatmax values for different
+- qcom,vddmax-mv:			Target voltage of battery in mV.
+- qcom,vddsafe-mv:			Maximum Vdd voltage in mV.
+- qcom,vinmin-mv:			Minimum input voltage in mV.
+- qcom,ibatmax-ma:			Maximum battery charge current in mA
+- qcom,ibatsafe-ma:			Safety battery current setting
+- qcom,thermal-mitigation:		Array of ibatmax values for different
 					system thermal mitigation level.
 
 Parent node optional properties:
-- qcom,chg-ibatterm-ma:			Current at which charging is terminated when
+- qcom,ibatterm-ma:			Current at which charging is terminated when
 					the analog end of charge option is selected.
-- qcom,chg-maxinput-usb-ma:		Maximum input current USB.
-- qcom,chg-maxinput-dc-ma:		Maximum input current DC.
-- qcom,chg-vbatdet-delta-mv:		Battery charging resume delta.
-- qcom,chg-charging-disabled:		Set this property to disable charging
+- qcom,maxinput-usb-ma:			Maximum input current USB.
+- qcom,maxinput-dc-ma:			Maximum input current DC.
+- qcom,vbatdet-delta-mv:		Battery charging resume delta.
+- qcom,charging-disabled:		Set this property to disable charging
 					by default. This can then be overriden
 					writing the the module parameter
 					"charging_disabled".
-- qcom,chg-use-default-batt-values:	Set this flag to force reporting of
+- qcom,use-default-batt-values:		Set this flag to force reporting of
 					battery temperature of 250 decidegree
 					Celsius, state of charge to be 50%
 					and disable charging.
-- qcom,chg-warm-bat-decidegc:		Warm battery temperature in decidegC.
-- qcom,chg-cool-bat-decidegc:		Cool battery temperature in decidegC.
+- qcom,warm-bat-decidegc:		Warm battery temperature in decidegC.
+- qcom,cool-bat-decidegc:		Cool battery temperature in decidegC.
 					Note that if both warm and cool battery
 					temperatures are set, the corresponding
 					ibatmax and bat-mv properties are
 					required to be set.
-- qcom,chg-ibatmax-cool-ma:		Maximum cool battery charge current.
-- qcom,chg-ibatmax-warm-ma:		Maximum warm battery charge current.
-- qcom,chg-warm-bat-mv:			Warm temperature battery target voltage.
-- qcom,chg-cool-bat-mv:			Cool temperature battery target voltage.
+- qcom,ibatmax-cool-ma:			Maximum cool battery charge current.
+- qcom,ibatmax-warm-ma:			Maximum warm battery charge current.
+- qcom,warm-bat-mv:			Warm temperature battery target voltage.
+- qcom,cool-bat-mv:			Cool temperature battery target voltage.
 
 Sub node required structure:
 - A qcom,chg node must be a child of an SPMI node that has specified
@@ -77,13 +77,13 @@
 
 			qcom,usb-chgpth:
 			 - usbin-valid
-			qcom,chg-chgr:
+			qcom,chgr:
 			 - chg-done
 			 - chg-failed
 
 			The following interrupts are available:
 
-			qcom,chg-chgr:
+			qcom,chgr:
 			 - chg-done:		Triggers on charge completion.
 			 - chg-failed:		Notifies of charge failures.
 			 - fast-chg-on:		Notifies of fast charging state.
@@ -98,7 +98,7 @@
 						setting, can be used as
 						battery alarm.
 
-			qcom,chg-buck:
+			qcom,buck:
 			 - vdd-loop:		VDD loop change interrupt.
 			 - ibat-loop:		Ibat loop change interrupt.
 			 - ichg-loop:		Charge current loop change.
@@ -107,7 +107,7 @@
 			 - vref-ov:		Reference overvoltage interrupt.
 			 - vbat-ov:		Battery overvoltage interrupt.
 
-			qcom,chg-bat-if:
+			qcom,bat-if:
 			 - psi:			PMIC serial interface interrupt.
 			 - vcp-on:		Voltage collapse protection
 						status interrupt.
@@ -140,22 +140,22 @@
 		#address-cells = <1>;
 		#size-cells = <1>;
 
-		qcom,chg-vddmax-mv = <4200>;
-		qcom,chg-vddsafe-mv = <4200>;
-		qcom,chg-vinmin-mv = <4200>;
-		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-cool-bat-degc = <10>;
-		qcom,chg-cool-bat-mv = <4100>;
-		qcom,chg-ibatmax-warm-ma = <350>;
-		qcom,chg-warm-bat-degc = <45>;
-		qcom,chg-warm-bat-mv = <4100>;
-		qcom,chg-ibatmax-cool-ma = <350>;
-		qcom,chg-vbatdet-delta-mv = <60>;
+		qcom,vddmax-mv = <4200>;
+		qcom,vddsafe-mv = <4200>;
+		qcom,vinmin-mv = <4200>;
+		qcom,ibatmax-ma = <1500>;
+		qcom,ibatterm-ma = <200>;
+		qcom,ibatsafe-ma = <1500>;
+		qcom,thermal-mitigation = <1500 700 600 325>;
+		qcom,cool-bat-degc = <10>;
+		qcom,cool-bat-mv = <4100>;
+		qcom,ibatmax-warm-ma = <350>;
+		qcom,warm-bat-degc = <45>;
+		qcom,warm-bat-mv = <4100>;
+		qcom,ibatmax-cool-ma = <350>;
+		qcom,vbatdet-delta-mv = <60>;
 
-		qcom,chg-chgr@1000 {
+		qcom,chgr@1000 {
 			reg = <0x1000 0x100>;
 			interrupts =	<0x0 0x10 0x0>,
 				<0x0 0x10 0x1>,
@@ -176,7 +176,7 @@
 						"vbat-det-lo";
 		};
 
-		qcom,chg-buck@1100 {
+		qcom,buck@1100 {
 			reg = <0x1100 0x100>;
 			interrupts =	<0x0 0x11 0x0>,
 					<0x0 0x11 0x1>,
@@ -195,7 +195,7 @@
 						"vbat-ov";
 		};
 
-		qcom,chg-bat-if@1200 {
+		qcom,bat-if@1200 {
 			reg = <0x1200 0x100>;
 			interrupts =	<0x0 0x12 0x0>,
 					<0x0 0x12 0x1>,
@@ -210,7 +210,7 @@
 						"batt-pres";
 		};
 
-		qcom,chg-usb-chgpth@1300 {
+		qcom,usb-chgpth@1300 {
 			reg = <0x1300 0x100>;
 			interrupts =	<0 0x13 0x0>,
 					<0 0x13 0x1>,
@@ -221,7 +221,7 @@
 						"chg-gone";
 		};
 
-		qcom,chg-dc-chgpth@1400 {
+		qcom,dc-chgpth@1400 {
 			reg = <0x1400 0x100>;
 			interrupts =	<0x0 0x14 0x0>,
 					<0x0 0x14 0x1>;
@@ -230,7 +230,7 @@
 						"coarse-det-dc";
 		};
 
-		qcom,chg-boost@1500 {
+		qcom,boost@1500 {
 			reg = <0x1500 0x100>;
 			interrupts =	<0x0 0x15 0x0>,
 					<0x0 0x15 0x1>;
@@ -239,7 +239,7 @@
 						"boost-pwr-ok";
 		};
 
-		qcom,chg-misc@1600 {
+		qcom,misc@1600 {
 			reg = <0x1600 0x100>;
 		};
 	};
diff --git a/Documentation/devicetree/bindings/sound/taiko_codec.txt b/Documentation/devicetree/bindings/sound/taiko_codec.txt
index ffea58f..777933a 100644
--- a/Documentation/devicetree/bindings/sound/taiko_codec.txt
+++ b/Documentation/devicetree/bindings/sound/taiko_codec.txt
@@ -35,6 +35,10 @@
  - qcom,cdc-vddcx-2-voltage: cx-2 supply's voltage level min and max in mV.
  - qcom,cdc-vddcx-2-current: cx-2 supply's max current in mA.
 
+ - qcom,cdc-static-supplies: List of supplies to be enabled prior to codec
+			     hardware probe.  Supplies in this list will be
+			     stay enabled.
+
  - qcom,cdc-micbias-ldoh-v - LDOH output in volts (should be 1.95 V and 3.00 V).
 
  - qcom,cdc-micbias-cfilt1-mv - cfilt1 output voltage in milli volts.
@@ -67,6 +71,11 @@
 			 values for 9.6MHZ mclk can be 2400000 Hz, 3200000 Hz
 			 and 4800000 Hz.  The values for 12.288MHz mclk can be
 			 3072200 Hz, 4096000 Hz and 6144000 Hz.
+
+ - qcom,cdc-on-demand-supplies: List of supplies which can be enabled
+				dynamically.
+				Supplies in this list are off by default.
+
 Example:
 
 taiko_codec {
@@ -103,6 +112,16 @@
 	qcom,cdc-vddcx-2-voltage = <1225000 1225000>;
 	qcom,cdc-vddcx-2-current = <5000>;
 
+	qcom,cdc-static-supplies = "cdc-vdd-buck",
+				   "cdc-vdd-tx-h",
+				   "cdc-vdd-rx-h",
+				   "cdc-vddpx-1",
+				   "cdc-vdd-a-1p2v",
+				   "cdc-vddcx-1",
+				   "cdc-vddcx-2";
+
+	com,cdc-on-demand-supplies = "cdc-vdd-spkdrv";
+
 	qcom,cdc-micbias-ldoh-v = <0x3>;
 	qcom,cdc-micbias-cfilt1-mv = <1800>;
 	qcom,cdc-micbias-cfilt2-mv = <2700>;
@@ -155,6 +174,10 @@
  - qcom,cdc-vddcx-2-voltage: cx-2 supply's voltage level min and max in mV.
  - qcom,cdc-vddcx-2-current: cx-2 supply's max current in mA.
 
+ - qcom,cdc-static-supplies: List of supplies to be enabled prior to codec
+			     hardware probe.  Supplies in this list will be
+			     stay enabled.
+
  - qcom,cdc-micbias-ldoh-v - LDOH output in volts (should be 1.95 V and 3.00 V).
 
  - qcom,cdc-micbias-cfilt1-mv - cfilt1 output voltage in milli volts.
@@ -179,6 +202,20 @@
  - qcom,cdc-mclk-clk-rate - Specifies the master clock rate in Hz required for
 			    codec.
 
+Optional properties:
+
+ - cdc-vdd-spkdrv-supply: phandle of spkdrv supply's regulator device tree node.
+ - qcom,cdc-vdd-spkdrv-voltage: spkdrv supply voltage level min and max in mV.
+ - qcom,cdc-vdd-spkdrv-current: spkdrv supply max current in mA.
+
+ - cdc-vdd-spkdrv-supply: phandle of spkdrv supply's regulator device tree node.
+ - qcom,cdc-vdd-spkdrv-voltage: spkdrv supply voltage level min and max in mV.
+ - qcom,cdc-vdd-spkdrv-current: spkdrv supply max current in mA.
+
+ - qcom,cdc-on-demand-supplies: List of supplies which can be enabled
+				dynamically.
+				Supplies in this list are off by default.
+
 Example:
 i2c@f9925000 {
 	cell-index = <3>;
@@ -228,6 +265,16 @@
 		qcom,cdc-vddcx-2-voltage = <1200000 1200000>;
 		qcom,cdc-vddcx-2-current = <10000>;
 
+		qcom,cdc-static-supplies = "cdc-vdd-buck",
+					   "cdc-vdd-tx-h",
+					   "cdc-vdd-rx-h",
+					   "cdc-vddpx-1",
+					   "cdc-vdd-a-1p2v",
+					   "cdc-vddcx-1",
+					   "cdc-vddcx-2";
+
+		com,cdc-on-demand-supplies = "cdc-vdd-spkdrv";
+
 		qcom,cdc-micbias-ldoh-v = <0x3>;
 		qcom,cdc-micbias-cfilt1-mv = <1800>;
 		qcom,cdc-micbias-cfilt2-mv = <2700>;
diff --git a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
index e394b56..c130b26 100644
--- a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
+++ b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
@@ -7,8 +7,8 @@
 
 Required properties:
 - compatible: "wcnss_wlan"
-- reg: offset and length of the register set for the device. The pair
-  corresponds to PRONTO.
+- reg: physical address and length of the register set for the device.
+- reg-names: "wcnss_mmio", "wcnss_fiq"
 - interupts: Pronto to Apps interrupts for tx done and rx pending.
 - qcom,pronto-vddmx-supply: regulator to supply pronto pll.
 - qcom,pronto-vddcx-supply: regulator to supply WLAN/BT/FM digital module.
@@ -25,8 +25,9 @@
 
     qcom,wcnss-wlan@fb000000 {
         compatible = "qcom,wcnss_wlan";
-        reg = <0xfb000000 0x280000>;
-        reg-names = "wcnss_mmio";
+        reg = <0xfb000000 0x280000>,
+              <0xf9011008 0x04>;
+        reg-names = "wcnss_mmio", "wcnss_fiq";
         interrupts = <0 145 0 0 146 0>;
         interrupt-names = "wcnss_wlantx_irq", "wcnss_wlanrx_irq";
 
diff --git a/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
index c52b7dd..c0c9107 100644
--- a/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
@@ -38,7 +38,7 @@
 		qcom,mdss-pan-dsi-stream = <0>;
 		qcom,mdss-pan-dsi-mdp-tr = <0x0>;
 		qcom,mdss-pan-dsi-dma-tr = <0x04>;
-		qcom,mdss-pan-frame-rate = <60>;
+		qcom,mdss-pan-dsi-frame-rate = <60>;
 		qcom,panel-phy-regulatorSettings = [07 09 03 00  /* Regualotor settings */
 						    20 00 01];
 		qcom,panel-phy-timingSettings = [7d 25 1d 00 37 33
diff --git a/arch/arm/boot/dts/dsi-panel-orise-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-orise-720p-video.dtsi
index 7bd95e7..448d357 100644
--- a/arch/arm/boot/dts/dsi-panel-orise-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-orise-720p-video.dtsi
@@ -36,7 +36,7 @@
 		qcom,mdss-pan-dsi-stream = <0>;
 		qcom,mdss-pan-dsi-mdp-tr = <0x0>;
 		qcom,mdss-pan-dsi-dma-tr = <0x04>;
-		qcom,mdss-pan-frame-rate = <60>;
+		qcom,mdss-pan-dsi-frame-rate = <60>;
 		qcom,panel-phy-regulatorSettings = [03 01 01 00  /* Regualotor settings */
 						    20 00 01];
 		qcom,panel-phy-timingSettings = [69 29 1f 00 55 55
diff --git a/arch/arm/boot/dts/dsi-panel-sim-video.dtsi b/arch/arm/boot/dts/dsi-panel-sim-video.dtsi
index 98074c8..9a734a0 100644
--- a/arch/arm/boot/dts/dsi-panel-sim-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-sim-video.dtsi
@@ -37,7 +37,7 @@
 		qcom,mdss-pan-dsi-stream = <0>;
 		qcom,mdss-pan-dsi-mdp-tr = <0x04>;
 		qcom,mdss-pan-dsi-dma-tr = <0x04>;
-		qcom,mdss-pan-frame-rate = <60>;
+		qcom,mdss-pan-dsi-frame-rate = <60>;
 		qcom,panel-on-cmds = [32 01 00 00 00 02 00 00];
 		qcom,on-cmds-dsi-state = "DSI_LP_MODE";
 		qcom,panel-off-cmds = [22 01 00 00 00 02 00 00];
diff --git a/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
index 42f6033..2937cde 100644
--- a/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
@@ -40,7 +40,7 @@
 		qcom,mdss-pan-dsi-stream = <0>;
 		qcom,mdss-pan-dsi-mdp-tr = <0x0>;
 		qcom,mdss-pan-dsi-dma-tr = <0x04>;
-		qcom,mdss-pan-frame-rate = <60>;
+		qcom,mdss-pan-dsi-frame-rate = <60>;
 		qcom,panel-phy-regulatorSettings = [07 09 03 00  /* Regualotor settings */
 						    20 00 01];
 		qcom,panel-phy-timingSettings = [b0 23 1b 00 94 93
diff --git a/arch/arm/boot/dts/msm-pm8226.dtsi b/arch/arm/boot/dts/msm-pm8226.dtsi
index f702abb..161b580 100644
--- a/arch/arm/boot/dts/msm-pm8226.dtsi
+++ b/arch/arm/boot/dts/msm-pm8226.dtsi
@@ -56,16 +56,16 @@
 			#size-cells = <1>;
 			status = "disabled";
 
-			qcom,chg-vddmax-mv = <4200>;
-			qcom,chg-vddsafe-mv = <4200>;
-			qcom,chg-vinmin-mv = <4200>;
-			qcom,chg-vbatdet-mv = <4100>;
-			qcom,chg-ibatmax-ma = <1500>;
-			qcom,chg-ibatterm-ma = <200>;
-			qcom,chg-ibatsafe-ma = <1500>;
-			qcom,chg-thermal-mitigation = <1500 700 600 325>;
+			qcom,vddmax-mv = <4200>;
+			qcom,vddsafe-mv = <4200>;
+			qcom,vinmin-mv = <4200>;
+			qcom,vbatdet-mv = <4100>;
+			qcom,ibatmax-ma = <1500>;
+			qcom,ibatterm-ma = <200>;
+			qcom,ibatsafe-ma = <1500>;
+			qcom,thermal-mitigation = <1500 700 600 325>;
 
-			qcom,chg-chgr@1000 {
+			qcom,chgr@1000 {
 				status = "disabled";
 				reg = <0x1000 0x100>;
 				interrupts =	<0x0 0x10 0x0>,
@@ -87,7 +87,7 @@
 							"chg-done";
 			};
 
-			qcom,chg-buck@1100 {
+			qcom,buck@1100 {
 				status = "disabled";
 				reg = <0x1100 0x100>;
 				interrupts =	<0x0 0x11 0x0>,
@@ -107,7 +107,7 @@
 							"vdd-loop";
 			};
 
-			qcom,chg-bat-if@1200 {
+			qcom,bat-if@1200 {
 				status = "disabled";
 				reg = <0x1200 0x100>;
 				interrupts =	<0x0 0x12 0x0>,
@@ -124,7 +124,7 @@
 
 			};
 
-			qcom,chg-usb-chgpth@1300 {
+			qcom,usb-chgpth@1300 {
 				status = "disabled";
 				reg = <0x1300 0x100>;
 				interrupts =	<0 0x13 0x0>,
@@ -136,7 +136,7 @@
 							"chg-gone";
 			};
 
-			qcom,chg-boost@1500 {
+			qcom,boost@1500 {
 				status = "disabled";
 				reg = <0x1500 0x100>;
 				interrupts =	<0x0 0x15 0x0>,
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index 1881311..21606e2 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -171,21 +171,21 @@
 			#size-cells = <1>;
 			status = "disabled";
 
-			qcom,chg-vddmax-mv = <4200>;
-			qcom,chg-vddsafe-mv = <4200>;
-			qcom,chg-vinmin-mv = <4200>;
-			qcom,chg-ibatmax-ma = <1500>;
-			qcom,chg-ibatsafe-ma = <1500>;
-			qcom,chg-thermal-mitigation = <1500 700 600 325>;
-			qcom,chg-cool-bat-decidegc = <100>;
-			qcom,chg-cool-bat-mv = <4100>;
-			qcom,chg-ibatmax-warm-ma = <350>;
-			qcom,chg-warm-bat-decidegc = <450>;
-			qcom,chg-warm-bat-mv = <4100>;
-			qcom,chg-ibatmax-cool-ma = <350>;
-			qcom,chg-vbatdet-delta-mv = <350>;
+			qcom,vddmax-mv = <4200>;
+			qcom,vddsafe-mv = <4200>;
+			qcom,vinmin-mv = <4200>;
+			qcom,ibatmax-ma = <1500>;
+			qcom,ibatsafe-ma = <1500>;
+			qcom,thermal-mitigation = <1500 700 600 325>;
+			qcom,cool-bat-decidegc = <100>;
+			qcom,cool-bat-mv = <4100>;
+			qcom,ibatmax-warm-ma = <350>;
+			qcom,warm-bat-decidegc = <450>;
+			qcom,warm-bat-mv = <4100>;
+			qcom,ibatmax-cool-ma = <350>;
+			qcom,vbatdet-delta-mv = <350>;
 
-			qcom,chg-chgr@1000 {
+			qcom,chgr@1000 {
 				status = "disabled";
 				reg = <0x1000 0x100>;
 				interrupts =	<0x0 0x10 0x0>,
@@ -207,7 +207,7 @@
 							"chg-done";
 			};
 
-			qcom,chg-buck@1100 {
+			qcom,buck@1100 {
 				status = "disabled";
 				reg = <0x1100 0x100>;
 				interrupts =	<0x0 0x11 0x0>,
@@ -227,7 +227,7 @@
 							"vdd-loop";
 			};
 
-			qcom,chg-bat-if@1200 {
+			qcom,bat-if@1200 {
 				status = "disabled";
 				reg = <0x1200 0x100>;
 				interrupts =	<0x0 0x12 0x0>,
@@ -244,7 +244,7 @@
 
 			};
 
-			qcom,chg-usb-chgpth@1300 {
+			qcom,usb-chgpth@1300 {
 				status = "disabled";
 				reg = <0x1300 0x100>;
 				interrupts =	<0 0x13 0x0>,
@@ -256,7 +256,7 @@
 							"chg-gone";
 			};
 
-			qcom,chg-dc-chgpth@1400 {
+			qcom,dc-chgpth@1400 {
 				status = "disabled";
 				reg = <0x1400 0x100>;
 				interrupts =	<0x0 0x14 0x0>,
@@ -266,7 +266,7 @@
 							"dcin-valid";
 			};
 
-			qcom,chg-boost@1500 {
+			qcom,boost@1500 {
 				status = "disabled";
 				reg = <0x1500 0x100>;
 				interrupts =	<0x0 0x15 0x0>,
diff --git a/arch/arm/boot/dts/msm8226-cdp.dts b/arch/arm/boot/dts/msm8226-cdp.dts
index bf2ab4f..510bb7d 100644
--- a/arch/arm/boot/dts/msm8226-cdp.dts
+++ b/arch/arm/boot/dts/msm8226-cdp.dts
@@ -272,6 +272,6 @@
 };
 
 &pm8226_chg {
-	qcom,chg-charging-disabled;
-	qcom,chg-use-default-batt-values;
+	qcom,charging-disabled;
+	qcom,use-default-batt-values;
 };
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index 16a7177..f8a4e31 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -65,6 +65,65 @@
 		clock-frequency = <19200000>;
 	};
 
+	timer@f9020000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		compatible = "arm,armv7-timer-mem";
+		reg = <0xf9020000 0x1000>;
+		clock-frequency = <19200000>;
+
+		frame@f9021000 {
+			frame-number = <0>;
+			interrupts = <0 8 0x4>,
+				     <0 7 0x4>;
+			reg = <0xf9021000 0x1000>,
+			      <0xf9022000 0x1000>;
+		};
+
+		frame@f9023000 {
+			frame-number = <1>;
+			interrupts = <0 9 0x4>;
+			reg = <0xf9023000 0x1000>;
+			status = "disabled";
+		};
+
+		frame@f9024000 {
+			frame-number = <2>;
+			interrupts = <0 10 0x4>;
+			reg = <0xf9024000 0x1000>;
+			status = "disabled";
+		};
+
+		frame@f9025000 {
+			frame-number = <3>;
+			interrupts = <0 11 0x4>;
+			reg = <0xf9025000 0x1000>;
+			status = "disabled";
+		};
+
+		frame@f9026000 {
+			frame-number = <4>;
+			interrupts = <0 12 0x4>;
+			reg = <0xf9026000 0x1000>;
+			status = "disabled";
+		};
+
+		frame@f9027000 {
+			frame-number = <5>;
+			interrupts = <0 13 0x4>;
+			reg = <0xf9027000 0x1000>;
+			status = "disabled";
+		};
+
+		frame@f9028000 {
+			frame-number = <6>;
+			interrupts = <0 14 0x4>;
+			reg = <0xf9028000 0x1000>;
+			status = "disabled";
+		};
+	};
+
 	qcom,vidc@fdc00000 {
 		compatible = "qcom,msm-vidc";
 		reg = <0xfdc00000 0xff000>;
@@ -234,6 +293,12 @@
 			qcom,cdc-vdd-cx-voltage = <1200000 1200000>;
 			qcom,cdc-vdd-cx-current = <10000>;
 
+			qcom,cdc-static-supplies = "cdc-vdd-buck",
+						   "cdc-vdd-h",
+						   "cdc-vdd-px",
+						   "cdc-vdd-a-1p2v",
+						   "cdc-vdd-cx";
+
 			qcom,cdc-micbias-ldoh-v = <0x3>;
 			qcom,cdc-micbias-cfilt1-mv = <1800>;
 			qcom,cdc-micbias-cfilt2-mv = <1800>;
@@ -412,8 +477,9 @@
 
 	qcom,wcnss-wlan@fb000000 {
 		compatible = "qcom,wcnss_wlan";
-		reg = <0xfb000000 0x280000>;
-		reg-names = "wcnss_mmio";
+		reg = <0xfb000000 0x280000>,
+			<0xf9011008 0x04>;
+		reg-names = "wcnss_mmio", "wcnss_fiq";
 		interrupts = <0 145 0 0 146 0>;
 		interrupt-names = "wcnss_wlantx_irq", "wcnss_wlanrx_irq";
 
@@ -950,23 +1016,23 @@
 &pm8226_chg {
 	status = "ok";
 
-	qcom,chg-chgr@1000 {
+	qcom,chgr@1000 {
 		status = "ok";
 	};
 
-	qcom,chg-buck@1100 {
+	qcom,buck@1100 {
 		status = "ok";
 	};
 
-	qcom,chg-bat-if@1200 {
+	qcom,bat-if@1200 {
 		status = "ok";
 	};
 
-	qcom,chg-usb-chgpth@1300 {
+	qcom,usb-chgpth@1300 {
 		status = "ok";
 	};
 
-	qcom,chg-boost@1500 {
+	qcom,boost@1500 {
 		status = "ok";
 	};
 
diff --git a/arch/arm/boot/dts/msm8610-ion.dtsi b/arch/arm/boot/dts/msm8610-ion.dtsi
index 848a6f5..41b58da 100644
--- a/arch/arm/boot/dts/msm8610-ion.dtsi
+++ b/arch/arm/boot/dts/msm8610-ion.dtsi
@@ -35,14 +35,6 @@
 			qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
 			qcom,memory-reservation-size = <0x100000>;
 		};
-
-		qcom,ion-heap@28 { /* AUDIO HEAP */
-			compatible = "qcom,msm-ion-reserve";
-			reg = <28>;
-			qcom,heap-align = <0x1000>;
-			qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
-			qcom,memory-reservation-size = <0x314000>;
-		};
 	};
 };
 
diff --git a/arch/arm/boot/dts/msm8974-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
index 91d3bc0..0319128 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-cdp.dtsi
@@ -235,6 +235,19 @@
 				<85 512 40000 160000>;
         };
 
+	wlan0: qca,wlan {
+		compatible = "qca,ar6004-hsic";
+		qcom,msm-bus,name = "wlan";
+		qcom,msm-bus,num-cases = <5>;
+		qcom,msm-bus,active-only = <0>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+				<85 512 0 0>,
+				<85 512 40000 160000>,
+				<85 512 40000 320000>,
+				<85 512 40000 480000>,
+				<85 512 40000 640000>;
+	};
 };
 
 &spmi_bus {
@@ -381,23 +394,23 @@
 &pm8941_chg {
 	status = "ok";
 
-	qcom,chg-chgr@1000 {
+	qcom,chgr@1000 {
 		status = "ok";
 	};
 
-	qcom,chg-buck@1100 {
+	qcom,buck@1100 {
 		status = "ok";
 	};
 
-	qcom,chg-usb-chgpth@1300 {
+	qcom,usb-chgpth@1300 {
 		status = "ok";
 	};
 
-	qcom,chg-dc-chgpth@1400 {
+	qcom,dc-chgpth@1400 {
 		status = "ok";
 	};
 
-	qcom,chg-boost@1500 {
+	qcom,boost@1500 {
 		status = "ok";
 	};
 
diff --git a/arch/arm/boot/dts/msm8974-fluid.dtsi b/arch/arm/boot/dts/msm8974-fluid.dtsi
index de370e7..79e6371 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-fluid.dtsi
@@ -355,27 +355,27 @@
 	status = "ok";
 	qcom,chg-charging-disabled;
 
-	qcom,chg-chgr@1000 {
+	qcom,chgr@1000 {
 		status = "ok";
 	};
 
-	qcom,chg-buck@1100 {
+	qcom,buck@1100 {
 		status = "ok";
 	};
 
-	qcom,chg-bat-if@1200 {
+	qcom,bat-if@1200 {
 		status = "ok";
 	};
 
-	qcom,chg-usb-chgpth@1300 {
+	qcom,usb-chgpth@1300 {
 		status = "ok";
 	};
 
-	qcom,chg-dc-chgpth@1400 {
+	qcom,dc-chgpth@1400 {
 		status = "ok";
 	};
 
-	qcom,chg-boost@1500 {
+	qcom,boost@1500 {
 		status = "ok";
 	};
 
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index 0ae20a0..be890b1 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -736,25 +736,25 @@
 &pm8941_chg {
 	status = "ok";
 
-	qcom,chg-charging-disabled;
+	qcom,charging-disabled;
 
-	qcom,chg-chgr@1000 {
+	qcom,chgr@1000 {
 		status = "ok";
 	};
 
-	qcom,chg-buck@1100 {
+	qcom,buck@1100 {
 		status = "ok";
 	};
 
-	qcom,chg-usb-chgpth@1300 {
+	qcom,usb-chgpth@1300 {
 		status = "ok";
 	};
 
-	qcom,chg-dc-chgpth@1400 {
+	qcom,dc-chgpth@1400 {
 		status = "ok";
 	};
 
-	qcom,chg-boost@1500 {
+	qcom,boost@1500 {
 		status = "ok";
 	};
 
diff --git a/arch/arm/boot/dts/msm8974-mtp.dtsi b/arch/arm/boot/dts/msm8974-mtp.dtsi
index a81fc20..cd83668 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-mtp.dtsi
@@ -338,27 +338,27 @@
 	status = "ok";
 	qcom,chg-charging-disabled;
 
-	qcom,chg-chgr@1000 {
+	qcom,chgr@1000 {
 		status = "ok";
 	};
 
-	qcom,chg-buck@1100 {
+	qcom,buck@1100 {
 		status = "ok";
 	};
 
-	qcom,chg-bat-if@1200 {
+	qcom,bat-if@1200 {
 		status = "ok";
 	};
 
-	qcom,chg-usb-chgpth@1300 {
+	qcom,usb-chgpth@1300 {
 		status = "ok";
 	};
 
-	qcom,chg-dc-chgpth@1400 {
+	qcom,dc-chgpth@1400 {
 		status = "ok";
 	};
 
-	qcom,chg-boost@1500 {
+	qcom,boost@1500 {
 		status = "ok";
 	};
 
diff --git a/arch/arm/boot/dts/msm8974-v1-fluid.dts b/arch/arm/boot/dts/msm8974-v1-fluid.dts
index 8f2ef31..8ab24df 100644
--- a/arch/arm/boot/dts/msm8974-v1-fluid.dts
+++ b/arch/arm/boot/dts/msm8974-v1-fluid.dts
@@ -23,7 +23,7 @@
 };
 
 &pm8941_chg {
-	qcom,chg-charging-disabled;
+	qcom,charging-disabled;
 };
 
 &sdcc1 {
diff --git a/arch/arm/boot/dts/msm8974-v1-mtp.dts b/arch/arm/boot/dts/msm8974-v1-mtp.dts
index 6cb9f09..09ea84b 100644
--- a/arch/arm/boot/dts/msm8974-v1-mtp.dts
+++ b/arch/arm/boot/dts/msm8974-v1-mtp.dts
@@ -22,5 +22,5 @@
 };
 
 &pm8941_chg {
-	qcom,chg-charging-disabled;
+	qcom,charging-disabled;
 };
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 273c677..a7ea5c3 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -84,6 +84,66 @@
 		clock-frequency = <19200000>;
 	};
 
+	timer@f9020000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		compatible = "arm,armv7-timer-mem";
+		reg = <0xf9020000 0x1000>;
+		clock-frequency = <19200000>;
+
+		frame@f9021000 {
+			frame-number = <0>;
+			interrupts = <0 8 0x4>,
+				     <0 7 0x4>;
+			reg = <0xf9021000 0x1000>,
+			      <0xf9022000 0x1000>;
+		};
+
+		frame@f9023000 {
+			frame-number = <1>;
+			interrupts = <0 9 0x4>;
+			reg = <0xf9023000 0x1000>;
+			status = "disabled";
+		};
+
+		frame@f9024000 {
+			frame-number = <2>;
+			interrupts = <0 10 0x4>;
+			reg = <0xf9024000 0x1000>;
+			status = "disabled";
+		};
+
+		frame@f9025000 {
+			frame-number = <3>;
+			interrupts = <0 11 0x4>;
+			reg = <0xf9025000 0x1000>;
+			status = "disabled";
+		};
+
+		frame@f9026000 {
+			frame-number = <4>;
+			interrupts = <0 12 0x4>;
+			reg = <0xf9026000 0x1000>;
+			status = "disabled";
+		};
+
+		frame@f9027000 {
+			frame-number = <5>;
+			interrupts = <0 13 0x4>;
+			reg = <0xf9027000 0x1000>;
+			status = "disabled";
+		};
+
+		frame@f9028000 {
+			frame-number = <6>;
+			interrupts = <0 14 0x4>;
+			reg = <0xf9028000 0x1000>;
+			status = "disabled";
+		};
+	};
+
+
 	qcom,mpm2-sleep-counter@fc4a3000 {
 		compatible = "qcom,mpm2-sleep-counter";
 		reg = <0xfc4a3000 0x1000>;
@@ -573,6 +633,14 @@
 			qcom,cdc-vddcx-2-voltage = <1225000 1225000>;
 			qcom,cdc-vddcx-2-current = <10000>;
 
+			qcom,cdc-static-supplies = "cdc-vdd-buck",
+						   "cdc-vdd-tx-h",
+						   "cdc-vdd-rx-h",
+						   "cdc-vddpx-1",
+						   "cdc-vdd-a-1p2v",
+						   "cdc-vddcx-1",
+						   "cdc-vddcx-2";
+
 			qcom,cdc-micbias-ldoh-v = <0x3>;
 			qcom,cdc-micbias-cfilt1-mv = <1800>;
 			qcom,cdc-micbias-cfilt2-mv = <2700>;
@@ -1058,8 +1126,9 @@
 
 	qcom,wcnss-wlan@fb000000 {
 		compatible = "qcom,wcnss_wlan";
-		reg = <0xfb000000 0x280000>;
-		reg-names = "wcnss_mmio";
+		reg = <0xfb000000 0x280000>,
+			<0xf9011008 0x04>;
+		reg-names = "wcnss_mmio", "wcnss_fiq";
 		interrupts = <0 145 0 0 146 0>;
 		interrupt-names = "wcnss_wlantx_irq", "wcnss_wlanrx_irq";
 
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index 0e98aa8..7faa07d 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -66,6 +66,72 @@
 		clock-frequency = <19200000>;
 	};
 
+	timer@f9020000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		compatible = "arm,armv7-timer-mem";
+		reg = <0xf9020000 0x1000>;
+		clock-frequency = <19200000>;
+
+		frame@f9021000 {
+			frame-number = <0>;
+			interrupts = <0 7 0x4>,
+				     <0 6 0x4>;
+			reg = <0xf9021000 0x1000>,
+			      <0xf9022000 0x1000>;
+		};
+
+		frame@f9023000 {
+			frame-number = <1>;
+			interrupts = <0 8 0x4>;
+			reg = <0xf9023000 0x1000>;
+			status = "disabled";
+		};
+
+		frame@f9024000 {
+			frame-number = <2>;
+			interrupts = <0 9 0x4>;
+			reg = <0xf9024000 0x1000>;
+			status = "disabled";
+		};
+
+		frame@f9025000 {
+			frame-number = <3>;
+			interrupts = <0 10 0x4>;
+			reg = <0xf9025000 0x1000>;
+			status = "disabled";
+		};
+
+		frame@f9026000 {
+			frame-number = <4>;
+			interrupts = <0 11 0x4>;
+			reg = <0xf9026000 0x1000>;
+			status = "disabled";
+		};
+
+		frame@f9027000 {
+			frame-number = <5>;
+			interrupts = <0 12 0x4>;
+			reg = <0xf9027000 0x1000>;
+			status = "disabled";
+		};
+
+		frame@f9028000 {
+			frame-number = <6>;
+			interrupts = <0 13 0x4>;
+			reg = <0xf9028000 0x1000>;
+			status = "disabled";
+		};
+
+		frame@f9029000 {
+			frame-number = <7>;
+			interrupts = <0 14 0x4>;
+			reg = <0xf9029000 0x1000>;
+			status = "disabled";
+		};
+	};
+
 	qcom,sps@f9980000 {
 		compatible = "qcom,msm_sps";
 		reg = <0xf9984000 0x15000>,
@@ -505,6 +571,14 @@
 			qcom,cdc-vddcx-2-voltage = <1200000 1200000>;
 			qcom,cdc-vddcx-2-current = <10000>;
 
+			qcom,cdc-static-supplies = "cdc-vdd-buck",
+						   "cdc-vdd-tx-h",
+						   "cdc-vdd-rx-h",
+						   "cdc-vddpx-1",
+						   "cdc-vdd-a-1p2v",
+						   "cdc-vddcx-1",
+						   "cdc-vddcx-2";
+
 			qcom,cdc-micbias-ldoh-v = <0x3>;
 			qcom,cdc-micbias-cfilt1-mv = <1800>;
 			qcom,cdc-micbias-cfilt2-mv = <2700>;
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 7e835f6..3291919 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -329,7 +329,6 @@
 CONFIG_QPNP_PWM=y
 CONFIG_QPNP_POWER_ON=y
 CONFIG_MSM_IOMMU=y
-CONFIG_MSM_IOMMU_PMON=y
 CONFIG_CORESIGHT=y
 CONFIG_CORESIGHT_TMC=y
 CONFIG_CORESIGHT_TPIU=y
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index 3b92171..705275c 100644
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -1097,8 +1097,9 @@
 			 ARRAY_SIZE(msm_blsp2_uart7_configs));
 	msm_gpiomux_install(wcnss_5wire_interface,
 				ARRAY_SIZE(wcnss_5wire_interface));
-	msm_gpiomux_install_nowrite(ath_gpio_configs,
-				ARRAY_SIZE(ath_gpio_configs));
+	if (of_board_is_liquid())
+		msm_gpiomux_install_nowrite(ath_gpio_configs,
+					ARRAY_SIZE(ath_gpio_configs));
 	msm_gpiomux_install(msm8974_slimbus_config,
 			ARRAY_SIZE(msm8974_slimbus_config));
 
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index 4a716fc..87572da 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -2550,6 +2550,8 @@
 
 	CLK_LOOKUP("iface_clk",  gcc_blsp1_ahb_clk.c, "f991f000.serial"),
 	CLK_LOOKUP("core_clk",  gcc_blsp1_uart3_apps_clk.c, "f991f000.serial"),
+	CLK_LOOKUP("iface_clk",  gcc_blsp1_ahb_clk.c, "f991e000.serial"),
+	CLK_LOOKUP("core_clk",  gcc_blsp1_uart2_apps_clk.c, "f991e000.serial"),
 
 	CLK_LOOKUP("dfab_clk", pnoc_sps_clk.c, "msm_sps"),
 	CLK_LOOKUP("bus_clk",  pnoc_qseecom_clk.c, "qseecom"),
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index c42da92..b96924f 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -4823,6 +4823,11 @@
 	CLK_LOOKUP("bus_clk",      gcc_ce1_axi_clk.c,     "qseecom"),
 	CLK_LOOKUP("core_clk_src", ce1_clk_src.c,         "qseecom"),
 
+	CLK_LOOKUP("ce_drv_core_clk",     gcc_ce2_clk.c,         "qseecom"),
+	CLK_LOOKUP("ce_drv_iface_clk",    gcc_ce2_ahb_clk.c,     "qseecom"),
+	CLK_LOOKUP("ce_drv_bus_clk",      gcc_ce2_axi_clk.c,     "qseecom"),
+	CLK_LOOKUP("ce_drv_core_clk_src", ce2_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"),
diff --git a/arch/arm/mach-msm/clock-9625.c b/arch/arm/mach-msm/clock-9625.c
index 0d97401..4984255 100644
--- a/arch/arm/mach-msm/clock-9625.c
+++ b/arch/arm/mach-msm/clock-9625.c
@@ -2018,12 +2018,6 @@
 	 */
 	clk_prepare_enable(&cxo_a_clk_src.c);
 
-	/*
-	 * TODO: This call is to prevent sending 0Hz to rpm to turn off pnoc.
-	 * Needs to remove this after vote of pnoc from sdcc driver is ready.
-	 */
-	clk_prepare_enable(&pnoc_msmbus_a_clk.c);
-
 	/* Set rates for single-rate clocks. */
 	clk_set_rate(&usb_hs_system_clk_src.c,
 			usb_hs_system_clk_src.freq_tbl[0].freq_hz);
diff --git a/arch/arm/mach-msm/gdsc.c b/arch/arm/mach-msm/gdsc.c
index 6665d66..a07b13d 100644
--- a/arch/arm/mach-msm/gdsc.c
+++ b/arch/arm/mach-msm/gdsc.c
@@ -38,7 +38,7 @@
 #define EN_FEW_WAIT_VAL		(0x8 << 16)
 #define CLK_DIS_WAIT_VAL	(0x2 << 12)
 
-#define TIMEOUT_US		100
+#define TIMEOUT_US		1000
 
 struct gdsc {
 	struct regulator_dev	*rdev;
diff --git a/arch/arm/mach-msm/include/mach/iommu_perfmon.h b/arch/arm/mach-msm/include/mach/iommu_perfmon.h
index dcae83b..dc4671c 100644
--- a/arch/arm/mach-msm/include/mach/iommu_perfmon.h
+++ b/arch/arm/mach-msm/include/mach/iommu_perfmon.h
@@ -63,6 +63,7 @@
  * @iommu_dev:  pointer to iommu device
  * @ops:        iommu access operations pointer.
  * @hw_ops:     iommu pm hw access operations pointer.
+ * @always_on:  1 if iommu is always on, 0 otherwise.
  */
 struct iommu_info {
 	const char *iommu_name;
@@ -71,6 +72,7 @@
 	struct device *iommu_dev;
 	struct iommu_access_ops *ops;
 	struct iommu_pm_hw_ops *hw_ops;
+	unsigned int always_on;
 };
 
 /**
diff --git a/arch/arm/mach-msm/include/mach/scm.h b/arch/arm/mach-msm/include/mach/scm.h
index 4258dbd..72eb999 100644
--- a/arch/arm/mach-msm/include/mach/scm.h
+++ b/arch/arm/mach-msm/include/mach/scm.h
@@ -24,6 +24,7 @@
 #define SCM_SVC_MP			0xC
 #define SCM_SVC_CRYPTO			0xA
 #define SCM_SVC_DCVS			0xD
+#define SCM_SVC_ES			0x10
 #define SCM_SVC_TZSCHEDULER		0xFC
 
 #ifdef CONFIG_MSM_SCM
diff --git a/arch/arm/mach-msm/krait-regulator.c b/arch/arm/mach-msm/krait-regulator.c
index b931ee6..af2fbab 100644
--- a/arch/arm/mach-msm/krait-regulator.c
+++ b/arch/arm/mach-msm/krait-regulator.c
@@ -133,6 +133,7 @@
 #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
@@ -1309,6 +1310,8 @@
 
 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
@@ -1335,6 +1338,23 @@
 		| 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/rpm_log.c b/arch/arm/mach-msm/rpm_log.c
index a2c74a5..53d5752 100644
--- a/arch/arm/mach-msm/rpm_log.c
+++ b/arch/arm/mach-msm/rpm_log.c
@@ -203,11 +203,14 @@
 	struct msm_rpm_log_buffer *buf;
 
 	buf = file->private_data;
-	pdata = buf->pdata;
-	if (!pdata)
-		return -EINVAL;
+
 	if (!buf)
 		return -ENOMEM;
+
+	pdata = buf->pdata;
+
+	if (!pdata)
+		return -EINVAL;
 	if (!buf->data)
 		return -ENOMEM;
 	if (!bufu || count < 0)
diff --git a/block/row-iosched.c b/block/row-iosched.c
index c8ba344..e71f6af 100644
--- a/block/row-iosched.c
+++ b/block/row-iosched.c
@@ -200,9 +200,9 @@
 	struct request			*pending_urgent_rq;
 	int				last_served_ioprio_class;
 
-#define	ROW_REG_STARVATION_TOLLERANCE	50
+#define	ROW_REG_STARVATION_TOLLERANCE	5000
 	struct starvation_data		reg_prio_starvation;
-#define	ROW_LOW_STARVATION_TOLLERANCE	1000
+#define	ROW_LOW_STARVATION_TOLLERANCE	10000
 	struct starvation_data		low_prio_starvation;
 
 	unsigned int			cycle_flags;
diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c
index 2557983..0383d8f 100644
--- a/drivers/bluetooth/hci_ath.c
+++ b/drivers/bluetooth/hci_ath.c
@@ -39,6 +39,8 @@
 #include <linux/platform_device.h>
 #include <linux/gpio.h>
 #include <linux/of_gpio.h>
+#include <linux/proc_fs.h>
+
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 
@@ -47,8 +49,10 @@
 #include <mach/msm_serial_hs.h>
 #endif
 
-unsigned int enableuartsleep = 1;
-module_param(enableuartsleep, uint, 0644);
+static int enableuartsleep = 1;
+module_param(enableuartsleep, int, 0644);
+MODULE_PARM_DESC(enableuartsleep, "Enable Atheros Sleep Protocol");
+
 /*
  * Global variables
  */
@@ -62,6 +66,9 @@
 /** Global state flags */
 static unsigned long flags;
 
+/** To Check LPM is enabled */
+static bool is_lpm_enabled;
+
 /** Workqueue to respond to change in hostwake line */
 static void wakeup_host_work(struct work_struct *work);
 
@@ -72,6 +79,8 @@
 /** Lock for state transitions */
 static spinlock_t rw_lock;
 
+#define PROC_DIR	"bluetooth/sleep"
+
 #define POLARITY_LOW 0
 #define POLARITY_HIGH 1
 
@@ -80,8 +89,11 @@
 	unsigned ext_wake;			/* wake up device */
 	unsigned host_wake_irq;
 	int irq_polarity;
+	struct uart_port *uport;
 };
 
+struct work_struct ws_sleep;
+
 /* 1 second timeout */
 #define TX_TIMER_INTERVAL  1
 
@@ -99,23 +111,24 @@
 
 	struct sk_buff_head txq;
 	struct work_struct ctxtsw;
-	struct work_struct ws_sleep;
 };
 
-static void hsuart_serial_clock_on(struct tty_struct *tty)
+static void hsuart_serial_clock_on(struct uart_port *port)
 {
-	struct uart_state *state = tty->driver_data;
-	struct uart_port *port = state->uart_port;
 	BT_DBG("");
-	msm_hs_request_clock_on(port);
+	if (port)
+		msm_hs_request_clock_on(port);
+	else
+		BT_INFO("Uart has not voted for Clock ON");
 }
 
-static void hsuart_serial_clock_off(struct tty_struct *tty)
+static void hsuart_serial_clock_off(struct uart_port *port)
 {
-	struct uart_state *state = tty->driver_data;
-	struct uart_port *port = state->uart_port;
 	BT_DBG("");
-	msm_hs_request_clock_off(port);
+	if (port)
+		msm_hs_request_clock_off(port);
+	else
+		BT_INFO("Uart has not voted for Clock OFF");
 }
 
 static void modify_timer_task(void)
@@ -127,31 +140,31 @@
 
 }
 
-static int ath_wakeup_ar3k(struct tty_struct *tty)
+static int ath_wakeup_ar3k(void)
 {
 	int status = 0;
 	if (test_bit(BT_TXEXPIRED, &flags)) {
-		hsuart_serial_clock_on(tty);
-		BT_INFO("wakeup device\n");
+		hsuart_serial_clock_on(bsi->uport);
+		BT_DBG("wakeup device\n");
 		gpio_set_value(bsi->ext_wake, 0);
 		msleep(20);
 		gpio_set_value(bsi->ext_wake, 1);
 	}
-	modify_timer_task();
+	if (!is_lpm_enabled)
+		modify_timer_task();
 	return status;
 }
 
 static void wakeup_host_work(struct work_struct *work)
 {
-	struct ath_struct *ath =
-		container_of(work, struct ath_struct, ws_sleep);
 
-	BT_INFO("wake up host");
+	BT_DBG("wake up host");
 	if (test_bit(BT_SLEEPENABLE, &flags)) {
 		if (test_bit(BT_TXEXPIRED, &flags))
-			hsuart_serial_clock_on(ath->hu->tty);
+			hsuart_serial_clock_on(bsi->uport);
 	}
-	modify_timer_task();
+	if (!is_lpm_enabled)
+		modify_timer_task();
 }
 
 static void ath_hci_uart_work(struct work_struct *work)
@@ -159,16 +172,14 @@
 	int status;
 	struct ath_struct *ath;
 	struct hci_uart *hu;
-	struct tty_struct *tty;
 
 	ath = container_of(work, struct ath_struct, ctxtsw);
 
 	hu = ath->hu;
-	tty = hu->tty;
 
 	/* verify and wake up controller */
 	if (test_bit(BT_SLEEPENABLE, &flags))
-		status = ath_wakeup_ar3k(tty);
+		status = ath_wakeup_ar3k();
 	/* Ready to send Data */
 	clear_bit(HCI_UART_SENDING, &hu->tx_state);
 	hci_uart_tx_wakeup(hu);
@@ -176,15 +187,15 @@
 
 static irqreturn_t bluesleep_hostwake_isr(int irq, void *dev_id)
 {
-	/* schedule a tasklet to handle the change in the host wake line */
-	struct ath_struct *ath = (struct ath_struct *)dev_id;
-
-	schedule_work(&ath->ws_sleep);
+	/* schedule a work to global shared workqueue to handle
+	 * the change in the host wake line
+	 */
+	schedule_work(&ws_sleep);
 
 	return IRQ_HANDLED;
 }
 
-static int ath_bluesleep_gpio_config(struct ath_struct *ath, int on)
+static int ath_bluesleep_gpio_config(int on)
 {
 	int ret = 0;
 
@@ -232,16 +243,16 @@
 	/* Initialize timer */
 	init_timer(&tx_timer);
 	tx_timer.function = bluesleep_tx_timer_expire;
-	tx_timer.data = (u_long)ath->hu;
+	tx_timer.data = 0;
 
 	if (bsi->irq_polarity == POLARITY_LOW) {
 		ret = request_irq(bsi->host_wake_irq, bluesleep_hostwake_isr,
 				IRQF_DISABLED | IRQF_TRIGGER_FALLING,
-				"bluetooth hostwake", (void *)ath);
+				"bluetooth hostwake", NULL);
 	} else  {
 		ret = request_irq(bsi->host_wake_irq, bluesleep_hostwake_isr,
 				IRQF_DISABLED | IRQF_TRIGGER_RISING,
-				"bluetooth hostwake", (void *)ath);
+				"bluetooth hostwake", NULL);
 	}
 	if (ret  < 0) {
 		BT_ERR("Couldn't acquire BT_HOST_WAKE IRQ");
@@ -257,7 +268,7 @@
 	return 0;
 
 free_host_wake_irq:
-	free_irq(bsi->host_wake_irq, (void *)ath);
+	free_irq(bsi->host_wake_irq, NULL);
 delete_timer:
 	del_timer(&tx_timer);
 gpio_ext_wake:
@@ -268,26 +279,76 @@
 	return ret;
 }
 
+static int ath_lpm_start(void)
+{
+	BT_DBG("Start LPM mode");
+
+	if (!bsi) {
+		BT_ERR("HCIATH3K bluesleep info does not exist");
+		return -EIO;
+	}
+
+	bsi->uport = msm_hs_get_uart_port(0);
+	if (!bsi->uport) {
+		BT_ERR("UART Port is not available");
+		return -ENODEV;
+	}
+
+	INIT_WORK(&ws_sleep, wakeup_host_work);
+
+	if (ath_bluesleep_gpio_config(1) < 0) {
+		BT_ERR("HCIATH3K GPIO Config failed");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int ath_lpm_stop(void)
+{
+	BT_DBG("Stop LPM mode");
+	cancel_work_sync(&ws_sleep);
+
+	if (bsi) {
+		bsi->uport = NULL;
+		ath_bluesleep_gpio_config(0);
+	}
+
+	return 0;
+}
+
 /* Initialize protocol */
 static int ath_open(struct hci_uart *hu)
 {
 	struct ath_struct *ath;
+	struct uart_state *state;
 
 	BT_DBG("hu %p, bsi %p", hu, bsi);
 
-	if (!bsi)
+	if (!bsi) {
+		BT_ERR("HCIATH3K bluesleep info does not exist");
 		return -EIO;
+	}
 
 	ath = kzalloc(sizeof(*ath), GFP_ATOMIC);
-	if (!ath)
+	if (!ath) {
+		BT_ERR("HCIATH3K Memory not enough to init driver");
 		return -ENOMEM;
+	}
 
 	skb_queue_head_init(&ath->txq);
 
 	hu->priv = ath;
 	ath->hu = hu;
+	state = hu->tty->driver_data;
 
-	if (ath_bluesleep_gpio_config(ath, 1) < 0) {
+	if (!state) {
+		BT_ERR("HCIATH3K tty driver data does not exist");
+		return -ENXIO;
+	}
+	bsi->uport = state->uart_port;
+
+	if (ath_bluesleep_gpio_config(1) < 0) {
 		BT_ERR("HCIATH3K GPIO Config failed");
 		hu->priv = NULL;
 		kfree(ath);
@@ -300,7 +361,7 @@
 		modify_timer_task();
 	}
 	INIT_WORK(&ath->ctxtsw, ath_hci_uart_work);
-	INIT_WORK(&ath->ws_sleep, wakeup_host_work);
+	INIT_WORK(&ws_sleep, wakeup_host_work);
 	return 0;
 }
 
@@ -327,12 +388,13 @@
 
 	cancel_work_sync(&ath->ctxtsw);
 
-	cancel_work_sync(&ath->ws_sleep);
+	cancel_work_sync(&ws_sleep);
 
 	if (bsi)
-		ath_bluesleep_gpio_config(ath, 0);
+		ath_bluesleep_gpio_config(0);
 
 	hu->priv = NULL;
+	bsi->uport = NULL;
 	kfree(ath);
 
 	return 0;
@@ -423,14 +485,13 @@
 
 static void bluesleep_tx_timer_expire(unsigned long data)
 {
-	struct hci_uart *hu = (struct hci_uart *) data;
 
 	if (!test_bit(BT_SLEEPENABLE, &flags))
 		return;
 	BT_INFO("Tx timer expired\n");
 
 	set_bit(BT_TXEXPIRED, &flags);
-	hsuart_serial_clock_off(hu->tty);
+	hsuart_serial_clock_off(bsi->uport);
 }
 
 static struct hci_uart_proto athp = {
@@ -443,6 +504,88 @@
 	.flush = ath_flush,
 };
 
+static int lpm_enabled;
+
+static int bluesleep_lpm_set(const char *val, const struct kernel_param *kp)
+{
+	int ret;
+
+	ret = param_set_int(val, kp);
+
+	if (ret) {
+		BT_ERR("HCIATH3K: lpm enable parameter set failed");
+		return ret;
+	}
+
+	BT_DBG("lpm : %d", lpm_enabled);
+
+	if ((lpm_enabled == 0) && is_lpm_enabled) {
+		ath_lpm_stop();
+		clear_bit(BT_SLEEPENABLE, &flags);
+		is_lpm_enabled = false;
+	} else if ((lpm_enabled == 1) && !is_lpm_enabled) {
+		if (ath_lpm_start() < 0) {
+			BT_ERR("HCIATH3K LPM mode failed");
+			return -EIO;
+		}
+		set_bit(BT_SLEEPENABLE, &flags);
+		is_lpm_enabled = true;
+	} else {
+		BT_ERR("HCIATH3K invalid lpm value");
+		return -EINVAL;
+	}
+	return 0;
+
+}
+
+static struct kernel_param_ops bluesleep_lpm_ops = {
+	.set = bluesleep_lpm_set,
+	.get = param_get_int,
+};
+
+module_param_cb(ath_lpm, &bluesleep_lpm_ops,
+		&lpm_enabled, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(ath_lpm, "Enable Atheros LPM sleep Protocol");
+
+static int lpm_btwrite;
+
+static int bluesleep_lpm_btwrite(const char *val, const struct kernel_param *kp)
+{
+	int ret;
+
+	ret = param_set_int(val, kp);
+
+	if (ret) {
+		BT_ERR("HCIATH3K: lpm btwrite parameter set failed");
+		return ret;
+	}
+
+	BT_DBG("btwrite : %d", lpm_btwrite);
+	if (is_lpm_enabled) {
+		if (lpm_btwrite == 0) {
+			/*Setting TXEXPIRED bit to make it
+			compatible with current solution*/
+			set_bit(BT_TXEXPIRED, &flags);
+			hsuart_serial_clock_off(bsi->uport);
+		} else if (lpm_btwrite == 1) {
+			ath_wakeup_ar3k();
+			clear_bit(BT_TXEXPIRED, &flags);
+		} else {
+			BT_ERR("HCIATH3K invalid btwrite value");
+			return -EINVAL;
+		}
+	}
+	return 0;
+}
+
+static struct kernel_param_ops bluesleep_lpm_btwrite_ops = {
+	.set = bluesleep_lpm_btwrite,
+	.get = param_get_int,
+};
+
+module_param_cb(ath_btwrite, &bluesleep_lpm_btwrite_ops,
+		&lpm_btwrite, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(ath_lpm, "Assert/Deassert the sleep");
 
 static int bluesleep_populate_dt_pinfo(struct platform_device *pdev)
 {
@@ -581,5 +724,6 @@
 int __exit ath_deinit(void)
 {
 	platform_driver_unregister(&bluesleep_driver);
+
 	return hci_uart_unregister_proto(&athp);
 }
diff --git a/drivers/gpu/ion/ion_system_heap.c b/drivers/gpu/ion/ion_system_heap.c
index af7f04b..f3f627d 100644
--- a/drivers/gpu/ion/ion_system_heap.c
+++ b/drivers/gpu/ion/ion_system_heap.c
@@ -57,7 +57,7 @@
 			continue;
 		if (split_pages)
 			split_page(page, orders[i]);
-		info = kmap(page);
+		info = kmalloc(sizeof(struct page_info *), GFP_KERNEL);
 		info->page = page;
 		info->order = orders[i];
 		return info;
@@ -118,7 +118,7 @@
 			sg = sg_next(sg);
 		}
 		list_del(&info->list);
-		kunmap(page);
+		kfree(info);
 	}
 
 	dma_sync_sg_for_device(NULL, table->sgl, table->nents,
@@ -137,7 +137,7 @@
 		else
 			__free_pages(info->page, info->order);
 
-		kunmap(info->page);
+		kfree(info);
 	}
 	return -ENOMEM;
 }
diff --git a/drivers/iommu/msm_iommu_dev-v0.c b/drivers/iommu/msm_iommu_dev-v0.c
index 549800f..7ae0b21 100644
--- a/drivers/iommu/msm_iommu_dev-v0.c
+++ b/drivers/iommu/msm_iommu_dev-v0.c
@@ -414,6 +414,7 @@
 			pmon_info->iommu.ops = &iommu_access_ops_v0;
 			pmon_info->iommu.hw_ops = iommu_pm_get_hw_ops_v0();
 			pmon_info->iommu.iommu_name = drvdata->name;
+			pmon_info->iommu.always_on = 1;
 			ret = msm_iommu_pm_iommu_register(pmon_info);
 			if (ret) {
 				pr_err("%s iommu register fail\n",
diff --git a/drivers/iommu/msm_iommu_perfmon.c b/drivers/iommu/msm_iommu_perfmon.c
index fee8a4a..a11d794 100644
--- a/drivers/iommu/msm_iommu_perfmon.c
+++ b/drivers/iommu/msm_iommu_perfmon.c
@@ -90,6 +90,19 @@
 	return pos;
 }
 
+static int iommu_pm_event_class_supported(struct iommu_pmon *pmon,
+					  int event_class)
+{
+	unsigned int nevent_cls = pmon->nevent_cls_supported;
+	unsigned int i;
+
+	for (i = 0; i < nevent_cls; ++i) {
+		if (event_class == pmon->event_cls_supported[i])
+			return event_class;
+	}
+	return MSM_IOMMU_PMU_NO_EVENT_CLASS;
+}
+
 static const char *iommu_pm_find_event_class_name(int event_class)
 {
 	size_t array_len;
@@ -113,7 +126,8 @@
 	return event_class_name;
 }
 
-static int iommu_pm_find_event_class(const char *event_class_name)
+static int iommu_pm_find_event_class(struct iommu_pmon *pmon,
+				     const char *event_class_name)
 {
 	size_t array_len;
 	struct event_class *ptr;
@@ -134,6 +148,7 @@
 	}
 
 out:
+	event_class = iommu_pm_event_class_supported(pmon, event_class);
 	return event_class;
 }
 
@@ -389,11 +404,11 @@
 		rv = kstrtol(buf, 10, &value);
 		if (!rv) {
 			counter->current_event_class =
-				iommu_pm_find_event_class(
+				iommu_pm_find_event_class(pmon,
 					iommu_pm_find_event_class_name(value));
 		} else {
 			counter->current_event_class =
-						iommu_pm_find_event_class(buf);
+					iommu_pm_find_event_class(pmon, buf);
 	}	}
 
 	if (current_event_class != counter->current_event_class)
@@ -488,14 +503,17 @@
 		rv = kstrtoul(buf, 10, &cmd);
 		if (!rv && (cmd < 2)) {
 			if (pmon->enabled == 1 && cmd == 0) {
-				if (pmon->iommu_attach_count > 0)
+				if (pmon->iommu.always_on ||
+				    pmon->iommu_attach_count > 0)
 					iommu_pm_off(pmon);
 			} else if (pmon->enabled == 0 && cmd == 1) {
 				/* We can only turn on perf. monitoring if
-				 * iommu is attached. Delay turning on perf.
-				 * monitoring until we are attached.
+				 * iommu is attached (if not always on).
+				 * Delay turning on perf. monitoring until
+				 * we are attached.
 				 */
-				if (pmon->iommu_attach_count > 0)
+				if (pmon->iommu.always_on ||
+				    pmon->iommu_attach_count > 0)
 					iommu_pm_on(pmon);
 				else
 					pmon->enabled = 1;
@@ -788,9 +806,9 @@
 		++pmon->iommu_attach_count;
 		if (pmon->iommu_attach_count == 1) {
 			/* If perf. mon was enabled before we attached we do
-			 * the actual after we attach.
+			 * the actual enabling after we attach.
 			 */
-			if (pmon->enabled)
+			if (pmon->enabled && !pmon->iommu.always_on)
 				iommu_pm_on(pmon);
 		}
 		mutex_unlock(&pmon->lock);
@@ -805,9 +823,9 @@
 		mutex_lock(&pmon->lock);
 		if (pmon->iommu_attach_count == 1) {
 			/* If perf. mon is still enabled we have to disable
-			 * before we do the detach.
+			 * before we do the detach if iommu is not always on.
 			 */
-			if (pmon->enabled)
+			if (pmon->enabled && !pmon->iommu.always_on)
 				iommu_pm_off(pmon);
 		}
 		BUG_ON(pmon->iommu_attach_count == 0);
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index e011d8f..046faac 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -34,8 +34,6 @@
 #define SLIMBUS_PRESENT_TIMEOUT 100
 
 #define MAX_WCD9XXX_DEVICE	4
-#define TABLA_I2C_MODE	0x03
-#define SITAR_I2C_MODE	0x01
 #define CODEC_DT_MAX_PROP_SIZE   40
 #define WCD9XXX_I2C_GSBI_SLAVE_ID "3-000d"
 #define WCD9XXX_I2C_TOP_SLAVE_ADDR	0x0d
@@ -59,18 +57,9 @@
 	int mod_id;
 };
 
-static char *taiko_supplies[] = {
-	WCD9XXX_SUPPLY_BUCK_NAME, "cdc-vdd-tx-h", "cdc-vdd-rx-h", "cdc-vddpx-1",
-	"cdc-vdd-a-1p2v", "cdc-vddcx-1", "cdc-vddcx-2",
-};
-
-static char *tapan_supplies[] = {
-	WCD9XXX_SUPPLY_BUCK_NAME, "cdc-vdd-h", "cdc-vdd-px",
-	"cdc-vdd-a-1p2v", "cdc-vdd-cx"
-};
-
 static int wcd9xxx_dt_parse_vreg_info(struct device *dev,
-	struct wcd9xxx_regulator *vreg, const char *vreg_name);
+				      struct wcd9xxx_regulator *vreg,
+				      const char *vreg_name, bool ondemand);
 static int wcd9xxx_dt_parse_micbias_info(struct device *dev,
 	struct wcd9xxx_micbias_setting *micbias);
 static struct wcd9xxx_pdata *wcd9xxx_populate_dt_pdata(struct device *dev);
@@ -292,49 +281,60 @@
 	},
 };
 
-static struct wcd9xx_codec_type {
-	u8 byte[4];
-	struct mfd_cell *dev;
-	int size;
-	int num_irqs;
-	int version; /* -1 to retrive version from chip version register */
-	enum wcd9xxx_slim_slave_addr_type slim_slave_type;
-} wcd9xxx_codecs[] = {
+
+enum wcd9xxx_chipid_major {
+	TABLA_MAJOR = cpu_to_le16(0x100),
+	SITAR_MAJOR = cpu_to_le16(0x101),
+	TAIKO_MAJOR = cpu_to_le16(0x102),
+	TAPAN_MAJOR = cpu_to_le16(0x103),
+};
+
+static const struct wcd9xxx_codec_type wcd9xxx_codecs[] = {
 	{
-	 {0x2, 0x0, 0x0, 0x1}, tabla_devs, ARRAY_SIZE(tabla_devs),
-	 TABLA_NUM_IRQS, -1, WCD9XXX_SLIM_SLAVE_ADDR_TYPE_TABLA
+		TABLA_MAJOR, cpu_to_le16(0x1), tabla1x_devs,
+		ARRAY_SIZE(tabla1x_devs), TABLA_NUM_IRQS, -1,
+		WCD9XXX_SLIM_SLAVE_ADDR_TYPE_TABLA, 0x03,
 	},
 	{
-	 {0x1, 0x0, 0x0, 0x1}, tabla1x_devs, ARRAY_SIZE(tabla1x_devs),
-	 TABLA_NUM_IRQS, -1, WCD9XXX_SLIM_SLAVE_ADDR_TYPE_TABLA
-	},
-	{ /* wcd9320 version 1 */
-	 {0x0, 0x0, 0x2, 0x1}, taiko_devs, ARRAY_SIZE(taiko_devs),
-	  TAIKO_NUM_IRQS, 1, WCD9XXX_SLIM_SLAVE_ADDR_TYPE_TAIKO
-	},
-	{ /* wcd9320 version 2 */
-	 {0x1, 0x0, 0x2, 0x1}, taiko_devs, ARRAY_SIZE(taiko_devs),
-	 TAIKO_NUM_IRQS, 2, WCD9XXX_SLIM_SLAVE_ADDR_TYPE_TAIKO
+		TABLA_MAJOR, cpu_to_le16(0x2), tabla_devs,
+		ARRAY_SIZE(tabla_devs), TABLA_NUM_IRQS, -1,
+		WCD9XXX_SLIM_SLAVE_ADDR_TYPE_TABLA, 0x03
 	},
 	{
-	 {0x0, 0x0, 0x3, 0x1}, tapan_devs, ARRAY_SIZE(tapan_devs),
-	 TAPAN_NUM_IRQS, -1, WCD9XXX_SLIM_SLAVE_ADDR_TYPE_TAIKO
+		/* Siter version 1 has same major chip id with Tabla */
+		TABLA_MAJOR, cpu_to_le16(0x0), sitar_devs,
+		ARRAY_SIZE(sitar_devs), SITAR_NUM_IRQS, -1,
+		WCD9XXX_SLIM_SLAVE_ADDR_TYPE_TABLA, 0x01
 	},
 	{
-	 {0x1, 0x0, 0x3, 0x1}, tapan_devs, ARRAY_SIZE(tapan_devs),
-	 TAPAN_NUM_IRQS, -1, WCD9XXX_SLIM_SLAVE_ADDR_TYPE_TAIKO
+		SITAR_MAJOR, cpu_to_le16(0x1), sitar_devs,
+		ARRAY_SIZE(sitar_devs), SITAR_NUM_IRQS, -1,
+		WCD9XXX_SLIM_SLAVE_ADDR_TYPE_TABLA, 0x01
 	},
 	{
-	 {0x0, 0x0, 0x0, 0x1}, sitar_devs, ARRAY_SIZE(sitar_devs),
-	 SITAR_NUM_IRQS, -1, WCD9XXX_SLIM_SLAVE_ADDR_TYPE_TABLA
+		SITAR_MAJOR, cpu_to_le16(0x2), sitar_devs,
+		ARRAY_SIZE(sitar_devs), SITAR_NUM_IRQS, -1,
+		WCD9XXX_SLIM_SLAVE_ADDR_TYPE_TABLA, 0x01
 	},
 	{
-	 {0x1, 0x0, 0x1, 0x1}, sitar_devs, ARRAY_SIZE(sitar_devs),
-	 SITAR_NUM_IRQS, -1, WCD9XXX_SLIM_SLAVE_ADDR_TYPE_TABLA
+		TAIKO_MAJOR, cpu_to_le16(0x0), taiko_devs,
+		ARRAY_SIZE(taiko_devs), TAIKO_NUM_IRQS, 1,
+		WCD9XXX_SLIM_SLAVE_ADDR_TYPE_TAIKO, 0x01
 	},
 	{
-	 {0x2, 0x0, 0x1, 0x1}, sitar_devs, ARRAY_SIZE(sitar_devs),
-	 SITAR_NUM_IRQS, -1, WCD9XXX_SLIM_SLAVE_ADDR_TYPE_TABLA
+		TAIKO_MAJOR, cpu_to_le16(0x1), taiko_devs,
+		ARRAY_SIZE(taiko_devs), TAIKO_NUM_IRQS, 2,
+		WCD9XXX_SLIM_SLAVE_ADDR_TYPE_TAIKO, 0x01
+	},
+	{
+		TAPAN_MAJOR, cpu_to_le16(0x0), tapan_devs,
+		ARRAY_SIZE(tapan_devs), TAPAN_NUM_IRQS, -1,
+		WCD9XXX_SLIM_SLAVE_ADDR_TYPE_TAIKO, 0x03
+	},
+	{
+		TAPAN_MAJOR, cpu_to_le16(0x1), tapan_devs,
+		ARRAY_SIZE(tapan_devs), TAPAN_NUM_IRQS, -1,
+		WCD9XXX_SLIM_SLAVE_ADDR_TYPE_TAIKO, 0x03
 	},
 };
 
@@ -384,65 +384,80 @@
 		wcd9xxx->reset_gpio = 0;
 	}
 }
-static int wcd9xxx_check_codec_type(struct wcd9xxx *wcd9xxx,
-				    struct mfd_cell **wcd9xxx_dev,
-				    int *wcd9xxx_dev_size,
-				    int *wcd9xxx_dev_num_irqs)
+
+static const struct wcd9xxx_codec_type
+*wcd9xxx_check_codec_type(struct wcd9xxx *wcd9xxx, u8 *version)
 {
-	int i;
-	int ret;
-	i = WCD9XXX_A_CHIP_ID_BYTE_0;
-	while (i <= WCD9XXX_A_CHIP_ID_BYTE_3) {
-		ret = wcd9xxx_reg_read(wcd9xxx, i);
-		if (ret < 0)
-			goto exit;
-		wcd9xxx->idbyte[i-WCD9XXX_A_CHIP_ID_BYTE_0] = (u8)ret;
-		pr_debug("%s: wcd9xx read = %x, byte = %x\n", __func__, ret,
-			i);
-		i++;
+	int i, rc;
+	const struct wcd9xxx_codec_type *c, *d = NULL;
+
+	rc = wcd9xxx_bulk_read(wcd9xxx, WCD9XXX_A_CHIP_ID_BYTE_0,
+			       sizeof(wcd9xxx->id_minor),
+			       (u8 *)&wcd9xxx->id_minor);
+	if (rc < 0)
+		goto exit;
+
+	rc = wcd9xxx_bulk_read(wcd9xxx, WCD9XXX_A_CHIP_ID_BYTE_2,
+			       sizeof(wcd9xxx->id_major),
+			       (u8 *)&wcd9xxx->id_major);
+	if (rc < 0)
+		goto exit;
+	dev_dbg(wcd9xxx->dev, "%s: wcd9xxx chip id major 0x%x, minor 0x%x\n",
+		__func__, wcd9xxx->id_major, wcd9xxx->id_minor);
+
+	for (i = 0, c = &wcd9xxx_codecs[0]; i < ARRAY_SIZE(wcd9xxx_codecs);
+	     i++, c++) {
+		if (c->id_major == wcd9xxx->id_major) {
+			if (c->id_minor == wcd9xxx->id_minor) {
+				d = c;
+				dev_dbg(wcd9xxx->dev,
+					"%s: exact match %s\n", __func__,
+					d->dev->name);
+				break;
+			} else if (!d) {
+				d = c;
+			} else {
+				if ((d->id_minor < c->id_minor) ||
+				    (d->id_minor == c->id_minor &&
+				     d->version < c->version))
+					d = c;
+			}
+			dev_dbg(wcd9xxx->dev,
+				"%s: best match %s, major 0x%x, minor 0x%x\n",
+				__func__, d->dev->name, d->id_major,
+				d->id_minor);
+		}
 	}
 
-	/* Read codec version */
-	ret = wcd9xxx_reg_read(wcd9xxx, WCD9XXX_A_CHIP_VERSION);
-	if (ret < 0)
-		goto exit;
-	wcd9xxx->version = (u8)ret & 0x1F;
-	i = 0;
-	while (i < ARRAY_SIZE(wcd9xxx_codecs)) {
-		if ((wcd9xxx_codecs[i].byte[0] == wcd9xxx->idbyte[0]) &&
-		    (wcd9xxx_codecs[i].byte[1] == wcd9xxx->idbyte[1]) &&
-		    (wcd9xxx_codecs[i].byte[2] == wcd9xxx->idbyte[2]) &&
-		    (wcd9xxx_codecs[i].byte[3] == wcd9xxx->idbyte[3])) {
-			pr_info("%s: codec is %s", __func__,
-				wcd9xxx_codecs[i].dev->name);
-			*wcd9xxx_dev = wcd9xxx_codecs[i].dev;
-			*wcd9xxx_dev_size = wcd9xxx_codecs[i].size;
-			*wcd9xxx_dev_num_irqs = wcd9xxx_codecs[i].num_irqs;
-			wcd9xxx->slim_slave_type =
-			    wcd9xxx_codecs[i].slim_slave_type;
-			if (wcd9xxx_codecs[i].version > -1)
-				wcd9xxx->version = wcd9xxx_codecs[i].version;
-			break;
+	if (!d) {
+		dev_warn(wcd9xxx->dev,
+			 "%s: driver for id major 0x%x, minor 0x%x not found\n",
+			 __func__, wcd9xxx->id_major, wcd9xxx->id_minor);
+	} else {
+		if (d->version > -1) {
+			*version = d->version;
+		} else {
+			rc = wcd9xxx_reg_read(wcd9xxx, WCD9XXX_A_CHIP_VERSION);
+			if (rc < 0) {
+				d = NULL;
+				goto exit;
+			}
+			*version = (u8)rc & 0x1F;
 		}
-		i++;
+		dev_info(wcd9xxx->dev,
+			 "%s: detected %s, major 0x%x, minor 0x%x, ver 0x%x\n",
+			 __func__, d->dev->name, d->id_major, d->id_minor,
+			 *version);
 	}
-	if (*wcd9xxx_dev == NULL || *wcd9xxx_dev_size == 0)
-		ret = -ENODEV;
-	pr_info("%s: Read codec idbytes & version\n"
-		"byte_0[%08x] byte_1[%08x] byte_2[%08x]\n"
-		" byte_3[%08x] version = %x\n", __func__,
-		wcd9xxx->idbyte[0], wcd9xxx->idbyte[1],
-		wcd9xxx->idbyte[2], wcd9xxx->idbyte[3],
-		wcd9xxx->version);
 exit:
-	return ret;
+	return d;
 }
 
 static int wcd9xxx_device_init(struct wcd9xxx *wcd9xxx)
 {
 	int ret;
-	struct mfd_cell *wcd9xxx_dev = NULL;
-	int wcd9xxx_dev_size = 0;
+	u8 version;
+	const struct wcd9xxx_codec_type *found;
 
 	mutex_init(&wcd9xxx->io_lock);
 	mutex_init(&wcd9xxx->xfer_lock);
@@ -458,10 +473,14 @@
 
 	wcd9xxx_bring_up(wcd9xxx);
 
-	ret = wcd9xxx_check_codec_type(wcd9xxx, &wcd9xxx_dev, &wcd9xxx_dev_size,
-				       &wcd9xxx->num_irqs);
-	if (ret < 0)
+	found = wcd9xxx_check_codec_type(wcd9xxx, &version);
+	if (!found) {
+		ret = -ENODEV;
 		goto err_irq;
+	} else {
+		wcd9xxx->codec_type = found;
+		wcd9xxx->version = version;
+	}
 
 	if (wcd9xxx->irq != -1) {
 		ret = wcd9xxx_irq_init(wcd9xxx);
@@ -471,7 +490,7 @@
 		}
 	}
 
-	ret = mfd_add_devices(wcd9xxx->dev, -1, wcd9xxx_dev, wcd9xxx_dev_size,
+	ret = mfd_add_devices(wcd9xxx->dev, -1, found->dev, found->size,
 			      NULL, 0);
 	if (ret != 0) {
 		dev_err(wcd9xxx->dev, "Failed to add children: %d\n", ret);
@@ -605,8 +624,8 @@
 };
 #endif
 
-static int wcd9xxx_enable_supplies(struct wcd9xxx *wcd9xxx,
-				struct wcd9xxx_pdata *pdata)
+static int wcd9xxx_init_supplies(struct wcd9xxx *wcd9xxx,
+				 struct wcd9xxx_pdata *pdata)
 {
 	int ret;
 	int i;
@@ -620,7 +639,7 @@
 
 	wcd9xxx->num_of_supplies = 0;
 
-	if (ARRAY_SIZE(pdata->regulator) > MAX_REGULATOR) {
+	if (ARRAY_SIZE(pdata->regulator) > WCD9XXX_MAX_REGULATOR) {
 		pr_err("%s: Array Size out of bound\n", __func__);
 		ret = -EINVAL;
 		goto err;
@@ -642,8 +661,12 @@
 	}
 
 	for (i = 0; i < wcd9xxx->num_of_supplies; i++) {
+		if (regulator_count_voltages(wcd9xxx->supplies[i].consumer) <=
+		    0)
+			continue;
 		ret = regulator_set_voltage(wcd9xxx->supplies[i].consumer,
-			pdata->regulator[i].min_uV, pdata->regulator[i].max_uV);
+					    pdata->regulator[i].min_uV,
+					    pdata->regulator[i].max_uV);
 		if (ret) {
 			pr_err("%s: Setting regulator voltage failed for "
 				"regulator %s err = %d\n", __func__,
@@ -652,30 +675,19 @@
 		}
 
 		ret = regulator_set_optimum_mode(wcd9xxx->supplies[i].consumer,
-			pdata->regulator[i].optimum_uA);
+						pdata->regulator[i].optimum_uA);
 		if (ret < 0) {
 			pr_err("%s: Setting regulator optimum mode failed for "
 				"regulator %s err = %d\n", __func__,
 				wcd9xxx->supplies[i].supply, ret);
 			goto err_get;
+		} else {
+			ret = 0;
 		}
 	}
 
-	ret = regulator_bulk_enable(wcd9xxx->num_of_supplies,
-				    wcd9xxx->supplies);
-	if (ret != 0) {
-		dev_err(wcd9xxx->dev, "Failed to enable supplies: err = %d\n",
-				ret);
-		goto err_configure;
-	}
 	return ret;
 
-err_configure:
-	for (i = 0; i < wcd9xxx->num_of_supplies; i++) {
-		regulator_set_voltage(wcd9xxx->supplies[i].consumer, 0,
-			pdata->regulator[i].max_uV);
-		regulator_set_optimum_mode(wcd9xxx->supplies[i].consumer, 0);
-	}
 err_get:
 	regulator_bulk_free(wcd9xxx->num_of_supplies, wcd9xxx->supplies);
 err_supplies:
@@ -684,6 +696,33 @@
 	return ret;
 }
 
+static int wcd9xxx_enable_static_supplies(struct wcd9xxx *wcd9xxx,
+					  struct wcd9xxx_pdata *pdata)
+{
+	int i;
+	int ret = 0;
+
+	for (i = 0; i < wcd9xxx->num_of_supplies; i++) {
+		if (pdata->regulator[i].ondemand)
+			continue;
+		ret = regulator_enable(wcd9xxx->supplies[i].consumer);
+		if (ret) {
+			pr_err("%s: Failed to enable %s\n", __func__,
+			       wcd9xxx->supplies[i].supply);
+			break;
+		} else {
+			pr_debug("%s: Enabled regulator %s\n", __func__,
+				 wcd9xxx->supplies[i].supply);
+		}
+	}
+
+	while (ret && --i)
+		if (!pdata->regulator[i].ondemand)
+			regulator_disable(wcd9xxx->supplies[i].consumer);
+
+	return ret;
+}
+
 static void wcd9xxx_disable_supplies(struct wcd9xxx *wcd9xxx,
 				     struct wcd9xxx_pdata *pdata)
 {
@@ -692,8 +731,11 @@
 	regulator_bulk_disable(wcd9xxx->num_of_supplies,
 				    wcd9xxx->supplies);
 	for (i = 0; i < wcd9xxx->num_of_supplies; i++) {
+		if (regulator_count_voltages(wcd9xxx->supplies[i].consumer) <=
+		    0)
+			continue;
 		regulator_set_voltage(wcd9xxx->supplies[i].consumer, 0,
-			pdata->regulator[i].max_uV);
+				      pdata->regulator[i].max_uV);
 		regulator_set_optimum_mode(wcd9xxx->supplies[i].consumer, 0);
 	}
 	regulator_bulk_free(wcd9xxx->num_of_supplies, wcd9xxx->supplies);
@@ -856,7 +898,6 @@
 	struct wcd9xxx_pdata *pdata = NULL;
 	int val = 0;
 	int ret = 0;
-	int i2c_mode = 0;
 	int wcd9xx_index = 0;
 	struct device *dev;
 
@@ -913,18 +954,26 @@
 		wcd9xxx->slim_device_bootup = true;
 		if (client->dev.of_node)
 			wcd9xxx->mclk_rate = pdata->mclk_rate;
-		ret = wcd9xxx_enable_supplies(wcd9xxx, pdata);
+
+		ret = wcd9xxx_init_supplies(wcd9xxx, pdata);
 		if (ret) {
 			pr_err("%s: Fail to enable Codec supplies\n",
 			       __func__);
 			goto err_codec;
 		}
 
+		ret = wcd9xxx_enable_static_supplies(wcd9xxx, pdata);
+		if (ret) {
+			pr_err("%s: Fail to enable Codec pre-reset supplies\n",
+			       __func__);
+			goto err_codec;
+		}
 		usleep_range(5, 5);
+
 		ret = wcd9xxx_reset(wcd9xxx);
 		if (ret) {
 			pr_err("%s: Resetting Codec failed\n", __func__);
-		goto err_supplies;
+			goto err_supplies;
 		}
 
 		ret = wcd9xxx_i2c_get_client_index(client, &wcd9xx_index);
@@ -948,18 +997,14 @@
 			goto err_device_init;
 		}
 
-		if ((wcd9xxx->idbyte[0] == 0x2) || (wcd9xxx->idbyte[0] == 0x1))
-			i2c_mode = TABLA_I2C_MODE;
-		else if (wcd9xxx->idbyte[0] == 0x0)
-			i2c_mode = SITAR_I2C_MODE;
-
 		ret = wcd9xxx_read(wcd9xxx, WCD9XXX_A_CHIP_STATUS, 1, &val, 0);
+		if (ret < 0)
+			pr_err("%s: failed to read the wcd9xxx status (%d)\n",
+			       __func__, ret);
+		if (val != wcd9xxx->codec_type->i2c_chip_status)
+			pr_err("%s: unknown chip status 0x%x\n", __func__, val);
 
-		if ((ret < 0) || (val != i2c_mode))
-			pr_err("failed to read the wcd9xxx status ret = %d\n",
-			       ret);
-
-	wcd9xxx_intf = WCD9XXX_INTERFACE_TYPE_I2C;
+		wcd9xxx_intf = WCD9XXX_INTERFACE_TYPE_I2C;
 
 		return ret;
 	} else
@@ -988,7 +1033,9 @@
 }
 
 static int wcd9xxx_dt_parse_vreg_info(struct device *dev,
-	struct wcd9xxx_regulator *vreg, const char *vreg_name)
+				      struct wcd9xxx_regulator *vreg,
+				      const char *vreg_name,
+				      bool ondemand)
 {
 	int len, ret = 0;
 	const __be32 *prop;
@@ -1006,6 +1053,7 @@
 		return -ENODEV;
 	}
 	vreg->name = vreg_name;
+	vreg->ondemand = ondemand;
 
 	snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
 		"qcom,%s-voltage", vreg_name);
@@ -1014,7 +1062,7 @@
 	if (!prop || (len != (2 * sizeof(__be32)))) {
 		dev_err(dev, "%s %s property\n",
 				prop ? "invalid format" : "no", prop_name);
-		return -ENODEV;
+		return -EINVAL;
 	} else {
 		vreg->min_uV = be32_to_cpup(&prop[0]);
 		vreg->max_uV = be32_to_cpup(&prop[1]);
@@ -1027,12 +1075,12 @@
 	if (ret) {
 		dev_err(dev, "Looking up %s property in node %s failed",
 				prop_name, dev->of_node->full_name);
-		return -ENODEV;
+		return -EFAULT;
 	}
 	vreg->optimum_uA = prop_val;
 
-	dev_info(dev, "%s: vol=[%d %d]uV, curr=[%d]uA\n", vreg->name,
-		vreg->min_uV, vreg->max_uV, vreg->optimum_uA);
+	dev_info(dev, "%s: vol=[%d %d]uV, curr=[%d]uA, ond %d\n", vreg->name,
+		vreg->min_uV, vreg->max_uV, vreg->optimum_uA, vreg->ondemand);
 	return 0;
 }
 
@@ -1150,40 +1198,66 @@
 static struct wcd9xxx_pdata *wcd9xxx_populate_dt_pdata(struct device *dev)
 {
 	struct wcd9xxx_pdata *pdata;
-	int ret, i;
-	char **codec_supplies;
-	u32 num_of_supplies = 0;
+	int ret, static_cnt, ond_cnt, idx, i;
+	const char *name = NULL;
 	u32 mclk_rate = 0;
 	u32 dmic_sample_rate = 0;
+	const char *static_prop_name = "qcom,cdc-static-supplies";
+	const char *ond_prop_name = "qcom,cdc-on-demand-supplies";
 
 	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
 	if (!pdata) {
 		dev_err(dev, "could not allocate memory for platform data\n");
 		return NULL;
 	}
-	if (!strcmp(dev_name(dev), "taiko-slim-pgd") ||
-		(!strcmp(dev_name(dev), WCD9XXX_I2C_GSBI_SLAVE_ID))) {
-		codec_supplies = taiko_supplies;
-		num_of_supplies = ARRAY_SIZE(taiko_supplies);
-	} else if (!strcmp(dev_name(dev), "tapan-slim-pgd")) {
-		codec_supplies = tapan_supplies;
-		num_of_supplies = ARRAY_SIZE(tapan_supplies);
-	} else {
-		dev_err(dev, "%s unsupported device %s\n",
-				__func__, dev_name(dev));
+
+	static_cnt = of_property_count_strings(dev->of_node, static_prop_name);
+	if (IS_ERR_VALUE(static_cnt)) {
+		dev_err(dev, "%s: Failed to get static supplies %d\n", __func__,
+			static_cnt);
 		goto err;
 	}
 
-	if (num_of_supplies > ARRAY_SIZE(pdata->regulator)) {
+	/* On-demand supply list is an optional property */
+	ond_cnt = of_property_count_strings(dev->of_node, ond_prop_name);
+	if (IS_ERR_VALUE(ond_cnt))
+		ond_cnt = 0;
+
+	BUG_ON(static_cnt <= 0 || ond_cnt < 0);
+	if ((static_cnt + ond_cnt) > ARRAY_SIZE(pdata->regulator)) {
 		dev_err(dev, "%s: Num of supplies %u > max supported %u\n",
-		      __func__, num_of_supplies, ARRAY_SIZE(pdata->regulator));
-
+			__func__, static_cnt, ARRAY_SIZE(pdata->regulator));
 		goto err;
 	}
 
-	for (i = 0; i < num_of_supplies; i++) {
-		ret = wcd9xxx_dt_parse_vreg_info(dev, &pdata->regulator[i],
-			codec_supplies[i]);
+	for (idx = 0; idx < static_cnt; idx++) {
+		ret = of_property_read_string_index(dev->of_node,
+						    static_prop_name, idx,
+						    &name);
+		if (ret) {
+			dev_err(dev, "%s: of read string %s idx %d error %d\n",
+				__func__, static_prop_name, idx, ret);
+			goto err;
+		}
+
+		dev_dbg(dev, "%s: Found static cdc supply %s\n", __func__,
+			name);
+		ret = wcd9xxx_dt_parse_vreg_info(dev, &pdata->regulator[idx],
+						 name, false);
+		if (ret)
+			goto err;
+	}
+
+	for (i = 0; i < ond_cnt; i++, idx++) {
+		ret = of_property_read_string_index(dev->of_node, ond_prop_name,
+						    i, &name);
+		if (ret)
+			goto err;
+
+		dev_dbg(dev, "%s: Found on-demand cdc supply %s\n", __func__,
+			name);
+		ret = wcd9xxx_dt_parse_vreg_info(dev, &pdata->regulator[idx],
+						 name, true);
 		if (ret)
 			goto err;
 	}
@@ -1325,9 +1399,17 @@
 	wcd9xxx->mclk_rate = pdata->mclk_rate;
 	wcd9xxx->slim_device_bootup = true;
 
-	ret = wcd9xxx_enable_supplies(wcd9xxx, pdata);
-	if (ret)
+	ret = wcd9xxx_init_supplies(wcd9xxx, pdata);
+	if (ret) {
+		pr_err("%s: Fail to init Codec supplies %d\n", __func__, ret);
 		goto err_codec;
+	}
+	ret = wcd9xxx_enable_static_supplies(wcd9xxx, pdata);
+	if (ret) {
+		pr_err("%s: Fail to enable Codec pre-reset supplies\n",
+		       __func__);
+		goto err_codec;
+	}
 	usleep_range(5, 5);
 
 	ret = wcd9xxx_reset(wcd9xxx);
diff --git a/drivers/mfd/wcd9xxx-irq.c b/drivers/mfd/wcd9xxx-irq.c
index f2c3959..356aecb 100644
--- a/drivers/mfd/wcd9xxx-irq.c
+++ b/drivers/mfd/wcd9xxx-irq.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
@@ -218,7 +218,8 @@
 
 static int wcd9xxx_num_irq_regs(const struct wcd9xxx *wcd9xxx)
 {
-	return (wcd9xxx->num_irqs / 8) + ((wcd9xxx->num_irqs % 8) ? 1 : 0);
+	return (wcd9xxx->codec_type->num_irqs / 8) +
+		((wcd9xxx->codec_type->num_irqs % 8) ? 1 : 0);
 }
 
 static irqreturn_t wcd9xxx_irq_thread(int irq, void *data)
@@ -266,7 +267,8 @@
 		if (status[BIT_BYTE(i)] & BYTE_BIT_MASK(i))
 			wcd9xxx_irq_dispatch(wcd9xxx, i);
 	}
-	for (i = WCD9XXX_IRQ_BG_PRECHARGE; i < wcd9xxx->num_irqs; i++) {
+	for (i = WCD9XXX_IRQ_BG_PRECHARGE; i < wcd9xxx->codec_type->num_irqs;
+	     i++) {
 		if (status[BIT_BYTE(i)] & BYTE_BIT_MASK(i))
 			wcd9xxx_irq_dispatch(wcd9xxx, i);
 	}
@@ -301,7 +303,7 @@
 
 	pr_debug("%s: enter\n", __func__);
 
-	for (irq = 0; irq < wcd9xxx->num_irqs; irq++) {
+	for (irq = 0; irq < wcd9xxx->codec_type->num_irqs; irq++) {
 		/* Map OF irq */
 		virq = wcd9xxx_map_irq(wcd9xxx, irq);
 		pr_debug("%s: irq %d -> %d\n", __func__, irq, virq);
@@ -365,7 +367,7 @@
 
 	/* mask all the interrupts */
 	memset(irq_level, 0, wcd9xxx_num_irq_regs(wcd9xxx));
-	for (i = 0; i < wcd9xxx->num_irqs; i++) {
+	for (i = 0; i < wcd9xxx->codec_type->num_irqs; i++) {
 		wcd9xxx->irq_masks_cur[BIT_BYTE(i)] |= BYTE_BIT_MASK(i);
 		wcd9xxx->irq_masks_cache[BIT_BYTE(i)] |= BYTE_BIT_MASK(i);
 		irq_level[BIT_BYTE(i)] |=
diff --git a/drivers/mfd/wcd9xxx-slimslave.c b/drivers/mfd/wcd9xxx-slimslave.c
index f2d71b6..81262b58 100644
--- a/drivers/mfd/wcd9xxx-slimslave.c
+++ b/drivers/mfd/wcd9xxx-slimslave.c
@@ -31,7 +31,8 @@
 
 static int wcd9xxx_configure_ports(struct wcd9xxx *wcd9xxx)
 {
-	if (wcd9xxx->slim_slave_type == WCD9XXX_SLIM_SLAVE_ADDR_TYPE_TABLA) {
+	if (wcd9xxx->codec_type->slim_slave_type ==
+	    WCD9XXX_SLIM_SLAVE_ADDR_TYPE_TABLA) {
 		sh_ch.rx_port_ch_reg_base = 0x180;
 		sh_ch.port_rx_cfg_reg_base = 0x040;
 		sh_ch.port_tx_cfg_reg_base = 0x040;
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index c02eecf..05a15b1 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -1,5 +1,3 @@
-
-
 /*Qualcomm Secure Execution Environment Communicator (QSEECOM) driver
  *
  * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
@@ -53,6 +51,7 @@
 #define QSEE_VERSION_01			0x401000
 #define QSEE_VERSION_02			0x402000
 #define QSEE_VERSION_03			0x403000
+#define QSEE_VERSION_04			0x404000
 
 
 #define QSEOS_CHECK_VERSION_CMD		0x00001803
@@ -62,6 +61,12 @@
 #define QSEECOM_MAX_SG_ENTRY	512
 #define QSEECOM_DISK_ENCRYTPION_KEY_ID 0
 
+/* Save partition image hash for authentication check */
+#define	SCM_SAVE_PARTITION_HASH_ID	0x01
+
+/* Check if enterprise security is activate */
+#define	SCM_IS_ACTIVATED_ID		0x02
+
 enum qseecom_clk_definitions {
 	CLK_DFAB = 0,
 	CLK_SFPB,
@@ -74,6 +79,11 @@
 	QSEECOM_GENERIC,
 };
 
+enum qseecom_ce_hw_instance {
+	CLK_QSEE = 0,
+	CLK_CE_DRV,
+};
+
 static struct class *driver_class;
 static dev_t qseecom_device_no;
 static struct cdev qseecom_cdev;
@@ -85,6 +95,7 @@
 
 static DEFINE_MUTEX(qsee_bw_mutex);
 static DEFINE_MUTEX(app_access_lock);
+static DEFINE_MUTEX(clk_access_lock);
 
 struct qseecom_registered_listener_list {
 	struct list_head                 list;
@@ -117,10 +128,12 @@
 };
 
 struct qseecom_clk {
+	enum qseecom_ce_hw_instance instance;
 	struct clk *ce_core_clk;
 	struct clk *ce_clk;
 	struct clk *ce_core_src_clk;
 	struct clk *ce_bus_clk;
+	uint32_t clk_access_cnt;
 };
 
 struct qseecom_control {
@@ -148,6 +161,7 @@
 
 	uint32_t qsee_perf_client;
 	struct qseecom_clk qsee;
+	struct qseecom_clk ce_drv;
 };
 
 struct qseecom_client_handle {
@@ -1891,12 +1905,23 @@
 	return 0;
 }
 
-static int __qseecom_enable_clk(void)
+static int __qseecom_enable_clk(enum qseecom_ce_hw_instance ce)
 {
 	int rc = 0;
 	struct qseecom_clk *qclk;
 
+	if (ce == CLK_QSEE)
 		qclk = &qseecom.qsee;
+	else
+		qclk = &qseecom.ce_drv;
+
+	mutex_lock(&clk_access_lock);
+	if (qclk->clk_access_cnt > 0) {
+		qclk->clk_access_cnt++;
+		mutex_unlock(&clk_access_lock);
+		return rc;
+	}
+
 	/* Enable CE core clk */
 	rc = clk_prepare_enable(qclk->ce_core_clk);
 	if (rc) {
@@ -1915,6 +1940,8 @@
 		pr_err("Unable to enable/prepare CE bus clk\n");
 		goto ce_bus_clk_err;
 	}
+	qclk->clk_access_cnt++;
+	mutex_unlock(&clk_access_lock);
 	return 0;
 
 ce_bus_clk_err:
@@ -1922,20 +1949,30 @@
 ce_clk_err:
 	clk_disable_unprepare(qclk->ce_core_clk);
 err:
+	mutex_unlock(&clk_access_lock);
 	return -EIO;
 }
 
-static void __qseecom_disable_clk(void)
+static void __qseecom_disable_clk(enum qseecom_ce_hw_instance ce)
 {
 	struct qseecom_clk *qclk;
 
-	qclk = &qseecom.qsee;
-	if (qclk->ce_clk != NULL)
-		clk_disable_unprepare(qclk->ce_clk);
-	if (qclk->ce_core_clk != NULL)
-		clk_disable_unprepare(qclk->ce_core_clk);
-	if (qclk->ce_bus_clk != NULL)
-		clk_disable_unprepare(qclk->ce_bus_clk);
+	if (ce == CLK_QSEE)
+		qclk = &qseecom.qsee;
+	else
+		qclk = &qseecom.ce_drv;
+
+	mutex_lock(&clk_access_lock);
+	if (qclk->clk_access_cnt == 1) {
+		if (qclk->ce_clk != NULL)
+			clk_disable_unprepare(qclk->ce_clk);
+		if (qclk->ce_core_clk != NULL)
+			clk_disable_unprepare(qclk->ce_core_clk);
+		if (qclk->ce_bus_clk != NULL)
+			clk_disable_unprepare(qclk->ce_bus_clk);
+	}
+	qclk->clk_access_cnt--;
+	mutex_unlock(&clk_access_lock);
 }
 
 static int qsee_vote_for_clock(struct qseecom_dev_handle *data,
@@ -1957,14 +1994,14 @@
 					qseecom.qsee_perf_client, 3);
 			else {
 				if (qclk->ce_core_src_clk != NULL)
-					ret = __qseecom_enable_clk();
+					ret = __qseecom_enable_clk(CLK_QSEE);
 				if (!ret) {
 					ret =
 					msm_bus_scale_client_update_request(
 						qseecom.qsee_perf_client, 1);
 					if ((ret) &&
 						(qclk->ce_core_src_clk != NULL))
-						__qseecom_disable_clk();
+						__qseecom_disable_clk(CLK_QSEE);
 				}
 			}
 			if (ret)
@@ -1988,14 +2025,14 @@
 					qseecom.qsee_perf_client, 3);
 			else {
 				if (qclk->ce_core_src_clk != NULL)
-					ret = __qseecom_enable_clk();
+					ret = __qseecom_enable_clk(CLK_QSEE);
 				if (!ret) {
 					ret =
 					msm_bus_scale_client_update_request(
 						qseecom.qsee_perf_client, 2);
 					if ((ret) &&
 						(qclk->ce_core_src_clk != NULL))
-						__qseecom_disable_clk();
+						__qseecom_disable_clk(CLK_QSEE);
 				}
 			}
 
@@ -2046,7 +2083,7 @@
 				ret = msm_bus_scale_client_update_request(
 						qseecom.qsee_perf_client, 0);
 				if ((!ret) && (qclk->ce_core_src_clk != NULL))
-					__qseecom_disable_clk();
+					__qseecom_disable_clk(CLK_QSEE);
 			}
 			if (ret)
 				pr_err("SFPB Bandwidth req fail (%d)\n",
@@ -2076,7 +2113,7 @@
 				ret = msm_bus_scale_client_update_request(
 						qseecom.qsee_perf_client, 0);
 				if ((!ret) && (qclk->ce_core_src_clk != NULL))
-					__qseecom_disable_clk();
+					__qseecom_disable_clk(CLK_QSEE);
 			}
 			if (ret)
 				pr_err("SFPB Bandwidth req fail (%d)\n",
@@ -2345,11 +2382,13 @@
 	memcpy(ireq.key_id, key_id, QSEECOM_KEY_ID_SIZE);
 	ireq.flags = flags;
 
+	__qseecom_enable_clk(CLK_QSEE);
 	ret = scm_call(SCM_SVC_CRYPTO, QSEOS_GENERATE_KEY,
 				&ireq, sizeof(struct qseecom_key_generate_ireq),
 				&resp, sizeof(resp));
 	if (ret) {
 		pr_err("scm call to generate key failed : %d\n", ret);
+		__qseecom_disable_clk(CLK_QSEE);
 		return ret;
 	}
 
@@ -2367,6 +2406,7 @@
 		ret = -EINVAL;
 		break;
 	}
+	__qseecom_disable_clk(CLK_QSEE);
 	return ret;
 }
 
@@ -2386,11 +2426,13 @@
 	memcpy(ireq.key_id, key_id, QSEECOM_KEY_ID_SIZE);
 	ireq.flags = flags;
 
+	__qseecom_enable_clk(CLK_QSEE);
 	ret = scm_call(SCM_SVC_CRYPTO, QSEOS_DELETE_KEY,
 				&ireq, sizeof(struct qseecom_key_delete_ireq),
 				&resp, sizeof(struct qseecom_command_scm_resp));
 	if (ret) {
 		pr_err("scm call to delete key failed : %d\n", ret);
+		__qseecom_disable_clk(CLK_QSEE);
 		return ret;
 	}
 
@@ -2409,6 +2451,7 @@
 		ret = -EINVAL;
 		break;
 	}
+	__qseecom_disable_clk(CLK_QSEE);
 	return ret;
 }
 
@@ -2424,6 +2467,12 @@
 			pr_err("Error:: unsupported usage %d\n", usage);
 			return -EFAULT;
 	}
+
+	if (qseecom.qsee.instance == qseecom.ce_drv.instance)
+		__qseecom_enable_clk(CLK_QSEE);
+	else
+		__qseecom_enable_clk(CLK_CE_DRV);
+
 	memcpy(ireq.key_id, set_key_para->key_id, QSEECOM_KEY_ID_SIZE);
 	ireq.ce = set_key_para->ce_hw;
 	ireq.pipe = set_key_para->pipe;
@@ -2459,6 +2508,11 @@
 		break;
 	}
 
+	if (qseecom.qsee.instance == qseecom.ce_drv.instance)
+		__qseecom_disable_clk(CLK_QSEE);
+	else
+		__qseecom_disable_clk(CLK_CE_DRV);
+
 	return ret;
 }
 
@@ -2570,6 +2624,70 @@
 	return ret;
 }
 
+static int qseecom_is_es_activated(void __user *argp)
+{
+	struct qseecom_is_es_activated_req req;
+	int ret;
+	int resp_buf;
+
+	if (qseecom.qsee_version < QSEE_VERSION_04) {
+		pr_err("invalid qsee version");
+		return -ENODEV;
+	}
+
+	if (argp == NULL) {
+		pr_err("arg is null");
+		return -EINVAL;
+	}
+
+	ret = scm_call(SCM_SVC_ES, SCM_IS_ACTIVATED_ID, NULL, 0,
+		       (void *) &resp_buf, sizeof(resp_buf));
+	if (ret) {
+		pr_err("scm_call failed");
+		return ret;
+	}
+
+	req.is_activated = resp_buf;
+	ret = copy_to_user(argp, &req, sizeof(req));
+	if (ret) {
+		pr_err("copy_to_user failed");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int qseecom_save_partition_hash(void __user *argp)
+{
+	struct qseecom_save_partition_hash_req req;
+	int ret;
+
+	if (qseecom.qsee_version < QSEE_VERSION_04) {
+		pr_err("invalid qsee version ");
+		return -ENODEV;
+	}
+
+	if (argp == NULL) {
+		pr_err("arg is null");
+		return -EINVAL;
+	}
+
+	ret = copy_from_user(&req, argp, sizeof(req));
+	if (ret) {
+		pr_err("copy_from_user failed");
+		return ret;
+	}
+
+	ret = scm_call(SCM_SVC_ES, SCM_SAVE_PARTITION_HASH_ID,
+		       (void *) &req, sizeof(req), NULL, 0);
+	if (ret) {
+		pr_err("scm_call failed");
+		return ret;
+	}
+
+	return 0;
+}
+
 static long qseecom_ioctl(struct file *file, unsigned cmd,
 		unsigned long arg)
 {
@@ -2782,6 +2900,24 @@
 		mutex_unlock(&app_access_lock);
 		break;
 	}
+	case QSEECOM_IOCTL_SAVE_PARTITION_HASH_REQ: {
+		data->released = true;
+		mutex_lock(&app_access_lock);
+		atomic_inc(&data->ioctl_count);
+		ret = qseecom_save_partition_hash(argp);
+		atomic_dec(&data->ioctl_count);
+		mutex_unlock(&app_access_lock);
+		break;
+	}
+	case QSEECOM_IOCTL_IS_ES_ACTIVATED_REQ: {
+		data->released = true;
+		mutex_lock(&app_access_lock);
+		atomic_inc(&data->ioctl_count);
+		ret = qseecom_is_es_activated(argp);
+		atomic_dec(&data->ioctl_count);
+		mutex_unlock(&app_access_lock);
+		break;
+	}
 	default:
 		return -EINVAL;
 	}
@@ -2877,18 +3013,43 @@
 		.release = qseecom_release
 };
 
-static int __qseecom_init_clk(void)
+static int __qseecom_init_clk(enum qseecom_ce_hw_instance ce)
 {
 	int rc = 0;
 	struct device *pdev;
 	struct qseecom_clk *qclk;
+	char *core_clk_src = NULL;
+	char *core_clk = NULL;
+	char *iface_clk = NULL;
+	char *bus_clk = NULL;
 
-	qclk = &qseecom.qsee;
-
+	switch (ce) {
+	case CLK_QSEE: {
+		core_clk_src = "core_clk_src";
+		core_clk = "core_clk";
+		iface_clk = "iface_clk";
+		bus_clk = "bus_clk";
+		qclk = &qseecom.qsee;
+		qclk->instance = CLK_QSEE;
+		break;
+	};
+	case CLK_CE_DRV: {
+		core_clk_src = "ce_drv_core_clk_src";
+		core_clk = "ce_drv_core_clk";
+		iface_clk = "ce_drv_iface_clk";
+		bus_clk = "ce_drv_bus_clk";
+		qclk = &qseecom.ce_drv;
+		qclk->instance = CLK_CE_DRV;
+		break;
+	};
+	default:
+		pr_err("Invalid ce hw instance: %d!\n", ce);
+		return -EIO;
+	}
 	pdev = qseecom.pdev;
-	/* Get CE3 src core clk. */
 
-	qclk->ce_core_src_clk = clk_get(pdev, "core_clk_src");
+	/* Get CE3 src core clk. */
+	qclk->ce_core_src_clk = clk_get(pdev, core_clk_src);
 	if (!IS_ERR(qclk->ce_core_src_clk)) {
 		/* Set the core src clk @100Mhz */
 		rc = clk_set_rate(qclk->ce_core_src_clk, QSEE_CE_CLK_100MHZ);
@@ -2903,7 +3064,7 @@
 	}
 
 	/* Get CE core clk */
-	qclk->ce_core_clk = clk_get(pdev, "core_clk");
+	qclk->ce_core_clk = clk_get(pdev, core_clk);
 	if (IS_ERR(qclk->ce_core_clk)) {
 		rc = PTR_ERR(qclk->ce_core_clk);
 		pr_err("Unable to get CE core clk\n");
@@ -2913,7 +3074,7 @@
 	}
 
 	/* Get CE Interface clk */
-	qclk->ce_clk = clk_get(pdev, "iface_clk");
+	qclk->ce_clk = clk_get(pdev, iface_clk);
 	if (IS_ERR(qclk->ce_clk)) {
 		rc = PTR_ERR(qclk->ce_clk);
 		pr_err("Unable to get CE interface clk\n");
@@ -2924,7 +3085,7 @@
 	}
 
 	/* Get CE AXI clk */
-	qclk->ce_bus_clk = clk_get(pdev, "bus_clk");
+	qclk->ce_bus_clk = clk_get(pdev, bus_clk);
 	if (IS_ERR(qclk->ce_bus_clk)) {
 		rc = PTR_ERR(qclk->ce_bus_clk);
 		pr_err("Unable to get CE BUS interface clk\n");
@@ -2937,11 +3098,14 @@
 	return rc;
 }
 
-static void __qseecom_deinit_clk(void)
+static void __qseecom_deinit_clk(enum qseecom_ce_hw_instance ce)
 {
 	struct qseecom_clk *qclk;
 
-	qclk = &qseecom.qsee;
+	if (ce == CLK_QSEE)
+		qclk = &qseecom.qsee;
+	else
+		qclk = &qseecom.ce_drv;
 
 	if (qclk->ce_clk != NULL) {
 		clk_put(qclk->ce_clk);
@@ -2979,6 +3143,11 @@
 	qseecom.qsee.ce_core_src_clk = NULL;
 	qseecom.qsee.ce_bus_clk = NULL;
 
+	qseecom.ce_drv.ce_core_clk = NULL;
+	qseecom.ce_drv.ce_clk = NULL;
+	qseecom.ce_drv.ce_core_src_clk = NULL;
+	qseecom.ce_drv.ce_bus_clk = NULL;
+
 	rc = alloc_chrdev_region(&qseecom_device_no, 0, 1, QSEECOM_DEV);
 	if (rc < 0) {
 		pr_err("alloc_chrdev_region failed %d\n", rc);
@@ -3053,6 +3222,7 @@
 
 	/* register client for bus scaling */
 	if (pdev->dev.of_node) {
+
 		if (of_property_read_u32((&pdev->dev)->of_node,
 				"qcom,disk-encrypt-pipe-pair",
 				&qseecom.ce_info.disk_encrypt_pipe)) {
@@ -3089,10 +3259,29 @@
 			qseecom.ce_info.hlos_ce_hw_instance);
 		}
 
-		ret = __qseecom_init_clk();
+		qseecom.qsee.instance = qseecom.ce_info.qsee_ce_hw_instance;
+		qseecom.ce_drv.instance = qseecom.ce_info.hlos_ce_hw_instance;
+
+		ret = __qseecom_init_clk(CLK_QSEE);
 		if (ret)
 			goto err;
 
+		if (qseecom.qsee.instance != qseecom.ce_drv.instance) {
+			ret = __qseecom_init_clk(CLK_CE_DRV);
+			if (ret) {
+				__qseecom_deinit_clk(CLK_QSEE);
+				goto err;
+			}
+		} else {
+			struct qseecom_clk *qclk;
+
+			qclk = &qseecom.qsee;
+			qseecom.ce_drv.ce_core_clk = qclk->ce_core_clk;
+			qseecom.ce_drv.ce_clk = qclk->ce_clk;
+			qseecom.ce_drv.ce_core_src_clk = qclk->ce_core_src_clk;
+			qseecom.ce_drv.ce_bus_clk = qclk->ce_bus_clk;
+		}
+
 		qseecom_platform_support = (struct msm_bus_scale_pdata *)
 						msm_bus_cl_get_pdata(pdev);
 		if (qseecom.qsee_version >= (QSEE_VERSION_02)) {
@@ -3203,9 +3392,11 @@
 		msm_bus_scale_client_update_request(qseecom.qsee_perf_client,
 									0);
 	/* register client for bus scaling */
-	if (pdev->dev.of_node)
-		__qseecom_deinit_clk();
-
+	if (pdev->dev.of_node) {
+		__qseecom_deinit_clk(CLK_QSEE);
+		if (qseecom.qsee.instance != qseecom.ce_drv.instance)
+			__qseecom_deinit_clk(CLK_CE_DRV);
+	}
 	return ret;
 };
 
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index 44465dc..1a175c9 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -197,6 +197,7 @@
 	void __iomem *riva_ccu_base;
 	void __iomem *pronto_a2xb_base;
 	void __iomem *pronto_ccpu_base;
+	void __iomem *fiq_reg;
 } *penv = NULL;
 
 static ssize_t wcnss_serial_number_show(struct device *dev,
@@ -401,7 +402,7 @@
 	if (wcnss_hardware_type() == WCNSS_PRONTO_HW) {
 		wcnss_pronto_log_debug_regs();
 		wmb();
-		__raw_writel(1 << 16, MSM_APCS_GCC_BASE + 0x8);
+		__raw_writel(1 << 16, penv->fiq_reg);
 	} else {
 		wcnss_riva_log_debug_regs();
 		wmb();
@@ -1068,6 +1069,7 @@
 	struct qcom_wcnss_opts *pdata;
 	unsigned long wcnss_phys_addr;
 	int size = 0;
+	struct resource *res;
 	int has_pronto_hw = of_property_read_bool(pdev->dev.of_node,
 									"qcom,has_pronto_hw");
 
@@ -1183,11 +1185,28 @@
 			pr_err("%s: ioremap wcnss physical failed\n", __func__);
 			goto fail_ioremap2;
 		}
+		/* for reset FIQ */
+		res = platform_get_resource_byname(penv->pdev,
+				IORESOURCE_MEM, "wcnss_fiq");
+		if (!res) {
+			dev_err(&pdev->dev, "insufficient irq mem resources\n");
+			ret = -ENOENT;
+			goto fail_ioremap3;
+		}
+		penv->fiq_reg = ioremap_nocache(res->start, resource_size(res));
+		if (!penv->fiq_reg) {
+			pr_err("wcnss: %s: ioremap_nocache() failed fiq_reg addr:%pr\n",
+				__func__, &res->start);
+			ret = -ENOMEM;
+			goto fail_ioremap3;
+		}
 	}
 	penv->cold_boot_done = 1;
 
 	return 0;
 
+fail_ioremap3:
+	iounmap(penv->pronto_ccpu_base);
 fail_ioremap2:
 	iounmap(penv->pronto_a2xb_base);
 fail_ioremap:
diff --git a/drivers/platform/msm/ipa/ipa.c b/drivers/platform/msm/ipa/ipa.c
index db7f7f0..5cc5d46 100644
--- a/drivers/platform/msm/ipa/ipa.c
+++ b/drivers/platform/msm/ipa/ipa.c
@@ -41,6 +41,7 @@
 #define IPA_DMA_POOL_SIZE (512)
 #define IPA_DMA_POOL_ALIGNMENT (4)
 #define IPA_DMA_POOL_BOUNDARY (1024)
+#define IPA_NUM_DESC_PER_SW_TX (2)
 #define IPA_ROUTING_RULE_BYTE_SIZE (4)
 #define IPA_BAM_CNFG_BITS_VAL (0x7FFFE004)
 
@@ -1761,15 +1762,20 @@
 	 * This is an issue with IPA HW v1.0 only.
 	 */
 	if (ipa_ctx->ipa_hw_type == IPA_HW_v1_0) {
-		ipa_ctx->one_kb_no_straddle_pool = dma_pool_create("ipa_1k",
+		ipa_ctx->dma_pool = dma_pool_create("ipa_1k",
 				NULL,
 				IPA_DMA_POOL_SIZE, IPA_DMA_POOL_ALIGNMENT,
 				IPA_DMA_POOL_BOUNDARY);
-		if (!ipa_ctx->one_kb_no_straddle_pool) {
-			IPAERR("cannot setup 1kb alloc DMA pool.\n");
-			result = -ENOMEM;
-			goto fail_dma_pool;
-		}
+	} else {
+		ipa_ctx->dma_pool = dma_pool_create("ipa_tx", NULL,
+			IPA_NUM_DESC_PER_SW_TX * sizeof(struct sps_iovec),
+			0, 0);
+	}
+
+	if (!ipa_ctx->dma_pool) {
+		IPAERR("cannot alloc DMA pool.\n");
+		result = -ENOMEM;
+		goto fail_dma_pool;
 	}
 
 	ipa_ctx->glob_flt_tbl[IPA_IP_v4].in_sys = !ipa_ctx->ip4_flt_tbl_lcl;
@@ -1976,7 +1982,7 @@
 	 * DMA pool need to be released only for IPA HW v1.0 only.
 	 */
 	if (ipa_ctx->ipa_hw_type == IPA_HW_v1_0)
-		dma_pool_destroy(ipa_ctx->one_kb_no_straddle_pool);
+		dma_pool_destroy(ipa_ctx->dma_pool);
 fail_dma_pool:
 	kmem_cache_destroy(ipa_ctx->tree_node_cache);
 fail_tree_node_cache:
diff --git a/drivers/platform/msm/ipa/ipa_dp.c b/drivers/platform/msm/ipa/ipa_dp.c
index 5f7f3d9..2555c6b 100644
--- a/drivers/platform/msm/ipa/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_dp.c
@@ -42,7 +42,7 @@
  *   the order for sent packet is the same as expected
  * - delete all the tx packet descriptors from the system
  *   pipe context (not needed anymore)
- * - return the tx buffer back to one_kb_no_straddle_pool
+ * - return the tx buffer back to dma_pool
  */
 void ipa_wq_write_done(struct work_struct *work)
 {
@@ -80,7 +80,7 @@
 		list_del(&tx_pkt->link);
 		spin_unlock_irqrestore(&tx_pkt->sys->spinlock, irq_flags);
 		if (unlikely(ipa_ctx->ipa_hw_type == IPA_HW_v1_0)) {
-			dma_pool_free(ipa_ctx->one_kb_no_straddle_pool,
+			dma_pool_free(ipa_ctx->dma_pool,
 					tx_pkt->bounce,
 					tx_pkt->mem.phys_base);
 		} else {
@@ -97,7 +97,7 @@
 	}
 
 	if (mult.phys_base)
-		dma_free_coherent(NULL, mult.size, mult.base, mult.phys_base);
+		dma_pool_free(ipa_ctx->dma_pool, mult.base, mult.phys_base);
 }
 
 /**
@@ -144,7 +144,7 @@
 		 * does not cross a 1KB boundary
 		 */
 		tx_pkt->bounce = dma_pool_alloc(
-					ipa_ctx->one_kb_no_straddle_pool,
+					ipa_ctx->dma_pool,
 					mem_flag, &dma_address);
 		if (!tx_pkt->bounce) {
 			dma_address = 0;
@@ -208,7 +208,7 @@
 	list_del(&tx_pkt->link);
 	spin_unlock_irqrestore(&sys->spinlock, irq_flags);
 	if (unlikely(ipa_ctx->ipa_hw_type == IPA_HW_v1_0))
-		dma_pool_free(ipa_ctx->one_kb_no_straddle_pool, tx_pkt->bounce,
+		dma_pool_free(ipa_ctx->dma_pool, tx_pkt->bounce,
 				dma_address);
 	else
 		dma_unmap_single(NULL, dma_address, desc->len, DMA_TO_DEVICE);
@@ -259,7 +259,7 @@
 	if (unlikely(!in_atomic))
 		mem_flag = GFP_KERNEL;
 
-	transfer.iovec = dma_alloc_coherent(NULL, size, &dma_addr, mem_flag);
+	transfer.iovec = dma_pool_alloc(ipa_ctx->dma_pool, mem_flag, &dma_addr);
 	transfer.iovec_phys = dma_addr;
 	transfer.iovec_count = num_desc;
 	spin_lock_irqsave(&sys->spinlock, irq_flags);
@@ -306,7 +306,7 @@
 			 * packet does not cross a 1KB boundary
 			 */
 			tx_pkt->bounce =
-			   dma_pool_alloc(ipa_ctx->one_kb_no_straddle_pool,
+			   dma_pool_alloc(ipa_ctx->dma_pool,
 					   mem_flag,
 					   &tx_pkt->mem.phys_base);
 			if (!tx_pkt->bounce) {
@@ -377,7 +377,7 @@
 		next_pkt = list_next_entry(tx_pkt, link);
 		list_del(&tx_pkt->link);
 		if (unlikely(ipa_ctx->ipa_hw_type == IPA_HW_v1_0))
-			dma_pool_free(ipa_ctx->one_kb_no_straddle_pool,
+			dma_pool_free(ipa_ctx->dma_pool,
 					tx_pkt->bounce,
 					tx_pkt->mem.phys_base);
 		else
@@ -392,7 +392,7 @@
 		if (fail_dma_wrap)
 			kmem_cache_free(ipa_ctx->tx_pkt_wrapper_cache, tx_pkt);
 	if (transfer.iovec_phys)
-		dma_free_coherent(NULL, size, transfer.iovec,
+		dma_pool_free(ipa_ctx->dma_pool, transfer.iovec,
 				  transfer.iovec_phys);
 failure_coherent:
 	spin_unlock_irqrestore(&sys->spinlock, irq_flags);
diff --git a/drivers/platform/msm/ipa/ipa_i.h b/drivers/platform/msm/ipa/ipa_i.h
index ca5740d..cb67514 100644
--- a/drivers/platform/msm/ipa/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_i.h
@@ -585,7 +585,7 @@
  * @ip6_flt_tbl_lcl: where ip6 flt tables reside 1-local; 0-system
  * @empty_rt_tbl_mem: empty routing tables memory
  * @pipe_mem_pool: pipe memory pool
- * @one_kb_no_straddle_pool: one kb no straddle pool
+ * @dma_pool: special purpose DMA pool
  * @ipa_hw_type: type of IPA HW type (e.g. IPA 1.0, IPA 1.1 etc')
  * @ipa_hw_mode: mode of IPA HW mode (e.g. Normal, Virtual or over PCIe)
  *
@@ -643,7 +643,7 @@
 	bool ip6_flt_tbl_lcl;
 	struct ipa_mem_buffer empty_rt_tbl_mem;
 	struct gen_pool *pipe_mem_pool;
-	struct dma_pool *one_kb_no_straddle_pool;
+	struct dma_pool *dma_pool;
 	atomic_t ipa_active_clients;
 	u32 clnt_hdl_cmd;
 	u32 clnt_hdl_data_in;
diff --git a/drivers/platform/msm/ipa/ipa_intf.c b/drivers/platform/msm/ipa/ipa_intf.c
index 0f41d2c..5ee1929 100644
--- a/drivers/platform/msm/ipa/ipa_intf.c
+++ b/drivers/platform/msm/ipa/ipa_intf.c
@@ -432,6 +432,7 @@
 			}
 			IPA_STATS_INC_CNT(
 				ipa_ctx->stats.msg_r[msg->meta.msg_type]);
+			kfree(msg);
 		}
 
 		ret = -EAGAIN;
diff --git a/drivers/platform/msm/ipa/ipa_rt.c b/drivers/platform/msm/ipa/ipa_rt.c
index 1d88280..fc5f668 100644
--- a/drivers/platform/msm/ipa/ipa_rt.c
+++ b/drivers/platform/msm/ipa/ipa_rt.c
@@ -505,6 +505,8 @@
 			IPAERR("failed to add to tree\n");
 			WARN_ON(1);
 		}
+	} else {
+		kmem_cache_free(ipa_ctx->tree_node_cache, node);
 	}
 
 	return entry;
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index e9cf973..459ab1d 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -4574,12 +4574,12 @@
 	int rc;
 	struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
 
-	pm8921_chg_force_19p2mhz_clk(chip);
-
 	rc = pm8921_chg_set_lpm(chip, 0);
 	if (rc)
 		pr_err("Failed to set lpm rc=%d\n", rc);
 
+	pm8921_chg_force_19p2mhz_clk(chip);
+
 	rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
 						VREF_BATT_THERM_FORCE_ON);
 	if (rc)
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 331c7f1..6cc27c2 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -1737,7 +1737,7 @@
 	}
 
 	/* Get the vddmax property */
-	rc = of_property_read_u32(spmi->dev.of_node, "qcom,chg-vddmax-mv",
+	rc = of_property_read_u32(spmi->dev.of_node, "qcom,vddmax-mv",
 						&chip->max_voltage_mv);
 	if (rc) {
 		pr_err("Error reading vddmax property %d\n", rc);
@@ -1745,7 +1745,7 @@
 	}
 
 	/* Get the vinmin property */
-	rc = of_property_read_u32(spmi->dev.of_node, "qcom,chg-vinmin-mv",
+	rc = of_property_read_u32(spmi->dev.of_node, "qcom,vinmin-mv",
 						&chip->min_voltage_mv);
 	if (rc) {
 		pr_err("Error reading vddmax property %d\n", rc);
@@ -1753,7 +1753,7 @@
 	}
 
 	/* Get the vddmax property */
-	rc = of_property_read_u32(spmi->dev.of_node, "qcom,chg-vddsafe-mv",
+	rc = of_property_read_u32(spmi->dev.of_node, "qcom,vddsafe-mv",
 						&chip->safe_voltage_mv);
 	if (rc) {
 		pr_err("Error reading vddsave property %d\n", rc);
@@ -1762,7 +1762,7 @@
 
 	/* Get the vbatdet-delta property */
 	rc = of_property_read_u32(spmi->dev.of_node,
-				"qcom,chg-vbatdet-delta-mv",
+				"qcom,vbatdet-delta-mv",
 				&chip->resume_delta_mv);
 	if (rc && rc != -EINVAL) {
 		pr_err("Error reading vbatdet-delta property %d\n", rc);
@@ -1771,7 +1771,7 @@
 
 	/* Get the ibatsafe property */
 	rc = of_property_read_u32(spmi->dev.of_node,
-				"qcom,chg-ibatsafe-ma",
+				"qcom,ibatsafe-ma",
 				&chip->safe_current);
 	if (rc) {
 		pr_err("Error reading ibatsafe property %d\n", rc);
@@ -1780,7 +1780,7 @@
 
 	/* Get the ibatterm property */
 	rc = of_property_read_u32(spmi->dev.of_node,
-				"qcom,chg-ibatterm-ma",
+				"qcom,ibatterm-ma",
 				&chip->term_current);
 	if (rc && rc != -EINVAL) {
 		pr_err("Error reading ibatterm property %d\n", rc);
@@ -1788,7 +1788,7 @@
 	}
 
 	/* Get the ibatmax property */
-	rc = of_property_read_u32(spmi->dev.of_node, "qcom,chg-ibatmax-ma",
+	rc = of_property_read_u32(spmi->dev.of_node, "qcom,ibatmax-ma",
 						&chip->max_bat_chg_current);
 	if (rc) {
 		pr_err("Error reading ibatmax property %d\n", rc);
@@ -1797,7 +1797,7 @@
 
 	/* Get the maxinput-dc-ma property */
 	rc = of_property_read_u32(spmi->dev.of_node,
-				"qcom,chg-maxinput-dc-ma",
+				"qcom,maxinput-dc-ma",
 				&chip->maxinput_dc_ma);
 	if (rc && rc != -EINVAL) {
 		pr_err("Error reading maxinput-dc-ma property %d\n", rc);
@@ -1806,7 +1806,7 @@
 
 	/* Get the maxinput-usb-ma property */
 	rc = of_property_read_u32(spmi->dev.of_node,
-				"qcom,chg-maxinput-usb-ma",
+				"qcom,maxinput-usb-ma",
 				&chip->maxinput_usb_ma);
 	if (rc && rc != -EINVAL) {
 		pr_err("Error reading maxinput-usb-ma property %d\n", rc);
@@ -1815,11 +1815,11 @@
 
 	/* Get the charging-disabled property */
 	chip->charging_disabled = of_property_read_bool(spmi->dev.of_node,
-					"qcom,chg-charging-disabled");
+					"qcom,charging-disabled");
 
 	/* Get the warm-bat-degc property */
 	rc = of_property_read_u32(spmi->dev.of_node,
-				"qcom,chg-warm-bat-decidegc",
+				"qcom,warm-bat-decidegc",
 				&chip->warm_bat_decidegc);
 	if (rc && rc != -EINVAL) {
 		pr_err("Error reading warm-bat-degc property %d\n", rc);
@@ -1828,7 +1828,7 @@
 
 	/* Get the cool-bat-degc property */
 	rc = of_property_read_u32(spmi->dev.of_node,
-				"qcom,chg-cool-bat-decidegc",
+				"qcom,cool-bat-decidegc",
 				&chip->cool_bat_decidegc);
 	if (rc && rc != -EINVAL) {
 		pr_err("Error reading cool-bat-degc property %d\n", rc);
@@ -1844,7 +1844,7 @@
 
 		/* Get the ibatmax-warm property */
 		rc = of_property_read_u32(spmi->dev.of_node,
-					"qcom,chg-ibatmax-warm-ma",
+					"qcom,ibatmax-warm-ma",
 					&chip->warm_bat_chg_ma);
 		if (rc) {
 			pr_err("Error reading ibatmax-warm-ma %d\n", rc);
@@ -1853,7 +1853,7 @@
 
 		/* Get the ibatmax-cool property */
 		rc = of_property_read_u32(spmi->dev.of_node,
-					"qcom,chg-ibatmax-cool-ma",
+					"qcom,ibatmax-cool-ma",
 					&chip->cool_bat_chg_ma);
 		if (rc) {
 			pr_err("Error reading ibatmax-cool-ma %d\n", rc);
@@ -1861,7 +1861,7 @@
 		}
 		/* Get the cool-bat-mv property */
 		rc = of_property_read_u32(spmi->dev.of_node,
-					"qcom,chg-cool-bat-mv",
+					"qcom,cool-bat-mv",
 					&chip->cool_bat_mv);
 		if (rc) {
 			pr_err("Error reading cool-bat-mv property %d\n", rc);
@@ -1870,7 +1870,7 @@
 
 		/* Get the warm-bat-mv property */
 		rc = of_property_read_u32(spmi->dev.of_node,
-					"qcom,chg-warm-bat-mv",
+					"qcom,warm-bat-mv",
 					&chip->warm_bat_mv);
 		if (rc) {
 			pr_err("Error reading warm-bat-mv property %d\n", rc);
@@ -1880,9 +1880,9 @@
 
 	/* Get the fake-batt-values property */
 	chip->use_default_batt_values = of_property_read_bool(spmi->dev.of_node,
-					"qcom,chg-use-default-batt-values");
+					"qcom,use-default-batt-values");
 
-	of_get_property(spmi->dev.of_node, "qcom,chg-thermal-mitigation",
+	of_get_property(spmi->dev.of_node, "qcom,thermal-mitigation",
 		&(chip->thermal_levels));
 
 	if (chip->thermal_levels > sizeof(int)) {
@@ -1897,10 +1897,10 @@
 
 		chip->thermal_levels /= sizeof(int);
 		rc = of_property_read_u32_array(spmi->dev.of_node,
-				"qcom,chg-thermal-mitigation",
+				"qcom,thermal-mitigation",
 				chip->thermal_mitigation, chip->thermal_levels);
 		if (rc) {
-			pr_err("qcom,chg-thermal-mitigation missing in dt\n");
+			pr_err("qcom,thermal-mitigation missing in dt\n");
 			goto fail_chg_enable;
 		}
 	}
diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig
index 706fba7..9a4ea63 100644
--- a/drivers/scsi/ufs/Kconfig
+++ b/drivers/scsi/ufs/Kconfig
@@ -58,6 +58,17 @@
 
 	  If unsure, say N.
 
+config SCSI_UFSHCD_PLATFORM
+	tristate "Platform bus based UFS Controller support"
+	depends on SCSI_UFSHCD
+	---help---
+	This selects the UFS host controller support. Select this if
+	you have an UFS controller on Platform bus.
+
+	If you have a controller with this interface, say Y or M here.
+
+	  If unsure, say N.
+
 config SCSI_UFS_TEST
 	tristate "Universal Flash Storage host controller driver unit-tests"
 	depends on SCSI_UFSHCD && IOSCHED_TEST
diff --git a/drivers/scsi/ufs/Makefile b/drivers/scsi/ufs/Makefile
index bbcc202..8d6665b 100644
--- a/drivers/scsi/ufs/Makefile
+++ b/drivers/scsi/ufs/Makefile
@@ -1,4 +1,5 @@
 # UFSHCD makefile
 obj-$(CONFIG_SCSI_UFSHCD) += ufshcd.o
 obj-$(CONFIG_SCSI_UFSHCD_PCI) += ufshcd-pci.o
+obj-$(CONFIG_SCSI_UFSHCD_PLATFORM) += ufshcd-pltfrm.o
 obj-$(CONFIG_SCSI_UFS_TEST) += ufs_test.o
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
new file mode 100644
index 0000000..03319ac
--- /dev/null
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -0,0 +1,217 @@
+/*
+ * Universal Flash Storage Host controller Platform bus based glue driver
+ *
+ * This code is based on drivers/scsi/ufs/ufshcd-pltfrm.c
+ * Copyright (C) 2011-2013 Samsung India Software Operations
+ *
+ * Authors:
+ *	Santosh Yaraganavi <santosh.sy@samsung.com>
+ *	Vinayak Holikatti <h.vinayak@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * See the COPYING file in the top-level directory or visit
+ * <http://www.gnu.org/licenses/gpl-2.0.html>
+ *
+ * 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.
+ *
+ * This program is provided "AS IS" and "WITH ALL FAULTS" and
+ * without warranty of any kind. You are solely responsible for
+ * determining the appropriateness of using and distributing
+ * the program and assume all risks associated with your exercise
+ * of rights with respect to the program, including but not limited
+ * to infringement of third party rights, the risks and costs of
+ * program errors, damage to or loss of data, programs or equipment,
+ * and unavailability or interruption of operations. Under no
+ * circumstances will the contributor of this Program be liable for
+ * any damages of any kind arising from your use or distribution of
+ * this program.
+ */
+
+#include "ufshcd.h"
+#include <linux/platform_device.h>
+
+#ifdef CONFIG_PM
+/**
+ * ufshcd_pltfrm_suspend - suspend power management function
+ * @dev: pointer to device handle
+ *
+ *
+ * Returns 0
+ */
+static int ufshcd_pltfrm_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct ufs_hba *hba =  platform_get_drvdata(pdev);
+
+	/*
+	 * TODO:
+	 * 1. Call ufshcd_suspend
+	 * 2. Do bus specific power management
+	 */
+
+	disable_irq(hba->irq);
+
+	return 0;
+}
+
+/**
+ * ufshcd_pltfrm_resume - resume power management function
+ * @dev: pointer to device handle
+ *
+ * Returns 0
+ */
+static int ufshcd_pltfrm_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct ufs_hba *hba =  platform_get_drvdata(pdev);
+
+	/*
+	 * TODO:
+	 * 1. Call ufshcd_resume.
+	 * 2. Do bus specific wake up
+	 */
+
+	enable_irq(hba->irq);
+
+	return 0;
+}
+#else
+#define ufshcd_pltfrm_suspend	NULL
+#define ufshcd_pltfrm_resume	NULL
+#endif
+
+/**
+ * ufshcd_pltfrm_probe - probe routine of the driver
+ * @pdev: pointer to Platform device handle
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+static int ufshcd_pltfrm_probe(struct platform_device *pdev)
+{
+	struct ufs_hba *hba;
+	void __iomem *mmio_base;
+	struct resource *mem_res;
+	struct resource *irq_res;
+	resource_size_t mem_size;
+	int err;
+	struct device *dev = &pdev->dev;
+
+	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mem_res) {
+		dev_err(&pdev->dev,
+			"Memory resource not available\n");
+		err = -ENODEV;
+		goto out_error;
+	}
+
+	mem_size = resource_size(mem_res);
+	if (!request_mem_region(mem_res->start, mem_size, "ufshcd")) {
+		dev_err(&pdev->dev,
+			"Cannot reserve the memory resource\n");
+		err = -EBUSY;
+		goto out_error;
+	}
+
+	mmio_base = ioremap_nocache(mem_res->start, mem_size);
+	if (!mmio_base) {
+		dev_err(&pdev->dev, "memory map failed\n");
+		err = -ENOMEM;
+		goto out_release_regions;
+	}
+
+	irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!irq_res) {
+		dev_err(&pdev->dev, "IRQ resource not available\n");
+		err = -ENODEV;
+		goto out_iounmap;
+	}
+
+	err = dma_set_coherent_mask(dev, dev->coherent_dma_mask);
+	if (err) {
+		dev_err(&pdev->dev, "set dma mask failed\n");
+		goto out_iounmap;
+	}
+
+	err = ufshcd_init(&pdev->dev, &hba, mmio_base, irq_res->start);
+	if (err) {
+		dev_err(&pdev->dev, "Intialization failed\n");
+		goto out_iounmap;
+	}
+
+	platform_set_drvdata(pdev, hba);
+
+	return 0;
+
+out_iounmap:
+	iounmap(mmio_base);
+out_release_regions:
+	release_mem_region(mem_res->start, mem_size);
+out_error:
+	return err;
+}
+
+/**
+ * ufshcd_pltfrm_remove - remove platform driver routine
+ * @pdev: pointer to platform device handle
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+static int ufshcd_pltfrm_remove(struct platform_device *pdev)
+{
+	struct resource *mem_res;
+	resource_size_t mem_size;
+	struct ufs_hba *hba =  platform_get_drvdata(pdev);
+
+	disable_irq(hba->irq);
+
+	/* Some buggy controllers raise interrupt after
+	 * the resources are removed. So first we unregister the
+	 * irq handler and then the resources used by driver
+	 */
+
+	free_irq(hba->irq, hba);
+	ufshcd_remove(hba);
+	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mem_res)
+		dev_err(&pdev->dev, "ufshcd: Memory resource not available\n");
+	else {
+		mem_size = resource_size(mem_res);
+		release_mem_region(mem_res->start, mem_size);
+	}
+	platform_set_drvdata(pdev, NULL);
+	return 0;
+}
+
+static const struct of_device_id ufs_of_match[] = {
+	{ .compatible = "jedec,ufs-1.1"},
+};
+
+static const struct dev_pm_ops ufshcd_dev_pm_ops = {
+	.suspend	= ufshcd_pltfrm_suspend,
+	.resume		= ufshcd_pltfrm_resume,
+};
+
+static struct platform_driver ufshcd_pltfrm_driver = {
+	.probe	= ufshcd_pltfrm_probe,
+	.remove	= ufshcd_pltfrm_remove,
+	.driver	= {
+		.name	= "ufshcd",
+		.owner	= THIS_MODULE,
+		.pm	= &ufshcd_dev_pm_ops,
+		.of_match_table = ufs_of_match,
+	},
+};
+
+module_platform_driver(ufshcd_pltfrm_driver);
+
+MODULE_AUTHOR("Santosh Yaragnavi <santosh.sy@samsung.com>");
+MODULE_AUTHOR("Vinayak Holikatti <h.vinayak@samsung.com>");
+MODULE_DESCRIPTION("UFS host controller Pltform bus based glue driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(UFSHCD_DRIVER_VERSION);
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 60fd40c..c32a478 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -478,7 +478,7 @@
 		ucd_cmd_ptr->header.dword_2 = 0;
 
 		ucd_cmd_ptr->exp_data_transfer_len =
-			cpu_to_be32(lrbp->cmd->transfersize);
+			cpu_to_be32(lrbp->cmd->sdb.length);
 
 		memcpy(ucd_cmd_ptr->cdb,
 		       lrbp->cmd->cmnd,
diff --git a/drivers/usb/gadget/f_rmnet.c b/drivers/usb/gadget/f_rmnet.c
index 2dccca8..f095efb 100644
--- a/drivers/usb/gadget/f_rmnet.c
+++ b/drivers/usb/gadget/f_rmnet.c
@@ -301,6 +301,7 @@
 	int	ret;
 	int	port_idx;
 	int	i;
+	u8 base;
 
 	pr_debug("%s: bam ports: %u bam2bam ports: %u data hsic ports: %u data hsuart ports: %u"
 		" smd ports: %u ctrl hsic ports: %u ctrl hsuart ports: %u"
@@ -317,9 +318,13 @@
 	}
 
 	if (no_ctrl_smd_ports) {
-		ret = gsmd_ctrl_setup(no_ctrl_smd_ports);
+		ret = gsmd_ctrl_setup(FRMNET_CTRL_CLIENT,
+				no_ctrl_smd_ports, &base);
 		if (ret)
 			return ret;
+		for (i = 0; i < nr_rmnet_ports; i++)
+			if (rmnet_ports[i].port)
+				rmnet_ports[i].port->port_num += base;
 	}
 
 	if (no_data_hsic_ports) {
diff --git a/drivers/usb/gadget/u_rmnet.h b/drivers/usb/gadget/u_rmnet.h
index a9cca50..98307d3 100644
--- a/drivers/usb/gadget/u_rmnet.h
+++ b/drivers/usb/gadget/u_rmnet.h
@@ -46,6 +46,12 @@
 	void (*connect)(struct grmnet *g);
 };
 
+enum ctrl_client {
+	FRMNET_CTRL_CLIENT,
+
+	NR_CTRL_CLIENTS
+};
+
 int gbam_setup(unsigned int no_bam_port, unsigned int no_bam2bam_port);
 int gbam_connect(struct grmnet *gr, u8 port_num,
 	enum transport_type trans, u8 src_connection_idx,
@@ -56,7 +62,8 @@
 void gbam_resume(struct grmnet *gr, u8 port_num, enum transport_type trans);
 int gsmd_ctrl_connect(struct grmnet *gr, int port_num);
 void gsmd_ctrl_disconnect(struct grmnet *gr, u8 port_num);
-int gsmd_ctrl_setup(unsigned int count);
+int gsmd_ctrl_setup(enum ctrl_client client_num, unsigned int count,
+					u8 *first_port_idx);
 int gqti_ctrl_connect(struct grmnet *gr);
 void gqti_ctrl_disconnect(struct grmnet *gr);
 
diff --git a/drivers/usb/gadget/u_rmnet_ctrl_smd.c b/drivers/usb/gadget/u_rmnet_ctrl_smd.c
index 161634e..9b824bb 100644
--- a/drivers/usb/gadget/u_rmnet_ctrl_smd.c
+++ b/drivers/usb/gadget/u_rmnet_ctrl_smd.c
@@ -24,11 +24,15 @@
 
 #include "u_rmnet.h"
 
-#define NR_CTRL_SMD_PORTS	3
-static int n_rmnet_ctrl_ports;
-static char *rmnet_ctrl_names[] = {"DATA40_CNTL", "DATA39_CNTL", "DATA38_CNTL"};
+#define MAX_CTRL_PER_CLIENT	3
+#define MAX_CTRL_PORT		(MAX_CTRL_PER_CLIENT * NR_CTRL_CLIENTS)
+static char *ctrl_names[NR_CTRL_CLIENTS][MAX_CTRL_PER_CLIENT] = {
+	{"DATA40_CNTL", "DATA39_CNTL", "DATA38_CNTL"},
+};
 static struct workqueue_struct *grmnet_ctrl_wq;
 
+u8 online_clients;
+
 #define SMD_CH_MAX_LEN	20
 #define CH_OPENED	0
 #define CH_READY	1
@@ -68,7 +72,7 @@
 static struct rmnet_ctrl_ports {
 	struct rmnet_ctrl_port *port;
 	struct platform_driver pdrv;
-} ctrl_smd_ports[NR_CTRL_SMD_PORTS];
+} ctrl_smd_ports[MAX_CTRL_PORT];
 
 
 /*---------------misc functions---------------- */
@@ -172,6 +176,15 @@
 	}
 	spin_unlock_irqrestore(&port->port_lock, flags);
 }
+static int is_legal_port_num(u8 portno)
+{
+	if (portno >= MAX_CTRL_PORT)
+		return false;
+	if (ctrl_smd_ports[portno].port == NULL)
+		return false;
+
+	return true;
+}
 
 static int
 grmnet_ctrl_smd_send_cpkt_tomodem(u8 portno,
@@ -182,7 +195,7 @@
 	struct smd_ch_info	*c;
 	struct rmnet_ctrl_pkt *cpkt;
 
-	if (portno >= n_rmnet_ctrl_ports) {
+	if (!is_legal_port_num(portno)) {
 		pr_err("%s: Invalid portno#%d\n", __func__, portno);
 		return -ENODEV;
 	}
@@ -225,7 +238,7 @@
 	int			clear_bits = 0;
 	int			temp = 0;
 
-	if (portno >= n_rmnet_ctrl_ports) {
+	if (!is_legal_port_num(portno)) {
 		pr_err("%s: Invalid portno#%d\n", __func__, portno);
 		return;
 	}
@@ -375,8 +388,8 @@
 
 	pr_debug("%s: grmnet:%p port#%d\n", __func__, gr, port_num);
 
-	if (port_num >= n_rmnet_ctrl_ports) {
-		pr_err("%s: invalid portno#%d\n", __func__, port_num);
+	if (!is_legal_port_num(port_num)) {
+		pr_err("%s: Invalid port_num#%d\n", __func__, port_num);
 		return -ENODEV;
 	}
 
@@ -431,8 +444,8 @@
 
 	pr_debug("%s: grmnet:%p port#%d\n", __func__, gr, port_num);
 
-	if (port_num >= n_rmnet_ctrl_ports) {
-		pr_err("%s: invalid portno#%d\n", __func__, port_num);
+	if (!is_legal_port_num(port_num)) {
+		pr_err("%s: Invalid port_num#%d\n", __func__, port_num);
 		return;
 	}
 
@@ -478,7 +491,10 @@
 
 	pr_debug("%s: name:%s\n", __func__, pdev->name);
 
-	for (i = 0; i < n_rmnet_ctrl_ports; i++) {
+	for (i = 0; i < MAX_CTRL_PORT; i++) {
+		if (!ctrl_smd_ports[i].port)
+			continue;
+
 		port = ctrl_smd_ports[i].port;
 		c = &port->ctrl_ch;
 
@@ -508,7 +524,10 @@
 
 	pr_debug("%s: name:%s\n", __func__, pdev->name);
 
-	for (i = 0; i < n_rmnet_ctrl_ports; i++) {
+	for (i = 0; i < MAX_CTRL_PORT; i++) {
+		if (!ctrl_smd_ports[i].port)
+			continue;
+
 		port = ctrl_smd_ports[i].port;
 		c = &port->ctrl_ch;
 
@@ -555,7 +574,8 @@
 	INIT_DELAYED_WORK(&port->disconnect_w, grmnet_ctrl_smd_disconnect_w);
 
 	c = &port->ctrl_ch;
-	c->name = rmnet_ctrl_names[portno];
+	c->name = ctrl_names[portno / MAX_CTRL_PER_CLIENT]
+						[portno % MAX_CTRL_PER_CLIENT];
 	c->port = port;
 	init_waitqueue_head(&c->wait);
 	INIT_LIST_HEAD(&c->tx_q);
@@ -575,44 +595,54 @@
 	return 0;
 }
 
-int gsmd_ctrl_setup(unsigned int count)
+int gsmd_ctrl_setup(enum ctrl_client client_num, unsigned int count,
+					u8 *first_port_idx)
 {
-	int	i;
+	int	i, start_port, allocated_ports;
 	int	ret;
 
 	pr_debug("%s: requested ports:%d\n", __func__, count);
 
-	if (!count || count > NR_CTRL_SMD_PORTS) {
+	if (!count || count > MAX_CTRL_PER_CLIENT) {
 		pr_err("%s: Invalid num of ports count:%d\n",
 				__func__, count);
 		return -EINVAL;
 	}
 
-	grmnet_ctrl_wq = alloc_workqueue("gsmd_ctrl",
-				WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
-	if (!grmnet_ctrl_wq) {
-		pr_err("%s: Unable to create workqueue grmnet_ctrl\n",
-				__func__);
-		return -ENOMEM;
+	if (!online_clients) {
+		grmnet_ctrl_wq = alloc_workqueue("gsmd_ctrl",
+			WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
+		if (!grmnet_ctrl_wq) {
+			pr_err("%s: Unable to create workqueue grmnet_ctrl\n",
+					__func__);
+			return -ENOMEM;
+		}
 	}
+	online_clients++;
 
-	for (i = 0; i < count; i++) {
-		n_rmnet_ctrl_ports++;
+	start_port = MAX_CTRL_PER_CLIENT * client_num;
+	allocated_ports = 0;
+	for (i = start_port; i < count + start_port; i++) {
+		allocated_ports++;
 		ret = grmnet_ctrl_smd_port_alloc(i);
 		if (ret) {
 			pr_err("%s: Unable to alloc port:%d\n", __func__, i);
-			n_rmnet_ctrl_ports--;
+			allocated_ports--;
 			goto free_ctrl_smd_ports;
 		}
 	}
-
+	if (first_port_idx)
+		*first_port_idx = start_port;
 	return 0;
 
 free_ctrl_smd_ports:
-	for (i = 0; i < n_rmnet_ctrl_ports; i++)
-		grmnet_ctrl_smd_port_free(i);
+	for (i = 0; i < allocated_ports; i++)
+		grmnet_ctrl_smd_port_free(start_port + i);
 
-	destroy_workqueue(grmnet_ctrl_wq);
+
+	online_clients--;
+	if (!online_clients)
+		destroy_workqueue(grmnet_ctrl_wq);
 
 	return ret;
 }
@@ -634,10 +664,11 @@
 	if (!buf)
 		return -ENOMEM;
 
-	for (i = 0; i < n_rmnet_ctrl_ports; i++) {
-		port = ctrl_smd_ports[i].port;
-		if (!port)
+	for (i = 0; i < MAX_CTRL_PORT; i++) {
+		if (!ctrl_smd_ports[i].port)
 			continue;
+		port = ctrl_smd_ports[i].port;
+
 		spin_lock_irqsave(&port->port_lock, flags);
 
 		c = &port->ctrl_ch;
@@ -677,10 +708,10 @@
 	int			i;
 	unsigned long		flags;
 
-	for (i = 0; i < n_rmnet_ctrl_ports; i++) {
-		port = ctrl_smd_ports[i].port;
-		if (!port)
+	for (i = 0; i < MAX_CTRL_PORT; i++) {
+		if (!ctrl_smd_ports[i].port)
 			continue;
+		port = ctrl_smd_ports[i].port;
 
 		spin_lock_irqsave(&port->port_lock, flags);
 
@@ -727,6 +758,7 @@
 static int __init gsmd_ctrl_init(void)
 {
 	gsmd_ctrl_debugfs_init();
+	online_clients = 0;
 
 	return 0;
 }
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 51776db..baedd03 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -878,6 +878,7 @@
 {
 	int i, j;
 	char *offset;
+	struct mdss_mdp_pipe *vig;
 
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 	mdata->mdp_rev = MDSS_MDP_REG_READ(MDSS_MDP_REG_HW_VERSION);
@@ -899,7 +900,16 @@
 			writel_relaxed(j, offset);
 
 		/* swap */
-		writel_relaxed(i, offset + 4);
+		writel_relaxed(1, offset + 4);
+	}
+	vig = mdata->vig_pipes;
+	for (i = 0; i < mdata->nvig_pipes; i++) {
+		offset = vig[i].base +
+			MDSS_MDP_REG_VIG_HIST_LUT_BASE;
+		for (j = 0; j < ENHIST_LUT_ENTRIES; j++)
+			writel_relaxed(j, offset);
+		/* swap */
+		writel_relaxed(1, offset + 16);
 	}
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 	pr_debug("MDP hw init done\n");
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 25c5871..175a07f 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -249,6 +249,7 @@
 struct mdss_pipe_pp_res {
 	u32 igc_c0_c1[IGC_LUT_ENTRIES];
 	u32 igc_c2[IGC_LUT_ENTRIES];
+	u32 hist_lut[ENHIST_LUT_ENTRIES];
 	struct pp_hist_col_info hist;
 	struct pp_sts_type pp_sts;
 };
@@ -438,13 +439,14 @@
 				struct mdp_histogram_start_req *req);
 int mdss_mdp_histogram_stop(struct mdss_mdp_ctl *ctl, u32 block);
 int mdss_mdp_hist_collect(struct mdss_mdp_ctl *ctl,
-				struct mdp_histogram_data *hist,
-				u32 *hist_data_addr);
+				struct mdp_histogram_data *hist);
 void mdss_mdp_hist_intr_done(u32 isr);
 
 struct mdss_mdp_pipe *mdss_mdp_pipe_alloc(struct mdss_mdp_mixer *mixer,
 					  u32 type);
 struct mdss_mdp_pipe *mdss_mdp_pipe_get(struct mdss_data_type *mdata, u32 ndx);
+struct mdss_mdp_pipe *mdss_mdp_pipe_search(struct mdss_data_type *mdata,
+						  u32 ndx);
 int mdss_mdp_pipe_map(struct mdss_mdp_pipe *pipe);
 void mdss_mdp_pipe_unmap(struct mdss_mdp_pipe *pipe);
 struct mdss_mdp_pipe *mdss_mdp_pipe_alloc_dma(struct mdss_mdp_mixer *mixer);
@@ -466,6 +468,8 @@
 			     struct mdss_mdp_plane_sizes *ps, u32 bwc_mode);
 int mdss_mdp_get_rau_strides(u32 w, u32 h, struct mdss_mdp_format_params *fmt,
 			       struct mdss_mdp_plane_sizes *ps);
+void mdss_mdp_data_calc_offset(struct mdss_mdp_data *data, u16 x, u16 y,
+	struct mdss_mdp_plane_sizes *ps, struct mdss_mdp_format_params *fmt);
 struct mdss_mdp_format_params *mdss_mdp_get_format_params(u32 format);
 int mdss_mdp_put_img(struct mdss_mdp_img_data *data);
 int mdss_mdp_get_img(struct msmfb_data *img, struct mdss_mdp_img_data *data);
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index 4e51100..03a33cd 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -279,8 +279,6 @@
 		return -EINVAL;
 	}
 
-	mutex_lock(&mdss_mdp_ctl_lock);
-	ctl->ref_cnt--;
 	if (ctl->mixer_left) {
 		mdss_mdp_mixer_free(ctl->mixer_left);
 		ctl->mixer_left = NULL;
@@ -289,6 +287,8 @@
 		mdss_mdp_mixer_free(ctl->mixer_right);
 		ctl->mixer_right = NULL;
 	}
+	mutex_lock(&mdss_mdp_ctl_lock);
+	ctl->ref_cnt--;
 	ctl->power_on = false;
 	ctl->start_fnc = NULL;
 	ctl->stop_fnc = NULL;
@@ -437,7 +437,6 @@
 	if (ctl->stop_fnc)
 		ctl->stop_fnc(ctl);
 
-	mdss_mdp_mixer_free(mixer);
 	mdss_mdp_ctl_free(ctl);
 
 	mdss_mdp_ctl_perf_commit(ctl->mdata, MDSS_MDP_PERF_UPDATE_ALL);
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
index 7fbb031..b3f15a7 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
@@ -33,9 +33,11 @@
 	u32 intf_num;
 
 	u32 opmode;
-	u32 format;
+	struct mdss_mdp_format_params *dst_fmt;
 	u16 width;
 	u16 height;
+	struct mdss_mdp_img_rect dst_rect;
+
 	u8 rot90;
 	u32 bwc_mode;
 	int initialized;
@@ -81,48 +83,55 @@
 }
 
 static int mdss_mdp_writeback_addr_setup(struct mdss_mdp_writeback_ctx *ctx,
-					 struct mdss_mdp_data *data)
+					 const struct mdss_mdp_data *in_data)
 {
 	int ret;
+	struct mdss_mdp_data data;
 
-	if (!data)
+	if (!in_data)
 		return -EINVAL;
+	data = *in_data;
 
-	pr_debug("wb_num=%d addr=0x%x\n", ctx->wb_num, data->p[0].addr);
+	pr_debug("wb_num=%d addr=0x%x\n", ctx->wb_num, data.p[0].addr);
 
 	if (ctx->bwc_mode)
-		data->bwc_enabled = 1;
+		data.bwc_enabled = 1;
 
-	ret = mdss_mdp_data_check(data, &ctx->dst_planes);
+	ret = mdss_mdp_data_check(&data, &ctx->dst_planes);
 	if (ret)
 		return ret;
 
-	mdp_wb_write(ctx, MDSS_MDP_REG_WB_DST0_ADDR, data->p[0].addr);
-	mdp_wb_write(ctx, MDSS_MDP_REG_WB_DST1_ADDR, data->p[1].addr);
-	mdp_wb_write(ctx, MDSS_MDP_REG_WB_DST2_ADDR, data->p[2].addr);
-	mdp_wb_write(ctx, MDSS_MDP_REG_WB_DST3_ADDR, data->p[3].addr);
+	mdss_mdp_data_calc_offset(&data, ctx->dst_rect.x, ctx->dst_rect.y,
+			&ctx->dst_planes, ctx->dst_fmt);
+
+	mdp_wb_write(ctx, MDSS_MDP_REG_WB_DST0_ADDR, data.p[0].addr);
+	mdp_wb_write(ctx, MDSS_MDP_REG_WB_DST1_ADDR, data.p[1].addr);
+	mdp_wb_write(ctx, MDSS_MDP_REG_WB_DST2_ADDR, data.p[2].addr);
+	mdp_wb_write(ctx, MDSS_MDP_REG_WB_DST3_ADDR, data.p[3].addr);
 
 	return 0;
 }
 
-static int mdss_mdp_writeback_format_setup(struct mdss_mdp_writeback_ctx *ctx)
+static int mdss_mdp_writeback_format_setup(struct mdss_mdp_writeback_ctx *ctx,
+		u32 format)
 {
 	struct mdss_mdp_format_params *fmt;
 	u32 dst_format, pattern, ystride0, ystride1, outsize, chroma_samp;
 	u32 opmode = ctx->opmode;
 	struct mdss_data_type *mdata;
 
-	pr_debug("wb_num=%d format=%d\n", ctx->wb_num, ctx->format);
+	pr_debug("wb_num=%d format=%d\n", ctx->wb_num, format);
 
-	mdss_mdp_get_plane_sizes(ctx->format, ctx->width, ctx->height,
+	mdss_mdp_get_plane_sizes(format, ctx->width, ctx->height,
 				 &ctx->dst_planes,
 				 ctx->opmode & MDSS_MDP_OP_BWC_EN);
 
-	fmt = mdss_mdp_get_format_params(ctx->format);
+	fmt = mdss_mdp_get_format_params(format);
 	if (!fmt) {
-		pr_err("wb format=%d not supported\n", ctx->format);
+		pr_err("wb format=%d not supported\n", format);
 		return -EINVAL;
 	}
+	ctx->dst_fmt = fmt;
 
 	chroma_samp = fmt->chroma_sample;
 
@@ -190,7 +199,7 @@
 		   (ctx->dst_planes.ystride[1] << 16);
 	ystride1 = (ctx->dst_planes.ystride[2]) |
 		   (ctx->dst_planes.ystride[3] << 16);
-	outsize = (ctx->height << 16) | ctx->width;
+	outsize = (ctx->dst_rect.h << 16) | ctx->dst_rect.w;
 
 	mdp_wb_write(ctx, MDSS_MDP_REG_WB_DST_FORMAT, dst_format);
 	mdp_wb_write(ctx, MDSS_MDP_REG_WB_DST_OP_MODE, opmode);
@@ -217,11 +226,14 @@
 	pr_debug("wfd setup ctl=%d\n", ctl->num);
 
 	ctx->opmode = 0;
-	ctx->format = ctl->dst_format;
 	ctx->width = ctl->width;
 	ctx->height = ctl->height;
+	ctx->dst_rect.x = 0;
+	ctx->dst_rect.y = 0;
+	ctx->dst_rect.w = ctx->width;
+	ctx->dst_rect.h = ctx->height;
 
-	ret = mdss_mdp_writeback_format_setup(ctx);
+	ret = mdss_mdp_writeback_format_setup(ctx, ctl->dst_format);
 	if (ret) {
 		pr_err("format setup failed\n");
 		return ret;
@@ -237,6 +249,7 @@
 	struct mdss_mdp_writeback_ctx *ctx;
 	struct mdss_mdp_writeback_arg *wb_args;
 	struct mdss_mdp_rotator_session *rot;
+	u32 format;
 
 	ctx = (struct mdss_mdp_writeback_ctx *) ctl->priv_data;
 	if (!ctx)
@@ -259,24 +272,26 @@
 	ctx->bwc_mode = rot->bwc_mode;
 	ctx->opmode |= ctx->bwc_mode;
 
-	ctx->width = rot->src_rect.w;
-	ctx->height = rot->src_rect.h;
-
-	ctx->format = rot->format;
+	ctx->width = rot->dst.w;
+	ctx->height = rot->dst.h;
+	ctx->dst_rect.x = rot->dst.x;
+	ctx->dst_rect.y = rot->dst.y;
+	ctx->dst_rect.w = rot->src_rect.w;
+	ctx->dst_rect.h = rot->src_rect.h;
 
 	ctx->rot90 = !!(rot->flags & MDP_ROT_90);
 
 	if (ctx->bwc_mode || ctx->rot90)
-		ctx->format = mdss_mdp_get_rotator_dst_format(rot->format);
+		format = mdss_mdp_get_rotator_dst_format(rot->format);
 	else
-		ctx->format = rot->format;
+		format = rot->format;
 
 	if (ctx->rot90) {
 		ctx->opmode |= BIT(5); /* ROT 90 */
-		swap(ctx->width, ctx->height);
+		swap(ctx->dst_rect.w, ctx->dst_rect.h);
 	}
 
-	return mdss_mdp_writeback_format_setup(ctx);
+	return mdss_mdp_writeback_format_setup(ctx, format);
 }
 
 static int mdss_mdp_writeback_stop(struct mdss_mdp_ctl *ctl)
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index dae3e05..3cce4f9 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -92,8 +92,7 @@
 		return -EOVERFLOW;
 	}
 
-	if (req->dst_rect.w < min_dst_size || req->dst_rect.h < min_dst_size ||
-	    req->dst_rect.w > MAX_DST_W || req->dst_rect.h > MAX_DST_H) {
+	if (req->dst_rect.w < min_dst_size || req->dst_rect.h < min_dst_size) {
 		pr_err("invalid destination resolution (%dx%d)",
 		       req->dst_rect.w, req->dst_rect.h);
 		return -EOVERFLOW;
@@ -227,9 +226,13 @@
 		rot->src_rect.h /= 2;
 	}
 
-	rot->params_changed++;
-
-	req->id = rot->session_id;
+	ret = mdss_mdp_rotator_setup(rot);
+	if (ret == 0) {
+		req->id = rot->session_id;
+	} else {
+		pr_err("Unable to setup rotator session\n");
+		mdss_mdp_rotator_release(rot->session_id);
+	}
 
 	return ret;
 }
@@ -243,11 +246,23 @@
 	struct mdss_mdp_mixer *mixer = NULL;
 	u32 pipe_type, mixer_mux, len, src_format;
 	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+	struct mdp_histogram_start_req hist;
 	int ret;
 
 	if (mdp5_data->ctl == NULL)
 		return -ENODEV;
 
+	if (req->flags & MDP_ROT_90) {
+		pr_err("unsupported inline rotation\n");
+		return -ENOTSUPP;
+	}
+
+	if ((req->dst_rect.w > MAX_DST_W) || (req->dst_rect.h > MAX_DST_H)) {
+		pr_err("exceeded max mixer supported resolution %dx%d\n",
+				req->dst_rect.w, req->dst_rect.h);
+		return -EOVERFLOW;
+	}
+
 	if (req->flags & MDSS_MDP_RIGHT_MIXER)
 		mixer_mux = MDSS_MDP_MIXER_MUX_RIGHT;
 	else
@@ -256,11 +271,6 @@
 	pr_debug("pipe ctl=%u req id=%x mux=%d\n", mdp5_data->ctl->num, req->id,
 			mixer_mux);
 
-	if (req->flags & MDP_ROT_90) {
-		pr_err("unsupported inline rotation\n");
-		return -ENOTSUPP;
-	}
-
 	src_format = req->src.format;
 	if (req->flags & (MDP_SOURCE_ROTATED_90 | MDP_BWC_EN))
 		src_format = mdss_mdp_get_rotator_dst_format(src_format);
@@ -365,7 +375,8 @@
 	pipe->is_fg = req->is_fg;
 	pipe->alpha = req->alpha;
 	pipe->transp = req->transp_mask;
-	pipe->overfetch_disable = fmt->is_yuv;
+	pipe->overfetch_disable = fmt->is_yuv &&
+			!(pipe->flags & MDP_SOURCE_ROTATED_90);
 
 	pipe->req_data = *req;
 
@@ -389,6 +400,31 @@
 							pipe->pp_res.igc_c0_c1;
 			pipe->pp_cfg.igc_cfg.c2_data = pipe->pp_res.igc_c2;
 		}
+		if (pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_HIST_CFG) {
+			if (pipe->pp_cfg.hist_cfg.ops & MDP_PP_OPS_ENABLE) {
+				hist.block = pipe->pp_cfg.hist_cfg.block;
+				hist.frame_cnt =
+					pipe->pp_cfg.hist_cfg.frame_cnt;
+				hist.bit_mask = pipe->pp_cfg.hist_cfg.bit_mask;
+				hist.num_bins = pipe->pp_cfg.hist_cfg.num_bins;
+				mdss_mdp_histogram_start(pipe->mixer->ctl,
+									&hist);
+			} else if (pipe->pp_cfg.hist_cfg.ops &
+							MDP_PP_OPS_DISABLE) {
+				mdss_mdp_histogram_stop(pipe->mixer->ctl,
+						pipe->pp_cfg.hist_cfg.block);
+			}
+		}
+		len = pipe->pp_cfg.hist_lut_cfg.len;
+		if ((pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_HIST_LUT_CFG) &&
+						(len == ENHIST_LUT_ENTRIES)) {
+			ret = copy_from_user(pipe->pp_res.hist_lut,
+					pipe->pp_cfg.hist_lut_cfg.data,
+					sizeof(uint32_t) * len);
+			if (ret)
+				return -ENOMEM;
+			pipe->pp_cfg.hist_lut_cfg.data = pipe->pp_res.hist_lut;
+		}
 	}
 
 	if (pipe->flags & MDP_DEINTERLACE) {
@@ -1457,7 +1493,7 @@
 	int ret = -ENOSYS;
 	struct mdp_histogram_data hist;
 	struct mdp_histogram_start_req hist_req;
-	u32 block, hist_data_addr = 0;
+	u32 block;
 	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 
 	switch (cmd) {
@@ -1488,15 +1524,9 @@
 		if (ret)
 			return ret;
 
-		ret = mdss_mdp_hist_collect(mdp5_data->ctl, &hist,
-					&hist_data_addr);
-		if ((ret == 0) && hist_data_addr) {
-			ret = copy_to_user(hist.c0, (u32 *)hist_data_addr,
-				sizeof(u32) * hist.bin_cnt);
-			if (ret == 0)
-				ret = copy_to_user(argp, &hist,
-						   sizeof(hist));
-		}
+		ret = mdss_mdp_hist_collect(mdp5_data->ctl, &hist);
+		if (!ret)
+			ret = copy_to_user(argp, &hist, sizeof(hist));
 		break;
 	default:
 		break;
@@ -1583,10 +1613,8 @@
 				ret = copy_to_user(argp, &req, sizeof(req));
 		}
 
-		if (ret) {
+		if (ret)
 			pr_debug("OVERLAY_GET failed (%d)\n", ret);
-			ret = -EFAULT;
-		}
 		break;
 
 	case MSMFB_OVERLAY_SET:
@@ -1597,10 +1625,8 @@
 			if (!IS_ERR_VALUE(ret))
 				ret = copy_to_user(argp, &req, sizeof(req));
 		}
-		if (ret) {
+		if (ret)
 			pr_debug("OVERLAY_SET failed (%d)\n", ret);
-			ret = -EFAULT;
-		}
 		break;
 
 
@@ -1629,10 +1655,8 @@
 					mdss_fb_update_backlight(mfd);
 			}
 
-			if (ret) {
+			if (ret)
 				pr_debug("OVERLAY_PLAY failed (%d)\n", ret);
-				ret = -EFAULT;
-			}
 		} else {
 			ret = 0;
 		}
@@ -1646,10 +1670,8 @@
 			if (!ret)
 				ret = mdss_mdp_overlay_play_wait(mfd, &data);
 
-			if (ret) {
+			if (ret)
 				pr_err("OVERLAY_PLAY_WAIT failed (%d)\n", ret);
-				ret = -EFAULT;
-			}
 		} else {
 			ret = 0;
 		}
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index b169c43..242972b 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -27,8 +27,6 @@
 static DEFINE_MUTEX(mdss_mdp_smp_lock);
 static DECLARE_BITMAP(mdss_mdp_smp_mmb_pool, MDSS_MDP_SMP_MMB_BLOCKS);
 
-static struct mdss_mdp_pipe *mdss_mdp_pipe_search(struct mdss_data_type *mdata,
-						  u32 ndx);
 static int mdss_mdp_pipe_free(struct mdss_mdp_pipe *pipe);
 
 static inline void mdss_mdp_pipe_write(struct mdss_mdp_pipe *pipe,
@@ -257,9 +255,11 @@
 		pipe = NULL;
 	}
 
-	if (pipe)
-		pr_debug("type=%x   pnum=%d\n", pipe->type, pipe->num);
-	else
+	if (pipe) {
+		pr_info("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
 		pr_err("no %d type pipes available\n", type);
 
 	return pipe;
@@ -318,7 +318,7 @@
 	return pipe;
 }
 
-static struct mdss_mdp_pipe *mdss_mdp_pipe_search(struct mdss_data_type *mdata,
+struct mdss_mdp_pipe *mdss_mdp_pipe_search(struct mdss_data_type *mdata,
 						  u32 ndx)
 {
 	u32 i;
@@ -487,28 +487,6 @@
 	return 0;
 }
 
-static void mdss_mdp_addr_add_offset(struct mdss_mdp_pipe *pipe,
-				    struct mdss_mdp_data *data)
-{
-	data->p[0].addr += pipe->src.x +
-		(pipe->src.y * pipe->src_planes.ystride[0]);
-	if (data->num_planes > 1) {
-		u8 hmap[] = { 1, 2, 1, 2 };
-		u8 vmap[] = { 1, 1, 2, 2 };
-		u16 xoff = pipe->src.x / hmap[pipe->src_fmt->chroma_sample];
-		u16 yoff = pipe->src.y / vmap[pipe->src_fmt->chroma_sample];
-
-		if (data->num_planes == 2) /* pseudo planar */
-			xoff *= 2;
-		data->p[1].addr += xoff + (yoff * pipe->src_planes.ystride[1]);
-
-		if (data->num_planes > 2) { /* planar */
-			data->p[2].addr += xoff +
-				(yoff * pipe->src_planes.ystride[2]);
-		}
-	}
-}
-
 int mdss_mdp_pipe_addr_setup(struct mdss_data_type *mdata, u32 *offsets,
 				u32 *ftch_id, u32 type, u32 num_base, u32 len)
 {
@@ -571,7 +549,8 @@
 		return ret;
 
 	if (pipe->overfetch_disable)
-		mdss_mdp_addr_add_offset(pipe, data);
+		mdss_mdp_data_calc_offset(data, pipe->src.x, pipe->src.y,
+			&pipe->src_planes, pipe->src_fmt);
 
 	/* planar format expects YCbCr, swap chroma planes if YCrCb */
 	if (!is_rot && (pipe->src_fmt->fetch_planes == MDSS_MDP_PLANE_PLANAR) &&
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 2e20eb6..cf9a8b6 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -78,7 +78,7 @@
 
 #define MDSS_BLOCK_DISP_NUM	(MDP_BLOCK_MAX - MDP_LOGICAL_BLOCK_DISP_0)
 
-#define HIST_WAIT_TIMEOUT(frame) ((60 * HZ * (frame)) / 1000)
+#define HIST_WAIT_TIMEOUT(frame) ((75 * HZ * (frame)) / 1000)
 /* hist collect state */
 enum {
 	HIST_UNKNOWN,
@@ -154,11 +154,13 @@
 };
 
 static DEFINE_MUTEX(mdss_pp_mutex);
-static DEFINE_SPINLOCK(mdss_hist_lock);
-static DEFINE_MUTEX(mdss_mdp_hist_mutex);
 static struct mdss_pp_res_type *mdss_pp_res;
 
-static void pp_hist_read(u32 v_base, struct pp_hist_col_info *hist_info);
+static void pp_hist_read(char __iomem *v_base,
+				struct pp_hist_col_info *hist_info);
+static int pp_histogram_setup(u32 *op, u32 block, struct mdss_mdp_mixer *mix);
+static int pp_histogram_disable(struct pp_hist_col_info *hist_info,
+					u32 done_bit, char __iomem *ctl_base);
 static void pp_update_pcc_regs(u32 offset,
 				struct mdp_pcc_cfg_data *cfg_ptr);
 static void pp_update_igc_lut(struct mdp_igc_lut_data *cfg,
@@ -167,7 +169,8 @@
 				struct mdp_ar_gc_lut_data *lut_data);
 static void pp_update_argc_lut(u32 offset,
 				struct mdp_pgc_lut_data *config);
-static void pp_update_hist_lut(u32 offset, struct mdp_hist_lut_data *cfg);
+static void pp_update_hist_lut(char __iomem *base,
+				struct mdp_hist_lut_data *cfg);
 static void pp_pa_config(unsigned long flags, u32 base,
 				struct pp_sts_type *pp_sts,
 				struct mdp_pa_cfg *pa_config);
@@ -178,7 +181,7 @@
 				struct pp_sts_type *pp_sts,
 				struct mdp_igc_lut_data *igc_config,
 				u32 pipe_num);
-static void pp_enhist_config(unsigned long flags, u32 base,
+static void pp_enhist_config(unsigned long flags, char __iomem *base,
 				struct pp_sts_type *pp_sts,
 				struct mdp_hist_lut_data *enhist_cfg);
 static void pp_sharp_config(char __iomem *offset,
@@ -379,7 +382,7 @@
 	}
 }
 
-static void pp_enhist_config(unsigned long flags, u32 base,
+static void pp_enhist_config(unsigned long flags, char __iomem *base,
 				struct pp_sts_type *pp_sts,
 				struct mdp_hist_lut_data *enhist_cfg)
 {
@@ -419,6 +422,7 @@
 {
 	u32 opmode = 0, base = 0;
 	unsigned long flags = 0;
+	char __iomem *offset;
 
 	pr_debug("pnum=%x\n", pipe->num);
 
@@ -452,6 +456,8 @@
 		}
 	}
 
+	pp_histogram_setup(&opmode, MDSS_PP_SSPP_CFG | pipe->num, pipe->mixer);
+
 	if (pipe->flags & MDP_OVERLAY_PP_CFG_EN) {
 		if (pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_PA_CFG) {
 			flags = PP_FLAGS_DIRTY_PA;
@@ -463,6 +469,26 @@
 			if (pipe->pp_res.pp_sts.pa_sts & PP_STS_ENABLE)
 				opmode |= (1 << 4); /* PA_EN */
 		}
+
+		if (pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_HIST_LUT_CFG) {
+			pp_enhist_config(PP_FLAGS_DIRTY_ENHIST,
+				pipe->base + MDSS_MDP_REG_VIG_HIST_LUT_BASE,
+				&pipe->pp_res.pp_sts,
+				&pipe->pp_cfg.hist_lut_cfg);
+		}
+	}
+
+	if (pipe->pp_res.pp_sts.enhist_sts & PP_STS_ENABLE) {
+		/* Enable HistLUT and PA */
+		opmode |= BIT(10) | BIT(4);
+		if (!(pipe->pp_res.pp_sts.pa_sts & PP_STS_ENABLE)) {
+			/* Program default value */
+			offset = pipe->base + MDSS_MDP_REG_VIG_PA_BASE;
+			writel_relaxed(0, offset);
+			writel_relaxed(0, offset + 4);
+			writel_relaxed(0, offset + 8);
+			writel_relaxed(0, offset + 12);
+		}
 	}
 
 	*op = opmode;
@@ -692,6 +718,17 @@
 
 void mdss_mdp_pipe_sspp_term(struct mdss_mdp_pipe *pipe)
 {
+	u32 done_bit;
+	struct pp_hist_col_info *hist_info;
+	char __iomem *ctl_base;
+
+	if (!pipe && pipe->pp_res.hist.col_en) {
+		done_bit = 3 << (pipe->num * 4);
+		hist_info = &pipe->pp_res.hist;
+		ctl_base = pipe->base +
+			MDSS_MDP_REG_VIG_HIST_CTL_BASE;
+		pp_histogram_disable(hist_info, done_bit, ctl_base);
+	}
 	memset(&pipe->pp_cfg, 0, sizeof(struct mdp_overlay_pp_params));
 	memset(&pipe->pp_res, 0, sizeof(struct mdss_pipe_pp_res));
 }
@@ -784,16 +821,86 @@
 	return 0;
 }
 
+static char __iomem *mdss_mdp_get_dspp_addr_off(u32 dspp_num)
+{
+	struct mdss_data_type *mdata;
+	struct mdss_mdp_mixer *mixer;
+
+	mdata = mdss_mdp_get_mdata();
+	if (mdata->nmixers_intf <= dspp_num) {
+		pr_err("Invalid dspp_num=%d", dspp_num);
+		return ERR_PTR(-EINVAL);
+	}
+	mixer = mdata->mixer_intf + dspp_num;
+	return mixer->dspp_base;
+}
+
+/* Assumes that function will be called from within clock enabled space*/
+static int pp_histogram_setup(u32 *op, u32 block, struct mdss_mdp_mixer *mix)
+{
+	int ret = -EINVAL;
+	char __iomem *base;
+	u32 op_flags, kick_base, col_state;
+	struct mdss_data_type *mdata;
+	struct mdss_mdp_pipe *pipe;
+	struct pp_hist_col_info *hist_info;
+	unsigned long flag;
+
+	if (mix && (PP_LOCAT(block) == MDSS_PP_DSPP_CFG)) {
+		/* HIST_EN & AUTO_CLEAR */
+		op_flags = BIT(16) | BIT(17);
+		hist_info = &mdss_pp_res->dspp_hist[mix->num];
+		base = mdss_mdp_get_dspp_addr_off(PP_BLOCK(block));
+		kick_base = MDSS_MDP_REG_DSPP_HIST_CTL_BASE;
+	} else if (PP_LOCAT(block) == MDSS_PP_SSPP_CFG) {
+		mdata = mdss_mdp_get_mdata();
+		pipe = mdss_mdp_pipe_get(mdata, BIT(PP_BLOCK(block)));
+		if (IS_ERR_OR_NULL(pipe)) {
+			pr_debug("pipe DNE (%d)", (u32) BIT(PP_BLOCK(block)));
+			ret = -ENODEV;
+			goto error;
+		}
+		/* HIST_EN & AUTO_CLEAR */
+		op_flags = BIT(8) + BIT(9);
+		hist_info = &pipe->pp_res.hist;
+		base = pipe->base;
+		kick_base = MDSS_MDP_REG_VIG_HIST_CTL_BASE;
+		mdss_mdp_pipe_unmap(pipe);
+	} else {
+		pr_warn("invalid histogram location (%d)", block);
+		goto error;
+	}
+
+	if (hist_info->col_en) {
+		*op |= op_flags;
+		mutex_lock(&hist_info->hist_mutex);
+		spin_lock_irqsave(&hist_info->hist_lock, flag);
+		col_state = hist_info->col_state;
+		if (hist_info->is_kick_ready &&
+			((col_state == HIST_IDLE) ||
+			((false == hist_info->read_request) &&
+				col_state == HIST_READY))) {
+			/* Kick off collection */
+			writel_relaxed(1, base + kick_base);
+			hist_info->col_state = HIST_START;
+		}
+		spin_unlock_irqrestore(&hist_info->hist_lock, flag);
+		mutex_unlock(&hist_info->hist_mutex);
+	}
+	ret = 0;
+error:
+	return ret;
+}
+
 static int pp_dspp_setup(u32 disp_num, struct mdss_mdp_ctl *ctl,
 				struct mdss_mdp_mixer *mixer)
 {
 	u32 flags, base, offset, dspp_num, opmode = 0;
 	struct mdp_dither_cfg_data *dither_cfg;
-	struct pp_hist_col_info *hist_info;
 	struct mdp_pgc_lut_data *pgc_config;
 	struct pp_sts_type *pp_sts;
-	u32 data, col_state;
-	unsigned long flag;
+	u32 data;
+	char __iomem *basel;
 	int i, ret = 0;
 
 	if (!mixer || !ctl)
@@ -805,28 +912,13 @@
 		(dspp_num >= MDSS_MDP_MAX_DSPP))
 		return -EINVAL;
 	base = MDSS_MDP_REG_DSPP_OFFSET(dspp_num);
-	hist_info = &mdss_pp_res->dspp_hist[dspp_num];
+	basel = mdss_mdp_get_dspp_addr_off(dspp_num);
 
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 
-	if (hist_info->col_en) {
-		/* HIST_EN & AUTO_CLEAR */
-		opmode |= (1 << 16) | (1 << 17);
-		mutex_lock(&mdss_mdp_hist_mutex);
-		spin_lock_irqsave(&mdss_hist_lock, flag);
-		col_state = hist_info->col_state;
-		if (hist_info->is_kick_ready &&
-				((col_state == HIST_IDLE) ||
-				((false == hist_info->read_request) &&
-						col_state == HIST_READY))) {
-			/* Kick off collection */
-			MDSS_MDP_REG_WRITE(base +
-				MDSS_MDP_REG_DSPP_HIST_CTL_BASE, 1);
-			hist_info->col_state = HIST_START;
-		}
-		spin_unlock_irqrestore(&mdss_hist_lock, flag);
-		mutex_unlock(&mdss_mdp_hist_mutex);
-	}
+	ret = pp_histogram_setup(&opmode, MDSS_PP_DSPP_CFG | dspp_num, mixer);
+	if (ret)
+		goto dspp_exit;
 
 	if (disp_num < MDSS_BLOCK_DISP_NUM)
 		flags = mdss_pp_res->pp_disp_flags[disp_num];
@@ -834,7 +926,7 @@
 		flags = 0;
 
 	/* nothing to update */
-	if ((!flags) && (!(hist_info->col_en)))
+	if ((!flags) && (!(opmode)))
 		goto dspp_exit;
 
 	pp_sts = &mdss_pp_res->pp_dspp_sts[dspp_num];
@@ -848,7 +940,7 @@
 	pp_igc_config(flags, MDSS_MDP_REG_IGC_DSPP_BASE, pp_sts,
 				&mdss_pp_res->igc_disp_cfg[disp_num], dspp_num);
 
-	pp_enhist_config(flags, base + MDSS_MDP_REG_DSPP_HIST_LUT_BASE,
+	pp_enhist_config(flags, basel + MDSS_MDP_REG_DSPP_HIST_LUT_BASE,
 			pp_sts, &mdss_pp_res->enhist_disp_cfg[disp_num]);
 
 	if (pp_sts->pa_sts & PP_STS_ENABLE)
@@ -922,7 +1014,7 @@
 	if (pp_sts->pgc_sts & PP_STS_ENABLE)
 		opmode |= (1 << 22);
 
-	MDSS_MDP_REG_WRITE(base + MDSS_MDP_REG_DSPP_OP_MODE, opmode);
+	writel_relaxed(opmode, basel + MDSS_MDP_REG_DSPP_OP_MODE);
 	mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, BIT(13 + dspp_num));
 	wmb();
 dspp_exit:
@@ -1056,7 +1148,9 @@
 
 int mdss_mdp_pp_init(struct device *dev)
 {
-	int ret = 0;
+	int i, ret = 0;
+	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+	struct mdss_mdp_pipe *vig;
 
 	mutex_lock(&mdss_pp_mutex);
 	if (!mdss_pp_res) {
@@ -1066,6 +1160,18 @@
 			pr_err("%s mdss_pp_res allocation failed!", __func__);
 			ret = -ENOMEM;
 		}
+
+		for (i = 0; i < MDSS_MDP_MAX_DSPP; i++) {
+			mutex_init(&mdss_pp_res->dspp_hist[i].hist_mutex);
+			spin_lock_init(&mdss_pp_res->dspp_hist[i].hist_lock);
+		}
+	}
+	if (mdata) {
+		vig = mdata->vig_pipes;
+		for (i = 0; i < mdata->nvig_pipes; i++) {
+			mutex_init(&vig[i].pp_res.hist.hist_mutex);
+			spin_lock_init(&vig[i].pp_res.hist.hist_lock);
+		}
 	}
 	mutex_unlock(&mdss_pp_mutex);
 	return ret;
@@ -1533,13 +1639,17 @@
 }
 
 /* Note: Assumes that its inputs have been checked by calling function */
-static void pp_update_hist_lut(u32 offset, struct mdp_hist_lut_data *cfg)
+static void pp_update_hist_lut(char __iomem *offset,
+				struct mdp_hist_lut_data *cfg)
 {
 	int i;
 	for (i = 0; i < ENHIST_LUT_ENTRIES; i++)
-		MDSS_MDP_REG_WRITE(offset, cfg->data[i]);
+		writel_relaxed(cfg->data[i], offset);
 	/* swap */
-	MDSS_MDP_REG_WRITE(offset + 4, 1);
+	if (PP_LOCAT(cfg->block) == MDSS_PP_DSPP_CFG)
+		writel_relaxed(1, offset + 4);
+	else
+		writel_relaxed(1, offset + 16);
 }
 
 int mdss_mdp_argc_config(struct mdss_mdp_ctl *ctl,
@@ -1562,7 +1672,7 @@
 	mutex_lock(&mdss_pp_mutex);
 
 	disp_num = PP_BLOCK(config->block) - MDP_LOGICAL_BLOCK_DISP_0;
-	switch (config->block & MDSS_PP_LOCATION_MASK) {
+	switch (PP_LOCAT(config->block)) {
 	case MDSS_PP_LM_CFG:
 		argc_offset = MDSS_MDP_REG_LM_OFFSET(dspp_num) +
 			MDSS_MDP_REG_LM_GC_LUT_BASE;
@@ -1658,12 +1768,12 @@
 	if (!ctl)
 		return -EINVAL;
 
-	if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
-		(config->block >= MDP_BLOCK_MAX))
+	if ((PP_BLOCK(config->block) < MDP_LOGICAL_BLOCK_DISP_0) ||
+		(PP_BLOCK(config->block) >= MDP_BLOCK_MAX))
 		return -EINVAL;
 
 	mutex_lock(&mdss_pp_mutex);
-	disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
+	disp_num = PP_BLOCK(config->block) - MDP_LOGICAL_BLOCK_DISP_0;
 
 	if (config->ops & MDP_PP_OPS_READ) {
 		ret = pp_get_dspp_num(disp_num, &dspp_num);
@@ -1821,124 +1931,205 @@
 		mdss_mdp_pp_setup(ctl);
 	return ret;
 }
-static void pp_hist_read(u32 v_base, struct pp_hist_col_info *hist_info)
+static void pp_hist_read(char __iomem *v_base,
+				struct pp_hist_col_info *hist_info)
 {
 	int i, i_start;
 	u32 data;
-	data = MDSS_MDP_REG_READ(v_base);
+	data = readl_relaxed(v_base);
 	i_start = data >> 24;
 	hist_info->data[i_start] = data & 0xFFFFFF;
 	for (i = i_start + 1; i < HIST_V_SIZE; i++)
-		hist_info->data[i] = MDSS_MDP_REG_READ(v_base) & 0xFFFFFF;
+		hist_info->data[i] = readl_relaxed(v_base) & 0xFFFFFF;
 	for (i = 0; i < i_start - 1; i++)
-		hist_info->data[i] = MDSS_MDP_REG_READ(v_base) & 0xFFFFFF;
+		hist_info->data[i] = readl_relaxed(v_base) & 0xFFFFFF;
 	hist_info->hist_cnt_read++;
 }
 
-int mdss_mdp_histogram_start(struct mdss_mdp_ctl *ctl,
-					struct mdp_histogram_start_req *req)
+/* Assumes that relevant clocks are enabled */
+static int pp_histogram_enable(struct pp_hist_col_info *hist_info,
+				struct mdp_histogram_start_req *req,
+				u32 shift_bit, char __iomem *ctl_base)
 {
-	u32 ctl_base, done_shift_bit;
+	unsigned long flag;
+	int ret = 0;
+	mutex_lock(&hist_info->hist_mutex);
+	/* check if it is idle */
+	if (hist_info->col_en) {
+		pr_info("%s Hist collection has already been enabled %d",
+			__func__, (u32) ctl_base);
+		ret = -EINVAL;
+		goto exit;
+	}
+	hist_info->frame_cnt = req->frame_cnt;
+	init_completion(&hist_info->comp);
+	hist_info->hist_cnt_read = 0;
+	hist_info->hist_cnt_sent = 0;
+	hist_info->hist_cnt_time = 0;
+	spin_lock_irqsave(&hist_info->hist_lock, flag);
+	hist_info->read_request = false;
+	hist_info->col_state = HIST_RESET;
+	hist_info->col_en = true;
+	spin_unlock_irqrestore(&hist_info->hist_lock, flag);
+	hist_info->is_kick_ready = false;
+	mdss_mdp_hist_irq_enable(3 << shift_bit);
+	writel_relaxed(req->frame_cnt, ctl_base + 8);
+	/* Kick out reset start */
+	writel_relaxed(1, ctl_base + 4);
+exit:
+	mutex_unlock(&hist_info->hist_mutex);
+	return ret;
+}
+
+int mdss_mdp_histogram_start(struct mdss_mdp_ctl *ctl,
+				struct mdp_histogram_start_req *req)
+{
+	u32 done_shift_bit;
+	char __iomem *ctl_base;
 	struct pp_hist_col_info *hist_info;
 	int i, ret = 0;
 	u32 disp_num, dspp_num = 0;
 	u32 mixer_cnt, mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
-	unsigned long flag;
-
+	struct mdss_mdp_pipe *pipe;
+	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
 	if (!ctl)
 		return -EINVAL;
 
-	if ((req->block < MDP_LOGICAL_BLOCK_DISP_0) ||
-		(req->block >= MDP_BLOCK_MAX))
+	if ((PP_BLOCK(req->block) < MDP_LOGICAL_BLOCK_DISP_0) ||
+		(PP_BLOCK(req->block) >= MDP_BLOCK_MAX))
 		return -EINVAL;
 
-	mutex_lock(&mdss_mdp_hist_mutex);
-	disp_num = req->block - MDP_LOGICAL_BLOCK_DISP_0;
+	disp_num = PP_BLOCK(req->block) - MDP_LOGICAL_BLOCK_DISP_0;
 	mixer_cnt = mdss_mdp_get_ctl_mixers(disp_num, mixer_id);
 
 	if (!mixer_cnt) {
 		pr_err("%s, no dspp connects to disp %d",
 			__func__, disp_num);
 		ret = -EPERM;
-		goto hist_start_exit;
+		goto hist_exit;
 	}
 	if (mixer_cnt >= MDSS_MDP_MAX_DSPP) {
 		pr_err("%s, Too many dspp connects to disp %d",
 			__func__, mixer_cnt);
 		ret = -EPERM;
-		goto hist_start_exit;
+		goto hist_exit;
 	}
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
-	for (i = 0; i < mixer_cnt; i++) {
-		dspp_num = mixer_id[i];
-		hist_info = &mdss_pp_res->dspp_hist[dspp_num];
-		done_shift_bit = (dspp_num * 4) + 12;
-		/* check if it is idle */
-		if (hist_info->col_en) {
-			mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
-			pr_info("%s Hist collection has already been enabled %d",
-				__func__, dspp_num);
-			goto hist_start_exit;
+
+	if (PP_LOCAT(req->block) == MDSS_PP_SSPP_CFG) {
+		i = MDSS_PP_ARG_MASK & req->block;
+		if (!i) {
+			ret = -EINVAL;
+			pr_warn("Must pass pipe arguments, %d", i);
+			goto hist_exit;
 		}
-		spin_lock_irqsave(&mdss_hist_lock, flag);
-		hist_info->frame_cnt = req->frame_cnt;
-		init_completion(&hist_info->comp);
-		hist_info->hist_cnt_read = 0;
-		hist_info->hist_cnt_sent = 0;
-		hist_info->read_request = false;
-		hist_info->col_state = HIST_RESET;
-		hist_info->col_en = true;
-		hist_info->is_kick_ready = false;
-		spin_unlock_irqrestore(&mdss_hist_lock, flag);
-		mdss_pp_res->hist_col[disp_num][i] =
-			&mdss_pp_res->dspp_hist[dspp_num];
-		mdss_mdp_hist_irq_enable(3 << done_shift_bit);
-		ctl_base = MDSS_MDP_REG_DSPP_OFFSET(dspp_num) +
-			  MDSS_MDP_REG_DSPP_HIST_CTL_BASE;
-		MDSS_MDP_REG_WRITE(ctl_base + 8, req->frame_cnt);
-		/* Kick out reset start */
-		MDSS_MDP_REG_WRITE(ctl_base + 4, 1);
+
+		for (i = 0; i < MDSS_PP_ARG_NUM; i++) {
+			if (!PP_ARG(i, req->block))
+				continue;
+			pipe = mdss_mdp_pipe_get(mdata, BIT(i));
+			if (IS_ERR_OR_NULL(pipe))
+				continue;
+			if (!pipe || pipe->num > MDSS_MDP_SSPP_VIG2) {
+				ret = -EINVAL;
+				pr_warn("Invalid Hist pipe (%d)", i);
+				goto hist_exit;
+			}
+			done_shift_bit = (pipe->num * 4);
+			hist_info = &pipe->pp_res.hist;
+			ctl_base = pipe->base +
+				MDSS_MDP_REG_VIG_HIST_CTL_BASE;
+			ret = pp_histogram_enable(hist_info, req,
+						done_shift_bit,	ctl_base);
+			mdss_mdp_pipe_unmap(pipe);
+		}
+	} else if (PP_LOCAT(req->block) == MDSS_PP_DSPP_CFG) {
+		for (i = 0; i < mixer_cnt; i++) {
+			dspp_num = mixer_id[i];
+			done_shift_bit = (dspp_num * 4) + 12;
+			hist_info = &mdss_pp_res->dspp_hist[dspp_num];
+			ctl_base = mdss_mdp_get_dspp_addr_off(dspp_num) +
+				MDSS_MDP_REG_DSPP_HIST_CTL_BASE;
+			ret = pp_histogram_enable(hist_info, req,
+						done_shift_bit,	ctl_base);
+			mdss_pp_res->pp_disp_flags[disp_num] |=
+							PP_FLAGS_DIRTY_HIST_COL;
+		}
 	}
-	for (i = mixer_cnt; i < MDSS_MDP_MAX_DSPP; i++)
-		mdss_pp_res->hist_col[disp_num][i] = 0;
-	mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_HIST_COL;
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
-hist_start_exit:
-	mutex_unlock(&mdss_mdp_hist_mutex);
-	if (!ret) {
+
+hist_exit:
+	if (!ret && (PP_LOCAT(req->block) == MDSS_PP_DSPP_CFG)) {
 		mdss_mdp_pp_setup(ctl);
 		/* wait for a frame to let histrogram enable itself */
+		/* TODO add hysteresis value to be able to remove this sleep */
 		usleep(41666);
 		for (i = 0; i < mixer_cnt; i++) {
 			dspp_num = mixer_id[i];
 			hist_info = &mdss_pp_res->dspp_hist[dspp_num];
-			mutex_lock(&mdss_mdp_hist_mutex);
-			spin_lock_irqsave(&mdss_hist_lock, flag);
+			mutex_lock(&hist_info->hist_mutex);
 			hist_info->is_kick_ready = true;
-			spin_unlock_irqrestore(&mdss_hist_lock, flag);
-			mutex_unlock(&mdss_mdp_hist_mutex);
+			mutex_unlock(&hist_info->hist_mutex);
+		}
+	} else if (!ret) {
+		for (i = 0; i < MDSS_PP_ARG_NUM; i++) {
+			if (!PP_ARG(i, req->block))
+				continue;
+			pr_info("PP_ARG(%d) = %d", i, PP_ARG(i, req->block));
+			pipe = mdss_mdp_pipe_get(mdata, BIT(i));
+			if (IS_ERR_OR_NULL(pipe))
+				continue;
+			hist_info = &pipe->pp_res.hist;
+			hist_info->is_kick_ready = true;
+			mdss_mdp_pipe_unmap(pipe);
 		}
 	}
 	return ret;
 }
 
+static int pp_histogram_disable(struct pp_hist_col_info *hist_info,
+					u32 done_bit, char __iomem *ctl_base)
+{
+	int ret = 0;
+	unsigned long flag;
+	mutex_lock(&hist_info->hist_mutex);
+	if (hist_info->col_en == false) {
+		pr_debug("Histogram already disabled (%d)", (u32) ctl_base);
+		ret = -EINVAL;
+		goto exit;
+	}
+	complete_all(&hist_info->comp);
+	spin_lock_irqsave(&hist_info->hist_lock, flag);
+	hist_info->col_en = false;
+	hist_info->col_state = HIST_UNKNOWN;
+	spin_unlock_irqrestore(&hist_info->hist_lock, flag);
+	hist_info->is_kick_ready = false;
+	mdss_mdp_hist_irq_disable(done_bit);
+	writel_relaxed(BIT(1), ctl_base);/* cancel */
+	ret = 0;
+exit:
+	mutex_unlock(&hist_info->hist_mutex);
+	return ret;
+}
+
 int mdss_mdp_histogram_stop(struct mdss_mdp_ctl *ctl, u32 block)
 {
 	int i, ret = 0;
-	u32 dspp_num, disp_num, ctl_base, done_bit;
+	char __iomem *ctl_base;
+	u32 dspp_num, disp_num, done_bit;
 	struct pp_hist_col_info *hist_info;
 	u32 mixer_cnt, mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
-	unsigned long flag;
+	struct mdss_mdp_pipe *pipe;
+	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
 
 	if (!ctl)
 		return -EINVAL;
 
-	if ((block < MDP_LOGICAL_BLOCK_DISP_0) ||
-		(block >= MDP_BLOCK_MAX))
+	if ((PP_BLOCK(block) < MDP_LOGICAL_BLOCK_DISP_0) ||
+		(PP_BLOCK(block) >= MDP_BLOCK_MAX))
 		return -EINVAL;
 
-	mutex_lock(&mdss_mdp_hist_mutex);
-	disp_num = block - MDP_LOGICAL_BLOCK_DISP_0;
+	disp_num = PP_BLOCK(block) - MDP_LOGICAL_BLOCK_DISP_0;
 	mixer_cnt = mdss_mdp_get_ctl_mixers(disp_num, mixer_id);
 
 	if (!mixer_cnt) {
@@ -1954,162 +2145,312 @@
 		goto hist_stop_exit;
 	}
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
-	for (i = 0; i < mixer_cnt; i++) {
-		dspp_num = mixer_id[i];
-		hist_info = &mdss_pp_res->dspp_hist[dspp_num];
-		done_bit = 3 << ((dspp_num * 4) + 12);
-		ctl_base = MDSS_MDP_REG_DSPP_OFFSET(dspp_num) +
-			  MDSS_MDP_REG_DSPP_HIST_CTL_BASE;
-		if (hist_info->col_en == false) {
-			mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+	if (PP_LOCAT(block) == MDSS_PP_SSPP_CFG) {
+		i = MDSS_PP_ARG_MASK & block;
+		if (!i) {
+			pr_warn("Must pass pipe arguments, %d", i);
 			goto hist_stop_exit;
 		}
-		complete_all(&hist_info->comp);
-		spin_lock_irqsave(&mdss_hist_lock, flag);
-		hist_info->col_en = false;
-		hist_info->col_state = HIST_UNKNOWN;
-		hist_info->is_kick_ready = false;
-		spin_unlock_irqrestore(&mdss_hist_lock, flag);
-		mdss_mdp_hist_irq_disable(done_bit);
-		MDSS_MDP_REG_WRITE(ctl_base, (1 << 1));/* cancel */
+
+		for (i = 0; i < MDSS_PP_ARG_NUM; i++) {
+			if (!PP_ARG(i, block))
+				continue;
+			pipe = mdss_mdp_pipe_get(mdata, BIT(i));
+			if (IS_ERR_OR_NULL(pipe) ||
+					pipe->num > MDSS_MDP_SSPP_VIG2) {
+				pr_warn("Invalid Hist pipe (%d)", i);
+				continue;
+			}
+			done_bit = 3 << (pipe->num * 4);
+			hist_info = &pipe->pp_res.hist;
+			ctl_base = pipe->base +
+				MDSS_MDP_REG_VIG_HIST_CTL_BASE;
+			ret = pp_histogram_disable(hist_info, done_bit,
+								ctl_base);
+			mdss_mdp_pipe_unmap(pipe);
+			if (ret)
+				goto hist_stop_exit;
+		}
+	} else if (PP_LOCAT(block) == MDSS_PP_DSPP_CFG) {
+		for (i = 0; i < mixer_cnt; i++) {
+			dspp_num = mixer_id[i];
+			done_bit = 3 << ((dspp_num * 4) + 12);
+			hist_info = &mdss_pp_res->dspp_hist[dspp_num];
+			ctl_base = mdss_mdp_get_dspp_addr_off(dspp_num) +
+				  MDSS_MDP_REG_DSPP_HIST_CTL_BASE;
+			ret = pp_histogram_disable(hist_info, done_bit,
+								ctl_base);
+			if (ret)
+				goto hist_stop_exit;
+			mdss_pp_res->pp_disp_flags[disp_num] |=
+							PP_FLAGS_DIRTY_HIST_COL;
+		}
 	}
-	for (i = 0; i < MDSS_MDP_MAX_DSPP; i++)
-		mdss_pp_res->hist_col[disp_num][i] = 0;
-	mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_HIST_COL;
-	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 hist_stop_exit:
-	mutex_unlock(&mdss_mdp_hist_mutex);
-	if (!ret)
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+	if (!ret && (PP_LOCAT(block) == MDSS_PP_DSPP_CFG))
 		mdss_mdp_pp_setup(ctl);
 	return ret;
 }
 
-int mdss_mdp_hist_collect(struct mdss_mdp_ctl *ctl,
-					struct mdp_histogram_data *hist,
-					u32 *hist_data_addr)
+static int pp_hist_collect(struct mdss_mdp_ctl *ctl,
+				struct mdp_histogram_data *hist,
+				struct pp_hist_col_info *hist_info,
+				char __iomem *ctl_base)
 {
-	int i, j, wait_ret, ret = 0;
-	u32 timeout, v_base;
-	struct pp_hist_col_info *hist_info;
-	u32 dspp_num, disp_num, ctl_base;
-	u32 mixer_cnt, mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
+	int wait_ret, ret = 0;
+	u32 timeout;
+	char __iomem *v_base;
 	unsigned long flag;
+	struct mdss_pipe_pp_res *res;
+	struct mdss_mdp_pipe *pipe;
+
+	mutex_lock(&hist_info->hist_mutex);
+	if ((hist_info->col_en == 0) ||
+			(hist_info->col_state == HIST_UNKNOWN)) {
+		ret = -EINVAL;
+		goto hist_collect_exit;
+	}
+	spin_lock_irqsave(&hist_info->hist_lock, flag);
+	/* wait for hist done if cache has no data */
+	if (hist_info->col_state != HIST_READY) {
+		hist_info->read_request = true;
+		spin_unlock_irqrestore(&hist_info->hist_lock, flag);
+		timeout = HIST_WAIT_TIMEOUT(hist_info->frame_cnt);
+		mutex_unlock(&hist_info->hist_mutex);
+		/* flush updates before wait*/
+		if (PP_LOCAT(hist->block) == MDSS_PP_DSPP_CFG)
+			mdss_mdp_pp_setup(ctl);
+		if (PP_LOCAT(hist->block) == MDSS_PP_SSPP_CFG) {
+			res = container_of(hist_info, struct mdss_pipe_pp_res,
+						hist);
+			pipe = container_of(res, struct mdss_mdp_pipe, pp_res);
+			pipe->params_changed++;
+		}
+		wait_ret = wait_for_completion_killable_timeout(
+				&(hist_info->comp), timeout);
+
+		mutex_lock(&hist_info->hist_mutex);
+		if (wait_ret == 0) {
+			ret = -ETIMEDOUT;
+			spin_lock_irqsave(&hist_info->hist_lock, flag);
+			pr_debug("bin collection timedout, state %d",
+					hist_info->col_state);
+			/*
+			 * When the histogram has timed out (usually
+			 * underrun) change the SW state back to idle
+			 * since histogram hardware will have done the
+			 * same. Histogram data also needs to be
+			 * cleared in this case, which is done by the
+			 * histogram being read (triggered by READY
+			 * state, which also moves the histogram SW back
+			 * to IDLE).
+			 */
+			hist_info->hist_cnt_time++;
+			hist_info->col_state = HIST_READY;
+			spin_unlock_irqrestore(&hist_info->hist_lock, flag);
+		} else if (wait_ret < 0) {
+			ret = -EINTR;
+			pr_debug("%s: bin collection interrupted",
+					__func__);
+			goto hist_collect_exit;
+		}
+		if (hist_info->col_state != HIST_READY) {
+			ret = -ENODATA;
+			pr_debug("%s: state is not ready: %d",
+					__func__, hist_info->col_state);
+			goto hist_collect_exit;
+		}
+	} else {
+		spin_unlock_irqrestore(&hist_info->hist_lock, flag);
+	}
+	spin_lock_irqsave(&hist_info->hist_lock, flag);
+	if (hist_info->col_state == HIST_READY) {
+		spin_unlock_irqrestore(&hist_info->hist_lock, flag);
+		v_base = ctl_base + 0x1C;
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+		pp_hist_read(v_base, hist_info);
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+		spin_lock_irqsave(&hist_info->hist_lock, flag);
+		hist_info->read_request = false;
+		hist_info->col_state = HIST_IDLE;
+	}
+	spin_unlock_irqrestore(&hist_info->hist_lock, flag);
+hist_collect_exit:
+	mutex_unlock(&hist_info->hist_mutex);
+	return ret;
+}
+
+int mdss_mdp_hist_collect(struct mdss_mdp_ctl *ctl,
+					struct mdp_histogram_data *hist)
+{
+	int i, j, off, ret = 0;
+	struct pp_hist_col_info *hist_info;
+	u32 dspp_num, disp_num;
+	char __iomem *ctl_base;
+	u32 hist_cnt, mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
+	u32 *hist_concat = NULL;
+	u32 *hist_data_addr;
+	u32 pipe_cnt = 0;
+	u32 pipe_num = MDSS_MDP_SSPP_VIG0;
+	struct mdss_mdp_pipe *pipe;
+	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
 
 	if (!ctl)
 		return -EINVAL;
 
-	if ((hist->block < MDP_LOGICAL_BLOCK_DISP_0) ||
-		(hist->block >= MDP_BLOCK_MAX))
+	if ((PP_BLOCK(hist->block) < MDP_LOGICAL_BLOCK_DISP_0) ||
+		(PP_BLOCK(hist->block) >= MDP_BLOCK_MAX))
 		return -EINVAL;
 
-	mutex_lock(&mdss_mdp_hist_mutex);
-	disp_num = hist->block - MDP_LOGICAL_BLOCK_DISP_0;
-	mixer_cnt = mdss_mdp_get_ctl_mixers(disp_num, mixer_id);
+	disp_num = PP_BLOCK(hist->block) - MDP_LOGICAL_BLOCK_DISP_0;
+	hist_cnt = mdss_mdp_get_ctl_mixers(disp_num, mixer_id);
 
-	if (!mixer_cnt) {
+	if (!hist_cnt) {
 		pr_err("%s, no dspp connects to disp %d",
 			__func__, disp_num);
 		ret = -EPERM;
 		goto hist_collect_exit;
 	}
-	if (mixer_cnt >= MDSS_MDP_MAX_DSPP) {
+	if (hist_cnt >= MDSS_MDP_MAX_DSPP) {
 		pr_err("%s, Too many dspp connects to disp %d",
-			__func__, mixer_cnt);
+			__func__, hist_cnt);
 		ret = -EPERM;
 		goto hist_collect_exit;
 	}
-	hist_info = &mdss_pp_res->dspp_hist[0];
-	for (i = 0; i < mixer_cnt; i++) {
-		dspp_num = mixer_id[i];
-		hist_info = &mdss_pp_res->dspp_hist[dspp_num];
-		ctl_base = MDSS_MDP_REG_DSPP_OFFSET(dspp_num) +
-			  MDSS_MDP_REG_DSPP_HIST_CTL_BASE;
-		if ((hist_info->col_en == 0) ||
-			(hist_info->col_state == HIST_UNKNOWN)) {
-			ret = -EINVAL;
-			goto hist_collect_exit;
-		}
-		spin_lock_irqsave(&mdss_hist_lock, flag);
-		/* wait for hist done if cache has no data */
-		if (hist_info->col_state != HIST_READY) {
-			hist_info->read_request = true;
-			spin_unlock_irqrestore(&mdss_hist_lock, flag);
-			timeout = HIST_WAIT_TIMEOUT(hist_info->frame_cnt);
-			mutex_unlock(&mdss_mdp_hist_mutex);
-			/* flush updates before wait*/
-			mdss_mdp_pp_setup(ctl);
-			wait_ret = wait_for_completion_killable_timeout(
-					&(hist_info->comp), timeout);
-
-			mutex_lock(&mdss_mdp_hist_mutex);
-			if (wait_ret == 0) {
-				ret = -ETIMEDOUT;
-				spin_lock_irqsave(&mdss_hist_lock, flag);
-				pr_debug("bin collection timedout, state %d",
-							hist_info->col_state);
-				/*
-				 * When the histogram has timed out (usually
-				 * underrun) change the SW state back to idle
-				 * since histogram hardware will have done the
-				 * same. Histogram data also needs to be
-				 * cleared in this case, which is done by the
-				 * histogram being read (triggered by READY
-				 * state, which also moves the histogram SW back
-				 * to IDLE).
-				 */
-				hist_info->col_state = HIST_READY;
-				spin_unlock_irqrestore(&mdss_hist_lock, flag);
-			} else if (wait_ret < 0) {
-				ret = -EINTR;
-				pr_debug("%s: bin collection interrupted",
-						__func__);
-				goto hist_collect_exit;
-			}
-			if (hist_info->col_state != HIST_READY) {
-				ret = -ENODATA;
-				pr_debug("%s: state is not ready: %d",
-					__func__, hist_info->col_state);
-				goto hist_collect_exit;
-			}
-		} else {
-			spin_unlock_irqrestore(&mdss_hist_lock, flag);
-		}
-		spin_lock_irqsave(&mdss_hist_lock, flag);
-		if (hist_info->col_state == HIST_READY) {
-			spin_unlock_irqrestore(&mdss_hist_lock, flag);
-			v_base = ctl_base + 0x1C;
-			mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
-			pp_hist_read(v_base, hist_info);
-			mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
-			spin_lock_irqsave(&mdss_hist_lock, flag);
-			hist_info->read_request = false;
-			hist_info->col_state = HIST_IDLE;
-		}
-		spin_unlock_irqrestore(&mdss_hist_lock, flag);
-	}
-	if (mixer_cnt > 1) {
-		memset(&mdss_pp_res->hist_data[disp_num][0],
-			0, HIST_V_SIZE * sizeof(u32));
-		for (i = 0; i < mixer_cnt; i++) {
+	if (PP_LOCAT(hist->block) == MDSS_PP_DSPP_CFG) {
+		hist_info = &mdss_pp_res->dspp_hist[disp_num];
+		for (i = 0; i < hist_cnt; i++) {
 			dspp_num = mixer_id[i];
 			hist_info = &mdss_pp_res->dspp_hist[dspp_num];
-			for (j = 0; j < HIST_V_SIZE; j++)
-				mdss_pp_res->hist_data[disp_num][i] +=
-					hist_info->data[i];
+			ctl_base = mdss_mdp_get_dspp_addr_off(dspp_num) +
+				MDSS_MDP_REG_DSPP_HIST_CTL_BASE;
+			ret = pp_hist_collect(ctl, hist, hist_info, ctl_base);
+			if (ret)
+				goto hist_collect_exit;
 		}
-		*hist_data_addr = (u32)&mdss_pp_res->hist_data[disp_num][0];
+		if (hist_cnt > 1) {
+			if (hist->bin_cnt != HIST_V_SIZE) {
+				pr_err("User not expecting size %d output",
+								HIST_V_SIZE);
+				ret = -EINVAL;
+				goto hist_collect_exit;
+			}
+			hist_concat = kmalloc(HIST_V_SIZE * sizeof(u32),
+								GFP_KERNEL);
+			if (!hist_concat) {
+				ret = -ENOMEM;
+				goto hist_collect_exit;
+			}
+			memset(hist_concat, 0, HIST_V_SIZE * sizeof(u32));
+			for (i = 0; i < hist_cnt; i++) {
+				dspp_num = mixer_id[i];
+				hist_info = &mdss_pp_res->dspp_hist[dspp_num];
+				mutex_lock(&hist_info->hist_mutex);
+				for (j = 0; j < HIST_V_SIZE; j++)
+					hist_concat[i] += hist_info->data[i];
+				mutex_unlock(&hist_info->hist_mutex);
+			}
+			hist_data_addr = hist_concat;
+		} else {
+			hist_data_addr = hist_info->data;
+		}
+		hist_info = &mdss_pp_res->dspp_hist[disp_num];
+		hist_info->hist_cnt_sent++;
+	} else if (PP_LOCAT(hist->block) == MDSS_PP_SSPP_CFG) {
+
+		hist_cnt = MDSS_PP_ARG_MASK & hist->block;
+		if (!hist_cnt) {
+			pr_warn("Must pass pipe arguments, %d", hist_cnt);
+			goto hist_collect_exit;
+		}
+
+		/* Find the first pipe requested */
+		for (i = 0; i < MDSS_PP_ARG_NUM; i++) {
+			if (PP_ARG(i, hist_cnt)) {
+				pipe_num = i;
+				break;
+			}
+		}
+
+		pipe = mdss_mdp_pipe_get(mdata, BIT(pipe_num));
+		if (IS_ERR_OR_NULL(pipe)) {
+			pr_warn("Invalid starting hist pipe, %d", pipe_num);
+			ret = -ENODEV;
+			goto hist_collect_exit;
+		}
+		hist_info  = &pipe->pp_res.hist;
+		mdss_mdp_pipe_unmap(pipe);
+		for (i = pipe_num; i < MDSS_PP_ARG_NUM; i++) {
+			if (!PP_ARG(i, hist->block))
+				continue;
+			pipe_cnt++;
+			pipe = mdss_mdp_pipe_get(mdata, BIT(i));
+			if (IS_ERR_OR_NULL(pipe) ||
+					pipe->num > MDSS_MDP_SSPP_VIG2) {
+				pr_warn("Invalid Hist pipe (%d)", i);
+				continue;
+			}
+			hist_info = &pipe->pp_res.hist;
+			ctl_base = pipe->base +
+				MDSS_MDP_REG_VIG_HIST_CTL_BASE;
+			ret = pp_hist_collect(ctl, hist, hist_info, ctl_base);
+			mdss_mdp_pipe_unmap(pipe);
+			if (ret)
+				goto hist_collect_exit;
+		}
+		if (pipe_cnt > 1) {
+			if (hist->bin_cnt != (HIST_V_SIZE * pipe_cnt)) {
+				pr_err("User not expecting size %d output",
+							pipe_cnt * HIST_V_SIZE);
+				ret = -EINVAL;
+				goto hist_collect_exit;
+			}
+			hist_concat = kmalloc(HIST_V_SIZE * pipe_cnt *
+						sizeof(u32), GFP_KERNEL);
+			if (!hist_concat) {
+				ret = -ENOMEM;
+				goto hist_collect_exit;
+			}
+
+			memset(hist_concat, 0, pipe_cnt * HIST_V_SIZE *
+								sizeof(u32));
+			for (i = pipe_num; i < MDSS_PP_ARG_NUM; i++) {
+				if (!PP_ARG(i, hist->block))
+					continue;
+				pipe = mdss_mdp_pipe_get(mdata, BIT(i));
+				hist_info  = &pipe->pp_res.hist;
+				off = HIST_V_SIZE * i;
+				mutex_lock(&hist_info->hist_mutex);
+				for (j = off; j < off + HIST_V_SIZE; j++)
+					hist_concat[j] =
+						hist_info->data[j - off];
+				hist_info->hist_cnt_sent++;
+				mutex_unlock(&hist_info->hist_mutex);
+				mdss_mdp_pipe_unmap(pipe);
+			}
+
+			hist_data_addr = hist_concat;
+		} else {
+			hist_data_addr = hist_info->data;
+		}
 	} else {
-		*hist_data_addr = (u32)hist_info->data;
+		pr_info("No Histogram at location %d", PP_LOCAT(hist->block));
+		goto hist_collect_exit;
 	}
-	hist_info->hist_cnt_sent++;
+	ret = copy_to_user(hist->c0, hist_data_addr, sizeof(u32) *
+								hist->bin_cnt);
 hist_collect_exit:
-	mutex_unlock(&mdss_mdp_hist_mutex);
+	kfree(hist_concat);
+
 	return ret;
 }
 void mdss_mdp_hist_intr_done(u32 isr)
 {
 	u32 isr_blk, blk_idx;
-	struct pp_hist_col_info *hist_info;
+	struct pp_hist_col_info *hist_info = NULL;
+	struct mdss_mdp_pipe *pipe;
+	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
 	isr &= 0x333333;
 	while (isr != 0) {
 		if (isr & 0xFFF000) {
@@ -2129,36 +2470,40 @@
 			hist_info = &mdss_pp_res->dspp_hist[blk_idx];
 		} else {
 			if (isr & 0x3) {
-				blk_idx = 0;
+				blk_idx = MDSS_MDP_SSPP_VIG0;
 				isr_blk = isr & 0x3;
 				isr &= ~0x3;
 			} else if (isr & 0x30) {
-				blk_idx = 1;
+				blk_idx = MDSS_MDP_SSPP_VIG1;
 				isr_blk = (isr >> 4) & 0x3;
 				isr &= ~0x30;
 			} else {
-				blk_idx = 2;
+				blk_idx = MDSS_MDP_SSPP_VIG2;
 				isr_blk = (isr >> 8) & 0x3;
 				isr &= ~0x300;
 			}
-			/* SSPP block, not support yet*/
-			continue;
+			pipe = mdss_mdp_pipe_search(mdata, BIT(blk_idx));
+			if (IS_ERR_OR_NULL(pipe)) {
+				pr_debug("pipe DNE, %d", blk_idx);
+				continue;
+			}
+			hist_info = &pipe->pp_res.hist;
 		}
 		/* Histogram Done Interrupt */
-		if ((isr_blk & 0x1) &&
+		if (hist_info && (isr_blk & 0x1) &&
 			(hist_info->col_en)) {
-			spin_lock(&mdss_hist_lock);
+			spin_lock(&hist_info->hist_lock);
 			hist_info->col_state = HIST_READY;
-			spin_unlock(&mdss_hist_lock);
+			spin_unlock(&hist_info->hist_lock);
 			if (hist_info->read_request)
 				complete(&hist_info->comp);
 		}
 		/* Histogram Reset Done Interrupt */
 		if ((isr_blk & 0x2) &&
 			(hist_info->col_en)) {
-				spin_lock(&mdss_hist_lock);
+				spin_lock(&hist_info->hist_lock);
 				hist_info->col_state = HIST_IDLE;
-				spin_unlock(&mdss_hist_lock);
+				spin_unlock(&hist_info->hist_lock);
 		}
 	};
 }
diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.c b/drivers/video/msm/mdss/mdss_mdp_rotator.c
index 5711653..ce4c28f 100644
--- a/drivers/video/msm/mdss/mdss_mdp_rotator.c
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.c
@@ -27,6 +27,8 @@
 static struct mdss_mdp_rotator_session rotator_session[MAX_ROTATOR_SESSIONS];
 static LIST_HEAD(rotator_queue);
 
+static int mdss_mdp_rotator_finish(struct mdss_mdp_rotator_session *rot);
+
 struct mdss_mdp_rotator_session *mdss_mdp_rotator_session_alloc(void)
 {
 	struct mdss_mdp_rotator_session *rot;
@@ -166,27 +168,21 @@
 	return 0;
 }
 
-int mdss_mdp_rotator_queue(struct mdss_mdp_rotator_session *rot,
+static int mdss_mdp_rotator_queue_sub(struct mdss_mdp_rotator_session *rot,
 			   struct mdss_mdp_data *src_data,
 			   struct mdss_mdp_data *dst_data)
 {
 	struct mdss_mdp_pipe *rot_pipe = NULL;
 	struct mdss_mdp_ctl *ctl;
-	int ret, need_wait = false;
+	int ret;
 
-	ret = mutex_lock_interruptible(&rotator_lock);
-	if (ret)
-		return ret;
-
-	if (!rot || !rot->ref_cnt) {
-		mutex_unlock(&rotator_lock);
-		return -ENODEV;
-	}
+	if (!rot || !rot->ref_cnt)
+		return -ENOENT;
 
 	ret = mdss_mdp_rotator_pipe_dequeue(rot);
 	if (ret) {
 		pr_err("unable to acquire rotator\n");
-		goto done;
+		return ret;
 	}
 
 	rot_pipe = rot->pipe;
@@ -203,31 +199,141 @@
 		rot_pipe->img_height = rot->img_height;
 		rot_pipe->src = rot->src_rect;
 		rot_pipe->dst = rot->src_rect;
+		rot_pipe->dst.x = 0;
+		rot_pipe->dst.y = 0;
 		rot_pipe->params_changed++;
 	}
 
 	ret = mdss_mdp_pipe_queue_data(rot->pipe, src_data);
 	if (ret) {
 		pr_err("unable to queue rot data\n");
-		goto done;
+		return ret;
 	}
 
 	ret = mdss_mdp_rotator_kickoff(ctl, rot, dst_data);
 
-	if (ret == 0 && !rot->no_wait)
-		need_wait = true;
-done:
+	return ret;
+}
+
+int mdss_mdp_rotator_queue(struct mdss_mdp_rotator_session *rot,
+			   struct mdss_mdp_data *src_data,
+			   struct mdss_mdp_data *dst_data)
+{
+	int ret;
+	struct mdss_mdp_rotator_session *tmp = rot;
+
+	ret = mutex_lock_interruptible(&rotator_lock);
+	if (ret)
+		return ret;
+
+	pr_debug("rotator session=%x start\n", rot->session_id);
+
+	for (ret = 0, tmp = rot; ret == 0 && tmp; tmp = tmp->next)
+		ret = mdss_mdp_rotator_queue_sub(tmp, src_data, dst_data);
+
 	mutex_unlock(&rotator_lock);
 
-	if (need_wait)
-		mdss_mdp_rotator_busy_wait(rot);
+	if (ret) {
+		pr_err("rotation failed %d for rot=%d\n", ret, rot->session_id);
+		return ret;
+	}
 
-	if (rot_pipe)
-		pr_debug("end of rotator pnum=%d enqueue\n", rot_pipe->num);
+	for (tmp = rot; tmp; tmp = tmp->next)
+		mdss_mdp_rotator_busy_wait(tmp);
+
+	pr_debug("rotator session=%x queue done\n", rot->session_id);
 
 	return ret;
 }
 
+int mdss_mdp_rotator_setup(struct mdss_mdp_rotator_session *rot)
+{
+
+	rot->dst = rot->src_rect;
+	/*
+	 * by default, rotator output should be placed directly on
+	 * output buffer address without any offset.
+	 */
+	rot->dst.x = 0;
+	rot->dst.y = 0;
+
+	if (rot->flags & MDP_ROT_90)
+		swap(rot->dst.w, rot->dst.h);
+
+	if (rot->src_rect.w > MAX_MIXER_WIDTH) {
+		struct mdss_mdp_rotator_session *tmp;
+		u32 width;
+
+		if (rot->bwc_mode) {
+			pr_err("Unable to do split rotation with bwc set\n");
+			return -EINVAL;
+		}
+
+		width = rot->src_rect.w;
+
+		pr_debug("setting up split rotation src=%dx%d\n",
+			rot->src_rect.w, rot->src_rect.h);
+
+		if (width > (MAX_MIXER_WIDTH * 2)) {
+			pr_err("unsupported source width %d\n", width);
+			return -EOVERFLOW;
+		}
+
+		if (!rot->next) {
+			tmp = mdss_mdp_rotator_session_alloc();
+			if (!tmp) {
+				pr_err("unable to allocate rot dual session\n");
+				return -ENOMEM;
+			}
+			rot->next = tmp;
+		}
+		tmp = rot->next;
+
+		tmp->session_id = rot->session_id & ~MDSS_MDP_ROT_SESSION_MASK;
+		tmp->flags = rot->flags;
+		tmp->format = rot->format;
+		tmp->img_width = rot->img_width;
+		tmp->img_height = rot->img_height;
+		tmp->src_rect = rot->src_rect;
+
+		tmp->src_rect.w = width / 2;
+		width -= tmp->src_rect.w;
+		tmp->src_rect.x += width;
+
+		tmp->dst = rot->dst;
+		rot->src_rect.w = width;
+
+		if (rot->flags & MDP_ROT_90) {
+			/*
+			 * If rotated by 90 first half should be on top.
+			 * But if horizontally flipped should be on bottom.
+			 */
+			if (rot->flags & MDP_FLIP_LR)
+				rot->dst.y = tmp->src_rect.w;
+			else
+				tmp->dst.y = rot->src_rect.w;
+		} else {
+			/*
+			 * If not rotated, first half should be the left part
+			 * of the frame, unless horizontally flipped
+			 */
+			if (rot->flags & MDP_FLIP_LR)
+				rot->dst.x = tmp->src_rect.w;
+			else
+				tmp->dst.x = rot->src_rect.w;
+		}
+
+		tmp->params_changed++;
+	} else if (rot->next) {
+		mdss_mdp_rotator_finish(rot->next);
+		rot->next = NULL;
+	}
+
+	rot->params_changed++;
+
+	return 0;
+}
+
 static int mdss_mdp_rotator_finish(struct mdss_mdp_rotator_session *rot)
 {
 	struct mdss_mdp_pipe *rot_pipe;
@@ -237,6 +343,9 @@
 
 	pr_debug("finish rot id=%x\n", rot->session_id);
 
+	if (rot->next)
+		mdss_mdp_rotator_finish(rot->next);
+
 	rot_pipe = rot->pipe;
 	if (rot_pipe) {
 		mdss_mdp_rotator_busy_wait(rot);
diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.h b/drivers/video/msm/mdss/mdss_mdp_rotator.h
index 21ee9bb..c50d710 100644
--- a/drivers/video/msm/mdss/mdss_mdp_rotator.h
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.h
@@ -30,6 +30,7 @@
 	u16 img_width;
 	u16 img_height;
 	struct mdss_mdp_img_rect src_rect;
+	struct mdss_mdp_img_rect dst;
 
 	u32 bwc_mode;
 	struct mdss_mdp_pipe *pipe;
@@ -40,6 +41,7 @@
 	u8 no_wait;
 
 	struct list_head head;
+	struct mdss_mdp_rotator_session *next;
 };
 
 static inline u32 mdss_mdp_get_rotator_dst_format(u32 in_format)
@@ -61,6 +63,7 @@
 struct mdss_mdp_rotator_session *mdss_mdp_rotator_session_alloc(void);
 struct mdss_mdp_rotator_session *mdss_mdp_rotator_session_get(u32 session_id);
 
+int mdss_mdp_rotator_setup(struct mdss_mdp_rotator_session *rot);
 int mdss_mdp_rotator_queue(struct mdss_mdp_rotator_session *rot,
 			   struct mdss_mdp_data *src_data,
 			   struct mdss_mdp_data *dst_data);
diff --git a/drivers/video/msm/mdss/mdss_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c
index 5915f61..4de6d03 100644
--- a/drivers/video/msm/mdss/mdss_mdp_util.c
+++ b/drivers/video/msm/mdss/mdss_mdp_util.c
@@ -387,6 +387,31 @@
 	return 0;
 }
 
+void mdss_mdp_data_calc_offset(struct mdss_mdp_data *data, u16 x, u16 y,
+	struct mdss_mdp_plane_sizes *ps, struct mdss_mdp_format_params *fmt)
+{
+	if ((x == 0) && (y == 0))
+		return;
+
+	data->p[0].addr += y * ps->ystride[0];
+
+	if (data->num_planes == 1) {
+		data->p[0].addr += x * fmt->bpp;
+	} else {
+		u8 hmap[] = { 1, 2, 1, 2 };
+		u8 vmap[] = { 1, 1, 2, 2 };
+		u16 xoff = x / hmap[fmt->chroma_sample];
+		u16 yoff = y / vmap[fmt->chroma_sample];
+
+		data->p[0].addr += x;
+		data->p[1].addr += xoff + (yoff * ps->ystride[1]);
+		if (data->num_planes == 2) /* pseudo planar */
+			data->p[1].addr += xoff;
+		else /* planar */
+			data->p[2].addr += xoff + (yoff * ps->ystride[2]);
+	}
+}
+
 int mdss_mdp_put_img(struct mdss_mdp_img_data *data)
 {
 	struct ion_client *iclient = mdss_get_ionclient();
diff --git a/include/linux/mfd/wcd9xxx/core.h b/include/linux/mfd/wcd9xxx/core.h
index 37a12fb..3a9b1b9 100644
--- a/include/linux/mfd/wcd9xxx/core.h
+++ b/include/linux/mfd/wcd9xxx/core.h
@@ -150,6 +150,17 @@
 #define WCD9XXX_CH(xport, xshift) \
 	{.port = xport, .shift = xshift}
 
+struct wcd9xxx_codec_type {
+	u16 id_major;
+	u16 id_minor;
+	struct mfd_cell *dev;
+	int size;
+	int num_irqs;
+	int version; /* -1 to retrive version from chip version register */
+	enum wcd9xxx_slim_slave_addr_type slim_slave_type;
+	u16 i2c_chip_status;
+};
+
 struct wcd9xxx {
 	struct device *dev;
 	struct slim_device *slim;
@@ -181,14 +192,14 @@
 	struct pm_qos_request pm_qos_req;
 	int wlock_holders;
 
-	u8 idbyte[4];
+	u16 id_minor;
+	u16 id_major;
 
 	unsigned int irq_base;
 	unsigned int irq;
 	u8 irq_masks_cur[WCD9XXX_NUM_IRQ_REGS];
 	u8 irq_masks_cache[WCD9XXX_NUM_IRQ_REGS];
 	bool irq_level_high[WCD9XXX_MAX_NUM_IRQS];
-	int num_irqs;
 	/* Slimbus or I2S port */
 	u32 num_rx_port;
 	u32 num_tx_port;
@@ -196,7 +207,7 @@
 	struct wcd9xxx_ch *tx_chs;
 	u32 mclk_rate;
 
-	enum wcd9xxx_slim_slave_addr_type slim_slave_type;
+	const struct wcd9xxx_codec_type *codec_type;
 };
 
 int wcd9xxx_reg_read(struct wcd9xxx *wcd9xxx, unsigned short reg);
diff --git a/include/linux/mfd/wcd9xxx/pdata.h b/include/linux/mfd/wcd9xxx/pdata.h
index 813cac3..c6e4ab3 100644
--- a/include/linux/mfd/wcd9xxx/pdata.h
+++ b/include/linux/mfd/wcd9xxx/pdata.h
@@ -136,7 +136,7 @@
 	unsigned int	hph_ocp_limit:3; /* Headphone OCP current limit */
 };
 
-#define MAX_REGULATOR	7
+#define WCD9XXX_MAX_REGULATOR	8
 /*
  *      format : TABLA_<POWER_SUPPLY_PIN_NAME>_CUR_MAX
  *
@@ -151,11 +151,14 @@
 #define  WCD9XXX_VDDD_CDC_D_CUR_MAX       5000
 #define  WCD9XXX_VDDD_CDC_A_CUR_MAX       5000
 
+#define WCD9XXX_VDD_SPKDRV_NAME "cdc-vdd-spkdrv"
+
 struct wcd9xxx_regulator {
 	const char *name;
 	int min_uV;
 	int max_uV;
 	int optimum_uA;
+	bool ondemand;
 	struct regulator *regulator;
 };
 
@@ -168,7 +171,7 @@
 	struct slim_device slimbus_slave_device;
 	struct wcd9xxx_micbias_setting micbias;
 	struct wcd9xxx_ocp_setting ocp;
-	struct wcd9xxx_regulator regulator[MAX_REGULATOR];
+	struct wcd9xxx_regulator regulator[WCD9XXX_MAX_REGULATOR];
 	u32 mclk_rate;
 	u32 dmic_sample_rate;
 };
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 60567fa..b9d4a6f 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -296,7 +296,7 @@
 
 #define MDSS_PP_ARG_MASK	0x3C00
 #define MDSS_PP_ARG_NUM		4
-#define MDSS_PP_ARG_SHIFT	8
+#define MDSS_PP_ARG_SHIFT	10
 #define MDSS_PP_LOCATION_MASK	0x0300
 #define MDSS_PP_LOGICAL_MASK	0x00FF
 
@@ -332,6 +332,7 @@
 #define MDP_OVERLAY_PP_IGC_CFG         0x8
 #define MDP_OVERLAY_PP_SHARP_CFG       0x10
 #define MDP_OVERLAY_PP_HIST_CFG        0x20
+#define MDP_OVERLAY_PP_HIST_LUT_CFG    0x40
 
 #define MDP_CSC_FLAG_ENABLE	0x1
 #define MDP_CSC_FLAG_YUV_IN	0x2
@@ -375,6 +376,13 @@
 	uint16_t num_bins;
 };
 
+struct mdp_hist_lut_data {
+	uint32_t block;
+	uint32_t ops;
+	uint32_t len;
+	uint32_t *data;
+};
+
 struct mdp_overlay_pp_params {
 	uint32_t config_ops;
 	struct mdp_csc_cfg csc_cfg;
@@ -383,6 +391,7 @@
 	struct mdp_igc_lut_data igc_cfg;
 	struct mdp_sharp_cfg sharp_cfg;
 	struct mdp_histogram_cfg hist_cfg;
+	struct mdp_hist_lut_data hist_lut_cfg;
 };
 
 struct mdp_overlay {
@@ -517,13 +526,6 @@
 };
 
 
-struct mdp_hist_lut_data {
-	uint32_t block;
-	uint32_t ops;
-	uint32_t len;
-	uint32_t *data;
-};
-
 struct mdp_lut_cfg_data {
 	uint32_t lut_type;
 	union {
diff --git a/include/linux/qseecom.h b/include/linux/qseecom.h
index c399b81..294c881 100644
--- a/include/linux/qseecom.h
+++ b/include/linux/qseecom.h
@@ -138,6 +138,25 @@
 	enum qseecom_key_management_usage_type usage;
 };
 
+#define SHA256_DIGEST_LENGTH	(256/8)
+/*
+ * struct qseecom_save_partition_hash_req
+ * @partition_id - partition id.
+ * @hash[SHA256_DIGEST_LENGTH] -  sha256 digest.
+ */
+struct qseecom_save_partition_hash_req {
+	int partition_id; /* in */
+	char digest[SHA256_DIGEST_LENGTH]; /* in */
+};
+
+/*
+ * struct qseecom_is_es_activated_req
+ * @is_activated - 1=true , 0=false
+ */
+struct qseecom_is_es_activated_req {
+	int is_activated; /* out */
+};
+
 #define QSEECOM_IOC_MAGIC    0x97
 
 
@@ -195,5 +214,10 @@
 #define QSEECOM_IOCTL_WIPE_KEY_REQ \
 	_IOWR(QSEECOM_IOC_MAGIC, 18, struct qseecom_wipe_key_req)
 
+#define QSEECOM_IOCTL_SAVE_PARTITION_HASH_REQ \
+	_IOWR(QSEECOM_IOC_MAGIC, 19, struct qseecom_save_partition_hash_req)
+
+#define QSEECOM_IOCTL_IS_ES_ACTIVATED_REQ \
+	_IOWR(QSEECOM_IOC_MAGIC, 20, struct qseecom_is_es_activated_req)
 
 #endif /* __QSEECOM_H_ */
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index cc1e8eb..fef7100 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -24,6 +24,7 @@
 #include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
 #include <linux/mfd/wcd9xxx/wcd9320_registers.h>
 #include <linux/mfd/wcd9xxx/pdata.h>
+#include <linux/regulator/consumer.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
@@ -394,6 +395,7 @@
 	u8 aux_r_gain;
 
 	bool spkr_pa_widget_on;
+	struct regulator *spkdrv_reg;
 
 	struct afe_param_cdc_slimbus_slave_cfg slimbus_slave_cfg;
 
@@ -404,7 +406,6 @@
 
 	/* class h specific data */
 	struct wcd9xxx_clsh_cdc_data clsh_d;
-
 };
 
 static const u32 comp_shift[] = {
@@ -1082,13 +1083,6 @@
 		40, digital_gain),
 	SOC_SINGLE_S8_TLV("IIR2 INP4 Volume", TAIKO_A_CDC_IIR2_GAIN_B4_CTL, -84,
 		40, digital_gain),
-	SOC_SINGLE_TLV("ADC1 Volume", TAIKO_A_TX_1_2_EN, 5, 3, 0, analog_gain),
-	SOC_SINGLE_TLV("ADC2 Volume", TAIKO_A_TX_1_2_EN, 1, 3, 0, analog_gain),
-	SOC_SINGLE_TLV("ADC3 Volume", TAIKO_A_TX_3_4_EN, 5, 3, 0, analog_gain),
-	SOC_SINGLE_TLV("ADC4 Volume", TAIKO_A_TX_3_4_EN, 1, 3, 0, analog_gain),
-	SOC_SINGLE_TLV("ADC5 Volume", TAIKO_A_TX_5_6_EN, 5, 3, 0, analog_gain),
-	SOC_SINGLE_TLV("ADC6 Volume", TAIKO_A_TX_5_6_EN, 1, 3, 0, analog_gain),
-
 
 	SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 100, 0, taiko_get_anc_slot,
 		taiko_put_anc_slot),
@@ -2707,10 +2701,20 @@
 	int ret = 0;
 	struct snd_soc_codec *codec = w->codec;
 	struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
+	struct taiko_priv *priv = snd_soc_codec_get_drvdata(codec);
 
 	pr_debug("%s: %d %s\n", __func__, event, w->name);
+
+	WARN_ONCE(!priv->spkdrv_reg, "SPKDRV supply %s isn't defined\n",
+		  WCD9XXX_VDD_SPKDRV_NAME);
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
+		if (priv->spkdrv_reg) {
+			ret = regulator_enable(priv->spkdrv_reg);
+			if (ret)
+				pr_err("%s: Failed to enable spkdrv_reg %s\n",
+				       __func__, WCD9XXX_VDD_SPKDRV_NAME);
+		}
 		if (spkr_drv_wrnd > 0) {
 			WARN_ON(!(snd_soc_read(codec, TAIKO_A_SPKR_DRV_EN) &
 				  0x80));
@@ -2731,6 +2735,12 @@
 			snd_soc_update_bits(codec, TAIKO_A_SPKR_DRV_EN, 0x80,
 					    0x80);
 		}
+		if (priv->spkdrv_reg) {
+			ret = regulator_disable(priv->spkdrv_reg);
+			if (ret)
+				pr_err("%s: Failed to disable spkdrv_reg %s\n",
+				       __func__, WCD9XXX_VDD_SPKDRV_NAME);
+		}
 		break;
 	}
 
@@ -5378,7 +5388,8 @@
 	}
 
 	for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
-		if (!strncmp(pdata->regulator[i].name, "CDC_VDDA_RX", 11)) {
+		if (pdata->regulator[i].name &&
+		    !strncmp(pdata->regulator[i].name, "CDC_VDDA_RX", 11)) {
 			if (pdata->regulator[i].min_uV == 1800000 &&
 			    pdata->regulator[i].max_uV == 1800000) {
 				snd_soc_write(codec, TAIKO_A_BIAS_REF_CTL,
@@ -5945,6 +5956,21 @@
 			   SND_SOC_DAPM_POST_PMU),
 };
 
+static struct regulator *taiko_codec_find_regulator(struct snd_soc_codec *codec,
+						    const char *name)
+{
+	int i;
+	struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
+
+	for (i = 0; i < core->num_of_supplies; i++) {
+		if (core->supplies[i].supply &&
+		    !strcmp(core->supplies[i].supply, name))
+			return core->supplies[i].consumer;
+	}
+
+	return NULL;
+}
+
 static int taiko_codec_probe(struct snd_soc_codec *codec)
 {
 	struct wcd9xxx *control;
@@ -6023,6 +6049,9 @@
 		goto err_pdata;
 	}
 
+	taiko->spkdrv_reg = taiko_codec_find_regulator(codec,
+						       WCD9XXX_VDD_SPKDRV_NAME);
+
 	if (spkr_drv_wrnd > 0) {
 		WCD9XXX_BCL_LOCK(&taiko->resmgr);
 		wcd9xxx_resmgr_get_bandgap(&taiko->resmgr,
@@ -6127,6 +6156,8 @@
 	/* cleanup resmgr */
 	wcd9xxx_resmgr_deinit(&taiko->resmgr);
 
+	taiko->spkdrv_reg = NULL;
+
 	kfree(taiko);
 	return 0;
 }
diff --git a/sound/soc/msm/mdm9625.c b/sound/soc/msm/mdm9625.c
index 2bef1b7..f3ccb33 100644
--- a/sound/soc/msm/mdm9625.c
+++ b/sound/soc/msm/mdm9625.c
@@ -761,6 +761,21 @@
 		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
 	},
 	{
+		.name = "MDM9625 Media2",
+		.stream_name = "MultiMedia2",
+		.cpu_dai_name   = "MultiMedia2",
+		.platform_name  = "msm-pcm-dsp.0",
+		.dynamic = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST},
+		.ignore_suspend = 1,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
+	},
+	{
 		.name = "MSM VoIP",
 		.stream_name = "VoIP",
 		.cpu_dai_name = "VoIP",
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index e79a0cf..63af271 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -947,7 +947,7 @@
 	int i;
 
 	i = port_id - SLIMBUS_0_RX;
-	if (i < 0 || i > ARRAY_SIZE(afe_ports_mad_type)) {
+	if (i < 0 || i >= ARRAY_SIZE(afe_ports_mad_type)) {
 		pr_debug("%s: Non Slimbus port_id 0x%x\n", __func__, port_id);
 		return MAD_HW_NONE;
 	}